diff --git a/drivers/usb/common/usb_dwc2_hw.h b/drivers/usb/common/usb_dwc2_hw.h index fcb35489a04..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) @@ -997,6 +1000,33 @@ USB_DWC2_SET_FIELD_DEFINE(doeptsizn_xfersize, DOEPTSIZN_XFERSIZE) /* Power and Clock Gating Control Register */ #define USB_DWC2_PCGCCTL 0x0E00UL +#define USB_DWC2_PCGCCTL_IF_DEV_MODE_POS 31UL +#define USB_DWC2_PCGCCTL_IF_DEV_MODE BIT(USB_DWC2_PCGCCTL_IF_DEV_MODE_POS) +#define USB_DWC2_PCGCCTL_P2HD_PRT_SPD_POS 29UL +#define USB_DWC2_PCGCCTL_P2HD_PRT_SPD_MASK (0x3UL << USB_DWC2_PCGCCTL_P2HD_PRT_SPD_POS) +#define USB_DWC2_PCGCCTL_P2HD_PRT_SPD_LS 2 +#define USB_DWC2_PCGCCTL_P2HD_PRT_SPD_FS 1 +#define USB_DWC2_PCGCCTL_P2HD_PRT_SPD_HS 0 +#define USB_DWC2_PCGCCTL_P2HD_DEV_ENUM_SPD_POS 27UL +#define USB_DWC2_PCGCCTL_P2HD_DEV_ENUM_SPD_MASK (0x3UL << USB_DWC2_PCGCCTL_P2HD_DEV_ENUM_SPD_POS) +#define USB_DWC2_PCGCCTL_P2HD_DEV_ENUM_SPD_FS48 3 +#define USB_DWC2_PCGCCTL_P2HD_DEV_ENUM_SPD_LS 2 +#define USB_DWC2_PCGCCTL_P2HD_DEV_ENUM_SPD_FS 1 +#define USB_DWC2_PCGCCTL_P2HD_DEV_ENUM_SPD_HS 0 +#define USB_DWC2_PCGCCTL_MAC_DEV_ADDR_POS 20UL +#define USB_DWC2_PCGCCTL_MAC_DEV_ADDR_MASK (0x7FUL << USB_DWC2_PCGCCTL_MAC_DEV_ADDR_POS) +#define USB_DWC2_PCGCCTL_MAX_TERMSELECT_POS 19UL +#define USB_DWC2_PCGCCTL_MAX_TERMSELECT BIT(USB_DWC2_PCGCCTL_MAX_TERMSELECT_POS) +#define USB_DWC2_PCGCCTL_MAC_XCVRSELECT_POS 17UL +#define USB_DWC2_PCGCCTL_MAC_XCVRSELECT_MASK (0x3UL << USB_DWC2_PCGCCTL_MAC_XCVRSELECT_POS) +#define USB_DWC2_PCGCCTL_MAC_XCVRSELECT_LFS 3 +#define USB_DWC2_PCGCCTL_MAC_XCVRSELECT_LS 2 +#define USB_DWC2_PCGCCTL_MAC_XCVRSELECT_FS 1 +#define USB_DWC2_PCGCCTL_MAC_XCVRSELECT_HS 0 +#define USB_DWC2_PCGCCTL_SH2PL_PRT_CTL0_POS 16UL +#define USB_DWC2_PCGCCTL_SH2PL_PRT_CTL0 BIT(USB_DWC2_PCGCCTL_SH2PL_PRT_CTL0_POS) +#define USB_DWC2_PCGCCTL_PRT_CLK_SEL_POS 14UL +#define USB_DWC2_PCGCCTL_PRT_CLK_SEL_MASK (0x3UL << USB_DWC2_PCGCCTL_PRT_CLK_SEL_POS) #define USB_DWC2_PCGCCTL_RESTOREVALUE_POS 14UL #define USB_DWC2_PCGCCTL_RESTOREVALUE_MASK (0x3FFFFUL << USB_DWC2_PCGCCTL_RESTOREVALUE_POS) #define USB_DWC2_PCGCCTL_ESSREGRESTORED_POS 13UL @@ -1016,6 +1046,11 @@ USB_DWC2_SET_FIELD_DEFINE(doeptsizn_xfersize, DOEPTSIZN_XFERSIZE) #define USB_DWC2_PCGCCTL_STOPPCLK_POS 0UL #define USB_DWC2_PCGCCTL_STOPPCLK BIT(USB_DWC2_PCGCCTL_STOPPCLK_POS) +USB_DWC2_GET_FIELD_DEFINE(pcgcctl_p2hd_prt_spd, PCGCCTL_P2HD_PRT_SPD) +USB_DWC2_GET_FIELD_DEFINE(pcgcctl_p2hd_dev_enum_spd, PCGCCTL_P2HD_DEV_ENUM_SPD) +USB_DWC2_GET_FIELD_DEFINE(pcgcctl_mac_dev_addr, PCGCCTL_MAC_DEV_ADDR) +USB_DWC2_GET_FIELD_DEFINE(pcgcctl_mac_xcvrselect, PCGCCTL_MAC_XCVRSELECT) +USB_DWC2_GET_FIELD_DEFINE(pcgcctl_prt_clk_sel, PCGCCTL_PRT_CLK_SEL) USB_DWC2_GET_FIELD_DEFINE(pcgcctl_restorevalue, PCGCCTL_RESTOREVALUE) USB_DWC2_SET_FIELD_DEFINE(pcgcctl_restorevalue, PCGCCTL_RESTOREVALUE) diff --git a/drivers/usb/udc/udc_dwc2.c b/drivers/usb/udc/udc_dwc2.c index 7f1256a10f0..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; @@ -915,6 +917,11 @@ static void dwc2_restore_essential_registers(const struct device *dev, struct dwc2_reg_backup *backup = &priv->backup; uint32_t pcgcctl = backup->pcgcctl & USB_DWC2_PCGCCTL_RESTOREVALUE_MASK; + if (usb_dwc2_get_pcgcctl_p2hd_dev_enum_spd(pcgcctl) == + USB_DWC2_PCGCCTL_P2HD_DEV_ENUM_SPD_HS) { + pcgcctl |= BIT(17); + } + sys_write32(backup->glpmcfg, (mem_addr_t)&base->glpmcfg); sys_write32(backup->gi2cctl, (mem_addr_t)&base->gi2cctl); sys_write32(pcgcctl, (mem_addr_t)&base->pcgcctl); @@ -940,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) @@ -1076,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); @@ -1752,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; @@ -1767,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);