xref: /openbsd/sys/arch/armv7/omap/omehci.c (revision 8529ddd3)
1 /*	$OpenBSD: omehci.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 /*-
20  * Copyright (c) 2011
21  *	Ben Gray <ben.r.gray@gmail.com>.
22  * All rights reserved.
23  *
24  * Redistribution and use in source and binary forms, with or without
25  * modification, are permitted provided that the following conditions
26  * are met:
27  * 1. Redistributions of source code must retain the above copyright
28  *    notice, this list of conditions and the following disclaimer.
29  * 2. Redistributions in binary form must reproduce the above copyright
30  *    notice, this list of conditions and the following disclaimer in the
31  *    documentation and/or other materials provided with the distribution.
32  *
33  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
34  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
37  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43  * SUCH DAMAGE.
44  */
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/device.h>
49 #include <sys/kernel.h>
50 #include <sys/rwlock.h>
51 #include <sys/timeout.h>
52 
53 #include <machine/intr.h>
54 #include <machine/bus.h>
55 
56 #include <dev/usb/usb.h>
57 #include <dev/usb/usbdi.h>
58 #include <dev/usb/usbdivar.h>
59 #include <dev/usb/usb_mem.h>
60 
61 #include <armv7/armv7/armv7var.h>
62 #include <armv7/omap/prcmvar.h>
63 #include <armv7/omap/omgpiovar.h>
64 #include <armv7/omap/omehcivar.h>
65 
66 #include <dev/usb/ehcireg.h>
67 #include <dev/usb/ehcivar.h>
68 
69 void	omehci_attach(struct device *, struct device *, void *);
70 int	omehci_detach(struct device *, int);
71 int	omehci_activate(struct device *, int);
72 
73 struct omehci_softc {
74 	struct ehci_softc	 sc;
75 	void			*sc_ih;
76 	bus_space_handle_t	 uhh_ioh;
77 	bus_space_handle_t	 tll_ioh;
78 
79 	uint32_t		 ehci_rev;
80 	uint32_t		 tll_avail;
81 
82 	uint32_t		 port_mode[OMAP_HS_USB_PORTS];
83 	uint32_t		 phy_reset[OMAP_HS_USB_PORTS];
84 	uint32_t		 reset_gpio_pin[OMAP_HS_USB_PORTS];
85 
86 	void			 (*early_init)(void);
87 };
88 
89 int omehci_init(struct omehci_softc *);
90 void omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port);
91 void omehci_enable(struct omehci_softc *);
92 void omehci_disable(struct omehci_softc *);
93 void omehci_utmi_init(struct omehci_softc *sc, unsigned int en_mask);
94 void misc_setup(struct omehci_softc *sc);
95 void omehci_phy_reset(uint32_t on, uint32_t _delay);
96 void omehci_uhh_init(struct omehci_softc *sc);
97 void omehci_v4_early_init(void);
98 
99 struct cfattach omehci_ca = {
100 	sizeof (struct omehci_softc), NULL, omehci_attach,
101 	omehci_detach, omehci_activate
102 };
103 
104 void
105 omehci_attach(struct device *parent, struct device *self, void *aux)
106 {
107 	struct omehci_softc	*sc = (struct omehci_softc *)self;
108 	struct armv7_attach_args *aa = aux;
109 	usbd_status		 r;
110 	char			*devname = sc->sc.sc_bus.bdev.dv_xname;
111 	uint32_t		 i;
112 
113 	sc->sc.iot = aa->aa_iot;
114 	sc->sc.sc_bus.dmatag = aa->aa_dmat;
115 	sc->sc.sc_size = aa->aa_dev->mem[0].size;
116 
117 	/* set defaults */
118 	for (i = 0; i < 3; i++) {
119 		sc->phy_reset[i] = 0;
120 		sc->port_mode[i] = EHCI_HCD_OMAP_MODE_UNKNOWN;
121 		sc->reset_gpio_pin[i] = -1;
122 	}
123 
124 	switch (board_id)
125 	{
126 	case BOARD_ID_OMAP4_PANDA:
127 		sc->tll_avail = 0;
128 		sc->port_mode[0] = EHCI_HCD_OMAP_MODE_PHY;
129 		sc->early_init = omehci_v4_early_init;
130 		break;
131 	default:
132 		break;
133 	}
134 
135 	/* Map I/O space */
136 	if (bus_space_map(sc->sc.iot, aa->aa_dev->mem[0].addr,
137 		aa->aa_dev->mem[0].size, 0, &sc->sc.ioh)) {
138 		printf(": cannot map mem space\n");
139 		goto out;
140 	}
141 
142 	if (bus_space_map(sc->sc.iot, aa->aa_dev->mem[1].addr,
143 		aa->aa_dev->mem[1].size, 0, &sc->uhh_ioh)) {
144 		printf(": cannot map mem space\n");
145 		goto mem0;
146 	}
147 
148 	if (sc->tll_avail &&
149 	    bus_space_map(sc->sc.iot, aa->aa_dev->mem[2].addr,
150 		aa->aa_dev->mem[2].size, 0, &sc->tll_ioh)) {
151 		printf(": cannot map mem space\n");
152 		goto mem1;
153 	}
154 
155 	printf("\n");
156 
157 	if (sc->early_init)
158 		sc->early_init();
159 
160 	if (omehci_init(sc))
161 		return;
162 
163 	/* Disable interrupts, so we don't get any spurious ones. */
164 	sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH);
165 	EOWRITE2(&sc->sc, EHCI_USBINTR, 0);
166 
167 	sc->sc_ih = arm_intr_establish(aa->aa_dev->irq[0], IPL_USB,
168 	    ehci_intr, &sc->sc, devname);
169 	if (sc->sc_ih == NULL) {
170 		printf(": unable to establish interrupt\n");
171 		printf("XXX - disable ehci and prcm");
172 		goto mem2;
173 	}
174 
175 	strlcpy(sc->sc.sc_vendor, "TI OMAP", sizeof(sc->sc.sc_vendor));
176 	r = ehci_init(&sc->sc);
177 	if (r != USBD_NORMAL_COMPLETION) {
178 		printf("%s: init failed, error=%d\n", devname, r);
179 		printf("XXX - disable ehci and prcm");
180 		goto intr;
181 	}
182 
183 	config_found(self, &sc->sc.sc_bus, usbctlprint);
184 
185 	goto out;
186 
187 intr:
188 	arm_intr_disestablish(sc->sc_ih);
189 	sc->sc_ih = NULL;
190 mem2:
191 	bus_space_unmap(sc->sc.iot, sc->tll_ioh, aa->aa_dev->mem[2].size);
192 mem1:
193 	bus_space_unmap(sc->sc.iot, sc->uhh_ioh, aa->aa_dev->mem[1].size);
194 mem0:
195 	bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
196 	sc->sc.sc_size = 0;
197 out:
198 	return;
199 }
200 
201 int
202 omehci_init(struct omehci_softc *sc)
203 {
204 	uint32_t i = 0, reg;
205 	uint32_t reset_performed = 0;
206 	uint32_t timeout = 0;
207 	uint32_t tll_ch_mask = 0;
208 
209 	/* enable high speed usb host clock */
210 	prcm_enablemodule(PRCM_USB);
211 
212 	/* Hold the PHY in reset while configuring */
213 	for (i = 0; i < OMAP_HS_USB_PORTS; i++) {
214 		if (sc->phy_reset[i]) {
215 			/* Configure the GPIO to drive low (hold in reset) */
216 			if (sc->reset_gpio_pin[i] != -1) {
217 				omgpio_set_dir(sc->reset_gpio_pin[i],
218 				    OMGPIO_DIR_OUT);
219 				omgpio_clear_bit(sc->reset_gpio_pin[i]);
220 				reset_performed = 1;
221 			}
222 		}
223 	}
224 
225 	/* Hold the PHY in RESET for enough time till DIR is high */
226 	if (reset_performed)
227 		delay(10);
228 
229 	/* Read the UHH revision */
230 	sc->ehci_rev = bus_space_read_4(sc->sc.iot, sc->uhh_ioh,
231 	    OMAP_USBHOST_UHH_REVISION);
232 
233 	/* Initilise the low level interface module(s) */
234 	if (sc->ehci_rev == OMAP_EHCI_REV1) {
235 		/* Enable the USB TLL */
236 		prcm_enablemodule(PRCM_USBTLL);
237 
238 		/* Perform TLL soft reset, and wait until reset is complete */
239 		bus_space_write_4(sc->sc.iot, sc->tll_ioh,
240 		    OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET);
241 
242 		/* Set the timeout to 100ms*/
243 		timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
244 
245 		/* Wait for TLL reset to complete */
246 		while ((bus_space_read_4(sc->sc.iot, sc->tll_ioh,
247 		    OMAP_USBTLL_SYSSTATUS) & TLL_SYSSTATUS_RESETDONE)
248 		    == 0x00) {
249 
250 			/* Sleep for a tick */
251 			delay(10);
252 
253 			if (timeout-- == 0) {
254 				return 1;
255 			}
256 		}
257 
258 		bus_space_write_4(sc->sc.iot, sc->tll_ioh,
259 		    OMAP_USBTLL_SYSCONFIG,
260 		    TLL_SYSCONFIG_ENAWAKEUP | TLL_SYSCONFIG_AUTOIDLE |
261 		    TLL_SYSCONFIG_SIDLE_SMART_IDLE | TLL_SYSCONFIG_CACTIVITY);
262 	} else if (sc->ehci_rev == OMAP_EHCI_REV2) {
263 		/* For OMAP44xx devices you have to enable the per-port clocks:
264 		 *  PHY_MODE  - External ULPI clock
265 		 *  TTL_MODE  - Internal UTMI clock
266 		 *  HSIC_MODE - Internal 480Mhz and 60Mhz clocks
267 		 */
268 		if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) {
269 			//ti_prcm_clk_set_source(USBP1_PHY_CLK, EXT_CLK);
270 			prcm_enablemodule(PRCM_USBP1_PHY);
271 		} else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
272 			prcm_enablemodule(PRCM_USBP1_UTMI);
273 		else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC)
274 			prcm_enablemodule(PRCM_USBP1_HSIC);
275 
276 		if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) {
277 			//ti_prcm_clk_set_source(USBP2_PHY_CLK, EXT_CLK);
278 			prcm_enablemodule(PRCM_USBP2_PHY);
279 		} else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
280 			prcm_enablemodule(PRCM_USBP2_UTMI);
281 		else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC)
282 			prcm_enablemodule(PRCM_USBP2_HSIC);
283 	}
284 
285 	/* Put UHH in SmartIdle/SmartStandby mode */
286 	reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh,
287 	    OMAP_USBHOST_UHH_SYSCONFIG);
288 	if (sc->ehci_rev == OMAP_EHCI_REV1) {
289 		reg &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK |
290 		         UHH_SYSCONFIG_MIDLEMODE_MASK);
291 		reg |= (UHH_SYSCONFIG_ENAWAKEUP |
292 		        UHH_SYSCONFIG_AUTOIDLE |
293 		        UHH_SYSCONFIG_CLOCKACTIVITY |
294 		        UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE |
295 		        UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY);
296 	} else if (sc->ehci_rev == OMAP_EHCI_REV2) {
297 		reg &= ~UHH_SYSCONFIG_IDLEMODE_MASK;
298 		reg |=  UHH_SYSCONFIG_IDLEMODE_NOIDLE;
299 		reg &= ~UHH_SYSCONFIG_STANDBYMODE_MASK;
300 		reg |=  UHH_SYSCONFIG_STANDBYMODE_NOSTDBY;
301 	}
302 	bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_SYSCONFIG,
303 	    reg);
304 
305 	reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh,
306 	    OMAP_USBHOST_UHH_HOSTCONFIG);
307 
308 	/* Setup ULPI bypass and burst configurations */
309 	reg |= (UHH_HOSTCONFIG_ENA_INCR4 |
310 		UHH_HOSTCONFIG_ENA_INCR8 |
311 		UHH_HOSTCONFIG_ENA_INCR16);
312 	reg &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN;
313 
314 	if (sc->ehci_rev == OMAP_EHCI_REV1) {
315 		if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
316 			reg &= ~UHH_HOSTCONFIG_P1_CONNECT_STATUS;
317 		if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
318 			reg &= ~UHH_HOSTCONFIG_P2_CONNECT_STATUS;
319 		if (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
320 			reg &= ~UHH_HOSTCONFIG_P3_CONNECT_STATUS;
321 
322 		/* Bypass the TLL module for PHY mode operation */
323 		if ((sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ||
324 		    (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ||
325 		    (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY))
326 			reg &= ~UHH_HOSTCONFIG_P1_ULPI_BYPASS;
327 		else
328 			reg |= UHH_HOSTCONFIG_P1_ULPI_BYPASS;
329 	} else if (sc->ehci_rev == OMAP_EHCI_REV2) {
330 		reg |=  UHH_HOSTCONFIG_APP_START_CLK;
331 
332 		/* Clear port mode fields for PHY mode*/
333 		reg &= ~UHH_HOSTCONFIG_P1_MODE_MASK;
334 		reg &= ~UHH_HOSTCONFIG_P2_MODE_MASK;
335 
336 		if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
337 			reg |= UHH_HOSTCONFIG_P1_MODE_UTMI_PHY;
338 		else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC)
339 			reg |= UHH_HOSTCONFIG_P1_MODE_HSIC;
340 
341 		if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
342 			reg |= UHH_HOSTCONFIG_P2_MODE_UTMI_PHY;
343 		else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC)
344 			reg |= UHH_HOSTCONFIG_P2_MODE_HSIC;
345 	}
346 
347 	bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_HOSTCONFIG, reg);
348 
349 	/* If any of the ports are configured in TLL mode, enable them */
350 	for (i = 0; i < OMAP_HS_USB_PORTS; i++)
351 		if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY)
352 			tll_ch_mask |= 1 << i;
353 
354 	/* Enable UTMI mode for required TLL channels */
355 #ifdef notyet
356 	if (tll_ch_mask)
357 		omap_ehci_utmi_init(sc, tll_ch_mask);
358 #endif
359 
360 	/* Release the PHY reset signal now we have configured everything */
361 	if (reset_performed) {
362 		/* Delay for 10ms */
363 		delay(10000);
364 
365 		/* Release reset */
366 		for (i = 0; i < 3; i++) {
367 			if (sc->phy_reset[i] && (sc->reset_gpio_pin[i] != -1))
368 				omgpio_set_bit(sc->reset_gpio_pin[i]);
369 		}
370 	}
371 
372 	/* Set the interrupt threshold control, it controls the maximum rate at
373 	 * which the host controller issues interrupts.  We set it to 1 microframe
374 	 * at startup - the default is 8 mircoframes (equates to 1ms).
375 	 */
376 	reg = bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD);
377 	reg &= 0xff00ffff;
378 	reg |= (1 << 16);
379 	bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD, reg);
380 
381 	/* Soft reset the PHY using PHY reset command over ULPI */
382 	for (i = 0; i < OMAP_HS_USB_PORTS; i++)
383 		if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY)
384 			omehci_soft_phy_reset(sc, i);
385 
386 	return(0);
387 }
388 
389 void
390 omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port)
391 {
392 	unsigned long timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
393 	uint32_t reg;
394 
395 	reg = ULPI_FUNC_CTRL_RESET
396 		/* FUNCTION_CTRL_SET register */
397 		| (ULPI_SET(ULPI_FUNC_CTRL) << OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT)
398 		/* Write */
399 		| (2 << OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT)
400 		/* PORTn */
401 		| ((port + 1) << OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT)
402 		/* start ULPI access*/
403 		| (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT);
404 
405 	bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI, reg);
406 
407 	timeout += 1000000;
408 	/* Wait for ULPI access completion */
409 	while ((bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI)
410 			& (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT))) {
411 
412 		/* Sleep for a tick */
413 		delay(10);
414 
415 		if (timeout-- == 0) {
416 			printf("PHY reset operation timed out\n");
417 			break;
418 		}
419 	}
420 }
421 
422 int
423 omehci_detach(struct device *self, int flags)
424 {
425 	struct omehci_softc		*sc = (struct omehci_softc *)self;
426 	int				rv;
427 
428 	rv = ehci_detach(self, flags);
429 	if (rv)
430 		return (rv);
431 
432 	if (sc->sc_ih != NULL) {
433 		arm_intr_disestablish(sc->sc_ih);
434 		sc->sc_ih = NULL;
435 	}
436 
437 	if (sc->sc.sc_size) {
438 		bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
439 		sc->sc.sc_size = 0;
440 	}
441 
442 	/* XXX: stop clock */
443 
444 	return (0);
445 }
446 
447 int
448 omehci_activate(struct device *self, int act)
449 {
450 	struct omehci_softc *sc = (struct omehci_softc *)self;
451 
452 	switch (act) {
453 	case DVACT_SUSPEND:
454 		sc->sc.sc_bus.use_polling++;
455 		/* FIXME */
456 		sc->sc.sc_bus.use_polling--;
457 		break;
458 	case DVACT_RESUME:
459 		sc->sc.sc_bus.use_polling++;
460 		/* FIXME */
461 		sc->sc.sc_bus.use_polling--;
462 		break;
463 	case DVACT_POWERDOWN:
464 		ehci_reset(&sc->sc);
465 		break;
466 	}
467 	return 0;
468 }
469 
470 void
471 omehci_v4_early_init()
472 {
473 	omgpio_set_dir(1, OMGPIO_DIR_OUT);
474 	omgpio_clear_bit(1);
475 	omgpio_set_dir(62, OMGPIO_DIR_OUT);
476 	omgpio_clear_bit(62);
477 
478 	/* wait for power down */
479 	delay(1000);
480 
481 	omgpio_set_bit(1);
482 	omgpio_set_bit(62);
483 
484 	/* wait until powered up */
485 	delay(1000);
486 }
487