aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2020-07-17 08:04:48 -0400
committerTom Rini <trini@konsulko.com>2020-07-17 08:04:48 -0400
commit7c3cc6f106ed1ca13b0ff6eea9f8e1473240aef3 (patch)
tree8c67a8ed3ab24b1421161960103d8614cbde659a /drivers
parent42e7659db0ac7089d3a2f80ee1c3b8eb64d84706 (diff)
parentd40d2c570600396b54dece16429727ef50cfeef0 (diff)
downloadu-boot-7c3cc6f106ed1ca13b0ff6eea9f8e1473240aef3.zip
u-boot-7c3cc6f106ed1ca13b0ff6eea9f8e1473240aef3.tar.gz
u-boot-7c3cc6f106ed1ca13b0ff6eea9f8e1473240aef3.tar.bz2
Merge https://gitlab.denx.de/u-boot/custodians/u-boot-x86
- New timer API to allow delays with a 32-bit microsecond timer - Add dynamic ACPI structs (DSDT/SSDT) generations to the DM core - x86: Enable ACPI table generation by default - x86: Enable the copy framebuffer on Coral - x86: A few fixes to FSP2 with ApolloLake - x86: Drop setup_pcat_compatibility() - x86: Primary-to-Sideband Bus minor fixes
Diffstat (limited to 'drivers')
-rw-r--r--drivers/core/Kconfig2
-rw-r--r--drivers/core/acpi.c263
-rw-r--r--drivers/core/root.c13
-rw-r--r--drivers/gpio/gpio-uclass.c22
-rw-r--r--drivers/gpio/intel_gpio.c49
-rw-r--r--drivers/gpio/sandbox.c77
-rw-r--r--drivers/i2c/designware_i2c.c36
-rw-r--r--drivers/i2c/designware_i2c.h15
-rw-r--r--drivers/i2c/designware_i2c_pci.c96
-rw-r--r--drivers/i2c/i2c-uclass.c4
-rw-r--r--drivers/i2c/sandbox_i2c.c1
-rw-r--r--drivers/misc/Kconfig12
-rw-r--r--drivers/misc/irq-uclass.c20
-rw-r--r--drivers/misc/irq_sandbox.c16
-rw-r--r--drivers/misc/p2sb-uclass.c26
-rw-r--r--drivers/mmc/pci_mmc.c78
-rw-r--r--drivers/pinctrl/intel/Kconfig12
-rw-r--r--drivers/pinctrl/intel/pinctrl.c21
-rw-r--r--drivers/pinctrl/intel/pinctrl_apl.c4
-rw-r--r--drivers/power/acpi_pmc/acpi-pmc-uclass.c9
-rw-r--r--drivers/rtc/sandbox_rtc.c13
-rw-r--r--drivers/sound/Kconfig18
-rw-r--r--drivers/sound/Makefile2
-rw-r--r--drivers/sound/da7219.c190
-rw-r--r--drivers/sound/max98357a.c161
-rw-r--r--drivers/spi/sandbox_spi.c1
26 files changed, 1107 insertions, 54 deletions
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index a594899..00d1d80 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -270,7 +270,7 @@ config DM_DEV_READ_INLINE
config ACPIGEN
bool "Support ACPI table generation in driver model"
- default y if SANDBOX || GENERATE_ACPI_TABLE
+ default y if SANDBOX || (GENERATE_ACPI_TABLE && !QEMU)
help
This option enables generation of ACPI tables using driver-model
devices. It adds a new operation struct to each driver, to support
diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c
index 8ae6157..cdbc2c5 100644
--- a/drivers/core/acpi.c
+++ b/drivers/core/acpi.c
@@ -11,18 +11,51 @@
#include <common.h>
#include <dm.h>
#include <log.h>
+#include <malloc.h>
+#include <acpi/acpi_device.h>
#include <dm/acpi.h>
#include <dm/device-internal.h>
#include <dm/root.h>
+#define MAX_ACPI_ITEMS 100
+
+/* Type of table that we collected */
+enum gen_type_t {
+ TYPE_NONE,
+ TYPE_SSDT,
+ TYPE_DSDT,
+};
+
/* Type of method to call */
enum method_t {
METHOD_WRITE_TABLES,
+ METHOD_FILL_SSDT,
+ METHOD_INJECT_DSDT,
+ METHOD_SETUP_NHLT,
};
/* Prototype for all methods */
typedef int (*acpi_method)(const struct udevice *dev, struct acpi_ctx *ctx);
+/**
+ * struct acpi_item - Holds info about ACPI data generated by a driver method
+ *
+ * @dev: Device that generated this data
+ * @type: Table type it refers to
+ * @buf: Buffer containing the data
+ * @size: Size of the data in bytes
+ */
+struct acpi_item {
+ struct udevice *dev;
+ enum gen_type_t type;
+ char *buf;
+ int size;
+};
+
+/* List of ACPI items collected */
+static struct acpi_item acpi_item[MAX_ACPI_ITEMS];
+static int item_count;
+
int acpi_copy_name(char *out_name, const char *name)
{
strncpy(out_name, name, ACPI_NAME_LEN);
@@ -34,12 +67,173 @@ int acpi_copy_name(char *out_name, const char *name)
int acpi_get_name(const struct udevice *dev, char *out_name)
{
struct acpi_ops *aops;
+ const char *name;
+ int ret;
aops = device_get_acpi_ops(dev);
if (aops && aops->get_name)
return aops->get_name(dev, out_name);
+ name = dev_read_string(dev, "acpi,name");
+ if (name)
+ return acpi_copy_name(out_name, name);
+ ret = acpi_device_infer_name(dev, out_name);
+ if (ret)
+ return log_msg_ret("dev", ret);
+
+ return 0;
+}
+
+int acpi_get_path(const struct udevice *dev, char *out_path, int maxlen)
+{
+ const char *path;
+ int ret;
- return -ENOSYS;
+ path = dev_read_string(dev, "acpi,path");
+ if (path) {
+ if (strlen(path) >= maxlen)
+ return -E2BIG;
+ strcpy(out_path, path);
+ return 0;
+ }
+ ret = acpi_device_path(dev, out_path, maxlen);
+ if (ret)
+ return log_msg_ret("dev", ret);
+
+ return 0;
+}
+
+/**
+ * acpi_add_item() - Add a new item to the list of data collected
+ *
+ * @ctx: ACPI context
+ * @dev: Device that generated the data
+ * @type: Table type it refers to
+ * @start: The start of the data (the end is obtained from ctx->current)
+ * @return 0 if OK, -ENOSPC if too many items, -ENOMEM if out of memory
+ */
+static int acpi_add_item(struct acpi_ctx *ctx, struct udevice *dev,
+ enum gen_type_t type, void *start)
+{
+ struct acpi_item *item;
+ void *end = ctx->current;
+
+ if (item_count == MAX_ACPI_ITEMS) {
+ log_err("Too many items\n");
+ return log_msg_ret("mem", -ENOSPC);
+ }
+
+ item = &acpi_item[item_count];
+ item->dev = dev;
+ item->type = type;
+ item->size = end - start;
+ if (!item->size)
+ return 0;
+ item->buf = malloc(item->size);
+ if (!item->buf)
+ return log_msg_ret("mem", -ENOMEM);
+ memcpy(item->buf, start, item->size);
+ item_count++;
+ log_debug("* %s: Added type %d, %p, size %x\n", dev->name, type, start,
+ item->size);
+
+ return 0;
+}
+
+void acpi_dump_items(enum acpi_dump_option option)
+{
+ int i;
+
+ for (i = 0; i < item_count; i++) {
+ struct acpi_item *item = &acpi_item[i];
+
+ printf("dev '%s', type %d, size %x\n", item->dev->name,
+ item->type, item->size);
+ if (option == ACPI_DUMP_CONTENTS) {
+ print_buffer(0, item->buf, 1, item->size, 0);
+ printf("\n");
+ }
+ }
+}
+
+static struct acpi_item *find_acpi_item(const char *devname)
+{
+ int i;
+
+ for (i = 0; i < item_count; i++) {
+ struct acpi_item *item = &acpi_item[i];
+
+ if (!strcmp(devname, item->dev->name))
+ return item;
+ }
+
+ return NULL;
+}
+
+/**
+ * sort_acpi_item_type - Sort the ACPI items into the desired order
+ *
+ * This looks up the ordering in the device tree and then adds each item one by
+ * one into the supplied buffer
+ *
+ * @ctx: ACPI context
+ * @start: Start position to put the sorted items. The items will follow each
+ * other in sorted order
+ * @type: Type of items to sort
+ * @return 0 if OK, -ve on error
+ */
+static int sort_acpi_item_type(struct acpi_ctx *ctx, void *start,
+ enum gen_type_t type)
+{
+ const u32 *order;
+ int size;
+ int count;
+ void *ptr;
+ void *end = ctx->current;
+
+ ptr = start;
+ order = ofnode_read_chosen_prop(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;
+ }
+
+ /*
+ * This algorithm rewrites the context buffer without changing its
+ * length. So there is no need to update ctx-current
+ */
+ count = size / sizeof(u32);
+ while (count--) {
+ struct acpi_item *item;
+ const char *name;
+ ofnode node;
+
+ node = ofnode_get_by_phandle(fdt32_to_cpu(*order++));
+ name = ofnode_get_name(node);
+ item = find_acpi_item(name);
+ if (!item) {
+ log_err("Failed to find item '%s'\n", name);
+ return log_msg_ret("find", -ENOENT);
+ }
+ if (item->type == type) {
+ log_debug(" - add %s\n", item->dev->name);
+ memcpy(ptr, item->buf, item->size);
+ ptr += item->size;
+ }
+ }
+
+ /*
+ * If the sort order is missing an item then the output will be too
+ * small. Report this error since the item needs to be added to the
+ * ordering for the ACPI tables to be complete.
+ */
+ if (ptr != end) {
+ log_warning("*** Missing bytes: ptr=%p, end=%p\n", ptr, end);
+ return -ENXIO;
+ }
+
+ return 0;
}
acpi_method acpi_get_method(struct udevice *dev, enum method_t method)
@@ -51,6 +245,12 @@ acpi_method acpi_get_method(struct udevice *dev, enum method_t method)
switch (method) {
case METHOD_WRITE_TABLES:
return aops->write_tables;
+ case METHOD_FILL_SSDT:
+ return aops->fill_ssdt;
+ case METHOD_INJECT_DSDT:
+ return aops->inject_dsdt;
+ case METHOD_SETUP_NHLT:
+ return aops->setup_nhlt;
}
}
@@ -58,7 +258,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;
@@ -66,6 +266,8 @@ int acpi_recurse_method(struct acpi_ctx *ctx, struct udevice *parent,
func = acpi_get_method(parent, method);
if (func) {
+ void *start = ctx->current;
+
log_debug("\n");
log_debug("- %s %p\n", parent->name, func);
ret = device_ofdata_to_platdata(parent);
@@ -74,9 +276,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);
}
@@ -84,13 +293,59 @@ int acpi_recurse_method(struct acpi_ctx *ctx, struct udevice *parent,
return 0;
}
+int acpi_fill_ssdt(struct acpi_ctx *ctx)
+{
+ void *start = ctx->current;
+ int ret;
+
+ log_debug("Writing SSDT tables\n");
+ item_count = 0;
+ ret = acpi_recurse_method(ctx, dm_root(), METHOD_FILL_SSDT, TYPE_SSDT);
+ log_debug("Writing SSDT finished, err=%d\n", ret);
+ ret = sort_acpi_item_type(ctx, start, TYPE_SSDT);
+ if (ret)
+ return log_msg_ret("build", ret);
+
+ return ret;
+}
+
+int acpi_inject_dsdt(struct acpi_ctx *ctx)
+{
+ void *start = ctx->current;
+ int ret;
+
+ log_debug("Writing DSDT tables\n");
+ item_count = 0;
+ ret = acpi_recurse_method(ctx, dm_root(), METHOD_INJECT_DSDT,
+ TYPE_DSDT);
+ log_debug("Writing DSDT finished, err=%d\n", ret);
+ ret = sort_acpi_item_type(ctx, start, TYPE_DSDT);
+ if (ret)
+ return log_msg_ret("build", ret);
+
+ return ret;
+}
+
int acpi_write_dev_tables(struct acpi_ctx *ctx)
{
int ret;
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;
}
+
+int acpi_setup_nhlt(struct acpi_ctx *ctx, struct nhlt *nhlt)
+{
+ int ret;
+
+ log_debug("Setup NHLT\n");
+ ctx->nhlt = nhlt;
+ ret = acpi_recurse_method(ctx, dm_root(), METHOD_SETUP_NHLT, TYPE_NONE);
+ log_debug("Setup finished, err=%d\n", ret);
+
+ return ret;
+}
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 0de5d7c..0726be6 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -12,6 +12,7 @@
#include <log.h>
#include <malloc.h>
#include <linux/libfdt.h>
+#include <dm/acpi.h>
#include <dm/device.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
@@ -377,10 +378,22 @@ int dm_init_and_scan(bool pre_reloc_only)
return 0;
}
+#ifdef CONFIG_ACPIGEN
+static int root_acpi_get_name(const struct udevice *dev, char *out_name)
+{
+ return acpi_copy_name(out_name, "\\_SB");
+}
+
+struct acpi_ops root_acpi_ops = {
+ .get_name = root_acpi_get_name,
+};
+#endif
+
/* This is the root driver - all drivers are children of this */
U_BOOT_DRIVER(root_driver) = {
.name = "root_driver",
.id = UCLASS_ROOT,
+ ACPI_OPS_PTR(&root_acpi_ops)
};
/* This is the root uclass */
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index ab17fa8..9c53299 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -13,6 +13,7 @@
#include <errno.h>
#include <fdtdec.h>
#include <malloc.h>
+#include <acpi/acpi_device.h>
#include <asm/gpio.h>
#include <dm/device_compat.h>
#include <linux/bug.h>
@@ -855,6 +856,27 @@ 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;
+
+ memset(gpio, '\0', sizeof(*gpio));
+ if (!dm_gpio_is_valid(desc)) {
+ /* Indicate that the GPIO is not valid */
+ gpio->pin_count = 0;
+ gpio->pins[0] = 0;
+ return -EINVAL;
+ }
+
+ ops = gpio_get_ops(desc->dev);
+ if (!ops->get_acpi)
+ return -ENOSYS;
+
+ return ops->get_acpi(desc, gpio);
+}
+#endif
+
int gpio_claim_vector(const int *gpio_num_array, const char *fmt)
{
int i, ret;
diff --git a/drivers/gpio/intel_gpio.c b/drivers/gpio/intel_gpio.c
index 711fea1..6a3a8c4 100644
--- a/drivers/gpio/intel_gpio.c
+++ b/drivers/gpio/intel_gpio.c
@@ -12,6 +12,7 @@
#include <pch.h>
#include <pci.h>
#include <syscon.h>
+#include <acpi/acpi_device.h>
#include <asm/cpu.h>
#include <asm/gpio.h>
#include <asm/intel_pinctrl.h>
@@ -19,12 +20,15 @@
#include <asm/io.h>
#include <asm/pci.h>
#include <asm/arch/gpio.h>
+#include <dm/acpi.h>
#include <dt-bindings/gpio/x86-gpio.h>
static int intel_gpio_direction_input(struct udevice *dev, uint offset)
{
struct udevice *pinctrl = dev_get_parent(dev);
- uint config_offset = intel_pinctrl_get_config_reg_addr(pinctrl, offset);
+ uint config_offset;
+
+ config_offset = intel_pinctrl_get_config_reg_offset(pinctrl, offset);
pcr_clrsetbits32(pinctrl, config_offset,
PAD_CFG0_MODE_MASK | PAD_CFG0_TX_STATE |
@@ -38,7 +42,9 @@ static int intel_gpio_direction_output(struct udevice *dev, uint offset,
int value)
{
struct udevice *pinctrl = dev_get_parent(dev);
- uint config_offset = intel_pinctrl_get_config_reg_addr(pinctrl, offset);
+ uint config_offset;
+
+ config_offset = intel_pinctrl_get_config_reg_offset(pinctrl, offset);
pcr_clrsetbits32(pinctrl, config_offset,
PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE |
@@ -68,10 +74,13 @@ static int intel_gpio_get_value(struct udevice *dev, uint offset)
return 0;
}
-static int intel_gpio_set_value(struct udevice *dev, unsigned offset, int value)
+static int intel_gpio_set_value(struct udevice *dev, unsigned int offset,
+ int value)
{
struct udevice *pinctrl = dev_get_parent(dev);
- uint config_offset = intel_pinctrl_get_config_reg_addr(pinctrl, offset);
+ uint config_offset;
+
+ config_offset = intel_pinctrl_get_config_reg_offset(pinctrl, offset);
pcr_clrsetbits32(pinctrl, config_offset, PAD_CFG0_TX_STATE,
value ? PAD_CFG0_TX_STATE : 0);
@@ -121,6 +130,35 @@ static int intel_gpio_xlate(struct udevice *orig_dev, struct gpio_desc *desc,
return 0;
}
+#if CONFIG_IS_ENABLED(ACPIGEN)
+static int intel_gpio_get_acpi(const struct gpio_desc *desc,
+ struct acpi_gpio *gpio)
+{
+ struct udevice *pinctrl;
+ int ret;
+
+ if (!dm_gpio_is_valid(desc))
+ return -ENOENT;
+ pinctrl = dev_get_parent(desc->dev);
+
+ memset(gpio, '\0', sizeof(*gpio));
+
+ gpio->type = ACPI_GPIO_TYPE_IO;
+ gpio->pull = ACPI_GPIO_PULL_DEFAULT;
+ gpio->io_restrict = ACPI_GPIO_IO_RESTRICT_OUTPUT;
+ gpio->polarity = ACPI_GPIO_ACTIVE_HIGH;
+ gpio->pin_count = 1;
+ gpio->pins[0] = intel_pinctrl_get_acpi_pin(pinctrl, desc->offset);
+ gpio->pin0_addr = intel_pinctrl_get_config_reg_addr(pinctrl,
+ desc->offset);
+ ret = acpi_get_path(pinctrl, gpio->resource, sizeof(gpio->resource));
+ if (ret)
+ return log_msg_ret("resource", ret);
+
+ return 0;
+}
+#endif
+
static int intel_gpio_probe(struct udevice *dev)
{
return 0;
@@ -145,6 +183,9 @@ static const struct dm_gpio_ops gpio_intel_ops = {
.set_value = intel_gpio_set_value,
.get_function = intel_gpio_get_function,
.xlate = intel_gpio_xlate,
+#if CONFIG_IS_ENABLED(ACPIGEN)
+ .get_acpi = intel_gpio_get_acpi,
+#endif
};
static const struct udevice_id intel_intel_gpio_ids[] = {
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c
index b9a1d65..c2f8047 100644
--- a/drivers/gpio/sandbox.c
+++ b/drivers/gpio/sandbox.c
@@ -8,7 +8,9 @@
#include <fdtdec.h>
#include <log.h>
#include <malloc.h>
+#include <acpi/acpi_device.h>
#include <asm/gpio.h>
+#include <dm/acpi.h>
#include <dm/device_compat.h>
#include <dm/lists.h>
#include <dm/of.h>
@@ -197,6 +199,63 @@ static int sb_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
return 0;
}
+#if CONFIG_IS_ENABLED(ACPIGEN)
+static int sb_gpio_get_acpi(const struct gpio_desc *desc,
+ struct acpi_gpio *gpio)
+{
+ int ret;
+
+ /* Note that gpio_get_acpi() zeroes *gpio before calling here */
+ gpio->pin_count = 1;
+ gpio->pins[0] = desc->offset;
+ ret = acpi_device_scope(desc->dev, gpio->resource,
+ sizeof(gpio->resource));
+ if (ret)
+ return log_ret(ret);
+
+ /* All of these values are just used for testing */
+ if (desc->flags & GPIOD_ACTIVE_LOW) {
+ gpio->pin0_addr = 0x80012 + desc->offset;
+ gpio->type = ACPI_GPIO_TYPE_INTERRUPT;
+ gpio->pull = ACPI_GPIO_PULL_DOWN;
+ gpio->interrupt_debounce_timeout = 4321;
+
+ /* We use the GpioInt part */
+ gpio->irq.pin = desc->offset;
+ gpio->irq.polarity = ACPI_IRQ_ACTIVE_BOTH;
+ gpio->irq.shared = ACPI_IRQ_SHARED;
+ gpio->irq.wake = ACPI_IRQ_WAKE;
+
+ /* The GpioIo part is only used for testing */
+ gpio->polarity = ACPI_GPIO_ACTIVE_LOW;
+ } else {
+ gpio->pin0_addr = 0xc00dc + desc->offset;
+ gpio->type = ACPI_GPIO_TYPE_IO;
+ gpio->pull = ACPI_GPIO_PULL_UP;
+ gpio->interrupt_debounce_timeout = 0;
+
+ /* The GpioInt part is not used */
+
+ /* We use the GpioIo part */
+ gpio->output_drive_strength = 1234;
+ gpio->io_shared = true;
+ gpio->io_restrict = ACPI_GPIO_IO_RESTRICT_INPUT;
+ gpio->polarity = 0;
+ }
+
+ return 0;
+}
+
+static int sb_gpio_get_name(const struct udevice *dev, char *out_name)
+{
+ return acpi_copy_name(out_name, "GPIO");
+}
+
+struct acpi_ops gpio_sandbox_acpi_ops = {
+ .get_name = sb_gpio_get_name,
+};
+#endif /* ACPIGEN */
+
static const struct dm_gpio_ops gpio_sandbox_ops = {
.direction_input = sb_gpio_direction_input,
.direction_output = sb_gpio_direction_output,
@@ -206,6 +265,9 @@ static const struct dm_gpio_ops gpio_sandbox_ops = {
.xlate = sb_gpio_xlate,
.set_dir_flags = sb_gpio_set_dir_flags,
.get_dir_flags = sb_gpio_get_dir_flags,
+#if CONFIG_IS_ENABLED(ACPIGEN)
+ .get_acpi = sb_gpio_get_acpi,
+#endif
};
static int sandbox_gpio_ofdata_to_platdata(struct udevice *dev)
@@ -252,6 +314,7 @@ U_BOOT_DRIVER(sandbox_gpio) = {
.probe = gpio_sandbox_probe,
.remove = gpio_sandbox_remove,
.ops = &gpio_sandbox_ops,
+ ACPI_OPS_PTR(&gpio_sandbox_acpi_ops)
};
U_BOOT_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias)
@@ -421,6 +484,13 @@ static int sb_pinctrl_get_pin_muxing(struct udevice *dev,
return 0;
}
+#if CONFIG_IS_ENABLED(ACPIGEN)
+static int sb_pinctrl_get_name(const struct udevice *dev, char *out_name)
+{
+ return acpi_copy_name(out_name, "PINC");
+}
+#endif
+
static int sandbox_pinctrl_probe(struct udevice *dev)
{
struct sb_pinctrl_priv *priv = dev_get_priv(dev);
@@ -436,6 +506,12 @@ static struct pinctrl_ops sandbox_pinctrl_gpio_ops = {
.get_pin_muxing = sb_pinctrl_get_pin_muxing,
};
+#if CONFIG_IS_ENABLED(ACPIGEN)
+struct acpi_ops pinctrl_sandbox_acpi_ops = {
+ .get_name = sb_pinctrl_get_name,
+};
+#endif
+
static const struct udevice_id sandbox_pinctrl_gpio_match[] = {
{ .compatible = "sandbox,pinctrl-gpio" },
{ /* sentinel */ }
@@ -449,4 +525,5 @@ U_BOOT_DRIVER(sandbox_pinctrl_gpio) = {
.bind = dm_scan_fdt_dev,
.probe = sandbox_pinctrl_probe,
.priv_auto_alloc_size = sizeof(struct sb_pinctrl_priv),
+ ACPI_OPS_PTR(&pinctrl_sandbox_acpi_ops)
};
diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c
index 3616e21..cf892c6 100644
--- a/drivers/i2c/designware_i2c.c
+++ b/drivers/i2c/designware_i2c.c
@@ -160,9 +160,9 @@ static int dw_i2c_calc_timing(struct dw_i2c *priv, enum i2c_speed_mode mode,
min_tlow_cnt = calc_counts(ic_clk, info->min_scl_lowtime_ns);
min_thigh_cnt = calc_counts(ic_clk, info->min_scl_hightime_ns);
- debug("dw_i2c: period %d rise %d fall %d tlow %d thigh %d spk %d\n",
- period_cnt, rise_cnt, fall_cnt, min_tlow_cnt, min_thigh_cnt,
- spk_cnt);
+ debug("dw_i2c: mode %d, ic_clk %d, speed %d, period %d rise %d fall %d tlow %d thigh %d spk %d\n",
+ mode, ic_clk, info->speed, period_cnt, rise_cnt, fall_cnt,
+ min_tlow_cnt, min_thigh_cnt, spk_cnt);
/*
* Back-solve for hcnt and lcnt according to the following equations:
@@ -174,7 +174,7 @@ static int dw_i2c_calc_timing(struct dw_i2c *priv, enum i2c_speed_mode mode,
if (hcnt < 0 || lcnt < 0) {
debug("dw_i2c: bad counts. hcnt = %d lcnt = %d\n", hcnt, lcnt);
- return -EINVAL;
+ return log_msg_ret("counts", -EINVAL);
}
/*
@@ -333,6 +333,32 @@ static int _dw_i2c_set_bus_speed(struct dw_i2c *priv, struct i2c_regs *i2c_base,
/* Restore back i2c now speed set */
if (ena == IC_ENABLE_0B)
dw_i2c_enable(i2c_base, true);
+ if (priv)
+ priv->config = config;
+
+ return 0;
+}
+
+int dw_i2c_gen_speed_config(const struct udevice *dev, int speed_hz,
+ struct dw_i2c_speed_config *config)
+{
+ struct dw_i2c *priv = dev_get_priv(dev);
+ ulong rate;
+ int ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+ rate = clk_get_rate(&priv->clk);
+ if (IS_ERR_VALUE(rate))
+ return log_msg_ret("clk", -EINVAL);
+#else
+ rate = IC_CLK;
+#endif
+
+ ret = calc_bus_speed(priv, priv->regs, speed_hz, rate, config);
+ if (ret)
+ printf("%s: ret=%d\n", __func__, ret);
+ if (ret)
+ return log_msg_ret("calc_bus_speed", ret);
return 0;
}
@@ -713,7 +739,7 @@ static int designware_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
#if CONFIG_IS_ENABLED(CLK)
rate = clk_get_rate(&i2c->clk);
if (IS_ERR_VALUE(rate))
- return -EINVAL;
+ return log_ret(-EINVAL);
#else
rate = IC_CLK;
#endif
diff --git a/drivers/i2c/designware_i2c.h b/drivers/i2c/designware_i2c.h
index dc9a6cc..18acf4e 100644
--- a/drivers/i2c/designware_i2c.h
+++ b/drivers/i2c/designware_i2c.h
@@ -205,6 +205,7 @@ struct dw_i2c {
#if CONFIG_IS_ENABLED(CLK)
struct clk clk;
#endif
+ struct dw_i2c_speed_config config;
};
extern const struct dm_i2c_ops designware_i2c_ops;
@@ -213,4 +214,18 @@ int designware_i2c_probe(struct udevice *bus);
int designware_i2c_remove(struct udevice *dev);
int designware_i2c_ofdata_to_platdata(struct udevice *bus);
+/**
+ * dw_i2c_gen_speed_config() - Calculate config info from requested speed
+ *
+ * Calculate the speed config from the given @speed_hz and return it so that
+ * it can be incorporated in ACPI tables
+ *
+ * @dev: I2C bus to check
+ * @speed_hz: Requested speed in Hz
+ * @config: Returns config to use for that speed
+ * @return 0 if OK, -ve on error
+ */
+int dw_i2c_gen_speed_config(const struct udevice *dev, int speed_hz,
+ struct dw_i2c_speed_config *config);
+
#endif /* __DW_I2C_H_ */
diff --git a/drivers/i2c/designware_i2c_pci.c b/drivers/i2c/designware_i2c_pci.c
index bd34ec0..d0d869c 100644
--- a/drivers/i2c/designware_i2c_pci.c
+++ b/drivers/i2c/designware_i2c_pci.c
@@ -9,7 +9,12 @@
#include <dm.h>
#include <log.h>
#include <spl.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_device.h>
#include <asm/lpss.h>
+#include <dm/acpi.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
#include "designware_i2c.h"
enum {
@@ -87,6 +92,9 @@ static int designware_i2c_pci_bind(struct udevice *dev)
{
char name[20];
+ if (dev_of_valid(dev))
+ return 0;
+
/*
* Create a unique device name for PCI type devices
* ToDo:
@@ -100,13 +108,98 @@ static int designware_i2c_pci_bind(struct udevice *dev)
* be possible. We cannot use static data in drivers since they may be
* used in SPL or before relocation.
*/
- dev->req_seq = gd->arch.dw_i2c_num_cards++;
+ dev->req_seq = uclass_find_next_free_req_seq(UCLASS_I2C);
sprintf(name, "i2c_designware#%u", dev->req_seq);
device_set_name(dev, name);
return 0;
}
+/*
+ * Write ACPI object to describe speed configuration.
+ *
+ * ACPI Object: Name ("xxxx", Package () { scl_lcnt, scl_hcnt, sda_hold }
+ *
+ * SSCN: I2C_SPEED_STANDARD
+ * FMCN: I2C_SPEED_FAST
+ * FPCN: I2C_SPEED_FAST_PLUS
+ * HSCN: I2C_SPEED_HIGH
+ */
+static void dw_i2c_acpi_write_speed_config(struct acpi_ctx *ctx,
+ struct dw_i2c_speed_config *config)
+{
+ switch (config->speed_mode) {
+ case IC_SPEED_MODE_HIGH:
+ acpigen_write_name(ctx, "HSCN");
+ break;
+ case IC_SPEED_MODE_FAST_PLUS:
+ acpigen_write_name(ctx, "FPCN");
+ break;
+ case IC_SPEED_MODE_FAST:
+ acpigen_write_name(ctx, "FMCN");
+ break;
+ case IC_SPEED_MODE_STANDARD:
+ default:
+ acpigen_write_name(ctx, "SSCN");
+ }
+
+ /* Package () { scl_lcnt, scl_hcnt, sda_hold } */
+ acpigen_write_package(ctx, 3);
+ acpigen_write_word(ctx, config->scl_hcnt);
+ acpigen_write_word(ctx, config->scl_lcnt);
+ acpigen_write_dword(ctx, config->sda_hold);
+ acpigen_pop_len(ctx);
+}
+
+/*
+ * Generate I2C timing information into the SSDT for the OS driver to consume,
+ * optionally applying override values provided by the caller.
+ */
+static int dw_i2c_acpi_fill_ssdt(const struct udevice *dev,
+ struct acpi_ctx *ctx)
+{
+ struct dw_i2c_speed_config config;
+ char path[ACPI_PATH_MAX];
+ u32 speeds[4];
+ uint speed;
+ int size;
+ int ret;
+
+ /* If no device-tree node, ignore this since we assume it isn't used */
+ if (!dev_of_valid(dev))
+ return 0;
+
+ ret = acpi_device_path(dev, path, sizeof(path));
+ if (ret)
+ return log_msg_ret("path", ret);
+
+ size = dev_read_size(dev, "i2c,speeds");
+ if (size < 0)
+ return log_msg_ret("i2c,speeds", -EINVAL);
+
+ size /= sizeof(u32);
+ if (size > ARRAY_SIZE(speeds))
+ return log_msg_ret("array", -E2BIG);
+
+ ret = dev_read_u32_array(dev, "i2c,speeds", speeds, size);
+ if (ret)
+ return log_msg_ret("read", -E2BIG);
+
+ speed = dev_read_u32_default(dev, "clock-frequency", 100000);
+ acpigen_write_scope(ctx, path);
+ ret = dw_i2c_gen_speed_config(dev, speed, &config);
+ if (ret)
+ return log_msg_ret("config", ret);
+ dw_i2c_acpi_write_speed_config(ctx, &config);
+ acpigen_pop_len(ctx);
+
+ return 0;
+}
+
+struct acpi_ops dw_i2c_acpi_ops = {
+ .fill_ssdt = dw_i2c_acpi_fill_ssdt,
+};
+
static const struct udevice_id designware_i2c_pci_ids[] = {
{ .compatible = "snps,designware-i2c-pci" },
{ .compatible = "intel,apl-i2c", .data = INTEL_APL },
@@ -124,6 +217,7 @@ U_BOOT_DRIVER(i2c_designware_pci) = {
.remove = designware_i2c_remove,
.flags = DM_FLAG_OS_PREPARE,
.ops = &designware_i2c_ops,
+ ACPI_OPS_PTR(&dw_i2c_acpi_ops)
};
static struct pci_device_id designware_pci_supported[] = {
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
index 8bc69e8..2373aa2 100644
--- a/drivers/i2c/i2c-uclass.c
+++ b/drivers/i2c/i2c-uclass.c
@@ -458,7 +458,7 @@ int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len)
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
if (offset_len > I2C_MAX_OFFSET_LEN)
- return -EINVAL;
+ return log_ret(-EINVAL);
chip->offset_len = offset_len;
return 0;
@@ -625,7 +625,7 @@ int i2c_chip_ofdata_to_platdata(struct udevice *dev, struct dm_i2c_chip *chip)
if (addr == -1) {
debug("%s: I2C Node '%s' has no 'reg' property %s\n", __func__,
dev_read_name(dev), dev->name);
- return -EINVAL;
+ return log_ret(-EINVAL);
}
chip->chip_addr = addr;
diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c
index f4ae239..57b1c60 100644
--- a/drivers/i2c/sandbox_i2c.c
+++ b/drivers/i2c/sandbox_i2c.c
@@ -11,6 +11,7 @@
#include <i2c.h>
#include <log.h>
#include <asm/test.h>
+#include <dm/acpi.h>
#include <dm/lists.h>
#include <dm/device-internal.h>
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 6bb5bc7..b67e906 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -243,10 +243,10 @@ config NUVOTON_NCT6102D
in the Nuvoton Super IO chips on X86 platforms.
config P2SB
- bool "Intel Primary-to-Sideband Bus"
+ bool "Intel Primary to Sideband Bridge"
depends on X86 || SANDBOX
help
- This enables support for the Intel Primary-to-Sideband bus,
+ This enables support for the Intel Primary to Sideband Bridge,
abbreviated to P2SB. The P2SB is used to access various peripherals
such as eSPI, GPIO, through memory-mapped I/O in a large chunk of PCI
space. The space is segmented into different channels and peripherals
@@ -256,20 +256,20 @@ config P2SB
devices - see pcr_readl(), etc.
config SPL_P2SB
- bool "Intel Primary-to-Sideband Bus in SPL"
+ bool "Intel Primary to Sideband Bridge in SPL"
depends on SPL && (X86 || SANDBOX)
help
- The Primary-to-Sideband bus is used to access various peripherals
+ The Primary to Sideband Bridge is used to access various peripherals
through memory-mapped I/O in a large chunk of PCI space. The space is
segmented into different channels and peripherals are accessed by
device-specific means within those channels. Devices should be added
in the device tree as subnodes of the p2sb.
config TPL_P2SB
- bool "Intel Primary-to-Sideband Bus in TPL"
+ bool "Intel Primary to Sideband Bridge in TPL"
depends on TPL && (X86 || SANDBOX)
help
- The Primary-to-Sideband bus is used to access various peripherals
+ The Primary to Sideband Bridge is used to access various peripherals
through memory-mapped I/O in a large chunk of PCI space. The space is
segmented into different channels and peripherals are accessed by
device-specific means within those channels. Devices should be added
diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
index ec70866..94fa233 100644
--- a/drivers/misc/irq-uclass.c
+++ b/drivers/misc/irq-uclass.c
@@ -152,8 +152,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;
@@ -170,11 +168,27 @@ int irq_first_device_type(enum irq_dev_t type, struct udevice **devp)
ret = uclass_first_device_drvdata(UCLASS_IRQ, type, devp);
if (ret)
- return log_msg_ret("find", ret);
+ return ret;
return 0;
}
+#if CONFIG_IS_ENABLED(ACPIGEN)
+int irq_get_acpi(const struct irq *irq, struct acpi_irq *acpi_irq)
+{
+ struct irq_ops *ops;
+
+ if (!irq_is_valid(irq))
+ return -EINVAL;
+
+ ops = irq_get_ops(irq->dev);
+ if (!ops->get_acpi)
+ return -ENOSYS;
+
+ return ops->get_acpi(irq, acpi_irq);
+}
+#endif
+
UCLASS_DRIVER(irq) = {
.id = UCLASS_IRQ,
.name = "irq",
diff --git a/drivers/misc/irq_sandbox.c b/drivers/misc/irq_sandbox.c
index 54bc47c..a2511b3 100644
--- a/drivers/misc/irq_sandbox.c
+++ b/drivers/misc/irq_sandbox.c
@@ -8,6 +8,7 @@
#include <common.h>
#include <dm.h>
#include <irq.h>
+#include <acpi/acpi_device.h>
#include <asm/test.h>
/**
@@ -73,6 +74,18 @@ static int sandbox_irq_of_xlate(struct irq *irq,
return 0;
}
+static __maybe_unused int sandbox_get_acpi(const struct irq *irq,
+ struct acpi_irq *acpi_irq)
+{
+ acpi_irq->pin = irq->id;
+ acpi_irq->mode = ACPI_IRQ_LEVEL_TRIGGERED;
+ acpi_irq->polarity = ACPI_IRQ_ACTIVE_HIGH;
+ acpi_irq->shared = ACPI_IRQ_SHARED;
+ acpi_irq->wake = ACPI_IRQ_WAKE;
+
+ return 0;
+}
+
static const struct irq_ops sandbox_irq_ops = {
.route_pmc_gpio_gpe = sandbox_route_pmc_gpio_gpe,
.set_polarity = sandbox_set_polarity,
@@ -80,6 +93,9 @@ static const struct irq_ops sandbox_irq_ops = {
.restore_polarities = sandbox_restore_polarities,
.read_and_clear = sandbox_irq_read_and_clear,
.of_xlate = sandbox_irq_of_xlate,
+#if CONFIG_IS_ENABLED(ACPIGEN)
+ .get_acpi = sandbox_get_acpi,
+#endif
};
static const struct udevice_id sandbox_irq_ids[] = {
diff --git a/drivers/misc/p2sb-uclass.c b/drivers/misc/p2sb-uclass.c
index 06b1e8d..b5219df 100644
--- a/drivers/misc/p2sb-uclass.c
+++ b/drivers/misc/p2sb-uclass.c
@@ -18,7 +18,17 @@
#define PCR_COMMON_IOSF_1_0 1
-static void *_pcr_reg_address(struct udevice *dev, uint offset)
+int p2sb_set_hide(struct udevice *dev, bool hide)
+{
+ struct p2sb_ops *ops = p2sb_get_ops(dev);
+
+ if (!ops->set_hide)
+ return -ENOSYS;
+
+ return ops->set_hide(dev, hide);
+}
+
+void *pcr_reg_address(struct udevice *dev, uint offset)
{
struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
struct udevice *p2sb = dev_get_parent(dev);
@@ -55,7 +65,7 @@ uint pcr_read32(struct udevice *dev, uint offset)
/* Ensure the PCR offset is correctly aligned */
assert(IS_ALIGNED(offset, sizeof(uint32_t)));
- ptr = _pcr_reg_address(dev, offset);
+ ptr = pcr_reg_address(dev, offset);
val = readl(ptr);
unmap_sysmem(ptr);
@@ -67,7 +77,7 @@ uint pcr_read16(struct udevice *dev, uint offset)
/* Ensure the PCR offset is correctly aligned */
check_pcr_offset_align(offset, sizeof(uint16_t));
- return readw(_pcr_reg_address(dev, offset));
+ return readw(pcr_reg_address(dev, offset));
}
uint pcr_read8(struct udevice *dev, uint offset)
@@ -75,7 +85,7 @@ uint pcr_read8(struct udevice *dev, uint offset)
/* Ensure the PCR offset is correctly aligned */
check_pcr_offset_align(offset, sizeof(uint8_t));
- return readb(_pcr_reg_address(dev, offset));
+ return readb(pcr_reg_address(dev, offset));
}
/*
@@ -86,7 +96,7 @@ uint pcr_read8(struct udevice *dev, uint offset)
*/
static void write_completion(struct udevice *dev, uint offset)
{
- readl(_pcr_reg_address(dev, ALIGN_DOWN(offset, sizeof(uint32_t))));
+ readl(pcr_reg_address(dev, ALIGN_DOWN(offset, sizeof(uint32_t))));
}
void pcr_write32(struct udevice *dev, uint offset, uint indata)
@@ -94,7 +104,7 @@ void pcr_write32(struct udevice *dev, uint offset, uint indata)
/* Ensure the PCR offset is correctly aligned */
assert(IS_ALIGNED(offset, sizeof(indata)));
- writel(indata, _pcr_reg_address(dev, offset));
+ writel(indata, pcr_reg_address(dev, offset));
/* Ensure the writes complete */
write_completion(dev, offset);
}
@@ -104,7 +114,7 @@ void pcr_write16(struct udevice *dev, uint offset, uint indata)
/* Ensure the PCR offset is correctly aligned */
check_pcr_offset_align(offset, sizeof(uint16_t));
- writew(indata, _pcr_reg_address(dev, offset));
+ writew(indata, pcr_reg_address(dev, offset));
/* Ensure the writes complete */
write_completion(dev, offset);
}
@@ -114,7 +124,7 @@ void pcr_write8(struct udevice *dev, uint offset, uint indata)
/* Ensure the PCR offset is correctly aligned */
check_pcr_offset_align(offset, sizeof(uint8_t));
- writeb(indata, _pcr_reg_address(dev, offset));
+ writeb(indata, pcr_reg_address(dev, offset));
/* Ensure the writes complete */
write_completion(dev, offset);
}
diff --git a/drivers/mmc/pci_mmc.c b/drivers/mmc/pci_mmc.c
index 404264a..0c45e1b 100644
--- a/drivers/mmc/pci_mmc.c
+++ b/drivers/mmc/pci_mmc.c
@@ -7,10 +7,15 @@
#include <common.h>
#include <dm.h>
#include <errno.h>
+#include <log.h>
#include <malloc.h>
#include <mapmem.h>
#include <sdhci.h>
-#include <asm/pci.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_device.h>
+#include <acpi/acpi_dp.h>
+#include <asm-generic/gpio.h>
+#include <dm/acpi.h>
struct pci_mmc_plat {
struct mmc_config cfg;
@@ -20,6 +25,7 @@ struct pci_mmc_plat {
struct pci_mmc_priv {
struct sdhci_host host;
void *base;
+ struct gpio_desc cd_gpio;
};
static int pci_mmc_probe(struct udevice *dev)
@@ -44,6 +50,15 @@ static int pci_mmc_probe(struct udevice *dev)
return sdhci_probe(dev);
}
+static int pci_mmc_ofdata_to_platdata(struct udevice *dev)
+{
+ struct pci_mmc_priv *priv = dev_get_priv(dev);
+
+ gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, GPIOD_IS_IN);
+
+ return 0;
+}
+
static int pci_mmc_bind(struct udevice *dev)
{
struct pci_mmc_plat *plat = dev_get_platdata(dev);
@@ -51,14 +66,75 @@ static int pci_mmc_bind(struct udevice *dev)
return sdhci_bind(dev, &plat->mmc, &plat->cfg);
}
+static int pci_mmc_acpi_fill_ssdt(const struct udevice *dev,
+ struct acpi_ctx *ctx)
+{
+ struct pci_mmc_priv *priv = dev_get_priv(dev);
+ char path[ACPI_PATH_MAX];
+ struct acpi_gpio gpio;
+ struct acpi_dp *dp;
+ int ret;
+
+ if (!dev_of_valid(dev))
+ return 0;
+
+ ret = gpio_get_acpi(&priv->cd_gpio, &gpio);
+ if (ret)
+ return log_msg_ret("gpio", ret);
+ gpio.type = ACPI_GPIO_TYPE_INTERRUPT;
+ gpio.pull = ACPI_GPIO_PULL_NONE;
+ gpio.irq.mode = ACPI_IRQ_EDGE_TRIGGERED;
+ gpio.irq.polarity = ACPI_IRQ_ACTIVE_BOTH;
+ gpio.irq.shared = ACPI_IRQ_SHARED;
+ gpio.irq.wake = ACPI_IRQ_WAKE;
+ gpio.interrupt_debounce_timeout = 10000; /* 100ms */
+
+ /* Use device path as the Scope for the SSDT */
+ ret = acpi_device_path(dev, path, sizeof(path));
+ if (ret)
+ return log_msg_ret("path", ret);
+ acpigen_write_scope(ctx, path);
+ acpigen_write_name(ctx, "_CRS");
+
+ /* Write GpioInt() as default (if set) or custom from devicetree */
+ acpigen_write_resourcetemplate_header(ctx);
+ acpi_device_write_gpio(ctx, &gpio);
+ acpigen_write_resourcetemplate_footer(ctx);
+
+ /* Bind the cd-gpio name to the GpioInt() resource */
+ dp = acpi_dp_new_table("_DSD");
+ if (!dp)
+ return -ENOMEM;
+ acpi_dp_add_gpio(dp, "cd-gpio", path, 0, 0, 1);
+ ret = acpi_dp_write(ctx, dp);
+ if (ret)
+ return log_msg_ret("cd", ret);
+
+ acpigen_pop_len(ctx);
+
+ return 0;
+}
+
+struct acpi_ops pci_mmc_acpi_ops = {
+ .fill_ssdt = pci_mmc_acpi_fill_ssdt,
+};
+
+static const struct udevice_id pci_mmc_match[] = {
+ { .compatible = "intel,apl-sd" },
+ { }
+};
+
U_BOOT_DRIVER(pci_mmc) = {
.name = "pci_mmc",
.id = UCLASS_MMC,
+ .of_match = pci_mmc_match,
.bind = pci_mmc_bind,
+ .ofdata_to_platdata = pci_mmc_ofdata_to_platdata,
.probe = pci_mmc_probe,
.ops = &sdhci_ops,
.priv_auto_alloc_size = sizeof(struct pci_mmc_priv),
.platdata_auto_alloc_size = sizeof(struct pci_mmc_plat),
+ ACPI_OPS_PTR(&pci_mmc_acpi_ops)
};
static struct pci_device_id mmc_supported[] = {
diff --git a/drivers/pinctrl/intel/Kconfig b/drivers/pinctrl/intel/Kconfig
index e62a2e0..1acc5da 100644
--- a/drivers/pinctrl/intel/Kconfig
+++ b/drivers/pinctrl/intel/Kconfig
@@ -15,6 +15,18 @@ config INTEL_PINCTRL_IOSTANDBY
bool
default y
+config INTEL_PINCTRL_MULTI_ACPI_DEVICES
+ bool
+ default y
+ help
+ Enable this if the pinctrl devices are modelled as multiple,
+ separate ACPI devices in the ACPI tables. If enabled, the ACPI
+ devices match the U-Boot pinctrl devices and the pin 'offset' is
+ relatove to a particular pinctrl device. If disabled, there is a
+ single ACPI pinctrl device which includes all U-Boot pinctrl devices
+ and the pin 'offset' is in effect a global pin number.
+
+
config PINCTRL_INTEL_APL
bool "Support Intel Apollo Lake (APL)"
help
diff --git a/drivers/pinctrl/intel/pinctrl.c b/drivers/pinctrl/intel/pinctrl.c
index ba82063..ba21c9d 100644
--- a/drivers/pinctrl/intel/pinctrl.c
+++ b/drivers/pinctrl/intel/pinctrl.c
@@ -394,7 +394,7 @@ static int pinctrl_configure_pad(struct udevice *dev,
return 0;
}
-u32 intel_pinctrl_get_config_reg_addr(struct udevice *dev, uint offset)
+u32 intel_pinctrl_get_config_reg_offset(struct udevice *dev, uint offset)
{
struct intel_pinctrl_priv *priv = dev_get_priv(dev);
const struct pad_community *comm = priv->comm;
@@ -407,9 +407,16 @@ u32 intel_pinctrl_get_config_reg_addr(struct udevice *dev, uint offset)
return config_offset;
}
+u32 intel_pinctrl_get_config_reg_addr(struct udevice *dev, uint offset)
+{
+ uint config_offset = intel_pinctrl_get_config_reg_offset(dev, offset);
+
+ return (u32)(ulong)pcr_reg_address(dev, config_offset);
+}
+
u32 intel_pinctrl_get_config_reg(struct udevice *dev, uint offset)
{
- uint config_offset = intel_pinctrl_get_config_reg_addr(dev, offset);
+ uint config_offset = intel_pinctrl_get_config_reg_offset(dev, offset);
return pcr_read32(dev, config_offset);
}
@@ -420,6 +427,8 @@ int intel_pinctrl_get_acpi_pin(struct udevice *dev, uint offset)
const struct pad_community *comm = priv->comm;
int group;
+ if (IS_ENABLED(CONFIG_INTEL_PINCTRL_MULTI_ACPI_DEVICES))
+ return offset;
group = pinctrl_group_index(comm, offset);
/* If pad base is not set then use GPIO number as ACPI pin number */
@@ -610,15 +619,11 @@ int intel_pinctrl_ofdata_to_platdata(struct udevice *dev,
{
struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
struct intel_pinctrl_priv *priv = dev_get_priv(dev);
- int ret;
if (!comm) {
log_err("Cannot find community for pid %d\n", pplat->pid);
return -EDOM;
}
- ret = irq_first_device_type(X86_IRQT_ITSS, &priv->itss);
- if (ret)
- return log_msg_ret("Cannot find ITSS", ret);
priv->comm = comm;
priv->num_cfgs = num_cfgs;
@@ -628,8 +633,12 @@ int intel_pinctrl_ofdata_to_platdata(struct udevice *dev,
int intel_pinctrl_probe(struct udevice *dev)
{
struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+ int ret;
priv->itss_pol_cfg = true;
+ ret = irq_first_device_type(X86_IRQT_ITSS, &priv->itss);
+ if (ret)
+ return log_msg_ret("Cannot find ITSS", ret);
return 0;
}
diff --git a/drivers/pinctrl/intel/pinctrl_apl.c b/drivers/pinctrl/intel/pinctrl_apl.c
index c14176d4..7624a99 100644
--- a/drivers/pinctrl/intel/pinctrl_apl.c
+++ b/drivers/pinctrl/intel/pinctrl_apl.c
@@ -75,7 +75,6 @@ static const struct pad_community apl_gpio_communities[] = {
.gpi_smi_en_reg_0 = GPI_SMI_EN_0,
.max_pads_per_group = GPIO_MAX_NUM_PER_GROUP,
.name = "GPIO_GPE_N",
- .acpi_path = "\\_SB.GPO0",
.reset_map = rst_map,
.num_reset_vals = ARRAY_SIZE(rst_map),
.groups = apl_community_n_groups,
@@ -94,7 +93,6 @@ static const struct pad_community apl_gpio_communities[] = {
.gpi_smi_en_reg_0 = GPI_SMI_EN_0,
.max_pads_per_group = GPIO_MAX_NUM_PER_GROUP,
.name = "GPIO_GPE_NW",
- .acpi_path = "\\_SB.GPO1",
.reset_map = rst_map,
.num_reset_vals = ARRAY_SIZE(rst_map),
.groups = apl_community_nw_groups,
@@ -113,7 +111,6 @@ static const struct pad_community apl_gpio_communities[] = {
.gpi_smi_en_reg_0 = GPI_SMI_EN_0,
.max_pads_per_group = GPIO_MAX_NUM_PER_GROUP,
.name = "GPIO_GPE_W",
- .acpi_path = "\\_SB.GPO2",
.reset_map = rst_map,
.num_reset_vals = ARRAY_SIZE(rst_map),
.groups = apl_community_w_groups,
@@ -132,7 +129,6 @@ static const struct pad_community apl_gpio_communities[] = {
.gpi_smi_en_reg_0 = GPI_SMI_EN_0,
.max_pads_per_group = GPIO_MAX_NUM_PER_GROUP,
.name = "GPIO_GPE_SW",
- .acpi_path = "\\_SB.GPO3",
.reset_map = rst_map,
.num_reset_vals = ARRAY_SIZE(rst_map),
.groups = apl_community_sw_groups,
diff --git a/drivers/power/acpi_pmc/acpi-pmc-uclass.c b/drivers/power/acpi_pmc/acpi-pmc-uclass.c
index 1c79f83..828963d 100644
--- a/drivers/power/acpi_pmc/acpi-pmc-uclass.c
+++ b/drivers/power/acpi_pmc/acpi-pmc-uclass.c
@@ -15,15 +15,6 @@
#include <asm/io.h>
#include <power/acpi_pmc.h>
-enum {
- PM1_STS = 0x00,
- PM1_EN = 0x02,
- PM1_CNT = 0x04,
-
- GPE0_STS = 0x20,
- GPE0_EN = 0x30,
-};
-
struct tco_regs {
u32 tco_rld;
u32 tco_sts;
diff --git a/drivers/rtc/sandbox_rtc.c b/drivers/rtc/sandbox_rtc.c
index 77065e4..852770a 100644
--- a/drivers/rtc/sandbox_rtc.c
+++ b/drivers/rtc/sandbox_rtc.c
@@ -9,6 +9,7 @@
#include <i2c.h>
#include <rtc.h>
#include <asm/rtc.h>
+#include <dm/acpi.h>
#define REG_COUNT 0x80
@@ -67,6 +68,17 @@ static int sandbox_rtc_write8(struct udevice *dev, unsigned int reg, int val)
return dm_i2c_reg_write(dev, reg, val);
}
+#if CONFIG_IS_ENABLED(ACPIGEN)
+static int sandbox_rtc_get_name(const struct udevice *dev, char *out_name)
+{
+ return acpi_copy_name(out_name, "RTCC");
+}
+
+struct acpi_ops sandbox_rtc_acpi_ops = {
+ .get_name = sandbox_rtc_get_name,
+};
+#endif
+
static const struct rtc_ops sandbox_rtc_ops = {
.get = sandbox_rtc_get,
.set = sandbox_rtc_set,
@@ -85,4 +97,5 @@ U_BOOT_DRIVER(rtc_sandbox) = {
.id = UCLASS_RTC,
.of_match = sandbox_rtc_ids,
.ops = &sandbox_rtc_ops,
+ ACPI_OPS_PTR(&sandbox_rtc_acpi_ops)
};
diff --git a/drivers/sound/Kconfig b/drivers/sound/Kconfig
index 4ebc719..0948d8c 100644
--- a/drivers/sound/Kconfig
+++ b/drivers/sound/Kconfig
@@ -40,6 +40,15 @@ config I2S_SAMSUNG
option provides an implementation for sound_init() and
sound_play().
+config SOUND_DA7219
+ bool "Dialog Semiconductor audio codec"
+ depends on SOUND
+ help
+ The DA7219 is an ultra-low-power audio codec with Advanced Accessory
+ Detection (AAD). This driver only supports generation of ACPI tables.
+ It does not support sound output or any of the other codec
+ features.
+
config SOUND_I8254
bool "Intel i8254 timer / beeper"
depends on SOUND
@@ -104,6 +113,15 @@ config SOUND_MAX98095
audio data and I2C for codec control. At present it only works
with the Samsung I2S driver.
+config SOUND_MAX98357A
+ bool "Support Maxim max98357a audio codec"
+ depends on PCI
+ help
+ Enable the max98357a audio codec. This is connected on PCI for
+ audio data codec control. This is currently only capable of providing
+ ACPI information. A full driver (with sound in U-Boot) is currently
+ not available.
+
config SOUND_RT5677
bool "Support Realtek RT5677 audio codec"
depends on SOUND
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index 73ed7fe..9b40c80 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_SOUND) += sound.o
obj-$(CONFIG_SOUND) += codec-uclass.o
obj-$(CONFIG_SOUND) += i2s-uclass.o
obj-$(CONFIG_SOUND) += sound-uclass.o
+obj-$(CONFIG_SOUND_DA7219) += da7219.o
obj-$(CONFIG_I2S_SAMSUNG) += samsung-i2s.o
obj-$(CONFIG_SOUND_SANDBOX) += sandbox.o
obj-$(CONFIG_I2S_ROCKCHIP) += rockchip_i2s.o rockchip_sound.o
@@ -16,6 +17,7 @@ obj-$(CONFIG_SOUND_WM8994) += wm8994.o
obj-$(CONFIG_SOUND_MAX98088) += max98088.o maxim_codec.o
obj-$(CONFIG_SOUND_MAX98090) += max98090.o maxim_codec.o
obj-$(CONFIG_SOUND_MAX98095) += max98095.o maxim_codec.o
+obj-$(CONFIG_SOUND_MAX98357A) += max98357a.o
obj-$(CONFIG_SOUND_INTEL_HDA) += hda_codec.o
obj-$(CONFIG_SOUND_I8254) += i8254_beep.o
obj-$(CONFIG_SOUND_RT5677) += rt5677.o
diff --git a/drivers/sound/da7219.c b/drivers/sound/da7219.c
new file mode 100644
index 0000000..6bc1ad0
--- /dev/null
+++ b/drivers/sound/da7219.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ACPI driver for DA7219 codec
+ *
+ * Copyright 2019 Google LLC
+ * Parts taken from coreboot
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <irq.h>
+#include <log.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_device.h>
+#include <acpi/acpi_dp.h>
+#ifdef CONFIG_X86
+#include <asm/acpi_nhlt.h>
+#endif
+#include <asm-generic/gpio.h>
+#include <dt-bindings/sound/nhlt.h>
+#include <dm/acpi.h>
+
+#define DA7219_ACPI_HID "DLGS7219"
+
+static int da7219_acpi_fill_ssdt(const struct udevice *dev,
+ struct acpi_ctx *ctx)
+{
+ char scope[ACPI_PATH_MAX];
+ char name[ACPI_NAME_MAX];
+ struct acpi_dp *dsd, *aad;
+ ofnode node;
+ u32 val;
+ int ret;
+
+ ret = acpi_device_scope(dev, scope, sizeof(scope));
+ if (ret)
+ return log_msg_ret("scope", ret);
+ ret = acpi_get_name(dev, name);
+ if (ret)
+ return log_msg_ret("name", ret);
+
+ /* Device */
+ acpigen_write_scope(ctx, scope);
+ acpigen_write_device(ctx, name);
+ acpigen_write_name_string(ctx, "_HID", DA7219_ACPI_HID);
+ acpigen_write_name_integer(ctx, "_UID", 1);
+ acpigen_write_name_string(ctx, "_DDN",
+ dev_read_string(dev, "acpi,ddn"));
+ acpigen_write_name_integer(ctx, "_S0W", 4);
+ acpigen_write_sta(ctx, acpi_device_status(dev));
+
+ /* Resources */
+ acpigen_write_name(ctx, "_CRS");
+ acpigen_write_resourcetemplate_header(ctx);
+ ret = acpi_device_write_i2c_dev(ctx, dev);
+ if (ret)
+ return log_msg_ret("i2c", ret);
+
+ /* Use either Interrupt() or GpioInt() */
+ ret = acpi_device_write_interrupt_or_gpio(ctx, (struct udevice *)dev,
+ "req-gpios");
+ if (ret)
+ return log_msg_ret("irq_gpio", ret);
+ acpigen_write_resourcetemplate_footer(ctx);
+
+ /* AAD Child Device Properties */
+ aad = acpi_dp_new_table("DAAD");
+ if (!aad)
+ return log_msg_ret("aad", -ENOMEM);
+
+ node = ofnode_find_subnode(dev_ofnode(dev), "da7219_aad");
+ if (!ofnode_valid(node))
+ return log_msg_ret("da7219_aad", -EINVAL);
+ acpi_dp_ofnode_copy_int(node, aad, "dlg,btn-cfg");
+ acpi_dp_ofnode_copy_int(node, aad, "dlg,mic-det-thr");
+ acpi_dp_ofnode_copy_int(node, aad, "dlg,jack-ins-deb");
+ acpi_dp_ofnode_copy_str(node, aad, "dlg,jack-det-rate");
+ acpi_dp_ofnode_copy_int(node, aad, "dlg,jack-rem-deb");
+ acpi_dp_ofnode_copy_int(node, aad, "dlg,a-d-btn-thr");
+ acpi_dp_ofnode_copy_int(node, aad, "dlg,d-b-btn-thr");
+ acpi_dp_ofnode_copy_int(node, aad, "dlg,b-c-btn-thr");
+ acpi_dp_ofnode_copy_int(node, aad, "dlg,c-mic-btn-thr");
+ acpi_dp_ofnode_copy_int(node, aad, "dlg,btn-avg");
+ acpi_dp_ofnode_copy_int(node, aad, "dlg,adc-1bit-rpt");
+ if (!ofnode_read_u32(node, "dlg,micbias-pulse-lvl", &val)) {
+ acpi_dp_ofnode_copy_int(node, aad, "dlg,micbias-pulse-lvl");
+ acpi_dp_ofnode_copy_int(node, aad, "dlg,micbias-pulse-time");
+ }
+
+ /* DA7219 Properties */
+ dsd = acpi_dp_new_table("_DSD");
+ if (!dsd)
+ return log_msg_ret("dsd", -ENOMEM);
+ acpi_dp_dev_copy_int(dev, dsd, "dlg,micbias-lvl");
+ acpi_dp_dev_copy_str(dev, dsd, "dlg,mic-amp-in-sel");
+ acpi_dp_dev_copy_str(dev, dsd, "dlg,mclk-name");
+ acpi_dp_add_child(dsd, "da7219_aad", aad);
+
+ /* Write Device Property Hierarchy */
+ acpi_dp_write(ctx, dsd);
+
+ acpigen_pop_len(ctx); /* Device */
+ acpigen_pop_len(ctx); /* Scope */
+
+ return 0;
+}
+
+/* For now only X86 boards support NHLT */
+#ifdef CONFIG_X86
+static const struct nhlt_format_config da7219_formats[] = {
+ /* 48 KHz 24-bits per sample. */
+ {
+ .num_channels = 2,
+ .sample_freq_khz = 48,
+ .container_bits_per_sample = 32,
+ .valid_bits_per_sample = 24,
+ .settings_file = "dialog-2ch-48khz-24b.dat",
+ },
+};
+
+static const struct nhlt_tdm_config tdm_config = {
+ .virtual_slot = 0,
+ .config_type = NHLT_TDM_BASIC,
+};
+
+static const struct nhlt_endp_descriptor da7219_descriptors[] = {
+ /* Render Endpoint */
+ {
+ .link = NHLT_LINK_SSP,
+ .device = NHLT_SSP_DEV_I2S,
+ .direction = NHLT_DIR_RENDER,
+ .vid = NHLT_VID,
+ .did = NHLT_DID_SSP,
+ .cfg = &tdm_config,
+ .cfg_size = sizeof(tdm_config),
+ .formats = da7219_formats,
+ .num_formats = ARRAY_SIZE(da7219_formats),
+ },
+ /* Capture Endpoint */
+ {
+ .link = NHLT_LINK_SSP,
+ .device = NHLT_SSP_DEV_I2S,
+ .direction = NHLT_DIR_CAPTURE,
+ .vid = NHLT_VID,
+ .did = NHLT_DID_SSP,
+ .cfg = &tdm_config,
+ .cfg_size = sizeof(tdm_config),
+ .formats = da7219_formats,
+ .num_formats = ARRAY_SIZE(da7219_formats),
+ },
+};
+
+static int da7219_acpi_setup_nhlt(const struct udevice *dev,
+ struct acpi_ctx *ctx)
+{
+ u32 hwlink;
+ int ret;
+
+ if (dev_read_u32(dev, "acpi,audio-link", &hwlink))
+ return log_msg_ret("link", -EINVAL);
+
+ /* Virtual bus id of SSP links are the hardware port ids proper. */
+ ret = nhlt_add_ssp_endpoints(ctx->nhlt, hwlink, da7219_descriptors,
+ ARRAY_SIZE(da7219_descriptors));
+ if (ret)
+ return log_msg_ret("add", ret);
+
+ return 0;
+}
+#endif
+
+struct acpi_ops da7219_acpi_ops = {
+ .fill_ssdt = da7219_acpi_fill_ssdt,
+#ifdef CONFIG_X86
+ .setup_nhlt = da7219_acpi_setup_nhlt,
+#endif
+};
+
+static const struct udevice_id da7219_ids[] = {
+ { .compatible = "dlg,da7219" },
+ { }
+};
+
+U_BOOT_DRIVER(da7219) = {
+ .name = "da7219",
+ .id = UCLASS_MISC,
+ .of_match = da7219_ids,
+ ACPI_OPS_PTR(&da7219_acpi_ops)
+};
diff --git a/drivers/sound/max98357a.c b/drivers/sound/max98357a.c
new file mode 100644
index 0000000..841bc6e
--- /dev/null
+++ b/drivers/sound/max98357a.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * max98357a.c -- MAX98357A Audio driver
+ *
+ * Copyright 2019 Google LLC
+ * Parts taken from coreboot
+ */
+
+#include <common.h>
+#include <audio_codec.h>
+#include <dm.h>
+#include <log.h>
+#include <sound.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_device.h>
+#include <acpi/acpi_dp.h>
+#include <asm-generic/gpio.h>
+#ifdef CONFIG_X86
+#include <asm/acpi_nhlt.h>
+#endif
+#include <dt-bindings/sound/nhlt.h>
+#include <dm/acpi.h>
+
+struct max98357a_priv {
+ struct gpio_desc sdmode_gpio;
+};
+
+static int max98357a_ofdata_to_platdata(struct udevice *dev)
+{
+ struct max98357a_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = gpio_request_by_name(dev, "sdmode-gpios", 0, &priv->sdmode_gpio,
+ GPIOD_IS_IN);
+ if (ret)
+ return log_msg_ret("gpio", ret);
+
+ return 0;
+}
+
+static int max98357a_acpi_fill_ssdt(const struct udevice *dev,
+ struct acpi_ctx *ctx)
+{
+ struct max98357a_priv *priv = dev_get_priv(dev);
+ char scope[ACPI_PATH_MAX];
+ char name[ACPI_NAME_MAX];
+ char path[ACPI_PATH_MAX];
+ struct acpi_dp *dp;
+ int ret;
+
+ ret = acpi_device_scope(dev, scope, sizeof(scope));
+ if (ret)
+ return log_msg_ret("scope", ret);
+ ret = acpi_get_name(dev, name);
+ if (ret)
+ return log_msg_ret("name", ret);
+
+ /* Device */
+ acpigen_write_scope(ctx, scope);
+ acpigen_write_device(ctx, name);
+ acpigen_write_name_string(ctx, "_HID",
+ dev_read_string(dev, "acpi,hid"));
+ acpigen_write_name_integer(ctx, "_UID", 0);
+ acpigen_write_name_string(ctx, "_DDN",
+ dev_read_string(dev, "acpi,ddn"));
+ acpigen_write_sta(ctx, acpi_device_status(dev));
+
+ /* Resources */
+ acpigen_write_name(ctx, "_CRS");
+ acpigen_write_resourcetemplate_header(ctx);
+ ret = acpi_device_write_gpio_desc(ctx, &priv->sdmode_gpio);
+ if (ret)
+ return log_msg_ret("gpio", ret);
+ acpigen_write_resourcetemplate_footer(ctx);
+
+ /* _DSD for devicetree properties */
+ /* This points to the first pin in the first gpio entry in _CRS */
+ ret = acpi_device_path(dev, path, sizeof(path));
+ if (ret)
+ return log_msg_ret("path", ret);
+ dp = acpi_dp_new_table("_DSD");
+ acpi_dp_add_gpio(dp, "sdmode-gpio", path, 0, 0,
+ priv->sdmode_gpio.flags & GPIOD_ACTIVE_LOW ?
+ ACPI_IRQ_ACTIVE_LOW : ACPI_IRQ_ACTIVE_HIGH);
+ acpi_dp_add_integer(dp, "sdmode-delay",
+ dev_read_u32_default(dev, "sdmode-delay", 0));
+ acpi_dp_write(ctx, dp);
+
+ acpigen_pop_len(ctx); /* Device */
+ acpigen_pop_len(ctx); /* Scope */
+
+ return 0;
+}
+
+/* For now only X86 boards support NHLT */
+#ifdef CONFIG_X86
+static const struct nhlt_format_config max98357a_formats[] = {
+ /* 48 KHz 24-bits per sample. */
+ {
+ .num_channels = 2,
+ .sample_freq_khz = 48,
+ .container_bits_per_sample = 32,
+ .valid_bits_per_sample = 24,
+ .settings_file = "max98357-render-2ch-48khz-24b.dat",
+ },
+};
+
+static const struct nhlt_endp_descriptor max98357a_descriptors[] = {
+ {
+ .link = NHLT_LINK_SSP,
+ .device = NHLT_SSP_DEV_I2S,
+ .direction = NHLT_DIR_RENDER,
+ .vid = NHLT_VID,
+ .did = NHLT_DID_SSP,
+ .formats = max98357a_formats,
+ .num_formats = ARRAY_SIZE(max98357a_formats),
+ },
+};
+
+static int max98357a_acpi_setup_nhlt(const struct udevice *dev,
+ struct acpi_ctx *ctx)
+{
+ u32 hwlink;
+ int ret;
+
+ if (dev_read_u32(dev, "acpi,audio-link", &hwlink))
+ return log_msg_ret("link", -EINVAL);
+
+ /* Virtual bus id of SSP links are the hardware port ids proper. */
+ ret = nhlt_add_ssp_endpoints(ctx->nhlt, hwlink, max98357a_descriptors,
+ ARRAY_SIZE(max98357a_descriptors));
+ if (ret)
+ return log_msg_ret("add", ret);
+
+ return 0;
+}
+#endif
+
+struct acpi_ops max98357a_acpi_ops = {
+ .fill_ssdt = max98357a_acpi_fill_ssdt,
+#ifdef CONFIG_X86
+ .setup_nhlt = max98357a_acpi_setup_nhlt,
+#endif
+};
+
+static const struct audio_codec_ops max98357a_ops = {
+};
+
+static const struct udevice_id max98357a_ids[] = {
+ { .compatible = "maxim,max98357a" },
+ { }
+};
+
+U_BOOT_DRIVER(max98357a) = {
+ .name = "max98357a",
+ .id = UCLASS_AUDIO_CODEC,
+ .of_match = max98357a_ids,
+ .ofdata_to_platdata = max98357a_ofdata_to_platdata,
+ .ops = &max98357a_ops,
+ ACPI_OPS_PTR(&max98357a_acpi_ops)
+};
diff --git a/drivers/spi/sandbox_spi.c b/drivers/spi/sandbox_spi.c
index 570ae28..755f176 100644
--- a/drivers/spi/sandbox_spi.c
+++ b/drivers/spi/sandbox_spi.c
@@ -21,6 +21,7 @@
#include <linux/errno.h>
#include <asm/spi.h>
#include <asm/state.h>
+#include <dm/acpi.h>
#include <dm/device-internal.h>
#ifndef CONFIG_SPI_IDLE_VAL