diff options
author | Philip Chen <philipchen@google.com> | 2017-06-19 19:20:27 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-06-22 17:03:59 -0700 |
commit | 9e32694d1051ef0eb3b091e1b03563cfd538b1d7 (patch) | |
tree | 1fc741d906e997aa7f796f8c2c93d1e2fba4f475 /power | |
parent | b0dd82b39c57eab3a30923eb4a755172b9852f7e (diff) | |
download | chrome-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>
Diffstat (limited to 'power')
-rw-r--r-- | power/rk3399.c | 183 |
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; |