mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
usb: dwc3: core: prevent re-enumeration in host mode
To prevent re-enumeration, we should let PD of dwc3 always on and avoid reset of dwc3. However, if we run phy_power_on for u3phy without reset of dwc3, the operation will failed with error code -110. Therefore, we add another phy_power_on operation for u3phy when current_dr_mode is host mode. Change-Id: I92f31de170c7d3d1d8da1d196103763b0cade05b Signed-off-by: Jianing Ren <jianing.ren@rock-chips.com>
This commit is contained in:
@@ -218,6 +218,7 @@ runtime:
|
||||
|
||||
switch (dwc->current_dr_role) {
|
||||
case DWC3_GCTL_PRTCAP_HOST:
|
||||
phy_power_on(dwc->usb3_generic_phy);
|
||||
ret = dwc3_host_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev,
|
||||
@@ -248,6 +249,7 @@ runtime:
|
||||
} else {
|
||||
switch (dwc->current_dr_role) {
|
||||
case DWC3_GCTL_PRTCAP_HOST:
|
||||
phy_power_off(dwc->usb3_generic_phy);
|
||||
dwc3_host_exit(dwc);
|
||||
break;
|
||||
case DWC3_GCTL_PRTCAP_DEVICE:
|
||||
@@ -763,7 +765,13 @@ static void dwc3_core_exit(struct dwc3 *dwc)
|
||||
phy_power_off(dwc->usb3_generic_phy);
|
||||
clk_bulk_disable(dwc->num_clks, dwc->clks);
|
||||
clk_bulk_unprepare(dwc->num_clks, dwc->clks);
|
||||
reset_control_assert(dwc->reset);
|
||||
/*
|
||||
* We're resetting only the device side, it can avoid to reset the DWC3
|
||||
* controller when resume from PM suspend which may cause the usb
|
||||
* device to be reenumerated.
|
||||
*/
|
||||
if (!dwc->drd_connected && dwc->dr_mode == USB_DR_MODE_OTG)
|
||||
reset_control_assert(dwc->reset);
|
||||
}
|
||||
|
||||
static bool dwc3_core_is_valid(struct dwc3 *dwc)
|
||||
@@ -1228,6 +1236,15 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
|
||||
}
|
||||
break;
|
||||
case USB_DR_MODE_HOST:
|
||||
/*
|
||||
* To prevent usb device be reenumerated when resume from PM
|
||||
* suspend, we set the flag dwc->power.can_wakeup which can
|
||||
* keep PD on and run phy_power_on again to avoid
|
||||
* phy_power_on failed (error -110) in Rockchip platform.
|
||||
*/
|
||||
device_init_wakeup(dev, true);
|
||||
phy_power_on(dwc->usb3_generic_phy);
|
||||
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
|
||||
|
||||
if (dwc->usb2_phy)
|
||||
@@ -1663,9 +1680,16 @@ static int dwc3_core_init_for_resume(struct dwc3 *dwc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = reset_control_deassert(dwc->reset);
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* We're resetting only the device side, it can avoid to reset the DWC3
|
||||
* controller when resume from PM suspend which may cause the usb
|
||||
* device to be reenumerated.
|
||||
*/
|
||||
if (!dwc->drd_connected && dwc->dr_mode == USB_DR_MODE_OTG) {
|
||||
ret = reset_control_deassert(dwc->reset);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_bulk_prepare(dwc->num_clks, dwc->clks);
|
||||
if (ret)
|
||||
@@ -1686,7 +1710,8 @@ disable_clks:
|
||||
unprepare_clks:
|
||||
clk_bulk_unprepare(dwc->num_clks, dwc->clks);
|
||||
assert_reset:
|
||||
reset_control_assert(dwc->reset);
|
||||
if (!dwc->drd_connected && dwc->dr_mode == USB_DR_MODE_OTG)
|
||||
reset_control_assert(dwc->reset);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1843,7 +1868,7 @@ static int dwc3_runtime_suspend(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
device_init_wakeup(dev, true);
|
||||
device_init_wakeup(dev, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1853,7 +1878,7 @@ static int dwc3_runtime_resume(struct device *dev)
|
||||
struct dwc3 *dwc = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
device_init_wakeup(dev, false);
|
||||
device_init_wakeup(dev, true);
|
||||
|
||||
ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME);
|
||||
if (ret)
|
||||
@@ -1902,10 +1927,37 @@ static int dwc3_suspend(struct device *dev)
|
||||
struct dwc3 *dwc = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (pm_runtime_suspended(dwc->dev))
|
||||
return 0;
|
||||
|
||||
ret = dwc3_suspend_common(dwc, PMSG_SUSPEND);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* If link state is Rx.Detect, it means that
|
||||
* no usb device is connecting with the DWC3
|
||||
* Host, and need to power off the USB3 PHY.
|
||||
*
|
||||
* If link state is in other state, like U0
|
||||
* or U3 state, it means that at least one
|
||||
* USB3 device is connecting with the Host
|
||||
* port, in this case, we don't power off
|
||||
* the USB3 PHY because some USB3 PHYs (like
|
||||
* RK3399 Type-C USB3 PHY) require that the
|
||||
* power on operation must be done while the
|
||||
* DWC3 controller is in P2 state, but the
|
||||
* state is in P0 after resume with a USB3
|
||||
* device connected. So we set the USB3 PHY
|
||||
* in power on state in this case.
|
||||
*/
|
||||
dwc->link_state = dwc3_gadget_get_link_state(dwc);
|
||||
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST &&
|
||||
dwc->link_state == DWC3_LINK_STATE_RX_DET) {
|
||||
phy_power_off(dwc->usb3_generic_phy);
|
||||
reset_control_assert(dwc->reset);
|
||||
}
|
||||
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
|
||||
return 0;
|
||||
@@ -1916,8 +1968,17 @@ static int dwc3_resume(struct device *dev)
|
||||
struct dwc3 *dwc = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (pm_runtime_suspended(dwc->dev))
|
||||
return 0;
|
||||
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
|
||||
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST &&
|
||||
dwc->link_state == DWC3_LINK_STATE_RX_DET) {
|
||||
reset_control_deassert(dwc->reset);
|
||||
phy_power_on(dwc->usb3_generic_phy);
|
||||
}
|
||||
|
||||
ret = dwc3_resume_common(dwc, PMSG_RESUME);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
Reference in New Issue
Block a user