common: Drop linux/delay.h from common header
[oweals/u-boot.git] / drivers / usb / dwc3 / core.c
index 2498f0efb1a488aee4854e51072852fde5ad8a4f..8d418c9412bb78b6196489dee62adee7611b38f8 100644 (file)
  */
 
 #include <common.h>
+#include <cpu_func.h>
 #include <malloc.h>
 #include <dwc3-uboot.h>
-#include <asm/dma-mapping.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
 #include <linux/ioport.h>
 #include <dm.h>
 #include <generic-phy.h>
@@ -284,8 +290,8 @@ static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
        return 0;
 
 err1:
-       dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch *
-                        DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
+       dma_unmap_single(scratch_addr, dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
+                        DMA_BIDIRECTIONAL);
 
 err0:
        return ret;
@@ -299,7 +305,7 @@ static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
        if (!dwc->nr_scratch)
                return;
 
-       dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch *
+       dma_unmap_single(dwc->scratch_addr, dwc->nr_scratch *
                         DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
        kfree(dwc->scratchbuf);
 }
@@ -373,6 +379,9 @@ static void 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);
 
        mdelay(100);
@@ -581,6 +590,12 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
        return 0;
 }
 
+static void dwc3_gadget_run(struct dwc3 *dwc)
+{
+       dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_RUN_STOP);
+       mdelay(100);
+}
+
 static void dwc3_core_exit_mode(struct dwc3 *dwc)
 {
        switch (dwc->dr_mode) {
@@ -598,6 +613,42 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
                /* do nothing */
                break;
        }
+
+       /*
+        * switch back to peripheral mode
+        * This enables the phy to enter idle and then, if enabled, suspend.
+        */
+       dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+       dwc3_gadget_run(dwc);
+}
+
+static void dwc3_uboot_hsphy_mode(struct dwc3_device *dwc3_dev,
+                                 struct dwc3 *dwc)
+{
+       enum usb_phy_interface hsphy_mode = dwc3_dev->hsphy_mode;
+       u32 reg;
+
+       /* Set dwc3 usb2 phy config */
+       reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+
+       switch (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;
+       }
+
+       dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 }
 
 #define DWC3_ALIGN_MASK                (16 - 1)
@@ -669,6 +720,7 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
        dwc->rx_detect_poll_quirk = dwc3_dev->rx_detect_poll_quirk;
        dwc->dis_u3_susphy_quirk = dwc3_dev->dis_u3_susphy_quirk;
        dwc->dis_u2_susphy_quirk = dwc3_dev->dis_u2_susphy_quirk;
+       dwc->dis_del_phy_power_chg_quirk = dwc3_dev->dis_del_phy_power_chg_quirk;
 
        dwc->tx_de_emphasis_quirk = dwc3_dev->tx_de_emphasis_quirk;
        if (dwc3_dev->tx_de_emphasis)
@@ -694,9 +746,9 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
                return -ENOMEM;
        }
 
-       if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
+       if (!IS_ENABLED(CONFIG_USB_DWC3_GADGET))
                dwc->dr_mode = USB_DR_MODE_HOST;
-       else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
+       else if (!IS_ENABLED(CONFIG_USB_HOST))
                dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
 
        if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
@@ -708,6 +760,8 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
                goto err0;
        }
 
+       dwc3_uboot_hsphy_mode(dwc3_dev, dwc);
+
        ret = dwc3_event_buffers_setup(dwc);
        if (ret) {
                dev_err(dwc->dev, "failed to setup event buffers\n");
@@ -790,91 +844,103 @@ MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
 
 #if CONFIG_IS_ENABLED(PHY) && CONFIG_IS_ENABLED(DM_USB)
-int dwc3_setup_phy(struct udevice *dev, struct phy **array, int *num_phys)
+int dwc3_setup_phy(struct udevice *dev, struct phy_bulk *phys)
 {
-       int i, ret, count;
-       struct phy *usb_phys;
-
-       /* Return if no phy declared */
-       if (!dev_read_prop(dev, "phys", NULL))
-               return 0;
-       count = dev_count_phandle_with_args(dev, "phys", "#phy-cells");
-       if (count <= 0)
-               return count;
-
-       usb_phys = devm_kcalloc(dev, count, sizeof(struct phy),
-                               GFP_KERNEL);
-       if (!usb_phys)
-               return -ENOMEM;
-
-       for (i = 0; i < count; i++) {
-               ret = generic_phy_get_by_index(dev, i, &usb_phys[i]);
-               if (ret && ret != -ENOENT) {
-                       pr_err("Failed to get USB PHY%d for %s\n",
-                              i, dev->name);
-                       return ret;
-               }
-       }
-
-       for (i = 0; i < count; i++) {
-               ret = generic_phy_init(&usb_phys[i]);
-               if (ret) {
-                       pr_err("Can't init USB PHY%d for %s\n",
-                              i, dev->name);
-                       goto phys_init_err;
-               }
-       }
-
-       for (i = 0; i < count; i++) {
-               ret = generic_phy_power_on(&usb_phys[i]);
-               if (ret) {
-                       pr_err("Can't power USB PHY%d for %s\n",
-                              i, dev->name);
-                       goto phys_poweron_err;
-               }
-       }
+       int ret;
 
-       *array = usb_phys;
-       *num_phys =  count;
-       return 0;
+       ret = generic_phy_get_bulk(dev, phys);
+       if (ret)
+               return ret;
 
-phys_poweron_err:
-       for (i = count - 1; i >= 0; i--)
-               generic_phy_power_off(&usb_phys[i]);
+       ret = generic_phy_init_bulk(phys);
+       if (ret)
+               return ret;
 
-       for (i = 0; i < count; i++)
-               generic_phy_exit(&usb_phys[i]);
+       ret = generic_phy_power_on_bulk(phys);
+       if (ret)
+               generic_phy_exit_bulk(phys);
 
        return ret;
+}
 
-phys_init_err:
-       for (; i >= 0; i--)
-               generic_phy_exit(&usb_phys[i]);
+int dwc3_shutdown_phy(struct udevice *dev, struct phy_bulk *phys)
+{
+       int ret;
 
+       ret = generic_phy_power_off_bulk(phys);
+       ret |= generic_phy_exit_bulk(phys);
        return ret;
 }
+#endif
 
-int dwc3_shutdown_phy(struct udevice *dev, struct phy *usb_phys, int num_phys)
+#if CONFIG_IS_ENABLED(DM_USB)
+void dwc3_of_parse(struct dwc3 *dwc)
 {
-       int i, ret;
+       const u8 *tmp;
+       struct udevice *dev = dwc->dev;
+       u8 lpm_nyet_threshold;
+       u8 tx_de_emphasis;
+       u8 hird_threshold;
 
-       for (i = 0; i < num_phys; i++) {
-               if (!generic_phy_valid(&usb_phys[i]))
-                       continue;
+       /* default to highest possible threshold */
+       lpm_nyet_threshold = 0xff;
 
-               ret = generic_phy_power_off(&usb_phys[i]);
-               ret |= generic_phy_exit(&usb_phys[i]);
-               if (ret) {
-                       pr_err("Can't shutdown USB PHY%d for %s\n",
-                              i, dev->name);
-               }
-       }
+       /* default to -3.5dB de-emphasis */
+       tx_de_emphasis = 1;
 
-       return 0;
+       /*
+        * default to assert utmi_sleep_n and use maximum allowed HIRD
+        * threshold value of 0b1100
+        */
+       hird_threshold = 12;
+
+       dwc->has_lpm_erratum = dev_read_bool(dev,
+                               "snps,has-lpm-erratum");
+       tmp = dev_read_u8_array_ptr(dev, "snps,lpm-nyet-threshold", 1);
+       if (tmp)
+               lpm_nyet_threshold = *tmp;
+
+       dwc->is_utmi_l1_suspend = dev_read_bool(dev,
+                               "snps,is-utmi-l1-suspend");
+       tmp = dev_read_u8_array_ptr(dev, "snps,hird-threshold", 1);
+       if (tmp)
+               hird_threshold = *tmp;
+
+       dwc->disable_scramble_quirk = dev_read_bool(dev,
+                               "snps,disable_scramble_quirk");
+       dwc->u2exit_lfps_quirk = dev_read_bool(dev,
+                               "snps,u2exit_lfps_quirk");
+       dwc->u2ss_inp3_quirk = dev_read_bool(dev,
+                               "snps,u2ss_inp3_quirk");
+       dwc->req_p1p2p3_quirk = dev_read_bool(dev,
+                               "snps,req_p1p2p3_quirk");
+       dwc->del_p1p2p3_quirk = dev_read_bool(dev,
+                               "snps,del_p1p2p3_quirk");
+       dwc->del_phy_power_chg_quirk = dev_read_bool(dev,
+                               "snps,del_phy_power_chg_quirk");
+       dwc->lfps_filter_quirk = dev_read_bool(dev,
+                               "snps,lfps_filter_quirk");
+       dwc->rx_detect_poll_quirk = dev_read_bool(dev,
+                               "snps,rx_detect_poll_quirk");
+       dwc->dis_u3_susphy_quirk = dev_read_bool(dev,
+                               "snps,dis_u3_susphy_quirk");
+       dwc->dis_u2_susphy_quirk = dev_read_bool(dev,
+                               "snps,dis_u2_susphy_quirk");
+       dwc->dis_del_phy_power_chg_quirk = dev_read_bool(dev,
+                               "snps,dis-del-phy-power-chg-quirk");
+       dwc->tx_de_emphasis_quirk = dev_read_bool(dev,
+                               "snps,tx_de_emphasis_quirk");
+       tmp = dev_read_u8_array_ptr(dev, "snps,tx_de_emphasis", 1);
+       if (tmp)
+               tx_de_emphasis = *tmp;
+
+       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);
 }
-#endif
 
-#if CONFIG_IS_ENABLED(DM_USB_GADGET)
 int dwc3_init(struct dwc3 *dwc)
 {
        int ret;