summaryrefslogtreecommitdiff
path: root/zephyr
diff options
context:
space:
mode:
authorMulin Chao <mlchao@nuvoton.com>2022-06-29 18:56:36 -0700
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-09-13 03:29:49 +0000
commit8d8629986c1e92c7d91c271b7c240283f7a811db (patch)
treec8cbd8aaddcbafe185ea4c028cb862413c6495cc /zephyr
parent953d4674e60b3c4cdabda38e0880fa92894ab5de (diff)
downloadchrome-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.npcx48
-rw-r--r--zephyr/shim/chip/npcx/gpio.c142
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 */