diff options
author | Wealian Liao <whliao@nuvoton.corp-partner.google.com> | 2021-02-26 10:16:11 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-03-24 17:27:46 +0000 |
commit | 893a8b354f45750e50a419670307fcc2e59ba4cb (patch) | |
tree | 224363e0c91e48b4cfb689a84f40e9afcdeef7c7 | |
parent | 09d0027924a74efaa8d1b55805af11377962d180 (diff) | |
download | chrome-ec-893a8b354f45750e50a419670307fcc2e59ba4cb.tar.gz |
zephyr: npcx: add reset cause check
The reset cause will influence the initialization flow. We define some
of initial flow of the reset cause for the following development.
This CL include the following:
1. Add check_reset_cause() which sets the system reset flag.
2. Add chip_bbram_status_check() to clear the error status & show the
error message.
3. Add CONFIG_BOARD_RESET_AFTER_POWER_ON feature.
4. Define the initialize flow for reset cause.
BRANCH=none
BUG=b:178101173
TEST=check the following reset cause by 'sysinfo'
1. power-up
2. reset-pin reset
3. soft by 'reboot' console command
4. watchdog by 'waitms 2000'
Signed-off-by: Wealian Liao <whliao@nuvoton.corp-partner.google.com>
Change-Id: I515868d8cda4544fdbe782210b0108b4dda0d8cc
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2731180
Reviewed-by: Keith Short <keithshort@chromium.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
Commit-Queue: Keith Short <keithshort@chromium.org>
-rw-r--r-- | docs/zephyr_init.md | 53 | ||||
-rw-r--r-- | zephyr/Kconfig | 2 | ||||
-rw-r--r-- | zephyr/Kconfig.system | 18 | ||||
-rw-r--r-- | zephyr/drivers/cros_bbram/Kconfig | 16 | ||||
-rw-r--r-- | zephyr/drivers/cros_bbram/cros_bbram_npcx.c | 8 | ||||
-rw-r--r-- | zephyr/drivers/cros_system/Kconfig | 13 | ||||
-rw-r--r-- | zephyr/drivers/cros_system/cros_system_npcx.c | 5 | ||||
-rw-r--r-- | zephyr/shim/chip/npcx/Kconfig.npcx | 18 | ||||
-rw-r--r-- | zephyr/shim/chip/npcx/system.c | 78 | ||||
-rw-r--r-- | zephyr/shim/src/system.c | 173 |
10 files changed, 341 insertions, 43 deletions
diff --git a/docs/zephyr_init.md b/docs/zephyr_init.md new file mode 100644 index 0000000000..8822736efb --- /dev/null +++ b/docs/zephyr_init.md @@ -0,0 +1,53 @@ +# Zephyr OS-based EC Initialization Order + +Zephyr provides Z_INIT_ENTRY_DEFINE() & the extend macro to install the initial +function. The initialize flow for different levels would be like the following +(not very detailed): +* architecture-specific initialization +* `PRE_KERNEL_1` level +* `PRE_KERNEL_2` level +* `POST_KERNEL` level +* `APPLICATION` level +* main() + +The kernel and driver initial functions separate into specific initialize +levels. It couldn't put all initial functions in main() for the Zephyr OS-based +EC. It is also hard to maintain those initial priority which separates into +different files. + +This file defines some Zephyr OS-based EC initial priorities which have critical +sequence requirement for initializing: + +## PRE_KERNEL_1 +* Priority (0-9) - Reserved for system testability: + + The highest priority could be used in zephyr. Don't use it when system + development. Buffer it for the following system development & testing. + +* Priority (10-19) - Chip level system pre-initialization: + + These priorities in this range are used for critical chip initialization, + including determining the reset cause and initializing the battery-backed + RAM driver. Most chip drivers should only be initialized after + `PLATFORM_EC_SYSTEM_PRE_INIT`. + +* Priority (20) - PLATFORM_EC_SYSTEM_PRE_INIT: + + At this initialization priority, the CROS system checks the reset cause and + initializing the system reset flags. Any chip level drivers related to + determining the reset type must be at a higher priority. + +* TODO + +## PRE_KERNEL_2 +* TODO + +## POST_KERNEL +* TODO + +## APPLICATION +* TODO + +## main() +* TODO +* Start the tasks. diff --git a/zephyr/Kconfig b/zephyr/Kconfig index b054d85372..4c3dc5849a 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -31,6 +31,7 @@ menuconfig PLATFORM_EC if PLATFORM_EC +rsource "shim/chip/npcx/Kconfig.npcx" rsource "Kconfig.adc" rsource "Kconfig.battery" rsource "Kconfig.console" @@ -39,6 +40,7 @@ rsource "Kconfig.keyboard" rsource "Kconfig.led" rsource "Kconfig.powerseq" rsource "Kconfig.motionsense" +rsource "Kconfig.system" rsource "Kconfig.tasks" rsource "Kconfig.temperature" rsource "Kconfig.usbc" diff --git a/zephyr/Kconfig.system b/zephyr/Kconfig.system new file mode 100644 index 0000000000..d8ae87b149 --- /dev/null +++ b/zephyr/Kconfig.system @@ -0,0 +1,18 @@ +# Copyright 2021 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +if PLATFORM_EC + +config PLATFORM_EC_SYSTEM_PRE_INIT_PRIORITY + int "System pre-initialization priority" + default 20 + range 0 99 + help + This defines the initialization priority for the CROS + system_pre_init() function. system_pre_init() reads chip level reset + cause and stores it into the system reset flags. All drivers, except + those critical to determining the reset type, should be initialized at + lower priority so that the system reset flags are valid. + +endif # PLATFORM_EC diff --git a/zephyr/drivers/cros_bbram/Kconfig b/zephyr/drivers/cros_bbram/Kconfig index ba7ce8b1ad..43850b032a 100644 --- a/zephyr/drivers/cros_bbram/Kconfig +++ b/zephyr/drivers/cros_bbram/Kconfig @@ -7,4 +7,18 @@ menuconfig CROS_BBRAM_NPCX depends on SOC_FAMILY_NPCX default y help - This options enables stuff.
\ No newline at end of file + This options enables stuff. + +if CROS_BBRAM_NPCX + +config CROS_BBRAM_NPCX_INIT_PRIORITY + int "cros_bbram npcx initialization priority" + default 11 + range 10 19 + help + This sets the npcx cros_bbram driver initialization priority. NPCX + chip uses BBRAM to save some system information that persists across + chip resets. The priority should be higher than + SYSTEM_PRE_INIT_PRIORITY & lower than CROS_SYSTEM_NPCX_INIT_PRIORITY. + +endif # CROS_BBRAM_NPCX diff --git a/zephyr/drivers/cros_bbram/cros_bbram_npcx.c b/zephyr/drivers/cros_bbram/cros_bbram_npcx.c index f6fa64fdd2..20698df85b 100644 --- a/zephyr/drivers/cros_bbram/cros_bbram_npcx.c +++ b/zephyr/drivers/cros_bbram/cros_bbram_npcx.c @@ -126,6 +126,12 @@ static int bbram_npcx_init(const struct device *dev) /* * The priority of bbram_npcx_init() should lower than cros_system_npcx_init(). */ +#if (CONFIG_CROS_BBRAM_NPCX_INIT_PRIORITY <= \ + CONFIG_CROS_SYSTEM_NPCX_INIT_PRIORITY) +#error CONFIG_CROS_BBRAM_NPCX_INIT_PRIORITY must greater than \ + CONFIG_CROS_SYSTEM_NPCX_INIT_PRIORITY +#endif + #define CROS_BBRAM_INIT(inst) \ static struct { \ } cros_bbram_data_##inst; \ @@ -137,7 +143,7 @@ static int bbram_npcx_init(const struct device *dev) DEVICE_DEFINE(cros_bbram_npcx_##inst, DT_INST_LABEL(inst), \ bbram_npcx_init, NULL, &cros_bbram_data_##inst, \ &cros_bbram_cfg_##inst, PRE_KERNEL_1, \ - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + CONFIG_CROS_BBRAM_NPCX_INIT_PRIORITY, \ &cros_bbram_npcx_driver_api); DT_INST_FOREACH_STATUS_OKAY(CROS_BBRAM_INIT); diff --git a/zephyr/drivers/cros_system/Kconfig b/zephyr/drivers/cros_system/Kconfig index e1e7163f99..09d47ad7e7 100644 --- a/zephyr/drivers/cros_system/Kconfig +++ b/zephyr/drivers/cros_system/Kconfig @@ -11,3 +11,16 @@ menuconfig CROS_SYSTEM_NPCX processors. Currently, Zephyr doesn't provide the system related API. The cros system driver provides the low-level driver related to chromium ec system functionality. + +if CROS_SYSTEM_NPCX + +config CROS_SYSTEM_NPCX_INIT_PRIORITY + int "cros_system npcx initialization priority" + default 10 + range 10 19 + help + This sets the npcx cros_system driver initialization priority. The + cros_system driver provides access to the NPCX reset cause and must be + higher priority than CONFIG_SYSTEM_PRE_INIT_PRIORITY. + +endif # CROS_SYSTEM_NPCX diff --git a/zephyr/drivers/cros_system/cros_system_npcx.c b/zephyr/drivers/cros_system/cros_system_npcx.c index b21219355d..48e33188cf 100644 --- a/zephyr/drivers/cros_system/cros_system_npcx.c +++ b/zephyr/drivers/cros_system/cros_system_npcx.c @@ -128,12 +128,13 @@ static const struct cros_system_driver_api cros_system_driver_npcx_api = { }; /* - * The priority of cros_system_npcx_init() should be lower than watchdog init + * The priority of cros_system_npcx_init() should be higher than watchdog init * for reset cause check. */ DEVICE_DEFINE(cros_system_npcx_0, "CROS_SYSTEM", cros_system_npcx_init, NULL, &cros_system_npcx_dev_data, &cros_system_dev_cfg, PRE_KERNEL_1, - 30, &cros_system_driver_npcx_api); + CONFIG_CROS_SYSTEM_NPCX_INIT_PRIORITY, + &cros_system_driver_npcx_api); #define HAL_DBG_REG_BASE_ADDR \ ((struct dbg_reg *)DT_REG_ADDR(DT_INST(0, nuvoton_npcx_cros_dbg))) diff --git a/zephyr/shim/chip/npcx/Kconfig.npcx b/zephyr/shim/chip/npcx/Kconfig.npcx new file mode 100644 index 0000000000..1107a846a8 --- /dev/null +++ b/zephyr/shim/chip/npcx/Kconfig.npcx @@ -0,0 +1,18 @@ +# Copyright 2021 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +if PLATFORM_EC + +config CROS_SYSTEM_NPCX_PRE_INIT_PRIORITY + int "System pre-initialization priority" + default 15 + range 10 19 + depends on SOC_FAMILY_NPCX + help + This sets the priority of the NPCX chip system initialization. The + chip system initialization verifies the integrity of the BBRAM and + must be a lower priority than CONFIG_CROS_BBRAM_NPCX_INIT_PRIORITY and + must be a higher priority than PLATFORM_EC_SYSTEM_PRE_INIT. + +endif # PLATFORM_EC diff --git a/zephyr/shim/chip/npcx/system.c b/zephyr/shim/chip/npcx/system.c index d776733827..96fccfebca 100644 --- a/zephyr/shim/chip/npcx/system.c +++ b/zephyr/shim/chip/npcx/system.c @@ -4,10 +4,8 @@ */ #include <drivers/cros_bbram.h> -#include <drivers/cros_system.h> #include <logging/log.h> -#include "watchdog.h" #include "system.h" #define GET_BBRAM_OFFSET(node) \ @@ -16,7 +14,7 @@ LOG_MODULE_REGISTER(shim_npcx_system, LOG_LEVEL_ERR); -const struct device *bbram_dev; +const static struct device *bbram_dev; void chip_save_reset_flags(uint32_t flags) { @@ -44,51 +42,53 @@ uint32_t chip_read_reset_flags(void) return flags; } -void system_reset(int flags) +void chip_bbram_status_check(void) { - const struct device *sys_dev = device_get_binding("CROS_SYSTEM"); - int err; - uint32_t save_flags; - - if (!sys_dev) - LOG_ERR("sys_dev get binding failed"); - - /* Disable interrupts to avoid task swaps during reboot */ - interrupt_disable_all(); - - /* Get flags to be saved in BBRAM */ - system_encode_save_flags(flags, &save_flags); - - /* Store flags to battery backed RAM. */ - chip_save_reset_flags(save_flags); - - /* If WAIT_EXT is set, then allow 10 seconds for external reset */ - if (flags & SYSTEM_RESET_WAIT_EXT) { - int i; - - /* Wait 10 seconds for external reset */ - for (i = 0; i < 1000; i++) { - watchdog_reload(); - udelay(10000); - } + if (!bbram_dev) { + LOG_DBG("bbram_dev doesn't binding"); + return; } - err = cros_system_soc_reset(sys_dev); - - if (err < 0) - LOG_ERR("soc reset failed"); - - /* should never return */ - while (1) - ; + if (cros_bbram_get_ibbr(bbram_dev)) { + LOG_ERR("VBAT power drop!"); + cros_bbram_reset_ibbr(bbram_dev); + } + if (cros_bbram_get_vsby(bbram_dev)) { + LOG_ERR("VSBY power drop!"); + cros_bbram_reset_vsby(bbram_dev); + } + if (cros_bbram_get_vcc1(bbram_dev)) { + LOG_ERR("VCC1 power drop!"); + cros_bbram_reset_vcc1(bbram_dev); + } } static int chip_system_init(const struct device *unused) { ARG_UNUSED(unused); + /* + * NPCX chip uses BBRAM to save the reset flag. Binding & check BBRAM + * here. + */ bbram_dev = device_get_binding(DT_LABEL(DT_NODELABEL(bbram))); + if (!bbram_dev) { + LOG_ERR("bbram_dev gets binding failed"); + return -1; + } + + /* check the BBRAM status */ + chip_bbram_status_check(); + return 0; } - -SYS_INIT(chip_system_init, PRE_KERNEL_1, 50); +/* + * The priority should be lower than CROS_BBRAM_NPCX_INIT_PRIORITY. + */ +#if (CONFIG_CROS_SYSTEM_NPCX_PRE_INIT_PRIORITY <= \ + CONFIG_CROS_BBRAM_NPCX_INIT_PRIORITY) +#error CONFIG_CROS_SYSTEM_NPCX_PRE_INIT_PRIORITY must greater than \ + CONFIG_CROS_BBRAM_NPCX_INIT_PRIORITY +#endif +SYS_INIT(chip_system_init, PRE_KERNEL_1, + CONFIG_CROS_SYSTEM_NPCX_PRE_INIT_PRIORITY); diff --git a/zephyr/shim/src/system.c b/zephyr/shim/src/system.c index bf421ad8ae..1e17dcea13 100644 --- a/zephyr/shim/src/system.c +++ b/zephyr/shim/src/system.c @@ -5,18 +5,24 @@ #include <device.h> #include <drivers/cros_bbram.h> +#include <drivers/cros_system.h> +#include <logging/log.h> #include "bbram.h" #include "common.h" #include "cros_version.h" #include "system.h" +#include "watchdog.h" #define BBRAM_REGION_PD0 DT_PATH(named_bbram_regions, pd0) #define BBRAM_REGION_PD1 DT_PATH(named_bbram_regions, pd1) #define BBRAM_REGION_PD2 DT_PATH(named_bbram_regions, pd2) #define BBRAM_REGION_TRY_SLOT DT_PATH(named_bbram_regions, try_slot) +LOG_MODULE_REGISTER(shim_system, LOG_LEVEL_ERR); + STATIC_IF_NOT(CONFIG_ZTEST) const struct device *bbram_dev; +STATIC_IF_NOT(CONFIG_ZTEST) const struct device *sys_dev; #if DT_NODE_EXISTS(DT_NODELABEL(bbram)) static int system_init(const struct device *unused) @@ -95,3 +101,170 @@ const char *system_get_chip_revision(void) { return ""; } + +void system_reset(int flags) +{ + int err; + uint32_t save_flags; + + if (!sys_dev) + LOG_ERR("sys_dev get binding failed"); + + /* Disable interrupts to avoid task swaps during reboot */ + interrupt_disable_all(); + + /* Get flags to be saved in BBRAM */ + system_encode_save_flags(flags, &save_flags); + + /* Store flags to battery backed RAM. */ + chip_save_reset_flags(save_flags); + + /* If WAIT_EXT is set, then allow 10 seconds for external reset */ + if (flags & SYSTEM_RESET_WAIT_EXT) { + int i; + + /* Wait 10 seconds for external reset */ + for (i = 0; i < 1000; i++) { + watchdog_reload(); + udelay(10000); + } + } + + err = cros_system_soc_reset(sys_dev); + + if (err < 0) + LOG_ERR("soc reset failed"); + + /* should never return */ + while (1) + continue; +} + +static int check_reset_cause(void) +{ + uint32_t chip_flags = 0; /* used to write back to the BBRAM */ + uint32_t system_flags = chip_read_reset_flags(); /* system reset flag */ + int chip_reset_cause = 0; /* chip-level reset cause */ + + chip_reset_cause = cros_system_get_reset_cause(sys_dev); + if (chip_reset_cause < 0) + return -1; + + /* + * TODO(b/182876692): Implement CONFIG_POWER_BUTTON_INIT_IDLE & + * CONFIG_BOARD_FORCE_RESET_PIN. Also, check the hibernate flow if PSL + * merge into tot. + */ + + switch (chip_reset_cause) { + case POWERUP: + system_flags |= EC_RESET_FLAG_POWER_ON; + if (IS_ENABLED(CONFIG_BOARD_RESET_AFTER_POWER_ON)) { + /* + * Power-on restart, so set a flag and save it for the + * next imminent reset. Later code will check for this + * flag and wait for the second reset. + */ + system_flags |= EC_RESET_FLAG_INITIAL_PWR; + chip_flags |= EC_RESET_FLAG_INITIAL_PWR; + } + break; + + case VCC1_RST_PIN: + /* + * If configured, check the saved flags to see whether the + * previous restart was a power-on, in which case treat this + * restart as a power-on as well. This is to workaround the fact + * that the H1 will reset the EC at power up. + */ + if (IS_ENABLED(CONFIG_BOARD_RESET_AFTER_POWER_ON)) { + if (system_flags & EC_RESET_FLAG_INITIAL_PWR) { + /* + * The previous restart was a power-on so treat + * this restart as that, and clear the flag so + * later code will not wait for the second + * reset. + */ + system_flags = (system_flags & + ~EC_RESET_FLAG_INITIAL_PWR) | + EC_RESET_FLAG_POWER_ON; + } else { + /* + * No previous reset flag, so this is a + * subsequent restart i.e any restarts after the + * second restart caused by the H1. + */ + system_flags |= EC_RESET_FLAG_RESET_PIN; + } + } else { + system_flags |= EC_RESET_FLAG_RESET_PIN; + } + break; + + case DEBUG_RST: + system_flags |= EC_RESET_FLAG_SOFT; + break; + + case WATCHDOG_RST: + /* + * Don't set EC_RESET_FLAG_WATCHDOG flag if watchdog is issued + * by system_reset in order to distinguish reset cause is panic + * reason or not. + */ + if (!(system_flags & (EC_RESET_FLAG_SOFT | EC_RESET_FLAG_HARD))) + system_flags |= EC_RESET_FLAG_WATCHDOG; + break; + } + + /* Clear & set the reset flags for the following reset. */ + chip_save_reset_flags(chip_flags); + + /* Set the system reset flags. */ + system_set_reset_flags(system_flags); + + return 0; +} + +static int system_preinitialize(const struct device *unused) +{ + ARG_UNUSED(unused); + + sys_dev = device_get_binding("CROS_SYSTEM"); + if (!sys_dev) { + /* + * TODO(b/183022804): This should not happen in normal + * operation. Check whether the error check can be change to + * build-time error, or at least a fatal run-time error. + */ + LOG_ERR("sys_dev gets binding failed"); + return -1; + } + + /* check the reset cause */ + if (check_reset_cause() != 0) { + LOG_ERR("check the reset cause failed"); + return -1; + } + + /* + * For some boards on power-on, the EC is reset by the H1 after + * power-on, so the EC sees 2 resets. This config enables the EC to save + * a flag on the first power-up restart, and then wait for the second + * reset before any other setup is done (such as GPIOs, timers, UART + * etc.) On the second reset, the saved flag is used to detect the + * previous power-on, and treat the second reset as a power-on instead + * of a reset. + */ + if (IS_ENABLED(CONFIG_BOARD_RESET_AFTER_POWER_ON) && + system_get_reset_flags() & EC_RESET_FLAG_INITIAL_PWR) { + /* TODO(b/182875520): Change to use 2 second delay. */ + while (1) + continue; + } + + return 0; +} +#if (!defined(CONFIG_ZTEST)) +SYS_INIT(system_preinitialize, PRE_KERNEL_1, + CONFIG_PLATFORM_EC_SYSTEM_PRE_INIT_PRIORITY); +#endif |