Merge remote-tracking branch 'usb-gadget/next'
[deliverable/linux.git] / drivers / usb / dwc3 / core.c
index 35d092456bec1da828ea41476e421d47809380a5..7287a763cd0cc4ca5a114ed687e6c34b0bdd643d 100644 (file)
 
 #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */
 
+/**
+ * dwc3_get_dr_mode - Validates and sets dr_mode
+ * @dwc: pointer to our context structure
+ */
+static int dwc3_get_dr_mode(struct dwc3 *dwc)
+{
+       enum usb_dr_mode mode;
+       struct device *dev = dwc->dev;
+       unsigned int hw_mode;
+
+       if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
+               dwc->dr_mode = USB_DR_MODE_OTG;
+
+       mode = dwc->dr_mode;
+       hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
+
+       switch (hw_mode) {
+       case DWC3_GHWPARAMS0_MODE_GADGET:
+               if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) {
+                       dev_err(dev,
+                               "Controller does not support host mode.\n");
+                       return -EINVAL;
+               }
+               mode = USB_DR_MODE_PERIPHERAL;
+               break;
+       case DWC3_GHWPARAMS0_MODE_HOST:
+               if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
+                       dev_err(dev,
+                               "Controller does not support device mode.\n");
+                       return -EINVAL;
+               }
+               mode = USB_DR_MODE_HOST;
+               break;
+       default:
+               if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
+                       mode = USB_DR_MODE_HOST;
+               else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
+                       mode = USB_DR_MODE_PERIPHERAL;
+       }
+
+       if (mode != dwc->dr_mode) {
+               dev_warn(dev,
+                        "Configuration mismatch. dr_mode forced to %s\n",
+                        mode == USB_DR_MODE_HOST ? "host" : "gadget");
+
+               dwc->dr_mode = mode;
+       }
+
+       return 0;
+}
+
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
 {
        u32 reg;
@@ -448,6 +499,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
        if (dwc->dis_u3_susphy_quirk)
                reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
 
+       if (dwc->dis_del_phy_power_chg_quirk)
+               reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
+
        dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
 
        reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
@@ -485,6 +539,23 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
                break;
        }
 
+       switch (dwc->hsphy_mode) {
+       case USBPHY_INTERFACE_MODE_UTMI:
+               reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
+                      DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
+               reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) |
+                      DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT);
+               break;
+       case USBPHY_INTERFACE_MODE_UTMIW:
+               reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
+                      DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
+               reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) |
+                      DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT);
+               break;
+       default:
+               break;
+       }
+
        /*
         * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
         * '0' during coreConsultant configuration. So default value will
@@ -500,6 +571,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
        if (dwc->dis_enblslpm_quirk)
                reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
 
+       if (dwc->dis_u2_freeclk_exists_quirk)
+               reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
+
        dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 
        return 0;
@@ -666,6 +740,32 @@ static int dwc3_core_init(struct dwc3 *dwc)
                goto err4;
        }
 
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
+               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+               break;
+       case USB_DR_MODE_HOST:
+               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
+               break;
+       case USB_DR_MODE_OTG:
+               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
+               break;
+       default:
+               dev_warn(dwc->dev, "Unsupported mode %d\n", dwc->dr_mode);
+               break;
+       }
+
+       /*
+        * ENDXFER polling is available on version 3.10a and later of
+        * the DWC_usb3 controller. It is NOT available in the
+        * DWC_usb31 controller.
+        */
+       if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) {
+               reg = dwc3_readl(dwc->regs, DWC3_GUCTL2);
+               reg |= DWC3_GUCTL2_RST_ACTBITLATER;
+               dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
+       }
+
        return 0;
 
 err4:
@@ -763,7 +863,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
 
        switch (dwc->dr_mode) {
        case USB_DR_MODE_PERIPHERAL:
-               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
                ret = dwc3_gadget_init(dwc);
                if (ret) {
                        if (ret != -EPROBE_DEFER)
@@ -772,7 +871,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
                }
                break;
        case USB_DR_MODE_HOST:
-               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
                ret = dwc3_host_init(dwc);
                if (ret) {
                        if (ret != -EPROBE_DEFER)
@@ -781,7 +879,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
                }
                break;
        case USB_DR_MODE_OTG:
-               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
                ret = dwc3_host_init(dwc);
                if (ret) {
                        if (ret != -EPROBE_DEFER)
@@ -888,6 +985,7 @@ static int dwc3_probe(struct platform_device *pdev)
 
        dwc->maximum_speed = usb_get_maximum_speed(dev);
        dwc->dr_mode = usb_get_dr_mode(dev);
+       dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node);
 
        dwc->has_lpm_erratum = device_property_read_bool(dev,
                                "snps,has-lpm-erratum");
@@ -924,6 +1022,10 @@ static int dwc3_probe(struct platform_device *pdev)
                                "snps,dis_enblslpm_quirk");
        dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
                                "snps,dis_rxdet_inp3_quirk");
+       dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
+                               "snps,dis-u2-freeclk-exists-quirk");
+       dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev,
+                               "snps,dis-del-phy-power-chg-quirk");
 
        dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
                                "snps,tx_de_emphasis_quirk");
@@ -972,17 +1074,9 @@ static int dwc3_probe(struct platform_device *pdev)
                goto err2;
        }
 
-       if (IS_ENABLED(CONFIG_USB_DWC3_HOST) &&
-                       (dwc->dr_mode == USB_DR_MODE_OTG ||
-                                       dwc->dr_mode == USB_DR_MODE_UNKNOWN))
-               dwc->dr_mode = USB_DR_MODE_HOST;
-       else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET) &&
-                       (dwc->dr_mode == USB_DR_MODE_OTG ||
-                                       dwc->dr_mode == USB_DR_MODE_UNKNOWN))
-               dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
-
-       if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
-               dwc->dr_mode = USB_DR_MODE_OTG;
+       ret = dwc3_get_dr_mode(dwc);
+       if (ret)
+               goto err3;
 
        ret = dwc3_alloc_scratch_buffers(dwc);
        if (ret)
This page took 0.025877 seconds and 5 git commands to generate.