1/* 2 * Startup Code for MIPS32 CPU-core 3 * 4 * Copyright (c) 2003 Wolfgang Denk <wd@denx.de> 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9#include <asm-offsets.h> 10#include <config.h> 11#include <asm/asm.h> 12#include <asm/regdef.h> 13#include <asm/mipsregs.h> 14 15#ifndef CONFIG_SYS_INIT_SP_ADDR 16#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + \ 17 CONFIG_SYS_INIT_SP_OFFSET) 18#endif 19 20#ifdef CONFIG_32BIT 21# define MIPS_RELOC 3 22# define STATUS_SET 0 23#endif 24 25#ifdef CONFIG_64BIT 26# ifdef CONFIG_SYS_LITTLE_ENDIAN 27# define MIPS64_R_INFO(ssym, r_type3, r_type2, r_type) \ 28 (((r_type) << 24) | ((r_type2) << 16) | ((r_type3) << 8) | (ssym)) 29# else 30# define MIPS64_R_INFO(ssym, r_type3, r_type2, r_type) \ 31 ((r_type) | ((r_type2) << 8) | ((r_type3) << 16) | (ssym) << 24) 32# endif 33# define MIPS_RELOC MIPS64_R_INFO(0x00, 0x00, 0x12, 0x03) 34# define STATUS_SET ST0_KX 35#endif 36 37 .set noreorder 38 39 .macro init_wr sel 40 MTC0 zero, CP0_WATCHLO,\sel 41 mtc0 t1, CP0_WATCHHI,\sel 42 mfc0 t0, CP0_WATCHHI,\sel 43 bgez t0, wr_done 44 nop 45 .endm 46 47 .macro uhi_mips_exception 48 move k0, t9 # preserve t9 in k0 49 move k1, a0 # preserve a0 in k1 50 li t9, 15 # UHI exception operation 51 li a0, 0 # Use hard register context 52 sdbbp 1 # Invoke UHI operation 53 .endm 54 55ENTRY(_start) 56 /* U-Boot entry point */ 57 b reset 58 mtc0 zero, CP0_COUNT # clear cp0 count for most accurate boot timing 59 60#if defined(CONFIG_SYS_XWAY_EBU_BOOTCFG) 61 /* 62 * Almost all Lantiq XWAY SoC devices have an external bus unit (EBU) to 63 * access external NOR flashes. If the board boots from NOR flash the 64 * internal BootROM does a blind read at address 0xB0000010 to read the 65 * initial configuration for that EBU in order to access the flash 66 * device with correct parameters. This config option is board-specific. 67 */ 68 .org 0x10 69 .word CONFIG_SYS_XWAY_EBU_BOOTCFG 70 .word 0x0 71#endif 72#if defined(CONFIG_MALTA) 73 /* 74 * Linux expects the Board ID here. 75 */ 76 .org 0x10 77 .word 0x00000420 # 0x420 (Malta Board with CoreLV) 78 .word 0x00000000 79#endif 80 81#if defined(CONFIG_ROM_EXCEPTION_VECTORS) 82 /* 83 * Exception vector entry points. When running from ROM, an exception 84 * cannot be handled. Halt execution and transfer control to debugger, 85 * if one is attached. 86 */ 87 .org 0x200 88 /* TLB refill, 32 bit task */ 89 uhi_mips_exception 90 91 .org 0x280 92 /* XTLB refill, 64 bit task */ 93 uhi_mips_exception 94 95 .org 0x300 96 /* Cache error exception */ 97 uhi_mips_exception 98 99 .org 0x380 100 /* General exception */ 101 uhi_mips_exception 102 103 .org 0x400 104 /* Catch interrupt exceptions */ 105 uhi_mips_exception 106 107 .org 0x480 108 /* EJTAG debug exception */ 1091: b 1b 110 nop 111 112 .org 0x500 113#endif 114 115reset: 116#if __mips_isa_rev >= 6 117 mfc0 t0, CP0_CONFIG, 5 118 and t0, t0, MIPS_CONF5_VP 119 beqz t0, 1f 120 nop 121 122 b 2f 123 mfc0 t0, CP0_GLOBALNUMBER 124#endif 125 1261: mfc0 t0, CP0_EBASE 127 and t0, t0, EBASE_CPUNUM 128 129 /* Hang if this isn't the first CPU in the system */ 1302: beqz t0, 4f 131 nop 1323: wait 133 b 3b 134 nop 135 136 /* Init CP0 Status */ 1374: mfc0 t0, CP0_STATUS 138 and t0, ST0_IMPL 139 or t0, ST0_BEV | ST0_ERL | STATUS_SET 140 mtc0 t0, CP0_STATUS 141 142 /* 143 * Check whether CP0 Config1 is implemented. If not continue 144 * with legacy Watch register initialization. 145 */ 146 mfc0 t0, CP0_CONFIG 147 bgez t0, wr_legacy 148 nop 149 150 /* 151 * Check WR bit in CP0 Config1 to determine if Watch registers 152 * are implemented. 153 */ 154 mfc0 t0, CP0_CONFIG, 1 155 andi t0, (1 << 3) 156 beqz t0, wr_done 157 nop 158 159 /* Clear Watch Status bits and disable watch exceptions */ 160 li t1, 0x7 # Clear I, R and W conditions 161 init_wr 0 162 init_wr 1 163 init_wr 2 164 init_wr 3 165 init_wr 4 166 init_wr 5 167 init_wr 6 168 init_wr 7 169 b wr_done 170 nop 171 172wr_legacy: 173 MTC0 zero, CP0_WATCHLO 174 mtc0 zero, CP0_WATCHHI 175 176wr_done: 177 /* Clear WP, IV and SW interrupts */ 178 mtc0 zero, CP0_CAUSE 179 180 /* Clear timer interrupt (CP0_COUNT cleared on branch to 'reset') */ 181 mtc0 zero, CP0_COMPARE 182 183#ifndef CONFIG_SKIP_LOWLEVEL_INIT 184 mfc0 t0, CP0_CONFIG 185 and t0, t0, MIPS_CONF_IMPL 186 or t0, t0, CONF_CM_UNCACHED 187 mtc0 t0, CP0_CONFIG 188 ehb 189#endif 190 191 /* 192 * Initialize $gp, force pointer sized alignment of bal instruction to 193 * forbid the compiler to put nop's between bal and _gp. This is 194 * required to keep _gp and ra aligned to 8 byte. 195 */ 196 .align PTRLOG 197 bal 1f 198 nop 199 PTR _gp 2001: 201 PTR_L gp, 0(ra) 202 203#ifdef CONFIG_MIPS_CM 204 PTR_LA t9, mips_cm_map 205 jalr t9 206 nop 207#endif 208 209#ifndef CONFIG_SKIP_LOWLEVEL_INIT 210# ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD 211 /* Initialize any external memory */ 212 PTR_LA t9, lowlevel_init 213 jalr t9 214 nop 215# endif 216 217 /* Initialize caches... */ 218 PTR_LA t9, mips_cache_reset 219 jalr t9 220 nop 221 222# ifndef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD 223 /* Initialize any external memory */ 224 PTR_LA t9, lowlevel_init 225 jalr t9 226 nop 227# endif 228#endif 229 230 /* Set up temporary stack */ 231 li t0, -16 232 PTR_LI t1, CONFIG_SYS_INIT_SP_ADDR 233 and sp, t1, t0 # force 16 byte alignment 234 PTR_SUBU \ 235 sp, sp, GD_SIZE # reserve space for gd 236 and sp, sp, t0 # force 16 byte alignment 237 move k0, sp # save gd pointer 238#ifdef CONFIG_SYS_MALLOC_F_LEN 239 li t2, CONFIG_SYS_MALLOC_F_LEN 240 PTR_SUBU \ 241 sp, sp, t2 # reserve space for early malloc 242 and sp, sp, t0 # force 16 byte alignment 243#endif 244 move fp, sp 245 246 /* Clear gd */ 247 move t0, k0 2481: 249 PTR_S zero, 0(t0) 250 blt t0, t1, 1b 251 PTR_ADDIU t0, PTRSIZE 252 253#ifdef CONFIG_SYS_MALLOC_F_LEN 254 PTR_S sp, GD_MALLOC_BASE(k0) # gd->malloc_base offset 255#endif 256 257 move a0, zero # a0 <-- boot_flags = 0 258 PTR_LA t9, board_init_f 259 260 jr t9 261 move ra, zero 262 263 END(_start) 264 265/* 266 * void relocate_code (addr_sp, gd, addr_moni) 267 * 268 * This "function" does not return, instead it continues in RAM 269 * after relocating the monitor code. 270 * 271 * a0 = addr_sp 272 * a1 = gd 273 * a2 = destination address 274 */ 275ENTRY(relocate_code) 276 move sp, a0 # set new stack pointer 277 move fp, sp 278 279 move s0, a1 # save gd in s0 280 move s2, a2 # save destination address in s2 281 282 PTR_LI t0, CONFIG_SYS_MONITOR_BASE 283 PTR_SUB s1, s2, t0 # s1 <-- relocation offset 284 285 PTR_LA t2, __image_copy_end 286 move t1, a2 287 288 /* 289 * t0 = source address 290 * t1 = target address 291 * t2 = source end address 292 */ 2931: 294 PTR_L t3, 0(t0) 295 PTR_S t3, 0(t1) 296 PTR_ADDU t0, PTRSIZE 297 blt t0, t2, 1b 298 PTR_ADDU t1, PTRSIZE 299 300 /* 301 * Now we want to update GOT. 302 * 303 * GOT[0] is reserved. GOT[1] is also reserved for the dynamic object 304 * generated by GNU ld. Skip these reserved entries from relocation. 305 */ 306 PTR_LA t3, num_got_entries 307 PTR_LA t8, _GLOBAL_OFFSET_TABLE_ 308 PTR_ADD t8, s1 # t8 now holds relocated _G_O_T_ 309 PTR_ADDIU t8, t8, 2 * PTRSIZE # skipping first two entries 310 PTR_LI t2, 2 3111: 312 PTR_L t1, 0(t8) 313 beqz t1, 2f 314 PTR_ADD t1, s1 315 PTR_S t1, 0(t8) 3162: 317 PTR_ADDIU t2, 1 318 blt t2, t3, 1b 319 PTR_ADDIU t8, PTRSIZE 320 321 /* Update dynamic relocations */ 322 PTR_LA t1, __rel_dyn_start 323 PTR_LA t2, __rel_dyn_end 324 325 b 2f # skip first reserved entry 326 PTR_ADDIU t1, 2 * PTRSIZE 327 3281: 329 lw t8, -4(t1) # t8 <-- relocation info 330 331 PTR_LI t3, MIPS_RELOC 332 bne t8, t3, 2f # skip non-MIPS_RELOC entries 333 nop 334 335 PTR_L t3, -(2 * PTRSIZE)(t1) # t3 <-- location to fix up in FLASH 336 337 PTR_L t8, 0(t3) # t8 <-- original pointer 338 PTR_ADD t8, s1 # t8 <-- adjusted pointer 339 340 PTR_ADD t3, s1 # t3 <-- location to fix up in RAM 341 PTR_S t8, 0(t3) 342 3432: 344 blt t1, t2, 1b 345 PTR_ADDIU t1, 2 * PTRSIZE # each rel.dyn entry is 2*PTRSIZE bytes 346 347 /* 348 * Flush caches to ensure our newly modified instructions are visible 349 * to the instruction cache. We're still running with the old GOT, so 350 * apply the reloc offset to the start address. 351 */ 352 PTR_LA a0, __text_start 353 PTR_LA a1, __text_end 354 PTR_SUB a1, a1, a0 355 PTR_LA t9, flush_cache 356 jalr t9 357 PTR_ADD a0, s1 358 359 PTR_ADD gp, s1 # adjust gp 360 361 /* 362 * Clear BSS 363 * 364 * GOT is now relocated. Thus __bss_start and __bss_end can be 365 * accessed directly via $gp. 366 */ 367 PTR_LA t1, __bss_start # t1 <-- __bss_start 368 PTR_LA t2, __bss_end # t2 <-- __bss_end 369 3701: 371 PTR_S zero, 0(t1) 372 blt t1, t2, 1b 373 PTR_ADDIU t1, PTRSIZE 374 375 move a0, s0 # a0 <-- gd 376 move a1, s2 377 PTR_LA t9, board_init_r 378 jr t9 379 move ra, zero 380 381 END(relocate_code) 382