diff mbox series

usb: cdnsp: Fix issue with resuming from L1

Message ID PH7PR07MB9538959C61B32EBCA33D1909DDB72@PH7PR07MB9538.namprd07.prod.outlook.com
State New
Headers show
Series usb: cdnsp: Fix issue with resuming from L1 | expand

Commit Message

Pawel Laszczak April 10, 2025, 7:34 a.m. UTC
Subject: [PATCH] usb: cdnsp: Fix issue with resuming from L1

In very rare cases after resuming controller from L1 to L0 it reads
registers before the clock has been enabled and as the result driver
reads incorrect value.
To fix this issue driver increases APB timeout value.

Probably this issue occurs only on Cadence platform but fix
should have no impact for other existing platforms.

Fixes: 3d82904559f4 ("usb: cdnsp: cdns3 Add main part of Cadence USBSSP DRD Driver")
cc: stable@vger.kernel.org
Signed-off-by: Pawel Laszczak <pawell@cadence.com>
---
 drivers/usb/cdns3/cdnsp-gadget.c | 22 ++++++++++++++++++++++
 drivers/usb/cdns3/cdnsp-gadget.h |  4 ++++
 2 files changed, 26 insertions(+)
diff mbox series

Patch

diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c
index 87f310841735..b12581b94567 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.c
+++ b/drivers/usb/cdns3/cdnsp-gadget.c
@@ -139,6 +139,21 @@  static void cdnsp_clear_port_change_bit(struct cdnsp_device *pdev,
 	       (portsc & PORT_CHANGE_BITS), port_regs);
 }
 
+static void cdnsp_set_apb_timeout_value(struct cdnsp_device *pdev)
+{
+	__le32 __iomem *reg;
+	void __iomem *base;
+	u32 offset = 0;
+	u32 val;
+
+	base = &pdev->cap_regs->hc_capbase;
+	offset = cdnsp_find_next_ext_cap(base, offset, D_XEC_PRE_REGS_CAP);
+	reg = base + offset + REG_CHICKEN_BITS_3_OFFSET;
+
+	val  = le32_to_cpu(readl(reg));
+	writel(cpu_to_le32(CHICKEN_APB_TIMEOUT_SET(val)), reg);
+}
+
 static void cdnsp_set_chicken_bits_2(struct cdnsp_device *pdev, u32 bit)
 {
 	__le32 __iomem *reg;
@@ -1798,6 +1813,13 @@  static int cdnsp_gen_setup(struct cdnsp_device *pdev)
 	pdev->hci_version = HC_VERSION(pdev->hcc_params);
 	pdev->hcc_params = readl(&pdev->cap_regs->hcc_params);
 
+	/* In very rare cases after resuming controller from L1 to L0 it reads
+	 * registers before the clock has been enabled and as the result driver
+	 * reads incorrect value.
+	 * To fix this issue driver increases APB timeout value.
+	 */
+	cdnsp_set_apb_timeout_value(pdev);
+
 	cdnsp_get_rev_cap(pdev);
 
 	/* Make sure the Device Controller is halted. */
diff --git a/drivers/usb/cdns3/cdnsp-gadget.h b/drivers/usb/cdns3/cdnsp-gadget.h
index 84887dfea763..a4d678fba005 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.h
+++ b/drivers/usb/cdns3/cdnsp-gadget.h
@@ -520,6 +520,10 @@  struct cdnsp_rev_cap {
 #define REG_CHICKEN_BITS_2_OFFSET	0x48
 #define CHICKEN_XDMA_2_TP_CACHE_DIS	BIT(28)
 
+#define REG_CHICKEN_BITS_3_OFFSET	0x4C
+#define CHICKEN_APB_TIMEOUT_VALUE	0x1C20
+#define CHICKEN_APB_TIMEOUT_SET(p) (((p) & ~GENMASK(21, 0)) | CHICKEN_APB_TIMEOUT_VALUE)
+
 /* XBUF Extended Capability ID. */
 #define XBUF_CAP_ID			0xCB
 #define XBUF_RX_TAG_MASK_0_OFFSET	0x1C