initial commit, pull in sys/arch/armv7/omap
[bbb-pru.git] / omohci.c
CommitLineData
cf3c20ae 1/* $OpenBSD: omohci.c,v 1.3 2014/05/19 13:11:31 mpi 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 <dev/usb/usb.h>
29#include <dev/usb/usbdi.h>
30#include <dev/usb/usbdivar.h>
31#include <dev/usb/usb_mem.h>
32
33#include <dev/usb/ohcireg.h>
34#include <dev/usb/ohcivar.h>
35#include <armv7/omap/prcmvar.h>
36
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 */
64
65#define TXDMA0 0x250
66#define TXDMA1 0x254
67#define TXDMA2 0x258
68#define RXDMA0 0x260
69#define RXDMA1 0x264
70#define RXDMA2 0x268
71
72#define EP0 0x280
73#define EP_RX(x) 0x280 + (x * 4)
74#define EP_TX(x) 0x2C0 + (x * 4)
75
76#define OTG_REV 0x300
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
85#if 0
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 */
90#endif
91#define OTG_VC 0x3FC
92
93
94int omohci_match(struct device *, void *, void *);
95void omohci_attach(struct device *, struct device *, void *);
96int omohci_detach(struct device *, int);
97int omohci_activate(struct device *, int);
98
99struct omohci_softc {
100 struct ohci_softc sc;
101 void *sc_ihc0;
102 void *sc_ihc1;
103 void *sc_ihc2;
104 void *sc_ih0;
105 void *sc_ih1;
106 void *sc_ihotg;
107};
108
109void omohci_enable(struct omohci_softc *);
110void omohci_disable(struct omohci_softc *);
111
112struct cfattach omohci_ca = {
113 sizeof (struct omohci_softc), omohci_match, omohci_attach,
114 omohci_detach, omohci_detach
115};
116
117int
118omohci_match(struct device *parent, void *match, void *aux)
119{
120#if 0
121 if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) != CPU_ID_PXA27X)
122 return (0);
123#endif
124
125 return (1);
126}
127
128void
129omohci_attach(struct device *parent, struct device *self, void *aux)
130{
131 struct omohci_softc *sc = (struct omohci_softc *)self;
132 struct ahb_attach_args *aa = aux;
133 usbd_status r;
134
135 sc->sc.iot = aa->aa_iot;
136 sc->sc.sc_bus.dmatag = aa->aa_dmat;
137 sc->sc_ih0 = NULL;
138 sc->sc_ih1 = NULL;
139 sc->sc_ihc0 = NULL;
140 sc->sc_ihc1 = NULL;
141 sc->sc_ihc2 = NULL;
142 sc->sc_ihotg = NULL;
143 sc->sc.sc_size = 0;
144
145 /* Map I/O space */
146 if (bus_space_map(sc->sc.iot, aa->aa_addr, aa->aa_size, 0,
147 &sc->sc.ioh)) {
148 printf(": cannot map mem space\n");
149 return;
150 }
151 sc->sc.sc_size = aa->aa_size;
152
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);
156
157#if 0
158 /* start the usb clock */
159 pxa2x0_clkman_config(CKEN_USBHC, 1);
160#endif
161 omohci_enable(sc);
162
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,
165 OHCI_MIE);
166
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");
186 omohci_disable(sc);
187#if 0
188 pxa2x0_clkman_config(CKEN_USBHC, 0);
189#endif
190 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
191 sc->sc.sc_size = 0;
192 return;
193 }
194
195 prcm_enablemodule(PRCM_USB);
196
197 bus_space_write_4(sc->sc.iot, sc->sc.ioh, OTG_SYSCON_2,
198 OTG_SYSCON2_UHOST_EN | OTG_SYSCON2_MODE_HOST);
199
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);
211 sc->sc_ih0 = NULL;
212 sc->sc_ih1 = NULL;
213 sc->sc_ihc0 = NULL;
214 sc->sc_ihc1 = NULL;
215 sc->sc_ihc2 = NULL;
216 sc->sc_ihotg = NULL;
217 omohci_disable(sc);
218#if 0
219 pxa2x0_clkman_config(CKEN_USBHC, 0);
220#endif
221 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
222 sc->sc.sc_size = 0;
223 return;
224 }
225
226 config_found(self, &sc->sc.sc_bus, usbctlprint);
227}
228
229int
230omohci_detach(struct device *self, int flags)
231{
232 struct omohci_softc *sc = (struct omohci_softc *)self;
233 int rv;
234
235 rv = ohci_detach(self, flags);
236 if (rv)
237 return (rv);
238
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);
246 sc->sc_ih0 = NULL;
247 sc->sc_ih1 = NULL;
248 sc->sc_ihc0 = NULL;
249 sc->sc_ihc1 = NULL;
250 sc->sc_ihc2 = NULL;
251 sc->sc_ihotg = NULL;
252 }
253
254 omohci_disable(sc);
255
256 /* stop clock */
257#if 0
258 pxa2x0_clkman_config(CKEN_USBHC, 0);
259#endif
260
261 if (sc->sc.sc_size) {
262 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
263 sc->sc.sc_size = 0;
264 }
265
266 return (0);
267}
268
269
270int
271omohci_activate(struct device *self, int act)
272{
273 struct omohci_softc *sc = (struct omohci_softc *)self;
274
275 switch (act) {
276 case DVACT_SUSPEND:
277 sc->sc.sc_bus.use_polling++;
278 ohci_power(why, &sc->sc);
279#if 0
280 pxa2x0_clkman_config(CKEN_USBHC, 0);
281#endif
282 sc->sc.sc_bus.use_polling--;
283 break;
284
285 case DVACT_RESUME:
286 sc->sc.sc_bus.use_polling++;
287#if 0
288 pxa2x0_clkman_config(CKEN_USBHC, 1);
289#endif
290 omohci_enable(sc);
291 ohci_power(why, &sc->sc);
292 sc->sc.sc_bus.use_polling--;
293 break;
294 }
295 return 0;
296}
297
298void
299omohci_enable(struct omohci_softc *sc)
300{
301#if 0
302 u_int32_t hr;
303
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);
308
309 DELAY(USBHC_RST_WAIT);
310
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));
314
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);
319
320 while (bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR) & \
321 USBHC_HR_FSBIR)
322 DELAY(3);
323
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));
331#endif
332}
333
334void
335omohci_disable(struct omohci_softc *sc)
336{
337#if 0
338 u_int32_t hr;
339
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);
344
345 DELAY(USBHC_RST_WAIT);
346
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));
350#endif
351}