summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/acpi/Kconfig6
-rw-r--r--src/acpi/acpi.c54
-rw-r--r--src/include/acpi/acpi.h49
-rw-r--r--src/soc/intel/common/block/acpi/Kconfig7
-rw-r--r--src/soc/intel/common/block/acpi/Makefile.inc1
-rw-r--r--src/soc/intel/common/block/acpi/acpi.c1
-rw-r--r--src/soc/intel/common/block/acpi/lpit.c65
7 files changed, 182 insertions, 1 deletions
diff --git a/src/acpi/Kconfig b/src/acpi/Kconfig
index 293c194538..2727889f9e 100644
--- a/src/acpi/Kconfig
+++ b/src/acpi/Kconfig
@@ -40,3 +40,9 @@ config HAVE_ACPI_TABLES
help
This variable specifies whether a given board has ACPI table support.
It is usually set in mainboard/*/Kconfig.
+
+config ACPI_LPIT
+ bool
+ depends on HAVE_ACPI_TABLES
+ help
+ Selected by platforms that support and fill Intel Low Power Idle Table.
diff --git a/src/acpi/acpi.c b/src/acpi/acpi.c
index a16800b025..ee30391923 100644
--- a/src/acpi/acpi.c
+++ b/src/acpi/acpi.c
@@ -1293,6 +1293,44 @@ void acpi_create_fadt(acpi_fadt_t *fadt, acpi_facs_t *facs, void *dsdt)
acpi_checksum((void *) fadt, header->length);
}
+void acpi_create_lpit(acpi_lpit_t *lpit)
+{
+ acpi_header_t *header = &(lpit->header);
+ unsigned long current = (unsigned long)lpit + sizeof(acpi_lpit_t);
+
+ memset((void *)lpit, 0, sizeof(acpi_lpit_t));
+
+ if (!header)
+ return;
+
+ /* Fill out header fields. */
+ memcpy(header->signature, "LPIT", 4);
+ memcpy(header->oem_id, OEM_ID, 6);
+ memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
+ memcpy(header->asl_compiler_id, ASLC, 4);
+
+ header->asl_compiler_revision = asl_revision;
+ header->revision = get_acpi_table_revision(LPIT);
+ header->oem_revision = 42;
+ header->length = sizeof(acpi_lpit_t);
+
+ current = acpi_fill_lpit(current);
+
+ /* (Re)calculate length and checksum. */
+ header->length = current - (unsigned long)lpit;
+ header->checksum = acpi_checksum((void *)lpit, header->length);
+}
+
+unsigned long acpi_create_lpi_desc_ncst(acpi_lpi_desc_ncst_t *lpi_desc, uint16_t uid)
+{
+ memset(lpi_desc, 0, sizeof(acpi_lpi_desc_ncst_t));
+ lpi_desc->header.length = sizeof(acpi_lpi_desc_ncst_t);
+ lpi_desc->header.type = ACPI_LPI_DESC_TYPE_NATIVE_CSTATE;
+ lpi_desc->header.uid = uid;
+
+ return lpi_desc->header.length;
+}
+
unsigned long __weak fw_cfg_acpi_tables(unsigned long start)
{
return 0;
@@ -1313,6 +1351,7 @@ unsigned long write_acpi_tables(unsigned long start)
acpi_tcpa_t *tcpa;
acpi_tpm2_t *tpm2;
acpi_madt_t *madt;
+ acpi_lpit_t *lpit;
struct device *dev;
unsigned long fw;
size_t slic_size, dsdt_size;
@@ -1507,6 +1546,18 @@ unsigned long write_acpi_tables(unsigned long start)
}
}
+ if (CONFIG(ACPI_LPIT)) {
+ printk(BIOS_DEBUG, "ACPI: * LPIT\n");
+
+ lpit = (acpi_lpit_t *)current;
+ acpi_create_lpit(lpit);
+ if (lpit->header.length >= sizeof(acpi_lpit_t)) {
+ current += lpit->header.length;
+ current = acpi_align_current(current);
+ acpi_add_table(rsdp, lpit);
+ }
+ }
+
printk(BIOS_DEBUG, "ACPI: * MADT\n");
madt = (acpi_madt_t *) current;
@@ -1515,6 +1566,7 @@ unsigned long write_acpi_tables(unsigned long start)
current += madt->header.length;
acpi_add_table(rsdp, madt);
}
+
current = acpi_align_current(current);
printk(BIOS_DEBUG, "current = %lx\n", current);
@@ -1665,6 +1717,8 @@ int get_acpi_table_revision(enum acpi_tables table)
return 1;
case CRAT:
return 1;
+ case LPIT: /* ACPI 5.1 up to 6.3: 0 */
+ return 0;
default:
return -1;
}
diff --git a/src/include/acpi/acpi.h b/src/include/acpi/acpi.h
index 1c364a0ee8..e266a2d668 100644
--- a/src/include/acpi/acpi.h
+++ b/src/include/acpi/acpi.h
@@ -71,7 +71,7 @@ enum coreboot_acpi_ids {
enum acpi_tables {
/* Tables defined by ACPI and used by coreboot */
BERT, DBG2, DMAR, DSDT, FACS, FADT, HEST, HPET, IVRS, MADT, MCFG,
- RSDP, RSDT, SLIT, SRAT, SSDT, TCPA, TPM2, XSDT, ECDT,
+ RSDP, RSDT, SLIT, SRAT, SSDT, TCPA, TPM2, XSDT, ECDT, LPIT,
/* Additional proprietary tables used by coreboot */
VFCT, NHLT, SPMI, CRAT
};
@@ -257,6 +257,48 @@ typedef struct acpi_madt {
u32 flags; /* Multiple APIC flags */
} __packed acpi_madt_t;
+/*
+ * LPIT (Low Power Idle Table)
+ * Conforms to "Intel Low Power S0 Idle" specification, rev 002 from July 2017.
+ */
+typedef struct acpi_lpit {
+ acpi_header_t header;
+} __packed acpi_lpit_t;
+
+/* LPIT: LPI descriptor flags */
+typedef struct acpi_lpi_flags {
+ uint32_t disabled : 1;
+ uint32_t counter_not_available : 1;
+ uint32_t reserved : 30;
+} __packed acpi_lpi_desc_flags_t;
+
+/* LPIT: LPI descriptor types */
+enum acpi_lpi_desc_type {
+ ACPI_LPI_DESC_TYPE_NATIVE_CSTATE = 0x00,
+ /* type >= 1 reserved */
+};
+
+/* LPIT: LPI descriptor header */
+typedef struct acpi_lpi_desc_hdr {
+ uint32_t type;
+ uint32_t length;
+ uint16_t uid;
+ uint16_t reserved;
+} __packed acpi_lpi_desc_hdr_t;
+
+#define ACPI_LPIT_CTR_FREQ_TSC 0
+
+/* LPIT: Native C-state instruction based LPI structure */
+typedef struct acpi_lpi_desc_ncst {
+ acpi_lpi_desc_hdr_t header;
+ acpi_lpi_desc_flags_t flags;
+ acpi_addr_t entry_trigger; /* Entry trigger C-state */
+ uint32_t min_residency; /* Minimum residency or "break-even" in microseconds */
+ uint32_t max_latency; /* Worst case exit latency in microseconds */
+ acpi_addr_t residency_counter;
+ uint64_t counter_frequency; /* Frequency in cycles per second - 0 means TSC freq */
+} __packed acpi_lpi_desc_ncst_t;
+
/* VFCT image header */
typedef struct acpi_vfct_image_hdr {
u32 PCIBus;
@@ -922,6 +964,8 @@ void mainboard_fill_fadt(acpi_fadt_t *fadt);
void update_ssdt(void *ssdt);
void update_ssdtx(void *ssdtx, int i);
+unsigned long acpi_fill_lpit(unsigned long current);
+
/* These can be used by the target port. */
u8 acpi_checksum(u8 *table, u32 length);
@@ -1025,6 +1069,9 @@ void acpi_write_hest(acpi_hest_t *hest,
unsigned long acpi_create_hest_error_source(acpi_hest_t *hest,
acpi_hest_esd_t *esd, u16 type, void *data, u16 len);
+void acpi_create_lpit(acpi_lpit_t *lpit);
+unsigned long acpi_create_lpi_desc_ncst(acpi_lpi_desc_ncst_t *lpi_desc, uint16_t uid);
+
/* For ACPI S3 support. */
void __noreturn acpi_resume(void *wake_vec);
void mainboard_suspend_resume(void);
diff --git a/src/soc/intel/common/block/acpi/Kconfig b/src/soc/intel/common/block/acpi/Kconfig
index d9a7a87859..a4f9844c70 100644
--- a/src/soc/intel/common/block/acpi/Kconfig
+++ b/src/soc/intel/common/block/acpi/Kconfig
@@ -5,6 +5,13 @@ config SOC_INTEL_COMMON_BLOCK_ACPI
help
Intel Processor common code for ACPI
+config SOC_INTEL_COMMON_BLOCK_ACPI_LPIT
+ bool
+ depends on HAVE_ACPI_TABLES
+ select ACPI_LPIT
+ help
+ Generate LPIT table with LPI state entries.
+
if SOC_INTEL_COMMON_BLOCK_ACPI
config SOC_INTEL_COMMON_BLOCK_ACPI_CPPC
diff --git a/src/soc/intel/common/block/acpi/Makefile.inc b/src/soc/intel/common/block/acpi/Makefile.inc
index c6bdac5d3e..4e3a323625 100644
--- a/src/soc/intel/common/block/acpi/Makefile.inc
+++ b/src/soc/intel/common/block/acpi/Makefile.inc
@@ -1 +1,2 @@
ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_ACPI) += acpi.c
+ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_ACPI_LPIT) += lpit.c
diff --git a/src/soc/intel/common/block/acpi/acpi.c b/src/soc/intel/common/block/acpi/acpi.c
index f4560bd585..1a18cfc23e 100644
--- a/src/soc/intel/common/block/acpi/acpi.c
+++ b/src/soc/intel/common/block/acpi/acpi.c
@@ -10,6 +10,7 @@
#include <cf9_reset.h>
#include <console/console.h>
#include <cpu/intel/turbo.h>
+#include <cpu/intel/msr.h>
#include <cpu/intel/common/common.h>
#include <cpu/x86/smm.h>
#include <intelblocks/acpi.h>
diff --git a/src/soc/intel/common/block/acpi/lpit.c b/src/soc/intel/common/block/acpi/lpit.c
new file mode 100644
index 0000000000..5b9689cead
--- /dev/null
+++ b/src/soc/intel/common/block/acpi/lpit.c
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <acpi/acpi.h>
+#include <cpu/intel/msr.h>
+#include <soc/iomap.h>
+#include <soc/pmc.h>
+
+unsigned long acpi_fill_lpit(unsigned long current)
+{
+ uint16_t uid = 0;
+ acpi_lpi_desc_ncst_t *pkg_counter;
+ acpi_lpi_desc_ncst_t *sys_counter;
+
+ /*
+ * Package C10 (PC10) residency counter
+ */
+ pkg_counter = (void *)current;
+ current += acpi_create_lpi_desc_ncst((void *)current, uid++);
+
+ /* MWAIT LPI state entry trigger */
+ pkg_counter->entry_trigger.addrl = 0x60; /* MWAIT(6,0) / HW C10 */
+ pkg_counter->entry_trigger.bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT;
+ pkg_counter->entry_trigger.bit_width = ACPI_FFIXEDHW_VENDOR_INTEL;
+ pkg_counter->entry_trigger.space_id = ACPI_ADDRESS_SPACE_FIXED;
+ pkg_counter->entry_trigger.access_size = ACPI_ACCESS_SIZE_UNDEFINED;
+
+ /* PC10 residency counter */
+ pkg_counter->residency_counter.addrl = MSR_PKG_C10_RESIDENCY;
+ pkg_counter->residency_counter.bit_offset = 0;
+ pkg_counter->residency_counter.bit_width = 64;
+ pkg_counter->residency_counter.space_id = ACPI_ADDRESS_SPACE_FIXED;
+ pkg_counter->residency_counter.access_size = ACPI_ACCESS_SIZE_UNDEFINED;
+ pkg_counter->counter_frequency = ACPI_LPIT_CTR_FREQ_TSC;
+
+ /* Min. residency and worst-case latency (from FSP and vendor dumps) */
+ pkg_counter->min_residency = 30000; /* break-even: 30 ms */
+ pkg_counter->max_latency = 3000; /* worst-case latency: 3 ms */
+
+ /*
+ * System (Slp_S0) residency counter
+ */
+ sys_counter = (void *)current;
+ current += acpi_create_lpi_desc_ncst((void *)current, uid++);
+
+ /* MWAIT LPI state entry trigger */
+ sys_counter->entry_trigger.addrl = 0x60; /* MWAIT(6,0) / HW C10 */
+ sys_counter->entry_trigger.bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT;
+ sys_counter->entry_trigger.bit_width = ACPI_FFIXEDHW_VENDOR_INTEL;
+ sys_counter->entry_trigger.space_id = ACPI_ADDRESS_SPACE_FIXED;
+ sys_counter->entry_trigger.access_size = ACPI_ACCESS_SIZE_UNDEFINED;
+
+ /* Slp_S0 residency counter */
+ sys_counter->residency_counter.addrl = PCH_PWRM_BASE_ADDRESS + SLP_S0_RES;
+ sys_counter->residency_counter.bit_offset = 0;
+ sys_counter->residency_counter.bit_width = 32;
+ sys_counter->residency_counter.space_id = ACPI_ADDRESS_SPACE_MEMORY;
+ sys_counter->residency_counter.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
+ sys_counter->counter_frequency = ACPI_LPIT_CTR_FREQ_TSC;
+
+ /* Min. residency and worst-case latency (from FSP and vendor dumps) */
+ sys_counter->min_residency = 30000; /* break-even: 30 ms */
+ sys_counter->max_latency = 3000; /* worst-case latency: 3 ms */
+
+ return current;
+}