summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/Kconfig2
-rw-r--r--arch/x86/Kconfig180
-rw-r--r--arch/x86/cpu/Makefile2
-rw-r--r--arch/x86/cpu/baytrail/Makefile1
-rw-r--r--arch/x86/cpu/baytrail/cpu.c205
-rw-r--r--arch/x86/cpu/baytrail/valleyview.c1
-rw-r--r--arch/x86/cpu/config.mk2
-rw-r--r--arch/x86/cpu/coreboot/pci.c11
-rw-r--r--arch/x86/cpu/cpu.c71
-rw-r--r--arch/x86/cpu/interrupts.c5
-rw-r--r--arch/x86/cpu/ivybridge/car.S1
-rw-r--r--arch/x86/cpu/ivybridge/cpu.c5
-rw-r--r--arch/x86/cpu/ivybridge/early_me.c13
-rw-r--r--arch/x86/cpu/ivybridge/model_206ax.c4
-rw-r--r--arch/x86/cpu/ivybridge/sdram.c3
-rw-r--r--arch/x86/cpu/mp_init.c496
-rw-r--r--arch/x86/cpu/pci.c21
-rw-r--r--arch/x86/cpu/quark/quark.c14
-rw-r--r--arch/x86/cpu/queensbay/Makefile2
-rw-r--r--arch/x86/cpu/queensbay/irq.c242
-rw-r--r--arch/x86/cpu/queensbay/tnc.c14
-rw-r--r--arch/x86/cpu/sipi_vector.S216
-rw-r--r--arch/x86/dts/chromebook_link.dts2
-rw-r--r--arch/x86/dts/crownbay.dts6
-rw-r--r--arch/x86/dts/galileo.dts4
-rw-r--r--arch/x86/dts/minnowmax.dts67
-rw-r--r--arch/x86/include/asm/arch-baytrail/gpio.h2
-rw-r--r--arch/x86/include/asm/arch-ivybridge/microcode.h3
-rw-r--r--arch/x86/include/asm/arch-ivybridge/model_206ax.h2
-rw-r--r--arch/x86/include/asm/arch-quark/quark.h7
-rw-r--r--arch/x86/include/asm/arch-queensbay/device.h94
-rw-r--r--arch/x86/include/asm/arch-queensbay/irq.h55
-rw-r--r--arch/x86/include/asm/arch-queensbay/tnc.h40
-rw-r--r--arch/x86/include/asm/atomic.h115
-rw-r--r--arch/x86/include/asm/cpu.h19
-rw-r--r--arch/x86/include/asm/e820.h133
-rw-r--r--arch/x86/include/asm/global_data.h1
-rw-r--r--arch/x86/include/asm/ibmpc.h3
-rw-r--r--arch/x86/include/asm/interrupt.h2
-rw-r--r--arch/x86/include/asm/mp.h94
-rw-r--r--arch/x86/include/asm/msr-index.h22
-rw-r--r--arch/x86/include/asm/msr.h28
-rw-r--r--arch/x86/include/asm/mtrr.h16
-rw-r--r--arch/x86/include/asm/pci.h14
-rw-r--r--arch/x86/include/asm/pirq_routing.h139
-rw-r--r--arch/x86/include/asm/processor.h22
-rw-r--r--arch/x86/include/asm/sfi.h137
-rw-r--r--arch/x86/include/asm/sipi.h86
-rw-r--r--arch/x86/include/asm/tables.h49
-rw-r--r--arch/x86/include/asm/turbo.h3
-rw-r--r--arch/x86/include/asm/u-boot-x86.h4
-rw-r--r--arch/x86/lib/Makefile4
-rw-r--r--arch/x86/lib/fsp/fsp_common.c7
-rw-r--r--arch/x86/lib/pirq_routing.c137
-rw-r--r--arch/x86/lib/sfi.c154
-rw-r--r--arch/x86/lib/tables.c35
-rw-r--r--arch/x86/lib/video.c205
-rw-r--r--arch/x86/lib/zimage.c29
58 files changed, 2757 insertions, 494 deletions
diff --git a/arch/Kconfig b/arch/Kconfig
index 1102346220..200588aef6 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -93,6 +93,8 @@ config X86
select DM
select DM_SERIAL
select DM_GPIO
+ select DM_SPI
+ select DM_SPI_FLASH
endchoice
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 3f1401ae4d..8e734fdfb4 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -11,84 +11,33 @@ config SYS_VSNPRINTF
default y
choice
- prompt "Target select"
+ prompt "Mainboard vendor"
+ default VENDOR_COREBOOT
-config TARGET_COREBOOT
- bool "Support coreboot"
- help
- This target is used for running U-Boot on top of Coreboot. In
- this case Coreboot does the early inititalisation, and U-Boot
- takes over once the RAM, video and CPU are fully running.
- U-Boot is loaded as a fallback payload from Coreboot, in
- Coreboot terminology. This method was used for the Chromebook
- Pixel when launched.
-
-config TARGET_CHROMEBOOK_LINK
- bool "Support Chromebook link"
- help
- This is the Chromebook Pixel released in 2013. It uses an Intel
- i5 Ivybridge which is a die-shrink of Sandybridge, with 4GB of
- SDRAM. It has a Panther Point platform controller hub, PCIe
- WiFi and Bluetooth. It also includes a 720p webcam, USB SD
- reader, microphone and speakers, display port and 32GB SATA
- solid state drive. There is a Chrome OS EC connected on LPC,
- and it provides a 2560x1700 high resolution touch-enabled LCD
- display.
-
-config TARGET_CHROMEBOX_PANTHER
- bool "Support Chromebox panther (not available)"
- select n
- help
- Note: At present this must be used with Coreboot. See README.x86
- for instructions.
-
- This is the Asus Chromebox CN60 released in 2014. It uses an Intel
- Haswell Celeron 2955U Dual Core CPU with 2GB of SDRAM. It has a
- Lynx Point platform controller hub, PCIe WiFi and Bluetooth. It also
- includes a USB SD reader, four USB3 ports, display port and HDMI
- video output and a 16GB SATA solid state drive. There is no Chrome
- OS EC on this model.
-
-config TARGET_CROWNBAY
- bool "Support Intel Crown Bay CRB"
- help
- This is the Intel Crown Bay Customer Reference Board. It contains
- the Intel Atom Processor E6xx populated on the COM Express module
- with 1GB DDR2 soldered down memory and a carrier board with the
- Intel Platform Controller Hub EG20T, other system components and
- peripheral connectors for PCIe/SATA/USB/LAN/SD/UART/Audio/LVDS.
-
-config TARGET_MINNOWMAX
- bool "Support Intel Minnowboard MAX"
- help
- This is the Intel Minnowboard MAX. It contains an Atom E3800
- processor in a small form factor with Ethernet, micro-SD, USB 2,
- USB 3, SATA, serial console, some GPIOs and HDMI 1.3 video out.
- It requires some binary blobs - see README.x86 for details.
+config VENDOR_COREBOOT
+ bool "coreboot"
- Note that PCIE_ECAM_BASE is set up by the FSP so the value used
- by U-Boot matches that value.
+config VENDOR_GOOGLE
+ bool "Google"
-config TARGET_GALILEO
- bool "Support Intel Galileo"
- help
- This is the Intel Galileo board, which is the first in a family of
- Arduino-certified development and prototyping boards based on Intel
- architecture. It includes an Intel Quark SoC X1000 processor, a 32-bit
- single-core, single-thread, Intel Pentium processor instrunction set
- architecture (ISA) compatible, operating at speeds up to 400Mhz,
- along with 256MB DDR3 memory. It supports a wide range of industry
- standard I/O interfaces, including a full-sized mini-PCIe slot,
- one 100Mb Ethernet port, a microSD card slot, a USB host port and
- a USB client port.
+config VENDOR_INTEL
+ bool "Intel"
endchoice
-config DM_SPI
- default y
+# board-specific options below
+source "board/coreboot/Kconfig"
+source "board/google/Kconfig"
+source "board/intel/Kconfig"
-config DM_SPI_FLASH
- default y
+# platform-specific options below
+source "arch/x86/cpu/baytrail/Kconfig"
+source "arch/x86/cpu/coreboot/Kconfig"
+source "arch/x86/cpu/ivybridge/Kconfig"
+source "arch/x86/cpu/quark/Kconfig"
+source "arch/x86/cpu/queensbay/Kconfig"
+
+# architecture-specific options below
config SYS_MALLOC_F_LEN
default 0x800
@@ -226,12 +175,12 @@ config X86_RAMTEST
detecting obvious failures.
config MARK_GRAPHICS_MEM_WRCOMB
- bool "Mark graphics memory as write-combining."
+ bool "Mark graphics memory as write-combining"
default n
help
- The graphics performance may increase if the graphics
- memory is set as write-combining cache type. This option
- enables marking the graphics memory as write-combining.
+ The graphics performance may increase if the graphics
+ memory is set as write-combining cache type. This option
+ enables marking the graphics memory as write-combining.
menu "Display"
@@ -412,15 +361,35 @@ config FSP_TEMP_RAM_ADDR
Stack top address which is used in FspInit after DRAM is ready and
CAR is disabled.
-source "arch/x86/cpu/baytrail/Kconfig"
-
-source "arch/x86/cpu/coreboot/Kconfig"
-
-source "arch/x86/cpu/ivybridge/Kconfig"
-
-source "arch/x86/cpu/quark/Kconfig"
+config MAX_CPUS
+ int "Maximum number of CPUs permitted"
+ default 4
+ help
+ When using multi-CPU chips it is possible for U-Boot to start up
+ more than one CPU. The stack memory used by all of these CPUs is
+ pre-allocated so at present U-Boot wants to know the maximum
+ number of CPUs that may be present. Set this to at least as high
+ as the number of CPUs in your system (it uses about 4KB of RAM for
+ each CPU).
+
+config SMP
+ bool "Enable Symmetric Multiprocessing"
+ default n
+ help
+ Enable use of more than one CPU in U-Boot and the Operating System
+ when loaded. Each CPU will be started up and information can be
+ obtained using the 'cpu' command. If this option is disabled, then
+ only one CPU will be enabled regardless of the number of CPUs
+ available.
-source "arch/x86/cpu/queensbay/Kconfig"
+config AP_STACK_SIZE
+ hex
+ default 0x1000
+ help
+ Each additional CPU started by U-Boot requires its own stack. This
+ option sets the stack size used by each CPU and directly affects
+ the memory used by this initialisation process. Typically 4KB is
+ enough space.
config TSC_CALIBRATION_BYPASS
bool "Bypass Time-Stamp Counter (TSC) calibration"
@@ -442,17 +411,50 @@ config TSC_FREQ_IN_MHZ
help
The running frequency in MHz of Time-Stamp Counter (TSC).
-source "board/coreboot/coreboot/Kconfig"
+menu "System tables"
-source "board/google/chromebook_link/Kconfig"
+config GENERATE_PIRQ_TABLE
+ bool "Generate a PIRQ table"
+ default n
+ help
+ Generate a PIRQ routing table for this board. The PIRQ routing table
+ is generated by U-Boot in the system memory from 0xf0000 to 0xfffff
+ at every 16-byte boundary with a PCI IRQ routing signature ("$PIR").
+ It specifies the interrupt router information as well how all the PCI
+ devices' interrupt pins are wired to PIRQs.
+
+config GENERATE_SFI_TABLE
+ bool "Generate a SFI (Simple Firmware Interface) table"
+ help
+ The Simple Firmware Interface (SFI) provides a lightweight method
+ for platform firmware to pass information to the operating system
+ via static tables in memory. Kernel SFI support is required to
+ boot on SFI-only platforms. If you have ACPI tables then these are
+ used instead.
-source "board/google/chromebox_panther/Kconfig"
+ U-Boot writes this table in write_sfi_table() just before booting
+ the OS.
-source "board/intel/crownbay/Kconfig"
+ For more information, see http://simplefirmware.org
+
+endmenu
-source "board/intel/minnowmax/Kconfig"
+config MAX_PIRQ_LINKS
+ int
+ default 8
+ help
+ This variable specifies the number of PIRQ interrupt links which are
+ routable. On most older chipsets, this is 4, PIRQA through PIRQD.
+ Some newer chipsets offer more than four links, commonly up to PIRQH.
-source "board/intel/galileo/Kconfig"
+config IRQ_SLOT_COUNT
+ int
+ default 128
+ help
+ U-Boot can support up to 254 IRQ slot info in the PIRQ routing table
+ which in turns forms a table of exact 4KiB. The default value 128
+ should be enough for most boards. If this does not fit your board,
+ change it according to your needs.
config PCIE_ECAM_BASE
hex
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile
index 6ded0a7f0f..043bea258c 100644
--- a/arch/x86/cpu/Makefile
+++ b/arch/x86/cpu/Makefile
@@ -19,6 +19,8 @@ obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/
obj-$(CONFIG_INTEL_QUARK) += quark/
obj-$(CONFIG_INTEL_QUEENSBAY) += queensbay/
obj-y += lapic.o
+obj-$(CONFIG_SMP) += mp_init.o
obj-y += mtrr.o
obj-$(CONFIG_PCI) += pci.o
+obj-$(CONFIG_SMP) += sipi_vector.o
obj-y += turbo.o
diff --git a/arch/x86/cpu/baytrail/Makefile b/arch/x86/cpu/baytrail/Makefile
index 8914e8b6d5..c78b644eb7 100644
--- a/arch/x86/cpu/baytrail/Makefile
+++ b/arch/x86/cpu/baytrail/Makefile
@@ -4,6 +4,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
+obj-y += cpu.o
obj-y += early_uart.o
obj-y += fsp_configs.o
obj-y += pci.o
diff --git a/arch/x86/cpu/baytrail/cpu.c b/arch/x86/cpu/baytrail/cpu.c
new file mode 100644
index 0000000000..1d482064b2
--- /dev/null
+++ b/arch/x86/cpu/baytrail/cpu.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Based on code from coreboot
+ */
+
+#include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <asm/cpu.h>
+#include <asm/lapic.h>
+#include <asm/mp.h>
+#include <asm/msr.h>
+#include <asm/turbo.h>
+
+#ifdef CONFIG_SMP
+static int enable_smis(struct udevice *cpu, void *unused)
+{
+ return 0;
+}
+
+static struct mp_flight_record mp_steps[] = {
+ MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL),
+ /* Wait for APs to finish initialization before proceeding. */
+ MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL),
+};
+
+static int detect_num_cpus(void)
+{
+ int ecx = 0;
+
+ /*
+ * Use the algorithm described in Intel 64 and IA-32 Architectures
+ * Software Developer's Manual Volume 3 (3A, 3B & 3C): System
+ * Programming Guide, Jan-2015. Section 8.9.2: Hierarchical Mapping
+ * of CPUID Extended Topology Leaf.
+ */
+ while (1) {
+ struct cpuid_result leaf_b;
+
+ leaf_b = cpuid_ext(0xb, ecx);
+
+ /*
+ * Bay Trail doesn't have hyperthreading so just determine the
+ * number of cores by from level type (ecx[15:8] == * 2)
+ */
+ if ((leaf_b.ecx & 0xff00) == 0x0200)
+ return leaf_b.ebx & 0xffff;
+ ecx++;
+ }
+}
+
+static int baytrail_init_cpus(void)
+{
+ struct mp_params mp_params;
+
+ lapic_setup();
+
+ mp_params.num_cpus = detect_num_cpus();
+ mp_params.parallel_microcode_load = 0,
+ mp_params.flight_plan = &mp_steps[0];
+ mp_params.num_records = ARRAY_SIZE(mp_steps);
+ mp_params.microcode_pointer = 0;
+
+ if (mp_init(&mp_params)) {
+ printf("Warning: MP init failure\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+#endif
+
+int x86_init_cpus(void)
+{
+#ifdef CONFIG_SMP
+ debug("Init additional CPUs\n");
+ baytrail_init_cpus();
+#endif
+
+ return 0;
+}
+
+static void set_max_freq(void)
+{
+ msr_t perf_ctl;
+ msr_t msr;
+
+ /* Enable speed step */
+ msr = msr_read(MSR_IA32_MISC_ENABLES);
+ msr.lo |= (1 << 16);
+ msr_write(MSR_IA32_MISC_ENABLES, msr);
+
+ /*
+ * Set guaranteed ratio [21:16] from IACORE_RATIOS to bits [15:8] of
+ * the PERF_CTL
+ */
+ msr = msr_read(MSR_IACORE_RATIOS);
+ perf_ctl.lo = (msr.lo & 0x3f0000) >> 8;
+
+ /*
+ * Set guaranteed vid [21:16] from IACORE_VIDS to bits [7:0] of
+ * the PERF_CTL
+ */
+ msr = msr_read(MSR_IACORE_VIDS);
+ perf_ctl.lo |= (msr.lo & 0x7f0000) >> 16;
+ perf_ctl.hi = 0;
+
+ msr_write(MSR_IA32_PERF_CTL, perf_ctl);
+}
+
+static int cpu_x86_baytrail_probe(struct udevice *dev)
+{
+ debug("Init BayTrail core\n");
+
+ /*
+ * On BayTrail the turbo disable bit is actually scoped at the
+ * building-block level, not package. For non-BSP cores that are
+ * within a building block, enable turbo. The cores within the BSP's
+ * building block will just see it already enabled and move on.
+ */
+ if (lapicid())
+ turbo_enable();
+
+ /* Dynamic L2 shrink enable and threshold */
+ msr_clrsetbits_64(MSR_PMG_CST_CONFIG_CONTROL, 0x3f000f, 0xe0008),
+
+ /* Disable C1E */
+ msr_clrsetbits_64(MSR_POWER_CTL, 2, 0);
+ msr_setbits_64(MSR_POWER_MISC, 0x44);
+
+ /* Set this core to max frequency ratio */
+ set_max_freq();
+
+ return 0;
+}
+
+static unsigned bus_freq(void)
+{
+ msr_t clk_info = msr_read(MSR_BSEL_CR_OVERCLOCK_CONTROL);
+ switch (clk_info.lo & 0x3) {
+ case 0:
+ return 83333333;
+ case 1:
+ return 100000000;
+ case 2:
+ return 133333333;
+ case 3:
+ return 116666666;
+ default:
+ return 0;
+ }
+}
+
+static unsigned long tsc_freq(void)
+{
+ msr_t platform_info;
+ ulong bclk = bus_freq();
+
+ if (!bclk)
+ return 0;
+
+ platform_info = msr_read(MSR_PLATFORM_INFO);
+
+ return bclk * ((platform_info.lo >> 8) & 0xff);
+}
+
+static int baytrail_get_info(struct udevice *dev, struct cpu_info *info)
+{
+ info->cpu_freq = tsc_freq();
+ info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU;
+
+ return 0;
+}
+
+static int cpu_x86_baytrail_bind(struct udevice *dev)
+{
+ struct cpu_platdata *plat = dev_get_parent_platdata(dev);
+
+ plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+ "intel,apic-id", -1);
+
+ return 0;
+}
+
+static const struct cpu_ops cpu_x86_baytrail_ops = {
+ .get_desc = x86_cpu_get_desc,
+ .get_info = baytrail_get_info,
+};
+
+static const struct udevice_id cpu_x86_baytrail_ids[] = {
+ { .compatible = "intel,baytrail-cpu" },
+ { }
+};
+
+U_BOOT_DRIVER(cpu_x86_baytrail_drv) = {
+ .name = "cpu_x86_baytrail",
+ .id = UCLASS_CPU,
+ .of_match = cpu_x86_baytrail_ids,
+ .bind = cpu_x86_baytrail_bind,
+ .probe = cpu_x86_baytrail_probe,
+ .ops = &cpu_x86_baytrail_ops,
+};
diff --git a/arch/x86/cpu/baytrail/valleyview.c b/arch/x86/cpu/baytrail/valleyview.c
index a3e837d43e..9915da5bd7 100644
--- a/arch/x86/cpu/baytrail/valleyview.c
+++ b/arch/x86/cpu/baytrail/valleyview.c
@@ -16,7 +16,6 @@ static struct pci_device_id mmc_supported[] = {
int cpu_mmc_init(bd_t *bis)
{
- printf("mmc init\n");
return pci_mmc_init("ValleyView SDHCI", mmc_supported,
ARRAY_SIZE(mmc_supported));
}
diff --git a/arch/x86/cpu/config.mk b/arch/x86/cpu/config.mk
index 84aeaf3edc..4c4d0c7cd2 100644
--- a/arch/x86/cpu/config.mk
+++ b/arch/x86/cpu/config.mk
@@ -7,7 +7,7 @@
CROSS_COMPILE ?= i386-linux-
-PLATFORM_CPPFLAGS += -D__I386__ -Werror
+PLATFORM_CPPFLAGS += -D__I386__
# DO NOT MODIFY THE FOLLOWING UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!
LDPPFLAGS += -DRESET_SEG_START=0xffff0000
diff --git a/arch/x86/cpu/coreboot/pci.c b/arch/x86/cpu/coreboot/pci.c
index fa415dd42b..67eb14ce99 100644
--- a/arch/x86/cpu/coreboot/pci.c
+++ b/arch/x86/cpu/coreboot/pci.c
@@ -34,3 +34,14 @@ U_BOOT_DRIVER(pci_x86_drv) = {
.of_match = pci_x86_ids,
.ops = &pci_x86_ops,
};
+
+static const struct udevice_id generic_pch_ids[] = {
+ { .compatible = "intel,pch" },
+ { }
+};
+
+U_BOOT_DRIVER(generic_pch_drv) = {
+ .name = "pch",
+ .id = UCLASS_PCH,
+ .of_match = generic_pch_ids,
+};
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c
index a9ca50b1e4..bb4a110c00 100644
--- a/arch/x86/cpu/cpu.c
+++ b/arch/x86/cpu/cpu.c
@@ -21,6 +21,8 @@
#include <common.h>
#include <command.h>
+#include <cpu.h>
+#include <dm.h>
#include <errno.h>
#include <malloc.h>
#include <asm/control_regs.h>
@@ -29,6 +31,7 @@
#include <asm/processor.h>
#include <asm/processor-flags.h>
#include <asm/interrupt.h>
+#include <asm/tables.h>
#include <linux/compiler.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -132,6 +135,7 @@ static void load_gdt(const u64 *boot_gdt, u16 num_entries)
void setup_gdt(gd_t *id, u64 *gdt_addr)
{
+ id->arch.gdt = gdt_addr;
/* CS: code, read/execute, 4 GB, base 0 */
gdt_addr[X86_GDT_ENTRY_32BIT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff);
@@ -379,21 +383,17 @@ void flush_cache(unsigned long dummy1, unsigned long dummy2)
asm("wbinvd\n");
}
-void __attribute__ ((regparm(0))) generate_gpf(void);
-
-/* segment 0x70 is an arbitrary segment which does not exist */
-asm(".globl generate_gpf\n"
- ".hidden generate_gpf\n"
- ".type generate_gpf, @function\n"
- "generate_gpf:\n"
- "ljmp $0x70, $0x47114711\n");
-
__weak void reset_cpu(ulong addr)
{
- printf("Resetting using x86 Triple Fault\n");
- set_vector(13, generate_gpf); /* general protection fault handler */
- set_vector(8, generate_gpf); /* double fault handler */
- generate_gpf(); /* start the show */
+ /* Do a hard reset through the chipset's reset control register */
+ outb(SYS_RST | RST_CPU, PORT_RESET);
+ for (;;)
+ cpu_hlt();
+}
+
+void x86_full_reset(void)
+{
+ outb(FULL_RST | SYS_RST | RST_CPU, PORT_RESET);
}
int dcache_status(void)
@@ -520,6 +520,16 @@ char *cpu_get_name(char *name)
return ptr;
}
+int x86_cpu_get_desc(struct udevice *dev, char *buf, int size)
+{
+ if (size < CPU_MAX_NAME_LEN)
+ return -ENOSPC;
+
+ cpu_get_name(buf);
+
+ return 0;
+}
+
int default_print_cpuinfo(void)
{
printf("CPU: %s, vendor %s, device %xh\n",
@@ -593,3 +603,38 @@ void show_boot_progress(int val)
#endif
outb(val, POST_PORT);
}
+
+#ifndef CONFIG_SYS_COREBOOT
+int last_stage_init(void)
+{
+ write_tables();
+
+ return 0;
+}
+#endif
+
+__weak int x86_init_cpus(void)
+{
+ return 0;
+}
+
+int cpu_init_r(void)
+{
+ return x86_init_cpus();
+}
+
+static const struct cpu_ops cpu_x86_ops = {
+ .get_desc = x86_cpu_get_desc,
+};
+
+static const struct udevice_id cpu_x86_ids[] = {
+ { .compatible = "cpu-x86" },
+ { }
+};
+
+U_BOOT_DRIVER(cpu_x86_drv) = {
+ .name = "cpu_x86",
+ .id = UCLASS_CPU,
+ .of_match = cpu_x86_ids,
+ .ops = &cpu_x86_ops,
+};
diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c
index a21d2a6c50..c777d3646f 100644
--- a/arch/x86/cpu/interrupts.c
+++ b/arch/x86/cpu/interrupts.c
@@ -147,6 +147,11 @@ int cpu_init_interrupts(void)
return 0;
}
+void *x86_get_idt(void)
+{
+ return &idt_ptr;
+}
+
void __do_irq(int irq)
{
printf("Unhandled IRQ : %d\n", irq);
diff --git a/arch/x86/cpu/ivybridge/car.S b/arch/x86/cpu/ivybridge/car.S
index 9441666f5a..407e451adc 100644
--- a/arch/x86/cpu/ivybridge/car.S
+++ b/arch/x86/cpu/ivybridge/car.S
@@ -15,6 +15,7 @@
#include <asm/msr-index.h>
#include <asm/mtrr.h>
#include <asm/post.h>
+#include <asm/processor.h>
#include <asm/processor-flags.h>
#include <asm/arch/microcode.h>
diff --git a/arch/x86/cpu/ivybridge/cpu.c b/arch/x86/cpu/ivybridge/cpu.c
index 37f373148c..cce5923f0b 100644
--- a/arch/x86/cpu/ivybridge/cpu.c
+++ b/arch/x86/cpu/ivybridge/cpu.c
@@ -92,7 +92,7 @@ static int set_flex_ratio_to_tdp_nominal(void)
/* Issue warm reset, will be "CPU only" due to soft reset data */
outb(0x0, PORT_RESET);
- outb(0x6, PORT_RESET);
+ outb(SYS_RST | RST_CPU, PORT_RESET);
cpu_hlt();
/* Not reached */
@@ -286,8 +286,7 @@ int print_cpuinfo(void)
/* System is not happy after keyboard reset... */
debug("Issuing CF9 warm reset\n");
- outb(0x6, 0xcf9);
- cpu_hlt();
+ reset_cpu(0);
}
/* Early chipset init required before RAM init can work */
diff --git a/arch/x86/cpu/ivybridge/early_me.c b/arch/x86/cpu/ivybridge/early_me.c
index 356bbb4a38..711470f364 100644
--- a/arch/x86/cpu/ivybridge/early_me.c
+++ b/arch/x86/cpu/ivybridge/early_me.c
@@ -117,7 +117,6 @@ static inline void set_global_reset(int enable)
int intel_early_me_init_done(u8 status)
{
- u8 reset;
int count;
u32 mebase_l, mebase_h;
struct me_hfs hfs;
@@ -156,7 +155,6 @@ int intel_early_me_init_done(u8 status)
/* Check status after acknowledgement */
intel_early_me_status();
- reset = 0;
switch (hfs.ack_data) {
case ME_HFS_ACK_CONTINUE:
/* Continue to boot */
@@ -164,17 +162,17 @@ int intel_early_me_init_done(u8 status)
case ME_HFS_ACK_RESET:
/* Non-power cycle reset */
set_global_reset(0);
- reset = 0x06;
+ reset_cpu(0);
break;
case ME_HFS_ACK_PWR_CYCLE:
/* Power cycle reset */
set_global_reset(0);
- reset = 0x0e;
+ x86_full_reset();
break;
case ME_HFS_ACK_GBL_RESET:
/* Global reset */
set_global_reset(1);
- reset = 0x0e;
+ x86_full_reset();
break;
case ME_HFS_ACK_S3:
case ME_HFS_ACK_S4:
@@ -182,10 +180,5 @@ int intel_early_me_init_done(u8 status)
break;
}
- /* Perform the requested reset */
- if (reset) {
- outb(reset, 0xcf9);
- cpu_hlt();
- }
return -1;
}
diff --git a/arch/x86/cpu/ivybridge/model_206ax.c b/arch/x86/cpu/ivybridge/model_206ax.c
index 11dc625da9..8b08c40bcb 100644
--- a/arch/x86/cpu/ivybridge/model_206ax.c
+++ b/arch/x86/cpu/ivybridge/model_206ax.c
@@ -435,8 +435,8 @@ static int intel_cores_init(struct x86_cpu_priv *cpu)
debug("CPU: %u has core %u\n", cpu->apic_id, new_cpu->apic_id);
-#if CONFIG_SMP && CONFIG_MAX_CPUS > 1
- /* Start the new cpu */
+#if 0 && CONFIG_SMP && CONFIG_MAX_CPUS > 1
+ /* TODO(sjg@chromium.org): Start the new cpu */
if (!start_cpu(new_cpu)) {
/* Record the error in cpu? */
printk(BIOS_ERR, "CPU %u would not start!\n",
diff --git a/arch/x86/cpu/ivybridge/sdram.c b/arch/x86/cpu/ivybridge/sdram.c
index 9a6da37d09..af907c5b9b 100644
--- a/arch/x86/cpu/ivybridge/sdram.c
+++ b/arch/x86/cpu/ivybridge/sdram.c
@@ -393,8 +393,7 @@ int sdram_initialise(struct pei_data *pei_data)
/* If MRC data is not found we cannot continue S3 resume. */
if (pei_data->boot_mode == PEI_BOOT_RESUME && !pei_data->mrc_input) {
debug("Giving up in sdram_initialize: No MRC data\n");
- outb(0x6, PORT_RESET);
- cpu_hlt();
+ reset_cpu(0);
}
/* Pass console handler in pei_data */
diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c
new file mode 100644
index 0000000000..ac5753a1fd
--- /dev/null
+++ b/arch/x86/cpu/mp_init.c
@@ -0,0 +1,496 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Based on code from the coreboot file of the same name
+ */
+
+#include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <errno.h>
+#include <malloc.h>
+#include <asm/atomic.h>
+#include <asm/cpu.h>
+#include <asm/interrupt.h>
+#include <asm/lapic.h>
+#include <asm/mp.h>
+#include <asm/mtrr.h>
+#include <asm/sipi.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#include <linux/linkage.h>
+
+/* This also needs to match the sipi.S assembly code for saved MSR encoding */
+struct saved_msr {
+ uint32_t index;
+ uint32_t lo;
+ uint32_t hi;
+} __packed;
+
+
+struct mp_flight_plan {
+ int num_records;
+ struct mp_flight_record *records;
+};
+
+static struct mp_flight_plan mp_info;
+
+struct cpu_map {
+ struct udevice *dev;
+ int apic_id;
+ int err_code;
+};
+
+static inline void barrier_wait(atomic_t *b)
+{
+ while (atomic_read(b) == 0)
+ asm("pause");
+ mfence();
+}
+
+static inline void release_barrier(atomic_t *b)
+{
+ mfence();
+ atomic_set(b, 1);
+}
+
+/* Returns 1 if timeout waiting for APs. 0 if target APs found */
+static int wait_for_aps(atomic_t *val, int target, int total_delay,
+ int delay_step)
+{
+ int timeout = 0;
+ int delayed = 0;
+
+ while (atomic_read(val) != target) {
+ udelay(delay_step);
+ delayed += delay_step;
+ if (delayed >= total_delay) {
+ timeout = 1;
+ break;
+ }
+ }
+
+ return timeout;
+}
+
+static void ap_do_flight_plan(struct udevice *cpu)
+{
+ int i;
+
+ for (i = 0; i < mp_info.num_records; i++) {
+ struct mp_flight_record *rec = &mp_info.records[i];
+
+ atomic_inc(&rec->cpus_entered);
+ barrier_wait(&rec->barrier);
+
+ if (rec->ap_call != NULL)
+ rec->ap_call(cpu, rec->ap_arg);
+ }
+}
+
+static int find_cpu_by_apid_id(int apic_id, struct udevice **devp)
+{
+ struct udevice *dev;
+
+ *devp = NULL;
+ for (uclass_find_first_device(UCLASS_CPU, &dev);
+ dev;
+ uclass_find_next_device(&dev)) {
+ struct cpu_platdata *plat = dev_get_parent_platdata(dev);
+
+ if (plat->cpu_id == apic_id) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+/*
+ * By the time APs call ap_init() caching has been setup, and microcode has
+ * been loaded
+ */
+static void ap_init(unsigned int cpu_index)
+{
+ struct udevice *dev;
+ int apic_id;
+ int ret;
+
+ /* Ensure the local apic is enabled */
+ enable_lapic();
+
+ apic_id = lapicid();
+ ret = find_cpu_by_apid_id(apic_id, &dev);
+ if (ret) {
+ debug("Unknown CPU apic_id %x\n", apic_id);
+ goto done;
+ }
+
+ debug("AP: slot %d apic_id %x, dev %s\n", cpu_index, apic_id,
+ dev ? dev->name : "(apic_id not found)");
+
+ /* Walk the flight plan */
+ ap_do_flight_plan(dev);
+
+ /* Park the AP */
+ debug("parking\n");
+done:
+ stop_this_cpu();
+}
+
+static const unsigned int fixed_mtrrs[NUM_FIXED_MTRRS] = {
+ MTRR_FIX_64K_00000_MSR, MTRR_FIX_16K_80000_MSR, MTRR_FIX_16K_A0000_MSR,
+ MTRR_FIX_4K_C0000_MSR, MTRR_FIX_4K_C8000_MSR, MTRR_FIX_4K_D0000_MSR,
+ MTRR_FIX_4K_D8000_MSR, MTRR_FIX_4K_E0000_MSR, MTRR_FIX_4K_E8000_MSR,
+ MTRR_FIX_4K_F0000_MSR, MTRR_FIX_4K_F8000_MSR,
+};
+
+static inline struct saved_msr *save_msr(int index, struct saved_msr *entry)
+{
+ msr_t msr;
+
+ msr = msr_read(index);
+ entry->index = index;
+ entry->lo = msr.lo;
+ entry->hi = msr.hi;
+
+ /* Return the next entry */
+ entry++;
+ return entry;
+}
+
+static int save_bsp_msrs(char *start, int size)
+{
+ int msr_count;
+ int num_var_mtrrs;
+ struct saved_msr *msr_entry;
+ int i;
+ msr_t msr;
+
+ /* Determine number of MTRRs need to be saved */
+ msr = msr_read(MTRR_CAP_MSR);
+ num_var_mtrrs = msr.lo & 0xff;
+
+ /* 2 * num_var_mtrrs for base and mask. +1 for IA32_MTRR_DEF_TYPE */
+ msr_count = 2 * num_var_mtrrs + NUM_FIXED_MTRRS + 1;
+
+ if ((msr_count * sizeof(struct saved_msr)) > size) {
+ printf("Cannot mirror all %d msrs.\n", msr_count);
+ return -ENOSPC;
+ }
+
+ msr_entry = (void *)start;
+ for (i = 0; i < NUM_FIXED_MTRRS; i++)
+ msr_entry = save_msr(fixed_mtrrs[i], msr_entry);
+
+ for (i = 0; i < num_var_mtrrs; i++) {
+ msr_entry = save_msr(MTRR_PHYS_BASE_MSR(i), msr_entry);
+ msr_entry = save_msr(MTRR_PHYS_MASK_MSR(i), msr_entry);
+ }
+
+ msr_entry = save_msr(MTRR_DEF_TYPE_MSR, msr_entry);
+
+ return msr_count;
+}
+
+static int load_sipi_vector(atomic_t **ap_countp)
+{
+ struct sipi_params_16bit *params16;
+ struct sipi_params *params;
+ static char msr_save[512];
+ char *stack;
+ ulong addr;
+ int code_len;
+ int size;
+ int ret;
+
+ /* Copy in the code */
+ code_len = ap_start16_code_end - ap_start16;
+ debug("Copying SIPI code to %x: %d bytes\n", AP_DEFAULT_BASE,
+ code_len);
+ memcpy((void *)AP_DEFAULT_BASE, ap_start16, code_len);
+
+ addr = AP_DEFAULT_BASE + (ulong)sipi_params_16bit - (ulong)ap_start16;
+ params16 = (struct sipi_params_16bit *)addr;
+ params16->ap_start = (uint32_t)ap_start;
+ params16->gdt = (uint32_t)gd->arch.gdt;
+ params16->gdt_limit = X86_GDT_SIZE - 1;
+ debug("gdt = %x, gdt_limit = %x\n", params16->gdt, params16->gdt_limit);
+
+ params = (struct sipi_params *)sipi_params;
+ debug("SIPI 32-bit params at %p\n", params);
+ params->idt_ptr = (uint32_t)x86_get_idt();
+
+ params->stack_size = CONFIG_AP_STACK_SIZE;
+ size = params->stack_size * CONFIG_MAX_CPUS;
+ stack = memalign(size, 4096);
+ if (!stack)
+ return -ENOMEM;
+ params->stack_top = (u32)(stack + size);
+
+ params->microcode_ptr = 0;
+ params->msr_table_ptr = (u32)msr_save;
+ ret = save_bsp_msrs(msr_save, sizeof(msr_save));
+ if (ret < 0)
+ return ret;
+ params->msr_count = ret;
+
+ params->c_handler = (uint32_t)&ap_init;
+
+ *ap_countp = &params->ap_count;
+ atomic_set(*ap_countp, 0);
+ debug("SIPI vector is ready\n");
+
+ return 0;
+}
+
+static int check_cpu_devices(int expected_cpus)
+{
+ int i;
+
+ for (i = 0; i < expected_cpus; i++) {
+ struct udevice *dev;
+ int ret;
+
+ ret = uclass_find_device(UCLASS_CPU, i, &dev);
+ if (ret) {
+ debug("Cannot find CPU %d in device tree\n", i);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* Returns 1 for timeout. 0 on success */
+static int apic_wait_timeout(int total_delay, int delay_step)
+{
+ int total = 0;
+ int timeout = 0;
+
+ while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY) {
+ udelay(delay_step);
+ total += delay_step;
+ if (total >= total_delay) {
+ timeout = 1;
+ break;
+ }
+ }
+
+ return timeout;
+}
+
+static int start_aps(int ap_count, atomic_t *num_aps)
+{
+ int sipi_vector;
+ /* Max location is 4KiB below 1MiB */
+ const int max_vector_loc = ((1 << 20) - (1 << 12)) >> 12;
+
+ if (ap_count == 0)
+ return 0;
+
+ /* The vector is sent as a 4k aligned address in one byte */
+ sipi_vector = AP_DEFAULT_BASE >> 12;
+
+ if (sipi_vector > max_vector_loc) {
+ printf("SIPI vector too large! 0x%08x\n",
+ sipi_vector);
+ return -1;
+ }
+
+ debug("Attempting to start %d APs\n", ap_count);
+
+ if ((lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY)) {
+ debug("Waiting for ICR not to be busy...");
+ if (apic_wait_timeout(1000, 50)) {
+ debug("timed out. Aborting.\n");
+ return -1;
+ } else {
+ debug("done.\n");
+ }
+ }
+
+ /* Send INIT IPI to all but self */
+ lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0));
+ lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT |
+ LAPIC_DM_INIT);
+ debug("Waiting for 10ms after sending INIT.\n");
+ mdelay(10);
+
+ /* Send 1st SIPI */
+ if ((lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY)) {
+ debug("Waiting for ICR not to be busy...");
+ if (apic_wait_timeout(1000, 50)) {
+ debug("timed out. Aborting.\n");
+ return -1;
+ } else {
+ debug("done.\n");
+ }
+ }
+
+ lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0));
+ lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT |
+ LAPIC_DM_STARTUP | sipi_vector);
+ debug("Waiting for 1st SIPI to complete...");
+ if (apic_wait_timeout(10000, 50)) {
+ debug("timed out.\n");
+ return -1;
+ } else {
+ debug("done.\n");
+ }
+
+ /* Wait for CPUs to check in up to 200 us */
+ wait_for_aps(num_aps, ap_count, 200, 15);
+
+ /* Send 2nd SIPI */
+ if ((lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY)) {
+ debug("Waiting for ICR not to be busy...");
+ if (apic_wait_timeout(1000, 50)) {
+ debug("timed out. Aborting.\n");
+ return -1;
+ } else {
+ debug("done.\n");
+ }
+ }
+
+ lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0));
+ lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT |
+ LAPIC_DM_STARTUP | sipi_vector);
+ debug("Waiting for 2nd SIPI to complete...");
+ if (apic_wait_timeout(10000, 50)) {
+ debug("timed out.\n");
+ return -1;
+ } else {
+ debug("done.\n");
+ }
+
+ /* Wait for CPUs to check in */
+ if (wait_for_aps(num_aps, ap_count, 10000, 50)) {
+ debug("Not all APs checked in: %d/%d.\n",
+ atomic_read(num_aps), ap_count);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int bsp_do_flight_plan(struct udevice *cpu, struct mp_params *mp_params)
+{
+ int i;
+ int ret = 0;
+ const int timeout_us = 100000;
+ const int step_us = 100;
+ int num_aps = mp_params->num_cpus - 1;
+
+ for (i = 0; i < mp_params->num_records; i++) {
+ struct mp_flight_record *rec = &mp_params->flight_plan[i];
+
+ /* Wait for APs if the record is not released */
+ if (atomic_read(&rec->barrier) == 0) {
+ /* Wait for the APs to check in */
+ if (wait_for_aps(&rec->cpus_entered, num_aps,
+ timeout_us, step_us)) {
+ debug("MP record %d timeout.\n", i);
+ ret = -1;
+ }
+ }
+
+ if (rec->bsp_call != NULL)
+ rec->bsp_call(cpu, rec->bsp_arg);
+
+ release_barrier(&rec->barrier);
+ }
+ return ret;
+}
+
+static int init_bsp(struct udevice **devp)
+{
+ char processor_name[CPU_MAX_NAME_LEN];
+ int apic_id;
+ int ret;
+
+ cpu_get_name(processor_name);
+ debug("CPU: %s.\n", processor_name);
+
+ enable_lapic();
+
+ apic_id = lapicid();
+ ret = find_cpu_by_apid_id(apic_id, devp);
+ if (ret) {
+ printf("Cannot find boot CPU, APIC ID %d\n", apic_id);
+ return ret;
+ }
+
+ return 0;
+}
+
+int mp_init(struct mp_params *p)
+{
+ int num_aps;
+ atomic_t *ap_count;
+ struct udevice *cpu;
+ int ret;
+
+ /* This will cause the CPUs devices to be bound */
+ struct uclass *uc;
+ ret = uclass_get(UCLASS_CPU, &uc);
+ if (ret)
+ return ret;
+
+ ret = init_bsp(&cpu);
+ if (ret) {
+ debug("Cannot init boot CPU: err=%d\n", ret);
+ return ret;
+ }
+
+ if (p == NULL || p->flight_plan == NULL || p->num_records < 1) {
+ printf("Invalid MP parameters\n");
+ return -1;
+ }
+
+ ret = check_cpu_devices(p->num_cpus);
+ if (ret)
+ debug("Warning: Device tree does not describe all CPUs. Extra ones will not be started correctly\n");
+
+ /* Copy needed parameters so that APs have a reference to the plan */
+ mp_info.num_records = p->num_records;
+ mp_info.records = p->flight_plan;
+
+ /* Load the SIPI vector */
+ ret = load_sipi_vector(&ap_count);
+ if (ap_count == NULL)
+ return -1;
+
+ /*
+ * Make sure SIPI data hits RAM so the APs that come up will see
+ * the startup code even if the caches are disabled
+ */
+ wbinvd();
+
+ /* Start the APs providing number of APs and the cpus_entered field */
+ num_aps = p->num_cpus - 1;
+ ret = start_aps(num_aps, ap_count);
+ if (ret) {
+ mdelay(1000);
+ debug("%d/%d eventually checked in?\n", atomic_read(ap_count),
+ num_aps);
+ return ret;
+ }
+
+ /* Walk the flight plan for the BSP */
+ ret = bsp_do_flight_plan(cpu, p);
+ if (ret) {
+ debug("CPU init failed: err=%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int mp_init_cpu(struct udevice *cpu, void *unused)
+{
+ return device_probe(cpu);
+}
diff --git a/arch/x86/cpu/pci.c b/arch/x86/cpu/pci.c
index e23b233961..c209f15ec4 100644
--- a/arch/x86/cpu/pci.c
+++ b/arch/x86/cpu/pci.c
@@ -151,3 +151,24 @@ int pci_x86_write_config(struct udevice *bus, pci_dev_t bdf, uint offset,
return 0;
}
+
+void pci_assign_irqs(int bus, int device, int func, u8 irq[4])
+{
+ pci_dev_t bdf;
+ u8 pin, line;
+
+ bdf = PCI_BDF(bus, device, func);
+
+ pin = x86_pci_read_config8(bdf, PCI_INTERRUPT_PIN);
+
+ /* PCI spec says all values except 1..4 are reserved */
+ if ((pin < 1) || (pin > 4))
+ return;
+
+ line = irq[pin - 1];
+
+ debug("Assigning IRQ %d to PCI device %d.%x.%d (INT%c)\n",
+ line, bus, device, func, 'A' + pin - 1);
+
+ x86_pci_write_config8(bdf, PCI_INTERRUPT_LINE, line);
+}
diff --git a/arch/x86/cpu/quark/quark.c b/arch/x86/cpu/quark/quark.c
index e4b19c2759..e78a271c50 100644
--- a/arch/x86/cpu/quark/quark.c
+++ b/arch/x86/cpu/quark/quark.c
@@ -72,6 +72,15 @@ static void quark_setup_bars(void)
CONFIG_PCIE_ECAM_BASE | MEM_BAR_EN);
}
+static void quark_enable_legacy_seg(void)
+{
+ u32 hmisc2;
+
+ hmisc2 = msg_port_read(MSG_PORT_HOST_BRIDGE, HMISC2);
+ hmisc2 |= (HMISC2_SEGE | HMISC2_SEGF | HMISC2_SEGAB);
+ msg_port_write(MSG_PORT_HOST_BRIDGE, HMISC2, hmisc2);
+}
+
int arch_cpu_init(void)
{
struct pci_controller *hose;
@@ -96,6 +105,9 @@ int arch_cpu_init(void)
*/
quark_setup_bars();
+ /* Turn on legacy segments (A/B/E/F) decode to system RAM */
+ quark_enable_legacy_seg();
+
unprotect_spi_flash();
return 0;
@@ -110,7 +122,7 @@ int print_cpuinfo(void)
void reset_cpu(ulong addr)
{
/* cold reset */
- outb(0x08, PORT_RESET);
+ x86_full_reset();
}
int cpu_mmc_init(bd_t *bis)
diff --git a/arch/x86/cpu/queensbay/Makefile b/arch/x86/cpu/queensbay/Makefile
index d8761fdfbd..4599a4896d 100644
--- a/arch/x86/cpu/queensbay/Makefile
+++ b/arch/x86/cpu/queensbay/Makefile
@@ -5,5 +5,5 @@
#
obj-y += fsp_configs.o
-obj-y += tnc.o topcliff.o
+obj-y += irq.o tnc.o topcliff.o
obj-$(CONFIG_PCI) += tnc_pci.o
diff --git a/arch/x86/cpu/queensbay/irq.c b/arch/x86/cpu/queensbay/irq.c
new file mode 100644
index 0000000000..faf951544f
--- /dev/null
+++ b/arch/x86/cpu/queensbay/irq.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <asm/post.h>
+#include <asm/processor.h>
+#include <asm/pirq_routing.h>
+#include <asm/arch/device.h>
+#include <asm/arch/tnc.h>
+#include <asm/arch/irq.h>
+
+static struct irq_routing_table *pirq_routing_table;
+
+bool pirq_check_irq_routed(int link, u8 irq)
+{
+ u8 pirq;
+
+ pirq = x86_pci_read_config8(TNC_LPC, LINK_N2V(link));
+ pirq &= 0xf;
+
+ /* IRQ# 0/1/2/8/13 are reserved */
+ if (pirq < 3 || pirq == 8 || pirq == 13)
+ return false;
+
+ return pirq == irq ? true : false;
+}
+
+int pirq_translate_link(int link)
+{
+ return LINK_V2N(link);
+}
+
+void pirq_assign_irq(int link, u8 irq)
+{
+ /* IRQ# 0/1/2/8/13 are reserved */
+ if (irq < 3 || irq == 8 || irq == 13)
+ return;
+
+ x86_pci_write_config8(TNC_LPC, LINK_N2V(link), irq);
+}
+
+static inline void fill_irq_info(struct irq_info **slotp, int *entries, u8 bus,
+ u8 device, u8 func, u8 pin, u8 pirq)
+{
+ struct irq_info *slot = *slotp;
+
+ slot->bus = bus;
+ slot->devfn = (device << 3) | func;
+ slot->irq[pin - 1].link = LINK_N2V(pirq);
+ slot->irq[pin - 1].bitmap = PIRQ_BITMAP;
+ (*entries)++;
+ (*slotp)++;
+}
+
+/* PCIe port downstream INTx swizzle */
+static inline u8 pin_swizzle(u8 pin, int port)
+{
+ return (pin + port) % 4;
+}
+
+__weak int board_fill_irq_info(struct irq_info *slot)
+{
+ return 0;
+}
+
+static int create_pirq_routing_table(void)
+{
+ struct irq_routing_table *rt;
+ struct irq_info *slot;
+ int irq_entries = 0;
+ pci_dev_t tcf_bdf;
+ u8 tcf_bus, bus;
+ int i;
+
+ rt = malloc(sizeof(struct irq_routing_table));
+ if (!rt)
+ return -ENOMEM;
+ memset((char *)rt, 0, sizeof(struct irq_routing_table));
+
+ /* Populate the PIRQ table fields */
+ rt->signature = PIRQ_SIGNATURE;
+ rt->version = PIRQ_VERSION;
+ rt->rtr_bus = 0;
+ rt->rtr_devfn = (TNC_LPC_DEV << 3) | TNC_LPC_FUNC;
+ rt->rtr_vendor = PCI_VENDOR_ID_INTEL;
+ rt->rtr_device = PCI_DEVICE_ID_INTEL_ICH7_31;
+
+ slot = rt->slots;
+
+ /*
+ * Now fill in the irq_info entries in the PIRQ table
+ *
+ * We start from internal TunnelCreek PCI devices first, then
+ * followed by all the 4 PCIe ports downstream devices, including
+ * the Queensbay platform Topcliff chipset devices.
+ */
+ fill_irq_info(&slot, &irq_entries, 0, TNC_IGD_DEV,
+ TNC_IGD_FUNC, INTA, PIRQE);
+ fill_irq_info(&slot, &irq_entries, 0, TNC_SDVO_DEV,
+ TNC_SDVO_FUNC, INTA, PIRQF);
+ fill_irq_info(&slot, &irq_entries, 0, TNC_HDA_DEV,
+ TNC_HDA_FUNC, INTA, PIRQG);
+ fill_irq_info(&slot, &irq_entries, 0, TNC_PCIE0_DEV,
+ TNC_PCIE0_FUNC, INTA, PIRQE);
+ fill_irq_info(&slot, &irq_entries, 0, TNC_PCIE1_DEV,
+ TNC_PCIE1_FUNC, INTA, PIRQF);
+ fill_irq_info(&slot, &irq_entries, 0, TNC_PCIE2_DEV,
+ TNC_PCIE2_FUNC, INTA, PIRQG);
+ fill_irq_info(&slot, &irq_entries, 0, TNC_PCIE3_DEV,
+ TNC_PCIE3_FUNC, INTA, PIRQH);
+
+ /* Check which PCIe port the Topcliff chipset is connected to */
+ tcf_bdf = pci_find_device(PCI_VENDOR_ID_INTEL, 0x8800, 0);
+ tcf_bus = PCI_BUS(tcf_bdf);
+ for (i = 0; i < 4; i++) {
+ bus = x86_pci_read_config8(PCI_BDF(0, TNC_PCIE0_DEV + i, 0),
+ PCI_SECONDARY_BUS);
+ if (bus == tcf_bus)
+ break;
+ }
+
+ /* Fill in the Topcliff chipset devices' irq info */
+ if (i < 4) {
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_PCIE_PORT_DEV,
+ TCF_PCIE_PORT_FUNC, INTA, pin_swizzle(PIRQA, i));
+
+ tcf_bus++;
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_0,
+ TCF_GBE_FUNC, INTA, pin_swizzle(PIRQA, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_0,
+ TCF_GPIO_FUNC, INTA, pin_swizzle(PIRQA, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2,
+ TCF_USB1_OHCI0_FUNC, INTB, pin_swizzle(PIRQB, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2,
+ TCF_USB1_OHCI1_FUNC, INTB, pin_swizzle(PIRQB, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2,
+ TCF_USB1_OHCI2_FUNC, INTB, pin_swizzle(PIRQB, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2,
+ TCF_USB1_EHCI_FUNC, INTB, pin_swizzle(PIRQB, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2,
+ TCF_USB_DEVICE_FUNC, INTB, pin_swizzle(PIRQB, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_4,
+ TCF_SDIO0_FUNC, INTC, pin_swizzle(PIRQC, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_4,
+ TCF_SDIO1_FUNC, INTC, pin_swizzle(PIRQC, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_6,
+ TCF_SATA_FUNC, INTD, pin_swizzle(PIRQD, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_8,
+ TCF_USB2_OHCI0_FUNC, INTA, pin_swizzle(PIRQA, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_8,
+ TCF_USB2_OHCI1_FUNC, INTA, pin_swizzle(PIRQA, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_8,
+ TCF_USB2_OHCI2_FUNC, INTA, pin_swizzle(PIRQA, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_8,
+ TCF_USB2_EHCI_FUNC, INTA, pin_swizzle(PIRQA, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10,
+ TCF_DMA1_FUNC, INTB, pin_swizzle(PIRQB, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10,
+ TCF_UART0_FUNC, INTB, pin_swizzle(PIRQB, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10,
+ TCF_UART1_FUNC, INTB, pin_swizzle(PIRQB, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10,
+ TCF_UART2_FUNC, INTB, pin_swizzle(PIRQB, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10,
+ TCF_UART3_FUNC, INTB, pin_swizzle(PIRQB, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12,
+ TCF_DMA2_FUNC, INTC, pin_swizzle(PIRQC, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12,
+ TCF_SPI_FUNC, INTC, pin_swizzle(PIRQC, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12,
+ TCF_I2C_FUNC, INTC, pin_swizzle(PIRQC, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12,
+ TCF_CAN_FUNC, INTC, pin_swizzle(PIRQC, i));
+ fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12,
+ TCF_1588_FUNC, INTC, pin_swizzle(PIRQC, i));
+ }
+
+ /* Call board-specific routine to fill in add-in card's irq info */
+ irq_entries += board_fill_irq_info(slot);
+
+ rt->size = irq_entries * sizeof(struct irq_info) + 32;
+
+ pirq_routing_table = rt;
+
+ return 0;
+}
+
+void pirq_init(void)
+{
+ struct tnc_rcba *rcba;
+ u32 base;
+
+ base = x86_pci_read_config32(TNC_LPC, LPC_RCBA);
+ base &= ~MEM_BAR_EN;
+ rcba = (struct tnc_rcba *)base;
+
+ /* Make sure all internal PCI devices are using INTA */
+ writel(INTA, &rcba->d02ip);
+ writel(INTA, &rcba->d03ip);
+ writel(INTA, &rcba->d27ip);
+ writel(INTA, &rcba->d31ip);
+ writel(INTA, &rcba->d23ip);
+ writel(INTA, &rcba->d24ip);
+ writel(INTA, &rcba->d25ip);
+ writel(INTA, &rcba->d26ip);
+
+ /*
+ * Route TunnelCreek PCI device interrupt pin to PIRQ
+ *
+ * Since PCIe downstream ports received INTx are routed to PIRQ
+ * A/B/C/D directly and not configurable, we route internal PCI
+ * device's INTx to PIRQ E/F/G/H.
+ */
+ writew(PIRQE, &rcba->d02ir);
+ writew(PIRQF, &rcba->d03ir);
+ writew(PIRQG, &rcba->d27ir);
+ writew(PIRQH, &rcba->d31ir);
+ writew(PIRQE, &rcba->d23ir);
+ writew(PIRQF, &rcba->d24ir);
+ writew(PIRQG, &rcba->d25ir);
+ writew(PIRQH, &rcba->d26ir);
+
+ if (create_pirq_routing_table()) {
+ debug("Failed to create pirq routing table\n");
+ } else {
+ /* Route PIRQ */
+ pirq_route_irqs(pirq_routing_table->slots,
+ get_irq_slot_count(pirq_routing_table));
+ }
+}
+
+u32 write_pirq_routing_table(u32 addr)
+{
+ return copy_pirq_routing_table(addr, pirq_routing_table);
+}
diff --git a/arch/x86/cpu/queensbay/tnc.c b/arch/x86/cpu/queensbay/tnc.c
index b7236e7b60..b46a7e996f 100644
--- a/arch/x86/cpu/queensbay/tnc.c
+++ b/arch/x86/cpu/queensbay/tnc.c
@@ -8,7 +8,8 @@
#include <asm/io.h>
#include <asm/pci.h>
#include <asm/post.h>
-#include <asm/arch/tnc.h>
+#include <asm/arch/device.h>
+#include <asm/arch/irq.h>
#include <asm/fsp/fsp_support.h>
#include <asm/processor.h>
@@ -16,9 +17,9 @@ static void unprotect_spi_flash(void)
{
u32 bc;
- bc = x86_pci_read_config32(PCH_LPC_DEV, 0xd8);
+ bc = x86_pci_read_config32(TNC_LPC, 0xd8);
bc |= 0x1; /* unprotect the flash */
- x86_pci_write_config32(PCH_LPC_DEV, 0xd8, bc);
+ x86_pci_write_config32(TNC_LPC, 0xd8, bc);
}
int arch_cpu_init(void)
@@ -43,3 +44,10 @@ int arch_cpu_init(void)
return 0;
}
+
+int arch_misc_init(void)
+{
+ pirq_init();
+
+ return 0;
+}
diff --git a/arch/x86/cpu/sipi_vector.S b/arch/x86/cpu/sipi_vector.S
new file mode 100644
index 0000000000..bcef12c6f1
--- /dev/null
+++ b/arch/x86/cpu/sipi_vector.S
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * Taken from coreboot file of the same name
+ */
+
+/*
+ * The SIPI vector is responsible for initializing the APs in the sytem. It
+ * loads microcode, sets up MSRs, and enables caching before calling into
+ * C code
+ */
+
+#include <asm/global_data.h>
+#include <asm/msr-index.h>
+#include <asm/processor.h>
+#include <asm/processor-flags.h>
+#include <asm/sipi.h>
+
+#define CODE_SEG (X86_GDT_ENTRY_32BIT_CS * X86_GDT_ENTRY_SIZE)
+#define DATA_SEG (X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE)
+
+/*
+ * First we have the 16-bit section. Every AP process starts here.
+ * The simple task is to load U-Boot's Global Descriptor Table (GDT) to allow
+ * U-Boot's 32-bit code to become visible, then jump to ap_start.
+ *
+ * Note that this code is copied to RAM below 1MB in mp_init.c, and runs from
+ * there, but the 32-bit code (ap_start and onwards) is part of U-Boot and
+ * is therefore relocated to the top of RAM with other U-Boot code. This
+ * means that for the 16-bit code we must write relocatable code, but for the
+ * rest, we can do what we like.
+ */
+.text
+.code16
+.globl ap_start16
+ap_start16:
+ cli
+ xorl %eax, %eax
+ movl %eax, %cr3 /* Invalidate TLB */
+
+ /* setup the data segment */
+ movw %cs, %ax
+ movw %ax, %ds
+
+ /* Use an address relative to the data segment for the GDT */
+ movl $gdtaddr, %ebx
+ subl $ap_start16, %ebx
+
+ data32 lgdt (%ebx)
+
+ movl %cr0, %eax
+ andl $(~(X86_CR0_PG | X86_CR0_AM | X86_CR0_WP | X86_CR0_NE | \
+ X86_CR0_TS | X86_CR0_EM | X86_CR0_MP)), %eax
+ orl $(X86_CR0_NW | X86_CR0_CD | X86_CR0_PE), %eax
+ movl %eax, %cr0
+
+ movl $ap_start_jmp, %eax
+ subl $ap_start16, %eax
+ movw %ax, %bp
+
+ /* Jump to ap_start within U-Boot */
+data32 cs ljmp *(%bp)
+
+ .align 4
+.globl sipi_params_16bit
+sipi_params_16bit:
+ /* 48-bit far pointer */
+ap_start_jmp:
+ .long 0 /* offset set to ap_start by U-Boot */
+ .word CODE_SEG /* segment */
+
+ .word 0 /* padding */
+gdtaddr:
+ .word 0 /* limit */
+ .long 0 /* table */
+ .word 0 /* unused */
+
+.globl ap_start16_code_end
+ap_start16_code_end:
+
+/*
+ * Set up the special 'fs' segment for global_data. Then jump to ap_continue
+ * to set up the AP.
+ */
+.globl ap_start
+ap_start:
+ .code32
+ movw $DATA_SEG, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ movw %ax, %gs
+
+ movw $(X86_GDT_ENTRY_32BIT_FS * X86_GDT_ENTRY_SIZE), %ax
+ movw %ax, %fs
+
+ /* Load the Interrupt descriptor table */
+ mov idt_ptr, %ebx
+ lidt (%ebx)
+
+ /* Obtain cpu number */
+ movl ap_count, %eax
+1:
+ movl %eax, %ecx
+ inc %ecx
+ lock cmpxchg %ecx, ap_count
+ jnz 1b
+
+ /* Setup stacks for each CPU */
+ movl stack_size, %eax
+ mul %ecx
+ movl stack_top, %edx
+ subl %eax, %edx
+ mov %edx, %esp
+ /* Save cpu number */
+ mov %ecx, %esi
+
+ /* Determine if one should check microcode versions */
+ mov microcode_ptr, %edi
+ test %edi, %edi
+ jz microcode_done /* Bypass if no microde exists */
+
+ /* Get the Microcode version */
+ mov $1, %eax
+ cpuid
+ mov $MSR_IA32_UCODE_REV, %ecx
+ rdmsr
+ /* If something already loaded skip loading again */
+ test %edx, %edx
+ jnz microcode_done
+
+ /* Determine if parallel microcode loading is allowed */
+ cmp $0xffffffff, microcode_lock
+ je load_microcode
+
+ /* Protect microcode loading */
+lock_microcode:
+ lock bts $0, microcode_lock
+ jc lock_microcode
+
+load_microcode:
+ /* Load new microcode */
+ mov $MSR_IA32_UCODE_WRITE, %ecx
+ xor %edx, %edx
+ mov %edi, %eax
+ /*
+ * The microcode pointer is passed in pointing to the header. Adjust
+ * pointer to reflect the payload (header size is 48 bytes)
+ */
+ add $UCODE_HEADER_LEN, %eax
+ pusha
+ wrmsr
+ popa
+
+ /* Unconditionally unlock microcode loading */
+ cmp $0xffffffff, microcode_lock
+ je microcode_done
+
+ xor %eax, %eax
+ mov %eax, microcode_lock
+
+microcode_done:
+ /*
+ * Load MSRs. Each entry in the table consists of:
+ * 0: index,
+ * 4: value[31:0]
+ * 8: value[63:32]
+ * See struct saved_msr in mp_init.c.
+ */
+ mov msr_table_ptr, %edi
+ mov msr_count, %ebx
+ test %ebx, %ebx
+ jz 1f
+load_msr:
+ mov (%edi), %ecx
+ mov 4(%edi), %eax
+ mov 8(%edi), %edx
+ wrmsr
+ add $12, %edi
+ dec %ebx
+ jnz load_msr
+
+1:
+ /* Enable caching */
+ mov %cr0, %eax
+ andl $(~(X86_CR0_CD | X86_CR0_NW)), %eax
+ mov %eax, %cr0
+
+ /* c_handler(cpu_num) */
+ movl %esi, %eax /* cpu_num */
+ mov c_handler, %eax
+ call *%eax
+
+ .align 4
+.globl sipi_params
+sipi_params:
+idt_ptr:
+ .long 0
+stack_top:
+ .long 0
+stack_size:
+ .long 0
+microcode_lock:
+ .long 0
+microcode_ptr:
+ .long 0
+msr_table_ptr:
+ .long 0
+msr_count:
+ .long 0
+c_handler:
+ .long 0
+ap_count:
+ .long 0
diff --git a/arch/x86/dts/chromebook_link.dts b/arch/x86/dts/chromebook_link.dts
index b450c3c55f..7c7034c7eb 100644
--- a/arch/x86/dts/chromebook_link.dts
+++ b/arch/x86/dts/chromebook_link.dts
@@ -181,7 +181,7 @@
pch {
reg = <0x0000f800 0 0 0 0>;
- compatible = "intel,bd82x6x";
+ compatible = "intel,bd82x6x", "intel,pch";
u-boot,dm-pre-reloc;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/x86/dts/crownbay.dts b/arch/x86/dts/crownbay.dts
index e81054ebc5..fbdeade047 100644
--- a/arch/x86/dts/crownbay.dts
+++ b/arch/x86/dts/crownbay.dts
@@ -13,6 +13,10 @@
model = "Intel Crown Bay";
compatible = "intel,crownbay", "intel,queensbay";
+ aliases {
+ spi0 = "/spi";
+ };
+
config {
silent_console = <0>;
};
@@ -46,7 +50,7 @@
spi {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "intel,ich7";
+ compatible = "intel,ich-spi";
spi-flash@0 {
reg = <0>;
compatible = "sst,25vf016b", "spi-flash";
diff --git a/arch/x86/dts/galileo.dts b/arch/x86/dts/galileo.dts
index 66af64abda..60dbc5f8a3 100644
--- a/arch/x86/dts/galileo.dts
+++ b/arch/x86/dts/galileo.dts
@@ -14,6 +14,10 @@
model = "Intel Galileo";
compatible = "intel,galileo", "intel,quark";
+ aliases {
+ spi0 = "/spi";
+ };
+
config {
silent_console = <0>;
};
diff --git a/arch/x86/dts/minnowmax.dts b/arch/x86/dts/minnowmax.dts
index 8f34369753..7103bc5077 100644
--- a/arch/x86/dts/minnowmax.dts
+++ b/arch/x86/dts/minnowmax.dts
@@ -15,23 +15,86 @@
aliases {
serial0 = &serial;
+ spi0 = "/spi";
};
config {
silent_console = <0>;
};
+ gpioa {
+ compatible = "intel,ich6-gpio";
+ u-boot,dm-pre-reloc;
+ reg = <0 0x20>;
+ bank-name = "A";
+ };
+
+ gpiob {
+ compatible = "intel,ich6-gpio";
+ u-boot,dm-pre-reloc;
+ reg = <0x20 0x20>;
+ bank-name = "B";
+ };
+
+ gpioc {
+ compatible = "intel,ich6-gpio";
+ u-boot,dm-pre-reloc;
+ reg = <0x40 0x20>;
+ bank-name = "C";
+ };
+
+ gpiod {
+ compatible = "intel,ich6-gpio";
+ u-boot,dm-pre-reloc;
+ reg = <0x60 0x20>;
+ bank-name = "D";
+ };
+
+ gpioe {
+ compatible = "intel,ich6-gpio";
+ u-boot,dm-pre-reloc;
+ reg = <0x80 0x20>;
+ bank-name = "E";
+ };
+
+ gpiof {
+ compatible = "intel,ich6-gpio";
+ u-boot,dm-pre-reloc;
+ reg = <0xA0 0x20>;
+ bank-name = "F";
+ };
+
chosen {
stdout-path = "/serial";
};
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "intel,baytrail-cpu";
+ reg = <0>;
+ intel,apic-id = <0>;
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "intel,baytrail-cpu";
+ reg = <1>;
+ intel,apic-id = <4>;
+ };
+
+ };
+
spi {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "intel,ich";
+ compatible = "intel,ich-spi";
spi-flash@0 {
reg = <0>;
- compatible = "sst,25vf016b", "spi-flash";
+ compatible = "stmicro,n25q064a", "spi-flash";
memory-map = <0xff800000 0x00800000>;
};
};
diff --git a/arch/x86/include/asm/arch-baytrail/gpio.h b/arch/x86/include/asm/arch-baytrail/gpio.h
index ab4e059131..4e8987ce5c 100644
--- a/arch/x86/include/asm/arch-baytrail/gpio.h
+++ b/arch/x86/include/asm/arch-baytrail/gpio.h
@@ -8,6 +8,6 @@
#define _X86_ARCH_GPIO_H_
/* Where in config space is the register that points to the GPIO registers? */
-#define PCI_CFG_GPIOBASE 0x44
+#define PCI_CFG_GPIOBASE 0x48
#endif /* _X86_ARCH_GPIO_H_ */
diff --git a/arch/x86/include/asm/arch-ivybridge/microcode.h b/arch/x86/include/asm/arch-ivybridge/microcode.h
index b868283761..67f32cc38f 100644
--- a/arch/x86/include/asm/arch-ivybridge/microcode.h
+++ b/arch/x86/include/asm/arch-ivybridge/microcode.h
@@ -7,9 +7,6 @@
#ifndef __ASM_ARCH_MICROCODE_H
#define __ASM_ARCH_MICROCODE_H
-/* Length of the public header on Intel microcode blobs */
-#define UCODE_HEADER_LEN 0x30
-
#ifndef __ASSEMBLY__
/**
diff --git a/arch/x86/include/asm/arch-ivybridge/model_206ax.h b/arch/x86/include/asm/arch-ivybridge/model_206ax.h
index 7b4f2e790b..d2f9006093 100644
--- a/arch/x86/include/asm/arch-ivybridge/model_206ax.h
+++ b/arch/x86/include/asm/arch-ivybridge/model_206ax.h
@@ -37,7 +37,6 @@
#define MSR_MISC_PWR_MGMT 0x1aa
#define MISC_PWR_MGMT_EIST_HW_DIS (1 << 0)
#define MSR_TURBO_RATIO_LIMIT 0x1ad
-#define MSR_POWER_CTL 0x1fc
#define MSR_PKGC3_IRTL 0x60a
#define MSR_PKGC6_IRTL 0x60b
@@ -63,7 +62,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_UNIT 0x606
#define MSR_PKG_POWER_SKU 0x614
#define IVB_CONFIG_TDP_MIN_CPUID 0x306a2
diff --git a/arch/x86/include/asm/arch-quark/quark.h b/arch/x86/include/asm/arch-quark/quark.h
index ceb583e3f0..6dd02fd31e 100644
--- a/arch/x86/include/asm/arch-quark/quark.h
+++ b/arch/x86/include/asm/arch-quark/quark.h
@@ -21,6 +21,13 @@
/* Port 0x03: Host Bridge Message Port Registers */
+/* Host Miscellaneous Controls 2 */
+#define HMISC2 0x03
+
+#define HMISC2_SEGE 0x00000002
+#define HMISC2_SEGF 0x00000004
+#define HMISC2_SEGAB 0x00000010
+
/* Host Memory I/O Boundary */
#define HM_BOUND 0x08
diff --git a/arch/x86/include/asm/arch-queensbay/device.h b/arch/x86/include/asm/arch-queensbay/device.h
new file mode 100644
index 0000000000..953b48f15c
--- /dev/null
+++ b/arch/x86/include/asm/arch-queensbay/device.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _QUEENSBAY_DEVICE_H_
+#define _QUEENSBAY_DEVICE_H_
+
+#include <pci.h>
+
+/* TunnelCreek PCI Devices */
+#define TNC_HOST_BRIDGE_DEV 0
+#define TNC_HOST_BRIDGE_FUNC 0
+#define TNC_IGD_DEV 2
+#define TNC_IGD_FUNC 0
+#define TNC_SDVO_DEV 3
+#define TNC_SDVO_FUNC 0
+#define TNC_PCIE0_DEV 23
+#define TNC_PCIE0_FUNC 0
+#define TNC_PCIE1_DEV 24
+#define TNC_PCIE1_FUNC 0
+#define TNC_PCIE2_DEV 25
+#define TNC_PCIE2_FUNC 0
+#define TNC_PCIE3_DEV 26
+#define TNC_PCIE3_FUNC 0
+#define TNC_HDA_DEV 27
+#define TNC_HDA_FUNC 0
+#define TNC_LPC_DEV 31
+#define TNC_LPC_FUNC 0
+
+#define TNC_HOST_BRIDGE \
+ PCI_BDF(0, TNC_HOST_BRIDGE_DEV, TNC_HOST_BRIDGE_FUNC)
+#define TNC_IGD \
+ PCI_BDF(0, TNC_IGD_DEV, TNC_IGD_FUNC)
+#define TNC_SDVO \
+ PCI_BDF(0, TNC_SDVO_DEV, TNC_SDVO_FUNC)
+#define TNC_PCIE0 \
+ PCI_BDF(0, TNC_PCIE0_DEV, TNC_PCIE0_FUNC)
+#define TNC_PCIE1 \
+ PCI_BDF(0, TNC_PCIE1_DEV, TNC_PCIE1_FUNC)
+#define TNC_PCIE2 \
+ PCI_BDF(0, TNC_PCIE2_DEV, TNC_PCIE2_FUNC)
+#define TNC_PCIE3 \
+ PCI_BDF(0, TNC_PCIE3_DEV, TNC_PCIE3_FUNC)
+#define TNC_HDA \
+ PCI_BDF(0, TNC_HDA_DEV, TNC_HDA_FUNC)
+#define TNC_LPC \
+ PCI_BDF(0, TNC_LPC_DEV, TNC_LPC_FUNC)
+
+/* Topcliff IOH PCI Devices */
+#define TCF_PCIE_PORT_DEV 0
+#define TCF_PCIE_PORT_FUNC 0
+
+#define TCF_DEV_0 0
+#define TCF_PKT_HUB_FUNC 0
+#define TCF_GBE_FUNC 1
+#define TCF_GPIO_FUNC 2
+
+#define TCF_DEV_2 2
+#define TCF_USB1_OHCI0_FUNC 0
+#define TCF_USB1_OHCI1_FUNC 1
+#define TCF_USB1_OHCI2_FUNC 2
+#define TCF_USB1_EHCI_FUNC 3
+#define TCF_USB_DEVICE_FUNC 4
+
+#define TCF_DEV_4 4
+#define TCF_SDIO0_FUNC 0
+#define TCF_SDIO1_FUNC 1
+
+#define TCF_DEV_6 6
+#define TCF_SATA_FUNC 0
+
+#define TCF_DEV_8 8
+#define TCF_USB2_OHCI0_FUNC 0
+#define TCF_USB2_OHCI1_FUNC 1
+#define TCF_USB2_OHCI2_FUNC 2
+#define TCF_USB2_EHCI_FUNC 3
+
+#define TCF_DEV_10 10
+#define TCF_DMA1_FUNC 0
+#define TCF_UART0_FUNC 1
+#define TCF_UART1_FUNC 2
+#define TCF_UART2_FUNC 3
+#define TCF_UART3_FUNC 4
+
+#define TCF_DEV_12 12
+#define TCF_DMA2_FUNC 0
+#define TCF_SPI_FUNC 1
+#define TCF_I2C_FUNC 2
+#define TCF_CAN_FUNC 3
+#define TCF_1588_FUNC 4
+
+#endif /* _QUEENSBAY_DEVICE_H_ */
diff --git a/arch/x86/include/asm/arch-queensbay/irq.h b/arch/x86/include/asm/arch-queensbay/irq.h
new file mode 100644
index 0000000000..e7f861623e
--- /dev/null
+++ b/arch/x86/include/asm/arch-queensbay/irq.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _ARCH_IRQ_H_
+#define _ARCH_IRQ_H_
+
+enum pci_int_pin {
+ INTX,
+ INTA,
+ INTB,
+ INTC,
+ INTD
+};
+
+enum pirq_pin {
+ PIRQA,
+ PIRQB,
+ PIRQC,
+ PIRQD,
+ PIRQE,
+ PIRQF,
+ PIRQG,
+ PIRQH
+};
+
+/* PIRQ link number and value conversion */
+#define LINK_V2N(link) (link - 0x60)
+#define LINK_N2V(link) (link + 0x60)
+
+#define PIRQ_BITMAP 0xdee0
+
+struct irq_info;
+
+/**
+ * board_fill_irq_info() - Board-specific irq_info fill routine
+ *
+ * This fills the irq_info table for any board-specific add-in cards.
+ *
+ * @slot: pointer to the struct irq_info that is to be filled in
+ * @return: number of entries were written to the struct irq_info
+ */
+int board_fill_irq_info(struct irq_info *slot);
+
+/**
+ * pirq_init() - Initialize platform PIRQ routing
+ *
+ * This initializes the PIRQ routing on the platform and configures all PCI
+ * devices' interrupt line register to a working IRQ number on the 8259 PIC.
+ */
+void pirq_init(void);
+
+#endif /* _ARCH_IRQ_H_ */
diff --git a/arch/x86/include/asm/arch-queensbay/tnc.h b/arch/x86/include/asm/arch-queensbay/tnc.h
index 67c5e0586c..ad9a6c4892 100644
--- a/arch/x86/include/asm/arch-queensbay/tnc.h
+++ b/arch/x86/include/asm/arch-queensbay/tnc.h
@@ -7,9 +7,43 @@
#ifndef _X86_ARCH_TNC_H_
#define _X86_ARCH_TNC_H_
-#include <pci.h>
+/* Memory BAR Enable */
+#define MEM_BAR_EN 0x00000001
-/* PCI Configuration Space (D31:F0): LPC */
-#define PCH_LPC_DEV PCI_BDF(0, 0x1f, 0)
+/* LPC PCI Configuration Registers */
+#define LPC_RCBA 0xf0
+
+/* Root Complex Register Block */
+struct tnc_rcba {
+ u32 rctl;
+ u32 esd;
+ u32 rsvd1[2];
+ u32 hdd;
+ u32 rsvd2;
+ u32 hdba;
+ u32 rsvd3[3129];
+ u32 d31ip;
+ u32 rsvd4[3];
+ u32 d27ip;
+ u32 rsvd5;
+ u32 d02ip;
+ u32 rsvd6;
+ u32 d26ip;
+ u32 d25ip;
+ u32 d24ip;
+ u32 d23ip;
+ u32 d03ip;
+ u32 rsvd7[3];
+ u16 d31ir;
+ u16 rsvd8[3];
+ u16 d27ir;
+ u16 d26ir;
+ u16 d25ir;
+ u16 d24ir;
+ u16 d23ir;
+ u16 rsvd9[7];
+ u16 d02ir;
+ u16 d03ir;
+};
#endif /* _X86_ARCH_TNC_H_ */
diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h
new file mode 100644
index 0000000000..806f787381
--- /dev/null
+++ b/arch/x86/include/asm/atomic.h
@@ -0,0 +1,115 @@
+#ifndef _ASM_X86_ATOMIC_H
+#define _ASM_X86_ATOMIC_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <asm/processor.h>
+
+typedef struct { volatile int counter; } atomic_t;
+
+/*
+ * Atomic operations that C can't guarantee us. Useful for
+ * resource counting etc..
+ */
+
+#define ATOMIC_INIT(i) { (i) }
+
+/**
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically reads the value of @v.
+ */
+static inline int atomic_read(const atomic_t *v)
+{
+ return ACCESS_ONCE((v)->counter);
+}
+
+/**
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ *
+ * Atomically sets the value of @v to @i.
+ */
+static inline void atomic_set(atomic_t *v, int i)
+{
+ v->counter = i;
+}
+
+/**
+ * atomic_add - add integer to atomic variable
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ *
+ * Atomically adds @i to @v.
+ */
+static inline void atomic_add(int i, atomic_t *v)
+{
+ asm volatile(LOCK_PREFIX "addl %1,%0"
+ : "+m" (v->counter)
+ : "ir" (i));
+}
+
+/**
+ * atomic_sub - subtract integer from atomic variable
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v.
+ */
+static inline void atomic_sub(int i, atomic_t *v)
+{
+ asm volatile(LOCK_PREFIX "subl %1,%0"
+ : "+m" (v->counter)
+ : "ir" (i));
+}
+
+/**
+ * atomic_inc - increment atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1.
+ */
+static inline void atomic_inc(atomic_t *v)
+{
+ asm volatile(LOCK_PREFIX "incl %0"
+ : "+m" (v->counter));
+}
+
+/**
+ * atomic_dec - decrement atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1.
+ */
+static inline void atomic_dec(atomic_t *v)
+{
+ asm volatile(LOCK_PREFIX "decl %0"
+ : "+m" (v->counter));
+}
+
+/**
+ * atomic_inc_short - increment of a short integer
+ * @v: pointer to type int
+ *
+ * Atomically adds 1 to @v
+ * Returns the new value of @u
+ */
+static inline short int atomic_inc_short(short int *v)
+{
+ asm(LOCK_PREFIX "addw $1, %0" : "+m" (*v));
+ return *v;
+}
+
+/* These are x86-specific, used by some header files */
+#define atomic_clear_mask(mask, addr) \
+ asm volatile(LOCK_PREFIX "andl %0,%1" \
+ : : "r" (~(mask)), "m" (*(addr)) : "memory")
+
+#define atomic_set_mask(mask, addr) \
+ asm volatile(LOCK_PREFIX "orl %0,%1" \
+ : : "r" ((unsigned)(mask)), "m" (*(addr)) \
+ : "memory")
+
+#endif /* _ASM_X86_ATOMIC_H */
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index c8392915f1..ebc74adbc3 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -151,6 +151,11 @@ static inline int flag_is_changeable_p(uint32_t flag)
return ((f1^f2) & flag) != 0;
}
+static inline void mfence(void)
+{
+ __asm__ __volatile__("mfence" : : : "memory");
+}
+
/**
* cpu_enable_paging_pae() - Enable PAE-paging
*
@@ -192,6 +197,20 @@ const char *cpu_vendor_name(int vendor);
char *cpu_get_name(char *name);
/**
+ *
+* x86_cpu_get_desc() - Get a description string for an x86 CPU
+*
+* This uses cpu_get_name() and is suitable to use as the get_desc() method for
+* the CPU uclass.
+*
+* @dev: Device to check (UCLASS_CPU)
+* @buf: Buffer to place string
+* @size: Size of string space
+* @return 0 if OK, -ENOSPC if buffer is too small, other -ve on error
+*/
+int x86_cpu_get_desc(struct udevice *dev, char *buf, int size);
+
+/**
* cpu_call64() - Jump to a 64-bit Linux kernel (internal function)
*
* The kernel is uncompressed and the 64-bit entry point is expected to be
diff --git a/arch/x86/include/asm/e820.h b/arch/x86/include/asm/e820.h
index d155ce9cee..21bc63339e 100644
--- a/arch/x86/include/asm/e820.h
+++ b/arch/x86/include/asm/e820.h
@@ -1,43 +1,7 @@
#ifndef _ASM_X86_E820_H
#define _ASM_X86_E820_H
-#define E820MAP 0x2d0 /* our map */
-#define E820MAX 128 /* number of entries in E820MAP */
-/*
- * Legacy E820 BIOS limits us to 128 (E820MAX) nodes due to the
- * constrained space in the zeropage. If we have more nodes than
- * that, and if we've booted off EFI firmware, then the EFI tables
- * passed us from the EFI firmware can list more nodes. Size our
- * internal memory map tables to have room for these additional
- * nodes, based on up to three entries per node for which the
- * kernel was built: MAX_NUMNODES == (1 << CONFIG_NODES_SHIFT),
- * plus E820MAX, allowing space for the possible duplicate E820
- * entries that might need room in the same arrays, prior to the
- * call to sanitize_e820_map() to remove duplicates. The allowance
- * of three memory map entries per node is "enough" entries for
- * the initial hardware platform motivating this mechanism to make
- * use of additional EFI map entries. Future platforms may want
- * to allow more than three entries per node or otherwise refine
- * this size.
- */
-
-/*
- * Odd: 'make headers_check' complains about numa.h if I try
- * to collapse the next two #ifdef lines to a single line:
- * #if defined(__KERNEL__) && defined(CONFIG_EFI)
- */
-#ifdef __KERNEL__
-#ifdef CONFIG_EFI
-#include <linux/numa.h>
-#define E820_X_MAX (E820MAX + 3 * MAX_NUMNODES)
-#else /* ! CONFIG_EFI */
-#define E820_X_MAX E820MAX
-#endif
-#else /* ! __KERNEL__ */
-#define E820_X_MAX E820MAX
-#endif
-
-#define E820NR 0x1e8 /* # entries in E820MAP */
+#define E820MAX 128 /* number of entries in E820MAP */
#define E820_RAM 1
#define E820_RESERVED 2
@@ -45,111 +9,18 @@
#define E820_NVS 4
#define E820_UNUSABLE 5
-/* reserved RAM used by kernel itself */
-#define E820_RESERVED_KERN 128
-
#ifndef __ASSEMBLY__
#include <linux/types.h>
+
struct e820entry {
__u64 addr; /* start of memory segment */
__u64 size; /* size of memory segment */
__u32 type; /* type of memory segment */
} __attribute__((packed));
-struct e820map {
- __u32 nr_map;
- struct e820entry map[E820_X_MAX];
-};
-
#define ISA_START_ADDRESS 0xa0000
#define ISA_END_ADDRESS 0x100000
-#define BIOS_BEGIN 0x000a0000
-#define BIOS_END 0x00100000
-
-#ifdef __KERNEL__
-/* see comment in arch/x86/kernel/e820.c */
-extern struct e820map e820;
-extern struct e820map e820_saved;
-
-extern unsigned long pci_mem_start;
-extern int e820_any_mapped(u64 start, u64 end, unsigned type);
-extern int e820_all_mapped(u64 start, u64 end, unsigned type);
-extern void e820_add_region(u64 start, u64 size, int type);
-extern void e820_print_map(char *who);
-extern int
-sanitize_e820_map(struct e820entry *biosmap, int max_nr_map, u32 *pnr_map);
-extern u64 e820_update_range(u64 start, u64 size, unsigned old_type,
- unsigned new_type);
-extern u64 e820_remove_range(u64 start, u64 size, unsigned old_type,
- int checktype);
-extern void update_e820(void);
-extern void e820_setup_gap(void);
-extern int e820_search_gap(unsigned long *gapstart, unsigned long *gapsize,
- unsigned long start_addr, unsigned long long end_addr);
-struct setup_data;
-extern void parse_e820_ext(struct setup_data *data, unsigned long pa_data);
-
-#if defined(CONFIG_X86_64) || \
- (defined(CONFIG_X86_32) && defined(CONFIG_HIBERNATION))
-extern void e820_mark_nosave_regions(unsigned long limit_pfn);
-#else
-static inline void e820_mark_nosave_regions(unsigned long limit_pfn)
-{
-}
-#endif
-
-#ifdef CONFIG_MEMTEST
-extern void early_memtest(unsigned long start, unsigned long end);
-#else
-static inline void early_memtest(unsigned long start, unsigned long end)
-{
-}
-#endif
-
-extern unsigned long end_user_pfn;
-
-extern u64 find_e820_area(u64 start, u64 end, u64 size, u64 align);
-extern u64 find_e820_area_size(u64 start, u64 *sizep, u64 align);
-extern void reserve_early(u64 start, u64 end, char *name);
-extern void reserve_early_overlap_ok(u64 start, u64 end, char *name);
-extern void free_early(u64 start, u64 end);
-extern void early_res_to_bootmem(u64 start, u64 end);
-extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align);
-
-extern unsigned long e820_end_of_ram_pfn(void);
-extern unsigned long e820_end_of_low_ram_pfn(void);
-extern int e820_find_active_region(const struct e820entry *ei,
- unsigned long start_pfn,
- unsigned long last_pfn,
- unsigned long *ei_startpfn,
- unsigned long *ei_endpfn);
-extern void e820_register_active_regions(int nid, unsigned long start_pfn,
- unsigned long end_pfn);
-extern u64 e820_hole_size(u64 start, u64 end);
-extern void finish_e820_parsing(void);
-extern void e820_reserve_resources(void);
-extern void e820_reserve_resources_late(void);
-extern void setup_memory_map(void);
-extern char *default_machine_specific_memory_setup(void);
-
-/*
- * Returns true iff the specified range [s,e) is completely contained inside
- * the ISA region.
- */
-/*
-static inline bool is_ISA_range(u64 s, u64 e)
-{
- return s >= ISA_START_ADDRESS && e <= ISA_END_ADDRESS;
-}
-*/
-#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
-#ifdef __KERNEL__
-/* #include <linux/ioport.h> */
-
-#define HIGH_MEMORY (1024*1024)
-#endif /* __KERNEL__ */
-
#endif /* _ASM_X86_E820_H */
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h
index 5ee06eb70d..4d9eac676e 100644
--- a/arch/x86/include/asm/global_data.h
+++ b/arch/x86/include/asm/global_data.h
@@ -68,6 +68,7 @@ struct arch_global_data {
/* MRC training data to save for the next boot */
char *mrc_output;
unsigned int mrc_output_len;
+ void *gdt; /* Global descriptor table */
};
#endif
diff --git a/arch/x86/include/asm/ibmpc.h b/arch/x86/include/asm/ibmpc.h
index c3b5187c22..678cde4c86 100644
--- a/arch/x86/include/asm/ibmpc.h
+++ b/arch/x86/include/asm/ibmpc.h
@@ -21,4 +21,7 @@
#define UART0_BASE 0x3f8
#define UART1_BASE 0x2f8
+#define UART0_IRQ 4
+#define UART1_IRQ 3
+
#endif
diff --git a/arch/x86/include/asm/interrupt.h b/arch/x86/include/asm/interrupt.h
index 25abde7be6..0a75f89d95 100644
--- a/arch/x86/include/asm/interrupt.h
+++ b/arch/x86/include/asm/interrupt.h
@@ -38,4 +38,6 @@ extern char exception_stack[];
*/
void configure_irq_trigger(int int_num, bool is_level_triggered);
+void *x86_get_idt(void);
+
#endif
diff --git a/arch/x86/include/asm/mp.h b/arch/x86/include/asm/mp.h
new file mode 100644
index 0000000000..c0930fd0c6
--- /dev/null
+++ b/arch/x86/include/asm/mp.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * Taken from coreboot file of the same name
+ */
+
+#ifndef _X86_MP_H_
+#define _X86_MP_H_
+
+#include <asm/atomic.h>
+
+typedef int (*mp_callback_t)(struct udevice *cpu, void *arg);
+
+/*
+ * A mp_flight_record details a sequence of calls for the APs to perform
+ * along with the BSP to coordinate sequencing. Each flight record either
+ * provides a barrier for each AP before calling the callback or the APs
+ * are allowed to perform the callback without waiting. Regardless, each
+ * record has the cpus_entered field incremented for each record. When
+ * the BSP observes that the cpus_entered matches the number of APs
+ * the bsp_call is called with bsp_arg and upon returning releases the
+ * barrier allowing the APs to make further progress.
+ *
+ * Note that ap_call() and bsp_call() can be NULL. In the NULL case the
+ * callback will just not be called.
+ */
+struct mp_flight_record {
+ atomic_t barrier;
+ atomic_t cpus_entered;
+ mp_callback_t ap_call;
+ void *ap_arg;
+ mp_callback_t bsp_call;
+ void *bsp_arg;
+} __attribute__((aligned(ARCH_DMA_MINALIGN)));
+
+#define MP_FLIGHT_RECORD(barrier_, ap_func_, ap_arg_, bsp_func_, bsp_arg_) \
+ { \
+ .barrier = ATOMIC_INIT(barrier_), \
+ .cpus_entered = ATOMIC_INIT(0), \
+ .ap_call = ap_func_, \
+ .ap_arg = ap_arg_, \
+ .bsp_call = bsp_func_, \
+ .bsp_arg = bsp_arg_, \
+ }
+
+#define MP_FR_BLOCK_APS(ap_func, ap_arg, bsp_func, bsp_arg) \
+ MP_FLIGHT_RECORD(0, ap_func, ap_arg, bsp_func, bsp_arg)
+
+#define MP_FR_NOBLOCK_APS(ap_func, ap_arg, bsp_func, bsp_arg) \
+ MP_FLIGHT_RECORD(1, ap_func, ap_arg, bsp_func, bsp_arg)
+
+/*
+ * The mp_params structure provides the arguments to the mp subsystem
+ * for bringing up APs.
+ *
+ * At present this is overkill for U-Boot, but it may make it easier to add
+ * SMM support.
+ */
+struct mp_params {
+ int num_cpus; /* Total cpus include BSP */
+ int parallel_microcode_load;
+ const void *microcode_pointer;
+ /* Flight plan for APs and BSP */
+ struct mp_flight_record *flight_plan;
+ int num_records;
+};
+
+/*
+ * mp_init() will set up the SIPI vector and bring up the APs according to
+ * mp_params. Each flight record will be executed according to the plan. Note
+ * that the MP infrastructure uses SMM default area without saving it. It's
+ * up to the chipset or mainboard to either e820 reserve this area or save this
+ * region prior to calling mp_init() and restoring it after mp_init returns.
+ *
+ * At the time mp_init() is called the MTRR MSRs are mirrored into APs then
+ * caching is enabled before running the flight plan.
+ *
+ * The MP init has the following properties:
+ * 1. APs are brought up in parallel.
+ * 2. The ordering of cpu number and APIC ids is not deterministic.
+ * Therefore, one cannot rely on this property or the order of devices in
+ * the device tree unless the chipset or mainboard know the APIC ids
+ * a priori.
+ *
+ * mp_init() returns < 0 on error, 0 on success.
+ */
+int mp_init(struct mp_params *params);
+
+/* Probes the CPU device */
+int mp_init_cpu(struct udevice *cpu, void *unused);
+
+#endif /* _X86_MP_H_ */
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 2cbb270089..38dbb3137a 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -53,10 +53,17 @@
#define SNB_C1_AUTO_UNDEMOTE (1UL << 27)
#define SNB_C3_AUTO_UNDEMOTE (1UL << 28)
+#define MSR_BSEL_CR_OVERCLOCK_CONTROL 0x000000cd
#define MSR_PLATFORM_INFO 0x000000ce
+#define MSR_PMG_CST_CONFIG_CONTROL 0x000000e2
+#define SINGLE_PCTL (1 << 11)
+
#define MSR_MTRRcap 0x000000fe
#define MSR_IA32_BBL_CR_CTL 0x00000119
#define MSR_IA32_BBL_CR_CTL3 0x0000011e
+#define MSR_POWER_MISC 0x00000120
+#define ENABLE_ULFM_AUTOCM_MASK (1 << 2)
+#define ENABLE_INDP_AUTOCM_MASK (1 << 3)
#define MSR_IA32_SYSENTER_CS 0x00000174
#define MSR_IA32_SYSENTER_ESP 0x00000175
@@ -66,6 +73,7 @@
#define MSR_IA32_MCG_STATUS 0x0000017a
#define MSR_IA32_MCG_CTL 0x0000017b
+#define MSR_IA32_MISC_ENABLES 0x000001a0
#define MSR_OFFCORE_RSP_0 0x000001a6
#define MSR_OFFCORE_RSP_1 0x000001a7
#define MSR_NHM_TURBO_RATIO_LIMIT 0x000001ad
@@ -73,6 +81,7 @@
#define MSR_LBR_SELECT 0x000001c8
#define MSR_LBR_TOS 0x000001c9
+#define MSR_POWER_CTL 0x000001fc
#define MSR_LBR_NHM_FROM 0x00000680
#define MSR_LBR_NHM_TO 0x000006c0
#define MSR_LBR_CORE_FROM 0x00000040
@@ -136,7 +145,7 @@
/* Run Time Average Power Limiting (RAPL) Interface */
-#define MSR_RAPL_POWER_UNIT 0x00000606
+#define MSR_PKG_POWER_SKU_UNIT 0x00000606
#define MSR_PKG_POWER_LIMIT 0x00000610
#define MSR_PKG_ENERGY_STATUS 0x00000611
@@ -158,6 +167,16 @@
#define MSR_PP1_POLICY 0x00000642
#define MSR_CORE_C1_RES 0x00000660
+#define MSR_IACORE_RATIOS 0x0000066a
+#define MSR_IACORE_TURBO_RATIOS 0x0000066c
+#define MSR_IACORE_VIDS 0x0000066b
+#define MSR_IACORE_TURBO_VIDS 0x0000066d
+#define MSR_PKG_TURBO_CFG1 0x00000670
+#define MSR_CPU_TURBO_WKLD_CFG1 0x00000671
+#define MSR_CPU_TURBO_WKLD_CFG2 0x00000672
+#define MSR_CPU_THERM_CFG1 0x00000673
+#define MSR_CPU_THERM_CFG2 0x00000674
+#define MSR_CPU_THERM_SENS_CFG 0x00000675
#define MSR_AMD64_MC0_MASK 0xc0010044
@@ -348,6 +367,7 @@
#define MSR_THERM2_CTL_TM_SELECT (1ULL << 16)
#define MSR_IA32_MISC_ENABLE 0x000001a0
+#define H_MISC_DISABLE_TURBO (1 << 6)
#define MSR_IA32_TEMPERATURE_TARGET 0x000001a2
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 1955a752b9..c480920d25 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -128,6 +128,34 @@ static inline void wrmsr(unsigned msr, unsigned low, unsigned high)
#define wrmsrl(msr, val) \
native_write_msr((msr), (u32)((u64)(val)), (u32)((u64)(val) >> 32))
+static inline void msr_clrsetbits_64(unsigned msr, u64 clear, u64 set)
+{
+ u64 val;
+
+ val = native_read_msr(msr);
+ val &= ~clear;
+ val |= set;
+ wrmsrl(msr, val);
+}
+
+static inline void msr_setbits_64(unsigned msr, u64 set)
+{
+ u64 val;
+
+ val = native_read_msr(msr);
+ val |= set;
+ wrmsrl(msr, val);
+}
+
+static inline void msr_clrbits_64(unsigned msr, u64 clear)
+{
+ u64 val;
+
+ val = native_read_msr(msr);
+ val &= ~clear;
+ wrmsrl(msr, val);
+}
+
/* rdmsr with exception handling */
#define rdmsr_safe(msr, p1, p2) \
({ \
diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h
index fda4eae10d..3ad617cb4a 100644
--- a/arch/x86/include/asm/mtrr.h
+++ b/arch/x86/include/asm/mtrr.h
@@ -34,6 +34,22 @@
/* Number of MTRRs supported */
#define MTRR_COUNT 8
+#define NUM_FIXED_MTRRS 11
+#define RANGES_PER_FIXED_MTRR 8
+#define NUM_FIXED_RANGES (NUM_FIXED_MTRRS * RANGES_PER_FIXED_MTRR)
+
+#define MTRR_FIX_64K_00000_MSR 0x250
+#define MTRR_FIX_16K_80000_MSR 0x258
+#define MTRR_FIX_16K_A0000_MSR 0x259
+#define MTRR_FIX_4K_C0000_MSR 0x268
+#define MTRR_FIX_4K_C8000_MSR 0x269
+#define MTRR_FIX_4K_D0000_MSR 0x26a
+#define MTRR_FIX_4K_D8000_MSR 0x26b
+#define MTRR_FIX_4K_E0000_MSR 0x26c
+#define MTRR_FIX_4K_E8000_MSR 0x26d
+#define MTRR_FIX_4K_F0000_MSR 0x26e
+#define MTRR_FIX_4K_F8000_MSR 0x26f
+
#if !defined(__ASSEMBLER__)
/**
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index a1969ede27..56eaa25b0c 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -64,6 +64,20 @@ int pci_x86_read_config(struct udevice *bus, pci_dev_t bdf, uint offset,
int pci_x86_write_config(struct udevice *bus, pci_dev_t bdf, uint offset,
ulong value, enum pci_size_t size);
+/**
+ * Assign IRQ number to a PCI device
+ *
+ * This function assigns IRQ for a PCI device. If the device does not exist
+ * or does not require interrupts then this function has no effect.
+ *
+ * @bus: PCI bus number
+ * @device: PCI device number
+ * @func: PCI function number
+ * @irq: An array of IRQ numbers that are assigned to INTA through
+ * INTD of this PCI device.
+ */
+void pci_assign_irqs(int bus, int device, int func, u8 irq[4]);
+
#endif /* __ASSEMBLY__ */
#endif /* _PCI_I386_H_ */
diff --git a/arch/x86/include/asm/pirq_routing.h b/arch/x86/include/asm/pirq_routing.h
new file mode 100644
index 0000000000..ddc08e11d5
--- /dev/null
+++ b/arch/x86/include/asm/pirq_routing.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * Ported from coreboot src/arch/x86/include/arch/pirq_routing.h
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _PIRQ_ROUTING_H_
+#define _PIRQ_ROUTING_H_
+
+/*
+ * This is the maximum number on interrupt entries that a PCI device may have.
+ * This is NOT the number of slots or devices in the system
+ * This is NOT the number of entries in the PIRQ table
+ *
+ * This tells us that in the PIRQ table, we are going to have 4 link-bitmap
+ * entries per PCI device which is fixed at 4: INTA, INTB, INTC, and INTD.
+ *
+ * CAUTION: If you change this, PIRQ routing will not work correctly.
+ */
+#define MAX_INTX_ENTRIES 4
+
+#define PIRQ_SIGNATURE \
+ (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
+#define PIRQ_VERSION 0x0100
+
+struct __packed irq_info {
+ u8 bus; /* Bus number */
+ u8 devfn; /* Device and function number */
+ struct __packed {
+ u8 link; /* IRQ line ID, 0=not routed */
+ u16 bitmap; /* Available IRQs */
+ } irq[MAX_INTX_ENTRIES];
+ u8 slot; /* Slot number, 0=onboard */
+ u8 rfu;
+};
+
+struct __packed irq_routing_table {
+ u32 signature; /* PIRQ_SIGNATURE */
+ u16 version; /* PIRQ_VERSION */
+ u16 size; /* Table size in bytes */
+ u8 rtr_bus; /* busno of the interrupt router */
+ u8 rtr_devfn; /* devfn of the interrupt router */
+ u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */
+ u16 rtr_vendor; /* Vendor ID of the interrupt router */
+ u16 rtr_device; /* Device ID of the interrupt router */
+ u32 miniport_data;
+ u8 rfu[11];
+ u8 checksum; /* Modulo 256 checksum must give zero */
+ struct irq_info slots[CONFIG_IRQ_SLOT_COUNT];
+};
+
+/**
+ * get_irq_slot_count() - Get the number of entries in the irq_info table
+ *
+ * This calculates the number of entries for the irq_info table.
+ *
+ * @rt: pointer to the base address of the struct irq_info
+ * @return: number of entries
+ */
+static inline int get_irq_slot_count(struct irq_routing_table *rt)
+{
+ return (rt->size - 32) / sizeof(struct irq_info);
+}
+
+/**
+ * pirq_check_irq_routed() - Check whether an IRQ is routed to 8259 PIC
+ *
+ * This function checks whether an IRQ is routed to 8259 PIC for a given link.
+ *
+ * Note: this function should be provided by the platform codes, as the
+ * implementation of interrupt router may be different.
+ *
+ * @link: link number which represents a PIRQ
+ * @irq: the 8259 IRQ number
+ * @return: true if the irq is already routed to 8259 for a given link,
+ * false elsewise
+ */
+bool pirq_check_irq_routed(int link, u8 irq);
+
+/**
+ * pirq_translate_link() - Translate a link value
+ *
+ * This function translates a platform-specific link value to a link number.
+ * On Intel platforms, the link value is normally a offset into the PCI
+ * configuration space into the legacy bridge.
+ *
+ * Note: this function should be provided by the platform codes, as the
+ * implementation of interrupt router may be different.
+ *
+ * @link: platform-specific link value
+ * @return: link number which represents a PIRQ
+ */
+int pirq_translate_link(int link);
+
+/**
+ * pirq_assign_irq() - Assign an IRQ to a PIRQ link
+ *
+ * This function assigns the IRQ to a PIRQ link so that the PIRQ is routed to
+ * the 8259 PIC.
+ *
+ * Note: this function should be provided by the platform codes, as the
+ * implementation of interrupt router may be different.
+ *
+ * @link: link number which represents a PIRQ
+ * @irq: IRQ to which the PIRQ is routed
+ */
+void pirq_assign_irq(int link, u8 irq);
+
+/**
+ * pirq_route_irqs() - Route PIRQs to 8259 PIC
+ *
+ * This function configures all PCI devices' interrupt pins and maps them to
+ * PIRQs and finally 8259 PIC. The routed irq number is written to interrupt
+ * line register in the configuration space of the PCI device for OS to use.
+ * The configuration source is taken from a struct irq_info table, the format
+ * of which is defined in PIRQ routing table spec and PCI BIOS spec.
+ *
+ * @irq: pointer to the base address of the struct irq_info
+ * @num: number of entries in the struct irq_info
+ */
+void pirq_route_irqs(struct irq_info *irq, int num);
+
+/**
+ * copy_pirq_routing_table() - Copy a PIRQ routing table
+ *
+ * This helper function copies the given PIRQ routing table to a given address.
+ * Before copying, it does several sanity tests against the PIRQ routing table.
+ * It also fixes up the table checksum and align the given address to a 16 byte
+ * boundary to meet the PIRQ routing table spec requirements.
+ *
+ * @addr: address to store the copied PIRQ routing table
+ * @rt: pointer to the PIRQ routing table to copy from
+ * @return: end address of the copied PIRQ routing table
+ */
+u32 copy_pirq_routing_table(u32 addr, struct irq_routing_table *rt);
+
+#endif /* _PIRQ_ROUTING_H_ */
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 3e26202aa5..7c77b90485 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -23,10 +23,32 @@
#define X86_GDT_SIZE (X86_GDT_NUM_ENTRIES * X86_GDT_ENTRY_SIZE)
+/* 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)".
+ *
+ * RST_CNT: Reset Control Register (RST_CNT) Offset cf9.
+ *
+ * The naming follows Intel's naming.
+ */
#define 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 */
+};
+
+/**
+ * x86_full_reset() - reset everything: perform a full power cycle
+ */
+void x86_full_reset(void);
+
static inline __attribute__((always_inline)) void cpu_hlt(void)
{
asm("hlt");
diff --git a/arch/x86/include/asm/sfi.h b/arch/x86/include/asm/sfi.h
new file mode 100644
index 0000000000..d1f0f0cb6b
--- /dev/null
+++ b/arch/x86/include/asm/sfi.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright(c) 2009 Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
+ */
+
+#ifndef _LINUX_SFI_H
+#define _LINUX_SFI_H
+
+#include <errno.h>
+#include <linux/types.h>
+
+/* Table signatures reserved by the SFI specification */
+#define SFI_SIG_SYST "SYST"
+#define SFI_SIG_FREQ "FREQ"
+#define SFI_SIG_CPUS "CPUS"
+#define SFI_SIG_MTMR "MTMR"
+#define SFI_SIG_MRTC "MRTC"
+#define SFI_SIG_MMAP "MMAP"
+#define SFI_SIG_APIC "APIC"
+#define SFI_SIG_XSDT "XSDT"
+#define SFI_SIG_WAKE "WAKE"
+#define SFI_SIG_DEVS "DEVS"
+#define SFI_SIG_GPIO "GPIO"
+
+#define SFI_SIGNATURE_SIZE 4
+#define SFI_OEM_ID_SIZE 6
+#define SFI_OEM_TABLE_ID_SIZE 8
+
+#define SFI_NAME_LEN 16
+#define SFI_TABLE_MAX_ENTRIES 16
+
+#define SFI_GET_NUM_ENTRIES(ptable, entry_type) \
+ ((ptable->header.len - sizeof(struct sfi_table_header)) / \
+ (sizeof(entry_type)))
+/*
+ * Table structures must be byte-packed to match the SFI specification,
+ * as they are provided by the BIOS.
+ */
+struct __packed sfi_table_header {
+ char sig[SFI_SIGNATURE_SIZE];
+ u32 len;
+ u8 rev;
+ u8 csum;
+ char oem_id[SFI_OEM_ID_SIZE];
+ char oem_table_id[SFI_OEM_TABLE_ID_SIZE];
+};
+
+struct __packed sfi_table_simple {
+ struct sfi_table_header header;
+ u64 pentry[1];
+};
+
+/* Comply with UEFI spec 2.1 */
+struct __packed sfi_mem_entry {
+ u32 type;
+ u64 phys_start;
+ u64 virt_start;
+ u64 pages;
+ u64 attrib;
+};
+
+struct __packed sfi_cpu_table_entry {
+ u32 apic_id;
+};
+
+struct __packed sfi_cstate_table_entry {
+ u32 hint; /* MWAIT hint */
+ u32 latency; /* latency in ms */
+};
+
+struct __packed sfi_apic_table_entry {
+ u64 phys_addr; /* phy base addr for APIC reg */
+};
+
+struct __packed sfi_freq_table_entry {
+ u32 freq_mhz; /* in MHZ */
+ u32 latency; /* transition latency in ms */
+ u32 ctrl_val; /* value to write to PERF_CTL */
+};
+
+struct __packed sfi_wake_table_entry {
+ u64 phys_addr; /* pointer to where the wake vector locates */
+};
+
+struct __packed sfi_timer_table_entry {
+ u64 phys_addr; /* phy base addr for the timer */
+ u32 freq_hz; /* in HZ */
+ u32 irq;
+};
+
+struct __packed sfi_rtc_table_entry {
+ u64 phys_addr; /* phy base addr for the RTC */
+ u32 irq;
+};
+
+struct __packed sfi_device_table_entry {
+ u8 type; /* bus type, I2C, SPI or ...*/
+ u8 host_num; /* attached to host 0, 1...*/
+ u16 addr;
+ u8 irq;
+ u32 max_freq;
+ char name[SFI_NAME_LEN];
+};
+
+enum {
+ SFI_DEV_TYPE_SPI = 0,
+ SFI_DEV_TYPE_I2C,
+ SFI_DEV_TYPE_UART,
+ SFI_DEV_TYPE_HSI,
+ SFI_DEV_TYPE_IPC,
+ SFI_DEV_TYPE_SD,
+};
+
+struct __packed sfi_gpio_table_entry {
+ char controller_name[SFI_NAME_LEN];
+ u16 pin_no;
+ char pin_name[SFI_NAME_LEN];
+};
+
+struct sfi_xsdt_header {
+ uint32_t oem_revision;
+ uint32_t creator_id;
+ uint32_t creator_revision;
+};
+
+typedef int (*sfi_table_handler) (struct sfi_table_header *table);
+
+/**
+ * write_sfi_table() - Write Simple Firmware Interface tables
+ *
+ * @base: Address to write table to
+ * @return address to use for the next table
+ */
+u32 write_sfi_table(u32 base);
+
+#endif /*_LINUX_SFI_H */
diff --git a/arch/x86/include/asm/sipi.h b/arch/x86/include/asm/sipi.h
new file mode 100644
index 0000000000..25d7d311d2
--- /dev/null
+++ b/arch/x86/include/asm/sipi.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015 Gooogle, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _ASM_SIPI_H
+#define _ASM_SIPI_H
+
+#define AP_DEFAULT_BASE 0x30000
+#define AP_DEFAULT_SIZE 0x10000
+
+#ifndef __ASSEMBLER__
+
+/**
+ * struct sipi_params_16bit - 16-bit SIPI entry-point parameters
+ *
+ * These are set up in the same space as the SIPI 16-bit code so that each AP
+ * can access the parameters when it boots.
+ *
+ * Each of these must be set up for the AP to boot, except @segment which is
+ * set in the assembly code.
+ *
+ * @ap_start: 32-bit SIPI entry point for U-Boot
+ * @segment: Code segment for U-Boot
+ * @pad: Padding (not used)
+ * @gdt_limit: U-Boot GDT limit (X86_GDT_SIZE - 1)
+ * @gdt: U-Boot GDT (gd->arch.gdt)
+ * @unused: Not used
+ */
+struct __packed sipi_params_16bit {
+ u32 ap_start;
+ u16 segment;
+ u16 pad;
+ u16 gdt_limit;
+ u32 gdt;
+ u16 unused;
+};
+
+/**
+ * struct sipi_params - 32-bit SIP entry-point parameters
+ *
+ * These are used by the AP init code and must be set up before the APs start.
+ *
+ * The stack area extends down from @stack_top, with @stack_size allocated
+ * for each AP.
+ *
+ * @idt_ptr: Interrupt descriptor table pointer
+ * @stack_top: Top of the AP stack area
+ * @stack_size: Size of each AP's stack
+ * @microcode_lock: Used to ensure only one AP loads microcode at once
+ * 0xffffffff enables parallel loading.
+ * @microcode_ptr: Pointer to microcode, or 0 if none
+ * @msr_table_ptr: Pointer to saved MSRs, a list of struct saved_msr
+ * @msr_count: Number of saved MSRs
+ * @c_handler: C function to call once early init is complete
+ * @ap_count: Shared atomic value to allocate CPU indexes
+ */
+struct sipi_params {
+ u32 idt_ptr;
+ u32 stack_top;
+ u32 stack_size;
+ u32 microcode_lock;
+ u32 microcode_ptr;
+ u32 msr_table_ptr;
+ u32 msr_count;
+ u32 c_handler;
+ atomic_t ap_count;
+};
+
+/* 16-bit AP entry point */
+void ap_start16(void);
+
+/* end of 16-bit code/data, marks the region to be copied to SIP vector */
+void ap_start16_code_end(void);
+
+/* 32-bit AP entry point */
+void ap_start(void);
+
+extern char sipi_params_16bit[];
+extern char sipi_params[];
+
+#endif /* __ASSEMBLER__ */
+
+#endif
diff --git a/arch/x86/include/asm/tables.h b/arch/x86/include/asm/tables.h
new file mode 100644
index 0000000000..8146ba39b2
--- /dev/null
+++ b/arch/x86/include/asm/tables.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _X86_TABLES_H_
+#define _X86_TABLES_H_
+
+/*
+ * All x86 tables happen to like the address range from 0xf0000 to 0x100000.
+ * We use 0xf0000 as the starting address to store those tables, including
+ * PIRQ routing table, Multi-Processor table and ACPI table.
+ */
+#define ROM_TABLE_ADDR 0xf0000
+
+/**
+ * table_compute_checksum() - Compute a table checksum
+ *
+ * This computes an 8-bit checksum for the configuration table.
+ * All bytes in the configuration table, including checksum itself and
+ * reserved bytes must add up to zero.
+ *
+ * @v: configuration table base address
+ * @len: configuration table size
+ * @return: the 8-bit checksum
+ */
+u8 table_compute_checksum(void *v, int len);
+
+/**
+ * write_tables() - Write x86 configuration tables
+ *
+ * This writes x86 configuration tables, including PIRQ routing table,
+ * Multi-Processor table and ACPI table. Whether a specific type of
+ * configuration table is written is controlled by a Kconfig option.
+ */
+void write_tables(void);
+
+/**
+ * write_pirq_routing_table() - Write PIRQ routing table
+ *
+ * This writes PIRQ routing table at a given address.
+ *
+ * @start: start address to write PIRQ routing table
+ * @return: end address of PIRQ routing table
+ */
+u32 write_pirq_routing_table(u32 start);
+
+#endif /* _X86_TABLES_H_ */
diff --git a/arch/x86/include/asm/turbo.h b/arch/x86/include/asm/turbo.h
index bb0d4b4354..21b910bbf0 100644
--- a/arch/x86/include/asm/turbo.h
+++ b/arch/x86/include/asm/turbo.h
@@ -12,9 +12,6 @@
#define CPUID_LEAF_PM 6
#define PM_CAP_TURBO_MODE (1 << 1)
-#define MSR_IA32_MISC_ENABLES 0x1a0
-#define H_MISC_DISABLE_TURBO (1 << 6)
-
enum {
TURBO_UNKNOWN,
TURBO_UNAVAILABLE,
diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h
index c743efd60b..be103c055c 100644
--- a/arch/x86/include/asm/u-boot-x86.h
+++ b/arch/x86/include/asm/u-boot-x86.h
@@ -53,6 +53,8 @@ int video_bios_init(void);
void board_init_f_r_trampoline(ulong) __attribute__ ((noreturn));
void board_init_f_r(void) __attribute__ ((noreturn));
+int arch_misc_init(void);
+
/* Read the time stamp counter */
static inline __attribute__((no_instrument_function)) uint64_t rdtsc(void)
{
@@ -67,6 +69,8 @@ uint64_t timer_get_tsc(void);
void quick_ram_check(void);
+int x86_init_cpus(void);
+
#define PCI_VGA_RAM_IMAGE_START 0xc0000
#endif /* _U_BOOT_I386_H_ */
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 6c571dd9c1..70ad19b263 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -22,12 +22,14 @@ ifndef CONFIG_DM_PCI
obj-$(CONFIG_PCI) += pci_type1.o
endif
obj-y += pch-uclass.o
+obj-y += pirq_routing.o
obj-y += relocate.o
obj-y += physmem.o
obj-$(CONFIG_X86_RAMTEST) += ramtest.o
+obj-y += sfi.o
obj-y += string.o
+obj-y += tables.o
obj-$(CONFIG_SYS_X86_TSC_TIMER) += tsc_timer.o
-obj-$(CONFIG_VIDEO_VGA) += video.o
obj-$(CONFIG_CMD_ZBOOT) += zimage.o
obj-$(CONFIG_HAVE_FSP) += fsp/
diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c
index f668259c0e..001494d97d 100644
--- a/arch/x86/lib/fsp/fsp_common.c
+++ b/arch/x86/lib/fsp/fsp_common.c
@@ -17,13 +17,6 @@ int print_cpuinfo(void)
return default_print_cpuinfo();
}
-void reset_cpu(ulong addr)
-{
- /* cold reset */
- outb(0x06, PORT_RESET);
-}
-
-
int board_pci_post_scan(struct pci_controller *hose)
{
u32 status;
diff --git a/arch/x86/lib/pirq_routing.c b/arch/x86/lib/pirq_routing.c
new file mode 100644
index 0000000000..7a34dcf366
--- /dev/null
+++ b/arch/x86/lib/pirq_routing.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * Part of this file is ported from coreboot src/arch/x86/boot/pirq_routing.c
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <asm/pci.h>
+#include <asm/pirq_routing.h>
+#include <asm/tables.h>
+
+static bool irq_already_routed[16];
+
+static u8 pirq_get_next_free_irq(u8 *pirq, u16 bitmap)
+{
+ int i, link;
+ u8 irq = 0;
+
+ /* IRQ sharing starts from IRQ#3 */
+ for (i = 3; i < 16; i++) {
+ /* Can we assign this IRQ? */
+ if (!((bitmap >> i) & 1))
+ continue;
+
+ /* We can, now let's assume we can use this IRQ */
+ irq = i;
+
+ /* Have we already routed it? */
+ if (irq_already_routed[irq])
+ continue;
+
+ for (link = 0; link < CONFIG_MAX_PIRQ_LINKS; link++) {
+ if (pirq_check_irq_routed(link, irq)) {
+ irq_already_routed[irq] = true;
+ break;
+ }
+ }
+
+ /* If it's not yet routed, use it */
+ if (!irq_already_routed[irq]) {
+ irq_already_routed[irq] = true;
+ break;
+ }
+
+ /* But if it was already routed, try the next one */
+ }
+
+ /* Now we get our IRQ */
+ return irq;
+}
+
+void pirq_route_irqs(struct irq_info *irq, int num)
+{
+ unsigned char irq_slot[MAX_INTX_ENTRIES];
+ unsigned char pirq[CONFIG_MAX_PIRQ_LINKS];
+ int i, intx;
+
+ memset(pirq, 0, CONFIG_MAX_PIRQ_LINKS);
+
+ /* Set PCI IRQs */
+ for (i = 0; i < num; i++) {
+ debug("PIRQ Entry %d Dev: %d.%x.%d\n", i,
+ irq->bus, irq->devfn >> 3, irq->devfn & 7);
+
+ for (intx = 0; intx < MAX_INTX_ENTRIES; intx++) {
+ int link = irq->irq[intx].link;
+ int bitmap = irq->irq[intx].bitmap;
+ int irq = 0;
+
+ debug("INT%c link: %x bitmap: %x ",
+ 'A' + intx, link, bitmap);
+
+ if (!bitmap || !link) {
+ debug("not routed\n");
+ irq_slot[intx] = irq;
+ continue;
+ }
+
+ /* translate link value to link number */
+ link = pirq_translate_link(link);
+
+ /* yet not routed */
+ if (!pirq[link]) {
+ irq = pirq_get_next_free_irq(pirq, bitmap);
+ pirq[link] = irq;
+ } else {
+ irq = pirq[link];
+ }
+
+ debug("IRQ: %d\n", irq);
+ irq_slot[intx] = irq;
+
+ /* Assign IRQ in the interrupt router */
+ pirq_assign_irq(link, irq);
+ }
+
+ /* Bus, device, slots IRQs for {A,B,C,D} */
+ pci_assign_irqs(irq->bus, irq->devfn >> 3, irq->devfn & 7,
+ irq_slot);
+
+ irq++;
+ }
+
+ for (i = 0; i < CONFIG_MAX_PIRQ_LINKS; i++)
+ debug("PIRQ%c: %d\n", 'A' + i, pirq[i]);
+}
+
+u32 copy_pirq_routing_table(u32 addr, struct irq_routing_table *rt)
+{
+ struct irq_routing_table *rom_rt;
+
+ /* Fix up the table checksum */
+ rt->checksum = table_compute_checksum(rt, rt->size);
+
+ /* Align the table to be 16 byte aligned */
+ addr = ALIGN(addr, 16);
+
+ debug("Copying Interrupt Routing Table to 0x%x\n", addr);
+ memcpy((void *)addr, rt, rt->size);
+
+ /*
+ * We do the sanity check here against the copied table after memcpy,
+ * as something might go wrong after the memcpy, which is normally
+ * due to the F segment decode is not turned on to systeam RAM.
+ */
+ rom_rt = (struct irq_routing_table *)addr;
+ if (rom_rt->signature != PIRQ_SIGNATURE ||
+ rom_rt->version != PIRQ_VERSION || rom_rt->size % 16) {
+ printf("Interrupt Routing Table not valid\n");
+ return addr;
+ }
+
+ return addr + rt->size;
+}
diff --git a/arch/x86/lib/sfi.c b/arch/x86/lib/sfi.c
new file mode 100644
index 0000000000..3d3658088a
--- /dev/null
+++ b/arch/x86/lib/sfi.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * Intel Simple Firmware Interface (SFI)
+ *
+ * Yet another way to pass information to the Linux kernel.
+ *
+ * See https://simplefirmware.org/ for details
+ */
+
+#include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <asm/cpu.h>
+#include <asm/ioapic.h>
+#include <asm/sfi.h>
+#include <asm/tables.h>
+#include <dm/uclass-internal.h>
+
+struct table_info {
+ u32 base;
+ int ptr;
+ u32 entry_start;
+ u64 table[SFI_TABLE_MAX_ENTRIES];
+ int count;
+};
+
+static void *get_entry_start(struct table_info *tab)
+{
+ if (tab->count == SFI_TABLE_MAX_ENTRIES)
+ return NULL;
+ tab->entry_start = tab->base + tab->ptr;
+ tab->table[tab->count] = tab->entry_start;
+ tab->entry_start += sizeof(struct sfi_table_header);
+
+ return (void *)tab->entry_start;
+}
+
+static void finish_table(struct table_info *tab, const char *sig, void *entry)
+{
+ struct sfi_table_header *hdr;
+
+ hdr = (struct sfi_table_header *)(tab->base + tab->ptr);
+ strcpy(hdr->sig, sig);
+ hdr->len = sizeof(*hdr) + ((ulong)entry - tab->entry_start);
+ hdr->rev = 1;
+ strncpy(hdr->oem_id, "U-Boot", SFI_OEM_ID_SIZE);
+ strncpy(hdr->oem_table_id, "Table v1", SFI_OEM_TABLE_ID_SIZE);
+ hdr->csum = 0;
+ hdr->csum = table_compute_checksum(hdr, hdr->len);
+ tab->ptr += hdr->len;
+ tab->ptr = ALIGN(tab->ptr, 16);
+ tab->count++;
+}
+
+static int sfi_write_system_header(struct table_info *tab)
+{
+ u64 *entry = get_entry_start(tab);
+ int i;
+
+ if (!entry)
+ return -ENOSPC;
+
+ for (i = 0; i < tab->count; i++)
+ *entry++ = tab->table[i];
+ finish_table(tab, SFI_SIG_SYST, entry);
+
+ return 0;
+}
+
+static int sfi_write_cpus(struct table_info *tab)
+{
+ struct sfi_cpu_table_entry *entry = get_entry_start(tab);
+ struct udevice *dev;
+ int count = 0;
+
+ if (!entry)
+ return -ENOSPC;
+
+ for (uclass_find_first_device(UCLASS_CPU, &dev);
+ dev;
+ uclass_find_next_device(&dev)) {
+ struct cpu_platdata *plat = dev_get_parent_platdata(dev);
+
+ if (!device_active(dev))
+ continue;
+ entry->apic_id = plat->cpu_id;
+ entry++;
+ count++;
+ }
+
+ /* Omit the table if there is only one CPU */
+ if (count > 1)
+ finish_table(tab, SFI_SIG_CPUS, entry);
+
+ return 0;
+}
+
+static int sfi_write_apic(struct table_info *tab)
+{
+ struct sfi_apic_table_entry *entry = get_entry_start(tab);
+
+ if (!entry)
+ return -ENOSPC;
+
+ entry->phys_addr = IO_APIC_ADDR;
+ entry++;
+ finish_table(tab, SFI_SIG_APIC, entry);
+
+ return 0;
+}
+
+static int sfi_write_xsdt(struct table_info *tab)
+{
+ struct sfi_xsdt_header *entry = get_entry_start(tab);
+
+ if (!entry)
+ return -ENOSPC;
+
+ entry->oem_revision = 1;
+ entry->creator_id = 1;
+ entry->creator_revision = 1;
+ entry++;
+ finish_table(tab, SFI_SIG_XSDT, entry);
+
+ return 0;
+}
+
+u32 write_sfi_table(u32 base)
+{
+ struct table_info table;
+
+ table.base = base;
+ table.ptr = 0;
+ table.count = 0;
+ sfi_write_cpus(&table);
+ sfi_write_apic(&table);
+
+ /*
+ * The SFI specification marks the XSDT table as option, but Linux 4.0
+ * crashes on start-up when it is not provided.
+ */
+ sfi_write_xsdt(&table);
+
+ /* Finally, write out the system header which points to the others */
+ sfi_write_system_header(&table);
+
+ return base + table.ptr;
+}
diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c
new file mode 100644
index 0000000000..8031201a49
--- /dev/null
+++ b/arch/x86/lib/tables.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/sfi.h>
+#include <asm/tables.h>
+
+u8 table_compute_checksum(void *v, int len)
+{
+ u8 *bytes = v;
+ u8 checksum = 0;
+ int i;
+
+ for (i = 0; i < len; i++)
+ checksum -= bytes[i];
+
+ return checksum;
+}
+
+void write_tables(void)
+{
+ u32 __maybe_unused rom_table_end = ROM_TABLE_ADDR;
+
+#ifdef CONFIG_GENERATE_PIRQ_TABLE
+ rom_table_end = write_pirq_routing_table(rom_table_end);
+ rom_table_end = ALIGN(rom_table_end, 1024);
+#endif
+#ifdef CONFIG_GENERATE_SFI_TABLE
+ rom_table_end = write_sfi_table(rom_table_end);
+ rom_table_end = ALIGN(rom_table_end, 1024);
+#endif
+}
diff --git a/arch/x86/lib/video.c b/arch/x86/lib/video.c
deleted file mode 100644
index 975949daa3..0000000000
--- a/arch/x86/lib/video.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * (C) Copyright 2002
- * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <pci.h>
-#include <stdio_dev.h>
-#include <i8042.h>
-#include <asm/ptrace.h>
-#include <asm/io.h>
-#include <asm/pci.h>
-
-/* basic textmode I/O from linux kernel */
-static char *vidmem = (char *)0xb8000;
-static int vidport;
-static int lines, cols;
-static int orig_x, orig_y;
-
-static void beep(int dur)
-{
- int i;
-
- outb_p(3, 0x61);
- for (i = 0; i < 10*dur; i++)
- udelay(1000);
-
- outb_p(0, 0x61);
-}
-
-static void scroll(void)
-{
- int i;
-
- memcpy(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2);
- for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2)
- vidmem[i] = ' ';
-}
-
-static void __video_putc(const char c, int *x, int *y)
-{
- if (c == '\n') {
- (*x) = 0;
- if (++(*y) >= lines) {
- scroll();
- (*y)--;
- }
- } else if (c == '\b') {
- if ((*x) != 0) {
- --(*x);
- vidmem[((*x) + cols * (*y)) * 2] = ' ';
- }
- } else if (c == '\r') {
- (*x) = 0;
-
- } else if (c == '\a') {
- beep(3);
-
- } else if (c == '\t') {
- __video_putc(' ', x, y);
- __video_putc(' ', x, y);
- __video_putc(' ', x, y);
- __video_putc(' ', x, y);
- __video_putc(' ', x, y);
- __video_putc(' ', x, y);
- __video_putc(' ', x, y);
- __video_putc(' ', x, y);
- } else if (c == '\v') {
- switch ((*x) % 8) {
- case 0:
- __video_putc(' ', x, y);
- case 7:
- __video_putc(' ', x, y);
- case 6:
- __video_putc(' ', x, y);
- case 5:
- __video_putc(' ', x, y);
- case 4:
- __video_putc(' ', x, y);
- case 3:
- __video_putc(' ', x, y);
- case 2:
- __video_putc(' ', x, y);
- case 1:
- __video_putc(' ', x, y);
- }
- } else if (c == '\f') {
- int i;
- for (i = 0; i < lines * cols * 2; i += 2)
- vidmem[i] = 0;
- (*x) = 0;
- (*y) = 0;
- } else {
- vidmem[((*x) + cols * (*y)) * 2] = c;
- if (++(*x) >= cols) {
- (*x) = 0;
- if (++(*y) >= lines) {
- scroll();
- (*y)--;
- }
- }
- }
-}
-
-static void video_putc(struct stdio_dev *dev, const char c)
-{
- int x, y, pos;
-
- x = orig_x;
- y = orig_y;
-
- __video_putc(c, &x, &y);
-
- orig_x = x;
- orig_y = y;
-
- pos = (x + cols * y) * 2; /* Update cursor position */
- outb_p(14, vidport);
- outb_p(0xff & (pos >> 9), vidport+1);
- outb_p(15, vidport);
- outb_p(0xff & (pos >> 1), vidport+1);
-}
-
-static void video_puts(struct stdio_dev *dev, const char *s)
-{
- int x, y, pos;
- char c;
-
- x = orig_x;
- y = orig_y;
-
- while ((c = *s++) != '\0')
- __video_putc(c, &x, &y);
-
- orig_x = x;
- orig_y = y;
-
- pos = (x + cols * y) * 2; /* Update cursor position */
- outb_p(14, vidport);
- outb_p(0xff & (pos >> 9), vidport+1);
- outb_p(15, vidport);
- outb_p(0xff & (pos >> 1), vidport+1);
-}
-
-int video_init(void)
-{
- u16 pos;
-
- static struct stdio_dev vga_dev;
- static struct stdio_dev kbd_dev;
-
- vidmem = (char *) 0xb8000;
- vidport = 0x3d4;
-
- lines = 25;
- cols = 80;
-
- outb_p(14, vidport);
- pos = inb_p(vidport+1);
- pos <<= 8;
- outb_p(15, vidport);
- pos |= inb_p(vidport+1);
-
- orig_x = pos%cols;
- orig_y = pos/cols;
-
-#if 0
- printf("pos %x %d %d\n", pos, orig_x, orig_y);
-#endif
- if (orig_y > lines)
- orig_x = orig_y = 0;
-
- memset(&vga_dev, 0, sizeof(vga_dev));
- strcpy(vga_dev.name, "vga");
- vga_dev.ext = 0;
- vga_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM;
- vga_dev.putc = video_putc; /* 'putc' function */
- vga_dev.puts = video_puts; /* 'puts' function */
-
- if (stdio_register(&vga_dev) == 0)
- return 1;
-
- if (i8042_kbd_init())
- return 1;
-
- memset(&kbd_dev, 0, sizeof(kbd_dev));
- strcpy(kbd_dev.name, "kbd");
- kbd_dev.ext = 0;
- kbd_dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
- kbd_dev.tstc = i8042_tstc; /* 'tstc' function */
- kbd_dev.getc = i8042_getc; /* 'getc' function */
-
- if (stdio_register(&kbd_dev) == 0)
- return 1;
-
- return 0;
-}
-
-
-int drv_video_init(void)
-{
- return video_init();
-}
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c
index 566b048c88..c3f8a7308f 100644
--- a/arch/x86/lib/zimage.c
+++ b/arch/x86/lib/zimage.c
@@ -25,6 +25,8 @@
#endif
#include <linux/compiler.h>
+DECLARE_GLOBAL_DATA_PTR;
+
/*
* Memory lay-out:
*
@@ -40,16 +42,29 @@
#define COMMAND_LINE_SIZE 2048
-unsigned generic_install_e820_map(unsigned max_entries,
- struct e820entry *entries)
+/*
+ * Install a default e820 table with 3 entries as follows:
+ *
+ * 0x000000-0x0a0000 Useable RAM
+ * 0x0a0000-0x100000 Reserved for ISA
+ * 0x100000-gd->ram_size Useable RAM
+ */
+__weak unsigned install_e820_map(unsigned max_entries,
+ struct e820entry *entries)
{
- return 0;
+ 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;
+ entries[2].addr = ISA_END_ADDRESS;
+ entries[2].size = gd->ram_size - ISA_END_ADDRESS;
+ entries[2].type = E820_RAM;
+
+ return 3;
}
-unsigned install_e820_map(unsigned max_entries,
- struct e820entry *entries)
- __attribute__((weak, alias("generic_install_e820_map")));
-
static void build_command_line(char *command_line, int auto_boot)
{
char *env_command_line;