summaryrefslogtreecommitdiff
path: root/arch/mips/cpu/start.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/cpu/start.S')
-rw-r--r--arch/mips/cpu/start.S93
1 files changed, 57 insertions, 36 deletions
diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S
index fc6dd66..3f0fc12 100644
--- a/arch/mips/cpu/start.S
+++ b/arch/mips/cpu/start.S
@@ -12,10 +12,6 @@
#include <asm/regdef.h>
#include <asm/mipsregs.h>
-#ifndef CONFIG_SYS_MIPS_CACHE_MODE
-#define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT
-#endif
-
#ifndef CONFIG_SYS_INIT_SP_ADDR
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + \
CONFIG_SYS_INIT_SP_OFFSET)
@@ -112,9 +108,28 @@ ENTRY(_start)
.align 4
reset:
+#if __mips_isa_rev >= 6
+ mfc0 t0, CP0_CONFIG, 5
+ and t0, t0, MIPS_CONF5_VP
+ beqz t0, 1f
+ nop
+
+ b 2f
+ mfc0 t0, CP0_GLOBALNUMBER
+#endif
+
+1: mfc0 t0, CP0_EBASE
+ and t0, t0, EBASE_CPUNUM
+
+ /* Hang if this isn't the first CPU in the system */
+2: beqz t0, 4f
+ nop
+3: wait
+ b 3b
+ nop
/* Clear watch registers */
- MTC0 zero, CP0_WATCHLO
+4: MTC0 zero, CP0_WATCHLO
mtc0 zero, CP0_WATCHHI
/* WP(Watch Pending), SW0/1 should be cleared */
@@ -127,9 +142,11 @@ reset:
mtc0 zero, CP0_COMPARE
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
- /* CONFIG0 register */
- li t0, CONF_CM_UNCACHED
+ mfc0 t0, CP0_CONFIG
+ and t0, t0, MIPS_CONF_IMPL
+ or t0, t0, CONF_CM_UNCACHED
mtc0 t0, CP0_CONFIG
+ ehb
#endif
/*
@@ -144,20 +161,31 @@ reset:
1:
PTR_L gp, 0(ra)
+#ifdef CONFIG_MIPS_CM
+ PTR_LA t9, mips_cm_map
+ jalr t9
+ nop
+#endif
+
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+# ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD
/* Initialize any external memory */
PTR_LA t9, lowlevel_init
jalr t9
nop
+# endif
/* Initialize caches... */
PTR_LA t9, mips_cache_reset
jalr t9
nop
- /* ... and enable them */
- li t0, CONFIG_SYS_MIPS_CACHE_MODE
- mtc0 t0, CP0_CONFIG
+# ifndef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD
+ /* Initialize any external memory */
+ PTR_LA t9, lowlevel_init
+ jalr t9
+ nop
+# endif
#endif
/* Set up temporary stack */
@@ -214,12 +242,9 @@ ENTRY(relocate_code)
PTR_LI t0, CONFIG_SYS_MONITOR_BASE
PTR_SUB s1, s2, t0 # s1 <-- relocation offset
- PTR_LA t3, in_ram
- PTR_L t2, -(3 * PTRSIZE)(t3) # t2 <-- __image_copy_end
+ PTR_LA t2, __image_copy_end
move t1, a2
- PTR_ADD gp, s1 # adjust gp
-
/*
* t0 = source address
* t1 = target address
@@ -232,32 +257,14 @@ ENTRY(relocate_code)
blt t0, t2, 1b
PTR_ADDU t1, PTRSIZE
- /* If caches were enabled, we would have to flush them here. */
- PTR_SUB a1, t1, s2 # a1 <-- size
- PTR_LA t9, flush_cache
- jalr t9
- move a0, s2 # a0 <-- destination address
-
- /* Jump to where we've relocated ourselves */
- PTR_ADDIU t0, s2, in_ram - _start
- jr t0
- nop
-
- PTR __rel_dyn_end
- PTR __rel_dyn_start
- PTR __image_copy_end
- PTR _GLOBAL_OFFSET_TABLE_
- PTR num_got_entries
-
-in_ram:
/*
* Now we want to update GOT.
*
* GOT[0] is reserved. GOT[1] is also reserved for the dynamic object
* generated by GNU ld. Skip these reserved entries from relocation.
*/
- PTR_L t3, -(1 * PTRSIZE)(t0) # t3 <-- num_got_entries
- PTR_L t8, -(2 * PTRSIZE)(t0) # t8 <-- _GLOBAL_OFFSET_TABLE_
+ PTR_LA t3, num_got_entries
+ PTR_LA t8, _GLOBAL_OFFSET_TABLE_
PTR_ADD t8, s1 # t8 now holds relocated _G_O_T_
PTR_ADDIU t8, t8, 2 * PTRSIZE # skipping first two entries
PTR_LI t2, 2
@@ -272,8 +279,8 @@ in_ram:
PTR_ADDIU t8, PTRSIZE
/* Update dynamic relocations */
- PTR_L t1, -(4 * PTRSIZE)(t0) # t1 <-- __rel_dyn_start
- PTR_L t2, -(5 * PTRSIZE)(t0) # t2 <-- __rel_dyn_end
+ PTR_LA t1, __rel_dyn_start
+ PTR_LA t2, __rel_dyn_end
b 2f # skip first reserved entry
PTR_ADDIU t1, 2 * PTRSIZE
@@ -298,6 +305,20 @@ in_ram:
PTR_ADDIU t1, 2 * PTRSIZE # each rel.dyn entry is 2*PTRSIZE bytes
/*
+ * Flush caches to ensure our newly modified instructions are visible
+ * to the instruction cache. We're still running with the old GOT, so
+ * apply the reloc offset to the start address.
+ */
+ PTR_LA a0, __text_start
+ PTR_LA a1, __text_end
+ PTR_SUB a1, a1, a0
+ PTR_LA t9, flush_cache
+ jalr t9
+ PTR_ADD a0, s1
+
+ PTR_ADD gp, s1 # adjust gp
+
+ /*
* Clear BSS
*
* GOT is now relocated. Thus __bss_start and __bss_end can be