diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 5d038e814203..ead827a714f5 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -48,6 +48,8 @@ Optional properties: fladj_30mhz_sdbnd signal is invalid or incorrect. - snps,nominal-elastic-buffer: When set, the nominal elastic buffer setting is used. By default, the half-full setting is used. + - snps,usb3-u1u2-disable: If present, disable u1u2 low power modes for DWC3 core + controller in SS mode. This is usually a subnode to DWC3 glue to which it is connected. @@ -57,4 +59,5 @@ dwc3@4a030000 { interrupts = <0 92 4> usb-phy = <&usb2_phy>, <&usb3,phy>; tx-fifo-resize; + snps,usb3-u1u2-disable; }; diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index aa78f38220d2..6ae3202ae9e6 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -997,6 +997,8 @@ static int dwc3_probe(struct platform_device *pdev) dwc->nominal_elastic_buffer = device_property_read_bool(dev, "snps,nominal-elastic-buffer"); + dwc->usb3_u1u2_disable = device_property_read_bool(dev, + "snps,usb3-u1u2-disable"); if (pdata) { dwc->maximum_speed = pdata->maximum_speed; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 60d5f8515f14..bc7129185554 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -797,6 +797,7 @@ struct dwc3_scratchpad_array { * 2 - No de-emphasis * 3 - Reserved * @err_evt_seen: previous event in queue was erratic error + * @usb3_u1u2_disable: if true, disable U1U2 low power modes in Superspeed mode. * @in_lpm: indicates if controller is in low power mode (no clocks) */ struct dwc3 { @@ -945,6 +946,7 @@ struct dwc3 { unsigned nominal_elastic_buffer:1; unsigned err_evt_seen:1; + unsigned usb3_u1u2_disable:1; struct dwc3_gadget_events dbg_gadget_events; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 55191ea9d6e2..e6bcbf11b872 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -36,6 +37,11 @@ #include "io.h" #include "debug.h" + +static bool enable_dwc3_u1u2; +module_param(enable_dwc3_u1u2, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(enable_dwc3_u1u2, "Enable support for U1U2 low power modes"); + static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep); static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req); @@ -431,6 +437,9 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, if (dwc->speed != DWC3_DSTS_SUPERSPEED) return -EINVAL; + if (dwc->usb3_u1u2_disable && !enable_dwc3_u1u2) + return -EINVAL; + reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (set) reg |= DWC3_DCTL_INITU1ENA; @@ -445,6 +454,9 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, if (dwc->speed != DWC3_DSTS_SUPERSPEED) return -EINVAL; + if (dwc->usb3_u1u2_disable && !enable_dwc3_u1u2) + return -EINVAL; + reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (set) reg |= DWC3_DCTL_INITU2ENA; @@ -579,13 +591,16 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) usb_gadget_set_state(&dwc->gadget, USB_STATE_CONFIGURED); - /* - * Enable transition to U1/U2 state when - * nothing is pending from application. - */ - reg = dwc3_readl(dwc->regs, DWC3_DCTL); - reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA); - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + if (!dwc->usb3_u1u2_disable || enable_dwc3_u1u2) { + /* + * Enable transition to U1/U2 state when + * nothing is pending from application. + */ + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + reg |= (DWC3_DCTL_ACCEPTU1ENA | + DWC3_DCTL_ACCEPTU2ENA); + dwc3_writel(dwc->regs, DWC3_DCTL, reg); + } dwc->resize_fifos = true; dwc3_trace(trace_dwc3_ep0, "resize FIFOs flag SET");