diff options
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 @@ -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 */ |