summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2018-09-18 16:36:46 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2018-09-19 09:55:14 +0200
commite6b0633b51f9cacb0f0e649e44a56dce50883d8d (patch)
treecfb0cd59e8a56f330606c8417273c678575ebe60
parentbf8f28c05cacbb0771f5c2ce0e552e6c84a495b4 (diff)
downloadbarebox-e6b0633b51f9cacb0f0e649e44a56dce50883d8d.tar.gz
barebox-e6b0633b51f9cacb0f0e649e44a56dce50883d8d.tar.xz
ARM: i.MX27: Fix NAND boot with newer gcc
This is a fix for a very weird icache problem when booting from NAND. With a OSELAS-2018.01 toolchain imx27_barebox_boot_nand_external() is compiled like this: 0000063c <imx27_barebox_boot_nand_external>: 63c: e92d4010 push {r4, lr} 640: e1a0200f mov r2, pc 644: e282230a add r2, r2, #671088640 ; 0x28000000 648: e3520b02 cmp r2, #2048 ; 0x800 64c: 9a000012 bls 69c <imx27_barebox_boot_nand_external+0x60> 650: eb000034 bl 728 <imx27_barebox_entry> 654: e592c000 ldr ip, [r2] 658: e2822004 add r2, r2, #4 65c: e580c000 str ip, [r0] 660: e1520001 cmp r2, r1 664: e2820332 add r0, r2, #-939524096 ; 0xc8000000 668: 1afffff9 bne 654 <imx27_barebox_boot_nand_external+0x18> 66c: e1a00003 mov r0, r3 670: e59f2034 ldr r2, [pc, #52] ; 6ac <imx27_barebox_boot_nand_external+0x70> 674: e2401376 sub r1, r0, #-671088639 ; 0xd8000001 678: e59f3030 ldr r3, [pc, #48] ; 6b0 <imx27_barebox_boot_nand_external+0x74> 67c: e1510002 cmp r1, r2 680: 93c004ff bicls r0, r0, #-16777216 ; 0xff000000 684: e1a03a83 lsl r3, r3, #21 688: e1a03aa3 lsr r3, r3, #21 68c: 93c0073e bicls r0, r0, #16252928 ; 0xf80000 690: e283320a add r3, r3, #-1610612736 ; 0xa0000000 694: 9280020a addls r0, r0, #-1610612736 ; 0xa0000000 698: e12fff33 blx r3 69c: e1a03000 mov r3, r0 6a0: e3a02336 mov r2, #-671088640 ; 0xd8000000 6a4: e59f1008 ldr r1, [pc, #8] ; 6b4 <imx27_barebox_boot_nand_external+0x78> 6a8: eaffffec b 660 <imx27_barebox_boot_nand_external+0x24> 6ac: 0007fffe .word 0x0007fffe 6b0: 00000604 .word 0x00000604 6b4: d8000800 .word 0xd8000800 From 0x64c the code jumps to 0x69c and then back to 0x660. The jump to 0x69c triggers a icache line fetch which works fine, but then when the function continues and the code enters the same instruction cache line at 0x680 again then only garbage is executed, most of the time we end up in an endless loop and the CPU jumps back somewhere at the beginning of the function. I have carefully added nops right before the out of line code block. When there are enough nops to move the block to the next cache line then the code works again. That of course is no solution to the problem. Since I am out of ideas what the real issue is let's just disable the icache in this function and re-enable it in the next function. This seems to solve the problem. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Tested-by: Florian Bäuerle <florian.baeuerle@allegion.com>
-rw-r--r--arch/arm/mach-imx/external-nand-boot.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/arch/arm/mach-imx/external-nand-boot.c b/arch/arm/mach-imx/external-nand-boot.c
index 17878e400b..745a129b23 100644
--- a/arch/arm/mach-imx/external-nand-boot.c
+++ b/arch/arm/mach-imx/external-nand-boot.c
@@ -323,10 +323,14 @@ void __noreturn BARE_INIT_FUNCTION(imx##soc##_boot_nand_external_cont) \
{ \
unsigned long nfc_base = MX##soc##_NFC_BASE_ADDR; \
void *sdram = (void *)MX##soc##_CSD0_BASE_ADDR; \
- uint32_t image_size; \
+ uint32_t image_size, r; \
\
image_size = *(uint32_t *)(sdram + 0x2c); \
\
+ r = get_cr(); \
+ r |= CR_I; \
+ set_cr(r); \
+ \
imx##soc##_nand_load_image(sdram, \
image_size, \
(void *)nfc_base, \
@@ -347,6 +351,9 @@ void __noreturn BARE_INIT_FUNCTION(imx##soc##_barebox_boot_nand_external) \
int i; \
void __noreturn (*fn)(void *); \
\
+ r = get_cr(); \
+ r &= ~CR_I; \
+ set_cr(r); \
/* skip NAND boot if not running from NFC space */ \
r = get_pc(); \
if (r < nfc_base || r > nfc_base + 0x800) \