diff options
Diffstat (limited to 'arch/powerpc/cpu/mpc85xx')
-rw-r--r-- | arch/powerpc/cpu/mpc85xx/config.mk | 4 | ||||
-rw-r--r-- | arch/powerpc/cpu/mpc85xx/cpu.c | 219 | ||||
-rw-r--r-- | arch/powerpc/cpu/mpc85xx/fdt.c | 22 | ||||
-rw-r--r-- | arch/powerpc/cpu/mpc85xx/mp.c | 31 | ||||
-rw-r--r-- | arch/powerpc/cpu/mpc85xx/mp.h | 1 | ||||
-rw-r--r-- | arch/powerpc/cpu/mpc85xx/tlb.c | 16 | ||||
-rw-r--r-- | arch/powerpc/cpu/mpc85xx/u-boot.lds | 52 |
7 files changed, 294 insertions, 51 deletions
diff --git a/arch/powerpc/cpu/mpc85xx/config.mk b/arch/powerpc/cpu/mpc85xx/config.mk index f07d9209a7..ce4376b100 100644 --- a/arch/powerpc/cpu/mpc85xx/config.mk +++ b/arch/powerpc/cpu/mpc85xx/config.mk @@ -25,6 +25,10 @@ PLATFORM_RELFLAGS += -fPIC -meabi PLATFORM_CPPFLAGS += -ffixed-r2 -Wa,-me500 -msoft-float -mno-string +# Enable gc-sections to enable generation of smaller images. +PLATFORM_LDFLAGS += --gc-sections +PLATFORM_RELFLAGS += -ffunction-sections -fdata-sections + # -mspe=yes is needed to have -mno-spe accepted by a buggy GCC; # see "[PATCH,rs6000] make -mno-spe work as expected" on # http://gcc.gnu.org/ml/gcc-patches/2008-04/msg00311.html diff --git a/arch/powerpc/cpu/mpc85xx/cpu.c b/arch/powerpc/cpu/mpc85xx/cpu.c index 3f80700711..fc5d951e9a 100644 --- a/arch/powerpc/cpu/mpc85xx/cpu.c +++ b/arch/powerpc/cpu/mpc85xx/cpu.c @@ -34,6 +34,9 @@ #include <asm/io.h> #include <asm/mmu.h> #include <asm/fsl_law.h> +#include <post.h> +#include <asm/processor.h> +#include <asm/fsl_ddr_sdram.h> DECLARE_GLOBAL_DATA_PTR; @@ -282,3 +285,219 @@ void mpc85xx_reginfo(void) print_laws(); print_lbc_regs(); } + +#if CONFIG_POST & CONFIG_SYS_POST_MEMORY + +/* Board-specific functions defined in each board's ddr.c */ +void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd, + unsigned int ctrl_num); +void read_tlbcam_entry(int idx, u32 *valid, u32 *tsize, unsigned long *epn, + phys_addr_t *rpn); +unsigned int + setup_ddr_tlbs_phys(phys_addr_t p_addr, unsigned int memsize_in_meg); + +static void dump_spd_ddr_reg(void) +{ + int i, j, k, m; + u8 *p_8; + u32 *p_32; + ccsr_ddr_t *ddr[CONFIG_NUM_DDR_CONTROLLERS]; + generic_spd_eeprom_t + spd[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR]; + + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) + fsl_ddr_get_spd(spd[i], i); + + puts("SPD data of all dimms (zero vaule is omitted)...\n"); + puts("Byte (hex) "); + k = 1; + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) + printf("Dimm%d ", k++); + } + puts("\n"); + for (k = 0; k < sizeof(generic_spd_eeprom_t); k++) { + m = 0; + printf("%3d (0x%02x) ", k, k); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + p_8 = (u8 *) &spd[i][j]; + if (p_8[k]) { + printf("0x%02x ", p_8[k]); + m++; + } else + puts(" "); + } + } + if (m) + puts("\n"); + else + puts("\r"); + } + + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + switch (i) { + case 0: + ddr[i] = (void *)CONFIG_SYS_MPC85xx_DDR_ADDR; + break; +#ifdef CONFIG_SYS_MPC85xx_DDR2_ADDR + case 1: + ddr[i] = (void *)CONFIG_SYS_MPC85xx_DDR2_ADDR; + break; +#endif + default: + printf("%s unexpected controller number = %u\n", + __func__, i); + return; + } + } + printf("DDR registers dump for all controllers " + "(zero vaule is omitted)...\n"); + puts("Offset (hex) "); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) + printf(" Base + 0x%04x", (u32)ddr[i] & 0xFFFF); + puts("\n"); + for (k = 0; k < sizeof(ccsr_ddr_t)/4; k++) { + m = 0; + printf("%6d (0x%04x)", k * 4, k * 4); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + p_32 = (u32 *) ddr[i]; + if (p_32[k]) { + printf(" 0x%08x", p_32[k]); + m++; + } else + puts(" "); + } + if (m) + puts("\n"); + else + puts("\r"); + } + puts("\n"); +} + +/* invalid the TLBs for DDR and setup new ones to cover p_addr */ +static int reset_tlb(phys_addr_t p_addr, u32 size, phys_addr_t *phys_offset) +{ + u32 vstart = CONFIG_SYS_DDR_SDRAM_BASE; + unsigned long epn; + u32 tsize, valid, ptr; + phys_addr_t rpn = 0; + int ddr_esel; + + ptr = vstart; + + while (ptr < (vstart + size)) { + ddr_esel = find_tlb_idx((void *)ptr, 1); + if (ddr_esel != -1) { + read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, &rpn); + disable_tlb(ddr_esel); + } + ptr += TSIZE_TO_BYTES(tsize); + } + + /* Setup new tlb to cover the physical address */ + setup_ddr_tlbs_phys(p_addr, size>>20); + + ptr = vstart; + ddr_esel = find_tlb_idx((void *)ptr, 1); + if (ddr_esel != -1) { + read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, phys_offset); + } else { + printf("TLB error in function %s\n", __func__); + return -1; + } + + return 0; +} + +/* + * slide the testing window up to test another area + * for 32_bit system, the maximum testable memory is limited to + * CONFIG_MAX_MEM_MAPPED + */ +int arch_memory_test_advance(u32 *vstart, u32 *size, phys_addr_t *phys_offset) +{ + phys_addr_t test_cap, p_addr; + phys_size_t p_size = min(gd->ram_size, CONFIG_MAX_MEM_MAPPED); + +#if !defined(CONFIG_PHYS_64BIT) || \ + !defined(CONFIG_SYS_INIT_RAM_ADDR_PHYS) || \ + (CONFIG_SYS_INIT_RAM_ADDR_PHYS < 0x100000000ull) + test_cap = p_size; +#else + test_cap = gd->ram_size; +#endif + p_addr = (*vstart) + (*size) + (*phys_offset); + if (p_addr < test_cap - 1) { + p_size = min(test_cap - p_addr, CONFIG_MAX_MEM_MAPPED); + if (reset_tlb(p_addr, p_size, phys_offset) == -1) + return -1; + *vstart = CONFIG_SYS_DDR_SDRAM_BASE; + *size = (u32) p_size; + printf("Testing 0x%08llx - 0x%08llx\n", + (u64)(*vstart) + (*phys_offset), + (u64)(*vstart) + (*phys_offset) + (*size) - 1); + } else + return 1; + + return 0; +} + +/* initialization for testing area */ +int arch_memory_test_prepare(u32 *vstart, u32 *size, phys_addr_t *phys_offset) +{ + phys_size_t p_size = min(gd->ram_size, CONFIG_MAX_MEM_MAPPED); + + *vstart = CONFIG_SYS_DDR_SDRAM_BASE; + *size = (u32) p_size; /* CONFIG_MAX_MEM_MAPPED < 4G */ + *phys_offset = 0; + +#if !defined(CONFIG_PHYS_64BIT) || \ + !defined(CONFIG_SYS_INIT_RAM_ADDR_PHYS) || \ + (CONFIG_SYS_INIT_RAM_ADDR_PHYS < 0x100000000ull) + if (gd->ram_size > CONFIG_MAX_MEM_MAPPED) { + puts("Cannot test more than "); + print_size(CONFIG_MAX_MEM_MAPPED, + " without proper 36BIT support.\n"); + } +#endif + printf("Testing 0x%08llx - 0x%08llx\n", + (u64)(*vstart) + (*phys_offset), + (u64)(*vstart) + (*phys_offset) + (*size) - 1); + + return 0; +} + +/* invalid TLBs for DDR and remap as normal after testing */ +int arch_memory_test_cleanup(u32 *vstart, u32 *size, phys_addr_t *phys_offset) +{ + unsigned long epn; + u32 tsize, valid, ptr; + phys_addr_t rpn = 0; + int ddr_esel; + + /* disable the TLBs for this testing */ + ptr = *vstart; + + while (ptr < (*vstart) + (*size)) { + ddr_esel = find_tlb_idx((void *)ptr, 1); + if (ddr_esel != -1) { + read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, &rpn); + disable_tlb(ddr_esel); + } + ptr += TSIZE_TO_BYTES(tsize); + } + + puts("Remap DDR "); + setup_ddr_tlbs(gd->ram_size>>20); + puts("\n"); + + return 0; +} + +void arch_memory_failure_handle(void) +{ + dump_spd_ddr_reg(); +} +#endif diff --git a/arch/powerpc/cpu/mpc85xx/fdt.c b/arch/powerpc/cpu/mpc85xx/fdt.c index 45403641cf..53e0596554 100644 --- a/arch/powerpc/cpu/mpc85xx/fdt.c +++ b/arch/powerpc/cpu/mpc85xx/fdt.c @@ -48,6 +48,7 @@ void ft_fixup_cpu(void *blob, u64 memory_limit) ulong spin_tbl_addr = get_spin_phys_addr(); u32 bootpg = determine_mp_bootpg(); u32 id = get_my_id(); + const char *enable_method; off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); while (off != -FDT_ERR_NOTFOUND) { @@ -63,10 +64,25 @@ void ft_fixup_cpu(void *blob, u64 memory_limit) fdt_setprop_string(blob, off, "status", "disabled"); } + + if (hold_cores_in_reset(0)) { +#ifdef CONFIG_FSL_CORENET + /* Cores held in reset, use BRR to release */ + enable_method = "fsl,brr-holdoff"; +#else + /* Cores held in reset, use EEBPCR to release */ + enable_method = "fsl,eebpcr-holdoff"; +#endif + } else { + /* Cores out of reset and in a spin-loop */ + enable_method = "spin-table"; + + fdt_setprop(blob, off, "cpu-release-addr", + &val, sizeof(val)); + } + fdt_setprop_string(blob, off, "enable-method", - "spin-table"); - fdt_setprop(blob, off, "cpu-release-addr", - &val, sizeof(val)); + enable_method); } else { printf ("cpu NULL\n"); } diff --git a/arch/powerpc/cpu/mpc85xx/mp.c b/arch/powerpc/cpu/mpc85xx/mp.c index 603baef1bd..a019b1bdb1 100644 --- a/arch/powerpc/cpu/mpc85xx/mp.c +++ b/arch/powerpc/cpu/mpc85xx/mp.c @@ -36,6 +36,27 @@ u32 get_my_id() return mfspr(SPRN_PIR); } +/* + * Determine if U-Boot should keep secondary cores in reset, or let them out + * of reset and hold them in a spinloop + */ +int hold_cores_in_reset(int verbose) +{ + const char *s = getenv("mp_holdoff"); + + /* Default to no, overriden by 'y', 'yes', 'Y', 'Yes', or '1' */ + if (s && (*s == 'y' || *s == 'Y' || *s == '1')) { + if (verbose) { + puts("Secondary cores are being held in reset.\n"); + puts("See 'mp_holdoff' environment variable\n"); + } + + return 1; + } + + return 0; +} + int cpu_reset(int nr) { volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR); @@ -51,6 +72,9 @@ int cpu_status(int nr) { u32 *table, id = get_my_id(); + if (hold_cores_in_reset(1)) + return 0; + if (nr == id) { table = (u32 *)get_spin_virt_addr(); printf("table base @ 0x%p\n", table); @@ -133,6 +157,9 @@ int cpu_release(int nr, int argc, char * const argv[]) u32 i, val, *table = (u32 *)get_spin_virt_addr() + nr * NUM_BOOT_ENTRY; u64 boot_addr; + if (hold_cores_in_reset(1)) + return 0; + if (nr == get_my_id()) { printf("Invalid to release the boot core.\n\n"); return 1; @@ -353,6 +380,10 @@ void setup_mp(void) ulong fixup = (ulong)&__secondary_start_page; u32 bootpg = determine_mp_bootpg(); + /* Some OSes expect secondary cores to be held in reset */ + if (hold_cores_in_reset(0)) + return; + /* Store the bootpg's SDRAM address for use by secondary CPU cores */ __bootpg_addr = bootpg; diff --git a/arch/powerpc/cpu/mpc85xx/mp.h b/arch/powerpc/cpu/mpc85xx/mp.h index 3422cc1070..87bac37152 100644 --- a/arch/powerpc/cpu/mpc85xx/mp.h +++ b/arch/powerpc/cpu/mpc85xx/mp.h @@ -6,6 +6,7 @@ ulong get_spin_phys_addr(void); ulong get_spin_virt_addr(void); u32 get_my_id(void); +int hold_cores_in_reset(int verbose); #define BOOT_ENTRY_ADDR_UPPER 0 #define BOOT_ENTRY_ADDR_LOWER 1 diff --git a/arch/powerpc/cpu/mpc85xx/tlb.c b/arch/powerpc/cpu/mpc85xx/tlb.c index f2833a5df7..e3a71aec5c 100644 --- a/arch/powerpc/cpu/mpc85xx/tlb.c +++ b/arch/powerpc/cpu/mpc85xx/tlb.c @@ -245,7 +245,8 @@ void init_addr_map(void) } #endif -unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg) +unsigned int +setup_ddr_tlbs_phys(phys_addr_t p_addr, unsigned int memsize_in_meg) { int i; unsigned int tlb_size; @@ -275,21 +276,24 @@ unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg) tlb_size = (camsize - 10) / 2; - set_tlb(1, ram_tlb_address, ram_tlb_address, + set_tlb(1, ram_tlb_address, p_addr, MAS3_SX|MAS3_SW|MAS3_SR, 0, 0, ram_tlb_index, tlb_size, 1); size -= 1ULL << camsize; memsize -= 1ULL << camsize; ram_tlb_address += 1UL << camsize; + p_addr += 1UL << camsize; } if (memsize) print_size(memsize, " left unmapped\n"); - - /* - * Confirm that the requested amount of memory was mapped. - */ return memsize_in_meg; } + +unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg) +{ + return + setup_ddr_tlbs_phys(CONFIG_SYS_DDR_SDRAM_BASE, memsize_in_meg); +} #endif /* !CONFIG_NAND_SPL */ diff --git a/arch/powerpc/cpu/mpc85xx/u-boot.lds b/arch/powerpc/cpu/mpc85xx/u-boot.lds index c88b1f35b9..85042c5254 100644 --- a/arch/powerpc/cpu/mpc85xx/u-boot.lds +++ b/arch/powerpc/cpu/mpc85xx/u-boot.lds @@ -25,8 +25,7 @@ #endif OUTPUT_ARCH(powerpc) -/* Do we need any of these for elf? - __DYNAMIC = 0; */ + PHDRS { text PT_LOAD; @@ -38,42 +37,16 @@ SECTIONS /* Read-only sections, merged into text segment: */ . = + SIZEOF_HEADERS; .interp : { *(.interp) } - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .rel.text : { *(.rel.text) } - .rela.text : { *(.rela.text) } - .rel.data : { *(.rel.data) } - .rela.data : { *(.rela.data) } - .rel.rodata : { *(.rel.rodata) } - .rela.rodata : { *(.rela.rodata) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.bss : { *(.rel.bss) } - .rela.bss : { *(.rela.bss) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : { *(.init) } - .plt : { *(.plt) } .text : { - *(.text) - *(.got1) + *(.text*) } :text _etext = .; PROVIDE (etext = .); .rodata : { - *(.eh_frame) *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } :text - .fini : { *(.fini) } =0 - .ctors : { *(.ctors) } - .dtors : { *(.dtors) } /* Read-write section, merged into data segment: */ . = (. + 0x00FF) & 0xFFFFFF00; @@ -81,23 +54,19 @@ SECTIONS PROVIDE (erotext = .); .reloc : { - *(.got) + KEEP(*(.got)) _GOT2_TABLE_ = .; - *(.got2) + KEEP(*(.got2)) _FIXUP_TABLE_ = .; - *(.fixup) + KEEP(*(.fixup)) } __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; __fixup_entries = (. - _FIXUP_TABLE_) >> 2; .data : { - *(.data) - *(.data1) - *(.sdata) - *(.sdata2) - *(.dynamic) - CONSTRUCTORS + *(.data*) + *(.sdata*) } _edata = .; PROVIDE (edata = .); @@ -126,7 +95,7 @@ SECTIONS .resetvec RESET_VECTOR_ADDRESS : { - *(.resetvec) + KEEP(*(.resetvec)) } :text = 0xffff . = RESET_VECTOR_ADDRESS + 0x4; @@ -145,9 +114,8 @@ SECTIONS __bss_start = .; .bss (NOLOAD) : { - *(.sbss) *(.scommon) - *(.dynbss) - *(.bss) + *(.sbss*) + *(.bss*) *(COMMON) } :bss |