summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Nematbakhsh <shawnn@chromium.org>2016-05-02 12:13:47 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-05-04 16:15:02 -0700
commit15ac27daa157ea0ec0ed717e373fb056c9479be6 (patch)
treecd8b35de705e100b57751875b8ab4557ea5d2b69
parent25a4f355e8d4ec67faa11241750868c721b448b5 (diff)
downloadchrome-ec-15ac27daa157ea0ec0ed717e373fb056c9479be6.tar.gz
rk3399: Set power state based on input signals
Use input signals to verify power state and determine power state after sysjump. BUG=chrome-os-partner:52878 BRANCH=None TEST=Manual on kevin. - Verify AP powers up on 'powerbtn'. - AP shuts down on 'apshutdown'. - AP re-powers / resets on 'powerbtn' + 'apreset'. - AP doesn't shutdown on 'sysjump rw' while in S0. Change-Id: Id24feb0f8490aa7cb73c46178085ff2e46f8d0a6 Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/341704 Commit-Ready: Shawn N <shawnn@chromium.org> Tested-by: Shawn N <shawnn@chromium.org> Reviewed-by: David Schneider <dnschneid@chromium.org> Reviewed-by: Shawn N <shawnn@chromium.org>
-rw-r--r--board/kevin/board.c9
-rw-r--r--board/kevin/board.h7
-rw-r--r--board/kevin/gpio.inc18
-rw-r--r--power/rk3399.c58
4 files changed, 73 insertions, 19 deletions
diff --git a/board/kevin/board.c b/board/kevin/board.c
index bd48fec0d6..538c91651f 100644
--- a/board/kevin/board.c
+++ b/board/kevin/board.c
@@ -86,6 +86,15 @@ const struct i2c_port_t i2c_ports[] = {
};
const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
+/* power signal list. Must match order of enum power_signal. */
+const struct power_signal_info power_signal_list[] = {
+ {GPIO_PP5000_PG, 1, "PP5000_PWR_GOOD"},
+ {GPIO_TPS65261_PG, 1, "SYS_PWR_GOOD"},
+ {GPIO_AP_CORE_PG, 1, "AP_PWR_GOOD"},
+ {GPIO_AP_EC_S3_S0_L, 0, "SUSPEND_DEASSERTED"},
+};
+BUILD_ASSERT(ARRAY_SIZE(power_signal_list) == POWER_SIGNAL_COUNT);
+
/******************************************************************************/
/* Wake-up pins for hibernate */
const enum gpio_signal hibernate_wake_pins[] = {
diff --git a/board/kevin/board.h b/board/kevin/board.h
index a450316f30..c9827a9285 100644
--- a/board/kevin/board.h
+++ b/board/kevin/board.h
@@ -122,8 +122,13 @@ enum pwm_channel {
/* power signal definitions */
enum power_signal {
+ PP5000_PWR_GOOD = 0,
+ SYS_PWR_GOOD,
+ AP_PWR_GOOD,
+ SUSPEND_DEASSERTED,
+
/* Number of signals */
- POWER_SIGNAL_COUNT = 0
+ POWER_SIGNAL_COUNT,
};
#include "gpio_signal.h"
diff --git a/board/kevin/gpio.inc b/board/kevin/gpio.inc
index d93b4d92d6..b31cc35f87 100644
--- a/board/kevin/gpio.inc
+++ b/board/kevin/gpio.inc
@@ -12,7 +12,6 @@
GPIO_INT(WP_L, PIN(9, 3), GPIO_INT_BOTH, switch_interrupt)
-/* TODO: May be floating when SOC unpowered */
GPIO_INT(SHI_CS_L, PIN(5, 3), GPIO_INT_FALLING, shi_cs_event)
GPIO_INT(USB_C0_PD_INT_L, PIN(6, 0), GPIO_INT_FALLING | GPIO_PULL_UP,
tcpc_alert_event)
@@ -27,7 +26,15 @@ GPIO_INT(POWER_BUTTON_L, PIN(0, 4), GPIO_INT_BOTH | GPIO_INPUT | GPIO_PULL_UP,
GPIO_INT(LID_OPEN, PIN(9, 7),
GPIO_INT_BOTH | GPIO_INPUT | GPIO_SEL_1P8V, lid_interrupt)
-/* TODO: Add power sequencing interrupt pins */
+GPIO_INT(PP5000_PG, PIN(7, 1),
+ GPIO_INT_BOTH | GPIO_INPUT | GPIO_PULL_UP, power_signal_interrupt)
+GPIO_INT(TPS65261_PG, PIN(7, 5),
+ GPIO_INT_BOTH | GPIO_INPUT | GPIO_PULL_UP, power_signal_interrupt)
+/* TODO: Remove PD in S3 for power savings */
+GPIO_INT(AP_EC_S3_S0_L, PIN(5, 4),
+ GPIO_INT_BOTH | GPIO_INPUT | GPIO_PULL_DOWN, power_signal_interrupt)
+GPIO_INT(AP_CORE_PG, PIN(6, 7),
+ GPIO_INT_BOTH | GPIO_INPUT | GPIO_PULL_UP, power_signal_interrupt)
/* VR EN */
GPIO(AP_CORE_EN, PIN(7, 2), GPIO_OUT_LOW)
@@ -58,12 +65,6 @@ GPIO(PP3300_USB_EN_L, PIN(3, 7), GPIO_OUT_HIGH)
GPIO(PP5000_EN, PIN(C, 6), GPIO_OUT_LOW)
-GPIO(PP5000_PG, PIN(7, 1), GPIO_INPUT | GPIO_PULL_UP)
-GPIO(TPS65261_PG, PIN(7, 5), GPIO_INPUT | GPIO_PULL_UP)
-/* TODO: May be floating when SOC unpowered */
-GPIO(AP_EC_S3_S0_L, PIN(5, 4), GPIO_INPUT)
-GPIO(AP_CORE_PG, PIN(6, 7), GPIO_INPUT | GPIO_PULL_UP)
-
/*
* I2C pins should be configured as inputs until I2C module is
* initialized. This will avoid driving the lines unintentionally.
@@ -110,7 +111,6 @@ GPIO(AP_OVERTEMP, PIN(7, 4), GPIO_INPUT)
GPIO(USB_A_CHARGE_EN, PIN(8, 4), GPIO_OUT_LOW)
GPIO(SPI_SENSOR_CS_L, PIN(9, 4), GPIO_OUT_HIGH)
-
GPIO(USB_C0_DISCHARGE, PIN(0, 3), GPIO_OUT_LOW)
GPIO(USB_C1_DISCHARGE, PIN(B, 1), GPIO_OUT_LOW)
/* SPIP_MOSI/SPIP_SCLK GPIOA3/A1 */
diff --git a/power/rk3399.c b/power/rk3399.c
index 81fff5c3a2..c374b78193 100644
--- a/power/rk3399.c
+++ b/power/rk3399.c
@@ -26,7 +26,19 @@
#define CPRINTS(format, args...) cprints(CC_CHIPSET, format, ## args)
/* Input state flags */
-/* TODO: Monitor input signals to determine AP power state */
+#define IN_PGOOD_PP5000 POWER_SIGNAL_MASK(PP5000_PWR_GOOD)
+#define IN_PGOOD_SYS POWER_SIGNAL_MASK(SYS_PWR_GOOD)
+#define IN_PGOOD_AP POWER_SIGNAL_MASK(AP_PWR_GOOD)
+#define IN_SUSPEND_DEASSERTED POWER_SIGNAL_MASK(SUSPEND_DEASSERTED)
+
+/* All always-on supplies */
+#define IN_PGOOD_ALWAYS_ON (IN_PGOOD_SYS)
+/* Rails requires for S3 */
+#define IN_PGOOD_S3 (IN_PGOOD_ALWAYS_ON | IN_PGOOD_PP5000)
+/* Rails required for S0 */
+#define IN_PGOOD_S0 (IN_PGOOD_S3 | IN_PGOOD_AP)
+/* All inputs in the right state for S0 */
+#define IN_ALL_S0 (IN_PGOOD_S0 | IN_SUSPEND_DEASSERTED)
static const struct power_signal_info power_control_outputs[] = {
{ GPIO_AP_CORE_EN, 1 },
@@ -83,20 +95,33 @@ void chipset_reset(int cold_reset)
gpio_set_level(GPIO_SYS_RST_L, 1);
}
-enum power_state power_chipset_init(void)
+static void chipset_force_g3(void)
{
int i;
const struct power_signal_info *output_signal;
- /* TODO: decode state after sysjump */
/* Force all signals to their G3 states */
CPRINTS("forcing G3");
for (i = 0; i < ARRAY_SIZE(power_control_outputs); ++i) {
output_signal = &power_control_outputs[i];
- gpio_set_level(output_signal->gpio, !output_signal->level);
+ gpio_set_level(output_signal->gpio,
+ !output_signal->level);
+ }
+}
+
+enum power_state power_chipset_init(void)
+{
+ if (system_jumped_to_this_image()) {
+ if ((power_get_signals() & IN_ALL_S0) == IN_ALL_S0) {
+ disable_sleep(SLEEP_MASK_AP_RUN);
+ CPRINTS("already in S0");
+ return POWER_S0;
+ }
+
+ chipset_force_g3();
+ wireless_set_state(WIRELESS_OFF);
}
- wireless_set_state(WIRELESS_OFF);
return POWER_G3;
}
@@ -113,13 +138,13 @@ enum power_state power_handle_state(enum power_state state)
return POWER_S5S3;
case POWER_S3:
- if (forcing_shutdown)
+ if (!power_has_signals(IN_PGOOD_S3) || forcing_shutdown)
return POWER_S3S5;
- else
+ else if (power_has_signals(IN_SUSPEND_DEASSERTED))
return POWER_S3S0;
case POWER_S0:
- if (forcing_shutdown)
+ if (!power_has_signals(IN_PGOOD_S0) || forcing_shutdown)
return POWER_S0S3;
break;
@@ -153,6 +178,15 @@ enum power_state power_handle_state(enum power_state state)
msleep(2);
gpio_set_level(GPIO_PP3300_TRACKPAD_EN_L, 0);
+ /*
+ * TODO: Consider ADC_PP900_AP / ADC_PP1200_LPDDR analog
+ * voltage levels for state transition.
+ */
+ if (power_wait_signals(IN_PGOOD_S3)) {
+ chipset_force_shutdown();
+ return POWER_S5;
+ }
+
/* Call hooks now that rails are up */
hook_notify(HOOK_CHIPSET_STARTUP);
/* Power up to next state */
@@ -176,6 +210,11 @@ enum power_state power_handle_state(enum power_state state)
gpio_set_level(GPIO_PP1800_LID_EN_L, 0);
gpio_set_level(GPIO_PP1800_SENSOR_EN_L, 0);
+ if (power_wait_signals(IN_PGOOD_S0)) {
+ chipset_force_shutdown();
+ return POWER_S3;
+ }
+
/* Enable wireless */
wireless_set_state(WIRELESS_ON);
@@ -218,7 +257,8 @@ enum power_state power_handle_state(enum power_state state)
case POWER_S5G3:
/* Initialize power signal outputs to default. */
- return power_chipset_init();
+ chipset_force_g3();
+ return POWER_G3;
}
return state;