Merge branch 'next' of https://gitlab.denx.de/u-boot/custodians/u-boot-x86 into next

- Various x86 common codes updated for TPL/SPL
- I2C designware driver updated for PCI
- ICH SPI driver updated to support Apollo Lake
- Add Intel FSP2 base support
- Intel Apollo Lake platform specific drivers support
- Add a new board Google Chromebook Coral
diff --git a/Kconfig b/Kconfig
index 92fc4fc..46a31f4 100644
--- a/Kconfig
+++ b/Kconfig
@@ -545,9 +545,14 @@
 	  configuration to Kconfig. Since this option will be removed sometime,
 	  new boards should not use this option.
 
-config SYS_TEXT_BASE
+config HAVE_SYS_TEXT_BASE
+	bool
 	depends on !NIOS2 && !XTENSA
 	depends on !EFI_APP
+	default y
+
+config SYS_TEXT_BASE
+	depends on HAVE_SYS_TEXT_BASE
 	default 0x80800000 if ARCH_OMAP2PLUS || ARCH_K3
 	default 0x4a000000 if ARCH_SUNXI && !MACH_SUN9I && !MACH_SUN8I_V3S
 	default 0x2a000000 if ARCH_SUNXI && MACH_SUN9I
@@ -556,8 +561,6 @@
 	help
 	  The address in memory that U-Boot will be running from, initially.
 
-
-
 config SYS_CLK_FREQ
 	depends on ARC || ARCH_SUNXI || MPC83xx
 	int "CPU clock frequency"
diff --git a/arch/Kconfig b/arch/Kconfig
index 141e48b..ae9c93e 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -133,6 +133,9 @@
 	imply PHYLIB
 	imply DM_MDIO
 	imply DM_MDIO_MUX
+	imply ACPI_PMC
+	imply ACPI_PMC_SANDBOX
+	imply CMD_PMC
 
 config SH
 	bool "SuperH architecture"
@@ -183,12 +186,14 @@
 	imply USB_HOST_ETHER
 	imply PCH
 	imply RTC_MC146818
+	imply IRQ
 
 	# Thing to enable for when SPL/TPL are enabled: SPL
 	imply SPL_DM
 	imply SPL_OF_LIBFDT
 	imply SPL_DRIVERS_MISC_SUPPORT
 	imply SPL_GPIO_SUPPORT
+	imply SPL_PINCTRL
 	imply SPL_LIBCOMMON_SUPPORT
 	imply SPL_LIBGENERIC_SUPPORT
 	imply SPL_SERIAL_SUPPORT
@@ -200,14 +205,12 @@
 	imply SPL_SYSCON
 	# TPL
 	imply TPL_DM
-	imply TPL_OF_LIBFDT
 	imply TPL_DRIVERS_MISC_SUPPORT
 	imply TPL_GPIO_SUPPORT
+	imply TPL_PINCTRL
 	imply TPL_LIBCOMMON_SUPPORT
 	imply TPL_LIBGENERIC_SUPPORT
 	imply TPL_SERIAL_SUPPORT
-	imply TPL_SPI_FLASH_SUPPORT
-	imply TPL_SPI_SUPPORT
 	imply TPL_OF_CONTROL
 	imply TPL_TIMER
 	imply TPL_REGMAP
diff --git a/arch/arm/include/asm/omap_gpio.h b/arch/arm/include/asm/omap_gpio.h
index 20268fa..151afa8 100644
--- a/arch/arm/include/asm/omap_gpio.h
+++ b/arch/arm/include/asm/omap_gpio.h
@@ -22,7 +22,7 @@
 
 #include <asm/arch/cpu.h>
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 
 /* Information about a GPIO bank */
 struct omap_gpio_platdata {
diff --git a/arch/arm/mach-at91/include/mach/at91sam9260.h b/arch/arm/mach-at91/include/mach/at91sam9260.h
index 91faf72..2daeb4f 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9260.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9260.h
@@ -133,7 +133,7 @@
 /*
  * Other misc defines
  */
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
 #define ATMEL_PIO_PORTS		3		/* these SoCs have 3 PIO */
 #define ATMEL_BASE_PIO		ATMEL_BASE_PIOA
 #endif
diff --git a/arch/arm/mach-davinci/include/mach/gpio.h b/arch/arm/mach-davinci/include/mach/gpio.h
index c150240..e5a4053 100644
--- a/arch/arm/mach-davinci/include/mach/gpio.h
+++ b/arch/arm/mach-davinci/include/mach/gpio.h
@@ -18,7 +18,7 @@
 #define davinci_gpio_bank67 ((struct davinci_gpio *)DAVINCI_GPIO_BANK67)
 #define davinci_gpio_bank8 ((struct davinci_gpio *)DAVINCI_GPIO_BANK8)
 
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
 #define gpio_status()		gpio_info()
 #endif
 #define GPIO_NAME_SIZE		20
diff --git a/arch/arm/mach-omap2/am33xx/board.c b/arch/arm/mach-omap2/am33xx/board.c
index 03460c3..e64942b 100644
--- a/arch/arm/mach-omap2/am33xx/board.c
+++ b/arch/arm/mach-omap2/am33xx/board.c
@@ -116,7 +116,7 @@
 };
 #endif
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 static const struct omap_gpio_platdata am33xx_gpio[] = {
 	{ 0, AM33XX_GPIO0_BASE },
 	{ 1, AM33XX_GPIO1_BASE },
@@ -141,7 +141,7 @@
 #endif
 #endif
 
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
 static const struct gpio_bank gpio_bank_am33xx[] = {
 	{ (void *)AM33XX_GPIO0_BASE },
 	{ (void *)AM33XX_GPIO1_BASE },
diff --git a/arch/arm/mach-omap2/omap3/board.c b/arch/arm/mach-omap2/omap3/board.c
index 658ef8c..60de0d6 100644
--- a/arch/arm/mach-omap2/omap3/board.c
+++ b/arch/arm/mach-omap2/omap3/board.c
@@ -33,7 +33,7 @@
 static void omap3_invalidate_l2_cache_secure(void);
 #endif
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 #if !CONFIG_IS_ENABLED(OF_CONTROL)
 /* Manually initialize GPIO banks when OF_CONTROL doesn't */
 static const struct omap_gpio_platdata omap34xx_gpio[] = {
diff --git a/arch/arm/mach-omap2/omap5/hwinit.c b/arch/arm/mach-omap2/omap5/hwinit.c
index eba2164..56458ce 100644
--- a/arch/arm/mach-omap2/omap5/hwinit.c
+++ b/arch/arm/mach-omap2/omap5/hwinit.c
@@ -25,7 +25,7 @@
 
 u32 *const omap_si_rev = (u32 *)OMAP_SRAM_SCRATCH_OMAP_REV;
 
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
 static struct gpio_bank gpio_bank_54xx[8] = {
 	{ (void *)OMAP54XX_GPIO1_BASE },
 	{ (void *)OMAP54XX_GPIO2_BASE },
diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c
index dee5fde..cd46e00 100644
--- a/arch/sandbox/cpu/state.c
+++ b/arch/sandbox/cpu/state.c
@@ -356,6 +356,7 @@
 	/* No reset yet, so mark it as such. Always allow power reset */
 	state->last_sysreset = SYSRESET_COUNT;
 	state->sysreset_allowed[SYSRESET_POWER_OFF] = true;
+	state->allow_memio = false;
 
 	memset(&state->wdt, '\0', sizeof(state->wdt));
 	memset(state->spi, '\0', sizeof(state->spi));
diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi
index f09bc70..7bf144f 100644
--- a/arch/sandbox/dts/sandbox.dtsi
+++ b/arch/sandbox/dts/sandbox.dtsi
@@ -100,6 +100,17 @@
 	};
 
 	pci-controller {
+		pci@1e,0 {
+			compatible = "sandbox,pmc";
+			reg = <0xf000 0 0 0 0>;
+			sandbox,emul = <&pmc_emul>;
+			gpe0-dwx-mask = <0xf>;
+			gpe0-dwx-shift-base = <4>;
+			gpe0-dw = <6 7 9>;
+			gpe0-sts = <0x20>;
+			gpe0-en = <0x30>;
+		};
+
 		pci@1f,0 {
 			compatible = "pci-generic";
 			reg = <0xf800 0 0 0 0>;
@@ -109,6 +120,9 @@
 
 	emul {
 		compatible = "sandbox,pci-emul-parent";
+		pmc_emul: emul@1e,0 {
+			compatible = "sandbox,pmc-emul";
+		};
 		swap_case_emul: emul@1f,0 {
 			compatible = "sandbox,swap-case";
 		};
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index fdb08f2..57513a4 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -353,6 +353,10 @@
 		vss-microvolts = <0>;
 	};
 
+	irq {
+		compatible = "sandbox,irq";
+	};
+
 	lcd {
 		u-boot,dm-pre-reloc;
 		compatible = "sandbox,lcd-sdl";
@@ -471,6 +475,27 @@
 			       0x01000810 0 0 0 0>;
 			sandbox,emul = <&swap_case_emul0_1>;
 		};
+		p2sb-pci@2,0 {
+			compatible = "sandbox,p2sb";
+			reg = <0x02001010 0 0 0 0>;
+			sandbox,emul = <&p2sb_emul>;
+
+			adder {
+				intel,p2sb-port-id = <3>;
+				compatible = "sandbox,adder";
+			};
+		};
+		pci@1e,0 {
+			compatible = "sandbox,pmc";
+			reg = <0xf000 0 0 0 0>;
+			sandbox,emul = <&pmc_emul1e>;
+			acpi-base = <0x400>;
+			gpe0-dwx-mask = <0xf>;
+			gpe0-dwx-shift-base = <4>;
+			gpe0-dw = <6 7 9>;
+			gpe0-sts = <0x20>;
+			gpe0-en = <0x30>;
+		};
 		pci@1f,0 {
 			compatible = "pci-generic";
 			/* reg 0 is at 0x10, using FDT_PCI_SPACE_IO */
@@ -491,6 +516,12 @@
 		swap_case_emul0_1f: emul0@1f,0 {
 			compatible = "sandbox,swap-case";
 		};
+		p2sb_emul: emul@2,0 {
+			compatible = "sandbox,p2sb-emul";
+		};
+		pmc_emul1e: emul@1e,0 {
+			compatible = "sandbox,pmc-emul";
+		};
 	};
 
 	pci1: pci-controller1 {
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index 7dd9aa5..2421922 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -13,6 +13,8 @@
 
 #define SANDBOX_PCI_VENDOR_ID		0x1234
 #define SANDBOX_PCI_SWAP_CASE_EMUL_ID	0x5678
+#define SANDBOX_PCI_PMC_EMUL_ID		0x5677
+#define SANDBOX_PCI_P2SB_EMUL_ID	0x5676
 #define SANDBOX_PCI_CLASS_CODE		PCI_CLASS_CODE_COMM
 #define SANDBOX_PCI_CLASS_SUB_CODE	PCI_CLASS_SUB_CODE_COMM_SERIAL
 
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 17a6fe6..89b93e5 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -106,6 +106,7 @@
 source "board/intel/Kconfig"
 
 # platform-specific options below
+source "arch/x86/cpu/apollolake/Kconfig"
 source "arch/x86/cpu/baytrail/Kconfig"
 source "arch/x86/cpu/braswell/Kconfig"
 source "arch/x86/cpu/broadwell/Kconfig"
@@ -217,6 +218,14 @@
 	depends on X86_RESET_VECTOR
 	default 0xfffff800
 
+config HAVE_X86_FIT
+	bool
+	help
+	  Enable inclusion of an Intel Firmware Interface Table (FIT) into the
+	  image. This table is supposed to point to microcode and the like. So
+	  far it is just a fixed table with the minimum set of headers, so that
+	  it is actually present.
+
 config X86_LOAD_FROM_32_BIT
 	bool "Boot from a 32-bit program"
 	help
@@ -326,7 +335,7 @@
 
 config FLASH_DESCRIPTOR_FILE
 	string "Flash descriptor binary filename"
-	depends on HAVE_INTEL_ME
+	depends on HAVE_INTEL_ME || FSP_VERSION2
 	default "descriptor.bin"
 	help
 	  The filename of the file to use as flash descriptor in the
@@ -411,6 +420,54 @@
 	  The default base address of 0xfffc0000 indicates that the binary must
 	  be located at offset 0xc0000 from the beginning of a 1MB flash device.
 
+if FSP_VERSION2
+
+config FSP_FILE_T
+	string "Firmware Support Package binary filename (Temp RAM)"
+	default "fsp_t.bin"
+	help
+	  The filename of the file to use for the temporary-RAM init phase from
+	  the Firmware Support Package binary. Put this in the board directory.
+	  It is used to set up an initial area of RAM which can be used for the
+	  stack and other purposes, while bringing up the main system DRAM.
+
+config FSP_ADDR_T
+	hex "Firmware Support Package binary location (Temp RAM)"
+	default 0xffff8000
+	help
+	  FSP is not Position-Independent Code (PIC) and FSP components have to
+	  be rebased if placed at a location which is different from the
+	  perferred base address specified during the FSP build. Use Intel's
+	  Binary Configuration Tool (BCT) to do the rebase.
+
+config FSP_FILE_M
+	string "Firmware Support Package binary filename (Memory Init)"
+	default "fsp_m.bin"
+	help
+	  The filename of the file to use for the RAM init phase from the
+	  Firmware Support Package binary. Put this in the board directory.
+	  It is used to set up the main system DRAM and runs in SPL, once
+	  temporary RAM (CAR) is working.
+
+config FSP_FILE_S
+	string "Firmware Support Package binary filename (Silicon Init)"
+	default "fsp_s.bin"
+	help
+	  The filename of the file to use for the Silicon init phase from the
+	  Firmware Support Package binary. Put this in the board directory.
+	  It is used to set up the silicon to work correctly and must be
+	  executed after DRAM is running.
+
+config IFWI_INPUT_FILE
+	string "Filename containing FIT (Firmware Interface Table) with IFWI"
+	default "fitimage.bin"
+	help
+	  The IFWI is obtained by running a tool on this file to extract the
+	  IFWI. Put this in the board directory. The IFWI contains U-Boot TPL,
+	  microcode and other internal items.
+
+endif
+
 config FSP_TEMP_RAM_ADDR
 	hex
 	depends on FSP_VERSION1
@@ -532,6 +589,10 @@
           broadwell) U-Boot will be missing some critical setup steps.
           Various peripherals may fail to work.
 
+config HAVE_MICROCODE
+	bool
+	default y if !FSP_VERSION2
+
 config SMP
 	bool "Enable Symmetric Multiprocessing"
 	default n
@@ -595,7 +656,7 @@
 
 config HAVE_VBT
 	bool "Add a Video BIOS Table (VBT) image"
-	depends on FSP_VERSION1
+	depends on HAVE_FSP
 	help
 	  Select this option if you have a Video BIOS Table (VBT) image that
 	  you would like to add to your ROM. This is normally required if you
@@ -823,4 +884,30 @@
 	  Increse it if the default size does not fit the board's needs.
 	  This is most likely due to a large ACPI DSDT table is used.
 
+config INTEL_CAR_CQOS
+	bool "Support Intel Cache Quality of Service"
+	help
+	  Cache Quality of Service allows more fine-grained control of cache
+	  usage. As result, it is possible to set up a portion of L2 cache for
+	  CAR and use the remainder for actual caching.
+
+#
+# Each bit in QOS mask controls this many bytes. This is calculated as:
+# (CACHE_WAYS / CACHE_BITS_PER_MASK) * CACHE_LINE_SIZE * CACHE_SETS
+#
+config CACHE_QOS_SIZE_PER_BIT
+	hex
+	depends on INTEL_CAR_CQOS
+	default 0x20000 # 128 KB
+
+config X86_OFFSET_U_BOOT
+	hex "Offset of U-Boot in ROM image"
+	depends on HAVE_SYS_TEXT_BASE
+	default SYS_TEXT_BASE
+
+config X86_OFFSET_SPL
+	hex "Offset of SPL in ROM image"
+	depends on SPL && X86
+	default SPL_TEXT_BASE
+
 endmenu
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile
index 6296b55..5b40838 100644
--- a/arch/x86/cpu/Makefile
+++ b/arch/x86/cpu/Makefile
@@ -41,6 +41,7 @@
 endif
 
 obj-y += intel_common/
+obj-$(CONFIG_INTEL_APOLLOLAKE) += apollolake/
 obj-$(CONFIG_INTEL_BAYTRAIL) += baytrail/
 obj-$(CONFIG_INTEL_BRASWELL) += braswell/
 obj-$(CONFIG_INTEL_BROADWELL) += broadwell/
@@ -53,7 +54,8 @@
 obj-$(CONFIG_INTEL_QUEENSBAY) += queensbay/
 obj-$(CONFIG_INTEL_TANGIER) += tangier/
 obj-$(CONFIG_APIC) += lapic.o ioapic.o
-obj-y += irq.o
+obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += irq.o
+obj-$(CONFIG_QFW) += qfw_cpu.o
 ifndef CONFIG_$(SPL_)X86_64
 obj-$(CONFIG_SMP) += mp_init.o
 endif
diff --git a/arch/x86/cpu/apollolake/Kconfig b/arch/x86/cpu/apollolake/Kconfig
new file mode 100644
index 0000000..fcff176
--- /dev/null
+++ b/arch/x86/cpu/apollolake/Kconfig
@@ -0,0 +1,96 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright 2019 Google LLC
+#
+
+config INTEL_APOLLOLAKE
+	bool
+	select FSP_VERSION2
+	select HAVE_FSP
+	select ARCH_MISC_INIT
+	select USE_CAR
+	select INTEL_PMC
+	select TPL_X86_TSC_TIMER_NATIVE
+	select SPL_PCH_SUPPORT
+	select TPL_PCH_SUPPORT
+	select PCH_SUPPORT
+	select P2SB
+	imply ENABLE_MRC_CACHE
+	imply AHCI_PCI
+	imply SCSI
+	imply SCSI_AHCI
+	imply SPI_FLASH
+	imply USB
+	imply USB_EHCI_HCD
+	imply TPL
+	imply SPL
+	imply TPL_X86_16BIT_INIT
+	imply TPL_OF_PLATDATA
+	imply ACPI_PMC
+	imply MMC
+	imply DM_MMC
+	imply MMC_PCI
+	imply MMC_SDHCI
+	imply CMD_MMC
+	imply VIDEO_FSP
+	imply PINCTRL_INTEL
+	imply PINCTRL_INTEL_APL
+	imply HAVE_VBT
+	imply HAVE_X86_FIT
+	imply INTEL_GPIO
+	imply SMP
+
+if INTEL_APOLLOLAKE
+
+config DCACHE_RAM_BASE
+	default 0xfef00000
+
+config DCACHE_RAM_SIZE
+	default 0xc0000
+
+config DCACHE_RAM_MRC_VAR_SIZE
+	default 0xb0000
+
+config CPU_SPECIFIC_OPTIONS
+	def_bool y
+	select SMM_TSEG
+	select X86_RAMTEST
+
+config SMM_TSEG_SIZE
+	hex
+	default 0x800000
+
+config MMCONF_BASE_ADDRESS
+	hex
+	default 0xe0000000
+
+config TPL_SIZE_LIMIT
+	default 0x7800
+
+config CPU_ADDR_BITS
+	default 39
+
+config APL_SPI_FLASH_BOOT
+	bool "Support booting with SPI-flash driver instead memory-mapped SPI"
+	select TPL_SPI_FLASH_SUPPORT
+	select TPL_SPI_SUPPORT
+	help
+	  This enables SPI and SPI flash in TPL. Without the this only
+	  available boot method is to use memory-mapped SPI. Since this is
+	  actually fast and produces a TPL which is 7KB smaller, memory-mapped
+	  SPI is the default.
+
+config APL_BOOT_FROM_FAST_SPI_FLASH
+	bool "Boot using SPI flash driver"
+	select APL_SPI_FLASH_BOOT
+	help
+	  This option is separate from APL_SPI_FLASH_BOOT since it is useful to
+	  be able to compare booting speed with the same build. Enable this to
+	  use the SPI-flash driver to load SPL, U-Boot and FSP-M. For technical
+	  reasons FSP-S is currently always loaded from memory-mapped SPI. See
+	  Apollo Lake's arch_fsp_init_r() for details about that.
+
+config VBT_ADDR
+	default 0xff3f1000
+
+endif
diff --git a/arch/x86/cpu/apollolake/Makefile b/arch/x86/cpu/apollolake/Makefile
new file mode 100644
index 0000000..1760df5
--- /dev/null
+++ b/arch/x86/cpu/apollolake/Makefile
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2019 Google LLC
+
+obj-$(CONFIG_SPL_BUILD) += cpu_spl.o
+obj-$(CONFIG_SPL_BUILD) += spl.o
+obj-$(CONFIG_SPL_BUILD) += systemagent.o
+obj-y += cpu_common.o
+
+ifndef CONFIG_TPL_BUILD
+obj-y += cpu.o
+obj-y += punit.o
+ifdef CONFIG_SPL_BUILD
+obj-y += fsp_m.o
+endif
+endif
+ifndef CONFIG_SPL_BUILD
+obj-y += fsp_s.o
+endif
+
+obj-y += hostbridge.o
+obj-y += itss.o
+obj-y += lpc.o
+obj-y += p2sb.o
+obj-y += pch.o
+obj-y += pmc.o
+obj-y += uart.o
diff --git a/arch/x86/cpu/apollolake/cpu.c b/arch/x86/cpu/apollolake/cpu.c
new file mode 100644
index 0000000..3d05c82
--- /dev/null
+++ b/arch/x86/cpu/apollolake/cpu.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <asm/cpu_common.h>
+#include <asm/cpu_x86.h>
+
+static int apl_get_info(struct udevice *dev, struct cpu_info *info)
+{
+	return cpu_intel_get_info(info, INTEL_BCLK_MHZ);
+}
+
+static int apl_get_count(struct udevice *dev)
+{
+	return 4;
+}
+
+static const struct cpu_ops cpu_x86_apl_ops = {
+	.get_desc	= cpu_x86_get_desc,
+	.get_info	= apl_get_info,
+	.get_count	= apl_get_count,
+	.get_vendor	= cpu_x86_get_vendor,
+};
+
+static const struct udevice_id cpu_x86_apl_ids[] = {
+	{ .compatible = "intel,apl-cpu" },
+	{ }
+};
+
+U_BOOT_DRIVER(cpu_x86_apl_drv) = {
+	.name		= "cpu_x86_apl",
+	.id		= UCLASS_CPU,
+	.of_match	= cpu_x86_apl_ids,
+	.bind		= cpu_x86_bind,
+	.ops		= &cpu_x86_apl_ops,
+	.flags		= DM_FLAG_PRE_RELOC,
+};
diff --git a/arch/x86/cpu/apollolake/cpu_common.c b/arch/x86/cpu/apollolake/cpu_common.c
new file mode 100644
index 0000000..ba6bda3
--- /dev/null
+++ b/arch/x86/cpu/apollolake/cpu_common.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <asm/cpu_common.h>
+#include <asm/msr.h>
+
+void cpu_flush_l1d_to_l2(void)
+{
+	struct msr_t msr;
+
+	msr = msr_read(MSR_POWER_MISC);
+	msr.lo |= FLUSH_DL1_L2;
+	msr_write(MSR_POWER_MISC, msr);
+}
diff --git a/arch/x86/cpu/apollolake/cpu_spl.c b/arch/x86/cpu/apollolake/cpu_spl.c
new file mode 100644
index 0000000..8a39c31
--- /dev/null
+++ b/arch/x86/cpu/apollolake/cpu_spl.c
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Portions taken from coreboot
+ */
+
+#include <common.h>
+#include <acpi_s3.h>
+#include <dm.h>
+#include <ec_commands.h>
+#include <log.h>
+#include <spi_flash.h>
+#include <spl.h>
+#include <syscon.h>
+#include <asm/cpu.h>
+#include <asm/cpu_common.h>
+#include <asm/cpu_x86.h>
+#include <asm/fast_spi.h>
+#include <asm/intel_pinctrl.h>
+#include <asm/intel_regs.h>
+#include <asm/io.h>
+#include <asm/msr.h>
+#include <asm/mtrr.h>
+#include <asm/pci.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/iomap.h>
+#include <asm/arch/lpc.h>
+#include <asm/arch/pch.h>
+#include <asm/arch/systemagent.h>
+#include <asm/arch/uart.h>
+#include <asm/fsp2/fsp_api.h>
+#include <linux/sizes.h>
+#include <power/acpi_pmc.h>
+
+/* Define this here to avoid referencing any drivers for the debug UART 1 */
+#define PCH_DEV_P2SB	PCI_BDF(0, 0x0d, 0)
+
+static void pch_uart_init(void)
+{
+	/*
+	 * Set up the pinmux so that the UART rx/tx signals are connected
+	 * outside the SoC.
+	 *
+	 * There are about 500 lines of code required to program the GPIO
+	 * configuration for the UARTs. But it boils down to four writes, and
+	 * for the debug UART we want the minimum possible amount of code before
+	 * the UART is running. So just add the magic writes here. See
+	 * apl_hostbridge_early_init_pinctrl() for the full horror.
+	 */
+	if (PCI_FUNC(PCH_DEV_UART) == 1) {
+		writel(0x40000402, 0xd0c50650);
+		writel(0x3c47, 0xd0c50654);
+		writel(0x40000400, 0xd0c50658);
+		writel(0x3c48, 0xd0c5065c);
+	} else { /* UART2 */
+		writel(0x40000402, 0xd0c50670);
+		writel(0x3c4b, 0xd0c50674);
+		writel(0x40000400, 0xd0c50678);
+		writel(0x3c4c, 0xd0c5067c);
+	}
+
+#ifdef CONFIG_DEBUG_UART
+	apl_uart_init(PCH_DEV_UART, CONFIG_DEBUG_UART_BASE);
+#endif
+}
+
+static void p2sb_enable_bar(ulong bar)
+{
+	/* Enable PCR Base address in PCH */
+	pci_x86_write_config(PCH_DEV_P2SB, PCI_BASE_ADDRESS_0, bar,
+			     PCI_SIZE_32);
+	pci_x86_write_config(PCH_DEV_P2SB, PCI_BASE_ADDRESS_1, 0, PCI_SIZE_32);
+
+	/* Enable P2SB MSE */
+	pci_x86_write_config(PCH_DEV_P2SB, PCI_COMMAND,
+			     PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY,
+			     PCI_SIZE_8);
+}
+
+/*
+ * board_debug_uart_init() - Init the debug UART ready for use
+ *
+ * This is the minimum init needed to get the UART running. It avoids any
+ * drivers or complex code, so that the UART is running as soon as possible.
+ */
+void board_debug_uart_init(void)
+{
+	p2sb_enable_bar(IOMAP_P2SB_BAR);
+	pch_uart_init();
+}
+
+static int fast_spi_cache_bios_region(void)
+{
+	uint map_size, offset;
+	ulong map_base, base;
+	int ret;
+
+	ret = fast_spi_early_init(PCH_DEV_SPI, IOMAP_SPI_BASE);
+	if (ret)
+		return log_msg_ret("early_init", ret);
+
+	ret = fast_spi_get_bios_mmap(PCH_DEV_SPI, &map_base, &map_size,
+				     &offset);
+	if (ret)
+		return log_msg_ret("get_mmap", ret);
+
+	base = SZ_4G - map_size;
+	mtrr_set_next_var(MTRR_TYPE_WRPROT, base, map_size);
+	log_debug("BIOS cache base=%lx, size=%x\n", base, (uint)map_size);
+
+	return 0;
+}
+
+static void enable_pm_timer_emulation(struct udevice *pmc)
+{
+	struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(pmc);
+	msr_t msr;
+
+	/*
+	 * The derived frequency is calculated as follows:
+	 *    (CTC_FREQ * msr[63:32]) >> 32 = target frequency.
+	 *
+	 * Back-solve the multiplier so the 3.579545MHz ACPI timer frequency is
+	 * used.
+	 */
+	msr.hi = (3579545ULL << 32) / CTC_FREQ;
+
+	/* Set PM1 timer IO port and enable */
+	msr.lo = EMULATE_PM_TMR_EN | (upriv->acpi_base + R_ACPI_PM1_TMR);
+	debug("PM timer %x %x\n", msr.hi, msr.lo);
+	msr_write(MSR_EMULATE_PM_TIMER, msr);
+}
+
+static void google_chromeec_ioport_range(uint *out_basep, uint *out_sizep)
+{
+	uint base;
+	uint size;
+
+	if (IS_ENABLED(CONFIG_EC_GOOGLE_CHROMEEC_MEC)) {
+		base = MEC_EMI_BASE;
+		size = MEC_EMI_SIZE;
+	} else {
+		base = EC_HOST_CMD_REGION0;
+		size = 2 * EC_HOST_CMD_REGION_SIZE;
+		/* Make sure MEMMAP region follows host cmd region */
+		assert(base + size == EC_LPC_ADDR_MEMMAP);
+		size += EC_MEMMAP_SIZE;
+	}
+
+	*out_basep = base;
+	*out_sizep = size;
+}
+
+static void early_ec_init(void)
+{
+	uint base, size;
+
+	/*
+	 * Set up LPC decoding for the Chrome OS EC I/O port ranges:
+	 * - Ports 62/66, 60/64, and 200->208
+	 * - Chrome OS EC communication I/O ports
+	 */
+	lpc_enable_fixed_io_ranges(LPC_IOE_EC_62_66 | LPC_IOE_KBC_60_64 |
+				   LPC_IOE_LGE_200);
+	google_chromeec_ioport_range(&base, &size);
+	lpc_open_pmio_window(base, size);
+}
+
+static int arch_cpu_init_tpl(void)
+{
+	struct udevice *pmc, *sa, *p2sb, *serial, *spi, *lpc;
+	int ret;
+
+	ret = uclass_first_device_err(UCLASS_ACPI_PMC, &pmc);
+	if (ret)
+		return log_msg_ret("PMC", ret);
+
+	/* Clear global reset promotion bit */
+	ret = pmc_global_reset_set_enable(pmc, false);
+	if (ret)
+		return log_msg_ret("disable global reset", ret);
+
+	enable_pm_timer_emulation(pmc);
+
+	ret = uclass_first_device_err(UCLASS_P2SB, &p2sb);
+	if (ret)
+		return log_msg_ret("p2sb", ret);
+	ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &sa);
+	if (ret)
+		return log_msg_ret("northbridge", ret);
+	gd->baudrate = CONFIG_BAUDRATE;
+	ret = uclass_first_device_err(UCLASS_SERIAL, &serial);
+	if (ret)
+		return log_msg_ret("serial", ret);
+	if (CONFIG_IS_ENABLED(SPI_FLASH_SUPPORT)) {
+		ret = uclass_first_device_err(UCLASS_SPI, &spi);
+		if (ret)
+			return log_msg_ret("SPI", ret);
+	} else {
+		/* Alternative code if we don't have SPI in TPL */
+		if (IS_ENABLED(CONFIG_APL_BOOT_FROM_FAST_SPI_FLASH))
+			printf("Warning: Enable APL_SPI_FLASHBOOT to use SPI-flash driver in TPL");
+		ret = fast_spi_cache_bios_region();
+		if (ret)
+			return log_msg_ret("BIOS cache", ret);
+	}
+	ret = pmc_disable_tco(pmc);
+	if (ret)
+		return log_msg_ret("disable TCO", ret);
+	ret = pmc_gpe_init(pmc);
+	if (ret)
+		return log_msg_ret("pmc_gpe", ret);
+	ret = uclass_first_device_err(UCLASS_LPC, &lpc);
+	if (ret)
+		return log_msg_ret("lpc", ret);
+
+	early_ec_init();
+
+	return 0;
+}
+
+/*
+ * Enables several BARs and devices which are needed for memory init
+ * - MCH_BASE_ADDR is needed in order to talk to the memory controller
+ * - HPET is enabled because FSP wants to store a pointer to global data in the
+ *   HPET comparator register
+ */
+static int arch_cpu_init_spl(void)
+{
+	struct udevice *pmc, *p2sb;
+	int ret;
+
+	ret = uclass_first_device_err(UCLASS_ACPI_PMC, &pmc);
+	if (ret)
+		return log_msg_ret("Could not probe PMC", ret);
+	ret = uclass_first_device_err(UCLASS_P2SB, &p2sb);
+	if (ret)
+		return log_msg_ret("Cannot set up p2sb", ret);
+
+	lpc_io_setup_comm_a_b();
+
+	/* TODO(sjg@chromium.org): Enable upper RTC bank here */
+
+	ret = pmc_init(pmc);
+	if (ret < 0)
+		return log_msg_ret("Could not init PMC", ret);
+#ifdef CONFIG_HAVE_ACPI_RESUME
+	ret = pmc_prev_sleep_state(pmc);
+	if (ret < 0)
+		return log_msg_ret("Could not get PMC sleep state", ret);
+	gd->arch.prev_sleep_state = ret;
+#endif
+
+	return 0;
+}
+
+int arch_cpu_init(void)
+{
+	int ret = 0;
+
+	if (spl_phase() == PHASE_TPL)
+		ret = arch_cpu_init_tpl();
+	else if (spl_phase() == PHASE_SPL)
+		ret = arch_cpu_init_spl();
+	if (ret)
+		printf("%s: Error %d\n", __func__, ret);
+
+	return ret;
+}
diff --git a/arch/x86/cpu/apollolake/fsp_m.c b/arch/x86/cpu/apollolake/fsp_m.c
new file mode 100644
index 0000000..5308af8
--- /dev/null
+++ b/arch/x86/cpu/apollolake/fsp_m.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/arch/iomap.h>
+#include <asm/arch/fsp/fsp_configs.h>
+#include <asm/arch/fsp/fsp_m_upd.h>
+#include <asm/fsp2/fsp_internal.h>
+#include <dm/uclass-internal.h>
+
+/*
+ * ODT settings:
+ * If ODT PIN to LP4 DRAM is pulled HIGH for ODT_A and HIGH for ODT_B,
+ * choose ODT_A_B_HIGH_HIGH. If ODT PIN to LP4 DRAM is pulled HIGH for ODT_A
+ * and LOW for ODT_B, choose ODT_A_B_HIGH_LOW.
+ *
+ * Note that the enum values correspond to the interpreted UPD fields
+ * within Ch[3:0]_OdtConfig parameters.
+ */
+enum {
+	ODT_A_B_HIGH_LOW	= 0 << 1,
+	ODT_A_B_HIGH_HIGH	= 1 << 1,
+	N_WR_24			= 1 << 5,
+};
+
+/*
+ * LPDDR4 helper routines for configuring the memory UPD for LPDDR4 operation.
+ * There are four physical LPDDR4 channels, each 32-bits wide. There are two
+ * logical channels using two physical channels together to form a 64-bit
+ * interface to memory for each logical channel.
+ */
+
+enum {
+	LP4_PHYS_CH0A,
+	LP4_PHYS_CH0B,
+	LP4_PHYS_CH1A,
+	LP4_PHYS_CH1B,
+
+	LP4_NUM_PHYS_CHANNELS,
+};
+
+/*
+ * The DQs within a physical channel can be bit-swizzled within each byte.
+ * Within a channel the bytes can be swapped, but the DQs need to be routed
+ * with the corresponding DQS (strobe).
+ */
+enum {
+	LP4_DQS0,
+	LP4_DQS1,
+	LP4_DQS2,
+	LP4_DQS3,
+
+	LP4_NUM_BYTE_LANES,
+	DQ_BITS_PER_DQS		= 8,
+};
+
+/* Provide bit swizzling per DQS and byte swapping within a channel */
+struct lpddr4_chan_swizzle_cfg {
+	u8 dqs[LP4_NUM_BYTE_LANES][DQ_BITS_PER_DQS];
+};
+
+struct lpddr4_swizzle_cfg {
+	struct lpddr4_chan_swizzle_cfg phys[LP4_NUM_PHYS_CHANNELS];
+};
+
+static void setup_sdram(struct fsp_m_config *cfg,
+			const struct lpddr4_swizzle_cfg *swizzle_cfg)
+{
+	const struct lpddr4_chan_swizzle_cfg *sch;
+	/* Number of bytes to copy per DQS */
+	const size_t sz = DQ_BITS_PER_DQS;
+	int chan;
+
+	cfg->memory_down = 1;
+	cfg->scrambler_support = 1;
+	cfg->channel_hash_mask = 0x36;
+	cfg->slice_hash_mask = 9;
+	cfg->interleaved_mode = 2;
+	cfg->channels_slices_enable = 0;
+	cfg->min_ref_rate2x_enable = 0;
+	cfg->dual_rank_support_enable = 1;
+
+	/* LPDDR4 is memory down so no SPD addresses */
+	cfg->dimm0_spd_address = 0;
+	cfg->dimm1_spd_address = 0;
+
+	for (chan = 0; chan < 4; chan++) {
+		struct fsp_ram_channel *ch = &cfg->chan[chan];
+
+		ch->rank_enable = 1;
+		ch->device_width = 1;
+		ch->dram_density = 2;
+		ch->option = 3;
+		ch->odt_config = ODT_A_B_HIGH_HIGH;
+	}
+
+	/*
+	 * CH0_DQB byte lanes in the bit swizzle configuration field are
+	 * not 1:1. The mapping within the swizzling field is:
+	 *   indices [0:7]   - byte lane 1 (DQS1) DQ[8:15]
+	 *   indices [8:15]  - byte lane 0 (DQS0) DQ[0:7]
+	 *   indices [16:23] - byte lane 3 (DQS3) DQ[24:31]
+	 *   indices [24:31] - byte lane 2 (DQS2) DQ[16:23]
+	 */
+	sch = &swizzle_cfg->phys[LP4_PHYS_CH0B];
+	memcpy(&cfg->ch_bit_swizzling[0][0], &sch->dqs[LP4_DQS1], sz);
+	memcpy(&cfg->ch_bit_swizzling[0][8], &sch->dqs[LP4_DQS0], sz);
+	memcpy(&cfg->ch_bit_swizzling[0][16], &sch->dqs[LP4_DQS3], sz);
+	memcpy(&cfg->ch_bit_swizzling[0][24], &sch->dqs[LP4_DQS2], sz);
+
+	/*
+	 * CH0_DQA byte lanes in the bit swizzle configuration field are 1:1.
+	 */
+	sch = &swizzle_cfg->phys[LP4_PHYS_CH0A];
+	memcpy(&cfg->ch_bit_swizzling[1][0], &sch->dqs[LP4_DQS0], sz);
+	memcpy(&cfg->ch_bit_swizzling[1][8], &sch->dqs[LP4_DQS1], sz);
+	memcpy(&cfg->ch_bit_swizzling[1][16], &sch->dqs[LP4_DQS2], sz);
+	memcpy(&cfg->ch_bit_swizzling[1][24], &sch->dqs[LP4_DQS3], sz);
+
+	sch = &swizzle_cfg->phys[LP4_PHYS_CH1B];
+	memcpy(&cfg->ch_bit_swizzling[2][0], &sch->dqs[LP4_DQS1], sz);
+	memcpy(&cfg->ch_bit_swizzling[2][8], &sch->dqs[LP4_DQS0], sz);
+	memcpy(&cfg->ch_bit_swizzling[2][16], &sch->dqs[LP4_DQS3], sz);
+	memcpy(&cfg->ch_bit_swizzling[2][24], &sch->dqs[LP4_DQS2], sz);
+
+	/*
+	 * CH0_DQA byte lanes in the bit swizzle configuration field are 1:1.
+	 */
+	sch = &swizzle_cfg->phys[LP4_PHYS_CH1A];
+	memcpy(&cfg->ch_bit_swizzling[3][0], &sch->dqs[LP4_DQS0], sz);
+	memcpy(&cfg->ch_bit_swizzling[3][8], &sch->dqs[LP4_DQS1], sz);
+	memcpy(&cfg->ch_bit_swizzling[3][16], &sch->dqs[LP4_DQS2], sz);
+	memcpy(&cfg->ch_bit_swizzling[3][24], &sch->dqs[LP4_DQS3], sz);
+}
+
+int fspm_update_config(struct udevice *dev, struct fspm_upd *upd)
+{
+	struct fsp_m_config *cfg = &upd->config;
+	struct fspm_arch_upd *arch = &upd->arch;
+
+	arch->nvs_buffer_ptr = NULL;
+	prepare_mrc_cache(upd);
+	arch->stack_base = (void *)0xfef96000;
+	arch->boot_loader_tolum_size = 0;
+
+	arch->boot_mode = FSP_BOOT_WITH_FULL_CONFIGURATION;
+	cfg->serial_debug_port_type = 2;
+	cfg->serial_debug_port_device = 2;
+	cfg->serial_debug_port_stride_size = 2;
+	cfg->serial_debug_port_address = 0;
+
+	cfg->package = 1;
+	/* Don't enforce a memory size limit */
+	cfg->memory_size_limit = 0;
+	cfg->low_memory_max_value = 2048;  /* 2 GB */
+	/* No restrictions on memory above 4GiB */
+	cfg->high_memory_max_value = 0;
+
+	/* Always default to attempt to use saved training data */
+	cfg->disable_fast_boot = 0;
+
+	const u8 *swizzle_data;
+
+	swizzle_data = dev_read_u8_array_ptr(dev, "lpddr4-swizzle",
+					     LP4_NUM_BYTE_LANES *
+					     DQ_BITS_PER_DQS *
+					     LP4_NUM_PHYS_CHANNELS);
+	if (!swizzle_data)
+		return log_msg_ret("Cannot read swizzel data", -EINVAL);
+
+	setup_sdram(cfg, (struct lpddr4_swizzle_cfg *)swizzle_data);
+
+	cfg->pre_mem_gpio_table_ptr = 0;
+
+	cfg->profile = 0xb;
+	cfg->msg_level_mask = 0;
+
+	/* other */
+	cfg->skip_cse_rbp = 1;
+	cfg->periodic_retraining_disable = 0;
+	cfg->enable_s3_heci2 = 0;
+
+	return 0;
+}
+
+/*
+ * The FSP-M binary appears to break the SPI controller. It can be fixed by
+ * writing the BAR again, so do that here
+ */
+int fspm_done(struct udevice *dev)
+{
+	struct udevice *spi;
+	int ret;
+
+	/* Don't probe the device, since that reads the BAR */
+	ret = uclass_find_first_device(UCLASS_SPI, &spi);
+	if (ret)
+		return log_msg_ret("SPI", ret);
+	if (!spi)
+		return log_msg_ret("no SPI", -ENODEV);
+
+	dm_pci_write_config32(spi, PCI_BASE_ADDRESS_0,
+			      IOMAP_SPI_BASE | PCI_BASE_ADDRESS_SPACE_MEMORY);
+
+	return 0;
+}
diff --git a/arch/x86/cpu/apollolake/fsp_s.c b/arch/x86/cpu/apollolake/fsp_s.c
new file mode 100644
index 0000000..9804227
--- /dev/null
+++ b/arch/x86/cpu/apollolake/fsp_s.c
@@ -0,0 +1,661 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <acpi_s3.h>
+#include <binman.h>
+#include <dm.h>
+#include <irq.h>
+#include <asm/intel_pinctrl.h>
+#include <asm/io.h>
+#include <asm/intel_regs.h>
+#include <asm/msr.h>
+#include <asm/msr-index.h>
+#include <asm/pci.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/systemagent.h>
+#include <asm/arch/fsp/fsp_configs.h>
+#include <asm/arch/fsp/fsp_s_upd.h>
+
+#define PCH_P2SB_E0		0xe0
+#define HIDE_BIT		BIT(0)
+
+#define INTEL_GSPI_MAX		3
+#define INTEL_I2C_DEV_MAX	8
+#define MAX_USB2_PORTS		8
+
+enum {
+	CHIPSET_LOCKDOWN_FSP = 0, /* FSP handles locking per UPDs */
+	CHIPSET_LOCKDOWN_COREBOOT, /* coreboot handles locking */
+};
+
+enum i2c_speed {
+	I2C_SPEED_STANDARD	= 100000,
+	I2C_SPEED_FAST		= 400000,
+	I2C_SPEED_FAST_PLUS	= 1000000,
+	I2C_SPEED_HIGH		= 3400000,
+	I2C_SPEED_FAST_ULTRA	= 5000000,
+};
+
+/*
+ * Timing values are in units of clock period, with the clock speed
+ * provided by the SOC
+ *
+ * TODO(sjg@chromium.org): Connect this up to the I2C driver
+ */
+struct dw_i2c_speed_config {
+	enum i2c_speed speed;
+	/* SCL high and low period count */
+	u16 scl_lcnt;
+	u16 scl_hcnt;
+	/*
+	 * SDA hold time should be 300ns in standard and fast modes
+	 * and long enough for deterministic logic level change in
+	 * fast-plus and high speed modes.
+	 *
+	 *  [15:0] SDA TX Hold Time
+	 * [23:16] SDA RX Hold Time
+	 */
+	u32 sda_hold;
+};
+
+/* Serial IRQ control. SERIRQ_QUIET is the default (0) */
+enum serirq_mode {
+	SERIRQ_QUIET,
+	SERIRQ_CONTINUOUS,
+	SERIRQ_OFF,
+};
+
+/*
+ * This I2C controller has support for 3 independent speed configs but can
+ * support both FAST_PLUS and HIGH speeds through the same set of speed
+ * config registers.  These are treated separately so the speed config values
+ * can be provided via ACPI to the OS.
+ */
+#define DW_I2C_SPEED_CONFIG_COUNT	4
+
+struct dw_i2c_bus_config {
+	/* Bus should be enabled in TPL with temporary base */
+	int early_init;
+	/* Bus speed in Hz, default is I2C_SPEED_FAST (400 KHz) */
+	enum i2c_speed speed;
+	/*
+	 * If rise_time_ns is non-zero the calculations for lcnt and hcnt
+	 * registers take into account the times of the bus. However, if
+	 * there is a match in speed_config those register values take
+	 * precedence
+	 */
+	int rise_time_ns;
+	int fall_time_ns;
+	int data_hold_time_ns;
+	/* Specific bus speed configuration */
+	struct dw_i2c_speed_config speed_config[DW_I2C_SPEED_CONFIG_COUNT];
+};
+
+struct gspi_cfg {
+	/* Bus speed in MHz */
+	u32 speed_mhz;
+	/* Bus should be enabled prior to ramstage with temporary base */
+	u8 early_init;
+};
+
+/*
+ * This structure will hold data required by common blocks.
+ * These are soc specific configurations which will be filled by soc.
+ * We'll fill this structure once during init and use the data in common block.
+ */
+struct soc_intel_common_config {
+	int chipset_lockdown;
+	struct gspi_cfg gspi[INTEL_GSPI_MAX];
+	struct dw_i2c_bus_config i2c[INTEL_I2C_DEV_MAX];
+};
+
+enum pnp_settings {
+	PNP_PERF,
+	PNP_POWER,
+	PNP_PERF_POWER,
+};
+
+struct usb2_eye_per_port {
+	u8 per_port_tx_pe_half;
+	u8 per_port_pe_txi_set;
+	u8 per_port_txi_set;
+	u8 hs_skew_sel;
+	u8 usb_tx_emphasis_en;
+	u8 per_port_rxi_set;
+	u8 hs_npre_drv_sel;
+	u8 override_en;
+};
+
+struct apl_config {
+	/* Common structure containing soc config data required by common code*/
+	struct soc_intel_common_config common_soc_config;
+
+	/*
+	 * Mapping from PCIe root port to CLKREQ input on the SOC. The SOC has
+	 * four CLKREQ inputs, but six root ports. Root ports without an
+	 * associated CLKREQ signal must be marked with "CLKREQ_DISABLED"
+	 */
+	u8 pcie_rp_clkreq_pin[MAX_PCIE_PORTS];
+
+	/* Enable/disable hot-plug for root ports (0 = disable, 1 = enable) */
+	u8 pcie_rp_hotplug_enable[MAX_PCIE_PORTS];
+
+	/* De-emphasis enable configuration for each PCIe root port */
+	u8 pcie_rp_deemphasis_enable[MAX_PCIE_PORTS];
+
+	/*
+	 * [14:8] DDR mode Number of dealy elements.Each = 125pSec.
+	 * [6:0] SDR mode Number of dealy elements.Each = 125pSec.
+	 */
+	u32 emmc_tx_cmd_cntl;
+
+	/*
+	 * [14:8] HS400 mode Number of dealy elements.Each = 125pSec.
+	 * [6:0] SDR104/HS200 mode Number of dealy elements.Each = 125pSec.
+	 */
+	u32 emmc_tx_data_cntl1;
+
+	/*
+	 * [30:24] SDR50 mode Number of dealy elements.Each = 125pSec.
+	 * [22:16] DDR50 mode Number of dealy elements.Each = 125pSec.
+	 * [14:8] SDR25/HS50 mode Number of dealy elements.Each = 125pSec.
+	 * [6:0] SDR12/Compatibility mode Number of dealy elements.
+	 *       Each = 125pSec.
+	 */
+	u32 emmc_tx_data_cntl2;
+
+	/*
+	 * [30:24] SDR50 mode Number of dealy elements.Each = 125pSec.
+	 * [22:16] DDR50 mode Number of dealy elements.Each = 125pSec.
+	 * [14:8] SDR25/HS50 mode Number of dealy elements.Each = 125pSec.
+	 * [6:0] SDR12/Compatibility mode Number of dealy elements.
+	 *       Each = 125pSec.
+	 */
+	u32 emmc_rx_cmd_data_cntl1;
+
+	/*
+	 * [14:8] HS400 mode 1 Number of dealy elements.Each = 125pSec.
+	 * [6:0] HS400 mode 2 Number of dealy elements.Each = 125pSec.
+	 */
+	u32 emmc_rx_strobe_cntl;
+
+	/*
+	 * [13:8] Auto Tuning mode Number of dealy elements.Each = 125pSec.
+	 * [6:0] SDR104/HS200 Number of dealy elements.Each = 125pSec.
+	 */
+	u32 emmc_rx_cmd_data_cntl2;
+
+	/* Select the eMMC max speed allowed */
+	u32 emmc_host_max_speed;
+
+	/* Specifies on which IRQ the SCI will internally appear */
+	u32 sci_irq;
+
+	/* Configure serial IRQ (SERIRQ) line */
+	enum serirq_mode serirq_mode;
+
+	/* Configure LPSS S0ix Enable */
+	bool lpss_s0ix_enable;
+
+	/* Enable DPTF support */
+	bool dptf_enable;
+
+	/* TCC activation offset value in degrees Celsius */
+	int tcc_offset;
+
+	/*
+	 * Configure Audio clk gate and power gate
+	 * IOSF-SB port ID 92 offset 0x530 [5] and [3]
+	 */
+	bool hdaudio_clk_gate_enable;
+	bool hdaudio_pwr_gate_enable;
+	bool hdaudio_bios_config_lockdown;
+
+	/* SLP S3 minimum assertion width */
+	int slp_s3_assertion_width_usecs;
+
+	/* GPIO pin for PERST_0 */
+	u32 prt0_gpio;
+
+	/* USB2 eye diagram settings per port */
+	struct usb2_eye_per_port usb2eye[MAX_USB2_PORTS];
+
+	/* GPIO SD card detect pin */
+	unsigned int sdcard_cd_gpio;
+
+	/*
+	 * PRMRR size setting with three options
+	 *  0x02000000 - 32MiB
+	 *  0x04000000 - 64MiB
+	 *  0x08000000 - 128MiB
+	 */
+	u32 PrmrrSize;
+
+	/*
+	 * Enable SGX feature.
+	 * Enabling SGX feature is 2 step process,
+	 * (1) set sgx_enable = 1
+	 * (2) set PrmrrSize to supported size
+	 */
+	bool sgx_enable;
+
+	/*
+	 * Select PNP Settings.
+	 * (0) Performance,
+	 * (1) Power
+	 * (2) Power & Performance
+	 */
+	enum pnp_settings pnp_settings;
+
+	/*
+	 * PMIC PCH_PWROK delay configuration - IPC Configuration
+	 * Upd for changing PCH_PWROK delay configuration : I2C_Slave_Address
+	 * (31:24) + Register_Offset (23:16) + OR Value (15:8) + AND Value (7:0)
+	 */
+	u32 pmic_pmc_ipc_ctrl;
+
+	/*
+	 * Options to disable XHCI Link Compliance Mode. Default is FALSE to not
+	 * disable Compliance Mode. Set TRUE to disable Compliance Mode.
+	 * 0:FALSE(Default), 1:True.
+	 */
+	bool disable_compliance_mode;
+
+	/*
+	 * Options to change USB3 ModPhy setting for the Integrated Filter (IF)
+	 * value. Default is 0 to not changing default IF value (0x12). Set
+	 * value with the range from 0x01 to 0xff to change IF value.
+	 */
+	u32 mod_phy_if_value;
+
+	/*
+	 * Options to bump USB3 LDO voltage. Default is FALSE to not increasing
+	 * LDO voltage. Set TRUE to increase LDO voltage with 40mV.
+	 * 0:FALSE (default), 1:True.
+	 */
+	bool mod_phy_voltage_bump;
+
+	/*
+	 * Options to adjust PMIC Vdd2 voltage. Default is 0 to not adjusting
+	 * the PMIC Vdd2 default voltage 1.20v. Upd for changing Vdd2 Voltage
+	 * configuration: I2C_Slave_Address (31:23) + Register_Offset (23:16)
+	 * + OR Value (15:8) + AND Value (7:0) through BUCK5_VID[3:2]:
+	 * 00=1.10v, 01=1.15v, 10=1.24v, 11=1.20v (default).
+	 */
+	u32 pmic_vdd2_voltage;
+
+	/* Option to enable VTD feature */
+	bool enable_vtd;
+};
+
+static int get_config(struct udevice *dev, struct apl_config *apl)
+{
+	const u8 *ptr;
+	ofnode node;
+	u32 emmc[4];
+	int ret;
+
+	memset(apl, '\0', sizeof(*apl));
+
+	node = dev_read_subnode(dev, "fsp-s");
+	if (!ofnode_valid(node))
+		return log_msg_ret("fsp-s settings", -ENOENT);
+
+	ptr = ofnode_read_u8_array_ptr(node, "pcie-rp-clkreq-pin",
+				       MAX_PCIE_PORTS);
+	if (!ptr)
+		return log_msg_ret("pcie-rp-clkreq-pin", -EINVAL);
+	memcpy(apl->pcie_rp_clkreq_pin, ptr, MAX_PCIE_PORTS);
+
+	ret = ofnode_read_u32(node, "prt0-gpio", &apl->prt0_gpio);
+	if (ret)
+		return log_msg_ret("prt0-gpio", ret);
+	ret = ofnode_read_u32(node, "sdcard-cd-gpio", &apl->sdcard_cd_gpio);
+	if (ret)
+		return log_msg_ret("sdcard-cd-gpio", ret);
+
+	ret = ofnode_read_u32_array(node, "emmc", emmc, ARRAY_SIZE(emmc));
+	if (ret)
+		return log_msg_ret("emmc", ret);
+	apl->emmc_tx_data_cntl1 = emmc[0];
+	apl->emmc_tx_data_cntl2 = emmc[1];
+	apl->emmc_rx_cmd_data_cntl1 = emmc[2];
+	apl->emmc_rx_cmd_data_cntl2 = emmc[3];
+
+	apl->dptf_enable = ofnode_read_bool(node, "dptf-enable");
+
+	apl->hdaudio_clk_gate_enable = ofnode_read_bool(node,
+						"hdaudio-clk-gate-enable");
+	apl->hdaudio_pwr_gate_enable = ofnode_read_bool(node,
+						"hdaudio-pwr-gate-enable");
+	apl->hdaudio_bios_config_lockdown = ofnode_read_bool(node,
+					     "hdaudio-bios-config-lockdown");
+	apl->lpss_s0ix_enable = ofnode_read_bool(node, "lpss-s0ix-enable");
+
+	/* Santa */
+	apl->usb2eye[1].per_port_pe_txi_set = 7;
+	apl->usb2eye[1].per_port_txi_set = 2;
+
+	return 0;
+}
+
+static void apl_fsp_silicon_init_params_cb(struct apl_config *apl,
+					   struct fsp_s_config *cfg)
+{
+	u8 port;
+
+	for (port = 0; port < MAX_USB2_PORTS; port++) {
+		if (apl->usb2eye[port].per_port_tx_pe_half)
+			cfg->port_usb20_per_port_tx_pe_half[port] =
+				apl->usb2eye[port].per_port_tx_pe_half;
+
+		if (apl->usb2eye[port].per_port_pe_txi_set)
+			cfg->port_usb20_per_port_pe_txi_set[port] =
+				apl->usb2eye[port].per_port_pe_txi_set;
+
+		if (apl->usb2eye[port].per_port_txi_set)
+			cfg->port_usb20_per_port_txi_set[port] =
+				apl->usb2eye[port].per_port_txi_set;
+
+		if (apl->usb2eye[port].hs_skew_sel)
+			cfg->port_usb20_hs_skew_sel[port] =
+				apl->usb2eye[port].hs_skew_sel;
+
+		if (apl->usb2eye[port].usb_tx_emphasis_en)
+			cfg->port_usb20_i_usb_tx_emphasis_en[port] =
+				apl->usb2eye[port].usb_tx_emphasis_en;
+
+		if (apl->usb2eye[port].per_port_rxi_set)
+			cfg->port_usb20_per_port_rxi_set[port] =
+				apl->usb2eye[port].per_port_rxi_set;
+
+		if (apl->usb2eye[port].hs_npre_drv_sel)
+			cfg->port_usb20_hs_npre_drv_sel[port] =
+				apl->usb2eye[port].hs_npre_drv_sel;
+	}
+}
+
+int fsps_update_config(struct udevice *dev, ulong rom_offset,
+		       struct fsps_upd *upd)
+{
+	struct fsp_s_config *cfg = &upd->config;
+	struct apl_config *apl;
+	struct binman_entry vbt;
+	void *buf;
+	int ret;
+
+	ret = binman_entry_find("intel-vbt", &vbt);
+	if (ret)
+		return log_msg_ret("Cannot find VBT", ret);
+	vbt.image_pos += rom_offset;
+	buf = malloc(vbt.size);
+	if (!buf)
+		return log_msg_ret("Alloc VBT", -ENOMEM);
+
+	/*
+	 * Load VBT before devicetree-specific config. This only supports
+	 * memory-mapped SPI at present.
+	 */
+	bootstage_start(BOOTSTAGE_ID_ACCUM_MMAP_SPI, "mmap_spi");
+	memcpy(buf, (void *)vbt.image_pos, vbt.size);
+	bootstage_accum(BOOTSTAGE_ID_ACCUM_MMAP_SPI);
+	if (*(u32 *)buf != VBT_SIGNATURE)
+		return log_msg_ret("VBT signature", -EINVAL);
+	cfg->graphics_config_ptr = (ulong)buf;
+
+	apl = malloc(sizeof(*apl));
+	if (!apl)
+		return log_msg_ret("config", -ENOMEM);
+	get_config(dev, apl);
+
+	cfg->ish_enable = 0;
+	cfg->enable_sata = 0;
+	cfg->pcie_root_port_en[2] = 0;
+	cfg->pcie_rp_hot_plug[2] = 0;
+	cfg->pcie_root_port_en[3] = 0;
+	cfg->pcie_rp_hot_plug[3] = 0;
+	cfg->pcie_root_port_en[4] = 0;
+	cfg->pcie_rp_hot_plug[4] = 0;
+	cfg->pcie_root_port_en[5] = 0;
+	cfg->pcie_rp_hot_plug[5] = 0;
+	cfg->pcie_root_port_en[1] = 0;
+	cfg->pcie_rp_hot_plug[1] = 0;
+	cfg->usb_otg = 0;
+	cfg->i2c6_enable = 0;
+	cfg->i2c7_enable = 0;
+	cfg->hsuart3_enable = 0;
+	cfg->spi1_enable = 0;
+	cfg->spi2_enable = 0;
+	cfg->sdio_enabled = 0;
+
+	memcpy(cfg->pcie_rp_clk_req_number, apl->pcie_rp_clkreq_pin,
+	       sizeof(cfg->pcie_rp_clk_req_number));
+
+	memcpy(cfg->pcie_rp_hot_plug, apl->pcie_rp_hotplug_enable,
+	       sizeof(cfg->pcie_rp_hot_plug));
+
+	switch (apl->serirq_mode) {
+	case SERIRQ_QUIET:
+		cfg->sirq_enable = 1;
+		cfg->sirq_mode = 0;
+		break;
+	case SERIRQ_CONTINUOUS:
+		cfg->sirq_enable = 1;
+		cfg->sirq_mode = 1;
+		break;
+	case SERIRQ_OFF:
+	default:
+		cfg->sirq_enable = 0;
+		break;
+	}
+
+	if (apl->emmc_tx_cmd_cntl)
+		cfg->emmc_tx_cmd_cntl = apl->emmc_tx_cmd_cntl;
+	if (apl->emmc_tx_data_cntl1)
+		cfg->emmc_tx_data_cntl1 = apl->emmc_tx_data_cntl1;
+	if (apl->emmc_tx_data_cntl2)
+		cfg->emmc_tx_data_cntl2 = apl->emmc_tx_data_cntl2;
+	if (apl->emmc_rx_cmd_data_cntl1)
+		cfg->emmc_rx_cmd_data_cntl1 = apl->emmc_rx_cmd_data_cntl1;
+	if (apl->emmc_rx_strobe_cntl)
+		cfg->emmc_rx_strobe_cntl = apl->emmc_rx_strobe_cntl;
+	if (apl->emmc_rx_cmd_data_cntl2)
+		cfg->emmc_rx_cmd_data_cntl2 = apl->emmc_rx_cmd_data_cntl2;
+	if (apl->emmc_host_max_speed)
+		cfg->e_mmc_host_max_speed = apl->emmc_host_max_speed;
+
+	cfg->lpss_s0ix_enable = apl->lpss_s0ix_enable;
+
+	cfg->skip_mp_init = true;
+
+	/* Disable setting of EISS bit in FSP */
+	cfg->spi_eiss = 0;
+
+	/* Disable FSP from locking access to the RTC NVRAM */
+	cfg->rtc_lock = 0;
+
+	/* Enable Audio clk gate and power gate */
+	cfg->hd_audio_clk_gate = apl->hdaudio_clk_gate_enable;
+	cfg->hd_audio_pwr_gate = apl->hdaudio_pwr_gate_enable;
+	/* Bios config lockdown Audio clk and power gate */
+	cfg->bios_cfg_lock_down = apl->hdaudio_bios_config_lockdown;
+	apl_fsp_silicon_init_params_cb(apl, cfg);
+
+	cfg->usb_otg = true;
+	cfg->vtd_enable = apl->enable_vtd;
+
+	return 0;
+}
+
+static void p2sb_set_hide_bit(pci_dev_t dev, int hide)
+{
+	pci_x86_clrset_config(dev, PCH_P2SB_E0 + 1, HIDE_BIT,
+			      hide ? HIDE_BIT : 0, PCI_SIZE_8);
+}
+
+/* Configure package power limits */
+static int set_power_limits(struct udevice *dev)
+{
+	msr_t rapl_msr_reg, limit;
+	u32 power_unit;
+	u32 tdp, min_power, max_power;
+	u32 pl2_val;
+	u32 override_tdp[2];
+	int ret;
+
+	/* Get units */
+	rapl_msr_reg = msr_read(MSR_PKG_POWER_SKU_UNIT);
+	power_unit = 1 << (rapl_msr_reg.lo & 0xf);
+
+	/* Get power defaults for this SKU */
+	rapl_msr_reg = msr_read(MSR_PKG_POWER_SKU);
+	tdp = rapl_msr_reg.lo & PKG_POWER_LIMIT_MASK;
+	pl2_val = rapl_msr_reg.hi & PKG_POWER_LIMIT_MASK;
+	min_power = (rapl_msr_reg.lo >> 16) & PKG_POWER_LIMIT_MASK;
+	max_power = rapl_msr_reg.hi & PKG_POWER_LIMIT_MASK;
+
+	if (min_power > 0 && tdp < min_power)
+		tdp = min_power;
+
+	if (max_power > 0 && tdp > max_power)
+		tdp = max_power;
+
+	ret = dev_read_u32_array(dev, "tdp-pl-override-mw", override_tdp,
+				 ARRAY_SIZE(override_tdp));
+	if (ret)
+		return log_msg_ret("tdp-pl-override-mw", ret);
+
+	/* Set PL1 override value */
+	if (override_tdp[0])
+		tdp = override_tdp[0] * power_unit / 1000;
+
+	/* Set PL2 override value */
+	if (override_tdp[1])
+		pl2_val = override_tdp[1] * power_unit / 1000;
+
+	/* Set long term power limit to TDP */
+	limit.lo = tdp & PKG_POWER_LIMIT_MASK;
+	/* Set PL1 Pkg Power clamp bit */
+	limit.lo |= PKG_POWER_LIMIT_CLAMP;
+
+	limit.lo |= PKG_POWER_LIMIT_EN;
+	limit.lo |= (MB_POWER_LIMIT1_TIME_DEFAULT &
+		PKG_POWER_LIMIT_TIME_MASK) << PKG_POWER_LIMIT_TIME_SHIFT;
+
+	/* Set short term power limit PL2 */
+	limit.hi = pl2_val & PKG_POWER_LIMIT_MASK;
+	limit.hi |= PKG_POWER_LIMIT_EN;
+
+	/* Program package power limits in RAPL MSR */
+	msr_write(MSR_PKG_POWER_LIMIT, limit);
+	log_info("RAPL PL1 %d.%dW\n", tdp / power_unit,
+		 100 * (tdp % power_unit) / power_unit);
+	log_info("RAPL PL2 %d.%dW\n", pl2_val / power_unit,
+		 100 * (pl2_val % power_unit) / power_unit);
+
+	/*
+	 * Sett RAPL MMIO register for Power limits. RAPL driver is using MSR
+	 * instead of MMIO, so disable LIMIT_EN bit for MMIO
+	 */
+	writel(limit.lo & ~PKG_POWER_LIMIT_EN, MCHBAR_REG(MCHBAR_RAPL_PPL));
+	writel(limit.hi & ~PKG_POWER_LIMIT_EN, MCHBAR_REG(MCHBAR_RAPL_PPL + 4));
+
+	return 0;
+}
+
+int p2sb_unhide(void)
+{
+	pci_dev_t dev = PCI_BDF(0, 0xd, 0);
+	ulong val;
+
+	p2sb_set_hide_bit(dev, 0);
+
+	pci_x86_read_config(dev, PCI_VENDOR_ID, &val, PCI_SIZE_16);
+
+	if (val != PCI_VENDOR_ID_INTEL)
+		return log_msg_ret("p2sb unhide", -EIO);
+
+	return 0;
+}
+
+/* Overwrites the SCI IRQ if another IRQ number is given by device tree */
+static void set_sci_irq(void)
+{
+	/* Skip this for now */
+}
+
+int arch_fsps_preinit(void)
+{
+	struct udevice *itss;
+	int ret;
+
+	ret = uclass_first_device_err(UCLASS_IRQ, &itss);
+	if (ret)
+		return log_msg_ret("no itss", ret);
+	/*
+	 * Snapshot the current GPIO IRQ polarities. FSP is setting a default
+	 * policy that doesn't honour boards' requirements
+	 */
+	irq_snapshot_polarities(itss);
+
+	/*
+	 * Clear the GPI interrupt status and enable registers. These
+	 * registers do not get reset to default state when booting from S5.
+	 */
+	ret = pinctrl_gpi_clear_int_cfg();
+	if (ret)
+		return log_msg_ret("gpi_clear", ret);
+
+	return 0;
+}
+
+int arch_fsp_init_r(void)
+{
+#ifdef CONFIG_HAVE_ACPI_RESUME
+	bool s3wake = gd->arch.prev_sleep_state == ACPI_S3;
+#else
+	bool s3wake = false;
+#endif
+	struct udevice *dev, *itss;
+	int ret;
+
+	/*
+	 * This must be called before any devices are probed. Put any probing
+	 * into arch_fsps_preinit() above.
+	 *
+	 * We don't use CONFIG_APL_BOOT_FROM_FAST_SPI_FLASH here since it will
+	 * force PCI to be probed.
+	 */
+	ret = fsp_silicon_init(s3wake, false);
+	if (ret)
+		return ret;
+
+	ret = uclass_first_device_err(UCLASS_IRQ, &itss);
+	if (ret)
+		return log_msg_ret("no itss", ret);
+	/* Restore GPIO IRQ polarities back to previous settings */
+	irq_restore_polarities(itss);
+
+	/* soc_init() */
+	ret = p2sb_unhide();
+	if (ret)
+		return log_msg_ret("unhide p2sb", ret);
+
+	/* Set RAPL MSR for Package power limits*/
+	ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &dev);
+	if (ret)
+		return log_msg_ret("Cannot get northbridge", ret);
+	set_power_limits(dev);
+
+	/*
+	 * FSP-S routes SCI to IRQ 9. With the help of this function you can
+	 * select another IRQ for SCI.
+	 */
+	set_sci_irq();
+
+	return 0;
+}
diff --git a/arch/x86/cpu/apollolake/hostbridge.c b/arch/x86/cpu/apollolake/hostbridge.c
new file mode 100644
index 0000000..793853d
--- /dev/null
+++ b/arch/x86/cpu/apollolake/hostbridge.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <spl.h>
+#include <asm/intel_pinctrl.h>
+#include <asm/intel_regs.h>
+#include <asm/pci.h>
+#include <asm/arch/systemagent.h>
+
+/**
+ * struct apl_hostbridge_platdata - platform data for hostbridge
+ *
+ * @dtplat: Platform data for of-platdata
+ * @early_pads: Early pad data to set up, each (pad, cfg0, cfg1)
+ * @early_pads_count: Number of pads to process
+ * @pciex_region_size: BAR length in bytes
+ * @bdf: Bus/device/function of hostbridge
+ */
+struct apl_hostbridge_platdata {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct dtd_intel_apl_hostbridge dtplat;
+#endif
+	u32 *early_pads;
+	int early_pads_count;
+	uint pciex_region_size;
+	pci_dev_t bdf;
+};
+
+enum {
+	PCIEXBAR		= 0x60,
+	PCIEXBAR_LENGTH_256MB	= 0,
+	PCIEXBAR_LENGTH_128MB,
+	PCIEXBAR_LENGTH_64MB,
+
+	PCIEXBAR_PCIEXBAREN	= 1 << 0,
+
+	TSEG			= 0xb8,  /* TSEG base */
+};
+
+static int apl_hostbridge_early_init_pinctrl(struct udevice *dev)
+{
+	struct apl_hostbridge_platdata *plat = dev_get_platdata(dev);
+	struct udevice *pinctrl;
+	int ret;
+
+	ret = uclass_first_device_err(UCLASS_PINCTRL, &pinctrl);
+	if (ret)
+		return log_msg_ret("no hostbridge pinctrl", ret);
+
+	return pinctrl_config_pads(pinctrl, plat->early_pads,
+				   plat->early_pads_count);
+}
+
+static int apl_hostbridge_early_init(struct udevice *dev)
+{
+	struct apl_hostbridge_platdata *plat = dev_get_platdata(dev);
+	u32 region_size;
+	ulong base;
+	u32 reg;
+	int ret;
+
+	/* Set up the MCHBAR */
+	pci_x86_read_config(plat->bdf, MCHBAR, &base, PCI_SIZE_32);
+	base = MCH_BASE_ADDRESS;
+	pci_x86_write_config(plat->bdf, MCHBAR, base | 1, PCI_SIZE_32);
+
+	/*
+	 * The PCIEXBAR is assumed to live in the memory mapped IO space under
+	 * 4GiB
+	 */
+	pci_x86_write_config(plat->bdf, PCIEXBAR + 4, 0, PCI_SIZE_32);
+
+	switch (plat->pciex_region_size >> 20) {
+	default:
+	case 256:
+		region_size = PCIEXBAR_LENGTH_256MB;
+		break;
+	case 128:
+		region_size = PCIEXBAR_LENGTH_128MB;
+		break;
+	case 64:
+		region_size = PCIEXBAR_LENGTH_64MB;
+		break;
+	}
+
+	reg = CONFIG_MMCONF_BASE_ADDRESS | (region_size << 1)
+				| PCIEXBAR_PCIEXBAREN;
+	pci_x86_write_config(plat->bdf, PCIEXBAR, reg, PCI_SIZE_32);
+
+	/*
+	 * 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_x86_write_config(plat->bdf, TSEG, 0, PCI_SIZE_32);
+
+	ret = apl_hostbridge_early_init_pinctrl(dev);
+	if (ret)
+		return log_msg_ret("pinctrl", ret);
+
+	return 0;
+}
+
+static int apl_hostbridge_ofdata_to_platdata(struct udevice *dev)
+{
+	struct apl_hostbridge_platdata *plat = dev_get_platdata(dev);
+	struct udevice *pinctrl;
+	int ret;
+
+	/*
+	 * The host bridge holds the early pad data needed to get through TPL.
+	 * This is a small amount of data, enough to fit in TPL, so we keep it
+	 * separate from the full pad data, stored in the fsp-s subnode. That
+	 * subnode is not present in TPL, to save space.
+	 */
+	ret = uclass_first_device_err(UCLASS_PINCTRL, &pinctrl);
+	if (ret)
+		return log_msg_ret("no hostbridge PINCTRL", ret);
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	int root;
+
+	/* Get length of PCI Express Region */
+	plat->pciex_region_size = dev_read_u32_default(dev, "pciex-region-size",
+						       256 << 20);
+
+	root = pci_get_devfn(dev);
+	if (root < 0)
+		return log_msg_ret("Cannot get host-bridge PCI address", root);
+	plat->bdf = root;
+
+	ret = pinctrl_read_pads(pinctrl, dev_ofnode(dev), "early-pads",
+				&plat->early_pads, &plat->early_pads_count);
+	if (ret)
+		return log_msg_ret("early-pads", ret);
+#else
+	struct dtd_intel_apl_hostbridge *dtplat = &plat->dtplat;
+	int size;
+
+	plat->pciex_region_size = dtplat->pciex_region_size;
+	plat->bdf = pci_ofplat_get_devfn(dtplat->reg[0]);
+
+	/* Assume that if everything is 0, it is empty */
+	plat->early_pads = dtplat->early_pads;
+	size = ARRAY_SIZE(dtplat->early_pads);
+	plat->early_pads_count = pinctrl_count_pads(pinctrl, plat->early_pads,
+						    size);
+
+#endif
+
+	return 0;
+}
+
+static int apl_hostbridge_probe(struct udevice *dev)
+{
+	if (spl_phase() == PHASE_TPL)
+		return apl_hostbridge_early_init(dev);
+
+	return 0;
+}
+
+static const struct udevice_id apl_hostbridge_ids[] = {
+	{ .compatible = "intel,apl-hostbridge" },
+	{ }
+};
+
+U_BOOT_DRIVER(apl_hostbridge_drv) = {
+	.name		= "intel_apl_hostbridge",
+	.id		= UCLASS_NORTHBRIDGE,
+	.of_match	= apl_hostbridge_ids,
+	.ofdata_to_platdata = apl_hostbridge_ofdata_to_platdata,
+	.probe		= apl_hostbridge_probe,
+	.platdata_auto_alloc_size = sizeof(struct apl_hostbridge_platdata),
+};
diff --git a/arch/x86/cpu/apollolake/itss.c b/arch/x86/cpu/apollolake/itss.c
new file mode 100644
index 0000000..8789f8e
--- /dev/null
+++ b/arch/x86/cpu/apollolake/itss.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Something to do with Interrupts, but I don't know what ITSS stands for
+ *
+ * Copyright (C) 2017 Intel Corporation.
+ * Copyright (C) 2017 Siemens AG
+ * Copyright 2019 Google LLC
+ *
+ * Taken from coreboot itss.c
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <irq.h>
+#include <p2sb.h>
+#include <spl.h>
+#include <asm/arch/itss.h>
+
+struct apl_itss_platdata {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	/* Put this first since driver model will copy the data here */
+	struct dtd_intel_apl_itss dtplat;
+#endif
+};
+
+/* struct pmc_route - Routing for PMC to GPIO */
+struct pmc_route {
+	u32 pmc;
+	u32 gpio;
+};
+
+struct apl_itss_priv {
+	struct pmc_route *route;
+	uint route_count;
+	u32 irq_snapshot[NUM_IPC_REGS];
+};
+
+static int apl_set_polarity(struct udevice *dev, uint irq, bool active_low)
+{
+	u32 mask;
+	uint reg;
+
+	if (irq > ITSS_MAX_IRQ)
+		return -EINVAL;
+
+	reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * (irq / IRQS_PER_IPC);
+	mask = 1 << (irq % IRQS_PER_IPC);
+
+	pcr_clrsetbits32(dev, reg, mask, active_low ? mask : 0);
+
+	return 0;
+}
+
+#ifndef CONFIG_TPL_BUILD
+static int apl_snapshot_polarities(struct udevice *dev)
+{
+	struct apl_itss_priv *priv = dev_get_priv(dev);
+	const int start = GPIO_IRQ_START;
+	const int end = GPIO_IRQ_END;
+	int reg_start;
+	int reg_end;
+	int i;
+
+	reg_start = start / IRQS_PER_IPC;
+	reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC;
+
+	for (i = reg_start; i < reg_end; i++) {
+		uint reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i;
+
+		priv->irq_snapshot[i] = pcr_read32(dev, reg);
+	}
+
+	return 0;
+}
+
+static void show_polarities(struct udevice *dev, const char *msg)
+{
+	int i;
+
+	log_info("ITSS IRQ Polarities %s:\n", msg);
+	for (i = 0; i < NUM_IPC_REGS; i++) {
+		uint reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i;
+
+		log_info("IPC%d: 0x%08x\n", i, pcr_read32(dev, reg));
+	}
+}
+
+static int apl_restore_polarities(struct udevice *dev)
+{
+	struct apl_itss_priv *priv = dev_get_priv(dev);
+	const int start = GPIO_IRQ_START;
+	const int end = GPIO_IRQ_END;
+	int reg_start;
+	int reg_end;
+	int i;
+
+	show_polarities(dev, "Before");
+
+	reg_start = start / IRQS_PER_IPC;
+	reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC;
+
+	for (i = reg_start; i < reg_end; i++) {
+		u32 mask;
+		u16 reg;
+		int irq_start;
+		int irq_end;
+
+		irq_start = i * IRQS_PER_IPC;
+		irq_end = min(irq_start + IRQS_PER_IPC - 1, ITSS_MAX_IRQ);
+
+		if (start > irq_end)
+			continue;
+		if (end < irq_start)
+			break;
+
+		/* Track bits within the bounds of of the register */
+		irq_start = max(start, irq_start) % IRQS_PER_IPC;
+		irq_end = min(end, irq_end) % IRQS_PER_IPC;
+
+		/* Create bitmask of the inclusive range of start and end */
+		mask = (((1U << irq_end) - 1) | (1U << irq_end));
+		mask &= ~((1U << irq_start) - 1);
+
+		reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i;
+		pcr_clrsetbits32(dev, reg, mask, mask & priv->irq_snapshot[i]);
+	}
+
+	show_polarities(dev, "After");
+
+	return 0;
+}
+#endif
+
+static int apl_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num)
+{
+	struct apl_itss_priv *priv = dev_get_priv(dev);
+	struct pmc_route *route;
+	int i;
+
+	for (i = 0, route = priv->route; i < priv->route_count; i++, route++) {
+		if (pmc_gpe_num == route->pmc)
+			return route->gpio;
+	}
+
+	return -ENOENT;
+}
+
+static int apl_itss_ofdata_to_platdata(struct udevice *dev)
+{
+	struct apl_itss_priv *priv = dev_get_priv(dev);
+	int ret;
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct apl_itss_platdata *plat = dev_get_platdata(dev);
+	struct dtd_intel_apl_itss *dtplat = &plat->dtplat;
+
+	/*
+	 * It would be nice to do this in the bind() method, but with
+	 * of-platdata binding happens in the order that DM finds things in the
+	 * linker list (i.e. alphabetical order by driver name). So the GPIO
+	 * device may well be bound before its parent (p2sb), and this call
+	 * will fail if p2sb is not bound yet.
+	 *
+	 * TODO(sjg@chromium.org): Add a parent pointer to child devices in dtoc
+	 */
+	ret = p2sb_set_port_id(dev, dtplat->intel_p2sb_port_id);
+	if (ret)
+		return log_msg_ret("Could not set port id", ret);
+	priv->route = (struct pmc_route *)dtplat->intel_pmc_routes;
+	priv->route_count = ARRAY_SIZE(dtplat->intel_pmc_routes) /
+		 sizeof(struct pmc_route);
+#else
+	int size;
+
+	size = dev_read_size(dev, "intel,pmc-routes");
+	if (size < 0)
+		return size;
+	priv->route = malloc(size);
+	if (!priv->route)
+		return -ENOMEM;
+	ret = dev_read_u32_array(dev, "intel,pmc-routes", (u32 *)priv->route,
+				 size / sizeof(fdt32_t));
+	if (ret)
+		return log_msg_ret("Cannot read pmc-routes", ret);
+	priv->route_count = size / sizeof(struct pmc_route);
+#endif
+
+	return 0;
+}
+
+static const struct irq_ops apl_itss_ops = {
+	.route_pmc_gpio_gpe	= apl_route_pmc_gpio_gpe,
+	.set_polarity	= apl_set_polarity,
+#ifndef CONFIG_TPL_BUILD
+	.snapshot_polarities = apl_snapshot_polarities,
+	.restore_polarities = apl_restore_polarities,
+#endif
+};
+
+static const struct udevice_id apl_itss_ids[] = {
+	{ .compatible = "intel,apl-itss"},
+	{ }
+};
+
+U_BOOT_DRIVER(apl_itss_drv) = {
+	.name		= "intel_apl_itss",
+	.id		= UCLASS_IRQ,
+	.of_match	= apl_itss_ids,
+	.ops		= &apl_itss_ops,
+	.ofdata_to_platdata = apl_itss_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct apl_itss_platdata),
+	.priv_auto_alloc_size = sizeof(struct apl_itss_priv),
+};
diff --git a/arch/x86/cpu/apollolake/lpc.c b/arch/x86/cpu/apollolake/lpc.c
new file mode 100644
index 0000000..45b2144
--- /dev/null
+++ b/arch/x86/cpu/apollolake/lpc.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ *
+ * From coreboot Apollo Lake support lpc.c
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <spl.h>
+#include <asm/lpc_common.h>
+#include <asm/pci.h>
+#include <asm/arch/iomap.h>
+#include <asm/arch/lpc.h>
+#include <linux/log2.h>
+
+void lpc_enable_fixed_io_ranges(uint io_enables)
+{
+	pci_x86_clrset_config(PCH_DEV_LPC, LPC_IO_ENABLES, 0, io_enables,
+			      PCI_SIZE_16);
+}
+
+/*
+ * Find the first unused IO window.
+ * Returns -1 if not found, 0 for reg 0x84, 1 for reg 0x88 ...
+ */
+static int find_unused_pmio_window(void)
+{
+	int i;
+	ulong lgir;
+
+	for (i = 0; i < LPC_NUM_GENERIC_IO_RANGES; i++) {
+		pci_x86_read_config(PCH_DEV_LPC, LPC_GENERIC_IO_RANGE(i),
+				    &lgir, PCI_SIZE_32);
+
+		if (!(lgir & LPC_LGIR_EN))
+			return i;
+	}
+
+	return -1;
+}
+
+int lpc_open_pmio_window(uint base, uint size)
+{
+	int i, lgir_reg_num;
+	u32 lgir_reg_offset, lgir, window_size, alignment;
+	ulong bridged_size, bridge_base;
+	ulong reg;
+
+	log_debug("LPC: Trying to open IO window from %x size %x\n", base,
+		  size);
+
+	bridged_size = 0;
+	bridge_base = base;
+
+	while (bridged_size < size) {
+		/* Each IO range register can only open a 256-byte window */
+		window_size = min(size, (uint)LPC_LGIR_MAX_WINDOW_SIZE);
+
+		/* Window size must be a power of two for the AMASK to work */
+		alignment = 1UL << (order_base_2(window_size));
+		window_size = ALIGN(window_size, alignment);
+
+		/* Address[15:2] in LGIR[15:12] and Mask[7:2] in LGIR[23:18] */
+		lgir = (bridge_base & LPC_LGIR_ADDR_MASK) | LPC_LGIR_EN;
+		lgir |= ((window_size - 1) << 16) & LPC_LGIR_AMASK_MASK;
+
+		/* Skip programming if same range already programmed */
+		for (i = 0; i < LPC_NUM_GENERIC_IO_RANGES; i++) {
+			pci_x86_read_config(PCH_DEV_LPC,
+					    LPC_GENERIC_IO_RANGE(i), &reg,
+					    PCI_SIZE_32);
+			if (lgir == reg)
+				return -EALREADY;
+		}
+
+		lgir_reg_num = find_unused_pmio_window();
+		if (lgir_reg_num < 0) {
+			log_err("LPC: Cannot open IO window: %lx size %lx\n",
+				bridge_base, size - bridged_size);
+			log_err("No more IO windows\n");
+
+			return -ENOSPC;
+		}
+		lgir_reg_offset = LPC_GENERIC_IO_RANGE(lgir_reg_num);
+
+		pci_x86_write_config(PCH_DEV_LPC, lgir_reg_offset, lgir,
+				     PCI_SIZE_32);
+
+		log_debug("LPC: Opened IO window LGIR%d: base %lx size %x\n",
+			  lgir_reg_num, bridge_base, window_size);
+
+		bridged_size += window_size;
+		bridge_base += window_size;
+	}
+
+	return 0;
+}
+
+void lpc_io_setup_comm_a_b(void)
+{
+	/* ComA Range 3F8h-3FFh [2:0] */
+	u16 com_ranges = LPC_IOD_COMA_RANGE;
+	u16 com_enable = LPC_IOE_COMA_EN;
+
+	/* Setup I/O Decode Range Register for LPC */
+	pci_write_config16(PCH_DEV_LPC, LPC_IO_DECODE, com_ranges);
+	/* Enable ComA and ComB Port */
+	lpc_enable_fixed_io_ranges(com_enable);
+}
+
+static const struct udevice_id apl_lpc_ids[] = {
+	{ .compatible = "intel,apl-lpc" },
+	{ }
+};
+
+/* All pads are LPC already configured by the hostbridge, so no probing here */
+U_BOOT_DRIVER(apl_lpc_drv) = {
+	.name		= "intel_apl_lpc",
+	.id		= UCLASS_LPC,
+	.of_match	= apl_lpc_ids,
+};
diff --git a/arch/x86/cpu/apollolake/p2sb.c b/arch/x86/cpu/apollolake/p2sb.c
new file mode 100644
index 0000000..eb27861
--- /dev/null
+++ b/arch/x86/cpu/apollolake/p2sb.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Primary-to-Sideband Bridge
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#define LOG_CATEGORY UCLASS_P2SB
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <p2sb.h>
+#include <spl.h>
+#include <asm/pci.h>
+
+struct p2sb_platdata {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct dtd_intel_apl_p2sb dtplat;
+#endif
+	ulong mmio_base;
+	pci_dev_t bdf;
+};
+
+/* PCI config space registers */
+#define HPTC_OFFSET		0x60
+#define HPTC_ADDR_ENABLE_BIT	BIT(7)
+
+/* High Performance Event Timer Configuration */
+#define P2SB_HPTC				0x60
+#define P2SB_HPTC_ADDRESS_ENABLE		BIT(7)
+
+/*
+ * ADDRESS_SELECT            ENCODING_RANGE
+ *      0                 0xfed0 0000 - 0xfed0 03ff
+ *      1                 0xfed0 1000 - 0xfed0 13ff
+ *      2                 0xfed0 2000 - 0xfed0 23ff
+ *      3                 0xfed0 3000 - 0xfed0 33ff
+ */
+#define P2SB_HPTC_ADDRESS_SELECT_0		(0 << 0)
+#define P2SB_HPTC_ADDRESS_SELECT_1		(1 << 0)
+#define P2SB_HPTC_ADDRESS_SELECT_2		(2 << 0)
+#define P2SB_HPTC_ADDRESS_SELECT_3		(3 << 0)
+
+/*
+ * apl_p2sb_early_init() - Enable decoding for HPET range
+ *
+ * This is needed by FSP-M which uses the High Precision Event Timer.
+ *
+ * @dev: P2SB device
+ * @return 0 if OK, -ve on error
+ */
+static int apl_p2sb_early_init(struct udevice *dev)
+{
+	struct p2sb_platdata *plat = dev_get_platdata(dev);
+	pci_dev_t pdev = plat->bdf;
+
+	/*
+	 * Enable decoding for HPET memory address range.
+	 * HPTC_OFFSET(0x60) bit 7, when set the P2SB will decode
+	 * the High Performance Timer memory address range
+	 * selected by bits 1:0
+	 */
+	pci_x86_write_config(pdev, HPTC_OFFSET, HPTC_ADDR_ENABLE_BIT,
+			     PCI_SIZE_8);
+
+	/* Enable PCR Base address in PCH */
+	pci_x86_write_config(pdev, PCI_BASE_ADDRESS_0, plat->mmio_base,
+			     PCI_SIZE_32);
+	pci_x86_write_config(pdev, PCI_BASE_ADDRESS_1, 0, PCI_SIZE_32);
+
+	/* Enable P2SB MSE */
+	pci_x86_write_config(pdev, PCI_COMMAND, PCI_COMMAND_MASTER |
+			     PCI_COMMAND_MEMORY, PCI_SIZE_8);
+
+	return 0;
+}
+
+static int apl_p2sb_spl_init(struct udevice *dev)
+{
+	/* Enable decoding for HPET. Needed for FSP global pointer storage */
+	dm_pci_write_config(dev, P2SB_HPTC, P2SB_HPTC_ADDRESS_SELECT_0 |
+			    P2SB_HPTC_ADDRESS_ENABLE, PCI_SIZE_8);
+
+	return 0;
+}
+
+int apl_p2sb_ofdata_to_platdata(struct udevice *dev)
+{
+	struct p2sb_uc_priv *upriv = dev_get_uclass_priv(dev);
+	struct p2sb_platdata *plat = dev_get_platdata(dev);
+
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	int ret;
+
+	if (spl_phase() == PHASE_TPL) {
+		u32 base[2];
+
+		/* TPL sets up the initial BAR */
+		ret = dev_read_u32_array(dev, "early-regs", base,
+					 ARRAY_SIZE(base));
+		if (ret)
+			return log_msg_ret("Missing/short early-regs", ret);
+		plat->mmio_base = base[0];
+		plat->bdf = pci_get_devfn(dev);
+		if (plat->bdf < 0)
+			return log_msg_ret("Cannot get p2sb PCI address",
+					   plat->bdf);
+	} else {
+		plat->mmio_base = dev_read_addr_pci(dev);
+		/* Don't set BDF since it should not be used */
+		if (!plat->mmio_base || plat->mmio_base == FDT_ADDR_T_NONE)
+			return -EINVAL;
+	}
+#else
+	plat->mmio_base = plat->dtplat.early_regs[0];
+	plat->bdf = pci_ofplat_get_devfn(plat->dtplat.reg[0]);
+#endif
+	upriv->mmio_base = plat->mmio_base;
+	debug("p2sb: mmio_base=%x\n", (uint)plat->mmio_base);
+
+	return 0;
+}
+
+static int apl_p2sb_probe(struct udevice *dev)
+{
+	if (spl_phase() == PHASE_TPL)
+		return apl_p2sb_early_init(dev);
+	else if (spl_phase() == PHASE_SPL)
+		return apl_p2sb_spl_init(dev);
+
+	return 0;
+}
+
+static int p2sb_child_post_bind(struct udevice *dev)
+{
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
+	int ret;
+	u32 pid;
+
+	ret = dev_read_u32(dev, "intel,p2sb-port-id", &pid);
+	if (ret)
+		return ret;
+	pplat->pid = pid;
+#endif
+
+	return 0;
+}
+
+static const struct udevice_id apl_p2sb_ids[] = {
+	{ .compatible = "intel,apl-p2sb" },
+	{ }
+};
+
+U_BOOT_DRIVER(apl_p2sb_drv) = {
+	.name		= "intel_apl_p2sb",
+	.id		= UCLASS_P2SB,
+	.of_match	= apl_p2sb_ids,
+	.probe		= apl_p2sb_probe,
+	.ofdata_to_platdata = apl_p2sb_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct p2sb_platdata),
+	.per_child_platdata_auto_alloc_size =
+		sizeof(struct p2sb_child_platdata),
+	.child_post_bind = p2sb_child_post_bind,
+};
diff --git a/arch/x86/cpu/apollolake/pch.c b/arch/x86/cpu/apollolake/pch.c
new file mode 100644
index 0000000..1a5a985
--- /dev/null
+++ b/arch/x86/cpu/apollolake/pch.c
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pch.h>
+#include <spl.h>
+#include <asm/lpc_common.h>
+
+#define BIOS_CTRL	0xdc
+
+static int apl_set_spi_protect(struct udevice *dev, bool protect)
+{
+	if (spl_phase() == PHASE_SPL)
+		return lpc_set_spi_protect(dev, BIOS_CTRL, protect);
+
+	return 0;
+}
+
+static const struct pch_ops apl_pch_ops = {
+	.set_spi_protect = apl_set_spi_protect,
+};
+
+static const struct udevice_id apl_pch_ids[] = {
+	{ .compatible = "intel,apl-pch" },
+	{ }
+};
+
+U_BOOT_DRIVER(apl_pch) = {
+	.name		= "apl_pch",
+	.id		= UCLASS_PCH,
+	.of_match	= apl_pch_ids,
+	.ops		= &apl_pch_ops,
+};
diff --git a/arch/x86/cpu/apollolake/pmc.c b/arch/x86/cpu/apollolake/pmc.c
new file mode 100644
index 0000000..683c608
--- /dev/null
+++ b/arch/x86/cpu/apollolake/pmc.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Intel Corporation.
+ * Copyright 2019 Google LLC
+ *
+ * Modified from coreboot pmclib.c, pmc.c and pmutil.c
+ */
+
+#define LOG_CATEGORY UCLASS_ACPI_PMC
+
+#include <common.h>
+#include <acpi_s3.h>
+#include <dt-structs.h>
+#include <dm.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <power/acpi_pmc.h>
+
+#define GPIO_GPE_CFG		0x1050
+
+/* Memory mapped IO registers behind PMC_BASE_ADDRESS */
+#define PRSTS			0x1000
+#define GEN_PMCON1		0x1020
+#define  COLD_BOOT_STS		BIT(27)
+#define  COLD_RESET_STS		BIT(26)
+#define  WARM_RESET_STS		BIT(25)
+#define  GLOBAL_RESET_STS	BIT(24)
+#define  SRS			BIT(20)
+#define  MS4V			BIT(18)
+#define  RPS			BIT(2)
+#define GEN_PMCON1_CLR1_BITS	(COLD_BOOT_STS | COLD_RESET_STS | \
+				 WARM_RESET_STS | GLOBAL_RESET_STS | \
+				 SRS | MS4V)
+#define GEN_PMCON2		0x1024
+#define GEN_PMCON3		0x1028
+
+/* Offset of TCO registers from ACPI base I/O address */
+#define TCO_REG_OFFSET		0x60
+#define TCO1_STS	0x64
+#define   DMISCI_STS	BIT(9)
+#define   BOOT_STS	BIT(18)
+#define TCO2_STS	0x66
+#define TCO1_CNT	0x68
+#define   TCO_LOCK	BIT(12)
+#define TCO2_CNT	0x6a
+
+enum {
+	ETR		= 0x1048,
+	CF9_LOCK        = 1UL << 31,
+	CF9_GLB_RST	= 1 << 20,
+};
+
+struct apl_pmc_platdata {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct dtd_intel_apl_pmc dtplat;
+#endif
+	pci_dev_t bdf;
+};
+
+static int apl_pmc_fill_power_state(struct udevice *dev)
+{
+	struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+
+	upriv->tco1_sts = inw(upriv->acpi_base + TCO1_STS);
+	upriv->tco2_sts = inw(upriv->acpi_base + TCO2_STS);
+
+	upriv->prsts = readl(upriv->pmc_bar0 + PRSTS);
+	upriv->gen_pmcon1 = readl(upriv->pmc_bar0 + GEN_PMCON1);
+	upriv->gen_pmcon2 = readl(upriv->pmc_bar0 + GEN_PMCON2);
+	upriv->gen_pmcon3 = readl(upriv->pmc_bar0 + GEN_PMCON3);
+
+	return 0;
+}
+
+static int apl_prev_sleep_state(struct udevice *dev, int prev_sleep_state)
+{
+	struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+
+	/* WAK_STS bit will not be set when waking from G3 state */
+	if (!(upriv->pm1_sts & WAK_STS) &&
+	    (upriv->gen_pmcon1 & COLD_BOOT_STS))
+		prev_sleep_state = ACPI_S5;
+
+	return prev_sleep_state;
+}
+
+static int apl_disable_tco(struct udevice *dev)
+{
+	struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+
+	pmc_disable_tco_base(upriv->acpi_base + TCO_REG_OFFSET);
+
+	return 0;
+}
+
+static int apl_global_reset_set_enable(struct udevice *dev, bool enable)
+{
+	struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+
+	if (enable)
+		setbits_le32(upriv->pmc_bar0 + ETR, CF9_GLB_RST);
+	else
+		clrbits_le32(upriv->pmc_bar0 + ETR, CF9_GLB_RST);
+
+	return 0;
+}
+
+int apl_pmc_ofdata_to_uc_platdata(struct udevice *dev)
+{
+	struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+	struct apl_pmc_platdata *plat = dev_get_platdata(dev);
+
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	u32 base[6];
+	int size;
+	int ret;
+
+	ret = dev_read_u32_array(dev, "early-regs", base, ARRAY_SIZE(base));
+	if (ret)
+		return log_msg_ret("Missing/short early-regs", ret);
+	upriv->pmc_bar0 = (void *)base[0];
+	upriv->pmc_bar2 = (void *)base[2];
+	upriv->acpi_base = base[4];
+
+	/* Since PCI is not enabled, we must get the BDF manually */
+	plat->bdf = pci_get_devfn(dev);
+	if (plat->bdf < 0)
+		return log_msg_ret("Cannot get PMC PCI address", plat->bdf);
+
+	/* Get the dwX values for pmc gpe settings */
+	size = dev_read_size(dev, "gpe0-dw");
+	if (size < 0)
+		return log_msg_ret("Cannot read gpe0-dm", size);
+	upriv->gpe0_count = size / sizeof(u32);
+	ret = dev_read_u32_array(dev, "gpe0-dw", upriv->gpe0_dw,
+				 upriv->gpe0_count);
+	if (ret)
+		return log_msg_ret("Bad gpe0-dw", ret);
+
+	return pmc_ofdata_to_uc_platdata(dev);
+#else
+	struct dtd_intel_apl_pmc *dtplat = &plat->dtplat;
+
+	plat->bdf = pci_ofplat_get_devfn(dtplat->reg[0]);
+	upriv->pmc_bar0 = (void *)dtplat->early_regs[0];
+	upriv->pmc_bar2 = (void *)dtplat->early_regs[2];
+	upriv->acpi_base = dtplat->early_regs[4];
+	upriv->gpe0_dwx_mask = dtplat->gpe0_dwx_mask;
+	upriv->gpe0_dwx_shift_base = dtplat->gpe0_dwx_shift_base;
+	upriv->gpe0_sts_reg = dtplat->gpe0_sts;
+	upriv->gpe0_sts_reg += upriv->acpi_base;
+	upriv->gpe0_en_reg = dtplat->gpe0_en;
+	upriv->gpe0_en_reg += upriv->acpi_base;
+	upriv->gpe0_count = min((int)ARRAY_SIZE(dtplat->gpe0_dw), GPE0_REG_MAX);
+	memcpy(upriv->gpe0_dw, dtplat->gpe0_dw, sizeof(dtplat->gpe0_dw));
+#endif
+	upriv->gpe_cfg = (u32 *)(upriv->pmc_bar0 + GPIO_GPE_CFG);
+
+	return 0;
+}
+
+static int enable_pmcbar(struct udevice *dev)
+{
+	struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+	struct apl_pmc_platdata *priv = dev_get_platdata(dev);
+	pci_dev_t pmc = priv->bdf;
+
+	/*
+	 * Set PMC base addresses and enable decoding. BARs 1 and 3 are 64-bit
+	 * BARs.
+	 */
+	pci_x86_write_config(pmc, PCI_BASE_ADDRESS_0, (ulong)upriv->pmc_bar0,
+			     PCI_SIZE_32);
+	pci_x86_write_config(pmc, PCI_BASE_ADDRESS_1, 0, PCI_SIZE_32);
+	pci_x86_write_config(pmc, PCI_BASE_ADDRESS_2, (ulong)upriv->pmc_bar2,
+			     PCI_SIZE_32);
+	pci_x86_write_config(pmc, PCI_BASE_ADDRESS_3, 0, PCI_SIZE_32);
+	pci_x86_write_config(pmc, PCI_BASE_ADDRESS_4, upriv->acpi_base,
+			     PCI_SIZE_16);
+	pci_x86_write_config(pmc, PCI_COMMAND, PCI_COMMAND_IO |
+			     PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
+			     PCI_SIZE_16);
+
+	return 0;
+}
+
+static int apl_pmc_probe(struct udevice *dev)
+{
+	if (spl_phase() == PHASE_TPL)
+		return enable_pmcbar(dev);
+
+	return 0;
+}
+
+static struct acpi_pmc_ops apl_pmc_ops = {
+	.init			= apl_pmc_fill_power_state,
+	.prev_sleep_state	= apl_prev_sleep_state,
+	.disable_tco		= apl_disable_tco,
+	.global_reset_set_enable = apl_global_reset_set_enable,
+};
+
+static const struct udevice_id apl_pmc_ids[] = {
+	{ .compatible = "intel,apl-pmc" },
+	{ }
+};
+
+U_BOOT_DRIVER(apl_pmc) = {
+	.name		= "intel_apl_pmc",
+	.id		= UCLASS_ACPI_PMC,
+	.of_match	= apl_pmc_ids,
+	.ofdata_to_platdata = apl_pmc_ofdata_to_uc_platdata,
+	.probe		= apl_pmc_probe,
+	.ops		= &apl_pmc_ops,
+	.platdata_auto_alloc_size = sizeof(struct apl_pmc_platdata),
+};
diff --git a/arch/x86/cpu/apollolake/punit.c b/arch/x86/cpu/apollolake/punit.c
new file mode 100644
index 0000000..1a131fb
--- /dev/null
+++ b/arch/x86/cpu/apollolake/punit.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <spl.h>
+#include <asm/cpu.h>
+#include <asm/cpu_common.h>
+#include <asm/intel_regs.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <asm/arch/systemagent.h>
+
+/*
+ * Punit Initialisation code. This all isn't documented, but
+ * this is the recipe.
+ */
+static int punit_init(struct udevice *dev)
+{
+	struct udevice *cpu;
+	u32 reg;
+	ulong start;
+	int ret;
+
+	/* Thermal throttle activation offset */
+	ret = uclass_first_device_err(UCLASS_CPU, &cpu);
+	if (ret)
+		return log_msg_ret("Cannot find CPU", ret);
+	cpu_configure_thermal_target(cpu);
+
+	/*
+	 * Software Core Disable Mask (P_CR_CORE_DISABLE_MASK_0_0_0_MCHBAR).
+	 * Enable all cores here.
+	 */
+	writel(0, MCHBAR_REG(CORE_DISABLE_MASK));
+
+	/* P-Unit bring up */
+	reg = readl(MCHBAR_REG(BIOS_RESET_CPL));
+	if (reg == 0xffffffff) {
+		/* P-unit not found */
+		debug("Punit MMIO not available\n");
+		return -ENOENT;
+	}
+
+	/* Set Punit interrupt pin IPIN offset 3D */
+	dm_pci_write_config8(dev, PCI_INTERRUPT_PIN, 0x2);
+
+	/* Set PUINT IRQ to 24 and INTPIN LOCK */
+	writel(PUINT_THERMAL_DEVICE_IRQ_VEC_NUMBER |
+	       PUINT_THERMAL_DEVICE_IRQ_LOCK,
+	       MCHBAR_REG(PUNIT_THERMAL_DEVICE_IRQ));
+
+	/* Stage0 BIOS Reset Complete (RST_CPL) */
+	enable_bios_reset_cpl();
+
+	/*
+	 * Poll for bit 8 to check if PCODE has completed its action in response
+	 * to BIOS Reset complete.  We wait here till 1 ms for the bit to get
+	 * set.
+	 */
+	start = get_timer(0);
+	while (!(readl(MCHBAR_REG(BIOS_RESET_CPL)) & PCODE_INIT_DONE)) {
+		if (get_timer(start) > 1) {
+			debug("PCODE Init Done timeout\n");
+			return -ETIMEDOUT;
+		}
+		udelay(100);
+	}
+	debug("PUNIT init complete\n");
+
+	return 0;
+}
+
+static int apl_punit_probe(struct udevice *dev)
+{
+	if (spl_phase() == PHASE_SPL)
+		return punit_init(dev);
+
+	return 0;
+}
+
+static const struct udevice_id apl_syscon_ids[] = {
+	{ .compatible = "intel,apl-punit", .data = X86_SYSCON_PUNIT },
+	{ }
+};
+
+U_BOOT_DRIVER(syscon_intel_punit) = {
+	.name		= "intel_punit_syscon",
+	.id		= UCLASS_SYSCON,
+	.of_match	= apl_syscon_ids,
+	.probe		= apl_punit_probe,
+};
diff --git a/arch/x86/cpu/apollolake/spl.c b/arch/x86/cpu/apollolake/spl.c
new file mode 100644
index 0000000..7ab7243
--- /dev/null
+++ b/arch/x86/cpu/apollolake/spl.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <binman_sym.h>
+#include <dm.h>
+#include <spi.h>
+#include <spl.h>
+#include <spi_flash.h>
+#include <asm/fast_spi.h>
+#include <asm/spl.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/iomap.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+
+/* This reads the next phase from mapped SPI flash */
+static int rom_load_image(struct spl_image_info *spl_image,
+			  struct spl_boot_device *bootdev)
+{
+	ulong spl_pos = spl_get_image_pos();
+	ulong spl_size = spl_get_image_size();
+	struct udevice *dev;
+	ulong map_base;
+	size_t map_size;
+	uint offset;
+	int ret;
+
+	spl_image->size = CONFIG_SYS_MONITOR_LEN;  /* We don't know SPL size */
+	spl_image->entry_point = spl_phase() == PHASE_TPL ?
+		CONFIG_SPL_TEXT_BASE : CONFIG_SYS_TEXT_BASE;
+	spl_image->load_addr = spl_image->entry_point;
+	spl_image->os = IH_OS_U_BOOT;
+	spl_image->name = "U-Boot";
+	debug("Reading from mapped SPI %lx, size %lx", spl_pos, spl_size);
+
+	if (CONFIG_IS_ENABLED(SPI_FLASH_SUPPORT)) {
+		ret = uclass_find_first_device(UCLASS_SPI_FLASH, &dev);
+		if (ret)
+			return log_msg_ret("spi_flash", ret);
+		if (!dev)
+			return log_msg_ret("spi_flash dev", -ENODEV);
+		ret = dm_spi_get_mmap(dev, &map_base, &map_size, &offset);
+		if (ret)
+			return log_msg_ret("mmap", ret);
+	} else {
+		ret = fast_spi_get_bios_mmap(PCH_DEV_SPI, &map_base, &map_size,
+					     &offset);
+		if (ret)
+			return ret;
+	}
+	spl_pos += map_base & ~0xff000000;
+	debug(", base %lx, pos %lx\n", map_base, spl_pos);
+	bootstage_start(BOOTSTAGE_ID_ACCUM_MMAP_SPI, "mmap_spi");
+	memcpy((void *)spl_image->load_addr, (void *)spl_pos, spl_size);
+	cpu_flush_l1d_to_l2();
+	bootstage_accum(BOOTSTAGE_ID_ACCUM_MMAP_SPI);
+
+	return 0;
+}
+SPL_LOAD_IMAGE_METHOD("Mapped SPI", 2, BOOT_DEVICE_SPI_MMAP, rom_load_image);
+
+#if CONFIG_IS_ENABLED(SPI_FLASH_SUPPORT)
+
+static int apl_flash_std_read(struct udevice *dev, u32 offset, size_t len,
+			      void *buf)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(dev);
+	struct mtd_info *mtd = &flash->mtd;
+	size_t retlen;
+
+	return log_ret(mtd->_read(mtd, offset, len, &retlen, buf));
+}
+
+static int apl_flash_probe(struct udevice *dev)
+{
+	return spi_flash_std_probe(dev);
+}
+
+/*
+ * Manually set the parent of the SPI flash to SPI, since dtoc doesn't. We also
+ * need to allocate the parent_platdata since by the time this function is
+ * called device_bind() has already gone past that step.
+ */
+static int apl_flash_bind(struct udevice *dev)
+{
+	if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
+		struct dm_spi_slave_platdata *plat;
+		struct udevice *spi;
+		int ret;
+
+		ret = uclass_first_device_err(UCLASS_SPI, &spi);
+		if (ret)
+			return ret;
+		dev->parent = spi;
+
+		plat = calloc(sizeof(*plat), 1);
+		if (!plat)
+			return -ENOMEM;
+		dev->parent_platdata = plat;
+	}
+
+	return 0;
+}
+
+static const struct dm_spi_flash_ops apl_flash_ops = {
+	.read		= apl_flash_std_read,
+};
+
+static const struct udevice_id apl_flash_ids[] = {
+	{ .compatible = "jedec,spi-nor" },
+	{ }
+};
+
+U_BOOT_DRIVER(winbond_w25q128fw) = {
+	.name		= "winbond_w25q128fw",
+	.id		= UCLASS_SPI_FLASH,
+	.of_match	= apl_flash_ids,
+	.bind		= apl_flash_bind,
+	.probe		= apl_flash_probe,
+	.priv_auto_alloc_size = sizeof(struct spi_flash),
+	.ops		= &apl_flash_ops,
+};
+
+/* This uses a SPI flash device to read the next phase */
+static int spl_fast_spi_load_image(struct spl_image_info *spl_image,
+				   struct spl_boot_device *bootdev)
+{
+	ulong spl_pos = spl_get_image_pos();
+	ulong spl_size = spl_get_image_size();
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_first_device_err(UCLASS_SPI_FLASH, &dev);
+	if (ret)
+		return ret;
+
+	spl_image->size = CONFIG_SYS_MONITOR_LEN;  /* We don't know SPL size */
+	spl_image->entry_point = spl_phase() == PHASE_TPL ?
+		CONFIG_SPL_TEXT_BASE : CONFIG_SYS_TEXT_BASE;
+	spl_image->load_addr = spl_image->entry_point;
+	spl_image->os = IH_OS_U_BOOT;
+	spl_image->name = "U-Boot";
+	spl_pos &= ~0xff000000;
+	debug("Reading from flash %lx, size %lx\n", spl_pos, spl_size);
+	ret = spi_flash_read_dm(dev, spl_pos, spl_size,
+				(void *)spl_image->load_addr);
+	cpu_flush_l1d_to_l2();
+	if (ret)
+		return ret;
+
+	return 0;
+}
+SPL_LOAD_IMAGE_METHOD("Fast SPI", 1, BOOT_DEVICE_FAST_SPI,
+		      spl_fast_spi_load_image);
+
+void board_boot_order(u32 *spl_boot_list)
+{
+	bool use_spi_flash = IS_ENABLED(CONFIG_APL_BOOT_FROM_FAST_SPI_FLASH);
+
+	if (use_spi_flash) {
+		spl_boot_list[0] = BOOT_DEVICE_FAST_SPI;
+		spl_boot_list[1] = BOOT_DEVICE_SPI_MMAP;
+	} else {
+		spl_boot_list[0] = BOOT_DEVICE_SPI_MMAP;
+		spl_boot_list[1] = BOOT_DEVICE_FAST_SPI;
+	}
+}
+
+#else
+
+void board_boot_order(u32 *spl_boot_list)
+{
+	spl_boot_list[0] = BOOT_DEVICE_SPI_MMAP;
+}
+#endif
diff --git a/arch/x86/cpu/apollolake/systemagent.c b/arch/x86/cpu/apollolake/systemagent.c
new file mode 100644
index 0000000..b6bc2ba
--- /dev/null
+++ b/arch/x86/cpu/apollolake/systemagent.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Intel Corporation.
+ * Take from coreboot project file of the same name
+ */
+
+#include <common.h>
+#include <asm/intel_regs.h>
+#include <asm/io.h>
+#include <asm/arch/systemagent.h>
+
+void enable_bios_reset_cpl(void)
+{
+	/*
+	 * Set bits 0+1 of BIOS_RESET_CPL to indicate to the CPU
+	 * that BIOS has initialised memory and power management
+	 *
+	 * The FSP-S does not do this. If we leave this as zero then I believe
+	 * the power-aware interrupts don't work in Linux, and CPU 0 always gets
+	 * the interrupt.
+	 */
+	setbits_8(MCHBAR_REG(BIOS_RESET_CPL), 3);
+}
diff --git a/arch/x86/cpu/apollolake/uart.c b/arch/x86/cpu/apollolake/uart.c
new file mode 100644
index 0000000..f2b356e
--- /dev/null
+++ b/arch/x86/cpu/apollolake/uart.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Special driver to handle of-platdata
+ *
+ * Copyright 2019 Google LLC
+ *
+ * Some code from coreboot lpss.c
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <ns16550.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <asm/lpss.h>
+
+/* Low-power Subsystem (LPSS) clock register */
+enum {
+	LPSS_CLOCK_CTL_REG	= 0x200,
+	LPSS_CNT_CLOCK_EN	= 1,
+	LPSS_CNT_CLK_UPDATE	= 1U << 31,
+	LPSS_CLOCK_DIV_N_SHIFT	= 16,
+	LPSS_CLOCK_DIV_N_MASK	= 0x7fff << LPSS_CLOCK_DIV_N_SHIFT,
+	LPSS_CLOCK_DIV_M_SHIFT	= 1,
+	LPSS_CLOCK_DIV_M_MASK	= 0x7fff << LPSS_CLOCK_DIV_M_SHIFT,
+
+	/* These set the UART input clock speed */
+	LPSS_UART_CLK_M_VAL	= 0x25a,
+	LPSS_UART_CLK_N_VAL	= 0x7fff,
+};
+
+static void lpss_clk_update(void *regs, u32 clk_m_val, u32 clk_n_val)
+{
+	u32 clk_sel;
+
+	clk_sel = clk_n_val << LPSS_CLOCK_DIV_N_SHIFT |
+		 clk_m_val << LPSS_CLOCK_DIV_M_SHIFT;
+	clk_sel |= LPSS_CNT_CLK_UPDATE | LPSS_CNT_CLOCK_EN;
+
+	writel(clk_sel, regs + LPSS_CLOCK_CTL_REG);
+}
+
+static void uart_lpss_init(void *regs)
+{
+	/* Take UART out of reset */
+	lpss_reset_release(regs);
+
+	/* Set M and N divisor inputs and enable clock */
+	lpss_clk_update(regs, LPSS_UART_CLK_M_VAL, LPSS_UART_CLK_N_VAL);
+}
+
+void apl_uart_init(pci_dev_t bdf, ulong base)
+{
+	/* Set UART base address */
+	pci_x86_write_config(bdf, PCI_BASE_ADDRESS_0, base, PCI_SIZE_32);
+
+	/* Enable memory access and bus master */
+	pci_x86_write_config(bdf, PCI_COMMAND, PCI_COMMAND_MEMORY |
+			     PCI_COMMAND_MASTER, PCI_SIZE_32);
+
+	uart_lpss_init((void *)base);
+}
+
+/*
+ * This driver uses its own compatible string but almost everything else from
+ * the standard ns16550 driver. This allows us to provide an of-platdata
+ * implementation, since the platdata produced by of-platdata does not match
+ * struct ns16550_platdata.
+ *
+ * When running with of-platdata (generally TPL), the platdata is converted to
+ * something that ns16550 expects. When running withoutof-platdata (SPL, U-Boot
+ * proper), we use ns16550's ofdata_to_platdata routine.
+ */
+
+static int apl_ns16550_probe(struct udevice *dev)
+{
+	struct ns16550_platdata *plat = dev_get_platdata(dev);
+
+	if (!CONFIG_IS_ENABLED(PCI))
+		apl_uart_init(plat->bdf, plat->base);
+
+	return ns16550_serial_probe(dev);
+}
+
+static int apl_ns16550_ofdata_to_platdata(struct udevice *dev)
+{
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct dtd_intel_apl_ns16550 *dtplat = dev_get_platdata(dev);
+	struct ns16550_platdata *plat;
+
+	/*
+	 * Convert our platdata to the ns16550's platdata, so we can just use
+	 * that driver
+	 */
+	plat = malloc(sizeof(*plat));
+	if (!plat)
+		return -ENOMEM;
+	plat->base = dtplat->early_regs[0];
+	plat->reg_width = 1;
+	plat->reg_shift = dtplat->reg_shift;
+	plat->reg_offset = 0;
+	plat->clock = dtplat->clock_frequency;
+	plat->fcr = UART_FCR_DEFVAL;
+	plat->bdf = pci_ofplat_get_devfn(dtplat->reg[0]);
+	dev->platdata = plat;
+#else
+	int ret;
+
+	ret = ns16550_serial_ofdata_to_platdata(dev);
+	if (ret)
+		return ret;
+#endif /* OF_PLATDATA */
+
+	return 0;
+}
+
+static const struct udevice_id apl_ns16550_serial_ids[] = {
+	{ .compatible = "intel,apl-ns16550" },
+	{ },
+};
+
+U_BOOT_DRIVER(apl_ns16550) = {
+	.name	= "intel_apl_ns16550",
+	.id	= UCLASS_SERIAL,
+	.of_match = apl_ns16550_serial_ids,
+	.platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
+	.priv_auto_alloc_size = sizeof(struct NS16550),
+	.ops	= &ns16550_serial_ops,
+	.ofdata_to_platdata = apl_ns16550_ofdata_to_platdata,
+	.probe = apl_ns16550_probe,
+};
diff --git a/arch/x86/cpu/broadwell/sdram.c b/arch/x86/cpu/broadwell/sdram.c
index dfd8afc..15bfc58 100644
--- a/arch/x86/cpu/broadwell/sdram.c
+++ b/arch/x86/cpu/broadwell/sdram.c
@@ -83,7 +83,7 @@
 	struct mrc_region entry;
 	int ret;
 
-	ret = mrccache_get_region(NULL, &entry);
+	ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry);
 	if (ret)
 		return ret;
 	mrc_cache = mrccache_find_current(&entry);
@@ -169,12 +169,14 @@
 	      pei_data->data_to_save);
 	/* S3 resume: don't save scrambler seed or MRC data */
 	if (pei_data->boot_mode != SLEEP_STATE_S3) {
+		struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
+
 		/*
 		 * This will be copied to SDRAM in reserve_arch(), then written
 		 * to SPI flash in mrccache_save()
 		 */
-		gd->arch.mrc_output = (char *)pei_data->data_to_save;
-		gd->arch.mrc_output_len = pei_data->data_to_save_size;
+		mrc->buf = (char *)pei_data->data_to_save;
+		mrc->len = pei_data->data_to_save_size;
 	}
 	gd->arch.pei_meminfo = pei_data->meminfo;
 
diff --git a/arch/x86/cpu/coreboot/Kconfig b/arch/x86/cpu/coreboot/Kconfig
index 93f61f2..c8e6a88 100644
--- a/arch/x86/cpu/coreboot/Kconfig
+++ b/arch/x86/cpu/coreboot/Kconfig
@@ -24,5 +24,6 @@
 	imply CMD_CBFS
 	imply FS_CBFS
 	imply CBMEM_CONSOLE
+	imply X86_TSC_READ_BASE
 
 endif
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c
index 4e59476..d626e38 100644
--- a/arch/x86/cpu/cpu.c
+++ b/arch/x86/cpu/cpu.c
@@ -46,6 +46,7 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#ifndef CONFIG_TPL_BUILD
 static const char *const x86_vendor_name[] = {
 	[X86_VENDOR_INTEL]     = "Intel",
 	[X86_VENDOR_CYRIX]     = "Cyrix",
@@ -58,6 +59,7 @@
 	[X86_VENDOR_NSC]       = "NSC",
 	[X86_VENDOR_SIS]       = "SiS",
 };
+#endif
 
 int __weak x86_cleanup_before_linux(void)
 {
@@ -114,6 +116,7 @@
 	return 1;
 }
 
+#ifndef CONFIG_TPL_BUILD
 const char *cpu_vendor_name(int vendor)
 {
 	const char *name;
@@ -124,6 +127,7 @@
 
 	return name;
 }
+#endif
 
 char *cpu_get_name(char *name)
 {
diff --git a/arch/x86/cpu/i386/Makefile b/arch/x86/cpu/i386/Makefile
index 0c47252..18e15207 100644
--- a/arch/x86/cpu/i386/Makefile
+++ b/arch/x86/cpu/i386/Makefile
@@ -5,5 +5,7 @@
 
 obj-y += call64.o
 obj-y += cpu.o
+ifndef CONFIG_TPL_BUILD
 obj-y += interrupt.o
+endif
 obj-y += setjmp.o
diff --git a/arch/x86/cpu/i386/cpu.c b/arch/x86/cpu/i386/cpu.c
index c66382b..2b27617 100644
--- a/arch/x86/cpu/i386/cpu.c
+++ b/arch/x86/cpu/i386/cpu.c
@@ -21,6 +21,7 @@
 #include <common.h>
 #include <cpu_func.h>
 #include <malloc.h>
+#include <spl.h>
 #include <asm/control_regs.h>
 #include <asm/cpu.h>
 #include <asm/mp.h>
@@ -58,6 +59,8 @@
 	uint8_t x86_mask;
 };
 
+/* gcc 7.3 does not wwant to drop x86_vendors, so use #ifdef */
+#ifndef CONFIG_TPL_BUILD
 /*
  * List of cpu vendor strings along with their normalized
  * id values.
@@ -78,6 +81,7 @@
 	{ X86_VENDOR_NSC,       "Geode by NSC", },
 	{ X86_VENDOR_SIS,       "SiS SiS SiS ", },
 };
+#endif
 
 static void load_ds(u32 segment)
 {
@@ -199,6 +203,7 @@
 	return (unsigned char) (test >> 8) == 0x02;
 }
 
+#ifndef CONFIG_TPL_BUILD
 /*
  *	Detect a NexGen CPU running without BIOS hypercode new enough
  *	to have CPUID. (Thanks to Herbert Oppmann)
@@ -219,6 +224,7 @@
 		: "=a" (ret) : : "cx", "dx");
 	return  ret;
 }
+#endif
 
 static bool has_cpuid(void)
 {
@@ -230,6 +236,7 @@
 	return cpuid_edx(0x00000001) & (1 << 12) ? true : false;
 }
 
+#ifndef CONFIG_TPL_BUILD
 static int build_vendor_name(char *vendor_name)
 {
 	struct cpuid_result result;
@@ -242,14 +249,40 @@
 
 	return result.eax;
 }
+#endif
 
 static void identify_cpu(struct cpu_device_id *cpu)
 {
+	cpu->device = 0; /* fix gcc 4.4.4 warning */
+
+	/*
+	 * Do a quick and dirty check to save space - Intel and AMD only and
+	 * just the vendor. This is enough for most TPL code.
+	 */
+	if (spl_phase() == PHASE_TPL) {
+		struct cpuid_result result;
+
+		result = cpuid(0x00000000);
+		switch (result.ecx >> 24) {
+		case 'l': /* GenuineIntel */
+			cpu->vendor = X86_VENDOR_INTEL;
+			break;
+		case 'D': /* AuthenticAMD */
+			cpu->vendor = X86_VENDOR_AMD;
+			break;
+		default:
+			cpu->vendor = X86_VENDOR_ANY;
+			break;
+		}
+		return;
+	}
+
+/* gcc 7.3 does not want to drop x86_vendors, so use #ifdef */
+#ifndef CONFIG_TPL_BUILD
 	char vendor_name[16];
 	int i;
 
 	vendor_name[0] = '\0'; /* Unset */
-	cpu->device = 0; /* fix gcc 4.4.4 warning */
 
 	/* Find the id and vendor_name */
 	if (!has_cpuid()) {
@@ -265,9 +298,8 @@
 		/* Detect NexGen with old hypercode */
 		else if (deep_magic_nexgen_probe())
 			memcpy(vendor_name, "NexGenDriven", 13);
-	}
-	if (has_cpuid()) {
-		int  cpuid_level;
+	} else {
+		int cpuid_level;
 
 		cpuid_level = build_vendor_name(vendor_name);
 		vendor_name[12] = '\0';
@@ -287,6 +319,7 @@
 			break;
 		}
 	}
+#endif
 }
 
 static inline void get_fms(struct cpuinfo_x86 *c, uint32_t tfms)
diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile
index 07f27c2..cc4e1c9 100644
--- a/arch/x86/cpu/intel_common/Makefile
+++ b/arch/x86/cpu/intel_common/Makefile
@@ -8,8 +8,18 @@
 obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += report_platform.o
 obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += mrc.o
 endif
+
+ifdef CONFIG_INTEL_CAR_CQOS
+obj-$(CONFIG_TPL_BUILD) += car2.o
+ifndef CONFIG_SPL_BUILD
+obj-y += car2_uninit.o
+endif
+endif
+
 obj-y += cpu.o
+obj-y += fast_spi.o
 obj-y += lpc.o
+obj-y += lpss.o
 ifndef CONFIG_TARGET_EFI_APP
 obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += microcode.o
 ifndef CONFIG_$(SPL_)X86_64
diff --git a/arch/x86/cpu/intel_common/car2.S b/arch/x86/cpu/intel_common/car2.S
new file mode 100644
index 0000000..086f987
--- /dev/null
+++ b/arch/x86/cpu/intel_common/car2.S
@@ -0,0 +1,448 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This file was modified from the coreboot version.
+ *
+ * Copyright (C) 2015-2016 Intel Corp.
+ */
+
+#include <config.h>
+#include <asm/msr-index.h>
+#include <asm/mtrr.h>
+#include <asm/post.h>
+#include <asm/processor.h>
+#include <asm/processor-flags.h>
+
+#define KiB 1024
+
+#define IS_POWER_OF_2(x)	(!((x) & ((x) - 1)))
+
+.global car_init
+car_init:
+	post_code(POST_CAR_START)
+
+	/*
+	 * Use the MTRR default type MSR as a proxy for detecting INIT#.
+	 * Reset the system if any known bits are set in that MSR. That is
+	 * an indication of the CPU not being properly reset.
+	 */
+check_for_clean_reset:
+	mov	$MTRR_DEF_TYPE_MSR, %ecx
+	rdmsr
+	and	$(MTRR_DEF_TYPE_EN | MTRR_DEF_TYPE_FIX_EN), %eax
+	cmp	$0, %eax
+	jz	no_reset
+	/* perform warm reset */
+	movw	$IO_PORT_RESET, %dx
+	movb	$(SYS_RST | RST_CPU), %al
+	outb	%al, %dx
+
+no_reset:
+	post_code(POST_CAR_SIPI)
+
+	/* Clear/disable fixed MTRRs */
+	mov	$fixed_mtrr_list_size, %ebx
+	xor	%eax, %eax
+	xor	%edx, %edx
+
+clear_fixed_mtrr:
+	add	$-2, %ebx
+	movzwl	fixed_mtrr_list(%ebx), %ecx
+	wrmsr
+	jnz	clear_fixed_mtrr
+
+	post_code(POST_CAR_MTRR)
+
+	/* Figure put how many MTRRs we have, and clear them out */
+	mov	$MTRR_CAP_MSR, %ecx
+	rdmsr
+	movzb	%al, %ebx		/* Number of variable MTRRs */
+	mov	$MTRR_PHYS_BASE_MSR(0), %ecx
+	xor	%eax, %eax
+	xor	%edx, %edx
+
+clear_var_mtrr:
+	wrmsr
+	inc	%ecx
+	wrmsr
+	inc	%ecx
+	dec	%ebx
+	jnz	clear_var_mtrr
+
+	post_code(POST_CAR_UNCACHEABLE)
+
+	/* Configure default memory type to uncacheable (UC) */
+	mov	$MTRR_DEF_TYPE_MSR, %ecx
+	rdmsr
+	/* Clear enable bits and set default type to UC */
+	and	$~(MTRR_DEF_TYPE_MASK | MTRR_DEF_TYPE_EN | \
+		 MTRR_DEF_TYPE_FIX_EN), %eax
+	wrmsr
+
+	/*
+	 * Configure MTRR_PHYS_MASK_HIGH for proper addressing above 4GB
+	 * based on the physical address size supported for this processor
+	 * This is based on read from CPUID EAX = 080000008h, EAX bits [7:0]
+	 *
+	 * Examples:
+	 *  MTRR_PHYS_MASK_HIGH = 00000000Fh  For 36 bit addressing
+	 *  MTRR_PHYS_MASK_HIGH = 0000000FFh  For 40 bit addressing
+	 */
+
+	movl	$0x80000008, %eax 	/* Address sizes leaf */
+	cpuid
+	sub	$32, %al
+	movzx	%al, %eax
+	xorl	%esi, %esi
+	bts	%eax, %esi
+	dec	%esi			/* esi <- MTRR_PHYS_MASK_HIGH */
+
+	post_code(POST_CAR_BASE_ADDRESS)
+
+#if IS_POWER_OF_2(CONFIG_DCACHE_RAM_SIZE)
+	/* Configure CAR region as write-back (WB) */
+	mov	$MTRR_PHYS_BASE_MSR(0), %ecx
+	mov	$CONFIG_DCACHE_RAM_BASE, %eax
+	or	$MTRR_TYPE_WRBACK, %eax
+	xor	%edx,%edx
+	wrmsr
+
+	/* Configure the MTRR mask for the size region */
+	mov	$MTRR_PHYS_MASK(0), %ecx
+	mov	$CONFIG_DCACHE_RAM_SIZE, %eax	/* size mask */
+	dec	%eax
+	not	%eax
+	or	$MTRR_PHYS_MASK_VALID, %eax
+	movl	%esi, %edx	/* edx <- MTRR_PHYS_MASK_HIGH */
+	wrmsr
+#elif (CONFIG_DCACHE_RAM_SIZE == 768 * KiB) /* 768 KiB */
+	/* Configure CAR region as write-back (WB) */
+	mov	$MTRR_PHYS_BASE_MSR(0), %ecx
+	mov	$CONFIG_DCACHE_RAM_BASE, %eax
+	or	$MTRR_TYPE_WRBACK, %eax
+	xor	%edx,%edx
+	wrmsr
+
+	mov	$MTRR_PHYS_MASK_MSR(0), %ecx
+	mov	$(512 * KiB), %eax	/* size mask */
+	dec	%eax
+	not	%eax
+	or	$MTRR_PHYS_MASK_VALID, %eax
+	movl	%esi, %edx	/* edx <- MTRR_PHYS_MASK_HIGH */
+	wrmsr
+
+	mov	$MTRR_PHYS_BASE_MSR(1), %ecx
+	mov	$(CONFIG_DCACHE_RAM_BASE + 512 * KiB), %eax
+	or	$MTRR_TYPE_WRBACK, %eax
+	xor	%edx,%edx
+	wrmsr
+
+	mov	$MTRR_PHYS_MASK_MSR(1), %ecx
+	mov	$(256 * KiB), %eax	/* size mask */
+	dec	%eax
+	not	%eax
+	or	$MTRR_PHYS_MASK_VALID, %eax
+	movl	%esi, %edx	/* edx <- MTRR_PHYS_MASK_HIGH */
+	wrmsr
+#else
+#error "DCACHE_RAM_SIZE is not a power of 2 and setup code is missing"
+#endif
+	post_code(POST_CAR_FILL)
+
+	/* Enable variable MTRRs */
+	mov	$MTRR_DEF_TYPE_MSR, %ecx
+	rdmsr
+	or	$MTRR_DEF_TYPE_EN, %eax
+	wrmsr
+
+	/* Enable caching */
+	mov	%cr0, %eax
+	and	$~(X86_CR0_CD | X86_CR0_NW), %eax
+	invd
+	mov	%eax, %cr0
+
+#if IS_ENABLED(CONFIG_INTEL_CAR_NEM)
+	jmp	car_nem
+#elif IS_ENABLED(CONFIG_INTEL_CAR_CQOS)
+	jmp	car_cqos
+#elif IS_ENABLED(CONFIG_INTEL_CAR_NEM_ENHANCED)
+	jmp	car_nem_enhanced
+#else
+#error "No CAR mechanism selected:
+#endif
+	jmp	car_init_ret
+
+fixed_mtrr_list:
+	.word	MTRR_FIX_64K_00000_MSR
+	.word	MTRR_FIX_16K_80000_MSR
+	.word	MTRR_FIX_16K_A0000_MSR
+	.word	MTRR_FIX_4K_C0000_MSR
+	.word	MTRR_FIX_4K_C8000_MSR
+	.word	MTRR_FIX_4K_D0000_MSR
+	.word	MTRR_FIX_4K_D8000_MSR
+	.word	MTRR_FIX_4K_E0000_MSR
+	.word	MTRR_FIX_4K_E8000_MSR
+	.word	MTRR_FIX_4K_F0000_MSR
+	.word	MTRR_FIX_4K_F8000_MSR
+fixed_mtrr_list_size = . - fixed_mtrr_list
+
+#if IS_ENABLED(CONFIG_INTEL_CAR_NEM)
+.global car_nem
+car_nem:
+	/* Disable cache eviction (setup stage) */
+	mov	$MSR_EVICT_CTL, %ecx
+	rdmsr
+	or	$0x1, %eax
+	wrmsr
+
+	post_code(0x26)
+
+	/* Clear the cache memory region. This will also fill up the cache */
+	movl	$CONFIG_DCACHE_RAM_BASE, %edi
+	movl	$CONFIG_DCACHE_RAM_SIZE, %ecx
+	shr	$0x02, %ecx
+	xor	%eax, %eax
+	cld
+	rep	stosl
+
+	post_code(0x27)
+
+	/* Disable cache eviction (run stage) */
+	mov	$MSR_EVICT_CTL, %ecx
+	rdmsr
+	or	$0x2, %eax
+	wrmsr
+
+	post_code(0x28)
+
+	jmp	car_init_ret
+
+#elif IS_ENABLED(CONFIG_INTEL_CAR_CQOS)
+.global car_cqos
+car_cqos:
+	/*
+	 * Create CBM_LEN_MASK based on CBM_LEN
+	 * Get CPUID.(EAX=10H, ECX=2H):EAX.CBM_LEN[bits 4:0]
+	 */
+	mov	$0x10, %eax
+	mov	$0x2,  %ecx
+	cpuid
+	and	$0x1f, %eax
+	add	$1, %al
+
+	mov	$1, %ebx
+	mov	%al, %cl
+	shl	%cl, %ebx
+	sub	$1, %ebx
+
+	/* Store the CBM_LEN_MASK in mm3 for later use */
+	movd	%ebx, %mm3
+
+	/*
+	 * Disable both L1 and L2 prefetcher. For yet-to-understood reason,
+	 * prefetchers slow down filling cache with rep stos in CQOS mode.
+	 */
+	mov	$MSR_PREFETCH_CTL, %ecx
+	rdmsr
+	or	$(PREFETCH_L1_DISABLE | PREFETCH_L2_DISABLE), %eax
+	wrmsr
+
+#if (CONFIG_DCACHE_RAM_SIZE == CONFIG_L2_CACHE_SIZE)
+/*
+ * If CAR size is set to full L2 size, mask is calculated as all-zeros.
+ * This is not supported by the CPU/uCode.
+ */
+#error "CQOS CAR may not use whole L2 cache area"
+#endif
+
+	/* Calculate how many bits to be used for CAR */
+	xor	%edx, %edx
+	mov	$CONFIG_DCACHE_RAM_SIZE, %eax	/* dividend */
+	mov	$CONFIG_CACHE_QOS_SIZE_PER_BIT, %ecx	/* divisor */
+	div	%ecx		/* result is in eax */
+	mov	%eax, %ecx	/* save to ecx */
+	mov	$1, %ebx
+	shl	%cl, %ebx
+	sub	$1, %ebx	/* resulting mask is is in ebx */
+
+	/* Set this mask for initial cache fill */
+	mov	$MSR_L2_QOS_MASK(0), %ecx
+	rdmsr
+	mov	%ebx, %eax
+	wrmsr
+
+	/* Set CLOS selector to 0 */
+	mov	$MSR_IA32_PQR_ASSOC, %ecx
+	rdmsr
+	and	$~MSR_IA32_PQR_ASSOC_MASK, %edx	/* select mask 0 */
+	wrmsr
+
+	/* We will need to block CAR region from evicts */
+	mov	$MSR_L2_QOS_MASK(1), %ecx
+	rdmsr
+	/* Invert bits that are to be used for cache */
+	mov	%ebx, %eax
+	xor	$~0, %eax			/* invert 32 bits */
+
+	/*
+	 * Use CBM_LEN_MASK stored in mm3 to set bits based on Capacity Bit
+	 * Mask Length.
+	 */
+	movd	%mm3, %ebx
+	and	%ebx, %eax
+	wrmsr
+
+	post_code(0x26)
+
+	/* Clear the cache memory region. This will also fill up the cache */
+	movl	$CONFIG_DCACHE_RAM_BASE, %edi
+	movl	$CONFIG_DCACHE_RAM_SIZE, %ecx
+	shr	$0x02, %ecx
+	xor	%eax, %eax
+	cld
+	rep	stosl
+
+	post_code(0x27)
+
+	/* Cache is populated. Use mask 1 that will block evicts */
+	mov	$MSR_IA32_PQR_ASSOC, %ecx
+	rdmsr
+	and	$~MSR_IA32_PQR_ASSOC_MASK, %edx	/* clear index bits first */
+	or	$1, %edx			/* select mask 1 */
+	wrmsr
+
+	/* Enable prefetchers */
+	mov	$MSR_PREFETCH_CTL, %ecx
+	rdmsr
+	and	$~(PREFETCH_L1_DISABLE | PREFETCH_L2_DISABLE), %eax
+	wrmsr
+
+	post_code(0x28)
+
+	jmp	car_init_ret
+
+#elif IS_ENABLED(CONFIG_INTEL_CAR_NEM_ENHANCED)
+.global car_nem_enhanced
+car_nem_enhanced:
+	/* Disable cache eviction (setup stage) */
+	mov	$MSR_EVICT_CTL, %ecx
+	rdmsr
+	or	$0x1, %eax
+	wrmsr
+	post_code(0x26)
+
+	/* Create n-way set associativity of cache */
+	xorl	%edi, %edi
+find_llc_subleaf:
+	movl	%edi, %ecx
+	movl	$0x04, %eax
+	cpuid
+	inc	%edi
+	and	$0xe0, %al	/* EAX[7:5] = Cache Level */
+	cmp	$0x60, %al	/* Check to see if it is LLC */
+	jnz	find_llc_subleaf
+
+	/*
+	 * Set MSR 0xC91 IA32_L3_MASK_! = 0xE/0xFE/0xFFE/0xFFFE
+	 * for 4/8/16 way of LLC
+	*/
+	shr	$22, %ebx
+	inc	%ebx
+	/* Calculate n-way associativity of LLC */
+	mov	%bl, %cl
+
+	/*
+	 * Maximizing RO cacheability while locking in the CAR to a
+	 * single way since that particular way won't be victim candidate
+	 * for evictions.
+	 * This has been done after programing LLC_WAY_MASK_1 MSR
+	 * with desired LLC way as mentioned below.
+	 *
+	 * Hence create Code and Data Size as per request
+	 * Code Size (RO) : Up to 16M
+	 * Data Size (RW) : Up to 256K
+	 */
+	movl	$0x01, %eax
+	/*
+	 * LLC Ways -> LLC_WAY_MASK_1:
+	 *  4: 0x000E
+	 *  8: 0x00FE
+	 * 12: 0x0FFE
+	 * 16: 0xFFFE
+	 *
+	 * These MSRs contain one bit per each way of LLC
+	 * - If this bit is '0' - the way is protected from eviction
+	 * - If this bit is '1' - the way is not protected from eviction
+	 */
+	shl	%cl, %eax
+	subl	$0x02, %eax
+	movl	$MSR_IA32_L3_MASK_1, %ecx
+	xorl	%edx, %edx
+	wrmsr
+	/*
+	 * Set MSR 0xC92 IA32_L3_MASK_2 = 0x1
+	 *
+	 * For SKL SOC, data size remains 256K consistently.
+	 * Hence, creating 1-way associative cache for Data
+	*/
+	mov	$MSR_IA32_L3_MASK_2, %ecx
+	mov	$0x01, %eax
+	xorl	%edx, %edx
+	wrmsr
+	/*
+	 * Set MSR_IA32_PQR_ASSOC = 0x02
+	 *
+	 * Possible values:
+	 * 0: Default value, no way mask should be applied
+	 * 1: Apply way mask 1 to LLC
+	 * 2: Apply way mask 2 to LLC
+	 * 3: Shouldn't be use in NEM Mode
+	 */
+	movl	$MSR_IA32_PQR_ASSOC, %ecx
+	movl	$0x02, %eax
+	xorl	%edx, %edx
+	wrmsr
+
+	movl	$CONFIG_DCACHE_RAM_BASE, %edi
+	movl	$CONFIG_DCACHE_RAM_SIZE, %ecx
+	shr	$0x02, %ecx
+	xor	%eax, %eax
+	cld
+	rep	stosl
+	/*
+	 * Set MSR_IA32_PQR_ASSOC = 0x01
+	 * At this stage we apply LLC_WAY_MASK_1 to the cache.
+	 * i.e. way 0 is protected from eviction.
+	*/
+	movl	$MSR_IA32_PQR_ASSOC, %ecx
+	movl	$0x01, %eax
+	xorl	%edx, %edx
+	wrmsr
+
+	post_code(0x27)
+	/*
+	 * Enable No-Eviction Mode Run State by setting
+	 * NO_EVICT_MODE MSR 2E0h bit [1] = '1'.
+	 */
+
+	movl	$MSR_EVICT_CTL, %ecx
+	rdmsr
+	orl	$0x02, %eax
+	wrmsr
+
+	post_code(0x28)
+
+	jmp	car_init_ret
+#endif
+
+#if CONFIG_IS_ENABLED(X86_16BIT_INIT)
+_dt_ucode_base_size:
+	/* These next two fields are filled in by binman */
+.globl ucode_base
+ucode_base:	/* Declared in microcode.h */
+	.long	0			/* microcode base */
+.globl ucode_size
+ucode_size:	/* Declared in microcode.h */
+	.long	0			/* microcode size */
+	.long	CONFIG_SYS_MONITOR_BASE	/* code region base */
+	.long	CONFIG_SYS_MONITOR_LEN	/* code region size */
+#endif
diff --git a/arch/x86/cpu/intel_common/car2_uninit.S b/arch/x86/cpu/intel_common/car2_uninit.S
new file mode 100644
index 0000000..aba3a53
--- /dev/null
+++ b/arch/x86/cpu/intel_common/car2_uninit.S
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2017 Intel Corp.
+ * Copyright 2019 Google LLC
+ * Taken from coreboot file exit_car.S
+ */
+
+#include <config.h>
+#include <asm/msr-index.h>
+#include <asm/mtrr.h>
+
+.text
+.global car_uninit
+car_uninit:
+
+	/*
+	 * Retrieve return address from stack as it will get trashed below if
+	 * execution is utilizing the cache-as-ram stack.
+	 */
+	pop	%ebx
+
+	/* Disable MTRRs */
+	mov	$(MTRR_DEF_TYPE_MSR), %ecx
+	rdmsr
+	and	$(~(MTRR_DEF_TYPE_EN | MTRR_DEF_TYPE_FIX_EN)), %eax
+	wrmsr
+
+#ifdef CONFIG_INTEL_CAR_NEM
+.global car_nem_teardown
+car_nem_teardown:
+
+	/* invalidate cache contents */
+	invd
+
+	/* Knock down bit 1 then bit 0 of NEM control not combining steps */
+	mov	$(MSR_EVICT_CTL), %ecx
+	rdmsr
+	and	$(~(1 << 1)), %eax
+	wrmsr
+	and	$(~(1 << 0)), %eax
+	wrmsr
+
+#elif IS_ENABLED(CONFIG_INTEL_CAR_CQOS)
+.global car_cqos_teardown
+car_cqos_teardown:
+
+	/* Go back to all-evicting mode, set both masks to all-1s */
+	mov	$MSR_L2_QOS_MASK(0), %ecx
+	rdmsr
+	mov	$~0, %al
+	wrmsr
+
+	mov	$MSR_L2_QOS_MASK(1), %ecx
+	rdmsr
+	mov	$~0, %al
+	wrmsr
+
+	/* Reset CLOS selector to 0 */
+	mov	$MSR_IA32_PQR_ASSOC, %ecx
+	rdmsr
+	and	$~MSR_IA32_PQR_ASSOC_MASK, %edx
+	wrmsr
+
+#elif IS_ENABLED(CONFIG_INTEL_CAR_NEM_ENHANCED)
+.global car_nem_enhanced_teardown
+car_nem_enhanced_teardown:
+
+	/* invalidate cache contents */
+	invd
+
+	/* Knock down bit 1 then bit 0 of NEM control not combining steps */
+	mov	$(MSR_EVICT_CTL), %ecx
+	rdmsr
+	and	$(~(1 << 1)), %eax
+	wrmsr
+	and	$(~(1 << 0)), %eax
+	wrmsr
+
+	/* Reset CLOS selector to 0 */
+	mov	$IA32_PQR_ASSOC, %ecx
+	rdmsr
+	and	$~IA32_PQR_ASSOC_MASK, %edx
+	wrmsr
+#endif
+
+	/* Return to caller */
+	jmp	*%ebx
diff --git a/arch/x86/cpu/intel_common/fast_spi.c b/arch/x86/cpu/intel_common/fast_spi.c
new file mode 100644
index 0000000..a6e3d0a
--- /dev/null
+++ b/arch/x86/cpu/intel_common/fast_spi.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/cpu_common.h>
+#include <asm/fast_spi.h>
+#include <asm/pci.h>
+
+/*
+ * Returns bios_start and fills in size of the BIOS region.
+ */
+static ulong fast_spi_get_bios_region(struct fast_spi_regs *regs,
+				      uint *bios_size)
+{
+	ulong bios_start, bios_end;
+
+	/*
+	 * BIOS_BFPREG provides info about BIOS-Flash Primary Region Base and
+	 * Limit. Base and Limit fields are in units of 4K.
+	 */
+	u32 val = readl(&regs->bfp);
+
+	bios_start = (val & SPIBAR_BFPREG_PRB_MASK) << 12;
+	bios_end = (((val & SPIBAR_BFPREG_PRL_MASK) >>
+		     SPIBAR_BFPREG_PRL_SHIFT) + 1) << 12;
+	*bios_size = bios_end - bios_start;
+
+	return bios_start;
+}
+
+int fast_spi_get_bios_mmap(pci_dev_t pdev, ulong *map_basep, uint *map_sizep,
+			   uint *offsetp)
+{
+	struct fast_spi_regs *regs;
+	ulong bar, base, mmio_base;
+
+	/* Special case to find mapping without probing the device */
+	pci_x86_read_config(pdev, PCI_BASE_ADDRESS_0, &bar, PCI_SIZE_32);
+	mmio_base = bar & PCI_BASE_ADDRESS_MEM_MASK;
+	regs = (struct fast_spi_regs *)mmio_base;
+	base = fast_spi_get_bios_region(regs, map_sizep);
+	*map_basep = (u32)-*map_sizep - base;
+	*offsetp = base;
+
+	return 0;
+}
+
+int fast_spi_early_init(pci_dev_t pdev, ulong mmio_base)
+{
+	/* Program Temporary BAR for SPI */
+	pci_x86_write_config(pdev, PCI_BASE_ADDRESS_0,
+			     mmio_base | PCI_BASE_ADDRESS_SPACE_MEMORY,
+			     PCI_SIZE_32);
+
+	/* Enable Bus Master and MMIO Space */
+	pci_x86_clrset_config(pdev, PCI_COMMAND, 0, PCI_COMMAND_MASTER |
+			      PCI_COMMAND_MEMORY, PCI_SIZE_8);
+
+	/*
+	 * Disable the BIOS write protect so write commands are allowed.
+	 * Enable Prefetching and caching.
+	 */
+	pci_x86_clrset_config(pdev, SPIBAR_BIOS_CONTROL,
+			      SPIBAR_BIOS_CONTROL_EISS |
+			      SPIBAR_BIOS_CONTROL_CACHE_DISABLE,
+			      SPIBAR_BIOS_CONTROL_WPD |
+			      SPIBAR_BIOS_CONTROL_PREFETCH_ENABLE, PCI_SIZE_8);
+
+	return 0;
+}
diff --git a/arch/x86/cpu/intel_common/lpss.c b/arch/x86/cpu/intel_common/lpss.c
new file mode 100644
index 0000000..26a2d2d
--- /dev/null
+++ b/arch/x86/cpu/intel_common/lpss.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Special driver to handle of-platdata
+ *
+ * Copyright 2019 Google LLC
+ *
+ * Some code from coreboot lpss.c
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+#include <asm/io.h>
+#include <asm/lpss.h>
+
+enum {
+	LPSS_RESET_CTL_REG	= 0x204,
+
+	/*
+	 * Bit 1:0 controls LPSS controller reset.
+	 *
+	 * 00 ->LPSS Host Controller is in reset (Reset Asserted)
+	 * 01/10 ->Reserved
+	 * 11 ->LPSS Host Controller is NOT at reset (Reset Released)
+	 */
+	LPSS_CNT_RST_RELEASE	= 3,
+
+	/* Power management control and status register */
+	PME_CTRL_STATUS		= 0x84,
+
+	/* Bit 1:0 Powerstate, controls D0 and D3 state */
+	POWER_STATE_MASK	= 3,
+};
+
+/* Take controller out of reset */
+void lpss_reset_release(void *regs)
+{
+	writel(LPSS_CNT_RST_RELEASE, regs + LPSS_RESET_CTL_REG);
+}
+
+void lpss_set_power_state(struct udevice *dev, enum lpss_pwr_state state)
+{
+	dm_pci_clrset_config8(dev, PME_CTRL_STATUS, POWER_STATE_MASK, state);
+}
diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c
index 3adc155..ed9938f 100644
--- a/arch/x86/cpu/irq.c
+++ b/arch/x86/cpu/irq.c
@@ -350,14 +350,6 @@
 	return 0;
 }
 
-ulong write_pirq_routing_table(ulong addr)
-{
-	if (!gd->arch.pirq_routing_table)
-		return addr;
-
-	return copy_pirq_routing_table(addr, gd->arch.pirq_routing_table);
-}
-
 static const struct udevice_id irq_router_ids[] = {
 	{ .compatible = "intel,irq-router" },
 	{ }
@@ -370,8 +362,3 @@
 	.probe		= irq_router_probe,
 	.priv_auto_alloc_size = sizeof(struct irq_router),
 };
-
-UCLASS_DRIVER(irq) = {
-	.id		= UCLASS_IRQ,
-	.name		= "irq",
-};
diff --git a/arch/x86/cpu/ivybridge/sdram.c b/arch/x86/cpu/ivybridge/sdram.c
index 51ca4ad..cf34f94 100644
--- a/arch/x86/cpu/ivybridge/sdram.c
+++ b/arch/x86/cpu/ivybridge/sdram.c
@@ -116,7 +116,7 @@
 	ret = read_seed_from_cmos(pei_data);
 	if (ret)
 		return ret;
-	ret = mrccache_get_region(NULL, &entry);
+	ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry);
 	if (ret)
 		return ret;
 	mrc_cache = mrccache_find_current(&entry);
@@ -538,12 +538,14 @@
 
 	/* S3 resume: don't save scrambler seed or MRC data */
 	if (pei_data->boot_mode != PEI_BOOT_RESUME) {
+		struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
+
 		/*
 		 * This will be copied to SDRAM in reserve_arch(), then written
 		 * to SPI flash in mrccache_save()
 		 */
-		gd->arch.mrc_output = (char *)pei_data->mrc_output;
-		gd->arch.mrc_output_len = pei_data->mrc_output_len;
+		mrc->buf = (char *)pei_data->mrc_output;
+		mrc->len = pei_data->mrc_output_len;
 		ret = write_seeds_to_cmos(pei_data);
 		if (ret)
 			debug("Failed to write seeds to CMOS: %d\n", ret);
diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c
index fefbf8f..7b09f90 100644
--- a/arch/x86/cpu/mp_init.c
+++ b/arch/x86/cpu/mp_init.c
@@ -418,69 +418,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_QFW
-static int qemu_cpu_fixup(void)
-{
-	int ret;
-	int cpu_num;
-	int cpu_online;
-	struct udevice *dev, *pdev;
-	struct cpu_platdata *plat;
-	char *cpu;
-
-	/* first we need to find '/cpus' */
-	for (device_find_first_child(dm_root(), &pdev);
-	     pdev;
-	     device_find_next_child(&pdev)) {
-		if (!strcmp(pdev->name, "cpus"))
-			break;
-	}
-	if (!pdev) {
-		printf("unable to find cpus device\n");
-		return -ENODEV;
-	}
-
-	/* calculate cpus that are already bound */
-	cpu_num = 0;
-	for (uclass_find_first_device(UCLASS_CPU, &dev);
-	     dev;
-	     uclass_find_next_device(&dev)) {
-		cpu_num++;
-	}
-
-	/* get actual cpu number */
-	cpu_online = qemu_fwcfg_online_cpus();
-	if (cpu_online < 0) {
-		printf("unable to get online cpu number: %d\n", cpu_online);
-		return cpu_online;
-	}
-
-	/* bind addtional cpus */
-	dev = NULL;
-	for (; cpu_num < cpu_online; cpu_num++) {
-		/*
-		 * allocate device name here as device_bind_driver() does
-		 * not copy device name, 8 bytes are enough for
-		 * sizeof("cpu@") + 3 digits cpu number + '\0'
-		 */
-		cpu = malloc(8);
-		if (!cpu) {
-			printf("unable to allocate device name\n");
-			return -ENOMEM;
-		}
-		sprintf(cpu, "cpu@%d", cpu_num);
-		ret = device_bind_driver(pdev, "cpu_qemu", cpu, &dev);
-		if (ret) {
-			printf("binding cpu@%d failed: %d\n", cpu_num, ret);
-			return ret;
-		}
-		plat = dev_get_parent_platdata(dev);
-		plat->cpu_id = cpu_num;
-	}
-	return 0;
-}
-#endif
-
 int mp_init(struct mp_params *p)
 {
 	int num_aps;
@@ -494,11 +431,11 @@
 	if (ret)
 		return ret;
 
-#ifdef CONFIG_QFW
-	ret = qemu_cpu_fixup();
-	if (ret)
-		return ret;
-#endif
+	if (IS_ENABLED(CONFIG_QFW)) {
+		ret = qemu_cpu_fixup();
+		if (ret)
+			return ret;
+	}
 
 	ret = init_bsp(&cpu);
 	if (ret) {
diff --git a/arch/x86/cpu/qfw_cpu.c b/arch/x86/cpu/qfw_cpu.c
new file mode 100644
index 0000000..49e9dfc
--- /dev/null
+++ b/arch/x86/cpu/qfw_cpu.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Google, Inc
+ */
+
+#include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <qfw.h>
+#include <dm/lists.h>
+#include <dm/uclass-internal.h>
+#include <dm/root.h>
+
+int qemu_cpu_fixup(void)
+{
+	int ret;
+	int cpu_num;
+	int cpu_online;
+	struct udevice *dev, *pdev;
+	struct cpu_platdata *plat;
+	char *cpu;
+
+	/* first we need to find '/cpus' */
+	for (device_find_first_child(dm_root(), &pdev);
+	     pdev;
+	     device_find_next_child(&pdev)) {
+		if (!strcmp(pdev->name, "cpus"))
+			break;
+	}
+	if (!pdev) {
+		printf("unable to find cpus device\n");
+		return -ENODEV;
+	}
+
+	/* calculate cpus that are already bound */
+	cpu_num = 0;
+	for (uclass_find_first_device(UCLASS_CPU, &dev);
+	     dev;
+	     uclass_find_next_device(&dev)) {
+		cpu_num++;
+	}
+
+	/* get actual cpu number */
+	cpu_online = qemu_fwcfg_online_cpus();
+	if (cpu_online < 0) {
+		printf("unable to get online cpu number: %d\n", cpu_online);
+		return cpu_online;
+	}
+
+	/* bind addtional cpus */
+	dev = NULL;
+	for (; cpu_num < cpu_online; cpu_num++) {
+		/*
+		 * allocate device name here as device_bind_driver() does
+		 * not copy device name, 8 bytes are enough for
+		 * sizeof("cpu@") + 3 digits cpu number + '\0'
+		 */
+		cpu = malloc(8);
+		if (!cpu) {
+			printf("unable to allocate device name\n");
+			return -ENOMEM;
+		}
+		sprintf(cpu, "cpu@%d", cpu_num);
+		ret = device_bind_driver(pdev, "cpu_qemu", cpu, &dev);
+		if (ret) {
+			printf("binding cpu@%d failed: %d\n", cpu_num, ret);
+			return ret;
+		}
+		plat = dev_get_parent_platdata(dev);
+		plat->cpu_id = cpu_num;
+	}
+	return 0;
+}
diff --git a/arch/x86/cpu/quark/dram.c b/arch/x86/cpu/quark/dram.c
index 995e119..2bf90dc 100644
--- a/arch/x86/cpu/quark/dram.c
+++ b/arch/x86/cpu/quark/dram.c
@@ -24,7 +24,7 @@
 	struct mrc_region entry;
 	int ret;
 
-	ret = mrccache_get_region(NULL, &entry);
+	ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry);
 	if (ret)
 		return ret;
 
@@ -154,9 +154,11 @@
 #ifdef CONFIG_ENABLE_MRC_CACHE
 	cache = malloc(sizeof(struct mrc_timings));
 	if (cache) {
+		struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
+
 		memcpy(cache, &mrc_params.timings, sizeof(struct mrc_timings));
-		gd->arch.mrc_output = cache;
-		gd->arch.mrc_output_len = sizeof(struct mrc_timings);
+		mrc->buf = cache;
+		mrc->len = sizeof(struct mrc_timings);
 	}
 #endif
 
diff --git a/arch/x86/cpu/slimbootloader/Kconfig b/arch/x86/cpu/slimbootloader/Kconfig
index 3ea4c99..58a9ca0 100644
--- a/arch/x86/cpu/slimbootloader/Kconfig
+++ b/arch/x86/cpu/slimbootloader/Kconfig
@@ -17,3 +17,4 @@
 	imply USB_EHCI_HCD
 	imply USB_XHCI_HCD
 	imply E1000
+	imply X86_TSC_READ_BASE
diff --git a/arch/x86/cpu/u-boot-spl.lds b/arch/x86/cpu/u-boot-spl.lds
index c1e9bfb..e6c2289 100644
--- a/arch/x86/cpu/u-boot-spl.lds
+++ b/arch/x86/cpu/u-boot-spl.lds
@@ -17,7 +17,10 @@
 
 	. = IMAGE_TEXT_BASE;	/* Location of bootcode in flash */
 	__text_start = .;
-	.text  : { *(.text*); }
+	.text  : {
+		__image_copy_start = .;
+		*(.text*);
+	}
 
 	. = ALIGN(4);
 
diff --git a/arch/x86/dts/Makefile b/arch/x86/dts/Makefile
index d4bdf62..be209aa 100644
--- a/arch/x86/dts/Makefile
+++ b/arch/x86/dts/Makefile
@@ -2,6 +2,7 @@
 
 dtb-y += bayleybay.dtb \
 	cherryhill.dtb \
+	chromebook_coral.dtb \
 	chromebook_link.dtb \
 	chromebox_panther.dtb \
 	chromebook_samus.dtb \
diff --git a/arch/x86/dts/chromebook_coral.dts b/arch/x86/dts/chromebook_coral.dts
new file mode 100644
index 0000000..24fcbb5
--- /dev/null
+++ b/arch/x86/dts/chromebook_coral.dts
@@ -0,0 +1,831 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/dts-v1/;
+
+#include <dt-bindings/gpio/x86-gpio.h>
+
+/include/ "skeleton.dtsi"
+/include/ "keyboard.dtsi"
+/include/ "reset.dtsi"
+/include/ "rtc.dtsi"
+/include/ "tsc_timer.dtsi"
+
+#ifdef CONFIG_CHROMEOS
+#include "chromeos-x86.dtsi"
+#include "flashmap-x86-ro.dtsi"
+#include "flashmap-16mb-rw.dtsi"
+#endif
+
+#include <asm/intel_pinctrl_defs.h>
+#include <asm/arch-apollolake/cpu.h>
+#include <asm/arch-apollolake/gpio.h>
+#include <asm/arch-apollolake/iomap.h>
+#include <asm/arch-apollolake/pm.h>
+
+/ {
+	model = "Google Coral";
+	compatible = "google,coral", "intel,apollolake";
+
+	aliases {
+		cros-ec0 = &cros_ec;
+		fsp = &fsp_s;
+		spi0 = &spi;
+	};
+
+	config {
+	       silent_console = <0>;
+	};
+
+	chosen {
+		stdout-path = &serial;
+	};
+
+	cpus {
+		u-boot,dm-pre-reloc;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			u-boot,dm-pre-reloc;
+			device_type = "cpu";
+			compatible = "intel,apl-cpu";
+			reg = <0>;
+			intel,apic-id = <0>;
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "intel,apl-cpu";
+			reg = <1>;
+			intel,apic-id = <2>;
+		};
+
+		cpu@2 {
+			device_type = "cpu";
+			compatible = "intel,apl-cpu";
+			reg = <2>;
+			intel,apic-id = <4>;
+		};
+
+		cpu@3 {
+			device_type = "cpu";
+			compatible = "intel,apl-cpu";
+			reg = <3>;
+			intel,apic-id = <6>;
+		};
+
+	};
+
+	keyboard {
+		intel,duplicate-por;
+	};
+
+	pci {
+		compatible = "pci-x86";
+		#address-cells = <3>;
+		#size-cells = <2>;
+		u-boot,dm-pre-reloc;
+		ranges = <0x02000000 0x0 0xc0000000 0xc0000000 0 0x10000000
+			0x42000000 0x0 0xb0000000 0xb0000000 0 0x10000000
+			0x01000000 0x0 0x1000 0x1000 0 0xefff>;
+		u-boot,skip-auto-config-until-reloc;
+
+		host_bridge: host-bridge@0,0 {
+			u-boot,dm-pre-reloc;
+			reg = <0x00000000 0 0 0 0>;
+			compatible = "intel,apl-hostbridge";
+			pciex-region-size = <0x10000000>;
+			/*
+			 * Parameters used by the FSP-S binary blob. This is
+			 * really unfortunate since these parameters mostly
+			 * relate to drivers but we need them in one place. We
+			 * could put them in the driver nodes easily, but then
+			 * would have to scan each node to find them. So just
+			 * dump them here for now.
+			 */
+			fsp_s: fsp-s {
+			};
+		};
+
+		punit@0,1 {
+			u-boot,dm-pre-reloc;
+			reg = <0x00000800 0 0 0 0>;
+			compatible = "intel,apl-punit";
+		};
+
+		p2sb: p2sb@d,0 {
+			u-boot,dm-pre-reloc;
+			reg = <0x02006810 0 0 0 0>;
+			compatible = "intel,apl-p2sb";
+			early-regs = <IOMAP_P2SB_BAR 0x100000>;
+
+			n {
+				compatible = "intel,apl-pinctrl";
+				u-boot,dm-pre-reloc;
+				intel,p2sb-port-id = <PID_GPIO_N>;
+				gpio_n: gpio-n {
+					compatible = "intel,gpio";
+					u-boot,dm-pre-reloc;
+					gpio-controller;
+					#gpio-cells = <2>;
+				};
+			};
+
+			nw {
+				u-boot,dm-pre-reloc;
+				compatible = "intel,apl-pinctrl";
+				intel,p2sb-port-id = <PID_GPIO_NW>;
+				#gpio-cells = <2>;
+				gpio_nw: gpio-nw {
+					compatible = "intel,gpio";
+					u-boot,dm-pre-reloc;
+					gpio-controller;
+					#gpio-cells = <2>;
+				};
+			};
+
+			w {
+				u-boot,dm-pre-reloc;
+				compatible = "intel,apl-pinctrl";
+				intel,p2sb-port-id = <PID_GPIO_W>;
+				#gpio-cells = <2>;
+				gpio_w: gpio-w {
+					compatible = "intel,gpio";
+					u-boot,dm-pre-reloc;
+					gpio-controller;
+					#gpio-cells = <2>;
+				};
+			};
+
+			sw {
+				u-boot,dm-pre-reloc;
+				compatible = "intel,apl-pinctrl";
+				intel,p2sb-port-id = <PID_GPIO_SW>;
+				#gpio-cells = <2>;
+				gpio_sw: gpio-sw {
+					compatible = "intel,gpio";
+					u-boot,dm-pre-reloc;
+					gpio-controller;
+					#gpio-cells = <2>;
+				};
+			};
+
+			itss {
+				u-boot,dm-pre-reloc;
+				compatible = "intel,apl-itss";
+				intel,p2sb-port-id = <PID_ITSS>;
+				intel,pmc-routes = <
+					PMC_GPE_SW_31_0 GPIO_GPE_SW_31_0
+					PMC_GPE_SW_63_32 GPIO_GPE_SW_63_32
+					PMC_GPE_NW_31_0 GPIO_GPE_NW_31_0
+					PMC_GPE_NW_63_32 GPIO_GPE_NW_63_32
+					PMC_GPE_NW_95_64 GPIO_GPE_NW_95_64
+					PMC_GPE_N_31_0 GPIO_GPE_N_31_0
+					PMC_GPE_N_63_32 GPIO_GPE_N_63_32
+					PMC_GPE_W_31_0 GPIO_GPE_W_31_0>;
+			};
+		};
+
+		pmc@d,1 {
+			u-boot,dm-pre-reloc;
+			reg = <0x6900 0 0 0 0>;
+
+			/*
+			 * Values for BAR0, BAR2 and ACPI_BASE for when PCI
+			 * auto-configure is not available
+			 */
+			early-regs = <0xfe042000 0x2000
+				0xfe044000 0x2000
+				IOMAP_ACPI_BASE IOMAP_ACPI_SIZE>;
+			compatible = "intel,apl-pmc";
+			gpe0-dwx-mask = <0xf>;
+			gpe0-dwx-shift-base = <4>;
+
+			/*
+			 * GPE configuration
+			 * Note that GPE events called out in ASL code rely on
+			 * this route, i.e., if this route changes then the
+			 * affected GPE * offset bits also need to be changed.
+			 * This sets the PMC register GPE_CFG fields.
+			 */
+			gpe0-dw = <PMC_GPE_N_31_0
+				PMC_GPE_N_63_32
+				PMC_GPE_SW_31_0>;
+			gpe0-sts = <0x20>;
+			gpe0-en = <0x30>;
+		};
+
+		spi: fast-spi@d,2 {
+			u-boot,dm-pre-reloc;
+			reg = <0x02006a10 0 0 0 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "intel,fast-spi";
+			early-regs = <IOMAP_SPI_BASE 0x1000>;
+			intel,hardware-seq = <1>;
+
+			fwstore_spi: spi-flash@0 {
+				#size-cells = <1>;
+				#address-cells = <1>;
+				u-boot,dm-pre-reloc;
+				reg = <0>;
+				compatible = "winbond,w25q128fw",
+					 "jedec,spi-nor";
+				rw-mrc-cache {
+					label = "rw-mrc-cache";
+					reg = <0x008e0000 0x00010000>;
+					u-boot,dm-pre-reloc;
+				};
+				rw-var-mrc-cache {
+					label = "rw-mrc-cache";
+					reg = <0x008f0000 0x0001000>;
+					u-boot,dm-pre-reloc;
+				};
+			};
+		};
+
+		serial: serial@18,2 {
+			reg = <0x0200c210 0 0 0 0>;
+			u-boot,dm-pre-reloc;
+			compatible = "intel,apl-ns16550";
+			early-regs = <0xde000000 0x20>;
+			reg-shift = <2>;
+			clock-frequency = <1843200>;
+			current-speed = <115200>;
+		};
+
+		pch: pch@1f,0 {
+			reg = <0x0000f800 0 0 0 0>;
+			compatible = "intel,apl-pch";
+			u-boot,dm-pre-reloc;
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			lpc {
+				compatible = "intel,apl-lpc";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				u-boot,dm-pre-reloc;
+				cros_ec: cros-ec {
+					u-boot,dm-pre-reloc;
+					compatible = "google,cros-ec-lpc";
+					reg = <0x204 1 0x200 1 0x880 0x80>;
+
+					/*
+					 * Describes the flash memory within
+					 * the EC
+					 */
+					#address-cells = <1>;
+					#size-cells = <1>;
+					flash@8000000 {
+						reg = <0x08000000 0x20000>;
+						erase-value = <0xff>;
+					};
+				};
+			};
+		};
+	};
+
+};
+
+&host_bridge {
+	/*
+	 * PL1 override 12000 mW: the energy calculation is wrong with the
+	 * current VR solution. Experiments show that SoC TDP max (6W) can be
+	 * reached when RAPL PL1 is set to 12W. Set RAPL PL2 to 15W.
+	 */
+	tdp-pl-override-mw = <12000 15000>;
+
+	early-pads = <
+		/* These two are for the debug UART */
+		GPIO_46 /* UART2 RX */
+			(PAD_CFG0_MODE_NF1 | PAD_CFG0_LOGICAL_RESET_DEEP)
+			(PAD_CFG1_PULL_NATIVE | PAD_CFG1_IOSSTATE_TX_LAST_RXE)
+
+		GPIO_47 /* UART2 TX */
+			(PAD_CFG0_MODE_NF1 | PAD_CFG0_LOGICAL_RESET_DEEP)
+			(PAD_CFG1_PULL_NATIVE | PAD_CFG1_IOSSTATE_TX_LAST_RXE)
+
+		GPIO_75 /* I2S1_BCLK -- PCH_WP */
+			(PAD_CFG0_MODE_GPIO | PAD_CFG0_LOGICAL_RESET_DEEP)
+			(PAD_CFG1_PULL_UP_20K | PAD_CFG1_IOSSTATE_TXD_RXE)
+
+		/* I2C2 - TPM  */
+		GPIO_128 /* LPSS_I2C2_SDA */
+			(PAD_CFG0_MODE_NF1 | PAD_CFG0_LOGICAL_RESET_DEEP)
+			(PAD_CFG1_PULL_UP_2K | PAD_CFG1_IOSSTATE_TX_LAST_RXE)
+		GPIO_129 /* LPSS_I2C2_SCL */
+			(PAD_CFG0_MODE_NF1 | PAD_CFG0_LOGICAL_RESET_DEEP)
+			(PAD_CFG1_PULL_UP_2K | PAD_CFG1_IOSSTATE_TX_LAST_RXE)
+		GPIO_28 /* TPM IRQ */
+			(PAD_CFG0_MODE_GPIO | PAD_CFG0_LOGICAL_RESET_DEEP |
+				PAD_CFG0_TX_DISABLE | PAD_CFG0_ROUTE_IOAPIC |
+				PAD_CFG0_TRIG_LEVEL | PAD_CFG0_RX_POL_INVERT)
+			(PAD_CFG1_PULL_NONE | PAD_CFG1_IOSSTATE_TXD_RXE)
+
+		/*
+		 * WLAN_PE_RST - default to deasserted just in case FSP
+		 * misbehaves
+		 */
+		GPIO_122  /* SIO_SPI_2_RXD */
+			(PAD_CFG0_MODE_GPIO | PAD_CFG0_LOGICAL_RESET_DEEP |
+				PAD_CFG0_RX_DISABLE | 0)
+			(PAD_CFG1_PULL_NONE | PAD_CFG1_IOSSTATE_TX_LAST_RXE)
+
+		/* LPC */
+		PAD_CFG_NF(LPC_ILB_SERIRQ, UP_20K, DEEP, NF1) /* LPC_SERIRQ */
+		PAD_CFG_NF(LPC_CLKOUT0, NONE, DEEP, NF1) /* LPC_CLKOUT0 */
+		PAD_CFG_NF(LPC_CLKOUT1, UP_20K, DEEP, NF1)
+		PAD_CFG_NF(LPC_AD0, UP_20K, DEEP, NF1)	 /* LPC_AD0 */
+		PAD_CFG_NF(LPC_AD1, UP_20K, DEEP, NF1)	 /* LPC_AD1 */
+		PAD_CFG_NF(LPC_AD2, UP_20K, DEEP, NF1)	 /* LPC_AD2 */
+		PAD_CFG_NF(LPC_AD3, UP_20K, DEEP, NF1)	 /* LPC_AD3 */
+		PAD_CFG_NF(LPC_CLKRUNB, UP_20K, DEEP, NF1) /* LPC_CLKRUN_N */
+		PAD_CFG_NF(LPC_FRAMEB, NATIVE, DEEP, NF1) /* LPC_FRAME_N */
+		>;
+
+	lpddr4-swizzle = /bits/ 8 <
+		/* LP4_PHYS_CH0A */
+
+		/* DQA[0:7] pins of LPDDR4 module */
+		6 7 5 4 3 1 0 2
+		/* DQA[8:15] pins of LPDDR4 module */
+		12 10 11 13 14 8 9 15
+		/* DQB[0:7] pins of LPDDR4 module with offset of 16 */
+		16 22 23 20 18 17 19 21
+		/* DQB[7:15] pins of LPDDR4 module with offset of 16 */
+		30 28 29 25 24 26 27 31
+
+		/* LP4_PHYS_CH0B */
+		/* DQA[0:7] pins of LPDDR4 module */
+		7 3 5 2 6 0 1 4
+		/* DQA[8:15] pins of LPDDR4 module */
+		 9 14 12 13 10 11 8 15
+		/* DQB[0:7] pins of LPDDR4 module with offset of 16 */
+		20 22 23 16 19 17 18 21
+		/* DQB[7:15] pins of LPDDR4 module with offset of 16 */
+		28 24 26 27 29 30 31 25
+
+		/* LP4_PHYS_CH1A */
+
+		/* DQA[0:7] pins of LPDDR4 module */
+		2 1 6 7 5 4 3 0
+		/* DQA[8:15] pins of LPDDR4 module */
+		11 10 8 9 12 15 13 14
+		/* DQB[0:7] pins of LPDDR4 module with offset of 16 */
+		17 23 19 16 21 22 20 18
+		/* DQB[7:15] pins of LPDDR4 module with offset of 16 */
+		31 29 26 25 28 27 24 30
+
+		/* LP4_PHYS_CH1B */
+
+		/* DQA[0:7] pins of LPDDR4 module */
+		4 3 7 5 6 1 0 2
+		/* DQA[8:15] pins of LPDDR4 module */
+		15 9 8 11 14 13 12 10
+		/* DQB[0:7] pins of LPDDR4 module with offset of 16 */
+		20 23 22 21 18 19 16 17
+		/* DQB[7:15] pins of LPDDR4 module with offset of 16 */
+		25 28 30 31 26 27 24 29>;
+};
+
+&fsp_s {
+	u-boot,dm-pre-proper;
+
+	/* Disable unused clkreq of PCIe root ports */
+	pcie-rp-clkreq-pin = /bits/ 8 <0 /* wifi/bt */
+		CLKREQ_DISABLED
+		CLKREQ_DISABLED
+		CLKREQ_DISABLED
+		CLKREQ_DISABLED
+		CLKREQ_DISABLED>;
+
+	/*
+	 * GPIO for PERST_0
+	 * If the Board has PERST_0 signal, assign the GPIO
+	 * If the Board does not have PERST_0, assign GPIO_PRT0_UDEF
+	 *
+	 * This are not used yet, so comment them out for now.
+	 *
+	 * prt0-gpio = <GPIO_122>;
+	 *
+	 * GPIO for SD card detect
+	 * sdcard-cd-gpio = <GPIO_177>;
+	 */
+
+	/*
+	 * Order is emmc-tx-data-cntl1, emmc-tx-data-cntl2,
+	 * emmc-rx-cmd-data-cntl1, emmc-rx-cmd-data-cntl2
+	 *
+	 * EMMC TX DATA Delay 1
+	 * Refer to EDS-Vol2-22.3
+	 * [14:8] steps of delay for HS400, each 125ps
+	 * [6:0] steps of delay for SDR104/HS200, each 125ps
+
+	/*
+	 * EMMC TX DATA Delay 2
+	 * Refer to EDS-Vol2-22.3.
+	 * [30:24] steps of delay for SDR50, each 125ps
+	 * [22:16] steps of delay for DDR50, each 125ps
+	 * [14:8] steps of delay for SDR25/HS50, each 125ps
+	 * [6:0] steps of delay for SDR12, each 125ps
+	 */
+
+	/*
+	 * EMMC RX CMD/DATA Delay 1
+	 * Refer to EDS-Vol2-22.3.
+	 * [30:24] steps of delay for SDR50, each 125ps
+	 * [22:16] steps of delay for DDR50, each 125ps
+	 * [14:8] steps of delay for SDR25/HS50, each 125ps
+	 * [6:0] steps of delay for SDR12, each 125ps
+	 */
+
+	/*
+	 * EMMC RX CMD/DATA Delay 2
+	 * Refer to EDS-Vol2-22.3.
+	 * [17:16] stands for Rx Clock before Output Buffer
+	 * [14:8] steps of delay for Auto Tuning Mode, each 125ps
+	 * [6:0] steps of delay for HS200, each 125ps
+	 */
+	emmc = <0x0c16 0x28162828 0x00181717 0x10008>;
+
+	/* Enable DPTF */
+	dptf-enable;
+
+	/* Enable Audio Clock and Power gating */
+	hdaudio-clk-gate-enable;
+	hdaudio-pwr-gate-enable;
+	hdaudio-bios-config-lockdown;
+
+	/* Enable lpss s0ix */
+	lpss-s0ix-enable;
+
+	/*
+	 * TODO(sjg@chromium.org): Move this to the I2C nodes
+	 * Intel Common SoC Config
+	 *+-------------------+---------------------------+
+	 *| Field             |  Value                    |
+	 *+-------------------+---------------------------+
+	 *| I2C0              | Audio                     |
+	 *| I2C2              | TPM                       |
+	 *| I2C3              | Touchscreen               |
+	 *| I2C4              | Trackpad                  |
+	 *| I2C5              | Digitizer                 |
+	 *+-------------------+---------------------------+
+	 *
+	common_soc_config" = "{
+		.i2c[0] = {
+			.speed = I2C_SPEED_FAST,
+			.rise-time-ns = 104,
+			.fall-time-ns = 52,
+		},
+		.i2c[2] = {
+			.early_init = 1,
+			.speed = I2C_SPEED_FAST,
+			.rise-time-ns = 57,
+			.fall-time-ns = 28,
+		},
+		.i2c[3] = {
+			.speed = I2C_SPEED_FAST,
+			.rise-time-ns = 76,
+			.fall-time-ns = 164,
+		},
+		.i2c[4] = {
+			.speed = I2C_SPEED_FAST,
+			.rise-time-ns = 114,
+			.fall-time-ns = 164,
+			.data_hold_time_ns = 350,
+		},
+		.i2c[5] = {
+			.speed = I2C_SPEED_FAST,
+			.rise-time-ns = 152,
+			.fall-time-ns = 30,
+		},
+	}"
+	*/
+
+	/* Minimum SLP S3 assertion width 28ms */
+	slp-s3-assertion-width-usecs = <28000>;
+
+	pads = <
+		/* PCIE_WAKE[0:3]_N */
+		PAD_CFG_GPI_SCI_LOW(GPIO_205, UP_20K, DEEP, EDGE_SINGLE) /* WLAN */
+		PAD_CFG_GPI(GPIO_206, UP_20K, DEEP)	 /* Unused */
+		PAD_CFG_GPI(GPIO_207, UP_20K, DEEP)	 /* Unused */
+		PAD_CFG_GPI(GPIO_208, UP_20K, DEEP)	 /* Unused */
+
+		/* EMMC interface */
+		PAD_CFG_NF(GPIO_156, DN_20K, DEEP, NF1) /* EMMC_CLK */
+		PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_157, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_D0 */
+		PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_158, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_D1 */
+		PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_159, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_D2 */
+		PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_160, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_D3 */
+		PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_161, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_D4 */
+		PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_162, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_D5 */
+		PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_163, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_D6 */
+		PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_164, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_D7 */
+		PAD_CFG_NF_IOSSTATE_IOSTERM(GPIO_165, UP_20K, DEEP, NF1, HIZCRX1, DISPUPD) /* EMMC_CMD */
+		PAD_CFG_NF(GPIO_182, DN_20K, DEEP, NF1) /* EMMC_RCLK */
+
+		/* SDIO -- unused */
+		PAD_CFG_GPI(GPIO_166, UP_20K, DEEP)	 /* SDIO_CLK */
+		PAD_CFG_GPI(GPIO_167, UP_20K, DEEP)	 /* SDIO_D0 */
+		/* Configure SDIO to enable power gating */
+		PAD_CFG_NF(GPIO_168, UP_20K, DEEP, NF1)	/* SDIO_D1 */
+		PAD_CFG_GPI(GPIO_169, UP_20K, DEEP)	 /* SDIO_D2 */
+		PAD_CFG_GPI(GPIO_170, UP_20K, DEEP)	 /* SDIO_D3 */
+		PAD_CFG_GPI(GPIO_171, UP_20K, DEEP)	 /* SDIO_CMD */
+
+		/* SDCARD */
+		/* Pull down clock by 20K */
+		PAD_CFG_NF(GPIO_172, DN_20K, DEEP, NF1) /* SDCARD_CLK */
+		PAD_CFG_NF(GPIO_173, UP_20K, DEEP, NF1) /* SDCARD_D0 */
+		PAD_CFG_NF(GPIO_174, UP_20K, DEEP, NF1) /* SDCARD_D1 */
+		PAD_CFG_NF(GPIO_175, UP_20K, DEEP, NF1) /* SDCARD_D2 */
+		PAD_CFG_NF(GPIO_176, UP_20K, DEEP, NF1) /* SDCARD_D3 */
+		/* Card detect is active LOW with external pull up */
+		PAD_CFG_NF(GPIO_177, NONE, DEEP, NF1) /* SDCARD_CD_N */
+		PAD_CFG_NF(GPIO_178, UP_20K, DEEP, NF1) /* SDCARD_CMD */
+		/* CLK feedback, internal signal, needs 20K pull down */
+		PAD_CFG_NF(GPIO_179, DN_20K, DEEP, NF1) /* SDCARD_CLK_FB */
+		/* No h/w write proect for uSD cards, pull down by 20K */
+		PAD_CFG_NF(GPIO_186, DN_20K, DEEP, NF1) /* SDCARD_LVL_WP */
+		/* EN_SD_SOCKET_PWR_L for SD slot power control. Default on */
+		PAD_CFG_GPO(GPIO_183, 0, DEEP)		 /* SDIO_PWR_DOWN_N */
+
+		/* SMBus -- unused */
+		PAD_CFG_GPI(SMB_ALERTB, UP_20K, DEEP)	 /* SMB_ALERT _N */
+		PAD_CFG_GPI(SMB_CLK, UP_20K, DEEP)	 /* SMB_CLK */
+		PAD_CFG_GPI(SMB_DATA, UP_20K, DEEP)	 /* SMB_DATA */
+
+		/* LPC */
+		PAD_CFG_NF(LPC_ILB_SERIRQ, UP_20K, DEEP, NF1) /* LPC_SERIRQ */
+		PAD_CFG_NF(LPC_CLKOUT0, NONE, DEEP, NF1) /* LPC_CLKOUT0 */
+		PAD_CFG_NF(LPC_CLKOUT1, UP_20K, DEEP, NF1)
+		PAD_CFG_NF(LPC_AD0, UP_20K, DEEP, NF1)	 /* LPC_AD0 */
+		PAD_CFG_NF(LPC_AD1, UP_20K, DEEP, NF1)	 /* LPC_AD1 */
+		PAD_CFG_NF(LPC_AD2, UP_20K, DEEP, NF1)	 /* LPC_AD2 */
+		PAD_CFG_NF(LPC_AD3, UP_20K, DEEP, NF1)	 /* LPC_AD3 */
+		PAD_CFG_NF(LPC_CLKRUNB, UP_20K, DEEP, NF1) /* LPC_CLKRUN_N */
+		PAD_CFG_NF(LPC_FRAMEB, NATIVE, DEEP, NF1) /* LPC_FRAME_N */
+
+		/* I2C0 - Audio */
+		PAD_CFG_NF(GPIO_124, UP_2K, DEEP, NF1) /* LPSS_I2C0_SDA */
+		PAD_CFG_NF(GPIO_125, UP_2K, DEEP, NF1) /* LPSS_I2C0_SCL */
+
+		/* I2C1 - NFC with external pulls */
+		PAD_CFG_NF(GPIO_126, NONE, DEEP, NF1) /* LPSS_I2C1_SDA */
+		PAD_CFG_NF(GPIO_127, NONE, DEEP, NF1) /* LPSS_I2C1_SCL */
+
+		/* I2C2 - TPM  */
+		PAD_CFG_NF(GPIO_128, UP_2K, DEEP, NF1) /* LPSS_I2C2_SDA */
+		PAD_CFG_NF(GPIO_129, UP_2K, DEEP, NF1) /* LPSS_I2C2_SCL */
+
+		/* I2C3 - touch */
+		PAD_CFG_NF(GPIO_130, UP_2K, DEEP, NF1) /* LPSS_I2C3_SDA */
+		PAD_CFG_NF(GPIO_131, UP_2K, DEEP, NF1) /* LPSS_I2C3_SCL */
+
+		/* I2C4 - trackpad */
+		/* LPSS_I2C4_SDA */
+		PAD_CFG_NF_IOSSTATE(GPIO_132, UP_2K, DEEP, NF1, HIZCRX1)
+		/* LPSS_I2C4_SCL */
+		PAD_CFG_NF_IOSSTATE(GPIO_133, UP_2K, DEEP, NF1, HIZCRX1)
+
+		/* I2C5 -- pen with external pulls  */
+		PAD_CFG_NF(GPIO_134, NONE, DEEP, NF1) /* LPSS_I2C5_SDA */
+		PAD_CFG_NF(GPIO_135, NONE, DEEP, NF1) /* LPSS_I2C5_SCL */
+
+		/* I2C6-7 -- unused */
+		PAD_CFG_GPI(GPIO_136, UP_20K, DEEP)	 /* LPSS_I2C6_SDA */
+		PAD_CFG_GPI(GPIO_137, UP_20K, DEEP)	 /* LPSS_I2C6_SCL */
+		PAD_CFG_GPI(GPIO_138, UP_20K, DEEP)	 /* LPSS_I2C7_SDA */
+		PAD_CFG_GPI(GPIO_139, UP_20K, DEEP)	 /* LPSS_I2C7_SCL */
+
+		/* Audio Amp - I2S6 */
+		PAD_CFG_NF(GPIO_146, NATIVE, DEEP, NF2) /* ISH_GPIO_0 - I2S6_BCLK */
+		PAD_CFG_NF(GPIO_147, NATIVE, DEEP, NF2) /* ISH_GPIO_1 - I2S6_WS_SYNC */
+		PAD_CFG_GPI(GPIO_148, UP_20K, DEEP)	 /* ISH_GPIO_2 - unused */
+		PAD_CFG_NF(GPIO_149, NATIVE, DEEP, NF2) /* ISH_GPIO_3 - I2S6_SDO */
+
+		/* NFC Reset */
+		PAD_CFG_GPO(GPIO_150, 1, DEEP)		 /* ISH_GPIO_4 */
+
+		PAD_CFG_GPI(GPIO_151, UP_20K, DEEP)	 /* ISH_GPIO_5 - unused */
+
+		/* Touch enable */
+		PAD_CFG_GPO(GPIO_152, 1, DEEP)		 /* ISH_GPIO_6 */
+
+		PAD_CFG_GPI(GPIO_153, UP_20K, DEEP)	 /* ISH_GPIO_7 - unused */
+		PAD_CFG_GPI(GPIO_154, UP_20K, DEEP)	 /* ISH_GPIO_8 - unused */
+		PAD_CFG_GPI(GPIO_155, UP_20K, DEEP)	 /* ISH_GPIO_9 - unused */
+
+		/* PCIE_CLKREQ[0:3]_N */
+		PAD_CFG_NF(GPIO_209, NONE, DEEP, NF1)	 /* WLAN with external pull */
+		PAD_CFG_GPI(GPIO_210, UP_20K, DEEP)	 /* unused */
+		PAD_CFG_GPI(GPIO_211, UP_20K, DEEP)	 /* unused */
+		PAD_CFG_GPI(GPIO_212, UP_20K, DEEP)	 /* unused */
+
+		/* OSC_CLK_OUT_[0:4] -- unused */
+		PAD_CFG_GPI(OSC_CLK_OUT_0, UP_20K, DEEP)
+		PAD_CFG_GPI(OSC_CLK_OUT_1, UP_20K, DEEP)
+		PAD_CFG_GPI(OSC_CLK_OUT_2, UP_20K, DEEP)
+		PAD_CFG_GPI(OSC_CLK_OUT_3, UP_20K, DEEP)
+		PAD_CFG_GPI(OSC_CLK_OUT_4, UP_20K, DEEP)
+
+		/* PMU Signals */
+		PAD_CFG_GPI(PMU_AC_PRESENT, UP_20K, DEEP) /* PMU_AC_PRESENT - unused */
+		PAD_CFG_NF(PMU_BATLOW_B, UP_20K, DEEP, NF1) /* PMU_BATLOW_N */
+		PAD_CFG_NF(PMU_PLTRST_B, NONE, DEEP, NF1) /* PMU_PLTRST_N */
+		PAD_CFG_NF(PMU_PWRBTN_B, UP_20K, DEEP, NF1) /* PMU_PWRBTN_N */
+		PAD_CFG_NF(PMU_RESETBUTTON_B, NONE, DEEP, NF1) /* PMU_RSTBTN_N */
+		PAD_CFG_NF_IOSSTATE(PMU_SLP_S0_B, NONE, DEEP, NF1, IGNORE) /* PMU_SLP_S0_N */
+		PAD_CFG_NF(PMU_SLP_S3_B, NONE, DEEP, NF1) /* PMU_SLP_S3_N */
+		PAD_CFG_NF(PMU_SLP_S4_B, NONE, DEEP, NF1) /* PMU_SLP_S4_N */
+		PAD_CFG_NF(PMU_SUSCLK, NONE, DEEP, NF1) /* PMU_SUSCLK */
+		PAD_CFG_GPO(PMU_WAKE_B, 1, DEEP)	 /* EN_PP3300_EMMC */
+		PAD_CFG_NF(SUS_STAT_B, NONE, DEEP, NF1) /* SUS_STAT_N */
+		PAD_CFG_NF(SUSPWRDNACK, NONE, DEEP, NF1) /* SUSPWRDNACK */
+
+		/* DDI[0:1] SDA and SCL -- unused */
+		PAD_CFG_GPI(GPIO_187, UP_20K, DEEP)	 /* HV_DDI0_DDC_SDA */
+		PAD_CFG_GPI(GPIO_188, UP_20K, DEEP)	 /* HV_DDI0_DDC_SCL */
+		PAD_CFG_GPI(GPIO_189, UP_20K, DEEP)	 /* HV_DDI1_DDC_SDA */
+		PAD_CFG_GPI(GPIO_190, UP_20K, DEEP)	 /* HV_DDI1_DDC_SCL */
+
+		/* MIPI I2C -- unused */
+		PAD_CFG_GPI(GPIO_191, UP_20K, DEEP)	 /* MIPI_I2C_SDA */
+		PAD_CFG_GPI(GPIO_192, UP_20K, DEEP)	 /* MIPI_I2C_SCL */
+
+		/* Panel 0 control */
+		PAD_CFG_NF(GPIO_193, NATIVE, DEEP, NF1) /* PNL0_VDDEN */
+		PAD_CFG_NF(GPIO_194, NATIVE, DEEP, NF1) /* PNL0_BKLTEN */
+		PAD_CFG_NF(GPIO_195, NATIVE, DEEP, NF1) /* PNL0_BKLTCTL */
+
+		/* Panel 1 control -- unused */
+		PAD_CFG_NF(GPIO_196, NATIVE, DEEP, NF1) /* PNL1_VDDEN */
+		PAD_CFG_NF(GPIO_197, NATIVE, DEEP, NF1) /* PNL1_BKLTEN */
+		PAD_CFG_NF(GPIO_198, NATIVE, DEEP, NF1) /* PNL1_BKLTCTL */
+
+		/* Hot plug detect */
+		PAD_CFG_NF(GPIO_199, UP_20K, DEEP, NF2) /* HV_DDI1_HPD */
+		PAD_CFG_NF(GPIO_200, UP_20K, DEEP, NF2) /* HV_DDI0_HPD */
+
+		/* MDSI signals -- unused */
+		PAD_CFG_GPI(GPIO_201, UP_20K, DEEP)	 /* MDSI_A_TE */
+		PAD_CFG_GPI(GPIO_202, UP_20K, DEEP)	 /* MDSI_A_TE */
+
+		/* USB overcurrent pins */
+		PAD_CFG_NF(GPIO_203, UP_20K, DEEP, NF1) /* USB_OC0_N */
+		PAD_CFG_NF(GPIO_204, UP_20K, DEEP, NF1) /* USB_OC1_N */
+
+		/* PMC SPI -- almost entirely unused */
+		PAD_CFG_GPI(PMC_SPI_FS0, UP_20K, DEEP)
+		PAD_CFG_NF(PMC_SPI_FS1, UP_20K, DEEP, NF2) /* HV_DDI2_HPD -- EDP HPD */
+		PAD_CFG_GPI(PMC_SPI_FS2, UP_20K, DEEP)
+		PAD_CFG_GPI(PMC_SPI_RXD, UP_20K, DEEP)
+		PAD_CFG_GPI(PMC_SPI_TXD, UP_20K, DEEP)
+		PAD_CFG_GPI(PMC_SPI_CLK, UP_20K, DEEP)
+
+		/* PMIC Signals Unused signals related to an old PMIC interface */
+		PAD_CFG_NF_IOSSTATE(PMIC_RESET_B, NATIVE, DEEP, NF1, IGNORE) /* PMIC_RESET_B */
+		PAD_CFG_GPI(GPIO_213, NONE, DEEP)	 /* unused external pull */
+		PAD_CFG_GPI(GPIO_214, UP_20K, DEEP)	 /* unused */
+		PAD_CFG_GPI(GPIO_215, UP_20K, DEEP)	 /* unused */
+		PAD_CFG_NF(PMIC_THERMTRIP_B, UP_20K, DEEP, NF1) /* THERMTRIP_N */
+		PAD_CFG_GPI(PMIC_STDBY, UP_20K, DEEP)	 /* unused */
+		PAD_CFG_NF(PROCHOT_B, UP_20K, DEEP, NF1) /* PROCHOT_N */
+		PAD_CFG_NF(PMIC_I2C_SCL, UP_1K, DEEP, NF1) /* PMIC_I2C_SCL */
+		PAD_CFG_NF(PMIC_I2C_SDA, UP_1K, DEEP, NF1) /* PMIC_I2C_SDA */
+
+		/* I2S1 -- largely unused */
+		PAD_CFG_GPI(GPIO_74, UP_20K, DEEP)	/* I2S1_MCLK */
+		PAD_CFG_GPI(GPIO_75, UP_20K, DEEP)	/* I2S1_BCLK -- PCH_WP */
+		PAD_CFG_GPO(GPIO_76, 0, DEEP)		/* I2S1_WS_SYNC -- SPK_PA_EN */
+		PAD_CFG_GPI(GPIO_77, UP_20K, DEEP)	/* I2S1_SDI */
+		PAD_CFG_GPO(GPIO_78, 1, DEEP)		/* I2S1_SDO -- EN_PP3300_DX_LTE_SOC */
+
+		/* DMIC or I2S4 */
+		/* AVS_DMIC_CLK_A1 */
+		PAD_CFG_NF_IOSSTATE(GPIO_79, NATIVE, DEEP, NF1, IGNORE)
+		PAD_CFG_NF(GPIO_80, NATIVE, DEEP, NF1) /* AVS_DMIC_CLK_B1 */
+		PAD_CFG_NF(GPIO_81, NATIVE, DEEP, NF1)	/* AVS_DMIC_DATA_1 */
+		PAD_CFG_GPI(GPIO_82, DN_20K, DEEP)	 /* unused -- strap */
+		PAD_CFG_NF(GPIO_83, NATIVE, DEEP, NF1) /* AVS_DMIC_DATA_2 */
+
+		/* I2S2 -- Headset amp */
+		PAD_CFG_NF(GPIO_84, NATIVE, DEEP, NF1)	 /* AVS_I2S2_MCLK */
+		PAD_CFG_NF(GPIO_85, NATIVE, DEEP, NF1)	 /* AVS_I2S2_BCLK */
+		PAD_CFG_NF(GPIO_86, NATIVE, DEEP, NF1)	 /* AVS_I2S2_SW_SYNC */
+		PAD_CFG_NF(GPIO_87, NATIVE, DEEP, NF1)	 /* AVS_I2S2_SDI */
+		PAD_CFG_NF(GPIO_88, NATIVE, DEEP, NF1)	 /* AVS_I2S2_SDO */
+
+		/* I2S3 -- largely unused */
+		PAD_CFG_GPI(GPIO_89, UP_20K, DEEP)	 /* unused */
+		PAD_CFG_GPI(GPIO_90, UP_20K, DEEP)	 /* GPS_HOST_WAKE */
+		PAD_CFG_GPO(GPIO_91, 1, DEEP)		 /* GPS_EN */
+		PAD_CFG_GPI(GPIO_92, DN_20K, DEEP)	 /* unused -- strap */
+
+		/* Fast SPI */
+		PAD_CFG_NF_IOSSTATE(GPIO_97, NATIVE, DEEP, NF1, IGNORE)	/* FST_SPI_CS0_B */
+		PAD_CFG_GPI(GPIO_98, UP_20K, DEEP)				/* FST_SPI_CS1_B -- unused */
+		PAD_CFG_NF_IOSSTATE(GPIO_99, NATIVE, DEEP, NF1, IGNORE)	/* FST_SPI_MOSI_IO0 */
+		PAD_CFG_NF_IOSSTATE(GPIO_100, NATIVE, DEEP, NF1, IGNORE)	/* FST_SPI_MISO_IO1 */
+		PAD_CFG_GPI(GPIO_101, NONE, DEEP)				/* FST_IO2 -- MEM_CONFIG0 */
+		PAD_CFG_GPI(GPIO_102, NONE, DEEP)				/* FST_IO3 -- MEM_CONFIG1 */
+		PAD_CFG_NF_IOSSTATE(GPIO_103, NATIVE, DEEP, NF1, IGNORE)	/* FST_SPI_CLK */
+		PAD_CFG_NF_IOSSTATE(FST_SPI_CLK_FB, NATIVE, DEEP, NF1, IGNORE) /* FST_SPI_CLK_FB */
+		PAD_CFG_NF_IOSSTATE(GPIO_106, NATIVE, DEEP, NF3, IGNORE)	/* FST_SPI_CS2_N */
+
+		/* SIO_SPI_0 - Used for FP */
+		PAD_CFG_NF(GPIO_104, NATIVE, DEEP, NF1)			/* SIO_SPI_0_CLK */
+		PAD_CFG_NF(GPIO_105, NATIVE, DEEP, NF1)			/* SIO_SPI_0_FS0 */
+		PAD_CFG_NF(GPIO_109, NATIVE, DEEP, NF1)			/* SIO_SPI_0_RXD */
+		PAD_CFG_NF(GPIO_110, NATIVE, DEEP, NF1)			/* SIO_SPI_0_TXD */
+
+		/* SIO_SPI_1 -- largely unused */
+		PAD_CFG_GPI(GPIO_111, UP_20K, DEEP)	 /* SIO_SPI_1_CLK */
+		PAD_CFG_GPI(GPIO_112, UP_20K, DEEP)	 /* SIO_SPI_1_FS0 */
+		PAD_CFG_GPI(GPIO_113, UP_20K, DEEP)	 /* SIO_SPI_1_FS1 */
+		/* Headset interrupt */
+		PAD_CFG_GPI_APIC_LOW(GPIO_116, NONE, DEEP) /* SIO_SPI_1_RXD */
+		PAD_CFG_GPI(GPIO_117, UP_20K, DEEP)	 /* SIO_SPI_1_TXD */
+
+		/* SIO_SPI_2 -- unused */
+		PAD_CFG_GPI(GPIO_118, UP_20K, DEEP)	 /* SIO_SPI_2_CLK */
+		PAD_CFG_GPI(GPIO_119, UP_20K, DEEP)	 /* SIO_SPI_2_FS0 */
+		PAD_CFG_GPI(GPIO_120, UP_20K, DEEP)	 /* SIO_SPI_2_FS1 */
+		PAD_CFG_GPI(GPIO_121, UP_20K, DEEP)	 /* SIO_SPI_2_FS2 */
+		/* WLAN_PE_RST - default to deasserted */
+		PAD_CFG_GPO(GPIO_122, 0, DEEP)		 /* SIO_SPI_2_RXD */
+		PAD_CFG_GPI(GPIO_123, UP_20K, DEEP)	 /* SIO_SPI_2_TXD */
+
+		/* Debug tracing */
+		PAD_CFG_GPI(GPIO_0, UP_20K, DEEP)
+		PAD_CFG_GPI(GPIO_1, UP_20K, DEEP)
+		PAD_CFG_GPI(GPIO_2, UP_20K, DEEP)
+		PAD_CFG_GPI_SCI_HIGH(GPIO_3, DN_20K, DEEP, LEVEL)	 /* FP_INT */
+		PAD_CFG_GPI(GPIO_4, UP_20K, DEEP)
+		PAD_CFG_GPI(GPIO_5, UP_20K, DEEP)
+		PAD_CFG_GPI(GPIO_6, UP_20K, DEEP)
+		PAD_CFG_GPI(GPIO_7, UP_20K, DEEP)
+		PAD_CFG_GPI(GPIO_8, UP_20K, DEEP)
+
+		PAD_CFG_GPI_APIC_LOW(GPIO_9, NONE, DEEP) /* dTPM IRQ */
+		PAD_CFG_GPI(GPIO_10, DN_20K, DEEP)	 /* Board phase enforcement */
+		PAD_CFG_GPI_SCI_LOW(GPIO_11, NONE, DEEP, EDGE_SINGLE) /* EC SCI  */
+		PAD_CFG_GPI(GPIO_12, UP_20K, DEEP)	 /* unused */
+		PAD_CFG_GPI_APIC_LOW(GPIO_13, NONE, DEEP) /* PEN_INT_ODL */
+		PAD_CFG_GPI_APIC_HIGH(GPIO_14, DN_20K, DEEP) /* FP_INT */
+		PAD_CFG_GPI_SCI_LOW(GPIO_15, NONE, DEEP, EDGE_SINGLE)	 /* TRACKPAD_INT_1V8_ODL */
+		PAD_CFG_GPI(GPIO_16, UP_20K, DEEP)	 /* unused */
+		PAD_CFG_GPI(GPIO_17, UP_20K, DEEP)	 /* 1 vs 4 DMIC config */
+		PAD_CFG_GPI_APIC_LOW(GPIO_18, NONE, DEEP) /* Trackpad IRQ */
+		PAD_CFG_GPI(GPIO_19, UP_20K, DEEP)	 /* unused */
+		PAD_CFG_GPI_APIC_LOW(GPIO_20, UP_20K, DEEP) /* NFC IRQ */
+		PAD_CFG_GPI_APIC_LOW(GPIO_21, NONE, DEEP) /* Touch IRQ */
+		PAD_CFG_GPI_SCI_LOW(GPIO_22, NONE, DEEP, EDGE_SINGLE) /* EC wake */
+		PAD_CFG_GPI(GPIO_23, UP_20K, DEEP)	 /* unused */
+		PAD_CFG_GPI(GPIO_24, NONE, DEEP)	 /* PEN_PDCT_ODL */
+		PAD_CFG_GPI(GPIO_25, UP_20K, DEEP)	 /* unused */
+		PAD_CFG_GPI(GPIO_26, UP_20K, DEEP)	 /* unused */
+		PAD_CFG_GPI(GPIO_27, UP_20K, DEEP)	 /* unused */
+		PAD_CFG_GPI_APIC_LOW(GPIO_28, NONE, DEEP) /* TPM IRQ */
+		PAD_CFG_GPO(GPIO_29, 1, DEEP)		 /* FP reset */
+		PAD_CFG_GPI_APIC_LOW(GPIO_30, NONE, DEEP) /* KB IRQ */
+		PAD_CFG_GPO(GPIO_31, 0, DEEP)		 /* NFC FW DL */
+		PAD_CFG_NF(GPIO_32, NONE, DEEP, NF5)	 /* SUS_CLK2 */
+		PAD_CFG_GPI_APIC_LOW(GPIO_33, NONE, DEEP) /* PMIC IRQ */
+		PAD_CFG_GPI(GPIO_34, UP_20K, DEEP)	 /* unused */
+		PAD_CFG_GPO(GPIO_35, 0, DEEP)		 /* PEN_RESET - active high */
+		PAD_CFG_GPO(GPIO_36, 0, DEEP)		 /* touch reset */
+		PAD_CFG_GPI(GPIO_37, UP_20K, DEEP)	 /* unused */
+
+		/* LPSS_UART[0:2] */
+		PAD_CFG_GPI(GPIO_38, NONE, DEEP)	 /* LPSS_UART0_RXD - MEM_CONFIG2*/
+		/* Next 2 are straps */
+		PAD_CFG_GPI(GPIO_39, DN_20K, DEEP)	 /* LPSS_UART0_TXD - unused */
+		PAD_CFG_GPI(GPIO_40, DN_20K, DEEP)	 /* LPSS_UART0_RTS - unused */
+		PAD_CFG_GPI(GPIO_41, NONE, DEEP)	 /* LPSS_UART0_CTS - EC_IN_RW */
+		PAD_CFG_NF(GPIO_42, NATIVE, DEEP, NF1)	 /* LPSS_UART1_RXD */
+		PAD_CFG_NF(GPIO_43, NATIVE, DEEP, NF1)	 /* LPSS_UART1_TXD */
+		PAD_CFG_GPO(GPIO_44, 1, DEEP)	 /* GPS_RST_ODL */
+		PAD_CFG_GPI(GPIO_45, NONE, DEEP)	 /* LPSS_UART1_CTS - MEM_CONFIG3 */
+		PAD_CFG_NF(GPIO_46, NATIVE, DEEP, NF1)	 /* LPSS_UART2_RXD */
+		PAD_CFG_NF_IOSSTATE(GPIO_47, NATIVE, DEEP, NF1, TX1_RX_DCR_X0) /* UART2 TX */
+		PAD_CFG_GPI(GPIO_48, UP_20K, DEEP)	 /* LPSS_UART2_RTS - unused */
+		PAD_CFG_GPI_SMI_LOW(GPIO_49, NONE, DEEP, EDGE_SINGLE) /* LPSS_UART2_CTS - EC_SMI_L */
+
+		/* Camera interface -- completely unused */
+		PAD_CFG_GPI(GPIO_62, UP_20K, DEEP)	 /* GP_CAMERASB00 */
+		PAD_CFG_GPI(GPIO_63, UP_20K, DEEP)	 /* GP_CAMERASB01 */
+		PAD_CFG_GPI(GPIO_64, UP_20K, DEEP)	 /* GP_CAMERASB02 */
+		PAD_CFG_GPI(GPIO_65, UP_20K, DEEP)	 /* GP_CAMERASB03 */
+		PAD_CFG_GPI(GPIO_66, UP_20K, DEEP)	 /* GP_CAMERASB04 */
+		PAD_CFG_GPI(GPIO_67, UP_20K, DEEP)	 /* GP_CAMERASB05 */
+		PAD_CFG_GPI(GPIO_68, UP_20K, DEEP)	 /* GP_CAMERASB06 */
+		PAD_CFG_GPI(GPIO_69, UP_20K, DEEP)	 /* GP_CAMERASB07 */
+		PAD_CFG_GPI(GPIO_70, UP_20K, DEEP)	 /* GP_CAMERASB08 */
+		PAD_CFG_GPI(GPIO_71, UP_20K, DEEP)	 /* GP_CAMERASB09 */
+		PAD_CFG_GPI(GPIO_72, UP_20K, DEEP)	 /* GP_CAMERASB10 */
+		PAD_CFG_GPI(GPIO_73, UP_20K, DEEP)	 /* GP_CAMERASB11 */
+	>;
+};
diff --git a/arch/x86/dts/u-boot.dtsi b/arch/x86/dts/u-boot.dtsi
index 0e87b88..f0f8c71 100644
--- a/arch/x86/dts/u-boot.dtsi
+++ b/arch/x86/dts/u-boot.dtsi
@@ -37,62 +37,110 @@
 	};
 #endif
 #ifdef CONFIG_TPL
+#ifdef CONFIG_HAVE_MICROCODE
 	u-boot-tpl-with-ucode-ptr {
 		offset = <CONFIG_TPL_TEXT_BASE>;
 	};
 	u-boot-tpl-dtb {
 	};
-	u-boot-spl {
-		offset = <CONFIG_SPL_TEXT_BASE>;
-	};
-	u-boot-spl-dtb {
+#endif
+	spl {
+		type = "section";
+		offset = <CONFIG_X86_OFFSET_SPL>;
+		u-boot-spl {
+		};
+		u-boot-spl-dtb {
+		};
 	};
 	u-boot {
-		offset = <CONFIG_SYS_TEXT_BASE>;
+		type = "section";
+		offset = <CONFIG_X86_OFFSET_U_BOOT>;
+		u-boot-nodtb {
+		};
+		u-boot-dtb {
+		};
 	};
 #elif defined(CONFIG_SPL)
 	u-boot-spl-with-ucode-ptr {
-		offset = <CONFIG_SPL_TEXT_BASE>;
+		offset = <CONFIG_X86_OFFSET_SPL>;
 	};
 	u-boot-dtb-with-ucode2 {
 		type = "u-boot-dtb-with-ucode";
 	};
 	u-boot {
-		/*
-		 * TODO(sjg@chromium.org):
-		 * Normally we use CONFIG_SYS_TEXT_BASE as the flash offset. But
-		 * for boards with textbase in SDRAM we cannot do this. Just use
-		 * an assumed-valid value (1MB before the end of flash) here so
-		 * that we can actually build an image for coreboot, etc.
-		 * We need a better solution, perhaps a separate Kconfig.
-		 */
-#if CONFIG_SYS_TEXT_BASE == 0x1110000
-		offset = <0xfff00000>;
+		offset = <CONFIG_X86_OFFSET_U_BOOT>;
+	};
 #else
+# ifdef CONFIG_SPL
+	u-boot {
 		offset = <CONFIG_SYS_TEXT_BASE>;
-#endif
 	};
-#else
+# else
+	/* If there is no SPL then we need to put microcode in U-Boot */
 	u-boot-with-ucode-ptr {
-		offset = <CONFIG_SYS_TEXT_BASE>;
+		offset = <CONFIG_X86_OFFSET_U_BOOT>;
 	};
+# endif
 #endif
+#ifdef CONFIG_HAVE_MICROCODE
 	u-boot-dtb-with-ucode {
 	};
 	u-boot-ucode {
 		align = <16>;
 	};
+#else
+	u-boot-dtb {
+	};
+#endif
+#ifdef CONFIG_HAVE_X86_FIT
+	intel-fit {
+	};
+	intel-fit-ptr {
+	};
+#endif
 #ifdef CONFIG_HAVE_MRC
 	intel-mrc {
 		offset = <CONFIG_X86_MRC_ADDR>;
 	};
 #endif
-#ifdef CONFIG_HAVE_FSP
+#ifdef CONFIG_FSP_VERSION1
 	intel-fsp {
 		filename = CONFIG_FSP_FILE;
 		offset = <CONFIG_FSP_ADDR>;
 	};
 #endif
+#ifdef CONFIG_FSP_VERSION2
+	intel-descriptor {
+		filename = CONFIG_FLASH_DESCRIPTOR_FILE;
+	};
+	intel-ifwi {
+		filename = CONFIG_IFWI_INPUT_FILE;
+		convert-fit;
+
+		section {
+			size = <0x8000>;
+			ifwi-replace;
+			ifwi-subpart = "IBBP";
+			ifwi-entry = "IBBL";
+			u-boot-tpl {
+			};
+			x86-start16-tpl {
+				offset = <0x7800>;
+			};
+			x86-reset16-tpl {
+				offset = <0x7ff0>;
+			};
+		};
+	};
+	intel-fsp-m {
+		filename = CONFIG_FSP_FILE_M;
+	};
+	intel-fsp-s {
+		filename = CONFIG_FSP_FILE_S;
+	};
+#endif
+	fdtmap {
+	};
 #ifdef CONFIG_HAVE_CMC
 	intel-cmc {
 		filename = CONFIG_CMC_FILE;
@@ -138,5 +186,8 @@
 		offset = <CONFIG_RESET_VEC_LOC>;
 	};
 #endif
+	image-header {
+		location = "end";
+	};
 };
 #endif
diff --git a/arch/x86/include/asm/arch-apollolake/cpu.h b/arch/x86/include/asm/arch-apollolake/cpu.h
new file mode 100644
index 0000000..5e906c5
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/cpu.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef _ASM_ARCH_CPU_H
+#define _ASM_ARCH_CPU_H
+
+/* Common Timer Copy (CTC) frequency - 19.2MHz */
+#define CTC_FREQ		19200000
+
+#define MAX_PCIE_PORTS		6
+#define CLKREQ_DISABLED		0xf
+
+#ifndef __ASSEMBLY__
+/* Flush L1D to L2 */
+void cpu_flush_l1d_to_l2(void);
+#endif
+
+#endif /* _ASM_ARCH_CPU_H */
diff --git a/arch/x86/include/asm/arch-apollolake/fsp/fsp_configs.h b/arch/x86/include/asm/arch-apollolake/fsp/fsp_configs.h
new file mode 100644
index 0000000..9185d94
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/fsp/fsp_configs.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: Intel */
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef __FSP_CONFIGS_H__
+#define __FSP_CONFIGS_H__
+
+#define FSPT_UPD_SIGNATURE	0x545F4450554C5041	/* 'APLUPD_T' */
+#define FSPM_UPD_SIGNATURE	0x4D5F4450554C5041	/* 'APLUPD_M' */
+#define FSPS_UPD_SIGNATURE	0x535F4450554C5041	/* 'APLUPD_S' */
+#define VBT_SIGNATURE		0x54425624
+
+#endif
diff --git a/arch/x86/include/asm/arch-apollolake/fsp/fsp_m_upd.h b/arch/x86/include/asm/arch-apollolake/fsp/fsp_m_upd.h
new file mode 100644
index 0000000..93bee5b
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/fsp/fsp_m_upd.h
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: Intel */
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef	__ASM_ARCH_FSP_M_UDP_H
+#define	__ASM_ARCH_FSP_M_UDP_H
+
+#include <asm/fsp2/fsp_api.h>
+
+#define FSP_DRAM_CHANNELS	4
+
+struct __packed fspm_arch_upd {
+	u8	revision;
+	u8	reserved[3];
+	void	*nvs_buffer_ptr;
+	void	*stack_base;
+	u32	stack_size;
+	u32	boot_loader_tolum_size;
+	u32	boot_mode;
+	u8	reserved1[8];
+};
+
+struct __packed fsp_ram_channel {
+	u8	rank_enable;
+	u8	device_width;
+	u8	dram_density;
+	u8	option;
+	u8	odt_config;
+	u8	tristate_clk1;
+	u8	mode2_n;
+	u8	odt_levels;
+};
+
+struct __packed fsp_m_config {
+	u32	serial_debug_port_address;
+	u8	serial_debug_port_type;
+	u8	serial_debug_port_device;
+	u8	serial_debug_port_stride_size;
+	u8	mrc_fast_boot;
+	u8	igd;
+	u8	igd_dvmt50_pre_alloc;
+	u8	igd_aperture_size;
+	u8	gtt_size;
+	u8	primary_video_adaptor;
+	u8	package;
+	u8	profile;
+	u8	memory_down;
+
+	u8	ddr3_l_page_size;
+	u8	ddr3_lasr;
+	u8	scrambler_support;
+	u8	interleaved_mode;
+	u16	channel_hash_mask;
+	u16	slice_hash_mask;
+	u8	channels_slices_enable;
+	u8	min_ref_rate2x_enable;
+	u8	dual_rank_support_enable;
+	u8	rmt_mode;
+	u16	memory_size_limit;
+	u16	low_memory_max_value;
+
+	u16	high_memory_max_value;
+	u8	disable_fast_boot;
+	u8	dimm0_spd_address;
+	u8	dimm1_spd_address;
+	struct fsp_ram_channel chan[FSP_DRAM_CHANNELS];
+	u8	rmt_check_run;
+	u16	rmt_margin_check_scale_high_threshold;
+	u8	ch_bit_swizzling[FSP_DRAM_CHANNELS][32];
+	u32	msg_level_mask;
+	u8	unused_upd_space0[4];
+
+	u8	pre_mem_gpio_table_pin_num[4];
+	u32	pre_mem_gpio_table_ptr;
+	u8	pre_mem_gpio_table_entry_num;
+	u8	enhance_port8xh_decoding;
+	u8	spd_write_enable;
+	u8	mrc_data_saving;
+	u32	oem_loading_base;
+
+	u8	oem_file_name[16];
+
+	void	*mrc_boot_data_ptr;
+	u8	e_mmc_trace_len;
+	u8	skip_cse_rbp;
+	u8	npk_en;
+	u8	fw_trace_en;
+	u8	fw_trace_destination;
+	u8	recover_dump;
+	u8	msc0_wrap;
+	u8	msc1_wrap;
+	u32	msc0_size;
+
+	u32	msc1_size;
+	u8	pti_mode;
+	u8	pti_training;
+	u8	pti_speed;
+	u8	punit_mlvl;
+
+	u8	pmc_mlvl;
+	u8	sw_trace_en;
+	u8	periodic_retraining_disable;
+	u8	enable_reset_system;
+
+	u8	enable_s3_heci2;
+	u8	unused_upd_space1[3];
+
+	void	*variable_nvs_buffer_ptr;
+	u8	reserved_fspm_upd[12];
+};
+
+/** FSP-M UPD Configuration */
+struct __packed fspm_upd {
+	struct fsp_upd_header header;
+	struct fspm_arch_upd arch;
+	struct fsp_m_config config;
+	u8 unused_upd_space2[158];
+	u16 upd_terminator;
+};
+
+#endif
diff --git a/arch/x86/include/asm/arch-apollolake/fsp/fsp_s_upd.h b/arch/x86/include/asm/arch-apollolake/fsp/fsp_s_upd.h
new file mode 100644
index 0000000..4a868e8
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/fsp/fsp_s_upd.h
@@ -0,0 +1,292 @@
+/* SPDX-License-Identifier: Intel */
+/*
+ * Copyright (c) 2016, Intel Corporation. All rights reserved.
+ * Copyright 2019 Google LLC
+ */
+#ifndef __ASM_ARCH_FSP_S_UDP_H
+#define __ASM_ARCH_FSP_S_UDP_H
+
+#include <asm/fsp2/fsp_api.h>
+
+struct __packed fsp_s_config {
+	u8	active_processor_cores;
+	u8	disable_core1;
+	u8	disable_core2;
+	u8	disable_core3;
+	u8	vmx_enable;
+	u8	proc_trace_mem_size;
+	u8	proc_trace_enable;
+	u8	eist;
+	u8	boot_p_state;
+	u8	enable_cx;
+	u8	c1e;
+	u8	bi_proc_hot;
+	u8	pkg_c_state_limit;
+	u8	c_state_auto_demotion;
+	u8	c_state_un_demotion;
+	u8	max_core_c_state;
+	u8	pkg_c_state_demotion;
+	u8	pkg_c_state_un_demotion;
+	u8	turbo_mode;
+	u8	hda_verb_table_entry_num;
+	u32	hda_verb_table_ptr;
+	u8	p2sb_unhide;
+	u8	ipu_en;
+	u8	ipu_acpi_mode;
+	u8	force_wake;
+	u32	gtt_mm_adr;
+	u32	gm_adr;
+	u8	pavp_lock;
+	u8	graphics_freq_modify;
+	u8	graphics_freq_req;
+	u8	graphics_video_freq;
+	u8	pm_lock;
+	u8	dop_clock_gating;
+	u8	unsolicited_attack_override;
+	u8	wopcm_support;
+	u8	wopcm_size;
+	u8	power_gating;
+	u8	unit_level_clock_gating;
+	u8	fast_boot;
+	u8	dyn_sr;
+	u8	sa_ipu_enable;
+	u8	pm_support;
+	u8	enable_render_standby;
+	u32	logo_size;
+	u32	logo_ptr;
+	u32	graphics_config_ptr;
+	u8	pavp_enable;
+	u8	pavp_pr3;
+	u8	cd_clock;
+	u8	pei_graphics_peim_init;
+	u8	write_protection_enable[5];
+	u8	read_protection_enable[5];
+	u16	protected_range_limit[5];
+	u16	protected_range_base[5];
+	u8	gmm;
+	u8	clk_gating_pgcb_clk_trunk;
+	u8	clk_gating_sb;
+	u8	clk_gating_sb_clk_trunk;
+	u8	clk_gating_sb_clk_partition;
+	u8	clk_gating_core;
+	u8	clk_gating_dma;
+	u8	clk_gating_reg_access;
+	u8	clk_gating_host;
+	u8	clk_gating_partition;
+	u8	clk_gating_trunk;
+	u8	hda_enable;
+	u8	dsp_enable;
+	u8	pme;
+	u8	hd_audio_io_buffer_ownership;
+	u8	hd_audio_io_buffer_voltage;
+	u8	hd_audio_vc_type;
+	u8	hd_audio_link_frequency;
+	u8	hd_audio_i_disp_link_frequency;
+	u8	hd_audio_i_disp_link_tmode;
+	u8	dsp_endpoint_dmic;
+	u8	dsp_endpoint_bluetooth;
+	u8	dsp_endpoint_i2s_skp;
+	u8	dsp_endpoint_i2s_hp;
+	u8	audio_ctl_pwr_gate;
+	u8	audio_dsp_pwr_gate;
+	u8	mmt;
+	u8	hmt;
+	u8	hd_audio_pwr_gate;
+	u8	hd_audio_clk_gate;
+	u32	dsp_feature_mask;
+	u32	dsp_pp_module_mask;
+	u8	bios_cfg_lock_down;
+	u8	hpet;
+	u8	hpet_bdf_valid;
+	u8	hpet_bus_number;
+	u8	hpet_device_number;
+	u8	hpet_function_number;
+	u8	io_apic_bdf_valid;
+	u8	io_apic_bus_number;
+	u8	io_apic_device_number;
+	u8	io_apic_function_number;
+	u8	io_apic_entry24_119;
+	u8	io_apic_id;
+	u8	io_apic_range_select;
+	u8	ish_enable;
+	u8	bios_interface;
+	u8	bios_lock;
+	u8	spi_eiss;
+	u8	bios_lock_sw_smi_number;
+	u8	lpss_s0ix_enable;
+	u8	unused_upd_space0[1];
+	u8	i2c_clk_gate_cfg[8];
+	u8	hsuart_clk_gate_cfg[4];
+	u8	spi_clk_gate_cfg[3];
+	u8	i2c0_enable;
+	u8	i2c1_enable;
+	u8	i2c2_enable;
+	u8	i2c3_enable;
+	u8	i2c4_enable;
+	u8	i2c5_enable;
+	u8	i2c6_enable;
+	u8	i2c7_enable;
+	u8	hsuart0_enable;
+	u8	hsuart1_enable;
+	u8	hsuart2_enable;
+	u8	hsuart3_enable;
+	u8	spi0_enable;
+	u8	spi1_enable;
+	u8	spi2_enable;
+	u8	os_dbg_enable;
+	u8	dci_en;
+	u32	uart2_kernel_debug_base_address;
+	u8	pcie_clock_gating_disabled;
+	u8	pcie_root_port8xh_decode;
+	u8	pcie8xh_decode_port_index;
+	u8	pcie_root_port_peer_memory_write_enable;
+	u8	pcie_aspm_sw_smi_number;
+	u8	unused_upd_space1[1];
+	u8	pcie_root_port_en[6];
+	u8	pcie_rp_hide[6];
+	u8	pcie_rp_slot_implemented[6];
+	u8	pcie_rp_hot_plug[6];
+	u8	pcie_rp_pm_sci[6];
+	u8	pcie_rp_ext_sync[6];
+	u8	pcie_rp_transmitter_half_swing[6];
+	u8	pcie_rp_acs_enabled[6];
+	u8	pcie_rp_clk_req_supported[6];
+	u8	pcie_rp_clk_req_number[6];
+	u8	pcie_rp_clk_req_detect[6];
+	u8	advanced_error_reporting[6];
+	u8	pme_interrupt[6];
+	u8	unsupported_request_report[6];
+	u8	fatal_error_report[6];
+	u8	no_fatal_error_report[6];
+	u8	correctable_error_report[6];
+	u8	system_error_on_fatal_error[6];
+	u8	system_error_on_non_fatal_error[6];
+	u8	system_error_on_correctable_error[6];
+	u8	pcie_rp_speed[6];
+	u8	physical_slot_number[6];
+	u8	pcie_rp_completion_timeout[6];
+	u8	ptm_enable[6];
+	u8	pcie_rp_aspm[6];
+	u8	pcie_rp_l1_substates[6];
+	u8	pcie_rp_ltr_enable[6];
+	u8	pcie_rp_ltr_config_lock[6];
+	u8	pme_b0_s5_dis;
+	u8	pci_clock_run;
+	u8	timer8254_clk_setting;
+	u8	enable_sata;
+	u8	sata_mode;
+	u8	sata_salp_support;
+	u8	sata_pwr_opt_enable;
+	u8	e_sata_speed_limit;
+	u8	speed_limit;
+	u8	unused_upd_space2[1];
+	u8	sata_ports_enable[2];
+	u8	sata_ports_dev_slp[2];
+	u8	sata_ports_hot_plug[2];
+	u8	sata_ports_interlock_sw[2];
+	u8	sata_ports_external[2];
+	u8	sata_ports_spin_up[2];
+	u8	sata_ports_solid_state_drive[2];
+	u8	sata_ports_enable_dito_config[2];
+	u8	sata_ports_dm_val[2];
+	u8	unused_upd_space3[2];
+	u16	sata_ports_dito_val[2];
+	u16	sub_system_vendor_id;
+	u16	sub_system_id;
+	u8	crid_settings;
+	u8	reset_select;
+	u8	sdcard_enabled;
+	u8	e_mmc_enabled;
+	u8	e_mmc_host_max_speed;
+	u8	ufs_enabled;
+	u8	sdio_enabled;
+	u8	gpp_lock;
+	u8	sirq_enable;
+	u8	sirq_mode;
+	u8	start_frame_pulse;
+	u8	smbus_enable;
+	u8	arp_enable;
+	u8	unused_upd_space4;
+	u16	num_rsvd_smbus_addresses;
+	u8	rsvd_smbus_address_table[128];
+	u8	disable_compliance_mode;
+	u8	usb_per_port_ctl;
+	u8	usb30_mode;
+	u8	unused_upd_space5[1];
+	u8	port_usb20_enable[8];
+	u8	port_us20b_over_current_pin[8];
+	u8	usb_otg;
+	u8	hsic_support_enable;
+	u8	port_usb30_enable[6];
+	u8	port_us30b_over_current_pin[6];
+	u8	ssic_port_enable[2];
+	u16	dlane_pwr_gating;
+	u8	vtd_enable;
+	u8	lock_down_global_smi;
+	u16	reset_wait_timer;
+	u8	rtc_lock;
+	u8	sata_test_mode;
+	u8	ssic_rate[2];
+	u16	dynamic_power_gating;
+	u16	pcie_rp_ltr_max_snoop_latency[6];
+	u8	pcie_rp_snoop_latency_override_mode[6];
+	u8	unused_upd_space6[2];
+	u16	pcie_rp_snoop_latency_override_value[6];
+	u8	pcie_rp_snoop_latency_override_multiplier[6];
+	u8	skip_mp_init;
+	u8	dci_auto_detect;
+	u16	pcie_rp_ltr_max_non_snoop_latency[6];
+	u8	pcie_rp_non_snoop_latency_override_mode[6];
+	u8	tco_timer_halt_lock;
+	u8	pwr_btn_override_period;
+	u16	pcie_rp_non_snoop_latency_override_value[6];
+	u8	pcie_rp_non_snoop_latency_override_multiplier[6];
+	u8	pcie_rp_slot_power_limit_scale[6];
+	u8	pcie_rp_slot_power_limit_value[6];
+	u8	disable_native_power_button;
+	u8	power_butter_debounce_mode;
+	u32	sdio_tx_cmd_cntl;
+	u32	sdio_tx_data_cntl1;
+	u32	sdio_tx_data_cntl2;
+	u32	sdio_rx_cmd_data_cntl1;
+	u32	sdio_rx_cmd_data_cntl2;
+	u32	sdcard_tx_cmd_cntl;
+	u32	sdcard_tx_data_cntl1;
+	u32	sdcard_tx_data_cntl2;
+	u32	sdcard_rx_cmd_data_cntl1;
+	u32	sdcard_rx_strobe_cntl;
+	u32	sdcard_rx_cmd_data_cntl2;
+	u32	emmc_tx_cmd_cntl;
+	u32	emmc_tx_data_cntl1;
+	u32	emmc_tx_data_cntl2;
+	u32	emmc_rx_cmd_data_cntl1;
+	u32	emmc_rx_strobe_cntl;
+	u32	emmc_rx_cmd_data_cntl2;
+	u32	emmc_master_sw_cntl;
+	u8	pcie_rp_selectable_deemphasis[6];
+	u8	monitor_mwait_enable;
+	u8	hd_audio_dsp_uaa_compliance;
+	u32	ipc[4];
+	u8	sata_ports_disable_dynamic_pg[2];
+	u8	init_s3_cpu;
+	u8	skip_punit_init;
+	u8	unused_upd_space7[4];
+	u8	port_usb20_per_port_tx_pe_half[8];
+	u8	port_usb20_per_port_pe_txi_set[8];
+	u8	port_usb20_per_port_txi_set[8];
+	u8	port_usb20_hs_skew_sel[8];
+	u8	port_usb20_i_usb_tx_emphasis_en[8];
+	u8	port_usb20_per_port_rxi_set[8];
+	u8	port_usb20_hs_npre_drv_sel[8];
+	u8	reserved_fsps_upd[16];
+};
+
+/** struct fsps_upd - FSP-S Configuration */
+struct __packed fsps_upd {
+	struct fsp_upd_header header;
+	struct fsp_s_config config;
+	u8 unused_upd_space2[46];
+	u16 upd_terminator;
+};
+
+#endif
diff --git a/arch/x86/include/asm/arch-apollolake/fsp/fsp_vpd.h b/arch/x86/include/asm/arch-apollolake/fsp/fsp_vpd.h
new file mode 100644
index 0000000..b14f28b
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/fsp/fsp_vpd.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: Intel */
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef __FSP_VPD_H
+#define __FSP_VPD_H
+
+/* Nothing to declare here for FSP2 */
+
+#endif
diff --git a/arch/x86/include/asm/arch-apollolake/gpio.h b/arch/x86/include/asm/arch-apollolake/gpio.h
new file mode 100644
index 0000000..10879c1
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/gpio.h
@@ -0,0 +1,485 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Definitions for the GPIO subsystem on Apollolake
+ *
+ * Copyright (C) 2015 - 2017 Intel Corp.
+ * (Written by Alexandru Gagniuc <alexandrux.gagniuc@intel.com> for Intel Corp.)
+ *
+ * Placed in a separate file since some of these definitions can be used from
+ * assembly code
+ *
+ * Taken from gpio_apl.h in coreboot
+ */
+
+#ifndef _ASM_ARCH_GPIO_H_
+#define _ASM_ARCH_GPIO_H_
+
+/* Port ids */
+#define PID_GPIO_SW	0xC0
+#define PID_GPIO_S	0xC2
+#define PID_GPIO_W	0xC7
+#define PID_GPIO_NW	0xC4
+#define PID_GPIO_N	0xC5
+#define PID_ITSS	0xD0
+#define PID_RTC		0xD1
+
+/*
+ * Miscellaneous Configuration register(MISCCFG). These are community-specific
+ * registers and are meant to house miscellaneous configuration fields per
+ * community. There are 8 GPIO groups: GPP_0 -> GPP_8 (Group 3 is absent)
+ */
+#define GPIO_MISCCFG		0x10 /* Miscellaneous Configuration offset */
+#define  GPIO_GPE_SW_31_0	0 /* SOUTHWEST GPIO#  0 ~ 31 belong to GROUP0 */
+#define  GPIO_GPE_SW_63_32	1 /* SOUTHWEST GPIO# 32 ~ 42 belong to GROUP1 */
+#define  GPIO_GPE_W_31_0	2 /* WEST      GPIO#  0 ~ 25 belong to GROUP2 */
+#define  GPIO_GPE_NW_31_0	4 /* NORTHWEST GPIO#  0 ~ 17 belong to GROUP4 */
+#define  GPIO_GPE_NW_63_32	5 /* NORTHWEST GPIO# 32 ~ 63 belong to GROUP5 */
+#define  GPIO_GPE_NW_95_64	6 /* NORTHWEST GPIO# 64 ~ 76 belong to GROUP6 */
+#define  GPIO_GPE_N_31_0	7 /* NORTH     GPIO#  0 ~ 31 belong to GROUP7 */
+#define  GPIO_GPE_N_63_32	8 /* NORTH     GPIO# 32 ~ 61 belong to GROUP8 */
+
+#define GPIO_MAX_NUM_PER_GROUP	32
+
+/*
+ * Host Software Pad Ownership Register.
+ * The pins in the community are divided into 3 groups:
+ * GPIO 0 ~ 31, GPIO 32 ~ 63, GPIO 64 ~ 95
+ */
+#define HOSTSW_OWN_REG_0		0x80
+
+#define PAD_CFG_BASE			0x500
+
+#define GPI_INT_STS_0			0x100
+#define GPI_INT_EN_0			0x110
+
+#define GPI_SMI_STS_0			0x140
+#define GPI_SMI_EN_0			0x150
+
+#define NUM_N_PADS			(PAD_N(SVID0_CLK) + 1)
+#define NUM_NW_PADS			(PAD_NW(GPIO_123) + 1)
+#define NUM_W_PADS			(PAD_W(SUSPWRDNACK) + 1)
+#define NUM_SW_PADS			(PAD_SW(LPC_FRAMEB) + 1)
+
+#define NUM_N_GPI_REGS	\
+	(ALIGN(NUM_N_PADS, GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP)
+
+#define NUM_NW_GPI_REGS	\
+	(ALIGN(NUM_NW_PADS, GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP)
+
+#define NUM_W_GPI_REGS	\
+	(ALIGN(NUM_W_PADS, GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP)
+
+#define NUM_SW_GPI_REGS	\
+	(ALIGN(NUM_SW_PADS, GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP)
+
+/*
+ * Total number of GPI status registers across all GPIO communities in the SOC
+ */
+#define NUM_GPI_STATUS_REGS		(NUM_N_GPI_REGS + NUM_NW_GPI_REGS \
+					+ NUM_W_GPI_REGS + NUM_SW_GPI_REGS)
+
+/* North community pads */
+#define GPIO_0				0
+#define GPIO_1				1
+#define GPIO_2				2
+#define GPIO_3				3
+#define GPIO_4				4
+#define GPIO_5				5
+#define GPIO_6				6
+#define GPIO_7				7
+#define GPIO_8				8
+#define GPIO_9				9
+#define GPIO_10				10
+#define GPIO_11				11
+#define GPIO_12				12
+#define GPIO_13				13
+#define GPIO_14				14
+#define GPIO_15				15
+#define GPIO_16				16
+#define GPIO_17				17
+#define GPIO_18				18
+#define GPIO_19				19
+#define GPIO_20				20
+#define GPIO_21				21
+#define GPIO_22				22
+#define GPIO_23				23
+#define GPIO_24				24
+#define GPIO_25				25
+#define GPIO_26				26
+#define GPIO_27				27
+#define GPIO_28				28
+#define GPIO_29				29
+#define GPIO_30				30
+#define GPIO_31				31
+#define GPIO_32				32
+#define GPIO_33				33
+#define GPIO_34				34
+#define GPIO_35				35
+#define GPIO_36				36
+#define GPIO_37				37
+#define GPIO_38				38
+#define GPIO_39				39
+#define GPIO_40				40
+#define GPIO_41				41
+#define GPIO_42				42
+#define GPIO_43				43
+#define GPIO_44				44
+#define GPIO_45				45
+#define GPIO_46				46
+#define GPIO_47				47
+#define GPIO_48				48
+#define GPIO_49				49
+#define GPIO_62				50
+#define GPIO_63				51
+#define GPIO_64				52
+#define GPIO_65				53
+#define GPIO_66				54
+#define GPIO_67				55
+#define GPIO_68				56
+#define GPIO_69				57
+#define GPIO_70				58
+#define GPIO_71				59
+#define GPIO_72				60
+#define GPIO_73				61
+#define JTAG_TCK			62
+#define JTAG_TRST_B			63
+#define JTAG_TMS			64
+#define JTAG_TDI			65
+#define JTAG_CX_PMODE			66
+#define JTAG_CX_PREQ_B			67
+#define JTAGX				68
+#define JTAG_CX_PRDY_B			69
+#define JTAG_TDO			70
+#define CNV_BRI_DT			71
+#define CNV_BRI_RSP			72
+#define CNV_RGI_DT			73
+#define CNV_RGI_RSP			74
+#define SVID0_ALERT_B			75
+#define SVID0_DATA			76
+#define SVID0_CLK			77
+
+/* Northwest community pads */
+#define GPIO_187			78
+#define GPIO_188			79
+#define GPIO_189			80
+#define GPIO_190			81
+#define GPIO_191			82
+#define GPIO_192			83
+#define GPIO_193			84
+#define GPIO_194			85
+#define GPIO_195			86
+#define GPIO_196			87
+#define GPIO_197			88
+#define GPIO_198			89
+#define GPIO_199			90
+#define GPIO_200			91
+#define GPIO_201			92
+#define GPIO_202			93
+#define GPIO_203			94
+#define GPIO_204			95
+#define PMC_SPI_FS0			96
+#define PMC_SPI_FS1			97
+#define PMC_SPI_FS2			98
+#define PMC_SPI_RXD			99
+#define PMC_SPI_TXD			100
+#define PMC_SPI_CLK			101
+#define PMIC_PWRGOOD			102
+#define PMIC_RESET_B			103
+#define GPIO_213			104
+#define GPIO_214			105
+#define GPIO_215			106
+#define PMIC_THERMTRIP_B		107
+#define PMIC_STDBY			108
+#define PROCHOT_B			109
+#define PMIC_I2C_SCL			110
+#define PMIC_I2C_SDA			111
+#define GPIO_74				112
+#define GPIO_75				113
+#define GPIO_76				114
+#define GPIO_77				115
+#define GPIO_78				116
+#define GPIO_79				117
+#define GPIO_80				118
+#define GPIO_81				119
+#define GPIO_82				120
+#define GPIO_83				121
+#define GPIO_84				122
+#define GPIO_85				123
+#define GPIO_86				124
+#define GPIO_87				125
+#define GPIO_88				126
+#define GPIO_89				127
+#define GPIO_90				128
+#define GPIO_91				129
+#define GPIO_92				130
+#define GPIO_97				131
+#define GPIO_98				132
+#define GPIO_99				133
+#define GPIO_100			134
+#define GPIO_101			135
+#define GPIO_102			136
+#define GPIO_103			137
+#define FST_SPI_CLK_FB			138
+#define GPIO_104			139
+#define GPIO_105			140
+#define GPIO_106			141
+#define GPIO_109			142
+#define GPIO_110			143
+#define GPIO_111			144
+#define GPIO_112			145
+#define GPIO_113			146
+#define GPIO_116			147
+#define GPIO_117			148
+#define GPIO_118			149
+#define GPIO_119			150
+#define GPIO_120			151
+#define GPIO_121			152
+#define GPIO_122			153
+#define GPIO_123			154
+
+/* West community pads */
+#define GPIO_124			155
+#define GPIO_125			156
+#define GPIO_126			157
+#define GPIO_127			158
+#define GPIO_128			159
+#define GPIO_129			160
+#define GPIO_130			161
+#define GPIO_131			162
+#define GPIO_132			163
+#define GPIO_133			164
+#define GPIO_134			165
+#define GPIO_135			166
+#define GPIO_136			167
+#define GPIO_137			168
+#define GPIO_138			169
+#define GPIO_139			170
+#define GPIO_146			171
+#define GPIO_147			172
+#define GPIO_148			173
+#define GPIO_149			174
+#define GPIO_150			175
+#define GPIO_151			176
+#define GPIO_152			177
+#define GPIO_153			178
+#define GPIO_154			179
+#define GPIO_155			180
+#define GPIO_209			181
+#define GPIO_210			182
+#define GPIO_211			183
+#define GPIO_212			184
+#define OSC_CLK_OUT_0			185
+#define OSC_CLK_OUT_1			186
+#define OSC_CLK_OUT_2			187
+#define OSC_CLK_OUT_3			188
+#define OSC_CLK_OUT_4			189
+#define PMU_AC_PRESENT			190
+#define PMU_BATLOW_B			191
+#define PMU_PLTRST_B			192
+#define PMU_PWRBTN_B			193
+#define PMU_RESETBUTTON_B		194
+#define PMU_SLP_S0_B			195
+#define PMU_SLP_S3_B			196
+#define PMU_SLP_S4_B			197
+#define PMU_SUSCLK			198
+#define PMU_WAKE_B			199
+#define SUS_STAT_B			200
+#define SUSPWRDNACK			201
+
+/* Southwest community pads */
+#define GPIO_205			202
+#define GPIO_206			203
+#define GPIO_207			204
+#define GPIO_208			205
+#define GPIO_156			206
+#define GPIO_157			207
+#define GPIO_158			208
+#define GPIO_159			209
+#define GPIO_160			210
+#define GPIO_161			211
+#define GPIO_162			212
+#define GPIO_163			213
+#define GPIO_164			214
+#define GPIO_165			215
+#define GPIO_166			216
+#define GPIO_167			217
+#define GPIO_168			218
+#define GPIO_169			219
+#define GPIO_170			220
+#define GPIO_171			221
+#define GPIO_172			222
+#define GPIO_179			223
+#define GPIO_173			224
+#define GPIO_174			225
+#define GPIO_175			226
+#define GPIO_176			227
+#define GPIO_177			228
+#define GPIO_178			229
+#define GPIO_186			230
+#define GPIO_182			231
+#define GPIO_183			232
+#define SMB_ALERTB			233
+#define SMB_CLK				234
+#define SMB_DATA			235
+#define LPC_ILB_SERIRQ			236
+#define LPC_CLKOUT0			237
+#define LPC_CLKOUT1			238
+#define LPC_AD0				239
+#define LPC_AD1				240
+#define LPC_AD2				241
+#define LPC_AD3				242
+#define LPC_CLKRUNB			243
+#define LPC_FRAMEB			244
+
+/* PERST_0 not defined */
+#define GPIO_PRT0_UDEF			0xFF
+
+#define TOTAL_PADS			245
+#define N_OFFSET			GPIO_0
+#define NW_OFFSET			GPIO_187
+#define W_OFFSET			GPIO_124
+#define SW_OFFSET			GPIO_205
+
+/* Macros for translating a global pad offset to a local offset */
+#define PAD_N(pad)			(pad - N_OFFSET)
+#define PAD_NW(pad)			(pad - NW_OFFSET)
+#define PAD_W(pad)			(pad - W_OFFSET)
+#define PAD_SW(pad)			(pad - SW_OFFSET)
+
+/* Linux names of the GPIO devices */
+#define GPIO_COMM_N_NAME		"INT3452:00"
+#define GPIO_COMM_NW_NAME		"INT3452:01"
+#define GPIO_COMM_W_NAME		"INT3452:02"
+#define GPIO_COMM_SW_NAME		"INT3452:03"
+
+/* Following is used in gpio asl */
+#define GPIO_COMM_NAME			"INT3452"
+#define GPIO_COMM_0_DESC	\
+	"General Purpose Input/Output (GPIO) Controller - North"
+#define GPIO_COMM_1_DESC	\
+	"General Purpose Input/Output (GPIO) Controller - Northwest"
+#define GPIO_COMM_2_DESC	\
+	"General Purpose Input/Output (GPIO) Controller - West"
+#define GPIO_COMM_3_DESC	\
+	"General Purpose Input/Output (GPIO) Controller - Southwest"
+
+#define GPIO_COMM0_PID			PID_GPIO_N
+#define GPIO_COMM1_PID			PID_GPIO_NW
+#define GPIO_COMM2_PID			PID_GPIO_W
+#define GPIO_COMM3_PID			PID_GPIO_SW
+
+/*
+ * IOxAPIC IRQs for the GPIOs, overlap is expected as we encourage to use
+ * shared IRQ instead of direct IRQ, in case of overlapping, we can easily
+ * program one of the overlap to shared IRQ to avoid the conflict.
+ */
+
+/* NorthWest community pads */
+#define PMIC_I2C_SDA_IRQ		0x32
+#define GPIO_74_IRQ			0x33
+#define GPIO_75_IRQ			0x34
+#define GPIO_76_IRQ			0x35
+#define GPIO_77_IRQ			0x36
+#define GPIO_78_IRQ			0x37
+#define GPIO_79_IRQ			0x38
+#define GPIO_80_IRQ			0x39
+#define GPIO_81_IRQ			0x3A
+#define GPIO_82_IRQ			0x3B
+#define GPIO_83_IRQ			0x3C
+#define GPIO_84_IRQ			0x3D
+#define GPIO_85_IRQ			0x3E
+#define GPIO_86_IRQ			0x3F
+#define GPIO_87_IRQ			0x40
+#define GPIO_88_IRQ			0x41
+#define GPIO_89_IRQ			0x42
+#define GPIO_90_IRQ			0x43
+#define GPIO_91_IRQ			0x44
+#define GPIO_97_IRQ			0x49
+#define GPIO_98_IRQ			0x4A
+#define GPIO_99_IRQ			0x4B
+#define GPIO_100_IRQ			0x4C
+#define GPIO_101_IRQ			0x4D
+#define GPIO_102_IRQ			0x4E
+#define GPIO_103_IRQ			0x4F
+#define GPIO_104_IRQ			0x50
+#define GPIO_105_IRQ			0x51
+#define GPIO_106_IRQ			0x52
+#define GPIO_109_IRQ			0x54
+#define GPIO_110_IRQ			0x55
+#define GPIO_111_IRQ			0x56
+#define GPIO_112_IRQ			0x57
+#define GPIO_113_IRQ			0x58
+#define GPIO_116_IRQ			0x5B
+#define GPIO_117_IRQ			0x5C
+#define GPIO_118_IRQ			0x5D
+#define GPIO_119_IRQ			0x5E
+#define GPIO_120_IRQ			0x5F
+#define GPIO_121_IRQ			0x60
+#define GPIO_122_IRQ			0x61
+#define GPIO_123_IRQ			0x62
+
+/* North community pads */
+#define GPIO_0_IRQ			0x63
+#define GPIO_1_IRQ			0x64
+#define GPIO_2_IRQ			0x65
+#define GPIO_3_IRQ			0x66
+#define GPIO_4_IRQ			0x67
+#define GPIO_5_IRQ			0x68
+#define GPIO_6_IRQ			0x69
+#define GPIO_7_IRQ			0x6A
+#define GPIO_8_IRQ			0x6B
+#define GPIO_9_IRQ			0x6C
+#define GPIO_10_IRQ			0x6D
+#define GPIO_11_IRQ			0x6E
+#define GPIO_12_IRQ			0x6F
+#define GPIO_13_IRQ			0x70
+#define GPIO_14_IRQ			0x71
+#define GPIO_15_IRQ			0x72
+#define GPIO_16_IRQ			0x73
+#define GPIO_17_IRQ			0x74
+#define GPIO_18_IRQ			0x75
+#define GPIO_19_IRQ			0x76
+#define GPIO_20_IRQ			0x77
+#define GPIO_21_IRQ			0x32
+#define GPIO_22_IRQ			0x33
+#define GPIO_23_IRQ			0x34
+#define GPIO_24_IRQ			0x35
+#define GPIO_25_IRQ			0x36
+#define GPIO_26_IRQ			0x37
+#define GPIO_27_IRQ			0x38
+#define GPIO_28_IRQ			0x39
+#define GPIO_29_IRQ			0x3A
+#define GPIO_30_IRQ			0x3B
+#define GPIO_31_IRQ			0x3C
+#define GPIO_32_IRQ			0x3D
+#define GPIO_33_IRQ			0x3E
+#define GPIO_34_IRQ			0x3F
+#define GPIO_35_IRQ			0x40
+#define GPIO_36_IRQ			0x41
+#define GPIO_37_IRQ			0x42
+#define GPIO_38_IRQ			0x43
+#define GPIO_39_IRQ			0x44
+#define GPIO_40_IRQ			0x45
+#define GPIO_41_IRQ			0x46
+#define GPIO_42_IRQ			0x47
+#define GPIO_43_IRQ			0x48
+#define GPIO_44_IRQ			0x49
+#define GPIO_45_IRQ			0x4A
+#define GPIO_46_IRQ			0x4B
+#define GPIO_47_IRQ			0x4C
+#define GPIO_48_IRQ			0x4D
+#define GPIO_49_IRQ			0x4E
+#define GPIO_62_IRQ			0x5B
+#define GPIO_63_IRQ			0x5C
+#define GPIO_64_IRQ			0x5D
+#define GPIO_65_IRQ			0x5E
+#define GPIO_66_IRQ			0x5F
+#define GPIO_67_IRQ			0x60
+#define GPIO_68_IRQ			0x61
+#define GPIO_69_IRQ			0x62
+#define GPIO_70_IRQ			0x63
+#define GPIO_71_IRQ			0x64
+#define GPIO_72_IRQ			0x65
+#define GPIO_73_IRQ			0x66
+
+#endif /* _ASM_ARCH_GPIO_H_ */
diff --git a/arch/x86/include/asm/arch-apollolake/iomap.h b/arch/x86/include/asm/arch-apollolake/iomap.h
new file mode 100644
index 0000000..4ce1017
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/iomap.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2017 Intel Corporation.
+ * Take from coreboot project file of the same name
+ */
+
+#ifndef _ASM_ARCH_IOMAP_H
+#define _ASM_ARCH_IOMAP_H
+
+#define R_ACPI_PM1_TMR			0x8
+
+/* Put p2sb at 0xd0000000 in TPL */
+#define IOMAP_P2SB_BAR		0xd0000000
+
+#define IOMAP_SPI_BASE		0xfe010000
+
+#define IOMAP_ACPI_BASE		0x400
+#define IOMAP_ACPI_SIZE		0x100
+
+/*
+ * Use UART2. To use UART1 you need to set '2' to '1', change device tree serial
+ * node name and 'reg' property, and update CONFIG_DEBUG_UART_BASE.
+ */
+#define PCH_DEV_UART		PCI_BDF(0, 0x18, 2)
+
+#define PCH_DEV_LPC		PCI_BDF(0, 0x1f, 0)
+#define PCH_DEV_SPI		PCI_BDF(0, 0x0d, 2)
+
+#endif
diff --git a/arch/x86/include/asm/arch-apollolake/itss.h b/arch/x86/include/asm/arch-apollolake/itss.h
new file mode 100644
index 0000000..1e29503
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/itss.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2017 Intel Corporation.
+ * Copyright 2019 Google LLC
+ *
+ * Modified from coreboot itss.h
+ */
+
+#ifndef _ASM_ARCH_ITSS_H
+#define _ASM_ARCH_ITSS_H
+
+#define GPIO_IRQ_START	50
+#define GPIO_IRQ_END	ITSS_MAX_IRQ
+
+#define ITSS_MAX_IRQ	119
+#define IRQS_PER_IPC	32
+#define NUM_IPC_REGS	((ITSS_MAX_IRQ + IRQS_PER_IPC - 1) / IRQS_PER_IPC)
+
+/* Max PXRC registers in ITSS */
+#define MAX_PXRC_CONFIG	(PCR_ITSS_PIRQH_ROUT - PCR_ITSS_PIRQA_ROUT + 1)
+
+/* PIRQA Routing Control Register */
+#define PCR_ITSS_PIRQA_ROUT	0x3100
+/* PIRQB Routing Control Register */
+#define PCR_ITSS_PIRQB_ROUT	0x3101
+/* PIRQC Routing Control Register */
+#define PCR_ITSS_PIRQC_ROUT	0x3102
+/* PIRQD Routing Control Register */
+#define PCR_ITSS_PIRQD_ROUT	0x3103
+/* PIRQE Routing Control Register */
+#define PCR_ITSS_PIRQE_ROUT	0x3104
+/* PIRQF Routing Control Register */
+#define PCR_ITSS_PIRQF_ROUT	0x3105
+/* PIRQG Routing Control Register */
+#define PCR_ITSS_PIRQG_ROUT	0x3106
+/* PIRQH Routing Control Register */
+#define PCR_ITSS_PIRQH_ROUT	0x3107
+/* ITSS Interrupt polarity control */
+#define PCR_ITSS_IPC0_CONF	0x3200
+/* ITSS Power reduction control */
+#define PCR_ITSS_ITSSPRC	0x3300
+
+#endif /* _ASM_ARCH_ITSS_H */
diff --git a/arch/x86/include/asm/arch-apollolake/lpc.h b/arch/x86/include/asm/arch-apollolake/lpc.h
new file mode 100644
index 0000000..5d2adad
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/lpc.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2017 Intel Corporation.
+ * Take from coreboot project file of the same name
+ */
+
+#ifndef _ASM_ARCH_LPC_H
+#define _ASM_ARCH_LPC_H
+
+#define LPC_SERIRQ_CTL			0x64
+#define  LPC_SCNT_EN			BIT(7)
+#define  LPC_SCNT_MODE			BIT(6)
+#define LPC_IO_DECODE			0x80
+#define  LPC_IOD_COMA_RANGE             (0 << 0) /* 0x3F8 - 0x3FF COMA*/
+#define  LPC_IOD_COMB_RANGE             (1 << 4) /* 0x2F8 - 0x2FF COMB*/
+/*
+ * Use IO_<peripheral>_<IO port> style macros defined in lpc_lib.h
+ * to enable decoding of I/O locations for a peripheral
+ */
+#define LPC_IO_ENABLES			0x82
+#define LPC_GENERIC_IO_RANGE(n)		((((n) & 0x3) * 4) + 0x84)
+#define  LPC_LGIR_AMASK_MASK		(0xfc << 16)
+#define  LPC_LGIR_ADDR_MASK		0xfffc
+#define  LPC_LGIR_EN			BIT(0)
+#define LPC_LGIR_MAX_WINDOW_SIZE	256
+#define LPC_GENERIC_MEM_RANGE		0x98
+#define  LPC_LGMR_ADDR_MASK		0xffff0000
+#define  LPC_LGMR_EN			BIT(0)
+#define LPC_LGMR_WINDOW_SIZE		(64 * KiB)
+#define LPC_BIOS_CNTL			0xdc
+#define  LPC_BC_BILD			BIT(7)
+#define  LPC_BC_LE			BIT(1)
+#define  LPC_BC_EISS			BIT(5)
+#define LPC_PCCTL			0xE0	/* PCI Clock Control */
+#define  LPC_PCCTL_CLKRUN_EN		BIT(0)
+
+/*
+ * IO decode enable macros are in the format IO_<peripheral>_<IO port>.
+ * For example, to open ports 0x60, 0x64 for the keyboard controller,
+ * use IOE_KBC_60_64 macro. For IOE_ macros that do not specify a port range,
+ * the port range is selectable via the IO decodes register.
+ */
+#define LPC_IOE_EC_4E_4F		BIT(13)
+#define LPC_IOE_SUPERIO_2E_2F		BIT(12)
+#define LPC_IOE_EC_62_66		BIT(11)
+#define LPC_IOE_KBC_60_64		BIT(10)
+#define LPC_IOE_HGE_208			BIT(9)
+#define LPC_IOE_LGE_200			BIT(8)
+#define LPC_IOE_FDD_EN			BIT(3)
+#define LPC_IOE_LPT_EN			BIT(2)
+#define LPC_IOE_COMB_EN			BIT(1)
+#define LPC_IOE_COMA_EN			BIT(0)
+#define LPC_NUM_GENERIC_IO_RANGES	4
+
+#define LPC_IO_ENABLES			0x82
+
+/**
+ * lpc_enable_fixed_io_ranges() - enable the fixed I/O ranges
+ *
+ * @io_enables: Mask of things to enable (LPC_IOE_.)
+ */
+void lpc_enable_fixed_io_ranges(uint io_enables);
+
+/**
+ * lpc_open_pmio_window() - Open an IO port range
+ *
+ * @base: Base I/O address (e.g. 0x800)
+ * @size: Size of window (e.g. 0x100)
+ * @return 0 if OK, -ENOSPC if there are no more windows available, -EALREADY
+ *	if already set up
+ */
+int lpc_open_pmio_window(uint base, uint size);
+
+/**
+ * lpc_io_setup_comm_a_b() - Set up basic serial UARTs
+ *
+ * Set up the LPC to handle I/O to the COMA/COMB serial UART addresses
+ * 2f8-2ff and 3f8-3ff.
+ */
+void lpc_io_setup_comm_a_b(void);
+
+#endif
diff --git a/arch/x86/include/asm/arch-apollolake/pch.h b/arch/x86/include/asm/arch-apollolake/pch.h
new file mode 100644
index 0000000..bf3e167
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/pch.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef _ASM_ARCH_PCH_H
+#define _ASM_ARCH_PCH_H
+
+#endif /* _ASM_ARCH_PCH_H */
diff --git a/arch/x86/include/asm/arch-apollolake/pm.h b/arch/x86/include/asm/arch-apollolake/pm.h
new file mode 100644
index 0000000..6718290
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/pm.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2015-2016 Intel Corp.
+ * (Written by Lance Zhao <lijian.zhao@intel.com> for Intel Corp.)
+ */
+
+#ifndef _ASM_ARCH_PM_H
+#define _ASM_ARCH_PM_H
+
+#define PMC_GPE_SW_31_0	0
+#define PMC_GPE_SW_63_32	1
+#define PMC_GPE_NW_31_0	3
+#define PMC_GPE_NW_63_32	4
+#define PMC_GPE_NW_95_64	5
+#define PMC_GPE_N_31_0		6
+#define PMC_GPE_N_63_32	7
+#define PMC_GPE_W_31_0		9
+
+#endif
diff --git a/arch/x86/include/asm/arch-apollolake/systemagent.h b/arch/x86/include/asm/arch-apollolake/systemagent.h
new file mode 100644
index 0000000..206d890
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/systemagent.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2017 Intel Corporation.
+ * Take from coreboot project file of the same name
+ */
+
+#ifndef _ASM_ARCH_SYSTEMAGENT_H
+#define _ASM_ARCH_SYSTEMAGENT_H
+
+/* Device 0:0.0 PCI configuration space */
+#define MCHBAR		0x48
+
+/* RAPL Package Power Limit register under MCHBAR */
+#define PUNIT_THERMAL_DEVICE_IRQ		0x700C
+#define PUINT_THERMAL_DEVICE_IRQ_VEC_NUMBER	0x18
+#define PUINT_THERMAL_DEVICE_IRQ_LOCK		0x80000000
+#define BIOS_RESET_CPL		0x7078
+#define   PCODE_INIT_DONE	BIT(8)
+#define MCHBAR_RAPL_PPL		0x70A8
+#define CORE_DISABLE_MASK	0x7168
+#define CAPID0_A		0xE4
+#define   VTD_DISABLE		BIT(23)
+#define DEFVTBAR		0x6c80
+#define GFXVTBAR		0x6c88
+#define   VTBAR_ENABLED		0x01
+#define VTBAR_MASK		GENMASK_ULL(39, 12)
+#define VTBAR_SIZE		0x1000
+
+/**
+ * enable_bios_reset_cpl() - Tell the system agent that memory/power are ready
+ *
+ * This should be called when U-Boot has set up the memory and power
+ * management.
+ */
+void enable_bios_reset_cpl(void);
+
+#endif
diff --git a/arch/x86/include/asm/arch-apollolake/uart.h b/arch/x86/include/asm/arch-apollolake/uart.h
new file mode 100644
index 0000000..d4fffe6
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/uart.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef _ASM_ARCH_UART_H
+#define _ASM_ARCH_UART_H
+
+/**
+ * apl_uart_init() - Set up the APL UART device and clock
+ *
+ * This enables the PCI device, sets up the MMIO region and turns on the clock
+ * using LPSS.
+ *
+ * The UART won't actually work unless the GPIO settings are correct and the
+ * signals actually exit the SoC. See board_debug_uart_init() for that.
+ */
+int apl_uart_init(pci_dev_t bdf, ulong base);
+
+#endif
diff --git a/arch/x86/include/asm/arch-broadwell/cpu.h b/arch/x86/include/asm/arch-broadwell/cpu.h
index 3bc3bd6..2b39a76 100644
--- a/arch/x86/include/asm/arch-broadwell/cpu.h
+++ b/arch/x86/include/asm/arch-broadwell/cpu.h
@@ -27,7 +27,6 @@
 
 #define MSR_VR_CURRENT_CONFIG		0x601
 #define MSR_VR_MISC_CONFIG		0x603
-#define MSR_PKG_POWER_SKU		0x614
 #define MSR_DDR_RAPL_LIMIT		0x618
 #define MSR_VR_MISC_CONFIG2		0x636
 
diff --git a/arch/x86/include/asm/arch-ivybridge/model_206ax.h b/arch/x86/include/asm/arch-ivybridge/model_206ax.h
index 4839ebc..5c06629 100644
--- a/arch/x86/include/asm/arch-ivybridge/model_206ax.h
+++ b/arch/x86/include/asm/arch-ivybridge/model_206ax.h
@@ -43,7 +43,6 @@
 #define MSR_PP1_CURRENT_CONFIG		0x602
 #define  PP1_CURRENT_LIMIT_SNB		(35 << 3) /* 35 A */
 #define  PP1_CURRENT_LIMIT_IVB		(50 << 3) /* 50 A */
-#define MSR_PKG_POWER_SKU		0x614
 
 #define IVB_CONFIG_TDP_MIN_CPUID	0x306a2
 #define MSR_CONFIG_TDP_LEVEL1		0x649
diff --git a/arch/x86/include/asm/fast_spi.h b/arch/x86/include/asm/fast_spi.h
new file mode 100644
index 0000000..6894298
--- /dev/null
+++ b/arch/x86/include/asm/fast_spi.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2017 Intel Corporation.
+ */
+
+#ifndef ASM_FAST_SPI_H
+#define ASM_FAST_SPI_H
+
+/* Register offsets from the MMIO region base (PCI_BASE_ADDRESS_0) */
+struct fast_spi_regs {
+	u32 bfp;
+	u32 hsfsts_ctl;
+	u32 faddr;
+	u32 dlock;
+
+	u32 fdata[0x10];
+
+	u32 fracc;
+	u32 freg[12];
+	u32 fpr[5];
+	u32 gpr0;
+	u32 spare2;
+	u32 sts_ctl;
+	u16 preop;
+	u16 optype;
+	u8 opmenu[8];
+
+	u32 spare3;
+	u32 fdoc;
+	u32 fdod;
+	u32 spare4;
+	u32 afc;
+	u32 vscc[2];
+	u32 ptinx;
+	u32 ptdata;
+};
+check_member(fast_spi_regs, ptdata, 0xd0);
+
+/* Bit definitions for BFPREG (0x00) register */
+#define SPIBAR_BFPREG_PRB_MASK		0x7fff
+#define SPIBAR_BFPREG_PRL_SHIFT		16
+#define SPIBAR_BFPREG_PRL_MASK		(0x7fff << SPIBAR_BFPREG_PRL_SHIFT)
+
+/* PCI configuration registers */
+#define SPIBAR_BIOS_CONTROL			0xdc
+#define SPIBAR_BIOS_CONTROL_WPD			BIT(0)
+#define SPIBAR_BIOS_CONTROL_LOCK_ENABLE		BIT(1)
+#define SPIBAR_BIOS_CONTROL_CACHE_DISABLE	BIT(2)
+#define SPIBAR_BIOS_CONTROL_PREFETCH_ENABLE	BIT(3)
+#define SPIBAR_BIOS_CONTROL_EISS		BIT(5)
+#define SPIBAR_BIOS_CONTROL_BILD		BIT(7)
+
+/**
+ * fast_spi_get_bios_mmap() - Get memory map for SPI flash
+ *
+ * @pdev:	PCI device to use (this is the Fast SPI device)
+ * @map_basep:	Returns base memory address for mapped SPI
+ * @map_sizep:	Returns size of mapped SPI
+ * @offsetp:	Returns start offset of SPI flash where the map works
+ *	correctly (offsets before this are not visible)
+ * @return 0 (always)
+ */
+int fast_spi_get_bios_mmap(pci_dev_t pdev, ulong *map_basep, uint *map_sizep,
+			   uint *offsetp);
+
+int fast_spi_early_init(pci_dev_t pdev, ulong mmio_base);
+
+#endif	/* ASM_FAST_SPI_H */
diff --git a/arch/x86/include/asm/fsp/fsp_api.h b/arch/x86/include/asm/fsp/fsp_api.h
new file mode 100644
index 0000000..e9ac86b
--- /dev/null
+++ b/arch/x86/include/asm/fsp/fsp_api.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef __ASM_FSP_API_H
+#define __ASM_FSP_API_H
+
+enum fsp_phase {
+	/* Notification code for post PCI enuermation */
+	INIT_PHASE_PCI	= 0x20,
+	/* Notification code before transferring control to the payload */
+	INIT_PHASE_BOOT	= 0x40
+};
+
+struct fsp_notify_params {
+	/* Notification phase used for NotifyPhase API */
+	enum fsp_phase	phase;
+};
+
+/* FspNotify API function prototype */
+typedef asmlinkage u32 (*fsp_notify_f)(struct fsp_notify_params *params);
+
+#endif
diff --git a/arch/x86/include/asm/fsp/fsp_support.h b/arch/x86/include/asm/fsp/fsp_support.h
index 4ac27d2..29e5114 100644
--- a/arch/x86/include/asm/fsp/fsp_support.h
+++ b/arch/x86/include/asm/fsp/fsp_support.h
@@ -144,13 +144,6 @@
 int fsp_scan_for_ram_size(void);
 
 /**
- * fsp_prepare_mrc_cache() - Find the DRAM training data from the MRC cache
- *
- * @return pointer to data, or NULL if no cache or no data found in the cache
- */
-void *fsp_prepare_mrc_cache(void);
-
-/**
  * fsp_notify() - FSP notification wrapper function
  *
  * @fsp_hdr: Pointer to FSP information header
diff --git a/arch/x86/include/asm/fsp1/fsp_api.h b/arch/x86/include/asm/fsp1/fsp_api.h
index f2d7079..524da5f 100644
--- a/arch/x86/include/asm/fsp1/fsp_api.h
+++ b/arch/x86/include/asm/fsp1/fsp_api.h
@@ -4,11 +4,11 @@
  * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
  */
 
-#ifndef __FSP_API_H__
-#define __FSP_API_H__
+#ifndef __FSP1_API_H__
+#define __FSP1_API_H__
 
 #include <linux/linkage.h>
-
+#include <asm/fsp/fsp_api.h>
 /*
  * FSP common configuration structure.
  * This needs to be included in the platform-specific struct fsp_config_data.
@@ -46,22 +46,7 @@
 	u32	reserved[6];	/* Reserved */
 };
 
-enum fsp_phase {
-	/* Notification code for post PCI enuermation */
-	INIT_PHASE_PCI	= 0x20,
-	/* Notification code before transfering control to the payload */
-	INIT_PHASE_BOOT	= 0x40
-};
-
-struct fsp_notify_params {
-	/* Notification phase used for NotifyPhase API */
-	enum fsp_phase	phase;
-};
-
 /* FspInit API function prototype */
 typedef asmlinkage u32 (*fsp_init_f)(struct fsp_init_params *params);
 
-/* FspNotify API function prototype */
-typedef asmlinkage u32 (*fsp_notify_f)(struct fsp_notify_params *params);
-
 #endif
diff --git a/arch/x86/include/asm/fsp2/fsp_api.h b/arch/x86/include/asm/fsp2/fsp_api.h
new file mode 100644
index 0000000..af1e885
--- /dev/null
+++ b/arch/x86/include/asm/fsp2/fsp_api.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: Intel */
+/*
+ * Copyright (C) 2015-2016 Intel Corp.
+ * (Written by Andrey Petrov <andrey.petrov@intel.com> for Intel Corp.)
+ * (Written by Alexandru Gagniuc <alexandrux.gagniuc@intel.com> for Intel Corp.)
+ * Mostly taken from coreboot fsp2_0/memory_init.c
+ */
+
+#ifndef __ASM_FSP2_API_H
+#define __ASM_FSP2_API_H
+
+#include <asm/fsp/fsp_api.h>
+
+struct fspm_upd;
+struct fsps_upd;
+struct hob_header;
+
+enum fsp_boot_mode {
+	FSP_BOOT_WITH_FULL_CONFIGURATION = 0x00,
+	FSP_BOOT_WITH_MINIMAL_CONFIGURATION = 0x01,
+	FSP_BOOT_ASSUMING_NO_CONFIGURATION_CHANGES = 0x02,
+	FSP_BOOT_ON_S4_RESUME = 0x05,
+	FSP_BOOT_ON_S3_RESUME = 0x11,
+	FSP_BOOT_ON_FLASH_UPDATE = 0x12,
+	FSP_BOOT_IN_RECOVERY_MODE = 0x20
+};
+
+struct __packed fsp_upd_header {
+	u64	signature;
+	u8	revision;
+	u8	reserved[23];
+};
+
+/**
+ * fsp_memory_init() - Init the SDRAM
+ *
+ * @s3wake: true if we are booting from resume, so cannot reinit the mememory
+ *	from scatch since we will lose its contents
+ * @use_spi_flash: true to use the fast SPI driver to read FSP, otherwise use
+ *	mapped SPI
+ * @return 0 if OK, -ve on error
+ */
+int fsp_memory_init(bool s3wake, bool use_spi_flash);
+
+typedef asmlinkage int (*fsp_memory_init_func)(struct fspm_upd *params,
+					       struct hob_header **hobp);
+
+/**
+ * fsp_silicon_init() - Init the silicon
+ *
+ * This calls the FSP's 'silicon init' entry point
+ *
+ * @s3wake: true if we are booting from resume, so cannot reinit the mememory
+ *	from scatch since we will lose its contents
+ * @use_spi_flash: true to use the fast SPI driver to read FSP, otherwise use
+ *	mapped SPI
+ * @return 0 if OK, -ve on error
+ */
+int fsp_silicon_init(bool s3wake, bool use_spi_flash);
+
+typedef asmlinkage int (*fsp_silicon_init_func)(struct fsps_upd *params);
+
+#endif
diff --git a/arch/x86/include/asm/fsp2/fsp_internal.h b/arch/x86/include/asm/fsp2/fsp_internal.h
new file mode 100644
index 0000000..f751fbf
--- /dev/null
+++ b/arch/x86/include/asm/fsp2/fsp_internal.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: Intel */
+/*
+ * Copyright (C) 2015-2016 Intel Corp.
+ * (Written by Alexandru Gagniuc <alexandrux.gagniuc@intel.com> for Intel Corp.)
+ * Mostly taken from coreboot
+ */
+
+#ifndef __ASM_FSP_INTERNAL_H
+#define __ASM_FSP_INTERNAL_H
+
+struct binman_entry;
+struct fsp_header;
+struct fspm_upd;
+struct fsps_upd;
+
+enum fsp_type_t {
+	FSP_M,
+	FSP_S,
+};
+
+int fsp_get_header(ulong offset, ulong size, bool use_spi_flash,
+		   struct fsp_header **fspp);
+
+/**
+ * fsp_locate_fsp() - Locate an FSP component
+ *
+ * This finds an FSP component by various methods. It is not as general-purpose
+ * as it looks, since it expects FSP-M to be requested in SPL (only), and FSP-S
+ * to be requested in U-Boot proper.
+ *
+ * @type: Component to locate
+ * @entry: Returns location of component
+ * @use_spi_flash: true to read using the Fast SPI driver, false to use
+ *	memory-mapped SPI flash
+ * @devp: Returns northbridge device
+ * @hdrp: Returns FSP header
+ * @rom_offsetp: If non-NULL, returns the offset to add to any image position to
+ *	find the memory-mapped location of that position. For example, for ROM
+ *	position 0x1000, it will be mapped into 0x1000 + *rom_offsetp.
+ */
+int fsp_locate_fsp(enum fsp_type_t type, struct binman_entry *entry,
+		   bool use_spi_flash, struct udevice **devp,
+		   struct fsp_header **hdrp, ulong *rom_offsetp);
+
+/**
+ * arch_fsps_preinit() - Perform init needed before calling FSP-S
+ *
+ * This allows use of probed drivers and PCI so is a convenient place to do any
+ * init that is needed before FSP-S is called. After this, U-Boot relocates and
+ * calls arch_fsp_init_r() before PCI is probed, and that function is not
+ * allowed to probe PCI before calling FSP-S.
+ */
+int arch_fsps_preinit(void);
+
+/**
+ * fspm_update_config() - Set up the config structure for FSP-M
+ *
+ * @dev: Hostbridge device containing config
+ * @upd: Config data to fill in
+ * @return 0 if OK, -ve on error
+ */
+int fspm_update_config(struct udevice *dev, struct fspm_upd *upd);
+
+/**
+ * fspm_done() - Indicate that memory init is complete
+ *
+ * This allows the board to do whatever post-init it needs before things
+ * continue.
+ *
+ * @dev: Hostbridge device
+ * @return 0 if OK, -ve on error
+ */
+int fspm_done(struct udevice *dev);
+
+/**
+ * fsps_update_config() - Set up the config structure for FSP-S
+ *
+ * @dev: Hostbridge device containing config
+ * @rom_offset: Value to add to convert from ROM offset to memory-mapped address
+ * @upd: Config data to fill in
+ * @return 0 if OK, -ve on error
+ */
+int fsps_update_config(struct udevice *dev, ulong rom_offset,
+		       struct fsps_upd *upd);
+
+/**
+ * prepare_mrc_cache() - Read the MRC cache into the product-data struct
+ *
+ * This looks for cached Memory-reference code (MRC) data and stores it into
+ * @upd for use by the FSP-M binary.
+ *
+ * @return 0 if OK, -ENOENT if no data (whereupon the caller can continue and
+ *	expect a slower boot), other -ve value on other error
+ */
+int prepare_mrc_cache(struct fspm_upd *upd);
+
+#endif
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h
index 7f3ada0..f4c1839 100644
--- a/arch/x86/include/asm/global_data.h
+++ b/arch/x86/include/asm/global_data.h
@@ -10,6 +10,7 @@
 #ifndef __ASSEMBLY__
 
 #include <asm/processor.h>
+#include <asm/mrccache.h>
 
 enum pei_boot_mode_t {
 	PEI_BOOT_NONE = 0,
@@ -66,6 +67,21 @@
 	uint64_t size;
 };
 
+/**
+ * struct mrc_output - holds the MRC data
+ *
+ * @buf: MRC training data to save for the next boot. This is set to point to
+ *	the raw data after SDRAM init is complete. Then mrccache_setup()
+ *	turns it into a proper cache record with a checksum
+ * @len: Length of @buf
+ * @cache: Resulting cache record
+ */
+struct mrc_output {
+	char *buf;
+	uint len;
+	struct mrc_data_container *cache;
+};
+
 /* Architecture-specific global data */
 struct arch_global_data {
 	u64 gdt[X86_GDT_NUM_ENTRIES] __aligned(16);
@@ -90,12 +106,12 @@
 	struct mtrr_request mtrr_req[MAX_MTRR_REQUESTS];
 	int mtrr_req_count;
 	int has_mtrr;
-	/* MRC training data to save for the next boot */
-	char *mrc_output;
-	unsigned int mrc_output_len;
+	/* MRC training data */
+	struct mrc_output mrc[MRC_TYPE_COUNT];
 	ulong table;			/* Table pointer from previous loader */
 	int turbo_state;		/* Current turbo state */
 	struct irq_routing_table *pirq_routing_table;
+	int dw_i2c_num_cards;		/* Used by designware i2c driver */
 #ifdef CONFIG_SEABIOS
 	u32 high_table_ptr;
 	u32 high_table_limit;
@@ -104,6 +120,9 @@
 	int prev_sleep_state;		/* Previous sleep state ACPI_S0/1../5 */
 	ulong backup_mem;		/* Backup memory address for S3 */
 #endif
+#ifdef CONFIG_FSP_VERSION2
+	struct fsp_header *fsp_s_hdr;	/* Pointer to FSP-S header */
+#endif
 };
 
 #endif
diff --git a/arch/x86/include/asm/intel_pinctrl.h b/arch/x86/include/asm/intel_pinctrl.h
new file mode 100644
index 0000000..72fd924
--- /dev/null
+++ b/arch/x86/include/asm/intel_pinctrl.h
@@ -0,0 +1,306 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2017 Intel Corporation.
+ * Copyright 2019 Google LLC
+ *
+ * Modified from coreboot gpio.h
+ */
+
+#ifndef __ASM_INTEL_PINCTRL_H
+#define __ASM_INTEL_PINCTRL_H
+
+#include <dm/pinctrl.h>
+
+/**
+ * struct pad_config - config for a pad
+ * @pad: offset of pad within community
+ * @pad_config: Pad config data corresponding to DW0, DW1, etc.
+ */
+struct pad_config {
+	int pad;
+	u32 pad_config[4];
+};
+
+#include <asm/arch/gpio.h>
+
+/* GPIO community IOSF sideband clock gating */
+#define MISCCFG_GPSIDEDPCGEN	BIT(5)
+/* GPIO community RCOMP clock gating */
+#define MISCCFG_GPRCOMPCDLCGEN	BIT(4)
+/* GPIO community RTC clock gating */
+#define MISCCFG_GPRTCDLCGEN	BIT(3)
+/* GFX controller clock gating */
+#define MISCCFG_GSXSLCGEN	BIT(2)
+/* GPIO community partition clock gating */
+#define MISCCFG_GPDPCGEN	BIT(1)
+/* GPIO community local clock gating */
+#define MISCCFG_GPDLCGEN	BIT(0)
+/* Enable GPIO community power management configuration */
+#define MISCCFG_ENABLE_GPIO_PM_CONFIG (MISCCFG_GPSIDEDPCGEN | \
+	MISCCFG_GPRCOMPCDLCGEN | MISCCFG_GPRTCDLCGEN | MISCCFG_GSXSLCGEN \
+	| MISCCFG_GPDPCGEN | MISCCFG_GPDLCGEN)
+
+/*
+ * GPIO numbers may not be contiguous and instead will have a different
+ * starting pin number for each pad group.
+ */
+#define INTEL_GPP_BASE(first_of_community, start_of_group, end_of_group,\
+			group_pad_base)					\
+	{								\
+		.first_pad = (start_of_group) - (first_of_community),	\
+		.size = (end_of_group) - (start_of_group) + 1,		\
+		.acpi_pad_base = (group_pad_base),			\
+	}
+
+/*
+ * A pad base of -1 indicates that this group uses contiguous numbering
+ * and a pad base should not be used for this group.
+ */
+#define PAD_BASE_NONE	-1
+
+/* The common/default group numbering is contiguous */
+#define INTEL_GPP(first_of_community, start_of_group, end_of_group)	\
+	INTEL_GPP_BASE(first_of_community, start_of_group, end_of_group,\
+		       PAD_BASE_NONE)
+
+/**
+ * struct reset_mapping - logical to actual value for PADRSTCFG in DW0
+ *
+ * Note that the values are expected to be within the field placement of the
+ * register itself. i.e. if the reset field is at 31:30 then the values within
+ * logical and chipset should occupy 31:30.
+ */
+struct reset_mapping {
+	u32 logical;
+	u32 chipset;
+};
+
+/**
+ * struct pad_group - describes the groups within each community
+ *
+ * @first_pad: offset of first pad of the group relative to the community
+ * @size: size of the group
+ * @acpi_pad_base: starting pin number for the pads in this group when they are
+ *	used in ACPI.  This is only needed if the pins are not contiguous across
+ *	groups. Most groups will have this set to PAD_BASE_NONE and use
+ *	contiguous numbering for ACPI.
+ */
+struct pad_group {
+	int first_pad;
+	uint size;
+	int acpi_pad_base;
+};
+
+/**
+ * struct pad_community - community of pads
+ *
+ * This describes a community, or each group within a community when multiple
+ * groups exist inside a community
+ *
+ * @name: Community name
+ * @acpi_path: ACPI path
+ * @num_gpi_regs: number of gpi registers in community
+ * @max_pads_per_group: number of pads in each group; number of pads bit-mapped
+ *	in each GPI status/en and Host Own Reg
+ * @first_pad: first pad in community
+ * @last_pad: last pad in community
+ * @host_own_reg_0: offset to Host Ownership Reg 0
+ * @gpi_int_sts_reg_0: offset to GPI Int STS Reg 0
+ * @gpi_int_en_reg_0: offset to GPI Int Enable Reg 0
+ * @gpi_smi_sts_reg_0: offset to GPI SMI STS Reg 0
+ * @gpi_smi_en_reg_0: offset to GPI SMI EN Reg 0
+ * @pad_cfg_base: offset to first PAD_GFG_DW0 Reg
+ * @gpi_status_offset: specifies offset in struct gpi_status
+ * @port: PCR Port ID
+ * @reset_map: PADRSTCFG logical to chipset mapping
+ * @num_reset_vals: number of values in @reset_map
+ * @groups; list of groups for this community
+ * @num_groups: number of groups
+ */
+struct pad_community {
+	const char *name;
+	const char *acpi_path;
+	size_t num_gpi_regs;
+	size_t max_pads_per_group;
+	uint first_pad;
+	uint last_pad;
+	u16 host_own_reg_0;
+	u16 gpi_int_sts_reg_0;
+	u16 gpi_int_en_reg_0;
+	u16 gpi_smi_sts_reg_0;
+	u16 gpi_smi_en_reg_0;
+	u16 pad_cfg_base;
+	u8 gpi_status_offset;
+	u8 port;
+	const struct reset_mapping *reset_map;
+	size_t num_reset_vals;
+	const struct pad_group *groups;
+	size_t num_groups;
+};
+
+/**
+ * struct intel_pinctrl_priv - private data for each pinctrl device
+ *
+ * @comm: Pad community for this device
+ * @num_cfgs: Number of configuration words for each pad
+ * @itss: ITSS device (for interrupt handling)
+ * @itss_pol_cfg: Use to program Interrupt Polarity Control (IPCx) register
+ *	Each bit represents IRQx Active High Polarity Disable configuration:
+ *	when set to 1, the interrupt polarity associated with IRQx is inverted
+ *	to appear as Active Low to IOAPIC and vice versa
+ */
+struct intel_pinctrl_priv {
+	const struct pad_community *comm;
+	int num_cfgs;
+	struct udevice *itss;
+	bool itss_pol_cfg;
+};
+
+/* Exported common operations for the pinctrl driver */
+extern const struct pinctrl_ops intel_pinctrl_ops;
+
+/* Exported common probe function for the pinctrl driver */
+int intel_pinctrl_probe(struct udevice *dev);
+
+/**
+ * intel_pinctrl_ofdata_to_platdata() - Handle common platdata setup
+ *
+ * @dev: Pinctrl device
+ * @comm: Pad community for this device
+ * @num_cfgs: Number of configuration words for each pad
+ * @return 0 if OK, -EDOM if @comm is NULL, other -ve value on other error
+ */
+int intel_pinctrl_ofdata_to_platdata(struct udevice *dev,
+				     const struct pad_community *comm,
+				     int num_cfgs);
+
+/**
+ * pinctrl_route_gpe() - set GPIO groups for the general-purpose-event blocks
+ *
+ * The values from PMC register GPE_CFG are passed which is then mapped to
+ * proper groups for MISCCFG. This basically sets the MISCCFG register bits:
+ *  dw0 = gpe0_route[11:8]. This is ACPI GPE0b.
+ *  dw1 = gpe0_route[15:12]. This is ACPI GPE0c.
+ *  dw2 = gpe0_route[19:16]. This is ACPI GPE0d.
+ *
+ * @dev: ITSS device
+ * @gpe0b: Value for GPE0B
+ * @gpe0c: Value for GPE0C
+ * @gpe0d: Value for GPE0D
+ * @return 0 if OK, -ve on error
+ */
+int pinctrl_route_gpe(struct udevice *dev, uint gpe0b, uint gpe0c, uint gpe0d);
+
+/**
+ * pinctrl_config_pads() - Configure a list of pads
+ *
+ * Configures multiple pads using the provided data from the device tree.
+ *
+ * @dev: pinctrl device (any will do)
+ * @pads: Pad data, consisting of a pad number followed by num_cfgs entries
+ *	containing the data for that pad (num_cfgs is set by the pinctrl device)
+ * @pads_count: Number of pads to configure
+ * @return 0 if OK, -ve on error
+ */
+int pinctrl_config_pads(struct udevice *dev, u32 *pads, int pads_count);
+
+/**
+ * pinctrl_gpi_clear_int_cfg() - Set up the interrupts for use
+ *
+ * This enables the interrupt inputs and clears the status register bits
+ *
+ * @return 0 if OK, -ve on error
+ */
+int pinctrl_gpi_clear_int_cfg(void);
+
+/**
+ * pinctrl_config_pads_for_node() - Configure pads
+ *
+ * Set up the pads using the data in a given node
+ *
+ * @dev: pinctrl device (any will do)
+ * @node: Node containing the 'pads' property with the data in it
+ * @return 0 if OK, -ve on error
+ */
+int pinctrl_config_pads_for_node(struct udevice *dev, ofnode node);
+
+/**
+ * pinctrl_read_pads() - Read pad data from a node
+ *
+ * @dev: pinctrl device (any will do, it is just used to get config)
+ * @node: Node to read pad data from
+ * @prop: Property name to use (e.g. "pads")
+ * @padsp: Returns a pointer to an allocated array of pad data, in the format:
+ *	<pad>
+ *	<pad_config0>
+ *	<pad_config1>
+ *	...
+ *
+ *	The number of pad config values is set by the pinctrl controller.
+ *	The caller must free this array.
+ * @pad_countp: Returns the number of pads read
+ * @ereturn 0 if OK, -ve on error
+ */
+int pinctrl_read_pads(struct udevice *dev, ofnode node, const char *prop,
+		      u32 **padsp, int *pad_countp);
+
+/**
+ * pinctrl_count_pads() - Count the number of pads in a pad array
+ *
+ * This used used with of-platdata where the array may be smaller than its
+ * maximum size. This function searches for the last pad in the array by finding
+ * the first 'zero' record
+ *
+ * This works out the number of records in the array. Each record has one word
+ * for the pad and num_cfgs words for the config.
+ *
+ * @dev: pinctrl device (any will do)
+ * @pads: Array of pad data
+ * @size: Size of pad data in bytes
+ * @return number of pads represented by the data
+ */
+int pinctrl_count_pads(struct udevice *dev, u32 *pads, int size);
+
+/**
+ * intel_pinctrl_get_config_reg_addr() - Get address of the pin config registers
+ *
+ * @dev: Pinctrl device
+ * @offset: GPIO offset within this device
+ * @return register offset within the GPIO p2sb region
+ */
+u32 intel_pinctrl_get_config_reg_addr(struct udevice *dev, uint offset);
+
+/**
+ * intel_pinctrl_get_config_reg() - Get the value of a GPIO register
+ *
+ * @dev: Pinctrl device
+ * @offset: GPIO offset within this device
+ * @return register value within the GPIO p2sb region
+ */
+u32 intel_pinctrl_get_config_reg(struct udevice *dev, uint offset);
+
+/**
+ * intel_pinctrl_get_pad() - Get pad information for a pad
+ *
+ * This is used by the GPIO controller to find the pinctrl used by a pad.
+ *
+ * @pad: Pad to check
+ * @devp: Returns pinctrl device containing that pad
+ * @offsetp: Returns offset of pad within that pinctrl device
+ */
+int intel_pinctrl_get_pad(uint pad, struct udevice **devp, uint *offsetp);
+
+/**
+ * intel_pinctrl_get_acpi_pin() - Get the ACPI pin for a pinctrl pin
+ *
+ * Maps a pinctrl pin (in terms of its offset within the pins controlled by that
+ * pinctrl) to an ACPI GPIO pin-table entry.
+ *
+ * @dev: Pinctrl device to check
+ * @offset: Offset of pin within that device (0 = first)
+ * @return associated ACPI GPIO pin-table entry, or standard pin number if the
+ *	ACPI pad base is not set
+ */
+int intel_pinctrl_get_acpi_pin(struct udevice *dev, uint offset);
+
+#endif
diff --git a/arch/x86/include/asm/intel_pinctrl_defs.h b/arch/x86/include/asm/intel_pinctrl_defs.h
new file mode 100644
index 0000000..6da06bb
--- /dev/null
+++ b/arch/x86/include/asm/intel_pinctrl_defs.h
@@ -0,0 +1,373 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2015-2016 Intel Corp.
+ * Copyright 2019 Google LLC
+ *
+ * Modified from coreboot gpio_defs.h
+ */
+
+#ifndef _ASM_INTEL_PINCTRL_DEFS_H_
+#define _ASM_INTEL_PINCTRL_DEFS_H_
+
+/* This file is included by device trees, so avoid BIT() macros */
+
+#define PAD_CFG0_TX_STATE_BIT		0
+#define PAD_CFG0_TX_STATE		(1 << PAD_CFG0_TX_STATE_BIT)
+#define PAD_CFG0_RX_STATE_BIT		1
+#define PAD_CFG0_RX_STATE		(1 << PAD_CFG0_RX_STATE_BIT)
+#define PAD_CFG0_TX_DISABLE		(1 << 8)
+#define PAD_CFG0_RX_DISABLE		(1 << 9)
+
+#define PAD_CFG0_MODE_SHIFT		10
+#define PAD_CFG0_MODE_MASK		(7 << PAD_CFG0_MODE_SHIFT)
+#define  PAD_CFG0_MODE_GPIO		(0 << PAD_CFG0_MODE_SHIFT)
+#define  PAD_CFG0_MODE_NF1		(1 << PAD_CFG0_MODE_SHIFT)
+#define  PAD_CFG0_MODE_NF2		(2 << PAD_CFG0_MODE_SHIFT)
+#define  PAD_CFG0_MODE_NF3		(3 << PAD_CFG0_MODE_SHIFT)
+#define  PAD_CFG0_MODE_NF4		(4 << PAD_CFG0_MODE_SHIFT)
+#define  PAD_CFG0_MODE_NF5		(5 << PAD_CFG0_MODE_SHIFT)
+#define  PAD_CFG0_MODE_NF6		(6 << PAD_CFG0_MODE_SHIFT)
+
+#define PAD_CFG0_ROUTE_MASK		(0xf << 17)
+#define  PAD_CFG0_ROUTE_NMI		(1 << 17)
+#define  PAD_CFG0_ROUTE_SMI		(1 << 18)
+#define  PAD_CFG0_ROUTE_SCI		(1 << 19)
+#define  PAD_CFG0_ROUTE_IOAPIC		(1 << 20)
+#define PAD_CFG0_RXTENCFG_MASK		(3 << 21)
+#define PAD_CFG0_RXINV_MASK		(1 << 23)
+#define  PAD_CFG0_RX_POL_INVERT		(1 << 23)
+#define  PAD_CFG0_RX_POL_NONE		(0 << 23)
+#define  PAD_CFG0_PREGFRXSEL		(1 << 24)
+#define PAD_CFG0_TRIG_MASK		(3 << 25)
+#define  PAD_CFG0_TRIG_LEVEL		(0 << 25)
+#define  PAD_CFG0_TRIG_EDGE_SINGLE	(1 << 25) /* controlled by RX_INVERT*/
+#define  PAD_CFG0_TRIG_OFF		(2 << 25)
+#define  PAD_CFG0_TRIG_EDGE_BOTH	(3 << 25)
+#define PAD_CFG0_RXRAW1_MASK		(1 << 28)
+#define PAD_CFG0_RXPADSTSEL_MASK	(1 << 29)
+#define PAD_CFG0_RESET_MASK		(3 << 30)
+#define  PAD_CFG0_LOGICAL_RESET_PWROK	(0U << 30)
+#define  PAD_CFG0_LOGICAL_RESET_DEEP	(1U << 30)
+#define  PAD_CFG0_LOGICAL_RESET_PLTRST	(2U << 30)
+#define  PAD_CFG0_LOGICAL_RESET_RSMRST	(3U << 30)
+
+/*
+ * Use the fourth bit in IntSel field to indicate gpio ownership. This field is
+ * RO and hence not used during gpio configuration.
+ */
+#define PAD_CFG1_GPIO_DRIVER		(0x1 << 4)
+#define PAD_CFG1_IRQ_MASK		(0xff << 0)
+#define PAD_CFG1_IOSTERM_MASK		(0x3 << 8)
+#define PAD_CFG1_IOSTERM_SAME		(0x0 << 8)
+#define PAD_CFG1_IOSTERM_DISPUPD	(0x1 << 8)
+#define PAD_CFG1_IOSTERM_ENPD		(0x2 << 8)
+#define PAD_CFG1_IOSTERM_ENPU		(0x3 << 8)
+#define PAD_CFG1_PULL_MASK		(0xf << 10)
+#define  PAD_CFG1_PULL_NONE		(0x0 << 10)
+#define  PAD_CFG1_PULL_DN_5K		(0x2 << 10)
+#define  PAD_CFG1_PULL_DN_20K		(0x4 << 10)
+#define  PAD_CFG1_PULL_UP_1K		(0x9 << 10)
+#define  PAD_CFG1_PULL_UP_5K		(0xa << 10)
+#define  PAD_CFG1_PULL_UP_2K		(0xb << 10)
+#define  PAD_CFG1_PULL_UP_20K		(0xc << 10)
+#define  PAD_CFG1_PULL_UP_667		(0xd << 10)
+#define  PAD_CFG1_PULL_NATIVE		(0xf << 10)
+
+/* Tx enabled driving last value driven, Rx enabled */
+#define PAD_CFG1_IOSSTATE_TX_LAST_RXE	(0x0 << 14)
+/*
+ * Tx enabled driving 0, Rx disabled and Rx driving 0 back to its controller
+ * internally
+ */
+#define PAD_CFG1_IOSSTATE_TX0_RX_DCR_X0	(0x1 << 14)
+/*
+ * Tx enabled driving 0, Rx disabled and Rx driving 1 back to its controller
+ * internally
+ */
+#define PAD_CFG1_IOSSTATE_TX0_RX_DCR_X1	(0x2 << 14)
+/*
+ * Tx enabled driving 1, Rx disabled and Rx driving 0 back to its controller
+ * internally
+ */
+#define PAD_CFG1_IOSSTATE_TX1_RX_DCR_X0	(0x3 << 14)
+/*
+ * Tx enabled driving 1, Rx disabled and Rx driving 1 back to its controller
+ * internally
+ */
+#define PAD_CFG1_IOSSTATE_TX1_RX_DCR_X1	(0x4 << 14)
+/* Tx enabled driving 0, Rx enabled */
+#define PAD_CFG1_IOSSTATE_TX0_RXE	(0x5 << 14)
+/* Tx enabled driving 1, Rx enabled */
+#define PAD_CFG1_IOSSTATE_TX1_RXE	(0x6 << 14)
+/* Hi-Z, Rx driving 0 back to its controller internally */
+#define PAD_CFG1_IOSSTATE_HIZCRX0	(0x7 << 14)
+/* Hi-Z, Rx driving 1 back to its controller internally */
+#define PAD_CFG1_IOSSTATE_HIZCRX1	(0x8 << 14)
+/* Tx disabled, Rx enabled */
+#define PAD_CFG1_IOSSTATE_TXD_RXE	(0x9 << 14)
+#define PAD_CFG1_IOSSTATE_IGNORE	(0xf << 14) /* Ignore Iostandby */
+/* mask to extract Iostandby bits */
+#define PAD_CFG1_IOSSTATE_MASK		(0xf << 14)
+#define PAD_CFG1_IOSSTATE_SHIFT		14 /* set Iostandby bits [17:14] */
+
+#define PAD_CFG2_DEBEN			1
+/* Debounce Duration = (2 ^ PAD_CFG2_DEBOUNCE_x_RTC) * RTC clock duration */
+#define PAD_CFG2_DEBOUNCE_8_RTC		(0x3 << 1)
+#define PAD_CFG2_DEBOUNCE_16_RTC	(0x4 << 1)
+#define PAD_CFG2_DEBOUNCE_32_RTC	(0x5 << 1)
+#define PAD_CFG2_DEBOUNCE_64_RTC	(0x6 << 1)
+#define PAD_CFG2_DEBOUNCE_128_RTC	(0x7 << 1)
+#define PAD_CFG2_DEBOUNCE_256_RTC	(0x8 << 1)
+#define PAD_CFG2_DEBOUNCE_512_RTC	(0x9 << 1)
+#define PAD_CFG2_DEBOUNCE_1K_RTC	(0xa << 1)
+#define PAD_CFG2_DEBOUNCE_2K_RTC	(0xb << 1)
+#define PAD_CFG2_DEBOUNCE_4K_RTC	(0xc << 1)
+#define PAD_CFG2_DEBOUNCE_8K_RTC	(0xd << 1)
+#define PAD_CFG2_DEBOUNCE_16K_RTC	(0xe << 1)
+#define PAD_CFG2_DEBOUNCE_32K_RTC	(0xf << 1)
+#define PAD_CFG2_DEBOUNCE_MASK		0x1f
+
+/* voltage tolerance  0=3.3V default 1=1.8V tolerant */
+#if IS_ENABLED(INTEL_PINCTRL_IOSTANDBY)
+#define PAD_CFG1_TOL_MASK		(0x1 << 25)
+#define  PAD_CFG1_TOL_1V8		(0x1 << 25)
+#endif
+
+#define PAD_FUNC(value)		PAD_CFG0_MODE_##value
+#define PAD_RESET(value)	PAD_CFG0_LOGICAL_RESET_##value
+#define PAD_PULL(value)		PAD_CFG1_PULL_##value
+
+#define PAD_IOSSTATE(value)	PAD_CFG1_IOSSTATE_##value
+#define PAD_IOSTERM(value)	PAD_CFG1_IOSTERM_##value
+
+#define PAD_IRQ_CFG(route, trig, inv) \
+				(PAD_CFG0_ROUTE_##route | \
+				PAD_CFG0_TRIG_##trig | \
+				PAD_CFG0_RX_POL_##inv)
+
+#if IS_ENABLED(INTEL_PINCTRL_DUAL_ROUTE_SUPPORT)
+#define PAD_IRQ_CFG_DUAL_ROUTE(route1, route2, trig, inv)  \
+				(PAD_CFG0_ROUTE_##route1 | \
+				PAD_CFG0_ROUTE_##route2 | \
+				PAD_CFG0_TRIG_##trig | \
+				PAD_CFG0_RX_POL_##inv)
+#endif /* CONFIG_INTEL_PINCTRL_DUAL_ROUTE_SUPPORT */
+
+#define _PAD_CFG_STRUCT(__pad, __config0, __config1)	\
+		__pad(__config0) (__config1)
+
+/* Native function configuration */
+#define PAD_CFG_NF(pad, pull, rst, func) \
+	_PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) | \
+		PAD_IOSSTATE(TX_LAST_RXE))
+
+#if IS_ENABLED(CONFIG_INTEL_GPIO_PADCFG_PADTOL)
+/*
+ * Native 1.8V tolerant pad, only applies to some pads like I2C/I2S. Not
+ * applicable to all SOCs. Refer EDS.
+ */
+#define PAD_CFG_NF_1V8(pad, pull, rst, func) \
+	_PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) |\
+		PAD_IOSSTATE(TX_LAST_RXE) | PAD_CFG1_TOL_1V8)
+#endif
+
+/* Native function configuration for standby state */
+#define PAD_CFG_NF_IOSSTATE(pad, pull, rst, func, iosstate) \
+	_PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) | \
+		PAD_IOSSTATE(iosstate))
+
+/*
+ * Native function configuration for standby state, also configuring iostandby
+ * as masked
+ */
+#define PAD_CFG_NF_IOSTANDBY_IGNORE(pad, pull, rst, func) \
+	_PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) | \
+		PAD_IOSSTATE(IGNORE))
+
+/*
+ * Native function configuration for standby state, also configuring iosstate
+ * and iosterm
+ */
+#define PAD_CFG_NF_IOSSTATE_IOSTERM(pad, pull, rst, func, iosstate, iosterm) \
+	_PAD_CFG_STRUCT(pad, PAD_RESET(rst) | PAD_FUNC(func), PAD_PULL(pull) | \
+		PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm))
+
+/* General purpose output, no pullup/down */
+#define PAD_CFG_GPO(pad, val, rst)	\
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_RX_DISABLE | !!val, \
+		PAD_PULL(NONE) | PAD_IOSSTATE(TX_LAST_RXE))
+
+/* General purpose output, with termination specified */
+#define PAD_CFG_TERM_GPO(pad, val, pull, rst)	\
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_RX_DISABLE | !!val, \
+		PAD_PULL(pull) | PAD_IOSSTATE(TX_LAST_RXE))
+
+/* General purpose output, no pullup/down */
+#define PAD_CFG_GPO_GPIO_DRIVER(pad, val, rst, pull)	\
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_RX_DISABLE | !!val, \
+		PAD_PULL(pull) | PAD_IOSSTATE(TX_LAST_RXE) | \
+			PAD_CFG1_GPIO_DRIVER)
+
+/* General purpose output */
+#define PAD_CFG_GPO_IOSSTATE_IOSTERM(pad, val, rst, pull, iosstate, ioterm) \
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_RX_DISABLE | !!val, \
+		PAD_PULL(pull) | PAD_IOSSTATE(iosstate) | PAD_IOSTERM(ioterm))
+
+/* General purpose input */
+#define PAD_CFG_GPI(pad, pull, rst) \
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE, \
+		PAD_PULL(pull) | PAD_IOSSTATE(TXD_RXE))
+
+/* General purpose input. The following macro sets the
+ * Host Software Pad Ownership to GPIO Driver mode.
+ */
+#define PAD_CFG_GPI_GPIO_DRIVER(pad, pull, rst) \
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE, \
+		PAD_PULL(pull) | PAD_CFG1_GPIO_DRIVER | PAD_IOSSTATE(TXD_RXE))
+
+#define PAD_CFG_GPIO_DRIVER_HI_Z(pad, pull, rst, iosstate, iosterm) \
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE |	\
+		PAD_CFG0_RX_DISABLE,					\
+		PAD_PULL(pull) | PAD_CFG1_GPIO_DRIVER |			\
+		PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm))
+
+#define PAD_CFG_GPIO_HI_Z(pad, pull, rst, iosstate, iosterm) \
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE |	\
+		PAD_CFG0_RX_DISABLE, PAD_PULL(pull) |			\
+		PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm))
+
+/* GPIO Interrupt */
+#define PAD_CFG_GPI_INT(pad, pull, rst, trig) \
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE |	\
+			PAD_CFG0_TRIG_##trig | PAD_CFG0_RX_POL_NONE,	\
+		PAD_PULL(pull) | PAD_CFG1_GPIO_DRIVER | PAD_IOSSTATE(TXD_RXE))
+
+/*
+ * No Connect configuration for unused pad.
+ * Both TX and RX are disabled. RX disabling is done to avoid unnecessary
+ * setting of GPI_STS.
+ */
+#define PAD_NC(pad, pull)			\
+	_PAD_CFG_STRUCT(pad,					\
+		PAD_FUNC(GPIO) | PAD_RESET(DEEP) |		\
+		PAD_CFG0_TX_DISABLE | PAD_CFG0_RX_DISABLE,	\
+		PAD_PULL(pull) | PAD_IOSSTATE(TXD_RXE))
+
+/* General purpose input, routed to APIC */
+#define PAD_CFG_GPI_APIC(pad, pull, rst, trig, inv) \
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \
+		PAD_IRQ_CFG(IOAPIC, trig, inv), PAD_PULL(pull) | \
+		PAD_IOSSTATE(TXD_RXE))
+
+/* General purpose input, routed to APIC - with IOStandby Config*/
+#define PAD_CFG_GPI_APIC_IOS(pad, pull, rst, trig, inv, iosstate, iosterm) \
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \
+		PAD_IRQ_CFG(IOAPIC, trig, inv), PAD_PULL(pull) | \
+		PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm))
+
+/*
+ * The following APIC macros assume the APIC will handle the filtering
+ * on its own end. One just needs to pass an active high message into the
+ * ITSS.
+ */
+#define PAD_CFG_GPI_APIC_LOW(pad, pull, rst) \
+	PAD_CFG_GPI_APIC(pad, pull, rst, LEVEL, INVERT)
+
+#define PAD_CFG_GPI_APIC_HIGH(pad, pull, rst) \
+	PAD_CFG_GPI_APIC(pad, pull, rst, LEVEL, NONE)
+
+#define PAD_CFG_GPI_APIC_EDGE_LOW(pad, pull, rst) \
+	PAD_CFG_GPI_APIC(pad, pull, rst, EDGE_SINGLE, INVERT)
+
+/* General purpose input, routed to SMI */
+#define PAD_CFG_GPI_SMI(pad, pull, rst, trig, inv) \
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \
+		PAD_IRQ_CFG(SMI, trig, inv), PAD_PULL(pull) | \
+		PAD_IOSSTATE(TXD_RXE))
+
+/* General purpose input, routed to SMI */
+#define PAD_CFG_GPI_SMI_IOS(pad, pull, rst, trig, inv, iosstate, iosterm) \
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \
+		PAD_IRQ_CFG(SMI, trig, inv), PAD_PULL(pull) | \
+		PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm))
+
+#define PAD_CFG_GPI_SMI_LOW(pad, pull, rst, trig) \
+	PAD_CFG_GPI_SMI(pad, pull, rst, trig, INVERT)
+
+#define PAD_CFG_GPI_SMI_HIGH(pad, pull, rst, trig) \
+	PAD_CFG_GPI_SMI(pad, pull, rst, trig, NONE)
+
+/* General purpose input, routed to SCI */
+#define PAD_CFG_GPI_SCI(pad, pull, rst, trig, inv) \
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \
+		PAD_IRQ_CFG(SCI, trig, inv), PAD_PULL(pull) | \
+		PAD_IOSSTATE(TXD_RXE))
+
+/* General purpose input, routed to SCI */
+#define PAD_CFG_GPI_SCI_IOS(pad, pull, rst, trig, inv, iosstate, iosterm) \
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \
+		PAD_IRQ_CFG(SCI, trig, inv), PAD_PULL(pull) | \
+		PAD_IOSSTATE(iosstate) | PAD_IOSTERM(iosterm))
+
+#define PAD_CFG_GPI_SCI_LOW(pad, pull, rst, trig) \
+	PAD_CFG_GPI_SCI(pad, pull, rst, trig, INVERT)
+
+#define PAD_CFG_GPI_SCI_HIGH(pad, pull, rst, trig) \
+	PAD_CFG_GPI_SCI(pad, pull, rst, trig, NONE)
+
+#define PAD_CFG_GPI_SCI_DEBEN(pad, pull, rst, trig, inv, dur) \
+	_PAD_CFG_STRUCT_3(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \
+		PAD_IRQ_CFG(SCI, trig, inv), PAD_PULL(pull) | \
+		PAD_IOSSTATE(TXD_RXE), PAD_CFG2_DEBEN | PAD_CFG2_##dur)
+
+#define PAD_CFG_GPI_SCI_LOW_DEBEN(pad, pull, rst, trig, dur) \
+	PAD_CFG_GPI_SCI_DEBEN(pad, pull, rst, trig, INVERT, dur)
+
+#define PAD_CFG_GPI_SCI_HIGH_DEBEN(pad, pull, rst, trig, dur) \
+	PAD_CFG_GPI_SCI_DEBEN(pad, pull, rst, trig, NONE, dur)
+
+/* General purpose input, routed to NMI */
+#define PAD_CFG_GPI_NMI(pad, pull, rst, trig, inv) \
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \
+		PAD_IRQ_CFG(NMI, trig, inv), PAD_PULL(pull) | \
+		PAD_IOSSTATE(TXD_RXE))
+
+#if IS_ENABLED(INTEL_PINCTRL_DUAL_ROUTE_SUPPORT)
+/* GPI, GPIO Driver, SCI interrupt */
+#define PAD_CFG_GPI_GPIO_DRIVER_SCI(pad, pull, rst, trig, inv)	\
+	_PAD_CFG_STRUCT(pad,		\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \
+			PAD_IRQ_CFG(SCI, trig, inv),	\
+		PAD_PULL(pull) | PAD_CFG1_GPIO_DRIVER | PAD_IOSSTATE(TXD_RXE))
+
+#define PAD_CFG_GPI_DUAL_ROUTE(pad, pull, rst, trig, inv, route1, route2) \
+	_PAD_CFG_STRUCT(pad,						\
+		PAD_FUNC(GPIO) | PAD_RESET(rst) | PAD_CFG0_TX_DISABLE | \
+		PAD_IRQ_CFG_DUAL_ROUTE(route1, route2,  trig, inv), \
+		PAD_PULL(pull) | PAD_IOSSTATE(TXD_RXE))
+
+#define PAD_CFG_GPI_IRQ_WAKE(pad, pull, rst, trig, inv)	\
+	PAD_CFG_GPI_DUAL_ROUTE(pad, pull, rst, trig, inv, IOAPIC, SCI)
+
+#endif /* CONFIG_INTEL_PINCTRL_DUAL_ROUTE_SUPPORT */
+
+#endif /* _ASM_INTEL_PINCTRL_DEFS_H_ */
diff --git a/arch/x86/include/asm/lpss.h b/arch/x86/include/asm/lpss.h
new file mode 100644
index 0000000..7814872
--- /dev/null
+++ b/arch/x86/include/asm/lpss.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef __ASM_LPSS_H
+#define __ASM_LPSS_H
+
+struct udevice;
+
+/* D0 and D3 enable config */
+enum lpss_pwr_state {
+	STATE_D0 = 0,
+	STATE_D3 = 3
+};
+
+/**
+ * lpss_reset_release() - Release device from reset
+ *
+ * This is used for devices which have LPSS support.
+ *
+ * @regs: Pointer to device registers
+ */
+void lpss_reset_release(void *regs);
+
+/**
+ * lpss_set_power_state() - Change power state of a device
+ *
+ * This is used for devices which have LPSS support.
+ *
+ * @dev: Device to update
+ * @state: New power state to set
+ */
+void lpss_set_power_state(struct udevice *dev, enum lpss_pwr_state state);
+
+#endif
diff --git a/arch/x86/include/asm/mrccache.h b/arch/x86/include/asm/mrccache.h
index 40fda85..d6b7529 100644
--- a/arch/x86/include/asm/mrccache.h
+++ b/arch/x86/include/asm/mrccache.h
@@ -7,7 +7,7 @@
 #ifndef _ASM_MRCCACHE_H
 #define _ASM_MRCCACHE_H
 
-#define MRC_DATA_ALIGN		0x1000
+#define MRC_DATA_ALIGN		0x100
 #define MRC_DATA_SIGNATURE	(('M' << 0) | ('R' << 8) | \
 				 ('C' << 16) | ('D'<<24))
 
@@ -27,6 +27,14 @@
 	u32	length;
 };
 
+/* Types of MRC data */
+enum mrc_type_t {
+	MRC_TYPE_NORMAL,
+	MRC_TYPE_VAR,
+
+	MRC_TYPE_COUNT,
+};
+
 struct udevice;
 
 /**
@@ -41,21 +49,6 @@
 struct mrc_data_container *mrccache_find_current(struct mrc_region *entry);
 
 /**
- * mrccache_update() - update the MRC cache with a new record
- *
- * This writes a new record to the end of the MRC cache region. If the new
- * record is the same as the latest record then the write is skipped
- *
- * @sf:		SPI flash to write to
- * @entry:	Position and size of MRC cache in SPI flash
- * @cur:	Record to write
- * @return 0 if updated, -EEXIST if the record is the same as the latest
- * record, -EINVAL if the record is not valid, other error if SPI write failed
- */
-int mrccache_update(struct udevice *sf, struct mrc_region *entry,
-		    struct mrc_data_container *cur);
-
-/**
  * mrccache_reserve() - reserve MRC data on the stack
  *
  * This copies MRC data pointed by gd->arch.mrc_output to a new place on the
@@ -84,6 +77,7 @@
  *   triggers PCI bus enumeration during which insufficient memory issue
  *   might be exposed and it causes subsequent SPI flash probe fails).
  *
+ * @type:	Type of MRC data to use
  * @devp:	Returns pointer to the SPI flash device
  * @entry:	Position and size of MRC cache in SPI flash
  * @return 0 if success, -ENOENT if SPI flash node does not exist in the
@@ -91,7 +85,8 @@
  * tree, -EINVAL if MRC region properties format is incorrect, other error
  * if SPI flash probe failed.
  */
-int mrccache_get_region(struct udevice **devp, struct mrc_region *entry);
+int mrccache_get_region(enum mrc_type_t type, struct udevice **devp,
+			struct mrc_region *entry);
 
 /**
  * mrccache_save() - save MRC data to the SPI flash
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 5bc8b6c..246c14f 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -70,6 +70,7 @@
 #define MSR_IA32_BBL_CR_CTL		0x00000119
 #define MSR_IA32_BBL_CR_CTL3		0x0000011e
 #define MSR_POWER_MISC			0x00000120
+#define  FLUSH_DL1_L2			(1 << 8)
 #define ENABLE_ULFM_AUTOCM_MASK		(1 << 2)
 #define ENABLE_INDP_AUTOCM_MASK		(1 << 3)
 
@@ -241,10 +242,17 @@
 #define  PKG_POWER_LIMIT_CLAMP		(1 << 16)
 #define  PKG_POWER_LIMIT_TIME_SHIFT	17
 #define  PKG_POWER_LIMIT_TIME_MASK	0x7f
+/*
+ * For Mobile, RAPL default PL1 time window value set to 28 seconds.
+ * RAPL time window calculation defined as follows:
+ * Time Window = (float)((1+X/4)*(2*^Y), X Corresponds to [23:22],
+ * Y to [21:17] in MSR 0x610. 28 sec is equal to 0x6e.
+ */
+#define  MB_POWER_LIMIT1_TIME_DEFAULT	0x6e
 
 #define MSR_PKG_ENERGY_STATUS		0x00000611
 #define MSR_PKG_PERF_STATUS		0x00000613
-#define MSR_PKG_POWER_INFO		0x00000614
+#define MSR_PKG_POWER_SKU		0x614
 
 #define MSR_DRAM_POWER_LIMIT		0x00000618
 #define MSR_DRAM_ENERGY_STATUS		0x00000619
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index f1d9977..d7b6836 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -25,8 +25,6 @@
 /* Length of the public header on Intel microcode blobs */
 #define UCODE_HEADER_LEN	0x30
 
-#ifndef __ASSEMBLY__
-
 /*
  * This register is documented in (for example) the Intel Atom Processor E3800
  * Product Family Datasheet in "PCU - Power Management Controller (PMC)".
@@ -37,11 +35,11 @@
  */
 #define IO_PORT_RESET		0xcf9
 
-enum {
-	SYS_RST		= 1 << 1,	/* 0 for soft reset, 1 for hard reset */
-	RST_CPU		= 1 << 2,	/* initiate reset */
-	FULL_RST	= 1 << 3,	/* full power cycle */
-};
+#define SYS_RST		(1 << 1)	/* 0 for soft reset, 1 for hard reset */
+#define RST_CPU		(1 << 2)	/* initiate reset */
+#define FULL_RST	(1 << 3)	/* full power cycle */
+
+#ifndef __ASSEMBLY__
 
 static inline __attribute__((always_inline)) void cpu_hlt(void)
 {
diff --git a/arch/x86/include/asm/spl.h b/arch/x86/include/asm/spl.h
index 1bef487..cc6cac0 100644
--- a/arch/x86/include/asm/spl.h
+++ b/arch/x86/include/asm/spl.h
@@ -11,6 +11,7 @@
 
 enum {
 	BOOT_DEVICE_SPI_MMAP	= 10,
+	BOOT_DEVICE_FAST_SPI,
 	BOOT_DEVICE_CROS_VBOOT,
 };
 
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index ca0ca10..5cd4587 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -4,9 +4,11 @@
 # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 
 ifndef CONFIG_X86_64
+ifndef CONFIG_TPL_BUILD
 obj-y += bios.o
 obj-y += bios_asm.o
 obj-y += bios_interrupts.o
+endif
 obj-y += string.o
 endif
 ifndef CONFIG_SPL_BUILD
diff --git a/arch/x86/lib/fsp/Makefile b/arch/x86/lib/fsp/Makefile
index 9e34856..da6c0a8 100644
--- a/arch/x86/lib/fsp/Makefile
+++ b/arch/x86/lib/fsp/Makefile
@@ -4,4 +4,7 @@
 
 obj-y += fsp_common.o
 obj-y += fsp_dram.o
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_VIDEO_FSP) += fsp_graphics.o
+endif
 obj-y += fsp_support.o
diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c
index a5efe35..5eff0f9 100644
--- a/arch/x86/lib/fsp/fsp_common.c
+++ b/arch/x86/lib/fsp/fsp_common.c
@@ -58,26 +58,6 @@
 		debug("OK\n");
 }
 
-void *fsp_prepare_mrc_cache(void)
-{
-	struct mrc_data_container *cache;
-	struct mrc_region entry;
-	int ret;
-
-	ret = mrccache_get_region(NULL, &entry);
-	if (ret)
-		return NULL;
-
-	cache = mrccache_find_current(&entry);
-	if (!cache)
-		return NULL;
-
-	debug("%s: mrc cache at %p, size %x checksum %04x\n", __func__,
-	      cache->data, cache->data_size, cache->checksum);
-
-	return cache->data;
-}
-
 #ifdef CONFIG_HAVE_ACPI_RESUME
 int fsp_save_s3_stack(void)
 {
diff --git a/arch/x86/lib/fsp/fsp_dram.c b/arch/x86/lib/fsp/fsp_dram.c
index bc456bb..9ce0ddf 100644
--- a/arch/x86/lib/fsp/fsp_dram.c
+++ b/arch/x86/lib/fsp/fsp_dram.c
@@ -9,6 +9,7 @@
 #include <asm/fsp/fsp_support.h>
 #include <asm/e820.h>
 #include <asm/mrccache.h>
+#include <asm/mtrr.h>
 #include <asm/post.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -38,8 +39,40 @@
 
 int dram_init_banksize(void)
 {
+	const struct hob_header *hdr;
+	struct hob_res_desc *res_desc;
+	phys_addr_t low_end;
+	uint bank;
+
+	low_end = 0;
+	for (bank = 1, hdr = gd->arch.hob_list;
+	     bank < CONFIG_NR_DRAM_BANKS && !end_of_hob(hdr);
+	     hdr = get_next_hob(hdr)) {
+		if (hdr->type != HOB_TYPE_RES_DESC)
+			continue;
+		res_desc = (struct hob_res_desc *)hdr;
+		if (res_desc->type != RES_SYS_MEM &&
+		    res_desc->type != RES_MEM_RESERVED)
+			continue;
+		if (res_desc->phys_start < (1ULL << 32)) {
+			low_end = max(low_end,
+				      res_desc->phys_start + res_desc->len);
+			continue;
+		}
+
+		gd->bd->bi_dram[bank].start = res_desc->phys_start;
+		gd->bd->bi_dram[bank].size = res_desc->len;
+		mtrr_add_request(MTRR_TYPE_WRBACK, res_desc->phys_start,
+				 res_desc->len);
+		log_debug("ram %llx %llx\n", gd->bd->bi_dram[bank].start,
+			  gd->bd->bi_dram[bank].size);
+	}
+
+	/* Add the memory below 4GB */
 	gd->bd->bi_dram[0].start = 0;
-	gd->bd->bi_dram[0].size = gd->ram_size;
+	gd->bd->bi_dram[0].size = low_end;
+
+	mtrr_add_request(MTRR_TYPE_WRBACK, 0, low_end);
 
 	return 0;
 }
diff --git a/arch/x86/lib/fsp1/fsp_graphics.c b/arch/x86/lib/fsp/fsp_graphics.c
similarity index 95%
rename from arch/x86/lib/fsp1/fsp_graphics.c
rename to arch/x86/lib/fsp/fsp_graphics.c
index 52e7133..226c7e6 100644
--- a/arch/x86/lib/fsp1/fsp_graphics.c
+++ b/arch/x86/lib/fsp/fsp_graphics.c
@@ -7,7 +7,8 @@
 #include <dm.h>
 #include <vbe.h>
 #include <video.h>
-#include <asm/fsp1/fsp_support.h>
+#include <asm/fsp/fsp_support.h>
+#include <asm/mtrr.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -97,6 +98,9 @@
 	if (ret)
 		goto err;
 
+	mtrr_add_request(MTRR_TYPE_WRCOMB, vesa->phys_base_ptr, 256 << 20);
+	mtrr_commit(true);
+
 	printf("%dx%dx%d\n", uc_priv->xsize, uc_priv->ysize,
 	       vesa->bits_per_pixel);
 
diff --git a/arch/x86/lib/fsp/fsp_support.c b/arch/x86/lib/fsp/fsp_support.c
index 983888f..ee22811 100644
--- a/arch/x86/lib/fsp/fsp_support.c
+++ b/arch/x86/lib/fsp/fsp_support.c
@@ -5,7 +5,7 @@
  */
 
 #include <common.h>
-#include <asm/fsp1/fsp_support.h>
+#include <asm/fsp/fsp_support.h>
 #include <asm/post.h>
 
 u32 fsp_get_usable_lowmem_top(const void *hob_list)
diff --git a/arch/x86/lib/fsp1/Makefile b/arch/x86/lib/fsp1/Makefile
index 870de71..1cf5e54 100644
--- a/arch/x86/lib/fsp1/Makefile
+++ b/arch/x86/lib/fsp1/Makefile
@@ -5,5 +5,4 @@
 obj-y += fsp_car.o
 obj-y += fsp_common.o
 obj-y += fsp_dram.o
-obj-$(CONFIG_VIDEO_FSP) += fsp_graphics.o
 obj-y += fsp_support.o
diff --git a/arch/x86/lib/fsp1/fsp_common.c b/arch/x86/lib/fsp1/fsp_common.c
index e8066d8..ec9c218 100644
--- a/arch/x86/lib/fsp1/fsp_common.c
+++ b/arch/x86/lib/fsp1/fsp_common.c
@@ -18,6 +18,26 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+static void *fsp_prepare_mrc_cache(void)
+{
+	struct mrc_data_container *cache;
+	struct mrc_region entry;
+	int ret;
+
+	ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry);
+	if (ret)
+		return NULL;
+
+	cache = mrccache_find_current(&entry);
+	if (!cache)
+		return NULL;
+
+	debug("%s: mrc cache at %p, size %x checksum %04x\n", __func__,
+	      cache->data, cache->data_size, cache->checksum);
+
+	return cache->data;
+}
+
 int arch_fsp_init(void)
 {
 	void *nvs;
diff --git a/arch/x86/lib/fsp1/fsp_dram.c b/arch/x86/lib/fsp1/fsp_dram.c
index 6a3349b..5ef8974 100644
--- a/arch/x86/lib/fsp1/fsp_dram.c
+++ b/arch/x86/lib/fsp1/fsp_dram.c
@@ -15,9 +15,11 @@
 	if (ret)
 		return ret;
 
-	if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE))
-		gd->arch.mrc_output = fsp_get_nvs_data(gd->arch.hob_list,
-					       &gd->arch.mrc_output_len);
+	if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) {
+		struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
+
+		mrc->buf = fsp_get_nvs_data(gd->arch.hob_list, &mrc->len);
+	}
 
 	return 0;
 }
diff --git a/arch/x86/lib/fsp2/Makefile b/arch/x86/lib/fsp2/Makefile
new file mode 100644
index 0000000..ddbe2d0
--- /dev/null
+++ b/arch/x86/lib/fsp2/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2019 Google LLC
+
+obj-y += fsp_common.o
+obj-y += fsp_dram.o
+obj-y += fsp_init.o
+obj-y += fsp_meminit.o
+obj-y += fsp_silicon_init.o
+obj-y += fsp_support.o
diff --git a/arch/x86/lib/fsp2/fsp_common.c b/arch/x86/lib/fsp2/fsp_common.c
new file mode 100644
index 0000000..f69456e
--- /dev/null
+++ b/arch/x86/lib/fsp2/fsp_common.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <init.h>
+
+int arch_fsp_init(void)
+{
+	return 0;
+}
diff --git a/arch/x86/lib/fsp2/fsp_dram.c b/arch/x86/lib/fsp2/fsp_dram.c
new file mode 100644
index 0000000..90a238a
--- /dev/null
+++ b/arch/x86/lib/fsp2/fsp_dram.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <acpi_s3.h>
+#include <handoff.h>
+#include <spl.h>
+#include <asm/arch/cpu.h>
+#include <asm/fsp/fsp_support.h>
+#include <asm/fsp2/fsp_api.h>
+#include <asm/fsp2/fsp_internal.h>
+
+int dram_init(void)
+{
+	int ret;
+
+	if (spl_phase() == PHASE_SPL) {
+#ifdef CONFIG_HAVE_ACPI_RESUME
+		bool s3wake = gd->arch.prev_sleep_state == ACPI_S3;
+#else
+		bool s3wake = false;
+#endif
+
+		ret = fsp_memory_init(s3wake,
+			      IS_ENABLED(CONFIG_APL_BOOT_FROM_FAST_SPI_FLASH));
+		if (ret) {
+			debug("Memory init failed (err=%x)\n", ret);
+			return ret;
+		}
+
+		/* The FSP has already set up DRAM, so grab the info we need */
+		ret = fsp_scan_for_ram_size();
+		if (ret)
+			return ret;
+
+#ifdef CONFIG_ENABLE_MRC_CACHE
+		gd->arch.mrc[MRC_TYPE_NORMAL].buf =
+			fsp_get_nvs_data(gd->arch.hob_list,
+					 &gd->arch.mrc[MRC_TYPE_NORMAL].len);
+		gd->arch.mrc[MRC_TYPE_VAR].buf =
+			fsp_get_var_nvs_data(gd->arch.hob_list,
+					     &gd->arch.mrc[MRC_TYPE_VAR].len);
+		log_debug("normal %x, var %x\n",
+			  gd->arch.mrc[MRC_TYPE_NORMAL].len,
+			  gd->arch.mrc[MRC_TYPE_VAR].len);
+#endif
+	} else {
+#if CONFIG_IS_ENABLED(HANDOFF)
+		struct spl_handoff *ho = gd->spl_handoff;
+
+		if (!ho) {
+			debug("No SPL handoff found\n");
+			return -ESTRPIPE;
+		}
+		gd->ram_size = ho->ram_size;
+		handoff_load_dram_banks(ho);
+#endif
+		ret = arch_fsps_preinit();
+		if (ret)
+			return log_msg_ret("fsp_s_preinit", ret);
+	}
+
+	return 0;
+}
+
+ulong board_get_usable_ram_top(ulong total_size)
+{
+#if CONFIG_IS_ENABLED(HANDOFF)
+	struct spl_handoff *ho = gd->spl_handoff;
+
+	return ho->arch.usable_ram_top;
+#endif
+
+	return gd->ram_top;
+}
diff --git a/arch/x86/lib/fsp2/fsp_init.c b/arch/x86/lib/fsp2/fsp_init.c
new file mode 100644
index 0000000..da9bd6b
--- /dev/null
+++ b/arch/x86/lib/fsp2/fsp_init.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <binman.h>
+#include <binman_sym.h>
+#include <cbfs.h>
+#include <dm.h>
+#include <init.h>
+#include <spi.h>
+#include <spl.h>
+#include <spi_flash.h>
+#include <asm/intel_pinctrl.h>
+#include <dm/uclass-internal.h>
+#include <asm/fsp2/fsp_internal.h>
+
+int arch_cpu_init_dm(void)
+{
+	struct udevice *dev;
+	ofnode node;
+	int ret;
+
+	/* Make sure pads are set up early in U-Boot */
+	if (spl_phase() != PHASE_BOARD_F)
+		return 0;
+
+	/* Probe all pinctrl devices to set up the pads */
+	ret = uclass_first_device_err(UCLASS_PINCTRL, &dev);
+	if (ret)
+		return log_msg_ret("no fsp pinctrl", ret);
+	node = ofnode_path("fsp");
+	if (!ofnode_valid(node))
+		return log_msg_ret("no fsp params", -EINVAL);
+	ret = pinctrl_config_pads_for_node(dev, node);
+	if (ret)
+		return log_msg_ret("pad config", ret);
+
+	return ret;
+}
+
+#if !defined(CONFIG_TPL_BUILD)
+binman_sym_declare(ulong, intel_fsp_m, image_pos);
+binman_sym_declare(ulong, intel_fsp_m, size);
+
+/**
+ * get_cbfs_fsp() - Obtain the FSP by looking up in CBFS
+ *
+ * This looks up an FSP in a CBFS. It is used mostly for testing, when booting
+ * U-Boot from a hybrid image containing coreboot as the first-stage bootloader.
+ *
+ * The typical use for this feature is when building a Chrome OS image which
+ * includes coreboot in it. By adding U-Boot into the 'COREBOOT' CBFS as well,
+ * it is possible to make coreboot chain-load U-Boot. Thus the initial stages of
+ * the SoC init can be done by coreboot and the later stages by U-Boot. This is
+ * a convenient way to start the porting work. The jump to U-Boot can then be
+ * moved progressively earlier and earlier, until U-Boot takes over all the init
+ * and you have a native port.
+ *
+ * This function looks up a CBFS at a known location and reads the FSP-M from it
+ * so that U-Boot can init the memory.
+ *
+ * This function is not used in the normal boot but is kept here for future
+ * development.
+ *
+ * @type; Type to look up (only FSP_M supported at present)
+ * @map_base: Base memory address for mapped SPI
+ * @entry: Returns an entry containing the position of the FSP image
+ */
+static int get_cbfs_fsp(enum fsp_type_t type, ulong map_base,
+			struct binman_entry *entry)
+{
+	/*
+	 * Use a hard-coded position of CBFS in the ROM for now. It would be
+	 * possible to read the position using the FMAP in the ROM, but since
+	 * this code is only used for development, it doesn't seem worth it.
+	 * Use the 'cbfstool <image> layout' command to get these values, e.g.:
+	 * 'COREBOOT' (CBFS, size 1814528, offset 2117632).
+	 */
+	ulong cbfs_base = 0x205000;
+	ulong cbfs_size = 0x1bb000;
+	struct cbfs_priv *cbfs;
+	int ret;
+
+	ret = cbfs_init_mem(map_base + cbfs_base, cbfs_size, &cbfs);
+	if (ret)
+		return ret;
+	if (!ret) {
+		const struct cbfs_cachenode *node;
+
+		node = cbfs_find_file(cbfs, "fspm.bin");
+		if (!node)
+			return log_msg_ret("fspm node", -ENOENT);
+
+		entry->image_pos = (ulong)node->data;
+		entry->size = node->data_length;
+	}
+
+	return 0;
+}
+
+int fsp_locate_fsp(enum fsp_type_t type, struct binman_entry *entry,
+		   bool use_spi_flash, struct udevice **devp,
+		   struct fsp_header **hdrp, ulong *rom_offsetp)
+{
+	ulong mask = CONFIG_ROM_SIZE - 1;
+	struct udevice *dev;
+	ulong rom_offset = 0;
+	uint map_size;
+	ulong map_base;
+	uint offset;
+	int ret;
+
+	/*
+	 * Find the devices but don't probe them, since we don't want to
+	 * auto-config PCI before silicon init runs
+	 */
+	ret = uclass_find_first_device(UCLASS_NORTHBRIDGE, &dev);
+	if (ret)
+		return log_msg_ret("Cannot get northbridge", ret);
+	if (!use_spi_flash) {
+		struct udevice *sf;
+
+		/* Just use the SPI driver to get the memory map */
+		ret = uclass_find_first_device(UCLASS_SPI_FLASH, &sf);
+		if (ret)
+			return log_msg_ret("Cannot get SPI flash", ret);
+		ret = dm_spi_get_mmap(sf, &map_base, &map_size, &offset);
+		if (ret)
+			return log_msg_ret("Could not get flash mmap", ret);
+	}
+
+	if (spl_phase() >= PHASE_BOARD_F) {
+		if (type != FSP_S)
+			return -EPROTONOSUPPORT;
+		ret = binman_entry_find("intel-fsp-s", entry);
+		if (ret)
+			return log_msg_ret("binman entry", ret);
+		if (!use_spi_flash)
+			rom_offset = (map_base & mask) - CONFIG_ROM_SIZE;
+	} else {
+		ret = -ENOENT;
+		if (false)
+			/*
+			 * Support using a hybrid image build by coreboot. See
+			 * the function comments for details
+			 */
+			ret = get_cbfs_fsp(type, map_base, entry);
+		if (ret) {
+			ulong mask = CONFIG_ROM_SIZE - 1;
+
+			if (type != FSP_M)
+				return -EPROTONOSUPPORT;
+			entry->image_pos = binman_sym(ulong, intel_fsp_m,
+						      image_pos);
+			entry->size = binman_sym(ulong, intel_fsp_m, size);
+			if (entry->image_pos != BINMAN_SYM_MISSING) {
+				ret = 0;
+				if (use_spi_flash)
+					entry->image_pos &= mask;
+				else
+					entry->image_pos += (map_base & mask);
+			} else {
+				ret = -ENOENT;
+			}
+		}
+	}
+	if (ret)
+		return log_msg_ret("Cannot find FSP", ret);
+	entry->image_pos += rom_offset;
+
+	/*
+	 * Account for the time taken to read memory-mapped SPI flash since in
+	 * this case we don't use the SPI driver and BOOTSTAGE_ID_ACCUM_SPI.
+	 */
+	if (!use_spi_flash)
+		bootstage_start(BOOTSTAGE_ID_ACCUM_MMAP_SPI, "mmap_spi");
+	ret = fsp_get_header(entry->image_pos, entry->size, use_spi_flash,
+			     hdrp);
+	if (!use_spi_flash)
+		bootstage_accum(BOOTSTAGE_ID_ACCUM_MMAP_SPI);
+	if (ret)
+		return log_msg_ret("fsp_get_header", ret);
+	*devp = dev;
+	if (rom_offsetp)
+		*rom_offsetp = rom_offset;
+
+	return 0;
+}
+#endif
diff --git a/arch/x86/lib/fsp2/fsp_meminit.c b/arch/x86/lib/fsp2/fsp_meminit.c
new file mode 100644
index 0000000..bf30c47
--- /dev/null
+++ b/arch/x86/lib/fsp2/fsp_meminit.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: Intel
+/*
+ * Copyright (C) 2015-2016 Intel Corp.
+ * (Written by Andrey Petrov <andrey.petrov@intel.com> for Intel Corp.)
+ * (Written by Alexandru Gagniuc <alexandrux.gagniuc@intel.com> for Intel Corp.)
+ * Mostly taken from coreboot fsp2_0/memory_init.c
+ */
+
+#include <common.h>
+#include <binman.h>
+#include <asm/mrccache.h>
+#include <asm/fsp/fsp_infoheader.h>
+#include <asm/fsp2/fsp_api.h>
+#include <asm/fsp2/fsp_internal.h>
+#include <asm/arch/fsp/fsp_configs.h>
+#include <asm/arch/fsp/fsp_m_upd.h>
+
+static int prepare_mrc_cache_type(enum mrc_type_t type,
+				  struct mrc_data_container **cachep)
+{
+	struct mrc_data_container *cache;
+	struct mrc_region entry;
+	int ret;
+
+	ret = mrccache_get_region(type, NULL, &entry);
+	if (ret)
+		return ret;
+	cache = mrccache_find_current(&entry);
+	if (!cache)
+		return -ENOENT;
+
+	log_debug("MRC at %x, size %x\n", (uint)cache->data, cache->data_size);
+	*cachep = cache;
+
+	return 0;
+}
+
+int prepare_mrc_cache(struct fspm_upd *upd)
+{
+	struct mrc_data_container *cache;
+	int ret;
+
+	ret = prepare_mrc_cache_type(MRC_TYPE_NORMAL, &cache);
+	if (ret)
+		return log_msg_ret("Cannot get normal cache", ret);
+	upd->arch.nvs_buffer_ptr = cache->data;
+
+	ret = prepare_mrc_cache_type(MRC_TYPE_VAR, &cache);
+	if (ret)
+		return log_msg_ret("Cannot get var cache", ret);
+	upd->config.variable_nvs_buffer_ptr = cache->data;
+
+	return 0;
+}
+
+int fsp_memory_init(bool s3wake, bool use_spi_flash)
+{
+	struct fspm_upd upd, *fsp_upd;
+	fsp_memory_init_func func;
+	struct binman_entry entry;
+	struct fsp_header *hdr;
+	struct hob_header *hob;
+	struct udevice *dev;
+	int ret;
+
+	ret = fsp_locate_fsp(FSP_M, &entry, use_spi_flash, &dev, &hdr, NULL);
+	if (ret)
+		return log_msg_ret("locate FSP", ret);
+	debug("Found FSP_M at %x, size %x\n", hdr->img_base, hdr->img_size);
+
+	/* Copy over the default config */
+	fsp_upd = (struct fspm_upd *)(hdr->img_base + hdr->cfg_region_off);
+	if (fsp_upd->header.signature != FSPM_UPD_SIGNATURE)
+		return log_msg_ret("Bad UPD signature", -EPERM);
+	memcpy(&upd, fsp_upd, sizeof(upd));
+
+	ret = fspm_update_config(dev, &upd);
+	if (ret)
+		return log_msg_ret("Could not setup config", ret);
+
+	debug("SDRAM init...");
+	bootstage_start(BOOTSTATE_ID_ACCUM_FSP_M, "fsp-m");
+	func = (fsp_memory_init_func)(hdr->img_base + hdr->fsp_mem_init);
+	ret = func(&upd, &hob);
+	bootstage_accum(BOOTSTATE_ID_ACCUM_FSP_M);
+	if (ret)
+		return log_msg_ret("SDRAM init fail\n", ret);
+
+	gd->arch.hob_list = hob;
+	debug("done\n");
+
+	ret = fspm_done(dev);
+	if (ret)
+		return log_msg_ret("fsm_done\n", ret);
+
+	return 0;
+}
diff --git a/arch/x86/lib/fsp2/fsp_silicon_init.c b/arch/x86/lib/fsp2/fsp_silicon_init.c
new file mode 100644
index 0000000..d7ce43e
--- /dev/null
+++ b/arch/x86/lib/fsp2/fsp_silicon_init.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: Intel
+/*
+ * Copyright (C) 2015-2016 Intel Corp.
+ * (Written by Andrey Petrov <andrey.petrov@intel.com> for Intel Corp.)
+ *
+ * Mostly taken from coreboot fsp2_0/silicon_init.c
+ */
+
+#define LOG_CATEGORY UCLASS_NORTHBRIDGE
+
+#include <common.h>
+#include <binman.h>
+#include <dm.h>
+#include <asm/arch/fsp/fsp_configs.h>
+#include <asm/arch/fsp/fsp_s_upd.h>
+#include <asm/fsp/fsp_infoheader.h>
+#include <asm/fsp2/fsp_internal.h>
+
+int fsp_silicon_init(bool s3wake, bool use_spi_flash)
+{
+	struct fsps_upd upd, *fsp_upd;
+	fsp_silicon_init_func func;
+	struct fsp_header *hdr;
+	struct binman_entry entry;
+	struct udevice *dev;
+	ulong rom_offset = 0;
+	int ret;
+
+	ret = fsp_locate_fsp(FSP_S, &entry, use_spi_flash, &dev, &hdr,
+			     &rom_offset);
+	if (ret)
+		return log_msg_ret("locate FSP", ret);
+	gd->arch.fsp_s_hdr = hdr;
+
+	/* Copy over the default config */
+	fsp_upd = (struct fsps_upd *)(hdr->img_base + hdr->cfg_region_off);
+	if (fsp_upd->header.signature != FSPS_UPD_SIGNATURE)
+		return log_msg_ret("Bad UPD signature", -EPERM);
+	memcpy(&upd, fsp_upd, sizeof(upd));
+
+	ret = fsps_update_config(dev, rom_offset, &upd);
+	if (ret)
+		return log_msg_ret("Could not setup config", ret);
+	log_debug("Silicon init...");
+	bootstage_start(BOOTSTATE_ID_ACCUM_FSP_S, "fsp-s");
+	func = (fsp_silicon_init_func)(hdr->img_base + hdr->fsp_silicon_init);
+	ret = func(&upd);
+	bootstage_accum(BOOTSTATE_ID_ACCUM_FSP_S);
+	if (ret)
+		return log_msg_ret("Silicon init fail\n", ret);
+	log_debug("done\n");
+
+	return 0;
+}
diff --git a/arch/x86/lib/fsp2/fsp_support.c b/arch/x86/lib/fsp2/fsp_support.c
new file mode 100644
index 0000000..0a04b44
--- /dev/null
+++ b/arch/x86/lib/fsp2/fsp_support.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: Intel
+/*
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <spi_flash.h>
+#include <asm/fsp/fsp_support.h>
+#include <asm/fsp2/fsp_internal.h>
+
+/* The amount of the FSP header to probe to obtain what we need */
+#define PROBE_BUF_SIZE 0x180
+
+int fsp_get_header(ulong offset, ulong size, bool use_spi_flash,
+		   struct fsp_header **fspp)
+{
+	static efi_guid_t guid = FSP_HEADER_GUID;
+	struct fv_ext_header *exhdr;
+	struct fsp_header *fsp;
+	struct ffs_file_header *file_hdr;
+	struct fv_header *fv;
+	struct raw_section *raw;
+	void *ptr, *base;
+	u8 buf[PROBE_BUF_SIZE];
+	struct udevice *dev;
+	int ret;
+
+	/*
+	 * There are quite a very steps to work through all the headers in this
+	 * file and the structs have similar names. Turn on debugging if needed
+	 * to understand what is going wrong.
+	 *
+	 * You are in a maze of twisty little headers all alike.
+	 */
+	debug("offset=%x buf=%x\n", (uint)offset, (uint)buf);
+	if (use_spi_flash) {
+		ret = uclass_first_device_err(UCLASS_SPI_FLASH, &dev);
+		if (ret)
+			return log_msg_ret("Cannot find flash device", ret);
+		ret = spi_flash_read_dm(dev, offset, PROBE_BUF_SIZE, buf);
+		if (ret)
+			return log_msg_ret("Cannot read flash", ret);
+	} else {
+		memcpy(buf, (void *)offset, PROBE_BUF_SIZE);
+	}
+
+	/* Initalise the FSP base */
+	ptr = buf;
+	fv = ptr;
+
+	/* Check the FV signature, _FVH */
+	debug("offset=%x sign=%x\n", (uint)offset, (uint)fv->sign);
+	if (fv->sign != EFI_FVH_SIGNATURE)
+		return log_msg_ret("Base FV signature", -EINVAL);
+
+	/* Go to the end of the FV header and align the address */
+	debug("fv->ext_hdr_off = %x\n", fv->ext_hdr_off);
+	ptr += fv->ext_hdr_off;
+	exhdr = ptr;
+	ptr += ALIGN(exhdr->ext_hdr_size, 8);
+	debug("ptr=%x\n", ptr - (void *)buf);
+
+	/* Check the FFS GUID */
+	file_hdr = ptr;
+	if (memcmp(&file_hdr->name, &guid, sizeof(guid)))
+		return log_msg_ret("Base FFS GUID", -ENXIO);
+	/* Add the FFS header size to find the raw section header */
+	ptr = file_hdr + 1;
+
+	raw = ptr;
+	debug("raw->type = %x\n", raw->type);
+	if (raw->type != EFI_SECTION_RAW)
+		return log_msg_ret("Section type not RAW", -ENOEXEC);
+
+	/* Add the raw section header size to find the FSP header */
+	ptr = raw + 1;
+	fsp = ptr;
+
+	/* Check the FSPH header */
+	debug("fsp %x\n", (uint)fsp);
+	if (fsp->sign != EFI_FSPH_SIGNATURE)
+		return log_msg_ret("Base FSPH signature", -EACCES);
+
+	base = (void *)fsp->img_base;
+	debug("Image base %x\n", (uint)base);
+	debug("Image addr %x\n", (uint)fsp->fsp_mem_init);
+	if (use_spi_flash) {
+		ret = spi_flash_read_dm(dev, offset, size, base);
+		if (ret)
+			return log_msg_ret("Could not read FPS-M", ret);
+	} else {
+		memcpy(base, (void *)offset, size);
+	}
+	ptr = base + (ptr - (void *)buf);
+	*fspp = ptr;
+
+	return 0;
+}
+
+u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase)
+{
+	fsp_notify_f notify;
+	struct fsp_notify_params params;
+	struct fsp_notify_params *params_ptr;
+	u32 status;
+
+	if (!fsp_hdr)
+		fsp_hdr = gd->arch.fsp_s_hdr;
+
+	if (!fsp_hdr)
+		return log_msg_ret("no FSP", -ENOENT);
+
+	notify = (fsp_notify_f)(fsp_hdr->img_base + fsp_hdr->fsp_notify);
+	params.phase = phase;
+	params_ptr = &params;
+
+	/*
+	 * Use ASM code to ensure correct parameter is on the stack for
+	 * FspNotify as U-Boot is using different ABI from FSP
+	 */
+	asm volatile (
+		"pushl	%1;"		/* push notify phase */
+		"call	*%%eax;"	/* call FspNotify */
+		"addl	$4, %%esp;"	/* clean up the stack */
+		: "=a"(status) : "m"(params_ptr), "a"(notify), "m"(*params_ptr)
+	);
+
+	return status;
+}
diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c
index 33bb520..b9420a4 100644
--- a/arch/x86/lib/mrccache.c
+++ b/arch/x86/lib/mrccache.c
@@ -14,6 +14,8 @@
 #include <spi.h>
 #include <spi_flash.h>
 #include <asm/mrccache.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -80,21 +82,31 @@
 /**
  * find_next_mrc_cache() - get next cache entry
  *
+ * This moves to the next cache entry in the region, making sure it has enough
+ * space to hold data of size @data_size.
+ *
  * @entry:	MRC cache flash area
  * @cache:	Entry to start from
+ * @data_size:	Required data size of the new entry. Note that we assume that
+ *	all cache entries are the same size
  *
  * @return next cache entry if found, NULL if we got to the end
  */
 static struct mrc_data_container *find_next_mrc_cache(struct mrc_region *entry,
-		struct mrc_data_container *cache)
+		struct mrc_data_container *prev, int data_size)
 {
+	struct mrc_data_container *cache;
 	ulong base_addr, end_addr;
 
 	base_addr = entry->base + entry->offset;
 	end_addr = base_addr + entry->length;
 
-	cache = next_mrc_block(cache);
-	if ((ulong)cache >= end_addr) {
+	/*
+	 * We assume that all cache entries are the same size, but let's use
+	 * data_size here for clarity.
+	 */
+	cache = next_mrc_block(prev);
+	if ((ulong)cache + mrc_block_size(data_size) > end_addr) {
 		/* Crossed the boundary */
 		cache = NULL;
 		debug("%s: no available entries found\n", __func__);
@@ -106,8 +118,20 @@
 	return cache;
 }
 
-int mrccache_update(struct udevice *sf, struct mrc_region *entry,
-		    struct mrc_data_container *cur)
+/**
+ * mrccache_update() - update the MRC cache with a new record
+ *
+ * This writes a new record to the end of the MRC cache region. If the new
+ * record is the same as the latest record then the write is skipped
+ *
+ * @sf:		SPI flash to write to
+ * @entry:	Position and size of MRC cache in SPI flash
+ * @cur:	Record to write
+ * @return 0 if updated, -EEXIST if the record is the same as the latest
+ * record, -EINVAL if the record is not valid, other error if SPI write failed
+ */
+static int mrccache_update(struct udevice *sf, struct mrc_region *entry,
+			   struct mrc_data_container *cur)
 {
 	struct mrc_data_container *cache;
 	ulong offset;
@@ -131,7 +155,7 @@
 
 	/* Move to the next block, which will be the first unused block */
 	if (cache)
-		cache = find_next_mrc_cache(entry, cache);
+		cache = find_next_mrc_cache(entry, cache, cur->data_size);
 
 	/*
 	 * If we have got to the end, erase the entire mrc-cache area and start
@@ -156,130 +180,158 @@
 				 cur);
 	if (ret) {
 		debug("Failed to write to SPI flash\n");
-		return ret;
+		return log_msg_ret("Cannot update mrccache", ret);
 	}
 
 	return 0;
 }
 
-static void mrccache_setup(void *data)
+static void mrccache_setup(struct mrc_output *mrc, void *data)
 {
 	struct mrc_data_container *cache = data;
 	u16 checksum;
 
 	cache->signature = MRC_DATA_SIGNATURE;
-	cache->data_size = gd->arch.mrc_output_len;
-	checksum = compute_ip_checksum(gd->arch.mrc_output, cache->data_size);
+	cache->data_size = mrc->len;
+	checksum = compute_ip_checksum(mrc->buf, cache->data_size);
 	debug("Saving %d bytes for MRC output data, checksum %04x\n",
 	      cache->data_size, checksum);
 	cache->checksum = checksum;
 	cache->reserved = 0;
-	memcpy(cache->data, gd->arch.mrc_output, cache->data_size);
+	memcpy(cache->data, mrc->buf, cache->data_size);
 
-	/* gd->arch.mrc_output now points to the container */
-	gd->arch.mrc_output = (char *)cache;
+	mrc->cache = cache;
 }
 
 int mrccache_reserve(void)
 {
-	if (!gd->arch.mrc_output_len)
-		return 0;
+	int i;
 
-	/* adjust stack pointer to store pure cache data plus the header */
-	gd->start_addr_sp -= (gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE);
-	mrccache_setup((void *)gd->start_addr_sp);
+	for (i = 0; i < MRC_TYPE_COUNT; i++) {
+		struct mrc_output *mrc = &gd->arch.mrc[i];
 
-	gd->start_addr_sp &= ~0xf;
+		if (!mrc->len)
+			continue;
+
+		/* adjust stack pointer to store pure cache data plus header */
+		gd->start_addr_sp -= (mrc->len + MRC_DATA_HEADER_SIZE);
+		mrccache_setup(mrc, (void *)gd->start_addr_sp);
+
+		gd->start_addr_sp &= ~0xf;
+	}
 
 	return 0;
 }
 
-int mrccache_get_region(struct udevice **devp, struct mrc_region *entry)
+int mrccache_get_region(enum mrc_type_t type, struct udevice **devp,
+			struct mrc_region *entry)
 {
-	const void *blob = gd->fdt_blob;
-	int node, mrc_node;
+	struct udevice *dev;
+	ofnode mrc_node;
+	ulong map_base;
+	uint map_size;
+	uint offset;
 	u32 reg[2];
 	int ret;
 
-	/* Find the flash chip within the SPI controller node */
-	node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH);
-	if (node < 0) {
-		debug("%s: Cannot find SPI flash\n", __func__);
-		return -ENOENT;
-	}
-
-	if (fdtdec_get_int_array(blob, node, "memory-map", reg, 2)) {
-		debug("%s: Cannot find memory map\n", __func__);
-		return -EINVAL;
+	/*
+	 * Find the flash chip within the SPI controller node. Avoid probing
+	 * the device here since it may put it into a strange state where the
+	 * memory map cannot be read.
+	 */
+	ret = uclass_find_first_device(UCLASS_SPI_FLASH, &dev);
+	if (ret)
+		return log_msg_ret("Cannot find SPI flash\n", ret);
+	ret = dm_spi_get_mmap(dev, &map_base, &map_size, &offset);
+	if (!ret) {
+		entry->base = map_base;
+	} else {
+		ret = dev_read_u32_array(dev, "memory-map", reg, 2);
+		if (ret)
+			return log_msg_ret("Cannot find memory map\n", ret);
+		entry->base = reg[0];
 	}
-	entry->base = reg[0];
 
 	/* Find the place where we put the MRC cache */
-	mrc_node = fdt_subnode_offset(blob, node, "rw-mrc-cache");
-	if (mrc_node < 0) {
-		debug("%s: Cannot find node\n", __func__);
-		return -EPERM;
-	}
+	mrc_node = dev_read_subnode(dev, type == MRC_TYPE_NORMAL ?
+				    "rw-mrc-cache" : "rw-var-mrc-cache");
+	if (!ofnode_valid(mrc_node))
+		return log_msg_ret("Cannot find node", -EPERM);
 
-	if (fdtdec_get_int_array(blob, mrc_node, "reg", reg, 2)) {
-		debug("%s: Cannot find address\n", __func__);
-		return -EINVAL;
-	}
+	ret = ofnode_read_u32_array(mrc_node, "reg", reg, 2);
+	if (ret)
+		return log_msg_ret("Cannot find address", ret);
 	entry->offset = reg[0];
 	entry->length = reg[1];
 
-	if (devp) {
-		ret = uclass_get_device_by_of_offset(UCLASS_SPI_FLASH, node,
-						     devp);
-		debug("ret = %d\n", ret);
-		if (ret)
-			return ret;
-	}
+	if (devp)
+		*devp = dev;
+	debug("MRC cache type %d in '%s', offset %x, len %x, base %x\n",
+	      type, dev->name, entry->offset, entry->length, entry->base);
 
 	return 0;
 }
 
-int mrccache_save(void)
+static int mrccache_save_type(enum mrc_type_t type)
 {
-	struct mrc_data_container *data;
+	struct mrc_data_container *cache;
+	struct mrc_output *mrc;
 	struct mrc_region entry;
 	struct udevice *sf;
 	int ret;
 
-	if (!gd->arch.mrc_output_len)
+	mrc = &gd->arch.mrc[type];
+	if (!mrc->len)
 		return 0;
-	debug("Saving %d bytes of MRC output data to SPI flash\n",
-	      gd->arch.mrc_output_len);
-
-	ret = mrccache_get_region(&sf, &entry);
+	log_debug("Saving %#x bytes of MRC output data type %d to SPI flash\n",
+		  mrc->len, type);
+	ret = mrccache_get_region(type, &sf, &entry);
 	if (ret)
-		goto err_entry;
-	data  = (struct mrc_data_container *)gd->arch.mrc_output;
-	ret = mrccache_update(sf, &entry, data);
-	if (!ret) {
-		debug("Saved MRC data with checksum %04x\n", data->checksum);
-	} else if (ret == -EEXIST) {
+		return log_msg_ret("Cannot get region", ret);
+	ret = device_probe(sf);
+	if (ret)
+		return log_msg_ret("Cannot probe device", ret);
+	cache = mrc->cache;
+
+	ret = mrccache_update(sf, &entry, cache);
+	if (!ret)
+		debug("Saved MRC data with checksum %04x\n", cache->checksum);
+	else if (ret == -EEXIST)
 		debug("MRC data is the same as last time, skipping save\n");
-		ret = 0;
+
+	return 0;
+}
+
+int mrccache_save(void)
+{
+	int i;
+
+	for (i = 0; i < MRC_TYPE_COUNT; i++) {
+		int ret;
+
+		ret = mrccache_save_type(i);
+		if (ret)
+			return ret;
 	}
 
-err_entry:
-	if (ret)
-		debug("%s: Failed: %d\n", __func__, ret);
-	return ret;
+	return 0;
 }
 
 int mrccache_spl_save(void)
 {
-	void *data;
-	int size;
+	int i;
 
-	size = gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE;
-	data = malloc(size);
-	if (!data)
-		return log_msg_ret("Allocate MRC cache block", -ENOMEM);
-	mrccache_setup(data);
-	gd->arch.mrc_output = data;
+	for (i = 0; i < MRC_TYPE_COUNT; i++) {
+		struct mrc_output *mrc = &gd->arch.mrc[i];
+		void *data;
+		int size;
+
+		size = mrc->len + MRC_DATA_HEADER_SIZE;
+		data = malloc(size);
+		if (!data)
+			return log_msg_ret("Allocate MRC cache block", -ENOMEM);
+		mrccache_setup(mrc, data);
+	}
 
 	return mrccache_save();
 }
diff --git a/arch/x86/lib/pirq_routing.c b/arch/x86/lib/pirq_routing.c
index e5f0e61..17bd2fc 100644
--- a/arch/x86/lib/pirq_routing.c
+++ b/arch/x86/lib/pirq_routing.c
@@ -10,6 +10,8 @@
 #include <asm/pci.h>
 #include <asm/pirq_routing.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 static u8 pirq_get_next_free_irq(struct udevice *dev, u8 *pirq, u16 bitmap,
 				 bool irq_already_routed[])
 {
@@ -131,3 +133,11 @@
 
 	return addr + rt->size;
 }
+
+ulong write_pirq_routing_table(ulong addr)
+{
+	if (!gd->arch.pirq_routing_table)
+		return addr;
+
+	return copy_pirq_routing_table(addr, gd->arch.pirq_routing_table);
+}
diff --git a/board/freescale/imx8qm_mek/imx8qm_mek.c b/board/freescale/imx8qm_mek/imx8qm_mek.c
index 68be0fe..667a274 100644
--- a/board/freescale/imx8qm_mek/imx8qm_mek.c
+++ b/board/freescale/imx8qm_mek/imx8qm_mek.c
@@ -50,7 +50,7 @@
 	return 0;
 }
 
-#if IS_ENABLED(CONFIG_DM_GPIO)
+#if CONFIG_IS_ENABLED(DM_GPIO)
 static void board_gpio_init(void)
 {
 	/* TODO */
diff --git a/board/freescale/imx8qxp_mek/imx8qxp_mek.c b/board/freescale/imx8qxp_mek/imx8qxp_mek.c
index 671064f..194eb60 100644
--- a/board/freescale/imx8qxp_mek/imx8qxp_mek.c
+++ b/board/freescale/imx8qxp_mek/imx8qxp_mek.c
@@ -54,7 +54,7 @@
 	return 0;
 }
 
-#if IS_ENABLED(CONFIG_DM_GPIO)
+#if CONFIG_IS_ENABLED(DM_GPIO)
 static void board_gpio_init(void)
 {
 	struct gpio_desc desc;
diff --git a/board/gateworks/gw_ventana/Kconfig b/board/gateworks/gw_ventana/Kconfig
index 5d1bae4..fee910c 100644
--- a/board/gateworks/gw_ventana/Kconfig
+++ b/board/gateworks/gw_ventana/Kconfig
@@ -1,5 +1,8 @@
 if TARGET_GW_VENTANA
 
+config DM_GPIO
+	default y
+
 config SYS_BOARD
 	default "gw_ventana"
 
diff --git a/board/google/Kconfig b/board/google/Kconfig
index 679a0f1..22c4be3 100644
--- a/board/google/Kconfig
+++ b/board/google/Kconfig
@@ -8,6 +8,20 @@
 	prompt "Mainboard model"
 	optional
 
+config TARGET_CHROMEBOOK_CORAL
+	bool "Chromebook coral"
+	help
+	  This is a range of Intel-based laptops released in 2018. They use an
+	  Intel Apollo Lake SoC. The design supports WiFi, 4GB to 16GB of
+	  LPDDR4 1600MHz SDRAM, PCIe WiFi and Bluetooth, eMMC (typically 32GB),
+	  up two cameras (front-facing 720p and another 5MP option), USB SD
+	  reader, microphone and speakers. It also includes two USB 3 Type A and
+	  two Type C ports. The latter are used as power input and can also
+	  charge external devices as well as a 4K external display. There is a
+	  Chrome OS EC connected on LPC, a Cr50 secure chip from Google and
+	  various display options. OEMs products include Acer Chromebook 11
+	  (e.g. C732, CB11, CP311) and Lenovo Chromebook (100e, 300e, 500e).
+
 config TARGET_CHROMEBOOK_LINK
 	bool "Chromebook link"
 	help
@@ -62,6 +76,7 @@
 
 endchoice
 
+source "board/google/chromebook_coral/Kconfig"
 source "board/google/chromebook_link/Kconfig"
 source "board/google/chromebox_panther/Kconfig"
 source "board/google/chromebook_samus/Kconfig"
diff --git a/board/google/chromebook_coral/Kconfig b/board/google/chromebook_coral/Kconfig
new file mode 100644
index 0000000..940bee8
--- /dev/null
+++ b/board/google/chromebook_coral/Kconfig
@@ -0,0 +1,43 @@
+if TARGET_CHROMEBOOK_CORAL
+
+config SYS_BOARD
+	default "chromebook_coral"
+
+config SYS_VENDOR
+	default "google"
+
+config SYS_SOC
+	default "apollolake"
+
+config SYS_CONFIG_NAME
+	default "chromebook_coral"
+
+config SYS_TEXT_BASE
+	default 0xffe00000
+
+config BOARD_SPECIFIC_OPTIONS # dummy
+	def_bool y
+	select X86_RESET_VECTOR
+	select INTEL_APOLLOLAKE
+	select BOARD_ROMSIZE_KB_16384
+
+config PCIE_ECAM_BASE
+	default 0xf0000000
+
+config EARLY_POST_CROS_EC
+	bool "Enable early post to Chrome OS EC"
+	help
+	  Allow post codes to be sent to the Chroem OS EC early during boot,
+	  to enable monitoring of the boot and debugging when things go wrong.
+	  With this option enabled, the EC console can be used to watch post
+	  codes the first part of boot.
+
+config SYS_CAR_ADDR
+	hex
+	default 0xfef00000
+
+config SYS_CAR_SIZE
+	hex
+	default 0xc0000
+
+endif
diff --git a/board/google/chromebook_coral/MAINTAINERS b/board/google/chromebook_coral/MAINTAINERS
new file mode 100644
index 0000000..904227e
--- /dev/null
+++ b/board/google/chromebook_coral/MAINTAINERS
@@ -0,0 +1,6 @@
+CHROMEBOOK_CORAL_BOARD
+M:	Simon Glass <sjg@chromium.org>
+S:	Maintained
+F:	board/google/chromebook_coral/
+F:	include/configs/chromebook_coral.h
+F:	configs/chromebook_coral_defconfig
diff --git a/board/google/chromebook_coral/Makefile b/board/google/chromebook_coral/Makefile
new file mode 100644
index 0000000..6a27ce3
--- /dev/null
+++ b/board/google/chromebook_coral/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2019 Google LLC
+
+obj-y	+= coral.o
diff --git a/board/google/chromebook_coral/coral.c b/board/google/chromebook_coral/coral.c
new file mode 100644
index 0000000..4e34710
--- /dev/null
+++ b/board/google/chromebook_coral/coral.c
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+
+int arch_misc_init(void)
+{
+	return 0;
+}
+
+/* This function is needed if CONFIG_CMDLINE is not enabled */
+int board_run_command(const char *cmdline)
+{
+	printf("No command line\n");
+
+	return 0;
+}
diff --git a/board/toradex/apalis-imx8/apalis-imx8.c b/board/toradex/apalis-imx8/apalis-imx8.c
index 3e5174e..0483041 100644
--- a/board/toradex/apalis-imx8/apalis-imx8.c
+++ b/board/toradex/apalis-imx8/apalis-imx8.c
@@ -51,7 +51,7 @@
 	return 0;
 }
 
-#if IS_ENABLED(CONFIG_DM_GPIO)
+#if CONFIG_IS_ENABLED(DM_GPIO)
 static void board_gpio_init(void)
 {
 	/* TODO */
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 1e4cf14..4e29e7b 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -228,6 +228,14 @@
 	help
 	  Print GPL license text
 
+config CMD_PMC
+	bool "pmc"
+	help
+	  Provides access to the Intel Power-Management Controller (PMC) so
+	  that its state can be examined. This does not currently support
+	  changing the state but it is still useful for debugging and seeing
+	  what is going on.
+
 config CMD_REGINFO
 	bool "reginfo"
 	depends on PPC
diff --git a/cmd/Makefile b/cmd/Makefile
index 3ac7104..12e898d 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -109,6 +109,7 @@
 obj-$(CONFIG_CMD_PCI) += pci.o
 endif
 obj-$(CONFIG_CMD_PINMUX) += pinmux.o
+obj-$(CONFIG_CMD_PMC) += pmc.o
 obj-$(CONFIG_CMD_PXE) += pxe.o pxe_utils.o
 obj-$(CONFIG_CMD_WOL) += wol.o
 obj-$(CONFIG_CMD_QFW) += qfw.o
diff --git a/cmd/pmc.c b/cmd/pmc.c
new file mode 100644
index 0000000..cafeba9
--- /dev/null
+++ b/cmd/pmc.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel PMC command
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <power/acpi_pmc.h>
+
+static int get_pmc_dev(struct udevice **devp)
+{
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_first_device_err(UCLASS_ACPI_PMC, &dev);
+	if (ret) {
+		printf("Could not find device (err=%d)\n", ret);
+		return ret;
+	}
+	ret = pmc_init(dev);
+	if (ret) {
+		printf("Could not init device (err=%d)\n", ret);
+		return ret;
+	}
+	*devp = dev;
+
+	return 0;
+}
+
+static int do_pmc_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	struct udevice *dev;
+	int ret;
+
+	ret = get_pmc_dev(&dev);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	return 0;
+}
+
+static int do_pmc_info(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	struct udevice *dev;
+	int ret;
+
+	ret = get_pmc_dev(&dev);
+	if (ret)
+		return CMD_RET_FAILURE;
+	pmc_dump_info(dev);
+
+	return 0;
+}
+
+static cmd_tbl_t cmd_pmc_sub[] = {
+	U_BOOT_CMD_MKENT(init, 0, 1, do_pmc_init, "", ""),
+	U_BOOT_CMD_MKENT(info, 0, 1, do_pmc_info, "", ""),
+};
+
+static int do_pmc(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	const cmd_tbl_t *cp;
+
+	if (argc < 2) /* no subcommand */
+		return cmd_usage(cmdtp);
+
+	cp = find_cmd_tbl(argv[1], &cmd_pmc_sub[0], ARRAY_SIZE(cmd_pmc_sub));
+	if (!cp)
+		return CMD_RET_USAGE;
+
+	return cp->cmd(cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(
+	pmc, 2, 1, do_pmc, "Power-management controller info",
+	"info - read state and show info about the PMC\n"
+	"pmc init - read state from the PMC\n"
+	);
diff --git a/cmd/x86/fsp.c b/cmd/x86/fsp.c
index b3b6630..6e485fb 100644
--- a/cmd/x86/fsp.c
+++ b/cmd/x86/fsp.c
@@ -5,23 +5,38 @@
 
 #include <common.h>
 #include <command.h>
-#include <asm/fsp1/fsp_support.h>
+#include <asm/fsp/fsp_support.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
 static int do_hdr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	struct fsp_header *hdr = fsp_find_header();
-	u32 img_addr = hdr->img_base;
-	char *sign = (char *)&hdr->sign;
+	struct fsp_header *hdr;
+	u32 img_addr;
+	char *sign;
+	uint addr;
 	int i;
 
-	printf("FSP    : binary 0x%08x, header 0x%08x\n",
-	       CONFIG_FSP_ADDR, (int)hdr);
+#ifdef CONFIG_FSP_VERSION2
+	/*
+	 * Only FSP-S is displayed. FSP-M was used in SPL but may not still be
+	 * around, and we didn't keep a pointer to it.
+	 */
+	hdr = gd->arch.fsp_s_hdr;
+	img_addr = hdr->img_base;
+	addr = img_addr;
+#else
+	addr = CONFIG_FSP_ADDR;
+	hdr = fsp_find_header();
+	img_addr = hdr->img_base;
+#endif
+	sign = (char *)&hdr->sign;
+
+	printf("FSP    : binary %08x, header %08x\n", addr, (int)hdr);
 	printf("Header : sign ");
 	for (i = 0; i < sizeof(hdr->sign); i++)
 		printf("%c", *sign++);
-	printf(", size %d, rev %d\n", hdr->hdr_len, hdr->hdr_rev);
+	printf(", size %x, rev %d\n", hdr->hdr_len, hdr->hdr_rev);
 	printf("Image  : rev ");
 	if (hdr->hdr_rev == FSP_HEADER_REVISION_1) {
 		printf("%d.%d",
@@ -34,24 +49,32 @@
 	printf(", id ");
 	for (i = 0; i < ARRAY_SIZE(hdr->img_id); i++)
 		printf("%c", hdr->img_id[i]);
-	printf(", addr 0x%08x, size %d\n", img_addr, hdr->img_size);
-	if (hdr->hdr_rev == FSP_HEADER_REVISION_2) {
+	printf(", addr %08x, size %x\n", img_addr, hdr->img_size);
+	if (hdr->hdr_rev >= FSP_HEADER_REVISION_1) {
 		printf("GFX    :%ssupported\n",
 		       hdr->img_attr & FSP_ATTR_GRAPHICS_SUPPORT ? " " : " un");
 	}
-	printf("VPD    : addr 0x%08x, size %d\n",
+	printf("VPD    : addr %08x, size %x\n",
 	       hdr->cfg_region_off + img_addr, hdr->cfg_region_size);
-	printf("\nNumber of APIs Supported : %d\n", hdr->api_num);
-	printf("\tTempRamInit : 0x%08x\n", hdr->fsp_tempram_init + img_addr);
-	printf("\tFspInit     : 0x%08x\n", hdr->fsp_init + img_addr);
-	printf("\tFspNotify   : 0x%08x\n", hdr->fsp_notify + img_addr);
-	if (hdr->hdr_rev == FSP_HEADER_REVISION_2) {
-		printf("\tMemoryInit  : 0x%08x\n",
-		       hdr->fsp_mem_init + img_addr);
-		printf("\tTempRamExit : 0x%08x\n",
-		       hdr->fsp_tempram_exit + img_addr);
-		printf("\tSiliconInit : 0x%08x\n",
-		       hdr->fsp_silicon_init + img_addr);
+	if (hdr->hdr_rev <= FSP_HEADER_REVISION_2)
+		printf("\nNumber of APIs Supported : %d\n", hdr->api_num);
+	if (hdr->fsp_tempram_init)
+		printf("\tTempRamInit : %08x\n",
+		       hdr->fsp_tempram_init + img_addr);
+	if (hdr->fsp_init)
+		printf("\tFspInit     : %08x\n", hdr->fsp_init + img_addr);
+	if (hdr->fsp_notify)
+		printf("\tFspNotify   : %08x\n", hdr->fsp_notify + img_addr);
+	if (hdr->hdr_rev >= FSP_HEADER_REVISION_1) {
+		if (hdr->fsp_mem_init)
+			printf("\tMemoryInit  : %08x\n",
+			       hdr->fsp_mem_init + img_addr);
+		if (hdr->fsp_tempram_exit)
+			printf("\tTempRamExit : %08x\n",
+			       hdr->fsp_tempram_exit + img_addr);
+		if (hdr->fsp_silicon_init)
+			printf("\tSiliconInit : %08x\n",
+			       hdr->fsp_silicon_init + img_addr);
 	}
 
 	return 0;
diff --git a/common/board_r.c b/common/board_r.c
index 5464172..e711de6 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -18,6 +18,7 @@
 #if defined(CONFIG_CMD_BEDBUG)
 #include <bedbug/type.h>
 #endif
+#include <binman.h>
 #include <command.h>
 #include <console.h>
 #include <dm.h>
@@ -310,16 +311,24 @@
 	bootstage_accum(BOOTSTATE_ID_ACCUM_DM_R);
 	if (ret)
 		return ret;
-#ifdef CONFIG_TIMER_EARLY
-	ret = dm_timer_init();
-	if (ret)
-		return ret;
-#endif
 
 	return 0;
 }
 #endif
 
+static int initr_dm_devices(void)
+{
+	int ret;
+
+	if (IS_ENABLED(CONFIG_TIMER_EARLY)) {
+		ret = dm_timer_init();
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 static int initr_bootstage(void)
 {
 	bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");
@@ -347,6 +356,14 @@
 }
 #endif
 
+static int initr_binman(void)
+{
+	if (!CONFIG_IS_ENABLED(BINMAN_FDT))
+		return 0;
+
+	return binman_init();
+}
+
 #if defined(CONFIG_MTD_NOR_FLASH)
 static int initr_flash(void)
 {
@@ -697,6 +714,11 @@
 #ifdef CONFIG_EFI_LOADER
 	efi_memory_init,
 #endif
+	initr_binman,
+#ifdef CONFIG_FSP_VERSION2
+	arch_fsp_init_r,
+#endif
+	initr_dm_devices,
 	stdio_init_tables,
 	initr_serial,
 	initr_announce,
diff --git a/common/spl/spl.c b/common/spl/spl.c
index d51dbe9..c1fce62 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -42,6 +42,12 @@
 
 /* See spl.h for information about this */
 binman_sym_declare(ulong, u_boot_any, image_pos);
+binman_sym_declare(ulong, u_boot_any, size);
+
+#ifdef CONFIG_TPL
+binman_sym_declare(ulong, spl, image_pos);
+binman_sym_declare(ulong, spl, size);
+#endif
 
 /* Define board data structure */
 static bd_t bdata __attribute__ ((section(".data")));
@@ -120,6 +126,20 @@
 #endif
 }
 
+ulong spl_get_image_pos(void)
+{
+	return spl_phase() == PHASE_TPL ?
+		binman_sym(ulong, spl, image_pos) :
+		binman_sym(ulong, u_boot_any, image_pos);
+}
+
+ulong spl_get_image_size(void)
+{
+	return spl_phase() == PHASE_TPL ?
+		binman_sym(ulong, spl, size) :
+		binman_sym(ulong, u_boot_any, size);
+}
+
 /*
  * Weak default function for board specific cleanup/preparation before
  * Linux boot. Some boards/platforms might not need it, so just provide
diff --git a/configs/chromebook_coral_defconfig b/configs/chromebook_coral_defconfig
new file mode 100644
index 0000000..566d47d
--- /dev/null
+++ b/configs/chromebook_coral_defconfig
@@ -0,0 +1,102 @@
+CONFIG_X86=y
+CONFIG_SYS_TEXT_BASE=0x1110000
+CONFIG_SYS_MALLOC_F_LEN=0x3d00
+CONFIG_SPL_SYS_MALLOC_F_LEN=0xf000
+CONFIG_NR_DRAM_BANKS=8
+CONFIG_BOOTSTAGE_STASH_ADDR=0xfef00000
+CONFIG_DEBUG_UART_BOARD_INIT=y
+CONFIG_DEBUG_UART_BASE=0xde000000
+CONFIG_DEBUG_UART_CLOCK=1843200
+CONFIG_VENDOR_GOOGLE=y
+CONFIG_TARGET_CHROMEBOOK_CORAL=y
+CONFIG_DEBUG_UART=y
+CONFIG_FSP_VERSION2=y
+CONFIG_HAVE_ACPI_RESUME=y
+CONFIG_INTEL_CAR_CQOS=y
+CONFIG_X86_OFFSET_U_BOOT=0xffe00000
+CONFIG_X86_OFFSET_SPL=0xffe80000
+CONFIG_SPL_TEXT_BASE=0xfef10000
+CONFIG_BOOTSTAGE=y
+CONFIG_SPL_BOOTSTAGE=y
+CONFIG_TPL_BOOTSTAGE=y
+CONFIG_BOOTSTAGE_REPORT=y
+CONFIG_SPL_BOOTSTAGE_RECORD_COUNT=10
+CONFIG_BOOTSTAGE_STASH=y
+CONFIG_USE_BOOTARGS=y
+CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro earlyprintk console=tty0 console=ttyS0,115200"
+CONFIG_SYS_CONSOLE_INFO_QUIET=y
+CONFIG_SPL_LOG=y
+CONFIG_LOG_DEFAULT_LEVEL=7
+CONFIG_DISPLAY_BOARDINFO_LATE=y
+CONFIG_LAST_STAGE_INIT=y
+CONFIG_BLOBLIST=y
+# CONFIG_TPL_BLOBLIST is not set
+CONFIG_BLOBLIST_ADDR=0x100000
+CONFIG_HANDOFF=y
+CONFIG_TPL_SYS_MALLOC_SIMPLE=y
+CONFIG_SPL_SEPARATE_BSS=y
+CONFIG_SPL_CPU_SUPPORT=y
+CONFIG_SPL_PCI=y
+# CONFIG_SPL_SPI_FLASH_TINY is not set
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_CPU=y
+CONFIG_CMD_PMC=y
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_PART=y
+CONFIG_CMD_READ=y
+CONFIG_CMD_SATA=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_USB=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_TIME=y
+CONFIG_CMD_SOUND=y
+CONFIG_CMD_BOOTSTAGE=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
+CONFIG_CMD_EXT2=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_EXT4_WRITE=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_MAC_PARTITION=y
+# CONFIG_SPL_MAC_PARTITION is not set
+# CONFIG_SPL_DOS_PARTITION is not set
+CONFIG_ISO_PARTITION=y
+CONFIG_EFI_PARTITION=y
+# CONFIG_SPL_EFI_PARTITION is not set
+CONFIG_DEFAULT_DEVICE_TREE="chromebook_coral"
+# CONFIG_NET is not set
+CONFIG_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_SPL_OF_TRANSLATE=y
+CONFIG_CPU=y
+CONFIG_DM_I2C=y
+CONFIG_SYS_I2C_DW=y
+CONFIG_TPL_MISC=y
+CONFIG_CROS_EC=y
+CONFIG_CROS_EC_LPC=y
+CONFIG_SPI_FLASH_WINBOND=y
+# CONFIG_X86_PCH7 is not set
+# CONFIG_X86_PCH9 is not set
+CONFIG_PINCTRL=y
+# CONFIG_SPL_PINCTRL_FULL is not set
+CONFIG_DEBUG_UART_SHIFT=2
+CONFIG_SYS_NS16550=y
+CONFIG_SOUND=y
+CONFIG_SOUND_I8254=y
+CONFIG_SOUND_RT5677=y
+CONFIG_SPI=y
+CONFIG_ICH_SPI=y
+CONFIG_TPL_SYSRESET=y
+CONFIG_TPM_TIS_LPC=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_KEYBOARD=y
+CONFIG_SPL_FS_CBFS=y
+# CONFIG_SPL_USE_TINY_PRINTF is not set
+CONFIG_TPL_USE_TINY_PRINTF=y
+CONFIG_CMD_DHRYSTONE=y
+CONFIG_TPM=y
+# CONFIG_EFI_LOADER is not set
diff --git a/configs/chromebook_samus_tpl_defconfig b/configs/chromebook_samus_tpl_defconfig
index 5ef2ecb..403b754 100644
--- a/configs/chromebook_samus_tpl_defconfig
+++ b/configs/chromebook_samus_tpl_defconfig
@@ -16,6 +16,7 @@
 CONFIG_SMP=y
 CONFIG_HAVE_VGA_BIOS=y
 CONFIG_SPL_TEXT_BASE=0xffe70000
+CONFIG_X86_OFFSET_U_BOOT=0xfff00000
 CONFIG_BOOTSTAGE=y
 CONFIG_BOOTSTAGE_REPORT=y
 CONFIG_SHOW_BOOT_PROGRESS=y
@@ -71,6 +72,8 @@
 CONFIG_TPL_MISC=y
 CONFIG_CROS_EC=y
 CONFIG_CROS_EC_LPC=y
+# CONFIG_SPL_PINCTRL is not set
+# CONFIG_TPL_PINCTRL is not set
 CONFIG_SYS_NS16550=y
 CONFIG_SOUND=y
 CONFIG_SOUND_I8254=y
diff --git a/configs/omap35_logic_defconfig b/configs/omap35_logic_defconfig
index 511c8ef..c7b67f0 100644
--- a/configs/omap35_logic_defconfig
+++ b/configs/omap35_logic_defconfig
@@ -45,6 +45,7 @@
 CONFIG_ENV_IS_IN_NAND=y
 CONFIG_SPL_DM=y
 CONFIG_SPL_OF_TRANSLATE=y
+# CONFIG_SPL_DM_GPIO is not set
 CONFIG_DM_I2C=y
 CONFIG_DM_MMC=y
 CONFIG_MMC_OMAP_HS=y
diff --git a/configs/qemu-x86_64_defconfig b/configs/qemu-x86_64_defconfig
index b88a4c5..a37ec4d 100644
--- a/configs/qemu-x86_64_defconfig
+++ b/configs/qemu-x86_64_defconfig
@@ -13,6 +13,7 @@
 CONFIG_GENERATE_PIRQ_TABLE=y
 CONFIG_GENERATE_MP_TABLE=y
 CONFIG_GENERATE_ACPI_TABLE=y
+CONFIG_X86_OFFSET_U_BOOT=0xfff00000
 CONFIG_SPL_TEXT_BASE=0xfffd0000
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_BUILD_ROM=y
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index cc536ff..b06ffce 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -83,6 +83,8 @@
 CONFIG_DEBUG_DEVRES=y
 CONFIG_ADC=y
 CONFIG_ADC_SANDBOX=y
+CONFIG_AXI=y
+CONFIG_AXI_SANDBOX=y
 CONFIG_CLK=y
 CONFIG_CPU=y
 CONFIG_DM_DEMO=y
@@ -112,6 +114,7 @@
 CONFIG_CROS_EC_LPC=y
 CONFIG_CROS_EC_SANDBOX=y
 CONFIG_CROS_EC_SPI=y
+CONFIG_IRQ=y
 CONFIG_PWRSEQ=y
 CONFIG_SPL_PWRSEQ=y
 CONFIG_I2C_EEPROM=y
@@ -203,3 +206,4 @@
 CONFIG_UNIT_TEST=y
 CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
+CONFIG_P2SB=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 64245f7..858ad04 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -132,6 +132,8 @@
 CONFIG_CROS_EC_LPC=y
 CONFIG_CROS_EC_SANDBOX=y
 CONFIG_CROS_EC_SPI=y
+CONFIG_IRQ=y
+CONFIG_P2SB=y
 CONFIG_PWRSEQ=y
 CONFIG_SPL_PWRSEQ=y
 CONFIG_I2C_EEPROM=y
diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig
index bb31b00..2a9161c 100644
--- a/configs/sandbox_flattree_defconfig
+++ b/configs/sandbox_flattree_defconfig
@@ -67,6 +67,8 @@
 CONFIG_DEBUG_DEVRES=y
 CONFIG_ADC=y
 CONFIG_ADC_SANDBOX=y
+CONFIG_AXI=y
+CONFIG_AXI_SANDBOX=y
 CONFIG_CLK=y
 CONFIG_CLK_COMPOSITE_CCF=y
 CONFIG_SANDBOX_CLK_CCF=y
@@ -98,6 +100,7 @@
 CONFIG_CROS_EC_LPC=y
 CONFIG_CROS_EC_SANDBOX=y
 CONFIG_CROS_EC_SPI=y
+CONFIG_IRQ=y
 CONFIG_PWRSEQ=y
 CONFIG_SPL_PWRSEQ=y
 CONFIG_I2C_EEPROM=y
@@ -117,6 +120,7 @@
 CONFIG_DM_PCI=y
 CONFIG_DM_PCI_COMPAT=y
 CONFIG_PCI_SANDBOX=y
+CONFIG_P2SB=y
 CONFIG_PHY=y
 CONFIG_PHY_SANDBOX=y
 CONFIG_PINCTRL=y
diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig
index 61a8ffd..138bb98 100644
--- a/configs/sandbox_spl_defconfig
+++ b/configs/sandbox_spl_defconfig
@@ -88,6 +88,8 @@
 # CONFIG_SPL_SIMPLE_BUS is not set
 CONFIG_ADC=y
 CONFIG_ADC_SANDBOX=y
+CONFIG_AXI=y
+CONFIG_AXI_SANDBOX=y
 CONFIG_CLK=y
 CONFIG_CPU=y
 CONFIG_DM_DEMO=y
@@ -118,6 +120,7 @@
 CONFIG_CROS_EC_LPC=y
 CONFIG_CROS_EC_SANDBOX=y
 CONFIG_CROS_EC_SPI=y
+CONFIG_IRQ=y
 CONFIG_PWRSEQ=y
 CONFIG_SPL_PWRSEQ=y
 CONFIG_MMC_SANDBOX=y
@@ -202,3 +205,4 @@
 CONFIG_UNIT_TEST=y
 CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
+CONFIG_P2SB=y
diff --git a/configs/tools-only_defconfig b/configs/tools-only_defconfig
index e36c9de..c698be6 100644
--- a/configs/tools-only_defconfig
+++ b/configs/tools-only_defconfig
@@ -13,6 +13,8 @@
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 CONFIG_IP_DEFRAG=y
 # CONFIG_UDP_FUNCTION_FASTBOOT is not set
+CONFIG_AXI=y
+CONFIG_AXI_SANDBOX=y
 CONFIG_SANDBOX_GPIO=y
 CONFIG_PCI=y
 CONFIG_DM_PCI=y
diff --git a/doc/board/google/chromebook_coral.rst b/doc/board/google/chromebook_coral.rst
new file mode 100644
index 0000000..515fd06
--- /dev/null
+++ b/doc/board/google/chromebook_coral.rst
@@ -0,0 +1,241 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Simon Glass <sjg@chromium.org>
+
+Chromebook Coral
+================
+
+Coral is a Chromebook (or really about 20 different Chromebooks) which use the
+Intel Apollo Lake platform (APL). The 'reef' Chromebooks use the same APL SoC so
+should also work. Some later ones based on Glacier Lake (GLK) need various
+changes in GPIOs, etc. but are very similar.
+
+It is hoped that this port can enable ports to embedded APL boards which are
+starting to appear.
+
+Note that booting U-Boot on APL is already supported by coreboot and
+Slim Bootloader. This documentation refers to a 'bare metal' port.
+
+
+Boot flow - TPL
+---------------
+
+Apollo Lake boots via an IFWI (Integrated Firmware Image). TPL is placed in
+this, in the IBBL entry.
+
+On boot, an on-chip microcontroller called the CSE (Converged Security Engine)
+sets up some SDRAM at ffff8000 and loads the TPL image to that address. The
+SRAM extends up to the top of 32-bit address space, but the last 2KB is the
+start16 region, so the TPL image must be 30KB at most, and CONFIG_TPL_TEXT_BASE
+must be ffff8000. Actually the start16 region is small and it could probably
+move from f800 to fe00, providing another 1.5KB, but TPL is only about 19KB so
+there is no need to change it at present. The size limit is enforced by
+CONFIG_TPL_SIZE_LIMIT to avoid producing images that won't boot.
+
+TPL (running from start.S) first sets up CAR (Cache-as-RAM) which provides
+larger area of RAM for use while booting. CAR is mapped at CONFIG_SYS_CAR_ADDR
+(fef00000) and is 768KB in size. It then sets up the stack in the botttom 64KB
+of this space (i.e. below fef10000). This means that the stack and early
+malloc() region in TPL can be 64KB at most.
+
+TPL operates without CONFIG_TPL_PCI enabled so PCI config access must use the
+x86-specific functions pci_x86_write_config(), etc. SPL creates a simple-bus
+device so that PCI devices are bound by driver model. Then arch_cpu_init_tpl()
+is called to early init on various devices. This includes placing PCI devices
+at hard-coded addresses in the memory map. PCI auto-config is not used.
+
+Most of the 16KB ROM is mapped into the very top of memory, except for the
+Intel descriptor (first 4KB) and the space for SRAM as above.
+
+TPL does not set up a bloblist since at present it does not have anything to
+pass to SPL.
+
+Once TPL is done it loads SPL from ROM using either the memory-mapped SPI or by
+using the Intel fast SPI driver. SPL is loaded into CAR, at the address given
+by CONFIG_SPL_TEXT_BASE, which is normally fef10000.
+
+Note that booting using the SPI driver results in an TPL image that is about
+26KB in size instead of 19KB. Also boot speed is worse by about 340ms. If you
+really want to use the driver, enable CONFIG_APL_SPI_FLASH_BOOT and set
+BOOT_FROM_FAST_SPI_FLASH to true[2].
+
+
+Boot flow - SPL
+---------------
+
+SPL (running from start_from_tpl.S) continues to use the same stack as TPL.
+It calls arch_cpu_init_spl() to set up a few devices, then init_dram() loads
+the FSP-M binary into CAR and runs to, to set up SDRAM. The address of the
+output 'HOB' list (Hand-off-block) is stored into gd->arch.hob_list for parsing.
+There is a 2GB chunk of SDRAM starting at 0 and the rest is at 4GB.
+
+PCI auto-config is not used in SPL either, but CONFIG_SPL_PCI is defined, so
+proper PCI access is available and normal dm_pci_read_config() calls can be
+used. However PCI auto-config is not used so the same static memory mapping set
+up by TPL is still active.
+
+SPL on x86 always runs with CONFIG_SPL_SEPARATE_BSS=y and BSS is at 120000
+(see u-boot-spl.lds). This works because SPL doesn't access BSS until after
+board_init_r(), as per the rules, and DRAM is available then.
+
+SPL sets up a bloblist and passes the SPL hand-off information to U-Boot proper.
+This includes a pointer to the HOB list as well as DRAM information. See
+struct arch_spl_handoff. The bloblist address is set by CONFIG_BLOBLIST_ADDR,
+normally 100000.
+
+SPL uses SPI flash to update the MRC caches in ROM. This speeds up subsequent
+boots. Be warned that SPL can take 30 seconds without this cache! This is a
+known issue with Intel SoCs with modern DRAM and apparently cannot be improved.
+The MRC caches are used to work around this.
+
+Once SPL is finished it loads U-Boot into SDRAM at CONFIG_SYS_TEXT_BASE, which
+is normally 1110000. Note that CAR is still active.
+
+
+Boot flow - U-Boot pre-relocation
+---------------------------------
+
+U-Boot (running from start_from_spl.S) starts running in RAM and uses the same
+stack as SPL. It does various init activities before relocation. Notably
+arch_cpu_init_dm() sets up the pin muxing for the chip using a very large table
+in the device tree.
+
+PCI auto-config is not used before relocation, but CONFIG_PCI of course is
+defined, so proper PCI access is available. The same static memory mapping set
+up by TPL is still active until relocation.
+
+As per usual, U-Boot allocates memory at the top of available RAM (a bit below
+2GB in this case) and copies things there ready to relocate itself. Notably
+reserve_arch() does not reserve space for the HOB list returned by FSP-M since
+this is already located in RAM.
+
+U-Boot then shuts down CAR and jumps to its relocated version.
+
+
+Boot flow - U-Boot post-relocation
+---------------------------------
+
+U-Boot starts up normally, running near the top of RAM. After driver model is
+running, arch_fsp_init_r() is called which loads and runs the FSP-S binary.
+This updates the HOB list to include graphics information, used by the fsp_video
+driver.
+
+PCI autoconfig is done and a few devices are probed to complete init. Most
+others are started only when they are used.
+
+Note that FSP-S is supposed to run after CAR has been shut down, which happens
+immediately before U-Boot starts up in its relocated position. Therefore we
+cannot run FSP-S before relocation. On the other hand we must run it before
+PCI auto-config is done, since FSP-S may show or hide devices. The first device
+that probes PCI after relocation is the serial port, in initr_serial(), so FSP-S
+must run before that. A corollary is that loading FSP-S must be done without
+using the SPI driver, to avoid probing PCI and causing an autoconfig, so
+memory-mapped reading is always used for FSP-S.
+
+It would be possible to tear down CAR in SPL instead of U-Boot. The SPL handoff
+information could make sure it does not include any pointers into CAR (in fact
+it doesn't). But tearing down CAR in U-Boot allows the initial state used by TPL
+and SPL to be read by U-Boot, which seems useful. It also matches how older
+platforms start up (those that don't use SPL).
+
+
+Performance
+-----------
+
+Bootstage is used through all phases of U-Boot to keep accurate timimgs for
+boot. Use 'bootstage report' in U-Boot to see the report, e.g.:
+
+Timer summary in microseconds (16 records):
+       Mark    Elapsed  Stage
+          0          0  reset
+    155,325    155,325  TPL
+    204,014     48,689  end TPL
+    204,385        371  SPL
+    738,633    534,248  end SPL
+    739,161        528  board_init_f
+    842,764    103,603  board_init_r
+  1,166,233    323,469  main_loop
+  1,166,283         50  id=175
+
+Accumulated time:
+                    62  fast_spi
+                   202  dm_r
+                 7,779  dm_spl
+                15,555  dm_f
+               208,357  fsp-m
+               239,847  fsp-s
+               292,143  mmap_spi
+
+CPU performance is about 3500 DMIPS:
+
+=> dhry
+1000000 iterations in 161 ms: 6211180/s, 3535 DMIPS
+
+
+Partial memory map
+------------------
+
+ffffffff	Top of ROM (and last byte of 32-bit address space)
+ffff8000	TPL loaded here (from IFWI)
+ff000000	Bottom of ROM
+fefc000		 Top of CAR region
+fef96000	Stack for FSP-M
+fef40000 59000	FSP-M
+fef11000	SPL loaded here
+fef10000	CONFIG_BLOBLIST_ADDR
+fef10000	Stack top in TPL, SPL and U-Boot before relocation
+fef00000  1000	CONFIG_BOOTSTAGE_STASH_ADDR
+fef00000	Base of CAR region
+
+   f0000	CONFIG_ROM_TABLE_ADDR
+  120000	BSS (defined in u-boot-spl.lds)
+  200000	FSP-S (which is run after U-Boot is relocated)
+ 1110000	CONFIG_SYS_TEXT_BASE
+
+
+Supported peripherals
+---------------------
+
+- UART
+- SPI flash
+- Video
+- MMC (dev 0) and micro-SD (dev 1)
+- Chrome OS EC
+- Keyboard
+- USB
+
+
+To do
+-----
+
+- Finish peripherals
+   - left-side USB
+   - USB-C
+   - Cr50 (security chip: a basic driver is running but not included here)
+   - I2C (driver exists but not enabled in device tree)
+   - Sound (Intel I2S support exists, but need da7219 driver)
+   - RTC (driver exists but not enabled in device tree)
+   - Various minor features supported by LPC, etc.
+- Booting Chrome OS, e.g. with verified boot
+- Integrate with Chrome OS vboot
+- Improvements to booting from coreboot (i.e. as a coreboot target)
+- Use FSP-T binary instead of our own CAR implementation
+- Use the official FSP package instead of the coreboot one
+- Enable all CPU cores
+- Suspend / resume
+- ACPI
+
+
+Credits
+-------
+
+This is a spare-time project conducted slowly over a long period of time.
+
+Much of the code for this port came from Coreboot, an open-source firmware
+project similar to U-Boot's SPL in terms of features.
+
+Also see [2] for information about the boot flow used by coreboot. It is
+similar, but has an extra postcar stage. U-Boot doesn't need this since it
+supports relocating itself in memory.
+
+
+[2] Intel PDF https://www.coreboot.org/images/2/23/Apollolake_SoC.pdf
diff --git a/doc/board/google/index.rst b/doc/board/google/index.rst
index 7f557fe..061c797 100644
--- a/doc/board/google/index.rst
+++ b/doc/board/google/index.rst
@@ -6,5 +6,6 @@
 .. toctree::
    :maxdepth: 2
 
+   chromebook_coral
    chromebook_link
    chromebook_samus
diff --git a/doc/device-tree-bindings/gpio/intel,apl-gpio.txt b/doc/device-tree-bindings/gpio/intel,apl-gpio.txt
new file mode 100644
index 0000000..e27a40b
--- /dev/null
+++ b/doc/device-tree-bindings/gpio/intel,apl-gpio.txt
@@ -0,0 +1,55 @@
+Intel Apollo Lake GPIO controller
+
+The Apollo Lake (APL) GPIO controller is used to control GPIO functions of
+the pins.
+
+Required properties:
+- compatible: "intel,apl-gpio"
+- #gpio-cells: Should be 2. The syntax of the gpio specifier used by client
+  nodes should be the following with values derived from the SoC user manual.
+     <[phandle of the gpio controller node]
+      [pin number within the gpio controller]
+      [flags]>
+
+  Values for gpio specifier:
+  - Pin number: is a GPIO pin number between 0 and 244
+  - Flags: GPIO_ACTIVE_HIGH or GPIO_ACTIVE_LOW
+
+- gpio-controller: Specifies that the node is a gpio controller.
+
+Example:
+
+...
+{
+	p2sb: p2sb@d,0 {
+		reg = <0x02006810 0 0 0 0>;
+		compatible = "intel,apl-p2sb";
+		early-regs = <IOMAP_P2SB_BAR 0x100000>;
+
+		north {
+			compatible = "intel,apl-pinctrl";
+			intel,p2sb-port-id = <PID_GPIO_N>;
+			gpio_n: gpio-n {
+				compatible = "intel,gpio";
+				gpio-controller;
+				#gpio-cells = <2>;
+			};
+		};
+	};
+
+	i2c_2: i2c2@16,2 {
+		compatible = "intel,apl-i2c", "snps,designware-i2c-pci";
+		reg = <0x0200b210 0 0 0 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-frequency = <400000>;
+		tpm@50 {
+			reg = <0x50>;
+			compatible = "google,cr50";
+			u-boot,i2c-offset-len = <0>;
+			ready-gpio = <&gpio_n GPIO_28 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+};
+...
diff --git a/doc/device-tree-bindings/pci/x86-pci.txt b/doc/device-tree-bindings/pci/x86-pci.txt
new file mode 100644
index 0000000..3aa5bd9
--- /dev/null
+++ b/doc/device-tree-bindings/pci/x86-pci.txt
@@ -0,0 +1,24 @@
+x86 PCI DT details:
+===================
+
+Some options are available to affect how PCI operates on x86.
+
+Optional properties:
+- u-boot,skip-auto-config-until-reloc : Don't set up PCI configuration until
+	after U-Boot has relocated. Normally if PCI is used before relocation,
+	this happens before relocation also. Some platforms set up static
+	configuration in TPL/SPL to reduce code size and boot time, since these
+	phases only know about a small subset of PCI devices.
+
+Example:
+
+pci {
+	compatible = "pci-x86";
+	#address-cells = <3>;
+	#size-cells = <2>;
+	u-boot,dm-pre-reloc;
+	ranges = <0x02000000 0x0 0xc0000000 0xc0000000 0 0x10000000
+		0x42000000 0x0 0xb0000000 0xb0000000 0 0x10000000
+		0x01000000 0x0 0x1000 0x1000 0 0xefff>;
+	u-boot,skip-auto-config-until-reloc;
+};
diff --git a/doc/device-tree-bindings/pinctrl/intel,apl-pinctrl.txt b/doc/device-tree-bindings/pinctrl/intel,apl-pinctrl.txt
new file mode 100644
index 0000000..cd7f8a0
--- /dev/null
+++ b/doc/device-tree-bindings/pinctrl/intel,apl-pinctrl.txt
@@ -0,0 +1,39 @@
+* Intel Apollo Lake pin controller
+
+The Apollo Lake (APL) pin controller is used to select the function of a pin
+and to configure it.
+
+Required properties:
+- compatible: "intel,apl-pinctrl"
+- intel,p2sb-port-id: Port ID number within the parent P2SB
+- reg: PCI address of the controller
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices.
+
+Optional subnodes:
+
+GPIO nodes may be added as children of the pinctrl nodes. See intel,apl-gpio
+for the binding.
+
+
+Example:
+
+...
+{
+	p2sb: p2sb@d,0 {
+		reg = <0x02006810 0 0 0 0>;
+		compatible = "intel,apl-p2sb";
+		early-regs = <IOMAP_P2SB_BAR 0x100000>;
+
+		n {
+			compatible = "intel,apl-pinctrl";
+			intel,p2sb-port-id = <PID_GPIO_N>;
+			gpio_n: gpio-n {
+				compatible = "intel,apl-gpio";
+				#gpio-cells = <2>;
+			};
+		};
+	};
+};
+...
diff --git a/doc/driver-model/of-plat.rst b/doc/driver-model/of-plat.rst
index 557957d..034a68b 100644
--- a/doc/driver-model/of-plat.rst
+++ b/doc/driver-model/of-plat.rst
@@ -279,6 +279,12 @@
     };
 
 
+Note that struct mmc_platdata is defined in the C file, not in a header. This
+is to avoid needing to include dt-structs.h in a header file. The idea is to
+keep the use of each of-platdata struct to the smallest possible code area.
+There is just one driver C file for each struct, that can convert from the
+of-platdata struct to the standard one used by the driver.
+
 In the case where SPL_OF_PLATDATA is enabled, platdata_auto_alloc_size is
 still used to allocate space for the platform data. This is different from
 the normal behaviour and is triggered by the use of of-platdata (strictly
diff --git a/drivers/Makefile b/drivers/Makefile
index e977f19..cb8c215 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -25,6 +25,7 @@
 obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox/
 obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/
 obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm/
+obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC) += power/acpi_pmc/
 
 ifndef CONFIG_TPL_BUILD
 ifdef CONFIG_SPL_BUILD
diff --git a/drivers/core/util.c b/drivers/core/util.c
index 7dc1a2a..69f8375 100644
--- a/drivers/core/util.c
+++ b/drivers/core/util.c
@@ -4,7 +4,9 @@
  */
 
 #include <common.h>
+#include <dm/device.h>
 #include <dm/ofnode.h>
+#include <dm/read.h>
 #include <dm/util.h>
 #include <linux/libfdt.h>
 #include <vsprintf.h>
@@ -58,3 +60,21 @@
 #endif
 }
 #endif
+
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+int pci_get_devfn(struct udevice *dev)
+{
+	struct fdt_pci_addr addr;
+	int ret;
+
+	/* Extract the devfn from fdt_pci_addr */
+	ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG,
+				   "reg", &addr);
+	if (ret) {
+		if (ret != -ENOENT)
+			return -EINVAL;
+	}
+
+	return addr.phys_hi & 0xff00;
+}
+#endif
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index c1ad5d6..1de6f52 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -14,6 +14,28 @@
 	  particular GPIOs that they provide. The uclass interface
 	  is defined in include/asm-generic/gpio.h.
 
+config SPL_DM_GPIO
+	bool "Enable Driver Model for GPIO drivers in SPL"
+	depends on DM_GPIO && SPL_DM && SPL_GPIO_SUPPORT
+	default y
+	help
+	  Enable driver model for GPIO access in SPL. The standard GPIO
+	  interface (gpio_get_value(), etc.) is then implemented by
+	  the GPIO uclass. Drivers provide methods to query the
+	  particular GPIOs that they provide. The uclass interface
+	  is defined in include/asm-generic/gpio.h.
+
+config TPL_DM_GPIO
+	bool "Enable Driver Model for GPIO drivers in TPL"
+	depends on DM_GPIO && TPL_DM && TPL_GPIO_SUPPORT
+	default y
+	help
+	  Enable driver model for GPIO access in TPL. The standard GPIO
+	  interface (gpio_get_value(), etc.) is then implemented by
+	  the GPIO uclass. Drivers provide methods to query the
+	  particular GPIOs that they provide. The uclass interface
+	  is defined in include/asm-generic/gpio.h.
+
 config GPIO_HOG
 	bool "Enable GPIO hog support"
 	depends on DM_GPIO
@@ -82,6 +104,15 @@
 	  driver from the common Intel ICH6 driver. It supports a total of
 	  95 GPIOs which can be configured from the device tree.
 
+config INTEL_GPIO
+	bool "Intel generic GPIO driver"
+	depends on DM_GPIO
+	help
+	  Say yes here to select Intel generic GPIO driver. This controller
+	  supports recent chips (e.g. Apollo Lake). It permits basic GPIO
+	  control including setting pins to input/output. It makes use of its
+	  parent pinctrl driver to actually effect changes.
+
 config INTEL_ICH6_GPIO
 	bool "Intel ICH6 compatible legacy GPIO driver"
 	depends on DM_GPIO
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index ccc49e2..449046b 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -7,14 +7,17 @@
 obj-$(CONFIG_DWAPB_GPIO)	+= dwapb_gpio.o
 obj-$(CONFIG_AXP_GPIO)		+= axp_gpio.o
 endif
-obj-$(CONFIG_DM_GPIO)		+= gpio-uclass.o
+obj-$(CONFIG_$(SPL_TPL_)DM_GPIO) += gpio-uclass.o
 
 obj-$(CONFIG_$(SPL_)DM_PCA953X)	+= pca953x_gpio.o
+ifdef CONFIG_$(SPL_TPL_)GPIO
 obj-$(CONFIG_DM_74X164)		+= 74x164_gpio.o
+endif
 
 obj-$(CONFIG_AT91_GPIO)	+= at91_gpio.o
 obj-$(CONFIG_ATMEL_PIO4)	+= atmel_pio4.o
 obj-$(CONFIG_BCM6345_GPIO)	+= bcm6345_gpio.o
+obj-$(CONFIG_INTEL_GPIO)	+= intel_gpio.o
 obj-$(CONFIG_INTEL_ICH6_GPIO)	+= intel_ich6_gpio.o
 obj-$(CONFIG_INTEL_BROADWELL_GPIO)	+= intel_broadwell_gpio.o
 obj-$(CONFIG_KIRKWOOD_GPIO)	+= kw_gpio.o
diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c
index dbfed72..5ea3e77 100644
--- a/drivers/gpio/at91_gpio.c
+++ b/drivers/gpio/at91_gpio.c
@@ -210,7 +210,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 static bool at91_get_port_output(struct at91_port *at91_port, int offset)
 {
 	u32 mask, val;
@@ -457,7 +457,7 @@
 	return 0;
 }
 
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
 /* Common GPIO API */
 
 int gpio_request(unsigned gpio, const char *label)
@@ -499,7 +499,7 @@
 }
 #endif
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 
 struct at91_port_priv {
 	struct at91_port *regs;
diff --git a/drivers/gpio/atmel_pio4.c b/drivers/gpio/atmel_pio4.c
index 95a189a..8e6f32d 100644
--- a/drivers/gpio/atmel_pio4.c
+++ b/drivers/gpio/atmel_pio4.c
@@ -168,7 +168,7 @@
 	return (readl(&port_base->pdsr) & mask) ? 1 : 0;
 }
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 
 struct atmel_pioctrl_data {
 	u32 nbanks;
diff --git a/drivers/gpio/da8xx_gpio.c b/drivers/gpio/da8xx_gpio.c
index 0a50c68..bd5a366 100644
--- a/drivers/gpio/da8xx_gpio.c
+++ b/drivers/gpio/da8xx_gpio.c
@@ -15,7 +15,7 @@
 
 #include "da8xx_gpio.h"
 
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
 #include <asm/arch/hardware.h>
 #include <asm/arch/davinci_misc.h>
 
@@ -377,7 +377,8 @@
 	_gpio_set_value(bank, gpio, value);
 	return 0;
 }
-#ifndef CONFIG_DM_GPIO
+
+#if !CONFIG_IS_ENABLED(DM_GPIO)
 
 void gpio_info(void)
 {
@@ -428,7 +429,7 @@
 	return _gpio_set_value(bank, gpio, value);
 }
 
-#else /* CONFIG_DM_GPIO */
+#else /* DM_GPIO */
 
 static struct davinci_gpio *davinci_get_gpio_bank(struct udevice *dev, unsigned int offset)
 {
diff --git a/drivers/gpio/da8xx_gpio.h b/drivers/gpio/da8xx_gpio.h
index 1de9ec7..849e8d2 100644
--- a/drivers/gpio/da8xx_gpio.h
+++ b/drivers/gpio/da8xx_gpio.h
@@ -28,7 +28,7 @@
 #define MAX_NUM_GPIOS		144
 #define GPIO_BIT(gp)		((gp) & 0x1F)
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 
 /* Information about a GPIO bank */
 struct davinci_gpio_platdata {
diff --git a/drivers/gpio/intel_gpio.c b/drivers/gpio/intel_gpio.c
new file mode 100644
index 0000000..4bf1c9d
--- /dev/null
+++ b/drivers/gpio/intel_gpio.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <p2sb.h>
+#include <pch.h>
+#include <pci.h>
+#include <syscon.h>
+#include <asm/cpu.h>
+#include <asm/gpio.h>
+#include <asm/intel_pinctrl.h>
+#include <asm/intel_pinctrl_defs.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <asm/arch/gpio.h>
+#include <dt-bindings/gpio/x86-gpio.h>
+
+static int intel_gpio_direction_input(struct udevice *dev, uint offset)
+{
+	struct udevice *pinctrl = dev_get_parent(dev);
+	uint config_offset = intel_pinctrl_get_config_reg_addr(pinctrl, offset);
+
+	pcr_clrsetbits32(pinctrl, config_offset,
+			 PAD_CFG0_MODE_MASK | PAD_CFG0_TX_STATE |
+				  PAD_CFG0_RX_DISABLE,
+			 PAD_CFG0_MODE_GPIO | PAD_CFG0_TX_DISABLE);
+
+	return 0;
+}
+
+static int intel_gpio_direction_output(struct udevice *dev, uint offset,
+				       int value)
+{
+	struct udevice *pinctrl = dev_get_parent(dev);
+	uint config_offset = intel_pinctrl_get_config_reg_addr(pinctrl, offset);
+
+	pcr_clrsetbits32(dev, config_offset,
+			 PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE |
+				  PAD_CFG0_TX_DISABLE,
+			 PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE |
+				  (value ? PAD_CFG0_TX_STATE : 0));
+
+	return 0;
+}
+
+static int intel_gpio_get_value(struct udevice *dev, uint offset)
+{
+	struct udevice *pinctrl = dev_get_parent(dev);
+	uint mode, rx_tx;
+	u32 reg;
+
+	reg = intel_pinctrl_get_config_reg(pinctrl, offset);
+	mode = (reg & PAD_CFG0_MODE_MASK) >> PAD_CFG0_MODE_SHIFT;
+	if (!mode) {
+		rx_tx = reg & (PAD_CFG0_TX_DISABLE | PAD_CFG0_RX_DISABLE);
+		if (rx_tx == PAD_CFG0_TX_DISABLE)
+			return mode & PAD_CFG0_RX_STATE_BIT ? 1 : 0;
+		else if (rx_tx == PAD_CFG0_RX_DISABLE)
+			return mode & PAD_CFG0_TX_STATE_BIT ? 1 : 0;
+	}
+
+	return 0;
+}
+
+static int intel_gpio_set_value(struct udevice *dev, unsigned offset, int value)
+{
+	struct udevice *pinctrl = dev_get_parent(dev);
+	uint config_offset = intel_pinctrl_get_config_reg_addr(pinctrl, offset);
+
+	pcr_clrsetbits32(dev, config_offset, PAD_CFG0_TX_STATE,
+			 value ? PAD_CFG0_TX_STATE : 0);
+
+	return 0;
+}
+
+static int intel_gpio_get_function(struct udevice *dev, uint offset)
+{
+	struct udevice *pinctrl = dev_get_parent(dev);
+	uint mode, rx_tx;
+	u32 reg;
+
+	reg = intel_pinctrl_get_config_reg(pinctrl, offset);
+	mode = (reg & PAD_CFG0_MODE_MASK) >> PAD_CFG0_MODE_SHIFT;
+	if (!mode) {
+		rx_tx = reg & (PAD_CFG0_TX_DISABLE | PAD_CFG0_RX_DISABLE);
+		if (rx_tx == PAD_CFG0_TX_DISABLE)
+			return GPIOF_INPUT;
+		else if (rx_tx == PAD_CFG0_RX_DISABLE)
+			return GPIOF_OUTPUT;
+	}
+
+	return GPIOF_FUNC;
+}
+
+static int intel_gpio_xlate(struct udevice *orig_dev, struct gpio_desc *desc,
+			    struct ofnode_phandle_args *args)
+{
+	struct udevice *pinctrl, *dev;
+	int gpio, ret;
+
+	/*
+	 * GPIO numbers are global in the device tree so it doesn't matter
+	 * which one is used
+	 */
+	gpio = args->args[0];
+	ret = intel_pinctrl_get_pad(gpio, &pinctrl, &desc->offset);
+	if (ret)
+		return log_msg_ret("bad", ret);
+	device_find_first_child(pinctrl, &dev);
+	if (!dev)
+		return log_msg_ret("no child", -ENOENT);
+	desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
+	desc->dev = dev;
+
+	return 0;
+}
+
+static int intel_gpio_probe(struct udevice *dev)
+{
+	return 0;
+}
+
+static int intel_gpio_ofdata_to_platdata(struct udevice *dev)
+{
+	struct gpio_dev_priv *upriv = dev_get_uclass_priv(dev);
+	struct intel_pinctrl_priv *pinctrl_priv = dev_get_priv(dev->parent);
+	const struct pad_community *comm = pinctrl_priv->comm;
+
+	upriv->gpio_count = comm->last_pad - comm->first_pad + 1;
+	upriv->bank_name = dev->name;
+
+	return 0;
+}
+
+static const struct dm_gpio_ops gpio_intel_ops = {
+	.direction_input	= intel_gpio_direction_input,
+	.direction_output	= intel_gpio_direction_output,
+	.get_value		= intel_gpio_get_value,
+	.set_value		= intel_gpio_set_value,
+	.get_function		= intel_gpio_get_function,
+	.xlate			= intel_gpio_xlate,
+};
+
+static const struct udevice_id intel_intel_gpio_ids[] = {
+	{ .compatible = "intel,gpio" },
+	{ }
+};
+
+U_BOOT_DRIVER(gpio_intel) = {
+	.name	= "gpio_intel",
+	.id	= UCLASS_GPIO,
+	.of_match = intel_intel_gpio_ids,
+	.ops	= &gpio_intel_ops,
+	.ofdata_to_platdata	= intel_gpio_ofdata_to_platdata,
+	.probe	= intel_gpio_probe,
+};
diff --git a/drivers/gpio/mxc_gpio.c b/drivers/gpio/mxc_gpio.c
index 64ab7a3..6592d14 100644
--- a/drivers/gpio/mxc_gpio.c
+++ b/drivers/gpio/mxc_gpio.c
@@ -30,7 +30,7 @@
 	struct gpio_regs *regs;
 };
 
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
 #define GPIO_TO_PORT(n)		((n) / 32)
 
 /* GPIO port description */
@@ -161,7 +161,7 @@
 }
 #endif
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 #include <fdtdec.h>
 static int mxc_gpio_is_output(struct gpio_regs *regs, int offset)
 {
diff --git a/drivers/gpio/mxs_gpio.c b/drivers/gpio/mxs_gpio.c
index 5795155..77778e9 100644
--- a/drivers/gpio/mxs_gpio.c
+++ b/drivers/gpio/mxs_gpio.c
@@ -128,7 +128,7 @@
 
 	return (bank << MXS_PAD_BANK_SHIFT) | (pin << MXS_PAD_PIN_SHIFT);
 }
-#else /* CONFIG_DM_GPIO */
+#else /* DM_GPIO */
 #include <dm.h>
 #include <asm/gpio.h>
 #include <dt-structs.h>
@@ -312,4 +312,4 @@
 	.ofdata_to_platdata = mxs_ofdata_to_platdata,
 #endif
 };
-#endif /* CONFIG_DM_GPIO */
+#endif /* DM_GPIO */
diff --git a/drivers/gpio/omap_gpio.c b/drivers/gpio/omap_gpio.c
index 0031415..4249850 100644
--- a/drivers/gpio/omap_gpio.c
+++ b/drivers/gpio/omap_gpio.c
@@ -30,7 +30,7 @@
 #define OMAP_GPIO_DIR_OUT	0
 #define OMAP_GPIO_DIR_IN	1
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 
 #define GPIO_PER_BANK			32
 
@@ -121,7 +121,7 @@
 	return (__raw_readl(reg) & (1 << gpio)) != 0;
 }
 
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
 
 static inline const struct gpio_bank *get_gpio_bank(int gpio)
 {
@@ -377,4 +377,4 @@
 #endif
 };
 
-#endif /* CONFIG_DM_GPIO */
+#endif /* !DM_GPIO */
diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c
index 719efc2..9c3a442 100644
--- a/drivers/gpio/sunxi_gpio.c
+++ b/drivers/gpio/sunxi_gpio.c
@@ -28,7 +28,7 @@
 	int gpio_count;
 };
 
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
 static int sunxi_gpio_output(u32 pin, u32 val)
 {
 	u32 dat;
@@ -116,7 +116,7 @@
 		return -1;
 	return group * 32 + pin;
 }
-#endif
+#endif /* DM_GPIO */
 
 int sunxi_name_to_gpio_bank(const char *name)
 {
@@ -132,7 +132,7 @@
 	return -1;
 }
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 /* TODO(sjg@chromium.org): Remove this function and use device tree */
 int sunxi_name_to_gpio(const char *name)
 {
@@ -373,4 +373,4 @@
 	.bind	= gpio_sunxi_bind,
 	.probe	= gpio_sunxi_probe,
 };
-#endif
+#endif /* DM_GPIO */
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index c2f75d8..f5a471f 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -14,6 +14,9 @@
 obj-$(CONFIG_SYS_I2C_CADENCE) += i2c-cdns.o
 obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o
 obj-$(CONFIG_SYS_I2C_DW) += designware_i2c.o
+ifdef CONFIG_DM_PCI
+obj-$(CONFIG_SYS_I2C_DW) += designware_i2c_pci.o
+endif
 obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o
 obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o
 obj-$(CONFIG_SYS_I2C_INTEL) += intel_i2c.o
diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c
index 6daa90e..b8cdd1c 100644
--- a/drivers/i2c/designware_i2c.c
+++ b/drivers/i2c/designware_i2c.c
@@ -13,34 +13,6 @@
 #include <asm/io.h>
 #include "designware_i2c.h"
 
-struct dw_scl_sda_cfg {
-	u32 ss_hcnt;
-	u32 fs_hcnt;
-	u32 ss_lcnt;
-	u32 fs_lcnt;
-	u32 sda_hold;
-};
-
-#ifdef CONFIG_X86
-/* BayTrail HCNT/LCNT/SDA hold time */
-static struct dw_scl_sda_cfg byt_config = {
-	.ss_hcnt = 0x200,
-	.fs_hcnt = 0x55,
-	.ss_lcnt = 0x200,
-	.fs_lcnt = 0x99,
-	.sda_hold = 0x6,
-};
-#endif
-
-struct dw_i2c {
-	struct i2c_regs *regs;
-	struct dw_scl_sda_cfg *scl_sda_cfg;
-	struct reset_ctl_bulk resets;
-#if CONFIG_IS_ENABLED(CLK)
-	struct clk clk;
-#endif
-};
-
 #ifdef CONFIG_SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED
 static int  dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
 {
@@ -90,7 +62,9 @@
 	unsigned int ena;
 	int i2c_spd;
 
-	if (speed >= I2C_MAX_SPEED)
+	/* Allow max speed if there is no config, or the config allows it */
+	if (speed >= I2C_MAX_SPEED &&
+	    (!scl_sda_cfg || scl_sda_cfg->has_max_speed))
 		i2c_spd = IC_SPEED_MODE_MAX;
 	else if (speed >= I2C_FAST_SPEED)
 		i2c_spd = IC_SPEED_MODE_FAST;
@@ -106,7 +80,6 @@
 	cntl = (readl(&i2c_base->ic_con) & (~IC_CON_SPD_MSK));
 
 	switch (i2c_spd) {
-#ifndef CONFIG_X86 /* No High-speed for BayTrail yet */
 	case IC_SPEED_MODE_MAX:
 		cntl |= IC_CON_SPD_SS;
 		if (scl_sda_cfg) {
@@ -119,7 +92,6 @@
 		writel(hcnt, &i2c_base->ic_hs_scl_hcnt);
 		writel(lcnt, &i2c_base->ic_hs_scl_lcnt);
 		break;
-#endif
 
 	case IC_SPEED_MODE_STANDARD:
 		cntl |= IC_CON_SPD_SS;
@@ -565,24 +537,19 @@
 	return ret;
 }
 
-static int designware_i2c_probe(struct udevice *bus)
+static int designware_i2c_ofdata_to_platdata(struct udevice *bus)
 {
 	struct dw_i2c *priv = dev_get_priv(bus);
-	int ret;
 
-	if (device_is_on_pci_bus(bus)) {
-#ifdef CONFIG_DM_PCI
-		/* Save base address from PCI BAR */
-		priv->regs = (struct i2c_regs *)
-			dm_pci_map_bar(bus, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
-#ifdef CONFIG_X86
-		/* Use BayTrail specific timing values */
-		priv->scl_sda_cfg = &byt_config;
-#endif
-#endif
-	} else {
-		priv->regs = (struct i2c_regs *)devfdt_get_addr_ptr(bus);
-	}
+	priv->regs = (struct i2c_regs *)devfdt_get_addr_ptr(bus);
+
+	return 0;
+}
+
+int designware_i2c_probe(struct udevice *bus)
+{
+	struct dw_i2c *priv = dev_get_priv(bus);
+	int ret;
 
 	ret = reset_get_bulk(bus, &priv->resets);
 	if (ret)
@@ -606,7 +573,7 @@
 	return __dw_i2c_init(priv->regs, 0, 0);
 }
 
-static int designware_i2c_remove(struct udevice *dev)
+int designware_i2c_remove(struct udevice *dev)
 {
 	struct dw_i2c *priv = dev_get_priv(dev);
 
@@ -618,30 +585,7 @@
 	return reset_release_bulk(&priv->resets);
 }
 
-static int designware_i2c_bind(struct udevice *dev)
-{
-	static int num_cards;
-	char name[20];
-
-	/* Create a unique device name for PCI type devices */
-	if (device_is_on_pci_bus(dev)) {
-		/*
-		 * ToDo:
-		 * Setting req_seq in the driver is probably not recommended.
-		 * But without a DT alias the number is not configured. And
-		 * using this driver is impossible for PCIe I2C devices.
-		 * This can be removed, once a better (correct) way for this
-		 * is found and implemented.
-		 */
-		dev->req_seq = num_cards;
-		sprintf(name, "i2c_designware#%u", num_cards++);
-		device_set_name(dev, name);
-	}
-
-	return 0;
-}
-
-static const struct dm_i2c_ops designware_i2c_ops = {
+const struct dm_i2c_ops designware_i2c_ops = {
 	.xfer		= designware_i2c_xfer,
 	.probe_chip	= designware_i2c_probe_chip,
 	.set_bus_speed	= designware_i2c_set_bus_speed,
@@ -656,28 +600,12 @@
 	.name	= "i2c_designware",
 	.id	= UCLASS_I2C,
 	.of_match = designware_i2c_ids,
-	.bind	= designware_i2c_bind,
+	.ofdata_to_platdata = designware_i2c_ofdata_to_platdata,
 	.probe	= designware_i2c_probe,
 	.priv_auto_alloc_size = sizeof(struct dw_i2c),
 	.remove = designware_i2c_remove,
-	.flags = DM_FLAG_OS_PREPARE,
+	.flags	= DM_FLAG_OS_PREPARE,
 	.ops	= &designware_i2c_ops,
 };
 
-#ifdef CONFIG_X86
-static struct pci_device_id designware_pci_supported[] = {
-	/* Intel BayTrail has 7 I2C controller located on the PCI bus */
-	{ PCI_VDEVICE(INTEL, 0x0f41) },
-	{ PCI_VDEVICE(INTEL, 0x0f42) },
-	{ PCI_VDEVICE(INTEL, 0x0f43) },
-	{ PCI_VDEVICE(INTEL, 0x0f44) },
-	{ PCI_VDEVICE(INTEL, 0x0f45) },
-	{ PCI_VDEVICE(INTEL, 0x0f46) },
-	{ PCI_VDEVICE(INTEL, 0x0f47) },
-	{},
-};
-
-U_BOOT_PCI_DEVICE(i2c_designware, designware_pci_supported);
-#endif
-
 #endif /* CONFIG_DM_I2C */
diff --git a/drivers/i2c/designware_i2c.h b/drivers/i2c/designware_i2c.h
index 20ff20d..48766d0 100644
--- a/drivers/i2c/designware_i2c.h
+++ b/drivers/i2c/designware_i2c.h
@@ -7,6 +7,8 @@
 #ifndef __DW_I2C_H_
 #define __DW_I2C_H_
 
+#include <reset.h>
+
 struct i2c_regs {
 	u32 ic_con;		/* 0x00 */
 	u32 ic_tar;		/* 0x04 */
@@ -131,4 +133,37 @@
 #define I2C_FAST_SPEED		400000
 #define I2C_STANDARD_SPEED	100000
 
+/**
+ * struct dw_scl_sda_cfg - I2C timing configuration
+ *
+ * @has_max_speed: Support maximum speed (1Mbps)
+ * @ss_hcnt: Standard speed high time in ns
+ * @fs_hcnt: Fast speed high time in ns
+ * @ss_lcnt: Standard speed low time in ns
+ * @fs_lcnt: Fast speed low time in ns
+ * @sda_hold: SDA hold time
+ */
+struct dw_scl_sda_cfg {
+	bool has_max_speed;
+	u32 ss_hcnt;
+	u32 fs_hcnt;
+	u32 ss_lcnt;
+	u32 fs_lcnt;
+	u32 sda_hold;
+};
+
+struct dw_i2c {
+	struct i2c_regs *regs;
+	struct dw_scl_sda_cfg *scl_sda_cfg;
+	struct reset_ctl_bulk resets;
+#if CONFIG_IS_ENABLED(CLK)
+	struct clk clk;
+#endif
+};
+
+extern const struct dm_i2c_ops designware_i2c_ops;
+
+int designware_i2c_probe(struct udevice *bus);
+int designware_i2c_remove(struct udevice *dev);
+
 #endif /* __DW_I2C_H_ */
diff --git a/drivers/i2c/designware_i2c_pci.c b/drivers/i2c/designware_i2c_pci.c
new file mode 100644
index 0000000..7f0625d
--- /dev/null
+++ b/drivers/i2c/designware_i2c_pci.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009
+ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ * Copyright 2019 Google Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <spl.h>
+#include <asm/lpss.h>
+#include "designware_i2c.h"
+
+enum {
+	VANILLA		= 0,	/* standard I2C with no tweaks */
+	INTEL_APL,		/* Apollo Lake I2C */
+};
+
+/* BayTrail HCNT/LCNT/SDA hold time */
+static struct dw_scl_sda_cfg byt_config = {
+	.ss_hcnt = 0x200,
+	.fs_hcnt = 0x55,
+	.ss_lcnt = 0x200,
+	.fs_lcnt = 0x99,
+	.sda_hold = 0x6,
+};
+
+/* Have a weak function for now - possibly should be a new uclass */
+__weak void lpss_reset_release(void *regs);
+
+static int designware_i2c_pci_ofdata_to_platdata(struct udevice *dev)
+{
+	struct dw_i2c *priv = dev_get_priv(dev);
+
+	if (spl_phase() < PHASE_SPL) {
+		u32 base;
+		int ret;
+
+		ret = dev_read_u32(dev, "early-regs", &base);
+		if (ret)
+			return log_msg_ret("early-regs", ret);
+
+		/* Set i2c base address */
+		dm_pci_write_config32(dev, PCI_BASE_ADDRESS_0, base);
+
+		/* Enable memory access and bus master */
+		dm_pci_write_config32(dev, PCI_COMMAND, PCI_COMMAND_MEMORY |
+				      PCI_COMMAND_MASTER);
+	}
+
+	if (spl_phase() < PHASE_BOARD_F) {
+		/* Handle early, fixed mapping into a different address space */
+		priv->regs = (struct i2c_regs *)dm_pci_read_bar32(dev, 0);
+	} else {
+		priv->regs = (struct i2c_regs *)
+			dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+	}
+	if (!priv->regs)
+		return -EINVAL;
+
+	/* Save base address from PCI BAR */
+	if (IS_ENABLED(CONFIG_INTEL_BAYTRAIL))
+		/* Use BayTrail specific timing values */
+		priv->scl_sda_cfg = &byt_config;
+
+	return 0;
+}
+
+static int designware_i2c_pci_probe(struct udevice *dev)
+{
+	struct dw_i2c *priv = dev_get_priv(dev);
+
+	if (dev_get_driver_data(dev) == INTEL_APL) {
+		/* Ensure controller is in D0 state */
+		lpss_set_power_state(dev, STATE_D0);
+
+		lpss_reset_release(priv->regs);
+	}
+
+	return designware_i2c_probe(dev);
+}
+
+static int designware_i2c_pci_bind(struct udevice *dev)
+{
+	char name[20];
+
+	/*
+	 * Create a unique device name for PCI type devices
+	 * ToDo:
+	 * Setting req_seq in the driver is probably not recommended.
+	 * But without a DT alias the number is not configured. And
+	 * using this driver is impossible for PCIe I2C devices.
+	 * This can be removed, once a better (correct) way for this
+	 * is found and implemented.
+	 *
+	 * TODO(sjg@chromium.org): Perhaps if uclasses had platdata this would
+	 * be possible. We cannot use static data in drivers since they may be
+	 * used in SPL or before relocation.
+	 */
+	dev->req_seq = gd->arch.dw_i2c_num_cards++;
+	sprintf(name, "i2c_designware#%u", dev->req_seq);
+	device_set_name(dev, name);
+
+	return 0;
+}
+
+static const struct udevice_id designware_i2c_pci_ids[] = {
+	{ .compatible = "snps,designware-i2c-pci" },
+	{ .compatible = "intel,apl-i2c", .data = INTEL_APL },
+	{ }
+};
+
+U_BOOT_DRIVER(i2c_designware_pci) = {
+	.name	= "i2c_designware_pci",
+	.id	= UCLASS_I2C,
+	.of_match = designware_i2c_pci_ids,
+	.bind	= designware_i2c_pci_bind,
+	.ofdata_to_platdata	= designware_i2c_pci_ofdata_to_platdata,
+	.probe	= designware_i2c_pci_probe,
+	.priv_auto_alloc_size = sizeof(struct dw_i2c),
+	.remove = designware_i2c_remove,
+	.flags = DM_FLAG_OS_PREPARE,
+	.ops	= &designware_i2c_ops,
+};
+
+static struct pci_device_id designware_pci_supported[] = {
+	/* Intel BayTrail has 7 I2C controller located on the PCI bus */
+	{ PCI_VDEVICE(INTEL, 0x0f41) },
+	{ PCI_VDEVICE(INTEL, 0x0f42) },
+	{ PCI_VDEVICE(INTEL, 0x0f43) },
+	{ PCI_VDEVICE(INTEL, 0x0f44) },
+	{ PCI_VDEVICE(INTEL, 0x0f45) },
+	{ PCI_VDEVICE(INTEL, 0x0f46) },
+	{ PCI_VDEVICE(INTEL, 0x0f47) },
+	{ PCI_VDEVICE(INTEL, 0x5aac), .driver_data = INTEL_APL },
+	{ PCI_VDEVICE(INTEL, 0x5aae), .driver_data = INTEL_APL },
+	{ PCI_VDEVICE(INTEL, 0x5ab0), .driver_data = INTEL_APL },
+	{ PCI_VDEVICE(INTEL, 0x5ab2), .driver_data = INTEL_APL },
+	{ PCI_VDEVICE(INTEL, 0x5ab4), .driver_data = INTEL_APL },
+	{ PCI_VDEVICE(INTEL, 0x5ab6), .driver_data = INTEL_APL },
+	{},
+};
+
+U_BOOT_PCI_DEVICE(i2c_designware_pci, designware_pci_supported);
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
index 44aace3..fe77e64 100644
--- a/drivers/i2c/i2c-uclass.c
+++ b/drivers/i2c/i2c-uclass.c
@@ -11,7 +11,7 @@
 #include <dm/device-internal.h>
 #include <dm/lists.h>
 #include <dm/pinctrl.h>
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 #include <asm/gpio.h>
 #endif
 
@@ -485,7 +485,7 @@
 	return chip->chip_addr_offset_mask;
 }
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 static void i2c_gpio_set_pin(struct gpio_desc *pin, int bit)
 {
 	if (bit)
@@ -581,7 +581,7 @@
 {
 	return -ENOSYS;
 }
-#endif // CONFIG_DM_GPIO
+#endif /* DM_GPIO */
 
 int i2c_deblock(struct udevice *bus)
 {
diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c
index a630ce9..bb2935f 100644
--- a/drivers/i2c/muxes/pca954x.c
+++ b/drivers/i2c/muxes/pca954x.c
@@ -125,7 +125,7 @@
 
 static int pca954x_probe(struct udevice *dev)
 {
-	if (IS_ENABLED(CONFIG_DM_GPIO)) {
+	if (CONFIG_IS_ENABLED(DM_GPIO)) {
 		struct pca954x_priv *priv = dev_get_priv(dev);
 		int err;
 
@@ -146,7 +146,7 @@
 
 static int pca954x_remove(struct udevice *dev)
 {
-	if (IS_ENABLED(CONFIG_DM_GPIO)) {
+	if (CONFIG_IS_ENABLED(DM_GPIO)) {
 		struct pca954x_priv *priv = dev_get_priv(dev);
 
 		if (dm_gpio_is_valid(&priv->gpio_mux_reset))
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 82bb093..f18aa8f 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -203,6 +203,15 @@
 	  Security Monitor can be transitioned on any security failures,
 	  like software violations or hardware security violations.
 
+config IRQ
+	bool "Intel Interrupt controller"
+	depends on X86 || SANDBOX
+	help
+	  This enables support for Intel interrupt controllers, including ITSS.
+	  Some devices have extra features, such as Apollo Lake. The
+	  device has its own uclass since there are several operations
+	  involved.
+
 config JZ4780_EFUSE
 	bool "Ingenic JZ4780 eFUSE support"
 	depends on ARCH_JZ47XX
@@ -226,6 +235,39 @@
 	  disable the legacy UART, the watchdog or other devices
 	  in the Nuvoton Super IO chips on X86 platforms.
 
+config P2SB
+	bool "Intel Primary-to-Sideband Bus"
+	depends on X86 || SANDBOX
+	help
+	  This enables support for the Intel Primary-to-Sideband bus,
+	  abbreviated to P2SB. The P2SB is used to access various peripherals
+	  such as eSPI, GPIO, through memory-mapped I/O in a large chunk of PCI
+	  space. The space is segmented into different channels and peripherals
+	  are accessed by device-specific means within those channels. Devices
+	  should be added in the device tree as subnodes of the P2SB. A
+	  Peripheral Channel Register? (PCR) API is provided to access those
+	  devices - see pcr_readl(), etc.
+
+config SPL_P2SB
+	bool "Intel Primary-to-Sideband Bus in SPL"
+	depends on SPL && (X86 || SANDBOX)
+	help
+	  The Primary-to-Sideband bus is used to access various peripherals
+	  through memory-mapped I/O in a large chunk of PCI space. The space is
+	  segmented into different channels and peripherals are accessed by
+	  device-specific means within those channels. Devices should be added
+	  in the device tree as subnodes of the p2sb.
+
+config TPL_P2SB
+	bool "Intel Primary-to-Sideband Bus in TPL"
+	depends on TPL && (X86 || SANDBOX)
+	help
+	  The Primary-to-Sideband bus is used to access various peripherals
+	  through memory-mapped I/O in a large chunk of PCI space. The space is
+	  segmented into different channels and peripherals are accessed by
+	  device-specific means within those channels. Devices should be added
+	  in the device tree as subnodes of the p2sb.
+
 config PWRSEQ
 	bool "Enable power-sequencing drivers"
 	depends on DM
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 55976d6..d4e8638 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -10,8 +10,10 @@
 obj-$(CONFIG_$(SPL_TPL_)CROS_EC_LPC) += cros_ec_lpc.o
 
 ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_SANDBOX) += sandbox_adder.o
 obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o
 obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
+obj-$(CONFIG_SANDBOX) += p2sb_sandbox.o p2sb_emul.o
 obj-$(CONFIG_SANDBOX) += swap_case.o
 endif
 
@@ -39,6 +41,8 @@
 obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o
 obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o
 obj-$(CONFIG_GDSYS_SOC) += gdsys_soc.o
+obj-$(CONFIG_IRQ) += irq-uclass.o
+obj-$(CONFIG_SANDBOX) += irq_sandbox.o
 obj-$(CONFIG_$(SPL_)I2C_EEPROM) += i2c_eeprom.o
 obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o
 obj-$(CONFIG_IMX8) += imx8/
@@ -49,6 +53,7 @@
 obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
 obj-$(CONFIG_NS87308) += ns87308.o
 obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o
+obj-$(CONFIG_P2SB) += p2sb-uclass.o
 obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
 obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
 obj-$(CONFIG_QFW) += qfw.o
diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
new file mode 100644
index 0000000..d5182cf
--- /dev/null
+++ b/drivers/misc/irq-uclass.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <irq.h>
+
+int irq_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num)
+{
+	const struct irq_ops *ops = irq_get_ops(dev);
+
+	if (!ops->route_pmc_gpio_gpe)
+		return -ENOSYS;
+
+	return ops->route_pmc_gpio_gpe(dev, pmc_gpe_num);
+}
+
+int irq_set_polarity(struct udevice *dev, uint irq, bool active_low)
+{
+	const struct irq_ops *ops = irq_get_ops(dev);
+
+	if (!ops->set_polarity)
+		return -ENOSYS;
+
+	return ops->set_polarity(dev, irq, active_low);
+}
+
+int irq_snapshot_polarities(struct udevice *dev)
+{
+	const struct irq_ops *ops = irq_get_ops(dev);
+
+	if (!ops->snapshot_polarities)
+		return -ENOSYS;
+
+	return ops->snapshot_polarities(dev);
+}
+
+int irq_restore_polarities(struct udevice *dev)
+{
+	const struct irq_ops *ops = irq_get_ops(dev);
+
+	if (!ops->restore_polarities)
+		return -ENOSYS;
+
+	return ops->restore_polarities(dev);
+}
+
+UCLASS_DRIVER(irq) = {
+	.id		= UCLASS_IRQ,
+	.name		= "irq",
+};
diff --git a/drivers/misc/irq_sandbox.c b/drivers/misc/irq_sandbox.c
new file mode 100644
index 0000000..6dda1a4
--- /dev/null
+++ b/drivers/misc/irq_sandbox.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sandbox driver for interrupts
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <irq.h>
+
+static int sandbox_set_polarity(struct udevice *dev, uint irq, bool active_low)
+{
+	if (irq > 10)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int sandbox_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num)
+{
+	if (pmc_gpe_num > 10)
+		return -ENOENT;
+
+	return pmc_gpe_num + 1;
+}
+
+static int sandbox_snapshot_polarities(struct udevice *dev)
+{
+	return 0;
+}
+
+static int sandbox_restore_polarities(struct udevice *dev)
+{
+	return 0;
+}
+
+static const struct irq_ops sandbox_irq_ops = {
+	.route_pmc_gpio_gpe	= sandbox_route_pmc_gpio_gpe,
+	.set_polarity		= sandbox_set_polarity,
+	.snapshot_polarities	= sandbox_snapshot_polarities,
+	.restore_polarities	= sandbox_restore_polarities,
+};
+
+static const struct udevice_id sandbox_irq_ids[] = {
+	{ .compatible = "sandbox,irq"},
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_irq_drv) = {
+	.name		= "sandbox_irq",
+	.id		= UCLASS_IRQ,
+	.of_match	= sandbox_irq_ids,
+	.ops		= &sandbox_irq_ops,
+};
diff --git a/drivers/misc/p2sb-uclass.c b/drivers/misc/p2sb-uclass.c
new file mode 100644
index 0000000..a198700
--- /dev/null
+++ b/drivers/misc/p2sb-uclass.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Uclass for Primary-to-sideband bus, used to access various peripherals
+ *
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <p2sb.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <dm/uclass-internal.h>
+
+#define PCR_COMMON_IOSF_1_0	1
+
+static void *_pcr_reg_address(struct udevice *dev, uint offset)
+{
+	struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
+	struct udevice *p2sb = dev_get_parent(dev);
+	struct p2sb_uc_priv *upriv = dev_get_uclass_priv(p2sb);
+	uintptr_t reg_addr;
+
+	/* Create an address based off of port id and offset */
+	reg_addr = upriv->mmio_base;
+	reg_addr += pplat->pid << PCR_PORTID_SHIFT;
+	reg_addr += offset;
+
+	return map_sysmem(reg_addr, 4);
+}
+
+/*
+ * The mapping of addresses via the SBREG_BAR assumes the IOSF-SB
+ * agents are using 32-bit aligned accesses for their configuration
+ * registers. For IOSF versions greater than 1_0, IOSF-SB
+ * agents can use any access (8/16/32 bit aligned) for their
+ * configuration registers
+ */
+static inline void check_pcr_offset_align(uint offset, uint size)
+{
+	const size_t align = PCR_COMMON_IOSF_1_0 ? sizeof(uint32_t) : size;
+
+	assert(IS_ALIGNED(offset, align));
+}
+
+uint pcr_read32(struct udevice *dev, uint offset)
+{
+	void *ptr;
+	uint val;
+
+	/* Ensure the PCR offset is correctly aligned */
+	assert(IS_ALIGNED(offset, sizeof(uint32_t)));
+
+	ptr = _pcr_reg_address(dev, offset);
+	val = readl(ptr);
+	unmap_sysmem(ptr);
+
+	return val;
+}
+
+uint pcr_read16(struct udevice *dev, uint offset)
+{
+	/* Ensure the PCR offset is correctly aligned */
+	check_pcr_offset_align(offset, sizeof(uint16_t));
+
+	return readw(_pcr_reg_address(dev, offset));
+}
+
+uint pcr_read8(struct udevice *dev, uint offset)
+{
+	/* Ensure the PCR offset is correctly aligned */
+	check_pcr_offset_align(offset, sizeof(uint8_t));
+
+	return readb(_pcr_reg_address(dev, offset));
+}
+
+/*
+ * After every write one needs to perform a read an innocuous register to
+ * ensure the writes are completed for certain ports. This is done for
+ * all ports so that the callers don't need the per-port knowledge for
+ * each transaction.
+ */
+static void write_completion(struct udevice *dev, uint offset)
+{
+	readl(_pcr_reg_address(dev, ALIGN_DOWN(offset, sizeof(uint32_t))));
+}
+
+void pcr_write32(struct udevice *dev, uint offset, uint indata)
+{
+	/* Ensure the PCR offset is correctly aligned */
+	assert(IS_ALIGNED(offset, sizeof(indata)));
+
+	writel(indata, _pcr_reg_address(dev, offset));
+	/* Ensure the writes complete */
+	write_completion(dev, offset);
+}
+
+void pcr_write16(struct udevice *dev, uint offset, uint indata)
+{
+	/* Ensure the PCR offset is correctly aligned */
+	check_pcr_offset_align(offset, sizeof(uint16_t));
+
+	writew(indata, _pcr_reg_address(dev, offset));
+	/* Ensure the writes complete */
+	write_completion(dev, offset);
+}
+
+void pcr_write8(struct udevice *dev, uint offset, uint indata)
+{
+	/* Ensure the PCR offset is correctly aligned */
+	check_pcr_offset_align(offset, sizeof(uint8_t));
+
+	writeb(indata, _pcr_reg_address(dev, offset));
+	/* Ensure the writes complete */
+	write_completion(dev, offset);
+}
+
+void pcr_clrsetbits32(struct udevice *dev, uint offset, uint clr, uint set)
+{
+	uint data32;
+
+	data32 = pcr_read32(dev, offset);
+	data32 &= ~clr;
+	data32 |= set;
+	pcr_write32(dev, offset, data32);
+}
+
+void pcr_clrsetbits16(struct udevice *dev, uint offset, uint clr, uint set)
+{
+	uint data16;
+
+	data16 = pcr_read16(dev, offset);
+	data16 &= ~clr;
+	data16 |= set;
+	pcr_write16(dev, offset, data16);
+}
+
+void pcr_clrsetbits8(struct udevice *dev, uint offset, uint clr, uint set)
+{
+	uint data8;
+
+	data8 = pcr_read8(dev, offset);
+	data8 &= ~clr;
+	data8 |= set;
+	pcr_write8(dev, offset, data8);
+}
+
+int p2sb_get_port_id(struct udevice *dev)
+{
+	struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
+
+	return pplat->pid;
+}
+
+int p2sb_set_port_id(struct udevice *dev, int portid)
+{
+	struct udevice *ps2b;
+	struct p2sb_child_platdata *pplat;
+
+	if (!CONFIG_IS_ENABLED(OF_PLATDATA))
+		return -ENOSYS;
+
+	uclass_find_first_device(UCLASS_P2SB, &ps2b);
+	if (!ps2b)
+		return -EDEADLK;
+	dev->parent = ps2b;
+
+	/*
+	 * We must allocate this, since when the device was bound it did not
+	 * have a parent.
+	 * TODO(sjg@chromium.org): Add a parent pointer to child devices in dtoc
+	 */
+	dev->parent_platdata = malloc(sizeof(*pplat));
+	if (!dev->parent_platdata)
+		return -ENOMEM;
+	pplat = dev_get_parent_platdata(dev);
+	pplat->pid = portid;
+
+	return 0;
+}
+
+static int p2sb_child_post_bind(struct udevice *dev)
+{
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
+	int ret;
+	u32 pid;
+
+	ret = dev_read_u32(dev, "intel,p2sb-port-id", &pid);
+	if (ret)
+		return ret;
+	pplat->pid = pid;
+#endif
+
+	return 0;
+}
+
+static int p2sb_post_bind(struct udevice *dev)
+{
+	if (spl_phase() > PHASE_TPL && !CONFIG_IS_ENABLED(OF_PLATDATA))
+		return dm_scan_fdt_dev(dev);
+
+	return 0;
+}
+
+UCLASS_DRIVER(p2sb) = {
+	.id		= UCLASS_P2SB,
+	.name		= "p2sb",
+	.per_device_auto_alloc_size = sizeof(struct p2sb_uc_priv),
+	.post_bind	= p2sb_post_bind,
+	.child_post_bind = p2sb_child_post_bind,
+	.per_child_platdata_auto_alloc_size =
+		sizeof(struct p2sb_child_platdata),
+};
diff --git a/drivers/misc/p2sb_emul.c b/drivers/misc/p2sb_emul.c
new file mode 100644
index 0000000..c3795c5
--- /dev/null
+++ b/drivers/misc/p2sb_emul.c
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PCI emulation device for an x86 Primary-to-Sideband bus
+ *
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#define LOG_CATEGORY UCLASS_MISC
+#define LOG_DEBUG
+
+#include <common.h>
+#include <axi.h>
+#include <dm.h>
+#include <pci.h>
+#include <asm/test.h>
+#include <p2sb.h>
+
+/**
+ * struct p2sb_emul_platdata - platform data for this device
+ *
+ * @command:	Current PCI command value
+ * @bar:	Current base address values
+ */
+struct p2sb_emul_platdata {
+	u16 command;
+	u32 bar[6];
+};
+
+enum {
+	/* This emulator supports 16 different devices */
+	MEMMAP_SIZE	= 16 << PCR_PORTID_SHIFT,
+};
+
+static struct pci_bar {
+	int type;
+	u32 size;
+} barinfo[] = {
+	{ PCI_BASE_ADDRESS_MEM_TYPE_32, MEMMAP_SIZE },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+};
+
+struct p2sb_emul_priv {
+	u8 regs[16];
+};
+
+static int sandbox_p2sb_emul_read_config(struct udevice *emul, uint offset,
+					 ulong *valuep, enum pci_size_t size)
+{
+	struct p2sb_emul_platdata *plat = dev_get_platdata(emul);
+
+	switch (offset) {
+	case PCI_COMMAND:
+		*valuep = plat->command;
+		break;
+	case PCI_HEADER_TYPE:
+		*valuep = PCI_HEADER_TYPE_NORMAL;
+		break;
+	case PCI_VENDOR_ID:
+		*valuep = SANDBOX_PCI_VENDOR_ID;
+		break;
+	case PCI_DEVICE_ID:
+		*valuep = SANDBOX_PCI_P2SB_EMUL_ID;
+		break;
+	case PCI_CLASS_DEVICE:
+		if (size == PCI_SIZE_8) {
+			*valuep = SANDBOX_PCI_CLASS_SUB_CODE;
+		} else {
+			*valuep = (SANDBOX_PCI_CLASS_CODE << 8) |
+					SANDBOX_PCI_CLASS_SUB_CODE;
+		}
+		break;
+	case PCI_CLASS_CODE:
+		*valuep = SANDBOX_PCI_CLASS_CODE;
+		break;
+	case PCI_BASE_ADDRESS_0:
+	case PCI_BASE_ADDRESS_1:
+	case PCI_BASE_ADDRESS_2:
+	case PCI_BASE_ADDRESS_3:
+	case PCI_BASE_ADDRESS_4:
+	case PCI_BASE_ADDRESS_5: {
+		int barnum;
+		u32 *bar;
+
+		barnum = pci_offset_to_barnum(offset);
+		bar = &plat->bar[barnum];
+
+		*valuep = sandbox_pci_read_bar(*bar, barinfo[barnum].type,
+					       barinfo[barnum].size);
+		break;
+	}
+	case PCI_CAPABILITY_LIST:
+		*valuep = PCI_CAP_ID_PM_OFFSET;
+		break;
+	}
+
+	return 0;
+}
+
+static int sandbox_p2sb_emul_write_config(struct udevice *emul, uint offset,
+					  ulong value, enum pci_size_t size)
+{
+	struct p2sb_emul_platdata *plat = dev_get_platdata(emul);
+
+	switch (offset) {
+	case PCI_COMMAND:
+		plat->command = value;
+		break;
+	case PCI_BASE_ADDRESS_0:
+	case PCI_BASE_ADDRESS_1: {
+		int barnum;
+		u32 *bar;
+
+		barnum = pci_offset_to_barnum(offset);
+		bar = &plat->bar[barnum];
+
+		log_debug("w bar %d=%lx\n", barnum, value);
+		*bar = value;
+		/* space indicator (bit#0) is read-only */
+		*bar |= barinfo[barnum].type;
+		break;
+	}
+	}
+
+	return 0;
+}
+
+static int sandbox_p2sb_emul_find_bar(struct udevice *emul, unsigned int addr,
+				      int *barnump, unsigned int *offsetp)
+{
+	struct p2sb_emul_platdata *plat = dev_get_platdata(emul);
+	int barnum;
+
+	for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) {
+		unsigned int size = barinfo[barnum].size;
+		u32 base = plat->bar[barnum] & ~PCI_BASE_ADDRESS_SPACE;
+
+		if (addr >= base && addr < base + size) {
+			*barnump = barnum;
+			*offsetp = addr - base;
+			return 0;
+		}
+	}
+	*barnump = -1;
+
+	return -ENOENT;
+}
+
+static int sandbox_p2sb_emul_read_io(struct udevice *dev, unsigned int addr,
+				     ulong *valuep, enum pci_size_t size)
+{
+	unsigned int offset;
+	int barnum;
+	int ret;
+
+	ret = sandbox_p2sb_emul_find_bar(dev, addr, &barnum, &offset);
+	if (ret)
+		return ret;
+
+	if (barnum == 4)
+		*valuep = offset;
+	else if (barnum == 0)
+		*valuep = offset;
+
+	return 0;
+}
+
+static int sandbox_p2sb_emul_write_io(struct udevice *dev, unsigned int addr,
+				      ulong value, enum pci_size_t size)
+{
+	unsigned int offset;
+	int barnum;
+	int ret;
+
+	ret = sandbox_p2sb_emul_find_bar(dev, addr, &barnum, &offset);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int find_p2sb_channel(struct udevice *emul, uint offset,
+			     struct udevice **devp)
+{
+	uint pid = offset >> PCR_PORTID_SHIFT;
+	struct udevice *p2sb, *dev;
+	int ret;
+
+	ret = sandbox_pci_get_client(emul, &p2sb);
+	if (ret)
+		return log_msg_ret("No client", ret);
+
+	device_foreach_child(dev, p2sb) {
+		struct p2sb_child_platdata *pplat =
+			 dev_get_parent_platdata(dev);
+
+		log_debug("   - child %s, pid %d, want %d\n", dev->name,
+			  pplat->pid, pid);
+		if (pid == pplat->pid) {
+			*devp = dev;
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+
+static int sandbox_p2sb_emul_map_physmem(struct udevice *dev,
+					 phys_addr_t addr, unsigned long *lenp,
+					 void **ptrp)
+{
+	struct p2sb_emul_priv *priv = dev_get_priv(dev);
+	struct udevice *child;
+	unsigned int offset;
+	int barnum;
+	int ret;
+
+	log_debug("map %x: ", (uint)addr);
+	ret = sandbox_p2sb_emul_find_bar(dev, addr, &barnum, &offset);
+	if (ret)
+		return log_msg_ret("Cannot find bar", ret);
+	log_debug("bar %d, offset %x\n", barnum, offset);
+
+	if (barnum != 0)
+		return log_msg_ret("Unknown BAR", -EINVAL);
+
+	ret = find_p2sb_channel(dev, offset, &child);
+	if (ret)
+		return log_msg_ret("Cannot find channel", ret);
+
+	offset &= ((1 << PCR_PORTID_SHIFT) - 1);
+	ret = axi_read(child, offset, priv->regs, AXI_SIZE_32);
+	if (ret)
+		return log_msg_ret("Child read failed", ret);
+	*ptrp = priv->regs + (offset & 3);
+	*lenp = 4;
+
+	return 0;
+}
+
+static struct dm_pci_emul_ops sandbox_p2sb_emul_emul_ops = {
+	.read_config = sandbox_p2sb_emul_read_config,
+	.write_config = sandbox_p2sb_emul_write_config,
+	.read_io = sandbox_p2sb_emul_read_io,
+	.write_io = sandbox_p2sb_emul_write_io,
+	.map_physmem = sandbox_p2sb_emul_map_physmem,
+};
+
+static const struct udevice_id sandbox_p2sb_emul_ids[] = {
+	{ .compatible = "sandbox,p2sb-emul" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_p2sb_emul_emul) = {
+	.name		= "sandbox_p2sb_emul_emul",
+	.id		= UCLASS_PCI_EMUL,
+	.of_match	= sandbox_p2sb_emul_ids,
+	.ops		= &sandbox_p2sb_emul_emul_ops,
+	.priv_auto_alloc_size = sizeof(struct p2sb_emul_priv),
+	.platdata_auto_alloc_size = sizeof(struct p2sb_emul_platdata),
+};
+
+static struct pci_device_id sandbox_p2sb_emul_supported[] = {
+	{ PCI_VDEVICE(SANDBOX, SANDBOX_PCI_PMC_EMUL_ID) },
+	{},
+};
+
+U_BOOT_PCI_DEVICE(sandbox_p2sb_emul_emul, sandbox_p2sb_emul_supported);
diff --git a/drivers/misc/p2sb_sandbox.c b/drivers/misc/p2sb_sandbox.c
new file mode 100644
index 0000000..ce50a97
--- /dev/null
+++ b/drivers/misc/p2sb_sandbox.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sandbox P2SB for testing
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#define LOG_CATEGORY UCLASS_P2SB
+
+#include <common.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <p2sb.h>
+
+struct sandbox_p2sb_priv {
+	ulong base;
+};
+
+static int sandbox_p2sb_probe(struct udevice *dev)
+{
+	struct p2sb_uc_priv *upriv = dev_get_uclass_priv(dev);
+
+	upriv->mmio_base = dm_pci_read_bar32(dev, 0);
+
+	return 0;
+}
+
+static const struct udevice_id sandbox_p2sb_ids[] = {
+	{ .compatible = "sandbox,p2sb" },
+	{ }
+};
+
+U_BOOT_DRIVER(p2sb_sandbox) = {
+	.name = "p2sb_sandbox",
+	.id = UCLASS_P2SB,
+	.of_match = sandbox_p2sb_ids,
+	.probe = sandbox_p2sb_probe,
+	.priv_auto_alloc_size = sizeof(struct sandbox_p2sb_priv),
+};
diff --git a/drivers/misc/sandbox_adder.c b/drivers/misc/sandbox_adder.c
new file mode 100644
index 0000000..df262e6
--- /dev/null
+++ b/drivers/misc/sandbox_adder.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sandbox adder for p2sb testing
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#define LOG_CATEGORY UCLASS_MISC
+
+#include <common.h>
+#include <axi.h>
+#include <dm.h>
+#include <misc.h>
+#include <p2sb.h>
+#include <asm/io.h>
+
+struct sandbox_adder_priv {
+	ulong base;
+};
+
+int sandbox_adder_read(struct udevice *dev, ulong address, void *data,
+		       enum axi_size_t size)
+{
+	struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
+	u32 *val = data;
+
+	*val = pplat->pid << 24 | address;
+
+	return 0;
+}
+
+int sandbox_adder_write(struct udevice *dev, ulong address, void *data,
+			enum axi_size_t size)
+{
+	return 0;
+}
+
+static int sandbox_adder_probe(struct udevice *dev)
+{
+	return 0;
+}
+
+static struct axi_ops sandbox_adder_ops = {
+	.read	= sandbox_adder_read,
+	.write	= sandbox_adder_write,
+};
+
+static const struct udevice_id sandbox_adder_ids[] = {
+	{ .compatible = "sandbox,adder" },
+	{ }
+};
+
+U_BOOT_DRIVER(adder_sandbox) = {
+	.name = "sandbox_adder",
+	.id = UCLASS_AXI,
+	.of_match = sandbox_adder_ids,
+	.probe = sandbox_adder_probe,
+	.ops = &sandbox_adder_ops,
+	.priv_auto_alloc_size = sizeof(struct sandbox_adder_priv),
+};
diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c
index f1afab7..f7b754b 100644
--- a/drivers/mmc/fsl_esdhc_imx.c
+++ b/drivers/mmc/fsl_esdhc_imx.c
@@ -150,7 +150,7 @@
 	struct udevice *vqmmc_dev;
 	struct udevice *vmmc_dev;
 #endif
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	struct gpio_desc cd_gpio;
 	struct gpio_desc wp_gpio;
 #endif
@@ -303,8 +303,9 @@
 				return -ETIMEDOUT;
 			}
 		} else {
-#ifdef CONFIG_DM_GPIO
-			if (dm_gpio_is_valid(&priv->wp_gpio) && dm_gpio_get_value(&priv->wp_gpio)) {
+#if CONFIG_IS_ENABLED(DM_GPIO)
+			if (dm_gpio_is_valid(&priv->wp_gpio) &&
+			    dm_gpio_get_value(&priv->wp_gpio)) {
 				printf("\nThe SD card is locked. Can not write to a locked card.\n\n");
 				return -ETIMEDOUT;
 			}
@@ -1092,7 +1093,7 @@
 #if CONFIG_IS_ENABLED(DM_MMC)
 	if (priv->non_removable)
 		return 1;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	if (dm_gpio_is_valid(&priv->cd_gpio))
 		return dm_gpio_get_value(&priv->cd_gpio);
 #endif
@@ -1454,7 +1455,7 @@
 		priv->non_removable = 1;
 	 } else {
 		priv->non_removable = 0;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 		gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
 				     GPIOD_IS_IN);
 #endif
@@ -1464,7 +1465,7 @@
 		priv->wp_enable = 1;
 	} else {
 		priv->wp_enable = 0;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 		gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio,
 				   GPIOD_IS_IN);
 #endif
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index dab3425..5d0cfb2 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -184,7 +184,7 @@
 {
 	int ret;
 
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
 	if (!gpio_is_valid(gpio))
 		return -1;
 #endif
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index f051e47..72b6ee7 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -137,7 +137,7 @@
 	return spi_flash_cmd_get_sw_write_prot(flash);
 }
 
-static int spi_flash_std_probe(struct udevice *dev)
+int spi_flash_std_probe(struct udevice *dev)
 {
 	struct spi_slave *slave = dev_get_parent_priv(dev);
 	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 5c2d5e5..19fc34f 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -82,7 +82,7 @@
 	return ret;
 }
 
-#if defined(CONFIG_DM_ETH) && defined(CONFIG_DM_GPIO)
+#if defined(CONFIG_DM_ETH) && CONFIG_IS_ENABLED(DM_GPIO)
 static int dw_mdio_reset(struct mii_dev *bus)
 {
 	struct udevice *dev = bus->priv;
@@ -128,7 +128,7 @@
 	bus->read = dw_mdio_read;
 	bus->write = dw_mdio_write;
 	snprintf(bus->name, sizeof(bus->name), "%s", name);
-#if defined(CONFIG_DM_ETH) && defined(CONFIG_DM_GPIO)
+#if defined(CONFIG_DM_ETH) && CONFIG_IS_ENABLED(DM_GPIO)
 	bus->reset = dw_mdio_reset;
 #endif
 
@@ -807,12 +807,12 @@
 int designware_eth_ofdata_to_platdata(struct udevice *dev)
 {
 	struct dw_eth_pdata *dw_pdata = dev_get_platdata(dev);
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	struct dw_eth_dev *priv = dev_get_priv(dev);
 #endif
 	struct eth_pdata *pdata = &dw_pdata->eth_pdata;
 	const char *phy_mode;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	int reset_flags = GPIOD_IS_OUT;
 #endif
 	int ret = 0;
@@ -829,7 +829,7 @@
 
 	pdata->max_speed = dev_read_u32_default(dev, "max-speed", 0);
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	if (dev_read_bool(dev, "snps,reset-active-low"))
 		reset_flags |= GPIOD_ACTIVE_LOW;
 
diff --git a/drivers/net/designware.h b/drivers/net/designware.h
index dea12b7..3519a41 100644
--- a/drivers/net/designware.h
+++ b/drivers/net/designware.h
@@ -7,7 +7,7 @@
 #ifndef _DW_ETH_H
 #define _DW_ETH_H
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 #include <asm-generic/gpio.h>
 #endif
 
@@ -235,7 +235,7 @@
 #ifndef CONFIG_DM_ETH
 	struct eth_device *dev;
 #endif
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	struct gpio_desc reset_gpio;
 #endif
 #ifdef CONFIG_CLK
diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c
index 2aa1029..bc5b63d 100644
--- a/drivers/net/fec_mxc.c
+++ b/drivers/net/fec_mxc.c
@@ -1309,7 +1309,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 /* FEC GPIO reset */
 static void fec_gpio_reset(struct fec_priv *priv)
 {
@@ -1402,7 +1402,7 @@
 	}
 #endif
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	fec_gpio_reset(priv);
 #endif
 	/* Reset chip. */
@@ -1508,7 +1508,7 @@
 	device_get_supply_regulator(dev, "phy-supply", &priv->phy_supply);
 #endif
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	ret = gpio_request_by_name(dev, "phy-reset-gpios", 0,
 				   &priv->phy_reset_gpio, GPIOD_IS_OUT);
 	if (ret < 0)
diff --git a/drivers/net/fec_mxc.h b/drivers/net/fec_mxc.h
index 723b06a..159aec8 100644
--- a/drivers/net/fec_mxc.h
+++ b/drivers/net/fec_mxc.h
@@ -255,7 +255,7 @@
 #ifdef CONFIG_DM_REGULATOR
 	struct udevice *phy_supply;
 #endif
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	struct gpio_desc phy_reset_gpio;
 	uint32_t reset_delay;
 	uint32_t reset_post_delay;
diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c
index 6f76a6b..5fe8500 100644
--- a/drivers/net/mvneta.c
+++ b/drivers/net/mvneta.c
@@ -276,7 +276,7 @@
 	int init;
 	int phyaddr;
 	struct phy_device *phydev;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	struct gpio_desc phy_reset_gpio;
 #endif
 	struct mii_dev *bus;
@@ -1754,7 +1754,7 @@
 	if (ret)
 		return ret;
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	gpio_request_by_name(dev, "phy-reset-gpios", 0,
 			     &pp->phy_reset_gpio, GPIOD_IS_OUT);
 
diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c
index c5d1f9c..917d06b 100644
--- a/drivers/net/mvpp2.c
+++ b/drivers/net/mvpp2.c
@@ -959,7 +959,8 @@
 	phy_interface_t phy_interface;
 	int phyaddr;
 	struct udevice *mdio_dev;
-#ifdef CONFIG_DM_GPIO
+	struct mii_dev *bus;
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	struct gpio_desc phy_reset_gpio;
 	struct gpio_desc phy_tx_disable_gpio;
 #endif
@@ -4742,7 +4743,7 @@
 		return -EINVAL;
 	}
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	gpio_request_by_name(dev, "phy-reset-gpios", 0,
 			     &port->phy_reset_gpio, GPIOD_IS_OUT);
 	gpio_request_by_name(dev, "marvell,sfp-tx-disable-gpio", 0,
@@ -4769,7 +4770,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 /* Port GPIO initialization */
 static void mvpp2_gpio_init(struct mvpp2_port *port)
 {
@@ -4802,7 +4803,7 @@
 	}
 	mvpp2_port_power_up(port);
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	mvpp2_gpio_init(port);
 #endif
 
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
index 9551918..6f10578 100644
--- a/drivers/net/sun8i_emac.c
+++ b/drivers/net/sun8i_emac.c
@@ -24,7 +24,7 @@
 #include <net.h>
 #include <reset.h>
 #include <dt-bindings/pinctrl/sun4i-a10.h>
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 #include <asm-generic/gpio.h>
 #endif
 
@@ -142,7 +142,7 @@
 	struct clk ephy_clk;
 	struct reset_ctl tx_rst;
 	struct reset_ctl ephy_rst;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	struct gpio_desc reset_gpio;
 #endif
 };
@@ -696,7 +696,7 @@
 	return ret;
 }
 
-#if defined(CONFIG_DM_GPIO)
+#if CONFIG_IS_ENABLED(DM_GPIO)
 static int sun8i_mdio_reset(struct mii_dev *bus)
 {
 	struct udevice *dev = bus->priv;
@@ -743,7 +743,7 @@
 	bus->write = sun8i_mdio_write;
 	snprintf(bus->name, sizeof(bus->name), name);
 	bus->priv = (void *)priv;
-#if defined(CONFIG_DM_GPIO)
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	bus->reset = sun8i_mdio_reset;
 #endif
 
@@ -905,7 +905,7 @@
 	const fdt32_t *reg;
 	int node = dev_of_offset(dev);
 	int offset = 0;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	int reset_flags = GPIOD_IS_OUT;
 #endif
 	int ret;
@@ -999,7 +999,7 @@
 		printf("%s: Invalid RX delay value %d\n", __func__,
 		       sun8i_pdata->rx_delay_ps);
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
 			    "snps,reset-active-low"))
 		reset_flags |= GPIOD_ACTIVE_LOW;
diff --git a/drivers/pch/Kconfig b/drivers/pch/Kconfig
index 18f006d..c49a928 100644
--- a/drivers/pch/Kconfig
+++ b/drivers/pch/Kconfig
@@ -7,3 +7,21 @@
 	  northbridge / southbridge architecture that was previously used. The
 	  PCH allows for higher performance since the memory functions are
 	  handled in the CPU.
+
+config X86_PCH7
+	bool "Add support for Intel PCH7"
+	default y if X86
+	help
+	  Enable this if your SoC uses Platform Controller Hub 7 (PCH7). This
+	  dates from about 2011 and is used on baytrail, for example. The
+	  PCH provides access to the GPIO and SPI base addresses, among other
+	  functions.
+
+config X86_PCH9
+	bool "Add support for Intel PCH9"
+	default y if X86
+	help
+	  Enable this if your SoC uses Platform Controller Hub 9 (PCH9). This
+	  dates from about 2015 and is used on baytrail, for example. The
+	  PCH provides access to the GPIO and SPI base addresses, among other
+	  functions.
diff --git a/drivers/pch/Makefile b/drivers/pch/Makefile
index 8ea6b78..d5de3e4 100644
--- a/drivers/pch/Makefile
+++ b/drivers/pch/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0+
 
 obj-y += pch-uclass.o
-obj-y += pch7.o
-obj-y += pch9.o
+obj-$(CONFIG_X86_PCH7) += pch7.o
+obj-$(CONFIG_X86_PCH9) += pch9.o
 obj-$(CONFIG_SANDBOX) += sandbox_pch.o
diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c
index 864ac16..aa0b4bc 100644
--- a/drivers/pci/pci-aardvark.c
+++ b/drivers/pci/pci-aardvark.c
@@ -610,7 +610,7 @@
 {
 	struct pcie_advk *pcie = dev_get_priv(dev);
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	struct gpio_desc reset_gpio;
 
 	gpio_request_by_name(dev, "reset-gpio", 0, &reset_gpio,
@@ -636,7 +636,7 @@
 	}
 #else
 	dev_dbg(pcie->dev, "PCIE Reset on GPIO support is missing\n");
-#endif /* CONFIG_DM_GPIO */
+#endif /* DM_GPIO */
 
 	pcie->first_busno = dev->seq;
 	pcie->dev = pci_get_controller(dev);
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index fab20fc..7308f61 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -975,12 +975,15 @@
 	hose->bus = bus;
 	hose->first_busno = bus->seq;
 	hose->last_busno = bus->seq;
+	hose->skip_auto_config_until_reloc =
+		dev_read_bool(bus, "u-boot,skip-auto-config-until-reloc");
 
 	return 0;
 }
 
 static int pci_uclass_post_probe(struct udevice *bus)
 {
+	struct pci_controller *hose = dev_get_uclass_priv(bus);
 	int ret;
 
 	debug("%s: probing bus %d\n", __func__, bus->seq);
@@ -988,11 +991,13 @@
 	if (ret)
 		return ret;
 
-#if CONFIG_IS_ENABLED(PCI_PNP)
-	ret = pci_auto_config_devices(bus);
-	if (ret < 0)
-		return ret;
-#endif
+	if (CONFIG_IS_ENABLED(PCI_PNP) &&
+	    (!hose->skip_auto_config_until_reloc ||
+	     (gd->flags & GD_FLG_RELOC))) {
+		ret = pci_auto_config_devices(bus);
+		if (ret < 0)
+			return log_msg_ret("pci auto-config", ret);
+	}
 
 #if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
 	/*
@@ -1018,22 +1023,6 @@
 	return 0;
 }
 
-int pci_get_devfn(struct udevice *dev)
-{
-	struct fdt_pci_addr addr;
-	int ret;
-
-	/* Extract the devfn from fdt_pci_addr */
-	ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG,
-				   "reg", &addr);
-	if (ret) {
-		if (ret != -ENOENT)
-			return -EINVAL;
-	}
-
-	return addr.phys_hi & 0xff00;
-}
-
 static int pci_uclass_child_post_bind(struct udevice *dev)
 {
 	struct pci_child_platdata *pplat;
diff --git a/drivers/pci/pcie_dw_mvebu.c b/drivers/pci/pcie_dw_mvebu.c
index 95fb419..693591e 100644
--- a/drivers/pci/pcie_dw_mvebu.c
+++ b/drivers/pci/pcie_dw_mvebu.c
@@ -476,7 +476,7 @@
 	struct pcie_dw_mvebu *pcie = dev_get_priv(dev);
 	struct udevice *ctlr = pci_get_controller(dev);
 	struct pci_controller *hose = dev_get_uclass_priv(ctlr);
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	struct gpio_desc reset_gpio;
 
 	gpio_request_by_name(dev, "marvell,reset-gpio", 0, &reset_gpio,
@@ -496,7 +496,7 @@
 	}
 #else
 	debug("PCIE Reset on GPIO support is missing\n");
-#endif /* CONFIG_DM_GPIO */
+#endif /* DM_GPIO */
 
 	pcie->first_busno = dev->seq;
 
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index eadcfd6..83e39b9 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -82,6 +82,13 @@
 	  This option is an SPL-variant of the PINCTRL option.
 	  See the help of PINCTRL for details.
 
+config TPL_PINCTRL
+	bool "Support pin controllers in TPL"
+	depends on TPL && TPL_DM
+	help
+	  This option is an TPL variant of the PINCTRL option.
+	  See the help of PINCTRL for details.
+
 config SPL_PINCTRL_FULL
 	bool "Support full pin controllers in SPL"
 	depends on SPL_PINCTRL && SPL_OF_CONTROL
@@ -91,6 +98,13 @@
 	  This option is an SPL-variant of the PINCTRL_FULL option.
 	  See the help of PINCTRL_FULL for details.
 
+config TPL_PINCTRL_FULL
+	bool "Support full pin controllers in TPL"
+	depends on TPL_PINCTRL && TPL_OF_CONTROL
+	help
+	  This option is an TPL-variant of the PINCTRL_FULL option.
+	  See the help of PINCTRL_FULL for details.
+
 config SPL_PINCTRL_GENERIC
 	bool "Support generic pin controllers in SPL"
 	depends on SPL_PINCTRL_FULL
@@ -163,6 +177,14 @@
 	  This option is to enable the AT91 pinctrl driver for AT91 PIO4
 	  controller which is available on SAMA5D2 SoC.
 
+config PINCTRL_INTEL
+	bool "Standard Intel pin-control and pin-mux driver"
+	help
+	  Recent Intel chips such as Apollo Lake (APL) use a common pin control
+	  and GPIO scheme. The settings for this come from an SoC-specific
+	  driver which must be separately enabled. The driver supports setting
+	  pins on start-up and changing the GPIO attributes.
+
 config PINCTRL_PIC32
 	bool "Microchip PIC32 pin-control and pin-mux driver"
 	depends on DM && MACH_PIC32
@@ -266,6 +288,7 @@
 
 source "drivers/pinctrl/broadcom/Kconfig"
 source "drivers/pinctrl/exynos/Kconfig"
+source "drivers/pinctrl/intel/Kconfig"
 source "drivers/pinctrl/mediatek/Kconfig"
 source "drivers/pinctrl/meson/Kconfig"
 source "drivers/pinctrl/mscc/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index ce0879a..4f662c4 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -9,6 +9,7 @@
 obj-$(CONFIG_$(SPL_)PINCTRL_ROCKCHIP)	+= rockchip/
 obj-$(CONFIG_ARCH_ASPEED) += aspeed/
 obj-$(CONFIG_ARCH_ATH79) += ath79/
+obj-$(CONFIG_PINCTRL_INTEL) += intel/
 obj-$(CONFIG_ARCH_MTMIPS) += mtmips/
 obj-$(CONFIG_ARCH_RMOBILE) += renesas/
 obj-$(CONFIG_PINCTRL_SANDBOX)	+= pinctrl-sandbox.o
diff --git a/drivers/pinctrl/intel/Kconfig b/drivers/pinctrl/intel/Kconfig
new file mode 100644
index 0000000..e62a2e0
--- /dev/null
+++ b/drivers/pinctrl/intel/Kconfig
@@ -0,0 +1,26 @@
+#
+# Intel PINCTRL drivers
+#
+
+if PINCTRL_INTEL
+
+config INTEL_PINCTRL_DUAL_ROUTE_SUPPORT
+	bool
+	default y
+
+config INTEL_PINCTRL_PADCFG_PADTOL
+	bool n
+
+config INTEL_PINCTRL_IOSTANDBY
+	bool
+	default y
+
+config PINCTRL_INTEL_APL
+	bool "Support Intel Apollo Lake (APL)"
+	help
+	  Add support for Intel Apollo Lake pin-control and pin-mux settings.
+	  These are mostly read from the device tree, with the early-pads
+	  property in the host bridge and the pads property in the fsp-s
+	  subnode of the host bridge.
+
+endif
diff --git a/drivers/pinctrl/intel/Makefile b/drivers/pinctrl/intel/Makefile
new file mode 100644
index 0000000..3aed8e9
--- /dev/null
+++ b/drivers/pinctrl/intel/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2019 Google LLC
+
+obj-y += pinctrl.o
+obj-$(CONFIG_PINCTRL_INTEL_APL) += pinctrl_apl.o
diff --git a/drivers/pinctrl/intel/pinctrl.c b/drivers/pinctrl/intel/pinctrl.c
new file mode 100644
index 0000000..4875a3b
--- /dev/null
+++ b/drivers/pinctrl/intel/pinctrl.c
@@ -0,0 +1,636 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Intel Corp.
+ * Copyright 2019 Google LLC
+ *
+ * Taken partly from coreboot gpio.c
+ *
+ * Pinctrl is modelled as a separate device-tree node and device for each
+ * 'community' (basically a set of GPIOs). The separate devices work together
+ * and many functions permit any PINCTRL device to be provided as a parameter,
+ * since the pad numbering is unique across all devices.
+ *
+ * Each pinctrl has a single child GPIO device to handle GPIO access and
+ * therefore there is a simple GPIO driver included in this file.
+ */
+
+#define LOG_CATEGORY UCLASS_GPIO
+
+#include <common.h>
+#include <dm.h>
+#include <irq.h>
+#include <p2sb.h>
+#include <spl.h>
+#include <asm-generic/gpio.h>
+#include <asm/intel_pinctrl.h>
+#include <asm/intel_pinctrl_defs.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/itss.h>
+#include <dm/device-internal.h>
+#include <dt-bindings/gpio/gpio.h>
+
+#define GPIO_DW_SIZE(x)			(sizeof(u32) * (x))
+#define PAD_CFG_OFFSET(x, dw_num)	((x) + GPIO_DW_SIZE(dw_num))
+#define PAD_CFG0_OFFSET(x)		PAD_CFG_OFFSET(x, 0)
+#define PAD_CFG1_OFFSET(x)		PAD_CFG_OFFSET(x, 1)
+
+#define MISCCFG_GPE0_DW0_SHIFT 8
+#define MISCCFG_GPE0_DW0_MASK (0xf << MISCCFG_GPE0_DW0_SHIFT)
+#define MISCCFG_GPE0_DW1_SHIFT 12
+#define MISCCFG_GPE0_DW1_MASK (0xf << MISCCFG_GPE0_DW1_SHIFT)
+#define MISCCFG_GPE0_DW2_SHIFT 16
+#define MISCCFG_GPE0_DW2_MASK (0xf << MISCCFG_GPE0_DW2_SHIFT)
+
+#define GPI_SMI_STS_OFFSET(comm, group) ((comm)->gpi_smi_sts_reg_0 +	\
+				((group) * sizeof(u32)))
+#define GPI_SMI_EN_OFFSET(comm, group) ((comm)->gpi_smi_en_reg_0 +	\
+				((group) * sizeof(u32)))
+#define GPI_IS_OFFSET(comm, group) ((comm)->gpi_int_sts_reg_0 +	\
+				((group) * sizeof(uint32_t)))
+#define GPI_IE_OFFSET(comm, group) ((comm)->gpi_int_en_reg_0 +	\
+				((group) * sizeof(uint32_t)))
+
+/**
+ * relative_pad_in_comm() - Get the relative position of a GPIO
+ *
+ * This finds the position of a GPIO within a community
+ *
+ * @comm: Community to search
+ * @gpio: Pad number to look up (assumed to be valid)
+ * @return offset, 0 for first GPIO in community
+ */
+static size_t relative_pad_in_comm(const struct pad_community *comm,
+				   uint gpio)
+{
+	return gpio - comm->first_pad;
+}
+
+/**
+ * pinctrl_group_index() - Find group for a a pad
+ *
+ * Find the group within the community that the pad is a part of
+ *
+ * @comm: Community to search
+ * @relative_pad: Pad to look up
+ * @return group number if found (see community_n_groups, etc.), or
+ *	-ESPIPE if no groups, or -ENOENT if not found
+ */
+static int pinctrl_group_index(const struct pad_community *comm,
+			       uint relative_pad)
+{
+	int i;
+
+	if (!comm->groups)
+		return -ESPIPE;
+
+	/* find the base pad number for this pad's group */
+	for (i = 0; i < comm->num_groups; i++) {
+		if (relative_pad >= comm->groups[i].first_pad &&
+		    relative_pad < comm->groups[i].first_pad +
+		    comm->groups[i].size)
+			return i;
+	}
+
+	return -ENOENT;
+}
+
+static int pinctrl_group_index_scaled(const struct pad_community *comm,
+				      uint relative_pad, size_t scale)
+{
+	int ret;
+
+	ret = pinctrl_group_index(comm, relative_pad);
+	if (ret < 0)
+		return ret;
+
+	return ret * scale;
+}
+
+static int pinctrl_within_group(const struct pad_community *comm,
+				uint relative_pad)
+{
+	int ret;
+
+	ret = pinctrl_group_index(comm, relative_pad);
+	if (ret < 0)
+		return ret;
+
+	return relative_pad - comm->groups[ret].first_pad;
+}
+
+static u32 pinctrl_bitmask_within_group(const struct pad_community *comm,
+					uint relative_pad)
+{
+	return 1U << pinctrl_within_group(comm, relative_pad);
+}
+
+/**
+ * pinctrl_get_device() - Find the device for a particular pad
+ *
+ * Each pinctr, device is attached to one community and this supports a number
+ * of pads. This function finds the device which controls a particular pad.
+ *
+ * @pad: Pad to check
+ * @devp: Returns the device for that pad
+ * @return 0 if OK, -ENOTBLK if no device was found for the given pin
+ */
+static int pinctrl_get_device(uint pad, struct udevice **devp)
+{
+	struct udevice *dev;
+
+	/*
+	 * We have to probe each one of these since the community link is only
+	 * attached in intel_pinctrl_ofdata_to_platdata().
+	 */
+	uclass_foreach_dev_probe(UCLASS_PINCTRL, dev) {
+		struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+		const struct pad_community *comm = priv->comm;
+
+		if (pad >= comm->first_pad && pad <= comm->last_pad) {
+			*devp = dev;
+			return 0;
+		}
+	}
+	printf("pad %d not found\n", pad);
+
+	return -ENOTBLK;
+}
+
+int intel_pinctrl_get_pad(uint pad, struct udevice **devp, uint *offsetp)
+{
+	const struct pad_community *comm;
+	struct intel_pinctrl_priv *priv;
+	struct udevice *dev;
+	int ret;
+
+	ret = pinctrl_get_device(pad, &dev);
+	if (ret)
+		return log_msg_ret("pad", ret);
+	priv = dev_get_priv(dev);
+	comm = priv->comm;
+	*devp = dev;
+	*offsetp = relative_pad_in_comm(comm, pad);
+
+	return 0;
+}
+
+static int pinctrl_configure_owner(struct udevice *dev,
+				   const struct pad_config *cfg,
+				   const struct pad_community *comm)
+{
+	u32 hostsw_own;
+	u16 hostsw_own_offset;
+	int pin;
+	int ret;
+
+	pin = relative_pad_in_comm(comm, cfg->pad);
+
+	/*
+	 * Based on the gpio pin number configure the corresponding bit in
+	 * HOSTSW_OWN register. Value of 0x1 indicates GPIO Driver onwership.
+	 */
+	hostsw_own_offset = comm->host_own_reg_0;
+	ret = pinctrl_group_index_scaled(comm, pin, sizeof(u32));
+	if (ret < 0)
+		return ret;
+	hostsw_own_offset += ret;
+
+	hostsw_own = pcr_read32(dev, hostsw_own_offset);
+
+	/*
+	 *The 4th bit in pad_config 1 (RO) is used to indicate if the pad
+	 * needs GPIO driver ownership.  Set the bit if GPIO driver ownership
+	 * requested, otherwise clear the bit.
+	 */
+	if (cfg->pad_config[1] & PAD_CFG1_GPIO_DRIVER)
+		hostsw_own |= pinctrl_bitmask_within_group(comm, pin);
+	else
+		hostsw_own &= ~pinctrl_bitmask_within_group(comm, pin);
+
+	pcr_write32(dev, hostsw_own_offset, hostsw_own);
+
+	return 0;
+}
+
+static int gpi_enable_smi(struct udevice *dev, const struct pad_config *cfg,
+			  const struct pad_community *comm)
+{
+	u32 value;
+	u16 sts_reg;
+	u16 en_reg;
+	int group;
+	int pin;
+	int ret;
+
+	if ((cfg->pad_config[0] & PAD_CFG0_ROUTE_SMI) != PAD_CFG0_ROUTE_SMI)
+		return 0;
+
+	pin = relative_pad_in_comm(comm, cfg->pad);
+	ret = pinctrl_group_index(comm, pin);
+	if (ret < 0)
+		return ret;
+	group = ret;
+
+	sts_reg = GPI_SMI_STS_OFFSET(comm, group);
+	value = pcr_read32(dev, sts_reg);
+	/* Write back 1 to reset the sts bits */
+	pcr_write32(dev, sts_reg, value);
+
+	/* Set enable bits */
+	en_reg = GPI_SMI_EN_OFFSET(comm, group);
+	pcr_setbits32(dev, en_reg, pinctrl_bitmask_within_group(comm, pin));
+
+	return 0;
+}
+
+static int pinctrl_configure_itss(struct udevice *dev,
+				  const struct pad_config *cfg,
+				  uint pad_cfg_offset)
+{
+	struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+
+	if (!priv->itss_pol_cfg)
+		return -ENOSYS;
+
+	int irq;
+
+	/*
+	 * Set up ITSS polarity if pad is routed to APIC.
+	 *
+	 * The ITSS takes only active high interrupt signals. Therefore,
+	 * if the pad configuration indicates an inversion assume the
+	 * intent is for the ITSS polarity. Before forwarding on the
+	 * request to the APIC there's an inversion setting for how the
+	 * signal is forwarded to the APIC. Honor the inversion setting
+	 * in the GPIO pad configuration so that a hardware active low
+	 * signal looks that way to the APIC (double inversion).
+	 */
+	if (!(cfg->pad_config[0] & PAD_CFG0_ROUTE_IOAPIC))
+		return 0;
+
+	irq = pcr_read32(dev, PAD_CFG1_OFFSET(pad_cfg_offset));
+	irq &= PAD_CFG1_IRQ_MASK;
+	if (!irq) {
+		log_err("GPIO %u doesn't support APIC routing\n", cfg->pad);
+
+		return -EPROTONOSUPPORT;
+	}
+	irq_set_polarity(priv->itss, irq,
+			 cfg->pad_config[0] & PAD_CFG0_RX_POL_INVERT);
+
+	return 0;
+}
+
+/* Number of DWx config registers can be different for different SOCs */
+static uint pad_config_offset(struct intel_pinctrl_priv *priv, uint pad)
+{
+	const struct pad_community *comm = priv->comm;
+	size_t offset;
+
+	offset = relative_pad_in_comm(comm, pad);
+	offset *= GPIO_DW_SIZE(priv->num_cfgs);
+
+	return offset + comm->pad_cfg_base;
+}
+
+static int pinctrl_pad_reset_config_override(const struct pad_community *comm,
+					     u32 config_value)
+{
+	const struct reset_mapping *rst_map = comm->reset_map;
+	int i;
+
+	/* Logical reset values equal chipset values */
+	if (!rst_map || !comm->num_reset_vals)
+		return config_value;
+
+	for (i = 0; i < comm->num_reset_vals; i++, rst_map++) {
+		if ((config_value & PAD_CFG0_RESET_MASK) == rst_map->logical) {
+			config_value &= ~PAD_CFG0_RESET_MASK;
+			config_value |= rst_map->chipset;
+
+			return config_value;
+		}
+	}
+	log_err("Logical-to-Chipset mapping not found\n");
+
+	return -ENOENT;
+}
+
+static const int mask[4] = {
+	PAD_CFG0_TX_STATE |
+	PAD_CFG0_TX_DISABLE | PAD_CFG0_RX_DISABLE | PAD_CFG0_MODE_MASK |
+	PAD_CFG0_ROUTE_MASK | PAD_CFG0_RXTENCFG_MASK |
+	PAD_CFG0_RXINV_MASK | PAD_CFG0_PREGFRXSEL |
+	PAD_CFG0_TRIG_MASK | PAD_CFG0_RXRAW1_MASK |
+	PAD_CFG0_RXPADSTSEL_MASK | PAD_CFG0_RESET_MASK,
+
+#ifdef CONFIG_INTEL_PINCTRL_IOSTANDBY
+	PAD_CFG1_IOSTERM_MASK | PAD_CFG1_PULL_MASK | PAD_CFG1_IOSSTATE_MASK,
+#else
+	PAD_CFG1_IOSTERM_MASK | PAD_CFG1_PULL_MASK,
+#endif
+
+	PAD_CFG2_DEBOUNCE_MASK,
+
+	0,
+};
+
+/**
+ * pinctrl_configure_pad() - Configure a pad
+ *
+ * @dev: Pinctrl device containing the pad (see pinctrl_get_device())
+ * @cfg: Configuration to apply
+ * @return 0 if OK, -ve on error
+ */
+static int pinctrl_configure_pad(struct udevice *dev,
+				 const struct pad_config *cfg)
+{
+	struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+	const struct pad_community *comm = priv->comm;
+	uint config_offset;
+	u32 pad_conf, soc_pad_conf;
+	int ret;
+	int i;
+
+	if (IS_ERR(comm))
+		return PTR_ERR(comm);
+	config_offset = pad_config_offset(priv, cfg->pad);
+	for (i = 0; i < priv->num_cfgs; i++) {
+		pad_conf = pcr_read32(dev, PAD_CFG_OFFSET(config_offset, i));
+
+		soc_pad_conf = cfg->pad_config[i];
+		if (i == 0) {
+			ret = pinctrl_pad_reset_config_override(comm,
+								soc_pad_conf);
+			if (ret < 0)
+				return ret;
+			soc_pad_conf = ret;
+		}
+		soc_pad_conf &= mask[i];
+		soc_pad_conf |= pad_conf & ~mask[i];
+
+		log_debug("pinctrl_padcfg [0x%02x, %02zd] DW%d [0x%08x : 0x%08x : 0x%08x]\n",
+			  comm->port, relative_pad_in_comm(comm, cfg->pad), i,
+			  pad_conf,/* old value */
+			  /* value passed from pinctrl table */
+			  cfg->pad_config[i],
+			  soc_pad_conf); /*new value*/
+		pcr_write32(dev, PAD_CFG_OFFSET(config_offset, i),
+			    soc_pad_conf);
+	}
+	ret = pinctrl_configure_itss(dev, cfg, config_offset);
+	if (ret && ret != -ENOSYS)
+		return log_msg_ret("itss config failed", ret);
+	ret = pinctrl_configure_owner(dev, cfg, comm);
+	if (ret)
+		return ret;
+	ret = gpi_enable_smi(dev, cfg, comm);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+u32 intel_pinctrl_get_config_reg_addr(struct udevice *dev, uint offset)
+{
+	struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+	const struct pad_community *comm = priv->comm;
+	uint config_offset;
+
+	assert(device_get_uclass_id(dev) == UCLASS_PINCTRL);
+	config_offset = comm->pad_cfg_base + offset *
+		 GPIO_DW_SIZE(priv->num_cfgs);
+
+	return config_offset;
+}
+
+u32 intel_pinctrl_get_config_reg(struct udevice *dev, uint offset)
+{
+	uint config_offset = intel_pinctrl_get_config_reg_addr(dev, offset);
+
+	return pcr_read32(dev, config_offset);
+}
+
+int intel_pinctrl_get_acpi_pin(struct udevice *dev, uint offset)
+{
+	struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+	const struct pad_community *comm = priv->comm;
+	int group;
+
+	group = pinctrl_group_index(comm, offset);
+
+	/* If pad base is not set then use GPIO number as ACPI pin number */
+	if (comm->groups[group].acpi_pad_base == PAD_BASE_NONE)
+		return comm->first_pad + offset;
+
+	/*
+	 * If this group has a non-zero pad base then compute the ACPI pin
+	 * number from the pad base and the relative pad in the group.
+	 */
+	return comm->groups[group].acpi_pad_base +
+		 pinctrl_within_group(comm, offset);
+}
+
+int pinctrl_route_gpe(struct udevice *itss, uint gpe0b, uint gpe0c, uint gpe0d)
+{
+	struct udevice *pinctrl_dev;
+	u32 misccfg_value;
+	u32 misccfg_clr;
+	int ret;
+
+	/*
+	 * Get the group here for community specific MISCCFG register.
+	 * If any of these returns -1 then there is some error in devicetree
+	 * where the group is probably hardcoded and does not comply with the
+	 * PMC group defines. So we return from here and MISCFG is set to
+	 * default.
+	 */
+	ret = irq_route_pmc_gpio_gpe(itss, gpe0b);
+	if (ret)
+		return ret;
+	gpe0b = ret;
+
+	ret = irq_route_pmc_gpio_gpe(itss, gpe0c);
+	if (ret)
+		return ret;
+	gpe0c = ret;
+
+	ret = irq_route_pmc_gpio_gpe(itss, gpe0d);
+	if (ret)
+		return ret;
+	gpe0d = ret;
+
+	misccfg_value = gpe0b << MISCCFG_GPE0_DW0_SHIFT;
+	misccfg_value |= gpe0c << MISCCFG_GPE0_DW1_SHIFT;
+	misccfg_value |= gpe0d << MISCCFG_GPE0_DW2_SHIFT;
+
+	/* Program GPIO_MISCCFG */
+	misccfg_clr = MISCCFG_GPE0_DW2_MASK | MISCCFG_GPE0_DW1_MASK |
+		MISCCFG_GPE0_DW0_MASK;
+
+	log_debug("misccfg_clr:%x misccfg_value:%x\n", misccfg_clr,
+		  misccfg_value);
+	uclass_foreach_dev_probe(UCLASS_PINCTRL, pinctrl_dev) {
+		pcr_clrsetbits32(pinctrl_dev, GPIO_MISCCFG, misccfg_clr,
+				 misccfg_value);
+	}
+
+	return 0;
+}
+
+int pinctrl_gpi_clear_int_cfg(void)
+{
+	struct udevice *dev;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_PINCTRL, &uc);
+	if (ret)
+		return log_msg_ret("pinctrl uc", ret);
+	uclass_foreach_dev(dev, uc) {
+		struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+		const struct pad_community *comm = priv->comm;
+		uint sts_value;
+		int group;
+
+		for (group = 0; group < comm->num_gpi_regs; group++) {
+			/* Clear the enable register */
+			pcr_write32(dev, GPI_IE_OFFSET(comm, group), 0);
+
+			/* Read and clear the set status register bits*/
+			sts_value = pcr_read32(dev,
+					       GPI_IS_OFFSET(comm, group));
+			pcr_write32(dev, GPI_IS_OFFSET(comm, group), sts_value);
+		}
+	}
+
+	return 0;
+}
+
+int pinctrl_config_pads(struct udevice *dev, u32 *pads, int pads_count)
+{
+	struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+	const u32 *ptr;
+	int i;
+
+	log_debug("%s: pads_count=%d\n", __func__, pads_count);
+	for (ptr = pads, i = 0; i < pads_count;
+	     ptr += 1 + priv->num_cfgs, i++) {
+		struct udevice *pad_dev = NULL;
+		struct pad_config *cfg;
+		int ret;
+
+		cfg = (struct pad_config *)ptr;
+		ret = pinctrl_get_device(cfg->pad, &pad_dev);
+		if (ret)
+			return ret;
+		ret = pinctrl_configure_pad(pad_dev, cfg);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int pinctrl_read_pads(struct udevice *dev, ofnode node, const char *prop,
+		      u32 **padsp, int *pad_countp)
+{
+	struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+	u32 *pads;
+	int size;
+	int ret;
+
+	*padsp = NULL;
+	*pad_countp = 0;
+	size = ofnode_read_size(node, prop);
+	if (size < 0)
+		return 0;
+
+	pads = malloc(size);
+	if (!pads)
+		return -ENOMEM;
+	size /= sizeof(fdt32_t);
+	ret = ofnode_read_u32_array(node, prop, pads, size);
+	if (ret) {
+		free(pads);
+		return ret;
+	}
+	*pad_countp = size / (1 + priv->num_cfgs);
+	*padsp = pads;
+
+	return 0;
+}
+
+int pinctrl_count_pads(struct udevice *dev, u32 *pads, int size)
+{
+	struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+	int count = 0;
+	int i;
+
+	for (i = 0; i < size;) {
+		u32 val;
+		int j;
+
+		for (val = j = 0; j < priv->num_cfgs + 1; j++)
+			val |= pads[i + j];
+		if (!val)
+			break;
+		count++;
+		i += priv->num_cfgs + 1;
+	}
+
+	return count;
+}
+
+int pinctrl_config_pads_for_node(struct udevice *dev, ofnode node)
+{
+	int pads_count;
+	u32 *pads;
+	int ret;
+
+	if (device_get_uclass_id(dev) != UCLASS_PINCTRL)
+		return log_msg_ret("uclass", -EPROTONOSUPPORT);
+	ret = pinctrl_read_pads(dev, node, "pads", &pads, &pads_count);
+	if (ret)
+		return log_msg_ret("no pads", ret);
+	ret = pinctrl_config_pads(dev, pads, pads_count);
+	free(pads);
+	if (ret)
+		return log_msg_ret("pad config", ret);
+
+	return 0;
+}
+
+int intel_pinctrl_ofdata_to_platdata(struct udevice *dev,
+				     const struct pad_community *comm,
+				     int num_cfgs)
+{
+	struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
+	struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	if (!comm) {
+		log_err("Cannot find community for pid %d\n", pplat->pid);
+		return -EDOM;
+	}
+	ret = uclass_first_device_err(UCLASS_IRQ, &priv->itss);
+	if (ret)
+		return log_msg_ret("Cannot find ITSS", ret);
+	priv->comm = comm;
+	priv->num_cfgs = num_cfgs;
+
+	return 0;
+}
+
+int intel_pinctrl_probe(struct udevice *dev)
+{
+	struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+
+	priv->itss_pol_cfg = true;
+
+	return 0;
+}
+
+const struct pinctrl_ops intel_pinctrl_ops = {
+	/* No operations are supported, but DM expects this to be present */
+};
diff --git a/drivers/pinctrl/intel/pinctrl_apl.c b/drivers/pinctrl/intel/pinctrl_apl.c
new file mode 100644
index 0000000..bd80435
--- /dev/null
+++ b/drivers/pinctrl/intel/pinctrl_apl.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Intel Corp.
+ * Copyright 2019 Google LLC
+ *
+ * Taken partly from coreboot gpio.c
+ */
+
+#define LOG_CATEGORY UCLASS_GPIO
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <p2sb.h>
+#include <asm/intel_pinctrl.h>
+#include <asm-generic/gpio.h>
+#include <asm/intel_pinctrl_defs.h>
+
+/**
+ * struct apl_gpio_platdata - platform data for each device
+ *
+ * @dtplat: of-platdata data from C struct
+ */
+struct apl_gpio_platdata {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	/* Put this first since driver model will copy the data here */
+	struct dtd_intel_apl_pinctrl dtplat;
+#endif
+};
+
+static const struct reset_mapping rst_map[] = {
+	{ .logical = PAD_CFG0_LOGICAL_RESET_PWROK, .chipset = 0U << 30 },
+	{ .logical = PAD_CFG0_LOGICAL_RESET_DEEP, .chipset = 1U << 30 },
+	{ .logical = PAD_CFG0_LOGICAL_RESET_PLTRST, .chipset = 2U << 30 },
+};
+
+/* Groups for each community */
+static const struct pad_group apl_community_n_groups[] = {
+	INTEL_GPP(N_OFFSET, N_OFFSET, GPIO_31),		/* NORTH 0 */
+	INTEL_GPP(N_OFFSET, GPIO_32, JTAG_TRST_B),	/* NORTH 1 */
+	INTEL_GPP(N_OFFSET, JTAG_TMS, SVID0_CLK),	/* NORTH 2 */
+};
+
+static const struct pad_group apl_community_w_groups[] = {
+	INTEL_GPP(W_OFFSET, W_OFFSET, OSC_CLK_OUT_1),	/* WEST 0 */
+	INTEL_GPP(W_OFFSET, OSC_CLK_OUT_2, SUSPWRDNACK),/* WEST 1 */
+};
+
+static const struct pad_group apl_community_sw_groups[] = {
+	INTEL_GPP(SW_OFFSET, SW_OFFSET, SMB_ALERTB),	/* SOUTHWEST 0 */
+	INTEL_GPP(SW_OFFSET, SMB_CLK, LPC_FRAMEB),	/* SOUTHWEST 1 */
+};
+
+static const struct pad_group apl_community_nw_groups[] = {
+	INTEL_GPP(NW_OFFSET, NW_OFFSET, PROCHOT_B),	/* NORTHWEST 0 */
+	INTEL_GPP(NW_OFFSET, PMIC_I2C_SCL, GPIO_106),	/* NORTHWEST 1 */
+	INTEL_GPP(NW_OFFSET, GPIO_109, GPIO_123),	/* NORTHWEST 2 */
+};
+
+/* TODO(sjg@chromium.org): Consider moving this to device tree */
+static const struct pad_community apl_gpio_communities[] = {
+	{
+		.port = PID_GPIO_N,
+		.first_pad = N_OFFSET,
+		.last_pad = SVID0_CLK,
+		.num_gpi_regs = NUM_N_GPI_REGS,
+		.gpi_status_offset = NUM_NW_GPI_REGS + NUM_W_GPI_REGS
+			+ NUM_SW_GPI_REGS,
+		.pad_cfg_base = PAD_CFG_BASE,
+		.host_own_reg_0 = HOSTSW_OWN_REG_0,
+		.gpi_int_sts_reg_0 = GPI_INT_STS_0,
+		.gpi_int_en_reg_0 = GPI_INT_EN_0,
+		.gpi_smi_sts_reg_0 = GPI_SMI_STS_0,
+		.gpi_smi_en_reg_0 = GPI_SMI_EN_0,
+		.max_pads_per_group = GPIO_MAX_NUM_PER_GROUP,
+		.name = "GPIO_GPE_N",
+		.acpi_path = "\\_SB.GPO0",
+		.reset_map = rst_map,
+		.num_reset_vals = ARRAY_SIZE(rst_map),
+		.groups = apl_community_n_groups,
+		.num_groups = ARRAY_SIZE(apl_community_n_groups),
+	}, {
+		.port = PID_GPIO_NW,
+		.first_pad = NW_OFFSET,
+		.last_pad = GPIO_123,
+		.num_gpi_regs = NUM_NW_GPI_REGS,
+		.gpi_status_offset = NUM_W_GPI_REGS + NUM_SW_GPI_REGS,
+		.pad_cfg_base = PAD_CFG_BASE,
+		.host_own_reg_0 = HOSTSW_OWN_REG_0,
+		.gpi_int_sts_reg_0 = GPI_INT_STS_0,
+		.gpi_int_en_reg_0 = GPI_INT_EN_0,
+		.gpi_smi_sts_reg_0 = GPI_SMI_STS_0,
+		.gpi_smi_en_reg_0 = GPI_SMI_EN_0,
+		.max_pads_per_group = GPIO_MAX_NUM_PER_GROUP,
+		.name = "GPIO_GPE_NW",
+		.acpi_path = "\\_SB.GPO1",
+		.reset_map = rst_map,
+		.num_reset_vals = ARRAY_SIZE(rst_map),
+		.groups = apl_community_nw_groups,
+		.num_groups = ARRAY_SIZE(apl_community_nw_groups),
+	}, {
+		.port = PID_GPIO_W,
+		.first_pad = W_OFFSET,
+		.last_pad = SUSPWRDNACK,
+		.num_gpi_regs = NUM_W_GPI_REGS,
+		.gpi_status_offset = NUM_SW_GPI_REGS,
+		.pad_cfg_base = PAD_CFG_BASE,
+		.host_own_reg_0 = HOSTSW_OWN_REG_0,
+		.gpi_int_sts_reg_0 = GPI_INT_STS_0,
+		.gpi_int_en_reg_0 = GPI_INT_EN_0,
+		.gpi_smi_sts_reg_0 = GPI_SMI_STS_0,
+		.gpi_smi_en_reg_0 = GPI_SMI_EN_0,
+		.max_pads_per_group = GPIO_MAX_NUM_PER_GROUP,
+		.name = "GPIO_GPE_W",
+		.acpi_path = "\\_SB.GPO2",
+		.reset_map = rst_map,
+		.num_reset_vals = ARRAY_SIZE(rst_map),
+		.groups = apl_community_w_groups,
+		.num_groups = ARRAY_SIZE(apl_community_w_groups),
+	}, {
+		.port = PID_GPIO_SW,
+		.first_pad = SW_OFFSET,
+		.last_pad = LPC_FRAMEB,
+		.num_gpi_regs = NUM_SW_GPI_REGS,
+		.gpi_status_offset = 0,
+		.pad_cfg_base = PAD_CFG_BASE,
+		.host_own_reg_0 = HOSTSW_OWN_REG_0,
+		.gpi_int_sts_reg_0 = GPI_INT_STS_0,
+		.gpi_int_en_reg_0 = GPI_INT_EN_0,
+		.gpi_smi_sts_reg_0 = GPI_SMI_STS_0,
+		.gpi_smi_en_reg_0 = GPI_SMI_EN_0,
+		.max_pads_per_group = GPIO_MAX_NUM_PER_GROUP,
+		.name = "GPIO_GPE_SW",
+		.acpi_path = "\\_SB.GPO3",
+		.reset_map = rst_map,
+		.num_reset_vals = ARRAY_SIZE(rst_map),
+		.groups = apl_community_sw_groups,
+		.num_groups = ARRAY_SIZE(apl_community_sw_groups),
+	},
+};
+
+static int apl_pinctrl_ofdata_to_platdata(struct udevice *dev)
+{
+	struct p2sb_child_platdata *pplat;
+	const struct pad_community *comm = NULL;
+	int i;
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct apl_gpio_platdata *plat = dev_get_platdata(dev);
+	int ret;
+
+	/*
+	 * It would be nice to do this in the bind() method, but with
+	 * of-platdata binding happens in the order that DM finds things in the
+	 * linker list (i.e. alphabetical order by driver name). So the GPIO
+	 * device may well be bound before its parent (p2sb), and this call
+	 * will fail if p2sb is not bound yet.
+	 *
+	 * TODO(sjg@chromium.org): Add a parent pointer to child devices in dtoc
+	 */
+	ret = p2sb_set_port_id(dev, plat->dtplat.intel_p2sb_port_id);
+	if (ret)
+		return log_msg_ret("Could not set port id", ret);
+#endif
+	/* Attach this device to its community structure */
+	pplat = dev_get_parent_platdata(dev);
+	for (i = 0; i < ARRAY_SIZE(apl_gpio_communities); i++) {
+		if (apl_gpio_communities[i].port == pplat->pid)
+			comm = &apl_gpio_communities[i];
+	}
+
+	return intel_pinctrl_ofdata_to_platdata(dev, comm, 2);
+}
+
+static const struct udevice_id apl_gpio_ids[] = {
+	{ .compatible = "intel,apl-pinctrl"},
+	{ }
+};
+
+U_BOOT_DRIVER(apl_pinctrl_drv) = {
+	.name		= "intel_apl_pinctrl",
+	.id		= UCLASS_PINCTRL,
+	.of_match	= apl_gpio_ids,
+	.probe		= intel_pinctrl_probe,
+	.ops		= &intel_pinctrl_ops,
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	.bind		= dm_scan_fdt_dev,
+#endif
+	.ofdata_to_platdata = apl_pinctrl_ofdata_to_platdata,
+	.priv_auto_alloc_size = sizeof(struct intel_pinctrl_priv),
+	.platdata_auto_alloc_size = sizeof(struct apl_gpio_platdata),
+};
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 9495dca..cb2c6fe 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -1,5 +1,7 @@
 menu "Power"
 
+source "drivers/power/acpi_pmc/Kconfig"
+
 source "drivers/power/domain/Kconfig"
 
 source "drivers/power/pmic/Kconfig"
diff --git a/drivers/power/acpi_pmc/Kconfig b/drivers/power/acpi_pmc/Kconfig
new file mode 100644
index 0000000..fcd50e3
--- /dev/null
+++ b/drivers/power/acpi_pmc/Kconfig
@@ -0,0 +1,34 @@
+config ACPI_PMC
+	bool "Power Manager (x86 PMC) support"
+	help
+	  Enable support for an x86-style power-management controller which
+	  provides features including checking whether the system started from
+	  resume, powering off the system and enabling/disabling the reset
+	  mechanism.
+
+config SPL_ACPI_PMC
+	bool "Power Manager (x86 PMC) support in SPL"
+	default y if ACPI_PMC
+	help
+	  Enable support for an x86-style power-management controller which
+	  provides features including checking whether the system started from
+	  resume, powering off the system and enabling/disabling the reset
+	  mechanism.
+
+config TPL_ACPI_PMC
+	bool "Power Manager (x86 PMC) support in TPL"
+	default y if ACPI_PMC
+	help
+	  Enable support for an x86-style power-management controller which
+	  provides features including checking whether the system started from
+	  resume, powering off the system and enabling/disabling the reset
+	  mechanism.
+
+config ACPI_PMC_SANDBOX
+	bool "Test power manager (PMC) for sandbox"
+	depends on ACPI_PMC && SANDBOX
+	help
+	  This driver emulates a PMC (Power-Management Controller) so that
+	  the uclass logic can be tested. You can use the 'pmc' command to
+	  access information from the driver. It uses I/O access to read
+	  from the PMC.
diff --git a/drivers/power/acpi_pmc/Makefile b/drivers/power/acpi_pmc/Makefile
new file mode 100644
index 0000000..115788f
--- /dev/null
+++ b/drivers/power/acpi_pmc/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2019 Google LLC
+
+obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC) += acpi-pmc-uclass.o
+obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC_SANDBOX) += sandbox.o pmc_emul.o
diff --git a/drivers/power/acpi_pmc/acpi-pmc-uclass.c b/drivers/power/acpi_pmc/acpi-pmc-uclass.c
new file mode 100644
index 0000000..d43de87
--- /dev/null
+++ b/drivers/power/acpi_pmc/acpi-pmc-uclass.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#define LOG_CATEGORY UCLASS_ACPI_PMC
+
+#include <common.h>
+#include <acpi_s3.h>
+#include <dm.h>
+#include <log.h>
+#ifdef CONFIG_X86
+#include <asm/intel_pinctrl.h>
+#endif
+#include <asm/io.h>
+#include <power/acpi_pmc.h>
+
+enum {
+	PM1_STS		= 0x00,
+	PM1_EN		= 0x02,
+	PM1_CNT		= 0x04,
+
+	GPE0_STS	= 0x20,
+	GPE0_EN		= 0x30,
+};
+
+struct tco_regs {
+	u32 tco_rld;
+	u32 tco_sts;
+	u32 tco1_cnt;
+	u32 tco_tmr;
+};
+
+enum {
+	TCO_STS_TIMEOUT			= 1 << 3,
+	TCO_STS_SECOND_TO_STS		= 1 << 17,
+	TCO1_CNT_HLT			= 1 << 11,
+};
+
+#ifdef CONFIG_X86
+static int gpe0_shift(struct acpi_pmc_upriv *upriv, int regnum)
+{
+	return upriv->gpe0_dwx_shift_base + regnum * 4;
+}
+
+int pmc_gpe_init(struct udevice *dev)
+{
+	struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+	struct udevice *itss;
+	u32 *dw;
+	u32 gpio_cfg_mask;
+	u32 gpio_cfg;
+	int ret, i;
+	u32 mask;
+
+	if (device_get_uclass_id(dev) != UCLASS_ACPI_PMC)
+		return log_msg_ret("uclass", -EPROTONOSUPPORT);
+	dw = upriv->gpe0_dw;
+	mask = upriv->gpe0_dwx_mask;
+	gpio_cfg_mask = 0;
+	for (i = 0; i < upriv->gpe0_count; i++) {
+		gpio_cfg_mask |= mask << gpe0_shift(upriv, i);
+		if (dw[i] & ~mask)
+			return log_msg_ret("Base GPE0 value", -EINVAL);
+	}
+
+	/*
+	 * Route the GPIOs to the GPE0 block. Determine that all values
+	 * are different and if they aren't, use the reset values.
+	 */
+	if (dw[0] == dw[1] || dw[1] == dw[2]) {
+		log_info("PMC: Using default GPE route");
+		gpio_cfg = readl(upriv->gpe_cfg);
+		for (i = 0; i < upriv->gpe0_count; i++)
+			dw[i] = gpio_cfg >> gpe0_shift(upriv, i);
+	} else {
+		gpio_cfg = 0;
+		for (i = 0; i < upriv->gpe0_count; i++)
+			gpio_cfg |= dw[i] << gpe0_shift(upriv, i);
+		clrsetbits_le32(upriv->gpe_cfg, gpio_cfg_mask, gpio_cfg);
+	}
+
+	/* Set the routes in the GPIO communities as well */
+	ret = uclass_first_device_err(UCLASS_IRQ, &itss);
+	if (ret)
+		return log_msg_ret("Cannot find itss", ret);
+	pinctrl_route_gpe(itss, dw[0], dw[1], dw[2]);
+
+	return 0;
+}
+#endif /* CONFIG_X86 */
+
+static void pmc_fill_pm_reg_info(struct udevice *dev)
+{
+	struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+	int i;
+
+	upriv->pm1_sts = inw(upriv->acpi_base + PM1_STS);
+	upriv->pm1_en = inw(upriv->acpi_base + PM1_EN);
+	upriv->pm1_cnt = inw(upriv->acpi_base + PM1_CNT);
+
+	log_debug("pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n",
+		  upriv->pm1_sts, upriv->pm1_en, upriv->pm1_cnt);
+
+	for (i = 0; i < GPE0_REG_MAX; i++) {
+		upriv->gpe0_sts[i] = inl(upriv->acpi_base + GPE0_STS + i * 4);
+		upriv->gpe0_en[i] = inl(upriv->acpi_base + GPE0_EN + i * 4);
+		log_debug("gpe0_sts[%d]: %08x gpe0_en[%d]: %08x\n", i,
+			  upriv->gpe0_sts[i], i, upriv->gpe0_en[i]);
+	}
+}
+
+int pmc_disable_tco_base(ulong tco_base)
+{
+	struct tco_regs *regs = (struct tco_regs *)tco_base;
+
+	debug("tco_base %lx = %x\n", (ulong)&regs->tco1_cnt, TCO1_CNT_HLT);
+	setio_32(&regs->tco1_cnt, TCO1_CNT_HLT);
+
+	return 0;
+}
+
+int pmc_init(struct udevice *dev)
+{
+	const struct acpi_pmc_ops *ops = acpi_pmc_get_ops(dev);
+	int ret;
+
+	pmc_fill_pm_reg_info(dev);
+	if (!ops->init)
+		return -ENOSYS;
+
+	ret = ops->init(dev);
+	if (ret)
+		return log_msg_ret("Failed to init pmc", ret);
+
+#ifdef DEBUG
+	pmc_dump_info(dev);
+#endif
+
+	return 0;
+}
+
+int pmc_prev_sleep_state(struct udevice *dev)
+{
+	struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+	const struct acpi_pmc_ops *ops = acpi_pmc_get_ops(dev);
+	int prev_sleep_state = ACPI_S0;	/* Default to S0 */
+
+	if (upriv->pm1_sts & WAK_STS) {
+		switch (acpi_sleep_from_pm1(upriv->pm1_cnt)) {
+		case ACPI_S3:
+			if (IS_ENABLED(HAVE_ACPI_RESUME))
+				prev_sleep_state = ACPI_S3;
+			break;
+		case ACPI_S5:
+			prev_sleep_state = ACPI_S5;
+			break;
+		default:
+			break;
+		}
+
+		/* Clear SLP_TYP */
+		outl(upriv->pm1_cnt & ~SLP_TYP, upriv->acpi_base + PM1_CNT);
+	}
+
+	if (!ops->prev_sleep_state)
+		return prev_sleep_state;
+
+	return ops->prev_sleep_state(dev, prev_sleep_state);
+}
+
+int pmc_disable_tco(struct udevice *dev)
+{
+	const struct acpi_pmc_ops *ops = acpi_pmc_get_ops(dev);
+
+	pmc_fill_pm_reg_info(dev);
+	if (!ops->disable_tco)
+		return -ENOSYS;
+
+	return ops->disable_tco(dev);
+}
+
+int pmc_global_reset_set_enable(struct udevice *dev, bool enable)
+{
+	const struct acpi_pmc_ops *ops = acpi_pmc_get_ops(dev);
+
+	if (!ops->global_reset_set_enable)
+		return -ENOSYS;
+
+	return ops->global_reset_set_enable(dev, enable);
+}
+
+void pmc_dump_info(struct udevice *dev)
+{
+	struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+	int i;
+
+	printf("Device: %s\n", dev->name);
+	printf("ACPI base %x, pmc_bar0 %p, pmc_bar2 %p, gpe_cfg %p\n",
+	       upriv->acpi_base, upriv->pmc_bar0, upriv->pmc_bar2,
+	       upriv->gpe_cfg);
+	printf("pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n",
+	       upriv->pm1_sts, upriv->pm1_en, upriv->pm1_cnt);
+
+	for (i = 0; i < GPE0_REG_MAX; i++) {
+		printf("gpe0_sts[%d]: %08x gpe0_en[%d]: %08x\n", i,
+		       upriv->gpe0_sts[i], i, upriv->gpe0_en[i]);
+	}
+
+	printf("prsts: %08x\n", upriv->prsts);
+	printf("tco_sts:   %04x %04x\n", upriv->tco1_sts, upriv->tco2_sts);
+	printf("gen_pmcon1: %08x gen_pmcon2: %08x gen_pmcon3: %08x\n",
+	       upriv->gen_pmcon1, upriv->gen_pmcon2, upriv->gen_pmcon3);
+}
+
+int pmc_ofdata_to_uc_platdata(struct udevice *dev)
+{
+	struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+	int ret;
+
+	ret = dev_read_u32(dev, "gpe0-dwx-mask", &upriv->gpe0_dwx_mask);
+	if (ret)
+		return log_msg_ret("no gpe0-dwx-mask", ret);
+	ret = dev_read_u32(dev, "gpe0-dwx-shift-base",
+			   &upriv->gpe0_dwx_shift_base);
+	if (ret)
+		return log_msg_ret("no gpe0-dwx-shift-base", ret);
+	ret = dev_read_u32(dev, "gpe0-sts", &upriv->gpe0_sts_reg);
+	if (ret)
+		return log_msg_ret("no gpe0-sts", ret);
+	upriv->gpe0_sts_reg += upriv->acpi_base;
+	ret = dev_read_u32(dev, "gpe0-en", &upriv->gpe0_en_reg);
+	if (ret)
+		return log_msg_ret("no gpe0-en", ret);
+	upriv->gpe0_en_reg += upriv->acpi_base;
+
+	return 0;
+}
+
+UCLASS_DRIVER(acpi_pmc) = {
+	.id		= UCLASS_ACPI_PMC,
+	.name		= "power-mgr",
+	.per_device_auto_alloc_size	= sizeof(struct acpi_pmc_upriv),
+};
diff --git a/drivers/power/acpi_pmc/pmc_emul.c b/drivers/power/acpi_pmc/pmc_emul.c
new file mode 100644
index 0000000..15cc7ac
--- /dev/null
+++ b/drivers/power/acpi_pmc/pmc_emul.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PCI emulation device for an x86 Power-Management Controller (PMC)
+ *
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+#include <asm/test.h>
+#include <power/acpi_pmc.h>
+
+/**
+ * struct pmc_emul_platdata - platform data for this device
+ *
+ * @command:	Current PCI command value
+ * @bar:	Current base address values
+ */
+struct pmc_emul_platdata {
+	u16 command;
+	u32 bar[6];
+};
+
+enum {
+	MEMMAP_SIZE	= 0x80,
+};
+
+static struct pci_bar {
+	int type;
+	u32 size;
+} barinfo[] = {
+	{ PCI_BASE_ADDRESS_MEM_TYPE_32, MEMMAP_SIZE },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ 0, 0 },
+	{ PCI_BASE_ADDRESS_SPACE_IO, 256 },
+};
+
+struct pmc_emul_priv {
+	u8 regs[MEMMAP_SIZE];
+};
+
+static int sandbox_pmc_emul_read_config(struct udevice *emul, uint offset,
+					ulong *valuep, enum pci_size_t size)
+{
+	struct pmc_emul_platdata *plat = dev_get_platdata(emul);
+
+	switch (offset) {
+	case PCI_COMMAND:
+		*valuep = plat->command;
+		break;
+	case PCI_HEADER_TYPE:
+		*valuep = 0;
+		break;
+	case PCI_VENDOR_ID:
+		*valuep = SANDBOX_PCI_VENDOR_ID;
+		break;
+	case PCI_DEVICE_ID:
+		*valuep = SANDBOX_PCI_PMC_EMUL_ID;
+		break;
+	case PCI_CLASS_DEVICE:
+		if (size == PCI_SIZE_8) {
+			*valuep = SANDBOX_PCI_CLASS_SUB_CODE;
+		} else {
+			*valuep = (SANDBOX_PCI_CLASS_CODE << 8) |
+					SANDBOX_PCI_CLASS_SUB_CODE;
+		}
+		break;
+	case PCI_CLASS_CODE:
+		*valuep = SANDBOX_PCI_CLASS_CODE;
+		break;
+	case PCI_BASE_ADDRESS_0:
+	case PCI_BASE_ADDRESS_1:
+	case PCI_BASE_ADDRESS_2:
+	case PCI_BASE_ADDRESS_3:
+	case PCI_BASE_ADDRESS_4:
+	case PCI_BASE_ADDRESS_5: {
+		int barnum;
+		u32 *bar;
+
+		barnum = pci_offset_to_barnum(offset);
+		bar = &plat->bar[barnum];
+
+		*valuep = sandbox_pci_read_bar(*bar, barinfo[barnum].type,
+					       barinfo[barnum].size);
+		break;
+	}
+	case PCI_CAPABILITY_LIST:
+		*valuep = PCI_CAP_ID_PM_OFFSET;
+		break;
+	}
+
+	return 0;
+}
+
+static int sandbox_pmc_emul_write_config(struct udevice *emul, uint offset,
+					 ulong value, enum pci_size_t size)
+{
+	struct pmc_emul_platdata *plat = dev_get_platdata(emul);
+
+	switch (offset) {
+	case PCI_COMMAND:
+		plat->command = value;
+		break;
+	case PCI_BASE_ADDRESS_0:
+	case PCI_BASE_ADDRESS_1: {
+		int barnum;
+		u32 *bar;
+
+		barnum = pci_offset_to_barnum(offset);
+		bar = &plat->bar[barnum];
+
+		debug("w bar %d=%lx\n", barnum, value);
+		*bar = value;
+		/* space indicator (bit#0) is read-only */
+		*bar |= barinfo[barnum].type;
+		break;
+	}
+	}
+
+	return 0;
+}
+
+static int sandbox_pmc_emul_find_bar(struct udevice *emul, unsigned int addr,
+				     int *barnump, unsigned int *offsetp)
+{
+	struct pmc_emul_platdata *plat = dev_get_platdata(emul);
+	int barnum;
+
+	for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) {
+		unsigned int size = barinfo[barnum].size;
+		u32 base = plat->bar[barnum] & ~PCI_BASE_ADDRESS_SPACE;
+
+		if (addr >= base && addr < base + size) {
+			*barnump = barnum;
+			*offsetp = addr - base;
+			return 0;
+		}
+	}
+	*barnump = -1;
+
+	return -ENOENT;
+}
+
+static int sandbox_pmc_emul_read_io(struct udevice *dev, unsigned int addr,
+				    ulong *valuep, enum pci_size_t size)
+{
+	unsigned int offset;
+	int barnum;
+	int ret;
+
+	ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
+	if (ret)
+		return ret;
+
+	if (barnum == 4)
+		*valuep = offset;
+	else if (barnum == 0)
+		*valuep = offset;
+
+	return 0;
+}
+
+static int sandbox_pmc_emul_write_io(struct udevice *dev, unsigned int addr,
+				     ulong value, enum pci_size_t size)
+{
+	unsigned int offset;
+	int barnum;
+	int ret;
+
+	ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int sandbox_pmc_emul_map_physmem(struct udevice *dev,
+					phys_addr_t addr, unsigned long *lenp,
+					void **ptrp)
+{
+	struct pmc_emul_priv *priv = dev_get_priv(dev);
+	unsigned int offset, avail;
+	int barnum;
+	int ret;
+
+	ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
+	if (ret)
+		return ret;
+
+	if (barnum == 0) {
+		*ptrp = priv->regs + offset;
+		avail = barinfo[0].size - offset;
+		if (avail > barinfo[0].size)
+			*lenp = 0;
+		else
+			*lenp = min(*lenp, (ulong)avail);
+
+		return 0;
+	}
+
+	return -ENOENT;
+}
+
+static int sandbox_pmc_probe(struct udevice *dev)
+{
+	struct pmc_emul_priv *priv = dev_get_priv(dev);
+	int i;
+
+	for (i = 0; i < MEMMAP_SIZE; i++)
+		priv->regs[i] = i;
+
+	return 0;
+}
+
+static struct dm_pci_emul_ops sandbox_pmc_emul_emul_ops = {
+	.read_config = sandbox_pmc_emul_read_config,
+	.write_config = sandbox_pmc_emul_write_config,
+	.read_io = sandbox_pmc_emul_read_io,
+	.write_io = sandbox_pmc_emul_write_io,
+	.map_physmem = sandbox_pmc_emul_map_physmem,
+};
+
+static const struct udevice_id sandbox_pmc_emul_ids[] = {
+	{ .compatible = "sandbox,pmc-emul" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_pmc_emul_emul) = {
+	.name		= "sandbox_pmc_emul_emul",
+	.id		= UCLASS_PCI_EMUL,
+	.of_match	= sandbox_pmc_emul_ids,
+	.ops		= &sandbox_pmc_emul_emul_ops,
+	.probe		= sandbox_pmc_probe,
+	.priv_auto_alloc_size = sizeof(struct pmc_emul_priv),
+	.platdata_auto_alloc_size = sizeof(struct pmc_emul_platdata),
+};
+
+static struct pci_device_id sandbox_pmc_emul_supported[] = {
+	{ PCI_VDEVICE(SANDBOX, SANDBOX_PCI_PMC_EMUL_ID) },
+	{},
+};
+
+U_BOOT_PCI_DEVICE(sandbox_pmc_emul_emul, sandbox_pmc_emul_supported);
diff --git a/drivers/power/acpi_pmc/sandbox.c b/drivers/power/acpi_pmc/sandbox.c
new file mode 100644
index 0000000..7fbbf97
--- /dev/null
+++ b/drivers/power/acpi_pmc/sandbox.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sandbox PMC for testing
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#define LOG_CATEGORY UCLASS_ACPI_PMC
+
+#include <common.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <power/acpi_pmc.h>
+
+#define GPIO_GPE_CFG		0x1050
+
+/* Memory mapped IO registers behind PMC_BASE_ADDRESS */
+#define PRSTS			0x1000
+#define GEN_PMCON1		0x1020
+#define GEN_PMCON2		0x1024
+#define GEN_PMCON3		0x1028
+
+/* Offset of TCO registers from ACPI base I/O address */
+#define TCO_REG_OFFSET		0x60
+#define TCO1_STS	0x64
+#define TCO2_STS	0x66
+#define TCO1_CNT	0x68
+#define TCO2_CNT	0x6a
+
+struct sandbox_pmc_priv {
+	ulong base;
+};
+
+static int sandbox_pmc_fill_power_state(struct udevice *dev)
+{
+	struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+
+	upriv->tco1_sts = inw(upriv->acpi_base + TCO1_STS);
+	upriv->tco2_sts = inw(upriv->acpi_base + TCO2_STS);
+
+	upriv->prsts = readl(upriv->pmc_bar0 + PRSTS);
+	upriv->gen_pmcon1 = readl(upriv->pmc_bar0 + GEN_PMCON1);
+	upriv->gen_pmcon2 = readl(upriv->pmc_bar0 + GEN_PMCON2);
+	upriv->gen_pmcon3 = readl(upriv->pmc_bar0 + GEN_PMCON3);
+
+	return 0;
+}
+
+static int sandbox_prev_sleep_state(struct udevice *dev, int prev_sleep_state)
+{
+	return prev_sleep_state;
+}
+
+static int sandbox_disable_tco(struct udevice *dev)
+{
+	struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+
+	pmc_disable_tco_base(upriv->acpi_base + TCO_REG_OFFSET);
+
+	return 0;
+}
+
+static int sandbox_pmc_probe(struct udevice *dev)
+{
+	struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+	struct udevice *bus;
+	ulong base;
+
+	uclass_first_device(UCLASS_PCI, &bus);
+	base = dm_pci_read_bar32(dev, 0);
+	if (base == FDT_ADDR_T_NONE)
+		return log_msg_ret("No base address", -EINVAL);
+	upriv->pmc_bar0 = map_sysmem(base, 0x2000);
+	upriv->gpe_cfg = (u32 *)(upriv->pmc_bar0 + GPIO_GPE_CFG);
+
+	return pmc_ofdata_to_uc_platdata(dev);
+}
+
+static struct acpi_pmc_ops sandbox_pmc_ops = {
+	.init			= sandbox_pmc_fill_power_state,
+	.prev_sleep_state	= sandbox_prev_sleep_state,
+	.disable_tco		= sandbox_disable_tco,
+};
+
+static const struct udevice_id sandbox_pmc_ids[] = {
+	{ .compatible = "sandbox,pmc" },
+	{ }
+};
+
+U_BOOT_DRIVER(pmc_sandbox) = {
+	.name = "pmc_sandbox",
+	.id = UCLASS_ACPI_PMC,
+	.of_match = sandbox_pmc_ids,
+	.probe = sandbox_pmc_probe,
+	.ops = &sandbox_pmc_ops,
+	.priv_auto_alloc_size = sizeof(struct sandbox_pmc_priv),
+};
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 8588866..fae2040 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -142,7 +142,6 @@
 
 config ICH_SPI
 	bool "Intel ICH SPI driver"
-	imply SPI_FLASH_BAR
 	help
 	  Enable the Intel ICH SPI driver. This driver can be used to
 	  access the SPI NOR flash on platforms embedding this Intel
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index cf4de9e..f076e92 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -17,7 +17,7 @@
 #ifdef CONFIG_DM_SPI
 #include <asm/arch/at91_spi.h>
 #endif
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 #include <asm/gpio.h>
 #endif
 
@@ -228,7 +228,7 @@
 	unsigned int freq;		/* Default frequency */
 	unsigned int mode;
 	ulong bus_clk_rate;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	struct gpio_desc cs_gpios[MAX_CS_COUNT];
 #endif
 };
@@ -285,7 +285,7 @@
 
 static void atmel_spi_cs_activate(struct udevice *dev)
 {
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	struct udevice *bus = dev_get_parent(dev);
 	struct atmel_spi_priv *priv = dev_get_priv(bus);
 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
@@ -300,7 +300,7 @@
 
 static void atmel_spi_cs_deactivate(struct udevice *dev)
 {
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	struct udevice *bus = dev_get_parent(dev);
 	struct atmel_spi_priv *priv = dev_get_priv(bus);
 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
@@ -468,7 +468,7 @@
 
 	bus_plat->regs = (struct at91_spi *)devfdt_get_addr(bus);
 
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
 	struct atmel_spi_priv *priv = dev_get_priv(bus);
 	int i;
 
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index 91e613e..66ff8ee 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -126,7 +126,7 @@
 
 static int request_gpio_cs(struct udevice *bus)
 {
-#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_SPL_BUILD)
+#if CONFIG_IS_ENABLED(DM_GPIO) && !defined(CONFIG_SPL_BUILD)
 	struct dw_spi_priv *priv = dev_get_priv(bus);
 	int ret;
 
@@ -373,7 +373,7 @@
  */
 __weak void external_cs_manage(struct udevice *dev, bool on)
 {
-#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_SPL_BUILD)
+#if CONFIG_IS_ENABLED(DM_GPIO) && !defined(CONFIG_SPL_BUILD)
 	struct dw_spi_priv *priv = dev_get_priv(dev->parent);
 
 	if (!dm_gpio_is_valid(&priv->cs_gpio))
diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c
index fbb58c7..133b25b 100644
--- a/drivers/spi/ich.c
+++ b/drivers/spi/ich.c
@@ -5,27 +5,44 @@
  * This file is derived from the flashrom project.
  */
 
+#define LOG_CATEGORY	UCLASS_SPI
+
 #include <common.h>
+#include <div64.h>
 #include <dm.h>
+#include <dt-structs.h>
 #include <errno.h>
 #include <malloc.h>
 #include <pch.h>
 #include <pci.h>
 #include <pci_ids.h>
 #include <spi.h>
-#include <asm/io.h>
+#include <spi_flash.h>
 #include <spi-mem.h>
-#include <div64.h>
+#include <spl.h>
+#include <asm/fast_spi.h>
+#include <asm/io.h>
+#include <asm/mtrr.h>
+#include <linux/sizes.h>
 
 #include "ich.h"
 
-DECLARE_GLOBAL_DATA_PTR;
-
 #ifdef DEBUG_TRACE
 #define debug_trace(fmt, args...) debug(fmt, ##args)
 #else
 #define debug_trace(x, args...)
 #endif
+
+struct ich_spi_platdata {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct dtd_intel_fast_spi dtplat;
+#endif
+	enum ich_version ich_version;	/* Controller version, 7 or 9 */
+	bool lockdown;			/* lock down controller settings? */
+	ulong mmio_base;		/* Base of MMIO registers */
+	pci_dev_t bdf;			/* PCI address used by of-platdata */
+	bool hwseq;			/* Use hardware sequencing (not s/w) */
+};
 
 static u8 ich_readb(struct ich_spi_priv *priv, int reg)
 {
@@ -89,22 +106,27 @@
 	const uint32_t bbar_mask = 0x00ffff00;
 	uint32_t ichspi_bbar;
 
-	minaddr &= bbar_mask;
-	ichspi_bbar = ich_readl(ctlr, ctlr->bbar) & ~bbar_mask;
-	ichspi_bbar |= minaddr;
-	ich_writel(ctlr, ichspi_bbar, ctlr->bbar);
+	if (ctlr->bbar) {
+		minaddr &= bbar_mask;
+		ichspi_bbar = ich_readl(ctlr, ctlr->bbar) & ~bbar_mask;
+		ichspi_bbar |= minaddr;
+		ich_writel(ctlr, ichspi_bbar, ctlr->bbar);
+	}
 }
 
 /* @return 1 if the SPI flash supports the 33MHz speed */
-static int ich9_can_do_33mhz(struct udevice *dev)
+static bool ich9_can_do_33mhz(struct udevice *dev)
 {
+	struct ich_spi_priv *priv = dev_get_priv(dev);
 	u32 fdod, speed;
 
+	if (!CONFIG_IS_ENABLED(PCI))
+		return false;
 	/* Observe SPI Descriptor Component Section 0 */
-	dm_pci_write_config32(dev->parent, 0xb0, 0x1000);
+	dm_pci_write_config32(priv->pch, 0xb0, 0x1000);
 
 	/* Extract the Write/Erase SPI Frequency from descriptor */
-	dm_pci_read_config32(dev->parent, 0xb4, &fdod);
+	dm_pci_read_config32(priv->pch, 0xb4, &fdod);
 
 	/* Bits 23:21 have the fast read clock frequency, 0=20MHz, 1=33MHz */
 	speed = (fdod >> 21) & 7;
@@ -112,67 +134,6 @@
 	return speed == 1;
 }
 
-static int ich_init_controller(struct udevice *dev,
-			       struct ich_spi_platdata *plat,
-			       struct ich_spi_priv *ctlr)
-{
-	ulong sbase_addr;
-	void *sbase;
-
-	/* SBASE is similar */
-	pch_get_spi_base(dev->parent, &sbase_addr);
-	sbase = (void *)sbase_addr;
-	debug("%s: sbase=%p\n", __func__, sbase);
-
-	if (plat->ich_version == ICHV_7) {
-		struct ich7_spi_regs *ich7_spi = sbase;
-
-		ctlr->opmenu = offsetof(struct ich7_spi_regs, opmenu);
-		ctlr->menubytes = sizeof(ich7_spi->opmenu);
-		ctlr->optype = offsetof(struct ich7_spi_regs, optype);
-		ctlr->addr = offsetof(struct ich7_spi_regs, spia);
-		ctlr->data = offsetof(struct ich7_spi_regs, spid);
-		ctlr->databytes = sizeof(ich7_spi->spid);
-		ctlr->status = offsetof(struct ich7_spi_regs, spis);
-		ctlr->control = offsetof(struct ich7_spi_regs, spic);
-		ctlr->bbar = offsetof(struct ich7_spi_regs, bbar);
-		ctlr->preop = offsetof(struct ich7_spi_regs, preop);
-		ctlr->base = ich7_spi;
-	} else if (plat->ich_version == ICHV_9) {
-		struct ich9_spi_regs *ich9_spi = sbase;
-
-		ctlr->opmenu = offsetof(struct ich9_spi_regs, opmenu);
-		ctlr->menubytes = sizeof(ich9_spi->opmenu);
-		ctlr->optype = offsetof(struct ich9_spi_regs, optype);
-		ctlr->addr = offsetof(struct ich9_spi_regs, faddr);
-		ctlr->data = offsetof(struct ich9_spi_regs, fdata);
-		ctlr->databytes = sizeof(ich9_spi->fdata);
-		ctlr->status = offsetof(struct ich9_spi_regs, ssfs);
-		ctlr->control = offsetof(struct ich9_spi_regs, ssfc);
-		ctlr->speed = ctlr->control + 2;
-		ctlr->bbar = offsetof(struct ich9_spi_regs, bbar);
-		ctlr->preop = offsetof(struct ich9_spi_regs, preop);
-		ctlr->bcr = offsetof(struct ich9_spi_regs, bcr);
-		ctlr->pr = &ich9_spi->pr[0];
-		ctlr->base = ich9_spi;
-	} else {
-		debug("ICH SPI: Unrecognised ICH version %d\n",
-		      plat->ich_version);
-		return -EINVAL;
-	}
-
-	/* Work out the maximum speed we can support */
-	ctlr->max_speed = 20000000;
-	if (plat->ich_version == ICHV_9 && ich9_can_do_33mhz(dev))
-		ctlr->max_speed = 33000000;
-	debug("ICH SPI: Version ID %d detected at %p, speed %ld\n",
-	      plat->ich_version, ctlr->base, ctlr->max_speed);
-
-	ich_set_bbar(ctlr, 0);
-
-	return 0;
-}
-
 static void spi_lock_down(struct ich_spi_platdata *plat, void *sbase)
 {
 	if (plat->ich_version == ICHV_7) {
@@ -233,8 +194,7 @@
 		}
 
 		if (opcode_index == ctlr->menubytes) {
-			printf("ICH SPI: Opcode %x not found\n",
-			       trans->opcode);
+			debug("ICH SPI: Opcode %x not found\n", trans->opcode);
 			return -EINVAL;
 		}
 
@@ -242,8 +202,8 @@
 		optype = (optypes >> (opcode_index * 2)) & 0x3;
 
 		if (optype != trans->type) {
-			printf("ICH SPI: Transaction doesn't fit type %d\n",
-			       optype);
+			debug("ICH SPI: Transaction doesn't fit type %d\n",
+			      optype);
 			return -ENOSPC;
 		}
 		return opcode_index;
@@ -274,9 +234,9 @@
 		}
 		udelay(10);
 	}
+	debug("ICH SPI: SCIP timeout, read %x, expected %x, wts %x %x\n",
+	      status, bitmask, wait_til_set, status & bitmask);
 
-	printf("ICH SPI: SCIP timeout, read %x, expected %x\n",
-	       status, bitmask);
 	return -ETIMEDOUT;
 }
 
@@ -295,7 +255,8 @@
 	ich_writel(ctlr, SPI_OPMENU_UPPER, ctlr->opmenu + sizeof(u32));
 }
 
-static int ich_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
+static int ich_spi_exec_op_swseq(struct spi_slave *slave,
+				 const struct spi_mem_op *op)
 {
 	struct udevice *bus = dev_get_parent(slave->dev);
 	struct ich_spi_platdata *plat = dev_get_platdata(bus);
@@ -466,6 +427,228 @@
 	return 0;
 }
 
+/*
+ * Ensure read/write xfer len is not greater than SPIBAR_FDATA_FIFO_SIZE and
+ * that the operation does not cross page boundary.
+ */
+static uint get_xfer_len(u32 offset, int len, int page_size)
+{
+	uint xfer_len = min(len, SPIBAR_FDATA_FIFO_SIZE);
+	uint bytes_left = ALIGN(offset, page_size) - offset;
+
+	if (bytes_left)
+		xfer_len = min(xfer_len, bytes_left);
+
+	return xfer_len;
+}
+
+/* Fill FDATAn FIFO in preparation for a write transaction */
+static void fill_xfer_fifo(struct fast_spi_regs *regs, const void *data,
+			   uint len)
+{
+	memcpy(regs->fdata, data, len);
+}
+
+/* Drain FDATAn FIFO after a read transaction populates data */
+static void drain_xfer_fifo(struct fast_spi_regs *regs, void *dest, uint len)
+{
+	memcpy(dest, regs->fdata, len);
+}
+
+/* Fire up a transfer using the hardware sequencer */
+static void start_hwseq_xfer(struct fast_spi_regs *regs, uint hsfsts_cycle,
+			     uint offset, uint len)
+{
+	/* Make sure all W1C status bits get cleared */
+	u32 hsfsts;
+
+	hsfsts = readl(&regs->hsfsts_ctl);
+	hsfsts &= ~(HSFSTS_FCYCLE_MASK | HSFSTS_FDBC_MASK);
+	hsfsts |= HSFSTS_AEL | HSFSTS_FCERR | HSFSTS_FDONE;
+
+	/* Set up transaction parameters */
+	hsfsts |= hsfsts_cycle << HSFSTS_FCYCLE_SHIFT;
+	hsfsts |= ((len - 1) << HSFSTS_FDBC_SHIFT) & HSFSTS_FDBC_MASK;
+	hsfsts |= HSFSTS_FGO;
+
+	writel(offset, &regs->faddr);
+	writel(hsfsts, &regs->hsfsts_ctl);
+}
+
+static int wait_for_hwseq_xfer(struct fast_spi_regs *regs, uint offset)
+{
+	ulong start;
+	u32 hsfsts;
+
+	start = get_timer(0);
+	do {
+		hsfsts = readl(&regs->hsfsts_ctl);
+		if (hsfsts & HSFSTS_FCERR) {
+			debug("SPI transaction error at offset %x HSFSTS = %08x\n",
+			      offset, hsfsts);
+			return -EIO;
+		}
+		if (hsfsts & HSFSTS_AEL)
+			return -EPERM;
+
+		if (hsfsts & HSFSTS_FDONE)
+			return 0;
+	} while (get_timer(start) < SPIBAR_HWSEQ_XFER_TIMEOUT_MS);
+
+	debug("SPI transaction timeout at offset %x HSFSTS = %08x, timer %d\n",
+	      offset, hsfsts, (uint)get_timer(start));
+
+	return -ETIMEDOUT;
+}
+
+/**
+ * exec_sync_hwseq_xfer() - Execute flash transfer by hardware sequencing
+ *
+ * This waits until complete or timeout
+ *
+ * @regs: SPI registers
+ * @hsfsts_cycle: Cycle type (enum hsfsts_cycle_t)
+ * @offset: Offset to access
+ * @len: Number of bytes to transfer (can be 0)
+ * @return 0 if OK, -EIO on flash-cycle error (FCERR), -EPERM on access error
+ *	(AEL), -ETIMEDOUT on timeout
+ */
+static int exec_sync_hwseq_xfer(struct fast_spi_regs *regs, uint hsfsts_cycle,
+				uint offset, uint len)
+{
+	start_hwseq_xfer(regs, hsfsts_cycle, offset, len);
+
+	return wait_for_hwseq_xfer(regs, offset);
+}
+
+static int ich_spi_exec_op_hwseq(struct spi_slave *slave,
+				 const struct spi_mem_op *op)
+{
+	struct spi_flash *flash = dev_get_uclass_priv(slave->dev);
+	struct udevice *bus = dev_get_parent(slave->dev);
+	struct ich_spi_priv *priv = dev_get_priv(bus);
+	struct fast_spi_regs *regs = priv->base;
+	uint page_size;
+	uint offset;
+	int cycle;
+	uint len;
+	bool out;
+	int ret;
+	u8 *buf;
+
+	offset = op->addr.val;
+	len = op->data.nbytes;
+
+	switch (op->cmd.opcode) {
+	case SPINOR_OP_RDID:
+		cycle = HSFSTS_CYCLE_RDID;
+		break;
+	case SPINOR_OP_READ_FAST:
+		cycle = HSFSTS_CYCLE_READ;
+		break;
+	case SPINOR_OP_PP:
+		cycle = HSFSTS_CYCLE_WRITE;
+		break;
+	case SPINOR_OP_WREN:
+		/* Nothing needs to be done */
+		return 0;
+	case SPINOR_OP_WRSR:
+		cycle = HSFSTS_CYCLE_WR_STATUS;
+		break;
+	case SPINOR_OP_RDSR:
+		cycle = HSFSTS_CYCLE_RD_STATUS;
+		break;
+	case SPINOR_OP_WRDI:
+		return 0;  /* ignore */
+	case SPINOR_OP_BE_4K:
+		cycle = HSFSTS_CYCLE_4K_ERASE;
+		while (len) {
+			uint xfer_len = 0x1000;
+
+			ret = exec_sync_hwseq_xfer(regs, cycle, offset, 0);
+			if (ret)
+				return ret;
+			offset += xfer_len;
+			len -= xfer_len;
+		}
+		return 0;
+	default:
+		debug("Unknown cycle %x\n", op->cmd.opcode);
+		return -EINVAL;
+	};
+
+	out = op->data.dir == SPI_MEM_DATA_OUT;
+	buf = out ? (u8 *)op->data.buf.out : op->data.buf.in;
+	page_size = flash->page_size ? : 256;
+
+	while (len) {
+		uint xfer_len = get_xfer_len(offset, len, page_size);
+
+		if (out)
+			fill_xfer_fifo(regs, buf, xfer_len);
+
+		ret = exec_sync_hwseq_xfer(regs, cycle, offset, xfer_len);
+		if (ret)
+			return ret;
+
+		if (!out)
+			drain_xfer_fifo(regs, buf, xfer_len);
+
+		offset += xfer_len;
+		buf += xfer_len;
+		len -= xfer_len;
+	}
+
+	return 0;
+}
+
+static int ich_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
+{
+	struct udevice *bus = dev_get_parent(slave->dev);
+	struct ich_spi_platdata *plat = dev_get_platdata(bus);
+	int ret;
+
+	bootstage_start(BOOTSTAGE_ID_ACCUM_SPI, "fast_spi");
+	if (plat->hwseq)
+		ret = ich_spi_exec_op_hwseq(slave, op);
+	else
+		ret = ich_spi_exec_op_swseq(slave, op);
+	bootstage_accum(BOOTSTAGE_ID_ACCUM_SPI);
+
+	return ret;
+}
+
+static int ich_get_mmap_bus(struct udevice *bus, ulong *map_basep,
+			    uint *map_sizep, uint *offsetp)
+{
+	pci_dev_t spi_bdf;
+
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct pci_child_platdata *pplat = dev_get_parent_platdata(bus);
+
+	spi_bdf = pplat->devfn;
+#else
+	struct ich_spi_platdata *plat = dev_get_platdata(bus);
+
+	/*
+	 * We cannot rely on plat->bdf being set up yet since this method can
+	 * be called before the device is probed. Use the of-platdata directly
+	 * instead.
+	 */
+	spi_bdf = pci_ofplat_get_devfn(plat->dtplat.reg[0]);
+#endif
+
+	return fast_spi_get_bios_mmap(spi_bdf, map_basep, map_sizep, offsetp);
+}
+
+static int ich_get_mmap(struct udevice *dev, ulong *map_basep, uint *map_sizep,
+			uint *offsetp)
+{
+	struct udevice *bus = dev_get_parent(dev);
+
+	return ich_get_mmap_bus(bus, map_basep, map_sizep, offsetp);
+}
+
 static int ich_spi_adjust_size(struct spi_slave *slave, struct spi_mem_op *op)
 {
 	unsigned int page_offset;
@@ -480,9 +663,11 @@
 		page_offset = do_div(aux, ICH_BOUNDARY);
 	}
 
-	if (op->data.dir == SPI_MEM_DATA_IN && slave->max_read_size) {
-		op->data.nbytes = min(ICH_BOUNDARY - page_offset,
-				      slave->max_read_size);
+	if (op->data.dir == SPI_MEM_DATA_IN) {
+		if (slave->max_read_size) {
+			op->data.nbytes = min(ICH_BOUNDARY - page_offset,
+					      slave->max_read_size);
+		}
 	} else if (slave->max_write_size) {
 		op->data.nbytes = min(ICH_BOUNDARY - page_offset,
 				      slave->max_write_size);
@@ -493,26 +678,18 @@
 	return 0;
 }
 
-static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen,
-			const void *dout, void *din, unsigned long flags)
-{
-	printf("ICH SPI: Only supports memory operations\n");
-	return -1;
-}
-
-static int ich_spi_probe(struct udevice *dev)
+static int ich_protect_lockdown(struct udevice *dev)
 {
 	struct ich_spi_platdata *plat = dev_get_platdata(dev);
 	struct ich_spi_priv *priv = dev_get_priv(dev);
-	uint8_t bios_cntl;
-	int ret;
+	int ret = -ENOSYS;
 
-	ret = ich_init_controller(dev, plat, priv);
-	if (ret)
-		return ret;
 	/* Disable the BIOS write protect so write commands are allowed */
-	ret = pch_set_spi_protect(dev->parent, false);
+	if (priv->pch)
+		ret = pch_set_spi_protect(priv->pch, false);
 	if (ret == -ENOSYS) {
+		u8 bios_cntl;
+
 		bios_cntl = ich_readb(priv, priv->bcr);
 		bios_cntl &= ~BIT(5);	/* clear Enable InSMM_STS (EISS) */
 		bios_cntl |= 1;		/* Write Protect Disable (WPD) */
@@ -529,6 +706,111 @@
 		spi_lock_down(plat, priv->base);
 	}
 
+	return 0;
+}
+
+static int ich_init_controller(struct udevice *dev,
+			       struct ich_spi_platdata *plat,
+			       struct ich_spi_priv *ctlr)
+{
+	if (spl_phase() == PHASE_TPL) {
+		struct ich_spi_platdata *plat = dev_get_platdata(dev);
+		int ret;
+
+		ret = fast_spi_early_init(plat->bdf, plat->mmio_base);
+		if (ret)
+			return ret;
+	}
+
+	ctlr->base = (void *)plat->mmio_base;
+	if (plat->ich_version == ICHV_7) {
+		struct ich7_spi_regs *ich7_spi = ctlr->base;
+
+		ctlr->opmenu = offsetof(struct ich7_spi_regs, opmenu);
+		ctlr->menubytes = sizeof(ich7_spi->opmenu);
+		ctlr->optype = offsetof(struct ich7_spi_regs, optype);
+		ctlr->addr = offsetof(struct ich7_spi_regs, spia);
+		ctlr->data = offsetof(struct ich7_spi_regs, spid);
+		ctlr->databytes = sizeof(ich7_spi->spid);
+		ctlr->status = offsetof(struct ich7_spi_regs, spis);
+		ctlr->control = offsetof(struct ich7_spi_regs, spic);
+		ctlr->bbar = offsetof(struct ich7_spi_regs, bbar);
+		ctlr->preop = offsetof(struct ich7_spi_regs, preop);
+	} else if (plat->ich_version == ICHV_9) {
+		struct ich9_spi_regs *ich9_spi = ctlr->base;
+
+		ctlr->opmenu = offsetof(struct ich9_spi_regs, opmenu);
+		ctlr->menubytes = sizeof(ich9_spi->opmenu);
+		ctlr->optype = offsetof(struct ich9_spi_regs, optype);
+		ctlr->addr = offsetof(struct ich9_spi_regs, faddr);
+		ctlr->data = offsetof(struct ich9_spi_regs, fdata);
+		ctlr->databytes = sizeof(ich9_spi->fdata);
+		ctlr->status = offsetof(struct ich9_spi_regs, ssfs);
+		ctlr->control = offsetof(struct ich9_spi_regs, ssfc);
+		ctlr->speed = ctlr->control + 2;
+		ctlr->bbar = offsetof(struct ich9_spi_regs, bbar);
+		ctlr->preop = offsetof(struct ich9_spi_regs, preop);
+		ctlr->bcr = offsetof(struct ich9_spi_regs, bcr);
+		ctlr->pr = &ich9_spi->pr[0];
+	} else if (plat->ich_version == ICHV_APL) {
+	} else {
+		debug("ICH SPI: Unrecognised ICH version %d\n",
+		      plat->ich_version);
+		return -EINVAL;
+	}
+
+	/* Work out the maximum speed we can support */
+	ctlr->max_speed = 20000000;
+	if (plat->ich_version == ICHV_9 && ich9_can_do_33mhz(dev))
+		ctlr->max_speed = 33000000;
+	debug("ICH SPI: Version ID %d detected at %lx, speed %ld\n",
+	      plat->ich_version, plat->mmio_base, ctlr->max_speed);
+
+	ich_set_bbar(ctlr, 0);
+
+	return 0;
+}
+
+static int ich_cache_bios_region(struct udevice *dev)
+{
+	ulong map_base;
+	uint map_size;
+	uint offset;
+	ulong base;
+	int ret;
+
+	ret = ich_get_mmap_bus(dev, &map_base, &map_size, &offset);
+	if (ret)
+		return ret;
+
+	/* Don't use WRBACK since we are not supposed to write to SPI flash */
+	base = SZ_4G - map_size;
+	mtrr_set_next_var(MTRR_TYPE_WRPROT, base, map_size);
+	log_debug("BIOS cache base=%lx, size=%x\n", base, (uint)map_size);
+
+	return 0;
+}
+
+static int ich_spi_probe(struct udevice *dev)
+{
+	struct ich_spi_platdata *plat = dev_get_platdata(dev);
+	struct ich_spi_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = ich_init_controller(dev, plat, priv);
+	if (ret)
+		return ret;
+
+	if (spl_phase() == PHASE_TPL) {
+		/* Cache the BIOS to speed things up */
+		ret = ich_cache_bios_region(dev);
+		if (ret)
+			return ret;
+	} else {
+		ret = ich_protect_lockdown(dev);
+		if (ret)
+			return ret;
+	}
 	priv->cur_speed = priv->max_speed;
 
 	return 0;
@@ -570,9 +852,11 @@
 
 	/*
 	 * Yes this controller can only write a small number of bytes at
-	 * once! The limit is typically 64 bytes.
+	 * once! The limit is typically 64 bytes. For hardware sequencing a
+	 * a loop is used to get around this.
 	 */
-	slave->max_write_size = priv->databytes;
+	if (!plat->hwseq)
+		slave->max_write_size = priv->databytes;
 	/*
 	 * ICH 7 SPI controller only supports array read command
 	 * and byte program command for SST flash
@@ -586,23 +870,37 @@
 static int ich_spi_ofdata_to_platdata(struct udevice *dev)
 {
 	struct ich_spi_platdata *plat = dev_get_platdata(dev);
-	int node = dev_of_offset(dev);
-	int ret;
 
-	ret = fdt_node_check_compatible(gd->fdt_blob, node, "intel,ich7-spi");
-	if (ret == 0) {
-		plat->ich_version = ICHV_7;
-	} else {
-		ret = fdt_node_check_compatible(gd->fdt_blob, node,
-						"intel,ich9-spi");
-		if (ret == 0)
-			plat->ich_version = ICHV_9;
-	}
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct ich_spi_priv *priv = dev_get_priv(dev);
 
-	plat->lockdown = fdtdec_get_bool(gd->fdt_blob, node,
-					 "intel,spi-lock-down");
+	/* Find a PCH if there is one */
+	uclass_first_device(UCLASS_PCH, &priv->pch);
+	if (!priv->pch)
+		priv->pch = dev_get_parent(dev);
 
-	return ret;
+	plat->ich_version = dev_get_driver_data(dev);
+	plat->lockdown = dev_read_bool(dev, "intel,spi-lock-down");
+	if (plat->ich_version == ICHV_APL) {
+		plat->mmio_base = dm_pci_read_bar32(dev, 0);
+	} else  {
+		/* SBASE is similar */
+		pch_get_spi_base(priv->pch, &plat->mmio_base);
+	}
+	/*
+	 * Use an int so that the property is present in of-platdata even
+	 * when false.
+	 */
+	plat->hwseq = dev_read_u32_default(dev, "intel,hardware-seq", 0);
+#else
+	plat->ich_version = ICHV_APL;
+	plat->mmio_base = plat->dtplat.early_regs[0];
+	plat->bdf = pci_ofplat_get_devfn(plat->dtplat.reg[0]);
+	plat->hwseq = plat->dtplat.intel_hardware_seq;
+#endif
+	debug("%s: mmio_base=%lx\n", __func__, plat->mmio_base);
+
+	return 0;
 }
 
 static const struct spi_controller_mem_ops ich_controller_mem_ops = {
@@ -612,10 +910,11 @@
 };
 
 static const struct dm_spi_ops ich_spi_ops = {
-	.xfer		= ich_spi_xfer,
+	/* xfer is not supported */
 	.set_speed	= ich_spi_set_speed,
 	.set_mode	= ich_spi_set_mode,
 	.mem_ops	= &ich_controller_mem_ops,
+	.get_mmap	= ich_get_mmap,
 	/*
 	 * cs_info is not needed, since we require all chip selects to be
 	 * in the device tree explicitly
@@ -623,13 +922,14 @@
 };
 
 static const struct udevice_id ich_spi_ids[] = {
-	{ .compatible = "intel,ich7-spi" },
-	{ .compatible = "intel,ich9-spi" },
+	{ .compatible = "intel,ich7-spi", ICHV_7 },
+	{ .compatible = "intel,ich9-spi", ICHV_9 },
+	{ .compatible = "intel,fast-spi", ICHV_APL },
 	{ }
 };
 
-U_BOOT_DRIVER(ich_spi) = {
-	.name	= "ich_spi",
+U_BOOT_DRIVER(intel_fast_spi) = {
+	.name	= "intel_fast_spi",
 	.id	= UCLASS_SPI,
 	.of_match = ich_spi_ids,
 	.ops	= &ich_spi_ops,
diff --git a/drivers/spi/ich.h b/drivers/spi/ich.h
index 3dfb2aa..d7f1ffd 100644
--- a/drivers/spi/ich.h
+++ b/drivers/spi/ich.h
@@ -163,16 +163,51 @@
 
 #define ICH_BOUNDARY	0x1000
 
+#define HSFSTS_FDBC_SHIFT	24
+#define HSFSTS_FDBC_MASK	(0x3f << HSFSTS_FDBC_SHIFT)
+#define HSFSTS_WET		BIT(21)
+#define HSFSTS_FCYCLE_SHIFT	17
+#define HSFSTS_FCYCLE_MASK	(0xf << HSFSTS_FCYCLE_SHIFT)
+
+/* Supported flash cycle types */
+enum hsfsts_cycle_t {
+	HSFSTS_CYCLE_READ	= 0,
+	HSFSTS_CYCLE_WRITE	= 2,
+	HSFSTS_CYCLE_4K_ERASE,
+	HSFSTS_CYCLE_64K_ERASE,
+	HSFSTS_CYCLE_RDSFDP,
+	HSFSTS_CYCLE_RDID,
+	HSFSTS_CYCLE_WR_STATUS,
+	HSFSTS_CYCLE_RD_STATUS,
+};
+
+#define HSFSTS_FGO		BIT(16)
+#define HSFSTS_FLOCKDN		BIT(15)
+#define HSFSTS_FDV		BIT(14)
+#define HSFSTS_FDOPSS		BIT(13)
+#define HSFSTS_WRSDIS		BIT(11)
+#define HSFSTS_SAF_CE		BIT(8)
+#define HSFSTS_SAF_ACTIVE	BIT(7)
+#define HSFSTS_SAF_LE		BIT(6)
+#define HSFSTS_SCIP		BIT(5)
+#define HSFSTS_SAF_DLE		BIT(4)
+#define HSFSTS_SAF_ERROR	BIT(3)
+#define HSFSTS_AEL		BIT(2)
+#define HSFSTS_FCERR		BIT(1)
+#define HSFSTS_FDONE		BIT(0)
+#define HSFSTS_W1C_BITS		0xff
+
+/* Maximum bytes of data that can fit in FDATAn (0x10) registers */
+#define SPIBAR_FDATA_FIFO_SIZE		0x40
+
+#define SPIBAR_HWSEQ_XFER_TIMEOUT_MS	5000
+
 enum ich_version {
 	ICHV_7,
 	ICHV_9,
+	ICHV_APL,
 };
 
-struct ich_spi_platdata {
-	enum ich_version ich_version;	/* Controller version, 7 or 9 */
-	bool lockdown;			/* lock down controller settings? */
-};
-
 struct ich_spi_priv {
 	int opmenu;
 	int menubytes;
@@ -191,6 +226,7 @@
 	ulong max_speed;	/* Maximum bus speed in MHz */
 	ulong cur_speed;	/* Current bus speed */
 	struct spi_trans trans;	/* current transaction in progress */
+	struct udevice *pch;	/* PCH, used to control SPI access */
 };
 
 #endif /* _ICH_H_ */
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 665611f..af910e9 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -85,11 +85,14 @@
 		const void *dout, void *din, unsigned long flags)
 {
 	struct udevice *bus = dev->parent;
+	struct dm_spi_ops *ops = spi_get_ops(bus);
 
 	if (bus->uclass->uc_drv->id != UCLASS_SPI)
 		return -EOPNOTSUPP;
+	if (!ops->xfer)
+		return -ENOSYS;
 
-	return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags);
+	return ops->xfer(dev, bitlen, dout, din, flags);
 }
 
 int dm_spi_get_mmap(struct udevice *dev, ulong *map_basep, uint *map_sizep,
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index 5f4bc6e..96cc492 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -174,6 +174,29 @@
 	help
 	  Select this to enable Time-Stamp Counter (TSC) timer for x86.
 
+config X86_TSC_READ_BASE
+	bool "Read the TSC timer base on start-up"
+	depends on X86_TSC_TIMER
+	help
+	  On x86 platforms the TSC timer tick starts at the value 0 on reset.
+	  This it makes no sense to read the timer on boot and use that as the
+	  base, since we will miss some time taken to load U-Boot, etc. This
+	  delay is controlled by the SoC and we cannot reduce it, but for
+	  bootstage we want to record the time since reset as accurately as
+	  possible.
+
+	  The only exception is when U-Boot is used as a secondary bootloader,
+	  where this option should be enabled.
+
+config TPL_X86_TSC_TIMER_NATIVE
+	bool "x86 TSC timer uses native calibration"
+	depends on TPL && X86_TSC_TIMER
+	help
+	  Selects native timer calibration for TPL and don't include the other
+	  methods in the code. This helps to reduce code size in TPL and works
+	  on fairly modern Intel chips. Code-size reductions is about 700
+	  bytes.
+
 config MTK_TIMER
 	bool "MediaTek timer support"
 	depends on TIMER
diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c
index 0df551f..43cb2d8 100644
--- a/drivers/timer/tsc_timer.c
+++ b/drivers/timer/tsc_timer.c
@@ -50,8 +50,7 @@
 		return 0;
 
 	crystal_freq = tsc_info.ecx / 1000;
-
-	if (!crystal_freq) {
+	if (!CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE) && !crystal_freq) {
 		switch (gd->arch.x86_model) {
 		case INTEL_FAM6_SKYLAKE_MOBILE:
 		case INTEL_FAM6_SKYLAKE_DESKTOP:
@@ -397,7 +396,8 @@
 {
 	if (gd->arch.tsc_inited)
 		return;
-	gd->arch.tsc_base = rdtsc();
+	if (IS_ENABLED(CONFIG_X86_TSC_READ_BASE))
+		gd->arch.tsc_base = rdtsc();
 
 	if (!gd->arch.clock_rate) {
 		unsigned long fast_calibrate;
@@ -406,6 +406,10 @@
 		if (fast_calibrate)
 			goto done;
 
+		/* Reduce code size by dropping other methods */
+		if (CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE))
+			panic("no timer");
+
 		fast_calibrate = cpu_mhz_from_cpuid();
 		if (fast_calibrate)
 			goto done;
diff --git a/drivers/tpm/tpm2_tis_spi.c b/drivers/tpm/tpm2_tis_spi.c
index 3d105fd..713111f 100644
--- a/drivers/tpm/tpm2_tis_spi.c
+++ b/drivers/tpm/tpm2_tis_spi.c
@@ -587,7 +587,7 @@
 	/* Use the TPM v2 stack */
 	priv->version = TPM_V2;
 
-	if (IS_ENABLED(CONFIG_DM_GPIO)) {
+	if (CONFIG_IS_ENABLED(DM_GPIO)) {
 		struct gpio_desc reset_gpio;
 
 		ret = gpio_request_by_name(dev, "gpio-reset", 0,
diff --git a/include/binman.h b/include/binman.h
new file mode 100644
index 0000000..b462dc8
--- /dev/null
+++ b/include/binman.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: Intel */
+/*
+ * Access to binman information at runtime
+ *
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#ifndef _BINMAN_H_
+#define _BINMAN_H_
+
+/**
+ *struct binman_entry - information about a binman entry
+ *
+ * @image_pos: Position of entry in the image
+ * @size: Size of entry
+ */
+struct binman_entry {
+	u32 image_pos;
+	u32 size;
+};
+
+/**
+ * binman_entry_find() - Find a binman symbol
+ *
+ * This searches the binman information in the device tree for a symbol of the
+ * given name
+ *
+ * @name: Path to entry to examine (e.g. "/read-only/u-boot")
+ * @entry: Returns information about the entry
+ * @return 0 if OK, -ENOENT if the path is not found, other -ve value if the
+ *	binman information is invalid (missing image-pos or size)
+ */
+int binman_entry_find(const char *name, struct binman_entry *entry);
+
+/**
+ * binman_init() - Set up the binman symbol information
+ *
+ * This locates the binary symbol information in the device tree ready for use
+ *
+ * @return 0 if OK, -ENOMEM if out of memory, -EINVAL if there is no binman node
+ */
+int binman_init(void);
+
+#endif
diff --git a/include/bootstage.h b/include/bootstage.h
index d105ae0..82f0307 100644
--- a/include/bootstage.h
+++ b/include/bootstage.h
@@ -202,6 +202,9 @@
 	BOOTSTATE_ID_ACCUM_DM_SPL,
 	BOOTSTATE_ID_ACCUM_DM_F,
 	BOOTSTATE_ID_ACCUM_DM_R,
+	BOOTSTATE_ID_ACCUM_FSP_M,
+	BOOTSTATE_ID_ACCUM_FSP_S,
+	BOOTSTAGE_ID_ACCUM_MMAP_SPI,
 
 	/* a few spare for the user, from here */
 	BOOTSTAGE_ID_USER,
diff --git a/include/config_uncmd_spl.h b/include/config_uncmd_spl.h
index c2f9735..31da621 100644
--- a/include/config_uncmd_spl.h
+++ b/include/config_uncmd_spl.h
@@ -12,7 +12,6 @@
 
 #ifndef CONFIG_SPL_DM
 #undef CONFIG_DM_SERIAL
-#undef CONFIG_DM_GPIO
 #undef CONFIG_DM_I2C
 #undef CONFIG_DM_SPI
 #endif
diff --git a/include/configs/at91-sama5_common.h b/include/configs/at91-sama5_common.h
index d19fd31..6e9793a 100644
--- a/include/configs/at91-sama5_common.h
+++ b/include/configs/at91-sama5_common.h
@@ -9,6 +9,8 @@
 #ifndef __AT91_SAMA5_COMMON_H
 #define __AT91_SAMA5_COMMON_H
 
+#include <linux/kconfig.h>
+
 /* ARM asynchronous clock */
 #define CONFIG_SYS_AT91_SLOW_CLOCK      32768
 #define CONFIG_SYS_AT91_MAIN_CLOCK      12000000 /* from 12 MHz crystal */
@@ -18,11 +20,10 @@
 #endif
 
 /* general purpose I/O */
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
 #define CONFIG_AT91_GPIO
 #endif
 
-
 /*
  * BOOTP options
  */
diff --git a/include/configs/chromebook_coral.h b/include/configs/chromebook_coral.h
new file mode 100644
index 0000000..a63c3c9
--- /dev/null
+++ b/include/configs/chromebook_coral.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 Google LLC
+ */
+
+/*
+ * board/config.h - configuration options, board-specific
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_BOOTCOMMAND	\
+	"fatload mmc 1:c 1000000 syslinux/vmlinuz.A; zboot 1000000"
+
+#include <configs/x86-common.h>
+#include <configs/x86-chromebook.h>
+
+#undef CONFIG_STD_DEVICES_SETTINGS
+#define CONFIG_STD_DEVICES_SETTINGS     "stdin=usbkbd,i8042-kbd,serial\0" \
+					"stdout=vidconsole,serial\0" \
+					"stderr=vidconsole,serial\0"
+
+#define CONFIG_ENV_SECT_SIZE		0x1000
+#define CONFIG_ENV_OFFSET		0x003f8000
+
+#define CONFIG_TPL_TEXT_BASE		0xffff8000
+
+#define CONFIG_SYS_NS16550_MEM32
+#undef CONFIG_SYS_NS16550_PORT_MAPPED
+
+#endif	/* __CONFIG_H */
diff --git a/include/configs/gw_ventana.h b/include/configs/gw_ventana.h
index 894f8b1..d169aa1 100644
--- a/include/configs/gw_ventana.h
+++ b/include/configs/gw_ventana.h
@@ -36,7 +36,6 @@
 
 /* Driver Model */
 #ifndef CONFIG_SPL_BUILD
-#define CONFIG_DM_GPIO
 #define CONFIG_DM_THERMAL
 #endif
 
diff --git a/include/configs/mx6ul_14x14_evk.h b/include/configs/mx6ul_14x14_evk.h
index c21d633..5cc15b6 100644
--- a/include/configs/mx6ul_14x14_evk.h
+++ b/include/configs/mx6ul_14x14_evk.h
@@ -44,6 +44,7 @@
 #define CONFIG_SYS_I2C_SPEED		100000
 #endif
 
+/* Note: This is incorrect and should move to Kconfig / defconfig */
 #ifdef CONFIG_DM_GPIO
 #define CONFIG_DM_74X164
 #endif
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index 5c4cbf0..4282169 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -118,7 +118,7 @@
 	if (of_live_active())
 		node.np = NULL;
 	else
-		node.of_offset = of_offset;
+		node.of_offset = of_offset >= 0 ? of_offset : -1;
 
 	return node;
 }
diff --git a/include/dm/pci.h b/include/dm/pci.h
new file mode 100644
index 0000000..10f9fd9
--- /dev/null
+++ b/include/dm/pci.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2019 Google, Inc
+ */
+
+#ifndef __DM_PCI_H
+#define __DM_PCI_H
+
+struct udevice;
+
+/**
+ * pci_get_devfn() - Extract the devfn from fdt_pci_addr of the device
+ *
+ * Get devfn from fdt_pci_addr of the specified device
+ *
+ * This returns an int to avoid a dependency on pci.h
+ *
+ * @dev:	PCI device
+ * @return devfn in bits 15...8 if found (pci_dev_t format), or -ENODEV if not
+ *	found
+ */
+int pci_get_devfn(struct udevice *dev);
+
+/**
+ * pci_ofplat_get_devfn() - Get the PCI dev/fn from of-platdata
+ *
+ * This function is used to obtain a PCI device/function from of-platdata
+ * register data. In this case the first cell of the 'reg' property contains
+ * the required information.
+ *
+ * This returns an int to avoid a dependency on pci.h
+ *
+ * @reg: reg value from dt-platdata.c array (first member). This is not a
+ *	pointer type, since the caller may use fdt32_t or fdt64_t depending on
+ *	the address sizes.
+ * @return device/function for that device (pci_dev_t format)
+ */
+static inline int pci_ofplat_get_devfn(u32 reg)
+{
+	return reg & 0xff00;
+}
+
+#endif
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 0c563d8..c1bab17 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -28,6 +28,7 @@
 	UCLASS_AXI_EMUL,	/* sandbox AXI bus device emulator */
 
 	/* U-Boot uclasses start here - in alphabetical order */
+	UCLASS_ACPI_PMC,	/* (x86) Power-management controller (PMC) */
 	UCLASS_ADC,		/* Analog-to-digital converter */
 	UCLASS_AHCI,		/* SATA disk controller */
 	UCLASS_AUDIO_CODEC,	/* Audio codec with control and data path */
@@ -69,6 +70,7 @@
 	UCLASS_NOP,		/* No-op devices */
 	UCLASS_NORTHBRIDGE,	/* Intel Northbridge / SDRAM controller */
 	UCLASS_NVME,		/* NVM Express device */
+	UCLASS_P2SB,		/* (x86) Primary-to-Sideband Bus */
 	UCLASS_PANEL,		/* Display panel, such as an LCD */
 	UCLASS_PANEL_BACKLIGHT,	/* Backlight controller for panel */
 	UCLASS_PCH,		/* x86 platform controller hub */
diff --git a/include/init.h b/include/init.h
index 8b65b2a..970a39a 100644
--- a/include/init.h
+++ b/include/init.h
@@ -67,6 +67,17 @@
  */
 int arch_fsp_init(void);
 
+/**
+ * arch_fsp_init() - perform post-relocation firmware support package init
+ *
+ * Where U-Boot relies on binary blobs to handle part of the system init, this
+ * function can be used to set up the blobs. This is used on some Intel
+ * platforms.
+ *
+ * Return: 0
+ */
+int arch_fsp_init_r(void);
+
 int dram_init(void);
 
 /**
diff --git a/include/irq.h b/include/irq.h
new file mode 100644
index 0000000..01ded64
--- /dev/null
+++ b/include/irq.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * IRQ is a type of interrupt controller used on recent Intel SoC.
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef __irq_H
+#define __irq_H
+
+/**
+ * struct irq_ops - Operations for the IRQ
+ */
+struct irq_ops {
+	/**
+	 * route_pmc_gpio_gpe() - Get the GPIO for an event
+	 *
+	 * @dev: IRQ device
+	 * @pmc_gpe_num: Event number to check
+	 * @returns GPIO for the event, or -ENOENT if none
+	 */
+	int (*route_pmc_gpio_gpe)(struct udevice *dev, uint pmc_gpe_num);
+
+	/**
+	 * set_polarity() - Set the IRQ polarity
+	 *
+	 * @dev: IRQ device
+	 * @irq: Interrupt number to set
+	 * @active_low: true if active low, false for active high
+	 * @return 0 if OK, -EINVAL if @irq is invalid
+	 */
+	int (*set_polarity)(struct udevice *dev, uint irq, bool active_low);
+
+	/**
+	 * snapshot_polarities() - record IRQ polarities for later restore
+	 *
+	 * @dev: IRQ device
+	 * @return 0
+	 */
+	int (*snapshot_polarities)(struct udevice *dev);
+
+	/**
+	 * restore_polarities() - restore IRQ polarities
+	 *
+	 * @dev: IRQ device
+	 * @return 0
+	 */
+	int (*restore_polarities)(struct udevice *dev);
+};
+
+#define irq_get_ops(dev)	((struct irq_ops *)(dev)->driver->ops)
+
+/**
+ * irq_route_pmc_gpio_gpe() - Get the GPIO for an event
+ *
+ * @dev: IRQ device
+ * @pmc_gpe_num: Event number to check
+ * @returns GPIO for the event, or -ENOENT if none
+ */
+int irq_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num);
+
+/**
+ * irq_set_polarity() - Set the IRQ polarity
+ *
+ * @dev: IRQ device
+ * @irq: Interrupt number to set
+ * @active_low: true if active low, false for active high
+ * @return 0 if OK, -EINVAL if @irq is invalid
+ */
+int irq_set_polarity(struct udevice *dev, uint irq, bool active_low);
+
+/**
+ * irq_snapshot_polarities() - record IRQ polarities for later restore
+ *
+ * @dev: IRQ device
+ * @return 0
+ */
+int irq_snapshot_polarities(struct udevice *dev);
+
+/**
+ * irq_restore_polarities() - restore IRQ polarities
+ *
+ * @dev: IRQ device
+ * @return 0
+ */
+int irq_restore_polarities(struct udevice *dev);
+
+#endif
diff --git a/include/p2sb.h b/include/p2sb.h
new file mode 100644
index 0000000..60c7f70
--- /dev/null
+++ b/include/p2sb.h
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#ifndef __p2sb_h
+#define __p2sb_h
+
+/* Port Id lives in bits 23:16 and register offset lives in 15:0 of address */
+#define PCR_PORTID_SHIFT	16
+
+/**
+ * struct p2sb_child_platdata - Information about each child of a p2sb device
+ *
+ * @pid: Port ID for this child
+ */
+struct p2sb_child_platdata {
+	uint pid;
+};
+
+/**
+ * struct p2sb_uc_priv - information for the uclass about each device
+ *
+ * This must be set up by the driver when it is probed
+ *
+ * @mmio_base: Base address of P2SB region
+ */
+struct p2sb_uc_priv {
+	uint mmio_base;
+};
+
+/**
+ * struct p2sb_ops - Operations for the P2SB (none at present)
+ */
+struct p2sb_ops {
+};
+
+#define p2sb_get_ops(dev)        ((struct p2sb_ops *)(dev)->driver->ops)
+
+/**
+ * pcr_read32/16/8() - Read from a PCR device
+ *
+ * Reads data from a PCR device within the P2SB
+ *
+ * @dev: Device to read from
+ * @offset: Offset within device to read
+ * @return value read
+ */
+uint pcr_read32(struct udevice *dev, uint offset);
+uint pcr_read16(struct udevice *dev, uint offset);
+uint pcr_read8(struct udevice *dev, uint offset);
+
+/**
+ * pcr_read32/16/8() - Write to a PCR device
+ *
+ * Writes data to a PCR device within the P2SB
+ *
+ * @dev: Device to write to
+ * @offset: Offset within device to write
+ * @data: Data to write
+ */
+void pcr_write32(struct udevice *dev, uint offset, uint data);
+void pcr_write16(struct udevice *dev, uint offset, uint data);
+void pcr_write8(struct udevice *dev, uint offset, uint data);
+
+/**
+ * pcr_clrsetbits32/16/8() - Update a PCR device
+ *
+ * Updates dat in a PCR device within the P2SB
+ *
+ * This reads from the device, clears and set bits, then writes back.
+ *
+ * new_data = (old_data & ~clr) | set
+ *
+ * @dev: Device to update
+ * @offset: Offset within device to update
+ * @clr: Bits to clear after reading
+ * @set: Bits to set before writing
+ */
+void pcr_clrsetbits32(struct udevice *dev, uint offset, uint clr, uint set);
+void pcr_clrsetbits16(struct udevice *dev, uint offset, uint clr, uint set);
+void pcr_clrsetbits8(struct udevice *dev, uint offset, uint clr, uint set);
+
+static inline void pcr_setbits32(struct udevice *dev, uint offset, uint set)
+{
+	return pcr_clrsetbits32(dev, offset, 0, set);
+}
+
+static inline void pcr_setbits16(struct udevice *dev, uint offset, uint set)
+{
+	return pcr_clrsetbits16(dev, offset, 0, set);
+}
+
+static inline void pcr_setbits8(struct udevice *dev, uint offset, uint set)
+{
+	return pcr_clrsetbits8(dev, offset, 0, set);
+}
+
+static inline void pcr_clrbits32(struct udevice *dev, uint offset, uint clr)
+{
+	return pcr_clrsetbits32(dev, offset, clr, 0);
+}
+
+static inline void pcr_clrbits16(struct udevice *dev, uint offset, uint clr)
+{
+	return pcr_clrsetbits16(dev, offset, clr, 0);
+}
+
+static inline void pcr_clrbits8(struct udevice *dev, uint offset, uint clr)
+{
+	return pcr_clrsetbits8(dev, offset, clr, 0);
+}
+
+/**
+ * p2sb_set_port_id() - Set the port ID for a p2sb child device
+ *
+ * This must be called in a device's bind() method when OF_PLATDATA is used
+ * since the uclass cannot access the device's of-platdata.
+ *
+ * @dev: Child device (whose parent is UCLASS_P2SB)
+ * @portid: Port ID of child device
+ * @return 0 if OK, -ENODEV is the p2sb device could not be found
+ */
+int p2sb_set_port_id(struct udevice *dev, int portid);
+
+/**
+ * p2sb_get_port_id() - Get the port ID for a p2sb child device
+ *
+ * @dev: Child device (whose parent is UCLASS_P2SB)
+ * @return Port ID of that child
+ */
+int p2sb_get_port_id(struct udevice *dev);
+
+#endif
diff --git a/include/pci.h b/include/pci.h
index ff59ac0..8c761d8 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -482,6 +482,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <dm/pci.h>
+
 #ifdef CONFIG_SYS_PCI_64BIT
 typedef u64 pci_addr_t;
 typedef u64 pci_size_t;
@@ -571,15 +573,22 @@
 
 #define INDIRECT_TYPE_NO_PCIE_LINK	1
 
-/*
+/**
  * Structure of a PCI controller (host bridge)
  *
  * With driver model this is dev_get_uclass_priv(bus)
+ *
+ * @skip_auto_config_until_reloc: true to avoid auto-config until U-Boot has
+ *	relocated. Normally if PCI is used before relocation, this happens
+ *	before relocation also. Some platforms set up static configuration in
+ *	TPL/SPL to reduce code size and boot time, since these phases only know
+ *	about a small subset of PCI devices. This is normally false.
  */
 struct pci_controller {
 #ifdef CONFIG_DM_PCI
 	struct udevice *bus;
 	struct udevice *ctlr;
+	bool skip_auto_config_until_reloc;
 #else
 	struct pci_controller *next;
 #endif
@@ -1612,16 +1621,6 @@
  */
 int sandbox_pci_get_client(struct udevice *emul, struct udevice **devp);
 
-/**
- * pci_get_devfn() - Extract the devfn from fdt_pci_addr of the device
- *
- * Get devfn from fdt_pci_addr of the specified device
- *
- * @dev:	PCI device
- * @return devfn in bits 15...8 if found, -ENODEV if not found
- */
-int pci_get_devfn(struct udevice *dev);
-
 #endif /* CONFIG_DM_PCI */
 
 /**
diff --git a/include/power/acpi_pmc.h b/include/power/acpi_pmc.h
new file mode 100644
index 0000000..1f50c23
--- /dev/null
+++ b/include/power/acpi_pmc.h
@@ -0,0 +1,185 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef __ACPI_PMC_H
+#define __ACPI_PMC_H
+
+enum {
+	GPE0_REG_MAX	= 4,
+};
+
+/**
+ * struct acpi_pmc_upriv - holds common data for the x86 PMC
+ *
+ * @pmc_bar0: Base address 0 of PMC
+ * @pmc_bar1: Base address 2 of PMC
+ * @acpi_base: Base address of ACPI block
+ * @pm1_sts: PM1 status
+ * @pm1_en: PM1 enable
+ * @pm1_cnt: PM1 control
+ * @gpe_cfg: Address of GPE_CFG register
+ * @gpe0_dwx_mask: Mask to use for each GPE0 (typically 7 or 0xf)
+ * @gpe0_dwx_shift_base: Base shift value to use for GPE0 (0 or 4)
+ * @gpe0_sts_req: GPE0 status register offset
+ * @gpe0_en_req: GPE0 enable register offset
+ * @gpe0_sts: GPE0 status values
+ * @gpe0_en: GPE0 enable values
+ * @gpe0_dw: GPE0 DW values
+ * @gpe0_count: Number of GPE0 registers
+ * @tco1_sts: TCO1 status
+ * @tco2_sts: TCO2 status
+ * @prsts: Power and reset status
+ * @gen_pmcon1: General power mgmt configuration 1
+ * @gen_pmcon2: General power mgmt configuration 2
+ * @gen_pmcon3: General power mgmt configuration 3
+ */
+struct acpi_pmc_upriv {
+	void *pmc_bar0;
+	void *pmc_bar2;
+	u32 acpi_base;
+	u16 pm1_sts;
+	u16 pm1_en;
+	u32 pm1_cnt;
+	u32 *gpe_cfg;
+	u32 gpe0_dwx_mask;
+	u32 gpe0_dwx_shift_base;
+	u32 gpe0_sts_reg;
+	u32 gpe0_en_reg;
+	u32 gpe0_sts[GPE0_REG_MAX];
+	u32 gpe0_en[GPE0_REG_MAX];
+	u32 gpe0_dw[GPE0_REG_MAX];
+	int gpe0_count;
+	u16 tco1_sts;
+	u16 tco2_sts;
+	u32 prsts;
+	u32 gen_pmcon1;
+	u32 gen_pmcon2;
+	u32 gen_pmcon3;
+};
+
+struct acpi_pmc_ops {
+	/**
+	 * init() - Set up the PMC for use
+	 *
+	 * This reads the current state of the PMC. Most of the state is read
+	 * automatically by the uclass since it is common.
+	 *
+	 * This is optional.
+	 *
+	 * @dev: PMC device to use
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*init)(struct udevice *dev);
+
+	/**
+	 * prev_sleep_state() - Get the previous sleep state (optional)
+	 *
+	 * This reads various state registers and returns the sleep state from
+	 * which the system woke. If this method is not provided, the uclass
+	 * will return a calculated value.
+	 *
+	 * This is optional.
+	 *
+	 * @dev: PMC device to use
+	 * @prev_sleep_state: Previous sleep state as calculated by the uclass.
+	 *	The method can use this as the return value or calculate its
+	 *	own.
+	 *
+	 * @return enum acpi_sleep_state indicating the previous sleep state
+	 *	(ACPI_S0, ACPI_S3 or ACPI_S5), or -ve on error
+	 */
+	int (*prev_sleep_state)(struct udevice *dev, int prev_sleep_state);
+
+	/**
+	 * disable_tco() - Disable the timer/counter
+	 *
+	 * Disables the timer/counter in the PMC
+	 *
+	 * This is optional.
+	 *
+	 * @dev: PMC device to use
+	 * @return 0
+	 */
+	int (*disable_tco)(struct udevice *dev);
+
+	/**
+	 * global_reset_set_enable() - Enable/Disable global reset
+	 *
+	 * Enable or disable global reset. If global reset is enabled, both hard
+	 * reset and soft reset will trigger global reset, where both host and
+	 * TXE are reset. This is cleared on cold boot, hard reset, soft reset
+	 * and Sx.
+	 *
+	 * This is optional.
+	 *
+	 * @dev: PMC device to use
+	 * @enable: true to enable global reset, false to disable
+	 * @return 0
+	 */
+	int (*global_reset_set_enable)(struct udevice *dev, bool enable);
+};
+
+#define acpi_pmc_get_ops(dev)	((struct acpi_pmc_ops *)(dev)->driver->ops)
+
+/**
+ * init() - Set up the PMC for use
+ *
+ * This reads the current state of the PMC. This reads in the common registers,
+ * then calls the device's init() method to read the SoC-specific registers.
+ *
+ * @return 0 if OK, -ve on error
+ */
+int pmc_init(struct udevice *dev);
+
+/**
+ * pmc_prev_sleep_state() - Get the previous sleep state
+ *
+ * This reads various state registers and returns the sleep state from
+ * which the system woke.
+ *
+ * @return enum acpi_sleep_state indicating the previous sleep state
+ *	(ACPI_S0, ACPI_S3 or ACPI_S5), or -ve on error
+ */
+int pmc_prev_sleep_state(struct udevice *dev);
+
+/**
+ * pmc_disable_tco() - Disable the timer/counter
+ *
+ * Disables the timer/counter in the PMC
+ *
+ * @dev: PMC device to use
+ * @return 0
+ */
+int pmc_disable_tco(struct udevice *dev);
+
+/**
+ * pmc_global_reset_set_enable() - Enable/Disable global reset
+ *
+ * Enable or disable global reset. If global reset is enabled, both hard
+ * reset and soft reset will trigger global reset, where both host and
+ * TXE are reset. This is cleared on cold boot, hard reset, soft reset
+ * and Sx.
+ *
+ * @dev: PMC device to use
+ * @enable: true to enable global reset, false to disable
+ * @return 0
+ */
+int pmc_global_reset_set_enable(struct udevice *dev, bool enable);
+
+int pmc_ofdata_to_uc_platdata(struct udevice *dev);
+
+int pmc_disable_tco_base(ulong tco_base);
+
+void pmc_dump_info(struct udevice *dev);
+
+/**
+ * pmc_gpe_init() - Set up general-purpose events
+ *
+ * @dev: PMC device
+ * @return 0 if OK, -ve on error
+ */
+int pmc_gpe_init(struct udevice *dev);
+
+#endif
diff --git a/include/qfw.h b/include/qfw.h
index 2f1a204..cea8e11 100644
--- a/include/qfw.h
+++ b/include/qfw.h
@@ -172,4 +172,12 @@
 bool qemu_fwcfg_present(void);
 bool qemu_fwcfg_dma_present(void);
 
+/**
+ * qemu_cpu_fixup() - Fix up the CPUs for QEMU
+ *
+ * @return 0 if OK, -ENODEV if no CPUs, -ENOMEM if out of memory, other -ve on
+ *	on other error
+ */
+int qemu_cpu_fixup(void);
+
 #endif
diff --git a/include/spi.h b/include/spi.h
index 6fbb433..ba2c840 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -224,7 +224,7 @@
 int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen);
 
 /**
- * SPI transfer
+ * SPI transfer (optional if mem_ops is used)
  *
  * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks
  * "bitlen" bits in the SPI MISO port.  That's just the way SPI works.
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 55b4721..0b23f57 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -102,6 +102,18 @@
  */
 int spl_flash_get_sw_write_prot(struct udevice *dev);
 
+/**
+ * spi_flash_std_probe() - Probe a SPI flash device
+ *
+ * This is the standard internal method for probing a SPI flash device to
+ * determine its type. It can be used in chip-specific drivers which need to
+ * do this, typically with of-platdata
+ *
+ * @dev: SPI-flash device to probe
+ * @return 0 if OK, -ve on error
+ */
+int spi_flash_std_probe(struct udevice *dev);
+
 int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs,
 			   unsigned int max_hz, unsigned int spi_mode,
 			   struct udevice **devp);
diff --git a/include/spl.h b/include/spl.h
index 08ffdda..02aa1ff 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -169,10 +169,29 @@
  * We need to know the position of U-Boot in memory so we can jump to it. We
  * allow any U-Boot binary to be used (u-boot.bin, u-boot-nodtb.bin,
  * u-boot.img), hence the '_any'. These is no checking here that the correct
- * image is found. For * example if u-boot.img is used we don't check that
+ * image is found. For example if u-boot.img is used we don't check that
  * spl_parse_image_header() can parse a valid header.
+ *
+ * Similarly for SPL, so that TPL can jump to SPL.
  */
 binman_sym_extern(ulong, u_boot_any, image_pos);
+binman_sym_extern(ulong, u_boot_any, size);
+binman_sym_extern(ulong, spl, image_pos);
+binman_sym_extern(ulong, spl, size);
+
+/**
+ * spl_get_image_pos() - get the image position of the next phase
+ *
+ * This returns the image position to use to load the next phase of U-Boot
+ */
+ulong spl_get_image_pos(void);
+
+/**
+ * spl_get_image_size() - get the size of the next phase
+ *
+ * This returns the size to use to load the next phase of U-Boot
+ */
+ulong spl_get_image_size(void);
 
 /**
  * spl_load_simple_fit_skip_processing() - Hook to allow skipping the FIT
diff --git a/lib/Kconfig b/lib/Kconfig
index 965cf7b..d040a87 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -7,6 +7,16 @@
 	  This is used by SoC platforms which do not have built-in ELM
 	  hardware engine required for BCH ECC correction.
 
+config BINMAN_FDT
+	bool "Allow access to binman information in the device tree"
+	depends on BINMAN && OF_CONTROL
+	default y
+	help
+	  This enables U-Boot to access information about binman entries,
+	  stored in the device tree in a binman node. Typical uses are to
+	  locate entries in the firmware image. See binman.h for the available
+	  functionality.
+
 config CC_OPTIMIZE_LIBS_FOR_SPEED
 	bool "Optimize libraries for speed"
 	help
diff --git a/lib/Makefile b/lib/Makefile
index 1fb650c..6b7b9ce 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -21,6 +21,7 @@
 obj-y += crypto/
 
 obj-$(CONFIG_AES) += aes.o
+obj-$(CONFIG_$(SPL_TPL_)BINMAN_FDT) += binman.o
 
 ifndef API_BUILD
 ifneq ($(CONFIG_UT_UNICODE)$(CONFIG_EFI_LOADER),)
@@ -77,7 +78,7 @@
 ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_SPL_YMODEM_SUPPORT) += crc16.o
 obj-$(CONFIG_$(SPL_TPL_)HASH_SUPPORT) += crc16.o
-obj-$(CONFIG_SPL_NET_SUPPORT) += net_utils.o
+obj-y += net_utils.o
 endif
 obj-$(CONFIG_ADDR_MAP) += addr_map.o
 obj-y += qsort.o
diff --git a/lib/binman.c b/lib/binman.c
new file mode 100644
index 0000000..1774bdf
--- /dev/null
+++ b/lib/binman.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: Intel
+/*
+ * Access to binman information at runtime
+ *
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <binman.h>
+#include <dm.h>
+
+struct binman_info {
+	ofnode image;
+};
+
+static struct binman_info *binman;
+
+int binman_entry_find(const char *name, struct binman_entry *entry)
+{
+	ofnode node;
+	int ret;
+
+	node = ofnode_find_subnode(binman->image, name);
+	if (!ofnode_valid(node))
+		return log_msg_ret("no binman node", -ENOENT);
+
+	ret = ofnode_read_u32(node, "image-pos", &entry->image_pos);
+	if (ret)
+		return log_msg_ret("bad binman node1", ret);
+	ret = ofnode_read_u32(node, "size", &entry->size);
+	if (ret)
+		return log_msg_ret("bad binman node2", ret);
+
+	return 0;
+}
+
+int binman_init(void)
+{
+	binman = malloc(sizeof(struct binman_info));
+	if (!binman)
+		return log_msg_ret("space for binman", -ENOMEM);
+	binman->image = ofnode_path("/binman");
+	if (!ofnode_valid(binman->image))
+		return log_msg_ret("binman node", -EINVAL);
+
+	return 0;
+}
diff --git a/lib/efi/Kconfig b/lib/efi/Kconfig
index 919e314..93b8564 100644
--- a/lib/efi/Kconfig
+++ b/lib/efi/Kconfig
@@ -1,6 +1,7 @@
 config EFI
 	bool "Support running U-Boot from EFI"
 	depends on X86
+	imply X86_TSC_READ_BASE
 	help
 	  U-Boot can be started from EFI on certain platforms. This allows
 	  EFI to perform most of the system init and then jump to U-Boot for
diff --git a/lib/net_utils.c b/lib/net_utils.c
index ed5044c..8af7782 100644
--- a/lib/net_utils.c
+++ b/lib/net_utils.c
@@ -56,3 +56,51 @@
 			addr = (*end) ? end + 1 : end;
 	}
 }
+
+uint compute_ip_checksum(const void *vptr, uint nbytes)
+{
+	int sum, oddbyte;
+	const unsigned short *ptr = vptr;
+
+	sum = 0;
+	while (nbytes > 1) {
+		sum += *ptr++;
+		nbytes -= 2;
+	}
+	if (nbytes == 1) {
+		oddbyte = 0;
+		((u8 *)&oddbyte)[0] = *(u8 *)ptr;
+		((u8 *)&oddbyte)[1] = 0;
+		sum += oddbyte;
+	}
+	sum = (sum >> 16) + (sum & 0xffff);
+	sum += (sum >> 16);
+	sum = ~sum & 0xffff;
+
+	return sum;
+}
+
+uint add_ip_checksums(uint offset, uint sum, uint new)
+{
+	ulong checksum;
+
+	sum = ~sum & 0xffff;
+	new = ~new & 0xffff;
+	if (offset & 1) {
+		/*
+		 * byte-swap the sum if it came from an odd offset; since the
+		 * computation is endian-independent this works.
+		 */
+		new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
+	}
+	checksum = sum + new;
+	if (checksum > 0xffff)
+		checksum -= 0xffff;
+
+	return (~checksum) & 0xffff;
+}
+
+int ip_checksum_ok(const void *addr, uint nbytes)
+{
+	return !(compute_ip_checksum(addr, nbytes) & 0xfffe);
+}
diff --git a/net/Makefile b/net/Makefile
index 2a700c8..fef71b9 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -5,7 +5,6 @@
 
 #ccflags-y += -DDEBUG
 
-obj-y += checksum.o
 obj-$(CONFIG_NET)      += arp.o
 obj-$(CONFIG_CMD_BOOTP) += bootp.o
 obj-$(CONFIG_CMD_CDP)  += cdp.o
diff --git a/net/checksum.c b/net/checksum.c
deleted file mode 100644
index 16ef416..0000000
--- a/net/checksum.c
+++ /dev/null
@@ -1,59 +0,0 @@
-// SPDX-License-Identifier: BSD-2-Clause
-/*
- * This file was originally taken from the FreeBSD project.
- *
- * Copyright (c) 2001 Charles Mott <cm@linktel.net>
- * Copyright (c) 2008 coresystems GmbH
- * All rights reserved.
- */
-
-#include <common.h>
-#include <net.h>
-
-unsigned compute_ip_checksum(const void *vptr, unsigned nbytes)
-{
-	int sum, oddbyte;
-	const unsigned short *ptr = vptr;
-
-	sum = 0;
-	while (nbytes > 1) {
-		sum += *ptr++;
-		nbytes -= 2;
-	}
-	if (nbytes == 1) {
-		oddbyte = 0;
-		((u8 *)&oddbyte)[0] = *(u8 *)ptr;
-		((u8 *)&oddbyte)[1] = 0;
-		sum += oddbyte;
-	}
-	sum = (sum >> 16) + (sum & 0xffff);
-	sum += (sum >> 16);
-	sum = ~sum & 0xffff;
-
-	return sum;
-}
-
-unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new)
-{
-	unsigned long checksum;
-
-	sum = ~sum & 0xffff;
-	new = ~new & 0xffff;
-	if (offset & 1) {
-		/*
-		 * byte-swap the sum if it came from an odd offset; since the
-		 * computation is endian independant this works.
-		 */
-		new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
-	}
-	checksum = sum + new;
-	if (checksum > 0xffff)
-		checksum -= 0xffff;
-
-	return (~checksum) & 0xffff;
-}
-
-int ip_checksum_ok(const void *addr, unsigned nbytes)
-{
-	return !(compute_ip_checksum(addr, nbytes) & 0xfffe);
-}
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index ef116e0..c10cd83 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -300,7 +300,9 @@
 	$(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $(pre-tmp) ; \
 	$(DTC) -O dtb -o $@ -b 0 \
 		-i $(dir $<) $(DTC_FLAGS) \
-		-d $(depfile).dtc.tmp $(dtc-tmp) ; \
+		-d $(depfile).dtc.tmp $(dtc-tmp) || \
+		(echo "Check $(shell pwd)/$(pre-tmp) for errors" && false) \
+		; \
 	cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile) ; \
 	sed -i "s:$(pre-tmp):$(<):" $(depfile)
 
diff --git a/scripts/Makefile.uncmd_spl b/scripts/Makefile.uncmd_spl
index ba267d9..6ea097d 100644
--- a/scripts/Makefile.uncmd_spl
+++ b/scripts/Makefile.uncmd_spl
@@ -6,7 +6,6 @@
 
 ifndef CONFIG_SPL_DM
 CONFIG_DM_SERIAL=
-CONFIG_DM_GPIO=
 CONFIG_DM_I2C=
 CONFIG_DM_SPI=
 CONFIG_DM_SPI_FLASH=
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 0c2fd5c..a268783 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -25,6 +25,7 @@
 obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock.o
 obj-$(CONFIG_DM_I2C) += i2c.o
 obj-$(CONFIG_SOUND) += i2s.o
+obj-y += irq.o
 obj-$(CONFIG_LED) += led.o
 obj-$(CONFIG_DM_MAILBOX) += mailbox.o
 obj-$(CONFIG_DM_MMC) += mmc.o
@@ -32,10 +33,12 @@
 obj-$(CONFIG_OSD) += osd.o
 obj-$(CONFIG_DM_VIDEO) += panel.o
 obj-$(CONFIG_DM_PCI) += pci.o
+obj-$(CONFIG_P2SB) += p2sb.o
 obj-$(CONFIG_PCI_ENDPOINT) += pci_ep.o
 obj-$(CONFIG_PCH) += pch.o
 obj-$(CONFIG_PHY) += phy.o
 obj-$(CONFIG_POWER_DOMAIN) += power-domain.o
+obj-$(CONFIG_ACPI_PMC) += pmc.o
 obj-$(CONFIG_DM_PWM) += pwm.o
 obj-$(CONFIG_RAM) += ram.o
 obj-y += regmap.o
diff --git a/test/dm/irq.c b/test/dm/irq.c
new file mode 100644
index 0000000..726189c
--- /dev/null
+++ b/test/dm/irq.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test for irq uclass
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <irq.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+/* Base test of the irq uclass */
+static int dm_test_irq_base(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+
+	ut_assertok(uclass_first_device_err(UCLASS_IRQ, &dev));
+
+	ut_asserteq(5, irq_route_pmc_gpio_gpe(dev, 4));
+	ut_asserteq(-ENOENT, irq_route_pmc_gpio_gpe(dev, 14));
+
+	ut_assertok(irq_set_polarity(dev, 4, true));
+	ut_asserteq(-EINVAL, irq_set_polarity(dev, 14, true));
+
+	ut_assertok(irq_snapshot_polarities(dev));
+	ut_assertok(irq_restore_polarities(dev));
+
+	return 0;
+}
+DM_TEST(dm_test_irq_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/p2sb.c b/test/dm/p2sb.c
new file mode 100644
index 0000000..ccb75cf
--- /dev/null
+++ b/test/dm/p2sb.c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test for Primary-to-Sideband bus (P2SB)
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <p2sb.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+/* Base test of the PMC uclass */
+static int dm_test_p2sb_base(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+
+	sandbox_set_enable_memio(true);
+	ut_assertok(uclass_get_device_by_name(UCLASS_AXI, "adder", &dev));
+	ut_asserteq(0x03000004, pcr_read32(dev, 4));
+	ut_asserteq(0x300, pcr_read16(dev, 6));
+	ut_asserteq(4, pcr_read8(dev, 4));
+
+	return 0;
+}
+DM_TEST(dm_test_p2sb_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/pmc.c b/test/dm/pmc.c
new file mode 100644
index 0000000..1a22283
--- /dev/null
+++ b/test/dm/pmc.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test for power-management controller uclass (PMC)
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <power/acpi_pmc.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+/* Base test of the PMC uclass */
+static int dm_test_pmc_base(struct unit_test_state *uts)
+{
+	struct acpi_pmc_upriv *upriv;
+	struct udevice *dev;
+
+	ut_assertok(uclass_first_device_err(UCLASS_ACPI_PMC, &dev));
+
+	ut_assertok(pmc_disable_tco(dev));
+	ut_assertok(pmc_init(dev));
+	ut_assertok(pmc_prev_sleep_state(dev));
+
+	/* Check some values to see that I/O works */
+	upriv = dev_get_uclass_priv(dev);
+	ut_asserteq(0x24, upriv->gpe0_sts[1]);
+	ut_asserteq(0x64, upriv->tco1_sts);
+
+	return 0;
+}
+DM_TEST(dm_test_pmc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);