summaryrefslogtreecommitdiff
path: root/driver/retimer/bb_retimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/retimer/bb_retimer.c')
-rw-r--r--driver/retimer/bb_retimer.c208
1 files changed, 138 insertions, 70 deletions
diff --git a/driver/retimer/bb_retimer.c b/driver/retimer/bb_retimer.c
index c515505900..897541bfc2 100644
--- a/driver/retimer/bb_retimer.c
+++ b/driver/retimer/bb_retimer.c
@@ -1,4 +1,4 @@
-/* Copyright 2019 The Chromium OS Authors. All rights reserved.
+/* Copyright 2019 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -10,40 +10,45 @@
#include "common.h"
#include "console.h"
#include "gpio.h"
+#include "hooks.h"
#include "i2c.h"
#include "task.h"
#include "timer.h"
#include "usb_pd.h"
#include "util.h"
-#define BB_RETIMER_REG_SIZE 4
-#define BB_RETIMER_READ_SIZE (BB_RETIMER_REG_SIZE + 1)
-#define BB_RETIMER_WRITE_SIZE (BB_RETIMER_REG_SIZE + 2)
-#define BB_RETIMER_MUX_DATA_PRESENT (USB_PD_MUX_USB_ENABLED \
- | USB_PD_MUX_DP_ENABLED \
- | USB_PD_MUX_SAFE_MODE \
- | USB_PD_MUX_TBT_COMPAT_ENABLED \
- | USB_PD_MUX_USB4_ENABLED)
+#define BB_RETIMER_REG_SIZE 4
+#define BB_RETIMER_READ_SIZE (BB_RETIMER_REG_SIZE + 1)
+#define BB_RETIMER_WRITE_SIZE (BB_RETIMER_REG_SIZE + 2)
+#define BB_RETIMER_MUX_DATA_PRESENT \
+ (USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED | \
+ USB_PD_MUX_SAFE_MODE | USB_PD_MUX_TBT_COMPAT_ENABLED | \
+ USB_PD_MUX_USB4_ENABLED)
-#define BB_RETIMER_MUX_USB_ALT_MODE (USB_PD_MUX_USB_ENABLED\
- | USB_PD_MUX_DP_ENABLED \
- | USB_PD_MUX_TBT_COMPAT_ENABLED \
- | USB_PD_MUX_USB4_ENABLED)
+#define BB_RETIMER_MUX_USB_ALT_MODE \
+ (USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED | \
+ USB_PD_MUX_TBT_COMPAT_ENABLED | USB_PD_MUX_USB4_ENABLED)
-#define BB_RETIMER_MUX_USB_DP_MODE (USB_PD_MUX_USB_ENABLED \
- | USB_PD_MUX_DP_ENABLED \
- | USB_PD_MUX_USB4_ENABLED)
+#define BB_RETIMER_MUX_USB_DP_MODE \
+ (USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED | \
+ USB_PD_MUX_USB4_ENABLED)
-#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
-#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args)
+#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ##args)
+#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ##args)
-#define BB_RETIMER_I2C_RETRY 5
+#define BB_RETIMER_I2C_RETRY 5
+
+/*
+ * Mutex for BB_RETIMER_REG_CONNECTION_STATE register, which can be
+ * accessed from multiple tasks.
+ */
+static mutex_t bb_retimer_lock[CONFIG_USB_PD_PORT_MAX_COUNT];
/**
* Utility functions
*/
-static int bb_retimer_read(const struct usb_mux *me,
- const uint8_t offset, uint32_t *data)
+static int bb_retimer_read(const struct usb_mux *me, const uint8_t offset,
+ uint32_t *data)
{
int rv, retry = 0;
uint8_t buf[BB_RETIMER_READ_SIZE];
@@ -60,15 +65,15 @@ static int bb_retimer_read(const struct usb_mux *me,
* byte[1:4] : Data [LSB -> MSB]
* Stop
*/
- rv = i2c_xfer(me->i2c_port, me->i2c_addr_flags,
- &offset, 1, buf, BB_RETIMER_READ_SIZE);
+ rv = i2c_xfer(me->i2c_port, me->i2c_addr_flags, &offset, 1, buf,
+ BB_RETIMER_READ_SIZE);
if (rv == EC_SUCCESS)
break;
if (++retry >= BB_RETIMER_I2C_RETRY) {
- CPRINTS("C%d: Retimer I2C read err=%d",
- me->usb_port, rv);
+ CPRINTS("C%d: Retimer I2C read err=%d", me->usb_port,
+ rv);
return rv;
}
msleep(10);
@@ -82,8 +87,8 @@ static int bb_retimer_read(const struct usb_mux *me,
return EC_SUCCESS;
}
-static int bb_retimer_write(const struct usb_mux *me,
- const uint8_t offset, uint32_t data)
+static int bb_retimer_write(const struct usb_mux *me, const uint8_t offset,
+ uint32_t data)
{
int rv, retry = 0;
uint8_t buf[BB_RETIMER_WRITE_SIZE];
@@ -109,14 +114,14 @@ static int bb_retimer_write(const struct usb_mux *me,
*/
while (1) {
rv = i2c_xfer(me->i2c_port, me->i2c_addr_flags, buf,
- BB_RETIMER_WRITE_SIZE, NULL, 0);
+ BB_RETIMER_WRITE_SIZE, NULL, 0);
if (rv == EC_SUCCESS)
break;
if (++retry >= BB_RETIMER_I2C_RETRY) {
- CPRINTS("C%d: Retimer I2C write err=%d",
- me->usb_port, rv);
+ CPRINTS("C%d: Retimer I2C write err=%d", me->usb_port,
+ rv);
break;
}
msleep(10);
@@ -157,7 +162,8 @@ static void retimer_set_state_dfp(int port, mux_state_t mux_state,
uint32_t *set_retimer_con)
{
union tbt_mode_resp_cable cable_resp = {
- .raw_value = pd_get_tbt_mode_vdo(port, TCPCI_MSG_SOP_PRIME) };
+ .raw_value = pd_get_tbt_mode_vdo(port, TCPCI_MSG_SOP_PRIME)
+ };
union tbt_mode_resp_device dev_resp;
enum idh_ptype cable_type = get_usb_pd_cable_type(port);
@@ -171,7 +177,7 @@ static void retimer_set_state_dfp(int port, mux_state_t mux_state,
*
*/
if (is_active_cable_element_retimer(port) &&
- (mux_state & BB_RETIMER_MUX_USB_DP_MODE))
+ (mux_state & BB_RETIMER_MUX_USB_DP_MODE))
*set_retimer_con |= BB_RETIMER_RE_TIMER_DRIVER;
/*
@@ -184,7 +190,7 @@ static void retimer_set_state_dfp(int port, mux_state_t mux_state,
*/
if ((mux_state & BB_RETIMER_MUX_USB_ALT_MODE) &&
((cable_type == IDH_PTYPE_ACABLE) ||
- cable_resp.tbt_active_passive == TBT_CABLE_ACTIVE))
+ cable_resp.tbt_active_passive == TBT_CABLE_ACTIVE))
*set_retimer_con |= BB_RETIMER_ACTIVE_PASSIVE;
if (mux_state & USB_PD_MUX_TBT_COMPAT_ENABLED ||
@@ -239,7 +245,7 @@ static void retimer_set_state_dfp(int port, mux_state_t mux_state,
*/
if ((cable_type == IDH_PTYPE_ACABLE ||
cable_resp.tbt_active_passive == TBT_CABLE_ACTIVE) &&
- cable_resp.lsrx_comm == UNIDIR_LSRX_COMM)
+ cable_resp.lsrx_comm == UNIDIR_LSRX_COMM)
*set_retimer_con |= BB_RETIMER_TBT_ACTIVE_LINK_TRAINING;
/*
@@ -251,9 +257,9 @@ static void retimer_set_state_dfp(int port, mux_state_t mux_state,
* 10..11b - Reserved
*/
*set_retimer_con |= BB_RETIMER_USB4_TBT_CABLE_SPEED_SUPPORT(
- mux_state & USB_PD_MUX_TBT_COMPAT_ENABLED ?
- get_tbt_cable_speed(port) :
- get_usb4_cable_speed(port));
+ mux_state & USB_PD_MUX_TBT_COMPAT_ENABLED ?
+ get_tbt_cable_speed(port) :
+ get_usb4_cable_speed(port));
/*
* Bits 29-28: TBT_GEN_SUPPORT
@@ -262,8 +268,8 @@ static void retimer_set_state_dfp(int port, mux_state_t mux_state,
* 20.0625Gb/s, 20.000Gb/s)
* 10..11b - Reserved
*/
- *set_retimer_con |= BB_RETIMER_TBT_CABLE_GENERATION(
- cable_resp.tbt_rounded);
+ *set_retimer_con |=
+ BB_RETIMER_TBT_CABLE_GENERATION(cable_resp.tbt_rounded);
}
}
@@ -284,7 +290,8 @@ static void retimer_set_state_ufp(int port, mux_state_t mux_state,
/* TODO:b/168890624: Set USB4 retimer config for UFP */
if (mux_state & USB_PD_MUX_TBT_COMPAT_ENABLED) {
union tbt_dev_mode_enter_cmd ufp_tbt_enter_mode = {
- .raw_value = pd_ufp_get_enter_mode(port)};
+ .raw_value = pd_ufp_get_enter_mode(port)
+ };
/*
* Bit 2: RE_TIMER_DRIVER
* 0 - Re-driver
@@ -316,9 +323,9 @@ static void retimer_set_state_ufp(int port, mux_state_t mux_state,
*/
if ((IS_ENABLED(CONFIG_USBC_RETIMER_INTEL_BB_VPRO_CAPABLE) &&
ufp_tbt_enter_mode.intel_spec_b0 ==
- VENDOR_SPECIFIC_SUPPORTED) ||
+ VENDOR_SPECIFIC_SUPPORTED) ||
ufp_tbt_enter_mode.vendor_spec_b1 ==
- VENDOR_SPECIFIC_SUPPORTED)
+ VENDOR_SPECIFIC_SUPPORTED)
*set_retimer_con |= BB_RETIMER_VPRO_DOCK_DP_OVERDRIVE;
/*
@@ -352,7 +359,7 @@ static void retimer_set_state_ufp(int port, mux_state_t mux_state,
* Set according to TBT3 Enter Mode bit 18:16
*/
*set_retimer_con |= BB_RETIMER_USB4_TBT_CABLE_SPEED_SUPPORT(
- ufp_tbt_enter_mode.tbt_cable_speed);
+ ufp_tbt_enter_mode.tbt_cable_speed);
/*
* Bits 29-28: TBT_GEN_SUPPORT
* 00b - 3rd generation TBT (10.3125 and 20.625Gb/s)
@@ -363,7 +370,7 @@ static void retimer_set_state_ufp(int port, mux_state_t mux_state,
* Set according to TBT3 Enter Mode bit 20:19
*/
*set_retimer_con |= BB_RETIMER_TBT_CABLE_GENERATION(
- ufp_tbt_enter_mode.tbt_rounded);
+ ufp_tbt_enter_mode.tbt_rounded);
}
}
@@ -376,10 +383,13 @@ static int retimer_set_state(const struct usb_mux *me, mux_state_t mux_state,
uint32_t set_retimer_con = 0;
uint8_t dp_pin_mode;
int port = me->usb_port;
+ int rv = 0;
/* This driver does not use host command ACKs */
*ack_required = false;
+ mutex_lock(&bb_retimer_lock[port]);
+
/*
* Bit 0: DATA_CONNECTION_PRESENT
* 0 - No connection present
@@ -413,14 +423,7 @@ static int retimer_set_state(const struct usb_mux *me, mux_state_t mux_state,
set_retimer_con |= BB_RETIMER_USB_3_SPEED;
}
- /*
- * Bit 8: DP_CONNECTION
- * 0 ā€“ No DP connection
- * 1 ā€“ DP connected
- */
if (mux_state & USB_PD_MUX_DP_ENABLED) {
- set_retimer_con |= BB_RETIMER_DP_CONNECTION;
-
/*
* Bit 11-10: DP_PIN_ASSIGNMENT (ignored if BIT8 = 0)
* 00 ā€“ Pin assignments E/Eā€™
@@ -429,7 +432,7 @@ static int retimer_set_state(const struct usb_mux *me, mux_state_t mux_state,
*/
dp_pin_mode = get_dp_pin_mode(port);
if (dp_pin_mode == MODE_DP_PIN_C ||
- dp_pin_mode == MODE_DP_PIN_D)
+ dp_pin_mode == MODE_DP_PIN_D)
set_retimer_con |= BB_RETIMER_DP_PIN_ASSIGNMENT;
/*
@@ -471,22 +474,28 @@ static int retimer_set_state(const struct usb_mux *me, mux_state_t mux_state,
retimer_set_state_ufp(port, mux_state, &set_retimer_con);
/* Writing the register4 */
- return bb_retimer_write(me, BB_RETIMER_REG_CONNECTION_STATE,
- set_retimer_con);
+ rv = bb_retimer_write(me, BB_RETIMER_REG_CONNECTION_STATE,
+ set_retimer_con);
+ mutex_unlock(&bb_retimer_lock[port]);
+ return rv;
}
void bb_retimer_hpd_update(const struct usb_mux *me, mux_state_t mux_state,
bool *ack_required)
{
uint32_t retimer_con_reg = 0;
+ int port = me->usb_port;
/* This driver does not use host command ACKs */
*ack_required = false;
+ mutex_lock(&bb_retimer_lock[port]);
+
if (bb_retimer_read(me, BB_RETIMER_REG_CONNECTION_STATE,
- &retimer_con_reg) != EC_SUCCESS)
+ &retimer_con_reg) != EC_SUCCESS) {
+ mutex_unlock(&bb_retimer_lock[port]);
return;
-
+ }
/*
* Bit 14: IRQ_HPD (ignored if BIT8 = 0)
* 0 - No IRQ_HPD
@@ -498,19 +507,69 @@ void bb_retimer_hpd_update(const struct usb_mux *me, mux_state_t mux_state,
retimer_con_reg &= ~BB_RETIMER_IRQ_HPD;
/*
+ * Bit 8: DP_CONNECTION
+ * 0 - No DP connection
+ * 1 - DP connected
+ *
* Bit 15: HPD_LVL (ignored if BIT8 = 0)
* 0 - HPD_State Low
* 1 - HPD_State High
+ *
+ * HDMI card connect to chromebook the DP_CONNECTION bit
+ * would be enable.
+ * It will increase BBR power consumption, so enable the DP bit
+ * 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)
- retimer_con_reg |= BB_RETIMER_HPD_LVL;
+ retimer_con_reg |=
+ (BB_RETIMER_HPD_LVL | BB_RETIMER_DP_CONNECTION);
else
- retimer_con_reg &= ~BB_RETIMER_HPD_LVL;
+ retimer_con_reg &=
+ ~(BB_RETIMER_HPD_LVL | BB_RETIMER_DP_CONNECTION);
/* Writing the register4 */
bb_retimer_write(me, BB_RETIMER_REG_CONNECTION_STATE, retimer_con_reg);
+
+ mutex_unlock(&bb_retimer_lock[port]);
+}
+
+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]);
}
+#ifdef CONFIG_ZEPHYR
+static void init_retimer_mutexes(void)
+{
+ int port;
+
+ for (port = 0; port < CONFIG_USB_PD_PORT_MAX_COUNT; port++) {
+ k_mutex_init(&bb_retimer_lock[port]);
+ }
+}
+DECLARE_HOOK(HOOK_INIT, init_retimer_mutexes, HOOK_PRIO_FIRST);
+#endif
+
static int retimer_low_power_mode(const struct usb_mux *me)
{
return bb_retimer_power_enable(me, false);
@@ -538,14 +597,21 @@ static int retimer_init(const struct usb_mux *me)
return rv;
rv = bb_retimer_read(me, BB_RETIMER_REG_VENDOR_ID, &data);
+ /*
+ * After reset, i2c controller may not be ready, if this fails,
+ * retry one more time.
+ * TODO: revisit the delay time after retimer reset.
+ */
+ if (rv != EC_SUCCESS)
+ rv = bb_retimer_read(me, BB_RETIMER_REG_VENDOR_ID, &data);
if (rv != EC_SUCCESS)
return rv;
+ CPRINTS("C%d: retimer power enable success", me->usb_port);
#ifdef CONFIG_USBC_RETIMER_INTEL_HB
if (data != BB_RETIMER_DEVICE_ID)
return EC_ERROR_INVAL;
#else
- if ((data != BB_RETIMER_VENDOR_ID_1) &&
- data != BB_RETIMER_VENDOR_ID_2)
+ if ((data != BB_RETIMER_VENDOR_ID_1) && data != BB_RETIMER_VENDOR_ID_2)
return EC_ERROR_INVAL;
rv = bb_retimer_read(me, BB_RETIMER_REG_DEVICE_ID, &data);
@@ -566,12 +632,13 @@ const struct usb_mux_driver bb_usb_retimer = {
};
#ifdef CONFIG_CMD_RETIMER
-static int console_command_bb_retimer(int argc, char **argv)
+static int console_command_bb_retimer(int argc, const char **argv)
{
char rw, *e;
int port, reg, data, val = 0;
int rv = EC_SUCCESS;
const struct usb_mux *mux;
+ const struct usb_mux_chain *mux_chain;
if (argc < 4)
return EC_ERROR_PARAM_COUNT;
@@ -581,14 +648,15 @@ static int console_command_bb_retimer(int argc, char **argv)
if (*e || !board_is_usb_pd_port_present(port))
return EC_ERROR_PARAM1;
- mux = &usb_muxes[port];
- while (mux) {
+ mux_chain = &usb_muxes[port];
+ while (mux_chain) {
+ mux = mux_chain->mux;
if (mux->driver == &bb_usb_retimer)
break;
- mux = mux->next_mux;
+ mux_chain = mux_chain->next;
}
- if (!mux)
+ if (!mux_chain)
return EC_ERROR_PARAM1;
/* Validate r/w selection */
@@ -608,17 +676,17 @@ static int console_command_bb_retimer(int argc, char **argv)
return EC_ERROR_PARAM4;
}
- for (; mux != NULL; mux = mux->next_mux) {
+ for (; mux_chain != NULL; mux_chain = mux_chain->next) {
+ mux = mux_chain->mux;
if (mux->driver == &bb_usb_retimer) {
if (rw == 'r')
rv = bb_retimer_read(mux, reg, &data);
else {
rv = bb_retimer_write(mux, reg, val);
if (rv == EC_SUCCESS) {
- rv = bb_retimer_read(
- mux, reg, &data);
- if (rv == EC_SUCCESS && data != val)
- rv = EC_ERROR_UNKNOWN;
+ rv = bb_retimer_read(mux, reg, &data);
+ if (rv == EC_SUCCESS && data != val)
+ rv = EC_ERROR_UNKNOWN;
}
}
if (rv == EC_SUCCESS)