summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHu, Hebo <hebo.hu@intel.com>2019-05-08 17:12:59 +0800
committerchrome-bot <chrome-bot@chromium.org>2019-05-12 19:27:51 -0700
commitb0b956cc0b17a04ffdff7d15292ecb33b4b8235b (patch)
tree49d7c8fcac8aa0d6fc457428314f290388c70053
parent1fd8e3b0c5609612cf3339edab73bd7b7bb93f54 (diff)
downloadchrome-ec-b0b956cc0b17a04ffdff7d15292ecb33b4b8235b.tar.gz
ish/ish5: fixed both-edge triggered gpio configuration blocking D0ix issue
ISH PMU does not support both-edge interrupt triggered gpio configuration. If both edges are configured, then the ISH can't stay in low power mode because it will exit immediately. As a W/A, we scan all gpio pins which have been configured as both-edge triggered, and then temporarily set each gpio pin to the single edge trigger that is opposite of its value, then restore the both-edge trigger configuration immediately after exiting low power mode. BUG=b:132001235 BRANCH=none TEST= tested on arcada platform, console should freeze after entered low power mode Change-Id: I83a43d9fbee6cfd1a6820bdb44c1446f109ffb32 Signed-off-by: Hu, Hebo <hebo.hu@intel.com> Reviewed-on: https://chromium-review.googlesource.com/1600310 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Tested-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Hebo Hu <hebo.hu@intel.corp-partner.google.com> Reviewed-by: Jack Rosenthal <jrosenth@chromium.org>
-rw-r--r--chip/ish/aontaskfw/ish_aontask.c5
-rw-r--r--chip/ish/power_mgt.c134
2 files changed, 97 insertions, 42 deletions
diff --git a/chip/ish/aontaskfw/ish_aontask.c b/chip/ish/aontaskfw/ish_aontask.c
index 95b6d9ce5d..7c0809b4a2 100644
--- a/chip/ish/aontaskfw/ish_aontask.c
+++ b/chip/ish/aontaskfw/ish_aontask.c
@@ -546,6 +546,11 @@ static void handle_reset(int pm_state)
/* disable watch dog */
WDT_CONTROL &= ~WDT_CONTROL_ENABLE_BIT;
+ /* disable all gpio interrupts */
+ ISH_GPIO_GRER = 0;
+ ISH_GPIO_GFER = 0;
+ ISH_GPIO_GIMR = 0;
+
/* disable CSME CSR irq */
IPC_PIMR &= ~IPC_PIMR_CSME_CSR_BIT;
diff --git a/chip/ish/power_mgt.c b/chip/ish/power_mgt.c
index 12645ab6b9..7fe5031b32 100644
--- a/chip/ish/power_mgt.c
+++ b/chip/ish/power_mgt.c
@@ -265,33 +265,73 @@ static void handle_reset_in_aontask(int pm_state)
static void enter_d0i0(void)
{
- timestamp_t t0, t1;
-
- t0 = get_time();
+ uint32_t t0, t1;
+ t0 = __hw_clock_source_read();
pm_ctx.aon_share->pm_state = ISH_PM_STATE_D0I0;
/* halt ISH cpu, will wakeup from any interrupt */
ish_mia_halt();
- t1 = get_time();
-
+ t1 = __hw_clock_source_read();
pm_ctx.aon_share->pm_state = ISH_PM_STATE_D0;
-
- pm_stats.d0i0_time_us += t1.val - t0.val;
+ pm_stats.d0i0_time_us += t1 - t0;
pm_stats.d0i0_cnt++;
}
+/**
+ * ISH PMU does not support both-edge interrupt triggered gpio configuration.
+ * If both edges are configured, then the ISH can't stay in low poer mode
+ * because it will exit immediately.
+ *
+ * As a workaround, we scan all gpio pins which have been configured as
+ * both-edge triggered, and then temporarily set each gpio pin to the single
+ * edge trigger that is opposite of its value, then restore the both-edge
+ * trigger configuration immediately after exiting low power mode.
+ */
+static uint32_t __unused convert_both_edge_gpio_to_single_edge(void)
+{
+ uint32_t both_edge_pins = 0;
+ int i = 0;
+
+ /**
+ * scan GPIO GFER, GRER and GIMR registers to find the both edge
+ * interrupt trigger mode enabled pins.
+ */
+ for (i = 0; i < 32; i++) {
+ if (ISH_GPIO_GIMR & BIT(i) &&
+ ISH_GPIO_GRER & BIT(i) &&
+ ISH_GPIO_GFER & BIT(i)) {
+
+ /* Record the pin so we can restore it later */
+ both_edge_pins |= BIT(i);
+
+ if (ISH_GPIO_GPLR & BIT(i)) {
+ /* pin is high, just keep falling edge mode */
+ ISH_GPIO_GRER &= ~BIT(i);
+ } else {
+ /* pin is low, just keep rising edge mode */
+ ISH_GPIO_GFER &= ~BIT(i);
+ }
+ }
+ }
+
+ return both_edge_pins;
+}
+
+static void __unused restore_both_edge_gpio_config(uint32_t both_edge_pin_map)
+{
+ ISH_GPIO_GRER |= both_edge_pin_map;
+ ISH_GPIO_GFER |= both_edge_pin_map;
+}
+
#ifdef CONFIG_ISH_PM_D0I1
static void enter_d0i1(void)
{
uint64_t current_irq_map;
-
- timestamp_t t0, t1;
- t0 = get_time();
-
- pm_ctx.aon_share->pm_state = ISH_PM_STATE_D0I1;
+ uint32_t both_edge_gpio_pins;
+ uint32_t t0, t1;
/* only enable PMU wakeup interrupt */
current_irq_map = disable_all_interrupts();
@@ -301,6 +341,11 @@ static void enter_d0i1(void)
task_enable_irq(ISH_RESET_PREP_IRQ);
#endif
+ t0 = __hw_clock_source_read();
+ pm_ctx.aon_share->pm_state = ISH_PM_STATE_D0I1;
+
+ both_edge_gpio_pins = convert_both_edge_gpio_to_single_edge();
+
/* enable Trunk Clock Gating (TCG) of ISH */
CCU_TCG_EN = 1;
@@ -310,15 +355,16 @@ static void enter_d0i1(void)
/* disable Trunk Clock Gating (TCG) of ISH */
CCU_TCG_EN = 0;
- /* restore interrupts */
- task_disable_irq(ISH_PMU_WAKEUP_IRQ);
- restore_interrupts(current_irq_map);
+ restore_both_edge_gpio_config(both_edge_gpio_pins);
pm_ctx.aon_share->pm_state = ISH_PM_STATE_D0;
-
- t1 = get_time();
- pm_stats.d0i1_time_us += t1.val - t0.val;
+ t1 = __hw_clock_source_read();
+ pm_stats.d0i1_time_us += t1 - t0;
pm_stats.d0i1_cnt++;
+
+ /* restore interrupts */
+ task_disable_irq(ISH_PMU_WAKEUP_IRQ);
+ restore_interrupts(current_irq_map);
}
#endif
@@ -328,11 +374,8 @@ static void enter_d0i1(void)
static void enter_d0i2(void)
{
uint64_t current_irq_map;
-
- timestamp_t t0, t1;
- t0 = get_time();
-
- pm_ctx.aon_share->pm_state = ISH_PM_STATE_D0I2;
+ uint32_t both_edge_gpio_pins;
+ uint32_t t0, t1;
/* only enable PMU wakeup interrupt */
current_irq_map = disable_all_interrupts();
@@ -342,6 +385,11 @@ static void enter_d0i2(void)
task_enable_irq(ISH_RESET_PREP_IRQ);
#endif
+ t0 = __hw_clock_source_read();
+ pm_ctx.aon_share->pm_state = ISH_PM_STATE_D0I2;
+
+ both_edge_gpio_pins = convert_both_edge_gpio_to_single_edge();
+
/* enable Trunk Clock Gating (TCG) of ISH */
CCU_TCG_EN = 1;
@@ -358,16 +406,16 @@ static void enter_d0i2(void)
/* disable Trunk Clock Gating (TCG) of ISH */
CCU_TCG_EN = 0;
- /* restore interrupts */
- task_disable_irq(ISH_PMU_WAKEUP_IRQ);
- restore_interrupts(current_irq_map);
-
- t1 = get_time();
+ restore_both_edge_gpio_config(both_edge_gpio_pins);
+ t1 = __hw_clock_source_read();
pm_ctx.aon_share->pm_state = ISH_PM_STATE_D0;
-
- pm_stats.d0i2_time_us += t1.val - t0.val;
+ pm_stats.d0i2_time_us += t1 - t0;
pm_stats.d0i2_cnt++;
+
+ /* restore interrupts */
+ task_disable_irq(ISH_PMU_WAKEUP_IRQ);
+ restore_interrupts(current_irq_map);
}
#endif
@@ -377,11 +425,8 @@ static void enter_d0i2(void)
static void enter_d0i3(void)
{
uint64_t current_irq_map;
- timestamp_t t0, t1;
-
- t0 = get_time();
-
- pm_ctx.aon_share->pm_state = ISH_PM_STATE_D0I3;
+ uint32_t both_edge_gpio_pins;
+ uint32_t t0, t1;
/* only enable PMU wakeup interrupt */
current_irq_map = disable_all_interrupts();
@@ -391,6 +436,11 @@ static void enter_d0i3(void)
task_enable_irq(ISH_RESET_PREP_IRQ);
#endif
+ t0 = __hw_clock_source_read();
+ pm_ctx.aon_share->pm_state = ISH_PM_STATE_D0I3;
+
+ both_edge_gpio_pins = convert_both_edge_gpio_to_single_edge();
+
/* enable Trunk Clock Gating (TCG) of ISH */
CCU_TCG_EN = 1;
@@ -407,16 +457,16 @@ static void enter_d0i3(void)
/* disable Trunk Clock Gating (TCG) of ISH */
CCU_TCG_EN = 0;
- /* restore interrupts */
- task_disable_irq(ISH_PMU_WAKEUP_IRQ);
- restore_interrupts(current_irq_map);
-
- t1 = get_time();
+ restore_both_edge_gpio_config(both_edge_gpio_pins);
+ t1 = __hw_clock_source_read();
pm_ctx.aon_share->pm_state = ISH_PM_STATE_D0;
-
- pm_stats.d0i3_time_us += t1.val - t0.val;
+ pm_stats.d0i3_time_us += t1 - t0;
pm_stats.d0i3_cnt++;
+
+ /* restore interrupts */
+ task_disable_irq(ISH_PMU_WAKEUP_IRQ);
+ restore_interrupts(current_irq_map);
}
#endif