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(®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 <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