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; 44ba3da734SChristophe 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) | 57ba3da734SChristophe 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; 76*70fd0710SChristophe Leroy case 0x09000000: 77*70fd0710SChristophe Leroy pre = 'M'; mid = suf = ""; m = 1; 78907208c4SChristophe Leroy if (id_str == NULL) 79907208c4SChristophe Leroy id_str = "PC885"; /* 870/875/880/885 */ 80907208c4SChristophe Leroy break; 81907208c4SChristophe Leroy 82*70fd0710SChristophe Leroy default: 83*70fd0710SChristophe Leroy suf = NULL; 84*70fd0710SChristophe Leroy break; 85907208c4SChristophe Leroy } 86907208c4SChristophe Leroy 87907208c4SChristophe Leroy if (id_str == NULL) 88907208c4SChristophe Leroy id_str = "PC86x"; /* Unknown 86x chip */ 89907208c4SChristophe Leroy if (suf) 90907208c4SChristophe Leroy printf("%c%s%sZPnn%s", pre, id_str, mid, suf); 91907208c4SChristophe Leroy else 92907208c4SChristophe Leroy printf("unknown M%s (0x%08x)", id_str, k); 93907208c4SChristophe Leroy 94907208c4SChristophe Leroy printf(" at %s MHz: ", strmhz(buf, clock)); 95907208c4SChristophe Leroy 96907208c4SChristophe Leroy print_size(checkicache(), " I-Cache "); 97907208c4SChristophe Leroy print_size(checkdcache(), " D-Cache"); 98907208c4SChristophe Leroy 99907208c4SChristophe Leroy /* do we have a FEC (860T/P or 852/859/866/885)? */ 100907208c4SChristophe Leroy 101ba3da734SChristophe Leroy out_be32(&immap->im_cpm.cp_fec.fec_addr_low, 0x12345678); 102ba3da734SChristophe Leroy if (in_be32(&immap->im_cpm.cp_fec.fec_addr_low) == 0x12345678) 103907208c4SChristophe Leroy printf(" FEC present"); 104907208c4SChristophe Leroy 105*70fd0710SChristophe Leroy if (!m) 106907208c4SChristophe Leroy puts(cpu_warning); 107907208c4SChristophe Leroy 108907208c4SChristophe Leroy putc('\n'); 109907208c4SChristophe Leroy 110907208c4SChristophe Leroy return 0; 111907208c4SChristophe Leroy } 112907208c4SChristophe Leroy 113907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 114907208c4SChristophe Leroy 115907208c4SChristophe Leroy int checkcpu(void) 116907208c4SChristophe Leroy { 117907208c4SChristophe Leroy ulong clock = gd->cpu_clk; 118907208c4SChristophe Leroy uint immr = get_immr(0); /* Return full IMMR contents */ 119907208c4SChristophe Leroy uint pvr = get_pvr(); 120907208c4SChristophe Leroy 121907208c4SChristophe Leroy puts("CPU: "); 122907208c4SChristophe Leroy 123907208c4SChristophe Leroy return check_CPU(clock, pvr, immr); 124907208c4SChristophe Leroy } 125907208c4SChristophe Leroy 126907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 127907208c4SChristophe Leroy /* L1 i-cache */ 128907208c4SChristophe Leroy 129907208c4SChristophe Leroy int checkicache(void) 130907208c4SChristophe Leroy { 131ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; 132ba3da734SChristophe Leroy memctl8xx_t __iomem *memctl = &immap->im_memctl; 133907208c4SChristophe Leroy u32 cacheon = rd_ic_cst() & IDC_ENABLED; 134ba3da734SChristophe Leroy /* probe in flash memoryarea */ 135ba3da734SChristophe Leroy u32 k = in_be32(&memctl->memc_br0) & ~0x00007fff; 136907208c4SChristophe Leroy u32 m; 137907208c4SChristophe Leroy u32 lines = -1; 138907208c4SChristophe Leroy 139907208c4SChristophe Leroy wr_ic_cst(IDC_UNALL); 140907208c4SChristophe Leroy wr_ic_cst(IDC_INVALL); 141907208c4SChristophe Leroy wr_ic_cst(IDC_DISABLE); 142907208c4SChristophe Leroy __asm__ volatile ("isync"); 143907208c4SChristophe Leroy 144907208c4SChristophe Leroy while (!((m = rd_ic_cst()) & IDC_CERR2)) { 145907208c4SChristophe Leroy wr_ic_adr(k); 146907208c4SChristophe Leroy wr_ic_cst(IDC_LDLCK); 147907208c4SChristophe Leroy __asm__ volatile ("isync"); 148907208c4SChristophe Leroy 149907208c4SChristophe Leroy lines++; 150907208c4SChristophe Leroy k += 0x10; /* the number of bytes in a cacheline */ 151907208c4SChristophe Leroy } 152907208c4SChristophe Leroy 153907208c4SChristophe Leroy wr_ic_cst(IDC_UNALL); 154907208c4SChristophe Leroy wr_ic_cst(IDC_INVALL); 155907208c4SChristophe Leroy 156907208c4SChristophe Leroy if (cacheon) 157907208c4SChristophe Leroy wr_ic_cst(IDC_ENABLE); 158907208c4SChristophe Leroy else 159907208c4SChristophe Leroy wr_ic_cst(IDC_DISABLE); 160907208c4SChristophe Leroy 161907208c4SChristophe Leroy __asm__ volatile ("isync"); 162907208c4SChristophe Leroy 163907208c4SChristophe Leroy return lines << 4; 164907208c4SChristophe Leroy }; 165907208c4SChristophe Leroy 166907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 167907208c4SChristophe Leroy /* L1 d-cache */ 168907208c4SChristophe Leroy /* call with cache disabled */ 169907208c4SChristophe Leroy 170907208c4SChristophe Leroy int checkdcache(void) 171907208c4SChristophe Leroy { 172ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; 173ba3da734SChristophe Leroy memctl8xx_t __iomem *memctl = &immap->im_memctl; 174907208c4SChristophe Leroy u32 cacheon = rd_dc_cst() & IDC_ENABLED; 175ba3da734SChristophe Leroy /* probe in flash memoryarea */ 176ba3da734SChristophe Leroy u32 k = in_be32(&memctl->memc_br0) & ~0x00007fff; 177907208c4SChristophe Leroy u32 m; 178907208c4SChristophe Leroy u32 lines = -1; 179907208c4SChristophe Leroy 180907208c4SChristophe Leroy wr_dc_cst(IDC_UNALL); 181907208c4SChristophe Leroy wr_dc_cst(IDC_INVALL); 182907208c4SChristophe Leroy wr_dc_cst(IDC_DISABLE); 183907208c4SChristophe Leroy 184907208c4SChristophe Leroy while (!((m = rd_dc_cst()) & IDC_CERR2)) { 185907208c4SChristophe Leroy wr_dc_adr(k); 186907208c4SChristophe Leroy wr_dc_cst(IDC_LDLCK); 187907208c4SChristophe Leroy lines++; 188907208c4SChristophe Leroy k += 0x10; /* the number of bytes in a cacheline */ 189907208c4SChristophe Leroy } 190907208c4SChristophe Leroy 191907208c4SChristophe Leroy wr_dc_cst(IDC_UNALL); 192907208c4SChristophe Leroy wr_dc_cst(IDC_INVALL); 193907208c4SChristophe Leroy 194907208c4SChristophe Leroy if (cacheon) 195907208c4SChristophe Leroy wr_dc_cst(IDC_ENABLE); 196907208c4SChristophe Leroy else 197907208c4SChristophe Leroy wr_dc_cst(IDC_DISABLE); 198907208c4SChristophe Leroy 199907208c4SChristophe Leroy return lines << 4; 200907208c4SChristophe Leroy }; 201907208c4SChristophe Leroy 202907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 203907208c4SChristophe Leroy 204907208c4SChristophe Leroy void upmconfig(uint upm, uint *table, uint size) 205907208c4SChristophe Leroy { 206907208c4SChristophe Leroy uint i; 207907208c4SChristophe Leroy uint addr = 0; 208ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; 209ba3da734SChristophe Leroy memctl8xx_t __iomem *memctl = &immap->im_memctl; 210907208c4SChristophe Leroy 211907208c4SChristophe Leroy for (i = 0; i < size; i++) { 212ba3da734SChristophe Leroy out_be32(&memctl->memc_mdr, table[i]); /* (16-15) */ 213ba3da734SChristophe Leroy out_be32(&memctl->memc_mcr, addr | upm); /* (16-16) */ 214907208c4SChristophe Leroy addr++; 215907208c4SChristophe Leroy } 216907208c4SChristophe Leroy } 217907208c4SChristophe Leroy 218907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 219907208c4SChristophe Leroy 220907208c4SChristophe Leroy int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 221907208c4SChristophe Leroy { 222907208c4SChristophe Leroy ulong msr, addr; 223907208c4SChristophe Leroy 224ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; 225907208c4SChristophe Leroy 226ba3da734SChristophe Leroy /* Checkstop Reset enable */ 227ba3da734SChristophe Leroy setbits_be32(&immap->im_clkrst.car_plprcr, PLPRCR_CSR); 228907208c4SChristophe Leroy 229907208c4SChristophe Leroy /* Interrupts and MMU off */ 230907208c4SChristophe Leroy __asm__ volatile ("mtspr 81, 0"); 231907208c4SChristophe Leroy __asm__ volatile ("mfmsr %0" : "=r" (msr)); 232907208c4SChristophe Leroy 233907208c4SChristophe Leroy msr &= ~0x1030; 234907208c4SChristophe Leroy __asm__ volatile ("mtmsr %0" : : "r" (msr)); 235907208c4SChristophe Leroy 236907208c4SChristophe Leroy /* 237907208c4SChristophe Leroy * Trying to execute the next instruction at a non-existing address 238907208c4SChristophe Leroy * should cause a machine check, resulting in reset 239907208c4SChristophe Leroy */ 240907208c4SChristophe Leroy #ifdef CONFIG_SYS_RESET_ADDRESS 241907208c4SChristophe Leroy addr = CONFIG_SYS_RESET_ADDRESS; 242907208c4SChristophe Leroy #else 243907208c4SChristophe Leroy /* 244*70fd0710SChristophe Leroy * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address, 245*70fd0710SChristophe Leroy * CONFIG_SYS_MONITOR_BASE - sizeof (ulong) is usually a valid address. 246*70fd0710SChristophe Leroy * Better pick an address known to be invalid on your system and assign 247*70fd0710SChristophe Leroy * it to CONFIG_SYS_RESET_ADDRESS. 248907208c4SChristophe Leroy * "(ulong)-1" used to be a good choice for many systems... 249907208c4SChristophe Leroy */ 250907208c4SChristophe Leroy addr = CONFIG_SYS_MONITOR_BASE - sizeof(ulong); 251907208c4SChristophe Leroy #endif 252907208c4SChristophe Leroy ((void (*)(void)) addr)(); 253907208c4SChristophe Leroy return 1; 254907208c4SChristophe Leroy } 255907208c4SChristophe Leroy 256907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 257907208c4SChristophe Leroy 258907208c4SChristophe Leroy /* 259907208c4SChristophe Leroy * Get timebase clock frequency (like cpu_clk in Hz) 260907208c4SChristophe Leroy * 261907208c4SChristophe Leroy * See sections 14.2 and 14.6 of the User's Manual 262907208c4SChristophe Leroy */ 263907208c4SChristophe Leroy unsigned long get_tbclk(void) 264907208c4SChristophe Leroy { 265907208c4SChristophe Leroy uint immr = get_immr(0); /* Return full IMMR contents */ 266ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)(immr & 0xFFFF0000); 267907208c4SChristophe Leroy ulong oscclk, factor, pll; 268907208c4SChristophe Leroy 269ba3da734SChristophe Leroy if (in_be32(&immap->im_clkrst.car_sccr) & SCCR_TBS) 270*70fd0710SChristophe Leroy return gd->cpu_clk / 16; 271907208c4SChristophe Leroy 272ba3da734SChristophe Leroy pll = in_be32(&immap->im_clkrst.car_plprcr); 273907208c4SChristophe Leroy 274907208c4SChristophe Leroy #define PLPRCR_val(a) ((pll & PLPRCR_ ## a ## _MSK) >> PLPRCR_ ## a ## _SHIFT) 275907208c4SChristophe Leroy 276907208c4SChristophe Leroy /* 277907208c4SChristophe Leroy * For newer PQ1 chips (MPC866/87x/88x families), PLL multiplication 278907208c4SChristophe Leroy * factor is calculated as follows: 279907208c4SChristophe Leroy * 280907208c4SChristophe Leroy * MFN 281907208c4SChristophe Leroy * MFI + ------- 282907208c4SChristophe Leroy * MFD + 1 283907208c4SChristophe Leroy * factor = ----------------- 284907208c4SChristophe Leroy * (PDF + 1) * 2^S 285907208c4SChristophe Leroy * 286907208c4SChristophe Leroy */ 287907208c4SChristophe Leroy factor = (PLPRCR_val(MFI) + PLPRCR_val(MFN) / (PLPRCR_val(MFD) + 1)) / 288907208c4SChristophe Leroy (PLPRCR_val(PDF) + 1) / (1 << PLPRCR_val(S)); 289907208c4SChristophe Leroy 290907208c4SChristophe Leroy oscclk = gd->cpu_clk / factor; 291907208c4SChristophe Leroy 292ba3da734SChristophe Leroy if ((in_be32(&immap->im_clkrst.car_sccr) & SCCR_RTSEL) == 0 || 293ba3da734SChristophe Leroy factor > 2) 294*70fd0710SChristophe Leroy return oscclk / 4; 295ba3da734SChristophe Leroy 296*70fd0710SChristophe Leroy return oscclk / 16; 297907208c4SChristophe Leroy } 298907208c4SChristophe Leroy 299907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 300907208c4SChristophe Leroy 301907208c4SChristophe Leroy #if defined(CONFIG_WATCHDOG) 302907208c4SChristophe Leroy void watchdog_reset(void) 303907208c4SChristophe Leroy { 304907208c4SChristophe Leroy int re_enable = disable_interrupts(); 305907208c4SChristophe Leroy 306ba3da734SChristophe Leroy reset_8xx_watchdog((immap_t __iomem *)CONFIG_SYS_IMMR); 307907208c4SChristophe Leroy if (re_enable) 308907208c4SChristophe Leroy enable_interrupts(); 309907208c4SChristophe Leroy } 310907208c4SChristophe Leroy #endif /* CONFIG_WATCHDOG */ 311907208c4SChristophe Leroy 312907208c4SChristophe Leroy #if defined(CONFIG_WATCHDOG) 313907208c4SChristophe Leroy 314ba3da734SChristophe Leroy void reset_8xx_watchdog(immap_t __iomem *immr) 315907208c4SChristophe Leroy { 316907208c4SChristophe Leroy /* 317907208c4SChristophe Leroy * All other boards use the MPC8xx Internal Watchdog 318907208c4SChristophe Leroy */ 319ba3da734SChristophe Leroy out_be16(&immr->im_siu_conf.sc_swsr, 0x556c); /* write magic1 */ 320ba3da734SChristophe Leroy out_be16(&immr->im_siu_conf.sc_swsr, 0xaa39); /* write magic2 */ 321907208c4SChristophe Leroy } 322907208c4SChristophe Leroy #endif /* CONFIG_WATCHDOG */ 323907208c4SChristophe Leroy 324907208c4SChristophe Leroy /* 325907208c4SChristophe Leroy * Initializes on-chip ethernet controllers. 326907208c4SChristophe Leroy * to override, implement board_eth_init() 327907208c4SChristophe Leroy */ 328907208c4SChristophe Leroy int cpu_eth_init(bd_t *bis) 329907208c4SChristophe Leroy { 330907208c4SChristophe Leroy #if defined(FEC_ENET) 331907208c4SChristophe Leroy fec_initialize(bis); 332907208c4SChristophe Leroy #endif 333907208c4SChristophe Leroy return 0; 334907208c4SChristophe Leroy } 335