Annotation of sys/arch/arm/xscale/pxa2x0_ohci.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: pxa2x0_ohci.c,v 1.21 2007/06/14 19:18:49 deraadt Exp $ */
2:
3: /*
4: * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/param.h>
20: #include <sys/systm.h>
21: #include <sys/device.h>
22: #include <sys/kernel.h>
23: #include <sys/timeout.h>
24:
25: #include <machine/intr.h>
26: #include <machine/bus.h>
27:
28: #include <arm/xscale/pxa2x0reg.h>
29: #include <arm/xscale/pxa2x0var.h>
30: #include <arm/xscale/pxa2x0_gpio.h>
31:
32: #include <dev/usb/usb.h>
33: #include <dev/usb/usbdi.h>
34: #include <dev/usb/usbdivar.h>
35: #include <dev/usb/usb_mem.h>
36:
37: #include <dev/usb/ohcireg.h>
38: #include <dev/usb/ohcivar.h>
39:
40: int pxaohci_match(struct device *, void *, void *);
41: void pxaohci_attach(struct device *, struct device *, void *);
42: int pxaohci_detach(struct device *, int);
43: void pxaohci_power(int, void *);
44:
45: struct pxaohci_softc {
46: ohci_softc_t sc;
47: void *sc_ih;
48: };
49:
50: void pxaohci_enable(struct pxaohci_softc *);
51: void pxaohci_disable(struct pxaohci_softc *);
52:
53: struct cfattach pxaohci_ca = {
54: sizeof (struct pxaohci_softc), pxaohci_match, pxaohci_attach,
55: pxaohci_detach, ohci_activate
56: };
57:
58: int
59: pxaohci_match(struct device *parent, void *match, void *aux)
60: {
61: if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) != CPU_ID_PXA27X)
62: return (0);
63:
64: return (1);
65: }
66:
67: void
68: pxaohci_attach(struct device *parent, struct device *self, void *aux)
69: {
70: struct pxaohci_softc *sc = (struct pxaohci_softc *)self;
71: struct pxaip_attach_args *pxa = aux;
72: usbd_status r;
73:
74: sc->sc.iot = pxa->pxa_iot;
75: sc->sc.sc_bus.dmatag = pxa->pxa_dmat;
76: sc->sc_ih = NULL;
77: sc->sc.sc_size = 0;
78:
79: /* Map I/O space */
80: if (bus_space_map(sc->sc.iot, PXA2X0_USBHC_BASE, PXA2X0_USBHC_SIZE, 0,
81: &sc->sc.ioh)) {
82: printf(": cannot map mem space\n");
83: return;
84: }
85: sc->sc.sc_size = PXA2X0_USBHC_SIZE;
86:
87: /* XXX copied from ohci_pci.c. needed? */
88: bus_space_barrier(sc->sc.iot, sc->sc.ioh, 0, sc->sc.sc_size,
89: BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
90:
91: /* start the usb clock */
92: pxa2x0_clkman_config(CKEN_USBHC, 1);
93: pxaohci_enable(sc);
94:
95: /* Disable interrupts, so we don't get any spurious ones. */
96: bus_space_write_4(sc->sc.iot, sc->sc.ioh, OHCI_INTERRUPT_DISABLE,
97: OHCI_MIE);
98:
99: sc->sc_ih = pxa2x0_intr_establish(PXA2X0_INT_USBH1, IPL_USB,
100: ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname);
101: if (sc->sc_ih == NULL) {
102: printf(": unable to establish interrupt\n");
103: pxaohci_disable(sc);
104: pxa2x0_clkman_config(CKEN_USBHC, 0);
105: bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
106: sc->sc.sc_size = 0;
107: return;
108: }
109:
110: strlcpy(sc->sc.sc_vendor, "PXA27x", sizeof(sc->sc.sc_vendor));
111:
112: if (ohci_checkrev(&sc->sc) != USBD_NORMAL_COMPLETION)
113: goto unsupported;
114:
115: r = ohci_init(&sc->sc);
116: if (r != USBD_NORMAL_COMPLETION) {
117: printf("%s: init failed, error=%d\n",
118: sc->sc.sc_bus.bdev.dv_xname, r);
119: unsupported:
120: pxa2x0_intr_disestablish(sc->sc_ih);
121: sc->sc_ih = NULL;
122: pxaohci_disable(sc);
123: pxa2x0_clkman_config(CKEN_USBHC, 0);
124: bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
125: sc->sc.sc_size = 0;
126: return;
127: }
128:
129: sc->sc.sc_powerhook = powerhook_establish(pxaohci_power, sc);
130: if (sc->sc.sc_powerhook == NULL)
131: printf("%s: cannot establish powerhook\n",
132: sc->sc.sc_bus.bdev.dv_xname);
133:
134: sc->sc.sc_child = config_found((void *)sc, &sc->sc.sc_bus,
135: usbctlprint);
136: }
137:
138: int
139: pxaohci_detach(struct device *self, int flags)
140: {
141: struct pxaohci_softc *sc = (struct pxaohci_softc *)self;
142: int rv;
143:
144: rv = ohci_detach(&sc->sc, flags);
145: if (rv)
146: return (rv);
147:
148: if (sc->sc.sc_powerhook != NULL) {
149: powerhook_disestablish(sc->sc.sc_powerhook);
150: sc->sc.sc_powerhook = NULL;
151: }
152:
153: if (sc->sc_ih != NULL) {
154: pxa2x0_intr_disestablish(sc->sc_ih);
155: sc->sc_ih = NULL;
156: }
157:
158: pxaohci_disable(sc);
159:
160: /* stop clock */
161: pxa2x0_clkman_config(CKEN_USBHC, 0);
162:
163: if (sc->sc.sc_size) {
164: bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
165: sc->sc.sc_size = 0;
166: }
167:
168: return (0);
169: }
170:
171:
172: void
173: pxaohci_power(int why, void *arg)
174: {
175: struct pxaohci_softc *sc = (struct pxaohci_softc *)arg;
176: int s;
177:
178: s = splhardusb();
179: sc->sc.sc_bus.use_polling++;
180: switch (why) {
181: case PWR_STANDBY:
182: case PWR_SUSPEND:
183: ohci_power(why, &sc->sc);
184: pxa2x0_clkman_config(CKEN_USBHC, 0);
185: break;
186:
187: case PWR_RESUME:
188: pxa2x0_clkman_config(CKEN_USBHC, 1);
189: pxaohci_enable(sc);
190: ohci_power(why, &sc->sc);
191: break;
192: }
193: sc->sc.sc_bus.use_polling--;
194: splx(s);
195: }
196:
197: void
198: pxaohci_enable(struct pxaohci_softc *sc)
199: {
200: u_int32_t hr;
201:
202: /* Full host reset */
203: hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
204: bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
205: (hr & USBHC_HR_MASK) | USBHC_HR_FHR);
206:
207: DELAY(USBHC_RST_WAIT);
208:
209: hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
210: bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
211: (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR));
212:
213: /* Force system bus interface reset */
214: hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
215: bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
216: (hr & USBHC_HR_MASK) | USBHC_HR_FSBIR);
217:
218: while (bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR) & \
219: USBHC_HR_FSBIR)
220: DELAY(3);
221:
222: /* Enable the ports (physically only one, only enable that one?) */
223: hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
224: bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
225: (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSE));
226: hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
227: bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
228: (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSEP2));
229: }
230:
231: void
232: pxaohci_disable(struct pxaohci_softc *sc)
233: {
234: u_int32_t hr;
235:
236: /* Full host reset */
237: hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
238: bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
239: (hr & USBHC_HR_MASK) | USBHC_HR_FHR);
240:
241: DELAY(USBHC_RST_WAIT);
242:
243: hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
244: bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
245: (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR));
246: }
CVSweb