[U-Boot] [PATCH 1/3] usb: dwc2: Add driver for Synopsis DWC2 USB IP block

Dinh Nguyen dinguyen at opensource.altera.com
Tue Sep 23 23:59:28 CEST 2014


On Sun, 21 Sep 2014, Marek Vasut wrote:

> From: Oleksandr Tymoshenko <gonzo at 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 <gonzo at bluezbox.com>
> Signed-off-by: Stephen Warren <swarren at wwwdotorg.org>
> Signed-off-by: Marek Vasut <marex at denx.de>
> Cc: Chin Liang See <clsee at altera.com>
> Cc: Dinh Nguyen <dinguyen at altera.com>
> Cc: Albert Aribaud <albert.u.boot at aribaud.net>
> Cc: Tom Rini <trini at ti.com>
> Cc: Wolfgang Denk <wd at denx.de>
> Cc: Pavel Machek <pavel at 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 <gonzo at freebsd.org>
> + * Copyright (C) 2014 Marek Vasut <marex at 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 <marex at 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


More information about the U-Boot mailing list