1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include <config.h>
8#include <machine/assembler.h>
9#include <arch/machine/hardware.h>
10#include <arch/machine/registerset.h>
11#include <util.h>
12
13#ifndef ALLOW_UNALIGNED_ACCESS
14#define ALLOW_UNALIGNED_ACCESS 1
15#endif
16
17#if ALLOW_UNALIGNED_ACCESS
18#define CR_ALIGN_SET     BIT(CONTROL_U)
19#define CR_ALIGN_CLEAR   BIT(CONTROL_A)
20#else
21#define CR_ALIGN_SET     BIT(CONTROL_A)
22#define CR_ALIGN_CLEAR   BIT(CONTROL_U)
23#endif
24
25#ifndef CONFIG_DEBUG_DISABLE_L1_ICACHE
26    #define CR_L1_ICACHE_SET   BIT(CONTROL_I)
27    #define CR_L1_ICACHE_CLEAR 0
28#else
29    #define CR_L1_ICACHE_SET   0
30    #define CR_L1_ICACHE_CLEAR BIT(CONTROL_I)
31#endif
32
33#ifndef CONFIG_DEBUG_DISABLE_L1_DCACHE
34    #define CR_L1_DCACHE_SET   BIT(CONTROL_C)
35    #define CR_L1_DCACHE_CLEAR 0
36#else
37    #define CR_L1_DCACHE_SET   0
38    #define CR_L1_DCACHE_CLEAR BIT(CONTROL_C)
39#endif
40
41#ifndef CONFIG_DEBUG_DISABLE_BRANCH_PREDICTION
42    #define CR_BRANCH_PREDICTION_SET   BIT(CONTROL_Z)
43    #define CR_BRANCH_PREDICTION_CLEAR 0
44#else
45    #define CR_BRANCH_PREDICTION_SET   0
46    #define CR_BRANCH_PREDICTION_CLEAR BIT(CONTROL_Z)
47#endif
48
49#define CR_BITS_SET    (CR_ALIGN_SET | \
50                        CR_L1_ICACHE_SET | \
51                        CR_L1_DCACHE_SET | \
52                        BIT(CONTROL_M) | \
53                        CR_BRANCH_PREDICTION_SET | \
54                        BIT(CONTROL_V) | \
55                        BIT(CONTROL_XP))
56
57#define CR_BITS_CLEAR  (CR_ALIGN_CLEAR | \
58                        CR_L1_ICACHE_CLEAR | \
59                        CR_L1_DCACHE_CLEAR | \
60                        CR_BRANCH_PREDICTION_CLEAR | \
61                        BIT(CONTROL_B) | \
62                        BIT(CONTROL_S) | \
63                        BIT(CONTROL_R) | \
64                        BIT(CONTROL_VE) | \
65                        BIT(CONTROL_RR) | \
66                        BIT(CONTROL_EE) | \
67                        BIT(CONTROL_TRE) | \
68                        BIT(CONTROL_AP))
69
70/*
71 * Entry point of the kernel ELF image.
72 * R0-R3 contain parameters that are passed to init_kernel(),
73 * and we put arguments 5 and 6 (DTB address/size) in r7 and r8.
74 */
75
76.code 32
77.section .boot.text, "ax"
78BEGIN_FUNC(_start)
79    /*
80     * Get the dtb and dtb size from the elfloader stack. Do this first because
81     * sp might change when we switch to supervisor mode.
82     */
83    pop {r7, r8}
84
85    /* Supervisor/hypervisor mode, interrupts disabled */
86    ldr r5, =CPSR_KERNEL
87    msr cpsr_fc, r5
88
89    /* Initialise CP15 control register */
90#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
91    mrc p15, 4, r4, c1, c0, 0
92#else
93    mrc p15, 0, r4, c1, c0, 0
94#endif
95    ldr r5, =CR_BITS_SET
96    ldr r6, =CR_BITS_CLEAR
97    orr r4, r4, r5
98    bic r4, r4, r6
99#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
100    mcr p15, 4, r4, c1, c0, 0
101
102    /* Initialise vector base */
103    ldr r4, =PPTR_VECTOR_TABLE
104    mcr p15, 4, r4, c12, c0, 0
105#else
106    mcr p15, 0, r4, c1, c0, 0
107#endif
108
109#if defined(CONFIG_ARM_CORTEX_A9) && defined(CONFIG_ENABLE_A9_PREFETCHER)
110    /* Set bit 2 in the ACTLR, which on the cortex-a9 is the l1 prefetch enable
111     * bit. See section 4.3.10 of the Cortex-A9 Technical Reference Manual */
112    mrc p15, 0, r4, c1, c0, 1
113    ldr r5, =BIT(2)
114    orr r4, r4, r5
115    mcr p15, 0, r4, c1, c0, 1
116#endif
117
118#if defined(CONFIG_PLAT_HIKEY)
119    /* Prefetcher configuration */
120   mrrc p15, 0, r4, r5, c15
121   ldr r6, =PREFETCHER_MASK
122   bic r4, r4, r6
123   ldr r6, =PREFETCHER
124   orr r4, r4, r6
125   mcrr p15, 0, r4, r5, c15
126#endif
127
128     /* Load kernel stack pointer
129      * On ARM SMP, kernel_stack_alloc is indexed by CPU ID
130      * to get different stacks for each core
131      */
132    ldr sp, =kernel_stack_alloc + BIT(CONFIG_KERNEL_STACK_BITS)
133
134#ifdef ENABLE_SMP_SUPPORT
135    /*
136     * Read MPIDR in r4
137     * See ARM Referce Manual (ARMv7-A and ARMv7-R edition), Section B4.1.106
138     * for more details about MPIDR register.
139     */
140    mrc p15, 0, r4, c0, c0, 5
141    and r4, r4, #0xff
142    /* Set the sp for each core assuming linear indices */
143    ldr     r5, =BIT(CONFIG_KERNEL_STACK_BITS)
144    mul     r5, r4
145    add     sp, sp, r5
146#endif /* ENABLE_SMP_SUPPORT */
147
148    /* Attempt to workaround any known ARM errata. */
149    push {r0-r3,r7-r8}
150    blx arm_errata
151    pop {r0-r3,r7-r8}
152
153    /* Hyp kernel always run in Hyp mode. */
154#ifndef CONFIG_ARM_HYPERVISOR_SUPPORT
155    /* Initialise ABORT stack pointer */
156    cps #PMODE_ABORT
157    ldr sp, =_breakpoint_stack_top
158    cps #PMODE_SUPERVISOR
159#endif
160
161    /* Put the DTB address back on the new stack for init_kernel. */
162    push {r7, r8}
163    /* Call bootstrapping implemented in C */
164    blx init_kernel
165
166    /* Restore the initial thread */
167    b restore_user_context
168
169END_FUNC(_start)
170