Merge 5.12-rc4 into usb-next
[linux-2.6-microblaze.git] / drivers / usb / dwc3 / gadget.c
index ee44321..2c94cc9 100644 (file)
@@ -605,8 +605,23 @@ static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action)
                params.param0 |= DWC3_DEPCFG_FIFO_NUMBER(dep->number >> 1);
 
        if (desc->bInterval) {
-               params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(desc->bInterval - 1);
-               dep->interval = 1 << (desc->bInterval - 1);
+               u8 bInterval_m1;
+
+               /*
+                * Valid range for DEPCFG.bInterval_m1 is from 0 to 13, and it
+                * must be set to 0 when the controller operates in full-speed.
+                */
+               bInterval_m1 = min_t(u8, desc->bInterval - 1, 13);
+               if (dwc->gadget->speed == USB_SPEED_FULL)
+                       bInterval_m1 = 0;
+
+               if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT &&
+                   dwc->gadget->speed == USB_SPEED_FULL)
+                       dep->interval = desc->bInterval;
+               else
+                       dep->interval = 1 << (desc->bInterval - 1);
+
+               params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(bInterval_m1);
        }
 
        return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETEPCONFIG, &params);
@@ -768,8 +783,6 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
 
        trace_dwc3_gadget_ep_disable(dep);
 
-       dwc3_remove_requests(dwc, dep);
-
        /* make sure HW endpoint isn't stalled */
        if (dep->flags & DWC3_EP_STALL)
                __dwc3_gadget_ep_set_halt(dep, 0, false);
@@ -788,6 +801,8 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
                dep->endpoint.desc = NULL;
        }
 
+       dwc3_remove_requests(dwc, dep);
+
        return 0;
 }
 
@@ -1602,7 +1617,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 {
        struct dwc3             *dwc = dep->dwc;
 
-       if (!dep->endpoint.desc || !dwc->pullups_connected) {
+       if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) {
                dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n",
                                dep->name);
                return -ESHUTDOWN;
@@ -2038,6 +2053,102 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc)
        }
 }
 
+static void __dwc3_gadget_set_ssp_rate(struct dwc3 *dwc)
+{
+       enum usb_ssp_rate       ssp_rate = dwc->gadget_ssp_rate;
+       u32                     reg;
+
+       if (ssp_rate == USB_SSP_GEN_UNKNOWN)
+               ssp_rate = dwc->max_ssp_rate;
+
+       reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+       reg &= ~DWC3_DCFG_SPEED_MASK;
+       reg &= ~DWC3_DCFG_NUMLANES(~0);
+
+       if (ssp_rate == USB_SSP_GEN_1x2)
+               reg |= DWC3_DCFG_SUPERSPEED;
+       else if (dwc->max_ssp_rate != USB_SSP_GEN_1x2)
+               reg |= DWC3_DCFG_SUPERSPEED_PLUS;
+
+       if (ssp_rate != USB_SSP_GEN_2x1 &&
+           dwc->max_ssp_rate != USB_SSP_GEN_2x1)
+               reg |= DWC3_DCFG_NUMLANES(1);
+
+       dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+}
+
+static void __dwc3_gadget_set_speed(struct dwc3 *dwc)
+{
+       enum usb_device_speed   speed;
+       u32                     reg;
+
+       speed = dwc->gadget_max_speed;
+       if (speed > dwc->maximum_speed)
+               speed = dwc->maximum_speed;
+
+       if (speed == USB_SPEED_SUPER_PLUS &&
+           DWC3_IP_IS(DWC32)) {
+               __dwc3_gadget_set_ssp_rate(dwc);
+               return;
+       }
+
+       reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+       reg &= ~(DWC3_DCFG_SPEED_MASK);
+
+       /*
+        * WORKAROUND: DWC3 revision < 2.20a have an issue
+        * which would cause metastability state on Run/Stop
+        * bit if we try to force the IP to USB2-only mode.
+        *
+        * Because of that, we cannot configure the IP to any
+        * speed other than the SuperSpeed
+        *
+        * Refers to:
+        *
+        * STAR#9000525659: Clock Domain Crossing on DCTL in
+        * USB 2.0 Mode
+        */
+       if (DWC3_VER_IS_PRIOR(DWC3, 220A) &&
+           !dwc->dis_metastability_quirk) {
+               reg |= DWC3_DCFG_SUPERSPEED;
+       } else {
+               switch (speed) {
+               case USB_SPEED_LOW:
+                       reg |= DWC3_DCFG_LOWSPEED;
+                       break;
+               case USB_SPEED_FULL:
+                       reg |= DWC3_DCFG_FULLSPEED;
+                       break;
+               case USB_SPEED_HIGH:
+                       reg |= DWC3_DCFG_HIGHSPEED;
+                       break;
+               case USB_SPEED_SUPER:
+                       reg |= DWC3_DCFG_SUPERSPEED;
+                       break;
+               case USB_SPEED_SUPER_PLUS:
+                       if (DWC3_IP_IS(DWC3))
+                               reg |= DWC3_DCFG_SUPERSPEED;
+                       else
+                               reg |= DWC3_DCFG_SUPERSPEED_PLUS;
+                       break;
+               default:
+                       dev_err(dwc->dev, "invalid speed (%d)\n", speed);
+
+                       if (DWC3_IP_IS(DWC3))
+                               reg |= DWC3_DCFG_SUPERSPEED;
+                       else
+                               reg |= DWC3_DCFG_SUPERSPEED_PLUS;
+               }
+       }
+
+       if (DWC3_IP_IS(DWC32) &&
+           speed > USB_SPEED_UNKNOWN &&
+           speed < USB_SPEED_SUPER_PLUS)
+               reg &= ~DWC3_DCFG_NUMLANES(~0);
+
+       dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+}
+
 static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
 {
        u32                     reg;
@@ -2060,6 +2171,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
                if (dwc->has_hibernation)
                        reg |= DWC3_DCTL_KEEP_CONNECT;
 
+               __dwc3_gadget_set_speed(dwc);
                dwc->pullups_connected = true;
        } else {
                reg &= ~DWC3_DCTL_RUN_STOP;
@@ -2110,6 +2222,17 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
                }
        }
 
+       /*
+        * Check the return value for successful resume, or error.  For a
+        * successful resume, the DWC3 runtime PM resume routine will handle
+        * the run stop sequence, so avoid duplicate operations here.
+        */
+       ret = pm_runtime_get_sync(dwc->dev);
+       if (!ret || ret < 0) {
+               pm_runtime_put(dwc->dev);
+               return 0;
+       }
+
        /*
         * Synchronize any pending event handling before executing the controller
         * halt routine.
@@ -2124,6 +2247,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
        if (!is_on) {
                u32 count;
 
+               dwc->connected = false;
                /*
                 * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
                 * Section 4.1.8 Table 4-7, it states that for a device-initiated
@@ -2154,6 +2278,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 
        ret = dwc3_gadget_run_stop(dwc, is_on, false);
        spin_unlock_irqrestore(&dwc->lock, flags);
+       pm_runtime_put(dwc->dev);
 
        return ret;
 }
@@ -2163,8 +2288,7 @@ static void dwc3_gadget_enable_irq(struct dwc3 *dwc)
        u32                     reg;
 
        /* Enable all but Start and End of Frame IRQs */
-       reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
-                       DWC3_DEVTEN_EVNTOVERFLOWEN |
+       reg = (DWC3_DEVTEN_EVNTOVERFLOWEN |
                        DWC3_DEVTEN_CMDCMPLTEN |
                        DWC3_DEVTEN_ERRTICERREN |
                        DWC3_DEVTEN_WKUPEVTEN |
@@ -2302,7 +2426,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
 {
        struct dwc3             *dwc = gadget_to_dwc(g);
        unsigned long           flags;
-       int                     ret = 0;
+       int                     ret;
        int                     irq;
 
        irq = dwc->irq_gadget;
@@ -2311,29 +2435,14 @@ static int dwc3_gadget_start(struct usb_gadget *g,
        if (ret) {
                dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
                                irq, ret);
-               goto err0;
+               return ret;
        }
 
        spin_lock_irqsave(&dwc->lock, flags);
-       if (dwc->gadget_driver) {
-               dev_err(dwc->dev, "%s is already bound to %s\n",
-                               dwc->gadget->name,
-                               dwc->gadget_driver->driver.name);
-               ret = -EBUSY;
-               goto err1;
-       }
-
        dwc->gadget_driver      = driver;
        spin_unlock_irqrestore(&dwc->lock, flags);
 
        return 0;
-
-err1:
-       spin_unlock_irqrestore(&dwc->lock, flags);
-       free_irq(irq, dwc);
-
-err0:
-       return ret;
 }
 
 static void __dwc3_gadget_stop(struct dwc3 *dwc)
@@ -2401,62 +2510,41 @@ static void dwc3_gadget_set_speed(struct usb_gadget *g,
 {
        struct dwc3             *dwc = gadget_to_dwc(g);
        unsigned long           flags;
-       u32                     reg;
 
        spin_lock_irqsave(&dwc->lock, flags);
-       reg = dwc3_readl(dwc->regs, DWC3_DCFG);
-       reg &= ~(DWC3_DCFG_SPEED_MASK);
-
-       /*
-        * WORKAROUND: DWC3 revision < 2.20a have an issue
-        * which would cause metastability state on Run/Stop
-        * bit if we try to force the IP to USB2-only mode.
-        *
-        * Because of that, we cannot configure the IP to any
-        * speed other than the SuperSpeed
-        *
-        * Refers to:
-        *
-        * STAR#9000525659: Clock Domain Crossing on DCTL in
-        * USB 2.0 Mode
-        */
-       if (DWC3_VER_IS_PRIOR(DWC3, 220A) &&
-           !dwc->dis_metastability_quirk) {
-               reg |= DWC3_DCFG_SUPERSPEED;
-       } else {
-               switch (speed) {
-               case USB_SPEED_LOW:
-                       reg |= DWC3_DCFG_LOWSPEED;
-                       break;
-               case USB_SPEED_FULL:
-                       reg |= DWC3_DCFG_FULLSPEED;
-                       break;
-               case USB_SPEED_HIGH:
-                       reg |= DWC3_DCFG_HIGHSPEED;
-                       break;
-               case USB_SPEED_SUPER:
-                       reg |= DWC3_DCFG_SUPERSPEED;
-                       break;
-               case USB_SPEED_SUPER_PLUS:
-                       if (DWC3_IP_IS(DWC3))
-                               reg |= DWC3_DCFG_SUPERSPEED;
-                       else
-                               reg |= DWC3_DCFG_SUPERSPEED_PLUS;
-                       break;
-               default:
-                       dev_err(dwc->dev, "invalid speed (%d)\n", speed);
+       dwc->gadget_max_speed = speed;
+       spin_unlock_irqrestore(&dwc->lock, flags);
+}
 
-                       if (DWC3_IP_IS(DWC3))
-                               reg |= DWC3_DCFG_SUPERSPEED;
-                       else
-                               reg |= DWC3_DCFG_SUPERSPEED_PLUS;
-               }
-       }
-       dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+static void dwc3_gadget_set_ssp_rate(struct usb_gadget *g,
+                                    enum usb_ssp_rate rate)
+{
+       struct dwc3             *dwc = gadget_to_dwc(g);
+       unsigned long           flags;
 
+       spin_lock_irqsave(&dwc->lock, flags);
+       dwc->gadget_ssp_rate = rate;
        spin_unlock_irqrestore(&dwc->lock, flags);
 }
 
+static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA)
+{
+       struct dwc3             *dwc = gadget_to_dwc(g);
+       union power_supply_propval      val = {0};
+       int                             ret;
+
+       if (dwc->usb2_phy)
+               return usb_phy_set_power(dwc->usb2_phy, mA);
+
+       if (!dwc->usb_psy)
+               return -EOPNOTSUPP;
+
+       val.intval = mA;
+       ret = power_supply_set_property(dwc->usb_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &val);
+
+       return ret;
+}
+
 static const struct usb_gadget_ops dwc3_gadget_ops = {
        .get_frame              = dwc3_gadget_get_frame,
        .wakeup                 = dwc3_gadget_wakeup,
@@ -2465,7 +2553,9 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
        .udc_start              = dwc3_gadget_start,
        .udc_stop               = dwc3_gadget_stop,
        .udc_set_speed          = dwc3_gadget_set_speed,
+       .udc_set_ssp_rate       = dwc3_gadget_set_ssp_rate,
        .get_config_params      = dwc3_gadget_config_params,
+       .vbus_draw              = dwc3_gadget_vbus_draw,
 };
 
 /* -------------------------------------------------------------------------- */
@@ -3239,8 +3329,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 {
        u32                     reg;
 
-       dwc->connected = true;
-
        /*
         * WORKAROUND: DWC3 revisions <1.88a have an issue which
         * would cause a missing Disconnect Event if there's a
@@ -3280,6 +3368,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
         * transfers."
         */
        dwc3_stop_active_transfers(dwc);
+       dwc->connected = true;
 
        reg = dwc3_readl(dwc->regs, DWC3_DCTL);
        reg &= ~DWC3_DCTL_TSTCTRL_MASK;
@@ -3298,12 +3387,18 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
        struct dwc3_ep          *dep;
        int                     ret;
        u32                     reg;
+       u8                      lanes = 1;
        u8                      speed;
 
        reg = dwc3_readl(dwc->regs, DWC3_DSTS);
        speed = reg & DWC3_DSTS_CONNECTSPD;
        dwc->speed = speed;
 
+       if (DWC3_IP_IS(DWC32))
+               lanes = DWC3_DSTS_CONNLANES(reg) + 1;
+
+       dwc->gadget->ssp_rate = USB_SSP_GEN_UNKNOWN;
+
        /*
         * RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed
         * each time on Connect Done.
@@ -3318,6 +3413,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
                dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
                dwc->gadget->ep0->maxpacket = 512;
                dwc->gadget->speed = USB_SPEED_SUPER_PLUS;
+
+               if (lanes > 1)
+                       dwc->gadget->ssp_rate = USB_SSP_GEN_2x2;
+               else
+                       dwc->gadget->ssp_rate = USB_SSP_GEN_2x1;
                break;
        case DWC3_DSTS_SUPERSPEED:
                /*
@@ -3339,6 +3439,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
                dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
                dwc->gadget->ep0->maxpacket = 512;
                dwc->gadget->speed = USB_SPEED_SUPER;
+
+               if (lanes > 1) {
+                       dwc->gadget->speed = USB_SPEED_SUPER_PLUS;
+                       dwc->gadget->ssp_rate = USB_SSP_GEN_1x2;
+               }
                break;
        case DWC3_DSTS_HIGHSPEED:
                dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
@@ -3833,6 +3938,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
        dev->platform_data              = dwc;
        dwc->gadget->ops                = &dwc3_gadget_ops;
        dwc->gadget->speed              = USB_SPEED_UNKNOWN;
+       dwc->gadget->ssp_rate           = USB_SSP_GEN_UNKNOWN;
        dwc->gadget->sg_supported       = true;
        dwc->gadget->name               = "dwc3-gadget";
        dwc->gadget->lpm_capable        = true;
@@ -3859,6 +3965,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
                                dwc->revision);
 
        dwc->gadget->max_speed          = dwc->maximum_speed;
+       dwc->gadget->max_ssp_rate       = dwc->max_ssp_rate;
 
        /*
         * REVISIT: Here we should clear all pending IRQs to be
@@ -3875,7 +3982,10 @@ int dwc3_gadget_init(struct dwc3 *dwc)
                goto err5;
        }
 
-       dwc3_gadget_set_speed(dwc->gadget, dwc->maximum_speed);
+       if (DWC3_IP_IS(DWC32) && dwc->maximum_speed == USB_SPEED_SUPER_PLUS)
+               dwc3_gadget_set_ssp_rate(dwc->gadget, dwc->max_ssp_rate);
+       else
+               dwc3_gadget_set_speed(dwc->gadget, dwc->maximum_speed);
 
        return 0;