summaryrefslogtreecommitdiff
path: root/src/soc/intel/alderlake
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/intel/alderlake')
-rw-r--r--src/soc/intel/alderlake/acpi.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/src/soc/intel/alderlake/acpi.c b/src/soc/intel/alderlake/acpi.c
index 159553465a..b6c5699d78 100644
--- a/src/soc/intel/alderlake/acpi.c
+++ b/src/soc/intel/alderlake/acpi.c
@@ -18,8 +18,16 @@
#include <soc/pm.h>
#include <soc/soc_chip.h>
#include <soc/systemagent.h>
+#include <cpu/cpu.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.
*/
@@ -110,6 +118,14 @@ static int cstate_set_s0ix[] = {
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)
{
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;
}
+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)
{
return read32p(soc_read_pmc_base() + IRQ_REG);