struct cvmx_usb_state usb;
};
-/* This macro spins on a field waiting for it to reach a value */
-#define CVMX_WAIT_FOR_FIELD32(address, type, field, op, value, timeout_usec)\
+/* This macro spins on a register waiting for it to reach a condition. */
+#define CVMX_WAIT_FOR_FIELD32(address, _union, cond, timeout_usec) \
({int result; \
do { \
uint64_t done = cvmx_get_cycle() + (uint64_t)timeout_usec * \
octeon_get_clock_rate() / 1000000; \
- type c; \
+ union _union c; \
+ \
while (1) { \
c.u32 = cvmx_usb_read_csr32(usb, address); \
- if (c.s.field op (value)) { \
+ \
+ if (cond) { \
result = 0; \
break; \
} else if (cvmx_get_cycle() > done) { \
* This macro logically sets a single field in a CSR. It does the sequence
* read, modify, and write
*/
-#define USB_SET_FIELD32(address, type, field, value) \
+#define USB_SET_FIELD32(address, _union, field, value) \
do { \
- type c; \
+ union _union c; \
+ \
c.u32 = cvmx_usb_read_csr32(usb, address); \
c.s.field = value; \
cvmx_usb_write_csr32(usb, address, c.u32); \
return 0; /* Data0 */
}
+static void cvmx_fifo_setup(struct cvmx_usb_state *usb)
+{
+ union cvmx_usbcx_ghwcfg3 usbcx_ghwcfg3;
+ union cvmx_usbcx_gnptxfsiz npsiz;
+ union cvmx_usbcx_hptxfsiz psiz;
+
+ usbcx_ghwcfg3.u32 = cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_GHWCFG3(usb->index));
+
+ /*
+ * Program the USBC_GRXFSIZ register to select the size of the receive
+ * FIFO (25%).
+ */
+ USB_SET_FIELD32(CVMX_USBCX_GRXFSIZ(usb->index), cvmx_usbcx_grxfsiz,
+ rxfdep, usbcx_ghwcfg3.s.dfifodepth / 4);
+
+ /*
+ * Program the USBC_GNPTXFSIZ register to select the size and the start
+ * address of the non-periodic transmit FIFO for nonperiodic
+ * transactions (50%).
+ */
+ npsiz.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index));
+ npsiz.s.nptxfdep = usbcx_ghwcfg3.s.dfifodepth / 2;
+ npsiz.s.nptxfstaddr = usbcx_ghwcfg3.s.dfifodepth / 4;
+ cvmx_usb_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index), npsiz.u32);
+
+ /*
+ * Program the USBC_HPTXFSIZ register to select the size and start
+ * address of the periodic transmit FIFO for periodic transactions
+ * (25%).
+ */
+ psiz.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index));
+ psiz.s.ptxfsize = usbcx_ghwcfg3.s.dfifodepth / 4;
+ psiz.s.ptxfstaddr = 3 * usbcx_ghwcfg3.s.dfifodepth / 4;
+ cvmx_usb_write_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index), psiz.u32);
+
+ /* Flush all FIFOs */
+ USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
+ cvmx_usbcx_grstctl, txfnum, 0x10);
+ USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
+ cvmx_usbcx_grstctl, txfflsh, 1);
+ CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
+ cvmx_usbcx_grstctl, c.s.txfflsh == 0, 100);
+ USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
+ cvmx_usbcx_grstctl, rxfflsh, 1);
+ CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
+ cvmx_usbcx_grstctl, c.s.rxfflsh == 0, 100);
+}
+
+/**
+ * Shutdown a USB port after a call to cvmx_usb_initialize().
+ * The port should be disabled with all pipes closed when this
+ * function is called.
+ *
+ * @usb: USB device state populated by cvmx_usb_initialize().
+ *
+ * Returns: 0 or a negative error code.
+ */
+static int cvmx_usb_shutdown(struct cvmx_usb_state *usb)
+{
+ union cvmx_usbnx_clk_ctl usbn_clk_ctl;
+
+ /* Make sure all pipes are closed */
+ if (!list_empty(&usb->idle_pipes) ||
+ !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_ISOCHRONOUS]) ||
+ !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_INTERRUPT]) ||
+ !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_CONTROL]) ||
+ !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_BULK]))
+ return -EBUSY;
+
+ /* Disable the clocks and put them in power on reset */
+ usbn_clk_ctl.u64 = cvmx_read64_uint64(CVMX_USBNX_CLK_CTL(usb->index));
+ usbn_clk_ctl.s.enable = 1;
+ usbn_clk_ctl.s.por = 1;
+ usbn_clk_ctl.s.hclk_rst = 1;
+ usbn_clk_ctl.s.prst = 0;
+ usbn_clk_ctl.s.hrst = 0;
+ cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
+ return 0;
+}
+
/**
* Initialize a USB port for use. This must be called before any
* other access to the Octeon USB port is made. The port starts
* off in the disabled state.
*
+ * @dev: Pointer to struct device for logging purposes.
* @usb: Pointer to struct cvmx_usb_state.
*
* Returns: 0 or a negative error code.
*/
-static int cvmx_usb_initialize(struct cvmx_usb_state *usb)
+static int cvmx_usb_initialize(struct device *dev,
+ struct cvmx_usb_state *usb)
{
+ int channel;
+ int divisor;
+ int retries = 0;
+ union cvmx_usbcx_hcfg usbcx_hcfg;
union cvmx_usbnx_clk_ctl usbn_clk_ctl;
+ union cvmx_usbcx_gintsts usbc_gintsts;
+ union cvmx_usbcx_gahbcfg usbcx_gahbcfg;
+ union cvmx_usbcx_gintmsk usbcx_gintmsk;
+ union cvmx_usbcx_gusbcfg usbcx_gusbcfg;
union cvmx_usbnx_usbp_ctl_status usbn_usbp_ctl_status;
+retry:
/*
* Power On Reset and PHY Initialization
*
* setting USBN0/1_CLK_CTL[ENABLE] = 1. Divide the core clock down
* such that USB is as close as possible to 125Mhz
*/
- {
- int divisor = DIV_ROUND_UP(octeon_get_clock_rate(), 125000000);
- /* Lower than 4 doesn't seem to work properly */
- if (divisor < 4)
- divisor = 4;
- usbn_clk_ctl.s.divide = divisor;
- usbn_clk_ctl.s.divide2 = 0;
- }
+ divisor = DIV_ROUND_UP(octeon_get_clock_rate(), 125000000);
+ /* Lower than 4 doesn't seem to work properly */
+ if (divisor < 4)
+ divisor = 4;
+ usbn_clk_ctl.s.divide = divisor;
+ usbn_clk_ctl.s.divide2 = 0;
cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
+
/* 2d. Write USBN0/1_CLK_CTL[HCLK_RST] = 1 */
usbn_clk_ctl.s.hclk_rst = 1;
cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
* USBC_GAHBCFG[PTXFEMPLVL]
* Global interrupt mask, USBC_GAHBCFG[GLBLINTRMSK] = 1
*/
- {
- union cvmx_usbcx_gahbcfg usbcx_gahbcfg;
- usbcx_gahbcfg.u32 = 0;
- usbcx_gahbcfg.s.dmaen = !(usb->init_flags &
- CVMX_USB_INITIALIZE_FLAGS_NO_DMA);
- usbcx_gahbcfg.s.hbstlen = 0;
- usbcx_gahbcfg.s.nptxfemplvl = 1;
- usbcx_gahbcfg.s.ptxfemplvl = 1;
- usbcx_gahbcfg.s.glblintrmsk = 1;
- cvmx_usb_write_csr32(usb, CVMX_USBCX_GAHBCFG(usb->index),
- usbcx_gahbcfg.u32);
- }
+ usbcx_gahbcfg.u32 = 0;
+ usbcx_gahbcfg.s.dmaen = !(usb->init_flags &
+ CVMX_USB_INITIALIZE_FLAGS_NO_DMA);
+ usbcx_gahbcfg.s.hbstlen = 0;
+ usbcx_gahbcfg.s.nptxfemplvl = 1;
+ usbcx_gahbcfg.s.ptxfemplvl = 1;
+ usbcx_gahbcfg.s.glblintrmsk = 1;
+ cvmx_usb_write_csr32(usb, CVMX_USBCX_GAHBCFG(usb->index),
+ usbcx_gahbcfg.u32);
+
/*
* 3. Program the following fields in USBC_GUSBCFG register.
* HS/FS timeout calibration, USBC_GUSBCFG[TOUTCAL] = 0
* USB turnaround time, USBC_GUSBCFG[USBTRDTIM] = 0x5
* PHY low-power clock select, USBC_GUSBCFG[PHYLPWRCLKSEL] = 0
*/
- {
- union cvmx_usbcx_gusbcfg usbcx_gusbcfg;
-
- usbcx_gusbcfg.u32 = cvmx_usb_read_csr32(usb,
- CVMX_USBCX_GUSBCFG(usb->index));
- usbcx_gusbcfg.s.toutcal = 0;
- usbcx_gusbcfg.s.ddrsel = 0;
- usbcx_gusbcfg.s.usbtrdtim = 0x5;
- usbcx_gusbcfg.s.phylpwrclksel = 0;
- cvmx_usb_write_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index),
- usbcx_gusbcfg.u32);
- }
+ usbcx_gusbcfg.u32 = cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_GUSBCFG(usb->index));
+ usbcx_gusbcfg.s.toutcal = 0;
+ usbcx_gusbcfg.s.ddrsel = 0;
+ usbcx_gusbcfg.s.usbtrdtim = 0x5;
+ usbcx_gusbcfg.s.phylpwrclksel = 0;
+ cvmx_usb_write_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index),
+ usbcx_gusbcfg.u32);
+
/*
* 4. The software must unmask the following bits in the USBC_GINTMSK
* register.
* OTG interrupt mask, USBC_GINTMSK[OTGINTMSK] = 1
* Mode mismatch interrupt mask, USBC_GINTMSK[MODEMISMSK] = 1
*/
- {
- union cvmx_usbcx_gintmsk usbcx_gintmsk;
- int channel;
-
- usbcx_gintmsk.u32 = cvmx_usb_read_csr32(usb,
- CVMX_USBCX_GINTMSK(usb->index));
- usbcx_gintmsk.s.otgintmsk = 1;
- usbcx_gintmsk.s.modemismsk = 1;
- usbcx_gintmsk.s.hchintmsk = 1;
- usbcx_gintmsk.s.sofmsk = 0;
- /* We need RX FIFO interrupts if we don't have DMA */
- if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
- usbcx_gintmsk.s.rxflvlmsk = 1;
- cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTMSK(usb->index),
- usbcx_gintmsk.u32);
-
- /*
- * Disable all channel interrupts. We'll enable them per channel
- * later.
- */
- for (channel = 0; channel < 8; channel++)
- cvmx_usb_write_csr32(usb,
- CVMX_USBCX_HCINTMSKX(channel, usb->index), 0);
- }
-
- {
- /*
- * Host Port Initialization
- *
- * 1. Program the host-port interrupt-mask field to unmask,
- * USBC_GINTMSK[PRTINT] = 1
- */
- USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
- union cvmx_usbcx_gintmsk, prtintmsk, 1);
- USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
- union cvmx_usbcx_gintmsk, disconnintmsk, 1);
- /*
- * 2. Program the USBC_HCFG register to select full-speed host
- * or high-speed host.
- */
- {
- union cvmx_usbcx_hcfg usbcx_hcfg;
-
- usbcx_hcfg.u32 = cvmx_usb_read_csr32(usb,
- CVMX_USBCX_HCFG(usb->index));
- usbcx_hcfg.s.fslssupp = 0;
- usbcx_hcfg.s.fslspclksel = 0;
- cvmx_usb_write_csr32(usb, CVMX_USBCX_HCFG(usb->index),
- usbcx_hcfg.u32);
- }
- /*
- * 3. Program the port power bit to drive VBUS on the USB,
- * USBC_HPRT[PRTPWR] = 1
- */
- USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index),
- union cvmx_usbcx_hprt, prtpwr, 1);
-
- /*
- * Steps 4-15 from the manual are done later in the port enable
- */
- }
+ usbcx_gintmsk.u32 = cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_GINTMSK(usb->index));
+ usbcx_gintmsk.s.otgintmsk = 1;
+ usbcx_gintmsk.s.modemismsk = 1;
+ usbcx_gintmsk.s.hchintmsk = 1;
+ usbcx_gintmsk.s.sofmsk = 0;
+ /* We need RX FIFO interrupts if we don't have DMA */
+ if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
+ usbcx_gintmsk.s.rxflvlmsk = 1;
+ cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTMSK(usb->index),
+ usbcx_gintmsk.u32);
- return 0;
-}
+ /*
+ * Disable all channel interrupts. We'll enable them per channel later.
+ */
+ for (channel = 0; channel < 8; channel++)
+ cvmx_usb_write_csr32(usb,
+ CVMX_USBCX_HCINTMSKX(channel, usb->index),
+ 0);
+ /*
+ * Host Port Initialization
+ *
+ * 1. Program the host-port interrupt-mask field to unmask,
+ * USBC_GINTMSK[PRTINT] = 1
+ */
+ USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
+ cvmx_usbcx_gintmsk, prtintmsk, 1);
+ USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
+ cvmx_usbcx_gintmsk, disconnintmsk, 1);
-/**
- * Shutdown a USB port after a call to cvmx_usb_initialize().
- * The port should be disabled with all pipes closed when this
- * function is called.
- *
- * @usb: USB device state populated by cvmx_usb_initialize().
- *
- * Returns: 0 or a negative error code.
- */
-static int cvmx_usb_shutdown(struct cvmx_usb_state *usb)
-{
- union cvmx_usbnx_clk_ctl usbn_clk_ctl;
+ /*
+ * 2. Program the USBC_HCFG register to select full-speed host
+ * or high-speed host.
+ */
+ usbcx_hcfg.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HCFG(usb->index));
+ usbcx_hcfg.s.fslssupp = 0;
+ usbcx_hcfg.s.fslspclksel = 0;
+ cvmx_usb_write_csr32(usb, CVMX_USBCX_HCFG(usb->index), usbcx_hcfg.u32);
- /* Make sure all pipes are closed */
- if (!list_empty(&usb->idle_pipes) ||
- !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_ISOCHRONOUS]) ||
- !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_INTERRUPT]) ||
- !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_CONTROL]) ||
- !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_BULK]))
- return -EBUSY;
+ cvmx_fifo_setup(usb);
- /* Disable the clocks and put them in power on reset */
- usbn_clk_ctl.u64 = cvmx_read64_uint64(CVMX_USBNX_CLK_CTL(usb->index));
- usbn_clk_ctl.s.enable = 1;
- usbn_clk_ctl.s.por = 1;
- usbn_clk_ctl.s.hclk_rst = 1;
- usbn_clk_ctl.s.prst = 0;
- usbn_clk_ctl.s.hrst = 0;
- cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
- return 0;
+ /*
+ * If the controller is getting port events right after the reset, it
+ * means the initialization failed. Try resetting the controller again
+ * in such case. This is seen to happen after cold boot on DSR-1000N.
+ */
+ usbc_gintsts.u32 = cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_GINTSTS(usb->index));
+ cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index),
+ usbc_gintsts.u32);
+ dev_dbg(dev, "gintsts after reset: 0x%x\n", (int)usbc_gintsts.u32);
+ if (!usbc_gintsts.s.disconnint && !usbc_gintsts.s.prtint)
+ return 0;
+ if (retries++ >= 5)
+ return -EAGAIN;
+ dev_info(dev, "controller reset failed (gintsts=0x%x) - retrying\n",
+ (int)usbc_gintsts.u32);
+ msleep(50);
+ cvmx_usb_shutdown(usb);
+ msleep(50);
+ goto retry;
}
-
/**
- * Enable a USB port. After this call succeeds, the USB port is
+ * Reset a USB port. After this call succeeds, the USB port is
* online and servicing requests.
*
* @usb: USB device state populated by cvmx_usb_initialize().
- *
- * Returns: 0 or a negative error code.
*/
-static int cvmx_usb_enable(struct cvmx_usb_state *usb)
+static void cvmx_usb_reset_port(struct cvmx_usb_state *usb)
{
- union cvmx_usbcx_ghwcfg3 usbcx_ghwcfg3;
-
usb->usbcx_hprt.u32 = cvmx_usb_read_csr32(usb,
CVMX_USBCX_HPRT(usb->index));
- /*
- * If the port is already enabled the just return. We don't need to do
- * anything
- */
- if (usb->usbcx_hprt.s.prtena)
- return 0;
-
- /* If there is nothing plugged into the port then fail immediately */
- if (!usb->usbcx_hprt.s.prtconnsts)
- return -ETIMEDOUT;
-
/* Program the port reset bit to start the reset process */
- USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt,
+ USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt,
prtrst, 1);
/*
mdelay(50);
/* Program the port reset bit to 0, USBC_HPRT[PRTRST] = 0 */
- USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt,
+ USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt,
prtrst, 0);
- /* Wait for the USBC_HPRT[PRTENA]. */
- if (CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_HPRT(usb->index),
- union cvmx_usbcx_hprt, prtena, ==, 1, 100000))
- return -ETIMEDOUT;
-
/*
* Read the port speed field to get the enumerated speed,
* USBC_HPRT[PRTSPD].
*/
usb->usbcx_hprt.u32 = cvmx_usb_read_csr32(usb,
CVMX_USBCX_HPRT(usb->index));
- usbcx_ghwcfg3.u32 = cvmx_usb_read_csr32(usb,
- CVMX_USBCX_GHWCFG3(usb->index));
-
- /*
- * 13. Program the USBC_GRXFSIZ register to select the size of the
- * receive FIFO (25%).
- */
- USB_SET_FIELD32(CVMX_USBCX_GRXFSIZ(usb->index),
- union cvmx_usbcx_grxfsiz, rxfdep,
- usbcx_ghwcfg3.s.dfifodepth / 4);
- /*
- * 14. Program the USBC_GNPTXFSIZ register to select the size and the
- * start address of the non- periodic transmit FIFO for nonperiodic
- * transactions (50%).
- */
- {
- union cvmx_usbcx_gnptxfsiz siz;
-
- siz.u32 = cvmx_usb_read_csr32(usb,
- CVMX_USBCX_GNPTXFSIZ(usb->index));
- siz.s.nptxfdep = usbcx_ghwcfg3.s.dfifodepth / 2;
- siz.s.nptxfstaddr = usbcx_ghwcfg3.s.dfifodepth / 4;
- cvmx_usb_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index),
- siz.u32);
- }
- /*
- * 15. Program the USBC_HPTXFSIZ register to select the size and start
- * address of the periodic transmit FIFO for periodic transactions
- * (25%).
- */
- {
- union cvmx_usbcx_hptxfsiz siz;
-
- siz.u32 = cvmx_usb_read_csr32(usb,
- CVMX_USBCX_HPTXFSIZ(usb->index));
- siz.s.ptxfsize = usbcx_ghwcfg3.s.dfifodepth / 4;
- siz.s.ptxfstaddr = 3 * usbcx_ghwcfg3.s.dfifodepth / 4;
- cvmx_usb_write_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index),
- siz.u32);
- }
- /* Flush all FIFOs */
- USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
- union cvmx_usbcx_grstctl, txfnum, 0x10);
- USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
- union cvmx_usbcx_grstctl, txfflsh, 1);
- CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
- union cvmx_usbcx_grstctl,
- txfflsh, ==, 0, 100);
- USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
- union cvmx_usbcx_grstctl, rxfflsh, 1);
- CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
- union cvmx_usbcx_grstctl,
- rxfflsh, ==, 0, 100);
-
- return 0;
}
static int cvmx_usb_disable(struct cvmx_usb_state *usb)
{
/* Disable the port */
- USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt,
+ USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt,
prtena, 1);
return 0;
}
if (cvmx_usb_fill_tx_hw(usb, &usb->periodic,
tx_status.s.ptxfspcavail))
USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
- union cvmx_usbcx_gintmsk,
- ptxfempmsk, 1);
+ cvmx_usbcx_gintmsk, ptxfempmsk, 1);
else
USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
- union cvmx_usbcx_gintmsk,
- ptxfempmsk, 0);
+ cvmx_usbcx_gintmsk, ptxfempmsk, 0);
}
if (usb->nonperiodic.head != usb->nonperiodic.tail) {
if (cvmx_usb_fill_tx_hw(usb, &usb->nonperiodic,
tx_status.s.nptxfspcavail))
USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
- union cvmx_usbcx_gintmsk,
- nptxfempmsk, 1);
+ cvmx_usbcx_gintmsk, nptxfempmsk, 1);
else
USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
- union cvmx_usbcx_gintmsk,
- nptxfempmsk, 0);
+ cvmx_usbcx_gintmsk, nptxfempmsk, 0);
}
}
bytes_to_transfer = sizeof(*header);
/* All Control operations start with a setup going OUT */
USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
- union cvmx_usbcx_hccharx, epdir,
+ cvmx_usbcx_hccharx, epdir,
CVMX_USB_DIRECTION_OUT);
/*
* Setup send the control header instead of the buffer data. The
bytes_to_transfer = 0;
/* All Control operations start with a setup going OUT */
USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
- union cvmx_usbcx_hccharx, epdir,
+ cvmx_usbcx_hccharx, epdir,
CVMX_USB_DIRECTION_OUT);
USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index),
- union cvmx_usbcx_hcspltx, compsplt, 1);
+ cvmx_usbcx_hcspltx, compsplt, 1);
break;
case CVMX_USB_STAGE_DATA:
usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe);
bytes_to_transfer = pipe->max_packet;
}
USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
- union cvmx_usbcx_hccharx, epdir,
+ cvmx_usbcx_hccharx, epdir,
((header->bRequestType & USB_DIR_IN) ?
CVMX_USB_DIRECTION_IN :
CVMX_USB_DIRECTION_OUT));
if (!(header->bRequestType & USB_DIR_IN))
bytes_to_transfer = 0;
USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
- union cvmx_usbcx_hccharx, epdir,
+ cvmx_usbcx_hccharx, epdir,
((header->bRequestType & USB_DIR_IN) ?
CVMX_USB_DIRECTION_IN :
CVMX_USB_DIRECTION_OUT));
USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index),
- union cvmx_usbcx_hcspltx, compsplt, 1);
+ cvmx_usbcx_hcspltx, compsplt, 1);
break;
case CVMX_USB_STAGE_STATUS:
usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe);
bytes_to_transfer = 0;
USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
- union cvmx_usbcx_hccharx, epdir,
+ cvmx_usbcx_hccharx, epdir,
((header->bRequestType & USB_DIR_IN) ?
CVMX_USB_DIRECTION_OUT :
CVMX_USB_DIRECTION_IN));
usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe);
bytes_to_transfer = 0;
USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
- union cvmx_usbcx_hccharx, epdir,
+ cvmx_usbcx_hccharx, epdir,
((header->bRequestType & USB_DIR_IN) ?
CVMX_USB_DIRECTION_OUT :
CVMX_USB_DIRECTION_IN));
USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index),
- union cvmx_usbcx_hcspltx, compsplt, 1);
+ cvmx_usbcx_hcspltx, compsplt, 1);
break;
}
USB_SET_FIELD32(
CVMX_USBCX_HCTSIZX(channel,
usb->index),
- union cvmx_usbcx_hctsizx,
- pid, 0);
+ cvmx_usbcx_hctsizx, pid, 0);
else /* Need MDATA */
USB_SET_FIELD32(
CVMX_USBCX_HCTSIZX(channel,
usb->index),
- union cvmx_usbcx_hctsizx,
- pid, 3);
+ cvmx_usbcx_hctsizx, pid, 3);
}
}
break;
if (cvmx_usb_pipe_needs_split(usb, pipe))
usb->active_split = transaction;
USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
- union cvmx_usbcx_hccharx, chena, 1);
+ cvmx_usbcx_hccharx, chena, 1);
if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
cvmx_usb_fill_tx_fifo(usb, channel);
}
}
}
USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
- union cvmx_usbcx_gintmsk, sofmsk, need_sof);
+ cvmx_usbcx_gintmsk, sofmsk, need_sof);
}
static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb,
(pipe->transfer_dir == CVMX_USB_DIRECTION_OUT))
pipe->flags |= CVMX_USB_PIPE_FLAGS_NEED_PING;
+ if (unlikely(WARN_ON_ONCE(bytes_this_transfer < 0))) {
+ /*
+ * In some rare cases the DMA engine seems to get stuck and
+ * keeps substracting same byte count over and over again. In
+ * such case we just need to fail every transaction.
+ */
+ cvmx_usb_perform_complete(usb, pipe, transaction,
+ CVMX_USB_COMPLETE_ERROR);
+ return 0;
+ }
+
if (usbc_hcint.s.stall) {
/*
* STALL as a response means this transaction cannot be
struct octeon_hcd *priv = hcd_to_octeon(hcd);
struct device *dev = hcd->self.controller;
struct cvmx_usb_port_status usb_port_status;
+ struct cvmx_usb_state *usb = &priv->usb;
int port_status;
struct usb_hub_descriptor *desc;
unsigned long flags;
return -EINVAL;
case USB_PORT_FEAT_POWER:
dev_dbg(dev, " POWER\n");
- return -EINVAL;
+ /*
+ * Program the port power bit to drive VBUS on the USB.
+ */
+ spin_lock_irqsave(&priv->lock, flags);
+ USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index),
+ cvmx_usbcx_hprt, prtpwr, 1);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return 0;
case USB_PORT_FEAT_RESET:
dev_dbg(dev, " RESET\n");
spin_lock_irqsave(&priv->lock, flags);
- cvmx_usb_disable(&priv->usb);
- if (cvmx_usb_enable(&priv->usb))
- dev_dbg(dev, "Failed to enable the port\n");
+ cvmx_usb_reset_port(&priv->usb);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
case USB_PORT_FEAT_INDICATOR:
struct device *dev = &pdev->dev;
struct octeon_hcd *priv;
struct usb_hcd *hcd;
- unsigned long flags;
u32 clock_rate = 48000000;
bool is_crystal_clock = false;
const char *clock_type;
priv->usb.idle_hardware_channels = 0xff;
}
- status = cvmx_usb_initialize(&priv->usb);
+ status = cvmx_usb_initialize(dev, &priv->usb);
if (status) {
dev_dbg(dev, "USB initialization failed with %d\n", status);
kfree(hcd);
return -1;
}
- /* This delay is needed for CN3010, but I don't know why... */
- mdelay(10);
-
status = usb_add_hcd(hcd, irq, 0);
if (status) {
dev_dbg(dev, "USB add HCD failed with %d\n", status);