diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index f07567c81ac4374c46349cf892c5420179841369..a995e32bb98cfc3dd1f5dc2a9efb4ed3b044516f 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -358,6 +358,15 @@ config GENERATE_ACPI_TABLE
 	  by the operating system. It defines platform-independent interfaces
 	  for configuration and power management monitoring.
 
+config QEMU_ACPI_TABLE
+	bool "Load ACPI table from QEMU fw_cfg interface"
+	depends on GENERATE_ACPI_TABLE && QEMU
+	default y
+	help
+	  By default, U-Boot generates its own ACPI tables. This option, if
+	  enabled, disables U-Boot's version and loads ACPI tables generated
+	  by QEMU.
+
 config GENERATE_SMBIOS_TABLE
 	bool "Generate an SMBIOS (System Management BIOS) table"
 	default y
diff --git a/arch/x86/cpu/baytrail/early_uart.c b/arch/x86/cpu/baytrail/early_uart.c
index b64a3a90db4ab7e1d10b9a20e3a0867a38031bab..471d592b49fddb45ed215bcf177311fdcec73a13 100644
--- a/arch/x86/cpu/baytrail/early_uart.c
+++ b/arch/x86/cpu/baytrail/early_uart.c
@@ -59,11 +59,15 @@ static void x86_pci_write_config32(int dev, unsigned int where, u32 value)
 }
 
 /* This can be called after memory-mapped PCI is working */
-int setup_early_uart(void)
+int setup_internal_uart(int enable)
 {
-	/* Enable the legacy UART hardware. */
+	/* Enable or disable the legacy UART hardware */
 	x86_pci_write_config32(PCI_DEV_CONFIG(0, LPC_DEV, LPC_FUNC), UART_CONT,
-			       1);
+			       enable);
+
+	/* All done for the disable part, so just return */
+	if (!enable)
+		return 0;
 
 	/*
 	 * Set up the pads to the UART function. This allows the signals to
diff --git a/arch/x86/cpu/qemu/Kconfig b/arch/x86/cpu/qemu/Kconfig
index 4f9862194a97e094b9cabee0439828453a1b4e28..6808c9a6b9a262b5ce67b2708e396902505d8b0c 100644
--- a/arch/x86/cpu/qemu/Kconfig
+++ b/arch/x86/cpu/qemu/Kconfig
@@ -17,4 +17,11 @@ config SYS_CAR_SIZE
 	hex
 	default 0x10000
 
+config ACPI_PM1_BASE
+	hex
+	default 0xe400
+	help
+	  ACPI Power Managment 1 (PM1) i/o-mapped base address.
+	  This device is defined in ACPI specification, with 16 bytes in size.
+
 endif
diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile
index 176ea54ae4ef831b6d5b93661ab67d99e837503a..801413a1cb1478f49fb2caa4094793556a8625e0 100644
--- a/arch/x86/cpu/qemu/Makefile
+++ b/arch/x86/cpu/qemu/Makefile
@@ -8,4 +8,6 @@ ifndef CONFIG_EFI_STUB
 obj-y += car.o dram.o
 endif
 obj-y += cpu.o fw_cfg.o qemu.o
+ifndef CONFIG_QEMU_ACPI_TABLE
 obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o dsdt.o
+endif
diff --git a/arch/x86/cpu/qemu/fw_cfg.c b/arch/x86/cpu/qemu/fw_cfg.c
index 05992145cf0cbe1a2c0a60c2064c6e5f02bfe5bb..5ea7a6e2e539c53b15801969b84ed908d80f1c31 100644
--- a/arch/x86/cpu/qemu/fw_cfg.c
+++ b/arch/x86/cpu/qemu/fw_cfg.c
@@ -10,10 +10,16 @@
 #include <malloc.h>
 #include <asm/io.h>
 #include <asm/fw_cfg.h>
+#include <asm/tables.h>
+#include <asm/e820.h>
+#include <linux/list.h>
+#include <memalign.h>
 
 static bool fwcfg_present;
 static bool fwcfg_dma_present;
 
+static LIST_HEAD(fw_list);
+
 /* Read configuration item using fw_cfg PIO interface */
 static void qemu_fwcfg_read_entry_pio(uint16_t entry,
 		uint32_t size, void *address)
@@ -162,29 +168,311 @@ static int qemu_fwcfg_setup_kernel(void *load_addr, void *initrd_addr)
 	return 0;
 }
 
-static int qemu_fwcfg_list_firmware(void)
+static int qemu_fwcfg_read_firmware_list(void)
 {
 	int i;
 	uint32_t count;
-	struct fw_cfg_files *files;
+	struct fw_file *file;
+	struct list_head *entry;
+
+	/* don't read it twice */
+	if (!list_empty(&fw_list))
+		return 0;
 
 	qemu_fwcfg_read_entry(FW_CFG_FILE_DIR, 4, &count);
 	if (!count)
 		return 0;
 
 	count = be32_to_cpu(count);
-	files = malloc(count * sizeof(struct fw_cfg_file));
-	if (!files)
-		return -ENOMEM;
-
-	files->count = count;
-	qemu_fwcfg_read_entry(FW_CFG_INVALID,
-			      count * sizeof(struct fw_cfg_file),
-			      files->files);
-
-	for (i = 0; i < files->count; i++)
-		printf("%-56s\n", files->files[i].name);
-	free(files);
+	for (i = 0; i < count; i++) {
+		file = malloc(sizeof(*file));
+		if (!file) {
+			printf("error: allocating resource\n");
+			goto err;
+		}
+		qemu_fwcfg_read_entry(FW_CFG_INVALID,
+				      sizeof(struct fw_cfg_file), &file->cfg);
+		file->addr = 0;
+		list_add_tail(&file->list, &fw_list);
+	}
+
+	return 0;
+
+err:
+	list_for_each(entry, &fw_list) {
+		file = list_entry(entry, struct fw_file, list);
+		free(file);
+	}
+
+	return -ENOMEM;
+}
+
+#ifdef CONFIG_QEMU_ACPI_TABLE
+static struct fw_file *qemu_fwcfg_find_file(const char *name)
+{
+	struct list_head *entry;
+	struct fw_file *file;
+
+	list_for_each(entry, &fw_list) {
+		file = list_entry(entry, struct fw_file, list);
+		if (!strcmp(file->cfg.name, name))
+			return file;
+	}
+
+	return NULL;
+}
+
+/*
+ * This function allocates memory for ACPI tables
+ *
+ * @entry : BIOS linker command entry which tells where to allocate memory
+ *          (either high memory or low memory)
+ * @addr  : The address that should be used for low memory allcation. If the
+ *          memory allocation request is 'ZONE_HIGH' then this parameter will
+ *          be ignored.
+ * @return: 0 on success, or negative value on failure
+ */
+static int bios_linker_allocate(struct bios_linker_entry *entry,
+			   unsigned long *addr)
+{
+	uint32_t size, align;
+	struct fw_file *file;
+	unsigned long aligned_addr;
+
+	align = le32_to_cpu(entry->alloc.align);
+	/* align must be power of 2 */
+	if (align & (align - 1)) {
+		printf("error: wrong alignment %u\n", align);
+		return -EINVAL;
+	}
+
+	file = qemu_fwcfg_find_file(entry->alloc.file);
+	if (!file) {
+		printf("error: can't find file %s\n", entry->alloc.file);
+		return -ENOENT;
+	}
+
+	size = be32_to_cpu(file->cfg.size);
+
+	/*
+	 * ZONE_HIGH means we need to allocate from high memory, since
+	 * malloc space is already at the end of RAM, so we directly use it.
+	 * If allocation zone is ZONE_FSEG, then we use the 'addr' passed
+	 * in which is low memory
+	 */
+	if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH) {
+		aligned_addr = (unsigned long)memalign(align, size);
+		if (!aligned_addr) {
+			printf("error: allocating resource\n");
+			return -ENOMEM;
+		}
+	} else if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG) {
+		aligned_addr = ALIGN(*addr, align);
+	} else {
+		printf("error: invalid allocation zone\n");
+		return -EINVAL;
+	}
+
+	debug("bios_linker_allocate: allocate file %s, size %u, zone %d, align %u, addr 0x%lx\n",
+	      file->cfg.name, size, entry->alloc.zone, align, aligned_addr);
+
+	qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select),
+			      size, (void *)aligned_addr);
+	file->addr = aligned_addr;
+
+	/* adjust address for low memory allocation */
+	if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG)
+		*addr = (aligned_addr + size);
+
+	return 0;
+}
+
+/*
+ * This function patches ACPI tables previously loaded
+ * by bios_linker_allocate()
+ *
+ * @entry : BIOS linker command entry which tells how to patch
+ *          ACPI tables
+ * @return: 0 on success, or negative value on failure
+ */
+static int bios_linker_add_pointer(struct bios_linker_entry *entry)
+{
+	struct fw_file *dest, *src;
+	uint32_t offset = le32_to_cpu(entry->pointer.offset);
+	uint64_t pointer = 0;
+
+	dest = qemu_fwcfg_find_file(entry->pointer.dest_file);
+	if (!dest || !dest->addr)
+		return -ENOENT;
+	src = qemu_fwcfg_find_file(entry->pointer.src_file);
+	if (!src || !src->addr)
+		return -ENOENT;
+
+	debug("bios_linker_add_pointer: dest->addr 0x%lx, src->addr 0x%lx, offset 0x%x size %u, 0x%llx\n",
+	      dest->addr, src->addr, offset, entry->pointer.size, pointer);
+
+	memcpy(&pointer, (char *)dest->addr + offset, entry->pointer.size);
+	pointer	= le64_to_cpu(pointer);
+	pointer += (unsigned long)src->addr;
+	pointer	= cpu_to_le64(pointer);
+	memcpy((char *)dest->addr + offset, &pointer, entry->pointer.size);
+
+	return 0;
+}
+
+/*
+ * This function updates checksum fields of ACPI tables previously loaded
+ * by bios_linker_allocate()
+ *
+ * @entry : BIOS linker command entry which tells where to update ACPI table
+ *          checksums
+ * @return: 0 on success, or negative value on failure
+ */
+static int bios_linker_add_checksum(struct bios_linker_entry *entry)
+{
+	struct fw_file *file;
+	uint8_t *data, cksum = 0;
+	uint8_t *cksum_start;
+
+	file = qemu_fwcfg_find_file(entry->cksum.file);
+	if (!file || !file->addr)
+		return -ENOENT;
+
+	data = (uint8_t *)(file->addr + le32_to_cpu(entry->cksum.offset));
+	cksum_start = (uint8_t *)(file->addr + le32_to_cpu(entry->cksum.start));
+	cksum = table_compute_checksum(cksum_start,
+				       le32_to_cpu(entry->cksum.length));
+	*data = cksum;
+
+	return 0;
+}
+
+unsigned install_e820_map(unsigned max_entries, struct e820entry *entries)
+{
+	entries[0].addr = 0;
+	entries[0].size = ISA_START_ADDRESS;
+	entries[0].type = E820_RAM;
+
+	entries[1].addr = ISA_START_ADDRESS;
+	entries[1].size = ISA_END_ADDRESS - ISA_START_ADDRESS;
+	entries[1].type = E820_RESERVED;
+
+	/*
+	 * since we use memalign(malloc) to allocate high memory for
+	 * storing ACPI tables, we need to reserve them in e820 tables,
+	 * otherwise kernel will reclaim them and data will be corrupted
+	 */
+	entries[2].addr = ISA_END_ADDRESS;
+	entries[2].size = gd->relocaddr - TOTAL_MALLOC_LEN - ISA_END_ADDRESS;
+	entries[2].type = E820_RAM;
+
+	/* for simplicity, reserve entire malloc space */
+	entries[3].addr = gd->relocaddr - TOTAL_MALLOC_LEN;
+	entries[3].size = TOTAL_MALLOC_LEN;
+	entries[3].type = E820_RESERVED;
+
+	entries[4].addr = gd->relocaddr;
+	entries[4].size = gd->ram_size - gd->relocaddr;
+	entries[4].type = E820_RESERVED;
+
+	entries[5].addr = CONFIG_PCIE_ECAM_BASE;
+	entries[5].size = CONFIG_PCIE_ECAM_SIZE;
+	entries[5].type = E820_RESERVED;
+
+	return 6;
+}
+
+/* This function loads and patches ACPI tables provided by QEMU */
+unsigned long write_acpi_tables(unsigned long addr)
+{
+	int i, ret = 0;
+	struct fw_file *file;
+	struct bios_linker_entry *table_loader;
+	struct bios_linker_entry *entry;
+	uint32_t size;
+	struct list_head *list;
+
+	/* make sure fw_list is loaded */
+	ret = qemu_fwcfg_read_firmware_list();
+	if (ret) {
+		printf("error: can't read firmware file list\n");
+		return addr;
+	}
+
+	file = qemu_fwcfg_find_file("etc/table-loader");
+	if (!file) {
+		printf("error: can't find etc/table-loader\n");
+		return addr;
+	}
+
+	size = be32_to_cpu(file->cfg.size);
+	if ((size % sizeof(*entry)) != 0) {
+		printf("error: table-loader maybe corrupted\n");
+		return addr;
+	}
+
+	table_loader = malloc(size);
+	if (!table_loader) {
+		printf("error: no memory for table-loader\n");
+		return addr;
+	}
+
+	qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select),
+			      size, table_loader);
+
+	for (i = 0; i < (size / sizeof(*entry)); i++) {
+		entry = table_loader + i;
+		switch (le32_to_cpu(entry->command)) {
+		case BIOS_LINKER_LOADER_COMMAND_ALLOCATE:
+			ret = bios_linker_allocate(entry, &addr);
+			if (ret)
+				goto out;
+			break;
+		case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER:
+			ret = bios_linker_add_pointer(entry);
+			if (ret)
+				goto out;
+			break;
+		case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM:
+			ret = bios_linker_add_checksum(entry);
+			if (ret)
+				goto out;
+			break;
+		default:
+			break;
+		}
+	}
+
+out:
+	if (ret) {
+		list_for_each(list, &fw_list) {
+			file = list_entry(list, struct fw_file, list);
+			if (file->addr)
+				free((void *)file->addr);
+		}
+	}
+
+	free(table_loader);
+	return addr;
+}
+#endif
+
+static int qemu_fwcfg_list_firmware(void)
+{
+	int ret;
+	struct list_head *entry;
+	struct fw_file *file;
+
+	/* make sure fw_list is loaded */
+	ret = qemu_fwcfg_read_firmware_list();
+	if (ret)
+		return ret;
+
+	list_for_each(entry, &fw_list) {
+		file = list_entry(entry, struct fw_file, list);
+		printf("%-56s\n", file->cfg.name);
+	}
+
 	return 0;
 }
 
diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c
index 5a7b92944a21501edd10b99824cb2eab337e0da1..f8af566deae80d714e2516aa04c370b6eed20c9a 100644
--- a/arch/x86/cpu/qemu/qemu.c
+++ b/arch/x86/cpu/qemu/qemu.c
@@ -15,6 +15,31 @@
 
 static bool i440fx;
 
+static void enable_pm_piix(void)
+{
+	u8 en;
+	u16 cmd;
+
+	/* Set the PM I/O base */
+	x86_pci_write_config32(PIIX_PM, PMBA, CONFIG_ACPI_PM1_BASE | 1);
+
+	/* Enable access to the PM I/O space */
+	cmd = x86_pci_read_config16(PIIX_PM, PCI_COMMAND);
+	cmd |= PCI_COMMAND_IO;
+	x86_pci_write_config16(PIIX_PM, PCI_COMMAND, cmd);
+
+	/* PM I/O Space Enable (PMIOSE) */
+	en = x86_pci_read_config8(PIIX_PM, PMREGMISC);
+	en |= PMIOSE;
+	x86_pci_write_config8(PIIX_PM, PMREGMISC, en);
+}
+
+static void enable_pm_ich9(void)
+{
+	/* Set the PM I/O base */
+	x86_pci_write_config32(ICH9_PM, PMBA, CONFIG_ACPI_PM1_BASE | 1);
+}
+
 static void qemu_chipset_init(void)
 {
 	u16 device, xbcs;
@@ -53,10 +78,14 @@ static void qemu_chipset_init(void)
 		xbcs = x86_pci_read_config16(PIIX_ISA, XBCS);
 		xbcs |= APIC_EN;
 		x86_pci_write_config16(PIIX_ISA, XBCS, xbcs);
+
+		enable_pm_piix();
 	} else {
 		/* Configure PCIe ECAM base address */
 		x86_pci_write_config32(PCI_BDF(0, 0, 0), PCIEX_BAR,
 				       CONFIG_PCIE_ECAM_BASE | BAR_EN);
+
+		enable_pm_ich9();
 	}
 
 	qemu_fwcfg_init();
diff --git a/arch/x86/dts/bayleybay.dts b/arch/x86/dts/bayleybay.dts
index 9bf707bf0e84bdd43c05d7f97d8fbafddcd2b5d7..fbca46762c55149ae601e41fc4edadbd4f3d37b8 100644
--- a/arch/x86/dts/bayleybay.dts
+++ b/arch/x86/dts/bayleybay.dts
@@ -21,7 +21,7 @@
 
 	aliases {
 		serial0 = &serial;
-		spi0 = "/spi";
+		spi0 = &spi;
 	};
 
 	config {
@@ -184,7 +184,7 @@
 				>;
 			};
 
-			spi {
+			spi: spi {
 				#address-cells = <1>;
 				#size-cells = <0>;
 				compatible = "intel,ich-spi";
diff --git a/arch/x86/dts/broadwell_som-6896.dts b/arch/x86/dts/broadwell_som-6896.dts
index 4e9e410b706aac85ea31ad99e4f28904bc6a64f7..7b2c51504b1a9694289359c94a94414a42799af9 100644
--- a/arch/x86/dts/broadwell_som-6896.dts
+++ b/arch/x86/dts/broadwell_som-6896.dts
@@ -10,7 +10,7 @@
 	compatible = "advantech,som-6896", "intel,broadwell";
 
 	aliases {
-		spi0 = "/spi";
+		spi0 = &spi;
 	};
 
 	config {
@@ -34,7 +34,7 @@
 			reg = <0x0000f800 0 0 0 0>;
 			compatible = "intel,pch9";
 
-			spi {
+			spi: spi {
 				#address-cells = <1>;
 				#size-cells = <0>;
 				compatible = "intel,ich-spi";
diff --git a/arch/x86/dts/chromebook_link.dts b/arch/x86/dts/chromebook_link.dts
index d148d6e349cd87f0d8c06395834aca3f52909e5e..58072031df88e7c2fd536b1bb6fa6ac686d84d72 100644
--- a/arch/x86/dts/chromebook_link.dts
+++ b/arch/x86/dts/chromebook_link.dts
@@ -11,7 +11,7 @@
 	compatible = "google,link", "intel,celeron-ivybridge";
 
 	aliases {
-		spi0 = "/pci/pch/spi";
+		spi0 = &spi;
 		usb0 = &usb_0;
 		usb1 = &usb_1;
 	};
@@ -252,7 +252,7 @@
 			/* Enable EC SMI source */
 			intel,alt-gp-smi-enable = <0x0100>;
 
-			spi {
+			spi: spi {
 				#address-cells = <1>;
 				#size-cells = <0>;
 				compatible = "intel,ich-spi";
diff --git a/arch/x86/dts/chromebox_panther.dts b/arch/x86/dts/chromebox_panther.dts
index 23027016e5746a51768974a2629f06ea906ceecc..48f0c77d45894b3efc2d7e3111426c62a11e574c 100644
--- a/arch/x86/dts/chromebox_panther.dts
+++ b/arch/x86/dts/chromebox_panther.dts
@@ -10,7 +10,7 @@
 	compatible = "google,panther", "intel,haswell";
 
 	aliases {
-		spi0 = "/spi";
+		spi0 = &spi;
 	};
 
 	config {
@@ -56,7 +56,7 @@
 			reg = <0x0000f800 0 0 0 0>;
 			compatible = "intel,pch9";
 
-			spi {
+			spi: spi {
 				#address-cells = <1>;
 				#size-cells = <0>;
 				compatible = "intel,ich-spi";
diff --git a/arch/x86/dts/crownbay.dts b/arch/x86/dts/crownbay.dts
index d6dd0b49f0fac3a64f9ec4192c3a2ed431d2610f..47fab0fda6758710d0cba172268f10a93c2790de 100644
--- a/arch/x86/dts/crownbay.dts
+++ b/arch/x86/dts/crownbay.dts
@@ -19,7 +19,7 @@
 	compatible = "intel,crownbay", "intel,queensbay";
 
 	aliases {
-		spi0 = "/spi";
+		spi0 = &spi;
 	};
 
 	config {
@@ -227,7 +227,7 @@
 				>;
 			};
 
-			spi {
+			spi: spi {
 				#address-cells = <1>;
 				#size-cells = <0>;
 				compatible = "intel,ich-spi";
diff --git a/arch/x86/dts/galileo.dts b/arch/x86/dts/galileo.dts
index a2f5a1f223427508c447225df87bdce965b91b4a..dd75fc4dc968725f627b7a89efa3d6cde77ce11f 100644
--- a/arch/x86/dts/galileo.dts
+++ b/arch/x86/dts/galileo.dts
@@ -18,7 +18,7 @@
 	compatible = "intel,galileo", "intel,quark";
 
 	aliases {
-		spi0 = "/spi";
+		spi0 = &spi;
 	};
 
 	config {
@@ -115,7 +115,7 @@
 				>;
 			};
 
-			spi {
+			spi: spi {
 				#address-cells = <1>;
 				#size-cells = <0>;
 				compatible = "intel,ich-spi";
diff --git a/arch/x86/dts/minnowmax.dts b/arch/x86/dts/minnowmax.dts
index e7ef7c987b6226b525a1d40be3299ec5787a0d6e..7afdf6c30ba015f134a12a55b0784daf0f188d19 100644
--- a/arch/x86/dts/minnowmax.dts
+++ b/arch/x86/dts/minnowmax.dts
@@ -20,7 +20,7 @@
 
 	aliases {
 		serial0 = &serial;
-		spi0 = "/spi";
+		spi0 = &spi;
 	};
 
 	config {
@@ -218,7 +218,7 @@
 				>;
 			};
 
-			spi {
+			spi: spi {
 				#address-cells = <1>;
 				#size-cells = <0>;
 				compatible = "intel,ich-spi";
diff --git a/arch/x86/include/asm/arch-qemu/device.h b/arch/x86/include/asm/arch-qemu/device.h
index 75a435e67b9ff294e33035b0cfaf83b811ef40f2..38ab798994f00e36d26d4e6e8148810eb8be0b42 100644
--- a/arch/x86/include/asm/arch-qemu/device.h
+++ b/arch/x86/include/asm/arch-qemu/device.h
@@ -13,6 +13,8 @@
 #define PIIX_ISA	PCI_BDF(0, 1, 0)
 #define PIIX_IDE	PCI_BDF(0, 1, 1)
 #define PIIX_USB	PCI_BDF(0, 1, 2)
+#define PIIX_PM	PCI_BDF(0, 1, 3)
+#define ICH9_PM	PCI_BDF(0, 0x1f, 0)
 #define I440FX_VGA	PCI_BDF(0, 2, 0)
 
 #define QEMU_Q35	PCI_BDF(0, 0, 0)
diff --git a/arch/x86/include/asm/arch-qemu/qemu.h b/arch/x86/include/asm/arch-qemu/qemu.h
index b67d3428ee69711f5e469aa70ebd13146e073fa7..a85eee8ec6d13bd6078b45a6c74cf9bcab50026b 100644
--- a/arch/x86/include/asm/arch-qemu/qemu.h
+++ b/arch/x86/include/asm/arch-qemu/qemu.h
@@ -33,4 +33,9 @@
 #define LOW_RAM_ADDR		0x34
 #define HIGH_RAM_ADDR		0x35
 
+/* PM registers */
+#define PMBA		0x40
+#define PMREGMISC	0x80
+#define PMIOSE		(1 << 0)
+
 #endif /* _ARCH_QEMU_H_ */
diff --git a/arch/x86/include/asm/fw_cfg.h b/arch/x86/include/asm/fw_cfg.h
index fb110fa8e786314e6ffcfd3c59721a5e3a362cc5..e9450c619687f246fdb5f6d2d46305ab06751cb2 100644
--- a/arch/x86/include/asm/fw_cfg.h
+++ b/arch/x86/include/asm/fw_cfg.h
@@ -12,6 +12,8 @@
 #define FW_DMA_PORT_LOW	0x514
 #define FW_DMA_PORT_HIGH	0x518
 
+#include <linux/list.h>
+
 enum qemu_fwcfg_items {
 	FW_CFG_SIGNATURE	= 0x00,
 	FW_CFG_ID		= 0x01,
@@ -45,11 +47,23 @@ enum qemu_fwcfg_items {
 	FW_CFG_INVALID		= 0xffff,
 };
 
+enum {
+	BIOS_LINKER_LOADER_COMMAND_ALLOCATE	= 0x1,
+	BIOS_LINKER_LOADER_COMMAND_ADD_POINTER  = 0x2,
+	BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM = 0x3,
+};
+
+enum {
+	BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH = 0x1,
+	BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG = 0x2,
+};
+
 #define FW_CFG_FILE_SLOTS	0x10
 #define FW_CFG_MAX_ENTRY	(FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS)
 #define FW_CFG_ENTRY_MASK	 ~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL)
 
 #define FW_CFG_MAX_FILE_PATH	56
+#define BIOS_LINKER_LOADER_FILESZ FW_CFG_MAX_FILE_PATH
 
 #define QEMU_FW_CFG_SIGNATURE	(('Q' << 24) | ('E' << 16) | ('M' << 8) | 'U')
 
@@ -67,9 +81,10 @@ struct fw_cfg_file {
 	char name[FW_CFG_MAX_FILE_PATH];
 };
 
-struct fw_cfg_files {
-	__be32 count;
-	struct fw_cfg_file files[];
+struct fw_file {
+	struct fw_cfg_file cfg; /* firmware file information */
+	unsigned long addr;     /* firmware file in-memory address */
+	struct list_head list;  /* list node to link to fw_list */
 };
 
 struct fw_cfg_dma_access {
@@ -78,6 +93,55 @@ struct fw_cfg_dma_access {
 	__be64 address;
 };
 
+struct bios_linker_entry {
+	__le32 command;
+	union {
+		/*
+		 * COMMAND_ALLOCATE - allocate a table from @alloc.file
+		 * subject to @alloc.align alignment (must be power of 2)
+		 * and @alloc.zone (can be HIGH or FSEG) requirements.
+		 *
+		 * Must appear exactly once for each file, and before
+		 * this file is referenced by any other command.
+		 */
+		struct {
+			char file[BIOS_LINKER_LOADER_FILESZ];
+			__le32 align;
+			uint8_t zone;
+		} alloc;
+
+		/*
+		 * COMMAND_ADD_POINTER - patch the table (originating from
+		 * @dest_file) at @pointer.offset, by adding a pointer to the
+		 * table originating from @src_file. 1,2,4 or 8 byte unsigned
+		 * addition is used depending on @pointer.size.
+		 */
+		struct {
+			char dest_file[BIOS_LINKER_LOADER_FILESZ];
+			char src_file[BIOS_LINKER_LOADER_FILESZ];
+			__le32 offset;
+			uint8_t size;
+		} pointer;
+
+		/*
+		 * COMMAND_ADD_CHECKSUM - calculate checksum of the range
+		 * specified by @cksum_start and @cksum_length fields,
+		 * and then add the value at @cksum.offset.
+		 * Checksum simply sums -X for each byte X in the range
+		 * using 8-bit math.
+		 */
+		struct {
+			char file[BIOS_LINKER_LOADER_FILESZ];
+			__le32 offset;
+			__le32 start;
+			__le32 length;
+		} cksum;
+
+		/* padding */
+		char pad[124];
+	};
+} __packed;
+
 /**
  * Initialize QEMU fw_cfg interface
  */
diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h
index 9c143caf670b84653d14eda57bf70b936b965c35..031740b708a8f5d660801f816db421af77e0a8fd 100644
--- a/arch/x86/include/asm/u-boot-x86.h
+++ b/arch/x86/include/asm/u-boot-x86.h
@@ -45,7 +45,7 @@ void dram_init_banksize(void);
 int default_print_cpuinfo(void);
 
 /* Set up a UART which can be used with printch(), printhex8(), etc. */
-int setup_early_uart(void);
+int setup_internal_uart(int enable);
 
 void setup_pcat_compatibility(void);
 
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index d9fc296b6e4877a1a3b3a8766fe7d54f6ac54d67..50bc69a659f078ad8a0ec022d0083bcab9d4444d 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -32,7 +32,9 @@ obj-$(CONFIG_X86_RAMTEST) += ramtest.o
 obj-y += sfi.o
 obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += smbios.o
 obj-y	+= string.o
+ifndef CONFIG_QEMU_ACPI_TABLE
 obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o
+endif
 obj-y	+= tables.o
 obj-$(CONFIG_CMD_ZBOOT)	+= zimage.o
 obj-$(CONFIG_HAVE_FSP) += fsp/
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index ab1db7ec26eee8e08aabf101aa4add678415e5da..2ec5ad2fa4a0d11f7b56984036d739c50ccb63c3 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -331,6 +331,10 @@ static void acpi_create_ssdt_generator(acpi_header_t *ssdt,
 	ssdt->checksum = table_compute_checksum((void *)ssdt, ssdt->length);
 }
 
+/*
+ * QEMU's version of write_acpi_tables is defined in
+ * arch/x86/cpu/qemu/fw_cfg.c
+ */
 unsigned long write_acpi_tables(unsigned long start)
 {
 	unsigned long current;
diff --git a/arch/x86/lib/fsp/fsp_support.c b/arch/x86/lib/fsp/fsp_support.c
index 875c96a8f19a47961b366d2f1ea400e3270ac347..29fa06098d1afb30f61e38683538ff62ce119b9f 100644
--- a/arch/x86/lib/fsp/fsp_support.c
+++ b/arch/x86/lib/fsp/fsp_support.c
@@ -111,7 +111,7 @@ void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf)
 #endif
 
 #ifdef CONFIG_DEBUG_UART
-	setup_early_uart();
+	setup_internal_uart(1);
 #endif
 
 	fsp_hdr = find_fsp_header();
diff --git a/doc/README.x86 b/doc/README.x86
index 36aaef011de9956dc6f3a6921024f8458b8b1448..6d9cb10edc85233bf25536ba971eadcdb19474ba 100644
--- a/doc/README.x86
+++ b/doc/README.x86
@@ -706,7 +706,7 @@ the board, then you can use post_code() calls from C or assembler to monitor
 boot progress. This can be good for debugging.
 
 If not, you can try to get serial working as early as possible. The early
-debug serial port may be useful here. See setup_early_uart() for an example.
+debug serial port may be useful here. See setup_internal_uart() for an example.
 
 During the U-Boot porting, one of the important steps is to write correct PIRQ
 routing information in the board device tree. Without it, device drivers in the
diff --git a/doc/device-tree-bindings/misc/intel,baytrail-fsp.txt b/doc/device-tree-bindings/misc/intel,baytrail-fsp.txt
index b44b5b5431f8e65cf7652832314959dc23b8576b..07fa46ef7ef557b095da01cd86b1a255d1160745 100644
--- a/doc/device-tree-bindings/misc/intel,baytrail-fsp.txt
+++ b/doc/device-tree-bindings/misc/intel,baytrail-fsp.txt
@@ -74,12 +74,41 @@ discovered by the FSP and used to setup main memory.
 
 	# Integer properties:
 
-	- fsp,dram-speed
+	- fsp,dram-speed:
+	  0x0: "800 MHz"
+	  0x1: "1066 MHz"
+	  0x2: "1333 MHz"
+	  0x3: "1600 MHz"
+
 	- fsp,dram-type
+	  0x0: "DDR3"
+	  0x1: "DDR3L"
+	  0x2: "DDR3U"
+	  0x4: "LPDDR2"
+	  0x5: "LPDDR3"
+	  0x6: "DDR4"
+
 	- fsp,dimm-width
+	  0x0: "x8"
+	  0x1: "x16"
+	  0x2: "x32"
+
 	- fsp,dimm-density
+	  0x0: "1 Gbit"
+	  0x1: "2 Gbit"
+	  0x2: "4 Gbit"
+	  0x3: "8 Gbit"
+
 	- fsp,dimm-bus-width
+	  0x0: "8 bits"
+	  0x1: "16 bits"
+	  0x2: "32 bits"
+	  0x3: "64 bits"
+
 	- fsp,dimm-sides
+	  0x0: "1 rank"
+	  0x1: "2 ranks"
+
 	- fsp,dimm-tcl
 	- fsp,dimm-trpt-rcd
 	- fsp,dimm-twr
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index cba236334c0e400101ff53c31ea1e8c57568b655..af8667f030c52c4f266351714df15401a301d372 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -130,4 +130,12 @@ config RESET
 	  effect a reset. The uclass will try all available drivers when
 	  reset_walk() is called.
 
+config WINBOND_W83627
+	bool "Enable Winbond Super I/O driver"
+	help
+	  If you say Y here, you will get support for the Winbond
+	  W83627 Super I/O driver. This can be used to enable the
+	  legacy UART or other devices in the Winbond Super IO chips
+	  on X86 platforms.
+
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index cd4846b4a8e93794990eb21e4b7cf8297997458d..e1e3c6b70fc047d746882e28cc40c38223e47438 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -41,3 +41,4 @@ obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o
 obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
 obj-$(CONFIG_RESET) += reset-uclass.o
 obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o
+obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o
diff --git a/drivers/misc/winbond_w83627.c b/drivers/misc/winbond_w83627.c
new file mode 100644
index 0000000000000000000000000000000000000000..59db7d971cab6cdcd79cb94cbb6a8dbf6602b11a
--- /dev/null
+++ b/drivers/misc/winbond_w83627.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 Stefan Roese <sr@denx.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/pnp_def.h>
+
+#define WINBOND_ENTRY_KEY	0x87
+#define WINBOND_EXIT_KEY	0xaa
+
+/* Enable configuration: pass entry key '0x87' into index port dev twice */
+static void pnp_enter_conf_state(u16 dev)
+{
+	u16 port = dev >> 8;
+
+	outb(WINBOND_ENTRY_KEY, port);
+	outb(WINBOND_ENTRY_KEY, port);
+}
+
+/* Disable configuration: pass exit key '0xAA' into index port dev */
+static void pnp_exit_conf_state(u16 dev)
+{
+	u16 port = dev >> 8;
+
+	outb(WINBOND_EXIT_KEY, port);
+}
+
+/* Bring up early serial debugging output before the RAM is initialized */
+void winbond_enable_serial(uint dev, uint iobase, uint irq)
+{
+	pnp_enter_conf_state(dev);
+	pnp_set_logical_device(dev);
+	pnp_set_enable(dev, 0);
+	pnp_set_iobase(dev, PNP_IDX_IO0, iobase);
+	pnp_set_irq(dev, PNP_IDX_IRQ0, irq);
+	pnp_set_enable(dev, 1);
+	pnp_exit_conf_state(dev);
+}
diff --git a/include/configs/x86-common.h b/include/configs/x86-common.h
index 4182a3bf6314a5ee2dbf596fce5c780598d8f46c..dc7b227d25c41e3061a521a2ad196237a666e362 100644
--- a/include/configs/x86-common.h
+++ b/include/configs/x86-common.h
@@ -100,6 +100,7 @@
  * Command line configuration.
  */
 #define CONFIG_CMD_DATE
+#define CONFIG_CMD_FS_GENERIC
 #define CONFIG_CMD_FPGA_LOADMK
 #define CONFIG_CMD_IO
 #define CONFIG_CMD_IRQ
diff --git a/include/winbond_w83627.h b/include/winbond_w83627.h
new file mode 100644
index 0000000000000000000000000000000000000000..ac3bec6f9fbfbf7064fc24ac699e1e8beb0b1306
--- /dev/null
+++ b/include/winbond_w83627.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 Stefan Roese <sr@denx.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _WINBOND_W83627_H_
+#define _WINBOND_W83627_H_
+
+/* I/O address of Winbond Super IO chip */
+#define WINBOND_IO_PORT		0x2e
+
+/* Logical device number */
+#define W83627DHG_FDC		0	/* Floppy */
+#define W83627DHG_PP		1	/* Parallel port */
+#define W83627DHG_SP1		2	/* Com1 */
+#define W83627DHG_SP2		3	/* Com2 */
+#define W83627DHG_KBC		5	/* PS/2 keyboard & mouse */
+#define W83627DHG_SPI		6	/* Serial peripheral interface */
+#define W83627DHG_WDTO_PLED	8	/* WDTO#, PLED */
+#define W83627DHG_ACPI		10	/* ACPI */
+#define W83627DHG_HWM		11	/* Hardware monitor */
+#define W83627DHG_PECI_SST	12	/* PECI, SST */
+
+/**
+ * Configure the base I/O port of the specified serial device and enable the
+ * serial device.
+ *
+ * @dev: high 8 bits = super I/O port, low 8 bits = logical device number
+ * @iobase: processor I/O port address to assign to this serial device
+ * @irq: processor IRQ number to assign to this serial device
+ */
+void winbond_enable_serial(uint dev, uint iobase, uint irq);
+
+#endif /* _WINBOND_W83627_H_ */