usb: dwc3: fix runtime pm for rockchip

The default autosuspend delay of runtime pm is 5000ms,
it's too long for the application scenario of hot plug.
If usb plug out and plug in again in 5000ms, it will
fail to do runtime suspend/resume, and also fail to
do usb phy ops. For RK3588 Type-C USB3.1 Gen1, it needs
to do usb3 phy init for normal or flip orientation
during dwc3 runtime process. This patch sets the runtime
autosuspend delay to 100ms for user's normal hotplug
operation.

Given the autosuspend delay 100ms is very short, it may
cause the usb device role fail to connect to usb host
in the following case:

1. Use Type-C to Type-A cable, connenct RK3588 usb to PC.
2. The TCPM set the usb role as PERIPHERAL and call
   dwc3_usb_role_switch_set() -> __dwc3_set_mode() ->
   dwc3_runtime_resume() -> power on u2/u3 phy ->
   delay 100ms -> dwc3_runtime_suspend().
3. In the dwc3_runtime_suspend(), it will check the
   dwc->connected which can only be set to true in the
   dwc3_gadget_reset_interrupt().
4. If the PC usb host doesn't send reset signal within
   100ms, the dwc3 will do dwc3_runtime_suspend() and
   power off u2/u3 phy. This cause usb device not to
   be detected.

So this patch fix the runtime pm mechanism for usb device
role to forbid dwc3 enter runtime suspend if the desired
role is PERIPHERAL. And allow dwc3 to enter runtime suspend
again after the desired role is not PERIPHERAL. For the usb
host role, the xHCI platform driver has forbidden it to
do autosuspend, so we don't care the usb host role here.

Signed-off-by: William Wu <william.wu@rock-chips.com>
Change-Id: I195a5fd7d8264108dd32f56f5b9bdb7f0e83da90
This commit is contained in:
William Wu
2021-12-07 15:14:34 +08:00
committed by Tao Huang
parent 81d9bd6936
commit 5ac62b80f7
3 changed files with 34 additions and 0 deletions

View File

@@ -126,6 +126,18 @@ static void __dwc3_set_mode(struct work_struct *work)
pm_runtime_get_sync(dwc->dev);
#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
if (dwc->desired_role_sw_mode == USB_DR_MODE_PERIPHERAL &&
dwc->desired_role_sw_mode != dwc->current_role_sw_mode)
pm_runtime_get(dwc->dev);
else if ((dwc->desired_role_sw_mode == USB_DR_MODE_UNKNOWN ||
dwc->desired_role_sw_mode == USB_DR_MODE_HOST) &&
dwc->current_role_sw_mode == USB_DR_MODE_PERIPHERAL)
pm_runtime_put(dwc->dev);
dwc->current_role_sw_mode = dwc->desired_role_sw_mode;
#endif
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG)
dwc3_otg_update(dwc, 0);
@@ -1664,6 +1676,9 @@ static int dwc3_probe(struct platform_device *pdev)
if (dwc->dr_mode == USB_DR_MODE_OTG &&
of_device_is_compatible(dev->parent->of_node,
"rockchip,rk3399-dwc3")) {
#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
pm_runtime_set_autosuspend_delay(dev, 100);
#endif
pm_runtime_allow(dev);
pm_runtime_put_sync_suspend(dev);
} else {

View File

@@ -1010,6 +1010,8 @@ struct dwc3_scratchpad_array {
* @role_sw: usb_role_switch handle
* @role_switch_default_mode: default operation mode of controller while
* usb role is USB_ROLE_NONE.
* @current_role_sw_mode: current usb role switch mode.
* @desired_role_sw_mode: desired usb role switch mode.
* @usb_psy: pointer to power supply interface.
* @usb2_phy: pointer to USB2 PHY
* @usb3_phy: pointer to USB3 PHY
@@ -1160,6 +1162,10 @@ struct dwc3 {
enum usb_phy_interface hsphy_mode;
struct usb_role_switch *role_sw;
enum usb_dr_mode role_switch_default_mode;
#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
u32 current_role_sw_mode;
u32 desired_role_sw_mode;
#endif
struct power_supply *usb_psy;

View File

@@ -431,6 +431,15 @@ static int dwc3_drd_notifier(struct notifier_block *nb,
{
struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb);
#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
if (extcon_get_state(dwc->edev, EXTCON_USB))
dwc->desired_role_sw_mode = USB_DR_MODE_PERIPHERAL;
else if (extcon_get_state(dwc->edev, EXTCON_USB_HOST))
dwc->desired_role_sw_mode = USB_DR_MODE_HOST;
else
dwc->desired_role_sw_mode = USB_DR_MODE_UNKNOWN;
#endif
dwc3_set_mode(dwc, event ?
DWC3_GCTL_PRTCAP_HOST :
DWC3_GCTL_PRTCAP_DEVICE);
@@ -491,6 +500,10 @@ static int dwc3_usb_role_switch_set(struct usb_role_switch *sw,
struct dwc3 *dwc = usb_role_switch_get_drvdata(sw);
u32 mode;
#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
dwc->desired_role_sw_mode = role;
#endif
switch (role) {
case USB_ROLE_HOST:
mode = DWC3_GCTL_PRTCAP_HOST;