Matt Delco has uploaded this change for review. ( https://review.coreboot.org/28066
Change subject: arch/x86/acpigen: add methods for cppc ......................................................................
arch/x86/acpigen: add methods for cppc
This change adds 2 methods for Conginuous Performance Control that was added in ACPI 5.0 and expanded twice in later versions. One function will create a global table based on a provided struct, while the other function is used to add a _CPC method in each processor object.
Change-Id: I8798a4c72c681b960087ed65668f01b2ca77d2ce Signed-off-by: Matt Delco delco@chromium.org --- M src/arch/x86/acpigen.c M src/arch/x86/include/arch/acpigen.h 2 files changed, 107 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/66/28066/1
diff --git a/src/arch/x86/acpigen.c b/src/arch/x86/acpigen.c index a614efb..06702ce 100644 --- a/src/arch/x86/acpigen.c +++ b/src/arch/x86/acpigen.c @@ -1339,6 +1339,54 @@ acpigen_pop_len(); /* Method _DSM */ }
+#define CPPC_PACKAGE_NAME "\GCPC" + +void acpigen_write_CPPC_package(const struct cppc_config *config) +{ + u32 i; + u32 max; + switch (config->version) { + case 1: + max = CPPC_MAX_FIELDS_VER_1; + break; + case 2: + max = CPPC_MAX_FIELDS_VER_2; + break; + case 3: + max = CPPC_MAX_FIELDS_VER_3; + break; + default: + printk(BIOS_ERR, "ERROR: CPPC version %u is not implemented\n", + config->version); + return; + } + acpigen_write_name(CPPC_PACKAGE_NAME); + acpigen_write_package(max); + + acpigen_write_dword(max); + acpigen_write_byte(config->version); + + for (i = 0; i < max; ++i) { + const acpi_addr_t *reg = &(config->regs[i]); + if (reg->space_id == ACPI_ADDRESS_SPACE_MEMORY && + reg->bit_width == 32 && reg->access_size == 0) { + acpigen_write_dword(reg->addrl); + } else { + acpigen_write_register_resource(reg); + } + } + acpigen_pop_len(); +} + +void acpigen_write_CPPC_method(void) +{ + acpigen_write_method("_CPC", 0); + acpigen_emit_byte(RETURN_OP); + acpigen_emit_namestring(CPPC_PACKAGE_NAME); + acpigen_pop_len(); +} + + /* * Generate ACPI AML code for _ROM method. * This function takes as input ROM data and ROM length. diff --git a/src/arch/x86/include/arch/acpigen.h b/src/arch/x86/include/arch/acpigen.h index 042c797..775339a 100644 --- a/src/arch/x86/include/arch/acpigen.h +++ b/src/arch/x86/include/arch/acpigen.h @@ -167,6 +167,56 @@ void *arg; };
+/*version 1 has 15 fields, version 2 has 19, and version 3 has 21 */ +enum cppc_fields { + CPPC_HIGHEST_PERF, /* can be DWORD */ + CPPC_NOMINAL_PERF, /* can be DWORD */ + CPPC_LOWEST_NONL_PERF, /* can be DWORD */ + CPPC_LOWEST_PERF, /* can be DWORD */ + CPPC_GUARANTEED_PERF, + CPPC_DESIRED_PERF, + CPPC_MIN_PERF, + CPPC_MAX_PERF, + CPPC_PERF_REDUCE_TOLERANCE, + CPPC_TIME_WINDOW, + CPPC_COUNTER_WRAP, /* can be DWORD */ + CPPC_REF_PERF_COUNTER, + CPPC_DELIVERED_PERF_COUNTER, + CPPC_PERF_LIMITED, + CPPC_ENABLE, /* can be System I/O */ + CPPC_MAX_FIELDS_VER_1, + CPPC_AUTO_SELECT = /* can be DWORD */ + CPPC_MAX_FIELDS_VER_1, + CPPC_AUTO_ACTIVITY_WINDOW, + CPPC_PERF_PREF, + CPPC_REF_PERF, /* can be DWORD */ + CPPC_MAX_FIELDS_VER_2, + CPPC_LOWEST_FREQ = /* can be DWORD */ + CPPC_MAX_FIELDS_VER_2, + CPPC_NOMINAL_FREQ, /* can be DWORD */ + CPPC_MAX_FIELDS_VER_3, +}; + +struct cppc_config { + u32 version; /* must be 1, 2, or 3 */ + /* + * The generic acpi_addr_t structure is being used, though + * anything besides PPC or FFIXED generally requires checking + * if the OS has advertised support for it (via _OSC). + * + * NOTE: some fields permit DWORDs to be used. If you + * provide a System Memory register with all zeros (which + * represents unsupported) then this will be used as-is. + * Otherwise, a System Memory register with a 32-bit + * width will be converted into a DWORD field (the value + * of which will be the value of 'addrl'. Any other use + * of System Memory register is currently undefined. + * (i.e., if you have an actual need for System Memory + * then you'll need to adjust this kludge). + */ + acpi_addr_t regs[CPPC_MAX_FIELDS_VER_3]; +}; + void acpigen_write_return_integer(uint64_t arg); void acpigen_write_return_string(const char *arg); void acpigen_write_len_f(void); @@ -269,6 +319,15 @@ void acpigen_write_dsm_uuid_arr(struct dsm_uuid *ids, size_t count);
/* + * Generate ACPI AML code for _CPC (Continuous Perfmance Control). + * Execute the package function once to create a global table, then + * execute the method function within each processor object to + * create a method that points to the global table. + */ +void acpigen_write_CPPC_package(const struct cppc_config *config); +void acpigen_write_CPPC_method(void); + +/* * Generate ACPI AML code for _ROM method. * This function takes as input ROM data and ROM length. * The ROM length has to be multiple of 4096 and has to be less