From 4e2ea2e9dce2d94fea932b939da79302a1a27cfd Mon Sep 17 00:00:00 2001 From: Devdutt Patnaik Date: Tue, 28 Jun 2016 16:52:31 -0700 Subject: usb: phy: qusb: Add support for host mode phy init seq Update QUSB2 HS PHY init sequence in host mode to fix enumeration issues due to port reset operation failure. Change-Id: I95daf3e3a833f9daeac6190daa33191f9db8cf26 Signed-off-by: Devdutt Patnaik --- Documentation/devicetree/bindings/usb/msm-phy.txt | 2 + drivers/usb/phy/phy-msm-qusb-v2.c | 51 +++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt index 35bb94b2ef70..83bccb7b5b31 100644 --- a/Documentation/devicetree/bindings/usb/msm-phy.txt +++ b/Documentation/devicetree/bindings/usb/msm-phy.txt @@ -172,6 +172,8 @@ Optional properties: control in device mode. The reg-names property is required if the reg property is specified. - qcom,qusb-phy-init-seq: QUSB PHY initialization sequence with value,reg pair. + - qcom,qusb-phy-host-init-seq: QUSB PHY initialization sequence for host mode + with value,reg pair. - qcom,emu-init-seq : emulation initialization sequence with value,reg pair. - qcom,phy-pll-reset-seq : emulation PLL reset sequence with value,reg pair. - qcom,emu-dcm-reset-seq : emulation DCM reset sequence with value,reg pair. diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index 1bc6b6ba4517..8b9bd10ce217 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -87,6 +87,8 @@ struct qusb_phy { int vdd_levels[3]; /* none, low, high */ int init_seq_len; int *qusb_phy_init_seq; + int host_init_seq_len; + int *qusb_phy_host_init_seq; u32 tune2_val; int tune2_efuse_bit_pos; @@ -374,6 +376,35 @@ static void qusb_phy_write_seq(void __iomem *base, u32 *seq, int cnt, } } +static void qusb_phy_host_init(struct usb_phy *phy) +{ + u8 reg; + struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); + + dev_dbg(phy->dev, "%s\n", __func__); + + /* Perform phy reset */ + clk_reset(qphy->phy_reset, CLK_RESET_ASSERT); + usleep_range(100, 150); + clk_reset(qphy->phy_reset, CLK_RESET_DEASSERT); + + qusb_phy_write_seq(qphy->base, qphy->qusb_phy_host_init_seq, + qphy->host_init_seq_len, 0); + + /* Ensure above write is completed before turning ON ref clk */ + wmb(); + + /* Require to get phy pll lock successfully */ + usleep_range(150, 160); + + reg = readb_relaxed(qphy->base + QUSB2PHY_PLL_COMMON_STATUS_ONE); + dev_dbg(phy->dev, "QUSB2PHY_PLL_COMMON_STATUS_ONE:%x\n", reg); + if (!(reg & CORE_READY_STATUS)) { + dev_err(phy->dev, "QUSB PHY PLL LOCK fails:%x\n", reg); + WARN_ON(1); + } +} + static int qusb_phy_init(struct usb_phy *phy) { struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); @@ -603,6 +634,9 @@ static int qusb_phy_notify_connect(struct usb_phy *phy, dev_dbg(phy->dev, " cable_connected=%d\n", qphy->cable_connected); + if (qphy->qusb_phy_host_init_seq && qphy->phy.flags & PHY_HOST_MODE) + qusb_phy_host_init(phy); + /* Set OTG VBUS Valid from HSPHY to controller */ qusb_write_readback(qphy->qscratch_base, HS_PHY_CTRL_REG, UTMI_OTG_VBUS_VALID, @@ -866,6 +900,23 @@ static int qusb_phy_probe(struct platform_device *pdev) } } + qphy->host_init_seq_len = of_property_count_elems_of_size(dev->of_node, + "qcom,qusb-phy-host-init-seq", + sizeof(*qphy->qusb_phy_host_init_seq)); + if (qphy->host_init_seq_len > 0) { + qphy->qusb_phy_host_init_seq = devm_kcalloc(dev, + qphy->host_init_seq_len, + sizeof(*qphy->qusb_phy_host_init_seq), + GFP_KERNEL); + if (qphy->qusb_phy_host_init_seq) + of_property_read_u32_array(dev->of_node, + "qcom,qusb-phy-host-init-seq", + qphy->qusb_phy_host_init_seq, + qphy->host_init_seq_len); + else + return -ENOMEM; + } + ret = of_property_read_u32_array(dev->of_node, "qcom,vdd-voltage-level", (u32 *) qphy->vdd_levels, ARRAY_SIZE(qphy->vdd_levels)); -- cgit v1.2.3 From 54178f48e08d9b7004aaa1a57f46319c52f4e3dc Mon Sep 17 00:00:00 2001 From: Devdutt Patnaik Date: Tue, 28 Jun 2016 16:13:52 -0700 Subject: ARM: dts: msm: Update QUSB2 PHY device node for host mode on msmcobalt Update the device node for QUSB2 PHY with the recommended register initialization sequence for host mode. This is needed to fix HS enumeration issues due to port reset failure. Change-Id: I8cfed672ff02cd61beb956116f9fcd365211cf11 Signed-off-by: Devdutt Patnaik --- arch/arm/boot/dts/qcom/msmcobalt-cdp.dts | 15 +++++++++++++++ arch/arm/boot/dts/qcom/msmcobalt-mtp.dts | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/arch/arm/boot/dts/qcom/msmcobalt-cdp.dts b/arch/arm/boot/dts/qcom/msmcobalt-cdp.dts index aebd9a1440de..c8402ba5b69a 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-cdp.dts +++ b/arch/arm/boot/dts/qcom/msmcobalt-cdp.dts @@ -21,3 +21,18 @@ compatible = "qcom,msmcobalt-cdp", "qcom,msmcobalt", "qcom,cdp"; qcom,board-id = <1 0>; }; + +&qusb_phy0 { + qcom,qusb-phy-host-init-seq = + /* value reg_offsets> */ + <0x63 0x210 + 0x13 0x04 + 0x7c 0x18c + 0x80 0x2c + 0x0a 0x184 + 0x8c 0x21c + 0x05 0x23c + 0x03 0x240 + 0xff 0x218 + 0x62 0x210>; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dts b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dts index e5708fc8d743..89ef72c104f5 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dts +++ b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dts @@ -21,3 +21,18 @@ compatible = "qcom,msmcobalt-mtp", "qcom,msmcobalt", "qcom,mtp"; qcom,board-id = <8 0>; }; + +&qusb_phy0 { + qcom,qusb-phy-host-init-seq = + /* value reg_offsets> */ + <0x63 0x210 + 0x13 0x04 + 0x7c 0x18c + 0x80 0x2c + 0x0a 0x184 + 0x8c 0x21c + 0x05 0x23c + 0x03 0x240 + 0xff 0x218 + 0x62 0x210>; +}; -- cgit v1.2.3 From 4d0a155ed7773832119d62f9450a338d0fd078ec Mon Sep 17 00:00:00 2001 From: Devdutt Patnaik Date: Mon, 20 Jun 2016 17:09:37 -0700 Subject: usb: dwc3: Determine connection speed for HS PHY DP/DM linestate is needed by the QUSB2 PHY driver to configure the polarity of DP/DM transition triggers for exiting low power mode. This was previously available via the QUSB2PHY_PORT_UTMI_STATUS PHY register which is now deprecated. In order to correctly determine the interrupt polarity we need to pass the current operating speed to the QUSB2 PHY driver. The PHY driver uses mode, speed and cable connection status to determine the linestate and configure interrupt polarities for wake up. Add logic to determine operating speed for host and device mode cases. Change-Id: Iaede1269f514a314bd9717a33100f748e7753b2a Signed-off-by: Devdutt Patnaik --- drivers/usb/dwc3/dwc3-msm.c | 32 ++++++++++++++++++++++++++++++++ include/linux/usb/msm_hsusb.h | 2 ++ 2 files changed, 34 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index f9c0b6a04224..1f597143ceb8 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -1794,6 +1794,36 @@ static void dwc3_msm_bus_vote_w(struct work_struct *w) dev_err(mdwc->dev, "Failed to reset bus bw vote %d\n", ret); } +static void dwc3_set_phy_speed_flags(struct dwc3_msm *mdwc) +{ + struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); + int i, num_ports; + u32 reg; + + mdwc->hs_phy->flags &= ~(PHY_HSFS_MODE | PHY_LS_MODE); + if (mdwc->in_host_mode) { + reg = dwc3_msm_read_reg(mdwc->base, USB3_HCSPARAMS1); + num_ports = HCS_MAX_PORTS(reg); + for (i = 0; i < num_ports; i++) { + reg = dwc3_msm_read_reg(mdwc->base, + USB3_PORTSC + i*0x10); + if (reg & PORT_PE) { + if (DEV_HIGHSPEED(reg) || DEV_FULLSPEED(reg)) + mdwc->hs_phy->flags |= PHY_HSFS_MODE; + else if (DEV_LOWSPEED(reg)) + mdwc->hs_phy->flags |= PHY_LS_MODE; + } + } + } else { + if (dwc->gadget.speed == USB_SPEED_HIGH || + dwc->gadget.speed == USB_SPEED_FULL) + mdwc->hs_phy->flags |= PHY_HSFS_MODE; + else if (dwc->gadget.speed == USB_SPEED_LOW) + mdwc->hs_phy->flags |= PHY_LS_MODE; + } +} + + static int dwc3_msm_suspend(struct dwc3_msm *mdwc) { int ret, i; @@ -1867,6 +1897,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) /* disable power event irq, hs and ss phy irq is used as wake up src */ disable_irq(mdwc->pwr_event_irq); + dwc3_set_phy_speed_flags(mdwc); /* Suspend HS PHY */ usb_phy_set_suspend(mdwc->hs_phy, 1); @@ -2016,6 +2047,7 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) mdwc->lpm_flags &= ~MDWC3_SS_PHY_SUSPEND; } + mdwc->hs_phy->flags &= ~(PHY_HSFS_MODE | PHY_LS_MODE); /* Resume HS PHY */ usb_phy_set_suspend(mdwc->hs_phy, 0); diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 89effb61d153..44b6222db9a3 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -176,6 +176,8 @@ struct msm_usb_cable { #define DEVICE_IN_SS_MODE BIT(5) #define PHY_LANE_A BIT(6) #define PHY_LANE_B BIT(7) +#define PHY_HSFS_MODE BIT(8) +#define PHY_LS_MODE BIT(9) #define USB_NUM_BUS_CLOCKS 3 -- cgit v1.2.3 From e00fec135a1e7c37f37dc25b64f6cfe6772f780e Mon Sep 17 00:00:00 2001 From: Devdutt Patnaik Date: Tue, 28 Jun 2016 16:31:45 -0700 Subject: usb: phy: qusb: Determine linestate for QUSB2 PHY Controller driver passes current speed to QUSB2 PHY driver in the flags parameter. Determine linestate using speed, mode and cable connection status. This deprecates the older mechanism where linestate was determined by reading the now obsoleted QUSB2PHY_PORT_UTMI_STATUS register. Change-Id: I682eb250964f32f93d7b31dae0291aca7fa44362 Signed-off-by: Devdutt Patnaik --- drivers/usb/phy/phy-msm-qusb-v2.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index 8b9bd10ce217..00e2ba370357 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -66,6 +66,9 @@ #define QUSB2PHY_3P3_VOL_MAX 3200000 /* uV */ #define QUSB2PHY_3P3_HPM_LOAD 30000 /* uA */ +#define LINESTATE_DP BIT(0) +#define LINESTATE_DM BIT(1) + unsigned int phy_tune2; module_param(phy_tune2, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(phy_tune2, "QUSB PHY v2 TUNE2"); @@ -520,6 +523,20 @@ static void qusb_phy_shutdown(struct usb_phy *phy) qusb_phy_enable_clocks(qphy, false); } + +static u32 qusb_phy_get_linestate(struct qusb_phy *qphy) +{ + u32 linestate = 0; + + if (qphy->cable_connected) { + if (qphy->phy.flags & PHY_HSFS_MODE) + linestate |= LINESTATE_DP; + else if (qphy->phy.flags & PHY_LS_MODE) + linestate |= LINESTATE_DM; + } + return linestate; +} + /** * Performs QUSB2 PHY suspend/resume functionality. * @@ -546,8 +563,7 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) writel_relaxed(0x00, qphy->base + QUSB2PHY_INTR_CTRL); - linestate = readl_relaxed(qphy->base + - QUSB2PHY_INTR_STAT); + linestate = qusb_phy_get_linestate(qphy); /* * D+/D- interrupts are level-triggered, but we are * only interested if the line state changes, so enable @@ -558,14 +574,17 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) * configure the mask to trigger on D+ low OR D- high */ intr_mask = DMSE_INTERRUPT | DPSE_INTERRUPT; - if (!(linestate & DPSE_INTR_EN)) /* D+ low */ + if (!(linestate & LINESTATE_DP)) /* D+ low */ intr_mask |= DPSE_INTR_HIGH_SEL; - if (!(linestate & DMSE_INTR_EN)) /* D- low */ + if (!(linestate & LINESTATE_DM)) /* D- low */ intr_mask |= DMSE_INTR_HIGH_SEL; writel_relaxed(intr_mask, qphy->base + QUSB2PHY_INTR_CTRL); + dev_dbg(phy->dev, "%s: intr_mask = %x\n", + __func__, intr_mask); + /* Makes sure that above write goes through */ wmb(); qusb_phy_enable_clocks(qphy, false); -- cgit v1.2.3 From 92a165748a25d43fb7e2fcb06c04b1e4e5db3567 Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Thu, 21 Apr 2016 10:27:05 -0700 Subject: ARM: dts: msm: Update QUSB PHY device node compatible property on msmcobalt It is required to use phy-msm-qusb-v2.c driver with msmcobalt platform. Hence use "qcom,qusb2phy-v2" instead of "qcom,qusb2phy" as compatiable string with QUSB PHY related device node on msmcobalt. Change-Id: I8d8ed29215f326801ba4e60794cc63e4eaeeb97e Signed-off-by: Mayank Rana --- arch/arm/boot/dts/qcom/msmcobalt.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi index 90d1ecd8f29c..aecaeb43b740 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi @@ -1734,7 +1734,7 @@ }; qusb_phy0: qusb@c012000 { - compatible = "qcom,qusb2phy"; + compatible = "qcom,qusb2phy-v2"; reg = <0x0c012000 0x2a8>, <0x0a8f8800 0x400>; reg-names = "qusb_phy_base", -- cgit v1.2.3