[096/108] tpm: cr50: Add ACPI support

Message ID 20200126220508.96.I1a9174fd9af26d0891e4ccfac247c7359b28b23e@changeid
State New
Headers show
Series
  • RFC: dm: Add programatic generation of ACPI tables
Related show

Commit Message

Simon Glass Jan. 27, 2020, 5:06 a.m.
Generate ACPI information for this device so that Linux can use it
correctly.

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

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

Patch

diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c
index d68534e7a9..5a3db87125 100644
--- a/drivers/tpm/cr50_i2c.c
+++ b/drivers/tpm/cr50_i2c.c
@@ -8,6 +8,8 @@ 
 #define LOG_CATEGORY UCLASS_TPM
 
 #include <common.h>
+#include <acpigen.h>
+#include <acpi_device.h>
 #include <dm.h>
 #include <i2c.h>
 #include <irq.h>
@@ -17,6 +19,7 @@ 
 #include <asm/io.h>
 #include <asm/arch/iomap.h>
 #include <asm/arch/pm.h>
+#include <dm/acpi.h>
 
 enum {
 	TIMEOUT_INIT_MS		= 30000, /* Very long timeout for TPM init */
@@ -580,6 +583,53 @@  static int cr50_i2c_cleanup(struct udevice *dev)
 	return 0;
 }
 
+static int cr50_acpi_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx)
+{
+	char scope[ACPI_PATH_MAX];
+	char name[ACPI_NAME_MAX];
+	const char *hid;
+	int ret;
+
+	ret = acpi_device_scope(dev, scope, sizeof(scope));
+	if (ret)
+		return log_msg_ret("scope", ret);
+	ret = acpi_device_name(dev, name);
+	if (ret)
+		return log_msg_ret("name", ret);
+
+	hid = dev_read_string(dev, "acpi,hid");
+	if (!hid)
+		return log_msg_ret("hid", ret);
+
+	/* Device */
+	acpigen_write_scope(ctx, scope);
+	acpigen_write_device(ctx, name);
+	acpigen_write_name_string(ctx, "_HID", hid);
+	acpigen_write_name_integer(ctx, "_UID",
+				   dev_read_u32_default(dev, "acpi,uid", 0));
+	acpigen_write_name_string(ctx, "_DDN",
+				  dev_read_string(dev, "acpi,desc"));
+	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);
+	ret = acpi_device_write_interrupt_or_gpio(ctx, (struct udevice *)dev,
+						  "ready-gpios");
+	if (ret)
+		return log_msg_ret("irq_gpio", ret);
+
+	acpigen_write_resourcetemplate_footer(ctx);
+
+	acpigen_pop_len(ctx); /* Device */
+	acpigen_pop_len(ctx); /* Scope */
+
+	return 0;
+}
+
 enum {
 	TPM_TIMEOUT_MS		= 5,
 	SHORT_TIMEOUT_MS	= 750,
@@ -652,6 +702,10 @@  static int cr50_i2c_probe(struct udevice *dev)
 	return 0;
 }
 
+struct acpi_ops cr50_acpi_ops = {
+	.fill_ssdt	= cr50_acpi_fill_ssdt,
+};
+
 static const struct tpm_ops cr50_i2c_ops = {
 	.open		= cr50_i2c_open,
 	.get_desc	= cr50_i2c_get_desc,
@@ -674,5 +728,6 @@  U_BOOT_DRIVER(cr50_i2c) = {
 	.probe	= cr50_i2c_probe,
 	.remove	= cr50_i2c_cleanup,
 	.priv_auto_alloc_size = sizeof(struct cr50_priv),
+	acpi_ops_ptr(&cr50_acpi_ops)
 	.flags		= DM_FLAG_OS_PREPARE,
 };