Merge branch 'master' of git://git.denx.de/u-boot-sunxi
authorTom Rini <trini@konsulko.com>
Mon, 4 May 2015 21:50:20 +0000 (17:50 -0400)
committerTom Rini <trini@konsulko.com>
Mon, 4 May 2015 21:50:20 +0000 (17:50 -0400)
104 files changed:
Kconfig
README
arch/Kconfig
arch/x86/Kconfig
arch/x86/cpu/Makefile
arch/x86/cpu/baytrail/Makefile
arch/x86/cpu/baytrail/cpu.c [new file with mode: 0644]
arch/x86/cpu/baytrail/valleyview.c
arch/x86/cpu/config.mk
arch/x86/cpu/coreboot/pci.c
arch/x86/cpu/cpu.c
arch/x86/cpu/interrupts.c
arch/x86/cpu/ivybridge/car.S
arch/x86/cpu/ivybridge/cpu.c
arch/x86/cpu/ivybridge/early_me.c
arch/x86/cpu/ivybridge/model_206ax.c
arch/x86/cpu/ivybridge/sdram.c
arch/x86/cpu/mp_init.c [new file with mode: 0644]
arch/x86/cpu/pci.c
arch/x86/cpu/quark/quark.c
arch/x86/cpu/queensbay/Makefile
arch/x86/cpu/queensbay/irq.c [new file with mode: 0644]
arch/x86/cpu/queensbay/tnc.c
arch/x86/cpu/sipi_vector.S [new file with mode: 0644]
arch/x86/dts/chromebook_link.dts
arch/x86/dts/crownbay.dts
arch/x86/dts/galileo.dts
arch/x86/dts/minnowmax.dts
arch/x86/include/asm/arch-baytrail/gpio.h
arch/x86/include/asm/arch-ivybridge/microcode.h
arch/x86/include/asm/arch-ivybridge/model_206ax.h
arch/x86/include/asm/arch-quark/quark.h
arch/x86/include/asm/arch-queensbay/device.h [new file with mode: 0644]
arch/x86/include/asm/arch-queensbay/irq.h [new file with mode: 0644]
arch/x86/include/asm/arch-queensbay/tnc.h
arch/x86/include/asm/atomic.h [new file with mode: 0644]
arch/x86/include/asm/cpu.h
arch/x86/include/asm/e820.h
arch/x86/include/asm/global_data.h
arch/x86/include/asm/ibmpc.h
arch/x86/include/asm/interrupt.h
arch/x86/include/asm/mp.h [new file with mode: 0644]
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/msr.h
arch/x86/include/asm/mtrr.h
arch/x86/include/asm/pci.h
arch/x86/include/asm/pirq_routing.h [new file with mode: 0644]
arch/x86/include/asm/processor.h
arch/x86/include/asm/sfi.h [new file with mode: 0644]
arch/x86/include/asm/sipi.h [new file with mode: 0644]
arch/x86/include/asm/tables.h [new file with mode: 0644]
arch/x86/include/asm/turbo.h
arch/x86/include/asm/u-boot-x86.h
arch/x86/lib/Makefile
arch/x86/lib/fsp/fsp_common.c
arch/x86/lib/pirq_routing.c [new file with mode: 0644]
arch/x86/lib/sfi.c [new file with mode: 0644]
arch/x86/lib/tables.c [new file with mode: 0644]
arch/x86/lib/video.c [deleted file]
arch/x86/lib/zimage.c
board/coreboot/Kconfig [new file with mode: 0644]
board/coreboot/coreboot/Kconfig
board/google/Kconfig [new file with mode: 0644]
board/google/chromebook_link/Kconfig
board/google/chromebox_panther/Kconfig
board/intel/Kconfig [new file with mode: 0644]
board/intel/crownbay/Kconfig
board/intel/crownbay/crownbay.c
board/intel/galileo/Kconfig
board/intel/minnowmax/Kconfig
board/intel/minnowmax/minnowmax.c
common/Kconfig
common/Makefile
common/board_f.c
common/board_r.c
common/cmd_cpu.c [new file with mode: 0644]
configs/chromebook_link_defconfig
configs/chromebox_panther_defconfig
configs/coreboot-x86_defconfig
configs/crownbay_defconfig
configs/galileo_defconfig
configs/minnowmax_defconfig
doc/README.x86
drivers/Kconfig
drivers/Makefile
drivers/bios_emulator/atibios.c
drivers/core/lists.c
drivers/cpu/Kconfig [new file with mode: 0644]
drivers/cpu/Makefile [new file with mode: 0644]
drivers/cpu/cpu-uclass.c [new file with mode: 0644]
drivers/misc/smsc_lpc47m.c
drivers/pci/pci_rom.c
include/common.h
include/configs/chromebook_link.h
include/configs/crownbay.h
include/configs/galileo.h
include/configs/minnowmax.h
include/configs/x86-common.h
include/cpu.h [new file with mode: 0644]
include/display_options.h [new file with mode: 0644]
include/dm/lists.h
include/dm/uclass-id.h
include/smsc_lpc47m.h
lib/display_options.c

diff --git a/Kconfig b/Kconfig
index 41d4784..85faff7 100644 (file)
--- a/Kconfig
+++ b/Kconfig
@@ -178,7 +178,7 @@ config SYS_EXTRA_OPTIONS
          new boards should not use this option.
 
 config SYS_TEXT_BASE
-       depends on SPARC || ARC
+       depends on SPARC || ARC || X86
        hex "Text Base"
        help
          TODO: Move CONFIG_SYS_TEXT_BASE for all the architecture
diff --git a/README b/README
index ee65fdb..7958921 100644 (file)
--- a/README
+++ b/README
@@ -1873,12 +1873,6 @@ CBFS (Coreboot Filesystem) support
                boot.  See the documentation file README.video for a
                description of this variable.
 
-               CONFIG_VIDEO_VGA
-
-               Enable the VGA video / BIOS for x86. The alternative if you
-               are using coreboot is to use the coreboot frame buffer
-               driver.
-
 
 - Keyboard Support:
                CONFIG_KEYBOARD
index 1102346..200588a 100644 (file)
@@ -93,6 +93,8 @@ config X86
        select DM
        select DM_SERIAL
        select DM_GPIO
+       select DM_SPI
+       select DM_SPI_FLASH
 
 endchoice
 
index 3f1401a..8e734fd 100644 (file)
@@ -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
index 6ded0a7..043bea2 100644 (file)
@@ -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
index 8914e8b..c78b644 100644 (file)
@@ -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 (file)
index 0000000..1d48206
--- /dev/null
@@ -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,
+};
index a3e837d..9915da5 100644 (file)
@@ -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));
 }
index 84aeaf3..4c4d0c7 100644 (file)
@@ -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
index fa415dd..67eb14c 100644 (file)
@@ -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,
+};
index a9ca50b..bb4a110 100644 (file)
@@ -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,
+};
index a21d2a6..c777d36 100644 (file)
@@ -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);
index 9441666..407e451 100644 (file)
@@ -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>
 
index 37f3731..cce5923 100644 (file)
@@ -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 */
index 356bbb4..711470f 100644 (file)
@@ -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;
 }
index 11dc625..8b08c40 100644 (file)
@@ -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",
index 9a6da37..af907c5 100644 (file)
@@ -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 (file)
index 0000000..ac5753a
--- /dev/null
@@ -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);
+}
index e23b233..c209f15 100644 (file)
@@ -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);
+}
index e4b19c2..e78a271 100644 (file)
@@ -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)
index d8761fd..4599a48 100644 (file)
@@ -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 (file)
index 0000000..faf9515
--- /dev/null
@@ -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);
+}
index b7236e7..b46a7e9 100644 (file)
@@ -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 (file)
index 0000000..bcef12c
--- /dev/null
@@ -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
index b450c3c..7c7034c 100644 (file)
 
                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>;
index e81054e..fbdeade 100644 (file)
        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";
index 66af64a..60dbc5f 100644 (file)
        model = "Intel Galileo";
        compatible = "intel,galileo", "intel,quark";
 
+       aliases {
+               spi0 = "/spi";
+       };
+
        config {
                silent_console = <0>;
        };
index 8f34369..7103bc5 100644 (file)
 
        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>;
                };
        };
index ab4e059..4e8987c 100644 (file)
@@ -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_ */
index b868283..67f32cc 100644 (file)
@@ -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__
 
 /**
index 7b4f2e7..d2f9006 100644 (file)
@@ -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
index ceb583e..6dd02fd 100644 (file)
 
 /* 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 (file)
index 0000000..953b48f
--- /dev/null
@@ -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 (file)
index 0000000..e7f8616
--- /dev/null
@@ -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_ */
index 67c5e05..ad9a6c4 100644 (file)
@@ -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 (file)
index 0000000..806f787
--- /dev/null
@@ -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 */
index c839291..ebc74ad 100644 (file)
@@ -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
index d155ce9..21bc633 100644 (file)
@@ -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
 #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 */
index 5ee06eb..4d9eac6 100644 (file)
@@ -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
index c3b5187..678cde4 100644 (file)
@@ -21,4 +21,7 @@
 #define UART0_BASE     0x3f8
 #define UART1_BASE     0x2f8
 
+#define UART0_IRQ      4
+#define UART1_IRQ      3
+
 #endif
index 25abde7..0a75f89 100644 (file)
@@ -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 (file)
index 0000000..c0930fd
--- /dev/null
@@ -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_ */
index 2cbb270..38dbb31 100644 (file)
 #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
 
 /* 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
 #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
 
 #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
 
index 1955a75..c480920 100644 (file)
@@ -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)                                        \
 ({                                                             \
index fda4eae..3ad617c 100644 (file)
 /* 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__)
 
 /**
index a1969ed..56eaa25 100644 (file)
@@ -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 (file)
index 0000000..ddc08e1
--- /dev/null
@@ -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_ */
index 3e26202..7c77b90 100644 (file)
 
 #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 (file)
index 0000000..d1f0f0c
--- /dev/null
@@ -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 (file)
index 0000000..25d7d31
--- /dev/null
@@ -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 (file)
index 0000000..8146ba3
--- /dev/null
@@ -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_ */
index bb0d4b4..21b910b 100644 (file)
@@ -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,
index c743efd..be103c0 100644 (file)
@@ -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_ */
index 6c571dd..70ad19b 100644 (file)
@@ -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/
 
index f668259..001494d 100644 (file)
@@ -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 (file)
index 0000000..7a34dcf
--- /dev/null
@@ -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 (file)
index 0000000..3d36580
--- /dev/null
@@ -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 (file)
index 0000000..8031201
--- /dev/null
@@ -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 (file)
index 975949d..0000000
+++ /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();
-}
index 566b048..c3f8a73 100644 (file)
@@ -25,6 +25,8 @@
 #endif
 #include <linux/compiler.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 /*
  * Memory lay-out:
  *
 
 #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;
diff --git a/board/coreboot/Kconfig b/board/coreboot/Kconfig
new file mode 100644 (file)
index 0000000..dc9b70f
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+if VENDOR_COREBOOT
+
+choice
+       prompt "Mainboard model"
+
+config TARGET_COREBOOT
+       bool "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.
+
+endchoice
+
+source "board/coreboot/coreboot/Kconfig"
+
+endif
index 981de1f..6a04158 100644 (file)
@@ -9,6 +9,9 @@ config SYS_VENDOR
 config SYS_SOC
        default "coreboot"
 
+config SYS_TEXT_BASE
+       default 0x01110000
+
 comment "coreboot-specific options"
 
 config SYS_CONFIG_NAME
diff --git a/board/google/Kconfig b/board/google/Kconfig
new file mode 100644 (file)
index 0000000..302f68e
--- /dev/null
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+if VENDOR_GOOGLE
+
+choice
+       prompt "Mainboard model"
+
+config TARGET_CHROMEBOOK_LINK
+       bool "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 "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.
+
+endchoice
+
+source "board/google/chromebook_link/Kconfig"
+source "board/google/chromebox_panther/Kconfig"
+
+endif
index ea45472..9c8d020 100644 (file)
@@ -12,6 +12,9 @@ config SYS_SOC
 config SYS_CONFIG_NAME
        default "chromebook_link"
 
+config SYS_TEXT_BASE
+       default 0xfff00000
+
 config BOARD_SPECIFIC_OPTIONS # dummy
        def_bool y
        select X86_RESET_VECTOR
index 11df55a..e3604eb 100644 (file)
@@ -12,6 +12,9 @@ config SYS_SOC
 config SYS_CONFIG_NAME
        default "chromebox_panther"
 
+config SYS_TEXT_BASE
+       default 0xfff00000
+
 # Panther actually uses haswell, not ivybridge, so this is just a placeholder
 config BOARD_SPECIFIC_OPTIONS # dummy
        def_bool y
diff --git a/board/intel/Kconfig b/board/intel/Kconfig
new file mode 100644 (file)
index 0000000..7fe21b9
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+if VENDOR_INTEL
+
+choice
+       prompt "Mainboard model"
+
+config TARGET_CROWNBAY
+       bool "Crown Bay"
+       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_GALILEO
+       bool "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 TARGET_MINNOWMAX
+       bool "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.
+
+         Note that PCIE_ECAM_BASE is set up by the FSP so the value used
+         by U-Boot matches that value.
+
+endchoice
+
+source "board/intel/crownbay/Kconfig"
+source "board/intel/galileo/Kconfig"
+source "board/intel/minnowmax/Kconfig"
+
+endif
index 762663a..b30701a 100644 (file)
@@ -12,6 +12,9 @@ config SYS_SOC
 config SYS_CONFIG_NAME
        default "crownbay"
 
+config SYS_TEXT_BASE
+       default 0xfff00000
+
 config BOARD_SPECIFIC_OPTIONS # dummy
        def_bool y
        select X86_RESET_VECTOR
index 2a254ef..31bb320 100644 (file)
@@ -16,7 +16,7 @@ DECLARE_GLOBAL_DATA_PTR;
 
 int board_early_init_f(void)
 {
-       lpc47m_enable_serial(SERIAL_DEV, UART0_BASE);
+       lpc47m_enable_serial(SERIAL_DEV, UART0_BASE, UART0_IRQ);
 
        return 0;
 }
index 85afbbc..6515bac 100644 (file)
@@ -12,6 +12,9 @@ config SYS_SOC
 config SYS_CONFIG_NAME
        default "galileo"
 
+config SYS_TEXT_BASE
+       default 0xfff10000
+
 config BOARD_SPECIFIC_OPTIONS # dummy
        def_bool y
        select X86_RESET_VECTOR
index 43c50a5..f2a0b71 100644 (file)
@@ -12,6 +12,9 @@ config SYS_SOC
 config SYS_CONFIG_NAME
        default "minnowmax"
 
+config SYS_TEXT_BASE
+       default 0xfff00000
+
 config BOARD_SPECIFIC_OPTIONS # dummy
        def_bool y
        select X86_RESET_VECTOR
index 6e82b16..fd2070a 100644 (file)
@@ -16,7 +16,7 @@ DECLARE_GLOBAL_DATA_PTR;
 
 int board_early_init_f(void)
 {
-       lpc47m_enable_serial(SERIAL_DEV, UART0_BASE);
+       lpc47m_enable_serial(SERIAL_DEV, UART0_BASE, UART0_IRQ);
 
        return 0;
 }
index 5d7e48a..15759f7 100644 (file)
@@ -31,6 +31,14 @@ config CMD_CONSOLE
        help
          Print console devices and information.
 
+config CMD_CPU
+       bool "cpu"
+       help
+         Print information about available CPUs. This normally shows the
+         number of CPUs, type (e.g. manufacturer, architecture, product or
+         internal name) and clock frequency. Other information may be
+         available depending on the CPU driver.
+
 config CMD_LICENSE
        bool "license"
        help
index fba3830..9084c73 100644 (file)
@@ -74,6 +74,7 @@ obj-$(CONFIG_CMD_CBFS) += cmd_cbfs.o
 obj-$(CONFIG_CMD_CLK) += cmd_clk.o
 obj-$(CONFIG_CMD_CONSOLE) += cmd_console.o
 obj-$(CONFIG_CMD_CPLBINFO) += cmd_cplbinfo.o
+obj-$(CONFIG_CMD_CPU) += cmd_cpu.o
 obj-$(CONFIG_DATAFLASH_MMC_SELECT) += cmd_dataflash_mmc_mux.o
 obj-$(CONFIG_CMD_DATE) += cmd_date.o
 obj-$(CONFIG_CMD_DEMO) += cmd_demo.o
index 322e070..fbbad1b 100644 (file)
@@ -73,7 +73,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #endif
 
 /*
- * sjg: IMO this code should be
+ * TODO(sjg@chromium.org): IMO this code should be
  * refactored to a single function, something like:
  *
  * void led_set_state(enum led_colour_t colour, int on);
@@ -300,7 +300,7 @@ __weak ulong board_get_usable_ram_top(ulong total_size)
 {
 #ifdef CONFIG_SYS_SDRAM_BASE
        /*
-        * Detect whether we have so much RAM it goes past the end of our
+        * Detect whether we have so much RAM that it goes past the end of our
         * 32-bit address space. If so, clip the usable RAM so it doesn't.
         */
        if (gd->ram_top < CONFIG_SYS_SDRAM_BASE)
@@ -507,7 +507,7 @@ static int reserve_global_data(void)
 static int reserve_fdt(void)
 {
        /*
-        * If the device tree is sitting immediate above our image then we
+        * If the device tree is sitting immediately above our image then we
         * must relocate it. If it is embedded in the data section, then it
         * will be relocated with other data.
         */
@@ -535,7 +535,7 @@ static int reserve_stacks(void)
        gd->start_addr_sp &= ~0xf;
 
        /*
-        * let the architecture specific code tailor gd->start_addr_sp and
+        * let the architecture-specific code tailor gd->start_addr_sp and
         * gd->irq_sp
         */
        return arch_reserve_stacks();
@@ -556,7 +556,6 @@ static int setup_board_part1(void)
        /*
         * Save local variables to board info struct
         */
-
        bd->bi_memstart = CONFIG_SYS_SDRAM_BASE;        /* start of memory */
        bd->bi_memsize = gd->ram_size;                  /* size in bytes */
 
index 307124e..1a46f62 100644 (file)
@@ -779,7 +779,7 @@ init_fnc_t init_sequence_r[] = {
        initr_flash,
 #endif
        INIT_FUNC_WATCHDOG_RESET
-#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
+#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_X86)
        /* initialize higher level parts of CPU like time base and timers */
        cpu_init_r,
 #endif
diff --git a/common/cmd_cpu.c b/common/cmd_cpu.c
new file mode 100644 (file)
index 0000000..c3e229f
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <cpu.h>
+#include <dm.h>
+
+static const char *cpu_feature_name[CPU_FEAT_COUNT] = {
+       "L1 cache",
+       "MMU",
+};
+
+static int print_cpu_list(bool detail)
+{
+       struct udevice *dev;
+       struct uclass *uc;
+       char buf[100];
+       int ret;
+
+       ret = uclass_get(UCLASS_CPU, &uc);
+       if (ret) {
+               printf("Cannot find CPU uclass\n");
+               return ret;
+       }
+       uclass_foreach_dev(dev, uc) {
+               struct cpu_platdata *plat = dev_get_parent_platdata(dev);
+               struct cpu_info info;
+               bool first;
+               int i;
+
+               ret = cpu_get_desc(dev, buf, sizeof(buf));
+               printf("%3d: %-10s %s\n", dev->seq, dev->name,
+                      ret ? "<no description>" : buf);
+               if (!detail)
+                       continue;
+               ret = cpu_get_info(dev, &info);
+               if (ret) {
+                       printf("\t(no detail available");
+                       if (ret != -ENOSYS)
+                               printf(": err=%d\n", ret);
+                       printf(")\n");
+                       continue;
+               }
+               printf("\tID = %d, freq = ", plat->cpu_id);
+               print_freq(info.cpu_freq, "");
+               first = true;
+               for (i = 0; i < CPU_FEAT_COUNT; i++) {
+                       if (info.features & (1 << i)) {
+                               printf("%s%s", first ? ": " : ", ",
+                                      cpu_feature_name[i]);
+                               first = false;
+                       }
+               }
+               printf("\n");
+       }
+
+       return 0;
+}
+
+static int do_cpu_list(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+       if (print_cpu_list(false))
+               return CMD_RET_FAILURE;
+
+       return 0;
+}
+
+static int do_cpu_detail(cmd_tbl_t *cmdtp, int flag, int argc,
+                        char *const argv[])
+{
+       if (print_cpu_list(true))
+               return CMD_RET_FAILURE;
+
+       return 0;
+}
+
+static cmd_tbl_t cmd_cpu_sub[] = {
+       U_BOOT_CMD_MKENT(list, 2, 1, do_cpu_list, "", ""),
+       U_BOOT_CMD_MKENT(detail, 4, 0, do_cpu_detail, "", ""),
+};
+
+/*
+ * Process a cpu sub-command
+ */
+static int do_cpu(cmd_tbl_t *cmdtp, int flag, int argc,
+                      char * const argv[])
+{
+       cmd_tbl_t *c = NULL;
+
+       /* Strip off leading 'cpu' command argument */
+       argc--;
+       argv++;
+
+       if (argc)
+               c = find_cmd_tbl(argv[0], cmd_cpu_sub, ARRAY_SIZE(cmd_cpu_sub));
+
+       if (c)
+               return c->cmd(cmdtp, flag, argc, argv);
+       else
+               return CMD_RET_USAGE;
+}
+
+U_BOOT_CMD(
+       cpu, 2, 1, do_cpu,
+       "display information about CPUs",
+       "list   - list available CPUs\n"
+       "cpu detail     - show CPU detail"
+);
index fe2610a..81222d2 100644 (file)
@@ -1,5 +1,5 @@
-CONFIG_SYS_EXTRA_OPTIONS="SYS_TEXT_BASE=0xfff00000"
 CONFIG_X86=y
+CONFIG_VENDOR_GOOGLE=y
 CONFIG_TARGET_CHROMEBOOK_LINK=y
 CONFIG_OF_CONTROL=y
 CONFIG_OF_SEPARATE=y
index 0613cd6..91189c9 100644 (file)
@@ -1,5 +1,5 @@
-CONFIG_SYS_EXTRA_OPTIONS="SYS_TEXT_BASE=0xfff00000"
 CONFIG_X86=y
+CONFIG_VENDOR_GOOGLE=y
 CONFIG_TARGET_CHROMEBOX_PANTHER=y
 CONFIG_OF_CONTROL=y
 CONFIG_OF_SEPARATE=y
index 0249172..799853f 100644 (file)
@@ -1,5 +1,5 @@
-CONFIG_SYS_EXTRA_OPTIONS="SYS_TEXT_BASE=0x01110000"
 CONFIG_X86=y
+CONFIG_VENDOR_COREBOOT=y
 CONFIG_TARGET_COREBOOT=y
 CONFIG_OF_CONTROL=y
 CONFIG_DM_PCI=y
index ce90553..61d1fcc 100644 (file)
@@ -1,6 +1,7 @@
-CONFIG_SYS_EXTRA_OPTIONS="SYS_TEXT_BASE=0xfff00000"
 CONFIG_X86=y
+CONFIG_VENDOR_INTEL=y
 CONFIG_TARGET_CROWNBAY=y
 CONFIG_OF_CONTROL=y
 CONFIG_OF_SEPARATE=y
 CONFIG_DEFAULT_DEVICE_TREE="crownbay"
+CONFIG_GENERATE_PIRQ_TABLE=y
index 9b0f969..1a54ba5 100644 (file)
@@ -1,5 +1,5 @@
-CONFIG_SYS_EXTRA_OPTIONS="SYS_TEXT_BASE=0xfff10000"
 CONFIG_X86=y
+CONFIG_VENDOR_INTEL=y
 CONFIG_TARGET_GALILEO=y
 CONFIG_OF_CONTROL=y
 CONFIG_OF_SEPARATE=y
index d124289..426fb52 100644 (file)
@@ -1,11 +1,14 @@
-CONFIG_SYS_EXTRA_OPTIONS="SYS_TEXT_BASE=0xfff00000"
 CONFIG_X86=y
+CONFIG_VENDOR_INTEL=y
 CONFIG_TARGET_MINNOWMAX=y
 CONFIG_OF_CONTROL=y
 CONFIG_OF_SEPARATE=y
 CONFIG_DEFAULT_DEVICE_TREE="minnowmax"
-CONFIG_VIDEO_X86=y
 CONFIG_FRAMEBUFFER_SET_VESA_MODE=y
 CONFIG_FRAMEBUFFER_VESA_MODE_11A=y
 CONFIG_MMCONF_BASE_ADDRESS=0xe0000000
 CONFIG_HAVE_INTEL_ME=y
+CONFIG_GENERATE_SFI_TABLE=y
+CONFIG_CPU=y
+CONFIG_CMD_CPU=y
+CONFIG_SMP=y
index 0355d1c..ef13fb4 100644 (file)
@@ -75,7 +75,7 @@ Find the following files:
 
 * ./mainboard/google/link/descriptor.bin
 * ./mainboard/google/link/me.bin
-* ./northbridge/intel/sandybridge/systemagent-ivybridge.bin
+* ./northbridge/intel/sandybridge/systemagent-r6.bin
 
 The 3rd one should be renamed to mrc.bin.
 As for the video ROM, you can get it here [2].
@@ -127,15 +127,32 @@ board/intel/minnowmax/fsp.bin
 Obtain the VGA RAM (Vga.dat at the time of writing) and put it into the same
 directory: board/intel/minnowmax/vga.bin
 
-You still need two more binary blobs. These come from the sample SPI image
-provided in the FSP (SPI.bin at the time of writing).
+You still need two more binary blobs. The first comes from the original
+firmware image available from:
+
+http://firmware.intel.com/sites/default/files/2014-WW42.4-MinnowBoardMax.73-64-bit.bin_Release.zip
+
+Unzip it:
+
+   $ unzip 2014-WW42.4-MinnowBoardMax.73-64-bit.bin_Release.zip
 
 Use ifdtool in the U-Boot tools directory to extract the images from that
 file, for example:
 
+   $ ./tools/ifdtool -x MNW2MAX1.X64.0073.R02.1409160934.bin
+
+This will provide the descriptor file - copy this into the correct place:
+
+   $ cp flashregion_0_flashdescriptor.bin board/intel/minnowmax/descriptor.bin
+
+Then do the same with the sample SPI image provided in the FSP (SPI.bin at
+the time of writing) to obtain the last image. Note that this will also
+produce a flash descriptor file, but it does not seem to work, probably
+because it is not designed for the Minnowmax. That is why you need to get
+the flash descriptor from the original firmware as above.
+
    $ ./tools/ifdtool -x BayleyBay/SPI.bin
    $ cp flashregion_2_intel_me.bin board/intel/minnowmax/me.bin
-   $ cp flashregion_0_flashdescriptor.bin board/intel/minnowmax/descriptor.bin
 
 Now you can build U-Boot and obtain u-boot.rom
 
index 941aa0c..1f40887 100644 (file)
@@ -2,6 +2,8 @@ menu "Device Drivers"
 
 source "drivers/core/Kconfig"
 
+source "drivers/cpu/Kconfig"
+
 source "drivers/demo/Kconfig"
 
 source "drivers/pci/Kconfig"
index 5ef58c0..405b64b 100644 (file)
@@ -3,6 +3,7 @@ obj-$(CONFIG_DM_DEMO) += demo/
 obj-$(CONFIG_BIOSEMU) += bios_emulator/
 obj-y += block/
 obj-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount/
+obj-$(CONFIG_CPU) += cpu/
 obj-y += crypto/
 obj-$(CONFIG_FPGA) += fpga/
 obj-y += hwmon/
index 7ea5fa6..dec6230 100644 (file)
@@ -502,7 +502,8 @@ int biosemu_run(pci_dev_t pcidev, uchar *bios_rom, int bios_len,
        */
        if (clean_up) {
                BE_exit();
-               if (vga_info->BIOSImage)
+               if (vga_info->BIOSImage &&
+                   (u32)(vga_info->BIOSImage) != 0xc0000)
                        free(vga_info->BIOSImage);
                free(vga_info);
                vga_info = NULL;
index 647e390..0c49d99 100644 (file)
@@ -74,6 +74,13 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only)
 int device_bind_driver(struct udevice *parent, const char *drv_name,
                       const char *dev_name, struct udevice **devp)
 {
+       return device_bind_driver_to_node(parent, drv_name, dev_name, -1, devp);
+}
+
+int device_bind_driver_to_node(struct udevice *parent, const char *drv_name,
+                              const char *dev_name, int node,
+                              struct udevice **devp)
+{
        struct driver *drv;
        int ret;
 
@@ -82,7 +89,7 @@ int device_bind_driver(struct udevice *parent, const char *drv_name,
                printf("Cannot find driver '%s'\n", drv_name);
                return -ENOENT;
        }
-       ret = device_bind(parent, drv, dev_name, NULL, -1, devp);
+       ret = device_bind(parent, drv, dev_name, NULL, node, devp);
        if (ret) {
                printf("Cannot create device named '%s' (err=%d)\n",
                       dev_name, ret);
diff --git a/drivers/cpu/Kconfig b/drivers/cpu/Kconfig
new file mode 100644 (file)
index 0000000..0d1424d
--- /dev/null
@@ -0,0 +1,8 @@
+config CPU
+       bool "Enable CPU drivers using Driver Model"
+       help
+         This allows drivers to be provided for CPUs and their type to be
+         specified in the board's device tree. For boards which support
+         multiple CPUs, then normally have to be set up in U-Boot so that
+         they can work correctly in the OS. This provides a framework for
+         finding out information about available CPUs and making changes.
diff --git a/drivers/cpu/Makefile b/drivers/cpu/Makefile
new file mode 100644 (file)
index 0000000..8710160
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2015 Google, Inc
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+obj-$(CONFIG_CPU) += cpu-uclass.o
diff --git a/drivers/cpu/cpu-uclass.c b/drivers/cpu/cpu-uclass.c
new file mode 100644 (file)
index 0000000..ab18ee2
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+int cpu_get_desc(struct udevice *dev, char *buf, int size)
+{
+       struct cpu_ops *ops = cpu_get_ops(dev);
+
+       if (!ops->get_desc)
+               return -ENOSYS;
+
+       return ops->get_desc(dev, buf, size);
+}
+
+int cpu_get_info(struct udevice *dev, struct cpu_info *info)
+{
+       struct cpu_ops *ops = cpu_get_ops(dev);
+
+       if (!ops->get_desc)
+               return -ENOSYS;
+
+       return ops->get_info(dev, info);
+}
+
+U_BOOT_DRIVER(cpu_bus) = {
+       .name   = "cpu_bus",
+       .id     = UCLASS_SIMPLE_BUS,
+       .per_child_platdata_auto_alloc_size = sizeof(struct cpu_platdata),
+};
+
+static int uclass_cpu_init(struct uclass *uc)
+{
+       struct udevice *dev;
+       int node;
+       int ret;
+
+       node = fdt_path_offset(gd->fdt_blob, "/cpus");
+       if (node < 0)
+               return 0;
+
+       ret = device_bind_driver_to_node(dm_root(), "cpu_bus", "cpus", node,
+                                        &dev);
+
+       return ret;
+}
+
+UCLASS_DRIVER(cpu) = {
+       .id             = UCLASS_CPU,
+       .name           = "cpu",
+       .flags          = DM_UC_FLAG_SEQ_ALIAS,
+       .init           = uclass_cpu_init,
+};
index d51f8e3..1e50d5b 100644 (file)
@@ -22,12 +22,13 @@ static void pnp_exit_conf_state(u16 dev)
        outb(0xaa, port);
 }
 
-void lpc47m_enable_serial(u16 dev, u16 iobase)
+void lpc47m_enable_serial(u16 dev, u16 iobase, u8 irq)
 {
        pnp_enter_conf_state(dev);
        pnp_set_logical_device(dev);
        pnp_set_enable(dev, 0);
        pnp_set_iobase(dev, PNP_IDX_IO0, iobase);
+       pnp_set_irq(dev, PNP_IDX_IRQ0, irq);
        pnp_set_enable(dev, 1);
        pnp_exit_conf_state(dev);
 }
index 48c0a77..37450c8 100644 (file)
@@ -67,6 +67,7 @@ static int pci_rom_probe(pci_dev_t dev, uint class,
        struct pci_rom_data *rom_data;
        u16 vendor, device;
        u16 rom_vendor, rom_device;
+       u32 rom_class;
        u32 vendev;
        u32 mapped_vendev;
        u32 rom_address;
@@ -125,20 +126,20 @@ static int pci_rom_probe(pci_dev_t dev, uint class,
                /* Continue anyway */
        }
 
-       debug("PCI ROM image, Class Code %04x%02x, Code Type %02x\n",
-             rom_data->class_hi, rom_data->class_lo, rom_data->type);
+       rom_class = (le16_to_cpu(rom_data->class_hi) << 8) | rom_data->class_lo;
+       debug("PCI ROM image, Class Code %06x, Code Type %02x\n",
+             rom_class, rom_data->type);
 
-       if (class != ((rom_data->class_hi << 8) | rom_data->class_lo)) {
-               debug("Class Code mismatch ROM %08x, dev %08x\n",
-                     (rom_data->class_hi << 8) | rom_data->class_lo,
-                     class);
+       if (class != rom_class) {
+               debug("Class Code mismatch ROM %06x, dev %06x\n",
+                     rom_class, class);
        }
        *hdrp = rom_header;
 
        return 0;
 }
 
-int pci_rom_load(uint16_t class, struct pci_rom_header *rom_header,
+int pci_rom_load(struct pci_rom_header *rom_header,
                 struct pci_rom_header **ram_headerp)
 {
        struct pci_rom_data *rom_data;
@@ -232,17 +233,18 @@ int pci_run_vga_bios(pci_dev_t dev, int (*int15_handler)(void), int exec_method)
 {
        struct pci_rom_header *rom, *ram;
        int vesa_mode = -1;
-       uint16_t class;
+       uint class;
        bool emulate;
        int ret;
 
        /* Only execute VGA ROMs */
-       pci_read_config_word(dev, PCI_CLASS_DEVICE, &class);
-       if ((class ^ PCI_CLASS_DISPLAY_VGA) & 0xff00) {
+       pci_read_config_dword(dev, PCI_REVISION_ID, &class);
+       if (((class >> 16) ^ PCI_CLASS_DISPLAY_VGA) & 0xff00) {
                debug("%s: Class %#x, should be %#x\n", __func__, class,
                      PCI_CLASS_DISPLAY_VGA);
                return -ENODEV;
        }
+       class >>= 8;
 
        if (!should_load_oprom(dev))
                return -ENXIO;
@@ -251,7 +253,7 @@ int pci_run_vga_bios(pci_dev_t dev, int (*int15_handler)(void), int exec_method)
        if (ret)
                return ret;
 
-       ret = pci_rom_load(class, rom, &ram);
+       ret = pci_rom_load(rom, &ram);
        if (ret)
                return ret;
 
index cde3474..d4d704a 100644 (file)
@@ -192,22 +192,8 @@ int        cpu_init(void);
 
 /* */
 phys_size_t initdram (int);
-int    display_options (void);
 
-/**
- * print_size() - Print a size with a suffic
- *
- * print sizes as "xxx KiB", "xxx.y KiB", "xxx MiB", "xxx.y MiB",
- * xxx GiB, xxx.y GiB, etc as needed; allow for optional trailing string
- * (like "\n")
- *
- * @size:      Size to print
- * @suffix     String to print after the size
- */
-void print_size(uint64_t size, const char *suffix);
-
-int print_buffer(ulong addr, const void *data, uint width, uint count,
-                uint linelen);
+#include <display_options.h>
 
 /* common/main.c */
 void   main_loop       (void);
index 5265787..f2d798a 100644 (file)
@@ -16,4 +16,7 @@
 #include <configs/x86-common.h>
 #include <configs/x86-chromebook.h>
 
+#define CONFIG_ENV_SECT_SIZE           0x1000
+#define CONFIG_ENV_OFFSET              0x003f8000
+
 #endif /* __CONFIG_H */
index df32f2a..4fef433 100644 (file)
@@ -15,6 +15,7 @@
 
 #define CONFIG_SYS_MONITOR_LEN         (1 << 20)
 #define CONFIG_BOARD_EARLY_INIT_F
+#define CONFIG_ARCH_MISC_INIT
 
 #define CONFIG_NR_DRAM_BANKS           1
 
 #undef CONFIG_CFB_CONSOLE
 
 /* Environment configuration */
-#undef CONFIG_ENV_IS_NOWHERE
-#undef CONFIG_ENV_SIZE
-#define CONFIG_ENV_IS_IN_SPI_FLASH
-#define CONFIG_ENV_SIZE                        0x1000
 #define CONFIG_ENV_SECT_SIZE           0x1000
 #define CONFIG_ENV_OFFSET              0
 
index 288acf3..f780b8f 100644 (file)
 #define CONFIG_PHYLIB
 
 /* Environment configuration */
-#undef CONFIG_ENV_IS_NOWHERE
-#undef CONFIG_ENV_SIZE
-#define CONFIG_ENV_IS_IN_SPI_FLASH
-#define CONFIG_ENV_SIZE                        0x1000
 #define CONFIG_ENV_SECT_SIZE           0x1000
 #define CONFIG_ENV_OFFSET              0
 
index 823e051..2a1915d 100644 (file)
@@ -42,7 +42,7 @@
 
 #define CONFIG_SCSI_DEV_LIST            \
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VALLEYVIEW_SATA}
-#define CONFIG_SPI_FLASH_SST
+#define CONFIG_SPI_FLASH_STMICRO
 
 #define CONFIG_MMC
 #define CONFIG_SDHCI
@@ -69,4 +69,8 @@
 /* Avoid a warning in the Realtek Ethernet driver */
 #define CONFIG_SYS_CACHELINE_SIZE 16
 
+/* Environment in SPI flash is unsupported for now */
+#undef CONFIG_ENV_IS_IN_SPI_FLASH
+#define CONFIG_ENV_IS_NOWHERE
+
 #endif /* __CONFIG_H */
index 9571c65..3e21e09 100644 (file)
@@ -20,6 +20,7 @@
 #define CONFIG_PHYSMEM
 #define CONFIG_DISPLAY_BOARDINFO_LATE
 #define CONFIG_DISPLAY_CPUINFO
+#define CONFIG_LAST_STAGE_INIT
 
 #define CONFIG_LMB
 #define CONFIG_OF_LIBFDT
 /*-----------------------------------------------------------------------
  * Environment configuration
  */
-#define CONFIG_ENV_IS_NOWHERE
+#define CONFIG_ENV_IS_IN_SPI_FLASH
 #define CONFIG_ENV_SIZE                        0x01000
 
 /*-----------------------------------------------------------------------
diff --git a/include/cpu.h b/include/cpu.h
new file mode 100644 (file)
index 0000000..34c60bc
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __CPU_H
+#define __CPU_H
+
+/**
+ * struct cpu_platdata - platform data for a CPU
+ *
+ * This can be accessed with dev_get_parent_platdata() for any UCLASS_CPU
+ * device.
+ *
+ * @cpu_id:    Platform-specific way of identifying the CPU.
+ */
+struct cpu_platdata {
+       int cpu_id;
+};
+
+/* CPU features - mostly just a placeholder for now */
+enum {
+       CPU_FEAT_L1_CACHE       = 0,    /* Supports level 1 cache */
+       CPU_FEAT_MMU            = 1,    /* Supports virtual memory */
+
+       CPU_FEAT_COUNT,
+};
+
+/**
+ * struct cpu_info - Information about a CPU
+ *
+ * @cpu_freq:  Current CPU frequency in Hz
+ * @features:  Flags for supported CPU features
+ */
+struct cpu_info {
+       ulong cpu_freq;
+       ulong features;
+};
+
+struct cpu_ops {
+       /**
+        * get_desc() - Get a description string for a CPU
+        *
+        * @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 (*get_desc)(struct udevice *dev, char *buf, int size);
+
+       /**
+        * get_info() - Get information about a CPU
+        *
+        * @dev:        Device to check (UCLASS_CPU)
+        * @info:       Returns CPU info
+        * @return 0 if OK, -ve on error
+        */
+       int (*get_info)(struct udevice *dev, struct cpu_info *info);
+};
+
+#define cpu_get_ops(dev)        ((struct cpu_ops *)(dev)->driver->ops)
+
+/**
+ * cpu_get_desc() - Get a description string for a CPU
+ *
+ * @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 cpu_get_desc(struct udevice *dev, char *buf, int size);
+
+/**
+ * cpu_get_info() - Get information about a CPU
+ *
+ * @dev:       Device to check (UCLASS_CPU)
+ * @info:      Returns CPU info
+ * @return 0 if OK, -ve on error
+ */
+int cpu_get_info(struct udevice *dev, struct cpu_info *info);
+
+#endif
diff --git a/include/display_options.h b/include/display_options.h
new file mode 100644 (file)
index 0000000..ac44c45
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __DISPLAY_OPTIONS_H
+#define __DISPLAY_OPTIONS_H
+
+/**
+ * print_size() - Print a size with a suffix
+ *
+ * Print sizes as "xxx KiB", "xxx.y KiB", "xxx MiB", "xxx.y MiB",
+ * xxx GiB, xxx.y GiB, etc as needed; allow for optional trailing string
+ * (like "\n")
+ *
+ * @size:      Size to print
+ * @suffix     String to print after the size
+ */
+void print_size(uint64_t size, const char *suffix);
+
+/**
+ * print_freq() - Print a frequency with a suffix
+ *
+ * Print frequencies as "x.xx GHz", "xxx KHz", etc as needed; allow for
+ * optional trailing string (like "\n")
+ *
+ * @freq:      Frequency to print in Hz
+ * @suffix     String to print after the frequency
+ */
+void print_freq(uint64_t freq, const char *suffix);
+
+/**
+ * print_buffer() - Print data buffer in hex and ascii form
+ *
+ * Data reads are buffered so that each memory address is only read once.
+ * This is useful when displaying the contents of volatile registers.
+ *
+ * @addr:      Starting address to display at start of line
+ * @data:      pointer to data buffer
+ * @width:     data value width.  May be 1, 2, or 4.
+ * @count:     number of values to display
+ * @linelen:   Number of values to print per line; specify 0 for default length
+ */
+int print_buffer(ulong addr, const void *data, uint width, uint count,
+                uint linelen);
+
+/**
+ * display_options() - display the version string / build tag
+ *
+ * This displays the U-Boot version string. If a build tag is available this
+ * is displayed also.
+ */
+int display_options(void);
+
+#endif
index 1b50af9..61610e6 100644 (file)
@@ -73,4 +73,20 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
 int device_bind_driver(struct udevice *parent, const char *drv_name,
                       const char *dev_name, struct udevice **devp);
 
+/**
+ * device_bind_driver_to_node() - bind a device to a driver for a node
+ *
+ * This binds a new device to a driver for a given device tree node. This
+ * should only be needed if the node lacks a compatible strings.
+ *
+ * @parent:    Parent device
+ * @drv_name:  Name of driver to attach to this parent
+ * @dev_name:  Name of the new device thus created
+ * @node:      Device tree node
+ * @devp:      Returns the newly bound device
+ */
+int device_bind_driver_to_node(struct udevice *parent, const char *drv_name,
+                              const char *dev_name, int node,
+                              struct udevice **devp);
+
 #endif
index fddfd35..395e25a 100644 (file)
@@ -45,6 +45,7 @@ enum uclass_id {
        UCLASS_USB_HUB,         /* USB hub */
        UCLASS_USB_DEV_GENERIC, /* USB generic device */
        UCLASS_MASS_STORAGE,    /* Mass storage device */
+       UCLASS_CPU,             /* CPU, typically part of an SoC */
 
        UCLASS_COUNT,
        UCLASS_INVALID = -1,
index bffd622..32b069d 100644 (file)
@@ -13,7 +13,8 @@
  *
  * @dev: High 8 bits = Super I/O port, low 8 bits = logical device number.
  * @iobase: Processor I/O port address to assign to this serial device.
+ * @irq: Processor IRQ number to assign to this serial device.
  */
-void lpc47m_enable_serial(u16 dev, u16 iobase);
+void lpc47m_enable_serial(u16 dev, u16 iobase, u8 irq);
 
 #endif /* _SMSC_LPC47M_H_ */
index d5d17b2..24d8f55 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <config.h>
 #include <common.h>
+#include <div64.h>
 #include <inttypes.h>
 #include <version.h>
 #include <linux/ctype.h>
@@ -22,6 +23,47 @@ int display_options (void)
        return 0;
 }
 
+void print_freq(uint64_t freq, const char *s)
+{
+       unsigned long m = 0, n;
+       uint32_t f;
+       static const char names[] = {'G', 'M', 'K'};
+       unsigned long d = 1e9;
+       char c = 0;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(names); i++, d /= 1000) {
+               if (freq >= d) {
+                       c = names[i];
+                       break;
+               }
+       }
+
+       if (!c) {
+               printf("%" PRIu64 " Hz%s", freq, s);
+               return;
+       }
+
+       f = do_div(freq, d);
+       n = freq;
+
+       /* If there's a remainder, show the first few digits */
+       if (f) {
+               m = f;
+               while (m > 1000)
+                       m /= 10;
+               while (m && !(m % 10))
+                       m /= 10;
+               if (m >= 100)
+                       m = (m / 10) + (m % 100 >= 50);
+       }
+
+       printf("%lu", n);
+       if (m)
+               printf(".%ld", m);
+       printf(" %cHz%s", c, s);
+}
+
 void print_size(uint64_t size, const char *s)
 {
        unsigned long m = 0, n;
@@ -63,19 +105,6 @@ void print_size(uint64_t size, const char *s)
        printf (" %ciB%s", c, s);
 }
 
-/*
- * Print data buffer in hex and ascii form to the terminal.
- *
- * data reads are buffered so that each memory address is only read once.
- * Useful when displaying the contents of volatile registers.
- *
- * parameters:
- *    addr: Starting address to display at start of line
- *    data: pointer to data buffer
- *    width: data value width.  May be 1, 2, or 4.
- *    count: number of values to display
- *    linelen: Number of values to print per line; specify 0 for default length
- */
 #define MAX_LINE_LENGTH_BYTES (64)
 #define DEFAULT_LINE_LENGTH_BYTES (16)
 int print_buffer(ulong addr, const void *data, uint width, uint count,