[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(®s->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(®s->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),
> + ®s->grstctl);
> + wait_for_bit(®s->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, ®s->grstctl);
> + wait_for_bit(®s->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(®s->grstctl, DWC2_GRSTCTL_AHBIDLE, 1);
> +
> + /* Core Soft Reset */
> + writel(DWC2_GRSTCTL_CSFTRST, ®s->grstctl);
> + wait_for_bit(®s->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, ®s->pcgcctl);
> +
> + /* Initialize Host Configuration Register */
> + init_fslspclksel(regs);
> +#ifdef CONFIG_DWC2_DFLT_SPEED_FULL
> + setbits_le32(®s->host_regs.hcfg, DWC2_HCFG_FSLSSUPP);
> +#endif
> +
> + /* Configure data FIFO sizes */
> +#ifdef CONFIG_DWC2_ENABLE_DYNAMIC_FIFO
> + if (readl(®s->ghwcfg2) & DWC2_HWCFG2_DYNAMIC_FIFO) {
> + /* Rx FIFO */
> + writel(CONFIG_DWC2_HOST_RX_FIFO_SIZE, ®s->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, ®s->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, ®s->hptxfsiz);
> + }
> +#endif
> +
> + /* Clear Host Set HNP Enable in the OTG Control Register */
> + clrbits_le32(®s->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(®s->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(®s->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(®s->hc_regs[i].hcchar,
> + DWC2_HCCHAR_EPDIR,
> + DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS);
> + wait_for_bit(®s->hc_regs[i].hcchar, DWC2_HCCHAR_CHEN, 0);
> + }
> +
> + /* Turn on the vbus power. */
> + if (readl(®s->gintsts) & DWC2_GINTSTS_CURMODE_HOST) {
> + hprt0 = readl(®s->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, ®s->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(®s->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, ®s->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(®s->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(®s->gintsts) & DWC2_GINTSTS_CURMODE_HOST)
> + init_fslspclksel(regs);
> +
> +#ifdef CONFIG_DWC2_I2C_ENABLE
> + /* Program GUSBCFG.OtgUtmifsSel to I2C */
> + setbits_le32(®s->gusbcfg, DWC2_GUSBCFG_OTGUTMIFSSEL);
> +
> + /* Program GI2CCTL.I2CEn */
> + clrsetbits_le32(®s->gi2cctl, DWC2_GI2CCTL_I2CEN |
> + DWC2_GI2CCTL_I2CDEVADDR_MASK,
> + 1 << DWC2_GI2CCTL_I2CDEVADDR_OFFSET);
> + setbits_le32(®s->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, ®s->gusbcfg);
> +
> + /* Reset after setting the PHY parameters */
> + dwc_otg_core_reset(regs);
> +#endif
> +
> + usbcfg = readl(®s->gusbcfg);
> + usbcfg &= ~(DWC2_GUSBCFG_ULPI_FSLS | DWC2_GUSBCFG_ULPI_CLK_SUS_M);
> +#ifdef CONFIG_DWC2_ULPI_FS_LS
> + uint32_t hwcfg2 = readl(®s->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, ®s->gusbcfg);
> +
> + /* Program the GAHBCFG Register. */
> + switch (readl(®s->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, ®s->gahbcfg);
> +
> + /* Program the GUSBCFG register for HNP/SRP. */
> + setbits_le32(®s->gusbcfg, DWC2_GUSBCFG_HNPCAP | DWC2_GUSBCFG_SRPCAP);
> +
> +#ifdef CONFIG_DWC2_IC_USB_CAP
> + setbits_le32(®s->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 = ®s->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(®s->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(®s->hprt0);
> + hprt0 &= ~DWC2_HPRT0_PRTCONNDET;
> + hprt0 |= DWC2_HPRT0_PRTCONNDET;
> + writel(hprt0, ®s->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(®s->hprt0, DWC2_HPRT0_PRTENA |
> + DWC2_HPRT0_PRTCONNDET |
> + DWC2_HPRT0_PRTENCHNG |
> + DWC2_HPRT0_PRTOVRCURRCHNG,
> + DWC2_HPRT0_PRTRST);
> + mdelay(50);
> + clrbits_le32(®s->hprt0, DWC2_HPRT0_PRTRST);
> + break;
> +
> + case USB_PORT_FEAT_POWER:
> + clrsetbits_le32(®s->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 = ®s->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 = ®s->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(®s->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(®s->hprt0, DWC2_HPRT0_PRTENA |
> + DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG |
> + DWC2_HPRT0_PRTOVRCURRCHNG,
> + DWC2_HPRT0_PRTRST);
> + mdelay(50);
> + clrbits_le32(®s->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(®s->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