Add OMAP3 USB support.

This commit is contained in:
jmcneill 2019-10-30 21:41:40 +00:00
parent 7448d10076
commit b99e71cc64
6 changed files with 695 additions and 62 deletions

View File

@ -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

View File

@ -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 <jmcneill@invisible.ca>
@ -28,7 +28,7 @@
#include <sys/cdefs.h>
__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 <sys/param.h>
#include <sys/bus.h>
@ -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);

157
sys/arch/arm/ti/ti_ehci.c Normal file
View File

@ -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 <jmcneill@invisible.ca>
* 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 <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ti_ehci.c,v 1.1 2019/10/30 21:41:40 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/intr.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usb_mem.h>
#include <dev/usb/ehcireg.h>
#include <dev/usb/ehcivar.h>
#include <dev/fdt/fdtvar.h>
#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);
}

View File

@ -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 <jmcneill@invisible.ca>
@ -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, \

221
sys/arch/arm/ti/ti_usb.c Normal file
View File

@ -0,0 +1,221 @@
/* $NetBSD: ti_usb.c,v 1.1 2019/10/30 21:41:40 jmcneill Exp $ */
/*-
* Copyright (c) 2019 Jared McNeill <jmcneill@invisible.ca>
* 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 <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ti_usb.c,v 1.1 2019/10/30 21:41:40 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/conf.h>
#include <sys/mutex.h>
#include <sys/bus.h>
#include <dev/fdt/fdtvar.h>
#include <arm/ti/ti_prcm.h>
#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);
}

203
sys/arch/arm/ti/ti_usbtll.c Normal file
View File

@ -0,0 +1,203 @@
/* $NetBSD: ti_usbtll.c,v 1.1 2019/10/30 21:41:40 jmcneill Exp $ */
/*-
* Copyright (c) 2019 Jared McNeill <jmcneill@invisible.ca>
* 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 <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ti_usbtll.c,v 1.1 2019/10/30 21:41:40 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/conf.h>
#include <sys/mutex.h>
#include <sys/bus.h>
#include <dev/fdt/fdtvar.h>
#include <arm/ti/ti_prcm.h>
#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;
}