ish-pm: support GPIO both edge interrupt
(cherry picked from commit e69df34314fae734b6ce898d759a1a4ad11fd2c8)
Original-Change-Id: I471a20c61fa2d3085e96e901af6afc6be72a77be
Original-Signed-off-by: Li Feng <li1.feng@intel.com>
GitOrigin-RevId: e69df34314fae734b6ce898d759a1a4ad11fd2c8
Change-Id: I11f1c5834420db30f20b085a2222d416313607b4
diff --git a/bsp_sedi/soc/intel_ish/pm/ish_pm.c b/bsp_sedi/soc/intel_ish/pm/ish_pm.c
index 48d0700..cf20ba1 100644
--- a/bsp_sedi/soc/intel_ish/pm/ish_pm.c
+++ b/bsp_sedi/soc/intel_ish/pm/ish_pm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Intel Corporation
+ * Copyright (c) 2024 Intel Corporation
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -81,6 +81,52 @@
write32(CCU_BCG_GPIO, 0);
}
+/**
+ * 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.
+ *
+ * To keep LPM fucntions intact and still support both edge configuration,
+ * the alternative way is:
+ * Before entering LPM, scan all gpio pins which are configured to be
+ * triggered by both-edge, and temporarily set each gpio pin to the single
+ * edge expected to be triggered next time, that is, opposite to its value.
+ * After exiting LPM, then restore the both-edge trigger configuration.
+ **/
+static uint32_t 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 (read32(ISH_GPIO_GIMR) & BIT(i) && read32(ISH_GPIO_GRER) & BIT(i) &&
+ read32(ISH_GPIO_GFER & BIT(i))) {
+ /* Record the pin so we can restore it later */
+ both_edge_pins |= BIT(i);
+
+ if (read32(ISH_GPIO_GPLR) & BIT(i)) {
+ /* pin is high, just keep falling edge mode */
+ write32(ISH_GPIO_GRER, read32(ISH_GPIO_GRER) & ~BIT(i));
+ } else {
+ /* pin is low, just keep rising edge mode */
+ write32(ISH_GPIO_GFER, read32(ISH_GPIO_GFER) & ~BIT(i));
+ }
+ }
+ }
+
+ return both_edge_pins;
+}
+
+static void restore_both_edge_gpio_config(uint32_t both_edge_pin_map)
+{
+ write32(ISH_GPIO_GRER, read32(ISH_GPIO_GRER) | both_edge_pin_map);
+ write32(ISH_GPIO_GFER, read32(ISH_GPIO_GFER) | both_edge_pin_map);
+}
+
/* power management internal context data structure */
struct pm_context {
/* aontask image valid flag */
@@ -322,6 +368,7 @@
uint64_t ioapic_state;
#endif
uint64_t t0, t1;
+ uint32_t both_edge_gpio_pins;
#ifndef CONFIG_SOC_INTEL_ISH_5_6_0
ioapic_state = sedi_core_get_irq_map();
@@ -333,6 +380,8 @@
t0 = sedi_rtc_get_us();
pm_ctx.aon_share->pm_state = ISH_PM_STATE_D0I1;
+ both_edge_gpio_pins = convert_both_edge_gpio_to_single_edge();
+
#ifndef CONFIG_SOC_INTEL_ISH_5_6_0
/* enable Trunk Clock Gating (TCG) of ISH */
write32(CCU_TCG_EN, 1);
@@ -350,6 +399,8 @@
write32(CCU_BCG_MIA, read32(CCU_BCG_MIA) & (~CCU_BCG_BIT_MIA));
#endif
+ restore_both_edge_gpio_config(both_edge_gpio_pins);
+
pm_ctx.aon_share->pm_state = ISH_PM_STATE_D0;
t1 = sedi_rtc_get_us();
log_pm_stat(&pm_stats.d0i1, t0, t1);
@@ -365,6 +416,7 @@
{
uint64_t ioapic_state;
uint64_t t0, t1;
+ uint32_t both_edge_gpio_pins;
ioapic_state = sedi_core_get_irq_map();
pm_disable_irqs(ioapic_state);
@@ -374,6 +426,8 @@
t0 = sedi_rtc_get_us();
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 */
write32(CCU_TCG_EN, 1);
@@ -397,6 +451,8 @@
pm_ctx.aon_share->pm_state = ISH_PM_STATE_D0;
log_pm_stat(&pm_stats.d0i2, t0, t1);
+ restore_both_edge_gpio_config(both_edge_gpio_pins);
+
if (pm_ctx.aon_share->pg_exit)
log_pm_stat(&pm_stats.pg, t0, t1);
@@ -409,6 +465,7 @@
{
uint64_t ioapic_state;
uint64_t t0, t1;
+ uint32_t both_edge_gpio_pins;
ioapic_state = sedi_core_get_irq_map();
pm_disable_irqs(ioapic_state);
@@ -418,6 +475,8 @@
t0 = sedi_rtc_get_us();
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 */
write32(CCU_TCG_EN, 1);
@@ -437,6 +496,8 @@
/* disable Trunk Clock Gating (TCG) of ISH */
write32(CCU_TCG_EN, 0);
+ restore_both_edge_gpio_config(both_edge_gpio_pins);
+
t1 = sedi_rtc_get_us();
pm_ctx.aon_share->pm_state = ISH_PM_STATE_D0;
log_pm_stat(&pm_stats.d0i3, t0, t1);