Commit 30a46746 authored by Krishna Kurapati's avatar Krishna Kurapati Committed by Greg Kroah-Hartman

usb: dwc3: core: Refactor PHY logic to support Multiport Controller

Currently the DWC3 driver supports only single port controller
which requires at least one HS PHY and at most 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.

DWC3 multiport controllers are capable to service at most 15 High Speed
PHYs and 4 Supser Speed PHYs. Add support for detecting, obtaining and
configuring PHYs supported by a multiport controller.
Signed-off-by: default avatarKrishna Kurapati <quic_kriskura@quicinc.com>
Reviewed-by: default avatarBjorn Andersson <quic_bjorande@quicinc.com>
Acked-by: default avatarThinh Nguyen <Thinh.Nguyen@synopsys.com>
Reviewed-by: default avatarJohan Hovold <johan+linaro@kernel.org>
Tested-by: default avatarJohan Hovold <johan+linaro@kernel.org>
Link: https://lore.kernel.org/r/20240420044901.884098-5-quic_kriskura@quicinc.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 89d7f962
This diff is collapsed.
...@@ -33,6 +33,13 @@ ...@@ -33,6 +33,13 @@
#include <linux/power_supply.h> #include <linux/power_supply.h>
/*
* DWC3 Multiport controllers support up to 15 High-Speed PHYs
* and 4 SuperSpeed PHYs.
*/
#define DWC3_USB2_MAX_PORTS 15
#define DWC3_USB3_MAX_PORTS 4
#define DWC3_MSG_MAX 500 #define DWC3_MSG_MAX 500
/* Global constants */ /* Global constants */
...@@ -1037,8 +1044,8 @@ struct dwc3_scratchpad_array { ...@@ -1037,8 +1044,8 @@ struct dwc3_scratchpad_array {
* @usb_psy: pointer to power supply interface. * @usb_psy: pointer to power supply interface.
* @usb2_phy: pointer to USB2 PHY * @usb2_phy: pointer to USB2 PHY
* @usb3_phy: pointer to USB3 PHY * @usb3_phy: pointer to USB3 PHY
* @usb2_generic_phy: pointer to USB2 PHY * @usb2_generic_phy: pointer to array of USB2 PHYs
* @usb3_generic_phy: pointer to USB3 PHY * @usb3_generic_phy: pointer to array of USB3 PHYs
* @num_usb2_ports: number of USB2 ports * @num_usb2_ports: number of USB2 ports
* @num_usb3_ports: number of USB3 ports * @num_usb3_ports: number of USB3 ports
* @phys_ready: flag to indicate that PHYs are ready * @phys_ready: flag to indicate that PHYs are ready
...@@ -1186,8 +1193,8 @@ struct dwc3 { ...@@ -1186,8 +1193,8 @@ struct dwc3 {
struct usb_phy *usb2_phy; struct usb_phy *usb2_phy;
struct usb_phy *usb3_phy; struct usb_phy *usb3_phy;
struct phy *usb2_generic_phy; struct phy *usb2_generic_phy[DWC3_USB2_MAX_PORTS];
struct phy *usb3_generic_phy; struct phy *usb3_generic_phy[DWC3_USB3_MAX_PORTS];
u8 num_usb2_ports; u8 num_usb2_ports;
u8 num_usb3_ports; u8 num_usb3_ports;
......
...@@ -331,6 +331,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) ...@@ -331,6 +331,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
u32 reg; u32 reg;
int id; int id;
unsigned long flags; unsigned long flags;
int i;
if (dwc->dr_mode != USB_DR_MODE_OTG) if (dwc->dr_mode != USB_DR_MODE_OTG)
return; return;
...@@ -386,10 +387,13 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) ...@@ -386,10 +387,13 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
} else { } else {
if (dwc->usb2_phy) if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true); otg_set_vbus(dwc->usb2_phy->otg, true);
if (dwc->usb2_generic_phy) for (i = 0; i < dwc->num_usb2_ports; i++) {
phy_set_mode(dwc->usb2_generic_phy, if (dwc->usb2_generic_phy[i]) {
phy_set_mode(dwc->usb2_generic_phy[i],
PHY_MODE_USB_HOST); PHY_MODE_USB_HOST);
} }
}
}
break; break;
case DWC3_OTG_ROLE_DEVICE: case DWC3_OTG_ROLE_DEVICE:
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
...@@ -400,9 +404,8 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) ...@@ -400,9 +404,8 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
if (dwc->usb2_phy) if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false); otg_set_vbus(dwc->usb2_phy->otg, false);
if (dwc->usb2_generic_phy) if (dwc->usb2_generic_phy[0])
phy_set_mode(dwc->usb2_generic_phy, phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE);
PHY_MODE_USB_DEVICE);
ret = dwc3_gadget_init(dwc); ret = dwc3_gadget_init(dwc);
if (ret) if (ret)
dev_err(dwc->dev, "failed to initialize peripheral\n"); dev_err(dwc->dev, "failed to initialize peripheral\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment