diff options
author | Sridhar Siricilla <sridhar.siricilla@intel.com> | 2020-06-17 00:38:20 +0530 |
---|---|---|
committer | Edward O'Callaghan <quasisec@chromium.org> | 2020-06-25 13:43:01 +0000 |
commit | e40b9481e616f8b8a899ac9bb9fbf1cda20d7114 (patch) | |
tree | 2affa524a52a7c4b3edf8cf9c0469f4e3139720f | |
parent | d95dba0ce34df0a0b61e70fa89470ab113e2e918 (diff) |
soc/intel/cannonlake: Add PchPmPwrCycDur to chip options
Add PchPmPwrCycDur to chip options to control the UPD FSPS PchPmPwrCycDur
from devicetree. The UPD determines the minimum time a platform will stay
in reset during host partition reset with power cycle or global reset.
This patch also ensures configured PchPmPwrCycDur value doesn't violate
the PCH EDS specification.
TEST=Verified on Hatch and Puff boards
Signed-off-by: Sridhar Siricilla <sridhar.siricilla@intel.com>
Change-Id: I55e836c78fab34e34d57b04428a1498b7dc7174b
Reviewed-on: https://review.coreboot.org/c/coreboot/+/42440
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Edward O'Callaghan <quasisec@chromium.org>
-rw-r--r-- | src/soc/intel/cannonlake/chip.h | 17 | ||||
-rw-r--r-- | src/soc/intel/cannonlake/fsp_params.c | 127 |
2 files changed, 144 insertions, 0 deletions
diff --git a/src/soc/intel/cannonlake/chip.h b/src/soc/intel/cannonlake/chip.h index 3ebbc5e38d..57922e131c 100644 --- a/src/soc/intel/cannonlake/chip.h +++ b/src/soc/intel/cannonlake/chip.h @@ -315,6 +315,23 @@ struct soc_intel_cannonlake_config { uint8_t PchPmSlpAMinAssert; /* + * PCH PM Reset Power Cycle Duration + * 0 = 4s + * 1 = 1s + * 2 = 2s + * 3 = 3s + * 4 = 4s (default) + * + * NOTE: Duration programmed in the PchPmPwrCycDur should never be smaller than the + * stretch duration programmed in the following registers - + * - GEN_PMCON_A.SLP_S3_MIN_ASST_WDTH (PchPmSlpS3MinAssert) + * - GEN_PMCON_A.S4MAW (PchPmSlpS4MinAssert) + * - PM_CFG.SLP_A_MIN_ASST_WDTH (PchPmSlpAMinAssert) + * - PM_CFG.SLP_LAN_MIN_ASST_WDTH + */ + uint8_t PchPmPwrCycDur; + + /* * SerialIO device mode selection: * * Device index: diff --git a/src/soc/intel/cannonlake/fsp_params.c b/src/soc/intel/cannonlake/fsp_params.c index a3b5588b77..bd2d7fc2d6 100644 --- a/src/soc/intel/cannonlake/fsp_params.c +++ b/src/soc/intel/cannonlake/fsp_params.c @@ -32,6 +32,39 @@ static const pci_devfn_t serial_io_dev[] = { PCH_DEVFN_UART2 }; +/* List of Minimum Assertion durations in microseconds */ +enum min_assrt_dur { + MinAssrtDur0s = 0, + MinAssrtDur60us = 60, + MinAssrtDur1ms = 1000, + MinAssrtDur50ms = 50000, + MinAssrtDur98ms = 98000, + MinAssrtDur500ms = 500000, + MinAssrtDur1s = 1000000, + MinAssrtDur2s = 2000000, + MinAssrtDur3s = 3000000, + MinAssrtDur4s = 4000000, +}; + + +/* Signal Assertion duration values */ +struct cfg_assrt_dur { + /* Minimum assertion duration of SLP_A signal */ + enum min_assrt_dur slp_a; + + /* Minimum assertion duration of SLP_4 signal */ + enum min_assrt_dur slp_s4; + + /* Minimum assertion duration of SLP_3 signal */ + enum min_assrt_dur slp_s3; + + /* PCH PM Power Cycle duration */ + enum min_assrt_dur pm_pwr_cyc_dur; +}; + +/* Default value of PchPmPwrCycDur */ +#define PCH_PM_PWR_CYC_DUR 4 + /* * Given an enum for PCH_SERIAL_IO_MODE, 1 needs to be subtracted to get the FSP * UPD expected value for Serial IO since valid enum index starts from 1. @@ -57,6 +90,93 @@ static uint8_t get_param_value(const config_t *config, uint32_t dev_offset) } #if CONFIG(SOC_INTEL_COMETLAKE) +static enum min_assrt_dur get_high_asst_width(const struct cfg_assrt_dur *cfg_assrt_dur) +{ + enum min_assrt_dur max_assert_dur = cfg_assrt_dur->slp_s4; + + if (max_assert_dur < cfg_assrt_dur->slp_s3) + max_assert_dur = cfg_assrt_dur->slp_s3; + + if (max_assert_dur < cfg_assrt_dur->slp_a) + max_assert_dur = cfg_assrt_dur->slp_a; + + return max_assert_dur; +} + +static void get_min_assrt_dur(uint8_t slp_s4_min_asst, uint8_t slp_s3_min_asst, + uint8_t slp_a_min_asst, uint8_t pm_pwr_cyc_dur, + struct cfg_assrt_dur *cfg_assrt_dur) +{ + /* + * Ensure slp_x_dur_list[] elements are in sync with devicetree config to FSP encoded + * values. + * slp_s4_asst_dur_list : 1s, 1s, 2s, 3s, 4s(Default) + */ + const enum min_assrt_dur slp_s4_asst_dur_list[] = { + MinAssrtDur1s, MinAssrtDur1s, MinAssrtDur2s, MinAssrtDur3s, MinAssrtDur4s + }; + + /* slp_s3_asst_dur_list: 50ms, 60us, 50ms (Default), 2s */ + const enum min_assrt_dur slp_s3_asst_dur_list[] = { + MinAssrtDur50ms, MinAssrtDur60us, MinAssrtDur50ms, MinAssrtDur2s + }; + + /* slp_a_asst_dur_list: 2s, 0s, 4s, 98ms, 2s(Default) */ + const enum min_assrt_dur slp_a_asst_dur_list[] = { + MinAssrtDur2s, MinAssrtDur0s, MinAssrtDur4s, MinAssrtDur98ms, MinAssrtDur2s + }; + + /* pm_pwr_cyc_dur_list: 4s(Default), 1s, 2s, 3s, 4s */ + const enum min_assrt_dur pm_pwr_cyc_dur_list[] = { + MinAssrtDur4s, MinAssrtDur1s, MinAssrtDur2s, MinAssrtDur3s, MinAssrtDur4s + }; + + /* Get signal assertion width */ + if (slp_s4_min_asst < ARRAY_SIZE(slp_s4_asst_dur_list)) + cfg_assrt_dur->slp_s4 = slp_s4_asst_dur_list[slp_s4_min_asst]; + + if (slp_s3_min_asst < ARRAY_SIZE(slp_s3_asst_dur_list)) + cfg_assrt_dur->slp_s3 = slp_s3_asst_dur_list[slp_s3_min_asst]; + + if (slp_a_min_asst < ARRAY_SIZE(slp_a_asst_dur_list)) + cfg_assrt_dur->slp_a = slp_a_asst_dur_list[slp_a_min_asst]; + + if (pm_pwr_cyc_dur < ARRAY_SIZE(pm_pwr_cyc_dur_list)) + cfg_assrt_dur->pm_pwr_cyc_dur = pm_pwr_cyc_dur_list[pm_pwr_cyc_dur]; +} + + +static uint8_t get_pm_pwr_cyc_dur(uint8_t slp_s4_min_asst, uint8_t slp_s3_min_asst, + uint8_t slp_a_min_asst, uint8_t pm_pwr_cyc_dur) +{ + /* Sets default minimum asserton duration values */ + struct cfg_assrt_dur cfg_assrt_dur = { + .slp_a = MinAssrtDur2s, + .slp_s4 = MinAssrtDur4s, + .slp_s3 = MinAssrtDur50ms, + .pm_pwr_cyc_dur = MinAssrtDur4s + }; + + enum min_assrt_dur high_asst_width; + + /* Convert assertion durations from register-encoded to microseconds */ + get_min_assrt_dur(slp_s4_min_asst, slp_s3_min_asst, slp_a_min_asst, pm_pwr_cyc_dur, + &cfg_assrt_dur); + + /* Get the higher assertion duration among PCH EDS specified signals for pwr_cyc_dur */ + high_asst_width = get_high_asst_width(&cfg_assrt_dur); + + if (cfg_assrt_dur.pm_pwr_cyc_dur >= high_asst_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; +} + + static void parse_devicetree_param(const config_t *config, FSP_S_CONFIG *params) { uint32_t dev_offset = 0; @@ -412,6 +532,13 @@ void platform_fsp_silicon_init_params_cb(FSPS_UPD *supd) if (config->PchPmSlpAMinAssert) params->PchPmSlpAMinAssert = config->PchPmSlpAMinAssert; +#if CONFIG(SOC_INTEL_COMETLAKE) + if (config->PchPmPwrCycDur) + params->PchPmPwrCycDur = get_pm_pwr_cyc_dur(config->PchPmSlpS4MinAssert, + config->PchPmSlpS3MinAssert, config->PchPmSlpAMinAssert, + config->PchPmPwrCycDur); +#endif + /* Set TccActivationOffset */ tconfig->TccActivationOffset = config->tcc_offset; |