1/*
2 * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved.
3 *
4 * Copyright (C) 2022-2023 Nuvoton Ltd.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9#ifndef NUVOTON_HELPERS_S
10#define NUVOTON_HELPERS_S
11
12#include <asm_macros.S>
13#include <cortex_a35.h>
14#include <platform_def.h>
15
16	.globl	plat_is_my_cpu_primary
17	.globl	plat_my_core_pos
18	.globl	plat_calc_core_pos
19	.globl	plat_reset_handler
20	.globl	plat_get_my_entrypoint
21	.globl	plat_secondary_cold_boot_setup
22	.globl	plat_crash_console_init
23	.globl	plat_crash_console_putc
24	.globl	plat_crash_console_flush
25	.globl	platform_mem_init
26	.globl  npcm845x_mailbox_init
27
28	/* --------------------------------------------------------------------
29	 * Helper macro that reads the part number of the current CPU and jumps
30	 * to the given label if it matches the CPU MIDR provided.
31	 *
32	 * Clobbers x0.
33	 * --------------------------------------------------------------------
34	 */
35	.macro  jump_if_cpu_midr _cpu_midr, _label
36
37	mrs	x0, midr_el1
38	ubfx	x0, x0, MIDR_PN_SHIFT, #12
39	cmp     w0, #((\_cpu_midr >> MIDR_PN_SHIFT) & MIDR_PN_MASK)
40	b.eq	\_label
41
42	.endm
43
44	/* ----------------------------------------------
45	 * The mailbox_base is used to distinguish warm/cold
46	 * reset. The mailbox_base is in the data section, not
47	 * in .bss, this allows function to start using this
48	 * variable before the runtime memory is initialized.
49	 * ----------------------------------------------
50	 */
51	.section .data.mailbox_base
52	.align 3
53	mailbox_base: .quad 0x0
54
55	/* ---------------------------------------------
56	 * void plat_reset_handler(void);
57	 *
58	 * To add: Determine the SoC type and call the appropriate
59	 * reset handler.
60	 *-----------------------------------------------	 */
61
62func plat_reset_handler
63	 ret
64endfunc plat_reset_handler
65
66	/* ----------------------------------------------
67	 * unsigned int plat_is_my_cpu_primary(void);
68	 * This function checks if this is the primary CPU
69	 * ----------------------------------------------
70	 */
71func plat_is_my_cpu_primary
72	mrs	x0, mpidr_el1
73	and	x0, x0, #(MPIDR_CPU_MASK)
74	cmp	x0, #PLAT_PRIMARY_CPU
75	cset	x0, eq
76	ret
77endfunc plat_is_my_cpu_primary
78
79	/* ----------------------------------------------
80	 * unsigned int plat_my_core_pos(void)
81	 * This Function uses the plat_calc_core_pos()
82	 * to get the index of the calling CPU.
83	 * ----------------------------------------------
84	 */
85func plat_my_core_pos
86	mrs	x0, mpidr_el1
87	and	x1, x0, #MPIDR_CPU_MASK
88	and 	x0, x0, #MPIDR_CLUSTER_MASK
89	add	x0, x1, x0, LSR #6
90	ret
91endfunc plat_my_core_pos
92
93	/*
94	 * unsigned int plat_calc_core_pos(uint64_t mpidr)
95	 * helper function to calculate the core position.
96	 * With this function.
97	 */
98func plat_calc_core_pos
99	and	x1, x0, #MPIDR_CPU_MASK
100	and 	x0, x0, #MPIDR_CLUSTER_MASK
101	add	x0, x1, x0, LSR #6
102	ret
103endfunc plat_calc_core_pos
104
105	/* ---------------------------------------------
106	 * function to get the entrypoint.
107	 * ---------------------------------------------
108	 */
109	/* ---------------------------------------------------------------------
110	 * uintptr_t plat_get_my_entrypoint (void);
111	 *
112	 * Main job of this routine is to distinguish between a cold and a warm
113	 * boot.
114	 *
115	 * This functions returns:
116	 *  - 0 for a cold boot.
117	 *  - Any other value for a warm boot.
118	 * ---------------------------------------------------------------------
119	 */
120func plat_get_my_entrypoint
121	mov	x1, x30
122	bl	plat_is_my_cpu_primary
123	/*
124	 * Secondaries always cold boot.
125	*/
126	cbz	w0, 1f
127	/*
128	 * Primaries warm boot if they are requested
129	 * to power off.
130	 */
131	mov_imm	x0, PLAT_NPCM_TM_HOLD_BASE
132	ldr	x0, [x0]
133	cmp	x0, PLAT_NPCM_TM_HOLD_STATE_BSP_OFF
134	adr	x0, plat_wait_for_warm_boot
135	csel	x0, x0, xzr, eq
136	ret	x1
1371:	mov	x0, #0
138	ret	x1
139endfunc plat_get_my_entrypoint
140
141func npcm845x_mailbox_init
142	adrp	x1, mailbox_base
143	str	x0, [x1, :lo12:mailbox_base]
144	ret
145endfunc npcm845x_mailbox_init
146
147func plat_wait_for_warm_boot
148	/*
149	 * Calculate address of our hold entry.
150	 * As the function will never return, there is no need to save LR.
151	 */
152	bl	plat_my_core_pos
153	lsl	x0, x0, #3
154	mov_imm	x2, PLAT_NPCM_TM_HOLD_BASE
155	add	x0, x0, x2
156	mov x8, x0
157	mov_imm	x2, PLAT_NPCM_TRUSTED_NOTIFICATION_BASE
158	add	x8, x8, x2
159	/*
160	 * This code runs way before requesting the warmboot of this core,
161	 * so it is possible to clear the mailbox before getting a request
162	 * to boot.
163	 */
164	mov	x1, PLAT_NPCM_TM_HOLD_STATE_WAIT
165	str	x1,[x0]
166
167	/* Notify that core is in pending state - do not use x0!, uses x7 and x8! */
168	mov	x7, PLAT_NPCM_TM_NOTIFICATION_START
169	str	x7,[x8]
170	/*
171	 * This code runs way before requesting the warmboot of this core,
172	 * so it is possible to clear the mailbox before getting a request
173	 * to boot.
174	 */
175	mov	x1, PLAT_NPCM_TM_HOLD_STATE_WAIT
176	str	x1,[x0]
177	/* Wait until we have a go */
178poll_mailbox:
179	wfe
180	ldr	x1, [x0]
181	cmp	x1, PLAT_NPCM_TM_HOLD_STATE_GO
182	bne	poll_mailbox
183
184	mov	x7, PLAT_NPCM_TM_NOTIFICATION_BR
185	str	x7,[x8]
186	/* Jump to the provided entrypoint */
187	mov_imm	x0, PLAT_NPCM_TM_ENTRYPOINT
188	ldr	x1, [x0]
189	br	x1
190endfunc plat_wait_for_warm_boot
191
192func plat_secondary_cold_boot_setup
193	b	plat_wait_for_warm_boot
194endfunc plat_secondary_cold_boot_setup
195
196func plat_crash_console_init
197	mov	x0, #1
198	ret
199endfunc plat_crash_console_init
200
201func plat_crash_console_putc
202	ret
203endfunc plat_crash_console_putc
204
205func plat_crash_console_flush
206	mov	x0, #0
207	ret
208endfunc plat_crash_console_flush
209
210func platform_mem_init
211	ret
212endfunc platform_mem_init
213
214#endif /* NUVOTON_HELPERS_S */
215