1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * loongson-specific suspend support
4  *
5  * Author: Huacai Chen <chenhuacai@loongson.cn>
6  * Copyright (C) 2020 Loongson Technology Co., Ltd.
7  */
8 #include <linux/acpi.h>
9 #include <linux/pm.h>
10 #include <linux/suspend.h>
11 
12 #include <asm/loongarchregs.h>
13 #include <asm/setup.h>
14 #include <asm/time.h>
15 #include <asm/tlbflush.h>
16 
17 #include <loongson.h>
18 
19 u64 loongarch_suspend_addr;
20 
21 struct saved_registers {
22 	u32 ecfg;
23 	u32 euen;
24 	u64 pgd;
25 	u64 kpgd;
26 	u32 pwctl0;
27 	u32 pwctl1;
28 };
29 static struct saved_registers saved_regs;
30 
arch_common_suspend(void)31 static void arch_common_suspend(void)
32 {
33 	save_counter();
34 	saved_regs.pgd = csr_read64(LOONGARCH_CSR_PGDL);
35 	saved_regs.kpgd = csr_read64(LOONGARCH_CSR_PGDH);
36 	saved_regs.pwctl0 = csr_read32(LOONGARCH_CSR_PWCTL0);
37 	saved_regs.pwctl1 = csr_read32(LOONGARCH_CSR_PWCTL1);
38 	saved_regs.ecfg = csr_read32(LOONGARCH_CSR_ECFG);
39 	saved_regs.euen = csr_read32(LOONGARCH_CSR_EUEN);
40 
41 	loongarch_suspend_addr = loongson_sysconf.suspend_addr;
42 }
43 
arch_common_resume(void)44 static void arch_common_resume(void)
45 {
46 	sync_counter();
47 	local_flush_tlb_all();
48 	csr_write64(per_cpu_offset(0), PERCPU_BASE_KS);
49 	csr_write64(eentry, LOONGARCH_CSR_EENTRY);
50 	csr_write64(eentry, LOONGARCH_CSR_MERRENTRY);
51 	csr_write64(tlbrentry, LOONGARCH_CSR_TLBRENTRY);
52 
53 	csr_write64(saved_regs.pgd, LOONGARCH_CSR_PGDL);
54 	csr_write64(saved_regs.kpgd, LOONGARCH_CSR_PGDH);
55 	csr_write32(saved_regs.pwctl0, LOONGARCH_CSR_PWCTL0);
56 	csr_write32(saved_regs.pwctl1, LOONGARCH_CSR_PWCTL1);
57 	csr_write32(saved_regs.ecfg, LOONGARCH_CSR_ECFG);
58 	csr_write32(saved_regs.euen, LOONGARCH_CSR_EUEN);
59 }
60 
loongarch_acpi_suspend(void)61 int loongarch_acpi_suspend(void)
62 {
63 	enable_gpe_wakeup();
64 	enable_pci_wakeup();
65 
66 	arch_common_suspend();
67 
68 	/* processor specific suspend */
69 	loongarch_suspend_enter();
70 
71 	arch_common_resume();
72 
73 	return 0;
74 }
75