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.c623
1 files changed, 0 insertions, 623 deletions
diff --git a/driver/retimer/bb_retimer.c b/driver/retimer/bb_retimer.c
deleted file mode 100644
index bf3da60b32..0000000000
--- a/driver/retimer/bb_retimer.c
+++ /dev/null
@@ -1,623 +0,0 @@
-/* Copyright 2019 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * Driver for Intel Burnside Bridge - Thunderbolt/USB/DisplayPort Retimer
- */
-
-#include "driver/retimer/bb_retimer.h"
-#include "chipset.h"
-#include "common.h"
-#include "console.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_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 CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
-#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args)
-
-#define BB_RETIMER_I2C_RETRY 5
-
-/**
- * Utility functions
- */
-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];
-
- /*
- * This I2C message will trigger retimer's internal read sequence
- * if its a NAK, sleep and resend same I2C
- */
- while (1) {
- /*
- * Read sequence
- * Addr flags (w) - Reg offset - repeated start - Addr flags(r)
- * byte[0] : Read size
- * byte[1:4] : Data [LSB -> MSB]
- * Stop
- */
- 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);
- return rv;
- }
- msleep(10);
- }
-
- if (buf[0] != BB_RETIMER_REG_SIZE)
- return EC_ERROR_UNKNOWN;
-
- *data = buf[1] | (buf[2] << 8) | (buf[3] << 16) | (buf[4] << 24);
-
- return EC_SUCCESS;
-}
-
-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];
-
- /*
- * Write sequence
- * Addr flags(w)
- * byte[0] : Reg offset
- * byte[1] : Write Size
- * byte[2:5] : Data [LSB -> MSB]
- * stop
- */
- buf[0] = offset;
- buf[1] = BB_RETIMER_REG_SIZE;
- buf[2] = data & 0xFF;
- buf[3] = (data >> 8) & 0xFF;
- buf[4] = (data >> 16) & 0xFF;
- buf[5] = (data >> 24) & 0xFF;
-
- /*
- * This I2C message will trigger retimer's internal write sequence
- * if its a NAK, sleep and resend same I2C
- */
- while (1) {
- rv = i2c_xfer(me->i2c_port, me->i2c_addr_flags, buf,
- 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);
- break;
- }
- msleep(10);
- }
- return rv;
-}
-
-__overridable int bb_retimer_power_enable(const struct usb_mux *me, bool enable)
-{
- const struct bb_usb_control *control = &bb_controls[me->usb_port];
-
- /* handle retimer's power domain */
-
- if (enable) {
- gpio_set_level(control->usb_ls_en_gpio, 1);
- /*
- * Tpw, minimum time from VCC to RESET_N de-assertion is 100us.
- * For boards that don't provide a load switch control, the
- * retimer_init() function ensures power is up before calling
- * this function.
- */
- msleep(1);
- gpio_set_level(control->retimer_rst_gpio, 1);
- /*
- * Allow 1ms time for the retimer to power up lc_domain
- * which powers I2C controller within retimer
- */
- msleep(1);
- } else {
- gpio_set_level(control->retimer_rst_gpio, 0);
- msleep(1);
- gpio_set_level(control->usb_ls_en_gpio, 0);
- }
- return EC_SUCCESS;
-}
-
-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) };
- union tbt_mode_resp_device dev_resp;
- enum idh_ptype cable_type = get_usb_pd_cable_type(port);
-
- /*
- * Bit 2: RE_TIMER_DRIVER
- * 0 - Re-driver
- * 1 - Re-timer
- *
- * If Alternate mode is USB/DP/USB4, RE_TIMER_DRIVER is
- * set according to SOP' VDO2 response Bit 9.
- *
- */
- if (is_active_cable_element_retimer(port) &&
- (mux_state & BB_RETIMER_MUX_USB_DP_MODE))
- *set_retimer_con |= BB_RETIMER_RE_TIMER_DRIVER;
-
- /*
- * Bit 22: ACTIVE/PASSIVE
- * 0 - Passive cable
- * 1 - Active cable
- *
- * If the mode is USB/DP/Thunderbolt_compat/USB4, ACTIVE/PASIVE is
- * set according to Discover mode SOP' response.
- */
- if ((mux_state & BB_RETIMER_MUX_USB_ALT_MODE) &&
- ((cable_type == IDH_PTYPE_ACABLE) ||
- cable_resp.tbt_active_passive == TBT_CABLE_ACTIVE))
- *set_retimer_con |= BB_RETIMER_ACTIVE_PASSIVE;
-
- if (mux_state & USB_PD_MUX_TBT_COMPAT_ENABLED ||
- mux_state & USB_PD_MUX_USB4_ENABLED) {
- dev_resp.raw_value = pd_get_tbt_mode_vdo(port, TCPCI_MSG_SOP);
-
- /*
- * Bit 2: RE_TIMER_DRIVER
- * 0 - Re-driver
- * 1 - Re-timer
- *
- * If Alternate mode is Thunderbolt-Compat, RE_TIMER_DRIVER is
- * set according to Discover Mode SOP' response,
- * Bit 22: Retimer Type.
- */
- if (cable_resp.retimer_type == USB_RETIMER)
- *set_retimer_con |= BB_RETIMER_RE_TIMER_DRIVER;
-
- /*
- * Bit 17: TBT_TYPE
- * 0 - Type-C to Type-C Cable
- * 1 - Type-C Legacy TBT Adapter
- */
- if (dev_resp.tbt_adapter == TBT_ADAPTER_TBT2_LEGACY)
- *set_retimer_con |= BB_RETIMER_TBT_TYPE;
-
- /*
- * Bit 18: CABLE_TYPE
- * 0 - Electrical cable
- * 1 - Optical cable
- */
- if (cable_resp.tbt_cable == TBT_CABLE_OPTICAL)
- *set_retimer_con |= BB_RETIMER_TBT_CABLE_TYPE;
-
- /*
- * Bit 19: VPO_DOCK_DETECTED_OR_DP_OVERDRIVE
- * 0 - No vPro Dock.No DP Overdrive
- * detected
- * 1 - vPro Dock or DP Overdrive
- * detected
- */
- if (dev_resp.intel_spec_b0 == VENDOR_SPECIFIC_SUPPORTED ||
- dev_resp.vendor_spec_b1 == VENDOR_SPECIFIC_SUPPORTED)
- *set_retimer_con |= BB_RETIMER_VPRO_DOCK_DP_OVERDRIVE;
-
- /*
- * Bit 20: TBT_ACTIVE_LINK_TRAINING
- * 0 - Active with bi-directional LSRX communication
- * 1 - Active with uni-directional LSRX communication
- * Set to "0" when passive cable plug
- */
- if ((cable_type == IDH_PTYPE_ACABLE ||
- cable_resp.tbt_active_passive == TBT_CABLE_ACTIVE) &&
- cable_resp.lsrx_comm == UNIDIR_LSRX_COMM)
- *set_retimer_con |= BB_RETIMER_TBT_ACTIVE_LINK_TRAINING;
-
- /*
- * Bit 27-25: USB4/TBT Cable speed
- * 000b - No functionality
- * 001b - USB3.1 Gen1 Cable
- * 010b - 10Gb/s
- * 011b - 10Gb/s and 20Gb/s
- * 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));
-
- /*
- * Bits 29-28: TBT_GEN_SUPPORT
- * 00b - 3rd generation TBT (10.3125 and 20.625Gb/s)
- * 01b - 4th generation TBT (10.00005Gb/s, 10.3125Gb/s,
- * 20.0625Gb/s, 20.000Gb/s)
- * 10..11b - Reserved
- */
- *set_retimer_con |= BB_RETIMER_TBT_CABLE_GENERATION(
- cable_resp.tbt_rounded);
- }
-}
-
-static void retimer_set_state_ufp(int port, mux_state_t mux_state,
- uint32_t *set_retimer_con)
-{
- /*
- * Bit 7: USB_DATA_ROLE for the Burnside Bridge side of
- * connection.
- * 0 - DFP
- * 1 - UFP
- */
- *set_retimer_con |= BB_RETIMER_USB_DATA_ROLE;
-
- if (!IS_ENABLED(CONFIG_USB_PD_ALT_MODE_UFP))
- return;
-
- /* 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)};
- /*
- * Bit 2: RE_TIMER_DRIVER
- * 0 - Re-driver
- * 1 - Re-timer
- *
- * Set according to TBT3 Enter Mode bit 22.
- */
- if (ufp_tbt_enter_mode.retimer_type == USB_RETIMER)
- *set_retimer_con |= BB_RETIMER_RE_TIMER_DRIVER;
-
- /*
- * Bit 18: CABLE_TYPE
- * 0 - Electrical cable
- * 1 - Optical cable
- *
- * Set according to TBT3 Enter Mode bit 21.
- */
- if (ufp_tbt_enter_mode.tbt_cable == TBT_CABLE_OPTICAL)
- *set_retimer_con |= BB_RETIMER_TBT_CABLE_TYPE;
-
- /*
- * Bit 19: VPO_DOCK_DETECTED_OR_DP_OVERDRIVE
- * 0 - No vPro Dock.No DP Overdrive
- * detected
- * 1 - vPro Dock or DP Overdrive
- * detected
- *
- * Set according to TBT3 Enter Mode bit 26 or bit 31
- */
- if (ufp_tbt_enter_mode.intel_spec_b0 ==
- VENDOR_SPECIFIC_SUPPORTED ||
- ufp_tbt_enter_mode.vendor_spec_b1 ==
- VENDOR_SPECIFIC_SUPPORTED)
- *set_retimer_con |= BB_RETIMER_VPRO_DOCK_DP_OVERDRIVE;
-
- /*
- * Bit 20: TBT_ACTIVE_LINK_TRAINING
- * 0 - Active with bi-directional LSRX communication
- * 1 - Active with uni-directional LSRX communication
- *
- * Set according to TBT3 Enter Mode bit 23
- */
- if (ufp_tbt_enter_mode.lsrx_comm == UNIDIR_LSRX_COMM)
- *set_retimer_con |= BB_RETIMER_TBT_ACTIVE_LINK_TRAINING;
-
- /*
- * Bit 22: ACTIVE/PASSIVE
- * 0 - Passive cable
- * 1 - Active cable
- *
- * Set according to TBT3 Enter Mode bit 24
- */
- if (ufp_tbt_enter_mode.cable == TBT_ENTER_ACTIVE_CABLE)
- *set_retimer_con |= BB_RETIMER_ACTIVE_PASSIVE;
-
- /*
- * Bit 27-25: TBT Cable speed
- * 000b - No functionality
- * 001b - USB3.1 Gen1 Cable
- * 010b - 10Gb/s
- * 011b - 10Gb/s and 20Gb/s
- * 10..11b - Reserved
- *
- * 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);
- /*
- * Bits 29-28: TBT_GEN_SUPPORT
- * 00b - 3rd generation TBT (10.3125 and 20.625Gb/s)
- * 01b - 4th generation TBT (10.00005Gb/s, 10.3125Gb/s,
- * 20.0625Gb/s, 20.000Gb/s)
- * 10..11b - Reserved
- *
- * Set according to TBT3 Enter Mode bit 20:19
- */
- *set_retimer_con |= BB_RETIMER_TBT_CABLE_GENERATION(
- ufp_tbt_enter_mode.tbt_rounded);
- }
-}
-
-/**
- * Driver interface functions
- */
-static int retimer_set_state(const struct usb_mux *me, mux_state_t mux_state,
- bool *ack_required)
-{
- uint32_t set_retimer_con = 0;
- uint8_t dp_pin_mode;
- int port = me->usb_port;
-
- /* This driver does not use host command ACKs */
- *ack_required = false;
-
- /*
- * Bit 0: DATA_CONNECTION_PRESENT
- * 0 - No connection present
- * 1 - Connection present
- */
- if (mux_state & BB_RETIMER_MUX_DATA_PRESENT)
- set_retimer_con |= BB_RETIMER_DATA_CONNECTION_PRESENT;
-
- /*
- * Bit 1: CONNECTION_ORIENTATION
- * 0 - Normal
- * 1 - reversed
- */
- if (mux_state & USB_PD_MUX_POLARITY_INVERTED)
- set_retimer_con |= BB_RETIMER_CONNECTION_ORIENTATION;
-
- /*
- * Bit 5: USB_3_CONNECTION
- * 0 - No USB3.1 Connection
- * 1 - USB3.1 connection
- */
- if (mux_state & USB_PD_MUX_USB_ENABLED) {
- set_retimer_con |= BB_RETIMER_USB_3_CONNECTION;
-
- /*
- * Bit 6: USB3_Speed
- * 0 – USB3 is limited to Gen1
- * 1 – USB3 Gen1/Gen2 supported
- */
- if (is_cable_speed_gen2_capable(port))
- 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’
- * 01 – Pin assignments C/C’/D/D’1,2
- * 10, 11 - reserved
- */
- dp_pin_mode = get_dp_pin_mode(port);
- if (dp_pin_mode == MODE_DP_PIN_C ||
- dp_pin_mode == MODE_DP_PIN_D)
- set_retimer_con |= BB_RETIMER_DP_PIN_ASSIGNMENT;
-
- /*
- * Bit 14: IRQ_HPD (ignored if BIT8 = 0)
- * 0 - No IRQ_HPD
- * 1 - IRQ_HPD received
- */
- if (mux_state & USB_PD_MUX_HPD_IRQ)
- set_retimer_con |= BB_RETIMER_IRQ_HPD;
-
- /*
- * Bit 15: HPD_LVL (ignored if BIT8 = 0)
- * 0 - HPD_State Low
- * 1 - HPD_State High
- */
- if (mux_state & USB_PD_MUX_HPD_LVL)
- set_retimer_con |= BB_RETIMER_HPD_LVL;
- }
-
- /*
- * Bit 16: TBT_CONNECTION
- * 0 - TBT not configured
- * 1 - TBT configured
- */
- if (mux_state & USB_PD_MUX_TBT_COMPAT_ENABLED)
- set_retimer_con |= BB_RETIMER_TBT_CONNECTION;
-
- /*
- * Bit 23: USB4_CONNECTION
- * 0 - USB4 not configured
- * 1 - USB4 Configured
- */
- if (mux_state & USB_PD_MUX_USB4_ENABLED)
- set_retimer_con |= BB_RETIMER_USB4_ENABLED;
-
- if (pd_get_data_role(port) == PD_ROLE_DFP)
- retimer_set_state_dfp(port, mux_state, &set_retimer_con);
- else
- 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);
-}
-
-void bb_retimer_hpd_update(const struct usb_mux *me, mux_state_t mux_state)
-{
- uint32_t retimer_con_reg = 0;
-
- if (bb_retimer_read(me, BB_RETIMER_REG_CONNECTION_STATE,
- &retimer_con_reg) != EC_SUCCESS)
- return;
-
- /*
- * Bit 14: IRQ_HPD (ignored if BIT8 = 0)
- * 0 - No IRQ_HPD
- * 1 - IRQ_HPD received
- */
- if (mux_state & USB_PD_MUX_HPD_IRQ)
- retimer_con_reg |= BB_RETIMER_IRQ_HPD;
- else
- retimer_con_reg &= ~BB_RETIMER_IRQ_HPD;
-
- /*
- * Bit 15: HPD_LVL (ignored if BIT8 = 0)
- * 0 - HPD_State Low
- * 1 - HPD_State High
- */
- if (mux_state & USB_PD_MUX_HPD_LVL)
- retimer_con_reg |= BB_RETIMER_HPD_LVL;
- else
- retimer_con_reg &= ~BB_RETIMER_HPD_LVL;
-
- /* Writing the register4 */
- bb_retimer_write(me, BB_RETIMER_REG_CONNECTION_STATE, retimer_con_reg);
-}
-
-static int retimer_low_power_mode(const struct usb_mux *me)
-{
- return bb_retimer_power_enable(me, false);
-}
-
-static bool is_retimer_fw_update_capable(void)
-{
- return true;
-}
-
-static int retimer_init(const struct usb_mux *me)
-{
- int rv;
- uint32_t data;
-
- /* Burnside Bridge is powered by main AP rail */
- if (chipset_in_or_transitioning_to_state(CHIPSET_STATE_ANY_OFF)) {
- /* Ensure reset is asserted while chip is not powered */
- bb_retimer_power_enable(me, false);
- return EC_ERROR_NOT_POWERED;
- }
-
- rv = bb_retimer_power_enable(me, true);
- if (rv != EC_SUCCESS)
- return rv;
-
- rv = bb_retimer_read(me, BB_RETIMER_REG_VENDOR_ID, &data);
- if (rv != EC_SUCCESS)
- return rv;
- 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);
- if (rv != EC_SUCCESS)
- return rv;
- if (data != BB_RETIMER_DEVICE_ID)
- return EC_ERROR_INVAL;
-
- return EC_SUCCESS;
-}
-
-const struct usb_mux_driver bb_usb_retimer = {
- .init = retimer_init,
- .set = retimer_set_state,
- .enter_low_power_mode = retimer_low_power_mode,
- .is_retimer_fw_update_capable = is_retimer_fw_update_capable,
-};
-
-#ifdef CONFIG_CMD_RETIMER
-static int console_command_bb_retimer(int argc, char **argv)
-{
- char rw, *e;
- int port, reg, data, val = 0;
- int rv = EC_SUCCESS;
- const struct usb_mux *mux;
-
- if (argc < 4)
- return EC_ERROR_PARAM_COUNT;
-
- /* Get port number */
- port = strtoi(argv[1], &e, 0);
- if (*e || !board_is_usb_pd_port_present(port))
- return EC_ERROR_PARAM1;
-
- mux = &usb_muxes[port];
- while (mux) {
- if (mux->driver == &bb_usb_retimer)
- break;
- mux = mux->next_mux;
- }
-
- if (!mux)
- return EC_ERROR_PARAM1;
-
- /* Validate r/w selection */
- rw = argv[2][0];
- if (rw != 'w' && rw != 'r')
- return EC_ERROR_PARAM2;
-
- /* Get register address */
- reg = strtoi(argv[3], &e, 0);
- if (*e || reg < 0)
- return EC_ERROR_PARAM3;
-
- /* Get value to be written */
- if (rw == 'w') {
- val = strtoi(argv[4], &e, 0);
- if (*e || val < 0)
- return EC_ERROR_PARAM4;
- }
-
- for (; mux != NULL; mux = mux->next_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;
- }
- }
- if (rv == EC_SUCCESS)
- CPRINTS("Addr 0x%x register %d = 0x%x",
- mux->i2c_addr_flags, reg, data);
- }
- }
-
- return rv;
-}
-DECLARE_CONSOLE_COMMAND(bb, console_command_bb_retimer,
- "<port> <r/w> <reg> | <val>",
- "Read or write to BB retimer register");
-#endif /* CONFIG_CMD_RETIMER */