From a65b25d148fb0a9ef7dd5fba4ae2709f5bcae0c6 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 7 May 2015 21:34:08 +0800 Subject: x86: Support QEMU x86 targets This commit introduces the initial U-Boot support for QEMU x86 targets. U-Boot can boot from coreboot as a payload, or directly without coreboot. Signed-off-by: Bin Meng Acked-by: Simon Glass Tested-by: Simon Glass Merged in patch 'x86: qemu: Add CMD_NET to qemu-x86_defconfig https://patchwork.ozlabs.org/patch/479745/ --- arch/x86/cpu/Makefile | 1 + arch/x86/cpu/qemu/Kconfig | 21 ++++++++++++++++++++ arch/x86/cpu/qemu/Makefile | 8 ++++++++ arch/x86/cpu/qemu/car.S | 26 ++++++++++++++++++++++++ arch/x86/cpu/qemu/dram.c | 46 +++++++++++++++++++++++++++++++++++++++++++ arch/x86/cpu/qemu/pci.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++ arch/x86/cpu/qemu/qemu.c | 37 ++++++++++++++++++++++++++++++++++ 7 files changed, 188 insertions(+) create mode 100644 arch/x86/cpu/qemu/Kconfig create mode 100644 arch/x86/cpu/qemu/Makefile create mode 100644 arch/x86/cpu/qemu/car.S create mode 100644 arch/x86/cpu/qemu/dram.c create mode 100644 arch/x86/cpu/qemu/pci.c create mode 100644 arch/x86/cpu/qemu/qemu.c (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 043bea2..307545a 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -14,6 +14,7 @@ obj-y += interrupts.o cpu.o call64.o obj-$(CONFIG_INTEL_BAYTRAIL) += baytrail/ obj-$(CONFIG_SYS_COREBOOT) += coreboot/ +obj-$(CONFIG_QEMU) += qemu/ obj-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += ivybridge/ obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/ obj-$(CONFIG_INTEL_QUARK) += quark/ diff --git a/arch/x86/cpu/qemu/Kconfig b/arch/x86/cpu/qemu/Kconfig new file mode 100644 index 0000000..fb775d7 --- /dev/null +++ b/arch/x86/cpu/qemu/Kconfig @@ -0,0 +1,21 @@ +# +# Copyright (C) 2015, Bin Meng +# +# SPDX-License-Identifier: GPL-2.0+ +# + +config QEMU + bool + select TSC_CALIBRATION_BYPASS + +if QEMU + +config SYS_CAR_ADDR + hex + default 0xd0000 + +config SYS_CAR_SIZE + hex + default 0x10000 + +endif diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile new file mode 100644 index 0000000..be79723 --- /dev/null +++ b/arch/x86/cpu/qemu/Makefile @@ -0,0 +1,8 @@ +# +# Copyright (C) 2015, Bin Meng +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += car.o dram.o qemu.o +obj-$(CONFIG_PCI) += pci.o diff --git a/arch/x86/cpu/qemu/car.S b/arch/x86/cpu/qemu/car.S new file mode 100644 index 0000000..13b3aea --- /dev/null +++ b/arch/x86/cpu/qemu/car.S @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +.globl car_init +car_init: + /* Save the BIST result */ + movl %eax, %ebp + + post_code(POST_CAR_START) + + /* + * Since we know we are running inside emulator, + * we can do nothing here for CAR initialization. + */ + + /* Restore the BIST result */ + movl %ebp, %eax + + post_code(POST_CAR_CPU_CACHE) + jmp car_init_ret diff --git a/arch/x86/cpu/qemu/dram.c b/arch/x86/cpu/qemu/dram.c new file mode 100644 index 0000000..a88d0d2 --- /dev/null +++ b/arch/x86/cpu/qemu/dram.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +int dram_init(void) +{ + u32 ram; + + outb(HIGH_RAM_ADDR, CMOS_ADDR_PORT); + ram = ((u32)inb(CMOS_DATA_PORT)) << 14; + outb(LOW_RAM_ADDR, CMOS_ADDR_PORT); + ram |= ((u32)inb(CMOS_DATA_PORT)) << 6; + ram += 16 * 1024; + + gd->ram_size = ram * 1024; + post_code(POST_DRAM); + + return 0; +} + +void dram_init_banksize(void) +{ + gd->bd->bi_dram[0].start = 0; + gd->bd->bi_dram[0].size = gd->ram_size; +} + +/* + * This function looks for the highest region of memory lower than 4GB which + * has enough space for U-Boot where U-Boot is aligned on a page boundary. + * It overrides the default implementation found elsewhere which simply + * picks the end of ram, wherever that may be. The location of the stack, + * the relocation address, and how far U-Boot is moved by relocation are + * set in the global data structure. + */ +ulong board_get_usable_ram_top(ulong total_size) +{ + return gd->ram_size; +} diff --git a/arch/x86/cpu/qemu/pci.c b/arch/x86/cpu/qemu/pci.c new file mode 100644 index 0000000..d50ab75 --- /dev/null +++ b/arch/x86/cpu/qemu/pci.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +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, + PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); + + hose->region_count = 4; +} + +int board_pci_post_scan(struct pci_controller *hose) +{ + return 0; +} diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c new file mode 100644 index 0000000..0f98476 --- /dev/null +++ b/arch/x86/cpu/qemu/qemu.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +int arch_cpu_init(void) +{ + int ret; + + post_code(POST_CPU_INIT); +#ifdef CONFIG_SYS_X86_TSC_TIMER + timer_set_base(rdtsc()); +#endif + + ret = x86_cpu_init_f(); + if (ret) + return ret; + + return 0; +} + +int print_cpuinfo(void) +{ + post_code(POST_CPU_INFO); + return default_print_cpuinfo(); +} + +void reset_cpu(ulong addr) +{ + /* cold reset */ + x86_full_reset(); +} -- cgit v1.1 From 9c4f541237d43439df4cc3021544741f318d378d Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 11 May 2015 07:36:30 +0800 Subject: x86: qemu: Add graphics support It turns out that QEMU x86 emulated graphic card has a built-in option ROM which can be run perfectly with native mode by U-Boot. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/qemu/pci.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/qemu/pci.c b/arch/x86/cpu/qemu/pci.c index d50ab75..ac9c056 100644 --- a/arch/x86/cpu/qemu/pci.c +++ b/arch/x86/cpu/qemu/pci.c @@ -6,6 +6,7 @@ #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -45,5 +46,26 @@ void board_pci_setup_hose(struct pci_controller *hose) int board_pci_post_scan(struct pci_controller *hose) { - return 0; + int ret = 0; + ulong start; + pci_dev_t bdf; + struct pci_device_id graphic_card[] = { { 0x1234, 0x1111 } }; + + /* + * QEMU emulated graphic card shows in the PCI configuration space with + * PCI vendor id and device id as an artificial pair 0x1234:0x1111. + * It is on PCI bus 0, function 0, but device number is not consistent + * for the two x86 targets it supports. For i440FX and PIIX chipset + * board, it shows as device 2, while for Q35 and ICH9 chipset board, + * it shows as device 1. Here we locate its bdf at run-time based on + * its vendor id and device id pair so we can support both boards. + */ + bdf = pci_find_devices(graphic_card, 0); + if (bdf != -1) { + start = get_timer(0); + ret = pci_run_vga_bios(bdf, NULL, PCI_ROM_USE_NATIVE); + debug("BIOS ran in %lums\n", get_timer(start)); + } + + return ret; } -- cgit v1.1 From 9c7dea602edd9027848d312e9b3b69f06c15f163 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 25 May 2015 22:35:04 +0800 Subject: x86: Refactor PIRQ routing support PIRQ routing is pretty much common in Intel chipset. It has several PIRQ links (normally 8) and corresponding registers (either in PCI configuration space or memory-mapped IBASE) to configure the legacy 8259 IRQ vector mapping. Refactor current Queensbay PIRQ routing support using device tree and move it to a common place, so that we can easily add PIRQ routing support on a new platform. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/Makefile | 2 +- arch/x86/cpu/irq.c | 213 +++++++++++++++++++++++++++++++++++ arch/x86/cpu/queensbay/Makefile | 2 +- arch/x86/cpu/queensbay/irq.c | 242 ---------------------------------------- arch/x86/cpu/queensbay/tnc.c | 39 ++++++- 5 files changed, 253 insertions(+), 245 deletions(-) create mode 100644 arch/x86/cpu/irq.c delete mode 100644 arch/x86/cpu/queensbay/irq.c (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 307545a..7ff05e6 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -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 += lapic.o +obj-y += irq.o lapic.o obj-$(CONFIG_SMP) += mp_init.o obj-y += mtrr.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c new file mode 100644 index 0000000..d1711af --- /dev/null +++ b/arch/x86/cpu/irq.c @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static struct irq_router irq_router; +static struct irq_routing_table *pirq_routing_table; + +bool pirq_check_irq_routed(int link, u8 irq) +{ + u8 pirq; + int base = irq_router.link_base; + + if (irq_router.config == PIRQ_VIA_PCI) + pirq = x86_pci_read_config8(irq_router.bdf, + LINK_N2V(link, base)); + else + pirq = readb(irq_router.ibase + LINK_N2V(link, base)); + + pirq &= 0xf; + + /* IRQ# 0/1/2/8/13 are reserved */ + if (pirq < 3 || pirq == 8 || pirq == 13) + return false; + + return pirq == irq ? true : false; +} + +int pirq_translate_link(int link) +{ + return LINK_V2N(link, irq_router.link_base); +} + +void pirq_assign_irq(int link, u8 irq) +{ + int base = irq_router.link_base; + + /* IRQ# 0/1/2/8/13 are reserved */ + if (irq < 3 || irq == 8 || irq == 13) + return; + + if (irq_router.config == PIRQ_VIA_PCI) + x86_pci_write_config8(irq_router.bdf, + LINK_N2V(link, base), irq); + else + 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) +{ + struct irq_info *slot = *slotp; + + slot->bus = bus; + slot->devfn = (device << 3) | func; + 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) +{ + return; +} + +static int create_pirq_routing_table(void) +{ + const void *blob = gd->fdt_blob; + struct fdt_pci_addr addr; + int node; + int len, count; + const u32 *cell; + struct irq_routing_table *rt; + struct irq_info *slot; + int irq_entries = 0; + int i; + int ret; + + node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_IRQ_ROUTER); + if (node < 0) { + debug("%s: Cannot find irq router node\n", __func__); + return -EINVAL; + } + + ret = fdtdec_get_pci_addr(blob, node, FDT_PCI_SPACE_CONFIG, + "reg", &addr); + if (ret) + return ret; + + /* extract the bdf from fdt_pci_addr */ + irq_router.bdf = addr.phys_hi & 0xffff00; + + ret = fdt_find_string(blob, node, "intel,pirq-config", "pci"); + if (!ret) { + irq_router.config = PIRQ_VIA_PCI; + } else { + ret = fdt_find_string(blob, node, "intel,pirq-config", "ibase"); + if (!ret) + irq_router.config = PIRQ_VIA_IBASE; + else + return -EINVAL; + } + + ret = fdtdec_get_int_array(blob, node, "intel,pirq-link", + &irq_router.link_base, 1); + if (ret) + return ret; + + irq_router.irq_mask = fdtdec_get_int(blob, node, + "intel,pirq-mask", PIRQ_BITMAP); + + if (irq_router.config == PIRQ_VIA_IBASE) { + int ibase_off; + + ibase_off = fdtdec_get_int(blob, node, "intel,ibase-offset", 0); + if (!ibase_off) + return -EINVAL; + + /* + * Here we assume that the IBASE register has already been + * properly configured by U-Boot before. + * + * By 'valid' we mean: + * 1) a valid memory space carved within system memory space + * assigned to IBASE register block. + * 2) memory range decoding is enabled. + * Hence we don't do any santify test here. + */ + irq_router.ibase = x86_pci_read_config32(irq_router.bdf, + ibase_off); + irq_router.ibase &= ~0xf; + } + + cell = fdt_getprop(blob, node, "intel,pirq-routing", &len); + if (!cell) + return -EINVAL; + + if ((len % sizeof(struct pirq_routing)) == 0) + count = len / sizeof(struct pirq_routing); + else + return -EINVAL; + + rt = malloc(sizeof(struct irq_routing_table)); + if (!rt) + return -ENOMEM; + memset((char *)rt, 0, sizeof(struct irq_routing_table)); + + /* Populate the PIRQ table fields */ + rt->signature = PIRQ_SIGNATURE; + rt->version = PIRQ_VERSION; + rt->rtr_bus = 0; + rt->rtr_devfn = (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; + + /* Now fill in the irq_info entries in the PIRQ table */ + 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]); + + debug("irq_info %d: b.d.f %x.%x.%x INT%c PIRQ%c\n", + 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), + pr.pin, pr.pirq); + cell += sizeof(struct pirq_routing) / sizeof(u32); + } + + rt->size = irq_entries * sizeof(struct irq_info) + 32; + + pirq_routing_table = rt; + + return 0; +} + +void pirq_init(void) +{ + cpu_irq_init(); + + if (create_pirq_routing_table()) { + debug("Failed to create pirq routing table\n"); + } else { + /* Route PIRQ */ + pirq_route_irqs(pirq_routing_table->slots, + get_irq_slot_count(pirq_routing_table)); + } +} + +u32 write_pirq_routing_table(u32 addr) +{ + return copy_pirq_routing_table(addr, pirq_routing_table); +} diff --git a/arch/x86/cpu/queensbay/Makefile b/arch/x86/cpu/queensbay/Makefile index 4599a48..d8761fd 100644 --- a/arch/x86/cpu/queensbay/Makefile +++ b/arch/x86/cpu/queensbay/Makefile @@ -5,5 +5,5 @@ # obj-y += fsp_configs.o -obj-y += irq.o tnc.o topcliff.o +obj-y += tnc.o topcliff.o obj-$(CONFIG_PCI) += tnc_pci.o diff --git a/arch/x86/cpu/queensbay/irq.c b/arch/x86/cpu/queensbay/irq.c deleted file mode 100644 index faf9515..0000000 --- a/arch/x86/cpu/queensbay/irq.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (C) 2015, Bin Meng - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct irq_routing_table *pirq_routing_table; - -bool pirq_check_irq_routed(int link, u8 irq) -{ - u8 pirq; - - pirq = x86_pci_read_config8(TNC_LPC, LINK_N2V(link)); - pirq &= 0xf; - - /* IRQ# 0/1/2/8/13 are reserved */ - if (pirq < 3 || pirq == 8 || pirq == 13) - return false; - - return pirq == irq ? true : false; -} - -int pirq_translate_link(int link) -{ - return LINK_V2N(link); -} - -void pirq_assign_irq(int link, u8 irq) -{ - /* IRQ# 0/1/2/8/13 are reserved */ - if (irq < 3 || irq == 8 || irq == 13) - return; - - x86_pci_write_config8(TNC_LPC, LINK_N2V(link), irq); -} - -static inline void fill_irq_info(struct irq_info **slotp, int *entries, u8 bus, - u8 device, u8 func, u8 pin, u8 pirq) -{ - struct irq_info *slot = *slotp; - - slot->bus = bus; - slot->devfn = (device << 3) | func; - slot->irq[pin - 1].link = LINK_N2V(pirq); - slot->irq[pin - 1].bitmap = PIRQ_BITMAP; - (*entries)++; - (*slotp)++; -} - -/* PCIe port downstream INTx swizzle */ -static inline u8 pin_swizzle(u8 pin, int port) -{ - return (pin + port) % 4; -} - -__weak int board_fill_irq_info(struct irq_info *slot) -{ - return 0; -} - -static int create_pirq_routing_table(void) -{ - struct irq_routing_table *rt; - struct irq_info *slot; - int irq_entries = 0; - pci_dev_t tcf_bdf; - u8 tcf_bus, bus; - int i; - - rt = malloc(sizeof(struct irq_routing_table)); - if (!rt) - return -ENOMEM; - memset((char *)rt, 0, sizeof(struct irq_routing_table)); - - /* Populate the PIRQ table fields */ - rt->signature = PIRQ_SIGNATURE; - rt->version = PIRQ_VERSION; - rt->rtr_bus = 0; - rt->rtr_devfn = (TNC_LPC_DEV << 3) | TNC_LPC_FUNC; - rt->rtr_vendor = PCI_VENDOR_ID_INTEL; - rt->rtr_device = PCI_DEVICE_ID_INTEL_ICH7_31; - - slot = rt->slots; - - /* - * Now fill in the irq_info entries in the PIRQ table - * - * We start from internal TunnelCreek PCI devices first, then - * followed by all the 4 PCIe ports downstream devices, including - * the Queensbay platform Topcliff chipset devices. - */ - fill_irq_info(&slot, &irq_entries, 0, TNC_IGD_DEV, - TNC_IGD_FUNC, INTA, PIRQE); - fill_irq_info(&slot, &irq_entries, 0, TNC_SDVO_DEV, - TNC_SDVO_FUNC, INTA, PIRQF); - fill_irq_info(&slot, &irq_entries, 0, TNC_HDA_DEV, - TNC_HDA_FUNC, INTA, PIRQG); - fill_irq_info(&slot, &irq_entries, 0, TNC_PCIE0_DEV, - TNC_PCIE0_FUNC, INTA, PIRQE); - fill_irq_info(&slot, &irq_entries, 0, TNC_PCIE1_DEV, - TNC_PCIE1_FUNC, INTA, PIRQF); - fill_irq_info(&slot, &irq_entries, 0, TNC_PCIE2_DEV, - TNC_PCIE2_FUNC, INTA, PIRQG); - fill_irq_info(&slot, &irq_entries, 0, TNC_PCIE3_DEV, - TNC_PCIE3_FUNC, INTA, PIRQH); - - /* Check which PCIe port the Topcliff chipset is connected to */ - tcf_bdf = pci_find_device(PCI_VENDOR_ID_INTEL, 0x8800, 0); - tcf_bus = PCI_BUS(tcf_bdf); - for (i = 0; i < 4; i++) { - bus = x86_pci_read_config8(PCI_BDF(0, TNC_PCIE0_DEV + i, 0), - PCI_SECONDARY_BUS); - if (bus == tcf_bus) - break; - } - - /* Fill in the Topcliff chipset devices' irq info */ - if (i < 4) { - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_PCIE_PORT_DEV, - TCF_PCIE_PORT_FUNC, INTA, pin_swizzle(PIRQA, i)); - - tcf_bus++; - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_0, - TCF_GBE_FUNC, INTA, pin_swizzle(PIRQA, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_0, - TCF_GPIO_FUNC, INTA, pin_swizzle(PIRQA, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2, - TCF_USB1_OHCI0_FUNC, INTB, pin_swizzle(PIRQB, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2, - TCF_USB1_OHCI1_FUNC, INTB, pin_swizzle(PIRQB, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2, - TCF_USB1_OHCI2_FUNC, INTB, pin_swizzle(PIRQB, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2, - TCF_USB1_EHCI_FUNC, INTB, pin_swizzle(PIRQB, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2, - TCF_USB_DEVICE_FUNC, INTB, pin_swizzle(PIRQB, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_4, - TCF_SDIO0_FUNC, INTC, pin_swizzle(PIRQC, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_4, - TCF_SDIO1_FUNC, INTC, pin_swizzle(PIRQC, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_6, - TCF_SATA_FUNC, INTD, pin_swizzle(PIRQD, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_8, - TCF_USB2_OHCI0_FUNC, INTA, pin_swizzle(PIRQA, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_8, - TCF_USB2_OHCI1_FUNC, INTA, pin_swizzle(PIRQA, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_8, - TCF_USB2_OHCI2_FUNC, INTA, pin_swizzle(PIRQA, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_8, - TCF_USB2_EHCI_FUNC, INTA, pin_swizzle(PIRQA, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10, - TCF_DMA1_FUNC, INTB, pin_swizzle(PIRQB, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10, - TCF_UART0_FUNC, INTB, pin_swizzle(PIRQB, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10, - TCF_UART1_FUNC, INTB, pin_swizzle(PIRQB, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10, - TCF_UART2_FUNC, INTB, pin_swizzle(PIRQB, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10, - TCF_UART3_FUNC, INTB, pin_swizzle(PIRQB, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12, - TCF_DMA2_FUNC, INTC, pin_swizzle(PIRQC, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12, - TCF_SPI_FUNC, INTC, pin_swizzle(PIRQC, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12, - TCF_I2C_FUNC, INTC, pin_swizzle(PIRQC, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12, - TCF_CAN_FUNC, INTC, pin_swizzle(PIRQC, i)); - fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12, - TCF_1588_FUNC, INTC, pin_swizzle(PIRQC, i)); - } - - /* Call board-specific routine to fill in add-in card's irq info */ - irq_entries += board_fill_irq_info(slot); - - rt->size = irq_entries * sizeof(struct irq_info) + 32; - - pirq_routing_table = rt; - - return 0; -} - -void pirq_init(void) -{ - struct tnc_rcba *rcba; - u32 base; - - base = x86_pci_read_config32(TNC_LPC, LPC_RCBA); - base &= ~MEM_BAR_EN; - rcba = (struct tnc_rcba *)base; - - /* Make sure all internal PCI devices are using INTA */ - writel(INTA, &rcba->d02ip); - writel(INTA, &rcba->d03ip); - writel(INTA, &rcba->d27ip); - writel(INTA, &rcba->d31ip); - writel(INTA, &rcba->d23ip); - writel(INTA, &rcba->d24ip); - writel(INTA, &rcba->d25ip); - writel(INTA, &rcba->d26ip); - - /* - * Route TunnelCreek PCI device interrupt pin to PIRQ - * - * Since PCIe downstream ports received INTx are routed to PIRQ - * A/B/C/D directly and not configurable, we route internal PCI - * device's INTx to PIRQ E/F/G/H. - */ - writew(PIRQE, &rcba->d02ir); - writew(PIRQF, &rcba->d03ir); - writew(PIRQG, &rcba->d27ir); - writew(PIRQH, &rcba->d31ir); - writew(PIRQE, &rcba->d23ir); - writew(PIRQF, &rcba->d24ir); - writew(PIRQG, &rcba->d25ir); - writew(PIRQH, &rcba->d26ir); - - if (create_pirq_routing_table()) { - debug("Failed to create pirq routing table\n"); - } else { - /* Route PIRQ */ - pirq_route_irqs(pirq_routing_table->slots, - get_irq_slot_count(pirq_routing_table)); - } -} - -u32 write_pirq_routing_table(u32 addr) -{ - return copy_pirq_routing_table(addr, pirq_routing_table); -} diff --git a/arch/x86/cpu/queensbay/tnc.c b/arch/x86/cpu/queensbay/tnc.c index b46a7e9..873de7b 100644 --- a/arch/x86/cpu/queensbay/tnc.c +++ b/arch/x86/cpu/queensbay/tnc.c @@ -6,10 +6,11 @@ #include #include +#include #include #include #include -#include +#include #include #include @@ -45,6 +46,42 @@ int arch_cpu_init(void) return 0; } +void cpu_irq_init(void) +{ + struct tnc_rcba *rcba; + u32 base; + + base = x86_pci_read_config32(TNC_LPC, LPC_RCBA); + base &= ~MEM_BAR_EN; + rcba = (struct tnc_rcba *)base; + + /* Make sure all internal PCI devices are using INTA */ + writel(INTA, &rcba->d02ip); + writel(INTA, &rcba->d03ip); + writel(INTA, &rcba->d27ip); + writel(INTA, &rcba->d31ip); + writel(INTA, &rcba->d23ip); + writel(INTA, &rcba->d24ip); + writel(INTA, &rcba->d25ip); + writel(INTA, &rcba->d26ip); + + /* + * Route TunnelCreek PCI device interrupt pin to PIRQ + * + * Since PCIe downstream ports received INTx are routed to PIRQ + * A/B/C/D directly and not configurable, we route internal PCI + * device's INTx to PIRQ E/F/G/H. + */ + writew(PIRQE, &rcba->d02ir); + writew(PIRQF, &rcba->d03ir); + writew(PIRQG, &rcba->d27ir); + writew(PIRQH, &rcba->d31ir); + writew(PIRQE, &rcba->d23ir); + writew(PIRQF, &rcba->d24ir); + writew(PIRQG, &rcba->d25ir); + writew(PIRQH, &rcba->d26ir); +} + int arch_misc_init(void) { pirq_init(); -- cgit v1.1 From 05b98ec3468547057666dd685b2a1615298c24cc Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 25 May 2015 22:35:06 +0800 Subject: x86: quark: Implement PIRQ routing Intel Quark SoC has the same interrupt routing mechanism as the Queensbay platform, only the difference is that PCI devices' INTA/B/C/D are harcoded and cannot be changed freely. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/quark/quark.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/quark/quark.c b/arch/x86/cpu/quark/quark.c index e78a271..20cc09e 100644 --- a/arch/x86/cpu/quark/quark.c +++ b/arch/x86/cpu/quark/quark.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -147,3 +148,33 @@ int cpu_eth_init(bd_t *bis) else return 0; } + +void cpu_irq_init(void) +{ + struct quark_rcba *rcba; + u32 base; + + base = x86_pci_read_config32(QUARK_LEGACY_BRIDGE, LB_RCBA); + base &= ~MEM_BAR_EN; + rcba = (struct quark_rcba *)base; + + /* + * Route Quark PCI device interrupt pin to PIRQ + * + * Route device#23's INTA/B/C/D to PIRQA/B/C/D + * Route device#20,21's INTA/B/C/D to PIRQE/F/G/H + */ + writew(PIRQC, &rcba->rmu_ir); + writew(PIRQA | (PIRQB << 4) | (PIRQC << 8) | (PIRQD << 12), + &rcba->d23_ir); + writew(PIRQD, &rcba->core_ir); + writew(PIRQE | (PIRQF << 4) | (PIRQG << 8) | (PIRQH << 12), + &rcba->d20d21_ir); +} + +int arch_misc_init(void) +{ + pirq_init(); + + return 0; +} -- cgit v1.1 From 67b24970cef90b6d230e370cce9db8c29b2f4d74 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 25 May 2015 22:35:07 +0800 Subject: x86: Do sanity test on pirq table before writing If pirq_routing_table points to NULL, that means U-Boot fails to generate the table before in create_pirq_routing_table(), so we test it against NULL before actually writing it. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/irq.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c index d1711af..74b89ad 100644 --- a/arch/x86/cpu/irq.c +++ b/arch/x86/cpu/irq.c @@ -209,5 +209,8 @@ void pirq_init(void) u32 write_pirq_routing_table(u32 addr) { + if (!pirq_routing_table) + return addr; + return copy_pirq_routing_table(addr, pirq_routing_table); } -- cgit v1.1 From cc7debc7199b3c637ceead92bc103aeb6eb10a38 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 24 May 2015 00:12:33 +0800 Subject: x86: qemu: Turn on legacy segments decode By default the legacy segments C/D/E/F do not decode to system RAM. Turn on the decode via Programmable Attribute Map (PAM) registers so that we can write configuration tables in the F segment. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/qemu/pci.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/qemu/pci.c b/arch/x86/cpu/qemu/pci.c index ac9c056..2f4ba17 100644 --- a/arch/x86/cpu/qemu/pci.c +++ b/arch/x86/cpu/qemu/pci.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include DECLARE_GLOBAL_DATA_PTR; @@ -50,6 +52,8 @@ int board_pci_post_scan(struct pci_controller *hose) ulong start; pci_dev_t bdf; struct pci_device_id graphic_card[] = { { 0x1234, 0x1111 } }; + u16 device; + int pam, i; /* * QEMU emulated graphic card shows in the PCI configuration space with @@ -67,5 +71,21 @@ int board_pci_post_scan(struct pci_controller *hose) debug("BIOS ran in %lums\n", get_timer(start)); } + /* + * i440FX and Q35 chipset have different PAM register offset, but with + * the same bitfield layout. Here we determine the offset based on its + * PCI device ID. + */ + device = x86_pci_read_config16(PCI_BDF(0, 0, 0), PCI_DEVICE_ID); + pam = (device == PCI_DEVICE_ID_INTEL_82441) ? I440FX_PAM : Q35_PAM; + + /* + * Initialize Programmable Attribute Map (PAM) Registers + * + * Configure legacy segments C/D/E/F to system RAM + */ + for (i = 0; i < PAM_NUM; i++) + x86_pci_write_config8(PCI_BDF(0, 0, 0), pam + i, PAM_RW); + return ret; } -- cgit v1.1 From 0fcb7acf6748d2ee0b7abfd75e074840be6b7e0e Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 25 May 2015 22:36:26 +0800 Subject: x86: qemu: Enable legacy IDE I/O ports decode QEMU always decode legacy IDE I/O ports on PIIX chipset. However Linux ata_piix driver does sanity check to see whether legacy ports decode is turned on. To make Linux ata_piix driver happy, turn on the decode via IDE_TIMING register. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/qemu/pci.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/qemu/pci.c b/arch/x86/cpu/qemu/pci.c index 2f4ba17..467d51d 100644 --- a/arch/x86/cpu/qemu/pci.c +++ b/arch/x86/cpu/qemu/pci.c @@ -8,6 +8,7 @@ #include #include #include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -87,5 +88,18 @@ int board_pci_post_scan(struct pci_controller *hose) for (i = 0; i < PAM_NUM; i++) x86_pci_write_config8(PCI_BDF(0, 0, 0), pam + i, PAM_RW); + if (device == PCI_DEVICE_ID_INTEL_82441) { + /* + * Enable legacy IDE I/O ports decode + * + * Note: QEMU always decode legacy IDE I/O port on PIIX chipset. + * However Linux ata_piix driver does sanity check on these two + * registers to see whether legacy ports decode is turned on. + * This is to make Linux ata_piix driver happy. + */ + x86_pci_write_config16(PIIX_IDE, IDE0_TIM, IDE_DECODE_EN); + x86_pci_write_config16(PIIX_IDE, IDE1_TIM, IDE_DECODE_EN); + } + return ret; } -- cgit v1.1 From 4be2f42bbc8171eae930db37f370f10779c5b02c Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 25 May 2015 22:36:27 +0800 Subject: x86: qemu: Adjust VGA initialization As VGA option rom needs to run at C segment, although QEMU PAM emulation seems to only guard E/F segments, for correctness, move VGA initialization after PAM decode C/D/E/F segments. Also since we already tested QEMU targets to differentiate I440FX and Q35 platforms, change to locate the VGA device via hardcoded b.d.f instead of dynamic search for its vendor id & device id pair. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/qemu/pci.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/qemu/pci.c b/arch/x86/cpu/qemu/pci.c index 467d51d..1a9140b 100644 --- a/arch/x86/cpu/qemu/pci.c +++ b/arch/x86/cpu/qemu/pci.c @@ -50,27 +50,10 @@ void board_pci_setup_hose(struct pci_controller *hose) int board_pci_post_scan(struct pci_controller *hose) { int ret = 0; - ulong start; - pci_dev_t bdf; - struct pci_device_id graphic_card[] = { { 0x1234, 0x1111 } }; u16 device; int pam, i; - - /* - * QEMU emulated graphic card shows in the PCI configuration space with - * PCI vendor id and device id as an artificial pair 0x1234:0x1111. - * It is on PCI bus 0, function 0, but device number is not consistent - * for the two x86 targets it supports. For i440FX and PIIX chipset - * board, it shows as device 2, while for Q35 and ICH9 chipset board, - * it shows as device 1. Here we locate its bdf at run-time based on - * its vendor id and device id pair so we can support both boards. - */ - bdf = pci_find_devices(graphic_card, 0); - if (bdf != -1) { - start = get_timer(0); - ret = pci_run_vga_bios(bdf, NULL, PCI_ROM_USE_NATIVE); - debug("BIOS ran in %lums\n", get_timer(start)); - } + pci_dev_t vga; + ulong start; /* * i440FX and Q35 chipset have different PAM register offset, but with @@ -101,5 +84,18 @@ int board_pci_post_scan(struct pci_controller *hose) x86_pci_write_config16(PIIX_IDE, IDE1_TIM, IDE_DECODE_EN); } + /* + * QEMU emulated graphic card shows in the PCI configuration space with + * PCI vendor id and device id as an artificial pair 0x1234:0x1111. + * It is on PCI bus 0, function 0, but device number is not consistent + * for the two x86 targets it supports. For i440FX and PIIX chipset + * board, it shows as device 2, while for Q35 and ICH9 chipset board, + * it shows as device 1. + */ + vga = (device == PCI_DEVICE_ID_INTEL_82441) ? I440FX_VGA : Q35_VGA; + start = get_timer(0); + ret = pci_run_vga_bios(vga, NULL, PCI_ROM_USE_NATIVE); + debug("BIOS ran in %lums\n", get_timer(start)); + return ret; } -- cgit v1.1 From 65cdd9be3e0fe79909962bba9bedf7967d44d60b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 3 Jun 2015 09:20:02 +0800 Subject: x86: coreboot: Fix cosmetic issues Clean up arch/x86/cpu/coreboot.c to fix several cosmetic issues. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/coreboot/coreboot.c | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/coreboot/coreboot.c b/arch/x86/cpu/coreboot/coreboot.c index 4cdd0d4..c3dfd28 100644 --- a/arch/x86/cpu/coreboot/coreboot.c +++ b/arch/x86/cpu/coreboot/coreboot.c @@ -7,16 +7,10 @@ */ #include -#include -#include #include -#include -#include -#include -#include #include +#include #include -#include #include #include @@ -53,13 +47,6 @@ int last_stage_init(void) return 0; } -#ifndef CONFIG_SYS_NO_FLASH -ulong board_flash_get_legacy(ulong base, int banknum, flash_info_t *info) -{ - return 0; -} -#endif - int board_eth_init(bd_t *bis) { return pci_eth_init(bis); @@ -67,7 +54,8 @@ int board_eth_init(bd_t *bis) void board_final_cleanup(void) { - /* Un-cache the ROM so the kernel has one + /* + * Un-cache the ROM so the kernel has one * more MTRR available. * * Coreboot should have assigned this to the @@ -91,15 +79,6 @@ void board_final_cleanup(void) outb(0xcb, 0xb2); } -void panic_puts(const char *str) -{ - NS16550_t port = (NS16550_t)0x3f8; - - NS16550_init(port, 1); - while (*str) - NS16550_putc(port, *str++); -} - int misc_init_r(void) { return 0; -- cgit v1.1 From f2653e8dd92229328480da35c26e6f9fbfec4381 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 3 Jun 2015 09:20:05 +0800 Subject: x86: coreboot: Control I/O port 0xb2 writing via device tree Writing 0xcb to I/O port 0xb2 (Advanced Power Management Control) causes U-Boot to hang on QEMU q35 target. We introduce a config option in the device tree "u-boot,no-apm-finalize" under /config node if we don't want to do that. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/coreboot/coreboot.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/coreboot/coreboot.c b/arch/x86/cpu/coreboot/coreboot.c index c3dfd28..c4cac04 100644 --- a/arch/x86/cpu/coreboot/coreboot.c +++ b/arch/x86/cpu/coreboot/coreboot.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -74,9 +75,14 @@ void board_final_cleanup(void) mtrr_close(&state); } - /* Issue SMI to Coreboot to lock down ME and registers */ - printf("Finalizing Coreboot\n"); - outb(0xcb, 0xb2); + if (!fdtdec_get_config_bool(gd->fdt_blob, "u-boot,no-apm-finalize")) { + /* + * Issue SMI to coreboot to lock down ME and registers + * when allowed via device tree + */ + printf("Finalizing coreboot\n"); + outb(0xcb, 0xb2); + } } int misc_init_r(void) -- cgit v1.1 From 5c564226fc8948e435edea8eb8c5c4afbc5edef1 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 3 Jun 2015 09:20:06 +0800 Subject: x86: qemu: Implement PIRQ routing Support QEMU PIRQ routing via device tree on both i440fx and q35 platforms. With this commit, Linux booting on QEMU from U-Boot has working ATA/SATA, USB and ethernet. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/coreboot/coreboot.c | 5 +++++ arch/x86/cpu/qemu/qemu.c | 8 ++++++++ 2 files changed, 13 insertions(+) (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/coreboot/coreboot.c b/arch/x86/cpu/coreboot/coreboot.c index c4cac04..0e9f15f 100644 --- a/arch/x86/cpu/coreboot/coreboot.c +++ b/arch/x86/cpu/coreboot/coreboot.c @@ -89,3 +89,8 @@ int misc_init_r(void) { return 0; } + +int arch_misc_init(void) +{ + return 0; +} diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c index 0f98476..930d2b6 100644 --- a/arch/x86/cpu/qemu/qemu.c +++ b/arch/x86/cpu/qemu/qemu.c @@ -5,6 +5,7 @@ */ #include +#include #include #include @@ -35,3 +36,10 @@ void reset_cpu(ulong addr) /* cold reset */ x86_full_reset(); } + +int arch_misc_init(void) +{ + pirq_init(); + + return 0; +} -- cgit v1.1 From afbbd413a3ef8a45155fcd083814ba645b09fcc7 Mon Sep 17 00:00:00 2001 From: Andrew Bradford Date: Wed, 3 Jun 2015 12:37:39 -0400 Subject: x86: baytrail: pci region 3 is not always mapped to end of ram Baytrail physically maps the first 2 GB of SDRAM from 0x0 to 0x7FFFFFFF and additional SDRAM is mapped from 0x100000000 and up. There is a physical memory hole from 0x80000000 to 0xFFFFFFFF for other uses. Because of this, PCI region 3 should only try to use up to the amount of SDRAM or 0x80000000, which ever is less. Signed-off-by: Andrew Bradford Reviewed-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/baytrail/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/baytrail/pci.c b/arch/x86/cpu/baytrail/pci.c index 6c291f9..48409de 100644 --- a/arch/x86/cpu/baytrail/pci.c +++ b/arch/x86/cpu/baytrail/pci.c @@ -39,7 +39,7 @@ void board_pci_setup_hose(struct pci_controller *hose) pci_set_region(hose->regions + 3, 0, 0, - gd->ram_size, + gd->ram_size < 0x80000000 ? gd->ram_size : 0x80000000, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); hose->region_count = 4; -- cgit v1.1