+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Startup Code for MIPS32 CPU-core
*
* Copyright (c) 2003 Wolfgang Denk <wd@denx.de>
- *
- * SPDX-License-Identifier: GPL-2.0+
*/
#include <asm-offsets.h>
#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)
#endif
#ifdef CONFIG_32BIT
-# define MIPS_RELOC 3
# define STATUS_SET 0
#endif
#ifdef CONFIG_64BIT
-# ifdef CONFIG_SYS_LITTLE_ENDIAN
-# define MIPS64_R_INFO(ssym, r_type3, r_type2, r_type) \
- (((r_type) << 24) | ((r_type2) << 16) | ((r_type3) << 8) | (ssym))
-# else
-# define MIPS64_R_INFO(ssym, r_type3, r_type2, r_type) \
- ((r_type) | ((r_type2) << 8) | ((r_type3) << 16) | (ssym) << 24)
-# endif
-# define MIPS_RELOC MIPS64_R_INFO(0x00, 0x00, 0x12, 0x03)
# define STATUS_SET ST0_KX
#endif
- /*
- * For the moment disable interrupts, mark the kernel mode and
- * set ST0_KX so that the CPU does not spit fire when using
- * 64-bit addresses.
- */
- .macro setup_c0_status set clr
- .set push
- mfc0 t0, CP0_STATUS
- or t0, ST0_CU0 | \set | 0x1f | \clr
- xor t0, 0x1f | \clr
- mtc0 t0, CP0_STATUS
- .set noreorder
- sll zero, 3 # ehb
- .set pop
+ .set noreorder
+
+ .macro init_wr sel
+ MTC0 zero, CP0_WATCHLO,\sel
+ mtc0 t1, CP0_WATCHHI,\sel
+ mfc0 t0, CP0_WATCHHI,\sel
+ bgez t0, wr_done
+ nop
.endm
- .set noreorder
+ .macro uhi_mips_exception
+ move k0, t9 # preserve t9 in k0
+ move k1, a0 # preserve a0 in k1
+ li t9, 15 # UHI exception operation
+ li a0, 0 # Use hard register context
+ sdbbp 1 # Invoke UHI operation
+ .endm
-ENTRY(_start)
- /* U-boot entry point */
- b reset
+ .macro setup_stack_gd
+ li t0, -16
+ PTR_LI t1, CONFIG_SYS_INIT_SP_ADDR
+ and sp, t1, t0 # force 16 byte alignment
+ PTR_SUBU \
+ sp, sp, GD_SIZE # reserve space for gd
+ and sp, sp, t0 # force 16 byte alignment
+ move k0, sp # save gd pointer
+#if CONFIG_VAL(SYS_MALLOC_F_LEN) && \
+ !CONFIG_IS_ENABLED(INIT_STACK_WITHOUT_MALLOC_F)
+ li t2, CONFIG_VAL(SYS_MALLOC_F_LEN)
+ PTR_SUBU \
+ sp, sp, t2 # reserve space for early malloc
+ and sp, sp, t0 # force 16 byte alignment
+#endif
+ move fp, sp
+
+ /* Clear gd */
+ move t0, k0
+1:
+ PTR_S zero, 0(t0)
+ PTR_ADDIU t0, PTRSIZE
+ blt t0, t1, 1b
nop
- .org 0x10
-#if defined(CONFIG_SYS_XWAY_EBU_BOOTCFG)
+#if CONFIG_VAL(SYS_MALLOC_F_LEN) && \
+ !CONFIG_IS_ENABLED(INIT_STACK_WITHOUT_MALLOC_F)
+ PTR_S sp, GD_MALLOC_BASE(k0) # gd->malloc_base offset
+#endif
+ .endm
+
+ENTRY(_start)
/*
- * Almost all Lantiq XWAY SoC devices have an external bus unit (EBU) to
- * access external NOR flashes. If the board boots from NOR flash the
- * internal BootROM does a blind read at address 0xB0000010 to read the
- * initial configuration for that EBU in order to access the flash
- * device with correct parameters. This config option is board-specific.
+ * U-Boot entry point.
+ * Do not add instructions to the branch delay slot! Some SoC's
+ * like Octeon might patch the final U-Boot binary at this location
+ * with additional boot headers.
*/
- .word CONFIG_SYS_XWAY_EBU_BOOTCFG
- .word 0x0
-#elif defined(CONFIG_MALTA)
+ b reset
+ nop
+
+#if defined(CONFIG_MIPS_INSERT_BOOT_CONFIG)
/*
- * Linux expects the Board ID here.
+ * Store some board-specific boot configuration. This is used by some
+ * MIPS systems like Malta.
*/
- .word 0x00000420 # 0x420 (Malta Board with CoreLV)
- .word 0x00000000
+ .org 0x10
+ .word CONFIG_MIPS_BOOT_CONFIG_WORD0
+ .word CONFIG_MIPS_BOOT_CONFIG_WORD1
#endif
+#if defined(CONFIG_ROM_EXCEPTION_VECTORS)
+ /*
+ * Exception vector entry points. When running from ROM, an exception
+ * cannot be handled. Halt execution and transfer control to debugger,
+ * if one is attached.
+ */
.org 0x200
/* TLB refill, 32 bit task */
-1: b 1b
- nop
+ uhi_mips_exception
.org 0x280
/* XTLB refill, 64 bit task */
-1: b 1b
- nop
+ uhi_mips_exception
.org 0x300
/* Cache error exception */
-1: b 1b
- nop
+ uhi_mips_exception
.org 0x380
/* General exception */
-1: b 1b
- nop
+ uhi_mips_exception
.org 0x400
/* Catch interrupt exceptions */
-1: b 1b
- nop
+ uhi_mips_exception
.org 0x480
/* EJTAG debug exception */
1: b 1b
nop
- .align 4
-reset:
+ .org 0x500
+#endif
- /* Clear watch registers */
- MTC0 zero, CP0_WATCHLO
- mtc0 zero, CP0_WATCHHI
+reset:
+ mtc0 zero, CP0_COUNT # clear cp0 count for most accurate boot timing
+#if __mips_isa_rev >= 6
+ mfc0 t0, CP0_CONFIG, 5
+ and t0, t0, MIPS_CONF5_VP
+ beqz t0, 1f
+ nop
- /* WP(Watch Pending), SW0/1 should be cleared */
- mtc0 zero, CP0_CAUSE
+ b 2f
+ mfc0 t0, CP0_GLOBALNUMBER
+#endif
- setup_c0_status STATUS_SET 0
+#ifdef CONFIG_ARCH_BMIPS
+1: mfc0 t0, CP0_DIAGNOSTIC, 3
+ and t0, t0, (1 << 31)
+#else
+1: mfc0 t0, CP0_EBASE
+ and t0, t0, MIPS_EBASE_CPUNUM
+#endif
- /* Init Timer */
- mtc0 zero, CP0_COUNT
- mtc0 zero, CP0_COMPARE
+ /* Hang if this isn't the first CPU in the system */
+2: beqz t0, 4f
+ nop
+3: wait
+ b 3b
+ nop
-#ifndef CONFIG_SKIP_LOWLEVEL_INIT
- /* CONFIG0 register */
- li t0, CONF_CM_UNCACHED
- mtc0 t0, CP0_CONFIG
-#endif
+ /* Init CP0 Status */
+4: mfc0 t0, CP0_STATUS
+ and t0, ST0_IMPL
+ or t0, ST0_BEV | ST0_ERL | STATUS_SET
+ mtc0 t0, CP0_STATUS
/*
- * Initialize $gp, force pointer sized alignment of bal instruction to
- * forbid the compiler to put nop's between bal and _gp. This is
- * required to keep _gp and ra aligned to 8 byte.
+ * Check whether CP0 Config1 is implemented. If not continue
+ * with legacy Watch register initialization.
*/
- .align PTRLOG
- bal 1f
+ mfc0 t0, CP0_CONFIG
+ bgez t0, wr_legacy
nop
- PTR _gp
-1:
- PTR_L gp, 0(ra)
-#ifndef CONFIG_SKIP_LOWLEVEL_INIT
- /* Initialize any external memory */
- PTR_LA t9, lowlevel_init
- jalr t9
+ /*
+ * Check WR bit in CP0 Config1 to determine if Watch registers
+ * are implemented.
+ */
+ mfc0 t0, CP0_CONFIG, 1
+ andi t0, (1 << 3)
+ beqz t0, wr_done
nop
- /* Initialize caches... */
- PTR_LA t9, mips_cache_reset
- jalr t9
+ /* Clear Watch Status bits and disable watch exceptions */
+ li t1, 0x7 # Clear I, R and W conditions
+ init_wr 0
+ init_wr 1
+ init_wr 2
+ init_wr 3
+ init_wr 4
+ init_wr 5
+ init_wr 6
+ init_wr 7
+ b wr_done
nop
- /* ... and enable them */
- li t0, CONFIG_SYS_MIPS_CACHE_MODE
- mtc0 t0, CP0_CONFIG
-#endif
+wr_legacy:
+ MTC0 zero, CP0_WATCHLO
+ mtc0 zero, CP0_WATCHHI
- /* Set up temporary stack */
- li t0, -16
- PTR_LI t1, CONFIG_SYS_INIT_SP_ADDR
- and sp, t1, t0 # force 16 byte alignment
- PTR_SUB sp, sp, GD_SIZE # reserve space for gd
- and sp, sp, t0 # force 16 byte alignment
- move k0, sp # save gd pointer
-#ifdef CONFIG_SYS_MALLOC_F_LEN
- li t2, CONFIG_SYS_MALLOC_F_LEN
- PTR_SUB sp, sp, t2 # reserve space for early malloc
- and sp, sp, t0 # force 16 byte alignment
-#endif
- move fp, sp
+wr_done:
+ /* Clear WP, IV and SW interrupts */
+ mtc0 zero, CP0_CAUSE
- /* Clear gd */
- move t0, k0
-1:
- PTR_S zero, 0(t0)
- blt t0, t1, 1b
- PTR_ADDI t0, PTRSIZE
+ /* Clear timer interrupt (CP0_COUNT cleared on branch to 'reset') */
+ mtc0 zero, CP0_COMPARE
-#ifdef CONFIG_SYS_MALLOC_F_LEN
- PTR_S sp, GD_MALLOC_BASE(k0) # gd->malloc_base offset
+#ifdef CONFIG_MIPS_CACHE_DISABLE
+ /* Disable caches */
+ PTR_LA t9, mips_cache_disable
+ jalr t9
+ nop
#endif
- move a0, zero # a0 <-- boot_flags = 0
- PTR_LA t9, board_init_f
- jr t9
- move ra, zero
-
- END(_start)
-
-/*
- * void relocate_code (addr_sp, gd, addr_moni)
- *
- * This "function" does not return, instead it continues in RAM
- * after relocating the monitor code.
- *
- * a0 = addr_sp
- * a1 = gd
- * a2 = destination address
- */
-ENTRY(relocate_code)
- move sp, a0 # set new stack pointer
- move fp, sp
-
- move s0, a1 # save gd in s0
- move s2, a2 # save destination address in s2
-
- 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
- move t1, a2
-
- PTR_ADD gp, s1 # adjust gp
-
- /*
- * t0 = source address
- * t1 = target address
- * t2 = source end address
- */
-1:
- PTR_L t3, 0(t0)
- PTR_S t3, 0(t1)
- PTR_ADDU t0, PTRSIZE
- 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
+#ifdef CONFIG_MIPS_CM
+ PTR_LA t9, mips_cm_map
jalr t9
- move a0, s2 # a0 <-- destination address
-
- /* Jump to where we've relocated ourselves */
- PTR_ADDI t0, s2, in_ram - _start
- jr t0
nop
+#endif
- PTR __rel_dyn_end
- PTR __rel_dyn_start
- PTR __image_copy_end
- PTR _GLOBAL_OFFSET_TABLE_
- PTR num_got_entries
+#ifdef CONFIG_MIPS_INIT_STACK_IN_SRAM
+#ifdef CONFIG_MIPS_SRAM_INIT
+ /* Initialize the SRAM first */
+ PTR_LA t9, mips_sram_init
+ jalr t9
+ nop
+#endif
-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_ADD t8, s1 # t8 now holds relocated _G_O_T_
- PTR_ADDI t8, t8, 2 * PTRSIZE # skipping first two entries
- PTR_LI t2, 2
-1:
- PTR_L t1, 0(t8)
- beqz t1, 2f
- PTR_ADD t1, s1
- PTR_S t1, 0(t8)
-2:
- PTR_ADDI t2, 1
- blt t2, t3, 1b
- PTR_ADDI 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
-
- b 2f # skip first reserved entry
- PTR_ADDI t1, 2 * PTRSIZE
+ /* Set up initial stack and global data */
+ setup_stack_gd
-1:
- lw t8, -4(t1) # t8 <-- relocation info
+# ifdef CONFIG_DEBUG_UART
+ /* Earliest point to set up debug uart */
+ PTR_LA t9, debug_uart_init
+ jalr t9
+ nop
+# endif
+#endif
- PTR_LI t3, MIPS_RELOC
- bne t8, t3, 2f # skip non-MIPS_RELOC entries
+#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
+#endif
- PTR_L t3, -(2 * PTRSIZE)(t1) # t3 <-- location to fix up in FLASH
+#ifdef CONFIG_MIPS_MACH_EARLY_INIT
+ bal mips_mach_early_init
+ nop
+#endif
- PTR_L t8, 0(t3) # t8 <-- original pointer
- PTR_ADD t8, s1 # t8 <-- adjusted pointer
+#ifdef CONFIG_MIPS_CACHE_SETUP
+ /* Initialize caches... */
+ PTR_LA t9, mips_cache_reset
+ jalr t9
+ nop
+#endif
- PTR_ADD t3, s1 # t3 <-- location to fix up in RAM
- PTR_S t8, 0(t3)
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+# ifndef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD
+ /* Initialize any external memory */
+ PTR_LA t9, lowlevel_init
+ jalr t9
+ nop
+# endif
+#endif
-2:
- blt t1, t2, 1b
- PTR_ADDI t1, 2 * PTRSIZE # each rel.dyn entry is 2*PTRSIZE bytes
+#ifndef CONFIG_MIPS_INIT_STACK_IN_SRAM
+ /* Set up initial stack and global data */
+ setup_stack_gd
- /*
- * Clear BSS
- *
- * GOT is now relocated. Thus __bss_start and __bss_end can be
- * accessed directly via $gp.
- */
- PTR_LA t1, __bss_start # t1 <-- __bss_start
- PTR_LA t2, __bss_end # t2 <-- __bss_end
+# ifdef CONFIG_DEBUG_UART
+ /* Earliest point to set up debug uart */
+ PTR_LA t9, debug_uart_init
+ jalr t9
+ nop
+# endif
+#endif
-1:
- PTR_S zero, 0(t1)
- blt t1, t2, 1b
- PTR_ADDI t1, PTRSIZE
+ move a0, zero # a0 <-- boot_flags = 0
+ PTR_LA t9, board_init_f
- move a0, s0 # a0 <-- gd
- move a1, s2
- PTR_LA t9, board_init_r
jr t9
move ra, zero
- END(relocate_code)
+ END(_start)