blob: 318c4d71b1ca2718bdf0b69aa41031791f1bca6e [file] [log] [blame]
Angel Pons5f249e62020-04-04 18:51:01 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* Early initialization code for aarch64 (a.k.a. armv8) */
David Hendricks8cbd5692017-12-01 20:49:48 -08003
4#include <arch/asm.h>
5#include <soc/addressmap.h>
6
7ENTRY(_start)
8 .org 0
9 /**
10 * According to the reference manual the first instruction is fetched from
11 * offset 0x100, but at offset 0 a branch instruction is always placed.
12 * Support two entry points for now.
13 * To save memory put the cavium specific init code between those to entry
14 * points.
15 */
16 ic ialluis
17 fmov d30, x0 /* Save X0 in FPR for use later */
Patrick Rudolphe15556e2018-02-16 09:04:38 +010018 /**
19 * The BDK stores X1 for later use, but it turns out that we don't need
20 * this "feature". The idea is to hide the devicetree somewhere in
21 * flash, that only the ROM will find it and point to it using X1.
22 */
David Hendricks8cbd5692017-12-01 20:49:48 -080023 adr x1, _start /* x1 = _start location based on PC */
24 fmov d29, x1 /* Save PC in FPR for use later */
25
26#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
27 /* Change the core to big endian mode for EL3 */
28 mrs x0, SCTLR_EL3
29 mov x1, 1<<25 /* Set SCTLR_EL3[ee]=1 */
30 orr x0, x0, x1
31 msr SCTLR_EL3, x0
32 #define ENDIAN_CONVERT64(reg) rev reg, reg
33 #define ENDIAN_CONVERT32(reg) rev reg, reg
34 #define ENDIAN_CONVERT16(reg) rev16 reg, reg
35#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
36 /* Nothing needed, default is little endian */
37 #define ENDIAN_CONVERT64(reg)
38 #define ENDIAN_CONVERT32(reg)
39 #define ENDIAN_CONVERT16(reg)
40#else
41 #error Unknown endianness
42#endif
43
44 mov x0, (LMC0_PF_BAR0 >> 32)
45 lsl x0, x0, 32
46 mov x1, (LMC0_PF_BAR0 & 0xffffffff)
47 orr x0, x0, x1
48
49 /* Test if DRAM PLL is running */
50 ldr x1, [x0, LMC0_DDR_PLL_CTL0]
51
52 tst x1, 0x80
53
54 b.ne cache_setup_done
55
56 bl _setup_car
57
58cache_setup_done:
59
60 /* Check that we're running on the node we're linked for */
61 mrs x0, MPIDR_EL1
62 ubfx x0, x0, 16, 8 /* Bits 23:16 are the physical node ID */
63 mov x1, 0x0
64 cmp x0, x1
65
66 b.ne _wfi
67
68node_check_done:
69 /* Get code position */
70 mov x1, 0x020000
71 mov x0, BOOTROM_OFFSET
72 add x1, x0, x1
73
74 adr x0, _start
75
76 /**
Patrick Rudolphe15556e2018-02-16 09:04:38 +010077 * Check if IROM has loaded the code to BOOTROM_OFFSET.
David Hendricks8cbd5692017-12-01 20:49:48 -080078 * In case the offset is wrong, try to relocate.
79 * Ideally the following code is never executed.
80 * FIXME: Add region overlap check.
81 */
82 cmp x0, x1
83 b.eq after_relocate
84
85relocate:
86 /* Get bootblock length */
87 ldr x2, =_program
88 ldr x3, =_eprogram
89 sub x2, x2, x3
90 b copy_code
91
92.align 7
93copy_code:
94 ldp q0, q1, [x1], 32 /* Load 32 bytes */
95 subs w2, w2, 32 /* Subtract 32 from length, setting flags */
96 stp q0, q1, [x0], 32 /* Store 32 bytes */
97 b.gt copy_code /* Repeat if length is still positive */
98 dmb sy
99
100 /* Load the actual location we're suppose to be at */
101 adr x0, after_relocate /* Relative address */
102 adr x1, _start /* Relative address */
103 sub x0, x0, x1 /* This only works if _start is suppose to be zero */
104 mov x1, BOOTROM_OFFSET
105 add x0, x0, x1
106 br x0 /* Branch to relocated code */
107
108 ic ialluis /* Clear the icache now that all code is correct */
109
110after_relocate:
111 /* Allow unaligned memory access as long as MMU is disabled */
112 mrs x22, s3_0_c11_c0_4
113 orr x22, x22, # (1 << 37) /* Set DCVA47 */
114 msr s3_0_c11_c0_4, x22
115
116 bl start
117
118 /* Real entry point */
119 .org 0x100
120 b _start
121ENDPROC(_start)
122
123
124ENTRY(_setup_car)
125 mrs x0, MIDR_EL1
126 ubfx x0, x0, 4, 12 /* Bits 15:4 are the part number */
127 cmp x0, 0xb0
128 b.ge _wfi
129
130thunder1_cache_setup:
131 /**
132 * Setup L2 cache to allow secure access to all of the address space
Martin Roth26f97f92021-10-01 14:53:22 -0600133 * thunder1 compatibility list:
David Hendricks8cbd5692017-12-01 20:49:48 -0800134 * - CN81XX
135 * - CN83XX
136 * - CN88XX
137 */
138 #define REGIONX_START 0x1000
139 #define REGIONX_END 0x1008
140 #define REGIONX_ATTR 0x1010
141 mov x0, L2C_PF_BAR0 >> 32
142 lsl x0, x0, 32
143 mov x1, (L2C_PF_BAR0 & 0xffffffff)
144 orr x0, x0, x1
145 str xzr, [x0, REGIONX_START] /* Start of zero */
146 mov x1, 0x3fffff00000 /* End of max address */
147 ENDIAN_CONVERT64(x1)
148 str x1, [x0, REGIONX_END]
149 mov x1, 2 /* Secure only access */
150 ENDIAN_CONVERT64(x1)
151 str x1, [x0, REGIONX_ATTR]
152 /* Update way partition to allow core 0 to write to L2 */
153 #define L2C_WPAR_PP0_OFFSET 0x40000
154 mov x1, L2C_WPAR_PP0_OFFSET
155 str xzr, [x0, x1]
156 ldr xzr, [x0, x1] /* Read back to make sure done */
157 #undef REGIONX_START
158 #undef REGIONX_END
159 #undef REGIONX_ATTR
160 #undef L2C_WPAR_PP0_OFFSET
161
162 /**
163 * At this point the whole CAR is readable and writeable, but if
164 * we touch to many cache-lines our code might get flushed out.
165 * We have to lock all cache-lines that are to be used as RAM, which are
166 * the ones marked as SRAM in memlayout.
167 */
168 mrs x0, CTR_EL0 /* Get cache-line size */
169 /* [19:16] - Indicates (Log2(number of words in cache line) */
170 ubfx x0, x0, 16, 4
171 mov x1, 4 /* Bytes in a word (32-bit) */
172 lsl x0, x1, x0 /* Number of Bytes in x0 */
173
174 sub x1, x0, 1
175 mvn x1, x1 /* Place mask in x1 */
176
177 ldr x3, =_sram
178 and x3, x3, x1 /* Align addresses with cache-lines */
179 ldr x4, =_esram
180 add x4, x4, x0
181 sub x4, x4, 1
182 and x4, x4, x1 /* Align addresses with cache-lines */
183 sub x2, x4, x3 /* Store sram length in x2 */
184
185lock_cache_lines:
186 sys #0, c11, c1, #4, x3
187 add x3, x3, x0 /* Increment address by cache-line bytes */
188 subs w2, w2, w0 /* Subtract cache-line bytes from length */
189 b.gt lock_cache_lines /* Repeat if length is still positive */
190
191 /**
192 * The locked region isn't considered dirty by L2. Do read/write of
193 * each cache line to force each to be dirty. This is needed across the
194 * whole line to make sure the L2 dirty bits are all up to date.
195 * NOTE: If we'd relocate we could memset the whole memory !
196 */
197 ldr x3, =_sram
198 and x3, x3, x1 /* Align addresses with cache-lines */
199 ldr x4, =_esram
200 add x4, x4, x0
201 sub x4, x4, 1
202 and x4, x4, x1 /* Align addresses with cache-lines */
203 sub x2, x4, x3 /* Store sram length in x2 */
204 mov x4, x3
205 b dirty_cache_line
206
207.align 7
208dirty_cache_line:
209 ldp q0, q1, [x3], 32 /* Load 32 bytes */
210 subs w2, w2, 32 /* Subtract 32 from length, setting flags */
211 stp q0, q1, [x4], 32 /* Store 32 bytes */
212 b.gt dirty_cache_line /* Repeat if length is still positive */
213 dmb sy
214
215clear_interrupts:
216 /**
217 * As the memory controller isn't running, but we access the DRAM's
218 * address space, some interrupt flags had been set.
219 * Tidy up our mess now on (valid for CN81XX only).
220 */
221 mov x0, (L2C_TAD0_INT_W1C >> 32)
222 lsl x0, x0, 32
223 mov x1, (L2C_TAD0_INT_W1C & 0xffffffff)
224 orr x0, x0, x1
225
226 ldr x1, [x0]
227 orr x1, x1, 0x1c00 /* Clear WRDISLMC, RDDISLMC, RDNXM */
228 str x1, [x0]
229
230 ret
231ENDPROC(_setup_car)
232
233ENTRY(_wfi)
234 wfi
235ENDPROC(_wfi)
236
237ENTRY(start)
238 bl arm64_init_cpu
239
240 fmov x0, d30 /* The original X0, info from previous image */
Patrick Rudolphe15556e2018-02-16 09:04:38 +0100241 fmov x1, d29 /* The original PC we were loaded at */
David Hendricks8cbd5692017-12-01 20:49:48 -0800242
243 /* Call C entry */
244 bl bootblock_main
245
246ENDPROC(start)