soc/intel/common/block: Add Intel common systemagent support

Add Intel common systemagent support for romstage and ramstage.
Include soc specific macros need to compile systemagent common code.

Change-Id: I969ff187e3d4199864cb2e9c9a13f4d04158e27c
Signed-off-by: V Sowmya <v.sowmya@intel.com>
Signed-off-by: Subrata Banik <subrata.banik@intel.com>
Reviewed-on: https://review.coreboot.org/19668
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
diff --git a/src/soc/intel/common/block/include/intelblocks/systemagent.h b/src/soc/intel/common/block/include/intelblocks/systemagent.h
index 77248bb..22a2b8d0 100644
--- a/src/soc/intel/common/block/include/intelblocks/systemagent.h
+++ b/src/soc/intel/common/block/include/intelblocks/systemagent.h
@@ -16,22 +16,77 @@
 #ifndef SOC_INTEL_COMMON_BLOCK_SA_H
 #define SOC_INTEL_COMMON_BLOCK_SA_H
 
+#include <device/device.h>
+#include <soc/iomap.h>
+#include <stddef.h>
+
 /* Device 0:0.0 PCI configuration space */
+#define MCHBAR		0x48
+#define PCIEXBAR		0x60
+#define TOUUD	0xa8 /* Top of Upper Usable DRAM */
+#define BDSM	0xb0 /* Base Data Stolen Memory */
+#define BGSM	0xb4 /* Base GTT Stolen Memory */
+#define TSEG	0xb8 /* TSEG base */
+#define TOLUD	0xbc /* Top of Low Used Memory */
 
-#define MCHBAR          0x48
-#define PCIEXBAR        0x60
-#define  PCIEXBAR_LENGTH_64MB       2
-#define  PCIEXBAR_LENGTH_128MB      1
-#define  PCIEXBAR_LENGTH_256MB      0
-#define  PCIEXBAR_PCIEXBAREN        (1 << 0)
-#define GGC             0x50
+/* MCHBAR */
+#define MCHBAR8(x)	(*(volatile u8 *)(MCH_BASE_ADDRESS + x))
+#define MCHBAR16(x)	(*(volatile u16 *)(MCH_BASE_ADDRESS + x))
+#define MCHBAR32(x)	(*(volatile u32 *)(MCH_BASE_ADDRESS + x))
 
-#define TOUUD           0xa8    /* Top of Upper Usable DRAM */
-#define BDSM            0xb0    /* Base Data Stolen Memory */
-#define BGSM            0xb4    /* Base GTT Stolen Memory */
-#define TSEG            0xb8    /* TSEG base */
-#define TOLUD           0xbc    /* Top of Low Used Memory */
-
+/* Perform System Agent Initialization during Bootblock phase */
 void bootblock_systemagent_early_init(void);
 
+/*
+ * Fixed MMIO range
+ *   INDEX = Either PCI configuration space registers or MMIO offsets
+ *   mapped from REG.
+ *   BASE = 32 bit Address.
+ *   SIZE = base length
+ *   DESCRIPTION = Name of the register/offset.
+ */
+struct sa_mmio_descriptor {
+	unsigned int index;
+	uintptr_t base;
+	size_t size;
+	const char *description;
+};
+
+/* API to set Fixed MMIO addresss into PCI configuration space */
+void sa_set_pci_bar(const struct sa_mmio_descriptor *fixed_set_resources,
+		size_t count);
+/* API to set Fixed MMIO addresss into MCH base address */
+void sa_set_mch_bar(const struct sa_mmio_descriptor *fixed_set_resources,
+		size_t count);
+/*
+ * API to program fixed mmio resource range based on SoC input
+ * struct sa_mmio_descriptor
+ */
+void sa_add_fixed_mmio_resources(struct device *dev, int *resource_cnt,
+	const struct sa_mmio_descriptor *sa_fixed_resources, size_t count);
+/*
+ * API to set BIOS Reset CPL through MCHBAR
+ * SoC to provide BIOS_RESET_CPL register offset through soc/systemagent.h
+ */
+void enable_bios_reset_cpl(void);
+/* API to enable PAM regisers */
+void enable_pam_region(void);
+/* API to enable Power Aware Interrupt Routing through MCHBAR */
+void enable_power_aware_intr(void);
+
+/*
+ * SoC overrides
+ *
+ * All new SoC must implement below functionality for ramstage.
+ */
+
+/* Perform System Agent Initialization during Ramstage phase */
+void soc_systemagent_init(struct device *dev);
+/*
+ * SoC call to provide all known fixed memory ranges for Device 0:0.0.
+ * SoC function should provide fixed resource ranges in form of
+ * struct sa_mmio_descriptor along with resource count.
+ */
+void soc_add_fixed_mmio_resources(struct device *dev, int *resource_cnt);
+
 #endif	/* SOC_INTEL_COMMON_BLOCK_SA_H */
diff --git a/src/soc/intel/common/block/systemagent/Kconfig b/src/soc/intel/common/block/systemagent/Kconfig
index 773a56b..01a4f8e 100644
--- a/src/soc/intel/common/block/systemagent/Kconfig
+++ b/src/soc/intel/common/block/systemagent/Kconfig
@@ -24,3 +24,15 @@
 
 config PCIEX_LENGTH_64MB
 	bool "64MB"
+
+config SA_ENABLE_IMR
+	bool
+	default n
+	help
+	  This option allows you to add the isolated memory ranges (IMRs).
+
+config SA_ENABLE_DPR
+	bool
+	default n
+	help
+	  This option allows you to add the DMA Protected Range (DPR).
diff --git a/src/soc/intel/common/block/systemagent/Makefile.inc b/src/soc/intel/common/block/systemagent/Makefile.inc
index 75d5626..81e680b 100644
--- a/src/soc/intel/common/block/systemagent/Makefile.inc
+++ b/src/soc/intel/common/block/systemagent/Makefile.inc
@@ -1 +1,4 @@
-bootblock-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA) += systemagent.c
+bootblock-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA) += systemagent_early.c
+romstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA) += systemagent_early.c
+ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA) += systemagent_early.c
+ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA) += systemagent.c
diff --git a/src/soc/intel/common/block/systemagent/systemagent.c b/src/soc/intel/common/block/systemagent/systemagent.c
index 58e2c7e..f2e74cc 100644
--- a/src/soc/intel/common/block/systemagent/systemagent.c
+++ b/src/soc/intel/common/block/systemagent/systemagent.c
@@ -14,46 +14,295 @@
  */
 
 #include <arch/io.h>
-#include <commonlib/helpers.h>
+#include <cbmem.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
 #include <intelblocks/systemagent.h>
+#include <soc/iomap.h>
 #include <soc/pci_devs.h>
+#include <soc/systemagent.h>
+#include "systemagent_def.h"
 
-void bootblock_systemagent_early_init(void)
+/* SoC override function */
+__attribute__((weak)) void soc_systemagent_init(struct device *dev)
 {
-	uint32_t reg;
-	uint8_t pciexbar_length;
-
-	/*
-	 * The PCIEXBAR is assumed to live in the memory mapped IO space under
-	 * 4GiB.
-	 */
-	reg = 0;
-	pci_io_write_config32(SA_DEV_ROOT, PCIEXBAR + 4, reg);
-
-	/* Get PCI Express Region Length */
-	switch (CONFIG_SA_PCIEX_LENGTH) {
-	case 256 * MiB:
-		pciexbar_length = PCIEXBAR_LENGTH_256MB;
-		break;
-	case 128 * MiB:
-		pciexbar_length = PCIEXBAR_LENGTH_128MB;
-		break;
-	case 64 * MiB:
-		pciexbar_length = PCIEXBAR_LENGTH_64MB;
-		break;
-	default:
-		pciexbar_length = PCIEXBAR_LENGTH_256MB;
-	}
-	reg = CONFIG_MMCONF_BASE_ADDRESS | (pciexbar_length << 1)
-				| PCIEXBAR_PCIEXBAREN;
-	pci_io_write_config32(SA_DEV_ROOT, PCIEXBAR, reg);
-
-	/*
-	 * TSEG defines the base of SMM range. BIOS determines the base
-	 * of TSEG memory which must be at or below Graphics base of GTT
-	 * Stolen memory, hence its better to clear TSEG register early
-	 * to avoid power on default non-zero value (if any).
-	 */
-	pci_write_config32(SA_DEV_ROOT, TSEG, 0);
+	/* no-op */
 }
 
+__attribute__((weak)) void soc_add_fixed_mmio_resources(struct device *dev,
+		int *resource_cnt)
+{
+	/* no-op */
+}
+
+/*
+ * Add all known fixed MMIO ranges that hang off the host bridge/memory
+ * controller device.
+ */
+void sa_add_fixed_mmio_resources(struct device *dev, int *resource_cnt,
+	const struct sa_mmio_descriptor *sa_fixed_resources, size_t count)
+{
+	int i;
+	int index = *resource_cnt;
+
+	for (i = 0; i < count; i++) {
+		uintptr_t base;
+		size_t size;
+
+		size = sa_fixed_resources[i].size;
+		base = sa_fixed_resources[i].base;
+
+		mmio_resource(dev, index++, base / KiB, size / KiB);
+	}
+
+	*resource_cnt = index;
+}
+
+/*
+ * DRAM memory mapped register
+ *
+ * TOUUD: This 64 bit register defines the Top of Upper Usable DRAM
+ * TOLUD: This 32 bit register defines the Top of Low Usable DRAM
+ * BGSM: This register contains the base address of stolen DRAM memory for GTT
+ * TSEG: This register contains the base address of TSEG DRAM memory
+ */
+static const struct sa_mem_map_descriptor sa_memory_map[MAX_MAP_ENTRIES] = {
+	{ TOUUD, true, "TOUUD" },
+	{ TOLUD, false, "TOLUD" },
+	{ BGSM, false, "BGSM" },
+	{ TSEG, false, "TSEG" },
+};
+
+/* Read DRAM memory map register value through PCI configuration space */
+static void sa_read_map_entry(device_t dev,
+		const struct sa_mem_map_descriptor *entry, uint64_t *result)
+{
+	uint64_t value = 0;
+
+	if (entry->is_64_bit) {
+		value = pci_read_config32(dev, entry->reg + 4);
+		value <<= 32;
+	}
+
+	value |= pci_read_config32(dev, entry->reg);
+	/* All registers are on a 1MiB granularity. */
+	value = ALIGN_DOWN(value, 1 * MiB);
+
+	*result = value;
+}
+
+static void sa_get_mem_map(struct device *dev, uint64_t *values)
+{
+	int i;
+	for (i = 0; i < MAX_MAP_ENTRIES; i++)
+		sa_read_map_entry(dev, &sa_memory_map[i], &values[i]);
+}
+
+/*
+ * Get DPR size incase CONFIG_SA_ENABLE_DPR is selected by SoC.
+ */
+static size_t get_dpr_size(void)
+{
+	uintptr_t dpr_reg;
+	size_t size = 0;
+	/*
+	 * DMA Protected Range can be reserved below TSEG for PCODE patch
+	 * or TXT/BootGuard related data.  Rather than report a base address
+	 * the DPR register reports the TOP of the region, which is the same
+	 * as TSEG base.  The region size is reported in MiB in bits 11:4.
+	 */
+	dpr_reg = pci_read_config32(SA_DEV_ROOT, DPR);
+	if (dpr_reg & DPR_EPM)
+		size = (dpr_reg & DPR_SIZE_MASK) << 16;
+
+	return size;
+}
+
+/*
+ * These are the host memory ranges that should be added:
+ * - 0 -> 0xa0000: cacheable
+ * - 0xc0000 -> top_of_ram : cacheable
+ * - top_of_ram -> TSEG - DPR: uncacheable
+ * - TESG - DPR -> BGSM: cacheable with standard MTRRs and reserved
+ * - BGSM -> TOLUD: not cacheable with standard MTRRs and reserved
+ * - 4GiB -> TOUUD: cacheable
+ *
+ * The default SMRAM space is reserved so that the range doesn't
+ * have to be saved during S3 Resume. Once marked reserved the OS
+ * cannot use the memory. This is a bit of an odd place to reserve
+ * the region, but the CPU devices don't have dev_ops->read_resources()
+ * called on them.
+ *
+ * The range 0xa0000 -> 0xc0000 does not have any resources
+ * associated with it to handle legacy VGA memory. If this range
+ * is not omitted the mtrr code will setup the area as cacheable
+ * causing VGA access to not work.
+ *
+ * The TSEG region is mapped as cacheable so that one can perform
+ * SMRAM relocation faster. Once the SMRR is enabled the SMRR takes
+ * precedence over the existing MTRRs covering this region.
+ *
+ * It should be noted that cacheable entry types need to be added in
+ * order. The reason is that the current MTRR code assumes this and
+ * falls over itself if it isn't.
+ *
+ * The resource index starts low and should not meet or exceed
+ * PCI_BASE_ADDRESS_0.
+ */
+static void sa_add_dram_resources(struct device *dev, int *resource_count)
+{
+	uintptr_t base_k, touud_k;
+	size_t dpr_size = 0, size_k;
+	uint64_t sa_map_values[MAX_MAP_ENTRIES];
+	uintptr_t top_of_ram;
+	int index = *resource_count;
+
+	if (IS_ENABLED(CONFIG_SA_ENABLE_DPR))
+		dpr_size = get_dpr_size();
+
+	top_of_ram = (uintptr_t)cbmem_top();
+
+	/* 0 - > 0xa0000 */
+	base_k = 0;
+	size_k = (0xa0000 / KiB) - base_k;
+	ram_resource(dev, index++, base_k, size_k);
+
+	/* 0xc0000 -> top_of_ram */
+	base_k = 0xc0000 / KiB;
+	size_k = (top_of_ram / KiB) - base_k;
+	ram_resource(dev, index++, base_k, size_k);
+
+	sa_get_mem_map(dev, &sa_map_values[0]);
+
+	/* top_of_ram -> TSEG - DPR */
+	base_k = top_of_ram;
+	size_k = sa_map_values[SA_TSEG_REG] - dpr_size - base_k;
+	mmio_resource(dev, index++, base_k / KiB, size_k / KiB);
+
+	/* TSEG - DPR -> BGSM */
+	base_k = sa_map_values[SA_TSEG_REG] - dpr_size;
+	size_k = sa_map_values[SA_BGSM_REG] - base_k;
+	reserved_ram_resource(dev, index++, base_k / KiB, size_k / KiB);
+
+	/* BGSM -> TOLUD */
+	base_k = sa_map_values[SA_BGSM_REG];
+	size_k = sa_map_values[SA_TOLUD_REG] - base_k;
+	mmio_resource(dev, index++, base_k / KiB, size_k / KiB);
+
+	/* 4GiB -> TOUUD */
+	base_k = 4 * (GiB / KiB); /* 4GiB */
+	touud_k = sa_map_values[SA_TOUUD_REG] / KiB;
+	size_k = touud_k - base_k;
+	if (touud_k > base_k)
+		ram_resource(dev, index++, base_k, size_k);
+
+	/*
+	 * Reserve everything between A segment and 1MB:
+	 *
+	 * 0xa0000 - 0xbffff: legacy VGA
+	 * 0xc0000 - 0xfffff: RAM
+	 */
+	mmio_resource(dev, index++, 0xa0000 / KiB, (0xc0000 - 0xa0000) / KiB);
+	reserved_ram_resource(dev, index++, 0xc0000 / KiB,
+			(1*MiB - 0xc0000) / KiB);
+
+	*resource_count = index;
+}
+
+static bool is_imr_enabled(uint32_t imr_base_reg)
+{
+	return !!(imr_base_reg & (1 << 31));
+}
+
+static void imr_resource(device_t dev, int idx, uint32_t base, uint32_t mask)
+{
+	uint32_t base_k, size_k;
+	/* Bits 28:0 encode the base address bits 38:10, hence the KiB unit. */
+	base_k = (base & 0x0fffffff);
+	/* Bits 28:0 encode the AND mask used for comparison, in KiB. */
+	size_k = ((~mask & 0x0fffffff) + 1);
+	/*
+	 * IMRs sit in lower DRAM. Mark them cacheable, otherwise we run
+	 * out of MTRRs. Memory reserved by IMRs is not usable for host
+	 * so mark it reserved.
+	 */
+	reserved_ram_resource(dev, idx, base_k, size_k);
+}
+
+/*
+ * Add IMR ranges that hang off the host bridge/memory
+ * controller device in case CONFIG_SA_ENABLE_IMR is selected by SoC.
+ */
+static void sa_add_imr_resources(struct device *dev, int *resource_cnt)
+{
+	size_t i, imr_offset;
+	uint32_t base, mask;
+	int index = *resource_cnt;
+
+	for (i = 0; i < MCH_NUM_IMRS; i++) {
+		imr_offset = i * MCH_IMR_PITCH;
+		base = MCHBAR32(imr_offset + MCH_IMR0_BASE);
+		mask = MCHBAR32(imr_offset + MCH_IMR0_MASK);
+
+		if (is_imr_enabled(base))
+			imr_resource(dev, index++, base, mask);
+	}
+
+	*resource_cnt = index;
+}
+
+static void systemagent_read_resources(struct device *dev)
+{
+	int index = 0;
+
+	/* Read standard PCI resources. */
+	pci_dev_read_resources(dev);
+
+	/* Add all fixed MMIO resources. */
+	soc_add_fixed_mmio_resources(dev, &index);
+	/* Calculate and add DRAM resources. */
+	sa_add_dram_resources(dev, &index);
+	if (IS_ENABLED(CONFIG_SA_ENABLE_IMR))
+		/* Add the isolated memory ranges (IMRs). */
+		sa_add_imr_resources(dev, &index);
+}
+
+void enable_power_aware_intr(void)
+{
+	uint8_t pair;
+
+	/* Enable Power Aware Interrupt Routing */
+	pair = MCHBAR8(MCH_PAIR);
+	pair &= ~0x7;	/* Clear 2:0 */
+	pair |= 0x4;	/* Fixed Priority */
+	MCHBAR8(MCH_PAIR) = pair;
+}
+
+static struct device_operations systemagent_ops = {
+	.read_resources   = &systemagent_read_resources,
+	.set_resources    = &pci_dev_set_resources,
+	.enable_resources = &pci_dev_enable_resources,
+	.init             = soc_systemagent_init,
+};
+
+static const unsigned short systemagent_ids[] = {
+	PCI_DEVICE_ID_INTEL_GLK_NB,
+	PCI_DEVICE_ID_INTEL_APL_NB,
+	PCI_DEVICE_ID_INTEL_SKL_ID_U,
+	PCI_DEVICE_ID_INTEL_SKL_ID_Y,
+	PCI_DEVICE_ID_INTEL_SKL_ID_ULX,
+	PCI_DEVICE_ID_INTEL_SKL_ID_H,
+	PCI_DEVICE_ID_INTEL_SKL_ID_H_EM,
+	PCI_DEVICE_ID_INTEL_KBL_ID_U,
+	PCI_DEVICE_ID_INTEL_KBL_ID_Y,
+	PCI_DEVICE_ID_INTEL_KBL_ID_H,
+	PCI_DEVICE_ID_INTEL_KBL_U_R,
+	0
+};
+
+static const struct pci_driver systemagent_driver __pci_driver = {
+	.ops     = &systemagent_ops,
+	.vendor  = PCI_VENDOR_ID_INTEL,
+	.devices = systemagent_ids
+};
diff --git a/src/soc/intel/common/block/systemagent/systemagent_def.h b/src/soc/intel/common/block/systemagent/systemagent_def.h
new file mode 100644
index 0000000..29ce9ec
--- /dev/null
+++ b/src/soc/intel/common/block/systemagent/systemagent_def.h
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2017 Intel Corporation.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.
+ */
+
+#ifndef SOC_INTEL_COMMON_BLOCK_SA_DEF_H
+#define SOC_INTEL_COMMON_BLOCK_SA_DEF_H
+
+
+/* Device 0:0.0 PCI configuration space */
+
+/* DPR register incase CONFIG_SA_ENABLE_DPR is selected by SoC */
+#define DPR		0x5c
+#define  DPR_EPM	(1 << 2)
+#define  DPR_PRS	(1 << 1)
+#define  DPR_SIZE_MASK	0xff0
+
+#define  PCIEXBAR_LENGTH_64MB	2
+#define  PCIEXBAR_LENGTH_128MB	1
+#define  PCIEXBAR_LENGTH_256MB	0
+#define  PCIEXBAR_PCIEXBAREN	(1 << 0)
+
+#define PAM0	0x80
+#define PAM1	0x81
+#define PAM2	0x82
+#define PAM3	0x83
+#define PAM4	0x84
+#define PAM5	0x85
+#define PAM6	0x86
+
+/* Device 0:0.0 MMIO space */
+#define MCH_PAIR	0x5418
+
+/*
+ * IMR register incase CONFIG_SA_ENABLE_IMR is selected by SoC.
+ *
+ * IMR registers are found under MCHBAR.
+ */
+#define MCH_IMR0_BASE	0x6870
+#define MCH_IMR0_MASK	0x6874
+#define MCH_IMR_PITCH	0x20
+#define MCH_NUM_IMRS	20
+
+/*
+ * System Memory Map Registers
+ * - top_of_ram -> TSEG - DPR: uncacheable
+ * - TESG - DPR -> BGSM: cacheable with standard MTRRs and reserved
+ * - BGSM -> TOLUD: not cacheable with standard MTRRs and reserved
+ * - 4GiB -> TOUUD: cacheable
+ */
+enum {
+	SA_TOUUD_REG,
+	SA_TOLUD_REG,
+	SA_BGSM_REG,
+	SA_TSEG_REG,
+	/* Must be last. */
+	MAX_MAP_ENTRIES
+};
+
+/*
+ * Set Fixed MMIO range
+ *   REG = Either PCI configuration space registers.
+ *   IS_64_BIT = If registers/offset is 64 bit.
+ *   DESCRIPTION = Name of the register/offset.
+ */
+struct sa_mem_map_descriptor {
+	unsigned int reg;
+	bool is_64_bit;
+	const char *description;
+};
+
+#endif	/* SOC_INTEL_COMMON_BLOCK_SA_DEF_H */
diff --git a/src/soc/intel/common/block/systemagent/systemagent_early.c b/src/soc/intel/common/block/systemagent/systemagent_early.c
new file mode 100644
index 0000000..7cf78e7
--- /dev/null
+++ b/src/soc/intel/common/block/systemagent/systemagent_early.c
@@ -0,0 +1,134 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2017 Intel Corporation.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 <arch/io.h>
+#include <delay.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <intelblocks/systemagent.h>
+#include <soc/iomap.h>
+#include <soc/pci_devs.h>
+#include <soc/systemagent.h>
+#include "systemagent_def.h"
+#include <timer.h>
+
+#if !ENV_RAMSTAGE
+void bootblock_systemagent_early_init(void)
+{
+	uint32_t reg;
+	uint8_t pciexbar_length;
+
+	/*
+	 * The PCIEXBAR is assumed to live in the memory mapped IO space under
+	 * 4GiB.
+	 */
+	reg = 0;
+	pci_io_write_config32(SA_DEV_ROOT, PCIEXBAR + 4, reg);
+
+	/* Get PCI Express Region Length */
+	switch (CONFIG_SA_PCIEX_LENGTH) {
+	case 256 * MiB:
+		pciexbar_length = PCIEXBAR_LENGTH_256MB;
+		break;
+	case 128 * MiB:
+		pciexbar_length = PCIEXBAR_LENGTH_128MB;
+		break;
+	case 64 * MiB:
+		pciexbar_length = PCIEXBAR_LENGTH_64MB;
+		break;
+	default:
+		pciexbar_length = PCIEXBAR_LENGTH_256MB;
+	}
+	reg = CONFIG_MMCONF_BASE_ADDRESS | (pciexbar_length << 1)
+				| PCIEXBAR_PCIEXBAREN;
+	pci_io_write_config32(SA_DEV_ROOT, PCIEXBAR, reg);
+
+	/*
+	 * TSEG defines the base of SMM range. BIOS determines the base
+	 * of TSEG memory which must be at or below Graphics base of GTT
+	 * Stolen memory, hence its better to clear TSEG register early
+	 * to avoid power on default non-zero value (if any).
+	 */
+	pci_write_config32(SA_DEV_ROOT, TSEG, 0);
+}
+#endif
+
+void sa_set_pci_bar(const struct sa_mmio_descriptor *fixed_set_resources,
+		size_t count)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		uintptr_t base;
+		unsigned int index;
+
+		index = fixed_set_resources[i].index;
+		/* Check if PCI BAR already enabled */
+		base = pci_read_config32(SA_DEV_ROOT, index);
+
+		/* If enabled don't program it. */
+		if (base & 0x1)
+			return;
+
+		base = fixed_set_resources[i].base;
+
+		pci_write_config32(SA_DEV_ROOT, index, base | 1);
+	}
+}
+
+/*
+ * There are special BARs that actually are programmed in the MCHBAR. These
+ * Intel special features, but they do consume resources that need to be
+ * accounted for.
+ */
+void sa_set_mch_bar(const struct sa_mmio_descriptor *fixed_set_resources,
+		size_t count)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		uintptr_t base;
+		unsigned int index;
+
+		base = fixed_set_resources[i].base;
+		index = fixed_set_resources[i].index;
+		write32((void *)(MCH_BASE_ADDRESS + index), base | 1);
+	}
+}
+
+void enable_pam_region(void)
+{
+	/* All read and writes in this region are serviced by DRAM */
+	pci_write_config8(SA_DEV_ROOT, PAM0, 0x30);
+	pci_write_config8(SA_DEV_ROOT, PAM1, 0x33);
+	pci_write_config8(SA_DEV_ROOT, PAM2, 0x33);
+	pci_write_config8(SA_DEV_ROOT, PAM3, 0x33);
+	pci_write_config8(SA_DEV_ROOT, PAM4, 0x33);
+	pci_write_config8(SA_DEV_ROOT, PAM5, 0x33);
+	pci_write_config8(SA_DEV_ROOT, PAM6, 0x33);
+}
+
+void enable_bios_reset_cpl(void)
+{
+	u8 bios_reset_cpl;
+
+	/*
+	 * Set bits 0+1 of BIOS_RESET_CPL to indicate to the CPU
+	 * that BIOS has initialized memory and power management
+	 */
+	bios_reset_cpl = MCHBAR8(BIOS_RESET_CPL);
+	bios_reset_cpl |= 3;
+	MCHBAR8(BIOS_RESET_CPL) = bios_reset_cpl;
+}