summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--baseboard/grunt/baseboard.h1
-rw-r--r--baseboard/octopus/baseboard.c2
-rw-r--r--board/host/chipset.c6
-rw-r--r--board/kukui/board.c2
-rw-r--r--board/rainier/board.c4
-rw-r--r--board/samus/power_sequence.c20
-rw-r--r--board/scarlet/board.c4
-rw-r--r--common/ap_hang_detect.c2
-rw-r--r--common/button.c4
-rw-r--r--common/charge_state_v2.c2
-rw-r--r--common/chipset.c73
-rw-r--r--common/keyboard_8042.c2
-rw-r--r--common/keyboard_scan.c2
-rw-r--r--common/thermal.c2
-rw-r--r--include/chipset.h85
-rw-r--r--include/config.h1
-rw-r--r--include/ec_commands.h49
-rw-r--r--power/apollolake.c8
-rw-r--r--power/braswell.c18
-rw-r--r--power/cannonlake.c7
-rw-r--r--power/intel_x86.c19
-rw-r--r--power/mt817x.c13
-rw-r--r--power/mt8183.c28
-rw-r--r--power/rk3288.c12
-rw-r--r--power/rk3399.c17
-rw-r--r--power/sdm845.c14
-rw-r--r--power/skylake.c3
-rw-r--r--power/stoney.c8
-rw-r--r--test/sbs_charging_v2.c2
-rw-r--r--util/ectool.c124
30 files changed, 447 insertions, 87 deletions
diff --git a/baseboard/grunt/baseboard.h b/baseboard/grunt/baseboard.h
index 1ba6354f33..5520affed1 100644
--- a/baseboard/grunt/baseboard.h
+++ b/baseboard/grunt/baseboard.h
@@ -34,6 +34,7 @@
#define CONFIG_HIBERNATE_PSL
#define CONFIG_HOSTCMD_LPC
#define CONFIG_HOSTCMD_SKUID
+#define CONFIG_CMD_AP_RESET_LOG
#define CONFIG_I2C
#define CONFIG_I2C_MASTER
#define CONFIG_PWM
diff --git a/baseboard/octopus/baseboard.c b/baseboard/octopus/baseboard.c
index 081a20278c..57e4ad3280 100644
--- a/baseboard/octopus/baseboard.c
+++ b/baseboard/octopus/baseboard.c
@@ -280,7 +280,7 @@ void board_hibernate(void)
* To support hibernate called from console commands, ectool commands
* and key sequence, shutdown the AP before hibernating.
*/
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_BOARD_CUSTOM);
#ifdef CONFIG_USBC_PPC_NX20P3483
/*
diff --git a/board/host/chipset.c b/board/host/chipset.c
index 62e7151e06..51e7222e2e 100644
--- a/board/host/chipset.c
+++ b/board/host/chipset.c
@@ -16,9 +16,9 @@ static int chipset_state = CHIPSET_STATE_SOFT_OFF;
static int power_on_req;
static int power_off_req;
-test_mockable void chipset_reset(void)
+test_mockable void chipset_reset(enum chipset_reset_reason reason)
{
- fprintf(stderr, "Chipset reset!\n");
+ fprintf(stderr, "Chipset reset: %d!\n", reason);
}
test_mockable void chipset_throttle_cpu(int throttle)
@@ -26,7 +26,7 @@ test_mockable void chipset_throttle_cpu(int throttle)
/* Do nothing */
}
-test_mockable void chipset_force_shutdown(void)
+test_mockable void chipset_force_shutdown(enum chipset_shutdown_reason reason)
{
/* Do nothing */
}
diff --git a/board/kukui/board.c b/board/kukui/board.c
index 001ba20649..ab46c6136f 100644
--- a/board/kukui/board.c
+++ b/board/kukui/board.c
@@ -57,7 +57,7 @@ static void tcpc_alert_event(enum gpio_signal signal)
static void warm_reset_request_interrupt(enum gpio_signal signal)
{
CPRINTS("AP wants warm reset");
- chipset_reset();
+ chipset_reset(CHIPSET_RESET_AP_REQ);
}
static void ap_watchdog_interrupt(enum gpio_signal signal)
diff --git a/board/rainier/board.c b/board/rainier/board.c
index 03e292bda4..0b61cd03e1 100644
--- a/board/rainier/board.c
+++ b/board/rainier/board.c
@@ -55,13 +55,13 @@ static void tcpc_alert_event(enum gpio_signal signal)
static void overtemp_interrupt(enum gpio_signal signal)
{
CPRINTS("AP wants shutdown");
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_THERMAL);
}
static void warm_reset_request_interrupt(enum gpio_signal signal)
{
CPRINTS("AP wants warm reset");
- chipset_reset();
+ chipset_reset(CHIPSET_RESET_AP_REQ);
}
#include "gpio_list.h"
diff --git a/board/samus/power_sequence.c b/board/samus/power_sequence.c
index 804d3ef208..717af8577c 100644
--- a/board/samus/power_sequence.c
+++ b/board/samus/power_sequence.c
@@ -65,9 +65,10 @@
static int throttle_cpu; /* Throttle CPU? */
static uint32_t pp5000_in_g3; /* Turn PP5000 on in G3? */
-void chipset_force_shutdown(void)
+void chipset_force_shutdown(enum chipset_shutdown_reason reason)
{
- CPRINTS("%s()", __func__);
+ CPRINTS("%s(%d)", __func__, reason);
+ report_ap_reset(reason);
/*
* Force off. This condition will reset once the state machine
@@ -111,9 +112,10 @@ static void chipset_reset_rtc(void)
udelay(10 * MSEC);
}
-void chipset_reset(void)
+void chipset_reset(enum chipset_reset_reason reason)
{
- CPRINTS("%s", __func__);
+ CPRINTS("%s(%d)", __func__, reason);
+ report_ap_reset(reason);
/*
* Send a RCIN# pulse to the PCH. This just causes it to
@@ -184,7 +186,7 @@ enum power_state power_handle_state(enum power_state state)
/* Check for state transitions */
if (!power_has_signals(IN_PGOOD_S3)) {
/* Required rail went away */
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_POWERFAIL);
return POWER_S3S5;
} else if (gpio_get_level(GPIO_PCH_SLP_S3_L) == 1) {
/* Power up to next state */
@@ -198,7 +200,7 @@ enum power_state power_handle_state(enum power_state state)
case POWER_S0:
if (!power_has_signals(IN_PGOOD_S0)) {
/* Required rail went away */
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_POWERFAIL);
return POWER_S0S3;
} else if (gpio_get_level(GPIO_PCH_SLP_S3_L) == 0) {
/* Power down to next state */
@@ -291,7 +293,7 @@ enum power_state power_handle_state(enum power_state state)
if (power_wait_signals(IN_PGOOD_S3)) {
gpio_set_level(GPIO_PP1800_EN, 0);
gpio_set_level(GPIO_PP1200_EN, 0);
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_WAIT);
return POWER_S5;
}
@@ -338,7 +340,7 @@ enum power_state power_handle_state(enum power_state state)
gpio_set_level(GPIO_TOUCHSCREEN_RESET_L, 0);
wireless_set_state(WIRELESS_OFF);
gpio_set_level(GPIO_PP3300_DSW_GATED_EN, 1);
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_WAIT);
return POWER_S3;
}
@@ -377,7 +379,7 @@ enum power_state power_handle_state(enum power_state state)
gpio_set_level(GPIO_TOUCHSCREEN_RESET_L, 0);
gpio_set_level(GPIO_PP3300_DSW_GATED_EN, 1);
wireless_set_state(WIRELESS_OFF);
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_WAIT);
return POWER_S3;
}
diff --git a/board/scarlet/board.c b/board/scarlet/board.c
index 9eb055e9f6..f4a6ae0b91 100644
--- a/board/scarlet/board.c
+++ b/board/scarlet/board.c
@@ -57,13 +57,13 @@ static void tcpc_alert_event(enum gpio_signal signal)
static void overtemp_interrupt(enum gpio_signal signal)
{
CPRINTS("AP wants shutdown");
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_THERMAL);
}
static void warm_reset_request_interrupt(enum gpio_signal signal)
{
CPRINTS("AP wants warm reset");
- chipset_reset();
+ chipset_reset(CHIPSET_RESET_AP_REQ);
}
#include "gpio_list.h"
diff --git a/common/ap_hang_detect.c b/common/ap_hang_detect.c
index 45e735e526..8b859aa2d7 100644
--- a/common/ap_hang_detect.c
+++ b/common/ap_hang_detect.c
@@ -41,7 +41,7 @@ static void hang_detect_deferred(void)
if (timeout_will_reboot) {
CPRINTS("hang detect triggering warm reboot");
host_set_single_event(EC_HOST_EVENT_HANG_REBOOT);
- chipset_reset();
+ chipset_reset(CHIPSET_RESET_HANG_REBOOT);
active = 0;
return;
}
diff --git a/common/button.c b/common/button.c
index 6190f414bb..1ccc548c75 100644
--- a/common/button.c
+++ b/common/button.c
@@ -416,7 +416,7 @@ static void debug_mode_handle(void)
host_send_sysrq('x');
CPRINTS("DEBUG MODE: sysrq-x sent");
} else {
- chipset_reset();
+ chipset_reset(CHIPSET_RESET_DBG_WARM_REBOOT);
CPRINTS("DEBUG MODE: Warm reset triggered");
}
recovery_button_pressed = 0;
@@ -531,7 +531,7 @@ static void debug_mode_transition(enum debug_state next_state)
break;
case STATE_WARM_RESET_EXEC:
/* Warm reset the host and transition to STATE_NONE. */
- chipset_reset();
+ chipset_reset(CHIPSET_RESET_DBG_WARM_REBOOT);
CPRINTS("DEBUG MODE: Warm reset triggered");
curr_debug_state = STATE_DEBUG_NONE;
break;
diff --git a/common/charge_state_v2.c b/common/charge_state_v2.c
index 666478293b..3387ac6302 100644
--- a/common/charge_state_v2.c
+++ b/common/charge_state_v2.c
@@ -1333,7 +1333,7 @@ static int shutdown_on_critical_battery(void)
/* Timeout waiting for AP to shut down, so kill it */
CPRINTS(
"charge force shutdown due to critical battery");
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_BATTERY_CRIT);
}
}
diff --git a/common/chipset.c b/common/chipset.c
index 7a2101624a..4342ba5fab 100644
--- a/common/chipset.c
+++ b/common/chipset.c
@@ -8,6 +8,11 @@
#include "chipset.h"
#include "common.h"
#include "console.h"
+#include "ec_commands.h"
+#include "host_command.h"
+#include "system.h"
+#include "task.h"
+#include "timer.h"
#include "util.h"
/* Console output macros */
@@ -22,7 +27,7 @@ static int command_apreset(int argc, char **argv)
{
/* Force the chipset to reset */
ccprintf("Issuing AP reset...\n");
- chipset_reset();
+ chipset_reset(CHIPSET_RESET_CONSOLE_CMD);
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(apreset, command_apreset,
@@ -31,10 +36,74 @@ DECLARE_CONSOLE_COMMAND(apreset, command_apreset,
static int command_apshutdown(int argc, char **argv)
{
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_CONSOLE_CMD);
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(apshutdown, command_apshutdown,
NULL,
"Force AP shutdown");
+
#endif
+
+#ifdef CONFIG_CMD_AP_RESET_LOG
+static struct mutex reset_log_mutex;
+static int next_reset_log;
+static uint32_t ap_resets_since_ec_boot;
+/* keep reset_logs size a power of 2 */
+static struct ap_reset_log_entry reset_logs[4];
+
+void report_ap_reset(enum chipset_shutdown_reason reason)
+{
+ timestamp_t now = get_time();
+ uint32_t now_ms = (uint32_t)(now.val / MSEC);
+
+ mutex_lock(&reset_log_mutex);
+ reset_logs[next_reset_log].reset_cause = reason;
+ reset_logs[next_reset_log++].reset_time_ms = now_ms;
+ next_reset_log &= ARRAY_SIZE(reset_logs) - 1;
+ ap_resets_since_ec_boot++;
+ mutex_unlock(&reset_log_mutex);
+}
+
+static int host_command_get_uptime_info(struct host_cmd_handler_args *args)
+{
+ /*
+ * In the current implementation, not all terms are preserved across a
+ * sysjump. Future implementations may preserve additional information.
+ *
+ * time_since_ec_boot_ms: preserved, but wraps at ~50 days
+ * ec_reset_flags: preserved, with 'sysjump' added
+ * ap_resets_since_ec_boot: Not preserved
+ * recent_ap_reset[*]: Not preserved
+ */
+ struct ec_response_uptime_info *r = args->response;
+ timestamp_t now = get_time();
+ uint32_t now_ms = (uint32_t)(now.val / MSEC);
+ size_t log_address = 0;
+ size_t i = 0;
+
+ r->time_since_ec_boot_ms = now_ms;
+ r->ec_reset_flags = system_get_reset_flags();
+
+ memset(r->recent_ap_reset, 0, sizeof(r->recent_ap_reset));
+
+ mutex_lock(&reset_log_mutex);
+ r->ap_resets_since_ec_boot = ap_resets_since_ec_boot;
+ for (i = 0;
+ i != ARRAY_SIZE(reset_logs) && i != ARRAY_SIZE(r->recent_ap_reset);
+ ++i) {
+ log_address = (next_reset_log + i) &
+ (ARRAY_SIZE(reset_logs) - 1);
+ r->recent_ap_reset[i] = reset_logs[log_address];
+ }
+ mutex_unlock(&reset_log_mutex);
+
+ args->response_size = sizeof(*r);
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_GET_UPTIME_INFO,
+ host_command_get_uptime_info,
+ EC_VER_MASK(0));
+
+#endif /* !CONFIG_AP_RESET_LOG */
+
diff --git a/common/keyboard_8042.c b/common/keyboard_8042.c
index 08ebeb43b1..04e00d2bb2 100644
--- a/common/keyboard_8042.c
+++ b/common/keyboard_8042.c
@@ -736,7 +736,7 @@ static int handle_keyboard_command(uint8_t command, uint8_t *output)
break;
case I8042_SYSTEM_RESET:
- chipset_reset();
+ chipset_reset(CHIPSET_RESET_KB_SYSRESET);
break;
default:
diff --git a/common/keyboard_scan.c b/common/keyboard_scan.c
index cc3379ef16..02a1c105a0 100644
--- a/common/keyboard_scan.c
+++ b/common/keyboard_scan.c
@@ -391,7 +391,7 @@ static int check_runtime_keys(const uint8_t *state)
/* R = reboot */
CPRINTS("KB warm reboot");
keyboard_clear_buffer();
- chipset_reset();
+ chipset_reset(CHIPSET_RESET_KB_WARM_REBOOT);
return 1;
} else if (state[KEYBOARD_COL_KEY_H] == KEYBOARD_MASK_KEY_H) {
/* H = hibernate */
diff --git a/common/thermal.c b/common/thermal.c
index 7d7438f3e5..60101516da 100644
--- a/common/thermal.c
+++ b/common/thermal.c
@@ -139,7 +139,7 @@ static void thermal_control(void)
if (cond_went_true(&cond_hot[EC_TEMP_THRESH_HALT])) {
CPRINTS("thermal SHUTDOWN");
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_THERMAL);
} else if (cond_went_false(&cond_hot[EC_TEMP_THRESH_HALT])) {
/* We don't reboot automatically - the user has to push
* the power button. It's likely that we can't even
diff --git a/include/chipset.h b/include/chipset.h
index 5169689d8a..5e51e5991a 100644
--- a/include/chipset.h
+++ b/include/chipset.h
@@ -39,6 +39,66 @@ enum chipset_state_mask {
CHIPSET_STATE_STANDBY),
};
+/*
+ * Reason codes used by the AP after a shutdown to figure out why it was reset
+ * by the EC. These are sent in EC commands. Therefore, to maintain protocol
+ * compatibility:
+ * - New entries must be inserted prior to the _COUNT field
+ * - If an existing entry is no longer in service, it must be replaced with a
+ * RESERVED entry instead.
+ * - The semantic meaning of an entry should not change.
+ * - Do not exceed 2^15 - 1 for reset reasons or 2^16 - 1 for shutdown reasons.
+ */
+enum chipset_reset_reason {
+ CHIPSET_RESET_BEGIN = 0,
+ CHIPSET_RESET_UNKNOWN = CHIPSET_RESET_BEGIN,
+ /* Custom reason defined by a board.c or baseboard.c file */
+ CHIPSET_RESET_BOARD_CUSTOM,
+ /* Believe that the AP has hung */
+ CHIPSET_RESET_HANG_REBOOT,
+ /* Reset by EC console command */
+ CHIPSET_RESET_CONSOLE_CMD,
+ /* Keyboard module reset key combination */
+ CHIPSET_RESET_KB_SYSRESET,
+ /* Keyboard module warm reboot */
+ CHIPSET_RESET_KB_WARM_REBOOT,
+ /* Debug module warm reboot */
+ CHIPSET_RESET_DBG_WARM_REBOOT,
+ /* I cannot self-terminate. You must lower me into the steel. */
+ CHIPSET_RESET_AP_REQ,
+ /* Reset as side-effect of startup sequence */
+ CHIPSET_RESET_INIT,
+ CHIPSET_RESET_COUNT,
+};
+
+/*
+ * Hard shutdowns are logged on the same path as resets.
+ */
+enum chipset_shutdown_reason {
+ CHIPSET_SHUTDOWN_BEGIN = 1 << 15,
+ CHIPSET_SHUTDOWN_POWERFAIL = CHIPSET_SHUTDOWN_BEGIN,
+ /* Forcing a shutdown as part of EC initialization */
+ CHIPSET_SHUTDOWN_INIT,
+ /* Custom reason on a per-board basis. */
+ CHIPSET_SHUTDOWN_BOARD_CUSTOM,
+ /* This is a reason to inhibit startup, not cause shut down. */
+ CHIPSET_SHUTDOWN_BATTERY_INHIBIT,
+ /* A power_wait_signal is being asserted */
+ CHIPSET_SHUTDOWN_WAIT,
+ /* Critical battery level. */
+ CHIPSET_SHUTDOWN_BATTERY_CRIT,
+ /* Because you told me to. */
+ CHIPSET_SHUTDOWN_CONSOLE_CMD,
+ /* Forcing a shutdown to effect entry to G3. */
+ CHIPSET_SHUTDOWN_G3,
+ /* Force shutdown due to over-temperature. */
+ CHIPSET_SHUTDOWN_THERMAL,
+ /* Force a chipset shutdown from the power button through EC */
+ CHIPSET_SHUTDOWN_BUTTON,
+
+ CHIPSET_SHUTDOWN_COUNT,
+};
+
#ifdef HAS_TASK_CHIPSET
/**
@@ -70,12 +130,12 @@ void chipset_throttle_cpu(int throttle);
* This is intended for use when the system is too hot or battery power is
* critical.
*/
-void chipset_force_shutdown(void);
+void chipset_force_shutdown(enum chipset_shutdown_reason reason);
/**
* Reset the CPU and/or chipset.
*/
-void chipset_reset(void);
+void chipset_reset(enum chipset_reset_reason reason);
/**
* Interrupt handler to power GPIO inputs.
@@ -102,8 +162,11 @@ static inline int chipset_in_state(int state_mask)
static inline void chipset_exit_hard_off(void) { }
static inline void chipset_throttle_cpu(int throttle) { }
-static inline void chipset_force_shutdown(void) { }
-static inline void chipset_reset(void) { }
+static inline void chipset_force_shutdown(enum chipset_shutdown_reason reason)
+{
+}
+
+static inline void chipset_reset(enum chipset_reset_reason reason) { }
static inline void power_interrupt(enum gpio_signal signal) { }
static inline void chipset_handle_espi_reset_assert(void) { }
static inline void chipset_handle_reboot(void) { }
@@ -139,4 +202,18 @@ void chipset_reset_request_interrupt(enum gpio_signal signal);
*/
void chipset_power_signal_interrupt(enum gpio_signal signal);
+
+#ifdef CONFIG_CMD_AP_RESET_LOG
+
+/**
+ * Report that the AP is being reset to the reset log.
+ */
+void report_ap_reset(enum chipset_shutdown_reason reason);
+
+#else
+
+static inline void report_ap_reset(enum chipset_shutdown_reason reason) { }
+
+#endif /* !CONFIG_CMD_AP_RESET_LOG */
+
#endif /* __CROS_EC_CHIPSET_H */
diff --git a/include/config.h b/include/config.h
index 719a10124c..0d363c4e57 100644
--- a/include/config.h
+++ b/include/config.h
@@ -953,6 +953,7 @@
#define CONFIG_CMD_USBMUX
#undef CONFIG_CMD_USB_PD_PE
#define CONFIG_CMD_WAITMS
+#undef CONFIG_CMD_AP_RESET_LOG
/*****************************************************************************/
diff --git a/include/ec_commands.h b/include/ec_commands.h
index f20113cf9c..ee91c80710 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -4796,6 +4796,55 @@ struct __ec_align1 ec_params_set_cbi {
uint8_t data[]; /* For string and raw data */
};
+/*
+ * Information about resets of the AP by the EC and the EC's own uptime.
+ */
+#define EC_CMD_GET_UPTIME_INFO 0x0121
+
+struct __ec_align4 ec_response_uptime_info {
+ /*
+ * Number of milliseconds since the last EC boot. Sysjump resets
+ * typically do not restart the EC's time_since_boot epoch.
+ *
+ * WARNING: The EC's sense of time is much less accurate than the AP's
+ * sense of time, in both phase and frequency. This timebase is similar
+ * to CLOCK_MONOTONIC_RAW, but with 1% or more frequency error.
+ */
+ uint32_t time_since_ec_boot_ms;
+
+ /*
+ * Number of times the AP was reset by the EC since the last EC boot.
+ * Note that the AP may be held in reset by the EC during the initial
+ * boot sequence, such that the very first AP boot may count as more
+ * than one here.
+ */
+ uint32_t ap_resets_since_ec_boot;
+
+ /*
+ * The set of flags which describe the EC's most recent reset. See
+ * include/system.h RESET_FLAG_* for details.
+ */
+ uint32_t ec_reset_flags;
+
+ /* Empty log entries have both the cause and timestamp set to zero. */
+ struct ap_reset_log_entry {
+ /*
+ * See include/chipset.h: enum chipset_{reset,shutdown}_reason
+ * for details.
+ */
+ uint16_t reset_cause;
+
+ /* Reserved for protocol growth. */
+ uint16_t reserved;
+
+ /*
+ * The time of the reset's assertion, in milliseconds since the
+ * last EC boot, in the same epoch as time_since_ec_boot_ms.
+ * Set to zero if the log entry is empty.
+ */
+ uint32_t reset_time_ms;
+ } recent_ap_reset[4];
+};
/*****************************************************************************/
/* The command range 0x200-0x2FF is reserved for Rotor. */
diff --git a/power/apollolake.c b/power/apollolake.c
index dda74a29b9..a9ac1c06d9 100644
--- a/power/apollolake.c
+++ b/power/apollolake.c
@@ -6,6 +6,7 @@
/* Apollolake chipset power control module for Chrome EC */
#include "apollolake.h"
+#include "chipset.h"
#include "console.h"
#include "gpio.h"
#include "intel_x86.h"
@@ -42,8 +43,11 @@ static void internal_chipset_shutdown(void)
chipset_do_shutdown();
}
-void chipset_force_shutdown(void)
+void chipset_force_shutdown(enum chipset_shutdown_reason reason)
{
+ CPRINTS("%s: %d", __func__, reason);
+ report_ap_reset(reason);
+
/*
* This function is called from multiple tasks and hence it is racy! But
* since things are going down hard, it does not matter if some task
@@ -55,7 +59,7 @@ void chipset_force_shutdown(void)
enum power_state chipset_force_g3(void)
{
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_G3);
return POWER_G3;
}
diff --git a/power/braswell.c b/power/braswell.c
index e04918c055..4140c02adf 100644
--- a/power/braswell.c
+++ b/power/braswell.c
@@ -53,9 +53,10 @@
static int throttle_cpu; /* Throttle CPU? */
static int forcing_shutdown; /* Forced shutdown in progress? */
-void chipset_force_shutdown(void)
+void chipset_force_shutdown(enum chipset_shutdown_reason reason)
{
- CPRINTS("%s()", __func__);
+ CPRINTS("%s(%d)", __func__, reason);
+ report_ap_reset(reason);
/*
* Force power off. This condition will reset once the state machine
@@ -68,9 +69,10 @@ void chipset_force_shutdown(void)
forcing_shutdown = 1;
}
-void chipset_reset(void)
+void chipset_reset(enum chipset_reset_reason reason)
{
- CPRINTS("%s", __func__);
+ CPRINTS("%s: %d", __func__, reason);
+ report_ap_reset(reason);
/*
* Send a reset pulse to the PCH. This just causes it to
@@ -138,7 +140,7 @@ enum power_state power_handle_state(enum power_state state)
CPRINTS("Exit SOC G3");
if (power_wait_signals(IN_PGOOD_S5)) {
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_WAIT);
return POWER_G3;
}
@@ -165,7 +167,7 @@ enum power_state power_handle_state(enum power_state state)
/* Check for state transitions */
if (!power_has_signals(IN_PGOOD_S3)) {
/* Required rail went away */
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_POWERFAIL);
return POWER_S3S5;
} else if (gpio_get_level(GPIO_PCH_SLP_S3_L) == 1) {
/* Power up to next state */
@@ -182,7 +184,7 @@ enum power_state power_handle_state(enum power_state state)
/*wireless_set_state(WIRELESS_ON);*/
if (!power_has_signals(IN_PGOOD_S3)) {
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_POWERFAIL);
/*wireless_set_state(WIRELESS_OFF);*/
return POWER_S3S5;
@@ -222,7 +224,7 @@ enum power_state power_handle_state(enum power_state state)
case POWER_S0:
if (!power_has_signals(IN_PGOOD_ALWAYS_ON)) {
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_POWERFAIL);
return POWER_S0S3;
}
diff --git a/power/cannonlake.c b/power/cannonlake.c
index 47b1c912f0..1822b1d3c2 100644
--- a/power/cannonlake.c
+++ b/power/cannonlake.c
@@ -20,9 +20,9 @@
static int forcing_shutdown; /* Forced shutdown in progress? */
-void chipset_force_shutdown(void)
+void chipset_force_shutdown(enum chipset_shutdown_reason reason)
{
- CPRINTS("%s()", __func__);
+ CPRINTS("%s(%d)", __func__, reason);
/*
* Force off. Sending a reset command to the PMIC will power off
@@ -32,6 +32,7 @@ void chipset_force_shutdown(void)
* hold time on the PMIC.
*/
if (!chipset_in_state(CHIPSET_STATE_ANY_OFF)) {
+ report_ap_reset(reason);
forcing_shutdown = 1;
power_button_pch_press();
}
@@ -55,7 +56,7 @@ void chipset_handle_espi_reset_assert(void)
enum power_state chipset_force_g3(void)
{
int timeout = 50;
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_G3);
/* Turn off DSW load switch. */
gpio_set_level(GPIO_EN_PP3300_DSW, 0);
diff --git a/power/intel_x86.c b/power/intel_x86.c
index 1cc8beadf5..15c1cf1b4a 100644
--- a/power/intel_x86.c
+++ b/power/intel_x86.c
@@ -219,7 +219,7 @@ enum power_state common_intel_x86_power_handle_state(enum power_state state)
case POWER_S3:
if (!power_has_signals(IN_PGOOD_ALL_CORE)) {
/* Required rail went away */
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_POWERFAIL);
return POWER_S3S5;
} else if (chipset_get_sleep_signal(SYS_SLEEP_S3) == 1) {
/* Power up to next state */
@@ -232,7 +232,7 @@ enum power_state common_intel_x86_power_handle_state(enum power_state state)
case POWER_S0:
if (!power_has_signals(IN_PGOOD_ALL_CORE)) {
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_POWERFAIL);
return POWER_S0S3;
} else if (chipset_get_sleep_signal(SYS_SLEEP_S3) == 0) {
/* Power down to next state */
@@ -293,7 +293,8 @@ enum power_state common_intel_x86_power_handle_state(enum power_state state)
if (tries == CHARGER_INITIALIZED_TRIES) {
CPRINTS("power-up inhibited");
power_up_inhibited = 1;
- chipset_force_shutdown();
+ chipset_force_shutdown(
+ CHIPSET_SHUTDOWN_BATTERY_INHIBIT);
return POWER_G3;
}
@@ -320,7 +321,7 @@ enum power_state common_intel_x86_power_handle_state(enum power_state state)
#endif
if (power_wait_signals(CHIPSET_G3S5_POWERUP_SIGNAL)) {
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_WAIT);
return POWER_G3;
}
@@ -330,7 +331,7 @@ enum power_state common_intel_x86_power_handle_state(enum power_state state)
case POWER_S5S3:
if (!power_has_signals(IN_PGOOD_ALL_CORE)) {
/* Required rail went away */
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_POWERFAIL);
return POWER_S5G3;
}
@@ -349,7 +350,7 @@ enum power_state common_intel_x86_power_handle_state(enum power_state state)
case POWER_S3S0:
if (!power_has_signals(IN_PGOOD_ALL_CORE)) {
/* Required rail went away */
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_POWERFAIL);
return POWER_S3S5;
}
@@ -563,7 +564,7 @@ void power_chipset_handle_host_sleep_event(enum host_sleep_event state)
#endif
-void chipset_reset(void)
+void chipset_reset(enum chipset_reset_reason reason)
{
/*
* Irrespective of cold_reset value, always toggle SYS_RESET_L to
@@ -574,7 +575,7 @@ void chipset_reset(void)
* The EC cannot control warm vs cold reset of the chipset using
* SYS_RESET_L; it's more of a request.
*/
- CPRINTS("%s", __func__);
+ CPRINTS("%s: %d", __func__, reason);
/*
* Toggling SYS_RESET_L will not have any impact when it's already
@@ -585,6 +586,8 @@ void chipset_reset(void)
return;
}
+ report_ap_reset(reason);
+
gpio_set_level(GPIO_SYS_RESET_L, 0);
/*
* Debounce time for SYS_RESET_L is 16 ms. Wait twice that period
diff --git a/power/mt817x.c b/power/mt817x.c
index 37db9fe698..f13e04a1e3 100644
--- a/power/mt817x.c
+++ b/power/mt817x.c
@@ -418,7 +418,7 @@ enum power_state power_chipset_init(void)
* The warm reset triggers AP into the recovery mode (
* flash SPI from USB).
*/
- chipset_reset();
+ chipset_reset(CHIPSET_RESET_UNKNOWN);
init_power_state = POWER_G3;
} else {
@@ -474,8 +474,11 @@ static void chipset_turn_off_power_rails(void)
set_system_power(0);
}
-void chipset_force_shutdown(void)
+void chipset_force_shutdown(enum chipset_shutdown_reason reason)
{
+ CPRINTS("%s: %d", __func__, reason);
+ report_ap_reset(reason);
+
chipset_turn_off_power_rails();
/* clean-up internal variable */
@@ -638,9 +641,11 @@ static void power_on(void)
CPRINTS("AP running ...");
}
-void chipset_reset(void)
+void chipset_reset(enum chipset_reset_reason reason)
{
- CPRINTS("EC triggered warm reboot");
+ CPRINTS("%s: %d", __func__, reason);
+ report_ap_reset(reason);
+
set_warm_reset(1);
usleep(PMIC_WARM_RESET_H_HOLD_TIME);
/* deassert the reset signals */
diff --git a/power/mt8183.c b/power/mt8183.c
index 7e8d5ba57b..13a76532a2 100644
--- a/power/mt8183.c
+++ b/power/mt8183.c
@@ -89,9 +89,10 @@ static const struct power_seq_op s3s5_power_seq[] = {
static int forcing_shutdown;
-void chipset_force_shutdown(void)
+void chipset_force_shutdown(enum chipset_shutdown_reason reason)
{
- CPRINTS("%s()", __func__);
+ CPRINTS("%s(%d)", __func__, reason);
+ report_ap_reset(reason);
/*
* Force power off. This condition will reset once the state machine
@@ -100,12 +101,18 @@ void chipset_force_shutdown(void)
forcing_shutdown = 1;
task_wake(TASK_ID_CHIPSET);
}
-DECLARE_DEFERRED(chipset_force_shutdown);
+
+void chipset_force_shutdown_button(void)
+{
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_BUTTON);
+}
+DECLARE_DEFERRED(chipset_force_shutdown_button);
/* If chipset needs to be reset, EC also reboots to RO. */
-void chipset_reset(void)
+void chipset_reset(enum chipset_reset_reason reason)
{
- CPRINTS("%s", __func__);
+ CPRINTS("%s: %d", __func__, reason);
+ report_ap_reset(reason);
cflush();
system_reset(SYSTEM_RESET_HARD);
@@ -214,7 +221,7 @@ enum power_state power_handle_state(enum power_state state)
* after debounce (32 ms), minus PMIC_EN_PULSE_MS above.
* It would be good to avoid another _EN pulse above.
*/
- chipset_reset();
+ chipset_reset(CHIPSET_RESET_INIT);
}
/* Wait for PMIC to bring up rails. */
@@ -238,7 +245,7 @@ enum power_state power_handle_state(enum power_state state)
power_seq_run(s3s0_power_seq, ARRAY_SIZE(s3s0_power_seq));
if (power_wait_signals(IN_PGOOD_S0)) {
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_WAIT);
return POWER_S0S3;
}
@@ -277,7 +284,8 @@ enum power_state power_handle_state(enum power_state state)
*/
if (power_button_is_pressed()) {
forcing_shutdown = 1;
- hook_call_deferred(&chipset_force_shutdown_data, -1);
+ hook_call_deferred(&chipset_force_shutdown_button_data,
+ -1);
}
return POWER_S3;
@@ -306,11 +314,11 @@ static void power_button_changed(void)
chipset_exit_hard_off();
/* Delayed power down from S0/S3, cancel on PB release */
- hook_call_deferred(&chipset_force_shutdown_data,
+ hook_call_deferred(&chipset_force_shutdown_button_data,
FORCED_SHUTDOWN_DELAY);
} else {
/* Power button released, cancel deferred shutdown */
- hook_call_deferred(&chipset_force_shutdown_data, -1);
+ hook_call_deferred(&chipset_force_shutdown_button_data, -1);
}
}
DECLARE_HOOK(HOOK_POWER_BUTTON_CHANGE, power_button_changed, HOOK_PRIO_DEFAULT);
diff --git a/power/rk3288.c b/power/rk3288.c
index 22ec8eff5b..8144401b54 100644
--- a/power/rk3288.c
+++ b/power/rk3288.c
@@ -223,7 +223,7 @@ enum power_state power_chipset_init(void)
* The warm reset triggers AP into the RK recovery mode (
* flash SPI from USB).
*/
- chipset_reset();
+ chipset_reset(CHIPSET_RESET_INIT);
init_power_state = POWER_G3;
} else {
@@ -265,8 +265,10 @@ static void chipset_turn_off_power_rails(void)
set_pmic_warm_reset(1);
}
-void chipset_force_shutdown(void)
+void chipset_force_shutdown(enum chipset_shutdown_reason reason)
{
+ CPRINTS("%s(%d)", __func__, reason);
+ report_ap_reset(reason);
chipset_turn_off_power_rails();
/* clean-up internal variable */
@@ -380,9 +382,11 @@ static void power_off(void)
CPRINTS("power shutdown complete");
}
-void chipset_reset(void)
+void chipset_reset(enum chipset_reset_reason reason)
{
- CPRINTS("EC triggered warm reboot");
+ CPRINTS("%s(%d)", __func__, reason);
+ report_ap_reset(reason);
+
CPRINTS("assert GPIO_PMIC_WARM_RESET_L for %d ms",
PMIC_WARM_RESET_L_HOLD_TIME / MSEC);
set_pmic_warm_reset(1);
diff --git a/power/rk3399.c b/power/rk3399.c
index e70bd3e84f..b229684e7a 100644
--- a/power/rk3399.c
+++ b/power/rk3399.c
@@ -207,9 +207,10 @@ static const struct power_seq_op s3s5_power_seq[] = {
static int forcing_shutdown;
-void chipset_force_shutdown(void)
+void chipset_force_shutdown(enum chipset_shutdown_reason reason)
{
- CPRINTS("%s()", __func__);
+ CPRINTS("%s(%d)", __func__, reason);
+ report_ap_reset(reason);
/*
* Force power off. This condition will reset once the state machine
@@ -220,13 +221,14 @@ void chipset_force_shutdown(void)
}
#define SYS_RST_HOLD_US (1 * MSEC)
-void chipset_reset(void)
+void chipset_reset(enum chipset_reset_reason reason)
{
#ifdef CONFIG_CMD_RTC
/* Print out the RTC to help correlate resets in logs. */
print_system_rtc(CC_CHIPSET);
#endif
- CPRINTS("%s", __func__);
+ CPRINTS("%s(%d)", __func__, reason);
+ report_ap_reset(reason);
/* Pulse SYS_RST */
gpio_set_level(GPIO_SYS_RST_L, 0);
@@ -389,7 +391,8 @@ enum power_state power_handle_state(enum power_state state)
if (charge_want_shutdown() ||
tries > CHARGER_INITIALIZED_TRIES) {
CPRINTS("power-up inhibited");
- chipset_force_shutdown();
+ chipset_force_shutdown(
+ CHIPSET_SHUTDOWN_BATTERY_INHIBIT);
return POWER_G3;
}
@@ -408,7 +411,7 @@ enum power_state power_handle_state(enum power_state state)
#endif
if (power_wait_signals(IN_PGOOD_S3)) {
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_WAIT);
return POWER_S3S5;
}
@@ -458,7 +461,7 @@ enum power_state power_handle_state(enum power_state state)
#else
if (power_wait_signals(IN_PGOOD_S0)) {
#endif /* POWER_SIGNAL_POLLING */
- chipset_force_shutdown();
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_WAIT);
return POWER_S0S3;
}
diff --git a/power/sdm845.c b/power/sdm845.c
index f6a22c54ae..350e940504 100644
--- a/power/sdm845.c
+++ b/power/sdm845.c
@@ -141,7 +141,7 @@ enum power_on_event_t {
static void chipset_reset_request_handler(void)
{
CPRINTS("AP wants reset");
- chipset_reset();
+ chipset_reset(CHIPSET_RESET_AP_REQ);
}
DECLARE_DEFERRED(chipset_reset_request_handler);
@@ -582,22 +582,26 @@ static int check_for_power_off_event(void)
/*****************************************************************************/
/* Chipset interface */
-void chipset_force_shutdown(void)
+void chipset_force_shutdown(enum chipset_shutdown_reason reason)
{
- CPRINTS("EC triggered shutdown");
+ CPRINTS("%s(%d)", __func__, reason);
+ report_ap_reset(reason);
+
power_off();
/* Clean-up internal variable */
power_request = POWER_REQ_NONE;
}
-void chipset_reset(void)
+void chipset_reset(enum chipset_reset_reason reason)
{
/*
* Before we can reprogram the PMIC to make the PMIC RESIN_N pin as
* reset pin and zero-latency. We do cold reset instead.
*/
- CPRINTS("EC triggered cold reboot");
+ CPRINTS("%s(%d)", __func__, reason);
+ report_ap_reset(reason);
+
bypass_power_lost_trigger = 1;
power_off();
bypass_power_lost_trigger = 0;
diff --git a/power/skylake.c b/power/skylake.c
index 8df01c542f..a5cf6aa0a5 100644
--- a/power/skylake.c
+++ b/power/skylake.c
@@ -23,7 +23,7 @@
static int forcing_shutdown; /* Forced shutdown in progress? */
-void chipset_force_shutdown(void)
+void chipset_force_shutdown(enum chipset_shutdown_reason reason)
{
CPRINTS("%s()", __func__);
@@ -35,6 +35,7 @@ void chipset_force_shutdown(void)
* hold time on the PMIC.
*/
if (!chipset_in_state(CHIPSET_STATE_ANY_OFF)) {
+ report_ap_reset(reason);
forcing_shutdown = 1;
power_button_pch_press();
}
diff --git a/power/stoney.c b/power/stoney.c
index 3034eee41e..1cc08de9fc 100644
--- a/power/stoney.c
+++ b/power/stoney.c
@@ -30,13 +30,14 @@
static int forcing_shutdown; /* Forced shutdown in progress? */
-void chipset_force_shutdown(void)
+void chipset_force_shutdown(enum chipset_shutdown_reason reason)
{
CPRINTS("%s()", __func__);
if (!chipset_in_state(CHIPSET_STATE_ANY_OFF)) {
forcing_shutdown = 1;
power_button_pch_press();
+ report_ap_reset(reason);
}
}
@@ -46,15 +47,16 @@ static void chipset_force_g3(void)
gpio_set_level(GPIO_EN_PWR_A, 0);
}
-void chipset_reset(void)
+void chipset_reset(enum chipset_reset_reason reason)
{
- CPRINTS("%s", __func__);
+ CPRINTS("%s: %d", __func__, reason);
if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) {
CPRINTS("Can't reset: SOC is off");
return;
}
+ report_ap_reset(reason);
/*
* Send a pulse to SYS_RST to trigger a warm reset.
*/
diff --git a/test/sbs_charging_v2.c b/test/sbs_charging_v2.c
index e69cbdfb34..e266e59215 100644
--- a/test/sbs_charging_v2.c
+++ b/test/sbs_charging_v2.c
@@ -36,7 +36,7 @@ static void reset_mocks(void)
shutdown_warning_time.val = 0ULL;
}
-void chipset_force_shutdown(void)
+void chipset_force_shutdown(enum chipset_shutdown_reason reason)
{
is_shutdown = 1;
mock_chipset_state = CHIPSET_STATE_HARD_OFF;
diff --git a/util/ectool.c b/util/ectool.c
index f1de218278..cf28ccca08 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -17,6 +17,7 @@
#include "anx74xx.h"
#include "battery.h"
#include "comm-host.h"
+#include "chipset.h"
#include "compile_time_macros.h"
#include "cros_ec_dev.h"
#include "ec_panicinfo.h"
@@ -256,6 +257,9 @@ const char help_str[] =
" Get/set TMP006 calibration\n"
" tmp006raw <tmp006_index>\n"
" Get raw TMP006 data\n"
+ " uptimeinfo\n"
+ " Get info about how long the EC has been running and the most\n"
+ " recent AP resets\n"
" usbchargemode <port> <mode>\n"
" Set USB charging mode\n"
" usbmux <mux>\n"
@@ -622,6 +626,125 @@ int cmd_cmdversions(int argc, char *argv[])
return 0;
}
+/*
+ * Convert a reset cause ID to human-readable string, providing total coverage
+ * of the 'cause' space. The returned string points to static storage and must
+ * not be free()ed.
+ */
+static const char *reset_cause_to_str(uint16_t cause)
+{
+ static const char * const reset_causes[] = {
+ "(reset unknown)",
+ "reset: board custom",
+ "reset: ap hang detected",
+ "reset: console command",
+ "reset: keyboard sysreset",
+ "reset: keyboard warm reboot",
+ "reset: debug warm reboot",
+ "reset: at AP's request",
+ "reset: during EC initialization",
+ };
+ BUILD_ASSERT(ARRAY_SIZE(reset_causes) == CHIPSET_RESET_COUNT);
+
+ static const char * const shutdown_causes[] = {
+ "shutdown: power failure",
+ "shutdown: during EC initialization",
+ "shutdown: board custom",
+ "shutdown: battery voltage startup inhibit",
+ "shutdown: power wait asserted",
+ "shutdown: critical battery",
+ "shutdown: by console command",
+ "shutdown: entering G3",
+ "shutdown: thermal",
+ "shutdown: power button",
+ };
+ BUILD_ASSERT(ARRAY_SIZE(shutdown_causes) ==
+ CHIPSET_SHUTDOWN_COUNT - CHIPSET_SHUTDOWN_BEGIN);
+
+ if (cause < CHIPSET_RESET_COUNT)
+ return reset_causes[cause];
+
+ if (cause < CHIPSET_SHUTDOWN_BEGIN)
+ return "(reset unknown)";
+
+ if (cause < CHIPSET_SHUTDOWN_COUNT)
+ return shutdown_causes[cause - CHIPSET_SHUTDOWN_BEGIN];
+
+ return "(shutdown unknown)";
+}
+
+int cmd_uptimeinfo(int argc, char *argv[])
+{
+ static const char * const reset_flag_strings[] = {
+ "other",
+ "reset-pin",
+ "brownout",
+ "power-on",
+ "watchdog",
+ "soft",
+ "hibernate",
+ "rtc-alarm",
+ "wake-pin",
+ "low-battery",
+ "sysjump",
+ "hard",
+ "ap-off",
+ "preserved",
+ "usb-resume",
+ "rdd",
+ "rbox",
+ "security"
+ };
+
+ struct ec_response_uptime_info r;
+ int rv;
+ int i;
+ int flag_count;
+ uint32_t flag;
+
+ if (argc != 1) {
+ fprintf(stderr, "uptimeinfo takes no arguments");
+ return -1;
+ }
+
+ rv = ec_command(EC_CMD_GET_UPTIME_INFO, 0, NULL, 0, &r, sizeof(r));
+ if (rv < 0) {
+ fprintf(stderr, "ERROR: EC_CMD_GET_UPTIME_INFO failed; %d\n",
+ rv);
+ return rv;
+ }
+
+ printf("EC uptime: %d.%03d seconds\n",
+ r.time_since_ec_boot_ms / 1000,
+ r.time_since_ec_boot_ms % 1000);
+
+ printf("AP resets since EC boot: %d\n", r.ap_resets_since_ec_boot);
+
+ printf("Most recent AP reset causes:\n");
+ for (i = 0; i != ARRAY_SIZE(r.recent_ap_reset); ++i) {
+ if (r.recent_ap_reset[i].reset_time_ms == 0)
+ continue;
+
+ printf("\t%d.%03d: %s\n",
+ r.recent_ap_reset[i].reset_time_ms / 1000,
+ r.recent_ap_reset[i].reset_time_ms % 1000,
+ reset_cause_to_str(r.recent_ap_reset[i].reset_cause));
+ }
+
+ printf("EC reset flags at last EC boot: ");
+ flag_count = 0;
+ for (flag = 0; flag != ARRAY_SIZE(reset_flag_strings); ++flag) {
+ if ((r.ec_reset_flags & (1 << flag)) != 0) {
+ if (flag_count)
+ printf(" | ");
+ printf(reset_flag_strings[flag]);
+ flag_count++;
+ }
+ }
+ printf("\n");
+ return 0;
+}
+
int cmd_version(int argc, char *argv[])
{
struct ec_response_get_version r;
@@ -8115,6 +8238,7 @@ const struct command commands[] = {
{"tpframeget", cmd_tp_frame_get},
{"tmp006cal", cmd_tmp006cal},
{"tmp006raw", cmd_tmp006raw},
+ {"uptimeinfo", cmd_uptimeinfo},
{"usbchargemode", cmd_usb_charge_set_mode},
{"usbmux", cmd_usb_mux},
{"usbpd", cmd_usb_pd},