summaryrefslogtreecommitdiff
path: root/zephyr/subsys
diff options
context:
space:
mode:
Diffstat (limited to 'zephyr/subsys')
-rw-r--r--zephyr/subsys/Kconfig2
-rw-r--r--zephyr/subsys/ap_pwrseq/CMakeLists.txt5
-rw-r--r--zephyr/subsys/ap_pwrseq/Kconfig15
-rw-r--r--zephyr/subsys/ap_pwrseq/ap_events.c5
-rw-r--r--zephyr/subsys/ap_pwrseq/ap_power_interface.c29
-rw-r--r--zephyr/subsys/ap_pwrseq/include/ap_power_host_sleep.h19
-rw-r--r--zephyr/subsys/ap_pwrseq/include/ap_power_override_functions.h6
-rw-r--r--zephyr/subsys/ap_pwrseq/include/power_signals.h32
-rw-r--r--zephyr/subsys/ap_pwrseq/include/signal_adc.h12
-rw-r--r--zephyr/subsys/ap_pwrseq/include/signal_gpio.h12
-rw-r--r--zephyr/subsys/ap_pwrseq/include/signal_vw.h12
-rw-r--r--zephyr/subsys/ap_pwrseq/include/x86_common_pwrseq.h7
-rw-r--r--zephyr/subsys/ap_pwrseq/include/x86_non_dsx_common_pwrseq_sm_handler.h10
-rw-r--r--zephyr/subsys/ap_pwrseq/include/x86_power_signals.h77
-rw-r--r--zephyr/subsys/ap_pwrseq/power_host_sleep.c49
-rw-r--r--zephyr/subsys/ap_pwrseq/power_signals.c68
-rw-r--r--zephyr/subsys/ap_pwrseq/signal_adc.c106
-rw-r--r--zephyr/subsys/ap_pwrseq/signal_gpio.c66
-rw-r--r--zephyr/subsys/ap_pwrseq/signal_vw.c132
-rw-r--r--zephyr/subsys/ap_pwrseq/x86_non_dsx_adlp_pwrseq_sm.c24
-rw-r--r--zephyr/subsys/ap_pwrseq/x86_non_dsx_chipset_power_state.c42
-rw-r--r--zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_console.c32
-rw-r--r--zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_host_command.c68
-rw-r--r--zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_host_sleep.c179
-rw-r--r--zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_sm_handler.c205
-rw-r--r--zephyr/subsys/ap_pwrseq/x86_non_dsx_mtl_pwrseq_sm.c6
26 files changed, 816 insertions, 404 deletions
diff --git a/zephyr/subsys/Kconfig b/zephyr/subsys/Kconfig
index f35a942afc..48011312d5 100644
--- a/zephyr/subsys/Kconfig
+++ b/zephyr/subsys/Kconfig
@@ -1,4 +1,4 @@
-# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Copyright 2022 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/zephyr/subsys/ap_pwrseq/CMakeLists.txt b/zephyr/subsys/ap_pwrseq/CMakeLists.txt
index 30edfae4dd..0a77bc821d 100644
--- a/zephyr/subsys/ap_pwrseq/CMakeLists.txt
+++ b/zephyr/subsys/ap_pwrseq/CMakeLists.txt
@@ -13,9 +13,10 @@ zephyr_library_sources_ifdef(CONFIG_AP_PWRSEQ
signal_adc.c
)
zephyr_library_sources_ifdef(CONFIG_X86_NON_DSX_PWRSEQ
- x86_non_dsx_common_pwrseq_sm_handler.c)
-zephyr_library_sources_ifdef(CONFIG_X86_NON_DSX_PWRSEQ
+ x86_non_dsx_common_pwrseq_sm_handler.c
x86_non_dsx_chipset_power_state.c)
+zephyr_library_sources_ifdef(CONFIG_AP_PWRSEQ_S0IX_ERROR_RECOVERY
+ x86_non_dsx_common_pwrseq_host_sleep.c)
zephyr_library_sources_ifdef(CONFIG_X86_NON_DSX_PWRSEQ_CONSOLE
x86_non_dsx_common_pwrseq_console.c)
zephyr_library_sources_ifdef(CONFIG_X86_NON_DSX_PWRSEQ_HOST_CMD
diff --git a/zephyr/subsys/ap_pwrseq/Kconfig b/zephyr/subsys/ap_pwrseq/Kconfig
index 6f39906bf2..677bca7c6d 100644
--- a/zephyr/subsys/ap_pwrseq/Kconfig
+++ b/zephyr/subsys/ap_pwrseq/Kconfig
@@ -1,16 +1,19 @@
-# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Copyright 2022 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
menuconfig AP_PWRSEQ
bool "AP Power sequencing support"
select HAS_TASK_POWERBTN
+ select GPIO_GET_CONFIG
help
Enables AP power sequencing support with
embedded controller. This includes normal shutdown, critical
shutdown and reset handling.
Enabling this automatically enables HAS_TASK_POWERBTN since this task
is required to handle power button pressed/released by user.
+ Enabling this also enables retrieving the GPIO config feature
+ so that the value of output GPIOs can be determined.
if AP_PWRSEQ
@@ -104,4 +107,14 @@ config AP_PWRSEQ_S0IX
required, AP_PWRSEQ_HOST_SLEEP for host sleep event handling is
enabled.
+config AP_PWRSEQ_S0IX_ERROR_RECOVERY
+ bool "Detect failure to enter or exit Sleep state"
+ depends on AP_PWRSEQ_HOST_SLEEP
+ help
+ Enables detection of the AP failing to go to sleep, perhaps due to a
+ bug in the internal SoC periodic housekeeping code.
+
+ Failure information is reported via the EC_CMD_HOST_SLEEP_EVENT host
+ command.
+
endif
diff --git a/zephyr/subsys/ap_pwrseq/ap_events.c b/zephyr/subsys/ap_pwrseq/ap_events.c
index d5b78c2c33..0d99c0fe36 100644
--- a/zephyr/subsys/ap_pwrseq/ap_events.c
+++ b/zephyr/subsys/ap_pwrseq/ap_events.c
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -71,7 +71,8 @@ void ap_power_ev_send_callbacks(enum ap_power_events event)
return;
}
data.event = event;
- SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&callbacks, cb, tmp, node) {
+ SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&callbacks, cb, tmp, node)
+ {
if (cb->events & event) {
cb->handler(cb, data);
}
diff --git a/zephyr/subsys/ap_pwrseq/ap_power_interface.c b/zephyr/subsys/ap_pwrseq/ap_power_interface.c
index d6dc352033..1461ed139b 100644
--- a/zephyr/subsys/ap_pwrseq/ap_power_interface.c
+++ b/zephyr/subsys/ap_pwrseq/ap_power_interface.c
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -6,12 +6,17 @@
#include <ap_power/ap_power_interface.h>
#include <x86_non_dsx_common_pwrseq_sm_handler.h>
-bool ap_power_in_state(
- enum ap_power_state_mask state_mask)
+LOG_MODULE_DECLARE(ap_pwrseq, CONFIG_AP_PWRSEQ_LOG_LEVEL);
+
+bool ap_power_in_state(enum ap_power_state_mask state_mask)
{
int need_mask = 0;
switch (pwr_sm_get_state()) {
+ case SYS_POWER_STATE_UNINIT:
+ LOG_WRN("%s: init not yet complete; AP state is unknown",
+ __func__);
+ return false;
case SYS_POWER_STATE_G3:
need_mask = AP_POWER_STATE_HARD_OFF;
break;
@@ -21,16 +26,14 @@ bool ap_power_in_state(
* In between hard and soft off states. Match only if caller
* will accept both.
*/
- need_mask = AP_POWER_STATE_HARD_OFF |
- AP_POWER_STATE_SOFT_OFF;
+ need_mask = AP_POWER_STATE_HARD_OFF | AP_POWER_STATE_SOFT_OFF;
break;
case SYS_POWER_STATE_S5:
need_mask = AP_POWER_STATE_SOFT_OFF;
break;
case SYS_POWER_STATE_S5S4:
case SYS_POWER_STATE_S4S5:
- need_mask = AP_POWER_STATE_SOFT_OFF |
- AP_POWER_STATE_SUSPEND;
+ need_mask = AP_POWER_STATE_SOFT_OFF | AP_POWER_STATE_SUSPEND;
break;
case SYS_POWER_STATE_S4:
case SYS_POWER_STATE_S4S3:
@@ -40,8 +43,7 @@ bool ap_power_in_state(
break;
case SYS_POWER_STATE_S3S0:
case SYS_POWER_STATE_S0S3:
- need_mask = AP_POWER_STATE_SUSPEND |
- AP_POWER_STATE_ON;
+ need_mask = AP_POWER_STATE_SUSPEND | AP_POWER_STATE_ON;
break;
case SYS_POWER_STATE_S0:
need_mask = AP_POWER_STATE_ON;
@@ -60,10 +62,13 @@ bool ap_power_in_state(
return (state_mask & need_mask) == need_mask;
}
-bool ap_power_in_or_transitioning_to_state(
- enum ap_power_state_mask state_mask)
+bool ap_power_in_or_transitioning_to_state(enum ap_power_state_mask state_mask)
{
switch (pwr_sm_get_state()) {
+ case SYS_POWER_STATE_UNINIT:
+ LOG_WRN("%s: init not yet complete; AP state is unknown",
+ __func__);
+ return 0;
case SYS_POWER_STATE_G3:
case SYS_POWER_STATE_S5G3:
return state_mask & AP_POWER_STATE_HARD_OFF;
@@ -107,7 +112,7 @@ void ap_power_exit_hardoff(void)
power_state != SYS_POWER_STATE_S5G3 &&
power_state != SYS_POWER_STATE_S5)
return;
- request_exit_hardoff(true);
+ request_start_from_g3();
}
void ap_power_init_reset_log(void)
diff --git a/zephyr/subsys/ap_pwrseq/include/ap_power_host_sleep.h b/zephyr/subsys/ap_pwrseq/include/ap_power_host_sleep.h
index 9bee8af826..7251f96b76 100644
--- a/zephyr/subsys/ap_pwrseq/include/ap_power_host_sleep.h
+++ b/zephyr/subsys/ap_pwrseq/include/ap_power_host_sleep.h
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -22,8 +22,8 @@ void ap_power_set_active_wake_mask(void);
*
* @return 0 for success; -EINVAL if power state is not S3/S5/S0ix
*/
-int ap_power_get_lazy_wake_mask(
- enum power_states_ndsx state, host_event_t *mask);
+int ap_power_get_lazy_wake_mask(enum power_states_ndsx state,
+ host_event_t *mask);
#if CONFIG_AP_PWRSEQ_S0IX
/* For S0ix path, flag to notify sleep change */
@@ -56,4 +56,17 @@ enum ap_power_sleep_type ap_power_sleep_get_notify(void);
void ap_power_sleep_notify_transition(enum ap_power_sleep_type check_state);
#endif /* CONFIG_AP_PWRSEQ_S0IX */
+/*
+ * Get sleep timeout from host command context
+ */
+uint16_t host_get_sleep_timeout(void);
+
+/*
+ * Set sleep transitions for host command response
+ *
+ * @param val sleep transitions
+ *
+ */
+void host_set_sleep_transitions(uint32_t val);
+
#endif /* __AP_PWRSEQ_HOST_SLEEP_H */
diff --git a/zephyr/subsys/ap_pwrseq/include/ap_power_override_functions.h b/zephyr/subsys/ap_pwrseq/include/ap_power_override_functions.h
index 229bfb7e60..0d9195e5f2 100644
--- a/zephyr/subsys/ap_pwrseq/include/ap_power_override_functions.h
+++ b/zephyr/subsys/ap_pwrseq/include/ap_power_override_functions.h
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -75,7 +75,7 @@ bool board_ap_power_check_power_rails_enabled(void);
/**
* @brief macro to access configuration properties from DTS
*/
-#define AP_PWRSEQ_DT_VALUE(p) \
- DT_PROP(DT_COMPAT_GET_ANY_STATUS_OKAY(intel_ap_pwrseq), p) \
+#define AP_PWRSEQ_DT_VALUE(p) \
+ DT_PROP(DT_COMPAT_GET_ANY_STATUS_OKAY(intel_ap_pwrseq), p)
#endif /* __AP_PWRSEQ_AP_POWER_BOARD_FUNCTIONS_H__ */
diff --git a/zephyr/subsys/ap_pwrseq/include/power_signals.h b/zephyr/subsys/ap_pwrseq/include/power_signals.h
index 8755f1005a..5d3e97a52e 100644
--- a/zephyr/subsys/ap_pwrseq/include/power_signals.h
+++ b/zephyr/subsys/ap_pwrseq/include/power_signals.h
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -48,10 +48,10 @@
* included if that signal source is configured in the
* devicetree.
*/
-#define HAS_GPIO_SIGNALS DT_HAS_COMPAT_STATUS_OKAY(intel_ap_pwrseq_gpio)
-#define HAS_VW_SIGNALS DT_HAS_COMPAT_STATUS_OKAY(intel_ap_pwrseq_vw)
-#define HAS_EXT_SIGNALS DT_HAS_COMPAT_STATUS_OKAY(intel_ap_pwrseq_external)
-#define HAS_ADC_SIGNALS DT_HAS_COMPAT_STATUS_OKAY(intel_ap_pwrseq_adc)
+#define HAS_GPIO_SIGNALS DT_HAS_COMPAT_STATUS_OKAY(intel_ap_pwrseq_gpio)
+#define HAS_VW_SIGNALS DT_HAS_COMPAT_STATUS_OKAY(intel_ap_pwrseq_vw)
+#define HAS_EXT_SIGNALS DT_HAS_COMPAT_STATUS_OKAY(intel_ap_pwrseq_external)
+#define HAS_ADC_SIGNALS DT_HAS_COMPAT_STATUS_OKAY(intel_ap_pwrseq_adc)
/**
* @brief Definitions for AP power sequence signals.
@@ -62,11 +62,9 @@
/**
* @brief Generate the enum for this power signal.
*/
-#define PWR_SIGNAL_ENUM(id) \
- DT_STRING_UPPER_TOKEN(id, enum_name)
+#define PWR_SIGNAL_ENUM(id) DT_STRING_UPPER_TOKEN(id, enum_name)
-#define PWR_SIGNAL_ENUM_COMMA(id) \
- PWR_SIGNAL_ENUM(id),
+#define PWR_SIGNAL_ENUM_COMMA(id) PWR_SIGNAL_ENUM(id),
/**
* @brief Enum of all power signals.
*
@@ -78,11 +76,14 @@
* must be the same as in power_signals.c
*/
enum power_signal {
-DT_FOREACH_STATUS_OKAY(intel_ap_pwrseq_gpio, PWR_SIGNAL_ENUM_COMMA)
-DT_FOREACH_STATUS_OKAY(intel_ap_pwrseq_vw, PWR_SIGNAL_ENUM_COMMA)
-DT_FOREACH_STATUS_OKAY(intel_ap_pwrseq_external, PWR_SIGNAL_ENUM_COMMA)
-DT_FOREACH_STATUS_OKAY(intel_ap_pwrseq_adc, PWR_SIGNAL_ENUM_COMMA)
- POWER_SIGNAL_COUNT,
+ DT_FOREACH_STATUS_OKAY(intel_ap_pwrseq_gpio, PWR_SIGNAL_ENUM_COMMA)
+ DT_FOREACH_STATUS_OKAY(intel_ap_pwrseq_vw,
+ PWR_SIGNAL_ENUM_COMMA)
+ DT_FOREACH_STATUS_OKAY(intel_ap_pwrseq_external,
+ PWR_SIGNAL_ENUM_COMMA)
+ DT_FOREACH_STATUS_OKAY(intel_ap_pwrseq_adc,
+ PWR_SIGNAL_ENUM_COMMA)
+ POWER_SIGNAL_COUNT,
};
#undef PWR_SIGNAL_ENUM_COMMA
@@ -301,8 +302,7 @@ static inline bool power_signals_off(power_signal_mask_t want)
* @return negative If the signals did not match before the timeout.
*/
int power_wait_mask_signals_timeout(power_signal_mask_t want,
- power_signal_mask_t mask,
- int timeout);
+ power_signal_mask_t mask, int timeout);
/**
* @brief Wait until the selected power signals match, with timeout
diff --git a/zephyr/subsys/ap_pwrseq/include/signal_adc.h b/zephyr/subsys/ap_pwrseq/include/signal_adc.h
index e43e73e1a7..81c6a1edd4 100644
--- a/zephyr/subsys/ap_pwrseq/include/signal_adc.h
+++ b/zephyr/subsys/ap_pwrseq/include/signal_adc.h
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -6,7 +6,7 @@
#ifndef __AP_PWRSEQ_SIGNAL_ADC_H__
#define __AP_PWRSEQ_SIGNAL_ADC_H__
-#define PWR_SIG_TAG_ADC PWR_ADC_
+#define PWR_SIG_TAG_ADC PWR_ADC_
/*
* Generate enums for the analogue converters.
@@ -21,13 +21,13 @@
enum pwr_sig_adc {
#if HAS_ADC_SIGNALS
-DT_FOREACH_STATUS_OKAY(intel_ap_pwrseq_adc, PWR_ADC_ENUM)
+ DT_FOREACH_STATUS_OKAY(intel_ap_pwrseq_adc, PWR_ADC_ENUM)
#endif
- PWR_SIG_ADC_COUNT
+ PWR_SIG_ADC_COUNT
};
-#undef PWR_ADC_ENUM
-#undef TAG_ADC
+#undef PWR_ADC_ENUM
+#undef TAG_ADC
/**
* @brief Get the value of the ADC power signal.
diff --git a/zephyr/subsys/ap_pwrseq/include/signal_gpio.h b/zephyr/subsys/ap_pwrseq/include/signal_gpio.h
index e797f0c21f..7cdd4ec316 100644
--- a/zephyr/subsys/ap_pwrseq/include/signal_gpio.h
+++ b/zephyr/subsys/ap_pwrseq/include/signal_gpio.h
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -6,7 +6,7 @@
#ifndef __AP_PWRSEQ_SIGNAL_GPIO_H__
#define __AP_PWRSEQ_SIGNAL_GPIO_H__
-#define PWR_SIG_TAG_GPIO PWR_GPIO_
+#define PWR_SIG_TAG_GPIO PWR_GPIO_
/*
* Generate enums for the GPIOs.
@@ -21,13 +21,13 @@
enum pwr_sig_gpio {
#if HAS_GPIO_SIGNALS
-DT_FOREACH_STATUS_OKAY(intel_ap_pwrseq_gpio, PWR_GPIO_ENUM)
+ DT_FOREACH_STATUS_OKAY(intel_ap_pwrseq_gpio, PWR_GPIO_ENUM)
#endif
- PWR_SIG_GPIO_COUNT
+ PWR_SIG_GPIO_COUNT
};
-#undef PWR_GPIO_ENUM
-#undef TAG_GPIO
+#undef PWR_GPIO_ENUM
+#undef TAG_GPIO
/**
* @brief Get the value of the GPIO power signal.
diff --git a/zephyr/subsys/ap_pwrseq/include/signal_vw.h b/zephyr/subsys/ap_pwrseq/include/signal_vw.h
index d005daaa40..55ecc73e99 100644
--- a/zephyr/subsys/ap_pwrseq/include/signal_vw.h
+++ b/zephyr/subsys/ap_pwrseq/include/signal_vw.h
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -6,7 +6,7 @@
#ifndef __AP_PWRSEQ_SIGNAL_VW_H__
#define __AP_PWRSEQ_SIGNAL_VW_H__
-#define PWR_SIG_TAG_VW PWR_VW_
+#define PWR_SIG_TAG_VW PWR_VW_
/*
* Generate enums for the virtual wire signals.
@@ -21,13 +21,13 @@
enum pwr_sig_vw {
#if HAS_VW_SIGNALS
-DT_FOREACH_STATUS_OKAY(intel_ap_pwrseq_vw, PWR_VW_ENUM)
+ DT_FOREACH_STATUS_OKAY(intel_ap_pwrseq_vw, PWR_VW_ENUM)
#endif
- PWR_SIG_VW_COUNT
+ PWR_SIG_VW_COUNT
};
-#undef PWR_VW_ENUM
-#undef TAG_VW
+#undef PWR_VW_ENUM
+#undef TAG_VW
/**
* @brief Get the value of the virtual wire signal.
diff --git a/zephyr/subsys/ap_pwrseq/include/x86_common_pwrseq.h b/zephyr/subsys/ap_pwrseq/include/x86_common_pwrseq.h
index 526b0b6ca6..dcb2b3b968 100644
--- a/zephyr/subsys/ap_pwrseq/include/x86_common_pwrseq.h
+++ b/zephyr/subsys/ap_pwrseq/include/x86_common_pwrseq.h
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -16,11 +16,6 @@
struct pwrseq_context {
/* On power-on start boot up sequence */
enum power_states_ndsx power_state;
- /* Indicate should exit G3 power state or not */
- bool want_g3_exit;
- /* Indicate to exit G3 state or not with delay in ms*/
- uint32_t reboot_ap_at_g3_delay_ms;
-
};
#endif /* __X86_COMMON_PWRSEQ_H__ */
diff --git a/zephyr/subsys/ap_pwrseq/include/x86_non_dsx_common_pwrseq_sm_handler.h b/zephyr/subsys/ap_pwrseq/include/x86_non_dsx_common_pwrseq_sm_handler.h
index f874879f04..2320e61965 100644
--- a/zephyr/subsys/ap_pwrseq/include/x86_non_dsx_common_pwrseq_sm_handler.h
+++ b/zephyr/subsys/ap_pwrseq/include/x86_non_dsx_common_pwrseq_sm_handler.h
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -15,7 +15,7 @@
#include <ap_power_host_sleep.h>
#include <x86_common_pwrseq.h>
-#define DT_DRV_COMPAT intel_ap_pwrseq
+#define DT_DRV_COMPAT intel_ap_pwrseq
/* The wait time is ~150 msec, allow for safety margin. */
#define IN_PCH_SLP_SUS_WAIT_TIME_MS 250
@@ -23,11 +23,11 @@
enum power_states_ndsx chipset_pwr_sm_run(enum power_states_ndsx curr_state);
void init_chipset_pwr_seq_state(void);
enum power_states_ndsx chipset_pwr_seq_get_state(void);
-void request_exit_hardoff(bool should_exit);
+void request_start_from_g3(void);
enum power_states_ndsx pwr_sm_get_state(void);
-const char * const pwr_sm_get_state_name(enum power_states_ndsx state);
+const char *const pwr_sm_get_state_name(enum power_states_ndsx state);
void apshutdown(void);
void ap_pwrseq_handle_chipset_reset(void);
-void set_reboot_ap_at_g3_delay_seconds(uint32_t d_time);
+void set_start_from_g3_delay_seconds(uint32_t d_time);
#endif /* __X86_NON_DSX_COMMON_PWRSEQ_SM_HANDLER_H__ */
diff --git a/zephyr/subsys/ap_pwrseq/include/x86_power_signals.h b/zephyr/subsys/ap_pwrseq/include/x86_power_signals.h
index 4e1277dce7..7c7e25d951 100644
--- a/zephyr/subsys/ap_pwrseq/include/x86_power_signals.h
+++ b/zephyr/subsys/ap_pwrseq/include/x86_power_signals.h
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -8,11 +8,15 @@
#ifndef __X86_POWER_SIGNALS_H__
#define __X86_POWER_SIGNALS_H__
-#define IN_PCH_SLP_S0 POWER_SIGNAL_MASK(PWR_SLP_S0)
-#define IN_PCH_SLP_S3 POWER_SIGNAL_MASK(PWR_SLP_S3)
-#define IN_PCH_SLP_S4 POWER_SIGNAL_MASK(PWR_SLP_S4)
-#define IN_PCH_SLP_S5 POWER_SIGNAL_MASK(PWR_SLP_S5)
+#define IN_PCH_SLP_S0 POWER_SIGNAL_MASK(PWR_SLP_S0)
+#define IN_PCH_SLP_S3 POWER_SIGNAL_MASK(PWR_SLP_S3)
+#define IN_PCH_SLP_S4 POWER_SIGNAL_MASK(PWR_SLP_S4)
+#define IN_PCH_SLP_S5 POWER_SIGNAL_MASK(PWR_SLP_S5)
+/*
+ * Define the chipset specific power signal masks and values
+ * matching the AP state.
+ */
#if defined(CONFIG_AP_X86_INTEL_ADL)
/* Input state flags */
@@ -21,18 +25,31 @@
#define PWRSEQ_G3S5_UP_SIGNAL IN_PCH_SLP_SUS
#define PWRSEQ_G3S5_UP_VALUE 0
-#define MASK_ALL_POWER_GOOD \
- (POWER_SIGNAL_MASK(PWR_RSMRST) | \
- POWER_SIGNAL_MASK(PWR_ALL_SYS_PWRGD) | \
- POWER_SIGNAL_MASK(PWR_DSW_PWROK) | \
- POWER_SIGNAL_MASK(PWR_PG_PP1P05))
-#define MASK_S0 \
- (MASK_ALL_POWER_GOOD | \
- POWER_SIGNAL_MASK(PWR_SLP_S0) | \
- POWER_SIGNAL_MASK(PWR_SLP_S3) | \
- POWER_SIGNAL_MASK(PWR_SLP_SUS) | \
- POWER_SIGNAL_MASK(PWR_SLP_S4) | \
+#define MASK_ALL_POWER_GOOD \
+ (POWER_SIGNAL_MASK(PWR_RSMRST) | \
+ POWER_SIGNAL_MASK(PWR_ALL_SYS_PWRGD) | \
+ POWER_SIGNAL_MASK(PWR_DSW_PWROK) | POWER_SIGNAL_MASK(PWR_PG_PP1P05))
+
+#define MASK_VW_POWER \
+ (POWER_SIGNAL_MASK(PWR_RSMRST) | POWER_SIGNAL_MASK(PWR_DSW_PWROK) | \
+ POWER_SIGNAL_MASK(PWR_SLP_SUS))
+#define VALUE_VW_POWER \
+ (POWER_SIGNAL_MASK(PWR_RSMRST) | POWER_SIGNAL_MASK(PWR_DSW_PWROK))
+
+#define MASK_S0 \
+ (MASK_ALL_POWER_GOOD | POWER_SIGNAL_MASK(PWR_SLP_S0) | \
+ POWER_SIGNAL_MASK(PWR_SLP_S3) | POWER_SIGNAL_MASK(PWR_SLP_SUS) | \
+ POWER_SIGNAL_MASK(PWR_SLP_S4) | POWER_SIGNAL_MASK(PWR_SLP_S5))
+#define VALUE_S0 MASK_ALL_POWER_GOOD
+
+#define MASK_S3 MASK_S0
+#define VALUE_S3 (MASK_ALL_POWER_GOOD | POWER_SIGNAL_MASK(PWR_SLP_S3))
+
+#define MASK_S5 \
+ (POWER_SIGNAL_MASK(PWR_RSMRST) | POWER_SIGNAL_MASK(PWR_DSW_PWROK) | \
+ POWER_SIGNAL_MASK(PWR_SLP_S3) | POWER_SIGNAL_MASK(PWR_SLP_S4) | \
POWER_SIGNAL_MASK(PWR_SLP_S5))
+#define VALUE_S5 MASK_S5
#elif defined(CONFIG_AP_X86_INTEL_MTL)
@@ -41,21 +58,27 @@
#define PWRSEQ_G3S5_UP_VALUE IN_PGOOD_ALL_CORE
#define MASK_ALL_POWER_GOOD \
- (POWER_SIGNAL_MASK(PWR_RSMRST) | \
- POWER_SIGNAL_MASK(PWR_ALL_SYS_PWRGD))
-#define MASK_S0 \
- (MASK_ALL_POWER_GOOD | \
- POWER_SIGNAL_MASK(PWR_SLP_S0) | \
- POWER_SIGNAL_MASK(PWR_SLP_S3) | \
- POWER_SIGNAL_MASK(PWR_SLP_S4) | \
+ (POWER_SIGNAL_MASK(PWR_RSMRST) | POWER_SIGNAL_MASK(PWR_ALL_SYS_PWRGD))
+
+#define MASK_VW_POWER POWER_SIGNAL_MASK(PWR_RSMRST)
+#define VALUE_VW_POWER POWER_SIGNAL_MASK(PWR_RSMRST)
+
+#define MASK_S0 \
+ (MASK_ALL_POWER_GOOD | POWER_SIGNAL_MASK(PWR_SLP_S0) | \
+ POWER_SIGNAL_MASK(PWR_SLP_S3) | POWER_SIGNAL_MASK(PWR_SLP_S4) | \
POWER_SIGNAL_MASK(PWR_SLP_S5))
+#define VALUE_S0 MASK_ALL_POWER_GOOD
+
+#define MASK_S3 MASK_S0
+#define VALUE_S3 (MASK_ALL_POWER_GOOD | POWER_SIGNAL_MASK(PWR_SLP_S3))
+
+#define MASK_S5 \
+ (POWER_SIGNAL_MASK(PWR_RSMRST) | POWER_SIGNAL_MASK(PWR_SLP_S3) | \
+ POWER_SIGNAL_MASK(PWR_SLP_S4) | POWER_SIGNAL_MASK(PWR_SLP_S5))
+#define VALUE_S5 MASK_S5
#else
#warning("Input power signals state flags not defined");
#endif
-#define MASK_S5 \
- (MASK_ALL_POWER_GOOD | \
- POWER_SIGNAL_MASK(PWR_SLP_S5))
-
#endif /* __X86_POWER_SIGNALS_H__ */
diff --git a/zephyr/subsys/ap_pwrseq/power_host_sleep.c b/zephyr/subsys/ap_pwrseq/power_host_sleep.c
index ff512fa941..30025d21ea 100644
--- a/zephyr/subsys/ap_pwrseq/power_host_sleep.c
+++ b/zephyr/subsys/ap_pwrseq/power_host_sleep.c
@@ -1,9 +1,10 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <ap_power/ap_power_interface.h>
+#include <ap_power/ap_pwrseq.h>
#include <x86_non_dsx_common_pwrseq_sm_handler.h>
LOG_MODULE_DECLARE(ap_pwrseq, CONFIG_AP_PWRSEQ_LOG_LEVEL);
@@ -11,8 +12,9 @@ LOG_MODULE_DECLARE(ap_pwrseq, CONFIG_AP_PWRSEQ_LOG_LEVEL);
#if CONFIG_PLATFORM_EC_HOST_INTERFACE_ESPI
/* If host doesn't program S0ix lazy wake mask, use default S0ix mask */
-#define DEFAULT_WAKE_MASK_S0IX (EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN) | \
- EC_HOST_EVENT_MASK(EC_HOST_EVENT_MODE_CHANGE))
+#define DEFAULT_WAKE_MASK_S0IX \
+ (EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN) | \
+ EC_HOST_EVENT_MASK(EC_HOST_EVENT_MODE_CHANGE))
/*
* Set the wake mask according to the current power state:
@@ -33,7 +35,7 @@ void power_update_wake_mask(void)
if (state == SYS_POWER_STATE_S0)
wake_mask = 0;
else if (lpc_is_active_wm_set_by_host() ||
- ap_power_get_lazy_wake_mask(state, &wake_mask))
+ ap_power_get_lazy_wake_mask(state, &wake_mask))
return;
#if CONFIG_AP_PWRSEQ_S0IX
if ((state == SYS_POWER_STATE_S0ix) && (wake_mask == 0))
@@ -48,8 +50,8 @@ static void power_update_wake_mask_deferred(struct k_work *work)
power_update_wake_mask();
}
-static K_WORK_DELAYABLE_DEFINE(
- power_update_wake_mask_deferred_data, power_update_wake_mask_deferred);
+static K_WORK_DELAYABLE_DEFINE(power_update_wake_mask_deferred_data,
+ power_update_wake_mask_deferred);
void ap_power_set_active_wake_mask(void)
{
@@ -74,14 +76,16 @@ void ap_power_set_active_wake_mask(void)
* has changed again and the work is not processed, we should
* reschedule it.
*/
- rv = k_work_reschedule(
- &power_update_wake_mask_deferred_data, K_MSEC(5));
+ rv = k_work_reschedule(&power_update_wake_mask_deferred_data,
+ K_MSEC(5));
}
__ASSERT(rv >= 0, "Set wake mask work queue error");
}
#else /* CONFIG_PLATFORM_EC_HOST_INTERFACE_ESPI */
-static void ap_power_set_active_wake_mask(void) { }
+static void ap_power_set_active_wake_mask(void)
+{
+}
#endif /* CONFIG_PLATFORM_EC_HOST_INTERFACE_ESPI */
#if CONFIG_AP_PWRSEQ_S0IX
@@ -180,11 +184,14 @@ void ap_power_sleep_notify_transition(enum ap_power_sleep_type check_state)
#if CONFIG_AP_PWRSEQ_HOST_SLEEP
#define HOST_SLEEP_EVENT_DEFAULT_RESET 0
+static struct host_sleep_event_context *g_ctx;
+
void ap_power_reset_host_sleep_state(void)
{
power_set_host_sleep_state(HOST_SLEEP_EVENT_DEFAULT_RESET);
- ap_power_chipset_handle_host_sleep_event(
- HOST_SLEEP_EVENT_DEFAULT_RESET, NULL);
+ ap_power_ev_send_callbacks(AP_POWER_S0IX_RESET_TRACKING);
+ ap_power_chipset_handle_host_sleep_event(HOST_SLEEP_EVENT_DEFAULT_RESET,
+ NULL);
}
/* TODO: hook to reset event */
@@ -195,19 +202,21 @@ void ap_power_handle_chipset_reset(void)
}
void ap_power_chipset_handle_host_sleep_event(
- enum host_sleep_event state,
- struct host_sleep_event_context *ctx)
+ enum host_sleep_event state, struct host_sleep_event_context *ctx)
{
LOG_DBG("host sleep event = %d!", state);
+
+ g_ctx = ctx;
+
#if CONFIG_AP_PWRSEQ_S0IX
if (state == HOST_SLEEP_EVENT_S0IX_SUSPEND) {
-
/*
* Indicate to power state machine that a new host event for
* s0ix/s3 suspend has been received and so chipset suspend
* notification needs to be sent to listeners.
*/
ap_power_sleep_set_notify(AP_POWER_SLEEP_SUSPEND);
+ ap_power_ev_send_callbacks(AP_POWER_S0IX_SUSPEND_START);
power_signal_enable(PWR_SLP_S0);
} else if (state == HOST_SLEEP_EVENT_S0IX_RESUME) {
@@ -218,6 +227,7 @@ void ap_power_chipset_handle_host_sleep_event(
ap_power_sleep_set_notify(AP_POWER_SLEEP_RESUME);
power_s0ix_resume_restore_masks();
power_signal_disable(PWR_SLP_S0);
+ ap_power_ev_send_callbacks(AP_POWER_S0IX_RESUME_COMPLETE);
/*
* If the sleep signal timed out and never transitioned, then
@@ -231,6 +241,17 @@ void ap_power_chipset_handle_host_sleep_event(
power_signal_disable(PWR_SLP_S0);
}
#endif /* CONFIG_AP_PWRSEQ_S0IX */
+ ap_pwrseq_wake();
+}
+
+uint16_t host_get_sleep_timeout(void)
+{
+ return g_ctx->sleep_timeout_ms;
+}
+
+void host_set_sleep_transitions(uint32_t val)
+{
+ g_ctx->sleep_transitions = val;
}
#endif /* CONFIG_AP_PWRSEQ_HOST_SLEEP */
diff --git a/zephyr/subsys/ap_pwrseq/power_signals.c b/zephyr/subsys/ap_pwrseq/power_signals.c
index 135a0d9ac1..a02eef6e6b 100644
--- a/zephyr/subsys/ap_pwrseq/power_signals.c
+++ b/zephyr/subsys/ap_pwrseq/power_signals.c
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -8,6 +8,7 @@
#include <zephyr/logging/log.h>
#include <zephyr/sys/atomic.h>
+#include <ap_power/ap_pwrseq.h>
#include <power_signals.h>
#include "signal_gpio.h"
@@ -18,7 +19,7 @@ LOG_MODULE_DECLARE(ap_pwrseq, CONFIG_AP_PWRSEQ_LOG_LEVEL);
#if DT_HAS_COMPAT_STATUS_OKAY(intel_ap_pwrseq)
BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(intel_ap_pwrseq) == 1,
- "Only one node for intel_ap_pwrseq is allowed");
+ "Only one node for intel_ap_pwrseq is allowed");
#endif
BUILD_ASSERT(POWER_SIGNAL_COUNT <= 32, "Too many power signals");
@@ -41,49 +42,46 @@ struct ps_config {
#define TAG_PWR_ENUM(tag, name) DT_CAT(tag, name)
-#define PWR_ENUM(id, tag) \
- TAG_PWR_ENUM(tag, PWR_SIGNAL_ENUM(id))
+#define PWR_ENUM(id, tag) TAG_PWR_ENUM(tag, PWR_SIGNAL_ENUM(id))
-#define DBGNAME(id) \
- "(" DT_PROP(id, enum_name) ") " \
- DT_PROP(id, dbg_label)
+#define DBGNAME(id) "(" DT_PROP(id, enum_name) ") " DT_PROP(id, dbg_label)
-#define GEN_PS_ENTRY(id, src, tag) \
-{ \
- .debug_name = DBGNAME(id), \
- .source = src, \
- .src_enum = PWR_ENUM(id, tag), \
-},
-
-#define GEN_PS_ENTRY_NO_ENUM(id, src) \
-{ \
- .debug_name = DBGNAME(id), \
- .source = src, \
-},
+#define GEN_PS_ENTRY(id, src, tag) \
+ { \
+ .debug_name = DBGNAME(id), \
+ .source = src, \
+ .src_enum = PWR_ENUM(id, tag), \
+ },
+#define GEN_PS_ENTRY_NO_ENUM(id, src) \
+ { \
+ .debug_name = DBGNAME(id), \
+ .source = src, \
+ },
/*
* Generate the power signal configuration array.
*/
static const struct ps_config sig_config[] = {
-DT_FOREACH_STATUS_OKAY_VARGS(intel_ap_pwrseq_gpio, GEN_PS_ENTRY,
- PWR_SIG_SRC_GPIO, PWR_SIG_TAG_GPIO)
-DT_FOREACH_STATUS_OKAY_VARGS(intel_ap_pwrseq_vw, GEN_PS_ENTRY,
- PWR_SIG_SRC_VW, PWR_SIG_TAG_VW)
-DT_FOREACH_STATUS_OKAY_VARGS(intel_ap_pwrseq_external, GEN_PS_ENTRY_NO_ENUM,
- PWR_SIG_SRC_EXT)
-DT_FOREACH_STATUS_OKAY_VARGS(intel_ap_pwrseq_adc, GEN_PS_ENTRY,
- PWR_SIG_SRC_ADC, PWR_SIG_TAG_ADC)
+ DT_FOREACH_STATUS_OKAY_VARGS(intel_ap_pwrseq_gpio, GEN_PS_ENTRY,
+ PWR_SIG_SRC_GPIO, PWR_SIG_TAG_GPIO)
+ DT_FOREACH_STATUS_OKAY_VARGS(intel_ap_pwrseq_vw, GEN_PS_ENTRY,
+ PWR_SIG_SRC_VW, PWR_SIG_TAG_VW)
+ DT_FOREACH_STATUS_OKAY_VARGS(intel_ap_pwrseq_external,
+ GEN_PS_ENTRY_NO_ENUM,
+ PWR_SIG_SRC_EXT)
+ DT_FOREACH_STATUS_OKAY_VARGS(
+ intel_ap_pwrseq_adc, GEN_PS_ENTRY,
+ PWR_SIG_SRC_ADC, PWR_SIG_TAG_ADC)
};
-#define PWR_SIGNAL_POLLED(id) PWR_SIGNAL_ENUM(id),
+#define PWR_SIGNAL_POLLED(id) PWR_SIGNAL_ENUM(id),
/*
* List of power signals that need to be polled.
*/
-static const uint8_t polled_signals[] = {
-DT_FOREACH_STATUS_OKAY(intel_ap_pwrseq_external, PWR_SIGNAL_POLLED)
-};
+static const uint8_t polled_signals[] = { DT_FOREACH_STATUS_OKAY(
+ intel_ap_pwrseq_external, PWR_SIGNAL_POLLED) };
/*
* Bitmasks of power signals. A previous copy is held so that
@@ -112,7 +110,7 @@ static inline void check_debug(enum power_signal signal)
*/
if ((CONFIG_AP_PWRSEQ_LOG_LEVEL >= LOG_LEVEL_INF) &&
(debug_signals & POWER_SIGNAL_MASK(signal))) {
- bool value = atomic_test_bit(&power_signals, signal);
+ bool value = atomic_test_bit(&power_signals, signal);
if (value != atomic_test_bit(&prev_power_signals, signal)) {
LOG_INF("%s -> %d", power_signal_name(signal), value);
@@ -137,11 +135,11 @@ void power_signal_interrupt(enum power_signal signal, int value)
{
atomic_set_bit_to(&power_signals, signal, value);
check_debug(signal);
+ ap_pwrseq_wake();
}
int power_wait_mask_signals_timeout(power_signal_mask_t mask,
- power_signal_mask_t want,
- int timeout)
+ power_signal_mask_t want, int timeout)
{
if (mask == 0) {
return 0;
@@ -166,7 +164,7 @@ int power_signal_get(enum power_signal signal)
cp = &sig_config[signal];
switch (cp->source) {
default:
- return -EINVAL; /* should never happen */
+ return -EINVAL; /* should never happen */
#if HAS_GPIO_SIGNALS
case PWR_SIG_SRC_GPIO:
diff --git a/zephyr/subsys/ap_pwrseq/signal_adc.c b/zephyr/subsys/ap_pwrseq/signal_adc.c
index 4b8f0e0366..c23cd0d30a 100644
--- a/zephyr/subsys/ap_pwrseq/signal_adc.c
+++ b/zephyr/subsys/ap_pwrseq/signal_adc.c
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -11,7 +11,7 @@
#include <power_signals.h>
#include <signal_adc.h>
-#define MY_COMPAT intel_ap_pwrseq_adc
+#define MY_COMPAT intel_ap_pwrseq_adc
#if HAS_ADC_SIGNALS
@@ -26,74 +26,59 @@ struct adc_config {
enum power_signal signal;
};
-#define ADC_HIGH_DEV(id) DEVICE_DT_GET(DT_IO_CHANNELS_CTLR(id))
+#define ADC_HIGH_DEV(id) DEVICE_DT_GET(DT_IO_CHANNELS_CTLR(id))
-#define ADC_HIGH_CHAN(id) DT_IO_CHANNELS_INPUT(id)
+#define ADC_HIGH_CHAN(id) DT_IO_CHANNELS_INPUT(id)
-#define ADC_THRESH(id) DT_PROP(id, threshold_mv)
+#define ADC_THRESH(id) DT_PROP(id, threshold_mv)
-#define INIT_ADC_CONFIG(id) \
-{ \
- .dev_trig_high = DEVICE_DT_GET(DT_PHANDLE(id, trigger_high)), \
- .dev_trig_low = DEVICE_DT_GET(DT_PHANDLE(id, trigger_low)), \
- .adc_dev = ADC_HIGH_DEV(DT_PHANDLE(id, trigger_high)), \
- .adc_ch = ADC_HIGH_CHAN(DT_PHANDLE(id, trigger_high)), \
- .threshold = ADC_THRESH(DT_PHANDLE(id, trigger_high)), \
- .signal = PWR_SIGNAL_ENUM(id), \
-},
+#define INIT_ADC_CONFIG(id) \
+ { \
+ .dev_trig_high = DEVICE_DT_GET(DT_PHANDLE(id, trigger_high)), \
+ .dev_trig_low = DEVICE_DT_GET(DT_PHANDLE(id, trigger_low)), \
+ .adc_dev = ADC_HIGH_DEV(DT_PHANDLE(id, trigger_high)), \
+ .adc_ch = ADC_HIGH_CHAN(DT_PHANDLE(id, trigger_high)), \
+ .threshold = ADC_THRESH(DT_PHANDLE(id, trigger_high)), \
+ .signal = PWR_SIGNAL_ENUM(id), \
+ },
-static const struct adc_config config[] = {
-DT_FOREACH_STATUS_OKAY(MY_COMPAT, INIT_ADC_CONFIG)
-};
+static const struct adc_config config[] = { DT_FOREACH_STATUS_OKAY(
+ MY_COMPAT, INIT_ADC_CONFIG) };
/*
* Bit allocations for atomic state
*/
-enum {
- ADC_BIT_VALUE = 0,
- ADC_BIT_LOW_ENABLED = 1,
- ADC_BIT_HIGH_ENABLED = 2
-};
+enum { ADC_BIT_VALUE = 0, ADC_BIT_LOW_ENABLED = 1, ADC_BIT_HIGH_ENABLED = 2 };
atomic_t adc_state[ARRAY_SIZE(config)];
-static void set_trigger(const struct device *dev,
- atomic_t *state,
- int bit,
+static void set_trigger(const struct device *dev, atomic_t *state, int bit,
bool enable)
{
/*
* Only enable or disable if the trigger is not
* already enabled or disabled.
*/
- if (enable
- ? !atomic_test_and_set_bit(state, bit)
- : atomic_test_and_clear_bit(state, bit)) {
+ if (enable ? !atomic_test_and_set_bit(state, bit) :
+ atomic_test_and_clear_bit(state, bit)) {
struct sensor_value val;
val.val1 = enable;
- sensor_attr_set(dev,
- SENSOR_CHAN_VOLTAGE,
- SENSOR_ATTR_ALERT,
+ sensor_attr_set(dev, SENSOR_CHAN_VOLTAGE, SENSOR_ATTR_ALERT,
&val);
}
}
static void set_low_trigger(enum pwr_sig_adc adc, bool enable)
{
- set_trigger(config[adc].dev_trig_low,
- &adc_state[adc],
- ADC_BIT_LOW_ENABLED,
- enable);
-
+ set_trigger(config[adc].dev_trig_low, &adc_state[adc],
+ ADC_BIT_LOW_ENABLED, enable);
}
static void set_high_trigger(enum pwr_sig_adc adc, bool enable)
{
- set_trigger(config[adc].dev_trig_high,
- &adc_state[adc],
- ADC_BIT_HIGH_ENABLED,
- enable);
+ set_trigger(config[adc].dev_trig_high, &adc_state[adc],
+ ADC_BIT_HIGH_ENABLED, enable);
}
static void trigger_high(enum pwr_sig_adc adc)
@@ -156,34 +141,30 @@ int power_signal_adc_disable(enum pwr_sig_adc adc)
#define PWR_ADC_ENUM(id) TAG_ADC(PWR_SIG_TAG_ADC, PWR_SIGNAL_ENUM(id))
-#define ADC_CB(id, lev) cb_##lev##_##id
+#define ADC_CB(id, lev) cb_##lev##_##id
-#define ADC_CB_DEFINE(id, lev) \
-static void ADC_CB(id, lev)(const struct device *dev, \
- const struct sensor_trigger *trigger) \
-{ \
- trigger_##lev(PWR_ADC_ENUM(id)); \
-}
+#define ADC_CB_DEFINE(id, lev) \
+ static void ADC_CB(id, lev)(const struct device *dev, \
+ const struct sensor_trigger *trigger) \
+ { \
+ trigger_##lev(PWR_ADC_ENUM(id)); \
+ }
DT_FOREACH_STATUS_OKAY_VARGS(MY_COMPAT, ADC_CB_DEFINE, high)
DT_FOREACH_STATUS_OKAY_VARGS(MY_COMPAT, ADC_CB_DEFINE, low)
-#define ADC_CB_COMMA(id, lev) ADC_CB(id, lev),
+#define ADC_CB_COMMA(id, lev) ADC_CB(id, lev),
void power_signal_adc_init(void)
{
- struct sensor_trigger trig = {
- .type = SENSOR_TRIG_THRESHOLD,
- .chan = SENSOR_CHAN_VOLTAGE
- };
- sensor_trigger_handler_t low_cb[] = {
- DT_FOREACH_STATUS_OKAY_VARGS(MY_COMPAT, ADC_CB_COMMA, low)
- };
- sensor_trigger_handler_t high_cb[] = {
- DT_FOREACH_STATUS_OKAY_VARGS(MY_COMPAT, ADC_CB_COMMA, high)
- };
+ struct sensor_trigger trig = { .type = SENSOR_TRIG_THRESHOLD,
+ .chan = SENSOR_CHAN_VOLTAGE };
+ sensor_trigger_handler_t low_cb[] = { DT_FOREACH_STATUS_OKAY_VARGS(
+ MY_COMPAT, ADC_CB_COMMA, low) };
+ sensor_trigger_handler_t high_cb[] = { DT_FOREACH_STATUS_OKAY_VARGS(
+ MY_COMPAT, ADC_CB_COMMA, high) };
int i, rv;
- int32_t val;
+ int32_t val = 0;
for (i = 0; i < ARRAY_SIZE(low_cb); i++) {
/*
@@ -202,11 +183,10 @@ void power_signal_adc_init(void)
rv = adc_read(dev, &seq);
if (rv) {
- LOG_ERR("ADC %s:%d initial read failed",
- dev->name, config[i].adc_ch);
+ LOG_ERR("ADC %s:%d initial read failed", dev->name,
+ config[i].adc_ch);
} else {
- adc_raw_to_millivolts(adc_ref_internal(dev),
- ADC_GAIN_1,
+ adc_raw_to_millivolts(adc_ref_internal(dev), ADC_GAIN_1,
CONFIG_PLATFORM_EC_ADC_RESOLUTION,
&val);
if (val >= config[i].threshold) {
diff --git a/zephyr/subsys/ap_pwrseq/signal_gpio.c b/zephyr/subsys/ap_pwrseq/signal_gpio.c
index 9f8c3adb48..1dbd430bef 100644
--- a/zephyr/subsys/ap_pwrseq/signal_gpio.c
+++ b/zephyr/subsys/ap_pwrseq/signal_gpio.c
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -8,16 +8,14 @@
#include <zephyr/drivers/gpio.h>
#include "system.h"
-#define MY_COMPAT intel_ap_pwrseq_gpio
+#define MY_COMPAT intel_ap_pwrseq_gpio
#if HAS_GPIO_SIGNALS
-#define INIT_GPIO_SPEC(id) \
- GPIO_DT_SPEC_GET(id, gpios),
+#define INIT_GPIO_SPEC(id) GPIO_DT_SPEC_GET(id, gpios),
-const static struct gpio_dt_spec spec[] = {
-DT_FOREACH_STATUS_OKAY(MY_COMPAT, INIT_GPIO_SPEC)
-};
+const static struct gpio_dt_spec spec[] = { DT_FOREACH_STATUS_OKAY(
+ MY_COMPAT, INIT_GPIO_SPEC) };
/*
* Configuration for GPIO inputs.
@@ -29,17 +27,16 @@ struct ps_gpio_int {
unsigned no_enable : 1;
};
-#define INIT_GPIO_CONFIG(id) \
- { \
- .flags = DT_PROP_OR(id, interrupt_flags, 0), \
- .signal = PWR_SIGNAL_ENUM(id), \
- .no_enable = DT_PROP(id, no_enable), \
- .output = DT_PROP(id, output), \
- },
+#define INIT_GPIO_CONFIG(id) \
+ { \
+ .flags = DT_PROP_OR(id, interrupt_flags, 0), \
+ .signal = PWR_SIGNAL_ENUM(id), \
+ .no_enable = DT_PROP(id, no_enable), \
+ .output = DT_PROP(id, output), \
+ },
-const static struct ps_gpio_int gpio_config[] = {
-DT_FOREACH_STATUS_OKAY(MY_COMPAT, INIT_GPIO_CONFIG)
-};
+const static struct ps_gpio_int gpio_config[] = { DT_FOREACH_STATUS_OKAY(
+ MY_COMPAT, INIT_GPIO_CONFIG) };
static struct gpio_callback int_cb[ARRAY_SIZE(gpio_config)];
@@ -103,6 +100,34 @@ int power_signal_gpio_get(enum pwr_sig_gpio index)
if (index < 0 || index >= ARRAY_SIZE(gpio_config)) {
return -EINVAL;
}
+ /*
+ * Getting the current value of an output is
+ * done by retrieving the config and checking what the
+ * output state has been set to, not by reading the
+ * physical level of the pin (open drain outputs
+ * may have a low voltage).
+ */
+ if (IS_ENABLED(CONFIG_GPIO_GET_CONFIG) && gpio_config[index].output) {
+ int rv;
+ gpio_flags_t flags;
+
+ rv = gpio_pin_get_config_dt(&spec[index], &flags);
+ if (rv == 0) {
+ int pin = (flags & GPIO_OUTPUT_INIT_HIGH) ? 1 : 0;
+ /* If active low signal, invert it */
+ if (spec[index].dt_flags & GPIO_ACTIVE_LOW) {
+ pin = !pin;
+ }
+ return pin;
+ }
+ /*
+ * -ENOSYS is returned when this API call is not supported,
+ * so drop into the default method of returning the pin value.
+ */
+ if (rv != -ENOSYS) {
+ return rv;
+ }
+ }
return gpio_pin_get_dt(&spec[index]);
}
@@ -123,7 +148,8 @@ void power_signal_gpio_init(void)
* to the deasserted state.
*/
gpio_flags_t out_flags = system_jumped_to_this_image() ?
- GPIO_OUTPUT : GPIO_OUTPUT_INACTIVE;
+ GPIO_OUTPUT :
+ GPIO_OUTPUT_INACTIVE;
for (int i = 0; i < ARRAY_SIZE(gpio_config); i++) {
if (gpio_config[i].output) {
@@ -133,8 +159,8 @@ void power_signal_gpio_init(void)
/* If interrupt, initialise it */
if (gpio_config[i].flags) {
gpio_init_callback(&int_cb[i],
- power_signal_gpio_interrupt,
- BIT(spec[i].pin));
+ power_signal_gpio_interrupt,
+ BIT(spec[i].pin));
gpio_add_callback(spec[i].port, &int_cb[i]);
/*
* If the interrupt is to be enabled at
diff --git a/zephyr/subsys/ap_pwrseq/signal_vw.c b/zephyr/subsys/ap_pwrseq/signal_vw.c
index de2756c137..0e9e4affff 100644
--- a/zephyr/subsys/ap_pwrseq/signal_vw.c
+++ b/zephyr/subsys/ap_pwrseq/signal_vw.c
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -9,40 +9,47 @@
#include "signal_vw.h"
-#define MY_COMPAT intel_ap_pwrseq_vw
+#define MY_COMPAT intel_ap_pwrseq_vw
#if HAS_VW_SIGNALS
+/*
+ * A callback must be registered on the ESPI device (for the
+ * bus events that are required to be handled) that calls
+ * power_signal_espi_cb().
+ *
+ * This registration is done in a common ESPI initialisation module so
+ * that there is no possibility of missing events.
+ */
+
LOG_MODULE_DECLARE(ap_pwrseq, CONFIG_AP_PWRSEQ_LOG_LEVEL);
-#define INIT_ESPI_SIGNAL(id) \
-{ \
- .espi_signal = DT_STRING_UPPER_TOKEN(id, virtual_wire), \
- .signal = PWR_SIGNAL_ENUM(id), \
- .invert = DT_PROP(id, vw_invert), \
-},
+#define INIT_ESPI_SIGNAL(id) \
+ { \
+ .espi_signal = DT_STRING_UPPER_TOKEN(id, virtual_wire), \
+ .signal = PWR_SIGNAL_ENUM(id), \
+ .invert = DT_PROP(id, vw_invert), \
+ },
/*
* Struct containing the eSPI virtual wire config.
*/
struct vw_config {
- uint8_t espi_signal; /* associated VW signal */
- uint8_t signal; /* power signal */
- bool invert; /* Invert the signal value */
+ uint8_t espi_signal; /* associated VW signal */
+ uint8_t signal; /* power signal */
+ bool invert; /* Invert the signal value */
};
-const static struct vw_config vw_config[] = {
-DT_FOREACH_STATUS_OKAY(MY_COMPAT, INIT_ESPI_SIGNAL)
-};
+const static struct vw_config vw_config[] = { DT_FOREACH_STATUS_OKAY(
+ MY_COMPAT, INIT_ESPI_SIGNAL) };
/*
* Current signal value.
*/
static atomic_t signal_data;
/*
- * Mask of valid signals. If the bus is reset, this is cleared,
- * and when a signal is updated the associated bit is set to indicate
- * the signal is valid.
+ * Mask of valid signals. A signal is considered valid once an
+ * initial value has been received for it.
*/
static atomic_t signal_valid;
@@ -50,36 +57,63 @@ static atomic_t signal_valid;
BUILD_ASSERT(ARRAY_SIZE(vw_config) <= (sizeof(atomic_t) * 8));
-static void espi_handler(const struct device *dev,
- struct espi_callback *cb,
- struct espi_event event)
+/*
+ * Set the value of the VW signal, and optionally
+ * call the power signal interrupt handling.
+ */
+static void vw_set(int index, int data, bool notify)
+{
+ bool value = vw_config[index].invert ? !data : !!data;
+
+ atomic_set_bit_to(&signal_data, index, value);
+ atomic_set_bit(&signal_valid, index);
+ if (notify) {
+ power_signal_interrupt(vw_config[index].signal, value);
+ }
+}
+
+/*
+ * Update all the VW signals.
+ */
+static void vw_update_all(bool notify)
+{
+ for (int i = 0; i < ARRAY_SIZE(vw_config); i++) {
+ uint8_t vw_value;
+
+ if (espi_receive_vwire(espi_dev, vw_config[i].espi_signal,
+ &vw_value) == 0) {
+ vw_set(i, vw_value, notify);
+ }
+ }
+}
+
+void power_signal_espi_cb(const struct device *dev, struct espi_callback *cb,
+ struct espi_event event)
{
- LOG_DBG("ESPI event type 0x%x %d:%d", event.evt_type,
- event.evt_details, event.evt_data);
+ LOG_DBG("ESPI event type 0x%x %d:%d", event.evt_type, event.evt_details,
+ event.evt_data);
switch (event.evt_type) {
default:
- __ASSERT(0, "ESPI unknown event type: %d",
- event.evt_type);
+ __ASSERT(0, "ESPI unknown event type: %d", event.evt_type);
break;
- case ESPI_BUS_RESET:
- /*
- * Clear the signal valid mask.
- */
- atomic_clear(&signal_valid);
+ case ESPI_BUS_EVENT_CHANNEL_READY:
+ /* Virtual wire channel status change */
+ if (event.evt_details == ESPI_CHANNEL_VWIRE) {
+ if (event.evt_data) {
+ /* If now ready, update all the signals */
+ vw_update_all(true);
+ } else {
+ /* If not ready, invalidate the signals */
+ atomic_clear(&signal_valid);
+ }
+ }
break;
case ESPI_BUS_EVENT_VWIRE_RECEIVED:
for (int i = 0; i < ARRAY_SIZE(vw_config); i++) {
if (event.evt_details == vw_config[i].espi_signal) {
- bool value = vw_config[i].invert
- ? !event.evt_data
- : !!event.evt_data;
-
- atomic_set_bit_to(&signal_data, i, value);
- atomic_set_bit(&signal_valid, i);
- power_signal_interrupt(vw_config[i].signal,
- value);
+ vw_set(i, event.evt_data, true);
}
}
break;
@@ -97,34 +131,12 @@ int power_signal_vw_get(enum pwr_sig_vw vw)
void power_signal_vw_init(void)
{
- static struct espi_callback espi_cb;
-
- /* Assumes ESPI device is already configured. */
-
- /* Configure handler for eSPI events */
- espi_init_callback(&espi_cb, espi_handler,
- ESPI_BUS_RESET |
- ESPI_BUS_EVENT_VWIRE_RECEIVED);
- espi_add_callback(espi_dev, &espi_cb);
/*
* Check whether the bus is ready, and if so,
* initialise the current values of the signals.
*/
if (espi_get_channel_status(espi_dev, ESPI_CHANNEL_VWIRE)) {
- for (int i = 0; i < ARRAY_SIZE(vw_config); i++) {
- uint8_t vw_value;
-
- if (espi_receive_vwire(espi_dev,
- vw_config[i].espi_signal,
- &vw_value) == 0) {
- atomic_set_bit_to(&signal_data, i,
- vw_config[i].invert
- ? !vw_value
- : !!vw_value);
- atomic_set_bit(&signal_valid, i);
-
- }
- }
+ vw_update_all(false);
}
}
diff --git a/zephyr/subsys/ap_pwrseq/x86_non_dsx_adlp_pwrseq_sm.c b/zephyr/subsys/ap_pwrseq/x86_non_dsx_adlp_pwrseq_sm.c
index 375e93c74f..9ef482b712 100644
--- a/zephyr/subsys/ap_pwrseq/x86_non_dsx_adlp_pwrseq_sm.c
+++ b/zephyr/subsys/ap_pwrseq/x86_non_dsx_adlp_pwrseq_sm.c
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -20,8 +20,7 @@ static int check_pch_out_of_suspend(void)
/*
* Wait for SLP_SUS deasserted.
*/
- ret = power_wait_mask_signals_timeout(IN_PCH_SLP_SUS,
- 0,
+ ret = power_wait_mask_signals_timeout(IN_PCH_SLP_SUS, 0,
IN_PCH_SLP_SUS_WAIT_TIME_MS);
if (ret == 0) {
LOG_DBG("SLP_SUS now %d", power_signal_get(PWR_SLP_SUS));
@@ -38,14 +37,21 @@ int all_sys_pwrgd_handler(void)
{
int retry = 0;
+ /* SLP_S3 is off */
+ if (power_signal_get(PWR_SLP_S3) == 1) {
+ ap_off();
+ return 1;
+ }
+
/* TODO: Add condition for no power sequencer */
- k_msleep(AP_PWRSEQ_DT_VALUE(all_sys_pwrgd_timeout));
+ power_wait_signals_timeout(POWER_SIGNAL_MASK(PWR_ALL_SYS_PWRGD),
+ AP_PWRSEQ_DT_VALUE(all_sys_pwrgd_timeout));
if (power_signal_get(PWR_DSW_PWROK) == 0) {
- /* Todo: Remove workaround for the retry
- * without this change the system hits G3 as it detects
- * ALL_SYS_PWRGD as 0 and then 1 as a glitch
- */
+ /* Todo: Remove workaround for the retry
+ * without this change the system hits G3 as it detects
+ * ALL_SYS_PWRGD as 0 and then 1 as a glitch
+ */
while (power_signal_get(PWR_ALL_SYS_PWRGD) == 0) {
if (++retry > 2) {
LOG_ERR("PG_EC_ALL_SYS_PWRGD not ok");
@@ -58,7 +64,7 @@ int all_sys_pwrgd_handler(void)
/* PG_EC_ALL_SYS_PWRGD is asserted, enable VCCST_PWRGD_OD. */
- if (power_signal_get(PWR_VCCST_PWRGD) == 0) {
+ if (!power_signals_on(POWER_SIGNAL_MASK(PWR_VCCST_PWRGD))) {
k_msleep(AP_PWRSEQ_DT_VALUE(vccst_pwrgd_delay));
power_signal_set(PWR_VCCST_PWRGD, 1);
}
diff --git a/zephyr/subsys/ap_pwrseq/x86_non_dsx_chipset_power_state.c b/zephyr/subsys/ap_pwrseq/x86_non_dsx_chipset_power_state.c
index 97268e8fe6..e4ce364cb1 100644
--- a/zephyr/subsys/ap_pwrseq/x86_non_dsx_chipset_power_state.c
+++ b/zephyr/subsys/ap_pwrseq/x86_non_dsx_chipset_power_state.c
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -14,39 +14,41 @@ LOG_MODULE_DECLARE(ap_pwrseq, CONFIG_AP_PWRSEQ_LOG_LEVEL);
*/
enum power_states_ndsx chipset_pwr_seq_get_state(void)
{
+ power_signal_mask_t sig = power_get_signals();
+
/*
- * Chip is shut down.
+ * Chip is shut down, G3 state.
*/
- if ((power_get_signals() & MASK_ALL_POWER_GOOD) == 0) {
- LOG_DBG("Power rails off, G3 state");
+ if ((sig & MASK_ALL_POWER_GOOD) == 0) {
+ LOG_DBG("All power rails off, G3 state");
return SYS_POWER_STATE_G3;
}
/*
- * If not all the power rails are available,
- * then force shutdown to G3 to get to known state.
+ * Not enough power rails up to read VW signals.
+ * Force a shutdown.
*/
- if ((power_get_signals() & MASK_ALL_POWER_GOOD)
- != MASK_ALL_POWER_GOOD) {
+ if ((sig & MASK_VW_POWER) != VALUE_VW_POWER) {
+ LOG_ERR("Not enough power signals on (%#x), forcing shutdown",
+ sig);
ap_power_force_shutdown(AP_POWER_SHUTDOWN_G3);
- LOG_INF("Not all power rails up, forcing shutdown");
return SYS_POWER_STATE_G3;
}
/*
- * All the power rails are good, so
+ * Enough power signals are up, so
* wait for virtual wire signals to become available.
* Not sure how long to wait? 5 seconds total.
*/
for (int delay = 0; delay < 500; k_msleep(10), delay++) {
-#if defined(CONFIG_PLATFORM_EC_ESPI_VW_SLP_S3)
+#if defined(CONFIG_PLATFORM_EC_HOST_INTERFACE_ESPI_VW_SLP_S3)
if (power_signal_get(PWR_SLP_S3) < 0)
continue;
#endif
-#if defined(CONFIG_PLATFORM_EC_ESPI_VW_SLP_S4)
+#if defined(CONFIG_PLATFORM_EC_HOST_INTERFACE_ESPI_VW_SLP_S4)
if (power_signal_get(PWR_SLP_S4) < 0)
continue;
#endif
-#if defined(CONFIG_PLATFORM_EC_ESPI_VW_SLP_S5)
+#if defined(CONFIG_PLATFORM_EC_HOST_INTERFACE_ESPI_VW_SLP_S5)
if (power_signal_get(PWR_SLP_S5) < 0)
continue;
#endif
@@ -56,32 +58,34 @@ enum power_states_ndsx chipset_pwr_seq_get_state(void)
LOG_DBG("All VW signals valid after %d ms", delay * 10);
break;
}
+ /* Re-read the power signals */
+ sig = power_get_signals();
+
/*
* S0, all power OK, no suspend or sleep on.
*/
- if ((power_get_signals() & MASK_S0) == MASK_ALL_POWER_GOOD) {
+ if ((sig & MASK_S0) == VALUE_S0) {
LOG_DBG("CPU in S0 state");
return SYS_POWER_STATE_S0;
}
/*
* S3, all power OK, PWR_SLP_S3 on.
*/
- if ((power_get_signals() & MASK_S0) ==
- (MASK_ALL_POWER_GOOD | POWER_SIGNAL_MASK(PWR_SLP_S3))) {
+ if ((sig & MASK_S3) == VALUE_S3) {
LOG_DBG("CPU in S3 state");
return SYS_POWER_STATE_S3;
}
/*
- * S5, all power OK, PWR_SLP_S5 on.
+ * S5, some power signals on, PWR_SLP_S5 on.
*/
- if ((power_get_signals() & MASK_S5) == MASK_S5) {
+ if ((sig & MASK_S5) == VALUE_S5) {
LOG_DBG("CPU in S5 state");
return SYS_POWER_STATE_S5;
}
/*
* Unable to determine state, force to G3.
*/
+ LOG_INF("Unable to determine CPU state (%#x), forcing shutdown", sig);
ap_power_force_shutdown(AP_POWER_SHUTDOWN_G3);
- LOG_INF("Unable to determine CPU state, forcing shutdown");
return SYS_POWER_STATE_G3;
}
diff --git a/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_console.c b/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_console.c
index e671e46113..dbceeacc85 100644
--- a/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_console.c
+++ b/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_console.c
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -11,20 +11,19 @@ LOG_MODULE_DECLARE(ap_pwrseq, CONFIG_AP_PWRSEQ_LOG_LEVEL);
/* Console commands */
static int powerinfo_handler(const struct shell *shell, size_t argc,
- char **argv)
+ char **argv)
{
enum power_states_ndsx state = pwr_sm_get_state();
shell_fprintf(shell, SHELL_INFO, "power state %d = %s, in 0x%04x\n",
- state, pwr_sm_get_state_name(state),
- power_get_signals());
+ state, pwr_sm_get_state_name(state), power_get_signals());
return 0;
}
SHELL_CMD_REGISTER(powerinfo, NULL, NULL, powerinfo_handler);
static int powerindebug_handler(const struct shell *shell, size_t argc,
- char **argv)
+ char **argv)
{
int i;
char *e;
@@ -42,29 +41,29 @@ static int powerindebug_handler(const struct shell *shell, size_t argc,
/* Print the mask */
current = power_get_signals();
- shell_fprintf(shell, SHELL_INFO, "power in: 0x%04x\n", current);
- shell_fprintf(shell, SHELL_INFO, "debug mask: 0x%04x\n",
- power_get_debug());
+ shell_fprintf(shell, SHELL_INFO, "power in: 0x%05x\n", current);
+ shell_fprintf(shell, SHELL_INFO, "debug mask: 0x%05x\n",
+ power_get_debug());
/* Print the decode */
shell_fprintf(shell, SHELL_INFO, "bit meanings:\n");
for (i = 0; i < POWER_SIGNAL_COUNT; i++) {
power_signal_mask_t mask = POWER_SIGNAL_MASK(i);
+ bool valid = (power_signal_get(i) >= 0);
- shell_fprintf(shell, SHELL_INFO, " 0x%04x %d %s\n",
- mask, (current & mask) ? 1 : 0,
- power_signal_name(i));
+ shell_fprintf(shell, SHELL_INFO, " 0x%05x %d%s %s\n", mask,
+ (current & mask) ? 1 : 0, valid ? " " : "!",
+ power_signal_name(i));
}
return 0;
};
-SHELL_CMD_REGISTER(powerindebug, NULL,
- "[mask] Get/set power input debug mask", powerindebug_handler);
-
+SHELL_CMD_REGISTER(powerindebug, NULL, "[mask] Get/set power input debug mask",
+ powerindebug_handler);
static int apshutdown_handler(const struct shell *shell, size_t argc,
- char **argv)
+ char **argv)
{
ap_power_force_shutdown(AP_POWER_SHUTDOWN_CONSOLE_CMD);
return 0;
@@ -72,8 +71,7 @@ static int apshutdown_handler(const struct shell *shell, size_t argc,
SHELL_CMD_REGISTER(apshutdown, NULL, NULL, apshutdown_handler);
-static int apreset_handler(const struct shell *shell, size_t argc,
- char **argv)
+static int apreset_handler(const struct shell *shell, size_t argc, char **argv)
{
ap_power_reset(AP_POWER_SHUTDOWN_CONSOLE_CMD);
return 0;
diff --git a/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_host_command.c b/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_host_command.c
index 7bacbcd8cd..ee6e2cf41e 100644
--- a/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_host_command.c
+++ b/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_host_command.c
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -12,14 +12,14 @@ host_command_reboot_ap_on_g3(struct host_cmd_handler_args *args)
const struct ec_params_reboot_ap_on_g3_v1 *cmd = args->params;
/* Store request for processing at g3 */
- request_exit_hardoff(true);
+ request_start_from_g3();
switch (args->version) {
case 0:
break;
case 1:
/* Store user specified delay to wait in G3 state */
- set_reboot_ap_at_g3_delay_seconds(cmd->reboot_ap_at_g3_delay);
+ set_start_from_g3_delay_seconds(cmd->reboot_ap_at_g3_delay);
break;
default:
return EC_RES_INVALID_PARAM;
@@ -27,8 +27,66 @@ host_command_reboot_ap_on_g3(struct host_cmd_handler_args *args)
return EC_RES_SUCCESS;
}
-DECLARE_HOST_COMMAND(EC_CMD_REBOOT_AP_ON_G3,
- host_command_reboot_ap_on_g3,
+DECLARE_HOST_COMMAND(EC_CMD_REBOOT_AP_ON_G3, host_command_reboot_ap_on_g3,
EC_VER_MASK(0) | EC_VER_MASK(1));
+#if CONFIG_AP_PWRSEQ_HOST_SLEEP
+/* Track last reported sleep event */
+static enum host_sleep_event host_sleep_state;
+
+static enum ec_status
+host_command_host_sleep_event(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_host_sleep_event_v1 *p = args->params;
+ struct ec_response_host_sleep_event_v1 *r = args->response;
+ struct host_sleep_event_context ctx;
+ enum host_sleep_event state = p->sleep_event;
+
+ host_sleep_state = state;
+ ctx.sleep_transitions = 0;
+ switch (state) {
+ case HOST_SLEEP_EVENT_S0IX_SUSPEND:
+ case HOST_SLEEP_EVENT_S3_SUSPEND:
+ case HOST_SLEEP_EVENT_S3_WAKEABLE_SUSPEND:
+ ctx.sleep_timeout_ms = EC_HOST_SLEEP_TIMEOUT_DEFAULT;
+
+ /* The original version contained only state. */
+ if (args->version >= 1)
+ ctx.sleep_timeout_ms =
+ p->suspend_params.sleep_timeout_ms;
+
+ break;
+
+ default:
+ break;
+ }
+
+ ap_power_chipset_handle_host_sleep_event(host_sleep_state, &ctx);
+ switch (state) {
+ case HOST_SLEEP_EVENT_S0IX_RESUME:
+ case HOST_SLEEP_EVENT_S3_RESUME:
+ if (args->version >= 1) {
+ r->resume_response.sleep_transitions =
+ ctx.sleep_transitions;
+
+ args->response_size = sizeof(*r);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_HOST_SLEEP_EVENT, host_command_host_sleep_event,
+ EC_VER_MASK(0) | EC_VER_MASK(1));
+
+void power_set_host_sleep_state(enum host_sleep_event state)
+{
+ host_sleep_state = state;
+}
+#endif /* CONFIG_AP_PWRSEQ_HOST_SLEEP */
+
/* End of host commands */
diff --git a/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_host_sleep.c b/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_host_sleep.c
new file mode 100644
index 0000000000..015cecb502
--- /dev/null
+++ b/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_host_sleep.c
@@ -0,0 +1,179 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <ap_power_host_sleep.h>
+#include <x86_non_dsx_common_pwrseq_sm_handler.h>
+
+static uint16_t sleep_signal_timeout;
+static uint16_t host_sleep_timeout_default = CONFIG_SLEEP_TIMEOUT_MS;
+static uint32_t sleep_signal_transitions;
+static enum sleep_hang_type timeout_hang_type;
+
+static void sleep_transition_timeout(struct k_work *work);
+
+static K_WORK_DELAYABLE_DEFINE(sleep_transition_timeout_data,
+ sleep_transition_timeout);
+
+/**
+ * Type of sleep hang detected
+ */
+enum sleep_hang_type {
+ SLEEP_HANG_NONE,
+ SLEEP_HANG_S0IX_SUSPEND,
+ SLEEP_HANG_S0IX_RESUME
+};
+
+void power_chipset_handle_sleep_hang(enum sleep_hang_type hang_type)
+{
+ /*
+ * Wake up the AP so they don't just chill in a non-suspended state and
+ * burn power. Overload a vaguely related event bit since event bits are
+ * at a premium. If the system never entered S0ix, then manually set the
+ * wake mask to pretend it did, so that the hang detect event wakes the
+ * system.
+ */
+ if (pwr_sm_get_state() == SYS_POWER_STATE_S0) {
+ host_event_t sleep_wake_mask;
+
+ ap_power_get_lazy_wake_mask(SYS_POWER_STATE_S0ix,
+ &sleep_wake_mask);
+ lpc_set_host_event_mask(LPC_HOST_EVENT_WAKE, sleep_wake_mask);
+ }
+
+ ccprintf("Warning: Detected sleep hang! Waking host up!");
+ host_set_single_event(EC_HOST_EVENT_HANG_DETECT);
+}
+
+static void sleep_transition_timeout(struct k_work *work)
+{
+ /* Mark the timeout. */
+ sleep_signal_transitions |= EC_HOST_RESUME_SLEEP_TIMEOUT;
+ k_work_cancel_delayable(&sleep_transition_timeout_data);
+
+ if (timeout_hang_type != SLEEP_HANG_NONE) {
+ power_chipset_handle_sleep_hang(timeout_hang_type);
+ }
+}
+
+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();
+ k_work_cancel_delayable(&sleep_transition_timeout_data);
+}
+
+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) {
+ timeout_hang_type = SLEEP_HANG_S0IX_RESUME;
+ k_work_schedule(&sleep_transition_timeout_data,
+ K_MSEC(sleep_signal_timeout));
+ }
+}
+
+void sleep_start_suspend(void)
+{
+ uint16_t timeout = host_get_sleep_timeout();
+
+ sleep_signal_transitions = 0;
+
+ /* Use 0xFFFF to disable the timeout */
+ if (timeout == EC_HOST_SLEEP_TIMEOUT_INFINITE) {
+ sleep_signal_timeout = 0;
+ return;
+ }
+
+ /* Use zero internally to indicate host doesn't set timeout value;
+ * we will use default timeout.
+ */
+ if (timeout == EC_HOST_SLEEP_TIMEOUT_DEFAULT) {
+ timeout = host_sleep_timeout_default;
+ }
+
+ sleep_signal_timeout = timeout;
+ timeout_hang_type = SLEEP_HANG_S0IX_SUSPEND;
+ k_work_schedule(&sleep_transition_timeout_data, K_MSEC(timeout));
+}
+
+void sleep_complete_resume(void)
+{
+ /*
+ * Ensure we don't schedule another sleep_transition_timeout
+ * if the the HOST_SLEEP_EVENT_S0IX_RESUME message arrives before
+ * the CHIPSET task transitions to the POWER_S0ixS0 state.
+ */
+ sleep_signal_timeout = 0;
+ k_work_cancel_delayable(&sleep_transition_timeout_data);
+ host_set_sleep_transitions(sleep_signal_transitions);
+}
+
+void sleep_reset_tracking(void)
+{
+ sleep_signal_transitions = 0;
+ sleep_signal_timeout = 0;
+ timeout_hang_type = SLEEP_HANG_NONE;
+}
+
+/*
+ * s0ix event handler.
+ */
+static void ap_power_sleep_event_handler(struct ap_power_ev_callback *cb,
+ struct ap_power_ev_data data)
+{
+ switch (data.event) {
+ case AP_POWER_S0IX_SUSPEND_START:
+ sleep_start_suspend();
+ break;
+ case AP_POWER_S0IX_SUSPEND:
+ sleep_suspend_transition();
+ break;
+ case AP_POWER_S0IX_RESUME:
+ sleep_resume_transition();
+ break;
+ case AP_POWER_S0IX_RESUME_COMPLETE:
+ sleep_complete_resume();
+ break;
+ case AP_POWER_S0IX_RESET_TRACKING:
+ sleep_reset_tracking();
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * Registers callback for s0ix events.
+ */
+static int ap_power_sleep_s0ix_event(const struct device *unused)
+{
+ static struct ap_power_ev_callback cb;
+
+ /*
+ * Register for all events.
+ */
+ ap_power_ev_init_callback(
+ &cb, ap_power_sleep_event_handler,
+ AP_POWER_S0IX_SUSPEND_START | AP_POWER_S0IX_SUSPEND |
+ AP_POWER_S0IX_RESUME | AP_POWER_S0IX_RESUME_COMPLETE |
+ AP_POWER_S0IX_RESET_TRACKING);
+ ap_power_ev_add_callback(&cb);
+ return 0;
+}
+SYS_INIT(ap_power_sleep_s0ix_event, APPLICATION, 1);
diff --git a/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_sm_handler.c b/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_sm_handler.c
index 2f38c36684..48cab7f6e7 100644
--- a/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_sm_handler.c
+++ b/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_sm_handler.c
@@ -1,25 +1,42 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
+#include <atomic.h>
#include <zephyr/init.h>
#include <x86_non_dsx_common_pwrseq_sm_handler.h>
-static K_KERNEL_STACK_DEFINE(pwrseq_thread_stack,
- CONFIG_AP_PWRSEQ_STACK_SIZE);
+static K_KERNEL_STACK_DEFINE(pwrseq_thread_stack, CONFIG_AP_PWRSEQ_STACK_SIZE);
static struct k_thread pwrseq_thread_data;
-static struct pwrseq_context pwrseq_ctx;
+static struct pwrseq_context pwrseq_ctx = {
+ .power_state = SYS_POWER_STATE_UNINIT,
+};
+static struct k_sem pwrseq_sem;
+
+static void s5_inactive_timer_handler(struct k_timer *timer);
/* S5 inactive timer*/
-K_TIMER_DEFINE(s5_inactive_timer, NULL, NULL);
+K_TIMER_DEFINE(s5_inactive_timer, s5_inactive_timer_handler, NULL);
+/*
+ * Flags, may be set/cleared from other threads.
+ */
+enum {
+ S5_INACTIVE_TIMER_RUNNING,
+ START_FROM_G3,
+ FLAGS_MAX,
+};
+static ATOMIC_DEFINE(flags, FLAGS_MAX);
+/* Delay in ms when starting from G3 */
+static uint32_t start_from_g3_delay_ms;
LOG_MODULE_REGISTER(ap_pwrseq, CONFIG_AP_PWRSEQ_LOG_LEVEL);
/**
* @brief power_state names for debug
*/
-static const char * const pwrsm_dbg[] = {
+static const char *const pwrsm_dbg[] = {
+ [SYS_POWER_STATE_UNINIT] = "Unknown",
[SYS_POWER_STATE_G3] = "G3",
[SYS_POWER_STATE_S5] = "S5",
[SYS_POWER_STATE_S4] = "S4",
@@ -48,17 +65,17 @@ static const char * const pwrsm_dbg[] = {
*/
static inline bool signals_valid(power_signal_mask_t signals)
{
-#if defined(CONFIG_PLATFORM_EC_ESPI_VW_SLP_S3)
+#if defined(CONFIG_PLATFORM_EC_HOST_INTERFACE_ESPI_VW_SLP_S3)
if ((signals & POWER_SIGNAL_MASK(PWR_SLP_S3)) &&
power_signal_get(PWR_SLP_S3) < 0)
return false;
#endif
-#if defined(CONFIG_PLATFORM_EC_ESPI_VW_SLP_S4)
+#if defined(CONFIG_PLATFORM_EC_HOST_INTERFACE_ESPI_VW_SLP_S4)
if ((signals & POWER_SIGNAL_MASK(PWR_SLP_S4)) &&
power_signal_get(PWR_SLP_S4) < 0)
return false;
#endif
-#if defined(CONFIG_PLATFORM_EC_ESPI_VW_SLP_S5)
+#if defined(CONFIG_PLATFORM_EC_HOST_INTERFACE_ESPI_VW_SLP_S5)
if ((signals & POWER_SIGNAL_MASK(PWR_SLP_S5)) &&
power_signal_get(PWR_SLP_S5) < 0)
return false;
@@ -81,7 +98,7 @@ enum power_states_ndsx pwr_sm_get_state(void)
return pwrseq_ctx.power_state;
}
-const char * const pwr_sm_get_state_name(enum power_states_ndsx state)
+const char *const pwr_sm_get_state_name(enum power_states_ndsx state)
{
return pwrsm_dbg[state];
}
@@ -95,14 +112,34 @@ void pwr_sm_set_state(enum power_states_ndsx new_state)
pwrseq_ctx.power_state = new_state;
}
-void request_exit_hardoff(bool should_exit)
+void ap_pwrseq_wake(void)
{
- pwrseq_ctx.want_g3_exit = should_exit;
+ k_sem_give(&pwrseq_sem);
}
-static bool chipset_is_exit_hardoff(void)
+/*
+ * Set a flag to enable starting the AP once it is in G3.
+ * This is called from ap_power_exit_hardoff() which checks
+ * to ensure that the AP is in S5 or G3 state before calling
+ * this function.
+ * It can also be called via a hostcmd, which allows the flag
+ * to be set in any AP state.
+ */
+void request_start_from_g3(void)
{
- return pwrseq_ctx.want_g3_exit;
+ LOG_INF("Request start from G3");
+ atomic_set_bit(flags, START_FROM_G3);
+ /*
+ * If in S5, restart the timer to give the CPU more time
+ * to respond to a power button press (which is presumably
+ * why we are being called). This avoids having the S5
+ * inactivity timer expiring before the AP can process
+ * the power button press and start up.
+ */
+ if (pwr_sm_get_state() == SYS_POWER_STATE_S5) {
+ atomic_clear_bit(flags, S5_INACTIVE_TIMER_RUNNING);
+ }
+ ap_pwrseq_wake();
}
void ap_power_force_shutdown(enum ap_power_shutdown_reason reason)
@@ -110,6 +147,11 @@ void ap_power_force_shutdown(enum ap_power_shutdown_reason reason)
board_ap_power_force_shutdown();
}
+static void s5_inactive_timer_handler(struct k_timer *timer)
+{
+ ap_pwrseq_wake();
+}
+
static void shutdown_and_notify(enum ap_power_shutdown_reason reason)
{
ap_power_force_shutdown(reason);
@@ -117,9 +159,9 @@ static void shutdown_and_notify(enum ap_power_shutdown_reason reason)
ap_power_ev_send_callbacks(AP_POWER_SHUTDOWN_COMPLETE);
}
-void set_reboot_ap_at_g3_delay_seconds(uint32_t d_time)
+void set_start_from_g3_delay_seconds(uint32_t d_time)
{
- pwrseq_ctx.reboot_ap_at_g3_delay_ms = d_time * MSEC;
+ start_from_g3_delay_ms = d_time * MSEC;
}
void apshutdown(void)
@@ -190,15 +232,16 @@ static int common_pwr_sm_run(int state)
{
switch (state) {
case SYS_POWER_STATE_G3:
- if (chipset_is_exit_hardoff()) {
- request_exit_hardoff(false);
- /*
- * G3->S0 transition should happen only after the
- * user specified delay. Hence, wait until the
- * user specified delay times out.
- */
- k_msleep(pwrseq_ctx.reboot_ap_at_g3_delay_ms);
- pwrseq_ctx.reboot_ap_at_g3_delay_ms = 0;
+ /*
+ * If the START_FROM_G3 flag is set, begin starting
+ * the AP. There may be a delay set, so only start
+ * after that delay.
+ */
+ if (atomic_test_and_clear_bit(flags, START_FROM_G3)) {
+ LOG_INF("Starting from G3, delay %d ms",
+ start_from_g3_delay_ms);
+ k_msleep(start_from_g3_delay_ms);
+ start_from_g3_delay_ms = 0;
return SYS_POWER_STATE_G3S5;
}
@@ -207,7 +250,7 @@ static int common_pwr_sm_run(int state)
case SYS_POWER_STATE_G3S5:
if ((power_get_signals() & PWRSEQ_G3S5_UP_SIGNAL) ==
- PWRSEQ_G3S5_UP_VALUE)
+ PWRSEQ_G3S5_UP_VALUE)
return SYS_POWER_STATE_S5;
else
return SYS_POWER_STATE_S5G3;
@@ -215,29 +258,56 @@ static int common_pwr_sm_run(int state)
case SYS_POWER_STATE_S5:
/* In S5 make sure no more signal lost */
/* If A-rails are stable then move to higher state */
- if (board_ap_power_check_power_rails_enabled()
- && rsmrst_power_is_good()) {
+ if (board_ap_power_check_power_rails_enabled() &&
+ rsmrst_power_is_good()) {
/* rsmrst is intact */
rsmrst_pass_thru_handler();
if (signals_valid_and_off(IN_PCH_SLP_S5)) {
k_timer_stop(&s5_inactive_timer);
+ /* Clear the timer running flag */
+ atomic_clear_bit(flags,
+ S5_INACTIVE_TIMER_RUNNING);
+ /* Clear any request to exit hard-off */
+ atomic_clear_bit(flags, START_FROM_G3);
+ LOG_INF("Clearing request to exit G3");
return SYS_POWER_STATE_S5S4;
}
}
- /* S5 inactivity timeout, go to S5G3 */
+ /*
+ * S5 state has an inactivity timer, so moving
+ * to S5G3 (where the power rails are turned off) is
+ * delayed for some time, usually ~10 seconds or so.
+ * The purpose of this delay is:
+ * - to handle AP initiated cold boot, where the AP
+ * will go to S5 for a short time and then restart.
+ * - give time for the power button to be pressed,
+ * which may set the START_FROM_G3 flag.
+ */
if (AP_PWRSEQ_DT_VALUE(s5_inactivity_timeout) == 0)
return SYS_POWER_STATE_S5G3;
else if (AP_PWRSEQ_DT_VALUE(s5_inactivity_timeout) > 0) {
- if (k_timer_status_get(&s5_inactive_timer) > 0)
+ /*
+ * Test and set timer running flag.
+ * If it was 0, then the timer wasn't running
+ * and it is started (and the flag is set),
+ * otherwise it is already set, so no change.
+ */
+ if (!atomic_test_and_set_bit(
+ flags, S5_INACTIVE_TIMER_RUNNING)) {
+ /*
+ * Timer is not started, or needs
+ * restarting.
+ */
+ k_timer_start(&s5_inactive_timer,
+ K_SECONDS(AP_PWRSEQ_DT_VALUE(
+ s5_inactivity_timeout)),
+ K_NO_WAIT);
+ } else if (k_timer_status_get(&s5_inactive_timer) > 0) {
/* Timer is expired */
+ atomic_clear_bit(flags,
+ S5_INACTIVE_TIMER_RUNNING);
return SYS_POWER_STATE_S5G3;
- else if (k_timer_remaining_get(
- &s5_inactive_timer) == 0)
- /* Timer is not started or stopped */
- k_timer_start(&s5_inactive_timer,
- K_SECONDS(AP_PWRSEQ_DT_VALUE(
- s5_inactivity_timeout)),
- K_NO_WAIT);
+ }
}
break;
@@ -318,7 +388,7 @@ static int common_pwr_sm_run(int state)
case SYS_POWER_STATE_S0ix:
/* System in S0 only if SLP_S0 and SLP_S3 are de-asserted */
if (power_signals_off(IN_PCH_SLP_S0) &&
- signals_valid_and_off(IN_PCH_SLP_S3)) {
+ signals_valid_and_off(IN_PCH_SLP_S3)) {
/* TODO: Make sure ap reset handling is done
* before leaving S0ix.
*/
@@ -334,6 +404,7 @@ static int common_pwr_sm_run(int state)
* HC already set sleep suspend state.
*/
ap_power_sleep_notify_transition(AP_POWER_SLEEP_SUSPEND);
+ ap_power_ev_send_callbacks(AP_POWER_S0IX_SUSPEND);
/*
* Enable idle task deep sleep. Allow the low power idle task
@@ -354,9 +425,11 @@ static int common_pwr_sm_run(int state)
*/
disable_sleep(SLEEP_MASK_AP_RUN);
+ ap_power_ev_send_callbacks(AP_POWER_S0IX_RESUME
#if CONFIG_PLATFORM_EC_CHIPSET_RESUME_INIT_HOOK
- ap_power_ev_send_callbacks(AP_POWER_RESUME_INIT);
+ | AP_POWER_RESUME_INIT
#endif
+ );
return SYS_POWER_STATE_S0;
@@ -370,19 +443,19 @@ static int common_pwr_sm_run(int state)
return SYS_POWER_STATE_S0S3;
#if CONFIG_AP_PWRSEQ_S0IX
- /*
- * SLP_S0 may assert in system idle scenario without a kernel
- * freeze call. This may cause interrupt storm since there is
- * no freeze/unfreeze of threads/process in the idle scenario.
- * Ignore the SLP_S0 assertions in idle scenario by checking
- * the host sleep state.
- */
+ /*
+ * SLP_S0 may assert in system idle scenario without a
+ * kernel freeze call. This may cause interrupt storm
+ * since there is no freeze/unfreeze of threads/process
+ * in the idle scenario. Ignore the SLP_S0 assertions in
+ * idle scenario by checking the host sleep state.
+ */
} else if (ap_power_sleep_get_notify() ==
- AP_POWER_SLEEP_SUSPEND &&
- power_signals_on(IN_PCH_SLP_S0)) {
+ AP_POWER_SLEEP_SUSPEND &&
+ power_signals_on(IN_PCH_SLP_S0)) {
return SYS_POWER_STATE_S0S0ix;
} else if (ap_power_sleep_get_notify() ==
- AP_POWER_SLEEP_RESUME) {
+ AP_POWER_SLEEP_RESUME) {
ap_power_sleep_notify_transition(AP_POWER_SLEEP_RESUME);
#endif /* CONFIG_AP_PWRSEQ_S0IX */
}
@@ -464,12 +537,16 @@ static void pwr_seq_set_initial_state(void)
static void pwrseq_loop_thread(void *p1, void *p2, void *p3)
{
- int32_t t_wait_ms = 10;
enum power_states_ndsx curr_state, new_state;
power_signal_mask_t this_in_signals;
power_signal_mask_t last_in_signals = 0;
enum power_states_ndsx last_state = -1;
+ /*
+ * Let clients know that the AP power state is now
+ * initialized and ready.
+ */
+ ap_power_ev_send_callbacks(AP_POWER_INITIALIZED);
while (1) {
curr_state = pwr_sm_get_state();
@@ -482,9 +559,8 @@ static void pwrseq_loop_thread(void *p1, void *p2, void *p3)
this_in_signals = power_get_signals();
if (this_in_signals != last_in_signals ||
- curr_state != last_state) {
- LOG_INF("power state %d = %s, in 0x%04x",
- curr_state,
+ curr_state != last_state) {
+ LOG_INF("power state %d = %s, in 0x%04x", curr_state,
pwr_sm_get_state_name(curr_state),
this_in_signals);
last_in_signals = this_in_signals;
@@ -506,22 +582,24 @@ static void pwrseq_loop_thread(void *p1, void *p2, void *p3)
if (curr_state != new_state) {
pwr_sm_set_state(new_state);
ap_power_set_active_wake_mask();
+ } else {
+ /*
+ * No state transition, we can go to sleep and wait
+ * for any event to wake us up.
+ */
+ k_sem_take(&pwrseq_sem, K_FOREVER);
}
-
- k_msleep(t_wait_ms);
}
}
static inline void create_pwrseq_thread(void)
{
- k_thread_create(&pwrseq_thread_data,
- pwrseq_thread_stack,
+ k_thread_create(&pwrseq_thread_data, pwrseq_thread_stack,
K_KERNEL_STACK_SIZEOF(pwrseq_thread_stack),
- (k_thread_entry_t)pwrseq_loop_thread,
- NULL, NULL, NULL,
+ (k_thread_entry_t)pwrseq_loop_thread, NULL, NULL, NULL,
CONFIG_AP_PWRSEQ_THREAD_PRIORITY, 0,
- IS_ENABLED(CONFIG_AP_PWRSEQ_AUTOSTART) ? K_NO_WAIT
- : K_FOREVER);
+ IS_ENABLED(CONFIG_AP_PWRSEQ_AUTOSTART) ? K_NO_WAIT :
+ K_FOREVER);
k_thread_name_set(&pwrseq_thread_data, "pwrseq_task");
}
@@ -535,7 +613,7 @@ void ap_pwrseq_task_start(void)
static void init_pwr_seq_state(void)
{
- request_exit_hardoff(false);
+ atomic_clear_bit(flags, START_FROM_G3);
/*
* The state of the CPU needs to be determined now
* so that init routines can check the state of
@@ -549,6 +627,7 @@ static int pwrseq_init(const struct device *dev)
{
LOG_INF("Pwrseq Init");
+ k_sem_init(&pwrseq_sem, 0, 1);
/* Initialize signal handlers */
power_signal_init();
LOG_DBG("Init pwr seq state");
@@ -559,7 +638,7 @@ static int pwrseq_init(const struct device *dev)
}
/*
- * The initialisation must occur after system I/O initialisation that
+ * The initialization must occur after system I/O initialization that
* the signals depend upon, such as GPIO, ADC etc.
*/
SYS_INIT(pwrseq_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
diff --git a/zephyr/subsys/ap_pwrseq/x86_non_dsx_mtl_pwrseq_sm.c b/zephyr/subsys/ap_pwrseq/x86_non_dsx_mtl_pwrseq_sm.c
index 5183824117..80fa06e454 100644
--- a/zephyr/subsys/ap_pwrseq/x86_non_dsx_mtl_pwrseq_sm.c
+++ b/zephyr/subsys/ap_pwrseq/x86_non_dsx_mtl_pwrseq_sm.c
@@ -1,4 +1,4 @@
-/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+/* Copyright 2022 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -33,8 +33,8 @@ static void generate_pwrok_handler(void)
power_signal_set(PWR_EC_PCH_SYS_PWROK, all_sys_pwrgd_in);
/* PCH_PWROK is set to combined result of ALL_SYS_PWRGD and SLP_S3 */
- power_signal_set(PWR_PCH_PWROK, all_sys_pwrgd_in &&
- !power_signal_get(PWR_SLP_S3));
+ power_signal_set(PWR_PCH_PWROK,
+ all_sys_pwrgd_in && !power_signal_get(PWR_SLP_S3));
}
/* Chipset specific power state machine handler */