summaryrefslogtreecommitdiff
path: root/power
diff options
context:
space:
mode:
Diffstat (limited to 'power')
-rw-r--r--power/sc7180.c103
1 files changed, 98 insertions, 5 deletions
diff --git a/power/sc7180.c b/power/sc7180.c
index d31728bfc7..fe093ad535 100644
--- a/power/sc7180.c
+++ b/power/sc7180.c
@@ -785,6 +785,61 @@ static inline int chipset_get_sleep_signal(void)
return fake_suspend;
}
+static void suspend_hang_detected(void)
+{
+ CPRINTS("Warning: Detected sleep hang! Waking host up!");
+ host_set_single_event(EC_HOST_EVENT_HANG_DETECT);
+}
+
+static void power_reset_host_sleep_state(void)
+{
+ power_set_host_sleep_state(HOST_SLEEP_EVENT_DEFAULT_RESET);
+ sleep_reset_tracking();
+ power_chipset_handle_host_sleep_event(HOST_SLEEP_EVENT_DEFAULT_RESET,
+ NULL);
+}
+
+static void handle_chipset_reset(void)
+{
+ if (chipset_in_state(CHIPSET_STATE_STANDBY)) {
+ CPRINTS("Chipset reset: exit s3");
+ power_reset_host_sleep_state();
+ task_wake(TASK_ID_CHIPSET);
+ }
+}
+DECLARE_HOOK(HOOK_CHIPSET_RESET, handle_chipset_reset, HOOK_PRIO_FIRST);
+
+__override void power_chipset_handle_host_sleep_event(
+ enum host_sleep_event state,
+ struct host_sleep_event_context *ctx)
+{
+ CPRINTS("Handle sleep: %d", state);
+
+ if (state == HOST_SLEEP_EVENT_S3_SUSPEND) {
+ /*
+ * Indicate to power state machine that a new host event for
+ * S3 suspend has been received and so chipset suspend
+ * notification needs to be sent to listeners.
+ */
+ sleep_set_notify(SLEEP_NOTIFY_SUSPEND);
+ sleep_start_suspend(ctx, suspend_hang_detected);
+ power_signal_enable_interrupt(GPIO_AP_SUSPEND);
+
+ } else if (state == HOST_SLEEP_EVENT_S3_RESUME) {
+ /*
+ * Wake up chipset task and indicate to power state machine that
+ * listeners need to be notified of chipset resume.
+ */
+ sleep_set_notify(SLEEP_NOTIFY_RESUME);
+ task_wake(TASK_ID_CHIPSET);
+ power_signal_disable_interrupt(GPIO_AP_SUSPEND);
+ sleep_complete_resume(ctx);
+
+ } else if (state == HOST_SLEEP_EVENT_DEFAULT_RESET) {
+ power_signal_disable_interrupt(GPIO_AP_SUSPEND);
+ }
+}
+
/**
* Power handler for steady states
*
@@ -844,6 +899,12 @@ enum power_state power_handle_state(enum power_state state)
/* Call hooks now that AP is running */
hook_notify(HOOK_CHIPSET_STARTUP);
+
+ /*
+ * Clearing the sleep failure detection tracking on the path
+ * to S0 to handle any reset conditions.
+ */
+ power_reset_host_sleep_state();
return POWER_S3;
case POWER_S3:
@@ -863,24 +924,41 @@ enum power_state power_handle_state(enum power_state state)
* AP has woken up and it deasserts the suspend signal;
* go to S0.
*
- * TODO(b/148149387): Add the hang detection that waits for a
- * host event before transits the state. It prevents changing
- * the state for modem paging.
+ * In S0, it will wait for a host event and then trigger the
+ * RESUME hook.
*/
if (!chipset_get_sleep_signal())
return POWER_S3S0;
break;
case POWER_S3S0:
+#ifdef CONFIG_CHIPSET_RESUME_INIT_HOOK
+ /*
+ * Notify the RESUME_INIT hooks, i.e. enabling SPI driver
+ * to receive host commands/events. The normal RESUME hook
+ * will be notified later, after receive a host resume event.
+ */
+ hook_notify(HOOK_CHIPSET_RESUME_INIT);
+#else
hook_notify(HOOK_CHIPSET_RESUME);
+#endif
+ sleep_resume_transition();
disable_sleep(SLEEP_MASK_AP_RUN);
return POWER_S0;
case POWER_S0:
shutdown_from_s0 = check_for_power_off_event();
- if (shutdown_from_s0 || chipset_get_sleep_signal())
+ if (shutdown_from_s0) {
return POWER_S0S3;
+ } else if (power_get_host_sleep_state()
+ == HOST_SLEEP_EVENT_S3_SUSPEND &&
+ chipset_get_sleep_signal()) {
+ return POWER_S0S3;
+ }
+ /* When receive the host event, trigger the RESUME hook. */
+ sleep_notify_transition(SLEEP_NOTIFY_RESUME,
+ HOOK_CHIPSET_RESUME);
break;
case POWER_S0S3:
@@ -891,8 +969,23 @@ enum power_state power_handle_state(enum power_state state)
if (power_button_was_pressed)
timer_cancel(TASK_ID_CHIPSET);
- /* Call hooks here since we don't know it prior to AP suspend */
+#ifdef CONFIG_CHIPSET_RESUME_INIT_HOOK
+ /*
+ * Pair with the HOOK_CHIPSET_RESUME_INIT, i.e. disabling SPI
+ * driver, by notifying the SUSPEND_COMPLETE hook. The normal
+ * SUSPEND hook will be notified afterward.
+ */
+ hook_notify(HOOK_CHIPSET_SUSPEND_COMPLETE);
+#else
hook_notify(HOOK_CHIPSET_SUSPEND);
+#endif
+ /*
+ * Call SUSPEND hooks only if we haven't notified listeners of
+ * S3 suspend.
+ */
+ sleep_notify_transition(SLEEP_NOTIFY_SUSPEND,
+ HOOK_CHIPSET_SUSPEND);
+ sleep_suspend_transition();
enable_sleep(SLEEP_MASK_AP_RUN);
return POWER_S3;