start.S 7.6 KB

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