All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A)
@ 2020-03-09  3:44 Simon Glass
  2020-03-09  3:44 ` [PATCH v2 01/39] cpu: Support querying the address width Simon Glass
                   ` (61 more replies)
  0 siblings, 62 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

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

The first 20 or so patches here have been reviewed and the changes here
incorporate those comments.

Changes in v2:
- Don't bracket the definitions with DM_SPI
- Drop the other comment change since it is already applied
- Drop the Chrome OS pieces
- Rename the 'coreboot' console to 'U-Boot'
- Move LOGC_ACPI definition to this patch
- Fix definition of HID
- Infer hid-over-i2c CID value
- Add the hid-over-i2c binding document
- Add in the acpi_table.h header file to this patch
- Move the sandbox acpi_table.h header file to an earlier patch
- Use #defines for MADT and MCFG version numbers
- Drop two unnecessary __packed
- Move __packed to after struct
- Drop definition of ACPI_TABLE_CREATOR
- Make _acpi_write_dev_tables() static and switch argument order
- Generalise the ACPI function recursion with acpi_recurse_method()
- Drop CID value from i2c struct
- Switch parameter order of _acpi_fill_ssdt() and make it static
- Generalise the ACPI function recursion with acpi_recurse_method()
- Generalise the ACPI function recursion with acpi_recurse_method()
- Move ACPI_TABLE_CREATOR to here
- Generalise the ACPI function recursion with acpi_recurse_method()

Simon Glass (39):
  cpu: Support querying the address width
  spi: Add SPI mode enums
  tpm: cr50: Release locality on exit
  tpm: cr50: Add a comment for cr50_priv
  tpm: cr50: Use the correct GPIO binding
  tpm: Don't cleanup unless an error happens
  dm: pci: Allow disabling auto-config for a device
  x86: Correct wording of coreboot source code
  x86: apl: Move p2sb ofdata reading to the correct method
  pci: Adjust dm_pci_read_bar32() to return errors correctly
  x86: apl: Add Global NVS table header
  dm: core: Add basic ACPI support
  acpi: Add a binding for ACPI settings in the device tree
  acpi: Add a simple sandbox test
  x86: Move acpi_table header to main include/ directory
  acpi: Add an __ACPI__ preprocessor symbol
  acpi: Add a central location for table version numbers
  acpi: Add support for DMAR
  acpi: Move acpi_fill_header() to generic code
  acpi: Add a method to write tables for a device
  acpi: Convert part of acpi_table to use acpi_ctx
  x86: Allow devices to write ACPI tables
  acpi: Drop code for missing XSDT from acpi_write_rsdp()
  acpi: Move acpi_add_table() to generic code
  acpi: Put table-setup code in its own function
  acpi: Move the xsdt pointer to acpi_ctx
  acpi: Add an acpi command
  acpi: Add some tables required by the generation code
  acpi: Add generation code for devices
  acpi: Add functions to generate ACPI code
  gpio: Add a method to convert a GPIO to ACPI
  irq: Add a method to convert an interrupt to ACPI
  acpi: Add support for SSDT generation
  x86: acpi: Move MADT up 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

 arch/sandbox/dts/test.dts                     |   13 +
 arch/sandbox/include/asm/acpi_table.h         |    9 +
 arch/sandbox/include/asm/global_data.h        |    1 +
 arch/x86/cpu/baytrail/acpi.c                  |    2 +-
 arch/x86/cpu/coreboot/timestamp.c             |    4 +-
 arch/x86/cpu/cpu.c                            |    2 +-
 arch/x86/cpu/intel_common/p2sb.c              |   35 +-
 arch/x86/cpu/quark/acpi.c                     |    2 +-
 arch/x86/cpu/tangier/acpi.c                   |    2 +-
 arch/x86/dts/chromebook_coral.dts             |    2 +-
 arch/x86/include/asm/acpi_table.h             |  376 ----
 .../include/asm/arch-apollolake/global_nvs.h  |   37 +
 .../x86/include/asm/arch-coreboot/timestamp.h |    4 +-
 arch/x86/include/asm/global_data.h            |    1 +
 arch/x86/include/asm/intel_pinctrl_defs.h     |    2 -
 arch/x86/lib/acpi.c                           |    2 +-
 arch/x86/lib/acpi_s3.c                        |    2 +-
 arch/x86/lib/acpi_table.c                     |  312 ++-
 arch/x86/lib/tables.c                         |    2 +-
 arch/x86/lib/zimage.c                         |    2 +-
 cmd/Kconfig                                   |   14 +
 cmd/Makefile                                  |    1 +
 cmd/acpi.c                                    |  179 ++
 doc/device-tree-bindings/chosen.txt           |    9 +
 doc/device-tree-bindings/device.txt           |   36 +
 .../gpio/intel,apl-gpio.txt                   |    2 +-
 .../input/hid-over-i2c.txt                    |   44 +
 .../interrupt-controller/intel,acpi-gpe.txt   |    2 +-
 doc/device-tree-bindings/pci/x86-pci.txt      |   24 +
 drivers/core/Kconfig                          |    9 +
 drivers/core/Makefile                         |    1 +
 drivers/core/acpi.c                           |  267 +++
 drivers/cpu/cpu_sandbox.c                     |    1 +
 drivers/gpio/gpio-uclass.c                    |   21 +
 drivers/misc/irq-uclass.c                     |   18 +-
 drivers/pci/pci-uclass.c                      |   11 +-
 drivers/tpm/cr50_i2c.c                        |   24 +-
 drivers/tpm/tpm-uclass.c                      |   13 +-
 include/acpi_device.h                         |  744 ++++++++
 include/acpi_table.h                          |  632 +++++++
 include/acpigen.h                             |  482 +++++
 include/asm-generic/gpio.h                    |   27 +
 include/cpu.h                                 |    2 +
 include/dm/acpi.h                             |  167 ++
 include/dm/device.h                           |    5 +
 include/dm/uclass-id.h                        |    1 +
 include/irq.h                                 |   43 +
 include/log.h                                 |    2 +
 include/spi.h                                 |   33 +
 lib/Makefile                                  |    1 +
 lib/acpi/Makefile                             |    6 +
 lib/acpi/acpi_device.c                        | 1204 ++++++++++++
 lib/acpi/acpi_table.c                         |  259 +++
 lib/acpi/acpigen.c                            | 1683 +++++++++++++++++
 lib/efi_loader/efi_acpi.c                     |    2 +-
 scripts/Makefile.lib                          |    4 +-
 test/dm/Makefile                              |    1 +
 test/dm/acpi.c                                |  399 ++++
 test/dm/cpu.c                                 |    1 +
 59 files changed, 6555 insertions(+), 631 deletions(-)
 create mode 100644 arch/sandbox/include/asm/acpi_table.h
 create mode 100644 arch/x86/include/asm/arch-apollolake/global_nvs.h
 create mode 100644 cmd/acpi.c
 create mode 100644 doc/device-tree-bindings/device.txt
 create mode 100644 doc/device-tree-bindings/input/hid-over-i2c.txt
 create mode 100644 drivers/core/acpi.c
 create mode 100644 include/acpi_device.h
 create mode 100644 include/acpi_table.h
 create mode 100644 include/acpigen.h
 create mode 100644 include/dm/acpi.h
 create mode 100644 lib/acpi/Makefile
 create mode 100644 lib/acpi/acpi_device.c
 create mode 100644 lib/acpi/acpi_table.c
 create mode 100644 lib/acpi/acpigen.c
 create mode 100644 test/dm/acpi.c

-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 01/39] cpu: Support querying the address width
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 02/39] spi: Add SPI mode enums Simon Glass
                   ` (60 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

Different CPUs may support different address widths, meaning the amount of
memory they can address. Add a property for this to the cpu_info struct.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---

Changes in v2: None

 drivers/cpu/cpu_sandbox.c | 1 +
 include/cpu.h             | 2 ++
 test/dm/cpu.c             | 1 +
 3 files changed, 4 insertions(+)

diff --git a/drivers/cpu/cpu_sandbox.c b/drivers/cpu/cpu_sandbox.c
index ff87e8adca..05b384f6a4 100644
--- a/drivers/cpu/cpu_sandbox.c
+++ b/drivers/cpu/cpu_sandbox.c
@@ -19,6 +19,7 @@ int cpu_sandbox_get_info(struct udevice *dev, struct cpu_info *info)
 {
 	info->cpu_freq = 42 * 42 * 42 * 42 * 42;
 	info->features = 0x42424242;
+	info->address_width = IS_ENABLED(CONFIG_PHYS_64BIT) ? 64 : 32;
 
 	return 0;
 }
diff --git a/include/cpu.h b/include/cpu.h
index 28dd48feb8..6b1b6b37b3 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -44,10 +44,12 @@ enum {
  *
  * @cpu_freq:	Current CPU frequency in Hz
  * @features:	Flags for supported CPU features
+ * @address_width:	Width of the CPU address space in bits (e.g. 32)
  */
 struct cpu_info {
 	ulong cpu_freq;
 	ulong features;
+	uint address_width;
 };
 
 struct cpu_ops {
diff --git a/test/dm/cpu.c b/test/dm/cpu.c
index f5f1caef71..e6dc576ea3 100644
--- a/test/dm/cpu.c
+++ b/test/dm/cpu.c
@@ -33,6 +33,7 @@ static int dm_test_cpu(struct unit_test_state *uts)
 	ut_assertok(cpu_get_info(dev, &info));
 	ut_asserteq(info.cpu_freq, 42 * 42 * 42 * 42 * 42);
 	ut_asserteq(info.features, 0x42424242);
+	ut_asserteq(info.address_width, 32);
 
 	ut_asserteq(cpu_get_count(dev), 42);
 
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 02/39] spi: Add SPI mode enums
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
  2020-03-09  3:44 ` [PATCH v2 01/39] cpu: Support querying the address width Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  7:41   ` Andy Shevchenko
  2020-03-09  3:44 ` [PATCH v2 03/39] tpm: cr50: Release locality on exit Simon Glass
                   ` (59 subsequent siblings)
  61 siblings, 1 reply; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

With ACPI we need to describe the settings of the SPI bus. Add enums to
handle this.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---

Changes in v2:
- Don't bracket the definitions with DM_SPI

 include/spi.h | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/include/spi.h b/include/spi.h
index 852f570eaa..2092940f4c 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -66,6 +66,39 @@ struct dm_spi_slave_platdata {
 
 #endif /* CONFIG_DM_SPI */
 
+/**
+ * enum spi_clock_phase - indicates  the clock phase to use for SPI (CPHA)
+ *
+ * @SPI_CLOCK_PHASE_FIRST: Data sampled on the first phase
+ * @SPI_CLOCK_PHASE_SECOND: Data sampled on the second phase
+ */
+enum spi_clock_phase {
+	SPI_CLOCK_PHASE_FIRST,
+	SPI_CLOCK_PHASE_SECOND
+};
+
+/**
+ * enum spi_wire_mode - indicates the number of wires used for SPI
+ *
+ * @SPI_4_WIRE_MODE: Normal bidirectional mode with MOSI and MISO
+ * @SPI_3_WIRE_MODE: Unidirectional version with a single data line SISO
+ */
+enum spi_wire_mode {
+	SPI_4_WIRE_MODE,
+	SPI_3_WIRE_MODE
+};
+
+/**
+ * enum spi_polarity - indicates the polarity of the SPI bus (CPOL)
+ *
+ * @SPI_POLARITY_LOW: Clock is low in idle state
+ * @SPI_POLARITY_HIGH: Clock is high in idle state
+ */
+enum spi_polarity {
+	SPI_POLARITY_LOW,
+	SPI_POLARITY_HIGH
+};
+
 /**
  * struct spi_slave - Representation of a SPI slave
  *
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 03/39] tpm: cr50: Release locality on exit
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
  2020-03-09  3:44 ` [PATCH v2 01/39] cpu: Support querying the address width Simon Glass
  2020-03-09  3:44 ` [PATCH v2 02/39] spi: Add SPI mode enums Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 04/39] tpm: cr50: Add a comment for cr50_priv Simon Glass
                   ` (58 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

At present the cr50 driver claims the locality and does not release it for
Linux. This causes problems. Fix this by tracking what is claimed, and
adding a 'remove' method.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---

Changes in v2: None

 drivers/tpm/cr50_i2c.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c
index b904a7d426..b30f55b40d 100644
--- a/drivers/tpm/cr50_i2c.c
+++ b/drivers/tpm/cr50_i2c.c
@@ -206,7 +206,7 @@ static int release_locality(struct udevice *dev, int force)
 		cr50_i2c_write(dev, addr, &buf, 1);
 	}
 
-	priv->locality = 0;
+	priv->locality = -1;
 
 	return 0;
 }
@@ -499,6 +499,7 @@ static int process_reset(struct udevice *dev)
 static int claim_locality(struct udevice *dev, int loc)
 {
 	const u8 mask = TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY;
+	struct cr50_priv *priv = dev_get_priv(dev);
 	u8 access;
 	int ret;
 
@@ -525,6 +526,7 @@ static int claim_locality(struct udevice *dev, int loc)
 		return -EPERM;
 	}
 	log_info("Claimed locality %d\n", loc);
+	priv->locality = loc;
 
 	return 0;
 }
@@ -559,7 +561,11 @@ static int cr50_i2c_open(struct udevice *dev)
 
 static int cr50_i2c_cleanup(struct udevice *dev)
 {
-	release_locality(dev, 1);
+	struct cr50_priv *priv = dev_get_priv(dev);
+
+	printf("%s: cleanup %d\n", __func__, priv->locality);
+	if (priv->locality != -1)
+		release_locality(dev, 1);
 
 	return 0;
 }
@@ -631,6 +637,7 @@ static int cr50_i2c_probe(struct udevice *dev)
 		return log_msg_ret("vendor-id", -EXDEV);
 	}
 	priv->vendor = vendor;
+	priv->locality = -1;
 
 	return 0;
 }
@@ -655,5 +662,7 @@ U_BOOT_DRIVER(cr50_i2c) = {
 	.ops    = &cr50_i2c_ops,
 	.ofdata_to_platdata	= cr50_i2c_ofdata_to_platdata,
 	.probe	= cr50_i2c_probe,
+	.remove	= cr50_i2c_cleanup,
 	.priv_auto_alloc_size = sizeof(struct cr50_priv),
+	.flags		= DM_FLAG_OS_PREPARE,
 };
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 04/39] tpm: cr50: Add a comment for cr50_priv
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (2 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 03/39] tpm: cr50: Release locality on exit Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 05/39] tpm: cr50: Use the correct GPIO binding Simon Glass
                   ` (57 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

Add a comment for the private structure

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---

Changes in v2:
- Drop the other comment change since it is already applied

 drivers/tpm/cr50_i2c.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c
index b30f55b40d..c1d2d2fa38 100644
--- a/drivers/tpm/cr50_i2c.c
+++ b/drivers/tpm/cr50_i2c.c
@@ -34,6 +34,15 @@ enum {
 	CR50_MAX_BUF_SIZE = 63,
 };
 
+/**
+ * struct cr50_priv - Private driver data
+ *
+ * @ready_gpio: GPIO to use to check if the TPM is ready
+ * @irq: IRQ to use check if the TPM is ready (has priority over @ready_gpio)
+ * @locality: Currenttly claimed locality (-1 if none)
+ * @vendor: vendor: Vendor ID for TPM
+ * @use_irq: true to use @irq, false to use @ready if available
+ */
 struct cr50_priv {
 	struct gpio_desc ready_gpio;
 	struct irq irq;
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 05/39] tpm: cr50: Use the correct GPIO binding
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (3 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 04/39] tpm: cr50: Add a comment for cr50_priv Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 06/39] tpm: Don't cleanup unless an error happens Simon Glass
                   ` (56 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

This device should use ready-gpios rather than ready-gpio. Fix it.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---

Changes in v2: None

 arch/x86/dts/chromebook_coral.dts                               | 2 +-
 doc/device-tree-bindings/gpio/intel,apl-gpio.txt                | 2 +-
 .../interrupt-controller/intel,acpi-gpe.txt                     | 2 +-
 drivers/tpm/cr50_i2c.c                                          | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/x86/dts/chromebook_coral.dts b/arch/x86/dts/chromebook_coral.dts
index af52e11c89..d48ef3573e 100644
--- a/arch/x86/dts/chromebook_coral.dts
+++ b/arch/x86/dts/chromebook_coral.dts
@@ -292,7 +292,7 @@
 				reg = <0x50>;
 				compatible = "google,cr50";
 				u-boot,i2c-offset-len = <0>;
-				ready-gpio = <&gpio_n 28 GPIO_ACTIVE_LOW>;
+				ready-gpios = <&gpio_n 28 GPIO_ACTIVE_LOW>;
 				interrupts-extended = <&acpi_gpe 0x3c 0>;
 			};
 		};
diff --git a/doc/device-tree-bindings/gpio/intel,apl-gpio.txt b/doc/device-tree-bindings/gpio/intel,apl-gpio.txt
index cf0659b70e..8422ff63ab 100644
--- a/doc/device-tree-bindings/gpio/intel,apl-gpio.txt
+++ b/doc/device-tree-bindings/gpio/intel,apl-gpio.txt
@@ -47,7 +47,7 @@ Example:
 			reg = <0x50>;
 			compatible = "google,cr50";
 			u-boot,i2c-offset-len = <0>;
-			ready-gpio = <&gpio_n GPIO_28 GPIO_ACTIVE_LOW>;
+			ready-gpios = <&gpio_n GPIO_28 GPIO_ACTIVE_LOW>;
 		};
 	};
 
diff --git a/doc/device-tree-bindings/interrupt-controller/intel,acpi-gpe.txt b/doc/device-tree-bindings/interrupt-controller/intel,acpi-gpe.txt
index d9252bf29f..2fe02d8a22 100644
--- a/doc/device-tree-bindings/interrupt-controller/intel,acpi-gpe.txt
+++ b/doc/device-tree-bindings/interrupt-controller/intel,acpi-gpe.txt
@@ -25,6 +25,6 @@ Example:
 	tpm at 50 {
 		reg = <0x50>;
 		compatible = "google,cr50";
-		ready-gpio = <&gpio_n 0x1c GPIO_ACTIVE_LOW>;
+		ready-gpios = <&gpio_n 0x1c GPIO_ACTIVE_LOW>;
 		interrupts-extended = <&acpi_gpe 0x3c 0>;
 	};
diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c
index c1d2d2fa38..b67051af26 100644
--- a/drivers/tpm/cr50_i2c.c
+++ b/drivers/tpm/cr50_i2c.c
@@ -607,7 +607,7 @@ static int cr50_i2c_ofdata_to_platdata(struct udevice *dev)
 		priv->irq = irq;
 		priv->use_irq = true;
 	} else {
-		ret = gpio_request_by_name(dev, "ready-gpio", 0,
+		ret = gpio_request_by_name(dev, "ready-gpios", 0,
 					   &priv->ready_gpio, GPIOD_IS_IN);
 		if (ret) {
 			log_warning("Cr50 does not have an ready GPIO/interrupt (err=%d)\n",
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 06/39] tpm: Don't cleanup unless an error happens
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (4 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 05/39] tpm: cr50: Use the correct GPIO binding Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 07/39] dm: pci: Allow disabling auto-config for a device Simon Glass
                   ` (55 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

At present the cleanup() method is called on every transfer. It should
only be called on failing transfers. Fix this and tidy up the error
handling a little.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---

Changes in v2: None

 drivers/tpm/tpm-uclass.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/tpm/tpm-uclass.c b/drivers/tpm/tpm-uclass.c
index 1b11c93194..71d5807006 100644
--- a/drivers/tpm/tpm-uclass.c
+++ b/drivers/tpm/tpm-uclass.c
@@ -72,7 +72,7 @@ int tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, size_t send_size,
 	struct tpm_ops *ops = tpm_get_ops(dev);
 	ulong start, stop;
 	uint count, ordinal;
-	int ret, ret2;
+	int ret, ret2 = 0;
 
 	if (ops->xfer)
 		return ops->xfer(dev, sendbuf, send_size, recvbuf, recv_size);
@@ -120,9 +120,16 @@ int tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, size_t send_size,
 		}
 	} while (ret);
 
-	ret2 = ops->cleanup ? ops->cleanup(dev) : 0;
+	if (ret) {
+		if (ops->cleanup) {
+			ret2 = ops->cleanup(dev);
+			if (ret2)
+				return log_msg_ret("cleanup", ret2);
+		}
+		return log_msg_ret("xfer", ret);
+	}
 
-	return ret2 ? ret2 : ret;
+	return 0;
 }
 
 UCLASS_DRIVER(tpm) = {
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 07/39] dm: pci: Allow disabling auto-config for a device
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (5 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 06/39] tpm: Don't cleanup unless an error happens Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  7:43   ` Andy Shevchenko
  2020-03-09  3:44 ` [PATCH v2 08/39] x86: Correct wording of coreboot source code Simon Glass
                   ` (54 subsequent siblings)
  61 siblings, 1 reply; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

Add a means to avoid configuring a device when needed. Add an explanation
of why this is useful to the binding file.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---

Changes in v2: None

 doc/device-tree-bindings/pci/x86-pci.txt | 24 ++++++++++++++++++++++++
 drivers/pci/pci-uclass.c                 |  2 ++
 2 files changed, 26 insertions(+)

diff --git a/doc/device-tree-bindings/pci/x86-pci.txt b/doc/device-tree-bindings/pci/x86-pci.txt
index 3aa5bd9a46..62b29a4e36 100644
--- a/doc/device-tree-bindings/pci/x86-pci.txt
+++ b/doc/device-tree-bindings/pci/x86-pci.txt
@@ -10,6 +10,17 @@ Optional properties:
 	configuration in TPL/SPL to reduce code size and boot time, since these
 	phases only know about a small subset of PCI devices.
 
+For PCI devices the following optional property is available:
+
+- pci,no-autoconfig : Don't automatically configure this PCI device at all.
+	This is used when the device is statically configured and must maintain
+	this same config throughout the boot process. An example is a serial
+	UART being used to debug PCI configuration, since reconfiguring it stops
+	the UART from working until the driver is re-probed, and this can cause
+	output to be lost. This should not generally be used in production code,
+	although it is often harmless.
+
+
 Example:
 
 pci {
@@ -21,4 +32,17 @@ pci {
 		0x42000000 0x0 0xb0000000 0xb0000000 0 0x10000000
 		0x01000000 0x0 0x1000 0x1000 0 0xefff>;
 	u-boot,skip-auto-config-until-reloc;
+
+
+	serial: serial at 18,2 {
+		reg = <0x0200c210 0 0 0 0>;
+		u-boot,dm-pre-reloc;
+		compatible = "intel,apl-ns16550";
+		early-regs = <0xde000000 0x20>;
+		reg-shift = <2>;
+		clock-frequency = <1843200>;
+		current-speed = <115200>;
+		acpi,name = "URT3";
+		pci,no-autoconfig;
+	};
 };
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index 94733662b1..213381da6b 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -536,6 +536,8 @@ int pci_auto_config_devices(struct udevice *bus)
 		int ret;
 
 		debug("%s: device %s\n", __func__, dev->name);
+		if (dev_read_bool(dev, "pci,no-autoconfig"))
+			continue;
 		ret = dm_pciauto_config_device(dev);
 		if (ret < 0)
 			return ret;
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 08/39] x86: Correct wording of coreboot source code
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (6 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 07/39] dm: pci: Allow disabling auto-config for a device Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  7:44   ` Andy Shevchenko
  2020-03-09  3:44 ` [PATCH v2 09/39] x86: apl: Move p2sb ofdata reading to the correct method Simon Glass
                   ` (53 subsequent siblings)
  61 siblings, 1 reply; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

Some files are taken or modified from coreboot, but the files are
no-longer part of the coreboot project. Fix the wording in a few places.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---

Changes in v2: None

 arch/x86/cpu/coreboot/timestamp.c              | 4 ++--
 arch/x86/include/asm/arch-coreboot/timestamp.h | 4 ++--
 arch/x86/include/asm/intel_pinctrl_defs.h      | 2 --
 3 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/arch/x86/cpu/coreboot/timestamp.c b/arch/x86/cpu/coreboot/timestamp.c
index e698200d70..e8ccaf2212 100644
--- a/arch/x86/cpu/coreboot/timestamp.c
+++ b/arch/x86/cpu/coreboot/timestamp.c
@@ -1,8 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * This file is part of the coreboot project.
- *
  * Copyright (C) 2011 The ChromiumOS Authors.  All rights reserved.
+ *
+ * Modified from the coreboot version
  */
 
 #include <common.h>
diff --git a/arch/x86/include/asm/arch-coreboot/timestamp.h b/arch/x86/include/asm/arch-coreboot/timestamp.h
index 9320afba56..85d42c02c4 100644
--- a/arch/x86/include/asm/arch-coreboot/timestamp.h
+++ b/arch/x86/include/asm/arch-coreboot/timestamp.h
@@ -1,8 +1,8 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * This file is part of the coreboot project.
- *
  * Copyright (C) 2011 The ChromiumOS Authors.  All rights reserved.
+ *
+ * Taken from the coreboot version
  */
 
 #ifndef __COREBOOT_TIMESTAMP_H__
diff --git a/arch/x86/include/asm/intel_pinctrl_defs.h b/arch/x86/include/asm/intel_pinctrl_defs.h
index 6da06bb52b..1ea141f082 100644
--- a/arch/x86/include/asm/intel_pinctrl_defs.h
+++ b/arch/x86/include/asm/intel_pinctrl_defs.h
@@ -1,7 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * This file is part of the coreboot project.
- *
  * Copyright (C) 2015-2016 Intel Corp.
  * Copyright 2019 Google LLC
  *
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 09/39] x86: apl: Move p2sb ofdata reading to the correct method
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (7 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 08/39] x86: Correct wording of coreboot source code Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-10 14:39   ` Andy Shevchenko
  2020-03-09  3:44 ` [PATCH v2 10/39] pci: Adjust dm_pci_read_bar32() to return errors correctly Simon Glass
                   ` (52 subsequent siblings)
  61 siblings, 1 reply; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

With P2SB the initial BAR (base-address register) is set up by TPL and
this is used unchanged right through U-Boot.

At present the reading of this address is split between the ofdata() and
probe() methods. There are a few problems that are unique to the p2sb.
One is that its children need to call pcr_read32(), etc. which needs to
have the p2sb address correct. Also some of its children are pinctrl
devices and pinctrl is used when any device is probed. So p2sb really
needs to get its base address set up in ofdata_to_platdata(), before it is
probed.

Another point is that reading the p2sb BAR will not work if the p2sb is
hidden. The FSP-S seems to hide it, presumably to avoid confusing PCI
enumeration.

Reading ofdata in ofdata_to_platdata() is the correct place anyway, so
this is easy to fix.

Move the code into one place and use the early-regs property in all cases
for simplicity and to avoid needing to probe any PCI devices just to read
the BAR.

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

Changes in v2: None

 arch/x86/cpu/intel_common/p2sb.c | 35 +++++++++++---------------------
 1 file changed, 12 insertions(+), 23 deletions(-)

diff --git a/arch/x86/cpu/intel_common/p2sb.c b/arch/x86/cpu/intel_common/p2sb.c
index d5b4846e0a..4af55786e6 100644
--- a/arch/x86/cpu/intel_common/p2sb.c
+++ b/arch/x86/cpu/intel_common/p2sb.c
@@ -92,46 +92,35 @@ int p2sb_ofdata_to_platdata(struct udevice *dev)
 
 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
 	int ret;
+	u32 base[2];
 
+	ret = dev_read_u32_array(dev, "early-regs", base, ARRAY_SIZE(base));
+	if (ret)
+		return log_msg_ret("Missing/short early-regs", ret);
+	plat->mmio_base = base[0];
+	/* TPL sets up the initial BAR */
 	if (spl_phase() == PHASE_TPL) {
-		u32 base[2];
-
-		/* TPL sets up the initial BAR */
-		ret = dev_read_u32_array(dev, "early-regs", base,
-					 ARRAY_SIZE(base));
-		if (ret)
-			return log_msg_ret("Missing/short early-regs", ret);
-		plat->mmio_base = base[0];
 		plat->bdf = pci_get_devfn(dev);
 		if (plat->bdf < 0)
 			return log_msg_ret("Cannot get p2sb PCI address",
-					   plat->bdf);
+						plat->bdf);
 	}
+	upriv->mmio_base = plat->mmio_base;
 #else
 	plat->mmio_base = plat->dtplat.early_regs[0];
 	plat->bdf = pci_ofplat_get_devfn(plat->dtplat.reg[0]);
-#endif
 	upriv->mmio_base = plat->mmio_base;
-	debug("p2sb: mmio_base=%x\n", (uint)plat->mmio_base);
+#endif
 
 	return 0;
 }
 
 static int p2sb_probe(struct udevice *dev)
 {
-	if (spl_phase() == PHASE_TPL) {
+	if (spl_phase() == PHASE_TPL)
 		return p2sb_early_init(dev);
-	} else {
-		struct p2sb_platdata *plat = dev_get_platdata(dev);
-
-		plat->mmio_base = dev_read_addr_pci(dev);
-		/* Don't set BDF since it should not be used */
-		if (!plat->mmio_base || plat->mmio_base == FDT_ADDR_T_NONE)
-			return -EINVAL;
-
-		if (spl_phase() == PHASE_SPL)
-			return p2sb_spl_init(dev);
-	}
+	else if (spl_phase() == PHASE_SPL)
+		return p2sb_spl_init(dev);
 
 	return 0;
 }
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 10/39] pci: Adjust dm_pci_read_bar32() to return errors correctly
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (8 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 09/39] x86: apl: Move p2sb ofdata reading to the correct method Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 11/39] x86: apl: Add Global NVS table header Simon Glass
                   ` (51 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

At present if reading a BAR returns 0xffffffff (e.g. the device is not
present) then the value is masked and a different value is returned.
This makes it harder to detect the problem when debugging.

Update the function to avoid masking in this case.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---

Changes in v2: None

 drivers/pci/pci-uclass.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index 213381da6b..7f46e901fb 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -1213,7 +1213,14 @@ u32 dm_pci_read_bar32(const struct udevice *dev, int barnum)
 
 	bar = PCI_BASE_ADDRESS_0 + barnum * 4;
 	dm_pci_read_config32(dev, bar, &addr);
-	if (addr & PCI_BASE_ADDRESS_SPACE_IO)
+
+	/*
+	 * If we get an invalid address, return this so that comparisons with
+	 * FDT_ADDR_T_NONE work correctly
+	 */
+	if (addr == 0xffffffff)
+		return addr;
+	else if (addr & PCI_BASE_ADDRESS_SPACE_IO)
 		return addr & PCI_BASE_ADDRESS_IO_MASK;
 	else
 		return addr & PCI_BASE_ADDRESS_MEM_MASK;
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 11/39] x86: apl: Add Global NVS table header
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (9 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 10/39] pci: Adjust dm_pci_read_bar32() to return errors correctly Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 12/39] dm: core: Add basic ACPI support Simon Glass
                   ` (50 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

Add the C version of this header. It includes a few Chrome OS bits which
are disabled for a normal build.

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

Changes in v2:
- Drop the Chrome OS pieces
- Rename the 'coreboot' console to 'U-Boot'

 .../include/asm/arch-apollolake/global_nvs.h  | 37 +++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 arch/x86/include/asm/arch-apollolake/global_nvs.h

diff --git a/arch/x86/include/asm/arch-apollolake/global_nvs.h b/arch/x86/include/asm/arch-apollolake/global_nvs.h
new file mode 100644
index 0000000000..344a853fe9
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/global_nvs.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2015-2017 Intel Corp.
+ * (Written by Lance Zhao <lijian.zhao@intel.com> for Intel Corp.)
+ * Copyright Google LLC 2019
+ *
+ * Modified from coreboot apollolake/include/soc/nvs.h
+ */
+
+#ifndef _GLOBAL_NVS_H_
+#define _GLOBAL_NVS_H_
+
+struct __packed acpi_global_nvs {
+	/* Miscellaneous */
+	u8	pcnt; /* 0x00 - Processor Count */
+	u8	ppcm; /* 0x01 - Max PPC State */
+	u8	lids; /* 0x02 - LID State */
+	u8	pwrs; /* 0x03 - AC Power State */
+	u8	dpte; /* 0x04 - Enable DPTF */
+	u32	cbmc; /* 0x05 - 0x08 - U-Boot Console */
+	u64	pm1i; /* 0x09 - 0x10 - System Wake Source - PM1 Index */
+	u64	gpei; /* 0x11 - 0x18 - GPE Wake Source */
+	u64	nhla; /* 0x19 - 0x20 - NHLT Address */
+	u32	nhll; /* 0x21 - 0x24 - NHLT Length */
+	u32	prt0; /* 0x25 - 0x28 - PERST_0 Address */
+	u8	scdp; /* 0x29 - SD_CD GPIO portid */
+	u8	scdo; /* 0x2A - GPIO pad offset relative to the community */
+	u8	uior; /* 0x2B - UART debug controller init on S3 resume */
+	u8	ecps; /* 0x2C - SGX Enabled status */
+	u64	emna; /* 0x2D - 0x34 EPC base address */
+	u64	elng; /* 0x35 - 0x3C EPC Length */
+	u8	unused[195];
+	u8		unused2[0xf00];
+#endif
+};
+
+#endif /* _GLOBAL_NVS_H_ */
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 12/39] dm: core: Add basic ACPI support
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (10 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 11/39] x86: apl: Add Global NVS table header Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-10 14:46   ` Andy Shevchenko
  2020-03-09  3:44 ` [PATCH v2 13/39] acpi: Add a binding for ACPI settings in the device tree Simon Glass
                   ` (49 subsequent siblings)
  61 siblings, 1 reply; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

ACPI (Advanced Configuration and Power Interface) is an Intel standard
for specifying information about a platform. It is a little like device
tree but considerably more complicated and with more backslashes. A
primary difference is that it supports an interpreted bytecode language.

Driver model does not use ACPI for U-Boot's configuration, but it is
convenient to have it support generation of ACPI tables for passing to
Linux, etc.

As a starting point, add an optional set of ACPI operations to each
device. Initially only a single operation is available, to obtain the
ACPI name for the device. More operations are added later.

Enable ACPI for sandbox to ensure build coverage and so that we can add
tests.

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- Move LOGC_ACPI definition to this patch

 drivers/core/Kconfig  |  9 ++++++
 drivers/core/Makefile |  1 +
 drivers/core/acpi.c   | 32 +++++++++++++++++++
 include/dm/acpi.h     | 73 +++++++++++++++++++++++++++++++++++++++++++
 include/dm/device.h   |  5 +++
 include/log.h         |  2 ++
 6 files changed, 122 insertions(+)
 create mode 100644 drivers/core/acpi.c
 create mode 100644 include/dm/acpi.h

diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 3b95b5387b..a3b0399342 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -261,4 +261,13 @@ config DM_DEV_READ_INLINE
 	bool
 	default y if !OF_LIVE
 
+config ACPIGEN
+	bool "Support ACPI table generation in driver model"
+	default y if SANDBOX || GENERATE_ACPI_TABLE
+	help
+	  This option enables generation of ACPI tables using driver-model
+	  devices. It adds a new operation struct to each driver, to support
+	  things like generating device-specific tables and returning the ACPI
+	  name of a device.
+
 endmenu
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index bce7467da1..c707026a3a 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -3,6 +3,7 @@
 # Copyright (c) 2013 Google, Inc
 
 obj-y	+= device.o fdtaddr.o lists.o root.o uclass.o util.o
+obj-$(CONFIG_$(SPL_TPL_)ACPIGEN) += acpi.o
 obj-$(CONFIG_DEVRES) += devres.o
 obj-$(CONFIG_$(SPL_)DM_DEVICE_REMOVE)	+= device-remove.o
 obj-$(CONFIG_$(SPL_)SIMPLE_BUS)	+= simple-bus.o
diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c
new file mode 100644
index 0000000000..45542199f5
--- /dev/null
+++ b/drivers/core/acpi.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Core driver model support for ACPI table generation
+ *
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#define LOG_CATEOGRY	LOGC_ACPI
+
+#include <common.h>
+#include <dm.h>
+#include <dm/acpi.h>
+#include <dm/root.h>
+
+int acpi_return_name(char *out_name, const char *name)
+{
+	strcpy(out_name, name);
+
+	return 0;
+}
+
+int acpi_get_name(const struct udevice *dev, char *out_name)
+{
+	struct acpi_ops *aops;
+
+	aops = device_get_acpi_ops(dev);
+	if (aops && aops->get_name)
+		return aops->get_name(dev, out_name);
+
+	return -ENOSYS;
+}
diff --git a/include/dm/acpi.h b/include/dm/acpi.h
new file mode 100644
index 0000000000..120576adc0
--- /dev/null
+++ b/include/dm/acpi.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Core ACPI (Advanced Configuration and Power Interface) support
+ *
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#ifndef __DM_ACPI_H__
+#define __DM_ACPI_H__
+
+/* Allow operations to be optional for ACPI */
+#if CONFIG_IS_ENABLED(ACPIGEN)
+#define acpi_ops_ptr(_ptr)	.acpi_ops	= _ptr,
+#else
+#define acpi_ops_ptr(_ptr)
+#endif
+
+/* Length of an ACPI name string, excluding nul terminator */
+#define ACPI_NAME_LEN	4
+
+/* Length of an ACPI name string including nul terminator */
+#define ACPI_NAME_MAX	5
+
+/**
+ * struct acpi_ops - ACPI operations supported by driver model
+ */
+struct acpi_ops {
+	/**
+	 * get_name() - Obtain the ACPI name of a device
+	 *
+	 * @dev: Device to check
+	 * @out_name: Place to put the name, must hold at least ACPI_NAME_MAX
+	 *	bytes
+	 * @return 0 if OK, -ENOENT if no name is available, other -ve value on
+	 *	other error
+	 */
+	int (*get_name)(const struct udevice *dev, char *out_name);
+};
+
+#define device_get_acpi_ops(dev)	((dev)->driver->acpi_ops)
+
+/**
+ * acpi_get_name() - Obtain the ACPI name of a device
+ *
+ * @dev: Device to check
+ * @out_name: Place to put the name, must hold at least ACPI_NAME_MAX
+ *	bytes
+ * @return 0 if OK, -ENOENT if no name is available, other -ve value on
+ *	other error
+ */
+int acpi_get_name(const struct udevice *dev, char *out_name);
+
+/**
+ * acpi_return_name() - Copy an ACPI name to an output buffer
+ *
+ * This convenience function can be used to return a literal string as a name
+ * in functions that implement the get_name() method.
+ *
+ * For example:
+ *
+ *	static int mydev_get_name(const struct udevice *dev, char *out_name)
+ *	{
+ *		return acpi_return_name(out_name, "WIBB");
+ *	}
+ *
+ * @out_name: Place to put the name
+ * @name: Name to copy
+ * @return 0 (always)
+ */
+int acpi_return_name(char *out_name, const char *name);
+
+#endif
diff --git a/include/dm/device.h b/include/dm/device.h
index 3517fc1926..9e77a0cd7b 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -245,6 +245,8 @@ struct udevice_id {
  * pointers defined by the driver, to implement driver functions required by
  * the uclass.
  * @flags: driver flags - see DM_FLAGS_...
+ * @acpi_ops: Advanced Configuration and Power Interface (ACPI) operations,
+ * allowing the device to add things to the ACPI tables passed to Linux
  */
 struct driver {
 	char *name;
@@ -264,6 +266,9 @@ struct driver {
 	int per_child_platdata_auto_alloc_size;
 	const void *ops;	/* driver-specific operations */
 	uint32_t flags;
+#if CONFIG_IS_ENABLED(ACPIGEN)
+	struct acpi_ops *acpi_ops;
+#endif
 };
 
 /* Declare a new U-Boot driver */
diff --git a/include/log.h b/include/log.h
index 62fb8afbd0..d706a1a464 100644
--- a/include/log.h
+++ b/include/log.h
@@ -51,6 +51,8 @@ enum log_category_t {
 	LOGC_SANDBOX,	/* Related to the sandbox board */
 	LOGC_BLOBLIST,	/* Bloblist */
 	LOGC_DEVRES,	/* Device resources (devres_... functions) */
+	/* Intel Advanced Configuration and Power Interface (ACPI) */
+	LOGC_ACPI,
 
 	LOGC_COUNT,	/* Number of log categories */
 	LOGC_END,	/* Sentinel value for a list of log categories */
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 13/39] acpi: Add a binding for ACPI settings in the device tree
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (11 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 12/39] dm: core: Add basic ACPI support Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-10 14:50   ` Andy Shevchenko
  2020-03-09  3:44 ` [PATCH v2 14/39] acpi: Add a simple sandbox test Simon Glass
                   ` (48 subsequent siblings)
  61 siblings, 1 reply; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

Devices need to report various identifiers in the ACPI tables. Rather than
hard-coding these in drivers it is typically better to put them in the
device tree.

Add a binding file to describe this.

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

Changes in v2:
- Fix definition of HID
- Infer hid-over-i2c CID value
- Add the hid-over-i2c binding document

 doc/device-tree-bindings/device.txt           | 36 +++++++++++++++
 .../input/hid-over-i2c.txt                    | 44 +++++++++++++++++++
 2 files changed, 80 insertions(+)
 create mode 100644 doc/device-tree-bindings/device.txt
 create mode 100644 doc/device-tree-bindings/input/hid-over-i2c.txt

diff --git a/doc/device-tree-bindings/device.txt b/doc/device-tree-bindings/device.txt
new file mode 100644
index 0000000000..31ec2fa31b
--- /dev/null
+++ b/doc/device-tree-bindings/device.txt
@@ -0,0 +1,36 @@
+Devices
+=======
+
+Device bindings are described by their own individual binding files.
+
+U-Boot provides for some optional properties which are documented here. See
+also hid-over-i2c.txt which describes HID devices.
+
+ - acpi,has-power-resource : (boolean) true if this device has a power resource.
+    This causes a PRIC (ACPI PowerResource) to be written containing the
+    properties provided by this binding, to describe how to handle powering the
+    device up and down using GPIOs
+ - acpi,compatible : compatible string to report
+ - acpi,desc : Contains the string to use as the _DDN (DOS (Disk Operating
+    System) Device Name)
+ - acpi,hid : Contains the string to use as the HID (Hardware ID)
+    identifier _HID
+ - hid-descr-addr : HID register offset (for Human Interface Devices)
+ - acpi,probed : Tells U-Boot to add 'linux,probed' to the ACPI tables so that
+    Linux will not re-init the device
+ - acpi,uid : _UID value for device
+
+
+Example
+-------
+
+synaptics_touchpad: synaptics-touchpad at 2c {
+	compatible = "hid-over-i2c";
+	reg = <0x2c>;
+	acpi,hid = "PNP0C50";
+	acpi,desc = "Synaptics Touchpad";
+	interrupts-extended = <&acpi_gpe GPIO_18_IRQ
+			IRQ_TYPE_EDGE_FALLING>;
+	acpi,probed;
+	hid-descr-addr = <0x20>;
+};
diff --git a/doc/device-tree-bindings/input/hid-over-i2c.txt b/doc/device-tree-bindings/input/hid-over-i2c.txt
new file mode 100644
index 0000000000..c76bafaf98
--- /dev/null
+++ b/doc/device-tree-bindings/input/hid-over-i2c.txt
@@ -0,0 +1,44 @@
+* HID over I2C Device-Tree bindings
+
+HID over I2C provides support for various Human Interface Devices over the
+I2C bus. These devices can be for example touchpads, keyboards, touch screens
+or sensors.
+
+The specification has been written by Microsoft and is currently available here:
+http://msdn.microsoft.com/en-us/library/windows/hardware/hh852380.aspx
+
+If this binding is used, the kernel module i2c-hid will handle the communication
+with the device and the generic hid core layer will handle the protocol.
+
+Required properties:
+- compatible: must be "hid-over-i2c"
+- reg: i2c slave address
+- hid-descr-addr: HID descriptor address
+- interrupts: interrupt line
+
+Additional optional properties:
+
+Some devices may support additional optional properties to help with, e.g.,
+power sequencing. The following properties can be supported by one or more
+device-specific compatible properties, which should be used in addition to the
+"hid-over-i2c" string.
+
+- compatible:
+  * "wacom,w9013" (Wacom W9013 digitizer). Supports:
+    - vdd-supply (3.3V)
+    - vddl-supply (1.8V)
+    - post-power-on-delay-ms
+
+- vdd-supply: phandle of the regulator that provides the supply voltage.
+- post-power-on-delay-ms: time required by the device after enabling its regulators
+  or powering it on, before it is ready for communication.
+
+Example:
+
+	i2c-hid-dev at 2c {
+		compatible = "hid-over-i2c";
+		reg = <0x2c>;
+		hid-descr-addr = <0x0020>;
+		interrupt-parent = <&gpx3>;
+		interrupts = <3 2>;
+	};
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 14/39] acpi: Add a simple sandbox test
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (12 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 13/39] acpi: Add a binding for ACPI settings in the device tree Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 15/39] x86: Move acpi_table header to main include/ directory Simon Glass
                   ` (47 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

Add a sandbox test for the basic ACPI functionality we have so far.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---

Changes in v2:
- Add in the acpi_table.h header file to this patch

 arch/sandbox/dts/test.dts             |  4 ++
 arch/sandbox/include/asm/acpi_table.h |  9 +++++
 include/dm/uclass-id.h                |  1 +
 test/dm/Makefile                      |  1 +
 test/dm/acpi.c                        | 55 +++++++++++++++++++++++++++
 5 files changed, 70 insertions(+)
 create mode 100644 arch/sandbox/include/asm/acpi_table.h
 create mode 100644 test/dm/acpi.c

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 4a277934a7..5fa951ad4b 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -206,6 +206,10 @@
 		compatible = "denx,u-boot-devres-test";
 	};
 
+	acpi-test {
+		compatible = "denx,u-boot-acpi-test";
+	};
+
 	clocks {
 		clk_fixed: clk-fixed {
 			compatible = "fixed-clock";
diff --git a/arch/sandbox/include/asm/acpi_table.h b/arch/sandbox/include/asm/acpi_table.h
new file mode 100644
index 0000000000..921c7f4201
--- /dev/null
+++ b/arch/sandbox/include/asm/acpi_table.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef __ASM_ACPI_TABLE_H__
+#define __ASM_ACPI_TABLE_H__
+
+#endif /* __ASM_ACPI_TABLE_H__ */
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 598f65ea7a..37ada51f9f 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -20,6 +20,7 @@ enum uclass_id {
 	UCLASS_TEST_PROBE,
 	UCLASS_TEST_DUMMY,
 	UCLASS_TEST_DEVRES,
+	UCLASS_TEST_ACPI,
 	UCLASS_SPI_EMUL,	/* sandbox SPI device emulator */
 	UCLASS_I2C_EMUL,	/* sandbox I2C device emulator */
 	UCLASS_I2C_EMUL_PARENT,	/* parent for I2C device emulators */
diff --git a/test/dm/Makefile b/test/dm/Makefile
index dd1ceff86c..3daf8a544e 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_UT_DM) += test-uclass.o
 # subsystem you must add sandbox tests here.
 obj-$(CONFIG_UT_DM) += core.o
 ifneq ($(CONFIG_SANDBOX),)
+obj-$(CONFIG_ACPIGEN) += acpi.o
 obj-$(CONFIG_SOUND) += audio.o
 obj-$(CONFIG_BLK) += blk.o
 obj-$(CONFIG_BOARD) += board.o
diff --git a/test/dm/acpi.c b/test/dm/acpi.c
new file mode 100644
index 0000000000..e3519d4689
--- /dev/null
+++ b/test/dm/acpi.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Tests for ACPI table generation
+ *
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/acpi.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+#define ACPI_TEST_DEV_NAME	"ABCD"
+
+static int testacpi_get_name(const struct udevice *dev, char *out_name)
+{
+	return acpi_return_name(out_name, ACPI_TEST_DEV_NAME);
+}
+
+struct acpi_ops testacpi_ops = {
+	.get_name	= testacpi_get_name,
+};
+
+static const struct udevice_id testacpi_ids[] = {
+	{ .compatible = "denx,u-boot-acpi-test" },
+	{ }
+};
+
+U_BOOT_DRIVER(testacpi_drv) = {
+	.name	= "testacpi_drv",
+	.of_match	= testacpi_ids,
+	.id	= UCLASS_TEST_ACPI,
+	acpi_ops_ptr(&testacpi_ops)
+};
+
+UCLASS_DRIVER(testacpi) = {
+	.name		= "testacpi",
+	.id		= UCLASS_TEST_ACPI,
+};
+
+/* Test ACPI get_name() */
+static int dm_test_acpi_get_name(struct unit_test_state *uts)
+{
+	char name[ACPI_NAME_MAX];
+	struct udevice *dev;
+
+	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);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_get_name, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 15/39] x86: Move acpi_table header to main include/ directory
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (13 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 14/39] acpi: Add a simple sandbox test Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 16/39] acpi: Add an __ACPI__ preprocessor symbol Simon Glass
                   ` (46 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

This file is potentially useful to other architectures saddled with ACPI
so move it into a common location.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---

Changes in v2: None

 arch/x86/cpu/baytrail/acpi.c      |   2 +-
 arch/x86/cpu/cpu.c                |   2 +-
 arch/x86/cpu/quark/acpi.c         |   2 +-
 arch/x86/cpu/tangier/acpi.c       |   2 +-
 arch/x86/include/asm/acpi_table.h | 376 ----------------------------
 arch/x86/lib/acpi.c               |   2 +-
 arch/x86/lib/acpi_s3.c            |   2 +-
 arch/x86/lib/acpi_table.c         |   2 +-
 arch/x86/lib/tables.c             |   2 +-
 arch/x86/lib/zimage.c             |   2 +-
 include/acpi_table.h              | 394 ++++++++++++++++++++++++++++++
 lib/efi_loader/efi_acpi.c         |   2 +-
 12 files changed, 404 insertions(+), 386 deletions(-)
 create mode 100644 include/acpi_table.h

diff --git a/arch/x86/cpu/baytrail/acpi.c b/arch/x86/cpu/baytrail/acpi.c
index f44228e693..856af95556 100644
--- a/arch/x86/cpu/baytrail/acpi.c
+++ b/arch/x86/cpu/baytrail/acpi.c
@@ -8,7 +8,7 @@
 #include <cpu.h>
 #include <dm.h>
 #include <dm/uclass-internal.h>
-#include <asm/acpi_table.h>
+#include <acpi_table.h>
 #include <asm/io.h>
 #include <asm/tables.h>
 #include <asm/arch/global_nvs.h>
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c
index 3db035c2c0..b878fd4b1f 100644
--- a/arch/x86/cpu/cpu.c
+++ b/arch/x86/cpu/cpu.c
@@ -28,7 +28,7 @@
 #include <malloc.h>
 #include <syscon.h>
 #include <asm/acpi.h>
-#include <asm/acpi_table.h>
+#include <acpi_table.h>
 #include <asm/control_regs.h>
 #include <asm/coreboot_tables.h>
 #include <asm/cpu.h>
diff --git a/arch/x86/cpu/quark/acpi.c b/arch/x86/cpu/quark/acpi.c
index 7b6fc2f4a5..dd562a6e2f 100644
--- a/arch/x86/cpu/quark/acpi.c
+++ b/arch/x86/cpu/quark/acpi.c
@@ -4,7 +4,7 @@
  */
 
 #include <common.h>
-#include <asm/acpi_table.h>
+#include <acpi_table.h>
 #include <asm/tables.h>
 #include <asm/arch/global_nvs.h>
 #include <asm/arch/iomap.h>
diff --git a/arch/x86/cpu/tangier/acpi.c b/arch/x86/cpu/tangier/acpi.c
index 8b128138b0..768c4dcbc8 100644
--- a/arch/x86/cpu/tangier/acpi.c
+++ b/arch/x86/cpu/tangier/acpi.c
@@ -9,7 +9,7 @@
 #include <cpu.h>
 #include <dm.h>
 #include <dm/uclass-internal.h>
-#include <asm/acpi_table.h>
+#include <acpi_table.h>
 #include <asm/ioapic.h>
 #include <asm/mpspec.h>
 #include <asm/tables.h>
diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h
index 7588913f93..22d54057f1 100644
--- a/arch/x86/include/asm/acpi_table.h
+++ b/arch/x86/include/asm/acpi_table.h
@@ -9,382 +9,6 @@
 #ifndef __ASM_ACPI_TABLE_H__
 #define __ASM_ACPI_TABLE_H__
 
-#define RSDP_SIG		"RSD PTR "	/* RSDP pointer signature */
-#define OEM_ID			"U-BOOT"	/* U-Boot */
-#define OEM_TABLE_ID		"U-BOOTBL"	/* U-Boot Table */
-#define ASLC_ID			"INTL"		/* Intel ASL Compiler */
-
-#define ACPI_RSDP_REV_ACPI_1_0	0
-#define ACPI_RSDP_REV_ACPI_2_0	2
-
-/*
- * RSDP (Root System Description Pointer)
- * Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum
- */
-struct acpi_rsdp {
-	char signature[8];	/* RSDP signature */
-	u8 checksum;		/* Checksum of the first 20 bytes */
-	char oem_id[6];		/* OEM ID */
-	u8 revision;		/* 0 for ACPI 1.0, others 2 */
-	u32 rsdt_address;	/* Physical address of RSDT (32 bits) */
-	u32 length;		/* Total RSDP length (incl. extended part) */
-	u64 xsdt_address;	/* Physical address of XSDT (64 bits) */
-	u8 ext_checksum;	/* Checksum of the whole table */
-	u8 reserved[3];
-};
-
-/* Generic ACPI header, provided by (almost) all tables */
-struct __packed acpi_table_header {
-	char signature[4];	/* ACPI signature (4 ASCII characters) */
-	u32 length;		/* Table length in bytes (incl. header) */
-	u8 revision;		/* Table version (not ACPI version!) */
-	volatile u8 checksum;	/* To make sum of entire table == 0 */
-	char oem_id[6];		/* OEM identification */
-	char oem_table_id[8];	/* OEM table identification */
-	u32 oem_revision;	/* OEM revision number */
-	char aslc_id[4];	/* ASL compiler vendor ID */
-	u32 aslc_revision;	/* ASL compiler revision number */
-};
-
-/* A maximum number of 32 ACPI tables ought to be enough for now */
-#define MAX_ACPI_TABLES		32
-
-/* RSDT (Root System Description Table) */
-struct acpi_rsdt {
-	struct acpi_table_header header;
-	u32 entry[MAX_ACPI_TABLES];
-};
-
-/* XSDT (Extended System Description Table) */
-struct acpi_xsdt {
-	struct acpi_table_header header;
-	u64 entry[MAX_ACPI_TABLES];
-};
-
-/* FADT Preferred Power Management Profile */
-enum acpi_pm_profile {
-	ACPI_PM_UNSPECIFIED = 0,
-	ACPI_PM_DESKTOP,
-	ACPI_PM_MOBILE,
-	ACPI_PM_WORKSTATION,
-	ACPI_PM_ENTERPRISE_SERVER,
-	ACPI_PM_SOHO_SERVER,
-	ACPI_PM_APPLIANCE_PC,
-	ACPI_PM_PERFORMANCE_SERVER,
-	ACPI_PM_TABLET
-};
-
-/* FADT flags for p_lvl2_lat and p_lvl3_lat */
-#define ACPI_FADT_C2_NOT_SUPPORTED	101
-#define ACPI_FADT_C3_NOT_SUPPORTED	1001
-
-/* FADT Boot Architecture Flags */
-#define ACPI_FADT_LEGACY_FREE		0x00
-#define ACPI_FADT_LEGACY_DEVICES	(1 << 0)
-#define ACPI_FADT_8042			(1 << 1)
-#define ACPI_FADT_VGA_NOT_PRESENT	(1 << 2)
-#define ACPI_FADT_MSI_NOT_SUPPORTED	(1 << 3)
-#define ACPI_FADT_NO_PCIE_ASPM_CONTROL	(1 << 4)
-
-/* FADT Feature Flags */
-#define ACPI_FADT_WBINVD		(1 << 0)
-#define ACPI_FADT_WBINVD_FLUSH		(1 << 1)
-#define ACPI_FADT_C1_SUPPORTED		(1 << 2)
-#define ACPI_FADT_C2_MP_SUPPORTED	(1 << 3)
-#define ACPI_FADT_POWER_BUTTON		(1 << 4)
-#define ACPI_FADT_SLEEP_BUTTON		(1 << 5)
-#define ACPI_FADT_FIXED_RTC		(1 << 6)
-#define ACPI_FADT_S4_RTC_WAKE		(1 << 7)
-#define ACPI_FADT_32BIT_TIMER		(1 << 8)
-#define ACPI_FADT_DOCKING_SUPPORTED	(1 << 9)
-#define ACPI_FADT_RESET_REGISTER	(1 << 10)
-#define ACPI_FADT_SEALED_CASE		(1 << 11)
-#define ACPI_FADT_HEADLESS		(1 << 12)
-#define ACPI_FADT_SLEEP_TYPE		(1 << 13)
-#define ACPI_FADT_PCI_EXPRESS_WAKE	(1 << 14)
-#define ACPI_FADT_PLATFORM_CLOCK	(1 << 15)
-#define ACPI_FADT_S4_RTC_VALID		(1 << 16)
-#define ACPI_FADT_REMOTE_POWER_ON	(1 << 17)
-#define ACPI_FADT_APIC_CLUSTER		(1 << 18)
-#define ACPI_FADT_APIC_PHYSICAL		(1 << 19)
-#define ACPI_FADT_HW_REDUCED_ACPI	(1 << 20)
-#define ACPI_FADT_LOW_PWR_IDLE_S0	(1 << 21)
-
-enum acpi_address_space_type {
-	ACPI_ADDRESS_SPACE_MEMORY = 0,	/* System memory */
-	ACPI_ADDRESS_SPACE_IO,		/* System I/O */
-	ACPI_ADDRESS_SPACE_PCI,		/* PCI config space */
-	ACPI_ADDRESS_SPACE_EC,		/* Embedded controller */
-	ACPI_ADDRESS_SPACE_SMBUS,	/* SMBus */
-	ACPI_ADDRESS_SPACE_PCC = 0x0a,	/* Platform Comm. Channel */
-	ACPI_ADDRESS_SPACE_FIXED = 0x7f	/* Functional fixed hardware */
-};
-
-enum acpi_address_space_size {
-	ACPI_ACCESS_SIZE_UNDEFINED = 0,
-	ACPI_ACCESS_SIZE_BYTE_ACCESS,
-	ACPI_ACCESS_SIZE_WORD_ACCESS,
-	ACPI_ACCESS_SIZE_DWORD_ACCESS,
-	ACPI_ACCESS_SIZE_QWORD_ACCESS
-};
-
-struct acpi_gen_regaddr {
-	u8 space_id;	/* Address space ID */
-	u8 bit_width;	/* Register size in bits */
-	u8 bit_offset;	/* Register bit offset */
-	u8 access_size;	/* Access size */
-	u32 addrl;	/* Register address, low 32 bits */
-	u32 addrh;	/* Register address, high 32 bits */
-};
-
-/* FADT (Fixed ACPI Description Table) */
-struct __packed acpi_fadt {
-	struct acpi_table_header header;
-	u32 firmware_ctrl;
-	u32 dsdt;
-	u8 res1;
-	u8 preferred_pm_profile;
-	u16 sci_int;
-	u32 smi_cmd;
-	u8 acpi_enable;
-	u8 acpi_disable;
-	u8 s4bios_req;
-	u8 pstate_cnt;
-	u32 pm1a_evt_blk;
-	u32 pm1b_evt_blk;
-	u32 pm1a_cnt_blk;
-	u32 pm1b_cnt_blk;
-	u32 pm2_cnt_blk;
-	u32 pm_tmr_blk;
-	u32 gpe0_blk;
-	u32 gpe1_blk;
-	u8 pm1_evt_len;
-	u8 pm1_cnt_len;
-	u8 pm2_cnt_len;
-	u8 pm_tmr_len;
-	u8 gpe0_blk_len;
-	u8 gpe1_blk_len;
-	u8 gpe1_base;
-	u8 cst_cnt;
-	u16 p_lvl2_lat;
-	u16 p_lvl3_lat;
-	u16 flush_size;
-	u16 flush_stride;
-	u8 duty_offset;
-	u8 duty_width;
-	u8 day_alrm;
-	u8 mon_alrm;
-	u8 century;
-	u16 iapc_boot_arch;
-	u8 res2;
-	u32 flags;
-	struct acpi_gen_regaddr reset_reg;
-	u8 reset_value;
-	u16 arm_boot_arch;
-	u8 minor_revision;
-	u32 x_firmware_ctl_l;
-	u32 x_firmware_ctl_h;
-	u32 x_dsdt_l;
-	u32 x_dsdt_h;
-	struct acpi_gen_regaddr x_pm1a_evt_blk;
-	struct acpi_gen_regaddr x_pm1b_evt_blk;
-	struct acpi_gen_regaddr x_pm1a_cnt_blk;
-	struct acpi_gen_regaddr x_pm1b_cnt_blk;
-	struct acpi_gen_regaddr x_pm2_cnt_blk;
-	struct acpi_gen_regaddr x_pm_tmr_blk;
-	struct acpi_gen_regaddr x_gpe0_blk;
-	struct acpi_gen_regaddr x_gpe1_blk;
-};
-
-/* FACS flags */
-#define ACPI_FACS_S4BIOS_F	(1 << 0)
-#define ACPI_FACS_64BIT_WAKE_F	(1 << 1)
-
-/* FACS (Firmware ACPI Control Structure) */
-struct acpi_facs {
-	char signature[4];		/* "FACS" */
-	u32 length;			/* Length in bytes (>= 64) */
-	u32 hardware_signature;		/* Hardware signature */
-	u32 firmware_waking_vector;	/* Firmware waking vector */
-	u32 global_lock;		/* Global lock */
-	u32 flags;			/* FACS flags */
-	u32 x_firmware_waking_vector_l;	/* X FW waking vector, low */
-	u32 x_firmware_waking_vector_h;	/* X FW waking vector, high */
-	u8 version;			/* Version 2 */
-	u8 res1[3];
-	u32 ospm_flags;			/* OSPM enabled flags */
-	u8 res2[24];
-};
-
-/* MADT flags */
-#define ACPI_MADT_PCAT_COMPAT	(1 << 0)
-
-/* MADT (Multiple APIC Description Table) */
-struct acpi_madt {
-	struct acpi_table_header header;
-	u32 lapic_addr;			/* Local APIC address */
-	u32 flags;			/* Multiple APIC flags */
-};
-
-/* MADT: APIC Structure Type*/
-enum acpi_apic_types {
-	ACPI_APIC_LAPIC	= 0,		/* Processor local APIC */
-	ACPI_APIC_IOAPIC,		/* I/O APIC */
-	ACPI_APIC_IRQ_SRC_OVERRIDE,	/* Interrupt source override */
-	ACPI_APIC_NMI_SRC,		/* NMI source */
-	ACPI_APIC_LAPIC_NMI,		/* Local APIC NMI */
-	ACPI_APIC_LAPIC_ADDR_OVERRIDE,	/* Local APIC address override */
-	ACPI_APIC_IOSAPIC,		/* I/O SAPIC */
-	ACPI_APIC_LSAPIC,		/* Local SAPIC */
-	ACPI_APIC_PLATFORM_IRQ_SRC,	/* Platform interrupt sources */
-	ACPI_APIC_LX2APIC,		/* Processor local x2APIC */
-	ACPI_APIC_LX2APIC_NMI,		/* Local x2APIC NMI */
-};
-
-/* MADT: Processor Local APIC Structure */
-
-#define LOCAL_APIC_FLAG_ENABLED	(1 << 0)
-
-struct acpi_madt_lapic {
-	u8 type;		/* Type (0) */
-	u8 length;		/* Length in bytes (8) */
-	u8 processor_id;	/* ACPI processor ID */
-	u8 apic_id;		/* Local APIC ID */
-	u32 flags;		/* Local APIC flags */
-};
-
-/* MADT: I/O APIC Structure */
-struct acpi_madt_ioapic {
-	u8 type;		/* Type (1) */
-	u8 length;		/* Length in bytes (12) */
-	u8 ioapic_id;		/* I/O APIC ID */
-	u8 reserved;
-	u32 ioapic_addr;	/* I/O APIC address */
-	u32 gsi_base;		/* Global system interrupt base */
-};
-
-/* MADT: Interrupt Source Override Structure */
-struct __packed acpi_madt_irqoverride {
-	u8 type;		/* Type (2) */
-	u8 length;		/* Length in bytes (10) */
-	u8 bus;			/* ISA (0) */
-	u8 source;		/* Bus-relative int. source (IRQ) */
-	u32 gsirq;		/* Global system interrupt */
-	u16 flags;		/* MPS INTI flags */
-};
-
-/* MADT: Local APIC NMI Structure */
-struct __packed acpi_madt_lapic_nmi {
-	u8 type;		/* Type (4) */
-	u8 length;		/* Length in bytes (6) */
-	u8 processor_id;	/* ACPI processor ID */
-	u16 flags;		/* MPS INTI flags */
-	u8 lint;		/* Local APIC LINT# */
-};
-
-/* MCFG (PCI Express MMIO config space BAR description table) */
-struct acpi_mcfg {
-	struct acpi_table_header header;
-	u8 reserved[8];
-};
-
-struct acpi_mcfg_mmconfig {
-	u32 base_address_l;
-	u32 base_address_h;
-	u16 pci_segment_group_number;
-	u8 start_bus_number;
-	u8 end_bus_number;
-	u8 reserved[4];
-};
-
-/* PM1_CNT bit defines */
-#define PM1_CNT_SCI_EN		(1 << 0)
-
-/* ACPI global NVS structure */
-struct acpi_global_nvs;
-
-/* CSRT (Core System Resource Table) */
-struct acpi_csrt {
-	struct acpi_table_header header;
-};
-
-struct acpi_csrt_group {
-	u32 length;
-	u32 vendor_id;
-	u32 subvendor_id;
-	u16 device_id;
-	u16 subdevice_id;
-	u16 revision;
-	u16 reserved;
-	u32 shared_info_length;
-};
-
-struct acpi_csrt_shared_info {
-	u16 major_version;
-	u16 minor_version;
-	u32 mmio_base_low;
-	u32 mmio_base_high;
-	u32 gsi_interrupt;
-	u8 interrupt_polarity;
-	u8 interrupt_mode;
-	u8 num_channels;
-	u8 dma_address_width;
-	u16 base_request_line;
-	u16 num_handshake_signals;
-	u32 max_block_size;
-};
-
-/* DBG2 definitions are partially used for SPCR interface_type */
-
-/* Types for port_type field */
-
-#define ACPI_DBG2_SERIAL_PORT		0x8000
-#define ACPI_DBG2_1394_PORT		0x8001
-#define ACPI_DBG2_USB_PORT		0x8002
-#define ACPI_DBG2_NET_PORT		0x8003
-
-/* Subtypes for port_subtype field */
-
-#define ACPI_DBG2_16550_COMPATIBLE	0x0000
-#define ACPI_DBG2_16550_SUBSET		0x0001
-#define ACPI_DBG2_ARM_PL011		0x0003
-#define ACPI_DBG2_ARM_SBSA_32BIT	0x000D
-#define ACPI_DBG2_ARM_SBSA_GENERIC	0x000E
-#define ACPI_DBG2_ARM_DCC		0x000F
-#define ACPI_DBG2_BCM2835		0x0010
-
-#define ACPI_DBG2_1394_STANDARD		0x0000
-
-#define ACPI_DBG2_USB_XHCI		0x0000
-#define ACPI_DBG2_USB_EHCI		0x0001
-
-#define ACPI_DBG2_UNKNOWN		0x00FF
-
-/* SPCR (Serial Port Console Redirection table) */
-struct __packed acpi_spcr {
-	struct acpi_table_header header;
-	u8 interface_type;
-	u8 reserved[3];
-	struct acpi_gen_regaddr serial_port;
-	u8 interrupt_type;
-	u8 pc_interrupt;
-	u32 interrupt;		/* Global system interrupt */
-	u8 baud_rate;
-	u8 parity;
-	u8 stop_bits;
-	u8 flow_control;
-	u8 terminal_type;
-	u8 reserved1;
-	u16 pci_device_id;	/* Must be 0xffff if not PCI device */
-	u16 pci_vendor_id;	/* Must be 0xffff if not PCI device */
-	u8 pci_bus;
-	u8 pci_device;
-	u8 pci_function;
-	u32 pci_flags;
-	u8 pci_segment;
-	u32 reserved2;
-};
-
 /* These can be used by the target port */
 
 void acpi_fill_header(struct acpi_table_header *header, char *signature);
diff --git a/arch/x86/lib/acpi.c b/arch/x86/lib/acpi.c
index cba9c24dd4..2f4cd736f7 100644
--- a/arch/x86/lib/acpi.c
+++ b/arch/x86/lib/acpi.c
@@ -4,7 +4,7 @@
  */
 
 #include <common.h>
-#include <asm/acpi_table.h>
+#include <acpi_table.h>
 #include <asm/io.h>
 #include <asm/tables.h>
 
diff --git a/arch/x86/lib/acpi_s3.c b/arch/x86/lib/acpi_s3.c
index 197636c4b5..74a78fd193 100644
--- a/arch/x86/lib/acpi_s3.c
+++ b/arch/x86/lib/acpi_s3.c
@@ -6,7 +6,7 @@
 #include <common.h>
 #include <acpi_s3.h>
 #include <asm/acpi.h>
-#include <asm/acpi_table.h>
+#include <acpi_table.h>
 #include <asm/post.h>
 #include <linux/linkage.h>
 
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index 0d69cf271f..71913b6f65 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -13,7 +13,7 @@
 #include <serial.h>
 #include <version.h>
 #include <asm/acpi/global_nvs.h>
-#include <asm/acpi_table.h>
+#include <acpi_table.h>
 #include <asm/ioapic.h>
 #include <asm/lapic.h>
 #include <asm/mpspec.h>
diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c
index 7aea722d0b..b718a5c3dc 100644
--- a/arch/x86/lib/tables.c
+++ b/arch/x86/lib/tables.c
@@ -9,7 +9,7 @@
 #include <asm/sfi.h>
 #include <asm/mpspec.h>
 #include <asm/tables.h>
-#include <asm/acpi_table.h>
+#include <acpi_table.h>
 #include <asm/coreboot_tables.h>
 
 /**
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c
index 9b5e767ccc..180b18349d 100644
--- a/arch/x86/lib/zimage.c
+++ b/arch/x86/lib/zimage.c
@@ -16,7 +16,7 @@
 #include <env.h>
 #include <irq_func.h>
 #include <malloc.h>
-#include <asm/acpi_table.h>
+#include <acpi_table.h>
 #include <asm/io.h>
 #include <asm/ptrace.h>
 #include <asm/zimage.h>
diff --git a/include/acpi_table.h b/include/acpi_table.h
new file mode 100644
index 0000000000..b4404a632c
--- /dev/null
+++ b/include/acpi_table.h
@@ -0,0 +1,394 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Helpers for ACPI table generation
+ *
+ * Based on acpi.c from coreboot
+ *
+ * Copyright 2019 Google LLC
+ *
+ * Copyright (C) 2015, Saket Sinha <saket.sinha89@gmail.com>
+ * Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#ifndef __ACPI_TABLE_H__
+#define __ACPI_TABLE_H__
+
+#define RSDP_SIG		"RSD PTR "	/* RSDP pointer signature */
+#define OEM_ID			"U-BOOT"	/* U-Boot */
+#define OEM_TABLE_ID		"U-BOOTBL"	/* U-Boot Table */
+#define ASLC_ID			"INTL"		/* Intel ASL Compiler */
+
+#define ACPI_RSDP_REV_ACPI_1_0	0
+#define ACPI_RSDP_REV_ACPI_2_0	2
+
+/*
+ * RSDP (Root System Description Pointer)
+ * Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum
+ */
+struct acpi_rsdp {
+	char signature[8];	/* RSDP signature */
+	u8 checksum;		/* Checksum of the first 20 bytes */
+	char oem_id[6];		/* OEM ID */
+	u8 revision;		/* 0 for ACPI 1.0, others 2 */
+	u32 rsdt_address;	/* Physical address of RSDT (32 bits) */
+	u32 length;		/* Total RSDP length (incl. extended part) */
+	u64 xsdt_address;	/* Physical address of XSDT (64 bits) */
+	u8 ext_checksum;	/* Checksum of the whole table */
+	u8 reserved[3];
+};
+
+/* Generic ACPI header, provided by (almost) all tables */
+struct __packed acpi_table_header {
+	char signature[4];	/* ACPI signature (4 ASCII characters) */
+	u32 length;		/* Table length in bytes (incl. header) */
+	u8 revision;		/* Table version (not ACPI version!) */
+	volatile u8 checksum;	/* To make sum of entire table == 0 */
+	char oem_id[6];		/* OEM identification */
+	char oem_table_id[8];	/* OEM table identification */
+	u32 oem_revision;	/* OEM revision number */
+	char aslc_id[4];	/* ASL compiler vendor ID */
+	u32 aslc_revision;	/* ASL compiler revision number */
+};
+
+/* A maximum number of 32 ACPI tables ought to be enough for now */
+#define MAX_ACPI_TABLES		32
+
+/* RSDT (Root System Description Table) */
+struct acpi_rsdt {
+	struct acpi_table_header header;
+	u32 entry[MAX_ACPI_TABLES];
+};
+
+/* XSDT (Extended System Description Table) */
+struct acpi_xsdt {
+	struct acpi_table_header header;
+	u64 entry[MAX_ACPI_TABLES];
+};
+
+/* FADT Preferred Power Management Profile */
+enum acpi_pm_profile {
+	ACPI_PM_UNSPECIFIED = 0,
+	ACPI_PM_DESKTOP,
+	ACPI_PM_MOBILE,
+	ACPI_PM_WORKSTATION,
+	ACPI_PM_ENTERPRISE_SERVER,
+	ACPI_PM_SOHO_SERVER,
+	ACPI_PM_APPLIANCE_PC,
+	ACPI_PM_PERFORMANCE_SERVER,
+	ACPI_PM_TABLET
+};
+
+/* FADT flags for p_lvl2_lat and p_lvl3_lat */
+#define ACPI_FADT_C2_NOT_SUPPORTED	101
+#define ACPI_FADT_C3_NOT_SUPPORTED	1001
+
+/* FADT Boot Architecture Flags */
+#define ACPI_FADT_LEGACY_FREE		0x00
+#define ACPI_FADT_LEGACY_DEVICES	BIT(0)
+#define ACPI_FADT_8042			BIT(1)
+#define ACPI_FADT_VGA_NOT_PRESENT	BIT(2)
+#define ACPI_FADT_MSI_NOT_SUPPORTED	BIT(3)
+#define ACPI_FADT_NO_PCIE_ASPM_CONTROL	BIT(4)
+
+/* FADT Feature Flags */
+#define ACPI_FADT_WBINVD		BIT(0)
+#define ACPI_FADT_WBINVD_FLUSH		BIT(1)
+#define ACPI_FADT_C1_SUPPORTED		BIT(2)
+#define ACPI_FADT_C2_MP_SUPPORTED	BIT(3)
+#define ACPI_FADT_POWER_BUTTON		BIT(4)
+#define ACPI_FADT_SLEEP_BUTTON		BIT(5)
+#define ACPI_FADT_FIXED_RTC		BIT(6)
+#define ACPI_FADT_S4_RTC_WAKE		BIT(7)
+#define ACPI_FADT_32BIT_TIMER		BIT(8)
+#define ACPI_FADT_DOCKING_SUPPORTED	BIT(9)
+#define ACPI_FADT_RESET_REGISTER	BIT(10)
+#define ACPI_FADT_SEALED_CASE		BIT(11)
+#define ACPI_FADT_HEADLESS		BIT(12)
+#define ACPI_FADT_SLEEP_TYPE		BIT(13)
+#define ACPI_FADT_PCI_EXPRESS_WAKE	BIT(14)
+#define ACPI_FADT_PLATFORM_CLOCK	BIT(15)
+#define ACPI_FADT_S4_RTC_VALID		BIT(16)
+#define ACPI_FADT_REMOTE_POWER_ON	BIT(17)
+#define ACPI_FADT_APIC_CLUSTER		BIT(18)
+#define ACPI_FADT_APIC_PHYSICAL		BIT(19)
+#define ACPI_FADT_HW_REDUCED_ACPI	BIT(20)
+#define ACPI_FADT_LOW_PWR_IDLE_S0	BIT(21)
+
+enum acpi_address_space_type {
+	ACPI_ADDRESS_SPACE_MEMORY = 0,	/* System memory */
+	ACPI_ADDRESS_SPACE_IO,		/* System I/O */
+	ACPI_ADDRESS_SPACE_PCI,		/* PCI config space */
+	ACPI_ADDRESS_SPACE_EC,		/* Embedded controller */
+	ACPI_ADDRESS_SPACE_SMBUS,	/* SMBus */
+	ACPI_ADDRESS_SPACE_PCC = 0x0a,	/* Platform Comm. Channel */
+	ACPI_ADDRESS_SPACE_FIXED = 0x7f	/* Functional fixed hardware */
+};
+
+enum acpi_address_space_size {
+	ACPI_ACCESS_SIZE_UNDEFINED = 0,
+	ACPI_ACCESS_SIZE_BYTE_ACCESS,
+	ACPI_ACCESS_SIZE_WORD_ACCESS,
+	ACPI_ACCESS_SIZE_DWORD_ACCESS,
+	ACPI_ACCESS_SIZE_QWORD_ACCESS
+};
+
+struct acpi_gen_regaddr {
+	u8 space_id;	/* Address space ID */
+	u8 bit_width;	/* Register size in bits */
+	u8 bit_offset;	/* Register bit offset */
+	u8 access_size;	/* Access size */
+	u32 addrl;	/* Register address, low 32 bits */
+	u32 addrh;	/* Register address, high 32 bits */
+};
+
+/* FADT (Fixed ACPI Description Table) */
+struct __packed acpi_fadt {
+	struct acpi_table_header header;
+	u32 firmware_ctrl;
+	u32 dsdt;
+	u8 res1;
+	u8 preferred_pm_profile;
+	u16 sci_int;
+	u32 smi_cmd;
+	u8 acpi_enable;
+	u8 acpi_disable;
+	u8 s4bios_req;
+	u8 pstate_cnt;
+	u32 pm1a_evt_blk;
+	u32 pm1b_evt_blk;
+	u32 pm1a_cnt_blk;
+	u32 pm1b_cnt_blk;
+	u32 pm2_cnt_blk;
+	u32 pm_tmr_blk;
+	u32 gpe0_blk;
+	u32 gpe1_blk;
+	u8 pm1_evt_len;
+	u8 pm1_cnt_len;
+	u8 pm2_cnt_len;
+	u8 pm_tmr_len;
+	u8 gpe0_blk_len;
+	u8 gpe1_blk_len;
+	u8 gpe1_base;
+	u8 cst_cnt;
+	u16 p_lvl2_lat;
+	u16 p_lvl3_lat;
+	u16 flush_size;
+	u16 flush_stride;
+	u8 duty_offset;
+	u8 duty_width;
+	u8 day_alrm;
+	u8 mon_alrm;
+	u8 century;
+	u16 iapc_boot_arch;
+	u8 res2;
+	u32 flags;
+	struct acpi_gen_regaddr reset_reg;
+	u8 reset_value;
+	u16 arm_boot_arch;
+	u8 minor_revision;
+	u32 x_firmware_ctl_l;
+	u32 x_firmware_ctl_h;
+	u32 x_dsdt_l;
+	u32 x_dsdt_h;
+	struct acpi_gen_regaddr x_pm1a_evt_blk;
+	struct acpi_gen_regaddr x_pm1b_evt_blk;
+	struct acpi_gen_regaddr x_pm1a_cnt_blk;
+	struct acpi_gen_regaddr x_pm1b_cnt_blk;
+	struct acpi_gen_regaddr x_pm2_cnt_blk;
+	struct acpi_gen_regaddr x_pm_tmr_blk;
+	struct acpi_gen_regaddr x_gpe0_blk;
+	struct acpi_gen_regaddr x_gpe1_blk;
+};
+
+/* FACS flags */
+#define ACPI_FACS_S4BIOS_F		BIT(0)
+#define ACPI_FACS_64BIT_WAKE_F		BIT(1)
+
+/* FACS (Firmware ACPI Control Structure) */
+struct acpi_facs {
+	char signature[4];		/* "FACS" */
+	u32 length;			/* Length in bytes (>= 64) */
+	u32 hardware_signature;		/* Hardware signature */
+	u32 firmware_waking_vector;	/* Firmware waking vector */
+	u32 global_lock;		/* Global lock */
+	u32 flags;			/* FACS flags */
+	u32 x_firmware_waking_vector_l;	/* X FW waking vector, low */
+	u32 x_firmware_waking_vector_h;	/* X FW waking vector, high */
+	u8 version;			/* Version 2 */
+	u8 res1[3];
+	u32 ospm_flags;			/* OSPM enabled flags */
+	u8 res2[24];
+};
+
+/* MADT flags */
+#define ACPI_MADT_PCAT_COMPAT	BIT(0)
+
+/* MADT (Multiple APIC Description Table) */
+struct acpi_madt {
+	struct acpi_table_header header;
+	u32 lapic_addr;			/* Local APIC address */
+	u32 flags;			/* Multiple APIC flags */
+};
+
+/* MADT: APIC Structure Type*/
+enum acpi_apic_types {
+	ACPI_APIC_LAPIC	= 0,		/* Processor local APIC */
+	ACPI_APIC_IOAPIC,		/* I/O APIC */
+	ACPI_APIC_IRQ_SRC_OVERRIDE,	/* Interrupt source override */
+	ACPI_APIC_NMI_SRC,		/* NMI source */
+	ACPI_APIC_LAPIC_NMI,		/* Local APIC NMI */
+	ACPI_APIC_LAPIC_ADDR_OVERRIDE,	/* Local APIC address override */
+	ACPI_APIC_IOSAPIC,		/* I/O SAPIC */
+	ACPI_APIC_LSAPIC,		/* Local SAPIC */
+	ACPI_APIC_PLATFORM_IRQ_SRC,	/* Platform interrupt sources */
+	ACPI_APIC_LX2APIC,		/* Processor local x2APIC */
+	ACPI_APIC_LX2APIC_NMI,		/* Local x2APIC NMI */
+};
+
+/* MADT: Processor Local APIC Structure */
+
+#define LOCAL_APIC_FLAG_ENABLED		BIT(0)
+
+struct acpi_madt_lapic {
+	u8 type;		/* Type (0) */
+	u8 length;		/* Length in bytes (8) */
+	u8 processor_id;	/* ACPI processor ID */
+	u8 apic_id;		/* Local APIC ID */
+	u32 flags;		/* Local APIC flags */
+};
+
+/* MADT: I/O APIC Structure */
+struct acpi_madt_ioapic {
+	u8 type;		/* Type (1) */
+	u8 length;		/* Length in bytes (12) */
+	u8 ioapic_id;		/* I/O APIC ID */
+	u8 reserved;
+	u32 ioapic_addr;	/* I/O APIC address */
+	u32 gsi_base;		/* Global system interrupt base */
+};
+
+/* MADT: Interrupt Source Override Structure */
+struct __packed acpi_madt_irqoverride {
+	u8 type;		/* Type (2) */
+	u8 length;		/* Length in bytes (10) */
+	u8 bus;			/* ISA (0) */
+	u8 source;		/* Bus-relative int. source (IRQ) */
+	u32 gsirq;		/* Global system interrupt */
+	u16 flags;		/* MPS INTI flags */
+};
+
+/* MADT: Local APIC NMI Structure */
+struct __packed acpi_madt_lapic_nmi {
+	u8 type;		/* Type (4) */
+	u8 length;		/* Length in bytes (6) */
+	u8 processor_id;	/* ACPI processor ID */
+	u16 flags;		/* MPS INTI flags */
+	u8 lint;		/* Local APIC LINT# */
+};
+
+/* MCFG (PCI Express MMIO config space BAR description table) */
+struct acpi_mcfg {
+	struct acpi_table_header header;
+	u8 reserved[8];
+};
+
+struct acpi_mcfg_mmconfig {
+	u32 base_address_l;
+	u32 base_address_h;
+	u16 pci_segment_group_number;
+	u8 start_bus_number;
+	u8 end_bus_number;
+	u8 reserved[4];
+};
+
+/* PM1_CNT bit defines */
+#define PM1_CNT_SCI_EN		BIT(0)
+
+/* ACPI global NVS structure */
+struct acpi_global_nvs;
+
+/* CSRT (Core System Resource Table) */
+struct acpi_csrt {
+	struct acpi_table_header header;
+};
+
+struct acpi_csrt_group {
+	u32 length;
+	u32 vendor_id;
+	u32 subvendor_id;
+	u16 device_id;
+	u16 subdevice_id;
+	u16 revision;
+	u16 reserved;
+	u32 shared_info_length;
+};
+
+struct acpi_csrt_shared_info {
+	u16 major_version;
+	u16 minor_version;
+	u32 mmio_base_low;
+	u32 mmio_base_high;
+	u32 gsi_interrupt;
+	u8 interrupt_polarity;
+	u8 interrupt_mode;
+	u8 num_channels;
+	u8 dma_address_width;
+	u16 base_request_line;
+	u16 num_handshake_signals;
+	u32 max_block_size;
+};
+
+/* DBG2 definitions are partially used for SPCR interface_type */
+
+/* Types for port_type field */
+
+#define ACPI_DBG2_SERIAL_PORT		0x8000
+#define ACPI_DBG2_1394_PORT		0x8001
+#define ACPI_DBG2_USB_PORT		0x8002
+#define ACPI_DBG2_NET_PORT		0x8003
+
+/* Subtypes for port_subtype field */
+
+#define ACPI_DBG2_16550_COMPATIBLE	0x0000
+#define ACPI_DBG2_16550_SUBSET		0x0001
+#define ACPI_DBG2_ARM_PL011		0x0003
+#define ACPI_DBG2_ARM_SBSA_32BIT	0x000D
+#define ACPI_DBG2_ARM_SBSA_GENERIC	0x000E
+#define ACPI_DBG2_ARM_DCC		0x000F
+#define ACPI_DBG2_BCM2835		0x0010
+
+#define ACPI_DBG2_1394_STANDARD		0x0000
+
+#define ACPI_DBG2_USB_XHCI		0x0000
+#define ACPI_DBG2_USB_EHCI		0x0001
+
+#define ACPI_DBG2_UNKNOWN		0x00FF
+
+/* SPCR (Serial Port Console Redirection table) */
+struct __packed acpi_spcr {
+	struct acpi_table_header header;
+	u8 interface_type;
+	u8 reserved[3];
+	struct acpi_gen_regaddr serial_port;
+	u8 interrupt_type;
+	u8 pc_interrupt;
+	u32 interrupt;		/* Global system interrupt */
+	u8 baud_rate;
+	u8 parity;
+	u8 stop_bits;
+	u8 flow_control;
+	u8 terminal_type;
+	u8 reserved1;
+	u16 pci_device_id;	/* Must be 0xffff if not PCI device */
+	u16 pci_vendor_id;	/* Must be 0xffff if not PCI device */
+	u8 pci_bus;
+	u8 pci_device;
+	u8 pci_function;
+	u32 pci_flags;
+	u8 pci_segment;
+	u32 reserved2;
+};
+
+#include <asm/acpi_table.h>
+
+#endif /* __ACPI_TABLE_H__ */
diff --git a/lib/efi_loader/efi_acpi.c b/lib/efi_loader/efi_acpi.c
index a4e5e53d15..74d8f5567f 100644
--- a/lib/efi_loader/efi_acpi.c
+++ b/lib/efi_loader/efi_acpi.c
@@ -7,7 +7,7 @@
 
 #include <common.h>
 #include <efi_loader.h>
-#include <asm/acpi_table.h>
+#include <acpi_table.h>
 
 static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID;
 
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 16/39] acpi: Add an __ACPI__ preprocessor symbol
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (14 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 15/39] x86: Move acpi_table header to main include/ directory Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 17/39] acpi: Add a central location for table version numbers Simon Glass
                   ` (45 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

The ASL compiler cannot handle C structures and the like so needs some
sort of header guard around these.

We already have an __ASSEMBLY__ #define but it seems best to create a new
one for ACPI since the rules may be different.

Add the check to a few files that ACPI always includes.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---

Changes in v2: None

 include/acpi_table.h | 4 ++++
 include/dm/acpi.h    | 4 ++++
 scripts/Makefile.lib | 4 ++--
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/include/acpi_table.h b/include/acpi_table.h
index b4404a632c..dd74895813 100644
--- a/include/acpi_table.h
+++ b/include/acpi_table.h
@@ -21,6 +21,8 @@
 #define ACPI_RSDP_REV_ACPI_1_0	0
 #define ACPI_RSDP_REV_ACPI_2_0	2
 
+#if !defined(__ACPI__)
+
 /*
  * RSDP (Root System Description Pointer)
  * Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum
@@ -389,6 +391,8 @@ struct __packed acpi_spcr {
 	u32 reserved2;
 };
 
+#endif /* !__ACPI__*/
+
 #include <asm/acpi_table.h>
 
 #endif /* __ACPI_TABLE_H__ */
diff --git a/include/dm/acpi.h b/include/dm/acpi.h
index 120576adc0..8d6c3fd424 100644
--- a/include/dm/acpi.h
+++ b/include/dm/acpi.h
@@ -22,6 +22,8 @@
 /* Length of an ACPI name string including nul terminator */
 #define ACPI_NAME_MAX	5
 
+#if !defined(__ACPI__)
+
 /**
  * struct acpi_ops - ACPI operations supported by driver model
  */
@@ -70,4 +72,6 @@ int acpi_get_name(const struct udevice *dev, char *out_name);
  */
 int acpi_return_name(char *out_name, const char *name);
 
+#endif /* __ACPI__ */
+
 #endif
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 30f392fdfb..aebdb38d0d 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -413,8 +413,8 @@ ASL_TMP = $(patsubst %.c,%.asl.tmp,$@)
 
 quiet_cmd_acpi_c_asl= ASL     $<
 cmd_acpi_c_asl=         \
-	$(CPP) -x assembler-with-cpp -D__ASSEMBLY__ -P $(UBOOTINCLUDE) \
-		-o $(ASL_TMP) $< && \
+	$(CPP) -x assembler-with-cpp -D__ASSEMBLY__ -D__ACPI__ \
+		-P $(UBOOTINCLUDE) -o $(ASL_TMP) $< && \
 	iasl -p $@ -tc $(ASL_TMP) $(if $(KBUILD_VERBOSE:1=), >/dev/null) && \
 	mv $(patsubst %.c,%.hex,$@) $@
 
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 17/39] acpi: Add a central location for table version numbers
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (15 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 16/39] acpi: Add an __ACPI__ preprocessor symbol Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 18/39] acpi: Add support for DMAR Simon Glass
                   ` (44 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

Each ACPI table has its own version number. Add the version numbers in a
single function so we can keep them consistent and easily see what
versions are supported.

Start a new acpi_table file in a generic directory to house this function.
We can move things over to this file from x86 as needed.

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

Changes in v2:
- Move the sandbox acpi_table.h header file to an earlier patch
- Use #defines for MADT and MCFG version numbers

 include/acpi_table.h  | 61 +++++++++++++++++++++++++++++++++++++++++++
 lib/Makefile          |  1 +
 lib/acpi/Makefile     |  4 +++
 lib/acpi/acpi_table.c | 60 ++++++++++++++++++++++++++++++++++++++++++
 test/dm/acpi.c        | 14 ++++++++++
 5 files changed, 140 insertions(+)
 create mode 100644 lib/acpi/Makefile
 create mode 100644 lib/acpi/acpi_table.c

diff --git a/include/acpi_table.h b/include/acpi_table.h
index dd74895813..ccf6fa04db 100644
--- a/include/acpi_table.h
+++ b/include/acpi_table.h
@@ -202,6 +202,26 @@ struct __packed acpi_fadt {
 	struct acpi_gen_regaddr x_gpe1_blk;
 };
 
+/* FADT TABLE Revision values */
+#define ACPI_FADT_REV_ACPI_1_0		1
+#define ACPI_FADT_REV_ACPI_2_0		3
+#define ACPI_FADT_REV_ACPI_3_0		4
+#define ACPI_FADT_REV_ACPI_4_0		4
+#define ACPI_FADT_REV_ACPI_5_0		5
+#define ACPI_FADT_REV_ACPI_6_0		6
+
+/* MADT TABLE Revision values */
+#define ACPI_MADT_REV_ACPI_3_0		2
+#define ACPI_MADT_REV_ACPI_4_0		3
+#define ACPI_MADT_REV_ACPI_5_0		3
+#define ACPI_MADT_REV_ACPI_6_0		5
+
+#define ACPI_MCFG_REV_ACPI_3_0		1
+
+/* IVRS Revision Field */
+#define IVRS_FORMAT_FIXED	0x01	/* Type 10h & 11h only */
+#define IVRS_FORMAT_MIXED	0x02	/* Type 10h, 11h, & 40h */
+
 /* FACS flags */
 #define ACPI_FACS_S4BIOS_F		BIT(0)
 #define ACPI_FACS_64BIT_WAKE_F		BIT(1)
@@ -391,6 +411,47 @@ struct __packed acpi_spcr {
 	u32 reserved2;
 };
 
+/* Tables defined by ACPI and generated by U-Boot */
+enum acpi_tables {
+	ACPITAB_BERT,
+	ACPITAB_DBG2,
+	ACPITAB_DMAR,
+	ACPITAB_DSDT,
+	ACPITAB_FACS,
+	ACPITAB_FADT,
+	ACPITAB_HEST,
+	ACPITAB_HPET,
+	ACPITAB_IVRS,
+	ACPITAB_MADT,
+	ACPITAB_MCFG,
+	ACPITAB_RSDP,
+	ACPITAB_RSDT,
+	ACPITAB_SLIT,
+	ACPITAB_SRAT,
+	ACPITAB_SSDT,
+	ACPITAB_TCPA,
+	ACPITAB_TPM2,
+	ACPITAB_XSDT,
+	ACPITAB_ECDT,
+
+	/* Additional proprietary tables */
+	ACPITAB_VFCT,
+	ACPITAB_NHLT,
+	ACPITAB_SPMI,
+
+	ACPITAB_COUNT,
+};
+
+/**
+ * acpi_get_table_revision() - Get the revision number generated for a table
+ *
+ * This keeps the version-number information in one place
+ *
+ * @table: ACPI table to check
+ * @return version number that U-Boot generates
+ */
+int acpi_get_table_revision(enum acpi_tables table);
+
 #endif /* !__ACPI__*/
 
 #include <asm/acpi_table.h>
diff --git a/lib/Makefile b/lib/Makefile
index 15259d0473..9df834c2fd 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -5,6 +5,7 @@
 
 ifndef CONFIG_SPL_BUILD
 
+obj-$(CONFIG_$(SPL_TPL_)ACPIGEN) += acpi/
 obj-$(CONFIG_EFI) += efi/
 obj-$(CONFIG_EFI_LOADER) += efi_driver/
 obj-$(CONFIG_EFI_LOADER) += efi_loader/
diff --git a/lib/acpi/Makefile b/lib/acpi/Makefile
new file mode 100644
index 0000000000..660491ef71
--- /dev/null
+++ b/lib/acpi/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-y += acpi_table.o
diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
new file mode 100644
index 0000000000..197f965c08
--- /dev/null
+++ b/lib/acpi/acpi_table.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Tests for ACPI table generation
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <acpi_table.h>
+
+int acpi_get_table_revision(enum acpi_tables table)
+{
+	switch (table) {
+	case ACPITAB_FADT:
+		return ACPI_FADT_REV_ACPI_3_0;
+	case ACPITAB_MADT:
+		return ACPI_MADT_REV_ACPI_3_0;
+	case ACPITAB_MCFG:
+		return ACPI_MCFG_REV_ACPI_3_0;
+	case ACPITAB_TCPA:
+		/* THis version and the rest are open-coded */
+		return 2;
+	case ACPITAB_TPM2:
+		return 4;
+	case ACPITAB_SSDT: /* ACPI 3.0 upto 6.3: 2 */
+		return 2;
+	case ACPITAB_SRAT: /* ACPI 2.0: 1, ACPI 3.0: 2, ACPI 4.0 upto 6.3: 3 */
+		return 1; /* TODO Should probably be upgraded to 2 */
+	case ACPITAB_DMAR:
+		return 1;
+	case ACPITAB_SLIT: /* ACPI 2.0 upto 6.3: 1 */
+		return 1;
+	case ACPITAB_SPMI: /* IMPI 2.0 */
+		return 5;
+	case ACPITAB_HPET: /* Currently 1. Table added in ACPI 2.0 */
+		return 1;
+	case ACPITAB_VFCT: /* ACPI 2.0/3.0/4.0: 1 */
+		return 1;
+	case ACPITAB_IVRS:
+		return IVRS_FORMAT_FIXED;
+	case ACPITAB_DBG2:
+		return 0;
+	case ACPITAB_FACS: /* ACPI 2.0/3.0: 1, ACPI 4.0 upto 6.3: 2 */
+		return 1;
+	case ACPITAB_RSDT: /* ACPI 1.0 upto 6.3: 1 */
+		return 1;
+	case ACPITAB_XSDT: /* ACPI 2.0 upto 6.3: 1 */
+		return 1;
+	case ACPITAB_RSDP: /* ACPI 2.0 upto 6.3: 2 */
+		return 2;
+	case ACPITAB_HEST:
+		return 1;
+	case ACPITAB_NHLT:
+		return 5;
+	case ACPITAB_BERT:
+		return 1;
+	default:
+		return -EINVAL;
+	}
+}
diff --git a/test/dm/acpi.c b/test/dm/acpi.c
index e3519d4689..e65295b7ca 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -7,6 +7,7 @@
  */
 
 #include <common.h>
+#include <acpi_table.h>
 #include <dm.h>
 #include <dm/acpi.h>
 #include <dm/test.h>
@@ -53,3 +54,16 @@ static int dm_test_acpi_get_name(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_get_name, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test acpi_get_table_revision() */
+static int dm_test_acpi_get_table_revision(struct unit_test_state *uts)
+{
+	ut_asserteq(1, acpi_get_table_revision(ACPITAB_MCFG));
+	ut_asserteq(2, acpi_get_table_revision(ACPITAB_RSDP));
+	ut_asserteq(4, acpi_get_table_revision(ACPITAB_TPM2));
+	ut_asserteq(-EINVAL, acpi_get_table_revision(ACPITAB_COUNT));
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_get_table_revision,
+	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 18/39] acpi: Add support for DMAR
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (16 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 17/39] acpi: Add a central location for table version numbers Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 19/39] acpi: Move acpi_fill_header() to generic code Simon Glass
                   ` (43 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

The DMA Remapping Reporting (DMAR) table contains information about DMA
remapping.

Add a version simple version of this table with only the minimum fields
filled out. i.e. no entries.

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- Drop two unnecessary __packed
- Move __packed to after struct

 include/acpi_table.h  | 57 +++++++++++++++++++++++++++++++++++++++++++
 lib/acpi/acpi_table.c | 26 ++++++++++++++++++++
 test/dm/acpi.c        | 14 +++++++++++
 3 files changed, 97 insertions(+)

diff --git a/include/acpi_table.h b/include/acpi_table.h
index ccf6fa04db..db84b79be5 100644
--- a/include/acpi_table.h
+++ b/include/acpi_table.h
@@ -21,6 +21,9 @@
 #define ACPI_RSDP_REV_ACPI_1_0	0
 #define ACPI_RSDP_REV_ACPI_2_0	2
 
+/* TODO(sjg at chromium.org): Figure out how to get compiler revision */
+#define ASL_REVISION	0
+
 #if !defined(__ACPI__)
 
 /*
@@ -360,6 +363,51 @@ struct acpi_csrt_shared_info {
 	u32 max_block_size;
 };
 
+enum dmar_type {
+	DMAR_DRHD = 0,
+	DMAR_RMRR = 1,
+	DMAR_ATSR = 2,
+	DMAR_RHSA = 3,
+	DMAR_ANDD = 4
+};
+
+enum {
+	DRHD_INCLUDE_PCI_ALL = 1
+};
+
+enum dmar_flags {
+	DMAR_INTR_REMAP			= 1 << 0,
+	DMAR_X2APIC_OPT_OUT		= 1 << 1,
+	DMA_CTRL_PLATFORM_OPT_IN_FLAG	= 1 << 2,
+};
+
+struct dmar_entry {
+	u16 type;
+	u16 length;
+	u8 flags;
+	u8 reserved;
+	u16 segment;
+	u64 bar;
+};
+
+struct dmar_rmrr_entry {
+	u16 type;
+	u16 length;
+	u16 reserved;
+	u16 segment;
+	u64 bar;
+	u64 limit;
+};
+
+/* DMAR (DMA Remapping Reporting Structure) */
+struct __packed acpi_dmar {
+	struct acpi_table_header header;
+	u8 host_address_width;
+	u8 flags;
+	u8 reserved[10];
+	struct dmar_entry structure[0];
+};
+
 /* DBG2 definitions are partially used for SPCR interface_type */
 
 /* Types for port_type field */
@@ -452,6 +500,15 @@ enum acpi_tables {
  */
 int acpi_get_table_revision(enum acpi_tables table);
 
+/**
+ * acpi_create_dmar() - Create a DMA Remapping Reporting (DMAR) table
+ *
+ * @dmar: Place to put the table
+ * @flags: DMAR flags to use
+ * @return 0 if OK, -ve on error
+ */
+int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags);
+
 #endif /* !__ACPI__*/
 
 #include <asm/acpi_table.h>
diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
index 197f965c08..ed312ac663 100644
--- a/lib/acpi/acpi_table.c
+++ b/lib/acpi/acpi_table.c
@@ -6,7 +6,33 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <acpi_table.h>
+#include <cpu.h>
+
+int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags)
+{
+	struct acpi_table_header *header = &dmar->header;
+	struct cpu_info info;
+	struct udevice *cpu;
+	int ret;
+
+	ret = uclass_first_device(UCLASS_CPU, &cpu);
+	if (ret)
+		return log_msg_ret("cpu", ret);
+	ret = cpu_get_info(cpu, &info);
+	memset((void *)dmar, 0, sizeof(struct acpi_dmar));
+
+	/* Fill out header fields. */
+	acpi_fill_header(&dmar->header, "DMAR");
+	header->length = sizeof(struct acpi_dmar);
+	header->revision = acpi_get_table_revision(ACPITAB_DMAR);
+
+	dmar->host_address_width = info.address_width - 1;
+	dmar->flags = flags;
+
+	return 0;
+}
 
 int acpi_get_table_revision(enum acpi_tables table)
 {
diff --git a/test/dm/acpi.c b/test/dm/acpi.c
index e65295b7ca..2737896643 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -67,3 +67,17 @@ static int dm_test_acpi_get_table_revision(struct unit_test_state *uts)
 }
 DM_TEST(dm_test_acpi_get_table_revision,
 	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test acpi_create_dmar() */
+static int dm_test_acpi_create_dmar(struct unit_test_state *uts)
+{
+	struct acpi_dmar dmar;
+
+	ut_assertok(acpi_create_dmar(&dmar, DMAR_INTR_REMAP));
+	ut_asserteq(DMAR_INTR_REMAP, dmar.flags);
+	ut_asserteq(DMAR_INTR_REMAP, dmar.flags);
+	ut_asserteq(32 - 1, dmar.host_address_width);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_create_dmar, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 19/39] acpi: Move acpi_fill_header() to generic code
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (17 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 18/39] acpi: Add support for DMAR Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 20/39] acpi: Add a method to write tables for a device Simon Glass
                   ` (42 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

This function needs to be used by sandbox for tests. Move it into the
generic directory.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---

Changes in v2: None

 arch/x86/lib/acpi_table.c |  9 ---------
 include/acpi_table.h      | 10 ++++++++++
 lib/acpi/acpi_table.c     | 10 ++++++++++
 test/dm/acpi.c            | 28 ++++++++++++++++++++++++++++
 4 files changed, 48 insertions(+), 9 deletions(-)

diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index 71913b6f65..487fef87f2 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -60,15 +60,6 @@ static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt,
 			sizeof(struct acpi_rsdp));
 }
 
-void acpi_fill_header(struct acpi_table_header *header, char *signature)
-{
-	memcpy(header->signature, signature, 4);
-	memcpy(header->oem_id, OEM_ID, 6);
-	memcpy(header->oem_table_id, OEM_TABLE_ID, 8);
-	header->oem_revision = U_BOOT_BUILD_DATE;
-	memcpy(header->aslc_id, ASLC_ID, 4);
-}
-
 static void acpi_write_rsdt(struct acpi_rsdt *rsdt)
 {
 	struct acpi_table_header *header = &(rsdt->header);
diff --git a/include/acpi_table.h b/include/acpi_table.h
index db84b79be5..3fd2ef16b0 100644
--- a/include/acpi_table.h
+++ b/include/acpi_table.h
@@ -509,6 +509,16 @@ int acpi_get_table_revision(enum acpi_tables table);
  */
 int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags);
 
+/**
+ * acpi_fill_header() - Set up a new table header
+ *
+ * This sets all fields except length, revision, checksum and aslc_revision
+ *
+ * @header: ACPI header to update
+ * @signature: Table signature to use (4 characters)
+ */
+void acpi_fill_header(struct acpi_table_header *header, char *signature);
+
 #endif /* !__ACPI__*/
 
 #include <asm/acpi_table.h>
diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
index ed312ac663..a86bfa6187 100644
--- a/lib/acpi/acpi_table.c
+++ b/lib/acpi/acpi_table.c
@@ -9,6 +9,7 @@
 #include <dm.h>
 #include <acpi_table.h>
 #include <cpu.h>
+#include <version.h>
 
 int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags)
 {
@@ -84,3 +85,12 @@ int acpi_get_table_revision(enum acpi_tables table)
 		return -EINVAL;
 	}
 }
+
+void acpi_fill_header(struct acpi_table_header *header, char *signature)
+{
+	memcpy(header->signature, signature, 4);
+	memcpy(header->oem_id, OEM_ID, 6);
+	memcpy(header->oem_table_id, OEM_TABLE_ID, 8);
+	header->oem_revision = U_BOOT_BUILD_DATE;
+	memcpy(header->aslc_id, ASLC_ID, 4);
+}
diff --git a/test/dm/acpi.c b/test/dm/acpi.c
index 2737896643..e28ebf4f90 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -9,6 +9,7 @@
 #include <common.h>
 #include <acpi_table.h>
 #include <dm.h>
+#include <version.h>
 #include <dm/acpi.h>
 #include <dm/test.h>
 #include <test/ut.h>
@@ -81,3 +82,30 @@ static int dm_test_acpi_create_dmar(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_create_dmar, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test acpi_fill_header() */
+static int dm_test_acpi_fill_header(struct unit_test_state *uts)
+{
+	struct acpi_table_header hdr;
+
+	/* Make sure these 5 fields are not changed */
+	hdr.length = 0x11;
+	hdr.revision = 0x22;
+	hdr.checksum = 0x33;
+	hdr.aslc_revision = 0x44;
+	acpi_fill_header(&hdr, "ABCD");
+
+	ut_assertok(memcmp("ABCD", hdr.signature, sizeof(hdr.signature)));
+	ut_asserteq(0x11, hdr.length);
+	ut_asserteq(0x22, hdr.revision);
+	ut_asserteq(0x33, hdr.checksum);
+	ut_assertok(memcmp(OEM_ID, hdr.oem_id, sizeof(hdr.oem_id)));
+	ut_assertok(memcmp(OEM_TABLE_ID, hdr.oem_table_id,
+			   sizeof(hdr.oem_table_id)));
+	ut_asserteq(U_BOOT_BUILD_DATE, hdr.oem_revision);
+	ut_assertok(memcmp(ASLC_ID, hdr.aslc_id, sizeof(hdr.aslc_id)));
+	ut_asserteq(0x44, hdr.aslc_revision);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_fill_header, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 20/39] acpi: Add a method to write tables for a device
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (18 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 19/39] acpi: Move acpi_fill_header() to generic code Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 21/39] acpi: Convert part of acpi_table to use acpi_ctx Simon Glass
                   ` (41 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

A device may want to write out ACPI tables to describe itself to Linux.
Add a method to permit this.

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

Changes in v2:
- Drop definition of ACPI_TABLE_CREATOR
- Make _acpi_write_dev_tables() static and switch argument order
- Generalise the ACPI function recursion with acpi_recurse_method()

 arch/sandbox/dts/test.dts |  4 +++
 drivers/core/acpi.c       | 61 +++++++++++++++++++++++++++++++++++++++
 include/dm/acpi.h         | 30 +++++++++++++++++++
 test/dm/acpi.c            | 43 +++++++++++++++++++++++++++
 4 files changed, 138 insertions(+)

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 5fa951ad4b..1204c14b07 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -210,6 +210,10 @@
 		compatible = "denx,u-boot-acpi-test";
 	};
 
+	acpi-test2 {
+		compatible = "denx,u-boot-acpi-test";
+	};
+
 	clocks {
 		clk_fixed: clk-fixed {
 			compatible = "fixed-clock";
diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c
index 45542199f5..10bac38c1d 100644
--- a/drivers/core/acpi.c
+++ b/drivers/core/acpi.c
@@ -11,8 +11,17 @@
 #include <common.h>
 #include <dm.h>
 #include <dm/acpi.h>
+#include <dm/device-internal.h>
 #include <dm/root.h>
 
+/* Type of method to call */
+enum method_t {
+	METHOD_WRITE_TABLES,
+};
+
+/* Prototype for all methods */
+typedef int (*acpi_method)(const struct udevice *dev, struct acpi_ctx *ctx);
+
 int acpi_return_name(char *out_name, const char *name)
 {
 	strcpy(out_name, name);
@@ -30,3 +39,55 @@ int acpi_get_name(const struct udevice *dev, char *out_name)
 
 	return -ENOSYS;
 }
+
+acpi_method acpi_get_method(struct udevice *dev, enum method_t method)
+{
+	struct acpi_ops *aops;
+
+	aops = device_get_acpi_ops(dev);
+	if (aops) {
+		switch (method) {
+		case METHOD_WRITE_TABLES:
+			return aops->write_tables;
+		}
+	}
+
+	return NULL;
+}
+
+int acpi_recurse_method(struct acpi_ctx *ctx, struct udevice *parent,
+			enum method_t method)
+{
+	struct udevice *dev;
+	acpi_method func;
+	int ret;
+
+	func = acpi_get_method(parent, method);
+	if (func) {
+		log_debug("\n- %s %p\n", parent->name, func);
+		ret = device_ofdata_to_platdata(parent);
+		if (ret)
+			return log_msg_ret("ofdata", ret);
+		ret = func(parent, ctx);
+		if (ret)
+			return log_msg_ret("func", ret);
+	}
+	device_foreach_child(dev, parent) {
+		ret = acpi_recurse_method(ctx, dev, method);
+		if (ret)
+			return log_msg_ret("recurse", ret);
+	}
+
+	return 0;
+}
+
+int acpi_write_dev_tables(struct acpi_ctx *ctx)
+{
+	int ret;
+
+	log_debug("Writing device tables\n");
+	ret = acpi_recurse_method(ctx, dm_root(), METHOD_WRITE_TABLES);
+	log_debug("Writing finished, err=%d\n", ret);
+
+	return ret;
+}
diff --git a/include/dm/acpi.h b/include/dm/acpi.h
index 8d6c3fd424..dcfcf5c347 100644
--- a/include/dm/acpi.h
+++ b/include/dm/acpi.h
@@ -24,6 +24,17 @@
 
 #if !defined(__ACPI__)
 
+/**
+ * struct acpi_ctx - Context used for writing ACPI tables
+ *
+ * This contains a few useful pieces of information used when writing
+ *
+ * @current: Current address for writing
+ */
+struct acpi_ctx {
+	void *current;
+};
+
 /**
  * struct acpi_ops - ACPI operations supported by driver model
  */
@@ -38,6 +49,15 @@ struct acpi_ops {
 	 *	other error
 	 */
 	int (*get_name)(const struct udevice *dev, char *out_name);
+
+	/**
+	 * write_tables() - Write out any tables required by this device
+	 *
+	 * @dev: Device to write
+	 * @ctx: ACPI context to use
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*write_tables)(const struct udevice *dev, struct acpi_ctx *ctx);
 };
 
 #define device_get_acpi_ops(dev)	((dev)->driver->acpi_ops)
@@ -72,6 +92,16 @@ int acpi_get_name(const struct udevice *dev, char *out_name);
  */
 int acpi_return_name(char *out_name, const char *name);
 
+/**
+ * acpi_write_dev_tables() - Write ACPI tables required by devices
+ *
+ * This scans through all devices and tells them to write any tables they want
+ * to write.
+ *
+ * @return 0 if OK, -ve if any device returned an error
+ */
+int acpi_write_dev_tables(struct acpi_ctx *ctx);
+
 #endif /* __ACPI__ */
 
 #endif
diff --git a/test/dm/acpi.c b/test/dm/acpi.c
index e28ebf4f90..b87fbd16b0 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -15,6 +15,19 @@
 #include <test/ut.h>
 
 #define ACPI_TEST_DEV_NAME	"ABCD"
+#define BUF_SIZE		4096
+
+static int testacpi_write_tables(const struct udevice *dev,
+				 struct acpi_ctx *ctx)
+{
+	struct acpi_dmar *dmar;
+
+	dmar = (struct acpi_dmar *)ctx->current;
+	acpi_create_dmar(dmar, DMAR_INTR_REMAP);
+	ctx->current += sizeof(struct acpi_dmar);
+
+	return 0;
+}
 
 static int testacpi_get_name(const struct udevice *dev, char *out_name)
 {
@@ -23,6 +36,7 @@ static int testacpi_get_name(const struct udevice *dev, char *out_name)
 
 struct acpi_ops testacpi_ops = {
 	.get_name	= testacpi_get_name,
+	.write_tables	= testacpi_write_tables,
 };
 
 static const struct udevice_id testacpi_ids[] = {
@@ -109,3 +123,32 @@ static int dm_test_acpi_fill_header(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_fill_header, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test ACPI write_tables() */
+static int dm_test_acpi_write_tables(struct unit_test_state *uts)
+{
+	struct acpi_dmar *dmar;
+	struct acpi_ctx ctx;
+	void *buf;
+
+	buf = malloc(BUF_SIZE);
+	ut_assertnonnull(buf);
+
+	ctx.current = buf;
+	ut_assertok(acpi_write_dev_tables(&ctx));
+	dmar = buf;
+
+	/*
+	 * We should have two dmar tables, one for each "denx,u-boot-acpi-test"
+	 * device
+	 */
+	ut_asserteq_ptr(dmar + 2, ctx.current);
+	ut_asserteq(DMAR_INTR_REMAP, dmar->flags);
+	ut_asserteq(32 - 1, dmar->host_address_width);
+
+	ut_asserteq(DMAR_INTR_REMAP, dmar[1].flags);
+	ut_asserteq(32 - 1, dmar[1].host_address_width);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_write_tables, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 21/39] acpi: Convert part of acpi_table to use acpi_ctx
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (19 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 20/39] acpi: Add a method to write tables for a device Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 22/39] x86: Allow devices to write ACPI tables Simon Glass
                   ` (40 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

The current code uses an address but a pointer would result in fewer
casts. Also it repeats the alignment code in a lot of places so this would
be better done in a helper function.

Update write_acpi_tables() to make use of the new acpi_ctx structure,
adding a few helpers to clean things up.

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

Changes in v2: None

 arch/x86/lib/acpi_table.c | 88 +++++++++++++++++++--------------------
 include/acpi_table.h      | 36 ++++++++++++++++
 lib/acpi/acpi_table.c     | 22 ++++++++++
 test/dm/acpi.c            | 28 +++++++++++++
 4 files changed, 129 insertions(+), 45 deletions(-)

diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index 487fef87f2..8e13d6a3e6 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -10,6 +10,7 @@
 #include <cpu.h>
 #include <dm.h>
 #include <dm/uclass-internal.h>
+#include <mapmem.h>
 #include <serial.h>
 #include <version.h>
 #include <asm/acpi/global_nvs.h>
@@ -19,6 +20,7 @@
 #include <asm/mpspec.h>
 #include <asm/tables.h>
 #include <asm/arch/global_nvs.h>
+#include <dm/acpi.h>
 
 /*
  * IASL compiles the dsdt entries and writes the hex values
@@ -468,9 +470,9 @@ static void acpi_create_spcr(struct acpi_spcr *spcr)
 /*
  * QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c
  */
-ulong write_acpi_tables(ulong start)
+ulong write_acpi_tables(ulong start_addr)
 {
-	u32 current;
+	struct acpi_ctx sctx, *ctx = &sctx;
 	struct acpi_rsdp *rsdp;
 	struct acpi_rsdt *rsdt;
 	struct acpi_xsdt *xsdt;
@@ -481,60 +483,61 @@ ulong write_acpi_tables(ulong start)
 	struct acpi_madt *madt;
 	struct acpi_csrt *csrt;
 	struct acpi_spcr *spcr;
+	void *start;
+	ulong addr;
 	int i;
 
-	current = start;
+	start = map_sysmem(start_addr, 0);
+	ctx->current = start;
 
 	/* Align ACPI tables to 16 byte */
-	current = ALIGN(current, 16);
+	acpi_align(ctx);
 
-	debug("ACPI: Writing ACPI tables at %lx\n", start);
+	debug("ACPI: Writing ACPI tables at %lx\n", start_addr);
 
 	/* We need at least an RSDP and an RSDT Table */
-	rsdp = (struct acpi_rsdp *)current;
-	current += sizeof(struct acpi_rsdp);
-	current = ALIGN(current, 16);
-	rsdt = (struct acpi_rsdt *)current;
-	current += sizeof(struct acpi_rsdt);
-	current = ALIGN(current, 16);
-	xsdt = (struct acpi_xsdt *)current;
-	current += sizeof(struct acpi_xsdt);
+	rsdp = ctx->current;
+	acpi_inc_align(ctx, sizeof(struct acpi_rsdp));
+	rsdt = ctx->current;
+	acpi_inc_align(ctx, sizeof(struct acpi_rsdt));
+	xsdt = ctx->current;
+	acpi_inc_align(ctx, sizeof(struct acpi_xsdt));
 	/*
 	 * Per ACPI spec, the FACS table address must be aligned to a 64 byte
 	 * boundary (Windows checks this, but Linux does not).
 	 */
-	current = ALIGN(current, 64);
+	acpi_align_large(ctx);
 
 	/* clear all table memory */
-	memset((void *)start, 0, current - start);
+	memset((void *)start, 0, ctx->current - start);
 
 	acpi_write_rsdp(rsdp, rsdt, xsdt);
 	acpi_write_rsdt(rsdt);
 	acpi_write_xsdt(xsdt);
 
 	debug("ACPI:    * FACS\n");
-	facs = (struct acpi_facs *)current;
-	current += sizeof(struct acpi_facs);
-	current = ALIGN(current, 16);
+	facs = ctx->current;
+	acpi_inc_align(ctx, sizeof(struct acpi_facs));
 
 	acpi_create_facs(facs);
 
 	debug("ACPI:    * DSDT\n");
-	dsdt = (struct acpi_table_header *)current;
+	dsdt = ctx->current;
 	memcpy(dsdt, &AmlCode, sizeof(struct acpi_table_header));
-	current += sizeof(struct acpi_table_header);
-	memcpy((char *)current,
+	acpi_inc(ctx, sizeof(struct acpi_table_header));
+	memcpy(ctx->current,
 	       (char *)&AmlCode + sizeof(struct acpi_table_header),
 	       dsdt->length - sizeof(struct acpi_table_header));
-	current += dsdt->length - sizeof(struct acpi_table_header);
-	current = ALIGN(current, 16);
+	acpi_inc_align(ctx, dsdt->length - sizeof(struct acpi_table_header));
 
 	/* Pack GNVS into the ACPI table area */
 	for (i = 0; i < dsdt->length; i++) {
 		u32 *gnvs = (u32 *)((u32)dsdt + i);
 		if (*gnvs == ACPI_GNVS_ADDR) {
-			debug("Fix up global NVS in DSDT to 0x%08x\n", current);
-			*gnvs = current;
+			ulong addr = (ulong)map_to_sysmem(ctx->current);
+
+			debug("Fix up global NVS in DSDT to %#08lx\n", addr);
+			*gnvs = addr;
 			break;
 		}
 	}
@@ -544,51 +547,46 @@ ulong write_acpi_tables(ulong start)
 	dsdt->checksum = table_compute_checksum((void *)dsdt, dsdt->length);
 
 	/* Fill in platform-specific global NVS variables */
-	acpi_create_gnvs((struct acpi_global_nvs *)current);
-	current += sizeof(struct acpi_global_nvs);
-	current = ALIGN(current, 16);
+	acpi_create_gnvs(ctx->current);
+	acpi_inc_align(ctx, sizeof(struct acpi_global_nvs));
 
 	debug("ACPI:    * FADT\n");
-	fadt = (struct acpi_fadt *)current;
-	current += sizeof(struct acpi_fadt);
-	current = ALIGN(current, 16);
+	fadt = ctx->current;
+	acpi_inc_align(ctx, sizeof(struct acpi_fadt));
 	acpi_create_fadt(fadt, facs, dsdt);
 	acpi_add_table(rsdp, fadt);
 
 	debug("ACPI:    * MADT\n");
-	madt = (struct acpi_madt *)current;
+	madt = ctx->current;
 	acpi_create_madt(madt);
-	current += madt->header.length;
+	acpi_inc_align(ctx, madt->header.length);
 	acpi_add_table(rsdp, madt);
-	current = ALIGN(current, 16);
 
 	debug("ACPI:    * MCFG\n");
-	mcfg = (struct acpi_mcfg *)current;
+	mcfg = ctx->current;
 	acpi_create_mcfg(mcfg);
-	current += mcfg->header.length;
+	acpi_inc_align(ctx, mcfg->header.length);
 	acpi_add_table(rsdp, mcfg);
-	current = ALIGN(current, 16);
 
 	debug("ACPI:    * CSRT\n");
-	csrt = (struct acpi_csrt *)current;
+	csrt = ctx->current;
 	acpi_create_csrt(csrt);
-	current += csrt->header.length;
+	acpi_inc_align(ctx, csrt->header.length);
 	acpi_add_table(rsdp, csrt);
-	current = ALIGN(current, 16);
 
 	debug("ACPI:    * SPCR\n");
-	spcr = (struct acpi_spcr *)current;
+	spcr = ctx->current;
 	acpi_create_spcr(spcr);
-	current += spcr->header.length;
+	acpi_inc_align(ctx, spcr->header.length);
 	acpi_add_table(rsdp, spcr);
-	current = ALIGN(current, 16);
 
-	debug("current = %x\n", current);
+	addr = map_to_sysmem(ctx->current);
+	debug("current = %lx\n", addr);
 
 	acpi_rsdp_addr = (unsigned long)rsdp;
 	debug("ACPI: done\n");
 
-	return current;
+	return addr;
 }
 
 ulong acpi_get_rsdp_addr(void)
diff --git a/include/acpi_table.h b/include/acpi_table.h
index 3fd2ef16b0..5fd0fa71a6 100644
--- a/include/acpi_table.h
+++ b/include/acpi_table.h
@@ -26,6 +26,8 @@
 
 #if !defined(__ACPI__)
 
+struct acpi_ctx;
+
 /*
  * RSDP (Root System Description Pointer)
  * Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum
@@ -519,6 +521,40 @@ int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags);
  */
 void acpi_fill_header(struct acpi_table_header *header, char *signature);
 
+/**
+ * acpi_align() - Align the ACPI output pointer to a 16-byte boundary
+ *
+ * @ctx: ACPI context
+ */
+void acpi_align(struct acpi_ctx *ctx);
+
+/**
+ * acpi_align_large() - Align the ACPI output pointer to a 64-byte boundary
+ *
+ * @ctx: ACPI context
+ */
+void acpi_align_large(struct acpi_ctx *ctx);
+
+/**
+ * acpi_inc() - Increment the ACPI output pointer by a bit
+ *
+ * The pointer is NOT aligned afterwards.
+ *
+ * @ctx: ACPI context
+ * @amount: Amount to increment by
+ */
+void acpi_inc(struct acpi_ctx *ctx, uint amount);
+
+/**
+ * acpi_inc_align() - Increment the ACPI output pointer by a bit and align
+ *
+ * The pointer is aligned afterwards.
+ *
+ * @ctx: ACPI context
+ * @amount: Amount to increment by
+ */
+void acpi_inc_align(struct acpi_ctx *ctx, uint amount);
+
 #endif /* !__ACPI__*/
 
 #include <asm/acpi_table.h>
diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
index a86bfa6187..3d24cc26b6 100644
--- a/lib/acpi/acpi_table.c
+++ b/lib/acpi/acpi_table.c
@@ -10,6 +10,7 @@
 #include <acpi_table.h>
 #include <cpu.h>
 #include <version.h>
+#include <dm/acpi.h>
 
 int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags)
 {
@@ -94,3 +95,24 @@ void acpi_fill_header(struct acpi_table_header *header, char *signature)
 	header->oem_revision = U_BOOT_BUILD_DATE;
 	memcpy(header->aslc_id, ASLC_ID, 4);
 }
+
+void acpi_align(struct acpi_ctx *ctx)
+{
+	ctx->current = (void *)ALIGN((ulong)ctx->current, 16);
+}
+
+void acpi_align_large(struct acpi_ctx *ctx)
+{
+	ctx->current = (void *)ALIGN((ulong)ctx->current, 64);
+}
+
+void acpi_inc(struct acpi_ctx *ctx, uint amount)
+{
+	ctx->current += amount;
+}
+
+void acpi_inc_align(struct acpi_ctx *ctx, uint amount)
+{
+	ctx->current += amount;
+	acpi_align(ctx);
+}
diff --git a/test/dm/acpi.c b/test/dm/acpi.c
index b87fbd16b0..0bd7e51ac9 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -152,3 +152,31 @@ static int dm_test_acpi_write_tables(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_write_tables, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test basic ACPI functions */
+static int dm_test_acpi_basic(struct unit_test_state *uts)
+{
+	struct acpi_ctx ctx;
+
+	/* Check align works */
+	ctx.current = (void *)5;
+	acpi_align(&ctx);
+	ut_asserteq_ptr((void *)16, ctx.current);
+
+	/* Check that align does nothing if already aligned */
+	acpi_align(&ctx);
+	ut_asserteq_ptr((void *)16, ctx.current);
+	acpi_align_large(&ctx);
+	ut_asserteq_ptr((void *)64, ctx.current);
+	acpi_align_large(&ctx);
+	ut_asserteq_ptr((void *)64, ctx.current);
+
+	/* Check incrementing */
+	acpi_inc(&ctx, 3);
+	ut_asserteq_ptr((void *)67, ctx.current);
+	acpi_inc_align(&ctx, 3);
+	ut_asserteq_ptr((void *)80, ctx.current);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_basic, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 22/39] x86: Allow devices to write ACPI tables
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (20 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 21/39] acpi: Convert part of acpi_table to use acpi_ctx Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 23/39] acpi: Drop code for missing XSDT from acpi_write_rsdp() Simon Glass
                   ` (39 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

Call the new core function to permit devices to write their own ACPI
tables. These tables will appear after all other tables.

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

Changes in v2: None

 arch/x86/lib/acpi_table.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index 8e13d6a3e6..964f10a7cb 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -580,6 +580,8 @@ ulong write_acpi_tables(ulong start_addr)
 	acpi_inc_align(ctx, spcr->header.length);
 	acpi_add_table(rsdp, spcr);
 
+	acpi_write_dev_tables(ctx);
+
 	addr = map_to_sysmem(ctx->current);
 	debug("current = %lx\n", addr);
 
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 23/39] acpi: Drop code for missing XSDT from acpi_write_rsdp()
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (21 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 22/39] x86: Allow devices to write ACPI tables Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 24/39] acpi: Move acpi_add_table() to generic code Simon Glass
                   ` (38 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

We don't actually support tables without an XSDT so we can drop this dead
code.

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

Changes in v2: None

 arch/x86/lib/acpi_table.c | 15 ++-------------
 1 file changed, 2 insertions(+), 13 deletions(-)

diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index 964f10a7cb..0757ac3431 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -42,19 +42,8 @@ static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt,
 	rsdp->length = sizeof(struct acpi_rsdp);
 	rsdp->rsdt_address = (u32)rsdt;
 
-	/*
-	 * Revision: ACPI 1.0: 0, ACPI 2.0/3.0/4.0: 2
-	 *
-	 * Some OSes expect an XSDT to be present for RSD PTR revisions >= 2.
-	 * If we don't have an ACPI XSDT, force ACPI 1.0 (and thus RSD PTR
-	 * revision 0)
-	 */
-	if (xsdt == NULL) {
-		rsdp->revision = ACPI_RSDP_REV_ACPI_1_0;
-	} else {
-		rsdp->xsdt_address = (u64)(u32)xsdt;
-		rsdp->revision = ACPI_RSDP_REV_ACPI_2_0;
-	}
+	rsdp->xsdt_address = (u64)(u32)xsdt;
+	rsdp->revision = ACPI_RSDP_REV_ACPI_2_0;
 
 	/* Calculate checksums */
 	rsdp->checksum = table_compute_checksum((void *)rsdp, 20);
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 24/39] acpi: Move acpi_add_table() to generic code
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (22 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 23/39] acpi: Drop code for missing XSDT from acpi_write_rsdp() Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 25/39] acpi: Put table-setup code in its own function Simon Glass
                   ` (37 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

Move this code to a generic location so that we can test it with sandbox.
This requires adding a few new fields to acpi_ctx, so drop the local
variables used in the original code.

Also use mapmem to avoid pointer-to-address casts which don't work on
sandbox.

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

Changes in v2: None

 arch/x86/lib/acpi_table.c | 82 +++++----------------------------------
 include/acpi_table.h      |  9 +++++
 include/dm/acpi.h         |  5 +++
 lib/acpi/acpi_table.c     | 64 ++++++++++++++++++++++++++++++
 test/dm/acpi.c            |  4 ++
 5 files changed, 92 insertions(+), 72 deletions(-)

diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index 0757ac3431..9168119547 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -83,66 +83,6 @@ static void acpi_write_xsdt(struct acpi_xsdt *xsdt)
 			sizeof(struct acpi_xsdt));
 }
 
-/**
- * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length
- * and checksum.
- */
-static void acpi_add_table(struct acpi_rsdp *rsdp, void *table)
-{
-	int i, entries_num;
-	struct acpi_rsdt *rsdt;
-	struct acpi_xsdt *xsdt = NULL;
-
-	/* The RSDT is mandatory while the XSDT is not */
-	rsdt = (struct acpi_rsdt *)rsdp->rsdt_address;
-
-	if (rsdp->xsdt_address)
-		xsdt = (struct acpi_xsdt *)((u32)rsdp->xsdt_address);
-
-	/* This should always be MAX_ACPI_TABLES */
-	entries_num = ARRAY_SIZE(rsdt->entry);
-
-	for (i = 0; i < entries_num; i++) {
-		if (rsdt->entry[i] == 0)
-			break;
-	}
-
-	if (i >= entries_num) {
-		debug("ACPI: Error: too many tables\n");
-		return;
-	}
-
-	/* Add table to the RSDT */
-	rsdt->entry[i] = (u32)table;
-
-	/* Fix RSDT length or the kernel will assume invalid entries */
-	rsdt->header.length = sizeof(struct acpi_table_header) +
-				(sizeof(u32) * (i + 1));
-
-	/* Re-calculate checksum */
-	rsdt->header.checksum = 0;
-	rsdt->header.checksum = table_compute_checksum((u8 *)rsdt,
-			rsdt->header.length);
-
-	/*
-	 * And now the same thing for the XSDT. We use the same index as for
-	 * now we want the XSDT and RSDT to always be in sync in U-Boot
-	 */
-	if (xsdt) {
-		/* Add table to the XSDT */
-		xsdt->entry[i] = (u64)(u32)table;
-
-		/* Fix XSDT length */
-		xsdt->header.length = sizeof(struct acpi_table_header) +
-			(sizeof(u64) * (i + 1));
-
-		/* Re-calculate checksum */
-		xsdt->header.checksum = 0;
-		xsdt->header.checksum = table_compute_checksum((u8 *)xsdt,
-				xsdt->header.length);
-	}
-}
-
 static void acpi_create_facs(struct acpi_facs *facs)
 {
 	memset((void *)facs, 0, sizeof(struct acpi_facs));
@@ -462,8 +402,6 @@ static void acpi_create_spcr(struct acpi_spcr *spcr)
 ulong write_acpi_tables(ulong start_addr)
 {
 	struct acpi_ctx sctx, *ctx = &sctx;
-	struct acpi_rsdp *rsdp;
-	struct acpi_rsdt *rsdt;
 	struct acpi_xsdt *xsdt;
 	struct acpi_facs *facs;
 	struct acpi_table_header *dsdt;
@@ -485,9 +423,9 @@ ulong write_acpi_tables(ulong start_addr)
 	debug("ACPI: Writing ACPI tables at %lx\n", start_addr);
 
 	/* We need at least an RSDP and an RSDT Table */
-	rsdp = ctx->current;
+	ctx->rsdp = ctx->current;
 	acpi_inc_align(ctx, sizeof(struct acpi_rsdp));
-	rsdt = ctx->current;
+	ctx->rsdt = ctx->current;
 	acpi_inc_align(ctx, sizeof(struct acpi_rsdt));
 	xsdt = ctx->current;
 	acpi_inc_align(ctx, sizeof(struct acpi_xsdt));
@@ -500,8 +438,8 @@ ulong write_acpi_tables(ulong start_addr)
 	/* clear all table memory */
 	memset((void *)start, 0, ctx->current - start);
 
-	acpi_write_rsdp(rsdp, rsdt, xsdt);
-	acpi_write_rsdt(rsdt);
+	acpi_write_rsdp(ctx->rsdp, ctx->rsdt, xsdt);
+	acpi_write_rsdt(ctx->rsdt);
 	acpi_write_xsdt(xsdt);
 
 	debug("ACPI:    * FACS\n");
@@ -543,38 +481,38 @@ ulong write_acpi_tables(ulong start_addr)
 	fadt = ctx->current;
 	acpi_inc_align(ctx, sizeof(struct acpi_fadt));
 	acpi_create_fadt(fadt, facs, dsdt);
-	acpi_add_table(rsdp, fadt);
+	acpi_add_table(ctx, fadt);
 
 	debug("ACPI:    * MADT\n");
 	madt = ctx->current;
 	acpi_create_madt(madt);
 	acpi_inc_align(ctx, madt->header.length);
-	acpi_add_table(rsdp, madt);
+	acpi_add_table(ctx, madt);
 
 	debug("ACPI:    * MCFG\n");
 	mcfg = ctx->current;
 	acpi_create_mcfg(mcfg);
 	acpi_inc_align(ctx, mcfg->header.length);
-	acpi_add_table(rsdp, mcfg);
+	acpi_add_table(ctx, mcfg);
 
 	debug("ACPI:    * CSRT\n");
 	csrt = ctx->current;
 	acpi_create_csrt(csrt);
 	acpi_inc_align(ctx, csrt->header.length);
-	acpi_add_table(rsdp, csrt);
+	acpi_add_table(ctx, csrt);
 
 	debug("ACPI:    * SPCR\n");
 	spcr = ctx->current;
 	acpi_create_spcr(spcr);
 	acpi_inc_align(ctx, spcr->header.length);
-	acpi_add_table(rsdp, spcr);
+	acpi_add_table(ctx, spcr);
 
 	acpi_write_dev_tables(ctx);
 
 	addr = map_to_sysmem(ctx->current);
 	debug("current = %lx\n", addr);
 
-	acpi_rsdp_addr = (unsigned long)rsdp;
+	acpi_rsdp_addr = (unsigned long)ctx->rsdp;
 	debug("ACPI: done\n");
 
 	return addr;
diff --git a/include/acpi_table.h b/include/acpi_table.h
index 5fd0fa71a6..2131484880 100644
--- a/include/acpi_table.h
+++ b/include/acpi_table.h
@@ -555,6 +555,15 @@ void acpi_inc(struct acpi_ctx *ctx, uint amount);
  */
 void acpi_inc_align(struct acpi_ctx *ctx, uint amount);
 
+/**
+ * acpi_add_table() - Add a new table to the RSDP and XSDT
+ *
+ * @ctx: ACPI context
+ * @table: Table to add
+ * @return 0 if OK, -E2BIG if too many tables
+ */
+int acpi_add_table(struct acpi_ctx *ctx, void *table);
+
 #endif /* !__ACPI__*/
 
 #include <asm/acpi_table.h>
diff --git a/include/dm/acpi.h b/include/dm/acpi.h
index dcfcf5c347..4465e62848 100644
--- a/include/dm/acpi.h
+++ b/include/dm/acpi.h
@@ -30,9 +30,14 @@
  * This contains a few useful pieces of information used when writing
  *
  * @current: Current address for writing
+ * @rsdp: Pointer to the Root System Description Pointer, typically used when
+ *	adding a new table. The RSDP holds pointers to the RSDP and XSDT.
+ * @rsdt: Pointer to the Root System Description Table
  */
 struct acpi_ctx {
 	void *current;
+	struct acpi_rsdp *rsdp;
+	struct acpi_rsdt *rsdt;
 };
 
 /**
diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
index 3d24cc26b6..00e80ac39a 100644
--- a/lib/acpi/acpi_table.c
+++ b/lib/acpi/acpi_table.c
@@ -9,6 +9,8 @@
 #include <dm.h>
 #include <acpi_table.h>
 #include <cpu.h>
+#include <mapmem.h>
+#include <tables_csum.h>
 #include <version.h>
 #include <dm/acpi.h>
 
@@ -116,3 +118,65 @@ void acpi_inc_align(struct acpi_ctx *ctx, uint amount)
 	ctx->current += amount;
 	acpi_align(ctx);
 }
+
+/**
+ * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length
+ * and checksum.
+ */
+int acpi_add_table(struct acpi_ctx *ctx, void *table)
+{
+	int i, entries_num;
+	struct acpi_rsdt *rsdt;
+	struct acpi_xsdt *xsdt = NULL;
+
+	/* The RSDT is mandatory while the XSDT is not */
+	rsdt = ctx->rsdt;
+
+	if (ctx->rsdp->xsdt_address)
+		xsdt = map_sysmem(ctx->rsdp->xsdt_address, 0);
+
+	/* This should always be MAX_ACPI_TABLES */
+	entries_num = ARRAY_SIZE(rsdt->entry);
+
+	for (i = 0; i < entries_num; i++) {
+		if (rsdt->entry[i] == 0)
+			break;
+	}
+
+	if (i >= entries_num) {
+		debug("ACPI: Error: too many tables\n");
+		return -E2BIG;
+	}
+
+	/* Add table to the RSDT */
+	rsdt->entry[i] = map_to_sysmem(table);
+
+	/* Fix RSDT length or the kernel will assume invalid entries */
+	rsdt->header.length = sizeof(struct acpi_table_header) +
+				(sizeof(u32) * (i + 1));
+
+	/* Re-calculate checksum */
+	rsdt->header.checksum = 0;
+	rsdt->header.checksum = table_compute_checksum((u8 *)rsdt,
+						       rsdt->header.length);
+
+	/*
+	 * And now the same thing for the XSDT. We use the same index as for
+	 * now we want the XSDT and RSDT to always be in sync in U-Boot
+	 */
+	if (xsdt) {
+		/* Add table to the XSDT */
+		xsdt->entry[i] = map_to_sysmem(table);
+
+		/* Fix XSDT length */
+		xsdt->header.length = sizeof(struct acpi_table_header) +
+			(sizeof(u64) * (i + 1));
+
+		/* Re-calculate checksum */
+		xsdt->header.checksum = 0;
+		xsdt->header.checksum =
+			table_compute_checksum((u8 *)xsdt, xsdt->header.length);
+	}
+
+	return 0;
+}
diff --git a/test/dm/acpi.c b/test/dm/acpi.c
index 0bd7e51ac9..a2a57a29a6 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -21,10 +21,14 @@ static int testacpi_write_tables(const struct udevice *dev,
 				 struct acpi_ctx *ctx)
 {
 	struct acpi_dmar *dmar;
+	int ret;
 
 	dmar = (struct acpi_dmar *)ctx->current;
 	acpi_create_dmar(dmar, DMAR_INTR_REMAP);
 	ctx->current += sizeof(struct acpi_dmar);
+	ret = acpi_add_table(ctx, dmar);
+	if (ret)
+		return log_msg_ret("add", ret);
 
 	return 0;
 }
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 25/39] acpi: Put table-setup code in its own function
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (23 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 24/39] acpi: Move acpi_add_table() to generic code Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 26/39] acpi: Move the xsdt pointer to acpi_ctx Simon Glass
                   ` (36 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

We always write three basic tables to ACPI at the start. Move this into
its own function, along with acpi_fill_header(), so we can write a test
for this code.

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

Changes in v2: None

 arch/x86/lib/acpi_table.c | 77 +----------------------------------
 include/acpi_table.h      | 10 +++++
 lib/acpi/acpi_table.c     | 86 ++++++++++++++++++++++++++++++++++++++-
 test/dm/acpi.c            | 55 ++++++++++++++++++++++++-
 4 files changed, 148 insertions(+), 80 deletions(-)

diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index 9168119547..83b92e2a4c 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -31,58 +31,6 @@ extern const unsigned char AmlCode[];
 /* ACPI RSDP address to be used in boot parameters */
 static ulong acpi_rsdp_addr;
 
-static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt,
-			    struct acpi_xsdt *xsdt)
-{
-	memset(rsdp, 0, sizeof(struct acpi_rsdp));
-
-	memcpy(rsdp->signature, RSDP_SIG, 8);
-	memcpy(rsdp->oem_id, OEM_ID, 6);
-
-	rsdp->length = sizeof(struct acpi_rsdp);
-	rsdp->rsdt_address = (u32)rsdt;
-
-	rsdp->xsdt_address = (u64)(u32)xsdt;
-	rsdp->revision = ACPI_RSDP_REV_ACPI_2_0;
-
-	/* Calculate checksums */
-	rsdp->checksum = table_compute_checksum((void *)rsdp, 20);
-	rsdp->ext_checksum = table_compute_checksum((void *)rsdp,
-			sizeof(struct acpi_rsdp));
-}
-
-static void acpi_write_rsdt(struct acpi_rsdt *rsdt)
-{
-	struct acpi_table_header *header = &(rsdt->header);
-
-	/* Fill out header fields */
-	acpi_fill_header(header, "RSDT");
-	header->length = sizeof(struct acpi_rsdt);
-	header->revision = 1;
-
-	/* Entries are filled in later, we come with an empty set */
-
-	/* Fix checksum */
-	header->checksum = table_compute_checksum((void *)rsdt,
-			sizeof(struct acpi_rsdt));
-}
-
-static void acpi_write_xsdt(struct acpi_xsdt *xsdt)
-{
-	struct acpi_table_header *header = &(xsdt->header);
-
-	/* Fill out header fields */
-	acpi_fill_header(header, "XSDT");
-	header->length = sizeof(struct acpi_xsdt);
-	header->revision = 1;
-
-	/* Entries are filled in later, we come with an empty set */
-
-	/* Fix checksum */
-	header->checksum = table_compute_checksum((void *)xsdt,
-			sizeof(struct acpi_xsdt));
-}
-
 static void acpi_create_facs(struct acpi_facs *facs)
 {
 	memset((void *)facs, 0, sizeof(struct acpi_facs));
@@ -402,7 +350,6 @@ static void acpi_create_spcr(struct acpi_spcr *spcr)
 ulong write_acpi_tables(ulong start_addr)
 {
 	struct acpi_ctx sctx, *ctx = &sctx;
-	struct acpi_xsdt *xsdt;
 	struct acpi_facs *facs;
 	struct acpi_table_header *dsdt;
 	struct acpi_fadt *fadt;
@@ -415,32 +362,10 @@ ulong write_acpi_tables(ulong start_addr)
 	int i;
 
 	start = map_sysmem(start_addr, 0);
-	ctx->current = start;
-
-	/* Align ACPI tables to 16 byte */
-	acpi_align(ctx);
 
 	debug("ACPI: Writing ACPI tables at %lx\n", start_addr);
 
-	/* We need at least an RSDP and an RSDT Table */
-	ctx->rsdp = ctx->current;
-	acpi_inc_align(ctx, sizeof(struct acpi_rsdp));
-	ctx->rsdt = ctx->current;
-	acpi_inc_align(ctx, sizeof(struct acpi_rsdt));
-	xsdt = ctx->current;
-	acpi_inc_align(ctx, sizeof(struct acpi_xsdt));
-	/*
-	 * Per ACPI spec, the FACS table address must be aligned to a 64 byte
-	 * boundary (Windows checks this, but Linux does not).
-	 */
-	acpi_align_large(ctx);
-
-	/* clear all table memory */
-	memset((void *)start, 0, ctx->current - start);
-
-	acpi_write_rsdp(ctx->rsdp, ctx->rsdt, xsdt);
-	acpi_write_rsdt(ctx->rsdt);
-	acpi_write_xsdt(xsdt);
+	acpi_setup_base_tables(ctx, start);
 
 	debug("ACPI:    * FACS\n");
 	facs = ctx->current;
diff --git a/include/acpi_table.h b/include/acpi_table.h
index 2131484880..f500f0d3fe 100644
--- a/include/acpi_table.h
+++ b/include/acpi_table.h
@@ -564,6 +564,16 @@ void acpi_inc_align(struct acpi_ctx *ctx, uint amount);
  */
 int acpi_add_table(struct acpi_ctx *ctx, void *table);
 
+/**
+ * acpi_setup_base_tables() - Set up context along with RSDP, RSDT and XDST
+ *
+ * Set up the context with the given start position. Some basic tables are
+ * always needed, so set them up as well.
+ *
+ * @ctx: Context to set up
+ */
+void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start);
+
 #endif /* !__ACPI__*/
 
 #include <asm/acpi_table.h>
diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
index 00e80ac39a..9f452a65ce 100644
--- a/lib/acpi/acpi_table.c
+++ b/lib/acpi/acpi_table.c
@@ -157,7 +157,7 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table)
 
 	/* Re-calculate checksum */
 	rsdt->header.checksum = 0;
-	rsdt->header.checksum = table_compute_checksum((u8 *)rsdt,
+	rsdt->header.checksum = table_compute_checksum(rsdt,
 						       rsdt->header.length);
 
 	/*
@@ -175,8 +175,90 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table)
 		/* Re-calculate checksum */
 		xsdt->header.checksum = 0;
 		xsdt->header.checksum =
-			table_compute_checksum((u8 *)xsdt, xsdt->header.length);
+			table_compute_checksum(xsdt, xsdt->header.length);
 	}
 
 	return 0;
 }
+
+static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt,
+			    struct acpi_xsdt *xsdt)
+{
+	memset(rsdp, 0, sizeof(struct acpi_rsdp));
+
+	memcpy(rsdp->signature, RSDP_SIG, 8);
+	memcpy(rsdp->oem_id, OEM_ID, 6);
+
+	rsdp->length = sizeof(struct acpi_rsdp);
+	rsdp->rsdt_address = map_to_sysmem(rsdt);
+
+	rsdp->xsdt_address = map_to_sysmem(xsdt);
+	rsdp->revision = ACPI_RSDP_REV_ACPI_2_0;
+
+	/* Calculate checksums */
+	rsdp->checksum = table_compute_checksum(rsdp, 20);
+	rsdp->ext_checksum = table_compute_checksum(rsdp,
+						    sizeof(struct acpi_rsdp));
+}
+
+static void acpi_write_rsdt(struct acpi_rsdt *rsdt)
+{
+	struct acpi_table_header *header = &rsdt->header;
+
+	/* Fill out header fields */
+	acpi_fill_header(header, "RSDT");
+	header->length = sizeof(struct acpi_rsdt);
+	header->revision = 1;
+
+	/* Entries are filled in later, we come with an empty set */
+
+	/* Fix checksum */
+	header->checksum = table_compute_checksum(rsdt,
+						  sizeof(struct acpi_rsdt));
+}
+
+static void acpi_write_xsdt(struct acpi_xsdt *xsdt)
+{
+	struct acpi_table_header *header = &xsdt->header;
+
+	/* Fill out header fields */
+	acpi_fill_header(header, "XSDT");
+	header->length = sizeof(struct acpi_xsdt);
+	header->revision = 1;
+
+	/* Entries are filled in later, we come with an empty set */
+
+	/* Fix checksum */
+	header->checksum = table_compute_checksum(xsdt,
+						  sizeof(struct acpi_xsdt));
+}
+
+void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start)
+{
+	struct acpi_xsdt *xsdt;
+
+	ctx->current = start;
+
+	/* Align ACPI tables to 16 byte */
+	acpi_align(ctx);
+
+	/* We need at least an RSDP and an RSDT Table */
+	ctx->rsdp = ctx->current;
+	acpi_inc_align(ctx, sizeof(struct acpi_rsdp));
+	ctx->rsdt = ctx->current;
+	acpi_inc_align(ctx, sizeof(struct acpi_rsdt));
+	xsdt = ctx->current;
+	acpi_inc_align(ctx, sizeof(struct acpi_xsdt));
+	/*
+	 * Per ACPI spec, the FACS table address must be aligned to a 64 byte
+	 * boundary (Windows checks this, but Linux does not).
+	 */
+	acpi_align_large(ctx);
+
+	/* clear all table memory */
+	memset((void *)start, '\0', ctx->current - start);
+
+	acpi_write_rsdp(ctx->rsdp, ctx->rsdt, xsdt);
+	acpi_write_rsdt(ctx->rsdt);
+	acpi_write_xsdt(xsdt);
+}
diff --git a/test/dm/acpi.c b/test/dm/acpi.c
index a2a57a29a6..bb66c7229c 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -9,6 +9,9 @@
 #include <common.h>
 #include <acpi_table.h>
 #include <dm.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <tables_csum.h>
 #include <version.h>
 #include <dm/acpi.h>
 #include <dm/test.h>
@@ -138,9 +141,9 @@ static int dm_test_acpi_write_tables(struct unit_test_state *uts)
 	buf = malloc(BUF_SIZE);
 	ut_assertnonnull(buf);
 
-	ctx.current = buf;
+	acpi_setup_base_tables(&ctx, buf);
+	dmar = ctx.current;
 	ut_assertok(acpi_write_dev_tables(&ctx));
-	dmar = buf;
 
 	/*
 	 * We should have two dmar tables, one for each "denx,u-boot-acpi-test"
@@ -153,6 +156,11 @@ static int dm_test_acpi_write_tables(struct unit_test_state *uts)
 	ut_asserteq(DMAR_INTR_REMAP, dmar[1].flags);
 	ut_asserteq(32 - 1, dmar[1].host_address_width);
 
+	/* Check that the pointers were added correctly */
+	ut_asserteq(map_to_sysmem(dmar), ctx.rsdt->entry[0]);
+	ut_asserteq(map_to_sysmem(dmar + 1), ctx.rsdt->entry[1]);
+	ut_asserteq(0, ctx.rsdt->entry[2]);
+
 	return 0;
 }
 DM_TEST(dm_test_acpi_write_tables, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
@@ -184,3 +192,46 @@ static int dm_test_acpi_basic(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_acpi_basic, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test acpi_setup_base_tables */
+static int dm_test_acpi_setup_base_tables(struct unit_test_state *uts)
+{
+	struct acpi_rsdp *rsdp;
+	struct acpi_rsdt *rsdt;
+	struct acpi_xsdt *xsdt;
+	struct acpi_ctx ctx;
+	void *buf, *end;
+
+	/* Use an unaligned address deliberately */
+	buf = memalign(64, BUF_SIZE);
+	ut_assertnonnull(buf);
+	acpi_setup_base_tables(&ctx, buf + 4);
+
+	rsdp = buf + 16;
+	ut_asserteq_ptr(rsdp, ctx.rsdp);
+	ut_assertok(memcmp(RSDP_SIG, rsdp->signature, sizeof(rsdp->signature)));
+	ut_asserteq(sizeof(*rsdp), rsdp->length);
+	ut_assertok(table_compute_checksum(rsdp, 20));
+	ut_assertok(table_compute_checksum(rsdp, sizeof(*rsdp)));
+
+	rsdt = PTR_ALIGN((void *)rsdp + sizeof(*rsdp), 16);
+	ut_asserteq_ptr(rsdt, ctx.rsdt);
+	ut_assertok(memcmp("RSDT", rsdt->header.signature, ACPI_NAME_LEN));
+	ut_asserteq(sizeof(*rsdt), rsdt->header.length);
+	ut_assertok(table_compute_checksum(rsdt, sizeof(*rsdt)));
+
+	xsdt = PTR_ALIGN((void *)rsdt + sizeof(*rsdt), 16);
+	ut_assertok(memcmp("XSDT", xsdt->header.signature, ACPI_NAME_LEN));
+	ut_asserteq(sizeof(*xsdt), xsdt->header.length);
+	ut_assertok(table_compute_checksum(xsdt, sizeof(*xsdt)));
+
+	end = PTR_ALIGN((void *)xsdt + sizeof(*xsdt), 64);
+	ut_asserteq_ptr(end, ctx.current);
+
+	ut_asserteq(map_to_sysmem(rsdt), rsdp->rsdt_address);
+	ut_asserteq(map_to_sysmem(xsdt), rsdp->xsdt_address);
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_setup_base_tables,
+	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 26/39] acpi: Move the xsdt pointer to acpi_ctx
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (24 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 25/39] acpi: Put table-setup code in its own function Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 27/39] acpi: Add an acpi command Simon Glass
                   ` (35 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

Put this in the context along with the other important pointers.

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

Changes in v2: None

 include/dm/acpi.h     |  2 ++
 lib/acpi/acpi_table.c | 38 ++++++++++++++++----------------------
 test/dm/acpi.c        |  5 +++++
 3 files changed, 23 insertions(+), 22 deletions(-)

diff --git a/include/dm/acpi.h b/include/dm/acpi.h
index 4465e62848..f3e9d73b78 100644
--- a/include/dm/acpi.h
+++ b/include/dm/acpi.h
@@ -33,11 +33,13 @@
  * @rsdp: Pointer to the Root System Description Pointer, typically used when
  *	adding a new table. The RSDP holds pointers to the RSDP and XSDT.
  * @rsdt: Pointer to the Root System Description Table
+ * @xsdt: Pointer to the Extended System Description Table
  */
 struct acpi_ctx {
 	void *current;
 	struct acpi_rsdp *rsdp;
 	struct acpi_rsdt *rsdt;
+	struct acpi_xsdt *xsdt;
 };
 
 /**
diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
index 9f452a65ce..be52b3ac8e 100644
--- a/lib/acpi/acpi_table.c
+++ b/lib/acpi/acpi_table.c
@@ -127,13 +127,11 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table)
 {
 	int i, entries_num;
 	struct acpi_rsdt *rsdt;
-	struct acpi_xsdt *xsdt = NULL;
+	struct acpi_xsdt *xsdt;
 
 	/* The RSDT is mandatory while the XSDT is not */
 	rsdt = ctx->rsdt;
-
-	if (ctx->rsdp->xsdt_address)
-		xsdt = map_sysmem(ctx->rsdp->xsdt_address, 0);
+	xsdt = ctx->xsdt;
 
 	/* This should always be MAX_ACPI_TABLES */
 	entries_num = ARRAY_SIZE(rsdt->entry);
@@ -164,19 +162,17 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table)
 	 * And now the same thing for the XSDT. We use the same index as for
 	 * now we want the XSDT and RSDT to always be in sync in U-Boot
 	 */
-	if (xsdt) {
-		/* Add table to the XSDT */
-		xsdt->entry[i] = map_to_sysmem(table);
-
-		/* Fix XSDT length */
-		xsdt->header.length = sizeof(struct acpi_table_header) +
-			(sizeof(u64) * (i + 1));
-
-		/* Re-calculate checksum */
-		xsdt->header.checksum = 0;
-		xsdt->header.checksum =
-			table_compute_checksum(xsdt, xsdt->header.length);
-	}
+	/* Add table to the XSDT */
+	xsdt->entry[i] = map_to_sysmem(table);
+
+	/* Fix XSDT length */
+	xsdt->header.length = sizeof(struct acpi_table_header) +
+		(sizeof(u64) * (i + 1));
+
+	/* Re-calculate checksum */
+	xsdt->header.checksum = 0;
+	xsdt->header.checksum = table_compute_checksum(xsdt,
+						       xsdt->header.length);
 
 	return 0;
 }
@@ -235,8 +231,6 @@ static void acpi_write_xsdt(struct acpi_xsdt *xsdt)
 
 void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start)
 {
-	struct acpi_xsdt *xsdt;
-
 	ctx->current = start;
 
 	/* Align ACPI tables to 16 byte */
@@ -247,7 +241,7 @@ void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start)
 	acpi_inc_align(ctx, sizeof(struct acpi_rsdp));
 	ctx->rsdt = ctx->current;
 	acpi_inc_align(ctx, sizeof(struct acpi_rsdt));
-	xsdt = ctx->current;
+	ctx->xsdt = ctx->current;
 	acpi_inc_align(ctx, sizeof(struct acpi_xsdt));
 	/*
 	 * Per ACPI spec, the FACS table address must be aligned to a 64 byte
@@ -258,7 +252,7 @@ void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start)
 	/* clear all table memory */
 	memset((void *)start, '\0', ctx->current - start);
 
-	acpi_write_rsdp(ctx->rsdp, ctx->rsdt, xsdt);
+	acpi_write_rsdp(ctx->rsdp, ctx->rsdt, ctx->xsdt);
 	acpi_write_rsdt(ctx->rsdt);
-	acpi_write_xsdt(xsdt);
+	acpi_write_xsdt(ctx->xsdt);
 }
diff --git a/test/dm/acpi.c b/test/dm/acpi.c
index bb66c7229c..a60f67e73d 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -161,6 +161,10 @@ static int dm_test_acpi_write_tables(struct unit_test_state *uts)
 	ut_asserteq(map_to_sysmem(dmar + 1), ctx.rsdt->entry[1]);
 	ut_asserteq(0, ctx.rsdt->entry[2]);
 
+	ut_asserteq(map_to_sysmem(dmar), ctx.xsdt->entry[0]);
+	ut_asserteq(map_to_sysmem(dmar + 1), ctx.xsdt->entry[1]);
+	ut_asserteq(0, ctx.xsdt->entry[2]);
+
 	return 0;
 }
 DM_TEST(dm_test_acpi_write_tables, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
@@ -221,6 +225,7 @@ static int dm_test_acpi_setup_base_tables(struct unit_test_state *uts)
 	ut_assertok(table_compute_checksum(rsdt, sizeof(*rsdt)));
 
 	xsdt = PTR_ALIGN((void *)rsdt + sizeof(*rsdt), 16);
+	ut_asserteq_ptr(xsdt, ctx.xsdt);
 	ut_assertok(memcmp("XSDT", xsdt->header.signature, ACPI_NAME_LEN));
 	ut_asserteq(sizeof(*xsdt), xsdt->header.length);
 	ut_assertok(table_compute_checksum(xsdt, sizeof(*xsdt)));
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 27/39] acpi: Add an acpi command
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (25 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 26/39] acpi: Move the xsdt pointer to acpi_ctx Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 28/39] acpi: Add some tables required by the generation code Simon Glass
                   ` (34 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

It is useful to dump ACPI tables in U-Boot to see what has been generated.
Add a command to handle this.

To allow the command to find the tables, add a position into the global
data.

Support subcommands to list and dump the tables.

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

Changes in v2: None

 arch/sandbox/include/asm/global_data.h |   1 +
 arch/x86/include/asm/global_data.h     |   1 +
 cmd/Kconfig                            |  14 ++
 cmd/Makefile                           |   1 +
 cmd/acpi.c                             | 179 +++++++++++++++++++++++++
 lib/acpi/acpi_table.c                  |   1 +
 test/dm/acpi.c                         |  73 ++++++++++
 7 files changed, 270 insertions(+)
 create mode 100644 cmd/acpi.c

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

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

* [PATCH v2 28/39] acpi: Add some tables required by the generation code
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (26 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 27/39] acpi: Add an acpi command Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 29/39] acpi: Add generation code for devices Simon Glass
                   ` (33 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

The code which generates ACPI tables programmatically, add a few ACPI
definitions required by that code.

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

Changes in v2: None

 include/acpi_table.h | 50 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/include/acpi_table.h b/include/acpi_table.h
index f500f0d3fe..5fd2cef5d1 100644
--- a/include/acpi_table.h
+++ b/include/acpi_table.h
@@ -28,6 +28,18 @@
 
 struct acpi_ctx;
 
+/*
+ * The assigned ACPI ID for the coreboot project is 'BOOT'
+ * http://www.uefi.org/acpi_id_list
+ */
+#define COREBOOT_ACPI_ID	"BOOT"      /* ACPI ID for coreboot HIDs */
+
+/* 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
@@ -365,6 +377,44 @@ struct acpi_csrt_shared_info {
 	u32 max_block_size;
 };
 
+struct __packed acpi_cstate {
+	u8  ctype;
+	u16 latency;
+	u32 power;
+	struct acpi_gen_regaddr resource;
+};
+
+struct __packed acpi_tstate {
+	u32 percent;
+	u32 power;
+	u32 latency;
+	u32 control;
+	u32 status;
+};
+
+/* Port types for ACPI _UPC object */
+enum acpi_upc_type {
+	UPC_TYPE_A,
+	UPC_TYPE_MINI_AB,
+	UPC_TYPE_EXPRESSCARD,
+	UPC_TYPE_USB3_A,
+	UPC_TYPE_USB3_B,
+	UPC_TYPE_USB3_MICRO_B,
+	UPC_TYPE_USB3_MICRO_AB,
+	UPC_TYPE_USB3_POWER_B,
+	UPC_TYPE_C_USB2_ONLY,
+	UPC_TYPE_C_USB2_SS_SWITCH,
+	UPC_TYPE_C_USB2_SS,
+	UPC_TYPE_PROPRIETARY = 0xff,
+	/*
+	 * The following types are not directly defined in the ACPI
+	 * spec but are used by coreboot to identify a USB device type.
+	 */
+	UPC_TYPE_INTERNAL = 0xff,
+	UPC_TYPE_UNUSED,
+	UPC_TYPE_HUB
+};
+
 enum dmar_type {
 	DMAR_DRHD = 0,
 	DMAR_RMRR = 1,
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 29/39] acpi: Add generation code for devices
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (27 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 28/39] acpi: Add some tables required by the generation code Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 30/39] acpi: Add functions to generate ACPI code Simon Glass
                   ` (32 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

Some devices need to create ACPI tables to communcate their parameters
to Linux. Add support for this.

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

Changes in v2:
- Drop CID value from i2c struct

 include/acpi_device.h  |  705 ++++++++++++++++++++++++++
 lib/acpi/acpi_device.c | 1094 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1799 insertions(+)
 create mode 100644 include/acpi_device.h
 create mode 100644 lib/acpi/acpi_device.c

diff --git a/include/acpi_device.h b/include/acpi_device.h
new file mode 100644
index 0000000000..f97bd075ec
--- /dev/null
+++ b/include/acpi_device.h
@@ -0,0 +1,705 @@
+/* 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
+
+#include <i2c.h>
+#include <irq.h>
+#include <spi.h>
+#include <asm-generic/gpio.h>
+
+struct acpi_ctx;
+struct irq;
+struct gpio_desc;
+struct udevice;
+
+/**
+ * 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,
+};
+
+/* 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)
+
+/*
+ * PRP0001 is a special DT namespace link device ID. It provides a means to use
+ * existing DT-compatible device identification in ACPI. When this _HID is used
+ * by an ACPI device, the ACPI subsystem in OS looks up "compatible" property in
+ * the device object's _DSD and will use the value of that property to identify
+ * the corresponding device in analogy with the original DT device
+ * identification algorithm.
+ * More details can be found in Linux kernel documentation:
+ * Documentation/acpi/enumeration.txt
+ */
+#define ACPI_DT_NAMESPACE_HID		"PRP0001"
+
+/* Length of a full path to an ACPI device */
+#define ACPI_PATH_MAX		30
+
+/**
+ * acpi_device_name() - Locate and return the ACPI name for this device
+ *
+ * @dev: Device to check
+ * @name: Returns the character name, must be at least ACPI_NAME_MAX long
+ * @return 0 if OK, -ve on error
+ */
+int acpi_device_name(const struct udevice *dev, char *name);
+
+/**
+ * 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);
+
+/**
+ * acpi_device_status() - Get the status of a device
+ *
+ * This currently just returns ACPI_STATUS_DEVICE_ALL_ON. It does not support
+ * inactive or hidden devices.
+ *
+ * @dev: Device to check
+ * @return device status, as ACPI_STATUS_DEVICE_...
+ */
+int acpi_device_status(const struct udevice *dev);
+
+/** 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;
+};
+
+/**
+ * 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
+ * @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];
+
+	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 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_gpio - 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;
+};
+
+/**
+ * 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;
+};
+
+/**
+ * struct acpi_power_res_params - power on/off sequence information
+ *
+ * This provides GPIOs and timing information for powering a device on and off.
+ * This can be applied to any device that has power control, so is fairly
+ * generic.
+ *
+ * @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)
+ */
+struct acpi_power_res_params {
+	struct acpi_gpio *reset_gpio;
+	unsigned int reset_delay_ms;
+	unsigned int reset_off_delay_ms;
+	struct acpi_gpio *enable_gpio;
+	unsigned int enable_delay_ms;
+	unsigned int enable_off_delay_ms;
+	struct acpi_gpio *stop_gpio;
+	unsigned int stop_delay_ms;
+	unsigned int stop_off_delay_ms;
+};
+
+/**
+ * struct acpi_dp - ACPI device properties
+ *
+ * Writing Device Properties objects via _DSD
+ *
+ * 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 }
+ *   }
+ * }
+ *
+ * @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_gpio() - Add a GPIO binding Device Property
+ *
+ * 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 of the device that has _CRS containing GpioIO()/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_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_add_property_list() - Add a list of of Device Properties
+ *
+ * This adds a list of properties to @dp. Any properties without a name or of
+ * type ACPI_DP_TYPE_UNKNOWN are ignored.
+ *
+ * @dp: Table to add properties to
+ * @property_list: List of properties to add
+ * @property_count: Number of properties in the list
+ * @return number of properties added
+ */
+size_t acpi_dp_add_property_list(struct acpi_dp *dp,
+				 const struct acpi_dp *property_list,
+				 size_t property_count);
+
+/**
+ * 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);
+
+/**
+ * acpi_device_write_i2c_dev() - Write an I2C device to ACPI, including
+ * information ACPI needs to use it.
+ *
+ * This writes a serial bus descriptor for the I2C device so that ACPI can
+ */
+int acpi_device_write_i2c_dev(struct acpi_ctx *ctx, const struct udevice *dev);
+
+/**
+ * struct acpi_i2c_priv - Information read from device tree
+ *
+ * This is used by devices which want to specify various pieces of ACPI
+ * information, including power control. It allows a generic function to
+ * generate the information for ACPI, based on device-tree properties.
+ *
+ * @disable_gpio_export_in_crs: Don't export GPIOs in the CRS
+ * @reset_gpio: GPIO used to assert reset to the device
+ * @enable_gpio: GPIO used to enable the device
+ * @stop_gpio: GPIO used to stop the device
+ * @irq_gpio: GPIO used for interrupt (if @irq is not used)
+ * @irq: IRQ used for interrupt (if @irq_gpio is not used)
+ * @hid: _HID value for device (required)
+ * @uid: _UID value for device
+ * @desc: _DDN value for device
+ * @wake: Wake event, e.g. GPE0_DW1_15; 0 if none
+ * @property_count: Number of other DSD properties (currently always 0)
+ * @probed: true set set 'linux,probed' property
+ * @compat_string: Device tree compatible string to report through ACPI
+ * @has_power_resource: true if this device has a power resource
+ * @reset_delay_ms: Delay after de-asserting reset, in ms
+ * @reset_off_delay_ms: Delay after asserting reset (during power off)
+ * @enable_delay_ms: Delay after asserting enable
+ * @enable_off_delay_ms: Delay after de-asserting enable (during power off)
+ * @stop_delay_ms: Delay after de-aserting stop
+ * @stop_off_delay_ms: Delay after asserting stop (during power off)
+ * @hid_desc_reg_offset: HID register offset (for Human Interface Devices)
+ */
+struct acpi_i2c_priv {
+	bool disable_gpio_export_in_crs;
+	struct gpio_desc reset_gpio;
+	struct gpio_desc enable_gpio;
+	struct gpio_desc irq_gpio;
+	struct gpio_desc stop_gpio;
+	struct irq irq;
+	const char *hid;
+	u32 uid;
+	const char *desc;
+	u32 wake;
+	u32 property_count;
+	bool probed;
+	const char *compat_string;
+	bool has_power_resource;
+	u32 reset_delay_ms;
+	u32 reset_off_delay_ms;
+	u32 enable_delay_ms;
+	u32 enable_off_delay_ms;
+	u32 stop_delay_ms;
+	u32 stop_off_delay_ms;
+	u32 hid_desc_reg_offset;
+};
+
+/**
+ * I2C Human-Interface Devices configuration
+ *
+ * @hid_desc_reg_offset: HID register offset
+ */
+struct dsm_i2c_hid_config {
+	u8 hid_desc_reg_offset;
+};
+
+/**
+ * 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_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.
+ *
+ * Reset - Put the device into / take the device out of reset.
+ * Enable - Enable / disable power to device.
+ * Stop - Stop / start operation of device.
+ *
+ * @return 0 if OK, -ve if at least one GPIO is not provided
+ */
+int acpi_device_add_power_res(struct acpi_ctx *ctx,
+			      const struct acpi_power_res_params *params);
+
+/**
+ * gpio_get_acpi() - Convert a GPIO description into an ACPI GPIO
+ *
+ * At present this is fairly limited. It only supports ACPI_GPIO_TYPE_IO and
+ * has hard-coded settings for type, pull, IO restrict and polarity. These
+ * could come from pinctrl potentially.
+ *
+ * @desc: GPIO description to convert
+ * @gpio: Place to put ACPI GPIO information
+ * @return 0 if OK, -ENOENT if @desc is invalid
+ */
+int gpio_get_acpi(const struct gpio_desc *desc, struct acpi_gpio *gpio);
+
+/**
+ * acpi_device_write_dsm_i2c_hid() - Write a device-specific method for HID
+ *
+ * This writes a DSM for an I2C Human-Interface Device based on the config
+ * provided
+ *
+ * @config: Config information to write
+ */
+void acpi_device_write_dsm_i2c_hid(struct acpi_ctx *ctx,
+				   struct dsm_i2c_hid_config *config);
+
+/**
+ * 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);
+
+int acpi_device_get_name(const struct udevice *dev, char *out_name);
+
+#endif
diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
new file mode 100644
index 0000000000..145de90677
--- /dev/null
+++ b/lib/acpi/acpi_device.c
@@ -0,0 +1,1094 @@
+// 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 <acpi_device.h>
+#include <acpigen.h>
+#include <dm.h>
+#include <irq.h>
+#include <malloc.h>
+#include <usb.h>
+#include <asm-generic/gpio.h>
+#include <dm/acpi.h>
+
+#define ACPI_DP_UUID		"daffd814-6eba-4d8c-8a91-bc9bbf4aa301"
+#define ACPI_DP_CHILD_UUID	"dbb8e3e6-5886-4ba6-8795-1319f52a966b"
+#define ACPI_DSM_I2C_HID_UUID	"3cdff6f7-4267-4555-ad05-b30a3d8938de"
+
+/**
+ * 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)
+{
+	char *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,
+				      char *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));
+}
+
+int acpi_device_name(const struct udevice *dev, char *name)
+{
+	int ret;
+
+	ret = acpi_get_name(dev, name);
+	if (ret)
+		return log_msg_ret("name", ret);
+
+	return 0;
+}
+
+/**
+ * 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_device_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 (!dev || (cur + strlen(name) + 2) > buf_len)
+		return cur;
+
+	/* 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;
+}
+
+int acpi_device_status(const struct udevice *dev)
+{
+	return ACPI_STATUS_DEVICE_ALL_ON;
+}
+
+/* ACPI 6.1 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 || 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;
+}
+
+/* ACPI 6.1 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 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);
+}
+
+/* PowerResource() with Enable and/or Reset control */
+int acpi_device_add_power_res(struct acpi_ctx *ctx,
+			      const struct acpi_power_res_params *params)
+{
+	static const char *const power_res_dev_states[] = { "_PR0", "_PR3" };
+	unsigned int reset_gpio = params->reset_gpio->pins[0];
+	unsigned int enable_gpio = params->enable_gpio->pins[0];
+	unsigned int stop_gpio = params->stop_gpio->pins[0];
+	int ret;
+
+	if (!reset_gpio && !enable_gpio && !stop_gpio)
+		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_enable_tx_gpio(ctx, params->reset_gpio);
+		if (ret)
+			return log_msg_ret("reset1", ret);
+	}
+	if (enable_gpio) {
+		ret = acpigen_enable_tx_gpio(ctx, params->enable_gpio);
+		if (ret)
+			return log_msg_ret("enable1", ret);
+		if (params->enable_delay_ms)
+			acpigen_write_sleep(ctx, params->enable_delay_ms);
+	}
+	if (reset_gpio) {
+		ret = acpigen_disable_tx_gpio(ctx, params->reset_gpio);
+		if (ret)
+			return log_msg_ret("reset2", ret);
+		if (params->reset_delay_ms)
+			acpigen_write_sleep(ctx, params->reset_delay_ms);
+	}
+	if (stop_gpio) {
+		ret = acpigen_disable_tx_gpio(ctx, params->stop_gpio);
+		if (ret)
+			return log_msg_ret("stop1", ret);
+		if (params->stop_delay_ms)
+			acpigen_write_sleep(ctx, params->stop_delay_ms);
+	}
+	acpigen_pop_len(ctx);		/* _ON method */
+
+	/* Method (_OFF, 0, Serialized) */
+	acpigen_write_method_serialized(ctx, "_OFF", 0);
+	if (stop_gpio) {
+		ret = acpigen_enable_tx_gpio(ctx, params->stop_gpio);
+		if (ret)
+			return log_msg_ret("stop2", ret);
+		if (params->stop_off_delay_ms)
+			acpigen_write_sleep(ctx, params->stop_off_delay_ms);
+	}
+	if (reset_gpio) {
+		ret = acpigen_enable_tx_gpio(ctx, params->reset_gpio);
+		if (ret)
+			return log_msg_ret("reset3", ret);
+		if (params->reset_off_delay_ms)
+			acpigen_write_sleep(ctx, params->reset_off_delay_ms);
+	}
+	if (enable_gpio) {
+		ret = acpigen_disable_tx_gpio(ctx, params->enable_gpio);
+		if (ret)
+			return log_msg_ret("enable2", ret);
+		if (params->enable_off_delay_ms)
+			acpigen_write_sleep(ctx, params->enable_off_delay_ms);
+	}
+	acpigen_pop_len(ctx);		/* _OFF method */
+
+	acpigen_pop_len(ctx);		/* PowerResource PRIC */
+
+	return 0;
+}
+
+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)
+{
+	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;
+
+	if (!table || 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);
+		}
+	}
+
+	/* Clean up */
+	acpi_dp_free(table);
+
+	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;
+
+	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);
+}
+
+size_t acpi_dp_add_property_list(struct acpi_dp *dp,
+				 const struct acpi_dp *property_list,
+				 size_t property_count)
+{
+	const struct acpi_dp *prop;
+	size_t i, properties_added = 0;
+
+	if (!dp || !property_list)
+		return 0;
+
+	for (i = 0; i < property_count; i++) {
+		prop = &property_list[i];
+
+		if (prop->type == ACPI_DP_TYPE_UNKNOWN || !prop->name)
+			continue;
+
+		switch (prop->type) {
+		case ACPI_DP_TYPE_INTEGER:
+			acpi_dp_add_integer(dp, prop->name, prop->integer);
+			break;
+		case ACPI_DP_TYPE_STRING:
+			acpi_dp_add_string(dp, prop->name, prop->string);
+			break;
+		case ACPI_DP_TYPE_REFERENCE:
+			acpi_dp_add_reference(dp, prop->name, prop->string);
+			break;
+		case ACPI_DP_TYPE_ARRAY:
+			acpi_dp_add_array(dp, prop->array);
+			break;
+		case ACPI_DP_TYPE_CHILD:
+			acpi_dp_add_child(dp, prop->name, prop->child);
+			break;
+		default:
+			continue;
+		}
+
+		++properties_added;
+	}
+
+	return properties_added;
+}
+
+struct acpi_dp *acpi_dp_add_integer(struct acpi_dp *dp, const char *name,
+				    u64 value)
+{
+	struct acpi_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 = 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)
+{
+	if (!dp)
+		return NULL;
+
+	struct acpi_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;
+
+	if (!dp || !child || 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;
+
+	if (!dp || !array || 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;
+
+	if (!dp || 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;
+}
+
+struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
+				 const char *ref, int index, int pin,
+				 bool active_low)
+{
+	if (!dp)
+		return NULL;
+
+	struct acpi_dp *gpio = acpi_dp_new_table(name);
+
+	if (!gpio)
+		return NULL;
+
+	/* The device that has _CRS containing GpioIO()/GpioInt() */
+	acpi_dp_add_reference(gpio, NULL, ref);
+
+	/* Index of the GPIO resource in _CRS starting from zero */
+	acpi_dp_add_integer(gpio, NULL, index);
+
+	/* Pin in the GPIO resource, typically zero */
+	acpi_dp_add_integer(gpio, NULL, pin);
+
+	/* Set if pin is active low */
+	acpi_dp_add_integer(gpio, NULL, active_low);
+
+	acpi_dp_add_array(dp, gpio);
+
+	return gpio;
+}
+
+/**
+ * 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;
+}
+
+static void i2c_hid_func0_cb(struct acpi_ctx *ctx, void *arg)
+{
+	/* ToInteger (Arg1, Local2) */
+	acpigen_write_to_integer(ctx, ARG1_OP, LOCAL2_OP);
+	/* If (LEqual (Local2, 0x0)) */
+	acpigen_write_if_lequal_op_int(ctx, LOCAL2_OP, 0x0);
+	/*   Return (Buffer (One) { 0x1f }) */
+	acpigen_write_return_singleton_buffer(ctx, 0x1f);
+	acpigen_pop_len(ctx);	/* Pop : If */
+	/* Else */
+	acpigen_write_else(ctx);
+	/*   If (LEqual (Local2, 0x1)) */
+	acpigen_write_if_lequal_op_int(ctx, LOCAL2_OP, 0x1);
+	/*     Return (Buffer (One) { 0x3f }) */
+	acpigen_write_return_singleton_buffer(ctx, 0x3f);
+	acpigen_pop_len(ctx);	/* Pop : If */
+	/*   Else */
+	acpigen_write_else(ctx);
+	/*     Return (Buffer (One) { 0x0 }) */
+	acpigen_write_return_singleton_buffer(ctx, 0x0);
+	acpigen_pop_len(ctx);	/* Pop : Else */
+	acpigen_pop_len(ctx);	/* Pop : Else */
+}
+
+static void i2c_hid_func1_cb(struct acpi_ctx *ctx, void *arg)
+{
+	struct dsm_i2c_hid_config *config = arg;
+
+	acpigen_write_return_byte(ctx, config->hid_desc_reg_offset);
+}
+
+static hid_callback_func i2c_hid_callbacks[2] = {
+	i2c_hid_func0_cb,
+	i2c_hid_func1_cb,
+};
+
+void acpi_device_write_dsm_i2c_hid(struct acpi_ctx *ctx,
+				   struct dsm_i2c_hid_config *config)
+{
+	acpigen_write_dsm(ctx, ACPI_DSM_I2C_HID_UUID, i2c_hid_callbacks,
+			  ARRAY_SIZE(i2c_hid_callbacks), config);
+}
+
+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_get_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)
+		memcpy(out_name, name, ACPI_NAME_MAX);
+
+	return 0;
+}
+
+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);
+	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 -ENOENT;
+	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);
+	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 -ENOENT;
+	acpi_dp_add_string(dp, prop, val);
+
+	return 0;
+}
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 30/39] acpi: Add functions to generate ACPI code
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (28 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 29/39] acpi: Add generation code for devices Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 31/39] gpio: Add a method to convert a GPIO to ACPI Simon Glass
                   ` (31 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 UTC (permalink / raw)
  To: u-boot

Sometimes we need to generate ACPI code on the fly based on things only
known at run time. Add a new 'acpigen' library to handle this. This code
comes from coreboot and has been modified to support the acpi_ctx struct.

Also add acpi_device.c to the build, since these files are co-dependent.

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

Changes in v2: None

 include/acpigen.h  |  482 +++++++++++++
 include/dm/acpi.h  |    7 +
 include/irq.h      |    2 +
 lib/acpi/Makefile  |    2 +
 lib/acpi/acpigen.c | 1683 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 2176 insertions(+)
 create mode 100644 include/acpigen.h
 create mode 100644 lib/acpi/acpigen.c

diff --git a/include/acpigen.h b/include/acpigen.h
new file mode 100644
index 0000000000..08000831b9
--- /dev/null
+++ b/include/acpigen.h
@@ -0,0 +1,482 @@
+/* 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 _ACPIGEN_H
+#define _ACPIGEN_H
+
+#include <acpi_table.h>
+
+struct acpi_cstate;
+struct acpi_pld;
+struct acpi_gpio;
+struct acpi_tstate;
+
+/* Values that can be returned for ACPI Device _STA method */
+#define ACPI_STATUS_DEVICE_PRESENT	BIT(0)
+#define ACPI_STATUS_DEVICE_ENABLED	BIT(1)
+#define ACPI_STATUS_DEVICE_SHOW_IN_UI	BIT(2)
+#define ACPI_STATUS_DEVICE_STATE_OK	BIT(3)
+
+#define ACPI_STATUS_DEVICE_ALL_OFF	0
+#define ACPI_STATUS_DEVICE_ALL_ON	(ACPI_STATUS_DEVICE_PRESENT |\
+					 ACPI_STATUS_DEVICE_ENABLED |\
+					 ACPI_STATUS_DEVICE_SHOW_IN_UI |\
+					 ACPI_STATUS_DEVICE_STATE_OK)
+#define ACPI_STATUS_DEVICE_HIDDEN_ON	(ACPI_STATUS_DEVICE_PRESENT |\
+					 ACPI_STATUS_DEVICE_ENABLED |\
+					 ACPI_STATUS_DEVICE_STATE_OK)
+
+/* ACPI Op/Prefix Codes */
+enum {
+	ZERO_OP			= 0x00,
+	ONE_OP			= 0x01,
+	ALIAS_OP		= 0x06,
+	NAME_OP			= 0x08,
+	BYTE_PREFIX		= 0x0A,
+	WORD_PREFIX		= 0x0B,
+	DWORD_PREFIX		= 0x0C,
+	STRING_PREFIX		= 0x0D,
+	QWORD_PREFIX		= 0x0E,
+	SCOPE_OP		= 0x10,
+	BUFFER_OP		= 0x11,
+	PACKAGE_OP		= 0x12,
+	VARIABLE_PACKAGE_OP	= 0x13,
+	METHOD_OP		= 0x14,
+	EXTERNAL_OP		= 0x15,
+	DUAL_NAME_PREFIX	= 0x2E,
+	MULTI_NAME_PREFIX	= 0x2F,
+	EXT_OP_PREFIX		= 0x5B,
+
+	MUTEX_OP		= 0x01,
+	EVENT_OP		= 0x01,
+	SF_RIGHT_OP		= 0x10,
+	SF_LEFT_OP		= 0x11,
+	COND_REFOF_OP		= 0x12,
+	CREATEFIELD_OP		= 0x13,
+	LOAD_TABLE_OP		= 0x1f,
+	LOAD_OP		= 0x20,
+	STALL_OP		= 0x21,
+	SLEEP_OP		= 0x22,
+	ACQUIRE_OP		= 0x23,
+	SIGNAL_OP		= 0x24,
+	WAIT_OP		= 0x25,
+	RST_OP			= 0x26,
+	RELEASE_OP		= 0x27,
+	FROM_BCD_OP		= 0x28,
+	TO_BCD_OP		= 0x29,
+	UNLOAD_OP		= 0x2A,
+	REVISON_OP		= 0x30,
+	DEBUG_OP		= 0x31,
+	FATAL_OP		= 0x32,
+	TIMER_OP		= 0x33,
+	OPREGION_OP		= 0x80,
+	FIELD_OP		= 0x81,
+	DEVICE_OP		= 0x82,
+	PROCESSOR_OP		= 0x83,
+	POWER_RES_OP		= 0x84,
+	THERMAL_ZONE_OP	= 0x85,
+	INDEX_FIELD_OP		= 0x86,
+	BANK_FIELD_OP		= 0x87,
+	DATA_REGION_OP		= 0x88,
+
+	ROOT_PREFIX		= 0x5C,
+	PARENT_PREFIX		= 0x5D,
+	LOCAL0_OP		= 0x60,
+	LOCAL1_OP		= 0x61,
+	LOCAL2_OP		= 0x62,
+	LOCAL3_OP		= 0x63,
+	LOCAL4_OP		= 0x64,
+	LOCAL5_OP		= 0x65,
+	LOCAL6_OP		= 0x66,
+	LOCAL7_OP		= 0x67,
+	ARG0_OP			= 0x68,
+	ARG1_OP			= 0x69,
+	ARG2_OP			= 0x6A,
+	ARG3_OP			= 0x6B,
+	ARG4_OP			= 0x6C,
+	ARG5_OP			= 0x6D,
+	ARG6_OP			= 0x6E,
+	STORE_OP		= 0x70,
+	REF_OF_OP		= 0x71,
+	ADD_OP			= 0x72,
+	CONCATENATE_OP		= 0x73,
+	SUBTRACT_OP		= 0x74,
+	INCREMENT_OP		= 0x75,
+	DECREMENT_OP		= 0x76,
+	MULTIPLY_OP		= 0x77,
+	DIVIDE_OP		= 0x78,
+	SHIFT_LEFT_OP		= 0x79,
+	SHIFT_RIGHT_OP		= 0x7A,
+	AND_OP			= 0x7B,
+	NAND_OP			= 0x7C,
+	OR_OP			= 0x7D,
+	NOR_OP			= 0x7E,
+	XOR_OP			= 0x7F,
+	NOT_OP			= 0x80,
+	FD_SHIFT_LEFT_BIT_OR	= 0x81,
+	FD_SHIFT_RIGHT_BIT_OR	= 0x82,
+	DEREF_OP		= 0x83,
+	CONCATENATE_TEMP_OP	= 0x84,
+	MOD_OP			= 0x85,
+	NOTIFY_OP		= 0x86,
+	SIZEOF_OP		= 0x87,
+	INDEX_OP		= 0x88,
+	MATCH_OP		= 0x89,
+	CREATE_DWORD_OP		= 0x8A,
+	CREATE_WORD_OP		= 0x8B,
+	CREATE_BYTE_OP		= 0x8C,
+	CREATE_BIT_OP		= 0x8D,
+	OBJ_TYPE_OP		= 0x8E,
+	CREATE_QWORD_OP		= 0x8F,
+	LAND_OP			= 0x90,
+	LOR_OP			= 0x91,
+	LNOT_OP			= 0x92,
+	LEQUAL_OP		= 0x93,
+	LGREATER_OP		= 0x94,
+	LLESS_OP		= 0x95,
+	TO_BUFFER_OP		= 0x96,
+	TO_DEC_STRING_OP	= 0x97,
+	TO_HEX_STRING_OP	= 0x98,
+	TO_INTEGER_OP		= 0x99,
+	TO_STRING_OP		= 0x9C,
+	CP_OBJ_OP		= 0x9D,
+	MID_OP			= 0x9E,
+	CONTINUE_OP		= 0x9F,
+	IF_OP			= 0xA0,
+	ELSE_OP			= 0xA1,
+	WHILE_OP		= 0xA2,
+	NOOP_OP			= 0xA3,
+	RETURN_OP		= 0xA4,
+	BREAK_OP		= 0xA5,
+	COMMENT_OP		= 0xA9,
+	BREAKPIONT_OP		= 0xCC,
+	ONES_OP			= 0xFF,
+};
+
+#define FIELDLIST_OFFSET(_bits)		{ .type = OFFSET, \
+					  .name = "", \
+					  .bits = _bits * 8, \
+					}
+#define FIELDLIST_NAMESTR(_name, _bits)		{ .type = NAME_STRING, \
+					  .name = _name, \
+					  .bits = _bits, \
+					}
+
+#define FIELD_ANYACC			0
+#define FIELD_BYTEACC			1
+#define FIELD_WORDACC			2
+#define FIELD_DWORDACC			3
+#define FIELD_QWORDACC			4
+#define FIELD_BUFFERACC			5
+#define FIELD_NOLOCK			(0 << 4)
+#define FIELD_LOCK			(1 << 4)
+#define FIELD_PRESERVE			(0 << 5)
+#define FIELD_WRITEASONES		(1 << 5)
+#define FIELD_WRITEASZEROS		(2 << 5)
+
+enum field_type {
+	OFFSET,
+	NAME_STRING,
+	FIELD_TYPE_MAX,
+};
+
+struct fieldlist {
+	enum field_type type;
+	const char *name;
+	u32 bits;
+};
+
+#define OPREGION(rname, space, offset, len)	{.name = rname, \
+						 .regionspace = space, \
+						 .regionoffset = offset, \
+						 .regionlen = len, \
+						}
+
+enum region_space {
+	SYSTEMMEMORY,
+	SYSTEMIO,
+	PCI_CONFIG,
+	EMBEDDEDCONTROL,
+	SMBUS,
+	CMOS,
+	PCIBARTARGET,
+	IPMI,
+	GPIO_REGION,
+	GPSERIALBUS,
+	PCC,
+	FIXED_HARDWARE = 0x7F,
+	REGION_SPACE_MAX,
+};
+
+struct opregion {
+	const char *name;
+	enum region_space regionspace;
+	unsigned long regionoffset;
+	unsigned long regionlen;
+};
+
+#define DSM_UUID(DSM_UUID, DSM_CALLBACKS, DSM_COUNT, DSM_ARG) \
+	{ .uuid = DSM_UUID, \
+	.callbacks = DSM_CALLBACKS, \
+	.count = DSM_COUNT, \
+	.arg = DSM_ARG, \
+	}
+
+typedef void (*hid_callback_func)(struct acpi_ctx *ctx, void *arg);
+
+struct dsm_uuid {
+	const char *uuid;
+	hid_callback_func *callbacks;
+	size_t count;
+	void *arg;
+};
+
+/* version 1 has 15 fields, version 2 has 19, and version 3 has 21 */
+enum cppc_fields {
+	CPPC_HIGHEST_PERF, /* can be DWORD */
+	CPPC_NOMINAL_PERF, /* can be DWORD */
+	CPPC_LOWEST_NONL_PERF, /* can be DWORD */
+	CPPC_LOWEST_PERF, /* can be DWORD */
+	CPPC_GUARANTEED_PERF,
+	CPPC_DESIRED_PERF,
+	CPPC_MIN_PERF,
+	CPPC_MAX_PERF,
+	CPPC_PERF_REDUCE_TOLERANCE,
+	CPPC_TIME_WINDOW,
+	CPPC_COUNTER_WRAP, /* can be DWORD */
+	CPPC_REF_PERF_COUNTER,
+	CPPC_DELIVERED_PERF_COUNTER,
+	CPPC_PERF_LIMITED,
+	CPPC_ENABLE, /* can be System I/O */
+	CPPC_MAX_FIELDS_VER_1,
+	CPPC_AUTO_SELECT = /* can be DWORD */
+		CPPC_MAX_FIELDS_VER_1,
+	CPPC_AUTO_ACTIVITY_WINDOW,
+	CPPC_PERF_PREF,
+	CPPC_REF_PERF, /* can be DWORD */
+	CPPC_MAX_FIELDS_VER_2,
+	CPPC_LOWEST_FREQ = /* can be DWORD */
+		CPPC_MAX_FIELDS_VER_2,
+	CPPC_NOMINAL_FREQ, /* can be DWORD */
+	CPPC_MAX_FIELDS_VER_3,
+};
+
+struct cppc_config {
+	u32 version; /* must be 1, 2, or 3 */
+	/*
+	 * The generic struct acpi_gen_regaddr structure is being used, though
+	 * anything besides PPC or FFIXED generally requires checking
+	 * if the OS has advertised support for it (via _OSC).
+	 *
+	 * NOTE: some fields permit DWORDs to be used.  If you
+	 * provide a System Memory register with all zeros (which
+	 * represents unsupported) then this will be used as-is.
+	 * Otherwise, a System Memory register with a 32-bit
+	 * width will be converted into a DWORD field (the value
+	 * of which will be the value of 'addrl'.  Any other use
+	 * of System Memory register is currently undefined.
+	 * (i.e., if you have an actual need for System Memory
+	 * then you'll need to adjust this kludge).
+	 */
+	struct acpi_gen_regaddr regs[CPPC_MAX_FIELDS_VER_3];
+};
+
+void acpigen_write_return_integer(struct acpi_ctx *ctx, u64 arg);
+void acpigen_write_return_string(struct acpi_ctx *ctx, const char *arg);
+void acpigen_write_len_f(struct acpi_ctx *ctx);
+void acpigen_pop_len(struct acpi_ctx *ctx);
+void acpigen_set_current(struct acpi_ctx *ctx, char *curr);
+char *acpigen_get_current(struct acpi_ctx *ctx);
+char *acpigen_write_package(struct acpi_ctx *ctx, int nr_el);
+void acpigen_write_zero(struct acpi_ctx *ctx);
+void acpigen_write_one(struct acpi_ctx *ctx);
+void acpigen_write_ones(struct acpi_ctx *ctx);
+void acpigen_write_byte(struct acpi_ctx *ctx, unsigned int data);
+void acpigen_emit_byte(struct acpi_ctx *ctx, unsigned char data);
+void acpigen_emit_ext_op(struct acpi_ctx *ctx, u8 op);
+void acpigen_emit_word(struct acpi_ctx *ctx, unsigned int data);
+void acpigen_emit_dword(struct acpi_ctx *ctx, unsigned int data);
+void acpigen_emit_stream(struct acpi_ctx *ctx, const char *data, int size);
+void acpigen_emit_string(struct acpi_ctx *ctx, const char *string);
+void acpigen_emit_namestring(struct acpi_ctx *ctx, const char *namepath);
+void acpigen_emit_eisaid(struct acpi_ctx *ctx, const char *eisaid);
+void acpigen_write_word(struct acpi_ctx *ctx, unsigned int data);
+void acpigen_write_dword(struct acpi_ctx *ctx, unsigned int data);
+void acpigen_write_qword(struct acpi_ctx *ctx, u64 data);
+void acpigen_write_integer(struct acpi_ctx *ctx, u64 data);
+void acpigen_write_string(struct acpi_ctx *ctx, const char *string);
+void acpigen_write_coreboot_hid(struct acpi_ctx *ctx,
+				enum coreboot_acpi_ids id);
+void acpigen_write_name(struct acpi_ctx *ctx, const char *name);
+void acpigen_write_name_zero(struct acpi_ctx *ctx, const char *name);
+void acpigen_write_name_one(struct acpi_ctx *ctx, const char *name);
+void acpigen_write_name_string(struct acpi_ctx *ctx, const char *name,
+			       const char *string);
+void acpigen_write_name_dword(struct acpi_ctx *ctx, const char *name, u32 val);
+void acpigen_write_name_qword(struct acpi_ctx *ctx, const char *name, u64 val);
+void acpigen_write_name_byte(struct acpi_ctx *ctx, const char *name, u8 val);
+void acpigen_write_name_integer(struct acpi_ctx *ctx, const char *name,
+				u64 val);
+void acpigen_write_scope(struct acpi_ctx *ctx, const char *name);
+void acpigen_write_method(struct acpi_ctx *ctx, const char *name, int nargs);
+void acpigen_write_method_serialized(struct acpi_ctx *ctx, const char *name,
+				     int nargs);
+void acpigen_write_device(struct acpi_ctx *ctx, const char *name);
+void acpigen_write_ppc(struct acpi_ctx *ctx, u8 nr);
+void acpigen_write_ppc_nvs(struct acpi_ctx *ctx);
+void acpigen_write_empty_pct(struct acpi_ctx *ctx);
+void acpigen_write_empty_ptc(struct acpi_ctx *ctx);
+void acpigen_write_prw(struct acpi_ctx *ctx, u32 wake, u32 level);
+void acpigen_write_sta(struct acpi_ctx *ctx, u8 status);
+void acpigen_write_tpc(struct acpi_ctx *ctx, const char *gnvs_tpc_limit);
+void acpigen_write_pss_package(struct acpi_ctx *ctx, u32 corefreq, u32 power,
+			       u32 translat,
+			u32 busmlat, u32 control, u32 status);
+enum psd_coord {
+	SW_ALL = 0xfc,
+	SW_ANY = 0xfd,
+	HW_ALL = 0xfe
+};
+
+void acpigen_write_psd_package(struct acpi_ctx *ctx, u32 domain, u32 numprocs,
+			       enum psd_coord coordtype);
+void acpigen_write_cst_package_entry(struct acpi_ctx *ctx,
+				     struct acpi_cstate *cstate);
+void acpigen_write_cst_package(struct acpi_ctx *ctx, struct acpi_cstate *entry,
+			       int nentries);
+
+enum csd_coord {
+	CSD_HW_ALL = 0xfe,
+};
+
+void acpigen_write_CSD_package(struct acpi_ctx *ctx, u32 domain, u32 numprocs,
+			       enum csd_coord coordtype, u32 index);
+void acpigen_write_processor(struct acpi_ctx *ctx, u8 cpuindex, u32 pblock_addr,
+			     u8 pblock_len);
+void acpigen_write_processor_package(struct acpi_ctx *ctx, const char *name,
+				     uint first_core, uint core_count);
+void acpigen_write_processor_cnot(struct acpi_ctx *ctx, const uint num_cores);
+void acpigen_write_tss_package(struct acpi_ctx *ctx, int entries,
+			       struct acpi_tstate *tstate_list);
+void acpigen_write_tsd_package(struct acpi_ctx *ctx, u32 domain, u32 numprocs,
+			       enum psd_coord coordtype);
+void acpigen_write_mem32fixed(struct acpi_ctx *ctx, int readwrite, u32 base,
+			      u32 size);
+void acpigen_write_register_resource(struct acpi_ctx *ctx,
+				     const struct acpi_gen_regaddr *addr);
+void acpigen_write_irq(struct acpi_ctx *ctx, u16 mask);
+void acpigen_write_resourcetemplate_header(struct acpi_ctx *ctx);
+void acpigen_write_resourcetemplate_footer(struct acpi_ctx *ctx);
+int acpigen_write_uuid(struct acpi_ctx *ctx, const char *uuid);
+void acpigen_write_power_res(struct acpi_ctx *ctx, const char *name, u8 level,
+			     u16 order, const char *const dev_states[],
+			     size_t dev_states_count);
+void acpigen_write_sleep(struct acpi_ctx *ctx, u64 sleep_ms);
+void acpigen_write_store(struct acpi_ctx *ctx);
+void acpigen_write_store_ops(struct acpi_ctx *ctx, u8 src, u8 dst);
+void acpigen_write_or(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res);
+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);
+void acpigen_write_debug_string(struct acpi_ctx *ctx, const char *str);
+void acpigen_write_debug_integer(struct acpi_ctx *ctx, u64 val);
+void acpigen_write_debug_op(struct acpi_ctx *ctx, u8 op);
+void acpigen_write_if(struct acpi_ctx *ctx);
+void acpigen_write_if_and(struct acpi_ctx *ctx, u8 arg1, u8 arg2);
+void acpigen_write_if_lequal_op_int(struct acpi_ctx *ctx, u8 op, u64 val);
+void acpigen_write_else(struct acpi_ctx *ctx);
+void acpigen_write_to_buffer(struct acpi_ctx *ctx, u8 src, u8 dst);
+void acpigen_write_to_integer(struct acpi_ctx *ctx, u8 src, u8 dst);
+void acpigen_write_byte_buffer(struct acpi_ctx *ctx, u8 *arr, size_t size);
+void acpigen_write_return_byte_buffer(struct acpi_ctx *ctx, u8 *arr,
+				      size_t size);
+void acpigen_write_return_singleton_buffer(struct acpi_ctx *ctx, u8 arg);
+void acpigen_write_return_byte(struct acpi_ctx *ctx, u8 arg);
+void acpigen_write_upc(struct acpi_ctx *ctx, enum acpi_upc_type type);
+
+/*
+ * Generate ACPI AML code for _DSM method.
+ * This function takes as input uuid for the device, set of callbacks and
+ * argument to pass into the callbacks. Callbacks should ensure that Local0 and
+ * Local1 are left untouched. Use of Local2-Local7 is permitted in callbacks.
+ */
+int acpigen_write_dsm(struct acpi_ctx *ctx, const char *uuid,
+		      hid_callback_func callbacks[], size_t count, void *arg);
+int acpigen_write_dsm_uuid_arr(struct acpi_ctx *ctx, struct dsm_uuid *ids,
+			       size_t count);
+
+/*
+ * Generate ACPI AML code for _CPC (struct acpi_ctx *ctx, Continuous Perfmance
+ * Control). Execute the package function once to create a global table, then
+ * execute the method function within each processor object to
+ * create a method that points to the global table.
+ */
+int acpigen_write_cppc_package(struct acpi_ctx *ctx,
+			       const struct cppc_config *config);
+void acpigen_write_cppc_method(struct acpi_ctx *ctx);
+
+/*
+ * Generate ACPI AML code for _ROM method.
+ * This function takes as input ROM data and ROM length.
+ * The ROM length has to be multiple of 4096 and has to be less
+ * than the current implementation limit of 0x40000.
+ */
+int acpigen_write_rom(struct acpi_ctx *ctx, void *bios, const size_t length);
+/*
+ * Generate ACPI AML code for OperationRegion
+ * This function takes input region name, region space, region offset & region
+ * length.
+ */
+void acpigen_write_opregion(struct acpi_ctx *ctx, struct opregion *opreg);
+/*
+ * Generate ACPI AML code for Field
+ * This function takes input region name, fieldlist, count & flags.
+ */
+int acpigen_write_field(struct acpi_ctx *ctx, const char *name,
+			struct fieldlist *l, size_t count, uint flags);
+/*
+ * Generate ACPI AML code for IndexField
+ * This function takes input index name, data name, fieldlist, count & flags.
+ */
+int acpigen_write_indexfield(struct acpi_ctx *ctx, const char *idx,
+			     const char *data, struct fieldlist *l,
+			     size_t count, uint flags);
+
+/*
+ * Soc-implemented functions for generating ACPI AML code for GPIO handling. All
+ * these functions are expected to use only Local5, Local6 and Local7
+ * variables. If the functions call into another ACPI method, then there is no
+ * restriction on the use of Local variables. In case of get/read functions,
+ * return value is expected to be stored in Local0 variable.
+ *
+ * All functions return 0 on success and -1 on error.
+ */
+
+/* Generate ACPI AML code to return Rx value of GPIO in Local0. */
+int acpigen_soc_read_rx_gpio(struct acpi_ctx *ctx, uint gpio_num);
+
+/* Generate ACPI AML code to return Tx value of GPIO in Local0. */
+int acpigen_soc_get_tx_gpio(struct acpi_ctx *ctx, uint gpio_num);
+
+/* Generate ACPI AML code to set Tx value of GPIO to 1. */
+int acpigen_soc_set_tx_gpio(struct acpi_ctx *ctx, uint gpio_num);
+
+/* Generate ACPI AML code to set Tx value of GPIO to 0. */
+int acpigen_soc_clear_tx_gpio(struct acpi_ctx *ctx, uint gpio_num);
+
+/*
+ * 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_enable_tx_gpio(struct acpi_ctx *ctx, struct acpi_gpio *gpio);
+int acpigen_disable_tx_gpio(struct acpi_ctx *ctx, struct acpi_gpio *gpio);
+
+#endif
diff --git a/include/dm/acpi.h b/include/dm/acpi.h
index f3e9d73b78..0f78a506da 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	5
 
+/* 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 RSDP 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/include/irq.h b/include/irq.h
index b71afe9bee..d4948e6dc4 100644
--- a/include/irq.h
+++ b/include/irq.h
@@ -8,6 +8,8 @@
 #ifndef __irq_H
 #define __irq_H
 
+struct ofnode_phandle_args;
+
 /*
  * Interrupt controller types available. You can find a particular one with
  * irq_first_device_type()
diff --git a/lib/acpi/Makefile b/lib/acpi/Makefile
index 660491ef71..85a1f774ad 100644
--- a/lib/acpi/Makefile
+++ b/lib/acpi/Makefile
@@ -1,4 +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..4e7d1ce51e
--- /dev/null
+++ b/lib/acpi/acpigen.c
@@ -0,0 +1,1683 @@
+// 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 <hexdump.h>
+#include <uuid.h>
+#include <acpigen.h>
+#include <acpi_device.h>
+#include <acpi_table.h>
+#include <dm/acpi.h>
+#include <linux/ioport.h>
+
+/*
+ * 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
+
+/* CPU path format */
+#define ACPI_CPU_STRING "\\_PR.CP%02d"
+
+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_set_current(struct acpi_ctx *ctx, char *curr)
+{
+	ctx->current = curr;
+}
+
+char *acpigen_get_current(struct acpi_ctx *ctx)
+{
+	return ctx->current;
+}
+
+void acpigen_emit_byte(struct acpi_ctx *ctx, unsigned char b)
+{
+	*(u8 *)ctx->current++ = b;
+}
+
+void acpigen_emit_ext_op(struct acpi_ctx *ctx, u8 op)
+{
+	acpigen_emit_byte(ctx, EXT_OP_PREFIX);
+	acpigen_emit_byte(ctx, op);
+}
+
+void acpigen_emit_word(struct acpi_ctx *ctx, unsigned int data)
+{
+	acpigen_emit_byte(ctx, data & 0xff);
+	acpigen_emit_byte(ctx, (data >> 8) & 0xff);
+}
+
+void acpigen_emit_dword(struct acpi_ctx *ctx, unsigned int 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);
+}
+
+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_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_ones(struct acpi_ctx *ctx)
+{
+	acpigen_emit_byte(ctx, ONES_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_write_name_zero(struct acpi_ctx *ctx, const char *name)
+{
+	acpigen_write_name(ctx, name);
+	acpigen_write_one(ctx);
+}
+
+void acpigen_write_name_one(struct acpi_ctx *ctx, const char *name)
+{
+	acpigen_write_name(ctx, name);
+	acpigen_write_zero(ctx);
+}
+
+void acpigen_write_name_byte(struct acpi_ctx *ctx, const char *name, u8 val)
+{
+	acpigen_write_name(ctx, name);
+	acpigen_write_byte(ctx, val);
+}
+
+void acpigen_write_name_dword(struct acpi_ctx *ctx, const char *name, u32 val)
+{
+	acpigen_write_name(ctx, name);
+	acpigen_write_dword(ctx, val);
+}
+
+void acpigen_write_name_qword(struct acpi_ctx *ctx, const char *name, u64 val)
+{
+	acpigen_write_name(ctx, name);
+	acpigen_write_qword(ctx, val);
+}
+
+void acpigen_write_name_integer(struct acpi_ctx *ctx, const char *name, u64 val)
+{
+	acpigen_write_name(ctx, name);
+	acpigen_write_integer(ctx, val);
+}
+
+void acpigen_write_name_string(struct acpi_ctx *ctx, const char *name,
+			       const char *string)
+{
+	acpigen_write_name(ctx, name);
+	acpigen_write_string(ctx, string);
+}
+
+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 *string)
+{
+	acpigen_emit_stream(ctx, string, string ? strlen(string) : 0);
+	acpigen_emit_byte(ctx, '\0'); /* NUL */
+}
+
+void acpigen_write_string(struct acpi_ctx *ctx, const char *string)
+{
+	acpigen_emit_byte(ctx, STRING_PREFIX);
+	acpigen_emit_string(ctx, string);
+}
+
+void acpigen_write_coreboot_hid(struct acpi_ctx *ctx, enum coreboot_acpi_ids id)
+{
+	char hid[9]; /* BOOTxxxx */
+
+	snprintf(hid, sizeof(hid), "%.4s%04X", COREBOOT_ACPI_ID, id);
+	acpigen_write_name_string(ctx, "_HID", hid);
+}
+
+/*
+ * 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, 18.2.2 and 18.4 of ACPI spec 3.0 for details.
+ */
+
+static void acpigen_emit_simple_namestring(struct acpi_ctx *ctx,
+					   const char *name)
+{
+	char ud[] = "____";
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		if ((name[i] == '\0') || (name[i] == '.')) {
+			acpigen_emit_stream(ctx, ud, 4 - i);
+			break;
+		}
+		acpigen_emit_byte(ctx, name[i]);
+	}
+}
+
+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)
+{
+	int count = 0;
+	unsigned char *pathlen;
+
+	acpigen_emit_byte(ctx, MULTI_NAME_PREFIX);
+	acpigen_emit_byte(ctx, ZERO_OP);
+	pathlen = ((unsigned char *)ctx->current) - 1;
+
+	while (name[0] != '\0') {
+		acpigen_emit_simple_namestring(ctx, name);
+		/* find end or next entity */
+		while ((name[0] != '.') && (name[0] != '\0'))
+			name++;
+		/* forward to next */
+		if (name[0] == '.')
+			name++;
+		count++;
+	}
+
+	pathlen[0] = count;
+}
+
+void acpigen_emit_namestring(struct acpi_ctx *ctx, const char *namepath)
+{
+	int dotcount = 0, i;
+	int dotpos = 0;
+
+	/* We can start with a '\'. */
+	if (namepath[0] == '\\') {
+		acpigen_emit_byte(ctx, '\\');
+		namepath++;
+	}
+
+	/* And there can be any number of '^' */
+	while (namepath[0] == '^') {
+		acpigen_emit_byte(ctx, '^');
+		namepath++;
+	}
+
+	/*
+	 * If we have only \\ or only ^...^ then we need to add a null name
+	 * (0x00)
+	 */
+	if (namepath[0] == '\0') {
+		acpigen_emit_byte(ctx, ZERO_OP);
+		return;
+	}
+
+	i = 0;
+	while (namepath[i] != '\0') {
+		if (namepath[i] == '.') {
+			dotcount++;
+			dotpos = i;
+		}
+		i++;
+	}
+
+	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 *name)
+{
+	acpigen_emit_byte(ctx, NAME_OP);
+	acpigen_emit_namestring(ctx, name);
+}
+
+void acpigen_write_scope(struct acpi_ctx *ctx, const char *name)
+{
+	acpigen_emit_byte(ctx, SCOPE_OP);
+	acpigen_write_len_f(ctx);
+	acpigen_emit_namestring(ctx, name);
+}
+
+void acpigen_write_processor(struct acpi_ctx *ctx, u8 cpuindex, u32 pblock_addr,
+			     u8 pblock_len)
+{
+	/*
+	 * Processor (\_PR.CPcpuindex, cpuindex, pblock_addr, pblock_len)
+	 * {
+	 */
+	char pscope[16];
+
+	acpigen_emit_ext_op(ctx, PROCESSOR_OP);
+	acpigen_write_len_f(ctx);
+
+	snprintf(pscope, sizeof(pscope), ACPI_CPU_STRING, (uint)cpuindex);
+	acpigen_emit_namestring(ctx, pscope);
+	acpigen_emit_byte(ctx, cpuindex);
+	acpigen_emit_dword(ctx, pblock_addr);
+	acpigen_emit_byte(ctx, pblock_len);
+}
+
+void acpigen_write_processor_package(struct acpi_ctx *ctx,
+				     const char *const name,
+				     const uint first_core,
+				     const uint core_count)
+{
+	uint i;
+	char pscope[16];
+
+	acpigen_write_name(ctx, name);
+	acpigen_write_package(ctx, core_count);
+	for (i = first_core; i < first_core + core_count; ++i) {
+		snprintf(pscope, sizeof(pscope), ACPI_CPU_STRING, i);
+		acpigen_emit_namestring(ctx, pscope);
+	}
+	acpigen_pop_len(ctx);
+}
+
+/* Method to notify all CPU cores */
+void acpigen_write_processor_cnot(struct acpi_ctx *ctx, const uint num_cores)
+{
+	int core_id;
+
+	acpigen_write_method(ctx, "\\_PR.CNOT", 1);
+	for (core_id = 0; core_id < num_cores; core_id++) {
+		char buffer[30];
+
+		snprintf(buffer, sizeof(buffer), ACPI_CPU_STRING, core_id);
+		acpigen_emit_byte(ctx, NOTIFY_OP);
+		acpigen_emit_namestring(ctx, buffer);
+		acpigen_emit_byte(ctx, ARG0_OP);
+	}
+	acpigen_pop_len(ctx);
+}
+
+/*
+ * Generate ACPI AML code for OperationRegion
+ * Arg0: Pointer to struct opregion opreg = OPREGION(rname, space, offset, len)
+ * where rname is region name, space is region space, offset is region offset &
+ * len is region length.
+ * OperationRegion(regionname, regionspace, regionoffset, regionlength)
+ */
+void acpigen_write_opregion(struct acpi_ctx *ctx, struct opregion *opreg)
+{
+	/* OpregionOp */
+	acpigen_emit_ext_op(ctx, OPREGION_OP);
+	/* NameString 4 chars only */
+	acpigen_emit_simple_namestring(ctx, opreg->name);
+	/* RegionSpace */
+	acpigen_emit_byte(ctx, opreg->regionspace);
+	/* RegionOffset & RegionLen, it can be byte word or double word */
+	acpigen_write_integer(ctx, opreg->regionoffset);
+	acpigen_write_integer(ctx, opreg->regionlen);
+}
+
+static void acpigen_write_field_length(struct acpi_ctx *ctx, u32 len)
+{
+	u8 i, j;
+	u8 emit[4];
+
+	i = 1;
+	if (len < 0x40) {
+		emit[0] = len & 0x3F;
+	} else {
+		emit[0] = len & 0xF;
+		len >>= 4;
+		while (len) {
+			emit[i] = len & 0xFF;
+			i++;
+			len >>= 8;
+		}
+	}
+	/* Update bit 7:6 : Number of bytes followed by emit[0] */
+	emit[0] |= (i - 1) << 6;
+
+	for (j = 0; j < i; j++)
+		acpigen_emit_byte(ctx, emit[j]);
+}
+
+static int acpigen_write_field_offset(struct acpi_ctx *ctx, u32 offset,
+				      u32 current_bit_pos)
+{
+	u32 diff_bits;
+
+	if (offset < current_bit_pos) {
+		log_warning("Cannot move offset backward");
+		return -ESPIPE;
+	}
+
+	diff_bits = offset - current_bit_pos;
+	/* Upper limit */
+	if (diff_bits > 0xFFFFFFF) {
+		log_warning("Offset very large to encode");
+		return E2BIG;
+	}
+
+	acpigen_emit_byte(ctx, 0);
+	acpigen_write_field_length(ctx, diff_bits);
+
+	return 0;
+}
+
+static void acpigen_write_field_name(struct acpi_ctx *ctx, const char *name,
+				     u32 size)
+{
+	acpigen_emit_simple_namestring(ctx, name);
+	acpigen_write_field_length(ctx, size);
+}
+
+/*
+ * Generate ACPI AML code for Field
+ * Arg0: region name
+ * Arg1: Pointer to struct fieldlist.
+ * Arg2: no. of entries in Arg1
+ * Arg3: flags which indicate filed access type, lock rule  & update rule.
+ * Example with fieldlist
+ * struct fieldlist l[] = {
+ *	FIELDLIST_OFFSET(0x84),
+ *	FIELDLIST_NAMESTR("PMCS", 2),
+ *	};
+ * acpigen_write_field("UART", l, ARRAY_SIZE(l), FIELD_ANYACC | FIELD_NOLOCK |
+ *								FIELD_PRESERVE);
+ * Output:
+ * Field (UART, AnyAcc, NoLock, Preserve)
+ *	{
+ *		Offset (0x84),
+ *		PMCS,   2
+ *	}
+ */
+int acpigen_write_field(struct acpi_ctx *ctx, const char *name,
+			struct fieldlist *l, size_t count, uint flags)
+{
+	int i;
+	u32 current_bit_pos = 0;
+	int ret;
+
+	/* FieldOp */
+	acpigen_emit_ext_op(ctx, FIELD_OP);
+	/* Package Length */
+	acpigen_write_len_f(ctx);
+	/* NameString 4 chars only */
+	acpigen_emit_simple_namestring(ctx, name);
+	/* Field Flag */
+	acpigen_emit_byte(ctx, flags);
+
+	for (i = 0; i < count; i++) {
+		switch (l[i].type) {
+		case NAME_STRING:
+			acpigen_write_field_name(ctx, l[i].name, l[i].bits);
+			current_bit_pos += l[i].bits;
+			break;
+		case OFFSET:
+			ret = acpigen_write_field_offset(ctx, l[i].bits,
+							 current_bit_pos);
+			if (ret)
+				return log_msg_ret("field", ret);
+			current_bit_pos = l[i].bits;
+			break;
+		default:
+			log_err("Invalid field type %#x\n", l[i].type);
+			return -EDOM;
+		}
+	}
+	acpigen_pop_len(ctx);
+
+	return 0;
+}
+
+/*
+ * Generate ACPI AML code for IndexField
+ * Arg0: region name
+ * Arg1: Pointer to struct fieldlist.
+ * Arg2: no. of entries in Arg1
+ * Arg3: flags which indicate filed access type, lock rule  & update rule.
+ * Example with fieldlist
+ * struct fieldlist l[] = {
+ *	FIELDLIST_OFFSET(0x84),
+ *	FIELDLIST_NAMESTR("PMCS", 2),
+ *	};
+ * acpigen_write_field("IDX", "DATA" l, ARRAY_SIZE(l), FIELD_ANYACC |
+ *						       FIELD_NOLOCK |
+ *						       FIELD_PRESERVE);
+ * Output:
+ * IndexField (IDX, DATA, AnyAcc, NoLock, Preserve)
+ *	{
+ *		Offset (0x84),
+ *		PMCS,   2
+ *	}
+ */
+int acpigen_write_indexfield(struct acpi_ctx *ctx, const char *idx,
+			     const char *data, struct fieldlist *l,
+			     size_t count, uint flags)
+{
+	u16 i;
+	u32 current_bit_pos = 0;
+	int ret;
+
+	/* FieldOp */
+	acpigen_emit_ext_op(ctx, INDEX_FIELD_OP);
+	/* Package Length */
+	acpigen_write_len_f(ctx);
+	/* NameString 4 chars only */
+	acpigen_emit_simple_namestring(ctx, idx);
+	/* NameString 4 chars only */
+	acpigen_emit_simple_namestring(ctx, data);
+	/* Field Flag */
+	acpigen_emit_byte(ctx, flags);
+
+	for (i = 0; i < count; i++) {
+		switch (l[i].type) {
+		case NAME_STRING:
+			acpigen_write_field_name(ctx, l[i].name, l[i].bits);
+			current_bit_pos += l[i].bits;
+			break;
+		case OFFSET:
+			ret = acpigen_write_field_offset(ctx, l[i].bits,
+							 current_bit_pos);
+			if (ret)
+				return log_msg_ret("field", ret);
+			current_bit_pos = l[i].bits;
+			break;
+		default:
+			log_err("Invalid field type 0x%X\n", l[i].type);
+			return -EDOM;
+		}
+	}
+	acpigen_pop_len(ctx);
+
+	return 0;
+}
+
+void acpigen_write_empty_pct(struct acpi_ctx *ctx)
+{
+	/*
+	 * Name (_PCT, Package (0x02)
+	 * {
+	 *	ResourceTemplate ()
+	 *	{
+	 *		Register (FFixedHW,
+	 *			0x00,               // Bit Width
+	 *			0x00,               // Bit Offset
+	 *			0x0000000000000000, // Address
+	 *			,)
+	 *	},
+	 *
+	 *	ResourceTemplate ()
+	 *	{
+	 *		Register (FFixedHW,
+	 *			0x00,               // Bit Width
+	 *			0x00,               // Bit Offset
+	 *			0x0000000000000000, // Address
+	 *			,)
+	 *	}
+	 * })
+	 */
+	static char stream[] = {
+		/* 00000030    "0._PCT.," */
+		0x08, 0x5F, 0x50, 0x43, 0x54, 0x12, 0x2C,
+		/* 00000038    "........" */
+		0x02, 0x11, 0x14, 0x0A, 0x11, 0x82, 0x0C, 0x00,
+		/* 00000040    "........" */
+		0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		/* 00000048    "....y..." */
+		0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x11, 0x14,
+		/* 00000050    "........" */
+		0x0A, 0x11, 0x82, 0x0C, 0x00, 0x7F, 0x00, 0x00,
+		/* 00000058    "........" */
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x79, 0x00
+	};
+	acpigen_emit_stream(ctx, stream, ARRAY_SIZE(stream));
+}
+
+void acpigen_write_empty_ptc(struct acpi_ctx *ctx)
+{
+	/*
+	 * Name (_PTC, Package (0x02)
+	 * {
+	 *	ResourceTemplate ()
+	 *	{
+	 *		Register (FFixedHW,
+	 *			0x00,               // Bit Width
+	 *			0x00,               // Bit Offset
+	 *			0x0000000000000000, // Address
+	 *			,)
+	 *	},
+	 *
+	 *	ResourceTemplate ()
+	 *	{
+	 *		Register (FFixedHW,
+	 *			0x00,               // Bit Width
+	 *			0x00,               // Bit Offset
+	 *			0x0000000000000000, // Address
+	 *			,)
+	 *	}
+	 * })
+	 */
+	struct acpi_gen_regaddr addr = {
+		.space_id    = ACPI_ADDRESS_SPACE_FIXED,
+		.bit_width   = 0,
+		.bit_offset  = 0,
+		.access_size = 0,
+		.addrl       = 0,
+		.addrh       = 0,
+	};
+
+	acpigen_write_name(ctx, "_PTC");
+	acpigen_write_package(ctx, 2);
+
+	/* ControlRegister */
+	acpigen_write_register_resource(ctx, &addr);
+
+	/* StatusRegister */
+	acpigen_write_register_resource(ctx, &addr);
+
+	acpigen_pop_len(ctx);
+}
+
+static void __acpigen_write_method(struct acpi_ctx *ctx, const char *name,
+				   u8 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_device(struct acpi_ctx *ctx, const char *name)
+{
+	acpigen_emit_ext_op(ctx, DEVICE_OP);
+	acpigen_write_len_f(ctx);
+	acpigen_emit_namestring(ctx, name);
+}
+
+void acpigen_write_sta(struct acpi_ctx *ctx, u8 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);
+}
+
+/*
+ * Generates a func with max supported P-states.
+ */
+void acpigen_write_ppc(struct acpi_ctx *ctx, u8 nr)
+{
+	/*
+	 * Method (_PPC, 0, NotSerialized)
+	 * {
+	 *	Return (nr)
+	 * }
+	 */
+	acpigen_write_method(ctx, "_PPC", 0);
+	acpigen_emit_byte(ctx, RETURN_OP);
+	/* arg */
+	acpigen_write_byte(ctx, nr);
+	acpigen_pop_len(ctx);
+}
+
+/*
+ * Generates a func with max supported P-states saved
+ * in the variable PPCM.
+ */
+void acpigen_write_ppc_nvs(struct acpi_ctx *ctx)
+{
+	/*
+	 * Method (_PPC, 0, NotSerialized)
+	 * {
+	 *	Return (PPCM)
+	 * }
+	 */
+	acpigen_write_method(ctx, "_PPC", 0);
+	acpigen_emit_byte(ctx, RETURN_OP);
+	/* arg */
+	acpigen_emit_namestring(ctx, "PPCM");
+	acpigen_pop_len(ctx);
+}
+
+void acpigen_write_tpc(struct acpi_ctx *ctx, const char *gnvs_tpc_limit)
+{
+	/*
+	 * // Sample _TPC method
+	 * Method (_TPC, 0, NotSerialized)
+	 * {
+	 *	Return (\TLVL)
+	 * }
+	 */
+	acpigen_write_method(ctx, "_TPC", 0);
+	acpigen_emit_byte(ctx, RETURN_OP);
+	acpigen_emit_namestring(ctx, gnvs_tpc_limit);
+	acpigen_pop_len(ctx);
+}
+
+void acpigen_write_prw(struct acpi_ctx *ctx, u32 wake, u32 level)
+{
+	/*
+	 * Name (_PRW, Package () { wake, level }
+	 */
+	acpigen_write_name(ctx, "_PRW");
+	acpigen_write_package(ctx, 2);
+	acpigen_write_integer(ctx, wake);
+	acpigen_write_integer(ctx, level);
+	acpigen_pop_len(ctx);
+}
+
+void acpigen_write_pss_package(struct acpi_ctx *ctx, u32 core_freq, u32 power,
+			       u32 trans_lat, u32 busm_lat, u32 control,
+			       u32 status)
+{
+	acpigen_write_package(ctx, 6);
+	acpigen_write_dword(ctx, core_freq);
+	acpigen_write_dword(ctx, power);
+	acpigen_write_dword(ctx, trans_lat);
+	acpigen_write_dword(ctx, busm_lat);
+	acpigen_write_dword(ctx, control);
+	acpigen_write_dword(ctx, status);
+	acpigen_pop_len(ctx);
+
+	log_debug("PSS: %uMHz power %u control 0x%x status 0x%x\n",
+		  core_freq, power, control, status);
+}
+
+void acpigen_write_psd_package(struct acpi_ctx *ctx, u32 domain, u32 numprocs,
+			       enum psd_coord coordtype)
+{
+	acpigen_write_name(ctx, "_PSD");
+	acpigen_write_package(ctx, 1);
+	acpigen_write_package(ctx, 5);
+	acpigen_write_byte(ctx, 5);	// 5 values
+	acpigen_write_byte(ctx, 0);	// revision 0
+	acpigen_write_dword(ctx, domain);
+	acpigen_write_dword(ctx, coordtype);
+	acpigen_write_dword(ctx, numprocs);
+	acpigen_pop_len(ctx);
+	acpigen_pop_len(ctx);
+}
+
+void acpigen_write_cst_package_entry(struct acpi_ctx *ctx,
+				     struct acpi_cstate *cstate)
+{
+	acpigen_write_package(ctx, 4);
+	acpigen_write_register_resource(ctx, &cstate->resource);
+	acpigen_write_dword(ctx, cstate->ctype);
+	acpigen_write_dword(ctx, cstate->latency);
+	acpigen_write_dword(ctx, cstate->power);
+	acpigen_pop_len(ctx);
+}
+
+void acpigen_write_cst_package(struct acpi_ctx *ctx, struct acpi_cstate *cstate,
+			       int nentries)
+{
+	int i;
+
+	acpigen_write_name(ctx, "_CST");
+	acpigen_write_package(ctx, nentries + 1);
+	acpigen_write_dword(ctx, nentries);
+
+	for (i = 0; i < nentries; i++)
+		acpigen_write_cst_package_entry(ctx, cstate + i);
+
+	acpigen_pop_len(ctx);
+}
+
+void acpigen_write_csd_package(struct acpi_ctx *ctx, u32 domain, u32 numprocs,
+			       enum csd_coord coordtype, u32 index)
+{
+	acpigen_write_name(ctx, "_CSD");
+	acpigen_write_package(ctx, 1);
+	acpigen_write_package(ctx, 6);
+	acpigen_write_byte(ctx, 6);	// 6 values
+	acpigen_write_byte(ctx, 0);	// revision 0
+	acpigen_write_dword(ctx, domain);
+	acpigen_write_dword(ctx, coordtype);
+	acpigen_write_dword(ctx, numprocs);
+	acpigen_write_dword(ctx, index);
+	acpigen_pop_len(ctx);
+	acpigen_pop_len(ctx);
+}
+
+void acpigen_write_tss_package(struct acpi_ctx *ctx, int entries,
+			       struct acpi_tstate *tstate_list)
+{
+	/*
+	 * Sample _TSS package with 100% and 50% duty cycles
+	 * Name (_TSS, Package (0x02)
+	 * {
+	 *	Package(){100, 1000, 0, 0x00, 0)
+	 *	Package(){50, 520, 0, 0x18, 0)
+	 * })
+	 */
+	int i;
+	struct acpi_tstate *tstate = tstate_list;
+
+	acpigen_write_name(ctx, "_TSS");
+	acpigen_write_package(ctx, entries);
+
+	for (i = 0; i < entries; i++) {
+		acpigen_write_package(ctx, 5);
+		acpigen_write_dword(ctx, tstate->percent);
+		acpigen_write_dword(ctx, tstate->power);
+		acpigen_write_dword(ctx, tstate->latency);
+		acpigen_write_dword(ctx, tstate->control);
+		acpigen_write_dword(ctx, tstate->status);
+		acpigen_pop_len(ctx);
+		tstate++;
+	}
+
+	acpigen_pop_len(ctx);
+}
+
+void acpigen_write_tsd_package(struct acpi_ctx *ctx, u32 domain, u32 numprocs,
+			       enum psd_coord coordtype)
+{
+	acpigen_write_name(ctx, "_TSD");
+	acpigen_write_package(ctx, 1);
+	acpigen_write_package(ctx, 5);
+	acpigen_write_byte(ctx, 5);	// 5 values
+	acpigen_write_byte(ctx, 0);	// revision 0
+	acpigen_write_dword(ctx, domain);
+	acpigen_write_dword(ctx, coordtype);
+	acpigen_write_dword(ctx, numprocs);
+	acpigen_pop_len(ctx);
+	acpigen_pop_len(ctx);
+}
+
+void acpigen_write_mem32fixed(struct acpi_ctx *ctx, int readwrite, u32 base,
+			      u32 size)
+{
+	/*
+	 * ACPI 4.0 section 6.4.3.4: 32-Bit Fixed Memory Range Descriptor
+	 * Byte 0:
+	 *   Bit7  : 1 => big item
+	 *   Bit6-0: 0000110 (0x6) => 32-bit fixed memory
+	 */
+	acpigen_emit_byte(ctx, 0x86);
+	/* Byte 1+2: length (0x0009) */
+	acpigen_emit_byte(ctx, 0x09);
+	acpigen_emit_byte(ctx, 0x00);
+	/* bit1-7 are ignored */
+	acpigen_emit_byte(ctx, readwrite ? 0x01 : 0x00);
+	acpigen_emit_dword(ctx, base);
+	acpigen_emit_dword(ctx, size);
+}
+
+static void acpigen_write_register(struct acpi_ctx *ctx,
+				   const struct acpi_gen_regaddr *addr)
+{
+	acpigen_emit_byte(ctx, 0x82);		/* Register Descriptor */
+	acpigen_emit_byte(ctx, 0x0c);		/* Register Length 7:0 */
+	acpigen_emit_byte(ctx, 0x00);		/* Register Length 15:8 */
+	acpigen_emit_byte(ctx, addr->space_id);
+	acpigen_emit_byte(ctx, addr->bit_width);
+	acpigen_emit_byte(ctx, addr->bit_offset);
+	acpigen_emit_byte(ctx, addr->access_size);
+	acpigen_emit_dword(ctx, addr->addrl);
+	acpigen_emit_dword(ctx, addr->addrh);
+}
+
+void acpigen_write_register_resource(struct acpi_ctx *ctx,
+				     const struct acpi_gen_regaddr *addr)
+{
+	acpigen_write_resourcetemplate_header(ctx);
+	acpigen_write_register(ctx, addr);
+	acpigen_write_resourcetemplate_footer(ctx);
+}
+
+void acpigen_write_irq(struct acpi_ctx *ctx, u16 mask)
+{
+	/*
+	 * ACPI 3.0b section 6.4.2.1: IRQ Descriptor
+	 * Byte 0:
+	 *   Bit7  : 0 => small item
+	 *   Bit6-3: 0100 (0x4) => IRQ port descriptor
+	 *   Bit2-0: 010 (0x2) => 2 Bytes long
+	 */
+	acpigen_emit_byte(ctx, 0x22);
+	acpigen_emit_byte(ctx, mask & 0xff);
+	acpigen_emit_byte(ctx, (mask >> 8) & 0xff);
+}
+
+void acpigen_write_resourcetemplate_header(struct acpi_ctx *ctx)
+{
+	/*
+	 * A ResourceTemplate() is a Buffer() with a
+	 * (Byte|Word|DWord) containing the length, followed by one or more
+	 * resource items, terminated by the end tag.
+	 * (small item 0xf, len 1)
+	 */
+	acpigen_emit_byte(ctx, BUFFER_OP);
+	acpigen_write_len_f(ctx);
+	acpigen_emit_byte(ctx, WORD_PREFIX);
+	ctx->len_stack[ctx->ltop++] = ctx->current;
+	/*
+	 * Add two dummy bytes for the ACPI word (keep aligned with the
+	 * calclulation in acpigen_write_resourcetemplate() below)
+	 */
+	acpigen_emit_byte(ctx, 0x00);
+	acpigen_emit_byte(ctx, 0x00);
+}
+
+void acpigen_write_resourcetemplate_footer(struct acpi_ctx *ctx)
+{
+	char *p = ctx->len_stack[--ctx->ltop];
+	int len;
+	/*
+	 * end tag (acpi 4.0 Section 6.4.2.8)
+	 * 0x79 <checksum>
+	 * 0x00 is treated as a good checksum according to the spec
+	 * and is what iasl generates.
+	 */
+	acpigen_emit_byte(ctx, 0x79);
+	acpigen_emit_byte(ctx, 0x00);
+
+	/*
+	 * Start counting past the 2-bytes length added in
+	 * acpigen_write_resourcetemplate() above
+	 */
+	len = (char *)ctx->current - (p + 2);
+
+	/* patch len word */
+	p[0] = len & 0xff;
+	p[1] = (len >> 8) & 0xff;
+	/* patch len field */
+	acpigen_pop_len(ctx);
+}
+
+/*
+ * ToUUID(uuid)
+ *
+ * ACPI 6.1 Section 19.6.136 table 19-385 defines a special output
+ * order for the bytes that make up a UUID Buffer object.
+ * UUID byte order for input:
+ *   aabbccdd-eeff-gghh-iijj-kkllmmnnoopp
+ * UUID byte order for output:
+ *   ddccbbaa-ffee-hhgg-iijj-kkllmmnnoopp
+ */
+#define UUID_LEN 16
+int acpigen_write_uuid(struct acpi_ctx *ctx, const char *uuid)
+{
+	u8 buf[UUID_LEN];
+	size_t i, order[UUID_LEN] = { 3, 2, 1, 0, 5, 4, 7, 6,
+				      8, 9, 10, 11, 12, 13, 14, 15 };
+	int ret;
+
+	/* Parse UUID string into bytes */
+	ret = uuid_str_to_bin(uuid, buf, UUID_STR_FORMAT_STD);
+	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 */
+	for (i = 0; i < UUID_LEN; i++)
+		acpigen_emit_byte(ctx, buf[order[i]]);
+
+	acpigen_pop_len(ctx);
+
+	return 0;
+}
+
+/*
+ * Name (_PRx, Package(One) { name })
+ * ...
+ * PowerResource (name, level, order)
+ */
+void acpigen_write_power_res(struct acpi_ctx *ctx, const char *name, u8 level,
+			     u16 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)
+{
+	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);
+}
+
+/* Store (src, dst) */
+void acpigen_write_store_ops(struct acpi_ctx *ctx, u8 src, u8 dst)
+{
+	acpigen_write_store(ctx);
+	acpigen_emit_byte(ctx, src);
+	acpigen_emit_byte(ctx, dst);
+}
+
+/* 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);
+}
+
+/* Store (val, DEBUG) */
+void acpigen_write_debug_integer(struct acpi_ctx *ctx, u64 val)
+{
+	acpigen_write_store(ctx);
+	acpigen_write_integer(ctx, val);
+	acpigen_emit_ext_op(ctx, DEBUG_OP);
+}
+
+/* Store (op, DEBUG) */
+void acpigen_write_debug_op(struct acpi_ctx *ctx, u8 op)
+{
+	acpigen_write_store(ctx);
+	acpigen_emit_byte(ctx, op);
+	acpigen_emit_ext_op(ctx, DEBUG_OP);
+}
+
+void acpigen_write_if(struct acpi_ctx *ctx)
+{
+	acpigen_emit_byte(ctx, IF_OP);
+	acpigen_write_len_f(ctx);
+}
+
+/* If (And (arg1, arg2)) */
+void acpigen_write_if_and(struct acpi_ctx *ctx, u8 arg1, u8 arg2)
+{
+	acpigen_write_if(ctx);
+	acpigen_emit_byte(ctx, AND_OP);
+	acpigen_emit_byte(ctx, arg1);
+	acpigen_emit_byte(ctx, arg2);
+}
+
+/*
+ * Generates ACPI code for checking if operand1 and operand2 are equal, where,
+ * operand1 is ACPI op and operand2 is an integer.
+ *
+ * If (Lequal (op, val))
+ */
+void acpigen_write_if_lequal_op_int(struct acpi_ctx *ctx, u8 op, u64 val)
+{
+	acpigen_write_if(ctx);
+	acpigen_emit_byte(ctx, LEQUAL_OP);
+	acpigen_emit_byte(ctx, op);
+	acpigen_write_integer(ctx, val);
+}
+
+void acpigen_write_else(struct acpi_ctx *ctx)
+{
+	acpigen_emit_byte(ctx, ELSE_OP);
+	acpigen_write_len_f(ctx);
+}
+
+void acpigen_write_to_buffer(struct acpi_ctx *ctx, u8 src, u8 dst)
+{
+	acpigen_emit_byte(ctx, TO_BUFFER_OP);
+	acpigen_emit_byte(ctx, src);
+	acpigen_emit_byte(ctx, dst);
+}
+
+void acpigen_write_to_integer(struct acpi_ctx *ctx, u8 src, u8 dst)
+{
+	acpigen_emit_byte(ctx, TO_INTEGER_OP);
+	acpigen_emit_byte(ctx, src);
+	acpigen_emit_byte(ctx, dst);
+}
+
+void acpigen_write_byte_buffer(struct acpi_ctx *ctx, u8 *arr, size_t size)
+{
+	size_t i;
+
+	acpigen_emit_byte(ctx, BUFFER_OP);
+	acpigen_write_len_f(ctx);
+	acpigen_write_integer(ctx, size);
+
+	for (i = 0; i < size; i++)
+		acpigen_emit_byte(ctx, arr[i]);
+
+	acpigen_pop_len(ctx);
+}
+
+void acpigen_write_return_byte_buffer(struct acpi_ctx *ctx, u8 *arr,
+				      size_t size)
+{
+	acpigen_emit_byte(ctx, RETURN_OP);
+	acpigen_write_byte_buffer(ctx, arr, size);
+}
+
+void acpigen_write_return_singleton_buffer(struct acpi_ctx *ctx, u8 arg)
+{
+	acpigen_write_return_byte_buffer(ctx, &arg, 1);
+}
+
+void acpigen_write_return_byte(struct acpi_ctx *ctx, u8 arg)
+{
+	acpigen_emit_byte(ctx, RETURN_OP);
+	acpigen_write_byte(ctx, arg);
+}
+
+void acpigen_write_return_integer(struct acpi_ctx *ctx, u64 arg)
+{
+	acpigen_emit_byte(ctx, RETURN_OP);
+	acpigen_write_integer(ctx, arg);
+}
+
+void acpigen_write_return_string(struct acpi_ctx *ctx, const char *arg)
+{
+	acpigen_emit_byte(ctx, RETURN_OP);
+	acpigen_write_string(ctx, arg);
+}
+
+void acpigen_write_upc(struct acpi_ctx *ctx, enum acpi_upc_type type)
+{
+	acpigen_write_name(ctx, "_UPC");
+	acpigen_write_package(ctx, 4);
+	/* Connectable */
+	acpigen_write_byte(ctx, type == UPC_TYPE_UNUSED ? 0 : 0xff);
+	/* Type */
+	acpigen_write_byte(ctx, type);
+	/* Reserved0 */
+	acpigen_write_zero(ctx);
+	/* Reserved1 */
+	acpigen_write_zero(ctx);
+	acpigen_pop_len(ctx);
+}
+
+int acpigen_write_dsm(struct acpi_ctx *ctx, const char *uuid,
+		      hid_callback_func callbacks[], size_t count, void *arg)
+{
+	struct dsm_uuid id = DSM_UUID(uuid, callbacks, count, arg);
+	int ret;
+
+	ret = acpigen_write_dsm_uuid_arr(ctx, &id, 1);
+	if (ret)
+		return log_msg_ret("uuid_arr", ret);
+
+	return 0;
+}
+
+static int acpigen_write_dsm_uuid(struct acpi_ctx *ctx, struct dsm_uuid *id)
+{
+	size_t i;
+	int ret;
+
+	/* If (LEqual (Local0, ToUUID(uuid))) */
+	acpigen_write_if(ctx);
+	acpigen_emit_byte(ctx, LEQUAL_OP);
+	acpigen_emit_byte(ctx, LOCAL0_OP);
+	ret = acpigen_write_uuid(ctx, id->uuid);
+	if (ret)
+		return log_msg_ret("uuid", ret);
+
+	/* ToInteger (Arg2, Local1) */
+	acpigen_write_to_integer(ctx, ARG2_OP, LOCAL1_OP);
+
+	for (i = 0; i < id->count; i++) {
+		/* If (LEqual (Local1, i)) */
+		acpigen_write_if_lequal_op_int(ctx, LOCAL1_OP, i);
+
+		/* Callback to write if handler. */
+		if (id->callbacks[i])
+			id->callbacks[i](ctx, id->arg);
+
+		acpigen_pop_len(ctx);	/* If */
+	}
+
+	/* Default case: Return (Buffer (One) { 0x0 }) */
+	acpigen_write_return_singleton_buffer(ctx, 0x0);
+
+	acpigen_pop_len(ctx);	/* If (LEqual (Local0, ToUUID(uuid))) */
+
+	return 0;
+}
+
+/*
+ * Generate ACPI AML code for _DSM method.
+ * This function takes as input array of uuid for the device, set of callbacks
+ * and argument to pass into the callbacks. Callbacks should ensure that Local0
+ * and Local1 are left untouched. Use of Local2-Local7 is permitted in
+ * callbacks.
+ *
+ * Arguments passed into _DSM method:
+ * Arg0 = UUID
+ * Arg1 = Revision
+ * Arg2 = Function index
+ * Arg3 = Function specific arguments
+ *
+ * AML code generated would look like:
+ * Method (_DSM, 4, Serialized) {
+ *	ToBuffer (Arg0, Local0)
+ *	If (LEqual (Local0, ToUUID(uuid))) {
+ *		ToInteger (Arg2, Local1)
+ *		If (LEqual (Local1, 0)) {
+ *			<acpigen by callback[0]>
+ *		}
+ *		...
+ *		If (LEqual (Local1, n)) {
+ *			<acpigen by callback[n]>
+ *		}
+ *		Return (Buffer (One) { 0x0 })
+ *	}
+ *	...
+ *	If (LEqual (Local0, ToUUID(uuidn))) {
+ *	...
+ *	}
+ *	Return (Buffer (One) { 0x0 })
+ * }
+ */
+int acpigen_write_dsm_uuid_arr(struct acpi_ctx *ctx, struct dsm_uuid *ids,
+			       size_t count)
+{
+	size_t i;
+	int ret;
+
+	/* Method (_DSM, 4, Serialized) */
+	acpigen_write_method_serialized(ctx, "_DSM", 0x4);
+
+	/* ToBuffer (Arg0, Local0) */
+	acpigen_write_to_buffer(ctx, ARG0_OP, LOCAL0_OP);
+
+	for (i = 0; i < count; i++) {
+		ret = acpigen_write_dsm_uuid(ctx, &ids[i]);
+		if (ret)
+			return ret;
+	}
+
+	/* Return (Buffer (One) { 0x0 }) */
+	acpigen_write_return_singleton_buffer(ctx, 0x0);
+
+	acpigen_pop_len(ctx);	/* Method _DSM */
+
+	return 0;
+}
+
+#define CPPC_PACKAGE_NAME "\\GCPC"
+
+int acpigen_write_cppc_package(struct acpi_ctx *ctx,
+			       const struct cppc_config *config)
+{
+	u32 i;
+	u32 max;
+
+	switch (config->version) {
+	case 1:
+		max = CPPC_MAX_FIELDS_VER_1;
+		break;
+	case 2:
+		max = CPPC_MAX_FIELDS_VER_2;
+		break;
+	case 3:
+		max = CPPC_MAX_FIELDS_VER_3;
+		break;
+	default:
+		log_err("CPPC version %u is not implemented\n",
+			config->version);
+		return -EDOM;
+	}
+	acpigen_write_name(ctx, CPPC_PACKAGE_NAME);
+
+	/* Adding 2 to account for length and version fields */
+	acpigen_write_package(ctx, max + 2);
+	acpigen_write_dword(ctx, max + 2);
+
+	acpigen_write_byte(ctx, config->version);
+
+	for (i = 0; i < max; ++i) {
+		const struct acpi_gen_regaddr *reg = &config->regs[i];
+
+		if (reg->space_id == ACPI_ADDRESS_SPACE_MEMORY &&
+		    reg->bit_width == 32 && reg->access_size == 0) {
+			acpigen_write_dword(ctx, reg->addrl);
+		} else {
+			acpigen_write_register_resource(ctx, reg);
+		}
+	}
+	acpigen_pop_len(ctx);
+
+	return 0;
+}
+
+void acpigen_write_cppc_method(struct acpi_ctx *ctx)
+{
+	acpigen_write_method(ctx, "_CPC", 0);
+	acpigen_emit_byte(ctx, RETURN_OP);
+	acpigen_emit_namestring(ctx, CPPC_PACKAGE_NAME);
+	acpigen_pop_len(ctx);
+}
+
+/*
+ * Generate ACPI AML code for _ROM method.
+ * This function takes as input ROM data and ROM length.
+ *
+ * The ACPI spec isn't clear about what should happen at the end of the
+ * ROM. Tests showed that it shouldn't truncate, but fill the remaining
+ * bytes in the returned buffer with zeros.
+ *
+ * Arguments passed into _DSM method:
+ * Arg0 = Offset in Bytes
+ * Arg1 = Bytes to return
+ *
+ * Example:
+ *   acpigen_write_rom(0xdeadbeef, 0x10000)
+ *
+ * AML code generated would look like:
+ * Method (_ROM, 2, NotSerialized) {
+ *
+ *	OperationRegion("ROMS", SYSTEMMEMORY, 0xdeadbeef, 0x10000)
+ *	Field (ROMS, AnyAcc, NoLock, Preserve)
+ *	{
+ *		Offset (0),
+ *		RBF0,   0x80000
+ *	}
+ *
+ *	Store (Arg0, Local0)
+ *	Store (Arg1, Local1)
+ *
+ *	If (LGreater (Local1, 0x1000))
+ *	{
+ *		Store (0x1000, Local1)
+ *	}
+ *
+ *	Store (Local1, Local3)
+ *
+ *	If (LGreater (Local0, 0x10000))
+ *	{
+ *		Return(Buffer(Local1){0})
+ *	}
+ *
+ *	If (LGreater (Local0, 0x0f000))
+ *	{
+ *		Subtract (0x10000, Local0, Local2)
+ *		If (LGreater (Local1, Local2))
+ *		{
+ *			Store (Local2, Local1)
+ *		}
+ *	}
+ *
+ *	Name (ROM1, Buffer (Local3) {0})
+ *
+ *	Multiply (Local0, 0x08, Local0)
+ *	Multiply (Local1, 0x08, Local1)
+ *
+ *	CreateField (RBF0, Local0, Local1, TMPB)
+ *	Store (TMPB, ROM1)
+ *	Return (ROM1)
+ * }
+ */
+int acpigen_write_rom(struct acpi_ctx *ctx, void *bios, const size_t length)
+{
+	int ret;
+
+	assert(bios);
+	assert(length);
+
+	/* Method (_ROM, 2, Serialized) */
+	acpigen_write_method_serialized(ctx, "_ROM", 2);
+
+	/* OperationRegion("ROMS", SYSTEMMEMORY, current, length) */
+	struct opregion opreg = OPREGION("ROMS", SYSTEMMEMORY,
+			(uintptr_t)bios, length);
+	acpigen_write_opregion(ctx, &opreg);
+
+	struct fieldlist l[] = {
+		FIELDLIST_OFFSET(0),
+		FIELDLIST_NAMESTR("RBF0", 8 * length),
+	};
+
+	/*
+	 * Field (ROMS, AnyAcc, NoLock, Preserve)
+	 * {
+	 *  Offset (0),
+	 *  RBF0,   0x80000
+	 * }
+	 */
+	ret = acpigen_write_field(ctx, opreg.name, l, 2, FIELD_ANYACC |
+				  FIELD_NOLOCK | FIELD_PRESERVE);
+	if (ret)
+		return log_msg_ret("field", ret);
+
+	/* Store (Arg0, Local0) */
+	acpigen_write_store(ctx);
+	acpigen_emit_byte(ctx, ARG0_OP);
+	acpigen_emit_byte(ctx, LOCAL0_OP);
+
+	/* Store (Arg1, Local1) */
+	acpigen_write_store(ctx);
+	acpigen_emit_byte(ctx, ARG1_OP);
+	acpigen_emit_byte(ctx, LOCAL1_OP);
+
+	/* ACPI SPEC requires to return at maximum 4KiB */
+	/* If (LGreater (Local1, 0x1000)) */
+	acpigen_write_if(ctx);
+	acpigen_emit_byte(ctx, LGREATER_OP);
+	acpigen_emit_byte(ctx, LOCAL1_OP);
+	acpigen_write_integer(ctx, 0x1000);
+
+	/* Store (0x1000, Local1) */
+	acpigen_write_store(ctx);
+	acpigen_write_integer(ctx, 0x1000);
+	acpigen_emit_byte(ctx, LOCAL1_OP);
+
+	/* Pop if */
+	acpigen_pop_len(ctx);
+
+	/* Store (Local1, Local3) */
+	acpigen_write_store(ctx);
+	acpigen_emit_byte(ctx, LOCAL1_OP);
+	acpigen_emit_byte(ctx, LOCAL3_OP);
+
+	/* If (LGreater (Local0, length)) */
+	acpigen_write_if(ctx);
+	acpigen_emit_byte(ctx, LGREATER_OP);
+	acpigen_emit_byte(ctx, LOCAL0_OP);
+	acpigen_write_integer(ctx, length);
+
+	/* Return(Buffer(Local1){0}) */
+	acpigen_emit_byte(ctx, RETURN_OP);
+	acpigen_emit_byte(ctx, BUFFER_OP);
+	acpigen_write_len_f(ctx);
+	acpigen_emit_byte(ctx, LOCAL1_OP);
+	acpigen_emit_byte(ctx, 0);
+	acpigen_pop_len(ctx);
+
+	/* Pop if */
+	acpigen_pop_len(ctx);
+
+	/* If (LGreater (Local0, length - 4096)) */
+	acpigen_write_if(ctx);
+	acpigen_emit_byte(ctx, LGREATER_OP);
+	acpigen_emit_byte(ctx, LOCAL0_OP);
+	acpigen_write_integer(ctx, length - 4096);
+
+	/* Subtract (length, Local0, Local2) */
+	acpigen_emit_byte(ctx, SUBTRACT_OP);
+	acpigen_write_integer(ctx, length);
+	acpigen_emit_byte(ctx, LOCAL0_OP);
+	acpigen_emit_byte(ctx, LOCAL2_OP);
+
+	/* If (LGreater (Local1, Local2)) */
+	acpigen_write_if(ctx);
+	acpigen_emit_byte(ctx, LGREATER_OP);
+	acpigen_emit_byte(ctx, LOCAL1_OP);
+	acpigen_emit_byte(ctx, LOCAL2_OP);
+
+	/* Store (Local2, Local1) */
+	acpigen_write_store(ctx);
+	acpigen_emit_byte(ctx, LOCAL2_OP);
+	acpigen_emit_byte(ctx, LOCAL1_OP);
+
+	/* Pop if */
+	acpigen_pop_len(ctx);
+
+	/* Pop if */
+	acpigen_pop_len(ctx);
+
+	/* Name (ROM1, Buffer (Local3) {0}) */
+	acpigen_write_name(ctx, "ROM1");
+	acpigen_emit_byte(ctx, BUFFER_OP);
+	acpigen_write_len_f(ctx);
+	acpigen_emit_byte(ctx, LOCAL3_OP);
+	acpigen_emit_byte(ctx, 0);
+	acpigen_pop_len(ctx);
+
+	/* Multiply (Local1, 0x08, Local1) */
+	acpigen_emit_byte(ctx, MULTIPLY_OP);
+	acpigen_emit_byte(ctx, LOCAL1_OP);
+	acpigen_write_integer(ctx, 0x08);
+	acpigen_emit_byte(ctx, LOCAL1_OP);
+
+	/* Multiply (Local0, 0x08, Local0) */
+	acpigen_emit_byte(ctx, MULTIPLY_OP);
+	acpigen_emit_byte(ctx, LOCAL0_OP);
+	acpigen_write_integer(ctx, 0x08);
+	acpigen_emit_byte(ctx, LOCAL0_OP);
+
+	/* CreateField (RBF0, Local0, Local1, TMPB) */
+	acpigen_emit_ext_op(ctx, CREATEFIELD_OP);
+	acpigen_emit_namestring(ctx, "RBF0");
+	acpigen_emit_byte(ctx, LOCAL0_OP);
+	acpigen_emit_byte(ctx, LOCAL1_OP);
+	acpigen_emit_namestring(ctx, "TMPB");
+
+	/* Store (TMPB, ROM1) */
+	acpigen_write_store(ctx);
+	acpigen_emit_namestring(ctx, "TMPB");
+	acpigen_emit_namestring(ctx, "ROM1");
+
+	/* Return (ROM1) */
+	acpigen_emit_byte(ctx, RETURN_OP);
+	acpigen_emit_namestring(ctx, "ROM1");
+
+	/* Pop method */
+	acpigen_pop_len(ctx);
+
+	return 0;
+}
+
+/* Soc-implemented functions -- weak definitions. */
+int __weak acpigen_soc_read_rx_gpio(struct acpi_ctx *ctx, unsigned int gpio_num)
+{
+	log_err("not implemented\n");
+	acpigen_write_debug_string(ctx, "read_rx_gpio not available");
+
+	return -ENOTSUPP;
+}
+
+int __weak acpigen_soc_get_tx_gpio(struct acpi_ctx *ctx, unsigned int gpio_num)
+{
+	log_err("not implemented\n");
+	acpigen_write_debug_string(ctx, "get_tx_gpio not available");
+
+	return -ENOTSUPP;
+}
+
+int __weak acpigen_soc_set_tx_gpio(struct acpi_ctx *ctx, unsigned int gpio_num)
+{
+	log_err("not implemented\n");
+	acpigen_write_debug_string(ctx, "set_tx_gpio not available");
+
+	return -ENOTSUPP;
+}
+
+int __weak acpigen_soc_clear_tx_gpio(struct acpi_ctx *ctx,
+				     unsigned int gpio_num)
+{
+	log_err("not implemented\n");
+	acpigen_write_debug_string(ctx, "clear_tx_gpio not available");
+
+	return -ENOTSUPP;
+}
+
+/*
+ * 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_enable_tx_gpio(struct acpi_ctx *ctx, struct acpi_gpio *gpio)
+{
+	int ret;
+
+	if (gpio->polarity == ACPI_GPIO_ACTIVE_HIGH)
+		ret = acpigen_soc_set_tx_gpio(ctx, gpio->pins[0]);
+	else
+		ret = acpigen_soc_clear_tx_gpio(ctx, gpio->pins[0]);
+	if (ret)
+		return log_msg_ret("call", ret);
+
+	return 0;
+}
+
+int acpigen_disable_tx_gpio(struct acpi_ctx *ctx, struct acpi_gpio *gpio)
+{
+	int ret;
+
+	if (gpio->polarity == ACPI_GPIO_ACTIVE_LOW)
+		return acpigen_soc_set_tx_gpio(ctx, gpio->pins[0]);
+	else
+		return acpigen_soc_clear_tx_gpio(ctx, gpio->pins[0]);
+	if (ret)
+		return log_msg_ret("call", ret);
+
+	return 0;
+}
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 31/39] gpio: Add a method to convert a GPIO to ACPI
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (29 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 30/39] acpi: Add functions to generate ACPI code Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 32/39] irq: Add a method to convert an interrupt " Simon Glass
                   ` (30 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 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>
---

Changes in v2: None

 drivers/gpio/gpio-uclass.c | 21 +++++++++++++++++++++
 include/acpi_device.h      | 12 ++++++++++++
 include/asm-generic/gpio.h | 27 +++++++++++++++++++++++++++
 lib/acpi/acpi_device.c     | 16 ++++++++++++++++
 4 files changed, 76 insertions(+)

diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 0a22441d38..7bd656ad63 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -4,6 +4,7 @@
  */
 
 #include <common.h>
+#include <acpi_device.h>
 #include <dm.h>
 #include <dm/device-internal.h>
 #include <dm/lists.h>
@@ -697,6 +698,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/include/acpi_device.h b/include/acpi_device.h
index f97bd075ec..acd26c0f54 100644
--- a/include/acpi_device.h
+++ b/include/acpi_device.h
@@ -533,6 +533,18 @@ size_t acpi_dp_add_property_list(struct acpi_dp *dp,
  */
 int acpi_dp_write(struct acpi_ctx *ctx, struct acpi_dp *table);
 
+/**
+ * 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.
+ *
+ * @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);
+
 /**
  * acpi_device_write_i2c_dev() - Write an I2C device to ACPI, including
  * information ACPI needs to use it.
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 05777e6afe..b594a273fa 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -9,6 +9,7 @@
 
 #include <dm/ofnode.h>
 
+struct acpi_gpio;
 struct ofnode_phandle_args;
 
 /*
@@ -290,6 +291,20 @@ struct dm_gpio_ops {
 	 */
 	int (*xlate)(struct udevice *dev, struct gpio_desc *desc,
 		     struct ofnode_phandle_args *args);
+
+#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
 };
 
 /**
@@ -657,4 +672,16 @@ int dm_gpio_set_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/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
index 145de90677..adc32f1216 100644
--- a/lib/acpi/acpi_device.c
+++ b/lib/acpi/acpi_device.c
@@ -288,6 +288,22 @@ int acpi_device_write_gpio(struct acpi_ctx *ctx, const struct acpi_gpio *gpio)
 	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;
+}
+
 /* ACPI 6.1 section 6.4.3.8.2.1 - I2cSerialBus() */
 static void acpi_device_write_i2c(struct acpi_ctx *ctx,
 				  const struct acpi_i2c *i2c)
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 32/39] irq: Add a method to convert an interrupt to ACPI
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (30 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 31/39] gpio: Add a method to convert a GPIO to ACPI Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-18 16:17   ` Antwort: " Wolfgang Wallner
  2020-03-18 16:20   ` Wolfgang Wallner
  2020-03-09  3:44 ` [PATCH v2 33/39] acpi: Add support for SSDT generation Simon Glass
                   ` (29 subsequent siblings)
  61 siblings, 2 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 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

 drivers/misc/irq-uclass.c | 18 +++++++-
 include/acpi_device.h     | 27 +++++++++++
 include/irq.h             | 41 +++++++++++++++++
 lib/acpi/acpi_device.c    | 94 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 178 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
index 61aa10e465..b4a8b7b429 100644
--- a/drivers/misc/irq-uclass.c
+++ b/drivers/misc/irq-uclass.c
@@ -153,8 +153,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;
@@ -176,6 +174,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/include/acpi_device.h b/include/acpi_device.h
index acd26c0f54..50ba9b66aa 100644
--- a/include/acpi_device.h
+++ b/include/acpi_device.h
@@ -545,6 +545,33 @@ int acpi_dp_write(struct acpi_ctx *ctx, struct acpi_dp *table);
 int acpi_device_write_gpio_desc(struct acpi_ctx *ctx,
 				const struct gpio_desc *desc);
 
+/**
+ * acpi_device_write_interrupt_irq() - Write an interrupt to ACPI
+ *
+ * This creates an interrupt descriptor for an interrupt, including information
+ * ACPI needs to use it.
+ *
+ * @req_irq: Interrupt to write
+ * @return 0 if OK, -ve on error
+ */
+int acpi_device_write_interrupt_irq(struct acpi_ctx *ctx,
+				    const struct irq *req_irq);
+
+/**
+ * acpi_device_write_interrupt_or_gpio() - Write interrupt or GPIO to ACPI
+ *
+ * This reads the an interrupt from the device tree, if available. If not it
+ * reads the first GPIO with the name @prop.
+ *
+ * If an interrupt is found, that is written to ACPI. If not, but an GPIO is
+ * found, that 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);
+
 /**
  * acpi_device_write_i2c_dev() - Write an I2C device to ACPI, including
  * information ACPI needs to use it.
diff --git a/include/irq.h b/include/irq.h
index d4948e6dc4..8527e4dd79 100644
--- a/include/irq.h
+++ b/include/irq.h
@@ -8,6 +8,7 @@
 #ifndef __irq_H
 #define __irq_H
 
+struct acpi_irq;
 struct ofnode_phandle_args;
 
 /*
@@ -26,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;
 };
 
 /**
@@ -121,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
  *
@@ -225,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/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
index adc32f1216..aa5edfe807 100644
--- a/lib/acpi/acpi_device.c
+++ b/lib/acpi/acpi_device.c
@@ -154,6 +154,58 @@ int acpi_device_status(const struct udevice *dev)
 	return ACPI_STATUS_DEVICE_ALL_ON;
 }
 
+/* ACPI 6.1 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 || !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;
+}
+
 /* ACPI 6.1 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)
 {
@@ -304,6 +356,48 @@ int acpi_device_write_gpio_desc(struct acpi_ctx *ctx,
 	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;
+}
+
+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;
+}
+
 /* ACPI 6.1 section 6.4.3.8.2.1 - I2cSerialBus() */
 static void acpi_device_write_i2c(struct acpi_ctx *ctx,
 				  const struct acpi_i2c *i2c)
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 33/39] acpi: Add support for SSDT generation
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (31 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 32/39] irq: Add a method to convert an interrupt " Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-18 16:48   ` Antwort: " Wolfgang Wallner
  2020-03-19  7:39   ` Wolfgang Wallner
  2020-03-09  3:44 ` [PATCH v2 34/39] x86: acpi: Move MADT up a bit Simon Glass
                   ` (28 subsequent siblings)
  61 siblings, 2 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 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>
---

Changes in v2:
- Switch parameter order of _acpi_fill_ssdt() and make it static

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

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 1204c14b07..fefa3af999 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -208,10 +208,12 @@
 
 	acpi-test {
 		compatible = "denx,u-boot-acpi-test";
+		acpi-ssdt-test-data = "ab";
 	};
 
 	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 10bac38c1d..d2f6a9a9d1 100644
--- a/drivers/core/acpi.c
+++ b/drivers/core/acpi.c
@@ -17,6 +17,7 @@
 /* Type of method to call */
 enum method_t {
 	METHOD_WRITE_TABLES,
+	METHOD_FILL_SDDT,
 };
 
 /* Prototype for all methods */
@@ -49,6 +50,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_SDDT:
+			return aops->fill_ssdt;
 		}
 	}
 
@@ -81,6 +84,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_SDDT);
+	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 0f78a506da..c340c21685 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_return_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 feb380b26c..305d8395ff 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -7,6 +7,7 @@
  */
 
 #include <common.h>
+#include <acpigen.h>
 #include <acpi_table.h>
 #include <console.h>
 #include <dm.h>
@@ -14,7 +15,6 @@
 #include <mapmem.h>
 #include <version.h>
 #include <tables_csum.h>
-#include <version.h>
 #include <dm/acpi.h>
 #include <dm/test.h>
 #include <test/ut.h>
@@ -43,9 +43,21 @@ static int testacpi_get_name(const struct udevice *dev, char *out_name)
 	return acpi_return_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");
+	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[] = {
@@ -313,3 +325,30 @@ 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_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';	/* sentinal */
+	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.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 34/39] x86: acpi: Move MADT up a bit
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (32 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 33/39] acpi: Add support for SSDT generation Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:44 ` [PATCH v2 35/39] acpi: Record the items added to SSDT Simon Glass
                   ` (27 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 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

 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 83b92e2a4c..694e92c158 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -408,18 +408,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.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 35/39] acpi: Record the items added to SSDT
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (33 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 34/39] x86: acpi: Move MADT up a bit Simon Glass
@ 2020-03-09  3:44 ` Simon Glass
  2020-03-09  3:45 ` [PATCH v2 36/39] acpi: Support ordering SSDT data by device Simon Glass
                   ` (26 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:44 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:
- 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 d2f6a9a9d1..7b295bf921 100644
--- a/drivers/core/acpi.c
+++ b/drivers/core/acpi.c
@@ -9,11 +9,20 @@
 #define LOG_CATEOGRY	LOGC_ACPI
 
 #include <common.h>
+#include <malloc.h>
 #include <dm.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,
@@ -23,6 +32,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_return_name(char *out_name, const char *name)
 {
 	strcpy(out_name, name);
@@ -41,6 +69,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;
@@ -59,7 +124,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;
@@ -67,6 +132,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- %s %p\n", parent->name, func);
 		ret = device_ofdata_to_platdata(parent);
 		if (ret)
@@ -74,9 +141,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);
 	}
@@ -89,7 +163,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_SDDT);
+	ret = acpi_recurse_method(ctx, dm_root(), METHOD_FILL_SDDT, TYPE_SSDT);
 	log_debug("Writing SSDT finished, err=%d\n", ret);
 
 	return ret;
@@ -100,7 +174,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.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 36/39] acpi: Support ordering SSDT data by device
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (34 preceding siblings ...)
  2020-03-09  3:44 ` [PATCH v2 35/39] acpi: Record the items added to SSDT Simon Glass
@ 2020-03-09  3:45 ` Simon Glass
  2020-03-09  3:45 ` [PATCH v2 37/39] x86: Allow devices to write an SSDT Simon Glass
                   ` (25 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:45 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:
- 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                      | 17 ++++----
 4 files changed, 84 insertions(+), 9 deletions(-)

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index fefa3af999..7d55d360f6 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -206,12 +206,12 @@
 		compatible = "denx,u-boot-devres-test";
 	};
 
-	acpi-test {
+	acpi_test1: acpi-test {
 		compatible = "denx,u-boot-acpi-test";
 		acpi-ssdt-test-data = "ab";
 	};
 
-	acpi-test2 {
+	acpi_test2: acpi-test2 {
 		compatible = "denx,u-boot-acpi-test";
 		acpi-ssdt-test-data = "cd";
 	};
@@ -829,6 +829,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 7b295bf921..2f57ff9da2 100644
--- a/drivers/core/acpi.c
+++ b/drivers/core/acpi.c
@@ -106,6 +106,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;
@@ -160,11 +217,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_SDDT, 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 305d8395ff..b0d8d41e49 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -336,16 +336,19 @@ static int dm_test_acpi_fill_ssdt(struct unit_test_state *uts)
 	ut_assertnonnull(buf);
 
 	ctx.current = buf;
-	buf[4] = 'z';	/* sentinal */
+	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.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 37/39] x86: Allow devices to write an SSDT
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (35 preceding siblings ...)
  2020-03-09  3:45 ` [PATCH v2 36/39] acpi: Support ordering SSDT data by device Simon Glass
@ 2020-03-09  3:45 ` Simon Glass
  2020-03-09  3:45 ` [PATCH v2 38/39] acpi: Add support for DSDT generation Simon Glass
                   ` (24 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:45 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:
- Move ACPI_TABLE_CREATOR to here

 arch/x86/lib/acpi_table.c | 50 +++++++++++++++++++++++++++++++++++++++
 include/acpi_table.h      |  1 +
 2 files changed, 51 insertions(+)

diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index 694e92c158..3b97fe162c 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -7,6 +7,7 @@
  */
 
 #include <common.h>
+#include <acpigen.h>
 #include <cpu.h>
 #include <dm.h>
 #include <dm/uclass-internal.h>
@@ -344,6 +345,46 @@ static void acpi_create_spcr(struct acpi_spcr *spcr)
 	header->checksum = table_compute_checksum((void *)spcr, header->length);
 }
 
+static void acpi_ssdt_write_cbtable(struct acpi_ctx *ctx)
+{
+	uintptr_t base;
+	u32 size;
+
+	base = 0;
+	size = 0;
+
+	acpigen_write_device(ctx, "CTBL");
+	acpigen_write_coreboot_hid(ctx, COREBOOT_ACPI_ID_CBTABLE);
+	acpigen_write_name_integer(ctx, "_UID", 0);
+	acpigen_write_sta(ctx, ACPI_STATUS_DEVICE_HIDDEN_ON);
+	acpigen_write_name(ctx, "_CRS");
+	acpigen_write_resourcetemplate_header(ctx);
+	acpigen_write_mem32fixed(ctx, 0, base, size);
+	acpigen_write_resourcetemplate_footer(ctx);
+	acpigen_pop_len(ctx);
+}
+
+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));
+
+	/* Write object to declare coreboot tables */
+	acpi_ssdt_write_cbtable(ctx);
+	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
  */
@@ -353,6 +394,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;
@@ -408,6 +450,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, ACPI_TABLE_CREATOR);
+	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_table.h b/include/acpi_table.h
index 5fd2cef5d1..2a802758aa 100644
--- a/include/acpi_table.h
+++ b/include/acpi_table.h
@@ -17,6 +17,7 @@
 #define OEM_ID			"U-BOOT"	/* U-Boot */
 #define OEM_TABLE_ID		"U-BOOTBL"	/* U-Boot Table */
 #define ASLC_ID			"INTL"		/* Intel ASL Compiler */
+#define ACPI_TABLE_CREATOR	OEM_TABLE_ID
 
 #define ACPI_RSDP_REV_ACPI_1_0	0
 #define ACPI_RSDP_REV_ACPI_2_0	2
-- 
2.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 38/39] acpi: Add support for DSDT generation
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (36 preceding siblings ...)
  2020-03-09  3:45 ` [PATCH v2 37/39] x86: Allow devices to write an SSDT Simon Glass
@ 2020-03-09  3:45 ` Simon Glass
  2020-03-09  3:45 ` [PATCH v2 39/39] x86: Allow devices to write to DSDT Simon Glass
                   ` (23 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:45 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:
- 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            | 42 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 91 insertions(+), 1 deletion(-)

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 7d55d360f6..9748c29a49 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -209,11 +209,13 @@
 	acpi_test1: acpi-test {
 		compatible = "denx,u-boot-acpi-test";
 		acpi-ssdt-test-data = "ab";
+		acpi-dsdt-test-data = "hi";
 	};
 
 	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 2f57ff9da2..5613a41eb0 100644
--- a/drivers/core/acpi.c
+++ b/drivers/core/acpi.c
@@ -21,12 +21,14 @@
 enum gen_type_t {
 	TYPE_NONE,
 	TYPE_SSDT,
+	TYPE_DSDT,
 };
 
 /* Type of method to call */
 enum method_t {
 	METHOD_WRITE_TABLES,
 	METHOD_FILL_SDDT,
+	METHOD_INJECT_DSDT,
 };
 
 /* Prototype for all methods */
@@ -129,7 +131,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;
@@ -174,6 +178,8 @@ acpi_method acpi_get_method(struct udevice *dev, enum method_t method)
 			return aops->write_tables;
 		case METHOD_FILL_SDDT:
 			return aops->fill_ssdt;
+		case METHOD_INJECT_DSDT:
+			return aops->inject_dsdt;
 		}
 	}
 
@@ -231,6 +237,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 c340c21685..8de9296e71 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 b0d8d41e49..16dc0955be 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -54,10 +54,22 @@ 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");
+	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[] = {
@@ -355,3 +367,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.25.1.481.gfbce0eb801-goog

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

* [PATCH v2 39/39] x86: Allow devices to write to DSDT
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (37 preceding siblings ...)
  2020-03-09  3:45 ` [PATCH v2 38/39] acpi: Add support for DSDT generation Simon Glass
@ 2020-03-09  3:45 ` Simon Glass
  2020-03-09  7:38 ` Antwort: [PATCH v2 02/39] spi: Add SPI mode enums Wolfgang Wallner
                   ` (22 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-09  3:45 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

 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 3b97fe162c..5e14149923 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -422,7 +422,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.25.1.481.gfbce0eb801-goog

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

* Antwort: [PATCH v2 02/39] spi: Add SPI mode enums
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (38 preceding siblings ...)
  2020-03-09  3:45 ` [PATCH v2 39/39] x86: Allow devices to write to DSDT Simon Glass
@ 2020-03-09  7:38 ` Wolfgang Wallner
  2020-03-09  7:38 ` Antwort: [PATCH v2 08/39] x86: Correct wording of coreboot source code Wolfgang Wallner
                   ` (21 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-09  7:38 UTC (permalink / raw)
  To: u-boot

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> With ACPI we need to describe the settings of the SPI bus. Add enums to
> handle this.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> ---
> 
> Changes in v2:
> - Don't bracket the definitions with DM_SPI
> 
>  include/spi.h | 33 +++++++++++++++++++++++++++++++++
>  1 file changed, 33 insertions(+)

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

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

* Antwort: [PATCH v2 08/39] x86: Correct wording of coreboot source code
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (39 preceding siblings ...)
  2020-03-09  7:38 ` Antwort: [PATCH v2 02/39] spi: Add SPI mode enums Wolfgang Wallner
@ 2020-03-09  7:38 ` Wolfgang Wallner
  2020-03-09  7:38 ` Antwort: [PATCH v2 10/39] pci: Adjust dm_pci_read_bar32() to return errors correctly Wolfgang Wallner
                   ` (20 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-09  7:38 UTC (permalink / raw)
  To: u-boot

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> Some files are taken or modified from coreboot, but the files are
> no-longer part of the coreboot project. Fix the wording in a few places.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> ---
> 
> Changes in v2: None
> 
>  arch/x86/cpu/coreboot/timestamp.c              | 4 ++--
>  arch/x86/include/asm/arch-coreboot/timestamp.h | 4 ++--
>  arch/x86/include/asm/intel_pinctrl_defs.h      | 2 --
>  3 files changed, 4 insertions(+), 6 deletions(-)

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

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

* Antwort: [PATCH v2 10/39] pci: Adjust dm_pci_read_bar32() to return errors correctly
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (40 preceding siblings ...)
  2020-03-09  7:38 ` Antwort: [PATCH v2 08/39] x86: Correct wording of coreboot source code Wolfgang Wallner
@ 2020-03-09  7:38 ` Wolfgang Wallner
  2020-03-09  7:38 ` Antwort: [PATCH v2 11/39] x86: apl: Add Global NVS table header Wolfgang Wallner
                   ` (19 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-09  7:38 UTC (permalink / raw)
  To: u-boot


-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> At present if reading a BAR returns 0xffffffff (e.g. the device is not
> present) then the value is masked and a different value is returned.
> This makes it harder to detect the problem when debugging.
> 
> Update the function to avoid masking in this case.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> ---
> 
> Changes in v2: None
> 
>  drivers/pci/pci-uclass.c | 9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)

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

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

* Antwort: [PATCH v2 11/39] x86: apl: Add Global NVS table header
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (41 preceding siblings ...)
  2020-03-09  7:38 ` Antwort: [PATCH v2 10/39] pci: Adjust dm_pci_read_bar32() to return errors correctly Wolfgang Wallner
@ 2020-03-09  7:38 ` Wolfgang Wallner
  2020-03-09  9:07 ` Antwort: [PATCH v2 12/39] dm: core: Add basic ACPI support Wolfgang Wallner
                   ` (18 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-09  7:38 UTC (permalink / raw)
  To: u-boot

Hi Simon,

> -----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> Add the C version of this header. It includes a few Chrome OS bits which
> are disabled for a normal build.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2:
> - Drop the Chrome OS pieces
> - Rename the 'coreboot' console to 'U-Boot'
> 
>  .../include/asm/arch-apollolake/global_nvs.h  | 37 +++++++++++++++++++
>  1 file changed, 37 insertions(+)
>  create mode 100644 arch/x86/include/asm/arch-apollolake/global_nvs.h
> 
> diff --git a/arch/x86/include/asm/arch-apollolake/global_nvs.h b/arch/x86/include/asm/arch-apollolake/global_nvs.h
> new file mode 100644
> index 0000000000..344a853fe9
> --- /dev/null
> +++ b/arch/x86/include/asm/arch-apollolake/global_nvs.h
> @@ -0,0 +1,37 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2015-2017 Intel Corp.
> + * (Written by Lance Zhao <lijian.zhao@intel.com> for Intel Corp.)
> + * Copyright Google LLC 2019
> + *
> + * Modified from coreboot apollolake/include/soc/nvs.h
> + */
> +
> +#ifndef _GLOBAL_NVS_H_
> +#define _GLOBAL_NVS_H_
> +
> +struct __packed acpi_global_nvs {
> +	/* Miscellaneous */
> +	u8	pcnt; /* 0x00 - Processor Count */
> +	u8	ppcm; /* 0x01 - Max PPC State */
> +	u8	lids; /* 0x02 - LID State */
> +	u8	pwrs; /* 0x03 - AC Power State */
> +	u8	dpte; /* 0x04 - Enable DPTF */
> +	u32	cbmc; /* 0x05 - 0x08 - U-Boot Console */
> +	u64	pm1i; /* 0x09 - 0x10 - System Wake Source - PM1 Index */
> +	u64	gpei; /* 0x11 - 0x18 - GPE Wake Source */
> +	u64	nhla; /* 0x19 - 0x20 - NHLT Address */
> +	u32	nhll; /* 0x21 - 0x24 - NHLT Length */
> +	u32	prt0; /* 0x25 - 0x28 - PERST_0 Address */
> +	u8	scdp; /* 0x29 - SD_CD GPIO portid */
> +	u8	scdo; /* 0x2A - GPIO pad offset relative to the community */
> +	u8	uior; /* 0x2B - UART debug controller init on S3 resume */
> +	u8	ecps; /* 0x2C - SGX Enabled status */
> +	u64	emna; /* 0x2D - 0x34 EPC base address */
> +	u64	elng; /* 0x35 - 0x3C EPC Length */
> +	u8	unused[195];
> +	u8		unused2[0xf00];
> +#endif

Something happened here in v2, there is no matching #if for the #endif anymore.

> +};
> +
> +#endif /* _GLOBAL_NVS_H_ */
> -- 
> 2.25.1.481.gfbce0eb801-goog

regards, Wolfgang

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

* [PATCH v2 02/39] spi: Add SPI mode enums
  2020-03-09  3:44 ` [PATCH v2 02/39] spi: Add SPI mode enums Simon Glass
@ 2020-03-09  7:41   ` Andy Shevchenko
  0 siblings, 0 replies; 86+ messages in thread
From: Andy Shevchenko @ 2020-03-09  7:41 UTC (permalink / raw)
  To: u-boot

On Mon, Mar 9, 2020 at 5:45 AM Simon Glass <sjg@chromium.org> wrote:
>
> With ACPI we need to describe the settings of the SPI bus. Add enums to
> handle this.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> ---
>
> Changes in v2:
> - Don't bracket the definitions with DM_SPI
>
>  include/spi.h | 33 +++++++++++++++++++++++++++++++++
>  1 file changed, 33 insertions(+)
>
> diff --git a/include/spi.h b/include/spi.h
> index 852f570eaa..2092940f4c 100644
> --- a/include/spi.h
> +++ b/include/spi.h
> @@ -66,6 +66,39 @@ struct dm_spi_slave_platdata {
>
>  #endif /* CONFIG_DM_SPI */
>
> +/**
> + * enum spi_clock_phase - indicates  the clock phase to use for SPI (CPHA)
> + *
> + * @SPI_CLOCK_PHASE_FIRST: Data sampled on the first phase
> + * @SPI_CLOCK_PHASE_SECOND: Data sampled on the second phase
> + */
> +enum spi_clock_phase {
> +       SPI_CLOCK_PHASE_FIRST,
> +       SPI_CLOCK_PHASE_SECOND

I always forget if absence of comma in such cases (where it's not
obvious that the last item in the enum, struct or array is a
terminator line) is U-Boot style, but I this the rule of thumb is to
have comma at the end to simplify extension or adjustment  in the
future.

> +};
> +
> +/**
> + * enum spi_wire_mode - indicates the number of wires used for SPI
> + *
> + * @SPI_4_WIRE_MODE: Normal bidirectional mode with MOSI and MISO
> + * @SPI_3_WIRE_MODE: Unidirectional version with a single data line SISO
> + */
> +enum spi_wire_mode {
> +       SPI_4_WIRE_MODE,
> +       SPI_3_WIRE_MODE
> +};
> +
> +/**
> + * enum spi_polarity - indicates the polarity of the SPI bus (CPOL)
> + *
> + * @SPI_POLARITY_LOW: Clock is low in idle state
> + * @SPI_POLARITY_HIGH: Clock is high in idle state
> + */
> +enum spi_polarity {
> +       SPI_POLARITY_LOW,
> +       SPI_POLARITY_HIGH
> +};
> +
>  /**
>   * struct spi_slave - Representation of a SPI slave
>   *
> --
> 2.25.1.481.gfbce0eb801-goog
>


-- 
With Best Regards,
Andy Shevchenko

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

* [PATCH v2 07/39] dm: pci: Allow disabling auto-config for a device
  2020-03-09  3:44 ` [PATCH v2 07/39] dm: pci: Allow disabling auto-config for a device Simon Glass
@ 2020-03-09  7:43   ` Andy Shevchenko
  0 siblings, 0 replies; 86+ messages in thread
From: Andy Shevchenko @ 2020-03-09  7:43 UTC (permalink / raw)
  To: u-boot

On Mon, Mar 9, 2020 at 5:46 AM Simon Glass <sjg@chromium.org> wrote:
>
> Add a means to avoid configuring a device when needed. Add an explanation
> of why this is useful to the binding file.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> ---
>
> Changes in v2: None
>
>  doc/device-tree-bindings/pci/x86-pci.txt | 24 ++++++++++++++++++++++++
>  drivers/pci/pci-uclass.c                 |  2 ++
>  2 files changed, 26 insertions(+)
>
> diff --git a/doc/device-tree-bindings/pci/x86-pci.txt b/doc/device-tree-bindings/pci/x86-pci.txt
> index 3aa5bd9a46..62b29a4e36 100644
> --- a/doc/device-tree-bindings/pci/x86-pci.txt
> +++ b/doc/device-tree-bindings/pci/x86-pci.txt
> @@ -10,6 +10,17 @@ Optional properties:
>         configuration in TPL/SPL to reduce code size and boot time, since these
>         phases only know about a small subset of PCI devices.
>
> +For PCI devices the following optional property is available:
> +
> +- pci,no-autoconfig : Don't automatically configure this PCI device at all.
> +       This is used when the device is statically configured and must maintain
> +       this same config throughout the boot process. An example is a serial
> +       UART being used to debug PCI configuration, since reconfiguring it stops
> +       the UART from working until the driver is re-probed, and this can cause
> +       output to be lost. This should not generally be used in production code,
> +       although it is often harmless.
> +
> +
>  Example:
>
>  pci {
> @@ -21,4 +32,17 @@ pci {
>                 0x42000000 0x0 0xb0000000 0xb0000000 0 0x10000000
>                 0x01000000 0x0 0x1000 0x1000 0 0xefff>;
>         u-boot,skip-auto-config-until-reloc;
> +
> +
> +       serial: serial at 18,2 {
> +               reg = <0x0200c210 0 0 0 0>;
> +               u-boot,dm-pre-reloc;
> +               compatible = "intel,apl-ns16550";
> +               early-regs = <0xde000000 0x20>;
> +               reg-shift = <2>;
> +               clock-frequency = <1843200>;
> +               current-speed = <115200>;


> +               acpi,name = "URT3";

Is this somehow being handled by the code at this point?
If no, please move to the patch that actually adds this functionality.

> +               pci,no-autoconfig;
> +       };
>  };
> diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
> index 94733662b1..213381da6b 100644
> --- a/drivers/pci/pci-uclass.c
> +++ b/drivers/pci/pci-uclass.c
> @@ -536,6 +536,8 @@ int pci_auto_config_devices(struct udevice *bus)
>                 int ret;
>
>                 debug("%s: device %s\n", __func__, dev->name);
> +               if (dev_read_bool(dev, "pci,no-autoconfig"))
> +                       continue;
>                 ret = dm_pciauto_config_device(dev);
>                 if (ret < 0)
>                         return ret;
> --
> 2.25.1.481.gfbce0eb801-goog
>


-- 
With Best Regards,
Andy Shevchenko

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

* [PATCH v2 08/39] x86: Correct wording of coreboot source code
  2020-03-09  3:44 ` [PATCH v2 08/39] x86: Correct wording of coreboot source code Simon Glass
@ 2020-03-09  7:44   ` Andy Shevchenko
  2020-03-10 23:22     ` Simon Glass
  0 siblings, 1 reply; 86+ messages in thread
From: Andy Shevchenko @ 2020-03-09  7:44 UTC (permalink / raw)
  To: u-boot

On Mon, Mar 9, 2020 at 5:47 AM Simon Glass <sjg@chromium.org> wrote:
>
> Some files are taken or modified from coreboot, but the files are
> no-longer part of the coreboot project. Fix the wording in a few places.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> ---
>
> Changes in v2: None
>
>  arch/x86/cpu/coreboot/timestamp.c              | 4 ++--
>  arch/x86/include/asm/arch-coreboot/timestamp.h | 4 ++--
>  arch/x86/include/asm/intel_pinctrl_defs.h      | 2 --
>  3 files changed, 4 insertions(+), 6 deletions(-)
>
> diff --git a/arch/x86/cpu/coreboot/timestamp.c b/arch/x86/cpu/coreboot/timestamp.c
> index e698200d70..e8ccaf2212 100644
> --- a/arch/x86/cpu/coreboot/timestamp.c
> +++ b/arch/x86/cpu/coreboot/timestamp.c
> @@ -1,8 +1,8 @@
>  // SPDX-License-Identifier: GPL-2.0+
>  /*
> - * This file is part of the coreboot project.
> - *
>   * Copyright (C) 2011 The ChromiumOS Authors.  All rights reserved.
> + *
> + * Modified from the coreboot version

Perhaps leave the period at the end of the line to follow English punctuation?

>   */
>
>  #include <common.h>
> diff --git a/arch/x86/include/asm/arch-coreboot/timestamp.h b/arch/x86/include/asm/arch-coreboot/timestamp.h
> index 9320afba56..85d42c02c4 100644
> --- a/arch/x86/include/asm/arch-coreboot/timestamp.h
> +++ b/arch/x86/include/asm/arch-coreboot/timestamp.h
> @@ -1,8 +1,8 @@
>  /* SPDX-License-Identifier: GPL-2.0 */
>  /*
> - * This file is part of the coreboot project.
> - *
>   * Copyright (C) 2011 The ChromiumOS Authors.  All rights reserved.
> + *
> + * Taken from the coreboot version
>   */
>
>  #ifndef __COREBOOT_TIMESTAMP_H__
> diff --git a/arch/x86/include/asm/intel_pinctrl_defs.h b/arch/x86/include/asm/intel_pinctrl_defs.h
> index 6da06bb52b..1ea141f082 100644
> --- a/arch/x86/include/asm/intel_pinctrl_defs.h
> +++ b/arch/x86/include/asm/intel_pinctrl_defs.h
> @@ -1,7 +1,5 @@
>  /* SPDX-License-Identifier: GPL-2.0 */
>  /*
> - * This file is part of the coreboot project.
> - *
>   * Copyright (C) 2015-2016 Intel Corp.
>   * Copyright 2019 Google LLC
>   *
> --
> 2.25.1.481.gfbce0eb801-goog
>


-- 
With Best Regards,
Andy Shevchenko

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

* Antwort: [PATCH v2 12/39] dm: core: Add basic ACPI support
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (42 preceding siblings ...)
  2020-03-09  7:38 ` Antwort: [PATCH v2 11/39] x86: apl: Add Global NVS table header Wolfgang Wallner
@ 2020-03-09  9:07 ` Wolfgang Wallner
  2020-03-10  9:15 ` Antwort: [PATCH v2 13/39] acpi: Add a binding for ACPI settings in the device tree Wolfgang Wallner
                   ` (17 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-09  9:07 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> ACPI (Advanced Configuration and Power Interface) is an Intel standard
> for specifying information about a platform. It is a little like device
> tree but considerably more complicated and with more backslashes. A
> primary difference is that it supports an interpreted bytecode language.
> 
> Driver model does not use ACPI for U-Boot's configuration, but it is
> convenient to have it support generation of ACPI tables for passing to
> Linux, etc.
> 
> As a starting point, add an optional set of ACPI operations to each
> device. Initially only a single operation is available, to obtain the
> ACPI name for the device. More operations are added later.
> 
> Enable ACPI for sandbox to ensure build coverage and so that we can add
> tests.
> 
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2:
> - Move LOGC_ACPI definition to this patch
> 
>  drivers/core/Kconfig  |  9 ++++++
>  drivers/core/Makefile |  1 +
>  drivers/core/acpi.c   | 32 +++++++++++++++++++
>  include/dm/acpi.h     | 73 +++++++++++++++++++++++++++++++++++++++++++
>  include/dm/device.h   |  5 +++
>  include/log.h         |  2 ++
>  6 files changed, 122 insertions(+)
>  create mode 100644 drivers/core/acpi.c
>  create mode 100644 include/dm/acpi.h
> 
> diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
> index 3b95b5387b..a3b0399342 100644
> --- a/drivers/core/Kconfig
> +++ b/drivers/core/Kconfig
> @@ -261,4 +261,13 @@ config DM_DEV_READ_INLINE
>  	bool
>  	default y if !OF_LIVE
>  
> +config ACPIGEN
> +	bool "Support ACPI table generation in driver model"
> +	default y if SANDBOX || GENERATE_ACPI_TABLE
> +	help
> +	  This option enables generation of ACPI tables using driver-model
> +	  devices. It adds a new operation struct to each driver, to support
> +	  things like generating device-specific tables and returning the ACPI
> +	  name of a device.
> +
>  endmenu
> diff --git a/drivers/core/Makefile b/drivers/core/Makefile
> index bce7467da1..c707026a3a 100644
> --- a/drivers/core/Makefile
> +++ b/drivers/core/Makefile
> @@ -3,6 +3,7 @@
>  # Copyright (c) 2013 Google, Inc
>  
>  obj-y	+= device.o fdtaddr.o lists.o root.o uclass.o util.o
> +obj-$(CONFIG_$(SPL_TPL_)ACPIGEN) += acpi.o
>  obj-$(CONFIG_DEVRES) += devres.o
>  obj-$(CONFIG_$(SPL_)DM_DEVICE_REMOVE)	+= device-remove.o
>  obj-$(CONFIG_$(SPL_)SIMPLE_BUS)	+= simple-bus.o
> diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c
> new file mode 100644
> index 0000000000..45542199f5
> --- /dev/null
> +++ b/drivers/core/acpi.c
> @@ -0,0 +1,32 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Core driver model support for ACPI table generation
> + *
> + * Copyright 2019 Google LLC
> + * Written by Simon Glass <sjg@chromium.org>
> + */
> +
> +#define LOG_CATEOGRY	LOGC_ACPI
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <dm/acpi.h>
> +#include <dm/root.h>
> +
> +int acpi_return_name(char *out_name, const char *name)

A few nits:

* IMHO acpi_copy_name() would be a more fitting name. The function does not
  return a name, it copies it.
* Could we use strncpy + explicit null-termination instead of strcpy?

> +{
> +	strcpy(out_name, name);
> +
> +	return 0;
> +}
> +
> +int acpi_get_name(const struct udevice *dev, char *out_name)
> +{
> +	struct acpi_ops *aops;
> +
> +	aops = device_get_acpi_ops(dev);
> +	if (aops && aops->get_name)
> +		return aops->get_name(dev, out_name);
> +
> +	return -ENOSYS;
> +}
> diff --git a/include/dm/acpi.h b/include/dm/acpi.h
> new file mode 100644
> index 0000000000..120576adc0
> --- /dev/null
> +++ b/include/dm/acpi.h
> @@ -0,0 +1,73 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Core ACPI (Advanced Configuration and Power Interface) support
> + *
> + * Copyright 2019 Google LLC
> + * Written by Simon Glass <sjg@chromium.org>
> + */
> +
> +#ifndef __DM_ACPI_H__
> +#define __DM_ACPI_H__
> +
> +/* Allow operations to be optional for ACPI */
> +#if CONFIG_IS_ENABLED(ACPIGEN)
> +#define acpi_ops_ptr(_ptr)	.acpi_ops	= _ptr,
> +#else
> +#define acpi_ops_ptr(_ptr)
> +#endif
> +
> +/* Length of an ACPI name string, excluding nul terminator */
> +#define ACPI_NAME_LEN	4
> +
> +/* Length of an ACPI name string including nul terminator */
> +#define ACPI_NAME_MAX	5
> +
> +/**
> + * struct acpi_ops - ACPI operations supported by driver model
> + */
> +struct acpi_ops {
> +	/**
> +	 * get_name() - Obtain the ACPI name of a device
> +	 *
> +	 * @dev: Device to check
> +	 * @out_name: Place to put the name, must hold at least ACPI_NAME_MAX
> +	 *	bytes
> +	 * @return 0 if OK, -ENOENT if no name is available, other -ve value on
> +	 *	other error
> +	 */
> +	int (*get_name)(const struct udevice *dev, char *out_name);
> +};
> +
> +#define device_get_acpi_ops(dev)	((dev)->driver->acpi_ops)
> +
> +/**
> + * acpi_get_name() - Obtain the ACPI name of a device
> + *
> + * @dev: Device to check
> + * @out_name: Place to put the name, must hold at least ACPI_NAME_MAX
> + *	bytes
> + * @return 0 if OK, -ENOENT if no name is available, other -ve value on
> + *	other error
> + */
> +int acpi_get_name(const struct udevice *dev, char *out_name);
> +
> +/**
> + * acpi_return_name() - Copy an ACPI name to an output buffer
> + *
> + * This convenience function can be used to return a literal string as a name
> + * in functions that implement the get_name() method.
> + *
> + * For example:
> + *
> + *	static int mydev_get_name(const struct udevice *dev, char *out_name)
> + *	{
> + *		return acpi_return_name(out_name, "WIBB");
> + *	}
> + *
> + * @out_name: Place to put the name
> + * @name: Name to copy
> + * @return 0 (always)
> + */
> +int acpi_return_name(char *out_name, const char *name);
> +
> +#endif
> diff --git a/include/dm/device.h b/include/dm/device.h
> index 3517fc1926..9e77a0cd7b 100644
> --- a/include/dm/device.h
> +++ b/include/dm/device.h
> @@ -245,6 +245,8 @@ struct udevice_id {
>   * pointers defined by the driver, to implement driver functions required by
>   * the uclass.
>   * @flags: driver flags - see DM_FLAGS_...
> + * @acpi_ops: Advanced Configuration and Power Interface (ACPI) operations,
> + * allowing the device to add things to the ACPI tables passed to Linux
>   */
>  struct driver {
>  	char *name;
> @@ -264,6 +266,9 @@ struct driver {
>  	int per_child_platdata_auto_alloc_size;
>  	const void *ops;	/* driver-specific operations */
>  	uint32_t flags;
> +#if CONFIG_IS_ENABLED(ACPIGEN)
> +	struct acpi_ops *acpi_ops;
> +#endif
>  };
>  
>  /* Declare a new U-Boot driver */
> diff --git a/include/log.h b/include/log.h
> index 62fb8afbd0..d706a1a464 100644
> --- a/include/log.h
> +++ b/include/log.h
> @@ -51,6 +51,8 @@ enum log_category_t {
>  	LOGC_SANDBOX,	/* Related to the sandbox board */
>  	LOGC_BLOBLIST,	/* Bloblist */
>  	LOGC_DEVRES,	/* Device resources (devres_... functions) */
> +	/* Intel Advanced Configuration and Power Interface (ACPI) */

I would drop the "Intel".

> +	LOGC_ACPI,
>  
>  	LOGC_COUNT,	/* Number of log categories */
>  	LOGC_END,	/* Sentinel value for a list of log categories */
> -- 
> 2.25.1.481.gfbce0eb801-goog
> 

regards, Wolfgang

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

* Antwort: [PATCH v2 13/39] acpi: Add a binding for ACPI settings in the device tree
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (43 preceding siblings ...)
  2020-03-09  9:07 ` Antwort: [PATCH v2 12/39] dm: core: Add basic ACPI support Wolfgang Wallner
@ 2020-03-10  9:15 ` Wolfgang Wallner
  2020-03-12  3:24   ` Simon Glass
  2020-03-12 12:44   ` Antwort: " Wolfgang Wallner
  2020-03-10  9:16 ` Antwort: [PATCH v2 15/39] x86: Move acpi_table header to main include/ directory Wolfgang Wallner
                   ` (16 subsequent siblings)
  61 siblings, 2 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-10  9:15 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> Devices need to report various identifiers in the ACPI tables. Rather than
> hard-coding these in drivers it is typically better to put them in the
> device tree.
> 
> Add a binding file to describe this.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2:
> - Fix definition of HID
> - Infer hid-over-i2c CID value
> - Add the hid-over-i2c binding document
> 
>  doc/device-tree-bindings/device.txt           | 36 +++++++++++++++
>  .../input/hid-over-i2c.txt                    | 44 +++++++++++++++++++
>  2 files changed, 80 insertions(+)
>  create mode 100644 doc/device-tree-bindings/device.txt
>  create mode 100644 doc/device-tree-bindings/input/hid-over-i2c.txt
> 
> diff --git a/doc/device-tree-bindings/device.txt b/doc/device-tree-bindings/device.txt
> new file mode 100644
> index 0000000000..31ec2fa31b
> --- /dev/null
> +++ b/doc/device-tree-bindings/device.txt
> @@ -0,0 +1,36 @@
> +Devices
> +=======
> +
> +Device bindings are described by their own individual binding files.
> +
> +U-Boot provides for some optional properties which are documented here. See
> +also hid-over-i2c.txt which describes HID devices.
> +
> + - acpi,has-power-resource : (boolean) true if this device has a power resource.
> +    This causes a PRIC (ACPI PowerResource) to be written containing the

What is the meaning of PRIC? I can't find a defition for this term.

> +    properties provided by this binding, to describe how to handle powering the
> +    device up and down using GPIOs
> + - acpi,compatible : compatible string to report

What does "compatible string" mean in this context? Does it refer to the 
"Compatible ID" (_CID) of ACPI? As stated in the previous mail thread [1],
I think we could infer many of the ACPI properties from existing device tree
properties. Especially I suspect that ACPI's _CID could have a 1:1 mapping
to the compatible property in device tree. E.g. a driver which states that
it is compatible with "hid-over-i2c" in its device tree description would
know (implement internally) that it is also compatible with ACPI's _CID
"PNP0C50", thus we would not have to add this information in the device tree.

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

> + - acpi,desc : Contains the string to use as the _DDN (DOS (Disk Operating
> +    System) Device Name)

Nit: I assume "desc" stands for "description". But strictly speaking it is
not a description, it is a device name. I would prefer something like
"acpi,devname" or even "acpi,ddn".

> + - acpi,hid : Contains the string to use as the HID (Hardware ID)
> +    identifier _HID
> + - hid-descr-addr : HID register offset (for Human Interface Devices)

This property is already described in the file hid-over-i2c.txt (with a similar
but slightly different text), thus I would not describe it here also.

> + - acpi,probed : Tells U-Boot to add 'linux,probed' to the ACPI tables so that
> +    Linux will not re-init the device

I can't find 'linux,probed' in the Linux kernel.
I only find it in patches specific for chromium-os[2], but the description
there does not match the description given here (there it is described as
being probed before insertion vs. here it is described as not being probed
any more).

[2] https://groups.google.com/a/chromium.org/forum/#!msg/chromium-os-reviews/4HTHl78IGHw/oz82uImnBgAJ

> + - acpi,uid : _UID value for device
> +
> +
> +Example
> +-------
> +
> +synaptics_touchpad: synaptics-touchpad at 2c {
> +	compatible = "hid-over-i2c";
> +	reg = <0x2c>;
> +	acpi,hid = "PNP0C50";
> +	acpi,desc = "Synaptics Touchpad";
> +	interrupts-extended = <&acpi_gpe GPIO_18_IRQ
> +			IRQ_TYPE_EDGE_FALLING>;
> +	acpi,probed;
> +	hid-descr-addr = <0x20>;
> +};
> diff --git a/doc/device-tree-bindings/input/hid-over-i2c.txt b/doc/device-tree-bindings/input/hid-over-i2c.txt
> new file mode 100644

Adding the file hid-over-i2c.txt is straight forward, while getting the ACPI
bindings correct is probably more tricky. Would it make sense to add this file
in an individual patch?

> index 0000000000..c76bafaf98
> --- /dev/null
> +++ b/doc/device-tree-bindings/input/hid-over-i2c.txt

This file is taken from the Linux kernel, should this be stated at the
beginning? (I often see "Taken from ..." in source code files, I'm not sure
how this is handled for documentation).

> @@ -0,0 +1,44 @@
> +* HID over I2C Device-Tree bindings
> +
> +HID over I2C provides support for various Human Interface Devices over the
> +I2C bus. These devices can be for example touchpads, keyboards, touch screens
> +or sensors.
> +
> +The specification has been written by Microsoft and is currently available here:
> +http://msdn.microsoft.com/en-us/library/windows/hardware/hh852380.aspx
> +
> +If this binding is used, the kernel module i2c-hid will handle the communication
> +with the device and the generic hid core layer will handle the protocol.

This sentence is specific to the Linux kernel, and does not really apply to
U-Boot. I would propose one of the following:

* Point out specifically that the Linux kernel is talked about
* Drop the sentence
* State at the beginning of the file that the file is taken unmodified from the
  Linux kernel

> +
> +Required properties:
> +- compatible: must be "hid-over-i2c"
> +- reg: i2c slave address
> +- hid-descr-addr: HID descriptor address
> +- interrupts: interrupt line
> +
> +Additional optional properties:
> +
> +Some devices may support additional optional properties to help with, e.g.,
> +power sequencing. The following properties can be supported by one or more
> +device-specific compatible properties, which should be used in addition to the
> +"hid-over-i2c" string.
> +
> +- compatible:
> +  * "wacom,w9013" (Wacom W9013 digitizer). Supports:
> +    - vdd-supply (3.3V)
> +    - vddl-supply (1.8V)
> +    - post-power-on-delay-ms
> +
> +- vdd-supply: phandle of the regulator that provides the supply voltage.
> +- post-power-on-delay-ms: time required by the device after enabling its regulators
> +  or powering it on, before it is ready for communication.
> +
> +Example:
> +
> +	i2c-hid-dev at 2c {
> +		compatible = "hid-over-i2c";
> +		reg = <0x2c>;
> +		hid-descr-addr = <0x0020>;
> +		interrupt-parent = <&gpx3>;
> +		interrupts = <3 2>;
> +	};
> -- 
> 2.25.1.481.gfbce0eb801-goog
> 

regards, Wolfgang

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

* Antwort: [PATCH v2 15/39] x86: Move acpi_table header to main include/ directory
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (44 preceding siblings ...)
  2020-03-10  9:15 ` Antwort: [PATCH v2 13/39] acpi: Add a binding for ACPI settings in the device tree Wolfgang Wallner
@ 2020-03-10  9:16 ` Wolfgang Wallner
  2020-03-10  9:17 ` Antwort: [PATCH v2 16/39] acpi: Add an __ACPI__ preprocessor symbol Wolfgang Wallner
                   ` (15 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-10  9:16 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> This file is potentially useful to other architectures saddled with ACPI
> so move it into a common location.

Nit: "move most of its contents to a common location"
(not the complete file is moved, some parts stay at the old location)

> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> ---
> 
> Changes in v2: None
> 
>  arch/x86/cpu/baytrail/acpi.c      |   2 +-
>  arch/x86/cpu/cpu.c                |   2 +-
>  arch/x86/cpu/quark/acpi.c         |   2 +-
>  arch/x86/cpu/tangier/acpi.c       |   2 +-
>  arch/x86/include/asm/acpi_table.h | 376 ----------------------------
>  arch/x86/lib/acpi.c               |   2 +-
>  arch/x86/lib/acpi_s3.c            |   2 +-
>  arch/x86/lib/acpi_table.c         |   2 +-
>  arch/x86/lib/tables.c             |   2 +-
>  arch/x86/lib/zimage.c             |   2 +-
>  include/acpi_table.h              | 394 ++++++++++++++++++++++++++++++
>  lib/efi_loader/efi_acpi.c         |   2 +-
>  12 files changed, 404 insertions(+), 386 deletions(-)

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

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

* Antwort: [PATCH v2 16/39] acpi: Add an __ACPI__ preprocessor symbol
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (45 preceding siblings ...)
  2020-03-10  9:16 ` Antwort: [PATCH v2 15/39] x86: Move acpi_table header to main include/ directory Wolfgang Wallner
@ 2020-03-10  9:17 ` Wolfgang Wallner
  2020-03-10  9:26 ` Antwort: [PATCH v2 17/39] acpi: Add a central location for table version numbers Wolfgang Wallner
                   ` (14 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-10  9:17 UTC (permalink / raw)
  To: u-boot

Hi Simon,

> -----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> The ASL compiler cannot handle C structures and the like so needs some
> sort of header guard around these.
> 
> We already have an __ASSEMBLY__ #define but it seems best to create a new
> one for ACPI since the rules may be different.
> 
> Add the check to a few files that ACPI always includes.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> ---
> 
> Changes in v2: None
> 
>  include/acpi_table.h | 4 ++++
>  include/dm/acpi.h    | 4 ++++
>  scripts/Makefile.lib | 4 ++--
>  3 files changed, 10 insertions(+), 2 deletions(-)

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

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

* Antwort: [PATCH v2 17/39] acpi: Add a central location for table version numbers
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (46 preceding siblings ...)
  2020-03-10  9:17 ` Antwort: [PATCH v2 16/39] acpi: Add an __ACPI__ preprocessor symbol Wolfgang Wallner
@ 2020-03-10  9:26 ` Wolfgang Wallner
  2020-03-12  3:22   ` Simon Glass
  2020-03-10 12:32 ` Antwort: [PATCH v2 18/39] acpi: Add support for DMAR Wolfgang Wallner
                   ` (13 subsequent siblings)
  61 siblings, 1 reply; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-10  9:26 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> Each ACPI table has its own version number. Add the version numbers in a
> single function so we can keep them consistent and easily see what
> versions are supported.
> 
> Start a new acpi_table file in a generic directory to house this function.
> We can move things over to this file from x86 as needed.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2:
> - Move the sandbox acpi_table.h header file to an earlier patch
> - Use #defines for MADT and MCFG version numbers
> 
>  include/acpi_table.h  | 61 +++++++++++++++++++++++++++++++++++++++++++
>  lib/Makefile          |  1 +
>  lib/acpi/Makefile     |  4 +++
>  lib/acpi/acpi_table.c | 60 ++++++++++++++++++++++++++++++++++++++++++
>  test/dm/acpi.c        | 14 ++++++++++
>  5 files changed, 140 insertions(+)
>  create mode 100644 lib/acpi/Makefile
>  create mode 100644 lib/acpi/acpi_table.c
> 
> diff --git a/include/acpi_table.h b/include/acpi_table.h
> index dd74895813..ccf6fa04db 100644
> --- a/include/acpi_table.h
> +++ b/include/acpi_table.h
> @@ -202,6 +202,26 @@ struct __packed acpi_fadt {
>  	struct acpi_gen_regaddr x_gpe1_blk;
>  };
>  
> +/* FADT TABLE Revision values */
> +#define ACPI_FADT_REV_ACPI_1_0		1
> +#define ACPI_FADT_REV_ACPI_2_0		3
> +#define ACPI_FADT_REV_ACPI_3_0		4
> +#define ACPI_FADT_REV_ACPI_4_0		4
> +#define ACPI_FADT_REV_ACPI_5_0		5
> +#define ACPI_FADT_REV_ACPI_6_0		6
> +
> +/* MADT TABLE Revision values */
> +#define ACPI_MADT_REV_ACPI_3_0		2
> +#define ACPI_MADT_REV_ACPI_4_0		3
> +#define ACPI_MADT_REV_ACPI_5_0		3
> +#define ACPI_MADT_REV_ACPI_6_0		5
> +
> +#define ACPI_MCFG_REV_ACPI_3_0		1
> +
> +/* IVRS Revision Field */
> +#define IVRS_FORMAT_FIXED	0x01	/* Type 10h & 11h only */
> +#define IVRS_FORMAT_MIXED	0x02	/* Type 10h, 11h, & 40h */
> +
>  /* FACS flags */
>  #define ACPI_FACS_S4BIOS_F		BIT(0)
>  #define ACPI_FACS_64BIT_WAKE_F		BIT(1)
> @@ -391,6 +411,47 @@ struct __packed acpi_spcr {
>  	u32 reserved2;
>  };
>  
> +/* Tables defined by ACPI and generated by U-Boot */
> +enum acpi_tables {
> +	ACPITAB_BERT,
> +	ACPITAB_DBG2,
> +	ACPITAB_DMAR,
> +	ACPITAB_DSDT,
> +	ACPITAB_FACS,
> +	ACPITAB_FADT,
> +	ACPITAB_HEST,
> +	ACPITAB_HPET,
> +	ACPITAB_IVRS,
> +	ACPITAB_MADT,
> +	ACPITAB_MCFG,
> +	ACPITAB_RSDP,
> +	ACPITAB_RSDT,
> +	ACPITAB_SLIT,
> +	ACPITAB_SRAT,
> +	ACPITAB_SSDT,
> +	ACPITAB_TCPA,
> +	ACPITAB_TPM2,
> +	ACPITAB_XSDT,
> +	ACPITAB_ECDT,
> +
> +	/* Additional proprietary tables */
> +	ACPITAB_VFCT,
> +	ACPITAB_NHLT,
> +	ACPITAB_SPMI,
> +
> +	ACPITAB_COUNT,
> +};
> +
> +/**
> + * acpi_get_table_revision() - Get the revision number generated for a table
> + *
> + * This keeps the version-number information in one place
> + *
> + * @table: ACPI table to check
> + * @return version number that U-Boot generates
> + */
> +int acpi_get_table_revision(enum acpi_tables table);
> +
>  #endif /* !__ACPI__*/
>  
>  #include <asm/acpi_table.h>
> diff --git a/lib/Makefile b/lib/Makefile
> index 15259d0473..9df834c2fd 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -5,6 +5,7 @@
>  
>  ifndef CONFIG_SPL_BUILD
>  
> +obj-$(CONFIG_$(SPL_TPL_)ACPIGEN) += acpi/

Is $(SPL_TPL_) needed here?
I don't see a CONFIG_SPL_ACPIGEN, and this section of the file is also covered
by "ifndef CONFIG_SPL_BUILD".

In any case, would it make sense to generate ACPI-related code for SPL and TPL?
As U-Boot does not use ACPI, but only provides it to the kernel, I would
assume we only need to handle ACPI tables in the last U-Boot stage before
booting a kernel.

>  obj-$(CONFIG_EFI) += efi/
>  obj-$(CONFIG_EFI_LOADER) += efi_driver/
>  obj-$(CONFIG_EFI_LOADER) += efi_loader/
> diff --git a/lib/acpi/Makefile b/lib/acpi/Makefile
> new file mode 100644
> index 0000000000..660491ef71
> --- /dev/null
> +++ b/lib/acpi/Makefile
> @@ -0,0 +1,4 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +#
> +
> +obj-y += acpi_table.o
> diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
> new file mode 100644
> index 0000000000..197f965c08
> --- /dev/null
> +++ b/lib/acpi/acpi_table.c
> @@ -0,0 +1,60 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Tests for ACPI table generation

The description here does not really fit, is this maybe a copy/paste mistake?

> + *
> + * Copyright 2019 Google LLC
> + */
> +
> +#include <common.h>
> +#include <acpi_table.h>
> +
> +int acpi_get_table_revision(enum acpi_tables table)
> +{
> +	switch (table) {
> +	case ACPITAB_FADT:
> +		return ACPI_FADT_REV_ACPI_3_0;
> +	case ACPITAB_MADT:
> +		return ACPI_MADT_REV_ACPI_3_0;
> +	case ACPITAB_MCFG:
> +		return ACPI_MCFG_REV_ACPI_3_0;
> +	case ACPITAB_TCPA:
> +		/* THis version and the rest are open-coded */

typo: This

> +		return 2;
> +	case ACPITAB_TPM2:
> +		return 4;
> +	case ACPITAB_SSDT: /* ACPI 3.0 upto 6.3: 2 */
> +		return 2;
> +	case ACPITAB_SRAT: /* ACPI 2.0: 1, ACPI 3.0: 2, ACPI 4.0 upto 6.3: 3 */

Nit: "up to" instead of "upto"?

> +		return 1; /* TODO Should probably be upgraded to 2 */
> +	case ACPITAB_DMAR:
> +		return 1;
> +	case ACPITAB_SLIT: /* ACPI 2.0 upto 6.3: 1 */
> +		return 1;
> +	case ACPITAB_SPMI: /* IMPI 2.0 */
> +		return 5;
> +	case ACPITAB_HPET: /* Currently 1. Table added in ACPI 2.0 */
> +		return 1;
> +	case ACPITAB_VFCT: /* ACPI 2.0/3.0/4.0: 1 */
> +		return 1;
> +	case ACPITAB_IVRS:
> +		return IVRS_FORMAT_FIXED;
> +	case ACPITAB_DBG2:
> +		return 0;
> +	case ACPITAB_FACS: /* ACPI 2.0/3.0: 1, ACPI 4.0 upto 6.3: 2 */

Nit: "up to" instead of "upto"?

> +		return 1;
> +	case ACPITAB_RSDT: /* ACPI 1.0 upto 6.3: 1 */
> +		return 1;
> +	case ACPITAB_XSDT: /* ACPI 2.0 upto 6.3: 1 */
> +		return 1;
> +	case ACPITAB_RSDP: /* ACPI 2.0 upto 6.3: 2 */
> +		return 2;
> +	case ACPITAB_HEST:
> +		return 1;
> +	case ACPITAB_NHLT:
> +		return 5;
> +	case ACPITAB_BERT:
> +		return 1;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> diff --git a/test/dm/acpi.c b/test/dm/acpi.c
> index e3519d4689..e65295b7ca 100644
> --- a/test/dm/acpi.c
> +++ b/test/dm/acpi.c
> @@ -7,6 +7,7 @@
>   */
>  
>  #include <common.h>
> +#include <acpi_table.h>
>  #include <dm.h>
>  #include <dm/acpi.h>
>  #include <dm/test.h>
> @@ -53,3 +54,16 @@ static int dm_test_acpi_get_name(struct unit_test_state *uts)
>  	return 0;
>  }
>  DM_TEST(dm_test_acpi_get_name, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> +
> +/* Test acpi_get_table_revision() */
> +static int dm_test_acpi_get_table_revision(struct unit_test_state *uts)
> +{
> +	ut_asserteq(1, acpi_get_table_revision(ACPITAB_MCFG));
> +	ut_asserteq(2, acpi_get_table_revision(ACPITAB_RSDP));
> +	ut_asserteq(4, acpi_get_table_revision(ACPITAB_TPM2));
> +	ut_asserteq(-EINVAL, acpi_get_table_revision(ACPITAB_COUNT));
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_acpi_get_table_revision,
> +	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> -- 
> 2.25.1.481.gfbce0eb801-goog

regards, Wolfgang

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

* Antwort: [PATCH v2 18/39] acpi: Add support for DMAR
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (47 preceding siblings ...)
  2020-03-10  9:26 ` Antwort: [PATCH v2 17/39] acpi: Add a central location for table version numbers Wolfgang Wallner
@ 2020-03-10 12:32 ` Wolfgang Wallner
  2020-03-10 12:33 ` Antwort: [PATCH v2 19/39] acpi: Move acpi_fill_header() to generic code Wolfgang Wallner
                   ` (12 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-10 12:32 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> The DMA Remapping Reporting (DMAR) table contains information about DMA
> remapping.
> 
> Add a version simple version of this table with only the minimum fields
> filled out. i.e. no entries.
> 
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2:
> - Drop two unnecessary __packed
> - Move __packed to after struct
> 
>  include/acpi_table.h  | 57 +++++++++++++++++++++++++++++++++++++++++++
>  lib/acpi/acpi_table.c | 26 ++++++++++++++++++++
>  test/dm/acpi.c        | 14 +++++++++++
>  3 files changed, 97 insertions(+)
> 
> diff --git a/include/acpi_table.h b/include/acpi_table.h
> index ccf6fa04db..db84b79be5 100644
> --- a/include/acpi_table.h
> +++ b/include/acpi_table.h
> @@ -21,6 +21,9 @@
>  #define ACPI_RSDP_REV_ACPI_1_0	0
>  #define ACPI_RSDP_REV_ACPI_2_0	2
>  
> +/* TODO(sjg at chromium.org): Figure out how to get compiler revision */
> +#define ASL_REVISION	0
> +
>  #if !defined(__ACPI__)
>  
>  /*
> @@ -360,6 +363,51 @@ struct acpi_csrt_shared_info {
>  	u32 max_block_size;
>  };
>  
> +enum dmar_type {
> +	DMAR_DRHD = 0,
> +	DMAR_RMRR = 1,
> +	DMAR_ATSR = 2,
> +	DMAR_RHSA = 3,
> +	DMAR_ANDD = 4
> +};
> +
> +enum {
> +	DRHD_INCLUDE_PCI_ALL = 1

Could you use "1 << 0" or "BIT(0)" ?
Similar as the flag definitions below.

> +};
> +
> +enum dmar_flags {
> +	DMAR_INTR_REMAP			= 1 << 0,
> +	DMAR_X2APIC_OPT_OUT		= 1 << 1,
> +	DMA_CTRL_PLATFORM_OPT_IN_FLAG	= 1 << 2,

The first two entries are prefixed with DMAR_, the last one is not.
Is this on purpose?

Could you use BIT(x) here?

> +};
> +
> +struct dmar_entry {
> +	u16 type;
> +	u16 length;
> +	u8 flags;
> +	u8 reserved;
> +	u16 segment;
> +	u64 bar;
> +};
> +
> +struct dmar_rmrr_entry {
> +	u16 type;
> +	u16 length;
> +	u16 reserved;
> +	u16 segment;
> +	u64 bar;
> +	u64 limit;
> +};
> +
> +/* DMAR (DMA Remapping Reporting Structure) */
> +struct __packed acpi_dmar {
> +	struct acpi_table_header header;
> +	u8 host_address_width;
> +	u8 flags;
> +	u8 reserved[10];
> +	struct dmar_entry structure[0];
> +};
> +
>  /* DBG2 definitions are partially used for SPCR interface_type */
>  
>  /* Types for port_type field */
> @@ -452,6 +500,15 @@ enum acpi_tables {
>   */
>  int acpi_get_table_revision(enum acpi_tables table);
>  
> +/**
> + * acpi_create_dmar() - Create a DMA Remapping Reporting (DMAR) table
> + *
> + * @dmar: Place to put the table
> + * @flags: DMAR flags to use
> + * @return 0 if OK, -ve on error
> + */
> +int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags);
> +
>  #endif /* !__ACPI__*/
>  
>  #include <asm/acpi_table.h>
> diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
> index 197f965c08..ed312ac663 100644
> --- a/lib/acpi/acpi_table.c
> +++ b/lib/acpi/acpi_table.c
> @@ -6,7 +6,33 @@
>   */
>  
>  #include <common.h>
> +#include <dm.h>
>  #include <acpi_table.h>
> +#include <cpu.h>
> +
> +int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags)
> +{
> +	struct acpi_table_header *header = &dmar->header;
> +	struct cpu_info info;
> +	struct udevice *cpu;
> +	int ret;
> +
> +	ret = uclass_first_device(UCLASS_CPU, &cpu);
> +	if (ret)
> +		return log_msg_ret("cpu", ret);
> +	ret = cpu_get_info(cpu, &info);

Here the return value of cpu_get_info() is ignored.

> +	memset((void *)dmar, 0, sizeof(struct acpi_dmar));
> +
> +	/* Fill out header fields. */
> +	acpi_fill_header(&dmar->header, "DMAR");
> +	header->length = sizeof(struct acpi_dmar);
> +	header->revision = acpi_get_table_revision(ACPITAB_DMAR);
> +
> +	dmar->host_address_width = info.address_width - 1;
> +	dmar->flags = flags;
> +
> +	return 0;
> +}
>  
>  int acpi_get_table_revision(enum acpi_tables table)
>  {
> diff --git a/test/dm/acpi.c b/test/dm/acpi.c
> index e65295b7ca..2737896643 100644
> --- a/test/dm/acpi.c
> +++ b/test/dm/acpi.c
> @@ -67,3 +67,17 @@ static int dm_test_acpi_get_table_revision(struct unit_test_state *uts)
>  }
>  DM_TEST(dm_test_acpi_get_table_revision,
>  	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> +
> +/* Test acpi_create_dmar() */
> +static int dm_test_acpi_create_dmar(struct unit_test_state *uts)
> +{
> +	struct acpi_dmar dmar;
> +
> +	ut_assertok(acpi_create_dmar(&dmar, DMAR_INTR_REMAP));
> +	ut_asserteq(DMAR_INTR_REMAP, dmar.flags);
> +	ut_asserteq(DMAR_INTR_REMAP, dmar.flags);

This test case is inserted twice.

> +	ut_asserteq(32 - 1, dmar.host_address_width);
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_acpi_create_dmar, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> -- 
> 2.25.1.481.gfbce0eb801-goog

regards, Wolfgang

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

* Antwort: [PATCH v2 19/39] acpi: Move acpi_fill_header() to generic code
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (48 preceding siblings ...)
  2020-03-10 12:32 ` Antwort: [PATCH v2 18/39] acpi: Add support for DMAR Wolfgang Wallner
@ 2020-03-10 12:33 ` Wolfgang Wallner
  2020-03-10 12:53 ` Antwort: [PATCH v2 14/39] acpi: Add a simple sandbox test Wolfgang Wallner
                   ` (11 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-10 12:33 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> This function needs to be used by sandbox for tests. Move it into the
> generic directory.

Nit: Move it into the generic directory and add a test for it.

> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> ---
> 
> Changes in v2: None
> 
>  arch/x86/lib/acpi_table.c |  9 ---------
>  include/acpi_table.h      | 10 ++++++++++
>  lib/acpi/acpi_table.c     | 10 ++++++++++
>  test/dm/acpi.c            | 28 ++++++++++++++++++++++++++++
>  4 files changed, 48 insertions(+), 9 deletions(-)
> 

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

regards, Wolfgang

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

* Antwort: [PATCH v2 14/39] acpi: Add a simple sandbox test
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (49 preceding siblings ...)
  2020-03-10 12:33 ` Antwort: [PATCH v2 19/39] acpi: Move acpi_fill_header() to generic code Wolfgang Wallner
@ 2020-03-10 12:53 ` Wolfgang Wallner
  2020-03-11  9:04 ` Antwort: [PATCH v2 19/39] acpi: Move acpi_fill_header() to generic code Wolfgang Wallner
                   ` (10 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-10 12:53 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> Add a sandbox test for the basic ACPI functionality we have so far.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> ---
> 
> Changes in v2:
> - Add in the acpi_table.h header file to this patch
> 
>  arch/sandbox/dts/test.dts             |  4 ++
>  arch/sandbox/include/asm/acpi_table.h |  9 +++++
>  include/dm/uclass-id.h                |  1 +
>  test/dm/Makefile                      |  1 +
>  test/dm/acpi.c                        | 55 +++++++++++++++++++++++++++
>  5 files changed, 70 insertions(+)

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

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

* [PATCH v2 09/39] x86: apl: Move p2sb ofdata reading to the correct method
  2020-03-09  3:44 ` [PATCH v2 09/39] x86: apl: Move p2sb ofdata reading to the correct method Simon Glass
@ 2020-03-10 14:39   ` Andy Shevchenko
  2020-03-11 12:17     ` Simon Glass
  0 siblings, 1 reply; 86+ messages in thread
From: Andy Shevchenko @ 2020-03-10 14:39 UTC (permalink / raw)
  To: u-boot

On Sun, Mar 08, 2020 at 09:44:33PM -0600, Simon Glass wrote:
> With P2SB the initial BAR (base-address register) is set up by TPL and
> this is used unchanged right through U-Boot.
> 
> At present the reading of this address is split between the ofdata() and
> probe() methods. There are a few problems that are unique to the p2sb.
> One is that its children need to call pcr_read32(), etc. which needs to
> have the p2sb address correct. Also some of its children are pinctrl
> devices and pinctrl is used when any device is probed. So p2sb really
> needs to get its base address set up in ofdata_to_platdata(), before it is
> probed.
> 
> Another point is that reading the p2sb BAR will not work if the p2sb is
> hidden. The FSP-S seems to hide it, presumably to avoid confusing PCI
> enumeration.
> 
> Reading ofdata in ofdata_to_platdata() is the correct place anyway, so
> this is easy to fix.
> 
> Move the code into one place and use the early-regs property in all cases
> for simplicity and to avoid needing to probe any PCI devices just to read
> the BAR.

>  		if (plat->bdf < 0)
>  			return log_msg_ret("Cannot get p2sb PCI address",
> -					   plat->bdf);
> +						plat->bdf);

Not sure I understand this hunk WRT the patch itself.

> +	if (spl_phase() == PHASE_TPL)
>  		return p2sb_early_init(dev);

> +	else if (spl_phase() == PHASE_SPL)

Redundant 'else', but I think we already discussed that and you prefer this
way. However, I think this is waste of compilation time. In any case, matter
of taste.

> +		return p2sb_spl_init(dev);

-- 
With Best Regards,
Andy Shevchenko

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

* [PATCH v2 12/39] dm: core: Add basic ACPI support
  2020-03-09  3:44 ` [PATCH v2 12/39] dm: core: Add basic ACPI support Simon Glass
@ 2020-03-10 14:46   ` Andy Shevchenko
  2020-03-11 12:17     ` Simon Glass
  0 siblings, 1 reply; 86+ messages in thread
From: Andy Shevchenko @ 2020-03-10 14:46 UTC (permalink / raw)
  To: u-boot

On Sun, Mar 08, 2020 at 09:44:36PM -0600, Simon Glass wrote:
> ACPI (Advanced Configuration and Power Interface) is an Intel standard

Not Intel for a long time. Or more precisely, not *only* Intel.

Also this should be corrected (I guess dropping Intel would work) everywhere in
this series.

> for specifying information about a platform.

> It is a little like device
> tree but considerably more complicated and with more backslashes.

For what purpose this passage?
Isn't the same reason why ARM64 choose ACPI to be supported for servers?

> A
> primary difference is that it supports an interpreted bytecode language.
> 
> Driver model does not use ACPI for U-Boot's configuration, but it is
> convenient to have it support generation of ACPI tables for passing to
> Linux, etc.
> 
> As a starting point, add an optional set of ACPI operations to each
> device. Initially only a single operation is available, to obtain the
> ACPI name for the device. More operations are added later.
> 
> Enable ACPI for sandbox to ensure build coverage and so that we can add
> tests.

...

> +/* Length of an ACPI name string, excluding nul terminator */
> +#define ACPI_NAME_LEN	4
> +
> +/* Length of an ACPI name string including nul terminator */
> +#define ACPI_NAME_MAX	5

Do we really need two definitions?

...

> +	/* Intel Advanced Configuration and Power Interface (ACPI) */

Same as above for commit message.

-- 
With Best Regards,
Andy Shevchenko

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

* [PATCH v2 13/39] acpi: Add a binding for ACPI settings in the device tree
  2020-03-09  3:44 ` [PATCH v2 13/39] acpi: Add a binding for ACPI settings in the device tree Simon Glass
@ 2020-03-10 14:50   ` Andy Shevchenko
  2020-03-12  3:22     ` Simon Glass
  0 siblings, 1 reply; 86+ messages in thread
From: Andy Shevchenko @ 2020-03-10 14:50 UTC (permalink / raw)
  To: u-boot

On Sun, Mar 08, 2020 at 09:44:37PM -0600, Simon Glass wrote:
> Devices need to report various identifiers in the ACPI tables. Rather than
> hard-coding these in drivers it is typically better to put them in the
> device tree.
> 
> Add a binding file to describe this.

...

> +Device bindings are described by their own individual binding files.
> +
> +U-Boot provides for some optional properties which are documented here. See
> +also hid-over-i2c.txt which describes HID devices.
> +
> + - acpi,has-power-resource : (boolean) true if this device has a power resource.
> +    This causes a PRIC (ACPI PowerResource) to be written containing the

What is PRIC?

> +    properties provided by this binding, to describe how to handle powering the
> +    device up and down using GPIOs

> + - acpi,compatible : compatible string to report

Hmm... I didn't get this. Is it ACPI _CID?

> + - acpi,desc : Contains the string to use as the _DDN (DOS (Disk Operating
> +    System) Device Name)

> + - acpi,hid : Contains the string to use as the HID (Hardware ID)
> +    identifier _HID

HID can be dropped to avoid confusion with below.

> + - hid-descr-addr : HID register offset (for Human Interface Devices)

> + - acpi,probed : Tells U-Boot to add 'linux,probed' to the ACPI tables so that
> +    Linux will not re-init the device

Why? How do we know that Linux will work correctly? Again, we must not depend
on the OS behaviour.

> + - acpi,uid : _UID value for device
> +
> +
> +Example
> +-------
> +
> +synaptics_touchpad: synaptics-touchpad at 2c {
> +	compatible = "hid-over-i2c";
> +	reg = <0x2c>;
> +	acpi,hid = "PNP0C50";
> +	acpi,desc = "Synaptics Touchpad";
> +	interrupts-extended = <&acpi_gpe GPIO_18_IRQ
> +			IRQ_TYPE_EDGE_FALLING>;
> +	acpi,probed;
> +	hid-descr-addr = <0x20>;
> +};

-- 
With Best Regards,
Andy Shevchenko

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

* [PATCH v2 08/39] x86: Correct wording of coreboot source code
  2020-03-09  7:44   ` Andy Shevchenko
@ 2020-03-10 23:22     ` Simon Glass
  0 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-10 23:22 UTC (permalink / raw)
  To: u-boot

Hi Andy,

On Mon, 9 Mar 2020 at 01:44, Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
>
> On Mon, Mar 9, 2020 at 5:47 AM Simon Glass <sjg@chromium.org> wrote:
> >
> > Some files are taken or modified from coreboot, but the files are
> > no-longer part of the coreboot project. Fix the wording in a few places.
> >
> > Signed-off-by: Simon Glass <sjg@chromium.org>
> > Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> > ---
> >
> > Changes in v2: None
> >
> >  arch/x86/cpu/coreboot/timestamp.c              | 4 ++--
> >  arch/x86/include/asm/arch-coreboot/timestamp.h | 4 ++--
> >  arch/x86/include/asm/intel_pinctrl_defs.h      | 2 --
> >  3 files changed, 4 insertions(+), 6 deletions(-)
> >
> > diff --git a/arch/x86/cpu/coreboot/timestamp.c b/arch/x86/cpu/coreboot/timestamp.c
> > index e698200d70..e8ccaf2212 100644
> > --- a/arch/x86/cpu/coreboot/timestamp.c
> > +++ b/arch/x86/cpu/coreboot/timestamp.c
> > @@ -1,8 +1,8 @@
> >  // SPDX-License-Identifier: GPL-2.0+
> >  /*
> > - * This file is part of the coreboot project.
> > - *
> >   * Copyright (C) 2011 The ChromiumOS Authors.  All rights reserved.
> > + *
> > + * Modified from the coreboot version
>
> Perhaps leave the period at the end of the line to follow English punctuation?

This is actually something I try to avoid. It is not a sentence and
turning it into one by adding more words doesn't improve its value
IMO.

Regards,
Simon

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

* Antwort: [PATCH v2 19/39] acpi: Move acpi_fill_header() to generic code
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (50 preceding siblings ...)
  2020-03-10 12:53 ` Antwort: [PATCH v2 14/39] acpi: Add a simple sandbox test Wolfgang Wallner
@ 2020-03-11  9:04 ` Wolfgang Wallner
  2020-03-11 11:36 ` Antwort: [PATCH v2 20/39] acpi: Add a method to write tables for a device Wolfgang Wallner
                   ` (9 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-11  9:04 UTC (permalink / raw)
  To: u-boot

Hi Simon,

looking at this patch some more I have another question, see below.

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> This function needs to be used by sandbox for tests. Move it into the
> generic directory.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> ---

[snip] 

> @@ -81,3 +82,30 @@ static int dm_test_acpi_create_dmar(struct unit_test_state *uts)
>  	return 0;
>  }
>  DM_TEST(dm_test_acpi_create_dmar, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> +
> +/* Test acpi_fill_header() */
> +static int dm_test_acpi_fill_header(struct unit_test_state *uts)
> +{
> +	struct acpi_table_header hdr;
> +
> +	/* Make sure these 5 fields are not changed */
> +	hdr.length = 0x11;
> +	hdr.revision = 0x22;
> +	hdr.checksum = 0x33;
> +	hdr.aslc_revision = 0x44;
> +	acpi_fill_header(&hdr, "ABCD");
> +
> +	ut_assertok(memcmp("ABCD", hdr.signature, sizeof(hdr.signature)));

Could ut_asserteq_mem() be used here?
The output would be a little more verbose.

With ut_assertok(memcmp()):
 test/dm/acpi.c:104, dm_test_acpi_fill_header(): 0 == memcmp("ABCD", hdr.signature, sizeof(hdr.signature)): Expected 0x0 (0), got 0x13 (19)

With ut_assertmem_eq():
 test/dm/acpi.c:103, dm_test_acpi_fill_header(): "ABCD" = hdr.signature: Expected "41424344", got "41424331"

> +	ut_asserteq(0x11, hdr.length);
> +	ut_asserteq(0x22, hdr.revision);
> +	ut_asserteq(0x33, hdr.checksum);
> +	ut_assertok(memcmp(OEM_ID, hdr.oem_id, sizeof(hdr.oem_id)));
> +	ut_assertok(memcmp(OEM_TABLE_ID, hdr.oem_table_id,
> +			   sizeof(hdr.oem_table_id)));
> +	ut_asserteq(U_BOOT_BUILD_DATE, hdr.oem_revision);
> +	ut_assertok(memcmp(ASLC_ID, hdr.aslc_id, sizeof(hdr.aslc_id)));
> +	ut_asserteq(0x44, hdr.aslc_revision);
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_acpi_fill_header, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> -- 
> 2.25.1.481.gfbce0eb801-goog

regards, Wolfgang

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

* Antwort: [PATCH v2 20/39] acpi: Add a method to write tables for a device
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (51 preceding siblings ...)
  2020-03-11  9:04 ` Antwort: [PATCH v2 19/39] acpi: Move acpi_fill_header() to generic code Wolfgang Wallner
@ 2020-03-11 11:36 ` Wolfgang Wallner
  2020-03-11 11:37 ` Antwort: [PATCH v2 22/39] x86: Allow devices to write ACPI tables Wolfgang Wallner
                   ` (8 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-11 11:36 UTC (permalink / raw)
  To: u-boot

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> A device may want to write out ACPI tables to describe itself to Linux.
> Add a method to permit this.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2:
> - Drop definition of ACPI_TABLE_CREATOR
> - Make _acpi_write_dev_tables() static and switch argument order
> - Generalise the ACPI function recursion with acpi_recurse_method()
> 
>  arch/sandbox/dts/test.dts |  4 +++
>  drivers/core/acpi.c       | 61 +++++++++++++++++++++++++++++++++++++++
>  include/dm/acpi.h         | 30 +++++++++++++++++++
>  test/dm/acpi.c            | 43 +++++++++++++++++++++++++++
>  4 files changed, 138 insertions(+)

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

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

* Antwort: [PATCH v2 22/39] x86: Allow devices to write ACPI tables
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (52 preceding siblings ...)
  2020-03-11 11:36 ` Antwort: [PATCH v2 20/39] acpi: Add a method to write tables for a device Wolfgang Wallner
@ 2020-03-11 11:37 ` Wolfgang Wallner
  2020-03-11 12:58 ` Antwort: [PATCH v2 21/39] acpi: Convert part of acpi_table to use acpi_ctx Wolfgang Wallner
                   ` (7 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-11 11:37 UTC (permalink / raw)
  To: u-boot

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> Call the new core function to permit devices to write their own ACPI
> tables. These tables will appear after all other tables.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> 
>  arch/x86/lib/acpi_table.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
> index 8e13d6a3e6..964f10a7cb 100644
> --- a/arch/x86/lib/acpi_table.c
> +++ b/arch/x86/lib/acpi_table.c
> @@ -580,6 +580,8 @@ ulong write_acpi_tables(ulong start_addr)
>  	acpi_inc_align(ctx, spcr->header.length);
>  	acpi_add_table(rsdp, spcr);
>  
> +	acpi_write_dev_tables(ctx);
> +
>  	addr = map_to_sysmem(ctx->current);
>  	debug("current = %lx\n", addr);
>  
> -- 
> 2.25.1.481.gfbce0eb801-goog

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

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

* [PATCH v2 12/39] dm: core: Add basic ACPI support
  2020-03-10 14:46   ` Andy Shevchenko
@ 2020-03-11 12:17     ` Simon Glass
  0 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-11 12:17 UTC (permalink / raw)
  To: u-boot

Hi Andy,

On Tue, 10 Mar 2020 at 08:46, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Sun, Mar 08, 2020 at 09:44:36PM -0600, Simon Glass wrote:
> > ACPI (Advanced Configuration and Power Interface) is an Intel standard
>
> Not Intel for a long time. Or more precisely, not *only* Intel.
>
> Also this should be corrected (I guess dropping Intel would work) everywhere in
> this series.

OK will do.

>
> > for specifying information about a platform.
>
> > It is a little like device
> > tree but considerably more complicated and with more backslashes.
>
> For what purpose this passage?
> Isn't the same reason why ARM64 choose ACPI to be supported for servers?
>
> > A
> > primary difference is that it supports an interpreted bytecode language.
> >
> > Driver model does not use ACPI for U-Boot's configuration, but it is
> > convenient to have it support generation of ACPI tables for passing to
> > Linux, etc.
> >
> > As a starting point, add an optional set of ACPI operations to each
> > device. Initially only a single operation is available, to obtain the
> > ACPI name for the device. More operations are added later.
> >
> > Enable ACPI for sandbox to ensure build coverage and so that we can add
> > tests.
>
> ...
>
> > +/* Length of an ACPI name string, excluding nul terminator */
> > +#define ACPI_NAME_LEN        4
> > +
> > +/* Length of an ACPI name string including nul terminator */
> > +#define ACPI_NAME_MAX        5
>
> Do we really need two definitions?

It is annoying to have to use

char name[ACPI_NAME_LEN + 1]

everywhere.

On the other hand, some structs don't need a terminator, so we need
ACPI_NAME_LEN.

I'll change it so one is computed from the other.

>
> ...
>
> > +     /* Intel Advanced Configuration and Power Interface (ACPI) */
>
> Same as above for commit message.
>

Regards,
Simon

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

* [PATCH v2 09/39] x86: apl: Move p2sb ofdata reading to the correct method
  2020-03-10 14:39   ` Andy Shevchenko
@ 2020-03-11 12:17     ` Simon Glass
  2020-03-11 13:06       ` Andy Shevchenko
  0 siblings, 1 reply; 86+ messages in thread
From: Simon Glass @ 2020-03-11 12:17 UTC (permalink / raw)
  To: u-boot

Hi Andy,

On Tue, 10 Mar 2020 at 08:39, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Sun, Mar 08, 2020 at 09:44:33PM -0600, Simon Glass wrote:
> > With P2SB the initial BAR (base-address register) is set up by TPL and
> > this is used unchanged right through U-Boot.
> >
> > At present the reading of this address is split between the ofdata() and
> > probe() methods. There are a few problems that are unique to the p2sb.
> > One is that its children need to call pcr_read32(), etc. which needs to
> > have the p2sb address correct. Also some of its children are pinctrl
> > devices and pinctrl is used when any device is probed. So p2sb really
> > needs to get its base address set up in ofdata_to_platdata(), before it is
> > probed.
> >
> > Another point is that reading the p2sb BAR will not work if the p2sb is
> > hidden. The FSP-S seems to hide it, presumably to avoid confusing PCI
> > enumeration.
> >
> > Reading ofdata in ofdata_to_platdata() is the correct place anyway, so
> > this is easy to fix.
> >
> > Move the code into one place and use the early-regs property in all cases
> > for simplicity and to avoid needing to probe any PCI devices just to read
> > the BAR.
>
> >               if (plat->bdf < 0)
> >                       return log_msg_ret("Cannot get p2sb PCI address",
> > -                                        plat->bdf);
> > +                                             plat->bdf);
>
> Not sure I understand this hunk WRT the patch itself.

This is to fix a checkpatch error - it reports problems in nearby lines.

>
> > +     if (spl_phase() == PHASE_TPL)
> >               return p2sb_early_init(dev);
>
> > +     else if (spl_phase() == PHASE_SPL)
>
> Redundant 'else', but I think we already discussed that and you prefer this
> way. However, I think this is waste of compilation time. In any case, matter
> of taste.

Yes. I feel that it shows that there are two options.

Just for fun I wrote a program to try to benchmark the difference and
it does not seem to be detectable.

>
> > +             return p2sb_spl_init(dev);

Regards,
Simon

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

* Antwort: [PATCH v2 21/39] acpi: Convert part of acpi_table to use acpi_ctx
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (53 preceding siblings ...)
  2020-03-11 11:37 ` Antwort: [PATCH v2 22/39] x86: Allow devices to write ACPI tables Wolfgang Wallner
@ 2020-03-11 12:58 ` Wolfgang Wallner
  2020-03-12  3:23   ` Simon Glass
  2020-03-12 13:03   ` Antwort: " Wolfgang Wallner
  2020-03-11 13:43 ` Antwort: [PATCH v2 24/39] acpi: Move acpi_add_table() to generic code Wolfgang Wallner
                   ` (6 subsequent siblings)
  61 siblings, 2 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-11 12:58 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> The current code uses an address but a pointer would result in fewer
> casts. Also it repeats the alignment code in a lot of places so this would
> be better done in a helper function.
> 
> Update write_acpi_tables() to make use of the new acpi_ctx structure,
> adding a few helpers to clean things up.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> 
>  arch/x86/lib/acpi_table.c | 88 +++++++++++++++++++--------------------
>  include/acpi_table.h      | 36 ++++++++++++++++
>  lib/acpi/acpi_table.c     | 22 ++++++++++
>  test/dm/acpi.c            | 28 +++++++++++++
>  4 files changed, 129 insertions(+), 45 deletions(-)
> 
> diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
> index 487fef87f2..8e13d6a3e6 100644
> --- a/arch/x86/lib/acpi_table.c
> +++ b/arch/x86/lib/acpi_table.c
> @@ -10,6 +10,7 @@
>  #include <cpu.h>
>  #include <dm.h>
>  #include <dm/uclass-internal.h>
> +#include <mapmem.h>
>  #include <serial.h>
>  #include <version.h>
>  #include <asm/acpi/global_nvs.h>
> @@ -19,6 +20,7 @@
>  #include <asm/mpspec.h>
>  #include <asm/tables.h>
>  #include <asm/arch/global_nvs.h>
> +#include <dm/acpi.h>
>  
>  /*
>   * IASL compiles the dsdt entries and writes the hex values
> @@ -468,9 +470,9 @@ static void acpi_create_spcr(struct acpi_spcr *spcr)
>  /*
>   * QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c
>   */
> -ulong write_acpi_tables(ulong start)
> +ulong write_acpi_tables(ulong start_addr)
>  {
> -	u32 current;
> +	struct acpi_ctx sctx, *ctx = &sctx;
>  	struct acpi_rsdp *rsdp;
>  	struct acpi_rsdt *rsdt;
>  	struct acpi_xsdt *xsdt;
> @@ -481,60 +483,61 @@ ulong write_acpi_tables(ulong start)
>  	struct acpi_madt *madt;
>  	struct acpi_csrt *csrt;
>  	struct acpi_spcr *spcr;
> +	void *start;
> +	ulong addr;
>  	int i;
>  
> -	current = start;
> +	start = map_sysmem(start_addr, 0);
> +	ctx->current = start;
>  
>  	/* Align ACPI tables to 16 byte */
> -	current = ALIGN(current, 16);
> +	acpi_align(ctx);
>  
> -	debug("ACPI: Writing ACPI tables at %lx\n", start);
> +	debug("ACPI: Writing ACPI tables at %lx\n", start_addr);
>  
>  	/* We need at least an RSDP and an RSDT Table */
> -	rsdp = (struct acpi_rsdp *)current;
> -	current += sizeof(struct acpi_rsdp);
> -	current = ALIGN(current, 16);
> -	rsdt = (struct acpi_rsdt *)current;
> -	current += sizeof(struct acpi_rsdt);
> -	current = ALIGN(current, 16);
> -	xsdt = (struct acpi_xsdt *)current;
> -	current += sizeof(struct acpi_xsdt);
> +	rsdp = ctx->current;
> +	acpi_inc_align(ctx, sizeof(struct acpi_rsdp));
> +	rsdt = ctx->current;
> +	acpi_inc_align(ctx, sizeof(struct acpi_rsdt));
> +	xsdt = ctx->current;
> +	acpi_inc_align(ctx, sizeof(struct acpi_xsdt));
>  	/*
>  	 * Per ACPI spec, the FACS table address must be aligned to a 64 byte
>  	 * boundary (Windows checks this, but Linux does not).
>  	 */
> -	current = ALIGN(current, 64);
> +	acpi_align_large(ctx);
>  
>  	/* clear all table memory */
> -	memset((void *)start, 0, current - start);
> +	memset((void *)start, 0, ctx->current - start);
>  
>  	acpi_write_rsdp(rsdp, rsdt, xsdt);
>  	acpi_write_rsdt(rsdt);
>  	acpi_write_xsdt(xsdt);
>  
>  	debug("ACPI:    * FACS\n");
> -	facs = (struct acpi_facs *)current;
> -	current += sizeof(struct acpi_facs);
> -	current = ALIGN(current, 16);
> +	facs = ctx->current;
> +	acpi_inc_align(ctx, sizeof(struct acpi_facs));
>  
>  	acpi_create_facs(facs);
>  
>  	debug("ACPI:    * DSDT\n");
> -	dsdt = (struct acpi_table_header *)current;
> +	dsdt = ctx->current;
>  	memcpy(dsdt, &AmlCode, sizeof(struct acpi_table_header));
> -	current += sizeof(struct acpi_table_header);
> -	memcpy((char *)current,
> +	acpi_inc(ctx, sizeof(struct acpi_table_header));
> +	memcpy(ctx->current,
>  	       (char *)&AmlCode + sizeof(struct acpi_table_header),
>  	       dsdt->length - sizeof(struct acpi_table_header));
> -	current += dsdt->length - sizeof(struct acpi_table_header);
> -	current = ALIGN(current, 16);
> +	acpi_inc_align(ctx, dsdt->length - sizeof(struct acpi_table_header));
>  
>  	/* Pack GNVS into the ACPI table area */
>  	for (i = 0; i < dsdt->length; i++) {
>  		u32 *gnvs = (u32 *)((u32)dsdt + i);
>  		if (*gnvs == ACPI_GNVS_ADDR) {
> -			debug("Fix up global NVS in DSDT to 0x%08x\n", current);
> -			*gnvs = current;
> +			ulong addr = (ulong)map_to_sysmem(ctx->current);
> +
> +			debug("Fix up global NVS in DSDT to %#08lx\n", addr);
> +			*gnvs = addr;
>  			break;
>  		}
>  	}
> @@ -544,51 +547,46 @@ ulong write_acpi_tables(ulong start)
>  	dsdt->checksum = table_compute_checksum((void *)dsdt, dsdt->length);
>  
>  	/* Fill in platform-specific global NVS variables */
> -	acpi_create_gnvs((struct acpi_global_nvs *)current);
> -	current += sizeof(struct acpi_global_nvs);
> -	current = ALIGN(current, 16);
> +	acpi_create_gnvs(ctx->current);
> +	acpi_inc_align(ctx, sizeof(struct acpi_global_nvs));
>  
>  	debug("ACPI:    * FADT\n");
> -	fadt = (struct acpi_fadt *)current;
> -	current += sizeof(struct acpi_fadt);
> -	current = ALIGN(current, 16);
> +	fadt = ctx->current;
> +	acpi_inc_align(ctx, sizeof(struct acpi_fadt));
>  	acpi_create_fadt(fadt, facs, dsdt);
>  	acpi_add_table(rsdp, fadt);
>  
>  	debug("ACPI:    * MADT\n");
> -	madt = (struct acpi_madt *)current;
> +	madt = ctx->current;
>  	acpi_create_madt(madt);
> -	current += madt->header.length;
> +	acpi_inc_align(ctx, madt->header.length);
>  	acpi_add_table(rsdp, madt);
> -	current = ALIGN(current, 16);
>  
>  	debug("ACPI:    * MCFG\n");
> -	mcfg = (struct acpi_mcfg *)current;
> +	mcfg = ctx->current;
>  	acpi_create_mcfg(mcfg);
> -	current += mcfg->header.length;
> +	acpi_inc_align(ctx, mcfg->header.length);
>  	acpi_add_table(rsdp, mcfg);
> -	current = ALIGN(current, 16);
>  
>  	debug("ACPI:    * CSRT\n");
> -	csrt = (struct acpi_csrt *)current;
> +	csrt = ctx->current;
>  	acpi_create_csrt(csrt);
> -	current += csrt->header.length;
> +	acpi_inc_align(ctx, csrt->header.length);
>  	acpi_add_table(rsdp, csrt);
> -	current = ALIGN(current, 16);
>  
>  	debug("ACPI:    * SPCR\n");
> -	spcr = (struct acpi_spcr *)current;
> +	spcr = ctx->current;
>  	acpi_create_spcr(spcr);
> -	current += spcr->header.length;
> +	acpi_inc_align(ctx, spcr->header.length);
>  	acpi_add_table(rsdp, spcr);
> -	current = ALIGN(current, 16);
>  
> -	debug("current = %x\n", current);
> +	addr = map_to_sysmem(ctx->current);
> +	debug("current = %lx\n", addr);
>  
>  	acpi_rsdp_addr = (unsigned long)rsdp;
>  	debug("ACPI: done\n");
>  
> -	return current;
> +	return addr;
>  }
>  
>  ulong acpi_get_rsdp_addr(void)
> diff --git a/include/acpi_table.h b/include/acpi_table.h
> index 3fd2ef16b0..5fd0fa71a6 100644
> --- a/include/acpi_table.h
> +++ b/include/acpi_table.h
> @@ -26,6 +26,8 @@
>  
>  #if !defined(__ACPI__)
>  
> +struct acpi_ctx;
> +
>  /*
>   * RSDP (Root System Description Pointer)
>   * Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum
> @@ -519,6 +521,40 @@ int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags);
>   */
>  void acpi_fill_header(struct acpi_table_header *header, char *signature);
>  
> +/**
> + * acpi_align() - Align the ACPI output pointer to a 16-byte boundary
> + *
> + * @ctx: ACPI context
> + */
> +void acpi_align(struct acpi_ctx *ctx);

Nit: The function names acpi_align() and acpi_align_large() are both vague
on the exact alignment that is used.
How about acpi_align16() and acpi_align64() ?

> +
> +/**
> + * acpi_align_large() - Align the ACPI output pointer to a 64-byte boundary
> + *
> + * @ctx: ACPI context
> + */
> +void acpi_align_large(struct acpi_ctx *ctx);
> +
> +/**
> + * acpi_inc() - Increment the ACPI output pointer by a bit
> + *
> + * The pointer is NOT aligned afterwards.
> + *
> + * @ctx: ACPI context
> + * @amount: Amount to increment by
> + */
> +void acpi_inc(struct acpi_ctx *ctx, uint amount);
> +
> +/**
> + * acpi_inc_align() - Increment the ACPI output pointer by a bit and align
> + *
> + * The pointer is aligned afterwards.
> + *
> + * @ctx: ACPI context
> + * @amount: Amount to increment by
> + */
> +void acpi_inc_align(struct acpi_ctx *ctx, uint amount);

Similar nit as above: acpi_inc_align16() ?

> +
>  #endif /* !__ACPI__*/
>  
>  #include <asm/acpi_table.h>
> diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
> index a86bfa6187..3d24cc26b6 100644
> --- a/lib/acpi/acpi_table.c
> +++ b/lib/acpi/acpi_table.c
> @@ -10,6 +10,7 @@
>  #include <acpi_table.h>
>  #include <cpu.h>
>  #include <version.h>
> +#include <dm/acpi.h>
>  
>  int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags)
>  {
> @@ -94,3 +95,24 @@ void acpi_fill_header(struct acpi_table_header *header, char *signature)
>  	header->oem_revision = U_BOOT_BUILD_DATE;
>  	memcpy(header->aslc_id, ASLC_ID, 4);
>  }
> +
> +void acpi_align(struct acpi_ctx *ctx)
> +{
> +	ctx->current = (void *)ALIGN((ulong)ctx->current, 16);
> +}
> +
> +void acpi_align_large(struct acpi_ctx *ctx)
> +{
> +	ctx->current = (void *)ALIGN((ulong)ctx->current, 64);
> +}
> +
> +void acpi_inc(struct acpi_ctx *ctx, uint amount)
> +{
> +	ctx->current += amount;
> +}
> +
> +void acpi_inc_align(struct acpi_ctx *ctx, uint amount)
> +{
> +	ctx->current += amount;
> +	acpi_align(ctx);
> +}
> diff --git a/test/dm/acpi.c b/test/dm/acpi.c
> index b87fbd16b0..0bd7e51ac9 100644
> --- a/test/dm/acpi.c
> +++ b/test/dm/acpi.c
> @@ -152,3 +152,31 @@ static int dm_test_acpi_write_tables(struct unit_test_state *uts)
>  	return 0;
>  }
>  DM_TEST(dm_test_acpi_write_tables, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> +
> +/* Test basic ACPI functions */
> +static int dm_test_acpi_basic(struct unit_test_state *uts)
> +{
> +	struct acpi_ctx ctx;
> +
> +	/* Check align works */
> +	ctx.current = (void *)5;
> +	acpi_align(&ctx);
> +	ut_asserteq_ptr((void *)16, ctx.current);
> +
> +	/* Check that align does nothing if already aligned */
> +	acpi_align(&ctx);
> +	ut_asserteq_ptr((void *)16, ctx.current);
> +	acpi_align_large(&ctx);
> +	ut_asserteq_ptr((void *)64, ctx.current);
> +	acpi_align_large(&ctx);
> +	ut_asserteq_ptr((void *)64, ctx.current);
> +
> +	/* Check incrementing */
> +	acpi_inc(&ctx, 3);
> +	ut_asserteq_ptr((void *)67, ctx.current);
> +	acpi_inc_align(&ctx, 3);
> +	ut_asserteq_ptr((void *)80, ctx.current);
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_acpi_basic, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> -- 
> 2.25.1.481.gfbce0eb801-goog

Apart from the nits above:
Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

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

* [PATCH v2 09/39] x86: apl: Move p2sb ofdata reading to the correct method
  2020-03-11 12:17     ` Simon Glass
@ 2020-03-11 13:06       ` Andy Shevchenko
  0 siblings, 0 replies; 86+ messages in thread
From: Andy Shevchenko @ 2020-03-11 13:06 UTC (permalink / raw)
  To: u-boot

On Wed, Mar 11, 2020 at 06:17:32AM -0600, Simon Glass wrote:
> On Tue, 10 Mar 2020 at 08:39, Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > On Sun, Mar 08, 2020 at 09:44:33PM -0600, Simon Glass wrote:

> > >               if (plat->bdf < 0)
> > >                       return log_msg_ret("Cannot get p2sb PCI address",
> > > -                                        plat->bdf);
> > > +                                             plat->bdf);
> >
> > Not sure I understand this hunk WRT the patch itself.
> 
> This is to fix a checkpatch error - it reports problems in nearby lines.

So, checkpatch insist on wrong indentation?!

> > > +     if (spl_phase() == PHASE_TPL)
> > >               return p2sb_early_init(dev);
> >
> > > +     else if (spl_phase() == PHASE_SPL)
> >
> > Redundant 'else', but I think we already discussed that and you prefer this
> > way. However, I think this is waste of compilation time. In any case, matter
> > of taste.
> 
> Yes. I feel that it shows that there are two options.
> 
> Just for fun I wrote a program to try to benchmark the difference and
> it does not seem to be detectable.

Compiler optimizes it away in any case, so, you won't see any difference.

> > > +             return p2sb_spl_init(dev);

-- 
With Best Regards,
Andy Shevchenko

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

* Antwort: [PATCH v2 24/39] acpi: Move acpi_add_table() to generic code
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (54 preceding siblings ...)
  2020-03-11 12:58 ` Antwort: [PATCH v2 21/39] acpi: Convert part of acpi_table to use acpi_ctx Wolfgang Wallner
@ 2020-03-11 13:43 ` Wolfgang Wallner
  2020-03-11 14:33 ` Antwort: [PATCH v2 25/39] acpi: Put table-setup code in its own function Wolfgang Wallner
                   ` (5 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-11 13:43 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> Move this code to a generic location so that we can test it with sandbox.
> This requires adding a few new fields to acpi_ctx, so drop the local
> variables used in the original code.
> 
> Also use mapmem to avoid pointer-to-address casts which don't work on
> sandbox.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> 
>  arch/x86/lib/acpi_table.c | 82 +++++----------------------------------
>  include/acpi_table.h      |  9 +++++
>  include/dm/acpi.h         |  5 +++
>  lib/acpi/acpi_table.c     | 64 ++++++++++++++++++++++++++++++
>  test/dm/acpi.c            |  4 ++
>  5 files changed, 92 insertions(+), 72 deletions(-)
> 
> diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
> index 0757ac3431..9168119547 100644
> --- a/arch/x86/lib/acpi_table.c
> +++ b/arch/x86/lib/acpi_table.c
> @@ -83,66 +83,6 @@ static void acpi_write_xsdt(struct acpi_xsdt *xsdt)
>  			sizeof(struct acpi_xsdt));
>  }
>  
> -/**
> - * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length
> - * and checksum.
> - */
> -static void acpi_add_table(struct acpi_rsdp *rsdp, void *table)
> -{
> -	int i, entries_num;
> -	struct acpi_rsdt *rsdt;
> -	struct acpi_xsdt *xsdt = NULL;
> -
> -	/* The RSDT is mandatory while the XSDT is not */
> -	rsdt = (struct acpi_rsdt *)rsdp->rsdt_address;
> -
> -	if (rsdp->xsdt_address)
> -		xsdt = (struct acpi_xsdt *)((u32)rsdp->xsdt_address);
> -
> -	/* This should always be MAX_ACPI_TABLES */
> -	entries_num = ARRAY_SIZE(rsdt->entry);
> -
> -	for (i = 0; i < entries_num; i++) {
> -		if (rsdt->entry[i] == 0)
> -			break;
> -	}
> -
> -	if (i >= entries_num) {
> -		debug("ACPI: Error: too many tables\n");
> -		return;
> -	}
> -
> -	/* Add table to the RSDT */
> -	rsdt->entry[i] = (u32)table;
> -
> -	/* Fix RSDT length or the kernel will assume invalid entries */
> -	rsdt->header.length = sizeof(struct acpi_table_header) +
> -				(sizeof(u32) * (i + 1));
> -
> -	/* Re-calculate checksum */
> -	rsdt->header.checksum = 0;
> -	rsdt->header.checksum = table_compute_checksum((u8 *)rsdt,
> -			rsdt->header.length);
> -
> -	/*
> -	 * And now the same thing for the XSDT. We use the same index as for
> -	 * now we want the XSDT and RSDT to always be in sync in U-Boot
> -	 */
> -	if (xsdt) {
> -		/* Add table to the XSDT */
> -		xsdt->entry[i] = (u64)(u32)table;
> -
> -		/* Fix XSDT length */
> -		xsdt->header.length = sizeof(struct acpi_table_header) +
> -			(sizeof(u64) * (i + 1));
> -
> -		/* Re-calculate checksum */
> -		xsdt->header.checksum = 0;
> -		xsdt->header.checksum = table_compute_checksum((u8 *)xsdt,
> -				xsdt->header.length);
> -	}
> -}
> -
>  static void acpi_create_facs(struct acpi_facs *facs)
>  {
>  	memset((void *)facs, 0, sizeof(struct acpi_facs));
> @@ -462,8 +402,6 @@ static void acpi_create_spcr(struct acpi_spcr *spcr)
>  ulong write_acpi_tables(ulong start_addr)
>  {
>  	struct acpi_ctx sctx, *ctx = &sctx;
> -	struct acpi_rsdp *rsdp;
> -	struct acpi_rsdt *rsdt;
>  	struct acpi_xsdt *xsdt;
>  	struct acpi_facs *facs;
>  	struct acpi_table_header *dsdt;
> @@ -485,9 +423,9 @@ ulong write_acpi_tables(ulong start_addr)
>  	debug("ACPI: Writing ACPI tables at %lx\n", start_addr);
>  
>  	/* We need at least an RSDP and an RSDT Table */
> -	rsdp = ctx->current;
> +	ctx->rsdp = ctx->current;
>  	acpi_inc_align(ctx, sizeof(struct acpi_rsdp));
> -	rsdt = ctx->current;
> +	ctx->rsdt = ctx->current;
>  	acpi_inc_align(ctx, sizeof(struct acpi_rsdt));
>  	xsdt = ctx->current;
>  	acpi_inc_align(ctx, sizeof(struct acpi_xsdt));
> @@ -500,8 +438,8 @@ ulong write_acpi_tables(ulong start_addr)
>  	/* clear all table memory */
>  	memset((void *)start, 0, ctx->current - start);
>  
> -	acpi_write_rsdp(rsdp, rsdt, xsdt);
> -	acpi_write_rsdt(rsdt);
> +	acpi_write_rsdp(ctx->rsdp, ctx->rsdt, xsdt);
> +	acpi_write_rsdt(ctx->rsdt);
>  	acpi_write_xsdt(xsdt);
>  
>  	debug("ACPI:    * FACS\n");
> @@ -543,38 +481,38 @@ ulong write_acpi_tables(ulong start_addr)
>  	fadt = ctx->current;
>  	acpi_inc_align(ctx, sizeof(struct acpi_fadt));
>  	acpi_create_fadt(fadt, facs, dsdt);
> -	acpi_add_table(rsdp, fadt);
> +	acpi_add_table(ctx, fadt);
>  
>  	debug("ACPI:    * MADT\n");
>  	madt = ctx->current;
>  	acpi_create_madt(madt);
>  	acpi_inc_align(ctx, madt->header.length);
> -	acpi_add_table(rsdp, madt);
> +	acpi_add_table(ctx, madt);
>  
>  	debug("ACPI:    * MCFG\n");
>  	mcfg = ctx->current;
>  	acpi_create_mcfg(mcfg);
>  	acpi_inc_align(ctx, mcfg->header.length);
> -	acpi_add_table(rsdp, mcfg);
> +	acpi_add_table(ctx, mcfg);
>  
>  	debug("ACPI:    * CSRT\n");
>  	csrt = ctx->current;
>  	acpi_create_csrt(csrt);
>  	acpi_inc_align(ctx, csrt->header.length);
> -	acpi_add_table(rsdp, csrt);
> +	acpi_add_table(ctx, csrt);
>  
>  	debug("ACPI:    * SPCR\n");
>  	spcr = ctx->current;
>  	acpi_create_spcr(spcr);
>  	acpi_inc_align(ctx, spcr->header.length);
> -	acpi_add_table(rsdp, spcr);
> +	acpi_add_table(ctx, spcr);
>  
>  	acpi_write_dev_tables(ctx);
>  
>  	addr = map_to_sysmem(ctx->current);
>  	debug("current = %lx\n", addr);
>  
> -	acpi_rsdp_addr = (unsigned long)rsdp;
> +	acpi_rsdp_addr = (unsigned long)ctx->rsdp;
>  	debug("ACPI: done\n");
>  
>  	return addr;
> diff --git a/include/acpi_table.h b/include/acpi_table.h
> index 5fd0fa71a6..2131484880 100644
> --- a/include/acpi_table.h
> +++ b/include/acpi_table.h
> @@ -555,6 +555,15 @@ void acpi_inc(struct acpi_ctx *ctx, uint amount);
>   */
>  void acpi_inc_align(struct acpi_ctx *ctx, uint amount);
>  
> +/**
> + * acpi_add_table() - Add a new table to the RSDP and XSDT
> + *
> + * @ctx: ACPI context
> + * @table: Table to add
> + * @return 0 if OK, -E2BIG if too many tables
> + */
> +int acpi_add_table(struct acpi_ctx *ctx, void *table);
> +
>  #endif /* !__ACPI__*/
>  
>  #include <asm/acpi_table.h>
> diff --git a/include/dm/acpi.h b/include/dm/acpi.h
> index dcfcf5c347..4465e62848 100644
> --- a/include/dm/acpi.h
> +++ b/include/dm/acpi.h
> @@ -30,9 +30,14 @@
>   * This contains a few useful pieces of information used when writing
>   *
>   * @current: Current address for writing
> + * @rsdp: Pointer to the Root System Description Pointer, typically used when
> + *	adding a new table. The RSDP holds pointers to the RSDP and XSDT.

typo: "to the RSDT" (not RSDP)

> + * @rsdt: Pointer to the Root System Description Table
>   */
>  struct acpi_ctx {
>  	void *current;
> +	struct acpi_rsdp *rsdp;
> +	struct acpi_rsdt *rsdt;
>  };
>  
>  /**
> diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
> index 3d24cc26b6..00e80ac39a 100644
> --- a/lib/acpi/acpi_table.c
> +++ b/lib/acpi/acpi_table.c
> @@ -9,6 +9,8 @@
>  #include <dm.h>
>  #include <acpi_table.h>
>  #include <cpu.h>
> +#include <mapmem.h>
> +#include <tables_csum.h>
>  #include <version.h>
>  #include <dm/acpi.h>
>  
> @@ -116,3 +118,65 @@ void acpi_inc_align(struct acpi_ctx *ctx, uint amount)
>  	ctx->current += amount;
>  	acpi_align(ctx);
>  }
> +
> +/**
> + * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length
> + * and checksum.
> + */
> +int acpi_add_table(struct acpi_ctx *ctx, void *table)
> +{
> +	int i, entries_num;
> +	struct acpi_rsdt *rsdt;
> +	struct acpi_xsdt *xsdt = NULL;
> +
> +	/* The RSDT is mandatory while the XSDT is not */
> +	rsdt = ctx->rsdt;
> +
> +	if (ctx->rsdp->xsdt_address)
> +		xsdt = map_sysmem(ctx->rsdp->xsdt_address, 0);
> +
> +	/* This should always be MAX_ACPI_TABLES */
> +	entries_num = ARRAY_SIZE(rsdt->entry);
> +
> +	for (i = 0; i < entries_num; i++) {
> +		if (rsdt->entry[i] == 0)
> +			break;
> +	}
> +
> +	if (i >= entries_num) {
> +		debug("ACPI: Error: too many tables\n");
> +		return -E2BIG;
> +	}
> +
> +	/* Add table to the RSDT */
> +	rsdt->entry[i] = map_to_sysmem(table);
> +
> +	/* Fix RSDT length or the kernel will assume invalid entries */
> +	rsdt->header.length = sizeof(struct acpi_table_header) +
> +				(sizeof(u32) * (i + 1));
> +
> +	/* Re-calculate checksum */
> +	rsdt->header.checksum = 0;
> +	rsdt->header.checksum = table_compute_checksum((u8 *)rsdt,
> +						       rsdt->header.length);
> +
> +	/*
> +	 * And now the same thing for the XSDT. We use the same index as for
> +	 * now we want the XSDT and RSDT to always be in sync in U-Boot
> +	 */
> +	if (xsdt) {
> +		/* Add table to the XSDT */
> +		xsdt->entry[i] = map_to_sysmem(table);
> +
> +		/* Fix XSDT length */
> +		xsdt->header.length = sizeof(struct acpi_table_header) +
> +			(sizeof(u64) * (i + 1));
> +
> +		/* Re-calculate checksum */
> +		xsdt->header.checksum = 0;
> +		xsdt->header.checksum =
> +			table_compute_checksum((u8 *)xsdt, xsdt->header.length);
> +	}
> +
> +	return 0;
> +}
> diff --git a/test/dm/acpi.c b/test/dm/acpi.c
> index 0bd7e51ac9..a2a57a29a6 100644
> --- a/test/dm/acpi.c
> +++ b/test/dm/acpi.c
> @@ -21,10 +21,14 @@ static int testacpi_write_tables(const struct udevice *dev,
>  				 struct acpi_ctx *ctx)
>  {
>  	struct acpi_dmar *dmar;
> +	int ret;
>  
>  	dmar = (struct acpi_dmar *)ctx->current;
>  	acpi_create_dmar(dmar, DMAR_INTR_REMAP);
>  	ctx->current += sizeof(struct acpi_dmar);
> +	ret = acpi_add_table(ctx, dmar);
> +	if (ret)
> +		return log_msg_ret("add", ret);
>  
>  	return 0;
>  }
> -- 
> 2.25.1.481.gfbce0eb801-goog

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

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

* Antwort: [PATCH v2 25/39] acpi: Put table-setup code in its own function
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (55 preceding siblings ...)
  2020-03-11 13:43 ` Antwort: [PATCH v2 24/39] acpi: Move acpi_add_table() to generic code Wolfgang Wallner
@ 2020-03-11 14:33 ` Wolfgang Wallner
  2020-03-11 14:34 ` Antwort: [PATCH v2 23/39] acpi: Drop code for missing XSDT from acpi_write_rsdp() Wolfgang Wallner
                   ` (4 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-11 14:33 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> We always write three basic tables to ACPI at the start. Move this into
> its own function, along with acpi_fill_header(), so we can write a test
> for this code.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> 
>  arch/x86/lib/acpi_table.c | 77 +----------------------------------
>  include/acpi_table.h      | 10 +++++
>  lib/acpi/acpi_table.c     | 86 ++++++++++++++++++++++++++++++++++++++-
>  test/dm/acpi.c            | 55 ++++++++++++++++++++++++-
>  4 files changed, 148 insertions(+), 80 deletions(-)
> 
> diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
> index 9168119547..83b92e2a4c 100644
> --- a/arch/x86/lib/acpi_table.c
> +++ b/arch/x86/lib/acpi_table.c
> @@ -31,58 +31,6 @@ extern const unsigned char AmlCode[];
>  /* ACPI RSDP address to be used in boot parameters */
>  static ulong acpi_rsdp_addr;
>  
> -static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt,
> -			    struct acpi_xsdt *xsdt)
> -{
> -	memset(rsdp, 0, sizeof(struct acpi_rsdp));
> -
> -	memcpy(rsdp->signature, RSDP_SIG, 8);
> -	memcpy(rsdp->oem_id, OEM_ID, 6);
> -
> -	rsdp->length = sizeof(struct acpi_rsdp);
> -	rsdp->rsdt_address = (u32)rsdt;
> -
> -	rsdp->xsdt_address = (u64)(u32)xsdt;
> -	rsdp->revision = ACPI_RSDP_REV_ACPI_2_0;
> -
> -	/* Calculate checksums */
> -	rsdp->checksum = table_compute_checksum((void *)rsdp, 20);
> -	rsdp->ext_checksum = table_compute_checksum((void *)rsdp,
> -			sizeof(struct acpi_rsdp));
> -}
> -
> -static void acpi_write_rsdt(struct acpi_rsdt *rsdt)
> -{
> -	struct acpi_table_header *header = &(rsdt->header);
> -
> -	/* Fill out header fields */
> -	acpi_fill_header(header, "RSDT");
> -	header->length = sizeof(struct acpi_rsdt);
> -	header->revision = 1;
> -
> -	/* Entries are filled in later, we come with an empty set */
> -
> -	/* Fix checksum */
> -	header->checksum = table_compute_checksum((void *)rsdt,
> -			sizeof(struct acpi_rsdt));
> -}
> -
> -static void acpi_write_xsdt(struct acpi_xsdt *xsdt)
> -{
> -	struct acpi_table_header *header = &(xsdt->header);
> -
> -	/* Fill out header fields */
> -	acpi_fill_header(header, "XSDT");
> -	header->length = sizeof(struct acpi_xsdt);
> -	header->revision = 1;
> -
> -	/* Entries are filled in later, we come with an empty set */
> -
> -	/* Fix checksum */
> -	header->checksum = table_compute_checksum((void *)xsdt,
> -			sizeof(struct acpi_xsdt));
> -}
> -
>  static void acpi_create_facs(struct acpi_facs *facs)
>  {
>  	memset((void *)facs, 0, sizeof(struct acpi_facs));
> @@ -402,7 +350,6 @@ static void acpi_create_spcr(struct acpi_spcr *spcr)
>  ulong write_acpi_tables(ulong start_addr)
>  {
>  	struct acpi_ctx sctx, *ctx = &sctx;
> -	struct acpi_xsdt *xsdt;
>  	struct acpi_facs *facs;
>  	struct acpi_table_header *dsdt;
>  	struct acpi_fadt *fadt;
> @@ -415,32 +362,10 @@ ulong write_acpi_tables(ulong start_addr)
>  	int i;
>  
>  	start = map_sysmem(start_addr, 0);
> -	ctx->current = start;
> -
> -	/* Align ACPI tables to 16 byte */
> -	acpi_align(ctx);
>  
>  	debug("ACPI: Writing ACPI tables at %lx\n", start_addr);
>  
> -	/* We need at least an RSDP and an RSDT Table */
> -	ctx->rsdp = ctx->current;
> -	acpi_inc_align(ctx, sizeof(struct acpi_rsdp));
> -	ctx->rsdt = ctx->current;
> -	acpi_inc_align(ctx, sizeof(struct acpi_rsdt));
> -	xsdt = ctx->current;
> -	acpi_inc_align(ctx, sizeof(struct acpi_xsdt));
> -	/*
> -	 * Per ACPI spec, the FACS table address must be aligned to a 64 byte
> -	 * boundary (Windows checks this, but Linux does not).
> -	 */
> -	acpi_align_large(ctx);
> -
> -	/* clear all table memory */
> -	memset((void *)start, 0, ctx->current - start);
> -
> -	acpi_write_rsdp(ctx->rsdp, ctx->rsdt, xsdt);
> -	acpi_write_rsdt(ctx->rsdt);
> -	acpi_write_xsdt(xsdt);
> +	acpi_setup_base_tables(ctx, start);
>  
>  	debug("ACPI:    * FACS\n");
>  	facs = ctx->current;
> diff --git a/include/acpi_table.h b/include/acpi_table.h
> index 2131484880..f500f0d3fe 100644
> --- a/include/acpi_table.h
> +++ b/include/acpi_table.h
> @@ -564,6 +564,16 @@ void acpi_inc_align(struct acpi_ctx *ctx, uint amount);
>   */
>  int acpi_add_table(struct acpi_ctx *ctx, void *table);
>  
> +/**
> + * acpi_setup_base_tables() - Set up context along with RSDP, RSDT and XDST

typo: XSDT

> + *
> + * Set up the context with the given start position. Some basic tables are
> + * always needed, so set them up as well.
> + *
> + * @ctx: Context to set up
> + */
> +void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start);
> +
>  #endif /* !__ACPI__*/
>  
>  #include <asm/acpi_table.h>
> diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
> index 00e80ac39a..9f452a65ce 100644
> --- a/lib/acpi/acpi_table.c
> +++ b/lib/acpi/acpi_table.c
> @@ -157,7 +157,7 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table)
>  
>  	/* Re-calculate checksum */
>  	rsdt->header.checksum = 0;
> -	rsdt->header.checksum = table_compute_checksum((u8 *)rsdt,
> +	rsdt->header.checksum = table_compute_checksum(rsdt,
>  						       rsdt->header.length);
>  
>  	/*
> @@ -175,8 +175,90 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table)
>  		/* Re-calculate checksum */
>  		xsdt->header.checksum = 0;
>  		xsdt->header.checksum =
> -			table_compute_checksum((u8 *)xsdt, xsdt->header.length);
> +			table_compute_checksum(xsdt, xsdt->header.length);
>  	}
>  
>  	return 0;
>  }
> +
> +static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt,
> +			    struct acpi_xsdt *xsdt)
> +{
> +	memset(rsdp, 0, sizeof(struct acpi_rsdp));
> +
> +	memcpy(rsdp->signature, RSDP_SIG, 8);
> +	memcpy(rsdp->oem_id, OEM_ID, 6);
> +
> +	rsdp->length = sizeof(struct acpi_rsdp);
> +	rsdp->rsdt_address = map_to_sysmem(rsdt);
> +
> +	rsdp->xsdt_address = map_to_sysmem(xsdt);
> +	rsdp->revision = ACPI_RSDP_REV_ACPI_2_0;
> +
> +	/* Calculate checksums */
> +	rsdp->checksum = table_compute_checksum(rsdp, 20);
> +	rsdp->ext_checksum = table_compute_checksum(rsdp,
> +						    sizeof(struct acpi_rsdp));
> +}
> +
> +static void acpi_write_rsdt(struct acpi_rsdt *rsdt)
> +{
> +	struct acpi_table_header *header = &rsdt->header;
> +
> +	/* Fill out header fields */
> +	acpi_fill_header(header, "RSDT");
> +	header->length = sizeof(struct acpi_rsdt);
> +	header->revision = 1;
> +
> +	/* Entries are filled in later, we come with an empty set */
> +
> +	/* Fix checksum */
> +	header->checksum = table_compute_checksum(rsdt,
> +						  sizeof(struct acpi_rsdt));
> +}
> +
> +static void acpi_write_xsdt(struct acpi_xsdt *xsdt)
> +{
> +	struct acpi_table_header *header = &xsdt->header;
> +
> +	/* Fill out header fields */
> +	acpi_fill_header(header, "XSDT");
> +	header->length = sizeof(struct acpi_xsdt);
> +	header->revision = 1;
> +
> +	/* Entries are filled in later, we come with an empty set */
> +
> +	/* Fix checksum */
> +	header->checksum = table_compute_checksum(xsdt,
> +						  sizeof(struct acpi_xsdt));
> +}
> +
> +void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start)
> +{
> +	struct acpi_xsdt *xsdt;
> +
> +	ctx->current = start;
> +
> +	/* Align ACPI tables to 16 byte */
> +	acpi_align(ctx);
> +
> +	/* We need at least an RSDP and an RSDT Table */
> +	ctx->rsdp = ctx->current;
> +	acpi_inc_align(ctx, sizeof(struct acpi_rsdp));
> +	ctx->rsdt = ctx->current;
> +	acpi_inc_align(ctx, sizeof(struct acpi_rsdt));
> +	xsdt = ctx->current;
> +	acpi_inc_align(ctx, sizeof(struct acpi_xsdt));
> +	/*
> +	 * Per ACPI spec, the FACS table address must be aligned to a 64 byte
> +	 * boundary (Windows checks this, but Linux does not).
> +	 */
> +	acpi_align_large(ctx);

Having this call inside of acpi_setup_base_tables() creates the requirement
that the FACS is set up directly after the base tables. With the current
code this is satisfied, but it might be overlooked by future refactoring.

Maybe move this call out directly in front of the setup of FACS?

> +
> +	/* clear all table memory */
> +	memset((void *)start, '\0', ctx->current - start);
> +
> +	acpi_write_rsdp(ctx->rsdp, ctx->rsdt, xsdt);
> +	acpi_write_rsdt(ctx->rsdt);
> +	acpi_write_xsdt(xsdt);
> +}
> diff --git a/test/dm/acpi.c b/test/dm/acpi.c
> index a2a57a29a6..bb66c7229c 100644
> --- a/test/dm/acpi.c
> +++ b/test/dm/acpi.c
> @@ -9,6 +9,9 @@
>  #include <common.h>
>  #include <acpi_table.h>
>  #include <dm.h>
> +#include <malloc.h>
> +#include <mapmem.h>
> +#include <tables_csum.h>
>  #include <version.h>
>  #include <dm/acpi.h>
>  #include <dm/test.h>
> @@ -138,9 +141,9 @@ static int dm_test_acpi_write_tables(struct unit_test_state *uts)
>  	buf = malloc(BUF_SIZE);
>  	ut_assertnonnull(buf);
>  
> -	ctx.current = buf;
> +	acpi_setup_base_tables(&ctx, buf);
> +	dmar = ctx.current;
>  	ut_assertok(acpi_write_dev_tables(&ctx));
> -	dmar = buf;
>  
>  	/*
>  	 * We should have two dmar tables, one for each "denx,u-boot-acpi-test"
> @@ -153,6 +156,11 @@ static int dm_test_acpi_write_tables(struct unit_test_state *uts)
>  	ut_asserteq(DMAR_INTR_REMAP, dmar[1].flags);
>  	ut_asserteq(32 - 1, dmar[1].host_address_width);
>  
> +	/* Check that the pointers were added correctly */
> +	ut_asserteq(map_to_sysmem(dmar), ctx.rsdt->entry[0]);
> +	ut_asserteq(map_to_sysmem(dmar + 1), ctx.rsdt->entry[1]);
> +	ut_asserteq(0, ctx.rsdt->entry[2]);
> +
>  	return 0;
>  }
>  DM_TEST(dm_test_acpi_write_tables, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> @@ -184,3 +192,46 @@ static int dm_test_acpi_basic(struct unit_test_state *uts)
>  	return 0;
>  }
>  DM_TEST(dm_test_acpi_basic, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> +
> +/* Test acpi_setup_base_tables */
> +static int dm_test_acpi_setup_base_tables(struct unit_test_state *uts)
> +{
> +	struct acpi_rsdp *rsdp;
> +	struct acpi_rsdt *rsdt;
> +	struct acpi_xsdt *xsdt;
> +	struct acpi_ctx ctx;
> +	void *buf, *end;
> +
> +	/* Use an unaligned address deliberately */
> +	buf = memalign(64, BUF_SIZE);

Maybe I'm missing something, but as far as I understand it, the comment 
contradicts the code (aligning to 64 bytes makes it an aligned address,
doesn't it?).

> +	ut_assertnonnull(buf);
> +	acpi_setup_base_tables(&ctx, buf + 4);
> +
> +	rsdp = buf + 16;
> +	ut_asserteq_ptr(rsdp, ctx.rsdp);
> +	ut_assertok(memcmp(RSDP_SIG, rsdp->signature, sizeof(rsdp->signature)));
> +	ut_asserteq(sizeof(*rsdp), rsdp->length);
> +	ut_assertok(table_compute_checksum(rsdp, 20));
> +	ut_assertok(table_compute_checksum(rsdp, sizeof(*rsdp)));
> +
> +	rsdt = PTR_ALIGN((void *)rsdp + sizeof(*rsdp), 16);
> +	ut_asserteq_ptr(rsdt, ctx.rsdt);
> +	ut_assertok(memcmp("RSDT", rsdt->header.signature, ACPI_NAME_LEN));
> +	ut_asserteq(sizeof(*rsdt), rsdt->header.length);
> +	ut_assertok(table_compute_checksum(rsdt, sizeof(*rsdt)));
> +
> +	xsdt = PTR_ALIGN((void *)rsdt + sizeof(*rsdt), 16);
> +	ut_assertok(memcmp("XSDT", xsdt->header.signature, ACPI_NAME_LEN));
> +	ut_asserteq(sizeof(*xsdt), xsdt->header.length);
> +	ut_assertok(table_compute_checksum(xsdt, sizeof(*xsdt)));
> +
> +	end = PTR_ALIGN((void *)xsdt + sizeof(*xsdt), 64);
> +	ut_asserteq_ptr(end, ctx.current);
> +
> +	ut_asserteq(map_to_sysmem(rsdt), rsdp->rsdt_address);
> +	ut_asserteq(map_to_sysmem(xsdt), rsdp->xsdt_address);
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_acpi_setup_base_tables,
> +	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> -- 
> 2.25.1.481.gfbce0eb801-goog

regards, Wolfgang

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

* Antwort: [PATCH v2 23/39] acpi: Drop code for missing XSDT from acpi_write_rsdp()
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (56 preceding siblings ...)
  2020-03-11 14:33 ` Antwort: [PATCH v2 25/39] acpi: Put table-setup code in its own function Wolfgang Wallner
@ 2020-03-11 14:34 ` Wolfgang Wallner
  2020-03-11 14:57 ` Antwort: [PATCH v2 26/39] acpi: Move the xsdt pointer to acpi_ctx Wolfgang Wallner
                   ` (3 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-11 14:34 UTC (permalink / raw)
  To: u-boot

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> We don't actually support tables without an XSDT so we can drop this dead
> code.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> 
>  arch/x86/lib/acpi_table.c | 15 ++-------------
>  1 file changed, 2 insertions(+), 13 deletions(-)

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

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

* Antwort: [PATCH v2 26/39] acpi: Move the xsdt pointer to acpi_ctx
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (57 preceding siblings ...)
  2020-03-11 14:34 ` Antwort: [PATCH v2 23/39] acpi: Drop code for missing XSDT from acpi_write_rsdp() Wolfgang Wallner
@ 2020-03-11 14:57 ` Wolfgang Wallner
  2020-03-12 14:30 ` Antwort: [PATCH v2 27/39] acpi: Add an acpi command Wolfgang Wallner
                   ` (2 subsequent siblings)
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-11 14:57 UTC (permalink / raw)
  To: u-boot

-----"Simon Glass" <sjg@chromium.org> schrieb: -----

> Put this in the context along with the other important pointers.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> 
>  include/dm/acpi.h     |  2 ++
>  lib/acpi/acpi_table.c | 38 ++++++++++++++++----------------------
>  test/dm/acpi.c        |  5 +++++
>  3 files changed, 23 insertions(+), 22 deletions(-)

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

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

* [PATCH v2 13/39] acpi: Add a binding for ACPI settings in the device tree
  2020-03-10 14:50   ` Andy Shevchenko
@ 2020-03-12  3:22     ` Simon Glass
  0 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-12  3:22 UTC (permalink / raw)
  To: u-boot

Hi Andy,

On Tue, 10 Mar 2020 at 08:51, Andy Shevchenko <
andriy.shevchenko@linux.intel.com> wrote:
>
> On Sun, Mar 08, 2020 at 09:44:37PM -0600, Simon Glass wrote:
> > Devices need to report various identifiers in the ACPI tables. Rather
than
> > hard-coding these in drivers it is typically better to put them in the
> > device tree.
> >
> > Add a binding file to describe this.
>
> ...
>
> > +Device bindings are described by their own individual binding files.
> > +
> > +U-Boot provides for some optional properties which are documented
here. See
> > +also hid-over-i2c.txt which describes HID devices.
> > +
> > + - acpi,has-power-resource : (boolean) true if this device has a power
resource.
> > +    This causes a PRIC (ACPI PowerResource) to be written containing
the
>
> What is PRIC?
>
> > +    properties provided by this binding, to describe how to handle
powering the
> > +    device up and down using GPIOs
>
> > + - acpi,compatible : compatible string to report
>
> Hmm... I didn't get this. Is it ACPI _CID?

Will add a pointer to the Linux ACPI docs for this.

>
> > + - acpi,desc : Contains the string to use as the _DDN (DOS (Disk
Operating
> > +    System) Device Name)
>
> > + - acpi,hid : Contains the string to use as the HID (Hardware ID)
> > +    identifier _HID
>
> HID can be dropped to avoid confusion with below.

OK I am actually dropping the next line.

>
> > + - hid-descr-addr : HID register offset (for Human Interface Devices)
>
> > + - acpi,probed : Tells U-Boot to add 'linux,probed' to the ACPI tables
so that
> > +    Linux will not re-init the device
>
> Why? How do we know that Linux will work correctly? Again, we must not
depend
> on the OS behaviour.

The wording is incorrect, will update. This is effectively an 'optional'
device.

>
> > + - acpi,uid : _UID value for device
> > +
> > +
> > +Example
> > +-------
> > +
> > +synaptics_touchpad: synaptics-touchpad at 2c {
> > +     compatible = "hid-over-i2c";
> > +     reg = <0x2c>;
> > +     acpi,hid = "PNP0C50";
> > +     acpi,desc = "Synaptics Touchpad";
> > +     interrupts-extended = <&acpi_gpe GPIO_18_IRQ
> > +                     IRQ_TYPE_EDGE_FALLING>;
> > +     acpi,probed;
> > +     hid-descr-addr = <0x20>;
> > +};

Regards,
Simon

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

* [PATCH v2 17/39] acpi: Add a central location for table version numbers
  2020-03-10  9:26 ` Antwort: [PATCH v2 17/39] acpi: Add a central location for table version numbers Wolfgang Wallner
@ 2020-03-12  3:22   ` Simon Glass
  0 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-12  3:22 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

On Tue, 10 Mar 2020 at 03:26, Wolfgang Wallner <
wolfgang.wallner@br-automation.com> wrote:
>
> Hi Simon,
>
> -----"Simon Glass" <sjg@chromium.org> schrieb: -----
> >
> > Each ACPI table has its own version number. Add the version numbers in a
> > single function so we can keep them consistent and easily see what
> > versions are supported.
> >
> > Start a new acpi_table file in a generic directory to house this
function.
> > We can move things over to this file from x86 as needed.
> >
> > Signed-off-by: Simon Glass <sjg@chromium.org>
> > ---
> >
> > Changes in v2:
> > - Move the sandbox acpi_table.h header file to an earlier patch
> > - Use #defines for MADT and MCFG version numbers
> >
> >  include/acpi_table.h  | 61 +++++++++++++++++++++++++++++++++++++++++++
> >  lib/Makefile          |  1 +
> >  lib/acpi/Makefile     |  4 +++
> >  lib/acpi/acpi_table.c | 60 ++++++++++++++++++++++++++++++++++++++++++
> >  test/dm/acpi.c        | 14 ++++++++++
> >  5 files changed, 140 insertions(+)
> >  create mode 100644 lib/acpi/Makefile
> >  create mode 100644 lib/acpi/acpi_table.c
> >
> > diff --git a/include/acpi_table.h b/include/acpi_table.h
> > index dd74895813..ccf6fa04db 100644
> > --- a/include/acpi_table.h
> > +++ b/include/acpi_table.h
> > @@ -202,6 +202,26 @@ struct __packed acpi_fadt {
> >       struct acpi_gen_regaddr x_gpe1_blk;
> >  };
> >
> > +/* FADT TABLE Revision values */
> > +#define ACPI_FADT_REV_ACPI_1_0               1
> > +#define ACPI_FADT_REV_ACPI_2_0               3
> > +#define ACPI_FADT_REV_ACPI_3_0               4
> > +#define ACPI_FADT_REV_ACPI_4_0               4
> > +#define ACPI_FADT_REV_ACPI_5_0               5
> > +#define ACPI_FADT_REV_ACPI_6_0               6
> > +
> > +/* MADT TABLE Revision values */
> > +#define ACPI_MADT_REV_ACPI_3_0               2
> > +#define ACPI_MADT_REV_ACPI_4_0               3
> > +#define ACPI_MADT_REV_ACPI_5_0               3
> > +#define ACPI_MADT_REV_ACPI_6_0               5
> > +
> > +#define ACPI_MCFG_REV_ACPI_3_0               1
> > +
> > +/* IVRS Revision Field */
> > +#define IVRS_FORMAT_FIXED    0x01    /* Type 10h & 11h only */
> > +#define IVRS_FORMAT_MIXED    0x02    /* Type 10h, 11h, & 40h */
> > +
> >  /* FACS flags */
> >  #define ACPI_FACS_S4BIOS_F           BIT(0)
> >  #define ACPI_FACS_64BIT_WAKE_F               BIT(1)
> > @@ -391,6 +411,47 @@ struct __packed acpi_spcr {
> >       u32 reserved2;
> >  };
> >
> > +/* Tables defined by ACPI and generated by U-Boot */
> > +enum acpi_tables {
> > +     ACPITAB_BERT,
> > +     ACPITAB_DBG2,
> > +     ACPITAB_DMAR,
> > +     ACPITAB_DSDT,
> > +     ACPITAB_FACS,
> > +     ACPITAB_FADT,
> > +     ACPITAB_HEST,
> > +     ACPITAB_HPET,
> > +     ACPITAB_IVRS,
> > +     ACPITAB_MADT,
> > +     ACPITAB_MCFG,
> > +     ACPITAB_RSDP,
> > +     ACPITAB_RSDT,
> > +     ACPITAB_SLIT,
> > +     ACPITAB_SRAT,
> > +     ACPITAB_SSDT,
> > +     ACPITAB_TCPA,
> > +     ACPITAB_TPM2,
> > +     ACPITAB_XSDT,
> > +     ACPITAB_ECDT,
> > +
> > +     /* Additional proprietary tables */
> > +     ACPITAB_VFCT,
> > +     ACPITAB_NHLT,
> > +     ACPITAB_SPMI,
> > +
> > +     ACPITAB_COUNT,
> > +};
> > +
> > +/**
> > + * acpi_get_table_revision() - Get the revision number generated for a
table
> > + *
> > + * This keeps the version-number information in one place
> > + *
> > + * @table: ACPI table to check
> > + * @return version number that U-Boot generates
> > + */
> > +int acpi_get_table_revision(enum acpi_tables table);
> > +
> >  #endif /* !__ACPI__*/
> >
> >  #include <asm/acpi_table.h>
> > diff --git a/lib/Makefile b/lib/Makefile
> > index 15259d0473..9df834c2fd 100644
> > --- a/lib/Makefile
> > +++ b/lib/Makefile
> > @@ -5,6 +5,7 @@
> >
> >  ifndef CONFIG_SPL_BUILD
> >
> > +obj-$(CONFIG_$(SPL_TPL_)ACPIGEN) += acpi/
>
> Is $(SPL_TPL_) needed here?
> I don't see a CONFIG_SPL_ACPIGEN, and this section of the file is also
covered
> by "ifndef CONFIG_SPL_BUILD".
>
> In any case, would it make sense to generate ACPI-related code for SPL
and TPL?
> As U-Boot does not use ACPI, but only provides it to the kernel, I would
> assume we only need to handle ACPI tables in the last U-Boot stage before
> booting a kernel.

That's right. The point of this is to only include it in U-Boot proper.
Actually I should use $SPL here so will fix that.

Regards,
Simon

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

* [PATCH v2 21/39] acpi: Convert part of acpi_table to use acpi_ctx
  2020-03-11 12:58 ` Antwort: [PATCH v2 21/39] acpi: Convert part of acpi_table to use acpi_ctx Wolfgang Wallner
@ 2020-03-12  3:23   ` Simon Glass
  2020-03-12 13:03   ` Antwort: " Wolfgang Wallner
  1 sibling, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-12  3:23 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

On Wed, 11 Mar 2020 at 06:58, Wolfgang Wallner <
wolfgang.wallner@br-automation.com> wrote:
>
> Hi Simon,
>
> -----"Simon Glass" <sjg@chromium.org> schrieb: -----
> >
> > The current code uses an address but a pointer would result in fewer
> > casts. Also it repeats the alignment code in a lot of places so this
would
> > be better done in a helper function.
> >
> > Update write_acpi_tables() to make use of the new acpi_ctx structure,
> > adding a few helpers to clean things up.
> >
> > Signed-off-by: Simon Glass <sjg@chromium.org>
> > ---
> >
> > Changes in v2: None
> >
> >  arch/x86/lib/acpi_table.c | 88 +++++++++++++++++++--------------------
> >  include/acpi_table.h      | 36 ++++++++++++++++
> >  lib/acpi/acpi_table.c     | 22 ++++++++++
> >  test/dm/acpi.c            | 28 +++++++++++++
> >  4 files changed, 129 insertions(+), 45 deletions(-)
> >

[..]

> > +/**
> > + * acpi_align() - Align the ACPI output pointer to a 16-byte boundary
> > + *
> > + * @ctx: ACPI context
> > + */
> > +void acpi_align(struct acpi_ctx *ctx);
>
> Nit: The function names acpi_align() and acpi_align_large() are both vague
> on the exact alignment that is used.
> How about acpi_align16() and acpi_align64() ?

There is I think only one case where we use 64. Most of the time it is 16.
So I thought it was a bit silly to put 16 in the function name - it is the
standard alignment.

Perhaps I should use align() and align64()?

Regards,
Simon

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

* [PATCH v2 13/39] acpi: Add a binding for ACPI settings in the device tree
  2020-03-10  9:15 ` Antwort: [PATCH v2 13/39] acpi: Add a binding for ACPI settings in the device tree Wolfgang Wallner
@ 2020-03-12  3:24   ` Simon Glass
  2020-03-12 12:44   ` Antwort: " Wolfgang Wallner
  1 sibling, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-12  3:24 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

On Tue, 10 Mar 2020 at 03:15, Wolfgang Wallner <
wolfgang.wallner@br-automation.com> wrote:
>
> Hi Simon,
>
> -----"Simon Glass" <sjg@chromium.org> schrieb: -----
> >
> > Devices need to report various identifiers in the ACPI tables. Rather
than
> > hard-coding these in drivers it is typically better to put them in the
> > device tree.
> >
> > Add a binding file to describe this.
> >
> > Signed-off-by: Simon Glass <sjg@chromium.org>
> > ---
> >
> > Changes in v2:
> > - Fix definition of HID
> > - Infer hid-over-i2c CID value
> > - Add the hid-over-i2c binding document
> >
> >  doc/device-tree-bindings/device.txt           | 36 +++++++++++++++
> >  .../input/hid-over-i2c.txt                    | 44 +++++++++++++++++++
> >  2 files changed, 80 insertions(+)
> >  create mode 100644 doc/device-tree-bindings/device.txt
> >  create mode 100644 doc/device-tree-bindings/input/hid-over-i2c.txt
> >
> > diff --git a/doc/device-tree-bindings/device.txt
b/doc/device-tree-bindings/device.txt
> > new file mode 100644
> > index 0000000000..31ec2fa31b
> > --- /dev/null
> > +++ b/doc/device-tree-bindings/device.txt
> > @@ -0,0 +1,36 @@
> > +Devices
> > +=======
> > +
> > +Device bindings are described by their own individual binding files.
> > +
> > +U-Boot provides for some optional properties which are documented
here. See
> > +also hid-over-i2c.txt which describes HID devices.
> > +
> > + - acpi,has-power-resource : (boolean) true if this device has a power
resource.
> > +    This causes a PRIC (ACPI PowerResource) to be written containing
the
>
> What is the meaning of PRIC? I can't find a defition for this term.

I'll drop that.

>
> > +    properties provided by this binding, to describe how to handle
powering the
> > +    device up and down using GPIOs
> > + - acpi,compatible : compatible string to report
>
> What does "compatible string" mean in this context? Does it refer to the
> "Compatible ID" (_CID) of ACPI? As stated in the previous mail thread [1],
> I think we could infer many of the ACPI properties from existing device
tree
> properties. Especially I suspect that ACPI's _CID could have a 1:1 mapping
> to the compatible property in device tree. E.g. a driver which states that
> it is compatible with "hid-over-i2c" in its device tree description would
> know (implement internally) that it is also compatible with ACPI's _CID
> "PNP0C50", thus we would not have to add this information in the device
tree.

This is described to in the Linux binding file:

Documentation/acpi/enumeration.txt

The special DT namespace link device ID, PRP0001, provides a means to use
the
existing DT-compatible device identification in ACPI and to satisfy the
above
requirements following from the ACPI specification at the same time.
Namely,
if PRP0001 is returned by _HID, the ACPI subsystem will look for the
"compatible" property in the device object's _DSD and will use the value of
that
property to identify the corresponding device in analogy with the original
DT
device identification algorithm.  If the "compatible" property is not
present
or its value is not valid, the device will not be enumerated by the ACPI
subsystem.  Otherwise, it will be enumerated automatically as a platform
device
(except when an I2C or SPI link from the device to its parent is present, in
which case the ACPI core will leave the device enumeration to the parent's
driver) and the identification strings from the "compatible" property value
will
be used to find a driver for the device along with the device IDs listed by
_CID
(if present).


So we set acpi,hid to "PRP0001" and acpi,compatible to the device-tree
compatible string.

>
> [1] https://lists.denx.de/pipermail/u-boot/2020-February/398856.html
>
> > + - acpi,desc : Contains the string to use as the _DDN (DOS (Disk
Operating
> > +    System) Device Name)
>
> Nit: I assume "desc" stands for "description". But strictly speaking it is
> not a description, it is a device name. I would prefer something like
> "acpi,devname" or even "acpi,ddn".

OK we can go with acpi,ddn. I have been thinking about that as it is one
less mapping to know.

>
> > + - acpi,hid : Contains the string to use as the HID (Hardware ID)
> > +    identifier _HID
> > + - hid-descr-addr : HID register offset (for Human Interface Devices)
>
> This property is already described in the file hid-over-i2c.txt (with a
similar
> but slightly different text), thus I would not describe it here also.

Will drop.

>
> > + - acpi,probed : Tells U-Boot to add 'linux,probed' to the ACPI tables
so that
> > +    Linux will not re-init the device
>
> I can't find 'linux,probed' in the Linux kernel.
> I only find it in patches specific for chromium-os[2], but the description
> there does not match the description given here (there it is described as
> being probed before insertion vs. here it is described as not being probed
> any more).
>
> [2]
https://groups.google.com/a/chromium.org/forum/#!msg/chromium-os-reviews/4HTHl78IGHw/oz82uImnBgAJ

Yes it seems that this has not yet made it upstream to Linux.

I will fix the description.

>
> > + - acpi,uid : _UID value for device
> > +
> > +
> > +Example
> > +-------
> > +
> > +synaptics_touchpad: synaptics-touchpad at 2c {
> > +     compatible = "hid-over-i2c";
> > +     reg = <0x2c>;
> > +     acpi,hid = "PNP0C50";
> > +     acpi,desc = "Synaptics Touchpad";
> > +     interrupts-extended = <&acpi_gpe GPIO_18_IRQ
> > +                     IRQ_TYPE_EDGE_FALLING>;
> > +     acpi,probed;
> > +     hid-descr-addr = <0x20>;
> > +};
> > diff --git a/doc/device-tree-bindings/input/hid-over-i2c.txt
b/doc/device-tree-bindings/input/hid-over-i2c.txt
> > new file mode 100644
>
> Adding the file hid-over-i2c.txt is straight forward, while getting the
ACPI
> bindings correct is probably more tricky. Would it make sense to add this
file
> in an individual patch?

OK I'll split it.

>
> > index 0000000000..c76bafaf98
> > --- /dev/null
> > +++ b/doc/device-tree-bindings/input/hid-over-i2c.txt
>
> This file is taken from the Linux kernel, should this be stated at the
> beginning? (I often see "Taken from ..." in source code files, I'm not
sure
> how this is handled for documentation).

Yes we normally mention that.

>
> > @@ -0,0 +1,44 @@
> > +* HID over I2C Device-Tree bindings
> > +
> > +HID over I2C provides support for various Human Interface Devices over
the
> > +I2C bus. These devices can be for example touchpads, keyboards, touch
screens
> > +or sensors.
> > +
> > +The specification has been written by Microsoft and is currently
available here:
> > +http://msdn.microsoft.com/en-us/library/windows/hardware/hh852380.aspx
> > +
> > +If this binding is used, the kernel module i2c-hid will handle the
communication
> > +with the device and the generic hid core layer will handle the
protocol.
>
> This sentence is specific to the Linux kernel, and does not really apply
to
> U-Boot. I would propose one of the following:
>
> * Point out specifically that the Linux kernel is talked about
> * Drop the sentence
> * State at the beginning of the file that the file is taken unmodified
from the
>   Linux kernel

Yes it's funny that the bindings are supposed to describe hardware but
sometimes the software creeps in.

In fact binding files are always supposed to be unmodified, so I don't
think we can/should change it.

Regards,
Simon

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

* Antwort: Re: [PATCH v2 13/39] acpi: Add a binding for ACPI settings in the device tree
  2020-03-10  9:15 ` Antwort: [PATCH v2 13/39] acpi: Add a binding for ACPI settings in the device tree Wolfgang Wallner
  2020-03-12  3:24   ` Simon Glass
@ 2020-03-12 12:44   ` Wolfgang Wallner
  2020-03-13  0:36     ` Simon Glass
  1 sibling, 1 reply; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-12 12:44 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----

[snip]

>  > > +    properties provided by this binding, to describe how to handle powering the
>  > > +    device up and down using GPIOs
>  > > + - acpi,compatible : compatible string to report
>  >
>  > What does "compatible string" mean in this context? Does it refer to the
>  > "Compatible ID" (_CID) of ACPI? As stated in the previous mail thread [1],
>  > I think we could infer many of the ACPI properties from existing device tree
>  > properties. Especially I suspect that ACPI's _CID could have a 1:1 mapping
>  > to the compatible property in device tree. E.g. a driver which states that
>  > it is compatible with "hid-over-i2c" in its device tree description would
>  > know (implement internally) that it is also compatible with ACPI's _CID
>  > "PNP0C50", thus we would not have to add this information in the device tree.
>  
>  This is described to in the Linux binding file:
>  
>  Documentation/acpi/enumeration.txt
>  
>  The special DT namespace link device ID, PRP0001, provides a means to use the
>  existing DT-compatible device identification in ACPI and to satisfy the above
>  requirements following from the ACPI specification at the same time.  Namely,
>  if PRP0001 is returned by _HID, the ACPI subsystem will look for the
>  "compatible" property in the device object's _DSD and will use the value of that
>  property to identify the corresponding device in analogy with the original DT
>  device identification algorithm.  If the "compatible" property is not present
>  or its value is not valid, the device will not be enumerated by the ACPI
>  subsystem.  Otherwise, it will be enumerated automatically as a platform device
>  (except when an I2C or SPI link from the device to its parent is present, in
>  which case the ACPI core will leave the device enumeration to the parent's
>  driver) and the identification strings from the "compatible" property value will
>  be used to find a driver for the device along with the device IDs listed by _CID
>  (if present).
>  
>  
>  So we set acpi,hid to "PRP0001" and acpi,compatible to the device-tree compatible string.
  
I think there are different cases that can be distinguished in which we need to
translate between ACPI and device tree.

1) The OS has an existing ACPI binding for the device. U-Boot uses device tree
   for device description, but the OS uses ACPI (e.g. Linux on x86).
   We need a way to tell U-Boot how to create the appropriate ACPI descriptons.

2) There is no existing ACPI binding for the device in the OS, but there is
   already an existing device tree binding. As stated in the Linux documentation
   you have referred to, it would not make sense to introduce a new ACPI binding
   that would just be the same as the existing device tree one. As I understand
   this is what the "PRP0001" tag was introduced for (to reuse existing device
   tree descriptions and save redundant work).

Handling case 2:
PRP0001 allows to wire existing device tree properties into ACPI descriptions,
and I think it provides a solution for most of case 2. So for case 2 I think
most of the ACPI description can be autogenerated:
  * Set _HID to "PRP0001"
  * Pack all existing device tree properties into the ACPI _DSD method
    (this also implies that no additional "acpi,compatible" property is
    required, as we can reuse the existing "compatible" property)

    I say "most of" because I don't know how to map certain parts between
    device tree and ACPI, e.g. interrupt descriptions.    
    
Handling case 1:
Case 1 is more tricky, and up to now I was assuming you are targeting case 1
with the new additional properties. It might not be as straigt forward as in
case 2, but I think also in this case we can infer most of the ACPI properties
from the existing device tree properties without adding new ones. This is the
example from the previous mail discussions where e.g. from a device tree
"compatible" property "hid-over-i2c" we could infer the ACPI _HID "PNP0C50"
without adding new properties in the device tree.

Again, I have left out more complex things like interrupts in this description.

Anyway, my experience with both device tree as well as ACPI is limited, so
please take all my statements with a grain of salt.

regards, Wolfgang

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

* Antwort: Re: [PATCH v2 21/39] acpi: Convert part of acpi_table to use acpi_ctx
  2020-03-11 12:58 ` Antwort: [PATCH v2 21/39] acpi: Convert part of acpi_table to use acpi_ctx Wolfgang Wallner
  2020-03-12  3:23   ` Simon Glass
@ 2020-03-12 13:03   ` Wolfgang Wallner
  1 sibling, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-12 13:03 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----

> Hi Wolfgang,
>  
>  On Wed, 11 Mar 2020 at 06:58, Wolfgang Wallner <wolfgang.wallner@br-automation.com> wrote:
>  >
>  > Hi Simon,
>  >
>  > -----"Simon Glass" <sjg@chromium.org> schrieb: -----
>  > >
>  > > The current code uses an address but a pointer would result in fewer
>  > > casts. Also it repeats the alignment code in a lot of places so this would
>  > > be better done in a helper function.
>  > >
>  > > Update write_acpi_tables() to make use of the new acpi_ctx structure,
>  > > adding a few helpers to clean things up.
>  > >
>  > > Signed-off-by: Simon Glass <sjg@chromium.org>
>  > > ---
>  > >
>  > > Changes in v2: None
>  > >
>  > >  arch/x86/lib/acpi_table.c | 88 +++++++++++++++++++--------------------
>  > >  include/acpi_table.h      | 36 ++++++++++++++++
>  > >  lib/acpi/acpi_table.c     | 22 ++++++++++
>  > >  test/dm/acpi.c            | 28 +++++++++++++
>  > >  4 files changed, 129 insertions(+), 45 deletions(-)
>  > >
>  
>  [..]
>  
>  > > +/**
>  > > + * acpi_align() - Align the ACPI output pointer to a 16-byte boundary
>  > > + *
>  > > + * @ctx: ACPI context
>  > > + */
>  > > +void acpi_align(struct acpi_ctx *ctx);
>  >
>  > Nit: The function names acpi_align() and acpi_align_large() are both vague
>  > on the exact alignment that is used.
>  > How about acpi_align16() and acpi_align64() ?
>  
>  There is I think only one case where we use 64. Most of the time it is 16. So I thought it was a bit silly to put 16 in the function name - it is the standard alignment.
>  
>  Perhaps I should use align() and align64()?

Yes, I'm fine with that.

regards, Wolfgang

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

* Antwort: [PATCH v2 27/39] acpi: Add an acpi command
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (58 preceding siblings ...)
  2020-03-11 14:57 ` Antwort: [PATCH v2 26/39] acpi: Move the xsdt pointer to acpi_ctx Wolfgang Wallner
@ 2020-03-12 14:30 ` Wolfgang Wallner
  2020-03-13  9:55 ` Antwort: [PATCH v2 30/39] acpi: Add functions to generate ACPI code Wolfgang Wallner
  2020-03-13 11:16 ` Antwort: [PATCH v2 31/39] gpio: Add a method to convert a GPIO to ACPI Wolfgang Wallner
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-12 14:30 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> It is useful to dump ACPI tables in U-Boot to see what has been generated.
> Add a command to handle this.
> 
> To allow the command to find the tables, add a position into the global
> data.
> 
> Support subcommands to list and dump the tables.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> 
>  arch/sandbox/include/asm/global_data.h |   1 +
>  arch/x86/include/asm/global_data.h     |   1 +
>  cmd/Kconfig                            |  14 ++
>  cmd/Makefile                           |   1 +
>  cmd/acpi.c                             | 179 +++++++++++++++++++++++++
>  lib/acpi/acpi_table.c                  |   1 +
>  test/dm/acpi.c                         |  73 ++++++++++
>  7 files changed, 270 insertions(+)
>  create mode 100644 cmd/acpi.c

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

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

* [PATCH v2 13/39] acpi: Add a binding for ACPI settings in the device tree
  2020-03-12 12:44   ` Antwort: " Wolfgang Wallner
@ 2020-03-13  0:36     ` Simon Glass
  0 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-13  0:36 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

On Thu, 12 Mar 2020 at 06:44, Wolfgang Wallner
<wolfgang.wallner@br-automation.com> wrote:
>
> Hi Simon,
>
> -----"Simon Glass" <sjg@chromium.org> schrieb: -----
>
> [snip]
>
> >  > > +    properties provided by this binding, to describe how to handle powering the
> >  > > +    device up and down using GPIOs
> >  > > + - acpi,compatible : compatible string to report
> >  >
> >  > What does "compatible string" mean in this context? Does it refer to the
> >  > "Compatible ID" (_CID) of ACPI? As stated in the previous mail thread [1],
> >  > I think we could infer many of the ACPI properties from existing device tree
> >  > properties. Especially I suspect that ACPI's _CID could have a 1:1 mapping
> >  > to the compatible property in device tree. E.g. a driver which states that
> >  > it is compatible with "hid-over-i2c" in its device tree description would
> >  > know (implement internally) that it is also compatible with ACPI's _CID
> >  > "PNP0C50", thus we would not have to add this information in the device tree.
> >
> >  This is described to in the Linux binding file:
> >
> >  Documentation/acpi/enumeration.txt
> >
> >  The special DT namespace link device ID, PRP0001, provides a means to use the
> >  existing DT-compatible device identification in ACPI and to satisfy the above
> >  requirements following from the ACPI specification at the same time.  Namely,
> >  if PRP0001 is returned by _HID, the ACPI subsystem will look for the
> >  "compatible" property in the device object's _DSD and will use the value of that
> >  property to identify the corresponding device in analogy with the original DT
> >  device identification algorithm.  If the "compatible" property is not present
> >  or its value is not valid, the device will not be enumerated by the ACPI
> >  subsystem.  Otherwise, it will be enumerated automatically as a platform device
> >  (except when an I2C or SPI link from the device to its parent is present, in
> >  which case the ACPI core will leave the device enumeration to the parent's
> >  driver) and the identification strings from the "compatible" property value will
> >  be used to find a driver for the device along with the device IDs listed by _CID
> >  (if present).
> >
> >
> >  So we set acpi,hid to "PRP0001" and acpi,compatible to the device-tree compatible string.
>
> I think there are different cases that can be distinguished in which we need to
> translate between ACPI and device tree.
>
> 1) The OS has an existing ACPI binding for the device. U-Boot uses device tree
>    for device description, but the OS uses ACPI (e.g. Linux on x86).
>    We need a way to tell U-Boot how to create the appropriate ACPI descriptons.

For now I'd like to do this in the U-Boot driver. We have so few
drivers doing it that I don't think we can generalise this yet. If we
start to see a pattern then we might start with some common code...

>
> 2) There is no existing ACPI binding for the device in the OS, but there is
>    already an existing device tree binding. As stated in the Linux documentation
>    you have referred to, it would not make sense to introduce a new ACPI binding
>    that would just be the same as the existing device tree one. As I understand
>    this is what the "PRP0001" tag was introduced for (to reuse existing device
>    tree descriptions and save redundant work).
>
> Handling case 2:
> PRP0001 allows to wire existing device tree properties into ACPI descriptions,
> and I think it provides a solution for most of case 2. So for case 2 I think
> most of the ACPI description can be autogenerated:
>   * Set _HID to "PRP0001"
>   * Pack all existing device tree properties into the ACPI _DSD method
>     (this also implies that no additional "acpi,compatible" property is
>     required, as we can reuse the existing "compatible" property)
>
>     I say "most of" because I don't know how to map certain parts between
>     device tree and ACPI, e.g. interrupt descriptions.

...and perhaps end up with something like this. But I really don't
feel comfortable trying to build out something like this with so few
use cases. We don't even have one* in coral yet.

>
> Handling case 1:
> Case 1 is more tricky, and up to now I was assuming you are targeting case 1
> with the new additional properties. It might not be as straigt forward as in
> case 2, but I think also in this case we can infer most of the ACPI properties
> from the existing device tree properties without adding new ones. This is the
> example from the previous mail discussions where e.g. from a device tree
> "compatible" property "hid-over-i2c" we could infer the ACPI _HID "PNP0C50"
> without adding new properties in the device tree.
>
> Again, I have left out more complex things like interrupts in this description.
>
> Anyway, my experience with both device tree as well as ACPI is limited, so
> please take all my statements with a grain of salt.

I suspect they may be some things we can do here to automate this. But
again, this is for the future when we actually start to see these
cases.

I have done the hid-over-i2c compatible string (automatically setting
CID to PNP0C50) as we have two coral drivers that do that.

Regards,
Simon

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

* Antwort: [PATCH v2 30/39] acpi: Add functions to generate ACPI code
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (59 preceding siblings ...)
  2020-03-12 14:30 ` Antwort: [PATCH v2 27/39] acpi: Add an acpi command Wolfgang Wallner
@ 2020-03-13  9:55 ` Wolfgang Wallner
  2020-03-14 20:34   ` Simon Glass
  2020-03-13 11:16 ` Antwort: [PATCH v2 31/39] gpio: Add a method to convert a GPIO to ACPI Wolfgang Wallner
  61 siblings, 1 reply; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-13  9:55 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> Sometimes we need to generate ACPI code on the fly based on things only
> known at run time. Add a new 'acpigen' library to handle this. This code
> comes from coreboot and has been modified to support the acpi_ctx struct.
> 
> Also add acpi_device.c to the build, since these files are co-dependent.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2: None
> 
>  include/acpigen.h  |  482 +++++++++++++
>  include/dm/acpi.h  |    7 +
>  include/irq.h      |    2 +
>  lib/acpi/Makefile  |    2 +
>  lib/acpi/acpigen.c | 1683 ++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 2176 insertions(+)
>  create mode 100644 include/acpigen.h
>  create mode 100644 lib/acpi/acpigen.c

What coreboot version is this based on?
I have compared it to the current master in coreboot and there are some
differences (ignoring the changes for acpi_ctx support).

regards, Wolfgang

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

* Antwort: [PATCH v2 31/39] gpio: Add a method to convert a GPIO to ACPI
  2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
                   ` (60 preceding siblings ...)
  2020-03-13  9:55 ` Antwort: [PATCH v2 30/39] acpi: Add functions to generate ACPI code Wolfgang Wallner
@ 2020-03-13 11:16 ` Wolfgang Wallner
  61 siblings, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-13 11:16 UTC (permalink / raw)
  To: u-boot

Hi Simon,

-----"Simon Glass" <sjg@chromium.org> schrieb: -----
> 
> 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>
> ---
> 
> Changes in v2: None
> 
>  drivers/gpio/gpio-uclass.c | 21 +++++++++++++++++++++
>  include/acpi_device.h      | 12 ++++++++++++
>  include/asm-generic/gpio.h | 27 +++++++++++++++++++++++++++
>  lib/acpi/acpi_device.c     | 16 ++++++++++++++++
>  4 files changed, 76 insertions(+)
 
Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>

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

* [PATCH v2 30/39] acpi: Add functions to generate ACPI code
  2020-03-13  9:55 ` Antwort: [PATCH v2 30/39] acpi: Add functions to generate ACPI code Wolfgang Wallner
@ 2020-03-14 20:34   ` Simon Glass
  0 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-14 20:34 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

On Fri, 13 Mar 2020 at 03:55, Wolfgang Wallner
<wolfgang.wallner@br-automation.com> wrote:
>
> Hi Simon,
>
> -----"Simon Glass" <sjg@chromium.org> schrieb: -----
> >
> > Sometimes we need to generate ACPI code on the fly based on things only
> > known at run time. Add a new 'acpigen' library to handle this. This code
> > comes from coreboot and has been modified to support the acpi_ctx struct.
> >
> > Also add acpi_device.c to the build, since these files are co-dependent.
> >
> > Signed-off-by: Simon Glass <sjg@chromium.org>
> > ---
> >
> > Changes in v2: None
> >
> >  include/acpigen.h  |  482 +++++++++++++
> >  include/dm/acpi.h  |    7 +
> >  include/irq.h      |    2 +
> >  lib/acpi/Makefile  |    2 +
> >  lib/acpi/acpigen.c | 1683 ++++++++++++++++++++++++++++++++++++++++++++
> >  5 files changed, 2176 insertions(+)
> >  create mode 100644 include/acpigen.h
> >  create mode 100644 lib/acpi/acpigen.c
>
> What coreboot version is this based on?
> I have compared it to the current master in coreboot and there are some
> differences (ignoring the changes for acpi_ctx support).

I don't think coreboot does releases very often. The commit is efa3084d63.

Regards,
Simon

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

* Antwort: [PATCH v2 32/39] irq: Add a method to convert an interrupt to ACPI
  2020-03-09  3:44 ` [PATCH v2 32/39] irq: Add a method to convert an interrupt " Simon Glass
@ 2020-03-18 16:17   ` Wolfgang Wallner
  2020-03-18 16:20   ` Wolfgang Wallner
  1 sibling, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-18 16:17 UTC (permalink / raw)
  To: u-boot

Hi Simon,

"Simon Glass" <sjg@chromium.org> schrieb am 09.03.2020 04:44:56:

> Von: "Simon Glass" <sjg@chromium.org>
> An: "U-Boot Mailing List" <u-boot@lists.denx.de>, 
> Kopie: "Bin Meng" <bmeng.cn@gmail.com>, "Wolfgang Wallner" 
> <wolfgang.wallner@br-automation.com>, "Andy Shevchenko" 
> <andriy.shevchenko@linux.intel.com>, "Simon Glass" <sjg@chromium.org>
> Datum: 09.03.2020 04:46
> Betreff: [PATCH v2 32/39] 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
> 
>  drivers/misc/irq-uclass.c | 18 +++++++-
>  include/acpi_device.h     | 27 +++++++++++
>  include/irq.h             | 41 +++++++++++++++++
>  lib/acpi/acpi_device.c    | 94 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 178 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
> index 61aa10e465..b4a8b7b429 100644
> --- a/drivers/misc/irq-uclass.c
> +++ b/drivers/misc/irq-uclass.c
> @@ -153,8 +153,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 is this code dropped?

>     ops = irq_get_ops(dev);
> 
>     irq->dev = dev;
> @@ -176,6 +174,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/include/acpi_device.h b/include/acpi_device.h
> index acd26c0f54..50ba9b66aa 100644
> --- a/include/acpi_device.h
> +++ b/include/acpi_device.h
> @@ -545,6 +545,33 @@ int acpi_dp_write(struct acpi_ctx *ctx, struct 
> acpi_dp *table);
>  int acpi_device_write_gpio_desc(struct acpi_ctx *ctx,
>              const struct gpio_desc *desc);
> 
> +/**
> + * acpi_device_write_interrupt_irq() - Write an interrupt to ACPI
> + *
> + * This creates an interrupt descriptor for an interrupt, including
> information
> + * ACPI needs to use it.
> + *
> + * @req_irq: Interrupt to write
> + * @return 0 if OK, -ve on error
> + */
> +int acpi_device_write_interrupt_irq(struct acpi_ctx *ctx,
> +                const struct irq *req_irq);
> +
> +/**
> + * acpi_device_write_interrupt_or_gpio() - Write interrupt or GPIO to 
ACPI
> + *
> + * This reads the an interrupt from the device tree, if available. If 
not it

typo: "the an"

The description of what this function should do is rather vague.
At least I'm not sure how it is meant to work.

> + * reads the first GPIO with the name @prop.
> + *
> + * If an interrupt is found, that is written to ACPI. If not, but an 
GPIO is
> + * found, that is written.
> + *
> + * @return 0 if OK, -ve if neither an interrupt nor a GPIO could 
befound, or
> + * some other error occurred
> + */
> +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, including
>   * information ACPI needs to use it.
> diff --git a/include/irq.h b/include/irq.h
> index d4948e6dc4..8527e4dd79 100644
> --- a/include/irq.h
> +++ b/include/irq.h
> @@ -8,6 +8,7 @@
>  #ifndef __irq_H
>  #define __irq_H
> 
> +struct acpi_irq;
>  struct ofnode_phandle_args;
> 
>  /*
> @@ -26,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;
>  };
> 
>  /**
> @@ -121,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
>   *
> @@ -225,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/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
> index adc32f1216..aa5edfe807 100644
> --- a/lib/acpi/acpi_device.c
> +++ b/lib/acpi/acpi_device.c
> @@ -154,6 +154,58 @@ int acpi_device_status(const struct udevice *dev)
>     return ACPI_STATUS_DEVICE_ALL_ON;
>  }
> 
> +/* ACPI 6.1 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 || !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;
> +}
> +
>  /* ACPI 6.1 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)
>  {
> @@ -304,6 +356,48 @@ int acpi_device_write_gpio_desc(struct acpi_ctx 
*ctx,
>     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;
> +}
> +
> +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);
> +   }

Both code paths set the index value hardcoded to 0.
Why is that? Would other indices not make sense?

> +
> +   return 0;
> +}
> +
>  /* ACPI 6.1 section 6.4.3.8.2.1 - I2cSerialBus() */
>  static void acpi_device_write_i2c(struct acpi_ctx *ctx,
>                const struct acpi_i2c *i2c)
> -- 
> 2.25.1.481.gfbce0eb801-goog
> 

regards, Wolfgang

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

* Antwort: [PATCH v2 32/39] irq: Add a method to convert an interrupt to ACPI
  2020-03-09  3:44 ` [PATCH v2 32/39] irq: Add a method to convert an interrupt " Simon Glass
  2020-03-18 16:17   ` Antwort: " Wolfgang Wallner
@ 2020-03-18 16:20   ` Wolfgang Wallner
  2020-03-19 16:18     ` Simon Glass
  1 sibling, 1 reply; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-18 16:20 UTC (permalink / raw)
  To: u-boot

Hi Simon,

I'm resending this mail, as my email client has broken the formating
in the first attempt, sorry.


"Simon Glass" <sjg@chromium.org> schrieb am 09.03.2020 04:44:56:

> Von: "Simon Glass" <sjg@chromium.org>
> An: "U-Boot Mailing List" <u-boot@lists.denx.de>, 
> Kopie: "Bin Meng" <bmeng.cn@gmail.com>, "Wolfgang Wallner" 
> <wolfgang.wallner@br-automation.com>, "Andy Shevchenko" 
> <andriy.shevchenko@linux.intel.com>, "Simon Glass" <sjg@chromium.org>
> Datum: 09.03.2020 04:46
> Betreff: [PATCH v2 32/39] 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
> 
>  drivers/misc/irq-uclass.c | 18 +++++++-
>  include/acpi_device.h     | 27 +++++++++++
>  include/irq.h             | 41 +++++++++++++++++
>  lib/acpi/acpi_device.c    | 94 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 178 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
> index 61aa10e465..b4a8b7b429 100644
> --- a/drivers/misc/irq-uclass.c
> +++ b/drivers/misc/irq-uclass.c
> @@ -153,8 +153,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 is this code dropped?

>     ops = irq_get_ops(dev);
> 
>     irq->dev = dev;
> @@ -176,6 +174,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/include/acpi_device.h b/include/acpi_device.h
> index acd26c0f54..50ba9b66aa 100644
> --- a/include/acpi_device.h
> +++ b/include/acpi_device.h
> @@ -545,6 +545,33 @@ int acpi_dp_write(struct acpi_ctx *ctx, struct 
> acpi_dp *table);
>  int acpi_device_write_gpio_desc(struct acpi_ctx *ctx,
>              const struct gpio_desc *desc);
> 
> +/**
> + * acpi_device_write_interrupt_irq() - Write an interrupt to ACPI
> + *
> + * This creates an interrupt descriptor for an interrupt, including
> information
> + * ACPI needs to use it.
> + *
> + * @req_irq: Interrupt to write
> + * @return 0 if OK, -ve on error
> + */
> +int acpi_device_write_interrupt_irq(struct acpi_ctx *ctx,
> +                const struct irq *req_irq);
> +
> +/**
> + * acpi_device_write_interrupt_or_gpio() - Write interrupt or GPIO to 
ACPI
> + *
> + * This reads the an interrupt from the device tree, if available. If 
not it

typo: "the an"

The description of what this function should do is rather vague.
At least I'm not sure how it is meant to work.

> + * reads the first GPIO with the name @prop.
> + *
> + * If an interrupt is found, that is written to ACPI. If not, but an 
GPIO is
> + * found, that is written.
> + *
> + * @return 0 if OK, -ve if neither an interrupt nor a GPIO could 
befound, or
> + * some other error occurred
> + */
> +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, including
>   * information ACPI needs to use it.
> diff --git a/include/irq.h b/include/irq.h
> index d4948e6dc4..8527e4dd79 100644
> --- a/include/irq.h
> +++ b/include/irq.h
> @@ -8,6 +8,7 @@
>  #ifndef __irq_H
>  #define __irq_H
> 
> +struct acpi_irq;
>  struct ofnode_phandle_args;
> 
>  /*
> @@ -26,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;
>  };
> 
>  /**
> @@ -121,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
>   *
> @@ -225,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/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
> index adc32f1216..aa5edfe807 100644
> --- a/lib/acpi/acpi_device.c
> +++ b/lib/acpi/acpi_device.c
> @@ -154,6 +154,58 @@ int acpi_device_status(const struct udevice *dev)
>     return ACPI_STATUS_DEVICE_ALL_ON;
>  }
> 
> +/* ACPI 6.1 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 || !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;
> +}
> +
>  /* ACPI 6.1 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)
>  {
> @@ -304,6 +356,48 @@ int acpi_device_write_gpio_desc(struct acpi_ctx 
*ctx,
>     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;
> +}
> +
> +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);
> +   }

Both code paths set the index value hardcoded to 0.
Why is that? Would other indices not make sense?

> +
> +   return 0;
> +}
> +
>  /* ACPI 6.1 section 6.4.3.8.2.1 - I2cSerialBus() */
>  static void acpi_device_write_i2c(struct acpi_ctx *ctx,
>                const struct acpi_i2c *i2c)
> -- 
> 2.25.1.481.gfbce0eb801-goog
> 

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

* Antwort: [PATCH v2 33/39] acpi: Add support for SSDT generation
  2020-03-09  3:44 ` [PATCH v2 33/39] acpi: Add support for SSDT generation Simon Glass
@ 2020-03-18 16:48   ` Wolfgang Wallner
  2020-03-19  7:39   ` Wolfgang Wallner
  1 sibling, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-18 16:48 UTC (permalink / raw)
  To: u-boot

Hi Simon,

"Simon Glass" <sjg@chromium.org> schrieb am 09.03.2020 04:44:57:

> Betreff: [PATCH v2 33/39] acpi: Add support for SSDT generation
> 
> Some devices need to generate code for the Secondary System Descriptor
> Table (SSDT). Add a method to handle this.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v2:
> - Switch parameter order of _acpi_fill_ssdt() and make it static
> 
>  arch/sandbox/dts/test.dts |  2 ++
>  drivers/core/acpi.c       | 14 +++++++++++++
>  include/dm/acpi.h         | 23 ++++++++++++++++++++++
>  test/dm/acpi.c            | 41 ++++++++++++++++++++++++++++++++++++++-
>  4 files changed, 79 insertions(+), 1 deletion(-)
> 

[snip]

> diff --git a/test/dm/acpi.c b/test/dm/acpi.c
> index feb380b26c..305d8395ff 100644
> --- a/test/dm/acpi.c
> +++ b/test/dm/acpi.c
> @@ -7,6 +7,7 @@

[snip]

>  static const struct udevice_id testacpi_ids[] = {
> @@ -313,3 +325,30 @@ 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_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';   /* sentinal */

nit: 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.25.1.481.gfbce0eb801-goog
> 

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

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

* Antwort: [PATCH v2 33/39] acpi: Add support for SSDT generation
  2020-03-09  3:44 ` [PATCH v2 33/39] acpi: Add support for SSDT generation Simon Glass
  2020-03-18 16:48   ` Antwort: " Wolfgang Wallner
@ 2020-03-19  7:39   ` Wolfgang Wallner
  1 sibling, 0 replies; 86+ messages in thread
From: Wolfgang Wallner @ 2020-03-19  7:39 UTC (permalink / raw)
  To: u-boot

Hi Simon,

during the review of a later patch I spotted a typo in this patch
that I missed initially, see below.

"Simon Glass" <sjg@chromium.org> schrieb am 09.03.2020 04:44:57:

> Betreff: [PATCH v2 33/39] acpi: Add support for SSDT generation
> 
> Some devices need to generate code for the Secondary System Descriptor
> Table (SSDT). Add a method to handle this.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>

[snip]

> diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c
> index 10bac38c1d..d2f6a9a9d1 100644
> --- a/drivers/core/acpi.c
> +++ b/drivers/core/acpi.c
> @@ -17,6 +17,7 @@
>  /* Type of method to call */
>  enum method_t {
>     METHOD_WRITE_TABLES,
> +   METHOD_FILL_SDDT,

typo: this should be METHOD_FILL_SSDT

>  };
> 

regards, Wolfgang

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

* [PATCH v2 32/39] irq: Add a method to convert an interrupt to ACPI
  2020-03-18 16:20   ` Wolfgang Wallner
@ 2020-03-19 16:18     ` Simon Glass
  0 siblings, 0 replies; 86+ messages in thread
From: Simon Glass @ 2020-03-19 16:18 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

On Wed, 18 Mar 2020 at 10:20, Wolfgang Wallner
<wolfgang.wallner@br-automation.com> wrote:
>
> Hi Simon,
>
> I'm resending this mail, as my email client has broken the formating
> in the first attempt, sorry.
>
>
> "Simon Glass" <sjg@chromium.org> schrieb am 09.03.2020 04:44:56:
>
> > Von: "Simon Glass" <sjg@chromium.org>
> > An: "U-Boot Mailing List" <u-boot@lists.denx.de>,
> > Kopie: "Bin Meng" <bmeng.cn@gmail.com>, "Wolfgang Wallner"
> > <wolfgang.wallner@br-automation.com>, "Andy Shevchenko"
> > <andriy.shevchenko@linux.intel.com>, "Simon Glass" <sjg@chromium.org>
> > Datum: 09.03.2020 04:46
> > Betreff: [PATCH v2 32/39] 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
> >
> >  drivers/misc/irq-uclass.c | 18 +++++++-
> >  include/acpi_device.h     | 27 +++++++++++
> >  include/irq.h             | 41 +++++++++++++++++
> >  lib/acpi/acpi_device.c    | 94 +++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 178 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
> > index 61aa10e465..b4a8b7b429 100644
> > --- a/drivers/misc/irq-uclass.c
> > +++ b/drivers/misc/irq-uclass.c
> > @@ -153,8 +153,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 is this code dropped?

We don't support passing NULL to this function. It would be invalid
and there is no point in adding code to check for it.

[..]

> > +/**
> > + * acpi_device_write_interrupt_or_gpio() - Write interrupt or GPIO to
> ACPI
> > + *
> > + * This reads the an interrupt from the device tree, if available. If
> not it
>
> typo: "the an"
>
> The description of what this function should do is rather vague.
> At least I'm not sure how it is meant to work.

OK I will beef it up.

[..]

> > +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);
> > +   }
>
> Both code paths set the index value hardcoded to 0.
> Why is that? Would other indices not make sense?

We only support a single interrupt / GPIO at present. We could expand
this but there is no use case for that yet.

Regards,
Simon

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

end of thread, other threads:[~2020-03-19 16:18 UTC | newest]

Thread overview: 86+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-09  3:44 [PATCH v2 00/39] dm: Add programmatic generation of ACPI tables (part A) Simon Glass
2020-03-09  3:44 ` [PATCH v2 01/39] cpu: Support querying the address width Simon Glass
2020-03-09  3:44 ` [PATCH v2 02/39] spi: Add SPI mode enums Simon Glass
2020-03-09  7:41   ` Andy Shevchenko
2020-03-09  3:44 ` [PATCH v2 03/39] tpm: cr50: Release locality on exit Simon Glass
2020-03-09  3:44 ` [PATCH v2 04/39] tpm: cr50: Add a comment for cr50_priv Simon Glass
2020-03-09  3:44 ` [PATCH v2 05/39] tpm: cr50: Use the correct GPIO binding Simon Glass
2020-03-09  3:44 ` [PATCH v2 06/39] tpm: Don't cleanup unless an error happens Simon Glass
2020-03-09  3:44 ` [PATCH v2 07/39] dm: pci: Allow disabling auto-config for a device Simon Glass
2020-03-09  7:43   ` Andy Shevchenko
2020-03-09  3:44 ` [PATCH v2 08/39] x86: Correct wording of coreboot source code Simon Glass
2020-03-09  7:44   ` Andy Shevchenko
2020-03-10 23:22     ` Simon Glass
2020-03-09  3:44 ` [PATCH v2 09/39] x86: apl: Move p2sb ofdata reading to the correct method Simon Glass
2020-03-10 14:39   ` Andy Shevchenko
2020-03-11 12:17     ` Simon Glass
2020-03-11 13:06       ` Andy Shevchenko
2020-03-09  3:44 ` [PATCH v2 10/39] pci: Adjust dm_pci_read_bar32() to return errors correctly Simon Glass
2020-03-09  3:44 ` [PATCH v2 11/39] x86: apl: Add Global NVS table header Simon Glass
2020-03-09  3:44 ` [PATCH v2 12/39] dm: core: Add basic ACPI support Simon Glass
2020-03-10 14:46   ` Andy Shevchenko
2020-03-11 12:17     ` Simon Glass
2020-03-09  3:44 ` [PATCH v2 13/39] acpi: Add a binding for ACPI settings in the device tree Simon Glass
2020-03-10 14:50   ` Andy Shevchenko
2020-03-12  3:22     ` Simon Glass
2020-03-09  3:44 ` [PATCH v2 14/39] acpi: Add a simple sandbox test Simon Glass
2020-03-09  3:44 ` [PATCH v2 15/39] x86: Move acpi_table header to main include/ directory Simon Glass
2020-03-09  3:44 ` [PATCH v2 16/39] acpi: Add an __ACPI__ preprocessor symbol Simon Glass
2020-03-09  3:44 ` [PATCH v2 17/39] acpi: Add a central location for table version numbers Simon Glass
2020-03-09  3:44 ` [PATCH v2 18/39] acpi: Add support for DMAR Simon Glass
2020-03-09  3:44 ` [PATCH v2 19/39] acpi: Move acpi_fill_header() to generic code Simon Glass
2020-03-09  3:44 ` [PATCH v2 20/39] acpi: Add a method to write tables for a device Simon Glass
2020-03-09  3:44 ` [PATCH v2 21/39] acpi: Convert part of acpi_table to use acpi_ctx Simon Glass
2020-03-09  3:44 ` [PATCH v2 22/39] x86: Allow devices to write ACPI tables Simon Glass
2020-03-09  3:44 ` [PATCH v2 23/39] acpi: Drop code for missing XSDT from acpi_write_rsdp() Simon Glass
2020-03-09  3:44 ` [PATCH v2 24/39] acpi: Move acpi_add_table() to generic code Simon Glass
2020-03-09  3:44 ` [PATCH v2 25/39] acpi: Put table-setup code in its own function Simon Glass
2020-03-09  3:44 ` [PATCH v2 26/39] acpi: Move the xsdt pointer to acpi_ctx Simon Glass
2020-03-09  3:44 ` [PATCH v2 27/39] acpi: Add an acpi command Simon Glass
2020-03-09  3:44 ` [PATCH v2 28/39] acpi: Add some tables required by the generation code Simon Glass
2020-03-09  3:44 ` [PATCH v2 29/39] acpi: Add generation code for devices Simon Glass
2020-03-09  3:44 ` [PATCH v2 30/39] acpi: Add functions to generate ACPI code Simon Glass
2020-03-09  3:44 ` [PATCH v2 31/39] gpio: Add a method to convert a GPIO to ACPI Simon Glass
2020-03-09  3:44 ` [PATCH v2 32/39] irq: Add a method to convert an interrupt " Simon Glass
2020-03-18 16:17   ` Antwort: " Wolfgang Wallner
2020-03-18 16:20   ` Wolfgang Wallner
2020-03-19 16:18     ` Simon Glass
2020-03-09  3:44 ` [PATCH v2 33/39] acpi: Add support for SSDT generation Simon Glass
2020-03-18 16:48   ` Antwort: " Wolfgang Wallner
2020-03-19  7:39   ` Wolfgang Wallner
2020-03-09  3:44 ` [PATCH v2 34/39] x86: acpi: Move MADT up a bit Simon Glass
2020-03-09  3:44 ` [PATCH v2 35/39] acpi: Record the items added to SSDT Simon Glass
2020-03-09  3:45 ` [PATCH v2 36/39] acpi: Support ordering SSDT data by device Simon Glass
2020-03-09  3:45 ` [PATCH v2 37/39] x86: Allow devices to write an SSDT Simon Glass
2020-03-09  3:45 ` [PATCH v2 38/39] acpi: Add support for DSDT generation Simon Glass
2020-03-09  3:45 ` [PATCH v2 39/39] x86: Allow devices to write to DSDT Simon Glass
2020-03-09  7:38 ` Antwort: [PATCH v2 02/39] spi: Add SPI mode enums Wolfgang Wallner
2020-03-09  7:38 ` Antwort: [PATCH v2 08/39] x86: Correct wording of coreboot source code Wolfgang Wallner
2020-03-09  7:38 ` Antwort: [PATCH v2 10/39] pci: Adjust dm_pci_read_bar32() to return errors correctly Wolfgang Wallner
2020-03-09  7:38 ` Antwort: [PATCH v2 11/39] x86: apl: Add Global NVS table header Wolfgang Wallner
2020-03-09  9:07 ` Antwort: [PATCH v2 12/39] dm: core: Add basic ACPI support Wolfgang Wallner
2020-03-10  9:15 ` Antwort: [PATCH v2 13/39] acpi: Add a binding for ACPI settings in the device tree Wolfgang Wallner
2020-03-12  3:24   ` Simon Glass
2020-03-12 12:44   ` Antwort: " Wolfgang Wallner
2020-03-13  0:36     ` Simon Glass
2020-03-10  9:16 ` Antwort: [PATCH v2 15/39] x86: Move acpi_table header to main include/ directory Wolfgang Wallner
2020-03-10  9:17 ` Antwort: [PATCH v2 16/39] acpi: Add an __ACPI__ preprocessor symbol Wolfgang Wallner
2020-03-10  9:26 ` Antwort: [PATCH v2 17/39] acpi: Add a central location for table version numbers Wolfgang Wallner
2020-03-12  3:22   ` Simon Glass
2020-03-10 12:32 ` Antwort: [PATCH v2 18/39] acpi: Add support for DMAR Wolfgang Wallner
2020-03-10 12:33 ` Antwort: [PATCH v2 19/39] acpi: Move acpi_fill_header() to generic code Wolfgang Wallner
2020-03-10 12:53 ` Antwort: [PATCH v2 14/39] acpi: Add a simple sandbox test Wolfgang Wallner
2020-03-11  9:04 ` Antwort: [PATCH v2 19/39] acpi: Move acpi_fill_header() to generic code Wolfgang Wallner
2020-03-11 11:36 ` Antwort: [PATCH v2 20/39] acpi: Add a method to write tables for a device Wolfgang Wallner
2020-03-11 11:37 ` Antwort: [PATCH v2 22/39] x86: Allow devices to write ACPI tables Wolfgang Wallner
2020-03-11 12:58 ` Antwort: [PATCH v2 21/39] acpi: Convert part of acpi_table to use acpi_ctx Wolfgang Wallner
2020-03-12  3:23   ` Simon Glass
2020-03-12 13:03   ` Antwort: " Wolfgang Wallner
2020-03-11 13:43 ` Antwort: [PATCH v2 24/39] acpi: Move acpi_add_table() to generic code Wolfgang Wallner
2020-03-11 14:33 ` Antwort: [PATCH v2 25/39] acpi: Put table-setup code in its own function Wolfgang Wallner
2020-03-11 14:34 ` Antwort: [PATCH v2 23/39] acpi: Drop code for missing XSDT from acpi_write_rsdp() Wolfgang Wallner
2020-03-11 14:57 ` Antwort: [PATCH v2 26/39] acpi: Move the xsdt pointer to acpi_ctx Wolfgang Wallner
2020-03-12 14:30 ` Antwort: [PATCH v2 27/39] acpi: Add an acpi command Wolfgang Wallner
2020-03-13  9:55 ` Antwort: [PATCH v2 30/39] acpi: Add functions to generate ACPI code Wolfgang Wallner
2020-03-14 20:34   ` Simon Glass
2020-03-13 11:16 ` Antwort: [PATCH v2 31/39] gpio: Add a method to convert a GPIO to ACPI 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.