1/*
2 * Copyright (c) 2023 Intel Corporation
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7	.equ	PMU_BASE, 			0x4200000
8	.equ	PMU_STATUS_REG,			(PMU_BASE + 0xF00)
9	.equ	PMU_SCRATCHPAD0,		(PMU_BASE + 0xF04)
10	.equ	PMU_SCRATCHPAD1,		(PMU_BASE + 0xF08)
11	.equ	PMU_PG_EN_REG,			(PMU_BASE + 0xF10)
12
13	.equ	PMU_STATUS_PG,			(1 << 4)
14	.equ	PMU_STATUS_PG_AON,		(1 << 5)
15
16	.equ	PMU_PG_EN,			(1 << 0)
17	.equ	PMU_PG_EXIT_COMPLETE,		(1 << 8)
18
19	.equ	FWST_AON_STATE_MASK,		(0x7 << 24)
20	.equ	FWST_AON_STATE_HALT,		(0x2 << 24)
21
22	.equ	EFLAGS_NT,			(1 << 14)
23
24	.equ	TSS_ESP0_OFFSET,		0x4
25	.equ	TSS_LDT_SEG_SEL_OFFSET,		0x60
26
27	.equ	AON_CS,				0x4
28	.equ	AON_DS,				0xc
29
30
31	.global ipapg
32ipapg:
33	push	%ebp
34	push	%edi
35	push	%esi
36	push	%ebx
37	mov	%cr0, %eax
38	push	%eax
39	mov	%cr4, %eax
40	push	%eax
41
42	clts
43
44	#write down return address for ROM
45	movl	$(PMU_STATUS_PG|PMU_STATUS_PG_AON), PMU_STATUS_REG
46	movl	$out_of_pg, %eax
47	movl	%eax, PMU_SCRATCHPAD0
48	movl	(%eax), %eax
49	movl	%eax, PMU_SCRATCHPAD1
50
51	#enable IPAPG, we will actually enter PG on the next halt
52	movl	$(PMU_PG_EN|PMU_PG_EXIT_COMPLETE), PMU_PG_EN_REG
53
54	#save esp so we can restore stack after returning from ROM
55	lea	aon_tss, %eax
56	movl	%esp, TSS_ESP0_OFFSET(%eax)
57
58	sti
59	hlt
60
61	#unreachable
62
63
64	#got out of IPAPG, jumped here from ROM if there was no abort condition
65out_of_pg:
66	cli
67
68	#restore stack
69	lea	aon_tss, %eax
70	movl	TSS_ESP0_OFFSET(%eax), %esp
71
72	#set the nested task bit in eflags
73	pushfl
74	orl	$EFLAGS_NT, (%esp)
75	popfl
76
77	clts
78	fninit
79
80	#restore non-volatile registers and CR0 & CR4
81	pop	%eax
82	mov	%eax, %cr4
83	pop	%eax
84	mov	%eax, %cr0
85	pop	%ebx
86	pop	%esi
87	pop	%edi
88	pop	%ebp
89
90	#check if we're indeed after IPAPG exit
91	testl	$PMU_STATUS_PG, PMU_STATUS_REG
92	jz	after_pg
93
94	#we didn't go through ROM, clear PG_EN bit and return an abort condition to AON
95	movl	$0, PMU_PG_EN_REG
96	movl	$0, %eax
97	jmp	return_to_aon
98
99after_pg:
100	#return to caller that we got ouf of PG
101	movl	$1, %eax
102
103return_to_aon:
104	movl	$0, PMU_STATUS_REG
105
106	#return to AON task (still with ROM GDT and segments in case of PG exit)
107	ret
108
109	.global pg_exit_save_ctx
110pg_exit_save_ctx:
111	sgdtl	mainfw_gdt
112	str 	tr
113	ret
114
115	.global pg_exit_restore_ctx
116pg_exit_restore_ctx:
117
118	#load RTOS GDT and AON task
119	lgdtl	mainfw_gdt
120	ltr	tr
121
122	#load AON LDT and segments
123	lea	aon_tss, %eax
124	lldt	TSS_LDT_SEG_SEL_OFFSET(%eax)
125	mov	$AON_DS, %ax
126	mov	%ax, %ds
127	mov	%ax, %es
128	mov	%ax, %fs
129	mov	%ax, %gs
130	mov	%ax, %ss
131	ljmpl	$AON_CS, $cont
132
133cont:
134	nop
135	ret
136