From 4b724a13770c39ee3806dd30d349b6f8d03cfbc6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 7 Jul 2020 13:11:38 -0600 Subject: dm: core: Add an ACPI name for the root node This always has a fixed ACPI name so add it as a driver function. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- drivers/core/root.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/core') diff --git a/drivers/core/root.c b/drivers/core/root.c index 0de5d7c70d..0726be6b79 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -377,10 +378,22 @@ int dm_init_and_scan(bool pre_reloc_only) return 0; } +#ifdef CONFIG_ACPIGEN +static int root_acpi_get_name(const struct udevice *dev, char *out_name) +{ + return acpi_copy_name(out_name, "\\_SB"); +} + +struct acpi_ops root_acpi_ops = { + .get_name = root_acpi_get_name, +}; +#endif + /* This is the root driver - all drivers are children of this */ U_BOOT_DRIVER(root_driver) = { .name = "root_driver", .id = UCLASS_ROOT, + ACPI_OPS_PTR(&root_acpi_ops) }; /* This is the root uclass */ -- cgit v1.2.3 From b5183172f031603c5d861c34389f88a3c493cfd7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 7 Jul 2020 13:12:03 -0600 Subject: acpi: Add support for SSDT generation Some devices need to generate code for the Secondary System Descriptor Table (SSDT). Add a method to handle this. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- arch/sandbox/dts/test.dts | 2 ++ drivers/core/acpi.c | 14 ++++++++++++++ include/dm/acpi.h | 23 +++++++++++++++++++++++ test/dm/acpi.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+) (limited to 'drivers/core') diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index f0d8f12d40..5b41edd8d3 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -256,6 +256,7 @@ acpi-test { compatible = "denx,u-boot-acpi-test"; + acpi-ssdt-test-data = "ab"; child { compatible = "denx,u-boot-acpi-test"; }; @@ -263,6 +264,7 @@ acpi-test2 { compatible = "denx,u-boot-acpi-test"; + acpi-ssdt-test-data = "cd"; }; clocks { diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c index 8ae61575dd..4497b5cb2f 100644 --- a/drivers/core/acpi.c +++ b/drivers/core/acpi.c @@ -18,6 +18,7 @@ /* Type of method to call */ enum method_t { METHOD_WRITE_TABLES, + METHOD_FILL_SSDT, }; /* Prototype for all methods */ @@ -51,6 +52,8 @@ acpi_method acpi_get_method(struct udevice *dev, enum method_t method) switch (method) { case METHOD_WRITE_TABLES: return aops->write_tables; + case METHOD_FILL_SSDT: + return aops->fill_ssdt; } } @@ -84,6 +87,17 @@ int acpi_recurse_method(struct acpi_ctx *ctx, struct udevice *parent, return 0; } +int acpi_fill_ssdt(struct acpi_ctx *ctx) +{ + int ret; + + log_debug("Writing SSDT tables\n"); + ret = acpi_recurse_method(ctx, dm_root(), METHOD_FILL_SSDT); + log_debug("Writing SSDT finished, err=%d\n", ret); + + return ret; +} + int acpi_write_dev_tables(struct acpi_ctx *ctx) { int ret; diff --git a/include/dm/acpi.h b/include/dm/acpi.h index dfda88e493..e956e49680 100644 --- a/include/dm/acpi.h +++ b/include/dm/acpi.h @@ -74,6 +74,19 @@ struct acpi_ops { * @return 0 if OK, -ve on error */ int (*write_tables)(const struct udevice *dev, struct acpi_ctx *ctx); + + /** + * fill_ssdt() - Generate SSDT code for a device + * + * This is called to create the SSDT code. The method should write out + * whatever ACPI code is needed by this device. It will end up in the + * SSDT table. + * + * @dev: Device to write + * @ctx: ACPI context to use + * @return 0 if OK, -ve on error + */ + int (*fill_ssdt)(const struct udevice *dev, struct acpi_ctx *ctx); }; #define device_get_acpi_ops(dev) ((dev)->driver->acpi_ops) @@ -118,6 +131,16 @@ int acpi_copy_name(char *out_name, const char *name); */ int acpi_write_dev_tables(struct acpi_ctx *ctx); +/** + * acpi_fill_ssdt() - Generate ACPI tables for SSDT + * + * This is called to create the SSDT code for all devices. + * + * @ctx: ACPI context to use + * @return 0 if OK, -ve on error + */ +int acpi_fill_ssdt(struct acpi_ctx *ctx); + #endif /* __ACPI__ */ #endif diff --git a/test/dm/acpi.c b/test/dm/acpi.c index 07b0daaab0..d46d1fbe66 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -67,9 +68,23 @@ static int testacpi_get_name(const struct udevice *dev, char *out_name) return acpi_copy_name(out_name, ACPI_TEST_DEV_NAME); } +static int testacpi_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx) +{ + const char *data; + + data = dev_read_string(dev, "acpi-ssdt-test-data"); + if (data) { + while (*data) + acpigen_emit_byte(ctx, *data++); + } + + return 0; +} + struct acpi_ops testacpi_ops = { .get_name = testacpi_get_name, .write_tables = testacpi_write_tables, + .fill_ssdt = testacpi_fill_ssdt, }; static const struct udevice_id testacpi_ids[] = { @@ -396,3 +411,30 @@ static int dm_test_acpi_device_status(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_acpi_device_status, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test acpi_fill_ssdt() */ +static int dm_test_acpi_fill_ssdt(struct unit_test_state *uts) +{ + struct acpi_ctx ctx; + u8 *buf; + + buf = malloc(BUF_SIZE); + ut_assertnonnull(buf); + + ctx.current = buf; + buf[4] = 'z'; /* sentinel */ + ut_assertok(acpi_fill_ssdt(&ctx)); + + /* These values come from acpi-test's acpi-ssdt-test-data property */ + ut_asserteq('a', buf[0]); + ut_asserteq('b', buf[1]); + + /* These values come from acpi-test2's acpi-ssdt-test-data property */ + ut_asserteq('c', buf[2]); + ut_asserteq('d', buf[3]); + + ut_asserteq('z', buf[4]); + + return 0; +} +DM_TEST(dm_test_acpi_fill_ssdt, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -- cgit v1.2.3 From 64ba6f43ef83e3a87abf5705d57ffc9109b5aa55 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 7 Jul 2020 13:12:05 -0600 Subject: acpi: Record the items added to SSDT It is useful to be able to control the order of data written to the SSDT so that we can compare the output against known-good kernel dumps. Add code to record each item that is added along with the device that added it. That allows us to reorder things later if needed. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- drivers/core/acpi.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 4 deletions(-) (limited to 'drivers/core') diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c index 4497b5cb2f..df3d7ba417 100644 --- a/drivers/core/acpi.c +++ b/drivers/core/acpi.c @@ -9,12 +9,21 @@ #define LOG_CATEOGRY LOGC_ACPI #include +#include #include #include #include #include #include +#define MAX_ACPI_ITEMS 100 + +/* Type of table that we collected */ +enum gen_type_t { + TYPE_NONE, + TYPE_SSDT, +}; + /* Type of method to call */ enum method_t { METHOD_WRITE_TABLES, @@ -24,6 +33,25 @@ enum method_t { /* Prototype for all methods */ typedef int (*acpi_method)(const struct udevice *dev, struct acpi_ctx *ctx); +/** + * struct acpi_item - Holds info about ACPI data generated by a driver method + * + * @dev: Device that generated this data + * @type: Table type it refers to + * @buf: Buffer containing the data + * @size: Size of the data in bytes + */ +struct acpi_item { + struct udevice *dev; + enum gen_type_t type; + char *buf; + int size; +}; + +/* List of ACPI items collected */ +static struct acpi_item acpi_item[MAX_ACPI_ITEMS]; +static int item_count; + int acpi_copy_name(char *out_name, const char *name) { strncpy(out_name, name, ACPI_NAME_LEN); @@ -43,6 +71,43 @@ int acpi_get_name(const struct udevice *dev, char *out_name) return -ENOSYS; } +/** + * acpi_add_item() - Add a new item to the list of data collected + * + * @ctx: ACPI context + * @dev: Device that generated the data + * @type: Table type it refers to + * @start: The start of the data (the end is obtained from ctx->current) + * @return 0 if OK, -ENOSPC if too many items, -ENOMEM if out of memory + */ +static int acpi_add_item(struct acpi_ctx *ctx, struct udevice *dev, + enum gen_type_t type, void *start) +{ + struct acpi_item *item; + void *end = ctx->current; + + if (item_count == MAX_ACPI_ITEMS) { + log_err("Too many items\n"); + return log_msg_ret("mem", -ENOSPC); + } + + item = &acpi_item[item_count]; + item->dev = dev; + item->type = type; + item->size = end - start; + if (!item->size) + return 0; + item->buf = malloc(item->size); + if (!item->buf) + return log_msg_ret("mem", -ENOMEM); + memcpy(item->buf, start, item->size); + item_count++; + log_debug("* %s: Added type %d, %p, size %x\n", dev->name, type, start, + item->size); + + return 0; +} + acpi_method acpi_get_method(struct udevice *dev, enum method_t method) { struct acpi_ops *aops; @@ -61,7 +126,7 @@ acpi_method acpi_get_method(struct udevice *dev, enum method_t method) } int acpi_recurse_method(struct acpi_ctx *ctx, struct udevice *parent, - enum method_t method) + enum method_t method, enum gen_type_t type) { struct udevice *dev; acpi_method func; @@ -69,6 +134,8 @@ int acpi_recurse_method(struct acpi_ctx *ctx, struct udevice *parent, func = acpi_get_method(parent, method); if (func) { + void *start = ctx->current; + log_debug("\n"); log_debug("- %s %p\n", parent->name, func); ret = device_ofdata_to_platdata(parent); @@ -77,9 +144,16 @@ int acpi_recurse_method(struct acpi_ctx *ctx, struct udevice *parent, ret = func(parent, ctx); if (ret) return log_msg_ret("func", ret); + + /* Add the item to the internal list */ + if (type != TYPE_NONE) { + ret = acpi_add_item(ctx, parent, type, start); + if (ret) + return log_msg_ret("add", ret); + } } device_foreach_child(dev, parent) { - ret = acpi_recurse_method(ctx, dev, method); + ret = acpi_recurse_method(ctx, dev, method, type); if (ret) return log_msg_ret("recurse", ret); } @@ -92,7 +166,7 @@ int acpi_fill_ssdt(struct acpi_ctx *ctx) int ret; log_debug("Writing SSDT tables\n"); - ret = acpi_recurse_method(ctx, dm_root(), METHOD_FILL_SSDT); + ret = acpi_recurse_method(ctx, dm_root(), METHOD_FILL_SSDT, TYPE_SSDT); log_debug("Writing SSDT finished, err=%d\n", ret); return ret; @@ -103,7 +177,8 @@ 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); + ret = acpi_recurse_method(ctx, dm_root(), METHOD_WRITE_TABLES, + TYPE_NONE); log_debug("Writing finished, err=%d\n", ret); return ret; -- cgit v1.2.3 From 0f7b111f70087f60e84f936fbe0c2a0a243a4fec Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 7 Jul 2020 13:12:06 -0600 Subject: acpi: Support ordering SSDT data by device Add a /chosen property to control the order in which the data appears in the SSDT. This allows matching up U-Boot's output from a dump of the known-good data obtained from within Linux. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- arch/sandbox/dts/test.dts | 5 ++- doc/device-tree-bindings/chosen.txt | 9 ++++ drivers/core/acpi.c | 84 +++++++++++++++++++++++++++++++++++++ test/dm/acpi.c | 15 ++++--- 4 files changed, 105 insertions(+), 8 deletions(-) (limited to 'drivers/core') diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 5b41edd8d3..c79ea34932 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -254,7 +254,7 @@ compatible = "denx,u-boot-devres-test"; }; - acpi-test { + acpi_test1: acpi-test { compatible = "denx,u-boot-acpi-test"; acpi-ssdt-test-data = "ab"; child { @@ -262,7 +262,7 @@ }; }; - acpi-test2 { + acpi_test2: acpi-test2 { compatible = "denx,u-boot-acpi-test"; acpi-ssdt-test-data = "cd"; }; @@ -924,6 +924,7 @@ setting = "sunrise ohoka"; other-node = "/some-bus/c-test@5"; int-values = <0x1937 72993>; + u-boot,acpi-ssdt-order = <&acpi_test2 &acpi_test1>; chosen-test { compatible = "denx,u-boot-fdt-test"; reg = <9 1>; diff --git a/doc/device-tree-bindings/chosen.txt b/doc/device-tree-bindings/chosen.txt index 395c9501e3..d4dfc05847 100644 --- a/doc/device-tree-bindings/chosen.txt +++ b/doc/device-tree-bindings/chosen.txt @@ -134,3 +134,12 @@ Example phandlepart = <&mmc 1>; }; }; + +u-boot,acpi-ssdt-order +---------------------- + +This provides the ordering to use when writing device data to the ACPI SSDT +(Secondary System Descriptor Table). Each cell is a phandle pointer to a device +node to add. The ACPI information is written in this order. + +If the ordering does not include all nodes, an error is generated. diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c index df3d7ba417..a9b7fc1d9a 100644 --- a/drivers/core/acpi.c +++ b/drivers/core/acpi.c @@ -108,6 +108,85 @@ static int acpi_add_item(struct acpi_ctx *ctx, struct udevice *dev, return 0; } +static struct acpi_item *find_acpi_item(const char *devname) +{ + int i; + + for (i = 0; i < item_count; i++) { + struct acpi_item *item = &acpi_item[i]; + + if (!strcmp(devname, item->dev->name)) + return item; + } + + return NULL; +} + +/** + * sort_acpi_item_type - Sort the ACPI items into the desired order + * + * This looks up the ordering in the device tree and then adds each item one by + * one into the supplied buffer + * + * @ctx: ACPI context + * @start: Start position to put the sorted items. The items will follow each + * other in sorted order + * @type: Type of items to sort + * @return 0 if OK, -ve on error + */ +static int sort_acpi_item_type(struct acpi_ctx *ctx, void *start, + enum gen_type_t type) +{ + const u32 *order; + int size; + int count; + void *ptr; + void *end = ctx->current; + + ptr = start; + order = ofnode_read_chosen_prop("u-boot,acpi-ssdt-order", &size); + if (!order) { + log_warning("Failed to find ordering, leaving as is\n"); + return 0; + } + + /* + * This algorithm rewrites the context buffer without changing its + * length. So there is no need to update ctx-current + */ + count = size / sizeof(u32); + while (count--) { + struct acpi_item *item; + const char *name; + ofnode node; + + node = ofnode_get_by_phandle(fdt32_to_cpu(*order++)); + name = ofnode_get_name(node); + item = find_acpi_item(name); + if (!item) { + log_err("Failed to find item '%s'\n", name); + return log_msg_ret("find", -ENOENT); + } + if (item->type == type) { + log_debug(" - add %s\n", item->dev->name); + memcpy(ptr, item->buf, item->size); + ptr += item->size; + } + } + + /* + * If the sort order is missing an item then the output will be too + * small. Report this error since the item needs to be added to the + * ordering for the ACPI tables to be complete. + */ + if (ptr != end) { + log_warning("*** Missing bytes: ptr=%p, end=%p\n", ptr, end); + return -ENXIO; + } + + return 0; +} + acpi_method acpi_get_method(struct udevice *dev, enum method_t method) { struct acpi_ops *aops; @@ -163,11 +242,16 @@ int acpi_recurse_method(struct acpi_ctx *ctx, struct udevice *parent, int acpi_fill_ssdt(struct acpi_ctx *ctx) { + void *start = ctx->current; int ret; log_debug("Writing SSDT tables\n"); + item_count = 0; ret = acpi_recurse_method(ctx, dm_root(), METHOD_FILL_SSDT, TYPE_SSDT); log_debug("Writing SSDT finished, err=%d\n", ret); + ret = sort_acpi_item_type(ctx, start, TYPE_SSDT); + if (ret) + return log_msg_ret("build", ret); return ret; } diff --git a/test/dm/acpi.c b/test/dm/acpi.c index d46d1fbe66..4e1d401e0d 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -425,13 +425,16 @@ static int dm_test_acpi_fill_ssdt(struct unit_test_state *uts) buf[4] = 'z'; /* sentinel */ ut_assertok(acpi_fill_ssdt(&ctx)); - /* These values come from acpi-test's acpi-ssdt-test-data property */ - ut_asserteq('a', buf[0]); - ut_asserteq('b', buf[1]); + /* + * These values come from acpi-test2's acpi-ssdt-test-data property. + * This device comes first because of u-boot,acpi-ssdt-order + */ + ut_asserteq('c', buf[0]); + ut_asserteq('d', buf[1]); - /* These values come from acpi-test2's acpi-ssdt-test-data property */ - ut_asserteq('c', buf[2]); - ut_asserteq('d', buf[3]); + /* These values come from acpi-test's acpi-ssdt-test-data property */ + ut_asserteq('a', buf[2]); + ut_asserteq('b', buf[3]); ut_asserteq('z', buf[4]); -- cgit v1.2.3 From 01694589af589212d6f2a6241821896ef9e334d3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 7 Jul 2020 13:12:08 -0600 Subject: acpi: Add support for DSDT generation Some devices need to inject extra code into the Differentiated System Descriptor Table (DSDT). Add a method to handle this. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng [bmeng: correct one typo in inject_dsdt() comments] Signed-off-by: Bin Meng --- arch/sandbox/dts/test.dts | 2 ++ drivers/core/acpi.c | 25 ++++++++++++++++++++++++- include/dm/acpi.h | 30 ++++++++++++++++++++++++++++++ test/dm/acpi.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 1 deletion(-) (limited to 'drivers/core') diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index c79ea34932..12101aaf79 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -257,6 +257,7 @@ acpi_test1: acpi-test { compatible = "denx,u-boot-acpi-test"; acpi-ssdt-test-data = "ab"; + acpi-dsdt-test-data = "hi"; child { compatible = "denx,u-boot-acpi-test"; }; @@ -265,6 +266,7 @@ acpi_test2: acpi-test2 { compatible = "denx,u-boot-acpi-test"; acpi-ssdt-test-data = "cd"; + acpi-dsdt-test-data = "jk"; }; clocks { diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c index a9b7fc1d9a..7b32694ad4 100644 --- a/drivers/core/acpi.c +++ b/drivers/core/acpi.c @@ -22,12 +22,14 @@ enum gen_type_t { TYPE_NONE, TYPE_SSDT, + TYPE_DSDT, }; /* Type of method to call */ enum method_t { METHOD_WRITE_TABLES, METHOD_FILL_SSDT, + METHOD_INJECT_DSDT, }; /* Prototype for all methods */ @@ -144,7 +146,9 @@ static int sort_acpi_item_type(struct acpi_ctx *ctx, void *start, void *end = ctx->current; ptr = start; - order = ofnode_read_chosen_prop("u-boot,acpi-ssdt-order", &size); + order = ofnode_read_chosen_prop(type == TYPE_DSDT ? + "u-boot,acpi-dsdt-order" : + "u-boot,acpi-ssdt-order", &size); if (!order) { log_warning("Failed to find ordering, leaving as is\n"); return 0; @@ -198,6 +202,8 @@ acpi_method acpi_get_method(struct udevice *dev, enum method_t method) return aops->write_tables; case METHOD_FILL_SSDT: return aops->fill_ssdt; + case METHOD_INJECT_DSDT: + return aops->inject_dsdt; } } @@ -256,6 +262,23 @@ int acpi_fill_ssdt(struct acpi_ctx *ctx) return ret; } +int acpi_inject_dsdt(struct acpi_ctx *ctx) +{ + void *start = ctx->current; + int ret; + + log_debug("Writing DSDT tables\n"); + item_count = 0; + ret = acpi_recurse_method(ctx, dm_root(), METHOD_INJECT_DSDT, + TYPE_DSDT); + log_debug("Writing DSDT finished, err=%d\n", ret); + ret = sort_acpi_item_type(ctx, start, TYPE_DSDT); + if (ret) + return log_msg_ret("build", ret); + + return ret; +} + int acpi_write_dev_tables(struct acpi_ctx *ctx) { int ret; diff --git a/include/dm/acpi.h b/include/dm/acpi.h index e956e49680..fceb1ae95c 100644 --- a/include/dm/acpi.h +++ b/include/dm/acpi.h @@ -82,11 +82,31 @@ struct acpi_ops { * whatever ACPI code is needed by this device. It will end up in the * SSDT table. * + * Note that this is called 'fill' because the entire contents of the + * SSDT is build by calling this method on all devices. + * * @dev: Device to write * @ctx: ACPI context to use * @return 0 if OK, -ve on error */ int (*fill_ssdt)(const struct udevice *dev, struct acpi_ctx *ctx); + + /** + * inject_dsdt() - Generate DSDT code for a device + * + * This is called to create the DSDT code. The method should write out + * whatever ACPI code is needed by this device. It will end up in the + * DSDT table. + * + * Note that this is called 'inject' because the output of calling this + * method on all devices is injected into the DSDT, the bulk of which + * is written in .asl files for the board. + * + * @dev: Device to write + * @ctx: ACPI context to use + * @return 0 if OK, -ve on error + */ + int (*inject_dsdt)(const struct udevice *dev, struct acpi_ctx *ctx); }; #define device_get_acpi_ops(dev) ((dev)->driver->acpi_ops) @@ -141,6 +161,16 @@ int acpi_write_dev_tables(struct acpi_ctx *ctx); */ int acpi_fill_ssdt(struct acpi_ctx *ctx); +/** + * acpi_inject_dsdt() - Generate ACPI tables for DSDT + * + * This is called to create the DSDT code for all devices. + * + * @ctx: ACPI context to use + * @return 0 if OK, -ve on error + */ +int acpi_inject_dsdt(struct acpi_ctx *ctx); + #endif /* __ACPI__ */ #endif diff --git a/test/dm/acpi.c b/test/dm/acpi.c index 4e1d401e0d..1abde65c8c 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -81,10 +81,24 @@ static int testacpi_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx) return 0; } +static int testacpi_inject_dsdt(const struct udevice *dev, struct acpi_ctx *ctx) +{ + const char *data; + + data = dev_read_string(dev, "acpi-dsdt-test-data"); + if (data) { + while (*data) + acpigen_emit_byte(ctx, *data++); + } + + return 0; +} + struct acpi_ops testacpi_ops = { .get_name = testacpi_get_name, .write_tables = testacpi_write_tables, .fill_ssdt = testacpi_fill_ssdt, + .inject_dsdt = testacpi_inject_dsdt, }; static const struct udevice_id testacpi_ids[] = { @@ -441,3 +455,33 @@ static int dm_test_acpi_fill_ssdt(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_acpi_fill_ssdt, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test acpi_inject_dsdt() */ +static int dm_test_acpi_inject_dsdt(struct unit_test_state *uts) +{ + struct acpi_ctx ctx; + u8 *buf; + + buf = malloc(BUF_SIZE); + ut_assertnonnull(buf); + + ctx.current = buf; + buf[4] = 'z'; /* sentinel */ + ut_assertok(acpi_inject_dsdt(&ctx)); + + /* + * These values come from acpi-test's acpi-dsdt-test-data property. + * There is no u-boot,acpi-dsdt-order so device-tree order is used. + */ + ut_asserteq('h', buf[0]); + ut_asserteq('i', buf[1]); + + /* These values come from acpi-test's acpi-dsdt-test-data property */ + ut_asserteq('j', buf[2]); + ut_asserteq('k', buf[3]); + + ut_asserteq('z', buf[4]); + + return 0; +} +DM_TEST(dm_test_acpi_inject_dsdt, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -- cgit v1.2.3 From fefac0b0643b14e72c356cf05dabcbe7512c4709 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 7 Jul 2020 13:12:11 -0600 Subject: dm: acpi: Enhance acpi_get_name() For many device types it is possible to figure out the name just by looking at its uclass or parent. Add a function to handle this, since it allows us to cover the vast majority of cases automatically. However it is sometimes impossible to figure out an ACPI name for a device just by looking at its uclass. For example a touch device may have a vendor-specific name. Add a new "acpi,name" property to allow a custom name to be created. With this new feature we can drop the get_name() methods in the sandbox I2C and SPI drivers. They were only added for testing purposes. Update the tests to use the new values. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- arch/sandbox/dts/test.dts | 1 + doc/device-tree-bindings/device.txt | 13 +++++ drivers/core/acpi.c | 13 ++++- drivers/i2c/sandbox_i2c.c | 10 ---- drivers/spi/sandbox_spi.c | 10 ---- include/acpi/acpi_device.h | 18 ++++++ lib/acpi/acpi_device.c | 106 ++++++++++++++++++++++++++++++++++++ test/dm/acpi.c | 42 +++++++++++++- 8 files changed, 190 insertions(+), 23 deletions(-) (limited to 'drivers/core') diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 12101aaf79..3744a46603 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -113,6 +113,7 @@ int-array = <5678 9123 4567>; str-value = "test string"; interrupts-extended = <&irq 3 0>; + acpi,name = "GHIJ"; }; junk { diff --git a/doc/device-tree-bindings/device.txt b/doc/device-tree-bindings/device.txt index 27bd3978d9..7140339623 100644 --- a/doc/device-tree-bindings/device.txt +++ b/doc/device-tree-bindings/device.txt @@ -17,6 +17,8 @@ the acpi,compatible property. System) Device Name) - acpi,hid : Contains the string to use as the HID (Hardware ID) identifier _HID + - acpi,name : Provides the ACPI name for a device, which is a string consisting + of four alphanumeric character (upper case) - 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 @@ -34,3 +36,14 @@ elan_touchscreen: elan-touchscreen@10 { interrupts-extended = <&acpi_gpe GPIO_21_IRQ IRQ_TYPE_EDGE_FALLING>; linux,probed; }; + +pcie-a0@14,0 { + reg = <0x0000a000 0 0 0 0>; + acpi,name = "RP01"; + wifi: wifi { + compatible = "intel,generic-wifi"; + acpi,ddn = "Intel WiFi"; + acpi,name = "WF00"; + interrupts-extended = <&acpi_gpe 0x3c 0>; + }; +}; diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c index 7b32694ad4..076fb4f1b4 100644 --- a/drivers/core/acpi.c +++ b/drivers/core/acpi.c @@ -9,9 +9,10 @@ #define LOG_CATEOGRY LOGC_ACPI #include -#include #include #include +#include +#include #include #include #include @@ -65,12 +66,20 @@ int acpi_copy_name(char *out_name, const char *name) int acpi_get_name(const struct udevice *dev, char *out_name) { struct acpi_ops *aops; + const char *name; + int ret; aops = device_get_acpi_ops(dev); if (aops && aops->get_name) return aops->get_name(dev, out_name); + name = dev_read_string(dev, "acpi,name"); + if (name) + return acpi_copy_name(out_name, name); + ret = acpi_device_infer_name(dev, out_name); + if (ret) + return log_msg_ret("dev", ret); - return -ENOSYS; + return 0; } /** diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c index 125026da90..57b1c60fde 100644 --- a/drivers/i2c/sandbox_i2c.c +++ b/drivers/i2c/sandbox_i2c.c @@ -84,15 +84,6 @@ static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, return ops->xfer(emul, msg, nmsgs); } -static int sandbox_i2c_get_name(const struct udevice *dev, char *out_name) -{ - return acpi_copy_name(out_name, "SI2C"); -} - -struct acpi_ops sandbox_i2c_acpi_ops = { - .get_name = sandbox_i2c_get_name, -}; - static const struct dm_i2c_ops sandbox_i2c_ops = { .xfer = sandbox_i2c_xfer, }; @@ -108,5 +99,4 @@ U_BOOT_DRIVER(i2c_sandbox) = { .of_match = sandbox_i2c_ids, .ops = &sandbox_i2c_ops, .priv_auto_alloc_size = sizeof(struct sandbox_i2c_priv), - ACPI_OPS_PTR(&sandbox_i2c_acpi_ops) }; diff --git a/drivers/spi/sandbox_spi.c b/drivers/spi/sandbox_spi.c index 77797bf096..755f176861 100644 --- a/drivers/spi/sandbox_spi.c +++ b/drivers/spi/sandbox_spi.c @@ -134,15 +134,6 @@ static int sandbox_spi_get_mmap(struct udevice *dev, ulong *map_basep, return 0; } -static int sandbox_spi_get_name(const struct udevice *dev, char *out_name) -{ - return acpi_copy_name(out_name, "SSPI"); -} - -struct acpi_ops sandbox_spi_acpi_ops = { - .get_name = sandbox_spi_get_name, -}; - static const struct dm_spi_ops sandbox_spi_ops = { .xfer = sandbox_spi_xfer, .set_speed = sandbox_spi_set_speed, @@ -161,5 +152,4 @@ U_BOOT_DRIVER(sandbox_spi) = { .id = UCLASS_SPI, .of_match = sandbox_spi_ids, .ops = &sandbox_spi_ops, - ACPI_OPS_PTR(&sandbox_spi_acpi_ops) }; diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h index e7db7bf5ad..5d94a88c02 100644 --- a/include/acpi/acpi_device.h +++ b/include/acpi/acpi_device.h @@ -384,4 +384,22 @@ int acpi_device_add_power_res(struct acpi_ctx *ctx, u32 tx_state_val, const struct gpio_desc *stop_gpio, uint stop_delay_ms, uint stop_off_delay_ms); +/** + * acpi_device_infer_name() - Infer the name from its uclass or parent + * + * Many ACPI devices have a standard name that can be inferred from the uclass + * they are in, or the uclass of their parent. These rules are implemented in + * this function. It attempts to produce a name for a device based on these + * rules. + * + * NOTE: This currently supports only x86 devices. Feel free to enhance it for + * other architectures as needed. + * + * @dev: Device to check + * @out_name: Place to put the name (must hold ACPI_NAME_MAX bytes) + * @return 0 if a name was found, -ENOENT if not found, -ENXIO if the device + * sequence number could not be determined + */ +int acpi_device_infer_name(const struct udevice *dev, char *out_name); + #endif diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c index c66cafcfee..3c75b6d962 100644 --- a/lib/acpi/acpi_device.c +++ b/lib/acpi/acpi_device.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -715,3 +717,107 @@ int acpi_device_write_spi_dev(struct acpi_ctx *ctx, const struct udevice *dev) return 0; } #endif /* CONFIG_SPI */ + +static const char *acpi_name_from_id(enum uclass_id id) +{ + switch (id) { + case UCLASS_USB_HUB: + /* Root Hub */ + return "RHUB"; + /* DSDT: acpi/northbridge.asl */ + case UCLASS_NORTHBRIDGE: + return "MCHC"; + /* DSDT: acpi/lpc.asl */ + case UCLASS_LPC: + return "LPCB"; + /* DSDT: acpi/xhci.asl */ + case UCLASS_USB: + /* This only supports USB3.0 controllers at present */ + return "XHCI"; + case UCLASS_PWM: + return "PWM"; + default: + return NULL; + } +} + +static int acpi_check_seq(const struct udevice *dev) +{ + if (dev->req_seq == -1) { + log_warning("Device '%s' has no seq\n", dev->name); + return log_msg_ret("no seq", -ENXIO); + } + + return dev->req_seq; +} + +/* If you change this function, add test cases to dm_test_acpi_get_name() */ +int acpi_device_infer_name(const struct udevice *dev, char *out_name) +{ + enum uclass_id parent_id = UCLASS_INVALID; + enum uclass_id id; + const char *name = NULL; + + id = device_get_uclass_id(dev); + if (dev_get_parent(dev)) + parent_id = device_get_uclass_id(dev_get_parent(dev)); + + if (id == UCLASS_SOUND) + name = "HDAS"; + else if (id == UCLASS_PCI) + name = "PCI0"; + else if (device_is_on_pci_bus(dev)) + name = acpi_name_from_id(id); + if (!name) { + switch (parent_id) { + case UCLASS_USB: { + struct usb_device *udev = dev_get_parent_priv(dev); + + sprintf(out_name, udev->speed >= USB_SPEED_SUPER ? + "HS%02d" : "FS%02d", udev->portnr); + name = out_name; + break; + } + default: + break; + } + } + if (!name) { + int num; + + switch (id) { + /* DSDT: acpi/lpss.asl */ + case UCLASS_SERIAL: + num = acpi_check_seq(dev); + if (num < 0) + return num; + sprintf(out_name, "URT%d", num); + name = out_name; + break; + case UCLASS_I2C: + num = acpi_check_seq(dev); + if (num < 0) + return num; + sprintf(out_name, "I2C%d", num); + name = out_name; + break; + case UCLASS_SPI: + num = acpi_check_seq(dev); + if (num < 0) + return num; + sprintf(out_name, "SPI%d", num); + name = out_name; + break; + default: + break; + } + } + if (!name) { + log_warning("No name for device '%s'\n", dev->name); + return -ENOENT; + } + if (name != out_name) + acpi_copy_name(out_name, name); + + return 0; +} diff --git a/test/dm/acpi.c b/test/dm/acpi.c index 1abde65c8c..69ca0902aa 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -124,12 +124,52 @@ UCLASS_DRIVER(testacpi) = { static int dm_test_acpi_get_name(struct unit_test_state *uts) { char name[ACPI_NAME_MAX]; - struct udevice *dev; + struct udevice *dev, *dev2, *i2c, *spi, *serial, *timer, *sound; + struct udevice *pci, *root; + /* Test getting the name from the driver */ ut_assertok(uclass_first_device_err(UCLASS_TEST_ACPI, &dev)); ut_assertok(acpi_get_name(dev, name)); ut_asserteq_str(ACPI_TEST_DEV_NAME, name); + /* Test getting the name from the device tree */ + ut_assertok(uclass_get_device_by_name(UCLASS_TEST_FDT, "a-test", + &dev2)); + ut_assertok(acpi_get_name(dev2, name)); + ut_asserteq_str("GHIJ", name); + + /* Test getting the name from acpi_device_get_name() */ + ut_assertok(uclass_first_device(UCLASS_I2C, &i2c)); + ut_assertok(acpi_get_name(i2c, name)); + ut_asserteq_str("I2C0", name); + + ut_assertok(uclass_first_device(UCLASS_SPI, &spi)); + ut_assertok(acpi_get_name(spi, name)); + ut_asserteq_str("SPI0", name); + + /* The uart has no sequence number, so this should fail */ + ut_assertok(uclass_first_device(UCLASS_SERIAL, &serial)); + ut_asserteq(-ENXIO, acpi_get_name(serial, name)); + + /* ACPI doesn't know about the timer */ + ut_assertok(uclass_first_device(UCLASS_TIMER, &timer)); + ut_asserteq(-ENOENT, acpi_get_name(timer, name)); + + /* May as well test the rest of the cases */ + ut_assertok(uclass_first_device(UCLASS_SOUND, &sound)); + ut_assertok(acpi_get_name(sound, name)); + ut_asserteq_str("HDAS", name); + + ut_assertok(uclass_first_device(UCLASS_PCI, &pci)); + ut_assertok(acpi_get_name(pci, name)); + ut_asserteq_str("PCI0", name); + + ut_assertok(uclass_first_device(UCLASS_ROOT, &root)); + ut_assertok(acpi_get_name(root, name)); + ut_asserteq_str("\\_SB", name); + + /* Note that we don't have tests for acpi_name_from_id() */ + return 0; } DM_TEST(dm_test_acpi_get_name, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -- cgit v1.2.3 From a4f8208919a4458ebe93d46d43a7cb0a13f7a0d8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 7 Jul 2020 13:12:12 -0600 Subject: acpi: Add an acpi command to list/dump generated ACPI items Add a command that shows the individual blocks of data generated by each device, effectively splitting the full table into its component parts. This can be helpful for debugging. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- cmd/acpi.c | 15 +++++++++++++-- drivers/core/acpi.c | 16 ++++++++++++++++ include/dm/acpi.h | 16 ++++++++++++++++ test/dm/acpi.c | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 2 deletions(-) (limited to 'drivers/core') diff --git a/cmd/acpi.c b/cmd/acpi.c index e9a9161a91..085a3a650d 100644 --- a/cmd/acpi.c +++ b/cmd/acpi.c @@ -153,6 +153,17 @@ static int do_acpi_list(struct cmd_tbl *cmdtp, int flag, int argc, return 0; } +static int do_acpi_items(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + bool dump_contents; + + dump_contents = argc >= 2 && !strcmp("-d", argv[1]); + acpi_dump_items(dump_contents ? ACPI_DUMP_CONTENTS : ACPI_DUMP_LIST); + + return 0; +} + static int do_acpi_dump(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -160,8 +171,6 @@ static int do_acpi_dump(struct cmd_tbl *cmdtp, int flag, int argc, 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); @@ -179,8 +188,10 @@ static int do_acpi_dump(struct cmd_tbl *cmdtp, int flag, int argc, static char acpi_help_text[] = "list - list ACPI tables\n" + "acpi items [-d] - List/dump each piece of ACPI data from devices\n" "acpi dump - 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(items, 2, 1, do_acpi_items), U_BOOT_SUBCMD_MKENT(dump, 2, 1, do_acpi_dump)); diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c index 076fb4f1b4..b566f4f186 100644 --- a/drivers/core/acpi.c +++ b/drivers/core/acpi.c @@ -119,6 +119,22 @@ static int acpi_add_item(struct acpi_ctx *ctx, struct udevice *dev, return 0; } +void acpi_dump_items(enum acpi_dump_option option) +{ + int i; + + for (i = 0; i < item_count; i++) { + struct acpi_item *item = &acpi_item[i]; + + printf("dev '%s', type %d, size %x\n", item->dev->name, + item->type, item->size); + if (option == ACPI_DUMP_CONTENTS) { + print_buffer(0, item->buf, 1, item->size, 0); + printf("\n"); + } + } +} + static struct acpi_item *find_acpi_item(const char *devname) { int i; diff --git a/include/dm/acpi.h b/include/dm/acpi.h index fceb1ae95c..aa1071ae35 100644 --- a/include/dm/acpi.h +++ b/include/dm/acpi.h @@ -27,6 +27,12 @@ #if !defined(__ACPI__) +/** enum acpi_dump_option - selects what ACPI information to dump */ +enum acpi_dump_option { + ACPI_DUMP_LIST, /* Just the list of items */ + ACPI_DUMP_CONTENTS, /* Include the binary contents also */ +}; + /** * struct acpi_ctx - Context used for writing ACPI tables * @@ -171,6 +177,16 @@ int acpi_fill_ssdt(struct acpi_ctx *ctx); */ int acpi_inject_dsdt(struct acpi_ctx *ctx); +/** + * acpi_dump_items() - Dump out the collected ACPI items + * + * This lists the ACPI DSDT and SSDT items generated by the various U-Boot + * drivers. + * + * @option: Sets what should be dumpyed + */ +void acpi_dump_items(enum acpi_dump_option option); + #endif /* __ACPI__ */ #endif diff --git a/test/dm/acpi.c b/test/dm/acpi.c index 69ca0902aa..7768f9514c 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -525,3 +525,42 @@ static int dm_test_acpi_inject_dsdt(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_acpi_inject_dsdt, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test 'acpi items' command */ +static int dm_test_acpi_cmd_items(struct unit_test_state *uts) +{ + struct acpi_ctx ctx; + void *buf; + + buf = malloc(BUF_SIZE); + ut_assertnonnull(buf); + + ctx.current = buf; + ut_assertok(acpi_fill_ssdt(&ctx)); + console_record_reset(); + run_command("acpi items", 0); + ut_assert_nextline("dev 'acpi-test', type 1, size 2"); + ut_assert_nextline("dev 'acpi-test2', type 1, size 2"); + ut_assert_console_end(); + + ctx.current = buf; + ut_assertok(acpi_inject_dsdt(&ctx)); + console_record_reset(); + run_command("acpi items", 0); + ut_assert_nextline("dev 'acpi-test', type 2, size 2"); + ut_assert_nextline("dev 'acpi-test2', type 2, size 2"); + ut_assert_console_end(); + + console_record_reset(); + run_command("acpi items -d", 0); + ut_assert_nextline("dev 'acpi-test', type 2, size 2"); + ut_assert_nextlines_are_dump(2); + ut_assert_nextline("%s", ""); + ut_assert_nextline("dev 'acpi-test2', type 2, size 2"); + ut_assert_nextlines_are_dump(2); + ut_assert_nextline("%s", ""); + ut_assert_console_end(); + + return 0; +} +DM_TEST(dm_test_acpi_cmd_items, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -- cgit v1.2.3 From f18589576cb87e76c20046b335124a8af6feb6ac Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 7 Jul 2020 21:32:07 -0600 Subject: dm: core: Add a way of overriding the ACPI device path Some devices such as GPIO need to override the normal path that would be generated by driver model. Add a device-tree property for this. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Reviewed-by: Wolfgang Wallner --- doc/device-tree-bindings/device.txt | 23 +++++++++++++++++++++++ drivers/core/acpi.c | 19 +++++++++++++++++++ include/dm/acpi.h | 13 +++++++++++++ 3 files changed, 55 insertions(+) (limited to 'drivers/core') diff --git a/doc/device-tree-bindings/device.txt b/doc/device-tree-bindings/device.txt index 7140339623..2a5736c598 100644 --- a/doc/device-tree-bindings/device.txt +++ b/doc/device-tree-bindings/device.txt @@ -17,6 +17,8 @@ the acpi,compatible property. System) Device Name) - acpi,hid : Contains the string to use as the HID (Hardware ID) identifier _HID + - acpi,path : Specifies the full ACPI path for a device. This overrides the + normal path built from the driver-model hierarchy - acpi,name : Provides the ACPI name for a device, which is a string consisting of four alphanumeric character (upper case) - acpi,uid : _UID value for device @@ -47,3 +49,24 @@ pcie-a0@14,0 { interrupts-extended = <&acpi_gpe 0x3c 0>; }; }; + +p2sb: p2sb@d,0 { + u-boot,dm-pre-reloc; + reg = <0x02006810 0 0 0 0>; + compatible = "intel,apl-p2sb"; + early-regs = ; + pci,no-autoconfig; + + n { + compatible = "intel,apl-pinctrl"; + u-boot,dm-pre-reloc; + intel,p2sb-port-id = ; + acpi,path = "\\_SB.GPO0"; + gpio_n: gpio-n { + compatible = "intel,gpio"; + u-boot,dm-pre-reloc; + gpio-controller; + #gpio-cells = <2>; + linux-name = "INT3452:00"; + }; + }; diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c index b566f4f186..ae69258562 100644 --- a/drivers/core/acpi.c +++ b/drivers/core/acpi.c @@ -82,6 +82,25 @@ int acpi_get_name(const struct udevice *dev, char *out_name) return 0; } +int acpi_get_path(const struct udevice *dev, char *out_path, int maxlen) +{ + const char *path; + int ret; + + path = dev_read_string(dev, "acpi,path"); + if (path) { + if (strlen(path) >= maxlen) + return -E2BIG; + strcpy(out_path, path); + return 0; + } + ret = acpi_device_path(dev, out_path, maxlen); + if (ret) + return log_msg_ret("dev", ret); + + return 0; +} + /** * acpi_add_item() - Add a new item to the list of data collected * diff --git a/include/dm/acpi.h b/include/dm/acpi.h index aa1071ae35..a58722de73 100644 --- a/include/dm/acpi.h +++ b/include/dm/acpi.h @@ -187,6 +187,19 @@ int acpi_inject_dsdt(struct acpi_ctx *ctx); */ void acpi_dump_items(enum acpi_dump_option option); +/** + * acpi_get_path() - Get the full ACPI path for a device + * + * This checks for any override in the device tree and calls acpi_device_path() + * if not + * + * @dev: Device to check + * @out_path: Buffer to place the path in (should be ACPI_PATH_MAX long) + * @maxlen: Size of buffer (typically ACPI_PATH_MAX) + * @return 0 if OK, -ve on error + */ +int acpi_get_path(const struct udevice *dev, char *out_path, int maxlen); + #endif /* __ACPI__ */ #endif -- cgit v1.2.3 From b4e843341816395ef8a9d48793322617f9a50f9f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 7 Jul 2020 21:32:08 -0600 Subject: dm: acpi: Add support for the NHLT table The Intel Non-High-Definition-Audio Link Table (NHLT) table describes the audio codecs and connections in a system. Various devices can contribute information to produce the table. Add core support for this, based on a structure which is built up through calls to the driver. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner --- drivers/core/acpi.c | 15 +++++++++++++++ include/dm/acpi.h | 26 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) (limited to 'drivers/core') diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c index ae69258562..cdbc2c5cf5 100644 --- a/drivers/core/acpi.c +++ b/drivers/core/acpi.c @@ -31,6 +31,7 @@ enum method_t { METHOD_WRITE_TABLES, METHOD_FILL_SSDT, METHOD_INJECT_DSDT, + METHOD_SETUP_NHLT, }; /* Prototype for all methods */ @@ -248,6 +249,8 @@ acpi_method acpi_get_method(struct udevice *dev, enum method_t method) return aops->fill_ssdt; case METHOD_INJECT_DSDT: return aops->inject_dsdt; + case METHOD_SETUP_NHLT: + return aops->setup_nhlt; } } @@ -334,3 +337,15 @@ int acpi_write_dev_tables(struct acpi_ctx *ctx) return ret; } + +int acpi_setup_nhlt(struct acpi_ctx *ctx, struct nhlt *nhlt) +{ + int ret; + + log_debug("Setup NHLT\n"); + ctx->nhlt = nhlt; + ret = acpi_recurse_method(ctx, dm_root(), METHOD_SETUP_NHLT, TYPE_NONE); + log_debug("Setup finished, err=%d\n", ret); + + return ret; +} diff --git a/include/dm/acpi.h b/include/dm/acpi.h index a58722de73..e8b0336f6d 100644 --- a/include/dm/acpi.h +++ b/include/dm/acpi.h @@ -27,6 +27,8 @@ #if !defined(__ACPI__) +struct nhlt; + /** enum acpi_dump_option - selects what ACPI information to dump */ enum acpi_dump_option { ACPI_DUMP_LIST, /* Just the list of items */ @@ -44,6 +46,9 @@ enum acpi_dump_option { * 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 + * @nhlt: Intel Non-High-Definition-Audio Link Table (NHLT) pointer, used to + * build up information that audio codecs need to provide in the NHLT ACPI + * table * @len_stack: Stack of 'length' words to fix up later * @ltop: Points to current top of stack (0 = empty) */ @@ -53,6 +58,7 @@ struct acpi_ctx { struct acpi_rsdp *rsdp; struct acpi_rsdt *rsdt; struct acpi_xsdt *xsdt; + struct nhlt *nhlt; char *len_stack[ACPIGEN_LENSTACK_SIZE]; int ltop; }; @@ -113,6 +119,15 @@ struct acpi_ops { * @return 0 if OK, -ve on error */ int (*inject_dsdt)(const struct udevice *dev, struct acpi_ctx *ctx); + + /** + * setup_nhlt() - Set up audio information for this device + * + * The method can add information to ctx->nhlt if it likes + * + * @return 0 if OK, -ENODATA if nothing to add, -ve on error + */ + int (*setup_nhlt)(const struct udevice *dev, struct acpi_ctx *ctx); }; #define device_get_acpi_ops(dev) ((dev)->driver->acpi_ops) @@ -177,6 +192,17 @@ int acpi_fill_ssdt(struct acpi_ctx *ctx); */ int acpi_inject_dsdt(struct acpi_ctx *ctx); +/** + * acpi_setup_nhlt() - Set up audio information + * + * This is called to set up the nhlt information for all devices. + * + * @ctx: ACPI context to use + * @nhlt: Pointer to nhlt information to add to + * @return 0 if OK, -ve on error + */ +int acpi_setup_nhlt(struct acpi_ctx *ctx, struct nhlt *nhlt); + /** * acpi_dump_items() - Dump out the collected ACPI items * -- cgit v1.2.3 From d40d2c570600396b54dece16429727ef50cfeef0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 16 Jul 2020 21:22:39 -0600 Subject: acpi: Enable ACPI table generation by default on x86 This should ideally be used by all x86 boards in U-Boot. Enable it by default. If some boards don't use it, the cost is small. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/Kconfig | 1 + drivers/core/Kconfig | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/core') diff --git a/arch/Kconfig b/arch/Kconfig index a11f872938..9be02d1319 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -190,6 +190,7 @@ config X86 imply PCH imply RTC_MC146818 imply IRQ + imply ACPIGEN if !QEMU # Thing to enable for when SPL/TPL are enabled: SPL imply SPL_DM diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index a594899f37..00d1d80dc3 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -270,7 +270,7 @@ config DM_DEV_READ_INLINE config ACPIGEN bool "Support ACPI table generation in driver model" - default y if SANDBOX || GENERATE_ACPI_TABLE + default y if SANDBOX || (GENERATE_ACPI_TABLE && !QEMU) help This option enables generation of ACPI tables using driver-model devices. It adds a new operation struct to each driver, to support -- cgit v1.2.3