1 /* 2 * OpenRISC setup.c 3 * 4 * Linux architectural port borrowing liberally from similar works of 5 * others. All original copyrights apply as per the original source 6 * declaration. 7 * 8 * Modifications for the OpenRISC architecture: 9 * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> 10 * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 15 * 2 of the License, or (at your option) any later version. 16 * 17 * This file handles the architecture-dependent parts of initialization 18 */ 19 20 #include <linux/errno.h> 21 #include <linux/sched.h> 22 #include <linux/kernel.h> 23 #include <linux/mm.h> 24 #include <linux/stddef.h> 25 #include <linux/unistd.h> 26 #include <linux/ptrace.h> 27 #include <linux/slab.h> 28 #include <linux/tty.h> 29 #include <linux/ioport.h> 30 #include <linux/delay.h> 31 #include <linux/console.h> 32 #include <linux/init.h> 33 #include <linux/bootmem.h> 34 #include <linux/seq_file.h> 35 #include <linux/serial.h> 36 #include <linux/initrd.h> 37 #include <linux/of_fdt.h> 38 #include <linux/of.h> 39 #include <linux/memblock.h> 40 #include <linux/device.h> 41 42 #include <asm/sections.h> 43 #include <asm/segment.h> 44 #include <asm/pgtable.h> 45 #include <asm/types.h> 46 #include <asm/setup.h> 47 #include <asm/io.h> 48 #include <asm/cpuinfo.h> 49 #include <asm/delay.h> 50 51 #include "vmlinux.h" 52 53 static void __init setup_memory(void) 54 { 55 unsigned long ram_start_pfn; 56 unsigned long ram_end_pfn; 57 phys_addr_t memory_start, memory_end; 58 struct memblock_region *region; 59 60 memory_end = memory_start = 0; 61 62 /* Find main memory where is the kernel, we assume its the only one */ 63 for_each_memblock(memory, region) { 64 memory_start = region->base; 65 memory_end = region->base + region->size; 66 printk(KERN_INFO "%s: Memory: 0x%x-0x%x\n", __func__, 67 memory_start, memory_end); 68 } 69 70 if (!memory_end) { 71 panic("No memory!"); 72 } 73 74 ram_start_pfn = PFN_UP(memory_start); 75 ram_end_pfn = PFN_DOWN(memblock_end_of_DRAM()); 76 77 /* setup bootmem globals (we use no_bootmem, but mm still depends on this) */ 78 min_low_pfn = ram_start_pfn; 79 max_low_pfn = ram_end_pfn; 80 max_pfn = ram_end_pfn; 81 82 /* 83 * initialize the boot-time allocator (with low memory only). 84 * 85 * This makes the memory from the end of the kernel to the end of 86 * RAM usable. 87 */ 88 memblock_reserve(__pa(_stext), _end - _stext); 89 90 early_init_fdt_reserve_self(); 91 early_init_fdt_scan_reserved_mem(); 92 93 memblock_dump_all(); 94 } 95 96 struct cpuinfo cpuinfo; 97 98 static void print_cpuinfo(void) 99 { 100 unsigned long upr = mfspr(SPR_UPR); 101 unsigned long vr = mfspr(SPR_VR); 102 unsigned int version; 103 unsigned int revision; 104 105 version = (vr & SPR_VR_VER) >> 24; 106 revision = (vr & SPR_VR_REV); 107 108 printk(KERN_INFO "CPU: OpenRISC-%x (revision %d) @%d MHz\n", 109 version, revision, cpuinfo.clock_frequency / 1000000); 110 111 if (!(upr & SPR_UPR_UP)) { 112 printk(KERN_INFO 113 "-- no UPR register... unable to detect configuration\n"); 114 return; 115 } 116 117 if (upr & SPR_UPR_DCP) 118 printk(KERN_INFO 119 "-- dcache: %4d bytes total, %2d bytes/line, %d way(s)\n", 120 cpuinfo.dcache_size, cpuinfo.dcache_block_size, 121 cpuinfo.dcache_ways); 122 else 123 printk(KERN_INFO "-- dcache disabled\n"); 124 if (upr & SPR_UPR_ICP) 125 printk(KERN_INFO 126 "-- icache: %4d bytes total, %2d bytes/line, %d way(s)\n", 127 cpuinfo.icache_size, cpuinfo.icache_block_size, 128 cpuinfo.icache_ways); 129 else 130 printk(KERN_INFO "-- icache disabled\n"); 131 132 if (upr & SPR_UPR_DMP) 133 printk(KERN_INFO "-- dmmu: %4d entries, %lu way(s)\n", 134 1 << ((mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTS) >> 2), 135 1 + (mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTW)); 136 if (upr & SPR_UPR_IMP) 137 printk(KERN_INFO "-- immu: %4d entries, %lu way(s)\n", 138 1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> 2), 139 1 + (mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTW)); 140 141 printk(KERN_INFO "-- additional features:\n"); 142 if (upr & SPR_UPR_DUP) 143 printk(KERN_INFO "-- debug unit\n"); 144 if (upr & SPR_UPR_PCUP) 145 printk(KERN_INFO "-- performance counters\n"); 146 if (upr & SPR_UPR_PMP) 147 printk(KERN_INFO "-- power management\n"); 148 if (upr & SPR_UPR_PICP) 149 printk(KERN_INFO "-- PIC\n"); 150 if (upr & SPR_UPR_TTP) 151 printk(KERN_INFO "-- timer\n"); 152 if (upr & SPR_UPR_CUP) 153 printk(KERN_INFO "-- custom unit(s)\n"); 154 } 155 156 void __init setup_cpuinfo(void) 157 { 158 struct device_node *cpu; 159 unsigned long iccfgr, dccfgr; 160 unsigned long cache_set_size; 161 162 cpu = of_find_compatible_node(NULL, NULL, "opencores,or1200-rtlsvn481"); 163 if (!cpu) 164 panic("No compatible CPU found in device tree...\n"); 165 166 iccfgr = mfspr(SPR_ICCFGR); 167 cpuinfo.icache_ways = 1 << (iccfgr & SPR_ICCFGR_NCW); 168 cache_set_size = 1 << ((iccfgr & SPR_ICCFGR_NCS) >> 3); 169 cpuinfo.icache_block_size = 16 << ((iccfgr & SPR_ICCFGR_CBS) >> 7); 170 cpuinfo.icache_size = 171 cache_set_size * cpuinfo.icache_ways * cpuinfo.icache_block_size; 172 173 dccfgr = mfspr(SPR_DCCFGR); 174 cpuinfo.dcache_ways = 1 << (dccfgr & SPR_DCCFGR_NCW); 175 cache_set_size = 1 << ((dccfgr & SPR_DCCFGR_NCS) >> 3); 176 cpuinfo.dcache_block_size = 16 << ((dccfgr & SPR_DCCFGR_CBS) >> 7); 177 cpuinfo.dcache_size = 178 cache_set_size * cpuinfo.dcache_ways * cpuinfo.dcache_block_size; 179 180 if (of_property_read_u32(cpu, "clock-frequency", 181 &cpuinfo.clock_frequency)) { 182 printk(KERN_WARNING 183 "Device tree missing CPU 'clock-frequency' parameter." 184 "Assuming frequency 25MHZ" 185 "This is probably not what you want."); 186 } 187 188 of_node_put(cpu); 189 190 print_cpuinfo(); 191 } 192 193 /** 194 * or32_early_setup 195 * 196 * Handles the pointer to the device tree that this kernel is to use 197 * for establishing the available platform devices. 198 * 199 * Falls back on built-in device tree in case null pointer is passed. 200 */ 201 202 void __init or32_early_setup(void *fdt) 203 { 204 if (fdt) 205 pr_info("FDT at %p\n", fdt); 206 else { 207 fdt = __dtb_start; 208 pr_info("Compiled-in FDT at %p\n", fdt); 209 } 210 early_init_devtree(fdt); 211 } 212 213 static inline unsigned long extract_value_bits(unsigned long reg, 214 short bit_nr, short width) 215 { 216 return (reg >> bit_nr) & (0 << width); 217 } 218 219 static inline unsigned long extract_value(unsigned long reg, unsigned long mask) 220 { 221 while (!(mask & 0x1)) { 222 reg = reg >> 1; 223 mask = mask >> 1; 224 } 225 return mask & reg; 226 } 227 228 void __init detect_unit_config(unsigned long upr, unsigned long mask, 229 char *text, void (*func) (void)) 230 { 231 if (text != NULL) 232 printk("%s", text); 233 234 if (upr & mask) { 235 if (func != NULL) 236 func(); 237 else 238 printk("present\n"); 239 } else 240 printk("not present\n"); 241 } 242 243 /* 244 * calibrate_delay 245 * 246 * Lightweight calibrate_delay implementation that calculates loops_per_jiffy 247 * from the clock frequency passed in via the device tree 248 * 249 */ 250 251 void calibrate_delay(void) 252 { 253 const int *val; 254 struct device_node *cpu = NULL; 255 cpu = of_find_compatible_node(NULL, NULL, "opencores,or1200-rtlsvn481"); 256 val = of_get_property(cpu, "clock-frequency", NULL); 257 if (!val) 258 panic("no cpu 'clock-frequency' parameter in device tree"); 259 loops_per_jiffy = *val / HZ; 260 pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n", 261 loops_per_jiffy / (500000 / HZ), 262 (loops_per_jiffy / (5000 / HZ)) % 100, loops_per_jiffy); 263 } 264 265 void __init setup_arch(char **cmdline_p) 266 { 267 unflatten_and_copy_device_tree(); 268 269 setup_cpuinfo(); 270 271 /* process 1's initial memory region is the kernel code/data */ 272 init_mm.start_code = (unsigned long)_stext; 273 init_mm.end_code = (unsigned long)_etext; 274 init_mm.end_data = (unsigned long)_edata; 275 init_mm.brk = (unsigned long)_end; 276 277 #ifdef CONFIG_BLK_DEV_INITRD 278 initrd_start = (unsigned long)&__initrd_start; 279 initrd_end = (unsigned long)&__initrd_end; 280 if (initrd_start == initrd_end) { 281 initrd_start = 0; 282 initrd_end = 0; 283 } 284 initrd_below_start_ok = 1; 285 #endif 286 287 /* setup memblock allocator */ 288 setup_memory(); 289 290 /* paging_init() sets up the MMU and marks all pages as reserved */ 291 paging_init(); 292 293 #if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) 294 if (!conswitchp) 295 conswitchp = &dummy_con; 296 #endif 297 298 *cmdline_p = boot_command_line; 299 300 printk(KERN_INFO "OpenRISC Linux -- http://openrisc.io\n"); 301 } 302 303 static int show_cpuinfo(struct seq_file *m, void *v) 304 { 305 unsigned long vr; 306 int version, revision; 307 308 vr = mfspr(SPR_VR); 309 version = (vr & SPR_VR_VER) >> 24; 310 revision = vr & SPR_VR_REV; 311 312 seq_printf(m, 313 "cpu\t\t: OpenRISC-%x\n" 314 "revision\t: %d\n" 315 "frequency\t: %ld\n" 316 "dcache size\t: %d bytes\n" 317 "dcache block size\t: %d bytes\n" 318 "dcache ways\t: %d\n" 319 "icache size\t: %d bytes\n" 320 "icache block size\t: %d bytes\n" 321 "icache ways\t: %d\n" 322 "immu\t\t: %d entries, %lu ways\n" 323 "dmmu\t\t: %d entries, %lu ways\n" 324 "bogomips\t: %lu.%02lu\n", 325 version, 326 revision, 327 loops_per_jiffy * HZ, 328 cpuinfo.dcache_size, 329 cpuinfo.dcache_block_size, 330 cpuinfo.dcache_ways, 331 cpuinfo.icache_size, 332 cpuinfo.icache_block_size, 333 cpuinfo.icache_ways, 334 1 << ((mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTS) >> 2), 335 1 + (mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTW), 336 1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> 2), 337 1 + (mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTW), 338 (loops_per_jiffy * HZ) / 500000, 339 ((loops_per_jiffy * HZ) / 5000) % 100); 340 return 0; 341 } 342 343 static void *c_start(struct seq_file *m, loff_t * pos) 344 { 345 /* We only have one CPU... */ 346 return *pos < 1 ? (void *)1 : NULL; 347 } 348 349 static void *c_next(struct seq_file *m, void *v, loff_t * pos) 350 { 351 ++*pos; 352 return NULL; 353 } 354 355 static void c_stop(struct seq_file *m, void *v) 356 { 357 } 358 359 const struct seq_operations cpuinfo_op = { 360 .start = c_start, 361 .next = c_next, 362 .stop = c_stop, 363 .show = show_cpuinfo, 364 }; 365