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