1 /* $OpenBSD: omohci.c,v 1.3 2014/05/19 13:11:31 mpi Exp $ */
4 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
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.
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.
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>
25 #include <machine/intr.h>
26 #include <machine/bus.h>
28 #include <dev/usb/usb.h>
29 #include <dev/usb/usbdi.h>
30 #include <dev/usb/usbdivar.h>
31 #include <dev/usb/usb_mem.h>
33 #include <dev/usb/ohcireg.h>
34 #include <dev/usb/ohcivar.h>
35 #include <armv7/omap/prcmvar.h>
37 #define HOSTUEADDR 0x0E0
38 #define HOSTUESTATUS 0x0E4
39 #define HOSTTIMEOUTCTRL 0x0E8
40 #define HOSTREVISION 0x0EC
41 #define WHM_REVID_REGISTER 0x0F4
42 #define WHM_TEST_OBSV 0x0F8
43 #define WHM_TEST_CTL 0x0FC
44 #define HHC_TEST_CFG 0x100
45 #define HHC_TEST_CTL 0x104
46 #define HHC_TEST_OBSV 0x108
47 #define REVDEV 0x200 /* 16 bit */
48 #define EP_NUM 0x204 /* 16 bit */
49 #define DATA 0x208 /* 16 bit */
50 #define CTRL 0x20C /* 16 bit */
51 #define STAT_FLG 0x210 /* 16 bit */
52 #define RXFSTAT 0x214 /* 16 bit */
53 #define SYSCON1 0x218 /* 16 bit */
54 #define SYSCON2 0x21C /* 16 bit */
55 #define DEVSTAT 0x220 /* 16 bit */
56 #define SOFREG 0x224 /* 16 bit */
57 #define IRQ_EN 0x228 /* 16 bit */
58 #define DMA_IRQ_EN 0x22C /* 16 bit */
59 #define IRQ_SRC 0x230 /* 16 bit */
60 #define EPN_STAT 0x234 /* 16 bit */
61 #define DMAN_STAT 0x238 /* 16 bit */
62 #define RXDMA_CFG 0x240 /* 16 bit */
63 #define TXDMA_CFG 0x244 /* 16 bit */
73 #define EP_RX(x) 0x280 + (x * 4)
74 #define EP_TX(x) 0x2C0 + (x * 4)
77 #define OTG_SYSCON_1 0x304
78 #define OTG_SYSCON_2 0x308
79 #define OTG_SYSCON2_OTG_EN 0x80000000
80 #define OTG_SYSCON2_UHOST_EN 0x00000100
81 #define OTG_SYSCON2_MODE_DISABLED 0x00000000
82 #define OTG_SYSCON2_MODE_CLIENT 0x00000001
83 #define OTG_SYSCON2_MODE_HOST 0x00000004
84 #define OTG_CTRL 0x30C
86 #define OTG_IRQ_EN 0x310 /* 16 bit */
87 #define OTG_IRQ_SRC 0x314 /* 16 bit */
88 #define OTG_OUTCTRL 0x318 /* 16 bit */
89 #define OTG_TEST 0x320 /* 16 bit */
94 int omohci_match(struct device
*, void *, void *);
95 void omohci_attach(struct device
*, struct device
*, void *);
96 int omohci_detach(struct device
*, int);
97 int omohci_activate(struct device
*, int);
100 struct ohci_softc sc
;
109 void omohci_enable(struct omohci_softc
*);
110 void omohci_disable(struct omohci_softc
*);
112 struct cfattach omohci_ca
= {
113 sizeof (struct omohci_softc
), omohci_match
, omohci_attach
,
114 omohci_detach
, omohci_detach
118 omohci_match(struct device
*parent
, void *match
, void *aux
)
121 if ((cputype
& ~CPU_ID_XSCALE_COREREV_MASK
) != CPU_ID_PXA27X
)
129 omohci_attach(struct device
*parent
, struct device
*self
, void *aux
)
131 struct omohci_softc
*sc
= (struct omohci_softc
*)self
;
132 struct ahb_attach_args
*aa
= aux
;
135 sc
->sc
.iot
= aa
->aa_iot
;
136 sc
->sc
.sc_bus
.dmatag
= aa
->aa_dmat
;
146 if (bus_space_map(sc
->sc
.iot
, aa
->aa_addr
, aa
->aa_size
, 0,
148 printf(": cannot map mem space\n");
151 sc
->sc
.sc_size
= aa
->aa_size
;
153 /* XXX copied from ohci_pci.c. needed? */
154 bus_space_barrier(sc
->sc
.iot
, sc
->sc
.ioh
, 0, sc
->sc
.sc_size
,
155 BUS_SPACE_BARRIER_READ
|BUS_SPACE_BARRIER_WRITE
);
158 /* start the usb clock */
159 pxa2x0_clkman_config(CKEN_USBHC
, 1);
163 /* Disable interrupts, so we don't get any spurious ones. */
164 bus_space_write_4(sc
->sc
.iot
, sc
->sc
.ioh
, OHCI_INTERRUPT_DISABLE
,
167 sc
->sc_ihc0
= arm_intr_establish(aa
->aa_intr
, IPL_USB
,
168 ohci_intr
, &sc
->sc
, sc
->sc
.sc_bus
.bdev
.dv_xname
);
169 sc
->sc_ihc1
= arm_intr_establish(aa
->aa_intr
+1, IPL_USB
,
170 ohci_intr
, &sc
->sc
, sc
->sc
.sc_bus
.bdev
.dv_xname
);
171 sc
->sc_ihc2
= arm_intr_establish(aa
->aa_intr
+2, IPL_USB
,
172 ohci_intr
, &sc
->sc
, sc
->sc
.sc_bus
.bdev
.dv_xname
);
173 sc
->sc_ih0
= arm_intr_establish(aa
->aa_intr
+3, IPL_USB
,
174 ohci_intr
, &sc
->sc
, sc
->sc
.sc_bus
.bdev
.dv_xname
);
175 sc
->sc_ih1
= arm_intr_establish(aa
->aa_intr
+4, IPL_USB
,
176 ohci_intr
, &sc
->sc
, sc
->sc
.sc_bus
.bdev
.dv_xname
);
177 sc
->sc_ihotg
= arm_intr_establish(aa
->aa_intr
+5, IPL_USB
,
178 ohci_intr
, &sc
->sc
, sc
->sc
.sc_bus
.bdev
.dv_xname
);
179 if (sc
->sc_ih0
== NULL
||
180 sc
->sc_ih1
== NULL
||
181 sc
->sc_ihc0
== NULL
||
182 sc
->sc_ihc1
== NULL
||
183 sc
->sc_ihc2
== NULL
||
184 sc
->sc_ihotg
== NULL
) {
185 printf(": unable to establish interrupt\n");
188 pxa2x0_clkman_config(CKEN_USBHC
, 0);
190 bus_space_unmap(sc
->sc
.iot
, sc
->sc
.ioh
, sc
->sc
.sc_size
);
195 prcm_enablemodule(PRCM_USB
);
197 bus_space_write_4(sc
->sc
.iot
, sc
->sc
.ioh
, OTG_SYSCON_2
,
198 OTG_SYSCON2_UHOST_EN
| OTG_SYSCON2_MODE_HOST
);
200 strlcpy(sc
->sc
.sc_vendor
, "OMAP24xx", sizeof(sc
->sc
.sc_vendor
));
201 r
= ohci_init(&sc
->sc
);
202 if (r
!= USBD_NORMAL_COMPLETION
) {
203 printf("%s: init failed, error=%d\n",
204 sc
->sc
.sc_bus
.bdev
.dv_xname
, r
);
205 arm_intr_disestablish(sc
->sc_ih0
);
206 arm_intr_disestablish(sc
->sc_ih1
);
207 arm_intr_disestablish(sc
->sc_ihc0
);
208 arm_intr_disestablish(sc
->sc_ihc1
);
209 arm_intr_disestablish(sc
->sc_ihc2
);
210 arm_intr_disestablish(sc
->sc_ihotg
);
219 pxa2x0_clkman_config(CKEN_USBHC
, 0);
221 bus_space_unmap(sc
->sc
.iot
, sc
->sc
.ioh
, sc
->sc
.sc_size
);
226 config_found(self
, &sc
->sc
.sc_bus
, usbctlprint
);
230 omohci_detach(struct device
*self
, int flags
)
232 struct omohci_softc
*sc
= (struct omohci_softc
*)self
;
235 rv
= ohci_detach(self
, flags
);
239 if (sc
->sc_ih0
!= NULL
) {
240 arm_intr_disestablish(sc
->sc_ih0
);
241 arm_intr_disestablish(sc
->sc_ih1
);
242 arm_intr_disestablish(sc
->sc_ihc0
);
243 arm_intr_disestablish(sc
->sc_ihc1
);
244 arm_intr_disestablish(sc
->sc_ihc2
);
245 arm_intr_disestablish(sc
->sc_ihotg
);
258 pxa2x0_clkman_config(CKEN_USBHC
, 0);
261 if (sc
->sc
.sc_size
) {
262 bus_space_unmap(sc
->sc
.iot
, sc
->sc
.ioh
, sc
->sc
.sc_size
);
271 omohci_activate(struct device
*self
, int act
)
273 struct omohci_softc
*sc
= (struct omohci_softc
*)self
;
277 sc
->sc
.sc_bus
.use_polling
++;
278 ohci_power(why
, &sc
->sc
);
280 pxa2x0_clkman_config(CKEN_USBHC
, 0);
282 sc
->sc
.sc_bus
.use_polling
--;
286 sc
->sc
.sc_bus
.use_polling
++;
288 pxa2x0_clkman_config(CKEN_USBHC
, 1);
291 ohci_power(why
, &sc
->sc
);
292 sc
->sc
.sc_bus
.use_polling
--;
299 omohci_enable(struct omohci_softc
*sc
)
304 /* Full host reset */
305 hr
= bus_space_read_4(sc
->sc
.iot
, sc
->sc
.ioh
, USBHC_HR
);
306 bus_space_write_4(sc
->sc
.iot
, sc
->sc
.ioh
, USBHC_HR
,
307 (hr
& USBHC_HR_MASK
) | USBHC_HR_FHR
);
309 DELAY(USBHC_RST_WAIT
);
311 hr
= bus_space_read_4(sc
->sc
.iot
, sc
->sc
.ioh
, USBHC_HR
);
312 bus_space_write_4(sc
->sc
.iot
, sc
->sc
.ioh
, USBHC_HR
,
313 (hr
& USBHC_HR_MASK
) & ~(USBHC_HR_FHR
));
315 /* Force system bus interface reset */
316 hr
= bus_space_read_4(sc
->sc
.iot
, sc
->sc
.ioh
, USBHC_HR
);
317 bus_space_write_4(sc
->sc
.iot
, sc
->sc
.ioh
, USBHC_HR
,
318 (hr
& USBHC_HR_MASK
) | USBHC_HR_FSBIR
);
320 while (bus_space_read_4(sc
->sc
.iot
, sc
->sc
.ioh
, USBHC_HR
) & \
324 /* Enable the ports (physically only one, only enable that one?) */
325 hr
= bus_space_read_4(sc
->sc
.iot
, sc
->sc
.ioh
, USBHC_HR
);
326 bus_space_write_4(sc
->sc
.iot
, sc
->sc
.ioh
, USBHC_HR
,
327 (hr
& USBHC_HR_MASK
) & ~(USBHC_HR_SSE
));
328 hr
= bus_space_read_4(sc
->sc
.iot
, sc
->sc
.ioh
, USBHC_HR
);
329 bus_space_write_4(sc
->sc
.iot
, sc
->sc
.ioh
, USBHC_HR
,
330 (hr
& USBHC_HR_MASK
) & ~(USBHC_HR_SSEP2
));
335 omohci_disable(struct omohci_softc
*sc
)
340 /* Full host reset */
341 hr
= bus_space_read_4(sc
->sc
.iot
, sc
->sc
.ioh
, USBHC_HR
);
342 bus_space_write_4(sc
->sc
.iot
, sc
->sc
.ioh
, USBHC_HR
,
343 (hr
& USBHC_HR_MASK
) | USBHC_HR_FHR
);
345 DELAY(USBHC_RST_WAIT
);
347 hr
= bus_space_read_4(sc
->sc
.iot
, sc
->sc
.ioh
, USBHC_HR
);
348 bus_space_write_4(sc
->sc
.iot
, sc
->sc
.ioh
, USBHC_HR
,
349 (hr
& USBHC_HR_MASK
) & ~(USBHC_HR_FHR
));