diff options
author | Tom Rini <trini@konsulko.com> | 2015-07-15 10:41:20 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2015-07-15 10:41:20 -0400 |
commit | 605e15db2b54302364a2528d3c6604fbc57be846 (patch) | |
tree | 1a1e344964bff1719939183124d66a71e7ca7731 /arch | |
parent | 4905dfc65d9a17083727865302d2cf633c15c911 (diff) | |
parent | f110da9984c0aa0aba9e1c4178b67b7abecf7e8d (diff) | |
download | u-boot-imx-605e15db2b54302364a2528d3c6604fbc57be846.zip u-boot-imx-605e15db2b54302364a2528d3c6604fbc57be846.tar.gz u-boot-imx-605e15db2b54302364a2528d3c6604fbc57be846.tar.bz2 |
Merge git://git.denx.de/u-boot-x86
Diffstat (limited to 'arch')
44 files changed, 1639 insertions, 616 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 20083e6..cbbaa4f 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -69,6 +69,21 @@ config X86_RESET_VECTOR bool default n +config RESET_SEG_START + hex + depends on X86_RESET_VECTOR + default 0xffff0000 + +config RESET_SEG_SIZE + hex + depends on X86_RESET_VECTOR + default 0x10000 + +config RESET_VEC_LOC + hex + depends on X86_RESET_VECTOR + default 0xfffffff0 + config SYS_X86_START16 hex depends on X86_RESET_VECTOR @@ -173,14 +188,6 @@ config X86_RAMTEST to work correctly. It is not exhaustive but can save time by detecting obvious failures. -config MARK_GRAPHICS_MEM_WRCOMB - 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. - config HAVE_FSP bool "Add an Firmware Support Package binary" help @@ -220,17 +227,6 @@ config FSP_TEMP_RAM_ADDR Stack top address which is used in FspInit after DRAM is ready and CAR is disabled. -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 @@ -241,8 +237,21 @@ config SMP only one CPU will be enabled regardless of the number of CPUs available. +config MAX_CPUS + int "Maximum number of CPUs permitted" + depends on SMP + 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 AP_STACK_SIZE hex + depends on SMP default 0x1000 help Each additional CPU started by U-Boot requires its own stack. This @@ -270,6 +279,28 @@ config TSC_FREQ_IN_MHZ help The running frequency in MHz of Time-Stamp Counter (TSC). +config HAVE_VGA_BIOS + bool "Add a VGA BIOS image" + help + Select this option if you have a VGA BIOS image that you would + like to add to your ROM. + +config VGA_BIOS_FILE + string "VGA BIOS image filename" + depends on HAVE_VGA_BIOS + default "vga.bin" + help + The filename of the VGA BIOS image in the board directory. + +config VGA_BIOS_ADDR + hex "VGA BIOS image location" + depends on HAVE_VGA_BIOS + default 0xfff90000 + help + The location of VGA BIOS image in the SPI flash. For example, base + address of 0xfff90000 indicates that the image will be put at offset + 0x90000 from the beginning of a 1MB flash device. + menu "System tables" config GENERATE_PIRQ_TABLE @@ -296,6 +327,15 @@ config GENERATE_SFI_TABLE For more information, see http://simplefirmware.org +config GENERATE_MP_TABLE + bool "Generate an MP (Multi-Processor) table" + default n + help + Generate an MP (Multi-Processor) table for this board. The MP table + provides a way for the operating system to support for symmetric + multiprocessing as well as symmetric I/O interrupt handling with + the local APIC and I/O APIC. + endmenu config MAX_PIRQ_LINKS diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 7ff05e6..8a8e63e 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -10,7 +10,7 @@ extra-y = start.o obj-$(CONFIG_X86_RESET_VECTOR) += resetvec.o start16.o -obj-y += interrupts.o cpu.o call64.o +obj-y += interrupts.o cpu.o cpu_x86.o call64.o obj-$(CONFIG_INTEL_BAYTRAIL) += baytrail/ obj-$(CONFIG_SYS_COREBOOT) += coreboot/ @@ -19,7 +19,7 @@ obj-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += ivybridge/ obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/ obj-$(CONFIG_INTEL_QUARK) += quark/ obj-$(CONFIG_INTEL_QUEENSBAY) += queensbay/ -obj-y += irq.o lapic.o +obj-y += irq.o lapic.o ioapic.o obj-$(CONFIG_SMP) += mp_init.o obj-y += mtrr.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/x86/cpu/baytrail/Makefile b/arch/x86/cpu/baytrail/Makefile index c78b644..5be5491 100644 --- a/arch/x86/cpu/baytrail/Makefile +++ b/arch/x86/cpu/baytrail/Makefile @@ -7,5 +7,4 @@ obj-y += cpu.o obj-y += early_uart.o obj-y += fsp_configs.o -obj-y += pci.o obj-y += valleyview.o diff --git a/arch/x86/cpu/baytrail/cpu.c b/arch/x86/cpu/baytrail/cpu.c index 1d48206..a011730 100644 --- a/arch/x86/cpu/baytrail/cpu.c +++ b/arch/x86/cpu/baytrail/cpu.c @@ -10,79 +10,11 @@ #include <cpu.h> #include <dm.h> #include <asm/cpu.h> +#include <asm/cpu_x86.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; @@ -175,19 +107,38 @@ static int baytrail_get_info(struct udevice *dev, struct cpu_info *info) return 0; } -static int cpu_x86_baytrail_bind(struct udevice *dev) +static int baytrail_get_count(struct udevice *dev) { - struct cpu_platdata *plat = dev_get_parent_platdata(dev); + 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; - plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, - "intel,apic-id", -1); + ecx++; + } return 0; } static const struct cpu_ops cpu_x86_baytrail_ops = { - .get_desc = x86_cpu_get_desc, + .get_desc = cpu_x86_get_desc, .get_info = baytrail_get_info, + .get_count = baytrail_get_count, }; static const struct udevice_id cpu_x86_baytrail_ids[] = { @@ -199,7 +150,7 @@ 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, + .bind = cpu_x86_bind, .probe = cpu_x86_baytrail_probe, .ops = &cpu_x86_baytrail_ops, }; diff --git a/arch/x86/cpu/baytrail/pci.c b/arch/x86/cpu/baytrail/pci.c deleted file mode 100644 index 48409de..0000000 --- a/arch/x86/cpu/baytrail/pci.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <pci.h> -#include <asm/pci.h> -#include <asm/fsp/fsp_support.h> - -DECLARE_GLOBAL_DATA_PTR; - -void board_pci_setup_hose(struct pci_controller *hose) -{ - hose->first_busno = 0; - hose->last_busno = 0; - - /* PCI memory space */ - pci_set_region(hose->regions + 0, - CONFIG_PCI_MEM_BUS, - CONFIG_PCI_MEM_PHYS, - CONFIG_PCI_MEM_SIZE, - PCI_REGION_MEM); - - /* PCI IO space */ - pci_set_region(hose->regions + 1, - CONFIG_PCI_IO_BUS, - CONFIG_PCI_IO_PHYS, - CONFIG_PCI_IO_SIZE, - PCI_REGION_IO); - - pci_set_region(hose->regions + 2, - CONFIG_PCI_PREF_BUS, - CONFIG_PCI_PREF_PHYS, - CONFIG_PCI_PREF_SIZE, - PCI_REGION_PREFETCH); - - pci_set_region(hose->regions + 3, - 0, - 0, - gd->ram_size < 0x80000000 ? gd->ram_size : 0x80000000, - PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); - - hose->region_count = 4; -} diff --git a/arch/x86/cpu/config.mk b/arch/x86/cpu/config.mk index 4c4d0c7..1263221 100644 --- a/arch/x86/cpu/config.mk +++ b/arch/x86/cpu/config.mk @@ -10,8 +10,8 @@ CROSS_COMPILE ?= i386-linux- PLATFORM_CPPFLAGS += -D__I386__ # DO NOT MODIFY THE FOLLOWING UNLESS YOU REALLY KNOW WHAT YOU ARE DOING! -LDPPFLAGS += -DRESET_SEG_START=0xffff0000 -LDPPFLAGS += -DRESET_SEG_SIZE=0x10000 -LDPPFLAGS += -DRESET_VEC_LOC=0xfffffff0 +LDPPFLAGS += -DRESET_SEG_START=$(CONFIG_RESET_SEG_START) +LDPPFLAGS += -DRESET_SEG_SIZE=$(CONFIG_RESET_SEG_SIZE) +LDPPFLAGS += -DRESET_VEC_LOC=$(CONFIG_RESET_VEC_LOC) LDPPFLAGS += -DSTART_16=$(CONFIG_SYS_X86_START16) LDPPFLAGS += -DRESET_BASE="CONFIG_SYS_TEXT_BASE + (CONFIG_SYS_MONITOR_LEN - RESET_SEG_SIZE)" diff --git a/arch/x86/cpu/coreboot/pci.c b/arch/x86/cpu/coreboot/pci.c index 67eb14c..41e29a6 100644 --- a/arch/x86/cpu/coreboot/pci.c +++ b/arch/x86/cpu/coreboot/pci.c @@ -11,29 +11,7 @@ #include <common.h> #include <dm.h> -#include <errno.h> #include <pci.h> -#include <asm/io.h> -#include <asm/pci.h> - -DECLARE_GLOBAL_DATA_PTR; - -static const struct dm_pci_ops pci_x86_ops = { - .read_config = pci_x86_read_config, - .write_config = pci_x86_write_config, -}; - -static const struct udevice_id pci_x86_ids[] = { - { .compatible = "pci-x86" }, - { } -}; - -U_BOOT_DRIVER(pci_x86_drv) = { - .name = "pci_x86", - .id = UCLASS_PCI, - .of_match = pci_x86_ids, - .ops = &pci_x86_ops, -}; static const struct udevice_id generic_pch_ids[] = { { .compatible = "intel,pch" }, diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index bb4a110..af927b9 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -21,12 +21,15 @@ #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/cpu.h> +#include <asm/lapic.h> +#include <asm/mp.h> +#include <asm/msr.h> +#include <asm/mtrr.h> #include <asm/post.h> #include <asm/processor.h> #include <asm/processor-flags.h> @@ -164,6 +167,26 @@ void setup_gdt(gd_t *id, u64 *gdt_addr) load_fs(X86_GDT_ENTRY_32BIT_FS); } +#ifdef CONFIG_HAVE_FSP +/* + * Setup FSP execution environment GDT + * + * Per Intel FSP external architecture specification, before calling any FSP + * APIs, we need make sure the system is in flat 32-bit mode and both the code + * and data selectors should have full 4GB access range. Here we reuse the one + * we used in arch/x86/cpu/start16.S, and reload the segement registers. + */ +void setup_fsp_gdt(void) +{ + load_gdt((const u64 *)(gdt_rom + CONFIG_RESET_SEG_START), 4); + load_ds(X86_GDT_ENTRY_32BIT_DS); + load_ss(X86_GDT_ENTRY_32BIT_DS); + load_es(X86_GDT_ENTRY_32BIT_DS); + load_fs(X86_GDT_ENTRY_32BIT_DS); + load_gs(X86_GDT_ENTRY_32BIT_DS); +} +#endif + int __weak x86_cleanup_before_linux(void) { #ifdef CONFIG_BOOTSTAGE_STASH @@ -330,6 +353,28 @@ int x86_cpu_init_f(void) gd->arch.has_mtrr = has_mtrr(); } + /* Don't allow PCI region 3 to use memory in the 2-4GB memory hole */ + gd->pci_ram_top = 0x80000000U; + + /* Configure fixed range MTRRs for some legacy regions */ + if (gd->arch.has_mtrr) { + u64 mtrr_cap; + + mtrr_cap = native_read_msr(MTRR_CAP_MSR); + if (mtrr_cap & MTRR_CAP_FIX) { + /* Mark the VGA RAM area as uncacheable */ + native_write_msr(MTRR_FIX_16K_A0000_MSR, 0, 0); + + /* Mark the PCI ROM area as uncacheable */ + native_write_msr(MTRR_FIX_4K_C0000_MSR, 0, 0); + native_write_msr(MTRR_FIX_4K_C8000_MSR, 0, 0); + native_write_msr(MTRR_FIX_4K_D0000_MSR, 0, 0); + native_write_msr(MTRR_FIX_4K_D8000_MSR, 0, 0); + + /* Enable the fixed range MTRRs */ + msr_setbits_64(MTRR_DEF_TYPE_MSR, MTRR_DEF_TYPE_FIX_EN); + } + } return 0; } @@ -520,16 +565,6 @@ char *cpu_get_name(char *name) return ptr; } -int x86_cpu_get_desc(struct udevice *dev, char *buf, int size) -{ - if (size < CPU_MAX_NAME_LEN) - return -ENOSPC; - - cpu_get_name(buf); - - return 0; -} - int default_print_cpuinfo(void) { printf("CPU: %s, vendor %s, device %xh\n", @@ -613,28 +648,47 @@ int last_stage_init(void) } #endif -__weak int x86_init_cpus(void) +#ifdef CONFIG_SMP +static int enable_smis(struct udevice *cpu, void *unused) { return 0; } -int cpu_init_r(void) +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 x86_mp_init(void) { - return x86_init_cpus(); + struct mp_params mp_params; + + 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 -static const struct cpu_ops cpu_x86_ops = { - .get_desc = x86_cpu_get_desc, -}; +__weak int x86_init_cpus(void) +{ +#ifdef CONFIG_SMP + debug("Init additional CPUs\n"); + x86_mp_init(); +#endif -static const struct udevice_id cpu_x86_ids[] = { - { .compatible = "cpu-x86" }, - { } -}; + return 0; +} -U_BOOT_DRIVER(cpu_x86_drv) = { - .name = "cpu_x86", - .id = UCLASS_CPU, - .of_match = cpu_x86_ids, - .ops = &cpu_x86_ops, -}; +int cpu_init_r(void) +{ + return x86_init_cpus(); +} diff --git a/arch/x86/cpu/cpu_x86.c b/arch/x86/cpu/cpu_x86.c new file mode 100644 index 0000000..0941041 --- /dev/null +++ b/arch/x86/cpu/cpu_x86.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <cpu.h> +#include <dm.h> +#include <errno.h> +#include <asm/cpu.h> + +DECLARE_GLOBAL_DATA_PTR; + +int cpu_x86_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; +} + +int cpu_x86_get_desc(struct udevice *dev, char *buf, int size) +{ + if (size < CPU_MAX_NAME_LEN) + return -ENOSPC; + + cpu_get_name(buf); + + return 0; +} + +static int cpu_x86_get_count(struct udevice *dev) +{ + int node, cpu; + int num = 0; + + node = fdt_path_offset(gd->fdt_blob, "/cpus"); + if (node < 0) + return -ENOENT; + + for (cpu = fdt_first_subnode(gd->fdt_blob, node); + cpu >= 0; + cpu = fdt_next_subnode(gd->fdt_blob, cpu)) { + const char *device_type; + + device_type = fdt_getprop(gd->fdt_blob, cpu, + "device_type", NULL); + if (!device_type) + continue; + if (strcmp(device_type, "cpu") == 0) + num++; + } + + return num; +} + +static const struct cpu_ops cpu_x86_ops = { + .get_desc = cpu_x86_get_desc, + .get_count = cpu_x86_get_count, +}; + +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, + .bind = cpu_x86_bind, + .ops = &cpu_x86_ops, +}; diff --git a/arch/x86/cpu/ioapic.c b/arch/x86/cpu/ioapic.c new file mode 100644 index 0000000..112a9c6 --- /dev/null +++ b/arch/x86/cpu/ioapic.c @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/ioapic.h> + +u32 io_apic_read(u32 reg) +{ + writel(reg, IO_APIC_INDEX); + return readl(IO_APIC_DATA); +} + +void io_apic_write(u32 reg, u32 val) +{ + writel(reg, IO_APIC_INDEX); + writel(val, IO_APIC_DATA); +} diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c index 74b89ad..97dd000 100644 --- a/arch/x86/cpu/irq.c +++ b/arch/x86/cpu/irq.c @@ -58,17 +58,28 @@ void pirq_assign_irq(int link, u8 irq) writeb(irq, irq_router.ibase + LINK_N2V(link, base)); } -static inline void fill_irq_info(struct irq_info **slotp, int *entries, u8 bus, - u8 device, u8 func, u8 pin, u8 pirq) +static struct irq_info *check_dup_entry(struct irq_info *slot_base, + int entry_num, int bus, int device) { - struct irq_info *slot = *slotp; + struct irq_info *slot = slot_base; + int i; + + for (i = 0; i < entry_num; i++) { + if (slot->bus == bus && slot->devfn == (device << 3)) + break; + slot++; + } + return (i == entry_num) ? NULL : slot; +} + +static inline void fill_irq_info(struct irq_info *slot, int bus, int device, + int pin, int pirq) +{ slot->bus = bus; - slot->devfn = (device << 3) | func; + slot->devfn = (device << 3) | 0; slot->irq[pin - 1].link = LINK_N2V(pirq, irq_router.link_base); slot->irq[pin - 1].bitmap = irq_router.irq_mask; - (*entries)++; - (*slotp)++; } __weak void cpu_irq_init(void) @@ -84,7 +95,7 @@ static int create_pirq_routing_table(void) int len, count; const u32 *cell; struct irq_routing_table *rt; - struct irq_info *slot; + struct irq_info *slot, *slot_base; int irq_entries = 0; int i; int ret; @@ -161,13 +172,13 @@ static int create_pirq_routing_table(void) /* Populate the PIRQ table fields */ rt->signature = PIRQ_SIGNATURE; rt->version = PIRQ_VERSION; - rt->rtr_bus = 0; + rt->rtr_bus = PCI_BUS(irq_router.bdf); rt->rtr_devfn = (PCI_DEV(irq_router.bdf) << 3) | PCI_FUNC(irq_router.bdf); rt->rtr_vendor = PCI_VENDOR_ID_INTEL; rt->rtr_device = PCI_DEVICE_ID_INTEL_ICH7_31; - slot = rt->slots; + slot_base = rt->slots; /* Now fill in the irq_info entries in the PIRQ table */ for (i = 0; i < count; i++) { @@ -181,9 +192,44 @@ static int create_pirq_routing_table(void) i, PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), PCI_FUNC(pr.bdf), 'A' + pr.pin - 1, 'A' + pr.pirq); - fill_irq_info(&slot, &irq_entries, PCI_BUS(pr.bdf), - PCI_DEV(pr.bdf), PCI_FUNC(pr.bdf), + + slot = check_dup_entry(slot_base, irq_entries, + PCI_BUS(pr.bdf), PCI_DEV(pr.bdf)); + if (slot) { + debug("found entry for bus %d device %d, ", + PCI_BUS(pr.bdf), PCI_DEV(pr.bdf)); + + if (slot->irq[pr.pin - 1].link) { + debug("skipping\n"); + + /* + * Sanity test on the routed PIRQ pin + * + * If they don't match, show a warning to tell + * there might be something wrong with the PIRQ + * routing information in the device tree. + */ + if (slot->irq[pr.pin - 1].link != + LINK_N2V(pr.pirq, irq_router.link_base)) + debug("WARNING: Inconsistent PIRQ routing information\n"); + + cell += sizeof(struct pirq_routing) / + sizeof(u32); + continue; + } else { + debug("writing INT%c\n", 'A' + pr.pin - 1); + fill_irq_info(slot, PCI_BUS(pr.bdf), + PCI_DEV(pr.bdf), pr.pin, pr.pirq); + cell += sizeof(struct pirq_routing) / + sizeof(u32); + continue; + } + } + + slot = slot_base + irq_entries; + fill_irq_info(slot, PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), pr.pin, pr.pirq); + irq_entries++; cell += sizeof(struct pirq_routing) / sizeof(u32); } diff --git a/arch/x86/cpu/ivybridge/Kconfig b/arch/x86/cpu/ivybridge/Kconfig index e4595be..0e249a4 100644 --- a/arch/x86/cpu/ivybridge/Kconfig +++ b/arch/x86/cpu/ivybridge/Kconfig @@ -95,7 +95,6 @@ config CPU_SPECIFIC_OPTIONS select ARCH_BOOTBLOCK_X86_32 select ARCH_ROMSTAGE_X86_32 select ARCH_RAMSTAGE_X86_32 - select SMP select SSE2 select UDELAY_LAPIC select CPU_MICROCODE_IN_CBFS diff --git a/arch/x86/cpu/ivybridge/model_206ax.c b/arch/x86/cpu/ivybridge/model_206ax.c index 8b08c40..fd7db97 100644 --- a/arch/x86/cpu/ivybridge/model_206ax.c +++ b/arch/x86/cpu/ivybridge/model_206ax.c @@ -13,12 +13,12 @@ #include <asm/acpi.h> #include <asm/cpu.h> #include <asm/lapic.h> -#include <asm/lapic_def.h> #include <asm/msr.h> #include <asm/mtrr.h> #include <asm/processor.h> #include <asm/speedstep.h> #include <asm/turbo.h> +#include <asm/arch/bd82x6x.h> #include <asm/arch/model_206ax.h> static void enable_vmx(void) diff --git a/arch/x86/cpu/lapic.c b/arch/x86/cpu/lapic.c index 4690603..30d2313 100644 --- a/arch/x86/cpu/lapic.c +++ b/arch/x86/cpu/lapic.c @@ -8,50 +8,153 @@ */ #include <common.h> -#include <asm/msr.h> #include <asm/io.h> #include <asm/lapic.h> +#include <asm/msr.h> +#include <asm/msr-index.h> #include <asm/post.h> +unsigned long lapic_read(unsigned long reg) +{ + return readl(LAPIC_DEFAULT_BASE + reg); +} + +#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \ + sizeof(*(ptr)))) + +struct __xchg_dummy { unsigned long a[100]; }; +#define __xg(x) ((struct __xchg_dummy *)(x)) + +/* + * Note: no "lock" prefix even on SMP. xchg always implies lock anyway. + * + * Note 2: xchg has side effect, so that attribute volatile is necessary, + * but generally the primitive is invalid, *ptr is output argument. + */ +static inline unsigned long __xchg(unsigned long x, volatile void *ptr, + int size) +{ + switch (size) { + case 1: + __asm__ __volatile__("xchgb %b0,%1" + : "=q" (x) + : "m" (*__xg(ptr)), "0" (x) + : "memory"); + break; + case 2: + __asm__ __volatile__("xchgw %w0,%1" + : "=r" (x) + : "m" (*__xg(ptr)), "0" (x) + : "memory"); + break; + case 4: + __asm__ __volatile__("xchgl %0,%1" + : "=r" (x) + : "m" (*__xg(ptr)), "0" (x) + : "memory"); + break; + } + + return x; +} + +void lapic_write(unsigned long reg, unsigned long v) +{ + (void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v); +} + +void enable_lapic(void) +{ + msr_t msr; + + msr = msr_read(MSR_IA32_APICBASE); + msr.hi &= 0xffffff00; + msr.lo |= MSR_IA32_APICBASE_ENABLE; + msr.lo &= ~MSR_IA32_APICBASE_BASE; + msr.lo |= LAPIC_DEFAULT_BASE; + msr_write(MSR_IA32_APICBASE, msr); +} + +void disable_lapic(void) +{ + msr_t msr; + + msr = msr_read(MSR_IA32_APICBASE); + msr.lo &= ~MSR_IA32_APICBASE_ENABLE; + msr_write(MSR_IA32_APICBASE, msr); +} + +unsigned long lapicid(void) +{ + return lapic_read(LAPIC_ID) >> 24; +} + +static void lapic_wait_icr_idle(void) +{ + do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY); +} + +int lapic_remote_read(int apicid, int reg, unsigned long *pvalue) +{ + int timeout; + unsigned long status; + int result; + + lapic_wait_icr_idle(); + lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); + lapic_write(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4)); + + timeout = 0; + do { + status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK; + } while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000); + + result = -1; + if (status == LAPIC_ICR_RR_VALID) { + *pvalue = lapic_read(LAPIC_RRR); + result = 0; + } + + return result; +} + void lapic_setup(void) { -#if NEED_LAPIC == 1 +#ifdef CONFIG_SMP /* Only Pentium Pro and later have those MSR stuff */ debug("Setting up local apic: "); /* Enable the local apic */ enable_lapic(); - /* - * Set Task Priority to 'accept all'. - */ - lapic_write_around(LAPIC_TASKPRI, - lapic_read_around(LAPIC_TASKPRI) & ~LAPIC_TPRI_MASK); + /* Set Task Priority to 'accept all' */ + lapic_write(LAPIC_TASKPRI, + lapic_read(LAPIC_TASKPRI) & ~LAPIC_TPRI_MASK); /* Put the local apic in virtual wire mode */ - lapic_write_around(LAPIC_SPIV, (lapic_read_around(LAPIC_SPIV) & - ~(LAPIC_VECTOR_MASK)) | LAPIC_SPIV_ENABLE); - lapic_write_around(LAPIC_LVT0, (lapic_read_around(LAPIC_LVT0) & - ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | - LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | - LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | - LAPIC_DELIVERY_MODE_MASK)) | - (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | - LAPIC_DELIVERY_MODE_EXTINT)); - lapic_write_around(LAPIC_LVT1, (lapic_read_around(LAPIC_LVT1) & - ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | - LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | - LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | - LAPIC_DELIVERY_MODE_MASK)) | - (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | - LAPIC_DELIVERY_MODE_NMI)); + lapic_write(LAPIC_SPIV, (lapic_read(LAPIC_SPIV) & + ~(LAPIC_VECTOR_MASK)) | LAPIC_SPIV_ENABLE); + lapic_write(LAPIC_LVT0, (lapic_read(LAPIC_LVT0) & + ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | + LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | + LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | + LAPIC_DELIVERY_MODE_MASK)) | + (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | + LAPIC_DELIVERY_MODE_EXTINT)); + lapic_write(LAPIC_LVT1, (lapic_read(LAPIC_LVT1) & + ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | + LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | + LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | + LAPIC_DELIVERY_MODE_MASK)) | + (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | + LAPIC_DELIVERY_MODE_NMI)); debug("apic_id: 0x%02lx, ", lapicid()); -#else /* !NEED_LLAPIC */ +#else /* !CONFIG_SMP */ /* Only Pentium Pro and later have those MSR stuff */ debug("Disabling local apic: "); disable_lapic(); -#endif /* !NEED_LAPIC */ +#endif /* CONFIG_SMP */ debug("done.\n"); post_code(POST_LAPIC); } diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index ac5753a..e686b28 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -16,12 +16,17 @@ #include <asm/interrupt.h> #include <asm/lapic.h> #include <asm/mp.h> +#include <asm/msr.h> #include <asm/mtrr.h> +#include <asm/processor.h> #include <asm/sipi.h> #include <dm/device-internal.h> #include <dm/uclass-internal.h> #include <linux/linkage.h> +/* Total CPUs include BSP */ +static int num_cpus; + /* This also needs to match the sipi.S assembly code for saved MSR encoding */ struct saved_msr { uint32_t index; @@ -56,6 +61,13 @@ static inline void release_barrier(atomic_t *b) atomic_set(b, 1); } +static inline void stop_this_cpu(void) +{ + /* Called by an AP when it is ready to halt and wait for a new task */ + for (;;) + cpu_hlt(); +} + /* 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) @@ -314,9 +326,9 @@ static int start_aps(int ap_count, atomic_t *num_aps) } /* 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); + lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); + lapic_write(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | + LAPIC_DM_INIT); debug("Waiting for 10ms after sending INIT.\n"); mdelay(10); @@ -331,9 +343,9 @@ static int start_aps(int ap_count, atomic_t *num_aps) } } - 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); + lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); + lapic_write(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"); @@ -356,9 +368,9 @@ static int start_aps(int ap_count, atomic_t *num_aps) } } - 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); + lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); + lapic_write(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"); @@ -383,7 +395,7 @@ static int bsp_do_flight_plan(struct udevice *cpu, struct mp_params *mp_params) int ret = 0; const int timeout_us = 100000; const int step_us = 100; - int num_aps = mp_params->num_cpus - 1; + int num_aps = num_cpus - 1; for (i = 0; i < mp_params->num_records; i++) { struct mp_flight_record *rec = &mp_params->flight_plan[i]; @@ -415,7 +427,7 @@ static int init_bsp(struct udevice **devp) cpu_get_name(processor_name); debug("CPU: %s.\n", processor_name); - enable_lapic(); + lapic_setup(); apic_id = lapicid(); ret = find_cpu_by_apid_id(apic_id, devp); @@ -451,7 +463,16 @@ int mp_init(struct mp_params *p) return -1; } - ret = check_cpu_devices(p->num_cpus); + num_cpus = cpu_get_count(cpu); + if (num_cpus < 0) { + debug("Cannot get number of CPUs: err=%d\n", num_cpus); + return num_cpus; + } + + if (num_cpus < 2) + debug("Warning: Only 1 CPU is detected\n"); + + ret = check_cpu_devices(num_cpus); if (ret) debug("Warning: Device tree does not describe all CPUs. Extra ones will not be started correctly\n"); @@ -471,7 +492,7 @@ int mp_init(struct mp_params *p) wbinvd(); /* Start the APs providing number of APs and the cpus_entered field */ - num_aps = p->num_cpus - 1; + num_aps = num_cpus - 1; ret = start_aps(num_aps, ap_count); if (ret) { mdelay(1000); diff --git a/arch/x86/cpu/queensbay/Kconfig b/arch/x86/cpu/queensbay/Kconfig index 397e599..fbf85f2 100644 --- a/arch/x86/cpu/queensbay/Kconfig +++ b/arch/x86/cpu/queensbay/Kconfig @@ -38,4 +38,8 @@ config CMC_ADDR The default base address of 0xfffb0000 indicates that the binary must be located at offset 0xb0000 from the beginning of a 1MB flash device. +config CPU_ADDR_BITS + int + default 32 + endif diff --git a/arch/x86/cpu/queensbay/tnc.c b/arch/x86/cpu/queensbay/tnc.c index 873de7b..d27b2d9 100644 --- a/arch/x86/cpu/queensbay/tnc.c +++ b/arch/x86/cpu/queensbay/tnc.c @@ -69,17 +69,18 @@ void cpu_irq_init(void) * 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. + * A/B/C/D directly and not configurable, we have to route PCIe + * root ports' INTx to PIRQ A/B/C/D as well. For other devices + * on TunneCreek, route them 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); + writew(PIRQA, &rcba->d23ir); + writew(PIRQB, &rcba->d24ir); + writew(PIRQC, &rcba->d25ir); + writew(PIRQD, &rcba->d26ir); } int arch_misc_init(void) diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 2e5f9da..00e585e 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -116,12 +116,16 @@ car_init_ret: rep stosb #ifdef CONFIG_HAVE_FSP + test %esi, %esi + jz skip_hob + /* Store HOB list */ movl %esp, %edx addl $GD_HOB_LIST, %edx movl %esi, (%edx) -#endif +skip_hob: +#endif /* Setup first parameter to setup_gdt, pointer to global_data */ movl %esp, %eax diff --git a/arch/x86/cpu/start16.S b/arch/x86/cpu/start16.S index 826e2b4..5eb17f1 100644 --- a/arch/x86/cpu/start16.S +++ b/arch/x86/cpu/start16.S @@ -71,11 +71,12 @@ idt_ptr: */ gdt_ptr: .word 0x1f /* limit (31 bytes = 4 GDT entries - 1) */ - .long BOOT_SEG + gdt /* base */ + .long BOOT_SEG + gdt_rom /* base */ /* Some CPUs are picky about GDT alignment... */ .align 16 -gdt: +.globl gdt_rom +gdt_rom: /* * The GDT table ... * diff --git a/arch/x86/dts/crownbay.dts b/arch/x86/dts/crownbay.dts index d68efda..60da1f5 100644 --- a/arch/x86/dts/crownbay.dts +++ b/arch/x86/dts/crownbay.dts @@ -10,6 +10,7 @@ /include/ "skeleton.dtsi" /include/ "serial.dtsi" +/include/ "rtc.dtsi" / { model = "Intel Crown Bay"; @@ -23,6 +24,26 @@ silent_console = <0>; }; + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "cpu-x86"; + reg = <0>; + intel,apic-id = <0>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "cpu-x86"; + reg = <1>; + intel,apic-id = <1>; + }; + + }; + gpioa { compatible = "intel,ich6-gpio"; u-boot,dm-pre-reloc; @@ -148,10 +169,22 @@ /* TunnelCreek PCI devices */ PCI_BDF(0, 2, 0) INTA PIRQE PCI_BDF(0, 3, 0) INTA PIRQF - PCI_BDF(0, 23, 0) INTA PIRQE - PCI_BDF(0, 24, 0) INTA PIRQF - PCI_BDF(0, 25, 0) INTA PIRQG - PCI_BDF(0, 26, 0) INTA PIRQH + PCI_BDF(0, 23, 0) INTA PIRQA + PCI_BDF(0, 23, 0) INTB PIRQB + PCI_BDF(0, 23, 0) INTC PIRQC + PCI_BDF(0, 23, 0) INTD PIRQD + PCI_BDF(0, 24, 0) INTA PIRQB + PCI_BDF(0, 24, 0) INTB PIRQC + PCI_BDF(0, 24, 0) INTC PIRQD + PCI_BDF(0, 24, 0) INTD PIRQA + PCI_BDF(0, 25, 0) INTA PIRQC + PCI_BDF(0, 25, 0) INTB PIRQD + PCI_BDF(0, 25, 0) INTC PIRQA + PCI_BDF(0, 25, 0) INTD PIRQB + PCI_BDF(0, 26, 0) INTA PIRQD + PCI_BDF(0, 26, 0) INTB PIRQA + PCI_BDF(0, 26, 0) INTC PIRQB + PCI_BDF(0, 26, 0) INTD PIRQC PCI_BDF(0, 27, 0) INTA PIRQG /* * Topcliff PCI devices @@ -159,29 +192,29 @@ * Note on the Crown Bay board, Topcliff chipset * is connected to TunnelCreek PCIe port 0, so * its bus number is 1 for its PCIe port and 2 - * for its PCI devices per U-Boot currnet PCI + * for its PCI devices per U-Boot current PCI * bus enumeration algorithm. */ PCI_BDF(1, 0, 0) INTA PIRQA PCI_BDF(2, 0, 1) INTA PIRQA PCI_BDF(2, 0, 2) INTA PIRQA - PCI_BDF(2, 2, 0) INTB PIRQB - PCI_BDF(2, 2, 1) INTB PIRQB - PCI_BDF(2, 2, 2) INTB PIRQB - PCI_BDF(2, 2, 3) INTB PIRQB - PCI_BDF(2, 2, 4) INTB PIRQB + PCI_BDF(2, 2, 0) INTB PIRQD + PCI_BDF(2, 2, 1) INTB PIRQD + PCI_BDF(2, 2, 2) INTB PIRQD + PCI_BDF(2, 2, 3) INTB PIRQD + PCI_BDF(2, 2, 4) INTB PIRQD PCI_BDF(2, 4, 0) INTC PIRQC PCI_BDF(2, 4, 1) INTC PIRQC - PCI_BDF(2, 6, 0) INTD PIRQD + PCI_BDF(2, 6, 0) INTD PIRQB PCI_BDF(2, 8, 0) INTA PIRQA PCI_BDF(2, 8, 1) INTA PIRQA PCI_BDF(2, 8, 2) INTA PIRQA PCI_BDF(2, 8, 3) INTA PIRQA - PCI_BDF(2, 10, 0) INTB PIRQB - PCI_BDF(2, 10, 1) INTB PIRQB - PCI_BDF(2, 10, 2) INTB PIRQB - PCI_BDF(2, 10, 3) INTB PIRQB - PCI_BDF(2, 10, 4) INTB PIRQB + PCI_BDF(2, 10, 0) INTB PIRQD + PCI_BDF(2, 10, 1) INTB PIRQD + PCI_BDF(2, 10, 2) INTB PIRQD + PCI_BDF(2, 10, 3) INTB PIRQD + PCI_BDF(2, 10, 4) INTB PIRQD PCI_BDF(2, 12, 0) INTC PIRQC PCI_BDF(2, 12, 1) INTC PIRQC PCI_BDF(2, 12, 2) INTC PIRQC diff --git a/arch/x86/dts/minnowmax.dts b/arch/x86/dts/minnowmax.dts index bd21bfb..0e59b18 100644 --- a/arch/x86/dts/minnowmax.dts +++ b/arch/x86/dts/minnowmax.dts @@ -111,6 +111,16 @@ }; + pci { + compatible = "intel,pci-baytrail", "pci-x86"; + #address-cells = <3>; + #size-cells = <2>; + u-boot,dm-pre-reloc; + ranges = <0x02000000 0x0 0xd0000000 0xd0000000 0 0x10000000 + 0x42000000 0x0 0xc0000000 0xc0000000 0 0x10000000 + 0x01000000 0x0 0x2000 0x2000 0 0xe000>; + }; + spi { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/x86/dts/rtc.dtsi b/arch/x86/dts/rtc.dtsi new file mode 100644 index 0000000..93dacd7 --- /dev/null +++ b/arch/x86/dts/rtc.dtsi @@ -0,0 +1,6 @@ +/ { + rtc { + compatible = "motorola,mc146818"; + reg = <0x70 2>; + }; +}; diff --git a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h index 5ae32f7..7786493 100644 --- a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h +++ b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h @@ -16,7 +16,19 @@ int gma_func0_init(pci_dev_t dev, struct pci_controller *hose, const void *blob, int node); int bd82x6x_init(void); -struct x86_cpu_priv; +/** + * struct x86_cpu_priv - Information about a single CPU + * + * @apic_id: Advanced Programmable Interrupt Controller Identifier, which is + * just a number representing the CPU core + * + * TODO: Move this to driver model once lifecycle is understood + */ +struct x86_cpu_priv { + int apic_id; + int start_err; +}; + int model_206ax_init(struct x86_cpu_priv *cpu); #endif diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index ebc74ad..08284ee 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -197,20 +197,6 @@ const char *cpu_vendor_name(int vendor); char *cpu_get_name(char *name); /** - * -* x86_cpu_get_desc() - Get a description string for an x86 CPU -* -* This uses cpu_get_name() and is suitable to use as the get_desc() method for -* the CPU uclass. -* -* @dev: Device to check (UCLASS_CPU) -* @buf: Buffer to place string -* @size: Size of string space -* @return 0 if OK, -ENOSPC if buffer is too small, other -ve on error -*/ -int x86_cpu_get_desc(struct udevice *dev, char *buf, int size); - -/** * cpu_call64() - Jump to a 64-bit Linux kernel (internal function) * * The kernel is uncompressed and the 64-bit entry point is expected to be diff --git a/arch/x86/include/asm/cpu_x86.h b/arch/x86/include/asm/cpu_x86.h new file mode 100644 index 0000000..1940480 --- /dev/null +++ b/arch/x86/include/asm/cpu_x86.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _ASM_CPU_X86_H +#define _ASM_CPU_X86_H + +/** + * cpu_x86_bind() - Bind an x86 CPU with the driver + * + * This updates cpu device's platform data with information from device tree, + * like the processor local apic id. + * + * @dev: Device to check (UCLASS_CPU) + * @return 0 always + */ +int cpu_x86_bind(struct udevice *dev); + +/** + * cpu_x86_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 cpu_x86_get_desc(struct udevice *dev, char *buf, int size); + +#endif /* _ASM_CPU_X86_H */ diff --git a/arch/x86/include/asm/ioapic.h b/arch/x86/include/asm/ioapic.h index 699160f..77c443e 100644 --- a/arch/x86/include/asm/ioapic.h +++ b/arch/x86/include/asm/ioapic.h @@ -10,29 +10,33 @@ #define __ASM_IOAPIC_H #define IO_APIC_ADDR 0xfec00000 -#define IO_APIC_INDEX IO_APIC_ADDR + +/* Direct addressed register */ +#define IO_APIC_INDEX (IO_APIC_ADDR + 0x00) #define IO_APIC_DATA (IO_APIC_ADDR + 0x10) -#define IO_APIC_INTERRUPTS 24 -#define ALL (0xff << 24) -#define NONE 0 -#define DISABLED (1 << 16) -#define ENABLED (0 << 16) -#define TRIGGER_EDGE (0 << 15) -#define TRIGGER_LEVEL (1 << 15) -#define POLARITY_HIGH (0 << 13) -#define POLARITY_LOW (1 << 13) -#define PHYSICAL_DEST (0 << 11) -#define LOGICAL_DEST (1 << 11) -#define ExtINT (7 << 8) -#define NMI (4 << 8) -#define SMI (2 << 8) -#define INT (1 << 8) +/* Indirect addressed register offset */ +#define IO_APIC_ID 0x00 +#define IO_APIC_VER 0x01 + +/** + * io_apic_read() - Read I/O APIC register + * + * This routine reads I/O APIC indirect addressed register. + * + * @reg: address of indirect addressed register + * @return: register value to read + */ +u32 io_apic_read(u32 reg); -u32 io_apic_read(u32 ioapic_base, u32 reg); -void io_apic_write(u32 ioapic_base, u32 reg, u32 value); -void set_ioapic_id(u32 ioapic_base, u8 ioapic_id); -void setup_ioapic(u32 ioapic_base, u8 ioapic_id); -void clear_ioapic(u32 ioapic_base); +/** + * io_apic_write() - Write I/O APIC register + * + * This routine writes I/O APIC indirect addressed register. + * + * @reg: address of indirect addressed register + * @val: register value to write + */ +void io_apic_write(u32 reg, u32 val); #endif diff --git a/arch/x86/include/asm/lapic.h b/arch/x86/include/asm/lapic.h index 0a7f443..bc2b2d1 100644 --- a/arch/x86/include/asm/lapic.h +++ b/arch/x86/include/asm/lapic.h @@ -1,5 +1,5 @@ /* - * From Coreboot file of same name + * From coreboot file of same name * * Copyright (C) 2014 Google, Inc * @@ -9,171 +9,70 @@ #ifndef _ARCH_ASM_LAPIC_H #define _ARCH_ASM_LAPIC_H -#include <asm/io.h> -#include <asm/lapic_def.h> -#include <asm/msr.h> -#include <asm/processor.h> - -/* See if I need to initialize the local apic */ -#if CONFIG_SMP || CONFIG_IOAPIC -# define NEED_LAPIC 1 -#else -# define NEED_LAPIC 0 -#endif - -static inline __attribute__((always_inline)) - unsigned long lapic_read(unsigned long reg) -{ - return readl(LAPIC_DEFAULT_BASE + reg); -} - -static inline __attribute__((always_inline)) - void lapic_write(unsigned long reg, unsigned long val) -{ - writel(val, LAPIC_DEFAULT_BASE + reg); -} - -static inline __attribute__((always_inline)) void lapic_wait_icr_idle(void) -{ - do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY); -} - -static inline void enable_lapic(void) -{ - msr_t msr; - - msr = msr_read(LAPIC_BASE_MSR); - msr.hi &= 0xffffff00; - msr.lo |= LAPIC_BASE_MSR_ENABLE; - msr.lo &= ~LAPIC_BASE_MSR_ADDR_MASK; - msr.lo |= LAPIC_DEFAULT_BASE; - msr_write(LAPIC_BASE_MSR, msr); -} - -static inline void disable_lapic(void) -{ - msr_t msr; - - msr = msr_read(LAPIC_BASE_MSR); - msr.lo &= ~(1 << 11); - msr_write(LAPIC_BASE_MSR, msr); -} - -static inline __attribute__((always_inline)) unsigned long lapicid(void) -{ - return lapic_read(LAPIC_ID) >> 24; -} - -#if !CONFIG_AP_IN_SIPI_WAIT -/* If we need to go back to sipi wait, we use the long non-inlined version of - * this function in lapic_cpu_init.c - */ -static inline __attribute__((always_inline)) void stop_this_cpu(void) -{ - /* Called by an AP when it is ready to halt and wait for a new task */ - for (;;) - cpu_hlt(); -} -#else -void stop_this_cpu(void); -#endif - -#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \ - sizeof(*(ptr)))) - -struct __xchg_dummy { unsigned long a[100]; }; -#define __xg(x) ((struct __xchg_dummy *)(x)) - -/* - * Note: no "lock" prefix even on SMP: xchg always implies lock anyway - * Note 2: xchg has side effect, so that attribute volatile is necessary, - * but generally the primitive is invalid, *ptr is output argument. --ANK - */ -static inline unsigned long __xchg(unsigned long x, volatile void *ptr, - int size) -{ - switch (size) { - case 1: - __asm__ __volatile__("xchgb %b0,%1" - : "=q" (x) - : "m" (*__xg(ptr)), "0" (x) - : "memory"); - break; - case 2: - __asm__ __volatile__("xchgw %w0,%1" - : "=r" (x) - : "m" (*__xg(ptr)), "0" (x) - : "memory"); - break; - case 4: - __asm__ __volatile__("xchgl %0,%1" - : "=r" (x) - : "m" (*__xg(ptr)), "0" (x) - : "memory"); - break; - } - - return x; -} - -static inline void lapic_write_atomic(unsigned long reg, unsigned long v) -{ - (void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v); -} - - -#ifdef X86_GOOD_APIC -# define FORCE_READ_AROUND_WRITE 0 -# define lapic_read_around(x) lapic_read(x) -# define lapic_write_around(x, y) lapic_write((x), (y)) -#else -# define FORCE_READ_AROUND_WRITE 1 -# define lapic_read_around(x) lapic_read(x) -# define lapic_write_around(x, y) lapic_write_atomic((x), (y)) -#endif - -static inline int lapic_remote_read(int apicid, int reg, unsigned long *pvalue) -{ - int timeout; - unsigned long status; - int result; - lapic_wait_icr_idle(); - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); - lapic_write_around(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4)); - timeout = 0; - do { - status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK; - } while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000); - - result = -1; - if (status == LAPIC_ICR_RR_VALID) { - *pvalue = lapic_read(LAPIC_RRR); - result = 0; - } - return result; -} - +#define LAPIC_DEFAULT_BASE 0xfee00000 + +#define LAPIC_ID 0x020 +#define LAPIC_LVR 0x030 + +#define LAPIC_TASKPRI 0x080 +#define LAPIC_TPRI_MASK 0xff + +#define LAPIC_RRR 0x0c0 + +#define LAPIC_SPIV 0x0f0 +#define LAPIC_SPIV_ENABLE 0x100 + +#define LAPIC_ICR 0x300 +#define LAPIC_DEST_SELF 0x40000 +#define LAPIC_DEST_ALLINC 0x80000 +#define LAPIC_DEST_ALLBUT 0xc0000 +#define LAPIC_ICR_RR_MASK 0x30000 +#define LAPIC_ICR_RR_INVALID 0x00000 +#define LAPIC_ICR_RR_INPROG 0x10000 +#define LAPIC_ICR_RR_VALID 0x20000 +#define LAPIC_INT_LEVELTRIG 0x08000 +#define LAPIC_INT_ASSERT 0x04000 +#define LAPIC_ICR_BUSY 0x01000 +#define LAPIC_DEST_LOGICAL 0x00800 +#define LAPIC_DM_FIXED 0x00000 +#define LAPIC_DM_LOWEST 0x00100 +#define LAPIC_DM_SMI 0x00200 +#define LAPIC_DM_REMRD 0x00300 +#define LAPIC_DM_NMI 0x00400 +#define LAPIC_DM_INIT 0x00500 +#define LAPIC_DM_STARTUP 0x00600 +#define LAPIC_DM_EXTINT 0x00700 +#define LAPIC_VECTOR_MASK 0x000ff + +#define LAPIC_ICR2 0x310 +#define GET_LAPIC_DEST_FIELD(x) (((x) >> 24) & 0xff) +#define SET_LAPIC_DEST_FIELD(x) ((x) << 24) + +#define LAPIC_LVT0 0x350 +#define LAPIC_LVT1 0x360 +#define LAPIC_LVT_MASKED (1 << 16) +#define LAPIC_LVT_LEVEL_TRIGGER (1 << 15) +#define LAPIC_LVT_REMOTE_IRR (1 << 14) +#define LAPIC_INPUT_POLARITY (1 << 13) +#define LAPIC_SEND_PENDING (1 << 12) +#define LAPIC_LVT_RESERVED_1 (1 << 11) +#define LAPIC_DELIVERY_MODE_MASK (7 << 8) +#define LAPIC_DELIVERY_MODE_FIXED (0 << 8) +#define LAPIC_DELIVERY_MODE_NMI (4 << 8) +#define LAPIC_DELIVERY_MODE_EXTINT (7 << 8) + +unsigned long lapic_read(unsigned long reg); + +void lapic_write(unsigned long reg, unsigned long v); + +void enable_lapic(void); + +void disable_lapic(void); + +unsigned long lapicid(void); + +int lapic_remote_read(int apicid, int reg, unsigned long *pvalue); void lapic_setup(void); -#if CONFIG_SMP -struct device; -int start_cpu(struct device *cpu); -#endif /* CONFIG_SMP */ - -int boot_cpu(void); - -/** - * struct x86_cpu_priv - Information about a single CPU - * - * @apic_id: Advanced Programmable Interrupt Controller Identifier, which is - * just a number representing the CPU core - * - * TODO: Move this to driver model once lifecycle is understood - */ -struct x86_cpu_priv { - int apic_id; - int start_err; -}; - #endif diff --git a/arch/x86/include/asm/lapic_def.h b/arch/x86/include/asm/lapic_def.h deleted file mode 100644 index 722cead..0000000 --- a/arch/x86/include/asm/lapic_def.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Taken from the Coreboot file of the same name - * - * (C) Copyright 2014 Google, Inc - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#ifndef _ASM_LAPIC_DEF_H -#define _ASM_LAPIC_DEF_H - -#define LAPIC_BASE_MSR 0x1B -#define LAPIC_BASE_MSR_BOOTSTRAP_PROCESSOR (1 << 8) -#define LAPIC_BASE_MSR_ENABLE (1 << 11) -#define LAPIC_BASE_MSR_ADDR_MASK 0xFFFFF000 - -#define LOCAL_APIC_ADDR 0xfee00000 -#define LAPIC_DEFAULT_BASE LOCAL_APIC_ADDR - -#define LAPIC_ID 0x020 -#define LAPIC_LVR 0x030 -#define LAPIC_TASKPRI 0x80 -#define LAPIC_TPRI_MASK 0xFF -#define LAPIC_ARBID 0x090 -#define LAPIC_RRR 0x0C0 -#define LAPIC_SVR 0x0f0 -#define LAPIC_SPIV 0x0f0 -#define LAPIC_SPIV_ENABLE 0x100 -#define LAPIC_ESR 0x280 -#define LAPIC_ESR_SEND_CS 0x00001 -#define LAPIC_ESR_RECV_CS 0x00002 -#define LAPIC_ESR_SEND_ACC 0x00004 -#define LAPIC_ESR_RECV_ACC 0x00008 -#define LAPIC_ESR_SENDILL 0x00020 -#define LAPIC_ESR_RECVILL 0x00040 -#define LAPIC_ESR_ILLREGA 0x00080 -#define LAPIC_ICR 0x300 -#define LAPIC_DEST_SELF 0x40000 -#define LAPIC_DEST_ALLINC 0x80000 -#define LAPIC_DEST_ALLBUT 0xC0000 -#define LAPIC_ICR_RR_MASK 0x30000 -#define LAPIC_ICR_RR_INVALID 0x00000 -#define LAPIC_ICR_RR_INPROG 0x10000 -#define LAPIC_ICR_RR_VALID 0x20000 -#define LAPIC_INT_LEVELTRIG 0x08000 -#define LAPIC_INT_ASSERT 0x04000 -#define LAPIC_ICR_BUSY 0x01000 -#define LAPIC_DEST_LOGICAL 0x00800 -#define LAPIC_DM_FIXED 0x00000 -#define LAPIC_DM_LOWEST 0x00100 -#define LAPIC_DM_SMI 0x00200 -#define LAPIC_DM_REMRD 0x00300 -#define LAPIC_DM_NMI 0x00400 -#define LAPIC_DM_INIT 0x00500 -#define LAPIC_DM_STARTUP 0x00600 -#define LAPIC_DM_EXTINT 0x00700 -#define LAPIC_VECTOR_MASK 0x000FF -#define LAPIC_ICR2 0x310 -#define GET_LAPIC_DEST_FIELD(x) (((x) >> 24) & 0xFF) -#define SET_LAPIC_DEST_FIELD(x) ((x) << 24) -#define LAPIC_LVTT 0x320 -#define LAPIC_LVTPC 0x340 -#define LAPIC_LVT0 0x350 -#define LAPIC_LVT_TIMER_BASE_MASK (0x3 << 18) -#define GET_LAPIC_TIMER_BASE(x) (((x) >> 18) & 0x3) -#define SET_LAPIC_TIMER_BASE(x) (((x) << 18)) -#define LAPIC_TIMER_BASE_CLKIN 0x0 -#define LAPIC_TIMER_BASE_TMBASE 0x1 -#define LAPIC_TIMER_BASE_DIV 0x2 -#define LAPIC_LVT_TIMER_PERIODIC (1 << 17) -#define LAPIC_LVT_MASKED (1 << 16) -#define LAPIC_LVT_LEVEL_TRIGGER (1 << 15) -#define LAPIC_LVT_REMOTE_IRR (1 << 14) -#define LAPIC_INPUT_POLARITY (1 << 13) -#define LAPIC_SEND_PENDING (1 << 12) -#define LAPIC_LVT_RESERVED_1 (1 << 11) -#define LAPIC_DELIVERY_MODE_MASK (7 << 8) -#define LAPIC_DELIVERY_MODE_FIXED (0 << 8) -#define LAPIC_DELIVERY_MODE_NMI (4 << 8) -#define LAPIC_DELIVERY_MODE_EXTINT (7 << 8) -#define GET_LAPIC_DELIVERY_MODE(x) (((x) >> 8) & 0x7) -#define SET_LAPIC_DELIVERY_MODE(x, y) (((x) & ~0x700)|((y) << 8)) -#define LAPIC_MODE_FIXED 0x0 -#define LAPIC_MODE_NMI 0x4 -#define LAPIC_MODE_EXINT 0x7 -#define LAPIC_LVT1 0x360 -#define LAPIC_LVTERR 0x370 -#define LAPIC_TMICT 0x380 -#define LAPIC_TMCCT 0x390 -#define LAPIC_TDCR 0x3E0 -#define LAPIC_TDR_DIV_TMBASE (1 << 2) -#define LAPIC_TDR_DIV_1 0xB -#define LAPIC_TDR_DIV_2 0x0 -#define LAPIC_TDR_DIV_4 0x1 -#define LAPIC_TDR_DIV_8 0x2 -#define LAPIC_TDR_DIV_16 0x3 -#define LAPIC_TDR_DIV_32 0x8 -#define LAPIC_TDR_DIV_64 0x9 -#define LAPIC_TDR_DIV_128 0xA - -#endif diff --git a/arch/x86/include/asm/mp.h b/arch/x86/include/asm/mp.h index c0930fd..2e6c312 100644 --- a/arch/x86/include/asm/mp.h +++ b/arch/x86/include/asm/mp.h @@ -59,7 +59,6 @@ struct mp_flight_record { * 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 */ diff --git a/arch/x86/include/asm/mpspec.h b/arch/x86/include/asm/mpspec.h new file mode 100644 index 0000000..efa9231 --- /dev/null +++ b/arch/x86/include/asm/mpspec.h @@ -0,0 +1,444 @@ +/* + * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> + * + * Adapted from coreboot src/arch/x86/include/arch/smp/mpspec.h + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __ASM_MPSPEC_H +#define __ASM_MPSPEC_H + +/* + * Structure definitions for SMP machines following the + * Intel MultiProcessor Specification 1.4 + */ + +#define MPSPEC_V14 4 + +#define MPF_SIGNATURE "_MP_" + +struct mp_floating_table { + char mpf_signature[4]; /* "_MP_" */ + u32 mpf_physptr; /* Configuration table address */ + u8 mpf_length; /* Our length (paragraphs) */ + u8 mpf_spec; /* Specification version */ + u8 mpf_checksum; /* Checksum (makes sum 0) */ + u8 mpf_feature1; /* Predefined or Unique configuration? */ + u8 mpf_feature2; /* Bit7 set for IMCR/PIC */ + u8 mpf_feature3; /* Unused (0) */ + u8 mpf_feature4; /* Unused (0) */ + u8 mpf_feature5; /* Unused (0) */ +}; + +#define MPC_SIGNATURE "PCMP" + +struct mp_config_table { + char mpc_signature[4]; /* "PCMP" */ + u16 mpc_length; /* Size of table */ + u8 mpc_spec; /* Specification version */ + u8 mpc_checksum; /* Checksum (makes sum 0) */ + char mpc_oem[8]; /* OEM ID */ + char mpc_product[12]; /* Product ID */ + u32 mpc_oemptr; /* OEM table address */ + u16 mpc_oemsize; /* OEM table size */ + u16 mpc_entry_count; /* Number of entries in the table */ + u32 mpc_lapic; /* Local APIC address */ + u16 mpe_length; /* Extended table size */ + u8 mpe_checksum; /* Extended table checksum */ + u8 reserved; +}; + +/* Base MP configuration table entry types */ + +enum mp_base_config_entry_type { + MP_PROCESSOR, + MP_BUS, + MP_IOAPIC, + MP_INTSRC, + MP_LINTSRC +}; + +#define MPC_CPU_EN (1 << 0) +#define MPC_CPU_BP (1 << 1) + +struct mpc_config_processor { + u8 mpc_type; + u8 mpc_apicid; + u8 mpc_apicver; + u8 mpc_cpuflag; + u32 mpc_cpusignature; + u32 mpc_cpufeature; + u32 mpc_reserved[2]; +}; + +#define BUSTYPE_CBUS "CBUS " +#define BUSTYPE_CBUSII "CBUSII" +#define BUSTYPE_EISA "EISA " +#define BUSTYPE_FUTURE "FUTURE" +#define BUSTYPE_INTERN "INTERN" +#define BUSTYPE_ISA "ISA " +#define BUSTYPE_MBI "MBI " +#define BUSTYPE_MBII "MBII " +#define BUSTYPE_MCA "MCA " +#define BUSTYPE_MPI "MPI " +#define BUSTYPE_MPSA "MPSA " +#define BUSTYPE_NUBUS "NUBUS " +#define BUSTYPE_PCI "PCI " +#define BUSTYPE_PCMCIA "PCMCIA" +#define BUSTYPE_TC "TC " +#define BUSTYPE_VL "VL " +#define BUSTYPE_VME "VME " +#define BUSTYPE_XPRESS "XPRESS" + +struct mpc_config_bus { + u8 mpc_type; + u8 mpc_busid; + u8 mpc_bustype[6]; +}; + +#define MPC_APIC_USABLE (1 << 0) + +struct mpc_config_ioapic { + u8 mpc_type; + u8 mpc_apicid; + u8 mpc_apicver; + u8 mpc_flags; + u32 mpc_apicaddr; +}; + +enum mp_irq_source_types { + MP_INT, + MP_NMI, + MP_SMI, + MP_EXTINT +}; + +#define MP_IRQ_POLARITY_DEFAULT 0x0 +#define MP_IRQ_POLARITY_HIGH 0x1 +#define MP_IRQ_POLARITY_LOW 0x3 +#define MP_IRQ_POLARITY_MASK 0x3 +#define MP_IRQ_TRIGGER_DEFAULT 0x0 +#define MP_IRQ_TRIGGER_EDGE 0x4 +#define MP_IRQ_TRIGGER_LEVEL 0xc +#define MP_IRQ_TRIGGER_MASK 0xc + +#define MP_APIC_ALL 0xff + +struct mpc_config_intsrc { + u8 mpc_type; + u8 mpc_irqtype; + u16 mpc_irqflag; + u8 mpc_srcbus; + u8 mpc_srcbusirq; + u8 mpc_dstapic; + u8 mpc_dstirq; +}; + +struct mpc_config_lintsrc { + u8 mpc_type; + u8 mpc_irqtype; + u16 mpc_irqflag; + u8 mpc_srcbusid; + u8 mpc_srcbusirq; + u8 mpc_destapic; + u8 mpc_destlint; +}; + +/* Extended MP configuration table entry types */ + +enum mp_ext_config_entry_type { + MPE_SYSTEM_ADDRESS_SPACE = 128, + MPE_BUS_HIERARCHY, + MPE_COMPAT_ADDRESS_SPACE +}; + +struct mp_ext_config { + u8 mpe_type; + u8 mpe_length; +}; + +#define ADDRESS_TYPE_IO 0 +#define ADDRESS_TYPE_MEM 1 +#define ADDRESS_TYPE_PREFETCH 2 + +struct mp_ext_system_address_space { + u8 mpe_type; + u8 mpe_length; + u8 mpe_busid; + u8 mpe_addr_type; + u32 mpe_addr_base_low; + u32 mpe_addr_base_high; + u32 mpe_addr_length_low; + u32 mpe_addr_length_high; +}; + +#define BUS_SUBTRACTIVE_DECODE (1 << 0) + +struct mp_ext_bus_hierarchy { + u8 mpe_type; + u8 mpe_length; + u8 mpe_busid; + u8 mpe_bus_info; + u8 mpe_parent_busid; + u8 reserved[3]; +}; + +#define ADDRESS_RANGE_ADD 0 +#define ADDRESS_RANGE_SUBTRACT 1 + +/* + * X100 - X3FF + * X500 - X7FF + * X900 - XBFF + * XD00 - XFFF + */ +#define RANGE_LIST_IO_ISA 0 +/* + * X3B0 - X3BB + * X3C0 - X3DF + * X7B0 - X7BB + * X7C0 - X7DF + * XBB0 - XBBB + * XBC0 - XBDF + * XFB0 - XFBB + * XFC0 - XCDF + */ +#define RANGE_LIST_IO_VGA 1 + +struct mp_ext_compat_address_space { + u8 mpe_type; + u8 mpe_length; + u8 mpe_busid; + u8 mpe_addr_modifier; + u32 mpe_range_list; +}; + +/** + * mp_next_mpc_entry() - Compute MP configuration table end to be used as + * next base table entry start address + * + * This computes the end address of current MP configuration table, without + * counting any extended configuration table entry. + * + * @mc: configuration table header address + * @return: configuration table end address + */ +static inline u32 mp_next_mpc_entry(struct mp_config_table *mc) +{ + return (u32)mc + mc->mpc_length; +} + +/** + * mp_add_mpc_entry() - Add a base MP configuration table entry + * + * This adds the base MP configuration table entry size with + * added base table entry length and increases entry count by 1. + * + * @mc: configuration table header address + * @length: length of the added table entry + */ +static inline void mp_add_mpc_entry(struct mp_config_table *mc, uint length) +{ + mc->mpc_length += length; + mc->mpc_entry_count++; +} + +/** + * mp_next_mpe_entry() - Compute MP configuration table end to be used as + * next extended table entry start address + * + * This computes the end address of current MP configuration table, + * including any extended configuration table entry. + * + * @mc: configuration table header address + * @return: configuration table end address + */ +static inline u32 mp_next_mpe_entry(struct mp_config_table *mc) +{ + return (u32)mc + mc->mpc_length + mc->mpe_length; +} + +/** + * mp_add_mpe_entry() - Add an extended MP configuration table entry + * + * This adds the extended MP configuration table entry size with + * added extended table entry length. + * + * @mc: configuration table header address + * @mpe: extended table entry base address + */ +static inline void mp_add_mpe_entry(struct mp_config_table *mc, + struct mp_ext_config *mpe) +{ + mc->mpe_length += mpe->mpe_length; +} + +/** + * mp_write_floating_table() - Write the MP floating table + * + * This writes the MP floating table, and points MP configuration table + * to its end address so that MP configuration table follows immediately + * after the floating table. + * + * @mf: MP floating table base address + * @return: MP configuration table header address + */ +struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf); + +/** + * mp_config_table_init() - Initialize the MP configuration table header + * + * This populates the MP configuration table header with valid bits. + * + * @mc: MP configuration table header address + */ +void mp_config_table_init(struct mp_config_table *mc); + +/** + * mp_write_processor() - Write a processor entry + * + * This writes a processor entry to the configuration table. + * + * @mc: MP configuration table header address + */ +void mp_write_processor(struct mp_config_table *mc); + +/** + * mp_write_bus() - Write a bus entry + * + * This writes a bus entry to the configuration table. + * + * @mc: MP configuration table header address + * @id: bus id + * @bustype: bus type name + */ +void mp_write_bus(struct mp_config_table *mc, int id, const char *bustype); + +/** + * mp_write_ioapic() - Write an I/O APIC entry + * + * This writes an I/O APIC entry to the configuration table. + * + * @mc: MP configuration table header address + * @id: I/O APIC id + * @ver: I/O APIC version + * @apicaddr: I/O APIC address + */ +void mp_write_ioapic(struct mp_config_table *mc, int id, int ver, u32 apicaddr); + +/** + * mp_write_intsrc() - Write an I/O interrupt assignment entry + * + * This writes an I/O interrupt assignment entry to the configuration table. + * + * @mc: MP configuration table header address + * @irqtype: IRQ type (INT/NMI/SMI/ExtINT) + * @irqflag: IRQ flag (level/trigger) + * @srcbus: source bus id where the interrupt comes from + * @srcbusirq: IRQ number mapped on the source bus + * @dstapic: destination I/O APIC id where the interrupt goes to + * @dstirq: destination I/O APIC pin where the interrupt goes to + */ +void mp_write_intsrc(struct mp_config_table *mc, int irqtype, int irqflag, + int srcbus, int srcbusirq, int dstapic, int dstirq); + +/** + * mp_write_pci_intsrc() - Write a PCI interrupt assignment entry + * + * This writes a PCI interrupt assignment entry to the configuration table. + * + * @mc: MP configuration table header address + * @irqtype: IRQ type (INT/NMI/SMI/ExtINT) + * @srcbus: PCI bus number where the interrupt comes from + * @dev: device number on the PCI bus + * @pin: PCI interrupt pin (INT A/B/C/D) + * @dstapic: destination I/O APIC id where the interrupt goes to + * @dstirq: destination I/O APIC pin where the interrupt goes to + */ +void mp_write_pci_intsrc(struct mp_config_table *mc, int irqtype, + int srcbus, int dev, int pin, int dstapic, int dstirq); + +/** + * mp_write_lintsrc() - Write a local interrupt assignment entry + * + * This writes a local interrupt assignment entry to the configuration table. + * + * @mc: MP configuration table header address + * @irqtype: IRQ type (INT/NMI/SMI/ExtINT) + * @irqflag: IRQ flag (level/trigger) + * @srcbus: PCI bus number where the interrupt comes from + * @srcbusirq: IRQ number mapped on the source bus + * @dstapic: destination local APIC id where the interrupt goes to + * @destlint: destination local APIC pin where the interrupt goes to + */ +void mp_write_lintsrc(struct mp_config_table *mc, int irqtype, int irqflag, + int srcbus, int srcbusirq, int destapic, int destlint); + + +/** + * mp_write_address_space() - Write a system address space entry + * + * This writes a system address space entry to the configuration table. + * + * @mc: MP configuration table header address + * @busid: bus id for the bus where system address space is mapped + * @addr_type: system address type + * @addr_base_low: starting address low + * @addr_base_high: starting address high + * @addr_length_low: address length low + * @addr_length_high: address length high + */ +void mp_write_address_space(struct mp_config_table *mc, + int busid, int addr_type, + u32 addr_base_low, u32 addr_base_high, + u32 addr_length_low, u32 addr_length_high); + +/** + * mp_write_bus_hierarchy() - Write a bus hierarchy descriptor entry + * + * This writes a bus hierarchy descriptor entry to the configuration table. + * + * @mc: MP configuration table header address + * @busid: bus id + * @bus_info: bit0 indicates if the bus is a subtractive decode bus + * @parent_busid: parent bus id + */ +void mp_write_bus_hierarchy(struct mp_config_table *mc, + int busid, int bus_info, int parent_busid); + +/** + * mp_write_compat_address_space() - Write a compat bus address space entry + * + * This writes a compatibility bus address space modifier entry to the + * configuration table. + * + * @mc: MP configuration table header address + * @busid: bus id + * @addr_modifier: add or subtract to predefined address range list + * @range_list: list of predefined address space ranges + */ +void mp_write_compat_address_space(struct mp_config_table *mc, int busid, + int addr_modifier, u32 range_list); + +/** + * mptable_finalize() - Finalize the MP table + * + * This finalizes the MP table by calculating required checksums. + * + * @mc: MP configuration table header address + * @return: MP table end address + */ +u32 mptable_finalize(struct mp_config_table *mc); + +/** + * write_mp_table() - Write MP table + * + * This writes MP table at a given address. + * + * @addr: start address to write MP table + * @return: end address of MP table + */ +u32 write_mp_table(u32 addr); + +#endif /* __ASM_MPSPEC_H */ diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h index 3ad617c..70762ee 100644 --- a/arch/x86/include/asm/mtrr.h +++ b/arch/x86/include/asm/mtrr.h @@ -21,6 +21,11 @@ #define MTRR_CAP_MSR 0x0fe #define MTRR_DEF_TYPE_MSR 0x2ff +#define MTRR_CAP_SMRR (1 << 11) +#define MTRR_CAP_WC (1 << 10) +#define MTRR_CAP_FIX (1 << 8) +#define MTRR_CAP_VCNT_MASK 0xff + #define MTRR_DEF_TYPE_EN (1 << 11) #define MTRR_DEF_TYPE_FIX_EN (1 << 10) @@ -38,17 +43,17 @@ #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 +#define MTRR_FIX_64K_00000_MSR 0x250 +#define MTRR_FIX_16K_80000_MSR 0x258 +#define MTRR_FIX_16K_A0000_MSR 0x259 +#define MTRR_FIX_4K_C0000_MSR 0x268 +#define MTRR_FIX_4K_C8000_MSR 0x269 +#define MTRR_FIX_4K_D0000_MSR 0x26a +#define MTRR_FIX_4K_D8000_MSR 0x26b +#define MTRR_FIX_4K_E0000_MSR 0x26c +#define MTRR_FIX_4K_E8000_MSR 0x26d +#define MTRR_FIX_4K_F0000_MSR 0x26e +#define MTRR_FIX_4K_F8000_MSR 0x26f #if !defined(__ASSEMBLER__) diff --git a/arch/x86/include/asm/tables.h b/arch/x86/include/asm/tables.h index 8146ba3..0aa6d9b 100644 --- a/arch/x86/include/asm/tables.h +++ b/arch/x86/include/asm/tables.h @@ -28,6 +28,20 @@ u8 table_compute_checksum(void *v, int len); /** + * table_fill_string() - Fill a string with pad in the configuration table + * + * This fills a string in the configuration table. It copies number of bytes + * from the source string, and if source string length is shorter than the + * required size to copy, pad the table string with the given pad character. + * + * @dest: where to fill a string + * @src: where to copy from + * @n: number of bytes to copy + * @pad: character to pad the remaining bytes + */ +void table_fill_string(char *dest, const char *src, size_t n, char pad); + +/** * write_tables() - Write x86 configuration tables * * This writes x86 configuration tables, including PIRQ routing table, diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index d1d21ed..4dae365 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -8,12 +8,19 @@ #ifndef _U_BOOT_I386_H_ #define _U_BOOT_I386_H_ 1 +extern char gdt_rom[]; + /* cpu/.../cpu.c */ int arch_cpu_init(void); int x86_cpu_init_f(void); int cpu_init_f(void); void init_gd(gd_t *id, u64 *gdt_addr); void setup_gdt(gd_t *id, u64 *gdt_addr); +/* + * Setup FSP execution environment GDT to use the one we used in + * arch/x86/cpu/start16.S and reload the segment registers. + */ +void setup_fsp_gdt(void); int init_cache(void); int cleanup_before_linux(void); @@ -49,6 +56,9 @@ u32 isa_map_rom(u32 bus_addr, int size); /* arch/x86/lib/... */ int video_bios_init(void); +/* arch/x86/lib/fsp/... */ +int x86_fsp_init(void); + void board_init_f_r_trampoline(ulong) __attribute__ ((noreturn)); void board_init_f_r(void) __attribute__ ((noreturn)); diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h index 8e7dd42..bf351ed 100644 --- a/arch/x86/include/asm/zimage.h +++ b/arch/x86/include/asm/zimage.h @@ -38,5 +38,6 @@ struct boot_params *load_zimage(char *image, unsigned long kernel_size, ulong *load_addressp); int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, unsigned long initrd_addr, unsigned long initrd_size); +void setup_video(struct screen_info *screen_info); #endif diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 70ad19b..43489fd 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -15,6 +15,7 @@ obj-y += gcc.o obj-y += init_helpers.o obj-y += interrupts.o obj-y += lpc-uclass.o +obj-y += mpspec.o obj-y += cmd_mtrr.o obj-$(CONFIG_SYS_PCAT_INTERRUPTS) += pcat_interrupts.o obj-$(CONFIG_SYS_PCAT_TIMER) += pcat_timer.o diff --git a/arch/x86/lib/bios_asm.S b/arch/x86/lib/bios_asm.S index 4faa70e..9dbf969 100644 --- a/arch/x86/lib/bios_asm.S +++ b/arch/x86/lib/bios_asm.S @@ -246,6 +246,9 @@ __interrupt_handler_16bit = PTR_TO_REAL_MODE(.) push %fs push %gs + /* Save real mode SS */ + movw %ss, %cs:__realmode_ss + /* Clear DF to not break ABI assumptions */ cld @@ -258,12 +261,29 @@ __interrupt_handler_16bit = PTR_TO_REAL_MODE(.) enter_protected_mode + /* + * Now we are in protected mode. We need compute the right ESP based + * on saved real mode SS otherwise interrupt_handler() won't get + * correct parameters from the stack. + */ + movzwl %cs:__realmode_ss, %ecx + shll $4, %ecx + addl %ecx, %esp + /* Call the C interrupt handler */ movl $interrupt_handler, %eax call *%eax + /* Restore real mode ESP based on saved SS */ + movzwl %cs:__realmode_ss, %ecx + shll $4, %ecx + subl %ecx, %esp + enter_real_mode + /* Restore real mode SS */ + movw %cs:__realmode_ss, %ss + /* * Restore all registers, including those manipulated by the C * handler @@ -276,6 +296,9 @@ __interrupt_handler_16bit = PTR_TO_REAL_MODE(.) popal iret +__realmode_ss = PTR_TO_REAL_MODE(.) + .word 0 + .globl asm_realmode_code_size asm_realmode_code_size: .long . - asm_realmode_code diff --git a/arch/x86/lib/bios_interrupts.c b/arch/x86/lib/bios_interrupts.c index 290990a..47d9f59 100644 --- a/arch/x86/lib/bios_interrupts.c +++ b/arch/x86/lib/bios_interrupts.c @@ -161,15 +161,7 @@ int int1a_handler(void) bus = M.x86.R_EBX >> 8; reg = M.x86.R_EDI; dev = PCI_BDF(bus, devfn >> 3, devfn & 7); - if (!dev) { - debug("0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, - bus, devfn); - /* Or are we supposed to return PCIBIOS_NODEV? */ - M.x86.R_EAX &= 0xffff00ff; /* Clear AH */ - M.x86.R_EAX |= PCIBIOS_BADREG; - retval = 0; - return retval; - } + switch (func) { case 0xb108: /* Read Config Byte */ byte = x86_pci_read_config8(dev, reg); diff --git a/arch/x86/lib/cmd_mtrr.c b/arch/x86/lib/cmd_mtrr.c index 7e0506b..f632f49 100644 --- a/arch/x86/lib/cmd_mtrr.c +++ b/arch/x86/lib/cmd_mtrr.c @@ -37,7 +37,8 @@ static int do_mtrr_list(void) valid = mask & MTRR_PHYS_MASK_VALID; type = mtrr_type_name[base & MTRR_BASE_TYPE_MASK]; printf("%d %-5s %-12s %016llx %016llx %016llx\n", i, - valid ? "Y" : "N", type, base, mask, size); + valid ? "Y" : "N", type, base & ~MTRR_BASE_TYPE_MASK, + mask & ~MTRR_PHYS_MASK_VALID, size); } return 0; diff --git a/arch/x86/lib/fsp/fsp_car.S b/arch/x86/lib/fsp/fsp_car.S index 5e09568..afbf3f9 100644 --- a/arch/x86/lib/fsp/fsp_car.S +++ b/arch/x86/lib/fsp/fsp_car.S @@ -56,28 +56,10 @@ temp_ram_init_ret: /* stack grows down from top of CAR */ movl %edx, %esp + subl $4, %esp - /* - * TODO: - * - * According to FSP architecture spec, the fsp_init() will not return - * to its caller, instead it requires the bootloader to provide a - * so-called continuation function to pass into the FSP as a parameter - * of fsp_init, and fsp_init() will call that continuation function - * directly. - * - * The call to fsp_init() may need to be moved out of the car_init() - * to cpu_init_f() with the help of some inline assembly codes. - * Note there is another issue that fsp_init() will setup another stack - * using the fsp_init parameter stack_top after DRAM is initialized, - * which means any data on the previous stack (on the CAR) gets lost - * (ie: U-Boot global_data). FSP is supposed to support such scenario, - * however it does not work. This should be revisited in the future. - */ - movl $CONFIG_FSP_TEMP_RAM_ADDR, %eax - xorl %edx, %edx - xorl %ecx, %ecx - call fsp_init + xor %esi, %esi + jmp car_init_done .global fsp_init_done fsp_init_done: @@ -86,6 +68,8 @@ fsp_init_done: * Save eax to esi temporarily. */ movl %eax, %esi + +car_init_done: /* * Re-initialize the ebp (BIST) to zero, as we already reach here * which means we passed BIST testing before. diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index 001494d..5b25632 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -46,3 +46,11 @@ void board_final_cleanup(void) return; } + +int x86_fsp_init(void) +{ + if (!gd->arch.hob_list) + fsp_init(CONFIG_FSP_TEMP_RAM_ADDR, BOOT_FULL_CONFIG, NULL); + + return 0; +} diff --git a/arch/x86/lib/fsp/fsp_support.c b/arch/x86/lib/fsp/fsp_support.c index 5809235..4585166 100644 --- a/arch/x86/lib/fsp/fsp_support.c +++ b/arch/x86/lib/fsp/fsp_support.c @@ -173,6 +173,9 @@ void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf) post_code(POST_PRE_MRC); + /* Load GDT for FSP */ + setup_fsp_gdt(); + /* * Use ASM code to ensure the register value in EAX & ECX * will be passed into BlContinuationFunc diff --git a/arch/x86/lib/mpspec.c b/arch/x86/lib/mpspec.c new file mode 100644 index 0000000..f16fbcb --- /dev/null +++ b/arch/x86/lib/mpspec.c @@ -0,0 +1,382 @@ +/* + * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> + * + * Adapted from coreboot src/arch/x86/boot/mpspec.c + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <cpu.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <asm/cpu.h> +#include <asm/irq.h> +#include <asm/ioapic.h> +#include <asm/lapic.h> +#include <asm/mpspec.h> +#include <asm/tables.h> +#include <dm/uclass-internal.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf) +{ + u32 mc; + + memcpy(mf->mpf_signature, MPF_SIGNATURE, 4); + mf->mpf_physptr = (u32)mf + sizeof(struct mp_floating_table); + mf->mpf_length = 1; + mf->mpf_spec = MPSPEC_V14; + mf->mpf_checksum = 0; + /* We don't use the default configuration table */ + mf->mpf_feature1 = 0; + /* Indicate that virtual wire mode is always implemented */ + mf->mpf_feature2 = 0; + mf->mpf_feature3 = 0; + mf->mpf_feature4 = 0; + mf->mpf_feature5 = 0; + mf->mpf_checksum = table_compute_checksum(mf, mf->mpf_length * 16); + + mc = (u32)mf + sizeof(struct mp_floating_table); + return (struct mp_config_table *)mc; +} + +void mp_config_table_init(struct mp_config_table *mc) +{ + memcpy(mc->mpc_signature, MPC_SIGNATURE, 4); + mc->mpc_length = sizeof(struct mp_config_table); + mc->mpc_spec = MPSPEC_V14; + mc->mpc_checksum = 0; + mc->mpc_oemptr = 0; + mc->mpc_oemsize = 0; + mc->mpc_entry_count = 0; + mc->mpc_lapic = LAPIC_DEFAULT_BASE; + mc->mpe_length = 0; + mc->mpe_checksum = 0; + mc->reserved = 0; + + /* The oem/product id fields are exactly 8/12 bytes long */ + table_fill_string(mc->mpc_oem, CONFIG_SYS_VENDOR, 8, ' '); + table_fill_string(mc->mpc_product, CONFIG_SYS_BOARD, 12, ' '); +} + +void mp_write_processor(struct mp_config_table *mc) +{ + struct mpc_config_processor *mpc; + struct udevice *dev; + u8 boot_apicid, apicver; + u32 cpusignature, cpufeature; + struct cpuid_result result; + + boot_apicid = lapicid(); + apicver = lapic_read(LAPIC_LVR) & 0xff; + result = cpuid(1); + cpusignature = result.eax; + cpufeature = result.edx; + + for (uclass_find_first_device(UCLASS_CPU, &dev); + dev; + uclass_find_next_device(&dev)) { + struct cpu_platdata *plat = dev_get_parent_platdata(dev); + u8 cpuflag = MPC_CPU_EN; + + if (!device_active(dev)) + continue; + + mpc = (struct mpc_config_processor *)mp_next_mpc_entry(mc); + mpc->mpc_type = MP_PROCESSOR; + mpc->mpc_apicid = plat->cpu_id; + mpc->mpc_apicver = apicver; + if (boot_apicid == plat->cpu_id) + cpuflag |= MPC_CPU_BP; + mpc->mpc_cpuflag = cpuflag; + mpc->mpc_cpusignature = cpusignature; + mpc->mpc_cpufeature = cpufeature; + mpc->mpc_reserved[0] = 0; + mpc->mpc_reserved[1] = 0; + mp_add_mpc_entry(mc, sizeof(*mpc)); + } +} + +void mp_write_bus(struct mp_config_table *mc, int id, const char *bustype) +{ + struct mpc_config_bus *mpc; + + mpc = (struct mpc_config_bus *)mp_next_mpc_entry(mc); + mpc->mpc_type = MP_BUS; + mpc->mpc_busid = id; + memcpy(mpc->mpc_bustype, bustype, 6); + mp_add_mpc_entry(mc, sizeof(*mpc)); +} + +void mp_write_ioapic(struct mp_config_table *mc, int id, int ver, u32 apicaddr) +{ + struct mpc_config_ioapic *mpc; + + mpc = (struct mpc_config_ioapic *)mp_next_mpc_entry(mc); + mpc->mpc_type = MP_IOAPIC; + mpc->mpc_apicid = id; + mpc->mpc_apicver = ver; + mpc->mpc_flags = MPC_APIC_USABLE; + mpc->mpc_apicaddr = apicaddr; + mp_add_mpc_entry(mc, sizeof(*mpc)); +} + +void mp_write_intsrc(struct mp_config_table *mc, int irqtype, int irqflag, + int srcbus, int srcbusirq, int dstapic, int dstirq) +{ + struct mpc_config_intsrc *mpc; + + mpc = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc); + mpc->mpc_type = MP_INTSRC; + mpc->mpc_irqtype = irqtype; + mpc->mpc_irqflag = irqflag; + mpc->mpc_srcbus = srcbus; + mpc->mpc_srcbusirq = srcbusirq; + mpc->mpc_dstapic = dstapic; + mpc->mpc_dstirq = dstirq; + mp_add_mpc_entry(mc, sizeof(*mpc)); +} + +void mp_write_pci_intsrc(struct mp_config_table *mc, int irqtype, + int srcbus, int dev, int pin, int dstapic, int dstirq) +{ + u8 srcbusirq = (dev << 2) | (pin - 1); + + mp_write_intsrc(mc, irqtype, MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW, + srcbus, srcbusirq, dstapic, dstirq); +} + +void mp_write_lintsrc(struct mp_config_table *mc, int irqtype, int irqflag, + int srcbus, int srcbusirq, int destapic, int destlint) +{ + struct mpc_config_lintsrc *mpc; + + mpc = (struct mpc_config_lintsrc *)mp_next_mpc_entry(mc); + mpc->mpc_type = MP_LINTSRC; + mpc->mpc_irqtype = irqtype; + mpc->mpc_irqflag = irqflag; + mpc->mpc_srcbusid = srcbus; + mpc->mpc_srcbusirq = srcbusirq; + mpc->mpc_destapic = destapic; + mpc->mpc_destlint = destlint; + mp_add_mpc_entry(mc, sizeof(*mpc)); +} + +void mp_write_address_space(struct mp_config_table *mc, + int busid, int addr_type, + u32 addr_base_low, u32 addr_base_high, + u32 addr_length_low, u32 addr_length_high) +{ + struct mp_ext_system_address_space *mpe; + + mpe = (struct mp_ext_system_address_space *)mp_next_mpe_entry(mc); + mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE; + mpe->mpe_length = sizeof(*mpe); + mpe->mpe_busid = busid; + mpe->mpe_addr_type = addr_type; + mpe->mpe_addr_base_low = addr_base_low; + mpe->mpe_addr_base_high = addr_base_high; + mpe->mpe_addr_length_low = addr_length_low; + mpe->mpe_addr_length_high = addr_length_high; + mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); +} + +void mp_write_bus_hierarchy(struct mp_config_table *mc, + int busid, int bus_info, int parent_busid) +{ + struct mp_ext_bus_hierarchy *mpe; + + mpe = (struct mp_ext_bus_hierarchy *)mp_next_mpe_entry(mc); + mpe->mpe_type = MPE_BUS_HIERARCHY; + mpe->mpe_length = sizeof(*mpe); + mpe->mpe_busid = busid; + mpe->mpe_bus_info = bus_info; + mpe->mpe_parent_busid = parent_busid; + mpe->reserved[0] = 0; + mpe->reserved[1] = 0; + mpe->reserved[2] = 0; + mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); +} + +void mp_write_compat_address_space(struct mp_config_table *mc, int busid, + int addr_modifier, u32 range_list) +{ + struct mp_ext_compat_address_space *mpe; + + mpe = (struct mp_ext_compat_address_space *)mp_next_mpe_entry(mc); + mpe->mpe_type = MPE_COMPAT_ADDRESS_SPACE; + mpe->mpe_length = sizeof(*mpe); + mpe->mpe_busid = busid; + mpe->mpe_addr_modifier = addr_modifier; + mpe->mpe_range_list = range_list; + mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); +} + +u32 mptable_finalize(struct mp_config_table *mc) +{ + u32 end; + + mc->mpe_checksum = table_compute_checksum((void *)mp_next_mpc_entry(mc), + mc->mpe_length); + mc->mpc_checksum = table_compute_checksum(mc, mc->mpc_length); + end = mp_next_mpe_entry(mc); + + debug("Write the MP table at: %x - %x\n", (u32)mc, end); + + return end; +} + +static void mptable_add_isa_interrupts(struct mp_config_table *mc, int bus_isa, + int apicid, int external_int2) +{ + int i; + + mp_write_intsrc(mc, external_int2 ? MP_INT : MP_EXTINT, + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, 0, apicid, 0); + mp_write_intsrc(mc, MP_INT, MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, 1, apicid, 1); + mp_write_intsrc(mc, external_int2 ? MP_EXTINT : MP_INT, + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, 0, apicid, 2); + + for (i = 3; i < 16; i++) + mp_write_intsrc(mc, MP_INT, + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, i, apicid, i); +} + +/* + * Check duplicated I/O interrupt assignment table entry, to make sure + * there is only one entry with the given bus, device and interrupt pin. + */ +static bool check_dup_entry(struct mpc_config_intsrc *intsrc_base, + int entry_num, int bus, int device, int pin) +{ + struct mpc_config_intsrc *intsrc = intsrc_base; + int i; + + for (i = 0; i < entry_num; i++) { + if (intsrc->mpc_srcbus == bus && + intsrc->mpc_srcbusirq == ((device << 2) | (pin - 1))) + break; + intsrc++; + } + + return (i == entry_num) ? false : true; +} + +static int mptable_add_intsrc(struct mp_config_table *mc, + int bus_isa, int apicid) +{ + struct mpc_config_intsrc *intsrc_base; + int intsrc_entries = 0; + const void *blob = gd->fdt_blob; + int node; + int len, count; + const u32 *cell; + int i; + + /* Legacy Interrupts */ + debug("Writing ISA IRQs\n"); + mptable_add_isa_interrupts(mc, bus_isa, apicid, 0); + + /* Get I/O interrupt information from device tree */ + node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_IRQ_ROUTER); + if (node < 0) { + debug("%s: Cannot find irq router node\n", __func__); + return -ENOENT; + } + + cell = fdt_getprop(blob, node, "intel,pirq-routing", &len); + if (!cell) + return -ENOENT; + + if ((len % sizeof(struct pirq_routing)) == 0) + count = len / sizeof(struct pirq_routing); + else + return -EINVAL; + + intsrc_base = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc); + + for (i = 0; i < count; i++) { + struct pirq_routing pr; + + pr.bdf = fdt_addr_to_cpu(cell[0]); + pr.pin = fdt_addr_to_cpu(cell[1]); + pr.pirq = fdt_addr_to_cpu(cell[2]); + + if (check_dup_entry(intsrc_base, intsrc_entries, + PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), pr.pin)) { + debug("found entry for bus %d device %d INT%c, skipping\n", + PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), + 'A' + pr.pin - 1); + cell += sizeof(struct pirq_routing) / sizeof(u32); + continue; + } + + /* PIRQ[A-H] are always connected to I/O APIC INTPIN#16-23 */ + mp_write_pci_intsrc(mc, MP_INT, PCI_BUS(pr.bdf), + PCI_DEV(pr.bdf), pr.pin, apicid, + pr.pirq + 16); + intsrc_entries++; + cell += sizeof(struct pirq_routing) / sizeof(u32); + } + + return 0; +} + +static void mptable_add_lintsrc(struct mp_config_table *mc, int bus_isa) +{ + mp_write_lintsrc(mc, MP_EXTINT, + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, 0, MP_APIC_ALL, 0); + mp_write_lintsrc(mc, MP_NMI, + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, 0, MP_APIC_ALL, 1); +} + +u32 write_mp_table(u32 addr) +{ + struct mp_config_table *mc; + int ioapic_id, ioapic_ver; + int bus_isa = 0xff; + int ret; + u32 end; + + /* 16 byte align the table address */ + addr = ALIGN(addr, 16); + + /* Write floating table */ + mc = mp_write_floating_table((struct mp_floating_table *)addr); + + /* Write configuration table header */ + mp_config_table_init(mc); + + /* Write processor entry */ + mp_write_processor(mc); + + /* Write bus entry */ + mp_write_bus(mc, bus_isa, BUSTYPE_ISA); + + /* Write I/O APIC entry */ + ioapic_id = io_apic_read(IO_APIC_ID) >> 24; + ioapic_ver = io_apic_read(IO_APIC_VER) & 0xff; + mp_write_ioapic(mc, ioapic_id, ioapic_ver, IO_APIC_ADDR); + + /* Write I/O interrupt assignment entry */ + ret = mptable_add_intsrc(mc, bus_isa, ioapic_id); + if (ret) + debug("Failed to write I/O interrupt assignment table\n"); + + /* Write local interrupt assignment entry */ + mptable_add_lintsrc(mc, bus_isa); + + /* Finalize the MP table */ + end = mptable_finalize(mc); + + return end; +} diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index 8031201..75ffbc1 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -6,6 +6,7 @@ #include <common.h> #include <asm/sfi.h> +#include <asm/mpspec.h> #include <asm/tables.h> u8 table_compute_checksum(void *v, int len) @@ -20,6 +21,20 @@ u8 table_compute_checksum(void *v, int len) return checksum; } +void table_fill_string(char *dest, const char *src, size_t n, char pad) +{ + int start, len; + int i; + + strncpy(dest, src, n); + + /* Fill the remaining bytes with pad */ + len = strlen(src); + start = len < n ? len : n; + for (i = start; i < n; i++) + dest[i] = pad; +} + void write_tables(void) { u32 __maybe_unused rom_table_end = ROM_TABLE_ADDR; @@ -32,4 +47,8 @@ void write_tables(void) rom_table_end = write_sfi_table(rom_table_end); rom_table_end = ALIGN(rom_table_end, 1024); #endif +#ifdef CONFIG_GENERATE_MP_TABLE + rom_table_end = write_mp_table(rom_table_end); + rom_table_end = ALIGN(rom_table_end, 1024); +#endif } diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index c3f8a73..144471c 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -273,6 +273,8 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, build_command_line(cmd_line, auto_boot); } + setup_video(&setup_base->screen_info); + return 0; } |