diff options
| author | Stefano Babic <sbabic@denx.de> | 2012-11-10 08:05:54 +0100 | 
|---|---|---|
| committer | Stefano Babic <sbabic@denx.de> | 2012-11-10 08:05:54 +0100 | 
| commit | 3e4d27b06d7484040355e22eec2cbce7335d6dab (patch) | |
| tree | 9672a2bb2e4ce0edc0ab776ddf0e2ca8e39a5f62 /arch/powerpc/cpu/mpc85xx/mp.c | |
| parent | bad05afe083eec0467220de21683443292c5012e (diff) | |
| parent | 59852d03867108217fe88e3bfc3e1e9cedfe63c5 (diff) | |
| download | olio-uboot-2014.01-3e4d27b06d7484040355e22eec2cbce7335d6dab.tar.xz olio-uboot-2014.01-3e4d27b06d7484040355e22eec2cbce7335d6dab.zip | |
Merge git://git.denx.de/u-boot
Diffstat (limited to 'arch/powerpc/cpu/mpc85xx/mp.c')
| -rw-r--r-- | arch/powerpc/cpu/mpc85xx/mp.c | 155 | 
1 files changed, 114 insertions, 41 deletions
| diff --git a/arch/powerpc/cpu/mpc85xx/mp.c b/arch/powerpc/cpu/mpc85xx/mp.c index ffc2a9ad6..e1197ac9e 100644 --- a/arch/powerpc/cpu/mpc85xx/mp.c +++ b/arch/powerpc/cpu/mpc85xx/mp.c @@ -27,9 +27,13 @@  #include <asm/io.h>  #include <asm/mmu.h>  #include <asm/fsl_law.h> +#include <asm/fsl_ddr_sdram.h>  #include "mp.h"  DECLARE_GLOBAL_DATA_PTR; +u32 fsl_ddr_get_intl3r(void); + +extern u32 __spin_table[];  u32 get_my_id()  { @@ -76,17 +80,16 @@ int cpu_status(int nr)  		return 0;  	if (nr == id) { -		table = (u32 *)get_spin_virt_addr(); +		table = (u32 *)&__spin_table;  		printf("table base @ 0x%p\n", table);  	} else { -		table = (u32 *)get_spin_virt_addr() + nr * NUM_BOOT_ENTRY; +		table = (u32 *)&__spin_table + nr * NUM_BOOT_ENTRY;  		printf("Running on cpu %d\n", id);  		printf("\n");  		printf("table @ 0x%p\n", table);  		printf("   addr - 0x%08x\n", table[BOOT_ENTRY_ADDR_LOWER]); -		printf("   pir  - 0x%08x\n", table[BOOT_ENTRY_PIR]);  		printf("   r3   - 0x%08x\n", table[BOOT_ENTRY_R3_LOWER]); -		printf("   r6   - 0x%08x\n", table[BOOT_ENTRY_R6_LOWER]); +		printf("   pir  - 0x%08x\n", table[BOOT_ENTRY_PIR]);  	}  	return 0; @@ -149,12 +152,11 @@ static u8 boot_entry_map[4] = {  	0,  	BOOT_ENTRY_PIR,  	BOOT_ENTRY_R3_LOWER, -	BOOT_ENTRY_R6_LOWER,  };  int cpu_release(int nr, int argc, char * const argv[])  { -	u32 i, val, *table = (u32 *)get_spin_virt_addr() + nr * NUM_BOOT_ENTRY; +	u32 i, val, *table = (u32 *)&__spin_table + nr * NUM_BOOT_ENTRY;  	u64 boot_addr;  	if (hold_cores_in_reset(1)) @@ -172,8 +174,8 @@ int cpu_release(int nr, int argc, char * const argv[])  	boot_addr = simple_strtoull(argv[0], NULL, 16); -	/* handle pir, r3, r6 */ -	for (i = 1; i < 4; i++) { +	/* handle pir, r3 */ +	for (i = 1; i < 3; i++) {  		if (argv[i][0] != '-') {  			u8 entry = boot_entry_map[i];  			val = simple_strtoul(argv[i], NULL, 16); @@ -191,38 +193,80 @@ int cpu_release(int nr, int argc, char * const argv[])  	return 0;  } -u32 determine_mp_bootpg(void) +u32 determine_mp_bootpg(unsigned int *pagesize)  { -	/* if we have 4G or more of memory, put the boot page at 4Gb-4k */ -	if ((u64)gd->ram_size > 0xfffff000) -		return (0xfffff000); +	u32 bootpg; +#ifdef CONFIG_SYS_FSL_ERRATUM_A004468 +	u32 svr = get_svr(); +	u32 granule_size, check; +	struct law_entry e; +#endif -	return (gd->ram_size - 4096); -} -ulong get_spin_phys_addr(void) -{ -	extern ulong __secondary_start_page; -	extern ulong __spin_table; +	/* use last 4K of mapped memory */ +	bootpg = ((gd->ram_size > CONFIG_MAX_MEM_MAPPED) ? +		CONFIG_MAX_MEM_MAPPED : gd->ram_size) + +		CONFIG_SYS_SDRAM_BASE - 4096; +	if (pagesize) +		*pagesize = 4096; + +#ifdef CONFIG_SYS_FSL_ERRATUM_A004468 +/* + * Erratum A004468 has two parts. The 3-way interleaving applies to T4240, + * to be fixed in rev 2.0. The 2-way interleaving applies to many SoCs. But + * the way boot page chosen in u-boot avoids hitting this erratum. So only + * thw workaround for 3-way interleaving is needed. + * + * To make sure boot page translation works with 3-Way DDR interleaving + * enforce a check for the following constrains + * 8K granule size requires BRSIZE=8K and + *    bootpg >> log2(BRSIZE) %3 == 1 + * 4K and 1K granule size requires BRSIZE=4K and + *    bootpg >> log2(BRSIZE) %3 == 0 + */ +	if (SVR_SOC_VER(svr) == SVR_T4240 && SVR_MAJ(svr) < 2) { +		e = find_law(bootpg); +		switch (e.trgt_id) { +		case LAW_TRGT_IF_DDR_INTLV_123: +			granule_size = fsl_ddr_get_intl3r() & 0x1f; +			if (granule_size == FSL_DDR_3WAY_8KB_INTERLEAVING) { +				if (pagesize) +					*pagesize = 8192; +				bootpg &= 0xffffe000;	/* align to 8KB */ +				check = bootpg >> 13; +				while ((check % 3) != 1) +					check--; +				bootpg = check << 13; +				debug("Boot page (8K) at 0x%08x\n", bootpg); +				break; +			} else { +				bootpg &= 0xfffff000;	/* align to 4KB */ +				check = bootpg >> 12; +				while ((check % 3) != 0) +					check--; +				bootpg = check << 12; +				debug("Boot page (4K) at 0x%08x\n", bootpg); +			} +				break; +		default: +			break; +		} +	} +#endif /* CONFIG_SYS_FSL_ERRATUM_A004468 */ -	return (determine_mp_bootpg() + -		(ulong)&__spin_table - (ulong)&__secondary_start_page); +	return bootpg;  } -ulong get_spin_virt_addr(void) +phys_addr_t get_spin_phys_addr(void)  { -	extern ulong __secondary_start_page; -	extern ulong __spin_table; - -	return (CONFIG_BPTR_VIRT_ADDR + -		(ulong)&__spin_table - (ulong)&__secondary_start_page); +	return virt_to_phys(&__spin_table);  }  #ifdef CONFIG_FSL_CORENET -static void plat_mp_up(unsigned long bootpg) +static void plat_mp_up(unsigned long bootpg, unsigned int pagesize)  { -	u32 cpu_up_mask, whoami; -	u32 *table = (u32 *)get_spin_virt_addr(); +	u32 cpu_up_mask, whoami, brsize = LAW_SIZE_4K; +	u32 *table = (u32 *)&__spin_table;  	volatile ccsr_gur_t *gur;  	volatile ccsr_local_t *ccm;  	volatile ccsr_rcpm_t *rcpm; @@ -241,7 +285,11 @@ static void plat_mp_up(unsigned long bootpg)  	out_be32(&ccm->bstrl, bootpg);  	e = find_law(bootpg); -	out_be32(&ccm->bstrar, LAW_EN | e.trgt_id << 20 | LAW_SIZE_4K); +	/* pagesize is only 4K or 8K */ +	if (pagesize == 8192) +		brsize = LAW_SIZE_8K; +	out_be32(&ccm->bstrar, LAW_EN | e.trgt_id << 20 | brsize); +	debug("BRSIZE is 0x%x\n", brsize);  	/* readback to sync write */  	in_be32(&ccm->bstrar); @@ -294,10 +342,10 @@ static void plat_mp_up(unsigned long bootpg)  #endif  }  #else -static void plat_mp_up(unsigned long bootpg) +static void plat_mp_up(unsigned long bootpg, unsigned int pagesize)  {  	u32 up, cpu_up_mask, whoami; -	u32 *table = (u32 *)get_spin_virt_addr(); +	u32 *table = (u32 *)&__spin_table;  	volatile u32 bpcr;  	volatile ccsr_local_ecm_t *ecm = (void *)(CONFIG_SYS_MPC85xx_ECM_ADDR);  	volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); @@ -374,27 +422,52 @@ static void plat_mp_up(unsigned long bootpg)  void cpu_mp_lmb_reserve(struct lmb *lmb)  { -	u32 bootpg = determine_mp_bootpg(); +	u32 bootpg = determine_mp_bootpg(NULL);  	lmb_reserve(lmb, bootpg, 4096);  }  void setup_mp(void)  { -	extern ulong __secondary_start_page; -	extern ulong __bootpg_addr; -	ulong fixup = (ulong)&__secondary_start_page; -	u32 bootpg = determine_mp_bootpg(); +	extern u32 __secondary_start_page; +	extern u32 __bootpg_addr, __spin_table_addr, __second_half_boot_page; + +	int i; +	ulong fixup = (u32)&__secondary_start_page; +	u32 bootpg, bootpg_map, pagesize; + +	bootpg = determine_mp_bootpg(&pagesize); + +	/* +	 * pagesize is only 4K or 8K +	 * we only use the last 4K of boot page +	 * bootpg_map saves the address for the boot page +	 * 8K is used for the workaround of 3-way DDR interleaving +	 */ + +	bootpg_map = bootpg; + +	if (pagesize == 8192) +		bootpg += 4096;	/* use 2nd half */  	/* 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; +	/* +	 * Store the bootpg's cache-able half address for use by secondary +	 * CPU cores to continue to boot +	 */ +	__bootpg_addr = (u32)virt_to_phys(&__second_half_boot_page); + +	/* Store spin table's physical address for use by secondary cores */ +	__spin_table_addr = (u32)get_spin_phys_addr(); + +	/* flush bootpg it before copying invalidate any staled cacheline */ +	flush_cache(bootpg, 4096);  	/* look for the tlb covering the reset page, there better be one */ -	int i = find_tlb_idx((void *)CONFIG_BPTR_VIRT_ADDR, 1); +	i = find_tlb_idx((void *)CONFIG_BPTR_VIRT_ADDR, 1);  	/* we found a match */  	if (i != -1) { @@ -407,7 +480,7 @@ void setup_mp(void)  		memcpy((void *)CONFIG_BPTR_VIRT_ADDR, (void *)fixup, 4096); -		plat_mp_up(bootpg); +		plat_mp_up(bootpg_map, pagesize);  	} else {  		puts("WARNING: No reset page TLB. "  			"Skipping secondary core setup\n"); |