diff options
author | Patrick Wildt <patrick@cvs.openbsd.org> | 2013-06-14 23:13:55 +0000 |
---|---|---|
committer | Patrick Wildt <patrick@cvs.openbsd.org> | 2013-06-14 23:13:55 +0000 |
commit | db98ae4f83496c349fc19a2e27ba4e46f541a014 (patch) | |
tree | eb88f201c93f920d307c41c5db916d1148075695 | |
parent | 4b69549b61f04d4c27aa5550c1c2d2034929f3e7 (diff) |
Rework beagle's ehci driver and add neccessay code to enable the clocks.
Only PandaBoard supported for now. Lots taken from FreeBSD.
ok bmercer@
-rw-r--r-- | sys/arch/beagle/dev/omap.c | 4 | ||||
-rw-r--r-- | sys/arch/beagle/dev/omap4.c | 49 | ||||
-rw-r--r-- | sys/arch/beagle/dev/omap4_prcmreg.h | 27 | ||||
-rw-r--r-- | sys/arch/beagle/dev/omehci.c | 444 | ||||
-rw-r--r-- | sys/arch/beagle/dev/omehcivar.h | 230 | ||||
-rw-r--r-- | sys/arch/beagle/dev/prcm.c | 219 | ||||
-rw-r--r-- | sys/arch/beagle/dev/prcmvar.h | 10 |
7 files changed, 850 insertions, 133 deletions
diff --git a/sys/arch/beagle/dev/omap.c b/sys/arch/beagle/dev/omap.c index 5c633ceeda0..71db5ce0d3d 100644 --- a/sys/arch/beagle/dev/omap.c +++ b/sys/arch/beagle/dev/omap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: omap.c,v 1.9 2013/06/11 19:19:43 rapha Exp $ */ +/* $OpenBSD: omap.c,v 1.10 2013/06/14 23:13:54 patrick Exp $ */ /* * Copyright (c) 2005,2008 Dale Rahn <drahn@openbsd.com> * @@ -98,6 +98,7 @@ struct board_dev overo_devs[] = { struct board_dev pandaboard_devs[] = { { "omapid", 0 }, + { "prcm", 0 }, { "omdog", 0 }, { "omgpio", 0 }, { "omgpio", 1 }, @@ -107,6 +108,7 @@ struct board_dev pandaboard_devs[] = { { "omgpio", 5 }, { "ommmc", 0 }, /* HSMMC1 */ { "com", 2 }, /* UART3 */ + { "ehci", 0 }, { NULL, 0 } }; diff --git a/sys/arch/beagle/dev/omap4.c b/sys/arch/beagle/dev/omap4.c index 3c712246936..f601682b694 100644 --- a/sys/arch/beagle/dev/omap4.c +++ b/sys/arch/beagle/dev/omap4.c @@ -1,4 +1,4 @@ -/* $OpenBSD: omap4.c,v 1.9 2013/05/10 00:18:42 patrick Exp $ */ +/* $OpenBSD: omap4.c,v 1.10 2013/06/14 23:13:54 patrick Exp $ */ /* * Copyright (c) 2011 Uwe Stuehler <uwe@openbsd.org> @@ -60,9 +60,43 @@ #define HSMMC1_ADDR 0x4809c000 #define HSMMC1_IRQ 83 +#define PRM_ADDR 0x4a306000 +#define PRM_SIZE 0x2000 +#define CM1_ADDR 0x4a004000 +#define CM1_SIZE 0x1000 +#define CM2_ADDR 0x4a008000 +#define CM2_SIZE 0x2000 +#define SCRM_ADDR 0x4a30a000 +#define SCRM_SIZE 0x1000 +#define PCNF1_ADDR 0x4a100000 +#define PCNF1_SIZE 0x1000 +#define PCNF2_ADDR 0x4a31e000 +#define PCNF2_SIZE 0x1000 + +#define HSUSBHOST_ADDR 0x4a064000 +#define HSUSBHOST_SIZE 0x800 +#define USBEHCI_ADDR 0x4a064c00 +#define USBEHCI_SIZE 0x400 +#define USBOHCI_ADDR 0x4a064800 +#define USBOHCI_SIZE 0x400 +#define USBEHCI_IRQ 77 + struct omap_dev omap4_devs[] = { /* + * Power, Reset and Clock Manager + */ + + { .name = "prcm", + .unit = 0, + .mem = { + { PRM_ADDR, PRM_SIZE }, + { CM1_ADDR, CM1_SIZE }, + { CM2_ADDR, CM2_SIZE }, + }, + }, + + /* * OMAP identification registers/fuses */ @@ -140,6 +174,19 @@ struct omap_dev omap4_devs[] = { .irq = { HSMMC1_IRQ } }, + /* + * USB + */ + + { .name = "ehci", + .unit = 0, + .mem = { + { USBEHCI_ADDR, USBEHCI_SIZE }, + { HSUSBHOST_ADDR, HSUSBHOST_SIZE }, + }, + .irq = { USBEHCI_IRQ } + }, + /* Terminator */ { .name = NULL, .unit = 0, diff --git a/sys/arch/beagle/dev/omap4_prcmreg.h b/sys/arch/beagle/dev/omap4_prcmreg.h new file mode 100644 index 00000000000..0b902a66645 --- /dev/null +++ b/sys/arch/beagle/dev/omap4_prcmreg.h @@ -0,0 +1,27 @@ +/* $OpenBSD: omap4_prcmreg.h,v 1.1 2013/06/14 23:13:54 patrick Exp $ */ +/* + * Copyright (c) 2007, 2009, 2012 Dale Rahn <drahn@dalerahn.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define O4_L3INIT_CM2_OFFSET 0x00001300 +#define O4_CLKCTRL_MODULEMODE_MASK 0x00000003 +#define O4_CLKCTRL_MODULEMODE_DISABLE 0x00000000 +#define O4_CLKCTRL_MODULEMODE_AUTO 0x00000001 +#define O4_CLKCTRL_MODULEMODE_ENABLE 0x00000001 + +#define O4_MAX_MODULE_ENABLE_WAIT 1000 + +#define O4_CLKCTRL_IDLEST_MASK 0x00030000UL +#define O4_CLKCTRL_IDLEST_ENABLED 0x00000000UL diff --git a/sys/arch/beagle/dev/omehci.c b/sys/arch/beagle/dev/omehci.c index 5766d25458b..566b81e621e 100644 --- a/sys/arch/beagle/dev/omehci.c +++ b/sys/arch/beagle/dev/omehci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: omehci.c,v 1.14 2013/06/12 11:42:01 mpi Exp $ */ +/* $OpenBSD: omehci.c,v 1.15 2013/06/14 23:13:54 patrick Exp $ */ /* * Copyright (c) 2005 David Gwynne <dlg@openbsd.org> @@ -16,6 +16,33 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/*- + * Copyright (c) 2011 + * Ben Gray <ben.r.gray@gmail.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + #include <sys/param.h> #include <sys/systm.h> #include <sys/device.h> @@ -33,23 +60,41 @@ #include <beagle/dev/omapvar.h> #include <beagle/dev/prcmvar.h> +#include <beagle/dev/omgpiovar.h> +#include <beagle/dev/omehcivar.h> #include <dev/usb/ehcireg.h> #include <dev/usb/ehcivar.h> -#define EHCI_HCPCAPBASE 0x48064800 - void omehci_attach(struct device *, struct device *, void *); int omehci_detach(struct device *, int); int omehci_activate(struct device *, int); struct omehci_softc { - struct ehci_softc sc; + struct ehci_softc sc; void *sc_ih; + bus_space_handle_t uhh_ioh; + bus_space_handle_t tll_ioh; + + uint32_t ehci_rev; + uint32_t tll_avail; + + uint32_t port_mode[OMAP_HS_USB_PORTS]; + uint32_t phy_reset[OMAP_HS_USB_PORTS]; + uint32_t reset_gpio_pin[OMAP_HS_USB_PORTS]; + + void (*early_init)(void); }; -void omehci_enable(struct omehci_softc *); -void omehci_disable(struct omehci_softc *); +int omehci_init(struct omehci_softc *); +void omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port); +void omehci_enable(struct omehci_softc *); +void omehci_disable(struct omehci_softc *); +void omehci_utmi_init(struct omehci_softc *sc, unsigned int en_mask); +void misc_setup(struct omehci_softc *sc); +void omehci_phy_reset(uint32_t on, uint32_t _delay); +void omehci_uhh_init(struct omehci_softc *sc); +void omehci_v4_early_init(void); struct cfattach omehci_ca = { sizeof (struct omehci_softc), NULL, omehci_attach, @@ -61,29 +106,59 @@ omehci_attach(struct device *parent, struct device *self, void *aux) { struct omehci_softc *sc = (struct omehci_softc *)self; struct omap_attach_args *oa = aux; - usbd_status r; - char *devname = sc->sc.sc_bus.bdev.dv_xname; + usbd_status r; + char *devname = sc->sc.sc_bus.bdev.dv_xname; + uint32_t i; sc->sc.iot = oa->oa_iot; sc->sc.sc_bus.dmatag = oa->oa_dmat; sc->sc.sc_size = oa->oa_dev->mem[0].size; + /* set defaults */ + for (i = 0; i < 3; i++) { + sc->phy_reset[i] = 0; + sc->port_mode[i] = EHCI_HCD_OMAP_MODE_UNKNOWN; + sc->reset_gpio_pin[i] = -1; + } + + switch (board_id) + { + case BOARD_ID_OMAP4_PANDA: + sc->tll_avail = 0; + sc->port_mode[0] = EHCI_HCD_OMAP_MODE_PHY; + sc->early_init = omehci_v4_early_init; + break; + default: + break; + } + /* Map I/O space */ if (bus_space_map(sc->sc.iot, oa->oa_dev->mem[0].addr, - sc->sc.sc_size, 0, &sc->sc.ioh)) { + oa->oa_dev->mem[0].size, 0, &sc->sc.ioh)) { printf(": cannot map mem space\n"); - return; + goto out; } - /* XXX copied from ohci_pci.c. needed? */ - bus_space_barrier(sc->sc.iot, sc->sc.ioh, 0, sc->sc.sc_size, - BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); + if (bus_space_map(sc->sc.iot, oa->oa_dev->mem[1].addr, + oa->oa_dev->mem[1].size, 0, &sc->uhh_ioh)) { + printf(": cannot map mem space\n"); + goto mem0; + } - prcm_enablemodule(PRCM_USB); + if (sc->tll_avail && + bus_space_map(sc->sc.iot, oa->oa_dev->mem[2].addr, + oa->oa_dev->mem[2].size, 0, &sc->tll_ioh)) { + printf(": cannot map mem space\n"); + goto mem1; + } -#if 0 - omehci_enable(sc); -#endif + printf("\n"); + + if (sc->early_init) + sc->early_init(); + + if (omehci_init(sc)) + return; /* Disable interrupts, so we don't get any spurious ones. */ sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH); @@ -93,38 +168,256 @@ omehci_attach(struct device *parent, struct device *self, void *aux) ehci_intr, &sc->sc, devname); if (sc->sc_ih == NULL) { printf(": unable to establish interrupt\n"); -#if 0 - omehci_disable(sc); -#endif - -#if 0 - prcm_disableclock(PRCM_CLK_EN_USB); -#endif - - bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); - sc->sc.sc_size = 0; - return; + printf("XXX - disable ehci and prcm"); + goto mem2; } - strlcpy(sc->sc.sc_vendor, "OMAP3[45]xx", sizeof(sc->sc.sc_vendor)); + strlcpy(sc->sc.sc_vendor, "TI OMAP", sizeof(sc->sc.sc_vendor)); r = ehci_init(&sc->sc); if (r != USBD_NORMAL_COMPLETION) { printf("%s: init failed, error=%d\n", devname, r); + printf("XXX - disable ehci and prcm"); + goto intr; + } - arm_intr_disestablish(sc->sc_ih); - sc->sc_ih = NULL; + sc->sc.sc_child = config_found((void *)sc, &sc->sc.sc_bus, + usbctlprint); - bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); + goto out; + +intr: + arm_intr_disestablish(sc->sc_ih); + sc->sc_ih = NULL; +mem2: + bus_space_unmap(sc->sc.iot, sc->tll_ioh, oa->oa_dev->mem[2].size); +mem1: + bus_space_unmap(sc->sc.iot, sc->uhh_ioh, oa->oa_dev->mem[1].size); +mem0: + bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); + sc->sc.sc_size = 0; +out: + return; +} + +int +omehci_init(struct omehci_softc *sc) +{ + uint32_t i = 0, reg; + uint32_t reset_performed = 0; + uint32_t timeout = 0; + uint32_t tll_ch_mask = 0; + + /* enable high speed usb host clock */ + prcm_enablemodule(PRCM_USB); + + /* Hold the PHY in reset while configuring */ + for (i = 0; i < OMAP_HS_USB_PORTS; i++) { + if (sc->phy_reset[i]) { + /* Configure the GPIO to drive low (hold in reset) */ + if (sc->reset_gpio_pin[i] != -1) { + omgpio_set_dir(sc->reset_gpio_pin[i], + OMGPIO_DIR_OUT); + omgpio_clear_bit(sc->reset_gpio_pin[i]); + reset_performed = 1; + } + } + } -#if 0 - prcm_disableclock(PRCM_CLK_EN_USB); + /* Hold the PHY in RESET for enough time till DIR is high */ + if (reset_performed) + delay(10); + + /* Read the UHH revision */ + sc->ehci_rev = bus_space_read_4(sc->sc.iot, sc->uhh_ioh, + OMAP_USBHOST_UHH_REVISION); + + /* Initilise the low level interface module(s) */ + if (sc->ehci_rev == OMAP_EHCI_REV1) { + /* Enable the USB TLL */ + prcm_enablemodule(PRCM_USBTLL); + + /* Perform TLL soft reset, and wait until reset is complete */ + bus_space_write_4(sc->sc.iot, sc->tll_ioh, + OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET); + + /* Set the timeout to 100ms*/ + timeout = (hz < 10) ? 1 : ((100 * hz) / 1000); + + /* Wait for TLL reset to complete */ + while ((bus_space_read_4(sc->sc.iot, sc->tll_ioh, + OMAP_USBTLL_SYSSTATUS) & TLL_SYSSTATUS_RESETDONE) + == 0x00) { + + /* Sleep for a tick */ + delay(10); + + if (timeout-- == 0) { + return 1; + } + } + + bus_space_write_4(sc->sc.iot, sc->tll_ioh, + OMAP_USBTLL_SYSCONFIG, + TLL_SYSCONFIG_ENAWAKEUP | TLL_SYSCONFIG_AUTOIDLE | + TLL_SYSCONFIG_SIDLE_SMART_IDLE | TLL_SYSCONFIG_CACTIVITY); + } else if (sc->ehci_rev == OMAP_EHCI_REV2) { + /* For OMAP44xx devices you have to enable the per-port clocks: + * PHY_MODE - External ULPI clock + * TTL_MODE - Internal UTMI clock + * HSIC_MODE - Internal 480Mhz and 60Mhz clocks + */ + if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) { + //ti_prcm_clk_set_source(USBP1_PHY_CLK, EXT_CLK); + prcm_enablemodule(PRCM_USBP1_PHY); + } else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) + prcm_enablemodule(PRCM_USBP1_UTMI); + else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC) + prcm_enablemodule(PRCM_USBP1_HSIC); + + if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) { + //ti_prcm_clk_set_source(USBP2_PHY_CLK, EXT_CLK); + prcm_enablemodule(PRCM_USBP2_PHY); + } else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) + prcm_enablemodule(PRCM_USBP2_UTMI); + else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC) + prcm_enablemodule(PRCM_USBP2_HSIC); + } + + /* Put UHH in SmartIdle/SmartStandby mode */ + reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh, + OMAP_USBHOST_UHH_SYSCONFIG); + if (sc->ehci_rev == OMAP_EHCI_REV1) { + reg &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK | + UHH_SYSCONFIG_MIDLEMODE_MASK); + reg |= (UHH_SYSCONFIG_ENAWAKEUP | + UHH_SYSCONFIG_AUTOIDLE | + UHH_SYSCONFIG_CLOCKACTIVITY | + UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE | + UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY); + } else if (sc->ehci_rev == OMAP_EHCI_REV2) { + reg &= ~UHH_SYSCONFIG_IDLEMODE_MASK; + reg |= UHH_SYSCONFIG_IDLEMODE_NOIDLE; + reg &= ~UHH_SYSCONFIG_STANDBYMODE_MASK; + reg |= UHH_SYSCONFIG_STANDBYMODE_NOSTDBY; + } + bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_SYSCONFIG, + reg); + + reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh, + OMAP_USBHOST_UHH_HOSTCONFIG); + + /* Setup ULPI bypass and burst configurations */ + reg |= (UHH_HOSTCONFIG_ENA_INCR4 | + UHH_HOSTCONFIG_ENA_INCR8 | + UHH_HOSTCONFIG_ENA_INCR16); + reg &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN; + + if (sc->ehci_rev == OMAP_EHCI_REV1) { + if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN) + reg &= ~UHH_HOSTCONFIG_P1_CONNECT_STATUS; + if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN) + reg &= ~UHH_HOSTCONFIG_P2_CONNECT_STATUS; + if (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN) + reg &= ~UHH_HOSTCONFIG_P3_CONNECT_STATUS; + + /* Bypass the TLL module for PHY mode operation */ + if ((sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) || + (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) || + (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)) + reg &= ~UHH_HOSTCONFIG_P1_ULPI_BYPASS; + else + reg |= UHH_HOSTCONFIG_P1_ULPI_BYPASS; + } else if (sc->ehci_rev == OMAP_EHCI_REV2) { + reg |= UHH_HOSTCONFIG_APP_START_CLK; + + /* Clear port mode fields for PHY mode*/ + reg &= ~UHH_HOSTCONFIG_P1_MODE_MASK; + reg &= ~UHH_HOSTCONFIG_P2_MODE_MASK; + + if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) + reg |= UHH_HOSTCONFIG_P1_MODE_UTMI_PHY; + else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC) + reg |= UHH_HOSTCONFIG_P1_MODE_HSIC; + + if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) + reg |= UHH_HOSTCONFIG_P2_MODE_UTMI_PHY; + else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC) + reg |= UHH_HOSTCONFIG_P2_MODE_HSIC; + } + + bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_HOSTCONFIG, reg); + + /* If any of the ports are configured in TLL mode, enable them */ + for (i = 0; i < OMAP_HS_USB_PORTS; i++) + if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY) + tll_ch_mask |= 1 << i; + + /* Enable UTMI mode for required TLL channels */ +#ifdef notyet + if (tll_ch_mask) + omap_ehci_utmi_init(sc, tll_ch_mask); #endif - sc->sc.sc_size = 0; - return; + + /* Release the PHY reset signal now we have configured everything */ + if (reset_performed) { + /* Delay for 10ms */ + delay(10000); + + /* Release reset */ + for (i = 0; i < 3; i++) { + if (sc->phy_reset[i] && (sc->reset_gpio_pin[i] != -1)) + omgpio_set_bit(sc->reset_gpio_pin[i]); + } } - sc->sc.sc_child = config_found((void *)sc, &sc->sc.sc_bus, - usbctlprint); + /* Set the interrupt threshold control, it controls the maximum rate at + * which the host controller issues interrupts. We set it to 1 microframe + * at startup - the default is 8 mircoframes (equates to 1ms). + */ + reg = bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD); + reg &= 0xff00ffff; + reg |= (1 << 16); + bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD, reg); + + /* Soft reset the PHY using PHY reset command over ULPI */ + for (i = 0; i < OMAP_HS_USB_PORTS; i++) + if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY) + omehci_soft_phy_reset(sc, i); + + return(0); +} + +void +omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port) +{ + unsigned long timeout = (hz < 10) ? 1 : ((100 * hz) / 1000); + uint32_t reg; + + reg = ULPI_FUNC_CTRL_RESET + /* FUNCTION_CTRL_SET register */ + | (ULPI_SET(ULPI_FUNC_CTRL) << OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT) + /* Write */ + | (2 << OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT) + /* PORTn */ + | ((port + 1) << OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT) + /* start ULPI access*/ + | (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT); + + bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI, reg); + + timeout += 1000000; + /* Wait for ULPI access completion */ + while ((bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI) + & (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT))) { + + /* Sleep for a tick */ + delay(10); + + if (timeout-- == 0) { + printf("PHY reset operation timed out\n"); + break; + } + } } int @@ -147,10 +440,7 @@ omehci_detach(struct device *self, int flags) sc->sc.sc_size = 0; } - /* stop clock */ -#if 0 - prcm_disableclock(PRCM_CLK_EN_USB); -#endif + /* XXX: stop clock */ return (0); } @@ -163,77 +453,35 @@ omehci_activate(struct device *self, int act) switch (act) { case DVACT_SUSPEND: sc->sc.sc_bus.use_polling++; -#if 0 - ohci_activate(&sc->sc, act); - prcm_disablemodule(PRCM_USB); -#endif + /* FIXME */ sc->sc.sc_bus.use_polling--; break; case DVACT_RESUME: sc->sc.sc_bus.use_polling++; - prcm_enablemodule(PRCM_USB); -#if 0 - omehci_enable(sc); - ohci_activate(&sc->sc, act); -#endif + /* FIXME */ sc->sc.sc_bus.use_polling--; break; case DVACT_POWERDOWN: - ehci_reset(sc->sc); + ehci_reset(&sc->sc); break; } return 0; } -#if 0 -void -omehci_enable(struct omehci_softc *sc) -{ - u_int32_t hr; - - /* Full host reset */ - hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); - bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, - (hr & USBHC_HR_MASK) | USBHC_HR_FHR); - - DELAY(USBHC_RST_WAIT); - - hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); - bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, - (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR)); - - /* Force system bus interface reset */ - hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); - bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, - (hr & USBHC_HR_MASK) | USBHC_HR_FSBIR); - - while (bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR) & \ - USBHC_HR_FSBIR) - DELAY(3); - - /* Enable the ports (physically only one, only enable that one?) */ - hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); - bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, - (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSE)); - hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); - bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, - (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSEP2)); -} - void -omehci_disable(struct omehci_softc *sc) +omehci_v4_early_init() { - u_int32_t hr; + omgpio_set_dir(1, OMGPIO_DIR_OUT); + omgpio_clear_bit(1); + omgpio_set_dir(62, OMGPIO_DIR_OUT); + omgpio_clear_bit(62); - /* Full host reset */ - hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); - bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, - (hr & USBHC_HR_MASK) | USBHC_HR_FHR); + /* wait for power down */ + delay(1000); - DELAY(USBHC_RST_WAIT); + omgpio_set_bit(1); + omgpio_set_bit(62); - hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); - bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, - (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR)); + /* wait until powered up */ + delay(1000); } -#endif diff --git a/sys/arch/beagle/dev/omehcivar.h b/sys/arch/beagle/dev/omehcivar.h new file mode 100644 index 00000000000..ddb13578954 --- /dev/null +++ b/sys/arch/beagle/dev/omehcivar.h @@ -0,0 +1,230 @@ +/* + * Misc + */ +#define OMAP_HS_USB_PORTS 3 + +/* + * USB TTL Module + */ +#define OMAP_USBTLL_REVISION 0x0000 +#define OMAP_USBTLL_SYSCONFIG 0x0010 +#define OMAP_USBTLL_SYSSTATUS 0x0014 +#define OMAP_USBTLL_IRQSTATUS 0x0018 +#define OMAP_USBTLL_IRQENABLE 0x001C +#define OMAP_USBTLL_TLL_SHARED_CONF 0x0030 +#define OMAP_USBTLL_TLL_CHANNEL_CONF(i) (0x0040 + (0x04 * (i))) +#define OMAP_USBTLL_SAR_CNTX(i) (0x0400 + (0x04 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_ID_LO(i) (0x0800 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_ID_HI(i) (0x0801 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_PRODUCT_ID_LO(i) (0x0802 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_PRODUCT_ID_HI(i) (0x0803 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_FUNCTION_CTRL(i) (0x0804 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_FUNCTION_CTRL_SET(i) (0x0805 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_FUNCTION_CTRL_CLR(i) (0x0806 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_INTERFACE_CTRL(i) (0x0807 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_INTERFACE_CTRL_SET(i) (0x0808 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_INTERFACE_CTRL_CLR(i) (0x0809 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_OTG_CTRL(i) (0x080A + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_OTG_CTRL_SET(i) (0x080B + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_OTG_CTRL_CLR(i) (0x080C + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_RISE(i) (0x080D + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_RISE_SET(i) (0x080E + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_RISE_CLR(i) (0x080F + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_FALL(i) (0x0810 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_FALL_SET(i) (0x0811 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_FALL_CLR(i) (0x0812 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_STATUS(i) (0x0813 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_LATCH(i) (0x0814 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_DEBUG(i) (0x0815 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_SCRATCH_REGISTER(i) (0x0816 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_SCRATCH_REGISTER_SET(i) (0x0817 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_SCRATCH_REGISTER_CLR(i) (0x0818 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_EXTENDED_SET_ACCESS(i) (0x082F + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN(i) (0x0830 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN_SET(i) (0x0831 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN_CLR(i) (0x0832 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_STATUS(i) (0x0833 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_LATCH(i) (0x0834 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VSTATUS(i) (0x0835 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VSTATUS_SET(i) (0x0836 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VSTATUS_CLR(i) (0x0837 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_LATCH_NOCLR(i) (0x0838 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_INT_EN(i) (0x083B + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_INT_EN_SET(i) (0x083C + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_INT_EN_CLR(i) (0x083D + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_INT_STATUS(i) (0x083E + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_INT_LATCH(i) (0x083F + (0x100 * (i))) + + +/* + * USB Host Module + */ + +/* UHH */ +#define OMAP_USBHOST_UHH_REVISION 0x0000 +#define OMAP_USBHOST_UHH_SYSCONFIG 0x0010 +#define OMAP_USBHOST_UHH_SYSSTATUS 0x0014 +#define OMAP_USBHOST_UHH_HOSTCONFIG 0x0040 +#define OMAP_USBHOST_UHH_DEBUG_CSR 0x0044 + +/* EHCI */ +#define OMAP_USBHOST_HCCAPBASE 0x0000 +#define OMAP_USBHOST_HCSPARAMS 0x0004 +#define OMAP_USBHOST_HCCPARAMS 0x0008 +#define OMAP_USBHOST_USBCMD 0x0010 +#define OMAP_USBHOST_USBSTS 0x0014 +#define OMAP_USBHOST_USBINTR 0x0018 +#define OMAP_USBHOST_FRINDEX 0x001C +#define OMAP_USBHOST_CTRLDSSEGMENT 0x0020 +#define OMAP_USBHOST_PERIODICLISTBASE 0x0024 +#define OMAP_USBHOST_ASYNCLISTADDR 0x0028 +#define OMAP_USBHOST_CONFIGFLAG 0x0050 +#define OMAP_USBHOST_PORTSC(i) (0x0054 + (0x04 * (i))) +#define OMAP_USBHOST_INSNREG00 0x0090 +#define OMAP_USBHOST_INSNREG01 0x0094 +#define OMAP_USBHOST_INSNREG02 0x0098 +#define OMAP_USBHOST_INSNREG03 0x009C +#define OMAP_USBHOST_INSNREG04 0x00A0 +#define OMAP_USBHOST_INSNREG05_UTMI 0x00A4 +#define OMAP_USBHOST_INSNREG05_ULPI 0x00A4 +#define OMAP_USBHOST_INSNREG06 0x00A8 +#define OMAP_USBHOST_INSNREG07 0x00AC +#define OMAP_USBHOST_INSNREG08 0x00B0 + +#define OMAP_USBHOST_INSNREG04_DISABLE_UNSUSPEND (1 << 5) + +#define OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT 31 +#define OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT 24 +#define OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT 22 +#define OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT 16 +#define OMAP_USBHOST_INSNREG05_ULPI_EXTREGADD_SHIFT 8 +#define OMAP_USBHOST_INSNREG05_ULPI_WRDATA_SHIFT 0 + + + + + +/* TLL Register Set */ +#define TLL_SYSCONFIG_CACTIVITY (1UL << 8) +#define TLL_SYSCONFIG_SIDLE_SMART_IDLE (2UL << 3) +#define TLL_SYSCONFIG_SIDLE_NO_IDLE (1UL << 3) +#define TLL_SYSCONFIG_SIDLE_FORCED_IDLE (0UL << 3) +#define TLL_SYSCONFIG_ENAWAKEUP (1UL << 2) +#define TLL_SYSCONFIG_SOFTRESET (1UL << 1) +#define TLL_SYSCONFIG_AUTOIDLE (1UL << 0) + +#define TLL_SYSSTATUS_RESETDONE (1UL << 0) + +#define TLL_SHARED_CONF_USB_90D_DDR_EN (1UL << 6) +#define TLL_SHARED_CONF_USB_180D_SDR_EN (1UL << 5) +#define TLL_SHARED_CONF_USB_DIVRATIO_MASK (7UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_128 (7UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_64 (6UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_32 (5UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_16 (4UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_8 (3UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_4 (2UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_2 (1UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_1 (0UL << 2) +#define TLL_SHARED_CONF_FCLK_REQ (1UL << 1) +#define TLL_SHARED_CONF_FCLK_IS_ON (1UL << 0) + +#define TLL_CHANNEL_CONF_DRVVBUS (1UL << 16) +#define TLL_CHANNEL_CONF_CHRGVBUS (1UL << 15) +#define TLL_CHANNEL_CONF_ULPINOBITSTUFF (1UL << 11) +#define TLL_CHANNEL_CONF_ULPIAUTOIDLE (1UL << 10) +#define TLL_CHANNEL_CONF_UTMIAUTOIDLE (1UL << 9) +#define TLL_CHANNEL_CONF_ULPIDDRMODE (1UL << 8) +#define TLL_CHANNEL_CONF_ULPIOUTCLKMODE (1UL << 7) +#define TLL_CHANNEL_CONF_TLLFULLSPEED (1UL << 6) +#define TLL_CHANNEL_CONF_TLLCONNECT (1UL << 5) +#define TLL_CHANNEL_CONF_TLLATTACH (1UL << 4) +#define TLL_CHANNEL_CONF_UTMIISADEV (1UL << 3) +#define TLL_CHANNEL_CONF_CHANEN (1UL << 0) + + +/* UHH Register Set */ +#define UHH_SYSCONFIG_MIDLEMODE_MASK (3UL << 12) +#define UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY (2UL << 12) +#define UHH_SYSCONFIG_MIDLEMODE_NOSTANDBY (1UL << 12) +#define UHH_SYSCONFIG_MIDLEMODE_FORCESTANDBY (0UL << 12) +#define UHH_SYSCONFIG_CLOCKACTIVITY (1UL << 8) +#define UHH_SYSCONFIG_SIDLEMODE_MASK (3UL << 3) +#define UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE (2UL << 3) +#define UHH_SYSCONFIG_SIDLEMODE_NOIDLE (1UL << 3) +#define UHH_SYSCONFIG_SIDLEMODE_FORCEIDLE (0UL << 3) +#define UHH_SYSCONFIG_ENAWAKEUP (1UL << 2) +#define UHH_SYSCONFIG_SOFTRESET (1UL << 1) +#define UHH_SYSCONFIG_AUTOIDLE (1UL << 0) + +#define UHH_HOSTCONFIG_APP_START_CLK (1UL << 31) +#define UHH_HOSTCONFIG_P3_CONNECT_STATUS (1UL << 10) +#define UHH_HOSTCONFIG_P2_CONNECT_STATUS (1UL << 9) +#define UHH_HOSTCONFIG_P1_CONNECT_STATUS (1UL << 8) +#define UHH_HOSTCONFIG_ENA_INCR_ALIGN (1UL << 5) +#define UHH_HOSTCONFIG_ENA_INCR16 (1UL << 4) +#define UHH_HOSTCONFIG_ENA_INCR8 (1UL << 3) +#define UHH_HOSTCONFIG_ENA_INCR4 (1UL << 2) +#define UHH_HOSTCONFIG_AUTOPPD_ON_OVERCUR_EN (1UL << 1) +#define UHH_HOSTCONFIG_P1_ULPI_BYPASS (1UL << 0) + +/* The following are on rev2 (OMAP44xx) of the EHCI only */ +#define UHH_SYSCONFIG_IDLEMODE_MASK (3UL << 2) +#define UHH_SYSCONFIG_IDLEMODE_NOIDLE (1UL << 2) +#define UHH_SYSCONFIG_STANDBYMODE_MASK (3UL << 4) +#define UHH_SYSCONFIG_STANDBYMODE_NOSTDBY (1UL << 4) + +#define UHH_HOSTCONFIG_P1_MODE_MASK (3UL << 16) +#define UHH_HOSTCONFIG_P1_MODE_ULPI_PHY (0UL << 16) +#define UHH_HOSTCONFIG_P1_MODE_UTMI_PHY (1UL << 16) +#define UHH_HOSTCONFIG_P1_MODE_HSIC (3UL << 16) +#define UHH_HOSTCONFIG_P2_MODE_MASK (3UL << 18) +#define UHH_HOSTCONFIG_P2_MODE_ULPI_PHY (0UL << 18) +#define UHH_HOSTCONFIG_P2_MODE_UTMI_PHY (1UL << 18) +#define UHH_HOSTCONFIG_P2_MODE_HSIC (3UL << 18) + +#define ULPI_FUNC_CTRL_RESET (1 << 5) + +/*-------------------------------------------------------------------------*/ + +/* + * Macros for Set and Clear + * See ULPI 1.1 specification to find the registers with Set and Clear offsets + */ +#define ULPI_SET(a) (a + 1) +#define ULPI_CLR(a) (a + 2) + +/*-------------------------------------------------------------------------*/ + +/* + * Register Map + */ +#define ULPI_VENDOR_ID_LOW 0x00 +#define ULPI_VENDOR_ID_HIGH 0x01 +#define ULPI_PRODUCT_ID_LOW 0x02 +#define ULPI_PRODUCT_ID_HIGH 0x03 +#define ULPI_FUNC_CTRL 0x04 +#define ULPI_IFC_CTRL 0x07 +#define ULPI_OTG_CTRL 0x0a +#define ULPI_USB_INT_EN_RISE 0x0d +#define ULPI_USB_INT_EN_FALL 0x10 +#define ULPI_USB_INT_STS 0x13 +#define ULPI_USB_INT_LATCH 0x14 +#define ULPI_DEBUG 0x15 +#define ULPI_SCRATCH 0x16 + +/* + * Values of UHH_REVISION - Note: these are not given in the TRM but taken + * from the linux OMAP EHCI driver (thanks guys). It has been verified on + * a Panda and Beagle board. + */ +#define OMAP_EHCI_REV1 0x00000010 /* OMAP3 */ +#define OMAP_EHCI_REV2 0x50700100 /* OMAP4 */ + +#define EHCI_VENDORID_OMAP3 0x42fa05 +#define OMAP_EHCI_HC_DEVSTR "TI OMAP USB 2.0 controller" + +#define EHCI_HCD_OMAP_MODE_UNKNOWN 0 +#define EHCI_HCD_OMAP_MODE_PHY 1 +#define EHCI_HCD_OMAP_MODE_TLL 2 +#define EHCI_HCD_OMAP_MODE_HSIC 3 diff --git a/sys/arch/beagle/dev/prcm.c b/sys/arch/beagle/dev/prcm.c index 667dd6fdf18..98e649b0cbd 100644 --- a/sys/arch/beagle/dev/prcm.c +++ b/sys/arch/beagle/dev/prcm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: prcm.c,v 1.12 2013/05/21 16:47:54 bmercer Exp $ */ +/* $OpenBSD: prcm.c,v 1.13 2013/06/14 23:13:54 patrick Exp $ */ /* * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> * @@ -15,6 +15,35 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/*- + * Copyright (c) 2011 + * Ben Gray <ben.r.gray@gmail.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + /* * Driver for the Power, Reset and Clock Management Module (PRCM). */ @@ -34,6 +63,7 @@ #include <beagle/dev/am335x_prcmreg.h> #include <beagle/dev/omap3_prcmreg.h> +#include <beagle/dev/omap4_prcmreg.h> #define PRCM_REVISION 0x0800 #define PRCM_SYSCONFIG 0x0810 @@ -48,10 +78,15 @@ uint32_t prcm_fmask_addr[PRCM_REG_MAX]; struct prcm_softc { struct device sc_dev; bus_space_tag_t sc_iot; - bus_space_handle_t sc_ioh; + bus_space_handle_t sc_prcm; + bus_space_handle_t sc_cm1; + bus_space_handle_t sc_cm2; + void (*sc_setup)(struct prcm_softc *sc); void (*sc_enablemodule)(struct prcm_softc *sc, int mod); void (*sc_setclock)(struct prcm_softc *sc, int clock, int speed); + uint32_t cm1_avail; + uint32_t cm2_avail; }; int prcm_match(struct device *, void *, void *); @@ -67,6 +102,10 @@ void prcm_v3_setup(struct prcm_softc *); void prcm_v3_enablemodule(struct prcm_softc *, int); void prcm_v3_setclock(struct prcm_softc *, int, int); +void prcm_v4_enablemodule(struct prcm_softc *, int); +int prcm_v4_hsusbhost_activate(int); +int prcm_v4_hsusbhost_set_source(int, int); + struct cfattach prcm_ca = { sizeof (struct prcm_softc), NULL, prcm_attach }; @@ -84,29 +123,48 @@ prcm_attach(struct device *parent, struct device *self, void *args) sc->sc_iot = oa->oa_iot; - if (bus_space_map(sc->sc_iot, oa->oa_dev->mem[0].addr, - oa->oa_dev->mem[0].size, 0, &sc->sc_ioh)) - panic("prcm_attach: bus_space_map failed!"); - - reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PRCM_REVISION); - printf(" rev %d.%d\n", reg >> 4 & 0xf, reg & 0xf); - switch (board_id) { case BOARD_ID_AM335X_BEAGLEBONE: + sc->sc_setup = NULL; sc->sc_enablemodule = prcm_am335x_enablemodule; sc->sc_setclock = prcm_am335x_setclock; break; case BOARD_ID_OMAP3_BEAGLE: case BOARD_ID_OMAP3_OVERO: + sc->sc_setup = prcm_v3_setup; sc->sc_enablemodule = prcm_v3_enablemodule; sc->sc_setclock = prcm_v3_setclock; - prcm_v3_setup(sc); break; case BOARD_ID_OMAP4_PANDA: - sc->sc_enablemodule = NULL; + sc->sc_setup = NULL; + sc->sc_enablemodule = prcm_v4_enablemodule; sc->sc_setclock = NULL; + sc->cm1_avail = 1; + sc->cm2_avail = 1; break; } + + if (bus_space_map(sc->sc_iot, oa->oa_dev->mem[0].addr, + oa->oa_dev->mem[0].size, 0, &sc->sc_prcm)) + panic("prcm_attach: bus_space_map failed!"); + + if (sc->cm1_avail && + bus_space_map(sc->sc_iot, oa->oa_dev->mem[1].addr, + oa->oa_dev->mem[1].size, 0, &sc->sc_cm1)) + panic("prcm_attach: bus_space_map failed!"); + + if (sc->cm2_avail && + bus_space_map(sc->sc_iot, oa->oa_dev->mem[2].addr, + oa->oa_dev->mem[2].size, 0, &sc->sc_cm2)) + panic("prcm_attach: bus_space_map failed!"); + + reg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_REVISION); + printf(" rev %d.%d\n", reg >> 4 & 0xf, reg & 0xf); + + if (sc->sc_setup) + sc->sc_setup(sc); + + printf("\n"); } void @@ -154,20 +212,20 @@ prcm_am335x_setclock(struct prcm_softc *sc, int clock, int speed) /* set CLKSEL register */ if (clock == 1) { - oreg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, + oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_CLKSEL_TIMER2_CLK); mask = 3; reg = oreg & ~mask; reg |=0x02; - bus_space_write_4(sc->sc_iot, sc->sc_ioh, + bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_CLKSEL_TIMER2_CLK, reg); } else if (clock == 2) { - oreg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, + oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_CLKSEL_TIMER3_CLK); mask = 3; reg = oreg & ~mask; reg |=0x02; - bus_space_write_4(sc->sc_iot, sc->sc_ioh, + bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_CLKSEL_TIMER3_CLK, reg); } } @@ -178,16 +236,16 @@ prcm_v3_setclock(struct prcm_softc *sc, int clock, int speed) u_int32_t oreg, reg, mask; if (clock == 1) { - oreg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CM_CLKSEL_WKUP); + oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_WKUP); mask = 1; reg = (oreg &~mask) | (speed & mask); - bus_space_write_4(sc->sc_iot, sc->sc_ioh, CM_CLKSEL_WKUP, reg); + bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_WKUP, reg); } else if (clock >= 2 && clock <= 9) { int shift = (clock-2); - oreg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CM_CLKSEL_PER); + oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_PER); mask = 1 << (shift); reg = (oreg & ~mask) | ( (speed << shift) & mask); - bus_space_write_4(sc->sc_iot, sc->sc_ioh, CM_CLKSEL_PER, reg); + bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_PER, reg); } else panic("%s: invalid clock %d", __func__, clock); } @@ -241,13 +299,13 @@ prcm_am335x_enablemodule(struct prcm_softc *sc, int mod) /*set enable bits in CLKCTRL register */ reg = prcm_am335x_clkctrl(mod); - clkctrl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg); + clkctrl = bus_space_read_4(sc->sc_iot, sc->sc_prcm, reg); clkctrl &=~AM335X_CLKCTRL_MODULEMODE_MASK; clkctrl |= AM335X_CLKCTRL_MODULEMODE_ENABLE; - bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, clkctrl); + bus_space_write_4(sc->sc_iot, sc->sc_prcm, reg, clkctrl); /* wait until module is enabled */ - while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg) & 0x30000) + while (bus_space_read_4(sc->sc_iot, sc->sc_prcm, reg) & 0x30000) ; } @@ -268,16 +326,115 @@ prcm_v3_enablemodule(struct prcm_softc *sc, int mod) mbit = 1 << (bit & 0x1f); if (fmask & mbit) { /* dont access the register if bit isn't present */ - fclk = bus_space_read_4(sc->sc_iot, sc->sc_ioh, freg); - bus_space_write_4(sc->sc_iot, sc->sc_ioh, freg, fclk | mbit); + fclk = bus_space_read_4(sc->sc_iot, sc->sc_prcm, freg); + bus_space_write_4(sc->sc_iot, sc->sc_prcm, freg, fclk | mbit); } if (imask & mbit) { /* dont access the register if bit isn't present */ - iclk = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ireg); - bus_space_write_4(sc->sc_iot, sc->sc_ioh, ireg, iclk | mbit); + iclk = bus_space_read_4(sc->sc_iot, sc->sc_prcm, ireg); + bus_space_write_4(sc->sc_iot, sc->sc_prcm, ireg, iclk | mbit); } printf("\n"); } +void +prcm_v4_enablemodule(struct prcm_softc *sc, int mod) +{ + switch (mod) { + case PRCM_USBP1_PHY: + case PRCM_USBP2_PHY: + prcm_v4_hsusbhost_set_source(mod, 0); + case PRCM_USB: + case PRCM_USBTLL: + case PRCM_USBP1_UTMI: + case PRCM_USBP1_HSIC: + case PRCM_USBP2_UTMI: + case PRCM_USBP2_HSIC: + prcm_v4_hsusbhost_activate(mod); + return; + default: + panic("%s: module not found\n", __func__); + } +} + +int +prcm_v4_hsusbhost_activate(int type) +{ + struct prcm_softc *sc = prcm_cd.cd_devs[0]; + uint32_t i; + uint32_t clksel_reg_off; + uint32_t clksel, oclksel; + + switch (type) { + case PRCM_USB: + case PRCM_USBP1_PHY: + case PRCM_USBP2_PHY: + /* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */ + clksel_reg_off = O4_L3INIT_CM2_OFFSET + 0x58; + clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off); + oclksel = clksel; + /* Enable the module and also enable the optional func clocks */ + if (type == PRCM_USB) { + clksel &= ~O4_CLKCTRL_MODULEMODE_MASK; + clksel |= /*O4_CLKCTRL_MODULEMODE_ENABLE*/2; + + clksel |= (0x1 << 15); /* USB-HOST clock control: FUNC48MCLK */ + } + + break; + + default: + panic("%s: invalid type %d", type); + return (EINVAL); + } + bus_space_write_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off, clksel); + + /* Try MAX_MODULE_ENABLE_WAIT number of times to check if enabled */ + for (i = 0; i < O4_MAX_MODULE_ENABLE_WAIT; i++) { + clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off); + if ((clksel & O4_CLKCTRL_IDLEST_MASK) == O4_CLKCTRL_IDLEST_ENABLED) + break; + } + + /* Check the enabled state */ + if ((clksel & O4_CLKCTRL_IDLEST_MASK) != O4_CLKCTRL_IDLEST_ENABLED) { + printf("Error: HERE failed to enable module with clock %d\n", type); + printf("Error: 0x%08x => 0x%08x\n", clksel_reg_off, clksel); + return (ETIMEDOUT); + } + + return (0); +} + +int +prcm_v4_hsusbhost_set_source(int clk, int clksrc) +{ + struct prcm_softc *sc = prcm_cd.cd_devs[0]; + uint32_t clksel_reg_off; + uint32_t clksel; + unsigned int bit; + + if (clk == PRCM_USBP1_PHY) + bit = 24; + else if (clk != PRCM_USBP2_PHY) + bit = 25; + else + return (-EINVAL); + + /* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */ + clksel_reg_off = O4_L3INIT_CM2_OFFSET + 0x58; + clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off); + + /* XXX: Set the clock source to either external or internal */ + if (clksrc == 0) + clksel |= (0x1 << bit); + else + clksel &= ~(0x1 << bit); + + bus_space_write_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off, clksel); + + return (0); +} + /* * OMAP35xx Power, Reset, and Clock Management Reference Guide * (sprufa5.pdf) and AM/DM37x Multimedia Device Technical Reference @@ -297,10 +454,10 @@ prcm_setup_dpll5(struct prcm_softc *sc) * with 120 (sprugn4h.pdf, 13.4.11.4.1 SSC Configuration) */ val = ((120 & 0x7ff) << 8) | ((SYS_CLK - 1) & 0x7f); - bus_space_write_4(sc->sc_iot, sc->sc_ioh, CM_CLKSEL4_PLL, val); + bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL4_PLL, val); /* Clock divider from the PLL to the 120MHz clock. */ - bus_space_write_4(sc->sc_iot, sc->sc_ioh, CM_CLKSEL5_PLL, val); + bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL5_PLL, val); /* * spruf98o.pdf, page 2319: @@ -308,13 +465,13 @@ prcm_setup_dpll5(struct prcm_softc *sc) * EN_PERIPH2_DPLL is 0x7 */ val = (7 << 4) | (7 << 0); - bus_space_write_4(sc->sc_iot, sc->sc_ioh, CM_CLKEN2_PLL, val); + bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKEN2_PLL, val); /* Disable the interconnect clock auto-idle. */ - bus_space_write_4(sc->sc_iot, sc->sc_ioh, CM_AUTOIDLE2_PLL, 0x0); + bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_AUTOIDLE2_PLL, 0x0); /* Wait until DPLL5 is locked and there's clock activity. */ - while ((val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, + while ((val = bus_space_read_4(sc->sc_iot, sc->sc_prcm, CM_IDLEST_CKGEN) & 0x01) == 0x00) { #ifdef DIAGNOSTIC printf("CM_IDLEST_PLL = 0x%08x\n", val); diff --git a/sys/arch/beagle/dev/prcmvar.h b/sys/arch/beagle/dev/prcmvar.h index a65f0a4f516..f0e01494a0a 100644 --- a/sys/arch/beagle/dev/prcmvar.h +++ b/sys/arch/beagle/dev/prcmvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: prcmvar.h,v 1.5 2013/05/14 12:01:17 rapha Exp $ */ +/* $OpenBSD: prcmvar.h,v 1.6 2013/06/14 23:13:54 patrick Exp $ */ /* * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> * @@ -29,7 +29,13 @@ enum PRCM_MODULES { PRCM_TIMER3, PRCM_MMC, PRCM_USB, - PRCM_USBTLL + PRCM_USBTLL, + PRCM_USBP1_PHY, + PRCM_USBP1_UTMI, + PRCM_USBP1_HSIC, + PRCM_USBP2_PHY, + PRCM_USBP2_UTMI, + PRCM_USBP2_HSIC }; #define PRCM_REG_MAX 6 |