[PATCH v7 0/9] dm: Add programmatic generation of ACPI tables (part A)

This is split from the original series in an attempt to get things applied in chunks.
v7 is just a rebase as requested
Changes in v7: - Rebase to master
Changes in v5: - Drop bisectability changes
Changes in v4: - Put 'interrupts-extended' property on one line - Rename acpi-probed to linux,probed - Note that linux,probed is an out-of-tree feature - Separate out the log newline - Update comment in acpi_inc_align() to show the alignment - Put back cast on table_compute_checksum() - Rename list_fact() to list_fadt() - Add a comment to dump_hdr()
Changes in v3: - Drop mention of PRIC - Rename acpi,desc to acpi,ddn - Correct description of acpi,probed - Drop hid-descr-addr - Just add the device.txt binding file in this patch - Change the example to ELAN - Add a pointer to information about acpi,compatible - Rename acpi_align_large() to acpi_align64() - Fix 'RSDP' typo - Fix 'XDST' typo - Move acpi_align_large() out of dm_test_acpi_setup_base_tables() - Beef up the comment explaining how the unaligned address is used
Changes in v2: - Fix definition of HID - Infer hid-over-i2c CID value - Add the hid-over-i2c binding document - Drop definition of ACPI_TABLE_CREATOR - Make _acpi_write_dev_tables() static and switch argument order - Generalise the ACPI function recursion with acpi_recurse_method()
Simon Glass (9): acpi: Add a binding for ACPI settings in the device tree acpi: Add a method to write tables for a device acpi: Convert part of acpi_table to use acpi_ctx x86: Allow devices to write ACPI tables acpi: Drop code for missing XSDT from acpi_write_rsdp() acpi: Move acpi_add_table() to generic code acpi: Put table-setup code in its own function acpi: Move the xsdt pointer to acpi_ctx acpi: Add an acpi command
arch/sandbox/dts/test.dts | 4 + arch/sandbox/include/asm/global_data.h | 1 + arch/x86/include/asm/global_data.h | 1 + arch/x86/lib/acpi_table.c | 239 +++++-------------------- cmd/Kconfig | 14 ++ cmd/Makefile | 1 + cmd/acpi.c | 186 +++++++++++++++++++ doc/device-tree-bindings/device.txt | 36 ++++ drivers/core/acpi.c | 62 +++++++ include/acpi/acpi_table.h | 65 +++++++ include/dm/acpi.h | 37 ++++ lib/acpi/acpi_table.c | 174 +++++++++++++++++- test/dm/acpi.c | 238 +++++++++++++++++++++++- 13 files changed, 855 insertions(+), 203 deletions(-) create mode 100644 cmd/acpi.c create mode 100644 doc/device-tree-bindings/device.txt

Devices need to report various identifiers in the ACPI tables. Rather than hard-coding these in drivers it is typically better to put them in the device tree.
Add a binding file to describe this.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v7: None Changes in v5: None Changes in v4: - Put 'interrupts-extended' property on one line - Rename acpi-probed to linux,probed - Note that linux,probed is an out-of-tree feature
Changes in v3: - Drop mention of PRIC - Rename acpi,desc to acpi,ddn - Correct description of acpi,probed - Drop hid-descr-addr - Just add the device.txt binding file in this patch - Change the example to ELAN - Add a pointer to information about acpi,compatible
Changes in v2: - Fix definition of HID - Infer hid-over-i2c CID value - Add the hid-over-i2c binding document
doc/device-tree-bindings/device.txt | 36 +++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 doc/device-tree-bindings/device.txt
diff --git a/doc/device-tree-bindings/device.txt b/doc/device-tree-bindings/device.txt new file mode 100644 index 0000000000..27bd3978d9 --- /dev/null +++ b/doc/device-tree-bindings/device.txt @@ -0,0 +1,36 @@ +Devices +======= + +Device bindings are described by their own individual binding files. + +U-Boot provides for some optional properties which are documented here. See +also hid-over-i2c.txt which describes HID devices. See also +Documentation/firmware-guide/acpi/enumeration.rst in the Linux kernel for +the acpi,compatible property. + + - acpi,has-power-resource : (boolean) true if this device has a power resource. + This causes an ACPI PowerResource to be written containing the properties + provided by this binding, to describe how to handle powering the device up + and down using GPIOs + - acpi,compatible : compatible string to report + - acpi,ddn : Contains the string to use as the _DDN (DOS (Disk Operating + System) Device Name) + - acpi,hid : Contains the string to use as the HID (Hardware ID) + identifier _HID + - acpi,uid : _UID value for device + - linux,probed : Tells U-Boot to add 'linux,probed' to the ACPI tables so that + Linux will only load the driver if the device can be detected (e.g. on I2C + bus). Note that this is an out-of-tree Linux feature. + + +Example +------- + +elan_touchscreen: elan-touchscreen@10 { + compatible = "i2c-chip"; + reg = <0x10>; + acpi,hid = "ELAN0001"; + acpi,ddn = "ELAN Touchscreen"; + interrupts-extended = <&acpi_gpe GPIO_21_IRQ IRQ_TYPE_EDGE_FALLING>; + linux,probed; +};

Hi Wolfgang, Andy,
On Mon, Apr 20, 2020 at 4:37 AM Simon Glass sjg@chromium.org wrote:
Devices need to report various identifiers in the ACPI tables. Rather than hard-coding these in drivers it is typically better to put them in the device tree.
Add a binding file to describe this.
Signed-off-by: Simon Glass sjg@chromium.org
Do you have any comments against this patch?
Regards, Bin

On Tue, Apr 21, 2020 at 3:28 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Wolfgang, Andy,
On Mon, Apr 20, 2020 at 4:37 AM Simon Glass sjg@chromium.org wrote:
Devices need to report various identifiers in the ACPI tables. Rather than hard-coding these in drivers it is typically better to put them in the device tree.
Add a binding file to describe this.
Signed-off-by: Simon Glass sjg@chromium.org
Do you have any comments against this patch?
As long as it doesn't mention PRP0001, I'm fine with it.

Hi Bin,
-----"Bin Meng" bmeng.cn@gmail.com schrieb: -----
Betreff: Re: [PATCH v7 1/9] acpi: Add a binding for ACPI settings in the device tree
Hi Wolfgang, Andy,
On Mon, Apr 20, 2020 at 4:37 AM Simon Glass sjg@chromium.org wrote:
Devices need to report various identifiers in the ACPI tables.
Rather than
hard-coding these in drivers it is typically better to put them in
the
device tree.
Add a binding file to describe this.
Signed-off-by: Simon Glass sjg@chromium.org
Do you have any comments against this patch?
I'm fine with the patch as it is.
However, two remarks:
1) I proposed some rewording in [1]. I'm fine with dropping it, I just point it out to make sure that it is deliberately dropped and no just overseen.
2) In [2] Andy stated that "acpi,compatible" can't work. @Andy: did I get this wrong? Is it still fine to add it in the binding?
regards, Wolfgang
[1] https://lists.denx.de/pipermail/u-boot/2020-April/406818.html [2] https://lists.denx.de/pipermail/u-boot/2020-April/406943.html

On Tue, Apr 21, 2020 at 4:07 PM Wolfgang Wallner wolfgang.wallner@br-automation.com wrote:
Betreff: Re: [PATCH v7 1/9] acpi: Add a binding for ACPI settings in the device tree
Hi Wolfgang, Andy,
On Mon, Apr 20, 2020 at 4:37 AM Simon Glass sjg@chromium.org wrote:
Devices need to report various identifiers in the ACPI tables.
Rather than
hard-coding these in drivers it is typically better to put them in
the
device tree.
Add a binding file to describe this.
Signed-off-by: Simon Glass sjg@chromium.org
Do you have any comments against this patch?
I'm fine with the patch as it is.
However, two remarks:
I proposed some rewording in [1]. I'm fine with dropping it, I just point it out to make sure that it is deliberately dropped and no just overseen.
In [2] Andy stated that "acpi,compatible" can't work. @Andy: did I get this wrong? Is it still fine to add it in the binding?
We can support it in the code, but user should themselves choose how to use it. This will be half-baked solution, though.
So, I suggest for now to drop it completely.
[1] https://lists.denx.de/pipermail/u-boot/2020-April/406818.html [2] https://lists.denx.de/pipermail/u-boot/2020-April/406943.html

Hi,
-----"Andy Shevchenko" andy.shevchenko@gmail.com schrieb: -----
An: "Wolfgang Wallner" wolfgang.wallner@br-automation.com Von: "Andy Shevchenko" andy.shevchenko@gmail.com Datum: 21.04.2020 16:41 Kopie: "Bin Meng" bmeng.cn@gmail.com, "Simon Glass" sjg@chromium.org, "Andy Shevchenko" andriy.shevchenko@linux.intel.com, "U-Boot Mailing List" u-boot@lists.denx.de, "Leif Lindholm" leif@nuviainc.com Betreff: Re: Re: [PATCH v7 1/9] acpi: Add a binding for ACPI settings in the device tree
On Tue, Apr 21, 2020 at 4:07 PM Wolfgang Wallner wolfgang.wallner@br-automation.com wrote:
Betreff: Re: [PATCH v7 1/9] acpi: Add a binding for ACPI settings
in
the device tree
Hi Wolfgang, Andy,
On Mon, Apr 20, 2020 at 4:37 AM Simon Glass sjg@chromium.org
wrote:
Devices need to report various identifiers in the ACPI tables.
Rather than
hard-coding these in drivers it is typically better to put them
in
the
device tree.
Add a binding file to describe this.
Signed-off-by: Simon Glass sjg@chromium.org
Do you have any comments against this patch?
I'm fine with the patch as it is.
However, two remarks:
I proposed some rewording in [1]. I'm fine with dropping it, I just point it out to make sure that it is deliberately dropped and no just overseen.
In [2] Andy stated that "acpi,compatible" can't work. @Andy: did I get this wrong? Is it still fine to add it in the binding?
We can support it in the code, but user should themselves choose how to use it. This will be half-baked solution, though.
So, I suggest for now to drop it completely.
Ok, thanks for clarifying. That was the only aspect of the the patch I still felt I don't understand enough. So whether "acpi,compatible" is dropped or not:
Reviewed-by: Wolfgang Wallner wolfgang.wallner@br-automation.com
[1] https://lists.denx.de/pipermail/u-boot/2020-April/406818.html [2] https://lists.denx.de/pipermail/u-boot/2020-April/406943.html
regards, Wolfgang

A device may want to write out ACPI tables to describe itself to Linux. Add a method to permit this.
Reviewed-by: Wolfgang Wallner wolfgang.wallner@br-automation.com Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v7: None Changes in v5: - Drop bisectability changes
Changes in v4: - Separate out the log newline
Changes in v3: None Changes in v2: - Drop definition of ACPI_TABLE_CREATOR - Make _acpi_write_dev_tables() static and switch argument order - Generalise the ACPI function recursion with acpi_recurse_method()
arch/sandbox/dts/test.dts | 4 +++ arch/x86/lib/acpi_table.c | 9 ----- drivers/core/acpi.c | 62 ++++++++++++++++++++++++++++++++ include/acpi/acpi_table.h | 10 ++++++ include/dm/acpi.h | 30 ++++++++++++++++ lib/acpi/acpi_table.c | 13 +++++-- test/dm/acpi.c | 74 +++++++++++++++++++++++++++++++++++++-- 7 files changed, 187 insertions(+), 15 deletions(-)
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index df9f1835c9..4bccfbe6e1 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -226,6 +226,10 @@ compatible = "denx,u-boot-acpi-test"; };
+ acpi-test2 { + compatible = "denx,u-boot-acpi-test"; + }; + clocks { clk_fixed: clk-fixed { compatible = "fixed-clock"; diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index 9346e165d8..235fc2268b 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -60,15 +60,6 @@ static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, sizeof(struct acpi_rsdp)); }
-void acpi_fill_header(struct acpi_table_header *header, char *signature) -{ - memcpy(header->signature, signature, 4); - memcpy(header->oem_id, OEM_ID, 6); - memcpy(header->oem_table_id, OEM_TABLE_ID, 8); - header->oem_revision = U_BOOT_BUILD_DATE; - memcpy(header->aslc_id, ASLC_ID, 4); -} - static void acpi_write_rsdt(struct acpi_rsdt *rsdt) { struct acpi_table_header *header = &(rsdt->header); diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c index ba50d688fe..e09905cf2a 100644 --- a/drivers/core/acpi.c +++ b/drivers/core/acpi.c @@ -11,8 +11,17 @@ #include <common.h> #include <dm.h> #include <dm/acpi.h> +#include <dm/device-internal.h> #include <dm/root.h>
+/* Type of method to call */ +enum method_t { + METHOD_WRITE_TABLES, +}; + +/* Prototype for all methods */ +typedef int (*acpi_method)(const struct udevice *dev, struct acpi_ctx *ctx); + int acpi_copy_name(char *out_name, const char *name) { strncpy(out_name, name, ACPI_NAME_LEN); @@ -31,3 +40,56 @@ int acpi_get_name(const struct udevice *dev, char *out_name)
return -ENOSYS; } + +acpi_method acpi_get_method(struct udevice *dev, enum method_t method) +{ + struct acpi_ops *aops; + + aops = device_get_acpi_ops(dev); + if (aops) { + switch (method) { + case METHOD_WRITE_TABLES: + return aops->write_tables; + } + } + + return NULL; +} + +int acpi_recurse_method(struct acpi_ctx *ctx, struct udevice *parent, + enum method_t method) +{ + struct udevice *dev; + acpi_method func; + int ret; + + func = acpi_get_method(parent, method); + if (func) { + log_debug("\n"); + log_debug("- %s %p\n", parent->name, func); + ret = device_ofdata_to_platdata(parent); + if (ret) + return log_msg_ret("ofdata", ret); + ret = func(parent, ctx); + if (ret) + return log_msg_ret("func", ret); + } + device_foreach_child(dev, parent) { + ret = acpi_recurse_method(ctx, dev, method); + if (ret) + return log_msg_ret("recurse", ret); + } + + return 0; +} + +int acpi_write_dev_tables(struct acpi_ctx *ctx) +{ + int ret; + + log_debug("Writing device tables\n"); + ret = acpi_recurse_method(ctx, dm_root(), METHOD_WRITE_TABLES); + log_debug("Writing finished, err=%d\n", ret); + + return ret; +} diff --git a/include/acpi/acpi_table.h b/include/acpi/acpi_table.h index 194be9aa58..a2bd929c92 100644 --- a/include/acpi/acpi_table.h +++ b/include/acpi/acpi_table.h @@ -505,6 +505,16 @@ int acpi_get_table_revision(enum acpi_tables table); */ int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags);
+/** + * acpi_fill_header() - Set up a new table header + * + * This sets all fields except length, revision, checksum and aslc_revision + * + * @header: ACPI header to update + * @signature: Table signature to use (4 characters) + */ +void acpi_fill_header(struct acpi_table_header *header, char *signature); + #endif /* !__ACPI__*/
#include <asm/acpi_table.h> diff --git a/include/dm/acpi.h b/include/dm/acpi.h index 49257914ff..69d69d7f42 100644 --- a/include/dm/acpi.h +++ b/include/dm/acpi.h @@ -24,6 +24,17 @@
#if !defined(__ACPI__)
+/** + * struct acpi_ctx - Context used for writing ACPI tables + * + * This contains a few useful pieces of information used when writing + * + * @current: Current address for writing + */ +struct acpi_ctx { + void *current; +}; + /** * struct acpi_ops - ACPI operations supported by driver model */ @@ -38,6 +49,15 @@ struct acpi_ops { * other error */ int (*get_name)(const struct udevice *dev, char *out_name); + + /** + * write_tables() - Write out any tables required by this device + * + * @dev: Device to write + * @ctx: ACPI context to use + * @return 0 if OK, -ve on error + */ + int (*write_tables)(const struct udevice *dev, struct acpi_ctx *ctx); };
#define device_get_acpi_ops(dev) ((dev)->driver->acpi_ops) @@ -72,6 +92,16 @@ int acpi_get_name(const struct udevice *dev, char *out_name); */ int acpi_copy_name(char *out_name, const char *name);
+/** + * acpi_write_dev_tables() - Write ACPI tables required by devices + * + * This scans through all devices and tells them to write any tables they want + * to write. + * + * @return 0 if OK, -ve if any device returned an error + */ +int acpi_write_dev_tables(struct acpi_ctx *ctx); + #endif /* __ACPI__ */
#endif diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c index 4633dcb948..372f19b16d 100644 --- a/lib/acpi/acpi_table.c +++ b/lib/acpi/acpi_table.c @@ -9,9 +9,8 @@ #include <acpi/acpi_table.h> #include <dm.h> #include <cpu.h> +#include <version.h>
-/* Temporary change to ensure bisectability */ -#ifndef CONFIG_SANDBOX int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags) { struct acpi_table_header *header = &dmar->header; @@ -37,7 +36,6 @@ int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags)
return 0; } -#endif
int acpi_get_table_revision(enum acpi_tables table) { @@ -91,3 +89,12 @@ int acpi_get_table_revision(enum acpi_tables table) return -EINVAL; } } + +void acpi_fill_header(struct acpi_table_header *header, char *signature) +{ + memcpy(header->signature, signature, 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, OEM_TABLE_ID, 8); + header->oem_revision = U_BOOT_BUILD_DATE; + memcpy(header->aslc_id, ASLC_ID, 4); +} diff --git a/test/dm/acpi.c b/test/dm/acpi.c index e7b8abd556..fb7b7e46b2 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -8,12 +8,26 @@
#include <common.h> #include <dm.h> +#include <version.h> #include <acpi/acpi_table.h> #include <dm/acpi.h> #include <dm/test.h> #include <test/ut.h>
#define ACPI_TEST_DEV_NAME "ABCD" +#define BUF_SIZE 4096 + +static int testacpi_write_tables(const struct udevice *dev, + struct acpi_ctx *ctx) +{ + struct acpi_dmar *dmar; + + dmar = (struct acpi_dmar *)ctx->current; + acpi_create_dmar(dmar, DMAR_INTR_REMAP); + ctx->current += sizeof(struct acpi_dmar); + + return 0; +}
static int testacpi_get_name(const struct udevice *dev, char *out_name) { @@ -22,6 +36,7 @@ static int testacpi_get_name(const struct udevice *dev, char *out_name)
struct acpi_ops testacpi_ops = { .get_name = testacpi_get_name, + .write_tables = testacpi_write_tables, };
static const struct udevice_id testacpi_ids[] = { @@ -68,8 +83,6 @@ static int dm_test_acpi_get_table_revision(struct unit_test_state *uts) DM_TEST(dm_test_acpi_get_table_revision, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-/* Temporary change to ensure bisectability */ -#ifndef CONFIG_SANDBOX /* Test acpi_create_dmar() */ static int dm_test_acpi_create_dmar(struct unit_test_state *uts) { @@ -82,4 +95,59 @@ static int dm_test_acpi_create_dmar(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_acpi_create_dmar, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -#endif + +/* Test acpi_fill_header() */ +static int dm_test_acpi_fill_header(struct unit_test_state *uts) +{ + struct acpi_table_header hdr; + + /* Make sure these 5 fields are not changed */ + hdr.length = 0x11; + hdr.revision = 0x22; + hdr.checksum = 0x33; + hdr.aslc_revision = 0x44; + acpi_fill_header(&hdr, "ABCD"); + + ut_asserteq_mem("ABCD", hdr.signature, sizeof(hdr.signature)); + ut_asserteq(0x11, hdr.length); + ut_asserteq(0x22, hdr.revision); + ut_asserteq(0x33, hdr.checksum); + ut_asserteq_mem(OEM_ID, hdr.oem_id, sizeof(hdr.oem_id)); + ut_asserteq_mem(OEM_TABLE_ID, hdr.oem_table_id, + sizeof(hdr.oem_table_id)); + ut_asserteq(U_BOOT_BUILD_DATE, hdr.oem_revision); + ut_asserteq_mem(ASLC_ID, hdr.aslc_id, sizeof(hdr.aslc_id)); + ut_asserteq(0x44, hdr.aslc_revision); + + return 0; +} +DM_TEST(dm_test_acpi_fill_header, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test ACPI write_tables() */ +static int dm_test_acpi_write_tables(struct unit_test_state *uts) +{ + struct acpi_dmar *dmar; + struct acpi_ctx ctx; + void *buf; + + buf = malloc(BUF_SIZE); + ut_assertnonnull(buf); + + ctx.current = buf; + ut_assertok(acpi_write_dev_tables(&ctx)); + dmar = buf; + + /* + * We should have two dmar tables, one for each "denx,u-boot-acpi-test" + * device + */ + ut_asserteq_ptr(dmar + 2, ctx.current); + ut_asserteq(DMAR_INTR_REMAP, dmar->flags); + ut_asserteq(32 - 1, dmar->host_address_width); + + ut_asserteq(DMAR_INTR_REMAP, dmar[1].flags); + ut_asserteq(32 - 1, dmar[1].host_address_width); + + return 0; +} +DM_TEST(dm_test_acpi_write_tables, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

The current code uses an address but a pointer would result in fewer casts. Also it repeats the alignment code in a lot of places so this would be better done in a helper function.
Update write_acpi_tables() to make use of the new acpi_ctx structure, adding a few helpers to clean things up.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Wolfgang Wallner wolfgang.wallner@br-automation.com ---
Changes in v7: None Changes in v5: None Changes in v4: - Update comment in acpi_inc_align() to show the alignment
Changes in v3: - Rename acpi_align_large() to acpi_align64()
Changes in v2: None
arch/x86/lib/acpi_table.c | 88 +++++++++++++++++++-------------------- include/acpi/acpi_table.h | 36 ++++++++++++++++ lib/acpi/acpi_table.c | 24 ++++++++++- test/dm/acpi.c | 28 +++++++++++++ 4 files changed, 130 insertions(+), 46 deletions(-)
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index 235fc2268b..b73cc64339 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -10,6 +10,7 @@ #include <cpu.h> #include <dm.h> #include <dm/uclass-internal.h> +#include <mapmem.h> #include <serial.h> #include <version.h> #include <acpi/acpi_table.h> @@ -19,6 +20,7 @@ #include <asm/mpspec.h> #include <asm/tables.h> #include <asm/arch/global_nvs.h> +#include <dm/acpi.h>
/* * IASL compiles the dsdt entries and writes the hex values @@ -478,9 +480,9 @@ static void acpi_create_spcr(struct acpi_spcr *spcr) /* * QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c */ -ulong write_acpi_tables(ulong start) +ulong write_acpi_tables(ulong start_addr) { - u32 current; + struct acpi_ctx sctx, *ctx = &sctx; struct acpi_rsdp *rsdp; struct acpi_rsdt *rsdt; struct acpi_xsdt *xsdt; @@ -491,60 +493,61 @@ ulong write_acpi_tables(ulong start) struct acpi_madt *madt; struct acpi_csrt *csrt; struct acpi_spcr *spcr; + void *start; + ulong addr; int i;
- current = start; + start = map_sysmem(start_addr, 0); + ctx->current = start;
/* Align ACPI tables to 16 byte */ - current = ALIGN(current, 16); + acpi_align(ctx);
- debug("ACPI: Writing ACPI tables at %lx\n", start); + debug("ACPI: Writing ACPI tables at %lx\n", start_addr);
/* We need at least an RSDP and an RSDT Table */ - rsdp = (struct acpi_rsdp *)current; - current += sizeof(struct acpi_rsdp); - current = ALIGN(current, 16); - rsdt = (struct acpi_rsdt *)current; - current += sizeof(struct acpi_rsdt); - current = ALIGN(current, 16); - xsdt = (struct acpi_xsdt *)current; - current += sizeof(struct acpi_xsdt); + rsdp = ctx->current; + acpi_inc_align(ctx, sizeof(struct acpi_rsdp)); + rsdt = ctx->current; + acpi_inc_align(ctx, sizeof(struct acpi_rsdt)); + xsdt = ctx->current; + acpi_inc_align(ctx, sizeof(struct acpi_xsdt)); /* * Per ACPI spec, the FACS table address must be aligned to a 64 byte * boundary (Windows checks this, but Linux does not). */ - current = ALIGN(current, 64); + acpi_align64(ctx);
/* clear all table memory */ - memset((void *)start, 0, current - start); + memset((void *)start, 0, ctx->current - start);
acpi_write_rsdp(rsdp, rsdt, xsdt); acpi_write_rsdt(rsdt); acpi_write_xsdt(xsdt);
debug("ACPI: * FACS\n"); - facs = (struct acpi_facs *)current; - current += sizeof(struct acpi_facs); - current = ALIGN(current, 16); + facs = ctx->current; + acpi_inc_align(ctx, sizeof(struct acpi_facs));
acpi_create_facs(facs);
debug("ACPI: * DSDT\n"); - dsdt = (struct acpi_table_header *)current; + dsdt = ctx->current; memcpy(dsdt, &AmlCode, sizeof(struct acpi_table_header)); - current += sizeof(struct acpi_table_header); - memcpy((char *)current, + acpi_inc(ctx, sizeof(struct acpi_table_header)); + memcpy(ctx->current, (char *)&AmlCode + sizeof(struct acpi_table_header), dsdt->length - sizeof(struct acpi_table_header)); - current += dsdt->length - sizeof(struct acpi_table_header); - current = ALIGN(current, 16); + acpi_inc_align(ctx, dsdt->length - sizeof(struct acpi_table_header));
/* Pack GNVS into the ACPI table area */ for (i = 0; i < dsdt->length; i++) { u32 *gnvs = (u32 *)((u32)dsdt + i); if (*gnvs == ACPI_GNVS_ADDR) { - debug("Fix up global NVS in DSDT to 0x%08x\n", current); - *gnvs = current; + ulong addr = (ulong)map_to_sysmem(ctx->current); + + debug("Fix up global NVS in DSDT to %#08lx\n", addr); + *gnvs = addr; break; } } @@ -554,51 +557,46 @@ ulong write_acpi_tables(ulong start) dsdt->checksum = table_compute_checksum((void *)dsdt, dsdt->length);
/* Fill in platform-specific global NVS variables */ - acpi_create_gnvs((struct acpi_global_nvs *)current); - current += sizeof(struct acpi_global_nvs); - current = ALIGN(current, 16); + acpi_create_gnvs(ctx->current); + acpi_inc_align(ctx, sizeof(struct acpi_global_nvs));
debug("ACPI: * FADT\n"); - fadt = (struct acpi_fadt *)current; - current += sizeof(struct acpi_fadt); - current = ALIGN(current, 16); + fadt = ctx->current; + acpi_inc_align(ctx, sizeof(struct acpi_fadt)); acpi_create_fadt(fadt, facs, dsdt); acpi_add_table(rsdp, fadt);
debug("ACPI: * MADT\n"); - madt = (struct acpi_madt *)current; + madt = ctx->current; acpi_create_madt(madt); - current += madt->header.length; + acpi_inc_align(ctx, madt->header.length); acpi_add_table(rsdp, madt); - current = ALIGN(current, 16);
debug("ACPI: * MCFG\n"); - mcfg = (struct acpi_mcfg *)current; + mcfg = ctx->current; acpi_create_mcfg(mcfg); - current += mcfg->header.length; + acpi_inc_align(ctx, mcfg->header.length); acpi_add_table(rsdp, mcfg); - current = ALIGN(current, 16);
debug("ACPI: * CSRT\n"); - csrt = (struct acpi_csrt *)current; + csrt = ctx->current; acpi_create_csrt(csrt); - current += csrt->header.length; + acpi_inc_align(ctx, csrt->header.length); acpi_add_table(rsdp, csrt); - current = ALIGN(current, 16);
debug("ACPI: * SPCR\n"); - spcr = (struct acpi_spcr *)current; + spcr = ctx->current; acpi_create_spcr(spcr); - current += spcr->header.length; + acpi_inc_align(ctx, spcr->header.length); acpi_add_table(rsdp, spcr); - current = ALIGN(current, 16);
- debug("current = %x\n", current); + addr = map_to_sysmem(ctx->current); + debug("current = %lx\n", addr);
acpi_rsdp_addr = (unsigned long)rsdp; debug("ACPI: done\n");
- return current; + return addr; }
ulong acpi_get_rsdp_addr(void) diff --git a/include/acpi/acpi_table.h b/include/acpi/acpi_table.h index a2bd929c92..6fd4c5241a 100644 --- a/include/acpi/acpi_table.h +++ b/include/acpi/acpi_table.h @@ -23,6 +23,8 @@
#if !defined(__ACPI__)
+struct acpi_ctx; + /* * RSDP (Root System Description Pointer) * Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum @@ -515,6 +517,40 @@ int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags); */ void acpi_fill_header(struct acpi_table_header *header, char *signature);
+/** + * acpi_align() - Align the ACPI output pointer to a 16-byte boundary + * + * @ctx: ACPI context + */ +void acpi_align(struct acpi_ctx *ctx); + +/** + * acpi_align64() - Align the ACPI output pointer to a 64-byte boundary + * + * @ctx: ACPI context + */ +void acpi_align64(struct acpi_ctx *ctx); + +/** + * acpi_inc() - Increment the ACPI output pointer by a bit + * + * The pointer is NOT aligned afterwards. + * + * @ctx: ACPI context + * @amount: Amount to increment by + */ +void acpi_inc(struct acpi_ctx *ctx, uint amount); + +/** + * acpi_inc_align() - Increment the ACPI output pointer by a bit and align + * + * The pointer is aligned afterwards to a 16-byte boundary + * + * @ctx: ACPI context + * @amount: Amount to increment by + */ +void acpi_inc_align(struct acpi_ctx *ctx, uint amount); + #endif /* !__ACPI__*/
#include <asm/acpi_table.h> diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c index 372f19b16d..07d9bbb0af 100644 --- a/lib/acpi/acpi_table.c +++ b/lib/acpi/acpi_table.c @@ -6,10 +6,11 @@ */
#include <common.h> -#include <acpi/acpi_table.h> #include <dm.h> #include <cpu.h> #include <version.h> +#include <acpi/acpi_table.h> +#include <dm/acpi.h>
int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags) { @@ -98,3 +99,24 @@ void acpi_fill_header(struct acpi_table_header *header, char *signature) header->oem_revision = U_BOOT_BUILD_DATE; memcpy(header->aslc_id, ASLC_ID, 4); } + +void acpi_align(struct acpi_ctx *ctx) +{ + ctx->current = (void *)ALIGN((ulong)ctx->current, 16); +} + +void acpi_align64(struct acpi_ctx *ctx) +{ + ctx->current = (void *)ALIGN((ulong)ctx->current, 64); +} + +void acpi_inc(struct acpi_ctx *ctx, uint amount) +{ + ctx->current += amount; +} + +void acpi_inc_align(struct acpi_ctx *ctx, uint amount) +{ + ctx->current += amount; + acpi_align(ctx); +} diff --git a/test/dm/acpi.c b/test/dm/acpi.c index fb7b7e46b2..59aee1f614 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -151,3 +151,31 @@ static int dm_test_acpi_write_tables(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_acpi_write_tables, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test basic ACPI functions */ +static int dm_test_acpi_basic(struct unit_test_state *uts) +{ + struct acpi_ctx ctx; + + /* Check align works */ + ctx.current = (void *)5; + acpi_align(&ctx); + ut_asserteq_ptr((void *)16, ctx.current); + + /* Check that align does nothing if already aligned */ + acpi_align(&ctx); + ut_asserteq_ptr((void *)16, ctx.current); + acpi_align64(&ctx); + ut_asserteq_ptr((void *)64, ctx.current); + acpi_align64(&ctx); + ut_asserteq_ptr((void *)64, ctx.current); + + /* Check incrementing */ + acpi_inc(&ctx, 3); + ut_asserteq_ptr((void *)67, ctx.current); + acpi_inc_align(&ctx, 3); + ut_asserteq_ptr((void *)80, ctx.current); + + return 0; +} +DM_TEST(dm_test_acpi_basic, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

Call the new core function to permit devices to write their own ACPI tables. These tables will appear after all other tables.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Wolfgang Wallner wolfgang.wallner@br-automation.com ---
Changes in v7: None Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None
arch/x86/lib/acpi_table.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index b73cc64339..d8622da394 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -590,6 +590,8 @@ ulong write_acpi_tables(ulong start_addr) acpi_inc_align(ctx, spcr->header.length); acpi_add_table(rsdp, spcr);
+ acpi_write_dev_tables(ctx); + addr = map_to_sysmem(ctx->current); debug("current = %lx\n", addr);

We don't actually support tables without an XSDT so we can drop this dead code.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Wolfgang Wallner wolfgang.wallner@br-automation.com ---
Changes in v7: None Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None
arch/x86/lib/acpi_table.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index d8622da394..de1acb0ebb 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -42,19 +42,8 @@ static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, rsdp->length = sizeof(struct acpi_rsdp); rsdp->rsdt_address = (u32)rsdt;
- /* - * Revision: ACPI 1.0: 0, ACPI 2.0/3.0/4.0: 2 - * - * Some OSes expect an XSDT to be present for RSD PTR revisions >= 2. - * If we don't have an ACPI XSDT, force ACPI 1.0 (and thus RSD PTR - * revision 0) - */ - if (xsdt == NULL) { - rsdp->revision = ACPI_RSDP_REV_ACPI_1_0; - } else { - rsdp->xsdt_address = (u64)(u32)xsdt; - rsdp->revision = ACPI_RSDP_REV_ACPI_2_0; - } + rsdp->xsdt_address = (u64)(u32)xsdt; + rsdp->revision = ACPI_RSDP_REV_ACPI_2_0;
/* Calculate checksums */ rsdp->checksum = table_compute_checksum((void *)rsdp, 20);

Move this code to a generic location so that we can test it with sandbox. This requires adding a few new fields to acpi_ctx, so drop the local variables used in the original code.
Also use mapmem to avoid pointer-to-address casts which don't work on sandbox.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Wolfgang Wallner wolfgang.wallner@br-automation.com ---
Changes in v7: None Changes in v5: None Changes in v4: None Changes in v3: - Fix 'RSDP' typo
Changes in v2: None
arch/x86/lib/acpi_table.c | 83 +++++---------------------------------- include/acpi/acpi_table.h | 9 +++++ include/dm/acpi.h | 5 +++ lib/acpi/acpi_table.c | 61 ++++++++++++++++++++++++++++ test/dm/acpi.c | 4 ++ 5 files changed, 89 insertions(+), 73 deletions(-)
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index de1acb0ebb..ff8cee51d6 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -83,67 +83,6 @@ static void acpi_write_xsdt(struct acpi_xsdt *xsdt) sizeof(struct acpi_xsdt)); }
-/** - * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length - * and checksum. - */ -static void acpi_add_table(struct acpi_rsdp *rsdp, void *table) -{ - int i, entries_num; - struct acpi_rsdt *rsdt; - struct acpi_xsdt *xsdt; - - /* The RSDT is mandatory while the XSDT is not */ - rsdt = (struct acpi_rsdt *)rsdp->rsdt_address; - - /* This should always be MAX_ACPI_TABLES */ - entries_num = ARRAY_SIZE(rsdt->entry); - - for (i = 0; i < entries_num; i++) { - if (rsdt->entry[i] == 0) - break; - } - - if (i >= entries_num) { - debug("ACPI: Error: too many tables\n"); - return; - } - - /* Add table to the RSDT */ - rsdt->entry[i] = (u32)table; - - /* Fix RSDT length or the kernel will assume invalid entries */ - rsdt->header.length = sizeof(struct acpi_table_header) + - sizeof(u32) * (i + 1); - - /* Re-calculate checksum */ - rsdt->header.checksum = 0; - rsdt->header.checksum = table_compute_checksum((u8 *)rsdt, - rsdt->header.length); - - /* The RSDT is mandatory while the XSDT is not */ - if (!rsdp->xsdt_address) - return; - - /* - * And now the same thing for the XSDT. We use the same index as for - * now we want the XSDT and RSDT to always be in sync in U-Boot - */ - xsdt = (struct acpi_xsdt *)((u32)rsdp->xsdt_address); - - /* Add table to the XSDT */ - xsdt->entry[i] = (u64)(u32)table; - - /* Fix XSDT length */ - xsdt->header.length = sizeof(struct acpi_table_header) + - sizeof(u64) * (i + 1); - - /* Re-calculate checksum */ - xsdt->header.checksum = 0; - xsdt->header.checksum = table_compute_checksum((u8 *)xsdt, - xsdt->header.length); -} - static void acpi_create_facs(struct acpi_facs *facs) { memset((void *)facs, 0, sizeof(struct acpi_facs)); @@ -472,8 +411,6 @@ static void acpi_create_spcr(struct acpi_spcr *spcr) ulong write_acpi_tables(ulong start_addr) { struct acpi_ctx sctx, *ctx = &sctx; - struct acpi_rsdp *rsdp; - struct acpi_rsdt *rsdt; struct acpi_xsdt *xsdt; struct acpi_facs *facs; struct acpi_table_header *dsdt; @@ -495,9 +432,9 @@ ulong write_acpi_tables(ulong start_addr) debug("ACPI: Writing ACPI tables at %lx\n", start_addr);
/* We need at least an RSDP and an RSDT Table */ - rsdp = ctx->current; + ctx->rsdp = ctx->current; acpi_inc_align(ctx, sizeof(struct acpi_rsdp)); - rsdt = ctx->current; + ctx->rsdt = ctx->current; acpi_inc_align(ctx, sizeof(struct acpi_rsdt)); xsdt = ctx->current; acpi_inc_align(ctx, sizeof(struct acpi_xsdt)); @@ -510,8 +447,8 @@ ulong write_acpi_tables(ulong start_addr) /* clear all table memory */ memset((void *)start, 0, ctx->current - start);
- acpi_write_rsdp(rsdp, rsdt, xsdt); - acpi_write_rsdt(rsdt); + acpi_write_rsdp(ctx->rsdp, ctx->rsdt, xsdt); + acpi_write_rsdt(ctx->rsdt); acpi_write_xsdt(xsdt);
debug("ACPI: * FACS\n"); @@ -553,38 +490,38 @@ ulong write_acpi_tables(ulong start_addr) fadt = ctx->current; acpi_inc_align(ctx, sizeof(struct acpi_fadt)); acpi_create_fadt(fadt, facs, dsdt); - acpi_add_table(rsdp, fadt); + acpi_add_table(ctx, fadt);
debug("ACPI: * MADT\n"); madt = ctx->current; acpi_create_madt(madt); acpi_inc_align(ctx, madt->header.length); - acpi_add_table(rsdp, madt); + acpi_add_table(ctx, madt);
debug("ACPI: * MCFG\n"); mcfg = ctx->current; acpi_create_mcfg(mcfg); acpi_inc_align(ctx, mcfg->header.length); - acpi_add_table(rsdp, mcfg); + acpi_add_table(ctx, mcfg);
debug("ACPI: * CSRT\n"); csrt = ctx->current; acpi_create_csrt(csrt); acpi_inc_align(ctx, csrt->header.length); - acpi_add_table(rsdp, csrt); + acpi_add_table(ctx, csrt);
debug("ACPI: * SPCR\n"); spcr = ctx->current; acpi_create_spcr(spcr); acpi_inc_align(ctx, spcr->header.length); - acpi_add_table(rsdp, spcr); + acpi_add_table(ctx, spcr);
acpi_write_dev_tables(ctx);
addr = map_to_sysmem(ctx->current); debug("current = %lx\n", addr);
- acpi_rsdp_addr = (unsigned long)rsdp; + acpi_rsdp_addr = (unsigned long)ctx->rsdp; debug("ACPI: done\n");
return addr; diff --git a/include/acpi/acpi_table.h b/include/acpi/acpi_table.h index 6fd4c5241a..55349c0bb6 100644 --- a/include/acpi/acpi_table.h +++ b/include/acpi/acpi_table.h @@ -551,6 +551,15 @@ void acpi_inc(struct acpi_ctx *ctx, uint amount); */ void acpi_inc_align(struct acpi_ctx *ctx, uint amount);
+/** + * acpi_add_table() - Add a new table to the RSDP and XSDT + * + * @ctx: ACPI context + * @table: Table to add + * @return 0 if OK, -E2BIG if too many tables + */ +int acpi_add_table(struct acpi_ctx *ctx, void *table); + #endif /* !__ACPI__*/
#include <asm/acpi_table.h> diff --git a/include/dm/acpi.h b/include/dm/acpi.h index 69d69d7f42..c6c63b8183 100644 --- a/include/dm/acpi.h +++ b/include/dm/acpi.h @@ -30,9 +30,14 @@ * This contains a few useful pieces of information used when writing * * @current: Current address for writing + * @rsdp: Pointer to the Root System Description Pointer, typically used when + * adding a new table. The RSDP holds pointers to the RSDT and XSDT. + * @rsdt: Pointer to the Root System Description Table */ struct acpi_ctx { void *current; + struct acpi_rsdp *rsdp; + struct acpi_rsdt *rsdt; };
/** diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c index 07d9bbb0af..5311ae9368 100644 --- a/lib/acpi/acpi_table.c +++ b/lib/acpi/acpi_table.c @@ -8,6 +8,8 @@ #include <common.h> #include <dm.h> #include <cpu.h> +#include <mapmem.h> +#include <tables_csum.h> #include <version.h> #include <acpi/acpi_table.h> #include <dm/acpi.h> @@ -120,3 +122,62 @@ void acpi_inc_align(struct acpi_ctx *ctx, uint amount) ctx->current += amount; acpi_align(ctx); } + +/** + * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length + * and checksum. + */ +int acpi_add_table(struct acpi_ctx *ctx, void *table) +{ + int i, entries_num; + struct acpi_rsdt *rsdt; + struct acpi_xsdt *xsdt; + + /* The RSDT is mandatory while the XSDT is not */ + rsdt = ctx->rsdt; + + /* This should always be MAX_ACPI_TABLES */ + entries_num = ARRAY_SIZE(rsdt->entry); + + for (i = 0; i < entries_num; i++) { + if (rsdt->entry[i] == 0) + break; + } + + if (i >= entries_num) { + debug("ACPI: Error: too many tables\n"); + return -E2BIG; + } + + /* Add table to the RSDT */ + rsdt->entry[i] = map_to_sysmem(table); + + /* Fix RSDT length or the kernel will assume invalid entries */ + rsdt->header.length = sizeof(struct acpi_table_header) + + (sizeof(u32) * (i + 1)); + + /* Re-calculate checksum */ + rsdt->header.checksum = 0; + rsdt->header.checksum = table_compute_checksum((u8 *)rsdt, + rsdt->header.length); + + /* + * And now the same thing for the XSDT. We use the same index as for + * now we want the XSDT and RSDT to always be in sync in U-Boot + */ + xsdt = (struct acpi_xsdt *)((uintptr_t)ctx->rsdp->xsdt_address); + + /* Add table to the XSDT */ + xsdt->entry[i] = map_to_sysmem(table); + + /* Fix XSDT length */ + xsdt->header.length = sizeof(struct acpi_table_header) + + (sizeof(u64) * (i + 1)); + + /* Re-calculate checksum */ + xsdt->header.checksum = 0; + xsdt->header.checksum = table_compute_checksum((u8 *)xsdt, + xsdt->header.length); + + return 0; +} diff --git a/test/dm/acpi.c b/test/dm/acpi.c index 59aee1f614..ffc611efb8 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -21,10 +21,14 @@ static int testacpi_write_tables(const struct udevice *dev, struct acpi_ctx *ctx) { struct acpi_dmar *dmar; + int ret;
dmar = (struct acpi_dmar *)ctx->current; acpi_create_dmar(dmar, DMAR_INTR_REMAP); ctx->current += sizeof(struct acpi_dmar); + ret = acpi_add_table(ctx, dmar); + if (ret) + return log_msg_ret("add", ret);
return 0; }

We always write three basic tables to ACPI at the start. Move this into its own function, along with acpi_fill_header(), so we can write a test for this code.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v7: None Changes in v5: None Changes in v4: - Put back cast on table_compute_checksum()
Changes in v3: - Fix 'XDST' typo - Move acpi_align_large() out of dm_test_acpi_setup_base_tables() - Beef up the comment explaining how the unaligned address is used
Changes in v2: None
arch/x86/lib/acpi_table.c | 72 +----------------------------------- include/acpi/acpi_table.h | 10 +++++ lib/acpi/acpi_table.c | 77 +++++++++++++++++++++++++++++++++++++++ test/dm/acpi.c | 58 ++++++++++++++++++++++++++++- 4 files changed, 144 insertions(+), 73 deletions(-)
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index ff8cee51d6..600bde2f5f 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -31,58 +31,6 @@ extern const unsigned char AmlCode[]; /* ACPI RSDP address to be used in boot parameters */ static ulong acpi_rsdp_addr;
-static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, - struct acpi_xsdt *xsdt) -{ - memset(rsdp, 0, sizeof(struct acpi_rsdp)); - - memcpy(rsdp->signature, RSDP_SIG, 8); - memcpy(rsdp->oem_id, OEM_ID, 6); - - rsdp->length = sizeof(struct acpi_rsdp); - rsdp->rsdt_address = (u32)rsdt; - - rsdp->xsdt_address = (u64)(u32)xsdt; - rsdp->revision = ACPI_RSDP_REV_ACPI_2_0; - - /* Calculate checksums */ - rsdp->checksum = table_compute_checksum((void *)rsdp, 20); - rsdp->ext_checksum = table_compute_checksum((void *)rsdp, - sizeof(struct acpi_rsdp)); -} - -static void acpi_write_rsdt(struct acpi_rsdt *rsdt) -{ - struct acpi_table_header *header = &(rsdt->header); - - /* Fill out header fields */ - acpi_fill_header(header, "RSDT"); - header->length = sizeof(struct acpi_rsdt); - header->revision = 1; - - /* Entries are filled in later, we come with an empty set */ - - /* Fix checksum */ - header->checksum = table_compute_checksum((void *)rsdt, - sizeof(struct acpi_rsdt)); -} - -static void acpi_write_xsdt(struct acpi_xsdt *xsdt) -{ - struct acpi_table_header *header = &(xsdt->header); - - /* Fill out header fields */ - acpi_fill_header(header, "XSDT"); - header->length = sizeof(struct acpi_xsdt); - header->revision = 1; - - /* Entries are filled in later, we come with an empty set */ - - /* Fix checksum */ - header->checksum = table_compute_checksum((void *)xsdt, - sizeof(struct acpi_xsdt)); -} - static void acpi_create_facs(struct acpi_facs *facs) { memset((void *)facs, 0, sizeof(struct acpi_facs)); @@ -411,7 +359,6 @@ static void acpi_create_spcr(struct acpi_spcr *spcr) ulong write_acpi_tables(ulong start_addr) { struct acpi_ctx sctx, *ctx = &sctx; - struct acpi_xsdt *xsdt; struct acpi_facs *facs; struct acpi_table_header *dsdt; struct acpi_fadt *fadt; @@ -424,33 +371,16 @@ ulong write_acpi_tables(ulong start_addr) int i;
start = map_sysmem(start_addr, 0); - ctx->current = start; - - /* Align ACPI tables to 16 byte */ - acpi_align(ctx);
debug("ACPI: Writing ACPI tables at %lx\n", start_addr);
- /* We need at least an RSDP and an RSDT Table */ - ctx->rsdp = ctx->current; - acpi_inc_align(ctx, sizeof(struct acpi_rsdp)); - ctx->rsdt = ctx->current; - acpi_inc_align(ctx, sizeof(struct acpi_rsdt)); - xsdt = ctx->current; - acpi_inc_align(ctx, sizeof(struct acpi_xsdt)); + acpi_setup_base_tables(ctx, start); /* * Per ACPI spec, the FACS table address must be aligned to a 64 byte * boundary (Windows checks this, but Linux does not). */ acpi_align64(ctx);
- /* clear all table memory */ - memset((void *)start, 0, ctx->current - start); - - acpi_write_rsdp(ctx->rsdp, ctx->rsdt, xsdt); - acpi_write_rsdt(ctx->rsdt); - acpi_write_xsdt(xsdt); - debug("ACPI: * FACS\n"); facs = ctx->current; acpi_inc_align(ctx, sizeof(struct acpi_facs)); diff --git a/include/acpi/acpi_table.h b/include/acpi/acpi_table.h index 55349c0bb6..3681c5c8ed 100644 --- a/include/acpi/acpi_table.h +++ b/include/acpi/acpi_table.h @@ -560,6 +560,16 @@ void acpi_inc_align(struct acpi_ctx *ctx, uint amount); */ int acpi_add_table(struct acpi_ctx *ctx, void *table);
+/** + * acpi_setup_base_tables() - Set up context along with RSDP, RSDT and XSDT + * + * Set up the context with the given start position. Some basic tables are + * always needed, so set them up as well. + * + * @ctx: Context to set up + */ +void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start); + #endif /* !__ACPI__*/
#include <asm/acpi_table.h> diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c index 5311ae9368..85193c49e4 100644 --- a/lib/acpi/acpi_table.c +++ b/lib/acpi/acpi_table.c @@ -181,3 +181,80 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table)
return 0; } + +static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, + struct acpi_xsdt *xsdt) +{ + memset(rsdp, 0, sizeof(struct acpi_rsdp)); + + memcpy(rsdp->signature, RSDP_SIG, 8); + memcpy(rsdp->oem_id, OEM_ID, 6); + + rsdp->length = sizeof(struct acpi_rsdp); + rsdp->rsdt_address = map_to_sysmem(rsdt); + + rsdp->xsdt_address = map_to_sysmem(xsdt); + rsdp->revision = ACPI_RSDP_REV_ACPI_2_0; + + /* Calculate checksums */ + rsdp->checksum = table_compute_checksum(rsdp, 20); + rsdp->ext_checksum = table_compute_checksum(rsdp, + sizeof(struct acpi_rsdp)); +} + +static void acpi_write_rsdt(struct acpi_rsdt *rsdt) +{ + struct acpi_table_header *header = &rsdt->header; + + /* Fill out header fields */ + acpi_fill_header(header, "RSDT"); + header->length = sizeof(struct acpi_rsdt); + header->revision = 1; + + /* Entries are filled in later, we come with an empty set */ + + /* Fix checksum */ + header->checksum = table_compute_checksum(rsdt, + sizeof(struct acpi_rsdt)); +} + +static void acpi_write_xsdt(struct acpi_xsdt *xsdt) +{ + struct acpi_table_header *header = &xsdt->header; + + /* Fill out header fields */ + acpi_fill_header(header, "XSDT"); + header->length = sizeof(struct acpi_xsdt); + header->revision = 1; + + /* Entries are filled in later, we come with an empty set */ + + /* Fix checksum */ + header->checksum = table_compute_checksum(xsdt, + sizeof(struct acpi_xsdt)); +} + +void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start) +{ + struct acpi_xsdt *xsdt; + + ctx->current = start; + + /* Align ACPI tables to 16 byte */ + acpi_align(ctx); + + /* We need at least an RSDP and an RSDT Table */ + ctx->rsdp = ctx->current; + acpi_inc_align(ctx, sizeof(struct acpi_rsdp)); + ctx->rsdt = ctx->current; + acpi_inc_align(ctx, sizeof(struct acpi_rsdt)); + xsdt = ctx->current; + acpi_inc_align(ctx, sizeof(struct acpi_xsdt)); + + /* clear all table memory */ + memset((void *)start, '\0', ctx->current - start); + + acpi_write_rsdp(ctx->rsdp, ctx->rsdt, xsdt); + acpi_write_rsdt(ctx->rsdt); + acpi_write_xsdt(xsdt); +} diff --git a/test/dm/acpi.c b/test/dm/acpi.c index ffc611efb8..beb1b6da73 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -8,6 +8,9 @@
#include <common.h> #include <dm.h> +#include <malloc.h> +#include <mapmem.h> +#include <tables_csum.h> #include <version.h> #include <acpi/acpi_table.h> #include <dm/acpi.h> @@ -137,9 +140,9 @@ static int dm_test_acpi_write_tables(struct unit_test_state *uts) buf = malloc(BUF_SIZE); ut_assertnonnull(buf);
- ctx.current = buf; + acpi_setup_base_tables(&ctx, buf); + dmar = ctx.current; ut_assertok(acpi_write_dev_tables(&ctx)); - dmar = buf;
/* * We should have two dmar tables, one for each "denx,u-boot-acpi-test" @@ -152,6 +155,11 @@ static int dm_test_acpi_write_tables(struct unit_test_state *uts) ut_asserteq(DMAR_INTR_REMAP, dmar[1].flags); ut_asserteq(32 - 1, dmar[1].host_address_width);
+ /* Check that the pointers were added correctly */ + ut_asserteq(map_to_sysmem(dmar), ctx.rsdt->entry[0]); + ut_asserteq(map_to_sysmem(dmar + 1), ctx.rsdt->entry[1]); + ut_asserteq(0, ctx.rsdt->entry[2]); + return 0; } DM_TEST(dm_test_acpi_write_tables, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); @@ -183,3 +191,49 @@ static int dm_test_acpi_basic(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_acpi_basic, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test acpi_setup_base_tables */ +static int dm_test_acpi_setup_base_tables(struct unit_test_state *uts) +{ + struct acpi_rsdp *rsdp; + struct acpi_rsdt *rsdt; + struct acpi_xsdt *xsdt; + struct acpi_ctx ctx; + void *buf, *end; + + /* + * Use an unaligned address deliberately, by allocating an aligned + * address and then adding 4 to it + */ + buf = memalign(64, BUF_SIZE); + ut_assertnonnull(buf); + acpi_setup_base_tables(&ctx, buf + 4); + + rsdp = buf + 16; + ut_asserteq_ptr(rsdp, ctx.rsdp); + ut_assertok(memcmp(RSDP_SIG, rsdp->signature, sizeof(rsdp->signature))); + ut_asserteq(sizeof(*rsdp), rsdp->length); + ut_assertok(table_compute_checksum(rsdp, 20)); + ut_assertok(table_compute_checksum(rsdp, sizeof(*rsdp))); + + rsdt = PTR_ALIGN((void *)rsdp + sizeof(*rsdp), 16); + ut_asserteq_ptr(rsdt, ctx.rsdt); + ut_assertok(memcmp("RSDT", rsdt->header.signature, ACPI_NAME_LEN)); + ut_asserteq(sizeof(*rsdt), rsdt->header.length); + ut_assertok(table_compute_checksum(rsdt, sizeof(*rsdt))); + + xsdt = PTR_ALIGN((void *)rsdt + sizeof(*rsdt), 16); + ut_assertok(memcmp("XSDT", xsdt->header.signature, ACPI_NAME_LEN)); + ut_asserteq(sizeof(*xsdt), xsdt->header.length); + ut_assertok(table_compute_checksum(xsdt, sizeof(*xsdt))); + + end = PTR_ALIGN((void *)xsdt + sizeof(*xsdt), 64); + ut_asserteq_ptr(end, ctx.current); + + ut_asserteq(map_to_sysmem(rsdt), rsdp->rsdt_address); + ut_asserteq(map_to_sysmem(xsdt), rsdp->xsdt_address); + + return 0; +} +DM_TEST(dm_test_acpi_setup_base_tables, + DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

Hi Simon, Wolfgang,
On Mon, Apr 20, 2020 at 4:37 AM Simon Glass sjg@chromium.org wrote:
We always write three basic tables to ACPI at the start. Move this into its own function, along with acpi_fill_header(), so we can write a test for this code.
Signed-off-by: Simon Glass sjg@chromium.org
I see Wolfgang gave a RB tag to the v5 patch, so I am going to add that tag here since no changes between v5 and v7
Reviewed-by: Wolfgang Wallner wolfgang.wallner@br-automation.com
But I wonder why this new series is tagged as v7. Do I miss v6?
Changes in v7: None Changes in v5: None Changes in v4:
- Put back cast on table_compute_checksum()
Changes in v3:
- Fix 'XDST' typo
- Move acpi_align_large() out of dm_test_acpi_setup_base_tables()
- Beef up the comment explaining how the unaligned address is used
Changes in v2: None
arch/x86/lib/acpi_table.c | 72 +----------------------------------- include/acpi/acpi_table.h | 10 +++++ lib/acpi/acpi_table.c | 77 +++++++++++++++++++++++++++++++++++++++ test/dm/acpi.c | 58 ++++++++++++++++++++++++++++- 4 files changed, 144 insertions(+), 73 deletions(-)
Regards, Bin

Hi Bin,
On Thu, 23 Apr 2020 at 03:38, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon, Wolfgang,
On Mon, Apr 20, 2020 at 4:37 AM Simon Glass sjg@chromium.org wrote:
We always write three basic tables to ACPI at the start. Move this into its own function, along with acpi_fill_header(), so we can write a test for this code.
Signed-off-by: Simon Glass sjg@chromium.org
I see Wolfgang gave a RB tag to the v5 patch, so I am going to add that tag here since no changes between v5 and v7
Reviewed-by: Wolfgang Wallner wolfgang.wallner@br-automation.com
But I wonder why this new series is tagged as v7. Do I miss v6?
I'm not sure...but I think I might have skipped a version.
Regards, SImon

Hi Bin, Simon,
-----"Simon Glass" sjg@chromium.org schrieb: -----
Betreff: Re: [PATCH v7 7/9] acpi: Put table-setup code in its own function
Hi Bin,
On Thu, 23 Apr 2020 at 03:38, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon, Wolfgang,
On Mon, Apr 20, 2020 at 4:37 AM Simon Glass sjg@chromium.org wrote:
We always write three basic tables to ACPI at the start. Move this into its own function, along with acpi_fill_header(), so we can write a test for this code.
Signed-off-by: Simon Glass sjg@chromium.org
I see Wolfgang gave a RB tag to the v5 patch, so I am going to add that tag here since no changes between v5 and v7
Reviewed-by: Wolfgang Wallner wolfgang.wallner@br-automation.com
But I wonder why this new series is tagged as v7. Do I miss v6?
I'm not sure...but I think I might have skipped a version.
v5 was the last full version of part A of this series. v6 contained only two fixes for v5, and was applied together with parts of v5. v7 are the remainig patches of v5.
regards, Wolfgang

Hi Wolfgang,
On Mon, Apr 27, 2020 at 2:36 PM Wolfgang Wallner wolfgang.wallner@br-automation.com wrote:
Hi Bin, Simon,
-----"Simon Glass" sjg@chromium.org schrieb: -----
Betreff: Re: [PATCH v7 7/9] acpi: Put table-setup code in its own function
Hi Bin,
On Thu, 23 Apr 2020 at 03:38, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon, Wolfgang,
On Mon, Apr 20, 2020 at 4:37 AM Simon Glass sjg@chromium.org wrote:
We always write three basic tables to ACPI at the start. Move this into its own function, along with acpi_fill_header(), so we can write a test for this code.
Signed-off-by: Simon Glass sjg@chromium.org
I see Wolfgang gave a RB tag to the v5 patch, so I am going to add that tag here since no changes between v5 and v7
Reviewed-by: Wolfgang Wallner wolfgang.wallner@br-automation.com
But I wonder why this new series is tagged as v7. Do I miss v6?
I'm not sure...but I think I might have skipped a version.
v5 was the last full version of part A of this series. v6 contained only two fixes for v5, and was applied together with parts of v5. v7 are the remainig patches of v5.
Ah, yes! Thanks for the information.
Regards, Bin

Put this in the context along with the other important pointers.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Wolfgang Wallner wolfgang.wallner@br-automation.com ---
Changes in v7: None Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None
include/dm/acpi.h | 2 ++ lib/acpi/acpi_table.c | 10 ++++------ test/dm/acpi.c | 5 +++++ 3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/include/dm/acpi.h b/include/dm/acpi.h index c6c63b8183..7563a4c60a 100644 --- a/include/dm/acpi.h +++ b/include/dm/acpi.h @@ -33,11 +33,13 @@ * @rsdp: Pointer to the Root System Description Pointer, typically used when * adding a new table. The RSDP holds pointers to the RSDT and XSDT. * @rsdt: Pointer to the Root System Description Table + * @xsdt: Pointer to the Extended System Description Table */ struct acpi_ctx { void *current; struct acpi_rsdp *rsdp; struct acpi_rsdt *rsdt; + struct acpi_xsdt *xsdt; };
/** diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c index 85193c49e4..9d2b49f8ba 100644 --- a/lib/acpi/acpi_table.c +++ b/lib/acpi/acpi_table.c @@ -165,7 +165,7 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table) * And now the same thing for the XSDT. We use the same index as for * now we want the XSDT and RSDT to always be in sync in U-Boot */ - xsdt = (struct acpi_xsdt *)((uintptr_t)ctx->rsdp->xsdt_address); + xsdt = ctx->xsdt;
/* Add table to the XSDT */ xsdt->entry[i] = map_to_sysmem(table); @@ -236,8 +236,6 @@ static void acpi_write_xsdt(struct acpi_xsdt *xsdt)
void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start) { - struct acpi_xsdt *xsdt; - ctx->current = start;
/* Align ACPI tables to 16 byte */ @@ -248,13 +246,13 @@ void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start) acpi_inc_align(ctx, sizeof(struct acpi_rsdp)); ctx->rsdt = ctx->current; acpi_inc_align(ctx, sizeof(struct acpi_rsdt)); - xsdt = ctx->current; + ctx->xsdt = ctx->current; acpi_inc_align(ctx, sizeof(struct acpi_xsdt));
/* clear all table memory */ memset((void *)start, '\0', ctx->current - start);
- acpi_write_rsdp(ctx->rsdp, ctx->rsdt, xsdt); + acpi_write_rsdp(ctx->rsdp, ctx->rsdt, ctx->xsdt); acpi_write_rsdt(ctx->rsdt); - acpi_write_xsdt(xsdt); + acpi_write_xsdt(ctx->xsdt); } diff --git a/test/dm/acpi.c b/test/dm/acpi.c index beb1b6da73..a29c3cab3e 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -160,6 +160,10 @@ static int dm_test_acpi_write_tables(struct unit_test_state *uts) ut_asserteq(map_to_sysmem(dmar + 1), ctx.rsdt->entry[1]); ut_asserteq(0, ctx.rsdt->entry[2]);
+ ut_asserteq(map_to_sysmem(dmar), ctx.xsdt->entry[0]); + ut_asserteq(map_to_sysmem(dmar + 1), ctx.xsdt->entry[1]); + ut_asserteq(0, ctx.xsdt->entry[2]); + return 0; } DM_TEST(dm_test_acpi_write_tables, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); @@ -223,6 +227,7 @@ static int dm_test_acpi_setup_base_tables(struct unit_test_state *uts) ut_assertok(table_compute_checksum(rsdt, sizeof(*rsdt)));
xsdt = PTR_ALIGN((void *)rsdt + sizeof(*rsdt), 16); + ut_asserteq_ptr(xsdt, ctx.xsdt); ut_assertok(memcmp("XSDT", xsdt->header.signature, ACPI_NAME_LEN)); ut_asserteq(sizeof(*xsdt), xsdt->header.length); ut_assertok(table_compute_checksum(xsdt, sizeof(*xsdt)));

It is useful to dump ACPI tables in U-Boot to see what has been generated. Add a command to handle this.
To allow the command to find the tables, add a position into the global data.
Support subcommands to list and dump the tables.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Wolfgang Wallner wolfgang.wallner@br-automation.com ---
Changes in v7: - Rebase to master
Changes in v5: None Changes in v4: - Rename list_fact() to list_fadt() - Add a comment to dump_hdr()
Changes in v3: None Changes in v2: None
arch/sandbox/include/asm/global_data.h | 1 + arch/x86/include/asm/global_data.h | 1 + cmd/Kconfig | 14 ++ cmd/Makefile | 1 + cmd/acpi.c | 186 +++++++++++++++++++++++++ lib/acpi/acpi_table.c | 1 + test/dm/acpi.c | 73 ++++++++++ 7 files changed, 277 insertions(+) create mode 100644 cmd/acpi.c
diff --git a/arch/sandbox/include/asm/global_data.h b/arch/sandbox/include/asm/global_data.h index f4ce72d566..f95ddb058a 100644 --- a/arch/sandbox/include/asm/global_data.h +++ b/arch/sandbox/include/asm/global_data.h @@ -13,6 +13,7 @@ struct arch_global_data { uint8_t *ram_buf; /* emulated RAM buffer */ void *text_base; /* pointer to base of text region */ + ulong acpi_start; /* Start address of ACPI tables */ };
#include <asm-generic/global_data.h> diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index f4c1839104..4aee2f3e8c 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -123,6 +123,7 @@ struct arch_global_data { #ifdef CONFIG_FSP_VERSION2 struct fsp_header *fsp_s_hdr; /* Pointer to FSP-S header */ #endif + ulong acpi_start; /* Start address of ACPI tables */ };
#endif diff --git a/cmd/Kconfig b/cmd/Kconfig index faa133da65..dd6dce8d20 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -190,6 +190,20 @@ comment "Commands"
menu "Info commands"
+config CMD_ACPI + bool "acpi" + default y if ACPIGEN + help + List and dump ACPI tables. ACPI (Advanced Configuration and Power + Interface) is used mostly on x86 for providing information to the + Operating System about devices in the system. The tables are set up + by the firmware, typically U-Boot but possibly an earlier firmware + module, if U-Boot is chain-loaded from something else. ACPI tables + can also include code, to perform hardware-specific tasks required + by the Operating Systems. This allows some amount of separation + between the firmware and OS, and is particularly useful when you + want to make hardware changes without the OS needing to be adjusted. + config CMD_BDI bool "bdinfo" default y diff --git a/cmd/Makefile b/cmd/Makefile index f1dd513a4b..15a9693ed0 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -11,6 +11,7 @@ obj-y += help.o obj-y += version.o
# command +obj-$(CONFIG_CMD_ACPI) += acpi.o obj-$(CONFIG_CMD_AES) += aes.o obj-$(CONFIG_CMD_AB_SELECT) += ab_select.o obj-$(CONFIG_CMD_ADC) += adc.o diff --git a/cmd/acpi.c b/cmd/acpi.c new file mode 100644 index 0000000000..203bd93bd5 --- /dev/null +++ b/cmd/acpi.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 Google LLC + * Written by Simon Glass sjg@chromium.org + */ +#include <common.h> +#include <command.h> +#include <mapmem.h> +#include <acpi/acpi_table.h> +#include <asm/acpi_table.h> +#include <dm/acpi.h> + +DECLARE_GLOBAL_DATA_PTR; + +/** + * dump_hdr() - Dump an ACPI header + * + * If the header is for FACS then it shows the revision information as well + * + * @hdr: ACPI header to dump + */ +static void dump_hdr(struct acpi_table_header *hdr) +{ + bool has_hdr = memcmp(hdr->signature, "FACS", ACPI_NAME_LEN); + + printf("%.*s %08lx %06x", ACPI_NAME_LEN, hdr->signature, + (ulong)map_to_sysmem(hdr), hdr->length); + if (has_hdr) { + printf(" (v%02d %.6s %.8s %u %.4s %d)\n", hdr->revision, + hdr->oem_id, hdr->oem_table_id, hdr->oem_revision, + hdr->aslc_id, hdr->aslc_revision); + } else { + printf("\n"); + } +} + +/** + * find_table() - Look up an ACPI table + * + * @sig: Signature of table (4 characters, upper case) + * @return pointer to table header, or NULL if not found + */ +struct acpi_table_header *find_table(const char *sig) +{ + struct acpi_rsdp *rsdp; + struct acpi_rsdt *rsdt; + int len, i, count; + + rsdp = map_sysmem(gd->arch.acpi_start, 0); + if (!rsdp) + return NULL; + rsdt = map_sysmem(rsdp->rsdt_address, 0); + len = rsdt->header.length - sizeof(rsdt->header); + count = len / sizeof(u32); + for (i = 0; i < count; i++) { + struct acpi_table_header *hdr; + + hdr = map_sysmem(rsdt->entry[i], 0); + if (!memcmp(hdr->signature, sig, ACPI_NAME_LEN)) + return hdr; + if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN)) { + struct acpi_fadt *fadt = (struct acpi_fadt *)hdr; + + if (!memcmp(sig, "DSDT", ACPI_NAME_LEN) && fadt->dsdt) + return map_sysmem(fadt->dsdt, 0); + if (!memcmp(sig, "FACS", ACPI_NAME_LEN) && + fadt->firmware_ctrl) + return map_sysmem(fadt->firmware_ctrl, 0); + } + } + + return NULL; +} + +static int dump_table_name(const char *sig) +{ + struct acpi_table_header *hdr; + + hdr = find_table(sig); + if (!hdr) + return -ENOENT; + printf("%.*s @ %08lx\n", ACPI_NAME_LEN, hdr->signature, + (ulong)map_to_sysmem(hdr)); + print_buffer(0, hdr, 1, hdr->length, 0); + + return 0; +} + +static void list_fadt(struct acpi_fadt *fadt) +{ + if (fadt->dsdt) + dump_hdr(map_sysmem(fadt->dsdt, 0)); + if (fadt->firmware_ctrl) + dump_hdr(map_sysmem(fadt->firmware_ctrl, 0)); +} + +static int list_rsdt(struct acpi_rsdt *rsdt, struct acpi_xsdt *xsdt) +{ + int len, i, count; + + dump_hdr(&rsdt->header); + if (xsdt) + dump_hdr(&xsdt->header); + len = rsdt->header.length - sizeof(rsdt->header); + count = len / sizeof(u32); + for (i = 0; i < count; i++) { + struct acpi_table_header *hdr; + + if (!rsdt->entry[i]) + break; + hdr = map_sysmem(rsdt->entry[i], 0); + dump_hdr(hdr); + if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN)) + list_fadt((struct acpi_fadt *)hdr); + if (xsdt) { + if (xsdt->entry[i] != rsdt->entry[i]) { + printf(" (xsdt mismatch %llx)\n", + xsdt->entry[i]); + } + } + } + + return 0; +} + +static int list_rsdp(struct acpi_rsdp *rsdp) +{ + struct acpi_rsdt *rsdt; + struct acpi_xsdt *xsdt; + + printf("RSDP %08lx %06x (v%02d %.6s)\n", (ulong)map_to_sysmem(rsdp), + rsdp->length, rsdp->revision, rsdp->oem_id); + rsdt = map_sysmem(rsdp->rsdt_address, 0); + xsdt = map_sysmem(rsdp->xsdt_address, 0); + list_rsdt(rsdt, xsdt); + + return 0; +} + +static int do_acpi_list(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct acpi_rsdp *rsdp; + + rsdp = map_sysmem(gd->arch.acpi_start, 0); + if (!rsdp) { + printf("No ACPI tables present\n"); + return 0; + } + printf("ACPI tables start at %lx\n", gd->arch.acpi_start); + list_rsdp(rsdp); + + return 0; +} + +static int do_acpi_dump(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + const char *name; + char sig[ACPI_NAME_LEN]; + int ret; + + if (argc < 2) + return CMD_RET_USAGE; + name = argv[1]; + if (strlen(name) != ACPI_NAME_LEN) { + printf("Table name '%s' must be four characters\n", name); + return CMD_RET_FAILURE; + } + str_to_upper(name, sig, -1); + ret = dump_table_name(sig); + if (ret) { + printf("Table '%.*s' not found\n", ACPI_NAME_LEN, sig); + return CMD_RET_FAILURE; + } + + return 0; +} + +static char acpi_help_text[] = + "list - list ACPI tables\n" + "acpi dump <name> - Dump ACPI table"; + +U_BOOT_CMD_WITH_SUBCMDS(acpi, "ACPI tables", acpi_help_text, + U_BOOT_SUBCMD_MKENT(list, 1, 1, do_acpi_list), + U_BOOT_SUBCMD_MKENT(dump, 2, 1, do_acpi_dump)); diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c index 9d2b49f8ba..5abf1cad50 100644 --- a/lib/acpi/acpi_table.c +++ b/lib/acpi/acpi_table.c @@ -240,6 +240,7 @@ void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start)
/* Align ACPI tables to 16 byte */ acpi_align(ctx); + gd->arch.acpi_start = map_to_sysmem(ctx->current);
/* We need at least an RSDP and an RSDT Table */ ctx->rsdp = ctx->current; diff --git a/test/dm/acpi.c b/test/dm/acpi.c index a29c3cab3e..176d207a55 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -7,9 +7,11 @@ */
#include <common.h> +#include <console.h> #include <dm.h> #include <malloc.h> #include <mapmem.h> +#include <version.h> #include <tables_csum.h> #include <version.h> #include <acpi/acpi_table.h> @@ -212,6 +214,7 @@ static int dm_test_acpi_setup_base_tables(struct unit_test_state *uts) buf = memalign(64, BUF_SIZE); ut_assertnonnull(buf); acpi_setup_base_tables(&ctx, buf + 4); + ut_asserteq(map_to_sysmem(PTR_ALIGN(buf + 4, 16)), gd->arch.acpi_start);
rsdp = buf + 16; ut_asserteq_ptr(rsdp, ctx.rsdp); @@ -242,3 +245,73 @@ static int dm_test_acpi_setup_base_tables(struct unit_test_state *uts) } DM_TEST(dm_test_acpi_setup_base_tables, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test 'acpi list' command */ +static int dm_test_acpi_cmd_list(struct unit_test_state *uts) +{ + struct acpi_ctx ctx; + ulong addr; + void *buf; + + buf = memalign(16, BUF_SIZE); + ut_assertnonnull(buf); + acpi_setup_base_tables(&ctx, buf); + + ut_assertok(acpi_write_dev_tables(&ctx)); + + console_record_reset(); + run_command("acpi list", 0); + addr = (ulong)map_to_sysmem(buf); + ut_assert_nextline("ACPI tables start at %lx", addr); + ut_assert_nextline("RSDP %08lx %06lx (v02 U-BOOT)", addr, + sizeof(struct acpi_rsdp)); + addr = ALIGN(addr + sizeof(struct acpi_rsdp), 16); + ut_assert_nextline("RSDT %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)", + addr, sizeof(struct acpi_table_header) + + 2 * sizeof(u32), U_BOOT_BUILD_DATE); + addr = ALIGN(addr + sizeof(struct acpi_rsdt), 16); + ut_assert_nextline("XSDT %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)", + addr, sizeof(struct acpi_table_header) + + 2 * sizeof(u64), U_BOOT_BUILD_DATE); + addr = ALIGN(addr + sizeof(struct acpi_xsdt), 64); + ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)", + addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE); + addr = ALIGN(addr + sizeof(struct acpi_dmar), 16); + ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)", + addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE); + ut_assert_console_end(); + + return 0; +} +DM_TEST(dm_test_acpi_cmd_list, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test 'acpi dump' command */ +static int dm_test_acpi_cmd_dump(struct unit_test_state *uts) +{ + struct acpi_ctx ctx; + ulong addr; + void *buf; + + buf = memalign(16, BUF_SIZE); + ut_assertnonnull(buf); + acpi_setup_base_tables(&ctx, buf); + + ut_assertok(acpi_write_dev_tables(&ctx)); + + /* First search for a non-existent table */ + console_record_reset(); + run_command("acpi dump rdst", 0); + ut_assert_nextline("Table 'RDST' not found"); + ut_assert_console_end(); + + /* Now a real table */ + console_record_reset(); + run_command("acpi dump dmar", 0); + addr = ALIGN(map_to_sysmem(ctx.xsdt) + sizeof(struct acpi_xsdt), 64); + ut_assert_nextline("DMAR @ %08lx", addr); + ut_assert_nextlines_are_dump(0x30); + ut_assert_console_end(); + + return 0; +} +DM_TEST(dm_test_acpi_cmd_dump, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

On Sun, Apr 19, 2020 at 02:36:48PM -0600, Simon Glass wrote:
This is split from the original series in an attempt to get things applied in chunks.
v7 is just a rebase as requested
So, overall I have no concerns, except that compatible string in ACPI seems half-baked solution and, due to PRP0001 awareness (my understanding that it should not be part of production devices), seems not needed right now. It means we should require to have _HID and/or _CID.
Code looks fine to me, though.
Changes in v7:
- Rebase to master
Changes in v5:
- Drop bisectability changes
Changes in v4:
- Put 'interrupts-extended' property on one line
- Rename acpi-probed to linux,probed
- Note that linux,probed is an out-of-tree feature
- Separate out the log newline
- Update comment in acpi_inc_align() to show the alignment
- Put back cast on table_compute_checksum()
- Rename list_fact() to list_fadt()
- Add a comment to dump_hdr()
Changes in v3:
- Drop mention of PRIC
- Rename acpi,desc to acpi,ddn
- Correct description of acpi,probed
- Drop hid-descr-addr
- Just add the device.txt binding file in this patch
- Change the example to ELAN
- Add a pointer to information about acpi,compatible
- Rename acpi_align_large() to acpi_align64()
- Fix 'RSDP' typo
- Fix 'XDST' typo
- Move acpi_align_large() out of dm_test_acpi_setup_base_tables()
- Beef up the comment explaining how the unaligned address is used
Changes in v2:
- Fix definition of HID
- Infer hid-over-i2c CID value
- Add the hid-over-i2c binding document
- Drop definition of ACPI_TABLE_CREATOR
- Make _acpi_write_dev_tables() static and switch argument order
- Generalise the ACPI function recursion with acpi_recurse_method()
Simon Glass (9): acpi: Add a binding for ACPI settings in the device tree acpi: Add a method to write tables for a device acpi: Convert part of acpi_table to use acpi_ctx x86: Allow devices to write ACPI tables acpi: Drop code for missing XSDT from acpi_write_rsdp() acpi: Move acpi_add_table() to generic code acpi: Put table-setup code in its own function acpi: Move the xsdt pointer to acpi_ctx acpi: Add an acpi command
arch/sandbox/dts/test.dts | 4 + arch/sandbox/include/asm/global_data.h | 1 + arch/x86/include/asm/global_data.h | 1 + arch/x86/lib/acpi_table.c | 239 +++++-------------------- cmd/Kconfig | 14 ++ cmd/Makefile | 1 + cmd/acpi.c | 186 +++++++++++++++++++ doc/device-tree-bindings/device.txt | 36 ++++ drivers/core/acpi.c | 62 +++++++ include/acpi/acpi_table.h | 65 +++++++ include/dm/acpi.h | 37 ++++ lib/acpi/acpi_table.c | 174 +++++++++++++++++- test/dm/acpi.c | 238 +++++++++++++++++++++++- 13 files changed, 855 insertions(+), 203 deletions(-) create mode 100644 cmd/acpi.c create mode 100644 doc/device-tree-bindings/device.txt
-- 2.26.1.301.g55bc3eb7cb9-goog

Hi Andy,
On Tue, 21 Apr 2020 at 11:43, Andy Shevchenko andriy.shevchenko@linux.intel.com wrote:
On Sun, Apr 19, 2020 at 02:36:48PM -0600, Simon Glass wrote:
This is split from the original series in an attempt to get things applied in chunks.
v7 is just a rebase as requested
So, overall I have no concerns, except that compatible string in ACPI seems half-baked solution and, due to PRP0001 awareness (my understanding that it should not be part of production devices), seems not needed right now. It means we should require to have _HID and/or _CID.
OK I am really not sure what to say about this. Let's deal with it when we see the use of it later.
Code looks fine to me, though.
OK good. I will send part B soon.
Changes in v7:
- Rebase to master
Changes in v5:
- Drop bisectability changes
Changes in v4:
- Put 'interrupts-extended' property on one line
- Rename acpi-probed to linux,probed
- Note that linux,probed is an out-of-tree feature
- Separate out the log newline
- Update comment in acpi_inc_align() to show the alignment
- Put back cast on table_compute_checksum()
- Rename list_fact() to list_fadt()
- Add a comment to dump_hdr()
Changes in v3:
- Drop mention of PRIC
- Rename acpi,desc to acpi,ddn
- Correct description of acpi,probed
- Drop hid-descr-addr
- Just add the device.txt binding file in this patch
- Change the example to ELAN
- Add a pointer to information about acpi,compatible
- Rename acpi_align_large() to acpi_align64()
- Fix 'RSDP' typo
- Fix 'XDST' typo
- Move acpi_align_large() out of dm_test_acpi_setup_base_tables()
- Beef up the comment explaining how the unaligned address is used
Changes in v2:
- Fix definition of HID
- Infer hid-over-i2c CID value
- Add the hid-over-i2c binding document
- Drop definition of ACPI_TABLE_CREATOR
- Make _acpi_write_dev_tables() static and switch argument order
- Generalise the ACPI function recursion with acpi_recurse_method()
Simon Glass (9): acpi: Add a binding for ACPI settings in the device tree acpi: Add a method to write tables for a device acpi: Convert part of acpi_table to use acpi_ctx x86: Allow devices to write ACPI tables acpi: Drop code for missing XSDT from acpi_write_rsdp() acpi: Move acpi_add_table() to generic code acpi: Put table-setup code in its own function acpi: Move the xsdt pointer to acpi_ctx acpi: Add an acpi command
arch/sandbox/dts/test.dts | 4 + arch/sandbox/include/asm/global_data.h | 1 + arch/x86/include/asm/global_data.h | 1 + arch/x86/lib/acpi_table.c | 239 +++++-------------------- cmd/Kconfig | 14 ++ cmd/Makefile | 1 + cmd/acpi.c | 186 +++++++++++++++++++ doc/device-tree-bindings/device.txt | 36 ++++ drivers/core/acpi.c | 62 +++++++ include/acpi/acpi_table.h | 65 +++++++ include/dm/acpi.h | 37 ++++ lib/acpi/acpi_table.c | 174 +++++++++++++++++- test/dm/acpi.c | 238 +++++++++++++++++++++++- 13 files changed, 855 insertions(+), 203 deletions(-) create mode 100644 cmd/acpi.c create mode 100644 doc/device-tree-bindings/device.txt
-- 2.26.1.301.g55bc3eb7cb9-goog
Regards, Simon

Hi Simon,
On Wed, Apr 22, 2020 at 5:37 AM Simon Glass sjg@chromium.org wrote:
Hi Andy,
On Tue, 21 Apr 2020 at 11:43, Andy Shevchenko andriy.shevchenko@linux.intel.com wrote:
On Sun, Apr 19, 2020 at 02:36:48PM -0600, Simon Glass wrote:
This is split from the original series in an attempt to get things applied in chunks.
v7 is just a rebase as requested
So, overall I have no concerns, except that compatible string in ACPI seems half-baked solution and, due to PRP0001 awareness (my understanding that it should not be part of production devices), seems not needed right now. It means we should require to have _HID and/or _CID.
OK I am really not sure what to say about this. Let's deal with it when we see the use of it later.
Code looks fine to me, though.
OK good. I will send part B soon.
v7 has been applied to u-boot-x86, thanks!
Regards, Bin

Hi Simon,
On Thu, Apr 23, 2020 at 5:46 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Apr 22, 2020 at 5:37 AM Simon Glass sjg@chromium.org wrote:
Hi Andy,
On Tue, 21 Apr 2020 at 11:43, Andy Shevchenko andriy.shevchenko@linux.intel.com wrote:
On Sun, Apr 19, 2020 at 02:36:48PM -0600, Simon Glass wrote:
This is split from the original series in an attempt to get things applied in chunks.
v7 is just a rebase as requested
So, overall I have no concerns, except that compatible string in ACPI seems half-baked solution and, due to PRP0001 awareness (my understanding that it should not be part of production devices), seems not needed right now. It means we should require to have _HID and/or _CID.
OK I am really not sure what to say about this. Let's deal with it when we see the use of it later.
Code looks fine to me, though.
OK good. I will send part B soon.
v7 has been applied to u-boot-x86, thanks!
Unfortunately this series breaks sandbox_spl, please take a look.
https://gitlab.denx.de/u-boot/custodians/u-boot-x86/-/jobs/81615
Regards, Bin

Hi Simon,
On Thu, Apr 23, 2020 at 5:58 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Thu, Apr 23, 2020 at 5:46 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Apr 22, 2020 at 5:37 AM Simon Glass sjg@chromium.org wrote:
Hi Andy,
On Tue, 21 Apr 2020 at 11:43, Andy Shevchenko andriy.shevchenko@linux.intel.com wrote:
On Sun, Apr 19, 2020 at 02:36:48PM -0600, Simon Glass wrote:
This is split from the original series in an attempt to get things applied in chunks.
v7 is just a rebase as requested
So, overall I have no concerns, except that compatible string in ACPI seems half-baked solution and, due to PRP0001 awareness (my understanding that it should not be part of production devices), seems not needed right now. It means we should require to have _HID and/or _CID.
OK I am really not sure what to say about this. Let's deal with it when we see the use of it later.
Code looks fine to me, though.
OK good. I will send part B soon.
v7 has been applied to u-boot-x86, thanks!
Unfortunately this series breaks sandbox_spl, please take a look.
https://gitlab.denx.de/u-boot/custodians/u-boot-x86/-/jobs/81615
Did you send out a fix for this series so that I can squash in?
Regards, Bin

Hi Bin,
On Sun, 26 Apr 2020 at 23:58, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Thu, Apr 23, 2020 at 5:58 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Thu, Apr 23, 2020 at 5:46 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Apr 22, 2020 at 5:37 AM Simon Glass sjg@chromium.org wrote:
Hi Andy,
On Tue, 21 Apr 2020 at 11:43, Andy Shevchenko andriy.shevchenko@linux.intel.com wrote:
On Sun, Apr 19, 2020 at 02:36:48PM -0600, Simon Glass wrote:
This is split from the original series in an attempt to get things applied in chunks.
v7 is just a rebase as requested
So, overall I have no concerns, except that compatible string in ACPI seems half-baked solution and, due to PRP0001 awareness (my understanding that it should not be part of production devices), seems not needed right now. It means we should require to have _HID and/or _CID.
OK I am really not sure what to say about this. Let's deal with it when we see the use of it later.
Code looks fine to me, though.
OK good. I will send part B soon.
v7 has been applied to u-boot-x86, thanks!
Unfortunately this series breaks sandbox_spl, please take a look.
https://gitlab.denx.de/u-boot/custodians/u-boot-x86/-/jobs/81615
Did you send out a fix for this series so that I can squash in?
Oops, no, I sent out a new series. I will send a fixup patch.
Regards, Simon

On 4/19/20 10:36 PM, Simon Glass wrote:
This is split from the original series in an attempt to get things applied in chunks.
v7 is just a rebase as requested
Hello Simon,
Andrei Warkentin pointed me to a similar development for EDK2:
Dynamic Tables Framework https://github.com/tianocore/edk2/tree/master/DynamicTablesPkg
Best regards
Heinrich

Hi Heinrich,
On Wed, 29 Apr 2020 at 12:14, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 4/19/20 10:36 PM, Simon Glass wrote:
This is split from the original series in an attempt to get things applied in chunks.
v7 is just a rebase as requested
Hello Simon,
Andrei Warkentin pointed me to a similar development for EDK2:
Dynamic Tables Framework https://github.com/tianocore/edk2/tree/master/DynamicTablesPkg
Thanks, I had a quick look. Are you thinking we should try to have a common library for this?
Regards, Simon
participants (6)
-
Andy Shevchenko
-
Andy Shevchenko
-
Bin Meng
-
Heinrich Schuchardt
-
Simon Glass
-
Wolfgang Wallner