1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c121c506SVineet Gupta /*
3c121c506SVineet Gupta * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
4c121c506SVineet Gupta */
5c121c506SVineet Gupta
6c121c506SVineet Gupta #include <linux/seq_file.h>
7c121c506SVineet Gupta #include <linux/fs.h>
8c121c506SVineet Gupta #include <linux/delay.h>
9c121c506SVineet Gupta #include <linux/root_dev.h>
107f35144cSVlad Zakharov #include <linux/clk.h>
1192b03314SVineet Gupta #include <linux/clocksource.h>
12c121c506SVineet Gupta #include <linux/console.h>
13c121c506SVineet Gupta #include <linux/module.h>
1443900edfSEugeniy Paltsev #include <linux/sizes.h>
15c121c506SVineet Gupta #include <linux/cpu.h>
163b00b042SGeert Uytterhoeven #include <linux/of_clk.h>
17999159a5SVineet Gupta #include <linux/of_fdt.h>
181ce0b585SVineet Gupta #include <linux/of.h>
191ec9db10SSachin Kamat #include <linux/cache.h>
20e262e32dSDavid Howells #include <uapi/linux/mount.h>
21999159a5SVineet Gupta #include <asm/sections.h>
22c121c506SVineet Gupta #include <asm/arcregs.h>
23240c84b1SEugeniy Paltsev #include <asm/asserts.h>
24c121c506SVineet Gupta #include <asm/tlb.h>
25c121c506SVineet Gupta #include <asm/setup.h>
26c121c506SVineet Gupta #include <asm/page.h>
27c121c506SVineet Gupta #include <asm/irq.h>
28854a0d95SVineet Gupta #include <asm/unwind.h>
2903a6d28cSVineet Gupta #include <asm/mach_desc.h>
30619f3018SVineet Gupta #include <asm/smp.h>
314827d0cfSEugeniy Paltsev #include <asm/dsp-impl.h>
32fad84e39SVineet Gupta #include <soc/arc/mcip.h>
33c121c506SVineet Gupta
34c121c506SVineet Gupta #define FIX_PTR(x) __asm__ __volatile__(";" : "+r"(x))
35c121c506SVineet Gupta
364255b07fSVineet Gupta unsigned int intr_to_DE_cnt;
374255b07fSVineet Gupta
3859ed9413SVineet Gupta /* Part of U-boot ABI: see head.S */
3959ed9413SVineet Gupta int __initdata uboot_tag;
40edb64bcaSEugeniy Paltsev int __initdata uboot_magic;
4159ed9413SVineet Gupta char __initdata *uboot_arg;
4259ed9413SVineet Gupta
43880beb88SRob Herring const struct machine_desc *machine_desc;
44c121c506SVineet Gupta
45c121c506SVineet Gupta struct task_struct *_current_task[NR_CPUS]; /* For stack switching */
46c121c506SVineet Gupta
47fad84e39SVineet Gupta struct cpuinfo_arc {
48fad84e39SVineet Gupta int arcver;
49fad84e39SVineet Gupta unsigned int t0:1, t1:1;
50fad84e39SVineet Gupta struct {
51fad84e39SVineet Gupta unsigned long base;
52fad84e39SVineet Gupta unsigned int sz;
53fad84e39SVineet Gupta } iccm, dccm;
54fad84e39SVineet Gupta };
55c121c506SVineet Gupta
56fad84e39SVineet Gupta #ifdef CONFIG_ISA_ARCV2
57fad84e39SVineet Gupta
58fad84e39SVineet Gupta static const struct id_to_str arc_hs_rel[] = {
5900a4ae65SVineet Gupta /* ID.ARCVER, Release */
60d975cbc8SVineet Gupta { 0x51, "R2.0" },
61d975cbc8SVineet Gupta { 0x52, "R2.1" },
62d975cbc8SVineet Gupta { 0x53, "R3.0" },
63d975cbc8SVineet Gupta };
64d975cbc8SVineet Gupta
6597d0b5d0SVineet Gupta static const struct id_to_str arc_hs_ver54_rel[] = {
6600a4ae65SVineet Gupta /* UARCH.MAJOR, Release */
6700a4ae65SVineet Gupta { 0, "R3.10a"},
6800a4ae65SVineet Gupta { 1, "R3.50a"},
6997d0b5d0SVineet Gupta { 2, "R3.60a"},
7097d0b5d0SVineet Gupta { 3, "R4.00a"},
7100a4ae65SVineet Gupta { 0xFF, NULL }
7273e284d2SVineet Gupta };
73fad84e39SVineet Gupta #endif
7473e284d2SVineet Gupta
75fad84e39SVineet Gupta static int
arcompact_mumbojumbo(int c,struct cpuinfo_arc * info,char * buf,int len)76fad84e39SVineet Gupta arcompact_mumbojumbo(int c, struct cpuinfo_arc *info, char *buf, int len)
77a150b085SVineet Gupta {
78fad84e39SVineet Gupta int n = 0;
79fad84e39SVineet Gupta #ifdef CONFIG_ISA_ARCOMPACT
80fad84e39SVineet Gupta char *cpu_nm, *isa_nm = "ARCompact";
81fad84e39SVineet Gupta struct bcr_fp_arcompact fpu_sp, fpu_dp;
82fad84e39SVineet Gupta int atomic = 0, be, present;
83fad84e39SVineet Gupta int bpu_full, bpu_cache, bpu_pred;
84fad84e39SVineet Gupta struct bcr_bpu_arcompact bpu;
85a150b085SVineet Gupta struct bcr_iccm_arcompact iccm;
86a150b085SVineet Gupta struct bcr_dccm_arcompact dccm;
87fad84e39SVineet Gupta struct bcr_generic isa;
88fad84e39SVineet Gupta
89fad84e39SVineet Gupta READ_BCR(ARC_REG_ISA_CFG_BCR, isa);
90fad84e39SVineet Gupta
91fad84e39SVineet Gupta if (!isa.ver) /* ISA BCR absent, use Kconfig info */
92fad84e39SVineet Gupta atomic = IS_ENABLED(CONFIG_ARC_HAS_LLSC);
93fad84e39SVineet Gupta else {
94fad84e39SVineet Gupta /* ARC700_BUILD only has 2 bits of isa info */
95fad84e39SVineet Gupta atomic = isa.info & 1;
96fad84e39SVineet Gupta }
97fad84e39SVineet Gupta
98fad84e39SVineet Gupta be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);
99fad84e39SVineet Gupta
100fad84e39SVineet Gupta if (info->arcver < 0x34)
101fad84e39SVineet Gupta cpu_nm = "ARC750";
102fad84e39SVineet Gupta else
103fad84e39SVineet Gupta cpu_nm = "ARC770";
104fad84e39SVineet Gupta
105c40cad3bSVineet Gupta n += scnprintf(buf + n, len - n, "processor [%d]\t: %s (%s ISA) %s%s%s\n",
106c40cad3bSVineet Gupta c, cpu_nm, isa_nm,
107c40cad3bSVineet Gupta IS_AVAIL2(atomic, "atomic ", CONFIG_ARC_HAS_LLSC),
108c40cad3bSVineet Gupta IS_AVAIL1(be, "[Big-Endian]"));
109fad84e39SVineet Gupta
110fad84e39SVineet Gupta READ_BCR(ARC_REG_FP_BCR, fpu_sp);
111fad84e39SVineet Gupta READ_BCR(ARC_REG_DPFP_BCR, fpu_dp);
112fad84e39SVineet Gupta
113fad84e39SVineet Gupta if (fpu_sp.ver | fpu_dp.ver)
114fad84e39SVineet Gupta n += scnprintf(buf + n, len - n, "FPU\t\t: %s%s\n",
115fad84e39SVineet Gupta IS_AVAIL1(fpu_sp.ver, "SP "),
116fad84e39SVineet Gupta IS_AVAIL1(fpu_dp.ver, "DP "));
117fad84e39SVineet Gupta
118fad84e39SVineet Gupta READ_BCR(ARC_REG_BPU_BCR, bpu);
119fad84e39SVineet Gupta bpu_full = bpu.fam ? 1 : 0;
120fad84e39SVineet Gupta bpu_cache = 256 << (bpu.ent - 1);
121fad84e39SVineet Gupta bpu_pred = 256 << (bpu.ent - 1);
122fad84e39SVineet Gupta
123fad84e39SVineet Gupta n += scnprintf(buf + n, len - n,
124fad84e39SVineet Gupta "BPU\t\t: %s%s match, cache:%d, Predict Table:%d\n",
125fad84e39SVineet Gupta IS_AVAIL1(bpu_full, "full"),
126fad84e39SVineet Gupta IS_AVAIL1(!bpu_full, "partial"),
127fad84e39SVineet Gupta bpu_cache, bpu_pred);
128a150b085SVineet Gupta
129a150b085SVineet Gupta READ_BCR(ARC_REG_ICCM_BUILD, iccm);
130a150b085SVineet Gupta if (iccm.ver) {
131fad84e39SVineet Gupta info->iccm.sz = 4096 << iccm.sz; /* 8K to 512K */
132fad84e39SVineet Gupta info->iccm.base = iccm.base << 16;
133a150b085SVineet Gupta }
134a150b085SVineet Gupta
135a150b085SVineet Gupta READ_BCR(ARC_REG_DCCM_BUILD, dccm);
136a150b085SVineet Gupta if (dccm.ver) {
137a150b085SVineet Gupta unsigned long base;
138fad84e39SVineet Gupta info->dccm.sz = 2048 << dccm.sz; /* 2K to 256K */
139a150b085SVineet Gupta
140a150b085SVineet Gupta base = read_aux_reg(ARC_REG_DCCM_BASE_BUILD);
141fad84e39SVineet Gupta info->dccm.base = base & ~0xF;
142a150b085SVineet Gupta }
143fad84e39SVineet Gupta
144fad84e39SVineet Gupta /* ARCompact ISA specific sanity checks */
145fad84e39SVineet Gupta present = fpu_dp.ver; /* SP has no arch visible regs */
146fad84e39SVineet Gupta CHK_OPT_STRICT(CONFIG_ARC_FPU_SAVE_RESTORE, present);
147fad84e39SVineet Gupta #endif
148fad84e39SVineet Gupta return n;
149fad84e39SVineet Gupta
150fad84e39SVineet Gupta }
151fad84e39SVineet Gupta
arcv2_mumbojumbo(int c,struct cpuinfo_arc * info,char * buf,int len)152fad84e39SVineet Gupta static int arcv2_mumbojumbo(int c, struct cpuinfo_arc *info, char *buf, int len)
153fad84e39SVineet Gupta {
154fad84e39SVineet Gupta int n = 0;
155fad84e39SVineet Gupta #ifdef CONFIG_ISA_ARCV2
1564eb69d00SVineet Gupta const char *release = "", *cpu_nm = "HS38", *isa_nm = "ARCv2";
157fad84e39SVineet Gupta int dual_issue = 0, dual_enb = 0, mpy_opt, present;
158fad84e39SVineet Gupta int bpu_full, bpu_cache, bpu_pred, bpu_ret_stk;
159fad84e39SVineet Gupta char mpy_nm[16], lpb_nm[32];
160fad84e39SVineet Gupta struct bcr_isa_arcv2 isa;
161fad84e39SVineet Gupta struct bcr_mpy mpy;
162fad84e39SVineet Gupta struct bcr_fp_arcv2 fpu;
163fad84e39SVineet Gupta struct bcr_bpu_arcv2 bpu;
164fad84e39SVineet Gupta struct bcr_lpb lpb;
165a150b085SVineet Gupta struct bcr_iccm_arcv2 iccm;
166a150b085SVineet Gupta struct bcr_dccm_arcv2 dccm;
167fad84e39SVineet Gupta struct bcr_erp erp;
16800a4ae65SVineet Gupta
16900a4ae65SVineet Gupta /*
17097d0b5d0SVineet Gupta * Initial HS cores bumped AUX IDENTITY.ARCVER for each release until
17197d0b5d0SVineet Gupta * ARCVER 0x54 which introduced AUX MICRO_ARCH_BUILD and subsequent
17297d0b5d0SVineet Gupta * releases only update it.
17300a4ae65SVineet Gupta */
17400a4ae65SVineet Gupta
175fad84e39SVineet Gupta if (info->arcver > 0x50 && info->arcver <= 0x53) {
176fad84e39SVineet Gupta release = arc_hs_rel[info->arcver - 0x51].str;
17700a4ae65SVineet Gupta } else {
178fad84e39SVineet Gupta const struct id_to_str *tbl;
179fad84e39SVineet Gupta struct bcr_uarch_build uarch;
180fad84e39SVineet Gupta
181fad84e39SVineet Gupta READ_BCR(ARC_REG_MICRO_ARCH_BCR, uarch);
18200a4ae65SVineet Gupta
18397d0b5d0SVineet Gupta for (tbl = &arc_hs_ver54_rel[0]; tbl->id != 0xFF; tbl++) {
18400a4ae65SVineet Gupta if (uarch.maj == tbl->id) {
185fad84e39SVineet Gupta release = tbl->str;
18600a4ae65SVineet Gupta break;
18700a4ae65SVineet Gupta }
18800a4ae65SVineet Gupta }
189fad84e39SVineet Gupta if (uarch.prod == 4) {
190dea82520SVineet Gupta unsigned int exec_ctrl;
191dea82520SVineet Gupta
192fad84e39SVineet Gupta cpu_nm = "HS48";
193fad84e39SVineet Gupta dual_issue = 1;
194fad84e39SVineet Gupta /* if dual issue hardware, is it enabled ? */
195dea82520SVineet Gupta READ_BCR(AUX_EXEC_CTRL, exec_ctrl);
196fad84e39SVineet Gupta dual_enb = !(exec_ctrl & 1);
197dea82520SVineet Gupta }
19856372082SVineet Gupta }
19956372082SVineet Gupta
200010a8c98SVineet Gupta READ_BCR(ARC_REG_ISA_CFG_BCR, isa);
201010a8c98SVineet Gupta
202dea82520SVineet Gupta n += scnprintf(buf + n, len - n, "processor [%d]\t: %s %s (%s ISA) %s%s%s\n",
203fad84e39SVineet Gupta c, cpu_nm, release, isa_nm,
204fad84e39SVineet Gupta IS_AVAIL1(isa.be, "[Big-Endian]"),
205fad84e39SVineet Gupta IS_AVAIL3(dual_issue, dual_enb, " Dual-Issue "));
206af617428SVineet Gupta
207fad84e39SVineet Gupta READ_BCR(ARC_REG_MPY_BCR, mpy);
208fad84e39SVineet Gupta mpy_opt = 2; /* stock MPY/MPYH */
209fad84e39SVineet Gupta if (mpy.dsp) /* OPT 7-9 */
210fad84e39SVineet Gupta mpy_opt = mpy.dsp + 6;
211af617428SVineet Gupta
212fad84e39SVineet Gupta scnprintf(mpy_nm, 16, "mpy[opt %d] ", mpy_opt);
21385d6adcbSVineet Gupta
214fad84e39SVineet Gupta READ_BCR(ARC_REG_FP_V2_BCR, fpu);
21585d6adcbSVineet Gupta
216fad84e39SVineet Gupta n += scnprintf(buf + n, len - n, "ISA Extn\t: %s%s%s%s%s%s%s%s%s%s%s\n",
217fad84e39SVineet Gupta IS_AVAIL2(isa.atomic, "atomic ", CONFIG_ARC_HAS_LLSC),
218fad84e39SVineet Gupta IS_AVAIL2(isa.ldd, "ll64 ", CONFIG_ARC_HAS_LL64),
219fad84e39SVineet Gupta IS_AVAIL2(isa.unalign, "unalign ", CONFIG_ARC_USE_UNALIGNED_MEM_ACCESS),
220fad84e39SVineet Gupta IS_AVAIL1(mpy.ver, mpy_nm),
221fad84e39SVineet Gupta IS_AVAIL1(isa.div_rem, "div_rem "),
222fad84e39SVineet Gupta IS_AVAIL1((fpu.sp | fpu.dp), " FPU:"),
223fad84e39SVineet Gupta IS_AVAIL1(fpu.sp, " sp"),
224fad84e39SVineet Gupta IS_AVAIL1(fpu.dp, " dp"));
22585d6adcbSVineet Gupta
226fad84e39SVineet Gupta READ_BCR(ARC_REG_BPU_BCR, bpu);
227fad84e39SVineet Gupta bpu_full = bpu.ft;
228fad84e39SVineet Gupta bpu_cache = 256 << bpu.bce;
229fad84e39SVineet Gupta bpu_pred = 2048 << bpu.pte;
230fad84e39SVineet Gupta bpu_ret_stk = 4 << bpu.rse;
231f3156851SVineet Gupta
232f3156851SVineet Gupta READ_BCR(ARC_REG_LPB_BUILD, lpb);
233f3156851SVineet Gupta if (lpb.ver) {
234f3156851SVineet Gupta unsigned int ctl;
235f3156851SVineet Gupta ctl = read_aux_reg(ARC_REG_LPB_CTRL);
236f3156851SVineet Gupta
237fad84e39SVineet Gupta scnprintf(lpb_nm, sizeof(lpb_nm), " Loop Buffer:%d %s",
238fad84e39SVineet Gupta lpb.entries, IS_DISABLED_RUN(!ctl));
23985d6adcbSVineet Gupta }
24085d6adcbSVineet Gupta
241fad84e39SVineet Gupta n += scnprintf(buf + n, len - n,
242fad84e39SVineet Gupta "BPU\t\t: %s%s match, cache:%d, Predict Table:%d Return stk: %d%s\n",
243fad84e39SVineet Gupta IS_AVAIL1(bpu_full, "full"),
244fad84e39SVineet Gupta IS_AVAIL1(!bpu_full, "partial"),
245fad84e39SVineet Gupta bpu_cache, bpu_pred, bpu_ret_stk,
246fad84e39SVineet Gupta lpb_nm);
247fad84e39SVineet Gupta
248fad84e39SVineet Gupta READ_BCR(ARC_REG_ICCM_BUILD, iccm);
249fad84e39SVineet Gupta if (iccm.ver) {
250fad84e39SVineet Gupta unsigned long base;
251fad84e39SVineet Gupta info->iccm.sz = 256 << iccm.sz00; /* 512B to 16M */
252fad84e39SVineet Gupta if (iccm.sz00 == 0xF && iccm.sz01 > 0)
253fad84e39SVineet Gupta info->iccm.sz <<= iccm.sz01;
254fad84e39SVineet Gupta base = read_aux_reg(ARC_REG_AUX_ICCM);
255fad84e39SVineet Gupta info->iccm.base = base & 0xF0000000;
256af617428SVineet Gupta }
257af617428SVineet Gupta
258fad84e39SVineet Gupta READ_BCR(ARC_REG_DCCM_BUILD, dccm);
259fad84e39SVineet Gupta if (dccm.ver) {
260fad84e39SVineet Gupta unsigned long base;
261fad84e39SVineet Gupta info->dccm.sz = 256 << dccm.sz0;
262fad84e39SVineet Gupta if (dccm.sz0 == 0xF && dccm.sz1 > 0)
263fad84e39SVineet Gupta info->dccm.sz <<= dccm.sz1;
264fad84e39SVineet Gupta base = read_aux_reg(ARC_REG_AUX_DCCM);
265fad84e39SVineet Gupta info->dccm.base = base & 0xF0000000;
2667dd380c3SVineet Gupta }
267f3156851SVineet Gupta
268f3156851SVineet Gupta /* Error Protection: ECC/Parity */
269f3156851SVineet Gupta READ_BCR(ARC_REG_ERP_BUILD, erp);
270f3156851SVineet Gupta if (erp.ver) {
271f3156851SVineet Gupta struct ctl_erp ctl;
272f3156851SVineet Gupta READ_BCR(ARC_REG_ERP_CTRL, ctl);
273f3156851SVineet Gupta /* inverted bits: 0 means enabled */
274f3156851SVineet Gupta n += scnprintf(buf + n, len - n, "Extn [ECC]\t: %s%s%s%s%s%s\n",
275f3156851SVineet Gupta IS_AVAIL3(erp.ic, !ctl.dpi, "IC "),
276f3156851SVineet Gupta IS_AVAIL3(erp.dc, !ctl.dpd, "DC "),
277f3156851SVineet Gupta IS_AVAIL3(erp.mmu, !ctl.mpd, "MMU "));
278f3156851SVineet Gupta }
279fad84e39SVineet Gupta
280fad84e39SVineet Gupta /* ARCv2 ISA specific sanity checks */
281fad84e39SVineet Gupta present = fpu.sp | fpu.dp | mpy.dsp; /* DSP and/or FPU */
282fad84e39SVineet Gupta CHK_OPT_STRICT(CONFIG_ARC_HAS_ACCL_REGS, present);
283fad84e39SVineet Gupta
284fad84e39SVineet Gupta dsp_config_check();
285fad84e39SVineet Gupta #endif
286fad84e39SVineet Gupta return n;
287f3156851SVineet Gupta }
288f3156851SVineet Gupta
arc_cpu_mumbojumbo(int c,struct cpuinfo_arc * info,char * buf,int len)289fad84e39SVineet Gupta static char *arc_cpu_mumbojumbo(int c, struct cpuinfo_arc *info, char *buf, int len)
290fad84e39SVineet Gupta {
291fad84e39SVineet Gupta struct bcr_identity ident;
292fad84e39SVineet Gupta struct bcr_timer timer;
293fad84e39SVineet Gupta struct bcr_generic bcr;
294fad84e39SVineet Gupta struct mcip_bcr mp;
295fad84e39SVineet Gupta struct bcr_actionpoint ap;
296fad84e39SVineet Gupta unsigned long vec_base;
297fad84e39SVineet Gupta int ap_num, ap_full, smart, rtt, n;
298fad84e39SVineet Gupta
299fad84e39SVineet Gupta memset(info, 0, sizeof(struct cpuinfo_arc));
300fad84e39SVineet Gupta
301fad84e39SVineet Gupta READ_BCR(AUX_IDENTITY, ident);
302fad84e39SVineet Gupta info->arcver = ident.family;
303fad84e39SVineet Gupta
304fad84e39SVineet Gupta n = scnprintf(buf, len,
305fad84e39SVineet Gupta "\nIDENTITY\t: ARCVER [%#02x] ARCNUM [%#02x] CHIPID [%#4x]\n",
306fad84e39SVineet Gupta ident.family, ident.cpu_id, ident.chip_id);
307fad84e39SVineet Gupta
308fad84e39SVineet Gupta if (is_isa_arcompact()) {
309fad84e39SVineet Gupta n += arcompact_mumbojumbo(c, info, buf + n, len - n);
310fad84e39SVineet Gupta } else if (is_isa_arcv2()){
311fad84e39SVineet Gupta n += arcv2_mumbojumbo(c, info, buf + n, len - n);
312fad84e39SVineet Gupta }
313fad84e39SVineet Gupta
314fad84e39SVineet Gupta n += arc_mmu_mumbojumbo(c, buf + n, len - n);
315fad84e39SVineet Gupta n += arc_cache_mumbojumbo(c, buf + n, len - n);
316fad84e39SVineet Gupta
317fad84e39SVineet Gupta READ_BCR(ARC_REG_TIMERS_BCR, timer);
318fad84e39SVineet Gupta info->t0 = timer.t0;
319fad84e39SVineet Gupta info->t1 = timer.t1;
320fad84e39SVineet Gupta
321fad84e39SVineet Gupta READ_BCR(ARC_REG_MCIP_BCR, mp);
322fad84e39SVineet Gupta vec_base = read_aux_reg(AUX_INTR_VEC_BASE);
323fad84e39SVineet Gupta
324fad84e39SVineet Gupta n += scnprintf(buf + n, len - n,
325fad84e39SVineet Gupta "Timers\t\t: %s%s%s%s%s%s\nVector Table\t: %#lx\n",
326fad84e39SVineet Gupta IS_AVAIL1(timer.t0, "Timer0 "),
327fad84e39SVineet Gupta IS_AVAIL1(timer.t1, "Timer1 "),
328fad84e39SVineet Gupta IS_AVAIL2(timer.rtc, "RTC [UP 64-bit] ", CONFIG_ARC_TIMERS_64BIT),
329fad84e39SVineet Gupta IS_AVAIL2(mp.gfrc, "GFRC [SMP 64-bit] ", CONFIG_ARC_TIMERS_64BIT),
330fad84e39SVineet Gupta vec_base);
331fad84e39SVineet Gupta
332fad84e39SVineet Gupta READ_BCR(ARC_REG_AP_BCR, ap);
333fad84e39SVineet Gupta if (ap.ver) {
334fad84e39SVineet Gupta ap_num = 2 << ap.num;
335fad84e39SVineet Gupta ap_full = !ap.min;
336fad84e39SVineet Gupta }
337fad84e39SVineet Gupta
338fad84e39SVineet Gupta READ_BCR(ARC_REG_SMART_BCR, bcr);
339fad84e39SVineet Gupta smart = bcr.ver ? 1 : 0;
340fad84e39SVineet Gupta
341fad84e39SVineet Gupta READ_BCR(ARC_REG_RTT_BCR, bcr);
342fad84e39SVineet Gupta rtt = bcr.ver ? 1 : 0;
343fad84e39SVineet Gupta
344fad84e39SVineet Gupta if (ap.ver | smart | rtt) {
345fad84e39SVineet Gupta n += scnprintf(buf + n, len - n, "DEBUG\t\t: %s%s",
346fad84e39SVineet Gupta IS_AVAIL1(smart, "smaRT "),
347fad84e39SVineet Gupta IS_AVAIL1(rtt, "RTT "));
348fad84e39SVineet Gupta if (ap.ver) {
349fad84e39SVineet Gupta n += scnprintf(buf + n, len - n, "ActionPoint %d/%s",
350fad84e39SVineet Gupta ap_num,
351fad84e39SVineet Gupta ap_full ? "full":"min");
352fad84e39SVineet Gupta }
353fad84e39SVineet Gupta n += scnprintf(buf + n, len - n, "\n");
354fad84e39SVineet Gupta }
355fad84e39SVineet Gupta
356fad84e39SVineet Gupta if (info->dccm.sz || info->iccm.sz)
357fad84e39SVineet Gupta n += scnprintf(buf + n, len - n,
358fad84e39SVineet Gupta "Extn [CCM]\t: DCCM @ %lx, %d KB / ICCM: @ %lx, %d KB\n",
359fad84e39SVineet Gupta info->dccm.base, TO_KB(info->dccm.sz),
360fad84e39SVineet Gupta info->iccm.base, TO_KB(info->iccm.sz));
361fad84e39SVineet Gupta
362af617428SVineet Gupta return buf;
363af617428SVineet Gupta }
364af617428SVineet Gupta
chk_opt_strict(char * opt_name,bool hw_exists,bool opt_ena)365240c84b1SEugeniy Paltsev void chk_opt_strict(char *opt_name, bool hw_exists, bool opt_ena)
366240c84b1SEugeniy Paltsev {
367240c84b1SEugeniy Paltsev if (hw_exists && !opt_ena)
368240c84b1SEugeniy Paltsev pr_warn(" ! Enable %s for working apps\n", opt_name);
369240c84b1SEugeniy Paltsev else if (!hw_exists && opt_ena)
370240c84b1SEugeniy Paltsev panic("Disable %s, hardware NOT present\n", opt_name);
371240c84b1SEugeniy Paltsev }
372240c84b1SEugeniy Paltsev
chk_opt_weak(char * opt_name,bool hw_exists,bool opt_ena)373f09d3174SEugeniy Paltsev void chk_opt_weak(char *opt_name, bool hw_exists, bool opt_ena)
374f09d3174SEugeniy Paltsev {
375f09d3174SEugeniy Paltsev if (!hw_exists && opt_ena)
376f09d3174SEugeniy Paltsev panic("Disable %s, hardware NOT present\n", opt_name);
377f09d3174SEugeniy Paltsev }
378f09d3174SEugeniy Paltsev
379fad84e39SVineet Gupta /*
380fad84e39SVineet Gupta * ISA agnostic sanity checks
381fad84e39SVineet Gupta */
arc_chk_core_config(struct cpuinfo_arc * info)382fad84e39SVineet Gupta static void arc_chk_core_config(struct cpuinfo_arc *info)
3838b5850f8SVineet Gupta {
384fad84e39SVineet Gupta if (!info->t0)
38556372082SVineet Gupta panic("Timer0 is not present!\n");
38656372082SVineet Gupta
387fad84e39SVineet Gupta if (!info->t1)
38856372082SVineet Gupta panic("Timer1 is not present!\n");
38956372082SVineet Gupta
3908b5850f8SVineet Gupta #ifdef CONFIG_ARC_HAS_DCCM
3918b5850f8SVineet Gupta /*
3928b5850f8SVineet Gupta * DCCM can be arbit placed in hardware.
393*ebfc2fd8SBjorn Helgaas * Make sure its placement/sz matches what Linux is built with
3948b5850f8SVineet Gupta */
395fad84e39SVineet Gupta if ((unsigned int)__arc_dccm_base != info->dccm.base)
3968b5850f8SVineet Gupta panic("Linux built with incorrect DCCM Base address\n");
3978b5850f8SVineet Gupta
398fad84e39SVineet Gupta if (CONFIG_ARC_DCCM_SZ * SZ_1K != info->dccm.sz)
3998b5850f8SVineet Gupta panic("Linux built with incorrect DCCM Size\n");
4008b5850f8SVineet Gupta #endif
4018b5850f8SVineet Gupta
4028b5850f8SVineet Gupta #ifdef CONFIG_ARC_HAS_ICCM
403fad84e39SVineet Gupta if (CONFIG_ARC_ICCM_SZ * SZ_1K != info->iccm.sz)
4048b5850f8SVineet Gupta panic("Linux built with incorrect ICCM Size\n");
4058b5850f8SVineet Gupta #endif
406c121c506SVineet Gupta }
407c121c506SVineet Gupta
408c121c506SVineet Gupta /*
409c121c506SVineet Gupta * Initialize and setup the processor core
410c121c506SVineet Gupta * This is called by all the CPUs thus should not do special case stuff
411c121c506SVineet Gupta * such as only for boot CPU etc
412c121c506SVineet Gupta */
413c121c506SVineet Gupta
setup_processor(void)414ce759956SPaul Gortmaker void setup_processor(void)
415c121c506SVineet Gupta {
416fad84e39SVineet Gupta struct cpuinfo_arc info;
417fad84e39SVineet Gupta int c = smp_processor_id();
418af617428SVineet Gupta char str[512];
419af617428SVineet Gupta
420fad84e39SVineet Gupta pr_info("%s", arc_cpu_mumbojumbo(c, &info, str, sizeof(str)));
421fad84e39SVineet Gupta pr_info("%s", arc_platform_smp_cpuinfo());
422fad84e39SVineet Gupta
423fad84e39SVineet Gupta arc_chk_core_config(&info);
424fad84e39SVineet Gupta
425c121c506SVineet Gupta arc_init_IRQ();
426c121c506SVineet Gupta arc_mmu_init();
427c121c506SVineet Gupta arc_cache_init();
428af617428SVineet Gupta
429c121c506SVineet Gupta }
430c121c506SVineet Gupta
uboot_arg_invalid(unsigned long addr)431a66f2e57SEugeniy Paltsev static inline bool uboot_arg_invalid(unsigned long addr)
43259ed9413SVineet Gupta {
433a66f2e57SEugeniy Paltsev /*
434a66f2e57SEugeniy Paltsev * Check that it is a untranslated address (although MMU is not enabled
435a66f2e57SEugeniy Paltsev * yet, it being a high address ensures this is not by fluke)
436a66f2e57SEugeniy Paltsev */
437a66f2e57SEugeniy Paltsev if (addr < PAGE_OFFSET)
438a66f2e57SEugeniy Paltsev return true;
439a66f2e57SEugeniy Paltsev
440a66f2e57SEugeniy Paltsev /* Check that address doesn't clobber resident kernel image */
441a66f2e57SEugeniy Paltsev return addr >= (unsigned long)_stext && addr <= (unsigned long)_end;
442a66f2e57SEugeniy Paltsev }
443a66f2e57SEugeniy Paltsev
444a66f2e57SEugeniy Paltsev #define IGNORE_ARGS "Ignore U-boot args: "
445a66f2e57SEugeniy Paltsev
446a66f2e57SEugeniy Paltsev /* uboot_tag values for U-boot - kernel ABI revision 0; see head.S */
447a66f2e57SEugeniy Paltsev #define UBOOT_TAG_NONE 0
448a66f2e57SEugeniy Paltsev #define UBOOT_TAG_CMDLINE 1
449a66f2e57SEugeniy Paltsev #define UBOOT_TAG_DTB 2
450edb64bcaSEugeniy Paltsev /* We always pass 0 as magic from U-boot */
451edb64bcaSEugeniy Paltsev #define UBOOT_MAGIC_VALUE 0
452a66f2e57SEugeniy Paltsev
handle_uboot_args(void)453a66f2e57SEugeniy Paltsev void __init handle_uboot_args(void)
454a66f2e57SEugeniy Paltsev {
455a66f2e57SEugeniy Paltsev bool use_embedded_dtb = true;
456a66f2e57SEugeniy Paltsev bool append_cmdline = false;
457a66f2e57SEugeniy Paltsev
458a66f2e57SEugeniy Paltsev /* check that we know this tag */
459a66f2e57SEugeniy Paltsev if (uboot_tag != UBOOT_TAG_NONE &&
460a66f2e57SEugeniy Paltsev uboot_tag != UBOOT_TAG_CMDLINE &&
461a66f2e57SEugeniy Paltsev uboot_tag != UBOOT_TAG_DTB) {
462a66f2e57SEugeniy Paltsev pr_warn(IGNORE_ARGS "invalid uboot tag: '%08x'\n", uboot_tag);
463a66f2e57SEugeniy Paltsev goto ignore_uboot_args;
464a66f2e57SEugeniy Paltsev }
465a66f2e57SEugeniy Paltsev
466edb64bcaSEugeniy Paltsev if (uboot_magic != UBOOT_MAGIC_VALUE) {
467edb64bcaSEugeniy Paltsev pr_warn(IGNORE_ARGS "non zero uboot magic\n");
468edb64bcaSEugeniy Paltsev goto ignore_uboot_args;
469edb64bcaSEugeniy Paltsev }
470edb64bcaSEugeniy Paltsev
471a66f2e57SEugeniy Paltsev if (uboot_tag != UBOOT_TAG_NONE &&
472a66f2e57SEugeniy Paltsev uboot_arg_invalid((unsigned long)uboot_arg)) {
473a66f2e57SEugeniy Paltsev pr_warn(IGNORE_ARGS "invalid uboot arg: '%px'\n", uboot_arg);
474a66f2e57SEugeniy Paltsev goto ignore_uboot_args;
475a66f2e57SEugeniy Paltsev }
476a66f2e57SEugeniy Paltsev
477a66f2e57SEugeniy Paltsev /* see if U-boot passed an external Device Tree blob */
478a66f2e57SEugeniy Paltsev if (uboot_tag == UBOOT_TAG_DTB) {
479a66f2e57SEugeniy Paltsev machine_desc = setup_machine_fdt((void *)uboot_arg);
480a66f2e57SEugeniy Paltsev
481a66f2e57SEugeniy Paltsev /* external Device Tree blob is invalid - use embedded one */
482a66f2e57SEugeniy Paltsev use_embedded_dtb = !machine_desc;
483a66f2e57SEugeniy Paltsev }
484a66f2e57SEugeniy Paltsev
485a66f2e57SEugeniy Paltsev if (uboot_tag == UBOOT_TAG_CMDLINE)
486a66f2e57SEugeniy Paltsev append_cmdline = true;
487a66f2e57SEugeniy Paltsev
488a66f2e57SEugeniy Paltsev ignore_uboot_args:
489a66f2e57SEugeniy Paltsev
490a66f2e57SEugeniy Paltsev if (use_embedded_dtb) {
491a66f2e57SEugeniy Paltsev machine_desc = setup_machine_fdt(__dtb_start);
492a66f2e57SEugeniy Paltsev if (!machine_desc)
493a66f2e57SEugeniy Paltsev panic("Embedded DT invalid\n");
494a66f2e57SEugeniy Paltsev }
495a66f2e57SEugeniy Paltsev
496a66f2e57SEugeniy Paltsev /*
497a66f2e57SEugeniy Paltsev * NOTE: @boot_command_line is populated by setup_machine_fdt() so this
498a66f2e57SEugeniy Paltsev * append processing can only happen after.
499a66f2e57SEugeniy Paltsev */
500a66f2e57SEugeniy Paltsev if (append_cmdline) {
501a66f2e57SEugeniy Paltsev /* Ensure a whitespace between the 2 cmdlines */
502a66f2e57SEugeniy Paltsev strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
503a66f2e57SEugeniy Paltsev strlcat(boot_command_line, uboot_arg, COMMAND_LINE_SIZE);
504a66f2e57SEugeniy Paltsev }
50559ed9413SVineet Gupta }
50659ed9413SVineet Gupta
setup_arch(char ** cmdline_p)507c121c506SVineet Gupta void __init setup_arch(char **cmdline_p)
508c121c506SVineet Gupta {
509a66f2e57SEugeniy Paltsev handle_uboot_args();
5109593a933SVineet Gupta
5119593a933SVineet Gupta /* Save unparsed command line copy for /proc/cmdline */
5129593a933SVineet Gupta *cmdline_p = boot_command_line;
5139593a933SVineet Gupta
514c121c506SVineet Gupta /* To force early parsing of things like mem=xxx */
515c121c506SVineet Gupta parse_early_param();
516c121c506SVineet Gupta
517c121c506SVineet Gupta /* Platform/board specific: e.g. early console registration */
51803a6d28cSVineet Gupta if (machine_desc->init_early)
51903a6d28cSVineet Gupta machine_desc->init_early();
520c121c506SVineet Gupta
52141195d23SVineet Gupta smp_init_cpus();
522e55af4daSVineet Gupta
523e55af4daSVineet Gupta setup_processor();
524c121c506SVineet Gupta setup_arch_memory();
525c121c506SVineet Gupta
526eab6a08cSVineet Gupta /* copy flat DT out of .init and then unflatten it */
5271efc959eSRob Herring unflatten_and_copy_device_tree();
528999159a5SVineet Gupta
529c121c506SVineet Gupta /* Can be issue if someone passes cmd line arg "ro"
530c121c506SVineet Gupta * But that is unlikely so keeping it as it is
531c121c506SVineet Gupta */
532c121c506SVineet Gupta root_mountflags &= ~MS_RDONLY;
533c121c506SVineet Gupta
534854a0d95SVineet Gupta arc_unwind_init();
535c121c506SVineet Gupta }
536c121c506SVineet Gupta
53792b03314SVineet Gupta /*
53892b03314SVineet Gupta * Called from start_kernel() - boot CPU only
53992b03314SVineet Gupta */
time_init(void)54092b03314SVineet Gupta void __init time_init(void)
54192b03314SVineet Gupta {
54292b03314SVineet Gupta of_clk_init(NULL);
543ba5d08c0SDaniel Lezcano timer_probe();
54492b03314SVineet Gupta }
54592b03314SVineet Gupta
customize_machine(void)54603a6d28cSVineet Gupta static int __init customize_machine(void)
54703a6d28cSVineet Gupta {
54803a6d28cSVineet Gupta if (machine_desc->init_machine)
54903a6d28cSVineet Gupta machine_desc->init_machine();
55003a6d28cSVineet Gupta
55103a6d28cSVineet Gupta return 0;
55203a6d28cSVineet Gupta }
55303a6d28cSVineet Gupta arch_initcall(customize_machine);
55403a6d28cSVineet Gupta
init_late_machine(void)55503a6d28cSVineet Gupta static int __init init_late_machine(void)
55603a6d28cSVineet Gupta {
55703a6d28cSVineet Gupta if (machine_desc->init_late)
55803a6d28cSVineet Gupta machine_desc->init_late();
55903a6d28cSVineet Gupta
56003a6d28cSVineet Gupta return 0;
56103a6d28cSVineet Gupta }
56203a6d28cSVineet Gupta late_initcall(init_late_machine);
563c121c506SVineet Gupta /*
564c121c506SVineet Gupta * Get CPU information for use by the procfs.
565c121c506SVineet Gupta */
566c121c506SVineet Gupta
567c121c506SVineet Gupta #define cpu_to_ptr(c) ((void *)(0xFFFF0000 | (unsigned int)(c)))
568c121c506SVineet Gupta #define ptr_to_cpu(p) (~0xFFFF0000UL & (unsigned int)(p))
569c121c506SVineet Gupta
show_cpuinfo(struct seq_file * m,void * v)570c121c506SVineet Gupta static int show_cpuinfo(struct seq_file *m, void *v)
571c121c506SVineet Gupta {
572c121c506SVineet Gupta char *str;
573c121c506SVineet Gupta int cpu_id = ptr_to_cpu(v);
5747f35144cSVlad Zakharov struct device *cpu_dev = get_cpu_device(cpu_id);
575fad84e39SVineet Gupta struct cpuinfo_arc info;
5767f35144cSVlad Zakharov struct clk *cpu_clk;
5777f35144cSVlad Zakharov unsigned long freq = 0;
578c121c506SVineet Gupta
5794c86231cSVineet Gupta if (!cpu_online(cpu_id)) {
5804c86231cSVineet Gupta seq_printf(m, "processor [%d]\t: Offline\n", cpu_id);
5814c86231cSVineet Gupta goto done;
5824c86231cSVineet Gupta }
5834c86231cSVineet Gupta
5840ee931c4SMichal Hocko str = (char *)__get_free_page(GFP_KERNEL);
585c121c506SVineet Gupta if (!str)
586c121c506SVineet Gupta goto done;
587c121c506SVineet Gupta
588fad84e39SVineet Gupta seq_printf(m, arc_cpu_mumbojumbo(cpu_id, &info, str, PAGE_SIZE));
589c121c506SVineet Gupta
5907f35144cSVlad Zakharov cpu_clk = clk_get(cpu_dev, NULL);
5917f35144cSVlad Zakharov if (IS_ERR(cpu_clk)) {
5927f35144cSVlad Zakharov seq_printf(m, "CPU speed \t: Cannot get clock for processor [%d]\n",
5937f35144cSVlad Zakharov cpu_id);
5947f35144cSVlad Zakharov } else {
5957f35144cSVlad Zakharov freq = clk_get_rate(cpu_clk);
5967f35144cSVlad Zakharov }
59720c7dbbdSAlexey Brodkin if (freq)
5987f35144cSVlad Zakharov seq_printf(m, "CPU speed\t: %lu.%02lu Mhz\n",
59920c7dbbdSAlexey Brodkin freq / 1000000, (freq / 10000) % 100);
60020c7dbbdSAlexey Brodkin
60156372082SVineet Gupta seq_printf(m, "Bogo MIPS\t: %lu.%02lu\n",
602c121c506SVineet Gupta loops_per_jiffy / (500000 / HZ),
603c121c506SVineet Gupta (loops_per_jiffy / (5000 / HZ)) % 100);
604c121c506SVineet Gupta
605af617428SVineet Gupta seq_printf(m, arc_platform_smp_cpuinfo());
606af617428SVineet Gupta
607c121c506SVineet Gupta free_page((unsigned long)str);
608c121c506SVineet Gupta done:
6094c86231cSVineet Gupta seq_printf(m, "\n");
610c121c506SVineet Gupta
611c121c506SVineet Gupta return 0;
612c121c506SVineet Gupta }
613c121c506SVineet Gupta
c_start(struct seq_file * m,loff_t * pos)614c121c506SVineet Gupta static void *c_start(struct seq_file *m, loff_t *pos)
615c121c506SVineet Gupta {
616c121c506SVineet Gupta /*
617c121c506SVineet Gupta * Callback returns cpu-id to iterator for show routine, NULL to stop.
618c121c506SVineet Gupta * However since NULL is also a valid cpu-id (0), we use a round-about
619c121c506SVineet Gupta * way to pass it w/o having to kmalloc/free a 2 byte string.
620c121c506SVineet Gupta * Encode cpu-id as 0xFFcccc, which is decoded by show routine.
621c121c506SVineet Gupta */
6223da43104SNoam Camus return *pos < nr_cpu_ids ? cpu_to_ptr(*pos) : NULL;
623c121c506SVineet Gupta }
624c121c506SVineet Gupta
c_next(struct seq_file * m,void * v,loff_t * pos)625c121c506SVineet Gupta static void *c_next(struct seq_file *m, void *v, loff_t *pos)
626c121c506SVineet Gupta {
627c121c506SVineet Gupta ++*pos;
628c121c506SVineet Gupta return c_start(m, pos);
629c121c506SVineet Gupta }
630c121c506SVineet Gupta
c_stop(struct seq_file * m,void * v)631c121c506SVineet Gupta static void c_stop(struct seq_file *m, void *v)
632c121c506SVineet Gupta {
633c121c506SVineet Gupta }
634c121c506SVineet Gupta
635c121c506SVineet Gupta const struct seq_operations cpuinfo_op = {
636c121c506SVineet Gupta .start = c_start,
637c121c506SVineet Gupta .next = c_next,
638c121c506SVineet Gupta .stop = c_stop,
639c121c506SVineet Gupta .show = show_cpuinfo
640c121c506SVineet Gupta };
641c121c506SVineet Gupta
642c121c506SVineet Gupta static DEFINE_PER_CPU(struct cpu, cpu_topology);
643c121c506SVineet Gupta
topology_init(void)644c121c506SVineet Gupta static int __init topology_init(void)
645c121c506SVineet Gupta {
646c121c506SVineet Gupta int cpu;
647c121c506SVineet Gupta
648c121c506SVineet Gupta for_each_present_cpu(cpu)
649c121c506SVineet Gupta register_cpu(&per_cpu(cpu_topology, cpu), cpu);
650c121c506SVineet Gupta
651c121c506SVineet Gupta return 0;
652c121c506SVineet Gupta }
653c121c506SVineet Gupta
654c121c506SVineet Gupta subsys_initcall(topology_init);
655