1 /* SPDX-License-Identifier: GPL-2.0+ */
3 * (C) Copyright 2007 Michal Simek
4 * (C) Copyright 2004 Atmark Techno, Inc.
6 * Michal SIMEK <monstr@monstr.eu>
7 * Yasushi SHOJI <yashi@atmark-techno.com>
10 #include <asm-offsets.h>
13 #define SYM_ADDR(reg, reg_add, symbol) \
15 addik r20, r20, _GLOBAL_OFFSET_TABLE_ + 8; \
16 lwi reg, r20, symbol@GOT; \
17 addk reg, reg reg_add;
22 mts rmsr, r0 /* disable cache */
29 #if defined(CONFIG_SPL_BUILD)
30 addi r1, r0, CONFIG_SPL_STACK
35 /* Force alignment for easier ASM code below */
36 #define ALIGNMENT_ADDR 0x20
51 lwi r7, r20, ALIGNMENT_ADDR
52 addi r7, r7, -CONFIG_TEXT_BASE
54 lwi r8, r20, ALIGNMENT_ADDR + 0x4
55 addi r8, r8, -CONFIG_TEXT_BASE
57 lwi r9, r20, ALIGNMENT_ADDR + 0x8
58 addi r9, r9, -CONFIG_TEXT_BASE
60 addi r10, r0, CONFIG_TEXT_BASE
62 brlid r15, mb_fix_rela
66 addi r1, r1, -4 /* Decrement SP to top of memory */
68 /* Call board_init_f_alloc_reserve with the current stack pointer as
71 brlid r15, board_init_f_alloc_reserve
74 /* board_init_f_alloc_reserve returns a pointer to the allocated area
75 * in r3. Set the new stack pointer below this area. */
80 /* Call board_init_f_init_reserve with the address returned by
81 * board_init_f_alloc_reserve as parameter. */
83 brlid r15, board_init_f_init_reserve
86 #if !defined(CONFIG_SPL_BUILD)
87 /* Setup vectors with pre-relocation symbols */
89 brlid r15, __setup_exceptions
94 * Initialize global data cpuinfo with default values (cache
95 * size, cache line size, etc).
97 brlid r15, microblaze_early_cpuinfo_init
100 /* Flush cache before enable cache */
101 brlid r15, flush_cache_all
104 /* enable instruction and data cache */
110 /* clear BSS segments */
111 SYM_ADDR(r5, r0, __bss_start)
112 SYM_ADDR(r4, r0, __bss_end)
116 swi r0, r5, 0 /* write zero to loc */
117 addi r5, r5, 4 /* increment to next loc */
118 cmp r6, r5, r4 /* check if we have reach the end */
120 3: /* jumping to board_init */
121 #ifdef CONFIG_DEBUG_UART
122 brlid r15, debug_uart_init
125 #ifndef CONFIG_SPL_BUILD
126 or r5, r0, r0 /* flags - empty */
133 #ifndef CONFIG_SPL_BUILD
135 .ent __setup_exceptions
138 * Set up reset, interrupt, user exception and hardware exception vectors.
141 * r5 - relocation offset (zero when setting up vectors before
142 * relocation, and gd->reloc_off when setting up vectors after
144 * - the relocation offset is added to the _exception_handler,
145 * _interrupt_handler and _hw_exception_handler symbols to reflect the
146 * post-relocation memory addresses
149 * r10: Stores little/big endian offset for vectors
150 * r2: Stores imm opcode
151 * r3: Stores brai opcode
152 * r4: Stores the vector base address
164 /* Find-out if u-boot is running on BIG/LITTLE endian platform
165 * There are some steps which is necessary to keep in mind:
166 * 1. Setup offset value to r6
167 * 2. Store word offset value to address 0x0
168 * 3. Load just byte from address 0x0
169 * 4a) LITTLE endian - r10 contains 0x2 because it is the smallest
170 * value that's why is on address 0x0
171 * 4b) BIG endian - r10 contains 0x0 because 0x2 offset is on addr 0x3
173 addik r6, r0, 0x2 /* BIG/LITTLE endian offset */
177 /* add opcode instruction for 32bit jump - 2 instruction imm & brai */
178 addi r2, r0, 0xb0000000 /* hex b000 opcode imm */
179 addi r3, r0, 0xb8080000 /* hew b808 opcode brai */
181 /* Store the vector base address in r4 */
182 addi r4, r0, CONFIG_XILINX_MICROBLAZE0_VECTOR_BASE_ADDR
185 swi r2, r4, 0x0 /* reset address - imm opcode */
186 swi r3, r4, 0x4 /* reset address - brai opcode */
188 SYM_ADDR(r6, r0, _start)
189 /* Intentionally keep reset vector back to origin u-boot location */
197 #if CONFIG_IS_ENABLED(XILINX_MICROBLAZE0_USR_EXCEP)
198 /* user_vector_exception */
199 swi r2, r4, 0x8 /* user vector exception - imm opcode */
200 swi r3, r4, 0xC /* user vector exception - brai opcode */
202 SYM_ADDR(r6, r5, _exception_handler)
205 * BIG ENDIAN memory map for user exception
209 * then it is necessary to count address for storing the most significant
210 * 16bits from _exception_handler address and copy it to
211 * 0xa address. Big endian use offset in r10=0 that's why is it just
212 * 0xa address. The same is done for the least significant 16 bits
215 * LITTLE ENDIAN memory map for user exception
219 * Offset is for little endian setup to 0x2. rsubi instruction decrease
220 * address value to ensure that points to proper place which is
221 * 0x8 for the most significant 16 bits and
222 * 0xC for the least significant 16 bits
231 /* interrupt_handler */
232 swi r2, r4, 0x10 /* interrupt - imm opcode */
233 swi r3, r4, 0x14 /* interrupt - brai opcode */
235 SYM_ADDR(r6, r5, _interrupt_handler)
243 /* hardware exception */
244 swi r2, r4, 0x20 /* hardware exception - imm opcode */
245 swi r3, r4, 0x24 /* hardware exception - brai opcode */
247 SYM_ADDR(r6, r5, _hw_exception_handler)
266 .end __setup_exceptions
272 .global relocate_code
281 addi r1, r5, 0 /* Start to use new SP */
283 addi r31, r6, 0 /* Start to use new GD */
285 /* Relocate text and data - r12 temp value */
286 SYM_ADDR(r21, r0, _start)
287 SYM_ADDR(r22, r0, _end) /* Include BSS too */
292 1: lw r12, r21, r5 /* Load u-boot data */
293 sw r12, r7, r5 /* Write zero to loc */
294 cmp r12, r5, r6 /* Check if we have reach the end */
296 addi r5, r5, 4 /* Increment to next loc - relocate code */
298 /* R23 points to the base address. */
299 rsub r23, r21, r7 /* keep - this is already here gd->reloc_off */
301 /* Setup vectors with post-relocation symbols */
302 add r5, r0, r23 /* load gd->reloc_off to r5 */
303 brlid r15, __setup_exceptions
306 /* reloc_offset is current location */
307 SYM_ADDR(r10, r0, _start)
309 /* r5 new address where I should copy code */
310 add r5, r0, r7 /* Move reloc addr to r5 */
312 /* Verbose message */
315 SYM_ADDR(r7, r0, __rel_dyn_start)
318 SYM_ADDR(r8, r0, __rel_dyn_end)
321 SYM_ADDR(r9, r0, __dyn_sym_start)
324 brlid r15, mb_fix_rela
326 /* end of code which does relocation */
328 /* Flush caches to ensure consistency */
329 brlid r15, flush_cache_all
332 2: addi r5, r31, 0 /* gd is initialized in board_r.c */
333 SYM_ADDR(r6, r0, _start)
334 SYM_ADDR(r12, r23, board_init_r)
335 bra r12 /* Jump to relocated code */