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