diff --git a/sys/arm/broadcom/bcm2835/bcm2835_machdep.c b/sys/arm/broadcom/bcm2835/bcm2835_machdep.c index 35aec41..0a56eab 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_machdep.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_machdep.c @@ -89,7 +89,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #define DEBUG #ifdef DEBUG @@ -458,7 +458,7 @@ initarm(void *mdp, void *unused __unused) &kernel_pt_table[i]); pmap_curmaxkvaddr = l2_start + (l2size - 1) * L1_S_SIZE; - + /* Map kernel code and data */ pmap_map_chunk(l1pagetable, KERNVIRTADDR, KERNPHYSADDR, (((uint32_t)(lastaddr) - KERNVIRTADDR) + PAGE_MASK) & ~PAGE_MASK, @@ -612,7 +612,7 @@ platform_devmap_init(void) int i = 0; fdt_devmap[i].pd_va = 0xf2000000; - fdt_devmap[i].pd_pa = 0x20000000; + fdt_devmap[i].pd_pa = 0x20000000; fdt_devmap[i].pd_size = 0x01000000; /* 1 MB */ fdt_devmap[i].pd_prot = VM_PROT_READ | VM_PROT_WRITE; fdt_devmap[i].pd_cache = PTE_DEVICE; @@ -639,7 +639,7 @@ bus_dma_get_range_nb(void) void cpu_reset() { - printf("Reset not implemented!\n"); + bcmwd_watchdog_reset(); while (1); } diff --git a/sys/arm/broadcom/bcm2835/dotg_brcm.c b/sys/arm/broadcom/bcm2835/dotg_brcm.c new file mode 100644 index 0000000..375b7e9 --- /dev/null +++ b/sys/arm/broadcom/bcm2835/dotg_brcm.c @@ -0,0 +1,238 @@ +#include +__FBSDID("$FreeBSD$"); + +/*- + * Copyright (c) 2010-2012 Aleksandr Rybalko. All rights reserved. + * Copyright (c) 2007-2008 Hans Petter Selasky. 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 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 THE 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#define MEM_RID 0 + +static device_probe_t dotg_brcm_probe; +static device_attach_t dotg_brcm_attach; +static device_detach_t dotg_brcm_detach; + +struct dotg_brcm_softc { + struct dotg_softc sc_dci; /* must be first */ +}; + +static int +dotg_brcm_probe(device_t dev) +{ + if (!ofw_bus_is_compatible(dev, "synopsys,designware-hs-otg2")) + return (ENXIO); + + device_set_desc(dev, "DWC OTG 2.0 integrated USB controller"); + + return (0); +} + +static int +dotg_brcm_attach(device_t dev) +{ + struct dotg_brcm_softc *sc = device_get_softc(dev); + int err; + + /* setup controller interface softc */ + + /* initialise some bus fields */ + sc->sc_dci.sc_dev = dev; + sc->sc_dci.sc_bus.parent = dev; + sc->sc_dci.sc_bus.devices = sc->sc_dci.sc_devices; + sc->sc_dci.sc_bus.devices_max = DOTG_MAX_DEVICES; + + /* get all DMA memory */ + if (usb_bus_mem_alloc_all(&sc->sc_dci.sc_bus, + USB_GET_DMA_TAG(dev), NULL)) { + printf("No mem\n"); + return (ENOMEM); + } + sc->sc_dci.sc_mem_rid = 0; + sc->sc_dci.sc_mem_res = + bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_dci.sc_irq_rid, + RF_ACTIVE); + if (!(sc->sc_dci.sc_mem_res)) { + printf("Can`t alloc MEM\n"); + goto error; + } + sc->sc_dci.sc_bst = rman_get_bustag(sc->sc_dci.sc_mem_res); + sc->sc_dci.sc_bsh = rman_get_bushandle(sc->sc_dci.sc_mem_res); + + sc->sc_dci.sc_irq_rid = 0; + sc->sc_dci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &sc->sc_dci.sc_irq_rid, RF_SHAREABLE| RF_ACTIVE); + if (!(sc->sc_dci.sc_irq_res)) { + printf("Can`t alloc IRQ\n"); + goto error; + } + + sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1); + if (!(sc->sc_dci.sc_bus.bdev)) { + printf("Can`t add usbus\n"); + goto error; + } + device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus); + +#if (__FreeBSD_version >= 700031) + err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, + INTR_TYPE_BIO | INTR_MPSAFE, NULL, (driver_intr_t *)dotg_interrupt, + sc, &sc->sc_dci.sc_intr_hdl); +#else + err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, + INTR_TYPE_BIO | INTR_MPSAFE, (driver_intr_t *)dotg_interrupt, + sc, &sc->sc_dci.sc_intr_hdl); +#endif + if (err) { + sc->sc_dci.sc_intr_hdl = NULL; + printf("Can`t set IRQ handle\n"); + goto error; + } + + /* Run clock for OTG core */ +// rt305x_sysctl_set(SYSCTL_CLKCFG1, rt305x_sysctl_get(SYSCTL_CLKCFG1) | +// SYSCTL_CLKCFG1_OTG_CLK_EN); +// rt305x_sysctl_set(SYSCTL_RSTCTRL, SYSCTL_RSTCTRL_OTG); +// DELAY(100); + + err = dotg_init(&sc->sc_dci); + if (err) printf("dotg_init fail\n"); + if (!err) { + err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev); + if (err) printf("device_probe_and_attach fail\n"); + } + if (err) { + goto error; + } + return (0); + +error: + dotg_brcm_detach(dev); + return (ENXIO); +} + +static int +dotg_brcm_detach(device_t dev) +{ + struct dotg_brcm_softc *sc = device_get_softc(dev); + device_t bdev; + int err; + + if (sc->sc_dci.sc_bus.bdev) { + bdev = sc->sc_dci.sc_bus.bdev; + device_detach(bdev); + device_delete_child(dev, bdev); + } + /* during module unload there are lots of children leftover */ + device_delete_children(dev); + + if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) { + /* + * only call dotg_uninit() after dotg_init() + */ + dotg_uninit(&sc->sc_dci); + + /* Stop OTG clock */ +// rt305x_sysctl_set(SYSCTL_CLKCFG1, +// rt305x_sysctl_get(SYSCTL_CLKCFG1) & +// ~SYSCTL_CLKCFG1_OTG_CLK_EN); + + err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res, + sc->sc_dci.sc_intr_hdl); + sc->sc_dci.sc_intr_hdl = NULL; + } + if (sc->sc_dci.sc_irq_res) { + bus_release_resource(dev, SYS_RES_IRQ, 0, + sc->sc_dci.sc_irq_res); + sc->sc_dci.sc_irq_res = NULL; + } + if (sc->sc_dci.sc_mem_res) { + bus_release_resource(dev, SYS_RES_MEMORY, 0, + sc->sc_dci.sc_mem_res); + sc->sc_dci.sc_mem_res = NULL; + } + usb_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL); + + return (0); +} + +static device_method_t dotg_brcm_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, dotg_brcm_probe), + DEVMETHOD(device_attach, dotg_brcm_attach), + DEVMETHOD(device_detach, dotg_brcm_detach), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + DEVMETHOD_END +}; + +static driver_t dotg_brcm_driver = { + .name = "dotg", + .methods = dotg_brcm_methods, + .size = sizeof(struct dotg_brcm_softc), +}; + +static devclass_t dotg_brcm_devclass; + +DRIVER_MODULE(dwcotg, simplebus, dotg_brcm_driver, dotg_brcm_devclass, 0, 0); + diff --git a/sys/arm/broadcom/bcm2835/files.bcm2835 b/sys/arm/broadcom/bcm2835/files.bcm2835 index 88a914d..f0ffecc 100644 --- a/sys/arm/broadcom/bcm2835/files.bcm2835 +++ b/sys/arm/broadcom/bcm2835/files.bcm2835 @@ -1,7 +1,9 @@ arm/broadcom/bcm2835/bcm2835_machdep.c standard +arm/broadcom/bcm2835/wdog_brcm.c standard arm/broadcom/bcm2835/bus_space.c optional fdt arm/broadcom/bcm2835/common.c optional fdt -arm/broadcom/bcm2835/dwc_otg_brcm.c optional dwc_otg +arm/broadcom/bcm2835/dotg_brcm.c optional dotg +dev/usb/controller/dotg.c optional dotg arm/broadcom/bcm2835/interrupt.c standard arm/broadcom/bcm2835/systimer.c standard arm/broadcom/bcm2835/mbox.c standard diff --git a/sys/arm/broadcom/bcm2835/systimer.c b/sys/arm/broadcom/bcm2835/systimer.c index 4aed0db..3e832b3 100644 --- a/sys/arm/broadcom/bcm2835/systimer.c +++ b/sys/arm/broadcom/bcm2835/systimer.c @@ -161,15 +161,13 @@ brcm_systimer_intr(void *arg) st->et.et_event_cb(&st->et, st->et.et_arg); } } - + return (FILTER_HANDLED); } static int brcm_systimer_probe(device_t dev) { - struct brcm_systimer_softc *sc; - sc = (struct brcm_systimer_softc *)device_get_softc(dev); if (ofw_bus_is_compatible(dev, "broadcom,bcm2835-system-timer")) { device_set_desc(dev, "BCM2835 System Timer"); diff --git a/sys/arm/broadcom/bcm2835/wdog_brcm.c b/sys/arm/broadcom/bcm2835/wdog_brcm.c new file mode 100644 index 0000000..d53f072 --- /dev/null +++ b/sys/arm/broadcom/bcm2835/wdog_brcm.c @@ -0,0 +1,143 @@ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define BCM2835_PASWORD 0x5a + +#define BCM2835_WDOG_RESET 0 +#define BCM2835_PASSWORD_MASK 0xff000000 +#define BCM2835_PASSWORD_SHIFT 24 +#define BCM2835_WDOG_TIME_MASK 0x000fffff +#define BCM2835_WDOG_TIME_SHIFT 0 + +#define READ(_sc, _r) bus_space_read_4((_sc)->bst, (_sc)->bsh, (_r)) +#define WRITE(_sc, _r, _v) bus_space_write_4((_sc)->bst, (_sc)->bsh, (_r), (_v)) + +#define BCM2835_RSTC_WRCFG_CLR 0xffffffcf +#define BCM2835_RSTC_WRCFG_SET 0x00000030 +#define BCM2835_RSTC_WRCFG_FULL_RESET 0x00000020 +#define BCM2835_RSTC_RESET 0x00000102 + +#define BCM2835_RSTC_REG 0x00 +#define BCM2835_RSTS_REG 0x04 +#define BCM2835_WDOG_REG 0x08 + +static struct bcmwd_softc *bcmwd_lsc = NULL; + +struct bcmwd_softc { + device_t dev; + struct resource * res; + bus_space_tag_t bst; + bus_space_handle_t bsh; + int wdog_armed; + int wdog_period; + char wdog_passwd; +}; + +#ifdef notyet +static void bcmwd_watchdog_fn(void *private, u_int cmd, int *error); +#endif + +static int +bcmwd_probe(device_t dev) +{ + + if (ofw_bus_is_compatible(dev, "broadcom,bcm2835-wdt")) { + device_set_desc(dev, "BCM2708/2835 Watchdog"); + return (BUS_PROBE_DEFAULT); + } + + return (ENXIO); +} + +static int +bcmwd_attach(device_t dev) +{ + struct bcmwd_softc *sc; + int rid; + + if (bcmwd_lsc != NULL) + return (ENXIO); + + sc = device_get_softc(dev); + sc->wdog_period = 7; + sc->wdog_passwd = BCM2835_PASWORD; + sc->wdog_armed = 0; + sc->dev = dev; + + rid = 0; + sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); + if (sc->res == NULL) { + device_printf(dev, "could not allocate memory resource\n"); + return (ENXIO); + } + + sc->bst = rman_get_bustag(sc->res); + sc->bsh = rman_get_bushandle(sc->res); + + bcmwd_lsc = sc; +#ifdef notyet + EVENTHANDLER_REGISTER(watchdog_list, bcmwd_watchdog_fn, sc, 0); +#endif + return (0); +} + +#ifdef notyet +static void +bcmwd_watchdog_fn(void *private, u_int cmd, int *error) +{ + /* XXX: not yet */ +} +#endif + +void +bcmwd_watchdog_reset() +{ + + if (bcmwd_lsc == NULL) + return; + + WRITE(bcmwd_lsc, BCM2835_WDOG_REG, + (BCM2835_PASWORD << BCM2835_PASSWORD_SHIFT) | 10); + + WRITE(bcmwd_lsc, BCM2835_RSTC_REG, + (READ(bcmwd_lsc, BCM2835_RSTC_REG) & BCM2835_RSTC_WRCFG_CLR) | + (BCM2835_PASWORD << BCM2835_PASSWORD_SHIFT) | + BCM2835_RSTC_WRCFG_FULL_RESET); +} + +static device_method_t bcmwd_methods[] = { + DEVMETHOD(device_probe, bcmwd_probe), + DEVMETHOD(device_attach, bcmwd_attach), + + DEVMETHOD_END +}; + +static driver_t bcmwd_driver = { + "bcmwd", + bcmwd_methods, + sizeof(struct bcmwd_softc), +}; +static devclass_t bcmwd_devclass; + +DRIVER_MODULE(bcmwd, simplebus, bcmwd_driver, bcmwd_devclass, 0, 0); + diff --git a/sys/arm/broadcom/bcm2835/wdog_brcm.h b/sys/arm/broadcom/bcm2835/wdog_brcm.h new file mode 100644 index 0000000..fbc859b --- /dev/null +++ b/sys/arm/broadcom/bcm2835/wdog_brcm.h @@ -0,0 +1,2 @@ +void bcmwd_watchdog_reset(void); + diff --git a/sys/arm/conf/RPI-B b/sys/arm/conf/RPI-B index 90e353b..6af592e 100644 --- a/sys/arm/conf/RPI-B +++ b/sys/arm/conf/RPI-B @@ -107,7 +107,8 @@ device random # Entropy device # USB support device usb # device dwc_otg -options USB_DEBUG +device dotg +#options USB_DEBUG #options USB_REQ_DEBUG #options USB_VERBOSE diff --git a/sys/boot/fdt/dts/bcm2835-rpi-b.dts b/sys/boot/fdt/dts/bcm2835-rpi-b.dts index 4207c43..f888f76 100644 --- a/sys/boot/fdt/dts/bcm2835-rpi-b.dts +++ b/sys/boot/fdt/dts/bcm2835-rpi-b.dts @@ -117,6 +117,11 @@ */ }; + watchdog0 { + compatible = "broadcom,bcm2835-wdt", "broadcom,bcm2708-wdt"; + reg = <0x10001c 0x0c>; /* 0x1c, 0x20, 0x24 */ + }; + gpio: gpio { compatible = "broadcom,bcm2835-gpio", "broadcom,bcm2708-gpio"; reg = <0x200000 0xb0>; @@ -442,7 +447,6 @@ reg-shift = <2>; }; - usb { compatible = "broadcom,bcm2835-usb", "broadcom,bcm2708-usb", "synopsys,designware-hs-otg2"; reg = <0x980000 0x20000>; diff --git a/sys/dev/usb/controller/dotg.c b/sys/dev/usb/controller/dotg.c new file mode 100644 index 0000000..2da04c4 --- /dev/null +++ b/sys/dev/usb/controller/dotg.c @@ -0,0 +1,2597 @@ +#include +__FBSDID("$FreeBSD$"); + +/*- + * Copyright (c) 2010,2011 Aleksandr Rybalko. All rights reserved. + * Copyright (c) 2010 Hans Petter Selasky. 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 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 THE 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. + */ + +/* + * This file contains the driver for DWC like USB OTG Controller. + */ + +/* TODO: + * FIX BULK OUT, work fine with 1k blocks, but after xfer (sometime with 2k/4k, everytime 8k) don`t answer to USBC packets + * Implement SPLIT (Required if used High speed HUB and Low or Full speed device on it) + * Make ZERO_COPY_SOCKET like (speedup) + * Implement and Test support for ISOC endpoints + * Implement Device mode + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* We need to know if it CPU_CNMIPS */ +#include "opt_global.h" + +#include +#include + +#define USB_DEBUG_VAR dotgdebug + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#define DOTG_BUS2SC(bus) \ + ((struct dotg_softc *)(((uint8_t *)(bus)) - \ + ((uint8_t *)&(((struct dotg_softc *)0)->sc_bus)))) + +#ifdef USB_DEBUG +static int dotgdebug = 0; + +SYSCTL_NODE(_hw_usb, OID_AUTO, dotg, CTLFLAG_RW, 0, "DOTG"); +SYSCTL_INT(_hw_usb_dotg, OID_AUTO, debug, CTLFLAG_RW, + &dotgdebug, 0, "DOTG debug level"); + +TUNABLE_INT("hw.usb.dotg.debug", &dotgdebug); +#endif + +struct dotg_std_temp { + dotg_cmd_t *func; + struct dotg_td *td; + struct dotg_td *td_next; + struct usb_page_cache *pc; + uint32_t offset; + uint32_t len; + uint8_t short_pkt; + uint8_t setup_alt_next; + uint8_t channel; +}; + +extern struct usb_bus_methods dotg_bus_methods; +extern struct usb_pipe_methods dotg_device_bulk_methods; +extern struct usb_pipe_methods dotg_device_ctrl_methods; +extern struct usb_pipe_methods dotg_device_intr_methods; +extern struct usb_pipe_methods dotg_device_isoc_methods; + +static void dotg_standard_done(struct usb_xfer *); +static void dotg_device_done(struct usb_xfer *, usb_error_t); +static void dotg_timeout(void *); +static void dotg_do_poll(struct usb_bus *); +static void +dotg_complete_cb(dotg_complete_t, int, struct dotg_td *); + +#ifdef CPU_CNMIPS + +#define WRITEDMA(sc, channel, val) \ + { \ + bus_space_write_8(sc->sc_bst, 0x00016F0000000000ull, 818+(channel)*8, htole64(val)); \ + bus_space_write_8(sc->sc_bst, 0x00016F0000000000ull, 858+(channel)*8, htole64(val)); \ + printf("Set dma to %p for channel %d\n", (val), (channel)); \ + } +#define READDMA(sc, channel) \ + htole64(bus_space_read_8(sc->sc_bst, 0x00016F0000000000ull, 818+(channel)*8)) + +#else /* defined(__mips_n64) */ + +#define WRITEDMA(sc, channel, val) \ + { bus_space_write_4(sc->sc_bst, sc->sc_bsh, DOTG_HCDMA(channel), htole32(val)); } +#define READDMA(sc, offset) \ + le32toh(bus_space_read_4(sc->sc_bst, sc->sc_bsh, DOTG_HCDMA(channel))) + +#endif /* defined(__mips_n64) */ + +#define WRITE4(sc, offset, val) \ + bus_space_write_4(sc->sc_bst, sc->sc_bsh, (offset), (val)) +// bus_space_write_4(sc->sc_bst, sc->sc_bsh, (offset), htole32(val)) +#define READ4(sc, offset) \ + (bus_space_read_4(sc->sc_bst, sc->sc_bsh, (offset))) +// le32toh(bus_space_read_4(sc->sc_bst, sc->sc_bsh, (offset))) + +//static uint32_t +//READ4(struct dotg_softc * sc, uint32_t offset) +//{ +// uint32_t val = le32toh(bus_space_read_4(sc->sc_bst, sc->sc_bsh, (offset))); +// printf("READ4(sc, 0x%08x, 0x%08x)\n", (offset), (val)); +// return (val); +//} + +static inline int +needs_split(struct dotg_softc * sc, struct dotg_td *td) +{ + return ((td->qh->dev_speed != USB_SPEED_HIGH) && + (GETFLD(sc->dotg_hprt, HPRT_PRTSPD) == HPRT_PRTSPD_HIGH)); + +} + +static inline int +get_data_pid(struct dotg_td *td) +{ + return ((td->qh->ep_toggle_next)?HCTSIZ_PID_DATA1:HCTSIZ_PID_DATA0); +} + +#if 0 +static int +dotg_core_reset(struct dotg_softc * sc) +{ + + DPRINTF("\n"); + /* Wait for AHB IDLE */ + if (WAIT_FOR_FIELD32(sc, DOTG_GRSTCTL, GRSTCTL_AHBIDLE, 1, 100000)) { + DPRINTF("AHB not Idle after 100ms\n"); + return (1); + } + + /* Core Soft Reset */ + SETFIELD32(sc, DOTG_GRSTCTL, GRSTCTL_CSFTRST, 1); + if (WAIT_FOR_FIELD32(sc, DOTG_GRSTCTL, GRSTCTL_CSFTRST, 0, 100000)) { + DPRINTF("Soft Reset Failed\n"); + return (1); + } + + DELAY(100); + return (0); +} +#endif + + +int +dotg_enable(struct dotg_softc * sc) +{ + uint32_t ghwcfg3, tmp; + + sc->dotg_hprt = READ4(sc, DOTG_HPRT); + if (sc->dotg_hprt & HPRT_PRTENA) + return (0); + + /* Some devices don`t shown without delay here */ + DELAY(100000); + sc->dotg_hprt = READ4(sc, DOTG_HPRT); + + if (!(sc->dotg_hprt & HPRT_PRTCONNSTS)) { + DPRINTF("Nothing plugged into the port\n"); + return (1); + } + SETFIELD32(sc, DOTG_HPRT, HPRT_PRTRST, 1); + DELAY(50000); + SETFIELD32(sc, DOTG_HPRT, HPRT_PRTRST, 0); + + if (WAIT_FOR_FIELD32(sc, DOTG_HPRT, HPRT_PRTENA, 1, 100000)) { + DPRINTF("Timeout waiting for the port to finish reset\n"); + return (1); + } + + sc->dotg_hprt = READ4(sc, DOTG_HPRT); + DPRINTF("port is in %s speed mode\n", + (GETFLD(sc->dotg_hprt, HPRT_PRTSPD) == HPRT_PRTSPD_HIGH) ? + "high" : + (GETFLD(sc->dotg_hprt, HPRT_PRTSPD) == HPRT_PRTSPD_FULL) ? + "full" : + "low"); + +/* NOT WORKING + tmp = READ4(sc, DOTG_HCFG); + tmp &= ~(HCFG_FSLSSUPP | HCFG_FSLSPCLKSEL_MASK); + if (GETFLD(sc->dotg_hprt, HPRT_PRTSPD) == HPRT_PRTSPD_HIGH) { + tmp &= ~HCFG_FSLSSUPP; + tmp |= SETFLD(1, HCFG_FSLSPCLKSEL); + } else { + tmp |= HCFG_FSLSSUPP; + tmp |= SETFLD(0, HCFG_FSLSPCLKSEL); + } + WRITE4(sc, DOTG_HCFG, tmp); +*/ +/* NOT WORKING + tmp = READ4(sc, DOTG_GUSBCFG); + tmp &= ~GUSBCFG_TOUTCAL_MASK; + if (GETFLD(sc->dotg_hprt, HPRT_PRTSPD) != HPRT_PRTSPD_HIGH) { + tmp |= SETFLD(0x7, GUSBCFG_TOUTCAL); + } + WRITE4(sc, DOTG_GUSBCFG, tmp); +*/ + + ghwcfg3 = READ4(sc, DOTG_GHWCFG3); + SETFIELD32_(sc, DOTG_GRXFSIZ, GRXFSIZ_RXFDEP, + GETFLD(ghwcfg3, GHWCFG3_DFIFODEPTH) / 4); + + tmp = (GETFLD(ghwcfg3, GHWCFG3_DFIFODEPTH) / 2) << + GNPTXFSIZ_NPTXFDEP_SHIFT; + tmp |= (GETFLD(ghwcfg3, GHWCFG3_DFIFODEPTH) / 4) << + GNPTXFSIZ_NPTXFSTADDR_SHIFT; + WRITE4(sc, DOTG_GNPTXFSIZ, tmp); + tmp = (GETFLD(ghwcfg3, GHWCFG3_DFIFODEPTH) / 4) << + HPTXFSIZ_PTXFSIZE_SHIFT; + tmp |= 3 * (GETFLD(ghwcfg3, GHWCFG3_DFIFODEPTH) / 4) << + HPTXFSIZ_PTXFSTADDR_SHIFT; + WRITE4(sc, DOTG_HPTXFSIZ, tmp); + + SETFIELD32_(sc, DOTG_GRSTCTL, GRSTCTL_TXFNUM, 0x10); + SETFIELD32(sc, DOTG_GRSTCTL, GRSTCTL_TXFFLSH, 1); + WAIT_FOR_FIELD32(sc, DOTG_GRSTCTL, GRSTCTL_TXFFLSH, 0, 100); + SETFIELD32(sc, DOTG_GRSTCTL, GRSTCTL_RXFFLSH, 1); + WAIT_FOR_FIELD32(sc, DOTG_GRSTCTL, GRSTCTL_RXFFLSH, 0, 100); + + return (0); +} + +#ifdef USB_DEBUG + +static void +dump_hcchar(uint32_t reg) +{ + printf("\tHCCHAR 0x%08x %s%s%s DEVADDR=%x MC_EC=%x EPTYPE=%x %s %s EPNUM=%x MPS=%x\n", reg, + ((reg & HCCHAR_CHENA)?"ENA ":"DIS "), + ((reg & HCCHAR_CHDIS)?"disable in progress ":""), + ((reg & HCCHAR_ODDFRM)?"send on ODD frame":"send on EVN frame"), + GETFLD(reg, HCCHAR_DEVADDR), + GETFLD(reg, HCCHAR_MC_EC), + GETFLD(reg, HCCHAR_EPTYPE), + ((reg & HCCHAR_LSPDDEV)?"LSPDDEV ":"F/HSPDDEV "), + ((reg & HCCHAR_EPDIR)?"DIR_IN":"DIR_OUT"), + GETFLD(reg, HCCHAR_EPNUM), + GETFLD(reg, HCCHAR_MPS)); +} + +static void +dump_hcsplt(uint32_t reg) +{ + printf("\tHCSPLT 0x%08x %s%s XACTPOS=%x HUBADDR=%x PRTADDR=%x\n", reg, + ((reg & HCSPLT_SPLTENA)?"SPLTENA ":""), + ((reg & HCSPLT_COMPSPLT)?"COMPSPLT ":""), + GETFLD(reg, HCSPLT_XACTPOS), + GETFLD(reg, HCSPLT_HUBADDR), + GETFLD(reg, HCSPLT_PRTADDR)); +} + +static void +dump_hcint(uint32_t reg) +{ + printf("\tHCINT 0x%08x %s %s %s %s %s %s %s %s %s %s %s\n", reg, + ((reg & HCINT_DATATGLERR )?"DATATGLERR":""), + ((reg & HCINT_FRMOVRUN )?"FRMOVRUN":""), + ((reg & HCINT_BBLERR )?"BBLERR":""), + ((reg & HCINT_XACTERR )?"XACTERR":""), + ((reg & HCINT_NYET )?"NYET":""), + ((reg & HCINT_ACK )?"ACK":""), + ((reg & HCINT_NAK )?"NAK":""), + ((reg & HCINT_STALL )?"STALL":""), + ((reg & HCINT_AHBERR )?"AHBERR":""), + ((reg & HCINT_CHHLTD )?"CHHLTD":""), + ((reg & HCINT_XFERCOMPL )?"XFERCOMPL":"")); +} + +static void +dump_hcintmsk(uint32_t reg) +{ + printf("\tHCINTMSK 0x%08x %s %s %s %s %s %s %s %s %s %s %s\n", reg, + ((reg & HCINTMSK_DATATGLERRMSK)?"DATATGLERRMSK":""), + ((reg & HCINTMSK_FRMOVRUNMSK)?"FRMOVRUNMSK":""), + ((reg & HCINTMSK_BBLERRMSK )?"BBLERRMSK":""), + ((reg & HCINTMSK_XACTERRMSK )?"XACTERRMSK":""), + ((reg & HCINTMSK_NYETMSK )?"NYETMSK":""), + ((reg & HCINTMSK_ACKMSK )?"ACKMSK":""), + ((reg & HCINTMSK_NAKMSK )?"NAKMSK":""), + ((reg & HCINTMSK_STALLMSK )?"STALLMSK":""), + ((reg & HCINTMSK_AHBERRMSK )?"AHBERRMSK":""), + ((reg & HCINTMSK_CHHLTDMSK )?"CHHLTDMSK":""), + ((reg & HCINTMSK_XFERCOMPLMSK)?"XFERCOMPLMSK":"")); +} + +static void +dump_hctsiz(uint32_t reg) +{ + + printf("\tHCTSIZ 0x%08x %s ", reg, ((reg & HCTSIZ_DOPNG)?"DOPNG":"")); + + switch (GETFLD(reg, HCTSIZ_PID)) { + case HCTSIZ_PID_DATA0: + printf("DATA0"); + break; + case HCTSIZ_PID_DATA2: + printf("DATA2"); + break; + case HCTSIZ_PID_DATA1: + printf("DATA1"); + break; + case HCTSIZ_PID_MDATA: + printf("MDATA/SETUP"); + break; + } + + printf(" PKTCNT=%x XFERSIZE=%x\n", + GETFLD(reg, HCTSIZ_PKTCNT), + GETFLD(reg, HCTSIZ_XFERSIZE)); +} + +static void +dump_channel_regs(struct dotg_softc * sc, int channel) +{ + printf("\tchannel=%d\n", channel); + dump_hcchar (READ4(sc, DOTG_HCCHAR (channel))); + dump_hcsplt (READ4(sc, DOTG_HCSPLT (channel))); + dump_hctsiz (READ4(sc, DOTG_HCTSIZ (channel))); + printf("\tHCDMA=0x%p\n", (int *)READDMA(sc, channel)); +return; + dump_hcint (READ4(sc, DOTG_HCINT (channel))); + dump_hcintmsk (READ4(sc, DOTG_HCINTMSK (channel))); +} +#endif + + +static int +poll_channel(struct dotg_softc * sc, int channel) +{ + uint32_t hcint; + uint32_t hctsiz; + uint32_t hcchar; + int bytes_this_transfer; + int packets_processed; + + struct dotg_td *td; + + hcint = READ4(sc, DOTG_HCINT(channel)); + +#ifdef USB_DEBUG + if (hcint & HCINT_AHBERR) { + DPRINTF("\nAHB ERROR: \n"); + dump_channel_regs(sc, channel); + } +#endif + + WRITE4(sc, DOTG_HCINT(channel), hcint); + + hcchar = READ4(sc, DOTG_HCCHAR(channel)); + hctsiz = READ4(sc, DOTG_HCTSIZ(channel)); + + if (sc->td_for_channel[channel]) { + td = sc->td_for_channel[channel]; + + /* Free channel */ + DPRINTF("idle=%02x\n", sc->idle_hardware_channels); + sc->td_for_channel[channel] = 0; + sc->idle_hardware_channels |= (1<idle_hardware_channels); + } else { + /* No transfer for channel */ + DPRINTF("No transfer for channel %d\n", channel); +#ifdef USB_DEBUG + if (dotgdebug) { + dump_channel_regs(sc, channel); + dump_hcint(hcint); + } +#endif + return (0); + } + + DPRINTF("channel %d halted td=%p qh=%p\n", channel, td, td->qh); + + + DPRINTF("channel=%0d xfersize=0x%08x\n", channel, td->qh->this_xfersize); +#ifdef USB_DEBUG + if (dotgdebug) { + dump_channel_regs(sc, channel); + dump_hcint(hcint); + } +#endif + + /* Find trasfered sizes */ + packets_processed = GETFLD(hctsiz, HCTSIZ_PKTCNT); + + if ((hcchar & HCCHAR_EPDIR) == HCCHAR_EPDIR_IN) { + if (td->qh->this_xfersize) { + bytes_this_transfer = (td->qh->this_xfersize - + GETFLD(hctsiz, HCTSIZ_XFERSIZE)); + } else + bytes_this_transfer = td->remainder - + ((GETFLD(hctsiz, HCTSIZ_XFERSIZE) > 0)? + GETFLD(hctsiz, HCTSIZ_XFERSIZE):0); + } else { + + bytes_this_transfer = packets_processed * + GETFLD(hcchar, HCCHAR_MPS); + + if (bytes_this_transfer > td->remainder) + bytes_this_transfer = td->remainder; + } + + + if (td->qh->dev_speed == USB_SPEED_HIGH) { + if ((td->qh->flags & __DOTG_FLAGS_NEED_PING) & + (hcint & HCINT_ACK) & !(hcint & HCINT_NAK)) + td->qh->flags &= ~__DOTG_FLAGS_NEED_PING; + } + + + if (hcint & HCINT_STALL) { + td->qh->ep_toggle_next = 0; + dotg_complete_cb(DOTG_COMPLETE_STALL, 0, td); + } + else if (hcint & HCINT_XACTERR) { + + if ((hcint & HCINT_NAK) || (hcint & HCINT_ACK)) + td->qh->retries = 0; + td->qh->retries++; + if (td->qh->retries > MAX_RETRIES) { + + dotg_complete_cb(DOTG_COMPLETE_XACTERR, 0, td); + } else { + + td->qh->split_sc_frame = -1; + td->qh->next_tx_cycle = cpu_ticks() + + /* +ep_interval in ms */ + td->qh->ep_interval*(cpu_tickrate()/1000); + } + } + else if (hcint & HCINT_BBLERR) { + + dotg_complete_cb(DOTG_COMPLETE_BABBLEERR, 0, td); + } + else if (hcint & HCINT_FRMOVRUN) { + + td->qh->split_sc_frame = -1; + WRITE4(sc, DOTG_HCINT(channel), hcchar | HCCHAR_CHDIS); + + dotg_complete_cb(DOTG_COMPLETE_FRAMEERR, 0, td); + } + else if ((hcint & HCINT_ACK) || (hcint & HCINT_NYET)) { + td->qh->retries = 0; + + if (td->qh->dev_speed == USB_SPEED_HIGH) { + td->qh->flags &= ~__DOTG_FLAGS_NEED_PING; + td->qh->flags |= __DOTG_FLAGS_DONE_PING; + } + + + switch (td->qh->ep_type) { + case UE_CONTROL: + if ((!td->qh->ep_toggle_next) && + (GETFLD(hctsiz, HCTSIZ_PID) == 0)) + td->qh->ep_toggle_next = 1; + else if ((td->qh->ep_toggle_next) && + (GETFLD(hctsiz, HCTSIZ_PID) != 0)) + td->qh->ep_toggle_next = 0; + + dotg_complete_cb(DOTG_COMPLETE_SUCCESS, + bytes_this_transfer, td); + break; + case UE_BULK: + case UE_INTERRUPT: + if ((!td->qh->ep_toggle_next) && + (GETFLD(hctsiz, HCTSIZ_PID) != 0)) + td->qh->ep_toggle_next = 1; + else if ((td->qh->ep_toggle_next) && + (GETFLD(hctsiz, HCTSIZ_PID) == 0)) + td->qh->ep_toggle_next = 0; + + td->qh->next_tx_cycle += td->qh->ep_interval; + dotg_complete_cb(DOTG_COMPLETE_SUCCESS, + bytes_this_transfer, td); + break; + case UE_ISOCHRONOUS: + td->qh->next_tx_cycle += td->qh->ep_interval; + dotg_complete_cb(DOTG_COMPLETE_SUCCESS, + bytes_this_transfer, td); + break; + } + } + else if (hcint & HCINT_NAK) { + uint64_t ipd_clk_count; + + if ((td->qh->ep_type == UE_INTERRUPT) && (td->qh->retries > 7)) { + dotg_complete_cb(DOTG_COMPLETE_SUCCESS, 0, td); + return (0); + } + + + DPRINTF("NAK, td->qh->retries=%d\n",td->qh->retries); + td->qh->fixup_state = FIXUP_NAK; + td->qh->retries ++; + ipd_clk_count = cpu_ticks(); + td->qh->next_tx_cycle = ipd_clk_count + td->qh->ep_interval; + } else { + + dotg_complete_cb(DOTG_COMPLETE_ERROR, 0, td); + } + return (0); +} + + + + +static uint8_t +dotg_host_alloc_endpoint(struct dotg_td *td) +{ + struct dotg_softc *sc; + + if (td->qh->fixup_state == FIXUP_PEND) + return (1); /* busy */ + + if (td->qh->fixup_state > FIXUP_NONE) + return (0); /* success */ + + /* get softc */ + sc = td->qh->sc; + + td->qh->fixup_len = 0; + td->qh->fixup_off = 0; + td->qh->fixup_actlen = 0; + td->qh->retries = 0; + td->qh->this_xfersize = 0; + + td->qh->fixup_state = FIXUP_ALOC; + + return (0); /* success */ +} + +static void +dotg_host_free_endpoint(struct dotg_td *td) +{ + struct dotg_softc *sc = td->qh->sc; + uint32_t hcchar; + + if (td->qh->fixup_state == FIXUP_NONE) + return; + + if (td->channel >= 0) { + /* cancel, if any */ + hcchar = READ4(sc, DOTG_HCCHAR(td->channel)); + if (hcchar & HCCHAR_CHENA) + WRITE4(sc, DOTG_HCCHAR(td->channel), + hcchar | HCCHAR_CHDIS); + td->channel = -1; + } + + td->qh->fixup_state = FIXUP_NONE; +} + +static void +dotg_complete_cb(dotg_complete_t status, int bytes, struct dotg_td *td) +{ + + td->qh->fixup_state = FIXUP_CMPL; + td->qh->fixup_actlen = bytes; + + switch (status) { + case DOTG_COMPLETE_SUCCESS: + case DOTG_COMPLETE_SHORT: + td->error_any = 0; + td->error_stall = 0; + break; + case DOTG_COMPLETE_STALL: + td->error_stall = 1; + td->error_any = 1; + break; + default: + td->error_any = 1; + break; + } + +} +static int +configure_channel(struct dotg_td *td, int xfersize, int pid, int dirin) +{ + /* get softc */ + struct dotg_softc *sc = td->qh->sc; + uint32_t hcsplt = 0, hctsiz = 0, hcchar = 0, hcint; + int channel = -1; + + DPRINTF("idle=%02x\n", sc->idle_hardware_channels); + for (channel = 0; channel < sc->channels; channel ++ ) { + if (sc->idle_hardware_channels & (1<td_for_channel[channel] = td; + sc->idle_hardware_channels &= ~(1<channel = channel; + DPRINTF("Allocate hardware channel %d. idle=%02x\n", + channel, sc->idle_hardware_channels); + break; + } + } + if (channel < 0 || channel > 3) { + device_printf(sc->sc_dev, "Wrong allocated channel=%d\n", channel); + return (EIO); + } + + if (READ4(sc, DOTG_HCCHAR(td->channel)) & HCCHAR_CHENA) { + device_printf(sc->sc_dev, "ERROR: channel %d already enabled\n", channel); + return (EIO); + } + + SETFIELD32(sc, DOTG_GINTMSK, GINTMSK_SOFMSK, 1); + + hcint = READ4(sc, DOTG_HCINT(td->channel)); + WRITE4(sc, DOTG_HCINT(td->channel), hcint); + WRITE4(sc, DOTG_HCINTMSK(td->channel), 0x7ff); + + td->qh->this_xfersize = xfersize; + + hctsiz |= SETFLD(xfersize, HCTSIZ_XFERSIZE); + hctsiz |= SETFLD(((xfersize > td->qh->max_packet_size)? + ((xfersize + td->qh->max_packet_size - 1) / + td->qh->max_packet_size):1), HCTSIZ_PKTCNT); + hctsiz |= SETFLD(pid, HCTSIZ_PID); + + DPRINTF("Use %s for ep %02x\n", + (pid == HCTSIZ_PID_DATA0)?"DATA0": + (pid == HCTSIZ_PID_DATA1)?"DATA1": + (pid == HCTSIZ_PID_SETUP)?"SETUP": + "DATA2", + td->qh->ep_num + ); + + if (td->qh->ep_mult < 1) + hcchar |= SETFLD(1, HCCHAR_EC); + else if (td->qh->ep_mult > 3) + hcchar |= SETFLD(3, HCCHAR_EC); + else + hcchar |= SETFLD(td->qh->ep_mult, HCCHAR_EC); + + hcchar |= SETFLD(td->qh->dev_addr, HCCHAR_DEVADDR); + hcchar |= SETFLD(td->qh->ep_type, HCCHAR_EPTYPE); + hcchar |= (td->qh->dev_speed == USB_SPEED_LOW)?HCCHAR_LSPDDEV:0; + hcchar |= dirin?HCCHAR_EPDIR_IN:HCCHAR_EPDIR_OUT; + hcchar |= SETFLD(td->qh->ep_num & 0x0f, HCCHAR_EPNUM); + hcchar |= SETFLD(td->qh->max_packet_size, HCCHAR_MPS); + + WRITEDMA(sc, td->channel, + (unsigned int *)(td->qh->fixup_phys + td->qh->fixup_off)); + WRITE4(sc, DOTG_HAINTMSK, + (READ4(sc, DOTG_HAINTMSK) | (1<channel))); + WRITE4(sc, DOTG_HCINTMSK(td->channel), + HCINTMSK_CHHLTDMSK|HCINTMSK_AHBERRMSK); + WRITE4(sc, DOTG_HCSPLT(td->channel), hcsplt); + WRITE4(sc, DOTG_HCTSIZ(td->channel), hctsiz); + + + WRITE4(sc, DOTG_HCCHAR(td->channel), hcchar); +#ifdef USB_DEBUG + if (dotgdebug) + dump_channel_regs(sc, td->channel); +#endif + return (0); +} + +static uint8_t +dotg_host_control_header_tx(struct dotg_td *td) +{ + struct dotg_softc *sc; + + if (dotg_host_alloc_endpoint(td)) + return (1); /* busy */ + DPRINTF("remainder=%d\n",td->remainder); + + /* check error */ + if (td->error_any) + return (0); /* done */ + + if (td->qh->fixup_state == FIXUP_CMPL) { + + /* clear complete flag */ + td->qh->fixup_state = FIXUP_ALOC; + + /* flush data */ + usb_pc_cpu_invalidate(td->qh->fixup_pc); + return (0); /* done */ + } + /* verify length */ + if (td->remainder != 8) { + td->error_any = 1; + return (0); /* done */ + } + usbd_copy_out(td->pc, td->offset, td->qh->fixup_buf, 8); + + /* update offset and remainder */ + td->offset += 8; + td->remainder -= 8; + + /* setup data length and offset */ + td->qh->fixup_len = UGETW(td->qh->fixup_buf + 6); + td->qh->fixup_off = 0; + + if (td->qh->fixup_len > (DOTG_MAX_FIXUP - 8)) { + td->error_any = 1; + return (0); /* done */ + } + + /* get softc */ + sc = td->qh->sc; + +//#ifdef USB_DEBUG +// if (dotgdebug) { +// DPRINTF("\n"); +// hexdump((uint8_t *)MIPS_PHYS_TO_KSEG1(td->qh->fixup_phys), +// 8, 0, 0); +// } +//#endif + + int ret = configure_channel(td, 8, HCTSIZ_PID_SETUP, HCCHAR_EPDIR_OUT); + if (ret != 0) + return (1); + uint32_t hcchar = READ4(sc, DOTG_HCCHAR(td->channel)); + + hcchar |= HCCHAR_CHENA; + + td->qh->fixup_state = FIXUP_PEND; + usb_pc_cpu_flush(td->qh->fixup_pc); + + WRITE4(sc, DOTG_HCCHAR(td->channel), hcchar); + + return (1); /* busy */ +} + +static uint8_t +dotg_host_control_data_tx(struct dotg_td *td) +{ + struct dotg_softc *sc = td->qh->sc; + uint32_t rem; + + /* allocate endpoint and check pending */ + if (dotg_host_alloc_endpoint(td)) + return (1); /* busy */ + + /* check error */ + if (td->error_any) + return (0); /* done */ + + if (td->qh->fixup_state == FIXUP_CMPL) { + rem = td->qh->fixup_len - td->qh->fixup_off; + + if (td->remainder > rem) { + td->error_any = 1; + DPRINTFN(1, "Excess setup transmit data\n"); + return (0); /* done */ + } + return (0); + } + + usbd_copy_out(td->pc, td->offset, td->qh->fixup_buf+8, td->remainder); + +/*---------------------------------------------------------------*/ + DPRINTF("%d: Ctrl data tx\n", __LINE__); + td->qh->fixup_off = 8; + int ret = configure_channel(td, td->remainder, td->qh->ep_toggle_next?HCTSIZ_PID_DATA0:HCTSIZ_PID_DATA1, HCCHAR_EPDIR_OUT); + if (ret != 0) + return (1); + uint32_t hcchar = READ4(sc, DOTG_HCCHAR(td->channel)); + + hcchar |= HCCHAR_CHENA; +/*---------------------------------------------------------------*/ + td->qh->fixup_state = FIXUP_PEND; + + td->offset += td->remainder; + td->remainder = 0; + + usb_pc_cpu_flush(td->qh->fixup_pc); +/*---------------------------------------------------------------*/ + WRITE4(sc, DOTG_HCCHAR(td->channel), hcchar); +/*---------------------------------------------------------------*/ + + return (1); /* done */ +} + +static uint8_t +dotg_host_control_data_rx(struct dotg_td *td) +{ + struct dotg_softc *sc = td->qh->sc; + uint32_t rem; + + /* allocate endpoint and check pending */ + if (dotg_host_alloc_endpoint(td)) + return (1); /* busy */ + + /* check error */ + if (td->error_any) + return (0); /* done */ + + if (td->qh->fixup_state == FIXUP_CMPL) { + /* clear complete flag */ + td->qh->fixup_state = FIXUP_ALOC; + + /* flush data */ + usb_pc_cpu_invalidate(td->qh->fixup_pc); + + + DPRINTF("fixup_actlen=%d, fixup_off=%d, td->offset=%d, td->remainder=%d\n", td->qh->fixup_actlen, td->qh->fixup_off, td->offset, td->remainder); + /* copy data from buffer */ + rem = td->qh->fixup_actlen; + + if (rem > td->remainder) + rem = td->remainder; + + usbd_copy_in(td->pc, td->offset, td->qh->fixup_buf+8, rem); + + DPRINTF("Data RX\n"); +#ifdef USB_DEBUG + if (dotgdebug == 0x0fffffff) hexdump((uint8_t *)(td->qh->fixup_buf+8), rem, 0, 0); +#endif + + td->offset += rem; + td->qh->fixup_off += rem; + td->remainder -= rem; + + + + return (0); /* done */ + } + + td->qh->fixup_off = 8; + int ret = configure_channel(td, td->remainder, td->qh->ep_toggle_next?HCTSIZ_PID_DATA0:HCTSIZ_PID_DATA1, HCCHAR_EPDIR_IN); + if (ret != 0) + return (1); + uint32_t hcchar = READ4(sc, DOTG_HCCHAR(td->channel)); + hcchar |= HCCHAR_CHENA; + + td->qh->fixup_state = FIXUP_PEND; + usb_pc_cpu_flush(td->qh->fixup_pc); + + WRITE4(sc, DOTG_HCCHAR(td->channel), hcchar); + + return (1); + + +} + +static uint8_t +dotg_host_control_status_tx(struct dotg_td *td) +{ + /* allocate endpoint and check pending */ + if (dotg_host_alloc_endpoint(td)) + return (1); /* busy */ + + /* check error */ + if (td->error_any) + return (0); /* done */ + + if (td->qh->fixup_state == FIXUP_CMPL) { + /* clear complete flag */ + td->qh->fixup_state = FIXUP_ALOC; + DPRINTF("%d: control status TX:\n", __LINE__); +#ifdef USB_DEBUG + if (dotgdebug == 0x0fffffff) + hexdump((uint8_t *)td->qh->fixup_buf, 8, 0, 0); +#endif + /* done */ + return (0); + } + /* do control IN request */ + if (!(td->qh->fixup_buf[0] & UE_DIR_IN)) { + + + struct dotg_softc *sc; + + /* get softc */ + sc = td->qh->sc; + + /* start USB transfer */ + td->qh->fixup_off = 0; + int ret = configure_channel(td, 0, td->qh->ep_toggle_next?HCTSIZ_PID_DATA0:HCTSIZ_PID_DATA1, HCCHAR_EPDIR_IN); + if (ret != 0) + return (1); + uint32_t hcchar = READ4(sc, DOTG_HCCHAR(td->channel)); + hcchar |= HCCHAR_CHENA; + + td->qh->fixup_state = FIXUP_PEND; + + usb_pc_cpu_flush(td->qh->fixup_pc); + WRITE4(sc, DOTG_HCCHAR(td->channel), hcchar); + return (1); /* busy */ + } + + return (0); /* done */ +} + +static uint8_t +dotg_non_control_data_tx(struct dotg_td *td) +{ + struct dotg_softc *sc; + uint32_t rem = 0; + + if ( td->qh->fixup_state == FIXUP_NAK) { + DPRINTF("%d: NAKed, retry\n", __LINE__); + rem = td->qh->this_xfersize; + goto dotg_non_control_data_tx_retry; + } + + + /* allocate endpoint and check pending */ + if (dotg_host_alloc_endpoint(td)) + return (1); /* busy */ + + + /* check error */ + if (td->error_any) + return (0); /* done */ + + + DPRINTF("td->qh->fixup_state = %d, td->short_pkt=%d, td->qh->dev_speed=%d == %d\n",td->qh->fixup_state, td->short_pkt, td->qh->dev_speed, USB_SPEED_HIGH); + if (td->qh->fixup_state == FIXUP_CMPL) { + if ((td->qh->ep_type & UE_XFERTYPE) == UE_ISOCHRONOUS) { + td->qh->fixup_state = FIXUP_ALOC; + DPRINTF("fixup_complete UE_ISOCHRONOUS\n"); + return (0); /* done */ + } + rem = td->qh->this_xfersize; + td->offset += rem; + td->qh->fixup_off += rem; + td->remainder -= rem; + } + + /* check complete */ + if (td->remainder == 0) { + if (td->short_pkt) { + DPRINTF("remainder == 0 && short_pkt\n"); + return (0); /* complete */ + } + /* else need to send a zero length packet */ + rem = 0; + td->short_pkt = 1; + return (0); /* complete */ + } else { + /* + * XXX TODO: fix handling transfers 1024 < x < DOTG_MAX_FIXUP + * "Small" devices says ACK & NYET in middle of 2048 BULK OUT + */ +#define DOTG_MAX_FIXUP_TX 1024 + /* get maximum length */ + rem = DOTG_MAX_FIXUP_TX % td->qh->max_frame_size; + rem = DOTG_MAX_FIXUP_TX - rem; + + if (rem == 0) { + /* should not happen */ + DPRINTFN(1, "Fixup buffer is too small\n"); + td->error_any = 1; + return (0); /* done */ + } + /* get minimum length */ + if (rem > td->remainder) { + rem = td->remainder; + if ((rem == 0) || (rem % td->qh->max_frame_size)) + td->short_pkt = 1; + } + /* copy data into fixup buffer */ + usbd_copy_out(td->pc, td->offset, td->qh->fixup_buf, rem); + td->qh->fixup_off = 0; + + /* flush data */ + usb_pc_cpu_flush(td->qh->fixup_pc); + + /* pre-increment TX buffer offset */ + } + +dotg_non_control_data_tx_retry: + /* get softc */ + sc = td->qh->sc; + + if (td->qh->dev_speed == USB_SPEED_HIGH) { + /* If USB2.0 BULK OUT */ + DPRINTF("%d: td->qh->dev_speed == USB_SPEED_HIGH\n", __LINE__); + td->qh->flags |= __DOTG_FLAGS_NEED_PING; + td->qh->flags &= ~__DOTG_FLAGS_DONE_PING; + } else { + td->qh->flags &= ~(__DOTG_FLAGS_DONE_PING| + __DOTG_FLAGS_NEED_PING); + } + +/*---------------------------------------------------------------*/ + DPRINTF("+++++++++++++++++ rem=%d\n", rem); +//#ifdef USB_DEBUG +// if (dotgdebug == 0x0fffffff) hexdump((uint8_t *)MIPS_PHYS_TO_KSEG1(td->qh->fixup_phys), rem, 0, 0); +//#endif + DPRINTF("\n"); + + int ret = configure_channel(td, rem, td->qh->ep_toggle_next?HCTSIZ_PID_DATA1:HCTSIZ_PID_DATA0, HCCHAR_EPDIR_OUT); + if (ret != 0) + return (1); + + uint32_t hcchar = READ4(sc, DOTG_HCCHAR(td->channel)); + uint32_t hctsiz = READ4(sc, DOTG_HCTSIZ(td->channel)); + if (td->qh->dev_speed == USB_SPEED_HIGH) { + if (td->qh->flags &__DOTG_FLAGS_NEED_PING) { + DPRINTF("Add DOPNG flag\n"); + hctsiz |= HCTSIZ_DOPNG; + } + } + WRITE4(sc, DOTG_HCTSIZ(td->channel), hctsiz); + + hcchar &= ~HCCHAR_MC_EC_MASK; + hcchar |= (!(GETFLD(READ4(sc, DOTG_HFNUM), HFNUM_FRNUM) & 1))?HCCHAR_ODDFRM:0; + WRITE4(sc, DOTG_HCCHAR(td->channel), hcchar); + + hcchar |= HCCHAR_CHENA; + + td->qh->fixup_state = FIXUP_PEND; + usb_pc_cpu_flush(td->qh->fixup_pc); + + WRITE4(sc, DOTG_HCCHAR(td->channel), hcchar); + + + + return (1); /* busy */ +} + +static uint8_t +dotg_non_control_data_rx(struct dotg_td *td) +{ + struct dotg_softc *sc; + uint32_t rem; + uint8_t got_short; + + /* allocate endpoint and check pending */ + if (dotg_host_alloc_endpoint(td)) + return (1); /* busy */ + + if ( + (((td->qh->ep_type & UE_XFERTYPE) == UE_ISOCHRONOUS) || + ((td->qh->ep_type & UE_XFERTYPE) == UE_INTERRUPT)) && + (td->qh->next_tx_cycle >= cpu_ticks())) { + return (1); /* busy */ + } + + /* check error */ + if (td->error_any) + return (0); /* done */ + + got_short = 0; + + if (td->qh->fixup_state == FIXUP_CMPL) { + DPRINTF("%d: no errors, fixup_state == FIXUP_CMPL\n", __LINE__); + + /* invalidate data */ + usb_pc_cpu_invalidate(td->qh->fixup_pc); + + DPRINTF("\n"); +//#ifdef USB_DEBUG +// if (dotgdebug == 0x0fffffff) hexdump((uint8_t *)MIPS_PHYS_TO_KSEG1(td->qh->fixup_phys), td->qh->fixup_actlen, 0, 0); +//#endif + DPRINTF("\n"); + + /* verify transfer length */ + if (td->qh->this_xfersize != td->qh->fixup_actlen) { + if (td->qh->this_xfersize > td->qh->fixup_actlen) { + /* we have a short packet */ + td->short_pkt = 1; + got_short = 1; + } else { + /* invalid USB packet */ + td->error_any = 1; + return (0); /* we are complete */ + } + } + /* copy data into fixup buffer */ + usbd_copy_in(td->pc, td->offset, td->qh->fixup_buf, td->qh->fixup_actlen); + + /* post-increment RX buffer offset */ + td->offset += td->qh->fixup_actlen; + td->qh->fixup_off += td->qh->fixup_actlen; + td->remainder -= td->qh->fixup_actlen; + + td->qh->fixup_state = FIXUP_ALOC; + + if ((td->qh->ep_type & UE_XFERTYPE) == UE_ISOCHRONOUS) + return (0); /* done */ + } + + /* check if we are complete */ + if ((td->remainder == 0) || got_short) { + if (td->short_pkt) { + /* we are complete */ + return (0); + } + /* else need to receive a zero length packet */ + rem = 0; + td->short_pkt = 1; + } else { + /* get maximum length */ + rem = DOTG_MAX_FIXUP % td->qh->max_frame_size; + rem = DOTG_MAX_FIXUP - rem; + DPRINTFN(2, "DOTG_MAX_FIXUP=%d, td->qh->max_frame_size=%d\n", DOTG_MAX_FIXUP, td->qh->max_frame_size); + DPRINTFN(2, "rem=%d, td->qh->fixup_actlen=%d\n", rem, td->qh->fixup_actlen); + + if (rem == 0) { + /* should not happen */ + DPRINTFN(1, "Fixup buffer is too small\n"); + td->error_any = 1; + return (0); /* done */ + } + /* get minimum length */ + if (rem > td->remainder) + rem = td->remainder; + } + + /* invalidate data */ + usb_pc_cpu_invalidate(td->qh->fixup_pc); + + /* get softc */ + sc = td->qh->sc; + + + DPRINTF("%d: \t\tep_toggle_next=%d\n", __LINE__, td->qh->ep_toggle_next); + td->qh->fixup_off = 0; + int ret = configure_channel(td, rem, td->qh->ep_toggle_next?HCTSIZ_PID_DATA1:HCTSIZ_PID_DATA0, HCCHAR_EPDIR_IN); + if (ret != 0) + return (1); + uint32_t hcchar = READ4(sc, DOTG_HCCHAR(td->channel)); + +// if ( td->qh->ep_type == UE_INTERRUPT ) + hcchar |= (!(GETFLD(READ4(sc, DOTG_HFNUM), HFNUM_FRNUM) & 1))?HCCHAR_ODDFRM:0; + + hcchar |= HCCHAR_CHENA; + + td->qh->fixup_state = FIXUP_PEND; + usb_pc_cpu_flush(td->qh->fixup_pc); + + WRITE4(sc, DOTG_HCCHAR(td->channel), hcchar); + + return (1); /* busy */ +} + +static uint8_t +dotg_xfer_do_fifo(struct usb_xfer *xfer) +{ + struct dotg_td *td; + + td = xfer->td_transfer_cache; + + while (1) { + if ((td->func) (td)) { + /* operation in progress */ + break; + } + if (((void *)td) == xfer->td_transfer_last) { + DPRINTF("%d: td_transfer_last\n", __LINE__); + goto done; + } + if (td->error_any) { + DPRINTF("%d: error_any\n", __LINE__); + goto done; + } else if (td->remainder > 0) { + /* + * We had a short transfer. If there is no + * alternate next, stop processing ! + */ + DPRINTF("%d: td->remainder[%d] > 0\n", __LINE__, td->remainder); + if (td->alt_next == 0) { + DPRINTF("%d: alt_next is 0\n", __LINE__); + goto done; + } + } + /* + * Fetch the next transfer descriptor and transfer + * some flags to the next transfer descriptor + */ + td = td->obj_next; + xfer->td_transfer_cache = td; + } + return (1); /* not complete */ + +done: + /* compute all actual lengths */ + + dotg_standard_done(xfer); + + return (0); /* complete */ +} + +static usb_error_t +dotg_standard_done_sub(struct usb_xfer *xfer) +{ + struct dotg_td *td; + uint32_t len; + usb_error_t error; + + DPRINTFN(8, "dotg_standard_done_sub\n"); + + td = xfer->td_transfer_cache; + + do { + len = td->remainder; + + if (xfer->aframes != xfer->nframes) { + /* + * Verify the length and subtract + * the remainder from "frlengths[]": + */ + if (len > xfer->frlengths[xfer->aframes]) { + td->error_any = 1; + } else { + xfer->frlengths[xfer->aframes] -= len; + } + } + /* Check for transfer error */ + if (td->error_any) { + /* the transfer is finished */ + error = td->error_stall ? USB_ERR_STALLED : USB_ERR_IOERROR; + td = NULL; + break; + } + /* Check for short transfer */ + if (len > 0) { + if (xfer->flags_int.short_frames_ok) { + /* follow alt next */ + if (td->alt_next) { + td = td->obj_next; + } else { + td = NULL; + } + } else { + /* the transfer is finished */ + td = NULL; + } + error = 0; + break; + } + td = td->obj_next; + + /* this USB frame is complete */ + error = 0; + break; + + } while (0); + + /* update transfer cache */ + + xfer->td_transfer_cache = td; + + return (error); +} + +static void +dotg_standard_done(struct usb_xfer *xfer) +{ + struct dotg_qh *qh; + usb_error_t error = 0; + + DPRINTFN(12, "xfer=%p endpoint=%p transfer done\n", + xfer, xfer->endpoint); + + /* reset scanner */ + + xfer->td_transfer_cache = xfer->td_transfer_first; + + if (xfer->flags_int.control_xfr) { + + if (xfer->flags_int.control_hdr) + error = dotg_standard_done_sub(xfer); + + xfer->aframes = 1; + + if (xfer->td_transfer_cache == NULL) + goto done; + } + while (xfer->aframes != xfer->nframes) { + + error = dotg_standard_done_sub(xfer); + + xfer->aframes++; + + if (xfer->td_transfer_cache == NULL) + goto done; + } + + if (xfer->flags_int.control_xfr && + !xfer->flags_int.control_act) + error = dotg_standard_done_sub(xfer); + +done: + /* update data toggle */ + qh = xfer->qh_start[0]; + + xfer->endpoint->toggle_next = (qh->ep_toggle_next)? 1 : 0; + + dotg_device_done(xfer, error); +} + +static void +dotg_interrupt_poll(struct dotg_softc *sc) +{ + struct usb_xfer *xfer; + uint32_t gintsts = READ4(sc, DOTG_GINTSTS); + WRITE4(sc, DOTG_GINTSTS, gintsts); + + if ((gintsts & GINTSTS_PRTINT) || (gintsts & GINTSTS_DISCONNINT)) { + uint32_t hprt = READ4(sc, DOTG_HPRT); + WRITE4(sc, DOTG_HPRT, hprt & ~HPRT_PRTENA); + DPRINTFN(12, "gintsts=0x%08x, hprt=0x%08x\n", gintsts, hprt); + + if (hprt & HPRT_PRTENCHNG) + sc->sc_ischange = 1; + + if (hprt & HPRT_PRTCONNSTS) { + if (!(hprt & HPRT_PRTENA)) { + dotg_enable(sc); + } + } + + /* Call root hub port status handler */ + uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, sizeof(sc->sc_hub_idata)); + + } + { + uint32_t haint = READ4(sc, DOTG_HAINT); + WRITE4(sc, DOTG_HAINT, haint); + haint &= ((1<channels) - 1); + while (haint) { + int channel; + for (channel = 0; channel < sc->channels; channel ++) + if (haint & (1<sc_bus.intr_q.head, wait_entry) { + if (!dotg_xfer_do_fifo(xfer)) { + /* queue has been modified */ + goto repeat; + } + } +} + +static void +dotg_start_standard_chain(struct usb_xfer *xfer) +{ + DPRINTFN(8, "dotg_start_standard_chain\n"); + + /* poll one time */ + if (dotg_xfer_do_fifo(xfer)) { + DPRINTFN(8, "Not transfered, will be queued, ++++++++++++++++++++++++++++++++++ xfer=%p\n", xfer); + + /* put transfer on interrupt queue */ + mtx_lock_spin(&((struct dotg_qh *)xfer->qh_start[0])->sc->q_mtx); + usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); + mtx_unlock_spin(&((struct dotg_qh *)xfer->qh_start[0])->sc->q_mtx); + DPRINTFN(8, "queued ++++++++++++++++++++++++++++++++++ xfer=%p\n", xfer); + + /* start timeout, if any */ + if (xfer->timeout != 0) { + usbd_transfer_timeout_ms(xfer, + &dotg_timeout, xfer->timeout); + } + } +} + +void +dotg_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb) +{ + +} + + + +usb_error_t +dotg_init(struct dotg_softc *sc) +{ + int channel; + uint32_t tmp; + +#ifdef USB_DEBUG + dotgdebug = 0x0fffffff; +#endif +#define CP printf("%s:%d\n", __func__, __LINE__) + /* flush all cache into memory */ + usb_bus_mem_flush_all(&sc->sc_bus, &dotg_iterate_hw_softc); + + CP; + /* set up the bus struct */ + sc->sc_bus.methods = &dotg_bus_methods; + + /* set USB revision */ + sc->sc_bus.usbrev = USB_REV_2_0; + + CP; + USB_BUS_LOCK(&sc->sc_bus); + mtx_init(&sc->q_mtx, "otgusb_xferq_spin", NULL, MTX_SPIN); + + CP; + WRITE4(sc, DOTG_PCGCCTL, 0xffffffff); + DELAY(10000); + WRITE4(sc, DOTG_PCGCCTL, 0); + DELAY(10000); + + sc->index = 0; + + CP; +// sc->channels = GETFLD(READ4(sc, DOTG_GHWCFG2), GHWCFG2_NUMHSTCHNL)+1; + sc->channels = 8; + /* TODO(device): GHWCFG2_NUMDEVEPS for device mode */ + + sc->idle_hardware_channels = (1<channels) - 1; + DPRINTF("%d: idle_hardware_channels= 0x%08x\n", __LINE__, sc->idle_hardware_channels); + + CP; + WRITE4(sc, DOTG_GAHBCFG, + GAHBCFG_DMAEN | + GAHBCFG_NPTXFEMPLVL | + GAHBCFG_PTXFEMPLVL | + GAHBCFG_GLBLINTRMSK | + SETFLD(0, GAHBCFG_HBSTLEN)); + + CP; + tmp = READ4(sc, DOTG_GUSBCFG); + tmp &= ~(GUSBCFG_CORRUPTTXPACKET | GUSBCFG_USBTRDTIM_MASK | + GUSBCFG_TOUTCAL_MASK | GUSBCFG_DDRSEL | GUSBCFG_PHYLPWRCLKSEL); + tmp |= SETFLD(0xf, GUSBCFG_USBTRDTIM); + WRITE4(sc, DOTG_GUSBCFG, tmp); + + CP; + for (channel = 0; channel < sc->channels; channel++) + if (sc->idle_hardware_channels & (1 << channel)) { +#ifdef USB_DEBUG + if (dotgdebug) + printf("HCINTMSK(%d) = 0x%08x\n", channel, HCINTMSK_CHHLTDMSK | HCINTMSK_AHBERRMSK); +#endif + WRITE4(sc, DOTG_HCINTMSK(channel), HCINTMSK_CHHLTDMSK | HCINTMSK_AHBERRMSK); + } + + CP; + WRITE4(sc, DOTG_HAINTMSK, sc->idle_hardware_channels); + sc->sc_mode_device = 0; + DPRINTF("%s: USB%d is in host mode\n", __func__, 0); + + CP; + SETFIELD32(sc, DOTG_GINTMSK, GINTMSK_PRTINTMSK, 1); + SETFIELD32(sc, DOTG_GINTMSK, GINTMSK_DISCONNINTMSK, 1); + + CP; + tmp = READ4(sc, DOTG_HCFG); + tmp &= ~(HCFG_FSLSSUPP | HCFG_FSLSPCLKSEL_MASK); + tmp |= SETFLD(1, HCFG_FSLSPCLKSEL); + WRITE4(sc, DOTG_HCFG, tmp); + + CP; + if (READ4(sc, DOTG_HPRT) & HPRT_PRTCONNSTS) + SETFIELD32(sc, DOTG_HPRT, HPRT_PRTPWR, 1); + + CP; + USB_BUS_UNLOCK(&sc->sc_bus); + + CP; + /* catch lost interrupts */ + dotg_do_poll(&sc->sc_bus); + + CP; + /* Enable interrupts */ + tmp = READ4(sc, DOTG_GINTMSK); +// tmp &= ~(GINTMSK_SOFMSK); //// + tmp |= (GINTMSK_SOFMSK); + tmp |= (GINTMSK_OTGINTMSK | GINTMSK_MODEMISMSK | GINTMSK_HCHINTMSK); + WRITE4(sc, DOTG_GINTMSK, tmp); + + CP; + return (0); +} + +usb_error_t +dotg_uninit(struct dotg_softc *sc) +{ + return (0); +} + +void +dotg_suspend(struct dotg_softc *sc) +{ + +} + +void +dotg_resume(struct dotg_softc *sc) +{ + +} + +/*------------------------------------------------------------------------* + * dotg_interrupt - DOTG interrupt handler + *------------------------------------------------------------------------*/ + +int +dotg_interrupt(void *arg) +{ + struct dotg_softc *sc = arg; + + /* Get current interrupts mask */ + uint32_t tmp = READ4(sc, DOTG_GINTMSK); + + /* Disable interrupts */ + WRITE4(sc, DOTG_GINTMSK, 0); + + USB_BUS_LOCK(&sc->sc_bus); + + + /* poll all the USB transfers */ + dotg_interrupt_poll(sc); + + USB_BUS_UNLOCK(&sc->sc_bus); + + /* Restore interrupts */ + WRITE4(sc, DOTG_GINTMSK, tmp); + return (FILTER_HANDLED); +} + +/*------------------------------------------------------------------------* + * dump_xfer_info - DEBUG print info about xfer, ep and channel regs * + *------------------------------------------------------------------------*/ +#ifdef USB_DEBUG +static void +dump_xfer_info(struct usb_xfer *xfer) +{ + int channel; + + DPRINTF("Timeout xfer=%p\n", xfer); + usb_dump_xfer(xfer); + usb_dump_endpoint(xfer->endpoint); + + channel = ((struct dotg_td *)xfer->td_transfer_cache)->channel; + + if (channel >= 0) { + DPRINTF("channel=%d\n", channel); + dump_channel_regs(((struct dotg_qh *)xfer->qh_start[0])->sc, channel); + } else { + DPRINTF("No channel asigned\n"); + } +} +#endif + +/*------------------------------------------------------------------------* + * dotg_timeout - DOTG transfer timeout handler + *------------------------------------------------------------------------*/ +static void +dotg_timeout(void *arg) +{ + struct usb_xfer *xfer = arg; + + DPRINTF("xfer=%p\n", xfer); + + USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); + +#ifdef USB_DEBUG + dump_xfer_info(xfer); +#endif + + /* transfer is transferred */ + dotg_device_done(xfer, USB_ERR_TIMEOUT); +} + +/*------------------------------------------------------------------------* + * dotg_do_poll - DOTG poll transfers + *------------------------------------------------------------------------*/ +static void +dotg_do_poll(struct usb_bus *bus) +{ + struct dotg_softc *sc = DOTG_BUS2SC(bus); + + USB_BUS_LOCK(&sc->sc_bus); + dotg_interrupt_poll(sc); + USB_BUS_UNLOCK(&sc->sc_bus); +} + +static void +dotg_setup_standard_chain_sub(struct dotg_std_temp *temp) +{ + struct dotg_td *td; + + /* get current Transfer Descriptor */ + td = temp->td_next; + temp->td = td; + + /* prepare for next TD */ + temp->td_next = td->obj_next; + + /* fill out the Transfer Descriptor */ + td->func = temp->func; + td->pc = temp->pc; + td->offset = temp->offset; + td->remainder = temp->len; + td->error_any = 0; + td->error_stall = 0; + td->short_pkt = temp->short_pkt; + td->alt_next = temp->setup_alt_next; + if (td->qh->dev_speed == USB_SPEED_HIGH) { + td->qh->flags |= __DOTG_FLAGS_NEED_PING; + } +} + +static void +dotg_setup_standard_chain(struct usb_xfer *xfer) +{ + struct dotg_std_temp temp; + struct dotg_td *td; + uint32_t x; + + DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", + xfer->address, UE_GET_ADDR(xfer->endpointno), + xfer->sumlen, usbd_get_speed(xfer->xroot->udev)); + + + /* setup starting point */ + td = xfer->td_start[0]; + xfer->td_transfer_first = td; + xfer->td_transfer_cache = td; + + temp.td = NULL; + temp.td_next = td; + temp.setup_alt_next = xfer->flags_int.short_frames_ok; + temp.offset = 0; + temp.channel = td->channel; + + /* check if we should prepend a setup message */ + + DPRINTF("xfer=%p, control_xfr=%d, control_hdr=%d, control_act=%d, nframes=%d\n", xfer, + xfer->flags_int.control_xfr, xfer->flags_int.control_hdr, xfer->flags_int.control_act, + xfer->nframes + ); + if (xfer->flags_int.control_xfr) { + + if (xfer->flags_int.control_hdr) { + + DPRINTF("Add &dotg_host_control_header_tx to xfer=%p\n", xfer); + temp.func = &dotg_host_control_header_tx; + temp.len = xfer->frlengths[0]; + temp.pc = xfer->frbuffers + 0; + temp.short_pkt = temp.len ? 1 : 0; + + /* check for last frame */ + if (xfer->nframes == 1) { + /* + * no STATUS stage yet, SETUP is + * last + */ + if (xfer->flags_int.control_act) + temp.setup_alt_next = 0; + } + dotg_setup_standard_chain_sub(&temp); + } + x = 1; + } else { + x = 0; + } + + if (x != xfer->nframes) { + if (xfer->endpointno & UE_DIR_IN) { + if (xfer->flags_int.control_xfr) { + DPRINTF("Add &dotg_host_control_data_rx to xfer=%p\n", xfer); + temp.func = &dotg_host_control_data_rx; + } else { + DPRINTF("Add &dotg_non_control_data_rx to xfer=%p\n", xfer); + temp.func = &dotg_non_control_data_rx; + } + } else { + if (xfer->flags_int.control_xfr) { + DPRINTF("Add &dotg_host_control_data_tx to xfer=%p\n", xfer); + temp.func = &dotg_host_control_data_tx; + } else { + DPRINTF("Add &dotg_non_control_data_tx to xfer=%p\n", xfer); + temp.func = &dotg_non_control_data_tx; + } + } + + /* setup "pc" pointer */ + temp.pc = xfer->frbuffers + x; + } + while (x != xfer->nframes) { + + /* DATA0 or DATA1 message */ + + temp.len = xfer->frlengths[x]; + + x++; + + if (x == xfer->nframes) { + if (xfer->flags_int.control_xfr) { + /* no STATUS stage yet, DATA is last */ + if (xfer->flags_int.control_act) + temp.setup_alt_next = 0; + } else { + temp.setup_alt_next = 0; + } + } + if (temp.len == 0) { + + /* make sure that we send an USB packet */ + + temp.short_pkt = 0; + + } else { + + /* regular data transfer */ + + temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1; + } + DPRINTF("Add TD with len=%d to xfer=%p\n", temp.len, xfer); + dotg_setup_standard_chain_sub(&temp); + + if (xfer->flags_int.isochronous_xfr) { + /* get next data offset */ + temp.offset += temp.len; + } else { + /* get next Page Cache pointer */ + temp.pc = xfer->frbuffers + x; + } + } + + /* check if we should append a status stage */ + + if (xfer->flags_int.control_xfr && + !xfer->flags_int.control_act) { + + DPRINTF("Add &dotg_host_control_status_tx to xfer=%p\n", xfer); + temp.func = &dotg_host_control_status_tx; + temp.len = 0; + temp.pc = NULL; + temp.short_pkt = 0; + temp.setup_alt_next = 0; + + dotg_setup_standard_chain_sub(&temp); + } + /* must have at least one frame! */ + td = temp.td; + xfer->td_transfer_last = td; + + /* properly setup QH */ + + td->qh->fixup_state = FIXUP_NONE; + td->qh->ep_toggle_next = xfer->endpoint->toggle_next ? 1 : 0; +} + +/*------------------------------------------------------------------------* + * dotg_device_done - DOTG transfers done code + * + * NOTE: This function can be called more than one time in a row. + *------------------------------------------------------------------------*/ +static void +dotg_device_done(struct usb_xfer *xfer, usb_error_t error) +{ + USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); + + DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d ----------------------------------!!!!\n", + xfer, xfer->endpoint, error); + + /* + * 1) Free any endpoints. + * 2) Control transfers can be split and we should not re-open + * the data pipe between transactions unless there is an error. + */ + if ((xfer->flags_int.control_act == 0) || (error != 0)) { + struct dotg_td *td; + + td = xfer->td_start[0]; + + dotg_host_free_endpoint(td); + } + /* dequeue transfer and start next transfer */ + mtx_lock_spin(&((struct dotg_qh *)xfer->qh_start[0])->sc->q_mtx); + usbd_transfer_done(xfer, error); + mtx_unlock_spin(&((struct dotg_qh *)xfer->qh_start[0])->sc->q_mtx); + DPRINTFN(2, "xfer=%p removed from queue (error=%d) ----------------------------------!!!!\n", + xfer, error); +} + +/*------------------------------------------------------------------------* + * dotg bulk support + *------------------------------------------------------------------------*/ +static void +dotg_device_bulk_open(struct usb_xfer *xfer) +{ + return; +} + +static void +dotg_device_bulk_close(struct usb_xfer *xfer) +{ + dotg_device_done(xfer, USB_ERR_CANCELLED); +} + +static void +dotg_device_bulk_enter(struct usb_xfer *xfer) +{ + return; +} + +static void +dotg_device_bulk_start(struct usb_xfer *xfer) +{ + /* setup TDs */ + dotg_setup_standard_chain(xfer); + dotg_start_standard_chain(xfer); +} + +struct usb_pipe_methods dotg_device_bulk_methods = +{ + .open = dotg_device_bulk_open, + .close = dotg_device_bulk_close, + .enter = dotg_device_bulk_enter, + .start = dotg_device_bulk_start, +}; + +/*------------------------------------------------------------------------* + * dotg control support + *------------------------------------------------------------------------*/ +static void +dotg_device_ctrl_open(struct usb_xfer *xfer) +{ + return; +} + +static void +dotg_device_ctrl_close(struct usb_xfer *xfer) +{ + dotg_device_done(xfer, USB_ERR_CANCELLED); +} + +static void +dotg_device_ctrl_enter(struct usb_xfer *xfer) +{ + return; +} + +static void +dotg_device_ctrl_start(struct usb_xfer *xfer) +{ + /* setup TDs */ + dotg_setup_standard_chain(xfer); + dotg_start_standard_chain(xfer); +} + +struct usb_pipe_methods dotg_device_ctrl_methods = +{ + .open = dotg_device_ctrl_open, + .close = dotg_device_ctrl_close, + .enter = dotg_device_ctrl_enter, + .start = dotg_device_ctrl_start, +}; + +/*------------------------------------------------------------------------* + * dotg interrupt support + *------------------------------------------------------------------------*/ +static void +dotg_device_intr_open(struct usb_xfer *xfer) +{ + usb_hs_bandwidth_alloc(xfer); + return; +} + +static void +dotg_device_intr_close(struct usb_xfer *xfer) +{ + dotg_device_done(xfer, USB_ERR_CANCELLED); + /* bandwidth must be freed after device done */ + usb_hs_bandwidth_free(xfer); +} + +static void +dotg_device_intr_enter(struct usb_xfer *xfer) +{ + return; +} + +static void +dotg_device_intr_start(struct usb_xfer *xfer) +{ + /* setup TDs */ + dotg_setup_standard_chain(xfer); + dotg_start_standard_chain(xfer); +} + +struct usb_pipe_methods dotg_device_intr_methods = +{ + .open = dotg_device_intr_open, + .close = dotg_device_intr_close, + .enter = dotg_device_intr_enter, + .start = dotg_device_intr_start, +}; + +/*------------------------------------------------------------------------* + * dotg isochronous support + *------------------------------------------------------------------------*/ +static void +dotg_device_isoc_open(struct usb_xfer *xfer) +{ + return; +} + +static void +dotg_device_isoc_close(struct usb_xfer *xfer) +{ + dotg_device_done(xfer, USB_ERR_CANCELLED); +} + +static void +dotg_device_isoc_enter(struct usb_xfer *xfer) +{ + struct dotg_softc *sc = DOTG_BUS2SC(xfer->xroot->bus); + uint32_t temp; + uint32_t frame_count; + uint32_t fs_frames; + + DPRINTFN(5, "xfer=%p next=%d nframes=%d\n", + xfer, xfer->endpoint->isoc_next, xfer->nframes); + + /* get the current frame index */ + + frame_count = /*(sc->init_flags & DEVICE_MODE)? + GETFLD(READ4(sc, DOTG_DSTS), DSTS_SOFFN) : */ + GETFLD(READ4(sc, DOTG_HFNUM), HFNUM_FRNUM); + + + /* + * check if the frame index is within the window where the frames + * will be inserted + */ + temp = (frame_count - xfer->endpoint->isoc_next) & 0x7FF; + + if (usbd_get_speed(xfer->xroot->udev) == USB_SPEED_HIGH) { + fs_frames = (xfer->nframes + 7) / 8; + } else { + fs_frames = xfer->nframes; + } + + if ((xfer->endpoint->is_synced == 0) || (temp < fs_frames)) { + /* + * If there is data underflow or the pipe queue is + * empty we schedule the transfer a few frames ahead + * of the current frame position. Else two isochronous + * transfers might overlap. + */ + xfer->endpoint->isoc_next = (frame_count + 3) & 0x7FF; + xfer->endpoint->is_synced = 1; + DPRINTFN(2, "start next=%d\n", xfer->endpoint->isoc_next); + } + /* + * compute how many milliseconds the insertion is ahead of the + * current frame position: + */ + temp = (xfer->endpoint->isoc_next - frame_count) & 0x7FF; + + /* + * pre-compute when the isochronous transfer will be finished: + */ + xfer->isoc_time_complete = + usb_isoc_time_expand(&sc->sc_bus, frame_count) + temp + + fs_frames; + + /* compute frame number for next insertion */ + xfer->endpoint->isoc_next += fs_frames; +} + +static void +dotg_device_isoc_start(struct usb_xfer *xfer) +{ + /* setup TDs */ + dotg_setup_standard_chain(xfer); + dotg_start_standard_chain(xfer); +} + +struct usb_pipe_methods dotg_device_isoc_methods = +{ + .open = dotg_device_isoc_open, + .close = dotg_device_isoc_close, + .enter = dotg_device_isoc_enter, + .start = dotg_device_isoc_start, +}; + +/*------------------------------------------------------------------------* + * DOTG root HUB support + *------------------------------------------------------------------------* + * Simulate a hardware HUB by handling all the necessary requests. + *------------------------------------------------------------------------*/ +static const +struct usb_device_descriptor dotg_devd = { + .bLength = sizeof(dotg_devd), + .bDescriptorType = UDESC_DEVICE, + .bcdUSB = {0x00, 0x02}, + .bDeviceClass = UDCLASS_HUB, + .bDeviceSubClass = UDSUBCLASS_HUB, + .bDeviceProtocol = UDPROTO_FSHUB, + .bMaxPacketSize = 64, + .idVendor = {0}, + .idProduct = {0}, + .bcdDevice = {0x00, 0x01}, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 0, + .bNumConfigurations = 1, +}; + +static const +struct usb_device_qualifier dotg_odevd = { + .bLength = sizeof(dotg_odevd), + .bDescriptorType = UDESC_DEVICE_QUALIFIER, + .bcdUSB = {0x00, 0x02}, + .bDeviceClass = UDCLASS_HUB, + .bDeviceSubClass = UDSUBCLASS_HUB, + .bDeviceProtocol = UDPROTO_FSHUB, + .bMaxPacketSize0 = 0, + .bNumConfigurations = 0, + .bReserved = 0, +}; + +static const +struct dotg_config_desc dotg_confd = { + .confd = { + .bLength = sizeof(struct usb_config_descriptor), + .bDescriptorType = UDESC_CONFIG, + .wTotalLength[0] = sizeof(dotg_confd), + .bNumInterface = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = UC_SELF_POWERED, + .bMaxPower = 0 /* max power */ + }, + .ifcd = { + .bLength = sizeof(struct usb_interface_descriptor), + .bDescriptorType = UDESC_INTERFACE, + .bNumEndpoints = 1, + .bInterfaceClass = UICLASS_HUB, + .bInterfaceSubClass = UISUBCLASS_HUB, + .bInterfaceProtocol = UIPROTO_FSHUB, + }, + .endpd = { + .bLength = sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = UDESC_ENDPOINT, + .bEndpointAddress = UE_DIR_IN | DOTG_INTR_ENDPT, + .bmAttributes = UE_INTERRUPT, + .wMaxPacketSize[0] = 8, /* max packet (63 ports) */ + .bInterval = 255, + }, +}; + +static const +struct usb_hub_descriptor_min dotg_hubd = +{ + .bDescLength = sizeof(dotg_hubd), + .bDescriptorType = UDESC_HUB, + .bNbrPorts = 1, + .wHubCharacteristics = {UHD_OC_INDIVIDUAL, 0}, + .bPwrOn2PwrGood = 50, + .bHubContrCurrent = 0, + .DeviceRemovable = {0x00}, /* all ports are removable */ +}; + +static usb_error_t +dotg_roothub_exec(struct usb_device *udev, + struct usb_device_request *req, const void **pptr, uint16_t *plength) +{ + struct dotg_softc *sc = DOTG_BUS2SC(udev->bus); + const void *ptr; + const char *str_ptr; + uint16_t value; + uint16_t index; + uint16_t status; + uint16_t change; + uint16_t len; + usb_error_t err; + + USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); + + /* XXX disable power save mode, hence it is not supported */ + udev->power_mode = USB_POWER_MODE_ON; + + /* buffer reset */ + ptr = (const void *)&sc->sc_hub_desc.temp; + len = 0; + err = 0; + + value = UGETW(req->wValue); + index = UGETW(req->wIndex); + + DPRINTFN(3, "type=0x%02x request=0x%02x wLen=0x%04x " + "wValue=0x%04x wIndex=0x%04x\n", + req->bmRequestType, req->bRequest, + UGETW(req->wLength), value, index); + +#define C(x,y) ((x) | ((y) << 8)) + switch (C(req->bRequest, req->bmRequestType)) { + case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): + case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): + case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): + break; + case C(UR_GET_CONFIG, UT_READ_DEVICE): + len = 1; + sc->sc_hub_desc.temp[0] = sc->sc_conf; + break; + case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): + switch (value >> 8) { + case UDESC_DEVICE: + if ((value & 0xff) != 0) { + err = USB_ERR_IOERROR; + goto done; + } + len = sizeof(dotg_devd); + + ptr = (const void *)&dotg_devd; + break; + + case UDESC_DEVICE_QUALIFIER: + if ((value & 0xff) != 0) { + err = USB_ERR_IOERROR; + goto done; + } + len = sizeof(dotg_odevd); + ptr = (const void *)&dotg_odevd; + break; + + case UDESC_CONFIG: + if ((value & 0xff) != 0) { + err = USB_ERR_IOERROR; + goto done; + } + len = sizeof(dotg_confd); + ptr = (const void *)&dotg_confd; + break; + + case UDESC_STRING: + switch (value & 0xff) { + case 0: /* Language table */ + str_ptr = "\001"; + break; + + case 1: /* Vendor */ + str_ptr = "DWC"; + break; + + case 2: /* Product */ + str_ptr = "OTG Root HUB"; + break; + + default: + str_ptr = ""; + break; + } + + len = usb_make_str_desc(sc->sc_hub_desc.temp, + sizeof(sc->sc_hub_desc.temp), str_ptr); + break; + + default: + err = USB_ERR_IOERROR; + goto done; + } + break; + case C(UR_GET_INTERFACE, UT_READ_INTERFACE): + len = 1; + sc->sc_hub_desc.temp[0] = 0; + break; + case C(UR_GET_STATUS, UT_READ_DEVICE): + len = 2; + USETW(sc->sc_hub_desc.stat.wStatus, UDS_SELF_POWERED); + break; + case C(UR_GET_STATUS, UT_READ_INTERFACE): + case C(UR_GET_STATUS, UT_READ_ENDPOINT): + len = 2; + USETW(sc->sc_hub_desc.stat.wStatus, 0); + break; + case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): + if (value >= DOTG_MAX_DEVICES) { + err = USB_ERR_IOERROR; + goto done; + } + sc->sc_addr = value; + break; + case C(UR_SET_CONFIG, UT_WRITE_DEVICE): + if ((value != 0) && (value != 1)) { + err = USB_ERR_IOERROR; + goto done; + } + sc->sc_conf = value; + break; + case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): + break; + case C(UR_SET_FEATURE, UT_WRITE_DEVICE): + case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): + case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): + err = USB_ERR_IOERROR; + goto done; + case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): + break; + case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): + break; + /* Hub requests */ + case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): + break; + case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): + if (index != 1) { + err = USB_ERR_IOERROR; + goto done; + } + + switch (value) { + case UHF_PORT_ENABLE: + break; + case UHF_PORT_SUSPEND: + break; + case UHF_PORT_RESET: + break; + case UHF_C_PORT_CONNECTION: + break; + case UHF_C_PORT_ENABLE: + break; + case UHF_C_PORT_OVER_CURRENT: + break; + case UHF_C_PORT_RESET: + sc->sc_isreset = 0; + goto done; + case UHF_C_PORT_SUSPEND: + break; + case UHF_PORT_POWER: + SETFIELD32(sc, DOTG_HPRT, HPRT_PRTPWR, 0); + break; + case UHF_PORT_CONNECTION: + case UHF_PORT_OVER_CURRENT: + case UHF_PORT_LOW_SPEED: + default: + err = USB_ERR_IOERROR; + goto done; + } + break; + case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): + if ((value & 0xff) != 0) { + err = USB_ERR_IOERROR; + goto done; + } + sc->sc_hubd = dotg_hubd; + sc->sc_hubd.bNbrPorts = 1; + len = sizeof(sc->sc_hubd); + ptr = (const void *)&sc->sc_hubd; + break; + case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): + len = 16; + memset(sc->sc_hub_desc.temp, 0, 16); + break; + case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): + if ((index < 1) || (index > 1) ) { + err = USB_ERR_IOERROR; + goto done; + } + + status = change = 0; + + uint32_t hprt = READ4(sc, DOTG_HPRT); + + status |= (hprt & HPRT_PRTCONNSTS)? + UPS_CURRENT_CONNECT_STATUS:0; + status |= (hprt & HPRT_PRTENA)? + UPS_PORT_ENABLED:0; + status |= (hprt & HPRT_PRTOVRCURRACT)? + UPS_OVERCURRENT_INDICATOR:0; + status |= (hprt & HPRT_PRTPWR)? + UPS_PORT_POWER:0; + + status |= (GETFLD(hprt, HPRT_PRTSPD) == HPRT_PRTSPD_LOW)? + UPS_LOW_SPEED: + (GETFLD(hprt, HPRT_PRTSPD) == HPRT_PRTSPD_FULL)? + 0: + UPS_HIGH_SPEED; + + change |= (hprt & HPRT_PRTENCHNG)?UPS_C_CONNECT_STATUS:0; + change |= (sc->sc_ischange)?UPS_C_CONNECT_STATUS:0; + sc->sc_ischange = 0; + + if (sc->sc_isreset) + change |= UPS_C_PORT_RESET; + + USETW(sc->sc_hub_desc.ps.wPortStatus, status); + USETW(sc->sc_hub_desc.ps.wPortChange, change); + + len = sizeof(sc->sc_hub_desc.ps); + break; + case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): + err = USB_ERR_IOERROR; + goto done; + case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): + break; + case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): + if ((index < 1) || (index > 1)) { + err = USB_ERR_IOERROR; + goto done; + } + + switch (value) { + case UHF_PORT_RESET: + DPRINTF("Reset port\n"); + /* passtrow */ + case UHF_PORT_ENABLE: + if (dotg_enable(sc)) { + err = USB_ERR_IOERROR; + goto done; + } + sc->sc_isreset = 1; + goto done; + case UHF_PORT_POWER: + /* pretend we turned on power */ + SETFIELD32(sc, DOTG_HPRT, HPRT_PRTPWR, 1); + /* 20ms */ + usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 50); + goto done; + case UHF_PORT_SUSPEND: + goto done; + case UHF_C_PORT_CONNECTION: + case UHF_C_PORT_ENABLE: + case UHF_C_PORT_OVER_CURRENT: + case UHF_PORT_CONNECTION: + case UHF_PORT_OVER_CURRENT: + case UHF_PORT_LOW_SPEED: + case UHF_C_PORT_SUSPEND: + case UHF_C_PORT_RESET: + default: + err = USB_ERR_IOERROR; + goto done; + } + break; + default: + err = USB_ERR_IOERROR; + goto done; + } +done: + *plength = len; + *pptr = ptr; + return (err); +} + +static void +dotg_xfer_setup(struct usb_setup_params *parm) +{ + struct usb_page_search page_info; + struct usb_page_cache *pc; + struct dotg_softc *sc; + struct dotg_qh *qh; + struct usb_xfer *xfer; + void *last_obj; + uint32_t n; + uint32_t ntd; + + sc = DOTG_BUS2SC(parm->udev->bus); + xfer = parm->curr_xfer; + qh = NULL; + + + /* + * NOTE: This driver does not use any of the parameters that + * are computed from the following values. Just set some + * reasonable dummies: + */ + + parm->hc_max_packet_size = 0x400; + parm->hc_max_packet_count = 8; + parm->hc_max_frame_size = 0x2000; + + usbd_transfer_setup_sub(parm); + + if (parm->err) + return; + + /* Allocate a queue head */ + + if (usbd_transfer_setup_sub_malloc( + parm, &pc, sizeof(struct dotg_qh), + USB_HOST_ALIGN, 1)) { + parm->err = USB_ERR_NOMEM; + return; + } + if (parm->buf) { + usbd_get_page(pc, 0, &page_info); + + qh = page_info.buffer; + + /* fill out QH */ + + qh->sc = DOTG_BUS2SC(xfer->xroot->bus); + qh->max_frame_size = xfer->max_frame_size; + qh->max_packet_size = xfer->max_packet_size; + qh->ep_num = xfer->endpointno; + qh->ep_type = xfer->endpoint->edesc->bmAttributes; + qh->dev_addr = xfer->address; + qh->dev_speed = usbd_get_speed(xfer->xroot->udev); + qh->port_index = xfer->xroot->udev->port_index; + + switch (xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE) { + case UE_INTERRUPT: + if (usbd_get_speed(xfer->xroot->udev) == USB_SPEED_HIGH) + qh->ep_interval = xfer->interval * 8; + else + qh->ep_interval = xfer->interval * 1; + break; + case UE_ISOCHRONOUS: + qh->ep_interval = 1 << xfer->fps_shift; + break; + default: + qh->ep_interval = 0; + break; + } + + qh->ep_mult = xfer->max_packet_count & 3; + qh->hs_hub_addr = xfer->xroot->udev->hs_hub_addr; + qh->hs_hub_port = xfer->xroot->udev->hs_port_no; + } + xfer->qh_start[0] = qh; + + /* Allocate a fixup buffer */ + + if (usbd_transfer_setup_sub_malloc( + parm, &pc, DOTG_MAX_FIXUP, + DOTG_MAX_FIXUP, 1)) { + parm->err = USB_ERR_NOMEM; + return; + } + if (parm->buf) { + usbd_get_page(pc, 0, &page_info); + + qh->fixup_phys = page_info.physaddr; + qh->fixup_pc = pc; + qh->fixup_buf = page_info.buffer; + } + /* Allocate transfer descriptors */ + + last_obj = NULL; + + ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC */ ; + + if (usbd_transfer_setup_sub_malloc( + parm, &pc, sizeof(struct dotg_td), + USB_HOST_ALIGN, ntd)) { + parm->err = USB_ERR_NOMEM; + return; + } + if (parm->buf) { + for (n = 0; n != ntd; n++) { + struct dotg_td *td; + + usbd_get_page(pc + n, 0, &page_info); + + td = page_info.buffer; + + td->qh = qh; + td->obj_next = last_obj; + + last_obj = td; + } + } + xfer->td_start[0] = last_obj; +} + +static void +dotg_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, + struct usb_endpoint *ep) +{ + struct dotg_softc *sc = DOTG_BUS2SC(udev->bus); + + DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n", + ep, udev->address, edesc->bEndpointAddress, + udev->flags.usb_mode, sc->sc_addr); + + if (udev->flags.usb_mode != USB_MODE_HOST) { + /* not supported */ + return; + } + if (udev->device_index != sc->sc_addr) { + switch (edesc->bmAttributes & UE_XFERTYPE) { + case UE_CONTROL: + ep->methods = &dotg_device_ctrl_methods; + break; + case UE_INTERRUPT: + ep->methods = &dotg_device_intr_methods; + break; + case UE_ISOCHRONOUS: + if (udev->speed != USB_SPEED_LOW) + ep->methods = &dotg_device_isoc_methods; + break; + case UE_BULK: + ep->methods = &dotg_device_bulk_methods; + break; + default: + /* do nothing */ + break; + } + } +} + +static void +dotg_xfer_unsetup(struct usb_xfer *xfer) +{ +} + +static void +dotg_get_dma_delay(struct usb_device *udev, uint32_t *pus) +{ + /* DMA delay - wait until any use of memory is finished */ + *pus = (2125); /* microseconds */ +// *pus = (300); /* microseconds */ +} + +static void +dotg_device_resume(struct usb_device *udev) +{ + DPRINTF("%s: Nothing to do.\n", __func__); +} + +static void +dotg_device_suspend(struct usb_device *udev) +{ + DPRINTF("%s: Nothing to do.\n", __func__); +} + +static void +dotg_set_hw_power(struct usb_bus *bus) +{ +} + +struct usb_bus_methods dotg_bus_methods = { + .endpoint_init = dotg_ep_init, + .xfer_setup = dotg_xfer_setup, + .xfer_unsetup = dotg_xfer_unsetup, + .get_dma_delay = dotg_get_dma_delay, + .device_resume = dotg_device_resume, + .device_suspend = dotg_device_suspend, + .set_hw_power = dotg_set_hw_power, + .roothub_exec = dotg_roothub_exec, + .xfer_poll = dotg_do_poll, +}; + + + + + + diff --git a/sys/dev/usb/controller/dotg.h b/sys/dev/usb/controller/dotg.h new file mode 100644 index 0000000..dc68fee --- /dev/null +++ b/sys/dev/usb/controller/dotg.h @@ -0,0 +1,243 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2010,2011 Aleksandr Rybalko. All rights reserved. + * Copyright (c) 2010 Hans Petter Selasky. 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 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 THE 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. + */ + +#ifndef _DOTG_H_ +#define _DOTG_H_ + +#define DOTG_MAX_DEVICES MIN(USB_MAX_DEVICES, 64) +/* + * The second port is on a different IRQ and so we disable it for now. + */ +#if 1 +#define DOTG_MAX_PORTS 1 /* hardcoded */ +#else +#define DOTG_MAX_PORTS 2 /* hardcoded */ +#endif + +#if 1 +#define DOTG_MAX_FIXUP 4096 /* bytes */ +#else +#define DOTG_MAX_FIXUP 2048 /* bytes */ +#endif + +#define DOTG_INTR_ENDPT 0x01 + +#define MAX_RETRIES 3 +#define MAX_PIPES 32 +#define MAX_TRANSACTIONS 256 +#define MAX_CHANNELS 4 +#define MAX_USB_ADDRESS 127 +#define MAX_USB_ENDPOINT 15 +#define MAX_USB_HUB_PORT 15 + +typedef enum { + DOTG_COMPLETE_SUCCESS, + DOTG_COMPLETE_SHORT, + DOTG_COMPLETE_CANCEL, + DOTG_COMPLETE_ERROR, + DOTG_COMPLETE_STALL, + DOTG_COMPLETE_XACTERR, + DOTG_COMPLETE_DATATGLERR, + DOTG_COMPLETE_BABBLEERR, + DOTG_COMPLETE_FRAMEERR, +} dotg_complete_t; + + +typedef enum { + __DOTG_FLAGS_NEED_PING = 1 << 0, + __DOTG_FLAGS_DONE_PING = 1 << 1, +} dotg_flags_t; + +enum fixup_state { + FIXUP_NONE = 0, + FIXUP_ALOC, + FIXUP_PEND, + FIXUP_NAK, + FIXUP_CMPL +}; + +struct dotg_qh; +struct dotg_td; +struct dotg_softc; + +typedef uint8_t (dotg_cmd_t)(struct dotg_td *td); + +struct dotg_td { + struct dotg_qh *qh; + struct dotg_td *obj_next; + struct usb_page_cache *pc; + dotg_cmd_t *func; + + uint8_t error_any:1; + uint8_t error_stall:1; + uint8_t short_pkt:1; + uint8_t alt_next:1; + uint8_t reserved:4; + int8_t channel; + uint16_t offset; + uint32_t remainder; +}; + +struct dotg_qh { + struct dotg_softc *sc; + struct usb_page_cache *fixup_pc; + uint8_t *fixup_buf; + + uint16_t max_frame_size; + uint16_t max_packet_size; + uint16_t fixup_len; + uint16_t fixup_actlen; + uint16_t fixup_off; + uint16_t this_xfersize; + uint16_t ep_interval; + + uint8_t dev_addr; + uint8_t dev_speed; + uint8_t ep_mult; + uint8_t ep_num; + uint8_t ep_type; + + uint8_t ep_toggle_next:1; + uint8_t fixup_state:3; + uint8_t port_index:3;//30 + uint8_t hs_hub_port; //31 + uint8_t hs_hub_addr; //32 + + /* We don`t know system address width */ + vm_paddr_t fixup_phys; + + + int8_t split_sc_frame; + + uint64_t next_tx_cycle; + uint32_t flags; + int retries; +}; + +struct dotg_config_desc { + struct usb_config_descriptor confd; + struct usb_interface_descriptor ifcd; + struct usb_endpoint_descriptor endpd; +} __packed; + +union dotg_hub_desc { + struct usb_status stat; + struct usb_port_status ps; + uint8_t temp[128]; +}; + +struct dotg_softc { + + struct usb_bus sc_bus; /* base device */ + union dotg_hub_desc sc_hub_desc; + + struct usb_device *sc_devices[DOTG_MAX_DEVICES]; + + int sc_mem_rid; + struct resource *sc_mem_res; + int sc_irq_rid; + struct resource *sc_irq_res; + void *sc_intr_hdl; + bus_space_handle_t sc_bsh; /* bus space handle */ + bus_space_tag_t sc_bst; /* bus space tag */ + /* Next two used on Octeons */ + bus_space_handle_t sc_iobsh; /* bus space handle for 64b pointers*/ + bus_space_tag_t sc_iobst; /* bus space tag for 64b pointers */ + + device_t sc_dev; + + struct usb_hub_descriptor_min sc_hubd; + + uint8_t sc_addr; /* device address */ + uint8_t sc_conf; /* device configuration */ + uint8_t sc_isreset; /* set if current port + * is reset */ + uint8_t sc_ischange; /* port change status */ + uint8_t sc_hub_idata[1]; + uint8_t sc_mode_device; + + int init_flags; + int index; + int channels; + int idle_hardware_channels; + int active_transactions; + uint32_t dotg_hprt; + struct dotg_td *td_for_channel[MAX_CHANNELS]; + struct dotg_ports *port_status; + uint32_t tx_packets; + uint32_t tx_packets_ack; + struct mtx q_mtx; +}; + + + +#define GETFLD(data, fld) (((data) & fld ## _MASK) >> fld ## _SHIFT) +#define SETFLD(data, fld) (((data) << fld ## _SHIFT) & fld ## _MASK) + +#define SETFIELD32(sc, address, field, value) \ + WRITE4(sc, (address), (READ4(sc, (address)) & ~field) | \ + ((value)?(field):0)) +#define SETFIELD32_(sc, address, field, value) \ + WRITE4(sc, (address), (READ4(sc, (address)) & ~field ## _MASK) |\ + ((value)<< field ## _SHIFT) ) + +/* This macro spins on a field waiting for it to reach a value */ +#define WAIT_FOR_FIELD32(sc, address, field, value, timeout_usec)\ + ({int result; \ + do { \ + uint32_t c, timeout = timeout_usec; \ + while (1) \ + { \ + c = (READ4(sc, address) & field)?1:0; \ + if (c == (value)) { \ + result = 0; \ + break; \ + } else if (!timeout) { \ + result = -1; \ + break; \ + } else { \ + DELAY(1); timeout--; \ + } \ + } \ + } while (0); \ + result;}) + + +int dotg_get_num_ports(void); + +int dotg_enable(struct dotg_softc *); +int dotg_disable(struct dotg_softc *); + +usb_bus_mem_cb_t dotg_iterate_hw_softc; +usb_error_t dotg_init(struct dotg_softc *); +usb_error_t dotg_uninit(struct dotg_softc *); +void dotg_suspend(struct dotg_softc *); +void dotg_resume(struct dotg_softc *); +int dotg_interrupt(void *); + +#endif /* _DOTG_H_ */ diff --git a/sys/dev/usb/controller/dotgreg.h b/sys/dev/usb/controller/dotgreg.h new file mode 100644 index 0000000..1f3670a --- /dev/null +++ b/sys/dev/usb/controller/dotgreg.h @@ -0,0 +1,640 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2010,2011 Aleksandr Rybalko. 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 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 THE 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. + */ + +#ifndef __DOTG_REG_H__ +#define __DOTG_REG_H__ + +#define DOTG_GOTGCTL 0x0000 +#define DOTG_GOTGINT 0x0004 +#define DOTG_GAHBCFG 0x0008 +#define DOTG_GUSBCFG 0x000C +#define DOTG_GRSTCTL 0x0010 +#define DOTG_GINTSTS 0x0014 +#define DOTG_GINTMSK 0x0018 +#define DOTG_GRXSTSRD 0x001C +#define DOTG_GRXSTSRH 0x001C +#define DOTG_GRXSTSPD 0x0020 +#define DOTG_GRXSTSPH 0x0020 +#define DOTG_GRXFSIZ 0x0024 +#define DOTG_GNPTXFSIZ 0x0028 +#define DOTG_GNPTXSTS 0x002C +#define DOTG_GI2CCTL 0x0030 +#define DOTG_GPVNDCTL 0x0034 +#define DOTG_GGPIO 0x0038 +#define DOTG_GUID 0x003c +#define DOTG_GSNPSID 0x0040 +#define DOTG_GHWCFG1 0x0044 +#define DOTG_GHWCFG2 0x0048 +#define DOTG_GHWCFG3 0x004C +#define DOTG_GHWCFG4 0x0050 + +#define DOTG_HPTXFSIZ 0x0100 +/* start from 0x104, but fifo0 not exists */ +#define DOTG_DPTXFSIZ(fifo) (0x0100 + (fifo)*4) +#define DOTG_DIEPTXF(fifo) (0x0100 + (fifo)*4) + +#define DOTG_HCFG 0x0400 +#define DOTG_HFIR 0x0404 +#define DOTG_HFNUM 0x0408 +#define DOTG_HPTXSTS 0x0410 +#define DOTG_HAINT 0x0414 +#define DOTG_HAINTMSK 0x0418 +#define DOTG_HPRT 0x0440 + +#define DOTG_HCCHAR(ch) (0x0500 + (ch)*0x20) +#define DOTG_HCSPLT(ch) (0x0504 + (ch)*0x20) +#define DOTG_HCINT(ch) (0x0508 + (ch)*0x20) +#define DOTG_HCINTMSK(ch) (0x050C + (ch)*0x20) +#define DOTG_HCTSIZ(ch) (0x0510 + (ch)*0x20) +#define DOTG_HCDMA(ch) (0x0514 + (ch)*0x20) +#define DOTG_HCDMAI(ch) (0x0514 + (ch)*0x20) +#define DOTG_HCDMAO(ch) (0x0514 + (ch)*0x20) + +/* Device Mode */ +#define DOTG_DCFG 0x0800 +#define DOTG_DCTL 0x0804 +#define DOTG_DSTS 0x0808 +#define DOTG_DIEPMSK 0x0810 +#define DOTG_DOEPMSK 0x0814 +#define DOTG_DAINT 0x0818 +#define DOTG_DAINTMSK 0x081C +#define DOTG_DTKNQR1 0x0820 +#define DOTG_DTKNQR2 0x0824 +#define DOTG_DVBUSDIS 0x0828 +#define DOTG_DVBUSPULSE 0x082C +#define DOTG_DTHRCTL 0x0830 +#define DOTG_DTKNQR4 0x0834 +#define DOTG_DIEPEMPMSK 0x0834 +#define DOTG_DEACHINT 0x0838 +#define DOTG_DEACHINTMSK 0x083C +#define DOTG_DIEPEACHINTMSK(ch) (0x0840 + (ch)*4) +#define DOTG_DOEPEACHINTMSK(ch) (0x0880 + (ch)*4) + +#define DOTG_DIEPCTL(ep) (0x0900 + (ep)*0x20) +#define DOTG_DIEPINT(ep) (0x0908 + (ep)*0x20) +#define DOTG_DIEPTSIZ(ep) (0x0910 + (ep)*0x20) +#define DOTG_DIEPDMA(ep) (0x0914 + (ep)*0x20) +#define DOTG_DTXFSTS(ep) (0x0918 + (ep)*0x20) +#define DOTG_DIEPDMAB(ep) (0x091c + (ep)*0x20) + +#define DOTG_DOEPCTL(ep) (0x0B00 + (ep)*0x20) +#define DOTG_DOEPFN(ep) (0x0B04 + (ep)*0x20) +#define DOTG_DOEPINT(ep) (0x0B08 + (ep)*0x20) +#define DOTG_DOEPTSIZ(ep) (0x0B10 + (ep)*0x20) +#define DOTG_DOEPDMA(ep) (0x0B14 + (ep)*0x20) +#define DOTG_DOEPDMAB(ep) (0x0B1c + (ep)*0x20) +/* End Device Mode */ + +/* Host Mode +#define DOTG_CTL_STATUS 0x0800 +#define DOTG_DMA0_INB_CHN0 0x0818 +#define DOTG_DMA0_INB_CHN1 0x0820 +#define DOTG_DMA0_INB_CHN2 0x0828 +#define DOTG_DVBUSDIS 0x0828 +#define DOTG_DVBUSPULSE 0x082c +#define DOTG_DMA0_INB_CHN3 0x0830 +#define DOTG_DMA0_INB_CHN4 0x0838 +#define DOTG_DMA0_INB_CHN5 0x0840 +#define DOTG_DMA0_INB_CHN6 0x0848 +#define DOTG_DMA0_INB_CHN7 0x0850 +#define DOTG_DMA0_OUTB_CHN0 0x0858 +#define DOTG_DMA0_OUTB_CHN1 0x0860 +#define DOTG_DMA0_OUTB_CHN2 0x0868 +#define DOTG_DMA0_OUTB_CHN3 0x0870 +#define DOTG_DMA0_OUTB_CHN4 0x0878 +#define DOTG_DMA0_OUTB_CHN5 0x0880 +#define DOTG_DMA0_OUTB_CHN6 0x0888 +#define DOTG_DMA0_OUTB_CHN7 0x0890 + End Host Mode */ + +#define DOTG_PCGCCTL 0x0E00 + +#define GOTGCTL_BSESVLD (1<<19) +#define GOTGCTL_ASESVLD (1<<18) +#define GOTGCTL_DBNCTIME (1<<17) +#define GOTGCTL_CONIDSTS (1<<16) +#define GOTGCTL_DEVHNPEN (1<<11) +#define GOTGCTL_HSTSETHNPEN (1<<10) +#define GOTGCTL_HNPREQ (1<<9) +#define GOTGCTL_HSTNEGSCS (1<<8) +#define GOTGCTL_SESREQ (1<<1) +#define GOTGCTL_SESREQSCS (1<<0) + +#define GOTGCTL_DBNCEDONE (1<<19) +#define GOTGCTL_ADEVTOUTCHG (1<<18) +#define GOTGCTL_HSTNEGDET (1<<17) +#define GOTGCTL_HSTNEGSUCSTSCHG (1<<9) +#define GOTGCTL_SESREQSUCSTSCHG (1<<8) +#define GOTGCTL_SESENDDET (1<<2) + +#define GAHBCFG_PTXFEMPLVL (1<<8) +#define GAHBCFG_NPTXFEMPLVL (1<<7) +#define GAHBCFG_DMAEN (1<<5) +#define GAHBCFG_HBSTLEN_MASK 0x0000001e +#define GAHBCFG_HBSTLEN_SHIFT 1 +#define GAHBCFG_GLBLINTRMSK (1<<0) + +#define GUSBCFG_CORRUPTTXPACKET (1<<31) +#define GUSBCFG_FORCEDEVMODE (1<<30) +#define GUSBCFG_FORCEHOSTMODE (1<<29) +#define GUSBCFG_TERMSELDLPULSE (1<<22) +#define GUSBCFG_ULPIEXTVBUSINDICATOR (1<<21) +#define GUSBCFG_ULPIEXTVBUSDRV (1<<20) +#define GUSBCFG_ULPICLKSUSM (1<<19) +#define GUSBCFG_ULPIAUTORES (1<<18) +#define GUSBCFG_ULPIFSLS (1<<17) +#define GUSBCFG_OTGI2CSEL (1<<16) +#define GUSBCFG_PHYLPWRCLKSEL (1<<15) +#define GUSBCFG_USBTRDTIM_MASK 0x00003c00 +#define GUSBCFG_USBTRDTIM_SHIFT 10 +#define GUSBCFG_HNPCAP (1<<9) +#define GUSBCFG_SRPCAP (1<<8) +#define GUSBCFG_DDRSEL (1<<7) +#define GUSBCFG_PHYSEL (1<<6) +#define GUSBCFG_FSINTF (1<<5) +#define GUSBCFG_ULPI_UTMI_SEL (1<<4) +#define GUSBCFG_PHYIF (1<<3) +#define GUSBCFG_TOUTCAL_MASK 0x00000007 +#define GUSBCFG_TOUTCAL_SHIFT 0 + +#define GRSTCTL_AHBIDLE (1<<31) +#define GRSTCTL_DMAREQ (1<<30) +#define GRSTCTL_TXFNUM_MASK 0x000007c0 +#define GRSTCTL_TXFNUM_SHIFT 6 +#define GRSTCTL_TXFFLSH (1<<5) +#define GRSTCTL_RXFFLSH (1<<4) +#define GRSTCTL_INTKNQFLSH (1<<3) +#define GRSTCTL_FRMCNTRRST (1<<2) +#define GRSTCTL_HSFTRST (1<<1) +#define GRSTCTL_CSFTRST (1<<0) + +#define GINTSTS_WKUPINT (1<<31) +#define GINTSTS_SESSREQINT (1<<30) +#define GINTSTS_DISCONNINT (1<<29) +#define GINTSTS_CONIDSTSCHNG (1<<28) +#define GINTSTS_PTXFEMP (1<<26) +#define GINTSTS_HCHINT (1<<25) +#define GINTSTS_PRTINT (1<<24) +#define GINTSTS_FETSUSP (1<<22) +#define GINTSTS_INCOMPLP (1<<21) +#define GINTSTS_INCOMPISOIN (1<<20) +#define GINTSTS_OEPINT (1<<19) +#define GINTSTS_IEPINT (1<<18) +#define GINTSTS_EPMIS (1<<17) +#define GINTSTS_EOPF (1<<15) +#define GINTSTS_ISOOUTDROP (1<<14) +#define GINTSTS_ENUMDONE (1<<13) +#define GINTSTS_USBRST (1<<12) +#define GINTSTS_USBSUSP (1<<11) +#define GINTSTS_ERLYSUSP (1<<10) +#define GINTSTS_I2CINT (1<<9) +#define GINTSTS_ULPICKINT (1<<8) +#define GINTSTS_GOUTNAKEFF (1<<7) +#define GINTSTS_GINNAKEFF (1<<6) +#define GINTSTS_NPTXFEMP (1<<5) +#define GINTSTS_RXFLVL (1<<4) +#define GINTSTS_SOF (1<<3) +#define GINTSTS_OTGINT (1<<2) +#define GINTSTS_MODEMIS (1<<1) +#define GINTSTS_CURMOD (1<<0) + +#define GINTMSK_WKUPINTMSK (1<<31) +#define GINTMSK_SESSREQINTMSK (1<<30) +#define GINTMSK_DISCONNINTMSK (1<<29) +#define GINTMSK_CONIDSTSCHNGMSK (1<<28) +#define GINTMSK_PTXFEMPMSK (1<<26) +#define GINTMSK_HCHINTMSK (1<<25) +#define GINTMSK_PRTINTMSK (1<<24) +#define GINTMSK_FETSUSPMSK (1<<22) +#define GINTMSK_INCOMPLPMSK (1<<21) +#define GINTMSK_INCOMPISOINMSK (1<<20) +#define GINTMSK_OEPINTMSK (1<<19) +#define GINTMSK_IEPINTMSK (1<<18) +#define GINTMSK_EPMISMSK (1<<17) +#define GINTMSK_EOPFMSK (1<<15) +#define GINTMSK_ISOOUTDROPMSK (1<<14) +#define GINTMSK_ENUMDONEMSK (1<<13) +#define GINTMSK_USBRSTMSK (1<<12) +#define GINTMSK_USBSUSPMSK (1<<11) +#define GINTMSK_ERLYSUSPMSK (1<<10) +#define GINTMSK_I2CINTMSK (1<<9) +#define GINTMSK_ULPICKINTMSK (1<<8) +#define GINTMSK_GOUTNAKEFFMSK (1<<7) +#define GINTMSK_GINNAKEFFMSK (1<<6) +#define GINTMSK_NPTXFEMPMSK (1<<5) +#define GINTMSK_RXFLVLMSK (1<<4) +#define GINTMSK_SOFMSK (1<<3) +#define GINTMSK_OTGINTMSK (1<<2) +#define GINTMSK_MODEMISMSK (1<<1) +#define GINTMSK_CURMODMSK (1<<0) + +#define GRXSTSRH_PKTSTS_MASK 0x001e0000 +#define GRXSTSRH_PKTSTS_SHIFT 17 +#define GRXSTSRH_DPID_MASK 0x00018000 +#define GRXSTSRH_DPID_SHIFT 15 +#define GRXSTSRH_BCNT_MASK 0x00007ff0 +#define GRXSTSRH_BCNT_SHIFT 4 +#define GRXSTSRH_CHNUM_MASK 0x0000000f +#define GRXSTSRH_CHNUM_SHIFT 0 + +#define GRXSTSRD_FN_MASK 0x01e00000 +#define GRXSTSRD_FN_SHIFT 21 +#define GRXSTSRD_PKTSTS_MASK 0x001e0000 +#define GRXSTSRD_PKTSTS_SHIFT 17 +#define GRXSTSRD_DPID_MASK 0x00018000 +#define GRXSTSRD_DPID_SHIFT 15 +#define GRXSTSRD_BCNT_MASK 0x00007ff0 +#define GRXSTSRD_BCNT_SHIFT 4 +#define GRXSTSRD_CHNUM_MASK 0x0000000f +#define GRXSTSRD_CHNUM_SHIFT 0 + +#define GRXFSIZ_RXFDEP_MASK 0x0000ffff +#define GRXFSIZ_RXFDEP_SHIFT 0 + +#define GNPTXFSIZ_NPTXFDEP_MASK 0xffff0000 +#define GNPTXFSIZ_NPTXFDEP_SHIFT 0 +#define GNPTXFSIZ_NPTXFSTADDR_MASK 0x0000ffff +#define GNPTXFSIZ_NPTXFSTADDR_SHIFT 16 + +#define GNPTXSTS_NPTXQTOP_SHIFT 24 +#define GNPTXSTS_NPTXQTOP_MASK 0x7f000000 +#define GNPTXSTS_NPTXQSPCAVAIL_SHIFT 16 +#define GNPTXSTS_NPTXQSPCAVAIL_MASK 0x00ff0000 +#define GNPTXSTS_NPTXFSPCAVAIL_SHIFT 0 +#define GNPTXSTS_NPTXFSPCAVAIL_MASK 0x0000ffff + +#define GI2CCTL_BSYDNE_SC (1<<31) +#define GI2CCTL_RW (1<<30) +#define GI2CCTL_I2CDATSE0 (1<<28) +#define GI2CCTL_I2CDEVADR_SHIFT 26 +#define GI2CCTL_I2CDEVADR_MASK 0x0c000000 +#define GI2CCTL_I2CSUSPCTL (1<<25) +#define GI2CCTL_ACK (1<<24) +#define GI2CCTL_I2CEN (1<<23) +#define GI2CCTL_ADDR_SHIFT 16 +#define GI2CCTL_ADDR_MASK 0x007f0000 +#define GI2CCTL_REGADDR_SHIFT 8 +#define GI2CCTL_REGADDR_MASK 0x0000ff00 +#define GI2CCTL_RWDATA_SHIFT 0 +#define GI2CCTL_RWDATA_MASK 0x000000ff + +#define GPVNDCTL_DISULPIDRVR (1<<31) +#define GPVNDCTL_VSTSDONE (1<<27) +#define GPVNDCTL_VSTSBSY (1<<26) +#define GPVNDCTL_NEWREGREQ (1<<25) +#define GPVNDCTL_REGWR (1<<22) +#define GPVNDCTL_REGADDR_SHIFT 16 +#define GPVNDCTL_REGADDR_MASK 0x003f0000 +#define GPVNDCTL_VCTRL_SHIFT 8 +#define GPVNDCTL_VCTRL_MASK 0x0000ff00 +#define GPVNDCTL_REGDATA_SHIFT 0 +#define GPVNDCTL_REGDATA_MASK 0x000000ff + +#define GGPIO_GPO_SHIFT 16 +#define GGPIO_GPO_MASK 0xffff0000 +#define GGPIO_GPI_SHIFT 0 +#define GGPIO_GPI_MASK 0x0000ffff + +#define GHWCFG2_TKNQDEPTH_SHIFT 26 +#define GHWCFG2_TKNQDEPTH_MASK 0x7c000000 +#define GHWCFG2_PTXQDEPTH_SHIFT 24 +#define GHWCFG2_PTXQDEPTH_MASK 0x03000000 +#define GHWCFG2_NPTXQDEPTH_SHIFT 22 +#define GHWCFG2_NPTXQDEPTH_MASK 0x00c00000 +#define GHWCFG2_DYNFIFOSIZING (1<<19) +#define GHWCFG2_PERIOSUPPORT (1<<18) +#define GHWCFG2_NUMHSTCHNL_SHIFT 14 +#define GHWCFG2_NUMHSTCHNL_MASK 0x0003c000 +#define GHWCFG2_NUMDEVEPS_SHIFT 10 +#define GHWCFG2_NUMDEVEPS_MASK 0x00003c00 +#define GHWCFG2_FSPHYTYPE_SHIFT 8 +#define GHWCFG2_FSPHYTYPE_MASK 0x00000300 +#define GHWCFG2_HSPHYTYPE_SHIFT 6 +#define GHWCFG2_HSPHYTYPE_MASK 0x000000c0 +#define GHWCFG2_SINGPNT (1<<5) +#define GHWCFG2_OTGARCH_SHIFT 3 +#define GHWCFG2_OTGARCH_MASK 0x00000018 +#define GHWCFG2_OTGMODE_SHIFT 0 +#define GHWCFG2_OTGMODE_MASK 0x00000007 + +#define GHWCFG3_DFIFODEPTH_SHIFT 16 +#define GHWCFG3_DFIFODEPTH_MASK 0xffff0000 +#define GHWCFG3_RSTTYPE (1<<11) +#define GHWCFG3_OPTFEATURE (1<<10) +#define GHWCFG3_VNDCTLSUPT (1<<9) +#define GHWCFG3_I2CINTSEL (1<<8) +#define GHWCFG3_OTGEN (1<<7) +#define GHWCFG3_PKTSIZEWIDTH_SHIFT 4 +#define GHWCFG3_PKTSIZEWIDTH_MASK 0x00000070 +#define GHWCFG3_XFERSIZEWIDTH_SHIFT 0 +#define GHWCFG3_XFERSIZEWIDTH_MASK 0x0000000f + +#define GHWCFG4_SESSENDFLTR (1<<24) +#define GHWCFG4_BVALIDFLTR (1<<23) +#define GHWCFG4_AVALIDFLTR (1<<22) +#define GHWCFG4_VBUSVALIDFLTR (1<<21) +#define GHWCFG4_IDDGFLTR (1<<20) +#define GHWCFG4_NUMCTLEPS_SHIFT 16 +#define GHWCFG4_NUMCTLEPS_MASK 0x000f0000 +#define GHWCFG4_PHYDATAWIDTH_SHIFT 14 +#define GHWCFG4_PHYDATAWIDTH_MASK 0x0000c000 +#define GHWCFG4_AHBFREQ (1<<5) +#define GHWCFG4_ENABLEPWROPT (1<<4) +#define GHWCFG4_NUMDEVPERIOEPS_SHIFT 0 +#define GHWCFG4_NUMDEVPERIOEPS_MASK 0x0000000f + +#define HPTXFSIZ_PTXFSIZE_SHIFT 16 +#define HPTXFSIZ_PTXFSIZE_MASK 0xffff0000 +#define HPTXFSIZ_PTXFSTADDR_SHIFT 0 +#define HPTXFSIZ_PTXFSTADDR_MASK 0x0000ffff + +#define DPTXFSIZN_DPTXFSIZE_SHIFT 16 +#define DPTXFSIZN_DPTXFSIZE_MASK 0xffff0000 +#define DPTXFSIZN_PTXFSTADDR_SHIFT 0 +#define DPTXFSIZN_PTXFSTADDR_MASK 0x0000ffff + +#define DIEPTXFN_INEPNTXFDEP_SHIFT 16 +#define DIEPTXFN_INEPNTXFDEP_MASK 0xffff0000 +#define DIEPTXFN_INEPNTXFSTADDR_SHIFT 0 +#define DIEPTXFN_INEPNTXFSTADDR_MASK 0x0000ffff + +#define HCFG_FSLSSUPP (1<<2) +#define HCFG_FSLSPCLKSEL_SHIFT 0 +#define HCFG_FSLSPCLKSEL_MASK 0x00000003 + +#define HFIR_FRINT_SHIFT 0 +#define HFIR_FRINT_MASK 0x0000ffff + +#define HFNUM_FRREM_SHIFT 16 +#define HFNUM_FRREM_MASK 0xffff0000 +#define HFNUM_FRNUM_SHIFT 0 +#define HFNUM_FRNUM_MASK 0x0000ffff + +#define HPTXSTS_PTXQTOP_SHIFT 24 +#define HPTXSTS_PTXQTOP_MASK 0xff000000 +#define HPTXSTS_PTXQSPCAVAIL_SHIFT 16 +#define HPTXSTS_PTXQSPCAVAIL_MASK 0x00ff0000 +#define HPTXSTS_PTXFSPCAVAIL_SHIFT 0 +#define HPTXSTS_PTXFSPCAVAIL_MASK 0x0000ffff + +#define HAINT_HAINT_SHIFT 0 +#define HAINT_HAINT_MASK 0x0000ffff +#define HAINTMSK_HAINTMSK_SHIFT 0 +#define HAINTMSK_HAINTMSK_MASK 0x0000ffff + +#define HPRT_PRTSPD_SHIFT 17 +#define HPRT_PRTSPD_MASK 0x00060000 +#define HPRT_PRTSPD_HIGH 0 +#define HPRT_PRTSPD_FULL 1 +#define HPRT_PRTSPD_LOW 2 +#define HPRT_PRTSPD_MASK 0x00060000 +#define HPRT_PRTTSTCTL_SHIFT 13 +#define HPRT_PRTTSTCTL_MASK 0x0001e000 +#define HPRT_PRTPWR (1<<12) +#define HPRT_PRTLNSTS_SHIFT 10 +#define HPRT_PRTLNSTS_MASK 0x00000c00 +#define HPRT_PRTRST (1<<8) +#define HPRT_PRTSUSP (1<<7) +#define HPRT_PRTRES (1<<6) +#define HPRT_PRTOVRCURRCHNG (1<<5) +#define HPRT_PRTOVRCURRACT (1<<4) +#define HPRT_PRTENCHNG (1<<3) +#define HPRT_PRTENA (1<<2) +#define HPRT_PRTCONNDET (1<<1) +#define HPRT_PRTCONNSTS (1<<0) + +#define HCCHAR_CHENA (1<<31) +#define HCCHAR_CHDIS (1<<30) +#define HCCHAR_ODDFRM (1<<29) +#define HCCHAR_DEVADDR_SHIFT 22 +#define HCCHAR_DEVADDR_MASK 0x1fc00000 +#define HCCHAR_MC_EC_SHIFT 20 +#define HCCHAR_MC_EC_MASK 0x00300000 +#define HCCHAR_EC_SHIFT 20 +#define HCCHAR_EC_MASK 0x00300000 +#define HCCHAR_EPTYPE_SHIFT 18 +#define HCCHAR_EPTYPE_MASK 0x000c0000 +#define HCCHAR_LSPDDEV (1<<17) +#define HCCHAR_EPDIR (1<<15) +#define HCCHAR_EPDIR_IN (1<<15) +#define HCCHAR_EPDIR_OUT 0 +#define HCCHAR_EPNUM_SHIFT 11 +#define HCCHAR_EPNUM_MASK 0x00007800 +#define HCCHAR_MPS_SHIFT 0 +#define HCCHAR_MPS_MASK 0x000007ff + +#define HCSPLT_SPLTENA (1<<31) +#define HCSPLT_COMPSPLT (1<<16) +#define HCSPLT_XACTPOS_SHIFT 14 +#define HCSPLT_XACTPOS_MASK 0x0000c000 +#define HCSPLT_HUBADDR_SHIFT 7 +#define HCSPLT_HUBADDR_MASK 0x00003f80 +#define HCSPLT_PRTADDR_SHIFT 0 +#define HCSPLT_PRTADDR_MASK 0x0000007f + +#define HCINT_DATATGLERR (1<<10) +#define HCINT_FRMOVRUN (1<<9) +#define HCINT_BBLERR (1<<8) +#define HCINT_XACTERR (1<<7) +#define HCINT_NYET (1<<6) +#define HCINT_ACK (1<<5) +#define HCINT_NAK (1<<4) +#define HCINT_STALL (1<<3) +#define HCINT_AHBERR (1<<2) +#define HCINT_CHHLTD (1<<1) +#define HCINT_XFERCOMPL (1<<0) + +#define HCINTMSK_DATATGLERRMSK (1<<10) +#define HCINTMSK_FRMOVRUNMSK (1<<9) +#define HCINTMSK_BBLERRMSK (1<<8) +#define HCINTMSK_XACTERRMSK (1<<7) +#define HCINTMSK_NYETMSK (1<<6) +#define HCINTMSK_ACKMSK (1<<5) +#define HCINTMSK_NAKMSK (1<<4) +#define HCINTMSK_STALLMSK (1<<3) +#define HCINTMSK_AHBERRMSK (1<<2) +#define HCINTMSK_CHHLTDMSK (1<<1) +#define HCINTMSK_XFERCOMPLMSK (1<<0) + +#define HCTSIZ_DOPNG (1<<31) +#define HCTSIZ_PID_SHIFT 29 +#define HCTSIZ_PID_MASK 0x60000000 +#define HCTSIZ_PID_DATA0 0 +#define HCTSIZ_PID_DATA2 1 +#define HCTSIZ_PID_DATA1 2 +#define HCTSIZ_PID_MDATA 3 +#define HCTSIZ_PID_SETUP 3 +#define HCTSIZ_PKTCNT_SHIFT 19 +#define HCTSIZ_PKTCNT_MASK 0x1ff80000 +#define HCTSIZ_XFERSIZE_SHIFT 0 +#define HCTSIZ_XFERSIZE_MASK 0x0007ffff + +#define DCFG_EPMISCNT_SHIFT 18 +#define DCFG_EPMISCNT_MASK 0x007c0000 +#define DCFG_PERFRINT_SHIFT 11 +#define DCFG_PERFRINT_MASK 0x00001800 +#define DCFG_DEVADDR_SHIFT 4 +#define DCFG_DEVADDR_MASK 0x000007f0 +#define DCFG_NZSTSOUTHSHK (1<<2) +#define DCFG_DEVSPD_SHIFT 0 +#define DCFG_DEVSPD_MASK 0x00000003 + +#define DCTL_PWRONPRGDONE (1<<11) +#define DCTL_CGOUTNAK (1<<10) +#define DCTL_SGOUTNAK (1<<9) +#define DCTL_CGNPINNAK (1<<8) +#define DCTL_SGNPINNAK (1<<7) +#define DCTL_TSTCTL_SHIFT 4 +#define DCTL_TSTCTL_MASK 0x00000070 +#define DCTL_GOUTNAKSTS (1<<3) +#define DCTL_GNPINNAKSTS (1<<2) +#define DCTL_SFTDISCON (1<<1) +#define DCTL_RMTWKUPSIG (1<<0) + +#define DSTS_SOFFN_SHIFT 8 +#define DSTS_SOFFN_MASK 0x003fff00 +#define DSTS_ERRTICERR (1<<3) +#define DSTS_ENUMSPD_SHIFT 1 +#define DSTS_ENUMSPD_MASK 0x00000006 +#define DSTS_SUSPSTS (1<<0) + +#define DIEPMSK_TXFIFOUNDRNMSK (1<<8) +#define DIEPMSK_INEPNAKEFFMSK (1<<6) +#define DIEPMSK_INTKNEPMISMSK (1<<5) +#define DIEPMSK_INTKNTXFEMPMSK (1<<4) +#define DIEPMSK_TIMEOUTMSK (1<<3) +#define DIEPMSK_AHBERRMSK (1<<2) +#define DIEPMSK_EPDISBLDMSK (1<<1) +#define DIEPMSK_XFERCOMPLMSK (1<<0) + +#define DOEPMSK_OUTPKTERRMSK (1<<8) +#define DOEPMSK_BACK2BACKSETUP (1<<6) +#define DOEPMSK_OUTTKNEPDISMSK (1<<4) +#define DOEPMSK_SETUPMSK (1<<3) +#define DOEPMSK_AHBERRMSK (1<<2) +#define DOEPMSK_EPDISBLDMSK (1<<1) +#define DOEPMSK_XFERCOMPLMSK (1<<0) + +#define DIEPINT_TXFIFOUNDRN (1<<8) +#define DIEPINT_INEPNAKEFF (1<<6) +#define DIEPINT_INTKNEPMIS (1<<5) +#define DIEPINT_INTKNTXFEMP (1<<4) +#define DIEPINT_TIMEOUT (1<<3) +#define DIEPINT_AHBERR (1<<2) +#define DIEPINT_EPDISBLD (1<<1) +#define DIEPINT_XFERCOMPL (1<<0) + +#define DOEPINT_OUTPKTERR (1<<8) +#define DOEPINT_BACK2BACKSETUP (1<<6) +#define DOEPINT_OUTTKNEPDIS (1<<4) +#define DOEPINT_SETUP (1<<3) +#define DOEPINT_AHBERR (1<<2) +#define DOEPINT_EPDISBLD (1<<1) +#define DOEPINT_XFERCOMPL (1<<0) + +#define DAINT_INEPINT_MASK 0xffff0000 +#define DAINT_INEPINT_SHIFT 0 +#define DAINT_OUTEPINT_MASK 0x0000ffff +#define DAINT_OUTEPINT_SHIFT 16 + +#define DAINTMSK_INEPINT_MASK 0xffff0000 +#define DAINTMSK_INEPINT_SHIFT 0 +#define DAINTMSK_OUTEPINT_MASK 0x0000ffff +#define DAINTMSK_OUTEPINT_SHIFT 16 + +#define DTKNQR1_EPTKN_SHIFT 8 +#define DTKNQR1_EPTKN_MASK 0xffffff00 +#define DTKNQR1_WRAPBIT (1<<7) +#define DTKNQR1_INTKNWPTR_SHIFT 0 +#define DTKNQR1_INTKNWPTR_MASK 0x0000001f + +#define DVBUSDIS_DVBUSDIS_SHIFT 0 +#define DVBUSDIS_DVBUSDIS_MASK 0x0000ffff + +#define DVBUSPULSE_DVBUSPULSE_SHIFT 0 +#define DVBUSPULSE_DVBUSPULSE_MASK 0x00000fff + +#define DTHRCTL_ARBPRKEN (1<<27) +#define DTHRCTL_RXTHRLEN_SHIFT 17 +#define DTHRCTL_RXTHRLEN_MASK 0x03fe0000 +#define DTHRCTL_RXTHREN (1<<16) +#define DTHRCTL_TXTHRLEN_SHIFT 2 +#define DTHRCTL_TXTHRLEN_MASK 0x000007fc +#define DTHRCTL_ISOTHREN (1<<1) +#define DTHRCTL_NONISOTHREN (1<<0) + +#define DIEPEMPMSK_INEPTXFEMPMSK_SHIFT 0 +#define DIEPEMPMSK_INEPTXFEMPMSK_MASK 0x0000ffff + +#define DIEPCTL_EPENA (1<<31) +#define DIEPCTL_EPDIS (1<<30) +#define DIEPCTL_SETD1PID (1<<29) +#define DIEPCTL_SETD0PID (1<<28) +#define DIEPCTL_SNAK (1<<27) +#define DIEPCTL_CNAK (1<<26) +#define DIEPCTL_TXFNUM_SHIFT 22 +#define DIEPCTL_TXFNUM_MASK 0x03c00000 +#define DIEPCTL_STALL (1<<21) +#define DIEPCTL_EPTYPE_SHIFT 18 +#define DIEPCTL_EPTYPE_MASK 0x000c0000 +#define DIEPCTL_NAKSTS (1<<17) +#define DIEPCTL_USBACTEP (1<<15) +#define DIEPCTL_NEXTEP_SHIFT 11 +#define DIEPCTL_NEXTEP_MASK 0x00007800 +#define DIEPCTL_MPS_SHIFT 0 +#define DIEPCTL_MPS_MASK 0x000007ff + +#define DOEPCTL_EPENA (1<<31) +#define DOEPCTL_EPDIS (1<<30) +#define DOEPCTL_SETD1PID (1<<29) +#define DOEPCTL_SETD0PID (1<<28) +#define DOEPCTL_SNAK (1<<27) +#define DOEPCTL_CNAK (1<<26) +#define DOEPCTL_STALL (1<<21) +#define DOEPCTL_EPTYPE_SHIFT 18 +#define DOEPCTL_EPTYPE_MASK 0x000c0000 +#define DOEPCTL_NAKSTS (1<<17) +#define DOEPCTL_USBACTEP (1<<15) +#define DOEPCTL_MPS_SHIFT 0 +#define DOEPCTL_MPS_MASK 0x000007ff + +#define DIEPTSIZ_XFERSIZE_MASK 0x0007ffff +#define DIEPTSIZ_XFERSIZE_SHIFT 0 +#define DIEPTSIZ_PKTCNT_MASK 0x1ff80000 +#define DIEPTSIZ_PKTCNT_SHIFT 19 +#define DIEPTSIZ_MC_MASK 0x60000000 +#define DIEPTSIZ_MC_SHIFT 29 + +#define DOEPTSIZ_XFERSIZE_MASK 0x0007ffff +#define DOEPTSIZ_XFERSIZE_SHIFT 0 +#define DOEPTSIZ_PKTCNT_MASK 0x1ff80000 +#define DOEPTSIZ_PKTCNT_SHIFT 19 +#define DOEPTSIZ_MC_MASK 0x60000000 +#define DOEPTSIZ_MC_SHIFT 29 + +#endif /* __DOTG_REG_H__ */ + diff --git a/sys/dev/usb/controller/usb_controller.c b/sys/dev/usb/controller/usb_controller.c index 9387ec8..531336c 100644 --- a/sys/dev/usb/controller/usb_controller.c +++ b/sys/dev/usb/controller/usb_controller.c @@ -122,6 +122,7 @@ DRIVER_MODULE(usbus, ohci, usb_driver, usb_devclass, 0, 0); DRIVER_MODULE(usbus, uhci, usb_driver, usb_devclass, 0, 0); DRIVER_MODULE(usbus, ehci, usb_driver, usb_devclass, 0, 0); DRIVER_MODULE(usbus, xhci, usb_driver, usb_devclass, 0, 0); +DRIVER_MODULE(usbus, dotg, usb_driver, usb_devclass, 0, 0); /* Device Only Drivers */ DRIVER_MODULE(usbus, at91_udp, usb_driver, usb_devclass, 0, 0);