From dd5921104688074e2879bddeb18349bff89688ef Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Mon, 27 Apr 2015 11:34:38 -0400 Subject: builderthread.py: Keep 'SPL' On i.MX platforms the SPL binary is called "SPL" so make sure we keep that. Cc: Simon Glass Signed-off-by: Tom Rini Acked-by: Simon Glass diff --git a/tools/buildman/builderthread.py b/tools/buildman/builderthread.py index ce1cfdd..cf25bb8 100644 --- a/tools/buildman/builderthread.py +++ b/tools/buildman/builderthread.py @@ -356,7 +356,7 @@ class BuilderThread(threading.Thread): # Now write the actual build output if keep_outputs: self.CopyFiles(result.out_dir, build_dir, '', ['u-boot*', '*.bin', - '*.map', '*.img', 'MLO', 'include/autoconf.mk', + '*.map', '*.img', 'MLO', 'SPL', 'include/autoconf.mk', 'spl/u-boot-spl*']) def CopyFiles(self, out_dir, build_dir, dirname, patterns): -- cgit v0.10.2 From 343fb990646cc3d552711bff30bda743de392f08 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 7 Jun 2015 11:33:12 +0800 Subject: x86: Add Kconfig options to be used by arch/x86/cpu/config.mk Add RESET_SEG_START, RESET_SEG_SIZE and RESET_VEC_LOC Kconfig options and make arch/x86/cpu/config.mk use these options. Signed-off-by: Bin Meng Acked-by: Simon Glass Tested-by: Andrew Bradford Tested-by: Simon Glass diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 20083e6..e35ae1d 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -69,6 +69,21 @@ config X86_RESET_VECTOR bool default n +config RESET_SEG_START + hex + depends on X86_RESET_VECTOR + default 0xffff0000 + +config RESET_SEG_SIZE + hex + depends on X86_RESET_VECTOR + default 0x10000 + +config RESET_VEC_LOC + hex + depends on X86_RESET_VECTOR + default 0xfffffff0 + config SYS_X86_START16 hex depends on X86_RESET_VECTOR diff --git a/arch/x86/cpu/config.mk b/arch/x86/cpu/config.mk index 4c4d0c7..1263221 100644 --- a/arch/x86/cpu/config.mk +++ b/arch/x86/cpu/config.mk @@ -10,8 +10,8 @@ CROSS_COMPILE ?= i386-linux- PLATFORM_CPPFLAGS += -D__I386__ # DO NOT MODIFY THE FOLLOWING UNLESS YOU REALLY KNOW WHAT YOU ARE DOING! -LDPPFLAGS += -DRESET_SEG_START=0xffff0000 -LDPPFLAGS += -DRESET_SEG_SIZE=0x10000 -LDPPFLAGS += -DRESET_VEC_LOC=0xfffffff0 +LDPPFLAGS += -DRESET_SEG_START=$(CONFIG_RESET_SEG_START) +LDPPFLAGS += -DRESET_SEG_SIZE=$(CONFIG_RESET_SEG_SIZE) +LDPPFLAGS += -DRESET_VEC_LOC=$(CONFIG_RESET_VEC_LOC) LDPPFLAGS += -DSTART_16=$(CONFIG_SYS_X86_START16) LDPPFLAGS += -DRESET_BASE="CONFIG_SYS_TEXT_BASE + (CONFIG_SYS_MONITOR_LEN - RESET_SEG_SIZE)" -- cgit v0.10.2 From 002610f620553bec06e5724052fc5cc5f34eb1e8 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 7 Jun 2015 11:33:13 +0800 Subject: x86: fsp: Load GDT before calling FspInitEntry Currently the FSP execution environment GDT is setup by U-Boot in arch/x86/cpu/start16.S, which works pretty well. But if we try to move the FspInitEntry call a little bit later to better fit into U-Boot's initialization sequence, FSP will fail to bring up the AP due to #GP fault as AP's GDT is duplicated from BSP whose GDT is now moved into CAR, and unfortunately FSP calls AP initialization after it disables the CAR. So basically the BSP's GDT still refers to the one in the CAR, whose content is no longer available, so when AP starts up and loads its segment register, it blows up. To resolve this, we load GDT before calling into FspInitEntry. The GDT is the same one used in arch/x86/cpu/start16.S, which is in the ROM and exists forever. Signed-off-by: Bin Meng Tested-by: Andrew Bradford Tested-by: Simon Glass Acked-by: Simon Glass diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index bb4a110..b6c585a 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -164,6 +164,26 @@ void setup_gdt(gd_t *id, u64 *gdt_addr) load_fs(X86_GDT_ENTRY_32BIT_FS); } +#ifdef CONFIG_HAVE_FSP +/* + * Setup FSP execution environment GDT + * + * Per Intel FSP external architecture specification, before calling any FSP + * APIs, we need make sure the system is in flat 32-bit mode and both the code + * and data selectors should have full 4GB access range. Here we reuse the one + * we used in arch/x86/cpu/start16.S, and reload the segement registers. + */ +void setup_fsp_gdt(void) +{ + load_gdt((const u64 *)(gdt_rom + CONFIG_RESET_SEG_START), 4); + load_ds(X86_GDT_ENTRY_32BIT_DS); + load_ss(X86_GDT_ENTRY_32BIT_DS); + load_es(X86_GDT_ENTRY_32BIT_DS); + load_fs(X86_GDT_ENTRY_32BIT_DS); + load_gs(X86_GDT_ENTRY_32BIT_DS); +} +#endif + int __weak x86_cleanup_before_linux(void) { #ifdef CONFIG_BOOTSTAGE_STASH diff --git a/arch/x86/cpu/start16.S b/arch/x86/cpu/start16.S index 826e2b4..5eb17f1 100644 --- a/arch/x86/cpu/start16.S +++ b/arch/x86/cpu/start16.S @@ -71,11 +71,12 @@ idt_ptr: */ gdt_ptr: .word 0x1f /* limit (31 bytes = 4 GDT entries - 1) */ - .long BOOT_SEG + gdt /* base */ + .long BOOT_SEG + gdt_rom /* base */ /* Some CPUs are picky about GDT alignment... */ .align 16 -gdt: +.globl gdt_rom +gdt_rom: /* * The GDT table ... * diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index d1d21ed..3c6ee29 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -8,12 +8,19 @@ #ifndef _U_BOOT_I386_H_ #define _U_BOOT_I386_H_ 1 +extern char gdt_rom[]; + /* cpu/.../cpu.c */ 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 + * arch/x86/cpu/start16.S and reload the segment registers. + */ +void setup_fsp_gdt(void); int init_cache(void); int cleanup_before_linux(void); diff --git a/arch/x86/lib/fsp/fsp_support.c b/arch/x86/lib/fsp/fsp_support.c index 5809235..4585166 100644 --- a/arch/x86/lib/fsp/fsp_support.c +++ b/arch/x86/lib/fsp/fsp_support.c @@ -173,6 +173,9 @@ void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf) post_code(POST_PRE_MRC); + /* Load GDT for FSP */ + setup_fsp_gdt(); + /* * Use ASM code to ensure the register value in EAX & ECX * will be passed into BlContinuationFunc -- cgit v0.10.2 From aefaff8ed83472da5ba96e179231eee665e2d843 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 7 Jun 2015 11:33:14 +0800 Subject: x86: fsp: Move FspInitEntry call to board_init_f() The call to FspInitEntry is done in arch/x86/lib/fsp/fsp_car.S so far. It worked pretty well but looks not that good. Apart from doing too much work than just enabling CAR, it cannot read the configuration data from device tree at that time. Now we want to move it a little bit later as part of init_sequence_f[] being called by board_init_f(). This way it looks and works better in the U-Boot initialization path. Due to FSP's design, after calling FspInitEntry it will not return to its caller, instead it jumps to a continuation function which is given by bootloader with a new stack in system memory. The original stack in the CAR is gone, but its content is perserved by FSP and described by a bootloader temporary memory HOB. Technically we can recover anything we had before in the previous stack, but that is way too complicated. To make life much easier, in the FSP continuation routine we just simply call fsp_init_done() and jump back to car_init_ret() to redo the whole board_init_f() initialization, but this time with a non-zero HOB list pointer saved in U-Boot's global data so that we can bypass the FspInitEntry for the second time. Signed-off-by: Bin Meng Acked-by: Simon Glass Tested-by: Andrew Bradford Tested-by: Simon Glass diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 2e5f9da..00e585e 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -116,12 +116,16 @@ car_init_ret: rep stosb #ifdef CONFIG_HAVE_FSP + test %esi, %esi + jz skip_hob + /* Store HOB list */ movl %esp, %edx addl $GD_HOB_LIST, %edx movl %esi, (%edx) -#endif +skip_hob: +#endif /* Setup first parameter to setup_gdt, pointer to global_data */ movl %esp, %eax diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index 3c6ee29..4dae365 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -56,6 +56,9 @@ u32 isa_map_rom(u32 bus_addr, int size); /* arch/x86/lib/... */ int video_bios_init(void); +/* arch/x86/lib/fsp/... */ +int x86_fsp_init(void); + void board_init_f_r_trampoline(ulong) __attribute__ ((noreturn)); void board_init_f_r(void) __attribute__ ((noreturn)); diff --git a/arch/x86/lib/fsp/fsp_car.S b/arch/x86/lib/fsp/fsp_car.S index 5e09568..afbf3f9 100644 --- a/arch/x86/lib/fsp/fsp_car.S +++ b/arch/x86/lib/fsp/fsp_car.S @@ -56,28 +56,10 @@ temp_ram_init_ret: /* stack grows down from top of CAR */ movl %edx, %esp + subl $4, %esp - /* - * TODO: - * - * According to FSP architecture spec, the fsp_init() will not return - * to its caller, instead it requires the bootloader to provide a - * so-called continuation function to pass into the FSP as a parameter - * of fsp_init, and fsp_init() will call that continuation function - * directly. - * - * The call to fsp_init() may need to be moved out of the car_init() - * to cpu_init_f() with the help of some inline assembly codes. - * Note there is another issue that fsp_init() will setup another stack - * using the fsp_init parameter stack_top after DRAM is initialized, - * which means any data on the previous stack (on the CAR) gets lost - * (ie: U-Boot global_data). FSP is supposed to support such scenario, - * however it does not work. This should be revisited in the future. - */ - movl $CONFIG_FSP_TEMP_RAM_ADDR, %eax - xorl %edx, %edx - xorl %ecx, %ecx - call fsp_init + xor %esi, %esi + jmp car_init_done .global fsp_init_done fsp_init_done: @@ -86,6 +68,8 @@ fsp_init_done: * Save eax to esi temporarily. */ movl %eax, %esi + +car_init_done: /* * Re-initialize the ebp (BIST) to zero, as we already reach here * which means we passed BIST testing before. diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index 001494d..5b25632 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -46,3 +46,11 @@ void board_final_cleanup(void) return; } + +int x86_fsp_init(void) +{ + if (!gd->arch.hob_list) + fsp_init(CONFIG_FSP_TEMP_RAM_ADDR, BOOT_FULL_CONFIG, NULL); + + return 0; +} diff --git a/common/board_f.c b/common/board_f.c index fbbad1b..21be26f 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -753,6 +753,9 @@ static init_fnc_t init_sequence_f[] = { #ifdef CONFIG_OF_CONTROL fdtdec_setup, #endif +#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP) + x86_fsp_init, +#endif #ifdef CONFIG_TRACE trace_early_init, #endif -- cgit v0.10.2 From a7d0711a2486b7420a938831512d859879e613cb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Jun 2015 08:50:32 -0600 Subject: spi: sf: Print the error code on failure Rather than just 'ERROR', display the error code, which may be useful, at least with driver model. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Acked-by: Marek Vasut Reviewed-by: Jagan Teki diff --git a/common/cmd_sf.c b/common/cmd_sf.c index aef8c2a..3746e0d 100644 --- a/common/cmd_sf.c +++ b/common/cmd_sf.c @@ -303,8 +303,12 @@ static int do_spi_flash_read_write(int argc, char * const argv[]) else ret = spi_flash_write(flash, offset, len, buf); - printf("SF: %zu bytes @ %#x %s: %s\n", (size_t)len, (u32)offset, - read ? "Read" : "Written", ret ? "ERROR" : "OK"); + printf("SF: %zu bytes @ %#x %s: ", (size_t)len, (u32)offset, + read ? "Read" : "Written"); + if (ret) + printf("ERROR %d\n", ret); + else + printf("OK\n"); } unmap_physmem(buf, len); -- cgit v0.10.2 From 5d4a757ca5edb8782188c2bc2735f016e4b6c290 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Jun 2015 08:50:33 -0600 Subject: dm: spi: Correct minor nits in ICH driver Tidy up three minor problems in this file. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Reviewed-by: Jagan Teki diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index 50354fd..6b6cfbf 100644 --- a/drivers/spi/ich.c +++ b/drivers/spi/ich.c @@ -422,7 +422,7 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen, int using_cmd = 0; int ret; - /* Ee don't support writing partial bytes. */ + /* We don't support writing partial bytes */ if (bitlen % 8) { debug("ICH SPI: Accessing partial bytes not supported\n"); return -EPROTONOSUPPORT; @@ -601,7 +601,7 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen, return status; if (status & SPIS_FCERR) { - debug("ICH SPI: Data transaction error\n"); + debug("ICH SPI: Data transaction error %x\n", status); return -EIO; } @@ -619,7 +619,6 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen, return 0; } - /* * This uses the SPI controller from the Intel Cougar Point and Panther Point * PCH to write-protect portions of the SPI flash until reboot. The changes -- cgit v0.10.2 From 166c3984e6b1271c2e31ff0528ad65aadc913860 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 12 Jun 2015 14:52:18 +0800 Subject: dm: cpu: Fix undefined ENOSYS build error Include otherwise ENOSYS is undefined. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/common/cmd_cpu.c b/common/cmd_cpu.c index c3e229f..b4af64f 100644 --- a/common/cmd_cpu.c +++ b/common/cmd_cpu.c @@ -9,6 +9,7 @@ #include #include #include +#include static const char *cpu_feature_name[CPU_FEAT_COUNT] = { "L1 cache", diff --git a/drivers/cpu/cpu-uclass.c b/drivers/cpu/cpu-uclass.c index ab18ee2..aa0267c 100644 --- a/drivers/cpu/cpu-uclass.c +++ b/drivers/cpu/cpu-uclass.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include -- cgit v0.10.2 From cb5cbfd503d38bfe963ebd52da958563c636709d Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 12 Jun 2015 14:52:19 +0800 Subject: dm: cpu: Test against cpu_ops->get_info in cpu_get_info() In cpu_get_info() it wrongly tests against cpu_ops->get_desc to see if it is NULL. It should test against cpu_ops->get_info. Signed-off-by: Bin Meng diff --git a/drivers/cpu/cpu-uclass.c b/drivers/cpu/cpu-uclass.c index aa0267c..d6be9d4 100644 --- a/drivers/cpu/cpu-uclass.c +++ b/drivers/cpu/cpu-uclass.c @@ -26,7 +26,7 @@ int cpu_get_info(struct udevice *dev, struct cpu_info *info) { struct cpu_ops *ops = cpu_get_ops(dev); - if (!ops->get_desc) + if (!ops->get_info) return -ENOSYS; return ops->get_info(dev, info); -- cgit v0.10.2 From be3f06bcc47e04bfc5fb7c900958918e2d019ef4 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 12 Jun 2015 14:52:20 +0800 Subject: x86: dm: Clean up cpu drivers This commit does the following to clean up x86 cpu dm drivers: - Move cpu_x86 driver codes from arch/x86/cpu/cpu.c to a dedicated file arch/x86/cpu/cpu_x86.c - Rename x86_cpu_get_desc() to cpu_x86_get_desc() to keep consistent naming with other dm drivers - Add a new cpu_x86_bind() in the cpu_x86 driver which does exactly the same as the one in the intel baytrail cpu driver - Update intel baytrail cpu driver to use cpu_x86_get_desc() and cpu_x86_bind() Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 7ff05e6..48197fb 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -10,7 +10,7 @@ extra-y = start.o obj-$(CONFIG_X86_RESET_VECTOR) += resetvec.o start16.o -obj-y += interrupts.o cpu.o call64.o +obj-y += interrupts.o cpu.o cpu_x86.o call64.o obj-$(CONFIG_INTEL_BAYTRAIL) += baytrail/ obj-$(CONFIG_SYS_COREBOOT) += coreboot/ diff --git a/arch/x86/cpu/baytrail/cpu.c b/arch/x86/cpu/baytrail/cpu.c index 1d48206..05156a5 100644 --- a/arch/x86/cpu/baytrail/cpu.c +++ b/arch/x86/cpu/baytrail/cpu.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -175,18 +176,8 @@ static int baytrail_get_info(struct udevice *dev, struct cpu_info *info) return 0; } -static int cpu_x86_baytrail_bind(struct udevice *dev) -{ - struct cpu_platdata *plat = dev_get_parent_platdata(dev); - - plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, - "intel,apic-id", -1); - - return 0; -} - static const struct cpu_ops cpu_x86_baytrail_ops = { - .get_desc = x86_cpu_get_desc, + .get_desc = cpu_x86_get_desc, .get_info = baytrail_get_info, }; @@ -199,7 +190,7 @@ U_BOOT_DRIVER(cpu_x86_baytrail_drv) = { .name = "cpu_x86_baytrail", .id = UCLASS_CPU, .of_match = cpu_x86_baytrail_ids, - .bind = cpu_x86_baytrail_bind, + .bind = cpu_x86_bind, .probe = cpu_x86_baytrail_probe, .ops = &cpu_x86_baytrail_ops, }; diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index b6c585a..1dfd9e6 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -21,8 +21,6 @@ #include #include -#include -#include #include #include #include @@ -540,16 +538,6 @@ char *cpu_get_name(char *name) return ptr; } -int x86_cpu_get_desc(struct udevice *dev, char *buf, int size) -{ - if (size < CPU_MAX_NAME_LEN) - return -ENOSPC; - - cpu_get_name(buf); - - return 0; -} - int default_print_cpuinfo(void) { printf("CPU: %s, vendor %s, device %xh\n", @@ -642,19 +630,3 @@ int cpu_init_r(void) { return x86_init_cpus(); } - -static const struct cpu_ops cpu_x86_ops = { - .get_desc = x86_cpu_get_desc, -}; - -static const struct udevice_id cpu_x86_ids[] = { - { .compatible = "cpu-x86" }, - { } -}; - -U_BOOT_DRIVER(cpu_x86_drv) = { - .name = "cpu_x86", - .id = UCLASS_CPU, - .of_match = cpu_x86_ids, - .ops = &cpu_x86_ops, -}; diff --git a/arch/x86/cpu/cpu_x86.c b/arch/x86/cpu/cpu_x86.c new file mode 100644 index 0000000..d32ba66 --- /dev/null +++ b/arch/x86/cpu/cpu_x86.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +int cpu_x86_bind(struct udevice *dev) +{ + struct cpu_platdata *plat = dev_get_parent_platdata(dev); + + plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "intel,apic-id", -1); + + return 0; +} + +int cpu_x86_get_desc(struct udevice *dev, char *buf, int size) +{ + if (size < CPU_MAX_NAME_LEN) + return -ENOSPC; + + cpu_get_name(buf); + + return 0; +} + +static const struct cpu_ops cpu_x86_ops = { + .get_desc = cpu_x86_get_desc, +}; + +static const struct udevice_id cpu_x86_ids[] = { + { .compatible = "cpu-x86" }, + { } +}; + +U_BOOT_DRIVER(cpu_x86_drv) = { + .name = "cpu_x86", + .id = UCLASS_CPU, + .of_match = cpu_x86_ids, + .bind = cpu_x86_bind, + .ops = &cpu_x86_ops, +}; diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index ebc74ad..08284ee 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -197,20 +197,6 @@ const char *cpu_vendor_name(int vendor); char *cpu_get_name(char *name); /** - * -* x86_cpu_get_desc() - Get a description string for an x86 CPU -* -* This uses cpu_get_name() and is suitable to use as the get_desc() method for -* the CPU uclass. -* -* @dev: Device to check (UCLASS_CPU) -* @buf: Buffer to place string -* @size: Size of string space -* @return 0 if OK, -ENOSPC if buffer is too small, other -ve on error -*/ -int x86_cpu_get_desc(struct udevice *dev, char *buf, int size); - -/** * cpu_call64() - Jump to a 64-bit Linux kernel (internal function) * * The kernel is uncompressed and the 64-bit entry point is expected to be diff --git a/arch/x86/include/asm/cpu_x86.h b/arch/x86/include/asm/cpu_x86.h new file mode 100644 index 0000000..1940480 --- /dev/null +++ b/arch/x86/include/asm/cpu_x86.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _ASM_CPU_X86_H +#define _ASM_CPU_X86_H + +/** + * cpu_x86_bind() - Bind an x86 CPU with the driver + * + * This updates cpu device's platform data with information from device tree, + * like the processor local apic id. + * + * @dev: Device to check (UCLASS_CPU) + * @return 0 always + */ +int cpu_x86_bind(struct udevice *dev); + +/** + * cpu_x86_get_desc() - Get a description string for an x86 CPU + * + * This uses cpu_get_name() and is suitable to use as the get_desc() method for + * the CPU uclass. + * + * @dev: Device to check (UCLASS_CPU) + * @buf: Buffer to place string + * @size: Size of string space + * @return: 0 if OK, -ENOSPC if buffer is too small, other -ve on error + */ +int cpu_x86_get_desc(struct udevice *dev, char *buf, int size); + +#endif /* _ASM_CPU_X86_H */ -- cgit v0.10.2 From 063374d2f698162d0cc2d6ea44c8e332c639db0a Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 12 Jun 2015 14:52:22 +0800 Subject: x86: kconfig: Make MAX_CPUS and AP_STACK_SIZE depend on SMP MAX_CPUS and AP_STACK_SIZE are only meaningful when SMP is on. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e35ae1d..984a917 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -237,6 +237,7 @@ config FSP_TEMP_RAM_ADDR config MAX_CPUS int "Maximum number of CPUs permitted" + depends on SMP default 4 help When using multi-CPU chips it is possible for U-Boot to start up @@ -258,6 +259,7 @@ config SMP config AP_STACK_SIZE hex + depends on SMP default 0x1000 help Each additional CPU started by U-Boot requires its own stack. This -- cgit v0.10.2 From 4c71322b41a657596ee5e5777393ed83e80139c6 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 12 Jun 2015 14:52:23 +0800 Subject: x86: kconfig: Fix minor nits in MAX_CPUS Move MAX_CPUS definition after SMP so that it shows below SMP in the menuconfig. Also replace the leading spaces in the MAX_CPUS section with tabs to conform coding standard. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 984a917..36e97c8 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -235,18 +235,6 @@ config FSP_TEMP_RAM_ADDR Stack top address which is used in FspInit after DRAM is ready and CAR is disabled. -config MAX_CPUS - int "Maximum number of CPUs permitted" - depends on SMP - default 4 - help - When using multi-CPU chips it is possible for U-Boot to start up - more than one CPU. The stack memory used by all of these CPUs is - pre-allocated so at present U-Boot wants to know the maximum - number of CPUs that may be present. Set this to at least as high - as the number of CPUs in your system (it uses about 4KB of RAM for - each CPU). - config SMP bool "Enable Symmetric Multiprocessing" default n @@ -257,6 +245,18 @@ config SMP only one CPU will be enabled regardless of the number of CPUs available. +config MAX_CPUS + int "Maximum number of CPUs permitted" + depends on SMP + default 4 + help + When using multi-CPU chips it is possible for U-Boot to start up + more than one CPU. The stack memory used by all of these CPUs is + pre-allocated so at present U-Boot wants to know the maximum + number of CPUs that may be present. Set this to at least as high + as the number of CPUs in your system (it uses about 4KB of RAM for + each CPU). + config AP_STACK_SIZE hex depends on SMP -- cgit v0.10.2 From 780bfdd3c72a058ba24cda0df66ca75f0a7d8b18 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 17 Jun 2015 11:15:34 +0800 Subject: dm: cpu: Add a new get_count method to cpu uclass Introduce a new method 'get_count' in the UCLASS_CPU ops to get the number of CPUs in the system. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/drivers/cpu/cpu-uclass.c b/drivers/cpu/cpu-uclass.c index d6be9d4..a2814a8 100644 --- a/drivers/cpu/cpu-uclass.c +++ b/drivers/cpu/cpu-uclass.c @@ -32,6 +32,16 @@ int cpu_get_info(struct udevice *dev, struct cpu_info *info) return ops->get_info(dev, info); } +int cpu_get_count(struct udevice *dev) +{ + struct cpu_ops *ops = cpu_get_ops(dev); + + if (!ops->get_count) + return -ENOSYS; + + return ops->get_count(dev); +} + U_BOOT_DRIVER(cpu_bus) = { .name = "cpu_bus", .id = UCLASS_SIMPLE_BUS, diff --git a/include/cpu.h b/include/cpu.h index 34c60bc..bfb0db2 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -58,6 +58,14 @@ struct cpu_ops { * @return 0 if OK, -ve on error */ int (*get_info)(struct udevice *dev, struct cpu_info *info); + + /** + * get_count() - Get number of CPUs + * + * @dev: Device to check (UCLASS_CPU) + * @return CPU count if OK, -ve on error + */ + int (*get_count)(struct udevice *dev); }; #define cpu_get_ops(dev) ((struct cpu_ops *)(dev)->driver->ops) @@ -81,4 +89,12 @@ int cpu_get_desc(struct udevice *dev, char *buf, int size); */ int cpu_get_info(struct udevice *dev, struct cpu_info *info); +/** + * cpu_get_count() - Get number of CPUs + * + * @dev: Device to check (UCLASS_CPU) + * @return CPU count if OK, -ve on error + */ +int cpu_get_count(struct udevice *dev); + #endif -- cgit v0.10.2 From 946c2b5259823ca6935a62e1a68b6e29a74e33f0 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 17 Jun 2015 11:15:35 +0800 Subject: x86: ivybridge: Remove SMP from CPU_SPECIFIC_OPTIONS Ivybridge is not ready for U-Boot MP initialization yet. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/cpu/ivybridge/Kconfig b/arch/x86/cpu/ivybridge/Kconfig index e4595be..0e249a4 100644 --- a/arch/x86/cpu/ivybridge/Kconfig +++ b/arch/x86/cpu/ivybridge/Kconfig @@ -95,7 +95,6 @@ config CPU_SPECIFIC_OPTIONS select ARCH_BOOTBLOCK_X86_32 select ARCH_ROMSTAGE_X86_32 select ARCH_RAMSTAGE_X86_32 - select SMP select SSE2 select UDELAY_LAPIC select CPU_MICROCODE_IN_CBFS -- cgit v0.10.2 From 6e6f4ce4f82501e35301322872152fe28846d743 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 17 Jun 2015 11:15:36 +0800 Subject: x86: Move MP initialization codes into a common place Most of the MP initialization codes in arch/x86/cpu/baytrail/cpu.c is common to all x86 processors, except detect_num_cpus() which varies from cpu to cpu. Move these to arch/x86/cpu/cpu.c and implement the new 'get_count' method for baytrail and cpu_x86 drivers. Now we call cpu_get_count() in mp_init() to get the number of CPUs. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/cpu/baytrail/cpu.c b/arch/x86/cpu/baytrail/cpu.c index 05156a5..a011730 100644 --- a/arch/x86/cpu/baytrail/cpu.c +++ b/arch/x86/cpu/baytrail/cpu.c @@ -12,78 +12,9 @@ #include #include #include -#include #include #include -#ifdef CONFIG_SMP -static int enable_smis(struct udevice *cpu, void *unused) -{ - return 0; -} - -static struct mp_flight_record mp_steps[] = { - MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL), - /* Wait for APs to finish initialization before proceeding. */ - MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL), -}; - -static int detect_num_cpus(void) -{ - int ecx = 0; - - /* - * Use the algorithm described in Intel 64 and IA-32 Architectures - * Software Developer's Manual Volume 3 (3A, 3B & 3C): System - * Programming Guide, Jan-2015. Section 8.9.2: Hierarchical Mapping - * of CPUID Extended Topology Leaf. - */ - while (1) { - struct cpuid_result leaf_b; - - leaf_b = cpuid_ext(0xb, ecx); - - /* - * Bay Trail doesn't have hyperthreading so just determine the - * number of cores by from level type (ecx[15:8] == * 2) - */ - if ((leaf_b.ecx & 0xff00) == 0x0200) - return leaf_b.ebx & 0xffff; - ecx++; - } -} - -static int baytrail_init_cpus(void) -{ - struct mp_params mp_params; - - lapic_setup(); - - mp_params.num_cpus = detect_num_cpus(); - mp_params.parallel_microcode_load = 0, - mp_params.flight_plan = &mp_steps[0]; - mp_params.num_records = ARRAY_SIZE(mp_steps); - mp_params.microcode_pointer = 0; - - if (mp_init(&mp_params)) { - printf("Warning: MP init failure\n"); - return -EIO; - } - - return 0; -} -#endif - -int x86_init_cpus(void) -{ -#ifdef CONFIG_SMP - debug("Init additional CPUs\n"); - baytrail_init_cpus(); -#endif - - return 0; -} - static void set_max_freq(void) { msr_t perf_ctl; @@ -176,9 +107,38 @@ static int baytrail_get_info(struct udevice *dev, struct cpu_info *info) return 0; } +static int baytrail_get_count(struct udevice *dev) +{ + int ecx = 0; + + /* + * Use the algorithm described in Intel 64 and IA-32 Architectures + * Software Developer's Manual Volume 3 (3A, 3B & 3C): System + * Programming Guide, Jan-2015. Section 8.9.2: Hierarchical Mapping + * of CPUID Extended Topology Leaf. + */ + while (1) { + struct cpuid_result leaf_b; + + leaf_b = cpuid_ext(0xb, ecx); + + /* + * Bay Trail doesn't have hyperthreading so just determine the + * number of cores by from level type (ecx[15:8] == * 2) + */ + if ((leaf_b.ecx & 0xff00) == 0x0200) + return leaf_b.ebx & 0xffff; + + ecx++; + } + + return 0; +} + static const struct cpu_ops cpu_x86_baytrail_ops = { .get_desc = cpu_x86_get_desc, .get_info = baytrail_get_info, + .get_count = baytrail_get_count, }; static const struct udevice_id cpu_x86_baytrail_ids[] = { diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 1dfd9e6..a6e88cf 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -21,10 +21,13 @@ #include #include +#include #include #include #include #include +#include +#include #include #include #include @@ -621,8 +624,45 @@ int last_stage_init(void) } #endif +#ifdef CONFIG_SMP +static int enable_smis(struct udevice *cpu, void *unused) +{ + return 0; +} + +static struct mp_flight_record mp_steps[] = { + MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL), + /* Wait for APs to finish initialization before proceeding */ + MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL), +}; + +static int x86_mp_init(void) +{ + struct mp_params mp_params; + + lapic_setup(); + + mp_params.parallel_microcode_load = 0, + mp_params.flight_plan = &mp_steps[0]; + mp_params.num_records = ARRAY_SIZE(mp_steps); + mp_params.microcode_pointer = 0; + + if (mp_init(&mp_params)) { + printf("Warning: MP init failure\n"); + return -EIO; + } + + return 0; +} +#endif + __weak int x86_init_cpus(void) { +#ifdef CONFIG_SMP + debug("Init additional CPUs\n"); + x86_mp_init(); +#endif + return 0; } diff --git a/arch/x86/cpu/cpu_x86.c b/arch/x86/cpu/cpu_x86.c index d32ba66..0941041 100644 --- a/arch/x86/cpu/cpu_x86.c +++ b/arch/x86/cpu/cpu_x86.c @@ -10,6 +10,8 @@ #include #include +DECLARE_GLOBAL_DATA_PTR; + int cpu_x86_bind(struct udevice *dev) { struct cpu_platdata *plat = dev_get_parent_platdata(dev); @@ -30,8 +32,34 @@ int cpu_x86_get_desc(struct udevice *dev, char *buf, int size) return 0; } +static int cpu_x86_get_count(struct udevice *dev) +{ + int node, cpu; + int num = 0; + + node = fdt_path_offset(gd->fdt_blob, "/cpus"); + if (node < 0) + return -ENOENT; + + for (cpu = fdt_first_subnode(gd->fdt_blob, node); + cpu >= 0; + cpu = fdt_next_subnode(gd->fdt_blob, cpu)) { + const char *device_type; + + device_type = fdt_getprop(gd->fdt_blob, cpu, + "device_type", NULL); + if (!device_type) + continue; + if (strcmp(device_type, "cpu") == 0) + num++; + } + + return num; +} + static const struct cpu_ops cpu_x86_ops = { .get_desc = cpu_x86_get_desc, + .get_count = cpu_x86_get_count, }; static const struct udevice_id cpu_x86_ids[] = { diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index ac5753a..5564d84 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -22,6 +22,9 @@ #include #include +/* Total CPUs include BSP */ +static int num_cpus; + /* This also needs to match the sipi.S assembly code for saved MSR encoding */ struct saved_msr { uint32_t index; @@ -383,7 +386,7 @@ static int bsp_do_flight_plan(struct udevice *cpu, struct mp_params *mp_params) int ret = 0; const int timeout_us = 100000; const int step_us = 100; - int num_aps = mp_params->num_cpus - 1; + int num_aps = num_cpus - 1; for (i = 0; i < mp_params->num_records; i++) { struct mp_flight_record *rec = &mp_params->flight_plan[i]; @@ -451,7 +454,16 @@ int mp_init(struct mp_params *p) return -1; } - ret = check_cpu_devices(p->num_cpus); + num_cpus = cpu_get_count(cpu); + if (num_cpus < 0) { + debug("Cannot get number of CPUs: err=%d\n", num_cpus); + return num_cpus; + } + + if (num_cpus < 2) + debug("Warning: Only 1 CPU is detected\n"); + + ret = check_cpu_devices(num_cpus); if (ret) debug("Warning: Device tree does not describe all CPUs. Extra ones will not be started correctly\n"); @@ -471,7 +483,7 @@ int mp_init(struct mp_params *p) wbinvd(); /* Start the APs providing number of APs and the cpus_entered field */ - num_aps = p->num_cpus - 1; + num_aps = num_cpus - 1; ret = start_aps(num_aps, ap_count); if (ret) { mdelay(1000); diff --git a/arch/x86/include/asm/mp.h b/arch/x86/include/asm/mp.h index c0930fd..2e6c312 100644 --- a/arch/x86/include/asm/mp.h +++ b/arch/x86/include/asm/mp.h @@ -59,7 +59,6 @@ struct mp_flight_record { * SMM support. */ struct mp_params { - int num_cpus; /* Total cpus include BSP */ int parallel_microcode_load; const void *microcode_pointer; /* Flight plan for APs and BSP */ diff --git a/drivers/cpu/cpu-uclass.c b/drivers/cpu/cpu-uclass.c index a2814a8..7660f99 100644 --- a/drivers/cpu/cpu-uclass.c +++ b/drivers/cpu/cpu-uclass.c @@ -12,6 +12,8 @@ #include #include +DECLARE_GLOBAL_DATA_PTR; + int cpu_get_desc(struct udevice *dev, char *buf, int size) { struct cpu_ops *ops = cpu_get_ops(dev); -- cgit v0.10.2 From 61788e468ebe4a7b8c852ab4e761e084a7975a93 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 17 Jun 2015 11:15:37 +0800 Subject: x86: Move lapic_setup() call into init_bsp() Currently lapic_setup() is called before calling mp_init(), which then calls init_bsp() where it calls enable_lapic(), which was already enabled in lapic_setup(). Hence move lapic_setup() call into init_bsp() to avoid the duplication. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index a6e88cf..d108ee5 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -640,8 +640,6 @@ static int x86_mp_init(void) { struct mp_params mp_params; - lapic_setup(); - mp_params.parallel_microcode_load = 0, mp_params.flight_plan = &mp_steps[0]; mp_params.num_records = ARRAY_SIZE(mp_steps); diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 5564d84..e8bc9b6 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -418,7 +418,7 @@ static int init_bsp(struct udevice **devp) cpu_get_name(processor_name); debug("CPU: %s.\n", processor_name); - enable_lapic(); + lapic_setup(); apic_id = lapicid(); ret = find_cpu_by_apid_id(apic_id, devp); -- cgit v0.10.2 From 63d54a67051e3e03b8a46b5442b65323d18ddb98 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 17 Jun 2015 11:15:38 +0800 Subject: x86: Clean up lapic codes This commit cleans up the lapic codes: - Delete arch/x86/include/asm/lapic_def.h, and move register and bit defines into arch/x86/include/asm/lapic.h - Use MSR defines from msr-index.h in enable_lapic() and disable_lapic() - Remove unnecessary stuff like NEED_LAPIC, X86_GOOD_APIC and CONFIG_AP_IN_SIPI_WAIT - Move struct x86_cpu_priv defines to asm/arch-ivybridge/bd82x6x.h, as it is not apic related and only used by ivybridge - Fix coding convention issues Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/cpu/ivybridge/model_206ax.c b/arch/x86/cpu/ivybridge/model_206ax.c index 8b08c40..fd7db97 100644 --- a/arch/x86/cpu/ivybridge/model_206ax.c +++ b/arch/x86/cpu/ivybridge/model_206ax.c @@ -13,12 +13,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include static void enable_vmx(void) diff --git a/arch/x86/cpu/lapic.c b/arch/x86/cpu/lapic.c index 4690603..6769ae5 100644 --- a/arch/x86/cpu/lapic.c +++ b/arch/x86/cpu/lapic.c @@ -8,50 +8,46 @@ */ #include -#include -#include #include #include void lapic_setup(void) { -#if NEED_LAPIC == 1 +#ifdef CONFIG_SMP /* Only Pentium Pro and later have those MSR stuff */ debug("Setting up local apic: "); /* Enable the local apic */ enable_lapic(); - /* - * Set Task Priority to 'accept all'. - */ + /* Set Task Priority to 'accept all' */ lapic_write_around(LAPIC_TASKPRI, lapic_read_around(LAPIC_TASKPRI) & ~LAPIC_TPRI_MASK); /* Put the local apic in virtual wire mode */ lapic_write_around(LAPIC_SPIV, (lapic_read_around(LAPIC_SPIV) & - ~(LAPIC_VECTOR_MASK)) | LAPIC_SPIV_ENABLE); + ~(LAPIC_VECTOR_MASK)) | LAPIC_SPIV_ENABLE); lapic_write_around(LAPIC_LVT0, (lapic_read_around(LAPIC_LVT0) & - ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | - LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | - LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | - LAPIC_DELIVERY_MODE_MASK)) | - (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | - LAPIC_DELIVERY_MODE_EXTINT)); + ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | + LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | + LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | + LAPIC_DELIVERY_MODE_MASK)) | + (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | + LAPIC_DELIVERY_MODE_EXTINT)); lapic_write_around(LAPIC_LVT1, (lapic_read_around(LAPIC_LVT1) & - ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | - LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | - LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | - LAPIC_DELIVERY_MODE_MASK)) | - (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | - LAPIC_DELIVERY_MODE_NMI)); + ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | + LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | + LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | + LAPIC_DELIVERY_MODE_MASK)) | + (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | + LAPIC_DELIVERY_MODE_NMI)); debug("apic_id: 0x%02lx, ", lapicid()); -#else /* !NEED_LLAPIC */ +#else /* !CONFIG_SMP */ /* Only Pentium Pro and later have those MSR stuff */ debug("Disabling local apic: "); disable_lapic(); -#endif /* !NEED_LAPIC */ +#endif /* CONFIG_SMP */ debug("done.\n"); post_code(POST_LAPIC); } diff --git a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h index 5ae32f7..7786493 100644 --- a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h +++ b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h @@ -16,7 +16,19 @@ int gma_func0_init(pci_dev_t dev, struct pci_controller *hose, const void *blob, int node); int bd82x6x_init(void); -struct x86_cpu_priv; +/** + * struct x86_cpu_priv - Information about a single CPU + * + * @apic_id: Advanced Programmable Interrupt Controller Identifier, which is + * just a number representing the CPU core + * + * TODO: Move this to driver model once lifecycle is understood + */ +struct x86_cpu_priv { + int apic_id; + int start_err; +}; + int model_206ax_init(struct x86_cpu_priv *cpu); #endif diff --git a/arch/x86/include/asm/lapic.h b/arch/x86/include/asm/lapic.h index 0a7f443..f60974a 100644 --- a/arch/x86/include/asm/lapic.h +++ b/arch/x86/include/asm/lapic.h @@ -1,5 +1,5 @@ /* - * From Coreboot file of same name + * From coreboot file of same name * * Copyright (C) 2014 Google, Inc * @@ -10,16 +10,61 @@ #define _ARCH_ASM_LAPIC_H #include -#include #include +#include #include -/* See if I need to initialize the local apic */ -#if CONFIG_SMP || CONFIG_IOAPIC -# define NEED_LAPIC 1 -#else -# define NEED_LAPIC 0 -#endif +#define LAPIC_DEFAULT_BASE 0xfee00000 + +#define LAPIC_ID 0x020 +#define LAPIC_LVR 0x030 + +#define LAPIC_TASKPRI 0x080 +#define LAPIC_TPRI_MASK 0xff + +#define LAPIC_RRR 0x0c0 + +#define LAPIC_SPIV 0x0f0 +#define LAPIC_SPIV_ENABLE 0x100 + +#define LAPIC_ICR 0x300 +#define LAPIC_DEST_SELF 0x40000 +#define LAPIC_DEST_ALLINC 0x80000 +#define LAPIC_DEST_ALLBUT 0xc0000 +#define LAPIC_ICR_RR_MASK 0x30000 +#define LAPIC_ICR_RR_INVALID 0x00000 +#define LAPIC_ICR_RR_INPROG 0x10000 +#define LAPIC_ICR_RR_VALID 0x20000 +#define LAPIC_INT_LEVELTRIG 0x08000 +#define LAPIC_INT_ASSERT 0x04000 +#define LAPIC_ICR_BUSY 0x01000 +#define LAPIC_DEST_LOGICAL 0x00800 +#define LAPIC_DM_FIXED 0x00000 +#define LAPIC_DM_LOWEST 0x00100 +#define LAPIC_DM_SMI 0x00200 +#define LAPIC_DM_REMRD 0x00300 +#define LAPIC_DM_NMI 0x00400 +#define LAPIC_DM_INIT 0x00500 +#define LAPIC_DM_STARTUP 0x00600 +#define LAPIC_DM_EXTINT 0x00700 +#define LAPIC_VECTOR_MASK 0x000ff + +#define LAPIC_ICR2 0x310 +#define GET_LAPIC_DEST_FIELD(x) (((x) >> 24) & 0xff) +#define SET_LAPIC_DEST_FIELD(x) ((x) << 24) + +#define LAPIC_LVT0 0x350 +#define LAPIC_LVT1 0x360 +#define LAPIC_LVT_MASKED (1 << 16) +#define LAPIC_LVT_LEVEL_TRIGGER (1 << 15) +#define LAPIC_LVT_REMOTE_IRR (1 << 14) +#define LAPIC_INPUT_POLARITY (1 << 13) +#define LAPIC_SEND_PENDING (1 << 12) +#define LAPIC_LVT_RESERVED_1 (1 << 11) +#define LAPIC_DELIVERY_MODE_MASK (7 << 8) +#define LAPIC_DELIVERY_MODE_FIXED (0 << 8) +#define LAPIC_DELIVERY_MODE_NMI (4 << 8) +#define LAPIC_DELIVERY_MODE_EXTINT (7 << 8) static inline __attribute__((always_inline)) unsigned long lapic_read(unsigned long reg) @@ -42,21 +87,21 @@ static inline void enable_lapic(void) { msr_t msr; - msr = msr_read(LAPIC_BASE_MSR); + msr = msr_read(MSR_IA32_APICBASE); msr.hi &= 0xffffff00; - msr.lo |= LAPIC_BASE_MSR_ENABLE; - msr.lo &= ~LAPIC_BASE_MSR_ADDR_MASK; + msr.lo |= MSR_IA32_APICBASE_ENABLE; + msr.lo &= ~MSR_IA32_APICBASE_BASE; msr.lo |= LAPIC_DEFAULT_BASE; - msr_write(LAPIC_BASE_MSR, msr); + msr_write(MSR_IA32_APICBASE, msr); } static inline void disable_lapic(void) { msr_t msr; - msr = msr_read(LAPIC_BASE_MSR); - msr.lo &= ~(1 << 11); - msr_write(LAPIC_BASE_MSR, msr); + msr = msr_read(MSR_IA32_APICBASE); + msr.lo &= ~MSR_IA32_APICBASE_ENABLE; + msr_write(MSR_IA32_APICBASE, msr); } static inline __attribute__((always_inline)) unsigned long lapicid(void) @@ -64,30 +109,24 @@ static inline __attribute__((always_inline)) unsigned long lapicid(void) return lapic_read(LAPIC_ID) >> 24; } -#if !CONFIG_AP_IN_SIPI_WAIT -/* If we need to go back to sipi wait, we use the long non-inlined version of - * this function in lapic_cpu_init.c - */ static inline __attribute__((always_inline)) void stop_this_cpu(void) { /* Called by an AP when it is ready to halt and wait for a new task */ for (;;) cpu_hlt(); } -#else -void stop_this_cpu(void); -#endif -#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \ - sizeof(*(ptr)))) +#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \ + sizeof(*(ptr)))) -struct __xchg_dummy { unsigned long a[100]; }; -#define __xg(x) ((struct __xchg_dummy *)(x)) +struct __xchg_dummy { unsigned long a[100]; }; +#define __xg(x) ((struct __xchg_dummy *)(x)) /* - * Note: no "lock" prefix even on SMP: xchg always implies lock anyway + * Note: no "lock" prefix even on SMP. xchg always implies lock anyway. + * * Note 2: xchg has side effect, so that attribute volatile is necessary, - * but generally the primitive is invalid, *ptr is output argument. --ANK + * but generally the primitive is invalid, *ptr is output argument. */ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) @@ -121,25 +160,19 @@ static inline void lapic_write_atomic(unsigned long reg, unsigned long v) (void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v); } - -#ifdef X86_GOOD_APIC -# define FORCE_READ_AROUND_WRITE 0 -# define lapic_read_around(x) lapic_read(x) -# define lapic_write_around(x, y) lapic_write((x), (y)) -#else -# define FORCE_READ_AROUND_WRITE 1 -# define lapic_read_around(x) lapic_read(x) -# define lapic_write_around(x, y) lapic_write_atomic((x), (y)) -#endif +#define lapic_read_around(x) lapic_read(x) +#define lapic_write_around(x, y) lapic_write_atomic((x), (y)) static inline int lapic_remote_read(int apicid, int reg, unsigned long *pvalue) { int timeout; unsigned long status; int result; + lapic_wait_icr_idle(); lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); lapic_write_around(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4)); + timeout = 0; do { status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK; @@ -150,30 +183,10 @@ static inline int lapic_remote_read(int apicid, int reg, unsigned long *pvalue) *pvalue = lapic_read(LAPIC_RRR); result = 0; } + return result; } - void lapic_setup(void); -#if CONFIG_SMP -struct device; -int start_cpu(struct device *cpu); -#endif /* CONFIG_SMP */ - -int boot_cpu(void); - -/** - * struct x86_cpu_priv - Information about a single CPU - * - * @apic_id: Advanced Programmable Interrupt Controller Identifier, which is - * just a number representing the CPU core - * - * TODO: Move this to driver model once lifecycle is understood - */ -struct x86_cpu_priv { - int apic_id; - int start_err; -}; - #endif diff --git a/arch/x86/include/asm/lapic_def.h b/arch/x86/include/asm/lapic_def.h deleted file mode 100644 index 722cead..0000000 --- a/arch/x86/include/asm/lapic_def.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Taken from the Coreboot file of the same name - * - * (C) Copyright 2014 Google, Inc - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#ifndef _ASM_LAPIC_DEF_H -#define _ASM_LAPIC_DEF_H - -#define LAPIC_BASE_MSR 0x1B -#define LAPIC_BASE_MSR_BOOTSTRAP_PROCESSOR (1 << 8) -#define LAPIC_BASE_MSR_ENABLE (1 << 11) -#define LAPIC_BASE_MSR_ADDR_MASK 0xFFFFF000 - -#define LOCAL_APIC_ADDR 0xfee00000 -#define LAPIC_DEFAULT_BASE LOCAL_APIC_ADDR - -#define LAPIC_ID 0x020 -#define LAPIC_LVR 0x030 -#define LAPIC_TASKPRI 0x80 -#define LAPIC_TPRI_MASK 0xFF -#define LAPIC_ARBID 0x090 -#define LAPIC_RRR 0x0C0 -#define LAPIC_SVR 0x0f0 -#define LAPIC_SPIV 0x0f0 -#define LAPIC_SPIV_ENABLE 0x100 -#define LAPIC_ESR 0x280 -#define LAPIC_ESR_SEND_CS 0x00001 -#define LAPIC_ESR_RECV_CS 0x00002 -#define LAPIC_ESR_SEND_ACC 0x00004 -#define LAPIC_ESR_RECV_ACC 0x00008 -#define LAPIC_ESR_SENDILL 0x00020 -#define LAPIC_ESR_RECVILL 0x00040 -#define LAPIC_ESR_ILLREGA 0x00080 -#define LAPIC_ICR 0x300 -#define LAPIC_DEST_SELF 0x40000 -#define LAPIC_DEST_ALLINC 0x80000 -#define LAPIC_DEST_ALLBUT 0xC0000 -#define LAPIC_ICR_RR_MASK 0x30000 -#define LAPIC_ICR_RR_INVALID 0x00000 -#define LAPIC_ICR_RR_INPROG 0x10000 -#define LAPIC_ICR_RR_VALID 0x20000 -#define LAPIC_INT_LEVELTRIG 0x08000 -#define LAPIC_INT_ASSERT 0x04000 -#define LAPIC_ICR_BUSY 0x01000 -#define LAPIC_DEST_LOGICAL 0x00800 -#define LAPIC_DM_FIXED 0x00000 -#define LAPIC_DM_LOWEST 0x00100 -#define LAPIC_DM_SMI 0x00200 -#define LAPIC_DM_REMRD 0x00300 -#define LAPIC_DM_NMI 0x00400 -#define LAPIC_DM_INIT 0x00500 -#define LAPIC_DM_STARTUP 0x00600 -#define LAPIC_DM_EXTINT 0x00700 -#define LAPIC_VECTOR_MASK 0x000FF -#define LAPIC_ICR2 0x310 -#define GET_LAPIC_DEST_FIELD(x) (((x) >> 24) & 0xFF) -#define SET_LAPIC_DEST_FIELD(x) ((x) << 24) -#define LAPIC_LVTT 0x320 -#define LAPIC_LVTPC 0x340 -#define LAPIC_LVT0 0x350 -#define LAPIC_LVT_TIMER_BASE_MASK (0x3 << 18) -#define GET_LAPIC_TIMER_BASE(x) (((x) >> 18) & 0x3) -#define SET_LAPIC_TIMER_BASE(x) (((x) << 18)) -#define LAPIC_TIMER_BASE_CLKIN 0x0 -#define LAPIC_TIMER_BASE_TMBASE 0x1 -#define LAPIC_TIMER_BASE_DIV 0x2 -#define LAPIC_LVT_TIMER_PERIODIC (1 << 17) -#define LAPIC_LVT_MASKED (1 << 16) -#define LAPIC_LVT_LEVEL_TRIGGER (1 << 15) -#define LAPIC_LVT_REMOTE_IRR (1 << 14) -#define LAPIC_INPUT_POLARITY (1 << 13) -#define LAPIC_SEND_PENDING (1 << 12) -#define LAPIC_LVT_RESERVED_1 (1 << 11) -#define LAPIC_DELIVERY_MODE_MASK (7 << 8) -#define LAPIC_DELIVERY_MODE_FIXED (0 << 8) -#define LAPIC_DELIVERY_MODE_NMI (4 << 8) -#define LAPIC_DELIVERY_MODE_EXTINT (7 << 8) -#define GET_LAPIC_DELIVERY_MODE(x) (((x) >> 8) & 0x7) -#define SET_LAPIC_DELIVERY_MODE(x, y) (((x) & ~0x700)|((y) << 8)) -#define LAPIC_MODE_FIXED 0x0 -#define LAPIC_MODE_NMI 0x4 -#define LAPIC_MODE_EXINT 0x7 -#define LAPIC_LVT1 0x360 -#define LAPIC_LVTERR 0x370 -#define LAPIC_TMICT 0x380 -#define LAPIC_TMCCT 0x390 -#define LAPIC_TDCR 0x3E0 -#define LAPIC_TDR_DIV_TMBASE (1 << 2) -#define LAPIC_TDR_DIV_1 0xB -#define LAPIC_TDR_DIV_2 0x0 -#define LAPIC_TDR_DIV_4 0x1 -#define LAPIC_TDR_DIV_8 0x2 -#define LAPIC_TDR_DIV_16 0x3 -#define LAPIC_TDR_DIV_32 0x8 -#define LAPIC_TDR_DIV_64 0x9 -#define LAPIC_TDR_DIV_128 0xA - -#endif -- cgit v0.10.2 From 990acd0d5165c3ca36716e01c5c182423bdfc16a Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 17 Jun 2015 11:15:39 +0800 Subject: x86: crownbay: Add MP initialization Intel Crown Bay board has a TunnelCreek processor which supports hyper-threading. Add /cpus node in the crownbay.dts and enable the MP initialization. Signed-off-by: Bin Meng Acked-by: Simon Glass Signed-off-by: Simon Glass (modified to remove error: overriding the value of OF_CONTROL. Old value: "y", new value: "y") diff --git a/arch/x86/dts/crownbay.dts b/arch/x86/dts/crownbay.dts index d68efda..1ec90cd 100644 --- a/arch/x86/dts/crownbay.dts +++ b/arch/x86/dts/crownbay.dts @@ -23,6 +23,26 @@ silent_console = <0>; }; + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "cpu-x86"; + reg = <0>; + intel,apic-id = <0>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "cpu-x86"; + reg = <1>; + intel,apic-id = <1>; + }; + + }; + gpioa { compatible = "intel,ich6-gpio"; u-boot,dm-pre-reloc; diff --git a/configs/crownbay_defconfig b/configs/crownbay_defconfig index f3fb206..93f9216 100644 --- a/configs/crownbay_defconfig +++ b/configs/crownbay_defconfig @@ -2,7 +2,10 @@ CONFIG_X86=y CONFIG_VENDOR_INTEL=y CONFIG_DEFAULT_DEVICE_TREE="crownbay" CONFIG_TARGET_CROWNBAY=y +CONFIG_SMP=y +CONFIG_MAX_CPUS=2 CONFIG_GENERATE_PIRQ_TABLE=y +CONFIG_CMD_CPU=y # CONFIG_CMD_IMLS is not set # CONFIG_CMD_FLASH is not set # CONFIG_CMD_SETEXPR is not set @@ -11,6 +14,7 @@ CONFIG_BOOTSTAGE=y CONFIG_BOOTSTAGE_REPORT=y CONFIG_CMD_BOOTSTAGE=y CONFIG_OF_CONTROL=y +CONFIG_CPU=y CONFIG_SPI_FLASH=y CONFIG_USE_PRIVATE_LIBGCC=y CONFIG_SYS_VSNPRINTF=y -- cgit v0.10.2 From ed2ac0d564c4fac1178d36ea46a34b923c262d03 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:41 +0800 Subject: dm: rtc: Support mc146818 driver in driver model Add driver model support to the mc146818 rtc driver. Also clean up the driver a little bit for coding convention issues. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/drivers/rtc/mc146818.c b/drivers/rtc/mc146818.c index 44857a6..363ade3 100644 --- a/drivers/rtc/mc146818.c +++ b/drivers/rtc/mc146818.c @@ -9,10 +9,9 @@ * Date & Time support for the MC146818 (PIXX4) RTC */ -/*#define DEBUG*/ - #include #include +#include #include #if defined(__I386__) || defined(CONFIG_MALTA) @@ -24,9 +23,9 @@ #if defined(CONFIG_CMD_DATE) /* Set this to 1 to clear the CMOS RAM */ -#define CLEAR_CMOS 0 +#define CLEAR_CMOS 0 -#define RTC_PORT_MC146818 CONFIG_SYS_ISA_IO_BASE_ADDRESS + 0x70 +#define RTC_PORT_MC146818 CONFIG_SYS_ISA_IO_BASE_ADDRESS + 0x70 #define RTC_SECONDS 0x00 #define RTC_SECONDS_ALARM 0x01 #define RTC_MINUTES 0x02 @@ -37,10 +36,10 @@ #define RTC_DATE_OF_MONTH 0x07 #define RTC_MONTH 0x08 #define RTC_YEAR 0x09 -#define RTC_CONFIG_A 0x0A -#define RTC_CONFIG_B 0x0B -#define RTC_CONFIG_C 0x0C -#define RTC_CONFIG_D 0x0D +#define RTC_CONFIG_A 0x0a +#define RTC_CONFIG_B 0x0b +#define RTC_CONFIG_C 0x0c +#define RTC_CONFIG_D 0x0d #define RTC_REG_SIZE 0x80 #define RTC_CONFIG_A_REF_CLCK_32KHZ (1 << 5) @@ -50,89 +49,7 @@ #define RTC_CONFIG_D_VALID_RAM_AND_TIME 0x80 -/* ------------------------------------------------------------------------- */ - -int rtc_get (struct rtc_time *tmp) -{ - uchar sec, min, hour, mday, wday, mon, year; - /* here check if rtc can be accessed */ - while ((rtc_read8(RTC_CONFIG_A) & 0x80) == 0x80); - sec = rtc_read8(RTC_SECONDS); - min = rtc_read8(RTC_MINUTES); - hour = rtc_read8(RTC_HOURS); - mday = rtc_read8(RTC_DATE_OF_MONTH); - wday = rtc_read8(RTC_DAY_OF_WEEK); - mon = rtc_read8(RTC_MONTH); - year = rtc_read8(RTC_YEAR); -#ifdef RTC_DEBUG - printf ( "Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x " - "hr: %02x min: %02x sec: %02x\n", - year, mon, mday, wday, - hour, min, sec ); - printf ( "Alarms: month: %02x hour: %02x min: %02x sec: %02x\n", - rtc_read8(RTC_CONFIG_D) & 0x3F, - rtc_read8(RTC_HOURS_ALARM), - rtc_read8(RTC_MINUTES_ALARM), - rtc_read8(RTC_SECONDS_ALARM)); -#endif - tmp->tm_sec = bcd2bin (sec & 0x7F); - tmp->tm_min = bcd2bin (min & 0x7F); - tmp->tm_hour = bcd2bin (hour & 0x3F); - tmp->tm_mday = bcd2bin (mday & 0x3F); - tmp->tm_mon = bcd2bin (mon & 0x1F); - tmp->tm_year = bcd2bin (year); - tmp->tm_wday = bcd2bin (wday & 0x07); - if(tmp->tm_year<70) - tmp->tm_year+=2000; - else - tmp->tm_year+=1900; - tmp->tm_yday = 0; - tmp->tm_isdst= 0; -#ifdef RTC_DEBUG - printf ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", - tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, - tmp->tm_hour, tmp->tm_min, tmp->tm_sec); -#endif - - return 0; -} - -int rtc_set (struct rtc_time *tmp) -{ -#ifdef RTC_DEBUG - printf ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", - tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, - tmp->tm_hour, tmp->tm_min, tmp->tm_sec); -#endif - rtc_write8(RTC_CONFIG_B, 0x82); /* disable the RTC to update the regs */ - - rtc_write8(RTC_YEAR, bin2bcd(tmp->tm_year % 100)); - rtc_write8(RTC_MONTH, bin2bcd(tmp->tm_mon)); - rtc_write8(RTC_DAY_OF_WEEK, bin2bcd(tmp->tm_wday)); - rtc_write8(RTC_DATE_OF_MONTH, bin2bcd(tmp->tm_mday)); - rtc_write8(RTC_HOURS, bin2bcd(tmp->tm_hour)); - rtc_write8(RTC_MINUTES, bin2bcd(tmp->tm_min)); - rtc_write8(RTC_SECONDS, bin2bcd(tmp->tm_sec)); - rtc_write8(RTC_CONFIG_B, 0x02); /* enable the RTC to update the regs */ - - return 0; -} - -void rtc_reset (void) -{ - rtc_write8(RTC_CONFIG_B, 0x82); /* disable the RTC to update the regs */ - rtc_write8(RTC_CONFIG_A, 0x20); /* Normal OP */ - rtc_write8(RTC_CONFIG_B, 0x00); - rtc_write8(RTC_CONFIG_B, 0x00); - rtc_write8(RTC_CONFIG_B, 0x02); /* enable the RTC to update the regs */ -} - -/* ------------------------------------------------------------------------- */ - -/* - * use direct memory access - */ -int rtc_read8(int reg) +static int mc146818_read8(int reg) { #ifdef CONFIG_SYS_RTC_REG_BASE_ADDR return in8(CONFIG_SYS_RTC_REG_BASE_ADDR + reg); @@ -149,7 +66,7 @@ int rtc_read8(int reg) #endif } -void rtc_write8(int reg, uchar val) +static void mc146818_write8(int reg, uchar val) { #ifdef CONFIG_SYS_RTC_REG_BASE_ADDR out8(CONFIG_SYS_RTC_REG_BASE_ADDR + reg, val); @@ -165,26 +82,93 @@ void rtc_write8(int reg, uchar val) #endif } -u32 rtc_read32(int reg) +static int mc146818_get(struct rtc_time *tmp) { - u32 value = 0; - int i; + uchar sec, min, hour, mday, wday, mon, year; - for (i = 0; i < sizeof(value); i++) - value |= rtc_read8(reg + i) << (i << 3); + /* here check if rtc can be accessed */ + while ((mc146818_read8(RTC_CONFIG_A) & 0x80) == 0x80) + ; + + sec = mc146818_read8(RTC_SECONDS); + min = mc146818_read8(RTC_MINUTES); + hour = mc146818_read8(RTC_HOURS); + mday = mc146818_read8(RTC_DATE_OF_MONTH); + wday = mc146818_read8(RTC_DAY_OF_WEEK); + mon = mc146818_read8(RTC_MONTH); + year = mc146818_read8(RTC_YEAR); +#ifdef RTC_DEBUG + printf("Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x hr: %02x min: %02x sec: %02x\n", + year, mon, mday, wday, hour, min, sec); + printf("Alarms: month: %02x hour: %02x min: %02x sec: %02x\n", + mc146818_read8(RTC_CONFIG_D) & 0x3f, + mc146818_read8(RTC_HOURS_ALARM), + mc146818_read8(RTC_MINUTES_ALARM), + mc146818_read8(RTC_SECONDS_ALARM)); +#endif + tmp->tm_sec = bcd2bin(sec & 0x7f); + tmp->tm_min = bcd2bin(min & 0x7f); + tmp->tm_hour = bcd2bin(hour & 0x3f); + tmp->tm_mday = bcd2bin(mday & 0x3f); + tmp->tm_mon = bcd2bin(mon & 0x1f); + tmp->tm_year = bcd2bin(year); + tmp->tm_wday = bcd2bin(wday & 0x07); + + if (tmp->tm_year < 70) + tmp->tm_year += 2000; + else + tmp->tm_year += 1900; - return value; + tmp->tm_yday = 0; + tmp->tm_isdst = 0; +#ifdef RTC_DEBUG + printf("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); +#endif + + return 0; } -void rtc_write32(int reg, u32 value) +static int mc146818_set(struct rtc_time *tmp) { - int i; +#ifdef RTC_DEBUG + printf("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); +#endif + /* Disable the RTC to update the regs */ + mc146818_write8(RTC_CONFIG_B, 0x82); - for (i = 0; i < sizeof(value); i++) - rtc_write8(reg + i, (value >> (i << 3)) & 0xff); + mc146818_write8(RTC_YEAR, bin2bcd(tmp->tm_year % 100)); + mc146818_write8(RTC_MONTH, bin2bcd(tmp->tm_mon)); + mc146818_write8(RTC_DAY_OF_WEEK, bin2bcd(tmp->tm_wday)); + mc146818_write8(RTC_DATE_OF_MONTH, bin2bcd(tmp->tm_mday)); + mc146818_write8(RTC_HOURS, bin2bcd(tmp->tm_hour)); + mc146818_write8(RTC_MINUTES, bin2bcd(tmp->tm_min)); + mc146818_write8(RTC_SECONDS, bin2bcd(tmp->tm_sec)); + + /* Enable the RTC to update the regs */ + mc146818_write8(RTC_CONFIG_B, 0x02); + + return 0; } -void rtc_init(void) +static void mc146818_reset(void) +{ + /* Disable the RTC to update the regs */ + mc146818_write8(RTC_CONFIG_B, 0x82); + + /* Normal OP */ + mc146818_write8(RTC_CONFIG_A, 0x20); + mc146818_write8(RTC_CONFIG_B, 0x00); + mc146818_write8(RTC_CONFIG_B, 0x00); + + /* Enable the RTC to update the regs */ + mc146818_write8(RTC_CONFIG_B, 0x02); +} + +static void mc146818_init(void) { #if CLEAR_CMOS int i; @@ -198,14 +182,126 @@ void rtc_init(void) #endif /* Setup the real time clock */ - rtc_write8(RTC_CONFIG_B, RTC_CONFIG_B_24H); + mc146818_write8(RTC_CONFIG_B, RTC_CONFIG_B_24H); /* Setup the frequency it operates at */ - rtc_write8(RTC_CONFIG_A, RTC_CONFIG_A_REF_CLCK_32KHZ | - RTC_CONFIG_A_RATE_1024HZ); + mc146818_write8(RTC_CONFIG_A, RTC_CONFIG_A_REF_CLCK_32KHZ | + RTC_CONFIG_A_RATE_1024HZ); /* Ensure all reserved bits are 0 in register D */ - rtc_write8(RTC_CONFIG_D, RTC_CONFIG_D_VALID_RAM_AND_TIME); + mc146818_write8(RTC_CONFIG_D, RTC_CONFIG_D_VALID_RAM_AND_TIME); /* Clear any pending interrupts */ - rtc_read8(RTC_CONFIG_C); + mc146818_read8(RTC_CONFIG_C); } #endif + +#ifdef CONFIG_DM_RTC + +static int rtc_mc146818_get(struct udevice *dev, struct rtc_time *time) +{ + return mc146818_get(time); +} + +static int rtc_mc146818_set(struct udevice *dev, const struct rtc_time *time) +{ + return mc146818_set((struct rtc_time *)time); +} + +static int rtc_mc146818_reset(struct udevice *dev) +{ + mc146818_reset(); + + return 0; +} + +static int rtc_mc146818_read8(struct udevice *dev, unsigned int reg) +{ + return mc146818_read8(reg); +} + +static int rtc_mc146818_write8(struct udevice *dev, unsigned int reg, int val) +{ + mc146818_write8(reg, val); + + return 0; +} + +static int rtc_mc146818_bind(struct udevice *dev) +{ + mc146818_init(); + + return 0; +} + +static const struct rtc_ops rtc_mc146818_ops = { + .get = rtc_mc146818_get, + .set = rtc_mc146818_set, + .reset = rtc_mc146818_reset, + .read8 = rtc_mc146818_read8, + .write8 = rtc_mc146818_write8, +}; + +static const struct udevice_id rtc_mc146818_ids[] = { + { .compatible = "motorola,mc146818" }, + { } +}; + +U_BOOT_DRIVER(rtc_mc146818) = { + .name = "rtc_mc146818", + .id = UCLASS_RTC, + .of_match = rtc_mc146818_ids, + .bind = rtc_mc146818_bind, + .ops = &rtc_mc146818_ops, +}; + +#else /* !CONFIG_DM_RTC */ + +int rtc_get(struct rtc_time *tmp) +{ + return mc146818_get(tmp); +} + +int rtc_set(struct rtc_time *tmp) +{ + return mc146818_set(tmp); +} + +void rtc_reset(void) +{ + mc146818_reset(); +} + +int rtc_read8(int reg) +{ + return mc146818_read8(reg); +} + +void rtc_write8(int reg, uchar val) +{ + mc146818_write8(reg, val); +} + +u32 rtc_read32(int reg) +{ + u32 value = 0; + int i; + + for (i = 0; i < sizeof(value); i++) + value |= rtc_read8(reg + i) << (i << 3); + + return value; +} + +void rtc_write32(int reg, u32 value) +{ + int i; + + for (i = 0; i < sizeof(value); i++) + rtc_write8(reg + i, (value >> (i << 3)) & 0xff); +} + +void rtc_init(void) +{ + mc146818_init(); +} + +#endif /* CONFIG_DM_RTC */ -- cgit v0.10.2 From ffe387988d598f14b5cfc17b07c6dc61d8b7fa16 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:42 +0800 Subject: cmd: date: Change to use CONFIG_DM_RTC instead of CONFIG_DM_I2C Currently CONFIG_DM_I2C is used in cmd_date.c for driver model, but it should be actually CONFIG_DM_RTC. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/common/cmd_date.c b/common/cmd_date.c index 61727e3..8714699 100644 --- a/common/cmd_date.c +++ b/common/cmd_date.c @@ -37,7 +37,7 @@ static int do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) int old_bus __maybe_unused; /* switch to correct I2C bus */ -#ifdef CONFIG_DM_I2C +#ifdef CONFIG_DM_RTC struct udevice *dev; rcode = uclass_get_device(UCLASS_RTC, 0, &dev); @@ -57,7 +57,7 @@ static int do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) case 2: /* set date & time */ if (strcmp(argv[1],"reset") == 0) { puts ("Reset RTC...\n"); -#ifdef CONFIG_DM_I2C +#ifdef CONFIG_DM_RTC rcode = dm_rtc_reset(dev); if (!rcode) rcode = dm_rtc_set(dev, &default_tm); @@ -69,7 +69,7 @@ static int do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) puts("## Failed to set date after RTC reset\n"); } else { /* initialize tm with current time */ -#ifdef CONFIG_DM_I2C +#ifdef CONFIG_DM_RTC rcode = dm_rtc_get(dev, &tm); #else rcode = rtc_get(&tm); @@ -81,7 +81,7 @@ static int do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) break; } /* and write to RTC */ -#ifdef CONFIG_DM_I2C +#ifdef CONFIG_DM_RTC rcode = dm_rtc_set(dev, &tm); #else rcode = rtc_set(&tm); @@ -96,7 +96,7 @@ static int do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } /* FALL TROUGH */ case 1: /* get date & time */ -#ifdef CONFIG_DM_I2C +#ifdef CONFIG_DM_RTC rcode = dm_rtc_get(dev, &tm); #else rcode = rtc_get(&tm); @@ -120,7 +120,7 @@ static int do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) /* switch back to original I2C bus */ #ifdef CONFIG_SYS_I2C i2c_set_bus_num(old_bus); -#elif !defined(CONFIG_DM_I2C) +#elif !defined(CONFIG_DM_RTC) I2C_SET_BUS(old_bus); #endif -- cgit v0.10.2 From b0014b6423574780cdcb9a76478be0c1f83f7990 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:43 +0800 Subject: x86: crownbay: Enable DM RTC support Add a RTC node in the device tree to enable DM RTC support. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/dts/crownbay.dts b/arch/x86/dts/crownbay.dts index 1ec90cd..87ed0f4 100644 --- a/arch/x86/dts/crownbay.dts +++ b/arch/x86/dts/crownbay.dts @@ -10,6 +10,7 @@ /include/ "skeleton.dtsi" /include/ "serial.dtsi" +/include/ "rtc.dtsi" / { model = "Intel Crown Bay"; diff --git a/arch/x86/dts/rtc.dtsi b/arch/x86/dts/rtc.dtsi new file mode 100644 index 0000000..93dacd7 --- /dev/null +++ b/arch/x86/dts/rtc.dtsi @@ -0,0 +1,6 @@ +/ { + rtc { + compatible = "motorola,mc146818"; + reg = <0x70 2>; + }; +}; diff --git a/configs/crownbay_defconfig b/configs/crownbay_defconfig index 93f9216..6c38504 100644 --- a/configs/crownbay_defconfig +++ b/configs/crownbay_defconfig @@ -18,3 +18,4 @@ CONFIG_CPU=y CONFIG_SPI_FLASH=y CONFIG_USE_PRIVATE_LIBGCC=y CONFIG_SYS_VSNPRINTF=y +CONFIG_DM_RTC=y -- cgit v0.10.2 From d402f922b291bb76e7e3b5c15dda7abf1ce33b85 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:44 +0800 Subject: x86: queensbay: Correct Topcliff device irqs There are 4 usb ports on the Intel Crown Bay board, 2 of which are connected to Topcliff usb host 0 and the other 2 connected to usb host 1. USB devices inserted in the ports connected to usb host 1 cannot get detected due to wrong IRQ assigned to the controller. Actually we need apply the PCI interrupt pin swizzling logic to all devices on the Topcliff chipset when configuring the PIRQ routing. This was observed on usb ports, but device 6 and 10 irqs are also wrong. Correct them all together. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/dts/crownbay.dts b/arch/x86/dts/crownbay.dts index 87ed0f4..b77c65a 100644 --- a/arch/x86/dts/crownbay.dts +++ b/arch/x86/dts/crownbay.dts @@ -180,29 +180,29 @@ * Note on the Crown Bay board, Topcliff chipset * is connected to TunnelCreek PCIe port 0, so * its bus number is 1 for its PCIe port and 2 - * for its PCI devices per U-Boot currnet PCI + * for its PCI devices per U-Boot current PCI * bus enumeration algorithm. */ PCI_BDF(1, 0, 0) INTA PIRQA PCI_BDF(2, 0, 1) INTA PIRQA PCI_BDF(2, 0, 2) INTA PIRQA - PCI_BDF(2, 2, 0) INTB PIRQB - PCI_BDF(2, 2, 1) INTB PIRQB - PCI_BDF(2, 2, 2) INTB PIRQB - PCI_BDF(2, 2, 3) INTB PIRQB - PCI_BDF(2, 2, 4) INTB PIRQB + PCI_BDF(2, 2, 0) INTB PIRQD + PCI_BDF(2, 2, 1) INTB PIRQD + PCI_BDF(2, 2, 2) INTB PIRQD + PCI_BDF(2, 2, 3) INTB PIRQD + PCI_BDF(2, 2, 4) INTB PIRQD PCI_BDF(2, 4, 0) INTC PIRQC PCI_BDF(2, 4, 1) INTC PIRQC - PCI_BDF(2, 6, 0) INTD PIRQD + PCI_BDF(2, 6, 0) INTD PIRQB PCI_BDF(2, 8, 0) INTA PIRQA PCI_BDF(2, 8, 1) INTA PIRQA PCI_BDF(2, 8, 2) INTA PIRQA PCI_BDF(2, 8, 3) INTA PIRQA - PCI_BDF(2, 10, 0) INTB PIRQB - PCI_BDF(2, 10, 1) INTB PIRQB - PCI_BDF(2, 10, 2) INTB PIRQB - PCI_BDF(2, 10, 3) INTB PIRQB - PCI_BDF(2, 10, 4) INTB PIRQB + PCI_BDF(2, 10, 0) INTB PIRQD + PCI_BDF(2, 10, 1) INTB PIRQD + PCI_BDF(2, 10, 2) INTB PIRQD + PCI_BDF(2, 10, 3) INTB PIRQD + PCI_BDF(2, 10, 4) INTB PIRQD PCI_BDF(2, 12, 0) INTC PIRQC PCI_BDF(2, 12, 1) INTC PIRQC PCI_BDF(2, 12, 2) INTC PIRQC -- cgit v0.10.2 From 9c235436a3fbc8d6959c0acee276b7060e61f2e5 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:45 +0800 Subject: x86: Write correct bus number for the irq router We should write correct bus number to the PIRQ routing table for the irq router from device tree, instead of hard-coded zero. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c index 74b89ad..7d5ccc1 100644 --- a/arch/x86/cpu/irq.c +++ b/arch/x86/cpu/irq.c @@ -161,7 +161,7 @@ static int create_pirq_routing_table(void) /* Populate the PIRQ table fields */ rt->signature = PIRQ_SIGNATURE; rt->version = PIRQ_VERSION; - rt->rtr_bus = 0; + rt->rtr_bus = PCI_BUS(irq_router.bdf); rt->rtr_devfn = (PCI_DEV(irq_router.bdf) << 3) | PCI_FUNC(irq_router.bdf); rt->rtr_vendor = PCI_VENDOR_ID_INTEL; -- cgit v0.10.2 From 8c38e4d0b8d37dcd3bfd2293481e220b1b4a3a42 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:46 +0800 Subject: x86: Ignore function number when writing PIRQ routing table In fill_irq_info() pci device's function number is written into the table, however this is not really necessary. The function number can be anything as OS doesn't care about this field, neither does the PIRQ routing specification. Change to always writing 0 as the function number. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c index 7d5ccc1..df4300c 100644 --- a/arch/x86/cpu/irq.c +++ b/arch/x86/cpu/irq.c @@ -59,12 +59,12 @@ void pirq_assign_irq(int link, u8 irq) } static inline void fill_irq_info(struct irq_info **slotp, int *entries, u8 bus, - u8 device, u8 func, u8 pin, u8 pirq) + u8 device, u8 pin, u8 pirq) { struct irq_info *slot = *slotp; slot->bus = bus; - slot->devfn = (device << 3) | func; + slot->devfn = (device << 3) | 0; slot->irq[pin - 1].link = LINK_N2V(pirq, irq_router.link_base); slot->irq[pin - 1].bitmap = irq_router.irq_mask; (*entries)++; @@ -182,8 +182,7 @@ static int create_pirq_routing_table(void) PCI_FUNC(pr.bdf), 'A' + pr.pin - 1, 'A' + pr.pirq); fill_irq_info(&slot, &irq_entries, PCI_BUS(pr.bdf), - PCI_DEV(pr.bdf), PCI_FUNC(pr.bdf), - pr.pin, pr.pirq); + PCI_DEV(pr.bdf), pr.pin, pr.pirq); cell += sizeof(struct pirq_routing) / sizeof(u32); } -- cgit v0.10.2 From df81749db7d7303508be41503e4c8d1229a07d4c Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:47 +0800 Subject: x86: Reduce PIRQ routing table size There is no need to populate multiple irq info entries with the same bus number and device number, but with different interrupt pin. We can use the same entry to store all the 4 interrupt pin (INT A/B/C/D) routing information to reduce the whole PIRQ routing table size. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c index df4300c..97dd000 100644 --- a/arch/x86/cpu/irq.c +++ b/arch/x86/cpu/irq.c @@ -58,17 +58,28 @@ void pirq_assign_irq(int link, u8 irq) writeb(irq, irq_router.ibase + LINK_N2V(link, base)); } -static inline void fill_irq_info(struct irq_info **slotp, int *entries, u8 bus, - u8 device, u8 pin, u8 pirq) +static struct irq_info *check_dup_entry(struct irq_info *slot_base, + int entry_num, int bus, int device) { - struct irq_info *slot = *slotp; + struct irq_info *slot = slot_base; + int i; + + for (i = 0; i < entry_num; i++) { + if (slot->bus == bus && slot->devfn == (device << 3)) + break; + slot++; + } + return (i == entry_num) ? NULL : slot; +} + +static inline void fill_irq_info(struct irq_info *slot, int bus, int device, + int pin, int pirq) +{ slot->bus = bus; slot->devfn = (device << 3) | 0; slot->irq[pin - 1].link = LINK_N2V(pirq, irq_router.link_base); slot->irq[pin - 1].bitmap = irq_router.irq_mask; - (*entries)++; - (*slotp)++; } __weak void cpu_irq_init(void) @@ -84,7 +95,7 @@ static int create_pirq_routing_table(void) int len, count; const u32 *cell; struct irq_routing_table *rt; - struct irq_info *slot; + struct irq_info *slot, *slot_base; int irq_entries = 0; int i; int ret; @@ -167,7 +178,7 @@ static int create_pirq_routing_table(void) rt->rtr_vendor = PCI_VENDOR_ID_INTEL; rt->rtr_device = PCI_DEVICE_ID_INTEL_ICH7_31; - slot = rt->slots; + slot_base = rt->slots; /* Now fill in the irq_info entries in the PIRQ table */ for (i = 0; i < count; i++) { @@ -181,8 +192,44 @@ static int create_pirq_routing_table(void) i, PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), PCI_FUNC(pr.bdf), 'A' + pr.pin - 1, 'A' + pr.pirq); - fill_irq_info(&slot, &irq_entries, PCI_BUS(pr.bdf), - PCI_DEV(pr.bdf), pr.pin, pr.pirq); + + slot = check_dup_entry(slot_base, irq_entries, + PCI_BUS(pr.bdf), PCI_DEV(pr.bdf)); + if (slot) { + debug("found entry for bus %d device %d, ", + PCI_BUS(pr.bdf), PCI_DEV(pr.bdf)); + + if (slot->irq[pr.pin - 1].link) { + debug("skipping\n"); + + /* + * Sanity test on the routed PIRQ pin + * + * If they don't match, show a warning to tell + * there might be something wrong with the PIRQ + * routing information in the device tree. + */ + 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; + } + } + + 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); } -- cgit v0.10.2 From ba9091f55d68fc3d7b65a710f9d47c0be15e816d Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:48 +0800 Subject: x86: Clean up ioapic header file Remove all the dead/unused macros from asm/ioapic.h. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/include/asm/ioapic.h b/arch/x86/include/asm/ioapic.h index 699160f..f5d69db 100644 --- a/arch/x86/include/asm/ioapic.h +++ b/arch/x86/include/asm/ioapic.h @@ -10,29 +10,9 @@ #define __ASM_IOAPIC_H #define IO_APIC_ADDR 0xfec00000 -#define IO_APIC_INDEX IO_APIC_ADDR -#define IO_APIC_DATA (IO_APIC_ADDR + 0x10) -#define IO_APIC_INTERRUPTS 24 - -#define ALL (0xff << 24) -#define NONE 0 -#define DISABLED (1 << 16) -#define ENABLED (0 << 16) -#define TRIGGER_EDGE (0 << 15) -#define TRIGGER_LEVEL (1 << 15) -#define POLARITY_HIGH (0 << 13) -#define POLARITY_LOW (1 << 13) -#define PHYSICAL_DEST (0 << 11) -#define LOGICAL_DEST (1 << 11) -#define ExtINT (7 << 8) -#define NMI (4 << 8) -#define SMI (2 << 8) -#define INT (1 << 8) -u32 io_apic_read(u32 ioapic_base, u32 reg); -void io_apic_write(u32 ioapic_base, u32 reg, u32 value); -void set_ioapic_id(u32 ioapic_base, u8 ioapic_id); -void setup_ioapic(u32 ioapic_base, u8 ioapic_id); -void clear_ioapic(u32 ioapic_base); +/* Direct addressed register */ +#define IO_APIC_INDEX (IO_APIC_ADDR + 0x00) +#define IO_APIC_DATA (IO_APIC_ADDR + 0x10) #endif -- cgit v0.10.2 From 3d232878289bf59e83c6b152407a01f6e0fb790b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:49 +0800 Subject: x86: Add I/O APIC register access routines I/O APIC registers are addressed indirectly. Add io_apic_read() and io_apic_write() routines to help register access. Two macros for I/O APIC ID and version register offset are also added. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 48197fb..8a8e63e 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -19,7 +19,7 @@ obj-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += ivybridge/ obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/ obj-$(CONFIG_INTEL_QUARK) += quark/ obj-$(CONFIG_INTEL_QUEENSBAY) += queensbay/ -obj-y += irq.o lapic.o +obj-y += irq.o lapic.o ioapic.o obj-$(CONFIG_SMP) += mp_init.o obj-y += mtrr.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/x86/cpu/ioapic.c b/arch/x86/cpu/ioapic.c new file mode 100644 index 0000000..112a9c6 --- /dev/null +++ b/arch/x86/cpu/ioapic.c @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +u32 io_apic_read(u32 reg) +{ + writel(reg, IO_APIC_INDEX); + return readl(IO_APIC_DATA); +} + +void io_apic_write(u32 reg, u32 val) +{ + writel(reg, IO_APIC_INDEX); + writel(val, IO_APIC_DATA); +} diff --git a/arch/x86/include/asm/ioapic.h b/arch/x86/include/asm/ioapic.h index f5d69db..77c443e 100644 --- a/arch/x86/include/asm/ioapic.h +++ b/arch/x86/include/asm/ioapic.h @@ -15,4 +15,28 @@ #define IO_APIC_INDEX (IO_APIC_ADDR + 0x00) #define IO_APIC_DATA (IO_APIC_ADDR + 0x10) +/* Indirect addressed register offset */ +#define IO_APIC_ID 0x00 +#define IO_APIC_VER 0x01 + +/** + * io_apic_read() - Read I/O APIC register + * + * This routine reads I/O APIC indirect addressed register. + * + * @reg: address of indirect addressed register + * @return: register value to read + */ +u32 io_apic_read(u32 reg); + +/** + * io_apic_write() - Write I/O APIC register + * + * This routine writes I/O APIC indirect addressed register. + * + * @reg: address of indirect addressed register + * @val: register value to write + */ +void io_apic_write(u32 reg, u32 val); + #endif -- cgit v0.10.2 From a2d73fdba638233253c14b31f3befb9099d76774 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:50 +0800 Subject: x86: Remove inline for lapic access routines Remove inline for lapic access routines and expose lapic_read() & lapic_write() as APIs to read/write lapic registers. Also move stop_this_cpu() to mp_init.c as it has nothing to do with lapic. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/cpu/lapic.c b/arch/x86/cpu/lapic.c index 6769ae5..30d2313 100644 --- a/arch/x86/cpu/lapic.c +++ b/arch/x86/cpu/lapic.c @@ -8,9 +8,116 @@ */ #include +#include #include +#include +#include #include +unsigned long lapic_read(unsigned long reg) +{ + return readl(LAPIC_DEFAULT_BASE + reg); +} + +#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \ + sizeof(*(ptr)))) + +struct __xchg_dummy { unsigned long a[100]; }; +#define __xg(x) ((struct __xchg_dummy *)(x)) + +/* + * Note: no "lock" prefix even on SMP. xchg always implies lock anyway. + * + * Note 2: xchg has side effect, so that attribute volatile is necessary, + * but generally the primitive is invalid, *ptr is output argument. + */ +static inline unsigned long __xchg(unsigned long x, volatile void *ptr, + int size) +{ + switch (size) { + case 1: + __asm__ __volatile__("xchgb %b0,%1" + : "=q" (x) + : "m" (*__xg(ptr)), "0" (x) + : "memory"); + break; + case 2: + __asm__ __volatile__("xchgw %w0,%1" + : "=r" (x) + : "m" (*__xg(ptr)), "0" (x) + : "memory"); + break; + case 4: + __asm__ __volatile__("xchgl %0,%1" + : "=r" (x) + : "m" (*__xg(ptr)), "0" (x) + : "memory"); + break; + } + + return x; +} + +void lapic_write(unsigned long reg, unsigned long v) +{ + (void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v); +} + +void enable_lapic(void) +{ + msr_t msr; + + msr = msr_read(MSR_IA32_APICBASE); + msr.hi &= 0xffffff00; + msr.lo |= MSR_IA32_APICBASE_ENABLE; + msr.lo &= ~MSR_IA32_APICBASE_BASE; + msr.lo |= LAPIC_DEFAULT_BASE; + msr_write(MSR_IA32_APICBASE, msr); +} + +void disable_lapic(void) +{ + msr_t msr; + + msr = msr_read(MSR_IA32_APICBASE); + msr.lo &= ~MSR_IA32_APICBASE_ENABLE; + msr_write(MSR_IA32_APICBASE, msr); +} + +unsigned long lapicid(void) +{ + return lapic_read(LAPIC_ID) >> 24; +} + +static void lapic_wait_icr_idle(void) +{ + do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY); +} + +int lapic_remote_read(int apicid, int reg, unsigned long *pvalue) +{ + int timeout; + unsigned long status; + int result; + + lapic_wait_icr_idle(); + lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); + lapic_write(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4)); + + timeout = 0; + do { + status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK; + } while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000); + + result = -1; + if (status == LAPIC_ICR_RR_VALID) { + *pvalue = lapic_read(LAPIC_RRR); + result = 0; + } + + return result; +} + void lapic_setup(void) { #ifdef CONFIG_SMP @@ -21,26 +128,26 @@ void lapic_setup(void) enable_lapic(); /* Set Task Priority to 'accept all' */ - lapic_write_around(LAPIC_TASKPRI, - lapic_read_around(LAPIC_TASKPRI) & ~LAPIC_TPRI_MASK); + lapic_write(LAPIC_TASKPRI, + lapic_read(LAPIC_TASKPRI) & ~LAPIC_TPRI_MASK); /* Put the local apic in virtual wire mode */ - lapic_write_around(LAPIC_SPIV, (lapic_read_around(LAPIC_SPIV) & - ~(LAPIC_VECTOR_MASK)) | LAPIC_SPIV_ENABLE); - lapic_write_around(LAPIC_LVT0, (lapic_read_around(LAPIC_LVT0) & - ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | - LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | - LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | - LAPIC_DELIVERY_MODE_MASK)) | - (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | - LAPIC_DELIVERY_MODE_EXTINT)); - lapic_write_around(LAPIC_LVT1, (lapic_read_around(LAPIC_LVT1) & - ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | - LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | - LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | - LAPIC_DELIVERY_MODE_MASK)) | - (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | - LAPIC_DELIVERY_MODE_NMI)); + lapic_write(LAPIC_SPIV, (lapic_read(LAPIC_SPIV) & + ~(LAPIC_VECTOR_MASK)) | LAPIC_SPIV_ENABLE); + lapic_write(LAPIC_LVT0, (lapic_read(LAPIC_LVT0) & + ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | + LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | + LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | + LAPIC_DELIVERY_MODE_MASK)) | + (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | + LAPIC_DELIVERY_MODE_EXTINT)); + lapic_write(LAPIC_LVT1, (lapic_read(LAPIC_LVT1) & + ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | + LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | + LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | + LAPIC_DELIVERY_MODE_MASK)) | + (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | + LAPIC_DELIVERY_MODE_NMI)); debug("apic_id: 0x%02lx, ", lapicid()); #else /* !CONFIG_SMP */ diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index e8bc9b6..e686b28 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -16,7 +16,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -59,6 +61,13 @@ static inline void release_barrier(atomic_t *b) atomic_set(b, 1); } +static inline void stop_this_cpu(void) +{ + /* Called by an AP when it is ready to halt and wait for a new task */ + for (;;) + cpu_hlt(); +} + /* Returns 1 if timeout waiting for APs. 0 if target APs found */ static int wait_for_aps(atomic_t *val, int target, int total_delay, int delay_step) @@ -317,9 +326,9 @@ static int start_aps(int ap_count, atomic_t *num_aps) } /* Send INIT IPI to all but self */ - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); - lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | - LAPIC_DM_INIT); + lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); + lapic_write(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | + LAPIC_DM_INIT); debug("Waiting for 10ms after sending INIT.\n"); mdelay(10); @@ -334,9 +343,9 @@ static int start_aps(int ap_count, atomic_t *num_aps) } } - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); - lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | - LAPIC_DM_STARTUP | sipi_vector); + lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); + lapic_write(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | + LAPIC_DM_STARTUP | sipi_vector); debug("Waiting for 1st SIPI to complete..."); if (apic_wait_timeout(10000, 50)) { debug("timed out.\n"); @@ -359,9 +368,9 @@ static int start_aps(int ap_count, atomic_t *num_aps) } } - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); - lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | - LAPIC_DM_STARTUP | sipi_vector); + lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); + lapic_write(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | + LAPIC_DM_STARTUP | sipi_vector); debug("Waiting for 2nd SIPI to complete..."); if (apic_wait_timeout(10000, 50)) { debug("timed out.\n"); diff --git a/arch/x86/include/asm/lapic.h b/arch/x86/include/asm/lapic.h index f60974a..bc2b2d1 100644 --- a/arch/x86/include/asm/lapic.h +++ b/arch/x86/include/asm/lapic.h @@ -9,11 +9,6 @@ #ifndef _ARCH_ASM_LAPIC_H #define _ARCH_ASM_LAPIC_H -#include -#include -#include -#include - #define LAPIC_DEFAULT_BASE 0xfee00000 #define LAPIC_ID 0x020 @@ -66,126 +61,17 @@ #define LAPIC_DELIVERY_MODE_NMI (4 << 8) #define LAPIC_DELIVERY_MODE_EXTINT (7 << 8) -static inline __attribute__((always_inline)) - unsigned long lapic_read(unsigned long reg) -{ - return readl(LAPIC_DEFAULT_BASE + reg); -} - -static inline __attribute__((always_inline)) - void lapic_write(unsigned long reg, unsigned long val) -{ - writel(val, LAPIC_DEFAULT_BASE + reg); -} - -static inline __attribute__((always_inline)) void lapic_wait_icr_idle(void) -{ - do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY); -} - -static inline void enable_lapic(void) -{ - msr_t msr; - - msr = msr_read(MSR_IA32_APICBASE); - msr.hi &= 0xffffff00; - msr.lo |= MSR_IA32_APICBASE_ENABLE; - msr.lo &= ~MSR_IA32_APICBASE_BASE; - msr.lo |= LAPIC_DEFAULT_BASE; - msr_write(MSR_IA32_APICBASE, msr); -} - -static inline void disable_lapic(void) -{ - msr_t msr; - - msr = msr_read(MSR_IA32_APICBASE); - msr.lo &= ~MSR_IA32_APICBASE_ENABLE; - msr_write(MSR_IA32_APICBASE, msr); -} - -static inline __attribute__((always_inline)) unsigned long lapicid(void) -{ - return lapic_read(LAPIC_ID) >> 24; -} - -static inline __attribute__((always_inline)) void stop_this_cpu(void) -{ - /* Called by an AP when it is ready to halt and wait for a new task */ - for (;;) - cpu_hlt(); -} - -#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \ - sizeof(*(ptr)))) - -struct __xchg_dummy { unsigned long a[100]; }; -#define __xg(x) ((struct __xchg_dummy *)(x)) +unsigned long lapic_read(unsigned long reg); -/* - * Note: no "lock" prefix even on SMP. xchg always implies lock anyway. - * - * Note 2: xchg has side effect, so that attribute volatile is necessary, - * but generally the primitive is invalid, *ptr is output argument. - */ -static inline unsigned long __xchg(unsigned long x, volatile void *ptr, - int size) -{ - switch (size) { - case 1: - __asm__ __volatile__("xchgb %b0,%1" - : "=q" (x) - : "m" (*__xg(ptr)), "0" (x) - : "memory"); - break; - case 2: - __asm__ __volatile__("xchgw %w0,%1" - : "=r" (x) - : "m" (*__xg(ptr)), "0" (x) - : "memory"); - break; - case 4: - __asm__ __volatile__("xchgl %0,%1" - : "=r" (x) - : "m" (*__xg(ptr)), "0" (x) - : "memory"); - break; - } - - return x; -} - -static inline void lapic_write_atomic(unsigned long reg, unsigned long v) -{ - (void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v); -} - -#define lapic_read_around(x) lapic_read(x) -#define lapic_write_around(x, y) lapic_write_atomic((x), (y)) - -static inline int lapic_remote_read(int apicid, int reg, unsigned long *pvalue) -{ - int timeout; - unsigned long status; - int result; - - lapic_wait_icr_idle(); - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); - lapic_write_around(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4)); - - timeout = 0; - do { - status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK; - } while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000); - - result = -1; - if (status == LAPIC_ICR_RR_VALID) { - *pvalue = lapic_read(LAPIC_RRR); - result = 0; - } - - return result; -} +void lapic_write(unsigned long reg, unsigned long v); + +void enable_lapic(void); + +void disable_lapic(void); + +unsigned long lapicid(void); + +int lapic_remote_read(int apicid, int reg, unsigned long *pvalue); void lapic_setup(void); -- cgit v0.10.2 From 7f5df8d42d8eb0fbdb6bf168fd530aa0f01b99c7 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:51 +0800 Subject: x86: Add MultiProcessor (MP) table APIs The MP table provides a way for the operating system to support for symmetric multiprocessing as well as symmetric I/O interrupt handling with the local APIC and I/O APIC. We provide a bunch of APIs for U-Boot to write the floating table, configuration table header as well as base and extended table entries. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/include/asm/mpspec.h b/arch/x86/include/asm/mpspec.h new file mode 100644 index 0000000..849113a --- /dev/null +++ b/arch/x86/include/asm/mpspec.h @@ -0,0 +1,434 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * Adapted from coreboot src/arch/x86/include/arch/smp/mpspec.h + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __ASM_MPSPEC_H +#define __ASM_MPSPEC_H + +/* + * Structure definitions for SMP machines following the + * Intel MultiProcessor Specification 1.4 + */ + +#define MPSPEC_V14 4 + +#define MPF_SIGNATURE "_MP_" + +struct mp_floating_table { + char mpf_signature[4]; /* "_MP_" */ + u32 mpf_physptr; /* Configuration table address */ + u8 mpf_length; /* Our length (paragraphs) */ + u8 mpf_spec; /* Specification version */ + u8 mpf_checksum; /* Checksum (makes sum 0) */ + u8 mpf_feature1; /* Predefined or Unique configuration? */ + u8 mpf_feature2; /* Bit7 set for IMCR/PIC */ + u8 mpf_feature3; /* Unused (0) */ + u8 mpf_feature4; /* Unused (0) */ + u8 mpf_feature5; /* Unused (0) */ +}; + +#define MPC_SIGNATURE "PCMP" + +struct mp_config_table { + char mpc_signature[4]; /* "PCMP" */ + u16 mpc_length; /* Size of table */ + u8 mpc_spec; /* Specification version */ + u8 mpc_checksum; /* Checksum (makes sum 0) */ + char mpc_oem[8]; /* OEM ID */ + char mpc_product[12]; /* Product ID */ + u32 mpc_oemptr; /* OEM table address */ + u16 mpc_oemsize; /* OEM table size */ + u16 mpc_entry_count; /* Number of entries in the table */ + u32 mpc_lapic; /* Local APIC address */ + u16 mpe_length; /* Extended table size */ + u8 mpe_checksum; /* Extended table checksum */ + u8 reserved; +}; + +/* Base MP configuration table entry types */ + +enum mp_base_config_entry_type { + MP_PROCESSOR, + MP_BUS, + MP_IOAPIC, + MP_INTSRC, + MP_LINTSRC +}; + +#define MPC_CPU_EN (1 << 0) +#define MPC_CPU_BP (1 << 1) + +struct mpc_config_processor { + u8 mpc_type; + u8 mpc_apicid; + u8 mpc_apicver; + u8 mpc_cpuflag; + u32 mpc_cpusignature; + u32 mpc_cpufeature; + u32 mpc_reserved[2]; +}; + +#define BUSTYPE_CBUS "CBUS " +#define BUSTYPE_CBUSII "CBUSII" +#define BUSTYPE_EISA "EISA " +#define BUSTYPE_FUTURE "FUTURE" +#define BUSTYPE_INTERN "INTERN" +#define BUSTYPE_ISA "ISA " +#define BUSTYPE_MBI "MBI " +#define BUSTYPE_MBII "MBII " +#define BUSTYPE_MCA "MCA " +#define BUSTYPE_MPI "MPI " +#define BUSTYPE_MPSA "MPSA " +#define BUSTYPE_NUBUS "NUBUS " +#define BUSTYPE_PCI "PCI " +#define BUSTYPE_PCMCIA "PCMCIA" +#define BUSTYPE_TC "TC " +#define BUSTYPE_VL "VL " +#define BUSTYPE_VME "VME " +#define BUSTYPE_XPRESS "XPRESS" + +struct mpc_config_bus { + u8 mpc_type; + u8 mpc_busid; + u8 mpc_bustype[6]; +}; + +#define MPC_APIC_USABLE (1 << 0) + +struct mpc_config_ioapic { + u8 mpc_type; + u8 mpc_apicid; + u8 mpc_apicver; + u8 mpc_flags; + u32 mpc_apicaddr; +}; + +enum mp_irq_source_types { + MP_INT, + MP_NMI, + MP_SMI, + MP_EXTINT +}; + +#define MP_IRQ_POLARITY_DEFAULT 0x0 +#define MP_IRQ_POLARITY_HIGH 0x1 +#define MP_IRQ_POLARITY_LOW 0x3 +#define MP_IRQ_POLARITY_MASK 0x3 +#define MP_IRQ_TRIGGER_DEFAULT 0x0 +#define MP_IRQ_TRIGGER_EDGE 0x4 +#define MP_IRQ_TRIGGER_LEVEL 0xc +#define MP_IRQ_TRIGGER_MASK 0xc + +#define MP_APIC_ALL 0xff + +struct mpc_config_intsrc { + u8 mpc_type; + u8 mpc_irqtype; + u16 mpc_irqflag; + u8 mpc_srcbus; + u8 mpc_srcbusirq; + u8 mpc_dstapic; + u8 mpc_dstirq; +}; + +struct mpc_config_lintsrc { + u8 mpc_type; + u8 mpc_irqtype; + u16 mpc_irqflag; + u8 mpc_srcbusid; + u8 mpc_srcbusirq; + u8 mpc_destapic; + u8 mpc_destlint; +}; + +/* Extended MP configuration table entry types */ + +enum mp_ext_config_entry_type { + MPE_SYSTEM_ADDRESS_SPACE = 128, + MPE_BUS_HIERARCHY, + MPE_COMPAT_ADDRESS_SPACE +}; + +struct mp_ext_config { + u8 mpe_type; + u8 mpe_length; +}; + +#define ADDRESS_TYPE_IO 0 +#define ADDRESS_TYPE_MEM 1 +#define ADDRESS_TYPE_PREFETCH 2 + +struct mp_ext_system_address_space { + u8 mpe_type; + u8 mpe_length; + u8 mpe_busid; + u8 mpe_addr_type; + u32 mpe_addr_base_low; + u32 mpe_addr_base_high; + u32 mpe_addr_length_low; + u32 mpe_addr_length_high; +}; + +#define BUS_SUBTRACTIVE_DECODE (1 << 0) + +struct mp_ext_bus_hierarchy { + u8 mpe_type; + u8 mpe_length; + u8 mpe_busid; + u8 mpe_bus_info; + u8 mpe_parent_busid; + u8 reserved[3]; +}; + +#define ADDRESS_RANGE_ADD 0 +#define ADDRESS_RANGE_SUBTRACT 1 + +/* + * X100 - X3FF + * X500 - X7FF + * X900 - XBFF + * XD00 - XFFF + */ +#define RANGE_LIST_IO_ISA 0 +/* + * X3B0 - X3BB + * X3C0 - X3DF + * X7B0 - X7BB + * X7C0 - X7DF + * XBB0 - XBBB + * XBC0 - XBDF + * XFB0 - XFBB + * XFC0 - XCDF + */ +#define RANGE_LIST_IO_VGA 1 + +struct mp_ext_compat_address_space { + u8 mpe_type; + u8 mpe_length; + u8 mpe_busid; + u8 mpe_addr_modifier; + u32 mpe_range_list; +}; + +/** + * mp_next_mpc_entry() - Compute MP configuration table end to be used as + * next base table entry start address + * + * This computes the end address of current MP configuration table, without + * counting any extended configuration table entry. + * + * @mc: configuration table header address + * @return: configuration table end address + */ +static inline u32 mp_next_mpc_entry(struct mp_config_table *mc) +{ + return (u32)mc + mc->mpc_length; +} + +/** + * mp_add_mpc_entry() - Add a base MP configuration table entry + * + * This adds the base MP configuration table entry size with + * added base table entry length and increases entry count by 1. + * + * @mc: configuration table header address + * @length: length of the added table entry + */ +static inline void mp_add_mpc_entry(struct mp_config_table *mc, uint length) +{ + mc->mpc_length += length; + mc->mpc_entry_count++; +} + +/** + * mp_next_mpe_entry() - Compute MP configuration table end to be used as + * next extended table entry start address + * + * This computes the end address of current MP configuration table, + * including any extended configuration table entry. + * + * @mc: configuration table header address + * @return: configuration table end address + */ +static inline u32 mp_next_mpe_entry(struct mp_config_table *mc) +{ + return (u32)mc + mc->mpc_length + mc->mpe_length; +} + +/** + * mp_add_mpe_entry() - Add an extended MP configuration table entry + * + * This adds the extended MP configuration table entry size with + * added extended table entry length. + * + * @mc: configuration table header address + * @mpe: extended table entry base address + */ +static inline void mp_add_mpe_entry(struct mp_config_table *mc, + struct mp_ext_config *mpe) +{ + mc->mpe_length += mpe->mpe_length; +} + +/** + * mp_write_floating_table() - Write the MP floating table + * + * This writes the MP floating table, and points MP configuration table + * to its end address so that MP configuration table follows immediately + * after the floating table. + * + * @mf: MP floating table base address + * @return: MP configuration table header address + */ +struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf); + +/** + * mp_config_table_init() - Initialize the MP configuration table header + * + * This populates the MP configuration table header with valid bits. + * + * @mc: MP configuration table header address + */ +void mp_config_table_init(struct mp_config_table *mc); + +/** + * mp_write_processor() - Write a processor entry + * + * This writes a processor entry to the configuration table. + * + * @mc: MP configuration table header address + */ +void mp_write_processor(struct mp_config_table *mc); + +/** + * mp_write_bus() - Write a bus entry + * + * This writes a bus entry to the configuration table. + * + * @mc: MP configuration table header address + * @id: bus id + * @bustype: bus type name + */ +void mp_write_bus(struct mp_config_table *mc, int id, const char *bustype); + +/** + * mp_write_ioapic() - Write an I/O APIC entry + * + * This writes an I/O APIC entry to the configuration table. + * + * @mc: MP configuration table header address + * @id: I/O APIC id + * @ver: I/O APIC version + * @apicaddr: I/O APIC address + */ +void mp_write_ioapic(struct mp_config_table *mc, int id, int ver, u32 apicaddr); + +/** + * mp_write_intsrc() - Write an I/O interrupt assignment entry + * + * This writes an I/O interrupt assignment entry to the configuration table. + * + * @mc: MP configuration table header address + * @irqtype: IRQ type (INT/NMI/SMI/ExtINT) + * @irqflag: IRQ flag (level/trigger) + * @srcbus: source bus id where the interrupt comes from + * @srcbusirq: IRQ number mapped on the source bus + * @dstapic: destination I/O APIC id where the interrupt goes to + * @dstirq: destination I/O APIC pin where the interrupt goes to + */ +void mp_write_intsrc(struct mp_config_table *mc, int irqtype, int irqflag, + int srcbus, int srcbusirq, int dstapic, int dstirq); + +/** + * mp_write_pci_intsrc() - Write a PCI interrupt assignment entry + * + * This writes a PCI interrupt assignment entry to the configuration table. + * + * @mc: MP configuration table header address + * @irqtype: IRQ type (INT/NMI/SMI/ExtINT) + * @srcbus: PCI bus number where the interrupt comes from + * @dev: device number on the PCI bus + * @pin: PCI interrupt pin (INT A/B/C/D) + * @dstapic: destination I/O APIC id where the interrupt goes to + * @dstirq: destination I/O APIC pin where the interrupt goes to + */ +void mp_write_pci_intsrc(struct mp_config_table *mc, int irqtype, + int srcbus, int dev, int pin, int dstapic, int dstirq); + +/** + * mp_write_lintsrc() - Write a local interrupt assignment entry + * + * This writes a local interrupt assignment entry to the configuration table. + * + * @mc: MP configuration table header address + * @irqtype: IRQ type (INT/NMI/SMI/ExtINT) + * @irqflag: IRQ flag (level/trigger) + * @srcbus: PCI bus number where the interrupt comes from + * @srcbusirq: IRQ number mapped on the source bus + * @dstapic: destination local APIC id where the interrupt goes to + * @destlint: destination local APIC pin where the interrupt goes to + */ +void mp_write_lintsrc(struct mp_config_table *mc, int irqtype, int irqflag, + int srcbus, int srcbusirq, int destapic, int destlint); + + +/** + * mp_write_address_space() - Write a system address space entry + * + * This writes a system address space entry to the configuration table. + * + * @mc: MP configuration table header address + * @busid: bus id for the bus where system address space is mapped + * @addr_type: system address type + * @addr_base_low: starting address low + * @addr_base_high: starting address high + * @addr_length_low: address length low + * @addr_length_high: address length high + */ +void mp_write_address_space(struct mp_config_table *mc, + int busid, int addr_type, + u32 addr_base_low, u32 addr_base_high, + u32 addr_length_low, u32 addr_length_high); + +/** + * mp_write_bus_hierarchy() - Write a bus hierarchy descriptor entry + * + * This writes a bus hierarchy descriptor entry to the configuration table. + * + * @mc: MP configuration table header address + * @busid: bus id + * @bus_info: bit0 indicates if the bus is a subtractive decode bus + * @parent_busid: parent bus id + */ +void mp_write_bus_hierarchy(struct mp_config_table *mc, + int busid, int bus_info, int parent_busid); + +/** + * mp_write_compat_address_space() - Write a compat bus address space entry + * + * This writes a compatibility bus address space modifier entry to the + * configuration table. + * + * @mc: MP configuration table header address + * @busid: bus id + * @addr_modifier: add or subtract to predefined address range list + * @range_list: list of predefined address space ranges + */ +void mp_write_compat_address_space(struct mp_config_table *mc, int busid, + int addr_modifier, u32 range_list); + +/** + * mptable_finalize() - Finalize the MP table + * + * This finalizes the MP table by calculating required checksums. + * + * @mc: MP configuration table header address + * @return: MP table end address + */ +u32 mptable_finalize(struct mp_config_table *mc); + +#endif /* __ASM_MPSPEC_H */ diff --git a/arch/x86/include/asm/tables.h b/arch/x86/include/asm/tables.h index 8146ba3..0aa6d9b 100644 --- a/arch/x86/include/asm/tables.h +++ b/arch/x86/include/asm/tables.h @@ -28,6 +28,20 @@ u8 table_compute_checksum(void *v, int len); /** + * table_fill_string() - Fill a string with pad in the configuration table + * + * This fills a string in the configuration table. It copies number of bytes + * from the source string, and if source string length is shorter than the + * required size to copy, pad the table string with the given pad character. + * + * @dest: where to fill a string + * @src: where to copy from + * @n: number of bytes to copy + * @pad: character to pad the remaining bytes + */ +void table_fill_string(char *dest, const char *src, size_t n, char pad); + +/** * write_tables() - Write x86 configuration tables * * This writes x86 configuration tables, including PIRQ routing table, diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 70ad19b..43489fd 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -15,6 +15,7 @@ obj-y += gcc.o obj-y += init_helpers.o obj-y += interrupts.o obj-y += lpc-uclass.o +obj-y += mpspec.o obj-y += cmd_mtrr.o obj-$(CONFIG_SYS_PCAT_INTERRUPTS) += pcat_interrupts.o obj-$(CONFIG_SYS_PCAT_TIMER) += pcat_timer.o diff --git a/arch/x86/lib/mpspec.c b/arch/x86/lib/mpspec.c new file mode 100644 index 0000000..26d1025 --- /dev/null +++ b/arch/x86/lib/mpspec.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * Adapted from coreboot src/arch/x86/boot/mpspec.c + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf) +{ + u32 mc; + + memcpy(mf->mpf_signature, MPF_SIGNATURE, 4); + mf->mpf_physptr = (u32)mf + sizeof(struct mp_floating_table); + mf->mpf_length = 1; + mf->mpf_spec = MPSPEC_V14; + mf->mpf_checksum = 0; + /* We don't use the default configuration table */ + mf->mpf_feature1 = 0; + /* Indicate that virtual wire mode is always implemented */ + mf->mpf_feature2 = 0; + mf->mpf_feature3 = 0; + mf->mpf_feature4 = 0; + mf->mpf_feature5 = 0; + mf->mpf_checksum = table_compute_checksum(mf, mf->mpf_length * 16); + + mc = (u32)mf + sizeof(struct mp_floating_table); + return (struct mp_config_table *)mc; +} + +void mp_config_table_init(struct mp_config_table *mc) +{ + memcpy(mc->mpc_signature, MPC_SIGNATURE, 4); + mc->mpc_length = sizeof(struct mp_config_table); + mc->mpc_spec = MPSPEC_V14; + mc->mpc_checksum = 0; + mc->mpc_oemptr = 0; + mc->mpc_oemsize = 0; + mc->mpc_entry_count = 0; + mc->mpc_lapic = LAPIC_DEFAULT_BASE; + mc->mpe_length = 0; + mc->mpe_checksum = 0; + mc->reserved = 0; + + /* The oem/product id fields are exactly 8/12 bytes long */ + table_fill_string(mc->mpc_oem, CONFIG_SYS_VENDOR, 8, ' '); + table_fill_string(mc->mpc_product, CONFIG_SYS_BOARD, 12, ' '); +} + +void mp_write_processor(struct mp_config_table *mc) +{ + struct mpc_config_processor *mpc; + struct udevice *dev; + u8 boot_apicid, apicver; + u32 cpusignature, cpufeature; + struct cpuid_result result; + + boot_apicid = lapicid(); + apicver = lapic_read(LAPIC_LVR) & 0xff; + result = cpuid(1); + cpusignature = result.eax; + cpufeature = result.edx; + + for (uclass_find_first_device(UCLASS_CPU, &dev); + dev; + uclass_find_next_device(&dev)) { + struct cpu_platdata *plat = dev_get_parent_platdata(dev); + u8 cpuflag = MPC_CPU_EN; + + if (!device_active(dev)) + continue; + + mpc = (struct mpc_config_processor *)mp_next_mpc_entry(mc); + mpc->mpc_type = MP_PROCESSOR; + mpc->mpc_apicid = plat->cpu_id; + mpc->mpc_apicver = apicver; + if (boot_apicid == plat->cpu_id) + cpuflag |= MPC_CPU_BP; + mpc->mpc_cpuflag = cpuflag; + mpc->mpc_cpusignature = cpusignature; + mpc->mpc_cpufeature = cpufeature; + mpc->mpc_reserved[0] = 0; + mpc->mpc_reserved[1] = 0; + mp_add_mpc_entry(mc, sizeof(*mpc)); + } +} + +void mp_write_bus(struct mp_config_table *mc, int id, const char *bustype) +{ + struct mpc_config_bus *mpc; + + mpc = (struct mpc_config_bus *)mp_next_mpc_entry(mc); + mpc->mpc_type = MP_BUS; + mpc->mpc_busid = id; + memcpy(mpc->mpc_bustype, bustype, 6); + mp_add_mpc_entry(mc, sizeof(*mpc)); +} + +void mp_write_ioapic(struct mp_config_table *mc, int id, int ver, u32 apicaddr) +{ + struct mpc_config_ioapic *mpc; + + mpc = (struct mpc_config_ioapic *)mp_next_mpc_entry(mc); + mpc->mpc_type = MP_IOAPIC; + mpc->mpc_apicid = id; + mpc->mpc_apicver = ver; + mpc->mpc_flags = MPC_APIC_USABLE; + mpc->mpc_apicaddr = apicaddr; + mp_add_mpc_entry(mc, sizeof(*mpc)); +} + +void mp_write_intsrc(struct mp_config_table *mc, int irqtype, int irqflag, + int srcbus, int srcbusirq, int dstapic, int dstirq) +{ + struct mpc_config_intsrc *mpc; + + mpc = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc); + mpc->mpc_type = MP_INTSRC; + mpc->mpc_irqtype = irqtype; + mpc->mpc_irqflag = irqflag; + mpc->mpc_srcbus = srcbus; + mpc->mpc_srcbusirq = srcbusirq; + mpc->mpc_dstapic = dstapic; + mpc->mpc_dstirq = dstirq; + mp_add_mpc_entry(mc, sizeof(*mpc)); +} + +void mp_write_pci_intsrc(struct mp_config_table *mc, int irqtype, + int srcbus, int dev, int pin, int dstapic, int dstirq) +{ + u8 srcbusirq = (dev << 2) | (pin - 1); + + mp_write_intsrc(mc, irqtype, MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW, + srcbus, srcbusirq, dstapic, dstirq); +} + +void mp_write_lintsrc(struct mp_config_table *mc, int irqtype, int irqflag, + int srcbus, int srcbusirq, int destapic, int destlint) +{ + struct mpc_config_lintsrc *mpc; + + mpc = (struct mpc_config_lintsrc *)mp_next_mpc_entry(mc); + mpc->mpc_type = MP_LINTSRC; + mpc->mpc_irqtype = irqtype; + mpc->mpc_irqflag = irqflag; + mpc->mpc_srcbusid = srcbus; + mpc->mpc_srcbusirq = srcbusirq; + mpc->mpc_destapic = destapic; + mpc->mpc_destlint = destlint; + mp_add_mpc_entry(mc, sizeof(*mpc)); +} + +void mp_write_address_space(struct mp_config_table *mc, + int busid, int addr_type, + u32 addr_base_low, u32 addr_base_high, + u32 addr_length_low, u32 addr_length_high) +{ + struct mp_ext_system_address_space *mpe; + + mpe = (struct mp_ext_system_address_space *)mp_next_mpe_entry(mc); + mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE; + mpe->mpe_length = sizeof(*mpe); + mpe->mpe_busid = busid; + mpe->mpe_addr_type = addr_type; + mpe->mpe_addr_base_low = addr_base_low; + mpe->mpe_addr_base_high = addr_base_high; + mpe->mpe_addr_length_low = addr_length_low; + mpe->mpe_addr_length_high = addr_length_high; + mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); +} + +void mp_write_bus_hierarchy(struct mp_config_table *mc, + int busid, int bus_info, int parent_busid) +{ + struct mp_ext_bus_hierarchy *mpe; + + mpe = (struct mp_ext_bus_hierarchy *)mp_next_mpe_entry(mc); + mpe->mpe_type = MPE_BUS_HIERARCHY; + mpe->mpe_length = sizeof(*mpe); + mpe->mpe_busid = busid; + mpe->mpe_bus_info = bus_info; + mpe->mpe_parent_busid = parent_busid; + mpe->reserved[0] = 0; + mpe->reserved[1] = 0; + mpe->reserved[2] = 0; + mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); +} + +void mp_write_compat_address_space(struct mp_config_table *mc, int busid, + int addr_modifier, u32 range_list) +{ + struct mp_ext_compat_address_space *mpe; + + mpe = (struct mp_ext_compat_address_space *)mp_next_mpe_entry(mc); + mpe->mpe_type = MPE_COMPAT_ADDRESS_SPACE; + mpe->mpe_length = sizeof(*mpe); + mpe->mpe_busid = busid; + mpe->mpe_addr_modifier = addr_modifier; + mpe->mpe_range_list = range_list; + mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); +} + +u32 mptable_finalize(struct mp_config_table *mc) +{ + u32 end; + + mc->mpe_checksum = table_compute_checksum((void *)mp_next_mpc_entry(mc), + mc->mpe_length); + mc->mpc_checksum = table_compute_checksum(mc, mc->mpc_length); + end = mp_next_mpe_entry(mc); + + debug("Write the MP table at: %x - %x\n", (u32)mc, end); + + return end; +} diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index 8031201..41c50bc 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -20,6 +20,20 @@ u8 table_compute_checksum(void *v, int len) return checksum; } +void table_fill_string(char *dest, const char *src, size_t n, char pad) +{ + int start, len; + int i; + + strncpy(dest, src, n); + + /* Fill the remaining bytes with pad */ + len = strlen(src); + start = len < n ? len : n; + for (i = start; i < n; i++) + dest[i] = pad; +} + void write_tables(void) { u32 __maybe_unused rom_table_end = ROM_TABLE_ADDR; -- cgit v0.10.2 From 07545d861ccc54aecbeaa51b264258b90912b856 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:52 +0800 Subject: x86: Generate a valid MultiProcessor (MP) table Implement write_mp_table() to create a minimal working MP table. This includes an MP floating table, a configuration table header and all of the 5 base configuration table entries. The I/O interrupt assignment table entry is created based on the same information used in the creation of PIRQ routing table from device tree. A check duplicated entry logic is applied to prevent writing multiple I/O interrupt entries with the same information. Use a Kconfig option GENERATE_MP_TABLE to tell U-Boot whether we need actually write the MP table at the F seg, just like we did for PIRQ routing and SFI tables. With MP table existence, linux kernel will switch to I/O APIC and local APIC to process all the peripheral interrupts instead of 8259 PICs. This takes full advantage of the multicore hardware and the SMP kernel. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 36e97c8..b52a80e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -313,6 +313,15 @@ config GENERATE_SFI_TABLE For more information, see http://simplefirmware.org +config GENERATE_MP_TABLE + bool "Generate an MP (Multi-Processor) table" + default n + help + Generate an MP (Multi-Processor) table for this board. The MP table + provides a way for the operating system to support for symmetric + multiprocessing as well as symmetric I/O interrupt handling with + the local APIC and I/O APIC. + endmenu config MAX_PIRQ_LINKS diff --git a/arch/x86/include/asm/mpspec.h b/arch/x86/include/asm/mpspec.h index 849113a..efa9231 100644 --- a/arch/x86/include/asm/mpspec.h +++ b/arch/x86/include/asm/mpspec.h @@ -431,4 +431,14 @@ void mp_write_compat_address_space(struct mp_config_table *mc, int busid, */ u32 mptable_finalize(struct mp_config_table *mc); +/** + * write_mp_table() - Write MP table + * + * This writes MP table at a given address. + * + * @addr: start address to write MP table + * @return: end address of MP table + */ +u32 write_mp_table(u32 addr); + #endif /* __ASM_MPSPEC_H */ diff --git a/arch/x86/lib/mpspec.c b/arch/x86/lib/mpspec.c index 26d1025..f16fbcb 100644 --- a/arch/x86/lib/mpspec.c +++ b/arch/x86/lib/mpspec.c @@ -9,13 +9,18 @@ #include #include #include +#include +#include #include +#include #include #include #include #include #include +DECLARE_GLOBAL_DATA_PTR; + struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf) { u32 mc; @@ -223,3 +228,155 @@ u32 mptable_finalize(struct mp_config_table *mc) return end; } + +static void mptable_add_isa_interrupts(struct mp_config_table *mc, int bus_isa, + int apicid, int external_int2) +{ + int i; + + mp_write_intsrc(mc, external_int2 ? MP_INT : MP_EXTINT, + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, 0, apicid, 0); + mp_write_intsrc(mc, MP_INT, MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, 1, apicid, 1); + mp_write_intsrc(mc, external_int2 ? MP_EXTINT : MP_INT, + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, 0, apicid, 2); + + for (i = 3; i < 16; i++) + mp_write_intsrc(mc, MP_INT, + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, i, apicid, i); +} + +/* + * Check duplicated I/O interrupt assignment table entry, to make sure + * there is only one entry with the given bus, device and interrupt pin. + */ +static bool check_dup_entry(struct mpc_config_intsrc *intsrc_base, + int entry_num, int bus, int device, int pin) +{ + struct mpc_config_intsrc *intsrc = intsrc_base; + int i; + + for (i = 0; i < entry_num; i++) { + if (intsrc->mpc_srcbus == bus && + intsrc->mpc_srcbusirq == ((device << 2) | (pin - 1))) + break; + intsrc++; + } + + return (i == entry_num) ? false : true; +} + +static int mptable_add_intsrc(struct mp_config_table *mc, + int bus_isa, int apicid) +{ + struct mpc_config_intsrc *intsrc_base; + int intsrc_entries = 0; + const void *blob = gd->fdt_blob; + int node; + int len, count; + const u32 *cell; + int i; + + /* Legacy Interrupts */ + debug("Writing ISA IRQs\n"); + mptable_add_isa_interrupts(mc, bus_isa, apicid, 0); + + /* Get I/O interrupt information from device tree */ + node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_IRQ_ROUTER); + if (node < 0) { + debug("%s: Cannot find irq router node\n", __func__); + return -ENOENT; + } + + cell = fdt_getprop(blob, node, "intel,pirq-routing", &len); + if (!cell) + return -ENOENT; + + if ((len % sizeof(struct pirq_routing)) == 0) + count = len / sizeof(struct pirq_routing); + else + return -EINVAL; + + intsrc_base = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc); + + for (i = 0; i < count; i++) { + struct pirq_routing pr; + + pr.bdf = fdt_addr_to_cpu(cell[0]); + pr.pin = fdt_addr_to_cpu(cell[1]); + pr.pirq = fdt_addr_to_cpu(cell[2]); + + if (check_dup_entry(intsrc_base, intsrc_entries, + PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), pr.pin)) { + debug("found entry for bus %d device %d INT%c, skipping\n", + PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), + 'A' + pr.pin - 1); + cell += sizeof(struct pirq_routing) / sizeof(u32); + continue; + } + + /* PIRQ[A-H] are always connected to I/O APIC INTPIN#16-23 */ + mp_write_pci_intsrc(mc, MP_INT, PCI_BUS(pr.bdf), + PCI_DEV(pr.bdf), pr.pin, apicid, + pr.pirq + 16); + intsrc_entries++; + cell += sizeof(struct pirq_routing) / sizeof(u32); + } + + return 0; +} + +static void mptable_add_lintsrc(struct mp_config_table *mc, int bus_isa) +{ + mp_write_lintsrc(mc, MP_EXTINT, + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, 0, MP_APIC_ALL, 0); + mp_write_lintsrc(mc, MP_NMI, + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, 0, MP_APIC_ALL, 1); +} + +u32 write_mp_table(u32 addr) +{ + struct mp_config_table *mc; + int ioapic_id, ioapic_ver; + int bus_isa = 0xff; + int ret; + u32 end; + + /* 16 byte align the table address */ + addr = ALIGN(addr, 16); + + /* Write floating table */ + mc = mp_write_floating_table((struct mp_floating_table *)addr); + + /* Write configuration table header */ + mp_config_table_init(mc); + + /* Write processor entry */ + mp_write_processor(mc); + + /* Write bus entry */ + mp_write_bus(mc, bus_isa, BUSTYPE_ISA); + + /* Write I/O APIC entry */ + ioapic_id = io_apic_read(IO_APIC_ID) >> 24; + ioapic_ver = io_apic_read(IO_APIC_VER) & 0xff; + mp_write_ioapic(mc, ioapic_id, ioapic_ver, IO_APIC_ADDR); + + /* Write I/O interrupt assignment entry */ + ret = mptable_add_intsrc(mc, bus_isa, ioapic_id); + if (ret) + debug("Failed to write I/O interrupt assignment table\n"); + + /* Write local interrupt assignment entry */ + mptable_add_lintsrc(mc, bus_isa); + + /* Finalize the MP table */ + end = mptable_finalize(mc); + + return end; +} diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index 41c50bc..75ffbc1 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -6,6 +6,7 @@ #include #include +#include #include u8 table_compute_checksum(void *v, int len) @@ -46,4 +47,8 @@ void write_tables(void) rom_table_end = write_sfi_table(rom_table_end); rom_table_end = ALIGN(rom_table_end, 1024); #endif +#ifdef CONFIG_GENERATE_MP_TABLE + rom_table_end = write_mp_table(rom_table_end); + rom_table_end = ALIGN(rom_table_end, 1024); +#endif } -- cgit v0.10.2 From 1281a1fc97992b8561f500bf2d0f222149031d4b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:53 +0800 Subject: x86: Update README.x86 for SMP support Document U-Boot multi-processor support as well as configuration tables like SFI and MP tables for SMP OS kernel. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/doc/README.x86 b/doc/README.x86 index c19f4a0..49d6e83 100644 --- a/doc/README.x86 +++ b/doc/README.x86 @@ -258,6 +258,17 @@ Modern CPUs usually require a special bit stream called microcode [6] to be loaded on the processor after power up in order to function properly. U-Boot has already integrated these as hex dumps in the source tree. +SMP Support +----------- +On a multicore system, U-Boot is executed on the bootstrap processor (BSP). +Additional application processors (AP) can be brought up by U-Boot. In order to +have an SMP kernel to discover all of the available processors, U-Boot needs to +prepare configuration tables which contain the multi-CPUs information before +loading the OS kernel. Currently U-Boot supports generating two types of tables +for SMP, called Simple Firmware Interface (SFI) [7] and Multi-Processor (MP) [8] +tables. The writing of these two tables are controlled by two Kconfig options +GENERATE_SFI_TABLE and GENERATE_MP_TABLE. + Driver Model ------------ x86 has been converted to use driver model for serial and GPIO. @@ -362,3 +373,5 @@ References [4] http://www.intel.com/content/www/us/en/embedded/design-tools/evaluation-platforms/atom-e660-eg20t-development-kit.html [5] http://www.intel.com/fsp [6] http://en.wikipedia.org/wiki/Microcode +[7] http://simplefirmware.org +[8] http://www.intel.com/design/archives/processors/pro/docs/242016.htm -- cgit v0.10.2 From 07a52865fe4a2e8bce16d9d8f8a61c66b3afa9ee Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:54 +0800 Subject: x86: crownbay: Enable writing MP table Enable writing MP table for Intel Crown Bay board. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/configs/crownbay_defconfig b/configs/crownbay_defconfig index 6c38504..2af93bc 100644 --- a/configs/crownbay_defconfig +++ b/configs/crownbay_defconfig @@ -18,4 +18,5 @@ CONFIG_CPU=y CONFIG_SPI_FLASH=y CONFIG_USE_PRIVATE_LIBGCC=y CONFIG_SYS_VSNPRINTF=y +CONFIG_GENERATE_MP_TABLE=y CONFIG_DM_RTC=y -- cgit v0.10.2 From cdb6babec6422ad4b89e447b1b468f625deaea79 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:55 +0800 Subject: x86: queensbay: Change PCIe root ports' interrupt routing So far interrupt routing works pretty well for any on-chip devices on Intel Crown Bay. When inserting any PCIe card to any PCIe slot, Linux kernel is smart enough to do interrupt swizzling and figure out device's irq using its parent bridge's interrupt routing info all the way up to its root port. In U-Boot all PCIe root ports' interrupts were routed to PIRQ E/F/G/H before, while actually all PCIe downstream ports received INTx are routed to PIRQ A/B/C/D directly and not configurable. Now we change this mapping so that any external PCIe device can work correctly. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/cpu/queensbay/tnc.c b/arch/x86/cpu/queensbay/tnc.c index 873de7b..d27b2d9 100644 --- a/arch/x86/cpu/queensbay/tnc.c +++ b/arch/x86/cpu/queensbay/tnc.c @@ -69,17 +69,18 @@ void cpu_irq_init(void) * Route TunnelCreek PCI device interrupt pin to PIRQ * * Since PCIe downstream ports received INTx are routed to PIRQ - * A/B/C/D directly and not configurable, we route internal PCI - * device's INTx to PIRQ E/F/G/H. + * A/B/C/D directly and not configurable, we have to route PCIe + * root ports' INTx to PIRQ A/B/C/D as well. For other devices + * on TunneCreek, route them to PIRQ E/F/G/H. */ writew(PIRQE, &rcba->d02ir); writew(PIRQF, &rcba->d03ir); writew(PIRQG, &rcba->d27ir); writew(PIRQH, &rcba->d31ir); - writew(PIRQE, &rcba->d23ir); - writew(PIRQF, &rcba->d24ir); - writew(PIRQG, &rcba->d25ir); - writew(PIRQH, &rcba->d26ir); + writew(PIRQA, &rcba->d23ir); + writew(PIRQB, &rcba->d24ir); + writew(PIRQC, &rcba->d25ir); + writew(PIRQD, &rcba->d26ir); } int arch_misc_init(void) diff --git a/arch/x86/dts/crownbay.dts b/arch/x86/dts/crownbay.dts index b77c65a..60da1f5 100644 --- a/arch/x86/dts/crownbay.dts +++ b/arch/x86/dts/crownbay.dts @@ -169,10 +169,22 @@ /* TunnelCreek PCI devices */ PCI_BDF(0, 2, 0) INTA PIRQE PCI_BDF(0, 3, 0) INTA PIRQF - PCI_BDF(0, 23, 0) INTA PIRQE - PCI_BDF(0, 24, 0) INTA PIRQF - PCI_BDF(0, 25, 0) INTA PIRQG - PCI_BDF(0, 26, 0) INTA PIRQH + PCI_BDF(0, 23, 0) INTA PIRQA + PCI_BDF(0, 23, 0) INTB PIRQB + PCI_BDF(0, 23, 0) INTC PIRQC + PCI_BDF(0, 23, 0) INTD PIRQD + PCI_BDF(0, 24, 0) INTA PIRQB + PCI_BDF(0, 24, 0) INTB PIRQC + PCI_BDF(0, 24, 0) INTC PIRQD + PCI_BDF(0, 24, 0) INTD PIRQA + PCI_BDF(0, 25, 0) INTA PIRQC + PCI_BDF(0, 25, 0) INTB PIRQD + PCI_BDF(0, 25, 0) INTC PIRQA + PCI_BDF(0, 25, 0) INTD PIRQB + PCI_BDF(0, 26, 0) INTA PIRQD + PCI_BDF(0, 26, 0) INTB PIRQA + PCI_BDF(0, 26, 0) INTC PIRQB + PCI_BDF(0, 26, 0) INTD PIRQC PCI_BDF(0, 27, 0) INTA PIRQG /* * Topcliff PCI devices -- cgit v0.10.2 From aec241dfb45e7763716c1cbc98942cb01a3a77fd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Jun 2015 08:50:40 -0600 Subject: dm: pci: Use the correct hose when configuring devices Only the PCI controller has access to the PCI region information. Make sure to use the controller (rather than any attached bridges) when configuring devices. This corrects a failure to scan and configure devices when driver model is enabled for PCI. Also add a comment to explain the problem. Signed-off-by: Simon Glass diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index de87505..41d19cb 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -296,6 +296,7 @@ int pci_auto_config_devices(struct udevice *bus) !ret && dev; ret = device_find_next_child(&dev)) { struct pci_child_platdata *pplat; + struct pci_controller *ctlr_hose; pplat = dev_get_parent_platdata(dev); unsigned int max_bus; @@ -303,7 +304,10 @@ int pci_auto_config_devices(struct udevice *bus) bdf = PCI_ADD_BUS(bus->seq, pplat->devfn); debug("%s: device %s\n", __func__, dev->name); - max_bus = pciauto_config_device(hose, bdf); + + /* The root controller has the region information */ + ctlr_hose = hose->ctlr->uclass_priv; + max_bus = pciauto_config_device(ctlr_hose, bdf); sub_bus = max(sub_bus, max_bus); } debug("%s: done\n", __func__); diff --git a/drivers/pci/pci_common.c b/drivers/pci/pci_common.c index b9ff23f..f67c9c7 100644 --- a/drivers/pci/pci_common.c +++ b/drivers/pci/pci_common.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -221,6 +222,11 @@ phys_addr_t pci_hose_bus_to_phys(struct pci_controller *hose, return phys_addr; } +#ifdef CONFIG_DM_PCI + /* The root controller has the region information */ + hose = hose->ctlr->uclass_priv; +#endif + /* * if PCI_REGION_MEM is set we do a two pass search with preference * on matches that don't have PCI_REGION_SYS_MEMORY set diff --git a/include/pci.h b/include/pci.h index 07b1e9a..3af511b 100644 --- a/include/pci.h +++ b/include/pci.h @@ -513,6 +513,16 @@ struct pci_controller { int indirect_type; + /* + * TODO(sjg@chromium.org): With driver model we use struct + * pci_controller for both the controller and any bridge devices + * attached to it. But there is only one region list and it is in the + * top-level controller. + * + * This could be changed so that struct pci_controller is only used + * for PCI controllers and a separate UCLASS (or perhaps + * UCLASS_PCI_GENERIC) is used for bridges. + */ struct pci_region regions[MAX_PCI_REGIONS]; int region_count; -- cgit v0.10.2 From 5afeb4bb456de129a88f38fae1573564cd53fc41 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 7 Jun 2015 08:50:41 -0600 Subject: dm: pci: Correct bus number when scanning sub-buses The sub-bus passed to pciauto_prescan_setup_bridge() is incorrect. Fix it so that sub-buses are numbered correctly. Signed-off-by: Simon Glass diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 41d19cb..edec93f 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -334,7 +334,7 @@ int dm_pci_hose_probe_bus(struct pci_controller *hose, pci_dev_t bdf) sub_bus = pci_get_bus_max() + 1; debug("%s: bus = %d/%s\n", __func__, sub_bus, bus->name); - pciauto_prescan_setup_bridge(hose, bdf, bus->seq); + pciauto_prescan_setup_bridge(hose, bdf, sub_bus); ret = device_probe(bus); if (ret) { -- cgit v0.10.2 From b018a8c71602d53d5d5ebac859f33327b97e9cec Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 6 Jul 2015 16:31:26 +0800 Subject: video: vesa_fb: Look up VGA device by class instead of id Per PCI spec, VGA device reports its class as standard 030000h in its configuration space, so we can use it to determine if we need run option rom instead of testing the supported vendor/device ids. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/drivers/video/vesa_fb.c b/drivers/video/vesa_fb.c index 47f824a..909f8e8 100644 --- a/drivers/video/vesa_fb.c +++ b/drivers/video/vesa_fb.c @@ -1,6 +1,5 @@ /* - * - * Vesa frame buffer driver for x86 + * VESA frame buffer driver * * Copyright (C) 2014 Google, Inc * @@ -17,16 +16,6 @@ */ GraphicDevice ctfb; -/* Devices to allow - only the last one works fully */ -struct pci_device_id vesa_video_ids[] = { - { .vendor = 0x102b, .device = 0x0525 }, - { .vendor = 0x1002, .device = 0x5159 }, - { .vendor = 0x1002, .device = 0x4752 }, - { .vendor = 0x1002, .device = 0x5452 }, - { .vendor = 0x8086, .device = 0x0f31 }, - {}, -}; - void *video_hw_init(void) { GraphicDevice *gdev = &ctfb; @@ -36,8 +25,7 @@ void *video_hw_init(void) printf("Video: "); if (vbe_get_video_info(gdev)) { - /* TODO: Should we look these up by class? */ - dev = pci_find_devices(vesa_video_ids, 0); + dev = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, 0); if (dev == -1) { printf("no card detected\n"); return NULL; -- cgit v0.10.2 From 7b5c3498901712dbd6503bf81c03bb6ea8e3b516 Mon Sep 17 00:00:00 2001 From: Jian Luo Date: Mon, 6 Jul 2015 16:42:06 +0800 Subject: x86: bios: Synchronize stack between real and protected mode PCI option rom may use different SS during its execution, so it is not safe to assume esp pointed to the same location in the protected mode. Signed-off-by: Jian Luo Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/lib/bios_asm.S b/arch/x86/lib/bios_asm.S index 4faa70e..9dbf969 100644 --- a/arch/x86/lib/bios_asm.S +++ b/arch/x86/lib/bios_asm.S @@ -246,6 +246,9 @@ __interrupt_handler_16bit = PTR_TO_REAL_MODE(.) push %fs push %gs + /* Save real mode SS */ + movw %ss, %cs:__realmode_ss + /* Clear DF to not break ABI assumptions */ cld @@ -258,12 +261,29 @@ __interrupt_handler_16bit = PTR_TO_REAL_MODE(.) enter_protected_mode + /* + * Now we are in protected mode. We need compute the right ESP based + * on saved real mode SS otherwise interrupt_handler() won't get + * correct parameters from the stack. + */ + movzwl %cs:__realmode_ss, %ecx + shll $4, %ecx + addl %ecx, %esp + /* Call the C interrupt handler */ movl $interrupt_handler, %eax call *%eax + /* Restore real mode ESP based on saved SS */ + movzwl %cs:__realmode_ss, %ecx + shll $4, %ecx + subl %ecx, %esp + enter_real_mode + /* Restore real mode SS */ + movw %cs:__realmode_ss, %ss + /* * Restore all registers, including those manipulated by the C * handler @@ -276,6 +296,9 @@ __interrupt_handler_16bit = PTR_TO_REAL_MODE(.) popal iret +__realmode_ss = PTR_TO_REAL_MODE(.) + .word 0 + .globl asm_realmode_code_size asm_realmode_code_size: .long . - asm_realmode_code -- cgit v0.10.2 From 1441d81a793507745603c4c3b9481930ebd53822 Mon Sep 17 00:00:00 2001 From: Jian Luo Date: Mon, 6 Jul 2015 16:31:28 +0800 Subject: x86: bios: Allow pci config read/write to host bridge in int1a_handler We should allow pci config read/write to host bridge (b.d.f = 0.0.0) in the int1a_handler() which is a valid pci device. Signed-off-by: Jian Luo Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/lib/bios_interrupts.c b/arch/x86/lib/bios_interrupts.c index 290990a..47d9f59 100644 --- a/arch/x86/lib/bios_interrupts.c +++ b/arch/x86/lib/bios_interrupts.c @@ -161,15 +161,7 @@ int int1a_handler(void) bus = M.x86.R_EBX >> 8; reg = M.x86.R_EDI; dev = PCI_BDF(bus, devfn >> 3, devfn & 7); - if (!dev) { - debug("0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, - bus, devfn); - /* Or are we supposed to return PCIBIOS_NODEV? */ - M.x86.R_EAX &= 0xffff00ff; /* Clear AH */ - M.x86.R_EAX |= PCIBIOS_BADREG; - retval = 0; - return retval; - } + switch (func) { case 0xb108: /* Read Config Byte */ byte = x86_pci_read_config8(dev, reg); -- cgit v0.10.2 From 0e98a1473a85f2d8590f97653a36f90f55267732 Mon Sep 17 00:00:00 2001 From: Jian Luo Date: Mon, 6 Jul 2015 16:31:29 +0800 Subject: video: Add 32-bit color depth support for VBE The TunnelCreek IGD VBE reports 32-bit color depth regardless 24-bit color depth is configured. Since 24-bit mode already uses 4 bytes internally, it should be OK to just add this option in switch case. Signed-off-by: Jian Luo Acked-by: Simon Glass Tested-by: Bin Meng diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c index 37450c8..0a644a9 100644 --- a/drivers/pci/pci_rom.c +++ b/drivers/pci/pci_rom.c @@ -203,6 +203,7 @@ int vbe_get_video_info(struct graphic_device *gdev) gdev->gdfBytesPP = vesa->bits_per_pixel / 8; switch (vesa->bits_per_pixel) { + case 32: case 24: gdev->gdfIndex = GDF_32BIT_X888RGB; break; -- cgit v0.10.2 From 43dd22f5fc4c368616721a69e5ea0769abf292dc Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 6 Jul 2015 16:31:30 +0800 Subject: x86: Setup fixed range MTRRs for legacy regions We should setup fixed range MTRRs for some legacy regions like VGA RAM and PCI ROM areas as uncacheable. Note FSP may setup these to other cache settings, but we can override this in x86_cpu_init_f(). Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index d108ee5..9afdafb 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -352,6 +354,26 @@ int x86_cpu_init_f(void) gd->arch.has_mtrr = has_mtrr(); } + /* Configure fixed range MTRRs for some legacy regions */ + if (gd->arch.has_mtrr) { + u64 mtrr_cap; + + mtrr_cap = native_read_msr(MTRR_CAP_MSR); + if (mtrr_cap & MTRR_CAP_FIX) { + /* Mark the VGA RAM area as uncacheable */ + native_write_msr(MTRR_FIX_16K_A0000_MSR, 0, 0); + + /* Mark the PCI ROM area as uncacheable */ + native_write_msr(MTRR_FIX_4K_C0000_MSR, 0, 0); + native_write_msr(MTRR_FIX_4K_C8000_MSR, 0, 0); + native_write_msr(MTRR_FIX_4K_D0000_MSR, 0, 0); + native_write_msr(MTRR_FIX_4K_D8000_MSR, 0, 0); + + /* Enable the fixed range MTRRs */ + msr_setbits_64(MTRR_DEF_TYPE_MSR, MTRR_DEF_TYPE_FIX_EN); + } + } + return 0; } diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h index 3ad617c..70762ee 100644 --- a/arch/x86/include/asm/mtrr.h +++ b/arch/x86/include/asm/mtrr.h @@ -21,6 +21,11 @@ #define MTRR_CAP_MSR 0x0fe #define MTRR_DEF_TYPE_MSR 0x2ff +#define MTRR_CAP_SMRR (1 << 11) +#define MTRR_CAP_WC (1 << 10) +#define MTRR_CAP_FIX (1 << 8) +#define MTRR_CAP_VCNT_MASK 0xff + #define MTRR_DEF_TYPE_EN (1 << 11) #define MTRR_DEF_TYPE_FIX_EN (1 << 10) @@ -38,17 +43,17 @@ #define RANGES_PER_FIXED_MTRR 8 #define NUM_FIXED_RANGES (NUM_FIXED_MTRRS * RANGES_PER_FIXED_MTRR) -#define MTRR_FIX_64K_00000_MSR 0x250 -#define MTRR_FIX_16K_80000_MSR 0x258 -#define MTRR_FIX_16K_A0000_MSR 0x259 -#define MTRR_FIX_4K_C0000_MSR 0x268 -#define MTRR_FIX_4K_C8000_MSR 0x269 -#define MTRR_FIX_4K_D0000_MSR 0x26a -#define MTRR_FIX_4K_D8000_MSR 0x26b -#define MTRR_FIX_4K_E0000_MSR 0x26c -#define MTRR_FIX_4K_E8000_MSR 0x26d -#define MTRR_FIX_4K_F0000_MSR 0x26e -#define MTRR_FIX_4K_F8000_MSR 0x26f +#define MTRR_FIX_64K_00000_MSR 0x250 +#define MTRR_FIX_16K_80000_MSR 0x258 +#define MTRR_FIX_16K_A0000_MSR 0x259 +#define MTRR_FIX_4K_C0000_MSR 0x268 +#define MTRR_FIX_4K_C8000_MSR 0x269 +#define MTRR_FIX_4K_D0000_MSR 0x26a +#define MTRR_FIX_4K_D8000_MSR 0x26b +#define MTRR_FIX_4K_E0000_MSR 0x26c +#define MTRR_FIX_4K_E8000_MSR 0x26d +#define MTRR_FIX_4K_F0000_MSR 0x26e +#define MTRR_FIX_4K_F8000_MSR 0x26f #if !defined(__ASSEMBLER__) -- cgit v0.10.2 From 92587b364b1750612739438810f17c5b98f406fb Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 6 Jul 2015 16:31:31 +0800 Subject: x86: queensbay: Change CPU_ADDR_BITS to 32 Per CPUID:80000008h result, the maximum physical address bits of TunnelCreek processor is 32 instead of default 36. This will fix the incorrect decoding of MTRR range mask. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/cpu/queensbay/Kconfig b/arch/x86/cpu/queensbay/Kconfig index 397e599..fbf85f2 100644 --- a/arch/x86/cpu/queensbay/Kconfig +++ b/arch/x86/cpu/queensbay/Kconfig @@ -38,4 +38,8 @@ config CMC_ADDR The default base address of 0xfffb0000 indicates that the binary must be located at offset 0xb0000 from the beginning of a 1MB flash device. +config CPU_ADDR_BITS + int + default 32 + endif -- cgit v0.10.2 From df07d91956162c55f948cf150c14d678eca3b838 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 6 Jul 2015 16:31:32 +0800 Subject: x86: cmd_mtrr: Improve MTRR list information Print the meaningful base address and mask of an MTRR range without showing the memory type encoding or valid bit. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/lib/cmd_mtrr.c b/arch/x86/lib/cmd_mtrr.c index 7e0506b..f632f49 100644 --- a/arch/x86/lib/cmd_mtrr.c +++ b/arch/x86/lib/cmd_mtrr.c @@ -37,7 +37,8 @@ static int do_mtrr_list(void) valid = mask & MTRR_PHYS_MASK_VALID; type = mtrr_type_name[base & MTRR_BASE_TYPE_MASK]; printf("%d %-5s %-12s %016llx %016llx %016llx\n", i, - valid ? "Y" : "N", type, base, mask, size); + valid ? "Y" : "N", type, base & ~MTRR_BASE_TYPE_MASK, + mask & ~MTRR_PHYS_MASK_VALID, size); } return 0; -- cgit v0.10.2 From 786a08e0dd3d0505e10cc93622ce5db696c627e9 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 6 Jul 2015 16:31:33 +0800 Subject: x86: Move VGA option rom macros to Kconfig Move X86_OPTION_ROM_FILE & X86_OPTION_ROM_ADDR to arch/x86/Kconfig and rename them to VGA_BIOS_FILE & VGA_BIOS_ADDR which depend on HAVE_VGA_BIOS. The new names are consistent with other x86 binary blob options like HAVE_FSP/FSP_FILE/FSP_ADDR. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/Makefile b/Makefile index a7dce06..b6f83a5 100644 --- a/Makefile +++ b/Makefile @@ -1035,8 +1035,8 @@ ifneq ($(CONFIG_HAVE_CMC),) IFDTOOL_FLAGS += -w $(CONFIG_CMC_ADDR):$(srctree)/board/$(BOARDDIR)/$(CONFIG_CMC_FILE) endif -ifneq ($(CONFIG_X86_OPTION_ROM_ADDR),) -IFDTOOL_FLAGS += -w $(CONFIG_X86_OPTION_ROM_ADDR):$(srctree)/board/$(BOARDDIR)/$(CONFIG_X86_OPTION_ROM_FILE) +ifneq ($(CONFIG_HAVE_VGA_BIOS),) +IFDTOOL_FLAGS += -w $(CONFIG_VGA_BIOS_ADDR):$(srctree)/board/$(BOARDDIR)/$(CONFIG_VGA_BIOS_FILE) endif quiet_cmd_ifdtool = IFDTOOL $@ diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index b52a80e..8381a3b 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -287,6 +287,28 @@ config TSC_FREQ_IN_MHZ help The running frequency in MHz of Time-Stamp Counter (TSC). +config HAVE_VGA_BIOS + bool "Add a VGA BIOS image" + help + Select this option if you have a VGA BIOS image that you would + like to add to your ROM. + +config VGA_BIOS_FILE + string "VGA BIOS image filename" + depends on HAVE_VGA_BIOS + default "vga.bin" + help + The filename of the VGA BIOS image in the board directory. + +config VGA_BIOS_ADDR + hex "VGA BIOS image location" + depends on HAVE_VGA_BIOS + default 0xfff90000 + help + The location of VGA BIOS image in the SPI flash. For example, base + address of 0xfff90000 indicates that the image will be put at offset + 0x90000 from the beginning of a 1MB flash device. + menu "System tables" config GENERATE_PIRQ_TABLE diff --git a/configs/chromebook_link_defconfig b/configs/chromebook_link_defconfig index 018fe91..9931d65 100644 --- a/configs/chromebook_link_defconfig +++ b/configs/chromebook_link_defconfig @@ -3,6 +3,7 @@ CONFIG_VENDOR_GOOGLE=y CONFIG_DEFAULT_DEVICE_TREE="chromebook_link" CONFIG_TARGET_CHROMEBOOK_LINK=y CONFIG_HAVE_MRC=y +CONFIG_HAVE_VGA_BIOS=y # CONFIG_CMD_IMLS is not set # CONFIG_CMD_FLASH is not set # CONFIG_CMD_SETEXPR is not set diff --git a/configs/chromebox_panther_defconfig b/configs/chromebox_panther_defconfig index 2ac23ed..b3a5f28 100644 --- a/configs/chromebox_panther_defconfig +++ b/configs/chromebox_panther_defconfig @@ -3,6 +3,7 @@ CONFIG_VENDOR_GOOGLE=y CONFIG_DEFAULT_DEVICE_TREE="chromebox_panther" CONFIG_TARGET_CHROMEBOX_PANTHER=y CONFIG_HAVE_MRC=y +CONFIG_HAVE_VGA_BIOS=y # CONFIG_CMD_IMLS is not set # CONFIG_CMD_FLASH is not set # CONFIG_CMD_SETEXPR is not set diff --git a/configs/minnowmax_defconfig b/configs/minnowmax_defconfig index e0a9216..b578805 100644 --- a/configs/minnowmax_defconfig +++ b/configs/minnowmax_defconfig @@ -3,6 +3,7 @@ CONFIG_VENDOR_INTEL=y CONFIG_DEFAULT_DEVICE_TREE="minnowmax" CONFIG_TARGET_MINNOWMAX=y CONFIG_HAVE_INTEL_ME=y +CONFIG_HAVE_VGA_BIOS=y CONFIG_SMP=y CONFIG_GENERATE_SFI_TABLE=y CONFIG_CMD_CPU=y diff --git a/doc/README.x86 b/doc/README.x86 index 49d6e83..7f3914f 100644 --- a/doc/README.x86 +++ b/doc/README.x86 @@ -79,7 +79,7 @@ Find the following files: * ./northbridge/intel/sandybridge/systemagent-r6.bin The 3rd one should be renamed to mrc.bin. -As for the video ROM, you can get it here [3]. +As for the video ROM, you can get it here [3] and rename it to vga.bin. Make sure all these binary blobs are put in the board directory. Now you can build U-Boot and obtain u-boot.rom: diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c index 0a644a9..dd7fd95 100644 --- a/drivers/pci/pci_rom.c +++ b/drivers/pci/pci_rom.c @@ -79,8 +79,8 @@ static int pci_rom_probe(pci_dev_t dev, uint class, if (vendev != mapped_vendev) debug("Device ID mapped to %#08x\n", mapped_vendev); -#ifdef CONFIG_X86_OPTION_ROM_ADDR - rom_address = CONFIG_X86_OPTION_ROM_ADDR; +#ifdef CONFIG_VGA_BIOS_ADDR + rom_address = CONFIG_VGA_BIOS_ADDR; #else if (pciauto_setup_rom(pci_bus_to_hose(PCI_BUS(dev)), dev)) { diff --git a/include/configs/minnowmax.h b/include/configs/minnowmax.h index 547765d..8ee84a6 100644 --- a/include/configs/minnowmax.h +++ b/include/configs/minnowmax.h @@ -52,9 +52,6 @@ #undef CONFIG_USB_MAX_CONTROLLER_COUNT #define CONFIG_USB_MAX_CONTROLLER_COUNT 1 -#define CONFIG_X86_OPTION_ROM_FILE vga.bin -#define CONFIG_X86_OPTION_ROM_ADDR 0xfff90000 - #define VIDEO_IO_OFFSET 0 #define CONFIG_X86EMU_RAW_IO #define CONFIG_VGA_AS_SINGLE_DEVICE diff --git a/include/configs/x86-chromebook.h b/include/configs/x86-chromebook.h index e0e7fca..408cbb1 100644 --- a/include/configs/x86-chromebook.h +++ b/include/configs/x86-chromebook.h @@ -26,9 +26,6 @@ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_AHCI_MOBILE}, \ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_AHCI} -#define CONFIG_X86_OPTION_ROM_FILE pci8086,0166.bin -#define CONFIG_X86_OPTION_ROM_ADDR 0xfff90000 - #define CONFIG_PCI_MEM_BUS 0xe0000000 #define CONFIG_PCI_MEM_PHYS CONFIG_PCI_MEM_BUS #define CONFIG_PCI_MEM_SIZE 0x10000000 -- cgit v0.10.2 From 9e3a7c9bac35d47b7a021e311147ba0b5a128b08 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 6 Jul 2015 16:31:34 +0800 Subject: x86: Remove MARK_GRAPHICS_MEM_WRCOMB MARK_GRAPHICS_MEM_WRCOMB is not referenced anywhere in the code, hence remove it. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 8381a3b..cbbaa4f 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -188,14 +188,6 @@ config X86_RAMTEST to work correctly. It is not exhaustive but can save time by detecting obvious failures. -config MARK_GRAPHICS_MEM_WRCOMB - bool "Mark graphics memory as write-combining" - default n - help - The graphics performance may increase if the graphics - memory is set as write-combining cache type. This option - enables marking the graphics memory as write-combining. - config HAVE_FSP bool "Add an Firmware Support Package binary" help diff --git a/board/google/chromebook_link/Kconfig b/board/google/chromebook_link/Kconfig index 9c8d020..d3644a9 100644 --- a/board/google/chromebook_link/Kconfig +++ b/board/google/chromebook_link/Kconfig @@ -22,7 +22,6 @@ config BOARD_SPECIFIC_OPTIONS # dummy select NORTHBRIDGE_INTEL_IVYBRIDGE select SOUTHBRIDGE_INTEL_C216 select HAVE_ACPI_RESUME - select MARK_GRAPHICS_MEM_WRCOMB select BOARD_ROMSIZE_KB_8192 config PCIE_ECAM_BASE diff --git a/board/google/chromebox_panther/Kconfig b/board/google/chromebox_panther/Kconfig index e3604eb..d56d903 100644 --- a/board/google/chromebox_panther/Kconfig +++ b/board/google/chromebox_panther/Kconfig @@ -23,7 +23,6 @@ config BOARD_SPECIFIC_OPTIONS # dummy select NORTHBRIDGE_INTEL_IVYBRIDGE select SOUTHBRIDGE_INTEL_C216 select HAVE_ACPI_RESUME - select MARK_GRAPHICS_MEM_WRCOMB select BOARD_ROMSIZE_KB_8192 config SYS_CAR_ADDR -- cgit v0.10.2 From 7aaff9bf81b17b7920826f99a17eae7659292f5c Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 6 Jul 2015 16:31:35 +0800 Subject: x86: crownbay: Enable graphics support Enable graphics support on Intel Crown Bay board With the help of vgabios for Intel TunnelCreek IGD. Tested with an external LVDS panel connected to X4 connector and SDVO adapter connected to X9 connector on the board. Signed-off-by: Jian Luo Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/configs/crownbay_defconfig b/configs/crownbay_defconfig index 2af93bc..379b881 100644 --- a/configs/crownbay_defconfig +++ b/configs/crownbay_defconfig @@ -18,5 +18,8 @@ CONFIG_CPU=y CONFIG_SPI_FLASH=y CONFIG_USE_PRIVATE_LIBGCC=y CONFIG_SYS_VSNPRINTF=y +CONFIG_HAVE_VGA_BIOS=y CONFIG_GENERATE_MP_TABLE=y +CONFIG_VIDEO_VESA=y +CONFIG_FRAMEBUFFER_SET_VESA_MODE=y CONFIG_DM_RTC=y diff --git a/doc/README.x86 b/doc/README.x86 index 7f3914f..646eff1 100644 --- a/doc/README.x86 +++ b/doc/README.x86 @@ -113,6 +113,10 @@ binary using any hex editor (eg: bvi). Go to the offset 0x1fcd8 of the FSP binary, change the following five bytes values from orginally E8 42 FF FF FF to B8 00 80 0B 00. +As for the video ROM, you need manually extract it from the Intel provided +BIOS for Crown Bay here [6], using the AMI MMTool [7]. Check PCI option ROM +ID 8086:4108, extract and save it as vga.bin in the board directory. + Now you can build U-Boot and obtain u-boot.rom $ make crownbay_defconfig @@ -254,7 +258,7 @@ If you want to check both consoles, use '-serial stdio'. CPU Microcode ------------- -Modern CPUs usually require a special bit stream called microcode [6] to be +Modern CPUs usually require a special bit stream called microcode [8] to be loaded on the processor after power up in order to function properly. U-Boot has already integrated these as hex dumps in the source tree. @@ -265,9 +269,9 @@ Additional application processors (AP) can be brought up by U-Boot. In order to have an SMP kernel to discover all of the available processors, U-Boot needs to prepare configuration tables which contain the multi-CPUs information before loading the OS kernel. Currently U-Boot supports generating two types of tables -for SMP, called Simple Firmware Interface (SFI) [7] and Multi-Processor (MP) [8] -tables. The writing of these two tables are controlled by two Kconfig options -GENERATE_SFI_TABLE and GENERATE_MP_TABLE. +for SMP, called Simple Firmware Interface (SFI) [9] and Multi-Processor (MP) +[10] tables. The writing of these two tables are controlled by two Kconfig +options GENERATE_SFI_TABLE and GENERATE_MP_TABLE. Driver Model ------------ @@ -372,6 +376,8 @@ References [3] http://www.coreboot.org/~stepan/pci8086,0166.rom [4] http://www.intel.com/content/www/us/en/embedded/design-tools/evaluation-platforms/atom-e660-eg20t-development-kit.html [5] http://www.intel.com/fsp -[6] http://en.wikipedia.org/wiki/Microcode -[7] http://simplefirmware.org -[8] http://www.intel.com/design/archives/processors/pro/docs/242016.htm +[6] http://www.intel.com/content/www/us/en/secure/intelligent-systems/privileged/e6xx-35-b1-cmc22211.html +[7] http://www.ami.com/products/bios-uefi-tools-and-utilities/bios-uefi-utilities/ +[8] http://en.wikipedia.org/wiki/Microcode +[9] http://simplefirmware.org +[10] http://www.intel.com/design/archives/processors/pro/docs/242016.htm diff --git a/include/configs/crownbay.h b/include/configs/crownbay.h index 0e1f046..6cf53a3 100644 --- a/include/configs/crownbay.h +++ b/include/configs/crownbay.h @@ -32,15 +32,16 @@ #define CONFIG_PCI_IO_PHYS CONFIG_PCI_IO_BUS #define CONFIG_PCI_IO_SIZE 0xe000 +#define CONFIG_PCI_CONFIG_HOST_BRIDGE #define CONFIG_SYS_EARLY_PCI_INIT #define CONFIG_PCI_PNP #define CONFIG_E1000 -#define CONFIG_STD_DEVICES_SETTINGS "stdin=serial\0" \ - "stdout=serial\0" \ - "stderr=serial\0" +#define CONFIG_STD_DEVICES_SETTINGS "stdin=serial,vga,usbkbd\0" \ + "stdout=serial,vga\0" \ + "stderr=serial,vga\0" -#define CONFIG_SCSI_DEV_LIST \ +#define CONFIG_SCSI_DEV_LIST \ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SATA} #define CONFIG_SPI_FLASH_SST @@ -55,9 +56,8 @@ #define CONFIG_PCH_GBE #define CONFIG_PHYLIB -/* Video is not supported */ -#undef CONFIG_VIDEO -#undef CONFIG_CFB_CONSOLE +/* TunnelCreek IGD support */ +#define CONFIG_VGA_AS_SINGLE_DEVICE /* Environment configuration */ #define CONFIG_ENV_SECT_SIZE 0x1000 -- cgit v0.10.2 From a452002259e172c93277dbe5752817e0732afe78 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 6 Jul 2015 16:31:36 +0800 Subject: x86: Configure VESA parameters before loading Linux kernel Store VESA parameters to Linux setup header so that vesafb driver in the kernel could work. Signed-off-by: Bin Meng Acked-by: Simon Glass Tested-by: Jian Luo diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h index 8e7dd42..bf351ed 100644 --- a/arch/x86/include/asm/zimage.h +++ b/arch/x86/include/asm/zimage.h @@ -38,5 +38,6 @@ struct boot_params *load_zimage(char *image, unsigned long kernel_size, ulong *load_addressp); int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, unsigned long initrd_addr, unsigned long initrd_size); +void setup_video(struct screen_info *screen_info); #endif diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index c3f8a73..144471c 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -273,6 +273,8 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, build_command_line(cmd_line, auto_boot); } + setup_video(&setup_base->screen_info); + return 0; } diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c index dd7fd95..e7f9959 100644 --- a/drivers/pci/pci_rom.c +++ b/drivers/pci/pci_rom.c @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef CONFIG_HAVE_ACPI_RESUME #include @@ -230,6 +231,33 @@ int vbe_get_video_info(struct graphic_device *gdev) #endif } +void setup_video(struct screen_info *screen_info) +{ +#ifdef CONFIG_FRAMEBUFFER_SET_VESA_MODE + struct vesa_mode_info *vesa = &mode_info.vesa; + + screen_info->orig_video_isVGA = VIDEO_TYPE_VLFB; + + screen_info->lfb_width = vesa->x_resolution; + screen_info->lfb_height = vesa->y_resolution; + screen_info->lfb_depth = vesa->bits_per_pixel; + screen_info->lfb_linelength = vesa->bytes_per_scanline; + screen_info->lfb_base = vesa->phys_base_ptr; + screen_info->lfb_size = + ALIGN(screen_info->lfb_linelength * screen_info->lfb_height, + 65536); + screen_info->lfb_size >>= 16; + screen_info->red_size = vesa->red_mask_size; + screen_info->red_pos = vesa->red_mask_pos; + screen_info->green_size = vesa->green_mask_size; + screen_info->green_pos = vesa->green_mask_pos; + screen_info->blue_size = vesa->blue_mask_size; + screen_info->blue_pos = vesa->blue_mask_pos; + screen_info->rsvd_size = vesa->reserved_mask_size; + screen_info->rsvd_pos = vesa->reserved_mask_pos; +#endif +} + int pci_run_vga_bios(pci_dev_t dev, int (*int15_handler)(void), int exec_method) { struct pci_rom_header *rom, *ram; diff --git a/include/vbe.h b/include/vbe.h index c5deee9..1a86db8 100644 --- a/include/vbe.h +++ b/include/vbe.h @@ -12,7 +12,7 @@ #define _VBE_H /* these structs are for input from and output to OF */ -struct __packed screen_info { +struct __packed vbe_screen_info { u8 display_type; /* 0=NONE, 1= analog, 2=digital */ u16 screen_width; u16 screen_height; @@ -23,7 +23,7 @@ struct __packed screen_info { u8 edid_block_zero[128]; }; -struct __packed screen_info_input { +struct __packed vbe_screen_info_input { u8 signature[4]; u16 size_reserved; u8 monitor_number; -- cgit v0.10.2 From e1e332c8f2e5cac70566998a0ba0ccfdea437f10 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 3 Jul 2015 18:28:21 -0600 Subject: dm: spi: Correct status register access width The status register on ICH9 is a single byte, so use byte access when writing to it, to avoid updating the control register also. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Reviewed-by: Jagan Teki diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index 6b6cfbf..66a5cba 100644 --- a/drivers/spi/ich.c +++ b/drivers/spi/ich.c @@ -411,6 +411,7 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { struct udevice *bus = dev_get_parent(dev); + struct ich_spi_platdata *plat = dev_get_platdata(bus); struct ich_spi_priv *ctlr = dev_get_priv(bus); uint16_t control; int16_t opcode_index; @@ -477,7 +478,10 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen, if (ret < 0) return ret; - ich_writew(ctlr, SPIS_CDS | SPIS_FCERR, ctlr->status); + if (plat->ich_version == 7) + ich_writew(ctlr, SPIS_CDS | SPIS_FCERR, ctlr->status); + else + ich_writeb(ctlr, SPIS_CDS | SPIS_FCERR, ctlr->status); spi_setup_type(trans, using_cmd ? bytes : 0); opcode_index = spi_setup_opcode(ctlr, trans); -- cgit v0.10.2 From 507879280750fc4af5e5fd0c4387147d286ff6f7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 3 Jul 2015 18:28:22 -0600 Subject: dm: spi: Correct BIOS protection logic for ICH9 The logic is incorrect and currently has no effect. Fix it so that we can write to SPI flash, since by default it is write-protected. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Andrew Bradford diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index 66a5cba..2e388e7 100644 --- a/drivers/spi/ich.c +++ b/drivers/spi/ich.c @@ -40,6 +40,7 @@ struct ich_spi_priv { int status; int control; int bbar; + int bcr; uint32_t *pr; /* only for ich9 */ int speed; /* pointer to speed control */ ulong max_speed; /* Maximum bus speed in MHz */ @@ -239,6 +240,7 @@ static int ich_init_controller(struct ich_spi_platdata *plat, ctlr->speed = ctlr->control + 2; ctlr->bbar = offsetof(struct ich9_spi_regs, bbar); ctlr->preop = offsetof(struct ich9_spi_regs, preop); + ctlr->bcr = offsetof(struct ich9_spi_regs, bcr); ctlr->pr = &ich9_spi->pr[0]; ctlr->base = ich9_spi; } else { @@ -688,13 +690,10 @@ static int ich_spi_probe(struct udevice *bus) * v9, deassert SMM BIOS Write Protect Disable. */ if (plat->use_sbase) { - struct ich9_spi_regs *ich9_spi; - - ich9_spi = priv->base; - bios_cntl = ich_readb(priv, ich9_spi->bcr); + bios_cntl = ich_readb(priv, priv->bcr); bios_cntl &= ~(1 << 5); /* clear Enable InSMM_STS (EISS) */ bios_cntl |= 1; /* Write Protect Disable (WPD) */ - ich_writeb(priv, bios_cntl, ich9_spi->bcr); + ich_writeb(priv, bios_cntl, priv->bcr); } else { pci_read_config_byte(plat->dev, 0xdc, &bios_cntl); if (plat->ich_version == 9) -- cgit v0.10.2 From d5359f2e4dd11d7a1e980beadff22a6e25578ad4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 3 Jul 2015 18:28:23 -0600 Subject: dm: spi: Enable environment for minnowmax Enable a SPI environment and store it in a suitable place. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Reviewed-by: Jagan Teki diff --git a/include/configs/minnowmax.h b/include/configs/minnowmax.h index 8ee84a6..e0f6f8a 100644 --- a/include/configs/minnowmax.h +++ b/include/configs/minnowmax.h @@ -62,8 +62,7 @@ /* Avoid a warning in the Realtek Ethernet driver */ #define CONFIG_SYS_CACHELINE_SIZE 16 -/* Environment in SPI flash is unsupported for now */ -#undef CONFIG_ENV_IS_IN_SPI_FLASH -#define CONFIG_ENV_IS_NOWHERE +#define CONFIG_ENV_SECT_SIZE 0x1000 +#define CONFIG_ENV_OFFSET 0x007fe000 #endif /* __CONFIG_H */ -- cgit v0.10.2 From 537ccba2a425d69d407c9e2cd0fd9d34391ddf82 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 3 Jul 2015 18:28:24 -0600 Subject: x86: Add ROM image description for minnowmax The layout of the ROM is a bit hard to discover by reading the code. Add a table to make it easier. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/doc/README.x86 b/doc/README.x86 index 646eff1..46a1eeb 100644 --- a/doc/README.x86 +++ b/doc/README.x86 @@ -164,6 +164,23 @@ Now you can build U-Boot and obtain u-boot.rom $ make minnowmax_defconfig $ make all +The ROM image is broken up into these parts: + +Offset Description Controlling config +------------------------------------------------------------ +000000 descriptor.bin Hard-coded to 0 in ifdtool +001000 me.bin Set by the descriptor +500000 +700000 u-boot-dtb.bin CONFIG_SYS_TEXT_BASE +790000 vga.bin CONFIG_X86_OPTION_ROM_ADDR +7c0000 fsp.bin CONFIG_FSP_ADDR +7f8000 (depends on size of fsp.bin) +7fe000 Environment CONFIG_ENV_OFFSET +7ff800 U-Boot 16-bit boot CONFIG_SYS_X86_START16 + +Overall ROM image size is controlled by CONFIG_ROM_SIZE. + + Intel Galileo instructions: Only one binary blob is needed for Remote Management Unit (RMU) within Intel -- cgit v0.10.2 From 945cae79e1b547d6edcce53aae68be2e3679a364 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 3 Jul 2015 18:28:25 -0600 Subject: x86: pci: Tidy up the generic x86 PCI driver This driver should use the x86 PCI configuration functions. Also adjust its compatible string to something generic (i.e. without a vendor name). Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/x86/cpu/coreboot/pci.c b/arch/x86/cpu/coreboot/pci.c index 67eb14c..41e29a6 100644 --- a/arch/x86/cpu/coreboot/pci.c +++ b/arch/x86/cpu/coreboot/pci.c @@ -11,29 +11,7 @@ #include #include -#include #include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -static const struct dm_pci_ops pci_x86_ops = { - .read_config = pci_x86_read_config, - .write_config = pci_x86_write_config, -}; - -static const struct udevice_id pci_x86_ids[] = { - { .compatible = "pci-x86" }, - { } -}; - -U_BOOT_DRIVER(pci_x86_drv) = { - .name = "pci_x86", - .id = UCLASS_PCI, - .of_match = pci_x86_ids, - .ops = &pci_x86_ops, -}; static const struct udevice_id generic_pch_ids[] = { { .compatible = "intel,pch" }, diff --git a/drivers/pci/pci_x86.c b/drivers/pci/pci_x86.c index 901bdca..89e8c11 100644 --- a/drivers/pci/pci_x86.c +++ b/drivers/pci/pci_x86.c @@ -7,18 +7,21 @@ #include #include #include +#include -static const struct dm_pci_ops x86_pci_ops = { +static const struct dm_pci_ops pci_x86_ops = { + .read_config = pci_x86_read_config, + .write_config = pci_x86_write_config, }; -static const struct udevice_id x86_pci_ids[] = { - { .compatible = "x86,pci" }, +static const struct udevice_id pci_x86_ids[] = { + { .compatible = "pci-x86" }, { } }; U_BOOT_DRIVER(pci_x86) = { .name = "pci_x86", .id = UCLASS_PCI, - .of_match = x86_pci_ids, - .ops = &x86_pci_ops, + .of_match = pci_x86_ids, + .ops = &pci_x86_ops, }; -- cgit v0.10.2 From b71f9dca89013b8b100006029c98d04b495ebdf7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 3 Jul 2015 18:28:26 -0600 Subject: dm: x86: minnowmax: Move PCI to use driver model Adjust minnowmax to use driver model for PCI. This requires adding a device tree node to specify the ranges, removing the board-specific PCI code and ensuring that the host bridge is configured. Reviewed-by: Bin Meng Signed-off-by: Simon Glass diff --git a/arch/x86/cpu/baytrail/Makefile b/arch/x86/cpu/baytrail/Makefile index c78b644..5be5491 100644 --- a/arch/x86/cpu/baytrail/Makefile +++ b/arch/x86/cpu/baytrail/Makefile @@ -7,5 +7,4 @@ obj-y += cpu.o obj-y += early_uart.o obj-y += fsp_configs.o -obj-y += pci.o obj-y += valleyview.o diff --git a/arch/x86/cpu/baytrail/pci.c b/arch/x86/cpu/baytrail/pci.c deleted file mode 100644 index 48409de..0000000 --- a/arch/x86/cpu/baytrail/pci.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2014, Bin Meng - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -void board_pci_setup_hose(struct pci_controller *hose) -{ - hose->first_busno = 0; - hose->last_busno = 0; - - /* PCI memory space */ - pci_set_region(hose->regions + 0, - CONFIG_PCI_MEM_BUS, - CONFIG_PCI_MEM_PHYS, - CONFIG_PCI_MEM_SIZE, - PCI_REGION_MEM); - - /* PCI IO space */ - pci_set_region(hose->regions + 1, - CONFIG_PCI_IO_BUS, - CONFIG_PCI_IO_PHYS, - CONFIG_PCI_IO_SIZE, - PCI_REGION_IO); - - pci_set_region(hose->regions + 2, - CONFIG_PCI_PREF_BUS, - CONFIG_PCI_PREF_PHYS, - CONFIG_PCI_PREF_SIZE, - PCI_REGION_PREFETCH); - - pci_set_region(hose->regions + 3, - 0, - 0, - gd->ram_size < 0x80000000 ? gd->ram_size : 0x80000000, - PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); - - hose->region_count = 4; -} diff --git a/arch/x86/dts/minnowmax.dts b/arch/x86/dts/minnowmax.dts index bd21bfb..0e59b18 100644 --- a/arch/x86/dts/minnowmax.dts +++ b/arch/x86/dts/minnowmax.dts @@ -111,6 +111,16 @@ }; + pci { + compatible = "intel,pci-baytrail", "pci-x86"; + #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>; + }; + spi { #address-cells = <1>; #size-cells = <0>; diff --git a/configs/minnowmax_defconfig b/configs/minnowmax_defconfig index b578805..45f666c 100644 --- a/configs/minnowmax_defconfig +++ b/configs/minnowmax_defconfig @@ -22,3 +22,4 @@ CONFIG_FRAMEBUFFER_SET_VESA_MODE=y CONFIG_FRAMEBUFFER_VESA_MODE_11A=y CONFIG_USE_PRIVATE_LIBGCC=y CONFIG_SYS_VSNPRINTF=y +CONFIG_DM_PCI=y diff --git a/include/configs/minnowmax.h b/include/configs/minnowmax.h index e0f6f8a..af36ac5 100644 --- a/include/configs/minnowmax.h +++ b/include/configs/minnowmax.h @@ -32,6 +32,7 @@ #define CONFIG_PCI_IO_PHYS CONFIG_PCI_IO_BUS #define CONFIG_PCI_IO_SIZE 0xe000 +#define CONFIG_PCI_CONFIG_HOST_BRIDGE #define CONFIG_SYS_EARLY_PCI_INIT #define CONFIG_PCI_PNP #define CONFIG_RTL8169 -- cgit v0.10.2 From b9da5086b88a1565c7aede14e68bef2456c44475 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 3 Jul 2015 18:28:27 -0600 Subject: dm: x86: baytrail: Correct PCI region 3 when driver model is used Commit afbbd413a fixed this for non-driver-model. Make sure that the driver model code handles this also. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 9afdafb..af927b9 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -353,6 +353,8 @@ int x86_cpu_init_f(void) gd->arch.has_mtrr = has_mtrr(); } + /* Don't allow PCI region 3 to use memory in the 2-4GB memory hole */ + gd->pci_ram_top = 0x80000000U; /* Configure fixed range MTRRs for some legacy regions */ if (gd->arch.has_mtrr) { diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index edec93f..5b91fe3 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -444,6 +444,7 @@ static int decode_regions(struct pci_controller *hose, const void *blob, { int pci_addr_cells, addr_cells, size_cells; int cells_per_record; + phys_addr_t addr; const u32 *prop; int len; int i; @@ -494,8 +495,11 @@ static int decode_regions(struct pci_controller *hose, const void *blob, } /* Add a region for our local memory */ - pci_set_region(hose->regions + hose->region_count++, 0, 0, - gd->ram_size, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); + addr = gd->ram_size; + if (gd->pci_ram_top && gd->pci_ram_top < addr) + addr = gd->pci_ram_top; + pci_set_region(hose->regions + hose->region_count++, 0, 0, addr, + PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); return 0; } diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 6747619..db0550b 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -93,6 +93,7 @@ typedef struct global_data { #endif #ifdef CONFIG_PCI struct pci_controller *hose; /* PCI hose for early use */ + phys_addr_t pci_ram_top; /* top of region accessible to PCI */ #endif #ifdef CONFIG_PCI_BOOTDELAY int pcidelay_done; -- cgit v0.10.2 From df898678ab96b904b962743bb5388284c712b9fb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 3 Jul 2015 18:28:28 -0600 Subject: x86: Add binary blob checksums for Minnowboard MAX To try to reduce the pain of confusion of binary blobs, add MD5 checksums for the current versions. This may worsen the situation as new versions appear, but it should still be possible to obtain these versions, and thus get a working setup. Signed-off-by: Simon Glass Reviewed-by: Bin Meng diff --git a/doc/README.x86 b/doc/README.x86 index 46a1eeb..5d71244 100644 --- a/doc/README.x86 +++ b/doc/README.x86 @@ -164,6 +164,14 @@ Now you can build U-Boot and obtain u-boot.rom $ make minnowmax_defconfig $ make all +Checksums are as follows (but note that newer versions will invalidate this): + +$ md5sum -b board/intel/minnowmax/*.bin +ffda9a3b94df5b74323afb328d51e6b4 board/intel/minnowmax/descriptor.bin +69f65b9a580246291d20d08cbef9d7c5 board/intel/minnowmax/fsp.bin +894a97d371544ec21de9c3e8e1716c4b board/intel/minnowmax/me.bin +a2588537da387da592a27219d56e9962 board/intel/minnowmax/vga.bin + The ROM image is broken up into these parts: Offset Description Controlling config -- cgit v0.10.2 From 50e8a6bba0cf5939afe849ef792f88f09a755758 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 6 Jul 2015 15:57:06 +0800 Subject: tools: ifdtool: Write correct offset on 32-bit machine On 32-bit machine strtol() returns LONG_MAX which is 0x7fffffff, which is wrong for u-boot.rom components like u-boot-x86-16bit.bin. Change to use strtoll() so that it works on both 32-bit and 64-bit machines. Reported-by: Fei Wang Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/tools/ifdtool.c b/tools/ifdtool.c index 1d61df1..df16616 100644 --- a/tools/ifdtool.c +++ b/tools/ifdtool.c @@ -987,7 +987,7 @@ int main(int argc, char *argv[]) print_usage(argv[0]); exit(EXIT_FAILURE); } - ifile->addr = strtol(optarg, NULL, 0); + ifile->addr = strtoll(optarg, NULL, 0); ifile->type = opt == 'f' ? IF_fdt : opt == 'U' ? IF_uboot : IF_normal; if (ifile->type == IF_fdt) -- cgit v0.10.2 From aeda4ab664d50a7b620c8b8a4075f9512110e180 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 9 Jul 2015 18:37:40 +0800 Subject: x86: Adjust config option order in defconfig for Crown Bay and Minnowmax Update crownbay_defconfig and minnowmax_defconfig with 'savedefconfig' result so that the config option order matches Kconfig. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/configs/crownbay_defconfig b/configs/crownbay_defconfig index 379b881..17e6a72 100644 --- a/configs/crownbay_defconfig +++ b/configs/crownbay_defconfig @@ -4,7 +4,9 @@ CONFIG_DEFAULT_DEVICE_TREE="crownbay" CONFIG_TARGET_CROWNBAY=y CONFIG_SMP=y CONFIG_MAX_CPUS=2 +CONFIG_HAVE_VGA_BIOS=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 @@ -16,10 +18,8 @@ CONFIG_CMD_BOOTSTAGE=y CONFIG_OF_CONTROL=y CONFIG_CPU=y CONFIG_SPI_FLASH=y -CONFIG_USE_PRIVATE_LIBGCC=y -CONFIG_SYS_VSNPRINTF=y -CONFIG_HAVE_VGA_BIOS=y -CONFIG_GENERATE_MP_TABLE=y CONFIG_VIDEO_VESA=y CONFIG_FRAMEBUFFER_SET_VESA_MODE=y CONFIG_DM_RTC=y +CONFIG_USE_PRIVATE_LIBGCC=y +CONFIG_SYS_VSNPRINTF=y diff --git a/configs/minnowmax_defconfig b/configs/minnowmax_defconfig index 45f666c..29dd44b 100644 --- a/configs/minnowmax_defconfig +++ b/configs/minnowmax_defconfig @@ -3,8 +3,8 @@ CONFIG_VENDOR_INTEL=y CONFIG_DEFAULT_DEVICE_TREE="minnowmax" CONFIG_TARGET_MINNOWMAX=y CONFIG_HAVE_INTEL_ME=y -CONFIG_HAVE_VGA_BIOS=y CONFIG_SMP=y +CONFIG_HAVE_VGA_BIOS=y CONFIG_GENERATE_SFI_TABLE=y CONFIG_CMD_CPU=y # CONFIG_CMD_IMLS is not set @@ -16,10 +16,10 @@ CONFIG_BOOTSTAGE_REPORT=y CONFIG_CMD_BOOTSTAGE=y CONFIG_OF_CONTROL=y CONFIG_CPU=y +CONFIG_DM_PCI=y CONFIG_SPI_FLASH=y CONFIG_VIDEO_VESA=y CONFIG_FRAMEBUFFER_SET_VESA_MODE=y CONFIG_FRAMEBUFFER_VESA_MODE_11A=y CONFIG_USE_PRIVATE_LIBGCC=y CONFIG_SYS_VSNPRINTF=y -CONFIG_DM_PCI=y -- cgit v0.10.2 From e1783b5ba3d32c0471a2b963ebec54e7e7cde264 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sat, 16 May 2015 09:33:16 +0800 Subject: drivers: block: Remove the ata_piix driver This driver was originally added to support the native IDE mode for Intel chipset, however it has some bugs like not supporting ATAPI devices, endianness issue, or even broken build when CONFIG_LAB48. Given no board is using this driver as of today, rather than fixing all these issues we just remove it from the source tree. Signed-off-by: Bin Meng Acked-by: Simon Glass diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 8697da4..f161c01 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -6,7 +6,6 @@ # obj-$(CONFIG_SCSI_AHCI) += ahci.o -obj-$(CONFIG_ATA_PIIX) += ata_piix.o obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o obj-$(CONFIG_FSL_SATA) += fsl_sata.o obj-$(CONFIG_IDE_FTIDE020) += ftide020.o diff --git a/drivers/block/ata_piix.c b/drivers/block/ata_piix.c deleted file mode 100644 index 3042684..0000000 --- a/drivers/block/ata_piix.c +++ /dev/null @@ -1,717 +0,0 @@ -/* - * Copyright (C) Procsys. All rights reserved. - * Author: Mushtaq Khan - * - * - * SPDX-License-Identifier: GPL-2.0+ - * - * with the reference to ata_piix driver in kernel 2.4.32 - */ - -/* - * This file contains SATA controller and SATA drive initialization functions - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEBUG_SATA 0 /* For debug prints set DEBUG_SATA to 1 */ - -#define SATA_DECL -#define DRV_DECL /* For file specific declarations */ -#include "ata_piix.h" - -/* Macros realted to PCI */ -#define PCI_SATA_BUS 0x00 -#define PCI_SATA_DEV 0x1f -#define PCI_SATA_FUNC 0x02 - -#define PCI_SATA_BASE1 0x10 -#define PCI_SATA_BASE2 0x14 -#define PCI_SATA_BASE3 0x18 -#define PCI_SATA_BASE4 0x1c -#define PCI_SATA_BASE5 0x20 -#define PCI_PMR 0x90 -#define PCI_PI 0x09 -#define PCI_PCS 0x92 -#define PCI_DMA_CTL 0x48 - -#define PORT_PRESENT (1<<0) -#define PORT_ENABLED (1<<4) - -u32 bdf; -u32 iobase1; /* Primary cmd block */ -u32 iobase2; /* Primary ctl block */ -u32 iobase3; /* Sec cmd block */ -u32 iobase4; /* sec ctl block */ -u32 iobase5; /* BMDMA*/ - -int pci_sata_init(void) -{ - u32 bus = PCI_SATA_BUS; - u32 dev = PCI_SATA_DEV; - u32 fun = PCI_SATA_FUNC; - u16 cmd = 0; - u8 lat = 0, pcibios_max_latency = 0xff; - u8 pmr; /* Port mapping reg */ - u8 pi; /* Prgming Interface reg */ - - bdf = PCI_BDF(bus, dev, fun); - pci_read_config_dword(bdf, PCI_SATA_BASE1, &iobase1); - pci_read_config_dword(bdf, PCI_SATA_BASE2, &iobase2); - pci_read_config_dword(bdf, PCI_SATA_BASE3, &iobase3); - pci_read_config_dword(bdf, PCI_SATA_BASE4, &iobase4); - pci_read_config_dword(bdf, PCI_SATA_BASE5, &iobase5); - - if ((iobase1 == 0xFFFFFFFF) || (iobase2 == 0xFFFFFFFF) || - (iobase3 == 0xFFFFFFFF) || (iobase4 == 0xFFFFFFFF) || - (iobase5 == 0xFFFFFFFF)) { - /* ERROR */ - printf("error no base addr for SATA controller\n"); - return 1; - } - - iobase1 &= 0xFFFFFFFE; - iobase2 &= 0xFFFFFFFE; - iobase3 &= 0xFFFFFFFE; - iobase4 &= 0xFFFFFFFE; - iobase5 &= 0xFFFFFFFE; - - /* check for mode */ - pci_read_config_byte(bdf, PCI_PMR, &pmr); - if (pmr > 1) { - puts("combined mode not supported\n"); - return 1; - } - - pci_read_config_byte(bdf, PCI_PI, &pi); - if ((pi & 0x05) != 0x05) { - puts("Sata is in Legacy mode\n"); - return 1; - } else - puts("sata is in Native mode\n"); - - /* MASTER CFG AND IO CFG */ - pci_read_config_word(bdf, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO; - pci_write_config_word(bdf, PCI_COMMAND, cmd); - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); - - if (lat < 16) - lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; - else if (lat > pcibios_max_latency) - lat = pcibios_max_latency; - pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); - - return 0; -} - -int sata_bus_probe(int port_no) -{ - int orig_mask, mask; - u16 pcs; - - mask = (PORT_PRESENT << port_no); - pci_read_config_word(bdf, PCI_PCS, &pcs); - orig_mask = (int) pcs & 0xff; - if ((orig_mask & mask) != mask) - return 0; - else - return 1; -} - -int init_sata(int dev) -{ - static int done; - u8 i, rv = 0; - - if (!done) - done = 1; - else - return 0; - - rv = pci_sata_init(); - if (rv == 1) { - puts("pci initialization failed\n"); - return 1; - } - - port[0].port_no = 0; - port[0].ioaddr.cmd_addr = iobase1; - port[0].ioaddr.altstatus_addr = port[0].ioaddr.ctl_addr = - iobase2 | ATA_PCI_CTL_OFS; - port[0].ioaddr.bmdma_addr = iobase5; - - port[1].port_no = 1; - port[1].ioaddr.cmd_addr = iobase3; - port[1].ioaddr.altstatus_addr = port[1].ioaddr.ctl_addr = - iobase4 | ATA_PCI_CTL_OFS; - port[1].ioaddr.bmdma_addr = iobase5 + 0x8; - - for (i = 0; i < CONFIG_SYS_SATA_MAXBUS; i++) - sata_port(&port[i].ioaddr); - - for (i = 0; i < CONFIG_SYS_SATA_MAXBUS; i++) { - if (!(sata_bus_probe(i))) { - port[i].port_state = 0; - printf("SATA#%d port is not present\n", i); - } else { - printf("SATA#%d port is present\n", i); - if (sata_bus_softreset(i)) - port[i].port_state = 0; - else - port[i].port_state = 1; - } - } - - for (i = 0; i < CONFIG_SYS_SATA_MAXBUS; i++) { - u8 j, devno; - - if (port[i].port_state == 0) - continue; - for (j = 0; j < CONFIG_SYS_SATA_DEVS_PER_BUS; j++) { - sata_identify(i, j); - set_Feature_cmd(i, j); - devno = i * CONFIG_SYS_SATA_DEVS_PER_BUS + j; - if ((sata_dev_desc[devno].lba > 0) && - (sata_dev_desc[devno].blksz > 0)) { - dev_print(&sata_dev_desc[devno]); - /* initialize partition type */ - init_part(&sata_dev_desc[devno]); - } - } - } - return 0; -} - -int reset_sata(int dev) -{ - return 0; -} - -static inline u8 sata_inb(unsigned long ioaddr) -{ - return inb(ioaddr); -} - -static inline void sata_outb(unsigned char val, unsigned long ioaddr) -{ - outb(val, ioaddr); -} - -static void output_data(struct sata_ioports *ioaddr, ulong * sect_buf, - int words) -{ - outsw(ioaddr->data_addr, sect_buf, words << 1); -} - -static int input_data(struct sata_ioports *ioaddr, ulong * sect_buf, int words) -{ - insw(ioaddr->data_addr, sect_buf, words << 1); - return 0; -} - -static void sata_cpy(unsigned char *dst, unsigned char *src, unsigned int len) -{ - unsigned char *end, *last; - - last = dst; - end = src + len - 1; - - /* reserve space for '\0' */ - if (len < 2) - goto OUT; - - /* skip leading white space */ - while ((*src) && (src < end) && (*src == ' ')) - ++src; - - /* copy string, omitting trailing white space */ - while ((*src) && (src < end)) { - *dst++ = *src; - if (*src++ != ' ') - last = dst; - } -OUT: - *last = '\0'; -} - -int sata_bus_softreset(int num) -{ - u8 dev = 0, status = 0, i; - - port[num].dev_mask = 0; - - for (i = 0; i < CONFIG_SYS_SATA_DEVS_PER_BUS; i++) { - if (!(sata_devchk(&port[num].ioaddr, i))) { - debug("dev_chk failed for dev#%d\n", i); - } else { - port[num].dev_mask |= (1 << i); - debug("dev_chk passed for dev#%d\n", i); - } - } - - if (!(port[num].dev_mask)) { - printf("no devices on port%d\n", num); - return 1; - } - - dev_select(&port[num].ioaddr, dev); - - port[num].ctl_reg = 0x08; /* Default value of control reg */ - sata_outb(port[num].ctl_reg, port[num].ioaddr.ctl_addr); - udelay(10); - sata_outb(port[num].ctl_reg | ATA_SRST, port[num].ioaddr.ctl_addr); - udelay(10); - sata_outb(port[num].ctl_reg, port[num].ioaddr.ctl_addr); - - /* - * spec mandates ">= 2ms" before checking status. - * We wait 150ms, because that was the magic delay used for - * ATAPI devices in Hale Landis's ATADRVR, for the period of time - * between when the ATA command register is written, and then - * status is checked. Because waiting for "a while" before - * checking status is fine, post SRST, we perform this magic - * delay here as well. - */ - mdelay(150); - status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 300); - while ((status & ATA_BUSY)) { - mdelay(100); - status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 3); - } - - if (status & ATA_BUSY) - printf("ata%u is slow to respond,plz be patient\n", num); - - while ((status & ATA_BUSY)) { - mdelay(100); - status = sata_chk_status(&port[num].ioaddr); - } - - if (status & ATA_BUSY) { - printf("ata%u failed to respond : bus reset failed\n", num); - return 1; - } - return 0; -} - -void sata_identify(int num, int dev) -{ - u8 cmd = 0, status = 0; - u8 devno = num * CONFIG_SYS_SATA_DEVS_PER_BUS + dev; - u16 iobuf[ATA_SECT_SIZE]; - u64 n_sectors = 0; - u8 mask = 0; - - memset(iobuf, 0, sizeof(iobuf)); - hd_driveid_t *iop = (hd_driveid_t *) iobuf; - - if (dev == 0) - mask = 0x01; - else - mask = 0x02; - - if (!(port[num].dev_mask & mask)) { - printf("dev%d is not present on port#%d\n", dev, num); - return; - } - - printf("port=%d dev=%d\n", num, dev); - - dev_select(&port[num].ioaddr, dev); - - status = 0; - cmd = ATA_CMD_IDENT; /* Device Identify Command */ - sata_outb(cmd, port[num].ioaddr.command_addr); - sata_inb(port[num].ioaddr.altstatus_addr); - udelay(10); - - status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 1000); - if (status & ATA_ERR) { - puts("\ndevice not responding\n"); - port[num].dev_mask &= ~mask; - return; - } - - input_data(&port[num].ioaddr, (ulong *) iobuf, ATA_SECTORWORDS); - - debug("\nata%u: dev %u cfg 49:%04x 82:%04x 83:%04x 84:%04x85:%04x" - "86:%04x" "87:%04x 88:%04x\n", num, dev, iobuf[49], - iobuf[82], iobuf[83], iobuf[84], iobuf[85], iobuf[86], - iobuf[87], iobuf[88]); - - /* we require LBA and DMA support (bits 8 & 9 of word 49) */ - if (!ata_id_has_dma(iobuf) || !ata_id_has_lba(iobuf)) - debug("ata%u: no dma/lba\n", num); - ata_dump_id(iobuf); - - if (ata_id_has_lba48(iobuf)) - n_sectors = ata_id_u64(iobuf, 100); - else - n_sectors = ata_id_u32(iobuf, 60); - debug("no. of sectors %u\n", ata_id_u64(iobuf, 100)); - debug("no. of sectors %u\n", ata_id_u32(iobuf, 60)); - - if (n_sectors == 0) { - port[num].dev_mask &= ~mask; - return; - } - - sata_cpy((unsigned char *)sata_dev_desc[devno].revision, iop->fw_rev, - sizeof(sata_dev_desc[devno].revision)); - sata_cpy((unsigned char *)sata_dev_desc[devno].vendor, iop->model, - sizeof(sata_dev_desc[devno].vendor)); - sata_cpy((unsigned char *)sata_dev_desc[devno].product, iop->serial_no, - sizeof(sata_dev_desc[devno].product)); - strswab(sata_dev_desc[devno].revision); - strswab(sata_dev_desc[devno].vendor); - - if ((iop->config & 0x0080) == 0x0080) - sata_dev_desc[devno].removable = 1; - else - sata_dev_desc[devno].removable = 0; - - sata_dev_desc[devno].lba = iop->lba_capacity; - debug("lba=0x%x", sata_dev_desc[devno].lba); - -#ifdef CONFIG_LBA48 - if (iop->command_set_2 & 0x0400) { - sata_dev_desc[devno].lba48 = 1; - lba = (unsigned long long) iop->lba48_capacity[0] | - ((unsigned long long) iop->lba48_capacity[1] << 16) | - ((unsigned long long) iop->lba48_capacity[2] << 32) | - ((unsigned long long) iop->lba48_capacity[3] << 48); - } else { - sata_dev_desc[devno].lba48 = 0; - } -#endif - - /* assuming HD */ - sata_dev_desc[devno].type = DEV_TYPE_HARDDISK; - sata_dev_desc[devno].blksz = ATA_BLOCKSIZE; - sata_dev_desc[devno].log2blksz = LOG2(sata_dev_desc[devno].blksz); - sata_dev_desc[devno].lun = 0; /* just to fill something in... */ -} - -void set_Feature_cmd(int num, int dev) -{ - u8 mask = 0x00, status = 0; - - if (dev == 0) - mask = 0x01; - else - mask = 0x02; - - if (!(port[num].dev_mask & mask)) { - debug("dev%d is not present on port#%d\n", dev, num); - return; - } - - dev_select(&port[num].ioaddr, dev); - - sata_outb(SETFEATURES_XFER, port[num].ioaddr.feature_addr); - sata_outb(XFER_PIO_4, port[num].ioaddr.nsect_addr); - sata_outb(0, port[num].ioaddr.lbal_addr); - sata_outb(0, port[num].ioaddr.lbam_addr); - sata_outb(0, port[num].ioaddr.lbah_addr); - - sata_outb(ATA_DEVICE_OBS, port[num].ioaddr.device_addr); - sata_outb(ATA_CMD_SETF, port[num].ioaddr.command_addr); - - udelay(50); - mdelay(150); - - status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 5000); - if ((status & (ATA_STAT_BUSY | ATA_STAT_ERR))) { - printf("Error : status 0x%02x\n", status); - port[num].dev_mask &= ~mask; - } -} - -void sata_port(struct sata_ioports *ioport) -{ - ioport->data_addr = ioport->cmd_addr + ATA_REG_DATA; - ioport->error_addr = ioport->cmd_addr + ATA_REG_ERR; - ioport->feature_addr = ioport->cmd_addr + ATA_REG_FEATURE; - ioport->nsect_addr = ioport->cmd_addr + ATA_REG_NSECT; - ioport->lbal_addr = ioport->cmd_addr + ATA_REG_LBAL; - ioport->lbam_addr = ioport->cmd_addr + ATA_REG_LBAM; - ioport->lbah_addr = ioport->cmd_addr + ATA_REG_LBAH; - ioport->device_addr = ioport->cmd_addr + ATA_REG_DEVICE; - ioport->status_addr = ioport->cmd_addr + ATA_REG_STATUS; - ioport->command_addr = ioport->cmd_addr + ATA_REG_CMD; -} - -int sata_devchk(struct sata_ioports *ioaddr, int dev) -{ - u8 nsect, lbal; - - dev_select(ioaddr, dev); - - sata_outb(0x55, ioaddr->nsect_addr); - sata_outb(0xaa, ioaddr->lbal_addr); - - sata_outb(0xaa, ioaddr->nsect_addr); - sata_outb(0x55, ioaddr->lbal_addr); - - sata_outb(0x55, ioaddr->nsect_addr); - sata_outb(0xaa, ioaddr->lbal_addr); - - nsect = sata_inb(ioaddr->nsect_addr); - lbal = sata_inb(ioaddr->lbal_addr); - - if ((nsect == 0x55) && (lbal == 0xaa)) - return 1; /* we found a device */ - else - return 0; /* nothing found */ -} - -void dev_select(struct sata_ioports *ioaddr, int dev) -{ - u8 tmp = 0; - - if (dev == 0) - tmp = ATA_DEVICE_OBS; - else - tmp = ATA_DEVICE_OBS | ATA_DEV1; - - sata_outb(tmp, ioaddr->device_addr); - sata_inb(ioaddr->altstatus_addr); - udelay(5); -} - -u8 sata_busy_wait(struct sata_ioports *ioaddr, int bits, unsigned int max) -{ - u8 status; - - do { - udelay(1000); - status = sata_chk_status(ioaddr); - max--; - } while ((status & bits) && (max > 0)); - - return status; -} - -u8 sata_chk_status(struct sata_ioports *ioaddr) -{ - return sata_inb(ioaddr->status_addr); -} - - -ulong sata_read(int device, ulong blknr, lbaint_t blkcnt, void *buff) -{ - ulong n = 0, *buffer = (ulong *)buff; - u8 dev = 0, num = 0, mask = 0, status = 0; - -#ifdef CONFIG_LBA48 - unsigned char lba48 = 0; - - if (blknr & 0x0000fffff0000000) { - if (!sata_dev_desc[devno].lba48) { - printf("Drive doesn't support 48-bit addressing\n"); - return 0; - } - /* more than 28 bits used, use 48bit mode */ - lba48 = 1; - } -#endif - /* Port Number */ - num = device / CONFIG_SYS_SATA_DEVS_PER_BUS; - /* dev on the port */ - if (device >= CONFIG_SYS_SATA_DEVS_PER_BUS) - dev = device - CONFIG_SYS_SATA_DEVS_PER_BUS; - else - dev = device; - - if (dev == 0) - mask = 0x01; - else - mask = 0x02; - - if (!(port[num].dev_mask & mask)) { - printf("dev%d is not present on port#%d\n", dev, num); - return 0; - } - - /* Select device */ - dev_select(&port[num].ioaddr, dev); - - status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 500); - if (status & ATA_BUSY) { - printf("ata%u failed to respond\n", port[num].port_no); - return n; - } - while (blkcnt-- > 0) { - status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 500); - if (status & ATA_BUSY) { - printf("ata%u failed to respond\n", 0); - return n; - } -#ifdef CONFIG_LBA48 - if (lba48) { - /* write high bits */ - sata_outb(0, port[num].ioaddr.nsect_addr); - sata_outb((blknr >> 24) & 0xFF, - port[num].ioaddr.lbal_addr); - sata_outb((blknr >> 32) & 0xFF, - port[num].ioaddr.lbam_addr); - sata_outb((blknr >> 40) & 0xFF, - port[num].ioaddr.lbah_addr); - } -#endif - sata_outb(1, port[num].ioaddr.nsect_addr); - sata_outb(((blknr) >> 0) & 0xFF, - port[num].ioaddr.lbal_addr); - sata_outb((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr); - sata_outb((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr); - -#ifdef CONFIG_LBA48 - if (lba48) { - sata_outb(ATA_LBA, port[num].ioaddr.device_addr); - sata_outb(ATA_CMD_READ_EXT, - port[num].ioaddr.command_addr); - } else -#endif - { - sata_outb(ATA_LBA | ((blknr >> 24) & 0xF), - port[num].ioaddr.device_addr); - sata_outb(ATA_CMD_READ, - port[num].ioaddr.command_addr); - } - - mdelay(50); - /* may take up to 4 sec */ - status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 4000); - - if ((status & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) - != ATA_STAT_DRQ) { - u8 err = 0; - - printf("Error no DRQ dev %d blk %ld: sts 0x%02x\n", - device, (ulong) blknr, status); - err = sata_inb(port[num].ioaddr.error_addr); - printf("Error reg = 0x%x\n", err); - return n; - } - input_data(&port[num].ioaddr, buffer, ATA_SECTORWORDS); - sata_inb(port[num].ioaddr.altstatus_addr); - udelay(50); - - ++n; - ++blknr; - buffer += ATA_SECTORWORDS; - } - return n; -} - -ulong sata_write(int device, ulong blknr, lbaint_t blkcnt, const void *buff) -{ - ulong n = 0, *buffer = (ulong *)buff; - unsigned char status = 0, num = 0, dev = 0, mask = 0; - -#ifdef CONFIG_LBA48 - unsigned char lba48 = 0; - - if (blknr & 0x0000fffff0000000) { - if (!sata_dev_desc[devno].lba48) { - printf("Drive doesn't support 48-bit addressing\n"); - return 0; - } - /* more than 28 bits used, use 48bit mode */ - lba48 = 1; - } -#endif - /* Port Number */ - num = device / CONFIG_SYS_SATA_DEVS_PER_BUS; - /* dev on the Port */ - if (device >= CONFIG_SYS_SATA_DEVS_PER_BUS) - dev = device - CONFIG_SYS_SATA_DEVS_PER_BUS; - else - dev = device; - - if (dev == 0) - mask = 0x01; - else - mask = 0x02; - - /* Select device */ - dev_select(&port[num].ioaddr, dev); - - status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 500); - if (status & ATA_BUSY) { - printf("ata%u failed to respond\n", port[num].port_no); - return n; - } - - while (blkcnt-- > 0) { - status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 500); - if (status & ATA_BUSY) { - printf("ata%u failed to respond\n", - port[num].port_no); - return n; - } -#ifdef CONFIG_LBA48 - if (lba48) { - /* write high bits */ - sata_outb(0, port[num].ioaddr.nsect_addr); - sata_outb((blknr >> 24) & 0xFF, - port[num].ioaddr.lbal_addr); - sata_outb((blknr >> 32) & 0xFF, - port[num].ioaddr.lbam_addr); - sata_outb((blknr >> 40) & 0xFF, - port[num].ioaddr.lbah_addr); - } -#endif - sata_outb(1, port[num].ioaddr.nsect_addr); - sata_outb((blknr >> 0) & 0xFF, port[num].ioaddr.lbal_addr); - sata_outb((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr); - sata_outb((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr); -#ifdef CONFIG_LBA48 - if (lba48) { - sata_outb(ATA_LBA, port[num].ioaddr.device_addr); - sata_outb(ATA_CMD_WRITE_EXT, - port[num].ioaddr.command_addr); - } else -#endif - { - sata_outb(ATA_LBA | ((blknr >> 24) & 0xF), - port[num].ioaddr.device_addr); - sata_outb(ATA_CMD_WRITE, - port[num].ioaddr.command_addr); - } - - mdelay(50); - /* may take up to 4 sec */ - status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 4000); - if ((status & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) - != ATA_STAT_DRQ) { - printf("Error no DRQ dev %d blk %ld: sts 0x%02x\n", - device, (ulong) blknr, status); - return n; - } - - output_data(&port[num].ioaddr, buffer, ATA_SECTORWORDS); - sata_inb(port[num].ioaddr.altstatus_addr); - udelay(50); - - ++n; - ++blknr; - buffer += ATA_SECTORWORDS; - } - return n; -} - -int scan_sata(int dev) -{ - return 0; -} diff --git a/drivers/block/ata_piix.h b/drivers/block/ata_piix.h deleted file mode 100644 index 6c68ea2..0000000 --- a/drivers/block/ata_piix.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef __ATA_PIIX_H__ -#define __ATA_PIIX_H__ - -struct sata_ioports { - unsigned long cmd_addr; - unsigned long data_addr; - unsigned long error_addr; - unsigned long feature_addr; - unsigned long nsect_addr; - unsigned long lbal_addr; - unsigned long lbam_addr; - unsigned long lbah_addr; - unsigned long device_addr; - unsigned long status_addr; - unsigned long command_addr; - unsigned long altstatus_addr; - unsigned long ctl_addr; - unsigned long bmdma_addr; - unsigned long scr_addr; -}; - -struct sata_port { - unsigned char port_no; /* primary=0, secondary=1 */ - struct sata_ioports ioaddr; /* ATA cmd/ctl/dma reg blks */ - unsigned char ctl_reg; - unsigned char last_ctl; - unsigned char port_state; /* 1-port is available and */ - /* 0-port is not available */ - unsigned char dev_mask; -}; - -/***********SATA LIBRARY SPECIFIC DEFINITIONS AND DECLARATIONS**************/ -#ifdef SATA_DECL /* SATA library specific declarations */ -inline void ata_dump_id(u16 *id) -{ - debug("49 = 0x%04x " - "53 = 0x%04x " - "63 = 0x%04x " - "64 = 0x%04x " - "75 = 0x%04x\n", id[49], id[53], id[63], id[64], id[75]); - debug("80 = 0x%04x " - "81 = 0x%04x " - "82 = 0x%04x " - "83 = 0x%04x " - "84 = 0x%04x\n", id[80], id[81], id[82], id[83], id[84]); - debug("88 = 0x%04x " "93 = 0x%04x\n", id[88], id[93]); -} -#endif - -#ifdef SATA_DECL /*SATA library specific declarations */ -int sata_bus_softreset(int num); -void sata_identify(int num, int dev); -void sata_port(struct sata_ioports *ioport); -void set_Feature_cmd(int num, int dev); -int sata_devchk(struct sata_ioports *ioaddr, int dev); -void dev_select(struct sata_ioports *ioaddr, int dev); -u8 sata_busy_wait(struct sata_ioports *ioaddr, int bits, unsigned int max); -u8 sata_chk_status(struct sata_ioports *ioaddr); -#endif - -/************DRIVER SPECIFIC DEFINITIONS AND DECLARATIONS**************/ - -#ifdef DRV_DECL /* Driver specific declaration */ -int init_sata(int dev); -#endif - -#ifdef DRV_DECL /* Defines Driver Specific variables */ -struct sata_port port[CONFIG_SYS_SATA_MAXBUS]; -#endif - -#endif /* __ATA_PIIX_H__ */ -- cgit v0.10.2 From 6c89663cb152bb49f7618f283d999c417fd85746 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 8 Jul 2015 13:06:40 +0800 Subject: pci: Configure expansion ROM during auto config process Currently PCI expansion ROM address is assigned by a call to pciauto_setup_rom() outside of the pci auto config process. This does not work when expansion ROM is on a device behind PCI bridge where bridge's memory limit register was already programmed to a value that does not cover the newly assigned expansion ROM address. To fix this, we should configure the ROM address during the auto config process. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Tested-by: Simon Glass Acked-by: Simon Glass diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index 7c10983..e034ed1 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -87,6 +87,8 @@ void pciauto_setup_device(struct pci_controller *hose, pci_size_t bar_size; u16 cmdstat = 0; int bar, bar_nr = 0; + u8 header_type; + int rom_addr; #ifndef CONFIG_PCI_ENUM_ONLY pci_addr_t bar_value; struct pci_region *bar_res; @@ -182,38 +184,32 @@ void pciauto_setup_device(struct pci_controller *hose, bar_nr++; } + /* Configure the expansion ROM address */ + pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type); + if (header_type != PCI_HEADER_TYPE_CARDBUS) { + rom_addr = (header_type == PCI_HEADER_TYPE_NORMAL) ? + PCI_ROM_ADDRESS : PCI_ROM_ADDRESS1; + pci_hose_write_config_dword(hose, dev, rom_addr, 0xfffffffe); + pci_hose_read_config_dword(hose, dev, rom_addr, &bar_response); + if (bar_response) { + bar_size = -(bar_response & ~1); + DEBUGF("PCI Autoconfig: ROM, size=%#x, ", bar_size); + if (pciauto_region_allocate(mem, bar_size, + &bar_value) == 0) { + pci_hose_write_config_dword(hose, dev, rom_addr, + bar_value); + } + cmdstat |= PCI_COMMAND_MEMORY; + DEBUGF("\n"); + } + } + pci_hose_write_config_word(hose, dev, PCI_COMMAND, cmdstat); pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, CONFIG_SYS_PCI_CACHE_LINE_SIZE); pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80); } -int pciauto_setup_rom(struct pci_controller *hose, pci_dev_t dev) -{ - pci_addr_t bar_value; - pci_size_t bar_size; - u32 bar_response; - u16 cmdstat = 0; - - pci_hose_write_config_dword(hose, dev, PCI_ROM_ADDRESS, 0xfffffffe); - pci_hose_read_config_dword(hose, dev, PCI_ROM_ADDRESS, &bar_response); - if (!bar_response) - return -ENOENT; - - bar_size = -(bar_response & ~1); - DEBUGF("PCI Autoconfig: ROM, size=%#x, ", bar_size); - if (pciauto_region_allocate(hose->pci_mem, bar_size, &bar_value) == 0) { - pci_hose_write_config_dword(hose, dev, PCI_ROM_ADDRESS, - bar_value); - } - DEBUGF("\n"); - pci_hose_read_config_word(hose, dev, PCI_COMMAND, &cmdstat); - cmdstat |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; - pci_hose_write_config_word(hose, dev, PCI_COMMAND, cmdstat); - - return 0; -} - void pciauto_prescan_setup_bridge(struct pci_controller *hose, pci_dev_t dev, int sub_bus) { diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c index e7f9959..aa06767 100644 --- a/drivers/pci/pci_rom.c +++ b/drivers/pci/pci_rom.c @@ -84,11 +84,6 @@ static int pci_rom_probe(pci_dev_t dev, uint class, rom_address = CONFIG_VGA_BIOS_ADDR; #else - if (pciauto_setup_rom(pci_bus_to_hose(PCI_BUS(dev)), dev)) { - debug("Cannot find option ROM\n"); - return -ENOENT; - } - pci_read_config_dword(dev, PCI_ROM_ADDRESS, &rom_address); if (rom_address == 0x00000000 || rom_address == 0xffffffff) { debug("%s: rom_address=%x\n", __func__, rom_address); diff --git a/include/pci.h b/include/pci.h index 3af511b..542e68b 100644 --- a/include/pci.h +++ b/include/pci.h @@ -722,15 +722,6 @@ void pci_write_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum, u32 pci_read_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum); /** - * pciauto_setup_rom() - Set up access to a device ROM - * - * @hose: PCI hose to use - * @dev: PCI device to adjust - * @return 0 if done, -ve on error - */ -int pciauto_setup_rom(struct pci_controller *hose, pci_dev_t dev); - -/** * pci_hose_find_devices() - Find devices by vendor/device ID * * @hose: PCI hose to search -- cgit v0.10.2 From f110da9984c0aa0aba9e1c4178b67b7abecf7e8d Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 8 Jul 2015 13:06:41 +0800 Subject: pci: Disable expansion ROM address decoding when signature check fails We should not leave the expansion ROM address window open when there is not a valid ROM. Suggested-by: Matt Porter Signed-off-by: Bin Meng Tested-by: Simon Glass Acked-by: Simon Glass diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c index aa06767..a33efae 100644 --- a/drivers/pci/pci_rom.c +++ b/drivers/pci/pci_rom.c @@ -104,6 +104,10 @@ static int pci_rom_probe(pci_dev_t dev, uint class, if (le16_to_cpu(rom_header->signature) != PCI_ROM_HDR) { printf("Incorrect expansion ROM header signature %04x\n", le16_to_cpu(rom_header->signature)); +#ifndef CONFIG_VGA_BIOS_ADDR + /* Disable expansion ROM address decoding */ + pci_write_config_dword(dev, PCI_ROM_ADDRESS, rom_address); +#endif return -EINVAL; } -- cgit v0.10.2