Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
0004  */
0005 
0006 #include <linux/seq_file.h>
0007 #include <linux/fs.h>
0008 #include <linux/delay.h>
0009 #include <linux/root_dev.h>
0010 #include <linux/clk.h>
0011 #include <linux/clocksource.h>
0012 #include <linux/console.h>
0013 #include <linux/module.h>
0014 #include <linux/sizes.h>
0015 #include <linux/cpu.h>
0016 #include <linux/of_clk.h>
0017 #include <linux/of_fdt.h>
0018 #include <linux/of.h>
0019 #include <linux/cache.h>
0020 #include <uapi/linux/mount.h>
0021 #include <asm/sections.h>
0022 #include <asm/arcregs.h>
0023 #include <asm/asserts.h>
0024 #include <asm/tlb.h>
0025 #include <asm/setup.h>
0026 #include <asm/page.h>
0027 #include <asm/irq.h>
0028 #include <asm/unwind.h>
0029 #include <asm/mach_desc.h>
0030 #include <asm/smp.h>
0031 #include <asm/dsp-impl.h>
0032 
0033 #define FIX_PTR(x)  __asm__ __volatile__(";" : "+r"(x))
0034 
0035 unsigned int intr_to_DE_cnt;
0036 
0037 /* Part of U-boot ABI: see head.S */
0038 int __initdata uboot_tag;
0039 int __initdata uboot_magic;
0040 char __initdata *uboot_arg;
0041 
0042 const struct machine_desc *machine_desc;
0043 
0044 struct task_struct *_current_task[NR_CPUS]; /* For stack switching */
0045 
0046 struct cpuinfo_arc cpuinfo_arc700[NR_CPUS];
0047 
0048 static const struct id_to_str arc_legacy_rel[] = {
0049     /* ID.ARCVER,   Release */
0050 #ifdef CONFIG_ISA_ARCOMPACT
0051     { 0x34,     "R4.10"},
0052     { 0x35,     "R4.11"},
0053 #else
0054     { 0x51,     "R2.0" },
0055     { 0x52,     "R2.1" },
0056     { 0x53,     "R3.0" },
0057 #endif
0058     { 0x00,     NULL   }
0059 };
0060 
0061 static const struct id_to_str arc_hs_ver54_rel[] = {
0062     /* UARCH.MAJOR, Release */
0063     {  0,       "R3.10a"},
0064     {  1,       "R3.50a"},
0065     {  2,       "R3.60a"},
0066     {  3,       "R4.00a"},
0067     {  0xFF,    NULL   }
0068 };
0069 
0070 static void read_decode_ccm_bcr(struct cpuinfo_arc *cpu)
0071 {
0072     if (is_isa_arcompact()) {
0073         struct bcr_iccm_arcompact iccm;
0074         struct bcr_dccm_arcompact dccm;
0075 
0076         READ_BCR(ARC_REG_ICCM_BUILD, iccm);
0077         if (iccm.ver) {
0078             cpu->iccm.sz = 4096 << iccm.sz; /* 8K to 512K */
0079             cpu->iccm.base_addr = iccm.base << 16;
0080         }
0081 
0082         READ_BCR(ARC_REG_DCCM_BUILD, dccm);
0083         if (dccm.ver) {
0084             unsigned long base;
0085             cpu->dccm.sz = 2048 << dccm.sz; /* 2K to 256K */
0086 
0087             base = read_aux_reg(ARC_REG_DCCM_BASE_BUILD);
0088             cpu->dccm.base_addr = base & ~0xF;
0089         }
0090     } else {
0091         struct bcr_iccm_arcv2 iccm;
0092         struct bcr_dccm_arcv2 dccm;
0093         unsigned long region;
0094 
0095         READ_BCR(ARC_REG_ICCM_BUILD, iccm);
0096         if (iccm.ver) {
0097             cpu->iccm.sz = 256 << iccm.sz00;    /* 512B to 16M */
0098             if (iccm.sz00 == 0xF && iccm.sz01 > 0)
0099                 cpu->iccm.sz <<= iccm.sz01;
0100 
0101             region = read_aux_reg(ARC_REG_AUX_ICCM);
0102             cpu->iccm.base_addr = region & 0xF0000000;
0103         }
0104 
0105         READ_BCR(ARC_REG_DCCM_BUILD, dccm);
0106         if (dccm.ver) {
0107             cpu->dccm.sz = 256 << dccm.sz0;
0108             if (dccm.sz0 == 0xF && dccm.sz1 > 0)
0109                 cpu->dccm.sz <<= dccm.sz1;
0110 
0111             region = read_aux_reg(ARC_REG_AUX_DCCM);
0112             cpu->dccm.base_addr = region & 0xF0000000;
0113         }
0114     }
0115 }
0116 
0117 static void decode_arc_core(struct cpuinfo_arc *cpu)
0118 {
0119     struct bcr_uarch_build_arcv2 uarch;
0120     const struct id_to_str *tbl;
0121 
0122     if (cpu->core.family < 0x54) { /* includes arc700 */
0123 
0124         for (tbl = &arc_legacy_rel[0]; tbl->id != 0; tbl++) {
0125             if (cpu->core.family == tbl->id) {
0126                 cpu->release = tbl->str;
0127                 break;
0128             }
0129         }
0130 
0131         if (is_isa_arcompact())
0132             cpu->name = "ARC700";
0133         else if (tbl->str)
0134             cpu->name = "HS38";
0135         else
0136             cpu->name = cpu->release = "Unknown";
0137 
0138         return;
0139     }
0140 
0141     /*
0142      * Initial HS cores bumped AUX IDENTITY.ARCVER for each release until
0143      * ARCVER 0x54 which introduced AUX MICRO_ARCH_BUILD and subsequent
0144      * releases only update it.
0145      */
0146     READ_BCR(ARC_REG_MICRO_ARCH_BCR, uarch);
0147 
0148     if (uarch.prod == 4) {
0149         cpu->name = "HS48";
0150         cpu->extn.dual = 1;
0151 
0152     } else {
0153         cpu->name = "HS38";
0154     }
0155 
0156     for (tbl = &arc_hs_ver54_rel[0]; tbl->id != 0xFF; tbl++) {
0157         if (uarch.maj == tbl->id) {
0158             cpu->release = tbl->str;
0159             break;
0160         }
0161     }
0162 }
0163 
0164 static void read_arc_build_cfg_regs(void)
0165 {
0166     struct bcr_timer timer;
0167     struct bcr_generic bcr;
0168     struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
0169     struct bcr_isa_arcv2 isa;
0170     struct bcr_actionpoint ap;
0171 
0172     FIX_PTR(cpu);
0173 
0174     READ_BCR(AUX_IDENTITY, cpu->core);
0175     decode_arc_core(cpu);
0176 
0177     READ_BCR(ARC_REG_TIMERS_BCR, timer);
0178     cpu->extn.timer0 = timer.t0;
0179     cpu->extn.timer1 = timer.t1;
0180     cpu->extn.rtc = timer.rtc;
0181 
0182     cpu->vec_base = read_aux_reg(AUX_INTR_VEC_BASE);
0183 
0184     READ_BCR(ARC_REG_MUL_BCR, cpu->extn_mpy);
0185 
0186     /* Read CCM BCRs for boot reporting even if not enabled in Kconfig */
0187     read_decode_ccm_bcr(cpu);
0188 
0189     read_decode_mmu_bcr();
0190     read_decode_cache_bcr();
0191 
0192     if (is_isa_arcompact()) {
0193         struct bcr_fp_arcompact sp, dp;
0194         struct bcr_bpu_arcompact bpu;
0195 
0196         READ_BCR(ARC_REG_FP_BCR, sp);
0197         READ_BCR(ARC_REG_DPFP_BCR, dp);
0198         cpu->extn.fpu_sp = sp.ver ? 1 : 0;
0199         cpu->extn.fpu_dp = dp.ver ? 1 : 0;
0200 
0201         READ_BCR(ARC_REG_BPU_BCR, bpu);
0202         cpu->bpu.ver = bpu.ver;
0203         cpu->bpu.full = bpu.fam ? 1 : 0;
0204         if (bpu.ent) {
0205             cpu->bpu.num_cache = 256 << (bpu.ent - 1);
0206             cpu->bpu.num_pred = 256 << (bpu.ent - 1);
0207         }
0208     } else {
0209         struct bcr_fp_arcv2 spdp;
0210         struct bcr_bpu_arcv2 bpu;
0211 
0212         READ_BCR(ARC_REG_FP_V2_BCR, spdp);
0213         cpu->extn.fpu_sp = spdp.sp ? 1 : 0;
0214         cpu->extn.fpu_dp = spdp.dp ? 1 : 0;
0215 
0216         READ_BCR(ARC_REG_BPU_BCR, bpu);
0217         cpu->bpu.ver = bpu.ver;
0218         cpu->bpu.full = bpu.ft;
0219         cpu->bpu.num_cache = 256 << bpu.bce;
0220         cpu->bpu.num_pred = 2048 << bpu.pte;
0221         cpu->bpu.ret_stk = 4 << bpu.rse;
0222 
0223         /* if dual issue hardware, is it enabled ? */
0224         if (cpu->extn.dual) {
0225             unsigned int exec_ctrl;
0226 
0227             READ_BCR(AUX_EXEC_CTRL, exec_ctrl);
0228             cpu->extn.dual_enb = !(exec_ctrl & 1);
0229         }
0230     }
0231 
0232     READ_BCR(ARC_REG_AP_BCR, ap);
0233     if (ap.ver) {
0234         cpu->extn.ap_num = 2 << ap.num;
0235         cpu->extn.ap_full = !ap.min;
0236     }
0237 
0238     READ_BCR(ARC_REG_SMART_BCR, bcr);
0239     cpu->extn.smart = bcr.ver ? 1 : 0;
0240 
0241     READ_BCR(ARC_REG_RTT_BCR, bcr);
0242     cpu->extn.rtt = bcr.ver ? 1 : 0;
0243 
0244     READ_BCR(ARC_REG_ISA_CFG_BCR, isa);
0245 
0246     /* some hacks for lack of feature BCR info in old ARC700 cores */
0247     if (is_isa_arcompact()) {
0248         if (!isa.ver)   /* ISA BCR absent, use Kconfig info */
0249             cpu->isa.atomic = IS_ENABLED(CONFIG_ARC_HAS_LLSC);
0250         else {
0251             /* ARC700_BUILD only has 2 bits of isa info */
0252             struct bcr_generic bcr = *(struct bcr_generic *)&isa;
0253             cpu->isa.atomic = bcr.info & 1;
0254         }
0255 
0256         cpu->isa.be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);
0257 
0258          /* there's no direct way to distinguish 750 vs. 770 */
0259         if (unlikely(cpu->core.family < 0x34 || cpu->mmu.ver < 3))
0260             cpu->name = "ARC750";
0261     } else {
0262         cpu->isa = isa;
0263     }
0264 }
0265 
0266 static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len)
0267 {
0268     struct cpuinfo_arc *cpu = &cpuinfo_arc700[cpu_id];
0269     struct bcr_identity *core = &cpu->core;
0270     char mpy_opt[16];
0271     int n = 0;
0272 
0273     FIX_PTR(cpu);
0274 
0275     n += scnprintf(buf + n, len - n,
0276                "\nIDENTITY\t: ARCVER [%#02x] ARCNUM [%#02x] CHIPID [%#4x]\n",
0277                core->family, core->cpu_id, core->chip_id);
0278 
0279     n += scnprintf(buf + n, len - n, "processor [%d]\t: %s %s (%s ISA) %s%s%s\n",
0280                cpu_id, cpu->name, cpu->release,
0281                is_isa_arcompact() ? "ARCompact" : "ARCv2",
0282                IS_AVAIL1(cpu->isa.be, "[Big-Endian]"),
0283                IS_AVAIL3(cpu->extn.dual, cpu->extn.dual_enb, " Dual-Issue "));
0284 
0285     n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s%s%s\nISA Extn\t: ",
0286                IS_AVAIL1(cpu->extn.timer0, "Timer0 "),
0287                IS_AVAIL1(cpu->extn.timer1, "Timer1 "),
0288                IS_AVAIL2(cpu->extn.rtc, "RTC [UP 64-bit] ", CONFIG_ARC_TIMERS_64BIT),
0289                IS_AVAIL2(cpu->extn.gfrc, "GFRC [SMP 64-bit] ", CONFIG_ARC_TIMERS_64BIT));
0290 
0291     if (cpu->extn_mpy.ver) {
0292         if (is_isa_arcompact()) {
0293             scnprintf(mpy_opt, 16, "mpy");
0294         } else {
0295 
0296             int opt = 2;    /* stock MPY/MPYH */
0297 
0298             if (cpu->extn_mpy.dsp)  /* OPT 7-9 */
0299                 opt = cpu->extn_mpy.dsp + 6;
0300 
0301             scnprintf(mpy_opt, 16, "mpy[opt %d] ", opt);
0302         }
0303     }
0304 
0305     n += scnprintf(buf + n, len - n, "%s%s%s%s%s%s%s%s\n",
0306                IS_AVAIL2(cpu->isa.atomic, "atomic ", CONFIG_ARC_HAS_LLSC),
0307                IS_AVAIL2(cpu->isa.ldd, "ll64 ", CONFIG_ARC_HAS_LL64),
0308                IS_AVAIL2(cpu->isa.unalign, "unalign ", CONFIG_ARC_USE_UNALIGNED_MEM_ACCESS),
0309                IS_AVAIL1(cpu->extn_mpy.ver, mpy_opt),
0310                IS_AVAIL1(cpu->isa.div_rem, "div_rem "));
0311 
0312     if (cpu->bpu.ver) {
0313         n += scnprintf(buf + n, len - n,
0314                   "BPU\t\t: %s%s match, cache:%d, Predict Table:%d Return stk: %d",
0315                   IS_AVAIL1(cpu->bpu.full, "full"),
0316                   IS_AVAIL1(!cpu->bpu.full, "partial"),
0317                   cpu->bpu.num_cache, cpu->bpu.num_pred, cpu->bpu.ret_stk);
0318 
0319         if (is_isa_arcv2()) {
0320             struct bcr_lpb lpb;
0321 
0322             READ_BCR(ARC_REG_LPB_BUILD, lpb);
0323             if (lpb.ver) {
0324                 unsigned int ctl;
0325                 ctl = read_aux_reg(ARC_REG_LPB_CTRL);
0326 
0327                 n += scnprintf(buf + n, len - n, " Loop Buffer:%d %s",
0328                            lpb.entries,
0329                            IS_DISABLED_RUN(!ctl));
0330             }
0331         }
0332         n += scnprintf(buf + n, len - n, "\n");
0333     }
0334 
0335     return buf;
0336 }
0337 
0338 static char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
0339 {
0340     int n = 0;
0341     struct cpuinfo_arc *cpu = &cpuinfo_arc700[cpu_id];
0342 
0343     FIX_PTR(cpu);
0344 
0345     n += scnprintf(buf + n, len - n, "Vector Table\t: %#x\n", cpu->vec_base);
0346 
0347     if (cpu->extn.fpu_sp || cpu->extn.fpu_dp)
0348         n += scnprintf(buf + n, len - n, "FPU\t\t: %s%s\n",
0349                    IS_AVAIL1(cpu->extn.fpu_sp, "SP "),
0350                    IS_AVAIL1(cpu->extn.fpu_dp, "DP "));
0351 
0352     if (cpu->extn.ap_num | cpu->extn.smart | cpu->extn.rtt) {
0353         n += scnprintf(buf + n, len - n, "DEBUG\t\t: %s%s",
0354                    IS_AVAIL1(cpu->extn.smart, "smaRT "),
0355                    IS_AVAIL1(cpu->extn.rtt, "RTT "));
0356         if (cpu->extn.ap_num) {
0357             n += scnprintf(buf + n, len - n, "ActionPoint %d/%s",
0358                        cpu->extn.ap_num,
0359                        cpu->extn.ap_full ? "full":"min");
0360         }
0361         n += scnprintf(buf + n, len - n, "\n");
0362     }
0363 
0364     if (cpu->dccm.sz || cpu->iccm.sz)
0365         n += scnprintf(buf + n, len - n, "Extn [CCM]\t: DCCM @ %x, %d KB / ICCM: @ %x, %d KB\n",
0366                    cpu->dccm.base_addr, TO_KB(cpu->dccm.sz),
0367                    cpu->iccm.base_addr, TO_KB(cpu->iccm.sz));
0368 
0369     if (is_isa_arcv2()) {
0370 
0371         /* Error Protection: ECC/Parity */
0372         struct bcr_erp erp;
0373         READ_BCR(ARC_REG_ERP_BUILD, erp);
0374 
0375         if (erp.ver) {
0376             struct  ctl_erp ctl;
0377             READ_BCR(ARC_REG_ERP_CTRL, ctl);
0378 
0379             /* inverted bits: 0 means enabled */
0380             n += scnprintf(buf + n, len - n, "Extn [ECC]\t: %s%s%s%s%s%s\n",
0381                 IS_AVAIL3(erp.ic,  !ctl.dpi, "IC "),
0382                 IS_AVAIL3(erp.dc,  !ctl.dpd, "DC "),
0383                 IS_AVAIL3(erp.mmu, !ctl.mpd, "MMU "));
0384         }
0385     }
0386 
0387     return buf;
0388 }
0389 
0390 void chk_opt_strict(char *opt_name, bool hw_exists, bool opt_ena)
0391 {
0392     if (hw_exists && !opt_ena)
0393         pr_warn(" ! Enable %s for working apps\n", opt_name);
0394     else if (!hw_exists && opt_ena)
0395         panic("Disable %s, hardware NOT present\n", opt_name);
0396 }
0397 
0398 void chk_opt_weak(char *opt_name, bool hw_exists, bool opt_ena)
0399 {
0400     if (!hw_exists && opt_ena)
0401         panic("Disable %s, hardware NOT present\n", opt_name);
0402 }
0403 
0404 static void arc_chk_core_config(void)
0405 {
0406     struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
0407     int present = 0;
0408 
0409     if (!cpu->extn.timer0)
0410         panic("Timer0 is not present!\n");
0411 
0412     if (!cpu->extn.timer1)
0413         panic("Timer1 is not present!\n");
0414 
0415 #ifdef CONFIG_ARC_HAS_DCCM
0416     /*
0417      * DCCM can be arbit placed in hardware.
0418      * Make sure it's placement/sz matches what Linux is built with
0419      */
0420     if ((unsigned int)__arc_dccm_base != cpu->dccm.base_addr)
0421         panic("Linux built with incorrect DCCM Base address\n");
0422 
0423     if (CONFIG_ARC_DCCM_SZ * SZ_1K != cpu->dccm.sz)
0424         panic("Linux built with incorrect DCCM Size\n");
0425 #endif
0426 
0427 #ifdef CONFIG_ARC_HAS_ICCM
0428     if (CONFIG_ARC_ICCM_SZ * SZ_1K != cpu->iccm.sz)
0429         panic("Linux built with incorrect ICCM Size\n");
0430 #endif
0431 
0432     /*
0433      * FP hardware/software config sanity
0434      * -If hardware present, kernel needs to save/restore FPU state
0435      * -If not, it will crash trying to save/restore the non-existant regs
0436      */
0437 
0438     if (is_isa_arcompact()) {
0439         /* only DPDP checked since SP has no arch visible regs */
0440         present = cpu->extn.fpu_dp;
0441         CHK_OPT_STRICT(CONFIG_ARC_FPU_SAVE_RESTORE, present);
0442     } else {
0443         /* Accumulator Low:High pair (r58:59) present if DSP MPY or FPU */
0444         present = cpu->extn_mpy.dsp | cpu->extn.fpu_sp | cpu->extn.fpu_dp;
0445         CHK_OPT_STRICT(CONFIG_ARC_HAS_ACCL_REGS, present);
0446 
0447         dsp_config_check();
0448     }
0449 }
0450 
0451 /*
0452  * Initialize and setup the processor core
0453  * This is called by all the CPUs thus should not do special case stuff
0454  *    such as only for boot CPU etc
0455  */
0456 
0457 void setup_processor(void)
0458 {
0459     char str[512];
0460     int cpu_id = smp_processor_id();
0461 
0462     read_arc_build_cfg_regs();
0463     arc_init_IRQ();
0464 
0465     pr_info("%s", arc_cpu_mumbojumbo(cpu_id, str, sizeof(str)));
0466 
0467     arc_mmu_init();
0468     arc_cache_init();
0469 
0470     pr_info("%s", arc_extn_mumbojumbo(cpu_id, str, sizeof(str)));
0471     pr_info("%s", arc_platform_smp_cpuinfo());
0472 
0473     arc_chk_core_config();
0474 }
0475 
0476 static inline bool uboot_arg_invalid(unsigned long addr)
0477 {
0478     /*
0479      * Check that it is a untranslated address (although MMU is not enabled
0480      * yet, it being a high address ensures this is not by fluke)
0481      */
0482     if (addr < PAGE_OFFSET)
0483         return true;
0484 
0485     /* Check that address doesn't clobber resident kernel image */
0486     return addr >= (unsigned long)_stext && addr <= (unsigned long)_end;
0487 }
0488 
0489 #define IGNORE_ARGS     "Ignore U-boot args: "
0490 
0491 /* uboot_tag values for U-boot - kernel ABI revision 0; see head.S */
0492 #define UBOOT_TAG_NONE      0
0493 #define UBOOT_TAG_CMDLINE   1
0494 #define UBOOT_TAG_DTB       2
0495 /* We always pass 0 as magic from U-boot */
0496 #define UBOOT_MAGIC_VALUE   0
0497 
0498 void __init handle_uboot_args(void)
0499 {
0500     bool use_embedded_dtb = true;
0501     bool append_cmdline = false;
0502 
0503     /* check that we know this tag */
0504     if (uboot_tag != UBOOT_TAG_NONE &&
0505         uboot_tag != UBOOT_TAG_CMDLINE &&
0506         uboot_tag != UBOOT_TAG_DTB) {
0507         pr_warn(IGNORE_ARGS "invalid uboot tag: '%08x'\n", uboot_tag);
0508         goto ignore_uboot_args;
0509     }
0510 
0511     if (uboot_magic != UBOOT_MAGIC_VALUE) {
0512         pr_warn(IGNORE_ARGS "non zero uboot magic\n");
0513         goto ignore_uboot_args;
0514     }
0515 
0516     if (uboot_tag != UBOOT_TAG_NONE &&
0517             uboot_arg_invalid((unsigned long)uboot_arg)) {
0518         pr_warn(IGNORE_ARGS "invalid uboot arg: '%px'\n", uboot_arg);
0519         goto ignore_uboot_args;
0520     }
0521 
0522     /* see if U-boot passed an external Device Tree blob */
0523     if (uboot_tag == UBOOT_TAG_DTB) {
0524         machine_desc = setup_machine_fdt((void *)uboot_arg);
0525 
0526         /* external Device Tree blob is invalid - use embedded one */
0527         use_embedded_dtb = !machine_desc;
0528     }
0529 
0530     if (uboot_tag == UBOOT_TAG_CMDLINE)
0531         append_cmdline = true;
0532 
0533 ignore_uboot_args:
0534 
0535     if (use_embedded_dtb) {
0536         machine_desc = setup_machine_fdt(__dtb_start);
0537         if (!machine_desc)
0538             panic("Embedded DT invalid\n");
0539     }
0540 
0541     /*
0542      * NOTE: @boot_command_line is populated by setup_machine_fdt() so this
0543      * append processing can only happen after.
0544      */
0545     if (append_cmdline) {
0546         /* Ensure a whitespace between the 2 cmdlines */
0547         strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
0548         strlcat(boot_command_line, uboot_arg, COMMAND_LINE_SIZE);
0549     }
0550 }
0551 
0552 void __init setup_arch(char **cmdline_p)
0553 {
0554     handle_uboot_args();
0555 
0556     /* Save unparsed command line copy for /proc/cmdline */
0557     *cmdline_p = boot_command_line;
0558 
0559     /* To force early parsing of things like mem=xxx */
0560     parse_early_param();
0561 
0562     /* Platform/board specific: e.g. early console registration */
0563     if (machine_desc->init_early)
0564         machine_desc->init_early();
0565 
0566     smp_init_cpus();
0567 
0568     setup_processor();
0569     setup_arch_memory();
0570 
0571     /* copy flat DT out of .init and then unflatten it */
0572     unflatten_and_copy_device_tree();
0573 
0574     /* Can be issue if someone passes cmd line arg "ro"
0575      * But that is unlikely so keeping it as it is
0576      */
0577     root_mountflags &= ~MS_RDONLY;
0578 
0579     arc_unwind_init();
0580 }
0581 
0582 /*
0583  * Called from start_kernel() - boot CPU only
0584  */
0585 void __init time_init(void)
0586 {
0587     of_clk_init(NULL);
0588     timer_probe();
0589 }
0590 
0591 static int __init customize_machine(void)
0592 {
0593     if (machine_desc->init_machine)
0594         machine_desc->init_machine();
0595 
0596     return 0;
0597 }
0598 arch_initcall(customize_machine);
0599 
0600 static int __init init_late_machine(void)
0601 {
0602     if (machine_desc->init_late)
0603         machine_desc->init_late();
0604 
0605     return 0;
0606 }
0607 late_initcall(init_late_machine);
0608 /*
0609  *  Get CPU information for use by the procfs.
0610  */
0611 
0612 #define cpu_to_ptr(c)   ((void *)(0xFFFF0000 | (unsigned int)(c)))
0613 #define ptr_to_cpu(p)   (~0xFFFF0000UL & (unsigned int)(p))
0614 
0615 static int show_cpuinfo(struct seq_file *m, void *v)
0616 {
0617     char *str;
0618     int cpu_id = ptr_to_cpu(v);
0619     struct device *cpu_dev = get_cpu_device(cpu_id);
0620     struct clk *cpu_clk;
0621     unsigned long freq = 0;
0622 
0623     if (!cpu_online(cpu_id)) {
0624         seq_printf(m, "processor [%d]\t: Offline\n", cpu_id);
0625         goto done;
0626     }
0627 
0628     str = (char *)__get_free_page(GFP_KERNEL);
0629     if (!str)
0630         goto done;
0631 
0632     seq_printf(m, arc_cpu_mumbojumbo(cpu_id, str, PAGE_SIZE));
0633 
0634     cpu_clk = clk_get(cpu_dev, NULL);
0635     if (IS_ERR(cpu_clk)) {
0636         seq_printf(m, "CPU speed \t: Cannot get clock for processor [%d]\n",
0637                cpu_id);
0638     } else {
0639         freq = clk_get_rate(cpu_clk);
0640     }
0641     if (freq)
0642         seq_printf(m, "CPU speed\t: %lu.%02lu Mhz\n",
0643                freq / 1000000, (freq / 10000) % 100);
0644 
0645     seq_printf(m, "Bogo MIPS\t: %lu.%02lu\n",
0646            loops_per_jiffy / (500000 / HZ),
0647            (loops_per_jiffy / (5000 / HZ)) % 100);
0648 
0649     seq_printf(m, arc_mmu_mumbojumbo(cpu_id, str, PAGE_SIZE));
0650     seq_printf(m, arc_cache_mumbojumbo(cpu_id, str, PAGE_SIZE));
0651     seq_printf(m, arc_extn_mumbojumbo(cpu_id, str, PAGE_SIZE));
0652     seq_printf(m, arc_platform_smp_cpuinfo());
0653 
0654     free_page((unsigned long)str);
0655 done:
0656     seq_printf(m, "\n");
0657 
0658     return 0;
0659 }
0660 
0661 static void *c_start(struct seq_file *m, loff_t *pos)
0662 {
0663     /*
0664      * Callback returns cpu-id to iterator for show routine, NULL to stop.
0665      * However since NULL is also a valid cpu-id (0), we use a round-about
0666      * way to pass it w/o having to kmalloc/free a 2 byte string.
0667      * Encode cpu-id as 0xFFcccc, which is decoded by show routine.
0668      */
0669     return *pos < nr_cpu_ids ? cpu_to_ptr(*pos) : NULL;
0670 }
0671 
0672 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
0673 {
0674     ++*pos;
0675     return c_start(m, pos);
0676 }
0677 
0678 static void c_stop(struct seq_file *m, void *v)
0679 {
0680 }
0681 
0682 const struct seq_operations cpuinfo_op = {
0683     .start  = c_start,
0684     .next   = c_next,
0685     .stop   = c_stop,
0686     .show   = show_cpuinfo
0687 };
0688 
0689 static DEFINE_PER_CPU(struct cpu, cpu_topology);
0690 
0691 static int __init topology_init(void)
0692 {
0693     int cpu;
0694 
0695     for_each_present_cpu(cpu)
0696         register_cpu(&per_cpu(cpu_topology, cpu), cpu);
0697 
0698     return 0;
0699 }
0700 
0701 subsys_initcall(topology_init);