linux/arch/openrisc/kernel/setup.c
<<
>>
Prefs
   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
  53static 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
  96struct cpuinfo_or1k cpuinfo_or1k[NR_CPUS];
  97
  98static 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        struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[smp_processor_id()];
 105
 106        version = (vr & SPR_VR_VER) >> 24;
 107        revision = (vr & SPR_VR_REV);
 108
 109        printk(KERN_INFO "CPU: OpenRISC-%x (revision %d) @%d MHz\n",
 110               version, revision, cpuinfo->clock_frequency / 1000000);
 111
 112        if (!(upr & SPR_UPR_UP)) {
 113                printk(KERN_INFO
 114                       "-- no UPR register... unable to detect configuration\n");
 115                return;
 116        }
 117
 118        if (upr & SPR_UPR_DCP)
 119                printk(KERN_INFO
 120                       "-- dcache: %4d bytes total, %2d bytes/line, %d way(s)\n",
 121                       cpuinfo->dcache_size, cpuinfo->dcache_block_size,
 122                       cpuinfo->dcache_ways);
 123        else
 124                printk(KERN_INFO "-- dcache disabled\n");
 125        if (upr & SPR_UPR_ICP)
 126                printk(KERN_INFO
 127                       "-- icache: %4d bytes total, %2d bytes/line, %d way(s)\n",
 128                       cpuinfo->icache_size, cpuinfo->icache_block_size,
 129                       cpuinfo->icache_ways);
 130        else
 131                printk(KERN_INFO "-- icache disabled\n");
 132
 133        if (upr & SPR_UPR_DMP)
 134                printk(KERN_INFO "-- dmmu: %4d entries, %lu way(s)\n",
 135                       1 << ((mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTS) >> 2),
 136                       1 + (mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTW));
 137        if (upr & SPR_UPR_IMP)
 138                printk(KERN_INFO "-- immu: %4d entries, %lu way(s)\n",
 139                       1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> 2),
 140                       1 + (mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTW));
 141
 142        printk(KERN_INFO "-- additional features:\n");
 143        if (upr & SPR_UPR_DUP)
 144                printk(KERN_INFO "-- debug unit\n");
 145        if (upr & SPR_UPR_PCUP)
 146                printk(KERN_INFO "-- performance counters\n");
 147        if (upr & SPR_UPR_PMP)
 148                printk(KERN_INFO "-- power management\n");
 149        if (upr & SPR_UPR_PICP)
 150                printk(KERN_INFO "-- PIC\n");
 151        if (upr & SPR_UPR_TTP)
 152                printk(KERN_INFO "-- timer\n");
 153        if (upr & SPR_UPR_CUP)
 154                printk(KERN_INFO "-- custom unit(s)\n");
 155}
 156
 157static struct device_node *setup_find_cpu_node(int cpu)
 158{
 159        u32 hwid;
 160        struct device_node *cpun;
 161        struct device_node *cpus = of_find_node_by_path("/cpus");
 162
 163        for_each_available_child_of_node(cpus, cpun) {
 164                if (of_property_read_u32(cpun, "reg", &hwid))
 165                        continue;
 166                if (hwid == cpu)
 167                        return cpun;
 168        }
 169
 170        return NULL;
 171}
 172
 173void __init setup_cpuinfo(void)
 174{
 175        struct device_node *cpu;
 176        unsigned long iccfgr, dccfgr;
 177        unsigned long cache_set_size;
 178        int cpu_id = smp_processor_id();
 179        struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[cpu_id];
 180
 181        cpu = setup_find_cpu_node(cpu_id);
 182        if (!cpu)
 183                panic("Couldn't find CPU%d in device tree...\n", cpu_id);
 184
 185        iccfgr = mfspr(SPR_ICCFGR);
 186        cpuinfo->icache_ways = 1 << (iccfgr & SPR_ICCFGR_NCW);
 187        cache_set_size = 1 << ((iccfgr & SPR_ICCFGR_NCS) >> 3);
 188        cpuinfo->icache_block_size = 16 << ((iccfgr & SPR_ICCFGR_CBS) >> 7);
 189        cpuinfo->icache_size =
 190            cache_set_size * cpuinfo->icache_ways * cpuinfo->icache_block_size;
 191
 192        dccfgr = mfspr(SPR_DCCFGR);
 193        cpuinfo->dcache_ways = 1 << (dccfgr & SPR_DCCFGR_NCW);
 194        cache_set_size = 1 << ((dccfgr & SPR_DCCFGR_NCS) >> 3);
 195        cpuinfo->dcache_block_size = 16 << ((dccfgr & SPR_DCCFGR_CBS) >> 7);
 196        cpuinfo->dcache_size =
 197            cache_set_size * cpuinfo->dcache_ways * cpuinfo->dcache_block_size;
 198
 199        if (of_property_read_u32(cpu, "clock-frequency",
 200                                 &cpuinfo->clock_frequency)) {
 201                printk(KERN_WARNING
 202                       "Device tree missing CPU 'clock-frequency' parameter."
 203                       "Assuming frequency 25MHZ"
 204                       "This is probably not what you want.");
 205        }
 206
 207        cpuinfo->coreid = mfspr(SPR_COREID);
 208
 209        of_node_put(cpu);
 210
 211        print_cpuinfo();
 212}
 213
 214/**
 215 * or32_early_setup
 216 *
 217 * Handles the pointer to the device tree that this kernel is to use
 218 * for establishing the available platform devices.
 219 *
 220 * Falls back on built-in device tree in case null pointer is passed.
 221 */
 222
 223void __init or32_early_setup(void *fdt)
 224{
 225        if (fdt)
 226                pr_info("FDT at %p\n", fdt);
 227        else {
 228                fdt = __dtb_start;
 229                pr_info("Compiled-in FDT at %p\n", fdt);
 230        }
 231        early_init_devtree(fdt);
 232}
 233
 234static inline unsigned long extract_value_bits(unsigned long reg,
 235                                               short bit_nr, short width)
 236{
 237        return (reg >> bit_nr) & (0 << width);
 238}
 239
 240static inline unsigned long extract_value(unsigned long reg, unsigned long mask)
 241{
 242        while (!(mask & 0x1)) {
 243                reg = reg >> 1;
 244                mask = mask >> 1;
 245        }
 246        return mask & reg;
 247}
 248
 249void __init detect_unit_config(unsigned long upr, unsigned long mask,
 250                               char *text, void (*func) (void))
 251{
 252        if (text != NULL)
 253                printk("%s", text);
 254
 255        if (upr & mask) {
 256                if (func != NULL)
 257                        func();
 258                else
 259                        printk("present\n");
 260        } else
 261                printk("not present\n");
 262}
 263
 264/*
 265 * calibrate_delay
 266 *
 267 * Lightweight calibrate_delay implementation that calculates loops_per_jiffy
 268 * from the clock frequency passed in via the device tree
 269 *
 270 */
 271
 272void calibrate_delay(void)
 273{
 274        const int *val;
 275        struct device_node *cpu = setup_find_cpu_node(smp_processor_id());
 276
 277        val = of_get_property(cpu, "clock-frequency", NULL);
 278        if (!val)
 279                panic("no cpu 'clock-frequency' parameter in device tree");
 280        loops_per_jiffy = *val / HZ;
 281        pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n",
 282                loops_per_jiffy / (500000 / HZ),
 283                (loops_per_jiffy / (5000 / HZ)) % 100, loops_per_jiffy);
 284}
 285
 286void __init setup_arch(char **cmdline_p)
 287{
 288        unflatten_and_copy_device_tree();
 289
 290        setup_cpuinfo();
 291
 292#ifdef CONFIG_SMP
 293        smp_init_cpus();
 294#endif
 295
 296        /* process 1's initial memory region is the kernel code/data */
 297        init_mm.start_code = (unsigned long)_stext;
 298        init_mm.end_code = (unsigned long)_etext;
 299        init_mm.end_data = (unsigned long)_edata;
 300        init_mm.brk = (unsigned long)_end;
 301
 302#ifdef CONFIG_BLK_DEV_INITRD
 303        initrd_start = (unsigned long)&__initrd_start;
 304        initrd_end = (unsigned long)&__initrd_end;
 305        if (initrd_start == initrd_end) {
 306                initrd_start = 0;
 307                initrd_end = 0;
 308        }
 309        initrd_below_start_ok = 1;
 310#endif
 311
 312        /* setup memblock allocator */
 313        setup_memory();
 314
 315        /* paging_init() sets up the MMU and marks all pages as reserved */
 316        paging_init();
 317
 318#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
 319        if (!conswitchp)
 320                conswitchp = &dummy_con;
 321#endif
 322
 323        *cmdline_p = boot_command_line;
 324
 325        printk(KERN_INFO "OpenRISC Linux -- http://openrisc.io\n");
 326}
 327
 328static int show_cpuinfo(struct seq_file *m, void *v)
 329{
 330        unsigned int vr, cpucfgr;
 331        unsigned int avr;
 332        unsigned int version;
 333        struct cpuinfo_or1k *cpuinfo = v;
 334
 335        vr = mfspr(SPR_VR);
 336        cpucfgr = mfspr(SPR_CPUCFGR);
 337
 338#ifdef CONFIG_SMP
 339        seq_printf(m, "processor\t\t: %d\n", cpuinfo->coreid);
 340#endif
 341        if (vr & SPR_VR_UVRP) {
 342                vr = mfspr(SPR_VR2);
 343                version = vr & SPR_VR2_VER;
 344                avr = mfspr(SPR_AVR);
 345                seq_printf(m, "cpu architecture\t: "
 346                           "OpenRISC 1000 (%d.%d-rev%d)\n",
 347                           (avr >> 24) & 0xff,
 348                           (avr >> 16) & 0xff,
 349                           (avr >> 8) & 0xff);
 350                seq_printf(m, "cpu implementation id\t: 0x%x\n",
 351                           (vr & SPR_VR2_CPUID) >> 24);
 352                seq_printf(m, "cpu version\t\t: 0x%x\n", version);
 353        } else {
 354                version = (vr & SPR_VR_VER) >> 24;
 355                seq_printf(m, "cpu\t\t\t: OpenRISC-%x\n", version);
 356                seq_printf(m, "revision\t\t: %d\n", vr & SPR_VR_REV);
 357        }
 358        seq_printf(m, "frequency\t\t: %ld\n", loops_per_jiffy * HZ);
 359        seq_printf(m, "dcache size\t\t: %d bytes\n", cpuinfo->dcache_size);
 360        seq_printf(m, "dcache block size\t: %d bytes\n",
 361                   cpuinfo->dcache_block_size);
 362        seq_printf(m, "dcache ways\t\t: %d\n", cpuinfo->dcache_ways);
 363        seq_printf(m, "icache size\t\t: %d bytes\n", cpuinfo->icache_size);
 364        seq_printf(m, "icache block size\t: %d bytes\n",
 365                   cpuinfo->icache_block_size);
 366        seq_printf(m, "icache ways\t\t: %d\n", cpuinfo->icache_ways);
 367        seq_printf(m, "immu\t\t\t: %d entries, %lu ways\n",
 368                   1 << ((mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTS) >> 2),
 369                   1 + (mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTW));
 370        seq_printf(m, "dmmu\t\t\t: %d entries, %lu ways\n",
 371                   1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> 2),
 372                   1 + (mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTW));
 373        seq_printf(m, "bogomips\t\t: %lu.%02lu\n",
 374                   (loops_per_jiffy * HZ) / 500000,
 375                   ((loops_per_jiffy * HZ) / 5000) % 100);
 376
 377        seq_puts(m, "features\t\t: ");
 378        seq_printf(m, "%s ", cpucfgr & SPR_CPUCFGR_OB32S ? "orbis32" : "");
 379        seq_printf(m, "%s ", cpucfgr & SPR_CPUCFGR_OB64S ? "orbis64" : "");
 380        seq_printf(m, "%s ", cpucfgr & SPR_CPUCFGR_OF32S ? "orfpx32" : "");
 381        seq_printf(m, "%s ", cpucfgr & SPR_CPUCFGR_OF64S ? "orfpx64" : "");
 382        seq_printf(m, "%s ", cpucfgr & SPR_CPUCFGR_OV64S ? "orvdx64" : "");
 383        seq_puts(m, "\n");
 384
 385        seq_puts(m, "\n");
 386
 387        return 0;
 388}
 389
 390static void *c_start(struct seq_file *m, loff_t *pos)
 391{
 392        *pos = cpumask_next(*pos - 1, cpu_online_mask);
 393        if ((*pos) < nr_cpu_ids)
 394                return &cpuinfo_or1k[*pos];
 395        return NULL;
 396}
 397
 398static void *c_next(struct seq_file *m, void *v, loff_t *pos)
 399{
 400        (*pos)++;
 401        return c_start(m, pos);
 402}
 403
 404static void c_stop(struct seq_file *m, void *v)
 405{
 406}
 407
 408const struct seq_operations cpuinfo_op = {
 409        .start = c_start,
 410        .next = c_next,
 411        .stop = c_stop,
 412        .show = show_cpuinfo,
 413};
 414