1/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * Copyright (C) 2024 9elements GmbH
4 *   Author: Patrick Rudolph <patrick.rudolph@9elements.com>
5 *
6 * This file provides ARMv8 specific code for the generic part of the
7 * ACPI parking protocol implementation. It contains the spinning code
8 * that will be installed into the parking protocol and it points the
9 * secondary CPUs to their own parking protocol page once it has been
10 * set up by the generic part.
11 */
12
13#include <asm/acpi_table.h>
14#include <linux/linkage.h>
15
16/* Filled by C code */
17.global acpi_pp_tables
18acpi_pp_tables:
19	.quad 0
20
21.global acpi_pp_etables
22acpi_pp_etables:
23	.quad 0
24
25/* Read by C code */
26.global acpi_pp_code_size
27acpi_pp_code_size:
28	.word __secondary_pp_code_end - __secondary_pp_code_start
29
30.global acpi_pp_secondary_jump
31ENTRY(acpi_pp_secondary_jump)
320:
33	/*
34	 * Cannot use atomic operations since the MMU and D-cache
35	 * might be off. Use the MPIDR instead to find the spintable.
36	 */
37
38	/* Check if parking protocol table is ready */
39	ldr	x1, =acpi_pp_tables
40	ldr	x0, [x1]
41	cbnz	x0, 0f
42	wfe
43	b	0b
44
450:	/* Get end of page tables in x3 */
46	ldr	x1, =acpi_pp_etables
47	ldr	x3, [x1]
48
49	/* Get own CPU ID in w2 */
50	mrs	x2, mpidr_el1
51	lsr	x9, x2, #32
52	bfi	x2, x9, #24, #8	/* w2 is aff3:aff2:aff1:aff0 */
53
540:	/* Loop over all parking protocol pages */
55	cmp	x0, x3
56	b.ge	hlt
57
58	/* Fetch CPU_ID from current page */
59	ldr	x1, [x0, #ACPI_PP_CPU_ID_OFFSET]
60	lsr	x9, x1, #32
61	bfi	x1, x9, #24, #8	/* w1 is aff3:aff2:aff1:aff0 */
62
63	/* Compare CPU_IDs */
64	cmp	w1, w2
65	b.eq	0f
66
67	add	x0, x0, #ACPI_PP_PAGE_SIZE
68	b	0b
69
70hlt:	wfi
71	b	hlt	/* Should never happen. */
72
730:	/* x0 points to the 4K-aligned, parking protocol page */
74	add	x2, x0, #ACPI_PP_CPU_CODE_OFFSET
75
76	/* Jump to spin code in own parking protocol page */
77	br	x2
78ENDPROC(acpi_pp_secondary_jump)
79
80.align 8
81__secondary_pp_code_start:
82.global acpi_pp_code_start
83ENTRY(acpi_pp_code_start)
84	/* x0 points to the 4K-aligned, parking protocol page */
85
86	/* Prepare defines for spinning code */
87	mov	w3, #ACPI_PP_CPU_ID_INVALID
88	mov	x2, #ACPI_PP_JMP_ADR_INVALID
89
90	/* Mark parking protocol page as ready */
91	str	w3, [x0, #ACPI_PP_CPU_ID_OFFSET]
92	dsb	sy
93
940:	wfe
95	ldr	w1, [x0, #ACPI_PP_CPU_ID_OFFSET]
96
97	/* Check CPU ID is valid */
98	cmp	w1, w3
99	b.eq	0b
100
101	/* Check jump address valid */
102	ldr	x1, [x0, #ACPI_PP_CPU_JMP_OFFSET]
103	cmp	x1, x2
104	b.eq	0b
105
106	/* Clear jump address before jump */
107	str	x2, [x0, #ACPI_PP_CPU_JMP_OFFSET]
108	dsb	sy
109
110	br	x1
111ENDPROC(acpi_pp_code_start)
112	/* Secondary Boot Code ends here */
113__secondary_pp_code_end:
114