All of lore.kernel.org
 help / color / mirror / Atom feed
From: Simon Glass <sjg@chromium.org>
To: u-boot@lists.denx.de
Subject: [PATCH v2 29/39] acpi: Add generation code for devices
Date: Sun,  8 Mar 2020 21:44:53 -0600	[thread overview]
Message-ID: <20200308214442.v2.29.I06704ecd3c988c7826720a7f447e0388bfe85808@changeid> (raw)
In-Reply-To: <20200309034504.149659-1-sjg@chromium.org>

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

  parent reply	other threads:[~2020-03-09  3:44 UTC|newest]

Thread overview: 86+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 ` Simon Glass [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200308214442.v2.29.I06704ecd3c988c7826720a7f447e0388bfe85808@changeid \
    --to=sjg@chromium.org \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.