Merge https://gitlab.denx.de/u-boot/custodians/u-boot-riscv
[platform/kernel/u-boot.git] / arch / riscv / cpu / start.S
1 /* SPDX-License-Identifier: GPL-2.0+ */
2 /*
3  * Startup Code for RISC-V Core
4  *
5  * Copyright (c) 2017 Microsemi Corporation.
6  * Copyright (c) 2017 Padmarao Begari <Padmarao.Begari@microsemi.com>
7  *
8  * Copyright (C) 2017 Andes Technology Corporation
9  * Rick Chen, Andes Technology Corporation <rick@andestech.com>
10  */
11
12 #include <asm-offsets.h>
13 #include <config.h>
14 #include <common.h>
15 #include <elf.h>
16 #include <asm/encoding.h>
17 #include <generated/asm-offsets.h>
18
19 #ifdef CONFIG_32BIT
20 #define LREG                    lw
21 #define SREG                    sw
22 #define REGBYTES                4
23 #define RELOC_TYPE              R_RISCV_32
24 #define SYM_INDEX               0x8
25 #define SYM_SIZE                0x10
26 #else
27 #define LREG                    ld
28 #define SREG                    sd
29 #define REGBYTES                8
30 #define RELOC_TYPE              R_RISCV_64
31 #define SYM_INDEX               0x20
32 #define SYM_SIZE                0x18
33 #endif
34
35 .section .data
36 secondary_harts_relocation_error:
37         .ascii "Relocation of secondary harts has failed, error %d\n"
38
39 .section .text
40 .globl _start
41 _start:
42 #if CONFIG_IS_ENABLED(RISCV_MMODE)
43         csrr    a0, CSR_MHARTID
44 #endif
45
46         /* save hart id and dtb pointer */
47         mv      tp, a0
48         mv      s1, a1
49
50         la      t0, trap_entry
51         csrw    MODE_PREFIX(tvec), t0
52
53         /* mask all interrupts */
54         csrw    MODE_PREFIX(ie), zero
55
56 #if CONFIG_IS_ENABLED(SMP)
57         /* check if hart is within range */
58         /* tp: hart id */
59         li      t0, CONFIG_NR_CPUS
60         bge     tp, t0, hart_out_of_bounds_loop
61
62         /* set xSIE bit to receive IPIs */
63 #if CONFIG_IS_ENABLED(RISCV_MMODE)
64         li      t0, MIE_MSIE
65 #else
66         li      t0, SIE_SSIE
67 #endif
68         /* Clear any pending IPIs */
69         csrc    MODE_PREFIX(ip), t0
70         csrs    MODE_PREFIX(ie), t0
71 #endif
72
73 /*
74  * Set stackpointer in internal/ex RAM to call board_init_f
75  */
76 call_board_init_f:
77         li      t0, -16
78 #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
79         li      t1, CONFIG_SPL_STACK
80 #else
81         li      t1, CONFIG_SYS_INIT_SP_ADDR
82 #endif
83         and     sp, t1, t0              /* force 16 byte alignment */
84
85 call_board_init_f_0:
86         mv      a0, sp
87         jal     board_init_f_alloc_reserve
88
89         /*
90          * Set global data pointer here for all harts, uninitialized at this
91          * point.
92          */
93         mv      gp, a0
94
95         /* setup stack */
96 #if CONFIG_IS_ENABLED(SMP)
97         /* tp: hart id */
98         slli    t0, tp, CONFIG_STACK_SIZE_SHIFT
99         sub     sp, a0, t0
100 #else
101         mv      sp, a0
102 #endif
103
104 #ifndef CONFIG_XIP
105         /*
106          * Pick hart to initialize global data and run U-Boot. The other harts
107          * wait for initialization to complete.
108          */
109         la      t0, hart_lottery
110         li      s2, 1
111         amoswap.w s2, t1, 0(t0)
112         bnez    s2, wait_for_gd_init
113 #else
114         bnez    tp, secondary_hart_loop
115 #endif
116
117 #ifdef CONFIG_OF_PRIOR_STAGE
118         la      t0, prior_stage_fdt_address
119         SREG    s1, 0(t0)
120 #endif
121
122         jal     board_init_f_init_reserve
123
124         SREG    s1, GD_FIRMWARE_FDT_ADDR(gp)
125         /* save the boot hart id to global_data */
126         SREG    tp, GD_BOOT_HART(gp)
127
128 #ifndef CONFIG_XIP
129         la      t0, available_harts_lock
130         fence   rw, w
131         amoswap.w zero, zero, 0(t0)
132
133 wait_for_gd_init:
134         la      t0, available_harts_lock
135         li      t1, 1
136 1:      amoswap.w t1, t1, 0(t0)
137         fence   r, rw
138         bnez    t1, 1b
139
140         /* register available harts in the available_harts mask */
141         li      t1, 1
142         sll     t1, t1, tp
143         LREG    t2, GD_AVAILABLE_HARTS(gp)
144         or      t2, t2, t1
145         SREG    t2, GD_AVAILABLE_HARTS(gp)
146
147         fence   rw, w
148         amoswap.w zero, zero, 0(t0)
149
150         /*
151          * Continue on hart lottery winner, others branch to
152          * secondary_hart_loop.
153          */
154         bnez    s2, secondary_hart_loop
155 #endif
156
157         /* Enable cache */
158         jal     icache_enable
159         jal     dcache_enable
160
161 #ifdef CONFIG_DEBUG_UART
162         jal     debug_uart_init
163 #endif
164
165         mv      a0, zero                /* a0 <-- boot_flags = 0 */
166         la      t5, board_init_f
167         jalr    t5                      /* jump to board_init_f() */
168
169 #ifdef CONFIG_SPL_BUILD
170 spl_clear_bss:
171         la      t0, __bss_start
172         la      t1, __bss_end
173         beq     t0, t1, spl_stack_gd_setup
174
175 spl_clear_bss_loop:
176         SREG    zero, 0(t0)
177         addi    t0, t0, REGBYTES
178         blt     t0, t1, spl_clear_bss_loop
179
180 spl_stack_gd_setup:
181         jal     spl_relocate_stack_gd
182
183         /* skip setup if we did not relocate */
184         beqz    a0, spl_call_board_init_r
185         mv      s0, a0
186
187         /* setup stack on main hart */
188 #if CONFIG_IS_ENABLED(SMP)
189         /* tp: hart id */
190         slli    t0, tp, CONFIG_STACK_SIZE_SHIFT
191         sub     sp, s0, t0
192 #else
193         mv      sp, s0
194 #endif
195
196 #if CONFIG_IS_ENABLED(SMP)
197         /* set new stack and global data pointer on secondary harts */
198 spl_secondary_hart_stack_gd_setup:
199         la      a0, secondary_hart_relocate
200         mv      a1, s0
201         mv      a2, s0
202         mv      a3, zero
203         jal     smp_call_function
204
205         /* hang if relocation of secondary harts has failed */
206         beqz    a0, 1f
207         mv      a1, a0
208         la      a0, secondary_harts_relocation_error
209         jal     printf
210         jal     hang
211 #endif
212
213         /* set new global data pointer on main hart */
214 1:      mv      gp, s0
215
216 spl_call_board_init_r:
217         mv      a0, zero
218         mv      a1, zero
219         jal     board_init_r
220 #endif
221
222 /*
223  * void relocate_code(addr_sp, gd, addr_moni)
224  *
225  * This "function" does not return, instead it continues in RAM
226  * after relocating the monitor code.
227  *
228  */
229 .globl relocate_code
230 relocate_code:
231         mv      s2, a0                  /* save addr_sp */
232         mv      s3, a1                  /* save addr of gd */
233         mv      s4, a2                  /* save addr of destination */
234
235 /*
236  *Set up the stack
237  */
238 stack_setup:
239 #if CONFIG_IS_ENABLED(SMP)
240         /* tp: hart id */
241         slli    t0, tp, CONFIG_STACK_SIZE_SHIFT
242         sub     sp, s2, t0
243 #else
244         mv      sp, s2
245 #endif
246
247         la      t0, _start
248         sub     t6, s4, t0              /* t6 <- relocation offset */
249         beq     t0, s4, clear_bss       /* skip relocation */
250
251         mv      t1, s4                  /* t1 <- scratch for copy_loop */
252         la      t3, __bss_start
253         sub     t3, t3, t0              /* t3 <- __bss_start_ofs */
254         add     t2, t0, t3              /* t2 <- source end address */
255
256 copy_loop:
257         LREG    t5, 0(t0)
258         addi    t0, t0, REGBYTES
259         SREG    t5, 0(t1)
260         addi    t1, t1, REGBYTES
261         blt     t0, t2, copy_loop
262
263 /*
264  * Update dynamic relocations after board_init_f
265  */
266 fix_rela_dyn:
267         la      t1, __rel_dyn_start
268         la      t2, __rel_dyn_end
269         beq     t1, t2, clear_bss
270         add     t1, t1, t6              /* t1 <- rela_dyn_start in RAM */
271         add     t2, t2, t6              /* t2 <- rela_dyn_end in RAM */
272
273 /*
274  * skip first reserved entry: address, type, addend
275  */
276         j       10f
277
278 6:
279         LREG    t5, -(REGBYTES*2)(t1)   /* t5 <-- relocation info:type */
280         li      t3, R_RISCV_RELATIVE    /* reloc type R_RISCV_RELATIVE */
281         bne     t5, t3, 8f              /* skip non-RISCV_RELOC entries */
282         LREG    t3, -(REGBYTES*3)(t1)
283         LREG    t5, -(REGBYTES)(t1)     /* t5 <-- addend */
284         add     t5, t5, t6              /* t5 <-- location to fix up in RAM */
285         add     t3, t3, t6              /* t3 <-- location to fix up in RAM */
286         SREG    t5, 0(t3)
287         j       10f
288
289 8:
290         la      t4, __dyn_sym_start
291         add     t4, t4, t6
292
293 9:
294         LREG    t5, -(REGBYTES*2)(t1)   /* t5 <-- relocation info:type */
295         srli    t0, t5, SYM_INDEX       /* t0 <--- sym table index */
296         andi    t5, t5, 0xFF            /* t5 <--- relocation type */
297         li      t3, RELOC_TYPE
298         bne     t5, t3, 10f             /* skip non-addned entries */
299
300         LREG    t3, -(REGBYTES*3)(t1)
301         li      t5, SYM_SIZE
302         mul     t0, t0, t5
303         add     s5, t4, t0
304         LREG    t0, -(REGBYTES)(t1)     /* t0 <-- addend */
305         LREG    t5, REGBYTES(s5)
306         add     t5, t5, t0
307         add     t5, t5, t6              /* t5 <-- location to fix up in RAM */
308         add     t3, t3, t6              /* t3 <-- location to fix up in RAM */
309         SREG    t5, 0(t3)
310 10:
311         addi    t1, t1, (REGBYTES*3)
312         ble     t1, t2, 6b
313
314 /*
315  * trap update
316 */
317         la      t0, trap_entry
318         add     t0, t0, t6
319         csrw    MODE_PREFIX(tvec), t0
320
321 clear_bss:
322         la      t0, __bss_start         /* t0 <- rel __bss_start in FLASH */
323         add     t0, t0, t6              /* t0 <- rel __bss_start in RAM */
324         la      t1, __bss_end           /* t1 <- rel __bss_end in FLASH */
325         add     t1, t1, t6              /* t1 <- rel __bss_end in RAM */
326         beq     t0, t1, relocate_secondary_harts
327
328 clbss_l:
329         SREG    zero, 0(t0)             /* clear loop... */
330         addi    t0, t0, REGBYTES
331         blt     t0, t1, clbss_l
332
333 relocate_secondary_harts:
334 #if CONFIG_IS_ENABLED(SMP)
335         /* send relocation IPI */
336         la      t0, secondary_hart_relocate
337         add     a0, t0, t6
338
339         /* store relocation offset */
340         mv      s5, t6
341
342         mv      a1, s2
343         mv      a2, s3
344         mv      a3, zero
345         jal     smp_call_function
346
347         /* hang if relocation of secondary harts has failed */
348         beqz    a0, 1f
349         mv      a1, a0
350         la      a0, secondary_harts_relocation_error
351         jal     printf
352         jal     hang
353
354         /* restore relocation offset */
355 1:      mv      t6, s5
356 #endif
357
358 /*
359  * We are done. Do not return, instead branch to second part of board
360  * initialization, now running from RAM.
361  */
362 call_board_init_r:
363         jal     invalidate_icache_all
364         jal     flush_dcache_all
365         la      t0, board_init_r        /* offset of board_init_r() */
366         add     t4, t0, t6              /* real address of board_init_r() */
367 /*
368  * setup parameters for board_init_r
369  */
370         mv      a0, s3                  /* gd_t */
371         mv      a1, s4                  /* dest_addr */
372
373 /*
374  * jump to it ...
375  */
376         jr      t4                      /* jump to board_init_r() */
377
378 #if CONFIG_IS_ENABLED(SMP)
379 hart_out_of_bounds_loop:
380         /* Harts in this loop are out of bounds, increase CONFIG_NR_CPUS. */
381         wfi
382         j       hart_out_of_bounds_loop
383
384 /* SMP relocation entry */
385 secondary_hart_relocate:
386         /* a1: new sp */
387         /* a2: new gd */
388         /* tp: hart id */
389
390         /* setup stack */
391         slli    t0, tp, CONFIG_STACK_SIZE_SHIFT
392         sub     sp, a1, t0
393
394         /* update global data pointer */
395         mv      gp, a2
396 #endif
397
398 secondary_hart_loop:
399         wfi
400
401 #if CONFIG_IS_ENABLED(SMP)
402         csrr    t0, MODE_PREFIX(ip)
403 #if CONFIG_IS_ENABLED(RISCV_MMODE)
404         andi    t0, t0, MIE_MSIE
405 #else
406         andi    t0, t0, SIE_SSIE
407 #endif
408         beqz    t0, secondary_hart_loop
409
410         mv      a0, tp
411         jal     handle_ipi
412 #endif
413
414         j       secondary_hart_loop