diff options
Diffstat (limited to 'arch/x86/lib')
-rw-r--r-- | arch/x86/lib/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/lib/acpi_table.c | 4 | ||||
-rw-r--r-- | arch/x86/lib/coreboot_table.c | 136 | ||||
-rw-r--r-- | arch/x86/lib/fsp/fsp_car.S | 2 | ||||
-rw-r--r-- | arch/x86/lib/mpspec.c | 2 | ||||
-rw-r--r-- | arch/x86/lib/pinctrl_ich6.c | 216 | ||||
-rw-r--r-- | arch/x86/lib/tables.c | 77 |
7 files changed, 417 insertions, 22 deletions
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 4fc19365eb..dc90df2050 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -10,6 +10,7 @@ obj-y += bios_asm.o obj-y += bios_interrupts.o obj-$(CONFIG_CMD_BOOTM) += bootm.o obj-y += cmd_boot.o +obj-y += coreboot_table.o obj-$(CONFIG_EFI) += efi/ obj-y += e820.o obj-y += gcc.o @@ -22,6 +23,7 @@ obj-y += cmd_mtrr.o obj-y += northbridge-uclass.o obj-$(CONFIG_I8259_PIC) += i8259.o obj-$(CONFIG_I8254_TIMER) += i8254.o +obj-y += pinctrl_ich6.o obj-y += pirq_routing.o obj-y += relocate.o obj-y += physmem.o diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index 2ec5ad2fa4..790f6fbd0f 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -335,9 +335,9 @@ static void acpi_create_ssdt_generator(acpi_header_t *ssdt, * QEMU's version of write_acpi_tables is defined in * arch/x86/cpu/qemu/fw_cfg.c */ -unsigned long write_acpi_tables(unsigned long start) +u32 write_acpi_tables(u32 start) { - unsigned long current; + u32 current; struct acpi_rsdp *rsdp; struct acpi_rsdt *rsdt; struct acpi_xsdt *xsdt; diff --git a/arch/x86/lib/coreboot_table.c b/arch/x86/lib/coreboot_table.c new file mode 100644 index 0000000000..cb45a79857 --- /dev/null +++ b/arch/x86/lib/coreboot_table.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <vbe.h> +#include <asm/coreboot_tables.h> +#include <asm/e820.h> + +/** + * cb_table_init() - initialize a coreboot table header + * + * This fills in the coreboot table header signature and the header bytes. + * Other fields are set to zero. + * + * @cbh: coreboot table header address + */ +static void cb_table_init(struct cb_header *cbh) +{ + memset(cbh, 0, sizeof(struct cb_header)); + memcpy(cbh->signature, "LBIO", 4); + cbh->header_bytes = sizeof(struct cb_header); +} + +/** + * cb_table_add_entry() - add a coreboot table entry + * + * This increases the coreboot table entry size with added table entry length + * and increases entry count by 1. + * + * @cbh: coreboot table header address + * @cbr: to be added table entry address + * @return: pointer to next table entry address + */ +static u32 cb_table_add_entry(struct cb_header *cbh, struct cb_record *cbr) +{ + cbh->table_bytes += cbr->size; + cbh->table_entries++; + + return (u32)cbr + cbr->size; +} + +/** + * cb_table_finalize() - finalize the coreboot table + * + * This calculates the checksum for all coreboot table entries as well as + * the checksum for the coreboot header itself. + * + * @cbh: coreboot table header address + */ +static void cb_table_finalize(struct cb_header *cbh) +{ + struct cb_record *cbr = (struct cb_record *)(cbh + 1); + + cbh->table_checksum = compute_ip_checksum(cbr, cbh->table_bytes); + cbh->header_checksum = compute_ip_checksum(cbh, cbh->header_bytes); +} + +void write_coreboot_table(u32 addr, struct memory_area *cfg_tables) +{ + struct cb_header *cbh = (struct cb_header *)addr; + struct cb_record *cbr; + struct cb_memory *mem; + struct cb_memory_range *map; + struct e820entry e820[32]; + struct cb_framebuffer *fb; + struct vesa_mode_info *vesa; + int i, num; + + cb_table_init(cbh); + cbr = (struct cb_record *)(cbh + 1); + + /* + * Two type of coreboot table entries are generated by us. + * They are 'struct cb_memory' and 'struct cb_framebuffer'. + */ + + /* populate memory map table */ + mem = (struct cb_memory *)cbr; + mem->tag = CB_TAG_MEMORY; + map = mem->map; + + /* first install e820 defined memory maps */ + num = install_e820_map(ARRAY_SIZE(e820), e820); + for (i = 0; i < num; i++) { + map->start.lo = e820[i].addr & 0xffffffff; + map->start.hi = e820[i].addr >> 32; + map->size.lo = e820[i].size & 0xffffffff; + map->size.hi = e820[i].size >> 32; + map->type = e820[i].type; + map++; + } + + /* then install all configuration tables */ + while (cfg_tables->size) { + map->start.lo = cfg_tables->start & 0xffffffff; + map->start.hi = cfg_tables->start >> 32; + map->size.lo = cfg_tables->size & 0xffffffff; + map->size.hi = cfg_tables->size >> 32; + map->type = CB_MEM_TABLE; + map++; + num++; + cfg_tables++; + } + mem->size = num * sizeof(struct cb_memory_range) + + sizeof(struct cb_record); + cbr = (struct cb_record *)cb_table_add_entry(cbh, cbr); + + /* populate framebuffer table if we have sane vesa info */ + vesa = &mode_info.vesa; + if (vesa->x_resolution && vesa->y_resolution) { + fb = (struct cb_framebuffer *)cbr; + fb->tag = CB_TAG_FRAMEBUFFER; + fb->size = sizeof(struct cb_framebuffer); + + fb->x_resolution = vesa->x_resolution; + fb->y_resolution = vesa->y_resolution; + fb->bits_per_pixel = vesa->bits_per_pixel; + fb->bytes_per_line = vesa->bytes_per_scanline; + fb->physical_address = vesa->phys_base_ptr; + fb->red_mask_size = vesa->red_mask_size; + fb->red_mask_pos = vesa->red_mask_pos; + fb->green_mask_size = vesa->green_mask_size; + fb->green_mask_pos = vesa->green_mask_pos; + fb->blue_mask_size = vesa->blue_mask_size; + fb->blue_mask_pos = vesa->blue_mask_pos; + fb->reserved_mask_size = vesa->reserved_mask_size; + fb->reserved_mask_pos = vesa->reserved_mask_pos; + + cbr = (struct cb_record *)cb_table_add_entry(cbh, cbr); + } + + cb_table_finalize(cbh); +} diff --git a/arch/x86/lib/fsp/fsp_car.S b/arch/x86/lib/fsp/fsp_car.S index 15b37512a5..fbe8aef540 100644 --- a/arch/x86/lib/fsp/fsp_car.S +++ b/arch/x86/lib/fsp/fsp_car.S @@ -102,6 +102,8 @@ temp_ram_init_romstack: temp_ram_init_params: _dt_ucode_base_size: /* These next two fields are filled in by ifdtool */ +.globl ucode_base +ucode_base: /* Declared in micrcode.h */ .long 0 /* microcode base */ .long 0 /* microcode size */ .long CONFIG_SYS_MONITOR_BASE /* code region base */ diff --git a/arch/x86/lib/mpspec.c b/arch/x86/lib/mpspec.c index 0faa582d77..6ab43f1055 100644 --- a/arch/x86/lib/mpspec.c +++ b/arch/x86/lib/mpspec.c @@ -297,7 +297,7 @@ static int mptable_add_intsrc(struct mp_config_table *mc, const u32 *cell; int i, ret; - ret = uclass_first_device(UCLASS_IRQ, &dev); + ret = uclass_first_device_err(UCLASS_IRQ, &dev); if (ret && ret != -ENODEV) { debug("%s: Cannot find irq router node\n", __func__); return ret; diff --git a/arch/x86/lib/pinctrl_ich6.c b/arch/x86/lib/pinctrl_ich6.c new file mode 100644 index 0000000000..3f94cdf2da --- /dev/null +++ b/arch/x86/lib/pinctrl_ich6.c @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2016 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <pch.h> +#include <pci.h> +#include <asm/cpu.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/pci.h> +#include <dm/pinctrl.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define GPIO_USESEL_OFFSET(x) (x) +#define GPIO_IOSEL_OFFSET(x) (x + 4) +#define GPIO_LVL_OFFSET(x) ((x) ? (x) + 8 : 0xc) +#define GPI_INV 0x2c + +#define IOPAD_MODE_MASK 0x7 +#define IOPAD_PULL_ASSIGN_SHIFT 7 +#define IOPAD_PULL_ASSIGN_MASK (0x3 << IOPAD_PULL_ASSIGN_SHIFT) +#define IOPAD_PULL_STRENGTH_SHIFT 9 +#define IOPAD_PULL_STRENGTH_MASK (0x3 << IOPAD_PULL_STRENGTH_SHIFT) + +static int ich6_pinctrl_set_value(uint16_t base, unsigned offset, int value) +{ + if (value) + setio_32(base, 1UL << offset); + else + clrio_32(base, 1UL << offset); + + return 0; +} + +static int ich6_pinctrl_set_function(uint16_t base, unsigned offset, int func) +{ + if (func) + setio_32(base, 1UL << offset); + else + clrio_32(base, 1UL << offset); + + return 0; +} + +static int ich6_pinctrl_set_direction(uint16_t base, unsigned offset, int dir) +{ + if (!dir) + setio_32(base, 1UL << offset); + else + clrio_32(base, 1UL << offset); + + return 0; +} + +static int ich6_pinctrl_cfg_pin(s32 gpiobase, s32 iobase, int pin_node) +{ + bool is_gpio, invert; + u32 gpio_offset[2]; + int pad_offset; + int dir, val; + int ret; + + /* + * GPIO node is not mandatory, so we only do the pinmuxing if the + * node exists. + */ + ret = fdtdec_get_int_array(gd->fdt_blob, pin_node, "gpio-offset", + gpio_offset, 2); + if (!ret) { + /* Do we want to force the GPIO mode? */ + is_gpio = fdtdec_get_bool(gd->fdt_blob, pin_node, "mode-gpio"); + if (is_gpio) + ich6_pinctrl_set_function(GPIO_USESEL_OFFSET(gpiobase) + + gpio_offset[0], gpio_offset[1], + 1); + + dir = fdtdec_get_int(gd->fdt_blob, pin_node, "direction", -1); + if (dir != -1) + ich6_pinctrl_set_direction(GPIO_IOSEL_OFFSET(gpiobase) + + gpio_offset[0], gpio_offset[1], + dir); + + val = fdtdec_get_int(gd->fdt_blob, pin_node, "output-value", + -1); + if (val != -1) + ich6_pinctrl_set_value(GPIO_LVL_OFFSET(gpiobase) + + gpio_offset[0], gpio_offset[1], + val); + + invert = fdtdec_get_bool(gd->fdt_blob, pin_node, "invert"); + if (invert) + setio_32(gpiobase + GPI_INV, 1 << gpio_offset[1]); + debug("gpio %#x bit %d, is_gpio %d, dir %d, val %d, invert %d\n", + gpio_offset[0], gpio_offset[1], is_gpio, dir, val, + invert); + } + + /* if iobase is present, let's configure the pad */ + if (iobase != -1) { + int iobase_addr; + + /* + * The offset for the same pin for the IOBASE and GPIOBASE are + * different, so instead of maintaining a lookup table, + * the device tree should provide directly the correct + * value for both mapping. + */ + pad_offset = fdtdec_get_int(gd->fdt_blob, pin_node, + "pad-offset", -1); + if (pad_offset == -1) + return 0; + + /* compute the absolute pad address */ + iobase_addr = iobase + pad_offset; + + /* + * Do we need to set a specific function mode? + * If someone put also 'mode-gpio', this option will + * be just ignored by the controller + */ + val = fdtdec_get_int(gd->fdt_blob, pin_node, "mode-func", -1); + if (val != -1) + clrsetbits_le32(iobase_addr, IOPAD_MODE_MASK, val); + + /* Configure the pull-up/down if needed */ + val = fdtdec_get_int(gd->fdt_blob, pin_node, "pull-assign", -1); + if (val != -1) + clrsetbits_le32(iobase_addr, + IOPAD_PULL_ASSIGN_MASK, + val << IOPAD_PULL_ASSIGN_SHIFT); + + val = fdtdec_get_int(gd->fdt_blob, pin_node, "pull-strength", + -1); + if (val != -1) + clrsetbits_le32(iobase_addr, + IOPAD_PULL_STRENGTH_MASK, + val << IOPAD_PULL_STRENGTH_SHIFT); + + debug("%s: pad cfg [0x%x]: %08x\n", __func__, pad_offset, + readl(iobase_addr)); + } + + return 0; +} + +static int ich6_pinctrl_probe(struct udevice *dev) +{ + struct udevice *pch; + int pin_node; + int ret; + u32 gpiobase; + u32 iobase = -1; + + debug("%s: start\n", __func__); + ret = uclass_first_device(UCLASS_PCH, &pch); + if (ret) + return ret; + if (!pch) + return -ENODEV; + + /* + * Get the memory/io base address to configure every pins. + * IOBASE is used to configure the mode/pads + * GPIOBASE is used to configure the direction and default value + */ + ret = pch_get_gpio_base(pch, &gpiobase); + if (ret) { + debug("%s: invalid GPIOBASE address (%08x)\n", __func__, + gpiobase); + return -EINVAL; + } + + /* + * Get the IOBASE, this is not mandatory as this is not + * supported by all the CPU + */ + ret = pch_get_io_base(pch, &iobase); + if (ret && ret != -ENOSYS) { + debug("%s: invalid IOBASE address (%08x)\n", __func__, iobase); + return -EINVAL; + } + + for (pin_node = fdt_first_subnode(gd->fdt_blob, dev->of_offset); + pin_node > 0; + pin_node = fdt_next_subnode(gd->fdt_blob, pin_node)) { + /* Configure the pin */ + ret = ich6_pinctrl_cfg_pin(gpiobase, iobase, pin_node); + if (ret != 0) { + debug("%s: invalid configuration for the pin %d\n", + __func__, pin_node); + return ret; + } + } + debug("%s: done\n", __func__); + + return 0; +} + +static const struct udevice_id ich6_pinctrl_match[] = { + { .compatible = "intel,x86-pinctrl", .data = X86_SYSCON_PINCONF }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(ich6_pinctrl) = { + .name = "ich6_pinctrl", + .id = UCLASS_SYSCON, + .of_match = ich6_pinctrl_match, + .probe = ich6_pinctrl_probe, +}; diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index 14b15cf389..a156f2ce31 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -10,6 +10,33 @@ #include <asm/smbios.h> #include <asm/tables.h> #include <asm/acpi_table.h> +#include <asm/coreboot_tables.h> + +/** + * Function prototype to write a specific configuration table + * + * @addr: start address to write the table + * @return: end address of the table + */ +typedef u32 (*table_write)(u32 addr); + +static table_write table_write_funcs[] = { +#ifdef CONFIG_GENERATE_PIRQ_TABLE + write_pirq_routing_table, +#endif +#ifdef CONFIG_GENERATE_SFI_TABLE + write_sfi_table, +#endif +#ifdef CONFIG_GENERATE_MP_TABLE + write_mp_table, +#endif +#ifdef CONFIG_GENERATE_ACPI_TABLE + write_acpi_tables, +#endif +#ifdef CONFIG_GENERATE_SMBIOS_TABLE + write_smbios_table, +#endif +}; u8 table_compute_checksum(void *v, int len) { @@ -39,26 +66,38 @@ void table_fill_string(char *dest, const char *src, size_t n, char pad) 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); + u32 rom_table_start = ROM_TABLE_ADDR; + u32 rom_table_end; +#ifdef CONFIG_SEABIOS + u32 high_table, table_size; + struct memory_area cfg_tables[ARRAY_SIZE(table_write_funcs) + 1]; #endif -#ifdef CONFIG_GENERATE_MP_TABLE - rom_table_end = write_mp_table(rom_table_end); - rom_table_end = ALIGN(rom_table_end, 1024); -#endif -#ifdef CONFIG_GENERATE_ACPI_TABLE - rom_table_end = write_acpi_tables(rom_table_end); - rom_table_end = ALIGN(rom_table_end, 1024); + int i; + + for (i = 0; i < ARRAY_SIZE(table_write_funcs); i++) { + rom_table_end = table_write_funcs[i](rom_table_start); + rom_table_end = ALIGN(rom_table_end, ROM_TABLE_ALIGN); + +#ifdef CONFIG_SEABIOS + table_size = rom_table_end - rom_table_start; + high_table = (u32)memalign(ROM_TABLE_ALIGN, table_size); + if (high_table) { + memset((void *)high_table, 0, table_size); + table_write_funcs[i](high_table); + + cfg_tables[i].start = high_table; + cfg_tables[i].size = table_size; + } else { + printf("%d: no memory for configuration tables\n", i); + } #endif -#ifdef CONFIG_GENERATE_SMBIOS_TABLE - rom_table_end = write_smbios_table(rom_table_end); - rom_table_end = ALIGN(rom_table_end, 1024); + + rom_table_start = rom_table_end; + } + +#ifdef CONFIG_SEABIOS + /* make sure the last item is zero */ + cfg_tables[i].size = 0; + write_coreboot_table(CB_TABLE_ADDR, cfg_tables); #endif } |