xref: /openbsd/sys/arch/armv7/omap/omohci.c (revision ea05d060)
1 /*	$OpenBSD: omohci.c,v 1.5 2024/08/20 16:24:50 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 <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 
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);
98 
99 struct 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 
109 void	omohci_enable(struct omohci_softc *);
110 void	omohci_disable(struct omohci_softc *);
111 
112 const struct cfattach omohci_ca = {
113         sizeof (struct omohci_softc), omohci_match, omohci_attach,
114 	omohci_detach, omohci_detach
115 };
116 
117 int
omohci_match(struct device * parent,void * match,void * aux)118 omohci_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 
128 void
omohci_attach(struct device * parent,struct device * self,void * aux)129 omohci_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 
229 int
omohci_detach(struct device * self,int flags)230 omohci_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 
270 int
omohci_activate(struct device * self,int act)271 omohci_activate(struct device *self, int act)
272 {
273 	struct omohci_softc *sc = (struct omohci_softc *)self;
274 	int rv;
275 
276 	switch (act) {
277 	case DVACT_SUSPEND:
278 		sc->sc.sc_bus.use_polling++;
279 		ohci_power(why, &sc->sc);
280 #if 0
281 		pxa2x0_clkman_config(CKEN_USBHC, 0);
282 #endif
283 		sc->sc.sc_bus.use_polling--;
284 		rv = config_activate_children(self, act);
285 		break;
286 
287 	case DVACT_RESUME:
288 		rv = config_activate_children(self, act);
289 		sc->sc.sc_bus.use_polling++;
290 #if 0
291 		pxa2x0_clkman_config(CKEN_USBHC, 1);
292 #endif
293 		omohci_enable(sc);
294 		ohci_power(why, &sc->sc);
295 		sc->sc.sc_bus.use_polling--;
296 		break;
297 	default:
298 		rv = config_activate_children(self, act);
299 		break;
300 	}
301 	return rv;
302 }
303 
304 void
omohci_enable(struct omohci_softc * sc)305 omohci_enable(struct omohci_softc *sc)
306 {
307 #if 0
308 	u_int32_t			hr;
309 
310 	/* Full host reset */
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 	DELAY(USBHC_RST_WAIT);
316 
317 	hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
318 	bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
319 	    (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR));
320 
321 	/* Force system bus interface reset */
322 	hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
323 	bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
324 	    (hr & USBHC_HR_MASK) | USBHC_HR_FSBIR);
325 
326 	while (bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR) & \
327 	    USBHC_HR_FSBIR)
328 		DELAY(3);
329 
330 	/* Enable the ports (physically only one, only enable that one?) */
331 	hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
332 	bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
333 	    (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSE));
334 	hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
335 	bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
336 	    (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSEP2));
337 #endif
338 }
339 
340 void
omohci_disable(struct omohci_softc * sc)341 omohci_disable(struct omohci_softc *sc)
342 {
343 #if 0
344 	u_int32_t			hr;
345 
346 	/* Full host reset */
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 
351 	DELAY(USBHC_RST_WAIT);
352 
353 	hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR);
354 	bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR,
355 	    (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR));
356 #endif
357 }
358