Support generating a DMAR table and add a few helper routines as well.

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

 arch/x86/cpu/apollolake/hostbridge.c          | 104 ++++++++++++++++++
 .../include/asm/arch-apollolake/systemagent.h |   6 +
 2 files changed, 110 insertions(+)

diff --git a/arch/x86/cpu/apollolake/hostbridge.c 
b/arch/x86/cpu/apollolake/hostbridge.c
index 793853d5b5..5616d89950 100644
--- a/arch/x86/cpu/apollolake/hostbridge.c
+++ b/arch/x86/cpu/apollolake/hostbridge.c
@@ -1,16 +1,29 @@
 // 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.gagn...@intel.com> for Intel 
Corp.)
+ * (Written by Andrey Petrov <andrey.pet...@intel.com> for Intel Corp.)
+ *
+ * Portions from coreboot soc/intel/apollolake/chip.c
  */
 
+#define LOG_CATEGORY UCLASS_NORTHBRIDGE
+
 #include <common.h>
+#include <acpi_table.h>
 #include <dm.h>
 #include <dt-structs.h>
 #include <spl.h>
+#include <tables_csum.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 <dm/acpi.h>
 
 /**
  * struct apl_hostbridge_platdata - platform data for hostbridge
@@ -39,7 +52,9 @@ enum {
 
        PCIEXBAR_PCIEXBAREN     = 1 << 0,
 
+       BGSM                    = 0xb4,  /* Base GTT Stolen Memory */
        TSEG                    = 0xb8,  /* TSEG base */
+       TOLUD                   = 0xbc,
 };
 
 static int apl_hostbridge_early_init_pinctrl(struct udevice *dev)
@@ -164,6 +179,92 @@ 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_return_name(out_name, "RHUB");
+}
+
+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;
+}
+
+static int apl_hostbridge_remove(struct udevice *dev)
+{
+       /*
+        * TODO(s...@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;
+
+       /* All regions concerned for have 1 MiB alignment */
+       dm_pci_read_config32(dev, BGSM, &val);
+
+       return ALIGN_DOWN(val, 1 << 20);
+}
+
+ulong sa_get_tolud_base(struct udevice *dev)
+{
+       return sa_read_reg(dev, TOLUD);
+}
+
+ulong sa_get_gsm_base(struct udevice *dev)
+{
+       return sa_read_reg(dev, BGSM);
+}
+
+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,
+       .write_tables   = apl_acpi_hb_write_tables,
+};
+
 static const struct udevice_id apl_hostbridge_ids[] = {
        { .compatible = "intel,apl-hostbridge" },
        { }
@@ -175,5 +276,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,
 };
diff --git a/arch/x86/include/asm/arch-apollolake/systemagent.h 
b/arch/x86/include/asm/arch-apollolake/systemagent.h
index 206d8903fa..1553ec1cf4 100644
--- a/arch/x86/include/asm/arch-apollolake/systemagent.h
+++ b/arch/x86/include/asm/arch-apollolake/systemagent.h
@@ -34,4 +34,10 @@
  */
 void enable_bios_reset_cpl(void);
 
+/* API to get TOLUD base address */
+uintptr_t sa_get_tolud_base(struct udevice *dev);
+/* API to get GSM base address */
+ulong sa_get_gsm_base(struct udevice *dev);
+ulong sa_get_tseg_base(struct udevice *dev);
+
 #endif
-- 
2.25.0.341.g760bfbb309-goog

Reply via email to