1 /* 2 * Copyright 2007-2009 Freescale Semiconductor, Inc. 3 * 4 * (C) Copyright 2000 5 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 6 * 7 * See file CREDITS for list of people who contributed to this 8 * project. 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License as 12 * published by the Free Software Foundation; either version 2 of 13 * the License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 23 * MA 02111-1307 USA 24 */ 25 26 #include <common.h> 27 #include <libfdt.h> 28 #include <fdt_support.h> 29 #include <asm/processor.h> 30 #include <linux/ctype.h> 31 #ifdef CONFIG_FSL_ESDHC 32 #include <fsl_esdhc.h> 33 #endif 34 35 DECLARE_GLOBAL_DATA_PTR; 36 37 extern void ft_qe_setup(void *blob); 38 extern void ft_fixup_num_cores(void *blob); 39 40 #ifdef CONFIG_MP 41 #include "mp.h" 42 43 void ft_fixup_cpu(void *blob, u64 memory_limit) 44 { 45 int off; 46 ulong spin_tbl_addr = get_spin_phys_addr(); 47 u32 bootpg = determine_mp_bootpg(); 48 u32 id = get_my_id(); 49 50 off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); 51 while (off != -FDT_ERR_NOTFOUND) { 52 u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0); 53 54 if (reg) { 55 if (*reg == id) { 56 fdt_setprop_string(blob, off, "status", "okay"); 57 } else { 58 u64 val = *reg * SIZE_BOOT_ENTRY + spin_tbl_addr; 59 val = cpu_to_fdt32(val); 60 fdt_setprop_string(blob, off, "status", 61 "disabled"); 62 fdt_setprop_string(blob, off, "enable-method", 63 "spin-table"); 64 fdt_setprop(blob, off, "cpu-release-addr", 65 &val, sizeof(val)); 66 } 67 } else { 68 printf ("cpu NULL\n"); 69 } 70 off = fdt_node_offset_by_prop_value(blob, off, 71 "device_type", "cpu", 4); 72 } 73 74 /* Reserve the boot page so OSes dont use it */ 75 if ((u64)bootpg < memory_limit) { 76 off = fdt_add_mem_rsv(blob, bootpg, (u64)4096); 77 if (off < 0) 78 printf("%s: %s\n", __FUNCTION__, fdt_strerror(off)); 79 } 80 } 81 #endif 82 83 #define ft_fixup_l3cache(x, y) 84 85 #if defined(CONFIG_L2_CACHE) 86 /* return size in kilobytes */ 87 static inline u32 l2cache_size(void) 88 { 89 volatile ccsr_l2cache_t *l2cache = (void *)CONFIG_SYS_MPC85xx_L2_ADDR; 90 volatile u32 l2siz_field = (l2cache->l2ctl >> 28) & 0x3; 91 u32 ver = SVR_SOC_VER(get_svr()); 92 93 switch (l2siz_field) { 94 case 0x0: 95 break; 96 case 0x1: 97 if (ver == SVR_8540 || ver == SVR_8560 || 98 ver == SVR_8541 || ver == SVR_8541_E || 99 ver == SVR_8555 || ver == SVR_8555_E) 100 return 128; 101 else 102 return 256; 103 break; 104 case 0x2: 105 if (ver == SVR_8540 || ver == SVR_8560 || 106 ver == SVR_8541 || ver == SVR_8541_E || 107 ver == SVR_8555 || ver == SVR_8555_E) 108 return 256; 109 else 110 return 512; 111 break; 112 case 0x3: 113 return 1024; 114 break; 115 } 116 117 return 0; 118 } 119 120 static inline void ft_fixup_l2cache(void *blob) 121 { 122 int len, off; 123 u32 *ph; 124 struct cpu_type *cpu = identify_cpu(SVR_SOC_VER(get_svr())); 125 char compat_buf[38]; 126 127 const u32 line_size = 32; 128 const u32 num_ways = 8; 129 const u32 size = l2cache_size() * 1024; 130 const u32 num_sets = size / (line_size * num_ways); 131 132 off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); 133 if (off < 0) { 134 debug("no cpu node fount\n"); 135 return; 136 } 137 138 ph = (u32 *)fdt_getprop(blob, off, "next-level-cache", 0); 139 140 if (ph == NULL) { 141 debug("no next-level-cache property\n"); 142 return ; 143 } 144 145 off = fdt_node_offset_by_phandle(blob, *ph); 146 if (off < 0) { 147 printf("%s: %s\n", __func__, fdt_strerror(off)); 148 return ; 149 } 150 151 if (cpu) { 152 if (isdigit(cpu->name[0])) 153 len = sprintf(compat_buf, 154 "fsl,mpc%s-l2-cache-controller", cpu->name); 155 else 156 len = sprintf(compat_buf, 157 "fsl,%c%s-l2-cache-controller", 158 tolower(cpu->name[0]), cpu->name + 1); 159 160 sprintf(&compat_buf[len + 1], "cache"); 161 } 162 fdt_setprop(blob, off, "cache-unified", NULL, 0); 163 fdt_setprop_cell(blob, off, "cache-block-size", line_size); 164 fdt_setprop_cell(blob, off, "cache-size", size); 165 fdt_setprop_cell(blob, off, "cache-sets", num_sets); 166 fdt_setprop_cell(blob, off, "cache-level", 2); 167 fdt_setprop(blob, off, "compatible", compat_buf, sizeof(compat_buf)); 168 169 /* we dont bother w/L3 since no platform of this type has one */ 170 } 171 #elif defined(CONFIG_BACKSIDE_L2_CACHE) 172 static inline void ft_fixup_l2cache(void *blob) 173 { 174 int off, l2_off, l3_off = -1; 175 u32 *ph; 176 u32 l2cfg0 = mfspr(SPRN_L2CFG0); 177 u32 size, line_size, num_ways, num_sets; 178 179 size = (l2cfg0 & 0x3fff) * 64 * 1024; 180 num_ways = ((l2cfg0 >> 14) & 0x1f) + 1; 181 line_size = (((l2cfg0 >> 23) & 0x3) + 1) * 32; 182 num_sets = size / (line_size * num_ways); 183 184 off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); 185 186 while (off != -FDT_ERR_NOTFOUND) { 187 ph = (u32 *)fdt_getprop(blob, off, "next-level-cache", 0); 188 189 if (ph == NULL) { 190 debug("no next-level-cache property\n"); 191 goto next; 192 } 193 194 l2_off = fdt_node_offset_by_phandle(blob, *ph); 195 if (l2_off < 0) { 196 printf("%s: %s\n", __func__, fdt_strerror(off)); 197 goto next; 198 } 199 200 #ifdef CONFIG_SYS_CACHE_STASHING 201 { 202 u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0); 203 if (reg) 204 fdt_setprop_cell(blob, l2_off, "cache-stash-id", 205 (*reg * 2) + 32 + 1); 206 } 207 #endif 208 209 fdt_setprop(blob, l2_off, "cache-unified", NULL, 0); 210 fdt_setprop_cell(blob, l2_off, "cache-block-size", line_size); 211 fdt_setprop_cell(blob, l2_off, "cache-size", size); 212 fdt_setprop_cell(blob, l2_off, "cache-sets", num_sets); 213 fdt_setprop_cell(blob, l2_off, "cache-level", 2); 214 fdt_setprop(blob, l2_off, "compatible", "cache", 6); 215 216 if (l3_off < 0) { 217 ph = (u32 *)fdt_getprop(blob, l2_off, "next-level-cache", 0); 218 219 if (ph == NULL) { 220 debug("no next-level-cache property\n"); 221 goto next; 222 } 223 l3_off = *ph; 224 } 225 next: 226 off = fdt_node_offset_by_prop_value(blob, off, 227 "device_type", "cpu", 4); 228 } 229 if (l3_off > 0) { 230 l3_off = fdt_node_offset_by_phandle(blob, l3_off); 231 if (l3_off < 0) { 232 printf("%s: %s\n", __func__, fdt_strerror(off)); 233 return ; 234 } 235 ft_fixup_l3cache(blob, l3_off); 236 } 237 } 238 #else 239 #define ft_fixup_l2cache(x) 240 #endif 241 242 static inline void ft_fixup_cache(void *blob) 243 { 244 int off; 245 246 off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); 247 248 while (off != -FDT_ERR_NOTFOUND) { 249 u32 l1cfg0 = mfspr(SPRN_L1CFG0); 250 u32 l1cfg1 = mfspr(SPRN_L1CFG1); 251 u32 isize, iline_size, inum_sets, inum_ways; 252 u32 dsize, dline_size, dnum_sets, dnum_ways; 253 254 /* d-side config */ 255 dsize = (l1cfg0 & 0x7ff) * 1024; 256 dnum_ways = ((l1cfg0 >> 11) & 0xff) + 1; 257 dline_size = (((l1cfg0 >> 23) & 0x3) + 1) * 32; 258 dnum_sets = dsize / (dline_size * dnum_ways); 259 260 fdt_setprop_cell(blob, off, "d-cache-block-size", dline_size); 261 fdt_setprop_cell(blob, off, "d-cache-size", dsize); 262 fdt_setprop_cell(blob, off, "d-cache-sets", dnum_sets); 263 264 #ifdef CONFIG_SYS_CACHE_STASHING 265 { 266 u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0); 267 if (reg) 268 fdt_setprop_cell(blob, off, "cache-stash-id", 269 (*reg * 2) + 32 + 0); 270 } 271 #endif 272 273 /* i-side config */ 274 isize = (l1cfg1 & 0x7ff) * 1024; 275 inum_ways = ((l1cfg1 >> 11) & 0xff) + 1; 276 iline_size = (((l1cfg1 >> 23) & 0x3) + 1) * 32; 277 inum_sets = isize / (iline_size * inum_ways); 278 279 fdt_setprop_cell(blob, off, "i-cache-block-size", iline_size); 280 fdt_setprop_cell(blob, off, "i-cache-size", isize); 281 fdt_setprop_cell(blob, off, "i-cache-sets", inum_sets); 282 283 off = fdt_node_offset_by_prop_value(blob, off, 284 "device_type", "cpu", 4); 285 } 286 287 ft_fixup_l2cache(blob); 288 } 289 290 291 void fdt_add_enet_stashing(void *fdt) 292 { 293 do_fixup_by_compat(fdt, "gianfar", "bd-stash", NULL, 0, 1); 294 295 do_fixup_by_compat_u32(fdt, "gianfar", "rx-stash-len", 96, 1); 296 297 do_fixup_by_compat_u32(fdt, "gianfar", "rx-stash-idx", 0, 1); 298 } 299 300 #if defined(CONFIG_SYS_DPAA_FMAN) || defined(CONFIG_SYS_DPAA_PME) 301 static void ft_fixup_clks(void *blob, const char *alias, unsigned long freq) 302 { 303 const char *path = fdt_get_alias(blob, alias); 304 305 int off = fdt_path_offset(blob, path); 306 307 if (off >= 0) { 308 off = fdt_setprop_cell(blob, off, "clock-frequency", freq); 309 if (off > 0) 310 printf("WARNING enable to set clock-frequency " 311 "for %s: %s\n", alias, fdt_strerror(off)); 312 } 313 } 314 315 static void ft_fixup_dpaa_clks(void *blob) 316 { 317 sys_info_t sysinfo; 318 319 get_sys_info(&sysinfo); 320 ft_fixup_clks(blob, "fman0", sysinfo.freqFMan[0]); 321 322 #if (CONFIG_SYS_NUM_FMAN == 2) 323 ft_fixup_clks(blob, "fman1", sysinfo.freqFMan[1]); 324 #endif 325 326 #ifdef CONFIG_SYS_DPAA_PME 327 ft_fixup_clks(blob, "pme", sysinfo.freqPME); 328 #endif 329 } 330 #else 331 #define ft_fixup_dpaa_clks(x) 332 #endif 333 334 #ifdef CONFIG_QE 335 static void ft_fixup_qe_snum(void *blob) 336 { 337 unsigned int svr; 338 339 svr = mfspr(SPRN_SVR); 340 if (SVR_SOC_VER(svr) == SVR_8569_E) { 341 if(IS_SVR_REV(svr, 1, 0)) 342 do_fixup_by_compat_u32(blob, "fsl,qe", 343 "fsl,qe-num-snums", 46, 1); 344 else 345 do_fixup_by_compat_u32(blob, "fsl,qe", 346 "fsl,qe-num-snums", 76, 1); 347 } 348 } 349 #endif 350 351 void ft_cpu_setup(void *blob, bd_t *bd) 352 { 353 int off; 354 int val; 355 sys_info_t sysinfo; 356 357 /* delete crypto node if not on an E-processor */ 358 if (!IS_E_PROCESSOR(get_svr())) 359 fdt_fixup_crypto_node(blob, 0); 360 361 fdt_fixup_ethernet(blob); 362 363 fdt_add_enet_stashing(blob); 364 365 do_fixup_by_prop_u32(blob, "device_type", "cpu", 4, 366 "timebase-frequency", get_tbclk(), 1); 367 do_fixup_by_prop_u32(blob, "device_type", "cpu", 4, 368 "bus-frequency", bd->bi_busfreq, 1); 369 get_sys_info(&sysinfo); 370 off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); 371 while (off != -FDT_ERR_NOTFOUND) { 372 u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0); 373 val = cpu_to_fdt32(sysinfo.freqProcessor[*reg]); 374 fdt_setprop(blob, off, "clock-frequency", &val, 4); 375 off = fdt_node_offset_by_prop_value(blob, off, "device_type", 376 "cpu", 4); 377 } 378 do_fixup_by_prop_u32(blob, "device_type", "soc", 4, 379 "bus-frequency", bd->bi_busfreq, 1); 380 381 do_fixup_by_compat_u32(blob, "fsl,pq3-localbus", 382 "bus-frequency", gd->lbc_clk, 1); 383 do_fixup_by_compat_u32(blob, "fsl,elbc", 384 "bus-frequency", gd->lbc_clk, 1); 385 #ifdef CONFIG_QE 386 ft_qe_setup(blob); 387 ft_fixup_qe_snum(blob); 388 #endif 389 390 #ifdef CONFIG_SYS_NS16550 391 do_fixup_by_compat_u32(blob, "ns16550", 392 "clock-frequency", CONFIG_SYS_NS16550_CLK, 1); 393 #endif 394 395 #ifdef CONFIG_CPM2 396 do_fixup_by_compat_u32(blob, "fsl,cpm2-scc-uart", 397 "current-speed", bd->bi_baudrate, 1); 398 399 do_fixup_by_compat_u32(blob, "fsl,cpm2-brg", 400 "clock-frequency", bd->bi_brgfreq, 1); 401 #endif 402 403 fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize); 404 405 #ifdef CONFIG_MP 406 ft_fixup_cpu(blob, (u64)bd->bi_memstart + (u64)bd->bi_memsize); 407 #endif 408 ft_fixup_num_cores(blob); 409 410 ft_fixup_cache(blob); 411 412 #if defined(CONFIG_FSL_ESDHC) 413 fdt_fixup_esdhc(blob, bd); 414 #endif 415 416 ft_fixup_dpaa_clks(blob); 417 } 418