linux/arch/arc/kernel/setup.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 */
   8
   9#include <linux/seq_file.h>
  10#include <linux/fs.h>
  11#include <linux/delay.h>
  12#include <linux/root_dev.h>
  13#include <linux/console.h>
  14#include <linux/module.h>
  15#include <linux/cpu.h>
  16#include <linux/clk-provider.h>
  17#include <linux/of_fdt.h>
  18#include <linux/of_platform.h>
  19#include <linux/cache.h>
  20#include <asm/sections.h>
  21#include <asm/arcregs.h>
  22#include <asm/tlb.h>
  23#include <asm/setup.h>
  24#include <asm/page.h>
  25#include <asm/irq.h>
  26#include <asm/unwind.h>
  27#include <asm/clk.h>
  28#include <asm/mach_desc.h>
  29#include <asm/smp.h>
  30
  31#define FIX_PTR(x)  __asm__ __volatile__(";" : "+r"(x))
  32
  33unsigned int intr_to_DE_cnt;
  34
  35/* Part of U-boot ABI: see head.S */
  36int __initdata uboot_tag;
  37char __initdata *uboot_arg;
  38
  39const struct machine_desc *machine_desc;
  40
  41struct task_struct *_current_task[NR_CPUS];     /* For stack switching */
  42
  43struct cpuinfo_arc cpuinfo_arc700[NR_CPUS];
  44
  45static void read_decode_ccm_bcr(struct cpuinfo_arc *cpu)
  46{
  47        if (is_isa_arcompact()) {
  48                struct bcr_iccm_arcompact iccm;
  49                struct bcr_dccm_arcompact dccm;
  50
  51                READ_BCR(ARC_REG_ICCM_BUILD, iccm);
  52                if (iccm.ver) {
  53                        cpu->iccm.sz = 4096 << iccm.sz; /* 8K to 512K */
  54                        cpu->iccm.base_addr = iccm.base << 16;
  55                }
  56
  57                READ_BCR(ARC_REG_DCCM_BUILD, dccm);
  58                if (dccm.ver) {
  59                        unsigned long base;
  60                        cpu->dccm.sz = 2048 << dccm.sz; /* 2K to 256K */
  61
  62                        base = read_aux_reg(ARC_REG_DCCM_BASE_BUILD);
  63                        cpu->dccm.base_addr = base & ~0xF;
  64                }
  65        } else {
  66                struct bcr_iccm_arcv2 iccm;
  67                struct bcr_dccm_arcv2 dccm;
  68                unsigned long region;
  69
  70                READ_BCR(ARC_REG_ICCM_BUILD, iccm);
  71                if (iccm.ver) {
  72                        cpu->iccm.sz = 256 << iccm.sz00;        /* 512B to 16M */
  73                        if (iccm.sz00 == 0xF && iccm.sz01 > 0)
  74                                cpu->iccm.sz <<= iccm.sz01;
  75
  76                        region = read_aux_reg(ARC_REG_AUX_ICCM);
  77                        cpu->iccm.base_addr = region & 0xF0000000;
  78                }
  79
  80                READ_BCR(ARC_REG_DCCM_BUILD, dccm);
  81                if (dccm.ver) {
  82                        cpu->dccm.sz = 256 << dccm.sz0;
  83                        if (dccm.sz0 == 0xF && dccm.sz1 > 0)
  84                                cpu->dccm.sz <<= dccm.sz1;
  85
  86                        region = read_aux_reg(ARC_REG_AUX_DCCM);
  87                        cpu->dccm.base_addr = region & 0xF0000000;
  88                }
  89        }
  90}
  91
  92static void read_arc_build_cfg_regs(void)
  93{
  94        struct bcr_perip uncached_space;
  95        struct bcr_timer timer;
  96        struct bcr_generic bcr;
  97        struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
  98        unsigned long perip_space;
  99        FIX_PTR(cpu);
 100
 101        READ_BCR(AUX_IDENTITY, cpu->core);
 102        READ_BCR(ARC_REG_ISA_CFG_BCR, cpu->isa);
 103
 104        READ_BCR(ARC_REG_TIMERS_BCR, timer);
 105        cpu->extn.timer0 = timer.t0;
 106        cpu->extn.timer1 = timer.t1;
 107        cpu->extn.rtc = timer.rtc;
 108
 109        cpu->vec_base = read_aux_reg(AUX_INTR_VEC_BASE);
 110
 111        READ_BCR(ARC_REG_D_UNCACH_BCR, uncached_space);
 112        if (uncached_space.ver < 3)
 113                perip_space = uncached_space.start << 24;
 114        else
 115                perip_space = read_aux_reg(AUX_NON_VOL) & 0xF0000000;
 116
 117        BUG_ON(perip_space != ARC_UNCACHED_ADDR_SPACE);
 118
 119        READ_BCR(ARC_REG_MUL_BCR, cpu->extn_mpy);
 120
 121        cpu->extn.norm = read_aux_reg(ARC_REG_NORM_BCR) > 1 ? 1 : 0; /* 2,3 */
 122        cpu->extn.barrel = read_aux_reg(ARC_REG_BARREL_BCR) > 1 ? 1 : 0; /* 2,3 */
 123        cpu->extn.swap = read_aux_reg(ARC_REG_SWAP_BCR) ? 1 : 0;        /* 1,3 */
 124        cpu->extn.crc = read_aux_reg(ARC_REG_CRC_BCR) ? 1 : 0;
 125        cpu->extn.minmax = read_aux_reg(ARC_REG_MIXMAX_BCR) > 1 ? 1 : 0; /* 2 */
 126        READ_BCR(ARC_REG_XY_MEM_BCR, cpu->extn_xymem);
 127
 128        /* Read CCM BCRs for boot reporting even if not enabled in Kconfig */
 129        read_decode_ccm_bcr(cpu);
 130
 131        read_decode_mmu_bcr();
 132        read_decode_cache_bcr();
 133
 134        if (is_isa_arcompact()) {
 135                struct bcr_fp_arcompact sp, dp;
 136                struct bcr_bpu_arcompact bpu;
 137
 138                READ_BCR(ARC_REG_FP_BCR, sp);
 139                READ_BCR(ARC_REG_DPFP_BCR, dp);
 140                cpu->extn.fpu_sp = sp.ver ? 1 : 0;
 141                cpu->extn.fpu_dp = dp.ver ? 1 : 0;
 142
 143                READ_BCR(ARC_REG_BPU_BCR, bpu);
 144                cpu->bpu.ver = bpu.ver;
 145                cpu->bpu.full = bpu.fam ? 1 : 0;
 146                if (bpu.ent) {
 147                        cpu->bpu.num_cache = 256 << (bpu.ent - 1);
 148                        cpu->bpu.num_pred = 256 << (bpu.ent - 1);
 149                }
 150        } else {
 151                struct bcr_fp_arcv2 spdp;
 152                struct bcr_bpu_arcv2 bpu;
 153
 154                READ_BCR(ARC_REG_FP_V2_BCR, spdp);
 155                cpu->extn.fpu_sp = spdp.sp ? 1 : 0;
 156                cpu->extn.fpu_dp = spdp.dp ? 1 : 0;
 157
 158                READ_BCR(ARC_REG_BPU_BCR, bpu);
 159                cpu->bpu.ver = bpu.ver;
 160                cpu->bpu.full = bpu.ft;
 161                cpu->bpu.num_cache = 256 << bpu.bce;
 162                cpu->bpu.num_pred = 2048 << bpu.pte;
 163        }
 164
 165        READ_BCR(ARC_REG_AP_BCR, bcr);
 166        cpu->extn.ap = bcr.ver ? 1 : 0;
 167
 168        READ_BCR(ARC_REG_SMART_BCR, bcr);
 169        cpu->extn.smart = bcr.ver ? 1 : 0;
 170
 171        READ_BCR(ARC_REG_RTT_BCR, bcr);
 172        cpu->extn.rtt = bcr.ver ? 1 : 0;
 173
 174        cpu->extn.debug = cpu->extn.ap | cpu->extn.smart | cpu->extn.rtt;
 175}
 176
 177static const struct cpuinfo_data arc_cpu_tbl[] = {
 178#ifdef CONFIG_ISA_ARCOMPACT
 179        { {0x20, "ARC 600"      }, 0x2F},
 180        { {0x30, "ARC 700"      }, 0x33},
 181        { {0x34, "ARC 700 R4.10"}, 0x34},
 182        { {0x35, "ARC 700 R4.11"}, 0x35},
 183#else
 184        { {0x50, "ARC HS38 R2.0"}, 0x51},
 185        { {0x52, "ARC HS38 R2.1"}, 0x52},
 186#endif
 187        { {0x00, NULL           } }
 188};
 189
 190
 191static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len)
 192{
 193        struct cpuinfo_arc *cpu = &cpuinfo_arc700[cpu_id];
 194        struct bcr_identity *core = &cpu->core;
 195        const struct cpuinfo_data *tbl;
 196        char *isa_nm;
 197        int i, be, atomic;
 198        int n = 0;
 199
 200        FIX_PTR(cpu);
 201
 202        if (is_isa_arcompact()) {
 203                isa_nm = "ARCompact";
 204                be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);
 205
 206                atomic = cpu->isa.atomic1;
 207                if (!cpu->isa.ver)      /* ISA BCR absent, use Kconfig info */
 208                        atomic = IS_ENABLED(CONFIG_ARC_HAS_LLSC);
 209        } else {
 210                isa_nm = "ARCv2";
 211                be = cpu->isa.be;
 212                atomic = cpu->isa.atomic;
 213        }
 214
 215        n += scnprintf(buf + n, len - n,
 216                       "\nIDENTITY\t: ARCVER [%#02x] ARCNUM [%#02x] CHIPID [%#4x]\n",
 217                       core->family, core->cpu_id, core->chip_id);
 218
 219        for (tbl = &arc_cpu_tbl[0]; tbl->info.id != 0; tbl++) {
 220                if ((core->family >= tbl->info.id) &&
 221                    (core->family <= tbl->up_range)) {
 222                        n += scnprintf(buf + n, len - n,
 223                                       "processor [%d]\t: %s (%s ISA) %s\n",
 224                                       cpu_id, tbl->info.str, isa_nm,
 225                                       IS_AVAIL1(be, "[Big-Endian]"));
 226                        break;
 227                }
 228        }
 229
 230        if (tbl->info.id == 0)
 231                n += scnprintf(buf + n, len - n, "UNKNOWN ARC Processor\n");
 232
 233        n += scnprintf(buf + n, len - n, "CPU speed\t: %u.%02u Mhz\n",
 234                       (unsigned int)(arc_get_core_freq() / 1000000),
 235                       (unsigned int)(arc_get_core_freq() / 10000) % 100);
 236
 237        n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s\nISA Extn\t: ",
 238                       IS_AVAIL1(cpu->extn.timer0, "Timer0 "),
 239                       IS_AVAIL1(cpu->extn.timer1, "Timer1 "),
 240                       IS_AVAIL2(cpu->extn.rtc, "Local-64-bit-Ctr ",
 241                                 CONFIG_ARC_HAS_RTC));
 242
 243        n += i = scnprintf(buf + n, len - n, "%s%s%s%s%s",
 244                           IS_AVAIL2(atomic, "atomic ", CONFIG_ARC_HAS_LLSC),
 245                           IS_AVAIL2(cpu->isa.ldd, "ll64 ", CONFIG_ARC_HAS_LL64),
 246                           IS_AVAIL1(cpu->isa.unalign, "unalign (not used)"));
 247
 248        if (i)
 249                n += scnprintf(buf + n, len - n, "\n\t\t: ");
 250
 251        if (cpu->extn_mpy.ver) {
 252                if (cpu->extn_mpy.ver <= 0x2) { /* ARCompact */
 253                        n += scnprintf(buf + n, len - n, "mpy ");
 254                } else {
 255                        int opt = 2;    /* stock MPY/MPYH */
 256
 257                        if (cpu->extn_mpy.dsp)  /* OPT 7-9 */
 258                                opt = cpu->extn_mpy.dsp + 6;
 259
 260                        n += scnprintf(buf + n, len - n, "mpy[opt %d] ", opt);
 261                }
 262        }
 263
 264        n += scnprintf(buf + n, len - n, "%s%s%s%s%s%s%s%s\n",
 265                       IS_AVAIL1(cpu->isa.div_rem, "div_rem "),
 266                       IS_AVAIL1(cpu->extn.norm, "norm "),
 267                       IS_AVAIL1(cpu->extn.barrel, "barrel-shift "),
 268                       IS_AVAIL1(cpu->extn.swap, "swap "),
 269                       IS_AVAIL1(cpu->extn.minmax, "minmax "),
 270                       IS_AVAIL1(cpu->extn.crc, "crc "),
 271                       IS_AVAIL2(1, "swape", CONFIG_ARC_HAS_SWAPE));
 272
 273        if (cpu->bpu.ver)
 274                n += scnprintf(buf + n, len - n,
 275                              "BPU\t\t: %s%s match, cache:%d, Predict Table:%d\n",
 276                              IS_AVAIL1(cpu->bpu.full, "full"),
 277                              IS_AVAIL1(!cpu->bpu.full, "partial"),
 278                              cpu->bpu.num_cache, cpu->bpu.num_pred);
 279
 280        return buf;
 281}
 282
 283static char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
 284{
 285        int n = 0;
 286        struct cpuinfo_arc *cpu = &cpuinfo_arc700[cpu_id];
 287
 288        FIX_PTR(cpu);
 289
 290        n += scnprintf(buf + n, len - n,
 291                       "Vector Table\t: %#x\nUncached Base\t: %#x\n",
 292                       cpu->vec_base, ARC_UNCACHED_ADDR_SPACE);
 293
 294        if (cpu->extn.fpu_sp || cpu->extn.fpu_dp)
 295                n += scnprintf(buf + n, len - n, "FPU\t\t: %s%s\n",
 296                               IS_AVAIL1(cpu->extn.fpu_sp, "SP "),
 297                               IS_AVAIL1(cpu->extn.fpu_dp, "DP "));
 298
 299        if (cpu->extn.debug)
 300                n += scnprintf(buf + n, len - n, "DEBUG\t\t: %s%s%s\n",
 301                               IS_AVAIL1(cpu->extn.ap, "ActionPoint "),
 302                               IS_AVAIL1(cpu->extn.smart, "smaRT "),
 303                               IS_AVAIL1(cpu->extn.rtt, "RTT "));
 304
 305        if (cpu->dccm.sz || cpu->iccm.sz)
 306                n += scnprintf(buf + n, len - n, "Extn [CCM]\t: DCCM @ %x, %d KB / ICCM: @ %x, %d KB\n",
 307                               cpu->dccm.base_addr, TO_KB(cpu->dccm.sz),
 308                               cpu->iccm.base_addr, TO_KB(cpu->iccm.sz));
 309
 310        n += scnprintf(buf + n, len - n,
 311                       "OS ABI [v3]\t: no-legacy-syscalls\n");
 312
 313        return buf;
 314}
 315
 316static void arc_chk_core_config(void)
 317{
 318        struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
 319        int fpu_enabled;
 320
 321        if (!cpu->extn.timer0)
 322                panic("Timer0 is not present!\n");
 323
 324        if (!cpu->extn.timer1)
 325                panic("Timer1 is not present!\n");
 326
 327        if (IS_ENABLED(CONFIG_ARC_HAS_RTC) && !cpu->extn.rtc)
 328                panic("RTC is not present\n");
 329
 330#ifdef CONFIG_ARC_HAS_DCCM
 331        /*
 332         * DCCM can be arbit placed in hardware.
 333         * Make sure it's placement/sz matches what Linux is built with
 334         */
 335        if ((unsigned int)__arc_dccm_base != cpu->dccm.base_addr)
 336                panic("Linux built with incorrect DCCM Base address\n");
 337
 338        if (CONFIG_ARC_DCCM_SZ != cpu->dccm.sz)
 339                panic("Linux built with incorrect DCCM Size\n");
 340#endif
 341
 342#ifdef CONFIG_ARC_HAS_ICCM
 343        if (CONFIG_ARC_ICCM_SZ != cpu->iccm.sz)
 344                panic("Linux built with incorrect ICCM Size\n");
 345#endif
 346
 347        /*
 348         * FP hardware/software config sanity
 349         * -If hardware contains DPFP, kernel needs to save/restore FPU state
 350         * -If not, it will crash trying to save/restore the non-existant regs
 351         *
 352         * (only DPDP checked since SP has no arch visible regs)
 353         */
 354        fpu_enabled = IS_ENABLED(CONFIG_ARC_FPU_SAVE_RESTORE);
 355
 356        if (cpu->extn.fpu_dp && !fpu_enabled)
 357                pr_warn("CONFIG_ARC_FPU_SAVE_RESTORE needed for working apps\n");
 358        else if (!cpu->extn.fpu_dp && fpu_enabled)
 359                panic("FPU non-existent, disable CONFIG_ARC_FPU_SAVE_RESTORE\n");
 360
 361        if (is_isa_arcv2() && IS_ENABLED(CONFIG_SMP) && cpu->isa.atomic &&
 362            IS_ENABLED(CONFIG_ARC_HAS_LLSC) &&
 363            !IS_ENABLED(CONFIG_ARC_STAR_9000923308))
 364                panic("llock/scond livelock workaround missing\n");
 365}
 366
 367/*
 368 * Initialize and setup the processor core
 369 * This is called by all the CPUs thus should not do special case stuff
 370 *    such as only for boot CPU etc
 371 */
 372
 373void setup_processor(void)
 374{
 375        char str[512];
 376        int cpu_id = smp_processor_id();
 377
 378        read_arc_build_cfg_regs();
 379        arc_init_IRQ();
 380
 381        printk(arc_cpu_mumbojumbo(cpu_id, str, sizeof(str)));
 382
 383        arc_mmu_init();
 384        arc_cache_init();
 385
 386        printk(arc_extn_mumbojumbo(cpu_id, str, sizeof(str)));
 387        printk(arc_platform_smp_cpuinfo());
 388
 389        arc_chk_core_config();
 390}
 391
 392static inline int is_kernel(unsigned long addr)
 393{
 394        if (addr >= (unsigned long)_stext && addr <= (unsigned long)_end)
 395                return 1;
 396        return 0;
 397}
 398
 399void __init setup_arch(char **cmdline_p)
 400{
 401#ifdef CONFIG_ARC_UBOOT_SUPPORT
 402        /* make sure that uboot passed pointer to cmdline/dtb is valid */
 403        if (uboot_tag && is_kernel((unsigned long)uboot_arg))
 404                panic("Invalid uboot arg\n");
 405
 406        /* See if u-boot passed an external Device Tree blob */
 407        machine_desc = setup_machine_fdt(uboot_arg);    /* uboot_tag == 2 */
 408        if (!machine_desc)
 409#endif
 410        {
 411                /* No, so try the embedded one */
 412                machine_desc = setup_machine_fdt(__dtb_start);
 413                if (!machine_desc)
 414                        panic("Embedded DT invalid\n");
 415
 416                /*
 417                 * If we are here, it is established that @uboot_arg didn't
 418                 * point to DT blob. Instead if u-boot says it is cmdline,
 419                 * Appent to embedded DT cmdline.
 420                 * setup_machine_fdt() would have populated @boot_command_line
 421                 */
 422                if (uboot_tag == 1) {
 423                        /* Ensure a whitespace between the 2 cmdlines */
 424                        strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
 425                        strlcat(boot_command_line, uboot_arg,
 426                                COMMAND_LINE_SIZE);
 427                }
 428        }
 429
 430        /* Save unparsed command line copy for /proc/cmdline */
 431        *cmdline_p = boot_command_line;
 432
 433        /* To force early parsing of things like mem=xxx */
 434        parse_early_param();
 435
 436        /* Platform/board specific: e.g. early console registration */
 437        if (machine_desc->init_early)
 438                machine_desc->init_early();
 439
 440        smp_init_cpus();
 441
 442        setup_processor();
 443        setup_arch_memory();
 444
 445        /* copy flat DT out of .init and then unflatten it */
 446        unflatten_and_copy_device_tree();
 447
 448        /* Can be issue if someone passes cmd line arg "ro"
 449         * But that is unlikely so keeping it as it is
 450         */
 451        root_mountflags &= ~MS_RDONLY;
 452
 453#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
 454        conswitchp = &dummy_con;
 455#endif
 456
 457        arc_unwind_init();
 458}
 459
 460static int __init customize_machine(void)
 461{
 462        of_clk_init(NULL);
 463        /*
 464         * Traverses flattened DeviceTree - registering platform devices
 465         * (if any) complete with their resources
 466         */
 467        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 468
 469        if (machine_desc->init_machine)
 470                machine_desc->init_machine();
 471
 472        return 0;
 473}
 474arch_initcall(customize_machine);
 475
 476static int __init init_late_machine(void)
 477{
 478        if (machine_desc->init_late)
 479                machine_desc->init_late();
 480
 481        return 0;
 482}
 483late_initcall(init_late_machine);
 484/*
 485 *  Get CPU information for use by the procfs.
 486 */
 487
 488#define cpu_to_ptr(c)   ((void *)(0xFFFF0000 | (unsigned int)(c)))
 489#define ptr_to_cpu(p)   (~0xFFFF0000UL & (unsigned int)(p))
 490
 491static int show_cpuinfo(struct seq_file *m, void *v)
 492{
 493        char *str;
 494        int cpu_id = ptr_to_cpu(v);
 495
 496        if (!cpu_online(cpu_id)) {
 497                seq_printf(m, "processor [%d]\t: Offline\n", cpu_id);
 498                goto done;
 499        }
 500
 501        str = (char *)__get_free_page(GFP_TEMPORARY);
 502        if (!str)
 503                goto done;
 504
 505        seq_printf(m, arc_cpu_mumbojumbo(cpu_id, str, PAGE_SIZE));
 506
 507        seq_printf(m, "Bogo MIPS\t: %lu.%02lu\n",
 508                   loops_per_jiffy / (500000 / HZ),
 509                   (loops_per_jiffy / (5000 / HZ)) % 100);
 510
 511        seq_printf(m, arc_mmu_mumbojumbo(cpu_id, str, PAGE_SIZE));
 512        seq_printf(m, arc_cache_mumbojumbo(cpu_id, str, PAGE_SIZE));
 513        seq_printf(m, arc_extn_mumbojumbo(cpu_id, str, PAGE_SIZE));
 514        seq_printf(m, arc_platform_smp_cpuinfo());
 515
 516        free_page((unsigned long)str);
 517done:
 518        seq_printf(m, "\n");
 519
 520        return 0;
 521}
 522
 523static void *c_start(struct seq_file *m, loff_t *pos)
 524{
 525        /*
 526         * Callback returns cpu-id to iterator for show routine, NULL to stop.
 527         * However since NULL is also a valid cpu-id (0), we use a round-about
 528         * way to pass it w/o having to kmalloc/free a 2 byte string.
 529         * Encode cpu-id as 0xFFcccc, which is decoded by show routine.
 530         */
 531        return *pos < num_possible_cpus() ? cpu_to_ptr(*pos) : NULL;
 532}
 533
 534static void *c_next(struct seq_file *m, void *v, loff_t *pos)
 535{
 536        ++*pos;
 537        return c_start(m, pos);
 538}
 539
 540static void c_stop(struct seq_file *m, void *v)
 541{
 542}
 543
 544const struct seq_operations cpuinfo_op = {
 545        .start  = c_start,
 546        .next   = c_next,
 547        .stop   = c_stop,
 548        .show   = show_cpuinfo
 549};
 550
 551static DEFINE_PER_CPU(struct cpu, cpu_topology);
 552
 553static int __init topology_init(void)
 554{
 555        int cpu;
 556
 557        for_each_present_cpu(cpu)
 558            register_cpu(&per_cpu(cpu_topology, cpu), cpu);
 559
 560        return 0;
 561}
 562
 563subsys_initcall(topology_init);
 564