Skip to content

Commit 8e58122

Browse files
pawellcdnsjfvogel
authored andcommitted
usb: cdnsp: Fix issue with resuming from L1
commit 241e2ce upstream. In very rare cases after resuming controller from L1 to L0 it reads registers before the clock UTMI have been enabled and as the result driver reads incorrect value. Most of registers are in APB domain clock but some of them (e.g. PORTSC) are in UTMI domain clock. After entering to L1 state the UTMI clock can be disabled. When controller transition from L1 to L0 the port status change event is reported and in interrupt runtime function driver reads PORTSC. During this read operation controller synchronize UTMI and APB domain but UTMI clock is still disabled and in result it reads 0xFFFFFFFF value. To fix this issue driver increases APB timeout value. The issue is platform specific and if the default value of APB timeout is not sufficient then this time should be set Individually for each platform. Fixes: 3d82904 ("usb: cdnsp: cdns3 Add main part of Cadence USBSSP DRD Driver") Cc: stable <[email protected]> Signed-off-by: Pawel Laszczak <[email protected]> Acked-by: Peter Chen <[email protected]> Link: https://lore.kernel.org/r/PH7PR07MB953846C57973E4DB134CAA71DDBF2@PH7PR07MB9538.namprd07.prod.outlook.com Signed-off-by: Greg Kroah-Hartman <[email protected]> (cherry picked from commit 88d92cffc9d9c8807d9a6aaa8a5235494636fc86) Signed-off-by: Jack Vogel <[email protected]>
1 parent 6462033 commit 8e58122

File tree

4 files changed

+45
-2
lines changed

4 files changed

+45
-2
lines changed

drivers/usb/cdns3/cdnsp-gadget.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,26 @@ static void cdnsp_clear_port_change_bit(struct cdnsp_device *pdev,
138138
(portsc & PORT_CHANGE_BITS), port_regs);
139139
}
140140

141+
static void cdnsp_set_apb_timeout_value(struct cdnsp_device *pdev)
142+
{
143+
struct cdns *cdns = dev_get_drvdata(pdev->dev);
144+
__le32 __iomem *reg;
145+
void __iomem *base;
146+
u32 offset = 0;
147+
u32 val;
148+
149+
if (!cdns->override_apb_timeout)
150+
return;
151+
152+
base = &pdev->cap_regs->hc_capbase;
153+
offset = cdnsp_find_next_ext_cap(base, offset, D_XEC_PRE_REGS_CAP);
154+
reg = base + offset + REG_CHICKEN_BITS_3_OFFSET;
155+
156+
val = le32_to_cpu(readl(reg));
157+
val = CHICKEN_APB_TIMEOUT_SET(val, cdns->override_apb_timeout);
158+
writel(cpu_to_le32(val), reg);
159+
}
160+
141161
static void cdnsp_set_chicken_bits_2(struct cdnsp_device *pdev, u32 bit)
142162
{
143163
__le32 __iomem *reg;
@@ -1797,6 +1817,15 @@ static int cdnsp_gen_setup(struct cdnsp_device *pdev)
17971817
pdev->hci_version = HC_VERSION(pdev->hcc_params);
17981818
pdev->hcc_params = readl(&pdev->cap_regs->hcc_params);
17991819

1820+
/*
1821+
* Override the APB timeout value to give the controller more time for
1822+
* enabling UTMI clock and synchronizing APB and UTMI clock domains.
1823+
* This fix is platform specific and is required to fixes issue with
1824+
* reading incorrect value from PORTSC register after resuming
1825+
* from L1 state.
1826+
*/
1827+
cdnsp_set_apb_timeout_value(pdev);
1828+
18001829
cdnsp_get_rev_cap(pdev);
18011830

18021831
/* Make sure the Device Controller is halted. */

drivers/usb/cdns3/cdnsp-gadget.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,9 @@ struct cdnsp_rev_cap {
520520
#define REG_CHICKEN_BITS_2_OFFSET 0x48
521521
#define CHICKEN_XDMA_2_TP_CACHE_DIS BIT(28)
522522

523+
#define REG_CHICKEN_BITS_3_OFFSET 0x4C
524+
#define CHICKEN_APB_TIMEOUT_SET(p, val) (((p) & ~GENMASK(21, 0)) | (val))
525+
523526
/* XBUF Extended Capability ID. */
524527
#define XBUF_CAP_ID 0xCB
525528
#define XBUF_RX_TAG_MASK_0_OFFSET 0x1C

drivers/usb/cdns3/cdnsp-pci.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#define PCI_CLASS_SERIAL_USB_CDNS_USB3 (PCI_CLASS_SERIAL_USB << 8 | 0x80)
3535
#define PCI_CLASS_SERIAL_USB_CDNS_UDC PCI_CLASS_SERIAL_USB_DEVICE
3636

37+
#define CHICKEN_APB_TIMEOUT_VALUE 0x1C20
38+
3739
static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev)
3840
{
3941
/*
@@ -145,6 +147,14 @@ static int cdnsp_pci_probe(struct pci_dev *pdev,
145147
cdnsp->otg_irq = pdev->irq;
146148
}
147149

150+
/*
151+
* Cadence PCI based platform require some longer timeout for APB
152+
* to fixes domain clock synchronization issue after resuming
153+
* controller from L1 state.
154+
*/
155+
cdnsp->override_apb_timeout = CHICKEN_APB_TIMEOUT_VALUE;
156+
pci_set_drvdata(pdev, cdnsp);
157+
148158
if (pci_is_enabled(func)) {
149159
cdnsp->dev = dev;
150160
cdnsp->gadget_init = cdnsp_gadget_init;
@@ -154,8 +164,6 @@ static int cdnsp_pci_probe(struct pci_dev *pdev,
154164
goto free_cdnsp;
155165
}
156166

157-
pci_set_drvdata(pdev, cdnsp);
158-
159167
device_wakeup_enable(&pdev->dev);
160168
if (pci_dev_run_wake(pdev))
161169
pm_runtime_put_noidle(&pdev->dev);

drivers/usb/cdns3/core.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ struct cdns3_platform_data {
7979
* @pdata: platform data from glue layer
8080
* @lock: spinlock structure
8181
* @xhci_plat_data: xhci private data structure pointer
82+
* @override_apb_timeout: hold value of APB timeout. For value 0 the default
83+
* value in CHICKEN_BITS_3 will be preserved.
8284
* @gadget_init: pointer to gadget initialization function
8385
*/
8486
struct cdns {
@@ -117,6 +119,7 @@ struct cdns {
117119
struct cdns3_platform_data *pdata;
118120
spinlock_t lock;
119121
struct xhci_plat_priv *xhci_plat_data;
122+
u32 override_apb_timeout;
120123

121124
int (*gadget_init)(struct cdns *cdns);
122125
};

0 commit comments

Comments
 (0)