summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/soc/intel/fsp_broadwell_de/acpi.c99
-rw-r--r--src/soc/intel/fsp_broadwell_de/include/soc/acpi.h4
-rw-r--r--src/soc/intel/fsp_broadwell_de/include/soc/broadwell_de.h3
-rw-r--r--src/soc/intel/fsp_broadwell_de/include/soc/pci_devs.h5
-rw-r--r--src/soc/intel/fsp_broadwell_de/northcluster.c17
5 files changed, 121 insertions, 7 deletions
diff --git a/src/soc/intel/fsp_broadwell_de/acpi.c b/src/soc/intel/fsp_broadwell_de/acpi.c
index 1e088684c0..1647505820 100644
--- a/src/soc/intel/fsp_broadwell_de/acpi.c
+++ b/src/soc/intel/fsp_broadwell_de/acpi.c
@@ -4,6 +4,7 @@
* Copyright (C) 2007-2009 coresystems GmbH
* Copyright (C) 2013 Google Inc.
* Copyright (C) 2015-2016 Intel Corp.
+ * Copyright (C) 2016 Siemens AG
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,6 +36,7 @@
#include <soc/msr.h>
#include <soc/pattrs.h>
#include <soc/pci_devs.h>
+#include <soc/broadwell_de.h>
#include <chip.h>
uint16_t get_pmbase(void)
@@ -312,6 +314,103 @@ void acpi_fill_in_fadt(acpi_fadt_t *fadt, acpi_facs_t *facs, void *dsdt)
header->checksum = acpi_checksum((void *) fadt, sizeof(acpi_fadt_t));
}
+static unsigned long acpi_fill_dmar(unsigned long current)
+{
+ uint32_t vtbar, tmp = current;
+ struct device *dev = dev_find_slot(0, VTD_DEV_FUNC);
+ uint16_t bdf, hpet_bdf[8];
+ uint8_t i, j;
+
+ if (!dev)
+ return current;
+
+ vtbar = pci_read_config32(dev, VTBAR_OFFSET) & VTBAR_MASK;
+ if (!vtbar)
+ return current;
+
+ current += acpi_create_dmar_drhd(current,
+ DRHD_INCLUDE_PCI_ALL, 0, vtbar);
+ /* The IIO I/O APIC is fixed on PCI 00:05.4 on Broadwell-DE */
+ current += acpi_create_dmar_drhd_ds_ioapic(current,
+ 9, 0, 5, 4);
+ /* Get the PCI BDF for the PCH I/O APIC */
+ dev = dev_find_slot(0, LPC_DEV_FUNC);
+ bdf = pci_read_config16(dev, 0x6c);
+ current += acpi_create_dmar_drhd_ds_ioapic(current,
+ 8, (bdf >> 8), PCI_SLOT(bdf), PCI_FUNC(bdf));
+
+ /*
+ * Check if there are different PCI paths for the 8 HPET timers
+ * and add every different PCI path as a separate HPET entry.
+ * Although the DMAR specification talks about HPET block for this
+ * entry, it is possible to assign a unique PCI BDF to every single
+ * timer within a HPET block which will result in different source
+ * IDs reported by a generated MSI.
+ * In default configuration every single timer will have the same
+ * PCI BDF which will result in a single HPET entry in DMAR table.
+ * I have checked several different systems and all of them had one
+ * single entry for HPET in DMAR.
+ */
+ memset(hpet_bdf, 0, sizeof(hpet_bdf));
+ /* Get all unique HPET paths. */
+ for (i = 0; i < ARRAY_SIZE(hpet_bdf); i++) {
+ bdf = pci_read_config16(dev, 0x70 + (i * 2));
+ for (j = 0; j < i; j++) {
+ if (hpet_bdf[j] == bdf)
+ break;
+ }
+ if (j == i)
+ hpet_bdf[i] = bdf;
+ }
+ /* Create one HPET entry in DMAR for every unique HPET PCI path. */
+ for (i = 0; i < ARRAY_SIZE(hpet_bdf); i++) {
+ if (hpet_bdf[i])
+ current += acpi_create_dmar_drhd_ds_msi_hpet(current,
+ 0, (hpet_bdf[i] >> 8), PCI_SLOT(hpet_bdf[i]),
+ PCI_FUNC(hpet_bdf[i]));
+ }
+ acpi_dmar_drhd_fixup(tmp, current);
+
+ /* Create root port ATSR capability */
+ tmp = current;
+ current += acpi_create_dmar_atsr(current, 0, 0);
+ /* Add one entry to ATSR for each PCI root port */
+ dev = all_devices;
+ do {
+ dev = dev_find_class(PCI_CLASS_BRIDGE_PCI << 8, dev);
+ if (dev && dev->bus->secondary == 0 &&
+ PCI_SLOT(dev->path.pci.devfn) <= 3)
+ current += acpi_create_dmar_drhd_ds_pci_br(current,
+ dev->bus->secondary,
+ PCI_SLOT(dev->path.pci.devfn),
+ PCI_FUNC(dev->path.pci.devfn));
+ } while (dev);
+ acpi_dmar_atsr_fixup(tmp, current);
+
+ return current;
+}
+
+unsigned long northcluster_write_acpi_tables(struct device *const dev,
+ unsigned long current,
+ struct acpi_rsdp *const rsdp)
+{
+ acpi_dmar_t *const dmar = (acpi_dmar_t *)current;
+ device_t vtdev = dev_find_slot(0, PCI_DEVFN(5, 0));
+
+ /* Create DMAR table only if virtualization is enabled */
+ if (!(pci_read_config32(vtdev, 0x180) & 0x01))
+ return current;
+
+ printk(BIOS_DEBUG, "ACPI: * DMAR\n");
+ acpi_create_dmar(dmar, DMAR_INTR_REMAP, acpi_fill_dmar);
+ current += dmar->header.length;
+ current = acpi_align_current(current);
+ acpi_add_table(rsdp, dmar);
+ current = acpi_align_current(current);
+
+ return current;
+}
+
static int calculate_power(int tdp, int p1_ratio, int ratio)
{
u32 m;
diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/acpi.h b/src/soc/intel/fsp_broadwell_de/include/soc/acpi.h
index f717d15a3b..da552cc615 100644
--- a/src/soc/intel/fsp_broadwell_de/include/soc/acpi.h
+++ b/src/soc/intel/fsp_broadwell_de/include/soc/acpi.h
@@ -3,6 +3,7 @@
*
* Copyright (C) 2013 Google, Inc.
* Copyright (C) 2015-2016 Intel Corp.
+ * Copyright (C) 2016 Siemens AG
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,5 +24,8 @@ void acpi_create_intel_hpet(acpi_hpet_t *hpet);
void acpi_fill_in_fadt(acpi_fadt_t *fadt, acpi_facs_t *facs, void *dsdt);
unsigned long acpi_madt_irq_overrides(unsigned long current);
uint16_t get_pmbase(void);
+unsigned long northcluster_write_acpi_tables(struct device *const dev,
+ unsigned long current,
+ struct acpi_rsdp *const rsdp);
#endif /* _SOC_ACPI_H_ */
diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/broadwell_de.h b/src/soc/intel/fsp_broadwell_de/include/soc/broadwell_de.h
index 6828d03dc9..85298a5ccd 100644
--- a/src/soc/intel/fsp_broadwell_de/include/soc/broadwell_de.h
+++ b/src/soc/intel/fsp_broadwell_de/include/soc/broadwell_de.h
@@ -17,4 +17,7 @@
#ifndef _SOC_BROADWELL_DE_H_
#define _SOC_BROADWELL_DE_H_
+#define VTBAR_OFFSET 0x180
+#define VTBAR_MASK 0xffffe000
+
#endif /* _SOC_BROADWELL_DE_H_ */
diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/pci_devs.h b/src/soc/intel/fsp_broadwell_de/include/soc/pci_devs.h
index 5f3cfb963a..c5bb77ab75 100644
--- a/src/soc/intel/fsp_broadwell_de/include/soc/pci_devs.h
+++ b/src/soc/intel/fsp_broadwell_de/include/soc/pci_devs.h
@@ -27,6 +27,11 @@
#define SOC_DEVID_ES2 0x6F00
#define SOC_DEV_FUNC PCI_DEVFN(SOC_DEV, SOC_FUNC)
+#define VTD_DEV 5
+#define VTD_FUNC 0
+#define VTD_DEVID 0x6f28
+#define VTD_DEV_FUNC PCI_DEVFN(VTD_DEV, VTD_FUNC)
+
#define LPC_DEV 31
#define LPC_FUNC 0
#define LPC_DEVID 0x8C42
diff --git a/src/soc/intel/fsp_broadwell_de/northcluster.c b/src/soc/intel/fsp_broadwell_de/northcluster.c
index 38872b4435..c15ff5f2fe 100644
--- a/src/soc/intel/fsp_broadwell_de/northcluster.c
+++ b/src/soc/intel/fsp_broadwell_de/northcluster.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2013 Google Inc.
* Copyright (C) 2015-2016 Intel Corp.
+ * Copyright (C) 2016 Siemens AG
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,6 +25,7 @@
#include <soc/iomap.h>
#include <soc/pci_devs.h>
#include <soc/ramstage.h>
+#include <soc/acpi.h>
static const int legacy_hole_base_k = 0xa0000 / 1024;
static const int legacy_hole_size_k = 384;
@@ -133,14 +135,15 @@ static void nc_enable(device_t dev)
}
static struct device_operations nc_ops = {
- .read_resources = nc_read_resources,
+ .read_resources = nc_read_resources,
.acpi_fill_ssdt_generator = generate_cpu_entries,
- .set_resources = pci_dev_set_resources,
- .enable_resources = pci_dev_enable_resources,
- .init = NULL,
- .enable = &nc_enable,
- .scan_bus = 0,
- .ops_pci = &soc_pci_ops,
+ .write_acpi_tables = northcluster_write_acpi_tables,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = NULL,
+ .enable = &nc_enable,
+ .scan_bus = 0,
+ .ops_pci = &soc_pci_ops,
};
static const struct pci_driver nc_driver __pci_driver = {