16260fb04SPeter Tyser/* 26260fb04SPeter Tyser * (C) Copyright 2007 Michal Simek 36260fb04SPeter Tyser * (C) Copyright 2004 Atmark Techno, Inc. 46260fb04SPeter Tyser * 56260fb04SPeter Tyser * Michal SIMEK <monstr@monstr.eu> 66260fb04SPeter Tyser * Yasushi SHOJI <yashi@atmark-techno.com> 76260fb04SPeter Tyser * 81a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 96260fb04SPeter Tyser */ 106260fb04SPeter Tyser 1125ddd1fbSWolfgang Denk#include <asm-offsets.h> 126260fb04SPeter Tyser#include <config.h> 136260fb04SPeter Tyser 146260fb04SPeter Tyser .text 156260fb04SPeter Tyser .global _start 166260fb04SPeter Tyser_start: 1786c1b2a8SMichal Simek /* 1886c1b2a8SMichal Simek * reserve registers: 1986c1b2a8SMichal Simek * r10: Stores little/big endian offset for vectors 2086c1b2a8SMichal Simek * r2: Stores imm opcode 2186c1b2a8SMichal Simek * r3: Stores brai opcode 2286c1b2a8SMichal Simek */ 2386c1b2a8SMichal Simek 246260fb04SPeter Tyser mts rmsr, r0 /* disable cache */ 259d242745SMichal Simek 26da931af1SMichal Simek addi r8, r0, __end 27da931af1SMichal Simek mts rslr, r8 28*ecc30663SAlbert ARIBAUD /* TODO: Redo this code to call board_init_f_*() */ 299d242745SMichal Simek#if defined(CONFIG_SPL_BUILD) 309d242745SMichal Simek addi r1, r0, CONFIG_SPL_STACK_ADDR 31da931af1SMichal Simek mts rshr, r1 329d242745SMichal Simek addi r1, r1, -4 /* Decrement SP to top of memory */ 339d242745SMichal Simek#else 34405e651dSMichal Simek#if defined(CONFIG_SYS_MALLOC_F_LEN) 35405e651dSMichal Simek addi r1, r0, CONFIG_SYS_INIT_SP_OFFSET - CONFIG_SYS_MALLOC_F_LEN 36405e651dSMichal Simek#else 376260fb04SPeter Tyser addi r1, r0, CONFIG_SYS_INIT_SP_OFFSET 38405e651dSMichal Simek#endif 39da931af1SMichal Simek mts rshr, r1 406260fb04SPeter Tyser addi r1, r1, -4 /* Decrement SP to top of memory */ 41b98cba09SMichal Simek 42b98cba09SMichal Simek /* Find-out if u-boot is running on BIG/LITTLE endian platform 43b98cba09SMichal Simek * There are some steps which is necessary to keep in mind: 44b98cba09SMichal Simek * 1. Setup offset value to r6 45b98cba09SMichal Simek * 2. Store word offset value to address 0x0 46b98cba09SMichal Simek * 3. Load just byte from address 0x0 47b98cba09SMichal Simek * 4a) LITTLE endian - r10 contains 0x2 because it is the smallest 48b98cba09SMichal Simek * value that's why is on address 0x0 49b98cba09SMichal Simek * 4b) BIG endian - r10 contains 0x0 because 0x2 offset is on addr 0x3 50b98cba09SMichal Simek */ 51b98cba09SMichal Simek addik r6, r0, 0x2 /* BIG/LITTLE endian offset */ 52f3090fceSMichal Simek lwi r7, r0, 0x28 53f3090fceSMichal Simek swi r6, r0, 0x28 /* used first unused MB vector */ 54f3090fceSMichal Simek lbui r10, r0, 0x28 /* used first unused MB vector */ 55f3090fceSMichal Simek swi r7, r0, 0x28 56b98cba09SMichal Simek 576260fb04SPeter Tyser /* add opcode instruction for 32bit jump - 2 instruction imm & brai */ 5886c1b2a8SMichal Simek addi r2, r0, 0xb0000000 /* hex b000 opcode imm */ 5986c1b2a8SMichal Simek addi r3, r0, 0xb8080000 /* hew b808 opcode brai */ 606260fb04SPeter Tyser 616260fb04SPeter Tyser#ifdef CONFIG_SYS_RESET_ADDRESS 626260fb04SPeter Tyser /* reset address */ 6386c1b2a8SMichal Simek swi r2, r0, 0x0 /* reset address - imm opcode */ 6486c1b2a8SMichal Simek swi r3, r0, 0x4 /* reset address - brai opcode */ 6586c1b2a8SMichal Simek 666260fb04SPeter Tyser addik r6, r0, CONFIG_SYS_RESET_ADDRESS 676260fb04SPeter Tyser sw r6, r1, r0 685562bcc2SMichal Simek lhu r7, r1, r10 695562bcc2SMichal Simek rsubi r8, r10, 0x2 705562bcc2SMichal Simek sh r7, r0, r8 715562bcc2SMichal Simek rsubi r8, r10, 0x6 725562bcc2SMichal Simek sh r6, r0, r8 736260fb04SPeter Tyser#endif 746260fb04SPeter Tyser 756260fb04SPeter Tyser#ifdef CONFIG_SYS_USR_EXCEP 766260fb04SPeter Tyser /* user_vector_exception */ 7786c1b2a8SMichal Simek swi r2, r0, 0x8 /* user vector exception - imm opcode */ 7886c1b2a8SMichal Simek swi r3, r0, 0xC /* user vector exception - brai opcode */ 7986c1b2a8SMichal Simek 806260fb04SPeter Tyser addik r6, r0, _exception_handler 816260fb04SPeter Tyser sw r6, r1, r0 82b98cba09SMichal Simek /* 83b98cba09SMichal Simek * BIG ENDIAN memory map for user exception 84b98cba09SMichal Simek * 0x8: 0xB000XXXX 85b98cba09SMichal Simek * 0xC: 0xB808XXXX 86b98cba09SMichal Simek * 87b98cba09SMichal Simek * then it is necessary to count address for storing the most significant 88b98cba09SMichal Simek * 16bits from _exception_handler address and copy it to 89b98cba09SMichal Simek * 0xa address. Big endian use offset in r10=0 that's why is it just 90b98cba09SMichal Simek * 0xa address. The same is done for the least significant 16 bits 91b98cba09SMichal Simek * for 0xe address. 92b98cba09SMichal Simek * 93b98cba09SMichal Simek * LITTLE ENDIAN memory map for user exception 94b98cba09SMichal Simek * 0x8: 0xXXXX00B0 95b98cba09SMichal Simek * 0xC: 0xXXXX08B8 96b98cba09SMichal Simek * 97b98cba09SMichal Simek * Offset is for little endian setup to 0x2. rsubi instruction decrease 98b98cba09SMichal Simek * address value to ensure that points to proper place which is 99b98cba09SMichal Simek * 0x8 for the most significant 16 bits and 100b98cba09SMichal Simek * 0xC for the least significant 16 bits 101b98cba09SMichal Simek */ 102b98cba09SMichal Simek lhu r7, r1, r10 103b98cba09SMichal Simek rsubi r8, r10, 0xa 104b98cba09SMichal Simek sh r7, r0, r8 105b98cba09SMichal Simek rsubi r8, r10, 0xe 106b98cba09SMichal Simek sh r6, r0, r8 1076260fb04SPeter Tyser#endif 1086260fb04SPeter Tyser 1096260fb04SPeter Tyser /* interrupt_handler */ 11086c1b2a8SMichal Simek swi r2, r0, 0x10 /* interrupt - imm opcode */ 11186c1b2a8SMichal Simek swi r3, r0, 0x14 /* interrupt - brai opcode */ 11286c1b2a8SMichal Simek 1136260fb04SPeter Tyser addik r6, r0, _interrupt_handler 1146260fb04SPeter Tyser sw r6, r1, r0 115b98cba09SMichal Simek lhu r7, r1, r10 116b98cba09SMichal Simek rsubi r8, r10, 0x12 117b98cba09SMichal Simek sh r7, r0, r8 118b98cba09SMichal Simek rsubi r8, r10, 0x16 119b98cba09SMichal Simek sh r6, r0, r8 1206260fb04SPeter Tyser 1216260fb04SPeter Tyser /* hardware exception */ 12286c1b2a8SMichal Simek swi r2, r0, 0x20 /* hardware exception - imm opcode */ 12386c1b2a8SMichal Simek swi r3, r0, 0x24 /* hardware exception - brai opcode */ 12486c1b2a8SMichal Simek 1256260fb04SPeter Tyser addik r6, r0, _hw_exception_handler 1266260fb04SPeter Tyser sw r6, r1, r0 127b98cba09SMichal Simek lhu r7, r1, r10 128b98cba09SMichal Simek rsubi r8, r10, 0x22 129b98cba09SMichal Simek sh r7, r0, r8 130b98cba09SMichal Simek rsubi r8, r10, 0x26 131b98cba09SMichal Simek sh r6, r0, r8 1329d242745SMichal Simek#endif /* BUILD_SPL */ 1336260fb04SPeter Tyser 1345811830fSMichal Simek /* Flush cache before enable cache */ 1355811830fSMichal Simek addik r5, r0, 0 1365811830fSMichal Simek addik r6, r0, XILINX_DCACHE_BYTE_SIZE 137e4a4743eSMichal Simek bralid r15, flush_cache 1385811830fSMichal Simek nop 1395811830fSMichal Simek 1406260fb04SPeter Tyser /* enable instruction and data cache */ 1416260fb04SPeter Tyser mfs r12, rmsr 142822d43a6SMichal Simek ori r12, r12, 0x1a0 1436260fb04SPeter Tyser mts rmsr, r12 1446260fb04SPeter Tyser 145*ecc30663SAlbert ARIBAUD /* TODO: Redo this code to call board_init_f_*() */ 1466260fb04SPeter Tyserclear_bss: 1476260fb04SPeter Tyser /* clear BSS segments */ 1486260fb04SPeter Tyser addi r5, r0, __bss_start 1496260fb04SPeter Tyser addi r4, r0, __bss_end 1506260fb04SPeter Tyser cmp r6, r5, r4 1516260fb04SPeter Tyser beqi r6, 3f 1526260fb04SPeter Tyser2: 1536260fb04SPeter Tyser swi r0, r5, 0 /* write zero to loc */ 1546260fb04SPeter Tyser addi r5, r5, 4 /* increment to next loc */ 1556260fb04SPeter Tyser cmp r6, r5, r4 /* check if we have reach the end */ 1566260fb04SPeter Tyser bnei r6, 2b 1576260fb04SPeter Tyser3: /* jumping to board_init */ 1589d242745SMichal Simek#ifndef CONFIG_SPL_BUILD 159e945f6dcSMichal Simek or r5, r0, r0 /* flags - empty */ 1600510b14bSMichal Simek addi r31, r0, _gd 161405e651dSMichal Simek#if defined(CONFIG_SYS_MALLOC_F_LEN) 162405e651dSMichal Simek addi r6, r0, CONFIG_SYS_INIT_SP_OFFSET 163405e651dSMichal Simek swi r6, r31, GD_MALLOC_BASE 164405e651dSMichal Simek#endif 1652380b8f5SMichal Simek brai board_init_f 1669d242745SMichal Simek#else 167ca7d2266SMichal Simek addi r31, r0, _gd 168ca7d2266SMichal Simek#if defined(CONFIG_SYS_MALLOC_F_LEN) 169ca7d2266SMichal Simek addi r6, r0, CONFIG_SPL_STACK_ADDR 170ca7d2266SMichal Simek swi r6, r31, GD_MALLOC_BASE 171ca7d2266SMichal Simek#endif 1729d242745SMichal Simek brai board_init_r 1739d242745SMichal Simek#endif 1746260fb04SPeter Tyser1: bri 1b 1756260fb04SPeter Tyser 1760510b14bSMichal Simek .section .bss 1770510b14bSMichal Simek.align 4 1780510b14bSMichal Simek_gd: 1790510b14bSMichal Simek .space GENERATED_GBL_DATA_SIZE 1800510b14bSMichal Simek 1819d242745SMichal Simek#ifndef CONFIG_SPL_BUILD 1826260fb04SPeter Tyser/* 1836260fb04SPeter Tyser * Read 16bit little endian 1846260fb04SPeter Tyser */ 1856260fb04SPeter Tyser .text 1866260fb04SPeter Tyser .global in16 1876260fb04SPeter Tyser .ent in16 1886260fb04SPeter Tyser .align 2 1896260fb04SPeter Tyserin16: lhu r3, r0, r5 1906260fb04SPeter Tyser bslli r4, r3, 8 1916260fb04SPeter Tyser bsrli r3, r3, 8 1926260fb04SPeter Tyser andi r4, r4, 0xffff 1936260fb04SPeter Tyser or r3, r3, r4 1946260fb04SPeter Tyser rtsd r15, 8 1956260fb04SPeter Tyser sext16 r3, r3 1966260fb04SPeter Tyser .end in16 1976260fb04SPeter Tyser 1986260fb04SPeter Tyser/* 1996260fb04SPeter Tyser * Write 16bit little endian 2006260fb04SPeter Tyser * first parameter(r5) - address, second(r6) - short value 2016260fb04SPeter Tyser */ 2026260fb04SPeter Tyser .text 2036260fb04SPeter Tyser .global out16 2046260fb04SPeter Tyser .ent out16 2056260fb04SPeter Tyser .align 2 2066260fb04SPeter Tyserout16: bslli r3, r6, 8 2076260fb04SPeter Tyser bsrli r6, r6, 8 2086260fb04SPeter Tyser andi r3, r3, 0xffff 2096260fb04SPeter Tyser or r3, r3, r6 2106260fb04SPeter Tyser sh r3, r0, r5 2116260fb04SPeter Tyser rtsd r15, 8 2126260fb04SPeter Tyser or r0, r0, r0 2136260fb04SPeter Tyser .end out16 214e945f6dcSMichal Simek 215e945f6dcSMichal Simek/* 216e945f6dcSMichal Simek * Relocate u-boot 217e945f6dcSMichal Simek */ 218e945f6dcSMichal Simek .text 219e945f6dcSMichal Simek .global relocate_code 220e945f6dcSMichal Simek .ent relocate_code 221e945f6dcSMichal Simek .align 2 222e945f6dcSMichal Simekrelocate_code: 223e945f6dcSMichal Simek /* 224e945f6dcSMichal Simek * r5 - start_addr_sp 225e945f6dcSMichal Simek * r6 - new_gd 226e945f6dcSMichal Simek * r7 - reloc_addr 227e945f6dcSMichal Simek */ 228e945f6dcSMichal Simek addi r1, r5, 0 /* Start to use new SP */ 229e945f6dcSMichal Simek addi r31, r6, 0 /* Start to use new GD */ 230e945f6dcSMichal Simek 231e945f6dcSMichal Simek add r23, r0, r7 /* Move reloc addr to r23 */ 232e945f6dcSMichal Simek /* Relocate text and data - r12 temp value */ 233e945f6dcSMichal Simek addi r21, r0, _start 234e945f6dcSMichal Simek addi r22, r0, __end - 4 /* Include BSS too */ 2357c4dd542SMichal Simek 2367c4dd542SMichal Simek rsub r6, r21, r22 2377c4dd542SMichal Simek or r5, r0, r0 2387c4dd542SMichal Simek1: lw r12, r21, r5 /* Load u-boot data */ 2397c4dd542SMichal Simek sw r12, r23, r5 /* Write zero to loc */ 2407c4dd542SMichal Simek cmp r12, r5, r6 /* Check if we have reach the end */ 241e945f6dcSMichal Simek bneid r12, 1b 2427c4dd542SMichal Simek addi r5, r5, 4 /* Increment to next loc - relocate code */ 243e945f6dcSMichal Simek 244e945f6dcSMichal Simek /* R23 points to the base address. */ 245e945f6dcSMichal Simek add r23, r0, r7 /* Move reloc addr to r23 */ 246e945f6dcSMichal Simek addi r24, r0, CONFIG_SYS_TEXT_BASE /* Get reloc offset */ 247e945f6dcSMichal Simek rsub r23, r24, r23 /* keep - this is already here gd->reloc_off */ 248e945f6dcSMichal Simek 249e945f6dcSMichal Simek addik r6, r0, 0x2 /* BIG/LITTLE endian offset */ 250e945f6dcSMichal Simek lwi r7, r0, 0x28 251e945f6dcSMichal Simek swi r6, r0, 0x28 /* used first unused MB vector */ 252e945f6dcSMichal Simek lbui r10, r0, 0x28 /* used first unused MB vector */ 253e945f6dcSMichal Simek swi r7, r0, 0x28 254e945f6dcSMichal Simek 255e945f6dcSMichal Simek#ifdef CONFIG_SYS_USR_EXCEP 256e945f6dcSMichal Simek addik r6, r0, _exception_handler 257e945f6dcSMichal Simek addk r6, r6, r23 /* add offset */ 258e945f6dcSMichal Simek sw r6, r1, r0 259e945f6dcSMichal Simek lhu r7, r1, r10 260e945f6dcSMichal Simek rsubi r8, r10, 0xa 261e945f6dcSMichal Simek sh r7, r0, r8 262e945f6dcSMichal Simek rsubi r8, r10, 0xe 263e945f6dcSMichal Simek sh r6, r0, r8 264e945f6dcSMichal Simek#endif 265e945f6dcSMichal Simek addik r6, r0, _hw_exception_handler 266e945f6dcSMichal Simek addk r6, r6, r23 /* add offset */ 267e945f6dcSMichal Simek sw r6, r1, r0 268e945f6dcSMichal Simek lhu r7, r1, r10 269e945f6dcSMichal Simek rsubi r8, r10, 0x22 270e945f6dcSMichal Simek sh r7, r0, r8 271e945f6dcSMichal Simek rsubi r8, r10, 0x26 272e945f6dcSMichal Simek sh r6, r0, r8 273e945f6dcSMichal Simek 274e945f6dcSMichal Simek addik r6, r0, _interrupt_handler 275e945f6dcSMichal Simek addk r6, r6, r23 /* add offset */ 276e945f6dcSMichal Simek sw r6, r1, r0 277e945f6dcSMichal Simek lhu r7, r1, r10 278e945f6dcSMichal Simek rsubi r8, r10, 0x12 279e945f6dcSMichal Simek sh r7, r0, r8 280e945f6dcSMichal Simek rsubi r8, r10, 0x16 281e945f6dcSMichal Simek sh r6, r0, r8 282e945f6dcSMichal Simek 283e945f6dcSMichal Simek /* Check if GOT exist */ 284e945f6dcSMichal Simek addik r21, r23, _got_start 285e945f6dcSMichal Simek addik r22, r23, _got_end 286e945f6dcSMichal Simek cmpu r12, r21, r22 287e945f6dcSMichal Simek beqi r12, 2f /* No GOT table - jump over */ 288e945f6dcSMichal Simek 289e945f6dcSMichal Simek /* Skip last 3 entries plus 1 because of loop boundary below */ 290e945f6dcSMichal Simek addik r22, r22, -0x10 291e945f6dcSMichal Simek 292e945f6dcSMichal Simek /* Relocate the GOT. */ 293e945f6dcSMichal Simek3: lw r12, r21, r0 /* Load entry */ 294e945f6dcSMichal Simek addk r12, r12, r23 /* Add reloc offset */ 295e945f6dcSMichal Simek sw r12, r21, r0 /* Save entry back */ 296e945f6dcSMichal Simek 297e945f6dcSMichal Simek cmpu r12, r21, r22 /* Check if this cross boundary */ 298e945f6dcSMichal Simek bneid r12, 3b 299e945f6dcSMichal Simek addik r21. r21, 4 300e945f6dcSMichal Simek 301e945f6dcSMichal Simek /* Update pointer to GOT */ 302e945f6dcSMichal Simek mfs r20, rpc 303e945f6dcSMichal Simek addik r20, r20, _GLOBAL_OFFSET_TABLE_ + 8 304e945f6dcSMichal Simek addk r20, r20, r23 305e945f6dcSMichal Simek 306e945f6dcSMichal Simek /* Flush caches to ensure consistency */ 307e945f6dcSMichal Simek addik r5, r0, 0 308e945f6dcSMichal Simek addik r6, r0, XILINX_DCACHE_BYTE_SIZE 309e945f6dcSMichal Simek bralid r15, flush_cache 310e945f6dcSMichal Simek nop 311e945f6dcSMichal Simek 312e945f6dcSMichal Simek2: addi r5, r31, 0 /* gd is initialized in board_r.c */ 313e945f6dcSMichal Simek addi r6, r0, CONFIG_SYS_TEXT_BASE 314e945f6dcSMichal Simek addi r12, r23, board_init_r 315e945f6dcSMichal Simek bra r12 /* Jump to relocated code */ 316e945f6dcSMichal Simek 317e945f6dcSMichal Simek .end relocate_code 3189d242745SMichal Simek#endif 319