summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--baseboard/intelrvp/adlrvp.c3
-rw-r--r--board/boldar/board.c3
-rw-r--r--board/copano/board.c3
-rw-r--r--board/drobit/board.c3
-rw-r--r--board/halvor/board.c2
-rw-r--r--board/lingcod/board.c2
-rw-r--r--board/malefor/board.c2
-rw-r--r--board/terrador/board.c3
-rw-r--r--board/tglrvpu_ite/board.c2
-rw-r--r--board/todor/board.c3
-rw-r--r--board/trondo/board.c3
-rw-r--r--board/volteer/board.c3
-rw-r--r--board/voxel/board.c3
-rw-r--r--driver/retimer/bb_retimer.c2
-rw-r--r--include/driver/retimer/bb_retimer.h (renamed from driver/retimer/bb_retimer.h)5
-rw-r--r--zephyr/dts/bindings/emul/cros,bb-retimer-emul.yaml30
-rw-r--r--zephyr/emul/CMakeLists.txt1
-rw-r--r--zephyr/emul/Kconfig9
-rw-r--r--zephyr/emul/emul_bb_retimer.c549
-rw-r--r--zephyr/include/emul/emul_bb_retimer.h188
20 files changed, 797 insertions, 22 deletions
diff --git a/baseboard/intelrvp/adlrvp.c b/baseboard/intelrvp/adlrvp.c
index ad7066fe5d..3bc70ac581 100644
--- a/baseboard/intelrvp/adlrvp.c
+++ b/baseboard/intelrvp/adlrvp.c
@@ -5,9 +5,9 @@
/* Intel ADLRVP board-specific common configuration */
-#include "bb_retimer.h"
#include "charger.h"
#include "common.h"
+#include "driver/retimer/bb_retimer_public.h"
#include "hooks.h"
#include "ioexpander.h"
#include "isl9241.h"
@@ -16,6 +16,7 @@
#include "sn5s330.h"
#include "system.h"
#include "task.h"
+#include "usb_mux.h"
#include "usbc_ppc.h"
#include "util.h"
diff --git a/board/boldar/board.c b/board/boldar/board.c
index 59b7166123..abc3fecfe0 100644
--- a/board/boldar/board.c
+++ b/board/boldar/board.c
@@ -4,7 +4,6 @@
*/
/* Volteer board-specific configuration */
-#include "bb_retimer.h"
#include "button.h"
#include "common.h"
#include "accelgyro.h"
@@ -15,7 +14,7 @@
#include "driver/bc12/pi3usb9201.h"
#include "driver/ppc/sn5s330.h"
#include "driver/ppc/syv682x.h"
-#include "driver/retimer/bb_retimer.h"
+#include "driver/retimer/bb_retimer_public.h"
#include "driver/sync.h"
#include "driver/tcpm/ps8xxx.h"
#include "driver/tcpm/rt1715.h"
diff --git a/board/copano/board.c b/board/copano/board.c
index 23395b0a61..6992731208 100644
--- a/board/copano/board.c
+++ b/board/copano/board.c
@@ -4,7 +4,6 @@
*/
/* Volteer board-specific configuration */
-#include "bb_retimer.h"
#include "button.h"
#include "common.h"
#include "accelgyro.h"
@@ -15,7 +14,7 @@
#include "driver/ppc/syv682x.h"
#include "driver/tcpm/tcpci.h"
#include "driver/tcpm/rt1715.h"
-#include "driver/retimer/bb_retimer.h"
+#include "driver/retimer/bb_retimer_public.h"
#include "driver/sync.h"
#include "extpower.h"
#include "fan.h"
diff --git a/board/drobit/board.c b/board/drobit/board.c
index 3fb336976c..56d8f3f4a7 100644
--- a/board/drobit/board.c
+++ b/board/drobit/board.c
@@ -4,7 +4,6 @@
*/
/* Volteer board-specific configuration */
-#include "bb_retimer.h"
#include "button.h"
#include "common.h"
#include "accelgyro.h"
@@ -12,7 +11,7 @@
#include "charge_state_v2.h"
#include "driver/bc12/pi3usb9201.h"
#include "driver/ppc/syv682x.h"
-#include "driver/retimer/bb_retimer.h"
+#include "driver/retimer/bb_retimer_public.h"
#include "driver/sync.h"
#include "driver/tcpm/rt1715.h"
#include "driver/tcpm/tcpci.h"
diff --git a/board/halvor/board.c b/board/halvor/board.c
index 078d0520f6..31b68906d4 100644
--- a/board/halvor/board.c
+++ b/board/halvor/board.c
@@ -6,7 +6,6 @@
/* Volteer board-specific configuration */
#include "accelgyro.h"
#include "assert.h"
-#include "bb_retimer.h"
#include "button.h"
#include "common.h"
#include "cbi_ec_fw_config.h"
@@ -14,6 +13,7 @@
#include "driver/als_tcs3400.h"
#include "driver/bc12/pi3usb9201.h"
#include "driver/ppc/syv682x.h"
+#include "driver/retimer/bb_retimer_public.h"
#include "driver/sync.h"
#include "driver/tcpm/tcpci.h"
#include "driver/tcpm/tusb422.h"
diff --git a/board/lingcod/board.c b/board/lingcod/board.c
index feeed33119..5b810c9795 100644
--- a/board/lingcod/board.c
+++ b/board/lingcod/board.c
@@ -4,7 +4,6 @@
*/
/* Malefor board-specific configuration */
-#include "bb_retimer.h"
#include "button.h"
#include "cbi_ec_fw_config.h"
#include "common.h"
@@ -15,6 +14,7 @@
#include "driver/ppc/syv682x.h"
#include "driver/tcpm/tcpci.h"
#include "driver/tcpm/tusb422.h"
+#include "driver/retimer/bb_retimer_public.h"
#include "driver/sync.h"
#include "extpower.h"
#include "fan.h"
diff --git a/board/malefor/board.c b/board/malefor/board.c
index 2dd92fabec..c584969b81 100644
--- a/board/malefor/board.c
+++ b/board/malefor/board.c
@@ -4,7 +4,6 @@
*/
/* Malefor board-specific configuration */
-#include "bb_retimer.h"
#include "button.h"
#include "cbi_ec_fw_config.h"
#include "common.h"
@@ -13,6 +12,7 @@
#include "driver/bc12/pi3usb9201.h"
#include "driver/ppc/sn5s330.h"
#include "driver/ppc/syv682x.h"
+#include "driver/retimer/bb_retimer_public.h"
#include "driver/sync.h"
#include "driver/tcpm/ps8xxx.h"
#include "driver/tcpm/tcpci.h"
diff --git a/board/terrador/board.c b/board/terrador/board.c
index e13b376c3f..a0ea2e6918 100644
--- a/board/terrador/board.c
+++ b/board/terrador/board.c
@@ -4,7 +4,6 @@
*/
/* Volteer board-specific configuration */
-#include "bb_retimer.h"
#include "button.h"
#include "common.h"
#include "accelgyro.h"
@@ -16,7 +15,7 @@
#include "driver/ppc/syv682x.h"
#include "driver/tcpm/tcpci.h"
#include "driver/tcpm/tusb422.h"
-#include "driver/retimer/bb_retimer.h"
+#include "driver/retimer/bb_retimer_public.h"
#include "driver/sync.h"
#include "extpower.h"
#include "fan.h"
diff --git a/board/tglrvpu_ite/board.c b/board/tglrvpu_ite/board.c
index c81e66b78f..def69448ad 100644
--- a/board/tglrvpu_ite/board.c
+++ b/board/tglrvpu_ite/board.c
@@ -5,10 +5,10 @@
/* Intel TGL-U-RVP-ITE board-specific configuration */
-#include "bb_retimer.h"
#include "button.h"
#include "charger.h"
#include "driver/charger/isl9241.h"
+#include "driver/retimer/bb_retimer_public.h"
#include "extpower.h"
#include "i2c.h"
#include "intc.h"
diff --git a/board/todor/board.c b/board/todor/board.c
index 06c030dea6..9dbfbfd2ee 100644
--- a/board/todor/board.c
+++ b/board/todor/board.c
@@ -4,7 +4,6 @@
*/
/* Volteer board-specific configuration */
-#include "bb_retimer.h"
#include "button.h"
#include "common.h"
#include "accelgyro.h"
@@ -16,7 +15,7 @@
#include "driver/ppc/syv682x.h"
#include "driver/tcpm/tcpci.h"
#include "driver/tcpm/tusb422.h"
-#include "driver/retimer/bb_retimer.h"
+#include "driver/retimer/bb_retimer_public.h"
#include "driver/sync.h"
#include "extpower.h"
#include "fan.h"
diff --git a/board/trondo/board.c b/board/trondo/board.c
index d6e68b35a7..10e346da5c 100644
--- a/board/trondo/board.c
+++ b/board/trondo/board.c
@@ -4,7 +4,6 @@
*/
/* Volteer board-specific configuration */
-#include "bb_retimer.h"
#include "button.h"
#include "common.h"
#include "accelgyro.h"
@@ -17,7 +16,7 @@
#include "driver/ppc/syv682x.h"
#include "driver/tcpm/tcpci.h"
#include "driver/tcpm/tusb422.h"
-#include "driver/retimer/bb_retimer.h"
+#include "driver/retimer/bb_retimer_public.h"
#include "driver/sync.h"
#include "extpower.h"
#include "fan.h"
diff --git a/board/volteer/board.c b/board/volteer/board.c
index 1112b4b4f3..8c1be1bf64 100644
--- a/board/volteer/board.c
+++ b/board/volteer/board.c
@@ -4,7 +4,6 @@
*/
/* Volteer board-specific configuration */
-#include "bb_retimer.h"
#include "button.h"
#include "common.h"
#include "accelgyro.h"
@@ -12,7 +11,7 @@
#include "driver/accel_bma2x2.h"
#include "driver/accelgyro_bmi260.h"
#include "driver/als_tcs3400.h"
-#include "driver/retimer/bb_retimer.h"
+#include "driver/retimer/bb_retimer_public.h"
#include "driver/sync.h"
#include "driver/tcpm/ps8xxx.h"
#include "extpower.h"
diff --git a/board/voxel/board.c b/board/voxel/board.c
index 2c7f7feac5..c13686d3b4 100644
--- a/board/voxel/board.c
+++ b/board/voxel/board.c
@@ -4,7 +4,6 @@
*/
/* Volteer board-specific configuration */
-#include "bb_retimer.h"
#include "button.h"
#include "common.h"
#include "accelgyro.h"
@@ -17,7 +16,7 @@
#include "driver/tcpm/tcpci.h"
#include "driver/tcpm/tusb422.h"
#include "driver/tcpm/rt1715.h"
-#include "driver/retimer/bb_retimer.h"
+#include "driver/retimer/bb_retimer_public.h"
#include "driver/sync.h"
#include "extpower.h"
#include "fan.h"
diff --git a/driver/retimer/bb_retimer.c b/driver/retimer/bb_retimer.c
index 75da6c653d..319c965228 100644
--- a/driver/retimer/bb_retimer.c
+++ b/driver/retimer/bb_retimer.c
@@ -5,7 +5,7 @@
* Driver for Intel Burnside Bridge - Thunderbolt/USB/DisplayPort Retimer
*/
-#include "bb_retimer.h"
+#include "driver/retimer/bb_retimer.h"
#include "chipset.h"
#include "common.h"
#include "console.h"
diff --git a/driver/retimer/bb_retimer.h b/include/driver/retimer/bb_retimer.h
index ddbdec0986..35b2352704 100644
--- a/driver/retimer/bb_retimer.h
+++ b/include/driver/retimer/bb_retimer.h
@@ -43,4 +43,9 @@
#define BB_RETIMER_USB4_TBT_CABLE_SPEED_SUPPORT(x) (((x) & 0x7) << 25)
#define BB_RETIMER_TBT_CABLE_GENERATION(x) (((x) & 0x3) << 28)
+#define BB_RETIMER_REG_TBT_CONTROL 5
+#define BB_RETIMER_REG_EXT_CONNECTION_MODE 6
+
+#define BB_RETIMER_REG_COUNT 7
+
#endif /* __CROS_EC_BB_RETIMER_H */
diff --git a/zephyr/dts/bindings/emul/cros,bb-retimer-emul.yaml b/zephyr/dts/bindings/emul/cros,bb-retimer-emul.yaml
new file mode 100644
index 0000000000..007a73b17b
--- /dev/null
+++ b/zephyr/dts/bindings/emul/cros,bb-retimer-emul.yaml
@@ -0,0 +1,30 @@
+# Copyright 2021 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.
+
+description: Zephyr BB retimer Emulator
+
+compatible: "cros,bb-retimer-emul"
+
+include: base.yaml
+
+properties:
+ vendor:
+ type: string
+ required: true
+ enum:
+ - BB_RETIMER_VENDOR_ID_1
+ - BB_RETIMER_VENDOR_ID_2
+ description: Vendor ID used by device that is emulated.
+
+ error-on-ro-write:
+ type: boolean
+ description:
+ Flag indicating if error should be generated when read only register
+ is being written.
+
+ error-on-reserved-bit-write:
+ type: boolean
+ description:
+ Flag indicating if error should be generated when reserved bit
+ is being written.
diff --git a/zephyr/emul/CMakeLists.txt b/zephyr/emul/CMakeLists.txt
index 500d1e8b2f..bd1d749267 100644
--- a/zephyr/emul/CMakeLists.txt
+++ b/zephyr/emul/CMakeLists.txt
@@ -10,3 +10,4 @@ zephyr_library_sources_ifdef(CONFIG_EMUL_BMI emul_bmi.c)
zephyr_library_sources_ifdef(CONFIG_EMUL_BMI emul_bmi160.c)
zephyr_library_sources_ifdef(CONFIG_EMUL_BMI emul_bmi260.c)
zephyr_library_sources_ifdef(CONFIG_EMUL_TCS3400 emul_tcs3400.c)
+zephyr_library_sources_ifdef(CONFIG_EMUL_BB_RETIMER emul_bb_retimer.c)
diff --git a/zephyr/emul/Kconfig b/zephyr/emul/Kconfig
index b4461213be..346d419862 100644
--- a/zephyr/emul/Kconfig
+++ b/zephyr/emul/Kconfig
@@ -27,6 +27,7 @@ config EMUL_PPC_SYV682X
help
Enable the SYV682x emulator. SYV682 is a USB Type-C PPC. This driver
uses the emulated I2C bus.
+
config EMUL_BMI
bool "BMI emulator"
help
@@ -45,3 +46,11 @@ config EMUL_TCS3400
TCS3400 registers support read and write with optional checking
of proper access to reserved bits. Emulators API is available in
zephyr/include/emul/emul_tcs3400.h
+
+config EMUL_BB_RETIMER
+ bool "BB retimer emulator"
+ help
+ Enable the BB (Burnside Bridge) retimer emulator. This driver use
+ emulated I2C bus. It is used to test bb_retimer driver. It supports
+ reads and writes to all emulator registers. Emulators API is
+ available in zephyr/include/emul/emul_bb_retimer.h
diff --git a/zephyr/emul/emul_bb_retimer.c b/zephyr/emul/emul_bb_retimer.c
new file mode 100644
index 0000000000..e016cf709e
--- /dev/null
+++ b/zephyr/emul/emul_bb_retimer.c
@@ -0,0 +1,549 @@
+/* Copyright 2021 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.
+ */
+
+#define DT_DRV_COMPAT cros_bb_retimer_emul
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <logging/log.h>
+LOG_MODULE_REGISTER(emul_bb_retimer);
+
+#include <device.h>
+#include <emul.h>
+#include <drivers/i2c.h>
+#include <drivers/i2c_emul.h>
+
+#include "emul/emul_bb_retimer.h"
+
+#include "driver/retimer/bb_retimer.h"
+
+/**
+ * Describe if there is no ongoing I2C message or if there is message handled
+ * at the moment (last message doesn't ended with stop or write is not followed
+ * by read).
+ */
+enum bb_emul_msg_state {
+ BB_EMUL_NONE_MSG,
+ BB_EMUL_IN_WRITE,
+ BB_EMUL_IN_READ
+};
+
+/** Run-time data used by the emulator */
+struct bb_emul_data {
+ /** I2C emulator detail */
+ struct i2c_emul emul;
+ /** BB retimer device being emulated */
+ const struct device *i2c;
+ /** Configuration information */
+ const struct bb_emul_cfg *cfg;
+
+ /** Current state of all emulated BB retimer registers */
+ uint32_t reg[BB_RETIMER_REG_COUNT];
+
+ /** Vendor ID of emulated device */
+ uint32_t vendor_id;
+
+ /** Return error when trying to write to RO register */
+ bool error_on_ro_write;
+ /** Return error when trying to write 1 to reserved bit */
+ bool error_on_rsvd_write;
+
+ /** Current state of I2C bus (if emulator is handling message) */
+ enum bb_emul_msg_state msg_state;
+ /** Number of already handled bytes in ongoing message */
+ int msg_byte;
+ /** Register selected in last write command */
+ uint8_t cur_reg;
+ /** Value of data dword in ongoing i2c message */
+ uint32_t data_dword;
+
+ /** Custom write function called on I2C write opperation */
+ bb_emul_write_func write_func;
+ /** Data passed to custom write function */
+ void *write_func_data;
+ /** Custom read function called on I2C read opperation */
+ bb_emul_read_func read_func;
+ /** Data passed to custom read function */
+ void *read_func_data;
+
+ /** Control if read should fail on given register */
+ int read_fail_reg;
+ /** Control if write should fail on given register */
+ int write_fail_reg;
+
+ /** Mutex used to control access to emulator data */
+ struct k_mutex data_mtx;
+};
+
+/** Static configuration for the emulator */
+struct bb_emul_cfg {
+ /** Label of the I2C bus this emulator connects to */
+ const char *i2c_label;
+ /** Pointer to run-time data */
+ struct bb_emul_data *data;
+ /** Address of BB retimer on i2c bus */
+ uint16_t addr;
+};
+
+/** Check description in emul_bb_retimer.h */
+int bb_emul_lock_data(struct i2c_emul *emul, k_timeout_t timeout)
+{
+ struct bb_emul_data *data;
+
+ data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+
+ return k_mutex_lock(&data->data_mtx, timeout);
+}
+
+/** Check description in emul_bb_retimer.h */
+int bb_emul_unlock_data(struct i2c_emul *emul)
+{
+ struct bb_emul_data *data;
+
+ data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+
+ return k_mutex_unlock(&data->data_mtx);
+}
+
+/** Check description in emul_bb_retimer.h */
+void bb_emul_set_write_func(struct i2c_emul *emul,
+ bb_emul_write_func func, void *data)
+{
+ struct bb_emul_data *emul_data;
+
+ emul_data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+ emul_data->write_func = func;
+ emul_data->write_func_data = data;
+}
+
+/** Check description in emul_bb_retimer.h */
+void bb_emul_set_read_func(struct i2c_emul *emul,
+ bb_emul_read_func func, void *data)
+{
+ struct bb_emul_data *emul_data;
+
+ emul_data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+ emul_data->read_func = func;
+ emul_data->read_func_data = data;
+}
+
+/** Check description in emul_bb_retimer.h */
+void bb_emul_set_reg(struct i2c_emul *emul, int reg, uint32_t val)
+{
+ struct bb_emul_data *data;
+
+ if (reg < 0 || reg > BB_RETIMER_REG_COUNT) {
+ return;
+ }
+
+ data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+ data->reg[reg] = val;
+}
+
+/** Check description in emul_bb_retimer.h */
+uint32_t bb_emul_get_reg(struct i2c_emul *emul, int reg)
+{
+ struct bb_emul_data *data;
+
+ if (reg < 0 || reg > BB_RETIMER_REG_COUNT) {
+ return 0;
+ }
+
+ data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+
+ return data->reg[reg];
+}
+
+/** Check description in emul_bb_retimer.h */
+void bb_emul_set_read_fail_reg(struct i2c_emul *emul, int reg)
+{
+ struct bb_emul_data *data;
+
+ data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+ data->read_fail_reg = reg;
+}
+
+/** Check description in emul_bb_retimer.h */
+void bb_emul_set_write_fail_reg(struct i2c_emul *emul, int reg)
+{
+ struct bb_emul_data *data;
+
+ data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+ data->write_fail_reg = reg;
+}
+
+/** Check description in emul_bb_retimer.h */
+void bb_emul_set_err_on_ro_write(struct i2c_emul *emul, bool set)
+{
+ struct bb_emul_data *data;
+
+ data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+ data->error_on_ro_write = set;
+}
+
+/** Check description in emul_bb_retimer.h */
+void bb_emul_set_err_on_rsvd_write(struct i2c_emul *emul, bool set)
+{
+ struct bb_emul_data *data;
+
+ data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+ data->error_on_rsvd_write = set;
+}
+
+/** Mask reserved bits in each register of BB retimer */
+static const uint32_t bb_emul_rsvd_mask[] = {
+ [BB_RETIMER_REG_VENDOR_ID] = 0x00000000,
+ [BB_RETIMER_REG_DEVICE_ID] = 0x00000000,
+ [0x02] = 0xffffffff, /* Reserved */
+ [0x03] = 0xffffffff, /* Reserved */
+ [BB_RETIMER_REG_CONNECTION_STATE] = 0xc0201000,
+ [BB_RETIMER_REG_TBT_CONTROL] = 0xffffdfff,
+ [0x06] = 0xffffffff, /* Reserved */
+ [BB_RETIMER_REG_EXT_CONNECTION_MODE] = 0x08007f00,
+};
+
+/**
+ * @brief Reset registers to default values
+ *
+ * @param emul Pointer to BB retimer emulator
+ */
+static void bb_emul_reset(struct i2c_emul *emul)
+{
+ struct bb_emul_data *data;
+
+ data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+
+ data->reg[BB_RETIMER_REG_VENDOR_ID] = data->vendor_id;
+ data->reg[BB_RETIMER_REG_DEVICE_ID] = BB_RETIMER_DEVICE_ID;
+ data->reg[0x02] = 0x00; /* Reserved */
+ data->reg[0x03] = 0x00; /* Reserved */
+ data->reg[BB_RETIMER_REG_CONNECTION_STATE] = 0x00;
+ data->reg[BB_RETIMER_REG_TBT_CONTROL] = 0x00;
+ data->reg[0x06] = 0x00; /* Reserved */
+ data->reg[BB_RETIMER_REG_EXT_CONNECTION_MODE] = 0x00;
+}
+
+/**
+ * @brief Handle I2C write message. It is checked if accessed register isn't RO
+ * and reserved bits are set to 0. Write set value of reg field of BB
+ * retimer emulator data ignoring reserved bits and write only bits. Some
+ * commands are handled specialy. Before any handling, custom function
+ * is called if provided.
+ *
+ * @param emul Pointer to BB retimer emulator
+ * @param reg Register which is written
+ * @param val Value being written to @p reg
+ * @param msg_len Length of handled I2C message
+ *
+ * @return 0 on success
+ * @return -EIO on error
+ */
+static int bb_emul_handle_write(struct i2c_emul *emul, int reg, uint32_t val,
+ int msg_len)
+{
+ struct bb_emul_data *data;
+ int ret;
+
+ data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+
+ /*
+ * BB retimer ignores data bytes above 4 and use zeros if there is less
+ * then 4 data bytes. Emulator prints warning in that case.
+ */
+ if (msg_len != 6) {
+ LOG_WRN("Got %d bytes of WR data, expected 4", msg_len - 2);
+ }
+
+ if (data->write_func) {
+ ret = data->write_func(emul, reg, val, data->write_func_data);
+ if (ret < 0) {
+ return -EIO;
+ } else if (ret == 0) {
+ return 0;
+ }
+ }
+
+ if (data->write_fail_reg == reg ||
+ data->write_fail_reg == BB_EMUL_FAIL_ALL_REG) {
+ return -EIO;
+ }
+
+ if (reg <= BB_RETIMER_REG_DEVICE_ID ||
+ reg >= BB_RETIMER_REG_COUNT ||
+ reg == BB_RETIMER_REG_TBT_CONTROL) {
+ if (data->error_on_ro_write) {
+ LOG_ERR("Writing to reg 0x%x which is RO", reg);
+ return -EIO;
+ }
+
+ return 0;
+ }
+
+ if (data->error_on_rsvd_write && bb_emul_rsvd_mask[reg] & val) {
+ LOG_ERR("Writing 0x%x to reg 0x%x with rsvd bits mask 0x%x",
+ val, reg, bb_emul_rsvd_mask[reg]);
+ return -EIO;
+ }
+
+ /* Ignore all reserved bits */
+ val &= ~bb_emul_rsvd_mask[reg];
+ val |= data->reg[reg] & bb_emul_rsvd_mask[reg];
+
+ data->reg[reg] = val;
+
+ return 0;
+}
+
+/**
+ * @brief Handle I2C read message. Response is obtained from reg field of bb
+ * emul data. When accessing accelerometer value, register data is first
+ * computed using internal emulator state. Before default handler, custom
+ * user read function is called if provided.
+ *
+ * @param emul Pointer to BB retimer emulator
+ * @param reg Register address to read
+ * @param buf Pointer where result should be stored
+ *
+ * @return 0 on success
+ * @return -EIO on error
+ */
+static int bb_emul_handle_read(struct i2c_emul *emul, int reg, uint32_t *buf)
+{
+ struct bb_emul_data *data;
+ int ret;
+
+ data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+
+ if (data->read_func) {
+ ret = data->read_func(emul, reg, data->read_func_data);
+ if (ret < 0) {
+ return -EIO;
+ } else if (ret == 0) {
+ /* Immediately return value set by custom function */
+ *buf = data->reg[reg];
+
+ return 0;
+ }
+ }
+
+ if (data->read_fail_reg == reg ||
+ data->read_fail_reg == BB_EMUL_FAIL_ALL_REG) {
+ return -EIO;
+ }
+
+ if (reg >= BB_RETIMER_REG_COUNT) {
+ LOG_ERR("Read unknown register 0x%x", reg);
+
+ return -EIO;
+ }
+
+ *buf = data->reg[reg];
+
+ return 0;
+}
+
+/**
+ * @biref Emulate an I2C transfer to a BB retimer
+ *
+ * This handles simple reads and writes
+ *
+ * @param emul I2C emulation information
+ * @param msgs List of messages to process
+ * @param num_msgs Number of messages to process
+ * @param addr Address of the I2C target device
+ *
+ * @retval 0 If successful
+ * @retval -EIO General input / output error
+ */
+static int bb_emul_transfer(struct i2c_emul *emul, struct i2c_msg *msgs,
+ int num_msgs, int addr)
+{
+ const struct bb_emul_cfg *cfg;
+ struct bb_emul_data *data;
+ int ret, i;
+ bool read;
+
+ data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+ cfg = data->cfg;
+
+ if (cfg->addr != addr) {
+ LOG_ERR("Address mismatch, expected %02x, got %02x", cfg->addr,
+ addr);
+ return -EIO;
+ }
+
+ i2c_dump_msgs("emul", msgs, num_msgs, addr);
+
+ for (; num_msgs > 0; num_msgs--, msgs++) {
+ read = msgs->flags & I2C_MSG_READ;
+
+ switch (data->msg_state) {
+ case BB_EMUL_NONE_MSG:
+ data->data_dword = 0;
+ data->msg_byte = 0;
+ break;
+ case BB_EMUL_IN_WRITE:
+ if (read) {
+ /* Finish write command */
+ if (data->msg_byte >= 2) {
+ k_mutex_lock(&data->data_mtx,
+ K_FOREVER);
+ ret = bb_emul_handle_write(emul,
+ data->cur_reg,
+ data->data_dword,
+ data->msg_byte);
+ k_mutex_unlock(&data->data_mtx);
+ if (ret) {
+ return -EIO;
+ }
+ }
+ data->data_dword = 0;
+ data->msg_byte = 0;
+ }
+ break;
+ case BB_EMUL_IN_READ:
+ if (!read) {
+ data->data_dword = 0;
+ data->msg_byte = 0;
+ }
+ break;
+ }
+ data->msg_state = read ? BB_EMUL_IN_READ : BB_EMUL_IN_WRITE;
+
+ if (msgs->flags & I2C_MSG_STOP) {
+ data->msg_state = BB_EMUL_NONE_MSG;
+ }
+
+ if (!read) {
+ /* Dispatch wrtie command */
+ for (i = 0; i < msgs->len; i++) {
+ switch (data->msg_byte) {
+ case 0:
+ data->cur_reg = msgs->buf[i];
+ break;
+ case 1:
+ /*
+ * BB retimer ignores size, but it
+ * should be 4, so emulator check this.
+ */
+ if (msgs->buf[i] != 4) {
+ LOG_WRN("Invalid write size");
+ }
+ break;
+ default:
+ data->data_dword |=
+ (msgs->buf[i] & 0xff) <<
+ (8 * (data->msg_byte - 2));
+ }
+ data->msg_byte++;
+ }
+
+ /* Execute write command */
+ if (msgs->flags & I2C_MSG_STOP && data->msg_byte >= 2) {
+ k_mutex_lock(&data->data_mtx, K_FOREVER);
+ ret = bb_emul_handle_write(emul, data->cur_reg,
+ data->data_dword,
+ data->msg_byte);
+ k_mutex_unlock(&data->data_mtx);
+ if (ret) {
+ return -EIO;
+ }
+ }
+ } else {
+ /* Prepare response */
+ if (data->msg_byte == 0) {
+ k_mutex_lock(&data->data_mtx, K_FOREVER);
+ ret = bb_emul_handle_read(emul, data->cur_reg,
+ &data->data_dword);
+ k_mutex_unlock(&data->data_mtx);
+ if (ret) {
+ return -EIO;
+ }
+ }
+
+ for (i = 0; i < msgs->len; i++) {
+ msgs->buf[i] = data->data_dword & 0xff;
+ data->data_dword >>= 8;
+
+ data->msg_byte++;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Device instantiation */
+
+static struct i2c_emul_api bb_emul_api = {
+ .transfer = bb_emul_transfer,
+};
+
+/**
+ * @brief Set up a new BB retimer emulator
+ *
+ * This should be called for each BB retimer device that needs to be
+ * emulated. It registers it with the I2C emulation controller.
+ *
+ * @param emul Emulation information
+ * @param parent Device to emulate
+ *
+ * @return 0 indicating success (always)
+ */
+static int bb_emul_init(const struct emul *emul,
+ const struct device *parent)
+{
+ const struct bb_emul_cfg *cfg = emul->cfg;
+ struct bb_emul_data *data = cfg->data;
+ int ret;
+
+ data->emul.api = &bb_emul_api;
+ data->emul.addr = cfg->addr;
+ data->i2c = parent;
+ data->cfg = cfg;
+ k_mutex_init(&data->data_mtx);
+
+ ret = i2c_emul_register(parent, emul->dev_label, &data->emul);
+
+ bb_emul_reset(&data->emul);
+
+ return ret;
+}
+
+#define BB_RETIMER_EMUL(n) \
+ static struct bb_emul_data bb_emul_data_##n = { \
+ .vendor_id = DT_ENUM_TOKEN(DT_DRV_INST(n), vendor), \
+ .error_on_ro_write = DT_INST_PROP(n, error_on_ro_write),\
+ .error_on_rsvd_write = DT_INST_PROP(n, \
+ error_on_reserved_bit_write), \
+ .msg_state = BB_EMUL_NONE_MSG, \
+ .cur_reg = 0, \
+ .write_func = NULL, \
+ .read_func = NULL, \
+ .write_fail_reg = BB_EMUL_NO_FAIL_REG, \
+ .read_fail_reg = BB_EMUL_NO_FAIL_REG, \
+ }; \
+ \
+ static const struct bb_emul_cfg bb_emul_cfg_##n = { \
+ .i2c_label = DT_INST_BUS_LABEL(n), \
+ .data = &bb_emul_data_##n, \
+ .addr = DT_INST_REG_ADDR(n), \
+ }; \
+ EMUL_DEFINE(bb_emul_init, DT_DRV_INST(n), &bb_emul_cfg_##n)
+
+DT_INST_FOREACH_STATUS_OKAY(BB_RETIMER_EMUL)
+
+#define BB_RETIMER_EMUL_CASE(n) \
+ case DT_INST_DEP_ORD(n): return &bb_emul_data_##n.emul;
+
+/** Check description in emul_bb_emulator.h */
+struct i2c_emul *bb_emul_get(int ord)
+{
+ switch (ord) {
+ DT_INST_FOREACH_STATUS_OKAY(BB_RETIMER_EMUL_CASE)
+
+ default:
+ return NULL;
+ }
+}
diff --git a/zephyr/include/emul/emul_bb_retimer.h b/zephyr/include/emul/emul_bb_retimer.h
new file mode 100644
index 0000000000..2820c59934
--- /dev/null
+++ b/zephyr/include/emul/emul_bb_retimer.h
@@ -0,0 +1,188 @@
+/* Copyright 2021 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.
+ */
+
+/**
+ * @file
+ *
+ * @brief Backend API for BB retimer emulator
+ */
+
+#ifndef __EMUL_BB_RETIMER_H
+#define __EMUL_BB_RETIMER_H
+
+#include <emul.h>
+#include <drivers/i2c.h>
+#include <drivers/i2c_emul.h>
+
+/**
+ * @brief BB retimer emulator backend API
+ * @defgroup bb_emul BB retimer emulator
+ * @{
+ *
+ * BB retimer emulator supports access to all its registers using I2C messages.
+ * It supports not four bytes writes by padding zeros (the same as real
+ * device), but show warning in that case.
+ * Application may alter emulator state:
+ *
+ * - define a Device Tree overlay file to set default vendor ID and which
+ * inadvisable driver behaviour should be treated as errors
+ * - call @ref bb_emul_set_read_func and @ref bb_emul_set_write_func to setup
+ * custom handlers for I2C messages
+ * - call @ref bb_emul_set_reg and @ref bb_emul_get_reg to set and get value
+ * of BB retimers registers
+ * - call bb_emul_set_err_* to change emulator behaviour on inadvisable driver
+ * behaviour
+ * - call @ref bb_emul_set_read_fail_reg and @ref bb_emul_set_write_fail_reg
+ * to configure emulator to fail on given register read or write
+ */
+
+/**
+ * Special register values used in @ref bb_emul_set_read_fail_reg and
+ * @ref bb_emul_set_write_fail_reg
+ */
+#define BB_EMUL_FAIL_ALL_REG (-1)
+#define BB_EMUL_NO_FAIL_REG (-2)
+
+/**
+ * @brief Get pointer to BB retimer emulator using device tree order number.
+ *
+ * @param ord Device tree order number obtained from DT_DEP_ORD macro
+ *
+ * @return Pointer to BB retimer emulator
+ */
+struct i2c_emul *bb_emul_get(int ord);
+
+/**
+ * @brief Custom function type that is used as user-defined callback in read
+ * I2C messages handling.
+ *
+ * @param emul Pointer to BB retimer emulator
+ * @param reg Address which is now accessed by read command
+ * @param data Pointer to custom user data
+ *
+ * @return 0 on success. Value of @p reg should be set by @ref bb_emul_set_reg
+ * @return 1 continue with normal BB retimer emulator handler
+ * @return negative on error
+ */
+typedef int (*bb_emul_read_func)(struct i2c_emul *emul, int reg, void *data);
+
+/**
+ * @brief Custom function type that is used as user-defined callback in write
+ * I2C messages handling.
+ *
+ * @param emul Pointer to BB retimer emulator
+ * @param reg Address which is now accessed by write command
+ * @param val Value which is being written to @p reg
+ * @param data Pointer to custom user data
+ *
+ * @return 0 on success
+ * @return 1 continue with normal BB retimer emulator handler
+ * @return negative on error
+ */
+typedef int (*bb_emul_write_func)(struct i2c_emul *emul, int reg, uint32_t val,
+ void *data);
+
+/**
+ * @brief Lock access to BB retimer properties. After acquiring lock, user
+ * may change emulator behaviour in multi-thread setup.
+ *
+ * @param emul Pointer to BB retimer emulator
+ * @param timeout Timeout in getting lock
+ *
+ * @return k_mutex_lock return code
+ */
+int bb_emul_lock_data(struct i2c_emul *emul, k_timeout_t timeout);
+
+/**
+ * @brief Unlock access to BB retimer properties.
+ *
+ * @param emul Pointer to BB retimer emulator
+ *
+ * @return k_mutex_unlock return code
+ */
+int bb_emul_unlock_data(struct i2c_emul *emul);
+
+/**
+ * @brief Set write handler for I2C messages. This function is called before
+ * generic handler.
+ *
+ * @param emul Pointer to BB retimer emulator
+ * @param func Pointer to custom function
+ * @param data User data passed on call of custom function
+ */
+void bb_emul_set_write_func(struct i2c_emul *emul, bb_emul_write_func func,
+ void *data);
+
+/**
+ * @brief Set read handler for I2C messages. This function is called before
+ * generic handler.
+ *
+ * @param emul Pointer to BB retimer emulator
+ * @param func Pointer to custom function
+ * @param data User data passed on call of custom function
+ */
+void bb_emul_set_read_func(struct i2c_emul *emul, bb_emul_read_func func,
+ void *data);
+
+/**
+ * @brief Set value of given register of BB retimer
+ *
+ * @param emul Pointer to BB retimer emulator
+ * @param reg Register address which value will be changed
+ * @param val New value of the register
+ */
+void bb_emul_set_reg(struct i2c_emul *emul, int reg, uint32_t val);
+
+/**
+ * @brief Get value of given register of BB retimer
+ *
+ * @param emul Pointer to BB retimer emulator
+ * @param reg Register address
+ *
+ * @return Value of the register
+ */
+uint32_t bb_emul_get_reg(struct i2c_emul *emul, int reg);
+
+/**
+ * @brief Setup fail on read of given register of BB retimer
+ *
+ * @param emul Pointer to BB retimer emulator
+ * @param reg Register address or one of special values (BB_EMUL_FAIL_ALL_REG,
+ * BB_EMUL_NO_FAIL_REG)
+ */
+void bb_emul_set_read_fail_reg(struct i2c_emul *emul, int reg);
+
+/**
+ * @brief Setup fail on write of given register of BB retimer
+ *
+ * @param emul Pointer to BB retimer emulator
+ * @param reg Register address or one of special values (BB_EMUL_FAIL_ALL_REG,
+ * BB_EMUL_NO_FAIL_REG)
+ */
+void bb_emul_set_write_fail_reg(struct i2c_emul *emul, int reg);
+
+/**
+ * @brief Set if error should be generated when read only register is being
+ * written
+ *
+ * @param emul Pointer to BB retimer emulator
+ * @param set Check for this error
+ */
+void bb_emul_set_err_on_ro_write(struct i2c_emul *emul, bool set);
+
+/**
+ * @brief Set if error should be generated when reserved bits of register are
+ * not set to 0 on write I2C message
+ *
+ * @param emul Pointer to BB retimer emulator
+ * @param set Check for this error
+ */
+void bb_emul_set_err_on_rsvd_write(struct i2c_emul *emul, bool set);
+
+/**
+ * @}
+ */
+
+#endif /* __EMUL_BB_RETIMER */