diff options
-rw-r--r-- | src/acpi/Kconfig | 6 | ||||
-rw-r--r-- | src/acpi/acpi.c | 54 | ||||
-rw-r--r-- | src/include/acpi/acpi.h | 49 | ||||
-rw-r--r-- | src/soc/intel/common/block/acpi/Kconfig | 7 | ||||
-rw-r--r-- | src/soc/intel/common/block/acpi/Makefile.inc | 1 | ||||
-rw-r--r-- | src/soc/intel/common/block/acpi/acpi.c | 1 | ||||
-rw-r--r-- | src/soc/intel/common/block/acpi/lpit.c | 65 |
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; +} |