ACPI has a number of CPU-related tables. Add utility functions to write
out the basic packages.

Signed-off-by: Simon Glass <s...@chromium.org>
---

(no changes since v1)

 include/acpi/acpigen.h |  39 +++++++++++++++
 lib/acpi/acpigen.c     |  55 +++++++++++++++++++++
 test/dm/acpigen.c      | 106 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 200 insertions(+)

diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
index c412898169e..3a2c6339d5e 100644
--- a/include/acpi/acpigen.h
+++ b/include/acpi/acpigen.h
@@ -64,7 +64,9 @@ enum {
        OR_OP                   = 0x7d,
        NOT_OP                  = 0x80,
        DEVICE_OP               = 0x82,
+       PROCESSOR_OP            = 0x83,
        POWER_RES_OP            = 0x84,
+       NOTIFY_OP               = 0x86,
        LEQUAL_OP               = 0x93,
        TO_BUFFER_OP            = 0x96,
        TO_INTEGER_OP           = 0x99,
@@ -777,4 +779,41 @@ void acpigen_write_dsm_uuid_end(struct acpi_ctx *ctx);
  */
 void acpigen_write_dsm_end(struct acpi_ctx *ctx);
 
+/**
+ * acpigen_write_processor() - Write a Processor package
+ *
+ * This emits a Processor package header with the required information. The
+ * caller must complete the information and call acpigen_pop_len() at the end
+ *
+ * @ctx: ACPI context pointer
+ * @cpuindex: CPU number
+ * @pblock_addr: PBlk system IO address
+ * @pblock_len: PBlk length
+ */
+void acpigen_write_processor(struct acpi_ctx *ctx, uint cpuindex,
+                            u32 pblock_addr, uint pblock_len);
+
+/**
+ * acpigen_write_processor_package() - Write a package containing the 
processors
+ *
+ * The package containins the name of each processor in the SoC
+ *
+ * @ctx: ACPI context pointer
+ * @name: Package name (.e.g "PPKG")
+ * @first_core: Number of the first core (e.g. 0)
+ * @core_count: Number of cores (e.g. 4)
+ */
+void acpigen_write_processor_package(struct acpi_ctx *ctx, const char *name,
+                                    uint first_core, uint core_count);
+
+/**
+ * acpigen_write_processor_cnot() - Write a processor notification method
+ *
+ * This writes a method that notifies all CPU cores
+ *
+ * @ctx: ACPI context pointer
+ * @num_cores: Number of CPU cores
+ */
+void acpigen_write_processor_cnot(struct acpi_ctx *ctx, const uint num_cores);
+
 #endif
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index d859f378413..b9985075cde 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);
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index 381fcb97022..74b7e23aab3 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -1344,3 +1344,109 @@ static int dm_test_acpi_write_i2c_dsm(struct 
unit_test_state *uts)
 }
 DM_TEST(dm_test_acpi_write_i2c_dsm, 0);
 
+/* Test emitting a processor */
+static int dm_test_acpi_write_processor(struct unit_test_state *uts)
+{
+       const int cpuindex = 6;
+       const u32 pblock_addr = 0x12345600;
+       const u32 pblock_len = 0x60;
+       struct acpi_ctx *ctx;
+       u8 *ptr;
+
+       ut_assertok(alloc_context(&ctx));
+
+       ptr = acpigen_get_current(ctx);
+       acpigen_write_processor(ctx, cpuindex, pblock_addr, pblock_len);
+       acpigen_pop_len(ctx);
+
+       ut_asserteq(EXT_OP_PREFIX, *ptr++);
+       ut_asserteq(PROCESSOR_OP, *ptr++);
+       ut_asserteq(0x13, acpi_test_get_length(ptr));
+       ptr += 3;
+       ut_asserteq_strn("\\._PR_CP06", (char *)ptr);
+       ptr += 10;
+       ut_asserteq(cpuindex, *ptr++);
+       ut_asserteq(pblock_addr, get_unaligned((u32 *)ptr));
+       ptr += 4;
+       ut_asserteq(pblock_len, *ptr++);
+
+       ut_asserteq_ptr(ptr, ctx->current);
+
+       free_context(&ctx);
+
+       return 0;
+}
+DM_TEST(dm_test_acpi_write_processor, 0);
+
+/* Test emitting a processor package */
+static int dm_test_acpi_write_processor_package(struct unit_test_state *uts)
+{
+       const int core_count = 3;
+       struct acpi_ctx *ctx;
+       u8 *ptr;
+
+       ut_assertok(alloc_context(&ctx));
+
+       ptr = acpigen_get_current(ctx);
+       acpigen_write_processor_package(ctx, "XCPU", 0, core_count);
+
+       ut_asserteq(NAME_OP, *ptr++);
+       ut_asserteq_strn("XCPU", (char *)ptr);
+       ptr += 4;
+       ut_asserteq(PACKAGE_OP, *ptr++);
+       ptr += 3;  /* skip length */
+       ut_asserteq(core_count, *ptr++);
+
+       ut_asserteq_strn("\\._PR_CP00", (char *)ptr);
+       ptr += 10;
+       ut_asserteq_strn("\\._PR_CP01", (char *)ptr);
+       ptr += 10;
+       ut_asserteq_strn("\\._PR_CP02", (char *)ptr);
+       ptr += 10;
+
+       ut_asserteq_ptr(ptr, ctx->current);
+
+       free_context(&ctx);
+
+       return 0;
+}
+DM_TEST(dm_test_acpi_write_processor_package, 0);
+
+/* Test emitting a processor notification package */
+static int dm_test_acpi_write_processor_cnot(struct unit_test_state *uts)
+{
+       const int core_count = 3;
+       struct acpi_ctx *ctx;
+       u8 *ptr;
+
+       ut_assertok(alloc_context(&ctx));
+
+       ptr = acpigen_get_current(ctx);
+       acpigen_write_processor_cnot(ctx, core_count);
+
+       ut_asserteq(METHOD_OP, *ptr++);
+       ptr += 3;  /* skip length */
+       ut_asserteq_strn("\\._PR_CNOT", (char *)ptr);
+       ptr += 10;
+       ut_asserteq(1, *ptr++);
+
+       ut_asserteq(NOTIFY_OP, *ptr++);
+       ut_asserteq_strn("\\._PR_CP00", (char *)ptr);
+       ptr += 10;
+       ut_asserteq(ARG0_OP, *ptr++);
+       ut_asserteq(NOTIFY_OP, *ptr++);
+       ut_asserteq_strn("\\._PR_CP01", (char *)ptr);
+       ptr += 10;
+       ut_asserteq(ARG0_OP, *ptr++);
+       ut_asserteq(NOTIFY_OP, *ptr++);
+       ut_asserteq_strn("\\._PR_CP02", (char *)ptr);
+       ptr += 10;
+       ut_asserteq(ARG0_OP, *ptr++);
+
+       ut_asserteq_ptr(ptr, ctx->current);
+
+       free_context(&ctx);
+
+       return 0;
+}
+DM_TEST(dm_test_acpi_write_processor_cnot, 0);
-- 
2.28.0.681.g6f77f65b4e-goog

Reply via email to