diff options
author | Tom Rini <trini@konsulko.com> | 2015-08-14 17:43:23 (GMT) |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2015-08-14 20:27:16 (GMT) |
commit | 632093b566569329bc6e5b0893bdca01de905314 (patch) | |
tree | ddd8cb84789bf0bc60a566fd8d33ff138d6861e9 | |
parent | 61dfa65e405f2713dfc8090ed8147ec33b003717 (diff) | |
parent | 236efe36be6d1c544f9477f10fdf38a17cd7a869 (diff) | |
download | u-boot-fsl-qoriq-632093b566569329bc6e5b0893bdca01de905314.tar.xz |
Merge git://git.denx.de/u-boot-x86
39 files changed, 875 insertions, 264 deletions
diff --git a/arch/x86/cpu/baytrail/fsp_configs.c b/arch/x86/cpu/baytrail/fsp_configs.c index 86b6926..a72d615 100644 --- a/arch/x86/cpu/baytrail/fsp_configs.c +++ b/arch/x86/cpu/baytrail/fsp_configs.c @@ -1,14 +1,18 @@ /* * Copyright (C) 2013, Intel Corporation * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com> + * Copyright (C) 2015, Kodak Alaris, Inc * * SPDX-License-Identifier: Intel */ #include <common.h> +#include <fdtdec.h> #include <asm/arch/fsp/azalia.h> #include <asm/fsp/fsp_support.h> +DECLARE_GLOBAL_DATA_PTR; + /* ALC262 Verb Table - 10EC0262 */ static const uint32_t verb_table_data13[] = { /* Pin Complex (NID 0x11) */ @@ -116,41 +120,139 @@ const struct pch_azalia_config azalia_config = { .reset_wait_timer_us = 300 }; +/** + * Override the FSP's UPD. + * If the device tree does not specify an integer setting, use the default + * provided in Intel's Baytrail_FSP_Gold4.tgz release FSP/BayleyBayFsp.bsf file. + */ void update_fsp_upd(struct upd_region *fsp_upd) { struct memory_down_data *mem; + const void *blob = gd->fdt_blob; + int node; - /* - * Configure everything here to avoid the poor hard-pressed user - * needing to run Intel's binary configuration tool. It may also allow - * us to support the 1GB single core variant easily. - * - * TODO(sjg@chromium.org): Move to device tree - */ - fsp_upd->mrc_init_tseg_size = 8; - fsp_upd->mrc_init_mmio_size = 0x800; - fsp_upd->emmc_boot_mode = 0xff; - fsp_upd->enable_sdio = 1; - fsp_upd->enable_sdcard = 1; - fsp_upd->enable_hsuart0 = 1; fsp_upd->azalia_config_ptr = (uint32_t)&azalia_config; - fsp_upd->enable_i2_c0 = 0; - fsp_upd->enable_i2_c2 = 0; - fsp_upd->enable_i2_c3 = 0; - fsp_upd->enable_i2_c4 = 0; - fsp_upd->enable_xhci = 0; - fsp_upd->igd_render_standby = 1; + + node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_BAYTRAIL_FSP); + if (node < 0) { + debug("%s: Cannot find FSP node\n", __func__); + return; + } + + fsp_upd->mrc_init_tseg_size = fdtdec_get_int(blob, node, + "fsp,mrc-init-tseg-size", + 0); + fsp_upd->mrc_init_mmio_size = fdtdec_get_int(blob, node, + "fsp,mrc-init-mmio-size", + 0x800); + fsp_upd->mrc_init_spd_addr1 = fdtdec_get_int(blob, node, + "fsp,mrc-init-spd-addr1", + 0xa0); + fsp_upd->mrc_init_spd_addr2 = fdtdec_get_int(blob, node, + "fsp,mrc-init-spd-addr2", + 0xa2); + fsp_upd->emmc_boot_mode = fdtdec_get_int(blob, node, + "fsp,emmc-boot-mode", 2); + fsp_upd->enable_sdio = fdtdec_get_bool(blob, node, "fsp,enable-sdio"); + fsp_upd->enable_sdcard = fdtdec_get_bool(blob, node, + "fsp,enable-sdcard"); + fsp_upd->enable_hsuart0 = fdtdec_get_bool(blob, node, + "fsp,enable-hsuart0"); + fsp_upd->enable_hsuart1 = fdtdec_get_bool(blob, node, + "fsp,enable-hsuart1"); + fsp_upd->enable_spi = fdtdec_get_bool(blob, node, "fsp,enable-spi"); + fsp_upd->enable_sata = fdtdec_get_bool(blob, node, "fsp,enable-sata"); + fsp_upd->sata_mode = fdtdec_get_int(blob, node, "fsp,sata-mode", 1); + fsp_upd->enable_azalia = fdtdec_get_bool(blob, node, + "fsp,enable-azalia"); + fsp_upd->enable_xhci = fdtdec_get_bool(blob, node, "fsp,enable-xhci"); + fsp_upd->enable_lpe = fdtdec_get_bool(blob, node, "fsp,enable-lpe"); + fsp_upd->lpss_sio_enable_pci_mode = fdtdec_get_bool(blob, node, + "fsp,lpss-sio-enable-pci-mode"); + fsp_upd->enable_dma0 = fdtdec_get_bool(blob, node, "fsp,enable-dma0"); + fsp_upd->enable_dma1 = fdtdec_get_bool(blob, node, "fsp,enable-dma1"); + fsp_upd->enable_i2_c0 = fdtdec_get_bool(blob, node, "fsp,enable-i2c0"); + fsp_upd->enable_i2_c1 = fdtdec_get_bool(blob, node, "fsp,enable-i2c1"); + fsp_upd->enable_i2_c2 = fdtdec_get_bool(blob, node, "fsp,enable-i2c2"); + fsp_upd->enable_i2_c3 = fdtdec_get_bool(blob, node, "fsp,enable-i2c3"); + fsp_upd->enable_i2_c4 = fdtdec_get_bool(blob, node, "fsp,enable-i2c4"); + fsp_upd->enable_i2_c5 = fdtdec_get_bool(blob, node, "fsp,enable-i2c5"); + fsp_upd->enable_i2_c6 = fdtdec_get_bool(blob, node, "fsp,enable-i2c6"); + fsp_upd->enable_pwm0 = fdtdec_get_bool(blob, node, "fsp,enable-pwm0"); + fsp_upd->enable_pwm1 = fdtdec_get_bool(blob, node, "fsp,enable-pwm1"); + fsp_upd->enable_hsi = fdtdec_get_bool(blob, node, "fsp,enable-hsi"); + fsp_upd->igd_dvmt50_pre_alloc = fdtdec_get_int(blob, node, + "fsp,igd-dvmt50-pre-alloc", 2); + fsp_upd->aperture_size = fdtdec_get_int(blob, node, "fsp,aperture-size", + 2); + fsp_upd->gtt_size = fdtdec_get_int(blob, node, "fsp,gtt-size", 2); + fsp_upd->serial_debug_port_address = fdtdec_get_int(blob, node, + "fsp,serial-debug-port-address", 0x3f8); + fsp_upd->serial_debug_port_type = fdtdec_get_int(blob, node, + "fsp,serial-debug-port-type", 1); + fsp_upd->mrc_debug_msg = fdtdec_get_bool(blob, node, + "fsp,mrc-debug-msg"); + fsp_upd->isp_enable = fdtdec_get_bool(blob, node, "fsp,isp-enable"); + fsp_upd->scc_enable_pci_mode = fdtdec_get_bool(blob, node, + "fsp,scc-enable-pci-mode"); + fsp_upd->igd_render_standby = fdtdec_get_bool(blob, node, + "fsp,igd-render-standby"); + fsp_upd->txe_uma_enable = fdtdec_get_bool(blob, node, + "fsp,txe-uma-enable"); + fsp_upd->os_selection = fdtdec_get_int(blob, node, "fsp,os-selection", + 4); + fsp_upd->emmc45_ddr50_enabled = fdtdec_get_bool(blob, node, + "fsp,emmc45-ddr50-enabled"); + fsp_upd->emmc45_hs200_enabled = fdtdec_get_bool(blob, node, + "fsp,emmc45-hs200-enabled"); + fsp_upd->emmc45_retune_timer_value = fdtdec_get_int(blob, node, + "fsp,emmc45-retune-timer-value", 8); + fsp_upd->enable_igd = fdtdec_get_bool(blob, node, "fsp,enable-igd"); mem = &fsp_upd->memory_params; - mem->enable_memory_down = 1; - mem->dram_speed = 1; - mem->dimm_width = 1; - mem->dimm_density = 2; - mem->dimm_tcl = 0xb; - mem->dimm_trpt_rcd = 0xb; - mem->dimm_twr = 0xc; - mem->dimm_twtr = 6; - mem->dimm_trrd = 6; - mem->dimm_trtp = 6; - mem->dimm_tfaw = 0x14; + mem->enable_memory_down = fdtdec_get_bool(blob, node, + "fsp,enable-memory-down"); + if (mem->enable_memory_down) { + node = fdtdec_next_compatible(blob, node, + COMPAT_INTEL_BAYTRAIL_FSP_MDP); + if (node < 0) { + debug("%s: Cannot find FSP memory-down-params node\n", + __func__); + } else { + mem->dram_speed = fdtdec_get_int(blob, node, + "fsp,dram-speed", + 0x02); + mem->dram_type = fdtdec_get_int(blob, node, + "fsp,dram-type", 0x01); + mem->dimm_0_enable = fdtdec_get_bool(blob, node, + "fsp,dimm-0-enable"); + mem->dimm_1_enable = fdtdec_get_bool(blob, node, + "fsp,dimm-1-enable"); + mem->dimm_width = fdtdec_get_int(blob, node, + "fsp,dimm-width", + 0x00); + mem->dimm_density = fdtdec_get_int(blob, node, + "fsp,dimm-density", + 0x01); + mem->dimm_bus_width = fdtdec_get_int(blob, node, + "fsp,dimm-bus-width", 0x03); + mem->dimm_sides = fdtdec_get_int(blob, node, + "fsp,dimm-sides", + 0x00); + mem->dimm_tcl = fdtdec_get_int(blob, node, + "fsp,dimm-tcl", 0x09); + mem->dimm_trpt_rcd = fdtdec_get_int(blob, node, + "fsp,dimm-trpt-rcd", 0x09); + mem->dimm_twr = fdtdec_get_int(blob, node, + "fsp,dimm-twr", 0x0A); + mem->dimm_twtr = fdtdec_get_int(blob, node, + "fsp,dimm-twtr", 0x05); + mem->dimm_trrd = fdtdec_get_int(blob, node, + "fsp,dimm-trrd", 0x04); + mem->dimm_trtp = fdtdec_get_int(blob, node, + "fsp,dimm-trtp", 0x05); + mem->dimm_tfaw = fdtdec_get_int(blob, node, + "fsp,dimm-tfaw", 0x14); + } + } } diff --git a/arch/x86/cpu/baytrail/valleyview.c b/arch/x86/cpu/baytrail/valleyview.c index 610e9d9..6c3dfe8 100644 --- a/arch/x86/cpu/baytrail/valleyview.c +++ b/arch/x86/cpu/baytrail/valleyview.c @@ -9,6 +9,7 @@ #include <pci_ids.h> #include <asm/irq.h> #include <asm/post.h> +#include <asm/fsp/fsp_support.h> static struct pci_device_id mmc_supported[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VALLEYVIEW_SDIO }, @@ -40,8 +41,14 @@ int arch_cpu_init(void) int arch_misc_init(void) { - pirq_init(); + int ret; - return 0; + if (!ll_boot_init()) + return 0; + ret = pirq_init(); + if (ret) + return ret; + + return fsp_init_phase_pci(); } #endif diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 129777c..1b76ca1 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -136,9 +136,12 @@ static void load_gdt(const u64 *boot_gdt, u16 num_entries) asm volatile("lgdtl %0\n" : : "m" (gdt)); } -void setup_gdt(gd_t *id, u64 *gdt_addr) +void arch_setup_gd(gd_t *new_gd) { - id->arch.gdt = gdt_addr; + u64 *gdt_addr; + + gdt_addr = new_gd->arch.gdt; + /* CS: code, read/execute, 4 GB, base 0 */ gdt_addr[X86_GDT_ENTRY_32BIT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff); @@ -146,9 +149,9 @@ void setup_gdt(gd_t *id, u64 *gdt_addr) gdt_addr[X86_GDT_ENTRY_32BIT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff); /* FS: data, read/write, 4 GB, base (Global Data Pointer) */ - id->arch.gd_addr = id; + new_gd->arch.gd_addr = new_gd; gdt_addr[X86_GDT_ENTRY_32BIT_FS] = GDT_ENTRY(0xc093, - (ulong)&id->arch.gd_addr, 0xfffff); + (ulong)&new_gd->arch.gd_addr, 0xfffff); /* 16-bit CS: code, read/execute, 64 kB, base 0 */ gdt_addr[X86_GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x009b, 0, 0x0ffff); diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index 9217307..addd26e 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -103,6 +103,8 @@ static void dump_regs(struct irq_regs *regs) printf("EIP: %04x:[<%08lx>] EFLAGS: %08lx\n", (u16)cs, eip, eflags); + if (gd->flags & GD_FLG_RELOC) + printf("Original EIP :[<%08lx>]\n", eip - gd->reloc_off); printf("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", regs->eax, regs->ebx, regs->ecx, regs->edx); diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c index 97dd000..35b29f6 100644 --- a/arch/x86/cpu/irq.c +++ b/arch/x86/cpu/irq.c @@ -125,10 +125,10 @@ static int create_pirq_routing_table(void) return -EINVAL; } - ret = fdtdec_get_int_array(blob, node, "intel,pirq-link", - &irq_router.link_base, 1); - if (ret) + ret = fdtdec_get_int(blob, node, "intel,pirq-link", -1); + if (ret == -1) return ret; + irq_router.link_base = ret; irq_router.irq_mask = fdtdec_get_int(blob, node, "intel,pirq-mask", PIRQ_BITMAP); @@ -156,18 +156,13 @@ static int create_pirq_routing_table(void) } 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 + if (!cell || len % sizeof(struct pirq_routing)) return -EINVAL; + count = len / sizeof(struct pirq_routing); - rt = malloc(sizeof(struct irq_routing_table)); + rt = calloc(1, 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; @@ -181,7 +176,8 @@ static int create_pirq_routing_table(void) slot_base = rt->slots; /* Now fill in the irq_info entries in the PIRQ table */ - for (i = 0; i < count; i++) { + for (i = 0; i < count; + i++, cell += sizeof(struct pirq_routing) / sizeof(u32)) { struct pirq_routing pr; pr.bdf = fdt_addr_to_cpu(cell[0]); @@ -212,25 +208,14 @@ static int create_pirq_routing_table(void) 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; } + } else { + slot = slot_base + irq_entries++; } - - 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); + 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); } rt->size = irq_entries * sizeof(struct irq_info) + 32; @@ -240,17 +225,22 @@ static int create_pirq_routing_table(void) return 0; } -void pirq_init(void) +int pirq_init(void) { + int ret; + cpu_irq_init(); - if (create_pirq_routing_table()) { + ret = create_pirq_routing_table(); + if (ret) { 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)); + return ret; } + /* Route PIRQ */ + pirq_route_irqs(pirq_routing_table->slots, + get_irq_slot_count(pirq_routing_table)); + + return 0; } u32 write_pirq_routing_table(u32 addr) diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 3294a50..4334f5b 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -515,5 +515,12 @@ int mp_init(struct mp_params *p) int mp_init_cpu(struct udevice *cpu, void *unused) { + /* + * Multiple APs are brought up simultaneously and they may get the same + * seq num in the uclass_resolve_seq() during device_probe(). To avoid + * this, set req_seq to the reg number in the device tree in advance. + */ + cpu->req_seq = fdtdec_get_int(gd->fdt_blob, cpu->of_offset, "reg", -1); + return device_probe(cpu); } diff --git a/arch/x86/cpu/pci.c b/arch/x86/cpu/pci.c index f8da080..d2ec45a 100644 --- a/arch/x86/cpu/pci.c +++ b/arch/x86/cpu/pci.c @@ -76,7 +76,8 @@ unsigned int x86_pci_read_config8(pci_dev_t dev, unsigned where) { uint8_t value; - pci_hose_read_config_byte(get_hose(), dev, where, &value); + if (pci_hose_read_config_byte(get_hose(), dev, where, &value)) + return -1U; return value; } @@ -85,7 +86,8 @@ unsigned int x86_pci_read_config16(pci_dev_t dev, unsigned where) { uint16_t value; - pci_hose_read_config_word(get_hose(), dev, where, &value); + if (pci_hose_read_config_word(get_hose(), dev, where, &value)) + return -1U; return value; } @@ -94,7 +96,8 @@ unsigned int x86_pci_read_config32(pci_dev_t dev, unsigned where) { uint32_t value; - pci_hose_read_config_dword(get_hose(), dev, where, &value); + if (pci_hose_read_config_dword(get_hose(), dev, where, &value)) + return -1U; return value; } diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c index 64634a9..7c03e02 100644 --- a/arch/x86/cpu/qemu/qemu.c +++ b/arch/x86/cpu/qemu/qemu.c @@ -41,7 +41,5 @@ void reset_cpu(ulong addr) int arch_misc_init(void) { - pirq_init(); - - return 0; + return pirq_init(); } diff --git a/arch/x86/cpu/quark/quark.c b/arch/x86/cpu/quark/quark.c index 20cc09e..12ac376 100644 --- a/arch/x86/cpu/quark/quark.c +++ b/arch/x86/cpu/quark/quark.c @@ -174,7 +174,5 @@ void cpu_irq_init(void) int arch_misc_init(void) { - pirq_init(); - - return 0; + return pirq_init(); } diff --git a/arch/x86/cpu/queensbay/tnc.c b/arch/x86/cpu/queensbay/tnc.c index de50893..c465642 100644 --- a/arch/x86/cpu/queensbay/tnc.c +++ b/arch/x86/cpu/queensbay/tnc.c @@ -80,7 +80,5 @@ void cpu_irq_init(void) int arch_misc_init(void) { - pirq_init(); - - return 0; + return pirq_init(); } diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 313fa3f..e94ddc4 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -104,8 +104,7 @@ car_init_ret: * * top-> CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE * MRC area - * global_data - * x86 global descriptor table + * global_data with x86 global descriptor table * early malloc area * stack * bottom-> CONFIG_SYS_CAR_ADDR @@ -120,13 +119,10 @@ car_init_ret: * and esi holds the HOB list address returned by the FSP. */ #endif - - /* Reserve space on stack for global data */ - subl $GENERATED_GBL_DATA_SIZE, %esp - - /* Align global data to 16-byte boundary */ - andl $0xfffffff0, %esp - post_code(POST_START_STACK) + /* Set up global data */ + mov %esp, %eax + call board_init_f_mem + mov %eax, %esp /* * Debug UART is available here although it may not be plumbed out @@ -137,56 +133,21 @@ car_init_ret: * call printch */ - /* Zero the global data since it won't happen later */ - xorl %eax, %eax - movl $GENERATED_GBL_DATA_SIZE, %ecx - movl %esp, %edi - rep stosb - + /* Get address of global_data */ + mov %fs:0, %edx #ifdef CONFIG_HAVE_FSP + /* Store the HOB list if we have one */ test %esi, %esi jz skip_hob - - /* Store HOB list */ - movl %esp, %edx - addl $GD_HOB_LIST, %edx - movl %esi, (%edx) + movl %esi, GD_HOB_LIST(%edx) skip_hob: #else /* Store table pointer */ - movl %esp, %edx - addl $GD_TABLE, %edx - movl %esi, (%edx) + movl %esi, GD_TABLE(%edx) #endif - - /* Setup first parameter to setup_gdt, pointer to global_data */ - movl %esp, %eax - - /* Reserve space for global descriptor table */ - subl $X86_GDT_SIZE, %esp - - /* Align temporary global descriptor table to 16-byte boundary */ - andl $0xfffffff0, %esp - movl %esp, %ecx - -#if defined(CONFIG_SYS_MALLOC_F_LEN) - /* Set up the pre-relocation malloc pool */ - subl $CONFIG_SYS_MALLOC_F_LEN, %esp - movl %eax, %edx - addl $GD_MALLOC_BASE, %edx - movl %esp, (%edx) -#endif - /* Store BIST into global_data */ - movl %eax, %edx - addl $GD_BIST, %edx - movl %ebp, (%edx) - - /* Set second parameter to setup_gdt() */ - movl %ecx, %edx - - /* Setup global descriptor table so gd->xyz works */ - call setup_gdt + /* Store BIST */ + movl %ebp, GD_BIST(%edx) /* Set parameter to board_init_f() to boot flags */ post_code(POST_START_DONE) @@ -213,37 +174,7 @@ board_init_f_r_trampoline: /* Stack grows down from top of SDRAM */ movl %eax, %esp - /* Reserve space on stack for global data */ - subl $GENERATED_GBL_DATA_SIZE, %esp - - /* Align global data to 16-byte boundary */ - andl $0xfffffff0, %esp - - /* Setup first parameter to memcpy() and setup_gdt() */ - movl %esp, %eax - - /* Setup second parameter to memcpy() */ - fs movl 0, %edx - - /* Set third parameter to memcpy() */ - movl $GENERATED_GBL_DATA_SIZE, %ecx - - /* Copy global data from CAR to SDRAM stack */ - call memcpy - - /* Reserve space for global descriptor table */ - subl $X86_GDT_SIZE, %esp - - /* Align global descriptor table to 16-byte boundary */ - andl $0xfffffff0, %esp - - /* Set second parameter to setup_gdt() */ - movl %esp, %edx - - /* Setup global descriptor table so gd->xyz works */ - call setup_gdt - - /* Set if we need to disable CAR */ + /* See if we need to disable CAR */ .weak car_uninit movl $car_uninit, %eax cmpl $0, %eax diff --git a/arch/x86/dts/bayleybay.dts b/arch/x86/dts/bayleybay.dts index 9f8fa70..8f0e192 100644 --- a/arch/x86/dts/bayleybay.dts +++ b/arch/x86/dts/bayleybay.dts @@ -188,6 +188,44 @@ }; }; + fsp { + compatible = "intel,baytrail-fsp"; + fsp,mrc-init-tseg-size = <0>; + fsp,mrc-init-mmio-size = <0x800>; + fsp,mrc-init-spd-addr1 = <0xa0>; + fsp,mrc-init-spd-addr2 = <0xa2>; + fsp,emmc-boot-mode = <2>; + fsp,enable-sdio; + fsp,enable-sdcard; + fsp,enable-hsuart1; + fsp,enable-spi; + fsp,enable-sata; + fsp,sata-mode = <1>; + fsp,enable-lpe; + fsp,lpss-sio-enable-pci-mode; + fsp,enable-dma0; + fsp,enable-dma1; + fsp,enable-i2c0; + fsp,enable-i2c1; + fsp,enable-i2c2; + fsp,enable-i2c3; + fsp,enable-i2c4; + fsp,enable-i2c5; + fsp,enable-i2c6; + fsp,enable-pwm0; + fsp,enable-pwm1; + fsp,igd-dvmt50-pre-alloc = <2>; + fsp,aperture-size = <2>; + fsp,gtt-size = <2>; + fsp,serial-debug-port-address = <0x3f8>; + fsp,serial-debug-port-type = <1>; + fsp,scc-enable-pci-mode; + fsp,os-selection = <4>; + fsp,emmc45-ddr50-enabled; + fsp,emmc45-retune-timer-value = <8>; + fsp,enable-igd; + }; + microcode { update@0 { #include "microcode/m0230671117.dtsi" diff --git a/arch/x86/dts/minnowmax.dts b/arch/x86/dts/minnowmax.dts index 9527233..daac24e 100644 --- a/arch/x86/dts/minnowmax.dts +++ b/arch/x86/dts/minnowmax.dts @@ -7,6 +7,7 @@ /dts-v1/; #include <dt-bindings/gpio/x86-gpio.h> +#include <dt-bindings/interrupt-router/intel-irq.h> /include/ "skeleton.dtsi" /include/ "serial.dtsi" @@ -117,9 +118,127 @@ #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>; + ranges = <0x02000000 0x0 0x80000000 0x80000000 0 0x40000000 + 0x42000000 0x0 0xc0000000 0xc0000000 0 0x20000000 + 0x01000000 0x0 0x2000 0x2000 0 0xe000>; + + irq-router@1f,0 { + reg = <0x0000f800 0 0 0 0>; + compatible = "intel,irq-router"; + intel,pirq-config = "ibase"; + intel,ibase-offset = <0x50>; + intel,pirq-link = <8 8>; + intel,pirq-mask = <0xdee0>; + intel,pirq-routing = < + /* BayTrail PCI devices */ + PCI_BDF(0, 2, 0) INTA PIRQA + PCI_BDF(0, 3, 0) INTA PIRQA + PCI_BDF(0, 16, 0) INTA PIRQA + PCI_BDF(0, 17, 0) INTA PIRQA + PCI_BDF(0, 18, 0) INTA PIRQA + PCI_BDF(0, 19, 0) INTA PIRQA + PCI_BDF(0, 20, 0) INTA PIRQA + PCI_BDF(0, 21, 0) INTA PIRQA + PCI_BDF(0, 22, 0) INTA PIRQA + PCI_BDF(0, 23, 0) INTA PIRQA + PCI_BDF(0, 24, 0) INTA PIRQA + PCI_BDF(0, 24, 1) INTC PIRQC + PCI_BDF(0, 24, 2) INTD PIRQD + PCI_BDF(0, 24, 3) INTB PIRQB + PCI_BDF(0, 24, 4) INTA PIRQA + PCI_BDF(0, 24, 5) INTC PIRQC + PCI_BDF(0, 24, 6) INTD PIRQD + PCI_BDF(0, 24, 7) INTB PIRQB + PCI_BDF(0, 26, 0) INTA PIRQA + PCI_BDF(0, 27, 0) INTA PIRQA + PCI_BDF(0, 28, 0) INTA PIRQA + PCI_BDF(0, 28, 1) INTB PIRQB + PCI_BDF(0, 28, 2) INTC PIRQC + PCI_BDF(0, 28, 3) INTD PIRQD + PCI_BDF(0, 29, 0) INTA PIRQA + PCI_BDF(0, 30, 0) INTA PIRQA + PCI_BDF(0, 30, 1) INTD PIRQD + PCI_BDF(0, 30, 2) INTB PIRQB + PCI_BDF(0, 30, 3) INTC PIRQC + PCI_BDF(0, 30, 4) INTD PIRQD + PCI_BDF(0, 30, 5) INTB PIRQB + PCI_BDF(0, 31, 3) INTB PIRQB + + /* PCIe root ports downstream interrupts */ + PCI_BDF(1, 0, 0) INTA PIRQA + PCI_BDF(1, 0, 0) INTB PIRQB + PCI_BDF(1, 0, 0) INTC PIRQC + PCI_BDF(1, 0, 0) INTD PIRQD + PCI_BDF(2, 0, 0) INTA PIRQB + PCI_BDF(2, 0, 0) INTB PIRQC + PCI_BDF(2, 0, 0) INTC PIRQD + PCI_BDF(2, 0, 0) INTD PIRQA + PCI_BDF(3, 0, 0) INTA PIRQC + PCI_BDF(3, 0, 0) INTB PIRQD + PCI_BDF(3, 0, 0) INTC PIRQA + PCI_BDF(3, 0, 0) INTD PIRQB + PCI_BDF(4, 0, 0) INTA PIRQD + PCI_BDF(4, 0, 0) INTB PIRQA + PCI_BDF(4, 0, 0) INTC PIRQB + PCI_BDF(4, 0, 0) INTD PIRQC + >; + }; + }; + + fsp { + compatible = "intel,baytrail-fsp"; + fsp,mrc-init-tseg-size = <0>; + fsp,mrc-init-mmio-size = <0x800>; + fsp,mrc-init-spd-addr1 = <0xa0>; + fsp,mrc-init-spd-addr2 = <0xa2>; + fsp,emmc-boot-mode = <2>; + fsp,enable-sdio; + fsp,enable-sdcard; + fsp,enable-hsuart1; + fsp,enable-spi; + fsp,enable-sata; + fsp,sata-mode = <1>; + fsp,enable-lpe; + fsp,lpss-sio-enable-pci-mode; + fsp,enable-dma0; + fsp,enable-dma1; + fsp,enable-i2c0; + fsp,enable-i2c1; + fsp,enable-i2c2; + fsp,enable-i2c3; + fsp,enable-i2c4; + fsp,enable-i2c5; + fsp,enable-i2c6; + fsp,enable-pwm0; + fsp,enable-pwm1; + fsp,igd-dvmt50-pre-alloc = <2>; + fsp,aperture-size = <2>; + fsp,gtt-size = <2>; + fsp,serial-debug-port-address = <0x3f8>; + fsp,serial-debug-port-type = <1>; + fsp,scc-enable-pci-mode; + fsp,os-selection = <4>; + fsp,emmc45-ddr50-enabled; + fsp,emmc45-retune-timer-value = <8>; + fsp,enable-igd; + fsp,enable-memory-down; + fsp,memory-down-params { + compatible = "intel,baytrail-fsp-mdp"; + fsp,dram-speed = <1>; + fsp,dram-type = <1>; + fsp,dimm-0-enable; + fsp,dimm-width = <1>; + fsp,dimm-density = <2>; + fsp,dimm-bus-width = <3>; + fsp,dimm-sides = <0>; + fsp,dimm-tcl = <0xb>; + fsp,dimm-trpt-rcd = <0xb>; + fsp,dimm-twr = <0xc>; + fsp,dimm-twtr = <6>; + fsp,dimm-trrd = <6>; + fsp,dimm-trtp = <6>; + fsp,dimm-tfaw = <0x14>; + }; }; spi { diff --git a/arch/x86/include/asm/arch-baytrail/fsp/fsp_vpd.h b/arch/x86/include/asm/arch-baytrail/fsp/fsp_vpd.h index eb0d506..3c782a8 100644 --- a/arch/x86/include/asm/arch-baytrail/fsp/fsp_vpd.h +++ b/arch/x86/include/asm/arch-baytrail/fsp/fsp_vpd.h @@ -82,7 +82,6 @@ struct __packed upd_region { }; #define VPD_IMAGE_ID 0x3157454956594C56 /* 'VLYVIEW1' */ -#define VPD_IMAGE_REV 0x00000303 struct __packed vpd_region { uint64_t sign; /* Offset 0x0000 */ diff --git a/arch/x86/include/asm/arch-queensbay/fsp/fsp_vpd.h b/arch/x86/include/asm/arch-queensbay/fsp/fsp_vpd.h index 3c57558..9c54ecc 100644 --- a/arch/x86/include/asm/arch-queensbay/fsp/fsp_vpd.h +++ b/arch/x86/include/asm/arch-queensbay/fsp/fsp_vpd.h @@ -35,7 +35,6 @@ struct __packed upd_region { }; #define VPD_IMAGE_ID 0x445056574F4E4E4D /* 'MNNOWVPD' */ -#define VPD_IMAGE_REV 0x00000301 struct __packed vpd_region { u64 sign; /* Offset 0x0000 */ diff --git a/arch/x86/include/asm/fsp/fsp_support.h b/arch/x86/include/asm/fsp/fsp_support.h index c6c7dc0..7317dda 100644 --- a/arch/x86/include/asm/fsp/fsp_support.h +++ b/arch/x86/include/asm/fsp/fsp_support.h @@ -207,4 +207,11 @@ void *fsp_get_bootloader_tmp_mem(const void *hob_list, u32 *len); */ void update_fsp_upd(struct upd_region *fsp_upd); +/** + * fsp_init_phase_pci() - Tell the FSP that we have completed PCI init + * + * @return 0 if OK, -EPERM if the FSP gave an error. + */ +int fsp_init_phase_pci(void); + #endif diff --git a/arch/x86/include/asm/fsp/fsp_types.h b/arch/x86/include/asm/fsp/fsp_types.h index f32d827..4fe69f2 100644 --- a/arch/x86/include/asm/fsp/fsp_types.h +++ b/arch/x86/include/asm/fsp/fsp_types.h @@ -68,15 +68,4 @@ struct efi_guid { #define SIGNATURE_64(A, B, C, D, E, F, G, H) \ (SIGNATURE_32(A, B, C, D) | ((u64)(SIGNATURE_32(E, F, G, H)) << 32)) -/* - * Define FSP API return status code. - * Compatiable with EFI_STATUS defined in PI Spec. - */ -#define FSP_SUCCESS 0 -#define FSP_INVALID_PARAM 0x80000002 -#define FSP_UNSUPPORTED 0x80000003 -#define FSP_DEVICE_ERROR 0x80000007 -#define FSP_NOT_FOUND 0x8000000E -#define FSP_ALREADY_STARTED 0x80000014 - #endif diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index f7e3889..35148ab 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -10,6 +10,8 @@ #ifndef __ASSEMBLY__ +#include <asm/processor.h> + enum pei_boot_mode_t { PEI_BOOT_NONE = 0, PEI_BOOT_SOFT_RESET, @@ -44,6 +46,7 @@ struct mtrr_request { /* Architecture-specific global data */ struct arch_global_data { + u64 gdt[X86_GDT_NUM_ENTRIES] __aligned(16); struct global_data *gd_addr; /* Location of Global Data */ uint8_t x86; /* CPU family */ uint8_t x86_vendor; /* CPU vendor */ @@ -68,7 +71,6 @@ struct arch_global_data { /* MRC training data to save for the next boot */ char *mrc_output; unsigned int mrc_output_len; - void *gdt; /* Global descriptor table */ ulong table; /* Table pointer from previous loader */ }; diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h index 4de5512..6697da3 100644 --- a/arch/x86/include/asm/irq.h +++ b/arch/x86/include/asm/irq.h @@ -70,7 +70,9 @@ void cpu_irq_init(void); * * This initializes the PIRQ routing on the platform and configures all PCI * devices' interrupt line register to a working IRQ number on the 8259 PIC. + * + * @return 0 if OK, -ve on error */ -void pirq_init(void); +int pirq_init(void); #endif /* _ARCH_IRQ_H_ */ diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index 4dae365..1c459d5 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -14,7 +14,6 @@ extern char gdt_rom[]; 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 diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index c585710..d564cb9 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -19,19 +19,24 @@ int print_cpuinfo(void) return default_print_cpuinfo(); } -int board_pci_post_scan(struct pci_controller *hose) +int fsp_init_phase_pci(void) { u32 status; /* call into FspNotify */ debug("Calling into FSP (notify phase INIT_PHASE_PCI): "); status = fsp_notify(NULL, INIT_PHASE_PCI); - if (status != FSP_SUCCESS) + if (status) debug("fail, error code %x\n", status); else debug("OK\n"); - return 0; + return status ? -EPERM : 0; +} + +int board_pci_post_scan(struct pci_controller *hose) +{ + return fsp_init_phase_pci(); } void board_final_cleanup(void) @@ -41,7 +46,7 @@ void board_final_cleanup(void) /* call into FspNotify */ debug("Calling into FSP (notify phase INIT_PHASE_BOOT): "); status = fsp_notify(NULL, INIT_PHASE_BOOT); - if (status != FSP_SUCCESS) + if (status) debug("fail, error code %x\n", status); else debug("OK\n"); diff --git a/arch/x86/lib/fsp/fsp_support.c b/arch/x86/lib/fsp/fsp_support.c index 4585166..1d48ff4 100644 --- a/arch/x86/lib/fsp/fsp_support.c +++ b/arch/x86/lib/fsp/fsp_support.c @@ -147,8 +147,7 @@ void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf) fsp_hdr->cfg_region_off); /* Verify the VPD data region is valid */ - assert((fsp_vpd->img_rev == VPD_IMAGE_REV) && - (fsp_vpd->sign == VPD_IMAGE_ID)); + assert(fsp_vpd->sign == VPD_IMAGE_ID); /* Copy default data from Flash */ memcpy(fsp_upd, (void *)(fsp_hdr->img_base + fsp_vpd->upd_offset), diff --git a/board/intel/minnowmax/minnowmax.c b/board/intel/minnowmax/minnowmax.c index c4f2c33..44e5bf4 100644 --- a/board/intel/minnowmax/minnowmax.c +++ b/board/intel/minnowmax/minnowmax.c @@ -6,7 +6,6 @@ #include <common.h> #include <asm/gpio.h> -#include <netdev.h> int arch_early_init_r(void) { @@ -20,8 +19,3 @@ void setup_pch_gpios(u16 gpiobase, const struct pch_gpio_map *gpio) { return; } - -int board_eth_init(bd_t *bis) -{ - return pci_eth_init(bis); -} diff --git a/common/board_f.c b/common/board_f.c index c7cc67c..c959774 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -206,7 +206,8 @@ static int show_dram_config(void) debug("\nRAM Configuration:\n"); for (i = size = 0; i < CONFIG_NR_DRAM_BANKS; i++) { size += gd->bd->bi_dram[i].size; - debug("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start); + debug("Bank #%d: %llx ", i, + (unsigned long long)(gd->bd->bi_dram[i].start)); #ifdef DEBUG print_size(gd->bd->bi_dram[i].size, "\n"); #endif @@ -498,6 +499,7 @@ static int setup_machine(void) static int reserve_global_data(void) { gd->start_addr_sp -= sizeof(gd_t); + gd->start_addr_sp &= ~0xf; gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t)); debug("Reserving %zu Bytes for Global Data at: %08lx\n", sizeof(gd_t), gd->start_addr_sp); @@ -713,6 +715,7 @@ static int jump_to_copy(void) * with the stack in SDRAM and Global Data in temporary memory * (CPU cache) */ + arch_setup_gd(gd->new_gd); board_init_f_r_trampoline(gd->start_addr_sp); #else relocate_code(gd->start_addr_sp, gd->new_gd, gd->relocaddr); @@ -1025,16 +1028,26 @@ void board_init_f_r(void) } #endif /* CONFIG_X86 */ +/* Unfortunately x86 can't compile this code as gd cannot be assigned */ #ifndef CONFIG_X86 +__weak void arch_setup_gd(struct global_data *gd_ptr) +{ + gd = gd_ptr; +} +#endif /* !CONFIG_X86 */ + ulong board_init_f_mem(ulong top) { + struct global_data *gd_ptr; + /* Leave space for the stack we are running with now */ top -= 0x40; top -= sizeof(struct global_data); top = ALIGN(top, 16); - gd = (struct global_data *)top; - memset((void *)gd, '\0', sizeof(*gd)); + gd_ptr = (struct global_data *)top; + memset(gd_ptr, '\0', sizeof(*gd)); + arch_setup_gd(gd_ptr); #ifdef CONFIG_SYS_MALLOC_F_LEN top -= CONFIG_SYS_MALLOC_F_LEN; @@ -1043,4 +1056,3 @@ ulong board_init_f_mem(ulong top) return top; } -#endif /* !CONFIG_X86 */ diff --git a/configs/efi-x86_defconfig b/configs/efi-x86_defconfig index 1aa0655..43fb0c4 100644 --- a/configs/efi-x86_defconfig +++ b/configs/efi-x86_defconfig @@ -1,16 +1,16 @@ CONFIG_X86=y CONFIG_VENDOR_EFI=y +CONFIG_DEFAULT_DEVICE_TREE="efi" CONFIG_TARGET_EFI=y CONFIG_TSC_CALIBRATION_BYPASS=y +# CONFIG_CMD_BOOTM is not set +# CONFIG_CMD_NET is not set CONFIG_OF_CONTROL=y CONFIG_OF_EMBED=y CONFIG_DM_PCI=y -CONFIG_DEFAULT_DEVICE_TREE="efi" -CONFIG_EFI=y -CONFIG_EFI_APP=y CONFIG_DEBUG_UART=y CONFIG_DEBUG_EFI_CONSOLE=y CONFIG_DEBUG_UART_BASE=0 CONFIG_DEBUG_UART_CLOCK=0 -# CONFIG_CMD_NET is not set -# CONFIG_CMD_BOOTM is not set +# CONFIG_X86_SERIAL is not set +CONFIG_EFI=y diff --git a/configs/minnowmax_defconfig b/configs/minnowmax_defconfig index a67597d..f3cf91b 100644 --- a/configs/minnowmax_defconfig +++ b/configs/minnowmax_defconfig @@ -5,7 +5,8 @@ CONFIG_TARGET_MINNOWMAX=y CONFIG_HAVE_INTEL_ME=y CONFIG_SMP=y CONFIG_HAVE_VGA_BIOS=y -CONFIG_GENERATE_SFI_TABLE=y +CONFIG_GENERATE_PIRQ_TABLE=y +CONFIG_GENERATE_MP_TABLE=y CONFIG_CMD_CPU=y # CONFIG_CMD_IMLS is not set # CONFIG_CMD_FLASH is not set @@ -18,13 +19,15 @@ CONFIG_OF_CONTROL=y CONFIG_CPU=y CONFIG_DM_PCI=y CONFIG_SPI_FLASH=y +CONFIG_DM_ETH=y +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_BASE=0x3f8 +CONFIG_DEBUG_UART_CLOCK=1843200 CONFIG_VIDEO_VESA=y CONFIG_FRAMEBUFFER_SET_VESA_MODE=y CONFIG_FRAMEBUFFER_VESA_MODE_11A=y +CONFIG_USB=y +CONFIG_DM_USB=y CONFIG_DM_RTC=y CONFIG_USE_PRIVATE_LIBGCC=y CONFIG_SYS_VSNPRINTF=y -CONFIG_DEBUG_UART=y -CONFIG_DEBUG_UART_NS16550=y -CONFIG_DEBUG_UART_BASE=0x3f8 -CONFIG_DEBUG_UART_CLOCK=1843200 diff --git a/doc/README.x86 b/doc/README.x86 index af2459c..e7dc090 100644 --- a/doc/README.x86 +++ b/doc/README.x86 @@ -18,15 +18,16 @@ U-Boot supports running as a coreboot [1] payload on x86. So far only Link work with minimal adjustments on other x86 boards since coreboot deals with most of the low-level details. -U-Boot also supports booting directly from x86 reset vector without coreboot, -aka raw support or bare support. Currently Link, QEMU x86 targets and all -Intel boards support running U-Boot 'bare metal'. +U-Boot also supports booting directly from x86 reset vector, without coreboot. +In this case, known as bare mode, from the fact that it runs on the +'bare metal', U-Boot acts like a BIOS replacement. Currently Link, QEMU x86 +targets and all Intel boards support running U-Boot 'bare metal'. As for loading an OS, U-Boot supports directly booting a 32-bit or 64-bit Linux kernel as part of a FIT image. It also supports a compressed zImage. -Build Instructions ------------------- +Build Instructions for U-Boot as coreboot payload +------------------------------------------------- Building U-Boot as a coreboot payload is just like building U-Boot for targets on other architectures, like below: @@ -48,6 +49,8 @@ Change the 'Board configuration file' and 'Board Device Tree Source (dts) file' to point to a new board. You can also change the Cache-As-RAM (CAR) related settings here if the default values do not fit your new board. +Build Instructions for U-Boot as BIOS replacement (bare mode) +------------------------------------------------------------- Building a ROM version of U-Boot (hereafter referred to as u-boot.rom) is a little bit tricky, as generally it requires several binary blobs which are not shipped in the U-Boot source tree. Due to this reason, the u-boot.rom build is @@ -58,7 +61,9 @@ $ export BUILD_ROM=y This tells the Makefile to build u-boot.rom as a target. -Link-specific instructions: +--- + +Chromebook Link specific instructions for bare mode: First, you need the following binary blobs: @@ -87,7 +92,9 @@ Now you can build U-Boot and obtain u-boot.rom: $ make chromebook_link_defconfig $ make all -Intel Crown Bay specific instructions: +--- + +Intel Crown Bay specific instructions for bare mode: U-Boot support of Intel Crown Bay board [4] relies on a binary blob called Firmware Support Package [5] to perform all the necessary initialization steps @@ -122,7 +129,9 @@ Now you can build U-Boot and obtain u-boot.rom $ make crownbay_defconfig $ make all -Intel Minnowboard Max instructions: +--- + +Intel Minnowboard Max instructions for bare mode: This uses as FSP as with Crown Bay, except it is for the Atom E3800 series. Download this and get the .fd file (BAYTRAIL_FSP_GOLD_003_16-SEP-2014.fd at @@ -188,8 +197,9 @@ Offset Description Controlling config Overall ROM image size is controlled by CONFIG_ROM_SIZE. +--- -Intel Galileo instructions: +Intel Galileo instructions for bare mode: Only one binary blob is needed for Remote Management Unit (RMU) within Intel Quark SoC. Not like FSP, U-Boot does not call into the binary. The binary is @@ -252,8 +262,8 @@ At present it seems that for Minnowboard Max, coreboot does not pass through the video information correctly (it always says the resolution is 0x0). This works correctly for link though. -Test with QEMU --------------- +Test with QEMU for bare mode +---------------------------- QEMU is a fancy emulator that can enable us to test U-Boot without access to a real x86 board. Please make sure your QEMU version is 2.3.0 or above test U-Boot. To launch QEMU with u-boot.rom, call QEMU as follows: @@ -708,6 +718,21 @@ allocation and assignment will be done by U-Boot automatically. Now you can enable CONFIG_GENERATE_PIRQ_TABLE for testing Linux kernel using i8259 PIC and CONFIG_GENERATE_MP_TABLE for testing Linux kernel using local APIC and I/O APIC. +This script might be useful. If you feed it the output of 'pci long' from +U-Boot then it will generate a device tree fragment with the interrupt +configuration for each device (note it needs gawk 4.0.0): + + $ cat console_output |awk '/PCI/ {device=$4} /interrupt line/ {line=$4} \ + /interrupt pin/ {pin = $4; if (pin != "0x00" && pin != "0xff") \ + {patsplit(device, bdf, "[0-9a-f]+"); \ + printf "PCI_BDF(%d, %d, %d) INT%c PIRQ%c\n", strtonum("0x" bdf[1]), \ + strtonum("0x" bdf[2]), bdf[3], strtonum(pin) + 64, 64 + strtonum(pin)}}' + +Example output: + PCI_BDF(0, 2, 0) INTA PIRQA + PCI_BDF(0, 3, 0) INTA PIRQA +... + TODO List --------- - Audio diff --git a/doc/device-tree-bindings/misc/intel,baytrail-fsp.txt b/doc/device-tree-bindings/misc/intel,baytrail-fsp.txt new file mode 100644 index 0000000..b44b5b5 --- /dev/null +++ b/doc/device-tree-bindings/misc/intel,baytrail-fsp.txt @@ -0,0 +1,158 @@ +Intel Bay Trail FSP UPD Binding +=============================== + +The device tree node which describes the overriding of the Intel Bay Trail FSP +UPD data for configuring the SoC. + +All properties can be found within the `upd-region` struct in +arch/x86/include/asm/arch-baytrail/fsp/fsp_vpd.h, under the same names, and in +Intel's FSP Binary Configuration Tool for Bay Trail. This list of properties is +matched up to Intel's E3800 FSPv4 release. + +# Boolean properties: + +- fsp,enable-sdio +- fsp,enable-sdcard +- fsp,enable-hsuart0 +- fsp,enable-hsuart1 +- fsp,enable-spi +- fsp,enable-sata +- fsp,enable-azalia +- fsp,enable-xhci +- fsp,enable-lpe +- fsp,lpss-sio-enable-pci-mode +- fsp,enable-dma0 +- fsp,enable-dma1 +- fsp,enable-i2-c0 +- fsp,enable-i2-c1 +- fsp,enable-i2-c2 +- fsp,enable-i2-c3 +- fsp,enable-i2-c4 +- fsp,enable-i2-c5 +- fsp,enable-i2-c6 +- fsp,enable-pwm0 +- fsp,enable-pwm1 +- fsp,enable-hsi +- fsp,mrc-debug-msg +- fsp,isp-enable +- fsp,scc-enable-pci-mode +- fsp,igd-render-standby +- fsp,txe-uma-enable +- fsp,emmc45-ddr50-enabled +- fsp,emmc45-hs200-enabled +- fsp,enable-igd +- fsp,enable-memory-down + +If you set "fsp,enable-memory-down" you are strongly encouraged to provide an +"fsp,memory-down-params{};" to specify how your memory is configured. If you do +not set "fsp,enable-memory-down", then the DIMM SPD information will be +discovered by the FSP and used to setup main memory. + + +# Integer properties: + +- fsp,mrc-init-tseg-size +- fsp,mrc-init-mmio-size +- fsp,mrc-init-spd-addr1 +- fsp,mrc-init-spd-addr2 +- fsp,emmc-boot-mode +- fsp,sata-mode +- fsp,igd-dvmt50-pre-alloc +- fsp,aperture-size +- fsp,gtt-size +- fsp,serial-debug-port-address +- fsp,serial-debug-port-type +- fsp,os-selection +- fsp,emmc45-retune-timer-value + +- fsp,memory-down-params { + + # Boolean properties: + + - fsp,dimm-0-enable + - fsp,dimm-1-enable + + # Integer properties: + + - fsp,dram-speed + - fsp,dram-type + - fsp,dimm-width + - fsp,dimm-density + - fsp,dimm-bus-width + - fsp,dimm-sides + - fsp,dimm-tcl + - fsp,dimm-trpt-rcd + - fsp,dimm-twr + - fsp,dimm-twtr + - fsp,dimm-trrd + - fsp,dimm-trtp + - fsp,dimm-tfaw +}; + + +Example (from MinnowMax Dual Core): +----------------------------------- + +/ { + ... + + fsp { + compatible = "intel,baytrail-fsp"; + fsp,mrc-init-tseg-size = <0>; + fsp,mrc-init-mmio-size = <0x800>; + fsp,mrc-init-spd-addr1 = <0xa0>; + fsp,mrc-init-spd-addr2 = <0xa2>; + fsp,emmc-boot-mode = <2>; + fsp,enable-sdio; + fsp,enable-sdcard; + fsp,enable-hsuart1; + fsp,enable-spi; + fsp,enable-sata; + fsp,sata-mode = <1>; + fsp,enable-xhci; + fsp,enable-lpe; + fsp,lpss-sio-enable-pci-mode; + fsp,enable-dma0; + fsp,enable-dma1; + fsp,enable-i2c0; + fsp,enable-i2c1; + fsp,enable-i2c2; + fsp,enable-i2c3; + fsp,enable-i2c4; + fsp,enable-i2c5; + fsp,enable-i2c6; + fsp,enable-pwm0; + fsp,enable-pwm1; + fsp,igd-dvmt50-pre-alloc = <2>; + fsp,aperture-size = <2>; + fsp,gtt-size = <2>; + fsp,serial-debug-port-address = <0x3f8>; + fsp,serial-debug-port-type = <1>; + fsp,mrc-debug-msg; + fsp,scc-enable-pci-mode; + fsp,os-selection = <4>; + fsp,emmc45-ddr50-enabled; + fsp,emmc45-retune-timer-value = <8>; + fsp,enable-igd; + fsp,enable-memory-down; + fsp,memory-down-params { + compatible = "intel,baytrail-fsp-mdp"; + fsp,dram-speed = <1>; + fsp,dram-type = <1>; + fsp,dimm-0-enable; + fsp,dimm-width = <1>; + fsp,dimm-density = <2>; + fsp,dimm-bus-width = <3>; + fsp,dimm-sides = <0>; + fsp,dimm-tcl = <0xb>; + fsp,dimm-trpt-rcd = <0xb>; + fsp,dimm-twr = <0xc>; + fsp,dimm-twtr = <6>; + fsp,dimm-trrd = <6>; + fsp,dimm-trtp = <6>; + fsp,dimm-tfaw = <0x14>; + }; + }; + + ... +}; diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 6262f35..7d41d56 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -210,6 +210,17 @@ int pci_write_config(pci_dev_t bdf, int offset, unsigned long value, return pci_bus_write_config(bus, bdf, offset, value, size); } +int dm_pci_write_config(struct udevice *dev, int offset, unsigned long value, + enum pci_size_t size) +{ + struct udevice *bus; + + for (bus = dev; device_get_uclass_id(bus->parent) == UCLASS_PCI;) + bus = bus->parent; + return pci_bus_write_config(bus, pci_get_bdf(dev), offset, value, size); +} + + int pci_write_config32(pci_dev_t bdf, int offset, u32 value) { return pci_write_config(bdf, offset, value, PCI_SIZE_32); @@ -225,6 +236,21 @@ int pci_write_config8(pci_dev_t bdf, int offset, u8 value) return pci_write_config(bdf, offset, value, PCI_SIZE_8); } +int dm_pci_write_config8(struct udevice *dev, int offset, u8 value) +{ + return dm_pci_write_config(dev, offset, value, PCI_SIZE_8); +} + +int dm_pci_write_config16(struct udevice *dev, int offset, u16 value) +{ + return dm_pci_write_config(dev, offset, value, PCI_SIZE_16); +} + +int dm_pci_write_config32(struct udevice *dev, int offset, u32 value) +{ + return dm_pci_write_config(dev, offset, value, PCI_SIZE_32); +} + int pci_bus_read_config(struct udevice *bus, pci_dev_t bdf, int offset, unsigned long *valuep, enum pci_size_t size) { @@ -249,6 +275,17 @@ int pci_read_config(pci_dev_t bdf, int offset, unsigned long *valuep, return pci_bus_read_config(bus, bdf, offset, valuep, size); } +int dm_pci_read_config(struct udevice *dev, int offset, unsigned long *valuep, + enum pci_size_t size) +{ + struct udevice *bus; + + for (bus = dev; device_get_uclass_id(bus->parent) == UCLASS_PCI;) + bus = bus->parent; + return pci_bus_read_config(bus, pci_get_bdf(dev), offset, valuep, + size); +} + int pci_read_config32(pci_dev_t bdf, int offset, u32 *valuep) { unsigned long value; @@ -288,6 +325,45 @@ int pci_read_config8(pci_dev_t bdf, int offset, u8 *valuep) return 0; } +int dm_pci_read_config8(struct udevice *dev, int offset, u8 *valuep) +{ + unsigned long value; + int ret; + + ret = dm_pci_read_config(dev, offset, &value, PCI_SIZE_8); + if (ret) + return ret; + *valuep = value; + + return 0; +} + +int dm_pci_read_config16(struct udevice *dev, int offset, u16 *valuep) +{ + unsigned long value; + int ret; + + ret = dm_pci_read_config(dev, offset, &value, PCI_SIZE_16); + if (ret) + return ret; + *valuep = value; + + return 0; +} + +int dm_pci_read_config32(struct udevice *dev, int offset, u32 *valuep) +{ + unsigned long value; + int ret; + + ret = dm_pci_read_config(dev, offset, &value, PCI_SIZE_32); + if (ret) + return ret; + *valuep = value; + + return 0; +} + int pci_auto_config_devices(struct udevice *bus) { struct pci_controller *hose = bus->uclass_priv; @@ -641,6 +717,10 @@ static int pci_uclass_post_probe(struct udevice *bus) { int ret; + /* Don't scan buses before relocation */ + if (!(gd->flags & GD_FLG_RELOC)) + return 0; + debug("%s: probing bus %d\n", __func__, bus->seq); ret = pci_bind_bus_devices(bus); if (ret) @@ -699,6 +779,66 @@ static int pci_bridge_write_config(struct udevice *bus, pci_dev_t bdf, return pci_bus_write_config(hose->ctlr, bdf, offset, value, size); } +static int skip_to_next_device(struct udevice *bus, struct udevice **devp) +{ + struct udevice *dev; + int ret = 0; + + /* + * Scan through all the PCI controllers. On x86 there will only be one + * but that is not necessarily true on other hardware. + */ + do { + device_find_first_child(bus, &dev); + if (dev) { + *devp = dev; + return 0; + } + ret = uclass_next_device(&bus); + if (ret) + return ret; + } while (bus); + + return 0; +} + +int pci_find_next_device(struct udevice **devp) +{ + struct udevice *child = *devp; + struct udevice *bus = child->parent; + int ret; + + /* First try all the siblings */ + *devp = NULL; + while (child) { + device_find_next_child(&child); + if (child) { + *devp = child; + return 0; + } + } + + /* We ran out of siblings. Try the next bus */ + ret = uclass_next_device(&bus); + if (ret) + return ret; + + return bus ? skip_to_next_device(bus, devp) : 0; +} + +int pci_find_first_device(struct udevice **devp) +{ + struct udevice *bus; + int ret; + + *devp = NULL; + ret = uclass_first_device(UCLASS_PCI, &bus); + if (ret) + return ret; + + return skip_to_next_device(bus, devp); +} + UCLASS_DRIVER(pci) = { .id = UCLASS_PCI, .name = "pci", diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 1dc082a..caf1efc 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -44,7 +44,7 @@ config FRAMEBUFFER_VESA_MODE_104 bool "1024x768 16-color" config FRAMEBUFFER_VESA_MODE_105 - bool "1024x7686 256-color" + bool "1024x768 256-color" config FRAMEBUFFER_VESA_MODE_106 bool "1280x1024 16-color" diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 2155265..cc369fc 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -99,7 +99,8 @@ typedef struct global_data { int pcidelay_done; #endif struct udevice *cur_serial_dev; /* current serial device */ - struct arch_global_data arch; /* architecture-specific data */ + /* arch-specific data */ + struct arch_global_data arch __attribute__((aligned(16))); } gd_t; #endif diff --git a/include/asm-generic/u-boot.h b/include/asm-generic/u-boot.h index c918049..9f3351d 100644 --- a/include/asm-generic/u-boot.h +++ b/include/asm-generic/u-boot.h @@ -130,8 +130,8 @@ typedef struct bd_info { ulong bi_boot_params; /* where this board expects params */ #ifdef CONFIG_NR_DRAM_BANKS struct { /* RAM configuration */ - ulong start; - ulong size; + phys_addr_t start; + phys_size_t size; } bi_dram[CONFIG_NR_DRAM_BANKS]; #endif /* CONFIG_NR_DRAM_BANKS */ } bd_t; diff --git a/include/common.h b/include/common.h index 5c076d6..c48e5bc 100644 --- a/include/common.h +++ b/include/common.h @@ -217,6 +217,49 @@ extern char console_buffer[]; /* arch/$(ARCH)/lib/board.c */ void board_init_f(ulong); void board_init_r(gd_t *, ulong) __attribute__ ((noreturn)); + +/** + * board_init_f_mem() - Allocate global data and set stack position + * + * This function is called by each architecture very early in the start-up + * code to set up the environment for board_init_f(). It allocates space for + * global_data (see include/asm-generic/global_data.h) and places the stack + * below this. + * + * This function requires a stack[1] Normally this is at @top. The function + * starts allocating space from 64 bytes below @top. First it creates space + * for global_data. Then it calls arch_setup_gd() which sets gd to point to + * the global_data space and can reserve additional bytes of space if + * required). Finally it allocates early malloc() memory + * (CONFIG_SYS_MALLOC_F_LEN). The new top of the stack is just below this, + * and it returned by this function. + * + * [1] Strictly speaking it would be possible to implement this function + * in C on many archs such that it does not require a stack. However this + * does not seem hugely important as only 64 byte are wasted. The 64 bytes + * are used to handle the calling standard which generally requires pushing + * addresses or registers onto the stack. We should be able to get away with + * less if this becomes important. + * + * @top: Top of available memory, also normally the top of the stack + * @return: New stack location + */ +ulong board_init_f_mem(ulong top); + +/** + * arch_setup_gd() - Set up the global_data pointer + * + * This pointer is special in some architectures and cannot easily be assigned + * to. For example on x86 it is implemented by adding a specific record to its + * Global Descriptor Table! So we we provide a function to carry out this task. + * For most architectures this can simply be: + * + * gd = gd_ptr; + * + * @gd_ptr: Pointer to global data + */ +void arch_setup_gd(gd_t *gd_ptr); + int checkboard(void); int show_board_info(void); int checkflash(void); diff --git a/include/configs/bayleybay.h b/include/configs/bayleybay.h index ecda4ba..c590f56 100644 --- a/include/configs/bayleybay.h +++ b/include/configs/bayleybay.h @@ -26,7 +26,8 @@ "stderr=serial,vga\0" #define CONFIG_SCSI_DEV_LIST \ - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VALLEYVIEW_SATA} + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VALLEYVIEW_SATA}, \ + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VALLEYVIEW_SATA_ALT} #define CONFIG_MMC #define CONFIG_SDHCI diff --git a/include/configs/minnowmax.h b/include/configs/minnowmax.h index 2a40d1f..aeb04b9 100644 --- a/include/configs/minnowmax.h +++ b/include/configs/minnowmax.h @@ -15,6 +15,7 @@ #define CONFIG_SYS_MONITOR_LEN (1 << 20) #define CONFIG_ARCH_EARLY_INIT_R +#define CONFIG_ARCH_MISC_INIT #define CONFIG_SMSC_LPC47M @@ -26,8 +27,10 @@ "stdout=vga,serial\0" \ "stderr=vga,serial\0" -#define CONFIG_SCSI_DEV_LIST \ - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VALLEYVIEW_SATA} +#define CONFIG_SCSI_DEV_LIST \ + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VALLEYVIEW_SATA}, \ + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VALLEYVIEW_SATA_ALT} + #define CONFIG_SPI_FLASH_STMICRO #define CONFIG_MMC diff --git a/include/fdtdec.h b/include/fdtdec.h index eac679e..62acbd0 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -182,6 +182,8 @@ enum fdt_compat_id { COMPAT_INTEL_PCH, /* Intel PCH */ COMPAT_INTEL_IRQ_ROUTER, /* Intel Interrupt Router */ COMPAT_ALTERA_SOCFPGA_DWMAC, /* SoCFPGA Ethernet controller */ + COMPAT_INTEL_BAYTRAIL_FSP, /* Intel Bay Trail FSP */ + COMPAT_INTEL_BAYTRAIL_FSP_MDP, /* Intel FSP memory-down params */ COMPAT_COUNT, }; diff --git a/include/pci.h b/include/pci.h index 628ede0..488ff44 100644 --- a/include/pci.h +++ b/include/pci.h @@ -910,6 +910,31 @@ int pci_bus_find_devfn(struct udevice *bus, pci_dev_t find_devfn, struct udevice **devp); /** + * pci_find_first_device() - return the first available PCI device + * + * This function and pci_find_first_device() allow iteration through all + * available PCI devices on all buses. Assuming there are any, this will + * return the first one. + * + * @devp: Set to the first available device, or NULL if no more are left + * or we got an error + * @return 0 if all is OK, -ve on error (e.g. a bus/bridge failed to probe) + */ +int pci_find_first_device(struct udevice **devp); + +/** + * pci_find_next_device() - return the next available PCI device + * + * Finds the next available PCI device after the one supplied, or sets @devp + * to NULL if there are no more. + * + * @devp: On entry, the last device returned. Set to the next available + * device, or NULL if no more are left or we got an error + * @return 0 if all is OK, -ve on error (e.g. a bus/bridge failed to probe) + */ +int pci_find_next_device(struct udevice **devp); + +/** * pci_get_ff() - Returns a mask for the given access size * * @size: Access size @@ -988,6 +1013,24 @@ int pci_bus_read_config(struct udevice *bus, pci_dev_t bdf, int offset, int pci_bus_write_config(struct udevice *bus, pci_dev_t bdf, int offset, unsigned long value, enum pci_size_t size); +/** + * Driver model PCI config access functions. Use these in preference to others + * when you have a valid device + */ +int dm_pci_read_config(struct udevice *dev, int offset, unsigned long *valuep, + enum pci_size_t size); + +int dm_pci_read_config8(struct udevice *dev, int offset, u8 *valuep); +int dm_pci_read_config16(struct udevice *dev, int offset, u16 *valuep); +int dm_pci_read_config32(struct udevice *dev, int offset, u32 *valuep); + +int dm_pci_write_config(struct udevice *dev, int offset, unsigned long value, + enum pci_size_t size); + +int dm_pci_write_config8(struct udevice *dev, int offset, u8 value); +int dm_pci_write_config16(struct udevice *dev, int offset, u16 value); +int dm_pci_write_config32(struct udevice *dev, int offset, u32 value); + /* * The following functions provide access to the above without needing the * size parameter. We are trying to encourage the use of the 8/16/32-style diff --git a/include/pci_ids.h b/include/pci_ids.h index 5771e12..49f7d7d 100644 --- a/include/pci_ids.h +++ b/include/pci_ids.h @@ -2602,7 +2602,10 @@ #define PCI_DEVICE_ID_INTEL_VALLEYVIEW_SDIO 0x0f15 #define PCI_DEVICE_ID_INTEL_VALLEYVIEW_SDCARD 0x0f16 #define PCI_DEVICE_ID_INTEL_VALLEYVIEW_LPC 0x0f1c -#define PCI_DEVICE_ID_INTEL_VALLEYVIEW_SATA 0x0f23 +#define PCI_DEVICE_ID_INTEL_VALLEYVIEW_IDE 0x0f20 +#define PCI_DEVICE_ID_INTEL_VALLEYVIEW_IDE_ALT 0x0f21 +#define PCI_DEVICE_ID_INTEL_VALLEYVIEW_SATA 0x0f22 +#define PCI_DEVICE_ID_INTEL_VALLEYVIEW_SATA_ALT 0x0f23 #define PCI_DEVICE_ID_INTEL_82541ER 0x1078 #define PCI_DEVICE_ID_INTEL_82541GI_LF 0x107c #define PCI_DEVICE_ID_INTEL_82542 0x1000 diff --git a/lib/fdtdec.c b/lib/fdtdec.c index b201787..d21fb74 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -76,6 +76,8 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(COMPAT_INTEL_PCH, "intel,bd82x6x"), COMPAT(COMPAT_INTEL_IRQ_ROUTER, "intel,irq-router"), COMPAT(ALTERA_SOCFPGA_DWMAC, "altr,socfpga-stmmac"), + COMPAT(COMPAT_INTEL_BAYTRAIL_FSP, "intel,baytrail-fsp"), + COMPAT(COMPAT_INTEL_BAYTRAIL_FSP_MDP, "intel,baytrail-fsp-mdp"), }; const char *fdtdec_get_compatible(enum fdt_compat_id id) @@ -88,45 +90,29 @@ const char *fdtdec_get_compatible(enum fdt_compat_id id) fdt_addr_t fdtdec_get_addr_size(const void *blob, int node, const char *prop_name, fdt_size_t *sizep) { - const fdt32_t *ptr, *end; - int parent, na, ns, len; - fdt_addr_t addr; + const fdt_addr_t *cell; + int len; debug("%s: %s: ", __func__, prop_name); - - parent = fdt_parent_offset(blob, node); - if (parent < 0) { - debug("(no parent found)\n"); - return FDT_ADDR_T_NONE; - } - - na = fdt_address_cells(blob, parent); - ns = fdt_size_cells(blob, parent); - - ptr = fdt_getprop(blob, node, prop_name, &len); - if (!ptr) { - debug("(not found)\n"); - return FDT_ADDR_T_NONE; - } - - end = ptr + len / sizeof(*ptr); - - if (ptr + na + ns > end) { - debug("(not enough data: expected %d bytes, got %d bytes)\n", - (na + ns) * 4, len); - return FDT_ADDR_T_NONE; - } - - addr = fdtdec_get_number(ptr, na); - - if (sizep) { - *sizep = fdtdec_get_number(ptr + na, ns); - debug("addr=%pa, size=%pa\n", &addr, sizep); - } else { - debug("%pa\n", &addr); + cell = fdt_getprop(blob, node, prop_name, &len); + if (cell && ((!sizep && len == sizeof(fdt_addr_t)) || + len == sizeof(fdt_addr_t) * 2)) { + fdt_addr_t addr = fdt_addr_to_cpu(*cell); + if (sizep) { + const fdt_size_t *size; + + size = (fdt_size_t *)((char *)cell + + sizeof(fdt_addr_t)); + *sizep = fdt_size_to_cpu(*size); + debug("addr=%08lx, size=%llx\n", + (ulong)addr, (u64)*sizep); + } else { + debug("%08lx\n", (ulong)addr); + } + return addr; } - - return addr; + debug("(not found)\n"); + return FDT_ADDR_T_NONE; } fdt_addr_t fdtdec_get_addr(const void *blob, int node, |