summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFurquan Shaikh <furquan@google.com>2020-07-16 13:16:21 -0700
committerFurquan Shaikh <furquan@google.com>2020-07-17 23:33:23 +0000
commit03294a384906b0d710f1b968e11d75b139e2f4a9 (patch)
tree6a794b5365bea678f22c4d0dd7979c51961178cd
parent550cd0599583c7dc3887f8c728f79855a8f2c149 (diff)
drivers/amd/i2s_machine_dev: Add a driver for AMD I2S machine device
This change adds a new driver for AMD I2S machine device. Currently, this device is added as part of `acp_fill_ssdt()` in Picasso, but with addition of this driver, this device can be added just like any other device in the devicetree. BUG=b:157708581 Change-Id: I49d1a867d7941397acca1054632b6ad855a021de Signed-off-by: Furquan Shaikh <furquan@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/43541 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Aaron Durbin <adurbin@chromium.org>
-rw-r--r--src/drivers/amd/i2s_machine_dev/Kconfig3
-rw-r--r--src/drivers/amd/i2s_machine_dev/Makefile.inc1
-rw-r--r--src/drivers/amd/i2s_machine_dev/chip.h19
-rw-r--r--src/drivers/amd/i2s_machine_dev/i2s_machine_dev.c92
4 files changed, 115 insertions, 0 deletions
diff --git a/src/drivers/amd/i2s_machine_dev/Kconfig b/src/drivers/amd/i2s_machine_dev/Kconfig
new file mode 100644
index 0000000000..c9dabf7b82
--- /dev/null
+++ b/src/drivers/amd/i2s_machine_dev/Kconfig
@@ -0,0 +1,3 @@
+config DRIVERS_AMD_I2S_MACHINE_DEV
+ bool
+ depends on HAVE_ACPI_TABLES
diff --git a/src/drivers/amd/i2s_machine_dev/Makefile.inc b/src/drivers/amd/i2s_machine_dev/Makefile.inc
new file mode 100644
index 0000000000..df09f4d016
--- /dev/null
+++ b/src/drivers/amd/i2s_machine_dev/Makefile.inc
@@ -0,0 +1 @@
+ramstage-$(CONFIG_DRIVERS_AMD_I2S_MACHINE_DEV) += i2s_machine_dev.c
diff --git a/src/drivers/amd/i2s_machine_dev/chip.h b/src/drivers/amd/i2s_machine_dev/chip.h
new file mode 100644
index 0000000000..5d3a423b43
--- /dev/null
+++ b/src/drivers/amd/i2s_machine_dev/chip.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef __DRIVERS_AMD_I2S_MACHINE_DEV_H__
+#define __DRIVERS_AMD_I2S_MACHINE_DEV_H__
+
+#include <acpi/acpi_device.h>
+
+struct drivers_amd_i2s_machine_dev_config {
+ /* ACPI _HID (required) */
+ const char *hid;
+
+ /* ACPI _UID */
+ unsigned int uid;
+
+ /* DMIC select GPIO (required) */
+ struct acpi_gpio dmic_select_gpio;
+};
+
+#endif /* ___DRIVERS_AMD_I2S_MACHINE_DEV_H__ */
diff --git a/src/drivers/amd/i2s_machine_dev/i2s_machine_dev.c b/src/drivers/amd/i2s_machine_dev/i2s_machine_dev.c
new file mode 100644
index 0000000000..a93826551d
--- /dev/null
+++ b/src/drivers/amd/i2s_machine_dev/i2s_machine_dev.c
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <acpi/acpi_device.h>
+#include <acpi/acpigen.h>
+#include <device/device.h>
+#include <string.h>
+#include "chip.h"
+#include <console/console.h>
+
+#define AMD_I2S_ACPI_DESC "I2S machine driver"
+
+static void i2s_machine_dev_fill_ssdt(const struct device *dev)
+{
+ const char *scope = acpi_device_scope(dev);
+ struct acpi_dp *dsd;
+ const struct acpi_gpio *dmic_select_gpio;
+ const struct drivers_amd_i2s_machine_dev_config *cfg;
+ const char *path = acpi_device_path(dev);
+
+ cfg = config_of(dev);
+
+ dmic_select_gpio = &cfg->dmic_select_gpio;
+
+ if (cfg->hid == NULL) {
+ printk(BIOS_ERR, "%s: ERROR: HID required\n", dev_path(dev));
+ return;
+ }
+
+ if (dmic_select_gpio->pin_count == 0) {
+ printk(BIOS_ERR, "%s: ERROR: DMIC select GPIO required\n", dev_path(dev));
+ return;
+ }
+
+ acpigen_write_scope(scope); /* Scope */
+ acpigen_write_device(acpi_device_name(dev)); /* Device */
+ acpigen_write_name_string("_HID", cfg->hid);
+ acpigen_write_name_integer("_UID", cfg->uid);
+ acpigen_write_name_string("_DDN", AMD_I2S_ACPI_DESC);
+
+ acpigen_write_STA(acpi_device_status(dev));
+
+ /* Resources */
+ acpigen_write_name("_CRS");
+ acpigen_write_resourcetemplate_header();
+ acpi_device_write_gpio(dmic_select_gpio);
+ acpigen_write_resourcetemplate_footer();
+
+ dsd = acpi_dp_new_table("_DSD");
+ /*
+ * This GPIO is used to select DMIC0 or DMIC1 by the kernel driver. It does not
+ * really have a polarity since low and high control the selection of DMIC and
+ * hence does not have an active polarity.
+ * Kernel driver does not use the polarity field and instead treats the GPIO
+ * selection as follows:
+ * Set low (0) = Select DMIC0
+ * Set high (1) = Select DMIC1
+ */
+ acpi_dp_add_gpio(dsd, "dmic-gpios", path,
+ 0, /* Index = 0 (There is a single GPIO entry in _CRS). */
+ 0, /* Pin = 0 (There is a single pin in the GPIO resource). */
+ 0); /* Active low = 0 (Kernel driver does not use active polarity). */
+ acpi_dp_write(dsd);
+
+ acpigen_pop_len(); /* Device */
+ acpigen_pop_len(); /* Scope */
+
+ printk(BIOS_INFO, "%s: %s at %s\n", path, AMD_I2S_ACPI_DESC, dev_path(dev));
+}
+
+static const char *i2s_machine_dev_acpi_name(const struct device *dev)
+{
+ static char name[5];
+ snprintf(name, sizeof(name), "I2S%X", dev->path.generic.id);
+ return name;
+}
+
+static struct device_operations i2s_machine_dev_ops = {
+ .read_resources = noop_read_resources,
+ .set_resources = noop_set_resources,
+ .acpi_name = i2s_machine_dev_acpi_name,
+ .acpi_fill_ssdt = i2s_machine_dev_fill_ssdt,
+};
+
+static void i2s_machine_dev_enable(struct device *dev)
+{
+ dev->ops = &i2s_machine_dev_ops;
+}
+
+struct chip_operations drivers_amd_i2s_machine_dev_ops = {
+ CHIP_NAME("AMD I2S Machine Device")
+ .enable_dev = i2s_machine_dev_enable
+};