From 186250f68e432f0c32b0c9909be6008cbc6aca47 Mon Sep 17 00:00:00 2001 From: V Sowmya Date: Wed, 2 Sep 2020 16:40:24 +0530 Subject: common/block/pmc: Add a check to program the PchPmPwrCycDur This patch adds a check to avoid violating the PCH EDS recommendation that the PchPmPwrCycDur will never be smaller than the the SLP_Sx assertion widths. This code was initially added for cannonlake and now moving it to common code since the same check will be used to program the PchPmPwrCycDur for Jasperlake and Tigerlake. Change-Id: Ie7d5f54939c5eb1f885d303f75a04958b9d77f4d Signed-off-by: V Sowmya Reviewed-on: https://review.coreboot.org/c/coreboot/+/45028 Reviewed-by: Tim Wawrzynczak Tested-by: build bot (Jenkins) --- .../common/block/include/intelblocks/pmclib.h | 9 ++ src/soc/intel/common/block/pmc/pmclib.c | 127 +++++++++++++++++++++ 2 files changed, 136 insertions(+) (limited to 'src/soc/intel') 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; +} -- cgit v1.2.3