308b0a97a58fa0ad81af39c9a9aa39c59ce849a6
[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         /*
47          * Save hart id and dtb pointer. The thread pointer register is not
48          * modified by C code. It is used by secondary_hart_loop.
49          */
50         mv      tp, a0
51         mv      s1, a1
52
53         /*
54          * Set the global data pointer to a known value in case we get a very
55          * early trap. The global data pointer will be set its actual value only
56          * after it has been initialized.
57          */
58         mv      gp, zero
59
60         /*
61          * Set the trap handler. This must happen after initializing gp because
62          * the handler may use it.
63          */
64         la      t0, trap_entry
65         csrw    MODE_PREFIX(tvec), t0
66
67         /*
68          * Mask all interrupts. Interrupts are disabled globally (in m/sstatus)
69          * for U-Boot, but we will need to read m/sip to determine if we get an
70          * IPI
71          */
72         csrw    MODE_PREFIX(ie), zero
73
74 #if CONFIG_IS_ENABLED(SMP)
75         /* check if hart is within range */
76         /* tp: hart id */
77         li      t0, CONFIG_NR_CPUS
78         bge     tp, t0, hart_out_of_bounds_loop
79
80         /* set xSIE bit to receive IPIs */
81 #if CONFIG_IS_ENABLED(RISCV_MMODE)
82         li      t0, MIE_MSIE
83 #else
84         li      t0, SIE_SSIE
85 #endif
86         csrs    MODE_PREFIX(ie), t0
87 #endif
88
89 /*
90  * Set stackpointer in internal/ex RAM to call board_init_f
91  */
92 call_board_init_f:
93         li      t0, -16
94 #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
95         li      t1, CONFIG_SPL_STACK
96 #else
97         li      t1, CONFIG_SYS_INIT_SP_ADDR
98 #endif
99         and     sp, t1, t0              /* force 16 byte alignment */
100
101 call_board_init_f_0:
102         mv      a0, sp
103         jal     board_init_f_alloc_reserve
104
105         /*
106          * Save global data pointer for later. We don't set it here because it
107          * is not initialized yet.
108          */
109         mv      s0, a0
110
111         /* setup stack */
112 #if CONFIG_IS_ENABLED(SMP)
113         /* tp: hart id */
114         slli    t0, tp, CONFIG_STACK_SIZE_SHIFT
115         sub     sp, a0, t0
116 #else
117         mv      sp, a0
118 #endif
119
120         /* Configure proprietary settings and customized CSRs of harts */
121 call_harts_early_init:
122         jal     harts_early_init
123
124 #ifndef CONFIG_XIP
125         /*
126          * Pick hart to initialize global data and run U-Boot. The other harts
127          * wait for initialization to complete.
128          */
129         la      t0, hart_lottery
130         li      t1, 1
131         amoswap.w s2, t1, 0(t0)
132         bnez    s2, wait_for_gd_init
133 #else
134         /*
135          * FIXME: gp is set before it is initialized. If an XIP U-Boot ever
136          * encounters a pending IPI on boot it is liable to jump to whatever
137          * memory happens to be in ipi_data.addr on boot. It may also run into
138          * problems if it encounters an exception too early (because printf/puts
139          * accesses gd).
140          */
141         mv      gp, s0
142         bnez    tp, secondary_hart_loop
143 #endif
144
145 #ifdef CONFIG_OF_PRIOR_STAGE
146         la      t0, prior_stage_fdt_address
147         SREG    s1, 0(t0)
148 #endif
149
150         jal     board_init_f_init_reserve
151
152         SREG    s1, GD_FIRMWARE_FDT_ADDR(gp)
153         /* save the boot hart id to global_data */
154         SREG    tp, GD_BOOT_HART(gp)
155
156 #ifndef CONFIG_XIP
157         la      t0, available_harts_lock
158         amoswap.w.rl zero, zero, 0(t0)
159
160 wait_for_gd_init:
161         la      t0, available_harts_lock
162         li      t1, 1
163 1:      amoswap.w.aq t1, t1, 0(t0)
164         bnez    t1, 1b
165
166         /*
167          * Set the global data pointer only when gd_t has been initialized.
168          * This was already set by arch_setup_gd on the boot hart, but all other
169          * harts' global data pointers gets set here.
170          */
171         mv      gp, s0
172
173         /* register available harts in the available_harts mask */
174         li      t1, 1
175         sll     t1, t1, tp
176         LREG    t2, GD_AVAILABLE_HARTS(gp)
177         or      t2, t2, t1
178         SREG    t2, GD_AVAILABLE_HARTS(gp)
179
180         amoswap.w.rl zero, zero, 0(t0)
181
182         /*
183          * Continue on hart lottery winner, others branch to
184          * secondary_hart_loop.
185          */
186         bnez    s2, secondary_hart_loop
187 #endif
188
189         /* Enable cache */
190         jal     icache_enable
191         jal     dcache_enable
192
193 #ifdef CONFIG_DEBUG_UART
194         jal     debug_uart_init
195 #endif
196
197         mv      a0, zero                /* a0 <-- boot_flags = 0 */
198         la      t5, board_init_f
199         jalr    t5                      /* jump to board_init_f() */
200
201 #ifdef CONFIG_SPL_BUILD
202 spl_clear_bss:
203         la      t0, __bss_start
204         la      t1, __bss_end
205         beq     t0, t1, spl_stack_gd_setup
206
207 spl_clear_bss_loop:
208         SREG    zero, 0(t0)
209         addi    t0, t0, REGBYTES
210         blt     t0, t1, spl_clear_bss_loop
211
212 spl_stack_gd_setup:
213         jal     spl_relocate_stack_gd
214
215         /* skip setup if we did not relocate */
216         beqz    a0, spl_call_board_init_r
217         mv      s0, a0
218
219         /* setup stack on main hart */
220 #if CONFIG_IS_ENABLED(SMP)
221         /* tp: hart id */
222         slli    t0, tp, CONFIG_STACK_SIZE_SHIFT
223         sub     sp, s0, t0
224 #else
225         mv      sp, s0
226 #endif
227
228 #if CONFIG_IS_ENABLED(SMP)
229         /* set new stack and global data pointer on secondary harts */
230 spl_secondary_hart_stack_gd_setup:
231         la      a0, secondary_hart_relocate
232         mv      a1, s0
233         mv      a2, s0
234         mv      a3, zero
235         jal     smp_call_function
236
237         /* hang if relocation of secondary harts has failed */
238         beqz    a0, 1f
239         mv      a1, a0
240         la      a0, secondary_harts_relocation_error
241         jal     printf
242         jal     hang
243 #endif
244
245         /* set new global data pointer on main hart */
246 1:      mv      gp, s0
247
248 spl_call_board_init_r:
249         mv      a0, zero
250         mv      a1, zero
251         jal     board_init_r
252 #endif
253
254 /*
255  * void relocate_code(addr_sp, gd, addr_moni)
256  *
257  * This "function" does not return, instead it continues in RAM
258  * after relocating the monitor code.
259  *
260  */
261 .globl relocate_code
262 relocate_code:
263         mv      s2, a0                  /* save addr_sp */
264         mv      s3, a1                  /* save addr of gd */
265         mv      s4, a2                  /* save addr of destination */
266
267 /*
268  *Set up the stack
269  */
270 stack_setup:
271 #if CONFIG_IS_ENABLED(SMP)
272         /* tp: hart id */
273         slli    t0, tp, CONFIG_STACK_SIZE_SHIFT
274         sub     sp, s2, t0
275 #else
276         mv      sp, s2
277 #endif
278
279         la      t0, _start
280         sub     t6, s4, t0              /* t6 <- relocation offset */
281         beq     t0, s4, clear_bss       /* skip relocation */
282
283         mv      t1, s4                  /* t1 <- scratch for copy_loop */
284         la      t3, __bss_start
285         sub     t3, t3, t0              /* t3 <- __bss_start_ofs */
286         add     t2, t0, t3              /* t2 <- source end address */
287
288 copy_loop:
289         LREG    t5, 0(t0)
290         addi    t0, t0, REGBYTES
291         SREG    t5, 0(t1)
292         addi    t1, t1, REGBYTES
293         blt     t0, t2, copy_loop
294
295 /*
296  * Update dynamic relocations after board_init_f
297  */
298 fix_rela_dyn:
299         la      t1, __rel_dyn_start
300         la      t2, __rel_dyn_end
301         beq     t1, t2, clear_bss
302         add     t1, t1, t6              /* t1 <- rela_dyn_start in RAM */
303         add     t2, t2, t6              /* t2 <- rela_dyn_end in RAM */
304
305 /*
306  * skip first reserved entry: address, type, addend
307  */
308         j       10f
309
310 6:
311         LREG    t5, -(REGBYTES*2)(t1)   /* t5 <-- relocation info:type */
312         li      t3, R_RISCV_RELATIVE    /* reloc type R_RISCV_RELATIVE */
313         bne     t5, t3, 8f              /* skip non-RISCV_RELOC entries */
314         LREG    t3, -(REGBYTES*3)(t1)
315         LREG    t5, -(REGBYTES)(t1)     /* t5 <-- addend */
316         add     t5, t5, t6              /* t5 <-- location to fix up in RAM */
317         add     t3, t3, t6              /* t3 <-- location to fix up in RAM */
318         SREG    t5, 0(t3)
319         j       10f
320
321 8:
322         la      t4, __dyn_sym_start
323         add     t4, t4, t6
324
325 9:
326         LREG    t5, -(REGBYTES*2)(t1)   /* t5 <-- relocation info:type */
327         srli    t0, t5, SYM_INDEX       /* t0 <--- sym table index */
328         andi    t5, t5, 0xFF            /* t5 <--- relocation type */
329         li      t3, RELOC_TYPE
330         bne     t5, t3, 10f             /* skip non-addned entries */
331
332         LREG    t3, -(REGBYTES*3)(t1)
333         li      t5, SYM_SIZE
334         mul     t0, t0, t5
335         add     s5, t4, t0
336         LREG    t0, -(REGBYTES)(t1)     /* t0 <-- addend */
337         LREG    t5, REGBYTES(s5)
338         add     t5, t5, t0
339         add     t5, t5, t6              /* t5 <-- location to fix up in RAM */
340         add     t3, t3, t6              /* t3 <-- location to fix up in RAM */
341         SREG    t5, 0(t3)
342 10:
343         addi    t1, t1, (REGBYTES*3)
344         ble     t1, t2, 6b
345
346 /*
347  * trap update
348 */
349         la      t0, trap_entry
350         add     t0, t0, t6
351         csrw    MODE_PREFIX(tvec), t0
352
353 clear_bss:
354         la      t0, __bss_start         /* t0 <- rel __bss_start in FLASH */
355         add     t0, t0, t6              /* t0 <- rel __bss_start in RAM */
356         la      t1, __bss_end           /* t1 <- rel __bss_end in FLASH */
357         add     t1, t1, t6              /* t1 <- rel __bss_end in RAM */
358         beq     t0, t1, relocate_secondary_harts
359
360 clbss_l:
361         SREG    zero, 0(t0)             /* clear loop... */
362         addi    t0, t0, REGBYTES
363         blt     t0, t1, clbss_l
364
365 relocate_secondary_harts:
366 #if CONFIG_IS_ENABLED(SMP)
367         /* send relocation IPI */
368         la      t0, secondary_hart_relocate
369         add     a0, t0, t6
370
371         /* store relocation offset */
372         mv      s5, t6
373
374         mv      a1, s2
375         mv      a2, s3
376         mv      a3, zero
377         jal     smp_call_function
378
379         /* hang if relocation of secondary harts has failed */
380         beqz    a0, 1f
381         mv      a1, a0
382         la      a0, secondary_harts_relocation_error
383         jal     printf
384         jal     hang
385
386         /* restore relocation offset */
387 1:      mv      t6, s5
388 #endif
389
390 /*
391  * We are done. Do not return, instead branch to second part of board
392  * initialization, now running from RAM.
393  */
394 call_board_init_r:
395         jal     invalidate_icache_all
396         jal     flush_dcache_all
397         la      t0, board_init_r        /* offset of board_init_r() */
398         add     t4, t0, t6              /* real address of board_init_r() */
399 /*
400  * setup parameters for board_init_r
401  */
402         mv      a0, s3                  /* gd_t */
403         mv      a1, s4                  /* dest_addr */
404
405 /*
406  * jump to it ...
407  */
408         jr      t4                      /* jump to board_init_r() */
409
410 #if CONFIG_IS_ENABLED(SMP)
411 hart_out_of_bounds_loop:
412         /* Harts in this loop are out of bounds, increase CONFIG_NR_CPUS. */
413         wfi
414         j       hart_out_of_bounds_loop
415
416 /* SMP relocation entry */
417 secondary_hart_relocate:
418         /* a1: new sp */
419         /* a2: new gd */
420         /* tp: hart id */
421
422         /* setup stack */
423         slli    t0, tp, CONFIG_STACK_SIZE_SHIFT
424         sub     sp, a1, t0
425
426         /* update global data pointer */
427         mv      gp, a2
428 #endif
429
430 /*
431  * Interrupts are disabled globally, but they can still be read from m/sip. The
432  * wfi function will wake us up if we get an IPI, even if we do not trap.
433  */
434 secondary_hart_loop:
435         wfi
436
437 #if CONFIG_IS_ENABLED(SMP)
438         csrr    t0, MODE_PREFIX(ip)
439 #if CONFIG_IS_ENABLED(RISCV_MMODE)
440         andi    t0, t0, MIE_MSIE
441 #else
442         andi    t0, t0, SIE_SSIE
443 #endif
444         beqz    t0, secondary_hart_loop
445
446         mv      a0, tp
447         jal     handle_ipi
448 #endif
449
450         j       secondary_hart_loop