From 8449a15aedd13de7fbb85dfc51b0fde9d3649963 Mon Sep 17 00:00:00 2001 From: Hari L Date: Tue, 28 Oct 2025 19:16:46 +0530 Subject: [PATCH] soc/qualcomm/x1p42100: Reduce USB OTG state enable timeout to 20ms Reduce maximum timeout from 100ms to 20ms for OTG Enablement polling for USB Type-C. Avoid OTG enablement polling when in sink mode BUG=b:455551151 TEST: Verify USB3.0 (SS) works for C0/C1 on Google/Bluey. Background: During USB Type-C port initialization, the OTG (On-The-Go) status must be verified when the port operates in source mode to ensure proper VBUS power delivery. The previous implementation polled the OTG status register with a 100ms timeout on all ports regardless of their role. Previous Implementation Issues: 1. Overly conservative timeout: The 100ms maximum wait significantly exceeded actual requirements, as OTG enablement consistently completes in approximately 14ms under normal conditions 2. Inefficient polling logic: OTG status was polled even when ports operated in sink mode, where OTG functionality is irrelevant since the port receives rather than provides power Improvements: 1. Timeout reduction: Decreased maximum polling duration from 100ms to 20ms, maintaining adequate margin (>40% headroom) while reducing boot time by up to 80ms per sink-mode port 2. Mode-aware polling: Added logic to detect port role and skip OTG status polling entirely for sink-mode ports, as demonstrated by the "Primary in SNK mode - skipping OTG status read" log entry The changes maintain full USB3.0 SuperSpeed functionality while improving initialization efficiency. The 20ms timeout remains sufficiently conservative to accommodate normal timing variations. Debug logs: [DEBUG] QMP PHY SS0 initialized and locked in 1671us, phy_status: 0x86868686 [INFO ] Enabling Primary VBUS SuperSpeed [INFO ] Primary in SNK mode - skipping OTG status read [INFO ] Primary Type-C Status: [INFO ] Misc Status (0x2B0B): 0x1a [INFO ] Src Status (0x2B08): 0x00 [INFO ] Mode Config (0x2B44): 0x00 [INFO ] Interrupt En Cfg 1 (0x2B5E): 0xff [INFO ] State Machine Status (0x2B09): 0x02 [DEBUG] USB HS PHY initialized for index 3 [DEBUG] QMP-1x16 USB4 DP PHY SS1 init [DEBUG] QMP PHY SS1 initialized and locked in 1671us, phy_status: 0x86868686 [INFO ] Enabling Secondary VBUS SuperSpeed [INFO ] Secondary in SRC mode - OTG Status: 0x02, State: 0x02 (OTG Enabled) - Time: 14 ms [INFO ] Secondary Type-C Status: [INFO ] Misc Status (0x2B0B): 0x4b [INFO ] Src Status (0x2B08): 0x08 [INFO ] Mode Config (0x2B44): 0x00 [INFO ] Interrupt En Cfg 1 (0x2B5E): 0xff [INFO ] State Machine Status (0x2B09): 0xa6 confirmed that there are no otg polling for sink mode and polling timeout is reduced to max of 20ms. Change-Id: I7467248185c9d0526816ac62e1e1a1496440fddc Signed-off-by: Hari L Reviewed-on: https://review.coreboot.org/c/coreboot/+/89826 Tested-by: build bot (Jenkins) Reviewed-by: Kapil Porwal Reviewed-by: Paul Menzel --- .../qualcomm/x1p42100/include/soc/usb/usb.h | 13 ++- src/soc/qualcomm/x1p42100/usb/usb.c | 85 +++++++------------ 2 files changed, 38 insertions(+), 60 deletions(-) diff --git a/src/soc/qualcomm/x1p42100/include/soc/usb/usb.h b/src/soc/qualcomm/x1p42100/include/soc/usb/usb.h index f8aa9e9ccc..250ae55c70 100644 --- a/src/soc/qualcomm/x1p42100/include/soc/usb/usb.h +++ b/src/soc/qualcomm/x1p42100/include/soc/usb/usb.h @@ -106,24 +106,21 @@ #define SCHG_DCDC_CMD_OTG 0x2740 #define SCHG_DCDC_OTG_CFG 0x2753 #define SCHG_DCDC_OTG_STATUS 0x270D +#define SCHG_DCDC_ENG_SDCDC_CFG7 0x27C7 +#define SCHG_DCDC_ENG_SDCDC_GM_CLOOP_PD_OTG_BUCK_MASK 0x30 /* OTG Status register bit definitions */ #define OTG_STATE_MASK 0x07 -#define OTG_STATE_DISABLED 0x00 -#define OTG_STATE_ENABLING 0x01 #define OTG_STATE_ENABLED 0x02 -#define OTG_STATE_DISABLING 0x03 -#define OTG_STATE_ERROR 0x04 - -/* OTG Status check timeout and polling interval */ -#define OTG_STATUS_TIMEOUT_MS 100 -#define OTG_STATUS_POLL_INTERVAL_MS 2 +#define OTG_STATUS_TIMEOUT_MS 20 +#define OTG_STATUS_POLL_DELAY_MS 2 /* Type-C register offsets */ #define SCHG_TYPE_C_TYPE_C_MISC_STATUS 0x2B0B #define SCHG_TYPE_C_TYPE_C_SRC_STATUS 0x2B08 #define SCHG_TYPE_C_TYPE_C_MODE_CFG 0x2B44 #define TYPEC_VBUS_STATUS_MASK BIT(5) +#define TYPEC_SNK_SRC_MODE BIT(6) #define CCOUT_INVERT_POLARITY 0x03 /* USB Repeater SPMI Tune register offsets */ diff --git a/src/soc/qualcomm/x1p42100/usb/usb.c b/src/soc/qualcomm/x1p42100/usb/usb.c index e97650773d..ec61ebd5be 100644 --- a/src/soc/qualcomm/x1p42100/usb/usb.c +++ b/src/soc/qualcomm/x1p42100/usb/usb.c @@ -8,6 +8,7 @@ #include #include #include +#include struct usb_dwc3 { u32 sbuscfg0; @@ -667,53 +668,6 @@ void usb_update_refclk_for_core(u32 core_num, bool enable) } } -/* - * wait_for_otg_enabled - Waits for OTG block to reach enabled state - * @status_reg_addr: SPMI address of the OTG status register - * @core_name: Name of the core for logging (e.g., "SMB1", "SMB2") - * @return: true if OTG enabled successfully, false if timeout or error - */ -static bool wait_for_otg_enabled(u32 status_reg_addr, const char *core_name) -{ - u32 timeout_ms = 0; - u8 otg_status; - u8 otg_state; - - while (timeout_ms < OTG_STATUS_TIMEOUT_MS) { - otg_status = spmi_read8(status_reg_addr); - otg_state = otg_status & OTG_STATE_MASK; - - printk(BIOS_DEBUG, "%s OTG Status: 0x%02x, State: 0x%02x\n", - core_name, otg_status, otg_state); - - switch (otg_state) { - case OTG_STATE_ENABLED: - printk(BIOS_INFO, "%s OTG block enabled successfully\n", core_name); - return true; - case OTG_STATE_ERROR: - printk(BIOS_ERR, "%s OTG block in ERROR state (0x%02x)\n", - core_name, otg_status); - return false; - case OTG_STATE_DISABLED: - case OTG_STATE_ENABLING: - case OTG_STATE_DISABLING: - /* Continue polling */ - break; - default: - printk(BIOS_WARNING, "%s OTG block in unknown state: 0x%02x\n", - core_name, otg_state); - break; - } - - mdelay(OTG_STATUS_POLL_INTERVAL_MS); - timeout_ms += OTG_STATUS_POLL_INTERVAL_MS; - } - - printk(BIOS_ERR, "%s OTG enable timeout after %d ms, final state: 0x%02x\n", - core_name, timeout_ms, otg_state); - return false; -} - /* * enable_vbus_ss - Enables VBUS SuperSpeed for specified USB core * @config: Controller configuration containing SMB slave address @@ -721,15 +675,43 @@ static bool wait_for_otg_enabled(u32 status_reg_addr, const char *core_name) void enable_vbus_ss(const struct dwc3_controller_config *config) { u8 slave = config->smb_slave_addr; + u8 misc_status, otg_status = 0, otg_state = 0; + struct stopwatch sw; printk(BIOS_INFO, "Enabling %s VBUS SuperSpeed\n", config->name); + /* Configure SDCDC CFG7 register before enabling OTG */ + spmi_write8(SPMI_ADDR(slave, SCHG_DCDC_ENG_SDCDC_CFG7), + SCHG_DCDC_ENG_SDCDC_GM_CLOOP_PD_OTG_BUCK_MASK); + spmi_write8(SPMI_ADDR(slave, SCHG_DCDC_OTG_CFG), 0x20); spmi_write8(SPMI_ADDR(slave, SCHG_DCDC_CMD_OTG), 0x1); - /* Wait for OTG block to reach enabled state */ - if (!wait_for_otg_enabled(SPMI_ADDR(slave, SCHG_DCDC_OTG_STATUS), config->name)) - printk(BIOS_ERR, "%s OTG enable failed\n", config->name); + /* Check Type-C mode */ + misc_status = spmi_read8(SPMI_ADDR(slave, SCHG_TYPE_C_TYPE_C_MISC_STATUS)); + + /* Check SNK_SRC_MODE bit (bit 6): 0 = SNK, 1 = SRC */ + if (misc_status & TYPEC_SNK_SRC_MODE) { + /* In SRC mode, poll OTG status until enabled */ + stopwatch_init_msecs_expire(&sw, OTG_STATUS_TIMEOUT_MS); + while (!stopwatch_expired(&sw)) { + otg_status = spmi_read8(SPMI_ADDR(slave, SCHG_DCDC_OTG_STATUS)); + otg_state = otg_status & OTG_STATE_MASK; + + if (otg_state == OTG_STATE_ENABLED) { + printk(BIOS_INFO, "%s in SRC mode - OTG Status: 0x%02x, State: 0x%02x (OTG Enabled)\n", + config->name, otg_status, otg_state); + return; + } + mdelay(OTG_STATUS_POLL_DELAY_MS); + } + + /* Timeout - log final state */ + printk(BIOS_INFO, "%s in SRC mode - OTG Status: 0x%02x, State: 0x%02x - Timeout after %d ms\n", + config->name, otg_status, otg_state, OTG_STATUS_TIMEOUT_MS); + } else { + printk(BIOS_INFO, "%s in SNK mode - skipping OTG status read\n", config->name); + } } /* @@ -746,8 +728,7 @@ void usb_typec_status_check(const struct dwc3_controller_config *config) mode_cfg = spmi_read8(SPMI_ADDR(slave, SCHG_TYPE_C_TYPE_C_MODE_CFG)); printk(BIOS_INFO, "%s Type-C Status:\n", config->name); - printk(BIOS_INFO, " Misc Status (0x2B0B): 0x%02x, VBUS Status (bit 5): %d\n", - misc_status, (misc_status & TYPEC_VBUS_STATUS_MASK) ? 1 : 0); + printk(BIOS_INFO, " Misc Status (0x2B0B): 0x%02x\n", misc_status); printk(BIOS_INFO, " Src Status (0x2B08): 0x%02x\n", src_status); printk(BIOS_INFO, " Mode Config (0x2B44): 0x%02x\n", mode_cfg); }