summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/soc/intel/common/block/include/intelblocks/pmclib.h9
-rw-r--r--src/soc/intel/common/block/pmc/pmclib.c127
2 files changed, 136 insertions, 0 deletions
diff --git a/src/soc/intel/common/block/include/intelblocks/pmclib.h b/src/soc/intel/common/block/include/intelblocks/pmclib.h
index 2b06a504d4..2123c4a6b7 100644
--- a/src/soc/intel/common/block/include/intelblocks/pmclib.h
+++ b/src/soc/intel/common/block/include/intelblocks/pmclib.h
@@ -220,4 +220,13 @@ void pmc_soc_set_afterg3_en(bool on);
*/
void pmc_set_power_failure_state(bool target_on);
+/*
+ * This function ensures that the duration programmed in the PchPmPwrCycDur will never be
+ * smaller than the SLP_Sx assertion widths.
+ * If the pm_pwr_cyc_dur is less than any of the SLP_Sx assertion widths then it returns the
+ * default value PCH_PM_PWR_CYC_DUR.
+ */
+uint8_t get_pm_pwr_cyc_dur(uint8_t slp_s4_min_assert, uint8_t slp_s3_min_assert,
+ uint8_t slp_a_min_assert, uint8_t pm_pwr_cyc_dur);
+
#endif /* SOC_INTEL_COMMON_BLOCK_PMCLIB_H */
diff --git a/src/soc/intel/common/block/pmc/pmclib.c b/src/soc/intel/common/block/pmc/pmclib.c
index 40d407bc78..ad9c4fec3d 100644
--- a/src/soc/intel/common/block/pmc/pmclib.c
+++ b/src/soc/intel/common/block/pmc/pmclib.c
@@ -18,6 +18,38 @@
static struct chipset_power_state power_state;
+/* List of Minimum Assertion durations in microseconds */
+enum min_assert_dur {
+ MinAssertDur0s = 0,
+ MinAssertDur60us = 60,
+ MinAssertDur1ms = 1000,
+ MinAssertDur50ms = 50000,
+ MinAssertDur98ms = 98000,
+ MinAssertDur500ms = 500000,
+ MinAssertDur1s = 1000000,
+ MinAssertDur2s = 2000000,
+ MinAssertDur3s = 3000000,
+ MinAssertDur4s = 4000000,
+};
+
+/* Signal Assertion duration values */
+struct cfg_assert_dur {
+ /* Minimum assertion duration of SLP_A signal */
+ enum min_assert_dur slp_a;
+
+ /* Minimum assertion duration of SLP_4 signal */
+ enum min_assert_dur slp_s4;
+
+ /* Minimum assertion duration of SLP_3 signal */
+ enum min_assert_dur slp_s3;
+
+ /* PCH PM Power Cycle duration */
+ enum min_assert_dur pm_pwr_cyc_dur;
+};
+
+/* Default value of PchPmPwrCycDur */
+#define PCH_PM_PWR_CYC_DUR 0
+
struct chipset_power_state *pmc_get_power_state(void)
{
struct chipset_power_state *ptr = NULL;
@@ -573,3 +605,98 @@ void pmc_set_power_failure_state(const bool target_on)
pmc_soc_set_afterg3_en(on);
}
+
+/* This function returns the highest assertion duration of the SLP_Sx assertion widths */
+static enum min_assert_dur get_high_assert_width(const struct cfg_assert_dur *cfg_assert_dur)
+{
+ enum min_assert_dur max_assert_dur = cfg_assert_dur->slp_s4;
+
+ if (max_assert_dur < cfg_assert_dur->slp_s3)
+ max_assert_dur = cfg_assert_dur->slp_s3;
+
+ if (max_assert_dur < cfg_assert_dur->slp_a)
+ max_assert_dur = cfg_assert_dur->slp_a;
+
+ return max_assert_dur;
+}
+
+/* This function converts assertion durations from register-encoded to microseconds */
+static void get_min_assert_dur(uint8_t slp_s4_min_assert, uint8_t slp_s3_min_assert,
+ uint8_t slp_a_min_assert, uint8_t pm_pwr_cyc_dur,
+ struct cfg_assert_dur *cfg_assert_dur)
+{
+ /*
+ * Ensure slp_x_dur_list[] elements in the devicetree config are in sync with
+ * FSP encoded values.
+ */
+
+ /* slp_s4_assert_dur_list : 1s, 1s(default), 2s, 3s, 4s */
+ const enum min_assert_dur slp_s4_assert_dur_list[] = {
+ MinAssertDur1s, MinAssertDur1s, MinAssertDur2s, MinAssertDur3s, MinAssertDur4s
+ };
+
+ /* slp_s3_assert_dur_list: 50ms, 60us, 1ms, 50ms (Default), 2s */
+ const enum min_assert_dur slp_s3_assert_dur_list[] = {
+ MinAssertDur50ms, MinAssertDur60us, MinAssertDur1ms, MinAssertDur50ms,
+ MinAssertDur2s
+ };
+
+ /* slp_a_assert_dur_list: 2s, 0s, 4s, 98ms, 2s(Default) */
+ const enum min_assert_dur slp_a_assert_dur_list[] = {
+ MinAssertDur2s, MinAssertDur0s, MinAssertDur4s, MinAssertDur98ms, MinAssertDur2s
+ };
+
+ /* pm_pwr_cyc_dur_list: 4s(Default), 1s, 2s, 3s, 4s */
+ const enum min_assert_dur pm_pwr_cyc_dur_list[] = {
+ MinAssertDur4s, MinAssertDur1s, MinAssertDur2s, MinAssertDur3s, MinAssertDur4s
+ };
+
+ /* Get signal assertion width */
+ if (slp_s4_min_assert < ARRAY_SIZE(slp_s4_assert_dur_list))
+ cfg_assert_dur->slp_s4 = slp_s4_assert_dur_list[slp_s4_min_assert];
+
+ if (slp_s3_min_assert < ARRAY_SIZE(slp_s3_assert_dur_list))
+ cfg_assert_dur->slp_s3 = slp_s3_assert_dur_list[slp_s3_min_assert];
+
+ if (slp_a_min_assert < ARRAY_SIZE(slp_a_assert_dur_list))
+ cfg_assert_dur->slp_a = slp_a_assert_dur_list[slp_a_min_assert];
+
+ if (pm_pwr_cyc_dur < ARRAY_SIZE(pm_pwr_cyc_dur_list))
+ cfg_assert_dur->pm_pwr_cyc_dur = pm_pwr_cyc_dur_list[pm_pwr_cyc_dur];
+}
+
+/*
+ * This function ensures that the duration programmed in the PchPmPwrCycDur will never be
+ * smaller than the SLP_Sx assertion widths.
+ * If the pm_pwr_cyc_dur is less than any of the SLP_Sx assertion widths then it returns the
+ * default value PCH_PM_PWR_CYC_DUR.
+ */
+uint8_t get_pm_pwr_cyc_dur(uint8_t slp_s4_min_assert, uint8_t slp_s3_min_assert,
+ uint8_t slp_a_min_assert, uint8_t pm_pwr_cyc_dur)
+{
+ /* Set default values for the minimum assertion duration */
+ struct cfg_assert_dur cfg_assert_dur = {
+ .slp_a = MinAssertDur2s,
+ .slp_s4 = MinAssertDur1s,
+ .slp_s3 = MinAssertDur50ms,
+ .pm_pwr_cyc_dur = MinAssertDur4s
+ };
+
+ enum min_assert_dur high_assert_width;
+
+ /* Convert assertion durations from register-encoded to microseconds */
+ get_min_assert_dur(slp_s4_min_assert, slp_s3_min_assert, slp_a_min_assert,
+ pm_pwr_cyc_dur, &cfg_assert_dur);
+
+ /* Get the highest assertion duration among PCH EDS specified signals for pwr_cyc_dur */
+ high_assert_width = get_high_assert_width(&cfg_assert_dur);
+
+ if (cfg_assert_dur.pm_pwr_cyc_dur >= high_assert_width)
+ return pm_pwr_cyc_dur;
+
+ printk(BIOS_DEBUG,
+ "Set PmPwrCycDur to 4s as configured PmPwrCycDur (%d) violates PCH EDS "
+ "spec\n", pm_pwr_cyc_dur);
+
+ return PCH_PM_PWR_CYC_DUR;
+}