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 <haril@qualcomm.corp-partner.google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/89826
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Kapil Porwal <kapilporwal@google.com>
Reviewed-by: Paul Menzel <paulepanter@mailbox.org>
This commit is contained in:
Hari L 2025-10-28 19:16:46 +05:30 committed by Matt DeVillier
commit 8449a15aed
2 changed files with 38 additions and 60 deletions

View file

@ -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 */

View file

@ -8,6 +8,7 @@
#include <soc/qcom_spmi.h>
#include <delay.h>
#include <gpio.h>
#include <timer.h>
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);
}