summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/power.h61
-rw-r--r--power/host_sleep.c143
-rw-r--r--power/intel_x86.c122
3 files changed, 204 insertions, 122 deletions
diff --git a/include/power.h b/include/power.h
index 8801250951..4a267ed8ad 100644
--- a/include/power.h
+++ b/include/power.h
@@ -278,6 +278,67 @@ __override_proto void power_board_handle_host_sleep_event(
*/
#define HOST_SLEEP_EVENT_DEFAULT_RESET 0
+enum sleep_notify_type {
+ SLEEP_NOTIFY_NONE,
+ SLEEP_NOTIFY_SUSPEND,
+ SLEEP_NOTIFY_RESUME,
+};
+
+/**
+ * Set the sleep notify
+ *
+ * It is called in power_chipset_handle_host_sleep_event(), to set the sleep
+ * notify. The sleep notify is assigned based on the host sleep state.
+ *
+ * @param notify The sleep notify to set.
+ */
+void sleep_set_notify(enum sleep_notify_type notify);
+
+/**
+ * Notify the given hook is the sleep notify is matched.
+ *
+ * @param check_state: The sleep notify to check.
+ * @param hook_id: The hook to notify.
+ */
+void sleep_notify_transition(int check_state, int hook_id);
+
+/**
+ * Called during the suspend transition, to increase the transition counter.
+ */
+void sleep_suspend_transition(void);
+
+/**
+ * Called during the resume transition, to increase the transition counter.
+ */
+void sleep_resume_transition(void);
+
+/**
+ * Start the suspend process.
+ *
+ * It is called in power_chipset_handle_host_sleep_event(), after it receives
+ * a host sleep event to hint that the suspend process starts.
+ *
+ * @param ctx Possible sleep parameters and return values, depending on state.
+ * @param callback Will be called if timed out, i.e. suspend hang.
+ */
+void sleep_start_suspend(struct host_sleep_event_context *ctx,
+ void (*callback)(void));
+
+/**
+ * Complete the resume process.
+ *
+ * It is called in power_chipset_handle_host_sleep_event(), after it receives
+ * a host sleep event to hint that the resume process completes.
+ *
+ * @param ctx Possible sleep parameters and return values, depending on state.
+ */
+void sleep_complete_resume(struct host_sleep_event_context *ctx);
+
+/**
+ * Reset the transition counter and timer.
+ */
+void sleep_reset_tracking(void);
+
#ifdef CONFIG_POWER_S0IX
/**
* Reset the sleep state reported by the host.
diff --git a/power/host_sleep.c b/power/host_sleep.c
index 673d421ca7..54a308d6c3 100644
--- a/power/host_sleep.c
+++ b/power/host_sleep.c
@@ -4,8 +4,14 @@
*/
#include "ec_commands.h"
+#include "hooks.h"
#include "host_command.h"
#include "power.h"
+#include "util.h"
+
+/* Console output macros */
+#define CPRINTS(format, args...) cprints(CC_CHIPSET, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_CHIPSET, format, ## args)
/* Track last reported sleep event */
static enum host_sleep_event host_sleep_state;
@@ -77,3 +83,140 @@ void power_set_host_sleep_state(enum host_sleep_event state)
host_sleep_state = state;
}
+#ifdef CONFIG_POWER_SLEEP_FAILURE_DETECTION
+/* Flag to notify listeners about suspend/resume events. */
+enum sleep_notify_type sleep_notify = SLEEP_NOTIFY_NONE;
+
+/*
+ * Note: the following sleep_ functions do not get called in the S3 path on
+ * Intel devices. On Intel devices, they are called in the S0ix path.
+ */
+void sleep_set_notify(enum sleep_notify_type notify)
+{
+ sleep_notify = notify;
+}
+
+void sleep_notify_transition(int check_state, int hook_id)
+{
+ if (sleep_notify != check_state)
+ return;
+
+ hook_notify(hook_id);
+ sleep_set_notify(SLEEP_NOTIFY_NONE);
+}
+
+static uint16_t sleep_signal_timeout;
+static uint32_t sleep_signal_transitions;
+static void (*sleep_timeout_callback)(void);
+
+static void sleep_transition_timeout(void);
+DECLARE_DEFERRED(sleep_transition_timeout);
+
+static void sleep_increment_transition(void)
+{
+ if ((sleep_signal_transitions & EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK) <
+ EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK)
+ sleep_signal_transitions += 1;
+}
+
+void sleep_suspend_transition(void)
+{
+ sleep_increment_transition();
+ hook_call_deferred(&sleep_transition_timeout_data, -1);
+}
+
+void sleep_resume_transition(void)
+{
+ sleep_increment_transition();
+
+ /*
+ * Start the timer again to ensure the AP doesn't get itself stuck in
+ * a state where it's no longer in a sleep state (S0ix/S3), but from
+ * the Linux perspective is still suspended. Perhaps a bug in the SoC-
+ * internal periodic housekeeping code might result in a situation
+ * like this.
+ */
+ if (sleep_signal_timeout)
+ hook_call_deferred(&sleep_transition_timeout_data,
+ (uint32_t)sleep_signal_timeout * 1000);
+}
+
+static void sleep_transition_timeout(void)
+{
+ /* Mark the timeout. */
+ sleep_signal_transitions |= EC_HOST_RESUME_SLEEP_TIMEOUT;
+ hook_call_deferred(&sleep_transition_timeout_data, -1);
+
+ /* Call the custom callback */
+ if (sleep_timeout_callback)
+ sleep_timeout_callback();
+}
+
+void sleep_start_suspend(struct host_sleep_event_context *ctx,
+ void (*callback)(void))
+{
+ uint16_t timeout = ctx->sleep_timeout_ms;
+
+ sleep_timeout_callback = callback;
+ sleep_signal_transitions = 0;
+
+ /* Use zero internally to indicate no timeout. */
+ if (timeout == EC_HOST_SLEEP_TIMEOUT_DEFAULT) {
+ timeout = CONFIG_SLEEP_TIMEOUT_MS;
+
+ } else if (timeout == EC_HOST_SLEEP_TIMEOUT_INFINITE) {
+ sleep_signal_timeout = 0;
+ return;
+ }
+
+ sleep_signal_timeout = timeout;
+ hook_call_deferred(&sleep_transition_timeout_data,
+ (uint32_t)timeout * 1000);
+}
+
+void sleep_complete_resume(struct host_sleep_event_context *ctx)
+{
+ hook_call_deferred(&sleep_transition_timeout_data, -1);
+ ctx->sleep_transitions = sleep_signal_transitions;
+}
+
+void sleep_reset_tracking(void)
+{
+ sleep_signal_transitions = 0;
+ sleep_signal_timeout = 0;
+ sleep_timeout_callback = NULL;
+}
+
+#else /* !CONFIG_POWER_SLEEP_FAILURE_DETECTION */
+
+/* No action */
+void sleep_set_notify(enum sleep_notify_type notify)
+{
+}
+
+void sleep_notify_transition(int check_state, int hook_id)
+{
+}
+
+void sleep_suspend_transition(void)
+{
+}
+
+void sleep_resume_transition(void)
+{
+}
+
+void sleep_start_suspend(struct host_sleep_event_context *ctx,
+ void (*callback)(void))
+{
+}
+
+void sleep_complete_resume(struct host_sleep_event_context *ctx)
+{
+}
+
+void sleep_reset_tracking(void)
+{
+}
+
+#endif /* CONFIG_POWER_SLEEP_FAILURE_DETECTION */
diff --git a/power/intel_x86.c b/power/intel_x86.c
index 4fdfbdfb9c..1fdf1b96ea 100644
--- a/power/intel_x86.c
+++ b/power/intel_x86.c
@@ -196,38 +196,10 @@ static void lpc_s0ix_hang_detected(void)
host_set_single_event(EC_HOST_EVENT_HANG_DETECT);
}
-enum sleep_notify_type {
- SLEEP_NOTIFY_NONE,
- SLEEP_NOTIFY_SUSPEND,
- SLEEP_NOTIFY_RESUME,
-};
-
-/* Flag to notify listeners about suspend/resume events. */
-enum sleep_notify_type sleep_notify = SLEEP_NOTIFY_NONE;
-
-/*
- * Note: the following sleep_ functions do not get called in the S3 path on
- * Intel devices. On Intel devices, they are called in the S0ix path.
- */
-static void sleep_set_notify(enum sleep_notify_type notify)
-{
- sleep_notify = notify;
-}
-
-static void sleep_notify_transition(int check_state, int hook_id)
-{
- if (sleep_notify != check_state)
- return;
-
- hook_notify(hook_id);
- sleep_set_notify(SLEEP_NOTIFY_NONE);
-}
-
static void handle_chipset_suspend(void)
{
/* Clear masks before any hooks are run for suspend. */
lpc_s0ix_suspend_clear_masks();
-
}
DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, handle_chipset_suspend, HOOK_PRIO_FIRST);
@@ -241,100 +213,6 @@ static void handle_chipset_reset(void)
}
DECLARE_HOOK(HOOK_CHIPSET_RESET, handle_chipset_reset, HOOK_PRIO_FIRST);
-#ifdef CONFIG_POWER_SLEEP_FAILURE_DETECTION
-
-static uint16_t sleep_signal_timeout;
-static uint32_t sleep_signal_transitions;
-static void (*sleep_timeout_callback)(void);
-
-static void sleep_transition_timeout(void);
-DECLARE_DEFERRED(sleep_transition_timeout);
-
-static void sleep_increment_transition(void)
-{
- if ((sleep_signal_transitions & EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK) <
- EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK)
- sleep_signal_transitions += 1;
-}
-
-static void sleep_suspend_transition(void)
-{
- sleep_increment_transition();
- hook_call_deferred(&sleep_transition_timeout_data, -1);
-}
-
-static void sleep_resume_transition(void)
-{
- sleep_increment_transition();
-
- /*
- * Start the timer again to ensure the AP doesn't get itself stuck in
- * a state where it's no longer in a sleep state (S0ix/S3), but from
- * the Linux perspective is still suspended. Perhaps a bug in the SoC-
- * internal periodic housekeeping code might result in a situation
- * like this.
- */
- if (sleep_signal_timeout)
- hook_call_deferred(&sleep_transition_timeout_data,
- (uint32_t)sleep_signal_timeout * 1000);
-}
-
-static void sleep_transition_timeout(void)
-{
- /* Mark the timeout. */
- sleep_signal_transitions |= EC_HOST_RESUME_SLEEP_TIMEOUT;
- hook_call_deferred(&sleep_transition_timeout_data, -1);
-
- /* Call the custom callback */
- if (sleep_timeout_callback)
- sleep_timeout_callback();
-}
-
-static void sleep_start_suspend(struct host_sleep_event_context *ctx,
- void (*callback)(void))
-{
- uint16_t timeout = ctx->sleep_timeout_ms;
-
- sleep_timeout_callback = callback;
- sleep_signal_transitions = 0;
-
- /* Use zero internally to indicate no timeout. */
- if (timeout == EC_HOST_SLEEP_TIMEOUT_DEFAULT) {
- timeout = CONFIG_SLEEP_TIMEOUT_MS;
-
- } else if (timeout == EC_HOST_SLEEP_TIMEOUT_INFINITE) {
- sleep_signal_timeout = 0;
- return;
- }
-
- sleep_signal_timeout = timeout;
- hook_call_deferred(&sleep_transition_timeout_data,
- (uint32_t)timeout * 1000);
-}
-
-static void sleep_complete_resume(struct host_sleep_event_context *ctx)
-{
- hook_call_deferred(&sleep_transition_timeout_data, -1);
- ctx->sleep_transitions = sleep_signal_transitions;
-}
-
-static void sleep_reset_tracking(void)
-{
- sleep_signal_transitions = 0;
- sleep_signal_timeout = 0;
- sleep_timeout_callback = NULL;
-}
-
-#else /* !CONFIG_POWER_SLEEP_FAILURE_DETECTION */
-
-#define sleep_suspend_transition()
-#define sleep_resume_transition()
-#define sleep_start_suspend(_ctx)
-#define sleep_complete_resume(_ctx)
-#define sleep_reset_tracking()
-
-#endif /* CONFIG_POWER_SLEEP_FAILURE_DETECTION */
-
void power_reset_host_sleep_state(void)
{
power_set_host_sleep_state(HOST_SLEEP_EVENT_DEFAULT_RESET);