Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 76251db8 authored by Enric Balletbo i Serra's avatar Enric Balletbo i Serra Committed by Felipe Balbi
Browse files

usb: dwc3: of-simple: reset host controller at suspend/resume



If we power off the SoC logic rail in S3, we can find that the Type-C
PHY can't initialize correctly after system resume. We need to toggle
the USB3-OTG reset before trying to initialize the PHY, or else it
times out.

    phy phy-ff800000.phy.9: phy poweron failed --> -110
    dwc3 fe900000.dwc3: failed to initialize core
    dwc3: probe of fe900000.dwc3 failed with error -110

Note that the RK3399 TRM suggests that we should keep the whole usb3
controller in reset for the duration of the Type-C PHY initialization.
However, it's hard to assert the reset in the current framework of
reset. We're still skeptical about that, and we haven't yet found a
case where this seems to have mattered. This approach is much easier, it
simply holds the USB3-OTG reset while device is supended.

The dwc3 core is going to reinitialize the controller at suspend/resume
anyway (including a "soft reset"), so it should be safe to do this.

Signed-off-by: default avatarEnric Balletbo i Serra <enric.balletbo@collabora.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 1fcba97e
Loading
Loading
Loading
Loading
+29 −0
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@ struct dwc3_of_simple {
	int			num_clocks;
	int			num_clocks;
	struct reset_control	*resets;
	struct reset_control	*resets;
	bool			pulse_resets;
	bool			pulse_resets;
	bool			need_reset;
};
};


static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count)
static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count)
@@ -93,6 +94,13 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
	platform_set_drvdata(pdev, simple);
	platform_set_drvdata(pdev, simple);
	simple->dev = dev;
	simple->dev = dev;


	/*
	 * Some controllers need to toggle the usb3-otg reset before trying to
	 * initialize the PHY, otherwise the PHY times out.
	 */
	if (of_device_is_compatible(np, "rockchip,rk3399-dwc3"))
		simple->need_reset = true;

	if (of_device_is_compatible(np, "amlogic,meson-axg-dwc3") ||
	if (of_device_is_compatible(np, "amlogic,meson-axg-dwc3") ||
	    of_device_is_compatible(np, "amlogic,meson-gxl-dwc3")) {
	    of_device_is_compatible(np, "amlogic,meson-gxl-dwc3")) {
		shared_resets = true;
		shared_resets = true;
@@ -201,9 +209,30 @@ static int dwc3_of_simple_runtime_resume(struct device *dev)


	return 0;
	return 0;
}
}

static int dwc3_of_simple_suspend(struct device *dev)
{
	struct dwc3_of_simple *simple = dev_get_drvdata(dev);

	if (simple->need_reset)
		reset_control_assert(simple->resets);

	return 0;
}

static int dwc3_of_simple_resume(struct device *dev)
{
	struct dwc3_of_simple *simple = dev_get_drvdata(dev);

	if (simple->need_reset)
		reset_control_deassert(simple->resets);

	return 0;
}
#endif
#endif


static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(dwc3_of_simple_suspend, dwc3_of_simple_resume)
	SET_RUNTIME_PM_OPS(dwc3_of_simple_runtime_suspend,
	SET_RUNTIME_PM_OPS(dwc3_of_simple_runtime_suspend,
			dwc3_of_simple_runtime_resume, NULL)
			dwc3_of_simple_runtime_resume, NULL)
};
};