intel/alderlake: Add helper functions for Power Management

Clock Power Management, ASPM and L1 Substates have been
configured the same way since Skylake. The main control to
enable or disable is Kconfig, and then the level can be overridden
in devicetree.

Despite the UPDs remaining the same since Skylake, this is not the
case for Alder Lake, Raptor Lake and Meteor Lake.

Taking `starlabs/starbook` as an example, at the time of this
commit it has PCIEXP_CLK_PM, PCIEXP_ASPM and PCIEXP_L1_SUB_STATE
enabled.

On Comet Lake, this results in the correct configuration, verified
with the lspci command:
```
	LnkCap:	Port #0, Speed 5GT/s, Width x1, ASPM L1, Exit Latency L1 <8us
		ClockPM+ Surprise- LLActRep- BwNot- ASPMOptComp+
	LnkCtl:	ASPM L1 Enabled; RCB 64 bytes, Disabled- CommClk+
		ExtSynch- ClockPM+ AutWidDis- BWInt- AutBWInt-
```
On Raptor Lake:

```
	LnkCap:	Port #0, Speed 16GT/s, Width x4, ASPM L1, Exit Latency L1 <64us
		ClockPM- Surprise- LLActRep- BwNot- ASPMOptComp+
	LnkCtl:	ASPM Disabled; RCB 64 bytes, Disabled- CommClk+
```

Clock Power Management, ASPM and L1 Substates are also not configured
for CPU root ports.

Add helper functions to configure these correctly based on Kconfig, but
retain the capability to override the specific levels from devicetree.

Change-Id: I9db18859f9a04ad4b7c0c3f7992b09e0f9484a81
Signed-off-by: Sean Rhodes <sean@starlabs.systems>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/81638
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nico Huber <nico.h@gmx.de>
This commit is contained in:
Sean Rhodes
2024-04-04 20:02:31 +01:00
committed by Martin Roth
parent c6c75dfbae
commit a25f310830
2 changed files with 88 additions and 38 deletions

View File

@@ -465,44 +465,97 @@ static const SI_PCH_DEVICE_INTERRUPT_CONFIG *pci_irq_to_fsp(size_t *out_count)
} }
/* /*
* Chip config parameter PcieRpL1Substates uses (UPD value + 1) * The PCIe RP ASPM and PCIe L1 Substate UPDs follow the PCI Express Base
* because UPD value of 0 for PcieRpL1Substates means disabled for FSP. * Specification 1.1. The UPDs and their default values are consistent
* In order to ensure that mainboard setting does not disable L1 substates * from Skylake through Meteor Lake. However, the default for CPU ports
* incorrectly, chip config parameter values are offset by 1 with 0 meaning * differs from PCH ports. Use auto and maximum unless overwritten
* use FSP UPD default. get_l1_substate_control() ensures that the right UPD * to make the behaviour consistent.
* value is set in fsp_params. *
* 0: Use FSP UPD default * +-------------------+--------------------------+-----------+-----------+
* 1: Disable L1 substates * | Setting | Option | PCH Ports | CPU Ports |
* 2: Use L1.1 * |-------------------|--------------------------|-----------|-----------|
* 3: Use L1.2 (FSP UPD default) * | PcieRpEnableCpm | Disabled | [Default] | [Default] |
* | | Enabled | | |
* |-------------------|--------------------------|-----------|-----------|
* | PcieRpAspm | PchPcieAspmDisabled | | |
* | | PchPcieAspmL0s | | |
* | | PchPcieAspmL1 | | |
* | | PchPcieAspmL0sL1 | | [Default] |
* | | PchPcieAspmAutoConfig | [Default] | |
* | | PchPcieAspmMax | | |
* |-------------------|--------------------------|-----------|-----------|
* | PcieRpL1Substates | Disabled | | |
* | | PchPcieL1SubstatesL1_1 | | |
* | | PchPcieL1SubstatesL1_1_2 | | [Default] |
* | | PchPcieL1SubstatesMax | [Default] | |
* +-------------------+--------------------------+-----------+-----------+
*/ */
static int get_l1_substate_control(enum L1_substates_control ctl)
static unsigned int adl_aspm_control_to_upd(enum ASPM_control aspm_control)
{ {
/* Disable without Kconfig selected */
if (!CONFIG(PCIEXP_ASPM))
return UPD_INDEX(ASPM_DISABLE);
/* Use auto unless overwritten */
if (!aspm_control)
return UPD_INDEX(ASPM_AUTO);
return UPD_INDEX(aspm_control);
}
static unsigned int adl_l1ss_control_to_upd(enum L1_substates_control l1_substates_control)
{
/* Disable without Kconfig selected */
if (!CONFIG(PCIEXP_ASPM))
return UPD_INDEX(L1_SS_DISABLED);
/* Don't enable UPD if Kconfig not set */
if (!CONFIG(PCIEXP_L1_SUB_STATE))
return UPD_INDEX(L1_SS_DISABLED);
/* L1 Substate should be disabled in compliance mode */
if (CONFIG(SOC_INTEL_COMPLIANCE_TEST_MODE)) if (CONFIG(SOC_INTEL_COMPLIANCE_TEST_MODE))
ctl = L1_SS_DISABLED; return UPD_INDEX(L1_SS_DISABLED);
else if ((ctl > L1_SS_L1_2) || (ctl == L1_SS_FSP_DEFAULT))
ctl = L1_SS_L1_2; /* Use maximum unless overwritten */
return ctl - 1; if (!l1_substates_control)
return UPD_INDEX(L1_SS_L1_2);
return UPD_INDEX(l1_substates_control);
}
static void configure_pch_rp_power_management(FSP_S_CONFIG *s_cfg,
const struct pcie_rp_config *rp_cfg,
unsigned int index)
{
s_cfg->PcieRpEnableCpm[index] = CONFIG(PCIEXP_CLK_PM);
s_cfg->PcieRpAspm[index] = adl_aspm_control_to_upd(rp_cfg->pcie_rp_aspm);
s_cfg->PcieRpL1Substates[index] = adl_l1ss_control_to_upd(rp_cfg->PcieRpL1Substates);
} }
/* /*
* Chip config parameter pcie_rp_aspm uses (UPD value + 1) because * Starting with Alder Lake, UPDs for Clock Power Management were
* a UPD value of 0 for pcie_rp_aspm means disabled. In order to ensure * introduced for the CPU root ports.
* that the mainboard setting does not disable ASPM incorrectly, chip *
* config parameter values are offset by 1 with 0 meaning use FSP UPD default. * CpuPcieClockGating:
* get_aspm_control() ensures that the right UPD value is set in fsp_params. * Disabled
* 0: Use FSP UPD default * Enabled [Default]
* 1: Disable ASPM *
* 2: L0s only * CpuPciePowerGating
* 3: L1 only * Disabled
* 4: L0s and L1 * Enabled [Default]
* 5: Auto configuration *
*/ */
static unsigned int get_aspm_control(enum ASPM_control ctl) static void configure_cpu_rp_power_management(FSP_S_CONFIG *s_cfg,
const struct pcie_rp_config *rp_cfg,
unsigned int index)
{ {
if ((ctl > ASPM_AUTO) || (ctl == ASPM_DEFAULT)) s_cfg->CpuPcieRpEnableCpm[index] = CONFIG(PCIEXP_CLK_PM);
ctl = ASPM_AUTO; s_cfg->CpuPcieClockGating[index] = CONFIG(PCIEXP_CLK_PM);
return ctl - 1; s_cfg->CpuPciePowerGating[index] = CONFIG(PCIEXP_CLK_PM);
s_cfg->CpuPcieRpAspm[index] = adl_aspm_control_to_upd(rp_cfg->pcie_rp_aspm);
s_cfg->CpuPcieRpL1Substates[index] = adl_l1ss_control_to_upd(rp_cfg->PcieRpL1Substates);
} }
/* This function returns the VccIn Aux Imon IccMax values for ADL and RPL /* This function returns the VccIn Aux Imon IccMax values for ADL and RPL
@@ -912,19 +965,16 @@ static void fill_fsps_pcie_params(FSP_S_CONFIG *s_cfg,
if (!(enable_mask & BIT(i))) if (!(enable_mask & BIT(i)))
continue; continue;
const struct pcie_rp_config *rp_cfg = &config->pch_pcie_rp[i]; const struct pcie_rp_config *rp_cfg = &config->pch_pcie_rp[i];
s_cfg->PcieRpL1Substates[i] =
get_l1_substate_control(rp_cfg->PcieRpL1Substates);
s_cfg->PcieRpLtrEnable[i] = !!(rp_cfg->flags & PCIE_RP_LTR); s_cfg->PcieRpLtrEnable[i] = !!(rp_cfg->flags & PCIE_RP_LTR);
s_cfg->PcieRpAdvancedErrorReporting[i] = !!(rp_cfg->flags & PCIE_RP_AER); s_cfg->PcieRpAdvancedErrorReporting[i] = !!(rp_cfg->flags & PCIE_RP_AER);
s_cfg->PcieRpHotPlug[i] = !!(rp_cfg->flags & PCIE_RP_HOTPLUG) s_cfg->PcieRpHotPlug[i] = !!(rp_cfg->flags & PCIE_RP_HOTPLUG)
|| CONFIG(SOC_INTEL_COMPLIANCE_TEST_MODE); || CONFIG(SOC_INTEL_COMPLIANCE_TEST_MODE);
s_cfg->PcieRpClkReqDetect[i] = !!(rp_cfg->flags & PCIE_RP_CLK_REQ_DETECT); s_cfg->PcieRpClkReqDetect[i] = !!(rp_cfg->flags & PCIE_RP_CLK_REQ_DETECT);
if (rp_cfg->pcie_rp_aspm)
s_cfg->PcieRpAspm[i] = get_aspm_control(rp_cfg->pcie_rp_aspm);
/* PcieRpSlotImplemented default to 1 (slot implemented) in FSP; 0: built-in */ /* PcieRpSlotImplemented default to 1 (slot implemented) in FSP; 0: built-in */
if (!!(rp_cfg->flags & PCIE_RP_BUILT_IN)) if (!!(rp_cfg->flags & PCIE_RP_BUILT_IN))
s_cfg->PcieRpSlotImplemented[i] = 0; s_cfg->PcieRpSlotImplemented[i] = 0;
s_cfg->PcieRpDetectTimeoutMs[i] = rp_cfg->pcie_rp_detect_timeout_ms; s_cfg->PcieRpDetectTimeoutMs[i] = rp_cfg->pcie_rp_detect_timeout_ms;
configure_pch_rp_power_management(s_cfg, rp_cfg, i);
} }
s_cfg->PcieComplianceTestMode = CONFIG(SOC_INTEL_COMPLIANCE_TEST_MODE); s_cfg->PcieComplianceTestMode = CONFIG(SOC_INTEL_COMPLIANCE_TEST_MODE);
@@ -976,19 +1026,16 @@ static void fill_fsps_cpu_pcie_params(FSP_S_CONFIG *s_cfg,
continue; continue;
const struct pcie_rp_config *rp_cfg = &config->cpu_pcie_rp[i]; const struct pcie_rp_config *rp_cfg = &config->cpu_pcie_rp[i];
s_cfg->CpuPcieRpL1Substates[i] =
get_l1_substate_control(rp_cfg->PcieRpL1Substates);
s_cfg->CpuPcieRpLtrEnable[i] = !!(rp_cfg->flags & PCIE_RP_LTR); s_cfg->CpuPcieRpLtrEnable[i] = !!(rp_cfg->flags & PCIE_RP_LTR);
s_cfg->CpuPcieRpAdvancedErrorReporting[i] = !!(rp_cfg->flags & PCIE_RP_AER); s_cfg->CpuPcieRpAdvancedErrorReporting[i] = !!(rp_cfg->flags & PCIE_RP_AER);
s_cfg->CpuPcieRpHotPlug[i] = !!(rp_cfg->flags & PCIE_RP_HOTPLUG) s_cfg->CpuPcieRpHotPlug[i] = !!(rp_cfg->flags & PCIE_RP_HOTPLUG)
|| CONFIG(SOC_INTEL_COMPLIANCE_TEST_MODE); || CONFIG(SOC_INTEL_COMPLIANCE_TEST_MODE);
s_cfg->CpuPcieRpDetectTimeoutMs[i] = rp_cfg->pcie_rp_detect_timeout_ms; s_cfg->CpuPcieRpDetectTimeoutMs[i] = rp_cfg->pcie_rp_detect_timeout_ms;
s_cfg->PtmEnabled[i] = 0; s_cfg->PtmEnabled[i] = 0;
if (rp_cfg->pcie_rp_aspm)
s_cfg->CpuPcieRpAspm[i] = get_aspm_control(rp_cfg->pcie_rp_aspm);
if (!!(rp_cfg->flags & PCIE_RP_BUILT_IN)) if (!!(rp_cfg->flags & PCIE_RP_BUILT_IN))
s_cfg->CpuPcieRpSlotImplemented[i] = 0; s_cfg->CpuPcieRpSlotImplemented[i] = 0;
configure_cpu_rp_power_management(s_cfg, rp_cfg, i);
} }
s_cfg->CpuPcieComplianceTestMode = CONFIG(SOC_INTEL_COMPLIANCE_TEST_MODE); s_cfg->CpuPcieComplianceTestMode = CONFIG(SOC_INTEL_COMPLIANCE_TEST_MODE);
} }

View File

@@ -37,6 +37,9 @@ enum pcie_clk_src_flags {
PCIE_CLK_LAN = (1 << 1), PCIE_CLK_LAN = (1 << 1),
}; };
/* coreboot enums are off-by-1 to allow for no config in devicetree */
#define UPD_INDEX(upd) (upd - 1)
/* This enum is for passing into an FSP UPD, typically PcieRpL1Substates */ /* This enum is for passing into an FSP UPD, typically PcieRpL1Substates */
enum L1_substates_control { enum L1_substates_control {
L1_SS_FSP_DEFAULT, L1_SS_FSP_DEFAULT,