From 68801c6d8c9697757b078d675948f998f7cbda6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Fri, 15 Nov 2024 12:26:11 +0100 Subject: [PATCH 1/2] [nrf fromlist] drivers: udc_dwc2: Set bit 17 if needed on Hibernation Exit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Programming Guide states that bit 17 on PCGCCTL writes should be set if the controller was enumerated for High Speed operation. Add the missing bit set to adhere to the Programming Guide. Upstream PR #: 85039 Signed-off-by: Tomasz Moń --- drivers/usb/common/usb_dwc2_hw.h | 32 ++++++++++++++++++++++++++++++++ drivers/usb/udc/udc_dwc2.c | 5 +++++ 2 files changed, 37 insertions(+) diff --git a/drivers/usb/common/usb_dwc2_hw.h b/drivers/usb/common/usb_dwc2_hw.h index fcb35489a04..d5e272c8752 100644 --- a/drivers/usb/common/usb_dwc2_hw.h +++ b/drivers/usb/common/usb_dwc2_hw.h @@ -997,6 +997,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 +1043,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..072fdbd2e13 100644 --- a/drivers/usb/udc/udc_dwc2.c +++ b/drivers/usb/udc/udc_dwc2.c @@ -915,6 +915,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); From c600dc8ac99c0e34829708f10762cff3d28581cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Fri, 15 Nov 2024 12:31:27 +0100 Subject: [PATCH 2/2] [nrf fromlist] drivers: udc_dwc2: Workaround hibernation exit glitch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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ń --- drivers/usb/common/usb_dwc2_hw.h | 3 +++ drivers/usb/udc/udc_dwc2.c | 30 ++++++++++++++++++++++-------- 2 files changed, 25 insertions(+), 8 deletions(-) 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);