1*a47a12beSStefan Roese /* 2*a47a12beSStefan Roese * Copyright (C) 2004-2007 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 /* 24*a47a12beSStefan Roese * CPU specific code for the MPC83xx family. 25*a47a12beSStefan Roese * 26*a47a12beSStefan Roese * Derived from the MPC8260 and MPC85xx. 27*a47a12beSStefan Roese */ 28*a47a12beSStefan Roese 29*a47a12beSStefan Roese #include <common.h> 30*a47a12beSStefan Roese #include <watchdog.h> 31*a47a12beSStefan Roese #include <command.h> 32*a47a12beSStefan Roese #include <mpc83xx.h> 33*a47a12beSStefan Roese #include <asm/processor.h> 34*a47a12beSStefan Roese #include <libfdt.h> 35*a47a12beSStefan Roese #include <tsec.h> 36*a47a12beSStefan Roese #include <netdev.h> 37*a47a12beSStefan Roese #include <fsl_esdhc.h> 38*a47a12beSStefan Roese #ifdef CONFIG_BOOTCOUNT_LIMIT 39*a47a12beSStefan Roese #include <asm/immap_qe.h> 40*a47a12beSStefan Roese #include <asm/io.h> 41*a47a12beSStefan Roese #endif 42*a47a12beSStefan Roese 43*a47a12beSStefan Roese DECLARE_GLOBAL_DATA_PTR; 44*a47a12beSStefan Roese 45*a47a12beSStefan Roese int checkcpu(void) 46*a47a12beSStefan Roese { 47*a47a12beSStefan Roese volatile immap_t *immr; 48*a47a12beSStefan Roese ulong clock = gd->cpu_clk; 49*a47a12beSStefan Roese u32 pvr = get_pvr(); 50*a47a12beSStefan Roese u32 spridr; 51*a47a12beSStefan Roese char buf[32]; 52*a47a12beSStefan Roese int i; 53*a47a12beSStefan Roese 54*a47a12beSStefan Roese const struct cpu_type { 55*a47a12beSStefan Roese char name[15]; 56*a47a12beSStefan Roese u32 partid; 57*a47a12beSStefan Roese } cpu_type_list [] = { 58*a47a12beSStefan Roese CPU_TYPE_ENTRY(8311), 59*a47a12beSStefan Roese CPU_TYPE_ENTRY(8313), 60*a47a12beSStefan Roese CPU_TYPE_ENTRY(8314), 61*a47a12beSStefan Roese CPU_TYPE_ENTRY(8315), 62*a47a12beSStefan Roese CPU_TYPE_ENTRY(8321), 63*a47a12beSStefan Roese CPU_TYPE_ENTRY(8323), 64*a47a12beSStefan Roese CPU_TYPE_ENTRY(8343), 65*a47a12beSStefan Roese CPU_TYPE_ENTRY(8347_TBGA_), 66*a47a12beSStefan Roese CPU_TYPE_ENTRY(8347_PBGA_), 67*a47a12beSStefan Roese CPU_TYPE_ENTRY(8349), 68*a47a12beSStefan Roese CPU_TYPE_ENTRY(8358_TBGA_), 69*a47a12beSStefan Roese CPU_TYPE_ENTRY(8358_PBGA_), 70*a47a12beSStefan Roese CPU_TYPE_ENTRY(8360), 71*a47a12beSStefan Roese CPU_TYPE_ENTRY(8377), 72*a47a12beSStefan Roese CPU_TYPE_ENTRY(8378), 73*a47a12beSStefan Roese CPU_TYPE_ENTRY(8379), 74*a47a12beSStefan Roese }; 75*a47a12beSStefan Roese 76*a47a12beSStefan Roese immr = (immap_t *)CONFIG_SYS_IMMR; 77*a47a12beSStefan Roese 78*a47a12beSStefan Roese puts("CPU: "); 79*a47a12beSStefan Roese 80*a47a12beSStefan Roese switch (pvr & 0xffff0000) { 81*a47a12beSStefan Roese case PVR_E300C1: 82*a47a12beSStefan Roese printf("e300c1, "); 83*a47a12beSStefan Roese break; 84*a47a12beSStefan Roese 85*a47a12beSStefan Roese case PVR_E300C2: 86*a47a12beSStefan Roese printf("e300c2, "); 87*a47a12beSStefan Roese break; 88*a47a12beSStefan Roese 89*a47a12beSStefan Roese case PVR_E300C3: 90*a47a12beSStefan Roese printf("e300c3, "); 91*a47a12beSStefan Roese break; 92*a47a12beSStefan Roese 93*a47a12beSStefan Roese case PVR_E300C4: 94*a47a12beSStefan Roese printf("e300c4, "); 95*a47a12beSStefan Roese break; 96*a47a12beSStefan Roese 97*a47a12beSStefan Roese default: 98*a47a12beSStefan Roese printf("Unknown core, "); 99*a47a12beSStefan Roese } 100*a47a12beSStefan Roese 101*a47a12beSStefan Roese spridr = immr->sysconf.spridr; 102*a47a12beSStefan Roese 103*a47a12beSStefan Roese for (i = 0; i < ARRAY_SIZE(cpu_type_list); i++) 104*a47a12beSStefan Roese if (cpu_type_list[i].partid == PARTID_NO_E(spridr)) { 105*a47a12beSStefan Roese puts("MPC"); 106*a47a12beSStefan Roese puts(cpu_type_list[i].name); 107*a47a12beSStefan Roese if (IS_E_PROCESSOR(spridr)) 108*a47a12beSStefan Roese puts("E"); 109*a47a12beSStefan Roese if (REVID_MAJOR(spridr) >= 2) 110*a47a12beSStefan Roese puts("A"); 111*a47a12beSStefan Roese printf(", Rev: %d.%d", REVID_MAJOR(spridr), 112*a47a12beSStefan Roese REVID_MINOR(spridr)); 113*a47a12beSStefan Roese break; 114*a47a12beSStefan Roese } 115*a47a12beSStefan Roese 116*a47a12beSStefan Roese if (i == ARRAY_SIZE(cpu_type_list)) 117*a47a12beSStefan Roese printf("(SPRIDR %08x unknown), ", spridr); 118*a47a12beSStefan Roese 119*a47a12beSStefan Roese printf(" at %s MHz, ", strmhz(buf, clock)); 120*a47a12beSStefan Roese 121*a47a12beSStefan Roese printf("CSB: %s MHz\n", strmhz(buf, gd->csb_clk)); 122*a47a12beSStefan Roese 123*a47a12beSStefan Roese return 0; 124*a47a12beSStefan Roese } 125*a47a12beSStefan Roese 126*a47a12beSStefan Roese 127*a47a12beSStefan Roese /* 128*a47a12beSStefan Roese * Program a UPM with the code supplied in the table. 129*a47a12beSStefan Roese * 130*a47a12beSStefan Roese * The 'dummy' variable is used to increment the MAD. 'dummy' is 131*a47a12beSStefan Roese * supposed to be a pointer to the memory of the device being 132*a47a12beSStefan Roese * programmed by the UPM. The data in the MDR is written into 133*a47a12beSStefan Roese * memory and the MAD is incremented every time there's a write 134*a47a12beSStefan Roese * to 'dummy'. Unfortunately, the current prototype for this 135*a47a12beSStefan Roese * function doesn't allow for passing the address of this 136*a47a12beSStefan Roese * device, and changing the prototype will break a number lots 137*a47a12beSStefan Roese * of other code, so we need to use a round-about way of finding 138*a47a12beSStefan Roese * the value for 'dummy'. 139*a47a12beSStefan Roese * 140*a47a12beSStefan Roese * The value can be extracted from the base address bits of the 141*a47a12beSStefan Roese * Base Register (BR) associated with the specific UPM. To find 142*a47a12beSStefan Roese * that BR, we need to scan all 8 BRs until we find the one that 143*a47a12beSStefan Roese * has its MSEL bits matching the UPM we want. Once we know the 144*a47a12beSStefan Roese * right BR, we can extract the base address bits from it. 145*a47a12beSStefan Roese * 146*a47a12beSStefan Roese * The MxMR and the BR and OR of the chosen bank should all be 147*a47a12beSStefan Roese * configured before calling this function. 148*a47a12beSStefan Roese * 149*a47a12beSStefan Roese * Parameters: 150*a47a12beSStefan Roese * upm: 0=UPMA, 1=UPMB, 2=UPMC 151*a47a12beSStefan Roese * table: Pointer to an array of values to program 152*a47a12beSStefan Roese * size: Number of elements in the array. Must be 64 or less. 153*a47a12beSStefan Roese */ 154*a47a12beSStefan Roese void upmconfig (uint upm, uint *table, uint size) 155*a47a12beSStefan Roese { 156*a47a12beSStefan Roese volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; 157*a47a12beSStefan Roese volatile fsl_lbus_t *lbus = &immap->lbus; 158*a47a12beSStefan Roese volatile uchar *dummy = NULL; 159*a47a12beSStefan Roese const u32 msel = (upm + 4) << BR_MSEL_SHIFT; /* What the MSEL field in BRn should be */ 160*a47a12beSStefan Roese volatile u32 *mxmr = &lbus->mamr + upm; /* Pointer to mamr, mbmr, or mcmr */ 161*a47a12beSStefan Roese uint i; 162*a47a12beSStefan Roese 163*a47a12beSStefan Roese /* Scan all the banks to determine the base address of the device */ 164*a47a12beSStefan Roese for (i = 0; i < 8; i++) { 165*a47a12beSStefan Roese if ((lbus->bank[i].br & BR_MSEL) == msel) { 166*a47a12beSStefan Roese dummy = (uchar *) (lbus->bank[i].br & BR_BA); 167*a47a12beSStefan Roese break; 168*a47a12beSStefan Roese } 169*a47a12beSStefan Roese } 170*a47a12beSStefan Roese 171*a47a12beSStefan Roese if (!dummy) { 172*a47a12beSStefan Roese printf("Error: %s() could not find matching BR\n", __FUNCTION__); 173*a47a12beSStefan Roese hang(); 174*a47a12beSStefan Roese } 175*a47a12beSStefan Roese 176*a47a12beSStefan Roese /* Set the OP field in the MxMR to "write" and the MAD field to 000000 */ 177*a47a12beSStefan Roese *mxmr = (*mxmr & 0xCFFFFFC0) | 0x10000000; 178*a47a12beSStefan Roese 179*a47a12beSStefan Roese for (i = 0; i < size; i++) { 180*a47a12beSStefan Roese lbus->mdr = table[i]; 181*a47a12beSStefan Roese __asm__ __volatile__ ("sync"); 182*a47a12beSStefan Roese *dummy = 0; /* Write the value to memory and increment MAD */ 183*a47a12beSStefan Roese __asm__ __volatile__ ("sync"); 184*a47a12beSStefan Roese while(((*mxmr & 0x3f) != ((i + 1) & 0x3f))); 185*a47a12beSStefan Roese } 186*a47a12beSStefan Roese 187*a47a12beSStefan Roese /* Set the OP field in the MxMR to "normal" and the MAD field to 000000 */ 188*a47a12beSStefan Roese *mxmr &= 0xCFFFFFC0; 189*a47a12beSStefan Roese } 190*a47a12beSStefan Roese 191*a47a12beSStefan Roese 192*a47a12beSStefan Roese int 193*a47a12beSStefan Roese do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) 194*a47a12beSStefan Roese { 195*a47a12beSStefan Roese ulong msr; 196*a47a12beSStefan Roese #ifndef MPC83xx_RESET 197*a47a12beSStefan Roese ulong addr; 198*a47a12beSStefan Roese #endif 199*a47a12beSStefan Roese 200*a47a12beSStefan Roese volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; 201*a47a12beSStefan Roese 202*a47a12beSStefan Roese puts("Resetting the board.\n"); 203*a47a12beSStefan Roese 204*a47a12beSStefan Roese #ifdef MPC83xx_RESET 205*a47a12beSStefan Roese 206*a47a12beSStefan Roese /* Interrupts and MMU off */ 207*a47a12beSStefan Roese __asm__ __volatile__ ("mfmsr %0":"=r" (msr):); 208*a47a12beSStefan Roese 209*a47a12beSStefan Roese msr &= ~( MSR_EE | MSR_IR | MSR_DR); 210*a47a12beSStefan Roese __asm__ __volatile__ ("mtmsr %0"::"r" (msr)); 211*a47a12beSStefan Roese 212*a47a12beSStefan Roese /* enable Reset Control Reg */ 213*a47a12beSStefan Roese immap->reset.rpr = 0x52535445; 214*a47a12beSStefan Roese __asm__ __volatile__ ("sync"); 215*a47a12beSStefan Roese __asm__ __volatile__ ("isync"); 216*a47a12beSStefan Roese 217*a47a12beSStefan Roese /* confirm Reset Control Reg is enabled */ 218*a47a12beSStefan Roese while(!((immap->reset.rcer) & RCER_CRE)); 219*a47a12beSStefan Roese 220*a47a12beSStefan Roese udelay(200); 221*a47a12beSStefan Roese 222*a47a12beSStefan Roese /* perform reset, only one bit */ 223*a47a12beSStefan Roese immap->reset.rcr = RCR_SWHR; 224*a47a12beSStefan Roese 225*a47a12beSStefan Roese #else /* ! MPC83xx_RESET */ 226*a47a12beSStefan Roese 227*a47a12beSStefan Roese immap->reset.rmr = RMR_CSRE; /* Checkstop Reset enable */ 228*a47a12beSStefan Roese 229*a47a12beSStefan Roese /* Interrupts and MMU off */ 230*a47a12beSStefan Roese __asm__ __volatile__ ("mfmsr %0":"=r" (msr):); 231*a47a12beSStefan Roese 232*a47a12beSStefan Roese msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR); 233*a47a12beSStefan Roese __asm__ __volatile__ ("mtmsr %0"::"r" (msr)); 234*a47a12beSStefan Roese 235*a47a12beSStefan Roese /* 236*a47a12beSStefan Roese * Trying to execute the next instruction at a non-existing address 237*a47a12beSStefan Roese * should cause a machine check, resulting in reset 238*a47a12beSStefan Roese */ 239*a47a12beSStefan Roese addr = CONFIG_SYS_RESET_ADDRESS; 240*a47a12beSStefan Roese 241*a47a12beSStefan Roese ((void (*)(void)) addr) (); 242*a47a12beSStefan Roese #endif /* MPC83xx_RESET */ 243*a47a12beSStefan Roese 244*a47a12beSStefan Roese return 1; 245*a47a12beSStefan Roese } 246*a47a12beSStefan Roese 247*a47a12beSStefan Roese 248*a47a12beSStefan Roese /* 249*a47a12beSStefan Roese * Get timebase clock frequency (like cpu_clk in Hz) 250*a47a12beSStefan Roese */ 251*a47a12beSStefan Roese 252*a47a12beSStefan Roese unsigned long get_tbclk(void) 253*a47a12beSStefan Roese { 254*a47a12beSStefan Roese ulong tbclk; 255*a47a12beSStefan Roese 256*a47a12beSStefan Roese tbclk = (gd->bus_clk + 3L) / 4L; 257*a47a12beSStefan Roese 258*a47a12beSStefan Roese return tbclk; 259*a47a12beSStefan Roese } 260*a47a12beSStefan Roese 261*a47a12beSStefan Roese 262*a47a12beSStefan Roese #if defined(CONFIG_WATCHDOG) 263*a47a12beSStefan Roese void watchdog_reset (void) 264*a47a12beSStefan Roese { 265*a47a12beSStefan Roese int re_enable = disable_interrupts(); 266*a47a12beSStefan Roese 267*a47a12beSStefan Roese /* Reset the 83xx watchdog */ 268*a47a12beSStefan Roese volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; 269*a47a12beSStefan Roese immr->wdt.swsrr = 0x556c; 270*a47a12beSStefan Roese immr->wdt.swsrr = 0xaa39; 271*a47a12beSStefan Roese 272*a47a12beSStefan Roese if (re_enable) 273*a47a12beSStefan Roese enable_interrupts (); 274*a47a12beSStefan Roese } 275*a47a12beSStefan Roese #endif 276*a47a12beSStefan Roese 277*a47a12beSStefan Roese /* 278*a47a12beSStefan Roese * Initializes on-chip ethernet controllers. 279*a47a12beSStefan Roese * to override, implement board_eth_init() 280*a47a12beSStefan Roese */ 281*a47a12beSStefan Roese int cpu_eth_init(bd_t *bis) 282*a47a12beSStefan Roese { 283*a47a12beSStefan Roese #if defined(CONFIG_UEC_ETH) 284*a47a12beSStefan Roese uec_standard_init(bis); 285*a47a12beSStefan Roese #endif 286*a47a12beSStefan Roese 287*a47a12beSStefan Roese #if defined(CONFIG_TSEC_ENET) 288*a47a12beSStefan Roese tsec_standard_init(bis); 289*a47a12beSStefan Roese #endif 290*a47a12beSStefan Roese return 0; 291*a47a12beSStefan Roese } 292*a47a12beSStefan Roese 293*a47a12beSStefan Roese /* 294*a47a12beSStefan Roese * Initializes on-chip MMC controllers. 295*a47a12beSStefan Roese * to override, implement board_mmc_init() 296*a47a12beSStefan Roese */ 297*a47a12beSStefan Roese int cpu_mmc_init(bd_t *bis) 298*a47a12beSStefan Roese { 299*a47a12beSStefan Roese #ifdef CONFIG_FSL_ESDHC 300*a47a12beSStefan Roese return fsl_esdhc_mmc_init(bis); 301*a47a12beSStefan Roese #else 302*a47a12beSStefan Roese return 0; 303*a47a12beSStefan Roese #endif 304*a47a12beSStefan Roese } 305*a47a12beSStefan Roese 306*a47a12beSStefan Roese #ifdef CONFIG_BOOTCOUNT_LIMIT 307*a47a12beSStefan Roese 308*a47a12beSStefan Roese #if !defined(CONFIG_MPC8360) 309*a47a12beSStefan Roese #error "CONFIG_BOOTCOUNT_LIMIT only for MPC8360 implemented" 310*a47a12beSStefan Roese #endif 311*a47a12beSStefan Roese 312*a47a12beSStefan Roese #if !defined(CONFIG_BOOTCOUNT_ADDR) 313*a47a12beSStefan Roese #define CONFIG_BOOTCOUNT_ADDR (0x110000 + QE_MURAM_SIZE - 2 * sizeof(unsigned long)) 314*a47a12beSStefan Roese #endif 315*a47a12beSStefan Roese 316*a47a12beSStefan Roese #include <asm/io.h> 317*a47a12beSStefan Roese 318*a47a12beSStefan Roese void bootcount_store (ulong a) 319*a47a12beSStefan Roese { 320*a47a12beSStefan Roese void *reg = (void *)(CONFIG_SYS_IMMR + CONFIG_BOOTCOUNT_ADDR); 321*a47a12beSStefan Roese out_be32 (reg, a); 322*a47a12beSStefan Roese out_be32 (reg + 4, BOOTCOUNT_MAGIC); 323*a47a12beSStefan Roese } 324*a47a12beSStefan Roese 325*a47a12beSStefan Roese ulong bootcount_load (void) 326*a47a12beSStefan Roese { 327*a47a12beSStefan Roese void *reg = (void *)(CONFIG_SYS_IMMR + CONFIG_BOOTCOUNT_ADDR); 328*a47a12beSStefan Roese 329*a47a12beSStefan Roese if (in_be32 (reg + 4) != BOOTCOUNT_MAGIC) 330*a47a12beSStefan Roese return 0; 331*a47a12beSStefan Roese else 332*a47a12beSStefan Roese return in_be32 (reg); 333*a47a12beSStefan Roese } 334*a47a12beSStefan Roese #endif /* CONFIG_BOOTCOUNT_LIMIT */ 335