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