On Sun, 21 Sep 2014, Marek Vasut wrote:

> From: Oleksandr Tymoshenko <go...@bluezbox.com>
> 
> This is the USB host controller used on the Altera SoCFPGA and Raspbery Pi.
> 
> This code has three checkpatch warnings, but to make sure it stays at least
> readable and clear, these are not fixed. These bugs are in the USB request
> handling combinatorial logic, so any abstracting of those is out of question.
> 
> Tested on DENX MCV (Altera SoCFPGA 5CSFXC6C6U23C8N) and RPi B+ (BCM2835).
> 
> Signed-off-by: Oleksandr Tymoshenko <go...@bluezbox.com>
> Signed-off-by: Stephen Warren <swar...@wwwdotorg.org>
> Signed-off-by: Marek Vasut <ma...@denx.de>
> Cc: Chin Liang See <cl...@altera.com>
> Cc: Dinh Nguyen <dingu...@altera.com>
> Cc: Albert Aribaud <albert.u.b...@aribaud.net>
> Cc: Tom Rini <tr...@ti.com>
> Cc: Wolfgang Denk <w...@denx.de>
> Cc: Pavel Machek <pa...@denx.de>
> ---
>  README                    |   3 +
>  drivers/usb/host/Makefile |   3 +
>  drivers/usb/host/dwc2.c   | 952 
> ++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/host/dwc2.h   | 784 ++++++++++++++++++++++++++++++++++++++
>  include/usb.h             |   3 +-
>  5 files changed, 1744 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/usb/host/dwc2.c
>  create mode 100644 drivers/usb/host/dwc2.h
> 
> diff --git a/README b/README
> index 0a0f528..ba23b32 100644
> --- a/README
> +++ b/README
> @@ -1453,6 +1453,9 @@ The following options need to be configured:
>               CONFIG_USB_EHCI_TXFIFO_THRESH enables setting of the
>               txfilltuning field in the EHCI controller on reset.
>  
> +             CONFIG_USB_DWC2_REG_ADDR the physical CPU address of the DWC2
> +             HW module registers
> +
>  - USB Device:
>               Define the below if you wish to use the USB console.
>               Once firmware is rebuilt from a serial console issue the
> diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
> index c4f5157..c9d2ed5 100644
> --- a/drivers/usb/host/Makefile
> +++ b/drivers/usb/host/Makefile
> @@ -45,3 +45,6 @@ obj-$(CONFIG_USB_EHCI_ZYNQ) += ehci-zynq.o
>  obj-$(CONFIG_USB_XHCI) += xhci.o xhci-mem.o xhci-ring.o
>  obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o
>  obj-$(CONFIG_USB_XHCI_OMAP) += xhci-omap.o
> +
> +# designware
> +obj-$(CONFIG_USB_DWC2) += dwc2.o
> diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c
> new file mode 100644
> index 0000000..aede53b
> --- /dev/null
> +++ b/drivers/usb/host/dwc2.c
> @@ -0,0 +1,952 @@
> +/*
> + * Copyright (C) 2012 Oleksandr Tymoshenko <go...@freebsd.org>
> + * Copyright (C) 2014 Marek Vasut <ma...@denx.de>
> + *
> + * SPDX-License-Identifier:     GPL-2.0
> + */
> +
> +#include <common.h>
> +#include <errno.h>
> +#include <usb.h>
> +#include <malloc.h>
> +#include <usbroothubdes.h>
> +#include <asm/io.h>
> +
> +#include "dwc2.h"
> +
> +static int wait_for_bit(void *reg, const uint32_t mask, bool set)
> +{
> +     unsigned int timeout = 1000000;
> +     uint32_t val;
> +
> +     while (--timeout) {
> +             val = readl(reg);
> +             if (!set)
> +                     val = ~val;
> +
> +             if ((val & mask) == mask)
> +                     return 0;
> +
> +             udelay(1);
> +     }
> +
> +     printf("%s: Timeout (reg=%p mask=%08x wait_set=%i)\n",
> +            __func__, reg, mask, set);

This debug print doesn't really tell us much. We've timed out, but we have
no idea from where?
> +
> +     return -ETIMEDOUT;

You're returning -ETIMEDOUT, but none of the users of wait_for_bit make any
use of this. Perhaps, a printf from the caller function would tell us more?

> +}
> +
> +/**
> + * Initializes the FSLSPClkSel field of the HCFG register
> + * depending on the PHY type.
> + */
> +static void init_fslspclksel(struct dwc2_core_regs *regs)
> +{
> +     uint32_t phyclk;
> +#ifdef CONFIG_DWC2_ULPI_FS_LS
> +     uint32_t hwcfg2 = readl(&regs->ghwcfg2);
> +     uint32_t hval = (ghwcfg2 & DWC2_HWCFG2_HS_PHY_TYPE_MASK) >>
> +                     DWC2_HWCFG2_HS_PHY_TYPE_OFFSET;
> +     uint32_t fval = (ghwcfg2 & DWC2_HWCFG2_FS_PHY_TYPE_MASK) >>
> +                     DWC2_HWCFG2_FS_PHY_TYPE_OFFSET;
> +
> +     if ((hval == 2) && (fval == 1))
> +             phyclk = DWC2_HCFG_FSLSPCLKSEL_48_MHZ;  /* Full speed PHY */
> +     else
> +#endif
> +
> +#if (CONFIG_DWC2_PHY_TYPE == DWC2_PHY_TYPE_FS)
> +     phyclk = DWC2_HCFG_FSLSPCLKSEL_48_MHZ;  /* Full speed PHY */
> +#else
> +     /* High speed PHY running at full speed or high speed */
> +     phyclk = DWC2_HCFG_FSLSPCLKSEL_30_60_MHZ;
> +#endif
> +
> +     clrsetbits_le32(&regs->host_regs.hcfg,
> +                     DWC2_HCFG_FSLSPCLKSEL_MASK,
> +                     phyclk << DWC2_HCFG_FSLSPCLKSEL_OFFSET);
> +}
> +
> +/**
> + * Flush a Tx FIFO.
> + *
> + * @param regs Programming view of DWC_otg controller.
> + * @param num Tx FIFO to flush.
> + */
> +static void dwc_otg_flush_tx_fifo(struct dwc2_core_regs *regs, const int num)
> +{
> +     writel(DWC2_GRSTCTL_TXFFLSH | (num << DWC2_GRSTCTL_TXFNUM_OFFSET),
> +            &regs->grstctl);
> +     wait_for_bit(&regs->grstctl, DWC2_GRSTCTL_TXFFLSH, 0);
> +
> +     /* Wait for 3 PHY Clocks */
> +     udelay(1);
> +}
> +
> +/**
> + * Flush Rx FIFO.
> + *
> + * @param regs Programming view of DWC_otg controller.
> + */
> +static void dwc_otg_flush_rx_fifo(struct dwc2_core_regs *regs)
> +{
> +     writel(DWC2_GRSTCTL_RXFFLSH, &regs->grstctl);
> +     wait_for_bit(&regs->grstctl, DWC2_GRSTCTL_RXFFLSH, 0);
> +
> +     /* Wait for 3 PHY Clocks */
> +     udelay(1);
> +}
> +
> +/**
> + * Do core a soft reset of the core.  Be careful with this because it
> + * resets all the internal state machines of the core.
> + */
> +static void dwc_otg_core_reset(struct dwc2_core_regs *regs)
> +{
> +     /* Wait for AHB master IDLE state. */
> +     wait_for_bit(&regs->grstctl, DWC2_GRSTCTL_AHBIDLE, 1);
> +
> +     /* Core Soft Reset */
> +     writel(DWC2_GRSTCTL_CSFTRST, &regs->grstctl);
> +     wait_for_bit(&regs->grstctl, DWC2_GRSTCTL_CSFTRST, 0);
> +
> +     /* Wait for 3 PHY Clocks */

This comment is probably not true since "3 PHY clocks" was 1 uS in
dwc_otg_flush_tx_fifo() and dwc_otg_flush_rx_fifo(), and here it's
100ms. The Linux version for this driver has a 150ms - 200ms range. So
150ms here should be good. The comment from the linux driver is:

"NOTE: This long sleep is _very_ important, otherwise the core will
 not stay in host mode after a connector ID change!"

> +     mdelay(100);
> +}
> +
> +
> +/**
> + * This function initializes the DWC_otg controller registers for
> + * host mode.
> + *
> + * This function flushes the Tx and Rx FIFOs and it flushes any entries in 
> the
> + * request queues. Host channels are reset to ensure that they are ready for
> + * performing transfers.
> + *
> + * @param regs Programming view of DWC_otg controller
> + *
> + */
> +static void dwc_otg_core_host_init(struct dwc2_core_regs *regs)
> +{
> +     uint32_t nptxfifosize = 0;
> +     uint32_t ptxfifosize = 0;
> +     uint32_t hprt0 = 0;
> +     int i, num_channels;
> +
> +     /* Restart the Phy Clock */
> +     writel(0, &regs->pcgcctl);
> +
> +     /* Initialize Host Configuration Register */
> +     init_fslspclksel(regs);
> +#ifdef CONFIG_DWC2_DFLT_SPEED_FULL
> +     setbits_le32(&regs->host_regs.hcfg, DWC2_HCFG_FSLSSUPP);
> +#endif
> +
> +     /* Configure data FIFO sizes */
> +#ifdef CONFIG_DWC2_ENABLE_DYNAMIC_FIFO
> +     if (readl(&regs->ghwcfg2) & DWC2_HWCFG2_DYNAMIC_FIFO) {
> +             /* Rx FIFO */
> +             writel(CONFIG_DWC2_HOST_RX_FIFO_SIZE, &regs->grxfsiz);
> +
> +             /* Non-periodic Tx FIFO */
> +             nptxfifosize |= CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE <<
> +                             DWC2_FIFOSIZE_DEPTH_OFFSET;
> +             nptxfifosize |= CONFIG_DWC2_HOST_RX_FIFO_SIZE <<
> +                             DWC2_FIFOSIZE_STARTADDR_OFFSET;
> +             writel(nptxfifosize, &regs->gnptxfsiz);
> +
> +             /* Periodic Tx FIFO */
> +             ptxfifosize |= CONFIG_DWC2_HOST_PERIO_TX_FIFO_SIZE <<
> +                             DWC2_FIFOSIZE_DEPTH_OFFSET;
> +             ptxfifosize |= (CONFIG_DWC2_HOST_RX_FIFO_SIZE +
> +                             CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE) <<
> +                             DWC2_FIFOSIZE_STARTADDR_OFFSET;
> +             writel(ptxfifosize, &regs->hptxfsiz);
> +     }
> +#endif
> +
> +     /* Clear Host Set HNP Enable in the OTG Control Register */
> +     clrbits_le32(&regs->gotgctl, DWC2_GOTGCTL_HSTSETHNPEN);
> +
> +     /* Make sure the FIFOs are flushed. */
> +     dwc_otg_flush_tx_fifo(regs, 0x10);      /* All Tx FIFOs */
> +     dwc_otg_flush_rx_fifo(regs);
> +
> +     /* Flush out any leftover queued requests. */
> +     num_channels = readl(&regs->ghwcfg2);
> +     num_channels &= DWC2_HWCFG2_NUM_HOST_CHAN_MASK;
> +     num_channels >>= DWC2_HWCFG2_NUM_HOST_CHAN_OFFSET;
> +     num_channels += 1;
> +
> +     for (i = 0; i < num_channels; i++)
> +             clrsetbits_le32(&regs->hc_regs[i].hcchar,
> +                             DWC2_HCCHAR_CHEN | DWC2_HCCHAR_EPDIR,
> +                             DWC2_HCCHAR_CHDIS);
> +
> +     /* Halt all channels to put them into a known state. */
> +     for (i = 0; i < num_channels; i++) {
> +             clrsetbits_le32(&regs->hc_regs[i].hcchar,
> +                             DWC2_HCCHAR_EPDIR,
> +                             DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS);
> +             wait_for_bit(&regs->hc_regs[i].hcchar, DWC2_HCCHAR_CHEN, 0);
> +     }
> +
> +     /* Turn on the vbus power. */
> +     if (readl(&regs->gintsts) & DWC2_GINTSTS_CURMODE_HOST) {
> +             hprt0 = readl(&regs->hprt0);
> +             hprt0 &= ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET);
> +             hprt0 &= ~(DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG);
> +             if (!(hprt0 & DWC2_HPRT0_PRTPWR)) {
> +                     hprt0 |= DWC2_HPRT0_PRTPWR;
> +                     writel(hprt0, &regs->hprt0);
> +             }
> +     }
> +}
> +
> +/**
> + * This function initializes the DWC_otg controller registers and
> + * prepares the core for device mode or host mode operation.
> + *
> + * @param regs Programming view of the DWC_otg controller
> + */
> +static void dwc_otg_core_init(struct dwc2_core_regs *regs)
> +{
> +     uint32_t ahbcfg = 0;
> +     uint32_t usbcfg = 0;
> +     uint8_t brst_sz = CONFIG_DWC2_DMA_BURST_SIZE;
> +
> +     /* Common Initialization */
> +     usbcfg = readl(&regs->gusbcfg);
> +
> +     /* Program the ULPI External VBUS bit if needed */
> +#ifdef CONFIG_DWC2_PHY_ULPI_EXT_VBUS
> +     usbcfg |= DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV;
> +#else
> +     usbcfg &= ~DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV;
> +#endif
> +
> +     /* Set external TS Dline pulsing */
> +#ifdef CONFIG_DWC2_TS_DLINE
> +     usbcfg |= DWC2_GUSBCFG_TERM_SEL_DL_PULSE;
> +#else
> +     usbcfg &= ~DWC2_GUSBCFG_TERM_SEL_DL_PULSE;
> +#endif
> +     writel(usbcfg, &regs->gusbcfg);
> +
> +     /* Reset the Controller */
> +     dwc_otg_core_reset(regs);
> +
> +     /*
> +      * This programming sequence needs to happen in FS mode before
> +      * any other programming occurs
> +      */
> +#if defined(CONFIG_DWC2_DFLT_SPEED_FULL) && \
> +     (CONFIG_DWC2_PHY_TYPE == DWC2_PHY_TYPE_FS)
> +     /* If FS mode with FS PHY */
> +     setbits_le32(&regs->gusbcfg, DWC2_GUSBCFG_PHYSEL);
> +
> +     /* Reset after a PHY select */
> +     dwc_otg_core_reset(regs);
> +
> +     /*
> +      * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS.
> +      * Also do this on HNP Dev/Host mode switches (done in dev_init
> +      * and host_init).
> +      */
> +     if (readl(&regs->gintsts) & DWC2_GINTSTS_CURMODE_HOST)
> +             init_fslspclksel(regs);
> +
> +#ifdef CONFIG_DWC2_I2C_ENABLE
> +     /* Program GUSBCFG.OtgUtmifsSel to I2C */
> +     setbits_le32(&regs->gusbcfg, DWC2_GUSBCFG_OTGUTMIFSSEL);
> +
> +     /* Program GI2CCTL.I2CEn */
> +     clrsetbits_le32(&regs->gi2cctl, DWC2_GI2CCTL_I2CEN |
> +                     DWC2_GI2CCTL_I2CDEVADDR_MASK,
> +                     1 << DWC2_GI2CCTL_I2CDEVADDR_OFFSET);
> +     setbits_le32(&regs->gi2cctl, DWC2_GI2CCTL_I2CEN);
> +#endif
> +
> +#else
> +     /* High speed PHY. */
> +
> +     /*
> +      * HS PHY parameters. These parameters are preserved during
> +      * soft reset so only program the first time. Do a soft reset
> +      * immediately after setting phyif.
> +      */
> +     usbcfg &= ~(DWC2_GUSBCFG_ULPI_UTMI_SEL | DWC2_GUSBCFG_PHYIF);
> +     usbcfg |= CONFIG_DWC2_PHY_TYPE << DWC2_GUSBCFG_ULPI_UTMI_SEL_OFFSET;
> +
> +     if (usbcfg & DWC2_GUSBCFG_ULPI_UTMI_SEL) {      /* ULPI interface */
> +#ifdef CONFIG_DWC2_PHY_ULPI_DDR
> +             usbcfg |= DWC2_GUSBCFG_DDRSEL;
> +#else
> +             usbcfg &= ~DWC2_GUSBCFG_DDRSEL;
> +#endif
> +     } else {        /* UTMI+ interface */
> +#if (CONFIG_DWC2_UTMI_PHY_WIDTH == 16)
> +             usbcfg |= DWC2_GUSBCFG_PHYIF;
> +#endif
> +     }
> +
> +     writel(usbcfg, &regs->gusbcfg);
> +
> +     /* Reset after setting the PHY parameters */
> +     dwc_otg_core_reset(regs);
> +#endif
> +
> +     usbcfg = readl(&regs->gusbcfg);
> +     usbcfg &= ~(DWC2_GUSBCFG_ULPI_FSLS | DWC2_GUSBCFG_ULPI_CLK_SUS_M);
> +#ifdef CONFIG_DWC2_ULPI_FS_LS
> +     uint32_t hwcfg2 = readl(&regs->ghwcfg2);
> +     uint32_t hval = (ghwcfg2 & DWC2_HWCFG2_HS_PHY_TYPE_MASK) >>
> +                     DWC2_HWCFG2_HS_PHY_TYPE_OFFSET;
> +     uint32_t fval = (ghwcfg2 & DWC2_HWCFG2_FS_PHY_TYPE_MASK) >>
> +                     DWC2_HWCFG2_FS_PHY_TYPE_OFFSET;
> +     if (hval == 2 && fval == 1) {
> +             usbcfg |= DWC2_GUSBCFG_ULPI_FSLS;
> +             usbcfg |= DWC2_GUSBCFG_ULPI_CLK_SUS_M;
> +     }
> +#endif
> +     writel(usbcfg, &regs->gusbcfg);
> +
> +     /* Program the GAHBCFG Register. */
> +     switch (readl(&regs->ghwcfg2) & DWC2_HWCFG2_ARCHITECTURE_MASK) {
> +     case DWC2_HWCFG2_ARCHITECTURE_SLAVE_ONLY:
> +             break;
> +     case DWC2_HWCFG2_ARCHITECTURE_EXT_DMA:
> +             while (brst_sz > 1) {
> +                     ahbcfg |= ahbcfg + (1 << DWC2_GAHBCFG_HBURSTLEN_OFFSET);
> +                     ahbcfg &= DWC2_GAHBCFG_HBURSTLEN_MASK;
> +                     brst_sz >>= 1;
> +             }
> +
> +#ifdef CONFIG_DWC2_DMA_ENABLE
> +             ahbcfg |= DWC2_GAHBCFG_DMAENABLE;
> +#endif
> +             break;
> +
> +     case DWC2_HWCFG2_ARCHITECTURE_INT_DMA:
> +             ahbcfg |= DWC2_GAHBCFG_HBURSTLEN_INCR4;
> +#ifdef CONFIG_DWC2_DMA_ENABLE
> +             ahbcfg |= DWC2_GAHBCFG_DMAENABLE;
> +#endif
> +             break;
> +     }
> +
> +     writel(ahbcfg, &regs->gahbcfg);
> +
> +     /* Program the GUSBCFG register for HNP/SRP. */
> +     setbits_le32(&regs->gusbcfg, DWC2_GUSBCFG_HNPCAP | DWC2_GUSBCFG_SRPCAP);
> +
> +#ifdef CONFIG_DWC2_IC_USB_CAP
> +     setbits_le32(&regs->gusbcfg, DWC2_GUSBCFG_IC_USB_CAP);
> +#endif
> +}
> +
> +/**
> + * Prepares a host channel for transferring packets to/from a specific
> + * endpoint. The HCCHARn register is set up with the characteristics 
> specified
> + * in _hc. Host channel interrupts that may need to be serviced while this
> + * transfer is in progress are enabled.
> + *
> + * @param regs Programming view of DWC_otg controller
> + * @param hc Information needed to initialize the host channel
> + */
> +static void dwc_otg_hc_init(struct dwc2_core_regs *regs, uint8_t hc_num,
> +             uint8_t dev_addr, uint8_t ep_num, uint8_t ep_is_in,
> +             uint8_t ep_type, uint16_t max_packet)
> +{
> +     struct dwc2_hc_regs *hc_regs = &regs->hc_regs[hc_num];
> +     const uint32_t hcchar = (dev_addr << DWC2_HCCHAR_DEVADDR_OFFSET) |
> +                             (ep_num << DWC2_HCCHAR_EPNUM_OFFSET) |
> +                             (ep_is_in << DWC2_HCCHAR_EPDIR_OFFSET) |
> +                             (ep_type << DWC2_HCCHAR_EPTYPE_OFFSET) |
> +                             (max_packet << DWC2_HCCHAR_MPS_OFFSET);
> +
> +     /* Clear old interrupt conditions for this host channel. */
> +     writel(0x3fff, &hc_regs->hcint);
> +
> +     /*
> +      * Program the HCCHARn register with the endpoint characteristics
> +      * for the current transfer.
> +      */
> +     writel(hcchar, &hc_regs->hcchar);
> +
> +     /* Program the HCSPLIT register for SPLITs */
> +     writel(0, &hc_regs->hcsplt);
> +}
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +#define STATUS_ACK_HLT_COMPL 0x23
> +#define CHANNEL 0
> +
> +#define DWC2_STATUS_BUF_SIZE 64
> +#define DWC2_DATA_BUF_SIZE   (64 * 1024)
> +
> +static int root_hub_devnum;
> +
> +/* We need doubleword-aligned buffers for DMA transfers */
> +DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer, DWC2_DATA_BUF_SIZE, 8);
> +DEFINE_ALIGN_BUFFER(uint8_t, status_buffer, DWC2_STATUS_BUF_SIZE, 8);
> +
> +#define MAX_DEVICE 16
> +#define MAX_ENDPOINT 16
> +static int bulk_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
> +static int control_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
> +
> +static struct dwc2_core_regs *regs =
> +     (struct dwc2_core_regs *)CONFIG_USB_DWC2_REG_ADDR;
> +
> +/*-------------------------------------------------------------------------*
> + * Virtual Root Hub
> + *-------------------------------------------------------------------------*/
> +
> +static int dwc_otg_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
> +                              void *buffer, int transfer_len,
> +                              struct devrequest *cmd)
> +{
> +     int leni = transfer_len;
> +     int len = 0;
> +     int stat = 0;
> +     __u16 bmRType_bReq;
> +     __u16 wValue;
> +     __u16 wLength;
> +     unsigned char data[32];
> +     uint32_t hprt0 = 0;
> +     uint32_t port_status = 0;
> +     uint32_t port_change = 0;
> +
> +     if (usb_pipeint(pipe)) {
> +             puts("Root-Hub submit IRQ: NOT implemented");
> +             return 0;
> +     }
> +
> +     bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
> +     wValue        = cpu_to_le16 (cmd->value);
> +     wLength       = cpu_to_le16 (cmd->length);
> +
> +     switch (bmRType_bReq) {
> +     case (USB_REQ_GET_STATUS << 8) | USB_DIR_IN:
> +             *(__u16 *)buffer = cpu_to_le16(1);
> +             len = 2;
> +             break;
> +     case (USB_REQ_GET_STATUS << 8) | USB_DIR_IN | USB_RECIP_INTERFACE:
> +             *(__u16 *)buffer = cpu_to_le16(0);
> +             len = 2;
> +             break;
> +     case (USB_REQ_GET_STATUS << 8) | USB_DIR_IN | USB_RECIP_ENDPOINT:
> +             *(__u16 *)buffer = cpu_to_le16(0);
> +             len = 2;
> +             break;
> +     case (USB_REQ_GET_STATUS << 8) | USB_DIR_IN | USB_TYPE_CLASS:
> +             *(__u32 *)buffer = cpu_to_le32(0);
> +             len = 4;
> +             break;
> +     case (USB_REQ_GET_STATUS << 8) | USB_DIR_IN | USB_RECIP_OTHER | 
> USB_TYPE_CLASS:
> +             hprt0 = readl(&regs->hprt0);
> +             if (hprt0 & DWC2_HPRT0_PRTCONNSTS)
> +                     port_status |= USB_PORT_STAT_CONNECTION;
> +             if (hprt0 & DWC2_HPRT0_PRTENA)
> +                     port_status |= USB_PORT_STAT_ENABLE;
> +             if (hprt0 & DWC2_HPRT0_PRTSUSP)
> +                     port_status |= USB_PORT_STAT_SUSPEND;
> +             if (hprt0 & DWC2_HPRT0_PRTOVRCURRACT)
> +                     port_status |= USB_PORT_STAT_OVERCURRENT;
> +             if (hprt0 & DWC2_HPRT0_PRTRST)
> +                     port_status |= USB_PORT_STAT_RESET;
> +             if (hprt0 & DWC2_HPRT0_PRTPWR)
> +                     port_status |= USB_PORT_STAT_POWER;
> +
> +             port_status |= USB_PORT_STAT_HIGH_SPEED;
> +
> +             if (hprt0 & DWC2_HPRT0_PRTENCHNG)
> +                     port_change |= USB_PORT_STAT_C_ENABLE;
> +             if (hprt0 & DWC2_HPRT0_PRTCONNDET)
> +                     port_change |= USB_PORT_STAT_C_CONNECTION;
> +             if (hprt0 & DWC2_HPRT0_PRTOVRCURRCHNG)
> +                     port_change |= USB_PORT_STAT_C_OVERCURRENT;
> +
> +             *(__u32 *)buffer = cpu_to_le32(port_status |
> +                                     (port_change << 16));
> +             len = 4;
> +             break;
> +     case (USB_REQ_CLEAR_FEATURE << 8) | USB_DIR_OUT | USB_RECIP_ENDPOINT:
> +     case (USB_REQ_CLEAR_FEATURE << 8) | USB_DIR_OUT | USB_TYPE_CLASS:
> +             break;
> +
> +     case (USB_REQ_CLEAR_FEATURE << 8) | USB_DIR_OUT | USB_RECIP_OTHER | 
> USB_TYPE_CLASS:
> +             switch (wValue) {
> +             case USB_PORT_FEAT_C_CONNECTION:
> +                     hprt0 = readl(&regs->hprt0);
> +                     hprt0 &= ~DWC2_HPRT0_PRTCONNDET;
> +                     hprt0 |= DWC2_HPRT0_PRTCONNDET;
> +                     writel(hprt0, &regs->hprt0);
> +                     break;
> +             }
> +             break;
> +
> +     case (USB_REQ_SET_FEATURE << 8) | USB_DIR_OUT | USB_RECIP_OTHER | 
> USB_TYPE_CLASS:
> +             switch (wValue) {
> +             case USB_PORT_FEAT_SUSPEND:
> +                     break;
> +
> +             case USB_PORT_FEAT_RESET:
> +                     clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
> +                                     DWC2_HPRT0_PRTCONNDET |
> +                                     DWC2_HPRT0_PRTENCHNG |
> +                                     DWC2_HPRT0_PRTOVRCURRCHNG,
> +                                     DWC2_HPRT0_PRTRST);
> +                     mdelay(50);
> +                     clrbits_le32(&regs->hprt0, DWC2_HPRT0_PRTRST);
> +                     break;
> +
> +             case USB_PORT_FEAT_POWER:
> +                     clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
> +                                     DWC2_HPRT0_PRTCONNDET |
> +                                     DWC2_HPRT0_PRTENCHNG |
> +                                     DWC2_HPRT0_PRTOVRCURRCHNG,
> +                                     DWC2_HPRT0_PRTRST);
> +                     break;
> +
> +             case USB_PORT_FEAT_ENABLE:
> +                     break;
> +             }
> +             break;
> +     case (USB_REQ_SET_ADDRESS << 8) | USB_DIR_OUT:
> +             root_hub_devnum = wValue;
> +             break;
> +     case (USB_REQ_GET_DESCRIPTOR << 8) | USB_DIR_IN:
> +             switch (wValue & 0xff00) {
> +             case 0x0100:    /* device descriptor */
> +                     len = min3(leni, sizeof(root_hub_dev_des), wLength);
> +                     memcpy(buffer, root_hub_dev_des, len);
> +                     break;
> +             case 0x0200:    /* configuration descriptor */
> +                     len = min3(leni, sizeof(root_hub_config_des), wLength);
> +                     memcpy(buffer, root_hub_config_des, len);
> +                     break;
> +             case 0x0300:    /* string descriptors */
> +                     switch (wValue & 0xff) {
> +                     case 0x00:
> +                             len = min3(leni, sizeof(root_hub_str_index0),
> +                                        wLength);
> +                             memcpy(buffer, root_hub_str_index0, len);
> +                             break;
> +                     case 0x01:
> +                             len = min3(leni, sizeof(root_hub_str_index1),
> +                                        wLength);
> +                             memcpy(buffer, root_hub_str_index1, len);
> +                             break;
> +                     }
> +                     break;
> +             default:
> +                     stat = USB_ST_STALLED;
> +             }
> +             break;
> +
> +     case (USB_REQ_GET_DESCRIPTOR << 8) | USB_DIR_IN | USB_TYPE_CLASS:
> +     {
> +             __u32 temp = 0x00000001;
> +
> +             data[0] = 9;            /* min length; */
> +             data[1] = 0x29;
> +             data[2] = temp & RH_A_NDP;
> +             data[3] = 0;
> +             if (temp & RH_A_PSM)
> +                     data[3] |= 0x1;
> +             if (temp & RH_A_NOCP)
> +                     data[3] |= 0x10;
> +             else if (temp & RH_A_OCPM)
> +                     data[3] |= 0x8;
> +
> +             /* corresponds to data[4-7] */
> +             data[5] = (temp & RH_A_POTPGT) >> 24;
> +             data[7] = temp & RH_B_DR;
> +             if (data[2] < 7) {
> +                     data[8] = 0xff;
> +             } else {
> +                     data[0] += 2;
> +                     data[8] = (temp & RH_B_DR) >> 8;
> +                     data[9] = 0xff;
> +                     data[10] = data[9];
> +             }
> +
> +             len = min3(leni, data[0], wLength);
> +             memcpy(buffer, data, len);
> +             break;
> +     }
> +
> +     case (USB_REQ_GET_CONFIGURATION << 8) | USB_DIR_IN:
> +             *(__u8 *)buffer = 0x01;
> +             len = 1;
> +             break;
> +     case (USB_REQ_SET_CONFIGURATION << 8) | USB_DIR_OUT:
> +             break;
> +     default:
> +             puts("unsupported root hub command");
> +             stat = USB_ST_STALLED;
> +     }
> +
> +     mdelay(1);
> +
> +     len = min(len, leni);
> +
> +     dev->act_len = len;
> +     dev->status = stat;
> +
> +     return stat;
> +}
> +
> +/* U-Boot USB transmission interface */
> +int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
> +                 int len)
> +{
> +     int devnum = usb_pipedevice(pipe);
> +     int ep = usb_pipeendpoint(pipe);
> +     int max = usb_maxpacket(dev, pipe);
> +     int done = 0;
> +     uint32_t hctsiz, sub, tmp;
> +     struct dwc2_hc_regs *hc_regs = &regs->hc_regs[CHANNEL];
> +     uint32_t hcint;
> +     uint32_t hcint_new;
> +     uint32_t xfer_len;
> +     uint32_t num_packets;
> +     int stop_transfer = 0;
> +
> +     if (devnum == root_hub_devnum) {
> +             dev->status = 0;
> +             return -EINVAL;
> +     }
> +
> +     if (len > DWC2_DATA_BUF_SIZE) {
> +             printf("%s: %d is more then available buffer size (%d)\n",
> +                    __func__, len, DWC2_DATA_BUF_SIZE);
> +             dev->status = 0;
> +             dev->act_len = 0;
> +             return -EINVAL;
> +     }
> +
> +     while ((done < len) && !stop_transfer) {
> +             /* Initialize channel */
> +             dwc_otg_hc_init(regs, CHANNEL, devnum, ep,
> +                             usb_pipein(pipe), DWC2_HCCHAR_EPTYPE_BULK, max);
> +
> +             xfer_len = len - done;
> +             /* Make sure that xfer_len is a multiple of max packet size. */
> +             if (xfer_len > CONFIG_DWC2_MAX_TRANSFER_SIZE)
> +                     xfer_len = CONFIG_DWC2_MAX_TRANSFER_SIZE - max + 1;
> +
> +             if (xfer_len > 0) {
> +                     num_packets = (xfer_len + max - 1) / max;
> +                     if (num_packets > CONFIG_DWC2_MAX_PACKET_COUNT) {
> +                             num_packets = CONFIG_DWC2_MAX_PACKET_COUNT;
> +                             xfer_len = num_packets * max;
> +                     }
> +             } else {
> +                     num_packets = 1;
> +             }
> +
> +             if (usb_pipein(pipe))
> +                     xfer_len = num_packets * max;
> +
> +             writel((xfer_len << DWC2_HCTSIZ_XFERSIZE_OFFSET) |
> +                    (num_packets << DWC2_HCTSIZ_PKTCNT_OFFSET) |
> +                    (bulk_data_toggle[devnum][ep] <<
> +                             DWC2_HCTSIZ_PID_OFFSET),
> +                    &hc_regs->hctsiz);
> +
> +             memcpy(aligned_buffer, (char *)buffer + done, len - done);
> +             writel((uint32_t)aligned_buffer, &hc_regs->hcdma);
> +
> +             /* Remember original int status */
> +             hcint = readl(&hc_regs->hcint);
> +
> +             /* Set host channel enable after all other setup is complete. */
> +             clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK |
> +                             DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS,
> +                             (1 << DWC2_HCCHAR_MULTICNT_OFFSET) |
> +                             DWC2_HCCHAR_CHEN);
> +
> +             /* TODO: no endless loop */
> +             while (1) {
> +                     hcint_new = readl(&hc_regs->hcint);
> +                     if (hcint != hcint_new)
> +                             hcint = hcint_new;
> +
> +                     if (!(hcint_new & DWC2_HCINT_CHHLTD))
> +                             continue;
> +
> +                     if (hcint_new & DWC2_HCINT_XFERCOMP) {
> +                             hctsiz = readl(&hc_regs->hctsiz);
> +                             done += xfer_len;
> +
> +                             sub = hctsiz & DWC2_HCTSIZ_XFERSIZE_MASK;
> +                             sub >>= DWC2_HCTSIZ_XFERSIZE_OFFSET;
> +
> +                             if (usb_pipein(pipe)) {
> +                                     done -= sub;
> +                                     if (hctsiz & DWC2_HCTSIZ_XFERSIZE_MASK)
> +                                             stop_transfer = 1;
> +                             }
> +
> +                             tmp = hctsiz & DWC2_HCTSIZ_PID_MASK;
> +                             tmp >>= DWC2_HCTSIZ_PID_OFFSET;
> +                             if (tmp == DWC2_HC_PID_DATA1) {
> +                                     bulk_data_toggle[devnum][ep] =
> +                                             DWC2_HC_PID_DATA1;
> +                             } else {
> +                                     bulk_data_toggle[devnum][ep] =
> +                                             DWC2_HC_PID_DATA0;
> +                             }
> +                             break;
> +                     }
> +
> +                     if (hcint_new & DWC2_HCINT_STALL) {
> +                             puts("DWC OTG: Channel halted");
> +                             bulk_data_toggle[devnum][ep] =
> +                                     DWC2_HC_PID_DATA0;
> +
> +                             stop_transfer = 1;
> +                             break;
> +                     }
> +             }
> +     }
> +
> +     if (done && usb_pipein(pipe))
> +             memcpy(buffer, aligned_buffer, done);
> +
> +     writel(0, &hc_regs->hcintmsk);
> +     writel(0xFFFFFFFF, &hc_regs->hcint);
> +
> +     dev->status = 0;
> +     dev->act_len = done;
> +
> +     return 0;
> +}
> +
> +int submit_control_msg(struct usb_device *dev, unsigned long pipe, void 
> *buffer,
> +                    int len, struct devrequest *setup)
> +{
> +     struct dwc2_hc_regs *hc_regs = &regs->hc_regs[CHANNEL];
> +     int done = 0;
> +     int devnum = usb_pipedevice(pipe);
> +     int ep = usb_pipeendpoint(pipe);
> +     int max = usb_maxpacket(dev, pipe);
> +     uint32_t hctsiz = 0, sub, tmp;
> +     uint32_t hcint;
> +     /* For CONTROL endpoint pid should start with DATA1 */
> +     int status_direction;
> +
> +     if (devnum == root_hub_devnum) {
> +             dev->status = 0;
> +             dev->speed = USB_SPEED_HIGH;
> +             return dwc_otg_submit_rh_msg(dev, pipe, buffer, len, setup);
> +     }
> +
> +     if (len > DWC2_DATA_BUF_SIZE) {
> +             printf("%s: %d is more then available buffer size(%d)\n",
> +                    __func__, len, DWC2_DATA_BUF_SIZE);
> +             dev->status = 0;
> +             dev->act_len = 0;
> +             return -EINVAL;
> +     }
> +
> +     /* Initialize channel, OUT for setup buffer */
> +     dwc_otg_hc_init(regs, CHANNEL, devnum, ep, 0,
> +                     DWC2_HCCHAR_EPTYPE_CONTROL, max);
> +
> +     /* SETUP stage  */
> +     writel((8 << DWC2_HCTSIZ_XFERSIZE_OFFSET) |
> +            (1 << DWC2_HCTSIZ_PKTCNT_OFFSET) |
> +            (DWC2_HC_PID_SETUP << DWC2_HCTSIZ_PID_OFFSET),
> +            &hc_regs->hctsiz);
> +
> +     writel((uint32_t)setup, &hc_regs->hcdma);
> +
> +     /* Set host channel enable after all other setup is complete. */
> +     clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK |
> +                     DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS,
> +                     (1 << DWC2_HCCHAR_MULTICNT_OFFSET) | DWC2_HCCHAR_CHEN);
> +
> +     wait_for_bit(&hc_regs->hcint, DWC2_HCINT_CHHLTD, 1);
> +     hcint = readl(&hc_regs->hcint);
> +
> +     if (!(hcint & DWC2_HCINT_CHHLTD) || !(hcint & DWC2_HCINT_XFERCOMP)) {
> +             printf("%s: Error (HCINT=%08x)\n", __func__, hcint);
> +             dev->status = 0;
> +             dev->act_len = 0;
> +             return -EINVAL;
> +     }
> +
> +     /* Clear interrupts */
> +     writel(0, &hc_regs->hcintmsk);
> +     writel(0xFFFFFFFF, &hc_regs->hcint);
> +
> +     if (buffer) {
> +             /* DATA stage */
> +             dwc_otg_hc_init(regs, CHANNEL, devnum, ep, usb_pipein(pipe),
> +                             DWC2_HCCHAR_EPTYPE_CONTROL, max);
> +
> +             /* TODO: check if len < 64 */
> +             control_data_toggle[devnum][ep] = DWC2_HC_PID_DATA1;
> +             writel((len << DWC2_HCTSIZ_XFERSIZE_OFFSET) |
> +                    (1 << DWC2_HCTSIZ_PKTCNT_OFFSET) |
> +                    (control_data_toggle[devnum][ep] <<
> +                             DWC2_HCTSIZ_PID_OFFSET),
> +                    &hc_regs->hctsiz);
> +
> +             writel((uint32_t)buffer, &hc_regs->hcdma);
> +
> +             /* Set host channel enable after all other setup is complete */
> +             clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK |
> +                             DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS,
> +                             (1 << DWC2_HCCHAR_MULTICNT_OFFSET) |
> +                             DWC2_HCCHAR_CHEN);
> +
> +             while (1) {
> +                     hcint = readl(&hc_regs->hcint);
> +                     if (!(hcint & DWC2_HCINT_CHHLTD))
> +                             continue;
> +
> +                     if (hcint & DWC2_HCINT_XFERCOMP) {
> +                             hctsiz = readl(&hc_regs->hctsiz);
> +                             done = len;
> +
> +                             sub = hctsiz & DWC2_HCTSIZ_XFERSIZE_MASK;
> +                             sub >>= DWC2_HCTSIZ_XFERSIZE_OFFSET;
> +
> +                             if (usb_pipein(pipe))
> +                                     done -= sub;
> +                     }
> +
> +                     if (hcint & DWC2_HCINT_ACK) {
> +                             tmp = hctsiz & DWC2_HCTSIZ_PID_MASK;
> +                             tmp >>= DWC2_HCTSIZ_PID_OFFSET;
> +                             if (tmp == DWC2_HC_PID_DATA0) {
> +                                     control_data_toggle[devnum][ep] =
> +                                             DWC2_HC_PID_DATA0;
> +                             } else {
> +                                     control_data_toggle[devnum][ep] =
> +                                             DWC2_HC_PID_DATA1;
> +                             }
> +                     }
> +
> +                     if (hcint != STATUS_ACK_HLT_COMPL) {
> +                             printf("%s: Error (HCINT=%08x)\n",
> +                                    __func__, hcint);
> +                             goto out;
> +                     }
> +
> +                     break;
> +             }
> +     } /* End of DATA stage */
> +
> +     /* STATUS stage */
> +     if ((len == 0) || usb_pipeout(pipe))
> +             status_direction = 1;
> +     else
> +             status_direction = 0;
> +
> +     dwc_otg_hc_init(regs, CHANNEL, devnum, ep,
> +                     status_direction, DWC2_HCCHAR_EPTYPE_CONTROL, max);
> +
> +     writel((1 << DWC2_HCTSIZ_PKTCNT_OFFSET) |
> +            (DWC2_HC_PID_DATA1 << DWC2_HCTSIZ_PID_OFFSET),
> +            &hc_regs->hctsiz);
> +
> +     writel((uint32_t)status_buffer, &hc_regs->hcdma);
> +
> +     /* Set host channel enable after all other setup is complete. */
> +     clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK |
> +                     DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS,
> +                     (1 << DWC2_HCCHAR_MULTICNT_OFFSET) | DWC2_HCCHAR_CHEN);
> +
> +     while (1) {
> +             hcint = readl(&hc_regs->hcint);
> +             if (hcint & DWC2_HCINT_CHHLTD)
> +                     break;
> +     }
> +
> +     if (hcint != STATUS_ACK_HLT_COMPL)
> +             printf("%s: Error (HCINT=%08x)\n", __func__, hcint);
> +
> +out:
> +     dev->act_len = done;
> +     dev->status = 0;
> +
> +     return done;
> +}
> +
> +int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
> +                int len, int interval)
> +{
> +     printf("dev = %p pipe = %#lx buf = %p size = %d int = %d\n",
> +            dev, pipe, buffer, len, interval);
> +     return -ENOSYS;
> +}
> +
> +/* U-Boot USB control interface */
> +int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
> +{
> +     uint32_t snpsid;
> +     int i, j;
> +
> +     root_hub_devnum = 0;
> +
> +     snpsid = readl(&regs->gsnpsid);
> +     printf("Core Release: %x.%03x\n", snpsid >> 12 & 0xf, snpsid & 0xfff);
> +
> +     if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx) {
> +             printf("SNPSID invalid (not DWC2 OTG device): %08x\n", snpsid);
> +             return -ENODEV;
> +     }
> +
> +     dwc_otg_core_init(regs);
> +     dwc_otg_core_host_init(regs);
> +
> +     clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
> +                     DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG |
> +                     DWC2_HPRT0_PRTOVRCURRCHNG,
> +                     DWC2_HPRT0_PRTRST);
> +     mdelay(50);
> +     clrbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET |
> +                  DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG |
> +                  DWC2_HPRT0_PRTRST);
> +
> +     for (i = 0; i < MAX_DEVICE; i++) {
> +             for (j = 0; j < MAX_ENDPOINT; j++) {
> +                     control_data_toggle[i][j] = DWC2_HC_PID_DATA1;
> +                     bulk_data_toggle[i][j] = DWC2_HC_PID_DATA0;
> +             }
> +     }
> +
> +     return 0;
> +}
> +
> +int usb_lowlevel_stop(int index)
> +{
> +     /* Put everything in reset. */
> +     clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
> +                     DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG |
> +                     DWC2_HPRT0_PRTOVRCURRCHNG,
> +                     DWC2_HPRT0_PRTRST);
> +     return 0;
> +}
> diff --git a/drivers/usb/host/dwc2.h b/drivers/usb/host/dwc2.h
> new file mode 100644
> index 0000000..6a1edd0
> --- /dev/null
> +++ b/drivers/usb/host/dwc2.h
> @@ -0,0 +1,784 @@
> +/*
> + * Copyright (C) 2014 Marek Vasut <ma...@denx.de>
> + *
> + * SPDX-License-Identifier:     GPL-2.0+
> + */
> +
> +#ifndef __DWC2_H__
> +#define __DWC2_H__
> +
> +struct dwc2_hc_regs {
> +     u32                     hcchar;         /* 0x00 */
> +     u32                     hcsplt;
> +     u32                     hcint;
> +     u32                     hcintmsk;
> +     u32                     hctsiz;         /* 0x10 */
> +     u32                     hcdma;
> +     u32                     reserved;
> +     u32                     hcdmab;
> +};
> +
> +struct dwc2_host_regs {
> +     u32                     hcfg;           /* 0x00 */
> +     u32                     hfir;
> +     u32                     hfnum;
> +     u32                     _pad_0x40c;
> +     u32                     hptxsts;        /* 0x10 */
> +     u32                     haint;
> +     u32                     haintmsk;
> +     u32                     hflbaddr;
> +};
> +
> +struct dwc2_core_regs {
> +     u32                     gotgctl;        /* 0x000 */
> +     u32                     gotgint;
> +     u32                     gahbcfg;
> +     u32                     gusbcfg;
> +     u32                     grstctl;        /* 0x010 */
> +     u32                     gintsts;
> +     u32                     gintmsk;
> +     u32                     grxstsr;
> +     u32                     grxstsp;        /* 0x020 */
> +     u32                     grxfsiz;
> +     u32                     gnptxfsiz;
> +     u32                     gnptxsts;
> +     u32                     gi2cctl;        /* 0x030 */
> +     u32                     gpvndctl;
> +     u32                     ggpio;
> +     u32                     guid;
> +     u32                     gsnpsid;        /* 0x040 */
> +     u32                     ghwcfg1;
> +     u32                     ghwcfg2;
> +     u32                     ghwcfg3;
> +     u32                     ghwcfg4;        /* 0x050 */
> +     u32                     glpmcfg;
> +     u32                     _pad_0x58_0x9c[42];
> +     u32                     hptxfsiz;       /* 0x100 */
> +     u32                     dptxfsiz_dieptxf[15];
> +     u32                     _pad_0x140_0x3fc[176];
> +     struct dwc2_host_regs   host_regs;      /* 0x400 */
> +     u32                     _pad_0x420_0x43c[8];
> +     u32                     hprt0;          /* 0x440 */
> +     u32                     _pad_0x444_0x4fc[47];
> +     struct dwc2_hc_regs     hc_regs[16];    /* 0x500 */
> +     u32                     _pad_0x700_0xe00[448];
> +     u32                     pcgcctl;        /* 0xe00 */
> +};
> +
> +#define DWC2_GOTGCTL_SESREQSCS                               (1 << 0)
> +#define DWC2_GOTGCTL_SESREQSCS_OFFSET                        0
> +#define DWC2_GOTGCTL_SESREQ                          (1 << 1)
> +#define DWC2_GOTGCTL_SESREQ_OFFSET                   1
> +#define DWC2_GOTGCTL_HSTNEGSCS                               (1 << 8)
> +#define DWC2_GOTGCTL_HSTNEGSCS_OFFSET                        8
> +#define DWC2_GOTGCTL_HNPREQ                          (1 << 9)
> +#define DWC2_GOTGCTL_HNPREQ_OFFSET                   9
> +#define DWC2_GOTGCTL_HSTSETHNPEN                     (1 << 10)
> +#define DWC2_GOTGCTL_HSTSETHNPEN_OFFSET                      10
> +#define DWC2_GOTGCTL_DEVHNPEN                                (1 << 11)
> +#define DWC2_GOTGCTL_DEVHNPEN_OFFSET                 11
> +#define DWC2_GOTGCTL_CONIDSTS                                (1 << 16)
> +#define DWC2_GOTGCTL_CONIDSTS_OFFSET                 16

Add bit 17 here for DBNCTIME.

> +#define DWC2_GOTGCTL_ASESVLD                         (1 << 18)
> +#define DWC2_GOTGCTL_ASESVLD_OFFSET                  18
> +#define DWC2_GOTGCTL_BSESVLD                         (1 << 19)
> +#define DWC2_GOTGCTL_BSESVLD_OFFSET                  19
> +#define DWC2_GOTGCTL_CURRMOD                         (1 << 20)
> +#define DWC2_GOTGCTL_CURRMOD_OFFSET                  20

Bit 20 of GOTCTL is OTGVER to indication the OTG version of the core.

> +#define DWC2_GOTGINT_SESENDDET                               (1 << 2)
> +#define DWC2_GOTGINT_SESENDDET_OFFSET                        2
> +#define DWC2_GOTGINT_SESREQSUCSTSCHNG                        (1 << 8)
> +#define DWC2_GOTGINT_SESREQSUCSTSCHNG_OFFSET         8
> +#define DWC2_GOTGINT_HSTNEGSUCSTSCHNG                        (1 << 9)
> +#define DWC2_GOTGINT_HSTNEGSUCSTSCHNG_OFFSET         9
> +#define DWC2_GOTGINT_RESERVER10_16_MASK                      (0x7F << 10)
> +#define DWC2_GOTGINT_RESERVER10_16_OFFSET            10
> +#define DWC2_GOTGINT_HSTNEGDET                               (1 << 17)
> +#define DWC2_GOTGINT_HSTNEGDET_OFFSET                        17
> +#define DWC2_GOTGINT_ADEVTOUTCHNG                    (1 << 18)
> +#define DWC2_GOTGINT_ADEVTOUTCHNG_OFFSET             18
> +#define DWC2_GOTGINT_DEBDONE                         (1 << 19)
> +#define DWC2_GOTGINT_DEBDONE_OFFSET                  19
> +#define DWC2_GAHBCFG_GLBLINTRMSK                     (1 << 0)
> +#define DWC2_GAHBCFG_GLBLINTRMSK_OFFSET                      0
> +#define DWC2_GAHBCFG_HBURSTLEN_SINGLE                        (0 << 1)
> +#define DWC2_GAHBCFG_HBURSTLEN_INCR                  (1 << 1)
> +#define DWC2_GAHBCFG_HBURSTLEN_INCR4                 (3 << 1)
> +#define DWC2_GAHBCFG_HBURSTLEN_INCR8                 (5 << 1)
> +#define DWC2_GAHBCFG_HBURSTLEN_INCR16                        (7 << 1)
> +#define DWC2_GAHBCFG_HBURSTLEN_MASK                  (0xF << 1)
> +#define DWC2_GAHBCFG_HBURSTLEN_OFFSET                        1
> +#define DWC2_GAHBCFG_DMAENABLE                               (1 << 5)
> +#define DWC2_GAHBCFG_DMAENABLE_OFFSET                        5
> +#define DWC2_GAHBCFG_NPTXFEMPLVL_TXFEMPLVL           (1 << 7)
> +#define DWC2_GAHBCFG_NPTXFEMPLVL_TXFEMPLVL_OFFSET    7
> +#define DWC2_GAHBCFG_PTXFEMPLVL                              (1 << 8)
> +#define DWC2_GAHBCFG_PTXFEMPLVL_OFFSET                       8
> +#define DWC2_GUSBCFG_TOUTCAL_MASK                    (0x7 << 0)
> +#define DWC2_GUSBCFG_TOUTCAL_OFFSET                  0
> +#define DWC2_GUSBCFG_PHYIF                           (1 << 3)
> +#define DWC2_GUSBCFG_PHYIF_OFFSET                    3
> +#define DWC2_GUSBCFG_ULPI_UTMI_SEL                   (1 << 4)
> +#define DWC2_GUSBCFG_ULPI_UTMI_SEL_OFFSET            4
> +#define DWC2_GUSBCFG_FSINTF                          (1 << 5)
> +#define DWC2_GUSBCFG_FSINTF_OFFSET                   5
> +#define DWC2_GUSBCFG_PHYSEL                          (1 << 6)
> +#define DWC2_GUSBCFG_PHYSEL_OFFSET                   6
> +#define DWC2_GUSBCFG_DDRSEL                          (1 << 7)
> +#define DWC2_GUSBCFG_DDRSEL_OFFSET                   7
> +#define DWC2_GUSBCFG_SRPCAP                          (1 << 8)
> +#define DWC2_GUSBCFG_SRPCAP_OFFSET                   8
> +#define DWC2_GUSBCFG_HNPCAP                          (1 << 9)
> +#define DWC2_GUSBCFG_HNPCAP_OFFSET                   9
> +#define DWC2_GUSBCFG_USBTRDTIM_MASK                  (0xF << 10)
> +#define DWC2_GUSBCFG_USBTRDTIM_OFFSET                        10
> +#define DWC2_GUSBCFG_NPTXFRWNDEN                     (1 << 14)
> +#define DWC2_GUSBCFG_NPTXFRWNDEN_OFFSET                      14
> +#define DWC2_GUSBCFG_PHYLPWRCLKSEL                   (1 << 15)
> +#define DWC2_GUSBCFG_PHYLPWRCLKSEL_OFFSET            15
> +#define DWC2_GUSBCFG_OTGUTMIFSSEL                    (1 << 16)
> +#define DWC2_GUSBCFG_OTGUTMIFSSEL_OFFSET             16
> +#define DWC2_GUSBCFG_ULPI_FSLS                               (1 << 17)
> +#define DWC2_GUSBCFG_ULPI_FSLS_OFFSET                        17
> +#define DWC2_GUSBCFG_ULPI_AUTO_RES                   (1 << 18)
> +#define DWC2_GUSBCFG_ULPI_AUTO_RES_OFFSET            18
> +#define DWC2_GUSBCFG_ULPI_CLK_SUS_M                  (1 << 19)
> +#define DWC2_GUSBCFG_ULPI_CLK_SUS_M_OFFSET           19
> +#define DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV                       (1 << 20)
> +#define DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV_OFFSET                20
> +#define DWC2_GUSBCFG_ULPI_INT_VBUS_INDICATOR         (1 << 21)
> +#define DWC2_GUSBCFG_ULPI_INT_VBUS_INDICATOR_OFFSET  21
> +#define DWC2_GUSBCFG_TERM_SEL_DL_PULSE                       (1 << 22)
> +#define DWC2_GUSBCFG_TERM_SEL_DL_PULSE_OFFSET                22
> +#define DWC2_GUSBCFG_IC_USB_CAP                              (1 << 26)
> +#define DWC2_GUSBCFG_IC_USB_CAP_OFFSET                       26
> +#define DWC2_GUSBCFG_IC_TRAFFIC_PULL_REMOVE          (1 << 27)
> +#define DWC2_GUSBCFG_IC_TRAFFIC_PULL_REMOVE_OFFSET   27
> +#define DWC2_GUSBCFG_TX_END_DELAY                    (1 << 28)
> +#define DWC2_GUSBCFG_TX_END_DELAY_OFFSET             28

bits 29 and 30 of GUSBCFG are to Force Host and Device mode, respectively.
These bits may get used in the future.

> +#define DWC2_GLPMCTL_LPM_CAP_EN                              (1 << 0)
> +#define DWC2_GLPMCTL_LPM_CAP_EN_OFFSET                       0
> +#define DWC2_GLPMCTL_APPL_RESP                               (1 << 1)
> +#define DWC2_GLPMCTL_APPL_RESP_OFFSET                        1
> +#define DWC2_GLPMCTL_HIRD_MASK                               (0xF << 2)
> +#define DWC2_GLPMCTL_HIRD_OFFSET                     2
> +#define DWC2_GLPMCTL_REM_WKUP_EN                     (1 << 6)
> +#define DWC2_GLPMCTL_REM_WKUP_EN_OFFSET                      6
> +#define DWC2_GLPMCTL_EN_UTMI_SLEEP                   (1 << 7)
> +#define DWC2_GLPMCTL_EN_UTMI_SLEEP_OFFSET            7
> +#define DWC2_GLPMCTL_HIRD_THRES_MASK                 (0x1F << 8)
> +#define DWC2_GLPMCTL_HIRD_THRES_OFFSET                       8
> +#define DWC2_GLPMCTL_LPM_RESP_MASK                   (0x3 << 13)
> +#define DWC2_GLPMCTL_LPM_RESP_OFFSET                 13
> +#define DWC2_GLPMCTL_PRT_SLEEP_STS                   (1 << 15)
> +#define DWC2_GLPMCTL_PRT_SLEEP_STS_OFFSET            15
> +#define DWC2_GLPMCTL_SLEEP_STATE_RESUMEOK            (1 << 16)
> +#define DWC2_GLPMCTL_SLEEP_STATE_RESUMEOK_OFFSET     16
> +#define DWC2_GLPMCTL_LPM_CHAN_INDEX_MASK             (0xF << 17)
> +#define DWC2_GLPMCTL_LPM_CHAN_INDEX_OFFSET           17
> +#define DWC2_GLPMCTL_RETRY_COUNT_MASK                        (0x7 << 21)
> +#define DWC2_GLPMCTL_RETRY_COUNT_OFFSET                      21
> +#define DWC2_GLPMCTL_SEND_LPM                                (1 << 24)
> +#define DWC2_GLPMCTL_SEND_LPM_OFFSET                 24
> +#define DWC2_GLPMCTL_RETRY_COUNT_STS_MASK            (0x7 << 25)
> +#define DWC2_GLPMCTL_RETRY_COUNT_STS_OFFSET          25
> +#define DWC2_GLPMCTL_HSIC_CONNECT                    (1 << 30)
> +#define DWC2_GLPMCTL_HSIC_CONNECT_OFFSET             30
> +#define DWC2_GLPMCTL_INV_SEL_HSIC                    (1 << 31)
> +#define DWC2_GLPMCTL_INV_SEL_HSIC_OFFSET             31
> +#define DWC2_GRSTCTL_CSFTRST                         (1 << 0)
> +#define DWC2_GRSTCTL_CSFTRST_OFFSET                  0
> +#define DWC2_GRSTCTL_HSFTRST                         (1 << 1)
> +#define DWC2_GRSTCTL_HSFTRST_OFFSET                  1
> +#define DWC2_GRSTCTL_HSTFRM                          (1 << 2)
> +#define DWC2_GRSTCTL_HSTFRM_OFFSET                   2
> +#define DWC2_GRSTCTL_INTKNQFLSH                              (1 << 3)
> +#define DWC2_GRSTCTL_INTKNQFLSH_OFFSET                       3
> +#define DWC2_GRSTCTL_RXFFLSH                         (1 << 4)
> +#define DWC2_GRSTCTL_RXFFLSH_OFFSET                  4
> +#define DWC2_GRSTCTL_TXFFLSH                         (1 << 5)
> +#define DWC2_GRSTCTL_TXFFLSH_OFFSET                  5
> +#define DWC2_GRSTCTL_TXFNUM_MASK                     (0x1F << 6)
> +#define DWC2_GRSTCTL_TXFNUM_OFFSET                   6
> +#define DWC2_GRSTCTL_DMAREQ                          (1 << 30)
> +#define DWC2_GRSTCTL_DMAREQ_OFFSET                   30
> +#define DWC2_GRSTCTL_AHBIDLE                         (1 << 31)
> +#define DWC2_GRSTCTL_AHBIDLE_OFFSET                  31
> +#define DWC2_GINTMSK_MODEMISMATCH                    (1 << 1)
> +#define DWC2_GINTMSK_MODEMISMATCH_OFFSET             1
> +#define DWC2_GINTMSK_OTGINTR                         (1 << 2)
> +#define DWC2_GINTMSK_OTGINTR_OFFSET                  2
> +#define DWC2_GINTMSK_SOFINTR                         (1 << 3)
> +#define DWC2_GINTMSK_SOFINTR_OFFSET                  3
> +#define DWC2_GINTMSK_RXSTSQLVL                               (1 << 4)
> +#define DWC2_GINTMSK_RXSTSQLVL_OFFSET                        4
> +#define DWC2_GINTMSK_NPTXFEMPTY                              (1 << 5)
> +#define DWC2_GINTMSK_NPTXFEMPTY_OFFSET                       5
> +#define DWC2_GINTMSK_GINNAKEFF                               (1 << 6)
> +#define DWC2_GINTMSK_GINNAKEFF_OFFSET                        6
> +#define DWC2_GINTMSK_GOUTNAKEFF                              (1 << 7)
> +#define DWC2_GINTMSK_GOUTNAKEFF_OFFSET                       7
> +#define DWC2_GINTMSK_I2CINTR                         (1 << 9)
> +#define DWC2_GINTMSK_I2CINTR_OFFSET                  9
> +#define DWC2_GINTMSK_ERLYSUSPEND                     (1 << 10)
> +#define DWC2_GINTMSK_ERLYSUSPEND_OFFSET                      10
> +#define DWC2_GINTMSK_USBSUSPEND                              (1 << 11)
> +#define DWC2_GINTMSK_USBSUSPEND_OFFSET                       11
> +#define DWC2_GINTMSK_USBRESET                                (1 << 12)
> +#define DWC2_GINTMSK_USBRESET_OFFSET                 12
> +#define DWC2_GINTMSK_ENUMDONE                                (1 << 13)
> +#define DWC2_GINTMSK_ENUMDONE_OFFSET                 13
> +#define DWC2_GINTMSK_ISOOUTDROP                              (1 << 14)
> +#define DWC2_GINTMSK_ISOOUTDROP_OFFSET                       14
> +#define DWC2_GINTMSK_EOPFRAME                                (1 << 15)
> +#define DWC2_GINTMSK_EOPFRAME_OFFSET                 15
> +#define DWC2_GINTMSK_EPMISMATCH                              (1 << 17)
> +#define DWC2_GINTMSK_EPMISMATCH_OFFSET                       17
> +#define DWC2_GINTMSK_INEPINTR                                (1 << 18)
> +#define DWC2_GINTMSK_INEPINTR_OFFSET                 18
> +#define DWC2_GINTMSK_OUTEPINTR                               (1 << 19)
> +#define DWC2_GINTMSK_OUTEPINTR_OFFSET                        19
> +#define DWC2_GINTMSK_INCOMPLISOIN                    (1 << 20)
> +#define DWC2_GINTMSK_INCOMPLISOIN_OFFSET             20
> +#define DWC2_GINTMSK_INCOMPLISOOUT                   (1 << 21)
> +#define DWC2_GINTMSK_INCOMPLISOOUT_OFFSET            21
> +#define DWC2_GINTMSK_PORTINTR                                (1 << 24)
> +#define DWC2_GINTMSK_PORTINTR_OFFSET                 24
> +#define DWC2_GINTMSK_HCINTR                          (1 << 25)
> +#define DWC2_GINTMSK_HCINTR_OFFSET                   25
> +#define DWC2_GINTMSK_PTXFEMPTY                               (1 << 26)
> +#define DWC2_GINTMSK_PTXFEMPTY_OFFSET                        26
> +#define DWC2_GINTMSK_LPMTRANRCVD                     (1 << 27)
> +#define DWC2_GINTMSK_LPMTRANRCVD_OFFSET                      27
> +#define DWC2_GINTMSK_CONIDSTSCHNG                    (1 << 28)
> +#define DWC2_GINTMSK_CONIDSTSCHNG_OFFSET             28
> +#define DWC2_GINTMSK_DISCONNECT                              (1 << 29)
> +#define DWC2_GINTMSK_DISCONNECT_OFFSET                       29
> +#define DWC2_GINTMSK_SESSREQINTR                     (1 << 30)
> +#define DWC2_GINTMSK_SESSREQINTR_OFFSET                      30
> +#define DWC2_GINTMSK_WKUPINTR                                (1 << 31)
> +#define DWC2_GINTMSK_WKUPINTR_OFFSET                 31
> +#define DWC2_GINTSTS_CURMODE_DEVICE                  (0 << 0)
> +#define DWC2_GINTSTS_CURMODE_HOST                    (1 << 0)
> +#define DWC2_GINTSTS_CURMODE                         (1 << 0)
> +#define DWC2_GINTSTS_CURMODE_OFFSET                  0
> +#define DWC2_GINTSTS_MODEMISMATCH                    (1 << 1)
> +#define DWC2_GINTSTS_MODEMISMATCH_OFFSET             1
> +#define DWC2_GINTSTS_OTGINTR                         (1 << 2)
> +#define DWC2_GINTSTS_OTGINTR_OFFSET                  2
> +#define DWC2_GINTSTS_SOFINTR                         (1 << 3)
> +#define DWC2_GINTSTS_SOFINTR_OFFSET                  3
> +#define DWC2_GINTSTS_RXSTSQLVL                               (1 << 4)
> +#define DWC2_GINTSTS_RXSTSQLVL_OFFSET                        4
> +#define DWC2_GINTSTS_NPTXFEMPTY                              (1 << 5)
> +#define DWC2_GINTSTS_NPTXFEMPTY_OFFSET                       5
> +#define DWC2_GINTSTS_GINNAKEFF                               (1 << 6)
> +#define DWC2_GINTSTS_GINNAKEFF_OFFSET                        6
> +#define DWC2_GINTSTS_GOUTNAKEFF                              (1 << 7)
> +#define DWC2_GINTSTS_GOUTNAKEFF_OFFSET                       7
> +#define DWC2_GINTSTS_I2CINTR                         (1 << 9)
> +#define DWC2_GINTSTS_I2CINTR_OFFSET                  9
> +#define DWC2_GINTSTS_ERLYSUSPEND                     (1 << 10)
> +#define DWC2_GINTSTS_ERLYSUSPEND_OFFSET                      10
> +#define DWC2_GINTSTS_USBSUSPEND                              (1 << 11)
> +#define DWC2_GINTSTS_USBSUSPEND_OFFSET                       11
> +#define DWC2_GINTSTS_USBRESET                                (1 << 12)
> +#define DWC2_GINTSTS_USBRESET_OFFSET                 12
> +#define DWC2_GINTSTS_ENUMDONE                                (1 << 13)
> +#define DWC2_GINTSTS_ENUMDONE_OFFSET                 13
> +#define DWC2_GINTSTS_ISOOUTDROP                              (1 << 14)
> +#define DWC2_GINTSTS_ISOOUTDROP_OFFSET                       14
> +#define DWC2_GINTSTS_EOPFRAME                                (1 << 15)
> +#define DWC2_GINTSTS_EOPFRAME_OFFSET                 15
> +#define DWC2_GINTSTS_INTOKENRX                               (1 << 16)
> +#define DWC2_GINTSTS_INTOKENRX_OFFSET                        16
> +#define DWC2_GINTSTS_EPMISMATCH                              (1 << 17)
> +#define DWC2_GINTSTS_EPMISMATCH_OFFSET                       17
> +#define DWC2_GINTSTS_INEPINT                         (1 << 18)
> +#define DWC2_GINTSTS_INEPINT_OFFSET                  18
> +#define DWC2_GINTSTS_OUTEPINTR                               (1 << 19)
> +#define DWC2_GINTSTS_OUTEPINTR_OFFSET                        19
> +#define DWC2_GINTSTS_INCOMPLISOIN                    (1 << 20)
> +#define DWC2_GINTSTS_INCOMPLISOIN_OFFSET             20
> +#define DWC2_GINTSTS_INCOMPLISOOUT                   (1 << 21)
> +#define DWC2_GINTSTS_INCOMPLISOOUT_OFFSET            21
> +#define DWC2_GINTSTS_PORTINTR                                (1 << 24)
> +#define DWC2_GINTSTS_PORTINTR_OFFSET                 24
> +#define DWC2_GINTSTS_HCINTR                          (1 << 25)
> +#define DWC2_GINTSTS_HCINTR_OFFSET                   25
> +#define DWC2_GINTSTS_PTXFEMPTY                               (1 << 26)
> +#define DWC2_GINTSTS_PTXFEMPTY_OFFSET                        26
> +#define DWC2_GINTSTS_LPMTRANRCVD                     (1 << 27)
> +#define DWC2_GINTSTS_LPMTRANRCVD_OFFSET                      27
> +#define DWC2_GINTSTS_CONIDSTSCHNG                    (1 << 28)
> +#define DWC2_GINTSTS_CONIDSTSCHNG_OFFSET             28
> +#define DWC2_GINTSTS_DISCONNECT                              (1 << 29)
> +#define DWC2_GINTSTS_DISCONNECT_OFFSET                       29
> +#define DWC2_GINTSTS_SESSREQINTR                     (1 << 30)
> +#define DWC2_GINTSTS_SESSREQINTR_OFFSET                      30
> +#define DWC2_GINTSTS_WKUPINTR                                (1 << 31)
> +#define DWC2_GINTSTS_WKUPINTR_OFFSET                 31
> +#define DWC2_DEVICE_GRXSTS_EPNUM_MASK                        (0xF << 0)
> +#define DWC2_DEVICE_GRXSTS_EPNUM_OFFSET                      0
> +#define DWC2_DEVICE_GRXSTS_BCNT_MASK                 (0x7FF << 4)
> +#define DWC2_DEVICE_GRXSTS_BCNT_OFFSET                       4
> +#define DWC2_DEVICE_GRXSTS_DPID_MASK                 (0x3 << 15)
> +#define DWC2_DEVICE_GRXSTS_DPID_OFFSET                       15
> +#define DWC2_DEVICE_GRXSTS_PKTSTS_MASK                       (0xF << 17)
> +#define DWC2_DEVICE_GRXSTS_PKTSTS_OFFSET             17
> +#define DWC2_DEVICE_GRXSTS_FN_MASK                   (0xF << 21)
> +#define DWC2_DEVICE_GRXSTS_FN_OFFSET                 21
> +#define DWC2_HOST_GRXSTS_CHNUM_MASK                  (0xF << 0)
> +#define DWC2_HOST_GRXSTS_CHNUM_OFFSET                        0
> +#define DWC2_HOST_GRXSTS_BCNT_MASK                   (0x7FF << 4)
> +#define DWC2_HOST_GRXSTS_BCNT_OFFSET                 4
> +#define DWC2_HOST_GRXSTS_DPID_MASK                   (0x3 << 15)
> +#define DWC2_HOST_GRXSTS_DPID_OFFSET                 15
> +#define DWC2_HOST_GRXSTS_PKTSTS_MASK                 (0xF << 17)
> +#define DWC2_HOST_GRXSTS_PKTSTS_OFFSET                       17

Not sure why there needs to be an entry for DEVICE_ and HOST_ of GRXSTS
defines here?

BR,
Dinh
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to