Loading Documentation/devicetree/bindings/usb/msm-phy.txt +8 −5 Original line number Diff line number Diff line Loading @@ -99,6 +99,8 @@ Required properties: Required regs are: "qmp_phy_base" : QMP PHY Base register set. "qmp_ahb2phy_base" : SS AHB2PHY CSR register set. - "vls_clamp_reg" : top-level CSR register to be written to enable phy vls clamp which allows phy to detect autonomous mode. - <supply-name>-supply: phandle to the regulator device tree node Required "supply-name" examples are: "vdd" : vdd supply for SSPHY digital circuit operation Loading @@ -113,14 +115,17 @@ Optional properties: order to manually relay the notification to the SSPHY. - qcom,no-pipe-clk-switch: If present, indicates that the pipe_clk does not need to switch sources between the XO and the PHY PIPE clock output. - qcom,emulation: Indicates that we are running on emulation platform. Example: ssphy0: ssphy@f9b38000 { compatible = "qcom,usb-ssphy-qmp"; reg = <0xf9b38000 0x16c>, <0xf9b3e000 0x3ff>; <0xf9b3e000 0x3ff>, <0x01947244 0x4>; reg-names = "qmp_phy_base", "qmp_ahb2phy_base"; "qmp_ahb2phy_base", "vls_clamp_reg"; vdd-supply = <&pmd9635_l4>; vdda18-supply = <&pmd9635_l8>; qcom,vdd-voltage-level = <0 900000 1050000>; Loading Loading @@ -156,12 +161,10 @@ Optional properties: allows us to manipulate QUSB PHY bits eg. to enable D+ pull-up using s/w control in device mode. The reg-names property is required if the reg property is specified. - qcom,qusb-tune: Used to pass QUSB PHY tuning parameters. The 4 tuning parameters are passed in as 4 bytes packed into a single 32-bit value. The parameters control On-chip Rout Term, TX Output Level, RX Sensitivity and TX Pre-emphasis respectively. - qcom,qusb-phy-init-seq: QUSB PHY initialization sequence with value,reg pair. - qcom,tune2-efuse-bit-pos: TUNE2 parameter related start bit position with EFUSE register - qcom,tune2-efuse-num-bits: Number of bits based value to use for TUNE2 high nibble - qcom,emulation: Indicates that we are running on emulation platform. Example: qusb_phy: qusb@f9b39000 { Loading arch/arm/boot/dts/qcom/msm8996.dtsi +4 −2 Original line number Diff line number Diff line Loading @@ -2136,9 +2136,11 @@ ssphy: ssphy@7410000 { compatible = "qcom,usb-ssphy-qmp-v2"; reg = <0x7410000 0x45C>, <0x7416000 0x400>; <0x7416000 0x400>, <0x007AB244 0x4>; reg-names = "qmp_phy_base", "qmp_ahb2phy_base"; "qmp_ahb2phy_base", "vls_clamp_reg"; vdd-supply = <&pm8994_l28>; vdda18-supply = <&pm8994_l12>; qcom,vdd-voltage-level = <0 925000 925000>; Loading drivers/usb/phy/phy-msm-qusb.c +93 −47 Original line number Diff line number Diff line Loading @@ -29,7 +29,16 @@ #define CLAMP_N_EN BIT(5) #define FREEZIO_N BIT(1) #define POWER_DOWN BIT(0) #define QUSB2PHY_PORT_UTMI_CTRL1 0xC0 #define TERM_SELECT BIT(4) #define XCVR_SELECT_FS BIT(2) #define OP_MODE_NON_DRIVE BIT(0) #define QUSB2PHY_PORT_UTMI_CTRL2 0xC4 #define UTMI_ULPI_SEL BIT(7) #define UTMI_TEST_MUX_SEL BIT(6) #define QUSB2PHY_PORT_TUNE1 0x80 #define QUSB2PHY_PORT_TUNE2 0x84 #define QUSB2PHY_PORT_TUNE3 0x88 Loading @@ -41,6 +50,14 @@ /* Get TUNE2's high nibble value read from efuse */ #define TUNE2_HIGH_NIBBLE_VAL(val, pos, mask) ((val >> pos) & mask) #define QRBTC_USB2_PLL 0x404 #define QRBTC_USB2_PLLCTRL2 0x414 #define QRBTC_USB2_PLLCTRL1 0x410 #define QRBTC_USB2_PLLCTRL3 0x418 #define QRBTC_USB2_PLLTEST1 0x408 #define RUMI_RESET_ADDRESS 0x6500 #define RUMI_RESET_VALUE_1 0x80000000 #define RUMI_RESET_VALUE_2 0x000201e0 #define QUSB2PHY_PORT_INTR_CTRL 0xBC #define CHG_DET_INTR_EN BIT(4) Loading Loading @@ -80,7 +97,6 @@ struct qusb_phy { struct regulator *vdda33; struct regulator *vdda18; int vdd_levels[3]; /* none, low, high */ u32 qusb_tune; int init_seq_len; int *qusb_phy_init_seq; Loading @@ -93,6 +109,7 @@ struct qusb_phy { bool cable_connected; bool suspended; bool ulpi_mode; bool emulation; }; static int qusb_phy_reset(struct usb_phy *phy) Loading Loading @@ -284,7 +301,6 @@ static int qusb_phy_init(struct usb_phy *phy) { struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); int ret, *seq = NULL, i; u32 t1, t2, t3, t4; dev_dbg(phy->dev, "%s\n", __func__); Loading @@ -298,6 +314,33 @@ static int qusb_phy_init(struct usb_phy *phy) qphy->clocks_enabled = true; } if (qphy->emulation) { /* Configure QUSB2 PLLs for RUMI */ writel_relaxed(0x19, qphy->base + QRBTC_USB2_PLL); writel_relaxed(0x20, qphy->base + QRBTC_USB2_PLLCTRL2); writel_relaxed(0x79, qphy->base + QRBTC_USB2_PLLCTRL1); writel_relaxed(0x00, qphy->base + QRBTC_USB2_PLLCTRL3); writel_relaxed(0x99, qphy->base + QRBTC_USB2_PLL); writel_relaxed(0x04, qphy->base + QRBTC_USB2_PLLTEST1); writel_relaxed(0xD9, qphy->base + QRBTC_USB2_PLL); /* Wait for 5ms as per QUSB2 RUMI sequence from VI */ usleep_range(5000, 7000); /* Perform the RUMI PLL Reset */ writel_relaxed((int)RUMI_RESET_VALUE_1, qphy->base + RUMI_RESET_ADDRESS); /* Wait for 10ms as per QUSB2 RUMI sequence from VI */ usleep_range(10000, 12000); writel_relaxed(0x0, qphy->base + RUMI_RESET_ADDRESS); /* Wait for 10ms as per QUSB2 RUMI sequence from VI */ usleep_range(10000, 12000); writel_relaxed((int)RUMI_RESET_VALUE_2, qphy->base + RUMI_RESET_ADDRESS); /* Wait for 10ms as per QUSB2 RUMI sequence from VI */ usleep_range(10000, 12000); writel_relaxed(0x0, qphy->base + RUMI_RESET_ADDRESS); } else { /* Disable the PHY */ writel_relaxed(CLAMP_N_EN | FREEZIO_N | POWER_DOWN, qphy->base + QUSB2PHY_PORT_POWERDOWN); Loading @@ -307,20 +350,6 @@ static int qusb_phy_init(struct usb_phy *phy) writel_relaxed(0x0, qphy->base + QUSB2PHY_PORT_UTMI_CTRL2); /* Program tuning parameters for PHY */ if (qphy->qusb_tune) { t1 = qphy->qusb_tune >> 24; t2 = (qphy->qusb_tune) >> 16 & 0xFF; t3 = (qphy->qusb_tune) >> 8 & 0xFF; t4 = (qphy->qusb_tune) & 0xFF; /* Program tuning parameters for PHY */ writel_relaxed(t1, qphy->base + QUSB2PHY_PORT_TUNE1); writel_relaxed(t2, qphy->base + QUSB2PHY_PORT_TUNE2); writel_relaxed(t3, qphy->base + QUSB2PHY_PORT_TUNE3); writel_relaxed(t4, qphy->base + QUSB2PHY_PORT_TUNE4); } if (qphy->qusb_phy_init_seq) { seq = qphy->qusb_phy_init_seq; dev_dbg(phy->dev, "count:%d\n", qphy->init_seq_len); Loading Loading @@ -351,7 +380,7 @@ static int qusb_phy_init(struct usb_phy *phy) /* Enable the PHY */ writel_relaxed(CLAMP_N_EN | FREEZIO_N, qphy->base + QUSB2PHY_PORT_POWERDOWN); } return 0; } Loading Loading @@ -433,6 +462,21 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) clk_disable_unprepare(qphy->cfg_ahb_clk); clk_disable_unprepare(qphy->ref_clk); } else { /* Disconnect case */ /* Disable all interrupts */ writel_relaxed(0x00, qphy->base + QUSB2PHY_PORT_INTR_CTRL); /* * Phy in non-driving mode leaves Dp and Dm lines in * high-Z state. Controller power collapse is not * switching phy to non-driving mode causing charger * detection failure. Bring phy to non-driving mode by * overriding controller output via UTMI interface. */ writel_relaxed(TERM_SELECT | XCVR_SELECT_FS | OP_MODE_NON_DRIVE, qphy->base + QUSB2PHY_PORT_UTMI_CTRL1); writel_relaxed(UTMI_ULPI_SEL | UTMI_TEST_MUX_SEL, qphy->base + QUSB2PHY_PORT_UTMI_CTRL2); clk_disable_unprepare(qphy->cfg_ahb_clk); clk_disable_unprepare(qphy->ref_clk); qusb_phy_enable_power(qphy, false); Loading Loading @@ -581,7 +625,9 @@ static int qusb_phy_probe(struct platform_device *pdev) if (IS_ERR(qphy->phy_reset)) return PTR_ERR(qphy->phy_reset); of_property_read_u32(dev->of_node, "qcom,qusb-tune", &qphy->qusb_tune); qphy->emulation = of_property_read_bool(dev->of_node, "qcom,emulation"); of_get_property(dev->of_node, "qcom,qusb-phy-init-seq", &size); if (size) { qphy->qusb_phy_init_seq = devm_kzalloc(dev, Loading drivers/usb/phy/phy-msm-ssusb-qmp.c +74 −31 Original line number Diff line number Diff line Loading @@ -34,6 +34,8 @@ #define PCIE_USB3_PHY_SW_RESET 0x600 #define PCIE_USB3_PHY_POWER_DOWN_CONTROL 0x604 #define PCIE_USB3_PHY_START 0x608 #define PCIE_USB3_PHY_AUTONOMOUS_MODE_CTRL 0x6BC #define PCIE_USB3_PHY_LFPS_RXTERM_IRQ_CLEAR 0x6C0 #define PHYSTATUS BIT(6) Loading Loading @@ -152,12 +154,12 @@ static const struct qmp_reg_val qmp_settings_rev1[] = { {0x100, 0xD5}, /* QSERDES_COM_DIV_FRAC_START1 */ {0x104, 0xAA}, /* QSERDES_COM_DIV_FRAC_START2 */ {0x108, 0x4D}, /* QSERDES_COM_DIV_FRAC_START3 */ {0x9C, 0x01}, /* QSERDES_COM_PLLLOCK_CMP_EN */ {0x9C, 0x11}, /* QSERDES_COM_PLLLOCK_CMP_EN */ {0x90, 0x2B}, /* QSERDES_COM_PLLLOCK_CMP1 */ {0x94, 0x68}, /* QSERDES_COM_PLLLOCK_CMP2 */ {0x114, 0x7C}, /* QSERDES_COM_PLL_CRCTRL */ {0x34, 0x07}, /* QSERDES_COM_PLL_CP_SETI */ {0x38, 0x1F}, /* QSERDES_COM_PLL_IP_SETP */ {0x34, 0x1F}, /* QSERDES_COM_PLL_CP_SETI */ {0x38, 0x12}, /* QSERDES_COM_PLL_IP_SETP */ {0x3C, 0x0F}, /* QSERDES_COM_PLL_CP_SETP */ {0x24, 0x01}, /* QSERDES_COM_PLL_IP_SETI */ {0x0C, 0x0F}, /* QSERDES_COM_IE_TRIM */ Loading @@ -172,7 +174,7 @@ static const struct qmp_reg_val qmp_settings_rev1[] = { {0x50, 0x07}, /* QSERDES_COM_RESETSM_CNTRL2 */ {0x04, 0xE1}, /* QSERDES_COM_PLL_VCOTAIL_EN */ {0xE0, 0x20}, /* QSERDES_COM_RES_CODE_START_SEG1 */ {0xE0, 0x24}, /* QSERDES_COM_RES_CODE_START_SEG1 */ {0xE8, 0x77}, /* QSERDES_COM_RES_CODE_CAL_CSR */ {0xF0, 0x15}, /* QSERDES_COM_RES_TRIM_CONTROL */ {0x268, 0x02}, /* QSERDES_TX_RCV_DETECT_LVL */ Loading Loading @@ -319,10 +321,19 @@ static const struct qmp_reg_val qmp_override_sysclk[] = { {-1, -1} /* terminating entry */ }; /* Vbg related settings */ static const struct qmp_reg_val qmp_settings_rev1_misc[] = { {0x0C, 0x03}, /* QSERDES_COM_IE_TRIM */ {0x10, 0x00}, /* QSERDES_COM_IP_TRIM */ {0xA0, 0xFF}, /* QSERDES_COM_BGTC */ {-1, -1} /* terminating entry */ }; struct msm_ssphy_qmp { struct usb_phy phy; void __iomem *base; void __iomem *ahb2phy; void __iomem *vls_clamp_reg; struct regulator *vdd; struct regulator *vdda18; int vdd_levels[3]; /* none, low, high */ Loading Loading @@ -361,28 +372,40 @@ static inline char *get_cable_status_str(struct msm_ssphy_qmp *phy) return phy->cable_connected ? "connected" : "disconnected"; } static void msm_ssusb_qmp_enable_autonomous(struct msm_ssphy_qmp *phy) static void msm_ssusb_qmp_clr_lfps_rxterm_int(struct msm_ssphy_qmp *phy) { writeb_relaxed(1, phy->base + PCIE_USB3_PHY_LFPS_RXTERM_IRQ_CLEAR); /* flush the previous write before next write */ wmb(); writeb_relaxed(0, phy->base + PCIE_USB3_PHY_LFPS_RXTERM_IRQ_CLEAR); } static void msm_ssusb_qmp_enable_autonomous(struct msm_ssphy_qmp *phy, int enable) { u8 val; dev_dbg(phy->phy.dev, "enabling QMP autonomous mode with cable %s\n", get_cable_status_str(phy)); val = readb_relaxed(phy->base + phy->phy_reg[USB3_PHY_AUTONOMOUS_MODE_CTRL]); if (enable) { msm_ssusb_qmp_clr_lfps_rxterm_int(phy); val = readb_relaxed(phy->base + PCIE_USB3_PHY_AUTONOMOUS_MODE_CTRL); val |= ARCVR_DTCT_EN; if (phy->cable_connected) { val |= ALFPS_DTCT_EN; /* Detect detach */ val &= ~ARCVR_DTCT_EVENT_SEL; writeb_relaxed(val, phy->base + PCIE_USB3_PHY_AUTONOMOUS_MODE_CTRL); /* clamp phy level shifter to perform autonomous detection */ writel_relaxed(0x1, phy->vls_clamp_reg); } else { val &= ~ALFPS_DTCT_EN; /* Detect attach */ val |= ARCVR_DTCT_EVENT_SEL; writel_relaxed(0x0, phy->vls_clamp_reg); writeb_relaxed(0, phy->base + PCIE_USB3_PHY_AUTONOMOUS_MODE_CTRL); msm_ssusb_qmp_clr_lfps_rxterm_int(phy); } writeb_relaxed(val, phy->base + phy->phy_reg[USB3_PHY_AUTONOMOUS_MODE_CTRL]); } Loading Loading @@ -521,6 +544,7 @@ static int msm_ssphy_qmp_init(struct usb_phy *uphy) break; case 0x10000001: reg = qmp_settings_rev1; misc = qmp_settings_rev1_misc; break; case 0x20000000: case 0x20000001: Loading Loading @@ -688,14 +712,13 @@ deassert_phy_com_reset: static int msm_ssphy_power_enable(struct msm_ssphy_qmp *phy, bool on) { bool host = phy->phy.flags & PHY_HOST_MODE; bool chg_connected = phy->phy.flags & PHY_CHARGER_CONNECTED; int ret = 0; /* * Turn off the phy's LDOs when cable is disconnected for device mode * with external vbus_id indication. */ if (!host && !chg_connected && !phy->cable_connected) { if (!host && !phy->cable_connected) { if (on) { ret = regulator_enable(phy->vdd); if (ret) Loading Loading @@ -748,29 +771,33 @@ static int msm_ssphy_qmp_set_suspend(struct usb_phy *uphy, int suspend) } if (suspend) { msm_ssusb_qmp_enable_autonomous(phy); if (!phy->cable_connected) { clk_disable_unprepare(phy->pipe_clk); if (!phy->cable_connected) writel_relaxed(0x00, phy->base + PCIE_USB3_PHY_POWER_DOWN_CONTROL); } else msm_ssusb_qmp_enable_autonomous(phy, 1); clk_disable_unprepare(phy->cfg_ahb_clk); clk_disable_unprepare(phy->aux_clk); clk_disable_unprepare(phy->pipe_clk); phy->clk_enabled = false; phy->in_suspend = true; msm_ssphy_power_enable(phy, 0); dev_dbg(uphy->dev, "QMP PHY is suspend\n"); } else { msm_ssphy_power_enable(phy, 1); clk_prepare_enable(phy->pipe_clk); if (!phy->clk_enabled) { clk_prepare_enable(phy->aux_clk); clk_prepare_enable(phy->cfg_ahb_clk); clk_prepare_enable(phy->pipe_clk); phy->clk_enabled = true; } if (!phy->cable_connected) { writel_relaxed(0x01, phy->base + PCIE_USB3_PHY_POWER_DOWN_CONTROL); msm_ssusb_qmp_enable_autonomous(phy); } else { msm_ssusb_qmp_enable_autonomous(phy, 0); } phy->in_suspend = false; dev_dbg(uphy->dev, "QMP PHY is resumed\n"); } Loading Loading @@ -798,7 +825,6 @@ static int msm_ssphy_qmp_notify_disconnect(struct usb_phy *uphy, dev_dbg(uphy->dev, "QMP phy disconnect notification\n"); dev_dbg(uphy->dev, " cable_connected=%d\n", phy->cable_connected); msm_ssusb_qmp_enable_autonomous(phy); phy->cable_connected = false; return 0; } Loading Loading @@ -899,19 +925,36 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qmp_phy_base"); if (!res) { dev_err(dev, "failed getting qmp_phy_base\n"); return -ENODEV; } phy->base = devm_ioremap_resource(dev, res); if (IS_ERR(phy->base)) { ret = PTR_ERR(phy->base); goto err; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vls_clamp_reg"); if (!res) { dev_err(dev, "failed getting vls_clamp_reg\n"); return -ENODEV; } phy->vls_clamp_reg = devm_ioremap_resource(dev, res); if (IS_ERR(phy->vls_clamp_reg)) { dev_err(dev, "couldn't find vls_clamp_reg address.\n"); return PTR_ERR(phy->vls_clamp_reg); } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qmp_ahb2phy_base"); if (res) { phy->ahb2phy = devm_ioremap_resource(dev, res); if (IS_ERR(phy->ahb2phy)) { dev_err(dev, "couldn't find qmp_ahb2phy_base address.\n"); ret = PTR_ERR(phy->ahb2phy); goto err; dev_err(dev, "couldn't find qmp_ahb2phy_base addr.\n"); phy->ahb2phy = NULL; } } phy->emulation = of_property_read_bool(dev->of_node, Loading Loading
Documentation/devicetree/bindings/usb/msm-phy.txt +8 −5 Original line number Diff line number Diff line Loading @@ -99,6 +99,8 @@ Required properties: Required regs are: "qmp_phy_base" : QMP PHY Base register set. "qmp_ahb2phy_base" : SS AHB2PHY CSR register set. - "vls_clamp_reg" : top-level CSR register to be written to enable phy vls clamp which allows phy to detect autonomous mode. - <supply-name>-supply: phandle to the regulator device tree node Required "supply-name" examples are: "vdd" : vdd supply for SSPHY digital circuit operation Loading @@ -113,14 +115,17 @@ Optional properties: order to manually relay the notification to the SSPHY. - qcom,no-pipe-clk-switch: If present, indicates that the pipe_clk does not need to switch sources between the XO and the PHY PIPE clock output. - qcom,emulation: Indicates that we are running on emulation platform. Example: ssphy0: ssphy@f9b38000 { compatible = "qcom,usb-ssphy-qmp"; reg = <0xf9b38000 0x16c>, <0xf9b3e000 0x3ff>; <0xf9b3e000 0x3ff>, <0x01947244 0x4>; reg-names = "qmp_phy_base", "qmp_ahb2phy_base"; "qmp_ahb2phy_base", "vls_clamp_reg"; vdd-supply = <&pmd9635_l4>; vdda18-supply = <&pmd9635_l8>; qcom,vdd-voltage-level = <0 900000 1050000>; Loading Loading @@ -156,12 +161,10 @@ Optional properties: allows us to manipulate QUSB PHY bits eg. to enable D+ pull-up using s/w control in device mode. The reg-names property is required if the reg property is specified. - qcom,qusb-tune: Used to pass QUSB PHY tuning parameters. The 4 tuning parameters are passed in as 4 bytes packed into a single 32-bit value. The parameters control On-chip Rout Term, TX Output Level, RX Sensitivity and TX Pre-emphasis respectively. - qcom,qusb-phy-init-seq: QUSB PHY initialization sequence with value,reg pair. - qcom,tune2-efuse-bit-pos: TUNE2 parameter related start bit position with EFUSE register - qcom,tune2-efuse-num-bits: Number of bits based value to use for TUNE2 high nibble - qcom,emulation: Indicates that we are running on emulation platform. Example: qusb_phy: qusb@f9b39000 { Loading
arch/arm/boot/dts/qcom/msm8996.dtsi +4 −2 Original line number Diff line number Diff line Loading @@ -2136,9 +2136,11 @@ ssphy: ssphy@7410000 { compatible = "qcom,usb-ssphy-qmp-v2"; reg = <0x7410000 0x45C>, <0x7416000 0x400>; <0x7416000 0x400>, <0x007AB244 0x4>; reg-names = "qmp_phy_base", "qmp_ahb2phy_base"; "qmp_ahb2phy_base", "vls_clamp_reg"; vdd-supply = <&pm8994_l28>; vdda18-supply = <&pm8994_l12>; qcom,vdd-voltage-level = <0 925000 925000>; Loading
drivers/usb/phy/phy-msm-qusb.c +93 −47 Original line number Diff line number Diff line Loading @@ -29,7 +29,16 @@ #define CLAMP_N_EN BIT(5) #define FREEZIO_N BIT(1) #define POWER_DOWN BIT(0) #define QUSB2PHY_PORT_UTMI_CTRL1 0xC0 #define TERM_SELECT BIT(4) #define XCVR_SELECT_FS BIT(2) #define OP_MODE_NON_DRIVE BIT(0) #define QUSB2PHY_PORT_UTMI_CTRL2 0xC4 #define UTMI_ULPI_SEL BIT(7) #define UTMI_TEST_MUX_SEL BIT(6) #define QUSB2PHY_PORT_TUNE1 0x80 #define QUSB2PHY_PORT_TUNE2 0x84 #define QUSB2PHY_PORT_TUNE3 0x88 Loading @@ -41,6 +50,14 @@ /* Get TUNE2's high nibble value read from efuse */ #define TUNE2_HIGH_NIBBLE_VAL(val, pos, mask) ((val >> pos) & mask) #define QRBTC_USB2_PLL 0x404 #define QRBTC_USB2_PLLCTRL2 0x414 #define QRBTC_USB2_PLLCTRL1 0x410 #define QRBTC_USB2_PLLCTRL3 0x418 #define QRBTC_USB2_PLLTEST1 0x408 #define RUMI_RESET_ADDRESS 0x6500 #define RUMI_RESET_VALUE_1 0x80000000 #define RUMI_RESET_VALUE_2 0x000201e0 #define QUSB2PHY_PORT_INTR_CTRL 0xBC #define CHG_DET_INTR_EN BIT(4) Loading Loading @@ -80,7 +97,6 @@ struct qusb_phy { struct regulator *vdda33; struct regulator *vdda18; int vdd_levels[3]; /* none, low, high */ u32 qusb_tune; int init_seq_len; int *qusb_phy_init_seq; Loading @@ -93,6 +109,7 @@ struct qusb_phy { bool cable_connected; bool suspended; bool ulpi_mode; bool emulation; }; static int qusb_phy_reset(struct usb_phy *phy) Loading Loading @@ -284,7 +301,6 @@ static int qusb_phy_init(struct usb_phy *phy) { struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); int ret, *seq = NULL, i; u32 t1, t2, t3, t4; dev_dbg(phy->dev, "%s\n", __func__); Loading @@ -298,6 +314,33 @@ static int qusb_phy_init(struct usb_phy *phy) qphy->clocks_enabled = true; } if (qphy->emulation) { /* Configure QUSB2 PLLs for RUMI */ writel_relaxed(0x19, qphy->base + QRBTC_USB2_PLL); writel_relaxed(0x20, qphy->base + QRBTC_USB2_PLLCTRL2); writel_relaxed(0x79, qphy->base + QRBTC_USB2_PLLCTRL1); writel_relaxed(0x00, qphy->base + QRBTC_USB2_PLLCTRL3); writel_relaxed(0x99, qphy->base + QRBTC_USB2_PLL); writel_relaxed(0x04, qphy->base + QRBTC_USB2_PLLTEST1); writel_relaxed(0xD9, qphy->base + QRBTC_USB2_PLL); /* Wait for 5ms as per QUSB2 RUMI sequence from VI */ usleep_range(5000, 7000); /* Perform the RUMI PLL Reset */ writel_relaxed((int)RUMI_RESET_VALUE_1, qphy->base + RUMI_RESET_ADDRESS); /* Wait for 10ms as per QUSB2 RUMI sequence from VI */ usleep_range(10000, 12000); writel_relaxed(0x0, qphy->base + RUMI_RESET_ADDRESS); /* Wait for 10ms as per QUSB2 RUMI sequence from VI */ usleep_range(10000, 12000); writel_relaxed((int)RUMI_RESET_VALUE_2, qphy->base + RUMI_RESET_ADDRESS); /* Wait for 10ms as per QUSB2 RUMI sequence from VI */ usleep_range(10000, 12000); writel_relaxed(0x0, qphy->base + RUMI_RESET_ADDRESS); } else { /* Disable the PHY */ writel_relaxed(CLAMP_N_EN | FREEZIO_N | POWER_DOWN, qphy->base + QUSB2PHY_PORT_POWERDOWN); Loading @@ -307,20 +350,6 @@ static int qusb_phy_init(struct usb_phy *phy) writel_relaxed(0x0, qphy->base + QUSB2PHY_PORT_UTMI_CTRL2); /* Program tuning parameters for PHY */ if (qphy->qusb_tune) { t1 = qphy->qusb_tune >> 24; t2 = (qphy->qusb_tune) >> 16 & 0xFF; t3 = (qphy->qusb_tune) >> 8 & 0xFF; t4 = (qphy->qusb_tune) & 0xFF; /* Program tuning parameters for PHY */ writel_relaxed(t1, qphy->base + QUSB2PHY_PORT_TUNE1); writel_relaxed(t2, qphy->base + QUSB2PHY_PORT_TUNE2); writel_relaxed(t3, qphy->base + QUSB2PHY_PORT_TUNE3); writel_relaxed(t4, qphy->base + QUSB2PHY_PORT_TUNE4); } if (qphy->qusb_phy_init_seq) { seq = qphy->qusb_phy_init_seq; dev_dbg(phy->dev, "count:%d\n", qphy->init_seq_len); Loading Loading @@ -351,7 +380,7 @@ static int qusb_phy_init(struct usb_phy *phy) /* Enable the PHY */ writel_relaxed(CLAMP_N_EN | FREEZIO_N, qphy->base + QUSB2PHY_PORT_POWERDOWN); } return 0; } Loading Loading @@ -433,6 +462,21 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) clk_disable_unprepare(qphy->cfg_ahb_clk); clk_disable_unprepare(qphy->ref_clk); } else { /* Disconnect case */ /* Disable all interrupts */ writel_relaxed(0x00, qphy->base + QUSB2PHY_PORT_INTR_CTRL); /* * Phy in non-driving mode leaves Dp and Dm lines in * high-Z state. Controller power collapse is not * switching phy to non-driving mode causing charger * detection failure. Bring phy to non-driving mode by * overriding controller output via UTMI interface. */ writel_relaxed(TERM_SELECT | XCVR_SELECT_FS | OP_MODE_NON_DRIVE, qphy->base + QUSB2PHY_PORT_UTMI_CTRL1); writel_relaxed(UTMI_ULPI_SEL | UTMI_TEST_MUX_SEL, qphy->base + QUSB2PHY_PORT_UTMI_CTRL2); clk_disable_unprepare(qphy->cfg_ahb_clk); clk_disable_unprepare(qphy->ref_clk); qusb_phy_enable_power(qphy, false); Loading Loading @@ -581,7 +625,9 @@ static int qusb_phy_probe(struct platform_device *pdev) if (IS_ERR(qphy->phy_reset)) return PTR_ERR(qphy->phy_reset); of_property_read_u32(dev->of_node, "qcom,qusb-tune", &qphy->qusb_tune); qphy->emulation = of_property_read_bool(dev->of_node, "qcom,emulation"); of_get_property(dev->of_node, "qcom,qusb-phy-init-seq", &size); if (size) { qphy->qusb_phy_init_seq = devm_kzalloc(dev, Loading
drivers/usb/phy/phy-msm-ssusb-qmp.c +74 −31 Original line number Diff line number Diff line Loading @@ -34,6 +34,8 @@ #define PCIE_USB3_PHY_SW_RESET 0x600 #define PCIE_USB3_PHY_POWER_DOWN_CONTROL 0x604 #define PCIE_USB3_PHY_START 0x608 #define PCIE_USB3_PHY_AUTONOMOUS_MODE_CTRL 0x6BC #define PCIE_USB3_PHY_LFPS_RXTERM_IRQ_CLEAR 0x6C0 #define PHYSTATUS BIT(6) Loading Loading @@ -152,12 +154,12 @@ static const struct qmp_reg_val qmp_settings_rev1[] = { {0x100, 0xD5}, /* QSERDES_COM_DIV_FRAC_START1 */ {0x104, 0xAA}, /* QSERDES_COM_DIV_FRAC_START2 */ {0x108, 0x4D}, /* QSERDES_COM_DIV_FRAC_START3 */ {0x9C, 0x01}, /* QSERDES_COM_PLLLOCK_CMP_EN */ {0x9C, 0x11}, /* QSERDES_COM_PLLLOCK_CMP_EN */ {0x90, 0x2B}, /* QSERDES_COM_PLLLOCK_CMP1 */ {0x94, 0x68}, /* QSERDES_COM_PLLLOCK_CMP2 */ {0x114, 0x7C}, /* QSERDES_COM_PLL_CRCTRL */ {0x34, 0x07}, /* QSERDES_COM_PLL_CP_SETI */ {0x38, 0x1F}, /* QSERDES_COM_PLL_IP_SETP */ {0x34, 0x1F}, /* QSERDES_COM_PLL_CP_SETI */ {0x38, 0x12}, /* QSERDES_COM_PLL_IP_SETP */ {0x3C, 0x0F}, /* QSERDES_COM_PLL_CP_SETP */ {0x24, 0x01}, /* QSERDES_COM_PLL_IP_SETI */ {0x0C, 0x0F}, /* QSERDES_COM_IE_TRIM */ Loading @@ -172,7 +174,7 @@ static const struct qmp_reg_val qmp_settings_rev1[] = { {0x50, 0x07}, /* QSERDES_COM_RESETSM_CNTRL2 */ {0x04, 0xE1}, /* QSERDES_COM_PLL_VCOTAIL_EN */ {0xE0, 0x20}, /* QSERDES_COM_RES_CODE_START_SEG1 */ {0xE0, 0x24}, /* QSERDES_COM_RES_CODE_START_SEG1 */ {0xE8, 0x77}, /* QSERDES_COM_RES_CODE_CAL_CSR */ {0xF0, 0x15}, /* QSERDES_COM_RES_TRIM_CONTROL */ {0x268, 0x02}, /* QSERDES_TX_RCV_DETECT_LVL */ Loading Loading @@ -319,10 +321,19 @@ static const struct qmp_reg_val qmp_override_sysclk[] = { {-1, -1} /* terminating entry */ }; /* Vbg related settings */ static const struct qmp_reg_val qmp_settings_rev1_misc[] = { {0x0C, 0x03}, /* QSERDES_COM_IE_TRIM */ {0x10, 0x00}, /* QSERDES_COM_IP_TRIM */ {0xA0, 0xFF}, /* QSERDES_COM_BGTC */ {-1, -1} /* terminating entry */ }; struct msm_ssphy_qmp { struct usb_phy phy; void __iomem *base; void __iomem *ahb2phy; void __iomem *vls_clamp_reg; struct regulator *vdd; struct regulator *vdda18; int vdd_levels[3]; /* none, low, high */ Loading Loading @@ -361,28 +372,40 @@ static inline char *get_cable_status_str(struct msm_ssphy_qmp *phy) return phy->cable_connected ? "connected" : "disconnected"; } static void msm_ssusb_qmp_enable_autonomous(struct msm_ssphy_qmp *phy) static void msm_ssusb_qmp_clr_lfps_rxterm_int(struct msm_ssphy_qmp *phy) { writeb_relaxed(1, phy->base + PCIE_USB3_PHY_LFPS_RXTERM_IRQ_CLEAR); /* flush the previous write before next write */ wmb(); writeb_relaxed(0, phy->base + PCIE_USB3_PHY_LFPS_RXTERM_IRQ_CLEAR); } static void msm_ssusb_qmp_enable_autonomous(struct msm_ssphy_qmp *phy, int enable) { u8 val; dev_dbg(phy->phy.dev, "enabling QMP autonomous mode with cable %s\n", get_cable_status_str(phy)); val = readb_relaxed(phy->base + phy->phy_reg[USB3_PHY_AUTONOMOUS_MODE_CTRL]); if (enable) { msm_ssusb_qmp_clr_lfps_rxterm_int(phy); val = readb_relaxed(phy->base + PCIE_USB3_PHY_AUTONOMOUS_MODE_CTRL); val |= ARCVR_DTCT_EN; if (phy->cable_connected) { val |= ALFPS_DTCT_EN; /* Detect detach */ val &= ~ARCVR_DTCT_EVENT_SEL; writeb_relaxed(val, phy->base + PCIE_USB3_PHY_AUTONOMOUS_MODE_CTRL); /* clamp phy level shifter to perform autonomous detection */ writel_relaxed(0x1, phy->vls_clamp_reg); } else { val &= ~ALFPS_DTCT_EN; /* Detect attach */ val |= ARCVR_DTCT_EVENT_SEL; writel_relaxed(0x0, phy->vls_clamp_reg); writeb_relaxed(0, phy->base + PCIE_USB3_PHY_AUTONOMOUS_MODE_CTRL); msm_ssusb_qmp_clr_lfps_rxterm_int(phy); } writeb_relaxed(val, phy->base + phy->phy_reg[USB3_PHY_AUTONOMOUS_MODE_CTRL]); } Loading Loading @@ -521,6 +544,7 @@ static int msm_ssphy_qmp_init(struct usb_phy *uphy) break; case 0x10000001: reg = qmp_settings_rev1; misc = qmp_settings_rev1_misc; break; case 0x20000000: case 0x20000001: Loading Loading @@ -688,14 +712,13 @@ deassert_phy_com_reset: static int msm_ssphy_power_enable(struct msm_ssphy_qmp *phy, bool on) { bool host = phy->phy.flags & PHY_HOST_MODE; bool chg_connected = phy->phy.flags & PHY_CHARGER_CONNECTED; int ret = 0; /* * Turn off the phy's LDOs when cable is disconnected for device mode * with external vbus_id indication. */ if (!host && !chg_connected && !phy->cable_connected) { if (!host && !phy->cable_connected) { if (on) { ret = regulator_enable(phy->vdd); if (ret) Loading Loading @@ -748,29 +771,33 @@ static int msm_ssphy_qmp_set_suspend(struct usb_phy *uphy, int suspend) } if (suspend) { msm_ssusb_qmp_enable_autonomous(phy); if (!phy->cable_connected) { clk_disable_unprepare(phy->pipe_clk); if (!phy->cable_connected) writel_relaxed(0x00, phy->base + PCIE_USB3_PHY_POWER_DOWN_CONTROL); } else msm_ssusb_qmp_enable_autonomous(phy, 1); clk_disable_unprepare(phy->cfg_ahb_clk); clk_disable_unprepare(phy->aux_clk); clk_disable_unprepare(phy->pipe_clk); phy->clk_enabled = false; phy->in_suspend = true; msm_ssphy_power_enable(phy, 0); dev_dbg(uphy->dev, "QMP PHY is suspend\n"); } else { msm_ssphy_power_enable(phy, 1); clk_prepare_enable(phy->pipe_clk); if (!phy->clk_enabled) { clk_prepare_enable(phy->aux_clk); clk_prepare_enable(phy->cfg_ahb_clk); clk_prepare_enable(phy->pipe_clk); phy->clk_enabled = true; } if (!phy->cable_connected) { writel_relaxed(0x01, phy->base + PCIE_USB3_PHY_POWER_DOWN_CONTROL); msm_ssusb_qmp_enable_autonomous(phy); } else { msm_ssusb_qmp_enable_autonomous(phy, 0); } phy->in_suspend = false; dev_dbg(uphy->dev, "QMP PHY is resumed\n"); } Loading Loading @@ -798,7 +825,6 @@ static int msm_ssphy_qmp_notify_disconnect(struct usb_phy *uphy, dev_dbg(uphy->dev, "QMP phy disconnect notification\n"); dev_dbg(uphy->dev, " cable_connected=%d\n", phy->cable_connected); msm_ssusb_qmp_enable_autonomous(phy); phy->cable_connected = false; return 0; } Loading Loading @@ -899,19 +925,36 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qmp_phy_base"); if (!res) { dev_err(dev, "failed getting qmp_phy_base\n"); return -ENODEV; } phy->base = devm_ioremap_resource(dev, res); if (IS_ERR(phy->base)) { ret = PTR_ERR(phy->base); goto err; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vls_clamp_reg"); if (!res) { dev_err(dev, "failed getting vls_clamp_reg\n"); return -ENODEV; } phy->vls_clamp_reg = devm_ioremap_resource(dev, res); if (IS_ERR(phy->vls_clamp_reg)) { dev_err(dev, "couldn't find vls_clamp_reg address.\n"); return PTR_ERR(phy->vls_clamp_reg); } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qmp_ahb2phy_base"); if (res) { phy->ahb2phy = devm_ioremap_resource(dev, res); if (IS_ERR(phy->ahb2phy)) { dev_err(dev, "couldn't find qmp_ahb2phy_base address.\n"); ret = PTR_ERR(phy->ahb2phy); goto err; dev_err(dev, "couldn't find qmp_ahb2phy_base addr.\n"); phy->ahb2phy = NULL; } } phy->emulation = of_property_read_bool(dev->of_node, Loading