summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2013-06-14 23:13:55 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2013-06-14 23:13:55 +0000
commitdb98ae4f83496c349fc19a2e27ba4e46f541a014 (patch)
treeeb88f201c93f920d307c41c5db916d1148075695
parent4b69549b61f04d4c27aa5550c1c2d2034929f3e7 (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.c4
-rw-r--r--sys/arch/beagle/dev/omap4.c49
-rw-r--r--sys/arch/beagle/dev/omap4_prcmreg.h27
-rw-r--r--sys/arch/beagle/dev/omehci.c444
-rw-r--r--sys/arch/beagle/dev/omehcivar.h230
-rw-r--r--sys/arch/beagle/dev/prcm.c219
-rw-r--r--sys/arch/beagle/dev/prcmvar.h10
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