Message ID | 20230828133033.11988-7-quic_kriskura@quicinc.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | Add multiport support for DWC3 controllers | expand |
Hi Krishna, On 8/28/2023 6:30 AM, Krishna Kurapati wrote: > From: Harsh Agarwal <quic_harshq@quicinc.com> > > Currently the DWC3 driver supports only single port controller > which requires at most one HS and one SS PHY. > > But the DWC3 USB controller can be connected to multiple ports and > each port can have their own PHYs. Each port of the multiport > controller can either be HS+SS capable or HS only capable > Proper quantification of them is required to modify GUSB2PHYCFG > and GUSB3PIPECTL registers appropriately. > > Add support for detecting, obtaining and configuring phy's supported > by a multiport controller and. Limit the max number of ports > supported to 4 as only SC8280 which is a quad port controller supports > Multiport currently. > > Co-developed-by: Harsh Agarwal <quic_harshq@quicinc.com> > Signed-off-by: Harsh Agarwal <quic_harshq@quicinc.com> > Co-developed-by:Krishna Kurapati <quic_kriskura@quicinc.com> > Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com> > --- > drivers/usb/dwc3/core.c | 252 +++++++++++++++++++++++++++------------- > drivers/usb/dwc3/core.h | 11 +- > drivers/usb/dwc3/drd.c | 15 ++- > 3 files changed, 190 insertions(+), 88 deletions(-) > > diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c > index 6eacf0ff90b5..31400c309bff 100644 > --- a/drivers/usb/dwc3/core.c > +++ b/drivers/usb/dwc3/core.c > @@ -124,6 +124,7 @@ static void __dwc3_set_mode(struct work_struct *work) > int ret; > u32 reg; > u32 desired_dr_role; > + int i; > > mutex_lock(&dwc->mutex); > spin_lock_irqsave(&dwc->lock, flags); > @@ -201,8 +202,10 @@ static void __dwc3_set_mode(struct work_struct *work) > } else { > if (dwc->usb2_phy) > otg_set_vbus(dwc->usb2_phy->otg, true); > - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST); > - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST); > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + phy_set_mode(dwc->usb2_generic_phy[i], PHY_MODE_USB_HOST); > + phy_set_mode(dwc->usb3_generic_phy[i], PHY_MODE_USB_HOST); > + } > if (dwc->dis_split_quirk) { > reg = dwc3_readl(dwc->regs, DWC3_GUCTL3); > reg |= DWC3_GUCTL3_SPLITDISABLE; > @@ -217,8 +220,8 @@ static void __dwc3_set_mode(struct work_struct *work) > > if (dwc->usb2_phy) > otg_set_vbus(dwc->usb2_phy->otg, false); > - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); > - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); > + phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE); > + phy_set_mode(dwc->usb3_generic_phy[0], PHY_MODE_USB_DEVICE); > Throughout this patch, you are looping across all PHYs irrespective of if we are in device mode or not. This is the only exception where you are setting only PHY index 0 (for both SS and HS PHYs). Do you think we should also only modify PHY index#0 for other PHY related sequences? > ret = dwc3_gadget_init(dwc); > if (ret) > @@ -589,22 +592,14 @@ static int dwc3_core_ulpi_init(struct dwc3 *dwc) > return ret; > } > > -/** > - * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core > - * @dwc: Pointer to our controller context structure > - * > - * Returns 0 on success. The USB PHY interfaces are configured but not > - * initialized. The PHY interfaces and the PHYs get initialized together with > - * the core in dwc3_core_init. > - */ > -static int dwc3_phy_setup(struct dwc3 *dwc) > +static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index) > { > unsigned int hw_mode; > u32 reg; > > hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); > > - reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); > + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(index)); > > /* > * Make sure UX_EXIT_PX is cleared as that causes issues with some > @@ -659,9 +654,19 @@ static int dwc3_phy_setup(struct dwc3 *dwc) > if (dwc->dis_del_phy_power_chg_quirk) > reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE; > > - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); > + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(index), reg); > > - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); > + return 0; > +} > + > +static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index) > +{ > + unsigned int hw_mode; > + u32 reg; > + > + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); > + > + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(index)); > > /* Select the HS PHY interface */ > switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) { > @@ -673,7 +678,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc) > } else if (dwc->hsphy_interface && > !strncmp(dwc->hsphy_interface, "ulpi", 4)) { > reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI; > - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); > + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg); > } else { > /* Relying on default value. */ > if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI)) > @@ -740,7 +745,35 @@ static int dwc3_phy_setup(struct dwc3 *dwc) > if (dwc->ulpi_ext_vbus_drv) > reg |= DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV; > > - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); > + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg); > + > + return 0; > +} > + > +/** > + * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core > + * @dwc: Pointer to our controller context structure > + * > + * Returns 0 on success. The USB PHY interfaces are configured but not > + * initialized. The PHY interfaces and the PHYs get initialized together with > + * the core in dwc3_core_init. > + */ > +static int dwc3_phy_setup(struct dwc3 *dwc) > +{ > + int i; > + int ret; > + > + for (i = 0; i < dwc->num_usb3_ports; i++) { > + ret = dwc3_ss_phy_setup(dwc, i); > + if (ret) > + return ret; > + } > + > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + ret = dwc3_hs_phy_setup(dwc, i); > + if (ret) > + return ret; > + } > > return 0; > } > @@ -748,23 +781,32 @@ static int dwc3_phy_setup(struct dwc3 *dwc) > static int dwc3_phy_init(struct dwc3 *dwc) > { > int ret; > + int i; > + int j; > > usb_phy_init(dwc->usb2_phy); > usb_phy_init(dwc->usb3_phy); > > - ret = phy_init(dwc->usb2_generic_phy); > - if (ret < 0) > - goto err_shutdown_usb3_phy; > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + ret = phy_init(dwc->usb2_generic_phy[i]); > + if (ret < 0) > + goto err_exit_phy; > > - ret = phy_init(dwc->usb3_generic_phy); > - if (ret < 0) > - goto err_exit_usb2_phy; > + ret = phy_init(dwc->usb3_generic_phy[i]); > + if (ret < 0) { > + phy_exit(dwc->usb2_generic_phy[i]); > + goto err_exit_phy; > + } > + } > > return 0; > > -err_exit_usb2_phy: > - phy_exit(dwc->usb2_generic_phy); > -err_shutdown_usb3_phy: > +err_exit_phy: > + for (j = i - 1; j >= 0; j--) { > + phy_exit(dwc->usb2_generic_phy[j]); > + phy_exit(dwc->usb3_generic_phy[j]); > + } > + > usb_phy_shutdown(dwc->usb3_phy); > usb_phy_shutdown(dwc->usb2_phy); > > @@ -773,8 +815,12 @@ static int dwc3_phy_init(struct dwc3 *dwc) > > static void dwc3_phy_exit(struct dwc3 *dwc) > { > - phy_exit(dwc->usb3_generic_phy); > - phy_exit(dwc->usb2_generic_phy); > + int i; > + > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + phy_exit(dwc->usb3_generic_phy[i]); > + phy_exit(dwc->usb2_generic_phy[i]); > + } > > usb_phy_shutdown(dwc->usb3_phy); > usb_phy_shutdown(dwc->usb2_phy); > @@ -783,23 +829,32 @@ static void dwc3_phy_exit(struct dwc3 *dwc) > static int dwc3_phy_power_on(struct dwc3 *dwc) > { > int ret; > + int i; > + int j; > > usb_phy_set_suspend(dwc->usb2_phy, 0); > usb_phy_set_suspend(dwc->usb3_phy, 0); > > - ret = phy_power_on(dwc->usb2_generic_phy); > - if (ret < 0) > - goto err_suspend_usb3_phy; > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + ret = phy_power_on(dwc->usb2_generic_phy[i]); > + if (ret < 0) > + goto err_power_off_phy; > > - ret = phy_power_on(dwc->usb3_generic_phy); > - if (ret < 0) > - goto err_power_off_usb2_phy; > + ret = phy_power_on(dwc->usb3_generic_phy[i]); > + if (ret < 0) { > + phy_power_off(dwc->usb2_generic_phy[i]); > + goto err_power_off_phy; > + } > + } > > return 0; > > -err_power_off_usb2_phy: > - phy_power_off(dwc->usb2_generic_phy); > -err_suspend_usb3_phy: > +err_power_off_phy: > + for (j = i - 1; j >= 0; j--) { > + phy_power_off(dwc->usb2_generic_phy[j]); > + phy_power_off(dwc->usb3_generic_phy[j]); > + } > + > usb_phy_set_suspend(dwc->usb3_phy, 1); > usb_phy_set_suspend(dwc->usb2_phy, 1); > > @@ -808,8 +863,12 @@ static int dwc3_phy_power_on(struct dwc3 *dwc) > > static void dwc3_phy_power_off(struct dwc3 *dwc) > { > - phy_power_off(dwc->usb3_generic_phy); > - phy_power_off(dwc->usb2_generic_phy); > + int i; > + > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + phy_power_off(dwc->usb3_generic_phy[i]); > + phy_power_off(dwc->usb2_generic_phy[i]); > + } > > usb_phy_set_suspend(dwc->usb3_phy, 1); > usb_phy_set_suspend(dwc->usb2_phy, 1); > @@ -1082,6 +1141,7 @@ static int dwc3_core_init(struct dwc3 *dwc) > unsigned int hw_mode; > u32 reg; > int ret; > + int i; > > hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); > > @@ -1125,15 +1185,19 @@ static int dwc3_core_init(struct dwc3 *dwc) > if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && > !DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) { > if (!dwc->dis_u3_susphy_quirk) { > - reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); > - reg |= DWC3_GUSB3PIPECTL_SUSPHY; > - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); > + for (i = 0; i < dwc->num_usb3_ports; i++) { > + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(i)); > + reg |= DWC3_GUSB3PIPECTL_SUSPHY; > + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(i), reg); > + } > } > > if (!dwc->dis_u2_susphy_quirk) { > - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); > - reg |= DWC3_GUSB2PHYCFG_SUSPHY; > - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i)); > + reg |= DWC3_GUSB2PHYCFG_SUSPHY; > + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg); > + } > } > } > > @@ -1276,7 +1340,9 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) > { > struct device *dev = dwc->dev; > struct device_node *node = dev->of_node; > + char phy_name[11]; > int ret; > + int i; > > if (node) { > dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); > @@ -1302,22 +1368,36 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) > return dev_err_probe(dev, ret, "no usb3 phy configured\n"); > } > > - dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy"); > - if (IS_ERR(dwc->usb2_generic_phy)) { > - ret = PTR_ERR(dwc->usb2_generic_phy); > - if (ret == -ENOSYS || ret == -ENODEV) > - dwc->usb2_generic_phy = NULL; > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + if (dwc->num_usb2_ports == 1) > + sprintf(phy_name, "usb2-phy"); > else > - return dev_err_probe(dev, ret, "no usb2 phy configured\n"); > - } > + sprintf(phy_name, "usb2-port%d", i); > > - dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy"); > - if (IS_ERR(dwc->usb3_generic_phy)) { > - ret = PTR_ERR(dwc->usb3_generic_phy); > - if (ret == -ENOSYS || ret == -ENODEV) > - dwc->usb3_generic_phy = NULL; > + dwc->usb2_generic_phy[i] = devm_phy_get(dev, phy_name); > + if (IS_ERR(dwc->usb2_generic_phy[i])) { > + ret = PTR_ERR(dwc->usb2_generic_phy[i]); > + if (ret == -ENOSYS || ret == -ENODEV) > + dwc->usb2_generic_phy[i] = NULL; > + else > + return dev_err_probe(dev, ret, > + "failed to lookup phy %s\n", phy_name); > + } > + > + if (dwc->num_usb2_ports == 1) > + sprintf(phy_name, "usb3-phy"); > else > - return dev_err_probe(dev, ret, "no usb3 phy configured\n"); > + sprintf(phy_name, "usb3-port%d", i); > + > + dwc->usb3_generic_phy[i] = devm_phy_get(dev, phy_name); > + if (IS_ERR(dwc->usb3_generic_phy[i])) { > + ret = PTR_ERR(dwc->usb3_generic_phy[i]); > + if (ret == -ENOSYS || ret == -ENODEV) > + dwc->usb3_generic_phy[i] = NULL; > + else > + return dev_err_probe(dev, ret, > + "failed to lookup phy %s\n", phy_name); > + } > } > > return 0; > @@ -1327,6 +1407,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) > { > struct device *dev = dwc->dev; > int ret; > + int i; > > switch (dwc->dr_mode) { > case USB_DR_MODE_PERIPHERAL: > @@ -1334,8 +1415,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) > > if (dwc->usb2_phy) > otg_set_vbus(dwc->usb2_phy->otg, false); > - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); > - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); > + phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE); > + phy_set_mode(dwc->usb3_generic_phy[0], PHY_MODE_USB_DEVICE); > > ret = dwc3_gadget_init(dwc); > if (ret) > @@ -1346,8 +1427,10 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) > > if (dwc->usb2_phy) > otg_set_vbus(dwc->usb2_phy->otg, true); > - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST); > - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST); > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + phy_set_mode(dwc->usb2_generic_phy[i], PHY_MODE_USB_HOST); > + phy_set_mode(dwc->usb3_generic_phy[i], PHY_MODE_USB_HOST); > + } > > ret = dwc3_host_init(dwc); > if (ret) > @@ -1804,9 +1887,12 @@ static int dwc3_read_port_info(struct dwc3 *dwc) > > dev_dbg(dwc->dev, "hs-ports: %u ss-ports: %u\n", > dwc->num_usb2_ports, dwc->num_usb3_ports); > - > iounmap(base); > > + if ((dwc->num_usb2_ports > DWC3_MAX_PORTS) || > + (dwc->num_usb3_ports > DWC3_MAX_PORTS)) > + return -ENOMEM; > + Shouldn't this be more applicable to be included in patch#4 in this series? Thanks Wesley Cheng > return 0; > } > > @@ -2042,6 +2128,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) > { > unsigned long flags; > u32 reg; > + int i; > > switch (dwc->current_dr_role) { > case DWC3_GCTL_PRTCAP_DEVICE: > @@ -2060,17 +2147,21 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) > /* Let controller to suspend HSPHY before PHY driver suspends */ > if (dwc->dis_u2_susphy_quirk || > dwc->dis_enblslpm_quirk) { > - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); > - reg |= DWC3_GUSB2PHYCFG_ENBLSLPM | > - DWC3_GUSB2PHYCFG_SUSPHY; > - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i)); > + reg |= DWC3_GUSB2PHYCFG_ENBLSLPM | > + DWC3_GUSB2PHYCFG_SUSPHY; > + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg); > + } > > /* Give some time for USB2 PHY to suspend */ > usleep_range(5000, 6000); > } > > - phy_pm_runtime_put_sync(dwc->usb2_generic_phy); > - phy_pm_runtime_put_sync(dwc->usb3_generic_phy); > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + phy_pm_runtime_put_sync(dwc->usb2_generic_phy[i]); > + phy_pm_runtime_put_sync(dwc->usb3_generic_phy[i]); > + } > break; > case DWC3_GCTL_PRTCAP_OTG: > /* do nothing during runtime_suspend */ > @@ -2100,6 +2191,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) > unsigned long flags; > int ret; > u32 reg; > + int i; > > switch (dwc->current_dr_role) { > case DWC3_GCTL_PRTCAP_DEVICE: > @@ -2119,17 +2211,21 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) > break; > } > /* Restore GUSB2PHYCFG bits that were modified in suspend */ > - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); > - if (dwc->dis_u2_susphy_quirk) > - reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i)); > + if (dwc->dis_u2_susphy_quirk) > + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; > > - if (dwc->dis_enblslpm_quirk) > - reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; > + if (dwc->dis_enblslpm_quirk) > + reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; > > - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); > + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg); > + } > > - phy_pm_runtime_get_sync(dwc->usb2_generic_phy); > - phy_pm_runtime_get_sync(dwc->usb3_generic_phy); > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + phy_pm_runtime_get_sync(dwc->usb2_generic_phy[i]); > + phy_pm_runtime_get_sync(dwc->usb3_generic_phy[i]); > + } > break; > case DWC3_GCTL_PRTCAP_OTG: > /* nothing to do on runtime_resume */ > diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h > index 5b0f2aa115d2..5521dc9ca034 100644 > --- a/drivers/usb/dwc3/core.h > +++ b/drivers/usb/dwc3/core.h > @@ -33,6 +33,9 @@ > > #include <linux/power_supply.h> > > +/* Number of ports supported by a multiport controller */ > +#define DWC3_MAX_PORTS 4 > + > #define DWC3_MSG_MAX 500 > > /* Global constants */ > @@ -1024,8 +1027,8 @@ struct dwc3_scratchpad_array { > * @usb_psy: pointer to power supply interface. > * @usb2_phy: pointer to USB2 PHY > * @usb3_phy: pointer to USB3 PHY > - * @usb2_generic_phy: pointer to USB2 PHY > - * @usb3_generic_phy: pointer to USB3 PHY > + * @usb2_generic_phy: pointer to array of USB2 PHY > + * @usb3_generic_phy: pointer to array of USB3 PHY > * @num_usb2_ports: number of USB2 ports > * @num_usb3_ports: number of USB3 ports > * @phys_ready: flag to indicate that PHYs are ready > @@ -1164,8 +1167,8 @@ struct dwc3 { > struct usb_phy *usb2_phy; > struct usb_phy *usb3_phy; > > - struct phy *usb2_generic_phy; > - struct phy *usb3_generic_phy; > + struct phy *usb2_generic_phy[DWC3_MAX_PORTS]; > + struct phy *usb3_generic_phy[DWC3_MAX_PORTS]; > > u8 num_usb2_ports; > u8 num_usb3_ports; > diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c > index 039bf241769a..9aec41f1ad43 100644 > --- a/drivers/usb/dwc3/drd.c > +++ b/drivers/usb/dwc3/drd.c > @@ -331,6 +331,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) > u32 reg; > int id; > unsigned long flags; > + int i; > > if (dwc->dr_mode != USB_DR_MODE_OTG) > return; > @@ -386,9 +387,12 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) > } else { > if (dwc->usb2_phy) > otg_set_vbus(dwc->usb2_phy->otg, true); > - if (dwc->usb2_generic_phy) > - phy_set_mode(dwc->usb2_generic_phy, > - PHY_MODE_USB_HOST); > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + if (dwc->usb2_generic_phy[i]) { > + phy_set_mode(dwc->usb2_generic_phy[i], > + PHY_MODE_USB_HOST); > + } > + } > } > break; > case DWC3_OTG_ROLE_DEVICE: > @@ -400,9 +404,8 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) > > if (dwc->usb2_phy) > otg_set_vbus(dwc->usb2_phy->otg, false); > - if (dwc->usb2_generic_phy) > - phy_set_mode(dwc->usb2_generic_phy, > - PHY_MODE_USB_DEVICE); > + if (dwc->usb2_generic_phy[0]) > + phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE); > ret = dwc3_gadget_init(dwc); > if (ret) > dev_err(dwc->dev, "failed to initialize peripheral\n");
On 9/1/2023 6:43 AM, Wesley Cheng wrote: > Hi Krishna, > >> if (dwc->usb2_phy) >> otg_set_vbus(dwc->usb2_phy->otg, false); >> - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); >> - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); >> + phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE); >> + phy_set_mode(dwc->usb3_generic_phy[0], PHY_MODE_USB_DEVICE); > > Throughout this patch, you are looping across all PHYs irrespective of > if we are in device mode or not. This is the only exception where you > are setting only PHY index 0 (for both SS and HS PHYs). Do you think we > should also only modify PHY index#0 for other PHY related sequences? > Hi Wesley, Multiport controllers are host only capable currently. So if the GHWPARAMS indicate we are DRD/peripheral capable, we set num_usb2/3_ports to "1" unconditionally. So there would not be any looping necessary here. >> if (ret) >> @@ -1804,9 +1887,12 @@ static int dwc3_read_port_info(struct dwc3 *dwc) >> dev_dbg(dwc->dev, "hs-ports: %u ss-ports: %u\n", >> dwc->num_usb2_ports, dwc->num_usb3_ports); >> - >> iounmap(base); >> + if ((dwc->num_usb2_ports > DWC3_MAX_PORTS) || >> + (dwc->num_usb3_ports > DWC3_MAX_PORTS)) >> + return -ENOMEM; >> + > > Shouldn't this be more applicable to be included in patch#4 in this series? > The read_port_info function was only initially intended to read only port count and later the macro was added. So the check was put here. Regards, Krishna,
Hi Krishna, kernel test robot noticed the following build warnings: [auto build test WARNING on usb/usb-testing] [also build test WARNING on usb/usb-next usb/usb-linus robh/for-next pza/reset/next linus/master v6.6-rc2 next-20230919] [cannot apply to pza/imx-drm/next] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Krishna-Kurapati/dt-bindings-usb-qcom-dwc3-Add-bindings-for-SC8280-Multiport/20230828-214326 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing patch link: https://lore.kernel.org/r/20230828133033.11988-7-quic_kriskura%40quicinc.com patch subject: [PATCH v11 06/13] usb: dwc3: core: Refactor PHY logic to support Multiport Controller config: x86_64-randconfig-011-20230902 (https://download.01.org/0day-ci/archive/20230920/202309200156.CxQ3yaLY-lkp@intel.com/config) compiler: gcc-12 (Debian 12.2.0-14) 12.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20230920/202309200156.CxQ3yaLY-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202309200156.CxQ3yaLY-lkp@intel.com/ All warnings (new ones prefixed by >>): drivers/usb/dwc3/core.c: In function 'dwc3_core_get_phy': >> drivers/usb/dwc3/core.c:1375:53: warning: '%d' directive writing between 1 and 3 bytes into a region of size 2 [-Wformat-overflow=] 1375 | sprintf(phy_name, "usb2-port%d", i); | ^~ drivers/usb/dwc3/core.c:1375:43: note: directive argument in the range [0, 254] 1375 | sprintf(phy_name, "usb2-port%d", i); | ^~~~~~~~~~~~~ drivers/usb/dwc3/core.c:1375:25: note: 'sprintf' output between 11 and 13 bytes into a destination of size 11 1375 | sprintf(phy_name, "usb2-port%d", i); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/usb/dwc3/core.c:1390:53: warning: '%d' directive writing between 1 and 3 bytes into a region of size 2 [-Wformat-overflow=] 1390 | sprintf(phy_name, "usb3-port%d", i); | ^~ drivers/usb/dwc3/core.c:1390:43: note: directive argument in the range [0, 254] 1390 | sprintf(phy_name, "usb3-port%d", i); | ^~~~~~~~~~~~~ drivers/usb/dwc3/core.c:1390:25: note: 'sprintf' output between 11 and 13 bytes into a destination of size 11 1390 | sprintf(phy_name, "usb3-port%d", i); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ vim +1375 drivers/usb/dwc3/core.c 1338 1339 static int dwc3_core_get_phy(struct dwc3 *dwc) 1340 { 1341 struct device *dev = dwc->dev; 1342 struct device_node *node = dev->of_node; 1343 char phy_name[11]; 1344 int ret; 1345 int i; 1346 1347 if (node) { 1348 dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); 1349 dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); 1350 } else { 1351 dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); 1352 dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); 1353 } 1354 1355 if (IS_ERR(dwc->usb2_phy)) { 1356 ret = PTR_ERR(dwc->usb2_phy); 1357 if (ret == -ENXIO || ret == -ENODEV) 1358 dwc->usb2_phy = NULL; 1359 else 1360 return dev_err_probe(dev, ret, "no usb2 phy configured\n"); 1361 } 1362 1363 if (IS_ERR(dwc->usb3_phy)) { 1364 ret = PTR_ERR(dwc->usb3_phy); 1365 if (ret == -ENXIO || ret == -ENODEV) 1366 dwc->usb3_phy = NULL; 1367 else 1368 return dev_err_probe(dev, ret, "no usb3 phy configured\n"); 1369 } 1370 1371 for (i = 0; i < dwc->num_usb2_ports; i++) { 1372 if (dwc->num_usb2_ports == 1) 1373 sprintf(phy_name, "usb2-phy"); 1374 else > 1375 sprintf(phy_name, "usb2-port%d", i); 1376 1377 dwc->usb2_generic_phy[i] = devm_phy_get(dev, phy_name); 1378 if (IS_ERR(dwc->usb2_generic_phy[i])) { 1379 ret = PTR_ERR(dwc->usb2_generic_phy[i]); 1380 if (ret == -ENOSYS || ret == -ENODEV) 1381 dwc->usb2_generic_phy[i] = NULL; 1382 else 1383 return dev_err_probe(dev, ret, 1384 "failed to lookup phy %s\n", phy_name); 1385 } 1386 1387 if (dwc->num_usb2_ports == 1) 1388 sprintf(phy_name, "usb3-phy"); 1389 else 1390 sprintf(phy_name, "usb3-port%d", i); 1391 1392 dwc->usb3_generic_phy[i] = devm_phy_get(dev, phy_name); 1393 if (IS_ERR(dwc->usb3_generic_phy[i])) { 1394 ret = PTR_ERR(dwc->usb3_generic_phy[i]); 1395 if (ret == -ENOSYS || ret == -ENODEV) 1396 dwc->usb3_generic_phy[i] = NULL; 1397 else 1398 return dev_err_probe(dev, ret, 1399 "failed to lookup phy %s\n", phy_name); 1400 } 1401 } 1402 1403 return 0; 1404 } 1405
On Mon, Aug 28, 2023, Krishna Kurapati wrote: > From: Harsh Agarwal <quic_harshq@quicinc.com> > > Currently the DWC3 driver supports only single port controller > which requires at most one HS and one SS PHY. > > But the DWC3 USB controller can be connected to multiple ports and > each port can have their own PHYs. Each port of the multiport > controller can either be HS+SS capable or HS only capable > Proper quantification of them is required to modify GUSB2PHYCFG > and GUSB3PIPECTL registers appropriately. > > Add support for detecting, obtaining and configuring phy's supported > by a multiport controller and. Limit the max number of ports > supported to 4 as only SC8280 which is a quad port controller supports > Multiport currently. > > Co-developed-by: Harsh Agarwal <quic_harshq@quicinc.com> > Signed-off-by: Harsh Agarwal <quic_harshq@quicinc.com> > Co-developed-by:Krishna Kurapati <quic_kriskura@quicinc.com> > Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com> > --- > drivers/usb/dwc3/core.c | 252 +++++++++++++++++++++++++++------------- > drivers/usb/dwc3/core.h | 11 +- > drivers/usb/dwc3/drd.c | 15 ++- > 3 files changed, 190 insertions(+), 88 deletions(-) > > diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c > index 6eacf0ff90b5..31400c309bff 100644 > --- a/drivers/usb/dwc3/core.c > +++ b/drivers/usb/dwc3/core.c > @@ -124,6 +124,7 @@ static void __dwc3_set_mode(struct work_struct *work) > int ret; > u32 reg; > u32 desired_dr_role; > + int i; > > mutex_lock(&dwc->mutex); > spin_lock_irqsave(&dwc->lock, flags); > @@ -201,8 +202,10 @@ static void __dwc3_set_mode(struct work_struct *work) > } else { > if (dwc->usb2_phy) > otg_set_vbus(dwc->usb2_phy->otg, true); > - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST); > - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST); > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + phy_set_mode(dwc->usb2_generic_phy[i], PHY_MODE_USB_HOST); > + phy_set_mode(dwc->usb3_generic_phy[i], PHY_MODE_USB_HOST); > + } > if (dwc->dis_split_quirk) { > reg = dwc3_readl(dwc->regs, DWC3_GUCTL3); > reg |= DWC3_GUCTL3_SPLITDISABLE; > @@ -217,8 +220,8 @@ static void __dwc3_set_mode(struct work_struct *work) > > if (dwc->usb2_phy) > otg_set_vbus(dwc->usb2_phy->otg, false); > - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); > - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); > + phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE); > + phy_set_mode(dwc->usb3_generic_phy[0], PHY_MODE_USB_DEVICE); > > ret = dwc3_gadget_init(dwc); > if (ret) > @@ -589,22 +592,14 @@ static int dwc3_core_ulpi_init(struct dwc3 *dwc) > return ret; > } > > -/** > - * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core > - * @dwc: Pointer to our controller context structure > - * > - * Returns 0 on success. The USB PHY interfaces are configured but not > - * initialized. The PHY interfaces and the PHYs get initialized together with > - * the core in dwc3_core_init. > - */ > -static int dwc3_phy_setup(struct dwc3 *dwc) > +static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index) > { > unsigned int hw_mode; > u32 reg; > > hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); > > - reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); > + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(index)); > > /* > * Make sure UX_EXIT_PX is cleared as that causes issues with some > @@ -659,9 +654,19 @@ static int dwc3_phy_setup(struct dwc3 *dwc) > if (dwc->dis_del_phy_power_chg_quirk) > reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE; > > - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); > + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(index), reg); > > - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); > + return 0; > +} > + > +static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index) > +{ > + unsigned int hw_mode; > + u32 reg; > + > + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); > + > + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(index)); > > /* Select the HS PHY interface */ > switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) { > @@ -673,7 +678,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc) > } else if (dwc->hsphy_interface && > !strncmp(dwc->hsphy_interface, "ulpi", 4)) { > reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI; > - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); > + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg); > } else { > /* Relying on default value. */ > if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI)) > @@ -740,7 +745,35 @@ static int dwc3_phy_setup(struct dwc3 *dwc) > if (dwc->ulpi_ext_vbus_drv) > reg |= DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV; > > - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); > + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg); > + > + return 0; > +} > + > +/** > + * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core > + * @dwc: Pointer to our controller context structure > + * > + * Returns 0 on success. The USB PHY interfaces are configured but not > + * initialized. The PHY interfaces and the PHYs get initialized together with > + * the core in dwc3_core_init. > + */ > +static int dwc3_phy_setup(struct dwc3 *dwc) > +{ > + int i; > + int ret; > + > + for (i = 0; i < dwc->num_usb3_ports; i++) { > + ret = dwc3_ss_phy_setup(dwc, i); > + if (ret) > + return ret; > + } > + > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + ret = dwc3_hs_phy_setup(dwc, i); > + if (ret) > + return ret; > + } > > return 0; > } > @@ -748,23 +781,32 @@ static int dwc3_phy_setup(struct dwc3 *dwc) > static int dwc3_phy_init(struct dwc3 *dwc) > { > int ret; > + int i; > + int j; > > usb_phy_init(dwc->usb2_phy); > usb_phy_init(dwc->usb3_phy); > > - ret = phy_init(dwc->usb2_generic_phy); > - if (ret < 0) > - goto err_shutdown_usb3_phy; > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + ret = phy_init(dwc->usb2_generic_phy[i]); > + if (ret < 0) > + goto err_exit_phy; > > - ret = phy_init(dwc->usb3_generic_phy); > - if (ret < 0) > - goto err_exit_usb2_phy; > + ret = phy_init(dwc->usb3_generic_phy[i]); > + if (ret < 0) { > + phy_exit(dwc->usb2_generic_phy[i]); > + goto err_exit_phy; > + } > + } > > return 0; > > -err_exit_usb2_phy: > - phy_exit(dwc->usb2_generic_phy); > -err_shutdown_usb3_phy: > +err_exit_phy: > + for (j = i - 1; j >= 0; j--) { > + phy_exit(dwc->usb2_generic_phy[j]); > + phy_exit(dwc->usb3_generic_phy[j]); > + } > + > usb_phy_shutdown(dwc->usb3_phy); > usb_phy_shutdown(dwc->usb2_phy); > > @@ -773,8 +815,12 @@ static int dwc3_phy_init(struct dwc3 *dwc) > > static void dwc3_phy_exit(struct dwc3 *dwc) > { > - phy_exit(dwc->usb3_generic_phy); > - phy_exit(dwc->usb2_generic_phy); > + int i; > + > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + phy_exit(dwc->usb3_generic_phy[i]); > + phy_exit(dwc->usb2_generic_phy[i]); > + } > > usb_phy_shutdown(dwc->usb3_phy); > usb_phy_shutdown(dwc->usb2_phy); > @@ -783,23 +829,32 @@ static void dwc3_phy_exit(struct dwc3 *dwc) > static int dwc3_phy_power_on(struct dwc3 *dwc) > { > int ret; > + int i; > + int j; > > usb_phy_set_suspend(dwc->usb2_phy, 0); > usb_phy_set_suspend(dwc->usb3_phy, 0); > > - ret = phy_power_on(dwc->usb2_generic_phy); > - if (ret < 0) > - goto err_suspend_usb3_phy; > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + ret = phy_power_on(dwc->usb2_generic_phy[i]); > + if (ret < 0) > + goto err_power_off_phy; > > - ret = phy_power_on(dwc->usb3_generic_phy); > - if (ret < 0) > - goto err_power_off_usb2_phy; > + ret = phy_power_on(dwc->usb3_generic_phy[i]); > + if (ret < 0) { > + phy_power_off(dwc->usb2_generic_phy[i]); > + goto err_power_off_phy; > + } > + } > > return 0; > > -err_power_off_usb2_phy: > - phy_power_off(dwc->usb2_generic_phy); > -err_suspend_usb3_phy: > +err_power_off_phy: > + for (j = i - 1; j >= 0; j--) { > + phy_power_off(dwc->usb2_generic_phy[j]); > + phy_power_off(dwc->usb3_generic_phy[j]); > + } > + > usb_phy_set_suspend(dwc->usb3_phy, 1); > usb_phy_set_suspend(dwc->usb2_phy, 1); > > @@ -808,8 +863,12 @@ static int dwc3_phy_power_on(struct dwc3 *dwc) > > static void dwc3_phy_power_off(struct dwc3 *dwc) > { > - phy_power_off(dwc->usb3_generic_phy); > - phy_power_off(dwc->usb2_generic_phy); > + int i; > + > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + phy_power_off(dwc->usb3_generic_phy[i]); > + phy_power_off(dwc->usb2_generic_phy[i]); > + } > > usb_phy_set_suspend(dwc->usb3_phy, 1); > usb_phy_set_suspend(dwc->usb2_phy, 1); > @@ -1082,6 +1141,7 @@ static int dwc3_core_init(struct dwc3 *dwc) > unsigned int hw_mode; > u32 reg; > int ret; > + int i; > > hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); > > @@ -1125,15 +1185,19 @@ static int dwc3_core_init(struct dwc3 *dwc) > if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && > !DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) { > if (!dwc->dis_u3_susphy_quirk) { > - reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); > - reg |= DWC3_GUSB3PIPECTL_SUSPHY; > - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); > + for (i = 0; i < dwc->num_usb3_ports; i++) { > + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(i)); > + reg |= DWC3_GUSB3PIPECTL_SUSPHY; > + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(i), reg); > + } > } > > if (!dwc->dis_u2_susphy_quirk) { > - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); > - reg |= DWC3_GUSB2PHYCFG_SUSPHY; > - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i)); > + reg |= DWC3_GUSB2PHYCFG_SUSPHY; > + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg); > + } > } > } > > @@ -1276,7 +1340,9 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) > { > struct device *dev = dwc->dev; > struct device_node *node = dev->of_node; > + char phy_name[11]; > int ret; > + int i; > > if (node) { > dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); > @@ -1302,22 +1368,36 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) > return dev_err_probe(dev, ret, "no usb3 phy configured\n"); > } > > - dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy"); > - if (IS_ERR(dwc->usb2_generic_phy)) { > - ret = PTR_ERR(dwc->usb2_generic_phy); > - if (ret == -ENOSYS || ret == -ENODEV) > - dwc->usb2_generic_phy = NULL; > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + if (dwc->num_usb2_ports == 1) > + sprintf(phy_name, "usb2-phy"); > else > - return dev_err_probe(dev, ret, "no usb2 phy configured\n"); > - } > + sprintf(phy_name, "usb2-port%d", i); > > - dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy"); > - if (IS_ERR(dwc->usb3_generic_phy)) { > - ret = PTR_ERR(dwc->usb3_generic_phy); > - if (ret == -ENOSYS || ret == -ENODEV) > - dwc->usb3_generic_phy = NULL; > + dwc->usb2_generic_phy[i] = devm_phy_get(dev, phy_name); > + if (IS_ERR(dwc->usb2_generic_phy[i])) { > + ret = PTR_ERR(dwc->usb2_generic_phy[i]); > + if (ret == -ENOSYS || ret == -ENODEV) > + dwc->usb2_generic_phy[i] = NULL; > + else > + return dev_err_probe(dev, ret, > + "failed to lookup phy %s\n", phy_name); > + } > + > + if (dwc->num_usb2_ports == 1) > + sprintf(phy_name, "usb3-phy"); > else > - return dev_err_probe(dev, ret, "no usb3 phy configured\n"); > + sprintf(phy_name, "usb3-port%d", i); > + > + dwc->usb3_generic_phy[i] = devm_phy_get(dev, phy_name); > + if (IS_ERR(dwc->usb3_generic_phy[i])) { > + ret = PTR_ERR(dwc->usb3_generic_phy[i]); > + if (ret == -ENOSYS || ret == -ENODEV) > + dwc->usb3_generic_phy[i] = NULL; > + else > + return dev_err_probe(dev, ret, > + "failed to lookup phy %s\n", phy_name); > + } > } > > return 0; > @@ -1327,6 +1407,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) > { > struct device *dev = dwc->dev; > int ret; > + int i; > > switch (dwc->dr_mode) { > case USB_DR_MODE_PERIPHERAL: > @@ -1334,8 +1415,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) > > if (dwc->usb2_phy) > otg_set_vbus(dwc->usb2_phy->otg, false); > - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); > - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); > + phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE); > + phy_set_mode(dwc->usb3_generic_phy[0], PHY_MODE_USB_DEVICE); > > ret = dwc3_gadget_init(dwc); > if (ret) > @@ -1346,8 +1427,10 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) > > if (dwc->usb2_phy) > otg_set_vbus(dwc->usb2_phy->otg, true); > - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST); > - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST); > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + phy_set_mode(dwc->usb2_generic_phy[i], PHY_MODE_USB_HOST); > + phy_set_mode(dwc->usb3_generic_phy[i], PHY_MODE_USB_HOST); > + } > > ret = dwc3_host_init(dwc); > if (ret) > @@ -1804,9 +1887,12 @@ static int dwc3_read_port_info(struct dwc3 *dwc) > > dev_dbg(dwc->dev, "hs-ports: %u ss-ports: %u\n", > dwc->num_usb2_ports, dwc->num_usb3_ports); > - > iounmap(base); > > + if ((dwc->num_usb2_ports > DWC3_MAX_PORTS) || > + (dwc->num_usb3_ports > DWC3_MAX_PORTS)) > + return -ENOMEM; > + > return 0; > } > > @@ -2042,6 +2128,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) > { > unsigned long flags; > u32 reg; > + int i; > > switch (dwc->current_dr_role) { > case DWC3_GCTL_PRTCAP_DEVICE: > @@ -2060,17 +2147,21 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) > /* Let controller to suspend HSPHY before PHY driver suspends */ > if (dwc->dis_u2_susphy_quirk || > dwc->dis_enblslpm_quirk) { > - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); > - reg |= DWC3_GUSB2PHYCFG_ENBLSLPM | > - DWC3_GUSB2PHYCFG_SUSPHY; > - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i)); > + reg |= DWC3_GUSB2PHYCFG_ENBLSLPM | > + DWC3_GUSB2PHYCFG_SUSPHY; > + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg); > + } > > /* Give some time for USB2 PHY to suspend */ > usleep_range(5000, 6000); > } > > - phy_pm_runtime_put_sync(dwc->usb2_generic_phy); > - phy_pm_runtime_put_sync(dwc->usb3_generic_phy); > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + phy_pm_runtime_put_sync(dwc->usb2_generic_phy[i]); > + phy_pm_runtime_put_sync(dwc->usb3_generic_phy[i]); > + } > break; > case DWC3_GCTL_PRTCAP_OTG: > /* do nothing during runtime_suspend */ > @@ -2100,6 +2191,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) > unsigned long flags; > int ret; > u32 reg; > + int i; > > switch (dwc->current_dr_role) { > case DWC3_GCTL_PRTCAP_DEVICE: > @@ -2119,17 +2211,21 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) > break; > } > /* Restore GUSB2PHYCFG bits that were modified in suspend */ > - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); > - if (dwc->dis_u2_susphy_quirk) > - reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i)); > + if (dwc->dis_u2_susphy_quirk) > + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; > > - if (dwc->dis_enblslpm_quirk) > - reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; > + if (dwc->dis_enblslpm_quirk) > + reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; > > - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); > + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg); > + } > > - phy_pm_runtime_get_sync(dwc->usb2_generic_phy); > - phy_pm_runtime_get_sync(dwc->usb3_generic_phy); > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + phy_pm_runtime_get_sync(dwc->usb2_generic_phy[i]); > + phy_pm_runtime_get_sync(dwc->usb3_generic_phy[i]); > + } > break; > case DWC3_GCTL_PRTCAP_OTG: > /* nothing to do on runtime_resume */ > diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h > index 5b0f2aa115d2..5521dc9ca034 100644 > --- a/drivers/usb/dwc3/core.h > +++ b/drivers/usb/dwc3/core.h > @@ -33,6 +33,9 @@ > > #include <linux/power_supply.h> > > +/* Number of ports supported by a multiport controller */ > +#define DWC3_MAX_PORTS 4 > + > #define DWC3_MSG_MAX 500 > > /* Global constants */ > @@ -1024,8 +1027,8 @@ struct dwc3_scratchpad_array { > * @usb_psy: pointer to power supply interface. > * @usb2_phy: pointer to USB2 PHY > * @usb3_phy: pointer to USB3 PHY > - * @usb2_generic_phy: pointer to USB2 PHY > - * @usb3_generic_phy: pointer to USB3 PHY > + * @usb2_generic_phy: pointer to array of USB2 PHY > + * @usb3_generic_phy: pointer to array of USB3 PHY > * @num_usb2_ports: number of USB2 ports > * @num_usb3_ports: number of USB3 ports > * @phys_ready: flag to indicate that PHYs are ready > @@ -1164,8 +1167,8 @@ struct dwc3 { > struct usb_phy *usb2_phy; > struct usb_phy *usb3_phy; > > - struct phy *usb2_generic_phy; > - struct phy *usb3_generic_phy; > + struct phy *usb2_generic_phy[DWC3_MAX_PORTS]; > + struct phy *usb3_generic_phy[DWC3_MAX_PORTS]; > > u8 num_usb2_ports; > u8 num_usb3_ports; > diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c > index 039bf241769a..9aec41f1ad43 100644 > --- a/drivers/usb/dwc3/drd.c > +++ b/drivers/usb/dwc3/drd.c > @@ -331,6 +331,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) > u32 reg; > int id; > unsigned long flags; > + int i; > > if (dwc->dr_mode != USB_DR_MODE_OTG) > return; > @@ -386,9 +387,12 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) > } else { > if (dwc->usb2_phy) > otg_set_vbus(dwc->usb2_phy->otg, true); > - if (dwc->usb2_generic_phy) > - phy_set_mode(dwc->usb2_generic_phy, > - PHY_MODE_USB_HOST); > + for (i = 0; i < dwc->num_usb2_ports; i++) { > + if (dwc->usb2_generic_phy[i]) { > + phy_set_mode(dwc->usb2_generic_phy[i], > + PHY_MODE_USB_HOST); > + } > + } > } > break; > case DWC3_OTG_ROLE_DEVICE: > @@ -400,9 +404,8 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) > > if (dwc->usb2_phy) > otg_set_vbus(dwc->usb2_phy->otg, false); > - if (dwc->usb2_generic_phy) > - phy_set_mode(dwc->usb2_generic_phy, > - PHY_MODE_USB_DEVICE); > + if (dwc->usb2_generic_phy[0]) > + phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE); > ret = dwc3_gadget_init(dwc); > if (ret) > dev_err(dwc->dev, "failed to initialize peripheral\n"); > -- > 2.40.0 > Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Thanks, Thinh
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 6eacf0ff90b5..31400c309bff 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -124,6 +124,7 @@ static void __dwc3_set_mode(struct work_struct *work) int ret; u32 reg; u32 desired_dr_role; + int i; mutex_lock(&dwc->mutex); spin_lock_irqsave(&dwc->lock, flags); @@ -201,8 +202,10 @@ static void __dwc3_set_mode(struct work_struct *work) } else { if (dwc->usb2_phy) otg_set_vbus(dwc->usb2_phy->otg, true); - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST); - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST); + for (i = 0; i < dwc->num_usb2_ports; i++) { + phy_set_mode(dwc->usb2_generic_phy[i], PHY_MODE_USB_HOST); + phy_set_mode(dwc->usb3_generic_phy[i], PHY_MODE_USB_HOST); + } if (dwc->dis_split_quirk) { reg = dwc3_readl(dwc->regs, DWC3_GUCTL3); reg |= DWC3_GUCTL3_SPLITDISABLE; @@ -217,8 +220,8 @@ static void __dwc3_set_mode(struct work_struct *work) if (dwc->usb2_phy) otg_set_vbus(dwc->usb2_phy->otg, false); - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); + phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE); + phy_set_mode(dwc->usb3_generic_phy[0], PHY_MODE_USB_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) @@ -589,22 +592,14 @@ static int dwc3_core_ulpi_init(struct dwc3 *dwc) return ret; } -/** - * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core - * @dwc: Pointer to our controller context structure - * - * Returns 0 on success. The USB PHY interfaces are configured but not - * initialized. The PHY interfaces and the PHYs get initialized together with - * the core in dwc3_core_init. - */ -static int dwc3_phy_setup(struct dwc3 *dwc) +static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index) { unsigned int hw_mode; u32 reg; hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); - reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(index)); /* * Make sure UX_EXIT_PX is cleared as that causes issues with some @@ -659,9 +654,19 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->dis_del_phy_power_chg_quirk) reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE; - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(index), reg); - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + return 0; +} + +static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index) +{ + unsigned int hw_mode; + u32 reg; + + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); + + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(index)); /* Select the HS PHY interface */ switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) { @@ -673,7 +678,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc) } else if (dwc->hsphy_interface && !strncmp(dwc->hsphy_interface, "ulpi", 4)) { reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg); } else { /* Relying on default value. */ if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI)) @@ -740,7 +745,35 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->ulpi_ext_vbus_drv) reg |= DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg); + + return 0; +} + +/** + * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core + * @dwc: Pointer to our controller context structure + * + * Returns 0 on success. The USB PHY interfaces are configured but not + * initialized. The PHY interfaces and the PHYs get initialized together with + * the core in dwc3_core_init. + */ +static int dwc3_phy_setup(struct dwc3 *dwc) +{ + int i; + int ret; + + for (i = 0; i < dwc->num_usb3_ports; i++) { + ret = dwc3_ss_phy_setup(dwc, i); + if (ret) + return ret; + } + + for (i = 0; i < dwc->num_usb2_ports; i++) { + ret = dwc3_hs_phy_setup(dwc, i); + if (ret) + return ret; + } return 0; } @@ -748,23 +781,32 @@ static int dwc3_phy_setup(struct dwc3 *dwc) static int dwc3_phy_init(struct dwc3 *dwc) { int ret; + int i; + int j; usb_phy_init(dwc->usb2_phy); usb_phy_init(dwc->usb3_phy); - ret = phy_init(dwc->usb2_generic_phy); - if (ret < 0) - goto err_shutdown_usb3_phy; + for (i = 0; i < dwc->num_usb2_ports; i++) { + ret = phy_init(dwc->usb2_generic_phy[i]); + if (ret < 0) + goto err_exit_phy; - ret = phy_init(dwc->usb3_generic_phy); - if (ret < 0) - goto err_exit_usb2_phy; + ret = phy_init(dwc->usb3_generic_phy[i]); + if (ret < 0) { + phy_exit(dwc->usb2_generic_phy[i]); + goto err_exit_phy; + } + } return 0; -err_exit_usb2_phy: - phy_exit(dwc->usb2_generic_phy); -err_shutdown_usb3_phy: +err_exit_phy: + for (j = i - 1; j >= 0; j--) { + phy_exit(dwc->usb2_generic_phy[j]); + phy_exit(dwc->usb3_generic_phy[j]); + } + usb_phy_shutdown(dwc->usb3_phy); usb_phy_shutdown(dwc->usb2_phy); @@ -773,8 +815,12 @@ static int dwc3_phy_init(struct dwc3 *dwc) static void dwc3_phy_exit(struct dwc3 *dwc) { - phy_exit(dwc->usb3_generic_phy); - phy_exit(dwc->usb2_generic_phy); + int i; + + for (i = 0; i < dwc->num_usb2_ports; i++) { + phy_exit(dwc->usb3_generic_phy[i]); + phy_exit(dwc->usb2_generic_phy[i]); + } usb_phy_shutdown(dwc->usb3_phy); usb_phy_shutdown(dwc->usb2_phy); @@ -783,23 +829,32 @@ static void dwc3_phy_exit(struct dwc3 *dwc) static int dwc3_phy_power_on(struct dwc3 *dwc) { int ret; + int i; + int j; usb_phy_set_suspend(dwc->usb2_phy, 0); usb_phy_set_suspend(dwc->usb3_phy, 0); - ret = phy_power_on(dwc->usb2_generic_phy); - if (ret < 0) - goto err_suspend_usb3_phy; + for (i = 0; i < dwc->num_usb2_ports; i++) { + ret = phy_power_on(dwc->usb2_generic_phy[i]); + if (ret < 0) + goto err_power_off_phy; - ret = phy_power_on(dwc->usb3_generic_phy); - if (ret < 0) - goto err_power_off_usb2_phy; + ret = phy_power_on(dwc->usb3_generic_phy[i]); + if (ret < 0) { + phy_power_off(dwc->usb2_generic_phy[i]); + goto err_power_off_phy; + } + } return 0; -err_power_off_usb2_phy: - phy_power_off(dwc->usb2_generic_phy); -err_suspend_usb3_phy: +err_power_off_phy: + for (j = i - 1; j >= 0; j--) { + phy_power_off(dwc->usb2_generic_phy[j]); + phy_power_off(dwc->usb3_generic_phy[j]); + } + usb_phy_set_suspend(dwc->usb3_phy, 1); usb_phy_set_suspend(dwc->usb2_phy, 1); @@ -808,8 +863,12 @@ static int dwc3_phy_power_on(struct dwc3 *dwc) static void dwc3_phy_power_off(struct dwc3 *dwc) { - phy_power_off(dwc->usb3_generic_phy); - phy_power_off(dwc->usb2_generic_phy); + int i; + + for (i = 0; i < dwc->num_usb2_ports; i++) { + phy_power_off(dwc->usb3_generic_phy[i]); + phy_power_off(dwc->usb2_generic_phy[i]); + } usb_phy_set_suspend(dwc->usb3_phy, 1); usb_phy_set_suspend(dwc->usb2_phy, 1); @@ -1082,6 +1141,7 @@ static int dwc3_core_init(struct dwc3 *dwc) unsigned int hw_mode; u32 reg; int ret; + int i; hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); @@ -1125,15 +1185,19 @@ static int dwc3_core_init(struct dwc3 *dwc) if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && !DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) { if (!dwc->dis_u3_susphy_quirk) { - reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); - reg |= DWC3_GUSB3PIPECTL_SUSPHY; - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + for (i = 0; i < dwc->num_usb3_ports; i++) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(i)); + reg |= DWC3_GUSB3PIPECTL_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(i), reg); + } } if (!dwc->dis_u2_susphy_quirk) { - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - reg |= DWC3_GUSB2PHYCFG_SUSPHY; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + for (i = 0; i < dwc->num_usb2_ports; i++) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i)); + reg |= DWC3_GUSB2PHYCFG_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg); + } } } @@ -1276,7 +1340,9 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) { struct device *dev = dwc->dev; struct device_node *node = dev->of_node; + char phy_name[11]; int ret; + int i; if (node) { dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); @@ -1302,22 +1368,36 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) return dev_err_probe(dev, ret, "no usb3 phy configured\n"); } - dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy"); - if (IS_ERR(dwc->usb2_generic_phy)) { - ret = PTR_ERR(dwc->usb2_generic_phy); - if (ret == -ENOSYS || ret == -ENODEV) - dwc->usb2_generic_phy = NULL; + for (i = 0; i < dwc->num_usb2_ports; i++) { + if (dwc->num_usb2_ports == 1) + sprintf(phy_name, "usb2-phy"); else - return dev_err_probe(dev, ret, "no usb2 phy configured\n"); - } + sprintf(phy_name, "usb2-port%d", i); - dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy"); - if (IS_ERR(dwc->usb3_generic_phy)) { - ret = PTR_ERR(dwc->usb3_generic_phy); - if (ret == -ENOSYS || ret == -ENODEV) - dwc->usb3_generic_phy = NULL; + dwc->usb2_generic_phy[i] = devm_phy_get(dev, phy_name); + if (IS_ERR(dwc->usb2_generic_phy[i])) { + ret = PTR_ERR(dwc->usb2_generic_phy[i]); + if (ret == -ENOSYS || ret == -ENODEV) + dwc->usb2_generic_phy[i] = NULL; + else + return dev_err_probe(dev, ret, + "failed to lookup phy %s\n", phy_name); + } + + if (dwc->num_usb2_ports == 1) + sprintf(phy_name, "usb3-phy"); else - return dev_err_probe(dev, ret, "no usb3 phy configured\n"); + sprintf(phy_name, "usb3-port%d", i); + + dwc->usb3_generic_phy[i] = devm_phy_get(dev, phy_name); + if (IS_ERR(dwc->usb3_generic_phy[i])) { + ret = PTR_ERR(dwc->usb3_generic_phy[i]); + if (ret == -ENOSYS || ret == -ENODEV) + dwc->usb3_generic_phy[i] = NULL; + else + return dev_err_probe(dev, ret, + "failed to lookup phy %s\n", phy_name); + } } return 0; @@ -1327,6 +1407,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) { struct device *dev = dwc->dev; int ret; + int i; switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: @@ -1334,8 +1415,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) if (dwc->usb2_phy) otg_set_vbus(dwc->usb2_phy->otg, false); - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); + phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE); + phy_set_mode(dwc->usb3_generic_phy[0], PHY_MODE_USB_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) @@ -1346,8 +1427,10 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) if (dwc->usb2_phy) otg_set_vbus(dwc->usb2_phy->otg, true); - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST); - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST); + for (i = 0; i < dwc->num_usb2_ports; i++) { + phy_set_mode(dwc->usb2_generic_phy[i], PHY_MODE_USB_HOST); + phy_set_mode(dwc->usb3_generic_phy[i], PHY_MODE_USB_HOST); + } ret = dwc3_host_init(dwc); if (ret) @@ -1804,9 +1887,12 @@ static int dwc3_read_port_info(struct dwc3 *dwc) dev_dbg(dwc->dev, "hs-ports: %u ss-ports: %u\n", dwc->num_usb2_ports, dwc->num_usb3_ports); - iounmap(base); + if ((dwc->num_usb2_ports > DWC3_MAX_PORTS) || + (dwc->num_usb3_ports > DWC3_MAX_PORTS)) + return -ENOMEM; + return 0; } @@ -2042,6 +2128,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) { unsigned long flags; u32 reg; + int i; switch (dwc->current_dr_role) { case DWC3_GCTL_PRTCAP_DEVICE: @@ -2060,17 +2147,21 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) /* Let controller to suspend HSPHY before PHY driver suspends */ if (dwc->dis_u2_susphy_quirk || dwc->dis_enblslpm_quirk) { - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - reg |= DWC3_GUSB2PHYCFG_ENBLSLPM | - DWC3_GUSB2PHYCFG_SUSPHY; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + for (i = 0; i < dwc->num_usb2_ports; i++) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i)); + reg |= DWC3_GUSB2PHYCFG_ENBLSLPM | + DWC3_GUSB2PHYCFG_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg); + } /* Give some time for USB2 PHY to suspend */ usleep_range(5000, 6000); } - phy_pm_runtime_put_sync(dwc->usb2_generic_phy); - phy_pm_runtime_put_sync(dwc->usb3_generic_phy); + for (i = 0; i < dwc->num_usb2_ports; i++) { + phy_pm_runtime_put_sync(dwc->usb2_generic_phy[i]); + phy_pm_runtime_put_sync(dwc->usb3_generic_phy[i]); + } break; case DWC3_GCTL_PRTCAP_OTG: /* do nothing during runtime_suspend */ @@ -2100,6 +2191,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) unsigned long flags; int ret; u32 reg; + int i; switch (dwc->current_dr_role) { case DWC3_GCTL_PRTCAP_DEVICE: @@ -2119,17 +2211,21 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) break; } /* Restore GUSB2PHYCFG bits that were modified in suspend */ - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - if (dwc->dis_u2_susphy_quirk) - reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; + for (i = 0; i < dwc->num_usb2_ports; i++) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i)); + if (dwc->dis_u2_susphy_quirk) + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; - if (dwc->dis_enblslpm_quirk) - reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; + if (dwc->dis_enblslpm_quirk) + reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg); + } - phy_pm_runtime_get_sync(dwc->usb2_generic_phy); - phy_pm_runtime_get_sync(dwc->usb3_generic_phy); + for (i = 0; i < dwc->num_usb2_ports; i++) { + phy_pm_runtime_get_sync(dwc->usb2_generic_phy[i]); + phy_pm_runtime_get_sync(dwc->usb3_generic_phy[i]); + } break; case DWC3_GCTL_PRTCAP_OTG: /* nothing to do on runtime_resume */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 5b0f2aa115d2..5521dc9ca034 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -33,6 +33,9 @@ #include <linux/power_supply.h> +/* Number of ports supported by a multiport controller */ +#define DWC3_MAX_PORTS 4 + #define DWC3_MSG_MAX 500 /* Global constants */ @@ -1024,8 +1027,8 @@ struct dwc3_scratchpad_array { * @usb_psy: pointer to power supply interface. * @usb2_phy: pointer to USB2 PHY * @usb3_phy: pointer to USB3 PHY - * @usb2_generic_phy: pointer to USB2 PHY - * @usb3_generic_phy: pointer to USB3 PHY + * @usb2_generic_phy: pointer to array of USB2 PHY + * @usb3_generic_phy: pointer to array of USB3 PHY * @num_usb2_ports: number of USB2 ports * @num_usb3_ports: number of USB3 ports * @phys_ready: flag to indicate that PHYs are ready @@ -1164,8 +1167,8 @@ struct dwc3 { struct usb_phy *usb2_phy; struct usb_phy *usb3_phy; - struct phy *usb2_generic_phy; - struct phy *usb3_generic_phy; + struct phy *usb2_generic_phy[DWC3_MAX_PORTS]; + struct phy *usb3_generic_phy[DWC3_MAX_PORTS]; u8 num_usb2_ports; u8 num_usb3_ports; diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c index 039bf241769a..9aec41f1ad43 100644 --- a/drivers/usb/dwc3/drd.c +++ b/drivers/usb/dwc3/drd.c @@ -331,6 +331,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) u32 reg; int id; unsigned long flags; + int i; if (dwc->dr_mode != USB_DR_MODE_OTG) return; @@ -386,9 +387,12 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) } else { if (dwc->usb2_phy) otg_set_vbus(dwc->usb2_phy->otg, true); - if (dwc->usb2_generic_phy) - phy_set_mode(dwc->usb2_generic_phy, - PHY_MODE_USB_HOST); + for (i = 0; i < dwc->num_usb2_ports; i++) { + if (dwc->usb2_generic_phy[i]) { + phy_set_mode(dwc->usb2_generic_phy[i], + PHY_MODE_USB_HOST); + } + } } break; case DWC3_OTG_ROLE_DEVICE: @@ -400,9 +404,8 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) if (dwc->usb2_phy) otg_set_vbus(dwc->usb2_phy->otg, false); - if (dwc->usb2_generic_phy) - phy_set_mode(dwc->usb2_generic_phy, - PHY_MODE_USB_DEVICE); + if (dwc->usb2_generic_phy[0]) + phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) dev_err(dwc->dev, "failed to initialize peripheral\n");