1*a47a12beSStefan Roese /* 2*a47a12beSStefan Roese * Copyright 2008-2010 Freescale Semiconductor, Inc. 3*a47a12beSStefan Roese * 4*a47a12beSStefan Roese * See file CREDITS for list of people who contributed to this 5*a47a12beSStefan Roese * project. 6*a47a12beSStefan Roese * 7*a47a12beSStefan Roese * This program is free software; you can redistribute it and/or 8*a47a12beSStefan Roese * modify it under the terms of the GNU General Public License as 9*a47a12beSStefan Roese * published by the Free Software Foundation; either version 2 of 10*a47a12beSStefan Roese * the License, or (at your option) any later version. 11*a47a12beSStefan Roese * 12*a47a12beSStefan Roese * This program is distributed in the hope that it will be useful, 13*a47a12beSStefan Roese * but WITHOUT ANY WARRANTY; without even the implied warranty of 14*a47a12beSStefan Roese * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*a47a12beSStefan Roese * GNU General Public License for more details. 16*a47a12beSStefan Roese * 17*a47a12beSStefan Roese * You should have received a copy of the GNU General Public License 18*a47a12beSStefan Roese * along with this program; if not, write to the Free Software 19*a47a12beSStefan Roese * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 20*a47a12beSStefan Roese * MA 02111-1307 USA 21*a47a12beSStefan Roese */ 22*a47a12beSStefan Roese 23*a47a12beSStefan Roese #include <common.h> 24*a47a12beSStefan Roese #include <asm/processor.h> 25*a47a12beSStefan Roese #include <ioports.h> 26*a47a12beSStefan Roese #include <lmb.h> 27*a47a12beSStefan Roese #include <asm/io.h> 28*a47a12beSStefan Roese #include <asm/mmu.h> 29*a47a12beSStefan Roese #include <asm/fsl_law.h> 30*a47a12beSStefan Roese #include "mp.h" 31*a47a12beSStefan Roese 32*a47a12beSStefan Roese DECLARE_GLOBAL_DATA_PTR; 33*a47a12beSStefan Roese 34*a47a12beSStefan Roese u32 get_my_id() 35*a47a12beSStefan Roese { 36*a47a12beSStefan Roese return mfspr(SPRN_PIR); 37*a47a12beSStefan Roese } 38*a47a12beSStefan Roese 39*a47a12beSStefan Roese int cpu_reset(int nr) 40*a47a12beSStefan Roese { 41*a47a12beSStefan Roese volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC85xx_PIC_ADDR); 42*a47a12beSStefan Roese out_be32(&pic->pir, 1 << nr); 43*a47a12beSStefan Roese /* the dummy read works around an errata on early 85xx MP PICs */ 44*a47a12beSStefan Roese (void)in_be32(&pic->pir); 45*a47a12beSStefan Roese out_be32(&pic->pir, 0x0); 46*a47a12beSStefan Roese 47*a47a12beSStefan Roese return 0; 48*a47a12beSStefan Roese } 49*a47a12beSStefan Roese 50*a47a12beSStefan Roese int cpu_status(int nr) 51*a47a12beSStefan Roese { 52*a47a12beSStefan Roese u32 *table, id = get_my_id(); 53*a47a12beSStefan Roese 54*a47a12beSStefan Roese if (nr == id) { 55*a47a12beSStefan Roese table = (u32 *)get_spin_virt_addr(); 56*a47a12beSStefan Roese printf("table base @ 0x%p\n", table); 57*a47a12beSStefan Roese } else { 58*a47a12beSStefan Roese table = (u32 *)get_spin_virt_addr() + nr * NUM_BOOT_ENTRY; 59*a47a12beSStefan Roese printf("Running on cpu %d\n", id); 60*a47a12beSStefan Roese printf("\n"); 61*a47a12beSStefan Roese printf("table @ 0x%p\n", table); 62*a47a12beSStefan Roese printf(" addr - 0x%08x\n", table[BOOT_ENTRY_ADDR_LOWER]); 63*a47a12beSStefan Roese printf(" pir - 0x%08x\n", table[BOOT_ENTRY_PIR]); 64*a47a12beSStefan Roese printf(" r3 - 0x%08x\n", table[BOOT_ENTRY_R3_LOWER]); 65*a47a12beSStefan Roese printf(" r6 - 0x%08x\n", table[BOOT_ENTRY_R6_LOWER]); 66*a47a12beSStefan Roese } 67*a47a12beSStefan Roese 68*a47a12beSStefan Roese return 0; 69*a47a12beSStefan Roese } 70*a47a12beSStefan Roese 71*a47a12beSStefan Roese #ifdef CONFIG_FSL_CORENET 72*a47a12beSStefan Roese int cpu_disable(int nr) 73*a47a12beSStefan Roese { 74*a47a12beSStefan Roese volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 75*a47a12beSStefan Roese 76*a47a12beSStefan Roese setbits_be32(&gur->coredisrl, 1 << nr); 77*a47a12beSStefan Roese 78*a47a12beSStefan Roese return 0; 79*a47a12beSStefan Roese } 80*a47a12beSStefan Roese #else 81*a47a12beSStefan Roese int cpu_disable(int nr) 82*a47a12beSStefan Roese { 83*a47a12beSStefan Roese volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 84*a47a12beSStefan Roese 85*a47a12beSStefan Roese switch (nr) { 86*a47a12beSStefan Roese case 0: 87*a47a12beSStefan Roese setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU0); 88*a47a12beSStefan Roese break; 89*a47a12beSStefan Roese case 1: 90*a47a12beSStefan Roese setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU1); 91*a47a12beSStefan Roese break; 92*a47a12beSStefan Roese default: 93*a47a12beSStefan Roese printf("Invalid cpu number for disable %d\n", nr); 94*a47a12beSStefan Roese return 1; 95*a47a12beSStefan Roese } 96*a47a12beSStefan Roese 97*a47a12beSStefan Roese return 0; 98*a47a12beSStefan Roese } 99*a47a12beSStefan Roese #endif 100*a47a12beSStefan Roese 101*a47a12beSStefan Roese static u8 boot_entry_map[4] = { 102*a47a12beSStefan Roese 0, 103*a47a12beSStefan Roese BOOT_ENTRY_PIR, 104*a47a12beSStefan Roese BOOT_ENTRY_R3_LOWER, 105*a47a12beSStefan Roese BOOT_ENTRY_R6_LOWER, 106*a47a12beSStefan Roese }; 107*a47a12beSStefan Roese 108*a47a12beSStefan Roese int cpu_release(int nr, int argc, char *argv[]) 109*a47a12beSStefan Roese { 110*a47a12beSStefan Roese u32 i, val, *table = (u32 *)get_spin_virt_addr() + nr * NUM_BOOT_ENTRY; 111*a47a12beSStefan Roese u64 boot_addr; 112*a47a12beSStefan Roese 113*a47a12beSStefan Roese if (nr == get_my_id()) { 114*a47a12beSStefan Roese printf("Invalid to release the boot core.\n\n"); 115*a47a12beSStefan Roese return 1; 116*a47a12beSStefan Roese } 117*a47a12beSStefan Roese 118*a47a12beSStefan Roese if (argc != 4) { 119*a47a12beSStefan Roese printf("Invalid number of arguments to release.\n\n"); 120*a47a12beSStefan Roese return 1; 121*a47a12beSStefan Roese } 122*a47a12beSStefan Roese 123*a47a12beSStefan Roese boot_addr = simple_strtoull(argv[0], NULL, 16); 124*a47a12beSStefan Roese 125*a47a12beSStefan Roese /* handle pir, r3, r6 */ 126*a47a12beSStefan Roese for (i = 1; i < 4; i++) { 127*a47a12beSStefan Roese if (argv[i][0] != '-') { 128*a47a12beSStefan Roese u8 entry = boot_entry_map[i]; 129*a47a12beSStefan Roese val = simple_strtoul(argv[i], NULL, 16); 130*a47a12beSStefan Roese table[entry] = val; 131*a47a12beSStefan Roese } 132*a47a12beSStefan Roese } 133*a47a12beSStefan Roese 134*a47a12beSStefan Roese table[BOOT_ENTRY_ADDR_UPPER] = (u32)(boot_addr >> 32); 135*a47a12beSStefan Roese 136*a47a12beSStefan Roese /* ensure all table updates complete before final address write */ 137*a47a12beSStefan Roese eieio(); 138*a47a12beSStefan Roese 139*a47a12beSStefan Roese table[BOOT_ENTRY_ADDR_LOWER] = (u32)(boot_addr & 0xffffffff); 140*a47a12beSStefan Roese 141*a47a12beSStefan Roese return 0; 142*a47a12beSStefan Roese } 143*a47a12beSStefan Roese 144*a47a12beSStefan Roese u32 determine_mp_bootpg(void) 145*a47a12beSStefan Roese { 146*a47a12beSStefan Roese /* if we have 4G or more of memory, put the boot page at 4Gb-4k */ 147*a47a12beSStefan Roese if ((u64)gd->ram_size > 0xfffff000) 148*a47a12beSStefan Roese return (0xfffff000); 149*a47a12beSStefan Roese 150*a47a12beSStefan Roese return (gd->ram_size - 4096); 151*a47a12beSStefan Roese } 152*a47a12beSStefan Roese 153*a47a12beSStefan Roese ulong get_spin_phys_addr(void) 154*a47a12beSStefan Roese { 155*a47a12beSStefan Roese extern ulong __secondary_start_page; 156*a47a12beSStefan Roese extern ulong __spin_table; 157*a47a12beSStefan Roese 158*a47a12beSStefan Roese return (determine_mp_bootpg() + 159*a47a12beSStefan Roese (ulong)&__spin_table - (ulong)&__secondary_start_page); 160*a47a12beSStefan Roese } 161*a47a12beSStefan Roese 162*a47a12beSStefan Roese ulong get_spin_virt_addr(void) 163*a47a12beSStefan Roese { 164*a47a12beSStefan Roese extern ulong __secondary_start_page; 165*a47a12beSStefan Roese extern ulong __spin_table; 166*a47a12beSStefan Roese 167*a47a12beSStefan Roese return (CONFIG_BPTR_VIRT_ADDR + 168*a47a12beSStefan Roese (ulong)&__spin_table - (ulong)&__secondary_start_page); 169*a47a12beSStefan Roese } 170*a47a12beSStefan Roese 171*a47a12beSStefan Roese #ifdef CONFIG_FSL_CORENET 172*a47a12beSStefan Roese static void plat_mp_up(unsigned long bootpg) 173*a47a12beSStefan Roese { 174*a47a12beSStefan Roese u32 up, cpu_up_mask, whoami; 175*a47a12beSStefan Roese u32 *table = (u32 *)get_spin_virt_addr(); 176*a47a12beSStefan Roese volatile ccsr_gur_t *gur; 177*a47a12beSStefan Roese volatile ccsr_local_t *ccm; 178*a47a12beSStefan Roese volatile ccsr_rcpm_t *rcpm; 179*a47a12beSStefan Roese volatile ccsr_pic_t *pic; 180*a47a12beSStefan Roese int timeout = 10; 181*a47a12beSStefan Roese u32 nr_cpus; 182*a47a12beSStefan Roese struct law_entry e; 183*a47a12beSStefan Roese 184*a47a12beSStefan Roese gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 185*a47a12beSStefan Roese ccm = (void *)(CONFIG_SYS_FSL_CORENET_CCM_ADDR); 186*a47a12beSStefan Roese rcpm = (void *)(CONFIG_SYS_FSL_CORENET_RCPM_ADDR); 187*a47a12beSStefan Roese pic = (void *)(CONFIG_SYS_MPC85xx_PIC_ADDR); 188*a47a12beSStefan Roese 189*a47a12beSStefan Roese nr_cpus = ((in_be32(&pic->frr) >> 8) & 0xff) + 1; 190*a47a12beSStefan Roese 191*a47a12beSStefan Roese whoami = in_be32(&pic->whoami); 192*a47a12beSStefan Roese cpu_up_mask = 1 << whoami; 193*a47a12beSStefan Roese out_be32(&ccm->bstrl, bootpg); 194*a47a12beSStefan Roese 195*a47a12beSStefan Roese e = find_law(bootpg); 196*a47a12beSStefan Roese out_be32(&ccm->bstrar, LAW_EN | e.trgt_id << 20 | LAW_SIZE_4K); 197*a47a12beSStefan Roese 198*a47a12beSStefan Roese /* readback to sync write */ 199*a47a12beSStefan Roese in_be32(&ccm->bstrar); 200*a47a12beSStefan Roese 201*a47a12beSStefan Roese /* disable time base at the platform */ 202*a47a12beSStefan Roese out_be32(&rcpm->ctbenrl, cpu_up_mask); 203*a47a12beSStefan Roese 204*a47a12beSStefan Roese /* release the hounds */ 205*a47a12beSStefan Roese up = ((1 << nr_cpus) - 1); 206*a47a12beSStefan Roese out_be32(&gur->brrl, up); 207*a47a12beSStefan Roese 208*a47a12beSStefan Roese /* wait for everyone */ 209*a47a12beSStefan Roese while (timeout) { 210*a47a12beSStefan Roese int i; 211*a47a12beSStefan Roese for (i = 0; i < nr_cpus; i++) { 212*a47a12beSStefan Roese if (table[i * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER]) 213*a47a12beSStefan Roese cpu_up_mask |= (1 << i); 214*a47a12beSStefan Roese }; 215*a47a12beSStefan Roese 216*a47a12beSStefan Roese if ((cpu_up_mask & up) == up) 217*a47a12beSStefan Roese break; 218*a47a12beSStefan Roese 219*a47a12beSStefan Roese udelay(100); 220*a47a12beSStefan Roese timeout--; 221*a47a12beSStefan Roese } 222*a47a12beSStefan Roese 223*a47a12beSStefan Roese if (timeout == 0) 224*a47a12beSStefan Roese printf("CPU up timeout. CPU up mask is %x should be %x\n", 225*a47a12beSStefan Roese cpu_up_mask, up); 226*a47a12beSStefan Roese 227*a47a12beSStefan Roese /* enable time base at the platform */ 228*a47a12beSStefan Roese out_be32(&rcpm->ctbenrl, 0); 229*a47a12beSStefan Roese mtspr(SPRN_TBWU, 0); 230*a47a12beSStefan Roese mtspr(SPRN_TBWL, 0); 231*a47a12beSStefan Roese out_be32(&rcpm->ctbenrl, (1 << nr_cpus) - 1); 232*a47a12beSStefan Roese 233*a47a12beSStefan Roese #ifdef CONFIG_MPC8xxx_DISABLE_BPTR 234*a47a12beSStefan Roese /* 235*a47a12beSStefan Roese * Disabling Boot Page Translation allows the memory region 0xfffff000 236*a47a12beSStefan Roese * to 0xffffffff to be used normally. Leaving Boot Page Translation 237*a47a12beSStefan Roese * enabled remaps 0xfffff000 to SDRAM which makes that memory region 238*a47a12beSStefan Roese * unusable for normal operation but it does allow OSes to easily 239*a47a12beSStefan Roese * reset a processor core to put it back into U-Boot's spinloop. 240*a47a12beSStefan Roese */ 241*a47a12beSStefan Roese clrbits_be32(&ecm->bptr, 0x80000000); 242*a47a12beSStefan Roese #endif 243*a47a12beSStefan Roese } 244*a47a12beSStefan Roese #else 245*a47a12beSStefan Roese static void plat_mp_up(unsigned long bootpg) 246*a47a12beSStefan Roese { 247*a47a12beSStefan Roese u32 up, cpu_up_mask, whoami; 248*a47a12beSStefan Roese u32 *table = (u32 *)get_spin_virt_addr(); 249*a47a12beSStefan Roese volatile u32 bpcr; 250*a47a12beSStefan Roese volatile ccsr_local_ecm_t *ecm = (void *)(CONFIG_SYS_MPC85xx_ECM_ADDR); 251*a47a12beSStefan Roese volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 252*a47a12beSStefan Roese volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC85xx_PIC_ADDR); 253*a47a12beSStefan Roese u32 devdisr; 254*a47a12beSStefan Roese int timeout = 10; 255*a47a12beSStefan Roese 256*a47a12beSStefan Roese whoami = in_be32(&pic->whoami); 257*a47a12beSStefan Roese out_be32(&ecm->bptr, 0x80000000 | (bootpg >> 12)); 258*a47a12beSStefan Roese 259*a47a12beSStefan Roese /* disable time base at the platform */ 260*a47a12beSStefan Roese devdisr = in_be32(&gur->devdisr); 261*a47a12beSStefan Roese if (whoami) 262*a47a12beSStefan Roese devdisr |= MPC85xx_DEVDISR_TB0; 263*a47a12beSStefan Roese else 264*a47a12beSStefan Roese devdisr |= MPC85xx_DEVDISR_TB1; 265*a47a12beSStefan Roese out_be32(&gur->devdisr, devdisr); 266*a47a12beSStefan Roese 267*a47a12beSStefan Roese /* release the hounds */ 268*a47a12beSStefan Roese up = ((1 << cpu_numcores()) - 1); 269*a47a12beSStefan Roese bpcr = in_be32(&ecm->eebpcr); 270*a47a12beSStefan Roese bpcr |= (up << 24); 271*a47a12beSStefan Roese out_be32(&ecm->eebpcr, bpcr); 272*a47a12beSStefan Roese asm("sync; isync; msync"); 273*a47a12beSStefan Roese 274*a47a12beSStefan Roese cpu_up_mask = 1 << whoami; 275*a47a12beSStefan Roese /* wait for everyone */ 276*a47a12beSStefan Roese while (timeout) { 277*a47a12beSStefan Roese int i; 278*a47a12beSStefan Roese for (i = 0; i < cpu_numcores(); i++) { 279*a47a12beSStefan Roese if (table[i * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER]) 280*a47a12beSStefan Roese cpu_up_mask |= (1 << i); 281*a47a12beSStefan Roese }; 282*a47a12beSStefan Roese 283*a47a12beSStefan Roese if ((cpu_up_mask & up) == up) 284*a47a12beSStefan Roese break; 285*a47a12beSStefan Roese 286*a47a12beSStefan Roese udelay(100); 287*a47a12beSStefan Roese timeout--; 288*a47a12beSStefan Roese } 289*a47a12beSStefan Roese 290*a47a12beSStefan Roese if (timeout == 0) 291*a47a12beSStefan Roese printf("CPU up timeout. CPU up mask is %x should be %x\n", 292*a47a12beSStefan Roese cpu_up_mask, up); 293*a47a12beSStefan Roese 294*a47a12beSStefan Roese /* enable time base at the platform */ 295*a47a12beSStefan Roese if (whoami) 296*a47a12beSStefan Roese devdisr |= MPC85xx_DEVDISR_TB1; 297*a47a12beSStefan Roese else 298*a47a12beSStefan Roese devdisr |= MPC85xx_DEVDISR_TB0; 299*a47a12beSStefan Roese out_be32(&gur->devdisr, devdisr); 300*a47a12beSStefan Roese mtspr(SPRN_TBWU, 0); 301*a47a12beSStefan Roese mtspr(SPRN_TBWL, 0); 302*a47a12beSStefan Roese 303*a47a12beSStefan Roese devdisr &= ~(MPC85xx_DEVDISR_TB0 | MPC85xx_DEVDISR_TB1); 304*a47a12beSStefan Roese out_be32(&gur->devdisr, devdisr); 305*a47a12beSStefan Roese 306*a47a12beSStefan Roese #ifdef CONFIG_MPC8xxx_DISABLE_BPTR 307*a47a12beSStefan Roese /* 308*a47a12beSStefan Roese * Disabling Boot Page Translation allows the memory region 0xfffff000 309*a47a12beSStefan Roese * to 0xffffffff to be used normally. Leaving Boot Page Translation 310*a47a12beSStefan Roese * enabled remaps 0xfffff000 to SDRAM which makes that memory region 311*a47a12beSStefan Roese * unusable for normal operation but it does allow OSes to easily 312*a47a12beSStefan Roese * reset a processor core to put it back into U-Boot's spinloop. 313*a47a12beSStefan Roese */ 314*a47a12beSStefan Roese clrbits_be32(&ecm->bptr, 0x80000000); 315*a47a12beSStefan Roese #endif 316*a47a12beSStefan Roese } 317*a47a12beSStefan Roese #endif 318*a47a12beSStefan Roese 319*a47a12beSStefan Roese void cpu_mp_lmb_reserve(struct lmb *lmb) 320*a47a12beSStefan Roese { 321*a47a12beSStefan Roese u32 bootpg = determine_mp_bootpg(); 322*a47a12beSStefan Roese 323*a47a12beSStefan Roese lmb_reserve(lmb, bootpg, 4096); 324*a47a12beSStefan Roese } 325*a47a12beSStefan Roese 326*a47a12beSStefan Roese void setup_mp(void) 327*a47a12beSStefan Roese { 328*a47a12beSStefan Roese extern ulong __secondary_start_page; 329*a47a12beSStefan Roese extern ulong __bootpg_addr; 330*a47a12beSStefan Roese ulong fixup = (ulong)&__secondary_start_page; 331*a47a12beSStefan Roese u32 bootpg = determine_mp_bootpg(); 332*a47a12beSStefan Roese 333*a47a12beSStefan Roese /* Store the bootpg's SDRAM address for use by secondary CPU cores */ 334*a47a12beSStefan Roese __bootpg_addr = bootpg; 335*a47a12beSStefan Roese 336*a47a12beSStefan Roese /* look for the tlb covering the reset page, there better be one */ 337*a47a12beSStefan Roese int i = find_tlb_idx((void *)CONFIG_BPTR_VIRT_ADDR, 1); 338*a47a12beSStefan Roese 339*a47a12beSStefan Roese /* we found a match */ 340*a47a12beSStefan Roese if (i != -1) { 341*a47a12beSStefan Roese /* map reset page to bootpg so we can copy code there */ 342*a47a12beSStefan Roese disable_tlb(i); 343*a47a12beSStefan Roese 344*a47a12beSStefan Roese set_tlb(1, CONFIG_BPTR_VIRT_ADDR, bootpg, /* tlb, epn, rpn */ 345*a47a12beSStefan Roese MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, /* perms, wimge */ 346*a47a12beSStefan Roese 0, i, BOOKE_PAGESZ_4K, 1); /* ts, esel, tsize, iprot */ 347*a47a12beSStefan Roese 348*a47a12beSStefan Roese memcpy((void *)CONFIG_BPTR_VIRT_ADDR, (void *)fixup, 4096); 349*a47a12beSStefan Roese 350*a47a12beSStefan Roese plat_mp_up(bootpg); 351*a47a12beSStefan Roese } else { 352*a47a12beSStefan Roese puts("WARNING: No reset page TLB. " 353*a47a12beSStefan Roese "Skipping secondary core setup\n"); 354*a47a12beSStefan Roese } 355*a47a12beSStefan Roese } 356