summaryrefslogtreecommitdiff
path: root/lib/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'lib/acpi')
-rw-r--r--lib/acpi/acpi_device.c45
-rw-r--r--lib/acpi/acpi_dp.c4
-rw-r--r--lib/acpi/acpi_table.c64
-rw-r--r--lib/acpi/acpigen.c354
4 files changed, 464 insertions, 3 deletions
diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
index 3c75b6d962..95dfac583f 100644
--- a/lib/acpi/acpi_device.c
+++ b/lib/acpi/acpi_device.c
@@ -487,7 +487,50 @@ int acpi_device_add_power_res(struct acpi_ctx *ctx, u32 tx_state_val,
return 0;
}
-/* ACPI 6.3 section 6.4.3.8.2.1 - I2cSerialBus() */
+int acpi_device_write_dsm_i2c_hid(struct acpi_ctx *ctx,
+ int hid_desc_reg_offset)
+{
+ int ret;
+
+ acpigen_write_dsm_start(ctx);
+ ret = acpigen_write_dsm_uuid_start(ctx, ACPI_DSM_I2C_HID_UUID);
+ if (ret)
+ return log_ret(ret);
+
+ acpigen_write_dsm_uuid_start_cond(ctx, 0);
+ /* ToInteger (Arg1, Local2) */
+ acpigen_write_to_integer(ctx, ARG1_OP, LOCAL2_OP);
+ /* If (LEqual (Local2, 0x0)) */
+ acpigen_write_if_lequal_op_int(ctx, LOCAL2_OP, 0x0);
+ /* Return (Buffer (One) { 0x1f }) */
+ acpigen_write_return_singleton_buffer(ctx, 0x1f);
+ acpigen_pop_len(ctx); /* Pop : If */
+ /* Else */
+ acpigen_write_else(ctx);
+ /* If (LEqual (Local2, 0x1)) */
+ acpigen_write_if_lequal_op_int(ctx, LOCAL2_OP, 0x1);
+ /* Return (Buffer (One) { 0x3f }) */
+ acpigen_write_return_singleton_buffer(ctx, 0x3f);
+ acpigen_pop_len(ctx); /* Pop : If */
+ /* Else */
+ acpigen_write_else(ctx);
+ /* Return (Buffer (One) { 0x0 }) */
+ acpigen_write_return_singleton_buffer(ctx, 0x0);
+ acpigen_pop_len(ctx); /* Pop : Else */
+ acpigen_pop_len(ctx); /* Pop : Else */
+ acpigen_write_dsm_uuid_end_cond(ctx);
+
+ acpigen_write_dsm_uuid_start_cond(ctx, 1);
+ acpigen_write_return_byte(ctx, hid_desc_reg_offset);
+ acpigen_write_dsm_uuid_end_cond(ctx);
+
+ acpigen_write_dsm_uuid_end(ctx);
+ acpigen_write_dsm_end(ctx);
+
+ return 0;
+}
+
+/* ACPI 6.3 section 6.4.3.8.2.1 - I2cSerialBusV2() */
static void acpi_device_write_i2c(struct acpi_ctx *ctx,
const struct acpi_i2c *i2c)
{
diff --git a/lib/acpi/acpi_dp.c b/lib/acpi/acpi_dp.c
index 579cab4771..7e3e3259d8 100644
--- a/lib/acpi/acpi_dp.c
+++ b/lib/acpi/acpi_dp.c
@@ -324,7 +324,7 @@ struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
const char *ref, int index, int pin,
- enum acpi_irq_polarity polarity)
+ enum acpi_gpio_polarity polarity)
{
struct acpi_dp *gpio;
@@ -336,7 +336,7 @@ struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
if (!acpi_dp_add_reference(gpio, NULL, ref) ||
!acpi_dp_add_integer(gpio, NULL, index) ||
!acpi_dp_add_integer(gpio, NULL, pin) ||
- !acpi_dp_add_integer(gpio, NULL, polarity == ACPI_IRQ_ACTIVE_LOW))
+ !acpi_dp_add_integer(gpio, NULL, polarity == ACPI_GPIO_ACTIVE_LOW))
return NULL;
if (!acpi_dp_add_array(dp, gpio))
diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
index acc55e7fad..908d890389 100644
--- a/lib/acpi/acpi_table.c
+++ b/lib/acpi/acpi_table.c
@@ -264,3 +264,67 @@ void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start)
*/
acpi_align64(ctx);
}
+
+void acpi_create_dbg2(struct acpi_dbg2_header *dbg2,
+ int port_type, int port_subtype,
+ struct acpi_gen_regaddr *address, u32 address_size,
+ const char *device_path)
+{
+ uintptr_t current;
+ struct acpi_dbg2_device *device;
+ u32 *dbg2_addr_size;
+ struct acpi_table_header *header;
+ size_t path_len;
+ const char *path;
+ char *namespace;
+
+ /* Fill out header fields. */
+ current = (uintptr_t)dbg2;
+ memset(dbg2, '\0', sizeof(struct acpi_dbg2_header));
+ header = &dbg2->header;
+
+ header->revision = acpi_get_table_revision(ACPITAB_DBG2);
+ acpi_fill_header(header, "DBG2");
+ header->aslc_revision = ASL_REVISION;
+
+ /* One debug device defined */
+ dbg2->devices_offset = sizeof(struct acpi_dbg2_header);
+ dbg2->devices_count = 1;
+ current += sizeof(struct acpi_dbg2_header);
+
+ /* Device comes after the header */
+ device = (struct acpi_dbg2_device *)current;
+ memset(device, 0, sizeof(struct acpi_dbg2_device));
+ current += sizeof(struct acpi_dbg2_device);
+
+ device->revision = 0;
+ device->address_count = 1;
+ device->port_type = port_type;
+ device->port_subtype = port_subtype;
+
+ /* Base Address comes after device structure */
+ memcpy((void *)current, address, sizeof(struct acpi_gen_regaddr));
+ device->base_address_offset = current - (uintptr_t)device;
+ current += sizeof(struct acpi_gen_regaddr);
+
+ /* Address Size comes after address structure */
+ dbg2_addr_size = (uint32_t *)current;
+ device->address_size_offset = current - (uintptr_t)device;
+ *dbg2_addr_size = address_size;
+ current += sizeof(uint32_t);
+
+ /* Namespace string comes last, use '.' if not provided */
+ path = device_path ? : ".";
+ /* Namespace string length includes NULL terminator */
+ path_len = strlen(path) + 1;
+ namespace = (char *)current;
+ device->namespace_string_length = path_len;
+ device->namespace_string_offset = current - (uintptr_t)device;
+ strncpy(namespace, path, path_len);
+ current += path_len;
+
+ /* Update structure lengths and checksum */
+ device->length = current - (uintptr_t)device;
+ header->length = current - (uintptr_t)dbg2;
+ header->checksum = table_compute_checksum(dbg2, header->length);
+}
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index c609ef4daa..e395226e3d 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -17,6 +17,9 @@
#include <acpi/acpi_table.h>
#include <dm/acpi.h>
+/* CPU path format */
+#define ACPI_CPU_STRING "\\_PR.CP%02d"
+
u8 *acpigen_get_current(struct acpi_ctx *ctx)
{
return ctx->current;
@@ -340,6 +343,58 @@ void acpigen_write_method_serialized(struct acpi_ctx *ctx, const char *name,
ACPI_METHOD_SERIALIZED_MASK);
}
+void acpigen_write_processor(struct acpi_ctx *ctx, uint cpuindex,
+ u32 pblock_addr, uint pblock_len)
+{
+ /*
+ * Processor (\_PR.CPnn, cpuindex, pblock_addr, pblock_len)
+ * {
+ */
+ char pscope[16];
+
+ acpigen_emit_ext_op(ctx, PROCESSOR_OP);
+ acpigen_write_len_f(ctx);
+
+ snprintf(pscope, sizeof(pscope), ACPI_CPU_STRING, cpuindex);
+ acpigen_emit_namestring(ctx, pscope);
+ acpigen_emit_byte(ctx, cpuindex);
+ acpigen_emit_dword(ctx, pblock_addr);
+ acpigen_emit_byte(ctx, pblock_len);
+}
+
+void acpigen_write_processor_package(struct acpi_ctx *ctx,
+ const char *const name,
+ const uint first_core,
+ const uint core_count)
+{
+ uint i;
+ char pscope[16];
+
+ acpigen_write_name(ctx, name);
+ acpigen_write_package(ctx, core_count);
+ for (i = first_core; i < first_core + core_count; ++i) {
+ snprintf(pscope, sizeof(pscope), ACPI_CPU_STRING, i);
+ acpigen_emit_namestring(ctx, pscope);
+ }
+ acpigen_pop_len(ctx);
+}
+
+void acpigen_write_processor_cnot(struct acpi_ctx *ctx, const uint num_cores)
+{
+ int core_id;
+
+ acpigen_write_method(ctx, "\\_PR.CNOT", 1);
+ for (core_id = 0; core_id < num_cores; core_id++) {
+ char buffer[30];
+
+ snprintf(buffer, sizeof(buffer), ACPI_CPU_STRING, core_id);
+ acpigen_emit_byte(ctx, NOTIFY_OP);
+ acpigen_emit_namestring(ctx, buffer);
+ acpigen_emit_byte(ctx, ARG0_OP);
+ }
+ acpigen_pop_len(ctx);
+}
+
void acpigen_write_device(struct acpi_ctx *ctx, const char *name)
{
acpigen_emit_ext_op(ctx, DEVICE_OP);
@@ -426,6 +481,183 @@ void acpigen_write_register_resource(struct acpi_ctx *ctx,
acpigen_write_resourcetemplate_footer(ctx);
}
+void acpigen_write_ppc(struct acpi_ctx *ctx, uint num_pstates)
+{
+ /*
+ * Method (_PPC, 0, NotSerialized)
+ * {
+ * Return (num_pstates)
+ * }
+ */
+ acpigen_write_method(ctx, "_PPC", 0);
+ acpigen_emit_byte(ctx, RETURN_OP);
+ acpigen_write_byte(ctx, num_pstates);
+ acpigen_pop_len(ctx);
+}
+
+/*
+ * Generates a func with max supported P-states saved
+ * in the variable PPCM.
+ */
+void acpigen_write_ppc_nvs(struct acpi_ctx *ctx)
+{
+ /*
+ * Method (_PPC, 0, NotSerialized)
+ * {
+ * Return (PPCM)
+ * }
+ */
+ acpigen_write_method(ctx, "_PPC", 0);
+ acpigen_emit_byte(ctx, RETURN_OP);
+ acpigen_emit_namestring(ctx, "PPCM");
+ acpigen_pop_len(ctx);
+}
+
+void acpigen_write_tpc(struct acpi_ctx *ctx, const char *gnvs_tpc_limit)
+{
+ /*
+ * // Sample _TPC method
+ * Method (_TPC, 0, NotSerialized)
+ * {
+ * Return (\TLVL)
+ * }
+ */
+ acpigen_write_method(ctx, "_TPC", 0);
+ acpigen_emit_byte(ctx, RETURN_OP);
+ acpigen_emit_namestring(ctx, gnvs_tpc_limit);
+ acpigen_pop_len(ctx);
+}
+
+void acpigen_write_prw(struct acpi_ctx *ctx, uint wake, uint level)
+{
+ /* Name (_PRW, Package () { wake, level } */
+ acpigen_write_name(ctx, "_PRW");
+ acpigen_write_package(ctx, 2);
+ acpigen_write_integer(ctx, wake);
+ acpigen_write_integer(ctx, level);
+ acpigen_pop_len(ctx);
+}
+
+void acpigen_write_pss_package(struct acpi_ctx *ctx, u32 core_freq, u32 power,
+ u32 trans_lat, u32 busm_lat, u32 control,
+ u32 status)
+{
+ acpigen_write_package(ctx, 6);
+ acpigen_write_dword(ctx, core_freq);
+ acpigen_write_dword(ctx, power);
+ acpigen_write_dword(ctx, trans_lat);
+ acpigen_write_dword(ctx, busm_lat);
+ acpigen_write_dword(ctx, control);
+ acpigen_write_dword(ctx, status);
+ acpigen_pop_len(ctx);
+
+ log_debug("PSS: %uMHz power %u control 0x%x status 0x%x\n",
+ core_freq, power, control, status);
+}
+
+void acpigen_write_psd_package(struct acpi_ctx *ctx, uint domain, uint numprocs,
+ enum psd_coord coordtype)
+{
+ acpigen_write_name(ctx, "_PSD");
+ acpigen_write_package(ctx, 1);
+ acpigen_write_package(ctx, 5);
+ acpigen_write_byte(ctx, 5); // 5 values
+ acpigen_write_byte(ctx, 0); // revision 0
+ acpigen_write_dword(ctx, domain);
+ acpigen_write_dword(ctx, coordtype);
+ acpigen_write_dword(ctx, numprocs);
+ acpigen_pop_len(ctx);
+ acpigen_pop_len(ctx);
+}
+
+static void acpigen_write_cst_package_entry(struct acpi_ctx *ctx,
+ const struct acpi_cstate *cstate)
+{
+ acpigen_write_package(ctx, 4);
+ acpigen_write_register_resource(ctx, &cstate->resource);
+ acpigen_write_dword(ctx, cstate->ctype);
+ acpigen_write_dword(ctx, cstate->latency);
+ acpigen_write_dword(ctx, cstate->power);
+ acpigen_pop_len(ctx);
+}
+
+void acpigen_write_cst_package(struct acpi_ctx *ctx,
+ const struct acpi_cstate *cstate, int nentries)
+{
+ int i;
+
+ acpigen_write_name(ctx, "_CST");
+ acpigen_write_package(ctx, nentries + 1);
+ acpigen_write_dword(ctx, nentries);
+
+ for (i = 0; i < nentries; i++)
+ acpigen_write_cst_package_entry(ctx, cstate + i);
+
+ acpigen_pop_len(ctx);
+}
+
+void acpigen_write_csd_package(struct acpi_ctx *ctx, uint domain, uint numprocs,
+ enum csd_coord coordtype, uint index)
+{
+ acpigen_write_name(ctx, "_CSD");
+ acpigen_write_package(ctx, 1);
+ acpigen_write_package(ctx, 6);
+ acpigen_write_byte(ctx, 6); // 6 values
+ acpigen_write_byte(ctx, 0); // revision 0
+ acpigen_write_dword(ctx, domain);
+ acpigen_write_dword(ctx, coordtype);
+ acpigen_write_dword(ctx, numprocs);
+ acpigen_write_dword(ctx, index);
+ acpigen_pop_len(ctx);
+ acpigen_pop_len(ctx);
+}
+
+void acpigen_write_tss_package(struct acpi_ctx *ctx,
+ struct acpi_tstate *entry, int nentries)
+{
+ /*
+ * Sample _TSS package with 100% and 50% duty cycles
+ * Name (_TSS, Package (0x02)
+ * {
+ * Package(){100, 1000, 0, 0x00, 0)
+ * Package(){50, 520, 0, 0x18, 0)
+ * })
+ */
+ struct acpi_tstate *tstate = entry;
+ int i;
+
+ acpigen_write_name(ctx, "_TSS");
+ acpigen_write_package(ctx, nentries);
+
+ for (i = 0; i < nentries; i++) {
+ acpigen_write_package(ctx, 5);
+ acpigen_write_dword(ctx, tstate->percent);
+ acpigen_write_dword(ctx, tstate->power);
+ acpigen_write_dword(ctx, tstate->latency);
+ acpigen_write_dword(ctx, tstate->control);
+ acpigen_write_dword(ctx, tstate->status);
+ acpigen_pop_len(ctx);
+ tstate++;
+ }
+
+ acpigen_pop_len(ctx);
+}
+
+void acpigen_write_tsd_package(struct acpi_ctx *ctx, u32 domain, u32 numprocs,
+ enum psd_coord coordtype)
+{
+ acpigen_write_name(ctx, "_TSD");
+ acpigen_write_package(ctx, 1);
+ acpigen_write_package(ctx, 5);
+ acpigen_write_byte(ctx, 5); // 5 values
+ acpigen_write_byte(ctx, 0); // revision 0
+ acpigen_write_dword(ctx, domain);
+ acpigen_write_dword(ctx, coordtype);
+ acpigen_write_dword(ctx, numprocs);
+ acpigen_pop_len(ctx);
+ acpigen_pop_len(ctx);
+}
+
/*
* ToUUID(uuid)
*
@@ -531,6 +763,128 @@ void acpigen_write_debug_string(struct acpi_ctx *ctx, const char *str)
acpigen_emit_ext_op(ctx, DEBUG_OP);
}
+void acpigen_write_if(struct acpi_ctx *ctx)
+{
+ acpigen_emit_byte(ctx, IF_OP);
+ acpigen_write_len_f(ctx);
+}
+
+void acpigen_write_if_lequal_op_int(struct acpi_ctx *ctx, uint op, u64 val)
+{
+ acpigen_write_if(ctx);
+ acpigen_emit_byte(ctx, LEQUAL_OP);
+ acpigen_emit_byte(ctx, op);
+ acpigen_write_integer(ctx, val);
+}
+
+void acpigen_write_else(struct acpi_ctx *ctx)
+{
+ acpigen_emit_byte(ctx, ELSE_OP);
+ acpigen_write_len_f(ctx);
+}
+
+void acpigen_write_to_buffer(struct acpi_ctx *ctx, uint src, uint dst)
+{
+ acpigen_emit_byte(ctx, TO_BUFFER_OP);
+ acpigen_emit_byte(ctx, src);
+ acpigen_emit_byte(ctx, dst);
+}
+
+void acpigen_write_to_integer(struct acpi_ctx *ctx, uint src, uint dst)
+{
+ acpigen_emit_byte(ctx, TO_INTEGER_OP);
+ acpigen_emit_byte(ctx, src);
+ acpigen_emit_byte(ctx, dst);
+}
+
+void acpigen_write_byte_buffer(struct acpi_ctx *ctx, u8 *arr, size_t size)
+{
+ size_t i;
+
+ acpigen_emit_byte(ctx, BUFFER_OP);
+ acpigen_write_len_f(ctx);
+ acpigen_write_integer(ctx, size);
+
+ for (i = 0; i < size; i++)
+ acpigen_emit_byte(ctx, arr[i]);
+
+ acpigen_pop_len(ctx);
+}
+
+void acpigen_write_return_byte_buffer(struct acpi_ctx *ctx, u8 *arr,
+ size_t size)
+{
+ acpigen_emit_byte(ctx, RETURN_OP);
+ acpigen_write_byte_buffer(ctx, arr, size);
+}
+
+void acpigen_write_return_singleton_buffer(struct acpi_ctx *ctx, uint arg)
+{
+ u8 buf = arg;
+
+ acpigen_write_return_byte_buffer(ctx, &buf, 1);
+}
+
+void acpigen_write_return_byte(struct acpi_ctx *ctx, uint arg)
+{
+ acpigen_emit_byte(ctx, RETURN_OP);
+ acpigen_write_byte(ctx, arg);
+}
+
+void acpigen_write_dsm_start(struct acpi_ctx *ctx)
+{
+ /* Method (_DSM, 4, Serialized) */
+ acpigen_write_method_serialized(ctx, "_DSM", 4);
+
+ /* ToBuffer (Arg0, Local0) */
+ acpigen_write_to_buffer(ctx, ARG0_OP, LOCAL0_OP);
+}
+
+int acpigen_write_dsm_uuid_start(struct acpi_ctx *ctx, const char *uuid)
+{
+ int ret;
+
+ /* If (LEqual (Local0, ToUUID(uuid))) */
+ acpigen_write_if(ctx);
+ acpigen_emit_byte(ctx, LEQUAL_OP);
+ acpigen_emit_byte(ctx, LOCAL0_OP);
+ ret = acpigen_write_uuid(ctx, uuid);
+ if (ret)
+ return log_msg_ret("uuid", ret);
+
+ /* ToInteger (Arg2, Local1) */
+ acpigen_write_to_integer(ctx, ARG2_OP, LOCAL1_OP);
+
+ return 0;
+}
+
+void acpigen_write_dsm_uuid_start_cond(struct acpi_ctx *ctx, int seq)
+{
+ /* If (LEqual (Local1, i)) */
+ acpigen_write_if_lequal_op_int(ctx, LOCAL1_OP, seq);
+}
+
+void acpigen_write_dsm_uuid_end_cond(struct acpi_ctx *ctx)
+{
+ acpigen_pop_len(ctx); /* If */
+}
+
+void acpigen_write_dsm_uuid_end(struct acpi_ctx *ctx)
+{
+ /* Default case: Return (Buffer (One) { 0x0 }) */
+ acpigen_write_return_singleton_buffer(ctx, 0x0);
+
+ acpigen_pop_len(ctx); /* If (LEqual (Local0, ToUUID(uuid))) */
+}
+
+void acpigen_write_dsm_end(struct acpi_ctx *ctx)
+{
+ /* Return (Buffer (One) { 0x0 }) */
+ acpigen_write_return_singleton_buffer(ctx, 0x0);
+
+ acpigen_pop_len(ctx); /* Method _DSM */
+}
+
/**
* acpigen_get_dw0_in_local5() - Generate code to put dw0 cfg0 in local5
*