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
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
select DM
select DM_SERIAL
select DM_GPIO
+ select DM_SPI
+ select DM_SPI_FLASH
endchoice
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
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"
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"
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
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
# SPDX-License-Identifier: GPL-2.0+
#
+obj-y += cpu.o
obj-y += early_uart.o
obj-y += fsp_configs.o
obj-y += pci.o
--- /dev/null
+/*
+ * 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,
+};
int cpu_mmc_init(bd_t *bis)
{
- printf("mmc init\n");
return pci_mmc_init("ValleyView SDHCI", mmc_supported,
ARRAY_SIZE(mmc_supported));
}
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
.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,
+};
#include <common.h>
#include <command.h>
+#include <cpu.h>
+#include <dm.h>
#include <errno.h>
#include <malloc.h>
#include <asm/control_regs.h>
#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;
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);
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)
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",
#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,
+};
return 0;
}
+void *x86_get_idt(void)
+{
+ return &idt_ptr;
+}
+
void __do_irq(int irq)
{
printf("Unhandled IRQ : %d\n", irq);
#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>
/* 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 */
/* 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 */
int intel_early_me_init_done(u8 status)
{
- u8 reset;
int count;
u32 mebase_l, mebase_h;
struct me_hfs hfs;
/* Check status after acknowledgement */
intel_early_me_status();
- reset = 0;
switch (hfs.ack_data) {
case ME_HFS_ACK_CONTINUE:
/* Continue to boot */
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:
break;
}
- /* Perform the requested reset */
- if (reset) {
- outb(reset, 0xcf9);
- cpu_hlt();
- }
return -1;
}
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",
/* 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 */
--- /dev/null
+/*
+ * 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 = ¶ms->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);
+}
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);
+}
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;
*/
quark_setup_bars();
+ /* Turn on legacy segments (A/B/E/F) decode to system RAM */
+ quark_enable_legacy_seg();
+
unprotect_spi_flash();
return 0;
void reset_cpu(ulong addr)
{
/* cold reset */
- outb(0x08, PORT_RESET);
+ x86_full_reset();
}
int cpu_mmc_init(bd_t *bis)
#
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
--- /dev/null
+/*
+ * 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);
+}
#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>
{
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)
return 0;
}
+
+int arch_misc_init(void)
+{
+ pirq_init();
+
+ return 0;
+}
--- /dev/null
+/*
+ * 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
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>;
model = "Intel Crown Bay";
compatible = "intel,crownbay", "intel,queensbay";
+ aliases {
+ spi0 = "/spi";
+ };
+
config {
silent_console = <0>;
};
spi {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "intel,ich7";
+ compatible = "intel,ich-spi";
spi-flash@0 {
reg = <0>;
compatible = "sst,25vf016b", "spi-flash";
model = "Intel Galileo";
compatible = "intel,galileo", "intel,quark";
+ aliases {
+ spi0 = "/spi";
+ };
+
config {
silent_console = <0>;
};
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>;
};
};
#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_ */
#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__
/**
#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
#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
/* 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
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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_ */
#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_ */
--- /dev/null
+#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 */
return ((f1^f2) & flag) != 0;
}
+static inline void mfence(void)
+{
+ __asm__ __volatile__("mfence" : : : "memory");
+}
+
/**
* cpu_enable_paging_pae() - Enable PAE-paging
*
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
#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 */
/* MRC training data to save for the next boot */
char *mrc_output;
unsigned int mrc_output_len;
+ void *gdt; /* Global descriptor table */
};
#endif
#define UART0_BASE 0x3f8
#define UART1_BASE 0x2f8
+#define UART0_IRQ 4
+#define UART1_IRQ 3
+
#endif
*/
void configure_irq_trigger(int int_num, bool is_level_triggered);
+void *x86_get_idt(void);
+
#endif
--- /dev/null
+/*
+ * 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_ */
#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
#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
#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
#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) \
({ \
/* 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__)
/**
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_ */
--- /dev/null
+/*
+ * 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_ */
#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");
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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_ */
#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,
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)
{
void quick_ram_check(void);
+int x86_init_cpus(void);
+
#define PCI_VGA_RAM_IMAGE_START 0xc0000
#endif /* _U_BOOT_I386_H_ */
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/
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;
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
+}
+++ /dev/null
-/*
- * (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();
-}
#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;
--- /dev/null
+#
+# 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
config SYS_SOC
default "coreboot"
+config SYS_TEXT_BASE
+ default 0x01110000
+
comment "coreboot-specific options"
config SYS_CONFIG_NAME
--- /dev/null
+#
+# 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
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
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
--- /dev/null
+#
+# 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
config SYS_CONFIG_NAME
default "crownbay"
+config SYS_TEXT_BASE
+ default 0xfff00000
+
config BOARD_SPECIFIC_OPTIONS # dummy
def_bool y
select X86_RESET_VECTOR
int board_early_init_f(void)
{
- lpc47m_enable_serial(SERIAL_DEV, UART0_BASE);
+ lpc47m_enable_serial(SERIAL_DEV, UART0_BASE, UART0_IRQ);
return 0;
}
config SYS_CONFIG_NAME
default "galileo"
+config SYS_TEXT_BASE
+ default 0xfff10000
+
config BOARD_SPECIFIC_OPTIONS # dummy
def_bool y
select X86_RESET_VECTOR
config SYS_CONFIG_NAME
default "minnowmax"
+config SYS_TEXT_BASE
+ default 0xfff00000
+
config BOARD_SPECIFIC_OPTIONS # dummy
def_bool y
select X86_RESET_VECTOR
int board_early_init_f(void)
{
- lpc47m_enable_serial(SERIAL_DEV, UART0_BASE);
+ lpc47m_enable_serial(SERIAL_DEV, UART0_BASE, UART0_IRQ);
return 0;
}
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
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
#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);
{
#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)
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.
*/
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();
/*
* 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 */
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
--- /dev/null
+/*
+ * 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"
+);
-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
-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
-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
-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
-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
-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
* ./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].
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
source "drivers/core/Kconfig"
+source "drivers/cpu/Kconfig"
+
source "drivers/demo/Kconfig"
source "drivers/pci/Kconfig"
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/
*/
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;
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;
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);
--- /dev/null
+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.
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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,
+};
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);
}
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;
/* 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;
{
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;
if (ret)
return ret;
- ret = pci_rom_load(class, rom, &ram);
+ ret = pci_rom_load(rom, &ram);
if (ret)
return ret;
/* */
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);
#include <configs/x86-common.h>
#include <configs/x86-chromebook.h>
+#define CONFIG_ENV_SECT_SIZE 0x1000
+#define CONFIG_ENV_OFFSET 0x003f8000
+
#endif /* __CONFIG_H */
#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
#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
#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
/* 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 */
#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
/*-----------------------------------------------------------------------
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
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
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,
*
* @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_ */
#include <config.h>
#include <common.h>
+#include <div64.h>
#include <inttypes.h>
#include <version.h>
#include <linux/ctype.h>
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;
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,