summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--driver/retimer/bb_retimer.c72
-rw-r--r--include/driver/retimer/bb_retimer_public.h2
-rw-r--r--zephyr/test/drivers/default/src/bb_retimer.c45
3 files changed, 95 insertions, 24 deletions
diff --git a/driver/retimer/bb_retimer.c b/driver/retimer/bb_retimer.c
index 897541bfc2..a013508863 100644
--- a/driver/retimer/bb_retimer.c
+++ b/driver/retimer/bb_retimer.c
@@ -43,6 +43,10 @@
* accessed from multiple tasks.
*/
static mutex_t bb_retimer_lock[CONFIG_USB_PD_PORT_MAX_COUNT];
+/*
+ * Requested BB mux state.
+ */
+static mux_state_t bb_mux_state[CONFIG_USB_PD_PORT_MAX_COUNT];
/**
* Utility functions
@@ -389,6 +393,7 @@ static int retimer_set_state(const struct usb_mux *me, mux_state_t mux_state,
*ack_required = false;
mutex_lock(&bb_retimer_lock[port]);
+ bb_mux_state[port] = mux_state;
/*
* Bit 0: DATA_CONNECTION_PRESENT
@@ -480,7 +485,38 @@ static int retimer_set_state(const struct usb_mux *me, mux_state_t mux_state,
return rv;
}
-void bb_retimer_hpd_update(const struct usb_mux *me, mux_state_t mux_state,
+static int bb_set_idle_mode(const struct usb_mux *me, bool idle)
+{
+ bool usb3_enable;
+ int rv;
+ uint32_t reg_val;
+ int port = me->usb_port;
+
+ mutex_lock(&bb_retimer_lock[port]);
+
+ if (!(bb_mux_state[port] & USB_PD_MUX_USB_ENABLED)) {
+ mutex_unlock(&bb_retimer_lock[port]);
+ return EC_SUCCESS;
+ }
+
+ rv = bb_retimer_read(me, BB_RETIMER_REG_CONNECTION_STATE, &reg_val);
+ if (rv != EC_SUCCESS) {
+ mutex_unlock(&bb_retimer_lock[port]);
+ return rv;
+ }
+
+ usb3_enable = !idle;
+
+ /* Bit 5: BB_RETIMER_USB_3_CONNECTION */
+ WRITE_BIT(reg_val, 5, usb3_enable);
+ rv = bb_retimer_write(me, BB_RETIMER_REG_CONNECTION_STATE, reg_val);
+
+ mutex_unlock(&bb_retimer_lock[port]);
+
+ return rv;
+}
+
+void bb_retimer_hpd_update(const struct usb_mux *me, mux_state_t hpd_state,
bool *ack_required)
{
uint32_t retimer_con_reg = 0;
@@ -490,6 +526,8 @@ void bb_retimer_hpd_update(const struct usb_mux *me, mux_state_t mux_state,
*ack_required = false;
mutex_lock(&bb_retimer_lock[port]);
+ bb_mux_state[port] = (bb_mux_state[port] & ~MUX_STATE_HPD_UPDATE_MASK) |
+ (hpd_state & MUX_STATE_HPD_UPDATE_MASK);
if (bb_retimer_read(me, BB_RETIMER_REG_CONNECTION_STATE,
&retimer_con_reg) != EC_SUCCESS) {
@@ -501,7 +539,7 @@ void bb_retimer_hpd_update(const struct usb_mux *me, mux_state_t mux_state,
* 0 - No IRQ_HPD
* 1 - IRQ_HPD received
*/
- if (mux_state & USB_PD_MUX_HPD_IRQ)
+ if (hpd_state & USB_PD_MUX_HPD_IRQ)
retimer_con_reg |= BB_RETIMER_IRQ_HPD;
else
retimer_con_reg &= ~BB_RETIMER_IRQ_HPD;
@@ -521,7 +559,7 @@ void bb_retimer_hpd_update(const struct usb_mux *me, mux_state_t mux_state,
* only when the HPD bit is set so that the retimer stays in
* low power mode until the external monitor is connected.
*/
- if (mux_state & USB_PD_MUX_HPD_LVL)
+ if (hpd_state & USB_PD_MUX_HPD_LVL)
retimer_con_reg |=
(BB_RETIMER_HPD_LVL | BB_RETIMER_DP_CONNECTION);
else
@@ -536,26 +574,7 @@ void bb_retimer_hpd_update(const struct usb_mux *me, mux_state_t mux_state,
void bb_retimer_set_usb3(const struct usb_mux *me, bool enable)
{
- int rv;
- uint32_t reg_val = 0;
- int port = me->usb_port;
-
- mutex_lock(&bb_retimer_lock[port]);
-
- rv = bb_retimer_read(me, BB_RETIMER_REG_CONNECTION_STATE, &reg_val);
- if (rv != EC_SUCCESS) {
- mutex_unlock(&bb_retimer_lock[port]);
- return;
- }
- /* Bit 5: USB_3_CONNECTION */
- WRITE_BIT(reg_val, 5, enable);
- rv = bb_retimer_write(me, BB_RETIMER_REG_CONNECTION_STATE, reg_val);
- if (rv != EC_SUCCESS) {
- mutex_unlock(&bb_retimer_lock[port]);
- return;
- }
-
- mutex_unlock(&bb_retimer_lock[port]);
+ bb_set_idle_mode(me, !enable);
}
#ifdef CONFIG_ZEPHYR
@@ -572,6 +591,9 @@ DECLARE_HOOK(HOOK_INIT, init_retimer_mutexes, HOOK_PRIO_FIRST);
static int retimer_low_power_mode(const struct usb_mux *me)
{
+ const int port = me->usb_port;
+
+ bb_mux_state[port] = USB_PD_MUX_NONE;
return bb_retimer_power_enable(me, false);
}
@@ -584,6 +606,9 @@ static int retimer_init(const struct usb_mux *me)
{
int rv;
uint32_t data;
+ const int port = me->usb_port;
+
+ bb_mux_state[port] = USB_PD_MUX_NONE;
/* Burnside Bridge is powered by main AP rail */
if (chipset_in_or_transitioning_to_state(CHIPSET_STATE_ANY_OFF)) {
@@ -627,6 +652,7 @@ static int retimer_init(const struct usb_mux *me)
const struct usb_mux_driver bb_usb_retimer = {
.init = retimer_init,
.set = retimer_set_state,
+ .set_idle_mode = bb_set_idle_mode,
.enter_low_power_mode = retimer_low_power_mode,
.is_retimer_fw_update_capable = is_retimer_fw_update_capable,
};
diff --git a/include/driver/retimer/bb_retimer_public.h b/include/driver/retimer/bb_retimer_public.h
index 2d2893fb49..8f5cec7421 100644
--- a/include/driver/retimer/bb_retimer_public.h
+++ b/include/driver/retimer/bb_retimer_public.h
@@ -53,7 +53,7 @@ __override_proto int bb_retimer_power_enable(const struct usb_mux *me,
* @param[out] ack_required Outputs whether the given change will require
* the AP to ACK before proceeding
*/
-void bb_retimer_hpd_update(const struct usb_mux *me, mux_state_t mux_state,
+void bb_retimer_hpd_update(const struct usb_mux *me, mux_state_t hpd_state,
bool *ack_required);
/**
diff --git a/zephyr/test/drivers/default/src/bb_retimer.c b/zephyr/test/drivers/default/src/bb_retimer.c
index 74d8fa86a2..7d7930894f 100644
--- a/zephyr/test/drivers/default/src/bb_retimer.c
+++ b/zephyr/test/drivers/default/src/bb_retimer.c
@@ -193,6 +193,51 @@ ZTEST_USER(bb_retimer_no_tasks, test_bb_set_state)
exp_conn, conn);
}
+/** Test retimer idle mode setting. */
+ZTEST_USER(bb_retimer_no_tasks, test_bb_set_idle_mode)
+{
+ const uint32_t usb3_conn =
+ BB_RETIMER_ACTIVE_PASSIVE | BB_RETIMER_USB_3_SPEED |
+ BB_RETIMER_USB_3_CONNECTION | BB_RETIMER_RE_TIMER_DRIVER |
+ BB_RETIMER_DATA_CONNECTION_PRESENT;
+ const uint32_t idle_conn =
+ BB_RETIMER_ACTIVE_PASSIVE | BB_RETIMER_USB_3_SPEED |
+ BB_RETIMER_RE_TIMER_DRIVER | BB_RETIMER_DATA_CONNECTION_PRESENT;
+ const struct emul *emul = EMUL_DT_GET(BB_RETIMER_NODE);
+ struct usb_mux usb_mux_c1;
+ uint32_t conn;
+ bool ack_required;
+
+ set_test_runner_tid();
+
+ /* Enable IDLE mode port C1 mux */
+ usb_mux_c1 = *usb_muxes[USBC_PORT_C1].mux;
+ usb_mux_c1.flags |= USB_MUX_FLAG_CAN_IDLE;
+
+ /* Check if USB3 is enabled before idle entry */
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(&usb_mux_c1, USB_PD_MUX_USB_ENABLED,
+ &ack_required),
+ NULL);
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ zassert_equal(conn, usb3_conn, "Expected state 0x%02x, got 0x%02x",
+ usb3_conn, conn);
+
+ /* Check if USB3 is disabled on idle entry */
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set_idle_mode(&usb_mux_c1, true), NULL);
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ zassert_equal(conn, idle_conn, "Expected state 0x%02x, got 0x%02x",
+ idle_conn, conn);
+
+ /* Check if USB3 is re-enabled on idle exit */
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set_idle_mode(&usb_mux_c1, false), NULL);
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ zassert_equal(conn, usb3_conn, "Expected state 0x%02x, got 0x%02x",
+ usb3_conn, conn);
+}
+
/** Test setting different options for DFP role */
ZTEST_USER(bb_retimer_no_tasks, test_bb_set_dfp_state)
{