summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorYH Lin <yueherngl@google.com>2022-10-28 21:09:13 +0000
committerYH Lin <yueherngl@google.com>2022-10-28 21:09:13 +0000
commit19d4d68ffa8b6910d716ab5e1953c41b58614a57 (patch)
treebdff671e5ad3e71e30ab56f4f084f34a2fd72e28 /common
parent1afa995cc54968d86bec8a23bab66bb07742dbdf (diff)
parentab9a716db1e256b4b95cb3679b0ade49b488b938 (diff)
downloadchrome-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.mk1
-rw-r--r--common/cbi.c3
-rw-r--r--common/chargen.c155
-rw-r--r--common/charger.c22
-rw-r--r--common/mock/charge_manager_mock.c14
-rw-r--r--common/motion_sense.c174
-rw-r--r--common/motion_sense_fifo.c51
-rw-r--r--common/panic_output.c13
-rw-r--r--common/peripheral_charger.c313
-rw-r--r--common/system.c2
-rw-r--r--common/usb_pd_dual_role.c3
-rw-r--r--common/usb_pd_flags.c1
-rw-r--r--common/usbc/usb_pd_dp_ufp.c2
-rw-r--r--common/usbc/usb_pd_dpm.c99
-rw-r--r--common/usbc/usb_pe_ctvpd_sm.c4
-rw-r--r--common/usbc/usb_pe_drp_sm.c38
-rw-r--r--common/usbc/usb_pe_private.h4
-rw-r--r--common/usbc_intr_task.c8
-rw-r--r--common/virtual_battery.c2
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;