162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * loongson-specific suspend support
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Huacai Chen <chenhuacai@loongson.cn>
662306a36Sopenharmony_ci * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci#include <linux/acpi.h>
962306a36Sopenharmony_ci#include <linux/pm.h>
1062306a36Sopenharmony_ci#include <linux/suspend.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <asm/loongarch.h>
1362306a36Sopenharmony_ci#include <asm/loongson.h>
1462306a36Sopenharmony_ci#include <asm/setup.h>
1562306a36Sopenharmony_ci#include <asm/time.h>
1662306a36Sopenharmony_ci#include <asm/tlbflush.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ciu64 loongarch_suspend_addr;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistruct saved_registers {
2162306a36Sopenharmony_ci	u32 ecfg;
2262306a36Sopenharmony_ci	u32 euen;
2362306a36Sopenharmony_ci	u64 pgd;
2462306a36Sopenharmony_ci	u64 kpgd;
2562306a36Sopenharmony_ci	u32 pwctl0;
2662306a36Sopenharmony_ci	u32 pwctl1;
2762306a36Sopenharmony_ci};
2862306a36Sopenharmony_cistatic struct saved_registers saved_regs;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_civoid loongarch_common_suspend(void)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	save_counter();
3362306a36Sopenharmony_ci	saved_regs.pgd = csr_read64(LOONGARCH_CSR_PGDL);
3462306a36Sopenharmony_ci	saved_regs.kpgd = csr_read64(LOONGARCH_CSR_PGDH);
3562306a36Sopenharmony_ci	saved_regs.pwctl0 = csr_read32(LOONGARCH_CSR_PWCTL0);
3662306a36Sopenharmony_ci	saved_regs.pwctl1 = csr_read32(LOONGARCH_CSR_PWCTL1);
3762306a36Sopenharmony_ci	saved_regs.ecfg = csr_read32(LOONGARCH_CSR_ECFG);
3862306a36Sopenharmony_ci	saved_regs.euen = csr_read32(LOONGARCH_CSR_EUEN);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	loongarch_suspend_addr = loongson_sysconf.suspend_addr;
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_civoid loongarch_common_resume(void)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	sync_counter();
4662306a36Sopenharmony_ci	local_flush_tlb_all();
4762306a36Sopenharmony_ci	csr_write64(per_cpu_offset(0), PERCPU_BASE_KS);
4862306a36Sopenharmony_ci	csr_write64(eentry, LOONGARCH_CSR_EENTRY);
4962306a36Sopenharmony_ci	csr_write64(eentry, LOONGARCH_CSR_MERRENTRY);
5062306a36Sopenharmony_ci	csr_write64(tlbrentry, LOONGARCH_CSR_TLBRENTRY);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	csr_write64(saved_regs.pgd, LOONGARCH_CSR_PGDL);
5362306a36Sopenharmony_ci	csr_write64(saved_regs.kpgd, LOONGARCH_CSR_PGDH);
5462306a36Sopenharmony_ci	csr_write32(saved_regs.pwctl0, LOONGARCH_CSR_PWCTL0);
5562306a36Sopenharmony_ci	csr_write32(saved_regs.pwctl1, LOONGARCH_CSR_PWCTL1);
5662306a36Sopenharmony_ci	csr_write32(saved_regs.ecfg, LOONGARCH_CSR_ECFG);
5762306a36Sopenharmony_ci	csr_write32(saved_regs.euen, LOONGARCH_CSR_EUEN);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ciint loongarch_acpi_suspend(void)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	enable_gpe_wakeup();
6362306a36Sopenharmony_ci	enable_pci_wakeup();
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	loongarch_common_suspend();
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	/* processor specific suspend */
6862306a36Sopenharmony_ci	loongarch_suspend_enter();
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	loongarch_common_resume();
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	return 0;
7362306a36Sopenharmony_ci}
74