summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMulin Chao <mlchao@nuvoton.com>2018-06-07 19:27:44 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-06-29 11:38:53 -0700
commitfde9042dbac2a273f5607e659b8e5a98c301e42b (patch)
tree9321c705dbbf5159f9b50e8520e5fdd1f39f7be3
parent47a1c1a0427400d5a0f5def8f69fcb70bbb4f4e7 (diff)
downloadchrome-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>
-rw-r--r--chip/npcx/clock.c10
-rw-r--r--chip/npcx/gpio.c70
-rw-r--r--chip/npcx/gpio_chip-npcx5.h20
-rw-r--r--chip/npcx/gpio_chip-npcx7.h14
-rw-r--r--chip/npcx/gpio_chip.h5
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.