1/* 2 * (C) Copyright 2007 Michal Simek 3 * (C) Copyright 2004 Atmark Techno, Inc. 4 * 5 * Michal SIMEK <monstr@monstr.eu> 6 * Yasushi SHOJI <yashi@atmark-techno.com> 7 * 8 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 11#include <asm-offsets.h> 12#include <config.h> 13 14 .text 15 .global _start 16_start: 17 /* 18 * reserve registers: 19 * r10: Stores little/big endian offset for vectors 20 * r2: Stores imm opcode 21 * r3: Stores brai opcode 22 */ 23 24 mts rmsr, r0 /* disable cache */ 25 26 addi r8, r0, __end 27 mts rslr, r8 28#if defined(CONFIG_SPL_BUILD) 29 addi r1, r0, CONFIG_SPL_STACK_ADDR 30 mts rshr, r1 31 addi r1, r1, -4 /* Decrement SP to top of memory */ 32#else 33 addi r1, r0, CONFIG_SYS_INIT_SP_OFFSET 34 mts rshr, r1 35 addi r1, r1, -4 /* Decrement SP to top of memory */ 36 37 /* Find-out if u-boot is running on BIG/LITTLE endian platform 38 * There are some steps which is necessary to keep in mind: 39 * 1. Setup offset value to r6 40 * 2. Store word offset value to address 0x0 41 * 3. Load just byte from address 0x0 42 * 4a) LITTLE endian - r10 contains 0x2 because it is the smallest 43 * value that's why is on address 0x0 44 * 4b) BIG endian - r10 contains 0x0 because 0x2 offset is on addr 0x3 45 */ 46 addik r6, r0, 0x2 /* BIG/LITTLE endian offset */ 47 lwi r7, r0, 0x28 48 swi r6, r0, 0x28 /* used first unused MB vector */ 49 lbui r10, r0, 0x28 /* used first unused MB vector */ 50 swi r7, r0, 0x28 51 52 /* add opcode instruction for 32bit jump - 2 instruction imm & brai */ 53 addi r2, r0, 0xb0000000 /* hex b000 opcode imm */ 54 addi r3, r0, 0xb8080000 /* hew b808 opcode brai */ 55 56#ifdef CONFIG_SYS_RESET_ADDRESS 57 /* reset address */ 58 swi r2, r0, 0x0 /* reset address - imm opcode */ 59 swi r3, r0, 0x4 /* reset address - brai opcode */ 60 61 addik r6, r0, CONFIG_SYS_RESET_ADDRESS 62 sw r6, r1, r0 63 lhu r7, r1, r10 64 rsubi r8, r10, 0x2 65 sh r7, r0, r8 66 rsubi r8, r10, 0x6 67 sh r6, r0, r8 68#endif 69 70#ifdef CONFIG_SYS_USR_EXCEP 71 /* user_vector_exception */ 72 swi r2, r0, 0x8 /* user vector exception - imm opcode */ 73 swi r3, r0, 0xC /* user vector exception - brai opcode */ 74 75 addik r6, r0, _exception_handler 76 sw r6, r1, r0 77 /* 78 * BIG ENDIAN memory map for user exception 79 * 0x8: 0xB000XXXX 80 * 0xC: 0xB808XXXX 81 * 82 * then it is necessary to count address for storing the most significant 83 * 16bits from _exception_handler address and copy it to 84 * 0xa address. Big endian use offset in r10=0 that's why is it just 85 * 0xa address. The same is done for the least significant 16 bits 86 * for 0xe address. 87 * 88 * LITTLE ENDIAN memory map for user exception 89 * 0x8: 0xXXXX00B0 90 * 0xC: 0xXXXX08B8 91 * 92 * Offset is for little endian setup to 0x2. rsubi instruction decrease 93 * address value to ensure that points to proper place which is 94 * 0x8 for the most significant 16 bits and 95 * 0xC for the least significant 16 bits 96 */ 97 lhu r7, r1, r10 98 rsubi r8, r10, 0xa 99 sh r7, r0, r8 100 rsubi r8, r10, 0xe 101 sh r6, r0, r8 102#endif 103 104 /* interrupt_handler */ 105 swi r2, r0, 0x10 /* interrupt - imm opcode */ 106 swi r3, r0, 0x14 /* interrupt - brai opcode */ 107 108 addik r6, r0, _interrupt_handler 109 sw r6, r1, r0 110 lhu r7, r1, r10 111 rsubi r8, r10, 0x12 112 sh r7, r0, r8 113 rsubi r8, r10, 0x16 114 sh r6, r0, r8 115 116 /* hardware exception */ 117 swi r2, r0, 0x20 /* hardware exception - imm opcode */ 118 swi r3, r0, 0x24 /* hardware exception - brai opcode */ 119 120 addik r6, r0, _hw_exception_handler 121 sw r6, r1, r0 122 lhu r7, r1, r10 123 rsubi r8, r10, 0x22 124 sh r7, r0, r8 125 rsubi r8, r10, 0x26 126 sh r6, r0, r8 127#endif /* BUILD_SPL */ 128 129 /* Flush cache before enable cache */ 130 addik r5, r0, 0 131 addik r6, r0, XILINX_DCACHE_BYTE_SIZE 132 bralid r15, flush_cache 133 nop 134 135 /* enable instruction and data cache */ 136 mfs r12, rmsr 137 ori r12, r12, 0x1a0 138 mts rmsr, r12 139 140clear_bss: 141 /* clear BSS segments */ 142 addi r5, r0, __bss_start 143 addi r4, r0, __bss_end 144 cmp r6, r5, r4 145 beqi r6, 3f 1462: 147 swi r0, r5, 0 /* write zero to loc */ 148 addi r5, r5, 4 /* increment to next loc */ 149 cmp r6, r5, r4 /* check if we have reach the end */ 150 bnei r6, 2b 1513: /* jumping to board_init */ 152#ifndef CONFIG_SPL_BUILD 153 or r5, r0, r0 /* flags - empty */ 154 addi r31, r0, _gd 155 brai board_init_f 156#else 157 addi r31, r0, CONFIG_SYS_SPL_MALLOC_END 158 brai board_init_r 159#endif 1601: bri 1b 161 162 .section .bss 163.align 4 164_gd: 165 .space GENERATED_GBL_DATA_SIZE 166 167#ifndef CONFIG_SPL_BUILD 168/* 169 * Read 16bit little endian 170 */ 171 .text 172 .global in16 173 .ent in16 174 .align 2 175in16: lhu r3, r0, r5 176 bslli r4, r3, 8 177 bsrli r3, r3, 8 178 andi r4, r4, 0xffff 179 or r3, r3, r4 180 rtsd r15, 8 181 sext16 r3, r3 182 .end in16 183 184/* 185 * Write 16bit little endian 186 * first parameter(r5) - address, second(r6) - short value 187 */ 188 .text 189 .global out16 190 .ent out16 191 .align 2 192out16: bslli r3, r6, 8 193 bsrli r6, r6, 8 194 andi r3, r3, 0xffff 195 or r3, r3, r6 196 sh r3, r0, r5 197 rtsd r15, 8 198 or r0, r0, r0 199 .end out16 200 201/* 202 * Relocate u-boot 203 */ 204 .text 205 .global relocate_code 206 .ent relocate_code 207 .align 2 208relocate_code: 209 /* 210 * r5 - start_addr_sp 211 * r6 - new_gd 212 * r7 - reloc_addr 213 */ 214 addi r1, r5, 0 /* Start to use new SP */ 215 addi r31, r6, 0 /* Start to use new GD */ 216 217 add r23, r0, r7 /* Move reloc addr to r23 */ 218 /* Relocate text and data - r12 temp value */ 219 addi r21, r0, _start 220 addi r22, r0, __end - 4 /* Include BSS too */ 221 222 rsub r6, r21, r22 223 or r5, r0, r0 2241: lw r12, r21, r5 /* Load u-boot data */ 225 sw r12, r23, r5 /* Write zero to loc */ 226 cmp r12, r5, r6 /* Check if we have reach the end */ 227 bneid r12, 1b 228 addi r5, r5, 4 /* Increment to next loc - relocate code */ 229 230 /* R23 points to the base address. */ 231 add r23, r0, r7 /* Move reloc addr to r23 */ 232 addi r24, r0, CONFIG_SYS_TEXT_BASE /* Get reloc offset */ 233 rsub r23, r24, r23 /* keep - this is already here gd->reloc_off */ 234 235 addik r6, r0, 0x2 /* BIG/LITTLE endian offset */ 236 lwi r7, r0, 0x28 237 swi r6, r0, 0x28 /* used first unused MB vector */ 238 lbui r10, r0, 0x28 /* used first unused MB vector */ 239 swi r7, r0, 0x28 240 241#ifdef CONFIG_SYS_USR_EXCEP 242 addik r6, r0, _exception_handler 243 addk r6, r6, r23 /* add offset */ 244 sw r6, r1, r0 245 lhu r7, r1, r10 246 rsubi r8, r10, 0xa 247 sh r7, r0, r8 248 rsubi r8, r10, 0xe 249 sh r6, r0, r8 250#endif 251 addik r6, r0, _hw_exception_handler 252 addk r6, r6, r23 /* add offset */ 253 sw r6, r1, r0 254 lhu r7, r1, r10 255 rsubi r8, r10, 0x22 256 sh r7, r0, r8 257 rsubi r8, r10, 0x26 258 sh r6, r0, r8 259 260 addik r6, r0, _interrupt_handler 261 addk r6, r6, r23 /* add offset */ 262 sw r6, r1, r0 263 lhu r7, r1, r10 264 rsubi r8, r10, 0x12 265 sh r7, r0, r8 266 rsubi r8, r10, 0x16 267 sh r6, r0, r8 268 269 /* Check if GOT exist */ 270 addik r21, r23, _got_start 271 addik r22, r23, _got_end 272 cmpu r12, r21, r22 273 beqi r12, 2f /* No GOT table - jump over */ 274 275 /* Skip last 3 entries plus 1 because of loop boundary below */ 276 addik r22, r22, -0x10 277 278 /* Relocate the GOT. */ 2793: lw r12, r21, r0 /* Load entry */ 280 addk r12, r12, r23 /* Add reloc offset */ 281 sw r12, r21, r0 /* Save entry back */ 282 283 cmpu r12, r21, r22 /* Check if this cross boundary */ 284 bneid r12, 3b 285 addik r21. r21, 4 286 287 /* Update pointer to GOT */ 288 mfs r20, rpc 289 addik r20, r20, _GLOBAL_OFFSET_TABLE_ + 8 290 addk r20, r20, r23 291 292 /* Flush caches to ensure consistency */ 293 addik r5, r0, 0 294 addik r6, r0, XILINX_DCACHE_BYTE_SIZE 295 bralid r15, flush_cache 296 nop 297 2982: addi r5, r31, 0 /* gd is initialized in board_r.c */ 299 addi r6, r0, CONFIG_SYS_TEXT_BASE 300 addi r12, r23, board_init_r 301 bra r12 /* Jump to relocated code */ 302 303 .end relocate_code 304#endif 305