diff options
author | Mulin Chao <mlchao@nuvoton.com> | 2018-06-07 19:27:44 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-06-29 11:38:53 -0700 |
commit | fde9042dbac2a273f5607e659b8e5a98c301e42b (patch) | |
tree | 9321c705dbbf5159f9b50e8520e5fdd1f39f7be3 /chip | |
parent | 47a1c1a0427400d5a0f5def8f69fcb70bbb4f4e7 (diff) | |
download | chrome-ec-fde9042dbac2a273f5607e659b8e5a98c301e42b.tar.gz |
npcx: gpio: bypass for excessive power consumption on low-voltage IOs.
It was found that for npcx ec's GPIOs that support low-voltage input,
there is an excessive power consumption when they are selected to
low-voltage mode and their Vin is 1.8V.
To bypass this issue when the chip enters deep sleep where current is
important, this CL includes:
1. Disable GPIOs without ISR which are selected to 1.8V and not i2c
ports in gpio_pre_init().
2. Disable input buffer of 1.8V i2c ports before entering deep sleep.
3. Enable input buffer of 1.8V i2c ports after ec wakes up.
BRANCH=none
BUG=b:110170824
TEST=No build errors for npcx ec series. Measured power consumption on
yorp and it saved ~1.3mA current after applying this patch at S0ix. Run
stress test on poppy and no symptom found. Remove CONFIG_LOW_POWER_IDLE
in board driver and no symptom occurred on poppy and yorp.
Change-Id: Iaf66c81ca16104839734ba19492f2061113dafb3
Signed-off-by: Mulin Chao <mlchao@nuvoton.com>
Reviewed-on: https://chromium-review.googlesource.com/1098864
Reviewed-by: Jett Rink <jettrink@chromium.org>
Diffstat (limited to 'chip')
-rw-r--r-- | chip/npcx/clock.c | 10 | ||||
-rw-r--r-- | chip/npcx/gpio.c | 70 | ||||
-rw-r--r-- | chip/npcx/gpio_chip-npcx5.h | 20 | ||||
-rw-r--r-- | chip/npcx/gpio_chip-npcx7.h | 14 | ||||
-rw-r--r-- | chip/npcx/gpio_chip.h | 5 |
5 files changed, 115 insertions, 4 deletions
diff --git a/chip/npcx/clock.c b/chip/npcx/clock.c index a146436034..9411959515 100644 --- a/chip/npcx/clock.c +++ b/chip/npcx/clock.c @@ -329,6 +329,13 @@ void __idle(void) /* Enable UART wake-up and interrupt request */ SET_BIT(NPCX_WKEN(MIWU_TABLE_1, MIWU_GROUP_8), 7); #endif + + /* + * Disable input buffer of all 1.8v i2c ports before + * entering deep sleep for better power consumption. + */ + gpio_enable_1p8v_i2c_wake_up_input(0); + /* Set deep idle - instant wake-up mode */ NPCX_PMCSR = IDLE_PARAMS; @@ -361,6 +368,9 @@ void __idle(void) clock_gpio2uart(); #endif + /* Enable input buffer of all 1.8v i2c ports. */ + gpio_enable_1p8v_i2c_wake_up_input(1); + /* Record time spent in deep sleep. */ idle_dsleep_time_us += next_evt_us; diff --git a/chip/npcx/gpio.c b/chip/npcx/gpio.c index df8e1733d9..01a0a6897f 100644 --- a/chip/npcx/gpio.c +++ b/chip/npcx/gpio.c @@ -9,6 +9,7 @@ #include "common.h" #include "gpio.h" #include "gpio_chip.h" +#include "i2c.h" #include "keyboard_config.h" #include "hooks.h" #include "registers.h" @@ -38,6 +39,15 @@ struct npcx_wui { /* Constants for GPIO interrupt mapping */ #define GPIO_INT(name, pin, flags, signal) NPCX_WUI_GPIO_##pin, +#ifdef CONFIG_LOW_POWER_IDLE +/* Extend gpio_wui_table for the bypass of better power consumption */ +#define GPIO(name, pin, flags) NPCX_WUI_GPIO_##pin, +#define UNIMPLEMENTED(name) WUI_NONE, +#else +/* Ignore GPIO and UNIMPLEMENTED definitions if not using lower power idle */ +#define GPIO(name, pin, flags) +#define UNIMPLEMENTED(name) +#endif static const struct npcx_wui gpio_wui_table[] = { #include "gpio.wrap" }; @@ -116,7 +126,7 @@ static void gpio_interrupt_type_sel(enum gpio_signal signal, uint32_t flags) { uint8_t table, group, pmask; - if (signal >= ARRAY_SIZE(gpio_wui_table)) + if (signal >= GPIO_IH_COUNT) return; table = gpio_wui_table[signal].table; @@ -196,6 +206,49 @@ void gpio_low_voltage_level_sel(uint8_t port, uint8_t mask, uint8_t low_voltage) CPRINTS("Warn! No low voltage support in port%d, mask%d\n", port, mask); } + +/* The bypass of low voltage IOs for better power consumption */ +#ifdef CONFIG_LOW_POWER_IDLE +static int gpio_is_i2c_pin(enum gpio_signal signal) +{ + int i; + + for (i = 0; i < i2c_ports_used; i++) + if (i2c_ports[i].scl == signal || i2c_ports[i].sda == signal) + return 1; + + return 0; +} + +static void gpio_enable_wake_up_input(enum gpio_signal signal, int enable) +{ + const struct npcx_wui *wui = gpio_wui_table + signal; + + /* Is it a valid wui mapping item? */ + if (wui->table != MIWU_TABLE_COUNT) { + /* Turn on/off input io buffer by WKINENx registers */ + if (enable) + SET_BIT(NPCX_WKINEN(wui->table, wui->group), wui->bit); + else + CLEAR_BIT(NPCX_WKINEN(wui->table, wui->group), + wui->bit); + } +} + +void gpio_enable_1p8v_i2c_wake_up_input(int enable) +{ + int i; + + /* Set input buffer of 1.8V i2c ports. */ + for (i = 0; i < i2c_ports_used; i++) { + if (gpio_list[i2c_ports[i].scl].flags & GPIO_SEL_1P8V) + gpio_enable_wake_up_input(i2c_ports[i].scl, enable); + if (gpio_list[i2c_ports[i].sda].flags & GPIO_SEL_1P8V) + gpio_enable_wake_up_input(i2c_ports[i].sda, enable); + } +} +#endif + /* * Make sure the bit depth of low voltage register. */ @@ -419,6 +472,21 @@ void gpio_pre_init(void) */ gpio_set_alternate_function(g->port, g->mask, -1); } + + /* The bypass of low voltage IOs for better power consumption */ +#ifdef CONFIG_LOW_POWER_IDLE + /* Disable input buffer of 1.8V GPIOs without ISR */ + g = gpio_list + GPIO_IH_COUNT; + for (i = GPIO_IH_COUNT; i < GPIO_COUNT; i++, g++) { + /* + * I2c ports are both alternate mode and normal gpio pin, but + * the alternate mode needs the wake up input even though the + * normal gpio definition doesn't have an ISR. + */ + if ((g->flags & GPIO_SEL_1P8V) && !gpio_is_i2c_pin(i)) + gpio_enable_wake_up_input(i, 0); + } +#endif } /* List of GPIO IRQs to enable. Don't automatically enable interrupts for diff --git a/chip/npcx/gpio_chip-npcx5.h b/chip/npcx/gpio_chip-npcx5.h index 0dbda59200..014dc326fb 100644 --- a/chip/npcx/gpio_chip-npcx5.h +++ b/chip/npcx/gpio_chip-npcx5.h @@ -142,6 +142,26 @@ #define NPCX_WUI_GPIO_7_5 WUI(1, MIWU_GROUP_8, 5) #define NPCX_WUI_GPIO_7_6 WUI(1, MIWU_GROUP_8, 6) +/* Others GPO without MIWU functionality */ +#define NPCX_WUI_GPIO_1_2 WUI_NONE +#define NPCX_WUI_GPIO_3_2 WUI_NONE +#define NPCX_WUI_GPIO_3_5 WUI_NONE +#define NPCX_WUI_GPIO_6_6 WUI_NONE +#define NPCX_WUI_GPIO_7_7 WUI_NONE +#define NPCX_WUI_GPIO_B_6 WUI_NONE +#define NPCX_WUI_GPIO_D_6 WUI_NONE + +/* Others GPIO without MIWU functionality on npcx5 */ +#define NPCX_WUI_GPIO_D_4 WUI_NONE +#define NPCX_WUI_GPIO_D_5 WUI_NONE +#define NPCX_WUI_GPIO_D_7 WUI_NONE +#define NPCX_WUI_GPIO_E_0 WUI_NONE +#define NPCX_WUI_GPIO_E_1 WUI_NONE +#define NPCX_WUI_GPIO_E_2 WUI_NONE +#define NPCX_WUI_GPIO_E_3 WUI_NONE +#define NPCX_WUI_GPIO_E_4 WUI_NONE +#define NPCX_WUI_GPIO_E_5 WUI_NONE + /*****************************************************************************/ /* Macro functions for Alternative mapping table */ diff --git a/chip/npcx/gpio_chip-npcx7.h b/chip/npcx/gpio_chip-npcx7.h index 23f18b8700..e0081b761a 100644 --- a/chip/npcx/gpio_chip-npcx7.h +++ b/chip/npcx/gpio_chip-npcx7.h @@ -100,7 +100,6 @@ #define NPCX_WUI_GPIO_1_0 WUI(1, MIWU_GROUP_2, 0) #define NPCX_WUI_GPIO_1_1 WUI(1, MIWU_GROUP_2, 1) #define NPCX_WUI_GPIO_F_4 WUI(1, MIWU_GROUP_2, 2) -#define NPCX_WUI_GPIO_1_3 WUI(1, MIWU_GROUP_2, 3) #define NPCX_WUI_GPIO_1_4 WUI(1, MIWU_GROUP_2, 4) #define NPCX_WUI_GPIO_1_5 WUI(1, MIWU_GROUP_2, 5) #define NPCX_WUI_GPIO_1_6 WUI(1, MIWU_GROUP_2, 6) @@ -151,7 +150,6 @@ #define NPCX_WUI_GPIO_6_2 WUI(1, MIWU_GROUP_7, 2) #define NPCX_WUI_GPIO_6_3 WUI(1, MIWU_GROUP_7, 3) #define NPCX_WUI_GPIO_6_4 WUI(1, MIWU_GROUP_7, 4) -#define NPCX_WUI_GPIO_6_5 WUI(1, MIWU_GROUP_7, 5) #ifndef NPCX_EXT32K_OSC_SUPPORT #define NPCX_WUI_GPIO_7_1 WUI(1, MIWU_GROUP_7, 7) /* Used as CLKOUT if support*/ #endif @@ -169,7 +167,17 @@ /* Group F: NPCX_IRQ_WKINTFG_2 */ #define NPCX_WUI_GPIO_F_1 WUI(2, MIWU_GROUP_6, 1) #define NPCX_WUI_GPIO_F_2 WUI(2, MIWU_GROUP_6, 2) -#define NPCX_WUI_GPIO_B_6 WUI(2, MIWU_GROUP_6, 6) + +/* Others GPO without MIWU functionality */ +#define NPCX_WUI_GPIO_1_2 WUI_NONE +#define NPCX_WUI_GPIO_1_3 WUI_NONE /* Software strap pin GP_SEL1_L */ +#define NPCX_WUI_GPIO_3_2 WUI_NONE +#define NPCX_WUI_GPIO_3_5 WUI_NONE +#define NPCX_WUI_GPIO_6_5 WUI_NONE /* Software strap pin FLPRG_L */ +#define NPCX_WUI_GPIO_6_6 WUI_NONE +#define NPCX_WUI_GPIO_7_7 WUI_NONE +#define NPCX_WUI_GPIO_B_6 WUI_NONE /* Software strap pin GP_SEL0_L */ +#define NPCX_WUI_GPIO_D_6 WUI_NONE /*****************************************************************************/ /* Macro functions for Alternative mapping table */ diff --git a/chip/npcx/gpio_chip.h b/chip/npcx/gpio_chip.h index b5fcec20c8..6d704a5e6a 100644 --- a/chip/npcx/gpio_chip.h +++ b/chip/npcx/gpio_chip.h @@ -11,6 +11,8 @@ #define WUI(tbl, grp, idx) ((struct npcx_wui) { .table = tbl, .group = grp, \ .bit = idx }) #define WUI_INT(tbl, grp) WUI(tbl, grp, 0) +#define WUI_NONE ((struct npcx_wui) { .table = MIWU_TABLE_COUNT, .group = 0, \ + .bit = 0 }) /* Macros to initialize the alternative and low voltage mapping table. */ #define NPCX_GPIO_NONE ((struct npcx_gpio) {.port = 0, .bit = 0, .valid = 0}) @@ -43,6 +45,9 @@ void npcx_uart2gpio(void); */ void npcx_gpio2uart(void); +/* Set input buffer of all 1.8v i2c ports. */ +void gpio_enable_1p8v_i2c_wake_up_input(int enable); + /* * Include the MIWU, alternative and low-Voltage macro functions for GPIOs * depends on Nuvoton chip series. |