summaryrefslogtreecommitdiffstats
path: root/arch/x86/lib
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/lib')
-rw-r--r--arch/x86/lib/Makefile2
-rw-r--r--arch/x86/lib/acpi_table.c4
-rw-r--r--arch/x86/lib/coreboot_table.c136
-rw-r--r--arch/x86/lib/fsp/fsp_car.S2
-rw-r--r--arch/x86/lib/mpspec.c2
-rw-r--r--arch/x86/lib/pinctrl_ich6.c216
-rw-r--r--arch/x86/lib/tables.c77
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
}
OpenPOWER on IntegriCloud