diff --git a/drivers/usb/common/usb_dwc2_hw.h b/drivers/usb/common/usb_dwc2_hw.h index d5e272c8752..fcd0d2a0060 100644 --- a/drivers/usb/common/usb_dwc2_hw.h +++ b/drivers/usb/common/usb_dwc2_hw.h @@ -338,6 +338,9 @@ USB_DWC2_SET_FIELD_DEFINE(gnptxfsiz_nptxfstaddr, GNPTXFSIZ_NPTXFSTADDR) #define USB_DWC2_GGPIO_STM32_PWRDWN_POS 16UL #define USB_DWC2_GGPIO_STM32_PWRDWN BIT(USB_DWC2_GGPIO_STM32_PWRDWN_POS) +/* GSNPSID register */ +#define USB_DWC2_GSNPSID_REV_5_00A 0x4F54500AUL + /* GHWCFG1 register */ #define USB_DWC2_GHWCFG1 0x0044UL #define USB_DWC2_GHWCFG1_EPDIR_POS(i) (i * 2) diff --git a/drivers/usb/udc/udc_dwc2.c b/drivers/usb/udc/udc_dwc2.c index 072fdbd2e13..01c0f3040ce 100644 --- a/drivers/usb/udc/udc_dwc2.c +++ b/drivers/usb/udc/udc_dwc2.c @@ -121,6 +121,8 @@ struct udc_dwc2_data { unsigned int dynfifosizing : 1; unsigned int bufferdma : 1; unsigned int syncrst : 1; + /* Defect workarounds */ + unsigned int wa_essregrestored : 1; /* Runtime state flags */ unsigned int hibernated : 1; unsigned int enumdone : 1; @@ -945,6 +947,21 @@ static void dwc2_restore_essential_registers(const struct device *dev, pcgcctl |= USB_DWC2_PCGCCTL_ESSREGRESTORED; sys_write32(pcgcctl, (mem_addr_t)&base->pcgcctl); + + /* Note: in Remote Wakeup case 15 ms max signaling time starts now */ + + /* Wait for Restore Done Interrupt */ + dwc2_wait_for_bit(dev, (mem_addr_t)&base->gintsts, USB_DWC2_GINTSTS_RSTRDONEINT); + + if (priv->wa_essregrestored) { + pcgcctl &= ~USB_DWC2_PCGCCTL_ESSREGRESTORED; + sys_write32(pcgcctl, (mem_addr_t)&base->pcgcctl); + k_busy_wait(1); + } + + if (!bus_reset) { + sys_write32(0xFFFFFFFFUL, (mem_addr_t)&base->gintsts); + } } 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, dwc2_restore_essential_registers(dev, rwup, bus_reset); - /* Note: in Remote Wakeup case 15 ms max signaling time starts now */ - - /* Wait for Restore Done Interrupt */ - dwc2_wait_for_bit(dev, (mem_addr_t)&base->gintsts, USB_DWC2_GINTSTS_RSTRDONEINT); - if (!bus_reset) { - sys_write32(0xFFFFFFFFUL, (mem_addr_t)&base->gintsts); - } - /* Disable restore from PMU */ sys_clear_bits(gpwrdn_reg, USB_DWC2_GPWRDN_RESTORE); k_busy_wait(1); @@ -1757,6 +1766,7 @@ static int udc_dwc2_init_controller(const struct device *dev) mem_addr_t gahbcfg_reg = (mem_addr_t)&base->gahbcfg; mem_addr_t gusbcfg_reg = (mem_addr_t)&base->gusbcfg; mem_addr_t dcfg_reg = (mem_addr_t)&base->dcfg; + uint32_t gsnpsid; uint32_t dcfg; uint32_t gusbcfg; uint32_t gahbcfg; @@ -1772,6 +1782,10 @@ static int udc_dwc2_init_controller(const struct device *dev) return ret; } + /* Enable RTL workarounds based on controller revision */ + gsnpsid = sys_read32((mem_addr_t)&base->gsnpsid); + priv->wa_essregrestored = gsnpsid < USB_DWC2_GSNPSID_REV_5_00A; + priv->ghwcfg1 = sys_read32((mem_addr_t)&base->ghwcfg1); ghwcfg2 = sys_read32((mem_addr_t)&base->ghwcfg2); ghwcfg3 = sys_read32((mem_addr_t)&base->ghwcfg3);