Merge tag 'modules-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[firefly-linux-kernel-4.4.55.git] / drivers / usb / dwc3 / core.c
index b0f4d52b7f04a023b6d743c686a54eace4797047..25ddc39efad880ca05ce2ab7bbe55523be66d8c6 100644 (file)
@@ -19,6 +19,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -32,6 +33,7 @@
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/of.h>
+#include <linux/acpi.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -362,6 +364,72 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
        parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
 }
 
+/**
+ * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
+ * @dwc: Pointer to our controller context structure
+ */
+static void dwc3_phy_setup(struct dwc3 *dwc)
+{
+       u32 reg;
+
+       reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+
+       /*
+        * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
+        * to '0' during coreConsultant configuration. So default value
+        * will be '0' when the core is reset. Application needs to set it
+        * to '1' after the core initialization is completed.
+        */
+       if (dwc->revision > DWC3_REVISION_194A)
+               reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+
+       if (dwc->u2ss_inp3_quirk)
+               reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
+
+       if (dwc->req_p1p2p3_quirk)
+               reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
+
+       if (dwc->del_p1p2p3_quirk)
+               reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN;
+
+       if (dwc->del_phy_power_chg_quirk)
+               reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE;
+
+       if (dwc->lfps_filter_quirk)
+               reg |= DWC3_GUSB3PIPECTL_LFPSFILT;
+
+       if (dwc->rx_detect_poll_quirk)
+               reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL;
+
+       if (dwc->tx_de_emphasis_quirk)
+               reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
+
+       if (dwc->dis_u3_susphy_quirk)
+               reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
+
+       dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+       mdelay(100);
+
+       reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+
+       /*
+        * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
+        * '0' during coreConsultant configuration. So default value will
+        * be '0' when the core is reset. Application needs to set it to
+        * '1' after the core initialization is completed.
+        */
+       if (dwc->revision > DWC3_REVISION_194A)
+               reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+
+       if (dwc->dis_u2_susphy_quirk)
+               reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+
+       dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+       mdelay(100);
+}
+
 /**
  * dwc3_core_init - Low-level initialization of DWC3 Core
  * @dwc: Pointer to our controller context structure
@@ -384,6 +452,12 @@ static int dwc3_core_init(struct dwc3 *dwc)
        }
        dwc->revision = reg;
 
+       /*
+        * Write Linux Version Code to our GUID register so it's easy to figure
+        * out which kernel version a bug was found.
+        */
+       dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
+
        /* Handle USB2.0-only core configuration */
        if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
                        DWC3_GHWPARAMS3_SSPHY_IFC_DIS) {
@@ -414,7 +488,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
 
        reg = dwc3_readl(dwc->regs, DWC3_GCTL);
        reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
-       reg &= ~DWC3_GCTL_DISSCRAMBLE;
 
        switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
        case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
@@ -441,11 +514,34 @@ static int dwc3_core_init(struct dwc3 *dwc)
        case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
                /* enable hibernation here */
                dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
+
+               /*
+                * REVISIT Enabling this bit so that host-mode hibernation
+                * will work. Device-mode hibernation is not yet implemented.
+                */
+               reg |= DWC3_GCTL_GBLHIBERNATIONEN;
                break;
        default:
                dev_dbg(dwc->dev, "No power optimization available\n");
        }
 
+       /* check if current dwc3 is on simulation board */
+       if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
+               dev_dbg(dwc->dev, "it is on FPGA board\n");
+               dwc->is_fpga = true;
+       }
+
+       WARN_ONCE(dwc->disable_scramble_quirk && !dwc->is_fpga,
+                       "disable_scramble cannot be used on non-FPGA builds\n");
+
+       if (dwc->disable_scramble_quirk && dwc->is_fpga)
+               reg |= DWC3_GCTL_DISSCRAMBLE;
+       else
+               reg &= ~DWC3_GCTL_DISSCRAMBLE;
+
+       if (dwc->u2exit_lfps_quirk)
+               reg |= DWC3_GCTL_U2EXIT_LFPS;
+
        /*
         * WORKAROUND: DWC3 revisions <1.90a have a bug
         * where the device can fail to connect at SuperSpeed
@@ -459,6 +555,8 @@ static int dwc3_core_init(struct dwc3 *dwc)
 
        dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 
+       dwc3_phy_setup(dwc);
+
        ret = dwc3_alloc_scratch_buffers(dwc);
        if (ret)
                goto err1;
@@ -630,6 +728,9 @@ static int dwc3_probe(struct platform_device *pdev)
        struct device_node      *node = dev->of_node;
        struct resource         *res;
        struct dwc3             *dwc;
+       u8                      lpm_nyet_threshold;
+       u8                      tx_de_emphasis;
+       u8                      hird_threshold;
 
        int                     ret;
 
@@ -685,22 +786,96 @@ static int dwc3_probe(struct platform_device *pdev)
         */
        res->start -= DWC3_GLOBALS_REGS_START;
 
+       /* default to highest possible threshold */
+       lpm_nyet_threshold = 0xff;
+
+       /* default to -3.5dB de-emphasis */
+       tx_de_emphasis = 1;
+
+       /*
+        * default to assert utmi_sleep_n and use maximum allowed HIRD
+        * threshold value of 0b1100
+        */
+       hird_threshold = 12;
+
        if (node) {
                dwc->maximum_speed = of_usb_get_maximum_speed(node);
-
-               dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
+               dwc->has_lpm_erratum = of_property_read_bool(node,
+                               "snps,has-lpm-erratum");
+               of_property_read_u8(node, "snps,lpm-nyet-threshold",
+                               &lpm_nyet_threshold);
+               dwc->is_utmi_l1_suspend = of_property_read_bool(node,
+                               "snps,is-utmi-l1-suspend");
+               of_property_read_u8(node, "snps,hird-threshold",
+                               &hird_threshold);
+
+               dwc->needs_fifo_resize = of_property_read_bool(node,
+                               "tx-fifo-resize");
                dwc->dr_mode = of_usb_get_dr_mode(node);
+
+               dwc->disable_scramble_quirk = of_property_read_bool(node,
+                               "snps,disable_scramble_quirk");
+               dwc->u2exit_lfps_quirk = of_property_read_bool(node,
+                               "snps,u2exit_lfps_quirk");
+               dwc->u2ss_inp3_quirk = of_property_read_bool(node,
+                               "snps,u2ss_inp3_quirk");
+               dwc->req_p1p2p3_quirk = of_property_read_bool(node,
+                               "snps,req_p1p2p3_quirk");
+               dwc->del_p1p2p3_quirk = of_property_read_bool(node,
+                               "snps,del_p1p2p3_quirk");
+               dwc->del_phy_power_chg_quirk = of_property_read_bool(node,
+                               "snps,del_phy_power_chg_quirk");
+               dwc->lfps_filter_quirk = of_property_read_bool(node,
+                               "snps,lfps_filter_quirk");
+               dwc->rx_detect_poll_quirk = of_property_read_bool(node,
+                               "snps,rx_detect_poll_quirk");
+               dwc->dis_u3_susphy_quirk = of_property_read_bool(node,
+                               "snps,dis_u3_susphy_quirk");
+               dwc->dis_u2_susphy_quirk = of_property_read_bool(node,
+                               "snps,dis_u2_susphy_quirk");
+
+               dwc->tx_de_emphasis_quirk = of_property_read_bool(node,
+                               "snps,tx_de_emphasis_quirk");
+               of_property_read_u8(node, "snps,tx_de_emphasis",
+                               &tx_de_emphasis);
        } else if (pdata) {
                dwc->maximum_speed = pdata->maximum_speed;
+               dwc->has_lpm_erratum = pdata->has_lpm_erratum;
+               if (pdata->lpm_nyet_threshold)
+                       lpm_nyet_threshold = pdata->lpm_nyet_threshold;
+               dwc->is_utmi_l1_suspend = pdata->is_utmi_l1_suspend;
+               if (pdata->hird_threshold)
+                       hird_threshold = pdata->hird_threshold;
 
                dwc->needs_fifo_resize = pdata->tx_fifo_resize;
                dwc->dr_mode = pdata->dr_mode;
+
+               dwc->disable_scramble_quirk = pdata->disable_scramble_quirk;
+               dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk;
+               dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk;
+               dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk;
+               dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk;
+               dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk;
+               dwc->lfps_filter_quirk = pdata->lfps_filter_quirk;
+               dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk;
+               dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk;
+               dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
+
+               dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
+               if (pdata->tx_de_emphasis)
+                       tx_de_emphasis = pdata->tx_de_emphasis;
        }
 
        /* default to superspeed if no maximum_speed passed */
        if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
                dwc->maximum_speed = USB_SPEED_SUPER;
 
+       dwc->lpm_nyet_threshold = lpm_nyet_threshold;
+       dwc->tx_de_emphasis = tx_de_emphasis;
+
+       dwc->hird_threshold = hird_threshold
+               | (dwc->is_utmi_l1_suspend << 4);
+
        ret = dwc3_core_get_phy(dwc);
        if (ret)
                return ret;
@@ -708,9 +883,11 @@ static int dwc3_probe(struct platform_device *pdev)
        spin_lock_init(&dwc->lock);
        platform_set_drvdata(pdev, dwc);
 
-       dev->dma_mask   = dev->parent->dma_mask;
-       dev->dma_parms  = dev->parent->dma_parms;
-       dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
+       if (!dev->dma_mask) {
+               dev->dma_mask = dev->parent->dma_mask;
+               dev->dma_parms = dev->parent->dma_parms;
+               dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
+       }
 
        pm_runtime_enable(dev);
        pm_runtime_get_sync(dev);
@@ -815,50 +992,6 @@ static int dwc3_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM_SLEEP
-static int dwc3_prepare(struct device *dev)
-{
-       struct dwc3     *dwc = dev_get_drvdata(dev);
-       unsigned long   flags;
-
-       spin_lock_irqsave(&dwc->lock, flags);
-
-       switch (dwc->dr_mode) {
-       case USB_DR_MODE_PERIPHERAL:
-       case USB_DR_MODE_OTG:
-               dwc3_gadget_prepare(dwc);
-               /* FALLTHROUGH */
-       case USB_DR_MODE_HOST:
-       default:
-               dwc3_event_buffers_cleanup(dwc);
-               break;
-       }
-
-       spin_unlock_irqrestore(&dwc->lock, flags);
-
-       return 0;
-}
-
-static void dwc3_complete(struct device *dev)
-{
-       struct dwc3     *dwc = dev_get_drvdata(dev);
-       unsigned long   flags;
-
-       spin_lock_irqsave(&dwc->lock, flags);
-
-       dwc3_event_buffers_setup(dwc);
-       switch (dwc->dr_mode) {
-       case USB_DR_MODE_PERIPHERAL:
-       case USB_DR_MODE_OTG:
-               dwc3_gadget_complete(dwc);
-               /* FALLTHROUGH */
-       case USB_DR_MODE_HOST:
-       default:
-               break;
-       }
-
-       spin_unlock_irqrestore(&dwc->lock, flags);
-}
-
 static int dwc3_suspend(struct device *dev)
 {
        struct dwc3     *dwc = dev_get_drvdata(dev);
@@ -873,7 +1006,7 @@ static int dwc3_suspend(struct device *dev)
                /* FALLTHROUGH */
        case USB_DR_MODE_HOST:
        default:
-               /* do nothing */
+               dwc3_event_buffers_cleanup(dwc);
                break;
        }
 
@@ -906,6 +1039,7 @@ static int dwc3_resume(struct device *dev)
 
        spin_lock_irqsave(&dwc->lock, flags);
 
+       dwc3_event_buffers_setup(dwc);
        dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
 
        switch (dwc->dr_mode) {
@@ -934,9 +1068,6 @@ err_usb2phy_init:
 }
 
 static const struct dev_pm_ops dwc3_dev_pm_ops = {
-       .prepare        = dwc3_prepare,
-       .complete       = dwc3_complete,
-
        SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
 };
 
@@ -958,12 +1089,24 @@ static const struct of_device_id of_dwc3_match[] = {
 MODULE_DEVICE_TABLE(of, of_dwc3_match);
 #endif
 
+#ifdef CONFIG_ACPI
+
+#define ACPI_ID_INTEL_BSW      "808622B7"
+
+static const struct acpi_device_id dwc3_acpi_match[] = {
+       { ACPI_ID_INTEL_BSW, 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
+#endif
+
 static struct platform_driver dwc3_driver = {
        .probe          = dwc3_probe,
        .remove         = dwc3_remove,
        .driver         = {
                .name   = "dwc3",
                .of_match_table = of_match_ptr(of_dwc3_match),
+               .acpi_match_table = ACPI_PTR(dwc3_acpi_match),
                .pm     = DWC3_PM_OPS,
        },
 };