soc/intel: Add Intel Xeon Scalable Processor support

This patch adds support for Intel Xeon-SP.

This patch is developed and verified with Skylake Scalable
Processor, which is a processor in Xeon-SP family. The code
is expected to be reusable for future geneations of Xeon-SP
processors, and will be updated with smaller targeted
patches accordingly, to add support for additional Xeon-SP
processors, to add features, and to improve the code base.

The Skylake-SP FSP is based on FSP 2.0. The FSP is a
proof-of-concept build. The binary is not shared in public,
when this patch is upstreamed.

Signed-off-by: Jonathan Zhang <jonzhang@fb.com>
Signed-off-by: Reddy Chagam <anjaneya.chagam@intel.com>
Tested-by: johnny_lin@wiwynn.com
Change-Id: Idc9c3bee17caf8b4841f0bc190cb1aa9d38fc23e
Reviewed-on: https://review.coreboot.org/c/coreboot/+/38548
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: David Hendricks <david.hendricks@gmail.com>
diff --git a/src/soc/intel/xeon_sp/uncore.c b/src/soc/intel/xeon_sp/uncore.c
new file mode 100644
index 0000000..adf3e3e
--- /dev/null
+++ b/src/soc/intel/xeon_sp/uncore.c
@@ -0,0 +1,305 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2019 - 2020 Intel Corporation
+ * Copyright (C) 2019 - 2020 Facebook Inc
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <cbmem.h>
+#include <console/console.h>
+#include <cpu/x86/lapic.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <soc/iomap.h>
+#include <soc/pci_devs.h>
+#include <soc/ramstage.h>
+#include <soc/soc_util.h>
+
+struct map_entry {
+	uint32_t    reg;
+	int         is_64_bit;
+	int         is_limit;
+	int         mask_bits;
+	const char *description;
+};
+
+enum {
+	TOHM_REG,
+	MMIOL_REG,
+	MMCFG_BASE_REG,
+	MMCFG_LIMIT_REG,
+	TOLM_REG,
+	ME_BASE_REG,
+	ME_LIMIT_REG,
+	TSEG_BASE_REG,
+	TSEG_LIMIT_REG,
+	/* Must be last. */
+	NUM_MAP_ENTRIES
+};
+
+static struct map_entry memory_map[NUM_MAP_ENTRIES] = {
+		[TOHM_REG] = MAP_ENTRY_LIMIT_64(VTD_TOHM_CSR, 26, "TOHM"),
+		[MMIOL_REG] = MAP_ENTRY_BASE_32(VTD_MMIOL_CSR, "MMIOL"),
+		[MMCFG_BASE_REG] = MAP_ENTRY_BASE_64(VTD_MMCFG_BASE_CSR, "MMCFG_BASE"),
+		[MMCFG_LIMIT_REG] = MAP_ENTRY_LIMIT_64(VTD_MMCFG_LIMIT_CSR, 26, "MMCFG_LIMIT"),
+		[TOLM_REG] = MAP_ENTRY_LIMIT_32(VTD_TOLM_CSR, 26, "TOLM"),
+		[ME_BASE_REG] = MAP_ENTRY_BASE_64(VTD_ME_BASE_CSR, "ME_BASE"),
+		[ME_LIMIT_REG] = MAP_ENTRY_LIMIT_64(VTD_ME_LIMIT_CSR, 19, "ME_LIMIT"),
+		[TSEG_BASE_REG] = MAP_ENTRY_BASE_32(VTD_TSEG_BASE_CSR, "TSEGMB_BASE"),
+		[TSEG_LIMIT_REG] = MAP_ENTRY_LIMIT_32(VTD_TSEG_LIMIT_CSR, 20, "TSEGMB_LIMIT"),
+};
+
+static void read_map_entry(struct device *dev, struct map_entry *entry,
+	uint64_t *result)
+{
+	uint64_t value;
+	uint64_t mask;
+
+	/* All registers are on a 1MiB granularity. */
+	mask = ((1ULL << entry->mask_bits) - 1);
+	mask = ~mask;
+
+	value = 0;
+
+	if (entry->is_64_bit) {
+		value = pci_read_config32(dev, entry->reg + sizeof(uint32_t));
+		value <<= 32;
+	}
+
+	value |= (uint64_t)pci_read_config32(dev, entry->reg);
+	value &= mask;
+
+	if (entry->is_limit)
+		value |= ~mask;
+
+	*result = value;
+}
+
+static void mc_read_map_entries(struct device *dev, uint64_t *values)
+{
+	int i;
+	for (i = 0; i < NUM_MAP_ENTRIES; i++)
+		read_map_entry(dev, &memory_map[i], &values[i]);
+}
+
+static void mc_report_map_entries(struct device *dev, uint64_t *values)
+{
+	int i;
+	for (i = 0; i < NUM_MAP_ENTRIES; i++) {
+		printk(BIOS_DEBUG, "MC MAP: %s: 0x%llx\n",
+		       memory_map[i].description, values[i]);
+	}
+}
+
+/*
+ * Host Memory Map:
+ *
+ * +--------------------------+ TOCM (2 pow 46 - 1)
+ * |     Reserved             |
+ * +--------------------------+
+ * |     MMIOH (relocatable)  |
+ * +--------------------------+
+ * |     PCISeg               |
+ * +--------------------------+ TOHM
+ * |    High DRAM Memory      |
+ * +--------------------------+ 4GiB (0x100000000)
+ * +--------------------------+ 0xFFFF_FFFF
+ * |     Firmware             |
+ * +--------------------------+ 0xFF00_0000
+ * |     Reserved             |
+ * +--------------------------+ 0xFEF0_0000
+ * |     Local xAPIC          |
+ * +--------------------------+ 0xFEE0_0000
+ * |     HPET/LT/TPM/Others   |
+ * +--------------------------+ 0xFED0_0000
+ * |     I/O xAPIC            |
+ * +--------------------------+ 0xFEC0_0000
+ * |     Reserved             |
+ * +--------------------------+ 0xFEB8_0000
+ * |     Reserved             |
+ * +--------------------------+ 0xFEB0_0000
+ * |     Reserved             |
+ * +--------------------------+ 0xFE00_0000
+ * |     MMIOL (relocatable)  |
+ * |     P2SB PCR cfg BAR     | (0xfd000000 - 0xfdffffff
+ * |     BAR space            | [mem 0x90000000-0xfcffffff] available for PCI devices
+ * +--------------------------+ 0x9000_0000
+ * |PCIe MMCFG (relocatable)  | CONFIG_MMCONF_BASE_ADDRESS 64 or 256MB
+ * |                          | (0x80000000 - 0x8fffffff, 0x40000)
+ * +--------------------------+ TOLM
+ * |     MEseg (relocatable)  | 32, 64, 128 or 256 MB (0x78000000 - 0x7fffffff, 0x20000)
+ * +--------------------------+
+ * |     Tseg (relocatable)   | N x 8MB (0x70000000 - 0x77ffffff, 0x20000)
+ * +--------------------------+ cbmem_top
+ * |     Reserved - CBMEM     | (0x6fffe000 - 0x6fffffff, 0x2000)
+ * +--------------------------+
+ * |     Reserved - FSP       | (0x6fbfe000 - 0x6fffdfff, 0x400000)
+ * +--------------------------+ top_of_ram (0x6fbfdfff)
+ * |     Low DRAM Memory      |
+ * +--------------------------+ FFFFF (1MB)
+ * |     E & F segments       |
+ * +--------------------------+ E0000
+ * |     C & D segments       |
+ * +--------------------------+ C0000
+ * |     VGA & SMM Memory     |
+ * +--------------------------+ A0000
+ * |    Conventional Memory   |
+ * |      (DOS Range)         |
+ * +--------------------------+ 0
+ */
+
+static void mc_add_dram_resources(struct device *dev, int *res_count)
+{
+	struct range_entry fsp_mem;
+	uint64_t base_kb;
+	uint64_t size_kb;
+	uint64_t top_of_ram;
+	uint64_t mc_values[NUM_MAP_ENTRIES];
+	struct resource *resource;
+	int index = *res_count;
+
+	fsp_find_reserved_memory(&fsp_mem);
+
+	/* Read in the MAP registers and report their values. */
+	mc_read_map_entries(dev, &mc_values[0]);
+	mc_report_map_entries(dev, &mc_values[0]);
+
+	top_of_ram = range_entry_base(&fsp_mem) - 1;
+	printk(BIOS_SPEW, "cbmem_top: 0x%lx, fsp range: [0x%llx - 0x%llx], top_of_ram: 0x%llx\n",
+		(uintptr_t) cbmem_top(), range_entry_base(&fsp_mem),
+		range_entry_end(&fsp_mem), top_of_ram);
+
+	/* Conventional Memory (DOS region, 0x0 to 0x9FFFF) */
+	base_kb = 0;
+	size_kb = (0xa0000 >> 10);
+	LOG_MEM_RESOURCE("legacy_ram", dev, index, base_kb, size_kb);
+	ram_resource(dev, index++, base_kb, size_kb);
+
+	/* 1MB -> top_of_ram i.e., fsp_mem_base+1*/
+	base_kb = (0x100000 >> 10);
+	size_kb = (top_of_ram - 0xfffff) >> 10;
+	LOG_MEM_RESOURCE("low_ram", dev, index, base_kb, size_kb);
+	ram_resource(dev, index++, base_kb, size_kb);
+
+	/*
+	 * FSP meomoy, CBMem regions are already added as reserved
+	 * Add TSEG and MESEG Regions as reserved memory
+	 * src/drivers/intel/fsp2_0/memory_init.c sets CBMEM reserved size
+	 * arch_upd->BootLoaderTolumSize = cbmem_overhead_size(); == 2 * CBMEM_ROOT_MIN_SIZE
+	 *    typically 0x2000
+	 *  Example config:
+	 *  FSP_RESERVED_MEMORY_RESOURCE_HOB
+	 *     FspReservedMemoryResource Base : 6FBFE000
+	 *     FspReservedMemoryResource Size : 400000
+	 *  FSP_BOOT_LOADER_TOLUM_HOB
+	 *     FspBootLoaderTolum Base : 6FFFE000
+	 *     FspBootLoaderTolum Size : 2000
+	 */
+
+	/* Mark TSEG/SMM region as reserved */
+	base_kb = (mc_values[TSEG_BASE_REG] >> 10);
+	size_kb = (mc_values[TSEG_LIMIT_REG] - mc_values[TSEG_BASE_REG] + 1) >> 10;
+	LOG_MEM_RESOURCE("mmio_tseg", dev, index, base_kb, size_kb);
+	reserved_ram_resource(dev, index++, base_kb, size_kb);
+
+	/* Mark region between TSEG - TOLM (eg. MESEG) as reserved */
+	if (mc_values[TSEG_LIMIT_REG] < mc_values[TOLM_REG]) {
+		base_kb = ((mc_values[TSEG_LIMIT_REG] + 1) >> 10);
+		size_kb = (mc_values[TOLM_REG] - mc_values[TSEG_LIMIT_REG]) >> 10;
+		LOG_MEM_RESOURCE("mmio_tolm", dev, index, base_kb, size_kb);
+		reserved_ram_resource(dev, index++, base_kb, size_kb);
+	}
+
+	/* 4GiB -> TOHM */
+	if (mc_values[TOHM_REG] > 0x100000000) {
+		base_kb = (0x100000000 >> 10);
+		size_kb = (mc_values[TOHM_REG] - 0x100000000 + 1) >> 10;
+		LOG_MEM_RESOURCE("high_ram", dev, index, base_kb, size_kb);
+		ram_resource(dev, index++, base_kb, size_kb);
+	}
+
+	/* add MMIO CFG resource */
+	resource = new_resource(dev, index++);
+	resource->base = (resource_t) mc_values[MMCFG_BASE_REG];
+	resource->size = (resource_t) (mc_values[MMCFG_LIMIT_REG] -
+		mc_values[MMCFG_BASE_REG] + 1);
+	resource->flags = IORESOURCE_MEM | IORESOURCE_RESERVE |
+		IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
+	LOG_MEM_RESOURCE("mmiocfg_res", dev, index-1, (resource->base >> 10),
+		(resource->size >> 10));
+
+	/* add Local APIC resource */
+	resource = new_resource(dev, index++);
+	resource->base = LAPIC_DEFAULT_BASE;
+	resource->size = 0x00001000;
+	resource->flags = IORESOURCE_MEM | IORESOURCE_RESERVE |
+		IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
+	LOG_MEM_RESOURCE("apic_res", dev, index-1, (resource->base >> 10),
+		(resource->size >> 10));
+
+	/*
+	 * Add legacy region as reserved - 0xa000 - 1MB
+	 * Reserve everything between A segment and 1MB:
+	 *
+	 * 0xa0000 - 0xbffff: legacy VGA
+	 * 0xc0000 - 0xfffff: RAM
+	 */
+	base_kb = VGA_BASE_ADDRESS >> 10;
+	size_kb = VGA_BASE_SIZE >> 10;
+	LOG_MEM_RESOURCE("legacy_mmio", dev, index, base_kb, size_kb);
+	mmio_resource(dev, index++, base_kb, size_kb);
+
+	base_kb = (0xc0000 >> 10);
+	size_kb = (0x100000 - 0xc0000) >> 10;
+	LOG_MEM_RESOURCE("legacy_write_protect", dev, index, base_kb, size_kb);
+	reserved_ram_resource(dev, index++, base_kb, size_kb);
+
+	*res_count = index;
+}
+
+static void mmapvtd_read_resources(struct device *dev)
+{
+	int index = 0;
+
+	/* Read standard PCI resources. */
+	pci_dev_read_resources(dev);
+
+	/* Calculate and add DRAM resources. */
+	mc_add_dram_resources(dev, &index);
+}
+
+static void mmapvtd_init(struct device *dev)
+{
+}
+
+static struct device_operations mmapvtd_ops = {
+	.read_resources    = mmapvtd_read_resources,
+	.set_resources     = pci_dev_set_resources,
+	.enable_resources  = pci_dev_enable_resources,
+	.init              = mmapvtd_init,
+	.ops_pci           = &soc_pci_ops,
+#if CONFIG(HAVE_ACPI_TABLES)
+	.acpi_inject_dsdt_generator = NULL,
+#endif
+};
+
+static const unsigned short mmapvtd_ids[] = {
+	MMAP_VTD_CFG_REG_DEVID, /* Memory Map/Intel® VT-d Configuration Registers */
+	0
+};
+
+static const struct pci_driver mmapvtd_driver __pci_driver = {
+	.ops      = &mmapvtd_ops,
+	.vendor   = PCI_VENDOR_ID_INTEL,
+	.devices  = mmapvtd_ids
+};