1/* 2 * Port on Texas Instruments TMS320C6x architecture 3 * 4 * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated 5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11#include <linux/dma-mapping.h> 12#include <linux/memblock.h> 13#include <linux/seq_file.h> 14#include <linux/bootmem.h> 15#include <linux/clkdev.h> 16#include <linux/initrd.h> 17#include <linux/kernel.h> 18#include <linux/module.h> 19#include <linux/of_fdt.h> 20#include <linux/string.h> 21#include <linux/errno.h> 22#include <linux/cache.h> 23#include <linux/delay.h> 24#include <linux/sched.h> 25#include <linux/clk.h> 26#include <linux/cpu.h> 27#include <linux/fs.h> 28#include <linux/of.h> 29 30 31#include <asm/sections.h> 32#include <asm/div64.h> 33#include <asm/setup.h> 34#include <asm/dscr.h> 35#include <asm/clock.h> 36#include <asm/soc.h> 37#include <asm/special_insns.h> 38 39static const char *c6x_soc_name; 40 41int c6x_num_cores; 42EXPORT_SYMBOL_GPL(c6x_num_cores); 43 44unsigned int c6x_silicon_rev; 45EXPORT_SYMBOL_GPL(c6x_silicon_rev); 46 47/* 48 * Device status register. This holds information 49 * about device configuration needed by some drivers. 50 */ 51unsigned int c6x_devstat; 52EXPORT_SYMBOL_GPL(c6x_devstat); 53 54/* 55 * Some SoCs have fuse registers holding a unique MAC 56 * address. This is parsed out of the device tree with 57 * the resulting MAC being held here. 58 */ 59unsigned char c6x_fuse_mac[6]; 60 61unsigned long memory_start; 62unsigned long memory_end; 63 64unsigned long ram_start; 65unsigned long ram_end; 66 67/* Uncached memory for DMA consistent use (memdma=) */ 68static unsigned long dma_start __initdata; 69static unsigned long dma_size __initdata; 70 71struct cpuinfo_c6x { 72 const char *cpu_name; 73 const char *cpu_voltage; 74 const char *mmu; 75 const char *fpu; 76 char *cpu_rev; 77 unsigned int core_id; 78 char __cpu_rev[5]; 79}; 80 81static DEFINE_PER_CPU(struct cpuinfo_c6x, cpu_data); 82 83unsigned int ticks_per_ns_scaled; 84EXPORT_SYMBOL(ticks_per_ns_scaled); 85 86unsigned int c6x_core_freq; 87 88static void __init get_cpuinfo(void) 89{ 90 unsigned cpu_id, rev_id, csr; 91 struct clk *coreclk = clk_get_sys(NULL, "core"); 92 unsigned long core_khz; 93 u64 tmp; 94 struct cpuinfo_c6x *p; 95 struct device_node *node, *np; 96 97 p = &per_cpu(cpu_data, smp_processor_id()); 98 99 if (!IS_ERR(coreclk)) 100 c6x_core_freq = clk_get_rate(coreclk); 101 else { 102 printk(KERN_WARNING 103 "Cannot find core clock frequency. Using 700MHz\n"); 104 c6x_core_freq = 700000000; 105 } 106 107 core_khz = c6x_core_freq / 1000; 108 109 tmp = (uint64_t)core_khz << C6X_NDELAY_SCALE; 110 do_div(tmp, 1000000); 111 ticks_per_ns_scaled = tmp; 112 113 csr = get_creg(CSR); 114 cpu_id = csr >> 24; 115 rev_id = (csr >> 16) & 0xff; 116 117 p->mmu = "none"; 118 p->fpu = "none"; 119 p->cpu_voltage = "unknown"; 120 121 switch (cpu_id) { 122 case 0: 123 p->cpu_name = "C67x"; 124 p->fpu = "yes"; 125 break; 126 case 2: 127 p->cpu_name = "C62x"; 128 break; 129 case 8: 130 p->cpu_name = "C64x"; 131 break; 132 case 12: 133 p->cpu_name = "C64x"; 134 break; 135 case 16: 136 p->cpu_name = "C64x+"; 137 p->cpu_voltage = "1.2"; 138 break; 139 case 21: 140 p->cpu_name = "C66X"; 141 p->cpu_voltage = "1.2"; 142 break; 143 default: 144 p->cpu_name = "unknown"; 145 break; 146 } 147 148 if (cpu_id < 16) { 149 switch (rev_id) { 150 case 0x1: 151 if (cpu_id > 8) { 152 p->cpu_rev = "DM640/DM641/DM642/DM643"; 153 p->cpu_voltage = "1.2 - 1.4"; 154 } else { 155 p->cpu_rev = "C6201"; 156 p->cpu_voltage = "2.5"; 157 } 158 break; 159 case 0x2: 160 p->cpu_rev = "C6201B/C6202/C6211"; 161 p->cpu_voltage = "1.8"; 162 break; 163 case 0x3: 164 p->cpu_rev = "C6202B/C6203/C6204/C6205"; 165 p->cpu_voltage = "1.5"; 166 break; 167 case 0x201: 168 p->cpu_rev = "C6701 revision 0 (early CPU)"; 169 p->cpu_voltage = "1.8"; 170 break; 171 case 0x202: 172 p->cpu_rev = "C6701/C6711/C6712"; 173 p->cpu_voltage = "1.8"; 174 break; 175 case 0x801: 176 p->cpu_rev = "C64x"; 177 p->cpu_voltage = "1.5"; 178 break; 179 default: 180 p->cpu_rev = "unknown"; 181 } 182 } else { 183 p->cpu_rev = p->__cpu_rev; 184 snprintf(p->__cpu_rev, sizeof(p->__cpu_rev), "0x%x", cpu_id); 185 } 186 187 p->core_id = get_coreid(); 188 189 node = of_find_node_by_name(NULL, "cpus"); 190 if (node) { 191 for_each_child_of_node(node, np) 192 if (!strcmp("cpu", np->name)) 193 ++c6x_num_cores; 194 of_node_put(node); 195 } 196 197 node = of_find_node_by_name(NULL, "soc"); 198 if (node) { 199 if (of_property_read_string(node, "model", &c6x_soc_name)) 200 c6x_soc_name = "unknown"; 201 of_node_put(node); 202 } else 203 c6x_soc_name = "unknown"; 204 205 printk(KERN_INFO "CPU%d: %s rev %s, %s volts, %uMHz\n", 206 p->core_id, p->cpu_name, p->cpu_rev, 207 p->cpu_voltage, c6x_core_freq / 1000000); 208} 209 210/* 211 * Early parsing of the command line 212 */ 213static u32 mem_size __initdata; 214 215/* "mem=" parsing. */ 216static int __init early_mem(char *p) 217{ 218 if (!p) 219 return -EINVAL; 220 221 mem_size = memparse(p, &p); 222 /* don't remove all of memory when handling "mem={invalid}" */ 223 if (mem_size == 0) 224 return -EINVAL; 225 226 return 0; 227} 228early_param("mem", early_mem); 229 230/* "memdma=<size>[@<address>]" parsing. */ 231static int __init early_memdma(char *p) 232{ 233 if (!p) 234 return -EINVAL; 235 236 dma_size = memparse(p, &p); 237 if (*p == '@') 238 dma_start = memparse(p, &p); 239 240 return 0; 241} 242early_param("memdma", early_memdma); 243 244int __init c6x_add_memory(phys_addr_t start, unsigned long size) 245{ 246 static int ram_found __initdata; 247 248 /* We only handle one bank (the one with PAGE_OFFSET) for now */ 249 if (ram_found) 250 return -EINVAL; 251 252 if (start > PAGE_OFFSET || PAGE_OFFSET >= (start + size)) 253 return 0; 254 255 ram_start = start; 256 ram_end = start + size; 257 258 ram_found = 1; 259 return 0; 260} 261 262/* 263 * Do early machine setup and device tree parsing. This is called very 264 * early on the boot process. 265 */ 266notrace void __init machine_init(unsigned long dt_ptr) 267{ 268 const void *dtb = __va(dt_ptr); 269 const void *fdt = _fdt_start; 270 271 /* interrupts must be masked */ 272 set_creg(IER, 2); 273 274 /* 275 * Set the Interrupt Service Table (IST) to the beginning of the 276 * vector table. 277 */ 278 set_ist(_vectors_start); 279 280 lockdep_init(); 281 282 /* 283 * dtb is passed in from bootloader. 284 * fdt is linked in blob. 285 */ 286 if (dtb && dtb != fdt) 287 fdt = dtb; 288 289 /* Do some early initialization based on the flat device tree */ 290 early_init_dt_scan(fdt); 291 292 parse_early_param(); 293} 294 295void __init setup_arch(char **cmdline_p) 296{ 297 int bootmap_size; 298 struct memblock_region *reg; 299 300 printk(KERN_INFO "Initializing kernel\n"); 301 302 /* Initialize command line */ 303 *cmdline_p = boot_command_line; 304 305 memory_end = ram_end; 306 memory_end &= ~(PAGE_SIZE - 1); 307 308 if (mem_size && (PAGE_OFFSET + PAGE_ALIGN(mem_size)) < memory_end) 309 memory_end = PAGE_OFFSET + PAGE_ALIGN(mem_size); 310 311 /* add block that this kernel can use */ 312 memblock_add(PAGE_OFFSET, memory_end - PAGE_OFFSET); 313 314 /* reserve kernel text/data/bss */ 315 memblock_reserve(PAGE_OFFSET, 316 PAGE_ALIGN((unsigned long)&_end - PAGE_OFFSET)); 317 318 if (dma_size) { 319 /* align to cacheability granularity */ 320 dma_size = CACHE_REGION_END(dma_size); 321 322 if (!dma_start) 323 dma_start = memory_end - dma_size; 324 325 /* align to cacheability granularity */ 326 dma_start = CACHE_REGION_START(dma_start); 327 328 /* reserve DMA memory taken from kernel memory */ 329 if (memblock_is_region_memory(dma_start, dma_size)) 330 memblock_reserve(dma_start, dma_size); 331 } 332 333 memory_start = PAGE_ALIGN((unsigned int) &_end); 334 335 printk(KERN_INFO "Memory Start=%08lx, Memory End=%08lx\n", 336 memory_start, memory_end); 337 338#ifdef CONFIG_BLK_DEV_INITRD 339 /* 340 * Reserve initrd memory if in kernel memory. 341 */ 342 if (initrd_start < initrd_end) 343 if (memblock_is_region_memory(initrd_start, 344 initrd_end - initrd_start)) 345 memblock_reserve(initrd_start, 346 initrd_end - initrd_start); 347#endif 348 349 init_mm.start_code = (unsigned long) &_stext; 350 init_mm.end_code = (unsigned long) &_etext; 351 init_mm.end_data = memory_start; 352 init_mm.brk = memory_start; 353 354 /* 355 * Give all the memory to the bootmap allocator, tell it to put the 356 * boot mem_map at the start of memory 357 */ 358 bootmap_size = init_bootmem_node(NODE_DATA(0), 359 memory_start >> PAGE_SHIFT, 360 PAGE_OFFSET >> PAGE_SHIFT, 361 memory_end >> PAGE_SHIFT); 362 memblock_reserve(memory_start, bootmap_size); 363 364 unflatten_device_tree(); 365 366 c6x_cache_init(); 367 368 /* Set the whole external memory as non-cacheable */ 369 disable_caching(ram_start, ram_end - 1); 370 371 /* Set caching of external RAM used by Linux */ 372 for_each_memblock(memory, reg) 373 enable_caching(CACHE_REGION_START(reg->base), 374 CACHE_REGION_START(reg->base + reg->size - 1)); 375 376#ifdef CONFIG_BLK_DEV_INITRD 377 /* 378 * Enable caching for initrd which falls outside kernel memory. 379 */ 380 if (initrd_start < initrd_end) { 381 if (!memblock_is_region_memory(initrd_start, 382 initrd_end - initrd_start)) 383 enable_caching(CACHE_REGION_START(initrd_start), 384 CACHE_REGION_START(initrd_end - 1)); 385 } 386#endif 387 388 /* 389 * Disable caching for dma coherent memory taken from kernel memory. 390 */ 391 if (dma_size && memblock_is_region_memory(dma_start, dma_size)) 392 disable_caching(dma_start, 393 CACHE_REGION_START(dma_start + dma_size - 1)); 394 395 /* Initialize the coherent memory allocator */ 396 coherent_mem_init(dma_start, dma_size); 397 398 /* 399 * Free all memory as a starting point. 400 */ 401 free_bootmem(PAGE_OFFSET, memory_end - PAGE_OFFSET); 402 403 /* 404 * Then reserve memory which is already being used. 405 */ 406 for_each_memblock(reserved, reg) { 407 pr_debug("reserved - 0x%08x-0x%08x\n", 408 (u32) reg->base, (u32) reg->size); 409 reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT); 410 } 411 412 max_low_pfn = PFN_DOWN(memory_end); 413 min_low_pfn = PFN_UP(memory_start); 414 max_mapnr = max_low_pfn - min_low_pfn; 415 416 /* Get kmalloc into gear */ 417 paging_init(); 418 419 /* 420 * Probe for Device State Configuration Registers. 421 * We have to do this early in case timer needs to be enabled 422 * through DSCR. 423 */ 424 dscr_probe(); 425 426 /* We do this early for timer and core clock frequency */ 427 c64x_setup_clocks(); 428 429 /* Get CPU info */ 430 get_cpuinfo(); 431 432#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) 433 conswitchp = &dummy_con; 434#endif 435} 436 437#define cpu_to_ptr(n) ((void *)((long)(n)+1)) 438#define ptr_to_cpu(p) ((long)(p) - 1) 439 440static int show_cpuinfo(struct seq_file *m, void *v) 441{ 442 int n = ptr_to_cpu(v); 443 struct cpuinfo_c6x *p = &per_cpu(cpu_data, n); 444 445 if (n == 0) { 446 seq_printf(m, 447 "soc\t\t: %s\n" 448 "soc revision\t: 0x%x\n" 449 "soc cores\t: %d\n", 450 c6x_soc_name, c6x_silicon_rev, c6x_num_cores); 451 } 452 453 seq_printf(m, 454 "\n" 455 "processor\t: %d\n" 456 "cpu\t\t: %s\n" 457 "core revision\t: %s\n" 458 "core voltage\t: %s\n" 459 "core id\t\t: %d\n" 460 "mmu\t\t: %s\n" 461 "fpu\t\t: %s\n" 462 "cpu MHz\t\t: %u\n" 463 "bogomips\t: %lu.%02lu\n\n", 464 n, 465 p->cpu_name, p->cpu_rev, p->cpu_voltage, 466 p->core_id, p->mmu, p->fpu, 467 (c6x_core_freq + 500000) / 1000000, 468 (loops_per_jiffy/(500000/HZ)), 469 (loops_per_jiffy/(5000/HZ))%100); 470 471 return 0; 472} 473 474static void *c_start(struct seq_file *m, loff_t *pos) 475{ 476 return *pos < nr_cpu_ids ? cpu_to_ptr(*pos) : NULL; 477} 478static void *c_next(struct seq_file *m, void *v, loff_t *pos) 479{ 480 ++*pos; 481 return NULL; 482} 483static void c_stop(struct seq_file *m, void *v) 484{ 485} 486 487const struct seq_operations cpuinfo_op = { 488 c_start, 489 c_stop, 490 c_next, 491 show_cpuinfo 492}; 493 494static struct cpu cpu_devices[NR_CPUS]; 495 496static int __init topology_init(void) 497{ 498 int i; 499 500 for_each_present_cpu(i) 501 register_cpu(&cpu_devices[i], i); 502 503 return 0; 504} 505 506subsys_initcall(topology_init); 507