Subject: [PATCH] ARM: BCM5301X: Disable MMU and Dcache during decompression
From: Rafał Miłecki <[email-masked]>
Date: Wed, 24 Sep 2014 22:14:07 +0200

Broadcom devices have broken CFE (bootloader) that leaves hardware in an
invalid state. It causes problems with booting Linux. On Northstar
devices kernel was randomly hanging in ~25% of tries during early init.
Hangs used to happen at random places in the start_kernel. On BCM53573
kernel doesn't even seem to start booting.

To workaround this problem we need to do following very early:
1) Clear 2 following bits in the SCTLR register:
#define CR_M    (1 << 0)        /* MMU enable */
#define CR_C    (1 << 2)        /* Dcache enable */
2) Flush the whole D-cache
3) Disable L2 cache

Unfortunately this patch is not upstreamable as it does above things
unconditionally. We can't check if we are running on Broadcom platform
in any safe way and doing such hacks with ARCH_MULTI_V7 is unacceptable
as it could break other devices support.

Signed-off-by: Rafał Miłecki <[email-masked]>
---

--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -35,6 +35,11 @@ ifeq ($(CONFIG_ARCH_ACORN),y)
 OBJS		+= ll_char_wr.o font.o
 endif
 
+ifeq ($(CONFIG_ARCH_BCM_5301X),y)
+OBJS		+= head-bcm_5301x-mpcore.o
+OBJS		+= cache-v7-min.o
+endif
+
 ifeq ($(CONFIG_ARCH_SA1100),y)
 OBJS		+= head-sa1100.o
 endif
--- /dev/null
+++ b/arch/arm/boot/compressed/head-bcm_5301x-mpcore.S
@@ -0,0 +1,37 @@
+/*
+ *
+ * Platform specific tweaks.  This is merged into head.S by the linker.
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/cp15.h>
+
+		.section        ".start", "ax"
+
+/*
+ * This code section is spliced into the head code by the linker
+ */
+
+__plat_uncompress_start:
+
+	@ Preserve r8/r7 i.e. kernel entry values
+	mov	r12, r8
+
+	@ Clear MMU enable and Dcache enable bits
+	mrc	p15, 0, r0, c1, c0, 0		@ Read SCTLR
+	bic	r0, #CR_C|CR_M
+	mcr	p15, 0, r0, c1, c0, 0		@ Write SCTLR
+	nop
+
+	@ Call the cache invalidation routine
+	bl	v7_flush_dcache_all
+	nop
+	mov	r0,#0
+	ldr	r3, =0x19022000			@ L2 cache controller, control reg
+	str	r0, [r3, #0x100]		@ Disable L2 cache
+	nop
+
+	@ Restore
+	mov	r8, r12
--- a/arch/arm/boot/compressed/cache-v7-min.S
+++ b/arch/arm/boot/compressed/cache-v7-min.S
@@ -12,6 +12,7 @@
 
 #include <linux/linkage.h>
 #include <linux/init.h>
+#include <asm/assembler.h>
 
 	__INIT
 
@@ -63,7 +64,7 @@ loop2:
  ARM(	orr	r11, r11, r9, lsl r2	)	@ factor index number into r11
  THUMB(	lsl	r6, r9, r2		)
  THUMB(	orr	r11, r11, r6		)	@ factor index number into r11
-	mcr	p15, 0, r11, c7, c14, 2		@ clean & invalidate by set/way
+	mcr     p15, 0, r11, c7, c6, 2		@ clean & invalidate by set/way
 	subs	r9, r9, #1			@ decrement the index
 	bge	loop2
 	subs	r4, r4, #1			@ decrement the way