1*6e9e0626SOleksandr Tymoshenko /* 2*6e9e0626SOleksandr Tymoshenko * Copyright (C) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org> 3*6e9e0626SOleksandr Tymoshenko * Copyright (C) 2014 Marek Vasut <marex@denx.de> 4*6e9e0626SOleksandr Tymoshenko * 5*6e9e0626SOleksandr Tymoshenko * SPDX-License-Identifier: GPL-2.0+ 6*6e9e0626SOleksandr Tymoshenko */ 7*6e9e0626SOleksandr Tymoshenko 8*6e9e0626SOleksandr Tymoshenko #include <common.h> 9*6e9e0626SOleksandr Tymoshenko #include <errno.h> 10*6e9e0626SOleksandr Tymoshenko #include <usb.h> 11*6e9e0626SOleksandr Tymoshenko #include <malloc.h> 12*6e9e0626SOleksandr Tymoshenko #include <usbroothubdes.h> 13*6e9e0626SOleksandr Tymoshenko #include <asm/io.h> 14*6e9e0626SOleksandr Tymoshenko 15*6e9e0626SOleksandr Tymoshenko #include "dwc2.h" 16*6e9e0626SOleksandr Tymoshenko 17*6e9e0626SOleksandr Tymoshenko /* Use only HC channel 0. */ 18*6e9e0626SOleksandr Tymoshenko #define DWC2_HC_CHANNEL 0 19*6e9e0626SOleksandr Tymoshenko 20*6e9e0626SOleksandr Tymoshenko #define DWC2_STATUS_BUF_SIZE 64 21*6e9e0626SOleksandr Tymoshenko #define DWC2_DATA_BUF_SIZE (64 * 1024) 22*6e9e0626SOleksandr Tymoshenko 23*6e9e0626SOleksandr Tymoshenko /* We need doubleword-aligned buffers for DMA transfers */ 24*6e9e0626SOleksandr Tymoshenko DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer, DWC2_DATA_BUF_SIZE, 8); 25*6e9e0626SOleksandr Tymoshenko DEFINE_ALIGN_BUFFER(uint8_t, status_buffer, DWC2_STATUS_BUF_SIZE, 8); 26*6e9e0626SOleksandr Tymoshenko 27*6e9e0626SOleksandr Tymoshenko #define MAX_DEVICE 16 28*6e9e0626SOleksandr Tymoshenko #define MAX_ENDPOINT 16 29*6e9e0626SOleksandr Tymoshenko static int bulk_data_toggle[MAX_DEVICE][MAX_ENDPOINT]; 30*6e9e0626SOleksandr Tymoshenko static int control_data_toggle[MAX_DEVICE][MAX_ENDPOINT]; 31*6e9e0626SOleksandr Tymoshenko 32*6e9e0626SOleksandr Tymoshenko static int root_hub_devnum; 33*6e9e0626SOleksandr Tymoshenko 34*6e9e0626SOleksandr Tymoshenko static struct dwc2_core_regs *regs = 35*6e9e0626SOleksandr Tymoshenko (struct dwc2_core_regs *)CONFIG_USB_DWC2_REG_ADDR; 36*6e9e0626SOleksandr Tymoshenko 37*6e9e0626SOleksandr Tymoshenko /* 38*6e9e0626SOleksandr Tymoshenko * DWC2 IP interface 39*6e9e0626SOleksandr Tymoshenko */ 40*6e9e0626SOleksandr Tymoshenko static int wait_for_bit(void *reg, const uint32_t mask, bool set) 41*6e9e0626SOleksandr Tymoshenko { 42*6e9e0626SOleksandr Tymoshenko unsigned int timeout = 1000000; 43*6e9e0626SOleksandr Tymoshenko uint32_t val; 44*6e9e0626SOleksandr Tymoshenko 45*6e9e0626SOleksandr Tymoshenko while (--timeout) { 46*6e9e0626SOleksandr Tymoshenko val = readl(reg); 47*6e9e0626SOleksandr Tymoshenko if (!set) 48*6e9e0626SOleksandr Tymoshenko val = ~val; 49*6e9e0626SOleksandr Tymoshenko 50*6e9e0626SOleksandr Tymoshenko if ((val & mask) == mask) 51*6e9e0626SOleksandr Tymoshenko return 0; 52*6e9e0626SOleksandr Tymoshenko 53*6e9e0626SOleksandr Tymoshenko udelay(1); 54*6e9e0626SOleksandr Tymoshenko } 55*6e9e0626SOleksandr Tymoshenko 56*6e9e0626SOleksandr Tymoshenko debug("%s: Timeout (reg=%p mask=%08x wait_set=%i)\n", 57*6e9e0626SOleksandr Tymoshenko __func__, reg, mask, set); 58*6e9e0626SOleksandr Tymoshenko 59*6e9e0626SOleksandr Tymoshenko return -ETIMEDOUT; 60*6e9e0626SOleksandr Tymoshenko } 61*6e9e0626SOleksandr Tymoshenko 62*6e9e0626SOleksandr Tymoshenko /* 63*6e9e0626SOleksandr Tymoshenko * Initializes the FSLSPClkSel field of the HCFG register 64*6e9e0626SOleksandr Tymoshenko * depending on the PHY type. 65*6e9e0626SOleksandr Tymoshenko */ 66*6e9e0626SOleksandr Tymoshenko static void init_fslspclksel(struct dwc2_core_regs *regs) 67*6e9e0626SOleksandr Tymoshenko { 68*6e9e0626SOleksandr Tymoshenko uint32_t phyclk; 69*6e9e0626SOleksandr Tymoshenko 70*6e9e0626SOleksandr Tymoshenko #if (CONFIG_DWC2_PHY_TYPE == DWC2_PHY_TYPE_FS) 71*6e9e0626SOleksandr Tymoshenko phyclk = DWC2_HCFG_FSLSPCLKSEL_48_MHZ; /* Full speed PHY */ 72*6e9e0626SOleksandr Tymoshenko #else 73*6e9e0626SOleksandr Tymoshenko /* High speed PHY running at full speed or high speed */ 74*6e9e0626SOleksandr Tymoshenko phyclk = DWC2_HCFG_FSLSPCLKSEL_30_60_MHZ; 75*6e9e0626SOleksandr Tymoshenko #endif 76*6e9e0626SOleksandr Tymoshenko 77*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_ULPI_FS_LS 78*6e9e0626SOleksandr Tymoshenko uint32_t hwcfg2 = readl(®s->ghwcfg2); 79*6e9e0626SOleksandr Tymoshenko uint32_t hval = (ghwcfg2 & DWC2_HWCFG2_HS_PHY_TYPE_MASK) >> 80*6e9e0626SOleksandr Tymoshenko DWC2_HWCFG2_HS_PHY_TYPE_OFFSET; 81*6e9e0626SOleksandr Tymoshenko uint32_t fval = (ghwcfg2 & DWC2_HWCFG2_FS_PHY_TYPE_MASK) >> 82*6e9e0626SOleksandr Tymoshenko DWC2_HWCFG2_FS_PHY_TYPE_OFFSET; 83*6e9e0626SOleksandr Tymoshenko 84*6e9e0626SOleksandr Tymoshenko if (hval == 2 && fval == 1) 85*6e9e0626SOleksandr Tymoshenko phyclk = DWC2_HCFG_FSLSPCLKSEL_48_MHZ; /* Full speed PHY */ 86*6e9e0626SOleksandr Tymoshenko #endif 87*6e9e0626SOleksandr Tymoshenko 88*6e9e0626SOleksandr Tymoshenko clrsetbits_le32(®s->host_regs.hcfg, 89*6e9e0626SOleksandr Tymoshenko DWC2_HCFG_FSLSPCLKSEL_MASK, 90*6e9e0626SOleksandr Tymoshenko phyclk << DWC2_HCFG_FSLSPCLKSEL_OFFSET); 91*6e9e0626SOleksandr Tymoshenko } 92*6e9e0626SOleksandr Tymoshenko 93*6e9e0626SOleksandr Tymoshenko /* 94*6e9e0626SOleksandr Tymoshenko * Flush a Tx FIFO. 95*6e9e0626SOleksandr Tymoshenko * 96*6e9e0626SOleksandr Tymoshenko * @param regs Programming view of DWC_otg controller. 97*6e9e0626SOleksandr Tymoshenko * @param num Tx FIFO to flush. 98*6e9e0626SOleksandr Tymoshenko */ 99*6e9e0626SOleksandr Tymoshenko static void dwc_otg_flush_tx_fifo(struct dwc2_core_regs *regs, const int num) 100*6e9e0626SOleksandr Tymoshenko { 101*6e9e0626SOleksandr Tymoshenko int ret; 102*6e9e0626SOleksandr Tymoshenko 103*6e9e0626SOleksandr Tymoshenko writel(DWC2_GRSTCTL_TXFFLSH | (num << DWC2_GRSTCTL_TXFNUM_OFFSET), 104*6e9e0626SOleksandr Tymoshenko ®s->grstctl); 105*6e9e0626SOleksandr Tymoshenko ret = wait_for_bit(®s->grstctl, DWC2_GRSTCTL_TXFFLSH, 0); 106*6e9e0626SOleksandr Tymoshenko if (ret) 107*6e9e0626SOleksandr Tymoshenko printf("%s: Timeout!\n", __func__); 108*6e9e0626SOleksandr Tymoshenko 109*6e9e0626SOleksandr Tymoshenko /* Wait for 3 PHY Clocks */ 110*6e9e0626SOleksandr Tymoshenko udelay(1); 111*6e9e0626SOleksandr Tymoshenko } 112*6e9e0626SOleksandr Tymoshenko 113*6e9e0626SOleksandr Tymoshenko /* 114*6e9e0626SOleksandr Tymoshenko * Flush Rx FIFO. 115*6e9e0626SOleksandr Tymoshenko * 116*6e9e0626SOleksandr Tymoshenko * @param regs Programming view of DWC_otg controller. 117*6e9e0626SOleksandr Tymoshenko */ 118*6e9e0626SOleksandr Tymoshenko static void dwc_otg_flush_rx_fifo(struct dwc2_core_regs *regs) 119*6e9e0626SOleksandr Tymoshenko { 120*6e9e0626SOleksandr Tymoshenko int ret; 121*6e9e0626SOleksandr Tymoshenko 122*6e9e0626SOleksandr Tymoshenko writel(DWC2_GRSTCTL_RXFFLSH, ®s->grstctl); 123*6e9e0626SOleksandr Tymoshenko ret = wait_for_bit(®s->grstctl, DWC2_GRSTCTL_RXFFLSH, 0); 124*6e9e0626SOleksandr Tymoshenko if (ret) 125*6e9e0626SOleksandr Tymoshenko printf("%s: Timeout!\n", __func__); 126*6e9e0626SOleksandr Tymoshenko 127*6e9e0626SOleksandr Tymoshenko /* Wait for 3 PHY Clocks */ 128*6e9e0626SOleksandr Tymoshenko udelay(1); 129*6e9e0626SOleksandr Tymoshenko } 130*6e9e0626SOleksandr Tymoshenko 131*6e9e0626SOleksandr Tymoshenko /* 132*6e9e0626SOleksandr Tymoshenko * Do core a soft reset of the core. Be careful with this because it 133*6e9e0626SOleksandr Tymoshenko * resets all the internal state machines of the core. 134*6e9e0626SOleksandr Tymoshenko */ 135*6e9e0626SOleksandr Tymoshenko static void dwc_otg_core_reset(struct dwc2_core_regs *regs) 136*6e9e0626SOleksandr Tymoshenko { 137*6e9e0626SOleksandr Tymoshenko int ret; 138*6e9e0626SOleksandr Tymoshenko 139*6e9e0626SOleksandr Tymoshenko /* Wait for AHB master IDLE state. */ 140*6e9e0626SOleksandr Tymoshenko ret = wait_for_bit(®s->grstctl, DWC2_GRSTCTL_AHBIDLE, 1); 141*6e9e0626SOleksandr Tymoshenko if (ret) 142*6e9e0626SOleksandr Tymoshenko printf("%s: Timeout!\n", __func__); 143*6e9e0626SOleksandr Tymoshenko 144*6e9e0626SOleksandr Tymoshenko /* Core Soft Reset */ 145*6e9e0626SOleksandr Tymoshenko writel(DWC2_GRSTCTL_CSFTRST, ®s->grstctl); 146*6e9e0626SOleksandr Tymoshenko ret = wait_for_bit(®s->grstctl, DWC2_GRSTCTL_CSFTRST, 0); 147*6e9e0626SOleksandr Tymoshenko if (ret) 148*6e9e0626SOleksandr Tymoshenko printf("%s: Timeout!\n", __func__); 149*6e9e0626SOleksandr Tymoshenko 150*6e9e0626SOleksandr Tymoshenko /* 151*6e9e0626SOleksandr Tymoshenko * Wait for core to come out of reset. 152*6e9e0626SOleksandr Tymoshenko * NOTE: This long sleep is _very_ important, otherwise the core will 153*6e9e0626SOleksandr Tymoshenko * not stay in host mode after a connector ID change! 154*6e9e0626SOleksandr Tymoshenko */ 155*6e9e0626SOleksandr Tymoshenko mdelay(100); 156*6e9e0626SOleksandr Tymoshenko } 157*6e9e0626SOleksandr Tymoshenko 158*6e9e0626SOleksandr Tymoshenko /* 159*6e9e0626SOleksandr Tymoshenko * This function initializes the DWC_otg controller registers for 160*6e9e0626SOleksandr Tymoshenko * host mode. 161*6e9e0626SOleksandr Tymoshenko * 162*6e9e0626SOleksandr Tymoshenko * This function flushes the Tx and Rx FIFOs and it flushes any entries in the 163*6e9e0626SOleksandr Tymoshenko * request queues. Host channels are reset to ensure that they are ready for 164*6e9e0626SOleksandr Tymoshenko * performing transfers. 165*6e9e0626SOleksandr Tymoshenko * 166*6e9e0626SOleksandr Tymoshenko * @param regs Programming view of DWC_otg controller 167*6e9e0626SOleksandr Tymoshenko * 168*6e9e0626SOleksandr Tymoshenko */ 169*6e9e0626SOleksandr Tymoshenko static void dwc_otg_core_host_init(struct dwc2_core_regs *regs) 170*6e9e0626SOleksandr Tymoshenko { 171*6e9e0626SOleksandr Tymoshenko uint32_t nptxfifosize = 0; 172*6e9e0626SOleksandr Tymoshenko uint32_t ptxfifosize = 0; 173*6e9e0626SOleksandr Tymoshenko uint32_t hprt0 = 0; 174*6e9e0626SOleksandr Tymoshenko int i, ret, num_channels; 175*6e9e0626SOleksandr Tymoshenko 176*6e9e0626SOleksandr Tymoshenko /* Restart the Phy Clock */ 177*6e9e0626SOleksandr Tymoshenko writel(0, ®s->pcgcctl); 178*6e9e0626SOleksandr Tymoshenko 179*6e9e0626SOleksandr Tymoshenko /* Initialize Host Configuration Register */ 180*6e9e0626SOleksandr Tymoshenko init_fslspclksel(regs); 181*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_DFLT_SPEED_FULL 182*6e9e0626SOleksandr Tymoshenko setbits_le32(®s->host_regs.hcfg, DWC2_HCFG_FSLSSUPP); 183*6e9e0626SOleksandr Tymoshenko #endif 184*6e9e0626SOleksandr Tymoshenko 185*6e9e0626SOleksandr Tymoshenko /* Configure data FIFO sizes */ 186*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_ENABLE_DYNAMIC_FIFO 187*6e9e0626SOleksandr Tymoshenko if (readl(®s->ghwcfg2) & DWC2_HWCFG2_DYNAMIC_FIFO) { 188*6e9e0626SOleksandr Tymoshenko /* Rx FIFO */ 189*6e9e0626SOleksandr Tymoshenko writel(CONFIG_DWC2_HOST_RX_FIFO_SIZE, ®s->grxfsiz); 190*6e9e0626SOleksandr Tymoshenko 191*6e9e0626SOleksandr Tymoshenko /* Non-periodic Tx FIFO */ 192*6e9e0626SOleksandr Tymoshenko nptxfifosize |= CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE << 193*6e9e0626SOleksandr Tymoshenko DWC2_FIFOSIZE_DEPTH_OFFSET; 194*6e9e0626SOleksandr Tymoshenko nptxfifosize |= CONFIG_DWC2_HOST_RX_FIFO_SIZE << 195*6e9e0626SOleksandr Tymoshenko DWC2_FIFOSIZE_STARTADDR_OFFSET; 196*6e9e0626SOleksandr Tymoshenko writel(nptxfifosize, ®s->gnptxfsiz); 197*6e9e0626SOleksandr Tymoshenko 198*6e9e0626SOleksandr Tymoshenko /* Periodic Tx FIFO */ 199*6e9e0626SOleksandr Tymoshenko ptxfifosize |= CONFIG_DWC2_HOST_PERIO_TX_FIFO_SIZE << 200*6e9e0626SOleksandr Tymoshenko DWC2_FIFOSIZE_DEPTH_OFFSET; 201*6e9e0626SOleksandr Tymoshenko ptxfifosize |= (CONFIG_DWC2_HOST_RX_FIFO_SIZE + 202*6e9e0626SOleksandr Tymoshenko CONFIG_DWC2_HOST_NPERIO_TX_FIFO_SIZE) << 203*6e9e0626SOleksandr Tymoshenko DWC2_FIFOSIZE_STARTADDR_OFFSET; 204*6e9e0626SOleksandr Tymoshenko writel(ptxfifosize, ®s->hptxfsiz); 205*6e9e0626SOleksandr Tymoshenko } 206*6e9e0626SOleksandr Tymoshenko #endif 207*6e9e0626SOleksandr Tymoshenko 208*6e9e0626SOleksandr Tymoshenko /* Clear Host Set HNP Enable in the OTG Control Register */ 209*6e9e0626SOleksandr Tymoshenko clrbits_le32(®s->gotgctl, DWC2_GOTGCTL_HSTSETHNPEN); 210*6e9e0626SOleksandr Tymoshenko 211*6e9e0626SOleksandr Tymoshenko /* Make sure the FIFOs are flushed. */ 212*6e9e0626SOleksandr Tymoshenko dwc_otg_flush_tx_fifo(regs, 0x10); /* All Tx FIFOs */ 213*6e9e0626SOleksandr Tymoshenko dwc_otg_flush_rx_fifo(regs); 214*6e9e0626SOleksandr Tymoshenko 215*6e9e0626SOleksandr Tymoshenko /* Flush out any leftover queued requests. */ 216*6e9e0626SOleksandr Tymoshenko num_channels = readl(®s->ghwcfg2); 217*6e9e0626SOleksandr Tymoshenko num_channels &= DWC2_HWCFG2_NUM_HOST_CHAN_MASK; 218*6e9e0626SOleksandr Tymoshenko num_channels >>= DWC2_HWCFG2_NUM_HOST_CHAN_OFFSET; 219*6e9e0626SOleksandr Tymoshenko num_channels += 1; 220*6e9e0626SOleksandr Tymoshenko 221*6e9e0626SOleksandr Tymoshenko for (i = 0; i < num_channels; i++) 222*6e9e0626SOleksandr Tymoshenko clrsetbits_le32(®s->hc_regs[i].hcchar, 223*6e9e0626SOleksandr Tymoshenko DWC2_HCCHAR_CHEN | DWC2_HCCHAR_EPDIR, 224*6e9e0626SOleksandr Tymoshenko DWC2_HCCHAR_CHDIS); 225*6e9e0626SOleksandr Tymoshenko 226*6e9e0626SOleksandr Tymoshenko /* Halt all channels to put them into a known state. */ 227*6e9e0626SOleksandr Tymoshenko for (i = 0; i < num_channels; i++) { 228*6e9e0626SOleksandr Tymoshenko clrsetbits_le32(®s->hc_regs[i].hcchar, 229*6e9e0626SOleksandr Tymoshenko DWC2_HCCHAR_EPDIR, 230*6e9e0626SOleksandr Tymoshenko DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS); 231*6e9e0626SOleksandr Tymoshenko ret = wait_for_bit(®s->hc_regs[i].hcchar, 232*6e9e0626SOleksandr Tymoshenko DWC2_HCCHAR_CHEN, 0); 233*6e9e0626SOleksandr Tymoshenko if (ret) 234*6e9e0626SOleksandr Tymoshenko printf("%s: Timeout!\n", __func__); 235*6e9e0626SOleksandr Tymoshenko } 236*6e9e0626SOleksandr Tymoshenko 237*6e9e0626SOleksandr Tymoshenko /* Turn on the vbus power. */ 238*6e9e0626SOleksandr Tymoshenko if (readl(®s->gintsts) & DWC2_GINTSTS_CURMODE_HOST) { 239*6e9e0626SOleksandr Tymoshenko hprt0 = readl(®s->hprt0); 240*6e9e0626SOleksandr Tymoshenko hprt0 &= ~(DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET); 241*6e9e0626SOleksandr Tymoshenko hprt0 &= ~(DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG); 242*6e9e0626SOleksandr Tymoshenko if (!(hprt0 & DWC2_HPRT0_PRTPWR)) { 243*6e9e0626SOleksandr Tymoshenko hprt0 |= DWC2_HPRT0_PRTPWR; 244*6e9e0626SOleksandr Tymoshenko writel(hprt0, ®s->hprt0); 245*6e9e0626SOleksandr Tymoshenko } 246*6e9e0626SOleksandr Tymoshenko } 247*6e9e0626SOleksandr Tymoshenko } 248*6e9e0626SOleksandr Tymoshenko 249*6e9e0626SOleksandr Tymoshenko /* 250*6e9e0626SOleksandr Tymoshenko * This function initializes the DWC_otg controller registers and 251*6e9e0626SOleksandr Tymoshenko * prepares the core for device mode or host mode operation. 252*6e9e0626SOleksandr Tymoshenko * 253*6e9e0626SOleksandr Tymoshenko * @param regs Programming view of the DWC_otg controller 254*6e9e0626SOleksandr Tymoshenko */ 255*6e9e0626SOleksandr Tymoshenko static void dwc_otg_core_init(struct dwc2_core_regs *regs) 256*6e9e0626SOleksandr Tymoshenko { 257*6e9e0626SOleksandr Tymoshenko uint32_t ahbcfg = 0; 258*6e9e0626SOleksandr Tymoshenko uint32_t usbcfg = 0; 259*6e9e0626SOleksandr Tymoshenko uint8_t brst_sz = CONFIG_DWC2_DMA_BURST_SIZE; 260*6e9e0626SOleksandr Tymoshenko 261*6e9e0626SOleksandr Tymoshenko /* Common Initialization */ 262*6e9e0626SOleksandr Tymoshenko usbcfg = readl(®s->gusbcfg); 263*6e9e0626SOleksandr Tymoshenko 264*6e9e0626SOleksandr Tymoshenko /* Program the ULPI External VBUS bit if needed */ 265*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_PHY_ULPI_EXT_VBUS 266*6e9e0626SOleksandr Tymoshenko usbcfg |= DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV; 267*6e9e0626SOleksandr Tymoshenko #else 268*6e9e0626SOleksandr Tymoshenko usbcfg &= ~DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV; 269*6e9e0626SOleksandr Tymoshenko #endif 270*6e9e0626SOleksandr Tymoshenko 271*6e9e0626SOleksandr Tymoshenko /* Set external TS Dline pulsing */ 272*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_TS_DLINE 273*6e9e0626SOleksandr Tymoshenko usbcfg |= DWC2_GUSBCFG_TERM_SEL_DL_PULSE; 274*6e9e0626SOleksandr Tymoshenko #else 275*6e9e0626SOleksandr Tymoshenko usbcfg &= ~DWC2_GUSBCFG_TERM_SEL_DL_PULSE; 276*6e9e0626SOleksandr Tymoshenko #endif 277*6e9e0626SOleksandr Tymoshenko writel(usbcfg, ®s->gusbcfg); 278*6e9e0626SOleksandr Tymoshenko 279*6e9e0626SOleksandr Tymoshenko /* Reset the Controller */ 280*6e9e0626SOleksandr Tymoshenko dwc_otg_core_reset(regs); 281*6e9e0626SOleksandr Tymoshenko 282*6e9e0626SOleksandr Tymoshenko /* 283*6e9e0626SOleksandr Tymoshenko * This programming sequence needs to happen in FS mode before 284*6e9e0626SOleksandr Tymoshenko * any other programming occurs 285*6e9e0626SOleksandr Tymoshenko */ 286*6e9e0626SOleksandr Tymoshenko #if defined(CONFIG_DWC2_DFLT_SPEED_FULL) && \ 287*6e9e0626SOleksandr Tymoshenko (CONFIG_DWC2_PHY_TYPE == DWC2_PHY_TYPE_FS) 288*6e9e0626SOleksandr Tymoshenko /* If FS mode with FS PHY */ 289*6e9e0626SOleksandr Tymoshenko setbits_le32(®s->gusbcfg, DWC2_GUSBCFG_PHYSEL); 290*6e9e0626SOleksandr Tymoshenko 291*6e9e0626SOleksandr Tymoshenko /* Reset after a PHY select */ 292*6e9e0626SOleksandr Tymoshenko dwc_otg_core_reset(regs); 293*6e9e0626SOleksandr Tymoshenko 294*6e9e0626SOleksandr Tymoshenko /* 295*6e9e0626SOleksandr Tymoshenko * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. 296*6e9e0626SOleksandr Tymoshenko * Also do this on HNP Dev/Host mode switches (done in dev_init 297*6e9e0626SOleksandr Tymoshenko * and host_init). 298*6e9e0626SOleksandr Tymoshenko */ 299*6e9e0626SOleksandr Tymoshenko if (readl(®s->gintsts) & DWC2_GINTSTS_CURMODE_HOST) 300*6e9e0626SOleksandr Tymoshenko init_fslspclksel(regs); 301*6e9e0626SOleksandr Tymoshenko 302*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_I2C_ENABLE 303*6e9e0626SOleksandr Tymoshenko /* Program GUSBCFG.OtgUtmifsSel to I2C */ 304*6e9e0626SOleksandr Tymoshenko setbits_le32(®s->gusbcfg, DWC2_GUSBCFG_OTGUTMIFSSEL); 305*6e9e0626SOleksandr Tymoshenko 306*6e9e0626SOleksandr Tymoshenko /* Program GI2CCTL.I2CEn */ 307*6e9e0626SOleksandr Tymoshenko clrsetbits_le32(®s->gi2cctl, DWC2_GI2CCTL_I2CEN | 308*6e9e0626SOleksandr Tymoshenko DWC2_GI2CCTL_I2CDEVADDR_MASK, 309*6e9e0626SOleksandr Tymoshenko 1 << DWC2_GI2CCTL_I2CDEVADDR_OFFSET); 310*6e9e0626SOleksandr Tymoshenko setbits_le32(®s->gi2cctl, DWC2_GI2CCTL_I2CEN); 311*6e9e0626SOleksandr Tymoshenko #endif 312*6e9e0626SOleksandr Tymoshenko 313*6e9e0626SOleksandr Tymoshenko #else 314*6e9e0626SOleksandr Tymoshenko /* High speed PHY. */ 315*6e9e0626SOleksandr Tymoshenko 316*6e9e0626SOleksandr Tymoshenko /* 317*6e9e0626SOleksandr Tymoshenko * HS PHY parameters. These parameters are preserved during 318*6e9e0626SOleksandr Tymoshenko * soft reset so only program the first time. Do a soft reset 319*6e9e0626SOleksandr Tymoshenko * immediately after setting phyif. 320*6e9e0626SOleksandr Tymoshenko */ 321*6e9e0626SOleksandr Tymoshenko usbcfg &= ~(DWC2_GUSBCFG_ULPI_UTMI_SEL | DWC2_GUSBCFG_PHYIF); 322*6e9e0626SOleksandr Tymoshenko usbcfg |= CONFIG_DWC2_PHY_TYPE << DWC2_GUSBCFG_ULPI_UTMI_SEL_OFFSET; 323*6e9e0626SOleksandr Tymoshenko 324*6e9e0626SOleksandr Tymoshenko if (usbcfg & DWC2_GUSBCFG_ULPI_UTMI_SEL) { /* ULPI interface */ 325*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_PHY_ULPI_DDR 326*6e9e0626SOleksandr Tymoshenko usbcfg |= DWC2_GUSBCFG_DDRSEL; 327*6e9e0626SOleksandr Tymoshenko #else 328*6e9e0626SOleksandr Tymoshenko usbcfg &= ~DWC2_GUSBCFG_DDRSEL; 329*6e9e0626SOleksandr Tymoshenko #endif 330*6e9e0626SOleksandr Tymoshenko } else { /* UTMI+ interface */ 331*6e9e0626SOleksandr Tymoshenko #if (CONFIG_DWC2_UTMI_PHY_WIDTH == 16) 332*6e9e0626SOleksandr Tymoshenko usbcfg |= DWC2_GUSBCFG_PHYIF; 333*6e9e0626SOleksandr Tymoshenko #endif 334*6e9e0626SOleksandr Tymoshenko } 335*6e9e0626SOleksandr Tymoshenko 336*6e9e0626SOleksandr Tymoshenko writel(usbcfg, ®s->gusbcfg); 337*6e9e0626SOleksandr Tymoshenko 338*6e9e0626SOleksandr Tymoshenko /* Reset after setting the PHY parameters */ 339*6e9e0626SOleksandr Tymoshenko dwc_otg_core_reset(regs); 340*6e9e0626SOleksandr Tymoshenko #endif 341*6e9e0626SOleksandr Tymoshenko 342*6e9e0626SOleksandr Tymoshenko usbcfg = readl(®s->gusbcfg); 343*6e9e0626SOleksandr Tymoshenko usbcfg &= ~(DWC2_GUSBCFG_ULPI_FSLS | DWC2_GUSBCFG_ULPI_CLK_SUS_M); 344*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_ULPI_FS_LS 345*6e9e0626SOleksandr Tymoshenko uint32_t hwcfg2 = readl(®s->ghwcfg2); 346*6e9e0626SOleksandr Tymoshenko uint32_t hval = (ghwcfg2 & DWC2_HWCFG2_HS_PHY_TYPE_MASK) >> 347*6e9e0626SOleksandr Tymoshenko DWC2_HWCFG2_HS_PHY_TYPE_OFFSET; 348*6e9e0626SOleksandr Tymoshenko uint32_t fval = (ghwcfg2 & DWC2_HWCFG2_FS_PHY_TYPE_MASK) >> 349*6e9e0626SOleksandr Tymoshenko DWC2_HWCFG2_FS_PHY_TYPE_OFFSET; 350*6e9e0626SOleksandr Tymoshenko if (hval == 2 && fval == 1) { 351*6e9e0626SOleksandr Tymoshenko usbcfg |= DWC2_GUSBCFG_ULPI_FSLS; 352*6e9e0626SOleksandr Tymoshenko usbcfg |= DWC2_GUSBCFG_ULPI_CLK_SUS_M; 353*6e9e0626SOleksandr Tymoshenko } 354*6e9e0626SOleksandr Tymoshenko #endif 355*6e9e0626SOleksandr Tymoshenko writel(usbcfg, ®s->gusbcfg); 356*6e9e0626SOleksandr Tymoshenko 357*6e9e0626SOleksandr Tymoshenko /* Program the GAHBCFG Register. */ 358*6e9e0626SOleksandr Tymoshenko switch (readl(®s->ghwcfg2) & DWC2_HWCFG2_ARCHITECTURE_MASK) { 359*6e9e0626SOleksandr Tymoshenko case DWC2_HWCFG2_ARCHITECTURE_SLAVE_ONLY: 360*6e9e0626SOleksandr Tymoshenko break; 361*6e9e0626SOleksandr Tymoshenko case DWC2_HWCFG2_ARCHITECTURE_EXT_DMA: 362*6e9e0626SOleksandr Tymoshenko while (brst_sz > 1) { 363*6e9e0626SOleksandr Tymoshenko ahbcfg |= ahbcfg + (1 << DWC2_GAHBCFG_HBURSTLEN_OFFSET); 364*6e9e0626SOleksandr Tymoshenko ahbcfg &= DWC2_GAHBCFG_HBURSTLEN_MASK; 365*6e9e0626SOleksandr Tymoshenko brst_sz >>= 1; 366*6e9e0626SOleksandr Tymoshenko } 367*6e9e0626SOleksandr Tymoshenko 368*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_DMA_ENABLE 369*6e9e0626SOleksandr Tymoshenko ahbcfg |= DWC2_GAHBCFG_DMAENABLE; 370*6e9e0626SOleksandr Tymoshenko #endif 371*6e9e0626SOleksandr Tymoshenko break; 372*6e9e0626SOleksandr Tymoshenko 373*6e9e0626SOleksandr Tymoshenko case DWC2_HWCFG2_ARCHITECTURE_INT_DMA: 374*6e9e0626SOleksandr Tymoshenko ahbcfg |= DWC2_GAHBCFG_HBURSTLEN_INCR4; 375*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_DMA_ENABLE 376*6e9e0626SOleksandr Tymoshenko ahbcfg |= DWC2_GAHBCFG_DMAENABLE; 377*6e9e0626SOleksandr Tymoshenko #endif 378*6e9e0626SOleksandr Tymoshenko break; 379*6e9e0626SOleksandr Tymoshenko } 380*6e9e0626SOleksandr Tymoshenko 381*6e9e0626SOleksandr Tymoshenko writel(ahbcfg, ®s->gahbcfg); 382*6e9e0626SOleksandr Tymoshenko 383*6e9e0626SOleksandr Tymoshenko /* Program the GUSBCFG register for HNP/SRP. */ 384*6e9e0626SOleksandr Tymoshenko setbits_le32(®s->gusbcfg, DWC2_GUSBCFG_HNPCAP | DWC2_GUSBCFG_SRPCAP); 385*6e9e0626SOleksandr Tymoshenko 386*6e9e0626SOleksandr Tymoshenko #ifdef CONFIG_DWC2_IC_USB_CAP 387*6e9e0626SOleksandr Tymoshenko setbits_le32(®s->gusbcfg, DWC2_GUSBCFG_IC_USB_CAP); 388*6e9e0626SOleksandr Tymoshenko #endif 389*6e9e0626SOleksandr Tymoshenko } 390*6e9e0626SOleksandr Tymoshenko 391*6e9e0626SOleksandr Tymoshenko /* 392*6e9e0626SOleksandr Tymoshenko * Prepares a host channel for transferring packets to/from a specific 393*6e9e0626SOleksandr Tymoshenko * endpoint. The HCCHARn register is set up with the characteristics specified 394*6e9e0626SOleksandr Tymoshenko * in _hc. Host channel interrupts that may need to be serviced while this 395*6e9e0626SOleksandr Tymoshenko * transfer is in progress are enabled. 396*6e9e0626SOleksandr Tymoshenko * 397*6e9e0626SOleksandr Tymoshenko * @param regs Programming view of DWC_otg controller 398*6e9e0626SOleksandr Tymoshenko * @param hc Information needed to initialize the host channel 399*6e9e0626SOleksandr Tymoshenko */ 400*6e9e0626SOleksandr Tymoshenko static void dwc_otg_hc_init(struct dwc2_core_regs *regs, uint8_t hc_num, 401*6e9e0626SOleksandr Tymoshenko uint8_t dev_addr, uint8_t ep_num, uint8_t ep_is_in, 402*6e9e0626SOleksandr Tymoshenko uint8_t ep_type, uint16_t max_packet) 403*6e9e0626SOleksandr Tymoshenko { 404*6e9e0626SOleksandr Tymoshenko struct dwc2_hc_regs *hc_regs = ®s->hc_regs[hc_num]; 405*6e9e0626SOleksandr Tymoshenko const uint32_t hcchar = (dev_addr << DWC2_HCCHAR_DEVADDR_OFFSET) | 406*6e9e0626SOleksandr Tymoshenko (ep_num << DWC2_HCCHAR_EPNUM_OFFSET) | 407*6e9e0626SOleksandr Tymoshenko (ep_is_in << DWC2_HCCHAR_EPDIR_OFFSET) | 408*6e9e0626SOleksandr Tymoshenko (ep_type << DWC2_HCCHAR_EPTYPE_OFFSET) | 409*6e9e0626SOleksandr Tymoshenko (max_packet << DWC2_HCCHAR_MPS_OFFSET); 410*6e9e0626SOleksandr Tymoshenko 411*6e9e0626SOleksandr Tymoshenko /* Clear old interrupt conditions for this host channel. */ 412*6e9e0626SOleksandr Tymoshenko writel(0x3fff, &hc_regs->hcint); 413*6e9e0626SOleksandr Tymoshenko 414*6e9e0626SOleksandr Tymoshenko /* 415*6e9e0626SOleksandr Tymoshenko * Program the HCCHARn register with the endpoint characteristics 416*6e9e0626SOleksandr Tymoshenko * for the current transfer. 417*6e9e0626SOleksandr Tymoshenko */ 418*6e9e0626SOleksandr Tymoshenko writel(hcchar, &hc_regs->hcchar); 419*6e9e0626SOleksandr Tymoshenko 420*6e9e0626SOleksandr Tymoshenko /* Program the HCSPLIT register for SPLITs */ 421*6e9e0626SOleksandr Tymoshenko writel(0, &hc_regs->hcsplt); 422*6e9e0626SOleksandr Tymoshenko } 423*6e9e0626SOleksandr Tymoshenko 424*6e9e0626SOleksandr Tymoshenko /* 425*6e9e0626SOleksandr Tymoshenko * DWC2 to USB API interface 426*6e9e0626SOleksandr Tymoshenko */ 427*6e9e0626SOleksandr Tymoshenko /* Direction: In ; Request: Status */ 428*6e9e0626SOleksandr Tymoshenko static int dwc_otg_submit_rh_msg_in_status(struct usb_device *dev, void *buffer, 429*6e9e0626SOleksandr Tymoshenko int txlen, struct devrequest *cmd) 430*6e9e0626SOleksandr Tymoshenko { 431*6e9e0626SOleksandr Tymoshenko uint32_t hprt0 = 0; 432*6e9e0626SOleksandr Tymoshenko uint32_t port_status = 0; 433*6e9e0626SOleksandr Tymoshenko uint32_t port_change = 0; 434*6e9e0626SOleksandr Tymoshenko int len = 0; 435*6e9e0626SOleksandr Tymoshenko int stat = 0; 436*6e9e0626SOleksandr Tymoshenko 437*6e9e0626SOleksandr Tymoshenko switch (cmd->requesttype & ~USB_DIR_IN) { 438*6e9e0626SOleksandr Tymoshenko case 0: 439*6e9e0626SOleksandr Tymoshenko *(uint16_t *)buffer = cpu_to_le16(1); 440*6e9e0626SOleksandr Tymoshenko len = 2; 441*6e9e0626SOleksandr Tymoshenko break; 442*6e9e0626SOleksandr Tymoshenko case USB_RECIP_INTERFACE: 443*6e9e0626SOleksandr Tymoshenko case USB_RECIP_ENDPOINT: 444*6e9e0626SOleksandr Tymoshenko *(uint16_t *)buffer = cpu_to_le16(0); 445*6e9e0626SOleksandr Tymoshenko len = 2; 446*6e9e0626SOleksandr Tymoshenko break; 447*6e9e0626SOleksandr Tymoshenko case USB_TYPE_CLASS: 448*6e9e0626SOleksandr Tymoshenko *(uint32_t *)buffer = cpu_to_le32(0); 449*6e9e0626SOleksandr Tymoshenko len = 4; 450*6e9e0626SOleksandr Tymoshenko break; 451*6e9e0626SOleksandr Tymoshenko case USB_RECIP_OTHER | USB_TYPE_CLASS: 452*6e9e0626SOleksandr Tymoshenko hprt0 = readl(®s->hprt0); 453*6e9e0626SOleksandr Tymoshenko if (hprt0 & DWC2_HPRT0_PRTCONNSTS) 454*6e9e0626SOleksandr Tymoshenko port_status |= USB_PORT_STAT_CONNECTION; 455*6e9e0626SOleksandr Tymoshenko if (hprt0 & DWC2_HPRT0_PRTENA) 456*6e9e0626SOleksandr Tymoshenko port_status |= USB_PORT_STAT_ENABLE; 457*6e9e0626SOleksandr Tymoshenko if (hprt0 & DWC2_HPRT0_PRTSUSP) 458*6e9e0626SOleksandr Tymoshenko port_status |= USB_PORT_STAT_SUSPEND; 459*6e9e0626SOleksandr Tymoshenko if (hprt0 & DWC2_HPRT0_PRTOVRCURRACT) 460*6e9e0626SOleksandr Tymoshenko port_status |= USB_PORT_STAT_OVERCURRENT; 461*6e9e0626SOleksandr Tymoshenko if (hprt0 & DWC2_HPRT0_PRTRST) 462*6e9e0626SOleksandr Tymoshenko port_status |= USB_PORT_STAT_RESET; 463*6e9e0626SOleksandr Tymoshenko if (hprt0 & DWC2_HPRT0_PRTPWR) 464*6e9e0626SOleksandr Tymoshenko port_status |= USB_PORT_STAT_POWER; 465*6e9e0626SOleksandr Tymoshenko 466*6e9e0626SOleksandr Tymoshenko port_status |= USB_PORT_STAT_HIGH_SPEED; 467*6e9e0626SOleksandr Tymoshenko 468*6e9e0626SOleksandr Tymoshenko if (hprt0 & DWC2_HPRT0_PRTENCHNG) 469*6e9e0626SOleksandr Tymoshenko port_change |= USB_PORT_STAT_C_ENABLE; 470*6e9e0626SOleksandr Tymoshenko if (hprt0 & DWC2_HPRT0_PRTCONNDET) 471*6e9e0626SOleksandr Tymoshenko port_change |= USB_PORT_STAT_C_CONNECTION; 472*6e9e0626SOleksandr Tymoshenko if (hprt0 & DWC2_HPRT0_PRTOVRCURRCHNG) 473*6e9e0626SOleksandr Tymoshenko port_change |= USB_PORT_STAT_C_OVERCURRENT; 474*6e9e0626SOleksandr Tymoshenko 475*6e9e0626SOleksandr Tymoshenko *(uint32_t *)buffer = cpu_to_le32(port_status | 476*6e9e0626SOleksandr Tymoshenko (port_change << 16)); 477*6e9e0626SOleksandr Tymoshenko len = 4; 478*6e9e0626SOleksandr Tymoshenko break; 479*6e9e0626SOleksandr Tymoshenko default: 480*6e9e0626SOleksandr Tymoshenko puts("unsupported root hub command\n"); 481*6e9e0626SOleksandr Tymoshenko stat = USB_ST_STALLED; 482*6e9e0626SOleksandr Tymoshenko } 483*6e9e0626SOleksandr Tymoshenko 484*6e9e0626SOleksandr Tymoshenko dev->act_len = min(len, txlen); 485*6e9e0626SOleksandr Tymoshenko dev->status = stat; 486*6e9e0626SOleksandr Tymoshenko 487*6e9e0626SOleksandr Tymoshenko return stat; 488*6e9e0626SOleksandr Tymoshenko } 489*6e9e0626SOleksandr Tymoshenko 490*6e9e0626SOleksandr Tymoshenko /* Direction: In ; Request: Descriptor */ 491*6e9e0626SOleksandr Tymoshenko static int dwc_otg_submit_rh_msg_in_descriptor(struct usb_device *dev, 492*6e9e0626SOleksandr Tymoshenko void *buffer, int txlen, 493*6e9e0626SOleksandr Tymoshenko struct devrequest *cmd) 494*6e9e0626SOleksandr Tymoshenko { 495*6e9e0626SOleksandr Tymoshenko unsigned char data[32]; 496*6e9e0626SOleksandr Tymoshenko uint32_t dsc; 497*6e9e0626SOleksandr Tymoshenko int len = 0; 498*6e9e0626SOleksandr Tymoshenko int stat = 0; 499*6e9e0626SOleksandr Tymoshenko uint16_t wValue = cpu_to_le16(cmd->value); 500*6e9e0626SOleksandr Tymoshenko uint16_t wLength = cpu_to_le16(cmd->length); 501*6e9e0626SOleksandr Tymoshenko 502*6e9e0626SOleksandr Tymoshenko switch (cmd->requesttype & ~USB_DIR_IN) { 503*6e9e0626SOleksandr Tymoshenko case 0: 504*6e9e0626SOleksandr Tymoshenko switch (wValue & 0xff00) { 505*6e9e0626SOleksandr Tymoshenko case 0x0100: /* device descriptor */ 506*6e9e0626SOleksandr Tymoshenko len = min3(txlen, sizeof(root_hub_dev_des), wLength); 507*6e9e0626SOleksandr Tymoshenko memcpy(buffer, root_hub_dev_des, len); 508*6e9e0626SOleksandr Tymoshenko break; 509*6e9e0626SOleksandr Tymoshenko case 0x0200: /* configuration descriptor */ 510*6e9e0626SOleksandr Tymoshenko len = min3(txlen, sizeof(root_hub_config_des), wLength); 511*6e9e0626SOleksandr Tymoshenko memcpy(buffer, root_hub_config_des, len); 512*6e9e0626SOleksandr Tymoshenko break; 513*6e9e0626SOleksandr Tymoshenko case 0x0300: /* string descriptors */ 514*6e9e0626SOleksandr Tymoshenko switch (wValue & 0xff) { 515*6e9e0626SOleksandr Tymoshenko case 0x00: 516*6e9e0626SOleksandr Tymoshenko len = min3(txlen, sizeof(root_hub_str_index0), 517*6e9e0626SOleksandr Tymoshenko wLength); 518*6e9e0626SOleksandr Tymoshenko memcpy(buffer, root_hub_str_index0, len); 519*6e9e0626SOleksandr Tymoshenko break; 520*6e9e0626SOleksandr Tymoshenko case 0x01: 521*6e9e0626SOleksandr Tymoshenko len = min3(txlen, sizeof(root_hub_str_index1), 522*6e9e0626SOleksandr Tymoshenko wLength); 523*6e9e0626SOleksandr Tymoshenko memcpy(buffer, root_hub_str_index1, len); 524*6e9e0626SOleksandr Tymoshenko break; 525*6e9e0626SOleksandr Tymoshenko } 526*6e9e0626SOleksandr Tymoshenko break; 527*6e9e0626SOleksandr Tymoshenko default: 528*6e9e0626SOleksandr Tymoshenko stat = USB_ST_STALLED; 529*6e9e0626SOleksandr Tymoshenko } 530*6e9e0626SOleksandr Tymoshenko break; 531*6e9e0626SOleksandr Tymoshenko 532*6e9e0626SOleksandr Tymoshenko case USB_TYPE_CLASS: 533*6e9e0626SOleksandr Tymoshenko /* Root port config, set 1 port and nothing else. */ 534*6e9e0626SOleksandr Tymoshenko dsc = 0x00000001; 535*6e9e0626SOleksandr Tymoshenko 536*6e9e0626SOleksandr Tymoshenko data[0] = 9; /* min length; */ 537*6e9e0626SOleksandr Tymoshenko data[1] = 0x29; 538*6e9e0626SOleksandr Tymoshenko data[2] = dsc & RH_A_NDP; 539*6e9e0626SOleksandr Tymoshenko data[3] = 0; 540*6e9e0626SOleksandr Tymoshenko if (dsc & RH_A_PSM) 541*6e9e0626SOleksandr Tymoshenko data[3] |= 0x1; 542*6e9e0626SOleksandr Tymoshenko if (dsc & RH_A_NOCP) 543*6e9e0626SOleksandr Tymoshenko data[3] |= 0x10; 544*6e9e0626SOleksandr Tymoshenko else if (dsc & RH_A_OCPM) 545*6e9e0626SOleksandr Tymoshenko data[3] |= 0x8; 546*6e9e0626SOleksandr Tymoshenko 547*6e9e0626SOleksandr Tymoshenko /* corresponds to data[4-7] */ 548*6e9e0626SOleksandr Tymoshenko data[5] = (dsc & RH_A_POTPGT) >> 24; 549*6e9e0626SOleksandr Tymoshenko data[7] = dsc & RH_B_DR; 550*6e9e0626SOleksandr Tymoshenko if (data[2] < 7) { 551*6e9e0626SOleksandr Tymoshenko data[8] = 0xff; 552*6e9e0626SOleksandr Tymoshenko } else { 553*6e9e0626SOleksandr Tymoshenko data[0] += 2; 554*6e9e0626SOleksandr Tymoshenko data[8] = (dsc & RH_B_DR) >> 8; 555*6e9e0626SOleksandr Tymoshenko data[9] = 0xff; 556*6e9e0626SOleksandr Tymoshenko data[10] = data[9]; 557*6e9e0626SOleksandr Tymoshenko } 558*6e9e0626SOleksandr Tymoshenko 559*6e9e0626SOleksandr Tymoshenko len = min3(txlen, data[0], wLength); 560*6e9e0626SOleksandr Tymoshenko memcpy(buffer, data, len); 561*6e9e0626SOleksandr Tymoshenko break; 562*6e9e0626SOleksandr Tymoshenko default: 563*6e9e0626SOleksandr Tymoshenko puts("unsupported root hub command\n"); 564*6e9e0626SOleksandr Tymoshenko stat = USB_ST_STALLED; 565*6e9e0626SOleksandr Tymoshenko } 566*6e9e0626SOleksandr Tymoshenko 567*6e9e0626SOleksandr Tymoshenko dev->act_len = min(len, txlen); 568*6e9e0626SOleksandr Tymoshenko dev->status = stat; 569*6e9e0626SOleksandr Tymoshenko 570*6e9e0626SOleksandr Tymoshenko return stat; 571*6e9e0626SOleksandr Tymoshenko } 572*6e9e0626SOleksandr Tymoshenko 573*6e9e0626SOleksandr Tymoshenko /* Direction: In ; Request: Configuration */ 574*6e9e0626SOleksandr Tymoshenko static int dwc_otg_submit_rh_msg_in_configuration(struct usb_device *dev, 575*6e9e0626SOleksandr Tymoshenko void *buffer, int txlen, 576*6e9e0626SOleksandr Tymoshenko struct devrequest *cmd) 577*6e9e0626SOleksandr Tymoshenko { 578*6e9e0626SOleksandr Tymoshenko int len = 0; 579*6e9e0626SOleksandr Tymoshenko int stat = 0; 580*6e9e0626SOleksandr Tymoshenko 581*6e9e0626SOleksandr Tymoshenko switch (cmd->requesttype & ~USB_DIR_IN) { 582*6e9e0626SOleksandr Tymoshenko case 0: 583*6e9e0626SOleksandr Tymoshenko *(uint8_t *)buffer = 0x01; 584*6e9e0626SOleksandr Tymoshenko len = 1; 585*6e9e0626SOleksandr Tymoshenko break; 586*6e9e0626SOleksandr Tymoshenko default: 587*6e9e0626SOleksandr Tymoshenko puts("unsupported root hub command\n"); 588*6e9e0626SOleksandr Tymoshenko stat = USB_ST_STALLED; 589*6e9e0626SOleksandr Tymoshenko } 590*6e9e0626SOleksandr Tymoshenko 591*6e9e0626SOleksandr Tymoshenko dev->act_len = min(len, txlen); 592*6e9e0626SOleksandr Tymoshenko dev->status = stat; 593*6e9e0626SOleksandr Tymoshenko 594*6e9e0626SOleksandr Tymoshenko return stat; 595*6e9e0626SOleksandr Tymoshenko } 596*6e9e0626SOleksandr Tymoshenko 597*6e9e0626SOleksandr Tymoshenko /* Direction: In */ 598*6e9e0626SOleksandr Tymoshenko static int dwc_otg_submit_rh_msg_in(struct usb_device *dev, 599*6e9e0626SOleksandr Tymoshenko void *buffer, int txlen, 600*6e9e0626SOleksandr Tymoshenko struct devrequest *cmd) 601*6e9e0626SOleksandr Tymoshenko { 602*6e9e0626SOleksandr Tymoshenko switch (cmd->request) { 603*6e9e0626SOleksandr Tymoshenko case USB_REQ_GET_STATUS: 604*6e9e0626SOleksandr Tymoshenko return dwc_otg_submit_rh_msg_in_status(dev, buffer, 605*6e9e0626SOleksandr Tymoshenko txlen, cmd); 606*6e9e0626SOleksandr Tymoshenko case USB_REQ_GET_DESCRIPTOR: 607*6e9e0626SOleksandr Tymoshenko return dwc_otg_submit_rh_msg_in_descriptor(dev, buffer, 608*6e9e0626SOleksandr Tymoshenko txlen, cmd); 609*6e9e0626SOleksandr Tymoshenko case USB_REQ_GET_CONFIGURATION: 610*6e9e0626SOleksandr Tymoshenko return dwc_otg_submit_rh_msg_in_configuration(dev, buffer, 611*6e9e0626SOleksandr Tymoshenko txlen, cmd); 612*6e9e0626SOleksandr Tymoshenko default: 613*6e9e0626SOleksandr Tymoshenko puts("unsupported root hub command\n"); 614*6e9e0626SOleksandr Tymoshenko return USB_ST_STALLED; 615*6e9e0626SOleksandr Tymoshenko } 616*6e9e0626SOleksandr Tymoshenko } 617*6e9e0626SOleksandr Tymoshenko 618*6e9e0626SOleksandr Tymoshenko /* Direction: Out */ 619*6e9e0626SOleksandr Tymoshenko static int dwc_otg_submit_rh_msg_out(struct usb_device *dev, 620*6e9e0626SOleksandr Tymoshenko void *buffer, int txlen, 621*6e9e0626SOleksandr Tymoshenko struct devrequest *cmd) 622*6e9e0626SOleksandr Tymoshenko { 623*6e9e0626SOleksandr Tymoshenko int len = 0; 624*6e9e0626SOleksandr Tymoshenko int stat = 0; 625*6e9e0626SOleksandr Tymoshenko uint16_t bmrtype_breq = cmd->requesttype | (cmd->request << 8); 626*6e9e0626SOleksandr Tymoshenko uint16_t wValue = cpu_to_le16(cmd->value); 627*6e9e0626SOleksandr Tymoshenko 628*6e9e0626SOleksandr Tymoshenko switch (bmrtype_breq & ~USB_DIR_IN) { 629*6e9e0626SOleksandr Tymoshenko case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_ENDPOINT: 630*6e9e0626SOleksandr Tymoshenko case (USB_REQ_CLEAR_FEATURE << 8) | USB_TYPE_CLASS: 631*6e9e0626SOleksandr Tymoshenko break; 632*6e9e0626SOleksandr Tymoshenko 633*6e9e0626SOleksandr Tymoshenko case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS: 634*6e9e0626SOleksandr Tymoshenko switch (wValue) { 635*6e9e0626SOleksandr Tymoshenko case USB_PORT_FEAT_C_CONNECTION: 636*6e9e0626SOleksandr Tymoshenko setbits_le32(®s->hprt0, DWC2_HPRT0_PRTCONNDET); 637*6e9e0626SOleksandr Tymoshenko break; 638*6e9e0626SOleksandr Tymoshenko } 639*6e9e0626SOleksandr Tymoshenko break; 640*6e9e0626SOleksandr Tymoshenko 641*6e9e0626SOleksandr Tymoshenko case (USB_REQ_SET_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS: 642*6e9e0626SOleksandr Tymoshenko switch (wValue) { 643*6e9e0626SOleksandr Tymoshenko case USB_PORT_FEAT_SUSPEND: 644*6e9e0626SOleksandr Tymoshenko break; 645*6e9e0626SOleksandr Tymoshenko 646*6e9e0626SOleksandr Tymoshenko case USB_PORT_FEAT_RESET: 647*6e9e0626SOleksandr Tymoshenko clrsetbits_le32(®s->hprt0, DWC2_HPRT0_PRTENA | 648*6e9e0626SOleksandr Tymoshenko DWC2_HPRT0_PRTCONNDET | 649*6e9e0626SOleksandr Tymoshenko DWC2_HPRT0_PRTENCHNG | 650*6e9e0626SOleksandr Tymoshenko DWC2_HPRT0_PRTOVRCURRCHNG, 651*6e9e0626SOleksandr Tymoshenko DWC2_HPRT0_PRTRST); 652*6e9e0626SOleksandr Tymoshenko mdelay(50); 653*6e9e0626SOleksandr Tymoshenko clrbits_le32(®s->hprt0, DWC2_HPRT0_PRTRST); 654*6e9e0626SOleksandr Tymoshenko break; 655*6e9e0626SOleksandr Tymoshenko 656*6e9e0626SOleksandr Tymoshenko case USB_PORT_FEAT_POWER: 657*6e9e0626SOleksandr Tymoshenko clrsetbits_le32(®s->hprt0, DWC2_HPRT0_PRTENA | 658*6e9e0626SOleksandr Tymoshenko DWC2_HPRT0_PRTCONNDET | 659*6e9e0626SOleksandr Tymoshenko DWC2_HPRT0_PRTENCHNG | 660*6e9e0626SOleksandr Tymoshenko DWC2_HPRT0_PRTOVRCURRCHNG, 661*6e9e0626SOleksandr Tymoshenko DWC2_HPRT0_PRTRST); 662*6e9e0626SOleksandr Tymoshenko break; 663*6e9e0626SOleksandr Tymoshenko 664*6e9e0626SOleksandr Tymoshenko case USB_PORT_FEAT_ENABLE: 665*6e9e0626SOleksandr Tymoshenko break; 666*6e9e0626SOleksandr Tymoshenko } 667*6e9e0626SOleksandr Tymoshenko break; 668*6e9e0626SOleksandr Tymoshenko case (USB_REQ_SET_ADDRESS << 8): 669*6e9e0626SOleksandr Tymoshenko root_hub_devnum = wValue; 670*6e9e0626SOleksandr Tymoshenko break; 671*6e9e0626SOleksandr Tymoshenko case (USB_REQ_SET_CONFIGURATION << 8): 672*6e9e0626SOleksandr Tymoshenko break; 673*6e9e0626SOleksandr Tymoshenko default: 674*6e9e0626SOleksandr Tymoshenko puts("unsupported root hub command\n"); 675*6e9e0626SOleksandr Tymoshenko stat = USB_ST_STALLED; 676*6e9e0626SOleksandr Tymoshenko } 677*6e9e0626SOleksandr Tymoshenko 678*6e9e0626SOleksandr Tymoshenko len = min(len, txlen); 679*6e9e0626SOleksandr Tymoshenko 680*6e9e0626SOleksandr Tymoshenko dev->act_len = len; 681*6e9e0626SOleksandr Tymoshenko dev->status = stat; 682*6e9e0626SOleksandr Tymoshenko 683*6e9e0626SOleksandr Tymoshenko return stat; 684*6e9e0626SOleksandr Tymoshenko } 685*6e9e0626SOleksandr Tymoshenko 686*6e9e0626SOleksandr Tymoshenko static int dwc_otg_submit_rh_msg(struct usb_device *dev, unsigned long pipe, 687*6e9e0626SOleksandr Tymoshenko void *buffer, int txlen, 688*6e9e0626SOleksandr Tymoshenko struct devrequest *cmd) 689*6e9e0626SOleksandr Tymoshenko { 690*6e9e0626SOleksandr Tymoshenko int stat = 0; 691*6e9e0626SOleksandr Tymoshenko 692*6e9e0626SOleksandr Tymoshenko if (usb_pipeint(pipe)) { 693*6e9e0626SOleksandr Tymoshenko puts("Root-Hub submit IRQ: NOT implemented\n"); 694*6e9e0626SOleksandr Tymoshenko return 0; 695*6e9e0626SOleksandr Tymoshenko } 696*6e9e0626SOleksandr Tymoshenko 697*6e9e0626SOleksandr Tymoshenko if (cmd->requesttype & USB_DIR_IN) 698*6e9e0626SOleksandr Tymoshenko stat = dwc_otg_submit_rh_msg_in(dev, buffer, txlen, cmd); 699*6e9e0626SOleksandr Tymoshenko else 700*6e9e0626SOleksandr Tymoshenko stat = dwc_otg_submit_rh_msg_out(dev, buffer, txlen, cmd); 701*6e9e0626SOleksandr Tymoshenko 702*6e9e0626SOleksandr Tymoshenko mdelay(1); 703*6e9e0626SOleksandr Tymoshenko 704*6e9e0626SOleksandr Tymoshenko return stat; 705*6e9e0626SOleksandr Tymoshenko } 706*6e9e0626SOleksandr Tymoshenko 707*6e9e0626SOleksandr Tymoshenko /* U-Boot USB transmission interface */ 708*6e9e0626SOleksandr Tymoshenko int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, 709*6e9e0626SOleksandr Tymoshenko int len) 710*6e9e0626SOleksandr Tymoshenko { 711*6e9e0626SOleksandr Tymoshenko int devnum = usb_pipedevice(pipe); 712*6e9e0626SOleksandr Tymoshenko int ep = usb_pipeendpoint(pipe); 713*6e9e0626SOleksandr Tymoshenko int max = usb_maxpacket(dev, pipe); 714*6e9e0626SOleksandr Tymoshenko int done = 0; 715*6e9e0626SOleksandr Tymoshenko uint32_t hctsiz, sub, tmp; 716*6e9e0626SOleksandr Tymoshenko struct dwc2_hc_regs *hc_regs = ®s->hc_regs[DWC2_HC_CHANNEL]; 717*6e9e0626SOleksandr Tymoshenko uint32_t hcint; 718*6e9e0626SOleksandr Tymoshenko uint32_t xfer_len; 719*6e9e0626SOleksandr Tymoshenko uint32_t num_packets; 720*6e9e0626SOleksandr Tymoshenko int stop_transfer = 0; 721*6e9e0626SOleksandr Tymoshenko unsigned int timeout = 1000000; 722*6e9e0626SOleksandr Tymoshenko 723*6e9e0626SOleksandr Tymoshenko if (devnum == root_hub_devnum) { 724*6e9e0626SOleksandr Tymoshenko dev->status = 0; 725*6e9e0626SOleksandr Tymoshenko return -EINVAL; 726*6e9e0626SOleksandr Tymoshenko } 727*6e9e0626SOleksandr Tymoshenko 728*6e9e0626SOleksandr Tymoshenko if (len > DWC2_DATA_BUF_SIZE) { 729*6e9e0626SOleksandr Tymoshenko printf("%s: %d is more then available buffer size (%d)\n", 730*6e9e0626SOleksandr Tymoshenko __func__, len, DWC2_DATA_BUF_SIZE); 731*6e9e0626SOleksandr Tymoshenko dev->status = 0; 732*6e9e0626SOleksandr Tymoshenko dev->act_len = 0; 733*6e9e0626SOleksandr Tymoshenko return -EINVAL; 734*6e9e0626SOleksandr Tymoshenko } 735*6e9e0626SOleksandr Tymoshenko 736*6e9e0626SOleksandr Tymoshenko while ((done < len) && !stop_transfer) { 737*6e9e0626SOleksandr Tymoshenko /* Initialize channel */ 738*6e9e0626SOleksandr Tymoshenko dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, devnum, ep, 739*6e9e0626SOleksandr Tymoshenko usb_pipein(pipe), DWC2_HCCHAR_EPTYPE_BULK, max); 740*6e9e0626SOleksandr Tymoshenko 741*6e9e0626SOleksandr Tymoshenko xfer_len = len - done; 742*6e9e0626SOleksandr Tymoshenko /* Make sure that xfer_len is a multiple of max packet size. */ 743*6e9e0626SOleksandr Tymoshenko if (xfer_len > CONFIG_DWC2_MAX_TRANSFER_SIZE) 744*6e9e0626SOleksandr Tymoshenko xfer_len = CONFIG_DWC2_MAX_TRANSFER_SIZE - max + 1; 745*6e9e0626SOleksandr Tymoshenko 746*6e9e0626SOleksandr Tymoshenko if (xfer_len > 0) { 747*6e9e0626SOleksandr Tymoshenko num_packets = (xfer_len + max - 1) / max; 748*6e9e0626SOleksandr Tymoshenko if (num_packets > CONFIG_DWC2_MAX_PACKET_COUNT) { 749*6e9e0626SOleksandr Tymoshenko num_packets = CONFIG_DWC2_MAX_PACKET_COUNT; 750*6e9e0626SOleksandr Tymoshenko xfer_len = num_packets * max; 751*6e9e0626SOleksandr Tymoshenko } 752*6e9e0626SOleksandr Tymoshenko } else { 753*6e9e0626SOleksandr Tymoshenko num_packets = 1; 754*6e9e0626SOleksandr Tymoshenko } 755*6e9e0626SOleksandr Tymoshenko 756*6e9e0626SOleksandr Tymoshenko if (usb_pipein(pipe)) 757*6e9e0626SOleksandr Tymoshenko xfer_len = num_packets * max; 758*6e9e0626SOleksandr Tymoshenko 759*6e9e0626SOleksandr Tymoshenko writel((xfer_len << DWC2_HCTSIZ_XFERSIZE_OFFSET) | 760*6e9e0626SOleksandr Tymoshenko (num_packets << DWC2_HCTSIZ_PKTCNT_OFFSET) | 761*6e9e0626SOleksandr Tymoshenko (bulk_data_toggle[devnum][ep] << 762*6e9e0626SOleksandr Tymoshenko DWC2_HCTSIZ_PID_OFFSET), 763*6e9e0626SOleksandr Tymoshenko &hc_regs->hctsiz); 764*6e9e0626SOleksandr Tymoshenko 765*6e9e0626SOleksandr Tymoshenko memcpy(aligned_buffer, (char *)buffer + done, len - done); 766*6e9e0626SOleksandr Tymoshenko writel((uint32_t)aligned_buffer, &hc_regs->hcdma); 767*6e9e0626SOleksandr Tymoshenko 768*6e9e0626SOleksandr Tymoshenko /* Set host channel enable after all other setup is complete. */ 769*6e9e0626SOleksandr Tymoshenko clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK | 770*6e9e0626SOleksandr Tymoshenko DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS, 771*6e9e0626SOleksandr Tymoshenko (1 << DWC2_HCCHAR_MULTICNT_OFFSET) | 772*6e9e0626SOleksandr Tymoshenko DWC2_HCCHAR_CHEN); 773*6e9e0626SOleksandr Tymoshenko 774*6e9e0626SOleksandr Tymoshenko while (1) { 775*6e9e0626SOleksandr Tymoshenko hcint = readl(&hc_regs->hcint); 776*6e9e0626SOleksandr Tymoshenko 777*6e9e0626SOleksandr Tymoshenko if (!(hcint & DWC2_HCINT_CHHLTD)) 778*6e9e0626SOleksandr Tymoshenko continue; 779*6e9e0626SOleksandr Tymoshenko 780*6e9e0626SOleksandr Tymoshenko if (hcint & DWC2_HCINT_XFERCOMP) { 781*6e9e0626SOleksandr Tymoshenko hctsiz = readl(&hc_regs->hctsiz); 782*6e9e0626SOleksandr Tymoshenko done += xfer_len; 783*6e9e0626SOleksandr Tymoshenko 784*6e9e0626SOleksandr Tymoshenko sub = hctsiz & DWC2_HCTSIZ_XFERSIZE_MASK; 785*6e9e0626SOleksandr Tymoshenko sub >>= DWC2_HCTSIZ_XFERSIZE_OFFSET; 786*6e9e0626SOleksandr Tymoshenko 787*6e9e0626SOleksandr Tymoshenko if (usb_pipein(pipe)) { 788*6e9e0626SOleksandr Tymoshenko done -= sub; 789*6e9e0626SOleksandr Tymoshenko if (hctsiz & DWC2_HCTSIZ_XFERSIZE_MASK) 790*6e9e0626SOleksandr Tymoshenko stop_transfer = 1; 791*6e9e0626SOleksandr Tymoshenko } 792*6e9e0626SOleksandr Tymoshenko 793*6e9e0626SOleksandr Tymoshenko tmp = hctsiz & DWC2_HCTSIZ_PID_MASK; 794*6e9e0626SOleksandr Tymoshenko tmp >>= DWC2_HCTSIZ_PID_OFFSET; 795*6e9e0626SOleksandr Tymoshenko if (tmp == DWC2_HC_PID_DATA1) { 796*6e9e0626SOleksandr Tymoshenko bulk_data_toggle[devnum][ep] = 797*6e9e0626SOleksandr Tymoshenko DWC2_HC_PID_DATA1; 798*6e9e0626SOleksandr Tymoshenko } else { 799*6e9e0626SOleksandr Tymoshenko bulk_data_toggle[devnum][ep] = 800*6e9e0626SOleksandr Tymoshenko DWC2_HC_PID_DATA0; 801*6e9e0626SOleksandr Tymoshenko } 802*6e9e0626SOleksandr Tymoshenko break; 803*6e9e0626SOleksandr Tymoshenko } 804*6e9e0626SOleksandr Tymoshenko 805*6e9e0626SOleksandr Tymoshenko if (hcint & DWC2_HCINT_STALL) { 806*6e9e0626SOleksandr Tymoshenko puts("DWC OTG: Channel halted\n"); 807*6e9e0626SOleksandr Tymoshenko bulk_data_toggle[devnum][ep] = 808*6e9e0626SOleksandr Tymoshenko DWC2_HC_PID_DATA0; 809*6e9e0626SOleksandr Tymoshenko 810*6e9e0626SOleksandr Tymoshenko stop_transfer = 1; 811*6e9e0626SOleksandr Tymoshenko break; 812*6e9e0626SOleksandr Tymoshenko } 813*6e9e0626SOleksandr Tymoshenko 814*6e9e0626SOleksandr Tymoshenko if (!--timeout) { 815*6e9e0626SOleksandr Tymoshenko printf("%s: Timeout!\n", __func__); 816*6e9e0626SOleksandr Tymoshenko break; 817*6e9e0626SOleksandr Tymoshenko } 818*6e9e0626SOleksandr Tymoshenko } 819*6e9e0626SOleksandr Tymoshenko } 820*6e9e0626SOleksandr Tymoshenko 821*6e9e0626SOleksandr Tymoshenko if (done && usb_pipein(pipe)) 822*6e9e0626SOleksandr Tymoshenko memcpy(buffer, aligned_buffer, done); 823*6e9e0626SOleksandr Tymoshenko 824*6e9e0626SOleksandr Tymoshenko writel(0, &hc_regs->hcintmsk); 825*6e9e0626SOleksandr Tymoshenko writel(0xFFFFFFFF, &hc_regs->hcint); 826*6e9e0626SOleksandr Tymoshenko 827*6e9e0626SOleksandr Tymoshenko dev->status = 0; 828*6e9e0626SOleksandr Tymoshenko dev->act_len = done; 829*6e9e0626SOleksandr Tymoshenko 830*6e9e0626SOleksandr Tymoshenko return 0; 831*6e9e0626SOleksandr Tymoshenko } 832*6e9e0626SOleksandr Tymoshenko 833*6e9e0626SOleksandr Tymoshenko int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, 834*6e9e0626SOleksandr Tymoshenko int len, struct devrequest *setup) 835*6e9e0626SOleksandr Tymoshenko { 836*6e9e0626SOleksandr Tymoshenko struct dwc2_hc_regs *hc_regs = ®s->hc_regs[DWC2_HC_CHANNEL]; 837*6e9e0626SOleksandr Tymoshenko int done = 0; 838*6e9e0626SOleksandr Tymoshenko int devnum = usb_pipedevice(pipe); 839*6e9e0626SOleksandr Tymoshenko int ep = usb_pipeendpoint(pipe); 840*6e9e0626SOleksandr Tymoshenko int max = usb_maxpacket(dev, pipe); 841*6e9e0626SOleksandr Tymoshenko uint32_t hctsiz = 0, sub, tmp, ret; 842*6e9e0626SOleksandr Tymoshenko uint32_t hcint; 843*6e9e0626SOleksandr Tymoshenko const uint32_t hcint_comp_hlt_ack = DWC2_HCINT_XFERCOMP | 844*6e9e0626SOleksandr Tymoshenko DWC2_HCINT_CHHLTD | DWC2_HCINT_ACK; 845*6e9e0626SOleksandr Tymoshenko unsigned int timeout = 1000000; 846*6e9e0626SOleksandr Tymoshenko 847*6e9e0626SOleksandr Tymoshenko /* For CONTROL endpoint pid should start with DATA1 */ 848*6e9e0626SOleksandr Tymoshenko int status_direction; 849*6e9e0626SOleksandr Tymoshenko 850*6e9e0626SOleksandr Tymoshenko if (devnum == root_hub_devnum) { 851*6e9e0626SOleksandr Tymoshenko dev->status = 0; 852*6e9e0626SOleksandr Tymoshenko dev->speed = USB_SPEED_HIGH; 853*6e9e0626SOleksandr Tymoshenko return dwc_otg_submit_rh_msg(dev, pipe, buffer, len, setup); 854*6e9e0626SOleksandr Tymoshenko } 855*6e9e0626SOleksandr Tymoshenko 856*6e9e0626SOleksandr Tymoshenko if (len > DWC2_DATA_BUF_SIZE) { 857*6e9e0626SOleksandr Tymoshenko printf("%s: %d is more then available buffer size(%d)\n", 858*6e9e0626SOleksandr Tymoshenko __func__, len, DWC2_DATA_BUF_SIZE); 859*6e9e0626SOleksandr Tymoshenko dev->status = 0; 860*6e9e0626SOleksandr Tymoshenko dev->act_len = 0; 861*6e9e0626SOleksandr Tymoshenko return -EINVAL; 862*6e9e0626SOleksandr Tymoshenko } 863*6e9e0626SOleksandr Tymoshenko 864*6e9e0626SOleksandr Tymoshenko /* Initialize channel, OUT for setup buffer */ 865*6e9e0626SOleksandr Tymoshenko dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, devnum, ep, 0, 866*6e9e0626SOleksandr Tymoshenko DWC2_HCCHAR_EPTYPE_CONTROL, max); 867*6e9e0626SOleksandr Tymoshenko 868*6e9e0626SOleksandr Tymoshenko /* SETUP stage */ 869*6e9e0626SOleksandr Tymoshenko writel((8 << DWC2_HCTSIZ_XFERSIZE_OFFSET) | 870*6e9e0626SOleksandr Tymoshenko (1 << DWC2_HCTSIZ_PKTCNT_OFFSET) | 871*6e9e0626SOleksandr Tymoshenko (DWC2_HC_PID_SETUP << DWC2_HCTSIZ_PID_OFFSET), 872*6e9e0626SOleksandr Tymoshenko &hc_regs->hctsiz); 873*6e9e0626SOleksandr Tymoshenko 874*6e9e0626SOleksandr Tymoshenko writel((uint32_t)setup, &hc_regs->hcdma); 875*6e9e0626SOleksandr Tymoshenko 876*6e9e0626SOleksandr Tymoshenko /* Set host channel enable after all other setup is complete. */ 877*6e9e0626SOleksandr Tymoshenko clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK | 878*6e9e0626SOleksandr Tymoshenko DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS, 879*6e9e0626SOleksandr Tymoshenko (1 << DWC2_HCCHAR_MULTICNT_OFFSET) | DWC2_HCCHAR_CHEN); 880*6e9e0626SOleksandr Tymoshenko 881*6e9e0626SOleksandr Tymoshenko ret = wait_for_bit(&hc_regs->hcint, DWC2_HCINT_CHHLTD, 1); 882*6e9e0626SOleksandr Tymoshenko if (ret) 883*6e9e0626SOleksandr Tymoshenko printf("%s: Timeout!\n", __func__); 884*6e9e0626SOleksandr Tymoshenko 885*6e9e0626SOleksandr Tymoshenko hcint = readl(&hc_regs->hcint); 886*6e9e0626SOleksandr Tymoshenko 887*6e9e0626SOleksandr Tymoshenko if (!(hcint & DWC2_HCINT_CHHLTD) || !(hcint & DWC2_HCINT_XFERCOMP)) { 888*6e9e0626SOleksandr Tymoshenko printf("%s: Error (HCINT=%08x)\n", __func__, hcint); 889*6e9e0626SOleksandr Tymoshenko dev->status = 0; 890*6e9e0626SOleksandr Tymoshenko dev->act_len = 0; 891*6e9e0626SOleksandr Tymoshenko return -EINVAL; 892*6e9e0626SOleksandr Tymoshenko } 893*6e9e0626SOleksandr Tymoshenko 894*6e9e0626SOleksandr Tymoshenko /* Clear interrupts */ 895*6e9e0626SOleksandr Tymoshenko writel(0, &hc_regs->hcintmsk); 896*6e9e0626SOleksandr Tymoshenko writel(0xFFFFFFFF, &hc_regs->hcint); 897*6e9e0626SOleksandr Tymoshenko 898*6e9e0626SOleksandr Tymoshenko if (buffer) { 899*6e9e0626SOleksandr Tymoshenko /* DATA stage */ 900*6e9e0626SOleksandr Tymoshenko dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, devnum, ep, 901*6e9e0626SOleksandr Tymoshenko usb_pipein(pipe), 902*6e9e0626SOleksandr Tymoshenko DWC2_HCCHAR_EPTYPE_CONTROL, max); 903*6e9e0626SOleksandr Tymoshenko 904*6e9e0626SOleksandr Tymoshenko /* TODO: check if len < 64 */ 905*6e9e0626SOleksandr Tymoshenko control_data_toggle[devnum][ep] = DWC2_HC_PID_DATA1; 906*6e9e0626SOleksandr Tymoshenko writel((len << DWC2_HCTSIZ_XFERSIZE_OFFSET) | 907*6e9e0626SOleksandr Tymoshenko (1 << DWC2_HCTSIZ_PKTCNT_OFFSET) | 908*6e9e0626SOleksandr Tymoshenko (control_data_toggle[devnum][ep] << 909*6e9e0626SOleksandr Tymoshenko DWC2_HCTSIZ_PID_OFFSET), 910*6e9e0626SOleksandr Tymoshenko &hc_regs->hctsiz); 911*6e9e0626SOleksandr Tymoshenko 912*6e9e0626SOleksandr Tymoshenko writel((uint32_t)buffer, &hc_regs->hcdma); 913*6e9e0626SOleksandr Tymoshenko 914*6e9e0626SOleksandr Tymoshenko /* Set host channel enable after all other setup is complete */ 915*6e9e0626SOleksandr Tymoshenko clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK | 916*6e9e0626SOleksandr Tymoshenko DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS, 917*6e9e0626SOleksandr Tymoshenko (1 << DWC2_HCCHAR_MULTICNT_OFFSET) | 918*6e9e0626SOleksandr Tymoshenko DWC2_HCCHAR_CHEN); 919*6e9e0626SOleksandr Tymoshenko 920*6e9e0626SOleksandr Tymoshenko while (1) { 921*6e9e0626SOleksandr Tymoshenko hcint = readl(&hc_regs->hcint); 922*6e9e0626SOleksandr Tymoshenko if (!(hcint & DWC2_HCINT_CHHLTD)) 923*6e9e0626SOleksandr Tymoshenko continue; 924*6e9e0626SOleksandr Tymoshenko 925*6e9e0626SOleksandr Tymoshenko if (hcint & DWC2_HCINT_XFERCOMP) { 926*6e9e0626SOleksandr Tymoshenko hctsiz = readl(&hc_regs->hctsiz); 927*6e9e0626SOleksandr Tymoshenko done = len; 928*6e9e0626SOleksandr Tymoshenko 929*6e9e0626SOleksandr Tymoshenko sub = hctsiz & DWC2_HCTSIZ_XFERSIZE_MASK; 930*6e9e0626SOleksandr Tymoshenko sub >>= DWC2_HCTSIZ_XFERSIZE_OFFSET; 931*6e9e0626SOleksandr Tymoshenko 932*6e9e0626SOleksandr Tymoshenko if (usb_pipein(pipe)) 933*6e9e0626SOleksandr Tymoshenko done -= sub; 934*6e9e0626SOleksandr Tymoshenko } 935*6e9e0626SOleksandr Tymoshenko 936*6e9e0626SOleksandr Tymoshenko if (hcint & DWC2_HCINT_ACK) { 937*6e9e0626SOleksandr Tymoshenko tmp = hctsiz & DWC2_HCTSIZ_PID_MASK; 938*6e9e0626SOleksandr Tymoshenko tmp >>= DWC2_HCTSIZ_PID_OFFSET; 939*6e9e0626SOleksandr Tymoshenko if (tmp == DWC2_HC_PID_DATA0) { 940*6e9e0626SOleksandr Tymoshenko control_data_toggle[devnum][ep] = 941*6e9e0626SOleksandr Tymoshenko DWC2_HC_PID_DATA0; 942*6e9e0626SOleksandr Tymoshenko } else { 943*6e9e0626SOleksandr Tymoshenko control_data_toggle[devnum][ep] = 944*6e9e0626SOleksandr Tymoshenko DWC2_HC_PID_DATA1; 945*6e9e0626SOleksandr Tymoshenko } 946*6e9e0626SOleksandr Tymoshenko } 947*6e9e0626SOleksandr Tymoshenko 948*6e9e0626SOleksandr Tymoshenko if (hcint != hcint_comp_hlt_ack) { 949*6e9e0626SOleksandr Tymoshenko printf("%s: Error (HCINT=%08x)\n", 950*6e9e0626SOleksandr Tymoshenko __func__, hcint); 951*6e9e0626SOleksandr Tymoshenko goto out; 952*6e9e0626SOleksandr Tymoshenko } 953*6e9e0626SOleksandr Tymoshenko 954*6e9e0626SOleksandr Tymoshenko if (!--timeout) { 955*6e9e0626SOleksandr Tymoshenko printf("%s: Timeout!\n", __func__); 956*6e9e0626SOleksandr Tymoshenko goto out; 957*6e9e0626SOleksandr Tymoshenko } 958*6e9e0626SOleksandr Tymoshenko 959*6e9e0626SOleksandr Tymoshenko break; 960*6e9e0626SOleksandr Tymoshenko } 961*6e9e0626SOleksandr Tymoshenko } /* End of DATA stage */ 962*6e9e0626SOleksandr Tymoshenko 963*6e9e0626SOleksandr Tymoshenko /* STATUS stage */ 964*6e9e0626SOleksandr Tymoshenko if ((len == 0) || usb_pipeout(pipe)) 965*6e9e0626SOleksandr Tymoshenko status_direction = 1; 966*6e9e0626SOleksandr Tymoshenko else 967*6e9e0626SOleksandr Tymoshenko status_direction = 0; 968*6e9e0626SOleksandr Tymoshenko 969*6e9e0626SOleksandr Tymoshenko dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, devnum, ep, 970*6e9e0626SOleksandr Tymoshenko status_direction, DWC2_HCCHAR_EPTYPE_CONTROL, max); 971*6e9e0626SOleksandr Tymoshenko 972*6e9e0626SOleksandr Tymoshenko writel((1 << DWC2_HCTSIZ_PKTCNT_OFFSET) | 973*6e9e0626SOleksandr Tymoshenko (DWC2_HC_PID_DATA1 << DWC2_HCTSIZ_PID_OFFSET), 974*6e9e0626SOleksandr Tymoshenko &hc_regs->hctsiz); 975*6e9e0626SOleksandr Tymoshenko 976*6e9e0626SOleksandr Tymoshenko writel((uint32_t)status_buffer, &hc_regs->hcdma); 977*6e9e0626SOleksandr Tymoshenko 978*6e9e0626SOleksandr Tymoshenko /* Set host channel enable after all other setup is complete. */ 979*6e9e0626SOleksandr Tymoshenko clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK | 980*6e9e0626SOleksandr Tymoshenko DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS, 981*6e9e0626SOleksandr Tymoshenko (1 << DWC2_HCCHAR_MULTICNT_OFFSET) | DWC2_HCCHAR_CHEN); 982*6e9e0626SOleksandr Tymoshenko 983*6e9e0626SOleksandr Tymoshenko while (1) { 984*6e9e0626SOleksandr Tymoshenko hcint = readl(&hc_regs->hcint); 985*6e9e0626SOleksandr Tymoshenko if (hcint & DWC2_HCINT_CHHLTD) 986*6e9e0626SOleksandr Tymoshenko break; 987*6e9e0626SOleksandr Tymoshenko } 988*6e9e0626SOleksandr Tymoshenko 989*6e9e0626SOleksandr Tymoshenko if (hcint != hcint_comp_hlt_ack) 990*6e9e0626SOleksandr Tymoshenko printf("%s: Error (HCINT=%08x)\n", __func__, hcint); 991*6e9e0626SOleksandr Tymoshenko 992*6e9e0626SOleksandr Tymoshenko out: 993*6e9e0626SOleksandr Tymoshenko dev->act_len = done; 994*6e9e0626SOleksandr Tymoshenko dev->status = 0; 995*6e9e0626SOleksandr Tymoshenko 996*6e9e0626SOleksandr Tymoshenko return done; 997*6e9e0626SOleksandr Tymoshenko } 998*6e9e0626SOleksandr Tymoshenko 999*6e9e0626SOleksandr Tymoshenko int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, 1000*6e9e0626SOleksandr Tymoshenko int len, int interval) 1001*6e9e0626SOleksandr Tymoshenko { 1002*6e9e0626SOleksandr Tymoshenko printf("dev = %p pipe = %#lx buf = %p size = %d int = %d\n", 1003*6e9e0626SOleksandr Tymoshenko dev, pipe, buffer, len, interval); 1004*6e9e0626SOleksandr Tymoshenko return -ENOSYS; 1005*6e9e0626SOleksandr Tymoshenko } 1006*6e9e0626SOleksandr Tymoshenko 1007*6e9e0626SOleksandr Tymoshenko /* U-Boot USB control interface */ 1008*6e9e0626SOleksandr Tymoshenko int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) 1009*6e9e0626SOleksandr Tymoshenko { 1010*6e9e0626SOleksandr Tymoshenko uint32_t snpsid; 1011*6e9e0626SOleksandr Tymoshenko int i, j; 1012*6e9e0626SOleksandr Tymoshenko 1013*6e9e0626SOleksandr Tymoshenko root_hub_devnum = 0; 1014*6e9e0626SOleksandr Tymoshenko 1015*6e9e0626SOleksandr Tymoshenko snpsid = readl(®s->gsnpsid); 1016*6e9e0626SOleksandr Tymoshenko printf("Core Release: %x.%03x\n", snpsid >> 12 & 0xf, snpsid & 0xfff); 1017*6e9e0626SOleksandr Tymoshenko 1018*6e9e0626SOleksandr Tymoshenko if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx) { 1019*6e9e0626SOleksandr Tymoshenko printf("SNPSID invalid (not DWC2 OTG device): %08x\n", snpsid); 1020*6e9e0626SOleksandr Tymoshenko return -ENODEV; 1021*6e9e0626SOleksandr Tymoshenko } 1022*6e9e0626SOleksandr Tymoshenko 1023*6e9e0626SOleksandr Tymoshenko dwc_otg_core_init(regs); 1024*6e9e0626SOleksandr Tymoshenko dwc_otg_core_host_init(regs); 1025*6e9e0626SOleksandr Tymoshenko 1026*6e9e0626SOleksandr Tymoshenko clrsetbits_le32(®s->hprt0, DWC2_HPRT0_PRTENA | 1027*6e9e0626SOleksandr Tymoshenko DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG | 1028*6e9e0626SOleksandr Tymoshenko DWC2_HPRT0_PRTOVRCURRCHNG, 1029*6e9e0626SOleksandr Tymoshenko DWC2_HPRT0_PRTRST); 1030*6e9e0626SOleksandr Tymoshenko mdelay(50); 1031*6e9e0626SOleksandr Tymoshenko clrbits_le32(®s->hprt0, DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET | 1032*6e9e0626SOleksandr Tymoshenko DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG | 1033*6e9e0626SOleksandr Tymoshenko DWC2_HPRT0_PRTRST); 1034*6e9e0626SOleksandr Tymoshenko 1035*6e9e0626SOleksandr Tymoshenko for (i = 0; i < MAX_DEVICE; i++) { 1036*6e9e0626SOleksandr Tymoshenko for (j = 0; j < MAX_ENDPOINT; j++) { 1037*6e9e0626SOleksandr Tymoshenko control_data_toggle[i][j] = DWC2_HC_PID_DATA1; 1038*6e9e0626SOleksandr Tymoshenko bulk_data_toggle[i][j] = DWC2_HC_PID_DATA0; 1039*6e9e0626SOleksandr Tymoshenko } 1040*6e9e0626SOleksandr Tymoshenko } 1041*6e9e0626SOleksandr Tymoshenko 1042*6e9e0626SOleksandr Tymoshenko return 0; 1043*6e9e0626SOleksandr Tymoshenko } 1044*6e9e0626SOleksandr Tymoshenko 1045*6e9e0626SOleksandr Tymoshenko int usb_lowlevel_stop(int index) 1046*6e9e0626SOleksandr Tymoshenko { 1047*6e9e0626SOleksandr Tymoshenko /* Put everything in reset. */ 1048*6e9e0626SOleksandr Tymoshenko clrsetbits_le32(®s->hprt0, DWC2_HPRT0_PRTENA | 1049*6e9e0626SOleksandr Tymoshenko DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG | 1050*6e9e0626SOleksandr Tymoshenko DWC2_HPRT0_PRTOVRCURRCHNG, 1051*6e9e0626SOleksandr Tymoshenko DWC2_HPRT0_PRTRST); 1052*6e9e0626SOleksandr Tymoshenko return 0; 1053*6e9e0626SOleksandr Tymoshenko } 1054