Loading Documentation/devicetree/bindings/usb/qcom,msm-phy.txt +2 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,8 @@ Optional properties: - qcom,core-voltage-level: This property must be a list of three integer values (no, min, max) where each value represents either a voltage in microvolts or a value corresponding to voltage corner. - qcom,link-training-reset: This property indicates to start link training timer to reset the elastic buffer based on rx equalization value. Example: ssphy0: ssphy@f9b38000 { Loading arch/arm64/boot/dts/qcom/sm8150-usb.dtsi +6 −1 Original line number Diff line number Diff line Loading @@ -152,6 +152,7 @@ qcom,vdd-voltage-level = <0 880000 880000>; core-supply = <&pm8150l_l3>; qcom,vbus-valid-override; qcom,link-training-reset; qcom,qmp-phy-init-seq = /* <reg_offset, value, delay> */ <USB3_DP_QSERDES_COM_SSC_EN_CENTER 0x01 0 Loading Loading @@ -280,6 +281,7 @@ USB3_DP_PCS_EQ_CONFIG1 0x0d 0 USB3_DP_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL 0xf8 0 USB3_DP_PCS_USB3_RXEQTRAINING_DFE_TIME_S2 0x07 0 USB3_DP_PCS_EQ_CONFIG5 0x52 0 0xffffffff 0xffffffff 0x00>; qcom,qmp-phy-reg-offset = Loading @@ -296,7 +298,10 @@ USB3_DP_COM_PHY_MODE_CTRL USB3_DP_COM_TYPEC_CTRL USB3_DP_COM_SWI_CTRL USB3_DP_PCS_CLAMP_ENABLE>; USB3_DP_PCS_CLAMP_ENABLE USB3_DP_PCS_PCS_STATUS2 USB3_DP_PCS_INSIG_SW_CTRL3 USB3_DP_PCS_INSIG_MX_CTRL3>; clocks = <&clock_gcc GCC_USB3_PRIM_PHY_AUX_CLK>, <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, Loading drivers/usb/dwc3/debug.h +4 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,10 @@ #define dbg_setup(ep_num, req) \ dwc3_dbg_setup(dwc, ep_num, req) #define dbg_log_string(fmt, ...) \ ipc_log_string(dwc->dwc_ipc_log_ctxt,\ "%s: " fmt, __func__, ##__VA_ARGS__) /** * dwc3_gadget_ep_cmd_string - returns endpoint command string * @cmd: command code Loading drivers/usb/dwc3/gadget.c +3 −0 Original line number Diff line number Diff line Loading @@ -3141,6 +3141,8 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) { u32 reg; usb_phy_start_link_training(dwc->usb3_phy); dwc->connected = true; /* Loading Loading @@ -3226,6 +3228,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) u8 speed; dbg_event(0xFF, "CONNECT DONE", 0); usb_phy_stop_link_training(dwc->usb3_phy); reg = dwc3_readl(dwc->regs, DWC3_DSTS); speed = reg & DWC3_DSTS_CONNECTSPD; dwc->speed = speed; Loading drivers/usb/phy/phy-msm-ssusb-qmp.c +85 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <linux/usb/phy.h> #include <linux/clk.h> #include <linux/reset.h> #include <linux/hrtimer.h> enum core_ldo_levels { CORE_LEVEL_NONE = 0, Loading Loading @@ -79,6 +80,9 @@ enum core_ldo_levels { #define USB3_MODE BIT(0) /* enables USB3 mode */ #define DP_MODE BIT(1) /* enables DP mode */ /* USB3 Gen2 link training indicator */ #define RX_EQUALIZATION_IN_PROGRESS BIT(3) enum qmp_phy_rev_reg { USB3_PHY_PCS_STATUS, USB3_PHY_AUTONOMOUS_MODE_CTRL, Loading @@ -96,6 +100,9 @@ enum qmp_phy_rev_reg { USB3_DP_COM_TYPEC_CTRL, USB3_DP_COM_SWI_CTRL, USB3_PCS_MISC_CLAMP_ENABLE, USB3_DP_PCS_PCS_STATUS2, USB3_DP_PCS_INSIG_SW_CTRL3, USB3_DP_PCS_INSIG_MX_CTRL3, /* TypeC port select configuration (optional) */ USB3_PHY_PCS_MISC_TYPEC_CTRL, USB3_PHY_REG_MAX, Loading Loading @@ -136,6 +143,7 @@ struct msm_ssphy_qmp { int reg_offset_cnt; u32 *qmp_phy_init_seq; int init_seq_len; struct hrtimer timer; }; static const struct of_device_id msm_usb_id_table[] = { Loading Loading @@ -634,6 +642,7 @@ static int msm_ssphy_qmp_set_suspend(struct usb_phy *uphy, int suspend) /* Make sure above write completed with PHY */ wmb(); hrtimer_cancel(&phy->timer); msm_ssphy_qmp_enable_clks(phy, false); phy->in_suspend = true; msm_ssphy_power_enable(phy, 0); Loading @@ -658,6 +667,74 @@ static int msm_ssphy_qmp_set_suspend(struct usb_phy *uphy, int suspend) return 0; } static enum hrtimer_restart timer_fn(struct hrtimer *timer) { struct msm_ssphy_qmp *phy = container_of(timer, struct msm_ssphy_qmp, timer); u8 status2, status2_1, sw1, mx1, sw2, mx2; int timeout = 15000; status2_1 = sw1 = sw2 = mx1 = mx2 = 0; status2 = readl_relaxed(phy->base + phy->phy_reg[USB3_DP_PCS_PCS_STATUS2]); if (status2 & RX_EQUALIZATION_IN_PROGRESS) { while (timeout > 0) { status2_1 = readl_relaxed(phy->base + phy->phy_reg[USB3_DP_PCS_PCS_STATUS2]); if (status2_1 & RX_EQUALIZATION_IN_PROGRESS) { timeout -= 500; udelay(500); continue; } writel_relaxed(0x08, phy->base + phy->phy_reg[USB3_DP_PCS_INSIG_SW_CTRL3]); writel_relaxed(0x08, phy->base + phy->phy_reg[USB3_DP_PCS_INSIG_MX_CTRL3]); sw1 = readl_relaxed(phy->base + phy->phy_reg[USB3_DP_PCS_INSIG_SW_CTRL3]); mx1 = readl_relaxed(phy->base + phy->phy_reg[USB3_DP_PCS_INSIG_MX_CTRL3]); udelay(1); writel_relaxed(0x0, phy->base + phy->phy_reg[USB3_DP_PCS_INSIG_SW_CTRL3]); writel_relaxed(0x0, phy->base + phy->phy_reg[USB3_DP_PCS_INSIG_MX_CTRL3]); sw2 = readl_relaxed(phy->base + phy->phy_reg[USB3_DP_PCS_INSIG_SW_CTRL3]); mx2 = readl_relaxed(phy->base + phy->phy_reg[USB3_DP_PCS_INSIG_MX_CTRL3]); break; } } dev_dbg(phy->phy.dev, "st=%x st2=%x sw1=%x sw2=%x mx1=%x mx2=%x timeout=%d\n", status2, status2_1, sw1, sw2, mx1, mx2, timeout); hrtimer_forward_now(timer, ms_to_ktime(1)); return HRTIMER_RESTART; } static int msm_ssphy_qmp_link_training(struct usb_phy *uphy, bool start) { struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp, phy); if (start) { hrtimer_start(&phy->timer, 0, HRTIMER_MODE_REL); dev_dbg(uphy->dev, "link training start\n"); } else { hrtimer_cancel(&phy->timer); dev_dbg(uphy->dev, "link training stop\n"); } return 0; } static int msm_ssphy_qmp_notify_connect(struct usb_phy *uphy, enum usb_device_speed speed) { Loading @@ -680,6 +757,7 @@ static int msm_ssphy_qmp_notify_disconnect(struct usb_phy *uphy, phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); readl_relaxed(phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); hrtimer_cancel(&phy->timer); dev_dbg(uphy->dev, "QMP phy disconnect notification\n"); dev_dbg(uphy->dev, " cable_connected=%d\n", phy->cable_connected); phy->cable_connected = false; Loading Loading @@ -979,12 +1057,19 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) if (of_property_read_bool(dev->of_node, "qcom,vbus-valid-override")) phy->phy.flags |= PHY_VBUS_VALID_OVERRIDE; hrtimer_init(&phy->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); phy->timer.function = timer_fn; phy->phy.dev = dev; phy->phy.init = msm_ssphy_qmp_init; phy->phy.set_suspend = msm_ssphy_qmp_set_suspend; phy->phy.notify_connect = msm_ssphy_qmp_notify_connect; phy->phy.notify_disconnect = msm_ssphy_qmp_notify_disconnect; if (of_property_read_bool(dev->of_node, "qcom,link-training-reset")) phy->phy.link_training = msm_ssphy_qmp_link_training; if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP) phy->phy.reset = msm_ssphy_qmp_dp_combo_reset; else Loading Loading
Documentation/devicetree/bindings/usb/qcom,msm-phy.txt +2 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,8 @@ Optional properties: - qcom,core-voltage-level: This property must be a list of three integer values (no, min, max) where each value represents either a voltage in microvolts or a value corresponding to voltage corner. - qcom,link-training-reset: This property indicates to start link training timer to reset the elastic buffer based on rx equalization value. Example: ssphy0: ssphy@f9b38000 { Loading
arch/arm64/boot/dts/qcom/sm8150-usb.dtsi +6 −1 Original line number Diff line number Diff line Loading @@ -152,6 +152,7 @@ qcom,vdd-voltage-level = <0 880000 880000>; core-supply = <&pm8150l_l3>; qcom,vbus-valid-override; qcom,link-training-reset; qcom,qmp-phy-init-seq = /* <reg_offset, value, delay> */ <USB3_DP_QSERDES_COM_SSC_EN_CENTER 0x01 0 Loading Loading @@ -280,6 +281,7 @@ USB3_DP_PCS_EQ_CONFIG1 0x0d 0 USB3_DP_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL 0xf8 0 USB3_DP_PCS_USB3_RXEQTRAINING_DFE_TIME_S2 0x07 0 USB3_DP_PCS_EQ_CONFIG5 0x52 0 0xffffffff 0xffffffff 0x00>; qcom,qmp-phy-reg-offset = Loading @@ -296,7 +298,10 @@ USB3_DP_COM_PHY_MODE_CTRL USB3_DP_COM_TYPEC_CTRL USB3_DP_COM_SWI_CTRL USB3_DP_PCS_CLAMP_ENABLE>; USB3_DP_PCS_CLAMP_ENABLE USB3_DP_PCS_PCS_STATUS2 USB3_DP_PCS_INSIG_SW_CTRL3 USB3_DP_PCS_INSIG_MX_CTRL3>; clocks = <&clock_gcc GCC_USB3_PRIM_PHY_AUX_CLK>, <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, Loading
drivers/usb/dwc3/debug.h +4 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,10 @@ #define dbg_setup(ep_num, req) \ dwc3_dbg_setup(dwc, ep_num, req) #define dbg_log_string(fmt, ...) \ ipc_log_string(dwc->dwc_ipc_log_ctxt,\ "%s: " fmt, __func__, ##__VA_ARGS__) /** * dwc3_gadget_ep_cmd_string - returns endpoint command string * @cmd: command code Loading
drivers/usb/dwc3/gadget.c +3 −0 Original line number Diff line number Diff line Loading @@ -3141,6 +3141,8 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) { u32 reg; usb_phy_start_link_training(dwc->usb3_phy); dwc->connected = true; /* Loading Loading @@ -3226,6 +3228,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) u8 speed; dbg_event(0xFF, "CONNECT DONE", 0); usb_phy_stop_link_training(dwc->usb3_phy); reg = dwc3_readl(dwc->regs, DWC3_DSTS); speed = reg & DWC3_DSTS_CONNECTSPD; dwc->speed = speed; Loading
drivers/usb/phy/phy-msm-ssusb-qmp.c +85 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <linux/usb/phy.h> #include <linux/clk.h> #include <linux/reset.h> #include <linux/hrtimer.h> enum core_ldo_levels { CORE_LEVEL_NONE = 0, Loading Loading @@ -79,6 +80,9 @@ enum core_ldo_levels { #define USB3_MODE BIT(0) /* enables USB3 mode */ #define DP_MODE BIT(1) /* enables DP mode */ /* USB3 Gen2 link training indicator */ #define RX_EQUALIZATION_IN_PROGRESS BIT(3) enum qmp_phy_rev_reg { USB3_PHY_PCS_STATUS, USB3_PHY_AUTONOMOUS_MODE_CTRL, Loading @@ -96,6 +100,9 @@ enum qmp_phy_rev_reg { USB3_DP_COM_TYPEC_CTRL, USB3_DP_COM_SWI_CTRL, USB3_PCS_MISC_CLAMP_ENABLE, USB3_DP_PCS_PCS_STATUS2, USB3_DP_PCS_INSIG_SW_CTRL3, USB3_DP_PCS_INSIG_MX_CTRL3, /* TypeC port select configuration (optional) */ USB3_PHY_PCS_MISC_TYPEC_CTRL, USB3_PHY_REG_MAX, Loading Loading @@ -136,6 +143,7 @@ struct msm_ssphy_qmp { int reg_offset_cnt; u32 *qmp_phy_init_seq; int init_seq_len; struct hrtimer timer; }; static const struct of_device_id msm_usb_id_table[] = { Loading Loading @@ -634,6 +642,7 @@ static int msm_ssphy_qmp_set_suspend(struct usb_phy *uphy, int suspend) /* Make sure above write completed with PHY */ wmb(); hrtimer_cancel(&phy->timer); msm_ssphy_qmp_enable_clks(phy, false); phy->in_suspend = true; msm_ssphy_power_enable(phy, 0); Loading @@ -658,6 +667,74 @@ static int msm_ssphy_qmp_set_suspend(struct usb_phy *uphy, int suspend) return 0; } static enum hrtimer_restart timer_fn(struct hrtimer *timer) { struct msm_ssphy_qmp *phy = container_of(timer, struct msm_ssphy_qmp, timer); u8 status2, status2_1, sw1, mx1, sw2, mx2; int timeout = 15000; status2_1 = sw1 = sw2 = mx1 = mx2 = 0; status2 = readl_relaxed(phy->base + phy->phy_reg[USB3_DP_PCS_PCS_STATUS2]); if (status2 & RX_EQUALIZATION_IN_PROGRESS) { while (timeout > 0) { status2_1 = readl_relaxed(phy->base + phy->phy_reg[USB3_DP_PCS_PCS_STATUS2]); if (status2_1 & RX_EQUALIZATION_IN_PROGRESS) { timeout -= 500; udelay(500); continue; } writel_relaxed(0x08, phy->base + phy->phy_reg[USB3_DP_PCS_INSIG_SW_CTRL3]); writel_relaxed(0x08, phy->base + phy->phy_reg[USB3_DP_PCS_INSIG_MX_CTRL3]); sw1 = readl_relaxed(phy->base + phy->phy_reg[USB3_DP_PCS_INSIG_SW_CTRL3]); mx1 = readl_relaxed(phy->base + phy->phy_reg[USB3_DP_PCS_INSIG_MX_CTRL3]); udelay(1); writel_relaxed(0x0, phy->base + phy->phy_reg[USB3_DP_PCS_INSIG_SW_CTRL3]); writel_relaxed(0x0, phy->base + phy->phy_reg[USB3_DP_PCS_INSIG_MX_CTRL3]); sw2 = readl_relaxed(phy->base + phy->phy_reg[USB3_DP_PCS_INSIG_SW_CTRL3]); mx2 = readl_relaxed(phy->base + phy->phy_reg[USB3_DP_PCS_INSIG_MX_CTRL3]); break; } } dev_dbg(phy->phy.dev, "st=%x st2=%x sw1=%x sw2=%x mx1=%x mx2=%x timeout=%d\n", status2, status2_1, sw1, sw2, mx1, mx2, timeout); hrtimer_forward_now(timer, ms_to_ktime(1)); return HRTIMER_RESTART; } static int msm_ssphy_qmp_link_training(struct usb_phy *uphy, bool start) { struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp, phy); if (start) { hrtimer_start(&phy->timer, 0, HRTIMER_MODE_REL); dev_dbg(uphy->dev, "link training start\n"); } else { hrtimer_cancel(&phy->timer); dev_dbg(uphy->dev, "link training stop\n"); } return 0; } static int msm_ssphy_qmp_notify_connect(struct usb_phy *uphy, enum usb_device_speed speed) { Loading @@ -680,6 +757,7 @@ static int msm_ssphy_qmp_notify_disconnect(struct usb_phy *uphy, phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); readl_relaxed(phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); hrtimer_cancel(&phy->timer); dev_dbg(uphy->dev, "QMP phy disconnect notification\n"); dev_dbg(uphy->dev, " cable_connected=%d\n", phy->cable_connected); phy->cable_connected = false; Loading Loading @@ -979,12 +1057,19 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) if (of_property_read_bool(dev->of_node, "qcom,vbus-valid-override")) phy->phy.flags |= PHY_VBUS_VALID_OVERRIDE; hrtimer_init(&phy->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); phy->timer.function = timer_fn; phy->phy.dev = dev; phy->phy.init = msm_ssphy_qmp_init; phy->phy.set_suspend = msm_ssphy_qmp_set_suspend; phy->phy.notify_connect = msm_ssphy_qmp_notify_connect; phy->phy.notify_disconnect = msm_ssphy_qmp_notify_disconnect; if (of_property_read_bool(dev->of_node, "qcom,link-training-reset")) phy->phy.link_training = msm_ssphy_qmp_link_training; if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP) phy->phy.reset = msm_ssphy_qmp_dp_combo_reset; else Loading