xref: /openbmc/linux/arch/mips/kernel/cpu-probe.c (revision 26d0dfbb16fcb17d128a79dc70f3020ea6992af0)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Processor capabilities determination functions.
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (C) xxxx  the Anonymous
6010b853bSRalf Baechle  * Copyright (C) 1994 - 2006 Ralf Baechle
74194318cSRalf Baechle  * Copyright (C) 2003, 2004  Maciej W. Rozycki
8113c62d9SSteven J. Hill  * Copyright (C) 2001, 2004, 2011, 2012	 MIPS Technologies, Inc.
91da177e4SLinus Torvalds  */
101da177e4SLinus Torvalds #include <linux/init.h>
111da177e4SLinus Torvalds #include <linux/kernel.h>
121da177e4SLinus Torvalds #include <linux/ptrace.h>
13631330f5SRalf Baechle #include <linux/smp.h>
141da177e4SLinus Torvalds #include <linux/stddef.h>
1573bc256dSPaul Gortmaker #include <linux/export.h>
161da177e4SLinus Torvalds 
175759906cSRalf Baechle #include <asm/bugs.h>
181da177e4SLinus Torvalds #include <asm/cpu.h>
19f6843626SMaciej W. Rozycki #include <asm/cpu-features.h>
2069f24d17SRalf Baechle #include <asm/cpu-type.h>
211da177e4SLinus Torvalds #include <asm/fpu.h>
221da177e4SLinus Torvalds #include <asm/mipsregs.h>
2330ee615bSPaul Burton #include <asm/mipsmtregs.h>
24a5e9a69eSPaul Burton #include <asm/msa.h>
25654f57bfSDavid Daney #include <asm/watch.h>
2606372a63SPaul Gortmaker #include <asm/elf.h>
274f12b91dSMarkos Chandras #include <asm/pgtable-bits.h>
28a074f0e8SChris Dearman #include <asm/spram.h>
29bd67b711SThomas Bogendoerfer #include <asm/traps.h>
307c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
31949e51beSDavid Daney 
32a616c061SThomas Bogendoerfer #include "fpu-probe.h"
33a616c061SThomas Bogendoerfer 
34ec7a9318SWANG Xuerui #include <asm/mach-loongson64/cpucfg-emul.h>
35ec7a9318SWANG Xuerui 
36e14f1db7SPaul Burton /* Hardware capabilities */
37e14f1db7SPaul Burton unsigned int elf_hwcap __read_mostly;
3805510f2bSMarcin Nowakowski EXPORT_SYMBOL_GPL(elf_hwcap);
39e14f1db7SPaul Burton 
cpu_get_msa_id(void)40b2e628a8SPaul Burton static inline unsigned long cpu_get_msa_id(void)
41b2e628a8SPaul Burton {
42b2e628a8SPaul Burton 	unsigned long status, msa_id;
43b2e628a8SPaul Burton 
44b2e628a8SPaul Burton 	status = read_c0_status();
45b2e628a8SPaul Burton 	__enable_fpu(FPU_64BIT);
46b2e628a8SPaul Burton 	enable_msa();
47b2e628a8SPaul Burton 	msa_id = read_msa_ir();
48b2e628a8SPaul Burton 	disable_msa();
49b2e628a8SPaul Burton 	write_c0_status(status);
50b2e628a8SPaul Burton 	return msa_id;
51b2e628a8SPaul Burton }
52b2e628a8SPaul Burton 
53b7fc2cc5SPaul Burton static int mips_dsp_disabled;
540103d23fSKevin Cernekee 
dsp_disable(char * s)550103d23fSKevin Cernekee static int __init dsp_disable(char *s)
560103d23fSKevin Cernekee {
57ee80f7c7SSteven J. Hill 	cpu_data[0].ases &= ~(MIPS_ASE_DSP | MIPS_ASE_DSP2P);
580103d23fSKevin Cernekee 	mips_dsp_disabled = 1;
590103d23fSKevin Cernekee 
600103d23fSKevin Cernekee 	return 1;
610103d23fSKevin Cernekee }
620103d23fSKevin Cernekee 
630103d23fSKevin Cernekee __setup("nodsp", dsp_disable);
640103d23fSKevin Cernekee 
653d528b32SMarkos Chandras static int mips_htw_disabled;
663d528b32SMarkos Chandras 
htw_disable(char * s)673d528b32SMarkos Chandras static int __init htw_disable(char *s)
683d528b32SMarkos Chandras {
693d528b32SMarkos Chandras 	mips_htw_disabled = 1;
703d528b32SMarkos Chandras 	cpu_data[0].options &= ~MIPS_CPU_HTW;
713d528b32SMarkos Chandras 	write_c0_pwctl(read_c0_pwctl() &
723d528b32SMarkos Chandras 		       ~(1 << MIPS_PWCTL_PWEN_SHIFT));
733d528b32SMarkos Chandras 
743d528b32SMarkos Chandras 	return 1;
753d528b32SMarkos Chandras }
763d528b32SMarkos Chandras 
773d528b32SMarkos Chandras __setup("nohtw", htw_disable);
783d528b32SMarkos Chandras 
7997f4ad29SMarkos Chandras static int mips_ftlb_disabled;
8097f4ad29SMarkos Chandras static int mips_has_ftlb_configured;
8197f4ad29SMarkos Chandras 
82ebd0e0f5SPaul Burton enum ftlb_flags {
83ebd0e0f5SPaul Burton 	FTLB_EN		= 1 << 0,
84ebd0e0f5SPaul Burton 	FTLB_SET_PROB	= 1 << 1,
85ebd0e0f5SPaul Burton };
86ebd0e0f5SPaul Burton 
87ebd0e0f5SPaul Burton static int set_ftlb_enable(struct cpuinfo_mips *c, enum ftlb_flags flags);
8897f4ad29SMarkos Chandras 
ftlb_disable(char * s)8997f4ad29SMarkos Chandras static int __init ftlb_disable(char *s)
9097f4ad29SMarkos Chandras {
9197f4ad29SMarkos Chandras 	unsigned int config4, mmuextdef;
9297f4ad29SMarkos Chandras 
9397f4ad29SMarkos Chandras 	/*
9497f4ad29SMarkos Chandras 	 * If the core hasn't done any FTLB configuration, there is nothing
9597f4ad29SMarkos Chandras 	 * for us to do here.
9697f4ad29SMarkos Chandras 	 */
9797f4ad29SMarkos Chandras 	if (!mips_has_ftlb_configured)
9897f4ad29SMarkos Chandras 		return 1;
9997f4ad29SMarkos Chandras 
10097f4ad29SMarkos Chandras 	/* Disable it in the boot cpu */
101912708c2SMarkos Chandras 	if (set_ftlb_enable(&cpu_data[0], 0)) {
102912708c2SMarkos Chandras 		pr_warn("Can't turn FTLB off\n");
103912708c2SMarkos Chandras 		return 1;
104912708c2SMarkos Chandras 	}
10597f4ad29SMarkos Chandras 
10697f4ad29SMarkos Chandras 	config4 = read_c0_config4();
10797f4ad29SMarkos Chandras 
10897f4ad29SMarkos Chandras 	/* Check that FTLB has been disabled */
10997f4ad29SMarkos Chandras 	mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF;
11097f4ad29SMarkos Chandras 	/* MMUSIZEEXT == VTLB ON, FTLB OFF */
11197f4ad29SMarkos Chandras 	if (mmuextdef == MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT) {
11297f4ad29SMarkos Chandras 		/* This should never happen */
11397f4ad29SMarkos Chandras 		pr_warn("FTLB could not be disabled!\n");
11497f4ad29SMarkos Chandras 		return 1;
11597f4ad29SMarkos Chandras 	}
11697f4ad29SMarkos Chandras 
11797f4ad29SMarkos Chandras 	mips_ftlb_disabled = 1;
11897f4ad29SMarkos Chandras 	mips_has_ftlb_configured = 0;
11997f4ad29SMarkos Chandras 
12097f4ad29SMarkos Chandras 	/*
12197f4ad29SMarkos Chandras 	 * noftlb is mainly used for debug purposes so print
12297f4ad29SMarkos Chandras 	 * an informative message instead of using pr_debug()
12397f4ad29SMarkos Chandras 	 */
12497f4ad29SMarkos Chandras 	pr_info("FTLB has been disabled\n");
12597f4ad29SMarkos Chandras 
12697f4ad29SMarkos Chandras 	/*
12797f4ad29SMarkos Chandras 	 * Some of these bits are duplicated in the decode_config4.
12897f4ad29SMarkos Chandras 	 * MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT is the only possible case
12997f4ad29SMarkos Chandras 	 * once FTLB has been disabled so undo what decode_config4 did.
13097f4ad29SMarkos Chandras 	 */
13197f4ad29SMarkos Chandras 	cpu_data[0].tlbsize -= cpu_data[0].tlbsizeftlbways *
13297f4ad29SMarkos Chandras 			       cpu_data[0].tlbsizeftlbsets;
13397f4ad29SMarkos Chandras 	cpu_data[0].tlbsizeftlbsets = 0;
13497f4ad29SMarkos Chandras 	cpu_data[0].tlbsizeftlbways = 0;
13597f4ad29SMarkos Chandras 
13697f4ad29SMarkos Chandras 	return 1;
13797f4ad29SMarkos Chandras }
13897f4ad29SMarkos Chandras 
13997f4ad29SMarkos Chandras __setup("noftlb", ftlb_disable);
14097f4ad29SMarkos Chandras 
1418270ab48SMatt Redfearn /*
1428270ab48SMatt Redfearn  * Check if the CPU has per tc perf counters
1438270ab48SMatt Redfearn  */
cpu_set_mt_per_tc_perf(struct cpuinfo_mips * c)1448270ab48SMatt Redfearn static inline void cpu_set_mt_per_tc_perf(struct cpuinfo_mips *c)
1458270ab48SMatt Redfearn {
1468270ab48SMatt Redfearn 	if (read_c0_config7() & MTI_CONF7_PTC)
1478270ab48SMatt Redfearn 		c->options |= MIPS_CPU_MT_PER_TC_PERF_COUNTERS;
1488270ab48SMatt Redfearn }
14997f4ad29SMarkos Chandras 
check_errata(void)1509267a30dSMarc St-Jean static inline void check_errata(void)
1519267a30dSMarc St-Jean {
1529267a30dSMarc St-Jean 	struct cpuinfo_mips *c = &current_cpu_data;
1539267a30dSMarc St-Jean 
15469f24d17SRalf Baechle 	switch (current_cpu_type()) {
1559267a30dSMarc St-Jean 	case CPU_34K:
1569267a30dSMarc St-Jean 		/*
1579267a30dSMarc St-Jean 		 * Erratum "RPS May Cause Incorrect Instruction Execution"
158b633648cSRalf Baechle 		 * This code only handles VPE0, any SMP/RTOS code
15994bd83e4SJulia Lawall 		 * making use of VPE1 will be responsible for that VPE.
1609267a30dSMarc St-Jean 		 */
1619267a30dSMarc St-Jean 		if ((c->processor_id & PRID_REV_MASK) <= PRID_REV_34K_V1_0_2)
1629267a30dSMarc St-Jean 			write_c0_config7(read_c0_config7() | MIPS_CONF7_RPS);
1639267a30dSMarc St-Jean 		break;
1649267a30dSMarc St-Jean 	default:
1659267a30dSMarc St-Jean 		break;
1669267a30dSMarc St-Jean 	}
1679267a30dSMarc St-Jean }
1689267a30dSMarc St-Jean 
check_bugs32(void)1691da177e4SLinus Torvalds void __init check_bugs32(void)
1701da177e4SLinus Torvalds {
1719267a30dSMarc St-Jean 	check_errata();
1721da177e4SLinus Torvalds }
1731da177e4SLinus Torvalds 
1741da177e4SLinus Torvalds /*
1751da177e4SLinus Torvalds  * Probe whether cpu has config register by trying to play with
1761da177e4SLinus Torvalds  * alternate cache bit and see whether it matters.
1771da177e4SLinus Torvalds  * It's used by cpu_probe to distinguish between R3000A and R3081.
1781da177e4SLinus Torvalds  */
cpu_has_confreg(void)1791da177e4SLinus Torvalds static inline int cpu_has_confreg(void)
1801da177e4SLinus Torvalds {
1811da177e4SLinus Torvalds #ifdef CONFIG_CPU_R3000
1821da177e4SLinus Torvalds 	extern unsigned long r3k_cache_size(unsigned long);
1831da177e4SLinus Torvalds 	unsigned long size1, size2;
1841da177e4SLinus Torvalds 	unsigned long cfg = read_c0_conf();
1851da177e4SLinus Torvalds 
1861da177e4SLinus Torvalds 	size1 = r3k_cache_size(ST0_ISC);
1871da177e4SLinus Torvalds 	write_c0_conf(cfg ^ R30XX_CONF_AC);
1881da177e4SLinus Torvalds 	size2 = r3k_cache_size(ST0_ISC);
1891da177e4SLinus Torvalds 	write_c0_conf(cfg);
1901da177e4SLinus Torvalds 	return size1 != size2;
1911da177e4SLinus Torvalds #else
1921da177e4SLinus Torvalds 	return 0;
1931da177e4SLinus Torvalds #endif
1941da177e4SLinus Torvalds }
1951da177e4SLinus Torvalds 
set_elf_platform(int cpu,const char * plat)196c094c99eSRobert Millan static inline void set_elf_platform(int cpu, const char *plat)
197c094c99eSRobert Millan {
198c094c99eSRobert Millan 	if (cpu == 0)
199c094c99eSRobert Millan 		__elf_platform = plat;
200c094c99eSRobert Millan }
201c094c99eSRobert Millan 
set_elf_base_platform(const char * plat)202e585b768SYunQiang Su static inline void set_elf_base_platform(const char *plat)
203e585b768SYunQiang Su {
204e585b768SYunQiang Su 	if (__elf_base_platform == NULL) {
205e585b768SYunQiang Su 		__elf_base_platform = plat;
206e585b768SYunQiang Su 	}
207e585b768SYunQiang Su }
208e585b768SYunQiang Su 
cpu_probe_vmbits(struct cpuinfo_mips * c)20991dfc423SGuenter Roeck static inline void cpu_probe_vmbits(struct cpuinfo_mips *c)
21091dfc423SGuenter Roeck {
21191dfc423SGuenter Roeck #ifdef __NEED_VMBITS_PROBE
2125b7efa89SDavid Daney 	write_c0_entryhi(0x3fffffffffffe000ULL);
21391dfc423SGuenter Roeck 	back_to_back_c0_hazard();
2145b7efa89SDavid Daney 	c->vmbits = fls64(read_c0_entryhi() & 0x3fffffffffffe000ULL);
21591dfc423SGuenter Roeck #endif
21691dfc423SGuenter Roeck }
21791dfc423SGuenter Roeck 
set_isa(struct cpuinfo_mips * c,unsigned int isa)218078a55fcSPaul Gortmaker static void set_isa(struct cpuinfo_mips *c, unsigned int isa)
219a96102beSSteven J. Hill {
220a96102beSSteven J. Hill 	switch (isa) {
221ab7c01fdSSerge Semin 	case MIPS_CPU_ISA_M64R5:
222ab7c01fdSSerge Semin 		c->isa_level |= MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5;
223ab7c01fdSSerge Semin 		set_elf_base_platform("mips64r5");
224ab7c01fdSSerge Semin 		fallthrough;
225a96102beSSteven J. Hill 	case MIPS_CPU_ISA_M64R2:
226a96102beSSteven J. Hill 		c->isa_level |= MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2;
227e585b768SYunQiang Su 		set_elf_base_platform("mips64r2");
228c9b02990SLiangliang Huang 		fallthrough;
229a96102beSSteven J. Hill 	case MIPS_CPU_ISA_M64R1:
230a96102beSSteven J. Hill 		c->isa_level |= MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1;
231e585b768SYunQiang Su 		set_elf_base_platform("mips64");
232c9b02990SLiangliang Huang 		fallthrough;
233a96102beSSteven J. Hill 	case MIPS_CPU_ISA_V:
234a96102beSSteven J. Hill 		c->isa_level |= MIPS_CPU_ISA_V;
235e585b768SYunQiang Su 		set_elf_base_platform("mips5");
236c9b02990SLiangliang Huang 		fallthrough;
237a96102beSSteven J. Hill 	case MIPS_CPU_ISA_IV:
238a96102beSSteven J. Hill 		c->isa_level |= MIPS_CPU_ISA_IV;
239e585b768SYunQiang Su 		set_elf_base_platform("mips4");
240c9b02990SLiangliang Huang 		fallthrough;
241a96102beSSteven J. Hill 	case MIPS_CPU_ISA_III:
2421990e542SRalf Baechle 		c->isa_level |= MIPS_CPU_ISA_II | MIPS_CPU_ISA_III;
243e585b768SYunQiang Su 		set_elf_base_platform("mips3");
244a96102beSSteven J. Hill 		break;
245a96102beSSteven J. Hill 
2468b8aa636SLeonid Yegoshin 	/* R6 incompatible with everything else */
2478b8aa636SLeonid Yegoshin 	case MIPS_CPU_ISA_M64R6:
2488b8aa636SLeonid Yegoshin 		c->isa_level |= MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6;
249e585b768SYunQiang Su 		set_elf_base_platform("mips64r6");
250c9b02990SLiangliang Huang 		fallthrough;
2518b8aa636SLeonid Yegoshin 	case MIPS_CPU_ISA_M32R6:
2528b8aa636SLeonid Yegoshin 		c->isa_level |= MIPS_CPU_ISA_M32R6;
253e585b768SYunQiang Su 		set_elf_base_platform("mips32r6");
2548b8aa636SLeonid Yegoshin 		/* Break here so we don't add incompatible ISAs */
2558b8aa636SLeonid Yegoshin 		break;
256ab7c01fdSSerge Semin 	case MIPS_CPU_ISA_M32R5:
257ab7c01fdSSerge Semin 		c->isa_level |= MIPS_CPU_ISA_M32R5;
258ab7c01fdSSerge Semin 		set_elf_base_platform("mips32r5");
259ab7c01fdSSerge Semin 		fallthrough;
260a96102beSSteven J. Hill 	case MIPS_CPU_ISA_M32R2:
261a96102beSSteven J. Hill 		c->isa_level |= MIPS_CPU_ISA_M32R2;
262e585b768SYunQiang Su 		set_elf_base_platform("mips32r2");
263c9b02990SLiangliang Huang 		fallthrough;
264a96102beSSteven J. Hill 	case MIPS_CPU_ISA_M32R1:
265a96102beSSteven J. Hill 		c->isa_level |= MIPS_CPU_ISA_M32R1;
266e585b768SYunQiang Su 		set_elf_base_platform("mips32");
267c9b02990SLiangliang Huang 		fallthrough;
268a96102beSSteven J. Hill 	case MIPS_CPU_ISA_II:
269a96102beSSteven J. Hill 		c->isa_level |= MIPS_CPU_ISA_II;
270e585b768SYunQiang Su 		set_elf_base_platform("mips2");
271a96102beSSteven J. Hill 		break;
272a96102beSSteven J. Hill 	}
273a96102beSSteven J. Hill }
274a96102beSSteven J. Hill 
275078a55fcSPaul Gortmaker static char unknown_isa[] = KERN_ERR \
2762fa36399SKelvin Cheung 	"Unsupported ISA type, c0.config0: %d.";
2772fa36399SKelvin Cheung 
calculate_ftlb_probability(struct cpuinfo_mips * c)278cf0a8aa0SMarkos Chandras static unsigned int calculate_ftlb_probability(struct cpuinfo_mips *c)
279cf0a8aa0SMarkos Chandras {
280cf0a8aa0SMarkos Chandras 
281cf0a8aa0SMarkos Chandras 	unsigned int probability = c->tlbsize / c->tlbsizevtlb;
282cf0a8aa0SMarkos Chandras 
283cf0a8aa0SMarkos Chandras 	/*
284cf0a8aa0SMarkos Chandras 	 * 0 = All TLBWR instructions go to FTLB
285cf0a8aa0SMarkos Chandras 	 * 1 = 15:1: For every 16 TBLWR instructions, 15 go to the
286cf0a8aa0SMarkos Chandras 	 * FTLB and 1 goes to the VTLB.
287cf0a8aa0SMarkos Chandras 	 * 2 = 7:1: As above with 7:1 ratio.
288cf0a8aa0SMarkos Chandras 	 * 3 = 3:1: As above with 3:1 ratio.
289cf0a8aa0SMarkos Chandras 	 *
290cf0a8aa0SMarkos Chandras 	 * Use the linear midpoint as the probability threshold.
291cf0a8aa0SMarkos Chandras 	 */
292cf0a8aa0SMarkos Chandras 	if (probability >= 12)
293cf0a8aa0SMarkos Chandras 		return 1;
294cf0a8aa0SMarkos Chandras 	else if (probability >= 6)
295cf0a8aa0SMarkos Chandras 		return 2;
296cf0a8aa0SMarkos Chandras 	else
297cf0a8aa0SMarkos Chandras 		/*
298cf0a8aa0SMarkos Chandras 		 * So FTLB is less than 4 times bigger than VTLB.
299cf0a8aa0SMarkos Chandras 		 * A 3:1 ratio can still be useful though.
300cf0a8aa0SMarkos Chandras 		 */
301cf0a8aa0SMarkos Chandras 		return 3;
302cf0a8aa0SMarkos Chandras }
303cf0a8aa0SMarkos Chandras 
set_ftlb_enable(struct cpuinfo_mips * c,enum ftlb_flags flags)304ebd0e0f5SPaul Burton static int set_ftlb_enable(struct cpuinfo_mips *c, enum ftlb_flags flags)
30575b5b5e0SLeonid Yegoshin {
30620a7f7e5SMarkos Chandras 	unsigned int config;
307d83b0e82SJames Hogan 
308d83b0e82SJames Hogan 	/* It's implementation dependent how the FTLB can be enabled */
309d83b0e82SJames Hogan 	switch (c->cputype) {
310d83b0e82SJames Hogan 	case CPU_PROAPTIV:
311d83b0e82SJames Hogan 	case CPU_P5600:
3121091bfa2SPaul Burton 	case CPU_P6600:
313d83b0e82SJames Hogan 		/* proAptiv & related cores use Config6 to enable the FTLB */
31420a7f7e5SMarkos Chandras 		config = read_c0_config6();
315ebd0e0f5SPaul Burton 
316ebd0e0f5SPaul Burton 		if (flags & FTLB_EN)
31704ef32afSHuacai Chen 			config |= MTI_CONF6_FTLBEN;
31875b5b5e0SLeonid Yegoshin 		else
31904ef32afSHuacai Chen 			config &= ~MTI_CONF6_FTLBEN;
320ebd0e0f5SPaul Burton 
321ebd0e0f5SPaul Burton 		if (flags & FTLB_SET_PROB) {
32204ef32afSHuacai Chen 			config &= ~(3 << MTI_CONF6_FTLBP_SHIFT);
323ebd0e0f5SPaul Burton 			config |= calculate_ftlb_probability(c)
32404ef32afSHuacai Chen 				  << MTI_CONF6_FTLBP_SHIFT;
325ebd0e0f5SPaul Burton 		}
326ebd0e0f5SPaul Burton 
327ebd0e0f5SPaul Burton 		write_c0_config6(config);
32867acd8d5SPaul Burton 		back_to_back_c0_hazard();
32920a7f7e5SMarkos Chandras 		break;
33020a7f7e5SMarkos Chandras 	case CPU_I6400:
331859aeb1bSPaul Burton 	case CPU_I6500:
33272c70f01SPaul Burton 		/* There's no way to disable the FTLB */
333ebd0e0f5SPaul Burton 		if (!(flags & FTLB_EN))
334ebd0e0f5SPaul Burton 			return 1;
335ebd0e0f5SPaul Burton 		return 0;
336268a2d60SJiaxun Yang 	case CPU_LOONGSON64:
33706e4814eSHuacai Chen 		/* Flush ITLB, DTLB, VTLB and FTLB */
33806e4814eSHuacai Chen 		write_c0_diag(LOONGSON_DIAG_ITLB | LOONGSON_DIAG_DTLB |
33906e4814eSHuacai Chen 			      LOONGSON_DIAG_VTLB | LOONGSON_DIAG_FTLB);
340b2edcfc8SHuacai Chen 		/* Loongson-3 cores use Config6 to enable the FTLB */
341b2edcfc8SHuacai Chen 		config = read_c0_config6();
342ebd0e0f5SPaul Burton 		if (flags & FTLB_EN)
343b2edcfc8SHuacai Chen 			/* Enable FTLB */
34404ef32afSHuacai Chen 			write_c0_config6(config & ~LOONGSON_CONF6_FTLBDIS);
345b2edcfc8SHuacai Chen 		else
346b2edcfc8SHuacai Chen 			/* Disable FTLB */
34704ef32afSHuacai Chen 			write_c0_config6(config | LOONGSON_CONF6_FTLBDIS);
348b2edcfc8SHuacai Chen 		break;
349912708c2SMarkos Chandras 	default:
350912708c2SMarkos Chandras 		return 1;
35175b5b5e0SLeonid Yegoshin 	}
352912708c2SMarkos Chandras 
353912708c2SMarkos Chandras 	return 0;
35475b5b5e0SLeonid Yegoshin }
35575b5b5e0SLeonid Yegoshin 
mm_config(struct cpuinfo_mips * c)356742318adSSerge Semin static int mm_config(struct cpuinfo_mips *c)
357742318adSSerge Semin {
358742318adSSerge Semin 	unsigned int config0, update, mm;
359742318adSSerge Semin 
360742318adSSerge Semin 	config0 = read_c0_config();
361742318adSSerge Semin 	mm = config0 & MIPS_CONF_MM;
362742318adSSerge Semin 
363742318adSSerge Semin 	/*
364742318adSSerge Semin 	 * It's implementation dependent what type of write-merge is supported
365742318adSSerge Semin 	 * and whether it can be enabled/disabled. If it is settable lets make
366742318adSSerge Semin 	 * the merging allowed by default. Some platforms might have
367742318adSSerge Semin 	 * write-through caching unsupported. In this case just ignore the
368742318adSSerge Semin 	 * CP0.Config.MM bit field value.
369742318adSSerge Semin 	 */
370742318adSSerge Semin 	switch (c->cputype) {
371742318adSSerge Semin 	case CPU_24K:
372742318adSSerge Semin 	case CPU_34K:
373742318adSSerge Semin 	case CPU_74K:
374742318adSSerge Semin 	case CPU_P5600:
375742318adSSerge Semin 	case CPU_P6600:
376742318adSSerge Semin 		c->options |= MIPS_CPU_MM_FULL;
377742318adSSerge Semin 		update = MIPS_CONF_MM_FULL;
378742318adSSerge Semin 		break;
379742318adSSerge Semin 	case CPU_1004K:
380742318adSSerge Semin 	case CPU_1074K:
381742318adSSerge Semin 	case CPU_INTERAPTIV:
382742318adSSerge Semin 	case CPU_PROAPTIV:
383742318adSSerge Semin 		mm = 0;
384742318adSSerge Semin 		fallthrough;
385742318adSSerge Semin 	default:
386742318adSSerge Semin 		update = 0;
387742318adSSerge Semin 		break;
388742318adSSerge Semin 	}
389742318adSSerge Semin 
390742318adSSerge Semin 	if (update) {
391742318adSSerge Semin 		config0 = (config0 & ~MIPS_CONF_MM) | update;
392742318adSSerge Semin 		write_c0_config(config0);
393742318adSSerge Semin 	} else if (mm == MIPS_CONF_MM_SYSAD) {
394742318adSSerge Semin 		c->options |= MIPS_CPU_MM_SYSAD;
395742318adSSerge Semin 	} else if (mm == MIPS_CONF_MM_FULL) {
396742318adSSerge Semin 		c->options |= MIPS_CPU_MM_FULL;
397742318adSSerge Semin 	}
398742318adSSerge Semin 
399742318adSSerge Semin 	return 0;
400742318adSSerge Semin }
401742318adSSerge Semin 
decode_config0(struct cpuinfo_mips * c)4022fa36399SKelvin Cheung static inline unsigned int decode_config0(struct cpuinfo_mips *c)
4032fa36399SKelvin Cheung {
4042fa36399SKelvin Cheung 	unsigned int config0;
4052f6f3136SJames Hogan 	int isa, mt;
4062fa36399SKelvin Cheung 
4072fa36399SKelvin Cheung 	config0 = read_c0_config();
4082fa36399SKelvin Cheung 
40975b5b5e0SLeonid Yegoshin 	/*
41075b5b5e0SLeonid Yegoshin 	 * Look for Standard TLB or Dual VTLB and FTLB
41175b5b5e0SLeonid Yegoshin 	 */
4122f6f3136SJames Hogan 	mt = config0 & MIPS_CONF_MT;
4132f6f3136SJames Hogan 	if (mt == MIPS_CONF_MT_TLB)
4142fa36399SKelvin Cheung 		c->options |= MIPS_CPU_TLB;
4152f6f3136SJames Hogan 	else if (mt == MIPS_CONF_MT_FTLB)
4162f6f3136SJames Hogan 		c->options |= MIPS_CPU_TLB | MIPS_CPU_FTLB;
41775b5b5e0SLeonid Yegoshin 
4182fa36399SKelvin Cheung 	isa = (config0 & MIPS_CONF_AT) >> 13;
4192fa36399SKelvin Cheung 	switch (isa) {
4202fa36399SKelvin Cheung 	case 0:
4212fa36399SKelvin Cheung 		switch ((config0 & MIPS_CONF_AR) >> 10) {
4222fa36399SKelvin Cheung 		case 0:
423a96102beSSteven J. Hill 			set_isa(c, MIPS_CPU_ISA_M32R1);
4242fa36399SKelvin Cheung 			break;
4252fa36399SKelvin Cheung 		case 1:
426a96102beSSteven J. Hill 			set_isa(c, MIPS_CPU_ISA_M32R2);
4272fa36399SKelvin Cheung 			break;
4288b8aa636SLeonid Yegoshin 		case 2:
4298b8aa636SLeonid Yegoshin 			set_isa(c, MIPS_CPU_ISA_M32R6);
4308b8aa636SLeonid Yegoshin 			break;
4312fa36399SKelvin Cheung 		default:
4322fa36399SKelvin Cheung 			goto unknown;
4332fa36399SKelvin Cheung 		}
4342fa36399SKelvin Cheung 		break;
4352fa36399SKelvin Cheung 	case 2:
4362fa36399SKelvin Cheung 		switch ((config0 & MIPS_CONF_AR) >> 10) {
4372fa36399SKelvin Cheung 		case 0:
438a96102beSSteven J. Hill 			set_isa(c, MIPS_CPU_ISA_M64R1);
4392fa36399SKelvin Cheung 			break;
4402fa36399SKelvin Cheung 		case 1:
441a96102beSSteven J. Hill 			set_isa(c, MIPS_CPU_ISA_M64R2);
4422fa36399SKelvin Cheung 			break;
4438b8aa636SLeonid Yegoshin 		case 2:
4448b8aa636SLeonid Yegoshin 			set_isa(c, MIPS_CPU_ISA_M64R6);
4458b8aa636SLeonid Yegoshin 			break;
4462fa36399SKelvin Cheung 		default:
4472fa36399SKelvin Cheung 			goto unknown;
4482fa36399SKelvin Cheung 		}
4492fa36399SKelvin Cheung 		break;
4502fa36399SKelvin Cheung 	default:
4512fa36399SKelvin Cheung 		goto unknown;
4522fa36399SKelvin Cheung 	}
4532fa36399SKelvin Cheung 
4542fa36399SKelvin Cheung 	return config0 & MIPS_CONF_M;
4552fa36399SKelvin Cheung 
4562fa36399SKelvin Cheung unknown:
4572fa36399SKelvin Cheung 	panic(unknown_isa, config0);
4582fa36399SKelvin Cheung }
4592fa36399SKelvin Cheung 
decode_config1(struct cpuinfo_mips * c)4602fa36399SKelvin Cheung static inline unsigned int decode_config1(struct cpuinfo_mips *c)
4612fa36399SKelvin Cheung {
4622fa36399SKelvin Cheung 	unsigned int config1;
4632fa36399SKelvin Cheung 
4642fa36399SKelvin Cheung 	config1 = read_c0_config1();
4652fa36399SKelvin Cheung 
4662fa36399SKelvin Cheung 	if (config1 & MIPS_CONF1_MD)
4672fa36399SKelvin Cheung 		c->ases |= MIPS_ASE_MDMX;
46830228c40SJames Hogan 	if (config1 & MIPS_CONF1_PC)
46930228c40SJames Hogan 		c->options |= MIPS_CPU_PERF;
4702fa36399SKelvin Cheung 	if (config1 & MIPS_CONF1_WR)
4712fa36399SKelvin Cheung 		c->options |= MIPS_CPU_WATCH;
4722fa36399SKelvin Cheung 	if (config1 & MIPS_CONF1_CA)
4732fa36399SKelvin Cheung 		c->ases |= MIPS_ASE_MIPS16;
4742fa36399SKelvin Cheung 	if (config1 & MIPS_CONF1_EP)
4752fa36399SKelvin Cheung 		c->options |= MIPS_CPU_EJTAG;
4762fa36399SKelvin Cheung 	if (config1 & MIPS_CONF1_FP) {
4772fa36399SKelvin Cheung 		c->options |= MIPS_CPU_FPU;
4782fa36399SKelvin Cheung 		c->options |= MIPS_CPU_32FPR;
4792fa36399SKelvin Cheung 	}
48075b5b5e0SLeonid Yegoshin 	if (cpu_has_tlb) {
4812fa36399SKelvin Cheung 		c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1;
48275b5b5e0SLeonid Yegoshin 		c->tlbsizevtlb = c->tlbsize;
48375b5b5e0SLeonid Yegoshin 		c->tlbsizeftlbsets = 0;
48475b5b5e0SLeonid Yegoshin 	}
4852fa36399SKelvin Cheung 
4862fa36399SKelvin Cheung 	return config1 & MIPS_CONF_M;
4872fa36399SKelvin Cheung }
4882fa36399SKelvin Cheung 
decode_config2(struct cpuinfo_mips * c)4892fa36399SKelvin Cheung static inline unsigned int decode_config2(struct cpuinfo_mips *c)
4902fa36399SKelvin Cheung {
4912fa36399SKelvin Cheung 	unsigned int config2;
4922fa36399SKelvin Cheung 
4932fa36399SKelvin Cheung 	config2 = read_c0_config2();
4942fa36399SKelvin Cheung 
4952fa36399SKelvin Cheung 	if (config2 & MIPS_CONF2_SL)
4962fa36399SKelvin Cheung 		c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
4972fa36399SKelvin Cheung 
4982fa36399SKelvin Cheung 	return config2 & MIPS_CONF_M;
4992fa36399SKelvin Cheung }
5002fa36399SKelvin Cheung 
decode_config3(struct cpuinfo_mips * c)5012fa36399SKelvin Cheung static inline unsigned int decode_config3(struct cpuinfo_mips *c)
5022fa36399SKelvin Cheung {
5032fa36399SKelvin Cheung 	unsigned int config3;
5042fa36399SKelvin Cheung 
5052fa36399SKelvin Cheung 	config3 = read_c0_config3();
5062fa36399SKelvin Cheung 
507b2ab4f08SSteven J. Hill 	if (config3 & MIPS_CONF3_SM) {
5082fa36399SKelvin Cheung 		c->ases |= MIPS_ASE_SMARTMIPS;
509f18bdfa1SJames Hogan 		c->options |= MIPS_CPU_RIXI | MIPS_CPU_CTXTC;
510b2ab4f08SSteven J. Hill 	}
511b2ab4f08SSteven J. Hill 	if (config3 & MIPS_CONF3_RXI)
512b2ab4f08SSteven J. Hill 		c->options |= MIPS_CPU_RIXI;
513f18bdfa1SJames Hogan 	if (config3 & MIPS_CONF3_CTXTC)
514f18bdfa1SJames Hogan 		c->options |= MIPS_CPU_CTXTC;
5152fa36399SKelvin Cheung 	if (config3 & MIPS_CONF3_DSP)
5162fa36399SKelvin Cheung 		c->ases |= MIPS_ASE_DSP;
517b5a6455cSZubair Lutfullah Kakakhel 	if (config3 & MIPS_CONF3_DSP2P) {
518ee80f7c7SSteven J. Hill 		c->ases |= MIPS_ASE_DSP2P;
519b5a6455cSZubair Lutfullah Kakakhel 		if (cpu_has_mips_r6)
520b5a6455cSZubair Lutfullah Kakakhel 			c->ases |= MIPS_ASE_DSP3;
521b5a6455cSZubair Lutfullah Kakakhel 	}
5222fa36399SKelvin Cheung 	if (config3 & MIPS_CONF3_VINT)
5232fa36399SKelvin Cheung 		c->options |= MIPS_CPU_VINT;
5242fa36399SKelvin Cheung 	if (config3 & MIPS_CONF3_VEIC)
5252fa36399SKelvin Cheung 		c->options |= MIPS_CPU_VEIC;
52612822570SJames Hogan 	if (config3 & MIPS_CONF3_LPA)
52712822570SJames Hogan 		c->options |= MIPS_CPU_LPA;
5282fa36399SKelvin Cheung 	if (config3 & MIPS_CONF3_MT)
5292fa36399SKelvin Cheung 		c->ases |= MIPS_ASE_MIPSMT;
5302fa36399SKelvin Cheung 	if (config3 & MIPS_CONF3_ULRI)
5312fa36399SKelvin Cheung 		c->options |= MIPS_CPU_ULRI;
532f8fa4811SSteven J. Hill 	if (config3 & MIPS_CONF3_ISA)
533f8fa4811SSteven J. Hill 		c->options |= MIPS_CPU_MICROMIPS;
5341e7decdbSDavid Daney 	if (config3 & MIPS_CONF3_VZ)
5351e7decdbSDavid Daney 		c->ases |= MIPS_ASE_VZ;
5364a0156fbSSteven J. Hill 	if (config3 & MIPS_CONF3_SC)
5374a0156fbSSteven J. Hill 		c->options |= MIPS_CPU_SEGMENTS;
538e06a1548SJames Hogan 	if (config3 & MIPS_CONF3_BI)
539e06a1548SJames Hogan 		c->options |= MIPS_CPU_BADINSTR;
540e06a1548SJames Hogan 	if (config3 & MIPS_CONF3_BP)
541e06a1548SJames Hogan 		c->options |= MIPS_CPU_BADINSTRP;
542a5e9a69eSPaul Burton 	if (config3 & MIPS_CONF3_MSA)
543a5e9a69eSPaul Burton 		c->ases |= MIPS_ASE_MSA;
544cab25bc7SPaul Burton 	if (config3 & MIPS_CONF3_PW) {
545ed4cbc81SMarkos Chandras 		c->htw_seq = 0;
5463d528b32SMarkos Chandras 		c->options |= MIPS_CPU_HTW;
547ed4cbc81SMarkos Chandras 	}
5489b3274bdSJames Hogan 	if (config3 & MIPS_CONF3_CDMM)
5499b3274bdSJames Hogan 		c->options |= MIPS_CPU_CDMM;
550aaa7be48SJames Hogan 	if (config3 & MIPS_CONF3_SP)
551aaa7be48SJames Hogan 		c->options |= MIPS_CPU_SP;
5522fa36399SKelvin Cheung 
5532fa36399SKelvin Cheung 	return config3 & MIPS_CONF_M;
5542fa36399SKelvin Cheung }
5552fa36399SKelvin Cheung 
decode_config4(struct cpuinfo_mips * c)5562fa36399SKelvin Cheung static inline unsigned int decode_config4(struct cpuinfo_mips *c)
5572fa36399SKelvin Cheung {
5582fa36399SKelvin Cheung 	unsigned int config4;
55975b5b5e0SLeonid Yegoshin 	unsigned int newcf4;
56075b5b5e0SLeonid Yegoshin 	unsigned int mmuextdef;
56175b5b5e0SLeonid Yegoshin 	unsigned int ftlb_page = MIPS_CONF4_FTLBPAGESIZE;
5622db003a5SPaul Burton 	unsigned long asid_mask;
5632fa36399SKelvin Cheung 
5642fa36399SKelvin Cheung 	config4 = read_c0_config4();
5652fa36399SKelvin Cheung 
5661745c1efSLeonid Yegoshin 	if (cpu_has_tlb) {
5671745c1efSLeonid Yegoshin 		if (((config4 & MIPS_CONF4_IE) >> 29) == 2)
5681745c1efSLeonid Yegoshin 			c->options |= MIPS_CPU_TLBINV;
56943d104dbSJames Hogan 
570e87569cdSMarkos Chandras 		/*
57143d104dbSJames Hogan 		 * R6 has dropped the MMUExtDef field from config4.
57243d104dbSJames Hogan 		 * On R6 the fields always describe the FTLB, and only if it is
57343d104dbSJames Hogan 		 * present according to Config.MT.
574e87569cdSMarkos Chandras 		 */
57543d104dbSJames Hogan 		if (!cpu_has_mips_r6)
57643d104dbSJames Hogan 			mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF;
57743d104dbSJames Hogan 		else if (cpu_has_ftlb)
578e87569cdSMarkos Chandras 			mmuextdef = MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT;
579e87569cdSMarkos Chandras 		else
58043d104dbSJames Hogan 			mmuextdef = 0;
581e87569cdSMarkos Chandras 
58275b5b5e0SLeonid Yegoshin 		switch (mmuextdef) {
58375b5b5e0SLeonid Yegoshin 		case MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT:
58475b5b5e0SLeonid Yegoshin 			c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
58575b5b5e0SLeonid Yegoshin 			c->tlbsizevtlb = c->tlbsize;
58675b5b5e0SLeonid Yegoshin 			break;
58775b5b5e0SLeonid Yegoshin 		case MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT:
58875b5b5e0SLeonid Yegoshin 			c->tlbsizevtlb +=
58975b5b5e0SLeonid Yegoshin 				((config4 & MIPS_CONF4_VTLBSIZEEXT) >>
59075b5b5e0SLeonid Yegoshin 				  MIPS_CONF4_VTLBSIZEEXT_SHIFT) * 0x40;
59175b5b5e0SLeonid Yegoshin 			c->tlbsize = c->tlbsizevtlb;
59275b5b5e0SLeonid Yegoshin 			ftlb_page = MIPS_CONF4_VFTLBPAGESIZE;
593c9b02990SLiangliang Huang 			fallthrough;
59475b5b5e0SLeonid Yegoshin 		case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT:
59597f4ad29SMarkos Chandras 			if (mips_ftlb_disabled)
59697f4ad29SMarkos Chandras 				break;
59775b5b5e0SLeonid Yegoshin 			newcf4 = (config4 & ~ftlb_page) |
59875b5b5e0SLeonid Yegoshin 				(page_size_ftlb(mmuextdef) <<
59975b5b5e0SLeonid Yegoshin 				 MIPS_CONF4_FTLBPAGESIZE_SHIFT);
60075b5b5e0SLeonid Yegoshin 			write_c0_config4(newcf4);
60175b5b5e0SLeonid Yegoshin 			back_to_back_c0_hazard();
60275b5b5e0SLeonid Yegoshin 			config4 = read_c0_config4();
60375b5b5e0SLeonid Yegoshin 			if (config4 != newcf4) {
60475b5b5e0SLeonid Yegoshin 				pr_err("PAGE_SIZE 0x%lx is not supported by FTLB (config4=0x%x)\n",
60575b5b5e0SLeonid Yegoshin 				       PAGE_SIZE, config4);
60675b5b5e0SLeonid Yegoshin 				/* Switch FTLB off */
60775b5b5e0SLeonid Yegoshin 				set_ftlb_enable(c, 0);
608ebd0e0f5SPaul Burton 				mips_ftlb_disabled = 1;
60975b5b5e0SLeonid Yegoshin 				break;
61075b5b5e0SLeonid Yegoshin 			}
61175b5b5e0SLeonid Yegoshin 			c->tlbsizeftlbsets = 1 <<
61275b5b5e0SLeonid Yegoshin 				((config4 & MIPS_CONF4_FTLBSETS) >>
61375b5b5e0SLeonid Yegoshin 				 MIPS_CONF4_FTLBSETS_SHIFT);
61475b5b5e0SLeonid Yegoshin 			c->tlbsizeftlbways = ((config4 & MIPS_CONF4_FTLBWAYS) >>
61575b5b5e0SLeonid Yegoshin 					      MIPS_CONF4_FTLBWAYS_SHIFT) + 2;
61675b5b5e0SLeonid Yegoshin 			c->tlbsize += c->tlbsizeftlbways * c->tlbsizeftlbsets;
61797f4ad29SMarkos Chandras 			mips_has_ftlb_configured = 1;
61875b5b5e0SLeonid Yegoshin 			break;
61975b5b5e0SLeonid Yegoshin 		}
6201745c1efSLeonid Yegoshin 	}
6211745c1efSLeonid Yegoshin 
6229e575f75SJames Hogan 	c->kscratch_mask = (config4 & MIPS_CONF4_KSCREXIST)
6239e575f75SJames Hogan 				>> MIPS_CONF4_KSCREXIST_SHIFT;
6242fa36399SKelvin Cheung 
6252db003a5SPaul Burton 	asid_mask = MIPS_ENTRYHI_ASID;
6262db003a5SPaul Burton 	if (config4 & MIPS_CONF4_AE)
6272db003a5SPaul Burton 		asid_mask |= MIPS_ENTRYHI_ASIDX;
6282db003a5SPaul Burton 	set_cpu_asid_mask(c, asid_mask);
6292db003a5SPaul Burton 
6302db003a5SPaul Burton 	/*
6312db003a5SPaul Burton 	 * Warn if the computed ASID mask doesn't match the mask the kernel
6322db003a5SPaul Burton 	 * is built for. This may indicate either a serious problem or an
6332db003a5SPaul Burton 	 * easy optimisation opportunity, but either way should be addressed.
6342db003a5SPaul Burton 	 */
6352db003a5SPaul Burton 	WARN_ON(asid_mask != cpu_asid_mask(c));
6362db003a5SPaul Burton 
6372fa36399SKelvin Cheung 	return config4 & MIPS_CONF_M;
6382fa36399SKelvin Cheung }
6392fa36399SKelvin Cheung 
decode_config5(struct cpuinfo_mips * c)6408b8a7634SRalf Baechle static inline unsigned int decode_config5(struct cpuinfo_mips *c)
6418b8a7634SRalf Baechle {
642c8790d65SPaul Burton 	unsigned int config5, max_mmid_width;
643c8790d65SPaul Burton 	unsigned long asid_mask;
6448b8a7634SRalf Baechle 
6458b8a7634SRalf Baechle 	config5 = read_c0_config5();
646d175ed2bSPaul Burton 	config5 &= ~(MIPS_CONF5_UFR | MIPS_CONF5_UFE);
647c8790d65SPaul Burton 
648c8790d65SPaul Burton 	if (cpu_has_mips_r6) {
649c8790d65SPaul Burton 		if (!__builtin_constant_p(cpu_has_mmid) || cpu_has_mmid)
650c8790d65SPaul Burton 			config5 |= MIPS_CONF5_MI;
651c8790d65SPaul Burton 		else
652c8790d65SPaul Burton 			config5 &= ~MIPS_CONF5_MI;
653c8790d65SPaul Burton 	}
654c8790d65SPaul Burton 
6558b8a7634SRalf Baechle 	write_c0_config5(config5);
6568b8a7634SRalf Baechle 
65749016748SMarkos Chandras 	if (config5 & MIPS_CONF5_EVA)
65849016748SMarkos Chandras 		c->options |= MIPS_CPU_EVA;
6591f6c52ffSPaul Burton 	if (config5 & MIPS_CONF5_MRP)
6601f6c52ffSPaul Burton 		c->options |= MIPS_CPU_MAAR;
6615aed9da1SMarkos Chandras 	if (config5 & MIPS_CONF5_LLB)
6625aed9da1SMarkos Chandras 		c->options |= MIPS_CPU_RW_LLB;
663c5b36783SSteven J. Hill 	if (config5 & MIPS_CONF5_MVH)
6640f2d988dSJames Hogan 		c->options |= MIPS_CPU_MVH;
665f270d881SPaul Burton 	if (cpu_has_mips_r6 && (config5 & MIPS_CONF5_VP))
666f270d881SPaul Burton 		c->options |= MIPS_CPU_VP;
6678d1630f1SMaciej W. Rozycki 	if (config5 & MIPS_CONF5_CA2)
6688d1630f1SMaciej W. Rozycki 		c->ases |= MIPS_ASE_MIPS16E2;
66949016748SMarkos Chandras 
670256211f2SMarcin Nowakowski 	if (config5 & MIPS_CONF5_CRCP)
671256211f2SMarcin Nowakowski 		elf_hwcap |= HWCAP_MIPS_CRC32;
672256211f2SMarcin Nowakowski 
673c8790d65SPaul Burton 	if (cpu_has_mips_r6) {
674c8790d65SPaul Burton 		/* Ensure the write to config5 above takes effect */
675c8790d65SPaul Burton 		back_to_back_c0_hazard();
676c8790d65SPaul Burton 
677c8790d65SPaul Burton 		/* Check whether we successfully enabled MMID support */
678c8790d65SPaul Burton 		config5 = read_c0_config5();
679c8790d65SPaul Burton 		if (config5 & MIPS_CONF5_MI)
680c8790d65SPaul Burton 			c->options |= MIPS_CPU_MMID;
681c8790d65SPaul Burton 
682c8790d65SPaul Burton 		/*
683c8790d65SPaul Burton 		 * Warn if we've hardcoded cpu_has_mmid to a value unsuitable
684c8790d65SPaul Burton 		 * for the CPU we're running on, or if CPUs in an SMP system
685c8790d65SPaul Burton 		 * have inconsistent MMID support.
686c8790d65SPaul Burton 		 */
687c8790d65SPaul Burton 		WARN_ON(!!cpu_has_mmid != !!(config5 & MIPS_CONF5_MI));
688c8790d65SPaul Burton 
689c8790d65SPaul Burton 		if (cpu_has_mmid) {
690c8790d65SPaul Burton 			write_c0_memorymapid(~0ul);
691c8790d65SPaul Burton 			back_to_back_c0_hazard();
692c8790d65SPaul Burton 			asid_mask = read_c0_memorymapid();
693c8790d65SPaul Burton 
694c8790d65SPaul Burton 			/*
695c8790d65SPaul Burton 			 * We maintain a bitmap to track MMID allocation, and
696c8790d65SPaul Burton 			 * need a sensible upper bound on the size of that
697c8790d65SPaul Burton 			 * bitmap. The initial CPU with MMID support (I6500)
698c8790d65SPaul Burton 			 * supports 16 bit MMIDs, which gives us an 8KiB
699c8790d65SPaul Burton 			 * bitmap. The architecture recommends that hardware
700c8790d65SPaul Burton 			 * support 32 bit MMIDs, which would give us a 512MiB
701c8790d65SPaul Burton 			 * bitmap - that's too big in most cases.
702c8790d65SPaul Burton 			 *
703c8790d65SPaul Burton 			 * Cap MMID width at 16 bits for now & we can revisit
704c8790d65SPaul Burton 			 * this if & when hardware supports anything wider.
705c8790d65SPaul Burton 			 */
706c8790d65SPaul Burton 			max_mmid_width = 16;
707c8790d65SPaul Burton 			if (asid_mask > GENMASK(max_mmid_width - 1, 0)) {
708c8790d65SPaul Burton 				pr_info("Capping MMID width at %d bits",
709c8790d65SPaul Burton 					max_mmid_width);
710c8790d65SPaul Burton 				asid_mask = GENMASK(max_mmid_width - 1, 0);
711c8790d65SPaul Burton 			}
712c8790d65SPaul Burton 
713c8790d65SPaul Burton 			set_cpu_asid_mask(c, asid_mask);
714c8790d65SPaul Burton 		}
715c8790d65SPaul Burton 	}
716c8790d65SPaul Burton 
7178b8a7634SRalf Baechle 	return config5 & MIPS_CONF_M;
7188b8a7634SRalf Baechle }
7198b8a7634SRalf Baechle 
decode_configs(struct cpuinfo_mips * c)720078a55fcSPaul Gortmaker static void decode_configs(struct cpuinfo_mips *c)
7212fa36399SKelvin Cheung {
7222fa36399SKelvin Cheung 	int ok;
7232fa36399SKelvin Cheung 
7242fa36399SKelvin Cheung 	/* MIPS32 or MIPS64 compliant CPU.  */
7252fa36399SKelvin Cheung 	c->options = MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER |
7262fa36399SKelvin Cheung 		     MIPS_CPU_DIVEC | MIPS_CPU_LLSC | MIPS_CPU_MCHECK;
7272fa36399SKelvin Cheung 
7282fa36399SKelvin Cheung 	c->scache.flags = MIPS_CACHE_NOT_PRESENT;
7292fa36399SKelvin Cheung 
73097f4ad29SMarkos Chandras 	/* Enable FTLB if present and not disabled */
731ebd0e0f5SPaul Burton 	set_ftlb_enable(c, mips_ftlb_disabled ? 0 : FTLB_EN);
73275b5b5e0SLeonid Yegoshin 
7332fa36399SKelvin Cheung 	ok = decode_config0(c);			/* Read Config registers.  */
7342fa36399SKelvin Cheung 	BUG_ON(!ok);				/* Arch spec violation!	 */
7352fa36399SKelvin Cheung 	if (ok)
7362fa36399SKelvin Cheung 		ok = decode_config1(c);
7372fa36399SKelvin Cheung 	if (ok)
7382fa36399SKelvin Cheung 		ok = decode_config2(c);
7392fa36399SKelvin Cheung 	if (ok)
7402fa36399SKelvin Cheung 		ok = decode_config3(c);
7412fa36399SKelvin Cheung 	if (ok)
7422fa36399SKelvin Cheung 		ok = decode_config4(c);
7438b8a7634SRalf Baechle 	if (ok)
7448b8a7634SRalf Baechle 		ok = decode_config5(c);
7452fa36399SKelvin Cheung 
74637fb60f8SJames Hogan 	/* Probe the EBase.WG bit */
74737fb60f8SJames Hogan 	if (cpu_has_mips_r2_r6) {
74837fb60f8SJames Hogan 		u64 ebase;
74937fb60f8SJames Hogan 		unsigned int status;
75037fb60f8SJames Hogan 
75137fb60f8SJames Hogan 		/* {read,write}_c0_ebase_64() may be UNDEFINED prior to r6 */
75237fb60f8SJames Hogan 		ebase = cpu_has_mips64r6 ? read_c0_ebase_64()
75337fb60f8SJames Hogan 					 : (s32)read_c0_ebase();
75437fb60f8SJames Hogan 		if (ebase & MIPS_EBASE_WG) {
75537fb60f8SJames Hogan 			/* WG bit already set, we can avoid the clumsy probe */
75637fb60f8SJames Hogan 			c->options |= MIPS_CPU_EBASE_WG;
75737fb60f8SJames Hogan 		} else {
75837fb60f8SJames Hogan 			/* Its UNDEFINED to change EBase while BEV=0 */
75937fb60f8SJames Hogan 			status = read_c0_status();
76037fb60f8SJames Hogan 			write_c0_status(status | ST0_BEV);
76137fb60f8SJames Hogan 			irq_enable_hazard();
76237fb60f8SJames Hogan 			/*
76337fb60f8SJames Hogan 			 * On pre-r6 cores, this may well clobber the upper bits
76437fb60f8SJames Hogan 			 * of EBase. This is hard to avoid without potentially
76537fb60f8SJames Hogan 			 * hitting UNDEFINED dm*c0 behaviour if EBase is 32-bit.
76637fb60f8SJames Hogan 			 */
76737fb60f8SJames Hogan 			if (cpu_has_mips64r6)
76837fb60f8SJames Hogan 				write_c0_ebase_64(ebase | MIPS_EBASE_WG);
76937fb60f8SJames Hogan 			else
77037fb60f8SJames Hogan 				write_c0_ebase(ebase | MIPS_EBASE_WG);
77137fb60f8SJames Hogan 			back_to_back_c0_hazard();
77237fb60f8SJames Hogan 			/* Restore BEV */
77337fb60f8SJames Hogan 			write_c0_status(status);
77437fb60f8SJames Hogan 			if (read_c0_ebase() & MIPS_EBASE_WG) {
77537fb60f8SJames Hogan 				c->options |= MIPS_CPU_EBASE_WG;
77637fb60f8SJames Hogan 				write_c0_ebase(ebase);
77737fb60f8SJames Hogan 			}
77837fb60f8SJames Hogan 		}
77937fb60f8SJames Hogan 	}
78037fb60f8SJames Hogan 
781ebd0e0f5SPaul Burton 	/* configure the FTLB write probability */
782ebd0e0f5SPaul Burton 	set_ftlb_enable(c, (mips_ftlb_disabled ? 0 : FTLB_EN) | FTLB_SET_PROB);
783ebd0e0f5SPaul Burton 
7842fa36399SKelvin Cheung 	mips_probe_watch_registers(c);
7852fa36399SKelvin Cheung 
7860ee958e1SPaul Burton #ifndef CONFIG_MIPS_CPS
7878b8aa636SLeonid Yegoshin 	if (cpu_has_mips_r2_r6) {
788f875a832SPaul Burton 		unsigned int core;
789f875a832SPaul Burton 
790f875a832SPaul Burton 		core = get_ebase_cpunum();
79130ee615bSPaul Burton 		if (cpu_has_mipsmt)
792f875a832SPaul Burton 			core >>= fls(core_nvpes()) - 1;
793f875a832SPaul Burton 		cpu_set_core(c, core);
79430ee615bSPaul Burton 	}
7950ee958e1SPaul Burton #endif
7962fa36399SKelvin Cheung }
7972fa36399SKelvin Cheung 
7986ad816e7SJames Hogan /*
7996ad816e7SJames Hogan  * Probe for certain guest capabilities by writing config bits and reading back.
8006ad816e7SJames Hogan  * Finally write back the original value.
8016ad816e7SJames Hogan  */
8026ad816e7SJames Hogan #define probe_gc0_config(name, maxconf, bits)				\
8036ad816e7SJames Hogan do {									\
8046ad816e7SJames Hogan 	unsigned int tmp;						\
8056ad816e7SJames Hogan 	tmp = read_gc0_##name();					\
8066ad816e7SJames Hogan 	write_gc0_##name(tmp | (bits));					\
8076ad816e7SJames Hogan 	back_to_back_c0_hazard();					\
8086ad816e7SJames Hogan 	maxconf = read_gc0_##name();					\
8096ad816e7SJames Hogan 	write_gc0_##name(tmp);						\
8106ad816e7SJames Hogan } while (0)
8116ad816e7SJames Hogan 
8126ad816e7SJames Hogan /*
8136ad816e7SJames Hogan  * Probe for dynamic guest capabilities by changing certain config bits and
8146ad816e7SJames Hogan  * reading back to see if they change. Finally write back the original value.
8156ad816e7SJames Hogan  */
8166ad816e7SJames Hogan #define probe_gc0_config_dyn(name, maxconf, dynconf, bits)		\
8176ad816e7SJames Hogan do {									\
8186ad816e7SJames Hogan 	maxconf = read_gc0_##name();					\
8196ad816e7SJames Hogan 	write_gc0_##name(maxconf ^ (bits));				\
8206ad816e7SJames Hogan 	back_to_back_c0_hazard();					\
8216ad816e7SJames Hogan 	dynconf = maxconf ^ read_gc0_##name();				\
8226ad816e7SJames Hogan 	write_gc0_##name(maxconf);					\
8236ad816e7SJames Hogan 	maxconf |= dynconf;						\
8246ad816e7SJames Hogan } while (0)
8256ad816e7SJames Hogan 
decode_guest_config0(struct cpuinfo_mips * c)8266ad816e7SJames Hogan static inline unsigned int decode_guest_config0(struct cpuinfo_mips *c)
8276ad816e7SJames Hogan {
8286ad816e7SJames Hogan 	unsigned int config0;
8296ad816e7SJames Hogan 
8306ad816e7SJames Hogan 	probe_gc0_config(config, config0, MIPS_CONF_M);
8316ad816e7SJames Hogan 
8326ad816e7SJames Hogan 	if (config0 & MIPS_CONF_M)
8336ad816e7SJames Hogan 		c->guest.conf |= BIT(1);
8346ad816e7SJames Hogan 	return config0 & MIPS_CONF_M;
8356ad816e7SJames Hogan }
8366ad816e7SJames Hogan 
decode_guest_config1(struct cpuinfo_mips * c)8376ad816e7SJames Hogan static inline unsigned int decode_guest_config1(struct cpuinfo_mips *c)
8386ad816e7SJames Hogan {
8396ad816e7SJames Hogan 	unsigned int config1, config1_dyn;
8406ad816e7SJames Hogan 
8416ad816e7SJames Hogan 	probe_gc0_config_dyn(config1, config1, config1_dyn,
8426ad816e7SJames Hogan 			     MIPS_CONF_M | MIPS_CONF1_PC | MIPS_CONF1_WR |
8436ad816e7SJames Hogan 			     MIPS_CONF1_FP);
8446ad816e7SJames Hogan 
8456ad816e7SJames Hogan 	if (config1 & MIPS_CONF1_FP)
8466ad816e7SJames Hogan 		c->guest.options |= MIPS_CPU_FPU;
8476ad816e7SJames Hogan 	if (config1_dyn & MIPS_CONF1_FP)
8486ad816e7SJames Hogan 		c->guest.options_dyn |= MIPS_CPU_FPU;
8496ad816e7SJames Hogan 
8506ad816e7SJames Hogan 	if (config1 & MIPS_CONF1_WR)
8516ad816e7SJames Hogan 		c->guest.options |= MIPS_CPU_WATCH;
8526ad816e7SJames Hogan 	if (config1_dyn & MIPS_CONF1_WR)
8536ad816e7SJames Hogan 		c->guest.options_dyn |= MIPS_CPU_WATCH;
8546ad816e7SJames Hogan 
8556ad816e7SJames Hogan 	if (config1 & MIPS_CONF1_PC)
8566ad816e7SJames Hogan 		c->guest.options |= MIPS_CPU_PERF;
8576ad816e7SJames Hogan 	if (config1_dyn & MIPS_CONF1_PC)
8586ad816e7SJames Hogan 		c->guest.options_dyn |= MIPS_CPU_PERF;
8596ad816e7SJames Hogan 
8606ad816e7SJames Hogan 	if (config1 & MIPS_CONF_M)
8616ad816e7SJames Hogan 		c->guest.conf |= BIT(2);
8626ad816e7SJames Hogan 	return config1 & MIPS_CONF_M;
8636ad816e7SJames Hogan }
8646ad816e7SJames Hogan 
decode_guest_config2(struct cpuinfo_mips * c)8656ad816e7SJames Hogan static inline unsigned int decode_guest_config2(struct cpuinfo_mips *c)
8666ad816e7SJames Hogan {
8676ad816e7SJames Hogan 	unsigned int config2;
8686ad816e7SJames Hogan 
8696ad816e7SJames Hogan 	probe_gc0_config(config2, config2, MIPS_CONF_M);
8706ad816e7SJames Hogan 
8716ad816e7SJames Hogan 	if (config2 & MIPS_CONF_M)
8726ad816e7SJames Hogan 		c->guest.conf |= BIT(3);
8736ad816e7SJames Hogan 	return config2 & MIPS_CONF_M;
8746ad816e7SJames Hogan }
8756ad816e7SJames Hogan 
decode_guest_config3(struct cpuinfo_mips * c)8766ad816e7SJames Hogan static inline unsigned int decode_guest_config3(struct cpuinfo_mips *c)
8776ad816e7SJames Hogan {
8786ad816e7SJames Hogan 	unsigned int config3, config3_dyn;
8796ad816e7SJames Hogan 
8806ad816e7SJames Hogan 	probe_gc0_config_dyn(config3, config3, config3_dyn,
881a7c7ad6cSJames Hogan 			     MIPS_CONF_M | MIPS_CONF3_MSA | MIPS_CONF3_ULRI |
882a7c7ad6cSJames Hogan 			     MIPS_CONF3_CTXTC);
8836ad816e7SJames Hogan 
8846ad816e7SJames Hogan 	if (config3 & MIPS_CONF3_CTXTC)
8856ad816e7SJames Hogan 		c->guest.options |= MIPS_CPU_CTXTC;
8866ad816e7SJames Hogan 	if (config3_dyn & MIPS_CONF3_CTXTC)
8876ad816e7SJames Hogan 		c->guest.options_dyn |= MIPS_CPU_CTXTC;
8886ad816e7SJames Hogan 
8896ad816e7SJames Hogan 	if (config3 & MIPS_CONF3_PW)
8906ad816e7SJames Hogan 		c->guest.options |= MIPS_CPU_HTW;
8916ad816e7SJames Hogan 
892a7c7ad6cSJames Hogan 	if (config3 & MIPS_CONF3_ULRI)
893a7c7ad6cSJames Hogan 		c->guest.options |= MIPS_CPU_ULRI;
894a7c7ad6cSJames Hogan 
8956ad816e7SJames Hogan 	if (config3 & MIPS_CONF3_SC)
8966ad816e7SJames Hogan 		c->guest.options |= MIPS_CPU_SEGMENTS;
8976ad816e7SJames Hogan 
8986ad816e7SJames Hogan 	if (config3 & MIPS_CONF3_BI)
8996ad816e7SJames Hogan 		c->guest.options |= MIPS_CPU_BADINSTR;
9006ad816e7SJames Hogan 	if (config3 & MIPS_CONF3_BP)
9016ad816e7SJames Hogan 		c->guest.options |= MIPS_CPU_BADINSTRP;
9026ad816e7SJames Hogan 
9036ad816e7SJames Hogan 	if (config3 & MIPS_CONF3_MSA)
9046ad816e7SJames Hogan 		c->guest.ases |= MIPS_ASE_MSA;
9056ad816e7SJames Hogan 	if (config3_dyn & MIPS_CONF3_MSA)
9066ad816e7SJames Hogan 		c->guest.ases_dyn |= MIPS_ASE_MSA;
9076ad816e7SJames Hogan 
9086ad816e7SJames Hogan 	if (config3 & MIPS_CONF_M)
9096ad816e7SJames Hogan 		c->guest.conf |= BIT(4);
9106ad816e7SJames Hogan 	return config3 & MIPS_CONF_M;
9116ad816e7SJames Hogan }
9126ad816e7SJames Hogan 
decode_guest_config4(struct cpuinfo_mips * c)9136ad816e7SJames Hogan static inline unsigned int decode_guest_config4(struct cpuinfo_mips *c)
9146ad816e7SJames Hogan {
9156ad816e7SJames Hogan 	unsigned int config4;
9166ad816e7SJames Hogan 
9176ad816e7SJames Hogan 	probe_gc0_config(config4, config4,
9186ad816e7SJames Hogan 			 MIPS_CONF_M | MIPS_CONF4_KSCREXIST);
9196ad816e7SJames Hogan 
9206ad816e7SJames Hogan 	c->guest.kscratch_mask = (config4 & MIPS_CONF4_KSCREXIST)
9216ad816e7SJames Hogan 				>> MIPS_CONF4_KSCREXIST_SHIFT;
9226ad816e7SJames Hogan 
9236ad816e7SJames Hogan 	if (config4 & MIPS_CONF_M)
9246ad816e7SJames Hogan 		c->guest.conf |= BIT(5);
9256ad816e7SJames Hogan 	return config4 & MIPS_CONF_M;
9266ad816e7SJames Hogan }
9276ad816e7SJames Hogan 
decode_guest_config5(struct cpuinfo_mips * c)9286ad816e7SJames Hogan static inline unsigned int decode_guest_config5(struct cpuinfo_mips *c)
9296ad816e7SJames Hogan {
9306ad816e7SJames Hogan 	unsigned int config5, config5_dyn;
9316ad816e7SJames Hogan 
9326ad816e7SJames Hogan 	probe_gc0_config_dyn(config5, config5, config5_dyn,
933a929bdc5SJames Hogan 			 MIPS_CONF_M | MIPS_CONF5_MVH | MIPS_CONF5_MRP);
9346ad816e7SJames Hogan 
9356ad816e7SJames Hogan 	if (config5 & MIPS_CONF5_MRP)
9366ad816e7SJames Hogan 		c->guest.options |= MIPS_CPU_MAAR;
9376ad816e7SJames Hogan 	if (config5_dyn & MIPS_CONF5_MRP)
9386ad816e7SJames Hogan 		c->guest.options_dyn |= MIPS_CPU_MAAR;
9396ad816e7SJames Hogan 
9406ad816e7SJames Hogan 	if (config5 & MIPS_CONF5_LLB)
9416ad816e7SJames Hogan 		c->guest.options |= MIPS_CPU_RW_LLB;
9426ad816e7SJames Hogan 
943a929bdc5SJames Hogan 	if (config5 & MIPS_CONF5_MVH)
944a929bdc5SJames Hogan 		c->guest.options |= MIPS_CPU_MVH;
945a929bdc5SJames Hogan 
9466ad816e7SJames Hogan 	if (config5 & MIPS_CONF_M)
9476ad816e7SJames Hogan 		c->guest.conf |= BIT(6);
9486ad816e7SJames Hogan 	return config5 & MIPS_CONF_M;
9496ad816e7SJames Hogan }
9506ad816e7SJames Hogan 
decode_guest_configs(struct cpuinfo_mips * c)9516ad816e7SJames Hogan static inline void decode_guest_configs(struct cpuinfo_mips *c)
9526ad816e7SJames Hogan {
9536ad816e7SJames Hogan 	unsigned int ok;
9546ad816e7SJames Hogan 
9556ad816e7SJames Hogan 	ok = decode_guest_config0(c);
9566ad816e7SJames Hogan 	if (ok)
9576ad816e7SJames Hogan 		ok = decode_guest_config1(c);
9586ad816e7SJames Hogan 	if (ok)
9596ad816e7SJames Hogan 		ok = decode_guest_config2(c);
9606ad816e7SJames Hogan 	if (ok)
9616ad816e7SJames Hogan 		ok = decode_guest_config3(c);
9626ad816e7SJames Hogan 	if (ok)
9636ad816e7SJames Hogan 		ok = decode_guest_config4(c);
9646ad816e7SJames Hogan 	if (ok)
9656ad816e7SJames Hogan 		decode_guest_config5(c);
9666ad816e7SJames Hogan }
9676ad816e7SJames Hogan 
cpu_probe_guestctl0(struct cpuinfo_mips * c)9686ad816e7SJames Hogan static inline void cpu_probe_guestctl0(struct cpuinfo_mips *c)
9696ad816e7SJames Hogan {
9706ad816e7SJames Hogan 	unsigned int guestctl0, temp;
9716ad816e7SJames Hogan 
9726ad816e7SJames Hogan 	guestctl0 = read_c0_guestctl0();
9736ad816e7SJames Hogan 
9746ad816e7SJames Hogan 	if (guestctl0 & MIPS_GCTL0_G0E)
9756ad816e7SJames Hogan 		c->options |= MIPS_CPU_GUESTCTL0EXT;
9766ad816e7SJames Hogan 	if (guestctl0 & MIPS_GCTL0_G1)
9776ad816e7SJames Hogan 		c->options |= MIPS_CPU_GUESTCTL1;
9786ad816e7SJames Hogan 	if (guestctl0 & MIPS_GCTL0_G2)
9796ad816e7SJames Hogan 		c->options |= MIPS_CPU_GUESTCTL2;
9806ad816e7SJames Hogan 	if (!(guestctl0 & MIPS_GCTL0_RAD)) {
9816ad816e7SJames Hogan 		c->options |= MIPS_CPU_GUESTID;
9826ad816e7SJames Hogan 
9836ad816e7SJames Hogan 		/*
9846ad816e7SJames Hogan 		 * Probe for Direct Root to Guest (DRG). Set GuestCtl1.RID = 0
9856ad816e7SJames Hogan 		 * first, otherwise all data accesses will be fully virtualised
9866ad816e7SJames Hogan 		 * as if they were performed by guest mode.
9876ad816e7SJames Hogan 		 */
9886ad816e7SJames Hogan 		write_c0_guestctl1(0);
9896ad816e7SJames Hogan 		tlbw_use_hazard();
9906ad816e7SJames Hogan 
9916ad816e7SJames Hogan 		write_c0_guestctl0(guestctl0 | MIPS_GCTL0_DRG);
9926ad816e7SJames Hogan 		back_to_back_c0_hazard();
9936ad816e7SJames Hogan 		temp = read_c0_guestctl0();
9946ad816e7SJames Hogan 
9956ad816e7SJames Hogan 		if (temp & MIPS_GCTL0_DRG) {
9966ad816e7SJames Hogan 			write_c0_guestctl0(guestctl0);
9976ad816e7SJames Hogan 			c->options |= MIPS_CPU_DRG;
9986ad816e7SJames Hogan 		}
9996ad816e7SJames Hogan 	}
10006ad816e7SJames Hogan }
10016ad816e7SJames Hogan 
cpu_probe_guestctl1(struct cpuinfo_mips * c)10026ad816e7SJames Hogan static inline void cpu_probe_guestctl1(struct cpuinfo_mips *c)
10036ad816e7SJames Hogan {
10046ad816e7SJames Hogan 	if (cpu_has_guestid) {
10056ad816e7SJames Hogan 		/* determine the number of bits of GuestID available */
10066ad816e7SJames Hogan 		write_c0_guestctl1(MIPS_GCTL1_ID);
10076ad816e7SJames Hogan 		back_to_back_c0_hazard();
10086ad816e7SJames Hogan 		c->guestid_mask = (read_c0_guestctl1() & MIPS_GCTL1_ID)
10096ad816e7SJames Hogan 						>> MIPS_GCTL1_ID_SHIFT;
10106ad816e7SJames Hogan 		write_c0_guestctl1(0);
10116ad816e7SJames Hogan 	}
10126ad816e7SJames Hogan }
10136ad816e7SJames Hogan 
cpu_probe_gtoffset(struct cpuinfo_mips * c)10146ad816e7SJames Hogan static inline void cpu_probe_gtoffset(struct cpuinfo_mips *c)
10156ad816e7SJames Hogan {
10166ad816e7SJames Hogan 	/* determine the number of bits of GTOffset available */
10176ad816e7SJames Hogan 	write_c0_gtoffset(0xffffffff);
10186ad816e7SJames Hogan 	back_to_back_c0_hazard();
10196ad816e7SJames Hogan 	c->gtoffset_mask = read_c0_gtoffset();
10206ad816e7SJames Hogan 	write_c0_gtoffset(0);
10216ad816e7SJames Hogan }
10226ad816e7SJames Hogan 
cpu_probe_vz(struct cpuinfo_mips * c)10236ad816e7SJames Hogan static inline void cpu_probe_vz(struct cpuinfo_mips *c)
10246ad816e7SJames Hogan {
10256ad816e7SJames Hogan 	cpu_probe_guestctl0(c);
10266ad816e7SJames Hogan 	if (cpu_has_guestctl1)
10276ad816e7SJames Hogan 		cpu_probe_guestctl1(c);
10286ad816e7SJames Hogan 
10296ad816e7SJames Hogan 	cpu_probe_gtoffset(c);
10306ad816e7SJames Hogan 
10316ad816e7SJames Hogan 	decode_guest_configs(c);
10326ad816e7SJames Hogan }
10336ad816e7SJames Hogan 
103402cf2119SRalf Baechle #define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \
10351da177e4SLinus Torvalds 		| MIPS_CPU_COUNTER)
10361da177e4SLinus Torvalds 
cpu_probe_legacy(struct cpuinfo_mips * c,unsigned int cpu)1037cea7e2dfSRalf Baechle static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
10381da177e4SLinus Torvalds {
10398ff374b9SMaciej W. Rozycki 	switch (c->processor_id & PRID_IMP_MASK) {
10401da177e4SLinus Torvalds 	case PRID_IMP_R2000:
10411da177e4SLinus Torvalds 		c->cputype = CPU_R2000;
1042cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "R2000";
10439b26616cSMaciej W. Rozycki 		c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
104402cf2119SRalf Baechle 		c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE |
104502cf2119SRalf Baechle 			     MIPS_CPU_NOFPUEX;
10461da177e4SLinus Torvalds 		if (__cpu_has_fpu())
10471da177e4SLinus Torvalds 			c->options |= MIPS_CPU_FPU;
10481da177e4SLinus Torvalds 		c->tlbsize = 64;
10491da177e4SLinus Torvalds 		break;
10501da177e4SLinus Torvalds 	case PRID_IMP_R3000:
10518ff374b9SMaciej W. Rozycki 		if ((c->processor_id & PRID_REV_MASK) == PRID_REV_R3000A) {
1052cea7e2dfSRalf Baechle 			if (cpu_has_confreg()) {
10531da177e4SLinus Torvalds 				c->cputype = CPU_R3081E;
1054cea7e2dfSRalf Baechle 				__cpu_name[cpu] = "R3081";
1055cea7e2dfSRalf Baechle 			} else {
10561da177e4SLinus Torvalds 				c->cputype = CPU_R3000A;
1057cea7e2dfSRalf Baechle 				__cpu_name[cpu] = "R3000A";
1058cea7e2dfSRalf Baechle 			}
1059cea7e2dfSRalf Baechle 		} else {
10601da177e4SLinus Torvalds 			c->cputype = CPU_R3000;
1061cea7e2dfSRalf Baechle 			__cpu_name[cpu] = "R3000";
1062cea7e2dfSRalf Baechle 		}
10639b26616cSMaciej W. Rozycki 		c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
106402cf2119SRalf Baechle 		c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE |
106502cf2119SRalf Baechle 			     MIPS_CPU_NOFPUEX;
10661da177e4SLinus Torvalds 		if (__cpu_has_fpu())
10671da177e4SLinus Torvalds 			c->options |= MIPS_CPU_FPU;
10681da177e4SLinus Torvalds 		c->tlbsize = 64;
10691da177e4SLinus Torvalds 		break;
10701da177e4SLinus Torvalds 	case PRID_IMP_R4000:
10711da177e4SLinus Torvalds 		if (read_c0_config() & CONF_SC) {
10728ff374b9SMaciej W. Rozycki 			if ((c->processor_id & PRID_REV_MASK) >=
10738ff374b9SMaciej W. Rozycki 			    PRID_REV_R4400) {
10741da177e4SLinus Torvalds 				c->cputype = CPU_R4400PC;
1075cea7e2dfSRalf Baechle 				__cpu_name[cpu] = "R4400PC";
10761da177e4SLinus Torvalds 			} else {
1077cea7e2dfSRalf Baechle 				c->cputype = CPU_R4000PC;
1078cea7e2dfSRalf Baechle 				__cpu_name[cpu] = "R4000PC";
1079cea7e2dfSRalf Baechle 			}
1080cea7e2dfSRalf Baechle 		} else {
10817f177a52SMaciej W. Rozycki 			int cca = read_c0_config() & CONF_CM_CMASK;
10827f177a52SMaciej W. Rozycki 			int mc;
10837f177a52SMaciej W. Rozycki 
10847f177a52SMaciej W. Rozycki 			/*
10857f177a52SMaciej W. Rozycki 			 * SC and MC versions can't be reliably told apart,
10867f177a52SMaciej W. Rozycki 			 * but only the latter support coherent caching
10877f177a52SMaciej W. Rozycki 			 * modes so assume the firmware has set the KSEG0
10887f177a52SMaciej W. Rozycki 			 * coherency attribute reasonably (if uncached, we
10897f177a52SMaciej W. Rozycki 			 * assume SC).
10907f177a52SMaciej W. Rozycki 			 */
10917f177a52SMaciej W. Rozycki 			switch (cca) {
10927f177a52SMaciej W. Rozycki 			case CONF_CM_CACHABLE_CE:
10937f177a52SMaciej W. Rozycki 			case CONF_CM_CACHABLE_COW:
10947f177a52SMaciej W. Rozycki 			case CONF_CM_CACHABLE_CUW:
10957f177a52SMaciej W. Rozycki 				mc = 1;
10967f177a52SMaciej W. Rozycki 				break;
10977f177a52SMaciej W. Rozycki 			default:
10987f177a52SMaciej W. Rozycki 				mc = 0;
10997f177a52SMaciej W. Rozycki 				break;
11007f177a52SMaciej W. Rozycki 			}
11018ff374b9SMaciej W. Rozycki 			if ((c->processor_id & PRID_REV_MASK) >=
11028ff374b9SMaciej W. Rozycki 			    PRID_REV_R4400) {
11037f177a52SMaciej W. Rozycki 				c->cputype = mc ? CPU_R4400MC : CPU_R4400SC;
11047f177a52SMaciej W. Rozycki 				__cpu_name[cpu] = mc ? "R4400MC" : "R4400SC";
1105cea7e2dfSRalf Baechle 			} else {
11067f177a52SMaciej W. Rozycki 				c->cputype = mc ? CPU_R4000MC : CPU_R4000SC;
11077f177a52SMaciej W. Rozycki 				__cpu_name[cpu] = mc ? "R4000MC" : "R4000SC";
1108cea7e2dfSRalf Baechle 			}
11091da177e4SLinus Torvalds 		}
11101da177e4SLinus Torvalds 
1111a96102beSSteven J. Hill 		set_isa(c, MIPS_CPU_ISA_III);
11129b26616cSMaciej W. Rozycki 		c->fpu_msk31 |= FPU_CSR_CONDX;
11131da177e4SLinus Torvalds 		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
11141da177e4SLinus Torvalds 			     MIPS_CPU_WATCH | MIPS_CPU_VCE |
11151da177e4SLinus Torvalds 			     MIPS_CPU_LLSC;
11161da177e4SLinus Torvalds 		c->tlbsize = 48;
11171da177e4SLinus Torvalds 		break;
111865ce6197SLauri Kasanen 	case PRID_IMP_R4300:
111965ce6197SLauri Kasanen 		c->cputype = CPU_R4300;
112065ce6197SLauri Kasanen 		__cpu_name[cpu] = "R4300";
112165ce6197SLauri Kasanen 		set_isa(c, MIPS_CPU_ISA_III);
112265ce6197SLauri Kasanen 		c->fpu_msk31 |= FPU_CSR_CONDX;
112365ce6197SLauri Kasanen 		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
112465ce6197SLauri Kasanen 			     MIPS_CPU_LLSC;
112565ce6197SLauri Kasanen 		c->tlbsize = 32;
112665ce6197SLauri Kasanen 		break;
11271da177e4SLinus Torvalds 	case PRID_IMP_R4600:
11281da177e4SLinus Torvalds 		c->cputype = CPU_R4600;
1129cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "R4600";
1130a96102beSSteven J. Hill 		set_isa(c, MIPS_CPU_ISA_III);
11319b26616cSMaciej W. Rozycki 		c->fpu_msk31 |= FPU_CSR_CONDX;
1132075e7502SThiemo Seufer 		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
1133075e7502SThiemo Seufer 			     MIPS_CPU_LLSC;
11341da177e4SLinus Torvalds 		c->tlbsize = 48;
11351da177e4SLinus Torvalds 		break;
11361da177e4SLinus Torvalds 	#if 0
11371da177e4SLinus Torvalds 	case PRID_IMP_R4650:
11381da177e4SLinus Torvalds 		/*
11391da177e4SLinus Torvalds 		 * This processor doesn't have an MMU, so it's not
11401da177e4SLinus Torvalds 		 * "real easy" to run Linux on it. It is left purely
11411da177e4SLinus Torvalds 		 * for documentation.  Commented out because it shares
11421da177e4SLinus Torvalds 		 * it's c0_prid id number with the TX3900.
11431da177e4SLinus Torvalds 		 */
11441da177e4SLinus Torvalds 		c->cputype = CPU_R4650;
1145cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "R4650";
1146a96102beSSteven J. Hill 		set_isa(c, MIPS_CPU_ISA_III);
11479b26616cSMaciej W. Rozycki 		c->fpu_msk31 |= FPU_CSR_CONDX;
11481da177e4SLinus Torvalds 		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC;
11491da177e4SLinus Torvalds 		c->tlbsize = 48;
11501da177e4SLinus Torvalds 		break;
11511da177e4SLinus Torvalds 	#endif
11521da177e4SLinus Torvalds 	case PRID_IMP_R4700:
11531da177e4SLinus Torvalds 		c->cputype = CPU_R4700;
1154cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "R4700";
1155a96102beSSteven J. Hill 		set_isa(c, MIPS_CPU_ISA_III);
11569b26616cSMaciej W. Rozycki 		c->fpu_msk31 |= FPU_CSR_CONDX;
11571da177e4SLinus Torvalds 		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
11581da177e4SLinus Torvalds 			     MIPS_CPU_LLSC;
11591da177e4SLinus Torvalds 		c->tlbsize = 48;
11601da177e4SLinus Torvalds 		break;
11611da177e4SLinus Torvalds 	case PRID_IMP_TX49:
11621da177e4SLinus Torvalds 		c->cputype = CPU_TX49XX;
1163cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "R49XX";
1164a96102beSSteven J. Hill 		set_isa(c, MIPS_CPU_ISA_III);
11659b26616cSMaciej W. Rozycki 		c->fpu_msk31 |= FPU_CSR_CONDX;
11661da177e4SLinus Torvalds 		c->options = R4K_OPTS | MIPS_CPU_LLSC;
11671da177e4SLinus Torvalds 		if (!(c->processor_id & 0x08))
11681da177e4SLinus Torvalds 			c->options |= MIPS_CPU_FPU | MIPS_CPU_32FPR;
11691da177e4SLinus Torvalds 		c->tlbsize = 48;
11701da177e4SLinus Torvalds 		break;
11711da177e4SLinus Torvalds 	case PRID_IMP_R5000:
11721da177e4SLinus Torvalds 		c->cputype = CPU_R5000;
1173cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "R5000";
1174a96102beSSteven J. Hill 		set_isa(c, MIPS_CPU_ISA_IV);
11751da177e4SLinus Torvalds 		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
11761da177e4SLinus Torvalds 			     MIPS_CPU_LLSC;
11771da177e4SLinus Torvalds 		c->tlbsize = 48;
11781da177e4SLinus Torvalds 		break;
11791da177e4SLinus Torvalds 	case PRID_IMP_R5500:
11801da177e4SLinus Torvalds 		c->cputype = CPU_R5500;
1181cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "R5500";
1182a96102beSSteven J. Hill 		set_isa(c, MIPS_CPU_ISA_IV);
11831da177e4SLinus Torvalds 		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
11841da177e4SLinus Torvalds 			     MIPS_CPU_WATCH | MIPS_CPU_LLSC;
11851da177e4SLinus Torvalds 		c->tlbsize = 48;
11861da177e4SLinus Torvalds 		break;
11871da177e4SLinus Torvalds 	case PRID_IMP_NEVADA:
11881da177e4SLinus Torvalds 		c->cputype = CPU_NEVADA;
1189cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "Nevada";
1190a96102beSSteven J. Hill 		set_isa(c, MIPS_CPU_ISA_IV);
11911da177e4SLinus Torvalds 		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
11921da177e4SLinus Torvalds 			     MIPS_CPU_DIVEC | MIPS_CPU_LLSC;
11931da177e4SLinus Torvalds 		c->tlbsize = 48;
11941da177e4SLinus Torvalds 		break;
11951da177e4SLinus Torvalds 	case PRID_IMP_RM7000:
11961da177e4SLinus Torvalds 		c->cputype = CPU_RM7000;
1197cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "RM7000";
1198a96102beSSteven J. Hill 		set_isa(c, MIPS_CPU_ISA_IV);
11991da177e4SLinus Torvalds 		c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
12001da177e4SLinus Torvalds 			     MIPS_CPU_LLSC;
12011da177e4SLinus Torvalds 		/*
12021da177e4SLinus Torvalds 		 * Undocumented RM7000:	 Bit 29 in the info register of
12031da177e4SLinus Torvalds 		 * the RM7000 v2.0 indicates if the TLB has 48 or 64
12041da177e4SLinus Torvalds 		 * entries.
12051da177e4SLinus Torvalds 		 *
12061da177e4SLinus Torvalds 		 * 29	   1 =>	   64 entry JTLB
12071da177e4SLinus Torvalds 		 *	   0 =>	   48 entry JTLB
12081da177e4SLinus Torvalds 		 */
12091da177e4SLinus Torvalds 		c->tlbsize = (read_c0_info() & (1 << 29)) ? 64 : 48;
12101da177e4SLinus Torvalds 		break;
12111da177e4SLinus Torvalds 	case PRID_IMP_R10000:
12121da177e4SLinus Torvalds 		c->cputype = CPU_R10000;
1213cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "R10000";
1214a96102beSSteven J. Hill 		set_isa(c, MIPS_CPU_ISA_IV);
12158b36612aSRalf Baechle 		c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX |
12161da177e4SLinus Torvalds 			     MIPS_CPU_FPU | MIPS_CPU_32FPR |
12171da177e4SLinus Torvalds 			     MIPS_CPU_COUNTER | MIPS_CPU_WATCH |
12181da177e4SLinus Torvalds 			     MIPS_CPU_LLSC;
12191da177e4SLinus Torvalds 		c->tlbsize = 64;
12201da177e4SLinus Torvalds 		break;
12211da177e4SLinus Torvalds 	case PRID_IMP_R12000:
12221da177e4SLinus Torvalds 		c->cputype = CPU_R12000;
1223cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "R12000";
1224a96102beSSteven J. Hill 		set_isa(c, MIPS_CPU_ISA_IV);
12258b36612aSRalf Baechle 		c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX |
12261da177e4SLinus Torvalds 			     MIPS_CPU_FPU | MIPS_CPU_32FPR |
12271da177e4SLinus Torvalds 			     MIPS_CPU_COUNTER | MIPS_CPU_WATCH |
122820cc5b64SThomas Bogendoerfer 			     MIPS_CPU_LLSC;
12291da177e4SLinus Torvalds 		c->tlbsize = 64;
123020cc5b64SThomas Bogendoerfer 		write_c0_r10k_diag(read_c0_r10k_diag() | R10K_DIAG_E_GHIST);
12311da177e4SLinus Torvalds 		break;
123244d921b2SKumba 	case PRID_IMP_R14000:
123330577391SJoshua Kinard 		if (((c->processor_id >> 4) & 0x0f) > 2) {
123430577391SJoshua Kinard 			c->cputype = CPU_R16000;
123530577391SJoshua Kinard 			__cpu_name[cpu] = "R16000";
123630577391SJoshua Kinard 		} else {
123744d921b2SKumba 			c->cputype = CPU_R14000;
1238cea7e2dfSRalf Baechle 			__cpu_name[cpu] = "R14000";
123930577391SJoshua Kinard 		}
1240a96102beSSteven J. Hill 		set_isa(c, MIPS_CPU_ISA_IV);
124144d921b2SKumba 		c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX |
124244d921b2SKumba 			     MIPS_CPU_FPU | MIPS_CPU_32FPR |
124344d921b2SKumba 			     MIPS_CPU_COUNTER | MIPS_CPU_WATCH |
124420cc5b64SThomas Bogendoerfer 			     MIPS_CPU_LLSC;
124544d921b2SKumba 		c->tlbsize = 64;
124620cc5b64SThomas Bogendoerfer 		write_c0_r10k_diag(read_c0_r10k_diag() | R10K_DIAG_E_GHIST);
124744d921b2SKumba 		break;
12487507445bSHuacai Chen 	case PRID_IMP_LOONGSON_64C:  /* Loongson-2/3 */
12495aac1e8aSRobert Millan 		switch (c->processor_id & PRID_REV_MASK) {
12505aac1e8aSRobert Millan 		case PRID_REV_LOONGSON2E:
1251268a2d60SJiaxun Yang 			c->cputype = CPU_LOONGSON2EF;
1252c579d310SHuacai Chen 			__cpu_name[cpu] = "ICT Loongson-2";
12535aac1e8aSRobert Millan 			set_elf_platform(cpu, "loongson2e");
12547352c8b1SHuacai Chen 			set_isa(c, MIPS_CPU_ISA_III);
12559b26616cSMaciej W. Rozycki 			c->fpu_msk31 |= FPU_CSR_CONDX;
12565aac1e8aSRobert Millan 			break;
12575aac1e8aSRobert Millan 		case PRID_REV_LOONGSON2F:
1258268a2d60SJiaxun Yang 			c->cputype = CPU_LOONGSON2EF;
1259c579d310SHuacai Chen 			__cpu_name[cpu] = "ICT Loongson-2";
12605aac1e8aSRobert Millan 			set_elf_platform(cpu, "loongson2f");
12617352c8b1SHuacai Chen 			set_isa(c, MIPS_CPU_ISA_III);
12629b26616cSMaciej W. Rozycki 			c->fpu_msk31 |= FPU_CSR_CONDX;
12635aac1e8aSRobert Millan 			break;
1264b2edcfc8SHuacai Chen 		case PRID_REV_LOONGSON3A_R1:
1265268a2d60SJiaxun Yang 			c->cputype = CPU_LOONGSON64;
1266c579d310SHuacai Chen 			__cpu_name[cpu] = "ICT Loongson-3";
1267c579d310SHuacai Chen 			set_elf_platform(cpu, "loongson3a");
12687352c8b1SHuacai Chen 			set_isa(c, MIPS_CPU_ISA_M64R1);
1269d2f96554SJiaxun Yang 			c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_CAM |
1270d2f96554SJiaxun Yang 				MIPS_ASE_LOONGSON_EXT);
1271c579d310SHuacai Chen 			break;
1272e7841be5SHuacai Chen 		case PRID_REV_LOONGSON3B_R1:
1273e7841be5SHuacai Chen 		case PRID_REV_LOONGSON3B_R2:
1274268a2d60SJiaxun Yang 			c->cputype = CPU_LOONGSON64;
1275e7841be5SHuacai Chen 			__cpu_name[cpu] = "ICT Loongson-3";
1276e7841be5SHuacai Chen 			set_elf_platform(cpu, "loongson3b");
12777352c8b1SHuacai Chen 			set_isa(c, MIPS_CPU_ISA_M64R1);
1278d2f96554SJiaxun Yang 			c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_CAM |
1279d2f96554SJiaxun Yang 				MIPS_ASE_LOONGSON_EXT);
1280e7841be5SHuacai Chen 			break;
12815aac1e8aSRobert Millan 		}
12825aac1e8aSRobert Millan 
12832a21c730SFuxin Zhang 		c->options = R4K_OPTS |
12842a21c730SFuxin Zhang 			     MIPS_CPU_FPU | MIPS_CPU_LLSC |
12852a21c730SFuxin Zhang 			     MIPS_CPU_32FPR;
12862a21c730SFuxin Zhang 		c->tlbsize = 64;
12877507445bSHuacai Chen 		set_cpu_asid_mask(c, MIPS_ENTRYHI_ASID);
1288cc94ea31SHuacai Chen 		c->writecombine = _CACHE_UNCACHED_ACCELERATED;
12892a21c730SFuxin Zhang 		break;
129026859198SHuacai Chen 	case PRID_IMP_LOONGSON_32:  /* Loongson-1 */
12912fa36399SKelvin Cheung 		decode_configs(c);
12921da177e4SLinus Torvalds 
1293b2afb64cSHuacai Chen 		c->cputype = CPU_LOONGSON32;
1294b4672d37SRalf Baechle 
12952fa36399SKelvin Cheung 		switch (c->processor_id & PRID_REV_MASK) {
12962fa36399SKelvin Cheung 		case PRID_REV_LOONGSON1B:
12972fa36399SKelvin Cheung 			__cpu_name[cpu] = "Loongson 1B";
12984194318cSRalf Baechle 			break;
12992fa36399SKelvin Cheung 		}
13002fa36399SKelvin Cheung 
13014194318cSRalf Baechle 		break;
1302b4672d37SRalf Baechle 	}
13031da177e4SLinus Torvalds }
13041da177e4SLinus Torvalds 
cpu_probe_mips(struct cpuinfo_mips * c,unsigned int cpu)1305cea7e2dfSRalf Baechle static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
13061da177e4SLinus Torvalds {
13074f12b91dSMarkos Chandras 	c->writecombine = _CACHE_UNCACHED_ACCELERATED;
13088ff374b9SMaciej W. Rozycki 	switch (c->processor_id & PRID_IMP_MASK) {
1309b2498af5SLeonid Yegoshin 	case PRID_IMP_QEMU_GENERIC:
1310b2498af5SLeonid Yegoshin 		c->writecombine = _CACHE_UNCACHED;
1311b2498af5SLeonid Yegoshin 		c->cputype = CPU_QEMU_GENERIC;
1312b2498af5SLeonid Yegoshin 		__cpu_name[cpu] = "MIPS GENERIC QEMU";
1313b2498af5SLeonid Yegoshin 		break;
13141da177e4SLinus Torvalds 	case PRID_IMP_4KC:
13151da177e4SLinus Torvalds 		c->cputype = CPU_4KC;
13164f12b91dSMarkos Chandras 		c->writecombine = _CACHE_UNCACHED;
1317cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "MIPS 4Kc";
13181da177e4SLinus Torvalds 		break;
13191da177e4SLinus Torvalds 	case PRID_IMP_4KEC:
13202b07bd02SRalf Baechle 	case PRID_IMP_4KECR2:
13212b07bd02SRalf Baechle 		c->cputype = CPU_4KEC;
13224f12b91dSMarkos Chandras 		c->writecombine = _CACHE_UNCACHED;
1323cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "MIPS 4KEc";
13242b07bd02SRalf Baechle 		break;
13251da177e4SLinus Torvalds 	case PRID_IMP_4KSC:
13268afcb5d8SRalf Baechle 	case PRID_IMP_4KSD:
13271da177e4SLinus Torvalds 		c->cputype = CPU_4KSC;
13284f12b91dSMarkos Chandras 		c->writecombine = _CACHE_UNCACHED;
1329cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "MIPS 4KSc";
13301da177e4SLinus Torvalds 		break;
13311da177e4SLinus Torvalds 	case PRID_IMP_5KC:
13321da177e4SLinus Torvalds 		c->cputype = CPU_5KC;
13334f12b91dSMarkos Chandras 		c->writecombine = _CACHE_UNCACHED;
1334cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "MIPS 5Kc";
13351da177e4SLinus Torvalds 		break;
133678d4803fSLeonid Yegoshin 	case PRID_IMP_5KE:
133778d4803fSLeonid Yegoshin 		c->cputype = CPU_5KE;
13384f12b91dSMarkos Chandras 		c->writecombine = _CACHE_UNCACHED;
133978d4803fSLeonid Yegoshin 		__cpu_name[cpu] = "MIPS 5KE";
134078d4803fSLeonid Yegoshin 		break;
13411da177e4SLinus Torvalds 	case PRID_IMP_20KC:
13421da177e4SLinus Torvalds 		c->cputype = CPU_20KC;
13434f12b91dSMarkos Chandras 		c->writecombine = _CACHE_UNCACHED;
1344cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "MIPS 20Kc";
13451da177e4SLinus Torvalds 		break;
13461da177e4SLinus Torvalds 	case PRID_IMP_24K:
13471da177e4SLinus Torvalds 		c->cputype = CPU_24K;
13484f12b91dSMarkos Chandras 		c->writecombine = _CACHE_UNCACHED;
1349cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "MIPS 24Kc";
13501da177e4SLinus Torvalds 		break;
135142f3caefSJohn Crispin 	case PRID_IMP_24KE:
135242f3caefSJohn Crispin 		c->cputype = CPU_24K;
13534f12b91dSMarkos Chandras 		c->writecombine = _CACHE_UNCACHED;
135442f3caefSJohn Crispin 		__cpu_name[cpu] = "MIPS 24KEc";
135542f3caefSJohn Crispin 		break;
13561da177e4SLinus Torvalds 	case PRID_IMP_25KF:
13571da177e4SLinus Torvalds 		c->cputype = CPU_25KF;
13584f12b91dSMarkos Chandras 		c->writecombine = _CACHE_UNCACHED;
1359cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "MIPS 25Kc";
13601da177e4SLinus Torvalds 		break;
1361bbc7f22fSRalf Baechle 	case PRID_IMP_34K:
1362bbc7f22fSRalf Baechle 		c->cputype = CPU_34K;
13634f12b91dSMarkos Chandras 		c->writecombine = _CACHE_UNCACHED;
1364cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "MIPS 34Kc";
13658270ab48SMatt Redfearn 		cpu_set_mt_per_tc_perf(c);
1366bbc7f22fSRalf Baechle 		break;
1367c620953cSChris Dearman 	case PRID_IMP_74K:
1368c620953cSChris Dearman 		c->cputype = CPU_74K;
13694f12b91dSMarkos Chandras 		c->writecombine = _CACHE_UNCACHED;
1370cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "MIPS 74Kc";
1371c620953cSChris Dearman 		break;
1372113c62d9SSteven J. Hill 	case PRID_IMP_M14KC:
1373113c62d9SSteven J. Hill 		c->cputype = CPU_M14KC;
13744f12b91dSMarkos Chandras 		c->writecombine = _CACHE_UNCACHED;
1375113c62d9SSteven J. Hill 		__cpu_name[cpu] = "MIPS M14Kc";
1376113c62d9SSteven J. Hill 		break;
1377f8fa4811SSteven J. Hill 	case PRID_IMP_M14KEC:
1378f8fa4811SSteven J. Hill 		c->cputype = CPU_M14KEC;
13794f12b91dSMarkos Chandras 		c->writecombine = _CACHE_UNCACHED;
1380f8fa4811SSteven J. Hill 		__cpu_name[cpu] = "MIPS M14KEc";
1381f8fa4811SSteven J. Hill 		break;
138239b8d525SRalf Baechle 	case PRID_IMP_1004K:
138339b8d525SRalf Baechle 		c->cputype = CPU_1004K;
13844f12b91dSMarkos Chandras 		c->writecombine = _CACHE_UNCACHED;
1385cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "MIPS 1004Kc";
13868270ab48SMatt Redfearn 		cpu_set_mt_per_tc_perf(c);
138739b8d525SRalf Baechle 		break;
1388006a851bSSteven J. Hill 	case PRID_IMP_1074K:
1389442e14a2SSteven J. Hill 		c->cputype = CPU_1074K;
13904f12b91dSMarkos Chandras 		c->writecombine = _CACHE_UNCACHED;
1391006a851bSSteven J. Hill 		__cpu_name[cpu] = "MIPS 1074Kc";
1392006a851bSSteven J. Hill 		break;
1393b5f065e7SLeonid Yegoshin 	case PRID_IMP_INTERAPTIV_UP:
1394b5f065e7SLeonid Yegoshin 		c->cputype = CPU_INTERAPTIV;
1395b5f065e7SLeonid Yegoshin 		__cpu_name[cpu] = "MIPS interAptiv";
13968270ab48SMatt Redfearn 		cpu_set_mt_per_tc_perf(c);
1397b5f065e7SLeonid Yegoshin 		break;
1398b5f065e7SLeonid Yegoshin 	case PRID_IMP_INTERAPTIV_MP:
1399b5f065e7SLeonid Yegoshin 		c->cputype = CPU_INTERAPTIV;
1400b5f065e7SLeonid Yegoshin 		__cpu_name[cpu] = "MIPS interAptiv (multi)";
14018270ab48SMatt Redfearn 		cpu_set_mt_per_tc_perf(c);
1402b5f065e7SLeonid Yegoshin 		break;
1403b0d4d300SLeonid Yegoshin 	case PRID_IMP_PROAPTIV_UP:
1404b0d4d300SLeonid Yegoshin 		c->cputype = CPU_PROAPTIV;
1405b0d4d300SLeonid Yegoshin 		__cpu_name[cpu] = "MIPS proAptiv";
1406b0d4d300SLeonid Yegoshin 		break;
1407b0d4d300SLeonid Yegoshin 	case PRID_IMP_PROAPTIV_MP:
1408b0d4d300SLeonid Yegoshin 		c->cputype = CPU_PROAPTIV;
1409b0d4d300SLeonid Yegoshin 		__cpu_name[cpu] = "MIPS proAptiv (multi)";
1410b0d4d300SLeonid Yegoshin 		break;
1411829dcc0aSJames Hogan 	case PRID_IMP_P5600:
1412829dcc0aSJames Hogan 		c->cputype = CPU_P5600;
1413829dcc0aSJames Hogan 		__cpu_name[cpu] = "MIPS P5600";
1414829dcc0aSJames Hogan 		break;
1415eba20a3aSPaul Burton 	case PRID_IMP_P6600:
1416eba20a3aSPaul Burton 		c->cputype = CPU_P6600;
1417eba20a3aSPaul Burton 		__cpu_name[cpu] = "MIPS P6600";
1418eba20a3aSPaul Burton 		break;
1419e57f9a2dSMarkos Chandras 	case PRID_IMP_I6400:
1420e57f9a2dSMarkos Chandras 		c->cputype = CPU_I6400;
1421e57f9a2dSMarkos Chandras 		__cpu_name[cpu] = "MIPS I6400";
1422e57f9a2dSMarkos Chandras 		break;
1423859aeb1bSPaul Burton 	case PRID_IMP_I6500:
1424859aeb1bSPaul Burton 		c->cputype = CPU_I6500;
1425859aeb1bSPaul Burton 		__cpu_name[cpu] = "MIPS I6500";
1426859aeb1bSPaul Burton 		break;
14279943ed92SLeonid Yegoshin 	case PRID_IMP_M5150:
14289943ed92SLeonid Yegoshin 		c->cputype = CPU_M5150;
14299943ed92SLeonid Yegoshin 		__cpu_name[cpu] = "MIPS M5150";
14309943ed92SLeonid Yegoshin 		break;
143143aff742SPaul Burton 	case PRID_IMP_M6250:
143243aff742SPaul Burton 		c->cputype = CPU_M6250;
143343aff742SPaul Burton 		__cpu_name[cpu] = "MIPS M6250";
143443aff742SPaul Burton 		break;
14351da177e4SLinus Torvalds 	}
14360b6d497fSChris Dearman 
143775b5b5e0SLeonid Yegoshin 	decode_configs(c);
143875b5b5e0SLeonid Yegoshin 
14390b6d497fSChris Dearman 	spram_config();
1440e7bc8557SPaul Burton 
1441742318adSSerge Semin 	mm_config(c);
1442742318adSSerge Semin 
1443e7bc8557SPaul Burton 	switch (__get_cpu_type(c->cputype)) {
1444ab7c01fdSSerge Semin 	case CPU_M5150:
1445ab7c01fdSSerge Semin 	case CPU_P5600:
1446ab7c01fdSSerge Semin 		set_isa(c, MIPS_CPU_ISA_M32R5);
1447ab7c01fdSSerge Semin 		break;
1448e7bc8557SPaul Burton 	case CPU_I6500:
1449e7bc8557SPaul Burton 		c->options |= MIPS_CPU_SHARED_FTLB_ENTRIES;
1450c9b02990SLiangliang Huang 		fallthrough;
1451e7bc8557SPaul Burton 	case CPU_I6400:
1452e7bc8557SPaul Burton 		c->options |= MIPS_CPU_SHARED_FTLB_RAM;
1453c9b02990SLiangliang Huang 		fallthrough;
1454e7bc8557SPaul Burton 	default:
1455e7bc8557SPaul Burton 		break;
1456e7bc8557SPaul Burton 	}
1457efd1b4adSWANG Xuerui 
1458efd1b4adSWANG Xuerui 	/* Recent MIPS cores use the implementation-dependent ExcCode 16 for
1459efd1b4adSWANG Xuerui 	 * cache/FTLB parity exceptions.
1460efd1b4adSWANG Xuerui 	 */
1461efd1b4adSWANG Xuerui 	switch (__get_cpu_type(c->cputype)) {
1462efd1b4adSWANG Xuerui 	case CPU_PROAPTIV:
1463efd1b4adSWANG Xuerui 	case CPU_P5600:
1464efd1b4adSWANG Xuerui 	case CPU_P6600:
1465efd1b4adSWANG Xuerui 	case CPU_I6400:
1466efd1b4adSWANG Xuerui 	case CPU_I6500:
1467efd1b4adSWANG Xuerui 		c->options |= MIPS_CPU_FTLBPAREX;
1468efd1b4adSWANG Xuerui 		break;
1469efd1b4adSWANG Xuerui 	}
14701da177e4SLinus Torvalds }
14711da177e4SLinus Torvalds 
cpu_probe_alchemy(struct cpuinfo_mips * c,unsigned int cpu)1472cea7e2dfSRalf Baechle static inline void cpu_probe_alchemy(struct cpuinfo_mips *c, unsigned int cpu)
14731da177e4SLinus Torvalds {
14744194318cSRalf Baechle 	decode_configs(c);
14758ff374b9SMaciej W. Rozycki 	switch (c->processor_id & PRID_IMP_MASK) {
14761da177e4SLinus Torvalds 	case PRID_IMP_AU1_REV1:
14771da177e4SLinus Torvalds 	case PRID_IMP_AU1_REV2:
1478270717a8SManuel Lauss 		c->cputype = CPU_ALCHEMY;
14791da177e4SLinus Torvalds 		switch ((c->processor_id >> 24) & 0xff) {
14801da177e4SLinus Torvalds 		case 0:
1481cea7e2dfSRalf Baechle 			__cpu_name[cpu] = "Au1000";
14821da177e4SLinus Torvalds 			break;
14831da177e4SLinus Torvalds 		case 1:
1484cea7e2dfSRalf Baechle 			__cpu_name[cpu] = "Au1500";
14851da177e4SLinus Torvalds 			break;
14861da177e4SLinus Torvalds 		case 2:
1487cea7e2dfSRalf Baechle 			__cpu_name[cpu] = "Au1100";
14881da177e4SLinus Torvalds 			break;
14891da177e4SLinus Torvalds 		case 3:
1490cea7e2dfSRalf Baechle 			__cpu_name[cpu] = "Au1550";
14911da177e4SLinus Torvalds 			break;
1492e3ad1c23SPete Popov 		case 4:
1493cea7e2dfSRalf Baechle 			__cpu_name[cpu] = "Au1200";
14948ff374b9SMaciej W. Rozycki 			if ((c->processor_id & PRID_REV_MASK) == 2)
1495cea7e2dfSRalf Baechle 				__cpu_name[cpu] = "Au1250";
1496237cfee1SManuel Lauss 			break;
1497237cfee1SManuel Lauss 		case 5:
1498cea7e2dfSRalf Baechle 			__cpu_name[cpu] = "Au1210";
1499e3ad1c23SPete Popov 			break;
15001da177e4SLinus Torvalds 		default:
1501270717a8SManuel Lauss 			__cpu_name[cpu] = "Au1xxx";
15021da177e4SLinus Torvalds 			break;
15031da177e4SLinus Torvalds 		}
15041da177e4SLinus Torvalds 		break;
1505f2041708SManuel Lauss 	case PRID_IMP_NETLOGIC_AU13XX:
1506f2041708SManuel Lauss 		c->cputype = CPU_ALCHEMY;
1507f2041708SManuel Lauss 		__cpu_name[cpu] = "Au1300";
1508f2041708SManuel Lauss 		break;
15091da177e4SLinus Torvalds 	}
15101da177e4SLinus Torvalds }
15111da177e4SLinus Torvalds 
cpu_probe_sibyte(struct cpuinfo_mips * c,unsigned int cpu)1512cea7e2dfSRalf Baechle static inline void cpu_probe_sibyte(struct cpuinfo_mips *c, unsigned int cpu)
15131da177e4SLinus Torvalds {
15144194318cSRalf Baechle 	decode_configs(c);
151502cf2119SRalf Baechle 
15164f12b91dSMarkos Chandras 	c->writecombine = _CACHE_UNCACHED_ACCELERATED;
15178ff374b9SMaciej W. Rozycki 	switch (c->processor_id & PRID_IMP_MASK) {
15181da177e4SLinus Torvalds 	case PRID_IMP_SB1:
15191da177e4SLinus Torvalds 		c->cputype = CPU_SB1;
1520cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "SiByte SB1";
15211da177e4SLinus Torvalds 		/* FPU in pass1 is known to have issues. */
15228ff374b9SMaciej W. Rozycki 		if ((c->processor_id & PRID_REV_MASK) < 0x02)
15234194318cSRalf Baechle 			c->options &= ~(MIPS_CPU_FPU | MIPS_CPU_32FPR);
15241da177e4SLinus Torvalds 		break;
152593ce2f52SAndrew Isaacson 	case PRID_IMP_SB1A:
152693ce2f52SAndrew Isaacson 		c->cputype = CPU_SB1A;
1527cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "SiByte SB1A";
152893ce2f52SAndrew Isaacson 		break;
15291da177e4SLinus Torvalds 	}
15301da177e4SLinus Torvalds }
15311da177e4SLinus Torvalds 
cpu_probe_sandcraft(struct cpuinfo_mips * c,unsigned int cpu)1532cea7e2dfSRalf Baechle static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c, unsigned int cpu)
15331da177e4SLinus Torvalds {
15344194318cSRalf Baechle 	decode_configs(c);
15358ff374b9SMaciej W. Rozycki 	switch (c->processor_id & PRID_IMP_MASK) {
15361da177e4SLinus Torvalds 	case PRID_IMP_SR71000:
15371da177e4SLinus Torvalds 		c->cputype = CPU_SR71000;
1538cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "Sandcraft SR71000";
15391da177e4SLinus Torvalds 		c->scache.ways = 8;
15401da177e4SLinus Torvalds 		c->tlbsize = 64;
15411da177e4SLinus Torvalds 		break;
15421da177e4SLinus Torvalds 	}
15431da177e4SLinus Torvalds }
15441da177e4SLinus Torvalds 
cpu_probe_nxp(struct cpuinfo_mips * c,unsigned int cpu)1545cea7e2dfSRalf Baechle static inline void cpu_probe_nxp(struct cpuinfo_mips *c, unsigned int cpu)
1546bdf21b18SPete Popov {
1547bdf21b18SPete Popov 	decode_configs(c);
15488ff374b9SMaciej W. Rozycki 	switch (c->processor_id & PRID_IMP_MASK) {
1549bdf21b18SPete Popov 	case PRID_IMP_PR4450:
1550bdf21b18SPete Popov 		c->cputype = CPU_PR4450;
1551cea7e2dfSRalf Baechle 		__cpu_name[cpu] = "Philips PR4450";
1552a96102beSSteven J. Hill 		set_isa(c, MIPS_CPU_ISA_M32R1);
1553bdf21b18SPete Popov 		break;
1554bdf21b18SPete Popov 	}
1555bdf21b18SPete Popov }
1556bdf21b18SPete Popov 
cpu_probe_broadcom(struct cpuinfo_mips * c,unsigned int cpu)1557cea7e2dfSRalf Baechle static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
15581c0c13ebSAurelien Jarno {
15591c0c13ebSAurelien Jarno 	decode_configs(c);
15608ff374b9SMaciej W. Rozycki 	switch (c->processor_id & PRID_IMP_MASK) {
1561190fca3eSKevin Cernekee 	case PRID_IMP_BMIPS32_REV4:
1562190fca3eSKevin Cernekee 	case PRID_IMP_BMIPS32_REV8:
1563602977b0SKevin Cernekee 		c->cputype = CPU_BMIPS32;
1564602977b0SKevin Cernekee 		__cpu_name[cpu] = "Broadcom BMIPS32";
156506785df0SKevin Cernekee 		set_elf_platform(cpu, "bmips32");
15661c0c13ebSAurelien Jarno 		break;
1567602977b0SKevin Cernekee 	case PRID_IMP_BMIPS3300:
1568602977b0SKevin Cernekee 	case PRID_IMP_BMIPS3300_ALT:
1569602977b0SKevin Cernekee 	case PRID_IMP_BMIPS3300_BUG:
1570602977b0SKevin Cernekee 		c->cputype = CPU_BMIPS3300;
1571602977b0SKevin Cernekee 		__cpu_name[cpu] = "Broadcom BMIPS3300";
157206785df0SKevin Cernekee 		set_elf_platform(cpu, "bmips3300");
1573bd67b711SThomas Bogendoerfer 		reserve_exception_space(0x400, VECTORSPACING * 64);
15741c0c13ebSAurelien Jarno 		break;
1575602977b0SKevin Cernekee 	case PRID_IMP_BMIPS43XX: {
15768ff374b9SMaciej W. Rozycki 		int rev = c->processor_id & PRID_REV_MASK;
1577602977b0SKevin Cernekee 
1578602977b0SKevin Cernekee 		if (rev >= PRID_REV_BMIPS4380_LO &&
1579602977b0SKevin Cernekee 				rev <= PRID_REV_BMIPS4380_HI) {
1580602977b0SKevin Cernekee 			c->cputype = CPU_BMIPS4380;
1581602977b0SKevin Cernekee 			__cpu_name[cpu] = "Broadcom BMIPS4380";
158206785df0SKevin Cernekee 			set_elf_platform(cpu, "bmips4380");
1583b4720809SFlorian Fainelli 			c->options |= MIPS_CPU_RIXI;
1584bd67b711SThomas Bogendoerfer 			reserve_exception_space(0x400, VECTORSPACING * 64);
1585602977b0SKevin Cernekee 		} else {
1586602977b0SKevin Cernekee 			c->cputype = CPU_BMIPS4350;
1587602977b0SKevin Cernekee 			__cpu_name[cpu] = "Broadcom BMIPS4350";
158806785df0SKevin Cernekee 			set_elf_platform(cpu, "bmips4350");
1589602977b0SKevin Cernekee 		}
15900de663efSMaxime Bizon 		break;
15910de663efSMaxime Bizon 	}
1592602977b0SKevin Cernekee 	case PRID_IMP_BMIPS5000:
159368e6a783SKevin Cernekee 	case PRID_IMP_BMIPS5200:
1594602977b0SKevin Cernekee 		c->cputype = CPU_BMIPS5000;
159537808d62SFlorian Fainelli 		if ((c->processor_id & PRID_IMP_MASK) == PRID_IMP_BMIPS5200)
159637808d62SFlorian Fainelli 			__cpu_name[cpu] = "Broadcom BMIPS5200";
159737808d62SFlorian Fainelli 		else
1598602977b0SKevin Cernekee 			__cpu_name[cpu] = "Broadcom BMIPS5000";
159906785df0SKevin Cernekee 		set_elf_platform(cpu, "bmips5000");
1600b4720809SFlorian Fainelli 		c->options |= MIPS_CPU_ULRI | MIPS_CPU_RIXI;
1601bd67b711SThomas Bogendoerfer 		reserve_exception_space(0x1000, VECTORSPACING * 64);
1602602977b0SKevin Cernekee 		break;
16031c0c13ebSAurelien Jarno 	}
16041c0c13ebSAurelien Jarno }
16051c0c13ebSAurelien Jarno 
cpu_probe_cavium(struct cpuinfo_mips * c,unsigned int cpu)16060dd4781bSDavid Daney static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu)
16070dd4781bSDavid Daney {
16080dd4781bSDavid Daney 	decode_configs(c);
1609918d7795SJiaxun Yang 	/* Octeon has different cache interface */
1610918d7795SJiaxun Yang 	c->options &= ~MIPS_CPU_4K_CACHE;
16118ff374b9SMaciej W. Rozycki 	switch (c->processor_id & PRID_IMP_MASK) {
16120dd4781bSDavid Daney 	case PRID_IMP_CAVIUM_CN38XX:
16130dd4781bSDavid Daney 	case PRID_IMP_CAVIUM_CN31XX:
16140dd4781bSDavid Daney 	case PRID_IMP_CAVIUM_CN30XX:
16156f329468SDavid Daney 		c->cputype = CPU_CAVIUM_OCTEON;
16166f329468SDavid Daney 		__cpu_name[cpu] = "Cavium Octeon";
16176f329468SDavid Daney 		goto platform;
16180dd4781bSDavid Daney 	case PRID_IMP_CAVIUM_CN58XX:
16190dd4781bSDavid Daney 	case PRID_IMP_CAVIUM_CN56XX:
16200dd4781bSDavid Daney 	case PRID_IMP_CAVIUM_CN50XX:
16210dd4781bSDavid Daney 	case PRID_IMP_CAVIUM_CN52XX:
16226f329468SDavid Daney 		c->cputype = CPU_CAVIUM_OCTEON_PLUS;
16236f329468SDavid Daney 		__cpu_name[cpu] = "Cavium Octeon+";
16246f329468SDavid Daney platform:
1625c094c99eSRobert Millan 		set_elf_platform(cpu, "octeon");
16260dd4781bSDavid Daney 		break;
1627a1431b61SDavid Daney 	case PRID_IMP_CAVIUM_CN61XX:
16280e56b385SDavid Daney 	case PRID_IMP_CAVIUM_CN63XX:
1629a1431b61SDavid Daney 	case PRID_IMP_CAVIUM_CN66XX:
1630a1431b61SDavid Daney 	case PRID_IMP_CAVIUM_CN68XX:
1631af04bb85SDavid Daney 	case PRID_IMP_CAVIUM_CNF71XX:
16320e56b385SDavid Daney 		c->cputype = CPU_CAVIUM_OCTEON2;
16330e56b385SDavid Daney 		__cpu_name[cpu] = "Cavium Octeon II";
1634c094c99eSRobert Millan 		set_elf_platform(cpu, "octeon2");
16350e56b385SDavid Daney 		break;
1636af04bb85SDavid Daney 	case PRID_IMP_CAVIUM_CN70XX:
1637b8c8f665SDavid Daney 	case PRID_IMP_CAVIUM_CN73XX:
1638b8c8f665SDavid Daney 	case PRID_IMP_CAVIUM_CNF75XX:
1639af04bb85SDavid Daney 	case PRID_IMP_CAVIUM_CN78XX:
1640af04bb85SDavid Daney 		c->cputype = CPU_CAVIUM_OCTEON3;
1641af04bb85SDavid Daney 		__cpu_name[cpu] = "Cavium Octeon III";
1642af04bb85SDavid Daney 		set_elf_platform(cpu, "octeon3");
1643af04bb85SDavid Daney 		break;
16440dd4781bSDavid Daney 	default:
16450dd4781bSDavid Daney 		printk(KERN_INFO "Unknown Octeon chip!\n");
16460dd4781bSDavid Daney 		c->cputype = CPU_UNKNOWN;
16470dd4781bSDavid Daney 		break;
16480dd4781bSDavid Daney 	}
16490dd4781bSDavid Daney }
16500dd4781bSDavid Daney 
1651da1bd297SJiaxun Yang #ifdef CONFIG_CPU_LOONGSON64
1652da1bd297SJiaxun Yang #include <loongson_regs.h>
1653da1bd297SJiaxun Yang 
decode_cpucfg(struct cpuinfo_mips * c)1654da1bd297SJiaxun Yang static inline void decode_cpucfg(struct cpuinfo_mips *c)
1655da1bd297SJiaxun Yang {
1656da1bd297SJiaxun Yang 	u32 cfg1 = read_cpucfg(LOONGSON_CFG1);
1657da1bd297SJiaxun Yang 	u32 cfg2 = read_cpucfg(LOONGSON_CFG2);
1658da1bd297SJiaxun Yang 	u32 cfg3 = read_cpucfg(LOONGSON_CFG3);
1659da1bd297SJiaxun Yang 
1660da1bd297SJiaxun Yang 	if (cfg1 & LOONGSON_CFG1_MMI)
1661da1bd297SJiaxun Yang 		c->ases |= MIPS_ASE_LOONGSON_MMI;
1662da1bd297SJiaxun Yang 
1663da1bd297SJiaxun Yang 	if (cfg2 & LOONGSON_CFG2_LEXT1)
1664da1bd297SJiaxun Yang 		c->ases |= MIPS_ASE_LOONGSON_EXT;
1665da1bd297SJiaxun Yang 
1666da1bd297SJiaxun Yang 	if (cfg2 & LOONGSON_CFG2_LEXT2)
1667da1bd297SJiaxun Yang 		c->ases |= MIPS_ASE_LOONGSON_EXT2;
1668da1bd297SJiaxun Yang 
16693210e2c2SHuacai Chen 	if (cfg2 & LOONGSON_CFG2_LSPW) {
1670da1bd297SJiaxun Yang 		c->options |= MIPS_CPU_LDPTE;
16713210e2c2SHuacai Chen 		c->guest.options |= MIPS_CPU_LDPTE;
16723210e2c2SHuacai Chen 	}
1673da1bd297SJiaxun Yang 
1674da1bd297SJiaxun Yang 	if (cfg3 & LOONGSON_CFG3_LCAMP)
1675da1bd297SJiaxun Yang 		c->ases |= MIPS_ASE_LOONGSON_CAM;
1676da1bd297SJiaxun Yang }
1677da1bd297SJiaxun Yang 
cpu_probe_loongson(struct cpuinfo_mips * c,unsigned int cpu)1678b2edcfc8SHuacai Chen static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu)
1679b2edcfc8SHuacai Chen {
168065fee014SHuacai Chen 	c->cputype = CPU_LOONGSON64;
168165fee014SHuacai Chen 
1682bc6e8dc1SWANG Xuerui 	/* All Loongson processors covered here define ExcCode 16 as GSExc. */
168365fee014SHuacai Chen 	decode_configs(c);
1684bc6e8dc1SWANG Xuerui 	c->options |= MIPS_CPU_GSEXCEX;
1685bc6e8dc1SWANG Xuerui 
1686b2edcfc8SHuacai Chen 	switch (c->processor_id & PRID_IMP_MASK) {
16870cf2ea11SJiaxun Yang 	case PRID_IMP_LOONGSON_64R: /* Loongson-64 Reduced */
16880cf2ea11SJiaxun Yang 		switch (c->processor_id & PRID_REV_MASK) {
16890cf2ea11SJiaxun Yang 		case PRID_REV_LOONGSON2K_R1_0:
16900cf2ea11SJiaxun Yang 		case PRID_REV_LOONGSON2K_R1_1:
16910cf2ea11SJiaxun Yang 		case PRID_REV_LOONGSON2K_R1_2:
16920cf2ea11SJiaxun Yang 		case PRID_REV_LOONGSON2K_R1_3:
16930cf2ea11SJiaxun Yang 			__cpu_name[cpu] = "Loongson-2K";
16940cf2ea11SJiaxun Yang 			set_elf_platform(cpu, "gs264e");
16950cf2ea11SJiaxun Yang 			set_isa(c, MIPS_CPU_ISA_M64R2);
16960cf2ea11SJiaxun Yang 			break;
16970cf2ea11SJiaxun Yang 		}
16980cf2ea11SJiaxun Yang 		c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_EXT |
16990cf2ea11SJiaxun Yang 				MIPS_ASE_LOONGSON_EXT2);
17000cf2ea11SJiaxun Yang 		break;
17010cf2ea11SJiaxun Yang 	case PRID_IMP_LOONGSON_64C:  /* Loongson-3 Classic */
1702b2edcfc8SHuacai Chen 		switch (c->processor_id & PRID_REV_MASK) {
1703f3ade253SHuacai Chen 		case PRID_REV_LOONGSON3A_R2_0:
1704f3ade253SHuacai Chen 		case PRID_REV_LOONGSON3A_R2_1:
1705b2edcfc8SHuacai Chen 			__cpu_name[cpu] = "ICT Loongson-3";
1706b2edcfc8SHuacai Chen 			set_elf_platform(cpu, "loongson3a");
1707b2edcfc8SHuacai Chen 			set_isa(c, MIPS_CPU_ISA_M64R2);
1708b2edcfc8SHuacai Chen 			break;
17097cff3f16SHuacai Chen 		case PRID_REV_LOONGSON3A_R3_0:
17107cff3f16SHuacai Chen 		case PRID_REV_LOONGSON3A_R3_1:
17110a00024dSHuacai Chen 			__cpu_name[cpu] = "ICT Loongson-3";
17120a00024dSHuacai Chen 			set_elf_platform(cpu, "loongson3a");
17130a00024dSHuacai Chen 			set_isa(c, MIPS_CPU_ISA_M64R2);
17140a00024dSHuacai Chen 			break;
1715b2edcfc8SHuacai Chen 		}
1716da1bd297SJiaxun Yang 		/*
1717da1bd297SJiaxun Yang 		 * Loongson-3 Classic did not implement MIPS standard TLBINV
1718da1bd297SJiaxun Yang 		 * but implemented TLBINVF and EHINV. As currently we're only
1719da1bd297SJiaxun Yang 		 * using these two features, enable MIPS_CPU_TLBINV as well.
17203aed240eSJiaxun Yang 		 *
17213aed240eSJiaxun Yang 		 * Also some early Loongson-3A2000 had wrong TLB type in Config
17223aed240eSJiaxun Yang 		 * register, we correct it here.
1723da1bd297SJiaxun Yang 		 */
17243aed240eSJiaxun Yang 		c->options |= MIPS_CPU_FTLB | MIPS_CPU_TLBINV | MIPS_CPU_LDPTE;
1725d2f96554SJiaxun Yang 		c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_CAM |
1726d2f96554SJiaxun Yang 			MIPS_ASE_LOONGSON_EXT | MIPS_ASE_LOONGSON_EXT2);
17270f78355cSHuacai Chen 		c->ases &= ~MIPS_ASE_VZ; /* VZ of Loongson-3A2000/3000 is incomplete */
1728*ac5d3bafSJiaxun Yang 		change_c0_config6(LOONGSON_CONF6_EXTIMER | LOONGSON_CONF6_INTIMER,
1729*ac5d3bafSJiaxun Yang 				  LOONGSON_CONF6_INTIMER);
1730b2edcfc8SHuacai Chen 		break;
17317507445bSHuacai Chen 	case PRID_IMP_LOONGSON_64G:
17327507445bSHuacai Chen 		__cpu_name[cpu] = "ICT Loongson-3";
17337507445bSHuacai Chen 		set_elf_platform(cpu, "loongson3a");
17347507445bSHuacai Chen 		set_isa(c, MIPS_CPU_ISA_M64R2);
1735da1bd297SJiaxun Yang 		decode_cpucfg(c);
1736*ac5d3bafSJiaxun Yang 		change_c0_config6(LOONGSON_CONF6_EXTIMER | LOONGSON_CONF6_INTIMER,
1737*ac5d3bafSJiaxun Yang 				  LOONGSON_CONF6_INTIMER);
17387507445bSHuacai Chen 		break;
1739b2edcfc8SHuacai Chen 	default:
1740b2edcfc8SHuacai Chen 		panic("Unknown Loongson Processor ID!");
1741b2edcfc8SHuacai Chen 		break;
1742b2edcfc8SHuacai Chen 	}
1743b2edcfc8SHuacai Chen }
1744da1bd297SJiaxun Yang #else
cpu_probe_loongson(struct cpuinfo_mips * c,unsigned int cpu)1745da1bd297SJiaxun Yang static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu) { }
1746da1bd297SJiaxun Yang #endif
1747b2edcfc8SHuacai Chen 
cpu_probe_ingenic(struct cpuinfo_mips * c,unsigned int cpu)174883ccf69dSLars-Peter Clausen static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
174983ccf69dSLars-Peter Clausen {
175083ccf69dSLars-Peter Clausen 	decode_configs(c);
1751368fb26cSPaul Cercueil 
1752368fb26cSPaul Cercueil 	/*
1753368fb26cSPaul Cercueil 	 * XBurst misses a config2 register, so config3 decode was skipped in
1754368fb26cSPaul Cercueil 	 * decode_configs().
1755368fb26cSPaul Cercueil 	 */
1756368fb26cSPaul Cercueil 	decode_config3(c);
1757368fb26cSPaul Cercueil 
17583b25b763SPaul Cercueil 	/* XBurst does not implement the CP0 counter. */
175983ccf69dSLars-Peter Clausen 	c->options &= ~MIPS_CPU_COUNTER;
17605f5ed0ebSPaul Cercueil 	BUG_ON(__builtin_constant_p(cpu_has_counter) && cpu_has_counter);
1761368fb26cSPaul Cercueil 
17625ef41510SPaul Cercueil 	/* XBurst has virtually tagged icache */
17635ef41510SPaul Cercueil 	c->icache.flags |= MIPS_CACHE_VTAG;
17645ef41510SPaul Cercueil 
17658ff374b9SMaciej W. Rozycki 	switch (c->processor_id & PRID_IMP_MASK) {
17660d10d17bS周琰杰 (Zhou Yanjie) 
17670d10d17bS周琰杰 (Zhou Yanjie) 	/* XBurst®1 with MXU1.0/MXU1.1 SIMD ISA */
1768b9bb868eS周琰杰 (Zhou Yanjie) 	case PRID_IMP_XBURST_REV1:
1769b9bb868eS周琰杰 (Zhou Yanjie) 
1770053951ddSZhou Yanjie 		/*
1771053951ddSZhou Yanjie 		 * The XBurst core by default attempts to avoid branch target
1772053951ddSZhou Yanjie 		 * buffer lookups by detecting & special casing loops. This
1773053951ddSZhou Yanjie 		 * feature will cause BogoMIPS and lpj calculate in error.
1774053951ddSZhou Yanjie 		 * Set cp0 config7 bit 4 to disable this feature.
1775053951ddSZhou Yanjie 		 */
1776053951ddSZhou Yanjie 		set_c0_config7(MIPS_CONF7_BTB_LOOP_EN);
17778041edb5SPaul Cercueil 
1778b02efeb0SZhou Yanjie 		switch (c->processor_id & PRID_COMP_MASK) {
1779b9bb868eS周琰杰 (Zhou Yanjie) 
1780b9bb868eS周琰杰 (Zhou Yanjie) 		/*
1781b9bb868eS周琰杰 (Zhou Yanjie) 		 * The config0 register in the XBurst CPUs with a processor ID of
1782b9bb868eS周琰杰 (Zhou Yanjie) 		 * PRID_COMP_INGENIC_D0 report themselves as MIPS32r2 compatible,
1783b9bb868eS周琰杰 (Zhou Yanjie) 		 * but they don't actually support this ISA.
1784b9bb868eS周琰杰 (Zhou Yanjie) 		 */
1785b9bb868eS周琰杰 (Zhou Yanjie) 		case PRID_COMP_INGENIC_D0:
1786b9bb868eS周琰杰 (Zhou Yanjie) 			c->isa_level &= ~MIPS_CPU_ISA_M32R2;
1787fc52f92aSPaul Cercueil 
1788fc52f92aSPaul Cercueil 			/* FPU is not properly detected on JZ4760(B). */
1789fc52f92aSPaul Cercueil 			if (c->processor_id == 0x2ed0024f)
1790fc52f92aSPaul Cercueil 				c->options |= MIPS_CPU_FPU;
1791fc52f92aSPaul Cercueil 
1792a5360958SPaul Cercueil 			fallthrough;
1793b9bb868eS周琰杰 (Zhou Yanjie) 
17948041edb5SPaul Cercueil 		/*
1795b02efeb0SZhou Yanjie 		 * The config0 register in the XBurst CPUs with a processor ID of
1796a5360958SPaul Cercueil 		 * PRID_COMP_INGENIC_D0 or PRID_COMP_INGENIC_D1 has an abandoned
1797a5360958SPaul Cercueil 		 * huge page tlb mode, this mode is not compatible with the MIPS
1798a5360958SPaul Cercueil 		 * standard, it will cause tlbmiss and into an infinite loop
1799a5360958SPaul Cercueil 		 * (line 21 in the tlb-funcs.S) when starting the init process.
1800a5360958SPaul Cercueil 		 * After chip reset, the default is HPTLB mode, Write 0xa9000000
1801a5360958SPaul Cercueil 		 * to cp0 register 5 sel 4 to switch back to VTLB mode to prevent
1802a5360958SPaul Cercueil 		 * getting stuck.
1803b02efeb0SZhou Yanjie 		 */
1804b02efeb0SZhou Yanjie 		case PRID_COMP_INGENIC_D1:
1805b02efeb0SZhou Yanjie 			write_c0_page_ctrl(XBURST_PAGECTRL_HPTLB_DIS);
1806b02efeb0SZhou Yanjie 			break;
1807b9bb868eS周琰杰 (Zhou Yanjie) 
1808b02efeb0SZhou Yanjie 		default:
1809b02efeb0SZhou Yanjie 			break;
1810b02efeb0SZhou Yanjie 		}
1811c9b02990SLiangliang Huang 		fallthrough;
18120d10d17bS周琰杰 (Zhou Yanjie) 
18130d10d17bS周琰杰 (Zhou Yanjie) 	/* XBurst®1 with MXU2.0 SIMD ISA */
1814b9bb868eS周琰杰 (Zhou Yanjie) 	case PRID_IMP_XBURST_REV2:
181595b1f6dbSPaul Cercueil 		/* Ingenic uses the WA bit to achieve write-combine memory writes */
181695b1f6dbSPaul Cercueil 		c->writecombine = _CACHE_CACHABLE_WA;
1817b9bb868eS周琰杰 (Zhou Yanjie) 		c->cputype = CPU_XBURST;
1818b9bb868eS周琰杰 (Zhou Yanjie) 		__cpu_name[cpu] = "Ingenic XBurst";
1819b9bb868eS周琰杰 (Zhou Yanjie) 		break;
1820b9bb868eS周琰杰 (Zhou Yanjie) 
18210d10d17bS周琰杰 (Zhou Yanjie) 	/* XBurst®2 with MXU2.1 SIMD ISA */
18220d10d17bS周琰杰 (Zhou Yanjie) 	case PRID_IMP_XBURST2:
18230d10d17bS周琰杰 (Zhou Yanjie) 		c->cputype = CPU_XBURST;
18240d10d17bS周琰杰 (Zhou Yanjie) 		__cpu_name[cpu] = "Ingenic XBurst II";
18250d10d17bS周琰杰 (Zhou Yanjie) 		break;
18260d10d17bS周琰杰 (Zhou Yanjie) 
1827b9bb868eS周琰杰 (Zhou Yanjie) 	default:
1828b9bb868eS周琰杰 (Zhou Yanjie) 		panic("Unknown Ingenic Processor ID!");
1829b9bb868eS周琰杰 (Zhou Yanjie) 		break;
1830b9bb868eS周琰杰 (Zhou Yanjie) 	}
183183ccf69dSLars-Peter Clausen }
183283ccf69dSLars-Peter Clausen 
1833949e51beSDavid Daney #ifdef CONFIG_64BIT
1834949e51beSDavid Daney /* For use by uaccess.h */
1835949e51beSDavid Daney u64 __ua_limit;
1836949e51beSDavid Daney EXPORT_SYMBOL(__ua_limit);
1837949e51beSDavid Daney #endif
1838949e51beSDavid Daney 
18399966db25SRalf Baechle const char *__cpu_name[NR_CPUS];
1840874fd3b5SDavid Daney const char *__elf_platform;
1841e585b768SYunQiang Su const char *__elf_base_platform;
18429966db25SRalf Baechle 
cpu_probe(void)1843078a55fcSPaul Gortmaker void cpu_probe(void)
18441da177e4SLinus Torvalds {
18451da177e4SLinus Torvalds 	struct cpuinfo_mips *c = &current_cpu_data;
18469966db25SRalf Baechle 	unsigned int cpu = smp_processor_id();
18471da177e4SLinus Torvalds 
184805510f2bSMarcin Nowakowski 	/*
184905510f2bSMarcin Nowakowski 	 * Set a default elf platform, cpu probe may later
185005510f2bSMarcin Nowakowski 	 * overwrite it with a more precise value
185105510f2bSMarcin Nowakowski 	 */
185205510f2bSMarcin Nowakowski 	set_elf_platform(cpu, "mips");
185305510f2bSMarcin Nowakowski 
18541da177e4SLinus Torvalds 	c->processor_id = PRID_IMP_UNKNOWN;
18551da177e4SLinus Torvalds 	c->fpu_id	= FPIR_IMP_NONE;
18561da177e4SLinus Torvalds 	c->cputype	= CPU_UNKNOWN;
18574f12b91dSMarkos Chandras 	c->writecombine = _CACHE_UNCACHED;
18581da177e4SLinus Torvalds 
18599b26616cSMaciej W. Rozycki 	c->fpu_csr31	= FPU_CSR_RN;
18609b26616cSMaciej W. Rozycki 	c->fpu_msk31	= FPU_CSR_RSVD | FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
18619b26616cSMaciej W. Rozycki 
18621da177e4SLinus Torvalds 	c->processor_id = read_c0_prid();
18638ff374b9SMaciej W. Rozycki 	switch (c->processor_id & PRID_COMP_MASK) {
18641da177e4SLinus Torvalds 	case PRID_COMP_LEGACY:
1865cea7e2dfSRalf Baechle 		cpu_probe_legacy(c, cpu);
18661da177e4SLinus Torvalds 		break;
18671da177e4SLinus Torvalds 	case PRID_COMP_MIPS:
1868cea7e2dfSRalf Baechle 		cpu_probe_mips(c, cpu);
18691da177e4SLinus Torvalds 		break;
18701da177e4SLinus Torvalds 	case PRID_COMP_ALCHEMY:
1871f2041708SManuel Lauss 	case PRID_COMP_NETLOGIC:
1872cea7e2dfSRalf Baechle 		cpu_probe_alchemy(c, cpu);
18731da177e4SLinus Torvalds 		break;
18741da177e4SLinus Torvalds 	case PRID_COMP_SIBYTE:
1875cea7e2dfSRalf Baechle 		cpu_probe_sibyte(c, cpu);
18761da177e4SLinus Torvalds 		break;
18771c0c13ebSAurelien Jarno 	case PRID_COMP_BROADCOM:
1878cea7e2dfSRalf Baechle 		cpu_probe_broadcom(c, cpu);
18791c0c13ebSAurelien Jarno 		break;
18801da177e4SLinus Torvalds 	case PRID_COMP_SANDCRAFT:
1881cea7e2dfSRalf Baechle 		cpu_probe_sandcraft(c, cpu);
18821da177e4SLinus Torvalds 		break;
1883a92b0588SDaniel Laird 	case PRID_COMP_NXP:
1884cea7e2dfSRalf Baechle 		cpu_probe_nxp(c, cpu);
1885bdf21b18SPete Popov 		break;
18860dd4781bSDavid Daney 	case PRID_COMP_CAVIUM:
18870dd4781bSDavid Daney 		cpu_probe_cavium(c, cpu);
18880dd4781bSDavid Daney 		break;
1889b2edcfc8SHuacai Chen 	case PRID_COMP_LOONGSON:
1890b2edcfc8SHuacai Chen 		cpu_probe_loongson(c, cpu);
1891b2edcfc8SHuacai Chen 		break;
18920d10d17bS周琰杰 (Zhou Yanjie) 	case PRID_COMP_INGENIC_13:
1893252617a4SPaul Burton 	case PRID_COMP_INGENIC_D0:
1894252617a4SPaul Burton 	case PRID_COMP_INGENIC_D1:
1895252617a4SPaul Burton 	case PRID_COMP_INGENIC_E1:
189683ccf69dSLars-Peter Clausen 		cpu_probe_ingenic(c, cpu);
189783ccf69dSLars-Peter Clausen 		break;
18981da177e4SLinus Torvalds 	}
1899dec8b1caSFranck Bui-Huu 
1900cea7e2dfSRalf Baechle 	BUG_ON(!__cpu_name[cpu]);
1901cea7e2dfSRalf Baechle 	BUG_ON(c->cputype == CPU_UNKNOWN);
1902cea7e2dfSRalf Baechle 
1903dec8b1caSFranck Bui-Huu 	/*
1904dec8b1caSFranck Bui-Huu 	 * Platform code can force the cpu type to optimize code
1905dec8b1caSFranck Bui-Huu 	 * generation. In that case be sure the cpu type is correctly
1906dec8b1caSFranck Bui-Huu 	 * manually setup otherwise it could trigger some nasty bugs.
1907dec8b1caSFranck Bui-Huu 	 */
1908dec8b1caSFranck Bui-Huu 	BUG_ON(current_cpu_type() != c->cputype);
1909dec8b1caSFranck Bui-Huu 
19102e274768SFlorian Fainelli 	if (cpu_has_rixi) {
19112e274768SFlorian Fainelli 		/* Enable the RIXI exceptions */
19122e274768SFlorian Fainelli 		set_c0_pagegrain(PG_IEC);
19132e274768SFlorian Fainelli 		back_to_back_c0_hazard();
19142e274768SFlorian Fainelli 		/* Verify the IEC bit is set */
19152e274768SFlorian Fainelli 		if (read_c0_pagegrain() & PG_IEC)
19162e274768SFlorian Fainelli 			c->options |= MIPS_CPU_RIXIEX;
19172e274768SFlorian Fainelli 	}
19182e274768SFlorian Fainelli 
19190103d23fSKevin Cernekee 	if (mips_fpu_disabled)
19200103d23fSKevin Cernekee 		c->options &= ~MIPS_CPU_FPU;
19210103d23fSKevin Cernekee 
19220103d23fSKevin Cernekee 	if (mips_dsp_disabled)
1923ee80f7c7SSteven J. Hill 		c->ases &= ~(MIPS_ASE_DSP | MIPS_ASE_DSP2P);
19240103d23fSKevin Cernekee 
19253d528b32SMarkos Chandras 	if (mips_htw_disabled) {
19263d528b32SMarkos Chandras 		c->options &= ~MIPS_CPU_HTW;
19273d528b32SMarkos Chandras 		write_c0_pwctl(read_c0_pwctl() &
19283d528b32SMarkos Chandras 			       ~(1 << MIPS_PWCTL_PWEN_SHIFT));
19293d528b32SMarkos Chandras 	}
19303d528b32SMarkos Chandras 
19317aecd5caSMaciej W. Rozycki 	if (c->options & MIPS_CPU_FPU)
19327aecd5caSMaciej W. Rozycki 		cpu_set_fpu_opts(c);
19337aecd5caSMaciej W. Rozycki 	else
19347aecd5caSMaciej W. Rozycki 		cpu_set_nofpu_opts(c);
19359966db25SRalf Baechle 
19368b8aa636SLeonid Yegoshin 	if (cpu_has_mips_r2_r6) {
1937f6771dbbSRalf Baechle 		c->srsets = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
1938da4b62cdSAl Cooper 		/* R2 has Performance Counter Interrupt indicator */
1939da4b62cdSAl Cooper 		c->options |= MIPS_CPU_PCI;
1940da4b62cdSAl Cooper 	}
1941f6771dbbSRalf Baechle 	else
1942f6771dbbSRalf Baechle 		c->srsets = 1;
194391dfc423SGuenter Roeck 
19444c063034SPaul Burton 	if (cpu_has_mips_r6)
19454c063034SPaul Burton 		elf_hwcap |= HWCAP_MIPS_R6;
19464c063034SPaul Burton 
1947a8ad1367SPaul Burton 	if (cpu_has_msa) {
1948a5e9a69eSPaul Burton 		c->msa_id = cpu_get_msa_id();
1949a8ad1367SPaul Burton 		WARN(c->msa_id & MSA_IR_WRPF,
1950a8ad1367SPaul Burton 		     "Vector register partitioning unimplemented!");
19513cc9fa7fSPaul Burton 		elf_hwcap |= HWCAP_MIPS_MSA;
1952a8ad1367SPaul Burton 	}
1953a5e9a69eSPaul Burton 
195438dffe1eSJiaxun Yang 	if (cpu_has_mips16)
195538dffe1eSJiaxun Yang 		elf_hwcap |= HWCAP_MIPS_MIPS16;
195638dffe1eSJiaxun Yang 
195738dffe1eSJiaxun Yang 	if (cpu_has_mdmx)
195838dffe1eSJiaxun Yang 		elf_hwcap |= HWCAP_MIPS_MDMX;
195938dffe1eSJiaxun Yang 
196038dffe1eSJiaxun Yang 	if (cpu_has_mips3d)
196138dffe1eSJiaxun Yang 		elf_hwcap |= HWCAP_MIPS_MIPS3D;
196238dffe1eSJiaxun Yang 
196338dffe1eSJiaxun Yang 	if (cpu_has_smartmips)
196438dffe1eSJiaxun Yang 		elf_hwcap |= HWCAP_MIPS_SMARTMIPS;
196538dffe1eSJiaxun Yang 
196638dffe1eSJiaxun Yang 	if (cpu_has_dsp)
196738dffe1eSJiaxun Yang 		elf_hwcap |= HWCAP_MIPS_DSP;
196838dffe1eSJiaxun Yang 
196938dffe1eSJiaxun Yang 	if (cpu_has_dsp2)
197038dffe1eSJiaxun Yang 		elf_hwcap |= HWCAP_MIPS_DSP2;
197138dffe1eSJiaxun Yang 
197238dffe1eSJiaxun Yang 	if (cpu_has_dsp3)
197338dffe1eSJiaxun Yang 		elf_hwcap |= HWCAP_MIPS_DSP3;
197438dffe1eSJiaxun Yang 
197538dffe1eSJiaxun Yang 	if (cpu_has_mips16e2)
197638dffe1eSJiaxun Yang 		elf_hwcap |= HWCAP_MIPS_MIPS16E2;
197738dffe1eSJiaxun Yang 
197838dffe1eSJiaxun Yang 	if (cpu_has_loongson_mmi)
197938dffe1eSJiaxun Yang 		elf_hwcap |= HWCAP_LOONGSON_MMI;
198038dffe1eSJiaxun Yang 
198138dffe1eSJiaxun Yang 	if (cpu_has_loongson_ext)
198238dffe1eSJiaxun Yang 		elf_hwcap |= HWCAP_LOONGSON_EXT;
198338dffe1eSJiaxun Yang 
198438dffe1eSJiaxun Yang 	if (cpu_has_loongson_ext2)
198538dffe1eSJiaxun Yang 		elf_hwcap |= HWCAP_LOONGSON_EXT2;
198638dffe1eSJiaxun Yang 
19876ad816e7SJames Hogan 	if (cpu_has_vz)
19886ad816e7SJames Hogan 		cpu_probe_vz(c);
19896ad816e7SJames Hogan 
199091dfc423SGuenter Roeck 	cpu_probe_vmbits(c);
1991949e51beSDavid Daney 
1992ec7a9318SWANG Xuerui 	/* Synthesize CPUCFG data if running on Loongson processors;
1993ec7a9318SWANG Xuerui 	 * no-op otherwise.
1994ec7a9318SWANG Xuerui 	 *
1995ec7a9318SWANG Xuerui 	 * This looks at previously probed features, so keep this at bottom.
1996ec7a9318SWANG Xuerui 	 */
1997ec7a9318SWANG Xuerui 	loongson3_cpucfg_synthesize_data(c);
1998ec7a9318SWANG Xuerui 
1999949e51beSDavid Daney #ifdef CONFIG_64BIT
2000949e51beSDavid Daney 	if (cpu == 0)
2001949e51beSDavid Daney 		__ua_limit = ~((1ull << cpu_vmbits) - 1);
2002949e51beSDavid Daney #endif
2003bd67b711SThomas Bogendoerfer 
2004bd67b711SThomas Bogendoerfer 	reserve_exception_space(0, 0x1000);
20051da177e4SLinus Torvalds }
20061da177e4SLinus Torvalds 
cpu_report(void)2007078a55fcSPaul Gortmaker void cpu_report(void)
20081da177e4SLinus Torvalds {
20091da177e4SLinus Torvalds 	struct cpuinfo_mips *c = &current_cpu_data;
20101da177e4SLinus Torvalds 
2011d9f897c9SLeonid Yegoshin 	pr_info("CPU%d revision is: %08x (%s)\n",
2012d9f897c9SLeonid Yegoshin 		smp_processor_id(), c->processor_id, cpu_name_string());
20131da177e4SLinus Torvalds 	if (c->options & MIPS_CPU_FPU)
20149966db25SRalf Baechle 		printk(KERN_INFO "FPU revision is: %08x\n", c->fpu_id);
2015a5e9a69eSPaul Burton 	if (cpu_has_msa)
2016a5e9a69eSPaul Burton 		pr_info("MSA revision is: %08x\n", c->msa_id);
20171da177e4SLinus Torvalds }
2018856fbceeSPaul Burton 
cpu_set_cluster(struct cpuinfo_mips * cpuinfo,unsigned int cluster)20195616897eSPaul Burton void cpu_set_cluster(struct cpuinfo_mips *cpuinfo, unsigned int cluster)
20205616897eSPaul Burton {
20215616897eSPaul Burton 	/* Ensure the core number fits in the field */
20225616897eSPaul Burton 	WARN_ON(cluster > (MIPS_GLOBALNUMBER_CLUSTER >>
20235616897eSPaul Burton 			   MIPS_GLOBALNUMBER_CLUSTER_SHF));
20245616897eSPaul Burton 
20255616897eSPaul Burton 	cpuinfo->globalnumber &= ~MIPS_GLOBALNUMBER_CLUSTER;
20265616897eSPaul Burton 	cpuinfo->globalnumber |= cluster << MIPS_GLOBALNUMBER_CLUSTER_SHF;
20275616897eSPaul Burton }
20285616897eSPaul Burton 
cpu_set_core(struct cpuinfo_mips * cpuinfo,unsigned int core)2029856fbceeSPaul Burton void cpu_set_core(struct cpuinfo_mips *cpuinfo, unsigned int core)
2030856fbceeSPaul Burton {
2031856fbceeSPaul Burton 	/* Ensure the core number fits in the field */
2032856fbceeSPaul Burton 	WARN_ON(core > (MIPS_GLOBALNUMBER_CORE >> MIPS_GLOBALNUMBER_CORE_SHF));
2033856fbceeSPaul Burton 
2034856fbceeSPaul Burton 	cpuinfo->globalnumber &= ~MIPS_GLOBALNUMBER_CORE;
2035856fbceeSPaul Burton 	cpuinfo->globalnumber |= core << MIPS_GLOBALNUMBER_CORE_SHF;
2036856fbceeSPaul Burton }
2037856fbceeSPaul Burton 
cpu_set_vpe_id(struct cpuinfo_mips * cpuinfo,unsigned int vpe)2038856fbceeSPaul Burton void cpu_set_vpe_id(struct cpuinfo_mips *cpuinfo, unsigned int vpe)
2039856fbceeSPaul Burton {
2040856fbceeSPaul Burton 	/* Ensure the VP(E) ID fits in the field */
2041856fbceeSPaul Burton 	WARN_ON(vpe > (MIPS_GLOBALNUMBER_VP >> MIPS_GLOBALNUMBER_VP_SHF));
2042856fbceeSPaul Burton 
2043856fbceeSPaul Burton 	/* Ensure we're not using VP(E)s without support */
2044856fbceeSPaul Burton 	WARN_ON(vpe && !IS_ENABLED(CONFIG_MIPS_MT_SMP) &&
2045856fbceeSPaul Burton 		!IS_ENABLED(CONFIG_CPU_MIPSR6));
2046856fbceeSPaul Burton 
2047856fbceeSPaul Burton 	cpuinfo->globalnumber &= ~MIPS_GLOBALNUMBER_VP;
2048856fbceeSPaul Burton 	cpuinfo->globalnumber |= vpe << MIPS_GLOBALNUMBER_VP_SHF;
2049856fbceeSPaul Burton }
2050