1 /* $OpenBSD: omehci.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.
21 * Ben Gray <ben.r.gray@gmail.com>.
22 * All rights reserved.
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
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.
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
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>
53 #include <machine/intr.h>
54 #include <machine/bus.h>
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>
61 #include <armv7/armv7/armv7var.h>
62 #include <armv7/omap/prcmvar.h>
63 #include <armv7/omap/omgpiovar.h>
64 #include <armv7/omap/omehcivar.h>
66 #include <dev/usb/ehcireg.h>
67 #include <dev/usb/ehcivar.h>
69 void omehci_attach(struct device
*, struct device
*, void *);
70 int omehci_detach(struct device
*, int);
71 int omehci_activate(struct device
*, int);
76 bus_space_handle_t uhh_ioh
;
77 bus_space_handle_t tll_ioh
;
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
];
86 void (*early_init
)(void);
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);
99 struct cfattach omehci_ca
= {
100 sizeof (struct omehci_softc
), NULL
, omehci_attach
,
101 omehci_detach
, omehci_activate
105 omehci_attach(struct device
*parent
, struct device
*self
, void *aux
)
107 struct omehci_softc
*sc
= (struct omehci_softc
*)self
;
108 struct armv7_attach_args
*aa
= aux
;
110 char *devname
= sc
->sc
.sc_bus
.bdev
.dv_xname
;
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
;
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;
126 case BOARD_ID_OMAP4_PANDA
:
128 sc
->port_mode
[0] = EHCI_HCD_OMAP_MODE_PHY
;
129 sc
->early_init
= omehci_v4_early_init
;
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");
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");
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");
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);
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");
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");
183 config_found(self
, &sc
->sc
.sc_bus
, usbctlprint
);
188 arm_intr_disestablish(sc
->sc_ih
);
191 bus_space_unmap(sc
->sc
.iot
, sc
->tll_ioh
, aa
->aa_dev
->mem
[2].size
);
193 bus_space_unmap(sc
->sc
.iot
, sc
->uhh_ioh
, aa
->aa_dev
->mem
[1].size
);
195 bus_space_unmap(sc
->sc
.iot
, sc
->sc
.ioh
, sc
->sc
.sc_size
);
202 omehci_init(struct omehci_softc
*sc
)
205 uint32_t reset_performed
= 0;
206 uint32_t timeout
= 0;
207 uint32_t tll_ch_mask
= 0;
209 /* enable high speed usb host clock */
210 prcm_enablemodule(PRCM_USB
);
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
],
219 omgpio_clear_bit(sc
->reset_gpio_pin
[i
]);
225 /* Hold the PHY in RESET for enough time till DIR is high */
229 /* Read the UHH revision */
230 sc
->ehci_rev
= bus_space_read_4(sc
->sc
.iot
, sc
->uhh_ioh
,
231 OMAP_USBHOST_UHH_REVISION
);
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
);
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
);
242 /* Set the timeout to 100ms*/
243 timeout
= (hz
< 10) ? 1 : ((100 * hz
) / 1000);
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
)
250 /* Sleep for a tick */
253 if (timeout
-- == 0) {
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
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
);
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
);
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
;
302 bus_space_write_4(sc
->sc
.iot
, sc
->uhh_ioh
, OMAP_USBHOST_UHH_SYSCONFIG
,
305 reg
= bus_space_read_4(sc
->sc
.iot
, sc
->uhh_ioh
,
306 OMAP_USBHOST_UHH_HOSTCONFIG
);
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
;
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
;
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
;
328 reg
|= UHH_HOSTCONFIG_P1_ULPI_BYPASS
;
329 } else if (sc
->ehci_rev
== OMAP_EHCI_REV2
) {
330 reg
|= UHH_HOSTCONFIG_APP_START_CLK
;
332 /* Clear port mode fields for PHY mode*/
333 reg
&= ~UHH_HOSTCONFIG_P1_MODE_MASK
;
334 reg
&= ~UHH_HOSTCONFIG_P2_MODE_MASK
;
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
;
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
;
347 bus_space_write_4(sc
->sc
.iot
, sc
->uhh_ioh
, OMAP_USBHOST_UHH_HOSTCONFIG
, reg
);
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
;
354 /* Enable UTMI mode for required TLL channels */
357 omap_ehci_utmi_init(sc
, tll_ch_mask
);
360 /* Release the PHY reset signal now we have configured everything */
361 if (reset_performed
) {
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
]);
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).
376 reg
= bus_space_read_4(sc
->sc
.iot
, sc
->sc
.ioh
, OMAP_USBHOST_USBCMD
);
379 bus_space_write_4(sc
->sc
.iot
, sc
->sc
.ioh
, OMAP_USBHOST_USBCMD
, reg
);
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
);
390 omehci_soft_phy_reset(struct omehci_softc
*sc
, unsigned int port
)
392 unsigned long timeout
= (hz
< 10) ? 1 : ((100 * hz
) / 1000);
395 reg
= ULPI_FUNC_CTRL_RESET
396 /* FUNCTION_CTRL_SET register */
397 | (ULPI_SET(ULPI_FUNC_CTRL
) << OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT
)
399 | (2 << OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT
)
401 | ((port
+ 1) << OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT
)
402 /* start ULPI access*/
403 | (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT
);
405 bus_space_write_4(sc
->sc
.iot
, sc
->sc
.ioh
, OMAP_USBHOST_INSNREG05_ULPI
, reg
);
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
))) {
412 /* Sleep for a tick */
415 if (timeout
-- == 0) {
416 printf("PHY reset operation timed out\n");
423 omehci_detach(struct device
*self
, int flags
)
425 struct omehci_softc
*sc
= (struct omehci_softc
*)self
;
428 rv
= ehci_detach(self
, flags
);
432 if (sc
->sc_ih
!= NULL
) {
433 arm_intr_disestablish(sc
->sc_ih
);
437 if (sc
->sc
.sc_size
) {
438 bus_space_unmap(sc
->sc
.iot
, sc
->sc
.ioh
, sc
->sc
.sc_size
);
442 /* XXX: stop clock */
448 omehci_activate(struct device
*self
, int act
)
450 struct omehci_softc
*sc
= (struct omehci_softc
*)self
;
454 sc
->sc
.sc_bus
.use_polling
++;
456 sc
->sc
.sc_bus
.use_polling
--;
459 sc
->sc
.sc_bus
.use_polling
++;
461 sc
->sc
.sc_bus
.use_polling
--;
463 case DVACT_POWERDOWN
:
471 omehci_v4_early_init()
473 omgpio_set_dir(1, OMGPIO_DIR_OUT
);
475 omgpio_set_dir(62, OMGPIO_DIR_OUT
);
476 omgpio_clear_bit(62);
478 /* wait for power down */
484 /* wait until powered up */