Commit 746667f1 authored by Tom Rini's avatar Tom Rini
Browse files

Merge git://git.denx.de/u-boot-x86



Conflicts:
	arch/x86/cpu/Makefile
Signed-off-by: default avatarTom Rini <trini@ti.com>
parents 6c016485 fe5b9b44
......@@ -746,6 +746,9 @@ ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%)
endif
ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf
# We can't do this yet due to the need for binary blobs
# ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom
# enable combined SPL/u-boot/dtb rules for tegra
ifneq ($(CONFIG_TEGRA),)
ifeq ($(CONFIG_SPL),y)
......@@ -814,7 +817,8 @@ OBJCOPYFLAGS_u-boot.srec := -O srec
u-boot.hex u-boot.srec: u-boot FORCE
$(call if_changed,objcopy)
OBJCOPYFLAGS_u-boot.bin := -O binary
OBJCOPYFLAGS_u-boot.bin := -O binary \
$(if $(CONFIG_X86_RESET_VECTOR),-R .start16 -R .resetvec)
binary_size_check: u-boot.bin FORCE
@file_size=$(shell wc -c u-boot.bin | awk '{print $$1}') ; \
......@@ -953,6 +957,36 @@ u-boot-nand.gph: u-boot.bin FORCE
$(call if_changed,mkimage)
@dd if=/dev/zero bs=8 count=1 2>/dev/null >> $@
# x86 uses a large ROM. We fill it with 0xff, put the 16-bit stuff (including
# reset vector) at the top, Intel ME descriptor at the bottom, and U-Boot in
# the middle.
ifneq ($(CONFIG_X86_RESET_VECTOR),)
rom: u-boot.rom FORCE
u-boot.rom: u-boot-x86-16bit.bin u-boot-dtb.bin \
$(srctree)/board/$(BOARDDIR)/mrc.bin
$(objtree)/tools/ifdtool -c -r $(CONFIG_ROM_SIZE) u-boot.tmp
if [ -n "$(CONFIG_HAVE_INTEL_ME)" ]; then \
$(objtree)/tools/ifdtool -D \
$(srctree)/board/$(BOARDDIR)/descriptor.bin u-boot.tmp; \
$(objtree)/tools/ifdtool \
-i ME:$(srctree)/board/$(BOARDDIR)/me.bin u-boot.tmp; \
fi
$(objtree)/tools/ifdtool -w \
$(CONFIG_SYS_TEXT_BASE):$(objtree)/u-boot-dtb.bin u-boot.tmp
$(objtree)/tools/ifdtool -w \
$(CONFIG_X86_MRC_START):$(srctree)/board/$(BOARDDIR)/mrc.bin \
u-boot.tmp
$(objtree)/tools/ifdtool -w \
$(CONFIG_SYS_X86_START16):$(objtree)/u-boot-x86-16bit.bin \
u-boot.tmp
mv u-boot.tmp $@
OBJCOPYFLAGS_u-boot-x86-16bit.bin := -O binary -j .start16 -j .resetvec
u-boot-x86-16bit.bin: u-boot FORCE
$(call if_changed,objcopy)
endif
ifneq ($(CONFIG_SUNXI),)
OBJCOPYFLAGS_u-boot-sunxi-with-spl.bin = -I binary -O binary \
--pad-to=$(CONFIG_SPL_PAD_TO) --gap-fill=0xff
......
......@@ -12,9 +12,81 @@ choice
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.
endchoice
source "board/chromebook-x86/coreboot/Kconfig"
config RAMBASE
hex
default 0x100000
config RAMTOP
hex
default 0x200000
config XIP_ROM_SIZE
hex
default 0x10000
config CPU_ADDR_BITS
int
default 36
config HPET_ADDRESS
hex
default 0xfed00000 if !HPET_ADDRESS_OVERRIDE
config SMM_TSEG
bool
default n
config SMM_TSEG_SIZE
hex
config ROM_SIZE
hex
default 0x800000
config HAVE_INTEL_ME
bool "Platform requires Intel Management Engine"
help
Newer higher-end devices have an Intel Management Engine (ME)
which is a very large binary blob (typically 1.5MB) which is
required for the platform to work. This enforces a particular
SPI flash format. You will need to supply the me.bin file in
your board directory.
config X86_RAMTEST
bool "Perform a simple RAM test after SDRAM initialisation"
help
If there is something wrong with SDRAM then the platform will
often crash within U-Boot or the kernel. This option enables a
very simple RAM test that quickly checks whether the SDRAM seems
to work correctly. It is not exhaustive but can save time by
detecting obvious failures.
source "arch/x86/cpu/ivybridge/Kconfig"
source "board/coreboot/coreboot/Kconfig"
source "board/google/chromebook_link/Kconfig"
endmenu
......@@ -15,7 +15,6 @@ PF_CPPFLAGS_X86 := $(call cc-option, -fno-toplevel-reorder, \
$(call cc-option, -mpreferred-stack-boundary=2)
PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_X86)
PLATFORM_CPPFLAGS += -fno-dwarf2-cfi-asm
PLATFORM_CPPFLAGS += -DREALMODE_BASE=0x7c0
PLATFORM_CPPFLAGS += -march=i386 -m32
# Support generic board on x86
......
......@@ -13,3 +13,4 @@ obj-$(CONFIG_X86_RESET_VECTOR) += resetvec.o start16.o
obj-y += interrupts.o cpu.o call64.o
obj-$(CONFIG_SYS_COREBOOT) += coreboot/
obj-$(CONFIG_PCI) += pci.o
......@@ -13,25 +13,25 @@
#include <ns16550.h>
#include <asm/msr.h>
#include <asm/cache.h>
#include <asm/cpu.h>
#include <asm/io.h>
#include <asm/arch-coreboot/tables.h>
#include <asm/arch-coreboot/sysinfo.h>
#include <asm/arch/tables.h>
#include <asm/arch/sysinfo.h>
#include <asm/arch/timestamp.h>
DECLARE_GLOBAL_DATA_PTR;
/*
* Miscellaneous platform dependent initializations
*/
int cpu_init_f(void)
int arch_cpu_init(void)
{
int ret = get_coreboot_info(&lib_sysinfo);
if (ret != 0)
if (ret != 0) {
printf("Failed to parse coreboot tables.\n");
return ret;
}
timestamp_init();
return ret;
return x86_cpu_init_f();
}
int board_early_init_f(void)
......@@ -50,27 +50,9 @@ int board_early_init_r(void)
return 0;
}
void show_boot_progress(int val)
int print_cpuinfo(void)
{
#if MIN_PORT80_KCLOCKS_DELAY
/*
* Scale the time counter reading to avoid using 64 bit arithmetics.
* Can't use get_timer() here becuase it could be not yet
* initialized or even implemented.
*/
if (!gd->arch.tsc_prev) {
gd->arch.tsc_base_kclocks = rdtsc() / 1000;
gd->arch.tsc_prev = 0;
} else {
uint32_t now;
do {
now = rdtsc() / 1000 - gd->arch.tsc_base_kclocks;
} while (now < (gd->arch.tsc_prev + MIN_PORT80_KCLOCKS_DELAY));
gd->arch.tsc_prev = now;
}
#endif
outb(val, 0x80);
return default_print_cpuinfo();
}
int last_stage_init(void)
......@@ -98,7 +80,7 @@ int board_eth_init(bd_t *bis)
#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
int board_final_cleanup(void)
void board_final_cleanup(void)
{
/* Un-cache the ROM so the kernel has one
* more MTRR available.
......@@ -120,8 +102,6 @@ int board_final_cleanup(void)
/* Issue SMI to Coreboot to lock down ME and registers */
printf("Finalizing Coreboot\n");
outb(0xcb, 0xb2);
return 0;
}
void panic_puts(const char *str)
......
......@@ -30,7 +30,7 @@
*/
#include <compiler.h>
#include <asm/arch-coreboot/ipchecksum.h>
#include <asm/arch/ipchecksum.h>
unsigned short ipchksum(const void *vptr, unsigned long nbytes)
{
......
......@@ -13,8 +13,6 @@
#include <pci.h>
#include <asm/pci.h>
static struct pci_controller coreboot_hose;
static void config_pci_bridge(struct pci_controller *hose, pci_dev_t dev,
struct pci_config_table *table)
{
......@@ -31,19 +29,13 @@ static struct pci_config_table pci_coreboot_config_table[] = {
{}
};
void pci_init_board(void)
void board_pci_setup_hose(struct pci_controller *hose)
{
coreboot_hose.config_table = pci_coreboot_config_table;
coreboot_hose.first_busno = 0;
coreboot_hose.last_busno = 0;
pci_set_region(coreboot_hose.regions + 0, 0x0, 0x0, 0xffffffff,
PCI_REGION_MEM);
coreboot_hose.region_count = 1;
pci_setup_type1(&coreboot_hose);
pci_register_hose(&coreboot_hose);
hose->config_table = pci_coreboot_config_table;
hose->first_busno = 0;
hose->last_busno = 0;
pci_hose_scan(&coreboot_hose);
pci_set_region(hose->regions + 0, 0x0, 0x0, 0xffffffff,
PCI_REGION_MEM);
hose->region_count = 1;
}
......@@ -11,8 +11,10 @@
#include <asm/e820.h>
#include <asm/u-boot-x86.h>
#include <asm/global_data.h>
#include <asm/init_helpers.h>
#include <asm/processor.h>
#include <asm/sections.h>
#include <asm/zimage.h>
#include <asm/arch/sysinfo.h>
#include <asm/arch/tables.h>
......@@ -79,7 +81,7 @@ ulong board_get_usable_ram_top(ulong total_size)
return (ulong)dest_addr;
}
int dram_init_f(void)
int dram_init(void)
{
int i;
phys_size_t ram_size = 0;
......@@ -94,10 +96,11 @@ int dram_init_f(void)
gd->ram_size = ram_size;
if (ram_size == 0)
return -1;
return 0;
return calculate_relocation_address();
}
int dram_init_banksize(void)
void dram_init_banksize(void)
{
int i, j;
......@@ -114,10 +117,4 @@ int dram_init_banksize(void)
}
}
}
return 0;
}
int dram_init(void)
{
return dram_init_banksize();
}
......@@ -8,9 +8,9 @@
*/
#include <common.h>
#include <asm/arch-coreboot/ipchecksum.h>
#include <asm/arch-coreboot/sysinfo.h>
#include <asm/arch-coreboot/tables.h>
#include <asm/arch/ipchecksum.h>
#include <asm/arch/sysinfo.h>
#include <asm/arch/tables.h>
/*
* This needs to be in the .data section so that it's copied over during
......
......@@ -13,6 +13,9 @@
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Alex Zuepke <azu@sysgo.de>
*
* Part of this file is adapted from coreboot
* src/arch/x86/lib/cpu.c
*
* SPDX-License-Identifier: GPL-2.0+
*/
......@@ -22,11 +25,14 @@
#include <malloc.h>
#include <asm/control_regs.h>
#include <asm/cpu.h>
#include <asm/post.h>
#include <asm/processor.h>
#include <asm/processor-flags.h>
#include <asm/interrupt.h>
#include <linux/compiler.h>
DECLARE_GLOBAL_DATA_PTR;
/*
* Constructor for a conventional segment GDT (or LDT) entry
* This is a macro so it can be used in initialisers
......@@ -43,6 +49,52 @@ struct gdt_ptr {
u32 ptr;
} __packed;
struct cpu_device_id {
unsigned vendor;
unsigned device;
};
struct cpuinfo_x86 {
uint8_t x86; /* CPU family */
uint8_t x86_vendor; /* CPU vendor */
uint8_t x86_model;
uint8_t x86_mask;
};
/*
* List of cpu vendor strings along with their normalized
* id values.
*/
static struct {
int vendor;
const char *name;
} x86_vendors[] = {
{ X86_VENDOR_INTEL, "GenuineIntel", },
{ X86_VENDOR_CYRIX, "CyrixInstead", },
{ X86_VENDOR_AMD, "AuthenticAMD", },
{ X86_VENDOR_UMC, "UMC UMC UMC ", },
{ X86_VENDOR_NEXGEN, "NexGenDriven", },
{ X86_VENDOR_CENTAUR, "CentaurHauls", },
{ X86_VENDOR_RISE, "RiseRiseRise", },
{ X86_VENDOR_TRANSMETA, "GenuineTMx86", },
{ X86_VENDOR_TRANSMETA, "TransmetaCPU", },
{ X86_VENDOR_NSC, "Geode by NSC", },
{ X86_VENDOR_SIS, "SiS SiS SiS ", },
};
static const char *const x86_vendor_name[] = {
[X86_VENDOR_INTEL] = "Intel",
[X86_VENDOR_CYRIX] = "Cyrix",
[X86_VENDOR_AMD] = "AMD",
[X86_VENDOR_UMC] = "UMC",
[X86_VENDOR_NEXGEN] = "NexGen",
[X86_VENDOR_CENTAUR] = "Centaur",
[X86_VENDOR_RISE] = "Rise",
[X86_VENDOR_TRANSMETA] = "Transmeta",
[X86_VENDOR_NSC] = "NSC",
[X86_VENDOR_SIS] = "SiS",
};
static void load_ds(u32 segment)
{
asm volatile("movl %0, %%ds" : : "r" (segment * X86_GDT_ENTRY_SIZE));
......@@ -115,6 +167,129 @@ int __weak x86_cleanup_before_linux(void)
return 0;
}
/*
* Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
* by the fact that they preserve the flags across the division of 5/2.
* PII and PPro exhibit this behavior too, but they have cpuid available.
*/
/*
* Perform the Cyrix 5/2 test. A Cyrix won't change
* the flags, while other 486 chips will.
*/
static inline int test_cyrix_52div(void)
{
unsigned int test;
__asm__ __volatile__(
"sahf\n\t" /* clear flags (%eax = 0x0005) */
"div %b2\n\t" /* divide 5 by 2 */
"lahf" /* store flags into %ah */
: "=a" (test)
: "0" (5), "q" (2)
: "cc");
/* AH is 0x02 on Cyrix after the divide.. */
return (unsigned char) (test >> 8) == 0x02;
}
/*
* Detect a NexGen CPU running without BIOS hypercode new enough
* to have CPUID. (Thanks to Herbert Oppmann)
*/
static int deep_magic_nexgen_probe(void)
{
int ret;
__asm__ __volatile__ (
" movw $0x5555, %%ax\n"
" xorw %%dx,%%dx\n"
" movw $2, %%cx\n"
" divw %%cx\n"
" movl $0, %%eax\n"
" jnz 1f\n"
" movl $1, %%eax\n"
"1:\n"
: "=a" (ret) : : "cx", "dx");
return ret;
}
static bool has_cpuid(void)
{
return flag_is_changeable_p(X86_EFLAGS_ID);
}
static int build_vendor_name(char *vendor_name)
{
struct cpuid_result result;
result = cpuid(0x00000000);
unsigned int *name_as_ints = (unsigned int *)vendor_name;
name_as_ints[0] = result.ebx;
name_as_ints[1] = result.edx;
name_as_ints[2] = result.ecx;
return result.eax;
}
static void identify_cpu(struct cpu_device_id *cpu)
{
char vendor_name[16];
int i;
vendor_name[0] = '\0'; /* Unset */
cpu->device = 0; /* fix gcc 4.4.4 warning */
/* Find the id and vendor_name */
if (!has_cpuid()) {
/* Its a 486 if we can modify the AC flag */
if (flag_is_changeable_p(X86_EFLAGS_AC))
cpu->device = 0x00000400; /* 486 */
else
cpu->device = 0x00000300; /* 386 */
if ((cpu->device == 0x00000400) && test_cyrix_52div()) {
memcpy(vendor_name, "CyrixInstead", 13);
/* If we ever care we can enable cpuid here */
}
/* Detect NexGen with old hypercode */
else if (deep_magic_nexgen_probe())
memcpy(vendor_name, "NexGenDriven", 13);
}
if (has_cpuid()) {
int cpuid_level;
cpuid_level = build_vendor_name(vendor_name);
vendor_name[12] = '\0';
/* Intel-defined flags: level 0x00000001 */
if (cpuid_level >= 0x00000001) {
cpu->device = cpuid_eax(0x00000001);
} else {
/* Have CPUID level 0 only unheard of */
cpu->device = 0x00000400;
}
}
cpu->vendor = X86_VENDOR_UNKNOWN;
for (i = 0; i < ARRAY_SIZE(x86_vendors); i++) {
if (memcmp(vendor_name, x86_vendors[i].name, 12) == 0) {
cpu->vendor = x86_vendors[i].vendor;
break;
}
}
}
static inline void get_fms(struct cpuinfo_x86 *c, uint32_t tfms)
{
c->x86 = (tfms >> 8) & 0xf;
c->x86_model = (tfms >> 4) & 0xf;
c->x86_mask = tfms & 0xf;
if (c->x86 == 0xf)
c->x86 += (tfms >> 20) & 0xff;
if (c->x86 >= 0x6)
c->x86_model += ((tfms >> 16) & 0xF) << 4;
}
int x86_cpu_init_f(void)
{
const u32 em_rst = ~X86_CR0_EM;
......@@ -128,9 +303,22 @@ int x86_cpu_init_f(void)
"movl %%eax, %%cr0\n" \
: : "i" (em_rst), "i" (mp_ne_set) : "eax");
/* identify CPU via cpuid and store the decoded info into gd->arch */
if (has_cpuid()) {
struct cpu_device_id cpu;
struct cpuinfo_x86 c;
identify_cpu(&cpu);
get_fms(&c, cpu.device);
gd->arch.x86 = c.x86;
gd->arch.x86_vendor = cpu.vendor;
gd->arch.x86_model = c.x86_model;
gd->arch.x86_mask = c.x86_mask;
gd->arch.x86_device = cpu.device;
}
return 0;
}
int cpu_init_f(void) __attribute__((weak, alias("x86_cpu_init_f")));
int x86_cpu_init_r(void)
{
......@@ -198,14 +386,13 @@ asm(".globl generate_gpf\n"
"generate_gpf:\n"
"ljmp $0x70, $0x47114711\n");
void __reset_cpu(ulong addr)
__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 */
}
void reset_cpu(ulong addr) __attribute__((weak, alias("__reset_cpu")));
int dcache_status(void)
{
......@@ -279,66 +466,63 @@ void cpu_disable_paging_pae(void)
: "eax");
}
static bool has_cpuid(void)
static bool can_detect_long_mode(void)
{
unsigned long flag;
asm volatile("pushf\n" \
"pop %%eax\n"
"mov %%eax, %%ecx\n" /* ecx = flags */
"xor %1, %%eax\n"
"push %%eax\n"
"popf\n" /* flags ^= $2 */
"pushf\n"
"pop %%eax\n" /* eax = flags */
"push %%ecx\n"
"popf\n" /* flags = ecx */
"xor %%ecx, %%eax\n"
"mov %%eax, %0"
: "=r" (flag)
: "i" (1 << 21)
: "eax", "ecx", "memory");
return cpuid_eax(0x80000000) > 0x80000000UL;
}