diff mbox series

[v1,33/54] x86: apl: Add support for hostbridge ACPI generation

Message ID 20200726214408.v1.33.I986016a4667fb7ef9018d9ade3f48c76b9a3f7d3@changeid
State Superseded
Delegated to: Bin Meng
Headers show
Series dm: Add programatic generation of ACPI tables (part D) | expand

Commit Message

Simon Glass July 27, 2020, 3:45 a.m. UTC
Support generating a DMAR table and add a few helper routines as well.
Also set up NHLT so that audio works.

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

Changes in v1:
- Add support for NHLT table
- Capitalise ACPI_OPS_PTR
- Move the acpi.h header file to this commit
- Update commit message

 arch/x86/cpu/apollolake/hostbridge.c | 221 +++++++++++++++++++++++++--
 1 file changed, 212 insertions(+), 9 deletions(-)
diff mbox series

Patch

diff --git a/arch/x86/cpu/apollolake/hostbridge.c b/arch/x86/cpu/apollolake/hostbridge.c
index 056f7e57a9a..cf60fd8b021 100644
--- a/arch/x86/cpu/apollolake/hostbridge.c
+++ b/arch/x86/cpu/apollolake/hostbridge.c
@@ -1,17 +1,45 @@ 
 // SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright 2019 Google LLC
+ * Copyright (C) 2015 - 2017 Intel Corp.
+ * Copyright (C) 2017 - 2019 Siemens AG
+ * (Written by Alexandru Gagniuc <alexandrux.gagniuc@intel.com> for Intel Corp.)
+ * (Written by Andrey Petrov <andrey.petrov@intel.com> for Intel Corp.)
+ *
+ * Portions from coreboot soc/intel/apollolake/chip.c
  */
 
+#define LOG_CATEGORY UCLASS_NORTHBRIDGE
+
 #include <common.h>
 #include <dm.h>
 #include <dt-structs.h>
 #include <log.h>
 #include <spl.h>
+#include <tables_csum.h>
+#include <acpi/acpi_table.h>
+#include <asm/acpi_nhlt.h>
 #include <asm/intel_pinctrl.h>
 #include <asm/intel_regs.h>
+#include <asm/io.h>
 #include <asm/pci.h>
+#include <asm/arch/acpi.h>
 #include <asm/arch/systemagent.h>
+#include <dt-bindings/sound/nhlt.h>
+#include <dm/acpi.h>
+
+enum {
+	PCIEXBAR		= 0x60,
+	PCIEXBAR_LENGTH_256MB	= 0,
+	PCIEXBAR_LENGTH_128MB,
+	PCIEXBAR_LENGTH_64MB,
+
+	PCIEXBAR_PCIEXBAREN	= 1 << 0,
+
+	BGSM			= 0xb4,  /* Base GTT Stolen Memory */
+	TSEG			= 0xb8,  /* TSEG base */
+	TOLUD			= 0xbc,
+};
 
 /**
  * struct apl_hostbridge_platdata - platform data for hostbridge
@@ -32,17 +60,100 @@  struct apl_hostbridge_platdata {
 	pci_dev_t bdf;
 };
 
-enum {
-	PCIEXBAR		= 0x60,
-	PCIEXBAR_LENGTH_256MB	= 0,
-	PCIEXBAR_LENGTH_128MB,
-	PCIEXBAR_LENGTH_64MB,
+static const struct nhlt_format_config dmic_1ch_formats[] = {
+	/* 48 KHz 16-bits per sample. */
+	{
+		.num_channels = 1,
+		.sample_freq_khz = 48,
+		.container_bits_per_sample = 16,
+		.valid_bits_per_sample = 16,
+		.settings_file = "dmic-1ch-48khz-16b.dat",
+	},
+};
 
-	PCIEXBAR_PCIEXBAREN	= 1 << 0,
+static const struct nhlt_dmic_array_config dmic_1ch_mic_config = {
+	.tdm_config = {
+		.config_type = NHLT_TDM_MIC_ARRAY,
+	},
+	.array_type = NHLT_MIC_ARRAY_VENDOR_DEFINED,
+};
 
-	BGSM			= 0xb4,  /* Base GTT Stolen Memory */
-	TSEG			= 0xb8,  /* TSEG base */
-	TOLUD			= 0xbc,
+static const struct nhlt_endp_descriptor dmic_1ch_descriptors[] = {
+	{
+		.link = NHLT_LINK_PDM,
+		.device = NHLT_PDM_DEV,
+		.direction = NHLT_DIR_CAPTURE,
+		.vid = NHLT_VID,
+		.did = NHLT_DID_DMIC,
+		.cfg = &dmic_1ch_mic_config,
+		.cfg_size = sizeof(dmic_1ch_mic_config),
+		.formats = dmic_1ch_formats,
+		.num_formats = ARRAY_SIZE(dmic_1ch_formats),
+	},
+};
+
+static const struct nhlt_format_config dmic_2ch_formats[] = {
+	/* 48 KHz 16-bits per sample. */
+	{
+		.num_channels = 2,
+		.sample_freq_khz = 48,
+		.container_bits_per_sample = 16,
+		.valid_bits_per_sample = 16,
+		.settings_file = "dmic-2ch-48khz-16b.dat",
+	},
+};
+
+static const struct nhlt_dmic_array_config dmic_2ch_mic_config = {
+	.tdm_config = {
+		.config_type = NHLT_TDM_MIC_ARRAY,
+	},
+	.array_type = NHLT_MIC_ARRAY_2CH_SMALL,
+};
+
+static const struct nhlt_endp_descriptor dmic_2ch_descriptors[] = {
+	{
+		.link = NHLT_LINK_PDM,
+		.device = NHLT_PDM_DEV,
+		.direction = NHLT_DIR_CAPTURE,
+		.vid = NHLT_VID,
+		.did = NHLT_DID_DMIC,
+		.cfg = &dmic_2ch_mic_config,
+		.cfg_size = sizeof(dmic_2ch_mic_config),
+		.formats = dmic_2ch_formats,
+		.num_formats = ARRAY_SIZE(dmic_2ch_formats),
+	},
+};
+
+static const struct nhlt_format_config dmic_4ch_formats[] = {
+	/* 48 KHz 16-bits per sample. */
+	{
+		.num_channels = 4,
+		.sample_freq_khz = 48,
+		.container_bits_per_sample = 16,
+		.valid_bits_per_sample = 16,
+		.settings_file = "dmic-4ch-48khz-16b.dat",
+	},
+};
+
+static const struct nhlt_dmic_array_config dmic_4ch_mic_config = {
+	.tdm_config = {
+		.config_type = NHLT_TDM_MIC_ARRAY,
+	},
+	.array_type = NHLT_MIC_ARRAY_4CH_L_SHAPED,
+};
+
+static const struct nhlt_endp_descriptor dmic_4ch_descriptors[] = {
+	{
+		.link = NHLT_LINK_PDM,
+		.device = NHLT_PDM_DEV,
+		.direction = NHLT_DIR_CAPTURE,
+		.vid = NHLT_VID,
+		.did = NHLT_DID_DMIC,
+		.cfg = &dmic_4ch_mic_config,
+		.cfg_size = sizeof(dmic_4ch_mic_config),
+		.formats = dmic_4ch_formats,
+		.num_formats = ARRAY_SIZE(dmic_4ch_formats),
+	},
 };
 
 static int apl_hostbridge_early_init_pinctrl(struct udevice *dev)
@@ -167,6 +278,87 @@  static int apl_hostbridge_probe(struct udevice *dev)
 	return 0;
 }
 
+static int apl_acpi_hb_get_name(const struct udevice *dev, char *out_name)
+{
+	return acpi_copy_name(out_name, "RHUB");
+}
+
+#ifdef CONFIG_GENERATE_ACPI_TABLE
+static int apl_acpi_hb_write_tables(const struct udevice *dev,
+				    struct acpi_ctx *ctx)
+{
+	struct acpi_table_header *header;
+	struct acpi_dmar *dmar;
+	u32 val;
+
+	/*
+	 * Create DMAR table only if virtualization is enabled. Due to some
+	 * constraints on Apollo Lake SoC (some stepping affected), VTD could
+	 * not be enabled together with IPU. Doing so will override and disable
+	 * VTD while leaving CAPID0_A still reporting that VTD is available.
+	 * As in this case FSP will lock VTD to disabled state, we need to make
+	 * sure that DMAR table generation only happens when at least DEFVTBAR
+	 * is enabled. Otherwise the DMAR header will be generated while the
+	 * content of the table will be missing.
+	 */
+	dm_pci_read_config32(dev, CAPID0_A, &val);
+	if ((val & VTD_DISABLE) ||
+	    !(readl(MCHBAR_REG(DEFVTBAR)) & VTBAR_ENABLED))
+		return 0;
+
+	log_debug("ACPI:    * DMAR\n");
+	dmar = (struct acpi_dmar *)ctx->current;
+	header = &dmar->header;
+	acpi_create_dmar(dmar, DMAR_INTR_REMAP);
+	ctx->current += sizeof(struct acpi_dmar);
+	apl_acpi_fill_dmar(ctx);
+
+	/* (Re)calculate length and checksum */
+	header->length = ctx->current - (void *)dmar;
+	header->checksum = table_compute_checksum((void *)dmar, header->length);
+
+	acpi_align(ctx);
+	acpi_add_table(ctx, dmar);
+	acpi_align(ctx);
+
+	return 0;
+}
+#endif
+
+static int apl_acpi_setup_nhlt(const struct udevice *dev, struct acpi_ctx *ctx)
+{
+	struct nhlt *nhlt = ctx->nhlt;
+	u32 channels;
+	ofnode node;
+
+	node = ofnode_find_subnode(dev_ofnode(dev), "nhlt");
+	if (ofnode_read_u32(node, "intel,dmic-channels", &channels))
+		return log_msg_ret("channels", -EINVAL);
+	switch (channels) {
+	case 1:
+		return nhlt_add_endpoints(nhlt, dmic_1ch_descriptors,
+					  ARRAY_SIZE(dmic_1ch_descriptors));
+	case 2:
+		return nhlt_add_endpoints(nhlt, dmic_2ch_descriptors,
+					  ARRAY_SIZE(dmic_2ch_descriptors));
+	case 4:
+		return nhlt_add_endpoints(nhlt, dmic_4ch_descriptors,
+					  ARRAY_SIZE(dmic_4ch_descriptors));
+	}
+
+	return log_msg_ret("channels", -EINVAL);
+}
+
+static int apl_hostbridge_remove(struct udevice *dev)
+{
+	/*
+	 * TODO(sjg@chromium.org): Consider adding code from coreboot's
+	 * platform_fsp_notify_status()
+	 */
+
+	return 0;
+}
+
 static ulong sa_read_reg(struct udevice *dev, int reg)
 {
 	u32 val;
@@ -192,6 +384,14 @@  ulong sa_get_tseg_base(struct udevice *dev)
 	return sa_read_reg(dev, TSEG);
 }
 
+struct acpi_ops apl_hostbridge_acpi_ops = {
+	.get_name	= apl_acpi_hb_get_name,
+#ifdef CONFIG_GENERATE_ACPI_TABLE
+	.write_tables	= apl_acpi_hb_write_tables,
+#endif
+	.setup_nhlt	= apl_acpi_setup_nhlt,
+};
+
 static const struct udevice_id apl_hostbridge_ids[] = {
 	{ .compatible = "intel,apl-hostbridge" },
 	{ }
@@ -203,5 +403,8 @@  U_BOOT_DRIVER(apl_hostbridge_drv) = {
 	.of_match	= apl_hostbridge_ids,
 	.ofdata_to_platdata = apl_hostbridge_ofdata_to_platdata,
 	.probe		= apl_hostbridge_probe,
+	.remove		= apl_hostbridge_remove,
 	.platdata_auto_alloc_size = sizeof(struct apl_hostbridge_platdata),
+	ACPI_OPS_PTR(&apl_hostbridge_acpi_ops)
+	.flags		= DM_FLAG_OS_PREPARE,
 };