1907208c4SChristophe Leroy /* 2907208c4SChristophe Leroy * (C) Copyright 2000-2002 3907208c4SChristophe Leroy * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4907208c4SChristophe Leroy * 5907208c4SChristophe Leroy * SPDX-License-Identifier: GPL-2.0+ 6907208c4SChristophe Leroy */ 7907208c4SChristophe Leroy 8907208c4SChristophe Leroy /* 9907208c4SChristophe Leroy * m8xx.c 10907208c4SChristophe Leroy * 11907208c4SChristophe Leroy * CPU specific code 12907208c4SChristophe Leroy * 13907208c4SChristophe Leroy * written or collected and sometimes rewritten by 14907208c4SChristophe Leroy * Magnus Damm <damm@bitsmart.com> 15907208c4SChristophe Leroy * 16907208c4SChristophe Leroy * minor modifications by 17907208c4SChristophe Leroy * Wolfgang Denk <wd@denx.de> 18907208c4SChristophe Leroy */ 19907208c4SChristophe Leroy 20907208c4SChristophe Leroy #include <common.h> 21907208c4SChristophe Leroy #include <watchdog.h> 22907208c4SChristophe Leroy #include <command.h> 23907208c4SChristophe Leroy #include <mpc8xx.h> 24907208c4SChristophe Leroy #include <commproc.h> 25907208c4SChristophe Leroy #include <netdev.h> 26907208c4SChristophe Leroy #include <asm/cache.h> 27907208c4SChristophe Leroy #include <linux/compiler.h> 28907208c4SChristophe Leroy #include <asm/io.h> 29907208c4SChristophe Leroy 30907208c4SChristophe Leroy #if defined(CONFIG_OF_LIBFDT) 31907208c4SChristophe Leroy #include <libfdt.h> 32907208c4SChristophe Leroy #include <fdt_support.h> 33907208c4SChristophe Leroy #endif 34907208c4SChristophe Leroy 35907208c4SChristophe Leroy DECLARE_GLOBAL_DATA_PTR; 36907208c4SChristophe Leroy 37907208c4SChristophe Leroy static char *cpu_warning = "\n " \ 38907208c4SChristophe Leroy "*** Warning: CPU Core has Silicon Bugs -- Check the Errata ***"; 39907208c4SChristophe Leroy 40907208c4SChristophe Leroy static int check_CPU (long clock, uint pvr, uint immr) 41907208c4SChristophe Leroy { 42907208c4SChristophe Leroy char *id_str = 43907208c4SChristophe Leroy NULL; 44*ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)(immr & 0xFFFF0000); 45907208c4SChristophe Leroy uint k, m; 46907208c4SChristophe Leroy char buf[32]; 47907208c4SChristophe Leroy char pre = 'X'; 48907208c4SChristophe Leroy char *mid = "xx"; 49907208c4SChristophe Leroy char *suf; 50907208c4SChristophe Leroy 51907208c4SChristophe Leroy /* the highest 16 bits should be 0x0050 for a 860 */ 52907208c4SChristophe Leroy 53907208c4SChristophe Leroy if ((pvr >> 16) != 0x0050) 54907208c4SChristophe Leroy return -1; 55907208c4SChristophe Leroy 56907208c4SChristophe Leroy k = (immr << 16) | 57*ba3da734SChristophe Leroy in_be16(&immap->im_cpm.cp_dparam16[PROFF_REVNUM / sizeof(u16)]); 58907208c4SChristophe Leroy m = 0; 59907208c4SChristophe Leroy suf = ""; 60907208c4SChristophe Leroy 61907208c4SChristophe Leroy /* 62907208c4SChristophe Leroy * Some boards use sockets so different CPUs can be used. 63907208c4SChristophe Leroy * We have to check chip version in run time. 64907208c4SChristophe Leroy */ 65907208c4SChristophe Leroy switch (k) { 66907208c4SChristophe Leroy /* MPC866P/MPC866T/MPC859T/MPC859DSL/MPC852T */ 67907208c4SChristophe Leroy case 0x08010004: /* Rev. A.0 */ 68907208c4SChristophe Leroy suf = "A"; 69907208c4SChristophe Leroy /* fall through */ 70907208c4SChristophe Leroy case 0x08000003: /* Rev. 0.3 */ 71907208c4SChristophe Leroy pre = 'M'; m = 1; 72907208c4SChristophe Leroy if (id_str == NULL) 73907208c4SChristophe Leroy id_str = 74907208c4SChristophe Leroy "PC866x"; /* Unknown chip from MPC866 family */ 75907208c4SChristophe Leroy break; 76907208c4SChristophe Leroy case 0x09000000: pre = 'M'; mid = suf = ""; m = 1; 77907208c4SChristophe Leroy if (id_str == NULL) 78907208c4SChristophe Leroy id_str = "PC885"; /* 870/875/880/885 */ 79907208c4SChristophe Leroy break; 80907208c4SChristophe Leroy 81907208c4SChristophe Leroy default: suf = NULL; break; 82907208c4SChristophe Leroy } 83907208c4SChristophe Leroy 84907208c4SChristophe Leroy if (id_str == NULL) 85907208c4SChristophe Leroy id_str = "PC86x"; /* Unknown 86x chip */ 86907208c4SChristophe Leroy if (suf) 87907208c4SChristophe Leroy printf ("%c%s%sZPnn%s", pre, id_str, mid, suf); 88907208c4SChristophe Leroy else 89907208c4SChristophe Leroy printf ("unknown M%s (0x%08x)", id_str, k); 90907208c4SChristophe Leroy 91907208c4SChristophe Leroy printf (" at %s MHz: ", strmhz (buf, clock)); 92907208c4SChristophe Leroy 93907208c4SChristophe Leroy print_size(checkicache(), " I-Cache "); 94907208c4SChristophe Leroy print_size(checkdcache(), " D-Cache"); 95907208c4SChristophe Leroy 96907208c4SChristophe Leroy /* do we have a FEC (860T/P or 852/859/866/885)? */ 97907208c4SChristophe Leroy 98*ba3da734SChristophe Leroy out_be32(&immap->im_cpm.cp_fec.fec_addr_low, 0x12345678); 99*ba3da734SChristophe Leroy if (in_be32(&immap->im_cpm.cp_fec.fec_addr_low) == 0x12345678) 100907208c4SChristophe Leroy printf (" FEC present"); 101907208c4SChristophe Leroy 102907208c4SChristophe Leroy if (!m) { 103907208c4SChristophe Leroy puts (cpu_warning); 104907208c4SChristophe Leroy } 105907208c4SChristophe Leroy 106907208c4SChristophe Leroy putc ('\n'); 107907208c4SChristophe Leroy 108907208c4SChristophe Leroy return 0; 109907208c4SChristophe Leroy } 110907208c4SChristophe Leroy 111907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 112907208c4SChristophe Leroy 113907208c4SChristophe Leroy int checkcpu (void) 114907208c4SChristophe Leroy { 115907208c4SChristophe Leroy ulong clock = gd->cpu_clk; 116907208c4SChristophe Leroy uint immr = get_immr (0); /* Return full IMMR contents */ 117907208c4SChristophe Leroy uint pvr = get_pvr (); 118907208c4SChristophe Leroy 119907208c4SChristophe Leroy puts ("CPU: "); 120907208c4SChristophe Leroy 121907208c4SChristophe Leroy return check_CPU (clock, pvr, immr); 122907208c4SChristophe Leroy } 123907208c4SChristophe Leroy 124907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 125907208c4SChristophe Leroy /* L1 i-cache */ 126907208c4SChristophe Leroy 127907208c4SChristophe Leroy int checkicache (void) 128907208c4SChristophe Leroy { 129*ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; 130*ba3da734SChristophe Leroy memctl8xx_t __iomem *memctl = &immap->im_memctl; 131907208c4SChristophe Leroy u32 cacheon = rd_ic_cst () & IDC_ENABLED; 132*ba3da734SChristophe Leroy /* probe in flash memoryarea */ 133*ba3da734SChristophe Leroy u32 k = in_be32(&memctl->memc_br0) & ~0x00007fff; 134907208c4SChristophe Leroy u32 m; 135907208c4SChristophe Leroy u32 lines = -1; 136907208c4SChristophe Leroy 137907208c4SChristophe Leroy wr_ic_cst (IDC_UNALL); 138907208c4SChristophe Leroy wr_ic_cst (IDC_INVALL); 139907208c4SChristophe Leroy wr_ic_cst (IDC_DISABLE); 140907208c4SChristophe Leroy __asm__ volatile ("isync"); 141907208c4SChristophe Leroy 142907208c4SChristophe Leroy while (!((m = rd_ic_cst ()) & IDC_CERR2)) { 143907208c4SChristophe Leroy wr_ic_adr (k); 144907208c4SChristophe Leroy wr_ic_cst (IDC_LDLCK); 145907208c4SChristophe Leroy __asm__ volatile ("isync"); 146907208c4SChristophe Leroy 147907208c4SChristophe Leroy lines++; 148907208c4SChristophe Leroy k += 0x10; /* the number of bytes in a cacheline */ 149907208c4SChristophe Leroy } 150907208c4SChristophe Leroy 151907208c4SChristophe Leroy wr_ic_cst (IDC_UNALL); 152907208c4SChristophe Leroy wr_ic_cst (IDC_INVALL); 153907208c4SChristophe Leroy 154907208c4SChristophe Leroy if (cacheon) 155907208c4SChristophe Leroy wr_ic_cst (IDC_ENABLE); 156907208c4SChristophe Leroy else 157907208c4SChristophe Leroy wr_ic_cst (IDC_DISABLE); 158907208c4SChristophe Leroy 159907208c4SChristophe Leroy __asm__ volatile ("isync"); 160907208c4SChristophe Leroy 161907208c4SChristophe Leroy return lines << 4; 162907208c4SChristophe Leroy }; 163907208c4SChristophe Leroy 164907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 165907208c4SChristophe Leroy /* L1 d-cache */ 166907208c4SChristophe Leroy /* call with cache disabled */ 167907208c4SChristophe Leroy 168907208c4SChristophe Leroy int checkdcache (void) 169907208c4SChristophe Leroy { 170*ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; 171*ba3da734SChristophe Leroy memctl8xx_t __iomem *memctl = &immap->im_memctl; 172907208c4SChristophe Leroy u32 cacheon = rd_dc_cst () & IDC_ENABLED; 173*ba3da734SChristophe Leroy /* probe in flash memoryarea */ 174*ba3da734SChristophe Leroy u32 k = in_be32(&memctl->memc_br0) & ~0x00007fff; 175907208c4SChristophe Leroy u32 m; 176907208c4SChristophe Leroy u32 lines = -1; 177907208c4SChristophe Leroy 178907208c4SChristophe Leroy wr_dc_cst (IDC_UNALL); 179907208c4SChristophe Leroy wr_dc_cst (IDC_INVALL); 180907208c4SChristophe Leroy wr_dc_cst (IDC_DISABLE); 181907208c4SChristophe Leroy 182907208c4SChristophe Leroy while (!((m = rd_dc_cst ()) & IDC_CERR2)) { 183907208c4SChristophe Leroy wr_dc_adr (k); 184907208c4SChristophe Leroy wr_dc_cst (IDC_LDLCK); 185907208c4SChristophe Leroy lines++; 186907208c4SChristophe Leroy k += 0x10; /* the number of bytes in a cacheline */ 187907208c4SChristophe Leroy } 188907208c4SChristophe Leroy 189907208c4SChristophe Leroy wr_dc_cst (IDC_UNALL); 190907208c4SChristophe Leroy wr_dc_cst (IDC_INVALL); 191907208c4SChristophe Leroy 192907208c4SChristophe Leroy if (cacheon) 193907208c4SChristophe Leroy wr_dc_cst (IDC_ENABLE); 194907208c4SChristophe Leroy else 195907208c4SChristophe Leroy wr_dc_cst (IDC_DISABLE); 196907208c4SChristophe Leroy 197907208c4SChristophe Leroy return lines << 4; 198907208c4SChristophe Leroy }; 199907208c4SChristophe Leroy 200907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 201907208c4SChristophe Leroy 202907208c4SChristophe Leroy void upmconfig (uint upm, uint * table, uint size) 203907208c4SChristophe Leroy { 204907208c4SChristophe Leroy uint i; 205907208c4SChristophe Leroy uint addr = 0; 206*ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; 207*ba3da734SChristophe Leroy memctl8xx_t __iomem *memctl = &immap->im_memctl; 208907208c4SChristophe Leroy 209907208c4SChristophe Leroy for (i = 0; i < size; i++) { 210*ba3da734SChristophe Leroy out_be32(&memctl->memc_mdr, table[i]); /* (16-15) */ 211*ba3da734SChristophe Leroy out_be32(&memctl->memc_mcr, addr | upm); /* (16-16) */ 212907208c4SChristophe Leroy addr++; 213907208c4SChristophe Leroy } 214907208c4SChristophe Leroy } 215907208c4SChristophe Leroy 216907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 217907208c4SChristophe Leroy 218907208c4SChristophe Leroy int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 219907208c4SChristophe Leroy { 220907208c4SChristophe Leroy ulong msr, addr; 221907208c4SChristophe Leroy 222*ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; 223907208c4SChristophe Leroy 224*ba3da734SChristophe Leroy /* Checkstop Reset enable */ 225*ba3da734SChristophe Leroy setbits_be32(&immap->im_clkrst.car_plprcr, PLPRCR_CSR); 226907208c4SChristophe Leroy 227907208c4SChristophe Leroy /* Interrupts and MMU off */ 228907208c4SChristophe Leroy __asm__ volatile ("mtspr 81, 0"); 229907208c4SChristophe Leroy __asm__ volatile ("mfmsr %0":"=r" (msr)); 230907208c4SChristophe Leroy 231907208c4SChristophe Leroy msr &= ~0x1030; 232907208c4SChristophe Leroy __asm__ volatile ("mtmsr %0"::"r" (msr)); 233907208c4SChristophe Leroy 234907208c4SChristophe Leroy /* 235907208c4SChristophe Leroy * Trying to execute the next instruction at a non-existing address 236907208c4SChristophe Leroy * should cause a machine check, resulting in reset 237907208c4SChristophe Leroy */ 238907208c4SChristophe Leroy #ifdef CONFIG_SYS_RESET_ADDRESS 239907208c4SChristophe Leroy addr = CONFIG_SYS_RESET_ADDRESS; 240907208c4SChristophe Leroy #else 241907208c4SChristophe Leroy /* 242907208c4SChristophe Leroy * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address, CONFIG_SYS_MONITOR_BASE 243907208c4SChristophe Leroy * - sizeof (ulong) is usually a valid address. Better pick an address 244907208c4SChristophe Leroy * known to be invalid on your system and assign it to CONFIG_SYS_RESET_ADDRESS. 245907208c4SChristophe Leroy * "(ulong)-1" used to be a good choice for many systems... 246907208c4SChristophe Leroy */ 247907208c4SChristophe Leroy addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong); 248907208c4SChristophe Leroy #endif 249907208c4SChristophe Leroy ((void (*)(void)) addr) (); 250907208c4SChristophe Leroy return 1; 251907208c4SChristophe Leroy } 252907208c4SChristophe Leroy 253907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 254907208c4SChristophe Leroy 255907208c4SChristophe Leroy /* 256907208c4SChristophe Leroy * Get timebase clock frequency (like cpu_clk in Hz) 257907208c4SChristophe Leroy * 258907208c4SChristophe Leroy * See sections 14.2 and 14.6 of the User's Manual 259907208c4SChristophe Leroy */ 260907208c4SChristophe Leroy unsigned long get_tbclk (void) 261907208c4SChristophe Leroy { 262907208c4SChristophe Leroy uint immr = get_immr (0); /* Return full IMMR contents */ 263*ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)(immr & 0xFFFF0000); 264907208c4SChristophe Leroy ulong oscclk, factor, pll; 265907208c4SChristophe Leroy 266*ba3da734SChristophe Leroy if (in_be32(&immap->im_clkrst.car_sccr) & SCCR_TBS) 267907208c4SChristophe Leroy return (gd->cpu_clk / 16); 268907208c4SChristophe Leroy 269*ba3da734SChristophe Leroy pll = in_be32(&immap->im_clkrst.car_plprcr); 270907208c4SChristophe Leroy 271907208c4SChristophe Leroy #define PLPRCR_val(a) ((pll & PLPRCR_ ## a ## _MSK) >> PLPRCR_ ## a ## _SHIFT) 272907208c4SChristophe Leroy 273907208c4SChristophe Leroy /* 274907208c4SChristophe Leroy * For newer PQ1 chips (MPC866/87x/88x families), PLL multiplication 275907208c4SChristophe Leroy * factor is calculated as follows: 276907208c4SChristophe Leroy * 277907208c4SChristophe Leroy * MFN 278907208c4SChristophe Leroy * MFI + ------- 279907208c4SChristophe Leroy * MFD + 1 280907208c4SChristophe Leroy * factor = ----------------- 281907208c4SChristophe Leroy * (PDF + 1) * 2^S 282907208c4SChristophe Leroy * 283907208c4SChristophe Leroy */ 284907208c4SChristophe Leroy factor = (PLPRCR_val(MFI) + PLPRCR_val(MFN)/(PLPRCR_val(MFD)+1))/ 285907208c4SChristophe Leroy (PLPRCR_val(PDF)+1) / (1<<PLPRCR_val(S)); 286907208c4SChristophe Leroy 287907208c4SChristophe Leroy oscclk = gd->cpu_clk / factor; 288907208c4SChristophe Leroy 289*ba3da734SChristophe Leroy if ((in_be32(&immap->im_clkrst.car_sccr) & SCCR_RTSEL) == 0 || 290*ba3da734SChristophe Leroy factor > 2) 291907208c4SChristophe Leroy return (oscclk / 4); 292*ba3da734SChristophe Leroy 293907208c4SChristophe Leroy return (oscclk / 16); 294907208c4SChristophe Leroy } 295907208c4SChristophe Leroy 296907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 297907208c4SChristophe Leroy 298907208c4SChristophe Leroy #if defined(CONFIG_WATCHDOG) 299907208c4SChristophe Leroy void watchdog_reset (void) 300907208c4SChristophe Leroy { 301907208c4SChristophe Leroy int re_enable = disable_interrupts (); 302907208c4SChristophe Leroy 303*ba3da734SChristophe Leroy reset_8xx_watchdog((immap_t __iomem *)CONFIG_SYS_IMMR); 304907208c4SChristophe Leroy if (re_enable) 305907208c4SChristophe Leroy enable_interrupts (); 306907208c4SChristophe Leroy } 307907208c4SChristophe Leroy #endif /* CONFIG_WATCHDOG */ 308907208c4SChristophe Leroy 309907208c4SChristophe Leroy #if defined(CONFIG_WATCHDOG) 310907208c4SChristophe Leroy 311*ba3da734SChristophe Leroy void reset_8xx_watchdog(immap_t __iomem *immr) 312907208c4SChristophe Leroy { 313907208c4SChristophe Leroy /* 314907208c4SChristophe Leroy * All other boards use the MPC8xx Internal Watchdog 315907208c4SChristophe Leroy */ 316*ba3da734SChristophe Leroy out_be16(&immr->im_siu_conf.sc_swsr, 0x556c); /* write magic1 */ 317*ba3da734SChristophe Leroy out_be16(&immr->im_siu_conf.sc_swsr, 0xaa39); /* write magic2 */ 318907208c4SChristophe Leroy } 319907208c4SChristophe Leroy #endif /* CONFIG_WATCHDOG */ 320907208c4SChristophe Leroy 321907208c4SChristophe Leroy /* 322907208c4SChristophe Leroy * Initializes on-chip ethernet controllers. 323907208c4SChristophe Leroy * to override, implement board_eth_init() 324907208c4SChristophe Leroy */ 325907208c4SChristophe Leroy int cpu_eth_init(bd_t *bis) 326907208c4SChristophe Leroy { 327907208c4SChristophe Leroy #if defined(FEC_ENET) 328907208c4SChristophe Leroy fec_initialize(bis); 329907208c4SChristophe Leroy #endif 330907208c4SChristophe Leroy return 0; 331907208c4SChristophe Leroy } 332