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 .text
36.globl _start
37_start:
38	/* save hart id and dtb pointer */
39	mv	s0, a0
40	mv	s1, a1
41
42	la	t0, trap_entry
43	csrw	MODE_PREFIX(tvec), t0
44
45	/* mask all interrupts */
46	csrw	MODE_PREFIX(ie), zero
47
48	/* Enable cache */
49	jal	icache_enable
50	jal	dcache_enable
51
52/*
53 * Set stackpointer in internal/ex RAM to call board_init_f
54 */
55call_board_init_f:
56	li	t0, -16
57	li	t1, CONFIG_SYS_INIT_SP_ADDR
58	and	sp, t1, t0		/* force 16 byte alignment */
59
60#ifdef CONFIG_DEBUG_UART
61	jal	debug_uart_init
62#endif
63
64call_board_init_f_0:
65	mv	a0, sp
66	jal	board_init_f_alloc_reserve
67	mv	sp, a0
68
69	la	t0, prior_stage_fdt_address
70	SREG	s1, 0(t0)
71
72	jal	board_init_f_init_reserve
73
74	/* save the boot hart id to global_data */
75	SREG	s0, GD_BOOT_HART(gp)
76
77	mv	a0, zero		/* a0 <-- boot_flags = 0 */
78	la	t5, board_init_f
79	jr	t5			/* jump to board_init_f() */
80
81/*
82 * void relocate_code (addr_sp, gd, addr_moni)
83 *
84 * This "function" does not return, instead it continues in RAM
85 * after relocating the monitor code.
86 *
87 */
88.globl relocate_code
89relocate_code:
90	mv	s2, a0			/* save addr_sp */
91	mv	s3, a1			/* save addr of gd */
92	mv	s4, a2			/* save addr of destination */
93
94/*
95 *Set up the stack
96 */
97stack_setup:
98	mv	sp, s2
99	la	t0, _start
100	sub	t6, s4, t0		/* t6 <- relocation offset */
101	beq	t0, s4, clear_bss	/* skip relocation */
102
103	mv	t1, s4			/* t1 <- scratch for copy_loop */
104	la	t3, __bss_start
105	sub	t3, t3, t0		/* t3 <- __bss_start_ofs */
106	add	t2, t0, t3		/* t2 <- source end address */
107
108copy_loop:
109	LREG	t5, 0(t0)
110	addi	t0, t0, REGBYTES
111	SREG	t5, 0(t1)
112	addi	t1, t1, REGBYTES
113	blt	t0, t2, copy_loop
114
115/*
116 * Update dynamic relocations after board_init_f
117 */
118fix_rela_dyn:
119	la	t1, __rel_dyn_start
120	la	t2, __rel_dyn_end
121	beq	t1, t2, clear_bss
122	add	t1, t1, t6		/* t1 <- rela_dyn_start in RAM */
123	add	t2, t2, t6		/* t2 <- rela_dyn_end in RAM */
124
125/*
126 * skip first reserved entry: address, type, addend
127 */
128	bne	t1, t2, 7f
129
1306:
131	LREG	t5, -(REGBYTES*2)(t1)	/* t5 <-- relocation info:type */
132	li	t3, R_RISCV_RELATIVE	/* reloc type R_RISCV_RELATIVE */
133	bne	t5, t3, 8f		/* skip non-RISCV_RELOC entries */
134	LREG	t3, -(REGBYTES*3)(t1)
135	LREG	t5, -(REGBYTES)(t1)	/* t5 <-- addend */
136	add	t5, t5, t6		/* t5 <-- location to fix up in RAM */
137	add	t3, t3, t6		/* t3 <-- location to fix up in RAM */
138	SREG	t5, 0(t3)
1397:
140	addi	t1, t1, (REGBYTES*3)
141	ble	t1, t2, 6b
142
1438:
144	la	t4, __dyn_sym_start
145	add	t4, t4, t6
146
1479:
148	LREG	t5, -(REGBYTES*2)(t1)	/* t5 <-- relocation info:type */
149	srli	t0, t5, SYM_INDEX	/* t0 <--- sym table index */
150	andi	t5, t5, 0xFF		/* t5 <--- relocation type */
151	li	t3, RELOC_TYPE
152	bne	t5, t3, 10f		/* skip non-addned entries */
153
154	LREG	t3, -(REGBYTES*3)(t1)
155	li	t5, SYM_SIZE
156	mul	t0, t0, t5
157	add	s5, t4, t0
158	LREG	t5, REGBYTES(s5)
159	add	t5, t5, t6		/* t5 <-- location to fix up in RAM */
160	add	t3, t3, t6		/* t3 <-- location to fix up in RAM */
161	SREG	t5, 0(t3)
16210:
163	addi	t1, t1, (REGBYTES*3)
164	ble	t1, t2, 9b
165
166/*
167 * trap update
168*/
169	la	t0, trap_entry
170	add	t0, t0, t6
171	csrw	MODE_PREFIX(tvec), t0
172
173clear_bss:
174	la	t0, __bss_start		/* t0 <- rel __bss_start in FLASH */
175	add	t0, t0, t6		/* t0 <- rel __bss_start in RAM */
176	la	t1, __bss_end		/* t1 <- rel __bss_end in FLASH */
177	add	t1, t1, t6		/* t1 <- rel __bss_end in RAM */
178	beq	t0, t1, call_board_init_r
179
180clbss_l:
181	SREG	zero, 0(t0)		/* clear loop... */
182	addi	t0, t0, REGBYTES
183	bne	t0, t1, clbss_l
184
185/*
186 * We are done. Do not return, instead branch to second part of board
187 * initialization, now running from RAM.
188 */
189call_board_init_r:
190	jal	invalidate_icache_all
191	jal	flush_dcache_all
192	la	t0, board_init_r
193	mv	t4, t0			/* offset of board_init_r() */
194	add	t4, t4, t6		/* real address of board_init_r() */
195/*
196 * setup parameters for board_init_r
197 */
198	mv	a0, s3			/* gd_t */
199	mv	a1, s4			/* dest_addr */
200
201/*
202 * jump to it ...
203 */
204	jr	t4			/* jump to board_init_r() */
205