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