From 03294a384906b0d710f1b968e11d75b139e2f4a9 Mon Sep 17 00:00:00 2001 From: Furquan Shaikh Date: Thu, 16 Jul 2020 13:16:21 -0700 Subject: 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 Reviewed-on: https://review.coreboot.org/c/coreboot/+/43541 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin --- src/drivers/amd/i2s_machine_dev/Kconfig | 3 + src/drivers/amd/i2s_machine_dev/Makefile.inc | 1 + src/drivers/amd/i2s_machine_dev/chip.h | 19 +++++ src/drivers/amd/i2s_machine_dev/i2s_machine_dev.c | 92 +++++++++++++++++++++++ 4 files changed, 115 insertions(+) create mode 100644 src/drivers/amd/i2s_machine_dev/Kconfig create mode 100644 src/drivers/amd/i2s_machine_dev/Makefile.inc create mode 100644 src/drivers/amd/i2s_machine_dev/chip.h create mode 100644 src/drivers/amd/i2s_machine_dev/i2s_machine_dev.c (limited to 'src') 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 + +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 +#include +#include +#include +#include "chip.h" +#include + +#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 +}; -- cgit v1.2.3