selfboot_gcc.S 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. /*
  2. * Copyright (c) 2006-2019, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Origin Authors: Loongson Technology Corporation Limited,
  7. * caogos <1207280597@qq.com>, Jiaxun Yang <jiaxun.yang@flygoat.com>,
  8. *
  9. * Also thanks to Liu Shiwei <liushiwei@gmail.com> and other Loongson
  10. * Community developers.
  11. *
  12. * Change Logs:
  13. * Date Author Notes
  14. * 2019-12-04 Jiaxun Yang Initial version
  15. */
  16. #include <rtconfig.h>
  17. #ifdef RT_USING_SELF_BOOT
  18. #ifndef __ASSEMBLY__
  19. #define __ASSEMBLY__
  20. #endif
  21. #include <mips.h>
  22. #include "selfboot.h"
  23. #include "ls1c.h"
  24. #include "cache.h"
  25. /*
  26. * Register usage:
  27. *
  28. * s0 link versus load offset, used to relocate absolute adresses.
  29. * s1 free
  30. * s2 memory size
  31. * s3 free
  32. * s4 free
  33. * s5 dbg
  34. * s6 sdCfg
  35. * s7 rasave
  36. * s8 free
  37. */
  38. #define tmpsize s1
  39. #define msize s2
  40. #define bonito s4
  41. #define dbg s5
  42. #define sdCfg s6
  43. /* Macros */
  44. #ifdef RT_SELF_BOOT_DEBUG
  45. #define PRINTSTR(str) \
  46. .pushsection .selfboot_data; .align 4; 98: .asciz str; .popsection; la a0, 98b; bal stringserial; nop
  47. #else
  48. #define PRINTSTR(x)
  49. #endif
  50. #define DELAY(count) \
  51. li v0, count; \
  52. 99: \
  53. bnez v0, 99b;\
  54. addiu v0, -1
  55. .section ".selfboot", "ax"
  56. .set noreorder
  57. .set mips32
  58. .globl _start
  59. .extern start
  60. _start:
  61. /* NMI/Reset vector starts here*/
  62. mtc0 zero, CP0_STATUS /* set cp0 status register to zero */
  63. mtc0 zero, CP0_CAUSE /* set cp0 cause register to zero */
  64. li t0, ST0_BEV /* set exception vector to in flash location */
  65. mtc0 t0, CP0_STATUS
  66. /* Speed up SPI reading */
  67. li t0, 0xbfe80000 /* load SPI0 controler base address to t0 */
  68. li t1, 0x17 /* load "div 4, fast_read + burst_en + memory_en double I/O" to
  69. * to t0 for write, not all the flash chips support this mode */
  70. sb t1, 0x4(t0) /* set sfc_param register */
  71. li t1, 0x05
  72. sb t1, 0x6(t0) /* set sfc_timing register */
  73. bal locate /* branch out of vector and get current address to ra */
  74. nop
  75. /* in-flash exception vectors start here */
  76. /* save the exception types to a0 and print out PANIC message in exc_common */
  77. #define EXC_TLB_REFILL 0x0
  78. #define EXC_CACHE_ERR 0x1
  79. #define EXC_GEN 0x2
  80. #define EXC_INT 0x3
  81. .org 0x200 /* 0xbfc00200 TLB_REFILL exception */
  82. li a0, EXC_TLB_REFILL
  83. b exc_common
  84. nop
  85. .org 0x300 /* 0xbfc00300 Cache Error exception */
  86. li a0, EXC_CACHE_ERR
  87. b exc_common
  88. nop
  89. .org 0x380 /* 0xbfc00300 General exception */
  90. li a0,EXC_GEN
  91. b exc_common
  92. nop
  93. .org 0x400 /* 0xbfc00400 Interrupt exception */
  94. li a0, EXC_INT
  95. b exc_common
  96. nop
  97. 1: /* impossible to reach here, so make a dead loop */
  98. b 1b
  99. nop
  100. exc_common: /* try one cause and pass to next */
  101. li s1, EXC_TLB_REFILL
  102. bne a0, s1, 1f
  103. nop
  104. PRINTSTR("\r\nEARLY_PANIC: Exception TLB Refill")
  105. b print_cause
  106. nop
  107. 1:
  108. li s1, EXC_CACHE_ERR
  109. bne a0, s1, 1f
  110. nop
  111. PRINTSTR("\r\nEARLY_PANIC: CACHE Error: ")
  112. mfc0 a0, CP0_CACHEERR
  113. bal hexserial
  114. nop
  115. b print_cause
  116. nop
  117. 1:
  118. li s1, EXC_GEN
  119. bne a0, s1, 1f
  120. nop
  121. PRINTSTR("\r\nEARLY_PANIC: General Exception")
  122. b print_cause
  123. nop
  124. 1:
  125. li s1, EXC_INT
  126. bne a0, s1, print_cause /* if all exceptions in a0 not reached,
  127. * print_cause directly*/
  128. nop
  129. PRINTSTR("\r\nEARLY_PANIC: Interrupt Exception")
  130. print_cause:
  131. PRINTSTR("\r\nCAUSE=")
  132. mfc0 a0, CP0_CAUSE
  133. bal hexserial
  134. nop
  135. PRINTSTR("\r\nSTATUS=")
  136. mfc0 a0, CP0_STATUS
  137. bal hexserial
  138. nop
  139. PRINTSTR("\r\nERRORPC=")
  140. mfc0 a0, CP0_ERROREPC
  141. bal hexserial
  142. nop
  143. PRINTSTR("\r\nEPC=")
  144. mfc0 a0, CP0_EPC
  145. bal hexserial
  146. nop
  147. PRINTSTR("\r\nBADADDR=")
  148. mfc0 a0, CP0_BADVADDR
  149. bal hexserial
  150. nop
  151. PRINTSTR("\r\nEARLY: LOOP! Noting to do")
  152. 1: /* Make a dead loop here, wait user to reset the MCU */
  153. b 1b
  154. nop
  155. /* locate here, continue the start progress */
  156. locate:
  157. /* fix the absolute address by ra */
  158. la s0, start /* s0 = start */
  159. subu s0, ra, s0 /* s0 = ra - s0 */
  160. and s0, 0xffff0000 /* s0 = s0 & 0xffff0000 */
  161. li t0, 0xbfe78030 /* load PLL/SDRAM freq config register base to t0 */
  162. li t2, (0x80000008 | (PLL_MULT << 8) | (0x3 << 2) | SDRAM_DIV) /* Set PLL
  163. * MULT and PLL DIV */
  164. li t3, (0x00008003 | (CPU_DIV << 8)) /* set CPU DEV */
  165. li t1, 0x2
  166. sw t1, 0x4(t0) /* disable CPU_DIV_VALID firstly for adjustment */
  167. sw t2, 0x0(t0) /* write START_FREQ */
  168. sw t3, 0x4(t0) /* write CLK_DIV_PARAM */
  169. /* start to initialize debug uart port */
  170. la v0, LS1C_UART2_BASE /* load UART2 base to v0, only UART2 can be debug port */
  171. 1:
  172. li v1, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4 /* clear Rx,Tx FIFO
  173. * declear 4 bit int trigger */
  174. sb v1, LS1C_UART_FCR_OFFSET(v0) /* write FCR (FIFO control register) */
  175. li v1, CFCR_DLAB /* reach freq div register */
  176. sb v1, LS1C_UART_LCR_OFFSET(v0) /* write LCR (Line control register)*/
  177. /* Set UART2 reuse with GPIO36,37*/
  178. li a0, LS1C_CBUS_FIRST1 /* load CBUS_FIRST1 offset to a0 */
  179. lw a1, 0x10(a0) /* load value from CBUS_SECOND1 to a1 */
  180. ori a1, 0x30 /* a1 |= 0x30, GPIO36,37 as secondary function */
  181. sw a1, 0x10(a0) /* write back modified CBUS_SECOND1 from a1 */
  182. /* Caculate PLL and bit rate */
  183. li a0, 0xbfe78030 /* load START_FREQ register address to a0 */
  184. lw a1, 0(a0) /* load value from START_FREQ to a1*/
  185. srl a1, 8 /* a1 >>= 8 */
  186. andi a1, 0xff /* a1 &= 0xff, as a1=PLL_MULT */
  187. li a2, APB_CLK /* a2 = APB_CLK = 24Mhz (External Clock Freq) */
  188. srl a2, 2 /* a2 = a2 >> 2 = APB_CLK/4 */
  189. multu a1, a2 /* hilo = a1 * a2 = PLL_MULT * APB_CLK /4 */
  190. mflo v1 /* v1 = lo. put low 32 bit of a1 * a2 to v1 as PLL freq */
  191. /* Determine if we need to devide the clock */
  192. lw a1, 4(a0) /* load value frm CLK_DIV_PARAM to a1 */
  193. andi a2, a1, DIV_CPU_SEL /* a2 = a1 & DIV_CPU_SEL, if CPU_SEL=1, devide the clock,
  194. * if CPU_SEL=0, bypass the clock */
  195. bnez a2, 1f /* if (a2 != 0), branch to next tag 1 */
  196. nop
  197. li v1, APB_CLK /* v1 = APB_CLK */
  198. b 3f
  199. nop
  200. 1: /* Determine if the CPU_DIV is valid*/
  201. andi a2, a1, DIV_CPU_EN /* a2 = a1 & DIV_CPU_EN */
  202. bnez a2, 2f /* if (a2 != 0), branch to next tag 2 */
  203. nop
  204. srl v1, 1 /* v1 >>= 1, so v1 = APB_CLK/4 * PLL_MULT/2 */
  205. b 3f
  206. nop
  207. 2: /* caculate CPU freq */
  208. andi a1, DIV_CPU /* a1 &= DIV_CPU */
  209. srl a1, DIV_CPU_SHIFT /* a1 >>= DIV_CPU_SHIFT */
  210. divu v1, a1 /* lo = v1/a1, hi = v1 % a1 */
  211. mflo v1 /* v1 = lo, CPU Freq */
  212. 3:
  213. li a1, (16 * EARLY_DEBUG_BAUD) /* a1 = 16 * BIT RATE */
  214. divu v1, v1, a1 /* v1 = v1 / a1 */
  215. srl v1, 1 /* v1 >>= 1 */
  216. sb v1, LS1C_UART_LSB_OFFSET(v0) /* write 8bit low into LSB */
  217. srl v1, 8 /* v1 >>= 8 */
  218. sb v1, LS1C_UART_MSB_OFFSET(v0) /* write 8bit low into MSB */
  219. li v1, CFCR_8BITS /* 8n1, no check */
  220. sb v1, LS1C_UART_LCR_OFFSET(v0) /* write to LCR (Line Control Register) */
  221. #ifdef EARLY_DEBUG_UART_FLOW_CTRL
  222. li v1, MCR_DTR|MCR_RTS /* valid DTR and RTS */
  223. sb v1, LS1C_UART_MCR_OFFSET(v0) /* write to MCR (MODEM Control Register) */
  224. #endif
  225. li v1, 0x0 /* disable all the interruptions */
  226. sb v1, LS1C_UART_IER_OFFSET(v0) /* write to IER (Interruptions Enable Registers) */
  227. PRINTSTR("\r\INFO: Loongson 1C300 Starting :) \r\n")
  228. /* disable all GPIOs for conflict functions */
  229. li a0,0xbfd00000
  230. sw zero,0x10c0(a0) /* disable GPIO 0-31 */
  231. sw zero,0x10c4(a0) /* disable GPIO 32-63 */
  232. sw zero,0x10c8(a0) /* disable GPIO 64-95 */
  233. sw zero,0x10cc(a0)
  234. li t0, 0xffffffff
  235. sw t0, 0x10d0(a0)
  236. sw t0, 0x10d4(a0)
  237. sw t0, 0x10d8(a0)
  238. sw t0, 0x10dc(a0)
  239. sw t0, 0x10f0(a0)
  240. sw t0, 0x10f4(a0)
  241. sw t0, 0x10f8(a0)
  242. sw t0, 0x10fc(a0)
  243. PRINTSTR("\r\INFO: All GPIOs are disabled\r\n")
  244. /* SDRAM initialize starts here */
  245. li msize, MEM_SIZE
  246. #ifdef EJTAG_SEL_AS_SDRAM_CS1
  247. li a0, 0xbfd011c0
  248. lw a1, 0x40(a0)
  249. ori a1, 0x01
  250. sw a1, 0x40(a0)
  251. PRINTSTR("\r\INFO: EJTAG_SEL PIN as SDRAM_CS1\r\n")
  252. #endif
  253. /*
  254. * recommanded by user manual, we should write SD_CONFIG[31:0] first, then
  255. * write SD_CONFIG[63:32]. Repeat writing for three times, valid the config in
  256. * the last time.
  257. */
  258. /* write first time */
  259. li t1, 0xbfd00410 /* load SD_CONFIG[31:0] address to t1 */
  260. li a1, SD_PARA0 /* get the memory config from macro SD_PARA0 */
  261. sw a1, 0x0(t1) /* write to SD_CONFIG[31:0] */
  262. li a1, SD_PARA1
  263. sw a1, 0x4(t1) /* write to SD_CONFIG[63:32] with offset */
  264. PRINTSTR("\r\INFO: SDRAM Config Pass1\r\n")
  265. /* write second time,the same */
  266. li a1, SD_PARA0
  267. sw a1, 0x0(t1)
  268. li a1, SD_PARA1
  269. sw a1, 0x4(t1)
  270. PRINTSTR("\r\INFO: SDRAM Config Pass2\r\n")
  271. /* write third time, enable controller this time */
  272. li a1, SD_PARA0
  273. sw a1, 0x0(t1)
  274. li a1, SD_PARA1_EN /* enable it */
  275. sw a1, 0x4(t1)
  276. PRINTSTR("\r\INFO: SDRAM initialize compeleted\r\n")
  277. /* initialize cache */
  278. bal cache_init /* branch to cache_init */
  279. nop
  280. /* enable cache */
  281. mfc0 a0, CP0_CONFIG /* load cp0 config to a0 */
  282. and a0, a0, ~((1<<12) | 7) /* a0 = a0 & ~((1<<12) | 7) */
  283. or a0, a0, 2 /* a0 |= 2 */
  284. mtc0 a0, CP0_CONFIG /* write back to CP0 config */
  285. /*
  286. * relocate: copy selfboot code to memory in kseg0, fix PC and jump to kseg0.
  287. * in order to speed up the copy progress, we will execute copy code in kseg0
  288. */
  289. PRINTSTR("\r\INFO: Relocating")
  290. la t0, text_copy_start /* load the adress of start tag to t0 */
  291. move t2, t0
  292. addu t0, s0 /* correct t0 address in rom by s0 */
  293. la t1, text_copy_end
  294. selfboot_copy_loop:
  295. lw v0, (t0) /* copy from memory address in t0 to register v0 */
  296. sw v0, (t2) /* write data in register v0 to memory address t0 */
  297. addiu t0, 0x4 /* t0 moves forward 4 bytes */
  298. addiu t2, 0x4 /* t2 moves forward 4 bytes */
  299. ble t2, t1, selfboot_copy_loop /* if t1 <= t2 loop to continue the copy */
  300. nop
  301. la t0, text_copy_start /* load start address to t0 */
  302. jr t0 /* jump to 122 in kseg0 to start copy code progress */
  303. nop
  304. text_copy_start:
  305. /* Copy code to memory*/
  306. la a0, start /* load address of start symbol to a0 */
  307. addu a1, a0, s0 /* correct a0 to address in flash */
  308. la a2, _edata /* load symbol _edata address to a2 */
  309. subu t1, a2, a0 /* t1 = a2 - a0, the space of text area */
  310. move t0, a0 /* the start address in ram */
  311. move t1, a1 /* the start address in rom */
  312. move t2, a2 /* the end address in rom (symbol _edata) */
  313. /* copy text section */
  314. 1:
  315. and t3, t0, 0x0000ffff /* t3 = t0 & 0x0000ffff, get low 16 bit */
  316. bnez t3, 2f /* if t3 != 0, jump to next tag 2 */
  317. nop
  318. 2:
  319. lw t3, 0(t1) /* copy 4 bit from memory address t1 to register t3 */
  320. nop
  321. sw t3, 0(t0) /* copy 4 bit from register t3 to memory address in t0 */
  322. addu t0, 4 /* t0 move forward 4 bytes */
  323. addu t1, 4 /* t1 move forward 4 bytes */
  324. bne t2, t0, 1b /* if t2 != t0, branch to last tag 1 to continue copy */
  325. nop
  326. /* copy text section done. */
  327. move a0, msize /* a0 = msize, will be passed to main */
  328. srl a0, 20 /* a0 >>= 20, convert to unit in MB */
  329. /* execute main */
  330. la v0, _rtthread_entry /* load address of function main to v0 */
  331. jalr v0 /* call address in v0, congrats! all low_level things done!
  332. * switch brain out of assembly */
  333. nop
  334. text_copy_end: /* end of self-copy in memory */
  335. loop: /* impossible to reach here, make a dead loop */
  336. b loop
  337. nop
  338. /* functions here */
  339. LEAF(stringserial) /* print out the string in address passed in a0 */
  340. nop
  341. move a2, ra /* save the return address to a2 */
  342. addu a1, a0, s0 /* correct the address in ROM */
  343. lbu a0, 0(a1) /* read the first byte in memory address a1 to a0 */
  344. 1:
  345. beqz a0, 2f /* if a0 == 0, jump to next tag 2, empty char */
  346. nop
  347. bal tgt_putchar /* print a char */
  348. addiu a1, 1 /* a1 += 1 move forward to next byte */
  349. b 1b /* branch to the last tag 1, continue */
  350. lbu a0, 0(a1) /* load the next bit from address a1 to a0, in delay solt,
  351. * will be execuated before branch */
  352. 2:
  353. j a2 /* return */
  354. nop
  355. END(stringserial)
  356. LEAF(hexserial) /* print out single hex char passed in register a0 */
  357. nop
  358. move a2, ra /* move return address from ra to a2 */
  359. move a1, a0 /* move hex char from register a0 to a1 */
  360. li a3, 7 /* load 7 to a3 */
  361. 1:
  362. rol a0, a1, 4 /* rotate left ward shift for 4 bit in a1 to a0 */
  363. move a1, a0
  364. and a0, 0xf
  365. la v0, hexchar
  366. .pushsection .selfboot_data
  367. .align 4
  368. hexchar:
  369. .ascii "0123456789abcdef"
  370. .popsection
  371. .align 4
  372. addu v0, s0
  373. addu v0, a0
  374. bal tgt_putchar
  375. lbu a0, 0(v0)
  376. bnez a3, 1b
  377. addu a3, -1
  378. j a2
  379. nop
  380. END(hexserial)
  381. LEAF(tgt_putchar) /* print out a char in a0 */
  382. la v0, LS1C_UART2_BASE /* load UART register address to a0 */
  383. lbu v1, LS1C_UART_LSR_OFFSET(v0) /* load value from LSR to v0 */
  384. 1:
  385. and v1, LSR_TXRDY /* v1 &= LSR_TXRDY determine wether we can send by TFE bit */
  386. beqz v1, 1b /* if (v1 == 0) jump to last 1 tag, waiting until TFE is 1 */
  387. lbu v1, LS1C_UART_LSR_OFFSET(v0) /* load value from LSR to v0 again, in delay solt */
  388. sb a0, LS1C_UART_DAT_OFFSET(v0) /* write a0 into DAT, send out */
  389. j ra /* */
  390. nop
  391. END(tgt_putchar)
  392. LEAF(CPU_SetSR) /* modify SR value, arg 1 = set bits, arg 2 = clear bits. */
  393. mfc0 v0, CP0_STATUS
  394. not v1, a1
  395. and v1, v0
  396. or v1, a0
  397. mtc0 v1, CP0_STATUS
  398. nop
  399. nop
  400. nop
  401. nop
  402. nop
  403. nop
  404. nop
  405. nop
  406. j ra
  407. nop
  408. END(CPU_SetSR)
  409. cache_init:
  410. move t1, ra
  411. ####part 2####
  412. cache_detect_4way:
  413. mfc0 t4, CP0_CONFIG,1 /* move CP0 CONFIG to t4 */
  414. lui v0, 0x7 /* v0 = 0x7 << 16 */
  415. and v0, t4, v0 /* v0 = t4 & v0 */
  416. srl t3, v0, 16 /* t3 = v0 >> 16 Icache组相联数 IA */
  417. li t5, 0x800 //32*64
  418. srl v1, t4,22 //v1 = t4 >> 22
  419. andi v1, 7 //Icache每路的组数 64x2^S IS
  420. sll t5, v1 //InstCacheSetSize
  421. sll t5, t3 //t5 InstCacheSize
  422. andi v0, t4, 0x0380
  423. srl t7, v0, 7 //DA
  424. li t6, 0x800 // 32*64
  425. srl v1, t4,13
  426. andi v1, 7 //DS
  427. sll t6, v1 // DataCacheSetSize
  428. sll t6, t7 // t5 DataCacheSize
  429. ####part 3####
  430. lui a0, 0x8000 //a0 = 0x8000 << 16
  431. addu a1, $0, t5
  432. addu a2, $0, t6
  433. cache_init_d2way:
  434. /* a0=0x80000000, a1=icache_size, a2=dcache_size */
  435. /* a3, v0 and v1 used as local registers */
  436. mtc0 $0, CP0_TAGHI
  437. addu v0, $0, a0 /* v0 = 0 + a0 */
  438. addu v1, a0, a2 /* v1 = a0 + a2 */
  439. 1: slt a3, v0, v1 /* a3 = v0 < v1 ? 1 : 0 */
  440. beq a3, $0, 1f /* if (a3 == 0) goto 1f */
  441. nop
  442. mtc0 $0, CP0_TAGLO
  443. cache Index_Store_Tag_D, 0x0(v0) /* 1 way */
  444. 4: beq $0, $0, 1b
  445. addiu v0, v0, 0x20
  446. 1:
  447. cache_flush_i2way:
  448. addu v0, $0, a0
  449. addu v1, a0, a1
  450. 1:
  451. slt a3, v0, v1
  452. beq a3, $0, 1f
  453. nop
  454. cache Index_Invalidate_I, 0x0(v0) /* 1 way */
  455. 4:
  456. beq $0, $0, 1b
  457. addiu v0, v0, 0x20
  458. 1:
  459. cache_flush_d2way:
  460. addu v0, $0, a0
  461. addu v1, a0, a2
  462. 1: slt a3, v0, v1
  463. beq a3, $0, 1f
  464. nop
  465. cache Index_Writeback_Inv_D, 0x0(v0) /* 1 way */
  466. 4: beq $0, $0, 1b
  467. addiu v0, v0, 0x20
  468. 1:
  469. cache_init_finish:
  470. jr t1
  471. nop
  472. #endif