[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20260115145153.3332570-1-sean.anderson@linux.dev>
Date: Thu, 15 Jan 2026 09:51:53 -0500
From: Sean Anderson <sean.anderson@...ux.dev>
To: Thinh Nguyen <Thinh.Nguyen@...opsys.com>,
linux-usb@...r.kernel.org
Cc: Radhey Shyam Pandey <radhey.shyam.pandey@....com>,
Neal Frager <neal.frager@....com>,
Philipp Zabel <p.zabel@...gutronix.de>,
Michal Simek <michal.simek@....com>,
linux-kernel@...r.kernel.org,
linux-arm-kernel@...ts.infradead.org,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
Sean Anderson <sean.anderson@...ux.dev>
Subject: [PATCH v2] usb: dwc3: Always deassert xilinx resets
I am working on moving serdes initialization to the phy (and consumer)
drivers to improve flexibility and boot times (depending on configuration).
Currently, core resets are released in the bootloader by init_serdes() in
psu_init_gpl.c. In order to remove init_serdes, we need to handle the case
where the bootloader never released the core resets. If we don't have a
usb3 phy we don't need to assert the core resets, but deassert them anyway
to handle this case.
We could assert all resets every boot, but I believe the existing procedure
is an optimization to reduce boot time when the bootloader has already
initialized USB. So this patch preserves the separate code paths.
Signed-off-by: Sean Anderson <sean.anderson@...ux.dev>
Acked-by: Thinh Nguyen <Thinh.Nguyen@...opsys.com>
---
Changes in v2:
- Update commit message
drivers/usb/dwc3/dwc3-xilinx.c | 67 ++++++++++++++++------------------
1 file changed, 32 insertions(+), 35 deletions(-)
diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c
index 0a8c47876ff9..f41b0da5e89d 100644
--- a/drivers/usb/dwc3/dwc3-xilinx.c
+++ b/drivers/usb/dwc3/dwc3-xilinx.c
@@ -132,21 +132,6 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
goto err;
}
- /*
- * The following core resets are not required unless a USB3 PHY
- * is used, and the subsequent register settings are not required
- * unless a core reset is performed (they should be set properly
- * by the first-stage boot loader, but may be reverted by a core
- * reset). They may also break the configuration if USB3 is actually
- * in use but the usb3-phy entry is missing from the device tree.
- * Therefore, skip these operations in this case.
- */
- if (!priv_data->usb3_phy) {
- /* Deselect the PIPE Clock Select bit in FPD PIPE Clock register */
- writel(PIPE_CLK_DESELECT, priv_data->regs + XLNX_USB_FPD_PIPE_CLK);
- goto skip_usb3_phy;
- }
-
crst = devm_reset_control_get_exclusive(dev, "usb_crst");
if (IS_ERR(crst)) {
ret = PTR_ERR(crst);
@@ -171,22 +156,31 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
goto err;
}
- ret = reset_control_assert(crst);
- if (ret < 0) {
- dev_err(dev, "Failed to assert core reset\n");
- goto err;
- }
+ /*
+ * Asserting the core resets is not required unless a USB3 PHY is used.
+ * They may also break the configuration if USB3 is actually in use but
+ * the usb3-phy entry is missing from the device tree. Therefore, skip
+ * a full reset cycle and just deassert the resets if the phy is
+ * absent.
+ */
+ if (priv_data->usb3_phy) {
+ ret = reset_control_assert(crst);
+ if (ret < 0) {
+ dev_err(dev, "Failed to assert core reset\n");
+ goto err;
+ }
- ret = reset_control_assert(hibrst);
- if (ret < 0) {
- dev_err(dev, "Failed to assert hibernation reset\n");
- goto err;
- }
+ ret = reset_control_assert(hibrst);
+ if (ret < 0) {
+ dev_err(dev, "Failed to assert hibernation reset\n");
+ goto err;
+ }
- ret = reset_control_assert(apbrst);
- if (ret < 0) {
- dev_err(dev, "Failed to assert APB reset\n");
- goto err;
+ ret = reset_control_assert(apbrst);
+ if (ret < 0) {
+ dev_err(dev, "Failed to assert APB reset\n");
+ goto err;
+ }
}
ret = phy_init(priv_data->usb3_phy);
@@ -201,11 +195,15 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
goto err;
}
- /* Set PIPE Power Present signal in FPD Power Present Register*/
- writel(FPD_POWER_PRSNT_OPTION, priv_data->regs + XLNX_USB_FPD_POWER_PRSNT);
-
- /* Set the PIPE Clock Select bit in FPD PIPE Clock register */
- writel(PIPE_CLK_SELECT, priv_data->regs + XLNX_USB_FPD_PIPE_CLK);
+ if (priv_data->usb3_phy) {
+ /* Set PIPE Power Present signal in FPD Power Present Register*/
+ writel(FPD_POWER_PRSNT_OPTION, priv_data->regs + XLNX_USB_FPD_POWER_PRSNT);
+ /* Set the PIPE Clock Select bit in FPD PIPE Clock register */
+ writel(PIPE_CLK_SELECT, priv_data->regs + XLNX_USB_FPD_PIPE_CLK);
+ } else {
+ /* Deselect the PIPE Clock Select bit in FPD PIPE Clock register */
+ writel(PIPE_CLK_DESELECT, priv_data->regs + XLNX_USB_FPD_PIPE_CLK);
+ }
ret = reset_control_deassert(crst);
if (ret < 0) {
@@ -225,7 +223,6 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
goto err;
}
-skip_usb3_phy:
/* ulpi reset via gpio-modepin or gpio-framework driver */
reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(reset_gpio)) {
--
2.35.1.1320.gc452695387.dirty
Powered by blists - more mailing lists