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) 31*0e00a84cSMasahiro Yamada #include <linux/libfdt.h> 32907208c4SChristophe Leroy #include <fdt_support.h> 33907208c4SChristophe Leroy #endif 34907208c4SChristophe Leroy 35907208c4SChristophe Leroy DECLARE_GLOBAL_DATA_PTR; 36907208c4SChristophe Leroy 37907208c4SChristophe Leroy static int check_CPU(long clock, uint pvr, uint immr) 38907208c4SChristophe Leroy { 39ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)(immr & 0xFFFF0000); 4036d32607SChristophe Leroy uint k; 41907208c4SChristophe Leroy char buf[32]; 42907208c4SChristophe Leroy 43907208c4SChristophe Leroy /* the highest 16 bits should be 0x0050 for a 860 */ 44907208c4SChristophe Leroy 45907208c4SChristophe Leroy if ((pvr >> 16) != 0x0050) 46907208c4SChristophe Leroy return -1; 47907208c4SChristophe Leroy 48907208c4SChristophe Leroy k = (immr << 16) | 49ba3da734SChristophe Leroy in_be16(&immap->im_cpm.cp_dparam16[PROFF_REVNUM / sizeof(u16)]); 50907208c4SChristophe Leroy 51907208c4SChristophe Leroy /* 52907208c4SChristophe Leroy * Some boards use sockets so different CPUs can be used. 53907208c4SChristophe Leroy * We have to check chip version in run time. 54907208c4SChristophe Leroy */ 55907208c4SChristophe Leroy switch (k) { 56907208c4SChristophe Leroy /* MPC866P/MPC866T/MPC859T/MPC859DSL/MPC852T */ 57907208c4SChristophe Leroy case 0x08010004: /* Rev. A.0 */ 5836d32607SChristophe Leroy printf("MPC866xxxZPnnA"); 59907208c4SChristophe Leroy break; 6036d32607SChristophe Leroy case 0x08000003: /* Rev. 0.3 */ 6136d32607SChristophe Leroy printf("MPC866xxxZPnn"); 6236d32607SChristophe Leroy break; 6336d32607SChristophe Leroy case 0x09000000: /* 870/875/880/885 */ 6436d32607SChristophe Leroy puts("MPC885ZPnn"); 65907208c4SChristophe Leroy break; 66907208c4SChristophe Leroy 6770fd0710SChristophe Leroy default: 6836d32607SChristophe Leroy printf("unknown MPC86x (0x%08x)", k); 6970fd0710SChristophe Leroy break; 70907208c4SChristophe Leroy } 71907208c4SChristophe Leroy 72907208c4SChristophe Leroy printf(" at %s MHz: ", strmhz(buf, clock)); 73907208c4SChristophe Leroy 74907208c4SChristophe Leroy print_size(checkicache(), " I-Cache "); 75907208c4SChristophe Leroy print_size(checkdcache(), " D-Cache"); 76907208c4SChristophe Leroy 77907208c4SChristophe Leroy /* do we have a FEC (860T/P or 852/859/866/885)? */ 78907208c4SChristophe Leroy 79ba3da734SChristophe Leroy out_be32(&immap->im_cpm.cp_fec.fec_addr_low, 0x12345678); 80ba3da734SChristophe Leroy if (in_be32(&immap->im_cpm.cp_fec.fec_addr_low) == 0x12345678) 81907208c4SChristophe Leroy printf(" FEC present"); 82907208c4SChristophe Leroy 83907208c4SChristophe Leroy putc('\n'); 84907208c4SChristophe Leroy 85907208c4SChristophe Leroy return 0; 86907208c4SChristophe Leroy } 87907208c4SChristophe Leroy 88907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 89907208c4SChristophe Leroy 90907208c4SChristophe Leroy int checkcpu(void) 91907208c4SChristophe Leroy { 92907208c4SChristophe Leroy ulong clock = gd->cpu_clk; 93907208c4SChristophe Leroy uint immr = get_immr(0); /* Return full IMMR contents */ 94907208c4SChristophe Leroy uint pvr = get_pvr(); 95907208c4SChristophe Leroy 96907208c4SChristophe Leroy puts("CPU: "); 97907208c4SChristophe Leroy 98907208c4SChristophe Leroy return check_CPU(clock, pvr, immr); 99907208c4SChristophe Leroy } 100907208c4SChristophe Leroy 101907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 102907208c4SChristophe Leroy /* L1 i-cache */ 103907208c4SChristophe Leroy 104907208c4SChristophe Leroy int checkicache(void) 105907208c4SChristophe Leroy { 106ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; 107ba3da734SChristophe Leroy memctl8xx_t __iomem *memctl = &immap->im_memctl; 108907208c4SChristophe Leroy u32 cacheon = rd_ic_cst() & IDC_ENABLED; 109ba3da734SChristophe Leroy /* probe in flash memoryarea */ 110ba3da734SChristophe Leroy u32 k = in_be32(&memctl->memc_br0) & ~0x00007fff; 111907208c4SChristophe Leroy u32 m; 112907208c4SChristophe Leroy u32 lines = -1; 113907208c4SChristophe Leroy 114907208c4SChristophe Leroy wr_ic_cst(IDC_UNALL); 115907208c4SChristophe Leroy wr_ic_cst(IDC_INVALL); 116907208c4SChristophe Leroy wr_ic_cst(IDC_DISABLE); 117907208c4SChristophe Leroy __asm__ volatile ("isync"); 118907208c4SChristophe Leroy 119907208c4SChristophe Leroy while (!((m = rd_ic_cst()) & IDC_CERR2)) { 120907208c4SChristophe Leroy wr_ic_adr(k); 121907208c4SChristophe Leroy wr_ic_cst(IDC_LDLCK); 122907208c4SChristophe Leroy __asm__ volatile ("isync"); 123907208c4SChristophe Leroy 124907208c4SChristophe Leroy lines++; 125907208c4SChristophe Leroy k += 0x10; /* the number of bytes in a cacheline */ 126907208c4SChristophe Leroy } 127907208c4SChristophe Leroy 128907208c4SChristophe Leroy wr_ic_cst(IDC_UNALL); 129907208c4SChristophe Leroy wr_ic_cst(IDC_INVALL); 130907208c4SChristophe Leroy 131907208c4SChristophe Leroy if (cacheon) 132907208c4SChristophe Leroy wr_ic_cst(IDC_ENABLE); 133907208c4SChristophe Leroy else 134907208c4SChristophe Leroy wr_ic_cst(IDC_DISABLE); 135907208c4SChristophe Leroy 136907208c4SChristophe Leroy __asm__ volatile ("isync"); 137907208c4SChristophe Leroy 138907208c4SChristophe Leroy return lines << 4; 139907208c4SChristophe Leroy }; 140907208c4SChristophe Leroy 141907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 142907208c4SChristophe Leroy /* L1 d-cache */ 143907208c4SChristophe Leroy /* call with cache disabled */ 144907208c4SChristophe Leroy 145907208c4SChristophe Leroy int checkdcache(void) 146907208c4SChristophe Leroy { 147ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; 148ba3da734SChristophe Leroy memctl8xx_t __iomem *memctl = &immap->im_memctl; 149907208c4SChristophe Leroy u32 cacheon = rd_dc_cst() & IDC_ENABLED; 150ba3da734SChristophe Leroy /* probe in flash memoryarea */ 151ba3da734SChristophe Leroy u32 k = in_be32(&memctl->memc_br0) & ~0x00007fff; 152907208c4SChristophe Leroy u32 m; 153907208c4SChristophe Leroy u32 lines = -1; 154907208c4SChristophe Leroy 155907208c4SChristophe Leroy wr_dc_cst(IDC_UNALL); 156907208c4SChristophe Leroy wr_dc_cst(IDC_INVALL); 157907208c4SChristophe Leroy wr_dc_cst(IDC_DISABLE); 158907208c4SChristophe Leroy 159907208c4SChristophe Leroy while (!((m = rd_dc_cst()) & IDC_CERR2)) { 160907208c4SChristophe Leroy wr_dc_adr(k); 161907208c4SChristophe Leroy wr_dc_cst(IDC_LDLCK); 162907208c4SChristophe Leroy lines++; 163907208c4SChristophe Leroy k += 0x10; /* the number of bytes in a cacheline */ 164907208c4SChristophe Leroy } 165907208c4SChristophe Leroy 166907208c4SChristophe Leroy wr_dc_cst(IDC_UNALL); 167907208c4SChristophe Leroy wr_dc_cst(IDC_INVALL); 168907208c4SChristophe Leroy 169907208c4SChristophe Leroy if (cacheon) 170907208c4SChristophe Leroy wr_dc_cst(IDC_ENABLE); 171907208c4SChristophe Leroy else 172907208c4SChristophe Leroy wr_dc_cst(IDC_DISABLE); 173907208c4SChristophe Leroy 174907208c4SChristophe Leroy return lines << 4; 175907208c4SChristophe Leroy }; 176907208c4SChristophe Leroy 177907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 178907208c4SChristophe Leroy 179907208c4SChristophe Leroy void upmconfig(uint upm, uint *table, uint size) 180907208c4SChristophe Leroy { 181907208c4SChristophe Leroy uint i; 182907208c4SChristophe Leroy uint addr = 0; 183ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; 184ba3da734SChristophe Leroy memctl8xx_t __iomem *memctl = &immap->im_memctl; 185907208c4SChristophe Leroy 186907208c4SChristophe Leroy for (i = 0; i < size; i++) { 187ba3da734SChristophe Leroy out_be32(&memctl->memc_mdr, table[i]); /* (16-15) */ 188ba3da734SChristophe Leroy out_be32(&memctl->memc_mcr, addr | upm); /* (16-16) */ 189907208c4SChristophe Leroy addr++; 190907208c4SChristophe Leroy } 191907208c4SChristophe Leroy } 192907208c4SChristophe Leroy 193907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 194907208c4SChristophe Leroy 195907208c4SChristophe Leroy int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 196907208c4SChristophe Leroy { 197907208c4SChristophe Leroy ulong msr, addr; 198907208c4SChristophe Leroy 199ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; 200907208c4SChristophe Leroy 201ba3da734SChristophe Leroy /* Checkstop Reset enable */ 202ba3da734SChristophe Leroy setbits_be32(&immap->im_clkrst.car_plprcr, PLPRCR_CSR); 203907208c4SChristophe Leroy 204907208c4SChristophe Leroy /* Interrupts and MMU off */ 205907208c4SChristophe Leroy __asm__ volatile ("mtspr 81, 0"); 206907208c4SChristophe Leroy __asm__ volatile ("mfmsr %0" : "=r" (msr)); 207907208c4SChristophe Leroy 208907208c4SChristophe Leroy msr &= ~0x1030; 209907208c4SChristophe Leroy __asm__ volatile ("mtmsr %0" : : "r" (msr)); 210907208c4SChristophe Leroy 211907208c4SChristophe Leroy /* 212907208c4SChristophe Leroy * Trying to execute the next instruction at a non-existing address 213907208c4SChristophe Leroy * should cause a machine check, resulting in reset 214907208c4SChristophe Leroy */ 215907208c4SChristophe Leroy #ifdef CONFIG_SYS_RESET_ADDRESS 216907208c4SChristophe Leroy addr = CONFIG_SYS_RESET_ADDRESS; 217907208c4SChristophe Leroy #else 218907208c4SChristophe Leroy /* 21970fd0710SChristophe Leroy * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address, 22070fd0710SChristophe Leroy * CONFIG_SYS_MONITOR_BASE - sizeof (ulong) is usually a valid address. 22170fd0710SChristophe Leroy * Better pick an address known to be invalid on your system and assign 22270fd0710SChristophe Leroy * it to CONFIG_SYS_RESET_ADDRESS. 223907208c4SChristophe Leroy * "(ulong)-1" used to be a good choice for many systems... 224907208c4SChristophe Leroy */ 225907208c4SChristophe Leroy addr = CONFIG_SYS_MONITOR_BASE - sizeof(ulong); 226907208c4SChristophe Leroy #endif 227907208c4SChristophe Leroy ((void (*)(void)) addr)(); 228907208c4SChristophe Leroy return 1; 229907208c4SChristophe Leroy } 230907208c4SChristophe Leroy 231907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 232907208c4SChristophe Leroy 233907208c4SChristophe Leroy /* 234907208c4SChristophe Leroy * Get timebase clock frequency (like cpu_clk in Hz) 235907208c4SChristophe Leroy * 236907208c4SChristophe Leroy * See sections 14.2 and 14.6 of the User's Manual 237907208c4SChristophe Leroy */ 238907208c4SChristophe Leroy unsigned long get_tbclk(void) 239907208c4SChristophe Leroy { 240907208c4SChristophe Leroy uint immr = get_immr(0); /* Return full IMMR contents */ 241ba3da734SChristophe Leroy immap_t __iomem *immap = (immap_t __iomem *)(immr & 0xFFFF0000); 242907208c4SChristophe Leroy ulong oscclk, factor, pll; 243907208c4SChristophe Leroy 244ba3da734SChristophe Leroy if (in_be32(&immap->im_clkrst.car_sccr) & SCCR_TBS) 24570fd0710SChristophe Leroy return gd->cpu_clk / 16; 246907208c4SChristophe Leroy 247ba3da734SChristophe Leroy pll = in_be32(&immap->im_clkrst.car_plprcr); 248907208c4SChristophe Leroy 249907208c4SChristophe Leroy #define PLPRCR_val(a) ((pll & PLPRCR_ ## a ## _MSK) >> PLPRCR_ ## a ## _SHIFT) 250907208c4SChristophe Leroy 251907208c4SChristophe Leroy /* 252907208c4SChristophe Leroy * For newer PQ1 chips (MPC866/87x/88x families), PLL multiplication 253907208c4SChristophe Leroy * factor is calculated as follows: 254907208c4SChristophe Leroy * 255907208c4SChristophe Leroy * MFN 256907208c4SChristophe Leroy * MFI + ------- 257907208c4SChristophe Leroy * MFD + 1 258907208c4SChristophe Leroy * factor = ----------------- 259907208c4SChristophe Leroy * (PDF + 1) * 2^S 260907208c4SChristophe Leroy * 261907208c4SChristophe Leroy */ 262907208c4SChristophe Leroy factor = (PLPRCR_val(MFI) + PLPRCR_val(MFN) / (PLPRCR_val(MFD) + 1)) / 263907208c4SChristophe Leroy (PLPRCR_val(PDF) + 1) / (1 << PLPRCR_val(S)); 264907208c4SChristophe Leroy 265907208c4SChristophe Leroy oscclk = gd->cpu_clk / factor; 266907208c4SChristophe Leroy 267ba3da734SChristophe Leroy if ((in_be32(&immap->im_clkrst.car_sccr) & SCCR_RTSEL) == 0 || 268ba3da734SChristophe Leroy factor > 2) 26970fd0710SChristophe Leroy return oscclk / 4; 270ba3da734SChristophe Leroy 27170fd0710SChristophe Leroy return oscclk / 16; 272907208c4SChristophe Leroy } 273907208c4SChristophe Leroy 274907208c4SChristophe Leroy /* ------------------------------------------------------------------------- */ 275907208c4SChristophe Leroy 276907208c4SChristophe Leroy #if defined(CONFIG_WATCHDOG) 277907208c4SChristophe Leroy void watchdog_reset(void) 278907208c4SChristophe Leroy { 279907208c4SChristophe Leroy int re_enable = disable_interrupts(); 280907208c4SChristophe Leroy 281ba3da734SChristophe Leroy reset_8xx_watchdog((immap_t __iomem *)CONFIG_SYS_IMMR); 282907208c4SChristophe Leroy if (re_enable) 283907208c4SChristophe Leroy enable_interrupts(); 284907208c4SChristophe Leroy } 285907208c4SChristophe Leroy #endif /* CONFIG_WATCHDOG */ 286907208c4SChristophe Leroy 287907208c4SChristophe Leroy #if defined(CONFIG_WATCHDOG) 288907208c4SChristophe Leroy 289ba3da734SChristophe Leroy void reset_8xx_watchdog(immap_t __iomem *immr) 290907208c4SChristophe Leroy { 291907208c4SChristophe Leroy /* 292907208c4SChristophe Leroy * All other boards use the MPC8xx Internal Watchdog 293907208c4SChristophe Leroy */ 294ba3da734SChristophe Leroy out_be16(&immr->im_siu_conf.sc_swsr, 0x556c); /* write magic1 */ 295ba3da734SChristophe Leroy out_be16(&immr->im_siu_conf.sc_swsr, 0xaa39); /* write magic2 */ 296907208c4SChristophe Leroy } 297907208c4SChristophe Leroy #endif /* CONFIG_WATCHDOG */ 298907208c4SChristophe Leroy 299907208c4SChristophe Leroy /* 300907208c4SChristophe Leroy * Initializes on-chip ethernet controllers. 301907208c4SChristophe Leroy * to override, implement board_eth_init() 302907208c4SChristophe Leroy */ 303907208c4SChristophe Leroy int cpu_eth_init(bd_t *bis) 304907208c4SChristophe Leroy { 305fad51ac3SChristophe Leroy #if defined(CONFIG_MPC8XX_FEC) 306907208c4SChristophe Leroy fec_initialize(bis); 307907208c4SChristophe Leroy #endif 308907208c4SChristophe Leroy return 0; 309907208c4SChristophe Leroy } 310