• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
36secondary_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#ifdef CONFIG_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#endif
62
63#ifdef CONFIG_SMP
64	/* set xSIE bit to receive IPIs */
65#if CONFIG_IS_ENABLED(RISCV_MMODE)
66	li	t0, MIE_MSIE
67#else
68	li	t0, SIE_SSIE
69#endif
70	csrs	MODE_PREFIX(ie), t0
71#endif
72
73/*
74 * Set stackpointer in internal/ex RAM to call board_init_f
75 */
76call_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
85call_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#ifdef CONFIG_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	/* save the boot hart id to global_data */
125	SREG	tp, GD_BOOT_HART(gp)
126
127#ifndef CONFIG_XIP
128	la	t0, available_harts_lock
129	fence	rw, w
130	amoswap.w zero, zero, 0(t0)
131
132wait_for_gd_init:
133	la	t0, available_harts_lock
134	li	t1, 1
1351:	amoswap.w t1, t1, 0(t0)
136	fence	r, rw
137	bnez	t1, 1b
138
139	/* register available harts in the available_harts mask */
140	li	t1, 1
141	sll	t1, t1, tp
142	LREG	t2, GD_AVAILABLE_HARTS(gp)
143	or	t2, t2, t1
144	SREG	t2, GD_AVAILABLE_HARTS(gp)
145
146	fence	rw, w
147	amoswap.w zero, zero, 0(t0)
148
149	/*
150	 * Continue on hart lottery winner, others branch to
151	 * secondary_hart_loop.
152	 */
153	bnez	s2, secondary_hart_loop
154#endif
155
156	/* Enable cache */
157	jal	icache_enable
158	jal	dcache_enable
159
160#ifdef CONFIG_DEBUG_UART
161	jal	debug_uart_init
162#endif
163
164	mv	a0, zero		/* a0 <-- boot_flags = 0 */
165	la	t5, board_init_f
166	jalr	t5			/* jump to board_init_f() */
167
168#ifdef CONFIG_SPL_BUILD
169spl_clear_bss:
170	la	t0, __bss_start
171	la	t1, __bss_end
172	beq	t0, t1, spl_stack_gd_setup
173
174spl_clear_bss_loop:
175	SREG	zero, 0(t0)
176	addi	t0, t0, REGBYTES
177	blt	t0, t1, spl_clear_bss_loop
178
179spl_stack_gd_setup:
180	jal	spl_relocate_stack_gd
181
182	/* skip setup if we did not relocate */
183	beqz	a0, spl_call_board_init_r
184	mv	s0, a0
185
186	/* setup stack on main hart */
187#ifdef CONFIG_SMP
188	/* tp: hart id */
189	slli	t0, tp, CONFIG_STACK_SIZE_SHIFT
190	sub	sp, s0, t0
191#else
192	mv	sp, s0
193#endif
194
195	/* set new stack and global data pointer on secondary harts */
196spl_secondary_hart_stack_gd_setup:
197	la	a0, secondary_hart_relocate
198	mv	a1, s0
199	mv	a2, s0
200	mv	a3, zero
201	jal	smp_call_function
202
203	/* hang if relocation of secondary harts has failed */
204	beqz	a0, 1f
205	mv	a1, a0
206	la	a0, secondary_harts_relocation_error
207	jal	printf
208	jal	hang
209
210	/* set new global data pointer on main hart */
2111:	mv	gp, s0
212
213spl_call_board_init_r:
214	mv	a0, zero
215	mv	a1, zero
216	jal	board_init_r
217#endif
218
219/*
220 * void relocate_code (addr_sp, gd, addr_moni)
221 *
222 * This "function" does not return, instead it continues in RAM
223 * after relocating the monitor code.
224 *
225 */
226.globl relocate_code
227relocate_code:
228	mv	s2, a0			/* save addr_sp */
229	mv	s3, a1			/* save addr of gd */
230	mv	s4, a2			/* save addr of destination */
231
232/*
233 *Set up the stack
234 */
235stack_setup:
236#ifdef CONFIG_SMP
237	/* tp: hart id */
238	slli	t0, tp, CONFIG_STACK_SIZE_SHIFT
239	sub	sp, s2, t0
240#else
241	mv	sp, s2
242#endif
243
244	la	t0, _start
245	sub	t6, s4, t0		/* t6 <- relocation offset */
246	beq	t0, s4, clear_bss	/* skip relocation */
247
248	mv	t1, s4			/* t1 <- scratch for copy_loop */
249	la	t3, __bss_start
250	sub	t3, t3, t0		/* t3 <- __bss_start_ofs */
251	add	t2, t0, t3		/* t2 <- source end address */
252
253copy_loop:
254	LREG	t5, 0(t0)
255	addi	t0, t0, REGBYTES
256	SREG	t5, 0(t1)
257	addi	t1, t1, REGBYTES
258	blt	t0, t2, copy_loop
259
260/*
261 * Update dynamic relocations after board_init_f
262 */
263fix_rela_dyn:
264	la	t1, __rel_dyn_start
265	la	t2, __rel_dyn_end
266	beq	t1, t2, clear_bss
267	add	t1, t1, t6		/* t1 <- rela_dyn_start in RAM */
268	add	t2, t2, t6		/* t2 <- rela_dyn_end in RAM */
269
270/*
271 * skip first reserved entry: address, type, addend
272 */
273	j	10f
274
2756:
276	LREG	t5, -(REGBYTES*2)(t1)	/* t5 <-- relocation info:type */
277	li	t3, R_RISCV_RELATIVE	/* reloc type R_RISCV_RELATIVE */
278	bne	t5, t3, 8f		/* skip non-RISCV_RELOC entries */
279	LREG	t3, -(REGBYTES*3)(t1)
280	LREG	t5, -(REGBYTES)(t1)	/* t5 <-- addend */
281	add	t5, t5, t6		/* t5 <-- location to fix up in RAM */
282	add	t3, t3, t6		/* t3 <-- location to fix up in RAM */
283	SREG	t5, 0(t3)
284	j	10f
285
2868:
287	la	t4, __dyn_sym_start
288	add	t4, t4, t6
289
2909:
291	LREG	t5, -(REGBYTES*2)(t1)	/* t5 <-- relocation info:type */
292	srli	t0, t5, SYM_INDEX	/* t0 <--- sym table index */
293	andi	t5, t5, 0xFF		/* t5 <--- relocation type */
294	li	t3, RELOC_TYPE
295	bne	t5, t3, 10f		/* skip non-addned entries */
296
297	LREG	t3, -(REGBYTES*3)(t1)
298	li	t5, SYM_SIZE
299	mul	t0, t0, t5
300	add	s5, t4, t0
301	LREG	t0, -(REGBYTES)(t1)	/* t0 <-- addend */
302	LREG	t5, REGBYTES(s5)
303	add	t5, t5, t0
304	add	t5, t5, t6		/* t5 <-- location to fix up in RAM */
305	add	t3, t3, t6		/* t3 <-- location to fix up in RAM */
306	SREG	t5, 0(t3)
30710:
308	addi	t1, t1, (REGBYTES*3)
309	ble	t1, t2, 6b
310
311/*
312 * trap update
313*/
314	la	t0, trap_entry
315	add	t0, t0, t6
316	csrw	MODE_PREFIX(tvec), t0
317
318clear_bss:
319	la	t0, __bss_start		/* t0 <- rel __bss_start in FLASH */
320	add	t0, t0, t6		/* t0 <- rel __bss_start in RAM */
321	la	t1, __bss_end		/* t1 <- rel __bss_end in FLASH */
322	add	t1, t1, t6		/* t1 <- rel __bss_end in RAM */
323	beq	t0, t1, relocate_secondary_harts
324
325clbss_l:
326	SREG	zero, 0(t0)		/* clear loop... */
327	addi	t0, t0, REGBYTES
328	blt	t0, t1, clbss_l
329
330relocate_secondary_harts:
331#ifdef CONFIG_SMP
332	/* send relocation IPI */
333	la	t0, secondary_hart_relocate
334	add	a0, t0, t6
335
336	/* store relocation offset */
337	mv	s5, t6
338
339	mv	a1, s2
340	mv	a2, s3
341	mv	a3, zero
342	jal	smp_call_function
343
344	/* hang if relocation of secondary harts has failed */
345	beqz	a0, 1f
346	mv	a1, a0
347	la	a0, secondary_harts_relocation_error
348	jal	printf
349	jal	hang
350
351	/* restore relocation offset */
3521:	mv	t6, s5
353#endif
354
355/*
356 * We are done. Do not return, instead branch to second part of board
357 * initialization, now running from RAM.
358 */
359call_board_init_r:
360	jal	invalidate_icache_all
361	jal	flush_dcache_all
362	la	t0, board_init_r
363	mv	t4, t0			/* offset of board_init_r() */
364	add	t4, t4, t6		/* real address of board_init_r() */
365/*
366 * setup parameters for board_init_r
367 */
368	mv	a0, s3			/* gd_t */
369	mv	a1, s4			/* dest_addr */
370
371/*
372 * jump to it ...
373 */
374	jr	t4			/* jump to board_init_r() */
375
376#ifdef CONFIG_SMP
377hart_out_of_bounds_loop:
378	/* Harts in this loop are out of bounds, increase CONFIG_NR_CPUS. */
379	wfi
380	j	hart_out_of_bounds_loop
381#endif
382
383#ifdef CONFIG_SMP
384/* SMP relocation entry */
385secondary_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
398secondary_hart_loop:
399	wfi
400
401#ifdef CONFIG_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
415