usb: phy2: analog tuning for aml-phy
authorJianxin Qin <jianxin.qin@amlogic.com>
Thu, 10 May 2018 06:50:56 +0000 (14:50 +0800)
committerYixun Lan <yixun.lan@amlogic.com>
Wed, 16 May 2018 08:08:45 +0000 (01:08 -0700)
PD#164286: usb: phy2: analog tuning for aml-phy

Packet lost occures with high probability in High Speed mode, This patch
re-configurate PHY parameters for improving this issue.

Change-Id: If51d300a01d8c30dce27454ad887a0d14f2d1e52
Signed-off-by: Jianxin Qin <jianxin.qin@amlogic.com>
13 files changed:
arch/arm64/boot/dts/amlogic/mesong12a.dtsi
drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.c
drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.h
drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.h
drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.c
drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.h
drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_intr.c
drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_linux.c
drivers/amlogic/usb/phy/phy-aml-new-usb2-v2.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.h
include/linux/amlogic/usb-v2.h

index 4fee85d..d1452e6 100644 (file)
                pll-setting-1 = <0x09400414>;
                pll-setting-2 = <0x927E0000>;
                pll-setting-3 = <0xac5f49e5>;
+               pll-setting-4 = <0xfe18>;
+               pll-setting-5 = <0xfff>;
+               pll-setting-6 = <0xc8000>;
+               pll-setting-7 = <0xe0004>;
+               pll-setting-8 = <0xe000c>;
        };
 
        usb3_phy_v2: usb3phy@ffe09080 {
index 3b5e462..b21d3a8 100644 (file)
@@ -348,6 +348,9 @@ void dwc_otg_cil_remove(dwc_otg_core_if_t *core_if)
        if (core_if->srp_timer)
                DWC_TIMER_FREE(core_if->srp_timer);
 
+       if (core_if->device_connect_timer)
+               DWC_TIMER_FREE(core_if->device_connect_timer);
+
        DWC_FREE(core_if);
        core_if = NULL;
 }
@@ -1560,6 +1563,8 @@ void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t *core_if)
        intr_mask.b.enumdone = 1;
        /* Disable Disconnect interrupt in Device mode */
        intr_mask.b.disconnect = 0;
+       if (core_if->phy_interface == 0)
+               intr_mask.b.sofintr = 1;
 
        if (!core_if->multiproc_int_enable) {
                intr_mask.b.inepintr = 1;
index 454dce8..d438e47 100644 (file)
@@ -1059,6 +1059,8 @@ struct dwc_otg_core_if {
        int controller_type;
 
        uint32_t phy_interface;
+
+       dwc_timer_t *device_connect_timer;
 };
 
 #ifdef DEBUG
index ce90831..897f515 100644 (file)
@@ -89,7 +89,6 @@ typedef struct dwc_otg_device {
 
        struct delayed_work     work;
 
-       u32 host_plug;
 } dwc_otg_device_t;
 
 /*We must clear S3C24XX_EINTPEND external interrupt register
index e54e214..cb6ae09 100644 (file)
@@ -1157,6 +1157,16 @@ static void srp_timeout(void *ptr)
        }
 }
 
+static void sof_timeout(void *ptr)
+{
+#ifdef CONFIG_AMLOGIC_USB3PHY
+       dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
+
+       if (core_if->phy_interface == 0)
+               set_usb_phy_device_tuning(1, 1);
+#endif
+}
+
 /**
  * Tasklet
  *
@@ -1361,6 +1371,10 @@ dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t *core_if)
        /* Initialize SRP timer */
        core_if->srp_timer = DWC_TIMER_ALLOC("SRP TIMER", srp_timeout, core_if);
 
+       /* Initialize SRP timer */
+       core_if->device_connect_timer =
+               DWC_TIMER_ALLOC("DEVICE CONNECT TIMER", sof_timeout, core_if);
+
        if (core_if->core_params->dev_out_nak) {
                /**
                * Initialize xfer timeout timer. Implemented for
index 3439d72..ba54785 100644 (file)
@@ -274,5 +274,8 @@ void dwc_otg_iso_buffer_done(dwc_otg_pcd_t *pcd, dwc_otg_pcd_ep_t *ep,
                             void *req_handle);
 
 extern void do_test_mode(void *data);
+#ifdef CONFIG_AMLOGIC_USB3PHY
+extern void set_usb_phy_device_tuning(int port, int default_val);
+#endif
 #endif
 #endif /* DWC_HOST_ONLY */
index e5c8644..9066ca3 100644 (file)
@@ -298,12 +298,15 @@ int32_t dwc_otg_pcd_handle_sof_intr(dwc_otg_pcd_t *pcd)
        gintsts_data_t gintsts;
 
        DWC_DEBUGPL(DBG_PCD, "SOF\n");
+       DWC_TIMER_CANCEL(core_if->device_connect_timer);
 
        /* Clear interrupt */
        gintsts.d32 = 0;
        gintsts.b.sofintr = 1;
        DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
 
+       DWC_TIMER_SCHEDULE(core_if->device_connect_timer, 10);
+
        return 1;
 }
 
@@ -852,6 +855,10 @@ int32_t dwc_otg_pcd_handle_usb_reset_intr(dwc_otg_pcd_t *pcd)
        core_if->otg_sts = 0;
 
        DWC_PRINTF("USB RESET\n");
+
+       if (core_if->phy_interface == 0)
+               DWC_TIMER_SCHEDULE(core_if->device_connect_timer, 100);
+
 #ifdef DWC_EN_ISOC
        for (i = 1; i < 16; ++i) {
                dwc_otg_pcd_ep_t *ep;
@@ -1057,21 +1064,24 @@ int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t *pcd)
            GET_CORE_IF(pcd)->core_global_regs;
        uint8_t utmi16b, utmi8b;
        int speed;
-       dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
 
        DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n");
-       if (core_if->controller_type == USB_OTG) {
-               if (core_if->phy_interface == 0) {
-                       if (pcd->otg_dev->host_plug) {
-                               gintsts.d32 = 0;
-                               gintsts.b.enumdone = 1;
-                               DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
-                                       core_global_regs->gintsts, gintsts.d32);
-                               DWC_DEBUGPL(DBG_PCD, "false speed emun\n");
-                               return 1;
-                       }
+
+#ifdef CONFIG_AMLOGIC_USB3PHY
+       if (GET_CORE_IF(pcd)->phy_interface == 0) {
+               speed = get_device_speed(GET_CORE_IF(pcd));
+               if (speed != USB_SPEED_HIGH) {
+                       gintsts.d32 = 0;
+                       gintsts.b.enumdone = 1;
+                       DWC_WRITE_REG32(&GET_CORE_IF(pcd)->
+                               core_global_regs->gintsts, gintsts.d32);
+                       DWC_DEBUGPL(DBG_PCD, "false speed emun\n");
+                       return 1;
                }
+
+               set_usb_phy_device_tuning(1, 0);
        }
+#endif
 
        if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_2_60a) {
                utmi16b = 6;
index 0565f09..868281f 100644 (file)
@@ -1265,13 +1265,11 @@ int dwc_usb_change(struct notifier_block *nb,
 
        if (value) {
                DWC_DEBUGPL(DBG_PCDV, "start usb device\n");
-               otg_dev->host_plug = 0;
                dwc_otg_enable_global_interrupts(otg_dev->core_if);
                if (otg_dev->core_if->phy_interface == 0)
                        dwc_otg_enable_device_interrupts(otg_dev->core_if);
                otg_dev->pcd->core_if->pcd_cb->start(otg_dev->pcd);
        } else {
-               otg_dev->host_plug = 1;
                DWC_DEBUGPL(DBG_PCDV, "stop usb device\n");
                dwc_otg_disable_global_interrupts(otg_dev->core_if);
 
index 1fdf8f9..7ffdd26 100644 (file)
 #include <linux/amlogic/usb-v2.h>
 #include "phy-aml-new-usb-v2.h"
 
+struct amlogic_usb_v2  *g_phy2_v2;
+
+void set_usb_phy_host_tuning(int port, int default_val)
+{
+       void __iomem    *phy_reg_base;
+
+       if (!g_phy2_v2)
+               return;
+       if (port > g_phy2_v2->portnum)
+               return;
+       if (default_val == g_phy2_v2->phy_cfg_state[port])
+               return;
+
+       phy_reg_base = g_phy2_v2->phy_cfg[port];
+       dev_info(g_phy2_v2->dev, "---%s port(%d) tuning for host cf(%pf)--\n",
+               default_val ? "Recovery" : "Set",
+               port, __builtin_return_address(0));
+       if (!default_val) {
+               writel(g_phy2_v2->pll_setting[3], phy_reg_base + 0x50);
+               writel(g_phy2_v2->pll_setting[4], phy_reg_base + 0x10);
+               writel(g_phy2_v2->pll_setting[6], phy_reg_base + 0x38);
+               writel(g_phy2_v2->pll_setting[5], phy_reg_base + 0x34);
+       } else {
+               writel(0, phy_reg_base + 0x38);
+               writel(g_phy2_v2->pll_setting[5], phy_reg_base + 0x34);
+       }
+       g_phy2_v2->phy_cfg_state[port] = default_val;
+}
+
+void set_usb_phy_device_tuning(int port, int default_val)
+{
+       void __iomem    *phy_reg_base;
+
+       if (!g_phy2_v2)
+               return;
+       if (port > g_phy2_v2->portnum)
+               return;
+       if (default_val == g_phy2_v2->phy_cfg_state[port])
+               return;
+
+       phy_reg_base = g_phy2_v2->phy_cfg[port];
+       dev_info(g_phy2_v2->dev, "---%s port(%d) tuning for device cf(%pf)--\n",
+               default_val ? "Recovery" : "Set",
+               port, __builtin_return_address(0));
+       if (!default_val) {
+               writel(g_phy2_v2->pll_setting[3], phy_reg_base + 0x50);
+               writel(g_phy2_v2->pll_setting[4], phy_reg_base + 0x10);
+               writel(g_phy2_v2->pll_setting[7], phy_reg_base + 0x38);
+               writel(g_phy2_v2->pll_setting[5], phy_reg_base + 0x34);
+       } else {
+               writel(0, phy_reg_base + 0x38);
+               writel(g_phy2_v2->pll_setting[5], phy_reg_base + 0x34);
+       }
+       g_phy2_v2->phy_cfg_state[port] = default_val;
+}
+
+
 void set_usb_pll(struct amlogic_usb_v2 *phy, void __iomem      *reg)
 {
        /* TO DO set usb  PLL */
@@ -141,7 +198,7 @@ static int amlogic_new_usb2_probe(struct platform_device *pdev)
        const void *prop;
        int i = 0;
        u32 retval;
-       u32 pll_setting[3];
+       u32 pll_setting[8];
 
        prop = of_get_property(dev->of_node, "portnum", NULL);
        if (prop)
@@ -195,6 +252,31 @@ static int amlogic_new_usb2_probe(struct platform_device *pdev)
        if (retval < 0)
                return -EINVAL;
 
+       retval = of_property_read_u32(dev->of_node,
+               "pll-setting-4", &(pll_setting[3]));
+       if (retval < 0)
+               return -EINVAL;
+
+       retval = of_property_read_u32(dev->of_node,
+               "pll-setting-5", &(pll_setting[4]));
+       if (retval < 0)
+               return -EINVAL;
+
+       retval = of_property_read_u32(dev->of_node,
+               "pll-setting-6", &(pll_setting[5]));
+       if (retval < 0)
+               return -EINVAL;
+
+       retval = of_property_read_u32(dev->of_node,
+                       "pll-setting-7", &(pll_setting[6]));
+       if (retval < 0)
+               return -EINVAL;
+
+       retval = of_property_read_u32(dev->of_node,
+                       "pll-setting-8", &(pll_setting[7]));
+       if (retval < 0)
+               return -EINVAL;
+
        dev_info(&pdev->dev, "USB2 phy probe:phy_mem:0x%lx, iomap phy_base:0x%lx\n",
                        (unsigned long)phy_mem->start, (unsigned long)phy_base);
 
@@ -211,9 +293,17 @@ static int amlogic_new_usb2_probe(struct platform_device *pdev)
        phy->pll_setting[0] = pll_setting[0];
        phy->pll_setting[1] = pll_setting[1];
        phy->pll_setting[2] = pll_setting[2];
+       phy->pll_setting[3] = pll_setting[3];
+       phy->pll_setting[4] = pll_setting[4];
+       phy->pll_setting[5] = pll_setting[5];
+       phy->pll_setting[6] = pll_setting[6];
+       phy->pll_setting[7] = pll_setting[7];
        phy->suspend_flag = 0;
-       for (i = 0; i < portnum; i++)
+       for (i = 0; i < portnum; i++) {
                phy->phy_cfg[i] = phy_cfg_base[i];
+               /* set port default tuning state */
+               phy->phy_cfg_state[i] = 1;
+       }
 
        usb_add_phy_dev(&phy->phy);
 
@@ -221,6 +311,8 @@ static int amlogic_new_usb2_probe(struct platform_device *pdev)
 
        pm_runtime_enable(phy->dev);
 
+       g_phy2_v2 = phy;
+
        return 0;
 }
 
index 39e52eb..13d74b6 100644 (file)
@@ -551,6 +551,11 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
        port_status = readl(addr);
        xhci_dbg(xhci, "clear port %s change, actual port %d status  = 0x%x\n",
                        port_change_bit, wIndex, port_status);
+#ifdef CONFIG_AMLOGIC_USB
+       if (DEV_HIGHSPEED(port_status) &&
+               (wValue == USB_PORT_FEAT_C_RESET))
+               set_usb_phy_host_tuning(wIndex, 0);
+#endif
 }
 
 static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
index 6f67e3c..8b1e766 100644 (file)
@@ -1706,6 +1706,10 @@ cleanup:
         * bits are still set.  When an event occurs, switch over to
         * polling to avoid losing status changes.
         */
+#ifdef CONFIG_AMLOGIC_USB
+       if (!(temp & PORT_CONNECT) || !(temp & PORT_PE))
+               set_usb_phy_host_tuning(faked_port_index, 1);
+#endif
        xhci_dbg(xhci, "%s: starting port polling.\n", __func__);
        set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
        spin_unlock(&xhci->lock);
index fd33bfc..08fe97a 100644 (file)
@@ -2012,6 +2012,7 @@ int xhci_start(struct xhci_hcd *xhci);
 int xhci_test_single_step(struct xhci_hcd *xhci, gfp_t mem_flags,
                struct urb *urb, int slot_id,
                unsigned int ep_index, int testflag);
+extern void set_usb_phy_host_tuning(int port, int default_val);
 #endif
 
 #endif /* __LINUX_XHCI_HCD_H */
index 25a68cd..b0be477 100644 (file)
@@ -169,7 +169,8 @@ struct amlogic_usb_v2 {
        void __iomem    *phy3_cfg_r4;
        void __iomem    *phy3_cfg_r5;
        void __iomem    *usb2_phy_cfg;
-       u32 pll_setting[3];
+       u32 pll_setting[8];
+       int phy_cfg_state[4];
        /* Set VBus Power though GPIO */
        int vbus_power_pin;
        int vbus_power_pin_work_mask;