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 289d242745SMichal Simek#if defined(CONFIG_SPL_BUILD) 299d242745SMichal Simek addi r1, r0, CONFIG_SPL_STACK_ADDR 30da931af1SMichal Simek mts rshr, r1 319d242745SMichal Simek addi r1, r1, -4 /* Decrement SP to top of memory */ 329d242745SMichal Simek#else 336260fb04SPeter Tyser addi r1, r0, CONFIG_SYS_INIT_SP_OFFSET 34da931af1SMichal Simek mts rshr, r1 356260fb04SPeter Tyser addi r1, r1, -4 /* Decrement SP to top of memory */ 36b98cba09SMichal Simek 37b98cba09SMichal Simek /* Find-out if u-boot is running on BIG/LITTLE endian platform 38b98cba09SMichal Simek * There are some steps which is necessary to keep in mind: 39b98cba09SMichal Simek * 1. Setup offset value to r6 40b98cba09SMichal Simek * 2. Store word offset value to address 0x0 41b98cba09SMichal Simek * 3. Load just byte from address 0x0 42b98cba09SMichal Simek * 4a) LITTLE endian - r10 contains 0x2 because it is the smallest 43b98cba09SMichal Simek * value that's why is on address 0x0 44b98cba09SMichal Simek * 4b) BIG endian - r10 contains 0x0 because 0x2 offset is on addr 0x3 45b98cba09SMichal Simek */ 46b98cba09SMichal Simek addik r6, r0, 0x2 /* BIG/LITTLE endian offset */ 47f3090fceSMichal Simek lwi r7, r0, 0x28 48f3090fceSMichal Simek swi r6, r0, 0x28 /* used first unused MB vector */ 49f3090fceSMichal Simek lbui r10, r0, 0x28 /* used first unused MB vector */ 50f3090fceSMichal Simek swi r7, r0, 0x28 51b98cba09SMichal Simek 526260fb04SPeter Tyser /* add opcode instruction for 32bit jump - 2 instruction imm & brai */ 5386c1b2a8SMichal Simek addi r2, r0, 0xb0000000 /* hex b000 opcode imm */ 5486c1b2a8SMichal Simek addi r3, r0, 0xb8080000 /* hew b808 opcode brai */ 556260fb04SPeter Tyser 566260fb04SPeter Tyser#ifdef CONFIG_SYS_RESET_ADDRESS 576260fb04SPeter Tyser /* reset address */ 5886c1b2a8SMichal Simek swi r2, r0, 0x0 /* reset address - imm opcode */ 5986c1b2a8SMichal Simek swi r3, r0, 0x4 /* reset address - brai opcode */ 6086c1b2a8SMichal Simek 616260fb04SPeter Tyser addik r6, r0, CONFIG_SYS_RESET_ADDRESS 626260fb04SPeter Tyser sw r6, r1, r0 635562bcc2SMichal Simek lhu r7, r1, r10 645562bcc2SMichal Simek rsubi r8, r10, 0x2 655562bcc2SMichal Simek sh r7, r0, r8 665562bcc2SMichal Simek rsubi r8, r10, 0x6 675562bcc2SMichal Simek sh r6, r0, r8 686260fb04SPeter Tyser#endif 696260fb04SPeter Tyser 706260fb04SPeter Tyser#ifdef CONFIG_SYS_USR_EXCEP 716260fb04SPeter Tyser /* user_vector_exception */ 7286c1b2a8SMichal Simek swi r2, r0, 0x8 /* user vector exception - imm opcode */ 7386c1b2a8SMichal Simek swi r3, r0, 0xC /* user vector exception - brai opcode */ 7486c1b2a8SMichal Simek 756260fb04SPeter Tyser addik r6, r0, _exception_handler 766260fb04SPeter Tyser sw r6, r1, r0 77b98cba09SMichal Simek /* 78b98cba09SMichal Simek * BIG ENDIAN memory map for user exception 79b98cba09SMichal Simek * 0x8: 0xB000XXXX 80b98cba09SMichal Simek * 0xC: 0xB808XXXX 81b98cba09SMichal Simek * 82b98cba09SMichal Simek * then it is necessary to count address for storing the most significant 83b98cba09SMichal Simek * 16bits from _exception_handler address and copy it to 84b98cba09SMichal Simek * 0xa address. Big endian use offset in r10=0 that's why is it just 85b98cba09SMichal Simek * 0xa address. The same is done for the least significant 16 bits 86b98cba09SMichal Simek * for 0xe address. 87b98cba09SMichal Simek * 88b98cba09SMichal Simek * LITTLE ENDIAN memory map for user exception 89b98cba09SMichal Simek * 0x8: 0xXXXX00B0 90b98cba09SMichal Simek * 0xC: 0xXXXX08B8 91b98cba09SMichal Simek * 92b98cba09SMichal Simek * Offset is for little endian setup to 0x2. rsubi instruction decrease 93b98cba09SMichal Simek * address value to ensure that points to proper place which is 94b98cba09SMichal Simek * 0x8 for the most significant 16 bits and 95b98cba09SMichal Simek * 0xC for the least significant 16 bits 96b98cba09SMichal Simek */ 97b98cba09SMichal Simek lhu r7, r1, r10 98b98cba09SMichal Simek rsubi r8, r10, 0xa 99b98cba09SMichal Simek sh r7, r0, r8 100b98cba09SMichal Simek rsubi r8, r10, 0xe 101b98cba09SMichal Simek sh r6, r0, r8 1026260fb04SPeter Tyser#endif 1036260fb04SPeter Tyser 1046260fb04SPeter Tyser /* interrupt_handler */ 10586c1b2a8SMichal Simek swi r2, r0, 0x10 /* interrupt - imm opcode */ 10686c1b2a8SMichal Simek swi r3, r0, 0x14 /* interrupt - brai opcode */ 10786c1b2a8SMichal Simek 1086260fb04SPeter Tyser addik r6, r0, _interrupt_handler 1096260fb04SPeter Tyser sw r6, r1, r0 110b98cba09SMichal Simek lhu r7, r1, r10 111b98cba09SMichal Simek rsubi r8, r10, 0x12 112b98cba09SMichal Simek sh r7, r0, r8 113b98cba09SMichal Simek rsubi r8, r10, 0x16 114b98cba09SMichal Simek sh r6, r0, r8 1156260fb04SPeter Tyser 1166260fb04SPeter Tyser /* hardware exception */ 11786c1b2a8SMichal Simek swi r2, r0, 0x20 /* hardware exception - imm opcode */ 11886c1b2a8SMichal Simek swi r3, r0, 0x24 /* hardware exception - brai opcode */ 11986c1b2a8SMichal Simek 1206260fb04SPeter Tyser addik r6, r0, _hw_exception_handler 1216260fb04SPeter Tyser sw r6, r1, r0 122b98cba09SMichal Simek lhu r7, r1, r10 123b98cba09SMichal Simek rsubi r8, r10, 0x22 124b98cba09SMichal Simek sh r7, r0, r8 125b98cba09SMichal Simek rsubi r8, r10, 0x26 126b98cba09SMichal Simek sh r6, r0, r8 1279d242745SMichal Simek#endif /* BUILD_SPL */ 1286260fb04SPeter Tyser 1295811830fSMichal Simek /* Flush cache before enable cache */ 1305811830fSMichal Simek addik r5, r0, 0 1315811830fSMichal Simek addik r6, r0, XILINX_DCACHE_BYTE_SIZE 132e4a4743eSMichal Simek bralid r15, flush_cache 1335811830fSMichal Simek nop 1345811830fSMichal Simek 1356260fb04SPeter Tyser /* enable instruction and data cache */ 1366260fb04SPeter Tyser mfs r12, rmsr 137822d43a6SMichal Simek ori r12, r12, 0x1a0 1386260fb04SPeter Tyser mts rmsr, r12 1396260fb04SPeter Tyser 1406260fb04SPeter Tyserclear_bss: 1416260fb04SPeter Tyser /* clear BSS segments */ 1426260fb04SPeter Tyser addi r5, r0, __bss_start 1436260fb04SPeter Tyser addi r4, r0, __bss_end 1446260fb04SPeter Tyser cmp r6, r5, r4 1456260fb04SPeter Tyser beqi r6, 3f 1466260fb04SPeter Tyser2: 1476260fb04SPeter Tyser swi r0, r5, 0 /* write zero to loc */ 1486260fb04SPeter Tyser addi r5, r5, 4 /* increment to next loc */ 1496260fb04SPeter Tyser cmp r6, r5, r4 /* check if we have reach the end */ 1506260fb04SPeter Tyser bnei r6, 2b 1516260fb04SPeter Tyser3: /* jumping to board_init */ 1529d242745SMichal Simek#ifndef CONFIG_SPL_BUILD 153*e945f6dcSMichal Simek or r5, r0, r0 /* flags - empty */ 1542380b8f5SMichal Simek brai board_init_f 1559d242745SMichal Simek#else 1569cef20b1SMichal Simek addi r31, r0, CONFIG_SYS_SPL_MALLOC_END 1579d242745SMichal Simek brai board_init_r 1589d242745SMichal Simek#endif 1596260fb04SPeter Tyser1: bri 1b 1606260fb04SPeter Tyser 1619d242745SMichal Simek#ifndef CONFIG_SPL_BUILD 1626260fb04SPeter Tyser/* 1636260fb04SPeter Tyser * Read 16bit little endian 1646260fb04SPeter Tyser */ 1656260fb04SPeter Tyser .text 1666260fb04SPeter Tyser .global in16 1676260fb04SPeter Tyser .ent in16 1686260fb04SPeter Tyser .align 2 1696260fb04SPeter Tyserin16: lhu r3, r0, r5 1706260fb04SPeter Tyser bslli r4, r3, 8 1716260fb04SPeter Tyser bsrli r3, r3, 8 1726260fb04SPeter Tyser andi r4, r4, 0xffff 1736260fb04SPeter Tyser or r3, r3, r4 1746260fb04SPeter Tyser rtsd r15, 8 1756260fb04SPeter Tyser sext16 r3, r3 1766260fb04SPeter Tyser .end in16 1776260fb04SPeter Tyser 1786260fb04SPeter Tyser/* 1796260fb04SPeter Tyser * Write 16bit little endian 1806260fb04SPeter Tyser * first parameter(r5) - address, second(r6) - short value 1816260fb04SPeter Tyser */ 1826260fb04SPeter Tyser .text 1836260fb04SPeter Tyser .global out16 1846260fb04SPeter Tyser .ent out16 1856260fb04SPeter Tyser .align 2 1866260fb04SPeter Tyserout16: bslli r3, r6, 8 1876260fb04SPeter Tyser bsrli r6, r6, 8 1886260fb04SPeter Tyser andi r3, r3, 0xffff 1896260fb04SPeter Tyser or r3, r3, r6 1906260fb04SPeter Tyser sh r3, r0, r5 1916260fb04SPeter Tyser rtsd r15, 8 1926260fb04SPeter Tyser or r0, r0, r0 1936260fb04SPeter Tyser .end out16 194*e945f6dcSMichal Simek 195*e945f6dcSMichal Simek/* 196*e945f6dcSMichal Simek * Relocate u-boot 197*e945f6dcSMichal Simek */ 198*e945f6dcSMichal Simek .text 199*e945f6dcSMichal Simek .global relocate_code 200*e945f6dcSMichal Simek .ent relocate_code 201*e945f6dcSMichal Simek .align 2 202*e945f6dcSMichal Simekrelocate_code: 203*e945f6dcSMichal Simek /* 204*e945f6dcSMichal Simek * r5 - start_addr_sp 205*e945f6dcSMichal Simek * r6 - new_gd 206*e945f6dcSMichal Simek * r7 - reloc_addr 207*e945f6dcSMichal Simek */ 208*e945f6dcSMichal Simek addi r1, r5, 0 /* Start to use new SP */ 209*e945f6dcSMichal Simek addi r31, r6, 0 /* Start to use new GD */ 210*e945f6dcSMichal Simek 211*e945f6dcSMichal Simek add r23, r0, r7 /* Move reloc addr to r23 */ 212*e945f6dcSMichal Simek /* Relocate text and data - r12 temp value */ 213*e945f6dcSMichal Simek addi r21, r0, _start 214*e945f6dcSMichal Simek addi r22, r0, __end - 4 /* Include BSS too */ 215*e945f6dcSMichal Simek1: lwi r12, r21, 0 /* Load u-boot data */ 216*e945f6dcSMichal Simek swi r12, r23, 0 /* Write zero to loc */ 217*e945f6dcSMichal Simek addi r21, r21, 4 /* Increment to next loc - origin code */ 218*e945f6dcSMichal Simek cmp r12, r21, r22 /* Check if we have reach the end */ 219*e945f6dcSMichal Simek bneid r12, 1b 220*e945f6dcSMichal Simek addi r23, r23, 4 /* Increment to next loc - relocate code */ 221*e945f6dcSMichal Simek 222*e945f6dcSMichal Simek /* R23 points to the base address. */ 223*e945f6dcSMichal Simek add r23, r0, r7 /* Move reloc addr to r23 */ 224*e945f6dcSMichal Simek addi r24, r0, CONFIG_SYS_TEXT_BASE /* Get reloc offset */ 225*e945f6dcSMichal Simek rsub r23, r24, r23 /* keep - this is already here gd->reloc_off */ 226*e945f6dcSMichal Simek 227*e945f6dcSMichal Simek addik r6, r0, 0x2 /* BIG/LITTLE endian offset */ 228*e945f6dcSMichal Simek lwi r7, r0, 0x28 229*e945f6dcSMichal Simek swi r6, r0, 0x28 /* used first unused MB vector */ 230*e945f6dcSMichal Simek lbui r10, r0, 0x28 /* used first unused MB vector */ 231*e945f6dcSMichal Simek swi r7, r0, 0x28 232*e945f6dcSMichal Simek 233*e945f6dcSMichal Simek#ifdef CONFIG_SYS_USR_EXCEP 234*e945f6dcSMichal Simek addik r6, r0, _exception_handler 235*e945f6dcSMichal Simek addk r6, r6, r23 /* add offset */ 236*e945f6dcSMichal Simek sw r6, r1, r0 237*e945f6dcSMichal Simek lhu r7, r1, r10 238*e945f6dcSMichal Simek rsubi r8, r10, 0xa 239*e945f6dcSMichal Simek sh r7, r0, r8 240*e945f6dcSMichal Simek rsubi r8, r10, 0xe 241*e945f6dcSMichal Simek sh r6, r0, r8 242*e945f6dcSMichal Simek#endif 243*e945f6dcSMichal Simek addik r6, r0, _hw_exception_handler 244*e945f6dcSMichal Simek addk r6, r6, r23 /* add offset */ 245*e945f6dcSMichal Simek sw r6, r1, r0 246*e945f6dcSMichal Simek lhu r7, r1, r10 247*e945f6dcSMichal Simek rsubi r8, r10, 0x22 248*e945f6dcSMichal Simek sh r7, r0, r8 249*e945f6dcSMichal Simek rsubi r8, r10, 0x26 250*e945f6dcSMichal Simek sh r6, r0, r8 251*e945f6dcSMichal Simek 252*e945f6dcSMichal Simek addik r6, r0, _interrupt_handler 253*e945f6dcSMichal Simek addk r6, r6, r23 /* add offset */ 254*e945f6dcSMichal Simek sw r6, r1, r0 255*e945f6dcSMichal Simek lhu r7, r1, r10 256*e945f6dcSMichal Simek rsubi r8, r10, 0x12 257*e945f6dcSMichal Simek sh r7, r0, r8 258*e945f6dcSMichal Simek rsubi r8, r10, 0x16 259*e945f6dcSMichal Simek sh r6, r0, r8 260*e945f6dcSMichal Simek 261*e945f6dcSMichal Simek /* Check if GOT exist */ 262*e945f6dcSMichal Simek addik r21, r23, _got_start 263*e945f6dcSMichal Simek addik r22, r23, _got_end 264*e945f6dcSMichal Simek cmpu r12, r21, r22 265*e945f6dcSMichal Simek beqi r12, 2f /* No GOT table - jump over */ 266*e945f6dcSMichal Simek 267*e945f6dcSMichal Simek /* Skip last 3 entries plus 1 because of loop boundary below */ 268*e945f6dcSMichal Simek addik r22, r22, -0x10 269*e945f6dcSMichal Simek 270*e945f6dcSMichal Simek /* Relocate the GOT. */ 271*e945f6dcSMichal Simek3: lw r12, r21, r0 /* Load entry */ 272*e945f6dcSMichal Simek addk r12, r12, r23 /* Add reloc offset */ 273*e945f6dcSMichal Simek sw r12, r21, r0 /* Save entry back */ 274*e945f6dcSMichal Simek 275*e945f6dcSMichal Simek cmpu r12, r21, r22 /* Check if this cross boundary */ 276*e945f6dcSMichal Simek bneid r12, 3b 277*e945f6dcSMichal Simek addik r21. r21, 4 278*e945f6dcSMichal Simek 279*e945f6dcSMichal Simek /* Update pointer to GOT */ 280*e945f6dcSMichal Simek mfs r20, rpc 281*e945f6dcSMichal Simek addik r20, r20, _GLOBAL_OFFSET_TABLE_ + 8 282*e945f6dcSMichal Simek addk r20, r20, r23 283*e945f6dcSMichal Simek 284*e945f6dcSMichal Simek /* Flush caches to ensure consistency */ 285*e945f6dcSMichal Simek addik r5, r0, 0 286*e945f6dcSMichal Simek addik r6, r0, XILINX_DCACHE_BYTE_SIZE 287*e945f6dcSMichal Simek bralid r15, flush_cache 288*e945f6dcSMichal Simek nop 289*e945f6dcSMichal Simek 290*e945f6dcSMichal Simek2: addi r5, r31, 0 /* gd is initialized in board_r.c */ 291*e945f6dcSMichal Simek addi r6, r0, CONFIG_SYS_TEXT_BASE 292*e945f6dcSMichal Simek addi r12, r23, board_init_r 293*e945f6dcSMichal Simek bra r12 /* Jump to relocated code */ 294*e945f6dcSMichal Simek 295*e945f6dcSMichal Simek .end relocate_code 2969d242745SMichal Simek#endif 297