Update Linux to v5.10.109

Sourced from [1]

[1] https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.109.tar.xz

Change-Id: I19bca9fc6762d4e63bcf3e4cba88bbe560d9c76c
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index f521cbf..d120201 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -28,315 +28,14 @@
 #include <asm/spram.h>
 #include <linux/uaccess.h>
 
+#include "fpu-probe.h"
+
+#include <asm/mach-loongson64/cpucfg-emul.h>
+
 /* Hardware capabilities */
 unsigned int elf_hwcap __read_mostly;
 EXPORT_SYMBOL_GPL(elf_hwcap);
 
-#ifdef CONFIG_MIPS_FP_SUPPORT
-
-/*
- * Get the FPU Implementation/Revision.
- */
-static inline unsigned long cpu_get_fpu_id(void)
-{
-	unsigned long tmp, fpu_id;
-
-	tmp = read_c0_status();
-	__enable_fpu(FPU_AS_IS);
-	fpu_id = read_32bit_cp1_register(CP1_REVISION);
-	write_c0_status(tmp);
-	return fpu_id;
-}
-
-/*
- * Check if the CPU has an external FPU.
- */
-static inline int __cpu_has_fpu(void)
-{
-	return (cpu_get_fpu_id() & FPIR_IMP_MASK) != FPIR_IMP_NONE;
-}
-
-/*
- * Determine the FCSR mask for FPU hardware.
- */
-static inline void cpu_set_fpu_fcsr_mask(struct cpuinfo_mips *c)
-{
-	unsigned long sr, mask, fcsr, fcsr0, fcsr1;
-
-	fcsr = c->fpu_csr31;
-	mask = FPU_CSR_ALL_X | FPU_CSR_ALL_E | FPU_CSR_ALL_S | FPU_CSR_RM;
-
-	sr = read_c0_status();
-	__enable_fpu(FPU_AS_IS);
-
-	fcsr0 = fcsr & mask;
-	write_32bit_cp1_register(CP1_STATUS, fcsr0);
-	fcsr0 = read_32bit_cp1_register(CP1_STATUS);
-
-	fcsr1 = fcsr | ~mask;
-	write_32bit_cp1_register(CP1_STATUS, fcsr1);
-	fcsr1 = read_32bit_cp1_register(CP1_STATUS);
-
-	write_32bit_cp1_register(CP1_STATUS, fcsr);
-
-	write_c0_status(sr);
-
-	c->fpu_msk31 = ~(fcsr0 ^ fcsr1) & ~mask;
-}
-
-/*
- * Determine the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes
- * supported by FPU hardware.
- */
-static void cpu_set_fpu_2008(struct cpuinfo_mips *c)
-{
-	if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
-			    MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
-			    MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) {
-		unsigned long sr, fir, fcsr, fcsr0, fcsr1;
-
-		sr = read_c0_status();
-		__enable_fpu(FPU_AS_IS);
-
-		fir = read_32bit_cp1_register(CP1_REVISION);
-		if (fir & MIPS_FPIR_HAS2008) {
-			fcsr = read_32bit_cp1_register(CP1_STATUS);
-
-			fcsr0 = fcsr & ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
-			write_32bit_cp1_register(CP1_STATUS, fcsr0);
-			fcsr0 = read_32bit_cp1_register(CP1_STATUS);
-
-			fcsr1 = fcsr | FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
-			write_32bit_cp1_register(CP1_STATUS, fcsr1);
-			fcsr1 = read_32bit_cp1_register(CP1_STATUS);
-
-			write_32bit_cp1_register(CP1_STATUS, fcsr);
-
-			if (!(fcsr0 & FPU_CSR_NAN2008))
-				c->options |= MIPS_CPU_NAN_LEGACY;
-			if (fcsr1 & FPU_CSR_NAN2008)
-				c->options |= MIPS_CPU_NAN_2008;
-
-			if ((fcsr0 ^ fcsr1) & FPU_CSR_ABS2008)
-				c->fpu_msk31 &= ~FPU_CSR_ABS2008;
-			else
-				c->fpu_csr31 |= fcsr & FPU_CSR_ABS2008;
-
-			if ((fcsr0 ^ fcsr1) & FPU_CSR_NAN2008)
-				c->fpu_msk31 &= ~FPU_CSR_NAN2008;
-			else
-				c->fpu_csr31 |= fcsr & FPU_CSR_NAN2008;
-		} else {
-			c->options |= MIPS_CPU_NAN_LEGACY;
-		}
-
-		write_c0_status(sr);
-	} else {
-		c->options |= MIPS_CPU_NAN_LEGACY;
-	}
-}
-
-/*
- * IEEE 754 conformance mode to use.  Affects the NaN encoding and the
- * ABS.fmt/NEG.fmt execution mode.
- */
-static enum { STRICT, LEGACY, STD2008, RELAXED } ieee754 = STRICT;
-
-/*
- * Set the IEEE 754 NaN encodings and the ABS.fmt/NEG.fmt execution modes
- * to support by the FPU emulator according to the IEEE 754 conformance
- * mode selected.  Note that "relaxed" straps the emulator so that it
- * allows 2008-NaN binaries even for legacy processors.
- */
-static void cpu_set_nofpu_2008(struct cpuinfo_mips *c)
-{
-	c->options &= ~(MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY);
-	c->fpu_csr31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
-	c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
-
-	switch (ieee754) {
-	case STRICT:
-		if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
-				    MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
-				    MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) {
-			c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY;
-		} else {
-			c->options |= MIPS_CPU_NAN_LEGACY;
-			c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
-		}
-		break;
-	case LEGACY:
-		c->options |= MIPS_CPU_NAN_LEGACY;
-		c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
-		break;
-	case STD2008:
-		c->options |= MIPS_CPU_NAN_2008;
-		c->fpu_csr31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
-		c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
-		break;
-	case RELAXED:
-		c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY;
-		break;
-	}
-}
-
-/*
- * Override the IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode
- * according to the "ieee754=" parameter.
- */
-static void cpu_set_nan_2008(struct cpuinfo_mips *c)
-{
-	switch (ieee754) {
-	case STRICT:
-		mips_use_nan_legacy = !!cpu_has_nan_legacy;
-		mips_use_nan_2008 = !!cpu_has_nan_2008;
-		break;
-	case LEGACY:
-		mips_use_nan_legacy = !!cpu_has_nan_legacy;
-		mips_use_nan_2008 = !cpu_has_nan_legacy;
-		break;
-	case STD2008:
-		mips_use_nan_legacy = !cpu_has_nan_2008;
-		mips_use_nan_2008 = !!cpu_has_nan_2008;
-		break;
-	case RELAXED:
-		mips_use_nan_legacy = true;
-		mips_use_nan_2008 = true;
-		break;
-	}
-}
-
-/*
- * IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode override
- * settings:
- *
- * strict:  accept binaries that request a NaN encoding supported by the FPU
- * legacy:  only accept legacy-NaN binaries
- * 2008:    only accept 2008-NaN binaries
- * relaxed: accept any binaries regardless of whether supported by the FPU
- */
-static int __init ieee754_setup(char *s)
-{
-	if (!s)
-		return -1;
-	else if (!strcmp(s, "strict"))
-		ieee754 = STRICT;
-	else if (!strcmp(s, "legacy"))
-		ieee754 = LEGACY;
-	else if (!strcmp(s, "2008"))
-		ieee754 = STD2008;
-	else if (!strcmp(s, "relaxed"))
-		ieee754 = RELAXED;
-	else
-		return -1;
-
-	if (!(boot_cpu_data.options & MIPS_CPU_FPU))
-		cpu_set_nofpu_2008(&boot_cpu_data);
-	cpu_set_nan_2008(&boot_cpu_data);
-
-	return 0;
-}
-
-early_param("ieee754", ieee754_setup);
-
-/*
- * Set the FIR feature flags for the FPU emulator.
- */
-static void cpu_set_nofpu_id(struct cpuinfo_mips *c)
-{
-	u32 value;
-
-	value = 0;
-	if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
-			    MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
-			    MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6))
-		value |= MIPS_FPIR_D | MIPS_FPIR_S;
-	if (c->isa_level & (MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
-			    MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6))
-		value |= MIPS_FPIR_F64 | MIPS_FPIR_L | MIPS_FPIR_W;
-	if (c->options & MIPS_CPU_NAN_2008)
-		value |= MIPS_FPIR_HAS2008;
-	c->fpu_id = value;
-}
-
-/* Determined FPU emulator mask to use for the boot CPU with "nofpu".  */
-static unsigned int mips_nofpu_msk31;
-
-/*
- * Set options for FPU hardware.
- */
-static void cpu_set_fpu_opts(struct cpuinfo_mips *c)
-{
-	c->fpu_id = cpu_get_fpu_id();
-	mips_nofpu_msk31 = c->fpu_msk31;
-
-	if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
-			    MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
-			    MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) {
-		if (c->fpu_id & MIPS_FPIR_3D)
-			c->ases |= MIPS_ASE_MIPS3D;
-		if (c->fpu_id & MIPS_FPIR_UFRP)
-			c->options |= MIPS_CPU_UFR;
-		if (c->fpu_id & MIPS_FPIR_FREP)
-			c->options |= MIPS_CPU_FRE;
-	}
-
-	cpu_set_fpu_fcsr_mask(c);
-	cpu_set_fpu_2008(c);
-	cpu_set_nan_2008(c);
-}
-
-/*
- * Set options for the FPU emulator.
- */
-static void cpu_set_nofpu_opts(struct cpuinfo_mips *c)
-{
-	c->options &= ~MIPS_CPU_FPU;
-	c->fpu_msk31 = mips_nofpu_msk31;
-
-	cpu_set_nofpu_2008(c);
-	cpu_set_nan_2008(c);
-	cpu_set_nofpu_id(c);
-}
-
-static int mips_fpu_disabled;
-
-static int __init fpu_disable(char *s)
-{
-	cpu_set_nofpu_opts(&boot_cpu_data);
-	mips_fpu_disabled = 1;
-
-	return 1;
-}
-
-__setup("nofpu", fpu_disable);
-
-#else /* !CONFIG_MIPS_FP_SUPPORT */
-
-#define mips_fpu_disabled 1
-
-static inline unsigned long cpu_get_fpu_id(void)
-{
-	return FPIR_IMP_NONE;
-}
-
-static inline int __cpu_has_fpu(void)
-{
-	return 0;
-}
-
-static void cpu_set_fpu_opts(struct cpuinfo_mips *c)
-{
-	/* no-op */
-}
-
-static void cpu_set_nofpu_opts(struct cpuinfo_mips *c)
-{
-	/* no-op */
-}
-
-#endif /* CONFIG_MIPS_FP_SUPPORT */
-
 static inline unsigned long cpu_get_msa_id(void)
 {
 	unsigned long status, msa_id;
@@ -499,6 +198,13 @@
 		__elf_platform = plat;
 }
 
+static inline void set_elf_base_platform(const char *plat)
+{
+	if (__elf_base_platform == NULL) {
+		__elf_base_platform = plat;
+	}
+}
+
 static inline void cpu_probe_vmbits(struct cpuinfo_mips *c)
 {
 #ifdef __NEED_VMBITS_PROBE
@@ -511,38 +217,56 @@
 static void set_isa(struct cpuinfo_mips *c, unsigned int isa)
 {
 	switch (isa) {
+	case MIPS_CPU_ISA_M64R5:
+		c->isa_level |= MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5;
+		set_elf_base_platform("mips64r5");
+		fallthrough;
 	case MIPS_CPU_ISA_M64R2:
 		c->isa_level |= MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2;
-		/* fall through */
+		set_elf_base_platform("mips64r2");
+		fallthrough;
 	case MIPS_CPU_ISA_M64R1:
 		c->isa_level |= MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1;
-		/* fall through */
+		set_elf_base_platform("mips64");
+		fallthrough;
 	case MIPS_CPU_ISA_V:
 		c->isa_level |= MIPS_CPU_ISA_V;
-		/* fall through */
+		set_elf_base_platform("mips5");
+		fallthrough;
 	case MIPS_CPU_ISA_IV:
 		c->isa_level |= MIPS_CPU_ISA_IV;
-		/* fall through */
+		set_elf_base_platform("mips4");
+		fallthrough;
 	case MIPS_CPU_ISA_III:
 		c->isa_level |= MIPS_CPU_ISA_II | MIPS_CPU_ISA_III;
+		set_elf_base_platform("mips3");
 		break;
 
 	/* R6 incompatible with everything else */
 	case MIPS_CPU_ISA_M64R6:
 		c->isa_level |= MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6;
-		/* fall through */
+		set_elf_base_platform("mips64r6");
+		fallthrough;
 	case MIPS_CPU_ISA_M32R6:
 		c->isa_level |= MIPS_CPU_ISA_M32R6;
+		set_elf_base_platform("mips32r6");
 		/* Break here so we don't add incompatible ISAs */
 		break;
+	case MIPS_CPU_ISA_M32R5:
+		c->isa_level |= MIPS_CPU_ISA_M32R5;
+		set_elf_base_platform("mips32r5");
+		fallthrough;
 	case MIPS_CPU_ISA_M32R2:
 		c->isa_level |= MIPS_CPU_ISA_M32R2;
-		/* fall through */
+		set_elf_base_platform("mips32r2");
+		fallthrough;
 	case MIPS_CPU_ISA_M32R1:
 		c->isa_level |= MIPS_CPU_ISA_M32R1;
-		/* fall through */
+		set_elf_base_platform("mips32");
+		fallthrough;
 	case MIPS_CPU_ISA_II:
 		c->isa_level |= MIPS_CPU_ISA_II;
+		set_elf_base_platform("mips2");
 		break;
 	}
 }
@@ -589,14 +313,14 @@
 		config = read_c0_config6();
 
 		if (flags & FTLB_EN)
-			config |= MIPS_CONF6_FTLBEN;
+			config |= MTI_CONF6_FTLBEN;
 		else
-			config &= ~MIPS_CONF6_FTLBEN;
+			config &= ~MTI_CONF6_FTLBEN;
 
 		if (flags & FTLB_SET_PROB) {
-			config &= ~(3 << MIPS_CONF6_FTLBP_SHIFT);
+			config &= ~(3 << MTI_CONF6_FTLBP_SHIFT);
 			config |= calculate_ftlb_probability(c)
-				  << MIPS_CONF6_FTLBP_SHIFT;
+				  << MTI_CONF6_FTLBP_SHIFT;
 		}
 
 		write_c0_config6(config);
@@ -608,7 +332,7 @@
 		if (!(flags & FTLB_EN))
 			return 1;
 		return 0;
-	case CPU_LOONGSON3:
+	case CPU_LOONGSON64:
 		/* Flush ITLB, DTLB, VTLB and FTLB */
 		write_c0_diag(LOONGSON_DIAG_ITLB | LOONGSON_DIAG_DTLB |
 			      LOONGSON_DIAG_VTLB | LOONGSON_DIAG_FTLB);
@@ -616,10 +340,10 @@
 		config = read_c0_config6();
 		if (flags & FTLB_EN)
 			/* Enable FTLB */
-			write_c0_config6(config & ~MIPS_CONF6_FTLBDIS);
+			write_c0_config6(config & ~LOONGSON_CONF6_FTLBDIS);
 		else
 			/* Disable FTLB */
-			write_c0_config6(config | MIPS_CONF6_FTLBDIS);
+			write_c0_config6(config | LOONGSON_CONF6_FTLBDIS);
 		break;
 	default:
 		return 1;
@@ -628,6 +352,52 @@
 	return 0;
 }
 
+static int mm_config(struct cpuinfo_mips *c)
+{
+	unsigned int config0, update, mm;
+
+	config0 = read_c0_config();
+	mm = config0 & MIPS_CONF_MM;
+
+	/*
+	 * It's implementation dependent what type of write-merge is supported
+	 * and whether it can be enabled/disabled. If it is settable lets make
+	 * the merging allowed by default. Some platforms might have
+	 * write-through caching unsupported. In this case just ignore the
+	 * CP0.Config.MM bit field value.
+	 */
+	switch (c->cputype) {
+	case CPU_24K:
+	case CPU_34K:
+	case CPU_74K:
+	case CPU_P5600:
+	case CPU_P6600:
+		c->options |= MIPS_CPU_MM_FULL;
+		update = MIPS_CONF_MM_FULL;
+		break;
+	case CPU_1004K:
+	case CPU_1074K:
+	case CPU_INTERAPTIV:
+	case CPU_PROAPTIV:
+		mm = 0;
+		fallthrough;
+	default:
+		update = 0;
+		break;
+	}
+
+	if (update) {
+		config0 = (config0 & ~MIPS_CONF_MM) | update;
+		write_c0_config(config0);
+	} else if (mm == MIPS_CONF_MM_SYSAD) {
+		c->options |= MIPS_CPU_MM_SYSAD;
+	} else if (mm == MIPS_CONF_MM_FULL) {
+		c->options |= MIPS_CPU_MM_FULL;
+	}
+
+	return 0;
+}
+
 static inline unsigned int decode_config0(struct cpuinfo_mips *c)
 {
 	unsigned int config0;
@@ -819,7 +589,7 @@
 				  MIPS_CONF4_VTLBSIZEEXT_SHIFT) * 0x40;
 			c->tlbsize = c->tlbsizevtlb;
 			ftlb_page = MIPS_CONF4_VFTLBPAGESIZE;
-			/* fall through */
+			fallthrough;
 		case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT:
 			if (mips_ftlb_disabled)
 				break;
@@ -1508,8 +1278,9 @@
 		c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX |
 			     MIPS_CPU_FPU | MIPS_CPU_32FPR |
 			     MIPS_CPU_COUNTER | MIPS_CPU_WATCH |
-			     MIPS_CPU_LLSC | MIPS_CPU_BP_GHIST;
+			     MIPS_CPU_LLSC;
 		c->tlbsize = 64;
+		write_c0_r10k_diag(read_c0_r10k_diag() | R10K_DIAG_E_GHIST);
 		break;
 	case PRID_IMP_R14000:
 		if (((c->processor_id >> 4) & 0x0f) > 2) {
@@ -1523,27 +1294,28 @@
 		c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX |
 			     MIPS_CPU_FPU | MIPS_CPU_32FPR |
 			     MIPS_CPU_COUNTER | MIPS_CPU_WATCH |
-			     MIPS_CPU_LLSC | MIPS_CPU_BP_GHIST;
+			     MIPS_CPU_LLSC;
 		c->tlbsize = 64;
+		write_c0_r10k_diag(read_c0_r10k_diag() | R10K_DIAG_E_GHIST);
 		break;
-	case PRID_IMP_LOONGSON_64:  /* Loongson-2/3 */
+	case PRID_IMP_LOONGSON_64C:  /* Loongson-2/3 */
 		switch (c->processor_id & PRID_REV_MASK) {
 		case PRID_REV_LOONGSON2E:
-			c->cputype = CPU_LOONGSON2;
+			c->cputype = CPU_LOONGSON2EF;
 			__cpu_name[cpu] = "ICT Loongson-2";
 			set_elf_platform(cpu, "loongson2e");
 			set_isa(c, MIPS_CPU_ISA_III);
 			c->fpu_msk31 |= FPU_CSR_CONDX;
 			break;
 		case PRID_REV_LOONGSON2F:
-			c->cputype = CPU_LOONGSON2;
+			c->cputype = CPU_LOONGSON2EF;
 			__cpu_name[cpu] = "ICT Loongson-2";
 			set_elf_platform(cpu, "loongson2f");
 			set_isa(c, MIPS_CPU_ISA_III);
 			c->fpu_msk31 |= FPU_CSR_CONDX;
 			break;
 		case PRID_REV_LOONGSON3A_R1:
-			c->cputype = CPU_LOONGSON3;
+			c->cputype = CPU_LOONGSON64;
 			__cpu_name[cpu] = "ICT Loongson-3";
 			set_elf_platform(cpu, "loongson3a");
 			set_isa(c, MIPS_CPU_ISA_M64R1);
@@ -1552,7 +1324,7 @@
 			break;
 		case PRID_REV_LOONGSON3B_R1:
 		case PRID_REV_LOONGSON3B_R2:
-			c->cputype = CPU_LOONGSON3;
+			c->cputype = CPU_LOONGSON64;
 			__cpu_name[cpu] = "ICT Loongson-3";
 			set_elf_platform(cpu, "loongson3b");
 			set_isa(c, MIPS_CPU_ISA_M64R1);
@@ -1565,12 +1337,13 @@
 			     MIPS_CPU_FPU | MIPS_CPU_LLSC |
 			     MIPS_CPU_32FPR;
 		c->tlbsize = 64;
+		set_cpu_asid_mask(c, MIPS_ENTRYHI_ASID);
 		c->writecombine = _CACHE_UNCACHED_ACCELERATED;
 		break;
 	case PRID_IMP_LOONGSON_32:  /* Loongson-1 */
 		decode_configs(c);
 
-		c->cputype = CPU_LOONGSON1;
+		c->cputype = CPU_LOONGSON32;
 
 		switch (c->processor_id & PRID_REV_MASK) {
 		case PRID_REV_LOONGSON1B:
@@ -1718,16 +1491,35 @@
 
 	spram_config();
 
+	mm_config(c);
+
 	switch (__get_cpu_type(c->cputype)) {
+	case CPU_M5150:
+	case CPU_P5600:
+		set_isa(c, MIPS_CPU_ISA_M32R5);
+		break;
 	case CPU_I6500:
 		c->options |= MIPS_CPU_SHARED_FTLB_ENTRIES;
-		/* fall-through */
+		fallthrough;
 	case CPU_I6400:
 		c->options |= MIPS_CPU_SHARED_FTLB_RAM;
-		/* fall-through */
+		fallthrough;
 	default:
 		break;
 	}
+
+	/* Recent MIPS cores use the implementation-dependent ExcCode 16 for
+	 * cache/FTLB parity exceptions.
+	 */
+	switch (__get_cpu_type(c->cputype)) {
+	case CPU_PROAPTIV:
+	case CPU_P5600:
+	case CPU_P6600:
+	case CPU_I6400:
+	case CPU_I6500:
+		c->options |= MIPS_CPU_FTLBPAREX;
+		break;
+	}
 }
 
 static inline void cpu_probe_alchemy(struct cpuinfo_mips *c, unsigned int cpu)
@@ -1900,38 +1692,101 @@
 	}
 }
 
+#ifdef CONFIG_CPU_LOONGSON64
+#include <loongson_regs.h>
+
+static inline void decode_cpucfg(struct cpuinfo_mips *c)
+{
+	u32 cfg1 = read_cpucfg(LOONGSON_CFG1);
+	u32 cfg2 = read_cpucfg(LOONGSON_CFG2);
+	u32 cfg3 = read_cpucfg(LOONGSON_CFG3);
+
+	if (cfg1 & LOONGSON_CFG1_MMI)
+		c->ases |= MIPS_ASE_LOONGSON_MMI;
+
+	if (cfg2 & LOONGSON_CFG2_LEXT1)
+		c->ases |= MIPS_ASE_LOONGSON_EXT;
+
+	if (cfg2 & LOONGSON_CFG2_LEXT2)
+		c->ases |= MIPS_ASE_LOONGSON_EXT2;
+
+	if (cfg2 & LOONGSON_CFG2_LSPW) {
+		c->options |= MIPS_CPU_LDPTE;
+		c->guest.options |= MIPS_CPU_LDPTE;
+	}
+
+	if (cfg3 & LOONGSON_CFG3_LCAMP)
+		c->ases |= MIPS_ASE_LOONGSON_CAM;
+}
+
 static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu)
 {
+	/* All Loongson processors covered here define ExcCode 16 as GSExc. */
+	c->options |= MIPS_CPU_GSEXCEX;
+
 	switch (c->processor_id & PRID_IMP_MASK) {
-	case PRID_IMP_LOONGSON_64:  /* Loongson-2/3 */
+	case PRID_IMP_LOONGSON_64R: /* Loongson-64 Reduced */
+		switch (c->processor_id & PRID_REV_MASK) {
+		case PRID_REV_LOONGSON2K_R1_0:
+		case PRID_REV_LOONGSON2K_R1_1:
+		case PRID_REV_LOONGSON2K_R1_2:
+		case PRID_REV_LOONGSON2K_R1_3:
+			c->cputype = CPU_LOONGSON64;
+			__cpu_name[cpu] = "Loongson-2K";
+			set_elf_platform(cpu, "gs264e");
+			set_isa(c, MIPS_CPU_ISA_M64R2);
+			break;
+		}
+		c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_EXT |
+				MIPS_ASE_LOONGSON_EXT2);
+		break;
+	case PRID_IMP_LOONGSON_64C:  /* Loongson-3 Classic */
 		switch (c->processor_id & PRID_REV_MASK) {
 		case PRID_REV_LOONGSON3A_R2_0:
 		case PRID_REV_LOONGSON3A_R2_1:
-			c->cputype = CPU_LOONGSON3;
+			c->cputype = CPU_LOONGSON64;
 			__cpu_name[cpu] = "ICT Loongson-3";
 			set_elf_platform(cpu, "loongson3a");
 			set_isa(c, MIPS_CPU_ISA_M64R2);
 			break;
 		case PRID_REV_LOONGSON3A_R3_0:
 		case PRID_REV_LOONGSON3A_R3_1:
-			c->cputype = CPU_LOONGSON3;
+			c->cputype = CPU_LOONGSON64;
 			__cpu_name[cpu] = "ICT Loongson-3";
 			set_elf_platform(cpu, "loongson3a");
 			set_isa(c, MIPS_CPU_ISA_M64R2);
 			break;
 		}
-
-		decode_configs(c);
+		/*
+		 * Loongson-3 Classic did not implement MIPS standard TLBINV
+		 * but implemented TLBINVF and EHINV. As currently we're only
+		 * using these two features, enable MIPS_CPU_TLBINV as well.
+		 *
+		 * Also some early Loongson-3A2000 had wrong TLB type in Config
+		 * register, we correct it here.
+		 */
 		c->options |= MIPS_CPU_FTLB | MIPS_CPU_TLBINV | MIPS_CPU_LDPTE;
-		c->writecombine = _CACHE_UNCACHED_ACCELERATED;
 		c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_CAM |
 			MIPS_ASE_LOONGSON_EXT | MIPS_ASE_LOONGSON_EXT2);
+		c->ases &= ~MIPS_ASE_VZ; /* VZ of Loongson-3A2000/3000 is incomplete */
+		break;
+	case PRID_IMP_LOONGSON_64G:
+		c->cputype = CPU_LOONGSON64;
+		__cpu_name[cpu] = "ICT Loongson-3";
+		set_elf_platform(cpu, "loongson3a");
+		set_isa(c, MIPS_CPU_ISA_M64R2);
+		decode_cpucfg(c);
 		break;
 	default:
 		panic("Unknown Loongson Processor ID!");
 		break;
 	}
+
+	decode_configs(c);
 }
+#else
+static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu) { }
+#endif
 
 static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
 {
@@ -1945,13 +1800,16 @@
 
 	/* XBurst does not implement the CP0 counter. */
 	c->options &= ~MIPS_CPU_COUNTER;
-	BUG_ON(!__builtin_constant_p(cpu_has_counter) || cpu_has_counter);
+	BUG_ON(__builtin_constant_p(cpu_has_counter) && cpu_has_counter);
+
+	/* XBurst has virtually tagged icache */
+	c->icache.flags |= MIPS_CACHE_VTAG;
 
 	switch (c->processor_id & PRID_IMP_MASK) {
-	case PRID_IMP_XBURST:
-		c->cputype = CPU_XBURST;
-		c->writecombine = _CACHE_UNCACHED_ACCELERATED;
-		__cpu_name[cpu] = "Ingenic JZRISC";
+
+	/* XBurst®1 with MXU1.0/MXU1.1 SIMD ISA */
+	case PRID_IMP_XBURST_REV1:
+
 		/*
 		 * The XBurst core by default attempts to avoid branch target
 		 * buffer lookups by detecting & special casing loops. This
@@ -1959,19 +1817,60 @@
 		 * Set cp0 config7 bit 4 to disable this feature.
 		 */
 		set_c0_config7(MIPS_CONF7_BTB_LOOP_EN);
+
+		switch (c->processor_id & PRID_COMP_MASK) {
+
+		/*
+		 * The config0 register in the XBurst CPUs with a processor ID of
+		 * PRID_COMP_INGENIC_D0 report themselves as MIPS32r2 compatible,
+		 * but they don't actually support this ISA.
+		 */
+		case PRID_COMP_INGENIC_D0:
+			c->isa_level &= ~MIPS_CPU_ISA_M32R2;
+
+			/* FPU is not properly detected on JZ4760(B). */
+			if (c->processor_id == 0x2ed0024f)
+				c->options |= MIPS_CPU_FPU;
+
+			fallthrough;
+
+		/*
+		 * The config0 register in the XBurst CPUs with a processor ID of
+		 * PRID_COMP_INGENIC_D0 or PRID_COMP_INGENIC_D1 has an abandoned
+		 * huge page tlb mode, this mode is not compatible with the MIPS
+		 * standard, it will cause tlbmiss and into an infinite loop
+		 * (line 21 in the tlb-funcs.S) when starting the init process.
+		 * After chip reset, the default is HPTLB mode, Write 0xa9000000
+		 * to cp0 register 5 sel 4 to switch back to VTLB mode to prevent
+		 * getting stuck.
+		 */
+		case PRID_COMP_INGENIC_D1:
+			write_c0_page_ctrl(XBURST_PAGECTRL_HPTLB_DIS);
+			break;
+
+		default:
+			break;
+		}
+		fallthrough;
+
+	/* XBurst®1 with MXU2.0 SIMD ISA */
+	case PRID_IMP_XBURST_REV2:
+		/* Ingenic uses the WA bit to achieve write-combine memory writes */
+		c->writecombine = _CACHE_CACHABLE_WA;
+		c->cputype = CPU_XBURST;
+		__cpu_name[cpu] = "Ingenic XBurst";
 		break;
+
+	/* XBurst®2 with MXU2.1 SIMD ISA */
+	case PRID_IMP_XBURST2:
+		c->cputype = CPU_XBURST;
+		__cpu_name[cpu] = "Ingenic XBurst II";
+		break;
+
 	default:
 		panic("Unknown Ingenic Processor ID!");
 		break;
 	}
-
-	/*
-	 * The config0 register in the Xburst CPUs with a processor ID of
-	 * PRID_COMP_INGENIC_D0 report themselves as MIPS32r2 compatible,
-	 * but they don't actually support this ISA.
-	 */
-	if ((c->processor_id & PRID_COMP_MASK) == PRID_COMP_INGENIC_D0)
-		c->isa_level &= ~MIPS_CPU_ISA_M32R2;
 }
 
 static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)
@@ -2063,6 +1962,7 @@
 
 const char *__cpu_name[NR_CPUS];
 const char *__elf_platform;
+const char *__elf_base_platform;
 
 void cpu_probe(void)
 {
@@ -2112,6 +2012,7 @@
 	case PRID_COMP_LOONGSON:
 		cpu_probe_loongson(c, cpu);
 		break;
+	case PRID_COMP_INGENIC_13:
 	case PRID_COMP_INGENIC_D0:
 	case PRID_COMP_INGENIC_D1:
 	case PRID_COMP_INGENIC_E1:
@@ -2158,10 +2059,6 @@
 	else
 		cpu_set_nofpu_opts(c);
 
-	if (cpu_has_bp_ghist)
-		write_c0_r10k_diag(read_c0_r10k_diag() |
-				   R10K_DIAG_E_GHIST);
-
 	if (cpu_has_mips_r2_r6) {
 		c->srsets = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
 		/* R2 has Performance Counter Interrupt indicator */
@@ -2218,6 +2115,13 @@
 
 	cpu_probe_vmbits(c);
 
+	/* Synthesize CPUCFG data if running on Loongson processors;
+	 * no-op otherwise.
+	 *
+	 * This looks at previously probed features, so keep this at bottom.
+	 */
+	loongson3_cpucfg_synthesize_data(c);
+
 #ifdef CONFIG_64BIT
 	if (cpu == 0)
 		__ua_limit = ~((1ull << cpu_vmbits) - 1);