diff options
author | YH Lin <yueherngl@google.com> | 2022-10-28 21:09:13 +0000 |
---|---|---|
committer | YH Lin <yueherngl@google.com> | 2022-10-28 21:09:13 +0000 |
commit | 19d4d68ffa8b6910d716ab5e1953c41b58614a57 (patch) | |
tree | bdff671e5ad3e71e30ab56f4f084f34a2fd72e28 /common | |
parent | 1afa995cc54968d86bec8a23bab66bb07742dbdf (diff) | |
parent | ab9a716db1e256b4b95cb3679b0ade49b488b938 (diff) | |
download | chrome-ec-19d4d68ffa8b6910d716ab5e1953c41b58614a57.tar.gz |
Merge remote-tracking branch cros/main into factory-brya-14909.124.B-main
Generated by: util/update_release_branch.py --baseboard brya --relevant_paths_file
baseboard/brya/relevant-paths.txt factory-brya-14909.124.B-main
Relevant changes:
git log --oneline 1afa995cc5..ab9a716db1 -- baseboard/brya board/agah
board/anahera board/banshee board/brya board/crota board/felwinter
board/gimble board/kano board/mithrax board/osiris board/primus
board/redrix board/taeko board/taniks board/vell board/volmar
driver/bc12/pi3usb9201_public.* driver/charger/bq25710.*
driver/ppc/nx20p348x.* driver/ppc/syv682x_public.*
driver/retimer/bb_retimer_public.* driver/tcpm/nct38xx.*
driver/tcpm/ps8xxx_public.* driver/tcpm/tcpci.* include/power/alderlake*
include/intel_x86.h power/alderlake* power/intel_x86.c
util/getversion.sh
4fced381a2 vell: Change SEQ_EC_ALL_SYS_PG signal
e31a1bc770 power/alderlake: Consistent GPIO_PG_EC_ALL_SYS_PWRG to intel_x86_get_pg_ec_all_sys_pwrgd
45ad08b8df power/alderlake: Add runtime CONFIG for power signal
7bcda9ace2 PCHG: Report errors to host
16da8285f9 tcpci: skip processing RX message when BIST mode enabled
BRANCH=None
BUG=b:245764044 b:253957352 b:229812911
TEST=`emerge-brya chromeos-ec`
Force-Relevant-Builds: all
Signed-off-by: YH Lin <yueherngl@google.com>
Change-Id: I2e71c606722cacb6a42fecb0b1afdd3df1e0f478
Diffstat (limited to 'common')
-rw-r--r-- | common/build.mk | 1 | ||||
-rw-r--r-- | common/cbi.c | 3 | ||||
-rw-r--r-- | common/chargen.c | 155 | ||||
-rw-r--r-- | common/charger.c | 22 | ||||
-rw-r--r-- | common/mock/charge_manager_mock.c | 14 | ||||
-rw-r--r-- | common/motion_sense.c | 174 | ||||
-rw-r--r-- | common/motion_sense_fifo.c | 51 | ||||
-rw-r--r-- | common/panic_output.c | 13 | ||||
-rw-r--r-- | common/peripheral_charger.c | 313 | ||||
-rw-r--r-- | common/system.c | 2 | ||||
-rw-r--r-- | common/usb_pd_dual_role.c | 3 | ||||
-rw-r--r-- | common/usb_pd_flags.c | 1 | ||||
-rw-r--r-- | common/usbc/usb_pd_dp_ufp.c | 2 | ||||
-rw-r--r-- | common/usbc/usb_pd_dpm.c | 99 | ||||
-rw-r--r-- | common/usbc/usb_pe_ctvpd_sm.c | 4 | ||||
-rw-r--r-- | common/usbc/usb_pe_drp_sm.c | 38 | ||||
-rw-r--r-- | common/usbc/usb_pe_private.h | 4 | ||||
-rw-r--r-- | common/usbc_intr_task.c | 8 | ||||
-rw-r--r-- | common/virtual_battery.c | 2 |
19 files changed, 527 insertions, 382 deletions
diff --git a/common/build.mk b/common/build.mk index ef429058f2..c9b2630de5 100644 --- a/common/build.mk +++ b/common/build.mk @@ -29,6 +29,7 @@ common-$(CONFIG_ACCEL_LIS2DH)+=math_util.o common-$(CONFIG_ACCEL_LIS2DS)+=math_util.o common-$(CONFIG_ACCEL_KXCJ9)+=math_util.o common-$(CONFIG_ACCEL_KX022)+=math_util.o +common-$(CONFIG_BODY_DETECTION)+=math_util.o common-$(CONFIG_TEMP_SENSOR_TMP112)+=math_util.o common-$(CONFIG_TEMP_SENSOR_PCT2075)+=math_util.o ifneq ($(CORE),cortex-m) diff --git a/common/cbi.c b/common/cbi.c index 2956621367..602fa422a0 100644 --- a/common/cbi.c +++ b/common/cbi.c @@ -216,7 +216,8 @@ static void cbi_remove_tag(void *const cbi, struct cbi_data *const d) h->total_size -= size; } -int cbi_set_board_info(enum cbi_data_tag tag, const uint8_t *buf, uint8_t size) +test_mockable int cbi_set_board_info(enum cbi_data_tag tag, const uint8_t *buf, + uint8_t size) { struct cbi_data *d; diff --git a/common/chargen.c b/common/chargen.c index cfbf8bb2ca..9b2c23ed79 100644 --- a/common/chargen.c +++ b/common/chargen.c @@ -11,8 +11,21 @@ #include "usb_console.h" #include "util.h" #include "watchdog.h" +#include "hooks.h" +#include "task.h" #ifndef SECTION_IS_RO + +/** + * Some unit tests do not have a watchdog enabled and the watchdog + * functions are stubbed. Define a default watchdog period in this case. + */ +#ifdef CONFIG_WATCHDOG_PERIOD_MS +#define CHARGEN_WATCHDOG_PERIOD_MS CONFIG_WATCHDOG_PERIOD_MS +#else +#define CHARGEN_WATCHDOG_PERIOD_MS 1600 +#endif + /* * Microseconds time to drain entire UART_TX console buffer at 115200 b/s, 10 * bits per character. @@ -20,57 +33,57 @@ #define BUFFER_DRAIN_TIME_US \ (1000000UL * 10 * CONFIG_UART_TX_BUF_SIZE / CONFIG_UART_BAUD_RATE) -/* - * Generate a stream of characters on the UART (and USB) console. - * - * The stream is an ever incrementing pattern of characters from the following - * set: 0..9A..Za..z. - * - * The two optional integer command line arguments work as follows: - * - * argv[1] - reset the pattern after this many characters have been printed. - * Setting this value to the width of the terminal window results - * in a very regular stream showing on the terminal, where it is - * easy to observe disruptions. - * argv[2] - limit number of printed characters to this amount. If not - * specified - keep printing indefinitely. - * - * Hitting 'x' on the keyboard stops the generator. - */ -static int command_chargen(int argc, const char **argv) -{ - int wrap_value = 0; - int wrap_counter = 0; - uint8_t c; - uint32_t seq_counter = 0; - uint32_t seq_number = 0; - timestamp_t prev_watchdog_time; +struct deferred_chargen_ctx { + int wrap_value; + uint32_t seq_number; + int (*putc)(int c); + int (*tx_is_blocked)(void); +}; +static struct deferred_chargen_ctx chargen_ctx; - int (*putc_)(int c) = uart_putc; - int (*tx_is_blocked_)(void) = uart_buffer_full; - - while (uart_getc() != -1 || usb_getc() != -1) - ; /* Drain received characters, if any. */ +static void acquire_console(void) +{ +#if !defined(CONFIG_USB_CONSOLE) && !defined(CONFIG_USB_CONSOLE_STREAM) + uart_shell_rx_bypass(true); +#endif +#if !defined(CONFIG_ZEPHYR) && !defined(BOARD_HOST) + /* The legacy fw console does not have an rx bypass feature (it is + * stubbed out). Disable the console task so that it does not + * steal character reads from chargen. + */ + if (task_start_called()) + task_disable_task(TASK_ID_CONSOLE); +#endif /* !CONFIG_ZEPHYR && !BOARD_HOST */ +} - if (argc > 1) - wrap_value = atoi(argv[1]); +static void release_console(void) +{ +#if !defined(CONFIG_USB_CONSOLE) && !defined(CONFIG_USB_CONSOLE_STREAM) + uart_shell_rx_bypass(false); +#endif +#if !defined(CONFIG_ZEPHYR) && !defined(BOARD_HOST) + if (task_start_called()) + task_enable_task(TASK_ID_CONSOLE); +#endif /* !CONFIG_ZEPHYR && !BOARD_HOST */ +} - if (argc > 2) - seq_number = atoi(argv[2]); +static void run_chargen(void) +{ + int wrap_value = chargen_ctx.wrap_value; + uint32_t seq_number = chargen_ctx.seq_number; + int (*putc_)(int c) = chargen_ctx.putc; + int (*tx_is_blocked_)(void) = chargen_ctx.tx_is_blocked; -#if defined(CONFIG_USB_CONSOLE) || defined(CONFIG_USB_CONSOLE_STREAM) - if (argc > 3) { - if (memcmp(argv[3], "usb", 3)) - return EC_ERROR_PARAM3; + timestamp_t prev_watchdog_time; + uint8_t c = '0'; + uint32_t seq_counter = 0; + int wrap_counter = 0; - putc_ = usb_putc; - tx_is_blocked_ = usb_console_tx_blocked; - } -#endif + acquire_console(); - uart_shell_stop(); + while (uart_getc() != -1 || usb_getc() != -1) + ; /* Drain received characters, if any. */ - c = '0'; prev_watchdog_time = get_time(); while (uart_getc() != 'x' && usb_getc() != 'x') { timestamp_t current_time; @@ -85,7 +98,7 @@ static int command_chargen(int argc, const char **argv) current_time = get_time(); if ((current_time.val - prev_watchdog_time.val) < - (CONFIG_WATCHDOG_PERIOD_MS * 1000 / 2)) + (CHARGEN_WATCHDOG_PERIOD_MS * 1000 / 2)) continue; watchdog_reload(); @@ -116,9 +129,57 @@ static int command_chargen(int argc, const char **argv) putc_('\n'); - uart_shell_start(); + release_console(); +} +DECLARE_DEFERRED(run_chargen); + +/* + * Generate a stream of characters on the UART (and USB) console. + * + * The stream is an ever incrementing pattern of characters from the following + * set: 0..9A..Za..z. + * + * The two optional integer command line arguments work as follows: + * + * argv[1] - reset the pattern after this many characters have been printed. + * Setting this value to the width of the terminal window results + * in a very regular stream showing on the terminal, where it is + * easy to observe disruptions. + * argv[2] - limit number of printed characters to this amount. If not + * specified - keep printing indefinitely. + * + * Hitting 'x' on the keyboard stops the generator. + */ +static int command_chargen(int argc, const char **argv) +{ + int wrap_value = 0; + uint32_t seq_number = 0; + + int (*putc_)(int c) = uart_putc; + int (*tx_is_blocked_)(void) = uart_buffer_full; + + if (argc > 1) + wrap_value = atoi(argv[1]); + + if (argc > 2) + seq_number = atoi(argv[2]); + +#if defined(CONFIG_USB_CONSOLE) || defined(CONFIG_USB_CONSOLE_STREAM) + if (argc > 3) { + if (memcmp(argv[3], "usb", 3)) + return EC_ERROR_PARAM3; + + putc_ = usb_putc; + tx_is_blocked_ = usb_console_tx_blocked; + } +#endif + + chargen_ctx.wrap_value = wrap_value; + chargen_ctx.seq_number = seq_number; + chargen_ctx.putc = putc_; + chargen_ctx.tx_is_blocked = tx_is_blocked_; - return EC_SUCCESS; + return hook_call_deferred(&run_chargen_data, 0); } DECLARE_SAFE_CONSOLE_COMMAND(chargen, command_chargen, #if defined(CONFIG_USB_CONSOLE) || defined(CONFIG_USB_CONSOLE_STREAM) diff --git a/common/charger.c b/common/charger.c index b289ba6a02..db780d59cf 100644 --- a/common/charger.c +++ b/common/charger.c @@ -279,7 +279,7 @@ enum ec_error_list charger_post_init(void) { int chgnum = 0; - if ((chgnum < 0) || (chgnum >= board_get_charger_chip_count())) { + if (chgnum >= board_get_charger_chip_count()) { CPRINTS("%s(%d) Invalid charger!", __func__, chgnum); return EC_ERROR_INVAL; } @@ -294,7 +294,7 @@ const struct charger_info *charger_get_info(void) { int chgnum = 0; - if ((chgnum < 0) || (chgnum >= board_get_charger_chip_count())) { + if (chgnum >= board_get_charger_chip_count()) { CPRINTS("%s(%d) Invalid charger!", __func__, chgnum); return NULL; } @@ -309,7 +309,7 @@ enum ec_error_list charger_get_status(int *status) { int chgnum = 0; - if ((chgnum < 0) || (chgnum >= board_get_charger_chip_count())) { + if (chgnum >= board_get_charger_chip_count()) { CPRINTS("%s(%d) Invalid charger!", __func__, chgnum); return EC_ERROR_INVAL; } @@ -324,7 +324,7 @@ enum ec_error_list charger_set_mode(int mode) { int chgnum = 0; - if ((chgnum < 0) || (chgnum >= board_get_charger_chip_count())) { + if (chgnum >= board_get_charger_chip_count()) { CPRINTS("%s(%d) Invalid charger!", __func__, chgnum); return EC_ERROR_INVAL; } @@ -602,7 +602,7 @@ enum ec_error_list charger_manufacturer_id(int *id) { int chgnum = 0; - if ((chgnum < 0) || (chgnum >= board_get_charger_chip_count())) { + if (chgnum >= board_get_charger_chip_count()) { CPRINTS("%s(%d) Invalid charger!", __func__, chgnum); return EC_ERROR_INVAL; } @@ -617,7 +617,7 @@ enum ec_error_list charger_device_id(int *id) { int chgnum = 0; - if ((chgnum < 0) || (chgnum >= board_get_charger_chip_count())) { + if (chgnum >= board_get_charger_chip_count()) { CPRINTS("%s(%d) Invalid charger!", __func__, chgnum); return EC_ERROR_INVAL; } @@ -632,7 +632,7 @@ enum ec_error_list charger_get_option(int *option) { int chgnum = 0; - if ((chgnum < 0) || (chgnum >= board_get_charger_chip_count())) { + if (chgnum >= board_get_charger_chip_count()) { CPRINTS("%s(%d) Invalid charger!", __func__, chgnum); return EC_ERROR_INVAL; } @@ -647,7 +647,7 @@ enum ec_error_list charger_set_option(int option) { int chgnum = 0; - if ((chgnum < 0) || (chgnum >= board_get_charger_chip_count())) { + if (chgnum >= board_get_charger_chip_count()) { CPRINTS("%s(%d) Invalid charger!", __func__, chgnum); return EC_ERROR_INVAL; } @@ -690,7 +690,7 @@ int chg_ramp_is_stable(void) { int chgnum = 0; - if ((chgnum < 0) || (chgnum >= board_get_charger_chip_count())) { + if (chgnum >= board_get_charger_chip_count()) { CPRINTS("%s(%d) Invalid charger!", __func__, chgnum); return 0; } @@ -705,7 +705,7 @@ int chg_ramp_is_detected(void) { int chgnum = 0; - if ((chgnum < 0) || (chgnum >= board_get_charger_chip_count())) { + if (chgnum >= board_get_charger_chip_count()) { CPRINTS("%s(%d) Invalid charger!", __func__, chgnum); return 0; } @@ -720,7 +720,7 @@ int chg_ramp_get_current_limit(void) { int chgnum = 0; - if ((chgnum < 0) || (chgnum >= board_get_charger_chip_count())) { + if (chgnum >= board_get_charger_chip_count()) { CPRINTS("%s(%d) Invalid charger!", __func__, chgnum); return 0; } diff --git a/common/mock/charge_manager_mock.c b/common/mock/charge_manager_mock.c index b27e7de241..c800b9b9b1 100644 --- a/common/mock/charge_manager_mock.c +++ b/common/mock/charge_manager_mock.c @@ -36,6 +36,20 @@ int charge_manager_get_active_charge_port(void) return 0; } +int charge_manager_get_charger_voltage(void) +{ + return 0; +} + +void charge_manager_force_ceil(int port, int ceil) +{ +} + +enum charge_supplier charge_manager_get_supplier(void) +{ + return CHARGE_SUPPLIER_NONE; +} + int charge_manager_get_vbus_voltage(int port) { return mock_ctrl_charge_manager.vbus_voltage_mv; diff --git a/common/motion_sense.c b/common/motion_sense.c index 38bc5ab702..c08909d24e 100644 --- a/common/motion_sense.c +++ b/common/motion_sense.c @@ -38,22 +38,12 @@ #define CPRINTS(format, args...) cprints(CC_MOTION_SENSE, format, ##args) #define CPRINTF(format, args...) cprintf(CC_MOTION_SENSE, format, ##args) -/* Delay between FIFO interruption. */ -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; STATIC_IF(CONFIG_CMD_ACCEL_INFO) int accel_disp; #define SENSOR_ACTIVE(_sensor) (sensor_active & (_sensor)->active_mask) -/* - * Adjustment in us to ec rate when calculating interrupt interval: - * To be sure the EC will send an interrupt even if it finishes processing - * events slightly earlier than the previous period. - */ -#define MOTION_SENSOR_INT_ADJUSTMENT_US 10 - mutex_t g_sensor_mutex; /* @@ -209,126 +199,6 @@ int motion_sense_set_data_rate(struct motion_sensor_t *sensor) return 0; } -static int -motion_sense_set_ec_rate_from_ap(const struct motion_sensor_t *sensor, - unsigned int new_rate_us) -{ - int odr_mhz = sensor->drv->get_data_rate(sensor); - - if (new_rate_us == 0) - return 0; - - if (odr_mhz == 0) - /* - * No event (interrupt or forced mode) are generated, - * any ec rate works. - */ - goto end_set_ec_rate_from_ap; - - /* - * If the EC collection rate is close to the sensor data rate, - * given variation from the EC scheduler, we want to be sure the EC is - * ready to send an event to the AP when either the interrupt arrives, - * or the EC is actively probing the sensor. - * Decrease the EC period by 5% to be sure to get at least one - * measurement at every collection time. - * We will apply that correction only if the ec rate is within 10% of - * the data rate. - * It is possible for sensors at the same ODR to not be in phase. - * One will have a delay guarantee to be less than its ODR. - */ - if (SECOND * 1100 / odr_mhz > new_rate_us) - new_rate_us = new_rate_us * 95 / 100; - -end_set_ec_rate_from_ap: - return MAX(new_rate_us, motion_min_interval); -} - -/* - * motion_sense_select_ec_rate - * - * Calculate the ec_rate for a given sensor. - * - sensor: sensor to use - * - config_id: determine the requester (AP or EC). - * - interrupt: - * If interrupt is set: return the sampling rate requested by AP or EC. - * If interrupt is not set and the sensor is in forced mode, - * we return the rate needed to probe the sensor at the right ODR. - * otherwise return the sampling rate requested by AP or EC. - * - * return rate in us. - */ -static int motion_sense_select_ec_rate(const struct motion_sensor_t *sensor, - enum sensor_config config_id, - int interrupt) -{ - if (interrupt == 0 && motion_sensor_in_forced_mode(sensor)) { - int rate_mhz = BASE_ODR(sensor->config[config_id].odr); - /* we have to run ec at the sensor frequency rate.*/ - if (rate_mhz > 0) - return SECOND * 1000 / rate_mhz; - else - return 0; - } else { - return sensor->config[config_id].ec_rate; - } -} - -/* motion_sense_ec_rate - * - * Calculate the sensor ec rate. It will be use to set the motion task polling - * rate. - * - * Return the EC rate, in us. - */ -static int motion_sense_ec_rate(struct motion_sensor_t *sensor) -{ - int ec_rate = 0, ec_rate_from_cfg; - - /* Check the AP setting first. */ - if (sensor_active != SENSOR_ACTIVE_S5) - ec_rate = motion_sense_select_ec_rate(sensor, SENSOR_CONFIG_AP, - 0); - - ec_rate_from_cfg = motion_sense_select_ec_rate( - sensor, motion_sense_get_ec_config(), 0); - - if (ec_rate_from_cfg != 0) - if (ec_rate == 0 || ec_rate_from_cfg < ec_rate) - ec_rate = ec_rate_from_cfg; - return ec_rate; -} - -/* - * motion_sense_set_motion_intervals - * - * Set the wake up interval for the motion sense thread. - * It is set to the highest frequency one of the sensors need to be polled at. - */ -static void motion_sense_set_motion_intervals(void) -{ - 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]; - /* - * If the sensor is sleeping, no need to check it periodically. - */ - if ((sensor->state != SENSOR_INITIALIZED) || - (sensor->drv->get_data_rate(sensor) == 0)) - continue; - - 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; - } - - ap_event_interval = - MAX(0, ec_int_rate - MOTION_SENSOR_INT_ADJUSTMENT_US); -} - /* Note: Always run on HOOK task, trigger by events from CHIPSET task. */ static inline int motion_sense_init(struct motion_sensor_t *sensor) { @@ -439,9 +309,6 @@ static void motion_sense_switch_sensor_rate(void) atomic_or(&odr_event_required, sensor_setup_mask); task_set_event(TASK_ID_MOTIONSENSE, TASK_EVENT_MOTION_ODR_CHANGE); - } else { - /* No sensor activated, reset host interval interval to 0. */ - ap_event_interval = 0; } /* disable the body detection since AP is suspended */ @@ -765,7 +632,6 @@ static int motion_sense_process(struct motion_sensor_t *sensor, uint32_t *event, /* ODR change was requested. */ if (is_odr_pending) { motion_sense_set_data_rate(sensor); - motion_sense_set_motion_intervals(); if (IS_ENABLED(CONFIG_ACCEL_FIFO)) motion_sense_fifo_insert_async_event(sensor, ASYNC_EVENT_ODR); @@ -891,8 +757,6 @@ void motion_sense_task(void *u) struct motion_sensor_t *sensor; uint8_t *lpc_status; - timestamp_t ts_last_int; - if (IS_ENABLED(CONFIG_MOTION_FILL_LPC_SENSE_DATA)) { lpc_status = host_get_memmap(EC_MEMMAP_ACC_STATUS); set_present(lpc_status); @@ -900,7 +764,6 @@ void motion_sense_task(void *u) if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { motion_sense_fifo_init(); - ts_last_int = get_time(); } while (1) { @@ -964,17 +827,14 @@ void motion_sense_task(void *u) */ if (IS_ENABLED(CONFIG_ACCEL_FIFO) && (motion_sense_fifo_bypass_needed() || + motion_sense_fifo_interrupt_needed() || event & (TASK_EVENT_MOTION_ODR_CHANGE | TASK_EVENT_MOTION_FLUSH_PENDING) || - motion_sense_fifo_over_thres() || - (ap_event_interval > 0 && - time_after(ts_begin_task.le.lo, - ts_last_int.le.lo + ap_event_interval)))) { + motion_sense_fifo_over_thres())) { if ((event & TASK_EVENT_MOTION_FLUSH_PENDING) == 0) { motion_sense_fifo_add_timestamp( __hw_clock_source_read()); } - ts_last_int = ts_begin_task; /* * Send an event if we know we are in S0 and the kernel * driver is listening, or the AP needs to be waken up. @@ -987,9 +847,7 @@ void motion_sense_task(void *u) motion_sense_fifo_wake_up_needed()))) { mkbp_send_event(EC_MKBP_EVENT_SENSOR_FIFO); } - if (motion_sense_fifo_bypass_needed()) - /* wakeup flag is a subset of bypass flag. */ - motion_sense_fifo_reset_needed_flags(); + motion_sense_fifo_reset_needed_flags(); } ts_end_task = get_time(); @@ -1158,18 +1016,20 @@ static enum ec_status host_cmd_motion_sense(struct host_cmd_handler_args *args) * has a value. */ if (in->ec_rate.data != EC_MOTION_SENSE_NO_VALUE) { - sensor->config[SENSOR_CONFIG_AP].ec_rate = - motion_sense_set_ec_rate_from_ap( - sensor, in->ec_rate.data * MSEC); - /* Bound the new sampling rate. */ - motion_sense_set_motion_intervals(); + int new_ec_rate = in->ec_rate.data * MSEC; + + if (new_ec_rate > 0) + new_ec_rate = + MAX(new_ec_rate, motion_min_interval); + sensor->config[SENSOR_CONFIG_AP].ec_rate = new_ec_rate; /* Force a collection to purge old events. */ task_set_event(TASK_ID_MOTIONSENSE, TASK_EVENT_MOTION_ODR_CHANGE); } - out->ec_rate.ret = motion_sense_ec_rate(sensor) / MSEC; + out->ec_rate.ret = + sensor->config[SENSOR_CONFIG_AP].ec_rate / MSEC; args->response_size = sizeof(out->ec_rate); break; @@ -1309,8 +1169,12 @@ static enum ec_status host_cmd_motion_sense(struct host_cmd_handler_args *args) break; case MOTIONSENSE_CMD_FIFO_FLUSH: - if (!IS_ENABLED(CONFIG_ACCEL_FIFO)) - return EC_RES_INVALID_PARAM; +/* TODO (http://b/255967867) Can't use the IS_ENABLED macro here because + * __fallthrough fails in clang as unreachable code. + */ +#ifndef CONFIG_ACCEL_FIFO + return EC_RES_INVALID_PARAM; +#else sensor = host_sensor_id_to_real_sensor( in->sensor_odr.sensor_num); if (sensor == NULL) @@ -1321,6 +1185,7 @@ static enum ec_status host_cmd_motion_sense(struct host_cmd_handler_args *args) task_set_event(TASK_ID_MOTIONSENSE, TASK_EVENT_MOTION_FLUSH_PENDING); __fallthrough; +#endif case MOTIONSENSE_CMD_FIFO_INFO: if (!IS_ENABLED(CONFIG_ACCEL_FIFO)) { /* @@ -1712,8 +1577,7 @@ static int command_accel_data_rate(int argc, const char **argv) ccprintf("Data rate for sensor %d: %d\n", id, sensor->drv->get_data_rate(sensor)); ccprintf("EC rate for sensor %d: %d\n", id, - motion_sense_ec_rate(sensor)); - ccprintf("Current Interrupt rate: %d\n", ap_event_interval); + sensor->config[SENSOR_CONFIG_AP].ec_rate); } return EC_SUCCESS; diff --git a/common/motion_sense_fifo.c b/common/motion_sense_fifo.c index 15db978a0b..d3887fa08f 100644 --- a/common/motion_sense_fifo.c +++ b/common/motion_sense_fifo.c @@ -17,6 +17,14 @@ #define CPRINTS(format, args...) cprints(CC_MOTION_SENSE, format, ##args) +/* + * Adjustment in us to ec rate when calculating interrupt interval: + * To be sure the EC will send an interrupt even if it finishes processing + * events slightly earlier than the previous period. + */ +#define MOTION_SENSOR_INT_ADJUSTMENT_US \ + (CONFIG_MOTION_MIN_SENSE_WAIT_TIME * MSEC / 10) + /** * Staged metadata for the fifo queue. * @read_ts: The timestamp at which the staged data was read. This value will @@ -88,6 +96,15 @@ static int bypass_needed; /** Need to wake up the AP. */ static int wake_up_needed; +/** Need to interrupt the AP. */ +static int ap_interrupt_needed; + +/** + * Timestamp of the first event put in the fifo during the + * last motion_task invocation. + */ +uint32_t ts_last_int[MAX_MOTION_SENSORS]; + /** * Check whether or not a give sensor data entry is a timestamp or not. * @@ -379,6 +396,11 @@ void motion_sense_fifo_init(void) online_calibration_init(); } +int motion_sense_fifo_interrupt_needed(void) +{ + return ap_interrupt_needed; +} + int motion_sense_fifo_bypass_needed(void) { return bypass_needed; @@ -391,6 +413,18 @@ int motion_sense_fifo_wake_up_needed(void) void motion_sense_fifo_reset_needed_flags(void) { + int i; + + if (ap_interrupt_needed) { + ap_interrupt_needed = 0; + /* + * The FIFO is emptied, note timestamp of the last event sent + * as we start counting the delay based on that timestamp. + */ + for (i = 0; i < MAX_MOTION_SENSORS; i++) + if (!is_new_timestamp(i)) + ts_last_int[i] = next_timestamp[i].prev; + } wake_up_needed = 0; bypass_needed = 0; } @@ -418,12 +452,20 @@ void motion_sense_fifo_stage_data(struct ec_response_motion_sensor_data *data, struct motion_sensor_t *sensor, int valid_data, uint32_t time) { + int id = data->sensor_num; + if (IS_ENABLED(CONFIG_SENSOR_TIGHT_TIMESTAMPS)) { /* First entry, save the time for spreading later. */ if (!fifo_staged.count) fifo_staged.read_ts = __hw_clock_source_read(); fifo_stage_timestamp(time, data->sensor_num); } + if (sensor->config[SENSOR_CONFIG_AP].ec_rate > 0 && + time_after(time, ts_last_int[id] + + sensor->config[SENSOR_CONFIG_AP].ec_rate - + MOTION_SENSOR_INT_ADJUSTMENT_US)) { + ap_interrupt_needed = 1; + } fifo_stage_unit(data, sensor, valid_data); } @@ -632,6 +674,15 @@ void motion_sense_fifo_reset(void) void motion_sense_set_data_period(int sensor_num, uint32_t data_period) { expected_data_periods[sensor_num] = data_period; + /* + * Reset the timestamp: + * - Avoid overflow when the sensor has been disabled for a long + * time. + * - First ODR setting. + * We may not send the first sample on time, but that is acceptable + * for CTS. + */ + ts_last_int[sensor_num] = __hw_clock_source_read(); next_timestamp_initialized &= ~BIT(sensor_num); } diff --git a/common/panic_output.c b/common/panic_output.c index b1fab3bebe..2f92e65514 100644 --- a/common/panic_output.c +++ b/common/panic_output.c @@ -418,14 +418,21 @@ host_command_panic_info(struct host_cmd_handler_args *args) { uint32_t pdata_size = get_panic_data_size(); uintptr_t pdata_start = get_panic_data_start(); - struct panic_data *pdata; + struct panic_data *pdata = panic_get_data(); if (pdata_start && pdata_size > 0) { - ASSERT(pdata_size <= args->response_max); + if (pdata_size > args->response_max) { + panic_printf("Panic data size %d is too " + "large, truncating to %d\n", + pdata_size, args->response_max); + pdata_size = args->response_max; + if (pdata) { + pdata->flags |= PANIC_DATA_FLAG_TRUNCATED; + } + } memcpy(args->response, (void *)pdata_start, pdata_size); args->response_size = pdata_size; - pdata = panic_get_data(); if (pdata) { /* Data has now been returned */ pdata->flags |= PANIC_DATA_FLAG_OLD_HOSTCMD; diff --git a/common/peripheral_charger.c b/common/peripheral_charger.c index 5767315a78..08cc7f3223 100644 --- a/common/peripheral_charger.c +++ b/common/peripheral_charger.c @@ -26,46 +26,48 @@ static struct queue const host_events = QUEUE_NULL(PCHG_EVENT_QUEUE_SIZE, uint32_t); struct mutex host_event_mtx; -static void pchg_queue_event(struct pchg *ctx, enum pchg_event event) -{ - mutex_lock(&ctx->mtx); - if (queue_add_unit(&ctx->events, &event) == 0) { - ctx->dropped_event_count++; - CPRINTS("ERR: Queue is full"); - } - mutex_unlock(&ctx->mtx); -} - -static void pchg_queue_host_event(struct pchg *ctx, uint32_t event) -{ - size_t len; - - event |= EC_MKBP_PCHG_PORT_TO_EVENT(PCHG_CTX_TO_PORT(ctx)); - - mutex_lock(&host_event_mtx); - len = queue_add_unit(&host_events, &event); - mutex_unlock(&host_event_mtx); - if (len == 0) { - ctx->dropped_host_event_count++; - CPRINTS("ERR: Host event queue is full"); - /* Send a reminder. */ - mkbp_send_event(EC_MKBP_EVENT_PCHG); - return; - } - - mkbp_send_event(EC_MKBP_EVENT_PCHG); -} - -static const char *_text_state(enum pchg_state state) +/* + * Events and errors to be reported to the host in each chipset state. + * + * Off: None + * Suspend: Device attach or detach (for wake-up) + * On: SoC change and all other events and new errors except FW update. + * FW update events are separately reported. + * + * TODO:Allow the host to update the masks. + */ +struct pchg_policy_t pchg_policy_on = { + .evt_mask = + BIT(PCHG_EVENT_IRQ) | BIT(PCHG_EVENT_RESET) | + BIT(PCHG_EVENT_INITIALIZED) | BIT(PCHG_EVENT_ENABLED) | + BIT(PCHG_EVENT_DISABLED) | BIT(PCHG_EVENT_DEVICE_DETECTED) | + BIT(PCHG_EVENT_DEVICE_CONNECTED) | BIT(PCHG_EVENT_DEVICE_LOST) | + BIT(PCHG_EVENT_CHARGE_STARTED) | BIT(PCHG_EVENT_CHARGE_UPDATE) | + BIT(PCHG_EVENT_CHARGE_ENDED) | BIT(PCHG_EVENT_CHARGE_STOPPED) | + BIT(PCHG_EVENT_ERROR) | BIT(PCHG_EVENT_IN_NORMAL) | + BIT(PCHG_EVENT_ENABLE) | BIT(PCHG_EVENT_DISABLE), + .err_mask = GENMASK(0, PCHG_ERROR_COUNT - 1), +}; + +struct pchg_policy_t pchg_policy_suspend = { + .evt_mask = BIT(PCHG_EVENT_DEVICE_DETECTED) | + BIT(PCHG_EVENT_DEVICE_LOST), + .err_mask = 0, +}; + +static const char *_text_mode(enum pchg_mode mode) { - /* TODO: Use "S%d" for normal build. */ - static const char *const state_names[] = EC_PCHG_STATE_TEXT; - BUILD_ASSERT(ARRAY_SIZE(state_names) == PCHG_STATE_COUNT); + static const char *const mode_names[] = { + [PCHG_MODE_NORMAL] = "NORMAL", + [PCHG_MODE_DOWNLOAD] = "DOWNLOAD", + [PCHG_MODE_PASSTHRU] = "PASSTHRU", + }; + BUILD_ASSERT(ARRAY_SIZE(mode_names) == PCHG_MODE_COUNT); - if (state >= sizeof(state_names)) + if (mode < 0 || mode >= PCHG_MODE_COUNT) return "UNDEF"; - return state_names[state]; + return mode_names[mode]; } static const char *_text_event(enum pchg_event event) @@ -89,14 +91,13 @@ static const char *_text_event(enum pchg_event event) [PCHG_EVENT_UPDATE_CLOSED] = "UPDATE_CLOSED", [PCHG_EVENT_UPDATE_WRITTEN] = "UPDATE_WRITTEN", [PCHG_EVENT_IN_NORMAL] = "IN_NORMAL", - [PCHG_EVENT_CHARGE_ERROR] = "CHARGE_ERROR", - [PCHG_EVENT_UPDATE_ERROR] = "UPDATE_ERROR", - [PCHG_EVENT_OTHER_ERROR] = "OTHER_ERROR", + [PCHG_EVENT_ERROR] = "ERROR", [PCHG_EVENT_ENABLE] = "ENABLE", [PCHG_EVENT_DISABLE] = "DISABLE", [PCHG_EVENT_UPDATE_OPEN] = "UPDATE_OPEN", [PCHG_EVENT_UPDATE_WRITE] = "UPDATE_WRITE", [PCHG_EVENT_UPDATE_CLOSE] = "UPDATE_CLOSE", + [PCHG_EVENT_UPDATE_ERROR] = "UPDATE_ERROR", }; BUILD_ASSERT(ARRAY_SIZE(event_names) == PCHG_EVENT_COUNT); @@ -106,6 +107,84 @@ static const char *_text_event(enum pchg_event event) return event_names[event]; } +static const char *_text_error(uint32_t error) +{ + static const char *const error_names[] = { + [PCHG_ERROR_COMMUNICATION] = "COMMUNICATION", + [PCHG_ERROR_OVER_TEMPERATURE] = "OVER_TEMPERATURE", + [PCHG_ERROR_OVER_CURRENT] = "OVER_CURRENT", + [PCHG_ERROR_FOREIGN_OBJECT] = "FOREIGN_OBJECT", + [PCHG_ERROR_RESPONSE] = "RESPONSE", + [PCHG_ERROR_FW_VERSION] = "FW_VERSION", + [PCHG_ERROR_INVALID_FW] = "INVALID_FW", + [PCHG_ERROR_WRITE_FLASH] = "WRITE_FLASH", + [PCHG_ERROR_OTHER] = "OTHER", + }; + BUILD_ASSERT(ARRAY_SIZE(error_names) == PCHG_ERROR_COUNT); + int ffs = __builtin_ffs(error) - 1; + + if (0 <= ffs && ffs < PCHG_ERROR_COUNT) + return error_names[ffs]; + + return "UNDEF"; +} + +static void pchg_queue_event(struct pchg *ctx, enum pchg_event event) +{ + mutex_lock(&ctx->mtx); + if (queue_add_unit(&ctx->events, &event) == 0) { + ctx->dropped_event_count++; + CPRINTS("WARN: Queue is full."); + } + mutex_unlock(&ctx->mtx); +} + +static void pchg_queue_host_event(struct pchg *ctx, uint32_t event) +{ + int len; + size_t i; + uint32_t last_event; + + event |= EC_MKBP_PCHG_PORT_TO_EVENT(PCHG_CTX_TO_PORT(ctx)); + + mutex_lock(&host_event_mtx); + i = queue_count(&host_events); + if (i > 0) { + queue_peek_units(&host_events, &last_event, i - 1, 1); + if (last_event != event) + /* New event */ + len = queue_add_unit(&host_events, &event); + else + /* Same event already in a queue. */ + len = -1; + } else { + len = queue_add_unit(&host_events, &event); + } + mutex_unlock(&host_event_mtx); + + if (len < 0) { + CPRINTS("INFO: Skipped back-to-back host event"); + } else if (len == 0) { + ctx->dropped_host_event_count++; + CPRINTS("WARN: Host event queue is full"); + } + + mkbp_send_event(EC_MKBP_EVENT_PCHG); +} + +static const char *_text_state(enum pchg_state state) +{ + /* TODO: Use "S%d" for normal build. */ + static const char *const state_names[] = EC_PCHG_STATE_TEXT; + + BUILD_ASSERT(ARRAY_SIZE(state_names) == PCHG_STATE_COUNT); + + if (state >= sizeof(state_names)) + return "UNDEF"; + + return state_names[state]; +} + static void _clear_port(struct pchg *ctx) { mutex_lock(&ctx->mtx); @@ -138,12 +217,14 @@ static enum pchg_state pchg_reset(struct pchg *ctx) state = PCHG_STATE_INITIALIZED; pchg_queue_event(ctx, PCHG_EVENT_ENABLE); } else if (rv != EC_SUCCESS_IN_PROGRESS) { + ctx->event = PCHG_EVENT_ERROR; + ctx->error |= PCHG_ERROR_MASK(PCHG_ERROR_COMMUNICATION); CPRINTS("ERR: Failed to reset to normal mode"); } - } else { + } else if (ctx->mode == PCHG_MODE_DOWNLOAD) { state = PCHG_STATE_DOWNLOAD; pchg_queue_event(ctx, PCHG_EVENT_UPDATE_OPEN); - } + } /* No-op for passthru mode */ return state; } @@ -167,13 +248,6 @@ static void pchg_state_initialized(struct pchg *ctx) { int rv; - if (ctx->event == PCHG_EVENT_ENABLE) - ctx->error &= ~PCHG_ERROR_HOST; - - /* Spin in INITIALIZED until error condition is cleared. */ - if (ctx->error) - return; - switch (ctx->event) { case PCHG_EVENT_RESET: ctx->state = pchg_reset(ctx); @@ -182,8 +256,11 @@ static void pchg_state_initialized(struct pchg *ctx) rv = ctx->cfg->drv->enable(ctx, true); if (rv == EC_SUCCESS) ctx->state = PCHG_STATE_ENABLED; - else if (rv != EC_SUCCESS_IN_PROGRESS) + else if (rv != EC_SUCCESS_IN_PROGRESS) { + ctx->event = PCHG_EVENT_ERROR; + ctx->error |= PCHG_ERROR_MASK(PCHG_ERROR_COMMUNICATION); CPRINTS("ERR: Failed to enable"); + } break; case PCHG_EVENT_ENABLED: ctx->state = PCHG_STATE_ENABLED; @@ -202,12 +279,14 @@ static void pchg_state_enabled(struct pchg *ctx) ctx->state = pchg_reset(ctx); break; case PCHG_EVENT_DISABLE: - ctx->error |= PCHG_ERROR_HOST; rv = ctx->cfg->drv->enable(ctx, false); if (rv == EC_SUCCESS) ctx->state = PCHG_STATE_INITIALIZED; - else if (rv != EC_SUCCESS_IN_PROGRESS) + else if (rv != EC_SUCCESS_IN_PROGRESS) { + ctx->event = PCHG_EVENT_ERROR; + ctx->error |= PCHG_ERROR_MASK(PCHG_ERROR_COMMUNICATION); CPRINTS("ERR: Failed to disable"); + } break; case PCHG_EVENT_DISABLED: ctx->state = PCHG_STATE_INITIALIZED; @@ -237,12 +316,14 @@ static void pchg_state_detected(struct pchg *ctx) ctx->state = pchg_reset(ctx); break; case PCHG_EVENT_DISABLE: - ctx->error |= PCHG_ERROR_HOST; rv = ctx->cfg->drv->enable(ctx, false); if (rv == EC_SUCCESS) ctx->state = PCHG_STATE_INITIALIZED; - else if (rv != EC_SUCCESS_IN_PROGRESS) + else if (rv != EC_SUCCESS_IN_PROGRESS) { + ctx->event = PCHG_EVENT_ERROR; + ctx->error |= PCHG_ERROR_MASK(PCHG_ERROR_COMMUNICATION); CPRINTS("ERR: Failed to disable"); + } break; case PCHG_EVENT_DISABLED: ctx->state = PCHG_STATE_INITIALIZED; @@ -273,12 +354,14 @@ static void pchg_state_connected(struct pchg *ctx) ctx->state = pchg_reset(ctx); break; case PCHG_EVENT_DISABLE: - ctx->error |= PCHG_ERROR_HOST; rv = ctx->cfg->drv->enable(ctx, false); if (rv == EC_SUCCESS) ctx->state = PCHG_STATE_INITIALIZED; - else if (rv != EC_SUCCESS_IN_PROGRESS) + else if (rv != EC_SUCCESS_IN_PROGRESS) { + ctx->event = PCHG_EVENT_ERROR; + ctx->error |= PCHG_ERROR_MASK(PCHG_ERROR_COMMUNICATION); CPRINTS("ERR: Failed to disable"); + } break; case PCHG_EVENT_DISABLED: ctx->state = PCHG_STATE_INITIALIZED; @@ -290,9 +373,6 @@ static void pchg_state_connected(struct pchg *ctx) ctx->battery_percent = 0; ctx->state = PCHG_STATE_ENABLED; break; - case PCHG_EVENT_CHARGE_ERROR: - ctx->state = PCHG_STATE_INITIALIZED; - break; default: break; } @@ -307,12 +387,14 @@ static void pchg_state_charging(struct pchg *ctx) ctx->state = pchg_reset(ctx); break; case PCHG_EVENT_DISABLE: - ctx->error |= PCHG_ERROR_HOST; rv = ctx->cfg->drv->enable(ctx, false); if (rv == EC_SUCCESS) ctx->state = PCHG_STATE_INITIALIZED; - else if (rv != EC_SUCCESS_IN_PROGRESS) + else if (rv != EC_SUCCESS_IN_PROGRESS) { + ctx->event = PCHG_EVENT_ERROR; + ctx->error |= PCHG_ERROR_MASK(PCHG_ERROR_COMMUNICATION); CPRINTS("ERR: Failed to disable"); + } break; case PCHG_EVENT_DISABLED: ctx->state = PCHG_STATE_INITIALIZED; @@ -323,9 +405,6 @@ static void pchg_state_charging(struct pchg *ctx) ctx->battery_percent = 0; ctx->state = PCHG_STATE_ENABLED; break; - case PCHG_EVENT_CHARGE_ERROR: - ctx->state = PCHG_STATE_INITIALIZED; - break; case PCHG_EVENT_CHARGE_ENDED: case PCHG_EVENT_CHARGE_STOPPED: ctx->state = PCHG_STATE_CONNECTED; @@ -407,6 +486,25 @@ static void pchg_state_downloading(struct pchg *ctx) } } +static int pchg_should_notify(struct pchg *ctx, enum pchg_chipset_state state, + uint32_t prev_error, uint8_t prev_battery) +{ + if (ctx->event == PCHG_EVENT_ERROR) { + uint32_t err = ctx->error & ctx->policy[state]->err_mask; + /* Report only 0->1. */ + return ((err ^ prev_error) & err) ? 1 : 0; + } + + if (BIT(ctx->event) & ctx->policy[state]->evt_mask) { + if (ctx->event == PCHG_EVENT_CHARGE_UPDATE) + /* Report only new SoC. */ + return ctx->battery_percent != prev_battery; + return 1; + } + + return 0; +} + /** * Process an event. * @@ -428,6 +526,7 @@ static int pchg_run(struct pchg *ctx) { enum pchg_state previous_state = ctx->state; uint8_t previous_battery = ctx->battery_percent; + uint32_t previous_error = ctx->error; int port = PCHG_CTX_TO_PORT(ctx); int rv; @@ -442,11 +541,17 @@ static int pchg_run(struct pchg *ctx) CPRINTS("P%d Run in STATE_%s for EVENT_%s", port, _text_state(ctx->state), _text_event(ctx->event)); + /* + * IRQ event is further translated to an actual event unless we're + * in passthru mode, where IRQ events will be passed to the host. + */ if (ctx->event == PCHG_EVENT_IRQ) { - rv = ctx->cfg->drv->get_event(ctx); - if (rv) { - CPRINTS("ERR: Failed to get event (%d)", rv); - return 0; + if (ctx->mode != PCHG_MODE_PASSTHRU) { + rv = ctx->cfg->drv->get_event(ctx); + if (rv) { + CPRINTS("ERR: Failed to get event (%d)", rv); + return 0; + } } CPRINTS(" EVENT_%s", _text_event(ctx->event)); } @@ -490,38 +595,29 @@ static int pchg_run(struct pchg *ctx) if (ctx->battery_percent != previous_battery) CPRINTS("Battery %u%%", ctx->battery_percent); - /* - * Notify the host of - * - [S0] Charge update with SoC change and all other events except - * FW update events. - * - [S3/S0IX] Device attach or detach (for wake-up) - * - [S5/G3] No events. - */ + if (ctx->event == PCHG_EVENT_ERROR) { + /* Print (only one) new error. */ + uint32_t err = (ctx->error ^ previous_error) & ctx->error; + + if (err) + CPRINTS("ERROR_%s", _text_error(err)); + } + if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) + /* Chipset off */ return 0; - - if (chipset_in_state(CHIPSET_STATE_ANY_SUSPEND)) { + else if (chipset_in_state(CHIPSET_STATE_ANY_SUSPEND)) { + /* Chipset in suspend */ if (IS_ENABLED(CONFIG_LID_SWITCH) && !lid_is_open()) /* Don't wake up if the lid is closed. */ return 0; - return (ctx->event == PCHG_EVENT_DEVICE_DETECTED || - ctx->event == PCHG_EVENT_DEVICE_LOST); + return pchg_should_notify(ctx, PCHG_CHIPSET_STATE_SUSPEND, + previous_error, previous_battery); + } else { + /* Chipset on */ + return pchg_should_notify(ctx, PCHG_CHIPSET_STATE_ON, + previous_error, previous_battery); } - - if (ctx->event == PCHG_EVENT_CHARGE_UPDATE) - return ctx->battery_percent != previous_battery; - - /* Don't report FW update events because they're separately reported. */ - if (ctx->event == PCHG_EVENT_UPDATE_OPENED || - ctx->event == PCHG_EVENT_UPDATE_CLOSED || - ctx->event == PCHG_EVENT_UPDATE_WRITTEN || - ctx->event == PCHG_EVENT_UPDATE_ERROR || - ctx->event == PCHG_EVENT_UPDATE_OPEN || - ctx->event == PCHG_EVENT_UPDATE_WRITE || - ctx->event == PCHG_EVENT_UPDATE_CLOSE) - return 0; - - return ctx->event != PCHG_EVENT_NONE; } void pchg_irq(enum gpio_signal signal) @@ -629,7 +725,7 @@ DECLARE_HOST_COMMAND(EC_CMD_PCHG_COUNT, hc_pchg_count, EC_VER_MASK(0)); static enum ec_status hc_pchg(struct host_cmd_handler_args *args) { - const struct ec_params_pchg *p = args->params; + const struct ec_params_pchg_v3 *p = args->params; struct ec_response_pchg_v2 *r = args->response; int port = p->port; struct pchg *ctx; @@ -642,6 +738,7 @@ static enum ec_status hc_pchg(struct host_cmd_handler_args *args) return EC_RES_INVALID_PARAM; ctx = &pchgs[port]; + mutex_lock(&ctx->mtx); if (ctx->state == PCHG_STATE_CONNECTED && ctx->battery_percent >= ctx->cfg->full_percent) @@ -655,13 +752,21 @@ static enum ec_status hc_pchg(struct host_cmd_handler_args *args) r->dropped_event_count = ctx->dropped_event_count; r->dropped_host_event_count = ctx->dropped_host_event_count; + /* Clear error flags acked by the host. */ + if (args->version > 2) + ctx->error &= ~p->error; + + /* v2 and v3 have the same response struct. */ args->response_size = args->version == 1 ? sizeof(struct ec_response_pchg) : sizeof(*r); + mutex_unlock(&ctx->mtx); + return EC_RES_SUCCESS; } -DECLARE_HOST_COMMAND(EC_CMD_PCHG, hc_pchg, EC_VER_MASK(1) | EC_VER_MASK(2)); +DECLARE_HOST_COMMAND(EC_CMD_PCHG, hc_pchg, + EC_VER_MASK(1) | EC_VER_MASK(2) | EC_VER_MASK(3)); int pchg_get_next_event(uint8_t *out) { @@ -747,6 +852,23 @@ static enum ec_status hc_pchg_update(struct host_cmd_handler_args *args) ctx->update.crc32 = p->crc32; pchg_queue_event(ctx, PCHG_EVENT_UPDATE_CLOSE); break; + + case EC_PCHG_UPDATE_CMD_RESET: + HCPRINTS("Resetting"); + + gpio_disable_interrupt(ctx->cfg->irq_pin); + _clear_port(ctx); + ctx->cfg->drv->reset(ctx); + gpio_enable_interrupt(ctx->cfg->irq_pin); + break; + + case EC_PCHG_UPDATE_CMD_ENABLE_PASSTHRU: + HCPRINTS("Enabling passthru mode"); + mutex_lock(&ctx->mtx); + ctx->mode = PCHG_MODE_PASSTHRU; + mutex_unlock(&ctx->mtx); + break; + default: return EC_RES_INVALID_PARAM; } @@ -775,6 +897,7 @@ static int cc_pchg(int argc, const char **argv) ccprintf("P%d STATE_%s EVENT_%s SOC=%d%%\n", port, _text_state(ctx->state), _text_event(ctx->event), ctx->battery_percent); + ccprintf("mode=%s\n", _text_mode(ctx->mode)); ccprintf("error=0x%x dropped=%u fw_version=0x%x\n", ctx->error, ctx->dropped_event_count, ctx->fw_version); return EC_SUCCESS; diff --git a/common/system.c b/common/system.c index 6f64960170..375cca2882 100644 --- a/common/system.c +++ b/common/system.c @@ -849,7 +849,7 @@ __overridable int board_get_version(void) * value is a negative version of an EC return code. Without this optimization * multiple boards run out of flash size. */ -int system_get_board_version(void) +test_mockable int system_get_board_version(void) { int board_id; diff --git a/common/usb_pd_dual_role.c b/common/usb_pd_dual_role.c index 6498e0853f..a17c8b926e 100644 --- a/common/usb_pd_dual_role.c +++ b/common/usb_pd_dual_role.c @@ -383,8 +383,7 @@ void pd_process_source_cap(int port, int cnt, uint32_t *src_caps) pd_get_src_caps(port), max_mv, &pdo); pd_extract_pdo_power(pdo, &ma, &mv, &unused); - /* Set max. limit, but apply 500mA ceiling */ - charge_manager_set_ceil(port, CEIL_REQUESTOR_PD, PD_MIN_MA); + /* Set max. limit, but 2.5 W ceiling will be applied later. */ pd_set_input_current_limit(port, ma, mv); } } diff --git a/common/usb_pd_flags.c b/common/usb_pd_flags.c index 89225f7730..fdd7a6f2af 100644 --- a/common/usb_pd_flags.c +++ b/common/usb_pd_flags.c @@ -8,7 +8,6 @@ */ #include "common.h" -#include "config.h" #include "usb_pd_flags.h" static union usb_pd_runtime_flags usb_pd_flags; diff --git a/common/usbc/usb_pd_dp_ufp.c b/common/usbc/usb_pd_dp_ufp.c index d88ee17aaf..1d375c5e2b 100644 --- a/common/usbc/usb_pd_dp_ufp.c +++ b/common/usbc/usb_pd_dp_ufp.c @@ -117,7 +117,7 @@ static void hpd_to_dp_attention(void) 0x2); /* Send request to DPM to send an attention VDM */ - pd_request_vdm_attention(port, vdm, ARRAY_SIZE(vdm)); + pd_request_vdm(port, vdm, ARRAY_SIZE(vdm), TCPCI_MSG_SOP); /* If there are still events, need to shift the buffer */ if (--hpd.count) { diff --git a/common/usbc/usb_pd_dpm.c b/common/usbc/usb_pd_dpm.c index 2538ef0be6..daccc2ba2a 100644 --- a/common/usbc/usb_pd_dpm.c +++ b/common/usbc/usb_pd_dpm.c @@ -49,9 +49,10 @@ static struct { atomic_t flags; - uint32_t vdm_attention[DPM_ATTENION_MAX_VDO]; - int vdm_cnt; - mutex_t vdm_attention_mutex; + uint32_t vdm_req[VDO_MAX_SIZE]; + int vdm_req_cnt; + enum tcpci_msg_type req_type; + mutex_t vdm_req_mutex; enum dpm_pd_button_state pd_button_state; } dpm[CONFIG_USB_PD_PORT_MAX_COUNT]; @@ -67,25 +68,25 @@ static struct { #define DPM_FLAG_ENTER_USB4 BIT(4) #define DPM_FLAG_ENTER_ANY \ (DPM_FLAG_ENTER_DP | DPM_FLAG_ENTER_TBT | DPM_FLAG_ENTER_USB4) -#define DPM_FLAG_SEND_ATTENTION BIT(5) +#define DPM_FLAG_SEND_VDM_REQ BIT(5) #define DPM_FLAG_DATA_RESET_REQUESTED BIT(6) #define DPM_FLAG_DATA_RESET_DONE BIT(7) #define DPM_FLAG_PD_BUTTON_PRESSED BIT(8) #define DPM_FLAG_PD_BUTTON_RELEASED BIT(9) #ifdef CONFIG_ZEPHYR -static int init_vdm_attention_mutex(const struct device *dev) +static int init_vdm_req_mutex(const struct device *dev) { int port; ARG_UNUSED(dev); for (port = 0; port < CONFIG_USB_PD_PORT_MAX_COUNT; port++) - k_mutex_init(&dpm[port].vdm_attention_mutex); + k_mutex_init(&dpm[port].vdm_req_mutex); return 0; } -SYS_INIT(init_vdm_attention_mutex, POST_KERNEL, 50); +SYS_INIT(init_vdm_req_mutex, POST_KERNEL, 50); #endif /* CONFIG_ZEPHYR */ __overridable bool board_is_tbt_usb4_port(int port) @@ -93,35 +94,43 @@ __overridable bool board_is_tbt_usb4_port(int port) return true; } -enum ec_status pd_request_vdm_attention(int port, const uint32_t *data, - int vdo_count) +enum ec_status pd_request_vdm(int port, const uint32_t *data, int vdo_count, + enum tcpci_msg_type tx_type) { - mutex_lock(&dpm[port].vdm_attention_mutex); + mutex_lock(&dpm[port].vdm_req_mutex); - /* Only one Attention message may be pending */ - if (DPM_CHK_FLAG(port, DPM_FLAG_SEND_ATTENTION)) { - mutex_unlock(&dpm[port].vdm_attention_mutex); - return EC_RES_UNAVAILABLE; + /* Only one VDM REQ message may be pending */ + if (DPM_CHK_FLAG(port, DPM_FLAG_SEND_VDM_REQ)) { + mutex_unlock(&dpm[port].vdm_req_mutex); + return EC_RES_BUSY; + } + + /* VDM header is required and we cannot exceed standard message size*/ + if (!vdo_count || vdo_count > VDO_MAX_SIZE) { + mutex_unlock(&dpm[port].vdm_req_mutex); + return EC_RES_INVALID_PARAM; } /* SVDM Attention message must be 1 or 2 VDOs in length */ - if (!vdo_count || (vdo_count > DPM_ATTENION_MAX_VDO)) { - mutex_unlock(&dpm[port].vdm_attention_mutex); + if (PD_VDO_SVDM(data[0]) && (PD_VDO_CMD(data[0]) == CMD_ATTENTION) && + vdo_count > DPM_ATTENION_MAX_VDO) { + mutex_unlock(&dpm[port].vdm_req_mutex); return EC_RES_INVALID_PARAM; } - /* Save contents of Attention message */ - memcpy(dpm[port].vdm_attention, data, vdo_count * sizeof(uint32_t)); - dpm[port].vdm_cnt = vdo_count; + /* Save contents of VDM REQ message */ + memcpy(dpm[port].vdm_req, data, vdo_count * sizeof(uint32_t)); + dpm[port].vdm_req_cnt = vdo_count; + dpm[port].req_type = tx_type; /* - * Indicate to DPM that an Attention message needs to be sent. This flag - * will be cleared when the Attention message is sent to the policy + * Indicate to DPM that a REQ message needs to be sent. This flag + * will be cleared when the REQ message is sent to the policy * engine. */ - DPM_SET_FLAG(port, DPM_FLAG_SEND_ATTENTION); + DPM_SET_FLAG(port, DPM_FLAG_SEND_VDM_REQ); - mutex_unlock(&dpm[port].vdm_attention_mutex); + mutex_unlock(&dpm[port].vdm_req_mutex); return EC_RES_SUCCESS; } @@ -176,7 +185,7 @@ void dpm_init(int port) void dpm_mode_exit_complete(int port) { DPM_CLR_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE | DPM_FLAG_EXIT_REQUEST | - DPM_FLAG_SEND_ATTENTION); + DPM_FLAG_SEND_VDM_REQ); } static void dpm_set_mode_entry_done(int port) @@ -239,11 +248,15 @@ void dpm_vdm_acked(int port, enum tcpci_msg_type type, int vdo_count, dp_vdm_acked(port, type, vdo_count, vdm); break; case USB_VID_INTEL: - if (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE)) { - intel_vdm_acked(port, type, vdo_count, vdm); - break; - } +/* TODO (http://b/255967867) Can't use the IS_ENABLED macro here because + * __fallthrough fails in clang as unreachable code. + */ +#ifdef CONFIG_USB_PD_TBT_COMPAT_MODE + intel_vdm_acked(port, type, vdo_count, vdm); + break; +#else __fallthrough; +#endif default: CPRINTS("C%d: Received unexpected VDM ACK for SVID %d", port, svid); @@ -258,11 +271,15 @@ void dpm_vdm_naked(int port, enum tcpci_msg_type type, uint16_t svid, dp_vdm_naked(port, type, vdm_cmd); break; case USB_VID_INTEL: - if (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE)) { - intel_vdm_naked(port, type, vdm_cmd); - break; - } +/* TODO (http://b/255967867) Can't use the IS_ENABLED macro here because + * __fallthrough fails in clang as unreachable code. + */ +#ifdef CONFIG_USB_PD_TBT_COMPAT_MODE + intel_vdm_naked(port, type, vdm_cmd); + break; +#else __fallthrough; +#endif default: CPRINTS("C%d: Received unexpected VDM NAK for SVID %d", port, svid); @@ -499,16 +516,16 @@ static void dpm_attempt_mode_exit(int port) pd_dpm_request(port, DPM_REQUEST_VDM); } -static void dpm_send_attention_vdm(int port) +static void dpm_send_req_vdm(int port) { - /* Set up VDM ATTEN msg that was passed in previously */ - if (pd_setup_vdm_request(port, TCPCI_MSG_SOP, dpm[port].vdm_attention, - dpm[port].vdm_cnt) == true) + /* Set up VDM REQ msg that was passed in previously */ + if (pd_setup_vdm_request(port, dpm[port].req_type, dpm[port].vdm_req, + dpm[port].vdm_req_cnt) == true) /* Trigger PE to start a VDM command run */ pd_dpm_request(port, DPM_REQUEST_VDM); /* Clear flag after message is sent to PE layer */ - DPM_CLR_FLAG(port, DPM_FLAG_SEND_ATTENTION); + DPM_CLR_FLAG(port, DPM_FLAG_SEND_VDM_REQ); } void dpm_handle_alert(int port, uint32_t ado) @@ -634,11 +651,11 @@ void dpm_run(int port) /* Run USB PD Power button state machine */ dpm_run_pd_button_sm(port); - } else { - /* Run UFP related DPM requests */ - if (DPM_CHK_FLAG(port, DPM_FLAG_SEND_ATTENTION)) - dpm_send_attention_vdm(port); } + + /* Run any VDM REQ messages */ + if (DPM_CHK_FLAG(port, DPM_FLAG_SEND_VDM_REQ)) + dpm_send_req_vdm(port); } /* diff --git a/common/usbc/usb_pe_ctvpd_sm.c b/common/usbc/usb_pe_ctvpd_sm.c index f3f3d8af9b..dbd32a6b7d 100644 --- a/common/usbc/usb_pe_ctvpd_sm.c +++ b/common/usbc/usb_pe_ctvpd_sm.c @@ -74,11 +74,11 @@ void pe_run(int port, int evt, int en) case SM_PAUSED: if (!en) break; - /* fall through */ + __fallthrough; case SM_INIT: pe_init(port); local_state[port] = SM_RUN; - /* fall through */ + __fallthrough; case SM_RUN: if (en) run_state(port, &pe[port].ctx); diff --git a/common/usbc/usb_pe_drp_sm.c b/common/usbc/usb_pe_drp_sm.c index 5a5aebc4b4..f6cd95463f 100644 --- a/common/usbc/usb_pe_drp_sm.c +++ b/common/usbc/usb_pe_drp_sm.c @@ -3030,9 +3030,7 @@ static void pe_src_hard_reset_entry(int port) pd_timer_enable(port, PE_TIMER_PS_HARD_RESET, PD_T_PS_HARD_RESET); /* Clear error flags */ - PE_CLR_MASK(port, BIT(PE_FLAGS_VDM_REQUEST_NAKED_FN) | - BIT(PE_FLAGS_PROTOCOL_ERROR_FN) | - BIT(PE_FLAGS_VDM_REQUEST_BUSY_FN)); + PE_CLR_FLAG(port, PE_FLAGS_PROTOCOL_ERROR); } static void pe_src_hard_reset_run(int port) @@ -3352,6 +3350,26 @@ static void pe_snk_select_capability_entry(int port) tc_pd_connection(port, 1); } +static void pe_snk_apply_psnkstdby(int port) +{ + uint32_t mv = pd_get_requested_voltage(port); + uint32_t high; + + /* + * Apply 2.5W ceiling during transition. We need choose the larger of + * the current input voltage and the new PDO voltage because during a + * transition, both voltages can be applied to the device. If the + * current source isn't PD, we don't need to care about drawing more + * than pSnkStdby. Thus, it's not considered (in the else clause). + */ + if (charge_manager_get_supplier() == CHARGE_SUPPLIER_PD) + high = MAX(charge_manager_get_charger_voltage(), mv); + else + high = mv; + charge_manager_force_ceil( + port, high > 0 ? PD_SNK_STDBY_MW * 1000 / high : PD_MIN_MA); +} + static void pe_snk_select_capability_run(int port) { uint8_t type; @@ -3416,6 +3434,9 @@ static void pe_snk_select_capability_run(int port) /* explicit contract is now in place */ pe_set_explicit_contract(port); + if (IS_ENABLED(CONFIG_CHARGE_MANAGER)) + pe_snk_apply_psnkstdby(port); + set_state_pe(port, PE_SNK_TRANSITION_SINK); return; @@ -3860,9 +3881,7 @@ static void pe_snk_hard_reset_entry(int port) #endif PE_CLR_MASK(port, BIT(PE_FLAGS_SNK_WAIT_CAP_TIMEOUT_FN) | - BIT(PE_FLAGS_VDM_REQUEST_NAKED_FN) | - BIT(PE_FLAGS_PROTOCOL_ERROR_FN) | - BIT(PE_FLAGS_VDM_REQUEST_BUSY_FN)); + BIT(PE_FLAGS_PROTOCOL_ERROR_FN)); /* Request the generation of Hard Reset Signaling by the PHY Layer */ prl_execute_hard_reset(port); @@ -6053,13 +6072,6 @@ static void pe_vdm_request_dpm_entry(int port) tx_emsg[port].len = pe[port].vdm_cnt * 4; } - /* - * Clear the VDM nak'ed flag so that each request is - * treated separately (NAKs are handled by the - * DPM layer). Otherwise previous NAKs received will - * cause the state to exit early. - */ - PE_CLR_FLAG(port, PE_FLAGS_VDM_REQUEST_NAKED); send_data_msg(port, pe[port].tx_type, PD_DATA_VENDOR_DEF); /* diff --git a/common/usbc/usb_pe_private.h b/common/usbc/usb_pe_private.h index bfe534dcca..c6703f6fd3 100644 --- a/common/usbc/usb_pe_private.h +++ b/common/usbc/usb_pe_private.h @@ -52,10 +52,6 @@ enum { PE_FLAGS_VDM_SETUP_DONE_FN, /* Flag to note PR Swap just completed for Startup entry */ PE_FLAGS_PR_SWAP_COMPLETE_FN, - /* Flag to note Port Discovery port partner replied with BUSY */ - PE_FLAGS_VDM_REQUEST_BUSY_FN, - /* Flag to note Port Discovery port partner replied with NAK */ - PE_FLAGS_VDM_REQUEST_NAKED_FN, /* Flag to note FRS/PRS context in shared state machine path */ PE_FLAGS_FAST_ROLE_SWAP_PATH_FN, /* Flag to note if FRS listening is enabled */ diff --git a/common/usbc_intr_task.c b/common/usbc_intr_task.c index 3c67ba4102..6c724c1279 100644 --- a/common/usbc_intr_task.c +++ b/common/usbc_intr_task.c @@ -25,11 +25,11 @@ #define PD_PROCESS_INTERRUPT BIT(0) /* - * Theoretically, we may need to support up to 480 USB-PD packets per second for - * intensive operations such as FW update over PD. This value has tested well - * preventing watchdog resets with a single bad port partner plugged in. + * Theoretically, we may need to support up to 1800 USB-PD packets per second + * for intensive operations such as BIST compliance tests. This value has tested + * well preventing watchdog resets with a single bad port partner plugged in. */ -#define ALERT_STORM_MAX_COUNT 480 +#define ALERT_STORM_MAX_COUNT 1800 #define ALERT_STORM_INTERVAL SECOND static uint8_t pd_int_task_id[CONFIG_USB_PD_PORT_MAX_COUNT]; diff --git a/common/virtual_battery.c b/common/virtual_battery.c index a9ad77e22b..adb4e96d7f 100644 --- a/common/virtual_battery.c +++ b/common/virtual_battery.c @@ -150,7 +150,7 @@ void reset_parse_state(void) * Copy memmap string data from offset to dest, up to size len, in the format * expected by SBS (first byte of dest contains strlen). */ -static void copy_memmap_string(uint8_t *dest, int offset, int len) +void copy_memmap_string(uint8_t *dest, int offset, int len) { uint8_t *memmap_str; uint8_t memmap_strlen; |