From b99e71cc6469a0c2f278bf32b8eedb1e6c1d76a4 Mon Sep 17 00:00:00 2001 From: jmcneill Date: Wed, 30 Oct 2019 21:41:40 +0000 Subject: [PATCH] Add OMAP3 USB support. --- sys/arch/arm/ti/files.ti | 13 ++- sys/arch/arm/ti/omap3_cm.c | 153 +++++++++++++++---------- sys/arch/arm/ti/ti_ehci.c | 157 +++++++++++++++++++++++++ sys/arch/arm/ti/ti_prcm.h | 10 +- sys/arch/arm/ti/ti_usb.c | 221 ++++++++++++++++++++++++++++++++++++ sys/arch/arm/ti/ti_usbtll.c | 203 +++++++++++++++++++++++++++++++++ 6 files changed, 695 insertions(+), 62 deletions(-) create mode 100644 sys/arch/arm/ti/ti_ehci.c create mode 100644 sys/arch/arm/ti/ti_usb.c create mode 100644 sys/arch/arm/ti/ti_usbtll.c diff --git a/sys/arch/arm/ti/files.ti b/sys/arch/arm/ti/files.ti index 032cefa4ca3a..d8008534254d 100644 --- a/sys/arch/arm/ti/files.ti +++ b/sys/arch/arm/ti/files.ti @@ -1,4 +1,4 @@ -# $NetBSD: files.ti,v 1.16 2019/10/29 22:19:13 jmcneill Exp $ +# $NetBSD: files.ti,v 1.17 2019/10/30 21:41:40 jmcneill Exp $ # file arch/arm/ti/ti_cpufreq.c soc_ti @@ -88,6 +88,17 @@ device tiotg { } : fdt attach tiotg at fdt with ti_otg file arch/arm/ti/ti_otg.c ti_otg +device tiusb { } : fdt +attach tiusb at fdt with ti_usb +file arch/arm/ti/ti_usb.c ti_usb + +device tiusbtll +attach tiusbtll at fdt with ti_usbtll +file arch/arm/ti/ti_usbtll.c ti_usbtll + +attach ehci at fdt with ti_ehci +file arch/arm/ti/ti_ehci.c ti_ehci + attach motg at fdt with ti_motg file arch/arm/ti/ti_motg.c ti_motg diff --git a/sys/arch/arm/ti/omap3_cm.c b/sys/arch/arm/ti/omap3_cm.c index a0a233e3770a..1e7e9ee80413 100644 --- a/sys/arch/arm/ti/omap3_cm.c +++ b/sys/arch/arm/ti/omap3_cm.c @@ -1,4 +1,4 @@ -/* $NetBSD: omap3_cm.c,v 1.1 2019/10/29 22:19:13 jmcneill Exp $ */ +/* $NetBSD: omap3_cm.c,v 1.2 2019/10/30 21:41:40 jmcneill Exp $ */ /*- * Copyright (c) 2017 Jared McNeill @@ -28,7 +28,7 @@ #include -__KERNEL_RCSID(1, "$NetBSD: omap3_cm.c,v 1.1 2019/10/29 22:19:13 jmcneill Exp $"); +__KERNEL_RCSID(1, "$NetBSD: omap3_cm.c,v 1.2 2019/10/30 21:41:40 jmcneill Exp $"); #include #include @@ -43,11 +43,20 @@ __KERNEL_RCSID(1, "$NetBSD: omap3_cm.c,v 1.1 2019/10/29 22:19:13 jmcneill Exp $" #define CM_CORE1_BASE 0x0a00 #define CM_CORE3_BASE 0x0a08 #define CM_WKUP_BASE 0x0c00 +#define CM_CLK_CTRL_REG_BASE 0x0d00 #define CM_PER_BASE 0x1000 #define CM_USBHOST_BASE 0x1400 #define CM_FCLKEN 0x00 #define CM_ICLKEN 0x10 +#define CM_AUTOIDLE 0x30 +#define CM_CLKSEL 0x40 + +#define CM_CLKEN2_PLL 0x04 +#define CM_IDLEST2_CKGEN 0x24 +#define CM_AUTOIDLE2_PLL 0x34 +#define CM_CLKSEL4_PLL 0x4c +#define CM_CLKSEL5_PLL 0x50 static int omap3_cm_match(device_t, cfdata_t, void *); static void omap3_cm_attach(device_t, device_t, void *); @@ -71,19 +80,25 @@ omap3_cm_hwmod_enable(struct ti_prcm_softc *sc, struct ti_prcm_clk *tc, int enab val &= ~tc->u.hwmod.mask; PRCM_WRITE(sc, tc->u.hwmod.reg + CM_ICLKEN, val); + if (tc->u.hwmod.flags & TI_HWMOD_DISABLE_AUTOIDLE) { + val = PRCM_READ(sc, tc->u.hwmod.reg + CM_AUTOIDLE); + val &= ~tc->u.hwmod.mask; + PRCM_WRITE(sc, tc->u.hwmod.reg + CM_AUTOIDLE, val); + } + return 0; } -#define OMAP3_CM_HWMOD_CORE1(_name, _bit, _parent) \ - TI_PRCM_HWMOD_MASK((_name), CM_CORE1_BASE, __BIT(_bit), (_parent), omap3_cm_hwmod_enable) -#define OMAP3_CM_HWMOD_CORE3(_name, _bit, _parent) \ - TI_PRCM_HWMOD_MASK((_name), CM_CORE3_BASE, __BIT(_bit), (_parent), omap3_cm_hwmod_enable) -#define OMAP3_CM_HWMOD_WKUP(_name, _bit, _parent) \ - TI_PRCM_HWMOD_MASK((_name), CM_WKUP_BASE, __BIT(_bit), (_parent), omap3_cm_hwmod_enable) -#define OMAP3_CM_HWMOD_PER(_name, _bit, _parent) \ - TI_PRCM_HWMOD_MASK((_name), CM_PER_BASE, __BIT(_bit), (_parent), omap3_cm_hwmod_enable) -#define OMAP3_CM_HWMOD_USBHOST(_name, _mask, _parent) \ - TI_PRCM_HWMOD_MASK((_name), CM_USBHOST_BASE, (_mask), (_parent), omap3_cm_hwmod_enable) +#define OMAP3_CM_HWMOD_CORE1(_name, _bit, _parent, _flags) \ + TI_PRCM_HWMOD_MASK((_name), CM_CORE1_BASE, __BIT(_bit), (_parent), omap3_cm_hwmod_enable, (_flags)) +#define OMAP3_CM_HWMOD_CORE3(_name, _bit, _parent, _flags) \ + TI_PRCM_HWMOD_MASK((_name), CM_CORE3_BASE, __BIT(_bit), (_parent), omap3_cm_hwmod_enable, (_flags)) +#define OMAP3_CM_HWMOD_WKUP(_name, _bit, _parent, _flags) \ + TI_PRCM_HWMOD_MASK((_name), CM_WKUP_BASE, __BIT(_bit), (_parent), omap3_cm_hwmod_enable, (_flags)) +#define OMAP3_CM_HWMOD_PER(_name, _bit, _parent, _flags) \ + TI_PRCM_HWMOD_MASK((_name), CM_PER_BASE, __BIT(_bit), (_parent), omap3_cm_hwmod_enable, (_flags)) +#define OMAP3_CM_HWMOD_USBHOST(_name, _bit, _parent, _flags) \ + TI_PRCM_HWMOD_MASK((_name), CM_USBHOST_BASE, __BIT(_bit), (_parent), omap3_cm_hwmod_enable, (_flags)) static const char * const compatible[] = { "ti,omap3-cm", @@ -96,59 +111,79 @@ CFATTACH_DECL_NEW(omap3_cm, sizeof(struct ti_prcm_softc), static struct ti_prcm_clk omap3_cm_clks[] = { /* XXX until we get a proper clock tree */ TI_PRCM_FIXED("FIXED_32K", 32768), - TI_PRCM_FIXED("FIXED_48MHZ", 48000000), - TI_PRCM_FIXED("FIXED_96MHZ", 96000000), - TI_PRCM_FIXED_FACTOR("PERIPH_CLK", 1, 1, "FIXED_48MHZ"), - TI_PRCM_FIXED_FACTOR("MMC_CLK", 1, 1, "FIXED_96MHZ"), + TI_PRCM_FIXED("SYS_CLK", 13000000), + TI_PRCM_FIXED("MMC_CLK", 96000000), + TI_PRCM_FIXED_FACTOR("PERIPH_CLK", 1, 1, "SYS_CLK"), - OMAP3_CM_HWMOD_CORE1("usb_otg_hs", 4, "PERIPH_CLK"), - OMAP3_CM_HWMOD_CORE1("mcbsp1", 9, "PERIPH_CLK"), - OMAP3_CM_HWMOD_CORE1("mcbsp5", 10, "PERIPH_CLK"), - OMAP3_CM_HWMOD_CORE1("timer10", 11, "PERIPH_CLK"), - OMAP3_CM_HWMOD_CORE1("timer11", 12, "PERIPH_CLK"), - OMAP3_CM_HWMOD_CORE1("uart1", 13, "PERIPH_CLK"), - OMAP3_CM_HWMOD_CORE1("uart2", 14, "PERIPH_CLK"), - OMAP3_CM_HWMOD_CORE1("i2c1", 15, "PERIPH_CLK"), - OMAP3_CM_HWMOD_CORE1("i2c2", 16, "PERIPH_CLK"), - OMAP3_CM_HWMOD_CORE1("i2c3", 17, "PERIPH_CLK"), - OMAP3_CM_HWMOD_CORE1("mcspi1", 18, "PERIPH_CLK"), - OMAP3_CM_HWMOD_CORE1("mcspi2", 19, "PERIPH_CLK"), - OMAP3_CM_HWMOD_CORE1("mcspi3", 20, "PERIPH_CLK"), - OMAP3_CM_HWMOD_CORE1("mcspi4", 21, "PERIPH_CLK"), - OMAP3_CM_HWMOD_CORE1("hdq1w", 22, "PERIPH_CLK"), - OMAP3_CM_HWMOD_CORE1("mmc1", 24, "MMC_CLK"), - OMAP3_CM_HWMOD_CORE1("mmc2", 25, "MMC_CLK"), - OMAP3_CM_HWMOD_CORE1("mmc3", 30, "MMC_CLK"), + OMAP3_CM_HWMOD_CORE1("usb_otg_hs", 4, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_CORE1("mcbsp1", 9, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_CORE1("mcbsp5", 10, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_CORE1("timer10", 11, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_CORE1("timer11", 12, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_CORE1("uart1", 13, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_CORE1("uart2", 14, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_CORE1("i2c1", 15, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_CORE1("i2c2", 16, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_CORE1("i2c3", 17, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_CORE1("mcspi1", 18, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_CORE1("mcspi2", 19, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_CORE1("mcspi3", 20, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_CORE1("mcspi4", 21, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_CORE1("hdq1w", 22, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_CORE1("mmc1", 24, "MMC_CLK", 0), + OMAP3_CM_HWMOD_CORE1("mmc2", 25, "MMC_CLK", 0), + OMAP3_CM_HWMOD_CORE1("mmc3", 30, "MMC_CLK", 0), - OMAP3_CM_HWMOD_CORE3("usb_tll_hs", 2, "PERIPH_CLK"), + OMAP3_CM_HWMOD_CORE3("usb_tll_hs", 2, "PERIPH_CLK", TI_HWMOD_DISABLE_AUTOIDLE), - OMAP3_CM_HWMOD_WKUP("timer1", 0, "PERIPH_CLK"), - OMAP3_CM_HWMOD_WKUP("counter_32k", 2, "FIXED_32K"), - OMAP3_CM_HWMOD_WKUP("gpio1", 3, "PERIPH_CLK"), - OMAP3_CM_HWMOD_WKUP("wd_timer2", 5, "FIXED_32K"), + OMAP3_CM_HWMOD_WKUP("timer1", 0, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_WKUP("counter_32k", 2, "FIXED_32K", 0), + OMAP3_CM_HWMOD_WKUP("gpio1", 3, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_WKUP("wd_timer2", 5, "FIXED_32K", 0), - OMAP3_CM_HWMOD_PER("mcbsp2", 0, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("mcbsp3", 1, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("mcbsp4", 2, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("timer2", 3, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("timer3", 4, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("timer4", 5, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("timer5", 6, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("timer6", 7, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("timer7", 8, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("timer8", 9, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("timer9", 10, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("uart3", 11, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("wd_timer3", 12, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("gpio2", 13, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("gpio3", 14, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("gpio4", 15, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("gpio5", 16, "PERIPH_CLK"), - OMAP3_CM_HWMOD_PER("gpio6", 17, "PERIPH_CLK"), + OMAP3_CM_HWMOD_PER("mcbsp2", 0, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("mcbsp3", 1, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("mcbsp4", 2, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("timer2", 3, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("timer3", 4, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("timer4", 5, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("timer5", 6, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("timer6", 7, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("timer7", 8, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("timer8", 9, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("timer9", 10, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("uart3", 11, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("wd_timer3", 12, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("gpio2", 13, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("gpio3", 14, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("gpio4", 15, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("gpio5", 16, "PERIPH_CLK", 0), + OMAP3_CM_HWMOD_PER("gpio6", 17, "PERIPH_CLK", 0), - OMAP3_CM_HWMOD_USBHOST("usb_host_hs", __BITS(1,0), "PERIPH_CLK"), + OMAP3_CM_HWMOD_USBHOST("usb_host_hs", 0, "PERIPH_CLK", 0), }; +static void +omap3_cm_initclocks(struct ti_prcm_softc *sc) +{ + uint32_t val; + + /* Select SYS_CLK for GPTIMER 2 and 3 */ + val = PRCM_READ(sc, CM_PER_BASE + CM_CLKSEL); + val |= __BIT(0); /* CLKSEL_GPT2 0x1: source is SYS_CLK */ + val |= __BIT(1); /* CLKSEL_GPT3 0x1: source is SYS_CLK */ + PRCM_WRITE(sc, CM_PER_BASE + CM_CLKSEL, val); + + /* Enable DPLL5 */ + const u_int m = 443, n = 11, m2 = 4; + PRCM_WRITE(sc, CM_CLK_CTRL_REG_BASE + CM_CLKEN2_PLL, (0x4 << 4) | 0x7); + PRCM_WRITE(sc, CM_CLK_CTRL_REG_BASE + CM_CLKSEL4_PLL, (m << 8) | n); + PRCM_WRITE(sc, CM_CLK_CTRL_REG_BASE + CM_CLKSEL5_PLL, m2); + PRCM_WRITE(sc, CM_CLK_CTRL_REG_BASE + CM_AUTOIDLE2_PLL, 1); + while ((PRCM_READ(sc, CM_CLK_CTRL_REG_BASE + CM_IDLEST2_CKGEN) & 1) == 0) + delay(100); +} + static int omap3_cm_match(device_t parent, cfdata_t cf, void *aux) { @@ -177,6 +212,8 @@ omap3_cm_attach(device_t parent, device_t self, void *aux) aprint_naive("\n"); aprint_normal(": OMAP3xxx CM\n"); + omap3_cm_initclocks(sc); + clocks = of_find_firstchild_byname(sc->sc_phandle, "clocks"); if (clocks > 0) fdt_add_bus(self, clocks, faa); diff --git a/sys/arch/arm/ti/ti_ehci.c b/sys/arch/arm/ti/ti_ehci.c new file mode 100644 index 000000000000..e67c6a36f7a6 --- /dev/null +++ b/sys/arch/arm/ti/ti_ehci.c @@ -0,0 +1,157 @@ +/* $NetBSD: ti_ehci.c,v 1.1 2019/10/30 21:41:40 jmcneill Exp $ */ + +/*- + * Copyright (c) 2015-2019 Jared McNeill + * 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 THE AUTHOR ``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 THE AUTHOR 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 +__KERNEL_RCSID(0, "$NetBSD: ti_ehci.c,v 1.1 2019/10/30 21:41:40 jmcneill Exp $"); + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define TI_EHCI_NPORTS 3 + +static int ti_ehci_match(device_t, cfdata_t, void *); +static void ti_ehci_attach(device_t, device_t, void *); + +CFATTACH_DECL2_NEW(ti_ehci, sizeof(struct ehci_softc), + ti_ehci_match, ti_ehci_attach, NULL, + ehci_activate, NULL, ehci_childdet); + +static int +ti_ehci_match(device_t parent, cfdata_t cf, void *aux) +{ + const char * const compatible[] = { + "ti,ehci-omap", + NULL + }; + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +ti_ehci_attach(device_t parent, device_t self, void *aux) +{ + struct ehci_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + struct fdtbus_reset *rst; + struct fdtbus_phy *phy; + struct clk *clk; + char intrstr[128]; + bus_addr_t addr; + bus_size_t size; + int error; + void *ih; + u_int n; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + /* Enable clocks */ + for (n = 0; (clk = fdtbus_clock_get_index(phandle, n)) != NULL; n++) + if (clk_enable(clk) != 0) { + aprint_error(": couldn't enable clock #%d\n", n); + return; + } + /* De-assert resets */ + for (n = 0; (rst = fdtbus_reset_get_index(phandle, n)) != NULL; n++) + if (fdtbus_reset_deassert(rst) != 0) { + aprint_error(": couldn't de-assert reset #%d\n", n); + return; + } + + sc->sc_dev = self; + sc->sc_bus.ub_hcpriv = sc; + sc->sc_bus.ub_dmatag = faa->faa_dmat; + sc->sc_bus.ub_revision = USBREV_2_0; + if (of_hasprop(phandle, "has-transaction-translator")) + sc->sc_flags |= EHCIF_ETTF; + else + sc->sc_ncomp = 1; + sc->sc_size = size; + sc->iot = faa->faa_bst; + if (bus_space_map(sc->iot, addr, size, 0, &sc->ioh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + + aprint_naive("\n"); + aprint_normal(": EHCI\n"); + + /* Enable PHYs */ + for (n = 0; n < TI_EHCI_NPORTS; n++) { + phy = fdtbus_phy_get_index(phandle, n); + if (phy && fdtbus_phy_enable(phy, true) != 0) { + aprint_error(": couldn't enable phy\n"); + return; + } + } + + /* Disable interrupts */ + sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH); + EOWRITE4(sc, EHCI_USBINTR, 0); + + if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { + aprint_error_dev(self, "failed to decode interrupt\n"); + return; + } + + ih = fdtbus_intr_establish(phandle, 0, IPL_USB, FDT_INTR_MPSAFE, + ehci_intr, sc); + if (ih == NULL) { + aprint_error_dev(self, "couldn't establish interrupt on %s\n", + intrstr); + return; + } + aprint_normal_dev(self, "interrupting on %s\n", intrstr); + + error = ehci_init(sc); + if (error) { + aprint_error_dev(self, "init failed, error = %d\n", error); + return; + } + + pmf_device_register1(self, NULL, NULL, ehci_shutdown); + + sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint); +} diff --git a/sys/arch/arm/ti/ti_prcm.h b/sys/arch/arm/ti/ti_prcm.h index ca44da2b679e..d433b3f5cdad 100644 --- a/sys/arch/arm/ti/ti_prcm.h +++ b/sys/arch/arm/ti/ti_prcm.h @@ -1,4 +1,4 @@ -/* $NetBSD: ti_prcm.h,v 1.3 2019/10/29 22:19:13 jmcneill Exp $ */ +/* $NetBSD: ti_prcm.h,v 1.4 2019/10/30 21:41:40 jmcneill Exp $ */ /*- * Copyright (c) 2017 Jared McNeill @@ -57,8 +57,11 @@ struct ti_prcm_hwmod { bus_size_t reg; uint32_t mask; const char *parent; + u_int flags; }; +#define TI_HWMOD_DISABLE_AUTOIDLE 0x01 + struct ti_prcm_clk { struct clk base; enum ti_prcm_clktype type; @@ -138,13 +141,14 @@ ti_prcm_hwmod_get_parent(struct ti_prcm_softc *sc, struct ti_prcm_clk *tc) } #define TI_PRCM_HWMOD(_name, _reg, _parent, _enable) \ - TI_PRCM_HWMOD_MASK(_name, _reg, 0, _parent, _enable) + TI_PRCM_HWMOD_MASK(_name, _reg, 0, _parent, _enable, 0) -#define TI_PRCM_HWMOD_MASK(_name, _reg, _mask, _parent, _enable) \ +#define TI_PRCM_HWMOD_MASK(_name, _reg, _mask, _parent, _enable, _flags) \ { \ .type = TI_PRCM_HWMOD, .base.name = (_name), \ .u.hwmod.reg = (_reg), \ .u.hwmod.mask = (_mask), \ + .u.hwmod.flags = (_flags), \ .u.hwmod.parent = (_parent), \ .enable = (_enable), \ .get_parent = ti_prcm_hwmod_get_parent, \ diff --git a/sys/arch/arm/ti/ti_usb.c b/sys/arch/arm/ti/ti_usb.c new file mode 100644 index 000000000000..51e9d31bc5f5 --- /dev/null +++ b/sys/arch/arm/ti/ti_usb.c @@ -0,0 +1,221 @@ +/* $NetBSD: ti_usb.c,v 1.1 2019/10/30 21:41:40 jmcneill Exp $ */ + +/*- + * Copyright (c) 2019 Jared McNeill + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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 +__KERNEL_RCSID(0, "$NetBSD: ti_usb.c,v 1.1 2019/10/30 21:41:40 jmcneill Exp $"); + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define UHH_SYSCONFIG 0x10 +#define UHH_SYSCONFIG_MIDLEMODE_MASK 0x00003000 +#define UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY 0x00002000 +#define UHH_SYSCONFIG_CLOCKACTIVITY 0x00000100 +#define UHH_SYSCONFIG_SIDLEMODE_MASK 0x00000018 +#define UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE 0x00000008 +#define UHH_SYSCONFIG_ENAWAKEUP 0x00000004 +#define UHH_SYSCONFIG_SOFTRESET 0x00000002 +#define UHH_SYSCONFIG_AUTOIDLE 0x00000001 + +#define UHH_HOSTCONFIG 0x40 +#define UHH_HOSTCONFIG_APP_START_CLK __BIT(31) +#define UHH_HOSTCONFIG_P3_MODE __BITS(21,20) +#define UHH_HOSTCONFIG_P2_MODE __BITS(19,18) +#define UHH_HOSTCONFIG_P1_MODE __BITS(17,16) +#define UHH_HOSTCONFIG_PMODE_ULPI_PHY 0 +#define UHH_HOSTCONFIG_PMODE_UTMI 1 +#define UHH_HOSTCONFIG_PMODE_HSIC 3 +#define UHH_HOSTCONFIG_P3_ULPI_BYPASS __BIT(12) +#define UHH_HOSTCONFIG_P2_ULPI_BYPASS __BIT(11) +#define UHH_HOSTCONFIG_P3_CONNECT_STATUS __BIT(10) +#define UHH_HOSTCONFIG_P2_CONNECT_STATUS __BIT(9) +#define UHH_HOSTCONFIG_P1_CONNECT_STATUS __BIT(8) +#define UHH_HOSTCONFIG_ENA_INCR_ALIGN __BIT(5) +#define UHH_HOSTCONFIG_ENA_INCR16 __BIT(4) +#define UHH_HOSTCONFIG_ENA_INCR8 __BIT(3) +#define UHH_HOSTCONFIG_ENA_INCR4 __BIT(2) +#define UHH_HOSTCONFIG_AUTOPPD_ON_OVERCUR_EN __BIT(1) +#define UHH_HOSTCONFIG_P1_ULPI_BYPASS __BIT(0) + +extern void tl_usbtll_enable_port(u_int); + +static const char * const compatible[] = { + "ti,usbhs-host", + NULL +}; + +#define TI_USB_NPORTS 3 + +enum { + CONNECT_STATUS, + ULPI_BYPASS, + TI_USB_NBITS +}; + +static const uint32_t ti_usb_portbits[TI_USB_NPORTS][TI_USB_NBITS] = { + [0] = { + [CONNECT_STATUS] = UHH_HOSTCONFIG_P1_CONNECT_STATUS, + [ULPI_BYPASS] = UHH_HOSTCONFIG_P1_ULPI_BYPASS, + }, + [1] = { + [CONNECT_STATUS] = UHH_HOSTCONFIG_P2_CONNECT_STATUS, + [ULPI_BYPASS] = UHH_HOSTCONFIG_P2_ULPI_BYPASS, + }, + [2] = { + [CONNECT_STATUS] = UHH_HOSTCONFIG_P3_CONNECT_STATUS, + [ULPI_BYPASS] = UHH_HOSTCONFIG_P3_ULPI_BYPASS, + }, +}; + +enum { + PORT_UNUSED, + PORT_EHCI_PHY, + PORT_EHCI_TLL, + PORT_EHCI_HSIC, +}; + +struct ti_usb_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + + u_int sc_portmode[TI_USB_NPORTS]; +}; + +static int ti_usb_match(device_t, cfdata_t, void *); +static void ti_usb_attach(device_t, device_t, void *); + +CFATTACH_DECL_NEW(ti_usb, sizeof(struct ti_usb_softc), + ti_usb_match, ti_usb_attach, NULL, NULL); + +#define RD4(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define WR4(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +static void +ti_usb_init(struct ti_usb_softc *sc) +{ + uint32_t val; + int port; + + val = RD4(sc, UHH_SYSCONFIG); + val &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK|UHH_SYSCONFIG_MIDLEMODE_MASK); + val |= UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY; + val |= UHH_SYSCONFIG_CLOCKACTIVITY; + val |= UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE; + val |= UHH_SYSCONFIG_ENAWAKEUP; + val &= ~UHH_SYSCONFIG_AUTOIDLE; + WR4(sc, UHH_SYSCONFIG, val); + + val = RD4(sc, UHH_SYSCONFIG); + + val = RD4(sc, UHH_HOSTCONFIG); + val |= UHH_HOSTCONFIG_ENA_INCR16; + val |= UHH_HOSTCONFIG_ENA_INCR8; + val |= UHH_HOSTCONFIG_ENA_INCR4; + val |= UHH_HOSTCONFIG_APP_START_CLK; + val &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN; + for (port = 0; port < TI_USB_NPORTS; port++) { + if (sc->sc_portmode[port] == PORT_UNUSED) + val &= ~ti_usb_portbits[port][CONNECT_STATUS]; + if (sc->sc_portmode[port] == PORT_EHCI_PHY) + val &= ~ti_usb_portbits[port][ULPI_BYPASS]; + else + val |= ti_usb_portbits[port][ULPI_BYPASS]; + } + WR4(sc, UHH_HOSTCONFIG, val); +} + +static int +ti_usb_match(device_t parent, cfdata_t match, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +ti_usb_attach(device_t parent, device_t self, void *aux) +{ + struct ti_usb_softc *sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + bus_addr_t addr; + bus_size_t size; + char propname[16]; + const char *portmode; + int port; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + if (ti_prcm_enable_hwmod(phandle, 0) != 0) { + aprint_error(": couldn't enable module\n"); + return; + } + + sc->sc_dev = self; + sc->sc_bst = faa->faa_bst; + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + + for (port = 0; port < TI_USB_NPORTS; port++) { + snprintf(propname, sizeof(propname), "port%d-mode", port + 1); + portmode = fdtbus_get_string(phandle, propname); + if (portmode == NULL) + continue; + if (strcmp(portmode, "ehci-phy") == 0) + sc->sc_portmode[port] = PORT_EHCI_PHY; + else if (strcmp(portmode, "ehci-tll") == 0) + sc->sc_portmode[port] = PORT_EHCI_TLL; + else if (strcmp(portmode, "ehci-hsic") == 0) + sc->sc_portmode[port] = PORT_EHCI_HSIC; + + if (sc->sc_portmode[port] != PORT_UNUSED) + tl_usbtll_enable_port(port); + } + + aprint_naive("\n"); + aprint_normal(": OMAP HS USB Host\n"); + + ti_usb_init(sc); + + fdt_add_bus(self, phandle, faa); +} diff --git a/sys/arch/arm/ti/ti_usbtll.c b/sys/arch/arm/ti/ti_usbtll.c new file mode 100644 index 000000000000..7d5900cb2f1d --- /dev/null +++ b/sys/arch/arm/ti/ti_usbtll.c @@ -0,0 +1,203 @@ +/* $NetBSD: ti_usbtll.c,v 1.1 2019/10/30 21:41:40 jmcneill Exp $ */ + +/*- + * Copyright (c) 2019 Jared McNeill + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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 +__KERNEL_RCSID(0, "$NetBSD: ti_usbtll.c,v 1.1 2019/10/30 21:41:40 jmcneill Exp $"); + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define USBTLL_SYSCONFIG 0x10 +#define USBTLL_SYSCONFIG_CLOCKACTIVITY 0x00000100 +#define USBTLL_SYSCONFIG_SIDLEMODE 0x00000018 +#define USBTLL_SYSCONFIG_ENAWAKEUP 0x00000004 +#define USBTLL_SYSCONFIG_SOFTRESET 0x00000002 +#define USBTLL_SYSCONFIG_AUTOIDLE 0x00000001 + +#define USBTLL_SYSSTATUS 0x14 +#define USBTLL_SYSSTATUS_RESETDONE 0x00000001 + +#define USBTLL_SHARED_CONF 0x30 +#define USBTLL_SHARED_CONF_USB_90D_DDR_EN 0x00000040 +#define USBTLL_SHARED_CONF_USB_180D_SDR_EN 0x00000020 +#define USBTLL_SHARED_CONF_USB_DIVRATIO 0x0000001c +#define USBTLL_SHARED_CONF_FCLK_REQ 0x00000002 +#define USBTLL_SHARED_CONF_FCLK_IS_ON 0x00000001 + +#define USBTLL_CHANNEL_CONF(i) (0x40 + (0x04 * (i))) +#define USBTLL_CHANNEL_CONF_FSLSLINESTATE 0x30000000 +#define USBTLL_CHANNEL_CONF_FSLSMODE 0x0f000000 +#define USBTLL_CHANNEL_CONF_TESTTXSE0 0x00100000 +#define USBTLL_CHANNEL_CONF_TESTTXDAT 0x00080000 +#define USBTLL_CHANNEL_CONF_TESTTXEN 0x00040000 +#define USBTLL_CHANNEL_CONF_TESTEN 0x00020000 +#define USBTLL_CHANNEL_CONF_DRVVBUS 0x00010000 +#define USBTLL_CHANNEL_CONF_CHRGVBUS 0x00008000 +#define USBTLL_CHANNEL_CONF_ULPINOBITSTUFF 0x00000800 +#define USBTLL_CHANNEL_CONF_ULPIAUTOIDLE 0x00000400 +#define USBTLL_CHANNEL_CONF_UTMIAUTOIDLE 0x00000200 +#define USBTLL_CHANNEL_CONF_ULPIDDRMODE 0x00000100 +#define USBTLL_CHANNEL_CONF_ULPIOUTCLKMODE 0x00000080 +#define USBTLL_CHANNEL_CONF_TLLFULLSPEED 0x00000040 +#define USBTLL_CHANNEL_CONF_TLLCONNECT 0x00000020 +#define USBTLL_CHANNEL_CONF_TLLATTACH 0x00000010 +#define USBTLL_CHANNEL_CONF_UTMIISADEV 0x00000008 +#define USBTLL_CHANNEL_CONF_CHANMODE 0x00000006 +#define USBTLL_CHANNEL_CONF_CHANEN 0x00000001 + +static const char * const compatible[] = { + "ti,usbhs-tll", + NULL +}; + +struct ti_usbtll_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; +}; + +static int ti_usbtll_match(device_t, cfdata_t, void *); +static void ti_usbtll_attach(device_t, device_t, void *); + +CFATTACH_DECL_NEW(ti_usbtll, sizeof(struct ti_usbtll_softc), + ti_usbtll_match, ti_usbtll_attach, NULL, NULL); + +#define RD4(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define WR4(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +static struct ti_usbtll_softc *ti_usbtll_sc = NULL; + +void tl_usbtll_enable_port(u_int); + +void +tl_usbtll_enable_port(u_int port) +{ + struct ti_usbtll_softc *sc = ti_usbtll_sc; + uint32_t val; + + if (sc == NULL) { + printf("%s: driver not loaded\n", __func__); + return; + } + + val = RD4(sc, USBTLL_CHANNEL_CONF(port)); + val &= ~(USBTLL_CHANNEL_CONF_ULPINOBITSTUFF| + USBTLL_CHANNEL_CONF_ULPIAUTOIDLE| + USBTLL_CHANNEL_CONF_ULPIDDRMODE); + val |= USBTLL_CHANNEL_CONF_CHANEN; + WR4(sc, USBTLL_CHANNEL_CONF(port), val); +} + +static void +ti_usbtll_reset(struct ti_usbtll_softc *sc) +{ + uint32_t val; + int retry = 5000; + + WR4(sc, USBTLL_SYSCONFIG, USBTLL_SYSCONFIG_SOFTRESET); + do { + val = RD4(sc, USBTLL_SYSSTATUS); + if (val & USBTLL_SYSSTATUS_RESETDONE) + break; + delay(10); + } while (--retry > 0); + if (retry == 0) + aprint_error_dev(sc->sc_dev, "reset timeout\n"); +} + +static void +ti_usbtll_init(struct ti_usbtll_softc *sc) +{ + uint32_t val; + + ti_usbtll_reset(sc); + + val = USBTLL_SYSCONFIG_ENAWAKEUP | + USBTLL_SYSCONFIG_AUTOIDLE | + USBTLL_SYSCONFIG_SIDLEMODE | + USBTLL_SYSCONFIG_CLOCKACTIVITY; + WR4(sc, USBTLL_SYSCONFIG, val); + + val = RD4(sc, USBTLL_SHARED_CONF); + val |= (USBTLL_SHARED_CONF_FCLK_IS_ON | (1 << 2)); + val &= ~USBTLL_SHARED_CONF_USB_90D_DDR_EN; + val &= ~USBTLL_SHARED_CONF_USB_180D_SDR_EN; + WR4(sc, USBTLL_SHARED_CONF, val); +} + +static int +ti_usbtll_match(device_t parent, cfdata_t match, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +ti_usbtll_attach(device_t parent, device_t self, void *aux) +{ + struct ti_usbtll_softc *sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + bus_addr_t addr; + bus_size_t size; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + if (ti_prcm_enable_hwmod(phandle, 0) != 0) { + aprint_error(": couldn't enable module\n"); + return; + } + + sc->sc_dev = self; + sc->sc_bst = faa->faa_bst; + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + + aprint_naive("\n"); + aprint_normal(": OMAP HS USB Host TLL\n"); + + ti_usbtll_init(sc); + + if (ti_usbtll_sc == NULL) + ti_usbtll_sc = sc; +}