diff options
Diffstat (limited to 'arch/x86/lib')
-rw-r--r-- | arch/x86/lib/Makefile | 4 | ||||
-rw-r--r-- | arch/x86/lib/fsp/fsp_common.c | 7 | ||||
-rw-r--r-- | arch/x86/lib/pirq_routing.c | 137 | ||||
-rw-r--r-- | arch/x86/lib/sfi.c | 154 | ||||
-rw-r--r-- | arch/x86/lib/tables.c | 35 | ||||
-rw-r--r-- | arch/x86/lib/video.c | 205 | ||||
-rw-r--r-- | arch/x86/lib/zimage.c | 29 |
7 files changed, 351 insertions, 220 deletions
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 6c571dd9c1..70ad19b263 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -22,12 +22,14 @@ ifndef CONFIG_DM_PCI obj-$(CONFIG_PCI) += pci_type1.o endif obj-y += pch-uclass.o +obj-y += pirq_routing.o obj-y += relocate.o obj-y += physmem.o obj-$(CONFIG_X86_RAMTEST) += ramtest.o +obj-y += sfi.o obj-y += string.o +obj-y += tables.o obj-$(CONFIG_SYS_X86_TSC_TIMER) += tsc_timer.o -obj-$(CONFIG_VIDEO_VGA) += video.o obj-$(CONFIG_CMD_ZBOOT) += zimage.o obj-$(CONFIG_HAVE_FSP) += fsp/ diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index f668259c0e..001494d97d 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -17,13 +17,6 @@ int print_cpuinfo(void) return default_print_cpuinfo(); } -void reset_cpu(ulong addr) -{ - /* cold reset */ - outb(0x06, PORT_RESET); -} - - int board_pci_post_scan(struct pci_controller *hose) { u32 status; diff --git a/arch/x86/lib/pirq_routing.c b/arch/x86/lib/pirq_routing.c new file mode 100644 index 0000000000..7a34dcf366 --- /dev/null +++ b/arch/x86/lib/pirq_routing.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> + * + * Part of this file is ported from coreboot src/arch/x86/boot/pirq_routing.c + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <pci.h> +#include <asm/pci.h> +#include <asm/pirq_routing.h> +#include <asm/tables.h> + +static bool irq_already_routed[16]; + +static u8 pirq_get_next_free_irq(u8 *pirq, u16 bitmap) +{ + int i, link; + u8 irq = 0; + + /* IRQ sharing starts from IRQ#3 */ + for (i = 3; i < 16; i++) { + /* Can we assign this IRQ? */ + if (!((bitmap >> i) & 1)) + continue; + + /* We can, now let's assume we can use this IRQ */ + irq = i; + + /* Have we already routed it? */ + if (irq_already_routed[irq]) + continue; + + for (link = 0; link < CONFIG_MAX_PIRQ_LINKS; link++) { + if (pirq_check_irq_routed(link, irq)) { + irq_already_routed[irq] = true; + break; + } + } + + /* If it's not yet routed, use it */ + if (!irq_already_routed[irq]) { + irq_already_routed[irq] = true; + break; + } + + /* But if it was already routed, try the next one */ + } + + /* Now we get our IRQ */ + return irq; +} + +void pirq_route_irqs(struct irq_info *irq, int num) +{ + unsigned char irq_slot[MAX_INTX_ENTRIES]; + unsigned char pirq[CONFIG_MAX_PIRQ_LINKS]; + int i, intx; + + memset(pirq, 0, CONFIG_MAX_PIRQ_LINKS); + + /* Set PCI IRQs */ + for (i = 0; i < num; i++) { + debug("PIRQ Entry %d Dev: %d.%x.%d\n", i, + irq->bus, irq->devfn >> 3, irq->devfn & 7); + + for (intx = 0; intx < MAX_INTX_ENTRIES; intx++) { + int link = irq->irq[intx].link; + int bitmap = irq->irq[intx].bitmap; + int irq = 0; + + debug("INT%c link: %x bitmap: %x ", + 'A' + intx, link, bitmap); + + if (!bitmap || !link) { + debug("not routed\n"); + irq_slot[intx] = irq; + continue; + } + + /* translate link value to link number */ + link = pirq_translate_link(link); + + /* yet not routed */ + if (!pirq[link]) { + irq = pirq_get_next_free_irq(pirq, bitmap); + pirq[link] = irq; + } else { + irq = pirq[link]; + } + + debug("IRQ: %d\n", irq); + irq_slot[intx] = irq; + + /* Assign IRQ in the interrupt router */ + pirq_assign_irq(link, irq); + } + + /* Bus, device, slots IRQs for {A,B,C,D} */ + pci_assign_irqs(irq->bus, irq->devfn >> 3, irq->devfn & 7, + irq_slot); + + irq++; + } + + for (i = 0; i < CONFIG_MAX_PIRQ_LINKS; i++) + debug("PIRQ%c: %d\n", 'A' + i, pirq[i]); +} + +u32 copy_pirq_routing_table(u32 addr, struct irq_routing_table *rt) +{ + struct irq_routing_table *rom_rt; + + /* Fix up the table checksum */ + rt->checksum = table_compute_checksum(rt, rt->size); + + /* Align the table to be 16 byte aligned */ + addr = ALIGN(addr, 16); + + debug("Copying Interrupt Routing Table to 0x%x\n", addr); + memcpy((void *)addr, rt, rt->size); + + /* + * We do the sanity check here against the copied table after memcpy, + * as something might go wrong after the memcpy, which is normally + * due to the F segment decode is not turned on to systeam RAM. + */ + rom_rt = (struct irq_routing_table *)addr; + if (rom_rt->signature != PIRQ_SIGNATURE || + rom_rt->version != PIRQ_VERSION || rom_rt->size % 16) { + printf("Interrupt Routing Table not valid\n"); + return addr; + } + + return addr + rt->size; +} diff --git a/arch/x86/lib/sfi.c b/arch/x86/lib/sfi.c new file mode 100644 index 0000000000..3d3658088a --- /dev/null +++ b/arch/x86/lib/sfi.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * Intel Simple Firmware Interface (SFI) + * + * Yet another way to pass information to the Linux kernel. + * + * See https://simplefirmware.org/ for details + */ + +#include <common.h> +#include <cpu.h> +#include <dm.h> +#include <asm/cpu.h> +#include <asm/ioapic.h> +#include <asm/sfi.h> +#include <asm/tables.h> +#include <dm/uclass-internal.h> + +struct table_info { + u32 base; + int ptr; + u32 entry_start; + u64 table[SFI_TABLE_MAX_ENTRIES]; + int count; +}; + +static void *get_entry_start(struct table_info *tab) +{ + if (tab->count == SFI_TABLE_MAX_ENTRIES) + return NULL; + tab->entry_start = tab->base + tab->ptr; + tab->table[tab->count] = tab->entry_start; + tab->entry_start += sizeof(struct sfi_table_header); + + return (void *)tab->entry_start; +} + +static void finish_table(struct table_info *tab, const char *sig, void *entry) +{ + struct sfi_table_header *hdr; + + hdr = (struct sfi_table_header *)(tab->base + tab->ptr); + strcpy(hdr->sig, sig); + hdr->len = sizeof(*hdr) + ((ulong)entry - tab->entry_start); + hdr->rev = 1; + strncpy(hdr->oem_id, "U-Boot", SFI_OEM_ID_SIZE); + strncpy(hdr->oem_table_id, "Table v1", SFI_OEM_TABLE_ID_SIZE); + hdr->csum = 0; + hdr->csum = table_compute_checksum(hdr, hdr->len); + tab->ptr += hdr->len; + tab->ptr = ALIGN(tab->ptr, 16); + tab->count++; +} + +static int sfi_write_system_header(struct table_info *tab) +{ + u64 *entry = get_entry_start(tab); + int i; + + if (!entry) + return -ENOSPC; + + for (i = 0; i < tab->count; i++) + *entry++ = tab->table[i]; + finish_table(tab, SFI_SIG_SYST, entry); + + return 0; +} + +static int sfi_write_cpus(struct table_info *tab) +{ + struct sfi_cpu_table_entry *entry = get_entry_start(tab); + struct udevice *dev; + int count = 0; + + if (!entry) + return -ENOSPC; + + for (uclass_find_first_device(UCLASS_CPU, &dev); + dev; + uclass_find_next_device(&dev)) { + struct cpu_platdata *plat = dev_get_parent_platdata(dev); + + if (!device_active(dev)) + continue; + entry->apic_id = plat->cpu_id; + entry++; + count++; + } + + /* Omit the table if there is only one CPU */ + if (count > 1) + finish_table(tab, SFI_SIG_CPUS, entry); + + return 0; +} + +static int sfi_write_apic(struct table_info *tab) +{ + struct sfi_apic_table_entry *entry = get_entry_start(tab); + + if (!entry) + return -ENOSPC; + + entry->phys_addr = IO_APIC_ADDR; + entry++; + finish_table(tab, SFI_SIG_APIC, entry); + + return 0; +} + +static int sfi_write_xsdt(struct table_info *tab) +{ + struct sfi_xsdt_header *entry = get_entry_start(tab); + + if (!entry) + return -ENOSPC; + + entry->oem_revision = 1; + entry->creator_id = 1; + entry->creator_revision = 1; + entry++; + finish_table(tab, SFI_SIG_XSDT, entry); + + return 0; +} + +u32 write_sfi_table(u32 base) +{ + struct table_info table; + + table.base = base; + table.ptr = 0; + table.count = 0; + sfi_write_cpus(&table); + sfi_write_apic(&table); + + /* + * The SFI specification marks the XSDT table as option, but Linux 4.0 + * crashes on start-up when it is not provided. + */ + sfi_write_xsdt(&table); + + /* Finally, write out the system header which points to the others */ + sfi_write_system_header(&table); + + return base + table.ptr; +} diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c new file mode 100644 index 0000000000..8031201a49 --- /dev/null +++ b/arch/x86/lib/tables.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/sfi.h> +#include <asm/tables.h> + +u8 table_compute_checksum(void *v, int len) +{ + u8 *bytes = v; + u8 checksum = 0; + int i; + + for (i = 0; i < len; i++) + checksum -= bytes[i]; + + return checksum; +} + +void write_tables(void) +{ + u32 __maybe_unused rom_table_end = ROM_TABLE_ADDR; + +#ifdef CONFIG_GENERATE_PIRQ_TABLE + rom_table_end = write_pirq_routing_table(rom_table_end); + rom_table_end = ALIGN(rom_table_end, 1024); +#endif +#ifdef CONFIG_GENERATE_SFI_TABLE + rom_table_end = write_sfi_table(rom_table_end); + rom_table_end = ALIGN(rom_table_end, 1024); +#endif +} diff --git a/arch/x86/lib/video.c b/arch/x86/lib/video.c deleted file mode 100644 index 975949daa3..0000000000 --- a/arch/x86/lib/video.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * (C) Copyright 2002 - * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <pci.h> -#include <stdio_dev.h> -#include <i8042.h> -#include <asm/ptrace.h> -#include <asm/io.h> -#include <asm/pci.h> - -/* basic textmode I/O from linux kernel */ -static char *vidmem = (char *)0xb8000; -static int vidport; -static int lines, cols; -static int orig_x, orig_y; - -static void beep(int dur) -{ - int i; - - outb_p(3, 0x61); - for (i = 0; i < 10*dur; i++) - udelay(1000); - - outb_p(0, 0x61); -} - -static void scroll(void) -{ - int i; - - memcpy(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2); - for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2) - vidmem[i] = ' '; -} - -static void __video_putc(const char c, int *x, int *y) -{ - if (c == '\n') { - (*x) = 0; - if (++(*y) >= lines) { - scroll(); - (*y)--; - } - } else if (c == '\b') { - if ((*x) != 0) { - --(*x); - vidmem[((*x) + cols * (*y)) * 2] = ' '; - } - } else if (c == '\r') { - (*x) = 0; - - } else if (c == '\a') { - beep(3); - - } else if (c == '\t') { - __video_putc(' ', x, y); - __video_putc(' ', x, y); - __video_putc(' ', x, y); - __video_putc(' ', x, y); - __video_putc(' ', x, y); - __video_putc(' ', x, y); - __video_putc(' ', x, y); - __video_putc(' ', x, y); - } else if (c == '\v') { - switch ((*x) % 8) { - case 0: - __video_putc(' ', x, y); - case 7: - __video_putc(' ', x, y); - case 6: - __video_putc(' ', x, y); - case 5: - __video_putc(' ', x, y); - case 4: - __video_putc(' ', x, y); - case 3: - __video_putc(' ', x, y); - case 2: - __video_putc(' ', x, y); - case 1: - __video_putc(' ', x, y); - } - } else if (c == '\f') { - int i; - for (i = 0; i < lines * cols * 2; i += 2) - vidmem[i] = 0; - (*x) = 0; - (*y) = 0; - } else { - vidmem[((*x) + cols * (*y)) * 2] = c; - if (++(*x) >= cols) { - (*x) = 0; - if (++(*y) >= lines) { - scroll(); - (*y)--; - } - } - } -} - -static void video_putc(struct stdio_dev *dev, const char c) -{ - int x, y, pos; - - x = orig_x; - y = orig_y; - - __video_putc(c, &x, &y); - - orig_x = x; - orig_y = y; - - pos = (x + cols * y) * 2; /* Update cursor position */ - outb_p(14, vidport); - outb_p(0xff & (pos >> 9), vidport+1); - outb_p(15, vidport); - outb_p(0xff & (pos >> 1), vidport+1); -} - -static void video_puts(struct stdio_dev *dev, const char *s) -{ - int x, y, pos; - char c; - - x = orig_x; - y = orig_y; - - while ((c = *s++) != '\0') - __video_putc(c, &x, &y); - - orig_x = x; - orig_y = y; - - pos = (x + cols * y) * 2; /* Update cursor position */ - outb_p(14, vidport); - outb_p(0xff & (pos >> 9), vidport+1); - outb_p(15, vidport); - outb_p(0xff & (pos >> 1), vidport+1); -} - -int video_init(void) -{ - u16 pos; - - static struct stdio_dev vga_dev; - static struct stdio_dev kbd_dev; - - vidmem = (char *) 0xb8000; - vidport = 0x3d4; - - lines = 25; - cols = 80; - - outb_p(14, vidport); - pos = inb_p(vidport+1); - pos <<= 8; - outb_p(15, vidport); - pos |= inb_p(vidport+1); - - orig_x = pos%cols; - orig_y = pos/cols; - -#if 0 - printf("pos %x %d %d\n", pos, orig_x, orig_y); -#endif - if (orig_y > lines) - orig_x = orig_y = 0; - - memset(&vga_dev, 0, sizeof(vga_dev)); - strcpy(vga_dev.name, "vga"); - vga_dev.ext = 0; - vga_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM; - vga_dev.putc = video_putc; /* 'putc' function */ - vga_dev.puts = video_puts; /* 'puts' function */ - - if (stdio_register(&vga_dev) == 0) - return 1; - - if (i8042_kbd_init()) - return 1; - - memset(&kbd_dev, 0, sizeof(kbd_dev)); - strcpy(kbd_dev.name, "kbd"); - kbd_dev.ext = 0; - kbd_dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; - kbd_dev.tstc = i8042_tstc; /* 'tstc' function */ - kbd_dev.getc = i8042_getc; /* 'getc' function */ - - if (stdio_register(&kbd_dev) == 0) - return 1; - - return 0; -} - - -int drv_video_init(void) -{ - return video_init(); -} diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 566b048c88..c3f8a7308f 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -25,6 +25,8 @@ #endif #include <linux/compiler.h> +DECLARE_GLOBAL_DATA_PTR; + /* * Memory lay-out: * @@ -40,16 +42,29 @@ #define COMMAND_LINE_SIZE 2048 -unsigned generic_install_e820_map(unsigned max_entries, - struct e820entry *entries) +/* + * Install a default e820 table with 3 entries as follows: + * + * 0x000000-0x0a0000 Useable RAM + * 0x0a0000-0x100000 Reserved for ISA + * 0x100000-gd->ram_size Useable RAM + */ +__weak unsigned install_e820_map(unsigned max_entries, + struct e820entry *entries) { - return 0; + entries[0].addr = 0; + entries[0].size = ISA_START_ADDRESS; + entries[0].type = E820_RAM; + entries[1].addr = ISA_START_ADDRESS; + entries[1].size = ISA_END_ADDRESS - ISA_START_ADDRESS; + entries[1].type = E820_RESERVED; + entries[2].addr = ISA_END_ADDRESS; + entries[2].size = gd->ram_size - ISA_END_ADDRESS; + entries[2].type = E820_RAM; + + return 3; } -unsigned install_e820_map(unsigned max_entries, - struct e820entry *entries) - __attribute__((weak, alias("generic_install_e820_map"))); - static void build_command_line(char *command_line, int auto_boot) { char *env_command_line; |