summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Chen <philipchen@google.com>2017-06-19 19:20:27 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-06-22 17:03:59 -0700
commit9e32694d1051ef0eb3b091e1b03563cfd538b1d7 (patch)
tree1fc741d906e997aa7f796f8c2c93d1e2fba4f475
parentb0dd82b39c57eab3a30923eb4a755172b9852f7e (diff)
downloadchrome-ec-9e32694d1051ef0eb3b091e1b03563cfd538b1d7.tar.gz
power/rk3399: Table-based power sequencing
We need to refactor power/rk3399.c to make it more flexible to support different power sequences for upcoming follower boards. BUG=b:62640322 BRANCH=none TEST=manaully test on scarlet and kevin: S0->S3->S0 and S0->S3->S5->G3->S5->S3->S0 work. Change-Id: I70cdcbaba046bfab4fe832eca58f30524e99e6de Reviewed-on: https://chromium-review.googlesource.com/540783 Commit-Ready: Philip Chen <philipchen@chromium.org> Tested-by: Philip Chen <philipchen@chromium.org> Reviewed-by: Aseda Aboagye <aaboagye@chromium.org> Reviewed-by: Shawn N <shawnn@chromium.org>
-rw-r--r--power/rk3399.c183
1 files changed, 107 insertions, 76 deletions
diff --git a/power/rk3399.c b/power/rk3399.c
index b5e9bdd1ee..4f211d78e4 100644
--- a/power/rk3399.c
+++ b/power/rk3399.c
@@ -52,6 +52,83 @@
#define CHARGER_INITIALIZED_DELAY_MS 100
#define CHARGER_INITIALIZED_TRIES 40
+/* Data structure for a GPIO operation for power sequencing */
+struct power_seq_op {
+ /* enum gpio_signal in 8 bits */
+ uint8_t signal;
+ uint8_t level;
+ /* Number of milliseconds to delay after setting signal to level */
+ uint8_t delay;
+};
+BUILD_ASSERT(GPIO_COUNT < 256);
+
+/*
+ * This is the power sequence for POWER_S5S3.
+ * The entries in the table are handled sequentially from the top
+ * to the bottom.
+ */
+static const struct power_seq_op s5s3_power_seq[] = {
+ { GPIO_PPVAR_LOGIC_EN, 1, 0 },
+ { GPIO_PP900_AP_EN, 1, 0 },
+ { GPIO_PP900_PCIE_EN, 1, 2 },
+#if CONFIG_CHIPSET_POWER_SEQ_VERSION == 0
+ { GPIO_PP900_PMU_EN, 1, 0 },
+ { GPIO_PP900_PLL_EN, 1, 0 },
+#endif
+ { GPIO_PP900_USB_EN, 1, 2 },
+ { GPIO_SYS_RST_L, 0, 0 },
+ { GPIO_PP1800_PMU_EN_L, 0, 2 },
+ { GPIO_LPDDR_PWR_EN, 1, 2 },
+ { GPIO_PP1800_USB_EN_L, 0, 2 },
+ { GPIO_PP3300_USB_EN_L, 0, 0 },
+ { GPIO_PP5000_EN, 1, 0 },
+ { GPIO_PP3300_TRACKPAD_EN_L, 0, 1 },
+ { GPIO_PP1800_LID_EN_L, 0, 0 },
+ { GPIO_PP1800_SIXAXIS_EN_L, 0, 2},
+ { GPIO_PP1800_SENSOR_EN_L, 0, 0},
+};
+
+/* The power sequence for POWER_S3S0 */
+static const struct power_seq_op s3s0_power_seq[] = {
+ { GPIO_PPVAR_CLOGIC_EN, 1, 2 },
+ { GPIO_PP900_DDRPLL_EN, 1, 2 },
+ { GPIO_PP1800_AP_AVDD_EN_L, 0, 2 },
+ { GPIO_AP_CORE_EN, 1, 2 },
+ { GPIO_PP1800_S0_EN_L, 0, 2 },
+ { GPIO_PP3300_S0_EN_L, 0, 0 },
+};
+
+/* The power sequence for POWER_S0S3 */
+static const struct power_seq_op s0s3_power_seq[] = {
+ { GPIO_PP3300_S0_EN_L, 1, 20 },
+ { GPIO_PP1800_S0_EN_L, 1, 1 },
+ { GPIO_AP_CORE_EN, 0, 20 },
+ { GPIO_PP1800_AP_AVDD_EN_L, 1, 1 },
+ { GPIO_PP900_DDRPLL_EN, 0, 1 },
+ { GPIO_PPVAR_CLOGIC_EN, 0, 0 },
+};
+
+/* The power sequence for POWER_S3S5 */
+static const struct power_seq_op s3s5_power_seq[] = {
+ { GPIO_PP1800_SENSOR_EN_L, 1, 0},
+ { GPIO_PP1800_SIXAXIS_EN_L, 1, 0},
+ { GPIO_PP1800_LID_EN_L, 1, 0 },
+ { GPIO_PP3300_TRACKPAD_EN_L, 1, 0 },
+ { GPIO_PP5000_EN, 0, 0 },
+ { GPIO_PP3300_USB_EN_L, 1, 20 },
+ { GPIO_PP1800_USB_EN_L, 1, 10 },
+ { GPIO_LPDDR_PWR_EN, 0, 20 },
+ { GPIO_PP1800_PMU_EN_L, 1, 2 },
+#if CONFIG_CHIPSET_POWER_SEQ_VERSION == 0
+ { GPIO_PP900_PLL_EN, 0, 0 },
+ { GPIO_PP900_PMU_EN, 0, 0 },
+#endif
+ { GPIO_PP900_USB_EN, 0, 6 },
+ { GPIO_PP900_PCIE_EN, 0, 0 },
+ { GPIO_PP900_AP_EN, 0, 0 },
+ { GPIO_PPVAR_LOGIC_EN, 0, 0 },
+};
+
static int forcing_shutdown;
void chipset_force_shutdown(void)
@@ -132,6 +209,31 @@ DECLARE_DEFERRED(force_shutdown);
} \
} while (sleep_remain > 0); \
} while (0)
+BUILD_ASSERT(POWER_S3S0 != 0);
+
+/**
+ * Step through the power sequence table and do corresponding GPIO operations.
+ *
+ * @param power_seq_ops The pointer to the power sequence table.
+ * @param op_count The number of entries of power_seq_ops.
+ * @return non-zero if suspend aborted during POWER_S0S3, 0 otherwise.
+ */
+static int power_seq_run(const struct power_seq_op *power_seq_ops, int op_count)
+{
+ int i;
+
+ for (i = 0; i < op_count; i++) {
+ gpio_set_level(power_seq_ops[i].signal,
+ power_seq_ops[i].level);
+ if (!power_seq_ops[i].delay)
+ continue;
+ if (power_seq_ops == s0s3_power_seq)
+ MSLEEP_CHECK_ABORTED_SUSPEND(power_seq_ops[i].delay);
+ else
+ msleep(power_seq_ops[i].delay);
+ }
+ return 0;
+}
enum power_state power_handle_state(enum power_state state)
{
@@ -208,40 +310,14 @@ enum power_state power_handle_state(enum power_state state)
return POWER_S5;
case POWER_S5S3:
- gpio_set_level(GPIO_PPVAR_LOGIC_EN, 1);
- gpio_set_level(GPIO_PP900_AP_EN, 1);
- gpio_set_level(GPIO_PP900_PCIE_EN, 1);
- msleep(2);
-#if CONFIG_CHIPSET_POWER_SEQ_VERSION == 0
- gpio_set_level(GPIO_PP900_PMU_EN, 1);
- gpio_set_level(GPIO_PP900_PLL_EN, 1);
-#endif
- gpio_set_level(GPIO_PP900_USB_EN, 1);
- msleep(2);
+ power_seq_run(s5s3_power_seq, ARRAY_SIZE(s5s3_power_seq));
/*
* Assert SYS_RST now, to be released in S3S0, to avoid
* resetting the TPM soon after power-on.
*/
- gpio_set_level(GPIO_SYS_RST_L, 0);
sys_reset_asserted = 1;
- gpio_set_level(GPIO_PP1800_PMU_EN_L, 0);
- msleep(2);
- gpio_set_level(GPIO_LPDDR_PWR_EN, 1);
- msleep(2);
- gpio_set_level(GPIO_PP1800_USB_EN_L, 0);
- msleep(2);
- gpio_set_level(GPIO_PP3300_USB_EN_L, 0);
- gpio_set_level(GPIO_PP5000_EN, 1);
- gpio_set_level(GPIO_PP3300_TRACKPAD_EN_L, 0);
- msleep(1);
- gpio_set_level(GPIO_PP1800_LID_EN_L, 0);
-
- gpio_set_level(GPIO_PP1800_SIXAXIS_EN_L, 0);
- msleep(2);
- gpio_set_level(GPIO_PP1800_SENSOR_EN_L, 0);
-
/*
* TODO: Consider ADC_PP900_AP / ADC_PP1200_LPDDR analog
* voltage levels for state transition.
@@ -258,17 +334,7 @@ enum power_state power_handle_state(enum power_state state)
return POWER_S3;
case POWER_S3S0:
- gpio_set_level(GPIO_PPVAR_CLOGIC_EN, 1);
- msleep(2);
- gpio_set_level(GPIO_PP900_DDRPLL_EN, 1);
- msleep(2);
- gpio_set_level(GPIO_PP1800_AP_AVDD_EN_L, 0);
- msleep(2);
- gpio_set_level(GPIO_AP_CORE_EN, 1);
- msleep(2);
- gpio_set_level(GPIO_PP1800_S0_EN_L, 0);
- msleep(2);
- gpio_set_level(GPIO_PP3300_S0_EN_L, 0);
+ power_seq_run(s3s0_power_seq, ARRAY_SIZE(s3s0_power_seq));
/* Release SYS_RST if we came from S5 */
if (sys_reset_asserted) {
@@ -300,22 +366,8 @@ enum power_state power_handle_state(enum power_state state)
hook_notify(HOOK_CHIPSET_SUSPEND);
MSLEEP_CHECK_ABORTED_SUSPEND(20);
- gpio_set_level(GPIO_PP3300_S0_EN_L, 1);
- MSLEEP_CHECK_ABORTED_SUSPEND(20);
-
- gpio_set_level(GPIO_PP1800_S0_EN_L, 1);
- MSLEEP_CHECK_ABORTED_SUSPEND(1);
-
- gpio_set_level(GPIO_AP_CORE_EN, 0);
- MSLEEP_CHECK_ABORTED_SUSPEND(20);
-
- gpio_set_level(GPIO_PP1800_AP_AVDD_EN_L, 1);
- MSLEEP_CHECK_ABORTED_SUSPEND(1);
-
- gpio_set_level(GPIO_PP900_DDRPLL_EN, 0);
- MSLEEP_CHECK_ABORTED_SUSPEND(1);
-
- gpio_set_level(GPIO_PPVAR_CLOGIC_EN, 0);
+ if (power_seq_run(s0s3_power_seq, ARRAY_SIZE(s0s3_power_seq)))
+ return POWER_S3S0;
/*
* Enable idle task deep sleep. Allow the low power idle task
@@ -338,28 +390,7 @@ enum power_state power_handle_state(enum power_state state)
/* Call hooks before we remove power rails */
hook_notify(HOOK_CHIPSET_SHUTDOWN);
- gpio_set_level(GPIO_PP1800_SENSOR_EN_L, 1);
- gpio_set_level(GPIO_PP1800_SIXAXIS_EN_L, 1);
- gpio_set_level(GPIO_PP1800_LID_EN_L, 1);
- gpio_set_level(GPIO_PP3300_TRACKPAD_EN_L, 1);
- gpio_set_level(GPIO_PP5000_EN, 0);
- gpio_set_level(GPIO_PP3300_USB_EN_L, 1);
- msleep(20);
- gpio_set_level(GPIO_PP1800_USB_EN_L, 1);
- msleep(10);
- gpio_set_level(GPIO_LPDDR_PWR_EN, 0);
- msleep(20);
- gpio_set_level(GPIO_PP1800_PMU_EN_L, 1);
- msleep(2);
- gpio_set_level(GPIO_PP900_USB_EN, 0);
-#if CONFIG_CHIPSET_POWER_SEQ_VERSION == 0
- gpio_set_level(GPIO_PP900_PLL_EN, 0);
- gpio_set_level(GPIO_PP900_PMU_EN, 0);
-#endif
- msleep(6);
- gpio_set_level(GPIO_PP900_PCIE_EN, 0);
- gpio_set_level(GPIO_PP900_AP_EN, 0);
- gpio_set_level(GPIO_PPVAR_LOGIC_EN, 0);
+ power_seq_run(s3s5_power_seq, ARRAY_SIZE(s3s5_power_seq));
/* Start shutting down */
return POWER_S5;