summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.toolchain11
-rw-r--r--OWNERS9
-rw-r--r--board/OWNERS2
-rw-r--r--board/aleena/board.h2
-rw-r--r--board/cheza/board.h1
-rw-r--r--board/elm/board.h1
-rw-r--r--board/jerry/board.h1
-rw-r--r--board/kukui/board.h1
-rw-r--r--board/meowth_fp/board.h1
-rw-r--r--board/nocturne/board.c20
-rw-r--r--board/nocturne/board.h1
-rw-r--r--board/npcx_evb_arm/board.h1
-rw-r--r--board/nucleo-f411re/board.c27
-rw-r--r--board/nucleo-f411re/board.h12
-rw-r--r--board/nucleo-f411re/ec.tasklist6
-rw-r--r--board/nucleo-f411re/gpio.inc3
-rw-r--r--board/oak/board.h1
-rw-r--r--board/rainier/board.h1
-rw-r--r--board/rammus/battery.c29
-rw-r--r--board/rammus/board.c115
-rw-r--r--board/rammus/board.h12
-rw-r--r--board/rammus/build.mk2
-rw-r--r--board/rammus/cbi_ssfc.c36
-rw-r--r--board/rammus/cbi_ssfc.h56
-rw-r--r--board/rammus/gpio.inc2
-rw-r--r--board/rowan/board.h1
-rw-r--r--board/scarlet/board.h1
-rw-r--r--chip/mec1322/hwtimer.c11
-rw-r--r--chip/npcx/hwtimer.c21
-rw-r--r--chip/npcx/system.c12
-rw-r--r--chip/stm32/gpio.c4
-rw-r--r--common/build.mk1
-rw-r--r--common/cbi.c34
-rw-r--r--common/charge_ramp.c32
-rw-r--r--common/crc.c2
-rw-r--r--common/i2c_master.c86
-rw-r--r--common/mkbp_event.c290
-rw-r--r--common/motion_sense.c157
-rw-r--r--common/panic_output.c2
-rw-r--r--common/timer.c4
-rw-r--r--common/usb_pd_protocol.c17
-rw-r--r--core/cortex-m/cpu.h6
-rw-r--r--core/cortex-m/panic.c172
-rw-r--r--core/cortex-m/watchdog.c16
-rw-r--r--docs/code_reviews.md33
-rw-r--r--driver/accelgyro_bmi160.c6
-rw-r--r--driver/accelgyro_icm426xx.c953
-rw-r--r--driver/accelgyro_icm426xx.h266
-rw-r--r--driver/accelgyro_icm_common.c287
-rw-r--r--driver/accelgyro_icm_common.h129
-rw-r--r--driver/als_si114x.c2
-rw-r--r--driver/build.mk1
-rw-r--r--extra/touchpad_updater/touchpad_updater.c2
-rw-r--r--extra/usb_console/usb_console.c2
-rw-r--r--include/common.h32
-rw-r--r--include/compile_time_macros.h22
-rw-r--r--include/config.h34
-rw-r--r--include/cros_board_info.h7
-rw-r--r--include/ec_commands.h18
-rw-r--r--include/i2c.h83
-rw-r--r--include/mkbp_event.h28
-rw-r--r--include/motion_sense.h16
-rw-r--r--include/panic.h53
-rw-r--r--include/timer.h31
-rw-r--r--test/build.mk2
-rw-r--r--test/cbi.c199
-rw-r--r--test/compile_time_macros.c47
-rw-r--r--test/compile_time_macros.tasklist9
-rw-r--r--test/kb_mkbp.c59
-rw-r--r--test/motion_lid.c3
-rw-r--r--test/test_config.h2
-rw-r--r--util/cbi-util.c53
-rw-r--r--util/comm-dev.c8
-rw-r--r--util/comm-host.c2
-rw-r--r--util/comm-lpc.c2
-rw-r--r--util/comm-servo-spi.c11
-rw-r--r--util/ec_flash.c2
-rw-r--r--util/ec_panicinfo.c22
-rwxr-xr-xutil/ecst.c3
-rw-r--r--util/ectool.c76
-rw-r--r--util/ectool_keyscan.c19
-rw-r--r--util/iteflash.c2
-rw-r--r--util/stm32mon.c17
-rw-r--r--util/uut/main.c4
-rw-r--r--util/uut/opr.c2
85 files changed, 3370 insertions, 401 deletions
diff --git a/Makefile.toolchain b/Makefile.toolchain
index 7cb8e212d1..23161d7bfd 100644
--- a/Makefile.toolchain
+++ b/Makefile.toolchain
@@ -45,13 +45,10 @@ HOSTCXX?=$(CCACHE) $(HOST_CROSS_COMPILE)g++
PROTOC?=protoc
C_WARN = -Wstrict-prototypes -Wdeclaration-after-statement -Wno-pointer-sign
-COMMON_WARN = -Wall -Werror -Wundef -Wno-trigraphs -fno-strict-aliasing \
- -fno-common -Werror-implicit-function-declaration \
- -Wno-format-security -fno-strict-overflow
-ifeq ($(cc-name),clang)
-# clang is pickier when it comes to packed struct members alignment.
-C_WARN+= -Wno-address-of-packed-member
-endif
+COMMON_WARN = -Wall -Wundef -Werror -Werror-implicit-function-declaration \
+ -Wno-trigraphs -Wno-format-security -Wno-address-of-packed-member \
+ -fno-common -fno-strict-aliasing -fno-strict-overflow
+
CFLAGS_WARN = $(COMMON_WARN) $(C_WARN)
CXXFLAGS_WARN = $(COMMON_WARN)
CFLAGS_DEBUG= -g
diff --git a/OWNERS b/OWNERS
index 56bc3389a1..72e8ffc0db 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,8 +1 @@
-# Chromium EC owners
-rspangler@chromium.org
-victoryang@chromium.org
-vpalatin@chromium.org
-wfrichar@chromium.org
-
-# Don't inherit owners from elsewhere in the manifest
-set noparent
+*
diff --git a/board/OWNERS b/board/OWNERS
deleted file mode 100644
index 5a0a0348b0..0000000000
--- a/board/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Additional owners for board directory
-dparker@chromium.org
diff --git a/board/aleena/board.h b/board/aleena/board.h
index 12e6869821..7756d5b181 100644
--- a/board/aleena/board.h
+++ b/board/aleena/board.h
@@ -29,6 +29,8 @@
/* KB backlight driver */
#define CONFIG_LED_DRIVER_LM3630A
+#define CONFIG_MKBP_USE_GPIO
+
#ifndef __ASSEMBLER__
enum pwm_channel {
diff --git a/board/cheza/board.h b/board/cheza/board.h
index 4fce7868fe..cb1bd0a068 100644
--- a/board/cheza/board.h
+++ b/board/cheza/board.h
@@ -55,6 +55,7 @@
#define CONFIG_HOSTCMD_SECTION_SORTED /* Host commands are sorted. */
#define CONFIG_MKBP_EVENT
#define CONFIG_KEYBOARD_PROTOCOL_MKBP
+#define CONFIG_MKBP_USE_GPIO
#define CONFIG_BOARD_VERSION_GPIO
#define CONFIG_POWER_BUTTON
diff --git a/board/elm/board.h b/board/elm/board.h
index b2036896e4..8d1283244c 100644
--- a/board/elm/board.h
+++ b/board/elm/board.h
@@ -65,6 +65,7 @@
#define CONFIG_LID_SWITCH
#define CONFIG_LOW_POWER_IDLE
#define CONFIG_MKBP_EVENT
+#define CONFIG_MKBP_USE_GPIO
#define CONFIG_POWER_BUTTON
#define CONFIG_POWER_COMMON
#define CONFIG_USB_CHARGER
diff --git a/board/jerry/board.h b/board/jerry/board.h
index ad8fdceeb8..da5de695df 100644
--- a/board/jerry/board.h
+++ b/board/jerry/board.h
@@ -37,6 +37,7 @@
#define CONFIG_LED_POWER_ACTIVE_LOW
#define CONFIG_LOW_POWER_IDLE
#define CONFIG_LOW_POWER_S0
+#define CONFIG_MKBP_USE_GPIO
#define CONFIG_POWER_BUTTON
#define CONFIG_POWER_BUTTON_ACTIVE_STATE 1
#define CONFIG_POWER_COMMON
diff --git a/board/kukui/board.h b/board/kukui/board.h
index 276bb0f1ea..2dc8daa64d 100644
--- a/board/kukui/board.h
+++ b/board/kukui/board.h
@@ -191,6 +191,7 @@
#define CONFIG_KEYBOARD_PROTOCOL_MKBP
#define CONFIG_MKBP_EVENT
+#define CONFIG_MKBP_USE_GPIO
/* Define the MKBP events which are allowed to wakeup AP in S3. */
#define CONFIG_MKBP_WAKEUP_MASK \
(EC_HOST_EVENT_MASK(EC_HOST_EVENT_POWER_BUTTON) |\
diff --git a/board/meowth_fp/board.h b/board/meowth_fp/board.h
index 5d3807c709..82fa7805b7 100644
--- a/board/meowth_fp/board.h
+++ b/board/meowth_fp/board.h
@@ -87,6 +87,7 @@
#undef CONFIG_LID_SWITCH
#define CONFIG_LOW_POWER_IDLE
#define CONFIG_MKBP_EVENT
+#define CONFIG_MKBP_USE_GPIO
#define CONFIG_PRINTF_LEGACY_LI_FORMAT
#define CONFIG_SHA256
#define CONFIG_SHA256_UNROLLED
diff --git a/board/nocturne/board.c b/board/nocturne/board.c
index ffa8c65920..31ebebd4e8 100644
--- a/board/nocturne/board.c
+++ b/board/nocturne/board.c
@@ -402,26 +402,6 @@ void board_hibernate(void)
;
}
-static int mkbp_uses_gpio(void)
-{
- return board_get_version() >= 2;
-}
-
-void mkbp_set_host_active(int active)
-{
- if (mkbp_uses_gpio())
- mkbp_set_host_active_via_gpio(active);
-
- /*
- * Always send the host event for compatibility.
- * On board versions 2 and newer, the firmware is configured
- * to not actually trigger an SCI on MKBP events. This means that
- * the EC can send host event notifications without concern for the
- * board version and expect the right thing to happen.
- */
- mkbp_set_host_active_via_event(active);
-}
-
static void board_init(void)
{
/* Enable USB Type-C interrupts. */
diff --git a/board/nocturne/board.h b/board/nocturne/board.h
index 63c409678b..83770875bb 100644
--- a/board/nocturne/board.h
+++ b/board/nocturne/board.h
@@ -86,6 +86,7 @@
/* MKBP */
#define CONFIG_MKBP_EVENT
#define CONFIG_KEYBOARD_PROTOCOL_MKBP
+#define CONFIG_MKBP_USE_GPIO
/* Sensors */
#define CONFIG_ALS
diff --git a/board/npcx_evb_arm/board.h b/board/npcx_evb_arm/board.h
index c6c09b1c58..0b3ab503e9 100644
--- a/board/npcx_evb_arm/board.h
+++ b/board/npcx_evb_arm/board.h
@@ -22,6 +22,7 @@
#define CONFIG_I2C_MASTER
#define CONFIG_KEYBOARD_BOARD_CONFIG
#define CONFIG_KEYBOARD_PROTOCOL_MKBP /* Instead of 8042 protocol of keyboard */
+#define CONFIG_MKBP_USE_GPIO
#define CONFIG_POWER_BUTTON
#define CONFIG_VBOOT_HASH
#define CONFIG_PWM_KBLIGHT
diff --git a/board/nucleo-f411re/board.c b/board/nucleo-f411re/board.c
index 0f7c57f1e3..d0a84638fd 100644
--- a/board/nucleo-f411re/board.c
+++ b/board/nucleo-f411re/board.c
@@ -8,7 +8,8 @@
#include "adc_chip.h"
#include "common.h"
#include "console.h"
-#include "driver/accelgyro_bmi160.h"
+#include "driver/accelgyro_icm_common.h"
+#include "driver/accelgyro_icm426xx.h"
#include "ec_version.h"
#include "gpio.h"
#include "hooks.h"
@@ -31,6 +32,7 @@ void user_button_evt(enum gpio_signal signal)
static void board_init(void)
{
gpio_enable_interrupt(GPIO_USER_BUTTON_L);
+ gpio_enable_interrupt(GPIO_ICM426XX_INT1_L);
/* No power control yet */
/* Go to S3 state */
@@ -39,7 +41,7 @@ static void board_init(void)
/* Go to S0 state */
hook_notify(HOOK_CHIPSET_RESUME);
}
-DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
+DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_LAST);
/* ADC channels */
const struct adc_t adc_channels[] = {
@@ -53,29 +55,28 @@ BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
/* I2C ports */
const struct i2c_port_t i2c_ports[] = {
- {"master", I2C_PORT_MASTER, 100,
+ {"master", I2C_PORT_MASTER, 400,
GPIO_MASTER_I2C_SCL, GPIO_MASTER_I2C_SDA},
};
-
const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
/* Base Sensor mutex */
static struct mutex g_base_mutex;
-static struct bmi160_drv_data_t g_bmi160_data;
+static struct icm_drv_data_t g_icm426xx_data;
struct motion_sensor_t motion_sensors[] = {
[BASE_ACCEL] = {
.name = "Base Accel",
.active_mask = SENSOR_ACTIVE_S0_S3,
- .chip = MOTIONSENSE_CHIP_BMI160,
+ .chip = MOTIONSENSE_CHIP_ICM426XX,
.type = MOTIONSENSE_TYPE_ACCEL,
.location = MOTIONSENSE_LOC_BASE,
- .drv = &bmi160_drv,
+ .drv = &icm426xx_drv,
.mutex = &g_base_mutex,
- .drv_data = &g_bmi160_data,
+ .drv_data = &g_icm426xx_data,
.port = I2C_PORT_ACCEL,
- .addr = BMI160_ADDR0,
+ .addr = ICM426XX_ADDR0_FLAGS,
.rot_standard_ref = NULL,
.default_range = 2, /* g, enough for laptop. */
.config = {
@@ -95,14 +96,14 @@ struct motion_sensor_t motion_sensors[] = {
[BASE_GYRO] = {
.name = "Base Gyro",
.active_mask = SENSOR_ACTIVE_S0_S3,
- .chip = MOTIONSENSE_CHIP_BMI160,
+ .chip = MOTIONSENSE_CHIP_ICM426XX,
.type = MOTIONSENSE_TYPE_GYRO,
.location = MOTIONSENSE_LOC_BASE,
- .drv = &bmi160_drv,
+ .drv = &icm426xx_drv,
.mutex = &g_base_mutex,
- .drv_data = &g_bmi160_data,
+ .drv_data = &g_icm426xx_data,
.port = I2C_PORT_ACCEL,
- .addr = BMI160_ADDR0,
+ .addr = ICM426XX_ADDR0_FLAGS,
.default_range = 1000, /* dps */
.rot_standard_ref = NULL,
},
diff --git a/board/nucleo-f411re/board.h b/board/nucleo-f411re/board.h
index 7ffa0b0f07..9c2380948b 100644
--- a/board/nucleo-f411re/board.h
+++ b/board/nucleo-f411re/board.h
@@ -34,7 +34,17 @@
#define CONFIG_UART_TX_REQ_CH STM32_REQ_USART2_TX
#define CONFIG_UART_RX_REQ_CH STM32_REQ_USART2_RX
-#define CONFIG_ACCELGYRO_BMI160
+#define CONFIG_ACCELGYRO_ICM426XX
+#define CONFIG_ACCEL_INTERRUPTS
+#define CONFIG_ACCELGYRO_ICM426XX_INT_EVENT TASK_EVENT_CUSTOM(4)
+
+#define CONFIG_MKBP_EVENT
+/* Enable sensor fifo, must also define the _SIZE and _THRES */
+/* FIFO size is in power of 2. */
+#define CONFIG_ACCEL_FIFO 512
+/* Depends on how fast the AP boots and typical ODRs */
+#define CONFIG_ACCEL_FIFO_THRES (CONFIG_ACCEL_FIFO / 3)
+
#define CONFIG_CMD_ACCELS
#define CONFIG_CMD_ACCEL_INFO
#define CONFIG_CMD_FLASH
diff --git a/board/nucleo-f411re/ec.tasklist b/board/nucleo-f411re/ec.tasklist
index 52135d97f8..847b82695c 100644
--- a/board/nucleo-f411re/ec.tasklist
+++ b/board/nucleo-f411re/ec.tasklist
@@ -17,7 +17,7 @@
* 's' is the stack size in bytes; must be a multiple of 8
*/
#define CONFIG_TASK_LIST \
- TASK_ALWAYS(HOOKS, hook_task, NULL, LARGER_TASK_STACK_SIZE) \
- TASK_NOTEST(HOSTCMD, host_command_task, NULL, TASK_STACK_SIZE) \
- TASK_NOTEST(MOTIONSENSE, motion_sense_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(HOOKS, hook_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_NOTEST(HOSTCMD, host_command_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_NOTEST(MOTIONSENSE, motion_sense_task, NULL, VENTI_TASK_STACK_SIZE) \
TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE)
diff --git a/board/nucleo-f411re/gpio.inc b/board/nucleo-f411re/gpio.inc
index 83a9e51a08..3ad0a0ff69 100644
--- a/board/nucleo-f411re/gpio.inc
+++ b/board/nucleo-f411re/gpio.inc
@@ -7,11 +7,12 @@
/* Interrupts */
GPIO_INT(USER_BUTTON_L, PIN(C, 13), GPIO_INT_BOTH, user_button_evt)
+GPIO_INT(ICM426XX_INT1_L, PIN(C, 10), GPIO_INT_FALLING, icm426xx_interrupt)
/* User LED */
GPIO(USER_LED, PIN(A, 5), GPIO_OUT_LOW)
+GPIO(EC_INT_L, PIN(A, 1), GPIO_OUT_HIGH)
-GPIO(BMI160_INT2_L, PIN(C, 10), GPIO_OUT_LOW)
/*
* I2C pins should be configured as inputs until I2C module is
* initialized. This will avoid driving the lines unintentionally.
diff --git a/board/oak/board.h b/board/oak/board.h
index 3e8dbd0698..b84b852679 100644
--- a/board/oak/board.h
+++ b/board/oak/board.h
@@ -83,6 +83,7 @@
#define CONFIG_LID_SWITCH
#define CONFIG_LOW_POWER_IDLE
#define CONFIG_MKBP_EVENT
+#define CONFIG_MKBP_USE_GPIO
#define CONFIG_POWER_BUTTON
#define CONFIG_POWER_COMMON
#define CONFIG_USB_CHARGER
diff --git a/board/rainier/board.h b/board/rainier/board.h
index 1c5e9b6a03..957c679a75 100644
--- a/board/rainier/board.h
+++ b/board/rainier/board.h
@@ -128,6 +128,7 @@
#define CONFIG_KEYBOARD_PROTOCOL_MKBP
#define CONFIG_MKBP_EVENT
+#define CONFIG_MKBP_USE_GPIO
/* Define the MKBP events which are allowed to wakeup AP in S3. */
#define CONFIG_MKBP_WAKEUP_MASK \
(EC_HOST_EVENT_MASK(EC_HOST_EVENT_POWER_BUTTON) |\
diff --git a/board/rammus/battery.c b/board/rammus/battery.c
index 916aac5fd3..d0cc2f13d2 100644
--- a/board/rammus/battery.c
+++ b/board/rammus/battery.c
@@ -7,11 +7,15 @@
#include "battery.h"
#include "battery_smart.h"
+#include "charge_manager.h"
#include "charge_state.h"
+#include "chipset.h"
#include "console.h"
#include "ec_commands.h"
#include "extpower.h"
+#include "hooks.h"
#include "gpio.h"
+#include "usb_pd.h"
#include "util.h"
static enum battery_present batt_pres_prev = BP_NOT_SURE;
@@ -128,3 +132,28 @@ enum battery_present battery_is_present(void)
return batt_pres;
}
+static void reduce_input_voltage_when_full(void)
+{
+ struct batt_params batt;
+ int max_pd_voltage_mv;
+ int active_chg_port;
+
+ active_chg_port = charge_manager_get_active_charge_port();
+ if (active_chg_port == CHARGE_PORT_NONE)
+ return;
+
+ battery_get_params(&batt);
+ if (!(batt.flags & BATT_FLAG_BAD_STATUS)) {
+ /* Lower our input voltage to 9V when battery is full. */
+ if ((batt.status & STATUS_FULLY_CHARGED) &&
+ chipset_in_state(CHIPSET_STATE_ANY_OFF))
+ max_pd_voltage_mv = 9000;
+ else
+ max_pd_voltage_mv = PD_MAX_VOLTAGE_MV;
+
+ if (pd_get_max_voltage() != max_pd_voltage_mv)
+ pd_set_external_voltage_limit(active_chg_port,
+ max_pd_voltage_mv);
+ }
+}
+DECLARE_HOOK(HOOK_SECOND, reduce_input_voltage_when_full, HOOK_PRIO_DEFAULT);
diff --git a/board/rammus/board.c b/board/rammus/board.c
index 4fc874a2f9..7577819fb8 100644
--- a/board/rammus/board.c
+++ b/board/rammus/board.c
@@ -11,6 +11,7 @@
#include "bd99992gw.h"
#include "board_config.h"
#include "button.h"
+#include "cbi_ssfc.h"
#include "charge_manager.h"
#include "charge_state.h"
#include "charge_ramp.h"
@@ -19,7 +20,11 @@
#include "console.h"
#include "cros_board_info.h"
#include "driver/accelgyro_bmi160.h"
+#include "driver/accelgyro_icm_common.h"
+#include "driver/accelgyro_icm426xx.h"
#include "driver/accel_bma2x2.h"
+#include "driver/accel_kionix.h"
+#include "driver/accel_kx022.h"
#include "driver/tcpm/ps8xxx.h"
#include "driver/tcpm/tcpci.h"
#include "driver/tcpm/tcpm.h"
@@ -600,9 +605,11 @@ static struct mutex g_lid_mutex;
static struct mutex g_base_mutex;
static struct bmi160_drv_data_t g_bmi160_data;
+static struct icm_drv_data_t g_icm426xx_data;
-/* BMA255 private data */
+/* private data */
static struct accelgyro_saved_data_t g_bma255_data;
+static struct kionix_accel_data g_kx022_data;
/* Matrix to rotate accelrator into standard reference frame */
const mat33_fp_t base_standard_ref = {
@@ -611,12 +618,93 @@ const mat33_fp_t base_standard_ref = {
{ 0, 0, FLOAT_TO_FP(-1) }
};
+const mat33_fp_t base_standard_ref_icm = {
+ { 0, FLOAT_TO_FP(1), 0 },
+ { FLOAT_TO_FP(1), 0, 0 },
+ { 0, 0, FLOAT_TO_FP(-1) }
+};
+
const mat33_fp_t lid_standard_ref = {
{ FLOAT_TO_FP(-1), 0, 0 },
{ 0, FLOAT_TO_FP(1), 0 },
{ 0, 0, FLOAT_TO_FP(-1) }
};
+struct motion_sensor_t base_accel_icm = {
+ .name = "Base Accel",
+ .active_mask = SENSOR_ACTIVE_S0_S3,
+ .chip = MOTIONSENSE_CHIP_ICM426XX,
+ .type = MOTIONSENSE_TYPE_ACCEL,
+ .location = MOTIONSENSE_LOC_BASE,
+ .drv = &icm426xx_drv,
+ .mutex = &g_base_mutex,
+ .drv_data = &g_icm426xx_data,
+ .port = I2C_PORT_ACCEL,
+ .addr = ICM426XX_ADDR0_FLAGS,
+ .rot_standard_ref = &base_standard_ref_icm,
+ .min_frequency = ICM426XX_ACCEL_MIN_FREQ,
+ .max_frequency = ICM426XX_ACCEL_MAX_FREQ,
+ .default_range = 4, /* g, to meet CDD 7.3.1/C-1-4 reqs */
+ .config = {
+ /* EC use accel for angle detection */
+ [SENSOR_CONFIG_EC_S0] = {
+ .odr = 10000 | ROUND_UP_FLAG,
+ .ec_rate = 100 * MSEC,
+ },
+ /* Sensor on in S3 */
+ [SENSOR_CONFIG_EC_S3] = {
+ .odr = 10000 | ROUND_UP_FLAG,
+ .ec_rate = 0,
+ },
+ },
+};
+
+struct motion_sensor_t base_gyro_icm = {
+ .name = "Base Gyro",
+ .active_mask = SENSOR_ACTIVE_S0_S3,
+ .chip = MOTIONSENSE_CHIP_ICM426XX,
+ .type = MOTIONSENSE_TYPE_GYRO,
+ .location = MOTIONSENSE_LOC_BASE,
+ .drv = &icm426xx_drv,
+ .mutex = &g_base_mutex,
+ .drv_data = &g_icm426xx_data,
+ .port = I2C_PORT_ACCEL,
+ .addr = ICM426XX_ADDR0_FLAGS,
+ .default_range = 1000, /* dps */
+ .rot_standard_ref = &base_standard_ref_icm,
+ .min_frequency = ICM426XX_GYRO_MIN_FREQ,
+ .max_frequency = ICM426XX_GYRO_MAX_FREQ,
+};
+
+struct motion_sensor_t lid_accel_kx022 = {
+ .name = "Lid Accel",
+ .active_mask = SENSOR_ACTIVE_S0_S3,
+ .chip = MOTIONSENSE_CHIP_KX022,
+ .type = MOTIONSENSE_TYPE_ACCEL,
+ .location = MOTIONSENSE_LOC_LID,
+ .drv = &kionix_accel_drv,
+ .mutex = &g_lid_mutex,
+ .drv_data = &g_kx022_data,
+ .port = I2C_PORT_ACCEL,
+ .addr = KX022_ADDR1,
+ .rot_standard_ref = &lid_standard_ref,
+ .min_frequency = KX022_ACCEL_MIN_FREQ,
+ .max_frequency = KX022_ACCEL_MAX_FREQ,
+ .default_range = 2, /* g, to support lid angle calculation. */
+ .config = {
+ /* EC use accel for angle detection */
+ [SENSOR_CONFIG_EC_S0] = {
+ .odr = 10000 | ROUND_UP_FLAG,
+ .ec_rate = 0,
+ },
+ /* Sensor on in S3 */
+ [SENSOR_CONFIG_EC_S3] = {
+ .odr = 10000 | ROUND_UP_FLAG,
+ .ec_rate = 0,
+ },
+ },
+};
+
struct motion_sensor_t motion_sensors[] = {
[LID_ACCEL] = {
.name = "Lid Accel",
@@ -693,6 +781,31 @@ struct motion_sensor_t motion_sensors[] = {
};
unsigned int motion_sensor_count = ARRAY_SIZE(motion_sensors);
+void motion_interrupt(enum gpio_signal signal)
+{
+ if (get_cbi_ssfc_base_sensor() == SSFC_SENSOR_BASE_ICM426XX)
+ icm426xx_interrupt(signal);
+ else
+ bmi160_interrupt(signal);
+}
+
+static void board_detect_motionsense(void)
+{
+ if (get_cbi_ssfc_lid_sensor() == SSFC_SENSOR_LID_KX022) {
+ motion_sensors[LID_ACCEL] = lid_accel_kx022;
+ ccprints("LID_ACCEL is KX022");
+ } else
+ ccprints("LID_ACCEL is BMA253");
+
+ if (get_cbi_ssfc_base_sensor() == SSFC_SENSOR_BASE_ICM426XX) {
+ motion_sensors[BASE_ACCEL] = base_accel_icm;
+ motion_sensors[BASE_GYRO] = base_gyro_icm;
+ ccprints("BASE_ACCEL is ICM426XX");
+ } else
+ ccprints("BASE_ACCEL is BMI160");
+}
+DECLARE_HOOK(HOOK_INIT, board_detect_motionsense, HOOK_PRIO_DEFAULT);
+
/* Enable or disable input devices, based on chipset state and tablet mode */
#ifndef TEST_BUILD
void lid_angle_peripheral_enable(int enable)
diff --git a/board/rammus/board.h b/board/rammus/board.h
index acd15753cb..ddd5320e41 100644
--- a/board/rammus/board.h
+++ b/board/rammus/board.h
@@ -8,6 +8,14 @@
#ifndef __CROS_EC_BOARD_H
#define __CROS_EC_BOARD_H
+/*
+ * By default, enable all console messages excepted HC, ACPI and event:
+ * The sensor stack is generating a lot of activity.
+ */
+#define CC_DEFAULT (CC_ALL & ~(CC_MASK(CC_EVENTS) | CC_MASK(CC_LPC)))
+#undef CONFIG_HOSTCMD_DEBUG_MODE
+#define CONFIG_HOSTCMD_DEBUG_MODE HCDEBUG_OFF
+
/* EC */
#define CONFIG_ADC
#define CONFIG_BACKLIGHT_LID
@@ -112,8 +120,11 @@
#define CONFIG_MKBP_USE_HOST_EVENT
#define CONFIG_ACCELGYRO_BMI160
#define CONFIG_ACCELGYRO_BMI160_INT_EVENT TASK_EVENT_CUSTOM(4)
+#define CONFIG_ACCELGYRO_ICM426XX
+#define CONFIG_ACCELGYRO_ICM426XX_INT_EVENT TASK_EVENT_CUSTOM(4)
#define CONFIG_ACCELGYRO_BMI160_INT2_OUTPUT
#define CONFIG_ACCEL_BMA255
+#define CONFIG_ACCEL_KX022
#define CONFIG_ACCEL_INTERRUPTS
#define CONFIG_LID_ANGLE
#define CONFIG_LID_ANGLE_SENSOR_BASE BASE_ACCEL
@@ -282,6 +293,7 @@ enum pwm_channel {
/* Board specific handlers */
void board_reset_pd_mcu(void);
void board_set_tcpc_power_mode(int port, int mode);
+void motion_interrupt(enum gpio_signal signal);
/* Sensors without hardware FIFO are in forced mode */
#define CONFIG_ACCEL_FORCE_MODE_MASK (1 << LID_ACCEL)
diff --git a/board/rammus/build.mk b/board/rammus/build.mk
index 21f6e4c99e..5a9cabdcae 100644
--- a/board/rammus/build.mk
+++ b/board/rammus/build.mk
@@ -9,7 +9,7 @@
CHIP:=npcx
CHIP_VARIANT:=npcx5m6g
-board-y=board.o
+board-y=board.o cbi_ssfc.o
board-$(CONFIG_BATTERY_SMART)+=battery.o
board-$(CONFIG_LED_COMMON)+=led.o
board-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_policy.o
diff --git a/board/rammus/cbi_ssfc.c b/board/rammus/cbi_ssfc.c
new file mode 100644
index 0000000000..e1f6fa4bd2
--- /dev/null
+++ b/board/rammus/cbi_ssfc.c
@@ -0,0 +1,36 @@
+/* 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.
+ */
+
+#include "cbi_ssfc.h"
+#include "common.h"
+#include "console.h"
+#include "cros_board_info.h"
+#include "hooks.h"
+
+#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ##args)
+
+/* Cache SSFC on init since we don't expect it to change in runtime */
+static union rammus_cbi_ssfc cached_ssfc;
+BUILD_ASSERT(sizeof(cached_ssfc) == sizeof(uint32_t));
+
+static void cbi_ssfc_init(void)
+{
+ if (cbi_get_ssfc(&cached_ssfc.raw_value) != EC_SUCCESS)
+ /* Default to 0 when CBI isn't populated */
+ cached_ssfc.raw_value = 0;
+
+ CPRINTS("Read CBI SSFC : 0x%04X", cached_ssfc.raw_value);
+}
+DECLARE_HOOK(HOOK_INIT, cbi_ssfc_init, HOOK_PRIO_INIT_I2C+1);
+
+enum ec_ssfc_lid_sensor get_cbi_ssfc_lid_sensor(void)
+{
+ return cached_ssfc.lid_sensor;
+}
+
+enum ec_ssfc_base_sensor get_cbi_ssfc_base_sensor(void)
+{
+ return cached_ssfc.base_sensor;
+}
diff --git a/board/rammus/cbi_ssfc.h b/board/rammus/cbi_ssfc.h
new file mode 100644
index 0000000000..2ca20f2376
--- /dev/null
+++ b/board/rammus/cbi_ssfc.h
@@ -0,0 +1,56 @@
+/* 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.
+ */
+
+#ifndef _RAMMUS_CBI_SSFC__H_
+#define _RAMMUS_CBI_SSFC__H_
+
+#include "stdint.h"
+
+/****************************************************************************
+ * Rammus CBI Second Source Factory Cache
+ */
+
+/*
+ * Lid Sensor (Bits 2-0)
+ */
+enum ec_ssfc_lid_sensor {
+ SSFC_SENSOR_LID_DEFAULT = 0,
+ SSFC_SENSOR_LID_BMA255 = 1,
+ SSFC_SENSOR_LID_KX022 = 2
+};
+
+/*
+ * Base Sensor (Bits 5-3)
+ */
+enum ec_ssfc_base_sensor {
+ SSFC_SENSOR_BASE_DEFAULT = 0,
+ SSFC_SENSOR_BASE_BMI160 = 1,
+ SSFC_SENSOR_BASE_ICM426XX = 2,
+};
+
+union rammus_cbi_ssfc {
+ struct {
+ enum ec_ssfc_lid_sensor lid_sensor : 3;
+ enum ec_ssfc_base_sensor base_sensor : 3;
+ uint32_t reserved_2 : 26;
+ };
+ uint32_t raw_value;
+};
+
+/**
+ * Get the Lid sensor type from SSFC_CONFIG.
+ *
+ * @return the Lid sensor board type.
+ */
+enum ec_ssfc_lid_sensor get_cbi_ssfc_lid_sensor(void);
+
+/**
+ * Get the base sensor type form SSFC_CONFIG.
+ *
+ * @return the base sensor board type.
+ */
+enum ec_ssfc_base_sensor get_cbi_ssfc_base_sensor(void);
+
+#endif /* _RAMMUS_CBI_SSFC__H_ */
diff --git a/board/rammus/gpio.inc b/board/rammus/gpio.inc
index 1a8f076aba..40cee5dfc5 100644
--- a/board/rammus/gpio.inc
+++ b/board/rammus/gpio.inc
@@ -26,7 +26,7 @@ GPIO_INT(USB_C0_VBUS_DET_L, PIN(9, 3), GPIO_INT_BOTH | GPIO_PULL_UP, vbus0_
GPIO_INT(USB_C1_VBUS_DET_L, PIN(9, 7), GPIO_INT_BOTH | GPIO_PULL_UP, vbus1_evt)
GPIO_INT(USB_C0_BC12_INT_L, PIN(D, 3), GPIO_INT_FALLING, usb0_evt)
GPIO_INT(USB_C1_BC12_INT_L, PIN(3, 3), GPIO_INT_FALLING, usb1_evt)
-GPIO_INT(BASE_SIXAXIS_INT_L, PIN(7, 3), GPIO_INT_FALLING | GPIO_SEL_1P8V, bmi160_interrupt)
+GPIO_INT(BASE_SIXAXIS_INT_L, PIN(7, 3), GPIO_INT_FALLING | GPIO_SEL_1P8V, motion_interrupt)
GPIO_INT(TABLET_MODE, PIN(C, 6), GPIO_INT_BOTH, hall_sensor_isr)
GPIO(EN_PP3300_TRACKPAD, PIN(4, 5), GPIO_OUT_LOW) /* Enable TouchPad */
diff --git a/board/rowan/board.h b/board/rowan/board.h
index 839dbdf262..95f34d9e3d 100644
--- a/board/rowan/board.h
+++ b/board/rowan/board.h
@@ -70,6 +70,7 @@
#define CONFIG_LID_SWITCH
#define CONFIG_LOW_POWER_IDLE
#define CONFIG_MKBP_EVENT
+#define CONFIG_MKBP_USE_GPIO
#define CONFIG_POWER_BUTTON
#define CONFIG_POWER_COMMON
#define CONFIG_USB_CHARGER
diff --git a/board/scarlet/board.h b/board/scarlet/board.h
index d6110c5ba3..74fc1ae2b2 100644
--- a/board/scarlet/board.h
+++ b/board/scarlet/board.h
@@ -180,6 +180,7 @@
#define CONFIG_KEYBOARD_PROTOCOL_MKBP
#define CONFIG_MKBP_EVENT
+#define CONFIG_MKBP_USE_GPIO
/* Define the MKBP events which are allowed to wakeup AP in S3. */
#define CONFIG_MKBP_WAKEUP_MASK \
(EC_HOST_EVENT_MASK(EC_HOST_EVENT_POWER_BUTTON) |\
diff --git a/chip/mec1322/hwtimer.c b/chip/mec1322/hwtimer.c
index be9ffac1ea..221633d3f4 100644
--- a/chip/mec1322/hwtimer.c
+++ b/chip/mec1322/hwtimer.c
@@ -107,3 +107,14 @@ int __hw_clock_source_init(uint32_t start_t)
return MEC1322_IRQ_TIMER32_1;
}
+
+/*
+ * Unrolled udelay. It preserves LR, which points to the root cause of WD crash.
+ */
+__override void udelay(unsigned us)
+{
+ unsigned t0 = 0xffffffff - MEC1322_TMR32_CNT(0);
+
+ while (0xffffffff - MEC1322_TMR32_CNT(0) - t0 <= us)
+ ;
+}
diff --git a/chip/npcx/hwtimer.c b/chip/npcx/hwtimer.c
index 76f1822a94..75b026c939 100644
--- a/chip/npcx/hwtimer.c
+++ b/chip/npcx/hwtimer.c
@@ -16,6 +16,7 @@
#include "console.h"
#include "task.h"
#include "timer.h"
+#include "registers.h"
#include "util.h"
/* Depth of event timer */
@@ -340,3 +341,23 @@ int __hw_clock_source_init(uint32_t start_t)
return NPCX_IRQ_ITIM32;
}
+
+/*
+ * Unrolled udelay. It preserves LR, which points to the root cause of WD crash.
+ */
+__override void udelay(unsigned us)
+{
+ uint32_t cnt, cnt2, t0;
+
+ cnt = NPCX_ITCNT32;
+ while ((cnt2 = NPCX_ITCNT32) != cnt)
+ cnt = cnt2;
+
+ t0 = TICK_ITIM32_MAX_CNT - cnt;
+
+ do {
+ cnt = NPCX_ITCNT32;
+ while ((cnt2 = NPCX_ITCNT32) != cnt)
+ cnt = cnt2;
+ } while (TICK_ITIM32_MAX_CNT - cnt - t0 <= us);
+}
diff --git a/chip/npcx/system.c b/chip/npcx/system.c
index edfbcf455b..cd90390e5f 100644
--- a/chip/npcx/system.c
+++ b/chip/npcx/system.c
@@ -244,7 +244,7 @@ void system_set_rtc(uint32_t seconds)
*
* index | data
* ==========|=============
- * 36 | MMFS
+ * 36 | CFSR
* 40 | HFSR
* 44 | BFAR
* 48 | LREG1
@@ -253,11 +253,11 @@ void system_set_rtc(uint32_t seconds)
* 60 | reserved
*
* Above registers are chosen to be saved in case of panic because:
- * 1. MMFS, HFSR and BFAR seem to provide more information about the fault.
+ * 1. CFSR, HFSR and BFAR seem to provide more information about the fault.
* 2. LREG1, LREG3 and LREG4 store exception, reason and info in case of
* software panic.
*/
-#define BKUP_MMFS (BBRM_DATA_INDEX_PANIC_BKUP + 0)
+#define BKUP_CFSR (BBRM_DATA_INDEX_PANIC_BKUP + 0)
#define BKUP_HFSR (BBRM_DATA_INDEX_PANIC_BKUP + 4)
#define BKUP_BFAR (BBRM_DATA_INDEX_PANIC_BKUP + 8)
#define BKUP_LREG1 (BBRM_DATA_INDEX_PANIC_BKUP + 12)
@@ -273,7 +273,7 @@ void chip_panic_data_backup(void)
if (!d)
return;
- bbram_data_write(BKUP_MMFS, d->cm.mmfs);
+ bbram_data_write(BKUP_CFSR, d->cm.cfsr);
bbram_data_write(BKUP_HFSR, d->cm.hfsr);
bbram_data_write(BKUP_BFAR, d->cm.dfsr);
bbram_data_write(BKUP_LREG1, d->cm.regs[1]);
@@ -287,7 +287,7 @@ static void chip_panic_data_restore(void)
struct panic_data *d = PANIC_DATA_PTR;
/* Ensure BBRAM is valid. */
- if (!bbram_valid(BKUP_MMFS, 4))
+ if (!bbram_valid(BKUP_CFSR, 4))
return;
/* Ensure Panic data in BBRAM is valid. */
@@ -301,7 +301,7 @@ static void chip_panic_data_restore(void)
d->struct_version = 2;
d->arch = PANIC_ARCH_CORTEX_M;
- d->cm.mmfs = bbram_data_read(BKUP_MMFS);
+ d->cm.cfsr = bbram_data_read(BKUP_CFSR);
d->cm.hfsr = bbram_data_read(BKUP_HFSR);
d->cm.dfsr = bbram_data_read(BKUP_BFAR);
diff --git a/chip/stm32/gpio.c b/chip/stm32/gpio.c
index a8415cce1b..21c7a7ce2e 100644
--- a/chip/stm32/gpio.c
+++ b/chip/stm32/gpio.c
@@ -127,7 +127,8 @@ int gpio_clear_pending_interrupt(enum gpio_signal signal)
if (!g->mask || signal >= GPIO_IH_COUNT)
return EC_ERROR_INVAL;
- STM32_EXTI_PR |= g->mask;
+ /* Write 1 to clear interrupt */
+ STM32_EXTI_PR = g->mask;
return EC_SUCCESS;
}
@@ -142,6 +143,7 @@ void __keep gpio_interrupt(void)
uint32_t pending = STM32_EXTI_PR & 0xFFFF;
uint8_t signal;
+ /* Write 1 to clear interrupt */
STM32_EXTI_PR = pending;
while (pending) {
diff --git a/common/build.mk b/common/build.mk
index 3b25e0bc99..5a10c91bb5 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -11,6 +11,7 @@ common-y+=version.o printf.o queue.o queue_policies.o
common-$(CONFIG_ACCELGYRO_BMA255)+=math_util.o
common-$(CONFIG_ACCELGYRO_BMI160)+=math_util.o
+common-$(CONFIG_ACCELGYRO_ICM426XX)+=math_util.o
common-$(CONFIG_ACCELGYRO_LSM6DS0)+=math_util.o
common-$(CONFIG_ACCELGYRO_LSM6DSM)+=math_util.o
common-$(CONFIG_ACCEL_LIS2DH)+=math_util.o
diff --git a/common/cbi.c b/common/cbi.c
index f37d6950b1..a6dd13443d 100644
--- a/common/cbi.c
+++ b/common/cbi.c
@@ -253,6 +253,37 @@ int cbi_get_oem_id(uint32_t *id)
return cbi_get_board_info(CBI_TAG_OEM_ID, (uint8_t *)id, &size);
}
+int cbi_get_model_id(uint32_t *id)
+{
+ uint8_t size = sizeof(*id);
+
+ return cbi_get_board_info(CBI_TAG_MODEL_ID, (uint8_t *)id, &size);
+}
+
+int cbi_get_fw_config(uint32_t *fw_config)
+{
+ uint8_t size = sizeof(*fw_config);
+
+ return cbi_get_board_info(CBI_TAG_FW_CONFIG, (uint8_t *)fw_config,
+ &size);
+}
+
+int cbi_get_ssfc(uint32_t *ssfc)
+{
+ uint8_t size = sizeof(*ssfc);
+
+ return cbi_get_board_info(CBI_TAG_SSFC, (uint8_t *)ssfc,
+ &size);
+}
+
+int cbi_get_pcb_supplier(uint32_t *pcb_supplier)
+{
+ uint8_t size = sizeof(*pcb_supplier);
+
+ return cbi_get_board_info(CBI_TAG_PCB_SUPPLIER, (uint8_t *)pcb_supplier,
+ &size);
+}
+
static int hc_cbi_get(struct host_cmd_handler_args *args)
{
const struct __ec_align4 ec_params_get_cbi *p = args->params;
@@ -368,6 +399,9 @@ static void dump_cbi(void)
print_tag("BOARD_VERSION", cbi_get_board_version(&val), &val);
print_tag("OEM_ID", cbi_get_oem_id(&val), &val);
print_tag("SKU_ID", cbi_get_sku_id(&val), &val);
+ print_tag("FW_CONFIG", cbi_get_fw_config(&val), &val);
+ print_tag("PCB_SUPPLIER", cbi_get_pcb_supplier(&val), &val);
+ print_tag("SSFC", cbi_get_ssfc(&val), &val);
}
static int cc_cbi(int argc, char **argv)
diff --git a/common/charge_ramp.c b/common/charge_ramp.c
index 86a0b454cc..3ca5bd89bb 100644
--- a/common/charge_ramp.c
+++ b/common/charge_ramp.c
@@ -11,17 +11,22 @@
#include "usb_charge.h"
#include "util.h"
-#define TYPEC_DTS_RAMP_MAX 2400
-
test_mockable int chg_ramp_allowed(int supplier)
{
/* Don't allow ramping in RO when write protected. */
if (!system_is_in_rw() && system_is_locked())
return 0;
- /* Ramp DTS suppliers. */
- if (supplier == CHARGE_SUPPLIER_TYPEC_DTS)
+ switch (supplier) {
+ case CHARGE_SUPPLIER_TYPEC_DTS:
+#ifdef CONFIG_CHARGE_RAMP_HW
+ /* Need ramping for USB-C chargers as well to avoid voltage droops. */
+ case CHARGE_SUPPLIER_PD:
+ case CHARGE_SUPPLIER_TYPEC:
+#endif
return 1;
+ /* default: fall through */
+ }
/* Othewise ask the BC1.2 detect module */
return usb_charger_ramp_allowed(supplier);
@@ -29,12 +34,19 @@ test_mockable int chg_ramp_allowed(int supplier)
test_mockable int chg_ramp_max(int supplier, int sup_curr)
{
- /*
- * Ramp DTS suppliers to advertised current or predetermined
- * limit, whichever is greater.
- */
- if (supplier == CHARGE_SUPPLIER_TYPEC_DTS)
- return MAX(TYPEC_DTS_RAMP_MAX, sup_curr);
+ switch (supplier) {
+#ifdef CONFIG_CHARGE_RAMP_HW
+ case CHARGE_SUPPLIER_PD:
+ case CHARGE_SUPPLIER_TYPEC:
+#endif
+ case CHARGE_SUPPLIER_TYPEC_DTS:
+ /*
+ * We should not ramp DTS beyond what they advertise, otherwise
+ * we may brownout the systems they are connected to.
+ */
+ return sup_curr;
+ /* default: fall through */
+ }
/* Otherwise ask the BC1.2 detect module */
return usb_charger_ramp_max(supplier, sup_curr);
diff --git a/common/crc.c b/common/crc.c
index 79d405eb13..a715a6d366 100644
--- a/common/crc.c
+++ b/common/crc.c
@@ -60,7 +60,7 @@ static uint32_t crc32_hash(uint32_t crc, const void *buf, int size)
{
const uint8_t *p;
- p = buf;
+ p = (const uint8_t *)buf;
while (size--) {
crc ^= *p++;
diff --git a/common/i2c_master.c b/common/i2c_master.c
index ec2cad96df..df9dbe57c2 100644
--- a/common/i2c_master.c
+++ b/common/i2c_master.c
@@ -304,6 +304,92 @@ int i2c_write8(int port, int slave_addr, int offset, int data)
return i2c_xfer(port, slave_addr, buf, 2, 0, 0);
}
+int i2c_update8(const int port,
+ const uint16_t slave_addr_flags,
+ const int offset,
+ const uint8_t mask,
+ const enum mask_update_action action)
+{
+ int rv;
+ int val, oldval;
+
+ rv = i2c_read8(port, slave_addr_flags, offset, &oldval);
+ if (rv)
+ return rv;
+
+ val = (action == MASK_SET) ? oldval | mask
+ : oldval & ~mask;
+
+ if (val != oldval)
+ return i2c_write8(port, slave_addr_flags, offset, val);
+
+ return EC_SUCCESS;
+}
+
+int i2c_update16(const int port,
+ const uint16_t slave_addr_flags,
+ const int offset,
+ const uint16_t mask,
+ const enum mask_update_action action)
+{
+ int rv;
+ int val, oldval;
+
+ rv = i2c_read16(port, slave_addr_flags, offset, &oldval);
+ if (rv)
+ return rv;
+
+ val = (action == MASK_SET) ? oldval | mask
+ : oldval & ~mask;
+
+ if (val != oldval)
+ return i2c_write16(port, slave_addr_flags, offset, val);
+
+ return EC_SUCCESS;
+}
+
+int i2c_field_update8(const int port,
+ const uint16_t slave_addr_flags,
+ const int offset,
+ const uint8_t field_mask,
+ const uint8_t set_value)
+{
+ int rv;
+ int val, oldval;
+
+ rv = i2c_read8(port, slave_addr_flags, offset, &oldval);
+ if (rv)
+ return rv;
+
+ val = (oldval & (~field_mask)) | set_value;
+
+ if (val != oldval)
+ return i2c_write8(port, slave_addr_flags, offset, val);
+
+ return EC_SUCCESS;
+}
+
+int i2c_field_update16(const int port,
+ const uint16_t slave_addr_flags,
+ const int offset,
+ const uint16_t field_mask,
+ const uint16_t set_value)
+{
+ int rv;
+ int val, oldval;
+
+ rv = i2c_read16(port, slave_addr_flags, offset, &oldval);
+ if (rv)
+ return rv;
+
+ val = (oldval & (~field_mask)) | set_value;
+
+ if (val != oldval)
+ return i2c_write16(port, slave_addr_flags, offset, val);
+
+ return EC_SUCCESS;
+}
+
int i2c_read_string(int port, int slave_addr, int offset, uint8_t *data,
int len)
{
diff --git a/common/mkbp_event.c b/common/mkbp_event.c
index 44cec336b5..18843ef6be 100644
--- a/common/mkbp_event.c
+++ b/common/mkbp_event.c
@@ -10,67 +10,125 @@
#include "gpio.h"
#include "host_command.h"
#include "hwtimer.h"
+#include "timer.h"
#include "link_defs.h"
#include "mkbp_event.h"
#include "power.h"
#include "util.h"
-static uint32_t events;
+#define CPUTS(outstr) cputs(CC_COMMAND, outstr)
+#define CPRINTS(format, args...) cprints(CC_COMMAND, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_COMMAND, format, ## args)
+
+/*
+ * Tracks the current state of the MKBP interrupt send from the EC to the AP.
+ *
+ * The inactive state is only valid when there are no events to set to the AP.
+ * If the AP is asleep, then some events are not worth waking the AP up, so the
+ * interrupt could remain in an inactive in that case.
+ *
+ * The transition state (INTERRUPT_INACTIVE_TO_ACTIVE) is used to track the
+ * sometimes lock transition for a "rising edge" for platforms that send the
+ * rising edge interrupt through a host communication layer
+ *
+ * The active state represents that a rising edge interrupt has already been
+ * sent to the AP, and the EC is waiting for the AP to call get next event
+ * host command to consume all of the events (at which point the state will
+ * move to inactive).
+ *
+ * The transition from ACTIVE -> INACTIVE is considerer to be simple meaning
+ * the operation can be performed within a blocking mutex (e.g. no-op or setting
+ * a gpio).
+ */
+enum interrupt_state {
+ INTERRUPT_INACTIVE,
+ INTERRUPT_INACTIVE_TO_ACTIVE, /* Transitioning */
+ INTERRUPT_ACTIVE,
+};
+
+struct mkbp_state {
+ struct mutex lock;
+ uint32_t events;
+ enum interrupt_state interrupt;
+ /*
+ * Tracks unique transitions to INTERRUPT_INACTIVE_TO_ACTIVE allowing
+ * only the most recent transition to finish the transition to a final
+ * state -- either active or inactive depending on the result of the
+ * operation.
+ */
+ uint8_t interrupt_id;
+ /*
+ * Tracks the number of consecutive failed attempts for the AP to poll
+ * get_next_events in order to limit the retry logic.
+ */
+ uint8_t failed_attempts;
+};
+
+static struct mkbp_state state;
uint32_t mkbp_last_event_time;
-static void set_event(uint8_t event_type)
+#ifdef CONFIG_MKBP_USE_GPIO
+static int mkbp_set_host_active_via_gpio(int active, uint32_t *timestamp)
{
- atomic_or(&events, 1 << event_type);
-}
+ /*
+ * If we want to take a timestamp, then disable interrupts temporarily
+ * to ensure that the timestamp is as close as possible to the setting
+ * of the GPIO pin in hardware (i.e. we aren't interrupted between
+ * taking the timestamp and setting the gpio)
+ */
+ if (timestamp) {
+ interrupt_disable();
+ *timestamp = __hw_clock_source_read();
+ }
-static void clear_event(uint8_t event_type)
-{
- atomic_clear(&events, 1 << event_type);
-}
+ gpio_set_level(GPIO_EC_INT_L, !active);
-static int event_is_set(uint8_t event_type)
-{
- return events & (1 << event_type);
-}
+ if (timestamp)
+ interrupt_enable();
-#ifndef CONFIG_MKBP_USE_HOST_EVENT
-void mkbp_set_host_active_via_gpio(int active)
-{
- gpio_set_level(GPIO_EC_INT_L, !active);
+ return EC_SUCCESS;
}
#endif
-void mkbp_set_host_active_via_event(int active)
+#ifdef CONFIG_MKBP_USE_HOST_EVENT
+static int mkbp_set_host_active_via_event(int active, uint32_t *timestamp)
{
+ /* This should be moved into host_set_single_event for more accuracy */
+ if (timestamp)
+ *timestamp = __hw_clock_source_read();
if (active)
host_set_single_event(EC_HOST_EVENT_MKBP);
+ return EC_SUCCESS;
}
-
-__attribute__((weak)) void mkbp_set_host_active(int active)
-{
-#ifdef CONFIG_MKBP_USE_HOST_EVENT
- mkbp_set_host_active_via_event(active);
-#else
- mkbp_set_host_active_via_gpio(active);
#endif
-}
-/**
- * Assert host keyboard interrupt line.
+/*
+ * This communicates to the AP whether an MKBP event is currently available
+ * for processing.
+ *
+ * NOTE: When active is 0 this function CANNOT de-schedule. It must be very
+ * simple like toggling a GPIO or no-op
+ *
+ * @param active 1 if there is an event, 0 otherwise
+ * @param timestamp, if non-null this variable will be written as close to the
+ * hardware interrupt from EC->AP as possible.
*/
-static void set_host_interrupt(int active)
+static int mkbp_set_host_active(int active, uint32_t *timestamp)
{
- static int old_active;
-
- interrupt_disable();
-
- if (old_active == 0 && active == 1)
- mkbp_last_event_time = __hw_clock_source_read();
-
- mkbp_set_host_active(active);
-
- old_active = active;
- interrupt_enable();
+#if defined(CONFIG_MKBP_USE_CUSTOM)
+ /*
+ * TODO change mkbp_set_host_active_via_custom declaration. Done in
+ * child CL to decouple changes
+ */
+ if (timestamp)
+ *timestamp = __hw_clock_source_read();
+ mkbp_set_host_active_via_custom(active);
+ return EC_SUCCESS;
+#elif defined(CONFIG_MKBP_USE_HOST_EVENT)
+ return mkbp_set_host_active_via_event(active, timestamp);
+#elif defined(CONFIG_MKBP_USE_GPIO)
+ return mkbp_set_host_active_via_gpio(active, timestamp);
+#endif
}
#ifdef CONFIG_MKBP_WAKEUP_MASK
@@ -92,24 +150,130 @@ static inline int host_is_sleeping(void)
}
#endif /* CONFIG_MKBP_WAKEUP_MASK */
-int mkbp_send_event(uint8_t event_type)
+/*
+ * This is the deferred function that ensures that we attempt to set the MKBP
+ * interrupt again if there was a failure in the system (EC or AP) and the AP
+ * never called get_next_event.
+ */
+static void force_mkbp_if_events(void);
+DECLARE_DEFERRED(force_mkbp_if_events);
+
+static void activate_mkbp_with_events(uint32_t events_to_add)
{
- set_event(event_type);
+ int interrupt_id = -1;
+ int skip_interrupt = 0;
+ int rv, schedule_deferred = 0;
#ifdef CONFIG_MKBP_WAKEUP_MASK
/* Only assert interrupt for wake events if host is sleeping */
- if (host_is_sleeping()) {
- /* Skip host wake if this isn't a wake event */
- if (!(host_get_events() & CONFIG_MKBP_WAKEUP_MASK) &&
- event_type != EC_MKBP_EVENT_KEY_MATRIX)
- return 0;
- }
+ skip_interrupt = host_is_sleeping() &&
+ !(host_get_events() & CONFIG_MKBP_WAKEUP_MASK);
#endif
- set_host_interrupt(1);
+ mutex_lock(&state.lock);
+ state.events |= events_to_add;
+
+ /* To skip the interrupt, we cannot have the EC_MKBP_EVENT_KEY_MATRIX */
+ skip_interrupt = skip_interrupt &&
+ !(state.events & (1 << EC_MKBP_EVENT_KEY_MATRIX));
+
+ if (state.events && state.interrupt == INTERRUPT_INACTIVE &&
+ !skip_interrupt) {
+ state.interrupt = INTERRUPT_INACTIVE_TO_ACTIVE;
+ interrupt_id = ++state.interrupt_id;
+ }
+ mutex_unlock(&state.lock);
+
+ /* If we don't need to send an interrupt we are done */
+ if (interrupt_id < 0)
+ return;
+
+ /* Send a rising edge MKBP interrupt */
+ rv = mkbp_set_host_active(1, &mkbp_last_event_time);
+
+ /*
+ * If this was the last interrupt to the AP, update state;
+ * otherwise the latest interrupt should update state.
+ */
+ mutex_lock(&state.lock);
+ if (state.interrupt == INTERRUPT_INACTIVE_TO_ACTIVE &&
+ interrupt_id == state.interrupt_id) {
+ schedule_deferred = 1;
+ state.interrupt = rv == EC_SUCCESS ? INTERRUPT_ACTIVE
+ : INTERRUPT_INACTIVE;
+ }
+ mutex_unlock(&state.lock);
+
+ if (schedule_deferred) {
+ hook_call_deferred(&force_mkbp_if_events_data, SECOND);
+ if (rv != EC_SUCCESS)
+ CPRINTS("Could not activate MKBP (%d). Deferring", rv);
+ }
+}
+
+/*
+ * This is the deferred function that ensures that we attempt to set the MKBP
+ * interrupt again if there was a failure in the system (EC or AP) and the AP
+ * never called get_next_event.
+ */
+static void force_mkbp_if_events(void)
+{
+ int toggled = 0;
+
+ mutex_lock(&state.lock);
+ if (state.interrupt == INTERRUPT_ACTIVE) {
+ if (++state.failed_attempts < 3) {
+ state.interrupt = INTERRUPT_INACTIVE;
+ toggled = 1;
+ }
+ }
+ mutex_unlock(&state.lock);
+
+ if (toggled)
+ CPRINTS("MKBP not cleared within threshold, toggling.");
+
+ activate_mkbp_with_events(0);
+}
+
+int mkbp_send_event(uint8_t event_type)
+{
+ activate_mkbp_with_events(1 << event_type);
+
return 1;
}
+static int set_inactive_if_no_events(void)
+{
+ int interrupt_cleared;
+
+ mutex_lock(&state.lock);
+ interrupt_cleared = !state.events;
+ if (interrupt_cleared) {
+ state.interrupt = INTERRUPT_INACTIVE;
+ state.failed_attempts = 0;
+ /* Only simple tasks (i.e. gpio set or no-op) allowed here */
+ mkbp_set_host_active(0, NULL);
+ }
+ mutex_unlock(&state.lock);
+
+ /* Cancel our safety net since the events were cleared. */
+ if (interrupt_cleared)
+ hook_call_deferred(&force_mkbp_if_events_data, -1);
+
+ return interrupt_cleared;
+}
+
+/* This can only be called when the state.lock mutex is held */
+static int take_event_if_set(uint8_t event_type)
+{
+ int taken;
+
+ taken = state.events & (1 << event_type);
+ state.events &= ~(1 << event_type);
+
+ return taken;
+}
+
static int mkbp_get_next_event(struct host_cmd_handler_args *args)
{
static int last;
@@ -122,24 +286,22 @@ static int mkbp_get_next_event(struct host_cmd_handler_args *args)
* Find the next event to service. We do this in a round-robin
* way to make sure no event gets starved.
*/
+ mutex_lock(&state.lock);
for (i = 0; i < EC_MKBP_EVENT_COUNT; ++i)
- if (event_is_set((last + i) % EC_MKBP_EVENT_COUNT))
+ if (take_event_if_set((last + i) % EC_MKBP_EVENT_COUNT))
break;
+ mutex_unlock(&state.lock);
if (i == EC_MKBP_EVENT_COUNT) {
- set_host_interrupt(0);
- return EC_RES_UNAVAILABLE;
+ if (set_inactive_if_no_events())
+ return EC_RES_UNAVAILABLE;
+ /* An event was set just now, restart loop. */
+ continue;
}
evt = (i + last) % EC_MKBP_EVENT_COUNT;
last = evt + 1;
- /*
- * Clear the event before retrieving the event data in case the
- * event source wants to send the same event.
- */
- clear_event(evt);
-
for (src = __mkbp_evt_srcs; src < __mkbp_evt_srcs_end; ++src)
if (src->event_type == evt)
break;
@@ -158,12 +320,16 @@ static int mkbp_get_next_event(struct host_cmd_handler_args *args)
* event first.
*/
data_size = src->get_data(resp + 1);
- if (data_size == -EC_ERROR_BUSY)
- set_event(evt);
+ if (data_size == -EC_ERROR_BUSY) {
+ mutex_lock(&state.lock);
+ state.events |= 1 << evt;
+ mutex_unlock(&state.lock);
+ }
} while (data_size == -EC_ERROR_BUSY);
- if (!events)
- set_host_interrupt(0);
+ /* If there are no more events and we support the "more" flag, set it */
+ if (!set_inactive_if_no_events() && args->version >= 2)
+ resp[0] |= EC_MKBP_HAS_MORE_EVENTS;
if (data_size < 0)
return EC_RES_ERROR;
@@ -173,7 +339,7 @@ static int mkbp_get_next_event(struct host_cmd_handler_args *args)
}
DECLARE_HOST_COMMAND(EC_CMD_GET_NEXT_EVENT,
mkbp_get_next_event,
- EC_VER_MASK(0) | EC_VER_MASK(1));
+ EC_VER_MASK(0) | EC_VER_MASK(1) | EC_VER_MASK(2));
#ifdef CONFIG_MKBP_WAKEUP_MASK
static int mkbp_get_wake_mask(struct host_cmd_handler_args *args)
diff --git a/common/motion_sense.c b/common/motion_sense.c
index 1023409f99..353e54030b 100644
--- a/common/motion_sense.c
+++ b/common/motion_sense.c
@@ -45,13 +45,8 @@ const intv3_t orientation_modes[] = {
};
#endif
-/*
- * Sampling interval for measuring acceleration and calculating lid angle.
- */
-test_export_static unsigned int motion_interval;
-
/* Delay between FIFO interruption. */
-static unsigned int motion_int_interval;
+static unsigned int ap_event_interval;
/* Minimum time in between running motion sense task loop. */
unsigned int motion_min_interval = CONFIG_MOTION_MIN_SENSE_WAIT_TIME * MSEC;
@@ -208,22 +203,19 @@ static inline int motion_sensor_in_forced_mode(
#endif
}
-
-
/* Minimal amount of time since last collection before triggering a new one */
static inline int motion_sensor_time_to_read(const timestamp_t *ts,
const struct motion_sensor_t *sensor)
{
- int rate_mhz = sensor->drv->get_data_rate(sensor);
-
- if (rate_mhz == 0)
+ if (sensor->collection_rate == 0)
return 0;
+
/*
- * converting from mHz to us.
- * If within 95% of the time, check sensor.
+ * If the time is within the min motion interval (3 ms) go ahead and
+ * read from the sensor
*/
return time_after(ts->le.lo,
- sensor->last_collection + SECOND * 950 / rate_mhz);
+ sensor->next_collection - motion_min_interval);
}
static enum sensor_config motion_sense_get_ec_config(void)
@@ -296,7 +288,9 @@ int motion_sense_set_data_rate(struct motion_sensor_t *sensor)
* Reset last collection: the last collection may be so much in the past
* it may appear to be in the future.
*/
- sensor->last_collection = ts.le.lo;
+ odr = sensor->drv->get_data_rate(sensor);
+ sensor->collection_rate = odr > 0 ? SECOND * 1000 / odr : 0;
+ sensor->next_collection = ts.le.lo + sensor->collection_rate;
sensor->oversampling = 0;
mutex_unlock(&g_sensor_mutex);
return 0;
@@ -402,9 +396,9 @@ static int motion_sense_ec_rate(struct motion_sensor_t *sensor)
*
* Note: Not static to be tested.
*/
-static int motion_sense_set_motion_intervals(void)
+static void motion_sense_set_motion_intervals(void)
{
- int i, sensor_ec_rate, ec_rate = 0, ec_int_rate = 0;
+ int i, sensor_ec_rate, ec_int_rate = 0;
struct motion_sensor_t *sensor;
for (i = 0; i < motion_sensor_count; ++i) {
sensor = &motion_sensors[i];
@@ -415,28 +409,20 @@ static int motion_sense_set_motion_intervals(void)
(sensor->drv->get_data_rate(sensor) == 0))
continue;
- sensor_ec_rate = motion_sense_ec_rate(sensor);
- if (sensor_ec_rate == 0)
- continue;
- if (ec_rate == 0 || sensor_ec_rate < ec_rate)
- ec_rate = sensor_ec_rate;
-
sensor_ec_rate = motion_sense_select_ec_rate(
sensor, SENSOR_CONFIG_AP, 1);
if (ec_int_rate == 0 ||
(sensor_ec_rate && sensor_ec_rate < ec_int_rate))
ec_int_rate = sensor_ec_rate;
}
- motion_interval = ec_rate;
- motion_int_interval =
+ ap_event_interval =
MAX(0, ec_int_rate - MOTION_SENSOR_INT_ADJUSTMENT_US);
/*
* Wake up the motion sense task: we want to sensor task to take
* in account the new period right away.
*/
task_wake(TASK_ID_MOTIONSENSE);
- return motion_interval;
}
static inline int motion_sense_init(struct motion_sensor_t *sensor)
@@ -692,11 +678,8 @@ static inline void update_sense_data(uint8_t *lpc_status, int *psample_id)
static int motion_sense_read(struct motion_sensor_t *sensor)
{
- if (sensor->state != SENSOR_INITIALIZED)
- return EC_ERROR_UNKNOWN;
-
- if (sensor->drv->get_data_rate(sensor) == 0)
- return EC_ERROR_NOT_POWERED;
+ ASSERT(sensor->state == SENSOR_INITIALIZED);
+ ASSERT(sensor->drv->get_data_rate(sensor) != 0);
#ifdef CONFIG_ACCEL_SPOOF_MODE
/*
@@ -711,6 +694,30 @@ static int motion_sense_read(struct motion_sensor_t *sensor)
return sensor->drv->read(sensor, sensor->raw_xyz);
}
+
+static inline void increment_sensor_collection(struct motion_sensor_t *sensor,
+ const timestamp_t *ts)
+{
+ sensor->next_collection += sensor->collection_rate;
+
+ if (time_after(ts->le.lo, sensor->next_collection)) {
+ /*
+ * If we get here it means that we completely missed a sensor
+ * collection time and we attempt to recover by scheduling as
+ * soon as possible. This should not happen and if it does it
+ * means that the ec cannot handle the requested data rate.
+ */
+ int missed_events =
+ time_until(sensor->next_collection, ts->le.lo) /
+ sensor->collection_rate;
+
+ CPRINTS("%s Missed %d data collections at %u - rate: %d",
+ sensor->name, missed_events, sensor->next_collection,
+ sensor->collection_rate);
+ sensor->next_collection = ts->le.lo + motion_min_interval;
+ }
+}
+
static int motion_sense_process(struct motion_sensor_t *sensor,
uint32_t *event,
const timestamp_t *ts)
@@ -729,6 +736,13 @@ static int motion_sense_process(struct motion_sensor_t *sensor,
struct ec_response_motion_sensor_data vector;
int *v = sensor->raw_xyz;
+ /*
+ * Since motion_sense_read can sleep, other task may be
+ * scheduled. In particular if suspend is called by
+ * HOOKS task, it may set colleciton_rate to 0 and we
+ * would crash in increment_sensor_collection.
+ */
+ increment_sensor_collection(sensor, ts);
ret = motion_sense_read(sensor);
if (ret == EC_SUCCESS) {
vector.flags = 0;
@@ -743,7 +757,6 @@ static int motion_sense_process(struct motion_sensor_t *sensor,
motion_sense_fifo_add_data(&vector, sensor, 3,
__hw_clock_source_read());
}
- sensor->last_collection = ts->le.lo;
} else {
ret = EC_ERROR_BUSY;
}
@@ -760,8 +773,14 @@ static int motion_sense_process(struct motion_sensor_t *sensor,
if (motion_sensor_in_forced_mode(sensor)) {
if (motion_sensor_time_to_read(ts, sensor)) {
/* Get latest data for local calculation */
+ /*
+ * Since motion_sense_read can sleep, other task may be
+ * scheduled. In particular if suspend is called by
+ * HOOKS task, it may set colleciton_rate to 0 and we
+ * would crash in increment_sensor_collection.
+ */
+ increment_sensor_collection(sensor, ts);
ret = motion_sense_read(sensor);
- sensor->last_collection = ts->le.lo;
} else {
ret = EC_ERROR_BUSY;
}
@@ -897,6 +916,7 @@ void motion_sense_task(void *u)
{
int i, ret, wait_us;
timestamp_t ts_begin_task, ts_end_task;
+ int32_t time_diff;
uint32_t event = 0;
uint16_t ready_status;
struct motion_sensor_t *sensor;
@@ -970,7 +990,6 @@ void motion_sense_task(void *u)
update_sense_data(lpc_status, &sample_id);
#endif
- ts_end_task = get_time();
#ifdef CONFIG_ACCEL_FIFO
/*
* Ask the host to flush the queue if
@@ -981,14 +1000,14 @@ void motion_sense_task(void *u)
if (fifo_flush_needed || wake_up_needed ||
event & TASK_EVENT_MOTION_ODR_CHANGE ||
queue_space(&motion_sense_fifo) < CONFIG_ACCEL_FIFO_THRES ||
- (motion_int_interval > 0 &&
- time_after(ts_end_task.le.lo,
- ts_last_int.le.lo + motion_int_interval))) {
+ (ap_event_interval > 0 &&
+ time_after(ts_begin_task.le.lo,
+ ts_last_int.le.lo + ap_event_interval))) {
if (!fifo_flush_needed)
motion_sense_insert_timestamp(
__hw_clock_source_read());
fifo_flush_needed = 0;
- ts_last_int = ts_end_task;
+ ts_last_int = ts_begin_task;
/*
* Count the number of event the AP is allowed to
* collect.
@@ -1012,25 +1031,36 @@ void motion_sense_task(void *u)
#endif
}
#endif
- if (motion_interval > 0) {
- /*
- * Delay appropriately to keep sampling time
- * consistent.
- */
- wait_us = motion_interval -
- (ts_end_task.val - ts_begin_task.val);
- /* and it cannnot be negative */
- wait_us = MAX(wait_us, 0);
+ ts_end_task = get_time();
+ wait_us = -1;
+
+ for (i = 0; i < motion_sensor_count; i++) {
+ struct motion_sensor_t *sensor = &motion_sensors[i];
+
+ if (!motion_sensor_in_forced_mode(sensor) ||
+ sensor->collection_rate == 0)
+ continue;
+
+ time_diff = time_until(ts_end_task.le.lo,
+ sensor->next_collection);
+
+ /* We missed our collection time so wake soon */
+ if (time_diff <= 0) {
+ wait_us = 0;
+ break;
+ }
+
+ if (wait_us == -1 || wait_us > time_diff)
+ wait_us = time_diff;
+ }
+ if (wait_us >= 0 && wait_us < motion_min_interval) {
/*
- * Guarantee some minimum delay to allow other lower
- * priority tasks to run.
- */
- if (wait_us < motion_min_interval)
- wait_us = motion_min_interval;
- } else {
- wait_us = -1;
+ * Guarantee some minimum delay to allow other lower
+ * priority tasks to run.
+ */
+ wait_us = motion_min_interval;
}
event = task_wait_event(wait_us);
@@ -1633,8 +1663,7 @@ static int command_accel_data_rate(int argc, char **argv)
sensor->drv->get_data_rate(sensor));
ccprintf("EC rate for sensor %d: %d\n", id,
motion_sense_ec_rate(sensor));
- ccprintf("Current EC rate: %d\n", motion_interval);
- ccprintf("Current Interrupt rate: %d\n", motion_int_interval);
+ ccprintf("Current Interrupt rate: %d\n", ap_event_interval);
}
return EC_SUCCESS;
@@ -1710,7 +1739,6 @@ DECLARE_CONSOLE_COMMAND(accelinit, command_accel_init,
#ifdef CONFIG_CMD_ACCEL_INFO
static int command_display_accel_info(int argc, char **argv)
{
- char *e;
int val;
if (argc > 3)
@@ -1724,21 +1752,6 @@ static int command_display_accel_info(int argc, char **argv)
accel_disp = val;
}
- /*
- * Second arg changes the accel task time interval. Note accel
- * sampling interval will be clobbered when chipset suspends or
- * resumes.
- */
- if (argc > 2) {
- val = strtoi(argv[2], &e, 0);
- if (*e)
- return EC_ERROR_PARAM2;
-
- motion_interval = val * MSEC;
- task_wake(TASK_ID_MOTIONSENSE);
-
- }
-
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(accelinfo, command_display_accel_info,
diff --git a/common/panic_output.c b/common/panic_output.c
index e6b48a375d..fd1b1999a0 100644
--- a/common/panic_output.c
+++ b/common/panic_output.c
@@ -98,7 +98,7 @@ void panic_assert_fail(const char *msg, const char *func, const char *fname,
panic_printf("\nASSERTION FAILURE '%s' in %s() at %s:%d\n",
msg, func, fname, linenum);
#ifdef CONFIG_SOFTWARE_PANIC
- software_panic(PANIC_SW_ASSERT, linenum);
+ panic_assert(func, fname, (uint16_t)linenum);
#else
panic_reboot();
#endif
diff --git a/common/timer.c b/common/timer.c
index 117cea4b71..6f31d93b09 100644
--- a/common/timer.c
+++ b/common/timer.c
@@ -94,8 +94,7 @@ void process_timers(int overflow)
} while (next.val <= get_time().val);
}
-#ifndef CONFIG_HW_SPECIFIC_UDELAY
-void udelay(unsigned us)
+__overridable void udelay(unsigned us)
{
unsigned t0 = __hw_clock_source_read();
@@ -112,7 +111,6 @@ void udelay(unsigned us)
while (__hw_clock_source_read() - t0 <= us)
;
}
-#endif
int timer_arm(timestamp_t tstamp, task_id_t tskid)
{
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index a75baa5c14..6c71c155cc 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -2577,8 +2577,8 @@ void pd_interrupt_handler_task(void *p)
const int port_mask = (PD_STATUS_TCPC_ALERT_0 << port);
struct {
int count;
- uint32_t time;
- } storm_tracker[CONFIG_USB_PD_PORT_COUNT] = { 0 };
+ timestamp_t time;
+ } storm_tracker[CONFIG_USB_PD_PORT_COUNT] = {};
ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_COUNT);
@@ -2601,14 +2601,17 @@ void pd_interrupt_handler_task(void *p)
*/
while ((tcpc_get_alert_status() & port_mask) &&
pd_is_port_enabled(port)) {
- uint32_t now;
+ timestamp_t now;
tcpc_alert(port);
- now = get_time().le.lo;
- if (time_after(now, storm_tracker[port].time)) {
- storm_tracker[port].time =
- now + ALERT_STORM_INTERVAL;
+ now = get_time();
+ if (timestamp_expired(
+ storm_tracker[port].time, &now)) {
+ /* Reset timer into future */
+ storm_tracker[port].time.val =
+ now.val + ALERT_STORM_INTERVAL;
+
/*
* Start at 1 since we are processing
* an interrupt now
diff --git a/core/cortex-m/cpu.h b/core/cortex-m/cpu.h
index a6029e2e7e..32a4205018 100644
--- a/core/cortex-m/cpu.h
+++ b/core/cortex-m/cpu.h
@@ -31,15 +31,15 @@
#define CPU_NVIC_CCR CPUREG(0xe000ed14)
#define CPU_NVIC_SHCSR CPUREG(0xe000ed24)
-#define CPU_NVIC_MMFS CPUREG(0xe000ed28)
+#define CPU_NVIC_CFSR CPUREG(0xe000ed28)
#define CPU_NVIC_HFSR CPUREG(0xe000ed2c)
#define CPU_NVIC_DFSR CPUREG(0xe000ed30)
#define CPU_NVIC_MFAR CPUREG(0xe000ed34)
#define CPU_NVIC_BFAR CPUREG(0xe000ed38)
enum {
- CPU_NVIC_MMFS_BFARVALID = 1 << 15,
- CPU_NVIC_MMFS_MFARVALID = 1 << 7,
+ CPU_NVIC_CFSR_BFARVALID = 1 << 15,
+ CPU_NVIC_CFSR_MFARVALID = 1 << 7,
CPU_NVIC_CCR_ICACHE = 1 << 17,
CPU_NVIC_CCR_DCACHE = 1 << 16,
diff --git a/core/cortex-m/panic.c b/core/cortex-m/panic.c
index 7daedbf7ab..c4954ec000 100644
--- a/core/cortex-m/panic.c
+++ b/core/cortex-m/panic.c
@@ -77,44 +77,28 @@ static int32_t is_frame_in_handler_stack(const uint32_t exc_return)
}
#ifdef CONFIG_DEBUG_EXCEPTIONS
-/* Names for each of the bits in the mmfs register, starting at bit 0 */
-static const char * const mmfs_name[32] = {
- "Instruction access violation",
- "Data access violation",
- NULL,
- "Unstack from exception violation",
- "Stack from exception violation",
- NULL,
- NULL,
- NULL,
-
- "Instruction bus error",
- "Precise data bus error",
- "Imprecise data bus error",
- "Unstack from exception bus fault",
- "Stack from exception bus fault",
- NULL,
- NULL,
- NULL,
-
- "Undefined instructions",
- "Invalid state",
- "Invalid PC",
- "No coprocessor",
- NULL,
- NULL,
- NULL,
- NULL,
-
- "Unaligned",
- "Divide by 0",
- NULL,
- NULL,
-
- NULL,
- NULL,
- NULL,
- NULL,
+/* Names for each of the bits in the cfs register, starting at bit 0 */
+static const char * const cfsr_name[32] = {
+ /* MMFSR */
+ [0] = "Instruction access violation",
+ [1] = "Data access violation",
+ [3] = "Unstack from exception violation",
+ [4] = "Stack from exception violation",
+
+ /* BFSR */
+ [8] = "Instruction bus error",
+ [9] = "Precise data bus error",
+ [10] = "Imprecise data bus error",
+ [11] = "Unstack from exception bus fault",
+ [12] = "Stack from exception bus fault",
+
+ /* UFSR */
+ [16] = "Undefined instructions",
+ [17] = "Invalid state",
+ [18] = "Invalid PC",
+ [19] = "No coprocessor",
+ [24] = "Unaligned",
+ [25] = "Divide by 0",
};
/* Names for the first 5 bits in the DFSR */
@@ -146,19 +130,19 @@ static void do_separate(int *count)
*
* A list of detected faults is shown, with no trailing newline.
*
- * @param mmfs Value of Memory Manage Fault Status
+ * @param cfsr Value of Configurable Fault Status
* @param hfsr Value of Hard Fault Status
* @param dfsr Value of Debug Fault Status
*/
-static void show_fault(uint32_t mmfs, uint32_t hfsr, uint32_t dfsr)
+static void show_fault(uint32_t cfsr, uint32_t hfsr, uint32_t dfsr)
{
unsigned int upto;
int count = 0;
for (upto = 0; upto < 32; upto++) {
- if ((mmfs & (1 << upto)) && mmfs_name[upto]) {
+ if ((cfsr & (1 << upto)) && cfsr_name[upto]) {
do_separate(&count);
- panic_puts(mmfs_name[upto]);
+ panic_puts(cfsr_name[upto]);
}
}
@@ -235,15 +219,16 @@ static uint32_t get_process_stack_position(const struct panic_data *pdata)
*/
static void panic_show_extra(const struct panic_data *pdata)
{
- show_fault(pdata->cm.mmfs, pdata->cm.hfsr, pdata->cm.dfsr);
- if (pdata->cm.mmfs & CPU_NVIC_MMFS_BFARVALID)
+ show_fault(pdata->cm.cfsr, pdata->cm.hfsr, pdata->cm.dfsr);
+ if (pdata->cm.cfsr & CPU_NVIC_CFSR_BFARVALID)
panic_printf(", bfar = %x", pdata->cm.bfar);
- if (pdata->cm.mmfs & CPU_NVIC_MMFS_MFARVALID)
+ if (pdata->cm.cfsr & CPU_NVIC_CFSR_MFARVALID)
panic_printf(", mfar = %x", pdata->cm.mfar);
- panic_printf("\nmmfs = %x, ", pdata->cm.mmfs);
+ panic_printf("\ncfsr = %x, ", pdata->cm.cfsr);
panic_printf("shcsr = %x, ", pdata->cm.shcsr);
panic_printf("hfsr = %x, ", pdata->cm.hfsr);
- panic_printf("dfsr = %x\n", pdata->cm.dfsr);
+ panic_printf("dfsr = %x, ", pdata->cm.dfsr);
+ panic_printf("ipsr = %x\n", pdata->cm.regs[1]);
}
/*
@@ -284,9 +269,18 @@ void panic_data_print(const struct panic_data *pdata)
if (pdata->flags & PANIC_DATA_FLAG_FRAME_VALID)
sregs = pdata->cm.frame;
- panic_printf("\n=== %s EXCEPTION: %02x ====== xPSR: %08x ===\n",
- in_handler ? "HANDLER" : "PROCESS",
- lregs[1] & 0xff, sregs ? sregs[7] : -1);
+ if (((pdata->cm.hfsr >> 26) & 0xf) == HFSR_FLAG_WATCHDOG) {
+ panic_printf("\n### WATCHDOG PC=%08x / LR=%08x / task=%d\n",
+ lregs[4], lregs[1], (pdata->cm.hfsr >> 2) & 0xff);
+ } else if (((pdata->cm.hfsr >> 26) & 0xf) == HFSR_FLAG_ASSERT) {
+ panic_printf("\nASSERTION FAILURE in %s() at %s:%d\n",
+ lregs[3], lregs[4],
+ (pdata->cm.hfsr >> 10) & 0xffff);
+ } else {
+ panic_printf("\n=== %s EXCEPTION: %02x ====== xPSR: %08x ===\n",
+ in_handler ? "HANDLER" : "PROCESS",
+ lregs[1] & 0xff, sregs ? sregs[7] : -1);
+ }
for (i = 0; i < 4; i++)
print_reg(i, sregs, i);
for (i = 4; i < 10; i++)
@@ -324,19 +318,36 @@ void __keep report_panic(void)
sp <= CONFIG_RAM_BASE + CONFIG_RAM_SIZE - 8 * sizeof(uint32_t)) {
const uint32_t *sregs = (const uint32_t *)sp;
int i;
- for (i = 0; i < 8; i++)
+
+ /* Skip r0-r3 and r12 registers if necessary */
+ for (i = CORTEX_PANIC_FRAME_REGISTER_R0;
+ i <= CORTEX_PANIC_FRAME_REGISTER_R12; i++)
+ if (IS_ENABLED(CONFIG_PANIC_STRIP_GPR))
+ pdata->cm.frame[i] = 0;
+ else
+ pdata->cm.frame[i] = sregs[i];
+
+ for (i = CORTEX_PANIC_FRAME_REGISTER_LR;
+ i < NUM_CORTEX_PANIC_FRAME_REGISTERS; i++)
pdata->cm.frame[i] = sregs[i];
+
pdata->flags |= PANIC_DATA_FLAG_FRAME_VALID;
}
/* Save extra information */
- pdata->cm.mmfs = CPU_NVIC_MMFS;
+ pdata->cm.cfsr = CPU_NVIC_CFSR;
pdata->cm.bfar = CPU_NVIC_BFAR;
pdata->cm.mfar = CPU_NVIC_MFAR;
pdata->cm.shcsr = CPU_NVIC_SHCSR;
pdata->cm.hfsr = CPU_NVIC_HFSR;
pdata->cm.dfsr = CPU_NVIC_DFSR;
+ /* Store LR & PC in cm.regs to make them survive a PMIC reset. */
+ if (pdata->flags & PANIC_DATA_FLAG_FRAME_VALID) {
+ pdata->cm.regs[3] = pdata->cm.frame[5]; /* LR */
+ pdata->cm.regs[4] = pdata->cm.frame[6]; /* PC */
+ }
+
#ifdef CONFIG_UART_PAD_SWITCH
uart_reset_default_pad_panic();
#endif
@@ -364,6 +375,33 @@ void exception_panic(void)
"mrs r1, psp\n"
"mrs r2, ipsr\n"
"mov r3, sp\n"
+#ifdef CONFIG_PANIC_STRIP_GPR
+ /*
+ * Check if we are in exception. This is similar to
+ * in_interrupt_context(). Exception bits are 9 LSB, so
+ * we can perform left shift for 23 bits and check if result
+ * is 0 (lsls instruction is setting appropriate flags).
+ */
+ "lsls r6, r2, #23\n"
+ /*
+ * If this is software panic (shift result == 0) then register
+ * r4 and r5 contain additional info about panic.
+ * Clear r6-r11 always and r4, r5 only if this is exception
+ * panic. To clear r4 and r5, 'movne' conditional instruction
+ * is used. It works only when flags contain information that
+ * result was != 0. Itt is pseudo instruction which is used
+ * to make sure we are using correct conditional instructions.
+ */
+ "itt ne\n"
+ "movne r4, #0\n"
+ "movne r5, #0\n"
+ "mov r6, #0\n"
+ "mov r7, #0\n"
+ "mov r8, #0\n"
+ "mov r9, #0\n"
+ "mov r10, #0\n"
+ "mov r11, #0\n"
+#endif
"stmia r0, {r1-r11, lr}\n"
"mov sp, %[pstack]\n"
"bl report_panic\n" : :
@@ -418,6 +456,36 @@ void panic_get_reason(uint32_t *reason, uint32_t *info, uint8_t *exception)
}
#endif
+void panic_assert(const char *func, const char *file, uint16_t line)
+{
+ struct panic_data *pdata = pdata_ptr;
+
+ pdata->magic = PANIC_DATA_MAGIC;
+ pdata->struct_size = sizeof(*pdata);
+ pdata->struct_version = 2;
+ pdata->arch = PANIC_ARCH_CORTEX_M;
+ pdata->flags = 0;
+ pdata->reserved = 0;
+
+ /*
+ * Panic data is cleared by PMIC reset on Nami. HFSR is used because
+ * it's saved to BBRAM by the released RO (before PMIC reset). Bit
+ * assignments are as follows:
+ *
+ * ([31:30] Used for DEBUGEVT and FORCED)
+ * [29:26] Flags
+ * [25:10] Line #
+ * [9:2] Task #
+ * ([1:0] Used for VECTTBLE and reserved)
+ */
+ pdata->cm.hfsr = HFSR_FLAG_ASSERT << 26 | line << 10
+ | (task_get_current() & 0xff) << 2;
+ pdata->cm.regs[3] = (uint32_t)func;
+ pdata->cm.regs[4] = (uint32_t)file;
+
+ panic_reboot();
+}
+
void bus_fault_handler(void)
{
if (!bus_fault_ignored)
diff --git a/core/cortex-m/watchdog.c b/core/cortex-m/watchdog.c
index a67903df62..f9283bbbd7 100644
--- a/core/cortex-m/watchdog.c
+++ b/core/cortex-m/watchdog.c
@@ -7,10 +7,14 @@
#include "common.h"
#include "panic.h"
+#include "system.h"
#include "task.h"
#include "timer.h"
#include "watchdog.h"
+/* Panic data goes at the end of RAM. */
+static struct panic_data * const pdata_ptr = PANIC_DATA_PTR;
+
void __keep watchdog_trace(uint32_t excep_lr, uint32_t excep_sp)
{
uint32_t psp;
@@ -28,6 +32,18 @@ void __keep watchdog_trace(uint32_t excep_lr, uint32_t excep_sp)
panic_set_reason(PANIC_SW_WATCHDOG, stack[6],
(excep_lr & 0xf) == 1 ? 0xff : task_get_current());
+ /* Copy task# to cm.hfsr[9:2]. */
+ pdata_ptr->cm.hfsr = HFSR_FLAG_WATCHDOG << 26
+ | (pdata_ptr->cm.regs[1] & 0xff) << 2;
+
+ /*
+ * Store LR in cm.regs[1] (ipsr). IPSR holds exception# but we don't
+ * need it because the reason (=PANIC_SW_WATCHDOG) is already stored
+ * in cm.regs[3] (r4). Note this overwrites task# in cm.regs[1] stored
+ * by panic_set_reason.
+ */
+ pdata_ptr->cm.regs[1] = stack[5];
+
panic_printf("### WATCHDOG PC=%08x / LR=%08x / pSP=%08x ",
stack[6], stack[5], psp);
if ((excep_lr & 0xf) == 1)
diff --git a/docs/code_reviews.md b/docs/code_reviews.md
new file mode 100644
index 0000000000..df99a231a7
--- /dev/null
+++ b/docs/code_reviews.md
@@ -0,0 +1,33 @@
+# Code Reviews
+
+The platform/ec repository makes use of a code review system that tries to
+evenly distributed code reviews among available reviewers.
+
+## How to request a review
+
+Add `cros-ec-reviewers@google.com` to the reviewer line in Gerrit. A background
+job will come around and replace the `cros-ec-reviewers@google.com` address with
+the next available reviewer in the EC reviewer rotation. This typically takes on
+the order of minutes.
+
+Optionally, you can click the [FIND OWNERS] button in the UI, and select
+`cros-ec-reviewers@google.com`
+
+## When to use review system
+
+If you are modifying code in `common/`, `chip/`, or `core/`, feel free to use
+the `cros-ec-reviewers@google.com` system. It is **never** a requirement to use
+`cros-ec-reviewers@google.com`. You can always request a review from a specific
+person.
+
+## Responsibilities of reviewers
+
+If the selected reviewer is unfamiliar with code in a CL, then that reviewer
+should at least ensure that EC style and paradigms are being followed. Once EC
+styles and paradigms are being followed, then the reviewer can give a +1 and add
+the appropriate domain expert for that section of code.
+
+## How can I join the rotation?
+
+The list of reviewer is at http://google3/chrome/crosinfra/gwsq/ec_reviewers;
+just add your name there.
diff --git a/driver/accelgyro_bmi160.c b/driver/accelgyro_bmi160.c
index 4468e6f6b4..b1652e4b05 100644
--- a/driver/accelgyro_bmi160.c
+++ b/driver/accelgyro_bmi160.c
@@ -1116,8 +1116,10 @@ static int irq_handler(struct motion_sensor_t *s, uint32_t *event)
do {
rv = raw_read32(s->port, s->addr, BMI160_INT_STATUS_0,
&interrupt);
- /* Bail out of this loop if the sensor isn't powered. */
- if (rv == EC_ERROR_NOT_POWERED)
+ /*
+ * Bail out of this loop there was an error reading the register
+ */
+ if (rv)
return rv;
#ifdef CONFIG_GESTURE_SENSOR_BATTERY_TAP
diff --git a/driver/accelgyro_icm426xx.c b/driver/accelgyro_icm426xx.c
new file mode 100644
index 0000000000..40adaaaace
--- /dev/null
+++ b/driver/accelgyro_icm426xx.c
@@ -0,0 +1,953 @@
+/* Copyright 2020 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.
+ */
+
+/**
+ * ICM-426xx accelerometer and gyroscope module for Chrome EC
+ * 3D digital accelerometer & 3D digital gyroscope
+ */
+
+#include "accelgyro.h"
+#include "console.h"
+#include "driver/accelgyro_icm_common.h"
+#include "driver/accelgyro_icm426xx.h"
+#include "hwtimer.h"
+#include "i2c.h"
+#include "math_util.h"
+#include "motion_sense.h"
+#include "spi.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+
+#define CPUTS(outstr) cputs(CC_ACCEL, outstr)
+#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args)
+#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args)
+
+#ifdef CONFIG_ACCEL_FIFO
+volatile uint32_t last_interrupt_timestamp;
+#endif /* CONFIG_ACCEL_FIFO */
+
+static int icm426xx_normalize(const struct motion_sensor_t *s, intv3_t v,
+ const uint8_t *raw)
+{
+ /* sensor data is configured as little-endian */
+ v[X] = (int16_t)UINT16_FROM_BYTE_ARRAY_LE(raw, 0);
+ v[Y] = (int16_t)UINT16_FROM_BYTE_ARRAY_LE(raw, 2);
+ v[Z] = (int16_t)UINT16_FROM_BYTE_ARRAY_LE(raw, 4);
+
+ /* check if data is valid */
+ if (v[X] == ICM426XX_INVALID_DATA &&
+ v[Y] == ICM426XX_INVALID_DATA &&
+ v[Z] == ICM426XX_INVALID_DATA) {
+ return EC_ERROR_INVAL;
+ }
+
+ rotate(v, *s->rot_standard_ref, v);
+
+ return EC_SUCCESS;
+}
+
+static int icm426xx_check_sensor_stabilized(const struct motion_sensor_t *s,
+ uint32_t ts)
+{
+ int32_t rem;
+
+ rem = icm_get_sensor_stabilized(s, ts);
+ if (rem == 0)
+ return EC_SUCCESS;
+ if (rem > 0)
+ return EC_ERROR_BUSY;
+
+ /* rem < 0: reset check since ts has passed stabilize_ts */
+ icm_reset_stabilize_ts(s);
+ return EC_SUCCESS;
+}
+
+/* use FIFO threshold interrupt on INT1 */
+#define ICM426XX_FIFO_INT_EN ICM426XX_FIFO_THS_INT1_EN
+#define ICM426XX_FIFO_INT_STATUS ICM426XX_FIFO_THS_INT
+
+static int __maybe_unused icm426xx_enable_fifo(const struct motion_sensor_t *s,
+ int enable)
+{
+ int val, ret;
+
+ if (enable) {
+ /* enable FIFO interrupts */
+ ret = icm_field_update8(s, ICM426XX_REG_INT_SOURCE0,
+ ICM426XX_FIFO_INT_EN,
+ ICM426XX_FIFO_INT_EN);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ /* flush FIFO data */
+ ret = icm_write8(s, ICM426XX_REG_SIGNAL_PATH_RESET,
+ ICM426XX_FIFO_FLUSH);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ /* set FIFO in streaming mode */
+ ret = icm_write8(s, ICM426XX_REG_FIFO_CONFIG,
+ ICM426XX_FIFO_MODE_STREAM);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ /* workaround: first read of FIFO count is always 0 */
+ ret = icm_read16(s, ICM426XX_REG_FIFO_COUNT, &val);
+ if (ret != EC_SUCCESS)
+ return ret;
+ } else {
+ /* set FIFO in bypass mode */
+ ret = icm_write8(s, ICM426XX_REG_FIFO_CONFIG,
+ ICM426XX_FIFO_MODE_BYPASS);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ /* flush FIFO data */
+ ret = icm_write8(s, ICM426XX_REG_SIGNAL_PATH_RESET,
+ ICM426XX_FIFO_FLUSH);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ /* disable FIFO interrupts */
+ ret = icm_field_update8(s, ICM426XX_REG_INT_SOURCE0,
+ ICM426XX_FIFO_INT_EN, 0);
+ if (ret != EC_SUCCESS)
+ return ret;
+ }
+
+ return EC_SUCCESS;
+}
+
+static int __maybe_unused icm426xx_config_fifo(const struct motion_sensor_t *s,
+ int enable)
+{
+ struct icm_drv_data_t *st = ICM_GET_DATA(s);
+ int mask, val;
+ uint8_t old_fifo_en;
+ int ret;
+
+ switch (s->type) {
+ case MOTIONSENSE_TYPE_ACCEL:
+ mask = ICM426XX_FIFO_ACCEL_EN;
+ break;
+ case MOTIONSENSE_TYPE_GYRO:
+ mask = ICM426XX_FIFO_GYRO_EN;
+ break;
+ default:
+ return EC_ERROR_INVAL;
+ }
+ /* temperature data has to be always present in the FIFO */
+ mask |= ICM426XX_FIFO_TEMP_EN;
+
+ val = enable ? mask : 0;
+
+ mutex_lock(s->mutex);
+
+ ret = icm_field_update8(s, ICM426XX_REG_FIFO_CONFIG1, mask, val);
+ if (ret != EC_SUCCESS)
+ goto out_unlock;
+
+ old_fifo_en = st->fifo_en;
+ if (enable)
+ st->fifo_en |= BIT(s->type);
+ else
+ st->fifo_en &= ~BIT(s->type);
+
+ if (!old_fifo_en && st->fifo_en) {
+ /* 1st sensor enabled => turn FIFO on */
+ ret = icm426xx_enable_fifo(s, 1);
+ if (ret != EC_SUCCESS)
+ goto out_unlock;
+ } else if (old_fifo_en && !st->fifo_en) {
+ /* last sensor disabled => turn FIFO off */
+ ret = icm426xx_enable_fifo(s, 0);
+ if (ret != EC_SUCCESS)
+ goto out_unlock;
+ }
+
+out_unlock:
+ mutex_unlock(s->mutex);
+ return ret;
+}
+
+static void __maybe_unused icm426xx_push_fifo_data(struct motion_sensor_t *s,
+ const uint8_t *raw, uint32_t ts)
+{
+ intv3_t v;
+ struct ec_response_motion_sensor_data vect;
+ int ret;
+
+ if (s == NULL)
+ return;
+
+ ret = icm426xx_normalize(s, v, raw);
+ if (ret == EC_SUCCESS) {
+ vect.data[X] = v[X];
+ vect.data[Y] = v[Y];
+ vect.data[Z] = v[Z];
+ vect.flags = 0;
+ vect.sensor_num = s - motion_sensors;
+ motion_sense_fifo_add_data(&vect, s, 3, ts);
+ }
+}
+
+/* division that round to the nearest integer */
+static int round_divide(int64_t dividend, int divisor)
+{
+ return (dividend > 0) ^ (divisor > 0) ?
+ (dividend - divisor / 2) / divisor :
+ (dividend + divisor / 2) / divisor;
+}
+
+static int __maybe_unused icm426xx_load_fifo(struct motion_sensor_t *s,
+ uint32_t ts)
+{
+ struct icm_drv_data_t *st = ICM_GET_DATA(s);
+ int count, i, size;
+ const uint8_t *accel, *gyro;
+ int ret;
+
+ ret = icm_read16(s, ICM426XX_REG_FIFO_COUNT, &count);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ if (count <= 0)
+ return EC_ERROR_INVAL;
+
+ /* flush FIFO if buffer is not large enough */
+ if (count > ICM_FIFO_BUFFER) {
+ CPRINTS("It should not happen, the EC is too slow for the ODR");
+ ret = icm_write8(s, ICM426XX_REG_SIGNAL_PATH_RESET,
+ ICM426XX_FIFO_FLUSH);
+ if (ret != EC_SUCCESS)
+ return ret;
+ return EC_ERROR_OVERFLOW;
+ }
+
+ ret = icm_read_n(s, ICM426XX_REG_FIFO_DATA, st->fifo_buffer, count);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ for (i = 0; i < count; i += size) {
+ size = icm_fifo_decode_packet(&st->fifo_buffer[i],
+ &accel, &gyro);
+ /* exit if error or FIFO is empty */
+ if (size <= 0)
+ return -size;
+ if (accel != NULL) {
+ ret = icm426xx_check_sensor_stabilized(st->accel, ts);
+ if (ret == EC_SUCCESS)
+ icm426xx_push_fifo_data(st->accel, accel, ts);
+ }
+ if (gyro != NULL) {
+ ret = icm426xx_check_sensor_stabilized(st->gyro, ts);
+ if (ret == EC_SUCCESS)
+ icm426xx_push_fifo_data(st->gyro, gyro, ts);
+ }
+ }
+
+ return EC_SUCCESS;
+}
+
+#ifdef CONFIG_ACCEL_INTERRUPTS
+
+/**
+ * icm426xx_interrupt - called when the sensor activates the interrupt line.
+ *
+ * This is a "top half" interrupt handler, it just asks motion sense ask
+ * to schedule the "bottom half", ->icm426xx_irq_handler().
+ */
+void icm426xx_interrupt(enum gpio_signal signal)
+{
+#ifdef CONFIG_ACCEL_FIFO
+ last_interrupt_timestamp = __hw_clock_source_read();
+#endif /* CONFIG_ACCEL_FIFO */
+
+ task_set_event(TASK_ID_MOTIONSENSE,
+ CONFIG_ACCELGYRO_ICM426XX_INT_EVENT, 0);
+}
+
+/**
+ * icm426xx_irq_handler - bottom half of the interrupt stack.
+ * Ran from the motion_sense task, finds the events that raised the interrupt.
+ */
+static int icm426xx_irq_handler(struct motion_sensor_t *s, uint32_t *event)
+{
+ int status;
+ int ret;
+
+ if ((s->type != MOTIONSENSE_TYPE_ACCEL) ||
+ (!(*event & CONFIG_ACCELGYRO_ICM426XX_INT_EVENT)))
+ return EC_ERROR_NOT_HANDLED;
+
+ mutex_lock(s->mutex);
+
+ /* read and clear interrupt status */
+ ret = icm_read8(s, ICM426XX_REG_INT_STATUS, &status);
+ if (ret != EC_SUCCESS)
+ goto out_unlock;
+
+#ifdef CONFIG_ACCEL_FIFO
+ if (status & ICM426XX_FIFO_INT_STATUS)
+ ret = icm426xx_load_fifo(s, last_interrupt_timestamp);
+#endif /* CONFIG_ACCEL_FIFO */
+
+out_unlock:
+ mutex_unlock(s->mutex);
+ return ret;
+}
+
+static int icm426xx_config_interrupt(const struct motion_sensor_t *s)
+{
+ struct icm_drv_data_t *st = ICM_GET_DATA(s);
+ int val, ret;
+
+ /* configure INT1 pin */
+ val = ICM426XX_INT1_PUSH_PULL | ICM426XX_INT1_ACTIVE_HIGH;
+
+ ret = icm_write8(s, ICM426XX_REG_INT_CONFIG, val);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ /* deassert async reset for proper INT pin operation */
+ ret = icm_field_update8(s, ICM426XX_REG_INT_CONFIG1,
+ ICM426XX_INT_ASYNC_RESET, 0);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+#ifdef CONFIG_ACCEL_FIFO
+ /*
+ * configure FIFO:
+ * - enable FIFO partial read
+ * - enable continuous watermark interrupt
+ * - disable all FIFO en bits
+ */
+ val = ICM426XX_FIFO_PARTIAL_READ | ICM426XX_FIFO_WM_GT_TH;
+ ret = icm_field_update8(s, ICM426XX_REG_FIFO_CONFIG1,
+ GENMASK(6, 5) | ICM426XX_FIFO_EN_MASK,
+ val);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ /* clear internal FIFO enable bits tracking */
+ st->fifo_en = 0;
+
+ /* set FIFO watermark to 1 data packet (8 bytes) */
+ ret = icm_write16(s, ICM426XX_REG_FIFO_WATERMARK, 8);
+ if (ret != EC_SUCCESS)
+ return ret;
+#endif /* CONFIG_ACCEL_FIFO */
+
+ return ret;
+}
+
+#endif /* CONFIG_ACCEL_INTERRUPTS */
+
+static int icm426xx_enable_sensor(const struct motion_sensor_t *s, int enable)
+{
+ uint32_t delay, stop_delay;
+ int32_t rem;
+ uint8_t mask, val;
+ int ret;
+
+ switch (s->type) {
+ case MOTIONSENSE_TYPE_ACCEL:
+ mask = ICM426XX_ACCEL_MODE_MASK;
+ if (enable) {
+ delay = ICM426XX_ACCEL_START_TIME;
+ stop_delay = ICM426XX_ACCEL_STOP_TIME;
+ val = ICM426XX_ACCEL_MODE(ICM426XX_MODE_LOW_POWER);
+ } else {
+ delay = ICM426XX_ACCEL_STOP_TIME;
+ val = ICM426XX_ACCEL_MODE(ICM426XX_MODE_OFF);
+ }
+ break;
+ case MOTIONSENSE_TYPE_GYRO:
+ mask = ICM426XX_GYRO_MODE_MASK;
+ if (enable) {
+ delay = ICM426XX_GYRO_START_TIME;
+ stop_delay = ICM426XX_GYRO_STOP_TIME;
+ val = ICM426XX_GYRO_MODE(ICM426XX_MODE_LOW_NOISE);
+ } else {
+ delay = ICM426XX_GYRO_STOP_TIME;
+ val = ICM426XX_GYRO_MODE(ICM426XX_MODE_OFF);
+ }
+ break;
+ default:
+ return EC_ERROR_INVAL;
+ }
+
+ /* check stop delay and sleep if required */
+ if (enable) {
+ rem = icm_get_sensor_stabilized(s, __hw_clock_source_read());
+ /* rem > stop_delay means counter rollover */
+ if (rem > 0 && rem <= stop_delay)
+ usleep(rem);
+ }
+
+ mutex_lock(s->mutex);
+
+ ret = icm_field_update8(s, ICM426XX_REG_PWR_MGMT0, mask, val);
+ if (ret == EC_SUCCESS) {
+ icm_set_stabilize_ts(s, delay);
+ /* when turning sensor on block any register write for 200 us */
+ if (enable)
+ usleep(200);
+ }
+
+ mutex_unlock(s->mutex);
+
+ return ret;
+}
+
+static int icm426xx_set_data_rate(const struct motion_sensor_t *s, int rate,
+ int rnd)
+{
+ struct accelgyro_saved_data_t *data = ICM_GET_SAVED_DATA(s);
+ int reg, ret, reg_val;
+ int normalized_rate;
+ int max_rate, min_rate;
+
+ switch (s->type) {
+ case MOTIONSENSE_TYPE_ACCEL:
+ reg = ICM426XX_REG_ACCEL_CONFIG0;
+ min_rate = ICM426XX_ACCEL_MIN_FREQ;
+ max_rate = ICM426XX_ACCEL_MAX_FREQ;
+ break;
+ case MOTIONSENSE_TYPE_GYRO:
+ reg = ICM426XX_REG_GYRO_CONFIG0;
+ min_rate = ICM426XX_GYRO_MIN_FREQ;
+ max_rate = ICM426XX_GYRO_MAX_FREQ;
+ break;
+ default:
+ return EC_RES_INVALID_PARAM;
+ }
+
+ /* normalize the rate */
+ reg_val = ICM426XX_ODR_TO_REG(rate);
+ normalized_rate = ICM426XX_REG_TO_ODR(reg_val);
+
+ /* round up the rate */
+ if (rnd && (normalized_rate < rate)) {
+ reg_val = ICM426XX_ODR_REG_UP(reg_val);
+ normalized_rate = ICM426XX_REG_TO_ODR(reg_val);
+ }
+
+ if (rate > 0) {
+ if ((normalized_rate < min_rate) ||
+ (normalized_rate > max_rate))
+ return EC_RES_INVALID_PARAM;
+ }
+
+ if (rate == 0) {
+#ifdef CONFIG_ACCEL_FIFO
+ /* disable data in FIFO */
+ icm426xx_config_fifo(s, 0);
+#endif /* CONFIG_ACCEL_FIFO */
+ /* disable sensor */
+ ret = icm426xx_enable_sensor(s, 0);
+ data->odr = 0;
+ return ret;
+ }
+
+ mutex_lock(s->mutex);
+
+ ret = icm_field_update8(s, reg, ICM426XX_ODR_MASK,
+ ICM426XX_ODR(reg_val));
+ if (ret != EC_SUCCESS)
+ goto out_unlock;
+
+ mutex_unlock(s->mutex);
+
+ if (data->odr == 0) {
+ /* enable sensor */
+ ret = icm426xx_enable_sensor(s, 1);
+ if (ret)
+ return ret;
+#ifdef CONFIG_ACCEL_FIFO
+ /* enable data in FIFO */
+ icm426xx_config_fifo(s, 1);
+#endif /* CONFIG_ACCEL_FIFO */
+ }
+
+ data->odr = normalized_rate;
+ return EC_SUCCESS;
+
+out_unlock:
+ mutex_unlock(s->mutex);
+ return ret;
+}
+
+static int icm426xx_set_range(const struct motion_sensor_t *s, int range,
+ int rnd)
+{
+ struct accelgyro_saved_data_t *data = ICM_GET_SAVED_DATA(s);
+ int reg, ret, reg_val;
+ int newrange;
+
+ switch (s->type) {
+ case MOTIONSENSE_TYPE_ACCEL:
+ reg = ICM426XX_REG_ACCEL_CONFIG0;
+
+ reg_val = ICM426XX_ACCEL_FS_TO_REG(range);
+ newrange = ICM426XX_ACCEL_REG_TO_FS(reg_val);
+
+ if (rnd && (newrange < range) && (reg_val > 0)) {
+ reg_val--;
+ newrange = ICM426XX_ACCEL_REG_TO_FS(reg_val);
+ }
+
+ if (newrange > ICM426XX_ACCEL_FS_MAX_VAL) {
+ newrange = ICM426XX_ACCEL_FS_MAX_VAL;
+ reg_val = ICM426XX_ACCEL_FS_TO_REG(range);
+ }
+
+ break;
+ case MOTIONSENSE_TYPE_GYRO:
+ reg = ICM426XX_REG_GYRO_CONFIG0;
+
+ reg_val = ICM426XX_GYRO_FS_TO_REG(range);
+ newrange = ICM426XX_GYRO_REG_TO_FS(reg_val);
+
+ if (rnd && (newrange < range) && (reg_val > 0)) {
+ reg_val--;
+ newrange = ICM426XX_GYRO_REG_TO_FS(reg_val);
+ }
+
+ if (newrange > ICM426XX_GYRO_FS_MAX_VAL) {
+ newrange = ICM426XX_GYRO_FS_MAX_VAL;
+ reg_val = ICM426XX_GYRO_FS_TO_REG(newrange);
+ }
+
+ break;
+ default:
+ return EC_RES_INVALID_PARAM;
+ }
+
+ mutex_lock(s->mutex);
+
+ ret = icm_field_update8(s, reg, ICM426XX_FS_MASK,
+ ICM426XX_FS_SEL(reg_val));
+ if (ret == EC_SUCCESS)
+ data->range = newrange;
+
+ mutex_unlock(s->mutex);
+
+ return ret;
+}
+
+static int icm426xx_get_hw_offset(const struct motion_sensor_t *s,
+ intv3_t offset)
+{
+ uint8_t raw[5];
+ int i, ret;
+
+ switch (s->type) {
+ case MOTIONSENSE_TYPE_ACCEL:
+ mutex_lock(s->mutex);
+ ret = icm_read_n(s, ICM426XX_REG_OFFSET_USER4,
+ raw, sizeof(raw));
+ mutex_unlock(s->mutex);
+ if (ret != EC_SUCCESS)
+ return ret;
+ /*
+ * raw[0]: Accel X[11:8] | gyro Z[11:8]
+ * raw[1]: Accel X[0:7]
+ * raw[2]: Accel Y[7:0]
+ * raw[3]: Accel Z[11:8] | Accel Y[11:8]
+ * raw[4]: Accel Z[7:0]
+ */
+ offset[X] = (((int)raw[0] << 4) & ~GENMASK(7, 0)) | raw[1];
+ offset[Y] = (((int)raw[3] << 8) & ~GENMASK(7, 0)) | raw[2];
+ offset[Z] = (((int)raw[3] << 4) & ~GENMASK(7, 0)) | raw[4];
+ break;
+ case MOTIONSENSE_TYPE_GYRO:
+ mutex_lock(s->mutex);
+ ret = icm_read_n(s, ICM426XX_REG_OFFSET_USER0,
+ raw, sizeof(raw));
+ mutex_unlock(s->mutex);
+ if (ret != EC_SUCCESS)
+ return ret;
+ /*
+ * raw[0]: Gyro X[7:0]
+ * raw[1]: Gyro Y[11:8] | Gyro X[11:8]
+ * raw[2]: Gyro Y[7:0]
+ * raw[3]: Gyro Z[7:0]
+ * raw[4]: Accel X[11:8] | gyro Z[11:8]
+ */
+ offset[X] = (((int)raw[1] << 8) & ~GENMASK(7, 0)) | raw[0];
+ offset[Y] = (((int)raw[1] << 4) & ~GENMASK(7, 0)) | raw[2];
+ offset[Z] = (((int)raw[4] << 8) & ~GENMASK(7, 0)) | raw[3];
+ break;
+ default:
+ return EC_ERROR_INVAL;
+ }
+
+ /* Extend sign-bit of 12 bits signed values */
+ for (i = X; i <= Z; ++i)
+ offset[i] = sign_extend(offset[i], 11);
+
+ return EC_SUCCESS;
+}
+
+static int icm426xx_set_hw_offset(const struct motion_sensor_t *s,
+ intv3_t offset)
+{
+ int i, val, ret;
+
+ /* value is 12 bits signed maximum */
+ for (i = X; i <= Z; ++i) {
+ if (offset[i] > 2047)
+ offset[i] = 2047;
+ else if (offset[i] < -2048)
+ offset[i] = -2048;
+ }
+
+ mutex_lock(s->mutex);
+
+ switch (s->type) {
+ case MOTIONSENSE_TYPE_ACCEL:
+ /* Accel X[11:8] | gyro Z[11:8] */
+ val = (offset[X] >> 4) & GENMASK(7, 4);
+ ret = icm_field_update8(s, ICM426XX_REG_OFFSET_USER4,
+ GENMASK(7, 4), val);
+ if (ret != EC_SUCCESS)
+ goto out_unlock;
+
+ /* Accel X[7:0] */
+ val = offset[X] & GENMASK(7, 0);
+ ret = icm_write8(s, ICM426XX_REG_OFFSET_USER5, val);
+ if (ret != EC_SUCCESS)
+ goto out_unlock;
+
+ /* Accel Y[7:0] */
+ val = offset[Y] & GENMASK(7, 0);
+ ret = icm_write8(s, ICM426XX_REG_OFFSET_USER6, val);
+ if (ret != EC_SUCCESS)
+ goto out_unlock;
+
+ /* Accel Z[11:8] | Accel Y[11:8] */
+ val = ((offset[Z] >> 4) & GENMASK(7, 4)) |
+ ((offset[Y] >> 8) & GENMASK(3, 0));
+ ret = icm_write8(s, ICM426XX_REG_OFFSET_USER7, val);
+ if (ret != EC_SUCCESS)
+ goto out_unlock;
+
+ /* Accel Z[7:0] */
+ val = offset[Z] & GENMASK(7, 0);
+ ret = icm_write8(s, ICM426XX_REG_OFFSET_USER8, val);
+ if (ret != EC_SUCCESS)
+ goto out_unlock;
+ break;
+
+ case MOTIONSENSE_TYPE_GYRO:
+ /* Gyro X[7:0] */
+ val = offset[X] & GENMASK(7, 0);
+ ret = icm_write8(s, ICM426XX_REG_OFFSET_USER0, val);
+ if (ret != EC_SUCCESS)
+ goto out_unlock;
+
+ /* Gyro Y[11:8] | Gyro X[11:8] */
+ val = ((offset[Y] >> 4) & GENMASK(7, 4)) |
+ ((offset[X] >> 8) & GENMASK(3, 0));
+ ret = icm_write8(s, ICM426XX_REG_OFFSET_USER1, val);
+ if (ret != EC_SUCCESS)
+ goto out_unlock;
+
+ /* Gyro Y[7:0] */
+ val = offset[Y] & GENMASK(7, 0);
+ ret = icm_write8(s, ICM426XX_REG_OFFSET_USER2, val);
+ if (ret != EC_SUCCESS)
+ goto out_unlock;
+
+ /* Gyro Z[7:0] */
+ val = offset[Z] & GENMASK(7, 0);
+ ret = icm_write8(s, ICM426XX_REG_OFFSET_USER3, val);
+ if (ret != EC_SUCCESS)
+ goto out_unlock;
+
+ /* Accel X[11:8] | gyro Z[11:8] */
+ val = (offset[Z] >> 8) & GENMASK(3, 0);
+ ret = icm_field_update8(s, ICM426XX_REG_OFFSET_USER4,
+ GENMASK(3, 0), val);
+ if (ret != EC_SUCCESS)
+ goto out_unlock;
+ break;
+
+ default:
+ ret = EC_ERROR_INVAL;
+ break;
+ }
+
+out_unlock:
+ mutex_unlock(s->mutex);
+ return ret;
+}
+
+static int icm426xx_set_offset(const struct motion_sensor_t *s,
+ const int16_t *offset, int16_t temp)
+{
+ intv3_t v = { offset[X], offset[Y], offset[Z] };
+ int div1, div2;
+ int i;
+
+ /* rotate back to chip frame */
+ rotate_inv(v, *s->rot_standard_ref, v);
+
+ /* convert raw data to hardware offset units */
+ switch (s->type) {
+ case MOTIONSENSE_TYPE_ACCEL:
+ /* hardware offset is 1/2048g /LSB, EC offset 1/1024g /LSB. */
+ div1 = 2;
+ div2 = 1;
+ break;
+ case MOTIONSENSE_TYPE_GYRO:
+ /* hardware offset is 1/32dps /LSB, EC offset 1/1024dps /LSB. */
+ div1 = 1;
+ div2 = 32;
+ break;
+ default:
+ return EC_ERROR_INVAL;
+ }
+ for (i = X; i <= Z; ++i)
+ v[i] = round_divide(v[i] * div1, div2);
+
+ return icm426xx_set_hw_offset(s, v);
+}
+
+static int icm426xx_get_offset(const struct motion_sensor_t *s, int16_t *offset,
+ int16_t *temp)
+{
+ intv3_t v;
+ int div1, div2;
+ int i, ret;
+
+ ret = icm426xx_get_hw_offset(s, v);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ /* transform offset to raw data */
+ switch (s->type) {
+ case MOTIONSENSE_TYPE_ACCEL:
+ /* hardware offset is 1/2048g /LSB, EC offset 1/1024g /LSB. */
+ div1 = 1;
+ div2 = 2;
+ break;
+ case MOTIONSENSE_TYPE_GYRO:
+ /* hardware offset is 1/32dps /LSB, EC offset 1/1024dps /LSB. */
+ div1 = 32;
+ div2 = 1;
+ break;
+ default:
+ return EC_ERROR_INVAL;
+ }
+ for (i = X; i <= Z; ++i)
+ v[i] = round_divide(v[i] * div1, div2);
+
+ rotate(v, *s->rot_standard_ref, v);
+ offset[X] = v[X];
+ offset[Y] = v[Y];
+ offset[Z] = v[Z];
+ *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP;
+ return EC_SUCCESS;
+}
+
+static int icm426xx_read(const struct motion_sensor_t *s, intv3_t v)
+{
+ uint8_t raw[6];
+ int reg, ret;
+
+ switch (s->type) {
+ case MOTIONSENSE_TYPE_ACCEL:
+ reg = ICM426XX_REG_ACCEL_DATA_XYZ;
+ break;
+ case MOTIONSENSE_TYPE_GYRO:
+ reg = ICM426XX_REG_GYRO_DATA_XYZ;
+ break;
+ default:
+ return EC_ERROR_INVAL;
+ }
+
+ /* read data registers if sensor is stabilized */
+ mutex_lock(s->mutex);
+
+ ret = icm426xx_check_sensor_stabilized(s, __hw_clock_source_read());
+ if (ret == EC_SUCCESS)
+ ret = icm_read_n(s, reg, raw, sizeof(raw));
+
+ mutex_unlock(s->mutex);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ ret = icm426xx_normalize(s, v, raw);
+ /* if data is invalid return the previous read data */
+ if (ret != EC_SUCCESS) {
+ if (v != s->raw_xyz)
+ memcpy(v, s->raw_xyz, sizeof(s->raw_xyz));
+ }
+
+ return EC_SUCCESS;
+}
+
+static int icm426xx_init_config(const struct motion_sensor_t *s)
+{
+ uint8_t mask, val;
+ int ret;
+
+ /*
+ * serial bus setup (i2c or spi)
+ *
+ * Do not check result for INTF_CONFIG6, since it can induce
+ * interferences on the bus.
+ */
+
+ ret = 0;
+#ifdef I2C_PORT_ACCEL
+ icm_field_update8(s, ICM426XX_REG_INTF_CONFIG6,
+ ICM426XX_INTF_CONFIG6_MASK,
+ ICM426XX_I3C_EN);
+ ret = icm_field_update8(s, ICM426XX_REG_INTF_CONFIG4,
+ ICM426XX_I3C_BUS_MODE,
+ 0);
+#endif
+ if (ret)
+ return ret;
+
+ ret = 0;
+#ifdef I2C_PORT_ACCEL
+ ret = icm_field_update8(s, ICM426XX_REG_DRIVE_CONFIG,
+ ICM426XX_DRIVE_CONFIG_MASK,
+ ICM426XX_I2C_SLEW_RATE(ICM426XX_SLEW_RATE_12NS_36NS) |
+ ICM426XX_SPI_SLEW_RATE(ICM426XX_SLEW_RATE_12NS_36NS));
+#endif
+ if (ret)
+ return ret;
+
+ /*
+ * Use invalid value in registers and FIFO.
+ * Data registers in little-endian format.
+ * Disable unused serial interface.
+ */
+ mask = ICM426XX_DATA_CONF_MASK | ICM426XX_UI_SIFS_CFG_MASK;
+ val = 0;
+#ifdef I2C_PORT_ACCEL
+ val |= ICM426XX_UI_SIFS_CFG_SPI_DIS;
+#endif
+
+ ret = icm_field_update8(s, ICM426XX_REG_INTF_CONFIG0, mask, val);
+ if (ret)
+ return ret;
+
+ /* set accel oscillator to RC clock to avoid bad transition with PLL */
+ return icm_field_update8(s, ICM426XX_REG_INTF_CONFIG1,
+ ICM426XX_ACCEL_LP_CLK_SEL,
+ ICM426XX_ACCEL_LP_CLK_SEL);
+}
+
+static int icm426xx_init(const struct motion_sensor_t *s)
+{
+ struct accelgyro_saved_data_t *saved_data = ICM_GET_SAVED_DATA(s);
+ struct icm_drv_data_t *st = ICM_GET_DATA(s);
+ int mask, val;
+ int ret;
+
+ mutex_lock(s->mutex);
+
+ /* manually force register bank to 0 */
+ st->bank = 0;
+ ret = icm_write8(s, ICM426XX_REG_BANK_SEL, ICM426XX_BANK_SEL(0));
+ if (ret)
+ goto out_unlock;
+
+ /* detect chip using whoami */
+ ret = icm_read8(s, ICM426XX_REG_WHO_AM_I, &val);
+ if (ret)
+ goto out_unlock;
+
+ if (val != ICM426XX_CHIP_ICM40608 && val != ICM426XX_CHIP_ICM42605) {
+ CPRINTS("Unknown WHO_AM_I: 0x%02x", val);
+ ret = EC_ERROR_ACCESS_DENIED;
+ goto out_unlock;
+ }
+
+ /* first time init done only for 1st sensor (accel) */
+ if (s->type == MOTIONSENSE_TYPE_ACCEL) {
+ /* reset the chip and verify it is ready */
+ ret = icm_write8(s, ICM426XX_REG_DEVICE_CONFIG,
+ ICM426XX_SOFT_RESET_CONFIG);
+ if (ret)
+ goto out_unlock;
+ msleep(1);
+
+ ret = icm_read8(s, ICM426XX_REG_INT_STATUS, &val);
+ if (ret)
+ goto out_unlock;
+ if (!(val & ICM426XX_RESET_DONE_INT)) {
+ ret = EC_ERROR_ACCESS_DENIED;
+ goto out_unlock;
+ }
+
+ /* configure sensor */
+ ret = icm426xx_init_config(s);
+ if (ret)
+ goto out_unlock;
+
+#ifdef CONFIG_ACCEL_INTERRUPTS
+ ret = icm426xx_config_interrupt(s);
+ if (ret)
+ goto out_unlock;
+#endif
+ }
+
+ saved_data->odr = 0;
+
+ /* set sensor filter */
+ switch (s->type) {
+ case MOTIONSENSE_TYPE_ACCEL:
+ mask = ICM426XX_ACCEL_UI_FILT_MASK;
+ val = ICM426XX_ACCEL_UI_FILT_BW(ICM426XX_FILTER_BW_AVG_16X);
+#ifdef CONFIG_ACCEL_FIFO
+ st->accel = (struct motion_sensor_t *)s;
+#endif /* CONFIG_ACCEL_FIFO */
+ break;
+ case MOTIONSENSE_TYPE_GYRO:
+ mask = ICM426XX_GYRO_UI_FILT_MASK;
+ val = ICM426XX_GYRO_UI_FILT_BW(ICM426XX_FILTER_BW_ODR_DIV_2);
+#ifdef CONFIG_ACCEL_FIFO
+ st->gyro = (struct motion_sensor_t *)s;
+#endif /* CONFIG_ACCEL_FIFO */
+ break;
+ default:
+ ret = EC_ERROR_INVAL;
+ goto out_unlock;
+ }
+ ret = icm_field_update8(s, ICM426XX_REG_GYRO_ACCEL_CONFIG0, mask, val);
+ if (ret != EC_SUCCESS)
+ goto out_unlock;
+
+ mutex_unlock(s->mutex);
+
+ return sensor_init_done(s);
+
+out_unlock:
+ mutex_unlock(s->mutex);
+ return ret;
+}
+
+const struct accelgyro_drv icm426xx_drv = {
+ .init = icm426xx_init,
+ .read = icm426xx_read,
+ .set_range = icm426xx_set_range,
+ .get_range = icm_get_range,
+ .get_resolution = icm_get_resolution,
+ .set_data_rate = icm426xx_set_data_rate,
+ .get_data_rate = icm_get_data_rate,
+ .set_offset = icm426xx_set_offset,
+ .get_offset = icm426xx_get_offset,
+#ifdef CONFIG_ACCEL_INTERRUPTS
+ .irq_handler = icm426xx_irq_handler,
+#endif
+};
diff --git a/driver/accelgyro_icm426xx.h b/driver/accelgyro_icm426xx.h
new file mode 100644
index 0000000000..0c1949e3f0
--- /dev/null
+++ b/driver/accelgyro_icm426xx.h
@@ -0,0 +1,266 @@
+/* Copyright 2020 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.
+ */
+
+/* ICM-426xx accelerometer and gyroscope for Chrome EC */
+
+#ifndef __CROS_EC_ACCELGYRO_ICM426XX_H
+#define __CROS_EC_ACCELGYRO_ICM426XX_H
+
+#include "accelgyro.h"
+#include "common.h"
+
+/*
+ * 8-bit address is 110100X0b. Where 'X' is determined
+ * by the logic level on pin AP_AD0.
+ */
+#define ICM426XX_ADDR0_FLAGS (0x68 << 1)
+#define ICM426XX_ADDR1_FLAGS (0x69 << 1)
+
+/* Min and Max sampling frequency in mHz */
+#define ICM426XX_ACCEL_MIN_FREQ 3125
+#define ICM426XX_ACCEL_MAX_FREQ 100000
+#define ICM426XX_GYRO_MIN_FREQ 12500
+#define ICM426XX_GYRO_MAX_FREQ 100000
+/* Min and Max Accel FS in G */
+#define ICM426XX_ACCEL_FS_MIN_VAL 2
+#define ICM426XX_ACCEL_FS_MAX_VAL 16
+
+/* Min and Max Gyro FS in dps */
+#define ICM426XX_GYRO_FS_MIN_VAL 125
+#define ICM426XX_GYRO_FS_MAX_VAL 2000
+
+/* accel stabilization time in us */
+#define ICM426XX_ACCEL_START_TIME 20000
+#define ICM426XX_ACCEL_STOP_TIME 0
+
+/* gyro stabilization time in us */
+#define ICM426XX_GYRO_START_TIME 60000
+#define ICM426XX_GYRO_STOP_TIME 150000
+
+/* Reg value from Accel FS in G */
+#define ICM426XX_ACCEL_FS_TO_REG(_fs) ((_fs) < 2 ? 3 : \
+ (_fs) > 16 ? 0 : \
+ 3 - __fls((_fs) / 2))
+
+/* Accel FSR in G from Reg value */
+#define ICM426XX_ACCEL_REG_TO_FS(_reg) ((1 << (3 - (_reg))) * 2)
+
+/* Reg value from Gyro FS in dps */
+#define ICM426XX_GYRO_FS_TO_REG(_fs) ((_fs) < 125 ? 4 : \
+ (_fs) > 2000 ? 0 : \
+ 4 - __fls((_fs) / 125))
+
+/* Gyro FSR in dps from Reg value */
+#define ICM426XX_GYRO_REG_TO_FS(_reg) ((1 << (4 - (_reg))) * 125)
+
+/* Reg value from ODR in mHz */
+#define ICM426XX_ODR_TO_REG(_odr) ((_odr) <= 200000 ? \
+ 13 - __fls((_odr) / 3125) : \
+ (_odr) < 500000 ? 7 : \
+ (_odr) < 1000000 ? 15 : \
+ 6 - __fls((_odr) / 1000000))
+
+/* ODR in mHz from Reg value */
+#define ICM426XX_REG_TO_ODR(_reg) ((_reg) == 15 ? 500000 : \
+ (_reg) >= 7 ? \
+ (1 << (13 - (_reg))) * 3125 : \
+ (1 << (6 - (_reg))) * 1000000)
+
+/* Reg value for the next higher ODR */
+#define ICM426XX_ODR_REG_UP(_reg) ((_reg) == 15 ? 6 : \
+ (_reg) == 7 ? 15 : \
+ (_reg) - 1)
+
+/*
+ * Register addresses are virtual address on 16 bits.
+ * MSB is coding register bank and LSB real register address.
+ * ex: bank 4, register 1F => 0x041F
+ */
+#define ICM426XX_REG_DEVICE_CONFIG 0x0011
+#define ICM426XX_SOFT_RESET_CONFIG BIT(0)
+
+enum icm426xx_slew_rate {
+ ICM426XX_SLEW_RATE_20NS_60NS,
+ ICM426XX_SLEW_RATE_12NS_36NS,
+ ICM426XX_SLEW_RATE_6NS_18NS,
+ ICM426XX_SLEW_RATE_4NS_12NS,
+ ICM426XX_SLEW_RATE_2NS_6NS,
+ ICM426XX_SLEW_RATE_INF_2NS,
+};
+#define ICM426XX_REG_DRIVE_CONFIG 0x0013
+#define ICM426XX_DRIVE_CONFIG_MASK GENMASK(5, 0)
+#define ICM426XX_I2C_SLEW_RATE(_s) (((_s) & 0x07) << 3)
+#define ICM426XX_SPI_SLEW_RATE(_s) ((_s) & 0x07)
+
+/* default int configuration is pulsed mode, open drain, and active low */
+#define ICM426XX_REG_INT_CONFIG 0x0014
+#define ICM426XX_INT2_LATCHED BIT(5)
+#define ICM426XX_INT2_PUSH_PULL BIT(4)
+#define ICM426XX_INT2_ACTIVE_HIGH BIT(3)
+#define ICM426XX_INT1_LATCHED BIT(2)
+#define ICM426XX_INT1_PUSH_PULL BIT(1)
+#define ICM426XX_INT1_ACTIVE_HIGH BIT(0)
+
+#define ICM426XX_REG_FIFO_CONFIG 0x0016
+#define ICM426XX_FIFO_MODE_BYPASS (0x00 << 6)
+#define ICM426XX_FIFO_MODE_STREAM (0x01 << 6)
+#define ICM426XX_FIFO_MODE_STOP_FULL (0x02 << 6)
+
+/* data are 16 bits */
+#define ICM426XX_REG_TEMP_DATA 0x001D
+/* X + Y + Z: 3 * 16 bits */
+#define ICM426XX_REG_ACCEL_DATA_XYZ 0x001F
+#define ICM426XX_REG_GYRO_DATA_XYZ 0x0025
+
+#define ICM426XX_INVALID_DATA -32768
+
+#define ICM426XX_REG_INT_STATUS 0x002D
+#define ICM426XX_UI_FSYNC_INT BIT(6)
+#define ICM426XX_PLL_RDY_INT BIT(5)
+#define ICM426XX_RESET_DONE_INT BIT(4)
+#define ICM426XX_DATA_RDY_INT BIT(3)
+#define ICM426XX_FIFO_THS_INT BIT(2)
+#define ICM426XX_FIFO_FULL_INT BIT(1)
+#define ICM426XX_AGC_RDY_INT BIT(0)
+
+/* FIFO count is 16 bits */
+#define ICM426XX_REG_FIFO_COUNT 0x002E
+#define ICM426XX_REG_FIFO_DATA 0x0030
+
+#define ICM426XX_REG_SIGNAL_PATH_RESET 0x004B
+#define ICM426XX_ABORT_AND_RESET BIT(3)
+#define ICM426XX_TMST_STROBE BIT(2)
+#define ICM426XX_FIFO_FLUSH BIT(1)
+
+#define ICM426XX_REG_INTF_CONFIG0 0x004C
+#define ICM426XX_DATA_CONF_MASK GENMASK(7, 4)
+#define ICM426XX_FIFO_HOLD_LAST_DATA BIT(7)
+#define ICM426XX_FIFO_COUNT_REC BIT(6)
+#define ICM426XX_FIFO_COUNT_BE BIT(5)
+#define ICM426XX_SENSOR_DATA_BE BIT(4)
+#define ICM426XX_UI_SIFS_CFG_MASK GENMASK(1, 0)
+#define ICM426XX_UI_SIFS_CFG_SPI_DIS 0x02
+#define ICM426XX_UI_SIFS_CFG_I2C_DIS 0x03
+
+#define ICM426XX_REG_INTF_CONFIG1 0x004D
+#define ICM426XX_ACCEL_LP_CLK_SEL BIT(3)
+
+enum icm426xx_sensor_mode {
+ ICM426XX_MODE_OFF,
+ ICM426XX_MODE_STANDBY,
+ ICM426XX_MODE_LOW_POWER,
+ ICM426XX_MODE_LOW_NOISE,
+};
+#define ICM426XX_REG_PWR_MGMT0 0x004E
+#define ICM426XX_TEMP_DIS BIT(5)
+#define ICM426XX_IDLE BIT(4)
+#define ICM426XX_GYRO_MODE_MASK GENMASK(3, 2)
+#define ICM426XX_GYRO_MODE(_m) (((_m) & 0x03) << 2)
+#define ICM426XX_ACCEL_MODE_MASK GENMASK(1, 0)
+#define ICM426XX_ACCEL_MODE(_m) ((_m) & 0x03)
+
+#define ICM426XX_REG_GYRO_CONFIG0 0x004F
+#define ICM426XX_REG_ACCEL_CONFIG0 0x0050
+#define ICM426XX_FS_MASK GENMASK(7, 5)
+#define ICM426XX_FS_SEL(_fs) (((_fs) & 0x07) << 5)
+#define ICM426XX_ODR_MASK GENMASK(3, 0)
+#define ICM426XX_ODR(_odr) ((_odr) & 0x0F)
+
+enum icm426xx_filter_bw {
+ /* low noise mode */
+ ICM426XX_FILTER_BW_ODR_DIV_2 = 0,
+
+ /* low power mode */
+ ICM426XX_FILTER_BW_AVG_1X = 1,
+ ICM426XX_FILTER_BW_AVG_16X = 6,
+};
+
+#define ICM426XX_REG_GYRO_ACCEL_CONFIG0 0x0052
+#define ICM426XX_ACCEL_UI_FILT_MASK GENMASK(7, 4)
+#define ICM426XX_ACCEL_UI_FILT_BW(_f) (((_f) & 0x0F) << 4)
+#define ICM426XX_GYRO_UI_FILT_MASK GENMASK(3, 0)
+#define ICM426XX_GYRO_UI_FILT_BW(_f) ((_f) & 0x0F)
+
+#define ICM426XX_REG_FIFO_CONFIG1 0x005F
+#define ICM426XX_FIFO_PARTIAL_READ BIT(6)
+#define ICM426XX_FIFO_WM_GT_TH BIT(5)
+#define ICM426XX_FIFO_EN_MASK GENMASK(3, 0)
+#define ICM426XX_FIFO_TMST_FSYNC_EN BIT(3)
+#define ICM426XX_FIFO_TEMP_EN BIT(2)
+#define ICM426XX_FIFO_GYRO_EN BIT(1)
+#define ICM426XX_FIFO_ACCEL_EN BIT(0)
+
+/* FIFO watermark value is 16 bits little endian */
+#define ICM426XX_REG_FIFO_WATERMARK 0x0060
+
+#define ICM426XX_REG_INT_CONFIG1 0x0064
+#define ICM426XX_INT_PULSE_DURATION BIT(6)
+#define ICM426XX_INT_TDEASSERT_DIS BIT(5)
+#define ICM426XX_INT_ASYNC_RESET BIT(4)
+
+#define ICM426XX_REG_INT_SOURCE0 0x0065
+#define ICM426XX_UI_FSYNC_INT1_EN BIT(6)
+#define ICM426XX_PLL_RDY_INT1_EN BIT(5)
+#define ICM426XX_RESET_DONE_INT1_EN BIT(4)
+#define ICM426XX_UI_DRDY_INT1_EN BIT(3)
+#define ICM426XX_FIFO_THS_INT1_EN BIT(2)
+#define ICM426XX_FIFO_FULL_INT1_EN BIT(1)
+#define ICM426XX_UI_AGC_RDY_INT1_EN BIT(0)
+
+#define ICM426XX_REG_INT_SOURCE3 0x0068
+#define ICM426XX_UI_FSYNC_INT2_EN BIT(6)
+#define ICM426XX_PLL_RDY_INT2_EN BIT(5)
+#define ICM426XX_RESET_DONE_INT2_EN BIT(4)
+#define ICM426XX_UI_DRDY_INT2_EN BIT(3)
+#define ICM426XX_FIFO_THS_INT2_EN BIT(2)
+#define ICM426XX_FIFO_FULL_INT2_EN BIT(1)
+#define ICM426XX_UI_AGC_RDY_INT2_EN BIT(0)
+
+#define ICM426XX_REG_WHO_AM_I 0x0075
+#define ICM426XX_CHIP_ICM40608 0x39
+#define ICM426XX_CHIP_ICM42605 0x42
+
+#define ICM426XX_REG_BANK_SEL 0x0076
+#define ICM426XX_BANK_SEL(_b) ((_b) & 0x07)
+
+#define ICM426XX_REG_INTF_CONFIG4 0x017A
+#define ICM426XX_I3C_BUS_MODE BIT(6)
+#define ICM426XX_SPI_AP_4WIRE BIT(1)
+
+#define ICM426XX_REG_INTF_CONFIG5 0x017B
+#define ICM426XX_PIN9_FUNC_INT2 (0x00 << 1)
+#define ICM426XX_PIN9_FUNC_FSYNC (0x01 << 1)
+
+#define ICM426XX_REG_INTF_CONFIG6 0x017C
+#define ICM426XX_INTF_CONFIG6_MASK GENMASK(4, 0)
+#define ICM426XX_I3C_EN BIT(4)
+#define ICM426XX_I3C_IBI_BYTE_EN BIT(3)
+#define ICM426XX_I3C_IBI_EN BIT(2)
+#define ICM426XX_I3C_DDR_EN BIT(1)
+#define ICM426XX_I3C_SDR_EN BIT(0)
+
+#define ICM426XX_REG_INT_SOURCE8 0x044F
+#define ICM426XX_FSYNC_IBI_EN BIT(5)
+#define ICM426XX_PLL_RDY_IBI_EN BIT(4)
+#define ICM426XX_UI_DRDY_IBI_EN BIT(3)
+#define ICM426XX_FIFO_THS_IBI_EN BIT(2)
+#define ICM426XX_FIFO_FULL_IBI_EN BIT(1)
+#define ICM426XX_AGC_RDY_IBI_EN BIT(0)
+
+#define ICM426XX_REG_OFFSET_USER0 0x0477
+#define ICM426XX_REG_OFFSET_USER1 0x0478
+#define ICM426XX_REG_OFFSET_USER2 0x0479
+#define ICM426XX_REG_OFFSET_USER3 0x047A
+#define ICM426XX_REG_OFFSET_USER4 0x047B
+#define ICM426XX_REG_OFFSET_USER5 0x047C
+#define ICM426XX_REG_OFFSET_USER6 0x047D
+#define ICM426XX_REG_OFFSET_USER7 0x047E
+#define ICM426XX_REG_OFFSET_USER8 0x047F
+
+extern const struct accelgyro_drv icm426xx_drv;
+
+void icm426xx_interrupt(enum gpio_signal signal);
+
+#endif /* __CROS_EC_ACCELGYRO_ICM426XX_H */
diff --git a/driver/accelgyro_icm_common.c b/driver/accelgyro_icm_common.c
new file mode 100644
index 0000000000..f4ec5a4a7e
--- /dev/null
+++ b/driver/accelgyro_icm_common.c
@@ -0,0 +1,287 @@
+/* Copyright 2020 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.
+ */
+
+/**
+ * ICM accelerometer and gyroscope module for Chrome EC
+ * 3D digital accelerometer & 3D digital gyroscope
+ */
+
+#include "accelgyro.h"
+#include "console.h"
+#include "i2c.h"
+#include "spi.h"
+#include "driver/accelgyro_icm_common.h"
+#include "driver/accelgyro_icm426xx.h"
+
+#define CPUTS(outstr) cputs(CC_ACCEL, outstr)
+#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args)
+#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args)
+
+#ifdef CONFIG_SPI_ACCEL_PORT
+static int icm_spi_raw_read(const int addr, const uint8_t reg,
+ uint8_t *data, const int len)
+{
+ uint8_t cmd = 0x80 | reg;
+
+ return spi_transaction(&spi_devices[addr], &cmd, 1, data, len);
+}
+
+static int icm_spi_raw_write(const int addr, const uint8_t reg,
+ const uint8_t *data, const int len)
+{
+ uint8_t cmd[3];
+ int i;
+
+ if (len > 2)
+ return EC_ERROR_UNIMPLEMENTED;
+
+ cmd[0] = reg;
+ for (i = 0; i < len; ++i)
+ cmd[i + 1] = data[i];
+
+ return spi_transaction(&spi_devices[addr], cmd, len + 1, NULL, 0);
+}
+#endif
+
+static int icm_bank_sel(const struct motion_sensor_t *s, const int reg)
+{
+ struct icm_drv_data_t *st = ICM_GET_DATA(s);
+ uint8_t bank = ICM426XX_REG_GET_BANK(reg);
+ int ret;
+
+ if (bank == st->bank)
+ return EC_SUCCESS;
+
+ ret = EC_ERROR_UNIMPLEMENTED;
+#ifdef I2C_PORT_ACCEL
+ ret = i2c_write8(s->port, s->addr,
+ ICM426XX_REG_BANK_SEL, bank);
+#endif
+
+ if (ret == EC_SUCCESS)
+ st->bank = bank;
+
+ return ret;
+}
+
+/**
+ * Read 8 bits register
+ */
+int icm_read8(const struct motion_sensor_t *s, const int reg, int *data_ptr)
+{
+ const uint8_t addr = ICM426XX_REG_GET_ADDR(reg);
+ int ret;
+
+ ret = icm_bank_sel(s, reg);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ ret = EC_ERROR_UNIMPLEMENTED;
+#ifdef I2C_PORT_ACCEL
+ ret = i2c_read8(s->port, s->addr, addr, data_ptr);
+#endif
+
+ return ret;
+}
+
+/**
+ * Write 8 bits register
+ */
+int icm_write8(const struct motion_sensor_t *s, const int reg, int data)
+{
+ const uint8_t addr = ICM426XX_REG_GET_ADDR(reg);
+ int ret;
+
+ ret = icm_bank_sel(s, reg);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ ret = EC_ERROR_UNIMPLEMENTED;
+#ifdef I2C_PORT_ACCEL
+ ret = i2c_write8(s->port, s->addr, addr, data);
+#endif
+
+ return ret;
+}
+
+/**
+ * Read 16 bits register
+ */
+int icm_read16(const struct motion_sensor_t *s, const int reg, int *data_ptr)
+{
+ const uint8_t addr = ICM426XX_REG_GET_ADDR(reg);
+ int ret;
+
+ ret = icm_bank_sel(s, reg);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ ret = EC_ERROR_UNIMPLEMENTED;
+#ifdef I2C_PORT_ACCEL
+ ret = i2c_read16(s->port, s->addr,
+ addr, data_ptr);
+#endif
+
+ return ret;
+}
+
+/**
+ * Write 16 bits register
+ */
+int icm_write16(const struct motion_sensor_t *s, const int reg, int data)
+{
+ const uint8_t addr = ICM426XX_REG_GET_ADDR(reg);
+ int ret;
+
+ ret = icm_bank_sel(s, reg);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ ret = EC_ERROR_UNIMPLEMENTED;
+#ifdef I2C_PORT_ACCEL
+ ret = i2c_write16(s->port, s->addr, addr, data);
+#endif
+
+ return ret;
+}
+
+/**
+ * Read n bytes
+ */
+int icm_read_n(const struct motion_sensor_t *s, const int reg,
+ uint8_t *data_ptr, const int len)
+{
+ const uint8_t addr = ICM426XX_REG_GET_ADDR(reg);
+ int ret;
+
+ ret = icm_bank_sel(s, reg);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ ret = EC_ERROR_UNIMPLEMENTED;
+#ifdef I2C_PORT_ACCEL
+ ret = i2c_read_block(s->port, s->addr, addr,
+ data_ptr, len);
+#endif
+
+ return ret;
+}
+
+int icm_field_update8(const struct motion_sensor_t *s, const int reg,
+ const uint8_t field_mask, const uint8_t set_value)
+{
+ const uint8_t addr = ICM426XX_REG_GET_ADDR(reg);
+ int ret;
+
+ ret = icm_bank_sel(s, reg);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ ret = EC_ERROR_UNIMPLEMENTED;
+#ifdef I2C_PORT_ACCEL
+ ret = i2c_field_update8(s->port, s->addr, addr,
+ field_mask, set_value);
+#endif
+
+ return ret;
+}
+
+int icm_get_resolution(const struct motion_sensor_t *s)
+{
+ return ICM_RESOLUTION;
+}
+
+int icm_get_range(const struct motion_sensor_t *s)
+{
+ struct accelgyro_saved_data_t *data = ICM_GET_SAVED_DATA(s);
+
+ return data->range;
+}
+
+int icm_get_data_rate(const struct motion_sensor_t *s)
+{
+ struct accelgyro_saved_data_t *data = ICM_GET_SAVED_DATA(s);
+
+ return data->odr;
+}
+
+/* FIFO header: 1 byte */
+#define ICM_FIFO_HEADER_MSG BIT(7)
+#define ICM_FIFO_HEADER_ACCEL BIT(6)
+#define ICM_FIFO_HEADER_GYRO BIT(5)
+#define ICM_FIFO_HEADER_TMST_FSYNC GENMASK(3, 2)
+#define ICM_FIFO_HEADER_ODR_ACCEL BIT(1)
+#define ICM_FIFO_HEADER_ODR_GYRO BIT(0)
+
+/* FIFO data packet */
+struct icm_fifo_sensor_data {
+ int16_t x;
+ int16_t y;
+ int16_t z;
+} __packed;
+
+struct icm_fifo_1sensor_packet {
+ uint8_t header;
+ struct icm_fifo_sensor_data data;
+ int8_t temp;
+} __packed;
+#define ICM_FIFO_1SENSOR_PACKET_SIZE 8
+
+struct icm_fifo_2sensors_packet {
+ uint8_t header;
+ struct icm_fifo_sensor_data accel;
+ struct icm_fifo_sensor_data gyro;
+ int8_t temp;
+ uint16_t timestamp;
+} __packed;
+#define ICM_FIFO_2SENSORS_PACKET_SIZE 16
+
+ssize_t icm_fifo_decode_packet(const void *packet, const uint8_t **accel,
+ const uint8_t **gyro)
+{
+ const struct icm_fifo_1sensor_packet *pack1 = packet;
+ const struct icm_fifo_2sensors_packet *pack2 = packet;
+ uint8_t header = *((const uint8_t *)packet);
+
+ /* FIFO empty */
+ if (header & ICM_FIFO_HEADER_MSG) {
+ if (accel != NULL)
+ *accel = NULL;
+ if (gyro != NULL)
+ *gyro = NULL;
+ return 0;
+ }
+
+ /* accel + gyro */
+ if ((header & ICM_FIFO_HEADER_ACCEL) &&
+ (header & ICM_FIFO_HEADER_GYRO)) {
+ if (accel != NULL)
+ *accel = (uint8_t *)&pack2->accel;
+ if (gyro != NULL)
+ *gyro = (uint8_t *)&pack2->gyro;
+ return ICM_FIFO_2SENSORS_PACKET_SIZE;
+ }
+
+ /* accel only */
+ if (header & ICM_FIFO_HEADER_ACCEL) {
+ if (accel != NULL)
+ *accel = (uint8_t *)&pack1->data;
+ if (gyro != NULL)
+ *gyro = NULL;
+ return ICM_FIFO_1SENSOR_PACKET_SIZE;
+ }
+
+ /* gyro only */
+ if (header & ICM_FIFO_HEADER_GYRO) {
+ if (accel != NULL)
+ *accel = NULL;
+ if (gyro != NULL)
+ *gyro = (uint8_t *)&pack1->data;
+ return ICM_FIFO_1SENSOR_PACKET_SIZE;
+ }
+
+ /* invalid packet if here */
+ return -EC_ERROR_INVAL;
+}
diff --git a/driver/accelgyro_icm_common.h b/driver/accelgyro_icm_common.h
new file mode 100644
index 0000000000..5f2db67df1
--- /dev/null
+++ b/driver/accelgyro_icm_common.h
@@ -0,0 +1,129 @@
+/* Copyright 2020 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.
+ */
+
+/* ICM accelerometer and gyroscope common definitions for Chrome EC */
+
+#ifndef __CROS_EC_ACCELGYRO_ICM_COMMON_H
+#define __CROS_EC_ACCELGYRO_ICM_COMMON_H
+
+#include "accelgyro.h"
+#include "hwtimer.h"
+#include "timer.h"
+
+#ifdef CONFIG_ACCEL_FIFO
+/* reserve maximum 4 samples of 16 bytes */
+#define ICM_FIFO_BUFFER 64
+#else
+#define ICM_FIFO_BUFFER 0
+#endif
+
+struct icm_drv_data_t {
+ struct accelgyro_saved_data_t saved_data[2];
+ struct motion_sensor_t *accel;
+ struct motion_sensor_t *gyro;
+ uint32_t stabilize_ts[2];
+ uint8_t bank;
+ uint8_t fifo_en;
+ uint8_t fifo_buffer[ICM_FIFO_BUFFER] __aligned(sizeof(long));
+};
+
+#define ICM_GET_DATA(_s) \
+ ((struct icm_drv_data_t *)(_s)->drv_data)
+#define ICM_GET_SAVED_DATA(_s) \
+ (&ICM_GET_DATA(_s)->saved_data[(_s)->type])
+
+/*
+ * Virtual register address is 16 bits:
+ * - 8 bits MSB coding bank number
+ * - 8 bits LSB coding physical address
+ */
+#define ICM426XX_REG_GET_BANK(_r) (((_r) & 0xFF00) >> 8)
+#define ICM426XX_REG_GET_ADDR(_r) ((_r) & 0x00FF)
+
+/* Sensor resolution in number of bits */
+#define ICM_RESOLUTION 16
+
+/**
+ * sign_extend - sign extend a standard int value using the given sign-bit
+ * @value: value to sign extend
+ * @index: 0 based bit index to sign bit
+ */
+static inline int sign_extend(int value, int index)
+{
+ int shift = (sizeof(int) * 8) - index - 1;
+
+ return (int)(value << shift) >> shift;
+}
+
+/**
+ * Read 8 bits register
+ */
+int icm_read8(const struct motion_sensor_t *s, const int reg, int *data_ptr);
+
+/**
+ * Write 8 bits register
+ */
+int icm_write8(const struct motion_sensor_t *s, const int reg, int data);
+
+/**
+ * Read 16 bits register
+ */
+int icm_read16(const struct motion_sensor_t *s, const int reg, int *data_ptr);
+
+/**
+ * Write 16 bits register
+ */
+int icm_write16(const struct motion_sensor_t *s, const int reg, int data);
+
+/**
+ * Read n bytes
+ */
+int icm_read_n(const struct motion_sensor_t *s, const int reg,
+ uint8_t *data_ptr, const int len);
+
+int icm_field_update8(const struct motion_sensor_t *s, const int reg,
+ const uint8_t field_mask, const uint8_t set_value);
+
+int icm_get_resolution(const struct motion_sensor_t *s);
+
+int icm_get_range(const struct motion_sensor_t *s);
+
+int icm_get_data_rate(const struct motion_sensor_t *s);
+
+ssize_t icm_fifo_decode_packet(const void *packet, const uint8_t **accel,
+ const uint8_t **gyro);
+
+static inline void icm_set_stabilize_ts(const struct motion_sensor_t *s,
+ uint32_t delay)
+{
+ struct icm_drv_data_t *st = ICM_GET_DATA(s);
+ uint32_t stabilize_ts;
+
+ stabilize_ts = __hw_clock_source_read() + delay;
+ /* prevent 0 value used for disabling time checking */
+ st->stabilize_ts[s->type] = stabilize_ts | 1;
+}
+
+static inline void icm_reset_stabilize_ts(const struct motion_sensor_t *s)
+{
+ struct icm_drv_data_t *st = ICM_GET_DATA(s);
+
+ st->stabilize_ts[s->type] = 0;
+}
+
+static inline
+int32_t icm_get_sensor_stabilized(const struct motion_sensor_t *s,
+ uint32_t ts)
+{
+ struct icm_drv_data_t *st = ICM_GET_DATA(s);
+ uint32_t stabilize_ts = st->stabilize_ts[s->type];
+
+ if (stabilize_ts == 0)
+ return 0;
+
+ return time_until(ts, stabilize_ts);
+}
+
+#endif /* __CROS_EC_ACCELGYRO_ICM_COMMON_H */
diff --git a/driver/als_si114x.c b/driver/als_si114x.c
index 17f178080f..be3f090db3 100644
--- a/driver/als_si114x.c
+++ b/driver/als_si114x.c
@@ -295,6 +295,7 @@ static int read(const struct motion_sensor_t *s, intv3_t v)
case SI114X_NOT_READY:
ret = EC_ERROR_NOT_POWERED;
}
+#if 0 /* This code is incorrect https://crbug.com/956569 */
if (ret == EC_ERROR_ACCESS_DENIED &&
s->type == MOTIONSENSE_TYPE_LIGHT) {
timestamp_t ts_now = get_time();
@@ -315,6 +316,7 @@ static int read(const struct motion_sensor_t *s, intv3_t v)
init(s);
}
}
+#endif
return ret;
}
diff --git a/driver/build.mk b/driver/build.mk
index 5d48edb242..b781062688 100644
--- a/driver/build.mk
+++ b/driver/build.mk
@@ -18,6 +18,7 @@ driver-$(CONFIG_ACCEL_LIS2D_COMMON)+=accel_lis2dh.o stm_mems_common.o
driver-$(CONFIG_MAG_LIS2MDL)+=mag_lis2mdl.o
driver-$(CONFIG_SENSORHUB_LSM6DSM)+=sensorhub_lsm6dsm.o
driver-$(CONFIG_SYNC)+=sync.o
+driver-$(CONFIG_ACCELGYRO_ICM426XX)+=accelgyro_icm426xx.o accelgyro_icm_common.o
# BC1.2 Charger Detection Devices
driver-$(CONFIG_BC12_DETECT_MAX14637)+=bc12/max14637.o
diff --git a/extra/touchpad_updater/touchpad_updater.c b/extra/touchpad_updater/touchpad_updater.c
index d09b899a8d..0bcd0fc70a 100644
--- a/extra/touchpad_updater/touchpad_updater.c
+++ b/extra/touchpad_updater/touchpad_updater.c
@@ -181,7 +181,7 @@ static void request_exit(const char *format, ...)
static void sighandler(int signum)
{
- request_exit("caught signal %d: %s\n", signum, sys_siglist[signum]);
+ request_exit("caught signal %d: %s\n", signum, strsignal(signum));
}
static int find_interface_with_endpoint(int want_ep_num)
diff --git a/extra/usb_console/usb_console.c b/extra/usb_console/usb_console.c
index 7d99bc3082..02909f7136 100644
--- a/extra/usb_console/usb_console.c
+++ b/extra/usb_console/usb_console.c
@@ -46,7 +46,7 @@ static void request_exit(const char *format, ...)
static void sighandler(int signum)
{
- request_exit("caught signal %d: %s\n", signum, sys_siglist[signum]);
+ request_exit("caught signal %d: %s\n", signum, strsignal(signum));
}
#if 0
diff --git a/include/common.h b/include/common.h
index ddd310f5d4..fc9e46c56e 100644
--- a/include/common.h
+++ b/include/common.h
@@ -124,6 +124,11 @@
#endif
#endif
+/* Macros for combining bytes into uint16s. */
+#define UINT16_FROM_BYTES(lsb, msb) ((lsb) | (msb) << 8)
+#define UINT16_FROM_BYTE_ARRAY_LE(data, lsb_index) \
+ UINT16_FROM_BYTES((data)[(lsb_index)], (data)[(lsb_index + 1)])
+
/* There isn't really a better place for this */
#define C_TO_K(temp_c) ((temp_c) + 273)
#define K_TO_C(temp_c) ((temp_c) - 273)
@@ -227,6 +232,33 @@ enum ec_error_list {
#endif
/*
+ * Weak symbol markers
+ *
+ * These macros are used to annotate weak definitions, their declarations, and
+ * overriding definitions.
+ *
+ * __override_proto: declarations
+ * __override: definitions which take precedence
+ * __overridable: default (weak) definitions
+ *
+ * For example, in foo.h:
+ * __override_proto void foo(void);
+ *
+ * and in foo.c:
+ * __overridable void foo(void) {
+ * ...
+ * }
+ *
+ * and in board.c:
+ * __override void foo(void) {
+ * ...
+ * }
+ */
+#define __override_proto
+#define __override
+#define __overridable __attribute__((weak))
+
+/*
* Mark functions that collide with stdlib so they can be hidden when linking
* against libraries that require stdlib. HIDE_EC_STDLIB should be defined
* before including common.h from code that links to cstdlib.
diff --git a/include/compile_time_macros.h b/include/compile_time_macros.h
index bf133d60f4..b05e2569e1 100644
--- a/include/compile_time_macros.h
+++ b/include/compile_time_macros.h
@@ -35,4 +35,26 @@
#define member_size(type, member) sizeof(((type *)0)->member)
+/*
+ * Bit operation macros.
+ */
+#define BIT(nr) (1UL << (nr))
+#define BIT_ULL(nr) (1ULL << (nr))
+
+/*
+ * Create a bit mask from least significant bit |l|
+ * to bit |h|, inclusive.
+ *
+ * Examples:
+ * GENMASK(31, 0) ==> 0xFF_FF_FF_FF
+ * GENMASK(3, 0) ==> 0x00_00_00_0F
+ * GENMASK(7, 4) ==> 0x00_00_00_F0
+ * GENMASK(b, b) ==> BIT(b)
+ *
+ * Note that we shift after using BIT() to avoid compiler
+ * warnings for BIT(31+1).
+ */
+#define GENMASK(h, l) (((BIT(h)<<1) - 1) ^ (BIT(l) - 1))
+#define GENMASK_ULL(h, l) (((BIT_ULL(h)<<1) - 1) ^ (BIT_ULL(l) - 1))
+
#endif /* __CROS_EC_COMPILE_TIME_MACROS_H */
diff --git a/include/config.h b/include/config.h
index c1f1457c21..a090cfe7ec 100644
--- a/include/config.h
+++ b/include/config.h
@@ -75,6 +75,7 @@
#undef CONFIG_ACCEL_LIS2DH
#undef CONFIG_ACCEL_LIS2DE
#undef CONFIG_ACCEL_LIS2D_COMMON
+#undef CONFIG_ACCELGYRO_ICM426XX
#undef CONFIG_ACCELGYRO_LSM6DS0
#undef CONFIG_ACCELGYRO_BMI160
#undef CONFIG_ACCELGYRO_LSM6DSM
@@ -219,6 +220,7 @@
* Must be within TASK_EVENT_MOTION_INTERRUPT_MASK.
*/
#undef CONFIG_ACCELGYRO_BMI160_INT_EVENT
+#undef CONFIG_ACCELGYRO_ICM426XX_INT_EVENT
#undef CONFIG_ACCEL_LSM6DSM_INT_EVENT
#undef CONFIG_ALS_SI114X_INT_EVENT
@@ -1101,6 +1103,9 @@
*/
#undef CONFIG_CHIP_PANIC_BACKUP
+/* Don't save General Purpose Registers during panic */
+#undef CONFIG_PANIC_STRIP_GPR
+
/*
* Provide the default GPIO abstraction layer.
* You want this unless you are doing a really tiny firmware.
@@ -1328,7 +1333,7 @@
* r8 :00000000 r9 :200013de r10:00000000 r11:00000000
* r12:00000000 sp :200009a0 lr :08002b85 pc :08003a8a
* Precise data bus error, Forced hard fault, Vector catch, bfar = 60000000
- * mmfs = 00008200, shcsr = 00000000, hfsr = 40000000, dfsr = 00000008
+ * cfsr = 00008200, shcsr = 00000000, hfsr = 40000000, dfsr = 00000008
*
* If this is not defined, only a register dump will be printed.
*
@@ -1959,9 +1964,6 @@
*/
#undef CONFIG_HIBERNATE_PSL
-/* Use a hardware specific udelay(). */
-#undef CONFIG_HW_SPECIFIC_UDELAY
-
/*****************************************************************************/
/* I2C configuration */
@@ -2441,9 +2443,15 @@
/* Support MKBP event */
#undef CONFIG_MKBP_EVENT
-/* MKBP events are sent using host event */
+/* MKBP events are sent by using host event */
#undef CONFIG_MKBP_USE_HOST_EVENT
+/* MKBP events are sent by using GPIO */
+#undef CONFIG_MKBP_USE_GPIO
+
+/* MKBP events are sent by using custom method */
+#undef CONFIG_MKBP_USE_CUSTOM
+
/*
* With this option, we can define the MKBP wakeup events in this mask (as a
* white list) in board level, those events allow to interrupt AP during S3.
@@ -3888,6 +3896,22 @@
#endif
/******************************************************************************/
+/* MKBP events delivery methods. */
+#ifdef CONFIG_MKBP_EVENT
+#if !defined(CONFIG_MKBP_USE_CUSTOM) && \
+ !defined(CONFIG_MKBP_USE_HOST_EVENT) && \
+ !defined(CONFIG_MKBP_USE_GPIO)
+#error Please define one of CONFIG_MKBP_USE_* macro.
+#endif
+
+#if defined(CONFIG_MKBP_USE_CUSTOM) + \
+ defined(CONFIG_MKBP_USE_GPIO) + \
+ defined(CONFIG_MKBP_USE_HOST_EVENT) > 1
+#error Must select only one type of MKBP event delivery method.
+#endif
+#endif /* CONFIG_MKBP_EVENT */
+
+/******************************************************************************/
/* Set generic orientation config if a specific orientation config is set. */
#if defined(CONFIG_KX022_ORIENTATION_SENSOR) || \
defined(CONFIG_BMI160_ORIENTATION_SENSOR)
diff --git a/include/cros_board_info.h b/include/cros_board_info.h
index 23063d2766..ca5dc34d0a 100644
--- a/include/cros_board_info.h
+++ b/include/cros_board_info.h
@@ -44,12 +44,17 @@ struct cbi_data {
/**
* Board info accessors
*
- * @param version/sku_id/oem_id [OUT] Data read from EEPROM
+ * @param version/sku_id/oem_id/id/fw_config/pcb_supplier/ssfc [OUT] Data read
+ * from EEPROM
* @return EC_SUCCESS on success or EC_ERROR_* otherwise.
*/
int cbi_get_board_version(uint32_t *version);
int cbi_get_sku_id(uint32_t *sku_id);
int cbi_get_oem_id(uint32_t *oem_id);
+int cbi_get_model_id(uint32_t *id);
+int cbi_get_fw_config(uint32_t *fw_config);
+int cbi_get_pcb_supplier(uint32_t *pcb_supplier);
+int cbi_get_ssfc(uint32_t *ssfc);
/**
* Primitive accessors
diff --git a/include/ec_commands.h b/include/ec_commands.h
index ca0660e5f5..a75953207e 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -2411,6 +2411,7 @@ enum motionsensor_chip {
MOTIONSENSE_CHIP_LIS2DH = 13,
MOTIONSENSE_CHIP_LSM6DSM = 14,
MOTIONSENSE_CHIP_LIS2DE = 15,
+ MOTIONSENSE_CHIP_ICM426XX = 25,
MOTIONSENSE_CHIP_MAX,
};
@@ -3315,6 +3316,17 @@ struct ec_result_keyscan_seq_ctrl {
*/
#define EC_CMD_GET_NEXT_EVENT 0x0067
+#define EC_MKBP_HAS_MORE_EVENTS_SHIFT 7
+
+/*
+ * We use the most significant bit of the event type to indicate to the host
+ * that the EC has more MKBP events available to provide.
+ */
+#define EC_MKBP_HAS_MORE_EVENTS (1 << EC_MKBP_HAS_MORE_EVENTS_SHIFT)
+
+/* The mask to apply to get the raw event type */
+#define EC_MKBP_EVENT_TYPE_MASK ((1 << EC_MKBP_HAS_MORE_EVENTS_SHIFT) - 1)
+
enum ec_mkbp_event {
/* Keyboard matrix changed. The event data is the new matrix state. */
EC_MKBP_EVENT_KEY_MATRIX = 0,
@@ -3355,6 +3367,7 @@ enum ec_mkbp_event {
/* Number of MKBP events */
EC_MKBP_EVENT_COUNT,
};
+BUILD_ASSERT(EC_MKBP_EVENT_COUNT <= EC_MKBP_EVENT_TYPE_MASK);
union __ec_align_offset1 ec_response_get_next_data {
uint8_t key_matrix[13];
@@ -4947,6 +4960,11 @@ enum cbi_data_tag {
CBI_TAG_SKU_ID = 2, /* uint8_t */
CBI_TAG_DRAM_PART_NUM = 3, /* variable length ascii, nul terminated. */
CBI_TAG_OEM_NAME = 4, /* variable length ascii, nul terminated. */
+ CBI_TAG_MODEL_ID = 5, /* uint32_t or smaller */
+ CBI_TAG_FW_CONFIG = 6, /* uint32_t bit field */
+ CBI_TAG_PCB_SUPPLIER = 7, /* uint32_t or smaller */
+ /* Second Source Factory Cache */
+ CBI_TAG_SSFC = 8, /* uint32_t bit field */
CBI_TAG_COUNT,
};
diff --git a/include/i2c.h b/include/i2c.h
index 1dcfe46332..9be4f19991 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -31,6 +31,16 @@ enum i2c_freq {
I2C_FREQ_COUNT,
};
+/*
+ * I2C mask update actions.
+ * MASK_SET will OR the mask into the old value
+ * MASK_CLR will AND the ~mask from the old value
+ */
+enum mask_update_action {
+ MASK_CLR,
+ MASK_SET
+};
+
/* Data structure to define I2C port configuration. */
struct i2c_port_t {
const char *name; /* Port name */
@@ -265,6 +275,79 @@ int i2c_read8(int port, int slave_addr, int offset, int *data);
int i2c_write8(int port, int slave_addr, int offset, int data);
/**
+ * Read, modify, write an i2c register to the slave at 7-bit slave address
+ * <slave_addr_flags>, at the specified 8-bit <offset> in the slave's
+ * address space. The <action> will specify whether this is setting the
+ * <mask> bit value(s) or clearing them. If the value to be written is the
+ * same as the original value of the register, the write will not be
+ * performed.
+ */
+int i2c_update8(const int port,
+ const uint16_t slave_addr_flags,
+ const int offset,
+ const uint8_t mask,
+ const enum mask_update_action action);
+
+int i2c_update16(const int port,
+ const uint16_t slave_addr_flags,
+ const int offset,
+ const uint16_t mask,
+ const enum mask_update_action action);
+
+/**
+ * Read, modify, write field of an i2c register to the slave at 7-bit
+ * slave address <slave_addr_flags>, at the specified 8-bit <offset> in
+ * the slave's address space. The register will be read, the <field_mask>
+ * will be cleared and then the <set_value> will be set. The field mask
+ * and the set value do not have to be in the same bit locations. If the
+ * new value is not the same as the original value, the new value will be
+ * written back out to the device, otherwise no write will be performed.
+ */
+int i2c_field_update8(const int port,
+ const uint16_t slave_addr_flags,
+ const int offset,
+ const uint8_t field_mask,
+ const uint8_t set_value);
+
+int i2c_field_update16(const int port,
+ const uint16_t slave_addr_flags,
+ const int offset,
+ const uint16_t field_mask,
+ const uint16_t set_value);
+
+/**
+ * Read one or two bytes data from the slave at 7-bit slave address
+ * * <slaveaddr>, at 16-bit <offset> in the slave's address space.
+ */
+int i2c_read_offset16(const int port,
+ const uint16_t slave_addr_flags,
+ uint16_t offset, int *data, int len);
+
+/**
+ * Write one or two bytes data to the slave at 7-bit slave address
+ * <slaveaddr>, at 16-bit <offset> in the slave's address space.
+ */
+int i2c_write_offset16(const int port,
+ const uint16_t slave_addr_flags,
+ uint16_t offset, int data, int len);
+
+/**
+ * Read <len> bytes block data from the slave at 7-bit slave address
+ * * <slaveaddr>, at 16-bit <offset> in the slave's address space.
+ */
+int i2c_read_offset16_block(const int port,
+ const uint16_t slave_addr_flags,
+ uint16_t offset, uint8_t *data, int len);
+
+/**
+ * Write <len> bytes block data to the slave at 7-bit slave address
+ * <slaveaddr>, at 16-bit <offset> in the slave's address space.
+ */
+int i2c_write_offset16_block(const int port,
+ const uint16_t slave_addr_flags,
+ uint16_t offset, const uint8_t *data, int len);
+
+/**
* @return non-zero if i2c bus is busy
*/
int i2c_is_busy(int port);
diff --git a/include/mkbp_event.h b/include/mkbp_event.h
index 61eb2c9052..c451c53673 100644
--- a/include/mkbp_event.h
+++ b/include/mkbp_event.h
@@ -29,33 +29,11 @@ extern uint32_t mkbp_last_event_time;
int mkbp_send_event(uint8_t event_type);
/*
- * Set MKBP active event status on the AP.
+ * Communicate an MKBP event to the AP via custom method.
*
- * This communicates to the AP whether an MKBP event is currently available
- * for processing. It is used by mkbp_send_event().
- *
- * The default implementation in mkbp_event.c has weak linkage and can be
- * overridden by individual boards depending on their hardware configuration.
- *
- * @param active 1 if there is an event, 0 otherwise
- */
-void mkbp_set_host_active(int active);
-
-/*
- * Communicate an MKBP event to the host via a dedicated GPIO pin.
- *
- * This can be used if the board schematic has a pin reserved for this purpose.
- */
-void mkbp_set_host_active_via_gpio(int active);
-
-/*
- * Communicate an MKBP event to the AP via EC_HOST_EVENT.
- *
- * This can be used without a dedicated interrupt pin configured. It is the
- * default behavior of mkbp_set_host_active when CONFIG_MKBP_USE_HOST_EVENT
- * is defined in board.h.
+ * This can be used if a board has a custom method.
*/
-void mkbp_set_host_active_via_event(int active);
+void mkbp_set_host_active_via_custom(int active);
/*
* The struct to store the event source definition. The get_data routine is
diff --git a/include/motion_sense.h b/include/motion_sense.h
index b7290e7bb4..6584ca05a6 100644
--- a/include/motion_sense.h
+++ b/include/motion_sense.h
@@ -146,13 +146,17 @@ struct motion_sensor_t {
uint16_t lost;
/*
- * Time since last collection:
- * For sensor with hardware FIFO, time since last sample
- * has move from the hardware FIFO to the FIFO (used if fifo rate != 0).
- * For sensor without FIFO, time since the last event was collect
- * from sensor registers.
+ * For sensors in forced mode the ideal time to collect the next
+ * measurement.
+ *
+ * This is unused with sensors that interrupt the ec like hw fifo chips.
+ */
+ uint32_t next_collection;
+
+ /*
+ * The time in us between collection measurements
*/
- uint32_t last_collection;
+ uint32_t collection_rate;
/* Minimum supported sampling frequency in miliHertz for this sensor */
uint32_t min_frequency;
diff --git a/include/panic.h b/include/panic.h
index 1984081dd7..d1099d6cce 100644
--- a/include/panic.h
+++ b/include/panic.h
@@ -17,15 +17,43 @@
extern "C" {
#endif
+enum cortex_panic_frame_registers {
+ CORTEX_PANIC_FRAME_REGISTER_R0 = 0,
+ CORTEX_PANIC_FRAME_REGISTER_R1,
+ CORTEX_PANIC_FRAME_REGISTER_R2,
+ CORTEX_PANIC_FRAME_REGISTER_R3,
+ CORTEX_PANIC_FRAME_REGISTER_R12,
+ CORTEX_PANIC_FRAME_REGISTER_LR,
+ CORTEX_PANIC_FRAME_REGISTER_PC,
+ CORTEX_PANIC_FRAME_REGISTER_PSR,
+ NUM_CORTEX_PANIC_FRAME_REGISTERS
+};
+
+enum cortex_panic_registers {
+ CORTEX_PANIC_REGISTER_PSP = 0,
+ CORTEX_PANIC_REGISTER_IPSR,
+ CORTEX_PANIC_REGISTER_MSP,
+ CORTEX_PANIC_REGISTER_R4,
+ CORTEX_PANIC_REGISTER_R5,
+ CORTEX_PANIC_REGISTER_R6,
+ CORTEX_PANIC_REGISTER_R7,
+ CORTEX_PANIC_REGISTER_R8,
+ CORTEX_PANIC_REGISTER_R9,
+ CORTEX_PANIC_REGISTER_R10,
+ CORTEX_PANIC_REGISTER_R11,
+ CORTEX_PANIC_REGISTER_LR,
+ NUM_CORTEX_PANIC_REGISTERS
+};
+
/* ARM Cortex-Mx registers saved on panic */
struct cortex_panic_data {
- uint32_t regs[12]; /* psp, ipsr, msp, r4-r11, lr(=exc_return).
- * In version 1, that was uint32_t regs[11] =
- * psp, ipsr, lr, r4-r11
- */
- uint32_t frame[8]; /* r0-r3, r12, lr, pc, xPSR */
+ /* See cortex_panic_registers enum for information about registers */
+ uint32_t regs[NUM_CORTEX_PANIC_REGISTERS];
+
+ /* See cortex_panic_frame_registers enum for more information */
+ uint32_t frame[NUM_CORTEX_PANIC_FRAME_REGISTERS];
- uint32_t mmfs;
+ uint32_t cfsr;
uint32_t bfar;
uint32_t mfar;
uint32_t shcsr;
@@ -160,6 +188,19 @@ void panic_set_reason(uint32_t reason, uint32_t info, uint8_t exception);
void panic_get_reason(uint32_t *reason, uint32_t *info, uint8_t *exception);
#endif
+#define HFSR_FLAG_ASSERT 3
+#define HFSR_FLAG_WATCHDOG 4
+
+/**
+ * Save code location in struct panic_data then reboot.
+ *
+ * @param func Function name (i.e. __func__). Stored in regs[3].
+ * @param file File path (i.e. __FILE__). Stored in regs[4].
+ * @param line Line number (i.e. __LINE__). Stored in HFSR[25:10].
+ */
+void panic_assert(const char *func, const char *file, uint16_t line)
+ __attribute__((noreturn));
+
/**
* Enable/disable bus fault handler
*
diff --git a/include/timer.h b/include/timer.h
index fb7800ce2e..26d39a975d 100644
--- a/include/timer.h
+++ b/include/timer.h
@@ -71,7 +71,7 @@ int timestamp_expired(timestamp_t deadline, const timestamp_t *now);
*
* @param us Number of microseconds to delay.
*/
-void udelay(unsigned us);
+__override_proto void udelay(unsigned us);
/**
* Sleep.
@@ -133,6 +133,23 @@ void force_time(timestamp_t ts);
void timer_print_info(void);
/**
+ * Returns a free running millisecond clock counter, which matches tpm2
+ * library expectations.
+ */
+clock_t clock(void);
+
+/**
+ * Compute how far to_time is from from_time with rollover taken into account
+ *
+ * Return us until to_time given from_time, if negative then to_time has
+ * passeed from_time.
+ */
+static inline int time_until(uint32_t from_time, uint32_t to_time)
+{
+ return (int32_t)(to_time - from_time);
+}
+
+/**
* Returns the number of microseconds that have elapsed from a start time.
*
* This function is for timing short delays typically of a few milliseconds
@@ -142,27 +159,21 @@ void timer_print_info(void);
* hour. After that, the value returned will wrap.
*
* @param start Start time to compare against
- * @return number of microseconds that have elspsed since that start time
+ * @return number of microseconds that have elapsed since that start time
*/
static inline unsigned time_since32(timestamp_t start)
{
- return get_time().le.lo - start.le.lo;
+ return time_until(start.le.lo, get_time().le.lo);
}
/**
- * Returns a free running millisecond clock counter, which matches tpm2
- * library expectations.
- */
-clock_t clock(void);
-
-/**
* To compare time and deal with rollover
*
* Return true if a is after b.
*/
static inline int time_after(uint32_t a, uint32_t b)
{
- return (int32_t)(b - a) < 0;
+ return time_until(a, b) < 0;
}
#endif /* __CROS_EC_TIMER_H */
diff --git a/test/build.mk b/test/build.mk
index 31cec03c9a..b3fee3ab6d 100644
--- a/test/build.mk
+++ b/test/build.mk
@@ -23,6 +23,7 @@ test-list-host += cec
test-list-host += charge_manager
test-list-host += charge_manager_drp_charging
test-list-host += charge_ramp
+test-list-host += compile_time_macros
test-list-host += console_edit
test-list-host += crc32
test-list-host += entropy
@@ -80,6 +81,7 @@ cec-y=cec.o
charge_manager-y=charge_manager.o
charge_manager_drp_charging-y=charge_manager.o
charge_ramp-y+=charge_ramp.o
+compile_time_macros-y=compile_time_macros.o
console_edit-y=console_edit.o
crc32-y=crc32.o
entropy-y=entropy.o
diff --git a/test/cbi.c b/test/cbi.c
new file mode 100644
index 0000000000..936dc204b8
--- /dev/null
+++ b/test/cbi.c
@@ -0,0 +1,199 @@
+/* Copyright 2020 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.
+ *
+ * Test CBI
+ */
+
+#include "common.h"
+#include "console.h"
+#include "cros_board_info.h"
+#include "gpio.h"
+#include "i2c.h"
+#include "test_util.h"
+#include "util.h"
+
+void before_test(void)
+{
+ cbi_create();
+ cbi_write();
+}
+
+static int test_uint8(void)
+{
+ uint8_t d8;
+ uint32_t d32;
+ uint8_t size;
+ const int tag = 0xff;
+
+ /* Set & get uint8_t */
+ d8 = 0xa5;
+ TEST_ASSERT(cbi_set_board_info(tag, &d8, sizeof(d8)) == EC_SUCCESS);
+ size = 1;
+ TEST_ASSERT(cbi_get_board_info(tag, &d8, &size) == EC_SUCCESS);
+ TEST_EQ(d8, 0xa5, "0x%x");
+ TEST_EQ(size, 1, "%x");
+
+ /* Size-up */
+ d32 = 0x1234abcd;
+ TEST_ASSERT(cbi_set_board_info(tag, (void *)&d32, sizeof(d32))
+ == EC_SUCCESS);
+ size = 4;
+ TEST_ASSERT(cbi_get_board_info(tag, (void *)&d32, &size) == EC_SUCCESS);
+ TEST_EQ(d32, 0x1234abcd, "0x%x");
+ TEST_EQ(size, 4, "%u");
+
+ return EC_SUCCESS;
+}
+
+static int test_uint32(void)
+{
+ uint8_t d8;
+ uint32_t d32;
+ uint8_t size;
+ const int tag = 0xff;
+
+ /* Set & get uint32_t */
+ d32 = 0x1234abcd;
+ TEST_ASSERT(cbi_set_board_info(tag, (void *)&d32, sizeof(d32))
+ == EC_SUCCESS);
+ size = 4;
+ TEST_ASSERT(cbi_get_board_info(tag, (void *)&d32, &size) == EC_SUCCESS);
+ TEST_EQ(d32, 0x1234abcd, "0x%x");
+ TEST_EQ(size, 4, "%u");
+
+ /* Size-down */
+ d8 = 0xa5;
+ TEST_ASSERT(cbi_set_board_info(tag, &d8, sizeof(d8)) == EC_SUCCESS);
+ size = 1;
+ TEST_ASSERT(cbi_get_board_info(tag, &d8, &size) == EC_SUCCESS);
+ TEST_EQ(d8, 0xa5, "0x%x");
+ TEST_EQ(size, 1, "%u");
+
+ return EC_SUCCESS;
+}
+
+static int test_string(void)
+{
+ const uint8_t string[] = "abcdefghijklmn";
+ uint8_t buf[32];
+ uint8_t size;
+ const int tag = 0xff;
+
+ /* Set & get string */
+ TEST_ASSERT(cbi_set_board_info(tag, string, sizeof(string))
+ == EC_SUCCESS);
+ size = sizeof(buf);
+ TEST_ASSERT(cbi_get_board_info(tag, buf, &size) == EC_SUCCESS);
+ TEST_ASSERT(strncmp(buf, string, sizeof(string)) == 0);
+ /* Size contains null byte */
+ TEST_EQ((size_t)size - 1, strlen(buf), "%zu");
+
+ /* Read buffer too small */
+ size = 4;
+ TEST_ASSERT(cbi_get_board_info(tag, buf, &size) == EC_ERROR_INVAL);
+
+ return EC_SUCCESS;
+}
+
+static int test_not_found(void)
+{
+ uint8_t d8;
+ const int tag = 0xff;
+ uint8_t size;
+
+ size = 1;
+ TEST_ASSERT(cbi_get_board_info(tag, &d8, &size) == EC_ERROR_UNKNOWN);
+
+ return EC_SUCCESS;
+}
+
+static int test_too_large(void)
+{
+ uint8_t buf[CBI_EEPROM_SIZE-1];
+ const int tag = 0xff;
+
+ /* Data too large */
+ memset(buf, 0xa5, sizeof(buf));
+ TEST_ASSERT(cbi_set_board_info(tag, buf, sizeof(buf))
+ == EC_ERROR_OVERFLOW);
+
+ return EC_SUCCESS;
+}
+
+static int test_all_tags(void)
+{
+ uint8_t d8;
+ uint32_t d32;
+
+ /* Populate all data and read out */
+ d8 = 0x12;
+ TEST_ASSERT(cbi_set_board_info(CBI_TAG_BOARD_VERSION, &d8, sizeof(d8))
+ == EC_SUCCESS);
+ TEST_ASSERT(cbi_set_board_info(CBI_TAG_OEM_ID, &d8, sizeof(d8))
+ == EC_SUCCESS);
+ TEST_ASSERT(cbi_set_board_info(CBI_TAG_SKU_ID, &d8, sizeof(d8))
+ == EC_SUCCESS);
+ TEST_ASSERT(cbi_set_board_info(CBI_TAG_MODEL_ID, &d8, sizeof(d8))
+ == EC_SUCCESS);
+ TEST_ASSERT(cbi_set_board_info(CBI_TAG_FW_CONFIG, &d8, sizeof(d8))
+ == EC_SUCCESS);
+ TEST_ASSERT(cbi_set_board_info(CBI_TAG_PCB_SUPPLIER, &d8, sizeof(d8))
+ == EC_SUCCESS);
+ TEST_ASSERT(cbi_set_board_info(CBI_TAG_SSFC, &d8, sizeof(d8))
+ == EC_SUCCESS);
+ TEST_ASSERT(cbi_get_board_version(&d32) == EC_SUCCESS);
+ TEST_EQ(d32, d8, "0x%x");
+ TEST_ASSERT(cbi_get_oem_id(&d32) == EC_SUCCESS);
+ TEST_EQ(d32, d8, "0x%x");
+ TEST_ASSERT(cbi_get_sku_id(&d32) == EC_SUCCESS);
+ TEST_EQ(d32, d8, "0x%x");
+ TEST_ASSERT(cbi_get_model_id(&d32) == EC_SUCCESS);
+ TEST_EQ(d32, d8, "0x%x");
+ TEST_ASSERT(cbi_get_fw_config(&d32) == EC_SUCCESS);
+ TEST_EQ(d32, d8, "0x%x");
+ TEST_ASSERT(cbi_get_pcb_supplier(&d32) == EC_SUCCESS);
+ TEST_EQ(d32, d8, "0x%x");
+ TEST_ASSERT(cbi_get_ssfc(&d32) == EC_SUCCESS);
+ TEST_EQ(d32, d8, "0x%x");
+
+ /* Write protect */
+ gpio_set_level(GPIO_WP, 1);
+ TEST_ASSERT(cbi_write() == EC_ERROR_ACCESS_DENIED);
+
+ return EC_SUCCESS;
+}
+
+static int test_bad_crc(void)
+{
+ uint8_t d8;
+ const int tag = 0xff;
+ uint8_t size;
+ int crc;
+
+ /* Bad CRC */
+ d8 = 0xa5;
+ TEST_ASSERT(cbi_set_board_info(tag, &d8, sizeof(d8)) == EC_SUCCESS);
+ i2c_read8(I2C_PORT_EEPROM, I2C_ADDR_EEPROM_FLAGS,
+ offsetof(struct cbi_header, crc), &crc);
+ i2c_write8(I2C_PORT_EEPROM, I2C_ADDR_EEPROM_FLAGS,
+ offsetof(struct cbi_header, crc), ++crc);
+ cbi_invalidate_cache();
+ size = sizeof(d8);
+ TEST_ASSERT(cbi_get_board_info(tag, &d8, &size) == EC_ERROR_UNKNOWN);
+
+ return EC_SUCCESS;
+}
+
+void run_test(int argc, char **argv)
+{
+ RUN_TEST(test_uint8);
+ RUN_TEST(test_uint32);
+ RUN_TEST(test_string);
+ RUN_TEST(test_not_found);
+ RUN_TEST(test_too_large);
+ RUN_TEST(test_all_tags);
+ RUN_TEST(test_bad_crc);
+
+ test_print_result();
+}
diff --git a/test/compile_time_macros.c b/test/compile_time_macros.c
new file mode 100644
index 0000000000..28e7af500b
--- /dev/null
+++ b/test/compile_time_macros.c
@@ -0,0 +1,47 @@
+/* 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.
+ *
+ * Test compile_time_macros.h
+ */
+
+#include "common.h"
+#include "test_util.h"
+
+
+static int test_GENMASK(void)
+{
+ TEST_EQ(GENMASK(0, 0), 0x00000001U, "%u");
+ TEST_EQ(GENMASK(31, 0), 0xFFFFFFFFU, "%u");
+ TEST_EQ(GENMASK(4, 4), 0x00000010U, "%u");
+ TEST_EQ(GENMASK(4, 0), 0x0000001FU, "%u");
+ TEST_EQ(GENMASK(21, 21), 0x00200000U, "%u");
+ TEST_EQ(GENMASK(31, 31), 0x80000000U, "%u");
+
+ return EC_SUCCESS;
+}
+
+static int test_GENMASK_ULL(void)
+{
+ TEST_EQ(GENMASK_ULL(0, 0), 0x0000000000000001ULL, "%Lu");
+ TEST_EQ(GENMASK_ULL(31, 0), 0x00000000FFFFFFFFULL, "%Lu");
+ TEST_EQ(GENMASK_ULL(63, 0), 0xFFFFFFFFFFFFFFFFULL, "%Lu");
+ TEST_EQ(GENMASK_ULL(4, 4), 0x0000000000000010ULL, "%Lu");
+ TEST_EQ(GENMASK_ULL(4, 0), 0x000000000000001FULL, "%Lu");
+ TEST_EQ(GENMASK_ULL(21, 21), 0x0000000000200000ULL, "%Lu");
+ TEST_EQ(GENMASK_ULL(31, 31), 0x0000000080000000ULL, "%Lu");
+ TEST_EQ(GENMASK_ULL(63, 63), 0x8000000000000000ULL, "%Lu");
+ TEST_EQ(GENMASK_ULL(62, 60), 0x7000000000000000ULL, "%Lu");
+
+ return EC_SUCCESS;
+}
+
+void run_test(void)
+{
+ test_reset();
+
+ RUN_TEST(test_GENMASK);
+ RUN_TEST(test_GENMASK_ULL);
+
+ test_print_result();
+}
diff --git a/test/compile_time_macros.tasklist b/test/compile_time_macros.tasklist
new file mode 100644
index 0000000000..5ffe662d01
--- /dev/null
+++ b/test/compile_time_macros.tasklist
@@ -0,0 +1,9 @@
+/* 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.
+ */
+
+/**
+ * See CONFIG_TASK_LIST in config.h for details.
+ */
+#define CONFIG_TEST_TASK_LIST /* No test task */
diff --git a/test/kb_mkbp.c b/test/kb_mkbp.c
index 15952e74bb..324b5b3e91 100644
--- a/test/kb_mkbp.c
+++ b/test/kb_mkbp.c
@@ -101,6 +101,46 @@ int verify_key(int c, int r, int pressed)
return 1;
}
+int verify_key_v2(int c, int r, int pressed, int expect_more)
+{
+ struct host_cmd_handler_args args;
+ struct ec_response_get_next_event_v1 event;
+ int i;
+
+ args.version = 2;
+ args.command = EC_CMD_GET_NEXT_EVENT;
+ args.params = NULL;
+ args.params_size = 0;
+ args.response = &event;
+ args.response_max = sizeof(event);
+ args.response_size = 0;
+
+ if (c >= 0 && r >= 0) {
+ ccprintf("Verify %s (%d, %d). Expect %smore.\n",
+ action[pressed], c, r, expect_more ? "" : "no ");
+ set_state(c, r, pressed);
+
+ if (host_command_process(&args) != EC_RES_SUCCESS)
+ return 0;
+
+ if (!!(event.event_type & EC_MKBP_HAS_MORE_EVENTS) !=
+ expect_more) {
+ ccprintf("Incorrect more events!\n");
+ return 0;
+ }
+
+ for (i = 0; i < KEYBOARD_COLS_MAX; ++i)
+ if (event.data.key_matrix[i] != state[i])
+ return 0;
+ } else {
+ ccprintf("Verify no events available\n");
+ if (host_command_process(&args) != EC_RES_UNAVAILABLE)
+ return 0;
+ }
+
+ return 1;
+}
+
int mkbp_config(struct ec_params_mkbp_set_config params)
{
struct host_cmd_handler_args args;
@@ -179,6 +219,24 @@ int single_key_press(void)
return EC_SUCCESS;
}
+int single_key_press_v2(void)
+{
+ keyboard_clear_buffer();
+ clear_state();
+ TEST_ASSERT(press_key(0, 0, 1) == EC_SUCCESS);
+ TEST_ASSERT(FIFO_NOT_EMPTY());
+ TEST_ASSERT(press_key(0, 0, 0) == EC_SUCCESS);
+ TEST_ASSERT(FIFO_NOT_EMPTY());
+
+ clear_state();
+ TEST_ASSERT(verify_key_v2(0, 0, 1, 1));
+ TEST_ASSERT(FIFO_NOT_EMPTY());
+ TEST_ASSERT(verify_key_v2(0, 0, 0, 0));
+ TEST_ASSERT(FIFO_EMPTY());
+
+ return EC_SUCCESS;
+}
+
int test_fifo_size(void)
{
keyboard_clear_buffer();
@@ -236,6 +294,7 @@ void run_test(void)
/* Clear any pending events such as lid open. */
clear_mkbp_events();
RUN_TEST(single_key_press);
+ RUN_TEST(single_key_press_v2);
RUN_TEST(test_fifo_size);
RUN_TEST(test_enable);
RUN_TEST(fifo_underrun);
diff --git a/test/motion_lid.c b/test/motion_lid.c
index 3282812e86..1436c489b1 100644
--- a/test/motion_lid.c
+++ b/test/motion_lid.c
@@ -21,7 +21,6 @@
#include "util.h"
extern enum chipset_state_mask sensor_active;
-extern unsigned motion_interval;
/*
* Period in us for the motion task period.
@@ -179,7 +178,6 @@ static int test_lid_angle(void)
hook_notify(HOOK_CHIPSET_SHUTDOWN);
TEST_ASSERT(sensor_active == SENSOR_ACTIVE_S5);
TEST_ASSERT(accel_get_data_rate(lid) == 0);
- TEST_ASSERT(motion_interval == 0);
/* Go to S0 state */
hook_notify(HOOK_CHIPSET_SUSPEND);
@@ -187,7 +185,6 @@ static int test_lid_angle(void)
msleep(1000);
TEST_ASSERT(sensor_active == SENSOR_ACTIVE_S0);
TEST_ASSERT(accel_get_data_rate(lid) == (119000 | ROUND_UP_FLAG));
- TEST_ASSERT(motion_interval == TEST_LID_EC_RATE);
/*
* Set the base accelerometer as if it were sitting flat on a desk
diff --git a/test/test_config.h b/test/test_config.h
index 1dfe0a2ffd..a27da10187 100644
--- a/test/test_config.h
+++ b/test/test_config.h
@@ -43,11 +43,13 @@
#ifdef TEST_KB_MKBP
#define CONFIG_KEYBOARD_PROTOCOL_MKBP
#define CONFIG_MKBP_EVENT
+#define CONFIG_MKBP_USE_GPIO
#endif
#ifdef TEST_KB_SCAN
#define CONFIG_KEYBOARD_PROTOCOL_MKBP
#define CONFIG_MKBP_EVENT
+#define CONFIG_MKBP_USE_GPIO
#endif
#ifdef TEST_MATH_UTIL
diff --git a/util/cbi-util.c b/util/cbi-util.c
index aa8e5dd325..108b82da7f 100644
--- a/util/cbi-util.c
+++ b/util/cbi-util.c
@@ -37,6 +37,10 @@ enum {
OPT_SKU_ID,
OPT_DRAM_PART_NUM,
OPT_OEM_NAME,
+ OPT_MODEL_ID,
+ OPT_FW_CONFIG,
+ OPT_PCB_SUPPLIER,
+ OPT_SSFC,
OPT_SIZE,
OPT_ERASE_BYTE,
OPT_SHOW_ALL,
@@ -50,6 +54,10 @@ static const struct option opts_create[] = {
{"sku_id", 1, 0, OPT_SKU_ID},
{"dram_part_num", 1, 0, OPT_DRAM_PART_NUM},
{"oem_name", 1, 0, OPT_OEM_NAME},
+ {"model_id", 1, 0, OPT_MODEL_ID},
+ {"fw_config", 1, 0, OPT_FW_CONFIG},
+ {"pcb_supplier", 1, 0, OPT_PCB_SUPPLIER},
+ {"ssfc", 1, 0, OPT_SSFC},
{"size", 1, 0, OPT_SIZE},
{"erase_byte", 1, 0, OPT_ERASE_BYTE},
{NULL, 0, 0, 0}
@@ -67,7 +75,11 @@ static const char *field_name[] = {
"OEM_ID",
"SKU_ID",
"DRAM_PART_NUM",
- "OEM_NAME"
+ "OEM_NAME",
+ "MODEL_ID",
+ "FW_CONFIG",
+ "PCB_SUPPLIER",
+ "SSFC",
};
BUILD_ASSERT(ARRAY_SIZE(field_name) == CBI_TAG_COUNT);
@@ -89,6 +101,15 @@ const char help_create[] =
" --oem_name <value> OEM NAME\n"
" --erase_byte <uint8> Byte used for empty space. Default:0xff\n"
" --format_version <uint16> Data format version\n"
+ " --model_id <value> Model ID\n"
+ " --fw_config <value> Firmware configuration bit-field\n"
+ " --pcb_supplier <value> PCB supplier\n"
+ " --ssfc <value> Second Source Factory Cache bit-field\n"
+ "\n"
+ "<value> must be a positive integer <= 0XFFFFFFFF and field size can\n"
+ " be optionally specified by <value:size> notation: e.g. 0xabcd:4.\n"
+ "<size> must be a positive integer <= 0XFFFF.\n"
+ "<string> is a string\n"
"\n";
const char help_show[] =
@@ -240,6 +261,10 @@ static int cmd_create(int argc, char **argv)
struct integer_field ver;
struct integer_field oem;
struct integer_field sku;
+ struct integer_field model;
+ struct integer_field fw_config;
+ struct integer_field pcb_supplier;
+ struct integer_field ssfc;
const char *dram_part_num;
const char *oem_name;
} bi;
@@ -305,6 +330,22 @@ static int cmd_create(int argc, char **argv)
case OPT_OEM_NAME:
bi.oem_name = optarg;
break;
+ case OPT_MODEL_ID:
+ if (parse_integer_field(optarg, &bi.model))
+ return -1;
+ break;
+ case OPT_FW_CONFIG:
+ if (parse_integer_field(optarg, &bi.fw_config))
+ return -1;
+ break;
+ case OPT_PCB_SUPPLIER:
+ if (parse_integer_field(optarg, &bi.pcb_supplier))
+ return -1;
+ break;
+ case OPT_SSFC:
+ if (parse_integer_field(optarg, &bi.ssfc))
+ return -1;
+ break;
}
}
@@ -338,6 +379,12 @@ static int cmd_create(int argc, char **argv)
p = cbi_set_data(p, CBI_TAG_OEM_NAME, bi.oem_name,
strlen(bi.oem_name) + 1);
}
+ p = cbi_set_data(p, CBI_TAG_MODEL_ID, &bi.model.val, bi.model.size);
+ p = cbi_set_data(p, CBI_TAG_FW_CONFIG, &bi.fw_config.val,
+ bi.fw_config.size);
+ p = cbi_set_data(p, CBI_TAG_PCB_SUPPLIER, &bi.pcb_supplier.val,
+ bi.pcb_supplier.size);
+ p = cbi_set_data(p, CBI_TAG_SSFC, &bi.ssfc.val, bi.ssfc.size);
h->total_size = p - cbi;
h->crc = cbi_crc8(h);
@@ -458,6 +505,10 @@ static int cmd_show(int argc, char **argv)
print_integer(buf, CBI_TAG_BOARD_VERSION);
print_integer(buf, CBI_TAG_OEM_ID);
print_integer(buf, CBI_TAG_SKU_ID);
+ print_integer(buf, CBI_TAG_MODEL_ID);
+ print_integer(buf, CBI_TAG_FW_CONFIG);
+ print_integer(buf, CBI_TAG_PCB_SUPPLIER);
+ print_integer(buf, CBI_TAG_SSFC);
print_string(buf, CBI_TAG_DRAM_PART_NUM);
print_string(buf, CBI_TAG_OEM_NAME);
diff --git a/util/comm-dev.c b/util/comm-dev.c
index 33a69f9d6f..e85df349bb 100644
--- a/util/comm-dev.c
+++ b/util/comm-dev.c
@@ -68,7 +68,7 @@ static int ec_command_dev(int command, int version,
s_cmd.outsize = outsize;
s_cmd.outdata = (uint8_t *)outdata;
s_cmd.insize = insize;
- s_cmd.indata = indata;
+ s_cmd.indata = (uint8_t *)(indata);
r = ioctl(fd, CROS_EC_DEV_IOCXCMD, &s_cmd);
if (r < 0) {
@@ -102,7 +102,7 @@ static int ec_readmem_dev(int offset, int bytes, void *dest)
if (!fake_it) {
s_mem.offset = offset;
s_mem.bytes = bytes;
- s_mem.buffer = dest;
+ s_mem.buffer = (char *)(dest);
r = ioctl(fd, CROS_EC_DEV_IOCRDMEM, &s_mem);
if (r < 0 && errno == ENOTTY)
fake_it = 1;
@@ -129,8 +129,8 @@ static int ec_command_dev_v2(int command, int version,
assert(outsize == 0 || outdata != NULL);
assert(insize == 0 || indata != NULL);
- s_cmd = malloc(sizeof(struct cros_ec_command_v2) +
- MAX(outsize, insize));
+ s_cmd = (struct cros_ec_command_v2 *)(malloc(
+ sizeof(struct cros_ec_command_v2) + MAX(outsize, insize)));
if (s_cmd == NULL)
return -EC_RES_ERROR;
diff --git a/util/comm-host.c b/util/comm-host.c
index e459bdfaa8..429befa333 100644
--- a/util/comm-host.c
+++ b/util/comm-host.c
@@ -57,7 +57,7 @@ static int fake_readmem(int offset, int bytes, void *dest)
if (c < 0)
return c;
- buf = dest;
+ buf = (char *)(dest);
for (c = 0; c < EC_MEMMAP_TEXT_MAX; c++) {
if (buf[c] == 0)
return c;
diff --git a/util/comm-lpc.c b/util/comm-lpc.c
index 54f16b3ffc..16269f388c 100644
--- a/util/comm-lpc.c
+++ b/util/comm-lpc.c
@@ -225,7 +225,7 @@ static int ec_command_lpc_3(int command, int version,
static int ec_readmem_lpc(int offset, int bytes, void *dest)
{
int i = offset;
- char *s = dest;
+ char *s = (char *)(dest);
int cnt = 0;
if (offset >= EC_MEMMAP_SIZE - bytes)
diff --git a/util/comm-servo-spi.c b/util/comm-servo-spi.c
index 4010d2ec64..ef6dc7880b 100644
--- a/util/comm-servo-spi.c
+++ b/util/comm-servo-spi.c
@@ -114,7 +114,7 @@ static int send_request(int cmd, int version,
size_t block_size = sizeof(struct ec_host_request) + outsize;
size_t total_len = MPSSE_CMD_SIZE + block_size;
- txbuf = calloc(1, total_len);
+ txbuf = (uint8_t *)(calloc(1, total_len));
if (!txbuf)
return -ENOMEM;
@@ -168,7 +168,7 @@ free_request:
return ret;
}
-static int spi_read(void *buf, size_t size)
+static int spi_read(uint8_t *buf, size_t size)
{
uint8_t cmd[MPSSE_CMD_SIZE];
@@ -206,7 +206,7 @@ static int get_response(uint8_t *bodydest, size_t bodylen)
}
/* Now read the response header */
- if (spi_read(&hdr, sizeof(hdr)))
+ if (spi_read((uint8_t *)(&hdr), sizeof(hdr)))
goto read_error;
/* Check the header */
@@ -256,8 +256,9 @@ static int ec_command_servo_spi(int cmd, int version,
return -EC_RES_ERROR;
}
- if (send_request(cmd, version, outdata, outsize) == 0)
- ret = get_response(indata, insize);
+ if (send_request(cmd, version, (const uint8_t *)(outdata), outsize) ==
+ 0)
+ ret = get_response((uint8_t *)(indata), insize);
if (mpsse_set_pins(CS_L) != 0) {
fprintf(stderr, "Stop failed: %s\n",
diff --git a/util/ec_flash.c b/util/ec_flash.c
index 93705694e3..2fa6d5943d 100644
--- a/util/ec_flash.c
+++ b/util/ec_flash.c
@@ -36,7 +36,7 @@ int ec_flash_read(uint8_t *buf, int offset, int size)
int ec_flash_verify(const uint8_t *buf, int offset, int size)
{
- uint8_t *rbuf = malloc(size);
+ uint8_t *rbuf = (uint8_t *)(malloc(size));
int rv;
int i;
diff --git a/util/ec_panicinfo.c b/util/ec_panicinfo.c
index 47de4b2a4c..296774021f 100644
--- a/util/ec_panicinfo.c
+++ b/util/ec_panicinfo.c
@@ -23,6 +23,26 @@ static void print_panic_reg(int regnum, const uint32_t *regs, int index)
printf((regnum & 3) == 3 ? "\n" : " ");
}
+static void panic_show_extra_cm(const struct panic_data *pdata)
+{
+ enum {
+ CPU_NVIC_CFSR_BFARVALID = 1 << 15,
+ CPU_NVIC_CFSR_MFARVALID = 1 << 7,
+ };
+
+ printf("\n");
+ if (pdata->cm.cfsr & CPU_NVIC_CFSR_BFARVALID)
+ printf("bfar=%08x, ", pdata->cm.bfar);
+ if (pdata->cm.cfsr & CPU_NVIC_CFSR_MFARVALID)
+ printf("mfar=%08x, ", pdata->cm.mfar);
+ printf("cfsr=%08x, ", pdata->cm.cfsr);
+ printf("shcsr=%08x, ", pdata->cm.shcsr);
+ printf("hfsr=%08x, ", pdata->cm.hfsr);
+ printf("dfsr=%08x, ", pdata->cm.dfsr);
+ printf("ipsr=%08x", pdata->cm.regs[CORTEX_PANIC_REGISTER_IPSR]);
+ printf("\n");
+}
+
static int parse_panic_info_cm(const struct panic_data *pdata)
{
const uint32_t *lregs = pdata->cm.regs;
@@ -65,6 +85,8 @@ static int parse_panic_info_cm(const struct panic_data *pdata)
print_panic_reg(14, sregs, 5);
print_panic_reg(15, sregs, 6);
+ panic_show_extra_cm(pdata);
+
return 0;
}
diff --git a/util/ecst.c b/util/ecst.c
index 73e6deb0e4..773b2ef956 100755
--- a/util/ecst.c
+++ b/util/ecst.c
@@ -389,7 +389,8 @@ int main(int argc, char *argv[])
/* Copy back the restored arguments. */
for (tmp_ind = 0;
- tmp_ind < tmp_arg_num;
+ (tmp_ind < tmp_arg_num) &&
+ (arg_ind < MAX_ARGS);
tmp_ind++) {
strncpy(hdr_args[arg_ind++],
tmp_hdr_args[tmp_ind],
diff --git a/util/ectool.c b/util/ectool.c
index 63833eb6da..2419ac87d7 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -1054,7 +1054,7 @@ int cmd_flash_read(int argc, char *argv[])
int offset, size;
int rv;
char *e;
- char *buf;
+ uint8_t *buf;
if (argc < 4) {
fprintf(stderr,
@@ -1073,7 +1073,7 @@ int cmd_flash_read(int argc, char *argv[])
}
printf("Reading %d bytes at offset %d...\n", size, offset);
- buf = (char *)malloc(size);
+ buf = (uint8_t *)malloc(size);
if (!buf) {
fprintf(stderr, "Unable to allocate buffer.\n");
return -1;
@@ -1086,7 +1086,7 @@ int cmd_flash_read(int argc, char *argv[])
return rv;
}
- rv = write_file(argv[3], buf, size);
+ rv = write_file(argv[3], (const char *)(buf), size);
free(buf);
if (rv)
return rv;
@@ -1121,7 +1121,8 @@ int cmd_flash_write(int argc, char *argv[])
printf("Writing to offset %d...\n", offset);
/* Write data in chunks */
- rv = ec_flash_write(buf, offset, size);
+ rv = ec_flash_write((const uint8_t *)(buf), offset,
+ size);
free(buf);
@@ -1394,7 +1395,7 @@ static void *fp_download_frame(struct ec_response_fp_info *info, int index)
return NULL;
}
- ptr = buffer;
+ ptr = (uint8_t *)(buffer);
p.offset = index << FP_FRAME_INDEX_SHIFT;
while (size) {
stride = MIN(ec_max_insize, size);
@@ -1579,7 +1580,7 @@ int cmd_fp_frame(int argc, char *argv[])
struct ec_response_fp_info r;
int idx = (argc == 2 && !strcasecmp(argv[1], "raw")) ?
FP_FRAME_INDEX_RAW_IMAGE : FP_FRAME_INDEX_SIMPLE_IMAGE;
- void *buffer = fp_download_frame(&r, idx);
+ uint8_t *buffer = (uint8_t *)(fp_download_frame(&r, idx));
uint8_t *ptr = buffer;
int x, y;
@@ -1610,14 +1611,15 @@ frame_done:
int cmd_fp_template(int argc, char *argv[])
{
struct ec_response_fp_info r;
- struct ec_params_fp_template *p = ec_outbuf;
+ struct ec_params_fp_template *p =
+ (struct ec_params_fp_template *)(ec_outbuf);
/* TODO(b/78544921): removing 32 bits is a workaround for the MCU bug */
int max_chunk = ec_max_outsize
- offsetof(struct ec_params_fp_template, data) - 4;
int idx = -1;
char *e;
int size;
- void *buffer = NULL;
+ char *buffer = NULL;
uint32_t offset = 0;
int rv = 0;
@@ -1628,7 +1630,7 @@ int cmd_fp_template(int argc, char *argv[])
idx = strtol(argv[1], &e, 0);
if (!(e && *e)) {
- buffer = fp_download_frame(&r, idx + 1);
+ buffer = (char *)(fp_download_frame(&r, idx + 1));
if (!buffer) {
fprintf(stderr, "Failed to get FP template %d\n", idx);
return -1;
@@ -4339,6 +4341,9 @@ static int cmd_motionsense(int argc, char **argv)
case MOTIONSENSE_CHIP_LIS2DE:
printf("lis2de\n");
break;
+ case MOTIONSENSE_CHIP_ICM426XX:
+ printf("icm426xx\n");
+ break;
default:
printf("unknown\n");
}
@@ -6059,7 +6064,7 @@ int cmd_i2c_xfer(int argc, char *argv[])
write_len = argc;
if (write_len) {
- write_buf = malloc(write_len);
+ write_buf = (uint8_t *)(malloc(write_len));
for (i = 0; i < write_len; i++) {
write_buf[i] = strtol(argv[i], &e, 0);
if (e && *e) {
@@ -6808,21 +6813,27 @@ int cmd_board_version(int argc, char *argv[])
static void cmd_cbi_help(char *cmd)
{
fprintf(stderr,
- " Usage: %s get <type> [get_flag]\n"
- " Usage: %s set <type> <value> <size> [set_flag]\n"
- " <type> is one of:\n"
- " 0: BOARD_VERSION\n"
- " 1: OEM_ID\n"
- " 2: SKU_ID\n"
- " 3: DRAM_PART_NUM\n"
- " 4: OEM_NAME\n"
- " <size> is the size of the data in byte\n"
- " <value> is integer to be set, string for DRAM_PART_NUM/OEM_NAME\n"
- " [get_flag] is combination of:\n"
- " 01b: Invalidate cache and reload data from EEPROM\n"
- " [set_flag] is combination of:\n"
- " 01b: Skip write to EEPROM. Use for back-to-back writes\n"
- " 10b: Set all fields to defaults first\n", cmd, cmd);
+ " Usage: %s get <tag> [get_flag]\n"
+ " Usage: %s set <tag> <value/string> <size> [set_flag]\n"
+ " Usage: %s remove <tag> [set_flag]\n"
+ " <tag> is one of:\n"
+ " 0: BOARD_VERSION\n"
+ " 1: OEM_ID\n"
+ " 2: SKU_ID\n"
+ " 3: DRAM_PART_NUM (string)\n"
+ " 4: OEM_NAME (string)\n"
+ " 5: MODEL_ID\n"
+ " 6: FW_CONFIG\n"
+ " 7: PCB_VENDOR\n"
+ " 8: SSFC\n"
+ " <size> is the size of the data in byte. It should be zero for\n"
+ " string types.\n"
+ " <value/string> is an integer or a string to be set\n"
+ " [get_flag] is combination of:\n"
+ " 01b: Invalidate cache and reload data from EEPROM\n"
+ " [set_flag] is combination of:\n"
+ " 01b: Skip write to EEPROM. Use for back-to-back writes\n"
+ " 10b: Set all fields to defaults first\n", cmd, cmd, cmd);
}
/*
@@ -6843,7 +6854,7 @@ static int cmd_cbi(int argc, char *argv[])
}
/* Tag */
- tag = strtol(argv[2], &e, 0);
+ tag = (enum cbi_data_tag)(strtol(argv[2], &e, 0));
if (e && *e) {
fprintf(stderr, "Bad tag\n");
return -1;
@@ -7526,8 +7537,10 @@ static int cmd_tmp006cal_v0(int idx, int argc, char *argv[])
static int cmd_tmp006cal_v1(int idx, int argc, char *argv[])
{
struct ec_params_tmp006_get_calibration pg;
- struct ec_response_tmp006_get_calibration_v1 *rg = ec_inbuf;
- struct ec_params_tmp006_set_calibration_v1 *ps = ec_outbuf;
+ struct ec_response_tmp006_get_calibration_v1 *rg =
+ (struct ec_response_tmp006_get_calibration_v1 *)(ec_inbuf);
+ struct ec_params_tmp006_set_calibration_v1 *ps =
+ (struct ec_params_tmp006_set_calibration_v1 *)(ec_outbuf);
float val;
char *e;
int i, rv, cmdsize;
@@ -7737,7 +7750,8 @@ int cmd_port80_read(int argc, char *argv[])
writes = rsp.get_info.writes;
history_size = rsp.get_info.history_size;
- history = malloc(history_size*sizeof(uint16_t));
+ history = (uint16_t *)(
+ malloc(history_size * sizeof(uint16_t)));
if (!history) {
fprintf(stderr, "Unable to allocate buffer.\n");
return -1;
@@ -8096,8 +8110,8 @@ int cmd_tp_frame_get(int argc, char* argv[])
struct ec_response_tp_frame_info* r;
struct ec_params_tp_frame_get p;
- data = malloc(ec_max_insize);
- r = malloc(ec_max_insize);
+ data = (uint8_t *)(malloc(ec_max_insize));
+ r = (struct ec_response_tp_frame_info *)(malloc(ec_max_insize));
rv = ec_command(EC_CMD_TP_FRAME_INFO, 0, NULL, 0, r, ec_max_insize);
if (rv < 0) {
diff --git a/util/ectool_keyscan.c b/util/ectool_keyscan.c
index 46ba221f6e..9470641ec7 100644
--- a/util/ectool_keyscan.c
+++ b/util/ectool_keyscan.c
@@ -78,8 +78,8 @@ static int keyscan_read_fdt_matrix(struct keyscan_info *keyscan,
return -1;
}
keyscan->matrix_count = buf.st_size / 4;
- keyscan->matrix = calloc(keyscan->matrix_count,
- sizeof(*keyscan->matrix));
+ keyscan->matrix = (struct matrix_entry *)(calloc(
+ keyscan->matrix_count, sizeof(*keyscan->matrix)));
if (!keyscan->matrix) {
fprintf(stderr, "Out of memory for key matrix\n");
return -1;
@@ -137,7 +137,7 @@ static const unsigned char kbd_plain_xlate[] = {
'8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
'2', '3', '0', '.', 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50 - 0x5F */
- '\r', 0xff, 0xff
+ '\r', 0xff, 0xff, '\0'
};
/**
@@ -205,7 +205,7 @@ static int keyscan_add_to_scan(struct keyscan_info *keyscan, char **keysp,
/* Convert keycode to key if needed */
if (keycode == -1) {
- pos = strchr(kbd_plain_xlate, key);
+ pos = (uint8_t *)(strchr((char *)kbd_plain_xlate, key));
if (!pos) {
fprintf(stderr, "Key '%c' not found in xlate table\n",
key);
@@ -267,8 +267,9 @@ static int keyscan_process_keys(struct keyscan_info *keyscan, int linenum,
size = test->item_alloced * sizeof(struct keyscan_test_item);
new_size = size + KEYSCAN_ALLOC_STEP *
- sizeof(struct keyscan_test_item);
- test->items = realloc(test->items, new_size);
+ sizeof(struct keyscan_test_item);
+ test->items = (struct keyscan_test_item *)(realloc(test->items,
+ new_size));
if (!test->items) {
fprintf(stderr, "Out of memory realloc()\n");
return -1;
@@ -335,10 +336,10 @@ static enum keyscan_cmd keyscan_read_cmd(const char *str, int len)
for (i = 0; i < KEYSCAN_CMD_COUNT; i++) {
if (!strncmp(keyscan_cmd_name[i], str, len))
- return i;
+ return (enum keyscan_cmd)(i);
}
- return -1;
+ return (enum keyscan_cmd)(-1);
}
/**
@@ -584,7 +585,7 @@ static int run_test(struct keyscan_info *keyscan, struct keyscan_test *test)
/* Ask EC for results */
size = sizeof(*resp) + test->item_count;
- resp = malloc(size);
+ resp = (struct ec_result_keyscan_seq_ctrl *)(malloc(size));
if (!resp) {
fprintf(stderr, "Out of memory for results\n");
return -1;
diff --git a/util/iteflash.c b/util/iteflash.c
index c97e5d064c..5ceabe9ee1 100644
--- a/util/iteflash.c
+++ b/util/iteflash.c
@@ -1760,7 +1760,7 @@ static int parse_parameters(int argc, char **argv, struct iteflash_config *conf)
static void sighandler(int signum)
{
printf("\nCaught signal %d: %s\nExiting...\n",
- signum, sys_siglist[signum]);
+ signum, strsignal(signum));
exit_requested = 1;
}
diff --git a/util/stm32mon.c b/util/stm32mon.c
index 665c4b28b2..c0807ce9d8 100644
--- a/util/stm32mon.c
+++ b/util/stm32mon.c
@@ -412,7 +412,10 @@ int send_command(int fd, uint8_t cmd, payload_t *loads, int cnt,
int res, i, c;
payload_t *p;
int readcnt = 0;
- uint8_t cmd_frame[] = { SOF, cmd, 0xff ^ cmd }; /* XOR checksum */
+
+ uint8_t cmd_frame[] = { SOF, cmd,
+ /* XOR checksum */
+ (uint8_t)(0xff ^ cmd) };
/* only the SPI mode needs the Start Of Frame byte */
int cmd_off = mode == MODE_SPI ? 0 : 1;
@@ -434,7 +437,7 @@ int send_command(int fd, uint8_t cmd, payload_t *loads, int cnt,
for (p = loads, c = 0; c < cnt; c++, p++) {
uint8_t crc = 0;
int size = p->size;
- uint8_t *data = malloc(size + 1), *data_ptr;
+ uint8_t *data = (uint8_t *)(malloc(size + 1)), *data_ptr;
if (data == NULL) {
fprintf(stderr,
@@ -710,7 +713,7 @@ int command_ext_erase(int fd, uint16_t count, uint16_t start)
int i;
/* not a special value : build a list of pages */
load.size = 2 * (count + 1);
- pages = malloc(load.size);
+ pages = (uint16_t *)(malloc(load.size));
if (!pages)
return -ENOMEM;
load.data = (uint8_t *)pages;
@@ -754,7 +757,7 @@ int command_erase_i2c(int fd, uint16_t count, uint16_t start)
*/
load_cnt = 2;
load[1].size = 2 * count;
- pages = malloc(load[1].size);
+ pages = (uint16_t *)(malloc(load[1].size));
if (!pages)
return -ENOMEM;
load[1].data = (uint8_t *)pages;
@@ -789,7 +792,7 @@ int command_erase(int fd, uint16_t count, uint16_t start)
int i;
/* not a special value : build a list of pages */
load.size = count + 1;
- pages = malloc(load.size);
+ pages = (uint8_t *)(malloc(load.size));
if (!pages)
return -ENOMEM;
load.data = (uint8_t *)pages;
@@ -906,7 +909,7 @@ int read_flash(int fd, struct stm32_def *chip, const char *filename,
if (!size)
size = chip->flash_size;
- buffer = malloc(size);
+ buffer = (uint8_t *)(malloc(size));
if (!buffer) {
fprintf(stderr, "Cannot allocate %d bytes\n", size);
return -ENOMEM;
@@ -939,7 +942,7 @@ int write_flash(int fd, struct stm32_def *chip, const char *filename,
int res, written;
FILE *hnd;
int size = chip->flash_size;
- uint8_t *buffer = malloc(size);
+ uint8_t *buffer = (uint8_t *)(malloc(size));
if (!buffer) {
fprintf(stderr, "Cannot allocate %d bytes\n", size);
diff --git a/util/uut/main.c b/util/uut/main.c
index 64a84e2725..6218e016f5 100644
--- a/util/uut/main.c
+++ b/util/uut/main.c
@@ -213,7 +213,7 @@ static uint8_t *read_input_file(uint32_t size, const char *file_name)
uint8_t *buffer;
FILE *input_fp;
- buffer = malloc(size);
+ buffer = (uint8_t *)(malloc(size));
if (!buffer) {
fprintf(stderr, "Cannot allocate %d bytes\n", size);
return NULL;
@@ -341,7 +341,7 @@ int main(int argc, char *argv[])
/* Ensure non-zero size */
if (size == 0)
exit_uart_app(EC_FILE_ERR);
- opr_write_mem(aux_buf, addr, size);
+ opr_write_mem((uint8_t *)(aux_buf), addr, size);
} else {
size = param_get_file_size(file_name);
if (size == 0)
diff --git a/util/uut/opr.c b/util/uut/opr.c
index 27f4c3463d..72eb485953 100644
--- a/util/uut/opr.c
+++ b/util/uut/opr.c
@@ -193,7 +193,7 @@ void opr_write_mem(uint8_t *buffer, uint32_t addr, uint32_t size)
/* Read first token from string */
if (console)
- token = strtok(buffer, seps);
+ token = strtok((char *)(buffer), seps);
size_remain = size;
/* Main write loop */