u-boot/arch/powerpc/cpu/mpc85xx/mp.c

478 lines
11 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2008-2011 Freescale Semiconductor, Inc.
*/
#include <common.h>
#include <cpu_func.h>
#include <env.h>
#include <log.h>
#include <asm/global_data.h>
#include <asm/processor.h>
#include <env.h>
#include <ioports.h>
#include <lmb.h>
#include <asm/io.h>
#include <asm/mmu.h>
#include <asm/fsl_law.h>
#include <fsl_ddr_sdram.h>
#include <linux/delay.h>
#include "mp.h"
DECLARE_GLOBAL_DATA_PTR;
u32 fsl_ddr_get_intl3r(void);
extern u32 __spin_table[];
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)
{
/* Default to no, overridden by 'y', 'yes', 'Y', 'Yes', or '1' */
if (env_get_yesno("mp_holdoff") == 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(u32 nr)
{
volatile ccsr_pic_t *pic = (void *)(CFG_SYS_MPC8xxx_PIC_ADDR);
out_be32(&pic->pir, 1 << nr);
/* the dummy read works around an errata on early 85xx MP PICs */
(void)in_be32(&pic->pir);
out_be32(&pic->pir, 0x0);
return 0;
}
int cpu_status(u32 nr)
{
u32 *table, id = get_my_id();
if (hold_cores_in_reset(1))
return 0;
if (nr == id) {
table = (u32 *)&__spin_table;
printf("table base @ 0x%p\n", table);
} else if (is_core_disabled(nr)) {
puts("Disabled\n");
} else {
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(" r3 - 0x%08x\n", table[BOOT_ENTRY_R3_LOWER]);
printf(" pir - 0x%08x\n", table[BOOT_ENTRY_PIR]);
}
return 0;
}
#ifdef CONFIG_FSL_CORENET
int cpu_disable(u32 nr)
{
volatile ccsr_gur_t *gur = (void *)(CFG_SYS_MPC85xx_GUTS_ADDR);
setbits_be32(&gur->coredisrl, 1 << nr);
return 0;
}
int is_core_disabled(int nr) {
ccsr_gur_t *gur = (void *)(CFG_SYS_MPC85xx_GUTS_ADDR);
u32 coredisrl = in_be32(&gur->coredisrl);
return (coredisrl & (1 << nr));
}
#else
int cpu_disable(u32 nr)
{
volatile ccsr_gur_t *gur = (void *)(CFG_SYS_MPC85xx_GUTS_ADDR);
switch (nr) {
case 0:
setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU0);
break;
case 1:
setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU1);
break;
default:
printf("Invalid cpu number for disable %d\n", nr);
return 1;
}
return 0;
}
int is_core_disabled(int nr) {
ccsr_gur_t *gur = (void *)(CFG_SYS_MPC85xx_GUTS_ADDR);
u32 devdisr = in_be32(&gur->devdisr);
switch (nr) {
case 0:
return (devdisr & MPC85xx_DEVDISR_CPU0);
case 1:
return (devdisr & MPC85xx_DEVDISR_CPU1);
default:
printf("Invalid cpu number for disable %d\n", nr);
}
return 0;
}
#endif
static u8 boot_entry_map[4] = {
0,
BOOT_ENTRY_PIR,
BOOT_ENTRY_R3_LOWER,
};
int cpu_release(u32 nr, int argc, char *const argv[])
{
u32 i, val, *table = (u32 *)&__spin_table + 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;
}
if (argc != 4) {
printf("Invalid number of arguments to release.\n\n");
return 1;
}
boot_addr = simple_strtoull(argv[0], NULL, 16);
/* handle pir, r3 */
for (i = 1; i < 3; i++) {
if (argv[i][0] != '-') {
u8 entry = boot_entry_map[i];
val = hextoul(argv[i], NULL);
table[entry] = val;
}
}
table[BOOT_ENTRY_ADDR_UPPER] = (u32)(boot_addr >> 32);
/* ensure all table updates complete before final address write */
eieio();
table[BOOT_ENTRY_ADDR_LOWER] = (u32)(boot_addr & 0xffffffff);
return 0;
}
u32 determine_mp_bootpg(unsigned int *pagesize)
{
u32 bootpg;
#ifdef CONFIG_SYS_FSL_ERRATUM_A004468
u32 svr = get_svr();
u32 granule_size, check;
struct law_entry e;
#endif
/* use last 4K of mapped memory */
bootpg = ((gd->ram_size > CFG_MAX_MEM_MAPPED) ?
CFG_MAX_MEM_MAPPED : gd->ram_size) +
CFG_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 bootpg;
}
phys_addr_t get_spin_phys_addr(void)
85xx: MP Boot Page Translation update This change has 3 goals: - Have secondary cores be released into spin loops at their 'true' address in SDRAM. Previously, secondary cores were put into spin loops in the 0xfffffxxx address range which required that boot page translation was always enabled while cores were in their spin loops. - Allow the TLB window that the primary core uses to access the secondary cores boot page to be placed at any address. Previously, a TLB window at 0xfffff000 was always used to access the seconary cores' boot page. This TLB address requirement overlapped with other peripherals on some boards (eg XPedite5370). By default, the boot page TLB will still use the 0xfffffxxx address range, but this can be overridden on a board-by-board basis by defining a custom CONFIG_BPTR_VIRT_ADDR. Note that the TLB used to map the boot page remains in use while U-Boot executes. Previously it was only temporarily used, then restored to its initial value. - Allow Boot Page Translation to be disabled on bootup. Previously, Boot Page Translation was always left enabled after secondary cores were brought out of reset. This caused the 0xfffffxxx address range to somewhat "magically" be translated to an address in SDRAM. Some boards may not want this oddity in their memory map, so defining CONFIG_MPC8xxx_DISABLE_BPTR will turn off Boot Page Translation after the secondary cores are initialized. These changes are only applicable to 85xx boards with CONFIG_MP defined. Signed-off-by: Peter Tyser <ptyser@xes-inc.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
2009-10-23 20:55:47 +00:00
{
return virt_to_phys(&__spin_table);
}
#ifdef CONFIG_FSL_CORENET
static void plat_mp_up(unsigned long bootpg, unsigned int pagesize)
{
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;
volatile ccsr_pic_t *pic;
int timeout = 10;
u32 mask = cpu_mask();
struct law_entry e;
gur = (void *)(CFG_SYS_MPC85xx_GUTS_ADDR);
ccm = (void *)(CFG_SYS_FSL_CORENET_CCM_ADDR);
rcpm = (void *)(CFG_SYS_FSL_CORENET_RCPM_ADDR);
pic = (void *)(CFG_SYS_MPC8xxx_PIC_ADDR);
whoami = in_be32(&pic->whoami);
cpu_up_mask = 1 << whoami;
out_be32(&ccm->bstrl, bootpg);
e = find_law(bootpg);
/* 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);
/* disable time base at the platform */
out_be32(&rcpm->ctbenrl, cpu_up_mask);
out_be32(&gur->brrl, mask);
/* wait for everyone */
while (timeout) {
unsigned int i, cpu, nr_cpus = cpu_numcores();
for_each_cpu(i, cpu, nr_cpus, mask) {
if (table[cpu * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER])
cpu_up_mask |= (1 << cpu);
}
if ((cpu_up_mask & mask) == mask)
break;
udelay(100);
timeout--;
}
if (timeout == 0)
printf("CPU up timeout. CPU up mask is %x should be %x\n",
cpu_up_mask, mask);
/* enable time base at the platform */
out_be32(&rcpm->ctbenrl, 0);
/* readback to sync write */
in_be32(&rcpm->ctbenrl);
mtspr(SPRN_TBWU, 0);
mtspr(SPRN_TBWL, 0);
out_be32(&rcpm->ctbenrl, mask);
85xx: MP Boot Page Translation update This change has 3 goals: - Have secondary cores be released into spin loops at their 'true' address in SDRAM. Previously, secondary cores were put into spin loops in the 0xfffffxxx address range which required that boot page translation was always enabled while cores were in their spin loops. - Allow the TLB window that the primary core uses to access the secondary cores boot page to be placed at any address. Previously, a TLB window at 0xfffff000 was always used to access the seconary cores' boot page. This TLB address requirement overlapped with other peripherals on some boards (eg XPedite5370). By default, the boot page TLB will still use the 0xfffffxxx address range, but this can be overridden on a board-by-board basis by defining a custom CONFIG_BPTR_VIRT_ADDR. Note that the TLB used to map the boot page remains in use while U-Boot executes. Previously it was only temporarily used, then restored to its initial value. - Allow Boot Page Translation to be disabled on bootup. Previously, Boot Page Translation was always left enabled after secondary cores were brought out of reset. This caused the 0xfffffxxx address range to somewhat "magically" be translated to an address in SDRAM. Some boards may not want this oddity in their memory map, so defining CONFIG_MPC8xxx_DISABLE_BPTR will turn off Boot Page Translation after the secondary cores are initialized. These changes are only applicable to 85xx boards with CONFIG_MP defined. Signed-off-by: Peter Tyser <ptyser@xes-inc.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
2009-10-23 20:55:47 +00:00
#ifdef CONFIG_MPC8xxx_DISABLE_BPTR
/*
* Disabling Boot Page Translation allows the memory region 0xfffff000
* to 0xffffffff to be used normally. Leaving Boot Page Translation
* enabled remaps 0xfffff000 to SDRAM which makes that memory region
* unusable for normal operation but it does allow OSes to easily
* reset a processor core to put it back into U-Boot's spinloop.
*/
clrbits_be32(&ccm->bstrar, LAW_EN);
85xx: MP Boot Page Translation update This change has 3 goals: - Have secondary cores be released into spin loops at their 'true' address in SDRAM. Previously, secondary cores were put into spin loops in the 0xfffffxxx address range which required that boot page translation was always enabled while cores were in their spin loops. - Allow the TLB window that the primary core uses to access the secondary cores boot page to be placed at any address. Previously, a TLB window at 0xfffff000 was always used to access the seconary cores' boot page. This TLB address requirement overlapped with other peripherals on some boards (eg XPedite5370). By default, the boot page TLB will still use the 0xfffffxxx address range, but this can be overridden on a board-by-board basis by defining a custom CONFIG_BPTR_VIRT_ADDR. Note that the TLB used to map the boot page remains in use while U-Boot executes. Previously it was only temporarily used, then restored to its initial value. - Allow Boot Page Translation to be disabled on bootup. Previously, Boot Page Translation was always left enabled after secondary cores were brought out of reset. This caused the 0xfffffxxx address range to somewhat "magically" be translated to an address in SDRAM. Some boards may not want this oddity in their memory map, so defining CONFIG_MPC8xxx_DISABLE_BPTR will turn off Boot Page Translation after the secondary cores are initialized. These changes are only applicable to 85xx boards with CONFIG_MP defined. Signed-off-by: Peter Tyser <ptyser@xes-inc.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
2009-10-23 20:55:47 +00:00
#endif
}
#else
static void plat_mp_up(unsigned long bootpg, unsigned int pagesize)
{
u32 up, cpu_up_mask, whoami;
u32 *table = (u32 *)&__spin_table;
volatile u32 bpcr;
volatile ccsr_local_ecm_t *ecm = (void *)(CFG_SYS_MPC85xx_ECM_ADDR);
volatile ccsr_gur_t *gur = (void *)(CFG_SYS_MPC85xx_GUTS_ADDR);
volatile ccsr_pic_t *pic = (void *)(CFG_SYS_MPC8xxx_PIC_ADDR);
u32 devdisr;
int timeout = 10;
whoami = in_be32(&pic->whoami);
out_be32(&ecm->bptr, 0x80000000 | (bootpg >> 12));
/* disable time base at the platform */
devdisr = in_be32(&gur->devdisr);
if (whoami)
devdisr |= MPC85xx_DEVDISR_TB0;
else
devdisr |= MPC85xx_DEVDISR_TB1;
out_be32(&gur->devdisr, devdisr);
/* release the hounds */
up = ((1 << cpu_numcores()) - 1);
bpcr = in_be32(&ecm->eebpcr);
bpcr |= (up << 24);
out_be32(&ecm->eebpcr, bpcr);
asm("sync; isync; msync");
cpu_up_mask = 1 << whoami;
/* wait for everyone */
while (timeout) {
int i;
for (i = 0; i < cpu_numcores(); i++) {
if (table[i * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER])
cpu_up_mask |= (1 << i);
};
if ((cpu_up_mask & up) == up)
break;
udelay(100);
timeout--;
}
if (timeout == 0)
printf("CPU up timeout. CPU up mask is %x should be %x\n",
cpu_up_mask, up);
/* enable time base at the platform */
if (whoami)
devdisr |= MPC85xx_DEVDISR_TB1;
else
devdisr |= MPC85xx_DEVDISR_TB0;
out_be32(&gur->devdisr, devdisr);
/* readback to sync write */
in_be32(&gur->devdisr);
mtspr(SPRN_TBWU, 0);
mtspr(SPRN_TBWL, 0);
devdisr &= ~(MPC85xx_DEVDISR_TB0 | MPC85xx_DEVDISR_TB1);
out_be32(&gur->devdisr, devdisr);
85xx: MP Boot Page Translation update This change has 3 goals: - Have secondary cores be released into spin loops at their 'true' address in SDRAM. Previously, secondary cores were put into spin loops in the 0xfffffxxx address range which required that boot page translation was always enabled while cores were in their spin loops. - Allow the TLB window that the primary core uses to access the secondary cores boot page to be placed at any address. Previously, a TLB window at 0xfffff000 was always used to access the seconary cores' boot page. This TLB address requirement overlapped with other peripherals on some boards (eg XPedite5370). By default, the boot page TLB will still use the 0xfffffxxx address range, but this can be overridden on a board-by-board basis by defining a custom CONFIG_BPTR_VIRT_ADDR. Note that the TLB used to map the boot page remains in use while U-Boot executes. Previously it was only temporarily used, then restored to its initial value. - Allow Boot Page Translation to be disabled on bootup. Previously, Boot Page Translation was always left enabled after secondary cores were brought out of reset. This caused the 0xfffffxxx address range to somewhat "magically" be translated to an address in SDRAM. Some boards may not want this oddity in their memory map, so defining CONFIG_MPC8xxx_DISABLE_BPTR will turn off Boot Page Translation after the secondary cores are initialized. These changes are only applicable to 85xx boards with CONFIG_MP defined. Signed-off-by: Peter Tyser <ptyser@xes-inc.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
2009-10-23 20:55:47 +00:00
#ifdef CONFIG_MPC8xxx_DISABLE_BPTR
/*
* Disabling Boot Page Translation allows the memory region 0xfffff000
* to 0xffffffff to be used normally. Leaving Boot Page Translation
* enabled remaps 0xfffff000 to SDRAM which makes that memory region
* unusable for normal operation but it does allow OSes to easily
* reset a processor core to put it back into U-Boot's spinloop.
*/
clrbits_be32(&ecm->bptr, 0x80000000);
#endif
}
#endif
void cpu_mp_lmb_reserve(struct lmb *lmb)
{
u32 bootpg = determine_mp_bootpg(NULL);
lmb_reserve(lmb, bootpg, 4096);
}
void setup_mp(void)
{
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 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);
85xx: MP Boot Page Translation update This change has 3 goals: - Have secondary cores be released into spin loops at their 'true' address in SDRAM. Previously, secondary cores were put into spin loops in the 0xfffffxxx address range which required that boot page translation was always enabled while cores were in their spin loops. - Allow the TLB window that the primary core uses to access the secondary cores boot page to be placed at any address. Previously, a TLB window at 0xfffff000 was always used to access the seconary cores' boot page. This TLB address requirement overlapped with other peripherals on some boards (eg XPedite5370). By default, the boot page TLB will still use the 0xfffffxxx address range, but this can be overridden on a board-by-board basis by defining a custom CONFIG_BPTR_VIRT_ADDR. Note that the TLB used to map the boot page remains in use while U-Boot executes. Previously it was only temporarily used, then restored to its initial value. - Allow Boot Page Translation to be disabled on bootup. Previously, Boot Page Translation was always left enabled after secondary cores were brought out of reset. This caused the 0xfffffxxx address range to somewhat "magically" be translated to an address in SDRAM. Some boards may not want this oddity in their memory map, so defining CONFIG_MPC8xxx_DISABLE_BPTR will turn off Boot Page Translation after the secondary cores are initialized. These changes are only applicable to 85xx boards with CONFIG_MP defined. Signed-off-by: Peter Tyser <ptyser@xes-inc.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
2009-10-23 20:55:47 +00:00
/* look for the tlb covering the reset page, there better be one */
i = find_tlb_idx((void *)BPTR_VIRT_ADDR, 1);
/* we found a match */
if (i != -1) {
/* map reset page to bootpg so we can copy code there */
disable_tlb(i);
set_tlb(1, BPTR_VIRT_ADDR, bootpg, /* tlb, epn, rpn */
MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, /* perms, wimge */
0, i, BOOKE_PAGESZ_4K, 1); /* ts, esel, tsize, iprot */
memcpy((void *)BPTR_VIRT_ADDR, (void *)fixup, 4096);
85xx: MP Boot Page Translation update This change has 3 goals: - Have secondary cores be released into spin loops at their 'true' address in SDRAM. Previously, secondary cores were put into spin loops in the 0xfffffxxx address range which required that boot page translation was always enabled while cores were in their spin loops. - Allow the TLB window that the primary core uses to access the secondary cores boot page to be placed at any address. Previously, a TLB window at 0xfffff000 was always used to access the seconary cores' boot page. This TLB address requirement overlapped with other peripherals on some boards (eg XPedite5370). By default, the boot page TLB will still use the 0xfffffxxx address range, but this can be overridden on a board-by-board basis by defining a custom CONFIG_BPTR_VIRT_ADDR. Note that the TLB used to map the boot page remains in use while U-Boot executes. Previously it was only temporarily used, then restored to its initial value. - Allow Boot Page Translation to be disabled on bootup. Previously, Boot Page Translation was always left enabled after secondary cores were brought out of reset. This caused the 0xfffffxxx address range to somewhat "magically" be translated to an address in SDRAM. Some boards may not want this oddity in their memory map, so defining CONFIG_MPC8xxx_DISABLE_BPTR will turn off Boot Page Translation after the secondary cores are initialized. These changes are only applicable to 85xx boards with CONFIG_MP defined. Signed-off-by: Peter Tyser <ptyser@xes-inc.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
2009-10-23 20:55:47 +00:00
plat_mp_up(bootpg_map, pagesize);
} else {
puts("WARNING: No reset page TLB. "
"Skipping secondary core setup\n");
}
}