summaryrefslogtreecommitdiff
path: root/arch/kvx/cpu/start.S
blob: d90272c71f8b89a46adea6339cbdada6522c9dc4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (C) 2019 Kalray Inc.
 */

#include <linux/linkage.h>
#include <asm/privilege.h>
#include <asm/sys_arch.h>

#define PS_VAL_WFXL(__field, __val) \
	SFR_SET_VAL_WFXL(PS, __field, __val)

#define PS_WFXL_START_VALUE	PS_VAL_WFXL(HLE, 1) | \
				PS_VAL_WFXL(USE, 1) | \
				PS_VAL_WFXL(DCE, 1) | \
				PS_VAL_WFXL(ICE, 1) | \
				PS_VAL_WFXL(V64, 1) | \
				PS_VAL_WFXL(ET, 0)

#define PCR_VAL_WFXM(__field, __val) \
	SFR_SET_VAL_WFXM(PCR, __field, __val)

#define PCR_WFXM_START_VALUE   PCR_VAL_WFXM(L1CE, 1)

/* Enable STOP in WS */
#define WS_ENABLE_WU2		(KVX_SFR_WS_WU2_MASK)

#define WS_WFXL_VALUE		(WS_ENABLE_WU2)

/*
 * This is our entry point. When entering from bootloader,
 * the following registers are set:
 * $r0 is a magic "KALARGV1" (FSBL_PARAM_MAGIC) indicating parameters are passed
 * $r1 Device tree pointer
 *
 * WARNING WARNING WARNING
 * ! DO NOT CLOBBER THEM !
 * WARNING WARNING WARNING
 *
 * Try to use register above $r20 to ease parameter adding in future
 */
.section .startup, "ax"
ENTRY(kvx_start)
	/* (Re)initialize performance counter */
	make $r20 = 0x00000000
	;;
	set $pmc = $r20
	;;
	call asm_init_pl
	;;
	/* Setup default processor status */
	make $r25 = PS_WFXL_START_VALUE
	;;
	wfxl $ps = $r25
	;;
	make $r25 = PCR_WFXM_START_VALUE
	;;
	wfxm $pcr = $r25
	;;
	/* Clear BSS */
	make $r22 = __bss_stop
	make $r21 = __bss_start
	;;
	sbfd $r22 = $r21, $r22
	make $r24 = 0
	;;
	/* Divide by 16 for hardware loop */
	srld $r22, $r22, 4
	make $r25 = 0
	;;
	/* Clear bss with hardware loop */
        loopdo $r22, clear_bss_done
		;;
		sq 0[$r21] = $r24r25
		addd $r21 = $r21, 16
		;;
	clear_bss_done:
	/* Setup stack */
	make $sp, __stack_start
	;;
	call kvx_lowlevel_setup
	;;
	call kvx_start_barebox
	;;
	goto kvx_proc_power_off
	;;
ENDPROC(kvx_start)

#define request_ownership(__pl) ;\
	make $r21 = SYO_WFXL_VALUE_##__pl ;\
	;; ;\
	wfxl $syow = $r21 ;\
	;; ;\
	make $r21 = HTO_WFXL_VALUE_##__pl ;\
	;; ;\
	wfxl $htow = $r21 ;\
	;; ;\
	make $r21 = MO_WFXL_VALUE_##__pl ;\
	make $r22 = MO_WFXM_VALUE_##__pl ;\
	;; ;\
	wfxl $mow = $r21 ;\
	;; ;\
	wfxm $mow = $r22 ;\
	;; ;\
	make $r21 = ITO_WFXL_VALUE_##__pl ;\
	make $r22 = ITO_WFXM_VALUE_##__pl ;\
	;; ;\
	wfxl $itow = $r21 ;\
	;; ;\
	wfxm $itow = $r22 ;\
	;; ;\
	make $r21 = PSO_WFXL_VALUE_##__pl ;\
	make $r22 = PSO_WFXM_VALUE_##__pl ;\
	;; ;\
	wfxl $psow = $r21 ;\
	;; ;\
	wfxm $psow = $r22 ;\
	;;

/**
 * Initialize privilege level
 */
ENTRY(asm_init_pl)
	get $r21 = $ps
	;;
	/* Extract privilege level from $ps to check if we need to
	 * lower our privilege level (we might already be in PL1)
	 */
	extfz $r20 = $r21, KVX_SFR_END(PS_PL), KVX_SFR_START(PS_PL)
	;;
	/* If our privilege level is 0, then we need to lower in execution level
	 * to ring 1 in order to let the debug routines be inserted at runtime
	 * by the JTAG. In both case, we will request the resources we need for
	 * barebox to run.
	 */
	cb.deqz $r20? delegate_pl
	;;
	/*
	 * When someone is already above us, request the resources we need to
	 * run barebox . No need to request double exception or ECC traps for
	 * instance. When doing so, the more privileged level will trap for
	 * permission and delegate us the required resources.
	 */
	request_ownership(PL_CUR)
	;;
	ret
	;;
delegate_pl:
	request_ownership(PL_CUR_PLUS_1)
	;;
	/* Copy our $ps into $sps for 1:1 restoration */
	get $r22 = $ps
	;;
	/* We will return to $ra after rfe */
	get $r21 = $ra
	/* Set privilege level to +1 in $sps (relative level from the
	 * current one)
	 */
	addd $r22 = $r22, PL_CUR_PLUS_1
	;;
	set $spc = $r21
	;;
	set $sps = $r22
	;;
	/* When using rfe, $spc and $sps will be restored in $ps and $pc,
	 * We will then return to the caller ($ra) in current PL + 1
	 */
	rfe
	;;
ENDPROC(asm_init_pl)

ENTRY(kvx_proc_power_off):
	dinval
	make $r1 = WS_WFXL_VALUE
	;;
        /* Enable STOP */
	wfxl $ws, $r1
	;;
1:	stop
	;;
	goto 1b
	;;
ENDPROC(kvx_proc_power_off)