mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	LoongArch: Add suspend (ACPI S3) support
Add suspend (Suspend To RAM, aka ACPI S3) support for LoongArch. Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
This commit is contained in:
		
							parent
							
								
									27cab43156
								
							
						
					
					
						commit
						366bb35a8e
					
				
					 13 changed files with 260 additions and 3 deletions
				
			
		| 
						 | 
					@ -56,6 +56,7 @@ config LOONGARCH
 | 
				
			||||||
	select ARCH_WANTS_NO_INSTR
 | 
						select ARCH_WANTS_NO_INSTR
 | 
				
			||||||
	select BUILDTIME_TABLE_SORT
 | 
						select BUILDTIME_TABLE_SORT
 | 
				
			||||||
	select COMMON_CLK
 | 
						select COMMON_CLK
 | 
				
			||||||
 | 
						select CPU_PM
 | 
				
			||||||
	select EFI
 | 
						select EFI
 | 
				
			||||||
	select GENERIC_CLOCKEVENTS
 | 
						select GENERIC_CLOCKEVENTS
 | 
				
			||||||
	select GENERIC_CMOS_UPDATE
 | 
						select GENERIC_CMOS_UPDATE
 | 
				
			||||||
| 
						 | 
					@ -517,6 +518,10 @@ config ARCH_MMAP_RND_BITS_MAX
 | 
				
			||||||
 | 
					
 | 
				
			||||||
menu "Power management options"
 | 
					menu "Power management options"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config ARCH_SUSPEND_POSSIBLE
 | 
				
			||||||
 | 
						def_bool y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					source "kernel/power/Kconfig"
 | 
				
			||||||
source "drivers/acpi/Kconfig"
 | 
					source "drivers/acpi/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endmenu
 | 
					endmenu
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,6 +104,9 @@ endif
 | 
				
			||||||
libs-y += arch/loongarch/lib/
 | 
					libs-y += arch/loongarch/lib/
 | 
				
			||||||
libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
 | 
					libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# suspend and hibernation support
 | 
				
			||||||
 | 
					drivers-$(CONFIG_PM)	+= arch/loongarch/power/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifeq ($(KBUILD_EXTMOD),)
 | 
					ifeq ($(KBUILD_EXTMOD),)
 | 
				
			||||||
prepare: vdso_prepare
 | 
					prepare: vdso_prepare
 | 
				
			||||||
vdso_prepare: prepare0
 | 
					vdso_prepare: prepare0
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,4 +35,14 @@ extern struct list_head acpi_wakeup_device_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ACPI_TABLE_UPGRADE_MAX_PHYS ARCH_LOW_ADDRESS_LIMIT
 | 
					#define ACPI_TABLE_UPGRADE_MAX_PHYS ARCH_LOW_ADDRESS_LIMIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int loongarch_acpi_suspend(void);
 | 
				
			||||||
 | 
					extern int (*acpi_suspend_lowlevel)(void);
 | 
				
			||||||
 | 
					extern void loongarch_suspend_enter(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline unsigned long acpi_get_wakeup_address(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						extern void loongarch_wakeup_start(void);
 | 
				
			||||||
 | 
						return (unsigned long)loongarch_wakeup_start;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _ASM_LOONGARCH_ACPI_H */
 | 
					#endif /* _ASM_LOONGARCH_ACPI_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,6 +32,7 @@ struct loongson_system_configuration {
 | 
				
			||||||
	int cores_per_node;
 | 
						int cores_per_node;
 | 
				
			||||||
	int cores_per_package;
 | 
						int cores_per_package;
 | 
				
			||||||
	unsigned long cores_io_master;
 | 
						unsigned long cores_io_master;
 | 
				
			||||||
 | 
						unsigned long suspend_addr;
 | 
				
			||||||
	const char *cpuname;
 | 
						const char *cpuname;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -136,4 +136,7 @@ typedef enum {
 | 
				
			||||||
#define ls7a_writel(val, addr)	*(volatile unsigned int   *)TO_UNCACHE(addr) = (val)
 | 
					#define ls7a_writel(val, addr)	*(volatile unsigned int   *)TO_UNCACHE(addr) = (val)
 | 
				
			||||||
#define ls7a_writeq(val, addr)	*(volatile unsigned long  *)TO_UNCACHE(addr) = (val)
 | 
					#define ls7a_writeq(val, addr)	*(volatile unsigned long  *)TO_UNCACHE(addr) = (val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void enable_gpe_wakeup(void);
 | 
				
			||||||
 | 
					void enable_pci_wakeup(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __ASM_LOONGSON_H */
 | 
					#endif /* __ASM_LOONGSON_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
extern u64 cpu_clock_freq;
 | 
					extern u64 cpu_clock_freq;
 | 
				
			||||||
extern u64 const_clock_freq;
 | 
					extern u64 const_clock_freq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void save_counter(void);
 | 
				
			||||||
extern void sync_counter(void);
 | 
					extern void sync_counter(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline unsigned int calc_const_freq(void)
 | 
					static inline unsigned int calc_const_freq(void)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -140,6 +140,12 @@ static void __init acpi_process_madt(void)
 | 
				
			||||||
	loongson_sysconf.nr_cpus = num_processors;
 | 
						loongson_sysconf.nr_cpus = num_processors;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CONFIG_SUSPEND
 | 
				
			||||||
 | 
					int (*acpi_suspend_lowlevel)(void);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					int (*acpi_suspend_lowlevel)(void) = loongarch_acpi_suspend;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void __init acpi_boot_table_init(void)
 | 
					void __init acpi_boot_table_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,7 @@
 | 
				
			||||||
#include <linux/smp.h>
 | 
					#include <linux/smp.h>
 | 
				
			||||||
#include <linux/threads.h>
 | 
					#include <linux/threads.h>
 | 
				
			||||||
#include <linux/export.h>
 | 
					#include <linux/export.h>
 | 
				
			||||||
 | 
					#include <linux/syscore_ops.h>
 | 
				
			||||||
#include <linux/time.h>
 | 
					#include <linux/time.h>
 | 
				
			||||||
#include <linux/tracepoint.h>
 | 
					#include <linux/tracepoint.h>
 | 
				
			||||||
#include <linux/sched/hotplug.h>
 | 
					#include <linux/sched/hotplug.h>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -115,12 +115,17 @@ static unsigned long __init get_loops_per_jiffy(void)
 | 
				
			||||||
	return lpj;
 | 
						return lpj;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static long init_timeval;
 | 
					static long init_offset __nosavedata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void save_counter(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						init_offset = drdtime();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void sync_counter(void)
 | 
					void sync_counter(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Ensure counter begin at 0 */
 | 
						/* Ensure counter begin at 0 */
 | 
				
			||||||
	csr_write64(-init_timeval, LOONGARCH_CSR_CNTC);
 | 
						csr_write64(init_offset, LOONGARCH_CSR_CNTC);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int get_timer_irq(void)
 | 
					static int get_timer_irq(void)
 | 
				
			||||||
| 
						 | 
					@ -219,7 +224,7 @@ void __init time_init(void)
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		const_clock_freq = calc_const_freq();
 | 
							const_clock_freq = calc_const_freq();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	init_timeval = drdtime() - csr_read64(LOONGARCH_CSR_CNTC);
 | 
						init_offset = -(drdtime() - csr_read64(LOONGARCH_CSR_CNTC));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	constant_clockevent_init();
 | 
						constant_clockevent_init();
 | 
				
			||||||
	constant_clocksource_init();
 | 
						constant_clocksource_init();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										3
									
								
								arch/loongarch/power/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								arch/loongarch/power/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					obj-y	+= platform.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-$(CONFIG_SUSPEND)		+= suspend.o suspend_asm.o
 | 
				
			||||||
							
								
								
									
										57
									
								
								arch/loongarch/power/platform.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								arch/loongarch/power/platform.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,57 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Author: Huacai Chen <chenhuacai@loongson.cn>
 | 
				
			||||||
 | 
					 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#include <linux/acpi.h>
 | 
				
			||||||
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/bootinfo.h>
 | 
				
			||||||
 | 
					#include <asm/loongson.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void enable_gpe_wakeup(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (acpi_disabled)
 | 
				
			||||||
 | 
						       return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (acpi_gbl_reduced_hardware)
 | 
				
			||||||
 | 
						       return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acpi_enable_all_wakeup_gpes();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void enable_pci_wakeup(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (acpi_disabled)
 | 
				
			||||||
 | 
						       return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (acpi_gbl_reduced_hardware)
 | 
				
			||||||
 | 
						       return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acpi_write_bit_register(ACPI_BITREG_PCIEXP_WAKE_STATUS, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (acpi_gbl_FADT.flags & ACPI_FADT_PCI_EXPRESS_WAKE)
 | 
				
			||||||
 | 
							acpi_write_bit_register(ACPI_BITREG_PCIEXP_WAKE_DISABLE, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int __init loongson3_acpi_suspend_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef CONFIG_ACPI
 | 
				
			||||||
 | 
						acpi_status status;
 | 
				
			||||||
 | 
						uint64_t suspend_addr = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (acpi_disabled || acpi_gbl_reduced_hardware)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1);
 | 
				
			||||||
 | 
						status = acpi_evaluate_integer(NULL, "\\SADR", NULL, &suspend_addr);
 | 
				
			||||||
 | 
						if (ACPI_FAILURE(status) || !suspend_addr) {
 | 
				
			||||||
 | 
							pr_err("ACPI S3 is not support!\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						loongson_sysconf.suspend_addr = (u64)phys_to_virt(PHYSADDR(suspend_addr));
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					device_initcall(loongson3_acpi_suspend_init);
 | 
				
			||||||
							
								
								
									
										73
									
								
								arch/loongarch/power/suspend.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								arch/loongarch/power/suspend.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,73 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * loongson-specific suspend support
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Huacai Chen <chenhuacai@loongson.cn>
 | 
				
			||||||
 | 
					 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#include <linux/acpi.h>
 | 
				
			||||||
 | 
					#include <linux/pm.h>
 | 
				
			||||||
 | 
					#include <linux/suspend.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/loongarch.h>
 | 
				
			||||||
 | 
					#include <asm/loongson.h>
 | 
				
			||||||
 | 
					#include <asm/setup.h>
 | 
				
			||||||
 | 
					#include <asm/time.h>
 | 
				
			||||||
 | 
					#include <asm/tlbflush.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					u64 loongarch_suspend_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct saved_registers {
 | 
				
			||||||
 | 
						u32 ecfg;
 | 
				
			||||||
 | 
						u32 euen;
 | 
				
			||||||
 | 
						u64 pgd;
 | 
				
			||||||
 | 
						u64 kpgd;
 | 
				
			||||||
 | 
						u32 pwctl0;
 | 
				
			||||||
 | 
						u32 pwctl1;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					static struct saved_registers saved_regs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void arch_common_suspend(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						save_counter();
 | 
				
			||||||
 | 
						saved_regs.pgd = csr_read64(LOONGARCH_CSR_PGDL);
 | 
				
			||||||
 | 
						saved_regs.kpgd = csr_read64(LOONGARCH_CSR_PGDH);
 | 
				
			||||||
 | 
						saved_regs.pwctl0 = csr_read32(LOONGARCH_CSR_PWCTL0);
 | 
				
			||||||
 | 
						saved_regs.pwctl1 = csr_read32(LOONGARCH_CSR_PWCTL1);
 | 
				
			||||||
 | 
						saved_regs.ecfg = csr_read32(LOONGARCH_CSR_ECFG);
 | 
				
			||||||
 | 
						saved_regs.euen = csr_read32(LOONGARCH_CSR_EUEN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						loongarch_suspend_addr = loongson_sysconf.suspend_addr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void arch_common_resume(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						sync_counter();
 | 
				
			||||||
 | 
						local_flush_tlb_all();
 | 
				
			||||||
 | 
						csr_write64(per_cpu_offset(0), PERCPU_BASE_KS);
 | 
				
			||||||
 | 
						csr_write64(eentry, LOONGARCH_CSR_EENTRY);
 | 
				
			||||||
 | 
						csr_write64(eentry, LOONGARCH_CSR_MERRENTRY);
 | 
				
			||||||
 | 
						csr_write64(tlbrentry, LOONGARCH_CSR_TLBRENTRY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						csr_write64(saved_regs.pgd, LOONGARCH_CSR_PGDL);
 | 
				
			||||||
 | 
						csr_write64(saved_regs.kpgd, LOONGARCH_CSR_PGDH);
 | 
				
			||||||
 | 
						csr_write32(saved_regs.pwctl0, LOONGARCH_CSR_PWCTL0);
 | 
				
			||||||
 | 
						csr_write32(saved_regs.pwctl1, LOONGARCH_CSR_PWCTL1);
 | 
				
			||||||
 | 
						csr_write32(saved_regs.ecfg, LOONGARCH_CSR_ECFG);
 | 
				
			||||||
 | 
						csr_write32(saved_regs.euen, LOONGARCH_CSR_EUEN);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int loongarch_acpi_suspend(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						enable_gpe_wakeup();
 | 
				
			||||||
 | 
						enable_pci_wakeup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						arch_common_suspend();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* processor specific suspend */
 | 
				
			||||||
 | 
						loongarch_suspend_enter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						arch_common_resume();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										89
									
								
								arch/loongarch/power/suspend_asm.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								arch/loongarch/power/suspend_asm.S
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,89 @@
 | 
				
			||||||
 | 
					/* SPDX-License-Identifier: GPL-2.0 */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Sleep helper for Loongson-3 sleep mode.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Huacai Chen <chenhuacai@loongson.cn>
 | 
				
			||||||
 | 
					 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/asm.h>
 | 
				
			||||||
 | 
					#include <asm/asmmacro.h>
 | 
				
			||||||
 | 
					#include <asm/addrspace.h>
 | 
				
			||||||
 | 
					#include <asm/loongarch.h>
 | 
				
			||||||
 | 
					#include <asm/stackframe.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* preparatory stuff */
 | 
				
			||||||
 | 
					.macro	SETUP_SLEEP
 | 
				
			||||||
 | 
						addi.d		sp, sp, -PT_SIZE
 | 
				
			||||||
 | 
						st.d		$r1, sp, PT_R1
 | 
				
			||||||
 | 
						st.d		$r2, sp, PT_R2
 | 
				
			||||||
 | 
						st.d		$r3, sp, PT_R3
 | 
				
			||||||
 | 
						st.d		$r4, sp, PT_R4
 | 
				
			||||||
 | 
						st.d		$r21, sp, PT_R21
 | 
				
			||||||
 | 
						st.d		$r22, sp, PT_R22
 | 
				
			||||||
 | 
						st.d		$r23, sp, PT_R23
 | 
				
			||||||
 | 
						st.d		$r24, sp, PT_R24
 | 
				
			||||||
 | 
						st.d		$r25, sp, PT_R25
 | 
				
			||||||
 | 
						st.d		$r26, sp, PT_R26
 | 
				
			||||||
 | 
						st.d		$r27, sp, PT_R27
 | 
				
			||||||
 | 
						st.d		$r28, sp, PT_R28
 | 
				
			||||||
 | 
						st.d		$r29, sp, PT_R29
 | 
				
			||||||
 | 
						st.d		$r30, sp, PT_R30
 | 
				
			||||||
 | 
						st.d		$r31, sp, PT_R31
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						la.pcrel	t0, acpi_saved_sp
 | 
				
			||||||
 | 
						st.d		sp, t0, 0
 | 
				
			||||||
 | 
					.endm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.macro SETUP_WAKEUP
 | 
				
			||||||
 | 
						ld.d		$r1, sp, PT_R1
 | 
				
			||||||
 | 
						ld.d		$r2, sp, PT_R2
 | 
				
			||||||
 | 
						ld.d		$r3, sp, PT_R3
 | 
				
			||||||
 | 
						ld.d		$r4, sp, PT_R4
 | 
				
			||||||
 | 
						ld.d		$r21, sp, PT_R21
 | 
				
			||||||
 | 
						ld.d		$r22, sp, PT_R22
 | 
				
			||||||
 | 
						ld.d		$r23, sp, PT_R23
 | 
				
			||||||
 | 
						ld.d		$r24, sp, PT_R24
 | 
				
			||||||
 | 
						ld.d		$r25, sp, PT_R25
 | 
				
			||||||
 | 
						ld.d		$r26, sp, PT_R26
 | 
				
			||||||
 | 
						ld.d		$r27, sp, PT_R27
 | 
				
			||||||
 | 
						ld.d		$r28, sp, PT_R28
 | 
				
			||||||
 | 
						ld.d		$r29, sp, PT_R29
 | 
				
			||||||
 | 
						ld.d		$r30, sp, PT_R30
 | 
				
			||||||
 | 
						ld.d		$r31, sp, PT_R31
 | 
				
			||||||
 | 
					.endm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.text
 | 
				
			||||||
 | 
						.align 12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Sleep/wakeup code for Loongson-3 */
 | 
				
			||||||
 | 
					SYM_FUNC_START(loongarch_suspend_enter)
 | 
				
			||||||
 | 
						SETUP_SLEEP
 | 
				
			||||||
 | 
						bl		__flush_cache_all
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Pass RA and SP to BIOS */
 | 
				
			||||||
 | 
						addi.d		a1, sp, 0
 | 
				
			||||||
 | 
						la.pcrel	a0, loongarch_wakeup_start
 | 
				
			||||||
 | 
						la.pcrel	t0, loongarch_suspend_addr
 | 
				
			||||||
 | 
						ld.d		t0, t0, 0
 | 
				
			||||||
 | 
						jirl		a0, t0, 0 /* Call BIOS's STR sleep routine */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * This is where we return upon wakeup.
 | 
				
			||||||
 | 
						 * Reload all of the registers and return.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					SYM_INNER_LABEL(loongarch_wakeup_start, SYM_L_GLOBAL)
 | 
				
			||||||
 | 
						li.d		t0, CSR_DMW0_INIT	# UC, PLV0
 | 
				
			||||||
 | 
						csrwr		t0, LOONGARCH_CSR_DMWIN0
 | 
				
			||||||
 | 
						li.d		t0, CSR_DMW1_INIT	# CA, PLV0
 | 
				
			||||||
 | 
						csrwr		t0, LOONGARCH_CSR_DMWIN1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						la.abs		t0, 0f
 | 
				
			||||||
 | 
						jr		t0
 | 
				
			||||||
 | 
					0:
 | 
				
			||||||
 | 
						la.pcrel	t0, acpi_saved_sp
 | 
				
			||||||
 | 
						ld.d		sp, t0, 0
 | 
				
			||||||
 | 
						SETUP_WAKEUP
 | 
				
			||||||
 | 
						addi.d		sp, sp, PT_SIZE
 | 
				
			||||||
 | 
						jr		ra
 | 
				
			||||||
 | 
					SYM_FUNC_END(loongarch_suspend_enter)
 | 
				
			||||||
		Loading…
	
		Reference in a new issue