1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * Copyright (c) 2021 Western Digital Corporation or its affiliates.
4 * Copyright (c) 2022 Ventana Micro Systems Inc.
5 */
6
7#include <linux/linkage.h>
8#include <asm/asm.h>
9#include <asm/asm-offsets.h>
10#include <asm/csr.h>
11#include <asm/xip_fixup.h>
12
13	.text
14	.altmacro
15	.option norelax
16
17ENTRY(__cpu_suspend_enter)
18	/* Save registers (except A0 and T0-T6) */
19	REG_S	ra, (SUSPEND_CONTEXT_REGS + PT_RA)(a0)
20	REG_S	sp, (SUSPEND_CONTEXT_REGS + PT_SP)(a0)
21	REG_S	gp, (SUSPEND_CONTEXT_REGS + PT_GP)(a0)
22	REG_S	tp, (SUSPEND_CONTEXT_REGS + PT_TP)(a0)
23	REG_S	s0, (SUSPEND_CONTEXT_REGS + PT_S0)(a0)
24	REG_S	s1, (SUSPEND_CONTEXT_REGS + PT_S1)(a0)
25	REG_S	a1, (SUSPEND_CONTEXT_REGS + PT_A1)(a0)
26	REG_S	a2, (SUSPEND_CONTEXT_REGS + PT_A2)(a0)
27	REG_S	a3, (SUSPEND_CONTEXT_REGS + PT_A3)(a0)
28	REG_S	a4, (SUSPEND_CONTEXT_REGS + PT_A4)(a0)
29	REG_S	a5, (SUSPEND_CONTEXT_REGS + PT_A5)(a0)
30	REG_S	a6, (SUSPEND_CONTEXT_REGS + PT_A6)(a0)
31	REG_S	a7, (SUSPEND_CONTEXT_REGS + PT_A7)(a0)
32	REG_S	s2, (SUSPEND_CONTEXT_REGS + PT_S2)(a0)
33	REG_S	s3, (SUSPEND_CONTEXT_REGS + PT_S3)(a0)
34	REG_S	s4, (SUSPEND_CONTEXT_REGS + PT_S4)(a0)
35	REG_S	s5, (SUSPEND_CONTEXT_REGS + PT_S5)(a0)
36	REG_S	s6, (SUSPEND_CONTEXT_REGS + PT_S6)(a0)
37	REG_S	s7, (SUSPEND_CONTEXT_REGS + PT_S7)(a0)
38	REG_S	s8, (SUSPEND_CONTEXT_REGS + PT_S8)(a0)
39	REG_S	s9, (SUSPEND_CONTEXT_REGS + PT_S9)(a0)
40	REG_S	s10, (SUSPEND_CONTEXT_REGS + PT_S10)(a0)
41	REG_S	s11, (SUSPEND_CONTEXT_REGS + PT_S11)(a0)
42
43	/* Save CSRs */
44	csrr	t0, CSR_EPC
45	REG_S	t0, (SUSPEND_CONTEXT_REGS + PT_EPC)(a0)
46	csrr	t0, CSR_STATUS
47	REG_S	t0, (SUSPEND_CONTEXT_REGS + PT_STATUS)(a0)
48	csrr	t0, CSR_TVAL
49	REG_S	t0, (SUSPEND_CONTEXT_REGS + PT_BADADDR)(a0)
50	csrr	t0, CSR_CAUSE
51	REG_S	t0, (SUSPEND_CONTEXT_REGS + PT_CAUSE)(a0)
52
53	/* Return non-zero value */
54	li	a0, 1
55
56	/* Return to C code */
57	ret
58END(__cpu_suspend_enter)
59
60ENTRY(__cpu_resume_enter)
61	/* Load the global pointer */
62	.option push
63	.option norelax
64		la gp, __global_pointer$
65	.option pop
66
67#ifdef CONFIG_MMU
68	/* Save A0 and A1 */
69	add	t0, a0, zero
70	add	t1, a1, zero
71
72	/* Enable MMU */
73	la	a0, swapper_pg_dir
74	XIP_FIXUP_OFFSET a0
75	call	relocate_enable_mmu
76
77	/* Restore A0 and A1 */
78	add	a0, t0, zero
79	add	a1, t1, zero
80#endif
81
82	/* Make A0 point to suspend context */
83	add	a0, a1, zero
84
85	/* Restore CSRs */
86	REG_L	t0, (SUSPEND_CONTEXT_REGS + PT_EPC)(a0)
87	csrw	CSR_EPC, t0
88	REG_L	t0, (SUSPEND_CONTEXT_REGS + PT_STATUS)(a0)
89	csrw	CSR_STATUS, t0
90	REG_L	t0, (SUSPEND_CONTEXT_REGS + PT_BADADDR)(a0)
91	csrw	CSR_TVAL, t0
92	REG_L	t0, (SUSPEND_CONTEXT_REGS + PT_CAUSE)(a0)
93	csrw	CSR_CAUSE, t0
94
95	/* Restore registers (except A0 and T0-T6) */
96	REG_L	ra, (SUSPEND_CONTEXT_REGS + PT_RA)(a0)
97	REG_L	sp, (SUSPEND_CONTEXT_REGS + PT_SP)(a0)
98	REG_L	gp, (SUSPEND_CONTEXT_REGS + PT_GP)(a0)
99	REG_L	tp, (SUSPEND_CONTEXT_REGS + PT_TP)(a0)
100	REG_L	s0, (SUSPEND_CONTEXT_REGS + PT_S0)(a0)
101	REG_L	s1, (SUSPEND_CONTEXT_REGS + PT_S1)(a0)
102	REG_L	a1, (SUSPEND_CONTEXT_REGS + PT_A1)(a0)
103	REG_L	a2, (SUSPEND_CONTEXT_REGS + PT_A2)(a0)
104	REG_L	a3, (SUSPEND_CONTEXT_REGS + PT_A3)(a0)
105	REG_L	a4, (SUSPEND_CONTEXT_REGS + PT_A4)(a0)
106	REG_L	a5, (SUSPEND_CONTEXT_REGS + PT_A5)(a0)
107	REG_L	a6, (SUSPEND_CONTEXT_REGS + PT_A6)(a0)
108	REG_L	a7, (SUSPEND_CONTEXT_REGS + PT_A7)(a0)
109	REG_L	s2, (SUSPEND_CONTEXT_REGS + PT_S2)(a0)
110	REG_L	s3, (SUSPEND_CONTEXT_REGS + PT_S3)(a0)
111	REG_L	s4, (SUSPEND_CONTEXT_REGS + PT_S4)(a0)
112	REG_L	s5, (SUSPEND_CONTEXT_REGS + PT_S5)(a0)
113	REG_L	s6, (SUSPEND_CONTEXT_REGS + PT_S6)(a0)
114	REG_L	s7, (SUSPEND_CONTEXT_REGS + PT_S7)(a0)
115	REG_L	s8, (SUSPEND_CONTEXT_REGS + PT_S8)(a0)
116	REG_L	s9, (SUSPEND_CONTEXT_REGS + PT_S9)(a0)
117	REG_L	s10, (SUSPEND_CONTEXT_REGS + PT_S10)(a0)
118	REG_L	s11, (SUSPEND_CONTEXT_REGS + PT_S11)(a0)
119
120	/* Return zero value */
121	add	a0, zero, zero
122
123	/* Return to C code */
124	ret
125END(__cpu_resume_enter)
126