diff options
author | Mulin Chao <mlchao@nuvoton.com> | 2022-06-29 18:56:36 -0700 |
---|---|---|
committer | Chromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2022-09-13 03:29:49 +0000 |
commit | 8d8629986c1e92c7d91c271b7c240283f7a811db (patch) | |
tree | c8cbd8aaddcbafe185ea4c028cb862413c6495cc /zephyr | |
parent | 953d4674e60b3c4cdabda38e0880fa92894ab5de (diff) | |
download | chrome-ec-8d8629986c1e92c7d91c271b7c240283f7a811db.tar.gz |
zephyr: gpio: npcx: Add `gpiodbg` command for power investigation
This CL adds a `gpiodbg` console command for investigating power
consumption. This command is used to turn on/off IO pad's input buffer
and observe power consumption via this pad.
Here is sn example to list all IO pads used on npcx9 evb and turn
`spi_cs_l` input buffer off
```
ec:~$ gpiodbg list
IDX|ON| GPIO | Name
---+--+------+----------
00 |* | io03 | recovery_l
01 |* | io93 | wp_l
02 |* | iod2 | ac_present
03 |* | io00 | power_button_l
04 |* | io01 | lid_open
05 |* | io36 | entering_rw
06 |* | io50 | pch_wake_l
07 |* | ioc7 | pgood_fan
08 |* | ioa5 | spi_cs_l
09 |* | io64 | board_version1
10 |* | io65 | board_version2
11 |* | io66 | board_version3
12 |* | io52 | unused pin
13 |* | io54 | unused pin
14 |* | io76 | unused pin
15 |* | iod1 | unused pin
ec:~$ gpiodbg off 8
```
BUG=b:228222441
BRANCH=none
TEST=zmake build npcx9 --clobber.
Observe WKINEN reg when 'gpiodbg off 8' is executed.
Signed-off-by: Mulin Chao <mlchao@nuvoton.com>
Change-Id: Ia61deaf6bd3acf9faa5c2bce14615f92a809ddc1
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3735445
Code-Coverage: Zoss <zoss-cl-coverage@prod.google.com>
Reviewed-by: Fabio Baltieri <fabiobaltieri@google.com>
Reviewed-by: Keith Short <keithshort@chromium.org>
Diffstat (limited to 'zephyr')
-rw-r--r-- | zephyr/shim/chip/npcx/Kconfig.npcx | 48 | ||||
-rw-r--r-- | zephyr/shim/chip/npcx/gpio.c | 142 |
2 files changed, 190 insertions, 0 deletions
diff --git a/zephyr/shim/chip/npcx/Kconfig.npcx b/zephyr/shim/chip/npcx/Kconfig.npcx index c9c1744c1e..5202d14448 100644 --- a/zephyr/shim/chip/npcx/Kconfig.npcx +++ b/zephyr/shim/chip/npcx/Kconfig.npcx @@ -15,4 +15,52 @@ config CROS_SYSTEM_NPCX_PRE_INIT_PRIORITY must be a lower priority than CONFIG_BBRAM_INIT_PRIORITY and must be a higher priority than PLATFORM_EC_SYSTEM_PRE_INIT. +config PLATFORM_EC_CONSOLE_CMD_GPIODBG + bool "Console command: gpiodbg" + depends on SOC_FAMILY_NPCX + help + Enable the "gpiodbg" command. This lists all IO pads used on platform + and turns on/off specific pad's input buffer to observe leakage + current through it. + + Example: + gpiodbg list + + IDX|ON| GPIO | Name + ---+--+------+---------- + 00 |* | io03 | recovery_l + 01 |* | io93 | wp_l + 02 |* | iod2 | ac_present + 03 |* | io00 | power_button_l + 04 |* | io01 | lid_open + 05 |* | io36 | entering_rw + 06 |* | io50 | pch_wake_l + 07 |* | ioc7 | pgood_fan + 08 |* | ioa5 | spi_cs_l + 09 |* | io64 | board_version1 + 10 |* | io65 | board_version2 + 11 |* | io66 | board_version3 + 12 |* | io52 | unused pin + 13 |* | io54 | unused pin + + gpiodbg off 11 + gpiodbg list + + IDX|ON| GPIO | Name + ---+--+------+---------- + 00 |* | io03 | recovery_l + 01 |* | io93 | wp_l + 02 |* | iod2 | ac_present + 03 |* | io00 | power_button_l + 04 |* | io01 | lid_open + 05 |* | io36 | entering_rw + 06 |* | io50 | pch_wake_l + 07 |* | ioc7 | pgood_fan + 08 |* | ioa5 | spi_cs_l + 09 |* | io64 | board_version1 + 10 |* | io65 | board_version2 + 11 | | io66 | board_version3 + 12 |* | io52 | unused pin + 13 |* | io54 | unused pin + endif # PLATFORM_EC diff --git a/zephyr/shim/chip/npcx/gpio.c b/zephyr/shim/chip/npcx/gpio.c index 7106b2a294..e8bf3dfdf5 100644 --- a/zephyr/shim/chip/npcx/gpio.c +++ b/zephyr/shim/chip/npcx/gpio.c @@ -6,10 +6,13 @@ #include <zephyr/device.h> #include <zephyr/drivers/gpio.h> #include <zephyr/kernel.h> +#include <zephyr/shell/shell.h> #include <zephyr/logging/log.h> #include "gpio/gpio.h" +#include "soc_gpio.h" +#include "util.h" LOG_MODULE_REGISTER(shim_cros_gpio, LOG_LEVEL_ERR); @@ -53,3 +56,142 @@ int gpio_config_unused_pins(void) return 0; } + +#ifdef CONFIG_PLATFORM_EC_CONSOLE_CMD_GPIODBG +/* + * IO information about each GPIO that is configured in the `named_gpios` and + *` unused_pins` device tree nodes. + */ +struct npcx_io_info { + /* A npcx gpio port device */ + const struct device *dev; + /* A npcx gpio port number */ + int port; + /* Bit number of pin within a npcx gpio port */ + gpio_pin_t pin; + /* GPIO net name */ + const char *name; + /* Enable flag of npcx gpio input buffer */ + bool enable; +}; + +#define NAMED_GPIO_INFO(node) \ + { \ + .dev = DEVICE_DT_GET(DT_GPIO_CTLR(node, gpios)), \ + .port = DT_PROP(DT_GPIO_CTLR(node, gpios), index), \ + .pin = DT_GPIO_PIN(node, gpios), \ + .name = DT_NODE_FULL_NAME(node), \ + .enable = true, \ + }, + +#define UNUSED_GPIO_INFO(node, prop, idx) \ + { \ + .dev = DEVICE_DT_GET(DT_GPIO_CTLR_BY_IDX(node, prop, idx)), \ + .port = DT_PROP(DT_GPIO_CTLR_BY_IDX(node, prop, idx), index), \ + .pin = DT_GPIO_PIN_BY_IDX(node, prop, idx), \ + .name = "unused pin", \ + .enable = true, \ + }, + +#define NAMED_GPIO_INIT(node) \ + COND_CODE_1(DT_NODE_HAS_PROP(node, gpios), (NAMED_GPIO_INFO(node)), ()) + +static struct npcx_io_info gpio_info[] = { +#if DT_NODE_EXISTS(DT_PATH(named_gpios)) + DT_FOREACH_CHILD(DT_PATH(named_gpios), NAMED_GPIO_INIT) +#endif +#if DT_NODE_EXISTS(DT_PATH(unused_pins)) + DT_FOREACH_PROP_ELEM(DT_PATH(unused_pins), unused_gpios, + UNUSED_GPIO_INFO) +#endif +}; + +static int get_index_from_arg(const struct shell *sh, char **argv, int *index) +{ + char *end_ptr; + int num = strtol(argv[1], &end_ptr, 0); + const int gpio_cnt = ARRAY_SIZE(gpio_info); + + if (*end_ptr != '\0') { + shell_error(sh, "Failed to parse %s", argv[1]); + return -EINVAL; + } + + if (num >= gpio_cnt) { + shell_error(sh, "Index shall be less than %u, was %u", gpio_cnt, + num); + return -EINVAL; + } + + *index = num; + + return 0; +} + +static int cmd_gpio_list_all(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + /* Print header */ + shell_print(sh, "IDX|ON| GPIO | Name"); + shell_print(sh, "---+--+------+----------"); + + /* List all GPIOs in 'named-gpios' and 'unused_pins' DT nodes */ + for (int i = 0; i < ARRAY_SIZE(gpio_info); i++) { + shell_print(sh, "%02d |%s | io%x%x | %s", i, + gpio_info[i].enable ? "*" : " ", gpio_info[i].port, + gpio_info[i].pin, gpio_info[i].name); + } + + return 0; +} + +static int cmd_gpio_turn_on(const struct shell *sh, size_t argc, char **argv) +{ + int index; + int res = get_index_from_arg(sh, argv, &index); + + if (res < 0) { + return res; + } + + /* Turn on GPIO's input buffer by index */ + gpio_info[index].enable = true; + npcx_gpio_enable_io_pads(gpio_info[index].dev, gpio_info[index].pin); + + return 0; +} + +static int cmd_gpio_turn_off(const struct shell *sh, size_t argc, char **argv) +{ + int index; + int res = get_index_from_arg(sh, argv, &index); + + if (res < 0) { + return res; + } + + /* Turn off GPIO's input buffer by index */ + gpio_info[index].enable = false; + npcx_gpio_disable_io_pads(gpio_info[index].dev, gpio_info[index].pin); + + return 0; +} + +SHELL_STATIC_SUBCMD_SET_CREATE( + sub_gpiodbg, + SHELL_CMD_ARG(list, NULL, "List all GPIOs used on platform by index", + cmd_gpio_list_all, 1, 0), + SHELL_CMD_ARG(on, NULL, "<index_in_list> Turn on GPIO's input buffer", + cmd_gpio_turn_on, 2, 0), + SHELL_CMD_ARG(off, NULL, "<index_in_list> Turn off GPIO's input buffer", + cmd_gpio_turn_off, 2, 0), + SHELL_SUBCMD_SET_END /* Array terminated. */ +); + +SHELL_CMD_ARG_REGISTER(gpiodbg, &sub_gpiodbg, + "Commands for power consumption " + "investigation", + NULL, 2, 0); +#endif /* CONFIG_PLATFORM_EC_CONSOLE_CMD_GPIODBG */ |