summaryrefslogtreecommitdiff
path: root/driver
diff options
context:
space:
mode:
authorVijay Hiremath <vijay.p.hiremath@intel.com>2019-03-06 13:01:45 -0800
committerchrome-bot <chrome-bot@chromium.org>2019-05-14 23:57:37 -0700
commita84d8055a57fe95c38df2ae1be332c57475aec27 (patch)
treec06e55d1d7520838265516abbe84f5e905e635b8 /driver
parentd823206bd2f5f6899ffe65d6086e3278552be903 (diff)
downloadchrome-ec-a84d8055a57fe95c38df2ae1be332c57475aec27.tar.gz
retimer: Add driver support for Intel Burnside Bridge retimer
Burnside Bridge is a Type-C multi-protocol retimer to be used in on-board applications. Burnside Bridge offers the ability to latch protocol signals into on-chip memory before retransmitting them onwards. It can be used to extend the physical length of the system without increasing high frequency jitter. Burnside Bridge supports spec compliant retimer of following protocols: 1. Display Port: four unidirectional DP lanes 2. USB3.1 Gen1/2: one bi-directional USB lane 3. Thunderbolt: two bi-directional CIO lanes 4. Multifunction Display (MFD): two unidirectional lanes of DP and one bi-directional lane of USB3.1 Gen1/2 Note: Only item 1, 2 & 4 are supported in this CL. Item 3 support will be added in follow on CLs. BUG=b:127623438 BRANCH=none TEST=Manually verified on ICLRVP, able to configure the registers Change-Id: I2d60dbcaf8fe7a1503f09a2f16007409f059f54e Signed-off-by: Ayushee <ayushee.shah@intel.com> Signed-off-by: Vijay Hiremath <vijay.p.hiremath@intel.com> Reviewed-on: https://chromium-review.googlesource.com/1594170 Commit-Ready: Jett Rink <jettrink@chromium.org> Tested-by: Vijay P Hiremath <vijay.p.hiremath@intel.com> Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Divya S Sasidharan <divya.s.sasidharan@intel.com>
Diffstat (limited to 'driver')
-rw-r--r--driver/build.mk3
-rw-r--r--driver/retimer/bb_retimer.c275
-rw-r--r--driver/retimer/bb_retimer.h56
-rw-r--r--driver/usb_mux_virtual.c12
4 files changed, 346 insertions, 0 deletions
diff --git a/driver/build.mk b/driver/build.mk
index 956035bc97..afd965b0f8 100644
--- a/driver/build.mk
+++ b/driver/build.mk
@@ -126,6 +126,9 @@ driver-$(CONFIG_USB_PD_TCPM_PS8805)+=tcpm/ps8xxx.o
driver-$(CONFIG_USB_PD_TCPM_TUSB422)+=tcpm/tusb422.o
driver-$(CONFIG_USB_PD_TCPM_NCT38XX)+=tcpm/nct38xx.o
+# Type-C Retimer drivers
+driver-$(CONFIG_USB_PD_RETIMER_INTEL_BB)+=retimer/bb_retimer.o
+
# USB mux high-level driver
driver-$(CONFIG_USBC_SS_MUX)+=usb_mux.o
diff --git a/driver/retimer/bb_retimer.c b/driver/retimer/bb_retimer.c
new file mode 100644
index 0000000000..bef247363a
--- /dev/null
+++ b/driver/retimer/bb_retimer.c
@@ -0,0 +1,275 @@
+/* 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 "bb_retimer.h"
+#include "common.h"
+#include "console.h"
+#include "i2c.h"
+#include "timer.h"
+#include "usb_pd.h"
+#include "usb_retimer.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 CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args)
+
+static int bb_retimer_read(int port, const uint8_t offset, uint32_t *data)
+{
+ int rv;
+ uint8_t buf[BB_RETIMER_READ_SIZE];
+
+ /*
+ * Read sequence
+ * Slave Addr(w) - Reg offset - repeated start - Slave Addr(r)
+ * byte[0] : Read size
+ * byte[1:4] : Data [LSB -> MSB]
+ * Stop
+ */
+ rv = i2c_xfer(bb_retimers[port].i2c_port, bb_retimers[port].i2c_addr,
+ &offset, 1, buf, BB_RETIMER_READ_SIZE);
+ if (rv)
+ return rv;
+ 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(int port, const uint8_t offset, uint32_t data)
+{
+ uint8_t buf[BB_RETIMER_WRITE_SIZE];
+
+ /*
+ * Write sequence
+ * Slave Addr(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;
+
+ return i2c_xfer(bb_retimers[port].i2c_port, bb_retimers[port].i2c_addr,
+ buf, BB_RETIMER_WRITE_SIZE, NULL, 0);
+}
+
+static void bb_retimer_power_handle(int port, int on_off)
+{
+ struct bb_retimer *retimer;
+
+ /* handle retimer's power domain */
+ retimer = &bb_retimers[port];
+
+ if (on_off) {
+ gpio_set_level(retimer->usb_ls_en_gpio, 1);
+ msleep(1);
+ gpio_set_level(retimer->retimer_rst_gpio, 1);
+ msleep(10);
+ gpio_set_level(retimer->force_power_gpio, 1);
+
+ /*
+ * If BB retimer NVM is shared between two ports allow 40ms
+ * time for both retimers to be initialized. Else allow 20ms
+ * to initialize.
+ */
+ if (retimer->shared_nvm)
+ msleep(40);
+ else
+ msleep(20);
+ } else {
+ gpio_set_level(retimer->force_power_gpio, 0);
+ msleep(1);
+ gpio_set_level(retimer->retimer_rst_gpio, 0);
+ msleep(1);
+ gpio_set_level(retimer->usb_ls_en_gpio, 0);
+ }
+}
+
+int retimer_set_state(int port, mux_state_t mux_state)
+{
+ uint32_t set_retimer_con = 0;
+ uint8_t dp_pin_mode;
+
+ /*
+ * Bit 0: DATA_CONNECTION_PRESENT
+ * 0 - No connection present
+ * 1 - Connection present
+ */
+ if (mux_state & USB_PD_MUX_USB_ENABLED ||
+ mux_state & USB_PD_MUX_DP_ENABLED)
+ 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;
+
+ /*
+ * TODO: b:129990370
+ * Bit 2: ACTIVE_CABLE
+ * 0 - Passive
+ * 1 -TBT Active cable
+ */
+
+ /*
+ * 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 7: USB_DATA_ROLE (ignored if BIT5=0)
+ * 0 - DFP
+ * 1 - UPF
+ */
+ if (pd_is_ufp(port))
+ set_retimer_con |= BB_RETIMER_USB_DATA_ROLE;
+ }
+
+ /*
+ * 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 10-11: 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 = board_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 12: DEBUG_ACCESSORY_MODE
+ * 0 - Not in debug mode
+ * 1 - In debug accessory mode
+ */
+ if (pd_is_debug_acc(port))
+ set_retimer_con |= BB_RETIMER_DEBUG_ACCESSORY_MODE;
+
+ /* Writing the register4 */
+ return bb_retimer_write(port, BB_RETIMER_REG_CONNECTION_STATE,
+ set_retimer_con);
+}
+
+int retimer_low_power_mode(int port)
+{
+ bb_retimer_power_handle(port, 0);
+ return EC_SUCCESS;
+}
+
+int retimer_init(int port)
+{
+ int rv;
+ uint32_t data;
+
+ bb_retimer_power_handle(port, 1);
+
+ rv = bb_retimer_read(port, BB_RETIMER_REG_VENDOR_ID, &data);
+ if (rv)
+ return rv;
+ if (data != BB_RETIMER_VENDOR_ID)
+ return EC_ERROR_UNKNOWN;
+
+ rv = bb_retimer_read(port, BB_RETIMER_REG_DEVICE_ID, &data);
+ if (rv)
+ return rv;
+
+ if (data != BB_RETIMER_DEVICE_ID)
+ return EC_ERROR_UNKNOWN;
+
+ return EC_SUCCESS;
+}
+
+#ifdef CONFIG_CMD_RETIMER
+static int console_command_bb_retimer(int argc, char **argv)
+{
+ char rw, *e;
+ int rv, port, reg, data, val;
+
+ if (argc < 4)
+ return EC_ERROR_PARAM_COUNT;
+
+ /* Get port number */
+ port = strtoi(argv[1], &e, 0);
+ if (*e || port < 0 || port > CONFIG_USB_PD_PORT_COUNT)
+ 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;
+
+ if (rw == 'r')
+ rv = bb_retimer_read(port, reg, &data);
+ else {
+ /* Get value to be written */
+ val = strtoi(argv[4], &e, 0);
+ if (*e || val < 0)
+ return EC_ERROR_PARAM4;
+
+ rv = bb_retimer_write(port, reg, val);
+ if (rv == EC_SUCCESS) {
+ rv = bb_retimer_read(port, reg, &data);
+ if (rv == EC_SUCCESS && data != val)
+ rv = EC_ERROR_UNKNOWN;
+ }
+ }
+
+ if (rv == EC_SUCCESS)
+ CPRINTS("register 0x%x [%d] = 0x%x [%d]", reg, reg, data, 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 */
diff --git a/driver/retimer/bb_retimer.h b/driver/retimer/bb_retimer.h
new file mode 100644
index 0000000000..faecfef4ba
--- /dev/null
+++ b/driver/retimer/bb_retimer.h
@@ -0,0 +1,56 @@
+/* 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 header for Intel Burnside Bridge - Thunderbolt/USB/DisplayPort Retimer
+ */
+
+#ifndef __CROS_EC_BB_RETIMER_H
+#define __CROS_EC_BB_RETIMER_H
+
+#include "gpio.h"
+
+/* Burnside Bridge I2C Configuration Space */
+#define BB_RETIMER_REG_VENDOR_ID 0
+#define BB_RETIMER_VENDOR_ID 0x8086
+
+#define BB_RETIMER_REG_DEVICE_ID 1
+#define BB_RETIMER_DEVICE_ID 0x15EE
+
+/* Connection State Register Attributes */
+#define BB_RETIMER_REG_CONNECTION_STATE 4
+#define BB_RETIMER_DATA_CONNECTION_PRESENT BIT(0)
+#define BB_RETIMER_CONNECTION_ORIENTATION BIT(1)
+#define BB_RETIMER_ACTIVE_CABLE BIT(2)
+#define BB_RETIMER_USB_3_CONNECTION BIT(5)
+#define BB_RETIMER_USB_DATA_ROLE BIT(7)
+#define BB_RETIMER_DP_CONNECTION BIT(8)
+#define BB_RETIMER_DP_PIN_ASSIGNMENT BIT(10)
+#define BB_RETIMER_DEBUG_ACCESSORY_MODE BIT(12)
+#define BB_RETIMER_IRQ_HPD BIT(14)
+#define BB_RETIMER_HPD_LVL BIT(15)
+
+/* Describes a USB Retimer present in the system */
+struct bb_retimer {
+ /* USB Retimer I2C port */
+ const int i2c_port;
+
+ /* USB Retimer I2C address */
+ const int i2c_addr;
+
+ /* NVM flag if shared with multiple BB-retimers */
+ uint8_t shared_nvm;
+
+ /* Retimer control GPIOs */
+ enum gpio_signal usb_ls_en_gpio; /* Load switch enable */
+ enum gpio_signal retimer_rst_gpio; /* Retimer reset */
+ enum gpio_signal force_power_gpio; /* Force power (active/low) */
+};
+
+/*
+ * USB Retimers in system, ordered by PD port #, defined at board-level
+ * CONFIG_USB_PD_RETIMER_INTEL_BB need to be defind at board-level.
+ */
+extern struct bb_retimer bb_retimers[];
+
+#endif /* __CROS_EC_BB_RETIMER_H */
diff --git a/driver/usb_mux_virtual.c b/driver/usb_mux_virtual.c
index b82cdf307a..e20e0a2ef7 100644
--- a/driver/usb_mux_virtual.c
+++ b/driver/usb_mux_virtual.c
@@ -9,6 +9,7 @@
#include "console.h"
#include "host_command.h"
#include "usb_mux.h"
+#include "usb_retimer.h"
#include "util.h"
/*
@@ -26,13 +27,21 @@ static inline void virtual_mux_update_state(int port, mux_state_t mux_state)
{
if (virtual_mux_state[port] != mux_state) {
virtual_mux_state[port] = mux_state;
+#ifdef CONFIG_USB_PD_RETIMER
+ if (retimer_set_state(port, mux_state))
+ return;
+#endif
host_set_single_event(EC_HOST_EVENT_USB_MUX);
}
}
static int virtual_init(int port)
{
+#ifdef CONFIG_USB_PD_RETIMER
+ return retimer_init(port);
+#else
return EC_SUCCESS;
+#endif
}
/*
@@ -76,4 +85,7 @@ const struct usb_mux_driver virtual_usb_mux_driver = {
.init = virtual_init,
.set = virtual_set_mux,
.get = virtual_get_mux,
+#ifdef CONFIG_USB_PD_RETIMER
+ .enter_low_power_mode = retimer_low_power_mode,
+#endif
};