From 2a55b618e92726082bcbbedccc43e1bdafd04af9 Mon Sep 17 00:00:00 2001 From: Linyu Yuan Date: Wed, 25 Nov 2020 18:23:59 +0800 Subject: [PATCH 1/4] usb: phy: qmp: change orientation to default portselect mode if there are two modules control one same pin, each module will request and release one state, there is race when one module request state before another module complete relase it's state. revert to commit 87aee0bf556a ("usb: phy: qmp: Perform DP_COM_SW_RESET during portselect") to allow only one module control one pin. Change-Id: Ie6df02f018e58be8bf832b5b3921f5430fadbf53 Signed-off-by: Linyu Yuan --- drivers/usb/phy/phy-msm-ssusb-qmp.c | 56 ++++++----------------------- 1 file changed, 10 insertions(+), 46 deletions(-) diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c index f33c7726c0ba..dc9767bb52de 100644 --- a/drivers/usb/phy/phy-msm-ssusb-qmp.c +++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c @@ -370,51 +370,6 @@ static void msm_ssphy_qmp_setmode(struct msm_ssphy_qmp *phy, u32 mode) readl_relaxed(phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]); } -static void usb_qmp_update_hw_portselect(struct msm_ssphy_qmp *phy) -{ - struct pinctrl *portselect_pinctrl; - struct pinctrl_state *portselect_state; - u32 status; - - if (phy->phy.dev->pins) { - portselect_pinctrl = phy->phy.dev->pins->p; - portselect_state = phy->phy.dev->pins->default_state; - } else { - portselect_pinctrl = pinctrl_get(phy->phy.dev); - if (IS_ERR_OR_NULL(portselect_pinctrl)) { - dev_dbg(phy->phy.dev, "failed to get pinctrl\n"); - return; - } - - portselect_state = - pinctrl_lookup_state(portselect_pinctrl, "portselect"); - if (IS_ERR_OR_NULL(portselect_state)) { - dev_dbg(phy->phy.dev, - "failed to find portselect state\n"); - pinctrl_put(portselect_pinctrl); - return; - } - } - - writel_relaxed(0x01, - phy->base + phy->phy_reg[USB3_DP_COM_SW_RESET]); - - pinctrl_select_state(portselect_pinctrl, portselect_state); - - writel_relaxed(0x00, - phy->base + phy->phy_reg[USB3_DP_COM_SW_RESET]); - - if (!phy->phy.dev->pins) - pinctrl_put(portselect_pinctrl); - - if (phy->phy_reg[USB3_DP_COM_TYPEC_STATUS]) { - status = readl_relaxed(phy->base + - phy->phy_reg[USB3_DP_COM_TYPEC_STATUS]); - dev_dbg(phy->phy.dev, "hw port select %s\n", - status & PORTSELECT_RAW ? "CC2" : "CC1"); - } -} - static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy) { int val; @@ -431,7 +386,16 @@ static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy) switch (phy->phy_type) { case USB3_AND_DP: - usb_qmp_update_hw_portselect(phy); + if (phy->phy.dev->pins) { + writel_relaxed(0x01, + phy->base + phy->phy_reg[USB3_DP_COM_SW_RESET]); + + pinctrl_select_state(phy->phy.dev->pins->p, + phy->phy.dev->pins->default_state); + + writel_relaxed(0x00, + phy->base + phy->phy_reg[USB3_DP_COM_SW_RESET]); + } /* override hardware control for reset of qmp phy */ writel_relaxed(SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | From eba0b1fc29841006b4f2c8b2638333dc706d90c3 Mon Sep 17 00:00:00 2001 From: Linyu Yuan Date: Wed, 9 Dec 2020 15:00:39 +0800 Subject: [PATCH 2/4] usb: misc: nb7vpq904m: default gpio operation for orientaion There is possible crash when phy driver which control the same pin, 1. redriver driver read gpio state and start release state, 2. phy driver start request another state, 3. redriver driver finish release state, clear module owner, 4. phy driver string compare of module owner which is NULL to crash, prepare to fix it by provide orientaion for USB module. Change-Id: I177691abd702bac4f388fbbc0c375e19008f5adb Signed-off-by: Linyu Yuan --- drivers/usb/misc/ssusb-redriver-nb7vpq904m.c | 45 +++----------------- 1 file changed, 6 insertions(+), 39 deletions(-) diff --git a/drivers/usb/misc/ssusb-redriver-nb7vpq904m.c b/drivers/usb/misc/ssusb-redriver-nb7vpq904m.c index 9ca119f5a6bc..c7c2cb661365 100644 --- a/drivers/usb/misc/ssusb-redriver-nb7vpq904m.c +++ b/drivers/usb/misc/ssusb-redriver-nb7vpq904m.c @@ -85,7 +85,6 @@ struct ssusb_redriver { struct i2c_client *client; int orientation_gpio; - bool orientation_gpio_enable; enum plug_orientation typec_orientation; enum operation_mode op_mode; @@ -403,40 +402,15 @@ err: static int ssusb_redriver_read_orientation(struct ssusb_redriver *redriver) { - struct device *dev = redriver->dev; - struct pinctrl *orientation_pinctrl; - struct pinctrl_state *gpio_state; int ret; - if (!redriver->orientation_gpio_enable) + if (!gpio_is_valid(redriver->orientation_gpio)) return -EINVAL; - orientation_pinctrl = pinctrl_get(dev); - if (IS_ERR_OR_NULL(orientation_pinctrl)) { - dev_err(dev, "Failed to get pinctrl\n"); - return -EINVAL; - } - - gpio_state = pinctrl_lookup_state(orientation_pinctrl, "enable_gpio"); - if (IS_ERR_OR_NULL(gpio_state)) { - dev_err(dev, "Failed to get gpio state\n"); - ret = -ENODEV; - goto put_pinctrl; - } - - ret = pinctrl_select_state(orientation_pinctrl, gpio_state); - if (ret) { - dev_err(redriver->dev, "fail to enable gpio state\n"); - ret = -EINVAL; - goto put_pinctrl; - } - - /* wait for some time ??? */ ret = gpio_get_value(redriver->orientation_gpio); if (ret < 0) { dev_err(redriver->dev, "fail to read gpio value\n"); - ret = -EINVAL; - goto put_pinctrl; + return -EINVAL; } if (ret == 0) @@ -444,12 +418,7 @@ static int ssusb_redriver_read_orientation(struct ssusb_redriver *redriver) else redriver->typec_orientation = ORIENTATION_CC2; - ret = 0; - -put_pinctrl: - pinctrl_put(orientation_pinctrl); - - return ret; + return 0; } static int ssusb_redriver_ucsi_notifier(struct notifier_block *nb, @@ -669,9 +638,8 @@ static void ssusb_redriver_orientation_gpio_init( struct device *dev = redriver->dev; int rc; - redriver->orientation_gpio = - of_get_named_gpio(dev->of_node, "orientation_gpio", 0); - if (redriver->orientation_gpio < 0) { + redriver->orientation_gpio = of_get_gpio(dev->of_node, 0); + if (!gpio_is_valid(redriver->orientation_gpio)) { dev_err(dev, "Failed to get gpio\n"); return; } @@ -679,10 +647,9 @@ static void ssusb_redriver_orientation_gpio_init( rc = devm_gpio_request(dev, redriver->orientation_gpio, "redriver"); if (rc < 0) { dev_err(dev, "Failed to request gpio\n"); + redriver->orientation_gpio = -EINVAL; return; } - - redriver->orientation_gpio_enable = true; } static const struct regmap_config redriver_regmap = { From efa6204924a0d7e3a739982b02058ef79428df0e Mon Sep 17 00:00:00 2001 From: Linyu Yuan Date: Wed, 9 Dec 2020 14:05:44 +0800 Subject: [PATCH 3/4] usb: misc: nb7vpq904m: add redriver_orientation_get() provide orientation info for external module. Change-Id: I5e49e5f8071320beaf9d2f2a0390521d4d9f3b91 Signed-off-by: Linyu Yuan --- drivers/usb/misc/ssusb-redriver-nb7vpq904m.c | 23 ++++++++++++++++++++ include/linux/usb/redriver.h | 6 +++++ 2 files changed, 29 insertions(+) diff --git a/drivers/usb/misc/ssusb-redriver-nb7vpq904m.c b/drivers/usb/misc/ssusb-redriver-nb7vpq904m.c index c7c2cb661365..3849f2dab9ee 100644 --- a/drivers/usb/misc/ssusb-redriver-nb7vpq904m.c +++ b/drivers/usb/misc/ssusb-redriver-nb7vpq904m.c @@ -421,6 +421,29 @@ static int ssusb_redriver_read_orientation(struct ssusb_redriver *redriver) return 0; } +int redriver_orientation_get(struct device_node *node) +{ + struct ssusb_redriver *redriver; + struct i2c_client *client; + + if (!node) + return -ENODEV; + + client = of_find_i2c_device_by_node(node); + if (!client) + return -ENODEV; + + redriver = i2c_get_clientdata(client); + if (!redriver) + return -EINVAL; + + if (!gpio_is_valid(redriver->orientation_gpio)) + return -EINVAL; + + return gpio_get_value(redriver->orientation_gpio); +} +EXPORT_SYMBOL(redriver_orientation_get); + static int ssusb_redriver_ucsi_notifier(struct notifier_block *nb, unsigned long action, void *data) { diff --git a/include/linux/usb/redriver.h b/include/linux/usb/redriver.h index 2ad09e9a4d57..0ad48a87a725 100644 --- a/include/linux/usb/redriver.h +++ b/include/linux/usb/redriver.h @@ -12,6 +12,7 @@ int redriver_release_usb_lanes(struct device_node *node); int redriver_gadget_pullup(struct device_node *node, int is_on); int redriver_notify_connect(struct device_node *node); int redriver_notify_disconnect(struct device_node *node); +int redriver_orientation_get(struct device_node *node); #else @@ -35,6 +36,11 @@ static inline int redriver_notify_disconnect(struct device_node *node) return 0; } +static inline int redriver_orientation_get(struct device_node *node) +{ + return -ENODEV; +} + #endif #endif /*__LINUX_USB_REDRIVER_H */ From f32272fde30fce509363a87fc40a65d046cd2b01 Mon Sep 17 00:00:00 2001 From: Linyu Yuan Date: Wed, 9 Dec 2020 14:29:25 +0800 Subject: [PATCH 4/4] usb: dwc3: allow get orientation from redriver call redriver_orientation_get() to get orientation if redriver present. Change-Id: I1ed69fece1f7577e2c478631920fb1bb3fe93cd1 Signed-off-by: Linyu Yuan --- drivers/usb/dwc3/dwc3-msm.c | 72 +++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 11af30370cb9..d2a344ccfd45 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -287,13 +287,6 @@ enum dwc3_id_state { DWC3_ID_FLOAT, }; -/* for type c cable */ -enum plug_orientation { - ORIENTATION_NONE, - ORIENTATION_CC1, - ORIENTATION_CC2, -}; - enum msm_usb_irq { HS_PHY_IRQ, PWR_EVNT_IRQ, @@ -476,7 +469,6 @@ struct dwc3_msm { atomic_t in_p3; unsigned int lpm_to_suspend_delay; - enum plug_orientation typec_orientation; u32 num_gsi_event_buffers; struct dwc3_event_buffer **gsi_ev_buff; int pm_qos_latency; @@ -2668,6 +2660,45 @@ static void dwc3_set_phy_speed_flags(struct dwc3_msm *mdwc) } } +static void dwc3_set_ssphy_orientation_flag(struct dwc3_msm *mdwc) +{ + struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); + union extcon_property_value val; + struct extcon_dev *edev = NULL; + unsigned int extcon_id; + int ret; + + mdwc->ss_phy->flags &= ~(PHY_LANE_A | PHY_LANE_B); + + if (mdwc->orientation_override) { + mdwc->ss_phy->flags |= mdwc->orientation_override; + } else if (mdwc->ss_redriver_node) { + ret = redriver_orientation_get(mdwc->ss_redriver_node); + if (ret == 0) + mdwc->ss_phy->flags |= PHY_LANE_A; + else + mdwc->ss_phy->flags |= PHY_LANE_B; + } else { + if (mdwc->extcon && mdwc->vbus_active && !mdwc->in_restart) { + extcon_id = EXTCON_USB; + edev = mdwc->extcon[mdwc->ext_idx].edev; + } else if (mdwc->extcon && mdwc->id_state == DWC3_ID_GROUND) { + extcon_id = EXTCON_USB_HOST; + edev = mdwc->extcon[mdwc->ext_idx].edev; + } + + if (edev && extcon_get_state(edev, extcon_id)) { + ret = extcon_get_property(edev, extcon_id, + EXTCON_PROP_USB_TYPEC_POLARITY, &val); + if (ret == 0) + mdwc->ss_phy->flags |= val.intval ? + PHY_LANE_B : PHY_LANE_A; + } + } + + dbg_event(0xFF, "ss_flag", mdwc->ss_phy->flags); +} + static void msm_dwc3_perf_vote_update(struct dwc3_msm *mdwc, bool perf_mode); @@ -3079,13 +3110,7 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) /* Resume SS PHY */ if (dwc->maximum_speed >= USB_SPEED_SUPER && mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND) { - mdwc->ss_phy->flags &= ~(PHY_LANE_A | PHY_LANE_B); - if (mdwc->orientation_override) - mdwc->ss_phy->flags |= mdwc->orientation_override; - else if (mdwc->typec_orientation == ORIENTATION_CC1) - mdwc->ss_phy->flags |= PHY_LANE_A; - else if (mdwc->typec_orientation == ORIENTATION_CC2) - mdwc->ss_phy->flags |= PHY_LANE_B; + dwc3_set_ssphy_orientation_flag(mdwc); usb_phy_set_suspend(mdwc->ss_phy, 0); mdwc->ss_phy->flags &= ~DEVICE_IN_SS_MODE; mdwc->lpm_flags &= ~MDWC3_SS_PHY_SUSPEND; @@ -3269,25 +3294,18 @@ static void dwc3_resume_work(struct work_struct *w) } dwc->maximum_speed = dwc->max_hw_supp_speed; - /* Check speed and Type-C polarity values in order to configure PHY */ + if (edev && extcon_get_state(edev, extcon_id)) { ret = extcon_get_property(edev, extcon_id, EXTCON_PROP_USB_SS, &val); if (!ret && val.intval == 0) dwc->maximum_speed = USB_SPEED_HIGH; - - ret = extcon_get_property(edev, extcon_id, - EXTCON_PROP_USB_TYPEC_POLARITY, &val); - if (ret) - mdwc->typec_orientation = ORIENTATION_NONE; - else - mdwc->typec_orientation = val.intval ? - ORIENTATION_CC2 : ORIENTATION_CC1; - - dbg_event(0xFF, "cc_state", mdwc->typec_orientation); } + if (dwc->maximum_speed >= USB_SPEED_SUPER) + dwc3_set_ssphy_orientation_flag(mdwc); + skip_update: dbg_log_string("max_speed:%d hw_supp_speed:%d override_speed:%d", dwc->maximum_speed, dwc->max_hw_supp_speed, @@ -3805,7 +3823,7 @@ static ssize_t orientation_store(struct device *dev, else if (sysfs_streq(buf, "B")) mdwc->orientation_override = PHY_LANE_B; else - mdwc->orientation_override = ORIENTATION_NONE; + mdwc->orientation_override = 0; return count; }