From d95db48cd718b080485b3f70183f58a5dd6a375e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 2 Dec 2020 15:59:24 -0700 Subject: [PATCH] Re-enable lpit --- src/Kconfig | 6 +++ src/acpi/acpi.c | 85 +++++++++++++++++++++++++++++++++++++++++ src/include/acpi/acpi.h | 60 +++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) diff --git a/src/Kconfig b/src/Kconfig index dc98ca2c05..4e5578bb1f 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -720,6 +720,12 @@ config ACPI_NHLT help Build support for NHLT (non HD Audio) ACPI table generation. +config ACPI_LPIT + bool + default y + help + Build an ACPI Low Power Idle Table. + #These Options are here to avoid "undefined" warnings. #The actual selection and help texts are in the following menu. diff --git a/src/acpi/acpi.c b/src/acpi/acpi.c index abc6e01b0a..795a2f84df 100644 --- a/src/acpi/acpi.c +++ b/src/acpi/acpi.c @@ -1264,6 +1264,78 @@ void acpi_create_fadt(acpi_fadt_t *fadt, acpi_facs_t *facs, void *dsdt) acpi_checksum((void *) fadt, header->length); } +/* + * The value of residency couneter register address is MSR value and + * implementation specific.e.e.g, scenerios: + * 1. For CNL: space_id:0,residency_counter.addrl:0x632 and ACPI_LPIT + * selected in soc Kconfig sysfs file thet kernel creates is + * /sys/devices/system/cpu/cpuidle/low_power_idle_cpu_residency_us. + * 2. For CNL: space_id:0, residency_counter.addrl:0xfe000000 + 0x193C + * and ACPI_LPIT elected in soc Kconfig sysfs file thet kernel creates is + * /sys/devices/system/cpu/cpuidle/low_power_idle_system_residency_us + * which gets populated with integer values whenever system goes in s0ix. + */ +__weak void soc_residency_counter(struct acpi_lpit_native *lpit_soc) +{ + lpit_soc->header.unique_id = 0; + + lpit_soc->residency = 0x7530; + lpit_soc->latency = 0xBB8; + + lpit_soc->entry_trigger.space_id = 0x7f; + lpit_soc->entry_trigger.bit_width = 0x01; + lpit_soc->entry_trigger.bit_offset = 0x02; + lpit_soc->entry_trigger.addrl = 0x60; + + lpit_soc->residency_counter.space_id = 0x7f; + lpit_soc->residency_counter.bit_width = 0x40; + lpit_soc->residency_counter.addrl = 0x632; +} + +__weak void system_residency_counter(struct acpi_lpit_native *lpit_system) +{ + lpit_system->header.unique_id = 1; + + lpit_system->counter_frequency = 0x256c; + lpit_system->residency = 0x7530; + lpit_system->latency = 0xBB8; + + lpit_system->entry_trigger.space_id = 0x7f; + lpit_system->entry_trigger.bit_width = 0x01; + lpit_system->entry_trigger.bit_offset = 0x02; + lpit_system->entry_trigger.addrl = 0x60; + + lpit_system->residency_counter.space_id = 0x00; + lpit_system->residency_counter.bit_width = 0x20; + lpit_system->residency_counter.access_size = 0x03; + lpit_system->residency_counter.addrl = 0xfe00193c; +} + +static void acpi_create_lpit_generator(acpi_table_lpit *lpit) +{ + acpi_header_t *header = &(lpit->header); + + memset((void *)lpit, 0, sizeof(acpi_table_lpit)); + + memcpy(header->signature, "LPIT", 4); + header->revision = 2; /* ACPI 1.0/2.0: ?, ACPI 3.0/4.0: 2 */ + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + header->oem_revision = 42; + memcpy(header->asl_compiler_id, ASLC, 4); + header->asl_compiler_revision = 0; + header->length = sizeof(acpi_table_lpit); + lpit->lpit_soc.header.length = sizeof(struct acpi_lpit_native); + lpit->lpit_system.header.length = sizeof(struct acpi_lpit_native); + + soc_residency_counter(&lpit->lpit_soc); + system_residency_counter(&lpit->lpit_system); + + + /* (Re)calculate length and checksum. */ + header->checksum = acpi_checksum((void *)lpit, header->length); +} + unsigned long __weak fw_cfg_acpi_tables(unsigned long start) { return 0; @@ -1284,6 +1356,7 @@ unsigned long write_acpi_tables(unsigned long start) acpi_tcpa_t *tcpa; acpi_tpm2_t *tpm2; acpi_madt_t *madt; + acpi_table_lpit *lpit; struct device *dev; unsigned long fw; size_t slic_size, dsdt_size; @@ -1489,6 +1562,18 @@ unsigned long write_acpi_tables(unsigned long start) current += madt->header.length; acpi_add_table(rsdp, madt); } + + if (CONFIG(ACPI_LPIT)) { + printk(BIOS_DEBUG, "ACPI: * LPIT\n"); + + lpit = (acpi_table_lpit *)current; + acpi_create_lpit_generator(lpit); + if (lpit->header.length >= sizeof(acpi_table_lpit)) { + current += lpit->header.length; + acpi_add_table(rsdp, lpit); + } + } + current = acpi_align_current(current); printk(BIOS_DEBUG, "current = %lx\n", current); diff --git a/src/include/acpi/acpi.h b/src/include/acpi/acpi.h index f6eb772ac7..2bb8683a7f 100644 --- a/src/include/acpi/acpi.h +++ b/src/include/acpi/acpi.h @@ -257,6 +257,63 @@ typedef struct acpi_madt { u32 flags; /* Multiple APIC flags */ } __packed acpi_madt_t; +/******************************************************************************* + * + * LPIT - Low Power Idle Table + * + * Conforms to "ACPI Low Power Idle Table (LPIT)" July 2014. + * + ******************************************************************************/ + +typedef struct acpi_lpi_state_flags { + u32 disabled:1; + u32 counterunavailable:1; + u32 reserved:30; +} __packed acpi_lpi_state_flags; + +/* LPIT subtable header */ + +typedef struct acpi_lpit_header { + u32 type; /* Subtable type */ + u32 length; /* Subtable length */ + u16 unique_id; + u16 reserved; + acpi_lpi_state_flags flags; +} __packed acpi_lpit_header; + +/* Values for subtable Type above */ + +enum acpi_lpit_type { + ACPI_LPIT_TYPE_NATIVE_CSTATE = 0x00, + ACPI_LPIT_TYPE_RESERVED = 0x01 /* 1 and above are reserved */ +}; + +/* Masks for Flags field above */ + +#define ACPI_LPIT_STATE_DISABLED (1) +#define ACPI_LPIT_NO_COUNTER (1<<1) + +/* + * LPIT subtables, correspond to Type in struct acpi_lpit_header + */ + +/* 0x00: Native C-state instruction based LPI structure */ + +struct acpi_lpit_native { + struct acpi_lpit_header header; + struct acpi_gen_regaddr entry_trigger; + u32 residency; + u32 latency; + struct acpi_gen_regaddr residency_counter; + u64 counter_frequency; +}; + +typedef struct acpi_table_lpit { + struct acpi_table_header header; /* Common ACPI table header */ + struct acpi_lpit_native lpit_soc; + struct acpi_lpit_native lpit_system; +} __packed acpi_table_lpit; + /* VFCT image header */ typedef struct acpi_vfct_image_hdr { u32 PCIBus; @@ -897,6 +954,9 @@ struct acpi_spmi { unsigned long fw_cfg_acpi_tables(unsigned long start); +void soc_residency_counter(struct acpi_lpit_native *lpit_soc); +void system_residency_counter(struct acpi_lpit_native *lpit_system); + /* These are implemented by the target port or north/southbridge. */ unsigned long write_acpi_tables(unsigned long addr); unsigned long acpi_fill_madt(unsigned long current);