Skip to content

Commit 693769a

Browse files
committed
[nrf fromlist] drivers: udc_dwc2: Workaround hibernation exit glitch
DWC2 otg versions earlier than 5.00a are subject to randomly occurring glitch on Hibernation Exit by Host Initiated Resume, Hibernation Exit by Device Inititated Resume and Hibernation Exit by Host Initiated Reset. When the glitch happens the device address is not correctly restored. If the address is not correctly restored then the tokens addressed to the device will timeout leading to host resetting the bus. Upstream PR #: 85039 Signed-off-by: Tomasz Moń <[email protected]>
1 parent f25809c commit 693769a

File tree

2 files changed

+25
-8
lines changed

2 files changed

+25
-8
lines changed

drivers/usb/common/usb_dwc2_hw.h

+3
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,9 @@ USB_DWC2_SET_FIELD_DEFINE(gnptxfsiz_nptxfstaddr, GNPTXFSIZ_NPTXFSTADDR)
338338
#define USB_DWC2_GGPIO_STM32_PWRDWN_POS 16UL
339339
#define USB_DWC2_GGPIO_STM32_PWRDWN BIT(USB_DWC2_GGPIO_STM32_PWRDWN_POS)
340340

341+
/* GSNPSID register */
342+
#define USB_DWC2_GSNPSID_REV_5_00A 0x4F54500AUL
343+
341344
/* GHWCFG1 register */
342345
#define USB_DWC2_GHWCFG1 0x0044UL
343346
#define USB_DWC2_GHWCFG1_EPDIR_POS(i) (i * 2)

drivers/usb/udc/udc_dwc2.c

+22-8
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ struct udc_dwc2_data {
121121
unsigned int dynfifosizing : 1;
122122
unsigned int bufferdma : 1;
123123
unsigned int syncrst : 1;
124+
/* Defect workarounds */
125+
unsigned int wa_essregrestored : 1;
124126
/* Runtime state flags */
125127
unsigned int hibernated : 1;
126128
unsigned int enumdone : 1;
@@ -945,6 +947,21 @@ static void dwc2_restore_essential_registers(const struct device *dev,
945947

946948
pcgcctl |= USB_DWC2_PCGCCTL_ESSREGRESTORED;
947949
sys_write32(pcgcctl, (mem_addr_t)&base->pcgcctl);
950+
951+
/* Note: in Remote Wakeup case 15 ms max signaling time starts now */
952+
953+
/* Wait for Restore Done Interrupt */
954+
dwc2_wait_for_bit(dev, (mem_addr_t)&base->gintsts, USB_DWC2_GINTSTS_RSTRDONEINT);
955+
956+
if (priv->wa_essregrestored) {
957+
pcgcctl &= ~USB_DWC2_PCGCCTL_ESSREGRESTORED;
958+
sys_write32(pcgcctl, (mem_addr_t)&base->pcgcctl);
959+
k_busy_wait(1);
960+
}
961+
962+
if (!bus_reset) {
963+
sys_write32(0xFFFFFFFFUL, (mem_addr_t)&base->gintsts);
964+
}
948965
}
949966

950967
static void dwc2_restore_device_registers(const struct device *dev, bool rwup)
@@ -1081,14 +1098,6 @@ static void dwc2_exit_hibernation(const struct device *dev,
10811098

10821099
dwc2_restore_essential_registers(dev, rwup, bus_reset);
10831100

1084-
/* Note: in Remote Wakeup case 15 ms max signaling time starts now */
1085-
1086-
/* Wait for Restore Done Interrupt */
1087-
dwc2_wait_for_bit(dev, (mem_addr_t)&base->gintsts, USB_DWC2_GINTSTS_RSTRDONEINT);
1088-
if (!bus_reset) {
1089-
sys_write32(0xFFFFFFFFUL, (mem_addr_t)&base->gintsts);
1090-
}
1091-
10921101
/* Disable restore from PMU */
10931102
sys_clear_bits(gpwrdn_reg, USB_DWC2_GPWRDN_RESTORE);
10941103
k_busy_wait(1);
@@ -1757,6 +1766,7 @@ static int udc_dwc2_init_controller(const struct device *dev)
17571766
mem_addr_t gahbcfg_reg = (mem_addr_t)&base->gahbcfg;
17581767
mem_addr_t gusbcfg_reg = (mem_addr_t)&base->gusbcfg;
17591768
mem_addr_t dcfg_reg = (mem_addr_t)&base->dcfg;
1769+
uint32_t gsnpsid;
17601770
uint32_t dcfg;
17611771
uint32_t gusbcfg;
17621772
uint32_t gahbcfg;
@@ -1772,6 +1782,10 @@ static int udc_dwc2_init_controller(const struct device *dev)
17721782
return ret;
17731783
}
17741784

1785+
/* Enable RTL workarounds based on controller revision */
1786+
gsnpsid = sys_read32((mem_addr_t)&base->gsnpsid);
1787+
priv->wa_essregrestored = gsnpsid < USB_DWC2_GSNPSID_REV_5_00A;
1788+
17751789
priv->ghwcfg1 = sys_read32((mem_addr_t)&base->ghwcfg1);
17761790
ghwcfg2 = sys_read32((mem_addr_t)&base->ghwcfg2);
17771791
ghwcfg3 = sys_read32((mem_addr_t)&base->ghwcfg3);

0 commit comments

Comments
 (0)