diff options
Diffstat (limited to 'src/soc/intel/common/block')
-rw-r--r-- | src/soc/intel/common/block/acpi/acpi.c | 2 | ||||
-rw-r--r-- | src/soc/intel/common/block/acpi/pep.c | 122 | ||||
-rw-r--r-- | src/soc/intel/common/block/include/intelblocks/acpi.h | 27 |
3 files changed, 146 insertions, 5 deletions
diff --git a/src/soc/intel/common/block/acpi/acpi.c b/src/soc/intel/common/block/acpi/acpi.c index 010f23d287..4b3cb8a50b 100644 --- a/src/soc/intel/common/block/acpi/acpi.c +++ b/src/soc/intel/common/block/acpi/acpi.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include <acpi/acpi.h> #include <acpi/acpi_pm.h> #include <acpi/acpigen.h> #include <arch/ioapic.h> @@ -69,7 +70,6 @@ static unsigned long acpi_madt_irq_overrides(unsigned long current) current += acpi_create_madt_irqoverride((void *)current, 0, sci, sci, flags); - return current; } diff --git a/src/soc/intel/common/block/acpi/pep.c b/src/soc/intel/common/block/acpi/pep.c index 2ba9f94573..2dd094908e 100644 --- a/src/soc/intel/common/block/acpi/pep.c +++ b/src/soc/intel/common/block/acpi/pep.c @@ -23,10 +23,20 @@ #define RESTORE_PM_BITS_HOOK "\\_SB.PCI0.RGPM" #define THUNDERBOLT_DEVICE "\\_SB.PCI0.TXHC" #define THUNDERBOLT_IOM_DPOF "\\_SB.PCI0.DPOF" -#define LPI_STATES_ALL 0xff -#define MIN_DEVICE_STATE ACPI_DEVICE_SLEEP_D0 #define PEPD_SCOPE "\\_SB.PCI0" +#define MIN_DEVICE_STATE ACPI_DEVICE_SLEEP_D0 +#define LPI_STATES_ALL 0xff + +enum { + LPI_REVISION_0 = 0, +}; + +enum { + LPI_DISABLED = 0, + LPI_ENABLED = 1, +}; + struct reg_info { uint8_t *addr; size_t buffer_size; @@ -81,7 +91,7 @@ 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 * one device and crashes without it with a bluescreen. */ -__weak void soc_lpi_get_constraints(void *unused) +static void acpi_gen_default_lpi_constraints(void) { char path[16]; printk(BIOS_INFO, "Returning default LPI constraint package\n"); @@ -117,6 +127,110 @@ __weak void soc_lpi_get_constraints(void *unused) acpigen_write_package_end(); } +__weak struct min_sleep_state *soc_get_min_sleep_state_array(size_t *size) +{ + printk(BIOS_DEBUG, "Empty min sleep state array returned\n"); + *size = 0; + return NULL; +} + +static enum acpi_device_sleep_states get_min_sleep_state( + const struct device *dev, struct min_sleep_state *states_arr, size_t size) +{ + if (!is_dev_enabled(dev)) + return ACPI_DEVICE_SLEEP_NONE; + switch (dev->path.type) { + case DEVICE_PATH_APIC: + return MIN_DEVICE_STATE; + + case DEVICE_PATH_PCI: + /* skip external buses*/ + if ((dev->bus->secondary != 0) || (!states_arr)) + return ACPI_DEVICE_SLEEP_NONE; + for (size_t i = 0; i < size; i++) + if (states_arr[i].pci_dev == dev->path.pci.devfn) + return states_arr[i].min_sleep_state; + printk(BIOS_WARNING, "Unknown min d_state for %x\n", dev->path.pci.devfn); + return ACPI_DEVICE_SLEEP_NONE; + + default: + return ACPI_DEVICE_SLEEP_NONE; + } +} + +/* Generate the LPI constraint table */ +static void acpi_lpi_get_constraints(void *unused) +{ + unsigned int num_entries = 0; + const struct device *dev; + enum acpi_device_sleep_states min_sleep_state; + size_t size; + struct min_sleep_state *states_arr = soc_get_min_sleep_state_array(&size); + + if (size && states_arr) { + for (dev = all_devices; dev; dev = dev->next) { + if (get_min_sleep_state(dev, states_arr, size) + != ACPI_DEVICE_SLEEP_NONE) + num_entries++; + } + } + if (!num_entries) { + acpi_gen_default_lpi_constraints(); + } else { + acpigen_emit_byte(RETURN_OP); + acpigen_write_package(num_entries); + + size_t cpu_index = 0; + for (dev = all_devices; dev; dev = dev->next) { + min_sleep_state = get_min_sleep_state(dev, states_arr, size); + if (min_sleep_state == ACPI_DEVICE_SLEEP_NONE) + continue; + + acpigen_write_package(3); + { + char path[32] = { 0 }; + /* Emit the device path */ + switch (dev->path.type) { + case DEVICE_PATH_PCI: + acpigen_emit_namestring(acpi_device_path(dev)); + break; + + case DEVICE_PATH_APIC: + snprintf(path, sizeof(path), CONFIG_ACPI_CPU_STRING, + cpu_index++); + 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_0); + acpigen_write_package(2); /* no optional device info */ + { + /* Assume constraints apply to all entries */ + acpigen_write_integer(LPI_STATES_ALL); + /* min D-state */ + acpigen_write_integer(min_sleep_state); + } + acpigen_write_package_end(); + } + acpigen_write_package_end(); + } + acpigen_write_package_end(); + } + acpigen_write_package_end(); + } +} + static void lpi_s0ix_entry(void *unused) { /* Inform the EC */ @@ -200,7 +314,7 @@ static void lpi_display_off(void *unused) static void (*lpi_s0_helpers[])(void *) = { NULL, /* enumerate functions (autogenerated) */ - soc_lpi_get_constraints,/* get device constraints */ + acpi_lpi_get_constraints,/* get device constraints */ NULL, /* get crash dump device */ lpi_display_off, /* display off notify */ lpi_display_on, /* display on notify */ diff --git a/src/soc/intel/common/block/include/intelblocks/acpi.h b/src/soc/intel/common/block/include/intelblocks/acpi.h index b03f6ccb2b..c149c6939e 100644 --- a/src/soc/intel/common/block/include/intelblocks/acpi.h +++ b/src/soc/intel/common/block/include/intelblocks/acpi.h @@ -127,4 +127,31 @@ enum core_type get_soc_cpu_type(void); /* Check if CPU supports Nominal frequency or not */ bool soc_is_nominal_freq_supported(void); + +/* Min sleep state per device*/ +struct min_sleep_state { + uint8_t pci_dev; + enum acpi_device_sleep_states min_sleep_state; +}; + +/* + * This SOC callback returns an array that maps devices to their min sleep state. + * Example: + * + * static struct min_sleep_state min_pci_sleep_states[] = { + * { SA_DEVFN_ROOT, ACPI_DEVICE_SLEEP_D3 }, + * { SA_DEVFN_CPU_PCIE1_0, ACPI_DEVICE_SLEEP_D3 }, + * { SA_DEVFN_IGD, ACPI_DEVICE_SLEEP_D3 }, + * ... + * }; + * + * const struct pad_config *variant_early_gpio_table(size_t *num) + * { + * *num = ARRAY_SIZE(early_gpio_table); + * return early_gpio_table; + * } + * + */ +struct min_sleep_state *soc_get_min_sleep_state_array(size_t *size); + #endif /* _SOC_INTEL_COMMON_BLOCK_ACPI_H_ */ |