summaryrefslogtreecommitdiff
path: root/drivers/core
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2020-07-07 13:12:06 -0600
committerBin Meng <bmeng.cn@gmail.com>2020-07-17 14:32:24 +0800
commit0f7b111f70087f60e84f936fbe0c2a0a243a4fec (patch)
tree7f0e2a35c81f35ad1642971dcea95900437c695b /drivers/core
parent64ba6f43ef83e3a87abf5705d57ffc9109b5aa55 (diff)
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 <sjg@chromium.org> Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Diffstat (limited to 'drivers/core')
-rw-r--r--drivers/core/acpi.c84
1 files changed, 84 insertions, 0 deletions
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;
}