soc/intel/alderlake: provide a list of D-states to enter LPM
Implement sub-function 1 (Get Device Constraints) of the Low Power S0 Idle Device-Specific Method (_DSM). This provides a way in which to describe various devices required D-states to enter LPM (S0ix). The information can be used to help in diagnostics and understanding of S0ix entry failure. Values were derived from Intel document 595644 (rev 0.45) and the ADL FSP sample ASL. This implementation adds support for ADL. Other SoC's could be ported to be included as well. If they aren't, they will default to the existing behavior of a single hardcoded device to ensure compatibility with Windows. TEST=Built and tested on brya by verifying SSDT contents Change-Id: Ibe46a0583c522a8adf0a015cd3a698f694482437 Signed-off-by: Tarun Tuli <taruntuli@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/63969 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org> Reviewed-by: Lance Zhao
This commit is contained in:
parent
da958d679d
commit
c66ea98577
|
@ -1234,6 +1234,8 @@ void acpi_create_ssdt_generator(acpi_header_t *ssdt, const char *oem_table_id);
|
||||||
void acpi_write_bert(acpi_bert_t *bert, uintptr_t region, size_t length);
|
void acpi_write_bert(acpi_bert_t *bert, uintptr_t region, size_t length);
|
||||||
void acpi_create_fadt(acpi_fadt_t *fadt, acpi_facs_t *facs, void *dsdt);
|
void acpi_create_fadt(acpi_fadt_t *fadt, acpi_facs_t *facs, void *dsdt);
|
||||||
|
|
||||||
|
void soc_lpi_get_constraints(void *unused);
|
||||||
|
|
||||||
void acpi_fill_fadt(acpi_fadt_t *fadt);
|
void acpi_fill_fadt(acpi_fadt_t *fadt);
|
||||||
void arch_fill_fadt(acpi_fadt_t *fadt);
|
void arch_fill_fadt(acpi_fadt_t *fadt);
|
||||||
void soc_fill_fadt(acpi_fadt_t *fadt);
|
void soc_fill_fadt(acpi_fadt_t *fadt);
|
||||||
|
|
|
@ -18,8 +18,16 @@
|
||||||
#include <soc/pm.h>
|
#include <soc/pm.h>
|
||||||
#include <soc/soc_chip.h>
|
#include <soc/soc_chip.h>
|
||||||
#include <soc/systemagent.h>
|
#include <soc/systemagent.h>
|
||||||
|
#include <cpu/cpu.h>
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define DEFAULT_CPU_D_STATE D0
|
||||||
|
#define LPI_STATES_ALL 0xff
|
||||||
|
#define LPI_REVISION 0
|
||||||
|
#define LPI_ENABLED 1
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List of supported C-states in this processor.
|
* List of supported C-states in this processor.
|
||||||
*/
|
*/
|
||||||
|
@ -110,6 +118,14 @@ static int cstate_set_s0ix[] = {
|
||||||
C_STATE_C10
|
C_STATE_C10
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum dev_sleep_states {
|
||||||
|
D0, /* 0 */
|
||||||
|
D1, /* 1 */
|
||||||
|
D2, /* 2 */
|
||||||
|
D3, /* 3 */
|
||||||
|
NONE
|
||||||
|
};
|
||||||
|
|
||||||
const acpi_cstate_t *soc_get_cstate_map(size_t *entries)
|
const acpi_cstate_t *soc_get_cstate_map(size_t *entries)
|
||||||
{
|
{
|
||||||
static acpi_cstate_t map[MAX(ARRAY_SIZE(cstate_set_s0ix),
|
static acpi_cstate_t map[MAX(ARRAY_SIZE(cstate_set_s0ix),
|
||||||
|
@ -164,6 +180,162 @@ void soc_fill_fadt(acpi_fadt_t *fadt)
|
||||||
fadt->flags |= ACPI_FADT_LOW_PWR_IDLE_S0;
|
fadt->flags |= ACPI_FADT_LOW_PWR_IDLE_S0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
uint8_t pci_dev;
|
||||||
|
enum dev_sleep_states min_sleep_state;
|
||||||
|
} min_pci_sleep_states[] = {
|
||||||
|
{ SA_DEVFN_ROOT, D3 },
|
||||||
|
{ SA_DEVFN_CPU_PCIE1_0, D3 },
|
||||||
|
{ SA_DEVFN_IGD, D3 },
|
||||||
|
{ SA_DEVFN_DPTF, D3 },
|
||||||
|
{ SA_DEVFN_IPU, D3 },
|
||||||
|
{ SA_DEVFN_CPU_PCIE6_0, D3 },
|
||||||
|
{ SA_DEVFN_CPU_PCIE6_2, D3 },
|
||||||
|
{ SA_DEVFN_TBT0, D3 },
|
||||||
|
{ SA_DEVFN_TBT1, D3 },
|
||||||
|
{ SA_DEVFN_TBT2, D3 },
|
||||||
|
{ SA_DEVFN_TBT3, D3 },
|
||||||
|
{ SA_DEVFN_GNA, D3 },
|
||||||
|
{ SA_DEVFN_TCSS_XHCI, D3 },
|
||||||
|
{ SA_DEVFN_TCSS_XDCI, D3 },
|
||||||
|
{ SA_DEVFN_TCSS_DMA0, D3 },
|
||||||
|
{ SA_DEVFN_TCSS_DMA1, D3 },
|
||||||
|
{ SA_DEVFN_VMD, D3 },
|
||||||
|
{ PCH_DEVFN_I2C6, D3 },
|
||||||
|
{ PCH_DEVFN_I2C7, D3 },
|
||||||
|
{ PCH_DEVFN_THC0, D3 },
|
||||||
|
{ PCH_DEVFN_THC1, D3 },
|
||||||
|
{ PCH_DEVFN_XHCI, D3 },
|
||||||
|
{ PCH_DEVFN_USBOTG, D3 },
|
||||||
|
{ PCH_DEVFN_SRAM, D3 },
|
||||||
|
{ PCH_DEVFN_CNVI_WIFI, D3 },
|
||||||
|
{ PCH_DEVFN_I2C0, D3 },
|
||||||
|
{ PCH_DEVFN_I2C1, D3 },
|
||||||
|
{ PCH_DEVFN_I2C2, D3 },
|
||||||
|
{ PCH_DEVFN_I2C3, D3 },
|
||||||
|
{ PCH_DEVFN_CSE, D0 },
|
||||||
|
{ PCH_DEVFN_SATA, D3 },
|
||||||
|
{ PCH_DEVFN_I2C4, D3 },
|
||||||
|
{ PCH_DEVFN_I2C5, D3 },
|
||||||
|
{ PCH_DEVFN_UART2, D3 },
|
||||||
|
{ PCH_DEVFN_PCIE1, D0 },
|
||||||
|
{ PCH_DEVFN_PCIE2, D0 },
|
||||||
|
{ PCH_DEVFN_PCIE3, D0 },
|
||||||
|
{ PCH_DEVFN_PCIE4, D0 },
|
||||||
|
{ PCH_DEVFN_PCIE5, D0 },
|
||||||
|
{ PCH_DEVFN_PCIE6, D0 },
|
||||||
|
{ PCH_DEVFN_PCIE7, D0 },
|
||||||
|
{ PCH_DEVFN_PCIE8, D0 },
|
||||||
|
{ PCH_DEVFN_PCIE9, D0 },
|
||||||
|
{ PCH_DEVFN_PCIE10, D0 },
|
||||||
|
{ PCH_DEVFN_PCIE11, D0 },
|
||||||
|
{ PCH_DEVFN_PCIE12, D0 },
|
||||||
|
{ PCH_DEVFN_UART0, D3 },
|
||||||
|
{ PCH_DEVFN_UART1, D3 },
|
||||||
|
{ PCH_DEVFN_GSPI0, D3 },
|
||||||
|
{ PCH_DEVFN_GSPI1, D3 },
|
||||||
|
{ PCH_DEVFN_ESPI, D0 },
|
||||||
|
{ PCH_DEVFN_PMC, D0 },
|
||||||
|
{ PCH_DEVFN_HDA, D0 },
|
||||||
|
{ PCH_DEVFN_SPI, D3 },
|
||||||
|
{ PCH_DEVFN_GBE, D3 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum dev_sleep_states get_min_sleep_state(const struct device *dev)
|
||||||
|
{
|
||||||
|
if (!is_dev_enabled(dev))
|
||||||
|
return NONE;
|
||||||
|
|
||||||
|
switch (dev->path.type) {
|
||||||
|
case DEVICE_PATH_APIC:
|
||||||
|
return DEFAULT_CPU_D_STATE;
|
||||||
|
|
||||||
|
case DEVICE_PATH_PCI:
|
||||||
|
for (size_t i = 0; i < ARRAY_SIZE(min_pci_sleep_states); i++)
|
||||||
|
if (min_pci_sleep_states[i].pci_dev == dev->path.pci.devfn)
|
||||||
|
return min_pci_sleep_states[i].min_sleep_state;
|
||||||
|
printk(BIOS_WARNING, "Unknown min d_state for %x\n", dev->path.pci.devfn);
|
||||||
|
return NONE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate the LPI constraint table and return the number of devices included */
|
||||||
|
void soc_lpi_get_constraints(void *unused)
|
||||||
|
{
|
||||||
|
unsigned int num_entries;
|
||||||
|
const struct device *dev;
|
||||||
|
enum dev_sleep_states min_sleep_state;
|
||||||
|
|
||||||
|
num_entries = 0;
|
||||||
|
|
||||||
|
for (dev = all_devices; dev; dev = dev->next) {
|
||||||
|
if (get_min_sleep_state(dev) != NONE)
|
||||||
|
num_entries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
acpigen_emit_byte(RETURN_OP);
|
||||||
|
acpigen_write_package(num_entries);
|
||||||
|
|
||||||
|
for (dev = all_devices; dev; dev = dev->next) {
|
||||||
|
min_sleep_state = get_min_sleep_state(dev);
|
||||||
|
if (min_sleep_state == NONE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
acpigen_write_package(3);
|
||||||
|
{
|
||||||
|
/* Emit the device path */
|
||||||
|
switch (dev->path.type) {
|
||||||
|
case DEVICE_PATH_PCI:
|
||||||
|
acpigen_emit_namestring(acpi_device_path(dev));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEVICE_PATH_APIC:
|
||||||
|
char path[32];
|
||||||
|
|
||||||
|
/* Lookup CPU id */
|
||||||
|
for (size_t i = 0; i < CONFIG_MAX_CPUS; i++) {
|
||||||
|
if (cpu_get_apic_id(i) == dev->path.apic.apic_id) {
|
||||||
|
snprintf(path, sizeof(path),
|
||||||
|
CONFIG_ACPI_CPU_STRING, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
acpigen_emit_namestring(path);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Unhandled */
|
||||||
|
printk(BIOS_WARNING,
|
||||||
|
"Unhandled device path type %d\n", dev->path.type);
|
||||||
|
acpigen_emit_namestring(NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
acpigen_write_integer(LPI_ENABLED);
|
||||||
|
acpigen_write_package(2);
|
||||||
|
{
|
||||||
|
acpigen_write_integer(LPI_REVISION);
|
||||||
|
acpigen_write_package(2); /* no optional device info */
|
||||||
|
{
|
||||||
|
/* Assume constraints apply to all entries */
|
||||||
|
acpigen_write_integer(LPI_STATES_ALL);
|
||||||
|
acpigen_write_integer(min_sleep_state); /* min D-state */
|
||||||
|
}
|
||||||
|
acpigen_write_package_end();
|
||||||
|
}
|
||||||
|
acpigen_write_package_end();
|
||||||
|
}
|
||||||
|
acpigen_write_package_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
acpigen_write_package_end();
|
||||||
|
printk(BIOS_INFO, "Returning SoC specific constraint package for %d devices\n", num_entries);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t soc_read_sci_irq_select(void)
|
uint32_t soc_read_sci_irq_select(void)
|
||||||
{
|
{
|
||||||
return read32p(soc_read_pmc_base() + IRQ_REG);
|
return read32p(soc_read_pmc_base() + IRQ_REG);
|
||||||
|
|
|
@ -77,9 +77,10 @@ static void read_pmc_lpm_requirements(const struct soc_pmc_lpm *lpm,
|
||||||
* device, one that is known to exist, i.e. ACPI_CPU_STRING. expects at least
|
* device, one that is known to exist, i.e. ACPI_CPU_STRING. expects at least
|
||||||
* one device and crashes without it with a bluescreen.
|
* one device and crashes without it with a bluescreen.
|
||||||
*/
|
*/
|
||||||
static void lpi_get_constraints(void *unused)
|
__weak void soc_lpi_get_constraints(void *unused)
|
||||||
{
|
{
|
||||||
char path[16];
|
char path[16];
|
||||||
|
printk(BIOS_INFO, "Returning default LPI constraint package\n");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return (Package() {
|
* Return (Package() {
|
||||||
|
@ -183,7 +184,7 @@ static void lpi_display_off(void *unused)
|
||||||
|
|
||||||
static void (*lpi_s0_helpers[])(void *) = {
|
static void (*lpi_s0_helpers[])(void *) = {
|
||||||
NULL, /* enumerate functions (autogenerated) */
|
NULL, /* enumerate functions (autogenerated) */
|
||||||
lpi_get_constraints, /* get device constraints */
|
soc_lpi_get_constraints,/* get device constraints */
|
||||||
NULL, /* get crash dump device */
|
NULL, /* get crash dump device */
|
||||||
lpi_display_off, /* display off notify */
|
lpi_display_off, /* display off notify */
|
||||||
lpi_display_on, /* display on notify */
|
lpi_display_on, /* display on notify */
|
||||||
|
|
Loading…
Reference in New Issue