summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/x86/acpigen.c49
-rw-r--r--src/arch/x86/include/arch/acpigen.h59
2 files changed, 108 insertions, 0 deletions
diff --git a/src/arch/x86/acpigen.c b/src/arch/x86/acpigen.c
index a614efb002..f73ace298e 100644
--- a/src/arch/x86/acpigen.c
+++ b/src/arch/x86/acpigen.c
@@ -1339,6 +1339,55 @@ void acpigen_write_dsm_uuid_arr(struct dsm_uuid *ids, size_t count)
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);
+
+ /* Adding 2 to account for length and version fields */
+ acpigen_write_package(max + 2);
+ acpigen_write_dword(max + 2);
+
+ 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 042c7971b3..775339a713 100644
--- a/src/arch/x86/include/arch/acpigen.h
+++ b/src/arch/x86/include/arch/acpigen.h
@@ -167,6 +167,56 @@ struct dsm_uuid {
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(const char *uuid, void (**callbacks)(void *),
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