All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B)
@ 2020-05-10 20:33 Simon Glass
  2020-05-10 20:33 ` [PATCH v2 01/35] dm: core: Add an ACPI name for the root node Simon Glass
                   ` (68 more replies)
  0 siblings, 69 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

NOTE: I have resent this as v1 to avoid confusion

This is split from the original series in an attempt to get things applied
in chunks.

This part includes:
- writing basic ACPI code for integers, strings, names, packages
- writing descriptors for GPIO, I2C, interrupts, SPI
- writing code to enable/disable ACPI peripherals via GPIOs
- writing SSDT and DSDT tables
- additional ways to determine ACPI device names

Much of this code is taken from coreboot and I have tried to avoid
changing the original code for no reason. Changes include:
- splitting the acpi_dp functions into their own file
- adding tests
- adding (lots of) comments
- using a context pointer instead of global variables
- tidying up some code where couldn't resist (e.g. acpigen_emit_namestring())

Changes in v2:
- Fix memset of I2C descriptor
- Fix memset of SPI descriptor

Changes in v1:
- Capitalise ACPI_OPS_PTR
- Split into more patches for review
- Add tests
- Rebase on top of common.h series
- Fix 'the an' typo
- Move header definitions into this patch
- Update sandbox driver slightly for testing
- Switch parameter order of _acpi_fill_ssdt() and make it static
- Fix 'sentinal' and 'METHOD_FILL_SDDT' typos
- Correct the commit subject
- Generalise the ACPI function recursion with acpi_recurse_method()
- Generalise the ACPI function recursion with acpi_recurse_method()
- Use OEM_TABLE_ID instead of ACPI_TABLE_CREATOR
- Update ACPI_DSTATUS enum
- Drop writing of coreboot tables
- Generalise the ACPI function recursion with acpi_recurse_method()
- Use acpi,ddn instead of acpi,desc
- Rename to acpi_device_infer_name()
- Update newly created sandbox tests

Simon Glass (35):
  dm: core: Add an ACPI name for the root node
  acpi: Add a function to get a device path and scope
  acpi: Add a way to check device status
  irq: Add a method to convert an interrupt to ACPI
  acpi: Support generation of ACPI code
  acpi: Support generation of interrupt descriptor
  gpio: Add a method to convert a GPIO to ACPI
  acpi: Support string output
  acpi: Support generation of GPIO descriptor
  acpi: Support generation of a GPIO/irq for a device
  acpi: Support generation of I2C descriptor
  acpi: Support generation of SPI descriptor
  acpigen: Support writing a length
  acpigen: Support writing a package
  acpi: Support writing an integer
  acpi: Support writing a string
  acpi: Support writing a name
  acpi: Support writing a UUID
  acpi: Support writing Device Properties objects via _DSD
  acpi: Support writing a GPIO
  acpi: Support copying properties from device tree to ACPI
  acpi: Add support for various misc ACPI opcodes
  acpi: Add support for writing a Power Resource
  acpi: Add support for writing a GPIO power sequence
  acpi: Add support for a generic power sequence
  acpi: Add support for SSDT generation
  x86: acpi: Move MADT down a bit
  acpi: Record the items added to SSDT
  acpi: Support ordering SSDT data by device
  x86: Allow devices to write an SSDT
  acpi: Add support for DSDT generation
  x86: Allow devices to write to DSDT
  pci: Avoid a crash in device_is_on_pci_bus()
  dm: acpi: Enhance acpi_get_name()
  acpi: Add an acpi split command

 arch/sandbox/dts/test.dts           |  14 +-
 arch/x86/lib/acpi_table.c           |  54 +-
 cmd/acpi.c                          |  15 +-
 doc/device-tree-bindings/chosen.txt |   9 +
 doc/device-tree-bindings/device.txt |  13 +
 drivers/core/acpi.c                 | 207 ++++++-
 drivers/core/root.c                 |  13 +
 drivers/gpio/gpio-uclass.c          |  21 +
 drivers/gpio/sandbox.c              |  86 +++
 drivers/i2c/sandbox_i2c.c           |   1 +
 drivers/misc/irq-uclass.c           |  18 +-
 drivers/misc/irq_sandbox.c          |  16 +
 drivers/rtc/sandbox_rtc.c           |  13 +
 drivers/spi/sandbox_spi.c           |   1 +
 include/acpi/acpi_device.h          | 401 +++++++++++++
 include/acpi/acpi_dp.h              | 283 +++++++++
 include/acpi/acpi_table.h           |   6 +
 include/acpi/acpigen.h              | 347 +++++++++++
 include/asm-generic/gpio.h          |  27 +
 include/dm/acpi.h                   |  63 ++
 include/dm/device.h                 |   2 +-
 include/irq.h                       |  43 ++
 include/spi.h                       |   4 +-
 include/test/ut.h                   |  17 +
 lib/acpi/Makefile                   |   3 +
 lib/acpi/acpi_device.c              | 812 ++++++++++++++++++++++++++
 lib/acpi/acpi_dp.c                  | 397 +++++++++++++
 lib/acpi/acpigen.c                  | 477 +++++++++++++++
 test/dm/Makefile                    |   2 +
 test/dm/acpi.c                      | 277 ++++++++-
 test/dm/acpi_dp.c                   | 511 +++++++++++++++++
 test/dm/acpigen.c                   | 861 ++++++++++++++++++++++++++++
 test/dm/gpio.c                      |  62 ++
 test/dm/irq.c                       |  23 +
 test/dm/pci.c                       |  14 +
 35 files changed, 5080 insertions(+), 33 deletions(-)
 create mode 100644 include/acpi/acpi_device.h
 create mode 100644 include/acpi/acpi_dp.h
 create mode 100644 include/acpi/acpigen.h
 create mode 100644 lib/acpi/acpi_device.c
 create mode 100644 lib/acpi/acpi_dp.c
 create mode 100644 lib/acpi/acpigen.c
 create mode 100644 test/dm/acpi_dp.c
 create mode 100644 test/dm/acpigen.c

-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 01/35] dm: core: Add an ACPI name for the root node
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-17 14:40   ` Bin Meng
  2020-05-10 20:33 ` [PATCH v2 02/35] acpi: Add a function to get a device path and scope Simon Glass
                   ` (67 subsequent siblings)
  68 siblings, 1 reply; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

This always has a fixed ACPI name so add it as a driver function.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>
---

Changes in v2: None
Changes in v1:
- Capitalise ACPI_OPS_PTR

 drivers/core/root.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/core/root.c b/drivers/core/root.c
index 7d257ea887..14ae8a953b 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -12,6 +12,7 @@
 #include <log.h>
 #include <malloc.h>
 #include <linux/libfdt.h>
+#include <dm/acpi.h>
 #include <dm/device.h>
 #include <dm/device-internal.h>
 #include <dm/lists.h>
@@ -373,10 +374,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 */
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 02/35] acpi: Add a function to get a device path and scope
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
  2020-05-10 20:33 ` [PATCH v2 01/35] dm: core: Add an ACPI name for the root node Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-17 14:54   ` Bin Meng
  2020-05-10 20:33 ` [PATCH v2 03/35] acpi: Add a way to check device status Simon Glass
                   ` (66 subsequent siblings)
  68 siblings, 1 reply; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

Add a function to build up the ACPI path for a device and another for its
scope.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>
---

Changes in v2: None
Changes in v1:
- Split into more patches for review
- Add tests
- Rebase on top of common.h series

 arch/sandbox/dts/test.dts  |  3 ++
 include/acpi/acpi_device.h | 44 ++++++++++++++++++
 lib/acpi/Makefile          |  1 +
 lib/acpi/acpi_device.c     | 83 +++++++++++++++++++++++++++++++++
 test/dm/acpi.c             | 95 ++++++++++++++++++++++++++++++++------
 5 files changed, 213 insertions(+), 13 deletions(-)
 create mode 100644 include/acpi/acpi_device.h
 create mode 100644 lib/acpi/acpi_device.c

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 15cd2330a3..b802c1c909 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -253,6 +253,9 @@
 
 	acpi-test {
 		compatible = "denx,u-boot-acpi-test";
+		child {
+			compatible = "denx,u-boot-acpi-test";
+		};
 	};
 
 	acpi-test2 {
diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h
new file mode 100644
index 0000000000..37a675f101
--- /dev/null
+++ b/include/acpi/acpi_device.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Generation of tables for particular device types
+ *
+ * Copyright 2019 Google LLC
+ * Mostly taken from coreboot file of the same name
+ */
+
+#ifndef __ACPI_DEVICE_H
+#define __ACPI_DEVICE_H
+
+struct udevice;
+
+/* Length of a full path to an ACPI device */
+#define ACPI_PATH_MAX		30
+
+/**
+ * acpi_device_path() - Get the full path to an ACPI device
+ *
+ * This gets the full path in the form XXXX.YYYY.ZZZZ where XXXX is the root
+ * and ZZZZ is the device. All parent devices are added to the path.
+ *
+ * @dev: Device to check
+ * @buf: 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_device_path(const struct udevice *dev, char *buf, int maxlen);
+
+/**
+ * acpi_device_scope() - Get the scope of an ACPI device
+ *
+ * This gets the scope which is the full path of the parent device, as per
+ * acpi_device_path().
+ *
+ * @dev: Device to check
+ * @buf: Buffer to place the path in (should be ACPI_PATH_MAX long)
+ * @maxlen: Size of buffer (typically ACPI_PATH_MAX)
+ * @return 0 if OK, -EINVAL if the device has no parent, other -ve on other
+ *	error
+ */
+int acpi_device_scope(const struct udevice *dev, char *scope, int maxlen);
+
+#endif
diff --git a/lib/acpi/Makefile b/lib/acpi/Makefile
index 660491ef71..caae6c01bd 100644
--- a/lib/acpi/Makefile
+++ b/lib/acpi/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0+
 #
 
+obj-y += acpi_device.o
 obj-y += acpi_table.o
diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
new file mode 100644
index 0000000000..f9af2343c1
--- /dev/null
+++ b/lib/acpi/acpi_device.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generation of tables for particular device types
+ *
+ * Copyright 2019 Google LLC
+ * Mostly taken from coreboot file of the same name
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <acpi/acpi_device.h>
+#include <dm/acpi.h>
+
+/**
+ * acpi_device_path_fill() - Find the root device and build a path from there
+ *
+ * This recursively reaches back to the root device and progressively adds path
+ * elements until the device is reached.
+ *
+ * @dev: Device to return path of
+ * @buf: Buffer to hold the path
+ * @buf_len: Length of buffer
+ * @cur: Current position in the buffer
+ * @return new position in buffer after adding @dev, or -ve on error
+ */
+static int acpi_device_path_fill(const struct udevice *dev, char *buf,
+				 size_t buf_len, int cur)
+{
+	char name[ACPI_NAME_MAX];
+	int next = 0;
+	int ret;
+
+	ret = acpi_get_name(dev, name);
+	if (ret)
+		return ret;
+
+	/*
+	 * Make sure this name segment will fit, including the path segment
+	 * separator and possible NUL terminator, if this is the last segment.
+	 */
+	if (cur + strlen(name) + 2 > buf_len)
+		return -ENOSPC;
+
+	/* Walk up the tree to the root device */
+	if (dev_get_parent(dev)) {
+		next = acpi_device_path_fill(dev_get_parent(dev), buf, buf_len,
+					     cur);
+		if (next < 0)
+			return next;
+	}
+
+	/* Fill in the path from the root device */
+	next += snprintf(buf + next, buf_len - next, "%s%s",
+			 dev_get_parent(dev) && *name ? "." : "", name);
+
+	return next;
+}
+
+int acpi_device_path(const struct udevice *dev, char *buf, int maxlen)
+{
+	int ret;
+
+	ret = acpi_device_path_fill(dev, buf, maxlen, 0);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+int acpi_device_scope(const struct udevice *dev, char *scope, int maxlen)
+{
+	int ret;
+
+	if (!dev_get_parent(dev))
+		return log_msg_ret("noparent", -EINVAL);
+
+	ret = acpi_device_path_fill(dev_get_parent(dev), scope, maxlen, 0);
+	if (ret < 0)
+		return log_msg_ret("fill", ret);
+
+	return 0;
+}
diff --git a/test/dm/acpi.c b/test/dm/acpi.c
index 176d207a55..c25fe805c4 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -14,14 +14,27 @@
 #include <version.h>
 #include <tables_csum.h>
 #include <version.h>
+#include <acpi/acpi_device.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 ACPI_TEST_CHILD_NAME	"EFGH"
 #define BUF_SIZE		4096
 
+/**
+ * struct testacpi_platdata - Platform data for the test ACPI device
+ *
+ * @no_name: true to emit an empty ACPI name from testacpi_get_name()
+ * @return_error: true to return an error instead of a name
+ */
+struct testacpi_platdata {
+	bool return_error;
+	bool no_name;
+};
+
 static int testacpi_write_tables(const struct udevice *dev,
 				 struct acpi_ctx *ctx)
 {
@@ -40,7 +53,18 @@ static int testacpi_write_tables(const struct udevice *dev,
 
 static int testacpi_get_name(const struct udevice *dev, char *out_name)
 {
-	return acpi_copy_name(out_name, ACPI_TEST_DEV_NAME);
+	struct testacpi_platdata *plat = dev_get_platdata(dev);
+
+	if (plat->return_error)
+		return -EINVAL;
+	if (plat->no_name) {
+		*out_name = '\0';
+		return 0;
+	}
+	if (device_get_uclass_id(dev->parent) == UCLASS_TEST_ACPI)
+		return acpi_copy_name(out_name, ACPI_TEST_CHILD_NAME);
+	else
+		return acpi_copy_name(out_name, ACPI_TEST_DEV_NAME);
 }
 
 struct acpi_ops testacpi_ops = {
@@ -57,6 +81,8 @@ U_BOOT_DRIVER(testacpi_drv) = {
 	.name	= "testacpi_drv",
 	.of_match	= testacpi_ids,
 	.id	= UCLASS_TEST_ACPI,
+	.bind	= dm_scan_fdt_dev,
+	.platdata_auto_alloc_size	= sizeof(struct testacpi_platdata),
 	ACPI_OPS_PTR(&testacpi_ops)
 };
 
@@ -138,6 +164,7 @@ static int dm_test_acpi_write_tables(struct unit_test_state *uts)
 	struct acpi_dmar *dmar;
 	struct acpi_ctx ctx;
 	void *buf;
+	int i;
 
 	buf = malloc(BUF_SIZE);
 	ut_assertnonnull(buf);
@@ -147,24 +174,26 @@ static int dm_test_acpi_write_tables(struct unit_test_state *uts)
 	ut_assertok(acpi_write_dev_tables(&ctx));
 
 	/*
-	 * We should have two dmar tables, one for each "denx,u-boot-acpi-test"
-	 * device
+	 * We should have three dmar tables, one for each
+	 * "denx,u-boot-acpi-test" device
 	 */
-	ut_asserteq_ptr(dmar + 2, ctx.current);
+	ut_asserteq_ptr(dmar + 3, 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);
 
-	/* 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]);
+	ut_asserteq(DMAR_INTR_REMAP, dmar[2].flags);
+	ut_asserteq(32 - 1, dmar[2].host_address_width);
 
-	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]);
+	/* Check that the pointers were added correctly */
+	for (i = 0; i < 3; i++) {
+		ut_asserteq(map_to_sysmem(dmar + i), ctx.rsdt->entry[i]);
+		ut_asserteq(map_to_sysmem(dmar + i), ctx.xsdt->entry[i]);
+	}
+	ut_asserteq(0, ctx.rsdt->entry[3]);
+	ut_asserteq(0, ctx.xsdt->entry[3]);
 
 	return 0;
 }
@@ -268,15 +297,18 @@ static int dm_test_acpi_cmd_list(struct unit_test_state *uts)
 	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);
+			   3 * 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);
+			   3 * 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);
+	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();
@@ -315,3 +347,40 @@ static int dm_test_acpi_cmd_dump(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_cmd_dump, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test acpi_device_path() */
+static int dm_test_acpi_device_path(struct unit_test_state *uts)
+{
+	struct testacpi_platdata *plat;
+	char buf[ACPI_PATH_MAX];
+	struct udevice *dev, *child;
+
+	ut_assertok(uclass_first_device_err(UCLASS_TEST_ACPI, &dev));
+	ut_assertok(acpi_device_path(dev, buf, sizeof(buf)));
+	ut_asserteq_str("\\_SB." ACPI_TEST_DEV_NAME, buf);
+
+	/* Test running out of space */
+	buf[5] = '\0';
+	ut_asserteq(-ENOSPC, acpi_device_path(dev, buf, 5));
+	ut_asserteq('\0', buf[5]);
+
+	/* Test a three-component name */
+	ut_assertok(device_first_child_err(dev, &child));
+	ut_assertok(acpi_device_path(child, buf, sizeof(buf)));
+	ut_asserteq_str("\\_SB." ACPI_TEST_DEV_NAME "." ACPI_TEST_CHILD_NAME,
+			buf);
+
+	/* Test handling of a device which doesn't produce a name */
+	plat = dev_get_platdata(dev);
+	plat->no_name = true;
+	ut_assertok(acpi_device_path(child, buf, sizeof(buf)));
+	ut_asserteq_str("\\_SB." ACPI_TEST_CHILD_NAME, buf);
+
+	/* Test handling of a device which returns an error */
+	plat = dev_get_platdata(dev);
+	plat->return_error = true;
+	ut_asserteq(-EINVAL, acpi_device_path(child, buf, sizeof(buf)));
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_device_path, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 03/35] acpi: Add a way to check device status
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
  2020-05-10 20:33 ` [PATCH v2 01/35] dm: core: Add an ACPI name for the root node Simon Glass
  2020-05-10 20:33 ` [PATCH v2 02/35] acpi: Add a function to get a device path and scope Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 04/35] irq: Add a method to convert an interrupt to ACPI Simon Glass
                   ` (65 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

At present U-Boot does not support the different ACPI status values, but
it is best to put this logic in a central place. Add a function to get the
device status.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpi_device.h | 28 ++++++++++++++++++++++++++++
 lib/acpi/acpi_device.c     |  5 +++++
 test/dm/acpi.c             | 12 ++++++++++++
 3 files changed, 45 insertions(+)

diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h
index 37a675f101..09c227489a 100644
--- a/include/acpi/acpi_device.h
+++ b/include/acpi/acpi_device.h
@@ -9,11 +9,28 @@
 #ifndef __ACPI_DEVICE_H
 #define __ACPI_DEVICE_H
 
+#include <linux/bitops.h>
+
 struct udevice;
 
 /* Length of a full path to an ACPI device */
 #define ACPI_PATH_MAX		30
 
+/* Values that can be returned for ACPI device _STA method */
+enum acpi_dev_status {
+	ACPI_DSTATUS_PRESENT		= BIT(0),
+	ACPI_DSTATUS_ENABLED		= BIT(1),
+	ACPI_DSTATUS_SHOW_IN_UI		= BIT(2),
+	ACPI_DSTATUS_OK			= BIT(3),
+	ACPI_DSTATUS_HAS_BATTERY	= BIT(4),
+
+	ACPI_DSTATUS_ALL_OFF	= 0,
+	ACPI_DSTATUS_HIDDEN_ON	= ACPI_DSTATUS_PRESENT | ACPI_DSTATUS_ENABLED |
+		ACPI_DSTATUS_OK,
+	ACPI_DSTATUS_ALL_ON	= ACPI_DSTATUS_HIDDEN_ON |
+		ACPI_DSTATUS_SHOW_IN_UI,
+};
+
 /**
  * acpi_device_path() - Get the full path to an ACPI device
  *
@@ -41,4 +58,15 @@ int acpi_device_path(const struct udevice *dev, char *buf, int maxlen);
  */
 int acpi_device_scope(const struct udevice *dev, char *scope, int maxlen);
 
+/**
+ * acpi_device_status() - Get the status of a device
+ *
+ * This currently just returns ACPI_DSTATUS_ALL_ON. It does not support
+ * inactive or hidden devices.
+ *
+ * @dev: Device to check
+ * @return device status, as ACPI_DSTATUS_...
+ */
+enum acpi_dev_status acpi_device_status(const struct udevice *dev);
+
 #endif
diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
index f9af2343c1..7b18cbf148 100644
--- a/lib/acpi/acpi_device.c
+++ b/lib/acpi/acpi_device.c
@@ -81,3 +81,8 @@ int acpi_device_scope(const struct udevice *dev, char *scope, int maxlen)
 
 	return 0;
 }
+
+enum acpi_dev_status acpi_device_status(const struct udevice *dev)
+{
+	return ACPI_DSTATUS_ALL_ON;
+}
diff --git a/test/dm/acpi.c b/test/dm/acpi.c
index c25fe805c4..0c2e12d170 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -384,3 +384,15 @@ static int dm_test_acpi_device_path(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_device_path, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test acpi_device_status() */
+static int dm_test_acpi_device_status(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+
+	ut_assertok(uclass_first_device_err(UCLASS_TEST_ACPI, &dev));
+	ut_asserteq(ACPI_DSTATUS_ALL_ON, acpi_device_status(dev));
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_device_status, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 04/35] irq: Add a method to convert an interrupt to ACPI
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (2 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 03/35] acpi: Add a way to check device status Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 05/35] acpi: Support generation of ACPI code Simon Glass
                   ` (64 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

When generating ACPI tables we need to convert IRQs in U-Boot to the ACPI
structures required by ACPI. This is a SoC-specific conversion and cannot
be handled by generic code, so add a new IRQ method to do the conversion.

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

Changes in v2: None
Changes in v1:
- Fix 'the an' typo
- Move header definitions into this patch

 drivers/misc/irq-uclass.c  | 18 ++++++++++--
 drivers/misc/irq_sandbox.c | 16 +++++++++++
 include/acpi/acpi_device.h | 59 ++++++++++++++++++++++++++++++++++++++
 include/irq.h              | 43 +++++++++++++++++++++++++++
 test/dm/irq.c              | 22 ++++++++++++++
 5 files changed, 156 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
index 16dc0be75c..98bc79eaba 100644
--- a/drivers/misc/irq-uclass.c
+++ b/drivers/misc/irq-uclass.c
@@ -154,8 +154,6 @@ int irq_request(struct udevice *dev, struct irq *irq)
 	const struct irq_ops *ops;
 
 	log_debug("(dev=%p, irq=%p)\n", dev, irq);
-	if (!irq)
-		return 0;
 	ops = irq_get_ops(dev);
 
 	irq->dev = dev;
@@ -177,6 +175,22 @@ int irq_first_device_type(enum irq_dev_t type, struct udevice **devp)
 	return 0;
 }
 
+#if CONFIG_IS_ENABLED(ACPIGEN)
+int irq_get_acpi(const struct irq *irq, struct acpi_irq *acpi_irq)
+{
+	struct irq_ops *ops;
+
+	if (!irq_is_valid(irq))
+		return -EINVAL;
+
+	ops = irq_get_ops(irq->dev);
+	if (!ops->get_acpi)
+		return -ENOSYS;
+
+	return ops->get_acpi(irq, acpi_irq);
+}
+#endif
+
 UCLASS_DRIVER(irq) = {
 	.id		= UCLASS_IRQ,
 	.name		= "irq",
diff --git a/drivers/misc/irq_sandbox.c b/drivers/misc/irq_sandbox.c
index 54bc47c8d8..a2511b32fc 100644
--- a/drivers/misc/irq_sandbox.c
+++ b/drivers/misc/irq_sandbox.c
@@ -8,6 +8,7 @@
 #include <common.h>
 #include <dm.h>
 #include <irq.h>
+#include <acpi/acpi_device.h>
 #include <asm/test.h>
 
 /**
@@ -73,6 +74,18 @@ static int sandbox_irq_of_xlate(struct irq *irq,
 	return 0;
 }
 
+static __maybe_unused int sandbox_get_acpi(const struct irq *irq,
+					   struct acpi_irq *acpi_irq)
+{
+	acpi_irq->pin = irq->id;
+	acpi_irq->mode = ACPI_IRQ_LEVEL_TRIGGERED;
+	acpi_irq->polarity = ACPI_IRQ_ACTIVE_HIGH;
+	acpi_irq->shared = ACPI_IRQ_SHARED;
+	acpi_irq->wake = ACPI_IRQ_WAKE;
+
+	return 0;
+}
+
 static const struct irq_ops sandbox_irq_ops = {
 	.route_pmc_gpio_gpe	= sandbox_route_pmc_gpio_gpe,
 	.set_polarity		= sandbox_set_polarity,
@@ -80,6 +93,9 @@ static const struct irq_ops sandbox_irq_ops = {
 	.restore_polarities	= sandbox_restore_polarities,
 	.read_and_clear		= sandbox_irq_read_and_clear,
 	.of_xlate		= sandbox_irq_of_xlate,
+#if CONFIG_IS_ENABLED(ACPIGEN)
+	.get_acpi		= sandbox_get_acpi,
+#endif
 };
 
 static const struct udevice_id sandbox_irq_ids[] = {
diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h
index 09c227489a..24895de0da 100644
--- a/include/acpi/acpi_device.h
+++ b/include/acpi/acpi_device.h
@@ -13,6 +13,12 @@
 
 struct udevice;
 
+/* ACPI descriptor values for common descriptors: SERIAL_BUS means I2C */
+#define ACPI_DESCRIPTOR_LARGE		BIT(7)
+#define ACPI_DESCRIPTOR_INTERRUPT	(ACPI_DESCRIPTOR_LARGE | 9)
+#define ACPI_DESCRIPTOR_GPIO		(ACPI_DESCRIPTOR_LARGE | 12)
+#define ACPI_DESCRIPTOR_SERIAL_BUS	(ACPI_DESCRIPTOR_LARGE | 14)
+
 /* Length of a full path to an ACPI device */
 #define ACPI_PATH_MAX		30
 
@@ -31,6 +37,59 @@ enum acpi_dev_status {
 		ACPI_DSTATUS_SHOW_IN_UI,
 };
 
+/** enum acpi_irq_mode - edge/level trigger mode */
+enum acpi_irq_mode {
+	ACPI_IRQ_EDGE_TRIGGERED,
+	ACPI_IRQ_LEVEL_TRIGGERED,
+};
+
+/**
+ * enum acpi_irq_polarity - polarity of interrupt
+ *
+ * @ACPI_IRQ_ACTIVE_LOW - for ACPI_IRQ_EDGE_TRIGGERED this means falling edge
+ * @ACPI_IRQ_ACTIVE_HIGH - for ACPI_IRQ_EDGE_TRIGGERED this means rising edge
+ * @ACPI_IRQ_ACTIVE_BOTH - not meaningful for ACPI_IRQ_EDGE_TRIGGERED
+ */
+enum acpi_irq_polarity {
+	ACPI_IRQ_ACTIVE_LOW,
+	ACPI_IRQ_ACTIVE_HIGH,
+	ACPI_IRQ_ACTIVE_BOTH,
+};
+
+/**
+ * enum acpi_irq_shared - whether interrupt is shared or not
+ *
+ * @ACPI_IRQ_EXCLUSIVE: only this device uses the interrupt
+ * @ACPI_IRQ_SHARED: other devices may use this interrupt
+ */
+enum acpi_irq_shared {
+	ACPI_IRQ_EXCLUSIVE,
+	ACPI_IRQ_SHARED,
+};
+
+/** enum acpi_irq_wake - indicates whether this interrupt can wake the device */
+enum acpi_irq_wake {
+	ACPI_IRQ_NO_WAKE,
+	ACPI_IRQ_WAKE,
+};
+
+/**
+ * struct acpi_irq - representation of an ACPI interrupt
+ *
+ * @pin: ACPI pin that is monitored for the interrupt
+ * @mode: Edge/level triggering
+ * @polarity: Interrupt polarity
+ * @shared: Whether interrupt is shared or not
+ * @wake: Whether interrupt can wake the device from sleep
+ */
+struct acpi_irq {
+	unsigned int pin;
+	enum acpi_irq_mode mode;
+	enum acpi_irq_polarity polarity;
+	enum acpi_irq_shared shared;
+	enum acpi_irq_wake wake;
+};
+
 /**
  * acpi_device_path() - Get the full path to an ACPI device
  *
diff --git a/include/irq.h b/include/irq.h
index b71afe9bee..8527e4dd79 100644
--- a/include/irq.h
+++ b/include/irq.h
@@ -8,6 +8,9 @@
 #ifndef __irq_H
 #define __irq_H
 
+struct acpi_irq;
+struct ofnode_phandle_args;
+
 /*
  * Interrupt controller types available. You can find a particular one with
  * irq_first_device_type()
@@ -24,10 +27,12 @@ enum irq_dev_t {
  *
  * @dev: IRQ device that handles this irq
  * @id: ID to identify this irq with the device
+ * @flags: Flags associated with this interrupt (IRQ_TYPE_...)
  */
 struct irq {
 	struct udevice *dev;
 	ulong id;
+	ulong flags;
 };
 
 /**
@@ -119,10 +124,36 @@ struct irq_ops {
 	 * @return 0 if OK, or a negative error code.
 	 */
 	int (*free)(struct irq *irq);
+
+#if CONFIG_IS_ENABLED(ACPIGEN)
+	/**
+	 * get_acpi() - Get the ACPI info for an irq
+	 *
+	 * This converts a irq to an ACPI structure for adding to the ACPI
+	 * tables.
+	 *
+	 * @irq:	irq to convert
+	 * @acpi_irq:	Output ACPI interrupt information
+	 * @return ACPI pin number or -ve on error
+	 */
+	int (*get_acpi)(const struct irq *irq, struct acpi_irq *acpi_irq);
+#endif
 };
 
 #define irq_get_ops(dev)	((struct irq_ops *)(dev)->driver->ops)
 
+/**
+ * irq_is_valid() - Check if an IRQ is valid
+ *
+ * @irq:	IRQ description containing device and ID, e.g. previously
+ *		returned by irq_get_by_index()
+ * @return true if valid, false if not
+ */
+static inline bool irq_is_valid(const struct irq *irq)
+{
+	return irq->dev != NULL;
+}
+
 /**
  * irq_route_pmc_gpio_gpe() - Get the GPIO for an event
  *
@@ -223,4 +254,16 @@ int irq_free(struct irq *irq);
  */
 int irq_first_device_type(enum irq_dev_t type, struct udevice **devp);
 
+/**
+ * irq_get_acpi() - Get the ACPI info for an irq
+ *
+ * This converts a irq to an ACPI structure for adding to the ACPI
+ * tables.
+ *
+ * @irq:	irq to convert
+ * @acpi_irq:	Output ACPI interrupt information
+ * @return ACPI pin number or -ve on error
+ */
+int irq_get_acpi(const struct irq *irq, struct acpi_irq *acpi_irq);
+
 #endif
diff --git a/test/dm/irq.c b/test/dm/irq.c
index 192d80d7e1..50e505e657 100644
--- a/test/dm/irq.c
+++ b/test/dm/irq.c
@@ -8,6 +8,7 @@
 #include <common.h>
 #include <dm.h>
 #include <irq.h>
+#include <acpi/acpi_device.h>
 #include <asm/test.h>
 #include <dm/test.h>
 #include <test/ut.h>
@@ -75,3 +76,24 @@ static int dm_test_request(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_request, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test of irq_get_acpi() */
+static int dm_test_irq_get_acpi(struct unit_test_state *uts)
+{
+	struct acpi_irq airq;
+	struct udevice *dev;
+	struct irq irq;
+
+	ut_assertok(uclass_first_device_err(UCLASS_TEST_FDT, &dev));
+	ut_assertok(irq_get_by_index(dev, 0, &irq));
+
+	ut_assertok(irq_get_acpi(&irq, &airq));
+	ut_asserteq(3, airq.pin);
+	ut_asserteq(ACPI_IRQ_LEVEL_TRIGGERED, airq.mode);
+	ut_asserteq(ACPI_IRQ_ACTIVE_HIGH, airq.polarity);
+	ut_asserteq(ACPI_IRQ_SHARED, airq.shared);
+	ut_asserteq(ACPI_IRQ_WAKE, airq.wake);
+
+	return 0;
+}
+DM_TEST(dm_test_irq_get_acpi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 05/35] acpi: Support generation of ACPI code
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (3 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 04/35] irq: Add a method to convert an interrupt to ACPI Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 06/35] acpi: Support generation of interrupt descriptor Simon Glass
                   ` (63 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

Add a new file to handle generating ACPI code programatically. This is
used when information must be dynamically added to the tables, e.g. the
SSDT.

Initial support is just for writing simple values.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpigen.h | 49 +++++++++++++++++++++++++++++++
 lib/acpi/Makefile      |  1 +
 lib/acpi/acpigen.c     | 38 ++++++++++++++++++++++++
 test/dm/Makefile       |  1 +
 test/dm/acpigen.c      | 65 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 154 insertions(+)
 create mode 100644 include/acpi/acpigen.h
 create mode 100644 lib/acpi/acpigen.c
 create mode 100644 test/dm/acpigen.c

diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
new file mode 100644
index 0000000000..8809cdb4e1
--- /dev/null
+++ b/include/acpi/acpigen.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Core ACPI (Advanced Configuration and Power Interface) support
+ *
+ * Copyright 2019 Google LLC
+ *
+ * Modified from coreboot file acpigen.h
+ */
+
+#ifndef __ACPI_ACPIGEN_H
+#define __ACPI_ACPIGEN_H
+
+#include <linux/types.h>
+
+struct acpi_ctx;
+
+/**
+ * acpigen_get_current() - Get the current ACPI code output pointer
+ *
+ * @ctx: ACPI context pointer
+ * @return output pointer
+ */
+u8 *acpigen_get_current(struct acpi_ctx *ctx);
+
+/**
+ * acpigen_emit_byte() - Emit a byte to the ACPI code
+ *
+ * @ctx: ACPI context pointer
+ * @data: Value to output
+ */
+void acpigen_emit_byte(struct acpi_ctx *ctx, uint data);
+
+/**
+ * acpigen_emit_word() - Emit a 16-bit word to the ACPI code
+ *
+ * @ctx: ACPI context pointer
+ * @data: Value to output
+ */
+void acpigen_emit_word(struct acpi_ctx *ctx, uint data);
+
+/**
+ * acpigen_emit_dword() - Emit a 32-bit 'double word' to the ACPI code
+ *
+ * @ctx: ACPI context pointer
+ * @data: Value to output
+ */
+void acpigen_emit_dword(struct acpi_ctx *ctx, uint data);
+
+#endif
diff --git a/lib/acpi/Makefile b/lib/acpi/Makefile
index caae6c01bd..85a1f774ad 100644
--- a/lib/acpi/Makefile
+++ b/lib/acpi/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0+
 #
 
+obj-y += acpigen.o
 obj-y += acpi_device.o
 obj-y += acpi_table.o
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
new file mode 100644
index 0000000000..59bd3af0b7
--- /dev/null
+++ b/lib/acpi/acpigen.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generation of ACPI (Advanced Configuration and Power Interface) tables
+ *
+ * Copyright 2019 Google LLC
+ * Mostly taken from coreboot
+ */
+
+#define LOG_CATEGORY LOGC_ACPI
+
+#include <common.h>
+#include <dm.h>
+#include <acpi/acpigen.h>
+#include <dm/acpi.h>
+
+u8 *acpigen_get_current(struct acpi_ctx *ctx)
+{
+	return ctx->current;
+}
+
+void acpigen_emit_byte(struct acpi_ctx *ctx, uint data)
+{
+	*(u8 *)ctx->current++ = data;
+}
+
+void acpigen_emit_word(struct acpi_ctx *ctx, uint data)
+{
+	acpigen_emit_byte(ctx, data & 0xff);
+	acpigen_emit_byte(ctx, (data >> 8) & 0xff);
+}
+
+void acpigen_emit_dword(struct acpi_ctx *ctx, uint data)
+{
+	acpigen_emit_byte(ctx, data & 0xff);
+	acpigen_emit_byte(ctx, (data >> 8) & 0xff);
+	acpigen_emit_byte(ctx, (data >> 16) & 0xff);
+	acpigen_emit_byte(ctx, (data >> 24) & 0xff);
+}
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 6c18fd04ce..e3e0cccf01 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_UT_DM) += test-uclass.o
 obj-$(CONFIG_UT_DM) += core.o
 ifneq ($(CONFIG_SANDBOX),)
 obj-$(CONFIG_ACPIGEN) += acpi.o
+obj-$(CONFIG_ACPIGEN) += acpigen.o
 obj-$(CONFIG_SOUND) += audio.o
 obj-$(CONFIG_BLK) += blk.o
 obj-$(CONFIG_BOARD) += board.o
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
new file mode 100644
index 0000000000..68f2b73132
--- /dev/null
+++ b/test/dm/acpigen.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Tests for ACPI code generation
+ *
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <acpi/acpigen.h>
+#include <asm/unaligned.h>
+#include <dm/acpi.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+static int alloc_context(struct acpi_ctx **ctxp)
+{
+	struct acpi_ctx *ctx;
+
+	*ctxp = NULL;
+	ctx = malloc(sizeof(*ctx));
+	if (!ctx)
+		return -ENOMEM;
+	ctx->current = malloc(150);
+	if (!ctx->current)
+		return -ENOMEM;
+	*ctxp = ctx;
+
+	return 0;
+}
+
+static void free_context(struct acpi_ctx **ctxp)
+{
+	free(*ctxp);
+	*ctxp = NULL;
+}
+
+/* Test emitting simple types and acpigen_get_current() */
+static int dm_test_acpi_emit_simple(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+	acpigen_emit_byte(ctx, 0x23);
+	ut_asserteq(1, acpigen_get_current(ctx) - ptr);
+	ut_asserteq(0x23, *(u8 *)ptr);
+
+	acpigen_emit_word(ctx, 0x1234);
+	ut_asserteq(3, acpigen_get_current(ctx) - ptr);
+	ut_asserteq(0x1234, get_unaligned((u16 *)(ptr + 1)));
+
+	acpigen_emit_dword(ctx, 0x87654321);
+	ut_asserteq(7, acpigen_get_current(ctx) - ptr);
+	ut_asserteq(0x87654321, get_unaligned((u32 *)(ptr + 3)));
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_emit_simple, 0);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 06/35] acpi: Support generation of interrupt descriptor
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (4 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 05/35] acpi: Support generation of ACPI code Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 07/35] gpio: Add a method to convert a GPIO to ACPI Simon Glass
                   ` (62 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

Add a function to write an interrupt descriptor to the generated ACPI
code.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpi_device.h |  15 +++++
 lib/acpi/acpi_device.c     | 118 +++++++++++++++++++++++++++++++++++++
 test/dm/acpigen.c          |  31 ++++++++++
 3 files changed, 164 insertions(+)

diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h
index 24895de0da..4f87cd003a 100644
--- a/include/acpi/acpi_device.h
+++ b/include/acpi/acpi_device.h
@@ -11,6 +11,8 @@
 
 #include <linux/bitops.h>
 
+struct acpi_ctx;
+struct irq;
 struct udevice;
 
 /* ACPI descriptor values for common descriptors: SERIAL_BUS means I2C */
@@ -128,4 +130,17 @@ int acpi_device_scope(const struct udevice *dev, char *scope, int maxlen);
  */
 enum acpi_dev_status acpi_device_status(const struct udevice *dev);
 
+/**
+ * acpi_device_write_interrupt_irq() - Write an interrupt descriptor
+ *
+ * This writes an ACPI interrupt descriptor for the given interrupt, converting
+ * fields as needed.
+ *
+ * @ctx: ACPI context pointer
+ * @req_irq: Interrupt to output
+ * @return 0 if OK, -ve on error
+ */
+int acpi_device_write_interrupt_irq(struct acpi_ctx *ctx,
+				    const struct irq *req_irq);
+
 #endif
diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
index 7b18cbf148..6b2fb7e47e 100644
--- a/lib/acpi/acpi_device.c
+++ b/lib/acpi/acpi_device.c
@@ -8,8 +8,10 @@
 
 #include <common.h>
 #include <dm.h>
+#include <irq.h>
 #include <log.h>
 #include <acpi/acpi_device.h>
+#include <acpi/acpigen.h>
 #include <dm/acpi.h>
 
 /**
@@ -86,3 +88,119 @@ enum acpi_dev_status acpi_device_status(const struct udevice *dev)
 {
 	return ACPI_DSTATUS_ALL_ON;
 }
+
+/**
+ * acpi_device_write_zero_len() - Write a placeholder word value
+ *
+ * @return pointer to the zero word (for fixing up later)
+ */
+static void *acpi_device_write_zero_len(struct acpi_ctx *ctx)
+{
+	u8 *p = acpigen_get_current(ctx);
+
+	acpigen_emit_word(ctx, 0);
+
+	return p;
+}
+
+/**
+ * acpi_device_fill_from_len() - Fill in a length value
+ *
+ * This calculated the number of bytes since the provided @start and writes it
+ * to @ptr, which was previous returned by acpi_device_write_zero_len().
+ *
+ * @ptr: Word to update
+ * @start: Start address to count from to calculated the length
+ */
+static void acpi_device_fill_from_len(struct acpi_ctx *ctx, char *ptr,
+				      u8 *start)
+{
+	u16 len = acpigen_get_current(ctx) - start;
+
+	ptr[0] = len & 0xff;
+	ptr[1] = (len >> 8) & 0xff;
+}
+
+/**
+ * acpi_device_fill_len() - Fill in a length value, excluding the length itself
+ *
+ * Fill in the length field with the value calculated from after the 16bit
+ * field to acpigen current. This is useful since the length value does not
+ * include the length field itself.
+ *
+ * This calls acpi_device_fill_from_len() passing @ptr + 2 as @start
+ *
+ * @ptr: Word to update.
+ */
+static void acpi_device_fill_len(struct acpi_ctx *ctx, void *ptr)
+{
+	acpi_device_fill_from_len(ctx, ptr, ptr + sizeof(u16));
+}
+
+/* ACPI 6.3 section 6.4.3.6: Extended Interrupt Descriptor */
+static int acpi_device_write_interrupt(struct acpi_ctx *ctx,
+				       const struct acpi_irq *irq)
+{
+	void *desc_length;
+	u8 flags;
+
+	if (!irq->pin)
+		return -ENOENT;
+
+	/* This is supported by GpioInt() but not Interrupt() */
+	if (irq->polarity == ACPI_IRQ_ACTIVE_BOTH)
+		return -EINVAL;
+
+	/* Byte 0: Descriptor Type */
+	acpigen_emit_byte(ctx, ACPI_DESCRIPTOR_INTERRUPT);
+
+	/* Byte 1-2: Length (filled in later) */
+	desc_length = acpi_device_write_zero_len(ctx);
+
+	/*
+	 * Byte 3: Flags
+	 *  [7:5]: Reserved
+	 *    [4]: Wake     (0=NO_WAKE   1=WAKE)
+	 *    [3]: Sharing  (0=EXCLUSIVE 1=SHARED)
+	 *    [2]: Polarity (0=HIGH      1=LOW)
+	 *    [1]: Mode     (0=LEVEL     1=EDGE)
+	 *    [0]: Resource (0=PRODUCER  1=CONSUMER)
+	 */
+	flags = 1 << 0; /* ResourceConsumer */
+	if (irq->mode == ACPI_IRQ_EDGE_TRIGGERED)
+		flags |= 1 << 1;
+	if (irq->polarity == ACPI_IRQ_ACTIVE_LOW)
+		flags |= 1 << 2;
+	if (irq->shared == ACPI_IRQ_SHARED)
+		flags |= 1 << 3;
+	if (irq->wake == ACPI_IRQ_WAKE)
+		flags |= 1 << 4;
+	acpigen_emit_byte(ctx, flags);
+
+	/* Byte 4: Interrupt Table Entry Count */
+	acpigen_emit_byte(ctx, 1);
+
+	/* Byte 5-8: Interrupt Number */
+	acpigen_emit_dword(ctx, irq->pin);
+
+	/* Fill in Descriptor Length (account for len word) */
+	acpi_device_fill_len(ctx, desc_length);
+
+	return 0;
+}
+
+int acpi_device_write_interrupt_irq(struct acpi_ctx *ctx,
+				    const struct irq *req_irq)
+{
+	struct acpi_irq irq;
+	int ret;
+
+	ret = irq_get_acpi(req_irq, &irq);
+	if (ret)
+		return log_msg_ret("get", ret);
+	ret = acpi_device_write_interrupt(ctx, &irq);
+	if (ret)
+		return log_msg_ret("write", ret);
+
+	return 0;
+}
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index 68f2b73132..ab1261db9f 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -8,8 +8,10 @@
 
 #include <common.h>
 #include <dm.h>
+#include <irq.h>
 #include <malloc.h>
 #include <acpi/acpigen.h>
+#include <acpi/acpi_device.h>
 #include <asm/unaligned.h>
 #include <dm/acpi.h>
 #include <dm/test.h>
@@ -63,3 +65,32 @@ static int dm_test_acpi_emit_simple(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_emit_simple, 0);
+
+/* Test emitting an interrupt descriptor */
+static int dm_test_acpi_interrupt(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	struct udevice *dev;
+	struct irq irq;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+
+	ut_assertok(uclass_first_device_err(UCLASS_TEST_FDT, &dev));
+	ut_assertok(irq_get_by_index(dev, 0, &irq));
+
+	ut_assertok(acpi_device_write_interrupt_irq(ctx, &irq));
+	ut_asserteq(9, acpigen_get_current(ctx) - ptr);
+	ut_asserteq(ACPI_DESCRIPTOR_INTERRUPT, ptr[0]);
+	ut_asserteq(6, get_unaligned((u16 *)(ptr + 1)));
+	ut_asserteq(0x19, ptr[3]);
+	ut_asserteq(1, ptr[4]);
+	ut_asserteq(3, get_unaligned((u32 *)(ptr + 5)));
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_interrupt, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 07/35] gpio: Add a method to convert a GPIO to ACPI
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (5 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 06/35] acpi: Support generation of interrupt descriptor Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 08/35] acpi: Support string output Simon Glass
                   ` (61 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

When generating ACPI tables we need to convert GPIOs in U-Boot to the ACPI
structures required by ACPI. This is a SoC-specific conversion and cannot
be handled by generic code, so add a new GPIO method to do the conversion.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>
---

Changes in v2: None
Changes in v1:
- Update sandbox driver slightly for testing

 drivers/gpio/gpio-uclass.c | 21 +++++++++
 drivers/gpio/sandbox.c     | 86 ++++++++++++++++++++++++++++++++++++
 include/acpi/acpi_device.h | 90 ++++++++++++++++++++++++++++++++++++++
 include/asm-generic/gpio.h | 27 ++++++++++++
 test/dm/gpio.c             | 62 ++++++++++++++++++++++++++
 test/dm/irq.c              |  1 +
 6 files changed, 287 insertions(+)

diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index aaaeb5940b..d50e677947 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -13,6 +13,7 @@
 #include <errno.h>
 #include <fdtdec.h>
 #include <malloc.h>
+#include <acpi/acpi_device.h>
 #include <asm/gpio.h>
 #include <dm/device_compat.h>
 #include <linux/bug.h>
@@ -794,6 +795,26 @@ int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize)
 	return 0;
 }
 
+#if CONFIG_IS_ENABLED(ACPIGEN)
+int gpio_get_acpi(const struct gpio_desc *desc, struct acpi_gpio *gpio)
+{
+	struct dm_gpio_ops *ops;
+
+	if (!dm_gpio_is_valid(desc)) {
+		/* Indicate that the GPIO is not valid */
+		gpio->pin_count = 0;
+		gpio->pins[0] = 0;
+		return -EINVAL;
+	}
+
+	ops = gpio_get_ops(desc->dev);
+	if (!ops->get_acpi)
+		return -ENOSYS;
+
+	return ops->get_acpi(desc, gpio);
+}
+#endif
+
 int gpio_claim_vector(const int *gpio_num_array, const char *fmt)
 {
 	int i, ret;
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c
index 98b7fa4bb3..6cd2a1455a 100644
--- a/drivers/gpio/sandbox.c
+++ b/drivers/gpio/sandbox.c
@@ -8,7 +8,9 @@
 #include <fdtdec.h>
 #include <log.h>
 #include <malloc.h>
+#include <acpi/acpi_device.h>
 #include <asm/gpio.h>
+#include <dm/acpi.h>
 #include <dm/device_compat.h>
 #include <dm/lists.h>
 #include <dm/of.h>
@@ -197,6 +199,72 @@ static int sb_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
 	return 0;
 }
 
+#if CONFIG_IS_ENABLED(ACPIGEN)
+static int sb_gpio_get_acpi(const struct gpio_desc *desc,
+			    struct acpi_gpio *gpio)
+{
+	int ret;
+
+	/* All of these values are just used for testing */
+	if (desc->flags & GPIOD_ACTIVE_LOW) {
+		gpio->pin_count = 1;
+		gpio->pins[0] = desc->offset;
+		gpio->pin0_addr = 0x80012 + desc->offset;
+		gpio->type = ACPI_GPIO_TYPE_INTERRUPT;
+		gpio->pull = ACPI_GPIO_PULL_DOWN;
+		ret = acpi_device_scope(desc->dev, gpio->resource,
+					sizeof(gpio->resource));
+		if (ret)
+			return log_ret(ret);
+		gpio->interrupt_debounce_timeout = 4321;
+		memset(&gpio->irq, '\0', sizeof(gpio->irq));
+
+		/* We use the GpioInt part */
+		gpio->irq.pin = desc->offset;
+		gpio->irq.polarity = ACPI_IRQ_ACTIVE_BOTH;
+		gpio->irq.shared = ACPI_IRQ_SHARED;
+		gpio->irq.wake = ACPI_IRQ_WAKE;
+
+		/* The GpioIo part is not used */
+		gpio->output_drive_strength = 0;
+		gpio->io_shared = false;
+		gpio->io_restrict = 0;
+		gpio->polarity = ACPI_GPIO_ACTIVE_LOW;
+	} else {
+		gpio->pin_count = 1;
+		gpio->pins[0] = desc->offset;
+		gpio->pin0_addr = 0xc00dc + desc->offset;
+		gpio->type = ACPI_GPIO_TYPE_IO;
+		gpio->pull = ACPI_GPIO_PULL_UP;
+		ret = acpi_device_scope(desc->dev, gpio->resource,
+					sizeof(gpio->resource));
+		if (ret)
+			return log_ret(ret);
+		gpio->interrupt_debounce_timeout = 0;
+
+		/* The GpioInt part is not used */
+		memset(&gpio->irq, '\0', sizeof(gpio->irq));
+
+		/* We use the GpioIo part */
+		gpio->output_drive_strength = 1234;
+		gpio->io_shared = true;
+		gpio->io_restrict = ACPI_GPIO_IO_RESTRICT_INPUT;
+		gpio->polarity = 0;
+	}
+
+	return 0;
+}
+
+static int sb_gpio_get_name(const struct udevice *dev, char *out_name)
+{
+	return acpi_copy_name(out_name, "GPIO");
+}
+
+struct acpi_ops gpio_sandbox_acpi_ops = {
+	.get_name	= sb_gpio_get_name,
+};
+#endif /* ACPIGEN */
+
 static const struct dm_gpio_ops gpio_sandbox_ops = {
 	.direction_input	= sb_gpio_direction_input,
 	.direction_output	= sb_gpio_direction_output,
@@ -206,6 +274,9 @@ static const struct dm_gpio_ops gpio_sandbox_ops = {
 	.xlate			= sb_gpio_xlate,
 	.set_dir_flags		= sb_gpio_set_dir_flags,
 	.get_dir_flags		= sb_gpio_get_dir_flags,
+#if CONFIG_IS_ENABLED(ACPIGEN)
+	.get_acpi		= sb_gpio_get_acpi,
+#endif
 };
 
 static int sandbox_gpio_ofdata_to_platdata(struct udevice *dev)
@@ -252,6 +323,7 @@ U_BOOT_DRIVER(gpio_sandbox) = {
 	.probe	= gpio_sandbox_probe,
 	.remove	= gpio_sandbox_remove,
 	.ops	= &gpio_sandbox_ops,
+	ACPI_OPS_PTR(&gpio_sandbox_acpi_ops)
 };
 
 /* pincontrol: used only to check GPIO pin configuration (pinmux command) */
@@ -419,6 +491,13 @@ static int sb_pinctrl_get_pin_muxing(struct udevice *dev,
 	return 0;
 }
 
+#if CONFIG_IS_ENABLED(ACPIGEN)
+static int sb_pinctrl_get_name(const struct udevice *dev, char *out_name)
+{
+	return acpi_copy_name(out_name, "PINC");
+}
+#endif
+
 static int sandbox_pinctrl_probe(struct udevice *dev)
 {
 	struct sb_pinctrl_priv *priv = dev_get_priv(dev);
@@ -434,6 +513,12 @@ static struct pinctrl_ops sandbox_pinctrl_gpio_ops = {
 	.get_pin_muxing		= sb_pinctrl_get_pin_muxing,
 };
 
+#if CONFIG_IS_ENABLED(ACPIGEN)
+struct acpi_ops pinctrl_sandbox_acpi_ops = {
+	.get_name	= sb_pinctrl_get_name,
+};
+#endif
+
 static const struct udevice_id sandbox_pinctrl_gpio_match[] = {
 	{ .compatible = "sandbox,pinctrl-gpio" },
 	{ /* sentinel */ }
@@ -447,4 +532,5 @@ U_BOOT_DRIVER(sandbox_pinctrl_gpio) = {
 	.bind = dm_scan_fdt_dev,
 	.probe = sandbox_pinctrl_probe,
 	.priv_auto_alloc_size	= sizeof(struct sb_pinctrl_priv),
+	ACPI_OPS_PTR(&pinctrl_sandbox_acpi_ops)
 };
diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h
index 4f87cd003a..cb9166aeae 100644
--- a/include/acpi/acpi_device.h
+++ b/include/acpi/acpi_device.h
@@ -92,6 +92,96 @@ struct acpi_irq {
 	enum acpi_irq_wake wake;
 };
 
+/**
+ * enum acpi_gpio_type - type of the descriptor
+ *
+ * @ACPI_GPIO_TYPE_INTERRUPT: GpioInterrupt
+ * @ACPI_GPIO_TYPE_IO: GpioIo
+ */
+enum acpi_gpio_type {
+	ACPI_GPIO_TYPE_INTERRUPT,
+	ACPI_GPIO_TYPE_IO,
+};
+
+/**
+ * enum acpi_gpio_pull - pull direction
+ *
+ * @ACPI_GPIO_PULL_DEFAULT: Use default value for pin
+ * @ACPI_GPIO_PULL_UP: Pull up
+ * @ACPI_GPIO_PULL_DOWN: Pull down
+ * @ACPI_GPIO_PULL_NONE: No pullup/pulldown
+ */
+enum acpi_gpio_pull {
+	ACPI_GPIO_PULL_DEFAULT,
+	ACPI_GPIO_PULL_UP,
+	ACPI_GPIO_PULL_DOWN,
+	ACPI_GPIO_PULL_NONE,
+};
+
+/**
+ * enum acpi_gpio_io_restrict - controls input/output of pin
+ *
+ * @ACPI_GPIO_IO_RESTRICT_NONE: no restrictions
+ * @ACPI_GPIO_IO_RESTRICT_INPUT: input only (no output)
+ * @ACPI_GPIO_IO_RESTRICT_OUTPUT: output only (no input)
+ * @ACPI_GPIO_IO_RESTRICT_PRESERVE: preserve settings when driver not active
+ */
+enum acpi_gpio_io_restrict {
+	ACPI_GPIO_IO_RESTRICT_NONE,
+	ACPI_GPIO_IO_RESTRICT_INPUT,
+	ACPI_GPIO_IO_RESTRICT_OUTPUT,
+	ACPI_GPIO_IO_RESTRICT_PRESERVE,
+};
+
+/** enum acpi_gpio_polarity - controls the GPIO polarity */
+enum acpi_gpio_polarity {
+	ACPI_GPIO_ACTIVE_HIGH = 0,
+	ACPI_GPIO_ACTIVE_LOW = 1,
+};
+
+#define ACPI_GPIO_REVISION_ID		1
+#define ACPI_GPIO_MAX_PINS		2
+
+/**
+ * struct acpi_gpio - representation of an ACPI GPIO
+ *
+ * @pin_count: Number of pins represented
+ * @pins: List of pins
+ * @pin0_addr: Address in memory of the control registers for pin 0. This is
+ *   used when generating ACPI tables
+ * @type: GPIO type
+ * @pull: Pullup/pulldown setting
+ * @resource: Resource name for this GPIO controller
+ * For GpioInt:
+ * @interrupt_debounce_timeout: Debounce timeout in units of 10us
+ * @irq: Interrupt
+ *
+ * For GpioIo:
+ * @output_drive_strength: Drive strength in units of 10uA
+ * @io_shared; true if GPIO is shared
+ * @io_restrict: I/O restriction setting
+ * @polarity: GPIO polarity
+ */
+struct acpi_gpio {
+	int pin_count;
+	u16 pins[ACPI_GPIO_MAX_PINS];
+	ulong pin0_addr;
+
+	enum acpi_gpio_type type;
+	enum acpi_gpio_pull pull;
+	char resource[ACPI_PATH_MAX];
+
+	/* GpioInt */
+	u16 interrupt_debounce_timeout;
+	struct acpi_irq irq;
+
+	/* GpioIo */
+	u16 output_drive_strength;
+	bool io_shared;
+	enum acpi_gpio_io_restrict io_restrict;
+	enum acpi_gpio_polarity polarity;
+};
+
 /**
  * acpi_device_path() - Get the full path to an ACPI device
  *
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index e16c2f31d9..a57dd2665c 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -10,6 +10,7 @@
 #include <dm/ofnode.h>
 #include <linux/bitops.h>
 
+struct acpi_gpio;
 struct ofnode_phandle_args;
 
 /*
@@ -329,6 +330,20 @@ struct dm_gpio_ops {
 	 */
 	int (*get_dir_flags)(struct udevice *dev, unsigned int offset,
 			     ulong *flags);
+
+#if CONFIG_IS_ENABLED(ACPIGEN)
+	/**
+	 * get_acpi() - Get the ACPI info for a GPIO
+	 *
+	 * This converts a GPIO to an ACPI structure for adding to the ACPI
+	 * tables.
+	 *
+	 * @desc:	GPIO description to convert
+	 * @gpio:	Output ACPI GPIO information
+	 * @return ACPI pin number or -ve on error
+	 */
+	int (*get_acpi)(const struct gpio_desc *desc, struct acpi_gpio *gpio);
+#endif
 };
 
 /**
@@ -674,4 +689,16 @@ int dm_gpio_get_dir_flags(struct gpio_desc *desc, ulong *flags);
  */
 int gpio_get_number(const struct gpio_desc *desc);
 
+/**
+ * gpio_get_acpi() - Get the ACPI pin for a GPIO
+ *
+ * This converts a GPIO to an ACPI pin number for adding to the ACPI
+ * tables. If the GPIO is invalid, the pin_count and pins[0] are set to 0
+ *
+ * @desc:	GPIO description to convert
+ * @gpio:	Output ACPI GPIO information
+ * @return ACPI pin number or -ve on error
+ */
+int gpio_get_acpi(const struct gpio_desc *desc, struct acpi_gpio *gpio);
+
 #endif	/* _ASM_GENERIC_GPIO_H_ */
diff --git a/test/dm/gpio.c b/test/dm/gpio.c
index f1e14b601f..3db32baa06 100644
--- a/test/dm/gpio.c
+++ b/test/dm/gpio.c
@@ -8,6 +8,7 @@
 #include <dm.h>
 #include <log.h>
 #include <malloc.h>
+#include <acpi/acpi_device.h>
 #include <dm/root.h>
 #include <dm/test.h>
 #include <dm/util.h>
@@ -296,3 +297,64 @@ static int dm_test_gpio_get_dir_flags(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_gpio_get_dir_flags, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test of gpio_get_acpi() */
+static int dm_test_gpio_get_acpi(struct unit_test_state *uts)
+{
+	struct acpi_gpio agpio;
+	struct udevice *dev;
+	struct gpio_desc desc;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("a-test", dev->name);
+	ut_assertok(gpio_request_by_name(dev, "test-gpios", 1, &desc, 0));
+
+	/* See sb_gpio_get_acpi() */
+	ut_assertok(gpio_get_acpi(&desc, &agpio));
+	ut_asserteq(1, agpio.pin_count);
+	ut_asserteq(4, agpio.pins[0]);
+	ut_asserteq(ACPI_GPIO_TYPE_IO, agpio.type);
+	ut_asserteq(ACPI_GPIO_PULL_UP, agpio.pull);
+	ut_asserteq_str("\\_SB.PINC", agpio.resource);
+	ut_asserteq(0, agpio.interrupt_debounce_timeout);
+	ut_asserteq(0, agpio.irq.pin);
+	ut_asserteq(1234, agpio.output_drive_strength);
+	ut_asserteq(true, agpio.io_shared);
+	ut_asserteq(ACPI_GPIO_IO_RESTRICT_INPUT, agpio.io_restrict);
+	ut_asserteq(ACPI_GPIO_ACTIVE_HIGH, agpio.polarity);
+
+	return 0;
+}
+DM_TEST(dm_test_gpio_get_acpi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test of gpio_get_acpi() with an interrupt GPIO */
+static int dm_test_gpio_get_acpi_irq(struct unit_test_state *uts)
+{
+	struct acpi_gpio agpio;
+	struct udevice *dev;
+	struct gpio_desc desc;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("a-test", dev->name);
+	ut_assertok(gpio_request_by_name(dev, "test2-gpios", 2, &desc, 0));
+
+	/* See sb_gpio_get_acpi() */
+	ut_assertok(gpio_get_acpi(&desc, &agpio));
+	ut_asserteq(1, agpio.pin_count);
+	ut_asserteq(6, agpio.pins[0]);
+	ut_asserteq(ACPI_GPIO_TYPE_INTERRUPT, agpio.type);
+	ut_asserteq(ACPI_GPIO_PULL_DOWN, agpio.pull);
+	ut_asserteq_str("\\_SB.PINC", agpio.resource);
+	ut_asserteq(4321, agpio.interrupt_debounce_timeout);
+	ut_asserteq(6, agpio.irq.pin);
+	ut_asserteq(ACPI_IRQ_ACTIVE_BOTH, agpio.irq.polarity);
+	ut_asserteq(ACPI_IRQ_SHARED, agpio.irq.shared);
+	ut_asserteq(true, agpio.irq.wake);
+	ut_asserteq(0, agpio.output_drive_strength);
+	ut_asserteq(false, agpio.io_shared);
+	ut_asserteq(0, agpio.io_restrict);
+	ut_asserteq(ACPI_GPIO_ACTIVE_LOW, agpio.polarity);
+
+	return 0;
+}
+DM_TEST(dm_test_gpio_get_acpi_irq, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/irq.c b/test/dm/irq.c
index 50e505e657..51bae31b0f 100644
--- a/test/dm/irq.c
+++ b/test/dm/irq.c
@@ -87,6 +87,7 @@ static int dm_test_irq_get_acpi(struct unit_test_state *uts)
 	ut_assertok(uclass_first_device_err(UCLASS_TEST_FDT, &dev));
 	ut_assertok(irq_get_by_index(dev, 0, &irq));
 
+	/* see sandbox_get_acpi() */
 	ut_assertok(irq_get_acpi(&irq, &airq));
 	ut_asserteq(3, airq.pin);
 	ut_asserteq(ACPI_IRQ_LEVEL_TRIGGERED, airq.mode);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 08/35] acpi: Support string output
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (6 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 07/35] gpio: Add a method to convert a GPIO to ACPI Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 09/35] acpi: Support generation of GPIO descriptor Simon Glass
                   ` (60 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

Add support for output of strings and streams of bytes.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpigen.h | 19 +++++++++++++++++++
 lib/acpi/acpigen.c     | 14 ++++++++++++++
 test/dm/acpigen.c      | 42 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 75 insertions(+)

diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
index 8809cdb4e1..7365cce738 100644
--- a/include/acpi/acpigen.h
+++ b/include/acpi/acpigen.h
@@ -46,4 +46,23 @@ void acpigen_emit_word(struct acpi_ctx *ctx, uint data);
  */
 void acpigen_emit_dword(struct acpi_ctx *ctx, uint data);
 
+/**
+ * acpigen_emit_stream() - Emit a stream of bytes
+ *
+ * @ctx: ACPI context pointer
+ * @data: Data to output
+ * @size: Size of data in bytes
+ */
+void acpigen_emit_stream(struct acpi_ctx *ctx, const char *data, int size);
+
+/**
+ * acpigen_emit_string() - Emit a string
+ *
+ * Emit a string with a nul terminator
+ *
+ * @ctx: ACPI context pointer
+ * @str: String to output, or NULL for an empty string
+ */
+void acpigen_emit_string(struct acpi_ctx *ctx, const char *str);
+
 #endif
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index 59bd3af0b7..1223f0d1c4 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -36,3 +36,17 @@ void acpigen_emit_dword(struct acpi_ctx *ctx, uint data)
 	acpigen_emit_byte(ctx, (data >> 16) & 0xff);
 	acpigen_emit_byte(ctx, (data >> 24) & 0xff);
 }
+
+void acpigen_emit_stream(struct acpi_ctx *ctx, const char *data, int size)
+{
+	int i;
+
+	for (i = 0; i < size; i++)
+		acpigen_emit_byte(ctx, data[i]);
+}
+
+void acpigen_emit_string(struct acpi_ctx *ctx, const char *str)
+{
+	acpigen_emit_stream(ctx, str, str ? strlen(str) : 0);
+	acpigen_emit_byte(ctx, '\0'); /* NUL */
+}
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index ab1261db9f..77d1a3bba6 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -17,6 +17,9 @@
 #include <dm/test.h>
 #include <test/ut.h>
 
+#define TEST_STRING	"frogmore"
+#define TEST_STREAM2	"\xfa\xde"
+
 static int alloc_context(struct acpi_ctx **ctxp)
 {
 	struct acpi_ctx *ctx;
@@ -66,6 +69,45 @@ static int dm_test_acpi_emit_simple(struct unit_test_state *uts)
 }
 DM_TEST(dm_test_acpi_emit_simple, 0);
 
+/* Test emitting a stream */
+static int dm_test_acpi_emit_stream(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+	acpigen_emit_stream(ctx, TEST_STREAM2, 2);
+	ut_asserteq(2, acpigen_get_current(ctx) - ptr);
+	ut_asserteq((u8)TEST_STREAM2[0], ptr[0]);
+	ut_asserteq((u8)TEST_STREAM2[1], ptr[1]);
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_emit_stream, 0);
+
+/* Test emitting a string */
+static int dm_test_acpi_emit_string(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+	acpigen_emit_string(ctx, TEST_STRING);
+	ut_asserteq(sizeof(TEST_STRING), acpigen_get_current(ctx) - ptr);
+	ut_asserteq_str(TEST_STRING, (char *)ptr);
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_emit_string, 0);
+
 /* Test emitting an interrupt descriptor */
 static int dm_test_acpi_interrupt(struct unit_test_state *uts)
 {
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 09/35] acpi: Support generation of GPIO descriptor
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (7 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 08/35] acpi: Support string output Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 10/35] acpi: Support generation of a GPIO/irq for a device Simon Glass
                   ` (59 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

Add a function to write a GPIO descriptor to the generated ACPI code.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpi_device.h |  22 ++++++
 lib/acpi/acpi_device.c     | 151 +++++++++++++++++++++++++++++++++++++
 test/dm/acpigen.c          |  89 ++++++++++++++++++++++
 3 files changed, 262 insertions(+)

diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h
index cb9166aeae..5f229d79cf 100644
--- a/include/acpi/acpi_device.h
+++ b/include/acpi/acpi_device.h
@@ -12,6 +12,7 @@
 #include <linux/bitops.h>
 
 struct acpi_ctx;
+struct gpio_desc;
 struct irq;
 struct udevice;
 
@@ -233,4 +234,25 @@ enum acpi_dev_status acpi_device_status(const struct udevice *dev);
 int acpi_device_write_interrupt_irq(struct acpi_ctx *ctx,
 				    const struct irq *req_irq);
 
+/**
+ * acpi_device_write_gpio() - Write GpioIo() or GpioInt() descriptor
+ *
+ * @gpio: GPIO information to write
+ * @return 0 if OK, -ve on error
+ */
+int acpi_device_write_gpio(struct acpi_ctx *ctx, const struct acpi_gpio *gpio);
+
+/**
+ * acpi_device_write_gpio_desc() - Write a GPIO to ACPI
+ *
+ * This creates a GPIO descriptor for a GPIO, including information ACPI needs
+ * to use it. The type is always ACPI_GPIO_TYPE_IO.
+ *
+ * @ctx: ACPI context pointer
+ * @desc: GPIO to write
+ * @return 0 if OK, -ve on error
+ */
+int acpi_device_write_gpio_desc(struct acpi_ctx *ctx,
+				const struct gpio_desc *desc);
+
 #endif
diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
index 6b2fb7e47e..4c5bfdb9a2 100644
--- a/lib/acpi/acpi_device.c
+++ b/lib/acpi/acpi_device.c
@@ -12,6 +12,7 @@
 #include <log.h>
 #include <acpi/acpi_device.h>
 #include <acpi/acpigen.h>
+#include <asm-generic/gpio.h>
 #include <dm/acpi.h>
 
 /**
@@ -204,3 +205,153 @@ int acpi_device_write_interrupt_irq(struct acpi_ctx *ctx,
 
 	return 0;
 }
+
+/* ACPI 6.3 section 6.4.3.8.1 - GPIO Interrupt or I/O */
+int acpi_device_write_gpio(struct acpi_ctx *ctx, const struct acpi_gpio *gpio)
+{
+	void *start, *desc_length;
+	void *pin_table_offset, *vendor_data_offset, *resource_offset;
+	u16 flags = 0;
+	int pin;
+
+	if (gpio->type > ACPI_GPIO_TYPE_IO)
+		return -EINVAL;
+
+	start = acpigen_get_current(ctx);
+
+	/* Byte 0: Descriptor Type */
+	acpigen_emit_byte(ctx, ACPI_DESCRIPTOR_GPIO);
+
+	/* Byte 1-2: Length (fill in later) */
+	desc_length = acpi_device_write_zero_len(ctx);
+
+	/* Byte 3: Revision ID */
+	acpigen_emit_byte(ctx, ACPI_GPIO_REVISION_ID);
+
+	/* Byte 4: GpioIo or GpioInt */
+	acpigen_emit_byte(ctx, gpio->type);
+
+	/*
+	 * Byte 5-6: General Flags
+	 *   [15:1]: 0 => Reserved
+	 *      [0]: 1 => ResourceConsumer
+	 */
+	acpigen_emit_word(ctx, 1 << 0);
+
+	switch (gpio->type) {
+	case ACPI_GPIO_TYPE_INTERRUPT:
+		/*
+		 * Byte 7-8: GPIO Interrupt Flags
+		 *   [15:5]: 0 => Reserved
+		 *      [4]: Wake     (0=NO_WAKE   1=WAKE)
+		 *      [3]: Sharing  (0=EXCLUSIVE 1=SHARED)
+		 *    [2:1]: Polarity (0=HIGH      1=LOW     2=BOTH)
+		 *      [0]: Mode     (0=LEVEL     1=EDGE)
+		 */
+		if (gpio->irq.mode == ACPI_IRQ_EDGE_TRIGGERED)
+			flags |= 1 << 0;
+		if (gpio->irq.shared == ACPI_IRQ_SHARED)
+			flags |= 1 << 3;
+		if (gpio->irq.wake == ACPI_IRQ_WAKE)
+			flags |= 1 << 4;
+
+		switch (gpio->irq.polarity) {
+		case ACPI_IRQ_ACTIVE_HIGH:
+			flags |= 0 << 1;
+			break;
+		case ACPI_IRQ_ACTIVE_LOW:
+			flags |= 1 << 1;
+			break;
+		case ACPI_IRQ_ACTIVE_BOTH:
+			flags |= 2 << 1;
+			break;
+		}
+		break;
+
+	case ACPI_GPIO_TYPE_IO:
+		/*
+		 * Byte 7-8: GPIO IO Flags
+		 *   [15:4]: 0 => Reserved
+		 *      [3]: Sharing  (0=EXCLUSIVE 1=SHARED)
+		 *      [2]: 0 => Reserved
+		 *    [1:0]: IO Restriction
+		 *           0 => IoRestrictionNone
+		 *           1 => IoRestrictionInputOnly
+		 *           2 => IoRestrictionOutputOnly
+		 *           3 => IoRestrictionNoneAndPreserve
+		 */
+		flags |= gpio->io_restrict & 3;
+		if (gpio->io_shared)
+			flags |= 1 << 3;
+		break;
+	}
+	acpigen_emit_word(ctx, flags);
+
+	/*
+	 * Byte 9: Pin Configuration
+	 *  0x01 => Default (no configuration applied)
+	 *  0x02 => Pull-up
+	 *  0x03 => Pull-down
+	 *  0x04-0x7F => Reserved
+	 *  0x80-0xff => Vendor defined
+	 */
+	acpigen_emit_byte(ctx, gpio->pull);
+
+	/* Byte 10-11: Output Drive Strength in 1/100 mA */
+	acpigen_emit_word(ctx, gpio->output_drive_strength);
+
+	/* Byte 12-13: Debounce Timeout in 1/100 ms */
+	acpigen_emit_word(ctx, gpio->interrupt_debounce_timeout);
+
+	/* Byte 14-15: Pin Table Offset, relative to start */
+	pin_table_offset = acpi_device_write_zero_len(ctx);
+
+	/* Byte 16: Reserved */
+	acpigen_emit_byte(ctx, 0);
+
+	/* Byte 17-18: Resource Source Name Offset, relative to start */
+	resource_offset = acpi_device_write_zero_len(ctx);
+
+	/* Byte 19-20: Vendor Data Offset, relative to start */
+	vendor_data_offset = acpi_device_write_zero_len(ctx);
+
+	/* Byte 21-22: Vendor Data Length */
+	acpigen_emit_word(ctx, 0);
+
+	/* Fill in Pin Table Offset */
+	acpi_device_fill_from_len(ctx, pin_table_offset, start);
+
+	/* Pin Table, one word for each pin */
+	for (pin = 0; pin < gpio->pin_count; pin++)
+		acpigen_emit_word(ctx, gpio->pins[pin]);
+
+	/* Fill in Resource Source Name Offset */
+	acpi_device_fill_from_len(ctx, resource_offset, start);
+
+	/* Resource Source Name String */
+	acpigen_emit_string(ctx, gpio->resource);
+
+	/* Fill in Vendor Data Offset */
+	acpi_device_fill_from_len(ctx, vendor_data_offset, start);
+
+	/* Fill in GPIO Descriptor Length (account for len word) */
+	acpi_device_fill_len(ctx, desc_length);
+
+	return 0;
+}
+
+int acpi_device_write_gpio_desc(struct acpi_ctx *ctx,
+				const struct gpio_desc *desc)
+{
+	struct acpi_gpio gpio;
+	int ret;
+
+	ret = gpio_get_acpi(desc, &gpio);
+	if (ret)
+		return log_msg_ret("desc", ret);
+	ret = acpi_device_write_gpio(ctx, &gpio);
+	if (ret)
+		return log_msg_ret("gpio", ret);
+
+	return 0;
+}
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index 77d1a3bba6..73fe6c9f4d 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -12,6 +12,7 @@
 #include <malloc.h>
 #include <acpi/acpigen.h>
 #include <acpi/acpi_device.h>
+#include <asm/gpio.h>
 #include <asm/unaligned.h>
 #include <dm/acpi.h>
 #include <dm/test.h>
@@ -136,3 +137,91 @@ static int dm_test_acpi_interrupt(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_interrupt, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test emitting a GPIO descriptor */
+static int dm_test_acpi_gpio(struct unit_test_state *uts)
+{
+	struct gpio_desc desc;
+	struct acpi_ctx *ctx;
+	struct udevice *dev;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("a-test", dev->name);
+	ut_assertok(gpio_request_by_name(dev, "test-gpios", 1, &desc, 0));
+
+	ut_assertok(acpi_device_write_gpio_desc(ctx, &desc));
+	ut_asserteq(35, acpigen_get_current(ctx) - ptr);
+	ut_asserteq(ACPI_DESCRIPTOR_GPIO, ptr[0]);
+	ut_asserteq(32, get_unaligned((u16 *)(ptr + 1)));
+	ut_asserteq(ACPI_GPIO_REVISION_ID, ptr[3]);
+	ut_asserteq(ACPI_GPIO_TYPE_IO, ptr[4]);
+	ut_asserteq(1, get_unaligned((u16 *)(ptr + 5)));
+	ut_asserteq(9, get_unaligned((u16 *)(ptr + 7)));
+	ut_asserteq(ACPI_GPIO_PULL_UP, ptr[9]);
+	ut_asserteq(1234, get_unaligned((u16 *)(ptr + 10)));
+	ut_asserteq(0, get_unaligned((u16 *)(ptr + 12)));
+	ut_asserteq(23, get_unaligned((u16 *)(ptr + 14)));
+	ut_asserteq(0, ptr[16]);
+	ut_asserteq(25, get_unaligned((u16 *)(ptr + 17)));
+	ut_asserteq(35, get_unaligned((u16 *)(ptr + 19)));
+	ut_asserteq(0, get_unaligned((u16 *)(ptr + 21)));
+
+	/* pin0 */
+	ut_asserteq(4, get_unaligned((u16 *)(ptr + 23)));
+
+	ut_asserteq_str("\\_SB.PINC", (char *)ptr + 25);
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_gpio, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test emitting a GPIO descriptor with an interrupt */
+static int dm_test_acpi_gpio_irq(struct unit_test_state *uts)
+{
+	struct gpio_desc desc;
+	struct acpi_ctx *ctx;
+	struct udevice *dev;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("a-test", dev->name);
+	ut_assertok(gpio_request_by_name(dev, "test2-gpios", 2, &desc, 0));
+
+	ut_assertok(acpi_device_write_gpio_desc(ctx, &desc));
+	ut_asserteq(35, acpigen_get_current(ctx) - ptr);
+	ut_asserteq(ACPI_DESCRIPTOR_GPIO, ptr[0]);
+	ut_asserteq(32, get_unaligned((u16 *)(ptr + 1)));
+	ut_asserteq(ACPI_GPIO_REVISION_ID, ptr[3]);
+	ut_asserteq(ACPI_GPIO_TYPE_INTERRUPT, ptr[4]);
+	ut_asserteq(1, get_unaligned((u16 *)(ptr + 5)));
+	ut_asserteq(29, get_unaligned((u16 *)(ptr + 7)));
+	ut_asserteq(ACPI_GPIO_PULL_DOWN, ptr[9]);
+	ut_asserteq(0, get_unaligned((u16 *)(ptr + 10)));
+	ut_asserteq(4321, get_unaligned((u16 *)(ptr + 12)));
+	ut_asserteq(23, get_unaligned((u16 *)(ptr + 14)));
+	ut_asserteq(0, ptr[16]);
+	ut_asserteq(25, get_unaligned((u16 *)(ptr + 17)));
+	ut_asserteq(35, get_unaligned((u16 *)(ptr + 19)));
+	ut_asserteq(0, get_unaligned((u16 *)(ptr + 21)));
+
+	/* pin0 */
+	ut_asserteq(6, get_unaligned((u16 *)(ptr + 23)));
+
+	ut_asserteq_str("\\_SB.PINC", (char *)ptr + 25);
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_gpio_irq, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 10/35] acpi: Support generation of a GPIO/irq for a device
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (8 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 09/35] acpi: Support generation of GPIO descriptor Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 11/35] acpi: Support generation of I2C descriptor Simon Glass
                   ` (58 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

Some devices use interrupts but some use GPIOs. Since these are fully
specified in the device tree we can automatically produce the correct ACPI
descriptor for a device.

Add a function to handle this.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpi_device.h | 15 ++++++++++++++
 lib/acpi/acpi_device.c     | 26 ++++++++++++++++++++++++
 test/dm/acpigen.c          | 41 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+)

diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h
index 5f229d79cf..70c151d150 100644
--- a/include/acpi/acpi_device.h
+++ b/include/acpi/acpi_device.h
@@ -255,4 +255,19 @@ int acpi_device_write_gpio(struct acpi_ctx *ctx, const struct acpi_gpio *gpio);
 int acpi_device_write_gpio_desc(struct acpi_ctx *ctx,
 				const struct gpio_desc *desc);
 
+/**
+ * acpi_device_write_interrupt_or_gpio() - Write interrupt or GPIO to ACPI
+ *
+ * This reads an interrupt from the device tree "interrupts-extended" property,
+ * if available. If not it reads the first GPIO with the name @prop.
+ *
+ * If an interrupt is found, an ACPI interrupt descriptor is written to the ACPI
+ * output. If not, but an GPIO is found, a GPIO descriptor is written.
+ *
+ * @return 0 if OK, -ve if neither an interrupt nor a GPIO could be found, or
+ * some other error occurred
+ */
+int acpi_device_write_interrupt_or_gpio(struct acpi_ctx *ctx,
+					struct udevice *dev, const char *prop);
+
 #endif
diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
index 4c5bfdb9a2..423b91cfd2 100644
--- a/lib/acpi/acpi_device.c
+++ b/lib/acpi/acpi_device.c
@@ -355,3 +355,29 @@ int acpi_device_write_gpio_desc(struct acpi_ctx *ctx,
 
 	return 0;
 }
+
+int acpi_device_write_interrupt_or_gpio(struct acpi_ctx *ctx,
+					struct udevice *dev, const char *prop)
+{
+	struct irq req_irq;
+	int ret;
+
+	ret = irq_get_by_index(dev, 0, &req_irq);
+	if (!ret) {
+		ret = acpi_device_write_interrupt_irq(ctx, &req_irq);
+		if (ret)
+			return log_msg_ret("irq", ret);
+	} else {
+		struct gpio_desc req_gpio;
+
+		ret = gpio_request_by_name(dev, prop, 0, &req_gpio,
+					   GPIOD_IS_IN);
+		if (ret)
+			return log_msg_ret("no gpio", ret);
+		ret = acpi_device_write_gpio_desc(ctx, &req_gpio);
+		if (ret)
+			return log_msg_ret("gpio", ret);
+	}
+
+	return 0;
+}
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index 73fe6c9f4d..6aefa6845d 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -16,6 +16,7 @@
 #include <asm/unaligned.h>
 #include <dm/acpi.h>
 #include <dm/test.h>
+#include <dm/uclass-internal.h>
 #include <test/ut.h>
 
 #define TEST_STRING	"frogmore"
@@ -225,3 +226,43 @@ static int dm_test_acpi_gpio_irq(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_gpio_irq, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test emitting either a GPIO or interrupt descriptor */
+static int dm_test_acpi_interrupt_or_gpio(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	struct udevice *dev;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+
+	/* This should produce an interrupt, even though it also has a GPIO */
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("a-test", dev->name);
+	ut_assertok(acpi_device_write_interrupt_or_gpio(ctx, dev,
+							"test2-gpios"));
+	ut_asserteq(ACPI_DESCRIPTOR_INTERRUPT, ptr[0]);
+
+	/* This has no interrupt so should produce a GPIO */
+	ptr = ctx->current;
+	ut_assertok(uclass_find_first_device(UCLASS_PANEL_BACKLIGHT, &dev));
+	ut_assertok(acpi_device_write_interrupt_or_gpio(ctx, dev,
+							"enable-gpios"));
+	ut_asserteq(ACPI_DESCRIPTOR_GPIO, ptr[0]);
+
+	/* This one has neither */
+	ptr = acpigen_get_current(ctx);
+	ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 3, &dev));
+	ut_asserteq_str("b-test", dev->name);
+	ut_asserteq(-ENOENT,
+		    acpi_device_write_interrupt_or_gpio(ctx, dev,
+							"enable-gpios"));
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_interrupt_or_gpio,
+	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 11/35] acpi: Support generation of I2C descriptor
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (9 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 10/35] acpi: Support generation of a GPIO/irq for a device Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 12/35] acpi: Support generation of SPI descriptor Simon Glass
                   ` (57 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

Add a function to write a GPIO descriptor to the generated ACPI code.

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

Changes in v2:
- Fix memset of I2C descriptor

Changes in v1: None

 drivers/i2c/sandbox_i2c.c  |  11 ++++
 drivers/rtc/sandbox_rtc.c  |  13 +++++
 include/acpi/acpi_device.h |  36 +++++++++++++
 lib/acpi/acpi_device.c     | 103 +++++++++++++++++++++++++++++++++++++
 test/dm/acpigen.c          |  32 ++++++++++++
 5 files changed, 195 insertions(+)

diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c
index f4ae2397a0..125026da90 100644
--- a/drivers/i2c/sandbox_i2c.c
+++ b/drivers/i2c/sandbox_i2c.c
@@ -11,6 +11,7 @@
 #include <i2c.h>
 #include <log.h>
 #include <asm/test.h>
+#include <dm/acpi.h>
 #include <dm/lists.h>
 #include <dm/device-internal.h>
 
@@ -83,6 +84,15 @@ 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,
 };
@@ -98,4 +108,5 @@ 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/rtc/sandbox_rtc.c b/drivers/rtc/sandbox_rtc.c
index b08d758a74..f2906c3397 100644
--- a/drivers/rtc/sandbox_rtc.c
+++ b/drivers/rtc/sandbox_rtc.c
@@ -9,6 +9,7 @@
 #include <i2c.h>
 #include <rtc.h>
 #include <asm/rtc.h>
+#include <dm/acpi.h>
 
 #define REG_COUNT 0x80
 
@@ -84,6 +85,17 @@ static int sandbox_rtc_write8(struct udevice *dev, unsigned int reg, int val)
 	return dm_i2c_reg_write(dev, reg, val);
 }
 
+#if CONFIG_IS_ENABLED(ACPIGEN)
+static int sandbox_rtc_get_name(const struct udevice *dev, char *out_name)
+{
+	return acpi_copy_name(out_name, "RTCC");
+}
+
+struct acpi_ops sandbox_rtc_acpi_ops = {
+	.get_name	= sandbox_rtc_get_name,
+};
+#endif
+
 static const struct rtc_ops sandbox_rtc_ops = {
 	.get = sandbox_rtc_get,
 	.set = sandbox_rtc_set,
@@ -102,4 +114,5 @@ U_BOOT_DRIVER(rtc_sandbox) = {
 	.id	= UCLASS_RTC,
 	.of_match = sandbox_rtc_ids,
 	.ops	= &sandbox_rtc_ops,
+	ACPI_OPS_PTR(&sandbox_rtc_acpi_ops)
 };
diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h
index 70c151d150..cf1ac695a7 100644
--- a/include/acpi/acpi_device.h
+++ b/include/acpi/acpi_device.h
@@ -9,6 +9,7 @@
 #ifndef __ACPI_DEVICE_H
 #define __ACPI_DEVICE_H
 
+#include <i2c.h>
 #include <linux/bitops.h>
 
 struct acpi_ctx;
@@ -183,6 +184,29 @@ struct acpi_gpio {
 	enum acpi_gpio_polarity polarity;
 };
 
+/* ACPI Descriptors for Serial Bus interfaces */
+#define ACPI_SERIAL_BUS_TYPE_I2C		1
+#define ACPI_SERIAL_BUS_TYPE_SPI		2
+#define ACPI_I2C_SERIAL_BUS_REVISION_ID		1 /* TODO: upgrade to 2 */
+#define ACPI_I2C_TYPE_SPECIFIC_REVISION_ID	1
+#define ACPI_SPI_SERIAL_BUS_REVISION_ID		1
+#define ACPI_SPI_TYPE_SPECIFIC_REVISION_ID	1
+
+/**
+ * struct acpi_i2c - representation of an ACPI I2C device
+ *
+ * @address: 7-bit or 10-bit I2C address
+ * @mode_10bit: Which address size is used
+ * @speed: Bus speed in Hz
+ * @resource: Resource name for the I2C controller
+ */
+struct acpi_i2c {
+	u16 address;
+	enum i2c_address_mode mode_10bit;
+	enum i2c_speed_rate speed;
+	const char *resource;
+};
+
 /**
  * acpi_device_path() - Get the full path to an ACPI device
  *
@@ -270,4 +294,16 @@ int acpi_device_write_gpio_desc(struct acpi_ctx *ctx,
 int acpi_device_write_interrupt_or_gpio(struct acpi_ctx *ctx,
 					struct udevice *dev, const char *prop);
 
+/**
+ * acpi_device_write_i2c_dev() - Write an I2C device to ACPI
+ *
+ * This creates a I2cSerialBus descriptor for an I2C device, including
+ * information ACPI needs to use it.
+ *
+ * @ctx: ACPI context pointer
+ * @dev: I2C device to write
+ * @return 0 if OK, -ve on error
+ */
+int acpi_device_write_i2c_dev(struct acpi_ctx *ctx, const struct udevice *dev);
+
 #endif
diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
index 423b91cfd2..0136a0bdc9 100644
--- a/lib/acpi/acpi_device.c
+++ b/lib/acpi/acpi_device.c
@@ -381,3 +381,106 @@ int acpi_device_write_interrupt_or_gpio(struct acpi_ctx *ctx,
 
 	return 0;
 }
+
+/* ACPI 6.3 section 6.4.3.8.2.1 - I2cSerialBus() */
+static void acpi_device_write_i2c(struct acpi_ctx *ctx,
+				  const struct acpi_i2c *i2c)
+{
+	void *desc_length, *type_length;
+
+	/* Byte 0: Descriptor Type */
+	acpigen_emit_byte(ctx, ACPI_DESCRIPTOR_SERIAL_BUS);
+
+	/* Byte 1+2: Length (filled in later) */
+	desc_length = acpi_device_write_zero_len(ctx);
+
+	/* Byte 3: Revision ID */
+	acpigen_emit_byte(ctx, ACPI_I2C_SERIAL_BUS_REVISION_ID);
+
+	/* Byte 4: Resource Source Index is Reserved */
+	acpigen_emit_byte(ctx, 0);
+
+	/* Byte 5: Serial Bus Type is I2C */
+	acpigen_emit_byte(ctx, ACPI_SERIAL_BUS_TYPE_I2C);
+
+	/*
+	 * Byte 6: Flags
+	 *  [7:2]: 0 => Reserved
+	 *    [1]: 1 => ResourceConsumer
+	 *    [0]: 0 => ControllerInitiated
+	 */
+	acpigen_emit_byte(ctx, 1 << 1);
+
+	/*
+	 * Byte 7-8: Type Specific Flags
+	 *   [15:1]: 0 => Reserved
+	 *      [0]: 0 => 7bit, 1 => 10bit
+	 */
+	acpigen_emit_word(ctx, i2c->mode_10bit);
+
+	/* Byte 9: Type Specific Revision ID */
+	acpigen_emit_byte(ctx, ACPI_I2C_TYPE_SPECIFIC_REVISION_ID);
+
+	/* Byte 10-11: I2C Type Data Length */
+	type_length = acpi_device_write_zero_len(ctx);
+
+	/* Byte 12-15: I2C Bus Speed */
+	acpigen_emit_dword(ctx, i2c->speed);
+
+	/* Byte 16-17: I2C Slave Address */
+	acpigen_emit_word(ctx, i2c->address);
+
+	/* Fill in Type Data Length */
+	acpi_device_fill_len(ctx, type_length);
+
+	/* Byte 18+: ResourceSource */
+	acpigen_emit_string(ctx, i2c->resource);
+
+	/* Fill in I2C Descriptor Length */
+	acpi_device_fill_len(ctx, desc_length);
+}
+
+/**
+ * acpi_device_set_i2c() - Set up an ACPI I2C struct from a device
+ *
+ * @dev: I2C device to convert
+ * @i2c: Place to put the new structure
+ * @scope: Scope of the I2C device (this is the controller path)
+ * @return 0 (always)
+ */
+static int acpi_device_set_i2c(const struct udevice *dev, struct acpi_i2c *i2c,
+			       const char *scope)
+{
+	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
+	struct udevice *bus = dev_get_parent(dev);
+
+	memset(i2c, '\0', sizeof(*i2c));
+	i2c->address = chip->chip_addr;
+	i2c->mode_10bit = 0;
+
+	/*
+	 * i2c_bus->speed_hz is set if this device is probed, but if not we
+	 * must use the device tree
+	 */
+	i2c->speed = dev_read_u32_default(bus, "clock-frequency", 100000);
+	i2c->resource = scope;
+
+	return 0;
+}
+
+int acpi_device_write_i2c_dev(struct acpi_ctx *ctx, const struct udevice *dev)
+{
+	char scope[ACPI_PATH_MAX];
+	struct acpi_i2c i2c;
+	int ret;
+
+	ret = acpi_device_scope(dev, scope, sizeof(scope));
+	if (ret)
+		return log_msg_ret("scope", ret);
+	ret = acpi_device_set_i2c(dev, &i2c, scope);
+	if (ret)
+		return log_msg_ret("set", ret);
+	acpi_device_write_i2c(ctx, &i2c);
+
+	return 0;
+}
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index 6aefa6845d..de9996ab35 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -266,3 +266,35 @@ static int dm_test_acpi_interrupt_or_gpio(struct unit_test_state *uts)
 }
 DM_TEST(dm_test_acpi_interrupt_or_gpio,
 	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test emitting an I2C descriptor */
+static int dm_test_acpi_i2c(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	struct udevice *dev;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+
+	ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
+	ut_assertok(acpi_device_write_i2c_dev(ctx, dev));
+	ut_asserteq(28, acpigen_get_current(ctx) - ptr);
+	ut_asserteq(ACPI_DESCRIPTOR_SERIAL_BUS, ptr[0]);
+	ut_asserteq(25, get_unaligned((u16 *)(ptr + 1)));
+	ut_asserteq(ACPI_I2C_SERIAL_BUS_REVISION_ID, ptr[3]);
+	ut_asserteq(0, ptr[4]);
+	ut_asserteq(ACPI_SERIAL_BUS_TYPE_I2C, ptr[5]);
+	ut_asserteq(0, get_unaligned((u16 *)(ptr + 7)));
+	ut_asserteq(ACPI_I2C_TYPE_SPECIFIC_REVISION_ID, ptr[9]);
+	ut_asserteq(6, get_unaligned((u16 *)(ptr + 10)));
+	ut_asserteq(100000, get_unaligned((u32 *)(ptr + 12)));
+	ut_asserteq(0x43, get_unaligned((u16 *)(ptr + 16)));
+	ut_asserteq_str("\\_SB.SI2C", (char *)ptr + 18);
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_i2c, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 12/35] acpi: Support generation of SPI descriptor
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (10 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 11/35] acpi: Support generation of I2C descriptor Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 13/35] acpigen: Support writing a length Simon Glass
                   ` (56 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

Add a function to write a SPI descriptor to the generated ACPI code.

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

Changes in v2:
- Fix memset of SPI descriptor

Changes in v1: None

 drivers/spi/sandbox_spi.c  |  11 ++++
 include/acpi/acpi_device.h |  36 +++++++++++
 include/spi.h              |   4 +-
 lib/acpi/acpi_device.c     | 121 +++++++++++++++++++++++++++++++++++++
 test/dm/acpigen.c          |  36 +++++++++++
 5 files changed, 206 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/sandbox_spi.c b/drivers/spi/sandbox_spi.c
index b0a46c8868..4264acc953 100644
--- a/drivers/spi/sandbox_spi.c
+++ b/drivers/spi/sandbox_spi.c
@@ -21,6 +21,7 @@
 #include <linux/errno.h>
 #include <asm/spi.h>
 #include <asm/state.h>
+#include <dm/acpi.h>
 #include <dm/device-internal.h>
 
 #ifndef CONFIG_SPI_IDLE_VAL
@@ -133,6 +134,15 @@ 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,
@@ -151,4 +161,5 @@ U_BOOT_DRIVER(spi_sandbox) = {
 	.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 cf1ac695a7..d43ab4ba36 100644
--- a/include/acpi/acpi_device.h
+++ b/include/acpi/acpi_device.h
@@ -10,6 +10,7 @@
 #define __ACPI_DEVICE_H
 
 #include <i2c.h>
+#include <spi.h>
 #include <linux/bitops.h>
 
 struct acpi_ctx;
@@ -207,6 +208,29 @@ struct acpi_i2c {
 	const char *resource;
 };
 
+/**
+ * struct acpi_spi - representation of an ACPI SPI device
+ *
+ * @device_select: Chip select used by this device (typically 0)
+ * @device_select_polarity: Polarity for the device
+ * @wire_mode: Number of wires used for SPI
+ * @speed: Bus speed in Hz
+ * @data_bit_length: Word length for SPI (typically 8)
+ * @clock_phase: Clock phase to capture data
+ * @clock_polarity: Bus polarity
+ * @resource: Resource name for the SPI controller
+ */
+struct acpi_spi {
+	u16 device_select;
+	enum spi_polarity device_select_polarity;
+	enum spi_wire_mode wire_mode;
+	unsigned int speed;
+	u8 data_bit_length;
+	enum spi_clock_phase clock_phase;
+	enum spi_polarity clock_polarity;
+	const char *resource;
+};
+
 /**
  * acpi_device_path() - Get the full path to an ACPI device
  *
@@ -306,4 +330,16 @@ int acpi_device_write_interrupt_or_gpio(struct acpi_ctx *ctx,
  */
 int acpi_device_write_i2c_dev(struct acpi_ctx *ctx, const struct udevice *dev);
 
+/**
+ * acpi_device_write_spi_dev() - Write a SPI device to ACPI
+ *
+ * This writes a serial bus descriptor for the SPI device so that ACPI can use
+ * it
+ *
+ * @ctx: ACPI context pointer
+ * @dev: SPI device to write
+ * @return 0 if OK, -ve on error
+ */
+int acpi_device_write_spi_dev(struct acpi_ctx *ctx, const struct udevice *dev);
+
 #endif
diff --git a/include/spi.h b/include/spi.h
index 5cc6d6e008..f34533f54e 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -13,8 +13,8 @@
 #include <linux/bitops.h>
 
 /* SPI mode flags */
-#define SPI_CPHA	BIT(0)			/* clock phase */
-#define SPI_CPOL	BIT(1)			/* clock polarity */
+#define SPI_CPHA	BIT(0)	/* clock phase (1 = SPI_CLOCK_PHASE_SECOND) */
+#define SPI_CPOL	BIT(1)	/* clock polarity (1 = SPI_POLARITY_HIGH) */
 #define SPI_MODE_0	(0|0)			/* (original MicroWire) */
 #define SPI_MODE_1	(0|SPI_CPHA)
 #define SPI_MODE_2	(SPI_CPOL|0)
diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
index 0136a0bdc9..3d5dc746f8 100644
--- a/lib/acpi/acpi_device.c
+++ b/lib/acpi/acpi_device.c
@@ -484,3 +484,124 @@ int acpi_device_write_i2c_dev(struct acpi_ctx *ctx, const struct udevice *dev)
 
 	return 0;
 }
+
+#ifdef CONFIG_SPI
+/* ACPI 6.1 section 6.4.3.8.2.2 - SpiSerialBus() */
+void acpi_device_write_spi(struct acpi_ctx *ctx, const struct acpi_spi *spi)
+{
+	void *desc_length, *type_length;
+	u16 flags = 0;
+
+	/* Byte 0: Descriptor Type */
+	acpigen_emit_byte(ctx, ACPI_DESCRIPTOR_SERIAL_BUS);
+
+	/* Byte 1+2: Length (filled in later) */
+	desc_length = acpi_device_write_zero_len(ctx);
+
+	/* Byte 3: Revision ID */
+	acpigen_emit_byte(ctx, ACPI_SPI_SERIAL_BUS_REVISION_ID);
+
+	/* Byte 4: Resource Source Index is Reserved */
+	acpigen_emit_byte(ctx, 0);
+
+	/* Byte 5: Serial Bus Type is SPI */
+	acpigen_emit_byte(ctx, ACPI_SERIAL_BUS_TYPE_SPI);
+
+	/*
+	 * Byte 6: Flags
+	 *  [7:2]: 0 => Reserved
+	 *    [1]: 1 => ResourceConsumer
+	 *    [0]: 0 => ControllerInitiated
+	 */
+	acpigen_emit_byte(ctx, 1 << 1);
+
+	/*
+	 * Byte 7-8: Type Specific Flags
+	 *   [15:2]: 0 => Reserveda
+	 *      [1]: 0 => ActiveLow, 1 => ActiveHigh
+	 *      [0]: 0 => FourWire, 1 => ThreeWire
+	 */
+	if (spi->wire_mode == SPI_3_WIRE_MODE)
+		flags |= 1 << 0;
+	if (spi->device_select_polarity == SPI_POLARITY_HIGH)
+		flags |= 1 << 1;
+	acpigen_emit_word(ctx, flags);
+
+	/* Byte 9: Type Specific Revision ID */
+	acpigen_emit_byte(ctx, ACPI_SPI_TYPE_SPECIFIC_REVISION_ID);
+
+	/* Byte 10-11: SPI Type Data Length */
+	type_length = acpi_device_write_zero_len(ctx);
+
+	/* Byte 12-15: Connection Speed */
+	acpigen_emit_dword(ctx, spi->speed);
+
+	/* Byte 16: Data Bit Length */
+	acpigen_emit_byte(ctx, spi->data_bit_length);
+
+	/* Byte 17: Clock Phase */
+	acpigen_emit_byte(ctx, spi->clock_phase);
+
+	/* Byte 18: Clock Polarity */
+	acpigen_emit_byte(ctx, spi->clock_polarity);
+
+	/* Byte 19-20: Device Selection */
+	acpigen_emit_word(ctx, spi->device_select);
+
+	/* Fill in Type Data Length */
+	acpi_device_fill_len(ctx, type_length);
+
+	/* Byte 21+: ResourceSource String */
+	acpigen_emit_string(ctx, spi->resource);
+
+	/* Fill in SPI Descriptor Length */
+	acpi_device_fill_len(ctx, desc_length);
+}
+
+/**
+ * acpi_device_set_spi() - Set up an ACPI SPI struct from a device
+ *
+ * @dev: SPI device to convert
+ * @spi: Place to put the new structure
+ * @scope: Scope of the SPI device (this is the controller path)
+ * @return 0 (always)
+ */
+static int acpi_device_set_spi(const struct udevice *dev, struct acpi_spi *spi,
+			       const char *scope)
+{
+	struct dm_spi_slave_platdata *plat;
+	struct spi_slave *slave = dev_get_parent_priv(dev);
+
+	plat = dev_get_parent_platdata(slave->dev);
+	memset(spi, '\0', sizeof(*spi));
+	spi->device_select = plat->cs;
+	spi->device_select_polarity = SPI_POLARITY_LOW;
+	spi->wire_mode = SPI_4_WIRE_MODE;
+	spi->speed = plat->max_hz;
+	spi->data_bit_length = slave->wordlen;
+	spi->clock_phase = plat->mode & SPI_CPHA ?
+		 SPI_CLOCK_PHASE_SECOND : SPI_CLOCK_PHASE_FIRST;
+	spi->clock_polarity = plat->mode & SPI_CPOL ?
+		 SPI_POLARITY_HIGH : SPI_POLARITY_LOW;
+	spi->resource = scope;
+
+	return 0;
+}
+
+int acpi_device_write_spi_dev(struct acpi_ctx *ctx, const struct udevice *dev)
+{
+	char scope[ACPI_PATH_MAX];
+	struct acpi_spi spi;
+	int ret;
+
+	ret = acpi_device_scope(dev, scope, sizeof(scope));
+	if (ret)
+		return log_msg_ret("scope", ret);
+	ret = acpi_device_set_spi(dev, &spi, scope);
+	if (ret)
+		return log_msg_ret("set", ret);
+	acpi_device_write_spi(ctx, &spi);
+
+	return 0;
+}
+#endif /* CONFIG_SPI */
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index de9996ab35..3d580a23a5 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -298,3 +298,39 @@ static int dm_test_acpi_i2c(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_i2c, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test emitting a SPI descriptor */
+static int dm_test_acpi_spi(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	struct udevice *dev;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+
+	ut_assertok(uclass_first_device_err(UCLASS_SPI_FLASH, &dev));
+	ut_assertok(acpi_device_write_spi_dev(ctx, dev));
+	ut_asserteq(31, acpigen_get_current(ctx) - ptr);
+	ut_asserteq(ACPI_DESCRIPTOR_SERIAL_BUS, ptr[0]);
+	ut_asserteq(28, get_unaligned((u16 *)(ptr + 1)));
+	ut_asserteq(ACPI_SPI_SERIAL_BUS_REVISION_ID, ptr[3]);
+	ut_asserteq(0, ptr[4]);
+	ut_asserteq(ACPI_SERIAL_BUS_TYPE_SPI, ptr[5]);
+	ut_asserteq(2, ptr[6]);
+	ut_asserteq(0, get_unaligned((u16 *)(ptr + 7)));
+	ut_asserteq(ACPI_SPI_TYPE_SPECIFIC_REVISION_ID, ptr[9]);
+	ut_asserteq(9, get_unaligned((u16 *)(ptr + 10)));
+	ut_asserteq(40000000, get_unaligned((u32 *)(ptr + 12)));
+	ut_asserteq(8, ptr[16]);
+	ut_asserteq(0, ptr[17]);
+	ut_asserteq(0, ptr[18]);
+	ut_asserteq(0, get_unaligned((u16 *)(ptr + 19)));
+	ut_asserteq_str("\\_SB.SSPI", (char *)ptr + 21);
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_spi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 13/35] acpigen: Support writing a length
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (11 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 12/35] acpi: Support generation of SPI descriptor Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 14/35] acpigen: Support writing a package Simon Glass
                   ` (55 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

It is convenient to write a length value for preceding a block of data.
Of course the length is not known or is hard to calculate a priori. So add
a way to mark the start on a stack, so the length can be updated when
known.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpigen.h |  3 ++
 include/dm/acpi.h      |  7 +++++
 lib/acpi/acpigen.c     | 33 ++++++++++++++++++++++
 test/dm/acpigen.c      | 64 ++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 105 insertions(+), 2 deletions(-)

diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
index 7365cce738..31366f5e34 100644
--- a/include/acpi/acpigen.h
+++ b/include/acpi/acpigen.h
@@ -65,4 +65,7 @@ void acpigen_emit_stream(struct acpi_ctx *ctx, const char *data, int size);
  */
 void acpigen_emit_string(struct acpi_ctx *ctx, const char *str);
 
+void acpigen_write_len_f(struct acpi_ctx *ctx);
+void acpigen_pop_len(struct acpi_ctx *ctx);
+
 #endif
diff --git a/include/dm/acpi.h b/include/dm/acpi.h
index 7563a4c60a..2bd03eaa0a 100644
--- a/include/dm/acpi.h
+++ b/include/dm/acpi.h
@@ -22,6 +22,9 @@
 /* Length of an ACPI name string including nul terminator */
 #define ACPI_NAME_MAX	(ACPI_NAME_LEN + 1)
 
+/* Number of nested objects supported */
+#define ACPIGEN_LENSTACK_SIZE 10
+
 #if !defined(__ACPI__)
 
 /**
@@ -34,12 +37,16 @@
  *	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
+ * @len_stack: Stack of 'length' words to fix up later
+ * @ltop: Points to current top of stack (0 = empty)
  */
 struct acpi_ctx {
 	void *current;
 	struct acpi_rsdp *rsdp;
 	struct acpi_rsdt *rsdt;
 	struct acpi_xsdt *xsdt;
+	char *len_stack[ACPIGEN_LENSTACK_SIZE];
+	int ltop;
 };
 
 /**
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index 1223f0d1c4..bd1fa24fb6 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -10,6 +10,7 @@
 
 #include <common.h>
 #include <dm.h>
+#include <log.h>
 #include <acpi/acpigen.h>
 #include <dm/acpi.h>
 
@@ -37,6 +38,38 @@ void acpigen_emit_dword(struct acpi_ctx *ctx, uint data)
 	acpigen_emit_byte(ctx, (data >> 24) & 0xff);
 }
 
+/*
+ * Maximum length for an ACPI object generated by this code,
+ *
+ * If you need to change this, change acpigen_write_len_f(ctx) and
+ * acpigen_pop_len(ctx)
+ */
+#define ACPIGEN_MAXLEN 0xfffff
+
+void acpigen_write_len_f(struct acpi_ctx *ctx)
+{
+	assert(ctx->ltop < (ACPIGEN_LENSTACK_SIZE - 1));
+	ctx->len_stack[ctx->ltop++] = ctx->current;
+	acpigen_emit_byte(ctx, 0);
+	acpigen_emit_byte(ctx, 0);
+	acpigen_emit_byte(ctx, 0);
+}
+
+void acpigen_pop_len(struct acpi_ctx *ctx)
+{
+	int len;
+	char *p;
+
+	assert(ctx->ltop > 0);
+	p = ctx->len_stack[--ctx->ltop];
+	len = ctx->current - (void *)p;
+	assert(len <= ACPIGEN_MAXLEN);
+	/* generate store length for 0xfffff max */
+	p[0] = (0x80 | (len & 0xf));
+	p[1] = (len >> 4 & 0xff);
+	p[2] = (len >> 12 & 0xff);
+}
+
 void acpigen_emit_stream(struct acpi_ctx *ctx, const char *data, int size)
 {
 	int i;
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index 3d580a23a5..f9c15b7503 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -22,7 +22,7 @@
 #define TEST_STRING	"frogmore"
 #define TEST_STREAM2	"\xfa\xde"
 
-static int alloc_context(struct acpi_ctx **ctxp)
+static int alloc_context_size(struct acpi_ctx **ctxp, int size)
 {
 	struct acpi_ctx *ctx;
 
@@ -30,7 +30,8 @@ static int alloc_context(struct acpi_ctx **ctxp)
 	ctx = malloc(sizeof(*ctx));
 	if (!ctx)
 		return -ENOMEM;
-	ctx->current = malloc(150);
+	ctx->current = malloc(size);
+	ctx->ltop = 0;
 	if (!ctx->current)
 		return -ENOMEM;
 	*ctxp = ctx;
@@ -38,6 +39,11 @@ static int alloc_context(struct acpi_ctx **ctxp)
 	return 0;
 }
 
+static int alloc_context(struct acpi_ctx **ctxp)
+{
+	return alloc_context_size(ctxp, 150);
+}
+
 static void free_context(struct acpi_ctx **ctxp)
 {
 	free(*ctxp);
@@ -334,3 +340,57 @@ static int dm_test_acpi_spi(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_spi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/**
+ * get_length() - decode a three-byte length field
+ *
+ * @ptr: Length encoded as per ACPI
+ * @return decoded length, or -EINVAL on error
+ */
+static int get_length(u8 *ptr)
+{
+	if (!(*ptr & 0x80))
+		return -EINVAL;
+
+	return (*ptr & 0xf) | ptr[1] << 4 | ptr[2] << 12;
+}
+
+/* Test emitting a length */
+static int dm_test_acpi_len(struct unit_test_state *uts)
+{
+	const int size = 0xc0000;
+	struct acpi_ctx *ctx;
+	u8 *ptr;
+	int i;
+
+	ut_assertok(alloc_context_size(&ctx, size));
+
+	ptr = acpigen_get_current(ctx);
+
+	/* Write a byte and a 3-byte length */
+	acpigen_write_len_f(ctx);
+	acpigen_emit_byte(ctx, 0x23);
+	acpigen_pop_len(ctx);
+	ut_asserteq(1 + 3, get_length(ptr));
+
+	/* Write 200 bytes so we need two length bytes */
+	ptr = ctx->current;
+	acpigen_write_len_f(ctx);
+	for (i = 0; i < 200; i++)
+		acpigen_emit_byte(ctx, 0x23);
+	acpigen_pop_len(ctx);
+	ut_asserteq(200 + 3, get_length(ptr));
+
+	/* Write 40KB so we need three length bytes */
+	ptr = ctx->current;
+	acpigen_write_len_f(ctx);
+	for (i = 0; i < 40000; i++)
+		acpigen_emit_byte(ctx, 0x23);
+	acpigen_pop_len(ctx);
+	ut_asserteq(40000 + 3, get_length(ptr));
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_len, 0);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 14/35] acpigen: Support writing a package
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (12 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 13/35] acpigen: Support writing a length Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 15/35] acpi: Support writing an integer Simon Glass
                   ` (54 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

A package collects together several elements. Add an easy way of writing
a package header and updating its length later.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpigen.h | 62 ++++++++++++++++++++++++++++++++++++++++++
 lib/acpi/acpigen.c     | 12 ++++++++
 test/dm/acpigen.c      | 27 ++++++++++++++++++
 3 files changed, 101 insertions(+)

diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
index 31366f5e34..52e0b75128 100644
--- a/include/acpi/acpigen.h
+++ b/include/acpi/acpigen.h
@@ -14,6 +14,11 @@
 
 struct acpi_ctx;
 
+/* ACPI Op/Prefix codes */
+enum {
+	PACKAGE_OP		= 0x12,
+};
+
 /**
  * acpigen_get_current() - Get the current ACPI code output pointer
  *
@@ -65,7 +70,64 @@ void acpigen_emit_stream(struct acpi_ctx *ctx, const char *data, int size);
  */
 void acpigen_emit_string(struct acpi_ctx *ctx, const char *str);
 
+/**
+ * acpigen_write_len_f() - Write a 'forward' length placeholder
+ *
+ * This adds space for a length value in the ACPI stream and pushes the current
+ * position (before the length) on the stack. After calling this you can write
+ * some data and then call acpigen_pop_len() to update the length value.
+ *
+ * Usage:
+ *
+ *    acpigen_write_len_f() ------\
+ *    acpigen_write...()          |
+ *    acpigen_write...()          |
+ *      acpigen_write_len_f() --\ |
+ *      acpigen_write...()      | |
+ *      acpigen_write...()      | |
+ *      acpigen_pop_len() ------/ |
+ *    acpigen_write...()          |
+ *    acpigen_pop_len() ----------/
+ *
+ * @ctx: ACPI context pointer
+ */
 void acpigen_write_len_f(struct acpi_ctx *ctx);
+
+/**
+ * acpigen_pop_len() - Update the previously stacked length placeholder
+ *
+ * Call this after the data for the block gas been written. It updates the
+ * top length value in the stack and pops it off.
+ *
+ * @ctx: ACPI context pointer
+ */
 void acpigen_pop_len(struct acpi_ctx *ctx);
 
+/**
+ * acpigen_write_package() - Start writing a package
+ *
+ * A package collects together a number of elements in the ACPI code. To write
+ * a package use:
+ *
+ * acpigen_write_package(ctx, 3);
+ * ...write things
+ * acpigen_pop_len()
+ *
+ * If you don't know the number of elements in advance, acpigen_write_package()
+ * returns a pointer to the value so you can update it later:
+ *
+ * char *num_elements = acpigen_write_package(ctx, 0);
+ * ...write things
+ * *num_elements += 1;
+ * ...write things
+ * *num_elements += 1;
+ * acpigen_pop_len()
+ *
+ * @ctx: ACPI context pointer
+ * @nr_el: Number of elements (0 if not known)
+ * @returns pointer to the number of elements, which can be updated by the
+ *	caller if needed
+ */
+char *acpigen_write_package(struct acpi_ctx *ctx, int nr_el);
+
 #endif
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index bd1fa24fb6..e1fd1f6b6a 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -70,6 +70,18 @@ void acpigen_pop_len(struct acpi_ctx *ctx)
 	p[2] = (len >> 12 & 0xff);
 }
 
+char *acpigen_write_package(struct acpi_ctx *ctx, int nr_el)
+{
+	char *p;
+
+	acpigen_emit_byte(ctx, PACKAGE_OP);
+	acpigen_write_len_f(ctx);
+	p = ctx->current;
+	acpigen_emit_byte(ctx, nr_el);
+
+	return p;
+}
+
 void acpigen_emit_stream(struct acpi_ctx *ctx, const char *data, int size)
 {
 	int i;
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index f9c15b7503..be81068759 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -394,3 +394,30 @@ static int dm_test_acpi_len(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_len, 0);
+
+/* Test emitting a package */
+static int dm_test_acpi_package(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	char *num_elements;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+
+	num_elements = acpigen_write_package(ctx, 3);
+	ut_asserteq_ptr(num_elements, ptr + 4);
+
+	/* For easy of testing, just emit a byte, not valid package contents */
+	acpigen_emit_byte(ctx, 0x23);
+	acpigen_pop_len(ctx);
+	ut_asserteq(PACKAGE_OP, ptr[0]);
+	ut_asserteq(5, get_length(ptr + 1));
+	ut_asserteq(3, ptr[4]);
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_package, 0);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 15/35] acpi: Support writing an integer
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (13 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 14/35] acpigen: Support writing a package Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 16/35] acpi: Support writing a string Simon Glass
                   ` (53 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

ACPI supports storing integers in various ways. Add a function to handle
this.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpigen.h | 17 ++++++++++++++
 lib/acpi/acpigen.c     | 51 ++++++++++++++++++++++++++++++++++++++++++
 test/dm/acpigen.c      | 46 +++++++++++++++++++++++++++++++++++++
 3 files changed, 114 insertions(+)

diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
index 52e0b75128..a4edcb097b 100644
--- a/include/acpi/acpigen.h
+++ b/include/acpi/acpigen.h
@@ -16,6 +16,12 @@ struct acpi_ctx;
 
 /* ACPI Op/Prefix codes */
 enum {
+	ZERO_OP			= 0x00,
+	ONE_OP			= 0x01,
+	BYTE_PREFIX		= 0x0a,
+	WORD_PREFIX		= 0x0b,
+	DWORD_PREFIX		= 0x0c,
+	QWORD_PREFIX		= 0x0e,
 	PACKAGE_OP		= 0x12,
 };
 
@@ -130,4 +136,15 @@ void acpigen_pop_len(struct acpi_ctx *ctx);
  */
 char *acpigen_write_package(struct acpi_ctx *ctx, int nr_el);
 
+/**
+ * acpigen_write_integer() - Write an integer
+ *
+ * This writes an operation (BYTE_OP, WORD_OP, DWORD_OP, QWORD_OP depending on
+ * the integer size) and an integer value. Note that WORD means 16 bits in ACPI.
+ *
+ * @ctx: ACPI context pointer
+ * @data: Integer to write
+ */
+void acpigen_write_integer(struct acpi_ctx *ctx, u64 data);
+
 #endif
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index e1fd1f6b6a..ece0111320 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -82,6 +82,57 @@ char *acpigen_write_package(struct acpi_ctx *ctx, int nr_el)
 	return p;
 }
 
+void acpigen_write_byte(struct acpi_ctx *ctx, unsigned int data)
+{
+	acpigen_emit_byte(ctx, BYTE_PREFIX);
+	acpigen_emit_byte(ctx, data & 0xff);
+}
+
+void acpigen_write_word(struct acpi_ctx *ctx, unsigned int data)
+{
+	acpigen_emit_byte(ctx, WORD_PREFIX);
+	acpigen_emit_word(ctx, data);
+}
+
+void acpigen_write_dword(struct acpi_ctx *ctx, unsigned int data)
+{
+	acpigen_emit_byte(ctx, DWORD_PREFIX);
+	acpigen_emit_dword(ctx, data);
+}
+
+void acpigen_write_qword(struct acpi_ctx *ctx, u64 data)
+{
+	acpigen_emit_byte(ctx, QWORD_PREFIX);
+	acpigen_emit_dword(ctx, data & 0xffffffff);
+	acpigen_emit_dword(ctx, (data >> 32) & 0xffffffff);
+}
+
+void acpigen_write_zero(struct acpi_ctx *ctx)
+{
+	acpigen_emit_byte(ctx, ZERO_OP);
+}
+
+void acpigen_write_one(struct acpi_ctx *ctx)
+{
+	acpigen_emit_byte(ctx, ONE_OP);
+}
+
+void acpigen_write_integer(struct acpi_ctx *ctx, u64 data)
+{
+	if (data == 0)
+		acpigen_write_zero(ctx);
+	else if (data == 1)
+		acpigen_write_one(ctx);
+	else if (data <= 0xff)
+		acpigen_write_byte(ctx, (unsigned char)data);
+	else if (data <= 0xffff)
+		acpigen_write_word(ctx, (unsigned int)data);
+	else if (data <= 0xffffffff)
+		acpigen_write_dword(ctx, (unsigned int)data);
+	else
+		acpigen_write_qword(ctx, data);
+}
+
 void acpigen_emit_stream(struct acpi_ctx *ctx, const char *data, int size)
 {
 	int i;
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index be81068759..9350943a12 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -22,6 +22,11 @@
 #define TEST_STRING	"frogmore"
 #define TEST_STREAM2	"\xfa\xde"
 
+#define TEST_INT8	0x7d
+#define TEST_INT16	0x2345
+#define TEST_INT32	0x12345678
+#define TEST_INT64	0x4567890123456
+
 static int alloc_context_size(struct acpi_ctx **ctxp, int size)
 {
 	struct acpi_ctx *ctx;
@@ -421,3 +426,44 @@ static int dm_test_acpi_package(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_package, 0);
+
+/* Test emitting an integer */
+static int dm_test_acpi_integer(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+
+	acpigen_write_integer(ctx, 0);
+	acpigen_write_integer(ctx, 1);
+	acpigen_write_integer(ctx, TEST_INT8);
+	acpigen_write_integer(ctx, TEST_INT16);
+	acpigen_write_integer(ctx, TEST_INT32);
+	acpigen_write_integer(ctx, TEST_INT64);
+
+	ut_asserteq(6 + 1 + 2 + 4 + 8, acpigen_get_current(ctx) - ptr);
+
+	ut_asserteq(ZERO_OP, ptr[0]);
+
+	ut_asserteq(ONE_OP, ptr[1]);
+
+	ut_asserteq(BYTE_PREFIX, ptr[2]);
+	ut_asserteq(TEST_INT8, ptr[3]);
+
+	ut_asserteq(WORD_PREFIX, ptr[4]);
+	ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 5)));
+
+	ut_asserteq(DWORD_PREFIX, ptr[7]);
+	ut_asserteq(TEST_INT32, get_unaligned((u32 *)(ptr + 8)));
+
+	ut_asserteq(QWORD_PREFIX, ptr[12]);
+	ut_asserteq_64(TEST_INT64, get_unaligned((u64 *)(ptr + 13)));
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_integer, 0);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 16/35] acpi: Support writing a string
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (14 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 15/35] acpi: Support writing an integer Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 17/35] acpi: Support writing a name Simon Glass
                   ` (52 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

ACPI supports storing a simple nul-terminated string. Add support for
this.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpigen.h | 10 ++++++++++
 lib/acpi/acpigen.c     |  6 ++++++
 test/dm/acpigen.c      | 32 ++++++++++++++++++++++++++++++--
 3 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
index a4edcb097b..f65de53a76 100644
--- a/include/acpi/acpigen.h
+++ b/include/acpi/acpigen.h
@@ -21,6 +21,7 @@ enum {
 	BYTE_PREFIX		= 0x0a,
 	WORD_PREFIX		= 0x0b,
 	DWORD_PREFIX		= 0x0c,
+	STRING_PREFIX		= 0x0d,
 	QWORD_PREFIX		= 0x0e,
 	PACKAGE_OP		= 0x12,
 };
@@ -147,4 +148,13 @@ char *acpigen_write_package(struct acpi_ctx *ctx, int nr_el);
  */
 void acpigen_write_integer(struct acpi_ctx *ctx, u64 data);
 
+/**
+ * acpigen_write_string() - Write a string
+ *
+ * This writes a STRING_PREFIX followed by a nul-terminated string
+ *
+ * @ctx: ACPI context pointer
+ * @str: String to write
+ */
+void acpigen_write_string(struct acpi_ctx *ctx, const char *str);
 #endif
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index ece0111320..a4ac3c8875 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -146,3 +146,9 @@ void acpigen_emit_string(struct acpi_ctx *ctx, const char *str)
 	acpigen_emit_stream(ctx, str, str ? strlen(str) : 0);
 	acpigen_emit_byte(ctx, '\0'); /* NUL */
 }
+
+void acpigen_write_string(struct acpi_ctx *ctx, const char *str)
+{
+	acpigen_emit_byte(ctx, STRING_PREFIX);
+	acpigen_emit_string(ctx, str);
+}
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index 9350943a12..dc6993b7a7 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -20,6 +20,7 @@
 #include <test/ut.h>
 
 #define TEST_STRING	"frogmore"
+#define TEST_STRING2	"ranch"
 #define TEST_STREAM2	"\xfa\xde"
 
 #define TEST_INT8	0x7d
@@ -400,7 +401,7 @@ static int dm_test_acpi_len(struct unit_test_state *uts)
 }
 DM_TEST(dm_test_acpi_len, 0);
 
-/* Test emitting a package */
+/* Test writing a package */
 static int dm_test_acpi_package(struct unit_test_state *uts)
 {
 	struct acpi_ctx *ctx;
@@ -427,7 +428,7 @@ static int dm_test_acpi_package(struct unit_test_state *uts)
 }
 DM_TEST(dm_test_acpi_package, 0);
 
-/* Test emitting an integer */
+/* Test writing an integer */
 static int dm_test_acpi_integer(struct unit_test_state *uts)
 {
 	struct acpi_ctx *ctx;
@@ -467,3 +468,30 @@ static int dm_test_acpi_integer(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_integer, 0);
+
+/* Test writing a string */
+static int dm_test_acpi_string(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+
+	acpigen_write_string(ctx, TEST_STRING);
+	acpigen_write_string(ctx, TEST_STRING2);
+
+	ut_asserteq(2 + sizeof(TEST_STRING) + sizeof(TEST_STRING2),
+		    acpigen_get_current(ctx) - ptr);
+	ut_asserteq(STRING_PREFIX, ptr[0]);
+	ut_asserteq_str(TEST_STRING, (char *)ptr + 1);
+	ptr += 1 + sizeof(TEST_STRING);
+	ut_asserteq(STRING_PREFIX, ptr[0]);
+	ut_asserteq_str(TEST_STRING2, (char *)ptr + 1);
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_string, 0);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 17/35] acpi: Support writing a name
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (15 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 16/35] acpi: Support writing a string Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 18/35] acpi: Support writing a UUID Simon Glass
                   ` (51 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

ACPI supports storing names which are made up of multiple path components.
Several special cases are supported. Add a function to emit a name.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpigen.h | 25 +++++++++++
 include/test/ut.h      | 17 ++++++++
 lib/acpi/acpigen.c     | 96 ++++++++++++++++++++++++++++++++++++++++++
 test/dm/acpigen.c      | 93 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 231 insertions(+)

diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
index f65de53a76..0fecb7d57a 100644
--- a/include/acpi/acpigen.h
+++ b/include/acpi/acpigen.h
@@ -18,12 +18,15 @@ struct acpi_ctx;
 enum {
 	ZERO_OP			= 0x00,
 	ONE_OP			= 0x01,
+	NAME_OP			= 0x08,
 	BYTE_PREFIX		= 0x0a,
 	WORD_PREFIX		= 0x0b,
 	DWORD_PREFIX		= 0x0c,
 	STRING_PREFIX		= 0x0d,
 	QWORD_PREFIX		= 0x0e,
 	PACKAGE_OP		= 0x12,
+	DUAL_NAME_PREFIX	= 0x2e,
+	MULTI_NAME_PREFIX	= 0x2f,
 };
 
 /**
@@ -157,4 +160,26 @@ void acpigen_write_integer(struct acpi_ctx *ctx, u64 data);
  * @str: String to write
  */
 void acpigen_write_string(struct acpi_ctx *ctx, const char *str);
+
+/**
+ * acpigen_emit_namestring() - Emit an ACPI name
+ *
+ * This writes out an ACPI name or path in the required special format. It does
+ * not add the NAME_OP prefix.
+ *
+ * @ctx: ACPI context pointer
+ * @namepath: Name / path to emit
+ */
+void acpigen_emit_namestring(struct acpi_ctx *ctx, const char *namepath);
+
+/**
+ * acpigen_write_name() - Write out an ACPI name
+ *
+ * This writes out an ACPI name or path in the required special format with a
+ * NAME_OP prefix.
+ *
+ * @ctx: ACPI context pointer
+ * @namepath: Name / path to emit
+ */
+void acpigen_write_name(struct acpi_ctx *ctx, const char *namepath);
 #endif
diff --git a/include/test/ut.h b/include/test/ut.h
index 7ddd6e8872..99bbb1230c 100644
--- a/include/test/ut.h
+++ b/include/test/ut.h
@@ -134,6 +134,23 @@ int ut_check_console_dump(struct unit_test_state *uts, int total_bytes);
 	}								\
 }
 
+/*
+ * Assert that two string expressions are equal, up to length of the
+ * first
+ */
+#define ut_asserteq_strn(expr1, expr2) {				\
+	const char *_val1 = (expr1), *_val2 = (expr2);			\
+	int _len = strlen(_val1);					\
+									\
+	if (memcmp(_val1, _val2, _len)) {				\
+		ut_failf(uts, __FILE__, __LINE__, __func__,		\
+			 #expr1 " = " #expr2,				\
+			 "Expected \"%.*s\", got \"%.*s\"",		\
+			 _len, _val1, _len, _val2);			\
+		return CMD_RET_FAILURE;					\
+	}								\
+}
+
 /* Assert that two memory areas are equal */
 #define ut_asserteq_mem(expr1, expr2, len) {				\
 	const u8 *_val1 = (u8 *)(expr1), *_val2 = (u8 *)(expr2);	\
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index a4ac3c8875..eae2f605ed 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -152,3 +152,99 @@ void acpigen_write_string(struct acpi_ctx *ctx, const char *str)
 	acpigen_emit_byte(ctx, STRING_PREFIX);
 	acpigen_emit_string(ctx, str);
 }
+
+/*
+ * The naming conventions for ACPI namespace names are a bit tricky as
+ * each element has to be 4 chars wide ("All names are a fixed 32 bits.")
+ * and "By convention, when an ASL compiler pads a name shorter than 4
+ * characters, it is done so with trailing underscores ('_')".
+ *
+ * Check sections 5.3, 20.2.2 and 20.4 of ACPI spec 6.3 for details.
+ */
+static void acpigen_emit_simple_namestring(struct acpi_ctx *ctx,
+					   const char *name)
+{
+	const char *ptr;
+	int i;
+
+	for (i = 0, ptr = name; i < 4; i++) {
+		if (!*ptr || *ptr == '.')
+			acpigen_emit_byte(ctx, '_');
+		else
+			acpigen_emit_byte(ctx, *ptr++);
+	}
+}
+
+static void acpigen_emit_double_namestring(struct acpi_ctx *ctx,
+					   const char *name, int dotpos)
+{
+	acpigen_emit_byte(ctx, DUAL_NAME_PREFIX);
+	acpigen_emit_simple_namestring(ctx, name);
+	acpigen_emit_simple_namestring(ctx, &name[dotpos + 1]);
+}
+
+static void acpigen_emit_multi_namestring(struct acpi_ctx *ctx,
+					  const char *name)
+{
+	unsigned char *pathlen;
+	int count = 0;
+
+	acpigen_emit_byte(ctx, MULTI_NAME_PREFIX);
+	pathlen = ctx->current;
+	acpigen_emit_byte(ctx, 0);
+
+	while (*name) {
+		acpigen_emit_simple_namestring(ctx, name);
+		/* find end or next entity */
+		while (*name != '.' && *name)
+			name++;
+		/* forward to next */
+		if (*name == '.')
+			name++;
+		count++;
+	}
+
+	*pathlen = count;
+}
+
+void acpigen_emit_namestring(struct acpi_ctx *ctx, const char *namepath)
+{
+	int dotcount;
+	int dotpos;
+	int i;
+
+	/* We can start with a '\' */
+	if (*namepath == '\\') {
+		acpigen_emit_byte(ctx, '\\');
+		namepath++;
+	}
+
+	/* And there can be any number of '^' */
+	while (*namepath == '^') {
+		acpigen_emit_byte(ctx, '^');
+		namepath++;
+	}
+
+	for (i = 0, dotcount = 0; namepath[i]; i++) {
+		if (namepath[i] == '.') {
+			dotcount++;
+			dotpos = i;
+		}
+	}
+
+	/* If we have only \\ or only ^* then we need to add a nul name */
+	if (!*namepath)
+		acpigen_emit_byte(ctx, ZERO_OP);
+	else if (dotcount == 0)
+		acpigen_emit_simple_namestring(ctx, namepath);
+	else if (dotcount == 1)
+		acpigen_emit_double_namestring(ctx, namepath, dotpos);
+	else
+		acpigen_emit_multi_namestring(ctx, namepath);
+}
+
+void acpigen_write_name(struct acpi_ctx *ctx, const char *namepath)
+{
+	acpigen_emit_byte(ctx, NAME_OP);
+	acpigen_emit_namestring(ctx, namepath);
+}
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index dc6993b7a7..0f56262a28 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -495,3 +495,96 @@ static int dm_test_acpi_string(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_string, 0);
+
+/* Test writing a name */
+static int dm_test_acpi_name(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+
+	/*
+	 * The names here are made up for testing the various cases. The
+	 * grammar is in the ACPI spec 6.3 section 19.2.2
+	 */
+	acpigen_write_name(ctx, "\\_SB");
+	acpigen_write_name(ctx, "\\_SB.I2C0");
+	acpigen_write_name(ctx, "\\_SB.I2C0.TPM2");
+	acpigen_write_name(ctx, "\\_SB.I2C0.TPM2.LONG");
+	acpigen_write_name(ctx, "^^^^SPI0.FLAS");
+	acpigen_write_name(ctx, "NN");
+	acpigen_write_name(ctx, "^AB.CD.D.EFG");
+	acpigen_write_name(ctx, "^^^^");
+	acpigen_write_name(ctx, "\\");
+	acpigen_write_name(ctx, "\\ABCD");
+
+	ut_asserteq(107, acpigen_get_current(ctx) - ptr);
+	ut_asserteq(NAME_OP, ptr[0]);
+	ut_asserteq_strn("\\_SB_", (char *)ptr + 1);
+	ptr += 6;
+
+	ut_asserteq(NAME_OP, ptr[0]);
+	ut_asserteq('\\', ptr[1]);
+	ut_asserteq(DUAL_NAME_PREFIX, ptr[2]);
+	ut_asserteq_strn("_SB_I2C0", (char *)ptr + 3);
+	ptr += 11;
+
+	ut_asserteq(NAME_OP, ptr[0]);
+	ut_asserteq('\\', ptr[1]);
+	ut_asserteq(MULTI_NAME_PREFIX, ptr[2]);
+	ut_asserteq(3, ptr[3]);
+	ut_asserteq_strn("_SB_I2C0TPM2", (char *)ptr + 4);
+	ptr += 16;
+
+	ut_asserteq(NAME_OP, ptr[0]);
+	ut_asserteq('\\', ptr[1]);
+	ut_asserteq(MULTI_NAME_PREFIX, ptr[2]);
+	ut_asserteq(4, ptr[3]);
+	ut_asserteq_strn("_SB_I2C0TPM2LONG", (char *)ptr + 4);
+	ptr += 20;
+
+	ut_asserteq(NAME_OP, ptr[0]);
+	ut_asserteq('^', ptr[1]);
+	ut_asserteq('^', ptr[2]);
+	ut_asserteq('^', ptr[3]);
+	ut_asserteq('^', ptr[4]);
+	ut_asserteq(DUAL_NAME_PREFIX, ptr[5]);
+	ut_asserteq_strn("SPI0FLAS", (char *)ptr + 6);
+	ptr += 14;
+
+	ut_asserteq(NAME_OP, ptr[0]);
+	ut_asserteq_strn("NN__", (char *)ptr + 1);
+	ptr += 5;
+
+	ut_asserteq(NAME_OP, ptr[0]);
+	ut_asserteq('^', ptr[1]);
+	ut_asserteq(MULTI_NAME_PREFIX, ptr[2]);
+	ut_asserteq(4, ptr[3]);
+	ut_asserteq_strn("AB__CD__D___EFG_", (char *)ptr + 4);
+	ptr += 20;
+
+	ut_asserteq(NAME_OP, ptr[0]);
+	ut_asserteq('^', ptr[1]);
+	ut_asserteq('^', ptr[2]);
+	ut_asserteq('^', ptr[3]);
+	ut_asserteq('^', ptr[4]);
+	ut_asserteq(ZERO_OP, ptr[5]);
+	ptr += 6;
+
+	ut_asserteq(NAME_OP, ptr[0]);
+	ut_asserteq('\\', ptr[1]);
+	ut_asserteq(ZERO_OP, ptr[2]);
+	ptr += 3;
+
+	ut_asserteq(NAME_OP, ptr[0]);
+	ut_asserteq_strn("\\ABCD", (char *)ptr + 1);
+	ptr += 5;
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_name, 0);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 18/35] acpi: Support writing a UUID
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (16 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 17/35] acpi: Support writing a name Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 19/35] acpi: Support writing Device Properties objects via _DSD Simon Glass
                   ` (50 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

ACPI supports writing a UUID in a special format. Add a function to handle
this.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpigen.h | 13 +++++++++++++
 lib/acpi/acpigen.c     | 39 +++++++++++++++++++++++++++++++++++++++
 test/dm/acpigen.c      | 33 +++++++++++++++++++++++++++++++++
 3 files changed, 85 insertions(+)

diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
index 0fecb7d57a..f35467f029 100644
--- a/include/acpi/acpigen.h
+++ b/include/acpi/acpigen.h
@@ -24,6 +24,7 @@ enum {
 	DWORD_PREFIX		= 0x0c,
 	STRING_PREFIX		= 0x0d,
 	QWORD_PREFIX		= 0x0e,
+	BUFFER_OP		= 0x11,
 	PACKAGE_OP		= 0x12,
 	DUAL_NAME_PREFIX	= 0x2e,
 	MULTI_NAME_PREFIX	= 0x2f,
@@ -182,4 +183,16 @@ void acpigen_emit_namestring(struct acpi_ctx *ctx, const char *namepath);
  * @namepath: Name / path to emit
  */
 void acpigen_write_name(struct acpi_ctx *ctx, const char *namepath);
+
+/**
+ * acpigen_write_uuid() - Write a UUID
+ *
+ * This writes out a UUID in the format used by ACPI, with a BUFFER_OP prefix.
+ *
+ * @ctx: ACPI context pointer
+ * @uuid: UUID to write in the form aabbccdd-eeff-gghh-iijj-kkllmmnnoopp
+ * @return 0 if OK, -EINVAL if the format is incorrect
+ */
+int acpigen_write_uuid(struct acpi_ctx *ctx, const char *uuid);
+
 #endif
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index eae2f605ed..f781ad4d87 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -11,6 +11,7 @@
 #include <common.h>
 #include <dm.h>
 #include <log.h>
+#include <uuid.h>
 #include <acpi/acpigen.h>
 #include <dm/acpi.h>
 
@@ -248,3 +249,41 @@ void acpigen_write_name(struct acpi_ctx *ctx, const char *namepath)
 	acpigen_emit_byte(ctx, NAME_OP);
 	acpigen_emit_namestring(ctx, namepath);
 }
+
+/*
+ * ToUUID(uuid)
+ *
+ * ACPI 6.3 Section 19.6.142 table 19-438 defines a special output order for the
+ * bytes that make up a UUID Buffer object:
+ *
+ * UUID byte order for input to this function:
+ *   aabbccdd-eeff-gghh-iijj-kkllmmnnoopp
+ *
+ * UUID byte order output by this function:
+ *   ddccbbaa-ffee-hhgg-iijj-kkllmmnnoopp
+ */
+#define UUID_LEN 16
+int acpigen_write_uuid(struct acpi_ctx *ctx, const char *uuid)
+{
+	u8 buf[UUID_LEN];
+	int ret;
+
+	/* Parse UUID string into bytes */
+	ret = uuid_str_to_bin(uuid, buf, UUID_STR_FORMAT_GUID);
+	if (ret)
+		return log_msg_ret("bad hex", -EINVAL);
+
+	/* BufferOp */
+	acpigen_emit_byte(ctx, BUFFER_OP);
+	acpigen_write_len_f(ctx);
+
+	/* Buffer length in bytes */
+	acpigen_write_word(ctx, UUID_LEN);
+
+	/* Output UUID in expected order */
+	acpigen_emit_stream(ctx, (char *)buf, UUID_LEN);
+
+	acpigen_pop_len(ctx);
+
+	return 0;
+}
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index 0f56262a28..db8cad47d8 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -588,3 +588,36 @@ static int dm_test_acpi_name(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_name, 0);
+
+/* Test writing a UUID */
+static int dm_test_acpi_uuid(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+
+	ut_assertok(acpigen_write_uuid(ctx,
+				       "dbb8e3e6-5886-4ba6-8795-1319f52a966b"));
+	ut_asserteq(23, acpigen_get_current(ctx) - ptr);
+	ut_asserteq(BUFFER_OP, ptr[0]);
+	ut_asserteq(22, get_length(ptr + 1));
+	ut_asserteq(0xdbb8e3e6, get_unaligned((u32 *)(ptr + 7)));
+	ut_asserteq(0x5886, get_unaligned((u16 *)(ptr + 11)));
+	ut_asserteq(0x4ba6, get_unaligned((u16 *)(ptr + 13)));
+	ut_asserteq(0x9587, get_unaligned((u16 *)(ptr + 15)));
+	ut_asserteq(0x2af51913, get_unaligned((u32 *)(ptr + 17)));
+	ut_asserteq(0x6b96, get_unaligned((u16 *)(ptr + 21)));
+
+	/* Try a bad UUID */
+	ut_asserteq(-EINVAL,
+		    acpigen_write_uuid(ctx,
+				       "dbb8e3e6-5886-4ba6x8795-1319f52a966b"));
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_uuid, 0);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 19/35] acpi: Support writing Device Properties objects via _DSD
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (17 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 18/35] acpi: Support writing a UUID Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 20/35] acpi: Support writing a GPIO Simon Glass
                   ` (49 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

More complex device properties can be provided to drivers via a
device-specific data (_DSD) object.

To create this we need to build it up in a separate data structure and
then generate the ACPI code, due to its recursive nature.

Add an implementation of this.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpi_dp.h | 215 ++++++++++++++++++++++
 include/acpi/acpigen.h |   1 +
 lib/acpi/Makefile      |   1 +
 lib/acpi/acpi_dp.c     | 324 +++++++++++++++++++++++++++++++++
 lib/acpi/acpigen.c     |   3 +
 test/dm/Makefile       |   1 +
 test/dm/acpi_dp.c      | 405 +++++++++++++++++++++++++++++++++++++++++
 7 files changed, 950 insertions(+)
 create mode 100644 include/acpi/acpi_dp.h
 create mode 100644 lib/acpi/acpi_dp.c
 create mode 100644 test/dm/acpi_dp.c

diff --git a/include/acpi/acpi_dp.h b/include/acpi/acpi_dp.h
new file mode 100644
index 0000000000..840be855c5
--- /dev/null
+++ b/include/acpi/acpi_dp.h
@@ -0,0 +1,215 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Device properties, a temporary data structure for adding to ACPI code
+ *
+ * Copyright 2019 Google LLC
+ * Mostly taken from coreboot file acpi_device.h
+ */
+
+#ifndef __ACPI_DP_H
+#define __ACPI_DP_H
+
+struct acpi_ctx;
+
+/*
+ * Writing Device Properties objects via _DSD
+ *
+ * This is described in ACPI 6.3 section 6.2.5
+ *
+ * This provides a structure to handle nested device-specific data which ends
+ * up in a _DSD table.
+ *
+ * https://www.kernel.org/doc/html/latest/firmware-guide/acpi/DSD-properties-rules.html
+ * https://uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
+ * https://uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf
+ *
+ * The Device Property Hierarchy can be multiple levels deep with multiple
+ * children possible in each level.  In order to support this flexibility
+ * the device property hierarchy must be built up before being written out.
+ *
+ * For example:
+ *
+ * // Child table with string and integer
+ * struct acpi_dp *child = acpi_dp_new_table("CHLD");
+ * acpi_dp_add_string(child, "childstring", "CHILD");
+ * acpi_dp_add_integer(child, "childint", 100);
+ *
+ * // _DSD table with integer and gpio and child pointer
+ * struct acpi_dp *dsd = acpi_dp_new_table("_DSD");
+ * acpi_dp_add_integer(dsd, "number1", 1);
+ * acpi_dp_add_gpio(dsd, "gpio", "\_SB.PCI0.GPIO", 0, 0, 1);
+ * acpi_dp_add_child(dsd, "child", child);
+ *
+ * // Write entries into SSDT and clean up resources
+ * acpi_dp_write(dsd);
+ *
+ * Name(_DSD, Package() {
+ *   ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301")
+ *   Package() {
+ *     Package() { "gpio", Package() { \_SB.PCI0.GPIO, 0, 0, 0 } }
+ *     Package() { "number1", 1 }
+ *   }
+ *   ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b")
+ *   Package() {
+ *     Package() { "child", CHLD }
+ *   }
+ * }
+ * Name(CHLD, Package() {
+ *   ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301")
+ *   Package() {
+ *     Package() { "childstring", "CHILD" }
+ *     Package() { "childint", 100 }
+ *   }
+ * }
+ */
+
+#define ACPI_DP_UUID		"daffd814-6eba-4d8c-8a91-bc9bbf4aa301"
+#define ACPI_DP_CHILD_UUID	"dbb8e3e6-5886-4ba6-8795-1319f52a966b"
+
+/**
+ * enum acpi_dp_type - types of device property objects
+ *
+ * These refer to the types defined by struct acpi_dp below
+ *
+ * @ACPI_DP_TYPE_UNKNOWN: Unknown / do not use
+ * @ACPI_DP_TYPE_INTEGER: Integer value (u64) in @integer
+ * @ACPI_DP_TYPE_STRING: String value in @string
+ * @ACPI_DP_TYPE_REFERENCE: Reference to another object, with value in @string
+ * @ACPI_DP_TYPE_TABLE: Type for a top-level table which may have children
+ * @ACPI_DP_TYPE_ARRAY: Array of items with first item in @array and following
+ *	items linked from that item's @next
+ * @ACPI_DP_TYPE_CHILD: Child object, with siblings in that child's @next
+ */
+enum acpi_dp_type {
+	ACPI_DP_TYPE_UNKNOWN,
+	ACPI_DP_TYPE_INTEGER,
+	ACPI_DP_TYPE_STRING,
+	ACPI_DP_TYPE_REFERENCE,
+	ACPI_DP_TYPE_TABLE,
+	ACPI_DP_TYPE_ARRAY,
+	ACPI_DP_TYPE_CHILD,
+};
+
+/**
+ * struct acpi_dp - ACPI device properties
+ *
+ * @type: Table type
+ * @name: Name of object, typically _DSD but could be CHLD for a child object
+ * @next: Next object in list (next array element or next sibling)
+ * @child: Pointer to first child, if @type == ACPI_DP_TYPE_CHILD, else NULL
+ * @array: First array element, if @type == ACPI_DP_TYPE_ARRAY, else NULL
+ * @integer: Integer value of the property, if @type == ACPI_DP_TYPE_INTEGER
+ * @string: String value of the property, if @type == ACPI_DP_TYPE_STRING;
+ *	child name if @type == ACPI_DP_TYPE_CHILD;
+ *	reference name if @type == ACPI_DP_TYPE_REFERENCE;
+ */
+struct acpi_dp {
+	enum acpi_dp_type type;
+	const char *name;
+	struct acpi_dp *next;
+	union {
+		struct acpi_dp *child;
+		struct acpi_dp *array;
+	};
+	union {
+		u64 integer;
+		const char *string;
+	};
+};
+
+/**
+ * acpi_dp_new_table() - Start a new Device Property table
+ *
+ * @ref: ACPI reference (e.g. "_DSD")
+ * @return pointer to table, or NULL if out of memory
+ */
+struct acpi_dp *acpi_dp_new_table(const char *ref);
+
+/**
+ * acpi_dp_add_integer() - Add integer Device Property
+ *
+ * A new node is added to the end of the property list of @dp
+ *
+ * @dp: Table to add this property to
+ * @name: Name of property
+ * @value: Integer value
+ * @return pointer to new node, or NULL if out of memory
+ */
+struct acpi_dp *acpi_dp_add_integer(struct acpi_dp *dp, const char *name,
+				    u64 value);
+
+/**
+ * acpi_dp_add_string() - Add string Device Property
+ *
+ * A new node is added to the end of the property list of @dp
+ *
+ * @dp: Table to add this property to
+ * @name: Name of property
+ * @string: String value
+ * @return pointer to new node, or NULL if out of memory
+ */
+struct acpi_dp *acpi_dp_add_string(struct acpi_dp *dp, const char *name,
+				   const char *string);
+
+/**
+ * acpi_dp_add_reference() - Add reference Device Property
+ *
+ * A new node is added to the end of the property list of @dp
+ *
+ * @dp: Table to add this property to
+ * @name: Name of property
+ * @reference: Reference value
+ * @return pointer to new node, or NULL if out of memory
+ */
+struct acpi_dp *acpi_dp_add_reference(struct acpi_dp *dp, const char *name,
+				      const char *reference);
+
+/**
+ * acpi_dp_add_array() - Add array Device Property
+ *
+ * A new node is added to the end of the property list of @dp, with the array
+ * attached to that.
+ *
+ * @dp: Table to add this property to
+ * @name: Name of property
+ * @return pointer to new node, or NULL if out of memory
+ */
+struct acpi_dp *acpi_dp_add_array(struct acpi_dp *dp, struct acpi_dp *array);
+
+/**
+ * acpi_dp_add_integer_array() - Add an array of integers
+ *
+ * A new node is added to the end of the property list of @dp, with the array
+ * attached to that. Each element of the array becomes a new node.
+ *
+ * @dp: Table to add this property to
+ * @name: Name of property
+ * @return pointer to new array node, or NULL if out of memory
+ */
+struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
+					  u64 *array, int len);
+
+/**
+ * acpi_dp_add_child() - Add a child table of Device Properties
+ *
+ * A new node is added as a child of @dp
+ *
+ * @dp: Table to add this child to
+ * @name: Name of child
+ * @child: Child node to add
+ * @return pointer to new array node, or NULL if out of memory
+ */
+struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name,
+				  struct acpi_dp *child);
+
+/**
+ * acpi_dp_write() - Write Device Property hierarchy and clean up resources
+ *
+ * This writes the table using acpigen and then frees it
+ *
+ * @table: Table to write
+ * @return 0 if OK, -ve on error
+ */
+int acpi_dp_write(struct acpi_ctx *ctx, struct acpi_dp *table);
+
+#endif
diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
index f35467f029..16b33ebe66 100644
--- a/include/acpi/acpigen.h
+++ b/include/acpi/acpigen.h
@@ -28,6 +28,7 @@ enum {
 	PACKAGE_OP		= 0x12,
 	DUAL_NAME_PREFIX	= 0x2e,
 	MULTI_NAME_PREFIX	= 0x2f,
+	ROOT_PREFIX		= 0x5c,
 };
 
 /**
diff --git a/lib/acpi/Makefile b/lib/acpi/Makefile
index 85a1f774ad..5c2f793701 100644
--- a/lib/acpi/Makefile
+++ b/lib/acpi/Makefile
@@ -3,4 +3,5 @@
 
 obj-y += acpigen.o
 obj-y += acpi_device.o
+obj-y += acpi_dp.o
 obj-y += acpi_table.o
diff --git a/lib/acpi/acpi_dp.c b/lib/acpi/acpi_dp.c
new file mode 100644
index 0000000000..479cb6743c
--- /dev/null
+++ b/lib/acpi/acpi_dp.c
@@ -0,0 +1,324 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generation of tables for particular device types
+ *
+ * Copyright 2019 Google LLC
+ * Mostly taken from coreboot file acpi_device.v
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <uuid.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_dp.h>
+#include <dm/acpi.h>
+
+static void acpi_dp_write_array(struct acpi_ctx *ctx,
+				const struct acpi_dp *array);
+
+static void acpi_dp_write_value(struct acpi_ctx *ctx,
+				const struct acpi_dp *prop)
+{
+	switch (prop->type) {
+	case ACPI_DP_TYPE_INTEGER:
+		acpigen_write_integer(ctx, prop->integer);
+		break;
+	case ACPI_DP_TYPE_STRING:
+	case ACPI_DP_TYPE_CHILD:
+		acpigen_write_string(ctx, prop->string);
+		break;
+	case ACPI_DP_TYPE_REFERENCE:
+		acpigen_emit_namestring(ctx, prop->string);
+		break;
+	case ACPI_DP_TYPE_ARRAY:
+		acpi_dp_write_array(ctx, prop->array);
+		break;
+	default:
+		break;
+	}
+}
+
+/* Package (2) { "prop->name", VALUE } */
+static void acpi_dp_write_property(struct acpi_ctx *ctx,
+				   const struct acpi_dp *prop)
+{
+	acpigen_write_package(ctx, 2);
+	acpigen_write_string(ctx, prop->name);
+	acpi_dp_write_value(ctx, prop);
+	acpigen_pop_len(ctx);
+}
+
+/* Write array of Device Properties */
+static void acpi_dp_write_array(struct acpi_ctx *ctx,
+				const struct acpi_dp *array)
+{
+	const struct acpi_dp *dp;
+	char *pkg_count;
+
+	/* Package element count determined as it is populated */
+	pkg_count = acpigen_write_package(ctx, 0);
+
+	/*
+	 * Only acpi_dp of type DP_TYPE_TABLE is allowed to be an array.
+	 * DP_TYPE_TABLE does not have a value to be written. Thus, start
+	 * the loop from next type in the array.
+	 */
+	for (dp = array->next; dp; dp = dp->next) {
+		acpi_dp_write_value(ctx, dp);
+		(*pkg_count)++;
+	}
+
+	acpigen_pop_len(ctx);
+}
+
+static void acpi_dp_free(struct acpi_dp *dp)
+{
+	assert(dp);
+	while (dp) {
+		struct acpi_dp *p = dp->next;
+
+		switch (dp->type) {
+		case ACPI_DP_TYPE_CHILD:
+			acpi_dp_free(dp->child);
+			break;
+		case ACPI_DP_TYPE_ARRAY:
+			acpi_dp_free(dp->array);
+			break;
+		default:
+			break;
+		}
+
+		free(dp);
+		dp = p;
+	}
+}
+
+int acpi_dp_write_(struct acpi_ctx *ctx, struct acpi_dp *table)
+{
+	struct acpi_dp *dp, *prop;
+	char *dp_count, *prop_count = NULL;
+	int child_count = 0;
+	int ret;
+
+	assert(table);
+	if (table->type != ACPI_DP_TYPE_TABLE)
+		return 0;
+
+	/* Name (name) */
+	acpigen_write_name(ctx, table->name);
+
+	/* Device Property list starts with the next entry */
+	prop = table->next;
+
+	/* Package (DP), default to assuming no properties or children */
+	dp_count = acpigen_write_package(ctx, 0);
+
+	/* Print base properties */
+	for (dp = prop; dp; dp = dp->next) {
+		if (dp->type == ACPI_DP_TYPE_CHILD) {
+			child_count++;
+		} else {
+			/*
+			 * The UUID and package is only added when
+			 * we come across the first property.  This
+			 * is to avoid creating a zero-length package
+			 * in situations where there are only children.
+			 */
+			if (!prop_count) {
+				*dp_count += 2;
+				/* ToUUID (ACPI_DP_UUID) */
+				ret = acpigen_write_uuid(ctx, ACPI_DP_UUID);
+				if (ret)
+					return log_msg_ret("touuid", ret);
+				/*
+				 * Package (PROP), element count determined as
+				 * it is populated
+				 */
+				prop_count = acpigen_write_package(ctx, 0);
+			}
+			(*prop_count)++;
+			acpi_dp_write_property(ctx, dp);
+		}
+	}
+
+	if (prop_count) {
+		/* Package (PROP) length, if a package was written */
+		acpigen_pop_len(ctx);
+	}
+
+	if (child_count) {
+		/* Update DP package count to 2 or 4 */
+		*dp_count += 2;
+		/* ToUUID (ACPI_DP_CHILD_UUID) */
+		ret = acpigen_write_uuid(ctx, ACPI_DP_CHILD_UUID);
+		if (ret)
+			return log_msg_ret("child uuid", ret);
+
+		/* Print child pointer properties */
+		acpigen_write_package(ctx, child_count);
+
+		for (dp = prop; dp; dp = dp->next)
+			if (dp->type == ACPI_DP_TYPE_CHILD)
+				acpi_dp_write_property(ctx, dp);
+		/* Package (CHILD) length */
+		acpigen_pop_len(ctx);
+	}
+
+	/* Package (DP) length */
+	acpigen_pop_len(ctx);
+
+	/* Recursively parse children into separate tables */
+	for (dp = prop; dp; dp = dp->next) {
+		if (dp->type == ACPI_DP_TYPE_CHILD) {
+			ret = acpi_dp_write_(ctx, dp->child);
+			if (ret)
+				return log_msg_ret("dp child", ret);
+		}
+	}
+
+	return 0;
+}
+
+int acpi_dp_write(struct acpi_ctx *ctx, struct acpi_dp *table)
+{
+	int ret;
+
+	ret = acpi_dp_write_(ctx, table);
+
+	/* Clean up */
+	acpi_dp_free(table);
+
+	if (ret)
+		return log_msg_ret("write", ret);
+
+	return 0;
+}
+
+static struct acpi_dp *acpi_dp_new(struct acpi_dp *dp, enum acpi_dp_type type,
+				   const char *name)
+{
+	struct acpi_dp *new;
+
+	assert(name);
+	new = malloc(sizeof(struct acpi_dp));
+	if (!new)
+		return NULL;
+
+	memset(new, '\0', sizeof(*new));
+	new->type = type;
+	new->name = name;
+
+	if (dp) {
+		/* Add to end of property list */
+		while (dp->next)
+			dp = dp->next;
+		dp->next = new;
+	}
+
+	return new;
+}
+
+struct acpi_dp *acpi_dp_new_table(const char *name)
+{
+	return acpi_dp_new(NULL, ACPI_DP_TYPE_TABLE, name);
+}
+
+struct acpi_dp *acpi_dp_add_integer(struct acpi_dp *dp, const char *name,
+				    u64 value)
+{
+	struct acpi_dp *new;
+
+	assert(dp);
+	new = acpi_dp_new(dp, ACPI_DP_TYPE_INTEGER, name);
+
+	if (new)
+		new->integer = value;
+
+	return new;
+}
+
+struct acpi_dp *acpi_dp_add_string(struct acpi_dp *dp, const char *name,
+				   const char *string)
+{
+	struct acpi_dp *new;
+
+	assert(dp);
+	new = acpi_dp_new(dp, ACPI_DP_TYPE_STRING, name);
+	if (new)
+		new->string = string;
+
+	return new;
+}
+
+struct acpi_dp *acpi_dp_add_reference(struct acpi_dp *dp, const char *name,
+				      const char *reference)
+{
+	struct acpi_dp *new;
+
+	assert(dp);
+	new = acpi_dp_new(dp, ACPI_DP_TYPE_REFERENCE, name);
+	if (new)
+		new->string = reference;
+
+	return new;
+}
+
+struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name,
+				  struct acpi_dp *child)
+{
+	struct acpi_dp *new;
+
+	assert(dp);
+	assert(name);
+	if (child->type != ACPI_DP_TYPE_TABLE)
+		return NULL;
+
+	new = acpi_dp_new(dp, ACPI_DP_TYPE_CHILD, name);
+	if (new) {
+		new->child = child;
+		new->string = child->name;
+	}
+
+	return new;
+}
+
+struct acpi_dp *acpi_dp_add_array(struct acpi_dp *dp, struct acpi_dp *array)
+{
+	struct acpi_dp *new;
+
+	assert(dp);
+	assert(array);
+	if (array->type != ACPI_DP_TYPE_TABLE)
+		return NULL;
+
+	new = acpi_dp_new(dp, ACPI_DP_TYPE_ARRAY, array->name);
+	if (new)
+		new->array = array;
+
+	return new;
+}
+
+struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
+					  u64 *array, int len)
+{
+	struct acpi_dp *dp_array;
+	int i;
+
+	assert(dp);
+	if (len <= 0)
+		return NULL;
+
+	dp_array = acpi_dp_new_table(name);
+	if (!dp_array)
+		return NULL;
+
+	for (i = 0; i < len; i++)
+		if (!acpi_dp_add_integer(dp_array, NULL, array[i]))
+			break;
+
+	acpi_dp_add_array(dp, dp_array);
+
+	return dp_array;
+}
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index f781ad4d87..7321a98c0f 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -15,6 +15,9 @@
 #include <acpi/acpigen.h>
 #include <dm/acpi.h>
 
+/* CPU path format */
+#define ACPI_CPU_STRING "\\_PR.CP%02d"
+
 u8 *acpigen_get_current(struct acpi_ctx *ctx)
 {
 	return ctx->current;
diff --git a/test/dm/Makefile b/test/dm/Makefile
index e3e0cccf01..eb62faa0e3 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_UT_DM) += core.o
 ifneq ($(CONFIG_SANDBOX),)
 obj-$(CONFIG_ACPIGEN) += acpi.o
 obj-$(CONFIG_ACPIGEN) += acpigen.o
+obj-$(CONFIG_ACPIGEN) += acpi_dp.o
 obj-$(CONFIG_SOUND) += audio.o
 obj-$(CONFIG_BLK) += blk.o
 obj-$(CONFIG_BOARD) += board.o
diff --git a/test/dm/acpi_dp.c b/test/dm/acpi_dp.c
new file mode 100644
index 0000000000..c11394786f
--- /dev/null
+++ b/test/dm/acpi_dp.c
@@ -0,0 +1,405 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Tests for ACPI code generation via a device-property table
+ *
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <uuid.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_dp.h>
+#include <asm/unaligned.h>
+#include <dm/acpi.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+#define TEST_INT8	0x7d
+#define TEST_INT16	0x2345
+#define TEST_INT32	0x12345678
+#define TEST_INT64	0x4567890123456
+#define TEST_STR	"testing acpi strings"
+#define TEST_REF	"\\SB.I2C0.TPM2"
+#define EXPECT_REF	"SB__I2C0TPM2"
+
+static int alloc_context(struct acpi_ctx **ctxp)
+{
+	struct acpi_ctx *ctx;
+
+	*ctxp = NULL;
+	ctx = malloc(sizeof(*ctx));
+	if (!ctx)
+		return -ENOMEM;
+	memset(ctx, '\0', sizeof(*ctx));
+	ctx->current = malloc(500);
+	if (!ctx->current)
+		return -ENOMEM;
+	*ctxp = ctx;
+
+	return 0;
+}
+
+static void free_context(struct acpi_ctx **ctxp)
+{
+	free(*ctxp);
+	*ctxp = NULL;
+}
+
+/**
+ * get_length() - decode a three-byte length field
+ *
+ * @ptr: Length encoded as per ACPI
+ * @return decoded length, or -EINVAL on error
+ */
+static int get_length(u8 *ptr)
+{
+	if (!(*ptr & 0x80))
+		return -EINVAL;
+
+	return (*ptr & 0xf) | ptr[1] << 4 | ptr[2] << 12;
+}
+
+/* Test emitting an empty table */
+static int dm_test_acpi_dp_new_table(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	struct acpi_dp *dp;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	dp = acpi_dp_new_table("FRED");
+	ut_assertnonnull(dp);
+
+	ptr = acpigen_get_current(ctx);
+	ut_assertok(acpi_dp_write(ctx, dp));
+	ut_asserteq(10, acpigen_get_current(ctx) - ptr);
+	ut_asserteq(NAME_OP, *(u8 *)ptr);
+	ut_asserteq_strn("FRED", (char *)ptr + 1);
+	ut_asserteq(PACKAGE_OP, ptr[5]);
+	ut_asserteq(4, get_length(ptr + 6));
+	ut_asserteq(0, ptr[9]);
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_dp_new_table, 0);
+
+/* Test emitting an integer */
+static int dm_test_acpi_dp_int(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	char uuid[UUID_STR_LEN + 1];
+	struct acpi_dp *dp;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	dp = acpi_dp_new_table("FRED");
+	ut_assertnonnull(dp);
+	ut_assertnonnull(acpi_dp_add_integer(dp, "MARY", TEST_INT32));
+
+	ptr = acpigen_get_current(ctx);
+	ut_assertok(acpi_dp_write(ctx, dp));
+	ut_asserteq(54, acpigen_get_current(ctx) - ptr);
+	ut_asserteq(NAME_OP, *(u8 *)ptr);
+	ut_asserteq_strn("FRED", (char *)ptr + 1);
+	ut_asserteq(PACKAGE_OP, ptr[5]);
+	ut_asserteq(48, get_length(ptr + 6));
+	ut_asserteq(2, ptr[9]);
+
+	/* UUID */
+	ut_asserteq(BUFFER_OP, ptr[10]);
+	ut_asserteq(22, get_length(ptr + 11));
+	ut_asserteq(WORD_PREFIX, ptr[14]);
+	ut_asserteq(16, get_unaligned((u16 *)(ptr + 15)));
+	uuid_bin_to_str(ptr + 17, uuid, 1);
+	ut_asserteq_str(ACPI_DP_UUID, uuid);
+
+	/* Container package */
+	ut_asserteq(PACKAGE_OP, ptr[33]);
+	ut_asserteq(20, get_length(ptr + 34));
+	ut_asserteq(1, ptr[37]);
+
+	/* Package with name and (integer) value */
+	ut_asserteq(PACKAGE_OP, ptr[38]);
+	ut_asserteq(15, get_length(ptr + 39));
+	ut_asserteq(2, ptr[42]);
+	ut_asserteq(STRING_PREFIX, ptr[43]);
+	ut_asserteq_str("MARY", (char *)ptr + 44);
+
+	ut_asserteq(DWORD_PREFIX, ptr[49]);
+	ut_asserteq(TEST_INT32, get_unaligned((u32 *)(ptr + 50)));
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_dp_int, 0);
+
+/* Test emitting a 64-bit integer */
+static int dm_test_acpi_dp_int64(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	struct acpi_dp *dp;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	dp = acpi_dp_new_table("FRED");
+	ut_assertnonnull(dp);
+	ut_assertnonnull(acpi_dp_add_integer(dp, "MARY", TEST_INT64));
+
+	ptr = acpigen_get_current(ctx);
+	ut_assertok(acpi_dp_write(ctx, dp));
+	ut_asserteq(58, acpigen_get_current(ctx) - ptr);
+
+	ut_asserteq(QWORD_PREFIX, ptr[49]);
+	ut_asserteq_64(TEST_INT64, get_unaligned((u64 *)(ptr + 50)));
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_dp_int64, 0);
+
+/* Test emitting a 16-bit integer */
+static int dm_test_acpi_dp_int16(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	struct acpi_dp *dp;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	dp = acpi_dp_new_table("FRED");
+	ut_assertnonnull(dp);
+	ut_assertnonnull(acpi_dp_add_integer(dp, "MARY", TEST_INT16));
+
+	ptr = acpigen_get_current(ctx);
+	ut_assertok(acpi_dp_write(ctx, dp));
+	ut_asserteq(52, acpigen_get_current(ctx) - ptr);
+
+	ut_asserteq(WORD_PREFIX, ptr[49]);
+	ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 50)));
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_dp_int16, 0);
+
+/* Test emitting a 8-bit integer */
+static int dm_test_acpi_dp_int8(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	struct acpi_dp *dp;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	dp = acpi_dp_new_table("FRED");
+	ut_assertnonnull(dp);
+	ut_assertnonnull(acpi_dp_add_integer(dp, "MARY", TEST_INT8));
+
+	ptr = acpigen_get_current(ctx);
+	ut_assertok(acpi_dp_write(ctx, dp));
+	ut_asserteq(51, acpigen_get_current(ctx) - ptr);
+
+	ut_asserteq(BYTE_PREFIX, ptr[49]);
+	ut_asserteq(TEST_INT8, ptr[50]);
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_dp_int8, 0);
+
+/* Test emitting multiple values */
+static int dm_test_acpi_dp_multiple(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	struct acpi_dp *dp;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	dp = acpi_dp_new_table("FRED");
+	ut_assertnonnull(dp);
+	ut_assertnonnull(acpi_dp_add_integer(dp, "int16", TEST_INT16));
+	ut_assertnonnull(acpi_dp_add_string(dp, "str", TEST_STR));
+	ut_assertnonnull(acpi_dp_add_reference(dp, "ref", TEST_REF));
+
+	ptr = acpigen_get_current(ctx);
+	ut_assertok(acpi_dp_write(ctx, dp));
+	ut_asserteq(110, acpigen_get_current(ctx) - ptr);
+
+	ut_asserteq(WORD_PREFIX, ptr[0x32]);
+	ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 0x33)));
+	ut_asserteq(STRING_PREFIX, ptr[0x3f]);
+	ut_asserteq_str(TEST_STR, (char *)ptr + 0x40);
+	ut_asserteq(ROOT_PREFIX, ptr[0x5f]);
+	ut_asserteq(MULTI_NAME_PREFIX, ptr[0x60]);
+	ut_asserteq(3, ptr[0x61]);
+	ut_asserteq_strn(EXPECT_REF, (char *)ptr + 0x62);
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_dp_multiple, 0);
+
+/* Test emitting an array */
+static int dm_test_acpi_dp_array(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	struct acpi_dp *dp;
+	u64 speed[4];
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	dp = acpi_dp_new_table("FRED");
+	ut_assertnonnull(dp);
+	speed[0] = TEST_INT8;
+	speed[1] = TEST_INT16;
+	speed[2] = TEST_INT32;
+	speed[3] = TEST_INT64;
+	ut_assertnonnull(acpi_dp_add_integer_array(dp, "speeds", speed,
+						   ARRAY_SIZE(speed)));
+
+	ptr = acpigen_get_current(ctx);
+	ut_assertok(acpi_dp_write(ctx, dp));
+	ut_asserteq(75, acpigen_get_current(ctx) - ptr);
+
+	ut_asserteq(BYTE_PREFIX, ptr[0x38]);
+	ut_asserteq(TEST_INT8, ptr[0x39]);
+
+	ut_asserteq(WORD_PREFIX, ptr[0x3a]);
+	ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 0x3b)));
+
+	ut_asserteq(DWORD_PREFIX, ptr[0x3d]);
+	ut_asserteq(TEST_INT32, get_unaligned((u32 *)(ptr + 0x3e)));
+
+	ut_asserteq(QWORD_PREFIX, ptr[0x42]);
+	ut_asserteq_64(TEST_INT64, get_unaligned((u64 *)(ptr + 0x43)));
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_dp_array, 0);
+
+/* Test emitting a child */
+static int dm_test_acpi_dp_child(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	struct acpi_dp *dp, *child1, *child2;
+	char uuid[UUID_STR_LEN + 1];
+	u8 *ptr, *pptr;
+	int i;
+
+	ut_assertok(alloc_context(&ctx));
+
+	child1 = acpi_dp_new_table("child");
+	ut_assertnonnull(child1);
+	ut_assertnonnull(acpi_dp_add_integer(child1, "height", TEST_INT16));
+
+	child2 = acpi_dp_new_table("child");
+	ut_assertnonnull(child2);
+	ut_assertnonnull(acpi_dp_add_integer(child2, "age", TEST_INT8));
+
+	dp = acpi_dp_new_table("FRED");
+	ut_assertnonnull(dp);
+
+	ut_assertnonnull(acpi_dp_add_child(dp, "anna", child1));
+	ut_assertnonnull(acpi_dp_add_child(dp, "john", child2));
+
+	ptr = acpigen_get_current(ctx);
+	ut_assertok(acpi_dp_write(ctx, dp));
+	ut_asserteq(178, acpigen_get_current(ctx) - ptr);
+
+	/* UUID for child extension using Hierarchical Data Extension UUID */
+	ut_asserteq(BUFFER_OP, ptr[10]);
+	ut_asserteq(22, get_length(ptr + 11));
+	ut_asserteq(WORD_PREFIX, ptr[14]);
+	ut_asserteq(16, get_unaligned((u16 *)(ptr + 15)));
+	uuid_bin_to_str(ptr + 17, uuid, 1);
+	ut_asserteq_str(ACPI_DP_CHILD_UUID, uuid);
+
+	/* Package with two children */
+	ut_asserteq(PACKAGE_OP, ptr[0x21]);
+	ut_asserteq(0x28, get_length(ptr + 0x22));
+	ut_asserteq(2, ptr[0x25]);
+
+	/* First we expect the two children as string/value */
+	pptr = ptr + 0x26;
+	for (i = 0; i < 2; i++) {
+		ut_asserteq(PACKAGE_OP, pptr[0]);
+		ut_asserteq(0x11, get_length(pptr + 1));
+		ut_asserteq(2, pptr[4]);
+		ut_asserteq(STRING_PREFIX, pptr[5]);
+		ut_asserteq_str(i ? "john" : "anna", (char *)pptr + 6);
+		ut_asserteq(STRING_PREFIX, pptr[11]);
+		ut_asserteq_str("child", (char *)pptr + 12);
+		pptr += 0x12;
+	}
+
+	/* Write the two children */
+	ut_asserteq(0x4a, pptr - ptr);
+	for (i = 0; i < 2; i++) {
+		const char *prop = i ? "age" : "height";
+		const int datalen = i ? 1 : 2;
+		int len = strlen(prop) + 1;
+
+		ut_asserteq(NAME_OP, pptr[0]);
+		ut_asserteq_strn("chil", (char *)pptr + 1);
+		ut_asserteq(PACKAGE_OP, pptr[5]);
+		ut_asserteq(0x27 + len + datalen, get_length(pptr + 6));
+		ut_asserteq(2, pptr[9]);
+
+		/* UUID */
+		ut_asserteq(BUFFER_OP, pptr[10]);
+		ut_asserteq(22, get_length(pptr + 11));
+		ut_asserteq(WORD_PREFIX, pptr[14]);
+		ut_asserteq(16, get_unaligned((u16 *)(pptr + 15)));
+		uuid_bin_to_str(pptr + 17, uuid, 1);
+		ut_asserteq_str(ACPI_DP_UUID, uuid);
+		pptr += 33;
+
+		/* Containing package */
+		ut_asserteq(i ? 0xa1 : 0x6b, pptr - ptr);
+		ut_asserteq(PACKAGE_OP, pptr[0]);
+		ut_asserteq(0xb + len + datalen, get_length(pptr + 1));
+		ut_asserteq(1, pptr[4]);
+
+		/* Package containing the property-name string and the value */
+		pptr += 5;
+		ut_asserteq(i ? 0xa6 : 0x70, pptr - ptr);
+		ut_asserteq(PACKAGE_OP, pptr[0]);
+		ut_asserteq(6 + len + datalen, get_length(pptr + 1));
+		ut_asserteq(2, pptr[4]);
+
+		ut_asserteq(STRING_PREFIX, pptr[5]);
+		ut_asserteq_str(i ? "age" : "height", (char *)pptr + 6);
+		pptr += 6 + len;
+		if (i) {
+			ut_asserteq(BYTE_PREFIX, pptr[0]);
+			ut_asserteq(TEST_INT8, pptr[1]);
+		} else {
+			ut_asserteq(WORD_PREFIX, pptr[0]);
+			ut_asserteq(TEST_INT16,
+				    get_unaligned((u16 *)(pptr + 1)));
+		}
+		pptr += 1 + datalen;
+	}
+	ut_asserteq(178, pptr - ptr);
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_dp_child, 0);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 20/35] acpi: Support writing a GPIO
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (18 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 19/35] acpi: Support writing Device Properties objects via _DSD Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 21/35] acpi: Support copying properties from device tree to ACPI Simon Glass
                   ` (48 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

Allowing writing out a reference to a GPIO within the ACPI output. This
can be used by ACPI code to access a GPIO at runtime.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpi_dp.h | 18 ++++++++++++++++++
 lib/acpi/acpi_dp.c     | 21 +++++++++++++++++++++
 test/dm/acpi_dp.c      | 39 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 78 insertions(+)

diff --git a/include/acpi/acpi_dp.h b/include/acpi/acpi_dp.h
index 840be855c5..f42602405a 100644
--- a/include/acpi/acpi_dp.h
+++ b/include/acpi/acpi_dp.h
@@ -202,6 +202,24 @@ struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
 struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name,
 				  struct acpi_dp *child);
 
+/**
+ * acpi_dp_add_gpio() - Add a GPIO to a list of Device Properties
+ *
+ * A new node is added to the end of the property list of @dp, with the
+ * GPIO properties added to the the new node
+ *
+ * @dp: Table to add this property to
+ * @name: Name of property
+ * @ref: Reference to device with a _CRS containing GpioIO or GpioInt
+ * @index: Index of the GPIO resource in _CRS starting from zero
+ * @pin: Pin in the GPIO resource, typically zero
+ * @active_low: true if pin is active low
+ * @return pointer to new node, or NULL if out of memory
+ */
+struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
+				 const char *ref, int index, int pin,
+				 bool active_low);
+
 /**
  * acpi_dp_write() - Write Device Property hierarchy and clean up resources
  *
diff --git a/lib/acpi/acpi_dp.c b/lib/acpi/acpi_dp.c
index 479cb6743c..4ba5d555a0 100644
--- a/lib/acpi/acpi_dp.c
+++ b/lib/acpi/acpi_dp.c
@@ -322,3 +322,24 @@ struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
 
 	return dp_array;
 }
+
+struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
+				 const char *ref, int index, int pin,
+				 bool active_low)
+{
+	struct acpi_dp *gpio;
+
+	assert(dp);
+	gpio = acpi_dp_new_table(name);
+	if (!gpio)
+		return NULL;
+
+	acpi_dp_add_reference(gpio, NULL, ref);
+	acpi_dp_add_integer(gpio, NULL, index);
+	acpi_dp_add_integer(gpio, NULL, pin);
+	acpi_dp_add_integer(gpio, NULL, active_low);
+
+	acpi_dp_add_array(dp, gpio);
+
+	return gpio;
+}
diff --git a/test/dm/acpi_dp.c b/test/dm/acpi_dp.c
index c11394786f..d6a054a98b 100644
--- a/test/dm/acpi_dp.c
+++ b/test/dm/acpi_dp.c
@@ -403,3 +403,42 @@ static int dm_test_acpi_dp_child(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_dp_child, 0);
+
+/* Test emitting a GPIO */
+static int dm_test_acpi_dp_gpio(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	struct acpi_dp *dp;
+	u8 *ptr, *pptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	dp = acpi_dp_new_table("FRED");
+	ut_assertnonnull(dp);
+
+	/* Try a few different parameters */
+	ut_assertnonnull(acpi_dp_add_gpio(dp, "reset", TEST_REF, 0x23, 0x24,
+					  false));
+	ut_assertnonnull(acpi_dp_add_gpio(dp, "allow", TEST_REF, 0, 0, true));
+
+	ptr = acpigen_get_current(ctx);
+	ut_assertok(acpi_dp_write(ctx, dp));
+	ut_asserteq(0x6e, acpigen_get_current(ctx) - ptr);
+
+	pptr = ptr + 0x2c; //0x3a;
+	ut_asserteq_str("reset", (char *)pptr);
+	ut_asserteq_strn(EXPECT_REF, (char *)pptr + 0xe);
+	ut_asserteq(0x23, pptr[0x1b]);
+	ut_asserteq(0x24, pptr[0x1d]);
+	ut_asserteq(ZERO_OP, pptr[0x1e]);
+
+	pptr = ptr + 0x51;
+	ut_asserteq_str("allow", (char *)pptr);
+	ut_asserteq_strn(EXPECT_REF, (char *)pptr + 0xe);
+	ut_asserteq(ZERO_OP, pptr[0x1a]);
+	ut_asserteq(ZERO_OP, pptr[0x1b]);
+	ut_asserteq(ONE_OP, pptr[0x1c]);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_dp_gpio, 0);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 21/35] acpi: Support copying properties from device tree to ACPI
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (19 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 20/35] acpi: Support writing a GPIO Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 22/35] acpi: Add support for various misc ACPI opcodes Simon Glass
                   ` (47 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

Some drivers in Linux support both device tree and ACPI. U-Boot itself
uses Linux device-tree bindings for its own configuration but does not use
ACPI.

It is convenient to copy these values over to the device tree for passing
to linux. Add some convenience functions to help with this.

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

Changes in v2: None
Changes in v1: None

 arch/sandbox/dts/test.dts |  1 +
 include/acpi/acpi_dp.h    | 50 +++++++++++++++++++++++++++++
 lib/acpi/acpi_dp.c        | 52 ++++++++++++++++++++++++++++++
 test/dm/acpi_dp.c         | 67 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 170 insertions(+)

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index b802c1c909..a90395fa62 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -109,6 +109,7 @@
 		uint-value = <(-1234)>;
 		int64-value = /bits/ 64 <0x1111222233334444>;
 		int-array = <5678 9123 4567>;
+		str-value = "test string";
 		interrupts-extended = <&irq 3 0>;
 	};
 
diff --git a/include/acpi/acpi_dp.h b/include/acpi/acpi_dp.h
index f42602405a..9e5a70b286 100644
--- a/include/acpi/acpi_dp.h
+++ b/include/acpi/acpi_dp.h
@@ -230,4 +230,54 @@ struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
  */
 int acpi_dp_write(struct acpi_ctx *ctx, struct acpi_dp *table);
 
+/**
+ * acpi_dp_ofnode_copy_int() - Copy a property from device tree to DP
+ *
+ * This copies an integer property from the device tree to the ACPI DP table.
+ *
+ * @dev: Device to copy from
+ * @dp: DP to copy to
+ * @prop: Property name to copy
+ * @return 0 if OK, -ve on error
+ */
+int acpi_dp_ofnode_copy_int(ofnode node, struct acpi_dp *dp, const char *prop);
+
+/**
+ * acpi_dp_dev_copy_str() - Copy a property from device tree to DP
+ *
+ * This copies a string property from the device tree to the ACPI DP table.
+ *
+ * @dev: Device to copy from
+ * @dp: DP to copy to
+ * @prop: Property name to copy
+ * @return 0 if OK, -ve on error
+ */
+int acpi_dp_ofnode_copy_str(ofnode node, struct acpi_dp *dp, const char *prop);
+
+/**
+ * acpi_dp_dev_copy_int() - Copy a property from device tree to DP
+ *
+ * This copies an integer property from the device tree to the ACPI DP table.
+ *
+ * @dev: Device to copy from
+ * @dp: DP to copy to
+ * @prop: Property name to copy
+ * @return 0 if OK, -ve on error
+ */
+int acpi_dp_dev_copy_int(const struct udevice *dev, struct acpi_dp *dp,
+			 const char *prop);
+
+/**
+ * acpi_dp_dev_copy_str() - Copy a property from device tree to DP
+ *
+ * This copies a string property from the device tree to the ACPI DP table.
+ *
+ * @dev: Device to copy from
+ * @dp: DP to copy to
+ * @prop: Property name to copy
+ * @return 0 if OK, -ve on error
+ */
+int acpi_dp_dev_copy_str(const struct udevice *dev, struct acpi_dp *dp,
+			 const char *prop);
+
 #endif
diff --git a/lib/acpi/acpi_dp.c b/lib/acpi/acpi_dp.c
index 4ba5d555a0..819e51005a 100644
--- a/lib/acpi/acpi_dp.c
+++ b/lib/acpi/acpi_dp.c
@@ -343,3 +343,55 @@ struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
 
 	return gpio;
 }
+
+int acpi_dp_ofnode_copy_int(ofnode node, struct acpi_dp *dp, const char *prop)
+{
+	int ret;
+	u32 val = 0;
+
+	ret = ofnode_read_u32(node, prop, &val);
+	if (ret)
+		return ret;
+	acpi_dp_add_integer(dp, prop, val);
+
+	return ret;
+}
+
+int acpi_dp_ofnode_copy_str(ofnode node, struct acpi_dp *dp, const char *prop)
+{
+	const char *val;
+
+	val = ofnode_read_string(node, prop);
+	if (!val)
+		return -EINVAL;
+	acpi_dp_add_string(dp, prop, val);
+
+	return 0;
+}
+
+int acpi_dp_dev_copy_int(const struct udevice *dev, struct acpi_dp *dp,
+			 const char *prop)
+{
+	int ret;
+	u32 val = 0;
+
+	ret = dev_read_u32(dev, prop, &val);
+	if (ret)
+		return ret;
+	acpi_dp_add_integer(dp, prop, val);
+
+	return ret;
+}
+
+int acpi_dp_dev_copy_str(const struct udevice *dev, struct acpi_dp *dp,
+			 const char *prop)
+{
+	const char *val;
+
+	val = dev_read_string(dev, prop);
+	if (!val)
+		return -EINVAL;
+	acpi_dp_add_string(dp, prop, val);
+
+	return 0;
+}
diff --git a/test/dm/acpi_dp.c b/test/dm/acpi_dp.c
index d6a054a98b..c1ab580cd2 100644
--- a/test/dm/acpi_dp.c
+++ b/test/dm/acpi_dp.c
@@ -442,3 +442,70 @@ static int dm_test_acpi_dp_gpio(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_dp_gpio, 0);
+
+/* Test copying info from the device tree to ACPI tables */
+static int dm_test_acpi_dp_copy(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	struct udevice *dev;
+	struct acpi_dp *dp;
+	ofnode node;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	dp = acpi_dp_new_table("FRED");
+	ut_assertnonnull(dp);
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("a-test", dev->name);
+
+	ut_assertok(acpi_dp_dev_copy_int(dev, dp, "int-value"));
+	ut_asserteq(-EINVAL, acpi_dp_dev_copy_int(dev, dp, "missing-value"));
+	ut_assertok(acpi_dp_dev_copy_int(dev, dp, "uint-value"));
+
+	ut_assertok(acpi_dp_dev_copy_str(dev, dp, "str-value"));
+	ut_asserteq(-EINVAL, acpi_dp_dev_copy_str(dev, dp, "missing-value"));
+
+	node = ofnode_path("/chosen");
+	ut_assert(ofnode_valid(node));
+	ut_assertok(acpi_dp_ofnode_copy_int(node, dp, "int-values"));
+	ut_asserteq(-EINVAL,
+		    acpi_dp_ofnode_copy_int(node, dp, "missing-value"));
+
+	ut_assertok(acpi_dp_ofnode_copy_str(node, dp, "setting"));
+	ut_asserteq(-EINVAL,
+		    acpi_dp_ofnode_copy_str(node, dp, "missing-value"));
+
+	ptr = acpigen_get_current(ctx);
+	ut_assertok(acpi_dp_write(ctx, dp));
+	ut_asserteq(0x9d, acpigen_get_current(ctx) - ptr);
+
+	ut_asserteq(STRING_PREFIX, ptr[0x2b]);
+	ut_asserteq_str("int-value", (char *)ptr + 0x2c);
+	ut_asserteq(WORD_PREFIX, ptr[0x36]);
+	ut_asserteq(1234, get_unaligned((u16 *)(ptr + 0x37)));
+
+	ut_asserteq(STRING_PREFIX, ptr[0x3e]);
+	ut_asserteq_str("uint-value", (char *)ptr + 0x3f);
+	ut_asserteq(DWORD_PREFIX, ptr[0x4a]);
+	ut_asserteq(-1234, get_unaligned((u32 *)(ptr + 0x4b)));
+
+	ut_asserteq(STRING_PREFIX, ptr[0x54]);
+	ut_asserteq_str("str-value", (char *)ptr + 0x55);
+	ut_asserteq(STRING_PREFIX, ptr[0x5f]);
+	ut_asserteq_str("test string", (char *)ptr + 0x60);
+
+	ut_asserteq(STRING_PREFIX, ptr[0x71]);
+	ut_asserteq_str("int-values", (char *)ptr + 0x72);
+	ut_asserteq(WORD_PREFIX, ptr[0x7d]);
+	ut_asserteq(0x1937, get_unaligned((u16 *)(ptr + 0x7e)));
+
+	ut_asserteq(STRING_PREFIX, ptr[0x85]);
+	ut_asserteq_str("setting", (char *)ptr + 0x86);
+	ut_asserteq(STRING_PREFIX, ptr[0x8e]);
+	ut_asserteq_str("sunrise ohoka", (char *)(ptr + 0x8f));
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_dp_copy, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 22/35] acpi: Add support for various misc ACPI opcodes
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (20 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 21/35] acpi: Support copying properties from device tree to ACPI Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 23/35] acpi: Add support for writing a Power Resource Simon Glass
                   ` (46 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

Add more functions to handle some miscellaneous ACPI opcodes.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpigen.h | 114 +++++++++++++++++++++++++++++++++++++++++
 lib/acpi/acpigen.c     |  83 ++++++++++++++++++++++++++++++
 test/dm/acpigen.c      |  75 +++++++++++++++++++++++++++
 3 files changed, 272 insertions(+)

diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
index 16b33ebe66..c595bb9efa 100644
--- a/include/acpi/acpigen.h
+++ b/include/acpi/acpigen.h
@@ -26,9 +26,26 @@ enum {
 	QWORD_PREFIX		= 0x0e,
 	BUFFER_OP		= 0x11,
 	PACKAGE_OP		= 0x12,
+	METHOD_OP		= 0x14,
+	SLEEP_OP		= 0x22,
 	DUAL_NAME_PREFIX	= 0x2e,
 	MULTI_NAME_PREFIX	= 0x2f,
+	DEBUG_OP		= 0x31,
+	EXT_OP_PREFIX		= 0x5b,
 	ROOT_PREFIX		= 0x5c,
+	LOCAL0_OP		= 0x60,
+	LOCAL1_OP		= 0x61,
+	LOCAL2_OP		= 0x62,
+	LOCAL3_OP		= 0x63,
+	LOCAL4_OP		= 0x64,
+	LOCAL5_OP		= 0x65,
+	LOCAL6_OP		= 0x66,
+	LOCAL7_OP		= 0x67,
+	STORE_OP		= 0x70,
+	AND_OP			= 0x7b,
+	OR_OP			= 0x7d,
+	NOT_OP			= 0x80,
+	RETURN_OP		= 0xa4,
 };
 
 /**
@@ -196,4 +213,101 @@ void acpigen_write_name(struct acpi_ctx *ctx, const char *namepath);
  */
 int acpigen_write_uuid(struct acpi_ctx *ctx, const char *uuid);
 
+/**
+ * acpigen_emit_ext_op() - Emit an extended op with the EXT_OP_PREFIX prefix
+ *
+ * @ctx: ACPI context pointer
+ * @op: Operation code (e.g. SLEEP_OP)
+ */
+void acpigen_emit_ext_op(struct acpi_ctx *ctx, uint op);
+
+/**
+ * acpigen_write_method() - Write a method header
+ *
+ * @ctx: ACPI context pointer
+ * @name: Method name (4 characters)
+ * @nargs: Number of method arguments (0 if none)
+ */
+void acpigen_write_method(struct acpi_ctx *ctx, const char *name, int nargs);
+
+/**
+ * acpigen_write_method_serialized() - Write a method header
+ *
+ * This sets the 'serialized' flag so that the method is thread-safe
+ *
+ * @ctx: ACPI context pointer
+ * @name: Method name (4 characters)
+ * @nargs: Number of method arguments (0 if none)
+ */
+void acpigen_write_method_serialized(struct acpi_ctx *ctx, const char *name,
+				     int nargs);
+
+/**
+ * acpigen_write_sta() - Write a _STA method
+ *
+ * @ctx: ACPI context pointer
+ * @status: Status value to return
+ */
+void acpigen_write_sta(struct acpi_ctx *ctx, uint status);
+
+/**
+ * acpigen_write_sleep() - Write a sleep operation
+ *
+ * @ctx: ACPI context pointer
+ * @sleep_ms: Number of milliseconds to sleep for
+ */
+void acpigen_write_sleep(struct acpi_ctx *ctx, u64 sleep_ms);
+
+/**
+ * acpigen_write_store() - Write a store operation
+ *
+ * @ctx: ACPI context pointer
+ */
+void acpigen_write_store(struct acpi_ctx *ctx);
+
+/**
+ * acpigen_write_debug_string() - Write a debug string
+ *
+ * This writes a debug operation with an associated string
+ *
+ * @ctx: ACPI context pointer
+ * @str: String to write
+ */
+void acpigen_write_debug_string(struct acpi_ctx *ctx, const char *str);
+
+/**
+ * acpigen_write_or() - Write a bitwise OR operation
+ *
+ * res = arg1 | arg2
+ *
+ * @ctx: ACPI context pointer
+ * @arg1: ACPI opcode for operand 1 (e.g. LOCAL0_OP)
+ * @arg2: ACPI opcode for operand 2 (e.g. LOCAL1_OP)
+ * @res: ACPI opcode for result (e.g. LOCAL2_OP)
+ */
+void acpigen_write_or(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res);
+
+/**
+ * acpigen_write_and() - Write a bitwise AND operation
+ *
+ * res = arg1 & arg2
+ *
+ * @ctx: ACPI context pointer
+ * @arg1: ACPI opcode for operand 1 (e.g. LOCAL0_OP)
+ * @arg2: ACPI opcode for operand 2 (e.g. LOCAL1_OP)
+ * @res: ACPI opcode for result (e.g. LOCAL2_OP)
+ */
+void acpigen_write_and(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res);
+
+/**
+ * acpigen_write_or() - Write a bitwise NOT operation
+ *
+ * res = ~arg1
+ *
+ * @ctx: ACPI context pointer
+ * @arg: ACPI opcode for operand (e.g. LOCAL0_OP)
+ * @res: ACPI opcode for result (e.g. LOCAL2_OP)
+ */
+void acpigen_write_not(struct acpi_ctx *ctx, u8 arg, u8 res);
+
 #endif
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index 7321a98c0f..57b295aa4e 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -74,6 +74,12 @@ void acpigen_pop_len(struct acpi_ctx *ctx)
 	p[2] = (len >> 12 & 0xff);
 }
 
+void acpigen_emit_ext_op(struct acpi_ctx *ctx, uint op)
+{
+	acpigen_emit_byte(ctx, EXT_OP_PREFIX);
+	acpigen_emit_byte(ctx, op);
+}
+
 char *acpigen_write_package(struct acpi_ctx *ctx, int nr_el)
 {
 	char *p;
@@ -253,6 +259,37 @@ void acpigen_write_name(struct acpi_ctx *ctx, const char *namepath)
 	acpigen_emit_namestring(ctx, namepath);
 }
 
+static void acpigen_write_method_(struct acpi_ctx *ctx, const char *name,
+				  uint flags)
+{
+	acpigen_emit_byte(ctx, METHOD_OP);
+	acpigen_write_len_f(ctx);
+	acpigen_emit_namestring(ctx, name);
+	acpigen_emit_byte(ctx, flags);
+}
+
+/* Method (name, nargs, NotSerialized) */
+void acpigen_write_method(struct acpi_ctx *ctx, const char *name, int nargs)
+{
+	acpigen_write_method_(ctx, name, nargs & 7);
+}
+
+/* Method (name, nargs, Serialized) */
+void acpigen_write_method_serialized(struct acpi_ctx *ctx, const char *name,
+				     int nargs)
+{
+	acpigen_write_method_(ctx, name, (nargs & 7) | (1 << 3));
+}
+
+void acpigen_write_sta(struct acpi_ctx *ctx, uint status)
+{
+	/* Method (_STA, 0, NotSerialized) { Return (status) } */
+	acpigen_write_method(ctx, "_STA", 0);
+	acpigen_emit_byte(ctx, RETURN_OP);
+	acpigen_write_byte(ctx, status);
+	acpigen_pop_len(ctx);
+}
+
 /*
  * ToUUID(uuid)
  *
@@ -290,3 +327,49 @@ int acpigen_write_uuid(struct acpi_ctx *ctx, const char *uuid)
 
 	return 0;
 }
+
+/* Sleep (ms) */
+void acpigen_write_sleep(struct acpi_ctx *ctx, u64 sleep_ms)
+{
+	acpigen_emit_ext_op(ctx, SLEEP_OP);
+	acpigen_write_integer(ctx, sleep_ms);
+}
+
+void acpigen_write_store(struct acpi_ctx *ctx)
+{
+	acpigen_emit_byte(ctx, STORE_OP);
+}
+
+/* Or (arg1, arg2, res) */
+void acpigen_write_or(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res)
+{
+	acpigen_emit_byte(ctx, OR_OP);
+	acpigen_emit_byte(ctx, arg1);
+	acpigen_emit_byte(ctx, arg2);
+	acpigen_emit_byte(ctx, res);
+}
+
+/* And (arg1, arg2, res) */
+void acpigen_write_and(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res)
+{
+	acpigen_emit_byte(ctx, AND_OP);
+	acpigen_emit_byte(ctx, arg1);
+	acpigen_emit_byte(ctx, arg2);
+	acpigen_emit_byte(ctx, res);
+}
+
+/* Not (arg, res) */
+void acpigen_write_not(struct acpi_ctx *ctx, u8 arg, u8 res)
+{
+	acpigen_emit_byte(ctx, NOT_OP);
+	acpigen_emit_byte(ctx, arg);
+	acpigen_emit_byte(ctx, res);
+}
+
+/* Store (str, DEBUG) */
+void acpigen_write_debug_string(struct acpi_ctx *ctx, const char *str)
+{
+	acpigen_write_store(ctx);
+	acpigen_write_string(ctx, str);
+	acpigen_emit_ext_op(ctx, DEBUG_OP);
+}
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index db8cad47d8..e059d6f80d 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -621,3 +621,78 @@ static int dm_test_acpi_uuid(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_uuid, 0);
+
+/* Test writing misc ACPI codes */
+static int dm_test_acpi_misc(struct unit_test_state *uts)
+{
+	struct acpi_ctx *ctx;
+	const int flags = 3;
+	const int nargs = 4;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+	acpigen_write_sleep(ctx, TEST_INT64);
+	ut_asserteq_64(TEST_INT64, get_unaligned((u64 *)(ptr + 3)));
+	ptr += 11;
+
+	acpigen_write_store(ctx);
+	ut_asserteq(STORE_OP, *ptr);
+	ptr++;
+
+	acpigen_write_debug_string(ctx, TEST_STRING);
+	ut_asserteq_str(TEST_STRING, (char *)ptr + 2);
+	ptr += 2 +  sizeof(TEST_STRING);
+	ut_asserteq(EXT_OP_PREFIX, ptr[0]);
+	ut_asserteq(DEBUG_OP, ptr[1]);
+	ptr += 2;
+
+	acpigen_write_sta(ctx, flags);
+	ut_asserteq(METHOD_OP, ptr[0]);
+	ut_asserteq(11, get_length(ptr + 1));
+	ut_asserteq_strn("_STA", (char *)ptr + 4);
+	ut_asserteq(0, ptr[8]);
+	ut_asserteq(RETURN_OP, ptr[9]);
+	ut_asserteq(BYTE_PREFIX, ptr[10]);
+	ut_asserteq(flags, ptr[11]);
+	ptr += 12;
+
+	acpigen_write_sleep(ctx, TEST_INT16);
+	ut_asserteq(SLEEP_OP, ptr[1]);
+	ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 3)));
+	ptr += 5;
+
+	acpigen_write_method_serialized(ctx, "FRED", nargs);
+	ut_asserteq(METHOD_OP, ptr[0]);
+	ut_asserteq_strn("FRED", (char *)ptr + 4);
+	ut_asserteq(1 << 3 | nargs, ptr[8]);
+	ut_asserteq(1, ctx->ltop);	/* method is unfinished */
+
+	ptr += 9;
+	acpigen_write_or(ctx, LOCAL0_OP, LOCAL1_OP, LOCAL2_OP);
+	acpigen_write_and(ctx, LOCAL3_OP, LOCAL4_OP, LOCAL5_OP);
+	acpigen_write_not(ctx, LOCAL6_OP, LOCAL7_OP);
+	ut_asserteq(OR_OP, ptr[0]);
+	ut_asserteq(LOCAL0_OP, ptr[1]);
+	ut_asserteq(LOCAL1_OP, ptr[2]);
+	ut_asserteq(LOCAL2_OP, ptr[3]);
+
+	ptr += 4;
+	ut_asserteq(AND_OP, ptr[0]);
+	ut_asserteq(LOCAL3_OP, ptr[1]);
+	ut_asserteq(LOCAL4_OP, ptr[2]);
+	ut_asserteq(LOCAL5_OP, ptr[3]);
+
+	ptr += 4;
+	ut_asserteq(NOT_OP, ptr[0]);
+	ut_asserteq(LOCAL6_OP, ptr[1]);
+	ut_asserteq(LOCAL7_OP, ptr[2]);
+	ptr += 3;
+	ut_asserteq_ptr(ptr, ctx->current);
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_misc, 0);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 23/35] acpi: Add support for writing a Power Resource
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (21 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 22/35] acpi: Add support for various misc ACPI opcodes Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 24/35] acpi: Add support for writing a GPIO power sequence Simon Glass
                   ` (45 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

These are used in ACPI to disable power to various pats of the system when
in sleep. Add a way to create a power resource, with the caller finishing
off the details.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpigen.h | 22 ++++++++++++++++++++++
 lib/acpi/acpigen.c     | 22 ++++++++++++++++++++++
 test/dm/acpigen.c      | 41 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 85 insertions(+)

diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
index c595bb9efa..7d9a02805b 100644
--- a/include/acpi/acpigen.h
+++ b/include/acpi/acpigen.h
@@ -45,6 +45,7 @@ enum {
 	AND_OP			= 0x7b,
 	OR_OP			= 0x7d,
 	NOT_OP			= 0x80,
+	POWER_RES_OP		= 0x84,
 	RETURN_OP		= 0xa4,
 };
 
@@ -310,4 +311,25 @@ void acpigen_write_and(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res);
  */
 void acpigen_write_not(struct acpi_ctx *ctx, u8 arg, u8 res);
 
+/**
+ * acpigen_write_power_res() - Write a power resource
+ *
+ * Name (_PRx, Package(One) { name })
+ * ...
+ * PowerResource (name, level, order)
+ *
+ * The caller should fill in the rest of the power resource and then call
+ * acpigen_pop_len() to close it off
+ *
+ * @ctx: ACPI context pointer
+ * @name: Name of power resource (e.g. "PRIC")
+ * @level: Deepest sleep level that this resource must be kept on (0=S0, 3=S3)
+ * @order: Order that this must be enabled/disabled (e.g. 0)
+ * @dev_stats: List of states to define, e.g. {"_PR0", "_PR3"}
+ * @dev_states_count: Number of dev states
+ */
+void acpigen_write_power_res(struct acpi_ctx *ctx, const char *name, uint level,
+			     uint order, const char *const dev_states[],
+			     size_t dev_states_count);
+
 #endif
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index 57b295aa4e..824a2c97cd 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -328,6 +328,28 @@ int acpigen_write_uuid(struct acpi_ctx *ctx, const char *uuid)
 	return 0;
 }
 
+void acpigen_write_power_res(struct acpi_ctx *ctx, const char *name, uint level,
+			     uint order, const char *const dev_states[],
+			     size_t dev_states_count)
+{
+	size_t i;
+
+	for (i = 0; i < dev_states_count; i++) {
+		acpigen_write_name(ctx, dev_states[i]);
+		acpigen_write_package(ctx, 1);
+		acpigen_emit_simple_namestring(ctx, name);
+		acpigen_pop_len(ctx);		/* Package */
+	}
+
+	acpigen_emit_ext_op(ctx, POWER_RES_OP);
+
+	acpigen_write_len_f(ctx);
+
+	acpigen_emit_simple_namestring(ctx, name);
+	acpigen_emit_byte(ctx, level);
+	acpigen_emit_word(ctx, order);
+}
+
 /* Sleep (ms) */
 void acpigen_write_sleep(struct acpi_ctx *ctx, u64 sleep_ms)
 {
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index e059d6f80d..c92f6cdb0b 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -696,3 +696,44 @@ static int dm_test_acpi_misc(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_misc, 0);
+
+/* Test writing an ACPI power resource */
+static int dm_test_acpi_power_res(struct unit_test_state *uts)
+{
+	const char *const states[] = { "_PR0", "_PR3" };
+	const char *name = "PRIC";
+	const int level = 3;
+	const int order = 2;
+	struct acpi_ctx *ctx;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ptr = acpigen_get_current(ctx);
+
+	/* PowerResource (PRIC, 0, 0) */
+	acpigen_write_power_res(ctx, name, level, order, states,
+				ARRAY_SIZE(states));
+	ut_asserteq(0x28, acpigen_get_current(ctx) - ptr);
+	ut_asserteq(NAME_OP, ptr[0]);
+	ut_asserteq_strn(states[0], (char *)ptr + 1);
+	ut_asserteq(8, get_length(ptr + 6));
+	ut_asserteq_strn(name, (char *)ptr + 0xa);
+
+	ut_asserteq_strn(states[1], (char *)ptr + 0xf);
+	ut_asserteq(8, get_length(ptr + 0x14));
+	ut_asserteq_strn(name, (char *)ptr + 0x18);
+
+	ut_asserteq(POWER_RES_OP, ptr[0x1d]);
+	ut_asserteq_strn(name, (char *)ptr + 0x21);
+	ut_asserteq(level, ptr[0x25]);
+	ut_asserteq(order, get_unaligned((u16 *)(ptr + 0x26)));
+
+	/* The length is not set - caller must use acpigen_pop_len() */
+	ut_asserteq(1, ctx->ltop);
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_power_res, 0);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 24/35] acpi: Add support for writing a GPIO power sequence
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (22 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 23/35] acpi: Add support for writing a Power Resource Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:33 ` [PATCH v2 25/35] acpi: Add support for a generic " Simon Glass
                   ` (44 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

Power to some devices is controlled by GPIOs. Add a way to generate ACPI
code to enable and disable a GPIO so that this can be handled within an
ACPI method.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpigen.h | 12 +++++++
 lib/acpi/acpigen.c     | 80 ++++++++++++++++++++++++++++++++++++++++++
 test/dm/acpigen.c      | 54 ++++++++++++++++++++++++++++
 3 files changed, 146 insertions(+)

diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
index 7d9a02805b..1205836f58 100644
--- a/include/acpi/acpigen.h
+++ b/include/acpi/acpigen.h
@@ -13,6 +13,7 @@
 #include <linux/types.h>
 
 struct acpi_ctx;
+struct acpi_gpio;
 
 /* ACPI Op/Prefix codes */
 enum {
@@ -332,4 +333,15 @@ void acpigen_write_power_res(struct acpi_ctx *ctx, const char *name, uint level,
 			     uint order, const char *const dev_states[],
 			     size_t dev_states_count);
 
+/*
+ * Helper functions for enabling/disabling Tx GPIOs based on the GPIO
+ * polarity. These functions end up calling acpigen_soc_{set,clear}_tx_gpio to
+ * make callbacks into SoC acpigen code.
+ *
+ * Returns 0 on success and -1 on error.
+ */
+int acpigen_set_enable_tx_gpio(struct acpi_ctx *ctx, u32 tx_state_val,
+			       const char *dw0_name, struct acpi_gpio *gpio,
+			       bool enable);
+
 #endif
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index 824a2c97cd..1c72306bd1 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -13,6 +13,7 @@
 #include <log.h>
 #include <uuid.h>
 #include <acpi/acpigen.h>
+#include <acpi/acpi_device.h>
 #include <dm/acpi.h>
 
 /* CPU path format */
@@ -395,3 +396,82 @@ void acpigen_write_debug_string(struct acpi_ctx *ctx, const char *str)
 	acpigen_write_string(ctx, str);
 	acpigen_emit_ext_op(ctx, DEBUG_OP);
 }
+
+/**
+ * acpigen_get_dw0_in_local5() - Generate code to put dw0 cfg0 in local5
+ *
+ * @ctx: ACPI context pointer
+ * @dw0_name: Name to use (e.g. "\\_SB.GPC0")
+ * @addr: GPIO pin configuration register address
+ *
+ * Store (\_SB.GPC0 (addr), Local5)
+ * \_SB.GPC0 is used to read cfg0 value from dw0. It is typically defined in
+ * the board's gpiolib.asl
+ */
+static void acpigen_get_dw0_in_local5(struct acpi_ctx *ctx,
+				      const char *dw0_name, ulong addr)
+{
+	acpigen_write_store(ctx);
+	acpigen_emit_namestring(ctx, dw0_name);
+	acpigen_write_integer(ctx, addr);
+	acpigen_emit_byte(ctx, LOCAL5_OP);
+}
+
+/**
+ * acpigen_set_gpio_val() - Set value of TX GPIO to on/off
+ *
+ * @ctx: ACPI context pointer
+ * @dw0_name: Name to use (e.g. "\\_SB.GPC0")
+ * @gpio_num: GPIO number to adjust
+ * @vaL: true to set on, false to set off
+ */
+static int acpigen_set_gpio_val(struct acpi_ctx *ctx, u32 tx_state_val,
+				const char *dw0_name, struct acpi_gpio *gpio,
+				bool val)
+{
+	acpigen_get_dw0_in_local5(ctx, dw0_name, gpio->pin0_addr);
+
+	if (val) {
+		/* Or (Local5, PAD_CFG0_TX_STATE, Local5) */
+		acpigen_write_or(ctx, LOCAL5_OP, tx_state_val, LOCAL5_OP);
+	} else {
+		/* Not (PAD_CFG0_TX_STATE, Local6) */
+		acpigen_write_not(ctx, tx_state_val, LOCAL6_OP);
+
+		/* And (Local5, Local6, Local5) */
+		acpigen_write_and(ctx, LOCAL5_OP, LOCAL6_OP, LOCAL5_OP);
+	}
+
+	/*
+	 * \_SB.SPC0 (addr, Local5)
+	 * \_SB.SPC0 is used to write cfg0 value in dw0. It is defined in
+	 * gpiolib.asl.
+	 */
+	acpigen_emit_namestring(ctx, dw0_name);
+	acpigen_write_integer(ctx, gpio->pin0_addr);
+	acpigen_emit_byte(ctx, LOCAL5_OP);
+
+	return 0;
+}
+
+/*
+ * Helper functions for enabling/disabling Tx GPIOs based on the GPIO
+ * polarity. These functions end up calling acpigen_{set,clear}_tx_gpio to
+ * make callbacks into SoC acpigen code.
+ *
+ * Returns 0 on success and -1 on error.
+ */
+int acpigen_set_enable_tx_gpio(struct acpi_ctx *ctx, u32 tx_state_val,
+			       const char *dw0_name, struct acpi_gpio *gpio,
+			       bool enable)
+{
+	bool set;
+	int ret;
+
+	set = gpio->polarity == ACPI_GPIO_ACTIVE_HIGH ? enable : !enable;
+	ret = acpigen_set_gpio_val(ctx, tx_state_val, dw0_name, gpio, set);
+	if (ret)
+		return log_msg_ret("call", ret);
+
+	return 0;
+}
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index c92f6cdb0b..06bdd63739 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -737,3 +737,57 @@ static int dm_test_acpi_power_res(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_power_res, 0);
+
+/* Test writing ACPI code to toggle a GPIO */
+static int dm_test_acpi_gpio_toggle(struct unit_test_state *uts)
+{
+	const uint addr = 0x80012;
+	const int txbit = BIT(2);
+	struct gpio_desc desc;
+	struct acpi_gpio gpio;
+	struct acpi_ctx *ctx;
+	struct udevice *dev;
+	u8 *ptr;
+
+	ut_assertok(alloc_context(&ctx));
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("a-test", dev->name);
+	ut_assertok(gpio_request_by_name(dev, "test2-gpios", 2, &desc, 0));
+	ut_assertok(gpio_get_acpi(&desc, &gpio));
+
+	/* Spot-check the results - see sb_gpio_get_acpi() */
+	ptr = acpigen_get_current(ctx);
+	acpigen_set_enable_tx_gpio(ctx, txbit, "\\_SB.GPC0", &gpio, true);
+	acpigen_set_enable_tx_gpio(ctx, txbit, "\\_SB.GPC0", &gpio, false);
+
+	/* Since this GPIO is active low, we expect it to be cleared here */
+	ut_asserteq(STORE_OP, ptr[0]);
+	ut_asserteq_strn("_SB_GPC0", (char *)ptr + 3);
+	ut_asserteq(addr + desc.offset, get_unaligned((u32 *)(ptr + 0xc)));
+	ut_asserteq(LOCAL5_OP, ptr[0x10]);
+
+	ut_asserteq(NOT_OP, ptr[0x11]);
+	ut_asserteq(txbit, ptr[0x12]);
+	ut_asserteq(AND_OP, ptr[0x14]);
+	ut_asserteq_strn("_SB_GPC0", (char *)ptr + 0x1a);
+	ut_asserteq(addr + desc.offset, get_unaligned((u32 *)(ptr + 0x23)));
+	ut_asserteq(LOCAL5_OP, ptr[0x27]);
+
+	/* Now the second one, which should be set */
+	ut_asserteq_strn("_SB_GPC0", (char *)ptr + 0x2b);
+	ut_asserteq(addr + desc.offset, get_unaligned((u32 *)(ptr + 0x34)));
+	ut_asserteq(LOCAL5_OP, ptr[0x38]);
+
+	ut_asserteq(OR_OP, ptr[0x39]);
+	ut_asserteq(txbit, ptr[0x3b]);
+	ut_asserteq_strn("_SB_GPC0", (char *)ptr + 0x3f);
+	ut_asserteq(addr + desc.offset, get_unaligned((u32 *)(ptr + 0x48)));
+	ut_asserteq(LOCAL5_OP, ptr[0x4c]);
+	ut_asserteq(0x4d, acpigen_get_current(ctx) - ptr);
+
+	free_context(&ctx);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_gpio_toggle, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 25/35] acpi: Add support for a generic power sequence
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (23 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 24/35] acpi: Add support for writing a GPIO power sequence Simon Glass
@ 2020-05-10 20:33 ` Simon Glass
  2020-05-10 20:34 ` [PATCH v2 26/35] acpi: Add support for SSDT generation Simon Glass
                   ` (43 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:33 UTC (permalink / raw)
  To: u-boot

Add a way for devices to enable and disable themselves using ACPI code
that updates GPIOs. This takes several timing parameters and supports
enable, reset and stop.

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

Changes in v2: None
Changes in v1: None

 include/acpi/acpi_device.h | 41 ++++++++++++++++
 lib/acpi/acpi_device.c     | 99 ++++++++++++++++++++++++++++++++++++++
 test/dm/acpigen.c          | 68 ++++++++++++++++++++++++++
 3 files changed, 208 insertions(+)

diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h
index d43ab4ba36..adebd63c15 100644
--- a/include/acpi/acpi_device.h
+++ b/include/acpi/acpi_device.h
@@ -342,4 +342,45 @@ int acpi_device_write_i2c_dev(struct acpi_ctx *ctx, const struct udevice *dev);
  */
 int acpi_device_write_spi_dev(struct acpi_ctx *ctx, const struct udevice *dev);
 
+/**
+ * acpi_device_add_power_res() - Add a basic PowerResource block for a device
+ *
+ * This includes GPIOs to control enable, reset and stop operation of the
+ * device. Each GPIO is optional, but at least one must be provided.
+ * This can be applied to any device that has power control, so is fairly
+ * generic.
+ *
+ * Reset - Put the device into / take the device out of reset.
+ * Enable - Enable / disable power to device.
+ * Stop - Stop / start operation of device.
+ *
+ * @ctx: ACPI context pointer
+ * @tx_state_val: Mask to use to toggle the TX state on the GPIO pin, e,g.
+ *	PAD_CFG0_TX_STATE
+ * @dw0_name: Name to use for access to dw0, e.g. "\\_SB.GPC0"
+ * @reset_gpio: GPIO used to take device out of reset or to put it into reset
+ * @reset_delay_ms: Delay to be inserted after device is taken out of reset
+ *	(_ON method delay)
+ * @reset_off_delay_ms: Delay to be inserted after device is put into reset
+ *	(_OFF method delay)
+ * @enable_gpio: GPIO used to enable device
+ * @enable_delay_ms: Delay to be inserted after device is enabled
+ * @enable_off_delay_ms: Delay to be inserted after device is disabled
+ *	(_OFF method delay)
+ * @stop_gpio: GPIO used to stop operation of device
+ * @stop_delay_ms: Delay to be inserted after disabling stop (_ON method delay)
+ * @stop_off_delay_ms: Delay to be inserted after enabling stop.
+ *	(_OFF method delay)
+ *
+ * @return 0 if OK, -ve if at least one GPIO is not provided
+ */
+int acpi_device_add_power_res(struct acpi_ctx *ctx, u32 tx_state_val,
+			      const char *dw0_name,
+			      const struct gpio_desc *reset_gpio,
+			      uint reset_delay_ms, uint reset_off_delay_ms,
+			      const struct gpio_desc *enable_gpio,
+			      uint enable_delay_ms, uint enable_off_delay_ms,
+			      const struct gpio_desc *stop_gpio,
+			      uint stop_delay_ms, uint stop_off_delay_ms);
+
 #endif
diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
index 3d5dc746f8..e5968bd3aa 100644
--- a/lib/acpi/acpi_device.c
+++ b/lib/acpi/acpi_device.c
@@ -382,6 +382,105 @@ int acpi_device_write_interrupt_or_gpio(struct acpi_ctx *ctx,
 	return 0;
 }
 
+/* PowerResource() with Enable and/or Reset control */
+int acpi_device_add_power_res(struct acpi_ctx *ctx, u32 tx_state_val,
+			      const char *dw0_name,
+			      const struct gpio_desc *reset_gpio,
+			      uint reset_delay_ms, uint reset_off_delay_ms,
+			      const struct gpio_desc *enable_gpio,
+			      uint enable_delay_ms, uint enable_off_delay_ms,
+			      const struct gpio_desc *stop_gpio,
+			      uint stop_delay_ms, uint stop_off_delay_ms)
+{
+	static const char *const power_res_dev_states[] = { "_PR0", "_PR3" };
+	struct acpi_gpio reset, enable, stop;
+	bool has_reset, has_enable, has_stop;
+	int ret;
+
+	gpio_get_acpi(reset_gpio, &reset);
+	gpio_get_acpi(enable_gpio, &enable);
+	gpio_get_acpi(stop_gpio, &stop);
+	has_reset = reset.pins[0];
+	has_enable = enable.pins[0];
+	has_stop = stop.pins[0];
+
+	if (!has_reset && !has_enable && !has_stop)
+		return -EINVAL;
+
+	/* PowerResource (PRIC, 0, 0) */
+	acpigen_write_power_res(ctx, "PRIC", 0, 0, power_res_dev_states,
+				ARRAY_SIZE(power_res_dev_states));
+
+	/* Method (_STA, 0, NotSerialized) { Return (0x1) } */
+	acpigen_write_sta(ctx, 0x1);
+
+	/* Method (_ON, 0, Serialized) */
+	acpigen_write_method_serialized(ctx, "_ON", 0);
+	if (reset_gpio) {
+		ret = acpigen_set_enable_tx_gpio(ctx, tx_state_val, dw0_name,
+						 &reset, true);
+		if (ret)
+			return log_msg_ret("reset1", ret);
+	}
+	if (has_enable) {
+		ret = acpigen_set_enable_tx_gpio(ctx, tx_state_val, dw0_name,
+						 &enable, true);
+		if (ret)
+			return log_msg_ret("enable1", ret);
+		if (enable_delay_ms)
+			acpigen_write_sleep(ctx, enable_delay_ms);
+	}
+	if (has_reset) {
+		ret = acpigen_set_enable_tx_gpio(ctx, tx_state_val, dw0_name,
+						 &reset, false);
+		if (ret)
+			return log_msg_ret("reset2", ret);
+		if (reset_delay_ms)
+			acpigen_write_sleep(ctx, reset_delay_ms);
+	}
+	if (has_stop) {
+		ret = acpigen_set_enable_tx_gpio(ctx, tx_state_val, dw0_name,
+						 &stop, false);
+		if (ret)
+			return log_msg_ret("stop1", ret);
+		if (stop_delay_ms)
+			acpigen_write_sleep(ctx, stop_delay_ms);
+	}
+	acpigen_pop_len(ctx);		/* _ON method */
+
+	/* Method (_OFF, 0, Serialized) */
+	acpigen_write_method_serialized(ctx, "_OFF", 0);
+	if (has_stop) {
+		ret = acpigen_set_enable_tx_gpio(ctx, tx_state_val, dw0_name,
+						 &stop, true);
+		if (ret)
+			return log_msg_ret("stop2", ret);
+		if (stop_off_delay_ms)
+			acpigen_write_sleep(ctx, stop_off_delay_ms);
+	}
+	if (has_reset) {
+		ret = acpigen_set_enable_tx_gpio(ctx, tx_state_val, dw0_name,
+						 &reset, true);
+		if (ret)
+			return log_msg_ret("reset3", ret);
+		if (reset_off_delay_ms)
+			acpigen_write_sleep(ctx, reset_off_delay_ms);
+	}
+	if (has_enable) {
+		ret = acpigen_set_enable_tx_gpio(ctx, tx_state_val, dw0_name,
+						 &enable, false);
+		if (ret)
+			return log_msg_ret("enable2", ret);
+		if (enable_off_delay_ms)
+			acpigen_write_sleep(ctx, enable_off_delay_ms);
+	}
+	acpigen_pop_len(ctx);		/* _OFF method */
+
+	acpigen_pop_len(ctx);		/* PowerResource PRIC */
+
+	return 0;
+}
+
 /* ACPI 6.3 section 6.4.3.8.2.1 - I2cSerialBus() */
 static void acpi_device_write_i2c(struct acpi_ctx *ctx,
 				  const struct acpi_i2c *i2c)
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index 06bdd63739..afaccc7664 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -791,3 +791,71 @@ static int dm_test_acpi_gpio_toggle(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_gpio_toggle, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test writing ACPI code to output power-sequence info */
+static int dm_test_acpi_power_seq(struct unit_test_state *uts)
+{
+	struct gpio_desc reset, enable, stop;
+	const uint addr = 0xc00dc, addr_act_low = 0x80012;
+	const int txbit = BIT(2);
+	struct acpi_ctx *ctx;
+	struct udevice *dev;
+	u8 *ptr;
+
+	ut_assertok(alloc_context_size(&ctx, 400));
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("a-test", dev->name);
+	ut_assertok(gpio_request_by_name(dev, "test2-gpios", 0, &reset, 0));
+	ut_assertok(gpio_request_by_name(dev, "test2-gpios", 1, &enable, 0));
+	ut_assertok(gpio_request_by_name(dev, "test2-gpios", 2, &stop, 0));
+	ptr = acpigen_get_current(ctx);
+
+	ut_assertok(acpi_device_add_power_res(ctx, txbit, "\\_SB.GPC0",
+					      &reset, 2, 3, &enable, 4, 5,
+					      &stop, 6, 7));
+	ut_asserteq(0x16a, acpigen_get_current(ctx) - ptr);
+	ut_asserteq_strn("PRIC", (char *)ptr + 0x18);
+
+	/* First the 'ON' sequence - spot check */
+	ut_asserteq_strn("_ON_", (char *)ptr + 0x38);
+
+	/* reset set */
+	ut_asserteq(addr + reset.offset, get_unaligned((u32 *)(ptr + 0x49)));
+	ut_asserteq(OR_OP, ptr[0x4e]);
+
+	/* enable set */
+	ut_asserteq(addr + enable.offset, get_unaligned((u32 *)(ptr + 0x6e)));
+	ut_asserteq(OR_OP, ptr[0x73]);
+
+	/* reset clear */
+	ut_asserteq(addr + reset.offset, get_unaligned((u32 *)(ptr + 0x97)));
+	ut_asserteq(NOT_OP, ptr[0x9c]);
+
+	/* stop set (disable, active low) */
+	ut_asserteq(addr_act_low + stop.offset,
+		    get_unaligned((u32 *)(ptr + 0xc3)));
+	ut_asserteq(OR_OP, ptr[0xc8]);
+
+	/* Now the 'OFF' sequence */
+	ut_asserteq_strn("_OFF", (char *)ptr + 0xe4);
+
+	/* stop clear (enable, active low) */
+	ut_asserteq(addr_act_low + stop.offset,
+		    get_unaligned((u32 *)(ptr + 0xf5)));
+	ut_asserteq(NOT_OP, ptr[0xfa]);
+
+	/* reset clear */
+	ut_asserteq(addr + reset.offset, get_unaligned((u32 *)(ptr + 0x121)));
+	ut_asserteq(OR_OP, ptr[0x126]);
+
+	/* enable clear */
+	ut_asserteq(addr + enable.offset, get_unaligned((u32 *)(ptr + 0x14a)));
+	ut_asserteq(NOT_OP, ptr[0x14f]);
+
+	free_context(&ctx);
+
+	return 0;
+}
+
+DM_TEST(dm_test_acpi_power_seq, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 26/35] acpi: Add support for SSDT generation
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (24 preceding siblings ...)
  2020-05-10 20:33 ` [PATCH v2 25/35] acpi: Add support for a generic " Simon Glass
@ 2020-05-10 20:34 ` Simon Glass
  2020-05-10 20:34 ` [PATCH v2 27/35] x86: acpi: Move MADT down a bit Simon Glass
                   ` (42 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:34 UTC (permalink / raw)
  To: u-boot

Some devices need to generate code for the Secondary System Descriptor
Table (SSDT). Add a method to handle this.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>
---

Changes in v2: None
Changes in v1:
- Switch parameter order of _acpi_fill_ssdt() and make it static
- Fix 'sentinal' and 'METHOD_FILL_SDDT' typos

 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(+)

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index a90395fa62..f6520a54e8 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -254,6 +254,7 @@
 
 	acpi-test {
 		compatible = "denx,u-boot-acpi-test";
+		acpi-ssdt-test-data = "ab";
 		child {
 			compatible = "denx,u-boot-acpi-test";
 		};
@@ -261,6 +262,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 2bd03eaa0a..dac1635cd3 100644
--- a/include/dm/acpi.h
+++ b/include/dm/acpi.h
@@ -72,6 +72,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)
@@ -116,6 +129,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 0c2e12d170..d1bd108223 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -14,6 +14,7 @@
 #include <version.h>
 #include <tables_csum.h>
 #include <version.h>
+#include <acpi/acpigen.h>
 #include <acpi/acpi_device.h>
 #include <acpi/acpi_table.h>
 #include <dm/acpi.h>
@@ -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);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 27/35] x86: acpi: Move MADT down a bit
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (25 preceding siblings ...)
  2020-05-10 20:34 ` [PATCH v2 26/35] acpi: Add support for SSDT generation Simon Glass
@ 2020-05-10 20:34 ` Simon Glass
  2020-05-10 20:34 ` [PATCH v2 28/35] acpi: Record the items added to SSDT Simon Glass
                   ` (41 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:34 UTC (permalink / raw)
  To: u-boot

Put this table before MCFG so that it matches the order that coreboot uses
when passing tables to Linux. This is a cosmetic change since the order of
the tables does not otherwise matter.

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

Changes in v2: None
Changes in v1:
- Correct the commit subject

 arch/x86/lib/acpi_table.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index 6985ef4ba5..e96acf08d4 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -418,18 +418,18 @@ ulong write_acpi_tables(ulong start_addr)
 	acpi_create_fadt(fadt, facs, dsdt);
 	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(ctx, madt);
-
 	debug("ACPI:    * MCFG\n");
 	mcfg = ctx->current;
 	acpi_create_mcfg(mcfg);
 	acpi_inc_align(ctx, mcfg->header.length);
 	acpi_add_table(ctx, mcfg);
 
+	debug("ACPI:    * MADT\n");
+	madt = ctx->current;
+	acpi_create_madt(madt);
+	acpi_inc_align(ctx, madt->header.length);
+	acpi_add_table(ctx, madt);
+
 	debug("ACPI:    * CSRT\n");
 	csrt = ctx->current;
 	acpi_create_csrt(csrt);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 28/35] acpi: Record the items added to SSDT
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (26 preceding siblings ...)
  2020-05-10 20:34 ` [PATCH v2 27/35] x86: acpi: Move MADT down a bit Simon Glass
@ 2020-05-10 20:34 ` Simon Glass
  2020-05-10 20:34 ` [PATCH v2 29/35] acpi: Support ordering SSDT data by device Simon Glass
                   ` (40 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:34 UTC (permalink / raw)
  To: u-boot

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 <sjg@chromium.org>
---

Changes in v2: None
Changes in v1:
- Generalise the ACPI function recursion with acpi_recurse_method()

 drivers/core/acpi.c | 83 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 79 insertions(+), 4 deletions(-)

diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c
index 4497b5cb2f..fa16be8154 100644
--- a/drivers/core/acpi.c
+++ b/drivers/core/acpi.c
@@ -9,12 +9,21 @@
 #define LOG_CATEOGRY	LOGC_ACPI
 
 #include <common.h>
+#include <malloc.h>
 #include <dm.h>
 #include <log.h>
 #include <dm/acpi.h>
 #include <dm/device-internal.h>
 #include <dm/root.h>
 
+#define MAX_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_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_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;
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 29/35] acpi: Support ordering SSDT data by device
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (27 preceding siblings ...)
  2020-05-10 20:34 ` [PATCH v2 28/35] acpi: Record the items added to SSDT Simon Glass
@ 2020-05-10 20:34 ` Simon Glass
  2020-05-10 20:34 ` [PATCH v2 30/35] x86: Allow devices to write an SSDT Simon Glass
                   ` (39 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:34 UTC (permalink / raw)
  To: u-boot

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>
---

Changes in v2: None
Changes in v1:
- Generalise the ACPI function recursion with acpi_recurse_method()

 arch/sandbox/dts/test.dts           |  5 ++-
 doc/device-tree-bindings/chosen.txt |  9 +++++
 drivers/core/acpi.c                 | 62 +++++++++++++++++++++++++++++
 test/dm/acpi.c                      | 15 ++++---
 4 files changed, 83 insertions(+), 8 deletions(-)

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index f6520a54e8..30eb749671 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -252,7 +252,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 {
@@ -260,7 +260,7 @@
 		};
 	};
 
-	acpi-test2 {
+	acpi_test2: acpi-test2 {
 		compatible = "denx,u-boot-acpi-test";
 		acpi-ssdt-test-data = "cd";
 	};
@@ -893,6 +893,7 @@
 		setting = "sunrise ohoka";
 		other-node = "/some-bus/c-test at 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 fa16be8154..a0b598b66b 100644
--- a/drivers/core/acpi.c
+++ b/drivers/core/acpi.c
@@ -108,6 +108,63 @@ static int acpi_add_item(struct acpi_ctx *ctx, struct udevice *dev,
 	return 0;
 }
 
+struct acpi_item *find_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;
+}
+
+static int build_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;
+	}
+
+	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_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 (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 +220,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 = build_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 d1bd108223..8df128706d 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]);
 
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 30/35] x86: Allow devices to write an SSDT
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (28 preceding siblings ...)
  2020-05-10 20:34 ` [PATCH v2 29/35] acpi: Support ordering SSDT data by device Simon Glass
@ 2020-05-10 20:34 ` Simon Glass
  2020-05-10 20:34 ` [PATCH v2 31/35] acpi: Add support for DSDT generation Simon Glass
                   ` (38 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:34 UTC (permalink / raw)
  To: u-boot

Call the new core function to write the SSDT. This is made up of fragments
generated by devices that have the fill_ssdt() method.

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

Changes in v2: None
Changes in v1:
- Use OEM_TABLE_ID instead of ACPI_TABLE_CREATOR
- Update ACPI_DSTATUS enum
- Drop writing of coreboot tables

 arch/x86/lib/acpi_table.c | 29 +++++++++++++++++++++++++++++
 include/acpi/acpi_table.h |  6 ++++++
 2 files changed, 35 insertions(+)

diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index e96acf08d4..4658d88351 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -14,6 +14,7 @@
 #include <mapmem.h>
 #include <serial.h>
 #include <version.h>
+#include <acpi/acpigen.h>
 #include <acpi/acpi_table.h>
 #include <asm/acpi/global_nvs.h>
 #include <asm/ioapic.h>
@@ -354,6 +355,25 @@ static void acpi_create_spcr(struct acpi_spcr *spcr)
 	header->checksum = table_compute_checksum((void *)spcr, header->length);
 }
 
+void acpi_create_ssdt(struct acpi_ctx *ctx, struct acpi_table_header *ssdt,
+		      const char *oem_table_id)
+{
+	memset((void *)ssdt, '\0', sizeof(struct acpi_table_header));
+
+	acpi_fill_header(ssdt, "SSDT");
+	ssdt->revision = acpi_get_table_revision(ACPITAB_SSDT);
+	ssdt->aslc_revision = 1;
+	ssdt->length = sizeof(struct acpi_table_header);
+
+	acpi_inc(ctx, sizeof(struct acpi_table_header));
+
+	acpi_fill_ssdt(ctx);
+
+	/* (Re)calculate length and checksum. */
+	ssdt->length = ctx->current - (void *)ssdt;
+	ssdt->checksum = table_compute_checksum((void *)ssdt, ssdt->length);
+}
+
 /*
  * QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c
  */
@@ -363,6 +383,7 @@ ulong write_acpi_tables(ulong start_addr)
 	struct acpi_facs *facs;
 	struct acpi_table_header *dsdt;
 	struct acpi_fadt *fadt;
+	struct acpi_table_header *ssdt;
 	struct acpi_mcfg *mcfg;
 	struct acpi_madt *madt;
 	struct acpi_csrt *csrt;
@@ -418,6 +439,14 @@ ulong write_acpi_tables(ulong start_addr)
 	acpi_create_fadt(fadt, facs, dsdt);
 	acpi_add_table(ctx, fadt);
 
+	debug("ACPI:     * SSDT\n");
+	ssdt = (struct acpi_table_header *)ctx->current;
+	acpi_create_ssdt(ctx, ssdt, OEM_TABLE_ID);
+	if (ssdt->length > sizeof(struct acpi_table_header)) {
+		acpi_inc_align(ctx, ssdt->length);
+		acpi_add_table(ctx, ssdt);
+	}
+
 	debug("ACPI:    * MCFG\n");
 	mcfg = ctx->current;
 	acpi_create_mcfg(mcfg);
diff --git a/include/acpi/acpi_table.h b/include/acpi/acpi_table.h
index fe9b29f3f8..9068da24f5 100644
--- a/include/acpi/acpi_table.h
+++ b/include/acpi/acpi_table.h
@@ -27,6 +27,12 @@
 
 struct acpi_ctx;
 
+/* List of ACPI HID that use the coreboot ACPI ID */
+enum coreboot_acpi_ids {
+	COREBOOT_ACPI_ID_CBTABLE	= 0x0000, /* BOOT0000 */
+	COREBOOT_ACPI_ID_MAX		= 0xFFFF, /* BOOTFFFF */
+};
+
 /*
  * RSDP (Root System Description Pointer)
  * Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 31/35] acpi: Add support for DSDT generation
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (29 preceding siblings ...)
  2020-05-10 20:34 ` [PATCH v2 30/35] x86: Allow devices to write an SSDT Simon Glass
@ 2020-05-10 20:34 ` Simon Glass
  2020-05-10 20:34 ` [PATCH v2 32/35] x86: Allow devices to write to DSDT Simon Glass
                   ` (37 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:34 UTC (permalink / raw)
  To: u-boot

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 <sjg@chromium.org>
---

Changes in v2: None
Changes in v1:
- Generalise the ACPI function recursion with acpi_recurse_method()

 arch/sandbox/dts/test.dts |  2 ++
 drivers/core/acpi.c       | 25 +++++++++++++++++++++-
 include/dm/acpi.h         | 23 ++++++++++++++++++++
 test/dm/acpi.c            | 44 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 93 insertions(+), 1 deletion(-)

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 30eb749671..aab3fb7471 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -255,6 +255,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";
 		};
@@ -263,6 +264,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 a0b598b66b..ebe9fde68e 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 */
@@ -131,7 +133,9 @@ static int build_type(struct acpi_ctx *ctx, void *start, enum gen_type_t type)
 	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;
@@ -176,6 +180,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;
 		}
 	}
 
@@ -234,6 +240,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 = build_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 dac1635cd3..73bad2e763 100644
--- a/include/dm/acpi.h
+++ b/include/dm/acpi.h
@@ -85,6 +85,19 @@ struct acpi_ops {
 	 * @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.
+	 *
+	 * @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)
@@ -139,6 +152,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 8df128706d..3fe0a0c9ff 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);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 32/35] x86: Allow devices to write to DSDT
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (30 preceding siblings ...)
  2020-05-10 20:34 ` [PATCH v2 31/35] acpi: Add support for DSDT generation Simon Glass
@ 2020-05-10 20:34 ` Simon Glass
  2020-05-10 20:34 ` [PATCH v2 33/35] pci: Avoid a crash in device_is_on_pci_bus() Simon Glass
                   ` (36 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:34 UTC (permalink / raw)
  To: u-boot

Call the new core function to inject ASL programmatically into the DSDT.
This is made up of fragments generated by devices that have the
inject_dsdt() method. The normal, compiled ASL file is added after this.

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

Changes in v2: None
Changes in v1: None

 arch/x86/lib/acpi_table.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index 4658d88351..a7ec6d2b15 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -411,7 +411,20 @@ ulong write_acpi_tables(ulong start_addr)
 	memcpy(ctx->current,
 	       (char *)&AmlCode + sizeof(struct acpi_table_header),
 	       dsdt->length - sizeof(struct acpi_table_header));
-	acpi_inc_align(ctx, dsdt->length - sizeof(struct acpi_table_header));
+
+	if (dsdt->length >= sizeof(struct acpi_table_header)) {
+		acpi_inject_dsdt(ctx);
+		memcpy(ctx->current,
+		       (char *)AmlCode + sizeof(struct acpi_table_header),
+		       dsdt->length - sizeof(struct acpi_table_header));
+		acpi_inc(ctx, dsdt->length - sizeof(struct acpi_table_header));
+
+		/* (Re)calculate length and checksum. */
+		dsdt->length = ctx->current - (void *)dsdt;
+		dsdt->checksum = 0;
+		dsdt->checksum = table_compute_checksum(dsdt, dsdt->length);
+	}
+	acpi_align(ctx);
 
 	/* Pack GNVS into the ACPI table area */
 	for (i = 0; i < dsdt->length; i++) {
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 33/35] pci: Avoid a crash in device_is_on_pci_bus()
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (31 preceding siblings ...)
  2020-05-10 20:34 ` [PATCH v2 32/35] x86: Allow devices to write to DSDT Simon Glass
@ 2020-05-10 20:34 ` Simon Glass
  2020-05-10 20:34 ` [PATCH v2 34/35] dm: acpi: Enhance acpi_get_name() Simon Glass
                   ` (35 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:34 UTC (permalink / raw)
  To: u-boot

This function cannot currently be called on the root node. Add a check
for this as well as a test.

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

Changes in v2: None
Changes in v1: None

 include/dm/device.h |  2 +-
 test/dm/pci.c       | 14 ++++++++++++++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/include/dm/device.h b/include/dm/device.h
index 975eec5d0e..6a41ee5500 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -742,7 +742,7 @@ int dev_enable_by_path(const char *path);
  */
 static inline bool device_is_on_pci_bus(const struct udevice *dev)
 {
-	return device_get_uclass_id(dev->parent) == UCLASS_PCI;
+	return dev->parent && device_get_uclass_id(dev->parent) == UCLASS_PCI;
 }
 
 /**
diff --git a/test/dm/pci.c b/test/dm/pci.c
index fb93e4c78a..39e82b3699 100644
--- a/test/dm/pci.c
+++ b/test/dm/pci.c
@@ -339,3 +339,17 @@ static int dm_test_pci_addr_live(struct unit_test_state *uts)
 }
 DM_TEST(dm_test_pci_addr_live, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT |
 		DM_TESTF_LIVE_TREE);
+
+/* Test device_is_on_pci_bus() */
+static int dm_test_pci_on_bus(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+
+	ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &dev));
+	ut_asserteq(true, device_is_on_pci_bus(dev));
+	ut_asserteq(false, device_is_on_pci_bus(dev_get_parent(dev)));
+	ut_asserteq(true, device_is_on_pci_bus(dev));
+
+	return 0;
+}
+DM_TEST(dm_test_pci_on_bus, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 34/35] dm: acpi: Enhance acpi_get_name()
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (32 preceding siblings ...)
  2020-05-10 20:34 ` [PATCH v2 33/35] pci: Avoid a crash in device_is_on_pci_bus() Simon Glass
@ 2020-05-10 20:34 ` Simon Glass
  2020-05-10 20:34 ` [PATCH v2 35/35] acpi: Add an acpi split command Simon Glass
                   ` (34 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:34 UTC (permalink / raw)
  To: u-boot

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 <sjg@chromium.org>
---

Changes in v2: None
Changes in v1:
- Use acpi,ddn instead of acpi,desc
- Rename to acpi_device_infer_name()
- Update newly created sandbox tests

 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          |  15 ++++
 lib/acpi/acpi_device.c              | 106 ++++++++++++++++++++++++++++
 test/dm/acpi.c                      |  42 ++++++++++-
 test/dm/acpigen.c                   |   4 +-
 9 files changed, 189 insertions(+), 25 deletions(-)

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index aab3fb7471..750381bcac 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -111,6 +111,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 at 10 {
 	interrupts-extended = <&acpi_gpe GPIO_21_IRQ IRQ_TYPE_EDGE_FALLING>;
 	linux,probed;
 };
+
+pcie-a0 at 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 ebe9fde68e..ec70db3951 100644
--- a/drivers/core/acpi.c
+++ b/drivers/core/acpi.c
@@ -9,9 +9,10 @@
 #define LOG_CATEOGRY	LOGC_ACPI
 
 #include <common.h>
-#include <malloc.h>
 #include <dm.h>
 #include <log.h>
+#include <malloc.h>
+#include <acpi/acpi_device.h>
 #include <dm/acpi.h>
 #include <dm/device-internal.h>
 #include <dm/root.h>
@@ -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 4264acc953..5aeb6bdf43 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(spi_sandbox) = {
 	.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 adebd63c15..e99330ac6f 100644
--- a/include/acpi/acpi_device.h
+++ b/include/acpi/acpi_device.h
@@ -383,4 +383,19 @@ 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, of 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.
+ *
+ * @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 e5968bd3aa..b39ec8eb93 100644
--- a/lib/acpi/acpi_device.c
+++ b/lib/acpi/acpi_device.c
@@ -10,6 +10,8 @@
 #include <dm.h>
 #include <irq.h>
 #include <log.h>
+#include <usb.h>
+#include <acpi/acpigen.h>
 #include <acpi/acpi_device.h>
 #include <acpi/acpigen.h>
 #include <asm-generic/gpio.h>
@@ -704,3 +706,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:
+		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 3fe0a0c9ff..bd4c66c471 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);
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index afaccc7664..2922896c69 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -303,7 +303,7 @@ static int dm_test_acpi_i2c(struct unit_test_state *uts)
 	ut_asserteq(6, get_unaligned((u16 *)(ptr + 10)));
 	ut_asserteq(100000, get_unaligned((u32 *)(ptr + 12)));
 	ut_asserteq(0x43, get_unaligned((u16 *)(ptr + 16)));
-	ut_asserteq_str("\\_SB.SI2C", (char *)ptr + 18);
+	ut_asserteq_str("\\_SB.I2C0", (char *)ptr + 18);
 
 	free_context(&ctx);
 
@@ -339,7 +339,7 @@ static int dm_test_acpi_spi(struct unit_test_state *uts)
 	ut_asserteq(0, ptr[17]);
 	ut_asserteq(0, ptr[18]);
 	ut_asserteq(0, get_unaligned((u16 *)(ptr + 19)));
-	ut_asserteq_str("\\_SB.SSPI", (char *)ptr + 21);
+	ut_asserteq_str("\\_SB.SPI0", (char *)ptr + 21);
 
 	free_context(&ctx);
 
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 35/35] acpi: Add an acpi split command
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (33 preceding siblings ...)
  2020-05-10 20:34 ` [PATCH v2 34/35] dm: acpi: Enhance acpi_get_name() Simon Glass
@ 2020-05-10 20:34 ` Simon Glass
  2020-05-12  2:13 ` [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Bin Meng
                   ` (33 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-10 20:34 UTC (permalink / raw)
  To: u-boot

Add a command that shows the individual blocks of data generated by each
device. This can be helpful for debugging.

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

Changes in v2: None
Changes in v1: None

 cmd/acpi.c          | 15 +++++++++++++--
 drivers/core/acpi.c | 16 ++++++++++++++++
 include/dm/acpi.h   | 10 ++++++++++
 test/dm/acpi.c      | 39 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 78 insertions(+), 2 deletions(-)

diff --git a/cmd/acpi.c b/cmd/acpi.c
index e9a9161a91..3204b2ec43 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;
+
+	dump = argc >= 2 && !strcmp("-d", argv[1]);
+	acpi_dump_items(dump);
+
+	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 <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(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 ec70db3951..aa11001a8d 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(bool dump_contents)
+{
+	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 (dump_contents) {
+			print_buffer(0, item->buf, 1, item->size, 0);
+			printf("\n");
+		}
+	}
+}
+
 struct acpi_item *find_item(const char *devname)
 {
 	int i;
diff --git a/include/dm/acpi.h b/include/dm/acpi.h
index 73bad2e763..678391ccfc 100644
--- a/include/dm/acpi.h
+++ b/include/dm/acpi.h
@@ -162,6 +162,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.
+ *
+ * @dump_contents: true to dump the binary contents, false to just show the list
+ */
+void acpi_dump_items(bool dump_contents);
+
 #endif /* __ACPI__ */
 
 #endif
diff --git a/test/dm/acpi.c b/test/dm/acpi.c
index bd4c66c471..4952256ce1 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);
-- 
2.26.2.645.ge9eca65c58-goog

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B)
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (34 preceding siblings ...)
  2020-05-10 20:34 ` [PATCH v2 35/35] acpi: Add an acpi split command Simon Glass
@ 2020-05-12  2:13 ` Bin Meng
  2020-05-12 11:55 ` Antwort: " Wolfgang Wallner
                   ` (32 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Bin Meng @ 2020-05-12  2:13 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang, Andy,

On Mon, May 11, 2020 at 4:34 AM Simon Glass <sjg@chromium.org> wrote:
>
> NOTE: I have resent this as v1 to avoid confusion
>
> This is split from the original series in an attempt to get things applied
> in chunks.
>
> This part includes:
> - writing basic ACPI code for integers, strings, names, packages
> - writing descriptors for GPIO, I2C, interrupts, SPI
> - writing code to enable/disable ACPI peripherals via GPIOs
> - writing SSDT and DSDT tables
> - additional ways to determine ACPI device names
>
> Much of this code is taken from coreboot and I have tried to avoid
> changing the original code for no reason. Changes include:
> - splitting the acpi_dp functions into their own file
> - adding tests
> - adding (lots of) comments
> - using a context pointer instead of global variables
> - tidying up some code where couldn't resist (e.g. acpigen_emit_namestring())
>
> Changes in v2:
> - Fix memset of I2C descriptor
> - Fix memset of SPI descriptor
>
> Changes in v1:
> - Capitalise ACPI_OPS_PTR
> - Split into more patches for review
> - Add tests
> - Rebase on top of common.h series
> - Fix 'the an' typo
> - Move header definitions into this patch
> - Update sandbox driver slightly for testing
> - Switch parameter order of _acpi_fill_ssdt() and make it static
> - Fix 'sentinal' and 'METHOD_FILL_SDDT' typos
> - Correct the commit subject
> - Generalise the ACPI function recursion with acpi_recurse_method()
> - Generalise the ACPI function recursion with acpi_recurse_method()
> - Use OEM_TABLE_ID instead of ACPI_TABLE_CREATOR
> - Update ACPI_DSTATUS enum
> - Drop writing of coreboot tables
> - Generalise the ACPI function recursion with acpi_recurse_method()
> - Use acpi,ddn instead of acpi,desc
> - Rename to acpi_device_infer_name()
> - Update newly created sandbox tests
>

Since you were involved a lot in the discussion in the part A series,
would you please let me know if you get some time to review this?

Regards,
Bin

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: Re: [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B)
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (35 preceding siblings ...)
  2020-05-12  2:13 ` [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Bin Meng
@ 2020-05-12 11:55 ` Wolfgang Wallner
  2020-05-12 12:32   ` Andy Shevchenko
  2020-05-13 12:18 ` Antwort: [PATCH v2 03/35] acpi: Add a way to check device status Wolfgang Wallner
                   ` (31 subsequent siblings)
  68 siblings, 1 reply; 84+ messages in thread
From: Wolfgang Wallner @ 2020-05-12 11:55 UTC (permalink / raw)
  To: u-boot

Hi Bin,

-----"Bin Meng" <bmeng.cn@gmail.com> schrieb: -----
> Betreff: Re: [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B)
> 
> Hi Wolfgang, Andy,
> 
> On Mon, May 11, 2020 at 4:34 AM Simon Glass <sjg@chromium.org> wrote:
> >
> > NOTE: I have resent this as v1 to avoid confusion
> >
> > This is split from the original series in an attempt to get things applied
> > in chunks.
> >
> > This part includes:
> > - writing basic ACPI code for integers, strings, names, packages
> > - writing descriptors for GPIO, I2C, interrupts, SPI
> > - writing code to enable/disable ACPI peripherals via GPIOs
> > - writing SSDT and DSDT tables
> > - additional ways to determine ACPI device names
> >
> > Much of this code is taken from coreboot and I have tried to avoid
> > changing the original code for no reason. Changes include:
> > - splitting the acpi_dp functions into their own file
> > - adding tests
> > - adding (lots of) comments
> > - using a context pointer instead of global variables
> > - tidying up some code where couldn't resist (e.g. acpigen_emit_namestring())
> >
> > Changes in v2:
> > - Fix memset of I2C descriptor
> > - Fix memset of SPI descriptor
> >
> > Changes in v1:
> > - Capitalise ACPI_OPS_PTR
> > - Split into more patches for review
> > - Add tests
> > - Rebase on top of common.h series
> > - Fix 'the an' typo
> > - Move header definitions into this patch
> > - Update sandbox driver slightly for testing
> > - Switch parameter order of _acpi_fill_ssdt() and make it static
> > - Fix 'sentinal' and 'METHOD_FILL_SDDT' typos
> > - Correct the commit subject
> > - Generalise the ACPI function recursion with acpi_recurse_method()
> > - Generalise the ACPI function recursion with acpi_recurse_method()
> > - Use OEM_TABLE_ID instead of ACPI_TABLE_CREATOR
> > - Update ACPI_DSTATUS enum
> > - Drop writing of coreboot tables
> > - Generalise the ACPI function recursion with acpi_recurse_method()
> > - Use acpi,ddn instead of acpi,desc
> > - Rename to acpi_device_infer_name()
> > - Update newly created sandbox tests
> >
> 
> Since you were involved a lot in the discussion in the part A series,
> would you please let me know if you get some time to review this?

Unfortunately, I don't have as much time now for review of part B as I had for
part A. I already started reviewing part B and I will try to continue when time
allows.

regards, Wolfgang

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: Re: [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B)
  2020-05-12 11:55 ` Antwort: " Wolfgang Wallner
@ 2020-05-12 12:32   ` Andy Shevchenko
  2020-05-12 23:22     ` Simon Glass
  0 siblings, 1 reply; 84+ messages in thread
From: Andy Shevchenko @ 2020-05-12 12:32 UTC (permalink / raw)
  To: u-boot

On Tue, May 12, 2020 at 01:55:49PM +0200, Wolfgang Wallner wrote:

> > Since you were involved a lot in the discussion in the part A series,
> > would you please let me know if you get some time to review this?
> 
> Unfortunately, I don't have as much time now for review of part B as I had for
> part A. I already started reviewing part B and I will try to continue when time
> allows.

I'm busy at the moment and I will be not available for this for few weeks.
Code can be fixed iteratively, the most important part now is to see the big
picture of the design and approach.

Could you remind which patch in the series describes that? I will look at it
closer and try to allocate a bit of time to do it.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: Re: [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B)
  2020-05-12 12:32   ` Andy Shevchenko
@ 2020-05-12 23:22     ` Simon Glass
  2020-05-13  9:55       ` Andy Shevchenko
  0 siblings, 1 reply; 84+ messages in thread
From: Simon Glass @ 2020-05-12 23:22 UTC (permalink / raw)
  To: u-boot

Hi Andy,

On Tue, 12 May 2020 at 06:32, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Tue, May 12, 2020 at 01:55:49PM +0200, Wolfgang Wallner wrote:
>
> > > Since you were involved a lot in the discussion in the part A series,
> > > would you please let me know if you get some time to review this?
> >
> > Unfortunately, I don't have as much time now for review of part B as I had for
> > part A. I already started reviewing part B and I will try to continue when time
> > allows.
>
> I'm busy at the moment and I will be not available for this for few weeks.
> Code can be fixed iteratively, the most important part now is to see the big
> picture of the design and approach.
>
> Could you remind which patch in the series describes that? I will look at it
> closer and try to allocate a bit of time to do it.
>

The big picture was in part A. Part B uses the same mechanism to add
support for SSDT and DSDT generation, e.g. see [1] and [2].

Regards,
Simon

[1] http://patchwork.ozlabs.org/project/uboot/patch/20200510203409.203520-24-sjg at chromium.org/
[2] http://patchwork.ozlabs.org/project/uboot/patch/20200510143320.v2.32.I8b14735c2286701cc6be7d36b85bbad8ca58babd at changeid/

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: Re: [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B)
  2020-05-12 23:22     ` Simon Glass
@ 2020-05-13  9:55       ` Andy Shevchenko
  2020-05-14 16:02         ` Simon Glass
  0 siblings, 1 reply; 84+ messages in thread
From: Andy Shevchenko @ 2020-05-13  9:55 UTC (permalink / raw)
  To: u-boot

On Tue, May 12, 2020 at 05:22:38PM -0600, Simon Glass wrote:
> Hi Andy,
> 
> On Tue, 12 May 2020 at 06:32, Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> >
> > On Tue, May 12, 2020 at 01:55:49PM +0200, Wolfgang Wallner wrote:
> >
> > > > Since you were involved a lot in the discussion in the part A series,
> > > > would you please let me know if you get some time to review this?
> > >
> > > Unfortunately, I don't have as much time now for review of part B as I had for
> > > part A. I already started reviewing part B and I will try to continue when time
> > > allows.
> >
> > I'm busy at the moment and I will be not available for this for few weeks.
> > Code can be fixed iteratively, the most important part now is to see the big
> > picture of the design and approach.
> >
> > Could you remind which patch in the series describes that? I will look at it
> > closer and try to allocate a bit of time to do it.
> >
> 
> The big picture was in part A. Part B uses the same mechanism to add
> support for SSDT and DSDT generation, e.g. see [1] and [2].

Thank you, then I think what is left are technical (implementation) details
that can be amended in the future.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: [PATCH v2 03/35] acpi: Add a way to check device status
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (36 preceding siblings ...)
  2020-05-12 11:55 ` Antwort: " Wolfgang Wallner
@ 2020-05-13 12:18 ` Wolfgang Wallner
  2020-05-13 13:01 ` Antwort: [PATCH v2 04/35] irq: Add a method to convert an interrupt to ACPI Wolfgang Wallner
                   ` (30 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-05-13 12:18 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
>Betreff: [PATCH v2 03/35] acpi: Add a way to check device status
>
>At present U-Boot does not support the different ACPI status values,
>but
>it is best to put this logic in a central place. Add a function to
>get the
>device status.
>
>Signed-off-by: Simon Glass <sjg@chromium.org>
>---
>
>Changes in v2: None
>Changes in v1: None
>
> include/acpi/acpi_device.h | 28 ++++++++++++++++++++++++++++
> lib/acpi/acpi_device.c     |  5 +++++
> test/dm/acpi.c             | 12 ++++++++++++
> 3 files changed, 45 insertions(+)

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: [PATCH v2 04/35] irq: Add a method to convert an interrupt to ACPI
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (37 preceding siblings ...)
  2020-05-13 12:18 ` Antwort: [PATCH v2 03/35] acpi: Add a way to check device status Wolfgang Wallner
@ 2020-05-13 13:01 ` Wolfgang Wallner
  2020-05-14 16:02   ` Simon Glass
  2020-05-18  7:47   ` Antwort: " Wolfgang Wallner
  2020-05-14  8:32 ` Antwort: [PATCH v2 05/35] acpi: Support generation of ACPI code Wolfgang Wallner
                   ` (29 subsequent siblings)
  68 siblings, 2 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-05-13 13:01 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
>Betreff: [PATCH v2 04/35] irq: Add a method to convert an interrupt
>to ACPI
>
>When generating ACPI tables we need to convert IRQs in U-Boot to the
>ACPI
>structures required by ACPI. This is a SoC-specific conversion and
>cannot
>be handled by generic code, so add a new IRQ method to do the
>conversion.
>
>Signed-off-by: Simon Glass <sjg@chromium.org>
>---
>
>Changes in v2: None
>Changes in v1:
>- Fix 'the an' typo
>- Move header definitions into this patch
>
> drivers/misc/irq-uclass.c  | 18 ++++++++++--
> drivers/misc/irq_sandbox.c | 16 +++++++++++
> include/acpi/acpi_device.h | 59
>++++++++++++++++++++++++++++++++++++++
> include/irq.h              | 43 +++++++++++++++++++++++++++
> test/dm/irq.c              | 22 ++++++++++++++
> 5 files changed, 156 insertions(+), 2 deletions(-)
>
>diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
>index 16dc0be75c..98bc79eaba 100644
>--- a/drivers/misc/irq-uclass.c
>+++ b/drivers/misc/irq-uclass.c
>@@ -154,8 +154,6 @@ int irq_request(struct udevice *dev, struct irq
>*irq)
> 	const struct irq_ops *ops;
> 
> 	log_debug("(dev=%p, irq=%p)\n", dev, irq);
>-	if (!irq)
>-		return 0;

Why are these lines dropped?

As far as I understand the code they can be dropped, I just fail
to see how that is related to the ACPI changes.

> 	ops = irq_get_ops(dev);
> 
> 	irq->dev = dev;
>@@ -177,6 +175,22 @@ int irq_first_device_type(enum irq_dev_t type,
>struct udevice **devp)
> 	return 0;
> }
> 
>+#if CONFIG_IS_ENABLED(ACPIGEN)
>+int irq_get_acpi(const struct irq *irq, struct acpi_irq *acpi_irq)
>+{
>+	struct irq_ops *ops;
>+
>+	if (!irq_is_valid(irq))
>+		return -EINVAL;
>+
>+	ops = irq_get_ops(irq->dev);
>+	if (!ops->get_acpi)
>+		return -ENOSYS;
>+
>+	return ops->get_acpi(irq, acpi_irq);
>+}
>+#endif
>+
> UCLASS_DRIVER(irq) = {
> 	.id		= UCLASS_IRQ,
> 	.name		= "irq",
>diff --git a/drivers/misc/irq_sandbox.c b/drivers/misc/irq_sandbox.c
>index 54bc47c8d8..a2511b32fc 100644
>--- a/drivers/misc/irq_sandbox.c
>+++ b/drivers/misc/irq_sandbox.c
>@@ -8,6 +8,7 @@
> #include <common.h>
> #include <dm.h>
> #include <irq.h>
>+#include <acpi/acpi_device.h>
> #include <asm/test.h>
> 
> /**
>@@ -73,6 +74,18 @@ static int sandbox_irq_of_xlate(struct irq *irq,
> 	return 0;
> }
> 
>+static __maybe_unused int sandbox_get_acpi(const struct irq *irq,
>+					   struct acpi_irq *acpi_irq)
>+{
>+	acpi_irq->pin = irq->id;
>+	acpi_irq->mode = ACPI_IRQ_LEVEL_TRIGGERED;
>+	acpi_irq->polarity = ACPI_IRQ_ACTIVE_HIGH;
>+	acpi_irq->shared = ACPI_IRQ_SHARED;
>+	acpi_irq->wake = ACPI_IRQ_WAKE;
>+
>+	return 0;
>+}
>+
> static const struct irq_ops sandbox_irq_ops = {
> 	.route_pmc_gpio_gpe	= sandbox_route_pmc_gpio_gpe,
> 	.set_polarity		= sandbox_set_polarity,
>@@ -80,6 +93,9 @@ static const struct irq_ops sandbox_irq_ops = {
> 	.restore_polarities	= sandbox_restore_polarities,
> 	.read_and_clear		= sandbox_irq_read_and_clear,
> 	.of_xlate		= sandbox_irq_of_xlate,
>+#if CONFIG_IS_ENABLED(ACPIGEN)
>+	.get_acpi		= sandbox_get_acpi,
>+#endif
> };
> 
> static const struct udevice_id sandbox_irq_ids[] = {
>diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h
>index 09c227489a..24895de0da 100644
>--- a/include/acpi/acpi_device.h
>+++ b/include/acpi/acpi_device.h
>@@ -13,6 +13,12 @@
> 
> struct udevice;
> 
>+/* ACPI descriptor values for common descriptors: SERIAL_BUS means
>I2C */

I don't understand the comment above. Why does SERIAL_BUS mean I2C?
It could also mean SPI, or am I missing something?

>+#define ACPI_DESCRIPTOR_LARGE		BIT(7)
>+#define ACPI_DESCRIPTOR_INTERRUPT	(ACPI_DESCRIPTOR_LARGE | 9)
>+#define ACPI_DESCRIPTOR_GPIO		(ACPI_DESCRIPTOR_LARGE | 12)
>+#define ACPI_DESCRIPTOR_SERIAL_BUS	(ACPI_DESCRIPTOR_LARGE | 14)
>+
> /* Length of a full path to an ACPI device */
> #define ACPI_PATH_MAX		30
> 
>@@ -31,6 +37,59 @@ enum acpi_dev_status {
> 		ACPI_DSTATUS_SHOW_IN_UI,
> };
> 
>+/** enum acpi_irq_mode - edge/level trigger mode */
>+enum acpi_irq_mode {
>+	ACPI_IRQ_EDGE_TRIGGERED,
>+	ACPI_IRQ_LEVEL_TRIGGERED,
>+};
>+
>+/**
>+ * enum acpi_irq_polarity - polarity of interrupt
>+ *
>+ * @ACPI_IRQ_ACTIVE_LOW - for ACPI_IRQ_EDGE_TRIGGERED this means
>falling edge
>+ * @ACPI_IRQ_ACTIVE_HIGH - for ACPI_IRQ_EDGE_TRIGGERED this means
>rising edge
>+ * @ACPI_IRQ_ACTIVE_BOTH - not meaningful for
>ACPI_IRQ_EDGE_TRIGGERED
>+ */
>+enum acpi_irq_polarity {
>+	ACPI_IRQ_ACTIVE_LOW,
>+	ACPI_IRQ_ACTIVE_HIGH,
>+	ACPI_IRQ_ACTIVE_BOTH,
>+};
>+
>+/**
>+ * enum acpi_irq_shared - whether interrupt is shared or not
>+ *
>+ * @ACPI_IRQ_EXCLUSIVE: only this device uses the interrupt
>+ * @ACPI_IRQ_SHARED: other devices may use this interrupt
>+ */
>+enum acpi_irq_shared {
>+	ACPI_IRQ_EXCLUSIVE,
>+	ACPI_IRQ_SHARED,
>+};
>+
>+/** enum acpi_irq_wake - indicates whether this interrupt can wake
>the device */
>+enum acpi_irq_wake {
>+	ACPI_IRQ_NO_WAKE,
>+	ACPI_IRQ_WAKE,
>+};
>+
>+/**
>+ * struct acpi_irq - representation of an ACPI interrupt
>+ *
>+ * @pin: ACPI pin that is monitored for the interrupt
>+ * @mode: Edge/level triggering
>+ * @polarity: Interrupt polarity
>+ * @shared: Whether interrupt is shared or not
>+ * @wake: Whether interrupt can wake the device from sleep
>+ */
>+struct acpi_irq {
>+	unsigned int pin;
>+	enum acpi_irq_mode mode;
>+	enum acpi_irq_polarity polarity;
>+	enum acpi_irq_shared shared;
>+	enum acpi_irq_wake wake;
>+};
>+
> /**
>  * acpi_device_path() - Get the full path to an ACPI device
>  *
>diff --git a/include/irq.h b/include/irq.h
>index b71afe9bee..8527e4dd79 100644
>--- a/include/irq.h
>+++ b/include/irq.h
>@@ -8,6 +8,9 @@
> #ifndef __irq_H
> #define __irq_H
> 
>+struct acpi_irq;
>+struct ofnode_phandle_args;
>+
> /*
>  * Interrupt controller types available. You can find a particular
>one with
>  * irq_first_device_type()
>@@ -24,10 +27,12 @@ enum irq_dev_t {
>  *
>  * @dev: IRQ device that handles this irq
>  * @id: ID to identify this irq with the device
>+ * @flags: Flags associated with this interrupt (IRQ_TYPE_...)
>  */
> struct irq {
> 	struct udevice *dev;
> 	ulong id;
>+	ulong flags;
> };
> 
> /**
>@@ -119,10 +124,36 @@ struct irq_ops {
> 	 * @return 0 if OK, or a negative error code.
> 	 */
> 	int (*free)(struct irq *irq);
>+
>+#if CONFIG_IS_ENABLED(ACPIGEN)
>+	/**
>+	 * get_acpi() - Get the ACPI info for an irq
>+	 *
>+	 * This converts a irq to an ACPI structure for adding to the ACPI
>+	 * tables.
>+	 *
>+	 * @irq:	irq to convert
>+	 * @acpi_irq:	Output ACPI interrupt information
>+	 * @return ACPI pin number or -ve on error
>+	 */
>+	int (*get_acpi)(const struct irq *irq, struct acpi_irq *acpi_irq);
>+#endif
> };
> 
> #define irq_get_ops(dev)	((struct irq_ops *)(dev)->driver->ops)
> 
>+/**
>+ * irq_is_valid() - Check if an IRQ is valid
>+ *
>+ * @irq:	IRQ description containing device and ID, e.g. previously
>+ *		returned by irq_get_by_index()
>+ * @return true if valid, false if not
>+ */
>+static inline bool irq_is_valid(const struct irq *irq)
>+{
>+	return irq->dev != NULL;
>+}
>+
> /**
>  * irq_route_pmc_gpio_gpe() - Get the GPIO for an event
>  *
>@@ -223,4 +254,16 @@ int irq_free(struct irq *irq);
>  */
> int irq_first_device_type(enum irq_dev_t type, struct udevice
>**devp);
> 
>+/**
>+ * irq_get_acpi() - Get the ACPI info for an irq
>+ *
>+ * This converts a irq to an ACPI structure for adding to the ACPI
>+ * tables.
>+ *
>+ * @irq:	irq to convert
>+ * @acpi_irq:	Output ACPI interrupt information
>+ * @return ACPI pin number or -ve on error
>+ */
>+int irq_get_acpi(const struct irq *irq, struct acpi_irq *acpi_irq);
>+
> #endif
>diff --git a/test/dm/irq.c b/test/dm/irq.c
>index 192d80d7e1..50e505e657 100644
>--- a/test/dm/irq.c
>+++ b/test/dm/irq.c
>@@ -8,6 +8,7 @@
> #include <common.h>
> #include <dm.h>
> #include <irq.h>
>+#include <acpi/acpi_device.h>
> #include <asm/test.h>
> #include <dm/test.h>
> #include <test/ut.h>
>@@ -75,3 +76,24 @@ static int dm_test_request(struct unit_test_state
>*uts)
> 	return 0;
> }
> DM_TEST(dm_test_request, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
>+
>+/* Test of irq_get_acpi() */
>+static int dm_test_irq_get_acpi(struct unit_test_state *uts)
>+{
>+	struct acpi_irq airq;
>+	struct udevice *dev;
>+	struct irq irq;
>+
>+	ut_assertok(uclass_first_device_err(UCLASS_TEST_FDT, &dev));
>+	ut_assertok(irq_get_by_index(dev, 0, &irq));
>+
>+	ut_assertok(irq_get_acpi(&irq, &airq));
>+	ut_asserteq(3, airq.pin);
>+	ut_asserteq(ACPI_IRQ_LEVEL_TRIGGERED, airq.mode);
>+	ut_asserteq(ACPI_IRQ_ACTIVE_HIGH, airq.polarity);
>+	ut_asserteq(ACPI_IRQ_SHARED, airq.shared);
>+	ut_asserteq(ACPI_IRQ_WAKE, airq.wake);
>+
>+	return 0;
>+}
>+DM_TEST(dm_test_irq_get_acpi, DM_TESTF_SCAN_PDATA |
>DM_TESTF_SCAN_FDT);
>-- 
>2.26.2.645.ge9eca65c58-goog
>

regards, Wolfgang

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: [PATCH v2 05/35] acpi: Support generation of ACPI code
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (38 preceding siblings ...)
  2020-05-13 13:01 ` Antwort: [PATCH v2 04/35] irq: Add a method to convert an interrupt to ACPI Wolfgang Wallner
@ 2020-05-14  8:32 ` Wolfgang Wallner
  2020-06-09 21:14   ` Simon Glass
                     ` (2 more replies)
  2020-05-19  8:14 ` Antwort: [PATCH v2 08/35] acpi: Support string output Wolfgang Wallner
                   ` (28 subsequent siblings)
  68 siblings, 3 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-05-14  8:32 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 05/35] acpi: Support generation of ACPI code
> 
> Add a new file to handle generating ACPI code programatically. This is
> used when information must be dynamically added to the tables, e.g. the
> SSDT.
> 
> Initial support is just for writing simple values.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  include/acpi/acpigen.h | 49 +++++++++++++++++++++++++++++++
>  lib/acpi/Makefile      |  1 +
>  lib/acpi/acpigen.c     | 38 ++++++++++++++++++++++++
>  test/dm/Makefile       |  1 +
>  test/dm/acpigen.c      | 65 ++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 154 insertions(+)
>  create mode 100644 include/acpi/acpigen.h
>  create mode 100644 lib/acpi/acpigen.c
>  create mode 100644 test/dm/acpigen.c
> 
> diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
> new file mode 100644
> index 0000000000..8809cdb4e1
> --- /dev/null
> +++ b/include/acpi/acpigen.h
> @@ -0,0 +1,49 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Core ACPI (Advanced Configuration and Power Interface) support
> + *
> + * Copyright 2019 Google LLC
> + *
> + * Modified from coreboot file acpigen.h
> + */
> +
> +#ifndef __ACPI_ACPIGEN_H
> +#define __ACPI_ACPIGEN_H
> +
> +#include <linux/types.h>
> +
> +struct acpi_ctx;
> +
> +/**
> + * acpigen_get_current() - Get the current ACPI code output pointer
> + *
> + * @ctx: ACPI context pointer
> + * @return output pointer
> + */
> +u8 *acpigen_get_current(struct acpi_ctx *ctx);
> +
> +/**
> + * acpigen_emit_byte() - Emit a byte to the ACPI code
> + *
> + * @ctx: ACPI context pointer
> + * @data: Value to output
> + */
> +void acpigen_emit_byte(struct acpi_ctx *ctx, uint data);
> +
> +/**
> + * acpigen_emit_word() - Emit a 16-bit word to the ACPI code
> + *
> + * @ctx: ACPI context pointer
> + * @data: Value to output
> + */
> +void acpigen_emit_word(struct acpi_ctx *ctx, uint data);
> +
> +/**
> + * acpigen_emit_dword() - Emit a 32-bit 'double word' to the ACPI code
> + *
> + * @ctx: ACPI context pointer
> + * @data: Value to output
> + */
> +void acpigen_emit_dword(struct acpi_ctx *ctx, uint data);
> +
> +#endif
> diff --git a/lib/acpi/Makefile b/lib/acpi/Makefile
> index caae6c01bd..85a1f774ad 100644
> --- a/lib/acpi/Makefile
> +++ b/lib/acpi/Makefile
> @@ -1,5 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0+
>  #
>  
> +obj-y += acpigen.o
>  obj-y += acpi_device.o
>  obj-y += acpi_table.o
> diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
> new file mode 100644
> index 0000000000..59bd3af0b7
> --- /dev/null
> +++ b/lib/acpi/acpigen.c
> @@ -0,0 +1,38 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Generation of ACPI (Advanced Configuration and Power Interface) tables
> + *
> + * Copyright 2019 Google LLC
> + * Mostly taken from coreboot
> + */
> +
> +#define LOG_CATEGORY LOGC_ACPI
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <acpi/acpigen.h>
> +#include <dm/acpi.h>
> +
> +u8 *acpigen_get_current(struct acpi_ctx *ctx)
> +{
> +	return ctx->current;
> +}
> +
> +void acpigen_emit_byte(struct acpi_ctx *ctx, uint data)
> +{

As we expect exactly a byte, could data be of type uint8_t ?
Similar for the functions below.

> +	*(u8 *)ctx->current++ = data;
> +}
> +
> +void acpigen_emit_word(struct acpi_ctx *ctx, uint data)
> +{
> +	acpigen_emit_byte(ctx, data & 0xff);
> +	acpigen_emit_byte(ctx, (data >> 8) & 0xff);

This function assumes little-endian host endianess.  This works under
x86 and probably most of ARM, and I'm not aware of other architectures
using ACPI.

Should it be made more portable anyway e.g. by using cpu_to_le16()?

> +}
> +
> +void acpigen_emit_dword(struct acpi_ctx *ctx, uint data)
> +{
> +	acpigen_emit_byte(ctx, data & 0xff);
> +	acpigen_emit_byte(ctx, (data >> 8) & 0xff);
> +	acpigen_emit_byte(ctx, (data >> 16) & 0xff);
> +	acpigen_emit_byte(ctx, (data >> 24) & 0xff);
> +}
> diff --git a/test/dm/Makefile b/test/dm/Makefile
> index 6c18fd04ce..e3e0cccf01 100644
> --- a/test/dm/Makefile
> +++ b/test/dm/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_UT_DM) += test-uclass.o
>  obj-$(CONFIG_UT_DM) += core.o
>  ifneq ($(CONFIG_SANDBOX),)
>  obj-$(CONFIG_ACPIGEN) += acpi.o
> +obj-$(CONFIG_ACPIGEN) += acpigen.o
>  obj-$(CONFIG_SOUND) += audio.o
>  obj-$(CONFIG_BLK) += blk.o
>  obj-$(CONFIG_BOARD) += board.o
> diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
> new file mode 100644
> index 0000000000..68f2b73132
> --- /dev/null
> +++ b/test/dm/acpigen.c
> @@ -0,0 +1,65 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Tests for ACPI code generation
> + *
> + * Copyright 2019 Google LLC
> + * Written by Simon Glass <sjg@chromium.org>
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <malloc.h>
> +#include <acpi/acpigen.h>
> +#include <asm/unaligned.h>
> +#include <dm/acpi.h>
> +#include <dm/test.h>
> +#include <test/ut.h>
> +
> +static int alloc_context(struct acpi_ctx **ctxp)
> +{
> +	struct acpi_ctx *ctx;
> +
> +	*ctxp = NULL;
> +	ctx = malloc(sizeof(*ctx));
> +	if (!ctx)
> +		return -ENOMEM;
> +	ctx->current = malloc(150);
> +	if (!ctx->current)

free(ctx)

> +		return -ENOMEM;
> +	*ctxp = ctx;
> +
> +	return 0;
> +}
> +
> +static void free_context(struct acpi_ctx **ctxp)
> +{
	
Should the memory that was initally allocated to ctx->current also be
released or stay allocted?
	
> +	free(*ctxp);
> +	*ctxp = NULL;
> +}
> +
> +/* Test emitting simple types and acpigen_get_current() */
> +static int dm_test_acpi_emit_simple(struct unit_test_state *uts)
> +{
> +	struct acpi_ctx *ctx;
> +	u8 *ptr;
> +
> +	ut_assertok(alloc_context(&ctx));
> +
> +	ptr = acpigen_get_current(ctx);
> +	acpigen_emit_byte(ctx, 0x23);
> +	ut_asserteq(1, acpigen_get_current(ctx) - ptr);
> +	ut_asserteq(0x23, *(u8 *)ptr);
> +
> +	acpigen_emit_word(ctx, 0x1234);
> +	ut_asserteq(3, acpigen_get_current(ctx) - ptr);
> +	ut_asserteq(0x1234, get_unaligned((u16 *)(ptr + 1)));
> +
> +	acpigen_emit_dword(ctx, 0x87654321);
> +	ut_asserteq(7, acpigen_get_current(ctx) - ptr);
> +	ut_asserteq(0x87654321, get_unaligned((u32 *)(ptr + 3)));
> +
> +	free_context(&ctx);
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_acpi_emit_simple, 0);
> -- 
> 2.26.2.645.ge9eca65c58-goog

regards, Wolfgang

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 04/35] irq: Add a method to convert an interrupt to ACPI
  2020-05-13 13:01 ` Antwort: [PATCH v2 04/35] irq: Add a method to convert an interrupt to ACPI Wolfgang Wallner
@ 2020-05-14 16:02   ` Simon Glass
  2020-05-18  7:47   ` Antwort: " Wolfgang Wallner
  1 sibling, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-05-14 16:02 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

On Wed, 13 May 2020 at 07:01, Wolfgang Wallner
<wolfgang.wallner@br-automation.com> wrote:
>
> Hi Simon,
>
> -----"Simon Glass" <sjg@chromium.org> schrieb: -----
> >Betreff: [PATCH v2 04/35] irq: Add a method to convert an interrupt
> >to ACPI
> >
> >When generating ACPI tables we need to convert IRQs in U-Boot to the
> >ACPI
> >structures required by ACPI. This is a SoC-specific conversion and
> >cannot
> >be handled by generic code, so add a new IRQ method to do the
> >conversion.
> >
> >Signed-off-by: Simon Glass <sjg@chromium.org>
> >---
> >
> >Changes in v2: None
> >Changes in v1:
> >- Fix 'the an' typo
> >- Move header definitions into this patch
> >
> > drivers/misc/irq-uclass.c  | 18 ++++++++++--
> > drivers/misc/irq_sandbox.c | 16 +++++++++++
> > include/acpi/acpi_device.h | 59
> >++++++++++++++++++++++++++++++++++++++
> > include/irq.h              | 43 +++++++++++++++++++++++++++
> > test/dm/irq.c              | 22 ++++++++++++++
> > 5 files changed, 156 insertions(+), 2 deletions(-)
> >
> >diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
> >index 16dc0be75c..98bc79eaba 100644
> >--- a/drivers/misc/irq-uclass.c
> >+++ b/drivers/misc/irq-uclass.c
> >@@ -154,8 +154,6 @@ int irq_request(struct udevice *dev, struct irq
> >*irq)
> >       const struct irq_ops *ops;
> >
> >       log_debug("(dev=%p, irq=%p)\n", dev, irq);
> >-      if (!irq)
> >-              return 0;
>
> Why are these lines dropped?

Because we are not allowed to pass a NULL irq to this function. That
check should not have been there.

>
> As far as I understand the code they can be dropped, I just fail
> to see how that is related to the ACPI changes.
>
> >       ops = irq_get_ops(dev);
> >
> >       irq->dev = dev;
> >@@ -177,6 +175,22 @@ int irq_first_device_type(enum irq_dev_t type,
> >struct udevice **devp)
> >       return 0;
> > }


> >
> >+#if CONFIG_IS_ENABLED(ACPIGEN)
> >+int irq_get_acpi(const struct irq *irq, struct acpi_irq *acpi_irq)
> >+{
> >+      struct irq_ops *ops;
> >+
> >+      if (!irq_is_valid(irq))
> >+              return -EINVAL;
> >+
> >+      ops = irq_get_ops(irq->dev);
> >+      if (!ops->get_acpi)
> >+              return -ENOSYS;
> >+
> >+      return ops->get_acpi(irq, acpi_irq);
> >+}
> >+#endif
> >+
> > UCLASS_DRIVER(irq) = {
> >       .id             = UCLASS_IRQ,
> >       .name           = "irq",
> >diff --git a/drivers/misc/irq_sandbox.c b/drivers/misc/irq_sandbox.c
> >index 54bc47c8d8..a2511b32fc 100644
> >--- a/drivers/misc/irq_sandbox.c
> >+++ b/drivers/misc/irq_sandbox.c
> >@@ -8,6 +8,7 @@
> > #include <common.h>
> > #include <dm.h>
> > #include <irq.h>
> >+#include <acpi/acpi_device.h>
> > #include <asm/test.h>
> >
> > /**
> >@@ -73,6 +74,18 @@ static int sandbox_irq_of_xlate(struct irq *irq,
> >       return 0;
> > }
> >
> >+static __maybe_unused int sandbox_get_acpi(const struct irq *irq,
> >+                                         struct acpi_irq *acpi_irq)
> >+{
> >+      acpi_irq->pin = irq->id;
> >+      acpi_irq->mode = ACPI_IRQ_LEVEL_TRIGGERED;
> >+      acpi_irq->polarity = ACPI_IRQ_ACTIVE_HIGH;
> >+      acpi_irq->shared = ACPI_IRQ_SHARED;
> >+      acpi_irq->wake = ACPI_IRQ_WAKE;
> >+
> >+      return 0;
> >+}
> >+
> > static const struct irq_ops sandbox_irq_ops = {
> >       .route_pmc_gpio_gpe     = sandbox_route_pmc_gpio_gpe,
> >       .set_polarity           = sandbox_set_polarity,
> >@@ -80,6 +93,9 @@ static const struct irq_ops sandbox_irq_ops = {
> >       .restore_polarities     = sandbox_restore_polarities,
> >       .read_and_clear         = sandbox_irq_read_and_clear,
> >       .of_xlate               = sandbox_irq_of_xlate,
> >+#if CONFIG_IS_ENABLED(ACPIGEN)
> >+      .get_acpi               = sandbox_get_acpi,
> >+#endif
> > };
> >
> > static const struct udevice_id sandbox_irq_ids[] = {
> >diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h
> >index 09c227489a..24895de0da 100644
> >--- a/include/acpi/acpi_device.h
> >+++ b/include/acpi/acpi_device.h
> >@@ -13,6 +13,12 @@
> >
> > struct udevice;
> >
> >+/* ACPI descriptor values for common descriptors: SERIAL_BUS means
> >I2C */
>
> I don't understand the comment above. Why does SERIAL_BUS mean I2C?
> It could also mean SPI, or am I missing something?

Just that descriptor 14 is used for serial bus (UART, SPI, I2C) and in
this code it is used for I2C. I didn't want to call it I2C since that
would be inaccurate, hence the comment.

>
> >+#define ACPI_DESCRIPTOR_LARGE         BIT(7)
> >+#define ACPI_DESCRIPTOR_INTERRUPT     (ACPI_DESCRIPTOR_LARGE | 9)
> >+#define ACPI_DESCRIPTOR_GPIO          (ACPI_DESCRIPTOR_LARGE | 12)
> >+#define ACPI_DESCRIPTOR_SERIAL_BUS    (ACPI_DESCRIPTOR_LARGE | 14)
> >+

Regards,
Simon

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: Re: [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B)
  2020-05-13  9:55       ` Andy Shevchenko
@ 2020-05-14 16:02         ` Simon Glass
  2020-05-14 16:38           ` Andy Shevchenko
  0 siblings, 1 reply; 84+ messages in thread
From: Simon Glass @ 2020-05-14 16:02 UTC (permalink / raw)
  To: u-boot

Hi,

On Wed, 13 May 2020 at 03:55, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Tue, May 12, 2020 at 05:22:38PM -0600, Simon Glass wrote:
> > Hi Andy,
> >
> > On Tue, 12 May 2020 at 06:32, Andy Shevchenko
> > <andriy.shevchenko@linux.intel.com> wrote:
> > >
> > > On Tue, May 12, 2020 at 01:55:49PM +0200, Wolfgang Wallner wrote:
> > >
> > > > > Since you were involved a lot in the discussion in the part A series,
> > > > > would you please let me know if you get some time to review this?
> > > >
> > > > Unfortunately, I don't have as much time now for review of part B as I had for
> > > > part A. I already started reviewing part B and I will try to continue when time
> > > > allows.
> > >
> > > I'm busy at the moment and I will be not available for this for few weeks.
> > > Code can be fixed iteratively, the most important part now is to see the big
> > > picture of the design and approach.
> > >
> > > Could you remind which patch in the series describes that? I will look at it
> > > closer and try to allocate a bit of time to do it.
> > >
> >
> > The big picture was in part A. Part B uses the same mechanism to add
> > support for SSDT and DSDT generation, e.g. see [1] and [2].
>
> Thank you, then I think what is left are technical (implementation) details
> that can be amended in the future.

OK then perhaps part B can be applied and I can send part C, which is
the actual coral implementation?

Regards,
SImon

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: Re: [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B)
  2020-05-14 16:02         ` Simon Glass
@ 2020-05-14 16:38           ` Andy Shevchenko
  0 siblings, 0 replies; 84+ messages in thread
From: Andy Shevchenko @ 2020-05-14 16:38 UTC (permalink / raw)
  To: u-boot

On Thu, May 14, 2020 at 10:02:08AM -0600, Simon Glass wrote:
> On Wed, 13 May 2020 at 03:55, Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > On Tue, May 12, 2020 at 05:22:38PM -0600, Simon Glass wrote:
> > > On Tue, 12 May 2020 at 06:32, Andy Shevchenko
> > > <andriy.shevchenko@linux.intel.com> wrote:
> > > > On Tue, May 12, 2020 at 01:55:49PM +0200, Wolfgang Wallner wrote:

...

> > > > Could you remind which patch in the series describes that? I will look at it
> > > > closer and try to allocate a bit of time to do it.
> > > >
> > >
> > > The big picture was in part A. Part B uses the same mechanism to add
> > > support for SSDT and DSDT generation, e.g. see [1] and [2].
> >
> > Thank you, then I think what is left are technical (implementation) details
> > that can be amended in the future.
> 
> OK then perhaps part B can be applied and I can send part C, which is
> the actual coral implementation?

I think so.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 01/35] dm: core: Add an ACPI name for the root node
  2020-05-10 20:33 ` [PATCH v2 01/35] dm: core: Add an ACPI name for the root node Simon Glass
@ 2020-05-17 14:40   ` Bin Meng
  0 siblings, 0 replies; 84+ messages in thread
From: Bin Meng @ 2020-05-17 14:40 UTC (permalink / raw)
  To: u-boot

On Mon, May 11, 2020 at 4:34 AM Simon Glass <sjg@chromium.org> wrote:
>
> This always has a fixed ACPI name so add it as a driver function.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>
> ---
>
> Changes in v2: None
> Changes in v1:
> - Capitalise ACPI_OPS_PTR
>
>  drivers/core/root.c | 13 +++++++++++++
>  1 file changed, 13 insertions(+)
>

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 02/35] acpi: Add a function to get a device path and scope
  2020-05-10 20:33 ` [PATCH v2 02/35] acpi: Add a function to get a device path and scope Simon Glass
@ 2020-05-17 14:54   ` Bin Meng
  0 siblings, 0 replies; 84+ messages in thread
From: Bin Meng @ 2020-05-17 14:54 UTC (permalink / raw)
  To: u-boot

On Mon, May 11, 2020 at 4:34 AM Simon Glass <sjg@chromium.org> wrote:
>
> Add a function to build up the ACPI path for a device and another for its
> scope.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>
> ---
>
> Changes in v2: None
> Changes in v1:
> - Split into more patches for review
> - Add tests
> - Rebase on top of common.h series
>
>  arch/sandbox/dts/test.dts  |  3 ++
>  include/acpi/acpi_device.h | 44 ++++++++++++++++++
>  lib/acpi/Makefile          |  1 +
>  lib/acpi/acpi_device.c     | 83 +++++++++++++++++++++++++++++++++
>  test/dm/acpi.c             | 95 ++++++++++++++++++++++++++++++++------
>  5 files changed, 213 insertions(+), 13 deletions(-)
>  create mode 100644 include/acpi/acpi_device.h
>  create mode 100644 lib/acpi/acpi_device.c
>
> diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
> index 15cd2330a3..b802c1c909 100644
> --- a/arch/sandbox/dts/test.dts
> +++ b/arch/sandbox/dts/test.dts
> @@ -253,6 +253,9 @@
>
>         acpi-test {
>                 compatible = "denx,u-boot-acpi-test";
> +               child {
> +                       compatible = "denx,u-boot-acpi-test";
> +               };
>         };
>
>         acpi-test2 {
> diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h
> new file mode 100644
> index 0000000000..37a675f101
> --- /dev/null
> +++ b/include/acpi/acpi_device.h
> @@ -0,0 +1,44 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Generation of tables for particular device types
> + *
> + * Copyright 2019 Google LLC
> + * Mostly taken from coreboot file of the same name
> + */
> +
> +#ifndef __ACPI_DEVICE_H
> +#define __ACPI_DEVICE_H
> +
> +struct udevice;
> +
> +/* Length of a full path to an ACPI device */
> +#define ACPI_PATH_MAX          30
> +
> +/**
> + * acpi_device_path() - Get the full path to an ACPI device
> + *
> + * This gets the full path in the form XXXX.YYYY.ZZZZ where XXXX is the root
> + * and ZZZZ is the device. All parent devices are added to the path.
> + *
> + * @dev: Device to check
> + * @buf: 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_device_path(const struct udevice *dev, char *buf, int maxlen);
> +
> +/**
> + * acpi_device_scope() - Get the scope of an ACPI device
> + *
> + * This gets the scope which is the full path of the parent device, as per
> + * acpi_device_path().
> + *
> + * @dev: Device to check
> + * @buf: Buffer to place the path in (should be ACPI_PATH_MAX long)
> + * @maxlen: Size of buffer (typically ACPI_PATH_MAX)
> + * @return 0 if OK, -EINVAL if the device has no parent, other -ve on other
> + *     error
> + */
> +int acpi_device_scope(const struct udevice *dev, char *scope, int maxlen);
> +
> +#endif
> diff --git a/lib/acpi/Makefile b/lib/acpi/Makefile
> index 660491ef71..caae6c01bd 100644
> --- a/lib/acpi/Makefile
> +++ b/lib/acpi/Makefile
> @@ -1,4 +1,5 @@
>  # SPDX-License-Identifier: GPL-2.0+
>  #
>
> +obj-y += acpi_device.o
>  obj-y += acpi_table.o
> diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
> new file mode 100644
> index 0000000000..f9af2343c1
> --- /dev/null
> +++ b/lib/acpi/acpi_device.c
> @@ -0,0 +1,83 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Generation of tables for particular device types
> + *
> + * Copyright 2019 Google LLC
> + * Mostly taken from coreboot file of the same name
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <log.h>
> +#include <acpi/acpi_device.h>
> +#include <dm/acpi.h>
> +
> +/**
> + * acpi_device_path_fill() - Find the root device and build a path from there
> + *
> + * This recursively reaches back to the root device and progressively adds path
> + * elements until the device is reached.
> + *
> + * @dev: Device to return path of
> + * @buf: Buffer to hold the path
> + * @buf_len: Length of buffer
> + * @cur: Current position in the buffer
> + * @return new position in buffer after adding @dev, or -ve on error
> + */
> +static int acpi_device_path_fill(const struct udevice *dev, char *buf,
> +                                size_t buf_len, int cur)
> +{
> +       char name[ACPI_NAME_MAX];
> +       int next = 0;
> +       int ret;
> +
> +       ret = acpi_get_name(dev, name);
> +       if (ret)
> +               return ret;
> +
> +       /*
> +        * Make sure this name segment will fit, including the path segment
> +        * separator and possible NUL terminator, if this is the last segment.

typo: NULL

> +        */
> +       if (cur + strlen(name) + 2 > buf_len)
> +               return -ENOSPC;
> +
> +       /* Walk up the tree to the root device */
> +       if (dev_get_parent(dev)) {
> +               next = acpi_device_path_fill(dev_get_parent(dev), buf, buf_len,
> +                                            cur);
> +               if (next < 0)
> +                       return next;
> +       }
> +
> +       /* Fill in the path from the root device */
> +       next += snprintf(buf + next, buf_len - next, "%s%s",
> +                        dev_get_parent(dev) && *name ? "." : "", name);
> +
> +       return next;
> +}
> +

[snip]

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: Re: [PATCH v2 04/35] irq: Add a method to convert an interrupt to ACPI
  2020-05-13 13:01 ` Antwort: [PATCH v2 04/35] irq: Add a method to convert an interrupt to ACPI Wolfgang Wallner
  2020-05-14 16:02   ` Simon Glass
@ 2020-05-18  7:47   ` Wolfgang Wallner
  1 sibling, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-05-18  7:47 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: Re: [PATCH v2 04/35] irq: Add a method to convert an interrupt to ACPI
> 
> Hi Wolfgang,
> 
> On Wed, 13 May 2020 at 07:01, Wolfgang Wallner
> <wolfgang.wallner@br-automation.com> wrote:
> >
> > Hi Simon,
> >
> > -----"Simon Glass" <sjg@chromium.org> schrieb: -----
> > >Betreff: [PATCH v2 04/35] irq: Add a method to convert an interrupt
> > >to ACPI
> > >
> > >When generating ACPI tables we need to convert IRQs in U-Boot to the
> > >ACPI
> > >structures required by ACPI. This is a SoC-specific conversion and
> > >cannot
> > >be handled by generic code, so add a new IRQ method to do the
> > >conversion.
> > >
> > >Signed-off-by: Simon Glass <sjg@chromium.org>
> > >---
> > >
> > >Changes in v2: None
> > >Changes in v1:
> > >- Fix 'the an' typo
> > >- Move header definitions into this patch
> > >
> > > drivers/misc/irq-uclass.c  | 18 ++++++++++--
> > > drivers/misc/irq_sandbox.c | 16 +++++++++++
> > > include/acpi/acpi_device.h | 59
> > >++++++++++++++++++++++++++++++++++++++
> > > include/irq.h              | 43 +++++++++++++++++++++++++++
> > > test/dm/irq.c              | 22 ++++++++++++++
> > > 5 files changed, 156 insertions(+), 2 deletions(-)
> > >
> > >diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
> > >index 16dc0be75c..98bc79eaba 100644
> > >--- a/drivers/misc/irq-uclass.c
> > >+++ b/drivers/misc/irq-uclass.c
> > >@@ -154,8 +154,6 @@ int irq_request(struct udevice *dev, struct irq
> > >*irq)
> > >       const struct irq_ops *ops;
> > >
> > >       log_debug("(dev=%p, irq=%p)\n", dev, irq);
> > >-      if (!irq)
> > >-              return 0;
> >
> > Why are these lines dropped?
> 
> Because we are not allowed to pass a NULL irq to this function. That
> check should not have been there.
> 
> >
> > As far as I understand the code they can be dropped, I just fail
> > to see how that is related to the ACPI changes.
> >
> > >       ops = irq_get_ops(dev);
> > >
> > >       irq->dev = dev;
> > >@@ -177,6 +175,22 @@ int irq_first_device_type(enum irq_dev_t type,
> > >struct udevice **devp)
> > >       return 0;
> > > }
> 
> 
> > >
> > >+#if CONFIG_IS_ENABLED(ACPIGEN)
> > >+int irq_get_acpi(const struct irq *irq, struct acpi_irq *acpi_irq)
> > >+{
> > >+      struct irq_ops *ops;
> > >+
> > >+      if (!irq_is_valid(irq))
> > >+              return -EINVAL;
> > >+
> > >+      ops = irq_get_ops(irq->dev);
> > >+      if (!ops->get_acpi)
> > >+              return -ENOSYS;
> > >+
> > >+      return ops->get_acpi(irq, acpi_irq);
> > >+}
> > >+#endif
> > >+
> > > UCLASS_DRIVER(irq) = {
> > >       .id             = UCLASS_IRQ,
> > >       .name           = "irq",
> > >diff --git a/drivers/misc/irq_sandbox.c b/drivers/misc/irq_sandbox.c
> > >index 54bc47c8d8..a2511b32fc 100644
> > >--- a/drivers/misc/irq_sandbox.c
> > >+++ b/drivers/misc/irq_sandbox.c
> > >@@ -8,6 +8,7 @@
> > > #include <common.h>
> > > #include <dm.h>
> > > #include <irq.h>
> > >+#include <acpi/acpi_device.h>
> > > #include <asm/test.h>
> > >
> > > /**
> > >@@ -73,6 +74,18 @@ static int sandbox_irq_of_xlate(struct irq *irq,
> > >       return 0;
> > > }
> > >
> > >+static __maybe_unused int sandbox_get_acpi(const struct irq *irq,
> > >+                                         struct acpi_irq *acpi_irq)
> > >+{
> > >+      acpi_irq->pin = irq->id;
> > >+      acpi_irq->mode = ACPI_IRQ_LEVEL_TRIGGERED;
> > >+      acpi_irq->polarity = ACPI_IRQ_ACTIVE_HIGH;
> > >+      acpi_irq->shared = ACPI_IRQ_SHARED;
> > >+      acpi_irq->wake = ACPI_IRQ_WAKE;
> > >+
> > >+      return 0;
> > >+}
> > >+
> > > static const struct irq_ops sandbox_irq_ops = {
> > >       .route_pmc_gpio_gpe     = sandbox_route_pmc_gpio_gpe,
> > >       .set_polarity           = sandbox_set_polarity,
> > >@@ -80,6 +93,9 @@ static const struct irq_ops sandbox_irq_ops = {
> > >       .restore_polarities     = sandbox_restore_polarities,
> > >       .read_and_clear         = sandbox_irq_read_and_clear,
> > >       .of_xlate               = sandbox_irq_of_xlate,
> > >+#if CONFIG_IS_ENABLED(ACPIGEN)
> > >+      .get_acpi               = sandbox_get_acpi,
> > >+#endif
> > > };
> > >
> > > static const struct udevice_id sandbox_irq_ids[] = {
> > >diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h
> > >index 09c227489a..24895de0da 100644
> > >--- a/include/acpi/acpi_device.h
> > >+++ b/include/acpi/acpi_device.h
> > >@@ -13,6 +13,12 @@
> > >
> > > struct udevice;
> > >
> > >+/* ACPI descriptor values for common descriptors: SERIAL_BUS means
> > >I2C */
> >
> > I don't understand the comment above. Why does SERIAL_BUS mean I2C?
> > It could also mean SPI, or am I missing something?
> 
> Just that descriptor 14 is used for serial bus (UART, SPI, I2C) and in
> this code it is used for I2C. I didn't want to call it I2C since that
> would be inaccurate, hence the comment.

Nit: I would suggest to either drop or expand "SERIAL_BUS means I2C".
In its current form that comment confused me more than it helped me.

> 
> >
> > >+#define ACPI_DESCRIPTOR_LARGE         BIT(7)
> > >+#define ACPI_DESCRIPTOR_INTERRUPT     (ACPI_DESCRIPTOR_LARGE | 9)
> > >+#define ACPI_DESCRIPTOR_GPIO          (ACPI_DESCRIPTOR_LARGE | 12)
> > >+#define ACPI_DESCRIPTOR_SERIAL_BUS    (ACPI_DESCRIPTOR_LARGE | 14)
> > >+
> 
> Regards,
> Simon

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: [PATCH v2 08/35] acpi: Support string output
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (39 preceding siblings ...)
  2020-05-14  8:32 ` Antwort: [PATCH v2 05/35] acpi: Support generation of ACPI code Wolfgang Wallner
@ 2020-05-19  8:14 ` Wolfgang Wallner
  2020-05-19  8:56 ` [PATCH v2 09/35] acpi: Support generation of GPIO descriptor Wolfgang Wallner
                   ` (27 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-05-19  8:14 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 08/35] acpi: Support string output
> 
> Add support for output of strings and streams of bytes.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  include/acpi/acpigen.h | 19 +++++++++++++++++++
>  lib/acpi/acpigen.c     | 14 ++++++++++++++
>  test/dm/acpigen.c      | 42 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 75 insertions(+)

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 09/35] acpi: Support generation of GPIO descriptor
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (40 preceding siblings ...)
  2020-05-19  8:14 ` Antwort: [PATCH v2 08/35] acpi: Support string output Wolfgang Wallner
@ 2020-05-19  8:56 ` Wolfgang Wallner
  2020-05-19  9:32 ` Antwort: [PATCH v2 10/35] acpi: Support generation of a GPIO/irq for a device Wolfgang Wallner
                   ` (26 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-05-19  8:56 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 09/35] acpi: Support generation of GPIO descriptor
> 
> Add a function to write a GPIO descriptor to the generated ACPI code.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  include/acpi/acpi_device.h |  22 ++++++
>  lib/acpi/acpi_device.c     | 151 +++++++++++++++++++++++++++++++++++++
>  test/dm/acpigen.c          |  89 ++++++++++++++++++++++
>  3 files changed, 262 insertions(+)

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: [PATCH v2 10/35] acpi: Support generation of a GPIO/irq for a device
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (41 preceding siblings ...)
  2020-05-19  8:56 ` [PATCH v2 09/35] acpi: Support generation of GPIO descriptor Wolfgang Wallner
@ 2020-05-19  9:32 ` Wolfgang Wallner
  2020-05-19 11:58 ` Antwort: [PATCH v2 11/35] acpi: Support generation of I2C descriptor Wolfgang Wallner
                   ` (25 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-05-19  9:32 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 10/35] acpi: Support generation of a GPIO/irq for a device
> 
> Some devices use interrupts but some use GPIOs. Since these are fully
> specified in the device tree we can automatically produce the correct ACPI
> descriptor for a device.
> 
> Add a function to handle this.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  include/acpi/acpi_device.h | 15 ++++++++++++++
>  lib/acpi/acpi_device.c     | 26 ++++++++++++++++++++++++
>  test/dm/acpigen.c          | 41 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 82 insertions(+)
> 
> diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h
> index 5f229d79cf..70c151d150 100644
> --- a/include/acpi/acpi_device.h
> +++ b/include/acpi/acpi_device.h
> @@ -255,4 +255,19 @@ int acpi_device_write_gpio(struct acpi_ctx *ctx, const struct acpi_gpio *gpio);
>  int acpi_device_write_gpio_desc(struct acpi_ctx *ctx,
>  				const struct gpio_desc *desc);
>  
> +/**
> + * acpi_device_write_interrupt_or_gpio() - Write interrupt or GPIO to ACPI
> + *
> + * This reads an interrupt from the device tree "interrupts-extended" property,
> + * if available. If not it reads the first GPIO with the name @prop.
> + *
> + * If an interrupt is found, an ACPI interrupt descriptor is written to the ACPI
> + * output. If not, but an GPIO is found, a GPIO descriptor is written.

Nit: I think it should be "a GPIO is found"

> + *
> + * @return 0 if OK, -ve if neither an interrupt nor a GPIO could be found, or
> + * some other error occurred
> + */
> +int acpi_device_write_interrupt_or_gpio(struct acpi_ctx *ctx,
> +					struct udevice *dev, const char *prop);
> +
>  #endif
> diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
> index 4c5bfdb9a2..423b91cfd2 100644
> --- a/lib/acpi/acpi_device.c
> +++ b/lib/acpi/acpi_device.c
> @@ -355,3 +355,29 @@ int acpi_device_write_gpio_desc(struct acpi_ctx *ctx,
>  
>  	return 0;
>  }
> +
> +int acpi_device_write_interrupt_or_gpio(struct acpi_ctx *ctx,
> +					struct udevice *dev, const char *prop)
> +{
> +	struct irq req_irq;
> +	int ret;
> +
> +	ret = irq_get_by_index(dev, 0, &req_irq);
> +	if (!ret) {
> +		ret = acpi_device_write_interrupt_irq(ctx, &req_irq);
> +		if (ret)
> +			return log_msg_ret("irq", ret);
> +	} else {
> +		struct gpio_desc req_gpio;
> +
> +		ret = gpio_request_by_name(dev, prop, 0, &req_gpio,
> +					   GPIOD_IS_IN);
> +		if (ret)
> +			return log_msg_ret("no gpio", ret);
> +		ret = acpi_device_write_gpio_desc(ctx, &req_gpio);
> +		if (ret)
> +			return log_msg_ret("gpio", ret);
> +	}
> +
> +	return 0;
> +}

Note to other reviewers:
The function above was already discussed in another thread at [1].
Summary: the index value 0 is hardcoded, as only a single interrupt / GPIO
is supported at present.

[1] https://lists.denx.de/pipermail/u-boot/2020-March/403557.html

> diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
> index 73fe6c9f4d..6aefa6845d 100644
> --- a/test/dm/acpigen.c
> +++ b/test/dm/acpigen.c
> @@ -16,6 +16,7 @@
>  #include <asm/unaligned.h>
>  #include <dm/acpi.h>
>  #include <dm/test.h>
> +#include <dm/uclass-internal.h>
>  #include <test/ut.h>
>  
>  #define TEST_STRING	"frogmore"
> @@ -225,3 +226,43 @@ static int dm_test_acpi_gpio_irq(struct unit_test_state *uts)
>  	return 0;
>  }
>  DM_TEST(dm_test_acpi_gpio_irq, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> +
> +/* Test emitting either a GPIO or interrupt descriptor */
> +static int dm_test_acpi_interrupt_or_gpio(struct unit_test_state *uts)
> +{
> +	struct acpi_ctx *ctx;
> +	struct udevice *dev;
> +	u8 *ptr;
> +
> +	ut_assertok(alloc_context(&ctx));
> +
> +	ptr = acpigen_get_current(ctx);
> +
> +	/* This should produce an interrupt, even though it also has a GPIO */
> +	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
> +	ut_asserteq_str("a-test", dev->name);
> +	ut_assertok(acpi_device_write_interrupt_or_gpio(ctx, dev,
> +							"test2-gpios"));
> +	ut_asserteq(ACPI_DESCRIPTOR_INTERRUPT, ptr[0]);
> +
> +	/* This has no interrupt so should produce a GPIO */
> +	ptr = ctx->current;
> +	ut_assertok(uclass_find_first_device(UCLASS_PANEL_BACKLIGHT, &dev));
> +	ut_assertok(acpi_device_write_interrupt_or_gpio(ctx, dev,
> +							"enable-gpios"));
> +	ut_asserteq(ACPI_DESCRIPTOR_GPIO, ptr[0]);
> +
> +	/* This one has neither */
> +	ptr = acpigen_get_current(ctx);
> +	ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 3, &dev));
> +	ut_asserteq_str("b-test", dev->name);
> +	ut_asserteq(-ENOENT,
> +		    acpi_device_write_interrupt_or_gpio(ctx, dev,
> +							"enable-gpios"));
> +
> +	free_context(&ctx);
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_acpi_interrupt_or_gpio,
> +	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> -- 
> 2.26.2.645.ge9eca65c58-goog
> 
 
Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: [PATCH v2 11/35] acpi: Support generation of I2C descriptor
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (42 preceding siblings ...)
  2020-05-19  9:32 ` Antwort: [PATCH v2 10/35] acpi: Support generation of a GPIO/irq for a device Wolfgang Wallner
@ 2020-05-19 11:58 ` Wolfgang Wallner
  2020-06-09 21:14   ` Simon Glass
  2020-05-19 13:14 ` Antwort: [PATCH v2 13/35] acpigen: Support writing a length Wolfgang Wallner
                   ` (24 subsequent siblings)
  68 siblings, 1 reply; 84+ messages in thread
From: Wolfgang Wallner @ 2020-05-19 11:58 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 11/35] acpi: Support generation of I2C descriptor
> 
> Add a function to write a GPIO descriptor to the generated ACPI code.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2:
> - Fix memset of I2C descriptor
> 
> Changes in v1: None
> 
>  drivers/i2c/sandbox_i2c.c  |  11 ++++
>  drivers/rtc/sandbox_rtc.c  |  13 +++++
>  include/acpi/acpi_device.h |  36 +++++++++++++
>  lib/acpi/acpi_device.c     | 103 +++++++++++++++++++++++++++++++++++++
>  test/dm/acpigen.c          |  32 ++++++++++++
>  5 files changed, 195 insertions(+)
> 
> diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c
> index f4ae2397a0..125026da90 100644
> --- a/drivers/i2c/sandbox_i2c.c
> +++ b/drivers/i2c/sandbox_i2c.c
> @@ -11,6 +11,7 @@
>  #include <i2c.h>
>  #include <log.h>
>  #include <asm/test.h>
> +#include <dm/acpi.h>
>  #include <dm/lists.h>
>  #include <dm/device-internal.h>
>  
> @@ -83,6 +84,15 @@ 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,
>  };
> @@ -98,4 +108,5 @@ 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/rtc/sandbox_rtc.c b/drivers/rtc/sandbox_rtc.c
> index b08d758a74..f2906c3397 100644
> --- a/drivers/rtc/sandbox_rtc.c
> +++ b/drivers/rtc/sandbox_rtc.c
> @@ -9,6 +9,7 @@
>  #include <i2c.h>
>  #include <rtc.h>
>  #include <asm/rtc.h>
> +#include <dm/acpi.h>
>  
>  #define REG_COUNT 0x80
>  
> @@ -84,6 +85,17 @@ static int sandbox_rtc_write8(struct udevice *dev, unsigned int reg, int val)
>  	return dm_i2c_reg_write(dev, reg, val);
>  }
>  
> +#if CONFIG_IS_ENABLED(ACPIGEN)
> +static int sandbox_rtc_get_name(const struct udevice *dev, char *out_name)
> +{
> +	return acpi_copy_name(out_name, "RTCC");
> +}
> +
> +struct acpi_ops sandbox_rtc_acpi_ops = {
> +	.get_name	= sandbox_rtc_get_name,
> +};
> +#endif
> +
>  static const struct rtc_ops sandbox_rtc_ops = {
>  	.get = sandbox_rtc_get,
>  	.set = sandbox_rtc_set,
> @@ -102,4 +114,5 @@ U_BOOT_DRIVER(rtc_sandbox) = {
>  	.id	= UCLASS_RTC,
>  	.of_match = sandbox_rtc_ids,
>  	.ops	= &sandbox_rtc_ops,
> +	ACPI_OPS_PTR(&sandbox_rtc_acpi_ops)
>  };
> diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h
> index 70c151d150..cf1ac695a7 100644
> --- a/include/acpi/acpi_device.h
> +++ b/include/acpi/acpi_device.h
> @@ -9,6 +9,7 @@
>  #ifndef __ACPI_DEVICE_H
>  #define __ACPI_DEVICE_H
>  
> +#include <i2c.h>
>  #include <linux/bitops.h>
>  
>  struct acpi_ctx;
> @@ -183,6 +184,29 @@ struct acpi_gpio {
>  	enum acpi_gpio_polarity polarity;
>  };
>  
> +/* ACPI Descriptors for Serial Bus interfaces */
> +#define ACPI_SERIAL_BUS_TYPE_I2C		1
> +#define ACPI_SERIAL_BUS_TYPE_SPI		2
> +#define ACPI_I2C_SERIAL_BUS_REVISION_ID		1 /* TODO: upgrade to 2 */
> +#define ACPI_I2C_TYPE_SPECIFIC_REVISION_ID	1
> +#define ACPI_SPI_SERIAL_BUS_REVISION_ID		1
> +#define ACPI_SPI_TYPE_SPECIFIC_REVISION_ID	1
> +
> +/**
> + * struct acpi_i2c - representation of an ACPI I2C device
> + *
> + * @address: 7-bit or 10-bit I2C address
> + * @mode_10bit: Which address size is used
> + * @speed: Bus speed in Hz
> + * @resource: Resource name for the I2C controller
> + */
> +struct acpi_i2c {
> +	u16 address;
> +	enum i2c_address_mode mode_10bit;
> +	enum i2c_speed_rate speed;
> +	const char *resource;
> +};
> +
>  /**
>   * acpi_device_path() - Get the full path to an ACPI device
>   *
> @@ -270,4 +294,16 @@ int acpi_device_write_gpio_desc(struct acpi_ctx *ctx,
>  int acpi_device_write_interrupt_or_gpio(struct acpi_ctx *ctx,
>  					struct udevice *dev, const char *prop);
>  
> +/**
> + * acpi_device_write_i2c_dev() - Write an I2C device to ACPI
> + *
> + * This creates a I2cSerialBus descriptor for an I2C device, including
> + * information ACPI needs to use it.
> + *
> + * @ctx: ACPI context pointer
> + * @dev: I2C device to write
> + * @return 0 if OK, -ve on error
> + */
> +int acpi_device_write_i2c_dev(struct acpi_ctx *ctx, const struct udevice *dev);
> +
>  #endif
> diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
> index 423b91cfd2..0136a0bdc9 100644
> --- a/lib/acpi/acpi_device.c
> +++ b/lib/acpi/acpi_device.c
> @@ -381,3 +381,106 @@ int acpi_device_write_interrupt_or_gpio(struct acpi_ctx *ctx,
>  
>  	return 0;
>  }
> +
> +/* ACPI 6.3 section 6.4.3.8.2.1 - I2cSerialBus() */
> +static void acpi_device_write_i2c(struct acpi_ctx *ctx,
> +				  const struct acpi_i2c *i2c)
> +{
> +	void *desc_length, *type_length;
> +
> +	/* Byte 0: Descriptor Type */
> +	acpigen_emit_byte(ctx, ACPI_DESCRIPTOR_SERIAL_BUS);
> +
> +	/* Byte 1+2: Length (filled in later) */
> +	desc_length = acpi_device_write_zero_len(ctx);
> +
> +	/* Byte 3: Revision ID */
> +	acpigen_emit_byte(ctx, ACPI_I2C_SERIAL_BUS_REVISION_ID);
> +
> +	/* Byte 4: Resource Source Index is Reserved */
> +	acpigen_emit_byte(ctx, 0);
> +
> +	/* Byte 5: Serial Bus Type is I2C */
> +	acpigen_emit_byte(ctx, ACPI_SERIAL_BUS_TYPE_I2C);
> +
> +	/*
> +	 * Byte 6: Flags
> +	 *  [7:2]: 0 => Reserved
> +	 *    [1]: 1 => ResourceConsumer
> +	 *    [0]: 0 => ControllerInitiated
> +	 */
> +	acpigen_emit_byte(ctx, 1 << 1);
> +
> +	/*
> +	 * Byte 7-8: Type Specific Flags
> +	 *   [15:1]: 0 => Reserved
> +	 *      [0]: 0 => 7bit, 1 => 10bit
> +	 */
> +	acpigen_emit_word(ctx, i2c->mode_10bit);
> +
> +	/* Byte 9: Type Specific Revision ID */
> +	acpigen_emit_byte(ctx, ACPI_I2C_TYPE_SPECIFIC_REVISION_ID);
> +
> +	/* Byte 10-11: I2C Type Data Length */
> +	type_length = acpi_device_write_zero_len(ctx);
> +
> +	/* Byte 12-15: I2C Bus Speed */
> +	acpigen_emit_dword(ctx, i2c->speed);
> +
> +	/* Byte 16-17: I2C Slave Address */
> +	acpigen_emit_word(ctx, i2c->address);
> +
> +	/* Fill in Type Data Length */
> +	acpi_device_fill_len(ctx, type_length);
> +
> +	/* Byte 18+: ResourceSource */
> +	acpigen_emit_string(ctx, i2c->resource);
> +
> +	/* Fill in I2C Descriptor Length */
> +	acpi_device_fill_len(ctx, desc_length);
> +}
> +
> +/**
> + * acpi_device_set_i2c() - Set up an ACPI I2C struct from a device
> + *
> + * @dev: I2C device to convert
> + * @i2c: Place to put the new structure
> + * @scope: Scope of the I2C device (this is the controller path)

From the declaration I would assume that "scope" is internally copied, but in
the code it is only referenced.
I would propose to add something like the following to its description:
"The value of scope is not copied, but only referenced. This implies the
caller has to ensure it stays valid for the lifetime of i2c."

> + * @return 0 (always)

dev_get_parent_platdata() could return NULL. Should we check this and return
and error?

> + */
> +static int acpi_device_set_i2c(const struct udevice *dev, struct acpi_i2c *i2c,
> +			       const char *scope)
> +{
> +	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
> +	struct udevice *bus = dev_get_parent(dev);
> +
> +	memset(i2c, '\0', sizeof(*i2c));

Nit: memset(i2c, 0, sizeof(*i2c));

This is only a style question. But it seems 0 is used for memset in existing
U-Boot code much more often then '\0' (~120 grep results vs ~1100 grep results).

> +	i2c->address = chip->chip_addr;
> +	i2c->mode_10bit = 0;
> +
> +	/*
> +	 * i2c_bus->speed_hz is set if this device is probed, but if not we
> +	 * must use the device tree
> +	 */
> +	i2c->speed = dev_read_u32_default(bus, "clock-frequency", 100000);

Nit: I2C_SPEED_STANDARD_RATE instead of 100000?

> +	i2c->resource = scope;
> +
> +	return 0;
> +}
> +
> +int acpi_device_write_i2c_dev(struct acpi_ctx *ctx, const struct udevice *dev)
> +{
> +	char scope[ACPI_PATH_MAX];
> +	struct acpi_i2c i2c;
> +	int ret;
> +
> +	ret = acpi_device_scope(dev, scope, sizeof(scope));
> +	if (ret)
> +		return log_msg_ret("scope", ret);
> +	ret = acpi_device_set_i2c(dev, &i2c, scope);
> +	if (ret)
> +		return log_msg_ret("set", ret);
> +	acpi_device_write_i2c(ctx, &i2c);
> +
> +	return 0;
> +}
> diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
> index 6aefa6845d..de9996ab35 100644
> --- a/test/dm/acpigen.c
> +++ b/test/dm/acpigen.c
> @@ -266,3 +266,35 @@ static int dm_test_acpi_interrupt_or_gpio(struct unit_test_state *uts)
>  }
>  DM_TEST(dm_test_acpi_interrupt_or_gpio,
>  	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> +
> +/* Test emitting an I2C descriptor */
> +static int dm_test_acpi_i2c(struct unit_test_state *uts)
> +{
> +	struct acpi_ctx *ctx;
> +	struct udevice *dev;
> +	u8 *ptr;
> +
> +	ut_assertok(alloc_context(&ctx));
> +
> +	ptr = acpigen_get_current(ctx);
> +
> +	ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
> +	ut_assertok(acpi_device_write_i2c_dev(ctx, dev));
> +	ut_asserteq(28, acpigen_get_current(ctx) - ptr);
> +	ut_asserteq(ACPI_DESCRIPTOR_SERIAL_BUS, ptr[0]);
> +	ut_asserteq(25, get_unaligned((u16 *)(ptr + 1)));
> +	ut_asserteq(ACPI_I2C_SERIAL_BUS_REVISION_ID, ptr[3]);
> +	ut_asserteq(0, ptr[4]);
> +	ut_asserteq(ACPI_SERIAL_BUS_TYPE_I2C, ptr[5]);
> +	ut_asserteq(0, get_unaligned((u16 *)(ptr + 7)));
> +	ut_asserteq(ACPI_I2C_TYPE_SPECIFIC_REVISION_ID, ptr[9]);
> +	ut_asserteq(6, get_unaligned((u16 *)(ptr + 10)));
> +	ut_asserteq(100000, get_unaligned((u32 *)(ptr + 12)));
> +	ut_asserteq(0x43, get_unaligned((u16 *)(ptr + 16)));
> +	ut_asserteq_str("\\_SB.SI2C", (char *)ptr + 18);
> +
> +	free_context(&ctx);
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_acpi_i2c, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> -- 
> 2.26.2.645.ge9eca65c58-goog

The remarks above are just this: remarks. I would also be fine with merging
the code as it is:

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: [PATCH v2 13/35] acpigen: Support writing a length
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (43 preceding siblings ...)
  2020-05-19 11:58 ` Antwort: [PATCH v2 11/35] acpi: Support generation of I2C descriptor Wolfgang Wallner
@ 2020-05-19 13:14 ` Wolfgang Wallner
  2020-05-27 13:04 ` [PATCH v2 14/35] acpigen: Support writing a package Wolfgang Wallner
                   ` (23 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-05-19 13:14 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 13/35] acpigen: Support writing a length
> 
> It is convenient to write a length value for preceding a block of data.
> Of course the length is not known or is hard to calculate a priori. So add
> a way to mark the start on a stack, so the length can be updated when
> known.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  include/acpi/acpigen.h |  3 ++
>  include/dm/acpi.h      |  7 +++++
>  lib/acpi/acpigen.c     | 33 ++++++++++++++++++++++
>  test/dm/acpigen.c      | 64 ++++++++++++++++++++++++++++++++++++++++--
>  4 files changed, 105 insertions(+), 2 deletions(-)
> 
> diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
> index 7365cce738..31366f5e34 100644
> --- a/include/acpi/acpigen.h
> +++ b/include/acpi/acpigen.h
> @@ -65,4 +65,7 @@ void acpigen_emit_stream(struct acpi_ctx *ctx, const char *data, int size);
>   */
>  void acpigen_emit_string(struct acpi_ctx *ctx, const char *str);
>  
> +void acpigen_write_len_f(struct acpi_ctx *ctx);
> +void acpigen_pop_len(struct acpi_ctx *ctx);
> +
>  #endif
> diff --git a/include/dm/acpi.h b/include/dm/acpi.h
> index 7563a4c60a..2bd03eaa0a 100644
> --- a/include/dm/acpi.h
> +++ b/include/dm/acpi.h
> @@ -22,6 +22,9 @@
>  /* Length of an ACPI name string including nul terminator */
>  #define ACPI_NAME_MAX	(ACPI_NAME_LEN + 1)
>  
> +/* Number of nested objects supported */
> +#define ACPIGEN_LENSTACK_SIZE 10
> +
>  #if !defined(__ACPI__)
>  
>  /**
> @@ -34,12 +37,16 @@
>   *	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
> + * @len_stack: Stack of 'length' words to fix up later
> + * @ltop: Points to current top of stack (0 = empty)
>   */
>  struct acpi_ctx {
>  	void *current;
>  	struct acpi_rsdp *rsdp;
>  	struct acpi_rsdt *rsdt;
>  	struct acpi_xsdt *xsdt;
> +	char *len_stack[ACPIGEN_LENSTACK_SIZE];
> +	int ltop;
>  };
>  
>  /**
> diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
> index 1223f0d1c4..bd1fa24fb6 100644
> --- a/lib/acpi/acpigen.c
> +++ b/lib/acpi/acpigen.c
> @@ -10,6 +10,7 @@
>  
>  #include <common.h>
>  #include <dm.h>
> +#include <log.h>
>  #include <acpi/acpigen.h>
>  #include <dm/acpi.h>
>  
> @@ -37,6 +38,38 @@ void acpigen_emit_dword(struct acpi_ctx *ctx, uint data)
>  	acpigen_emit_byte(ctx, (data >> 24) & 0xff);
>  }
>  
> +/*
> + * Maximum length for an ACPI object generated by this code,
> + *
> + * If you need to change this, change acpigen_write_len_f(ctx) and
> + * acpigen_pop_len(ctx)
> + */
> +#define ACPIGEN_MAXLEN 0xfffff
> +
> +void acpigen_write_len_f(struct acpi_ctx *ctx)
> +{
> +	assert(ctx->ltop < (ACPIGEN_LENSTACK_SIZE - 1));
> +	ctx->len_stack[ctx->ltop++] = ctx->current;
> +	acpigen_emit_byte(ctx, 0);
> +	acpigen_emit_byte(ctx, 0);
> +	acpigen_emit_byte(ctx, 0);
> +}
> +
> +void acpigen_pop_len(struct acpi_ctx *ctx)
> +{
> +	int len;
> +	char *p;
> +
> +	assert(ctx->ltop > 0);
> +	p = ctx->len_stack[--ctx->ltop];
> +	len = ctx->current - (void *)p;
> +	assert(len <= ACPIGEN_MAXLEN);
> +	/* generate store length for 0xfffff max */
> +	p[0] = (0x80 | (len & 0xf));

Nit: Without context this code is hard to understand.
I would propose adding a comment pointing to "ACPI 6.3 20.2.4 Package Length
Encoding" and using a define for 0x80 (something like ACPI_PKG_LEN_3_BYTES ...).

> +	p[1] = (len >> 4 & 0xff);
> +	p[2] = (len >> 12 & 0xff);
> +}
> +
>  void acpigen_emit_stream(struct acpi_ctx *ctx, const char *data, int size)
>  {
>  	int i;
> diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
> index 3d580a23a5..f9c15b7503 100644
> --- a/test/dm/acpigen.c
> +++ b/test/dm/acpigen.c
> @@ -22,7 +22,7 @@
>  #define TEST_STRING	"frogmore"
>  #define TEST_STREAM2	"\xfa\xde"
>  
> -static int alloc_context(struct acpi_ctx **ctxp)
> +static int alloc_context_size(struct acpi_ctx **ctxp, int size)
>  {
>  	struct acpi_ctx *ctx;
>  
> @@ -30,7 +30,8 @@ static int alloc_context(struct acpi_ctx **ctxp)
>  	ctx = malloc(sizeof(*ctx));
>  	if (!ctx)
>  		return -ENOMEM;
> -	ctx->current = malloc(150);
> +	ctx->current = malloc(size);
> +	ctx->ltop = 0;
>  	if (!ctx->current)
>  		return -ENOMEM;
>  	*ctxp = ctx;
> @@ -38,6 +39,11 @@ static int alloc_context(struct acpi_ctx **ctxp)
>  	return 0;
>  }
>  
> +static int alloc_context(struct acpi_ctx **ctxp)
> +{
> +	return alloc_context_size(ctxp, 150);
> +}
> +
>  static void free_context(struct acpi_ctx **ctxp)
>  {
>  	free(*ctxp);
> @@ -334,3 +340,57 @@ static int dm_test_acpi_spi(struct unit_test_state *uts)
>  	return 0;
>  }
>  DM_TEST(dm_test_acpi_spi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> +
> +/**
> + * get_length() - decode a three-byte length field
> + *
> + * @ptr: Length encoded as per ACPI
> + * @return decoded length, or -EINVAL on error
> + */
> +static int get_length(u8 *ptr)
> +{
> +	if (!(*ptr & 0x80))
> +		return -EINVAL;
> +
> +	return (*ptr & 0xf) | ptr[1] << 4 | ptr[2] << 12;
> +}
> +
> +/* Test emitting a length */
> +static int dm_test_acpi_len(struct unit_test_state *uts)
> +{
> +	const int size = 0xc0000;
> +	struct acpi_ctx *ctx;
> +	u8 *ptr;
> +	int i;
> +
> +	ut_assertok(alloc_context_size(&ctx, size));
> +
> +	ptr = acpigen_get_current(ctx);
> +
> +	/* Write a byte and a 3-byte length */
> +	acpigen_write_len_f(ctx);
> +	acpigen_emit_byte(ctx, 0x23);
> +	acpigen_pop_len(ctx);
> +	ut_asserteq(1 + 3, get_length(ptr));
> +
> +	/* Write 200 bytes so we need two length bytes */
> +	ptr = ctx->current;
> +	acpigen_write_len_f(ctx);
> +	for (i = 0; i < 200; i++)
> +		acpigen_emit_byte(ctx, 0x23);
> +	acpigen_pop_len(ctx);
> +	ut_asserteq(200 + 3, get_length(ptr));
> +
> +	/* Write 40KB so we need three length bytes */
> +	ptr = ctx->current;
> +	acpigen_write_len_f(ctx);
> +	for (i = 0; i < 40000; i++)
> +		acpigen_emit_byte(ctx, 0x23);
> +	acpigen_pop_len(ctx);
> +	ut_asserteq(40000 + 3, get_length(ptr));
> +
> +	free_context(&ctx);
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_acpi_len, 0);
> -- 
> 2.26.2.645.ge9eca65c58-goog
> 

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 14/35] acpigen: Support writing a package
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (44 preceding siblings ...)
  2020-05-19 13:14 ` Antwort: [PATCH v2 13/35] acpigen: Support writing a length Wolfgang Wallner
@ 2020-05-27 13:04 ` Wolfgang Wallner
  2020-05-28  9:45 ` [PATCH v2 15/35] acpi: Support writing an integer Wolfgang Wallner
                   ` (22 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-05-27 13:04 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 14/35] acpigen: Support writing a package
> 
> A package collects together several elements. Add an easy way of writing
> a package header and updating its length later.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  include/acpi/acpigen.h | 62 ++++++++++++++++++++++++++++++++++++++++++
>  lib/acpi/acpigen.c     | 12 ++++++++
>  test/dm/acpigen.c      | 27 ++++++++++++++++++
>  3 files changed, 101 insertions(+)
> 
> diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
> index 31366f5e34..52e0b75128 100644
> --- a/include/acpi/acpigen.h
> +++ b/include/acpi/acpigen.h
> @@ -14,6 +14,11 @@
>  
>  struct acpi_ctx;
>  
> +/* ACPI Op/Prefix codes */
> +enum {
> +	PACKAGE_OP		= 0x12,
> +};
> +
>  /**
>   * acpigen_get_current() - Get the current ACPI code output pointer
>   *
> @@ -65,7 +70,64 @@ void acpigen_emit_stream(struct acpi_ctx *ctx, const char *data, int size);
>   */
>  void acpigen_emit_string(struct acpi_ctx *ctx, const char *str);
>  
> +/**
> + * acpigen_write_len_f() - Write a 'forward' length placeholder
> + *
> + * This adds space for a length value in the ACPI stream and pushes the current
> + * position (before the length) on the stack. After calling this you can write
> + * some data and then call acpigen_pop_len() to update the length value.
> + *
> + * Usage:
> + *
> + *    acpigen_write_len_f() ------\
> + *    acpigen_write...()          |
> + *    acpigen_write...()          |
> + *      acpigen_write_len_f() --\ |
> + *      acpigen_write...()      | |
> + *      acpigen_write...()      | |
> + *      acpigen_pop_len() ------/ |
> + *    acpigen_write...()          |
> + *    acpigen_pop_len() ----------/
> + *
> + * @ctx: ACPI context pointer
> + */

Nit: This description should be part of the previous patch.

>  void acpigen_write_len_f(struct acpi_ctx *ctx);
> +
> +/**
> + * acpigen_pop_len() - Update the previously stacked length placeholder
> + *
> + * Call this after the data for the block gas been written. It updates the
> + * top length value in the stack and pops it off.
> + *
> + * @ctx: ACPI context pointer
> + */

Nit: This description should be part of the previous patch.

>  void acpigen_pop_len(struct acpi_ctx *ctx);
>  
> +/**
> + * acpigen_write_package() - Start writing a package
> + *
> + * A package collects together a number of elements in the ACPI code. To write
> + * a package use:
> + *
> + * acpigen_write_package(ctx, 3);
> + * ...write things
> + * acpigen_pop_len()
> + *
> + * If you don't know the number of elements in advance, acpigen_write_package()
> + * returns a pointer to the value so you can update it later:
> + *
> + * char *num_elements = acpigen_write_package(ctx, 0);
> + * ...write things
> + * *num_elements += 1;
> + * ...write things
> + * *num_elements += 1;
> + * acpigen_pop_len()
> + *
> + * @ctx: ACPI context pointer
> + * @nr_el: Number of elements (0 if not known)
> + * @returns pointer to the number of elements, which can be updated by the
> + *	caller if needed
> + */
> +char *acpigen_write_package(struct acpi_ctx *ctx, int nr_el);
> +
>  #endif
> diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
> index bd1fa24fb6..e1fd1f6b6a 100644
> --- a/lib/acpi/acpigen.c
> +++ b/lib/acpi/acpigen.c
> @@ -70,6 +70,18 @@ void acpigen_pop_len(struct acpi_ctx *ctx)
>  	p[2] = (len >> 12 & 0xff);
>  }
>  
> +char *acpigen_write_package(struct acpi_ctx *ctx, int nr_el)
> +{
> +	char *p;
> +
> +	acpigen_emit_byte(ctx, PACKAGE_OP);
> +	acpigen_write_len_f(ctx);
> +	p = ctx->current;
> +	acpigen_emit_byte(ctx, nr_el);
> +
> +	return p;
> +}
> +
>  void acpigen_emit_stream(struct acpi_ctx *ctx, const char *data, int size)
>  {
>  	int i;
> diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
> index f9c15b7503..be81068759 100644
> --- a/test/dm/acpigen.c
> +++ b/test/dm/acpigen.c
> @@ -394,3 +394,30 @@ static int dm_test_acpi_len(struct unit_test_state *uts)
>  	return 0;
>  }
>  DM_TEST(dm_test_acpi_len, 0);
> +
> +/* Test emitting a package */
> +static int dm_test_acpi_package(struct unit_test_state *uts)
> +{
> +	struct acpi_ctx *ctx;
> +	char *num_elements;
> +	u8 *ptr;
> +
> +	ut_assertok(alloc_context(&ctx));
> +
> +	ptr = acpigen_get_current(ctx);
> +
> +	num_elements = acpigen_write_package(ctx, 3);
> +	ut_asserteq_ptr(num_elements, ptr + 4);
> +
> +	/* For easy of testing, just emit a byte, not valid package contents */

I'm not sure, but shouldn't this be "ease" of testing?

> +	acpigen_emit_byte(ctx, 0x23);
> +	acpigen_pop_len(ctx);
> +	ut_asserteq(PACKAGE_OP, ptr[0]);
> +	ut_asserteq(5, get_length(ptr + 1));
> +	ut_asserteq(3, ptr[4]);
> +
> +	free_context(&ctx);
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_acpi_package, 0);
> -- 
> 2.26.2.645.ge9eca65c58-goog

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 15/35] acpi: Support writing an integer
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (45 preceding siblings ...)
  2020-05-27 13:04 ` [PATCH v2 14/35] acpigen: Support writing a package Wolfgang Wallner
@ 2020-05-28  9:45 ` Wolfgang Wallner
  2020-05-28  9:45 ` Antwort: [PATCH v2 16/35] acpi: Support writing a string Wolfgang Wallner
                   ` (21 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-05-28  9:45 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
>Betreff: [PATCH v2 15/35] acpi: Support writing an integer
>
>ACPI supports storing integers in various ways. Add a function to
>handle
>this.
>
>Signed-off-by: Simon Glass <sjg@chromium.org>
>---
>
>Changes in v2: None
>Changes in v1: None
>
> include/acpi/acpigen.h | 17 ++++++++++++++
> lib/acpi/acpigen.c     | 51
>++++++++++++++++++++++++++++++++++++++++++
> test/dm/acpigen.c      | 46 +++++++++++++++++++++++++++++++++++++
> 3 files changed, 114 insertions(+)

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: [PATCH v2 16/35] acpi: Support writing a string
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (46 preceding siblings ...)
  2020-05-28  9:45 ` [PATCH v2 15/35] acpi: Support writing an integer Wolfgang Wallner
@ 2020-05-28  9:45 ` Wolfgang Wallner
  2020-05-28  9:46 ` [PATCH v2 17/35] acpi: Support writing a name Wolfgang Wallner
                   ` (20 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-05-28  9:45 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
>Betreff: [PATCH v2 16/35] acpi: Support writing a string
>
>ACPI supports storing a simple nul-terminated string. Add support for
>this.
>
>Signed-off-by: Simon Glass <sjg@chromium.org>
>---
>
>Changes in v2: None
>Changes in v1: None
>
> include/acpi/acpigen.h | 10 ++++++++++
> lib/acpi/acpigen.c     |  6 ++++++
> test/dm/acpigen.c      | 32 ++++++++++++++++++++++++++++++--
> 3 files changed, 46 insertions(+), 2 deletions(-)
>

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 17/35] acpi: Support writing a name
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (47 preceding siblings ...)
  2020-05-28  9:45 ` Antwort: [PATCH v2 16/35] acpi: Support writing a string Wolfgang Wallner
@ 2020-05-28  9:46 ` Wolfgang Wallner
  2020-05-28  9:57 ` [PATCH v2 18/35] acpi: Support writing a UUID Wolfgang Wallner
                   ` (19 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-05-28  9:46 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
>Betreff: [PATCH v2 17/35] acpi: Support writing a name
>
>ACPI supports storing names which are made up of multiple path
>components.
>Several special cases are supported. Add a function to emit a name.
>
>Signed-off-by: Simon Glass <sjg@chromium.org>
>---
>
>Changes in v2: None
>Changes in v1: None
>
> include/acpi/acpigen.h | 25 +++++++++++
> include/test/ut.h      | 17 ++++++++
> lib/acpi/acpigen.c     | 96
>++++++++++++++++++++++++++++++++++++++++++
> test/dm/acpigen.c      | 93 ++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 231 insertions(+)
>

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 18/35] acpi: Support writing a UUID
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (48 preceding siblings ...)
  2020-05-28  9:46 ` [PATCH v2 17/35] acpi: Support writing a name Wolfgang Wallner
@ 2020-05-28  9:57 ` Wolfgang Wallner
  2020-05-28 13:36 ` [PATCH v2 19/35] acpi: Support writing Device Properties objects via _DSD Wolfgang Wallner
                   ` (18 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-05-28  9:57 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 18/35] acpi: Support writing a UUID
> 
> ACPI supports writing a UUID in a special format. Add a function to handle
> this.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  include/acpi/acpigen.h | 13 +++++++++++++
>  lib/acpi/acpigen.c     | 39 +++++++++++++++++++++++++++++++++++++++
>  test/dm/acpigen.c      | 33 +++++++++++++++++++++++++++++++++
>  3 files changed, 85 insertions(+)
> 
> diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
> index 0fecb7d57a..f35467f029 100644
> --- a/include/acpi/acpigen.h
> +++ b/include/acpi/acpigen.h
> @@ -24,6 +24,7 @@ enum {
>  	DWORD_PREFIX		= 0x0c,
>  	STRING_PREFIX		= 0x0d,
>  	QWORD_PREFIX		= 0x0e,
> +	BUFFER_OP		= 0x11,
>  	PACKAGE_OP		= 0x12,
>  	DUAL_NAME_PREFIX	= 0x2e,
>  	MULTI_NAME_PREFIX	= 0x2f,
> @@ -182,4 +183,16 @@ void acpigen_emit_namestring(struct acpi_ctx *ctx, const char *namepath);
>   * @namepath: Name / path to emit
>   */
>  void acpigen_write_name(struct acpi_ctx *ctx, const char *namepath);
> +
> +/**
> + * acpigen_write_uuid() - Write a UUID
> + *
> + * This writes out a UUID in the format used by ACPI, with a BUFFER_OP prefix.
> + *
> + * @ctx: ACPI context pointer
> + * @uuid: UUID to write in the form aabbccdd-eeff-gghh-iijj-kkllmmnnoopp
> + * @return 0 if OK, -EINVAL if the format is incorrect
> + */
> +int acpigen_write_uuid(struct acpi_ctx *ctx, const char *uuid);
> +
>  #endif
> diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
> index eae2f605ed..f781ad4d87 100644
> --- a/lib/acpi/acpigen.c
> +++ b/lib/acpi/acpigen.c
> @@ -11,6 +11,7 @@
>  #include <common.h>
>  #include <dm.h>
>  #include <log.h>
> +#include <uuid.h>
>  #include <acpi/acpigen.h>
>  #include <dm/acpi.h>
>  
> @@ -248,3 +249,41 @@ void acpigen_write_name(struct acpi_ctx *ctx, const char *namepath)
>  	acpigen_emit_byte(ctx, NAME_OP);
>  	acpigen_emit_namestring(ctx, namepath);
>  }
> +
> +/*
> + * ToUUID(uuid)
> + *
> + * ACPI 6.3 Section 19.6.142 table 19-438 defines a special output order for the
> + * bytes that make up a UUID Buffer object:
> + *
> + * UUID byte order for input to this function:
> + *   aabbccdd-eeff-gghh-iijj-kkllmmnnoopp
> + *
> + * UUID byte order output by this function:
> + *   ddccbbaa-ffee-hhgg-iijj-kkllmmnnoopp
> + */
> +#define UUID_LEN 16

Nit: To me it looks strange that this is defined within the ACPI module.
Could this be moved to e.g. include/uuid.h?

It seems this define could be useful elsewhere, as I could not find an
existing define like this, but "grep -r -i -e uuid | grep -e 16" shows
several places where the fixed length of 16 bytes for UUIDs is hardcoded.

> +int acpigen_write_uuid(struct acpi_ctx *ctx, const char *uuid)
> +{
> +	u8 buf[UUID_LEN];
> +	int ret;
> +
> +	/* Parse UUID string into bytes */
> +	ret = uuid_str_to_bin(uuid, buf, UUID_STR_FORMAT_GUID);
> +	if (ret)
> +		return log_msg_ret("bad hex", -EINVAL);
> +
> +	/* BufferOp */
> +	acpigen_emit_byte(ctx, BUFFER_OP);
> +	acpigen_write_len_f(ctx);
> +
> +	/* Buffer length in bytes */
> +	acpigen_write_word(ctx, UUID_LEN);
> +
> +	/* Output UUID in expected order */
> +	acpigen_emit_stream(ctx, (char *)buf, UUID_LEN);
> +
> +	acpigen_pop_len(ctx);
> +
> +	return 0;
> +}
> diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
> index 0f56262a28..db8cad47d8 100644
> --- a/test/dm/acpigen.c
> +++ b/test/dm/acpigen.c
> @@ -588,3 +588,36 @@ static int dm_test_acpi_name(struct unit_test_state *uts)
>  	return 0;
>  }
>  DM_TEST(dm_test_acpi_name, 0);
> +
> +/* Test writing a UUID */
> +static int dm_test_acpi_uuid(struct unit_test_state *uts)
> +{
> +	struct acpi_ctx *ctx;
> +	u8 *ptr;
> +
> +	ut_assertok(alloc_context(&ctx));
> +
> +	ptr = acpigen_get_current(ctx);
> +
> +	ut_assertok(acpigen_write_uuid(ctx,
> +				       "dbb8e3e6-5886-4ba6-8795-1319f52a966b"));
> +	ut_asserteq(23, acpigen_get_current(ctx) - ptr);
> +	ut_asserteq(BUFFER_OP, ptr[0]);
> +	ut_asserteq(22, get_length(ptr + 1));
> +	ut_asserteq(0xdbb8e3e6, get_unaligned((u32 *)(ptr + 7)));
> +	ut_asserteq(0x5886, get_unaligned((u16 *)(ptr + 11)));
> +	ut_asserteq(0x4ba6, get_unaligned((u16 *)(ptr + 13)));
> +	ut_asserteq(0x9587, get_unaligned((u16 *)(ptr + 15)));
> +	ut_asserteq(0x2af51913, get_unaligned((u32 *)(ptr + 17)));
> +	ut_asserteq(0x6b96, get_unaligned((u16 *)(ptr + 21)));
> +
> +	/* Try a bad UUID */
> +	ut_asserteq(-EINVAL,
> +		    acpigen_write_uuid(ctx,
> +				       "dbb8e3e6-5886-4ba6x8795-1319f52a966b"));
> +
> +	free_context(&ctx);
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_acpi_uuid, 0);
> -- 
> 2.26.2.645.ge9eca65c58-goog

I would also be fine with keeping the UUID_LEN define where it is,
and the rest of the patch looks good to me:

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

regards, Wolfgang

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 19/35] acpi: Support writing Device Properties objects via _DSD
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (49 preceding siblings ...)
  2020-05-28  9:57 ` [PATCH v2 18/35] acpi: Support writing a UUID Wolfgang Wallner
@ 2020-05-28 13:36 ` Wolfgang Wallner
  2020-06-03 11:49 ` Antwort: [PATCH v2 20/35] acpi: Support writing a GPIO Wolfgang Wallner
                   ` (17 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-05-28 13:36 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 19/35] acpi: Support writing Device Properties objects via _DSD
> 
> More complex device properties can be provided to drivers via a
> device-specific data (_DSD) object.
> 
> To create this we need to build it up in a separate data structure and
> then generate the ACPI code, due to its recursive nature.
> 
> Add an implementation of this.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  include/acpi/acpi_dp.h | 215 ++++++++++++++++++++++
>  include/acpi/acpigen.h |   1 +
>  lib/acpi/Makefile      |   1 +
>  lib/acpi/acpi_dp.c     | 324 +++++++++++++++++++++++++++++++++
>  lib/acpi/acpigen.c     |   3 +
>  test/dm/Makefile       |   1 +
>  test/dm/acpi_dp.c      | 405 +++++++++++++++++++++++++++++++++++++++++
>  7 files changed, 950 insertions(+)
>  create mode 100644 include/acpi/acpi_dp.h
>  create mode 100644 lib/acpi/acpi_dp.c
>  create mode 100644 test/dm/acpi_dp.c
> 

[snip]

> diff --git a/lib/acpi/acpi_dp.c b/lib/acpi/acpi_dp.c
> new file mode 100644
> index 0000000000..479cb6743c
> --- /dev/null
> +++ b/lib/acpi/acpi_dp.c
> @@ -0,0 +1,324 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Generation of tables for particular device types
> + *
> + * Copyright 2019 Google LLC
> + * Mostly taken from coreboot file acpi_device.v

Typo: acpi_device.c

> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <log.h>
> +#include <malloc.h>
> +#include <uuid.h>
> +#include <acpi/acpigen.h>
> +#include <acpi/acpi_dp.h>
> +#include <dm/acpi.h>
> +
> +static void acpi_dp_write_array(struct acpi_ctx *ctx,
> +				const struct acpi_dp *array);
> +

[snip]

> diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
> index f781ad4d87..7321a98c0f 100644
> --- a/lib/acpi/acpigen.c
> +++ b/lib/acpi/acpigen.c
> @@ -15,6 +15,9 @@
>  #include <acpi/acpigen.h>
>  #include <dm/acpi.h>
>  
> +/* CPU path format */
> +#define ACPI_CPU_STRING "\\_PR.CP%02d"

Nit: This change seems unrelated to the rest of the patch,
is it here on purpose?

> +
>  u8 *acpigen_get_current(struct acpi_ctx *ctx)
>  {
>  	return ctx->current;

[snip]

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: [PATCH v2 20/35] acpi: Support writing a GPIO
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (50 preceding siblings ...)
  2020-05-28 13:36 ` [PATCH v2 19/35] acpi: Support writing Device Properties objects via _DSD Wolfgang Wallner
@ 2020-06-03 11:49 ` Wolfgang Wallner
  2020-06-03 12:00 ` [PATCH v2 21/35] acpi: Support copying properties from device tree to ACPI Wolfgang Wallner
                   ` (16 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-03 11:49 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 20/35] acpi: Support writing a GPIO
> 
> Allowing writing out a reference to a GPIO within the ACPI output. This
> can be used by ACPI code to access a GPIO at runtime.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  include/acpi/acpi_dp.h | 18 ++++++++++++++++++
>  lib/acpi/acpi_dp.c     | 21 +++++++++++++++++++++
>  test/dm/acpi_dp.c      | 39 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 78 insertions(+)
> 
> diff --git a/include/acpi/acpi_dp.h b/include/acpi/acpi_dp.h
> index 840be855c5..f42602405a 100644
> --- a/include/acpi/acpi_dp.h
> +++ b/include/acpi/acpi_dp.h
> @@ -202,6 +202,24 @@ struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
>  struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name,
>  				  struct acpi_dp *child);
>  
> +/**
> + * acpi_dp_add_gpio() - Add a GPIO to a list of Device Properties
> + *
> + * A new node is added to the end of the property list of @dp, with the
> + * GPIO properties added to the the new node
> + *
> + * @dp: Table to add this property to
> + * @name: Name of property
> + * @ref: Reference to device with a _CRS containing GpioIO or GpioInt
> + * @index: Index of the GPIO resource in _CRS starting from zero
> + * @pin: Pin in the GPIO resource, typically zero
> + * @active_low: true if pin is active low
> + * @return pointer to new node, or NULL if out of memory
> + */
> +struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
> +				 const char *ref, int index, int pin,
> +				 bool active_low);
> +
>  /**
>   * acpi_dp_write() - Write Device Property hierarchy and clean up resources
>   *
> diff --git a/lib/acpi/acpi_dp.c b/lib/acpi/acpi_dp.c
> index 479cb6743c..4ba5d555a0 100644
> --- a/lib/acpi/acpi_dp.c
> +++ b/lib/acpi/acpi_dp.c
> @@ -322,3 +322,24 @@ struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
>  
>  	return dp_array;
>  }
> +
> +struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
> +				 const char *ref, int index, int pin,
> +				 bool active_low)

Boolean parameters can be hard to read.
Could we instead of a boolean parameter use the type enum acpi_irq_polarity
which is defined in acpi_device.h?

> +{
> +	struct acpi_dp *gpio;
> +
> +	assert(dp);
> +	gpio = acpi_dp_new_table(name);
> +	if (!gpio)
> +		return NULL;
> +
> +	acpi_dp_add_reference(gpio, NULL, ref);
> +	acpi_dp_add_integer(gpio, NULL, index);
> +	acpi_dp_add_integer(gpio, NULL, pin);
> +	acpi_dp_add_integer(gpio, NULL, active_low);

Is it allowed to pass NULL for the parameter 'name' of these functions?

The descriptions of acpi_dp_add_reference() and acpi_dp_add_integer()
don't mention that name may be NULL, and both of these functions pass
it on internally to acpi_dp_new() which has an explicit check for
assert(name) ... ?

Also, acpi_dp_add_reference() and acpi_dp_add_integer() could return an error
(NULL), which is not checked for here.

> +
> +	acpi_dp_add_array(dp, gpio);
> +
> +	return gpio;
> +}
> diff --git a/test/dm/acpi_dp.c b/test/dm/acpi_dp.c
> index c11394786f..d6a054a98b 100644
> --- a/test/dm/acpi_dp.c
> +++ b/test/dm/acpi_dp.c
> @@ -403,3 +403,42 @@ static int dm_test_acpi_dp_child(struct unit_test_state *uts)
>  	return 0;
>  }
>  DM_TEST(dm_test_acpi_dp_child, 0);
> +
> +/* Test emitting a GPIO */
> +static int dm_test_acpi_dp_gpio(struct unit_test_state *uts)
> +{
> +	struct acpi_ctx *ctx;
> +	struct acpi_dp *dp;
> +	u8 *ptr, *pptr;
> +
> +	ut_assertok(alloc_context(&ctx));
> +
> +	dp = acpi_dp_new_table("FRED");
> +	ut_assertnonnull(dp);
> +
> +	/* Try a few different parameters */
> +	ut_assertnonnull(acpi_dp_add_gpio(dp, "reset", TEST_REF, 0x23, 0x24,
> +					  false));
> +	ut_assertnonnull(acpi_dp_add_gpio(dp, "allow", TEST_REF, 0, 0, true));
> +
> +	ptr = acpigen_get_current(ctx);
> +	ut_assertok(acpi_dp_write(ctx, dp));
> +	ut_asserteq(0x6e, acpigen_get_current(ctx) - ptr);
> +
> +	pptr = ptr + 0x2c; //0x3a;
> +	ut_asserteq_str("reset", (char *)pptr);
> +	ut_asserteq_strn(EXPECT_REF, (char *)pptr + 0xe);
> +	ut_asserteq(0x23, pptr[0x1b]);
> +	ut_asserteq(0x24, pptr[0x1d]);
> +	ut_asserteq(ZERO_OP, pptr[0x1e]);
> +
> +	pptr = ptr + 0x51;
> +	ut_asserteq_str("allow", (char *)pptr);
> +	ut_asserteq_strn(EXPECT_REF, (char *)pptr + 0xe);
> +	ut_asserteq(ZERO_OP, pptr[0x1a]);
> +	ut_asserteq(ZERO_OP, pptr[0x1b]);
> +	ut_asserteq(ONE_OP, pptr[0x1c]);
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_acpi_dp_gpio, 0);
> -- 
> 2.26.2.645.ge9eca65c58-goog
> 

regards, Wolfgang

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 21/35] acpi: Support copying properties from device tree to ACPI
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (51 preceding siblings ...)
  2020-06-03 11:49 ` Antwort: [PATCH v2 20/35] acpi: Support writing a GPIO Wolfgang Wallner
@ 2020-06-03 12:00 ` Wolfgang Wallner
  2020-06-03 13:04 ` [PATCH v2 22/35] acpi: Add support for various misc ACPI opcodes Wolfgang Wallner
                   ` (15 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-03 12:00 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 21/35] acpi: Support copying properties from device tree to ACPI
> 
> Some drivers in Linux support both device tree and ACPI. U-Boot itself
> uses Linux device-tree bindings for its own configuration but does not use
> ACPI.
> 
> It is convenient to copy these values over to the device tree for passing
> to linux. Add some convenience functions to help with this.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  arch/sandbox/dts/test.dts |  1 +
>  include/acpi/acpi_dp.h    | 50 +++++++++++++++++++++++++++++
>  lib/acpi/acpi_dp.c        | 52 ++++++++++++++++++++++++++++++
>  test/dm/acpi_dp.c         | 67 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 170 insertions(+)
> 
> diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
> index b802c1c909..a90395fa62 100644
> --- a/arch/sandbox/dts/test.dts
> +++ b/arch/sandbox/dts/test.dts
> @@ -109,6 +109,7 @@
>  		uint-value = <(-1234)>;
>  		int64-value = /bits/ 64 <0x1111222233334444>;
>  		int-array = <5678 9123 4567>;
> +		str-value = "test string";
>  		interrupts-extended = <&irq 3 0>;
>  	};
>  
> diff --git a/include/acpi/acpi_dp.h b/include/acpi/acpi_dp.h
> index f42602405a..9e5a70b286 100644
> --- a/include/acpi/acpi_dp.h
> +++ b/include/acpi/acpi_dp.h
> @@ -230,4 +230,54 @@ struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
>   */
>  int acpi_dp_write(struct acpi_ctx *ctx, struct acpi_dp *table);
>  
> +/**
> + * acpi_dp_ofnode_copy_int() - Copy a property from device tree to DP
> + *
> + * This copies an integer property from the device tree to the ACPI DP table.
> + *
> + * @dev: Device to copy from

There is some copy/paste error here, the description here doesn't match the code.
It should describe "node", not "dev".

> + * @dp: DP to copy to
> + * @prop: Property name to copy
> + * @return 0 if OK, -ve on error
> + */
> +int acpi_dp_ofnode_copy_int(ofnode node, struct acpi_dp *dp, const char *prop);
> +
> +/**
> + * acpi_dp_dev_copy_str() - Copy a property from device tree to DP

This should be acpi_dp_ofnode_copy_str()

> + *
> + * This copies a string property from the device tree to the ACPI DP table.
> + *
> + * @dev: Device to copy from

This should be "node".

> + * @dp: DP to copy to
> + * @prop: Property name to copy
> + * @return 0 if OK, -ve on error
> + */
> +int acpi_dp_ofnode_copy_str(ofnode node, struct acpi_dp *dp, const char *prop);
> +
> +/**
> + * acpi_dp_dev_copy_int() - Copy a property from device tree to DP
> + *
> + * This copies an integer property from the device tree to the ACPI DP table.
> + *
> + * @dev: Device to copy from
> + * @dp: DP to copy to
> + * @prop: Property name to copy
> + * @return 0 if OK, -ve on error
> + */
> +int acpi_dp_dev_copy_int(const struct udevice *dev, struct acpi_dp *dp,
> +			 const char *prop);
> +
> +/**
> + * acpi_dp_dev_copy_str() - Copy a property from device tree to DP
> + *
> + * This copies a string property from the device tree to the ACPI DP table.
> + *
> + * @dev: Device to copy from
> + * @dp: DP to copy to
> + * @prop: Property name to copy
> + * @return 0 if OK, -ve on error
> + */
> +int acpi_dp_dev_copy_str(const struct udevice *dev, struct acpi_dp *dp,
> +			 const char *prop);
> +
>  #endif
> diff --git a/lib/acpi/acpi_dp.c b/lib/acpi/acpi_dp.c
> index 4ba5d555a0..819e51005a 100644
> --- a/lib/acpi/acpi_dp.c
> +++ b/lib/acpi/acpi_dp.c
> @@ -343,3 +343,55 @@ struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
>  
>  	return gpio;
>  }
> +
> +int acpi_dp_ofnode_copy_int(ofnode node, struct acpi_dp *dp, const char *prop)
> +{
> +	int ret;
> +	u32 val = 0;
> +
> +	ret = ofnode_read_u32(node, prop, &val);
> +	if (ret)
> +		return ret;
> +	acpi_dp_add_integer(dp, prop, val);

The return value of the above function could be NULL, but this is not checked.

> +
> +	return ret;
> +}
> +
> +int acpi_dp_ofnode_copy_str(ofnode node, struct acpi_dp *dp, const char *prop)
> +{
> +	const char *val;
> +
> +	val = ofnode_read_string(node, prop);
> +	if (!val)
> +		return -EINVAL;
> +	acpi_dp_add_string(dp, prop, val);

Same here.

> +
> +	return 0;
> +}
> +
> +int acpi_dp_dev_copy_int(const struct udevice *dev, struct acpi_dp *dp,
> +			 const char *prop)
> +{
> +	int ret;
> +	u32 val = 0;
> +
> +	ret = dev_read_u32(dev, prop, &val);
> +	if (ret)
> +		return ret;
> +	acpi_dp_add_integer(dp, prop, val);

Same here.

> +
> +	return ret;
> +}
> +
> +int acpi_dp_dev_copy_str(const struct udevice *dev, struct acpi_dp *dp,
> +			 const char *prop)
> +{
> +	const char *val;
> +
> +	val = dev_read_string(dev, prop);
> +	if (!val)
> +		return -EINVAL;
> +	acpi_dp_add_string(dp, prop, val);

Same here.

> +
> +	return 0;
> +}
> diff --git a/test/dm/acpi_dp.c b/test/dm/acpi_dp.c
> index d6a054a98b..c1ab580cd2 100644
> --- a/test/dm/acpi_dp.c
> +++ b/test/dm/acpi_dp.c
> @@ -442,3 +442,70 @@ static int dm_test_acpi_dp_gpio(struct unit_test_state *uts)
>  	return 0;
>  }
>  DM_TEST(dm_test_acpi_dp_gpio, 0);
> +
> +/* Test copying info from the device tree to ACPI tables */
> +static int dm_test_acpi_dp_copy(struct unit_test_state *uts)
> +{
> +	struct acpi_ctx *ctx;
> +	struct udevice *dev;
> +	struct acpi_dp *dp;
> +	ofnode node;
> +	u8 *ptr;
> +
> +	ut_assertok(alloc_context(&ctx));
> +
> +	dp = acpi_dp_new_table("FRED");
> +	ut_assertnonnull(dp);
> +
> +	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
> +	ut_asserteq_str("a-test", dev->name);
> +
> +	ut_assertok(acpi_dp_dev_copy_int(dev, dp, "int-value"));
> +	ut_asserteq(-EINVAL, acpi_dp_dev_copy_int(dev, dp, "missing-value"));
> +	ut_assertok(acpi_dp_dev_copy_int(dev, dp, "uint-value"));
> +
> +	ut_assertok(acpi_dp_dev_copy_str(dev, dp, "str-value"));
> +	ut_asserteq(-EINVAL, acpi_dp_dev_copy_str(dev, dp, "missing-value"));
> +
> +	node = ofnode_path("/chosen");
> +	ut_assert(ofnode_valid(node));
> +	ut_assertok(acpi_dp_ofnode_copy_int(node, dp, "int-values"));
> +	ut_asserteq(-EINVAL,
> +		    acpi_dp_ofnode_copy_int(node, dp, "missing-value"));
> +
> +	ut_assertok(acpi_dp_ofnode_copy_str(node, dp, "setting"));
> +	ut_asserteq(-EINVAL,
> +		    acpi_dp_ofnode_copy_str(node, dp, "missing-value"));
> +
> +	ptr = acpigen_get_current(ctx);
> +	ut_assertok(acpi_dp_write(ctx, dp));
> +	ut_asserteq(0x9d, acpigen_get_current(ctx) - ptr);
> +
> +	ut_asserteq(STRING_PREFIX, ptr[0x2b]);
> +	ut_asserteq_str("int-value", (char *)ptr + 0x2c);
> +	ut_asserteq(WORD_PREFIX, ptr[0x36]);
> +	ut_asserteq(1234, get_unaligned((u16 *)(ptr + 0x37)));
> +
> +	ut_asserteq(STRING_PREFIX, ptr[0x3e]);
> +	ut_asserteq_str("uint-value", (char *)ptr + 0x3f);
> +	ut_asserteq(DWORD_PREFIX, ptr[0x4a]);
> +	ut_asserteq(-1234, get_unaligned((u32 *)(ptr + 0x4b)));
> +
> +	ut_asserteq(STRING_PREFIX, ptr[0x54]);
> +	ut_asserteq_str("str-value", (char *)ptr + 0x55);
> +	ut_asserteq(STRING_PREFIX, ptr[0x5f]);
> +	ut_asserteq_str("test string", (char *)ptr + 0x60);
> +
> +	ut_asserteq(STRING_PREFIX, ptr[0x71]);
> +	ut_asserteq_str("int-values", (char *)ptr + 0x72);
> +	ut_asserteq(WORD_PREFIX, ptr[0x7d]);
> +	ut_asserteq(0x1937, get_unaligned((u16 *)(ptr + 0x7e)));
> +
> +	ut_asserteq(STRING_PREFIX, ptr[0x85]);
> +	ut_asserteq_str("setting", (char *)ptr + 0x86);
> +	ut_asserteq(STRING_PREFIX, ptr[0x8e]);
> +	ut_asserteq_str("sunrise ohoka", (char *)(ptr + 0x8f));
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_acpi_dp_copy, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> -- 
> 2.26.2.645.ge9eca65c58-goog
> 

regards, Wolfgang

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 22/35] acpi: Add support for various misc ACPI opcodes
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (52 preceding siblings ...)
  2020-06-03 12:00 ` [PATCH v2 21/35] acpi: Support copying properties from device tree to ACPI Wolfgang Wallner
@ 2020-06-03 13:04 ` Wolfgang Wallner
  2020-06-04  7:39 ` Antwort: [PATCH v2 23/35] acpi: Add support for writing a Power Resource Wolfgang Wallner
                   ` (14 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-03 13:04 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 22/35] acpi: Add support for various misc ACPI opcodes
> 
> Add more functions to handle some miscellaneous ACPI opcodes.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  include/acpi/acpigen.h | 114 +++++++++++++++++++++++++++++++++++++++++
>  lib/acpi/acpigen.c     |  83 ++++++++++++++++++++++++++++++
>  test/dm/acpigen.c      |  75 +++++++++++++++++++++++++++
>  3 files changed, 272 insertions(+)
> 
> diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
> index 16b33ebe66..c595bb9efa 100644
> --- a/include/acpi/acpigen.h
> +++ b/include/acpi/acpigen.h
> @@ -26,9 +26,26 @@ enum {
>  	QWORD_PREFIX		= 0x0e,
>  	BUFFER_OP		= 0x11,
>  	PACKAGE_OP		= 0x12,
> +	METHOD_OP		= 0x14,
> +	SLEEP_OP		= 0x22,
>  	DUAL_NAME_PREFIX	= 0x2e,
>  	MULTI_NAME_PREFIX	= 0x2f,
> +	DEBUG_OP		= 0x31,
> +	EXT_OP_PREFIX		= 0x5b,
>  	ROOT_PREFIX		= 0x5c,
> +	LOCAL0_OP		= 0x60,
> +	LOCAL1_OP		= 0x61,
> +	LOCAL2_OP		= 0x62,
> +	LOCAL3_OP		= 0x63,
> +	LOCAL4_OP		= 0x64,
> +	LOCAL5_OP		= 0x65,
> +	LOCAL6_OP		= 0x66,
> +	LOCAL7_OP		= 0x67,
> +	STORE_OP		= 0x70,
> +	AND_OP			= 0x7b,
> +	OR_OP			= 0x7d,
> +	NOT_OP			= 0x80,
> +	RETURN_OP		= 0xa4,
>  };
>  
>  /**
> @@ -196,4 +213,101 @@ void acpigen_write_name(struct acpi_ctx *ctx, const char *namepath);
>   */
>  int acpigen_write_uuid(struct acpi_ctx *ctx, const char *uuid);
>  
> +/**
> + * acpigen_emit_ext_op() - Emit an extended op with the EXT_OP_PREFIX prefix
> + *
> + * @ctx: ACPI context pointer
> + * @op: Operation code (e.g. SLEEP_OP)
> + */
> +void acpigen_emit_ext_op(struct acpi_ctx *ctx, uint op);
> +
> +/**
> + * acpigen_write_method() - Write a method header
> + *
> + * @ctx: ACPI context pointer
> + * @name: Method name (4 characters)
> + * @nargs: Number of method arguments (0 if none)
> + */
> +void acpigen_write_method(struct acpi_ctx *ctx, const char *name, int nargs);
> +
> +/**
> + * acpigen_write_method_serialized() - Write a method header
> + *
> + * This sets the 'serialized' flag so that the method is thread-safe
> + *
> + * @ctx: ACPI context pointer
> + * @name: Method name (4 characters)
> + * @nargs: Number of method arguments (0 if none)
> + */
> +void acpigen_write_method_serialized(struct acpi_ctx *ctx, const char *name,
> +				     int nargs);
> +
> +/**
> + * acpigen_write_sta() - Write a _STA method
> + *
> + * @ctx: ACPI context pointer
> + * @status: Status value to return
> + */
> +void acpigen_write_sta(struct acpi_ctx *ctx, uint status);
> +
> +/**
> + * acpigen_write_sleep() - Write a sleep operation
> + *
> + * @ctx: ACPI context pointer
> + * @sleep_ms: Number of milliseconds to sleep for
> + */
> +void acpigen_write_sleep(struct acpi_ctx *ctx, u64 sleep_ms);
> +
> +/**
> + * acpigen_write_store() - Write a store operation
> + *
> + * @ctx: ACPI context pointer
> + */
> +void acpigen_write_store(struct acpi_ctx *ctx);
> +
> +/**
> + * acpigen_write_debug_string() - Write a debug string
> + *
> + * This writes a debug operation with an associated string
> + *
> + * @ctx: ACPI context pointer
> + * @str: String to write
> + */
> +void acpigen_write_debug_string(struct acpi_ctx *ctx, const char *str);
> +
> +/**
> + * acpigen_write_or() - Write a bitwise OR operation
> + *
> + * res = arg1 | arg2
> + *
> + * @ctx: ACPI context pointer
> + * @arg1: ACPI opcode for operand 1 (e.g. LOCAL0_OP)
> + * @arg2: ACPI opcode for operand 2 (e.g. LOCAL1_OP)
> + * @res: ACPI opcode for result (e.g. LOCAL2_OP)
> + */
> +void acpigen_write_or(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res);
> +
> +/**
> + * acpigen_write_and() - Write a bitwise AND operation
> + *
> + * res = arg1 & arg2
> + *
> + * @ctx: ACPI context pointer
> + * @arg1: ACPI opcode for operand 1 (e.g. LOCAL0_OP)
> + * @arg2: ACPI opcode for operand 2 (e.g. LOCAL1_OP)
> + * @res: ACPI opcode for result (e.g. LOCAL2_OP)
> + */
> +void acpigen_write_and(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res);
> +
> +/**
> + * acpigen_write_or() - Write a bitwise NOT operation

Typo: this should be acpigen_write_not()

> + *
> + * res = ~arg1
> + *
> + * @ctx: ACPI context pointer
> + * @arg: ACPI opcode for operand (e.g. LOCAL0_OP)
> + * @res: ACPI opcode for result (e.g. LOCAL2_OP)
> + */
> +void acpigen_write_not(struct acpi_ctx *ctx, u8 arg, u8 res);
> +
>  #endif
> diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
> index 7321a98c0f..57b295aa4e 100644
> --- a/lib/acpi/acpigen.c
> +++ b/lib/acpi/acpigen.c
> @@ -74,6 +74,12 @@ void acpigen_pop_len(struct acpi_ctx *ctx)
>  	p[2] = (len >> 12 & 0xff);
>  }
>  
> +void acpigen_emit_ext_op(struct acpi_ctx *ctx, uint op)
> +{
> +	acpigen_emit_byte(ctx, EXT_OP_PREFIX);
> +	acpigen_emit_byte(ctx, op);
> +}
> +
>  char *acpigen_write_package(struct acpi_ctx *ctx, int nr_el)
>  {
>  	char *p;
> @@ -253,6 +259,37 @@ void acpigen_write_name(struct acpi_ctx *ctx, const char *namepath)
>  	acpigen_emit_namestring(ctx, namepath);
>  }
>  
> +static void acpigen_write_method_(struct acpi_ctx *ctx, const char *name,
> +				  uint flags)
> +{
> +	acpigen_emit_byte(ctx, METHOD_OP);
> +	acpigen_write_len_f(ctx);
> +	acpigen_emit_namestring(ctx, name);
> +	acpigen_emit_byte(ctx, flags);
> +}
> +
> +/* Method (name, nargs, NotSerialized) */
> +void acpigen_write_method(struct acpi_ctx *ctx, const char *name, int nargs)
> +{
> +	acpigen_write_method_(ctx, name, nargs & 7);
> +}
> +
> +/* Method (name, nargs, Serialized) */
> +void acpigen_write_method_serialized(struct acpi_ctx *ctx, const char *name,
> +				     int nargs)
> +{
> +	acpigen_write_method_(ctx, name, (nargs & 7) | (1 << 3));

Nit: Defines for the mask and the flag would make this and the above function
more readable.

> +}
> +
> +void acpigen_write_sta(struct acpi_ctx *ctx, uint status)
> +{
> +	/* Method (_STA, 0, NotSerialized) { Return (status) } */
> +	acpigen_write_method(ctx, "_STA", 0);
> +	acpigen_emit_byte(ctx, RETURN_OP);
> +	acpigen_write_byte(ctx, status);
> +	acpigen_pop_len(ctx);
> +}
> +
>  /*
>   * ToUUID(uuid)
>   *
> @@ -290,3 +327,49 @@ int acpigen_write_uuid(struct acpi_ctx *ctx, const char *uuid)
>  
>  	return 0;
>  }
> +
> +/* Sleep (ms) */
> +void acpigen_write_sleep(struct acpi_ctx *ctx, u64 sleep_ms)
> +{
> +	acpigen_emit_ext_op(ctx, SLEEP_OP);
> +	acpigen_write_integer(ctx, sleep_ms);
> +}
> +
> +void acpigen_write_store(struct acpi_ctx *ctx)
> +{
> +	acpigen_emit_byte(ctx, STORE_OP);
> +}
> +
> +/* Or (arg1, arg2, res) */
> +void acpigen_write_or(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res)
> +{
> +	acpigen_emit_byte(ctx, OR_OP);
> +	acpigen_emit_byte(ctx, arg1);
> +	acpigen_emit_byte(ctx, arg2);
> +	acpigen_emit_byte(ctx, res);
> +}
> +
> +/* And (arg1, arg2, res) */
> +void acpigen_write_and(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res)
> +{
> +	acpigen_emit_byte(ctx, AND_OP);
> +	acpigen_emit_byte(ctx, arg1);
> +	acpigen_emit_byte(ctx, arg2);
> +	acpigen_emit_byte(ctx, res);
> +}
> +
> +/* Not (arg, res) */
> +void acpigen_write_not(struct acpi_ctx *ctx, u8 arg, u8 res)
> +{
> +	acpigen_emit_byte(ctx, NOT_OP);
> +	acpigen_emit_byte(ctx, arg);
> +	acpigen_emit_byte(ctx, res);
> +}
> +
> +/* Store (str, DEBUG) */
> +void acpigen_write_debug_string(struct acpi_ctx *ctx, const char *str)
> +{
> +	acpigen_write_store(ctx);
> +	acpigen_write_string(ctx, str);
> +	acpigen_emit_ext_op(ctx, DEBUG_OP);
> +}
> diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
> index db8cad47d8..e059d6f80d 100644
> --- a/test/dm/acpigen.c
> +++ b/test/dm/acpigen.c
> @@ -621,3 +621,78 @@ static int dm_test_acpi_uuid(struct unit_test_state *uts)
>  	return 0;
>  }
>  DM_TEST(dm_test_acpi_uuid, 0);
> +
> +/* Test writing misc ACPI codes */
> +static int dm_test_acpi_misc(struct unit_test_state *uts)
> +{
> +	struct acpi_ctx *ctx;
> +	const int flags = 3;
> +	const int nargs = 4;
> +	u8 *ptr;
> +
> +	ut_assertok(alloc_context(&ctx));
> +
> +	ptr = acpigen_get_current(ctx);
> +	acpigen_write_sleep(ctx, TEST_INT64);
> +	ut_asserteq_64(TEST_INT64, get_unaligned((u64 *)(ptr + 3)));
> +	ptr += 11;
> +
> +	acpigen_write_store(ctx);
> +	ut_asserteq(STORE_OP, *ptr);
> +	ptr++;
> +
> +	acpigen_write_debug_string(ctx, TEST_STRING);
> +	ut_asserteq_str(TEST_STRING, (char *)ptr + 2);
> +	ptr += 2 +  sizeof(TEST_STRING);
> +	ut_asserteq(EXT_OP_PREFIX, ptr[0]);
> +	ut_asserteq(DEBUG_OP, ptr[1]);
> +	ptr += 2;
> +
> +	acpigen_write_sta(ctx, flags);
> +	ut_asserteq(METHOD_OP, ptr[0]);
> +	ut_asserteq(11, get_length(ptr + 1));
> +	ut_asserteq_strn("_STA", (char *)ptr + 4);
> +	ut_asserteq(0, ptr[8]);
> +	ut_asserteq(RETURN_OP, ptr[9]);
> +	ut_asserteq(BYTE_PREFIX, ptr[10]);
> +	ut_asserteq(flags, ptr[11]);
> +	ptr += 12;
> +
> +	acpigen_write_sleep(ctx, TEST_INT16);
> +	ut_asserteq(SLEEP_OP, ptr[1]);
> +	ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 3)));
> +	ptr += 5;
> +
> +	acpigen_write_method_serialized(ctx, "FRED", nargs);
> +	ut_asserteq(METHOD_OP, ptr[0]);
> +	ut_asserteq_strn("FRED", (char *)ptr + 4);
> +	ut_asserteq(1 << 3 | nargs, ptr[8]);
> +	ut_asserteq(1, ctx->ltop);	/* method is unfinished */
> +
> +	ptr += 9;
> +	acpigen_write_or(ctx, LOCAL0_OP, LOCAL1_OP, LOCAL2_OP);
> +	acpigen_write_and(ctx, LOCAL3_OP, LOCAL4_OP, LOCAL5_OP);
> +	acpigen_write_not(ctx, LOCAL6_OP, LOCAL7_OP);
> +	ut_asserteq(OR_OP, ptr[0]);
> +	ut_asserteq(LOCAL0_OP, ptr[1]);
> +	ut_asserteq(LOCAL1_OP, ptr[2]);
> +	ut_asserteq(LOCAL2_OP, ptr[3]);
> +
> +	ptr += 4;
> +	ut_asserteq(AND_OP, ptr[0]);
> +	ut_asserteq(LOCAL3_OP, ptr[1]);
> +	ut_asserteq(LOCAL4_OP, ptr[2]);
> +	ut_asserteq(LOCAL5_OP, ptr[3]);
> +
> +	ptr += 4;
> +	ut_asserteq(NOT_OP, ptr[0]);
> +	ut_asserteq(LOCAL6_OP, ptr[1]);
> +	ut_asserteq(LOCAL7_OP, ptr[2]);
> +	ptr += 3;
> +	ut_asserteq_ptr(ptr, ctx->current);
> +
> +	free_context(&ctx);
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_acpi_misc, 0);
> -- 
> 2.26.2.645.ge9eca65c58-goog
> 

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Antwort: [PATCH v2 23/35] acpi: Add support for writing a Power Resource
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (53 preceding siblings ...)
  2020-06-03 13:04 ` [PATCH v2 22/35] acpi: Add support for various misc ACPI opcodes Wolfgang Wallner
@ 2020-06-04  7:39 ` Wolfgang Wallner
  2020-06-04  8:50 ` [PATCH v2 24/35] acpi: Add support for writing a GPIO power sequence Wolfgang Wallner
                   ` (13 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-04  7:39 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 23/35] acpi: Add support for writing a Power Resource
> 
> These are used in ACPI to disable power to various pats of the system when

Typo: "pats" instead of "parts"

> in sleep. Add a way to create a power resource, with the caller finishing
> off the details.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  include/acpi/acpigen.h | 22 ++++++++++++++++++++++
>  lib/acpi/acpigen.c     | 22 ++++++++++++++++++++++
>  test/dm/acpigen.c      | 41 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 85 insertions(+)
> 

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 24/35] acpi: Add support for writing a GPIO power sequence
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (54 preceding siblings ...)
  2020-06-04  7:39 ` Antwort: [PATCH v2 23/35] acpi: Add support for writing a Power Resource Wolfgang Wallner
@ 2020-06-04  8:50 ` Wolfgang Wallner
  2020-06-04  9:12 ` [PATCH v2 25/35] acpi: Add support for a generic " Wolfgang Wallner
                   ` (12 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-04  8:50 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 24/35] acpi: Add support for writing a GPIO power sequence
> 
> Power to some devices is controlled by GPIOs. Add a way to generate ACPI
> code to enable and disable a GPIO so that this can be handled within an
> ACPI method.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  include/acpi/acpigen.h | 12 +++++++
>  lib/acpi/acpigen.c     | 80 ++++++++++++++++++++++++++++++++++++++++++
>  test/dm/acpigen.c      | 54 ++++++++++++++++++++++++++++
>  3 files changed, 146 insertions(+)

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 25/35] acpi: Add support for a generic power sequence
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (55 preceding siblings ...)
  2020-06-04  8:50 ` [PATCH v2 24/35] acpi: Add support for writing a GPIO power sequence Wolfgang Wallner
@ 2020-06-04  9:12 ` Wolfgang Wallner
  2020-06-04  9:20 ` [PATCH v2 27/35] x86: acpi: Move MADT down a bit Wolfgang Wallner
                   ` (11 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-04  9:12 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 25/35] acpi: Add support for a generic power sequence
> 
> Add a way for devices to enable and disable themselves using ACPI code
> that updates GPIOs. This takes several timing parameters and supports
> enable, reset and stop.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  include/acpi/acpi_device.h | 41 ++++++++++++++++
>  lib/acpi/acpi_device.c     | 99 ++++++++++++++++++++++++++++++++++++++
>  test/dm/acpigen.c          | 68 ++++++++++++++++++++++++++
>  3 files changed, 208 insertions(+)

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 27/35] x86: acpi: Move MADT down a bit
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (56 preceding siblings ...)
  2020-06-04  9:12 ` [PATCH v2 25/35] acpi: Add support for a generic " Wolfgang Wallner
@ 2020-06-04  9:20 ` Wolfgang Wallner
  2020-06-04 11:52 ` [PATCH v2 29/35] acpi: Support ordering SSDT data by device Wolfgang Wallner
                   ` (10 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-04  9:20 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 27/35] x86: acpi: Move MADT down a bit
> 
> Put this table before MCFG so that it matches the order that coreboot uses
> when passing tables to Linux. This is a cosmetic change since the order of
> the tables does not otherwise matter.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1:
> - Correct the commit subject
> 
>  arch/x86/lib/acpi_table.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
> index 6985ef4ba5..e96acf08d4 100644
> --- a/arch/x86/lib/acpi_table.c
> +++ b/arch/x86/lib/acpi_table.c
> @@ -418,18 +418,18 @@ ulong write_acpi_tables(ulong start_addr)
>  	acpi_create_fadt(fadt, facs, dsdt);
>  	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(ctx, madt);
> -
>  	debug("ACPI:    * MCFG\n");
>  	mcfg = ctx->current;
>  	acpi_create_mcfg(mcfg);
>  	acpi_inc_align(ctx, mcfg->header.length);
>  	acpi_add_table(ctx, mcfg);
>  
> +	debug("ACPI:    * MADT\n");
> +	madt = ctx->current;
> +	acpi_create_madt(madt);
> +	acpi_inc_align(ctx, madt->header.length);
> +	acpi_add_table(ctx, madt);
> +
>  	debug("ACPI:    * CSRT\n");
>  	csrt = ctx->current;
>  	acpi_create_csrt(csrt);
> -- 
> 2.26.2.645.ge9eca65c58-goog

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 29/35] acpi: Support ordering SSDT data by device
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (57 preceding siblings ...)
  2020-06-04  9:20 ` [PATCH v2 27/35] x86: acpi: Move MADT down a bit Wolfgang Wallner
@ 2020-06-04 11:52 ` Wolfgang Wallner
  2020-06-04 11:54 ` [PATCH v2 28/35] acpi: Record the items added to SSDT Wolfgang Wallner
                   ` (9 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-04 11:52 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 29/35] 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>
> ---
> 
> Changes in v2: None
> Changes in v1:
> - Generalise the ACPI function recursion with acpi_recurse_method()
> 
>  arch/sandbox/dts/test.dts           |  5 ++-
>  doc/device-tree-bindings/chosen.txt |  9 +++++
>  drivers/core/acpi.c                 | 62 +++++++++++++++++++++++++++++
>  test/dm/acpi.c                      | 15 ++++---
>  4 files changed, 83 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
> index f6520a54e8..30eb749671 100644
> --- a/arch/sandbox/dts/test.dts
> +++ b/arch/sandbox/dts/test.dts
> @@ -252,7 +252,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 {
> @@ -260,7 +260,7 @@
>  		};
>  	};
>  
> -	acpi-test2 {
> +	acpi_test2: acpi-test2 {
>  		compatible = "denx,u-boot-acpi-test";
>  		acpi-ssdt-test-data = "cd";
>  	};
> @@ -893,6 +893,7 @@
>  		setting = "sunrise ohoka";
>  		other-node = "/some-bus/c-test at 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 fa16be8154..a0b598b66b 100644
> --- a/drivers/core/acpi.c
> +++ b/drivers/core/acpi.c
> @@ -108,6 +108,63 @@ static int acpi_add_item(struct acpi_ctx *ctx, struct udevice *dev,
>  	return 0;
>  }
>  
> +struct acpi_item *find_item(const char *devname)

1) Shouldn't this function be static?
2) The name is very generic. How about find_acpi_item?

> +{
> +	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;
> +}
> +
> +static int build_type(struct acpi_ctx *ctx, void *start, enum gen_type_t type)

1) I find the name "build_type" confusing. It is actually sorting items of a
given type from acpi_items and copies them to a given location. How about
sort_acpi_item_type?

2) What the function does is not immediatly obvious. A function description
would be nice.

> +{
> +	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;
> +	}
> +
> +	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_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 (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 +220,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 = build_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 d1bd108223..8df128706d 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]);
>  
> -- 
> 2.26.2.645.ge9eca65c58-goog
> 

regards, Wolfgang

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 28/35] acpi: Record the items added to SSDT
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (58 preceding siblings ...)
  2020-06-04 11:52 ` [PATCH v2 29/35] acpi: Support ordering SSDT data by device Wolfgang Wallner
@ 2020-06-04 11:54 ` Wolfgang Wallner
  2020-06-04 12:20 ` [PATCH v2 30/35] x86: Allow devices to write an SSDT Wolfgang Wallner
                   ` (8 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-04 11:54 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 28/35] 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 <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1:
> - Generalise the ACPI function recursion with acpi_recurse_method()
> 
>  drivers/core/acpi.c | 83 ++++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 79 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c
> index 4497b5cb2f..fa16be8154 100644
> --- a/drivers/core/acpi.c
> +++ b/drivers/core/acpi.c
> @@ -9,12 +9,21 @@
>  #define LOG_CATEOGRY	LOGC_ACPI
>  
>  #include <common.h>
> +#include <malloc.h>
>  #include <dm.h>
>  #include <log.h>
>  #include <dm/acpi.h>
>  #include <dm/device-internal.h>
>  #include <dm/root.h>
>  
> +#define MAX_ITEMS	100

Nit: How about MAX_ACPI_ITEMS?

> +
> +/* 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,

[snip]

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 30/35] x86: Allow devices to write an SSDT
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (59 preceding siblings ...)
  2020-06-04 11:54 ` [PATCH v2 28/35] acpi: Record the items added to SSDT Wolfgang Wallner
@ 2020-06-04 12:20 ` Wolfgang Wallner
  2020-06-04 12:22 ` [PATCH v2 33/35] pci: Avoid a crash in device_is_on_pci_bus() Wolfgang Wallner
                   ` (7 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-04 12:20 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 30/35] x86: Allow devices to write an SSDT
> 
> Call the new core function to write the SSDT. This is made up of fragments
> generated by devices that have the fill_ssdt() method.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1:
> - Use OEM_TABLE_ID instead of ACPI_TABLE_CREATOR
> - Update ACPI_DSTATUS enum
> - Drop writing of coreboot tables
> 
>  arch/x86/lib/acpi_table.c | 29 +++++++++++++++++++++++++++++
>  include/acpi/acpi_table.h |  6 ++++++
>  2 files changed, 35 insertions(+)
> 
> diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
> index e96acf08d4..4658d88351 100644
> --- a/arch/x86/lib/acpi_table.c
> +++ b/arch/x86/lib/acpi_table.c
> @@ -14,6 +14,7 @@
>  #include <mapmem.h>
>  #include <serial.h>
>  #include <version.h>
> +#include <acpi/acpigen.h>
>  #include <acpi/acpi_table.h>
>  #include <asm/acpi/global_nvs.h>
>  #include <asm/ioapic.h>
> @@ -354,6 +355,25 @@ static void acpi_create_spcr(struct acpi_spcr *spcr)
>  	header->checksum = table_compute_checksum((void *)spcr, header->length);
>  }
>  
> +void acpi_create_ssdt(struct acpi_ctx *ctx, struct acpi_table_header *ssdt,
> +		      const char *oem_table_id)
> +{
> +	memset((void *)ssdt, '\0', sizeof(struct acpi_table_header));
> +
> +	acpi_fill_header(ssdt, "SSDT");
> +	ssdt->revision = acpi_get_table_revision(ACPITAB_SSDT);
> +	ssdt->aslc_revision = 1;
> +	ssdt->length = sizeof(struct acpi_table_header);
> +
> +	acpi_inc(ctx, sizeof(struct acpi_table_header));
> +
> +	acpi_fill_ssdt(ctx);
> +
> +	/* (Re)calculate length and checksum. */
> +	ssdt->length = ctx->current - (void *)ssdt;
> +	ssdt->checksum = table_compute_checksum((void *)ssdt, ssdt->length);
> +}
> +
>  /*
>   * QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c
>   */
> @@ -363,6 +383,7 @@ ulong write_acpi_tables(ulong start_addr)
>  	struct acpi_facs *facs;
>  	struct acpi_table_header *dsdt;
>  	struct acpi_fadt *fadt;
> +	struct acpi_table_header *ssdt;
>  	struct acpi_mcfg *mcfg;
>  	struct acpi_madt *madt;
>  	struct acpi_csrt *csrt;
> @@ -418,6 +439,14 @@ ulong write_acpi_tables(ulong start_addr)
>  	acpi_create_fadt(fadt, facs, dsdt);
>  	acpi_add_table(ctx, fadt);
>  
> +	debug("ACPI:     * SSDT\n");
> +	ssdt = (struct acpi_table_header *)ctx->current;
> +	acpi_create_ssdt(ctx, ssdt, OEM_TABLE_ID);
> +	if (ssdt->length > sizeof(struct acpi_table_header)) {
> +		acpi_inc_align(ctx, ssdt->length);
> +		acpi_add_table(ctx, ssdt);
> +	}
> +
>  	debug("ACPI:    * MCFG\n");
>  	mcfg = ctx->current;
>  	acpi_create_mcfg(mcfg);
> diff --git a/include/acpi/acpi_table.h b/include/acpi/acpi_table.h
> index fe9b29f3f8..9068da24f5 100644
> --- a/include/acpi/acpi_table.h
> +++ b/include/acpi/acpi_table.h
> @@ -27,6 +27,12 @@
>  
>  struct acpi_ctx;
>  
> +/* List of ACPI HID that use the coreboot ACPI ID */
> +enum coreboot_acpi_ids {
> +	COREBOOT_ACPI_ID_CBTABLE	= 0x0000, /* BOOT0000 */
> +	COREBOOT_ACPI_ID_MAX		= 0xFFFF, /* BOOTFFFF */
> +};
> +

I can't see how this new type is related to the patch? Is it here on purpose?

>  /*
>   * RSDP (Root System Description Pointer)
>   * Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum
> -- 
> 2.26.2.645.ge9eca65c58-goog
> 

regards, Wolfgang

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 33/35] pci: Avoid a crash in device_is_on_pci_bus()
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (60 preceding siblings ...)
  2020-06-04 12:20 ` [PATCH v2 30/35] x86: Allow devices to write an SSDT Wolfgang Wallner
@ 2020-06-04 12:22 ` Wolfgang Wallner
  2020-06-04 12:26 ` [PATCH v2 31/35] acpi: Add support for DSDT generation Wolfgang Wallner
                   ` (6 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-04 12:22 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 33/35] pci: Avoid a crash in device_is_on_pci_bus()
> 
> This function cannot currently be called on the root node. Add a check
> for this as well as a test.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  include/dm/device.h |  2 +-
>  test/dm/pci.c       | 14 ++++++++++++++
>  2 files changed, 15 insertions(+), 1 deletion(-)
> 
> diff --git a/include/dm/device.h b/include/dm/device.h
> index 975eec5d0e..6a41ee5500 100644
> --- a/include/dm/device.h
> +++ b/include/dm/device.h
> @@ -742,7 +742,7 @@ int dev_enable_by_path(const char *path);
>   */
>  static inline bool device_is_on_pci_bus(const struct udevice *dev)
>  {
> -	return device_get_uclass_id(dev->parent) == UCLASS_PCI;
> +	return dev->parent && device_get_uclass_id(dev->parent) == UCLASS_PCI;
>  }
>  
>  /**
> diff --git a/test/dm/pci.c b/test/dm/pci.c
> index fb93e4c78a..39e82b3699 100644
> --- a/test/dm/pci.c
> +++ b/test/dm/pci.c
> @@ -339,3 +339,17 @@ static int dm_test_pci_addr_live(struct unit_test_state *uts)
>  }
>  DM_TEST(dm_test_pci_addr_live, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT |
>  		DM_TESTF_LIVE_TREE);
> +
> +/* Test device_is_on_pci_bus() */
> +static int dm_test_pci_on_bus(struct unit_test_state *uts)
> +{
> +	struct udevice *dev;
> +
> +	ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &dev));
> +	ut_asserteq(true, device_is_on_pci_bus(dev));
> +	ut_asserteq(false, device_is_on_pci_bus(dev_get_parent(dev)));
> +	ut_asserteq(true, device_is_on_pci_bus(dev));
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_pci_on_bus, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> -- 
> 2.26.2.645.ge9eca65c58-goog

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 31/35] acpi: Add support for DSDT generation
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (61 preceding siblings ...)
  2020-06-04 12:22 ` [PATCH v2 33/35] pci: Avoid a crash in device_is_on_pci_bus() Wolfgang Wallner
@ 2020-06-04 12:26 ` Wolfgang Wallner
  2020-06-04 12:55 ` [PATCH v2 32/35] x86: Allow devices to write to DSDT Wolfgang Wallner
                   ` (5 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-04 12:26 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 31/35] 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 <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1:
> - Generalise the ACPI function recursion with acpi_recurse_method()
> 
>  arch/sandbox/dts/test.dts |  2 ++
>  drivers/core/acpi.c       | 25 +++++++++++++++++++++-
>  include/dm/acpi.h         | 23 ++++++++++++++++++++
>  test/dm/acpi.c            | 44 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 93 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
> index 30eb749671..aab3fb7471 100644
> --- a/arch/sandbox/dts/test.dts
> +++ b/arch/sandbox/dts/test.dts
> @@ -255,6 +255,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";
>  		};
> @@ -263,6 +264,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 a0b598b66b..ebe9fde68e 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 */
> @@ -131,7 +133,9 @@ static int build_type(struct acpi_ctx *ctx, void *start, enum gen_type_t type)
>  	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;
> @@ -176,6 +180,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;
>  		}
>  	}
>  
> @@ -234,6 +240,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 = build_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 dac1635cd3..73bad2e763 100644
> --- a/include/dm/acpi.h
> +++ b/include/dm/acpi.h
> @@ -85,6 +85,19 @@ struct acpi_ops {
>  	 * @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

Typo: THe

> +	 * whatever ACPI code is needed by this device. It will end up in the
> +	 * DSDT table.
> +	 *
> +	 * @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)
> @@ -139,6 +152,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 8df128706d..3fe0a0c9ff 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);
> -- 
> 2.26.2.645.ge9eca65c58-goog

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 32/35] x86: Allow devices to write to DSDT
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (62 preceding siblings ...)
  2020-06-04 12:26 ` [PATCH v2 31/35] acpi: Add support for DSDT generation Wolfgang Wallner
@ 2020-06-04 12:55 ` Wolfgang Wallner
  2020-06-04 13:04 ` [PATCH v2 35/35] acpi: Add an acpi split command Wolfgang Wallner
                   ` (4 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-04 12:55 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 32/35] x86: Allow devices to write to DSDT
> 
> Call the new core function to inject ASL programmatically into the DSDT.
> This is made up of fragments generated by devices that have the
> inject_dsdt() method. The normal, compiled ASL file is added after this.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  arch/x86/lib/acpi_table.c | 15 ++++++++++++++-
>  1 file changed, 14 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
> index 4658d88351..a7ec6d2b15 100644
> --- a/arch/x86/lib/acpi_table.c
> +++ b/arch/x86/lib/acpi_table.c
> @@ -411,7 +411,20 @@ ulong write_acpi_tables(ulong start_addr)
>  	memcpy(ctx->current,
>  	       (char *)&AmlCode + sizeof(struct acpi_table_header),
>  	       dsdt->length - sizeof(struct acpi_table_header));
> -	acpi_inc_align(ctx, dsdt->length - sizeof(struct acpi_table_header));
> +
> +	if (dsdt->length >= sizeof(struct acpi_table_header)) {
> +		acpi_inject_dsdt(ctx);
> +		memcpy(ctx->current,
> +		       (char *)AmlCode + sizeof(struct acpi_table_header),
> +		       dsdt->length - sizeof(struct acpi_table_header));

A similar memcpy is already executed a few lines above before acpi_inject_dsdt()
is called. Would it be possible to unify the two code paths, e.g. only call
that memcpy once with the correct adress? In the case of the if() the initial
memcpy would have no effect because that memory will be overwritten again
if I understand correctly.

> +		acpi_inc(ctx, dsdt->length - sizeof(struct acpi_table_header));
> +
> +		/* (Re)calculate length and checksum. */
> +		dsdt->length = ctx->current - (void *)dsdt;
> +		dsdt->checksum = 0;
> +		dsdt->checksum = table_compute_checksum(dsdt, dsdt->length);

1) dsdt->checksum is set anyway a few line below (after the GVNS update). Is it
also required to set it here?

2) Why is set to 0 just before recomputation? (This is also done in the
existing code a few lines below when it is set again.)

> +	}
> +	acpi_align(ctx);
>  
>  	/* Pack GNVS into the ACPI table area */
>  	for (i = 0; i < dsdt->length; i++) {
> -- 
> 2.26.2.645.ge9eca65c58-goog

regards, Wolfgang

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 35/35] acpi: Add an acpi split command
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (63 preceding siblings ...)
  2020-06-04 12:55 ` [PATCH v2 32/35] x86: Allow devices to write to DSDT Wolfgang Wallner
@ 2020-06-04 13:04 ` Wolfgang Wallner
  2020-06-04 13:17 ` [PATCH v2 34/35] dm: acpi: Enhance acpi_get_name() Wolfgang Wallner
                   ` (3 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-04 13:04 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 35/35] acpi: Add an acpi split command

Nit: I find the commit message confusing. What does "split command" mean?
How about: "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. This can be helpful for debugging.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  cmd/acpi.c          | 15 +++++++++++++--
>  drivers/core/acpi.c | 16 ++++++++++++++++
>  include/dm/acpi.h   | 10 ++++++++++
>  test/dm/acpi.c      | 39 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 78 insertions(+), 2 deletions(-)
> 
> diff --git a/cmd/acpi.c b/cmd/acpi.c
> index e9a9161a91..3204b2ec43 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;
> +
> +	dump = argc >= 2 && !strcmp("-d", argv[1]);
> +	acpi_dump_items(dump);
> +
> +	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 <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(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 ec70db3951..aa11001a8d 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(bool dump_contents)
> +{
> +	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 (dump_contents) {
> +			print_buffer(0, item->buf, 1, item->size, 0);
> +			printf("\n");
> +		}
> +	}
> +}
> +
>  struct acpi_item *find_item(const char *devname)
>  {
>  	int i;
> diff --git a/include/dm/acpi.h b/include/dm/acpi.h
> index 73bad2e763..678391ccfc 100644
> --- a/include/dm/acpi.h
> +++ b/include/dm/acpi.h
> @@ -162,6 +162,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.
> + *
> + * @dump_contents: true to dump the binary contents, false to just show the list
> + */
> +void acpi_dump_items(bool dump_contents);

Nit: IMHO an enum would be more readable instead of a boolean parameter.

> +
>  #endif /* __ACPI__ */
>  
>  #endif
> diff --git a/test/dm/acpi.c b/test/dm/acpi.c
> index bd4c66c471..4952256ce1 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);
> -- 
> 2.26.2.645.ge9eca65c58-goog

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 34/35] dm: acpi: Enhance acpi_get_name()
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (64 preceding siblings ...)
  2020-06-04 13:04 ` [PATCH v2 35/35] acpi: Add an acpi split command Wolfgang Wallner
@ 2020-06-04 13:17 ` Wolfgang Wallner
  2020-06-04 13:27 ` [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Wolfgang Wallner
                   ` (2 subsequent siblings)
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-04 13:17 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 34/35] 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 <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1:
> - Use acpi,ddn instead of acpi,desc
> - Rename to acpi_device_infer_name()
> - Update newly created sandbox tests
> 
>  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          |  15 ++++
>  lib/acpi/acpi_device.c              | 106 ++++++++++++++++++++++++++++
>  test/dm/acpi.c                      |  42 ++++++++++-
>  test/dm/acpigen.c                   |   4 +-
>  9 files changed, 189 insertions(+), 25 deletions(-)
> 
> diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
> index aab3fb7471..750381bcac 100644
> --- a/arch/sandbox/dts/test.dts
> +++ b/arch/sandbox/dts/test.dts
> @@ -111,6 +111,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 at 10 {
>  	interrupts-extended = <&acpi_gpe GPIO_21_IRQ IRQ_TYPE_EDGE_FALLING>;
>  	linux,probed;
>  };
> +
> +pcie-a0 at 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 ebe9fde68e..ec70db3951 100644
> --- a/drivers/core/acpi.c
> +++ b/drivers/core/acpi.c
> @@ -9,9 +9,10 @@
>  #define LOG_CATEOGRY	LOGC_ACPI
>  
>  #include <common.h>
> -#include <malloc.h>
>  #include <dm.h>
>  #include <log.h>
> +#include <malloc.h>
> +#include <acpi/acpi_device.h>
>  #include <dm/acpi.h>
>  #include <dm/device-internal.h>
>  #include <dm/root.h>
> @@ -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 4264acc953..5aeb6bdf43 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(spi_sandbox) = {
>  	.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 adebd63c15..e99330ac6f 100644
> --- a/include/acpi/acpi_device.h
> +++ b/include/acpi/acpi_device.h
> @@ -383,4 +383,19 @@ 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, of the uclass of their parent. These rules are implemented in
 
Typo: or the uclass
 
> + * this function. It attempts to produce a name for a device based on these
> + * rules.
> + *
> + * @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 e5968bd3aa..b39ec8eb93 100644
> --- a/lib/acpi/acpi_device.c
> +++ b/lib/acpi/acpi_device.c
> @@ -10,6 +10,8 @@
>  #include <dm.h>
>  #include <irq.h>
>  #include <log.h>
> +#include <usb.h>
> +#include <acpi/acpigen.h>
>  #include <acpi/acpi_device.h>
>  #include <acpi/acpigen.h>
>  #include <asm-generic/gpio.h>
> @@ -704,3 +706,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:
> +		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 3fe0a0c9ff..bd4c66c471 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);
> diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
> index afaccc7664..2922896c69 100644
> --- a/test/dm/acpigen.c
> +++ b/test/dm/acpigen.c
> @@ -303,7 +303,7 @@ static int dm_test_acpi_i2c(struct unit_test_state *uts)
>  	ut_asserteq(6, get_unaligned((u16 *)(ptr + 10)));
>  	ut_asserteq(100000, get_unaligned((u32 *)(ptr + 12)));
>  	ut_asserteq(0x43, get_unaligned((u16 *)(ptr + 16)));
> -	ut_asserteq_str("\\_SB.SI2C", (char *)ptr + 18);
> +	ut_asserteq_str("\\_SB.I2C0", (char *)ptr + 18);
>  
>  	free_context(&ctx);
>  
> @@ -339,7 +339,7 @@ static int dm_test_acpi_spi(struct unit_test_state *uts)
>  	ut_asserteq(0, ptr[17]);
>  	ut_asserteq(0, ptr[18]);
>  	ut_asserteq(0, get_unaligned((u16 *)(ptr + 19)));
> -	ut_asserteq_str("\\_SB.SSPI", (char *)ptr + 21);
> +	ut_asserteq_str("\\_SB.SPI0", (char *)ptr + 21);
>  
>  	free_context(&ctx);
>  
> -- 
> 2.26.2.645.ge9eca65c58-goog

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B)
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (65 preceding siblings ...)
  2020-06-04 13:17 ` [PATCH v2 34/35] dm: acpi: Enhance acpi_get_name() Wolfgang Wallner
@ 2020-06-04 13:27 ` Wolfgang Wallner
  2020-06-04 15:59   ` Simon Glass
  2020-06-10  8:06 ` [PATCH v2 06/35] acpi: Support generation of interrupt descriptor Wolfgang Wallner
  2020-06-10  8:40 ` [PATCH v2 12/35] acpi: Support generation of SPI descriptor Wolfgang Wallner
  68 siblings, 1 reply; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-04 13:27 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"U-Boot" <u-boot-bounces@lists.denx.de> schrieb: -----
> Betreff: Antwort: Re: [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B)
> 
> Hi Bin,
> 
> -----"Bin Meng" <bmeng.cn@gmail.com> schrieb: -----
> > Betreff: Re: [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B)
> > 
> > Hi Wolfgang, Andy,
> > 
> > On Mon, May 11, 2020 at 4:34 AM Simon Glass <sjg@chromium.org> wrote:
> > >
> > > NOTE: I have resent this as v1 to avoid confusion
> > >
> > > This is split from the original series in an attempt to get things applied
> > > in chunks.
> > >

[snip]

> > >
> > 
> > Since you were involved a lot in the discussion in the part A series,
> > would you please let me know if you get some time to review this?
> 
> Unfortunately, I don't have as much time now for review of part B as I had for
> part A. I already started reviewing part B and I will try to continue when time
> allows.

I'm done with my review of v2 of part B.
I haven't commented on the patches 06/35 and 12/35, as the comments would be
similar as in other patches of the series and I thought it would not make sense
to review them without waiting for the feedback to the other reviews.

regards, Wolfgang

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B)
  2020-06-04 13:27 ` [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Wolfgang Wallner
@ 2020-06-04 15:59   ` Simon Glass
  0 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-06-04 15:59 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

On Thu, 4 Jun 2020 at 07:27, Wolfgang Wallner
<wolfgang.wallner@br-automation.com> wrote:
>
> Hi Simon,
>
> -----"U-Boot" <u-boot-bounces@lists.denx.de> schrieb: -----
> > Betreff: Antwort: Re: [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B)
> >
> > Hi Bin,
> >
> > -----"Bin Meng" <bmeng.cn@gmail.com> schrieb: -----
> > > Betreff: Re: [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B)
> > >
> > > Hi Wolfgang, Andy,
> > >
> > > On Mon, May 11, 2020 at 4:34 AM Simon Glass <sjg@chromium.org> wrote:
> > > >
> > > > NOTE: I have resent this as v1 to avoid confusion
> > > >
> > > > This is split from the original series in an attempt to get things applied
> > > > in chunks.
> > > >
>
> [snip]
>
> > > >
> > >
> > > Since you were involved a lot in the discussion in the part A series,
> > > would you please let me know if you get some time to review this?
> >
> > Unfortunately, I don't have as much time now for review of part B as I had for
> > part A. I already started reviewing part B and I will try to continue when time
> > allows.
>
> I'm done with my review of v2 of part B.
> I haven't commented on the patches 06/35 and 12/35, as the comments would be
> similar as in other patches of the series and I thought it would not make sense
> to review them without waiting for the feedback to the other reviews.
>

OK great, thank you! I'll go through these soon.

Regards,
Simon

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 05/35] acpi: Support generation of ACPI code
  2020-05-14  8:32 ` Antwort: [PATCH v2 05/35] acpi: Support generation of ACPI code Wolfgang Wallner
@ 2020-06-09 21:14   ` Simon Glass
  2020-06-10  7:33   ` Wolfgang Wallner
  2020-06-10  7:39   ` Wolfgang Wallner
  2 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-06-09 21:14 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

On Thu, 14 May 2020 at 02:32, Wolfgang Wallner
<wolfgang.wallner@br-automation.com> wrote:
>
> Hi Simon,
>
> -----"Simon Glass" <sjg@chromium.org> schrieb: -----
> > Betreff: [PATCH v2 05/35] acpi: Support generation of ACPI code
> >
> > Add a new file to handle generating ACPI code programatically. This is
> > used when information must be dynamically added to the tables, e.g. the
> > SSDT.
> >
> > Initial support is just for writing simple values.
> >
> > Signed-off-by: Simon Glass <sjg@chromium.org>
> > ---
> >
> > Changes in v2: None
> > Changes in v1: None
> >
> >  include/acpi/acpigen.h | 49 +++++++++++++++++++++++++++++++
> >  lib/acpi/Makefile      |  1 +
> >  lib/acpi/acpigen.c     | 38 ++++++++++++++++++++++++
> >  test/dm/Makefile       |  1 +
> >  test/dm/acpigen.c      | 65 ++++++++++++++++++++++++++++++++++++++++++
> >  5 files changed, 154 insertions(+)
> >  create mode 100644 include/acpi/acpigen.h
> >  create mode 100644 lib/acpi/acpigen.c
> >  create mode 100644 test/dm/acpigen.c
> >
> > diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
> > new file mode 100644
> > index 0000000000..8809cdb4e1
> > --- /dev/null
> > +++ b/include/acpi/acpigen.h
> > @@ -0,0 +1,49 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Core ACPI (Advanced Configuration and Power Interface) support
> > + *
> > + * Copyright 2019 Google LLC
> > + *
> > + * Modified from coreboot file acpigen.h
> > + */
> > +
> > +#ifndef __ACPI_ACPIGEN_H
> > +#define __ACPI_ACPIGEN_H
> > +
> > +#include <linux/types.h>
> > +
> > +struct acpi_ctx;
> > +
> > +/**
> > + * acpigen_get_current() - Get the current ACPI code output pointer
> > + *
> > + * @ctx: ACPI context pointer
> > + * @return output pointer
> > + */
> > +u8 *acpigen_get_current(struct acpi_ctx *ctx);
> > +
> > +/**
> > + * acpigen_emit_byte() - Emit a byte to the ACPI code
> > + *
> > + * @ctx: ACPI context pointer
> > + * @data: Value to output
> > + */
> > +void acpigen_emit_byte(struct acpi_ctx *ctx, uint data);
> > +
> > +/**
> > + * acpigen_emit_word() - Emit a 16-bit word to the ACPI code
> > + *
> > + * @ctx: ACPI context pointer
> > + * @data: Value to output
> > + */
> > +void acpigen_emit_word(struct acpi_ctx *ctx, uint data);
> > +
> > +/**
> > + * acpigen_emit_dword() - Emit a 32-bit 'double word' to the ACPI code
> > + *
> > + * @ctx: ACPI context pointer
> > + * @data: Value to output
> > + */
> > +void acpigen_emit_dword(struct acpi_ctx *ctx, uint data);
> > +
> > +#endif
> > diff --git a/lib/acpi/Makefile b/lib/acpi/Makefile
> > index caae6c01bd..85a1f774ad 100644
> > --- a/lib/acpi/Makefile
> > +++ b/lib/acpi/Makefile
> > @@ -1,5 +1,6 @@
> >  # SPDX-License-Identifier: GPL-2.0+
> >  #
> >
> > +obj-y += acpigen.o
> >  obj-y += acpi_device.o
> >  obj-y += acpi_table.o
> > diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
> > new file mode 100644
> > index 0000000000..59bd3af0b7
> > --- /dev/null
> > +++ b/lib/acpi/acpigen.c
> > @@ -0,0 +1,38 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Generation of ACPI (Advanced Configuration and Power Interface) tables
> > + *
> > + * Copyright 2019 Google LLC
> > + * Mostly taken from coreboot
> > + */
> > +
> > +#define LOG_CATEGORY LOGC_ACPI
> > +
> > +#include <common.h>
> > +#include <dm.h>
> > +#include <acpi/acpigen.h>
> > +#include <dm/acpi.h>
> > +
> > +u8 *acpigen_get_current(struct acpi_ctx *ctx)
> > +{
> > +     return ctx->current;
> > +}
> > +
> > +void acpigen_emit_byte(struct acpi_ctx *ctx, uint data)
> > +{
>
> As we expect exactly a byte, could data be of type uint8_t ?
> Similar for the functions below.

It could but I really try to avoid that. It means that the compiler
has to mask the values coming in in a register wihch adds to code
size.

>
> > +     *(u8 *)ctx->current++ = data;
> > +}
> > +
> > +void acpigen_emit_word(struct acpi_ctx *ctx, uint data)
> > +{
> > +     acpigen_emit_byte(ctx, data & 0xff);
> > +     acpigen_emit_byte(ctx, (data >> 8) & 0xff);
>
> This function assumes little-endian host endianess.  This works under
> x86 and probably most of ARM, and I'm not aware of other architectures
> using ACPI.
>
> Should it be made more portable anyway e.g. by using cpu_to_le16()?

Do you mean that ACPI can store the bytes in the other order? I
thought it was only big-endian but actually I don't know that. Do you
have any details?

Or are you asking about the shift? I believe that on big-endian
machines, shifting right still divides by 256, and so does what is
expected.

>
> > +}
> > +
> > +void acpigen_emit_dword(struct acpi_ctx *ctx, uint data)
> > +{
> > +     acpigen_emit_byte(ctx, data & 0xff);
> > +     acpigen_emit_byte(ctx, (data >> 8) & 0xff);
> > +     acpigen_emit_byte(ctx, (data >> 16) & 0xff);
> > +     acpigen_emit_byte(ctx, (data >> 24) & 0xff);
> > +}
> > diff --git a/test/dm/Makefile b/test/dm/Makefile
> > index 6c18fd04ce..e3e0cccf01 100644
> > --- a/test/dm/Makefile
> > +++ b/test/dm/Makefile
> > @@ -14,6 +14,7 @@ obj-$(CONFIG_UT_DM) += test-uclass.o
> >  obj-$(CONFIG_UT_DM) += core.o
> >  ifneq ($(CONFIG_SANDBOX),)
> >  obj-$(CONFIG_ACPIGEN) += acpi.o
> > +obj-$(CONFIG_ACPIGEN) += acpigen.o
> >  obj-$(CONFIG_SOUND) += audio.o
> >  obj-$(CONFIG_BLK) += blk.o
> >  obj-$(CONFIG_BOARD) += board.o
> > diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
> > new file mode 100644
> > index 0000000000..68f2b73132
> > --- /dev/null
> > +++ b/test/dm/acpigen.c
> > @@ -0,0 +1,65 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Tests for ACPI code generation
> > + *
> > + * Copyright 2019 Google LLC
> > + * Written by Simon Glass <sjg@chromium.org>
> > + */
> > +
> > +#include <common.h>
> > +#include <dm.h>
> > +#include <malloc.h>
> > +#include <acpi/acpigen.h>
> > +#include <asm/unaligned.h>
> > +#include <dm/acpi.h>
> > +#include <dm/test.h>
> > +#include <test/ut.h>
> > +
> > +static int alloc_context(struct acpi_ctx **ctxp)
> > +{
> > +     struct acpi_ctx *ctx;
> > +
> > +     *ctxp = NULL;
> > +     ctx = malloc(sizeof(*ctx));
> > +     if (!ctx)
> > +             return -ENOMEM;
> > +     ctx->current = malloc(150);
> > +     if (!ctx->current)
>
> free(ctx)
>
> > +             return -ENOMEM;
> > +     *ctxp = ctx;
> > +
> > +     return 0;
> > +}
> > +
> > +static void free_context(struct acpi_ctx **ctxp)
> > +{
>
> Should the memory that was initally allocated to ctx->current also be
> released or stay allocted?

It is normally allocated by the code that uses it, and generally just
points to memory (e.g. 0xf0000) rather than using malloc(). But for
the benefit of tests I can add a base value, and free it.

Regards,
Simon

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 11/35] acpi: Support generation of I2C descriptor
  2020-05-19 11:58 ` Antwort: [PATCH v2 11/35] acpi: Support generation of I2C descriptor Wolfgang Wallner
@ 2020-06-09 21:14   ` Simon Glass
  0 siblings, 0 replies; 84+ messages in thread
From: Simon Glass @ 2020-06-09 21:14 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

On Tue, 19 May 2020 at 05:58, Wolfgang Wallner
<wolfgang.wallner@br-automation.com> wrote:
>
> Hi Simon,
>
> -----"Simon Glass" <sjg@chromium.org> schrieb: -----
> > Betreff: [PATCH v2 11/35] acpi: Support generation of I2C descriptor
> >
> > Add a function to write a GPIO descriptor to the generated ACPI code.
> >
> > Signed-off-by: Simon Glass <sjg@chromium.org>
> > ---
> >
> > Changes in v2:
> > - Fix memset of I2C descriptor
> >
> > Changes in v1: None
> >
> >  drivers/i2c/sandbox_i2c.c  |  11 ++++
> >  drivers/rtc/sandbox_rtc.c  |  13 +++++
> >  include/acpi/acpi_device.h |  36 +++++++++++++
> >  lib/acpi/acpi_device.c     | 103 +++++++++++++++++++++++++++++++++++++
> >  test/dm/acpigen.c          |  32 ++++++++++++
> >  5 files changed, 195 insertions(+)
> >

[..]

> > +/**
> > + * acpi_device_set_i2c() - Set up an ACPI I2C struct from a device
> > + *
> > + * @dev: I2C device to convert
> > + * @i2c: Place to put the new structure
> > + * @scope: Scope of the I2C device (this is the controller path)
>
> From the declaration I would assume that "scope" is internally copied, but in
> the code it is only referenced.
> I would propose to add something like the following to its description:
> "The value of scope is not copied, but only referenced. This implies the
> caller has to ensure it stays valid for the lifetime of i2c."

OK done

>
> > + * @return 0 (always)
>
> dev_get_parent_platdata() could return NULL. Should we check this and return
> and error?
>
> > + */
> > +static int acpi_device_set_i2c(const struct udevice *dev, struct acpi_i2c *i2c,
> > +                            const char *scope)
> > +{
> > +     struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
> > +     struct udevice *bus = dev_get_parent(dev);
> > +
> > +     memset(i2c, '\0', sizeof(*i2c));
>
> Nit: memset(i2c, 0, sizeof(*i2c));
>
> This is only a style question. But it seems 0 is used for memset in existing
> U-Boot code much more often then '\0' (~120 grep results vs ~1100 grep results).

Yes I do feel in the minority. I used to write 0 but was corrected by
a CS professor years ago and it has stuck with me. It makes it clear
that it is the character that is repeated, not integer, which is
presumably larger than a byte.

>
> > +     i2c->address = chip->chip_addr;
> > +     i2c->mode_10bit = 0;
> > +
> > +     /*
> > +      * i2c_bus->speed_hz is set if this device is probed, but if not we
> > +      * must use the device tree
> > +      */
> > +     i2c->speed = dev_read_u32_default(bus, "clock-frequency", 100000);
>
> Nit: I2C_SPEED_STANDARD_RATE instead of 100000?

Done

Regards,
Simon

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 05/35] acpi: Support generation of ACPI code
  2020-05-14  8:32 ` Antwort: [PATCH v2 05/35] acpi: Support generation of ACPI code Wolfgang Wallner
  2020-06-09 21:14   ` Simon Glass
@ 2020-06-10  7:33   ` Wolfgang Wallner
  2020-06-10  7:39   ` Wolfgang Wallner
  2 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-10  7:33 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: Re: [PATCH v2 05/35] acpi: Support generation of ACPI code
> 
> Hi Wolfgang,
> 
> On Thu, 14 May 2020 at 02:32, Wolfgang Wallner
> <wolfgang.wallner@br-automation.com> wrote:
> >
> > Hi Simon,
> >
> > -----"Simon Glass" <sjg@chromium.org> schrieb: -----
> > > Betreff: [PATCH v2 05/35] acpi: Support generation of ACPI code
> > >
> > > Add a new file to handle generating ACPI code programatically. This is
> > > used when information must be dynamically added to the tables, e.g. the
> > > SSDT.
> > >
> > > Initial support is just for writing simple values.
> > >
> > > Signed-off-by: Simon Glass <sjg@chromium.org>
> > > ---
> > >
> > > Changes in v2: None
> > > Changes in v1: None
> > >
> > >  include/acpi/acpigen.h | 49 +++++++++++++++++++++++++++++++
> > >  lib/acpi/Makefile      |  1 +
> > >  lib/acpi/acpigen.c     | 38 ++++++++++++++++++++++++
> > >  test/dm/Makefile       |  1 +
> > >  test/dm/acpigen.c      | 65 ++++++++++++++++++++++++++++++++++++++++++
> > >  5 files changed, 154 insertions(+)
> > >  create mode 100644 include/acpi/acpigen.h
> > >  create mode 100644 lib/acpi/acpigen.c
> > >  create mode 100644 test/dm/acpigen.c
> > >
> > > diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
> > > new file mode 100644
> > > index 0000000000..8809cdb4e1
> > > --- /dev/null
> > > +++ b/include/acpi/acpigen.h
> > > @@ -0,0 +1,49 @@
> > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > +/*
> > > + * Core ACPI (Advanced Configuration and Power Interface) support
> > > + *
> > > + * Copyright 2019 Google LLC
> > > + *
> > > + * Modified from coreboot file acpigen.h
> > > + */
> > > +
> > > +#ifndef __ACPI_ACPIGEN_H
> > > +#define __ACPI_ACPIGEN_H
> > > +
> > > +#include <linux/types.h>
> > > +
> > > +struct acpi_ctx;
> > > +
> > > +/**
> > > + * acpigen_get_current() - Get the current ACPI code output pointer
> > > + *
> > > + * @ctx: ACPI context pointer
> > > + * @return output pointer
> > > + */
> > > +u8 *acpigen_get_current(struct acpi_ctx *ctx);
> > > +
> > > +/**
> > > + * acpigen_emit_byte() - Emit a byte to the ACPI code
> > > + *
> > > + * @ctx: ACPI context pointer
> > > + * @data: Value to output
> > > + */
> > > +void acpigen_emit_byte(struct acpi_ctx *ctx, uint data);
> > > +
> > > +/**
> > > + * acpigen_emit_word() - Emit a 16-bit word to the ACPI code
> > > + *
> > > + * @ctx: ACPI context pointer
> > > + * @data: Value to output
> > > + */
> > > +void acpigen_emit_word(struct acpi_ctx *ctx, uint data);
> > > +
> > > +/**
> > > + * acpigen_emit_dword() - Emit a 32-bit 'double word' to the ACPI code
> > > + *
> > > + * @ctx: ACPI context pointer
> > > + * @data: Value to output
> > > + */
> > > +void acpigen_emit_dword(struct acpi_ctx *ctx, uint data);
> > > +
> > > +#endif
> > > diff --git a/lib/acpi/Makefile b/lib/acpi/Makefile
> > > index caae6c01bd..85a1f774ad 100644
> > > --- a/lib/acpi/Makefile
> > > +++ b/lib/acpi/Makefile
> > > @@ -1,5 +1,6 @@
> > >  # SPDX-License-Identifier: GPL-2.0+
> > >  #
> > >
> > > +obj-y += acpigen.o
> > >  obj-y += acpi_device.o
> > >  obj-y += acpi_table.o
> > > diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
> > > new file mode 100644
> > > index 0000000000..59bd3af0b7
> > > --- /dev/null
> > > +++ b/lib/acpi/acpigen.c
> > > @@ -0,0 +1,38 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * Generation of ACPI (Advanced Configuration and Power Interface) tables
> > > + *
> > > + * Copyright 2019 Google LLC
> > > + * Mostly taken from coreboot
> > > + */
> > > +
> > > +#define LOG_CATEGORY LOGC_ACPI
> > > +
> > > +#include <common.h>
> > > +#include <dm.h>
> > > +#include <acpi/acpigen.h>
> > > +#include <dm/acpi.h>
> > > +
> > > +u8 *acpigen_get_current(struct acpi_ctx *ctx)
> > > +{
> > > +     return ctx->current;
> > > +}
> > > +
> > > +void acpigen_emit_byte(struct acpi_ctx *ctx, uint data)
> > > +{
> >
> > As we expect exactly a byte, could data be of type uint8_t ?
> > Similar for the functions below.
> 
> It could but I really try to avoid that. It means that the compiler
> has to mask the values coming in in a register wihch adds to code
> size.

Ok, thanks for the explanation.

> 
> >
> > > +     *(u8 *)ctx->current++ = data;
> > > +}
> > > +
> > > +void acpigen_emit_word(struct acpi_ctx *ctx, uint data)
> > > +{
> > > +     acpigen_emit_byte(ctx, data & 0xff);
> > > +     acpigen_emit_byte(ctx, (data >> 8) & 0xff);
> >
> > This function assumes little-endian host endianess.  This works under
> > x86 and probably most of ARM, and I'm not aware of other architectures
> > using ACPI.
> >
> > Should it be made more portable anyway e.g. by using cpu_to_le16()?
> 
> Do you mean that ACPI can store the bytes in the other order?

No, I did not mean that.

> I
> thought it was only big-endian but actually I don't know that. Do you
> have any details?

You are right that ACPI only supports a single endianess, but it is
little-endian, not big-endian.

Section 5.2 "ACPI System Description Tables" of ACPI 6.3 states:
"All numeric values in ACPI-defined tables, blocks, and structures are always
encoded in little endian format."

and section 19.3.5 "ASL Data Types" tells us that an integer is "An n-bit
little-endian unsigned integer".

The only exception to the everything-is-little-endian-rule that I could find
is given in Section "5.2.6 System Description Table Header":

"Tables defined outside of the ACPI specification may define data value
encodings in either little endian or big endian format. For the purpose of
clarity, external table definition documents should include the endian-ness
of their data value encodings."

> Or are you asking about the shift? I believe that on big-endian
> machines, shifting right still divides by 256, and so does what is
> expected.

Yes, that is what I was worried about, but I got it wrong. As long as we only
write, we only have to take care about the endianess of the target (ACPI).

The could above should work on both little-endian and big-endian architectures,
so please ignore my comment.

> >
> > > +}
> > > +
> > > +void acpigen_emit_dword(struct acpi_ctx *ctx, uint data)
> > > +{
> > > +     acpigen_emit_byte(ctx, data & 0xff);
> > > +     acpigen_emit_byte(ctx, (data >> 8) & 0xff);
> > > +     acpigen_emit_byte(ctx, (data >> 16) & 0xff);
> > > +     acpigen_emit_byte(ctx, (data >> 24) & 0xff);
> > > +}
> > > diff --git a/test/dm/Makefile b/test/dm/Makefile
> > > index 6c18fd04ce..e3e0cccf01 100644
> > > --- a/test/dm/Makefile
> > > +++ b/test/dm/Makefile
> > > @@ -14,6 +14,7 @@ obj-$(CONFIG_UT_DM) += test-uclass.o
> > >  obj-$(CONFIG_UT_DM) += core.o
> > >  ifneq ($(CONFIG_SANDBOX),)
> > >  obj-$(CONFIG_ACPIGEN) += acpi.o
> > > +obj-$(CONFIG_ACPIGEN) += acpigen.o
> > >  obj-$(CONFIG_SOUND) += audio.o
> > >  obj-$(CONFIG_BLK) += blk.o
> > >  obj-$(CONFIG_BOARD) += board.o
> > > diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
> > > new file mode 100644
> > > index 0000000000..68f2b73132
> > > --- /dev/null
> > > +++ b/test/dm/acpigen.c
> > > @@ -0,0 +1,65 @@
> > > +// SPDX-License-Identifier: GPL-2.0+
> > > +/*
> > > + * Tests for ACPI code generation
> > > + *
> > > + * Copyright 2019 Google LLC
> > > + * Written by Simon Glass <sjg@chromium.org>
> > > + */
> > > +
> > > +#include <common.h>
> > > +#include <dm.h>
> > > +#include <malloc.h>
> > > +#include <acpi/acpigen.h>
> > > +#include <asm/unaligned.h>
> > > +#include <dm/acpi.h>
> > > +#include <dm/test.h>
> > > +#include <test/ut.h>
> > > +
> > > +static int alloc_context(struct acpi_ctx **ctxp)
> > > +{
> > > +     struct acpi_ctx *ctx;
> > > +
> > > +     *ctxp = NULL;
> > > +     ctx = malloc(sizeof(*ctx));
> > > +     if (!ctx)
> > > +             return -ENOMEM;
> > > +     ctx->current = malloc(150);
> > > +     if (!ctx->current)
> >
> > free(ctx)
> >
> > > +             return -ENOMEM;
> > > +     *ctxp = ctx;
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static void free_context(struct acpi_ctx **ctxp)
> > > +{
> >
> > Should the memory that was initally allocated to ctx->current also be
> > released or stay allocted?
> 
> It is normally allocated by the code that uses it, and generally just
> points to memory (e.g. 0xf0000) rather than using malloc(). But for
> the benefit of tests I can add a base value, and free it.
> 
> Regards,
> Simon

regards, Wolfgang

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 05/35] acpi: Support generation of ACPI code
  2020-05-14  8:32 ` Antwort: [PATCH v2 05/35] acpi: Support generation of ACPI code Wolfgang Wallner
  2020-06-09 21:14   ` Simon Glass
  2020-06-10  7:33   ` Wolfgang Wallner
@ 2020-06-10  7:39   ` Wolfgang Wallner
  2 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-10  7:39 UTC (permalink / raw)
  To: u-boot

Hi Simon,

[snip]

> The could above should work on both little-endian and big-endian architectures,
> so please ignore my comment.

The code above ... :)

[snip]

regards, Wolfgang

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 06/35] acpi: Support generation of interrupt descriptor
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (66 preceding siblings ...)
  2020-06-04 13:27 ` [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Wolfgang Wallner
@ 2020-06-10  8:06 ` Wolfgang Wallner
  2020-06-10  8:40 ` [PATCH v2 12/35] acpi: Support generation of SPI descriptor Wolfgang Wallner
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-10  8:06 UTC (permalink / raw)
  To: u-boot

Hi Simon,


-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 06/35] acpi: Support generation of interrupt descriptor
> 
> Add a function to write an interrupt descriptor to the generated ACPI
> code.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> Changes in v1: None
> 
>  include/acpi/acpi_device.h |  15 +++++
>  lib/acpi/acpi_device.c     | 118 +++++++++++++++++++++++++++++++++++++
>  test/dm/acpigen.c          |  31 ++++++++++
>  3 files changed, 164 insertions(+)
> 
> diff --git a/include/acpi/acpi_device.h b/include/acpi/acpi_device.h
> index 24895de0da..4f87cd003a 100644
> --- a/include/acpi/acpi_device.h
> +++ b/include/acpi/acpi_device.h

[snip]

> @@ -86,3 +88,119 @@ enum acpi_dev_status acpi_device_status(const struct udevice *dev)
>  {
>  	return ACPI_DSTATUS_ALL_ON;
>  }
> +
> +/**
> + * acpi_device_write_zero_len() - Write a placeholder word value
> + *
> + * @return pointer to the zero word (for fixing up later)
> + */
> +static void *acpi_device_write_zero_len(struct acpi_ctx *ctx)
> +{
> +	u8 *p = acpigen_get_current(ctx);
> +
> +	acpigen_emit_word(ctx, 0);
> +
> +	return p;
> +}
> +
> +/**
> + * acpi_device_fill_from_len() - Fill in a length value
> + *
> + * This calculated the number of bytes since the provided @start and writes it
> + * to @ptr, which was previous returned by acpi_device_write_zero_len().
> + *
> + * @ptr: Word to update
> + * @start: Start address to count from to calculated the length
> + */
> +static void acpi_device_fill_from_len(struct acpi_ctx *ctx, char *ptr,
> +				      u8 *start)
> +{
> +	u16 len = acpigen_get_current(ctx) - start;
> +
> +	ptr[0] = len & 0xff;
> +	ptr[1] = (len >> 8) & 0xff;
> +}
> +
> +/**
> + * acpi_device_fill_len() - Fill in a length value, excluding the length itself
> + *
> + * Fill in the length field with the value calculated from after the 16bit
> + * field to acpigen current. This is useful since the length value does not
> + * include the length field itself.
> + *
> + * This calls acpi_device_fill_from_len() passing @ptr + 2 as @start
> + *
> + * @ptr: Word to update.
> + */
> +static void acpi_device_fill_len(struct acpi_ctx *ctx, void *ptr)
> +{
> +	acpi_device_fill_from_len(ctx, ptr, ptr + sizeof(u16));
> +}
> +
> +/* ACPI 6.3 section 6.4.3.6: Extended Interrupt Descriptor */
> +static int acpi_device_write_interrupt(struct acpi_ctx *ctx,
> +				       const struct acpi_irq *irq)
> +{
> +	void *desc_length;
> +	u8 flags;
> +
> +	if (!irq->pin)
> +		return -ENOENT;
> +
> +	/* This is supported by GpioInt() but not Interrupt() */
> +	if (irq->polarity == ACPI_IRQ_ACTIVE_BOTH)
> +		return -EINVAL;
> +
> +	/* Byte 0: Descriptor Type */
> +	acpigen_emit_byte(ctx, ACPI_DESCRIPTOR_INTERRUPT);
> +
> +	/* Byte 1-2: Length (filled in later) */
> +	desc_length = acpi_device_write_zero_len(ctx);
> +
> +	/*
> +	 * Byte 3: Flags
> +	 *  [7:5]: Reserved
> +	 *    [4]: Wake     (0=NO_WAKE   1=WAKE)
> +	 *    [3]: Sharing  (0=EXCLUSIVE 1=SHARED)
> +	 *    [2]: Polarity (0=HIGH      1=LOW)
> +	 *    [1]: Mode     (0=LEVEL     1=EDGE)
> +	 *    [0]: Resource (0=PRODUCER  1=CONSUMER)
> +	 */
> +	flags = 1 << 0; /* ResourceConsumer */

Nit: BIT(0), etc. ?

> +	if (irq->mode == ACPI_IRQ_EDGE_TRIGGERED)
> +		flags |= 1 << 1;
> +	if (irq->polarity == ACPI_IRQ_ACTIVE_LOW)
> +		flags |= 1 << 2;
> +	if (irq->shared == ACPI_IRQ_SHARED)
> +		flags |= 1 << 3;
> +	if (irq->wake == ACPI_IRQ_WAKE)
> +		flags |= 1 << 4;
> +	acpigen_emit_byte(ctx, flags);
> +
> +	/* Byte 4: Interrupt Table Entry Count */
> +	acpigen_emit_byte(ctx, 1);
> +
> +	/* Byte 5-8: Interrupt Number */
> +	acpigen_emit_dword(ctx, irq->pin);
> +
> +	/* Fill in Descriptor Length (account for len word) */
> +	acpi_device_fill_len(ctx, desc_length);
> +
> +	return 0;
> +}
> +

[snip]

Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v2 12/35] acpi: Support generation of SPI descriptor
  2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
                   ` (67 preceding siblings ...)
  2020-06-10  8:06 ` [PATCH v2 06/35] acpi: Support generation of interrupt descriptor Wolfgang Wallner
@ 2020-06-10  8:40 ` Wolfgang Wallner
  68 siblings, 0 replies; 84+ messages in thread
From: Wolfgang Wallner @ 2020-06-10  8:40 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> Betreff: [PATCH v2 12/35] acpi: Support generation of SPI descriptor
> 
> Add a function to write a SPI descriptor to the generated ACPI code.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2:
> - Fix memset of SPI descriptor
> 
> Changes in v1: None
> 
>  drivers/spi/sandbox_spi.c  |  11 ++++
>  include/acpi/acpi_device.h |  36 +++++++++++
>  include/spi.h              |   4 +-
>  lib/acpi/acpi_device.c     | 121 +++++++++++++++++++++++++++++++++++++
>  test/dm/acpigen.c          |  36 +++++++++++
>  5 files changed, 206 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/spi/sandbox_spi.c b/drivers/spi/sandbox_spi.c
> index b0a46c8868..4264acc953 100644
> --- a/drivers/spi/sandbox_spi.c
> +++ b/drivers/spi/sandbox_spi.c
> @@ -21,6 +21,7 @@
>  #include <linux/errno.h>
>  #include <asm/spi.h>
>  #include <asm/state.h>
> +#include <dm/acpi.h>
>  #include <dm/device-internal.h>
>  
>  #ifndef CONFIG_SPI_IDLE_VAL
> @@ -133,6 +134,15 @@ 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,
> @@ -151,4 +161,5 @@ U_BOOT_DRIVER(spi_sandbox) = {
>  	.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 cf1ac695a7..d43ab4ba36 100644
> --- a/include/acpi/acpi_device.h
> +++ b/include/acpi/acpi_device.h
> @@ -10,6 +10,7 @@
>  #define __ACPI_DEVICE_H
>  
>  #include <i2c.h>
> +#include <spi.h>
>  #include <linux/bitops.h>
>  
>  struct acpi_ctx;
> @@ -207,6 +208,29 @@ struct acpi_i2c {
>  	const char *resource;
>  };
>  
> +/**
> + * struct acpi_spi - representation of an ACPI SPI device
> + *
> + * @device_select: Chip select used by this device (typically 0)
> + * @device_select_polarity: Polarity for the device
> + * @wire_mode: Number of wires used for SPI
> + * @speed: Bus speed in Hz
> + * @data_bit_length: Word length for SPI (typically 8)
> + * @clock_phase: Clock phase to capture data
> + * @clock_polarity: Bus polarity
> + * @resource: Resource name for the SPI controller
> + */
> +struct acpi_spi {
> +	u16 device_select;
> +	enum spi_polarity device_select_polarity;
> +	enum spi_wire_mode wire_mode;
> +	unsigned int speed;
> +	u8 data_bit_length;
> +	enum spi_clock_phase clock_phase;
> +	enum spi_polarity clock_polarity;
> +	const char *resource;
> +};
> +
>  /**
>   * acpi_device_path() - Get the full path to an ACPI device
>   *
> @@ -306,4 +330,16 @@ int acpi_device_write_interrupt_or_gpio(struct acpi_ctx *ctx,
>   */
>  int acpi_device_write_i2c_dev(struct acpi_ctx *ctx, const struct udevice *dev);
>  
> +/**
> + * acpi_device_write_spi_dev() - Write a SPI device to ACPI

Nit: Should it be "an" SPI device instead of "a" SPI device?
(at least as I pronounce it, the abbreviation starts with a vowel)

> + *
> + * This writes a serial bus descriptor for the SPI device so that ACPI can use
> + * it
> + *
> + * @ctx: ACPI context pointer
> + * @dev: SPI device to write
> + * @return 0 if OK, -ve on error
> + */
> +int acpi_device_write_spi_dev(struct acpi_ctx *ctx, const struct udevice *dev);
> +
>  #endif
> diff --git a/include/spi.h b/include/spi.h
> index 5cc6d6e008..f34533f54e 100644
> --- a/include/spi.h
> +++ b/include/spi.h
> @@ -13,8 +13,8 @@
>  #include <linux/bitops.h>
>  
>  /* SPI mode flags */
> -#define SPI_CPHA	BIT(0)			/* clock phase */
> -#define SPI_CPOL	BIT(1)			/* clock polarity */
> +#define SPI_CPHA	BIT(0)	/* clock phase (1 = SPI_CLOCK_PHASE_SECOND) */
> +#define SPI_CPOL	BIT(1)	/* clock polarity (1 = SPI_POLARITY_HIGH) */

Nit: I assume the comments are now unaligned to stay within 80 characters/line.
According to [1], I think it would be fine to keep them aligned, and trade off
slightly longer line length vs readability.

[1] https://lists.denx.de/pipermail/u-boot/2020-June/414419.html

>  #define SPI_MODE_0	(0|0)			/* (original MicroWire) */
>  #define SPI_MODE_1	(0|SPI_CPHA)
>  #define SPI_MODE_2	(SPI_CPOL|0)
> diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
> index 0136a0bdc9..3d5dc746f8 100644
> --- a/lib/acpi/acpi_device.c
> +++ b/lib/acpi/acpi_device.c
> @@ -484,3 +484,124 @@ int acpi_device_write_i2c_dev(struct acpi_ctx *ctx, const struct udevice *dev)
>  
>  	return 0;
>  }
> +
> +#ifdef CONFIG_SPI
> +/* ACPI 6.1 section 6.4.3.8.2.2 - SpiSerialBus() */
> +void acpi_device_write_spi(struct acpi_ctx *ctx, const struct acpi_spi *spi)

I think this function should be static.

> +{
> +	void *desc_length, *type_length;
> +	u16 flags = 0;
> +
> +	/* Byte 0: Descriptor Type */
> +	acpigen_emit_byte(ctx, ACPI_DESCRIPTOR_SERIAL_BUS);
> +
> +	/* Byte 1+2: Length (filled in later) */
> +	desc_length = acpi_device_write_zero_len(ctx);
> +
> +	/* Byte 3: Revision ID */
> +	acpigen_emit_byte(ctx, ACPI_SPI_SERIAL_BUS_REVISION_ID);
> +
> +	/* Byte 4: Resource Source Index is Reserved */
> +	acpigen_emit_byte(ctx, 0);
> +
> +	/* Byte 5: Serial Bus Type is SPI */
> +	acpigen_emit_byte(ctx, ACPI_SERIAL_BUS_TYPE_SPI);
> +
> +	/*
> +	 * Byte 6: Flags
> +	 *  [7:2]: 0 => Reserved
> +	 *    [1]: 1 => ResourceConsumer
> +	 *    [0]: 0 => ControllerInitiated
> +	 */
> +	acpigen_emit_byte(ctx, 1 << 1);

Nit: BIT(1) ?

> +
> +	/*
> +	 * Byte 7-8: Type Specific Flags
> +	 *   [15:2]: 0 => Reserveda
> +	 *      [1]: 0 => ActiveLow, 1 => ActiveHigh
> +	 *      [0]: 0 => FourWire, 1 => ThreeWire
> +	 */
> +	if (spi->wire_mode == SPI_3_WIRE_MODE)
> +		flags |= 1 << 0;
> +	if (spi->device_select_polarity == SPI_POLARITY_HIGH)
> +		flags |= 1 << 1;
> +	acpigen_emit_word(ctx, flags);
> +
> +	/* Byte 9: Type Specific Revision ID */
> +	acpigen_emit_byte(ctx, ACPI_SPI_TYPE_SPECIFIC_REVISION_ID);
> +
> +	/* Byte 10-11: SPI Type Data Length */
> +	type_length = acpi_device_write_zero_len(ctx);
> +
> +	/* Byte 12-15: Connection Speed */
> +	acpigen_emit_dword(ctx, spi->speed);
> +
> +	/* Byte 16: Data Bit Length */
> +	acpigen_emit_byte(ctx, spi->data_bit_length);
> +
> +	/* Byte 17: Clock Phase */
> +	acpigen_emit_byte(ctx, spi->clock_phase);
> +
> +	/* Byte 18: Clock Polarity */
> +	acpigen_emit_byte(ctx, spi->clock_polarity);
> +
> +	/* Byte 19-20: Device Selection */
> +	acpigen_emit_word(ctx, spi->device_select);
> +
> +	/* Fill in Type Data Length */
> +	acpi_device_fill_len(ctx, type_length);
> +
> +	/* Byte 21+: ResourceSource String */
> +	acpigen_emit_string(ctx, spi->resource);
> +
> +	/* Fill in SPI Descriptor Length */
> +	acpi_device_fill_len(ctx, desc_length);
> +}
> +
> +/**
> + * acpi_device_set_spi() - Set up an ACPI SPI struct from a device
> + *
> + * @dev: SPI device to convert
> + * @spi: Place to put the new structure
> + * @scope: Scope of the SPI device (this is the controller path)

As with the previous patch (about I2C) I would propose to add an additional
comment to state that scope is only referenced.

> + * @return 0 (always)
> + */
> +static int acpi_device_set_spi(const struct udevice *dev, struct acpi_spi *spi,
> +			       const char *scope)
> +{
> +	struct dm_spi_slave_platdata *plat;
> +	struct spi_slave *slave = dev_get_parent_priv(dev);
> +
> +	plat = dev_get_parent_platdata(slave->dev);
> +	memset(spi, '\0', sizeof(*spi));
> +	spi->device_select = plat->cs;
> +	spi->device_select_polarity = SPI_POLARITY_LOW;
> +	spi->wire_mode = SPI_4_WIRE_MODE;
> +	spi->speed = plat->max_hz;
> +	spi->data_bit_length = slave->wordlen;
> +	spi->clock_phase = plat->mode & SPI_CPHA ?
> +		 SPI_CLOCK_PHASE_SECOND : SPI_CLOCK_PHASE_FIRST;
> +	spi->clock_polarity = plat->mode & SPI_CPOL ?
> +		 SPI_POLARITY_HIGH : SPI_POLARITY_LOW;
> +	spi->resource = scope;
> +
> +	return 0;
> +}
> +
> +int acpi_device_write_spi_dev(struct acpi_ctx *ctx, const struct udevice *dev)
> +{
> +	char scope[ACPI_PATH_MAX];
> +	struct acpi_spi spi;
> +	int ret;
> +
> +	ret = acpi_device_scope(dev, scope, sizeof(scope));
> +	if (ret)
> +		return log_msg_ret("scope", ret);
> +	ret = acpi_device_set_spi(dev, &spi, scope);
> +	if (ret)
> +		return log_msg_ret("set", ret);
> +	acpi_device_write_spi(ctx, &spi);
> +
> +	return 0;
> +}
> +#endif /* CONFIG_SPI */
> diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
> index de9996ab35..3d580a23a5 100644
> --- a/test/dm/acpigen.c
> +++ b/test/dm/acpigen.c
> @@ -298,3 +298,39 @@ static int dm_test_acpi_i2c(struct unit_test_state *uts)
>  	return 0;
>  }
>  DM_TEST(dm_test_acpi_i2c, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> +
> +/* Test emitting a SPI descriptor */
> +static int dm_test_acpi_spi(struct unit_test_state *uts)
> +{
> +	struct acpi_ctx *ctx;
> +	struct udevice *dev;
> +	u8 *ptr;
> +
> +	ut_assertok(alloc_context(&ctx));
> +
> +	ptr = acpigen_get_current(ctx);
> +
> +	ut_assertok(uclass_first_device_err(UCLASS_SPI_FLASH, &dev));
> +	ut_assertok(acpi_device_write_spi_dev(ctx, dev));
> +	ut_asserteq(31, acpigen_get_current(ctx) - ptr);
> +	ut_asserteq(ACPI_DESCRIPTOR_SERIAL_BUS, ptr[0]);
> +	ut_asserteq(28, get_unaligned((u16 *)(ptr + 1)));
> +	ut_asserteq(ACPI_SPI_SERIAL_BUS_REVISION_ID, ptr[3]);
> +	ut_asserteq(0, ptr[4]);
> +	ut_asserteq(ACPI_SERIAL_BUS_TYPE_SPI, ptr[5]);
> +	ut_asserteq(2, ptr[6]);
> +	ut_asserteq(0, get_unaligned((u16 *)(ptr + 7)));
> +	ut_asserteq(ACPI_SPI_TYPE_SPECIFIC_REVISION_ID, ptr[9]);
> +	ut_asserteq(9, get_unaligned((u16 *)(ptr + 10)));
> +	ut_asserteq(40000000, get_unaligned((u32 *)(ptr + 12)));
> +	ut_asserteq(8, ptr[16]);
> +	ut_asserteq(0, ptr[17]);
> +	ut_asserteq(0, ptr[18]);
> +	ut_asserteq(0, get_unaligned((u16 *)(ptr + 19)));
> +	ut_asserteq_str("\\_SB.SSPI", (char *)ptr + 21);
> +
> +	free_context(&ctx);
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_acpi_spi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> -- 
> 2.26.2.645.ge9eca65c58-goog
> 

regards, Wolfgang

^ permalink raw reply	[flat|nested] 84+ messages in thread

end of thread, other threads:[~2020-06-10  8:40 UTC | newest]

Thread overview: 84+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-10 20:33 [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Simon Glass
2020-05-10 20:33 ` [PATCH v2 01/35] dm: core: Add an ACPI name for the root node Simon Glass
2020-05-17 14:40   ` Bin Meng
2020-05-10 20:33 ` [PATCH v2 02/35] acpi: Add a function to get a device path and scope Simon Glass
2020-05-17 14:54   ` Bin Meng
2020-05-10 20:33 ` [PATCH v2 03/35] acpi: Add a way to check device status Simon Glass
2020-05-10 20:33 ` [PATCH v2 04/35] irq: Add a method to convert an interrupt to ACPI Simon Glass
2020-05-10 20:33 ` [PATCH v2 05/35] acpi: Support generation of ACPI code Simon Glass
2020-05-10 20:33 ` [PATCH v2 06/35] acpi: Support generation of interrupt descriptor Simon Glass
2020-05-10 20:33 ` [PATCH v2 07/35] gpio: Add a method to convert a GPIO to ACPI Simon Glass
2020-05-10 20:33 ` [PATCH v2 08/35] acpi: Support string output Simon Glass
2020-05-10 20:33 ` [PATCH v2 09/35] acpi: Support generation of GPIO descriptor Simon Glass
2020-05-10 20:33 ` [PATCH v2 10/35] acpi: Support generation of a GPIO/irq for a device Simon Glass
2020-05-10 20:33 ` [PATCH v2 11/35] acpi: Support generation of I2C descriptor Simon Glass
2020-05-10 20:33 ` [PATCH v2 12/35] acpi: Support generation of SPI descriptor Simon Glass
2020-05-10 20:33 ` [PATCH v2 13/35] acpigen: Support writing a length Simon Glass
2020-05-10 20:33 ` [PATCH v2 14/35] acpigen: Support writing a package Simon Glass
2020-05-10 20:33 ` [PATCH v2 15/35] acpi: Support writing an integer Simon Glass
2020-05-10 20:33 ` [PATCH v2 16/35] acpi: Support writing a string Simon Glass
2020-05-10 20:33 ` [PATCH v2 17/35] acpi: Support writing a name Simon Glass
2020-05-10 20:33 ` [PATCH v2 18/35] acpi: Support writing a UUID Simon Glass
2020-05-10 20:33 ` [PATCH v2 19/35] acpi: Support writing Device Properties objects via _DSD Simon Glass
2020-05-10 20:33 ` [PATCH v2 20/35] acpi: Support writing a GPIO Simon Glass
2020-05-10 20:33 ` [PATCH v2 21/35] acpi: Support copying properties from device tree to ACPI Simon Glass
2020-05-10 20:33 ` [PATCH v2 22/35] acpi: Add support for various misc ACPI opcodes Simon Glass
2020-05-10 20:33 ` [PATCH v2 23/35] acpi: Add support for writing a Power Resource Simon Glass
2020-05-10 20:33 ` [PATCH v2 24/35] acpi: Add support for writing a GPIO power sequence Simon Glass
2020-05-10 20:33 ` [PATCH v2 25/35] acpi: Add support for a generic " Simon Glass
2020-05-10 20:34 ` [PATCH v2 26/35] acpi: Add support for SSDT generation Simon Glass
2020-05-10 20:34 ` [PATCH v2 27/35] x86: acpi: Move MADT down a bit Simon Glass
2020-05-10 20:34 ` [PATCH v2 28/35] acpi: Record the items added to SSDT Simon Glass
2020-05-10 20:34 ` [PATCH v2 29/35] acpi: Support ordering SSDT data by device Simon Glass
2020-05-10 20:34 ` [PATCH v2 30/35] x86: Allow devices to write an SSDT Simon Glass
2020-05-10 20:34 ` [PATCH v2 31/35] acpi: Add support for DSDT generation Simon Glass
2020-05-10 20:34 ` [PATCH v2 32/35] x86: Allow devices to write to DSDT Simon Glass
2020-05-10 20:34 ` [PATCH v2 33/35] pci: Avoid a crash in device_is_on_pci_bus() Simon Glass
2020-05-10 20:34 ` [PATCH v2 34/35] dm: acpi: Enhance acpi_get_name() Simon Glass
2020-05-10 20:34 ` [PATCH v2 35/35] acpi: Add an acpi split command Simon Glass
2020-05-12  2:13 ` [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Bin Meng
2020-05-12 11:55 ` Antwort: " Wolfgang Wallner
2020-05-12 12:32   ` Andy Shevchenko
2020-05-12 23:22     ` Simon Glass
2020-05-13  9:55       ` Andy Shevchenko
2020-05-14 16:02         ` Simon Glass
2020-05-14 16:38           ` Andy Shevchenko
2020-05-13 12:18 ` Antwort: [PATCH v2 03/35] acpi: Add a way to check device status Wolfgang Wallner
2020-05-13 13:01 ` Antwort: [PATCH v2 04/35] irq: Add a method to convert an interrupt to ACPI Wolfgang Wallner
2020-05-14 16:02   ` Simon Glass
2020-05-18  7:47   ` Antwort: " Wolfgang Wallner
2020-05-14  8:32 ` Antwort: [PATCH v2 05/35] acpi: Support generation of ACPI code Wolfgang Wallner
2020-06-09 21:14   ` Simon Glass
2020-06-10  7:33   ` Wolfgang Wallner
2020-06-10  7:39   ` Wolfgang Wallner
2020-05-19  8:14 ` Antwort: [PATCH v2 08/35] acpi: Support string output Wolfgang Wallner
2020-05-19  8:56 ` [PATCH v2 09/35] acpi: Support generation of GPIO descriptor Wolfgang Wallner
2020-05-19  9:32 ` Antwort: [PATCH v2 10/35] acpi: Support generation of a GPIO/irq for a device Wolfgang Wallner
2020-05-19 11:58 ` Antwort: [PATCH v2 11/35] acpi: Support generation of I2C descriptor Wolfgang Wallner
2020-06-09 21:14   ` Simon Glass
2020-05-19 13:14 ` Antwort: [PATCH v2 13/35] acpigen: Support writing a length Wolfgang Wallner
2020-05-27 13:04 ` [PATCH v2 14/35] acpigen: Support writing a package Wolfgang Wallner
2020-05-28  9:45 ` [PATCH v2 15/35] acpi: Support writing an integer Wolfgang Wallner
2020-05-28  9:45 ` Antwort: [PATCH v2 16/35] acpi: Support writing a string Wolfgang Wallner
2020-05-28  9:46 ` [PATCH v2 17/35] acpi: Support writing a name Wolfgang Wallner
2020-05-28  9:57 ` [PATCH v2 18/35] acpi: Support writing a UUID Wolfgang Wallner
2020-05-28 13:36 ` [PATCH v2 19/35] acpi: Support writing Device Properties objects via _DSD Wolfgang Wallner
2020-06-03 11:49 ` Antwort: [PATCH v2 20/35] acpi: Support writing a GPIO Wolfgang Wallner
2020-06-03 12:00 ` [PATCH v2 21/35] acpi: Support copying properties from device tree to ACPI Wolfgang Wallner
2020-06-03 13:04 ` [PATCH v2 22/35] acpi: Add support for various misc ACPI opcodes Wolfgang Wallner
2020-06-04  7:39 ` Antwort: [PATCH v2 23/35] acpi: Add support for writing a Power Resource Wolfgang Wallner
2020-06-04  8:50 ` [PATCH v2 24/35] acpi: Add support for writing a GPIO power sequence Wolfgang Wallner
2020-06-04  9:12 ` [PATCH v2 25/35] acpi: Add support for a generic " Wolfgang Wallner
2020-06-04  9:20 ` [PATCH v2 27/35] x86: acpi: Move MADT down a bit Wolfgang Wallner
2020-06-04 11:52 ` [PATCH v2 29/35] acpi: Support ordering SSDT data by device Wolfgang Wallner
2020-06-04 11:54 ` [PATCH v2 28/35] acpi: Record the items added to SSDT Wolfgang Wallner
2020-06-04 12:20 ` [PATCH v2 30/35] x86: Allow devices to write an SSDT Wolfgang Wallner
2020-06-04 12:22 ` [PATCH v2 33/35] pci: Avoid a crash in device_is_on_pci_bus() Wolfgang Wallner
2020-06-04 12:26 ` [PATCH v2 31/35] acpi: Add support for DSDT generation Wolfgang Wallner
2020-06-04 12:55 ` [PATCH v2 32/35] x86: Allow devices to write to DSDT Wolfgang Wallner
2020-06-04 13:04 ` [PATCH v2 35/35] acpi: Add an acpi split command Wolfgang Wallner
2020-06-04 13:17 ` [PATCH v2 34/35] dm: acpi: Enhance acpi_get_name() Wolfgang Wallner
2020-06-04 13:27 ` [PATCH v2 00/35] dm: Add programmatic generation of ACPI tables (part B) Wolfgang Wallner
2020-06-04 15:59   ` Simon Glass
2020-06-10  8:06 ` [PATCH v2 06/35] acpi: Support generation of interrupt descriptor Wolfgang Wallner
2020-06-10  8:40 ` [PATCH v2 12/35] acpi: Support generation of SPI descriptor Wolfgang Wallner

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.