xref: /openbmc/linux/arch/mips/kernel/pm.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b1d4c6caSJames Hogan /*
3b1d4c6caSJames Hogan  * Copyright (C) 2014 Imagination Technologies Ltd.
4b1d4c6caSJames Hogan  *
5b1d4c6caSJames Hogan  * CPU PM notifiers for saving/restoring general CPU state.
6b1d4c6caSJames Hogan  */
7b1d4c6caSJames Hogan 
8b1d4c6caSJames Hogan #include <linux/cpu_pm.h>
9b1d4c6caSJames Hogan #include <linux/init.h>
10b1d4c6caSJames Hogan 
11b1d4c6caSJames Hogan #include <asm/dsp.h>
12b1d4c6caSJames Hogan #include <asm/fpu.h>
13b1d4c6caSJames Hogan #include <asm/mmu_context.h>
1474e91335SJames Hogan #include <asm/pm.h>
15b1d4c6caSJames Hogan #include <asm/watch.h>
16b1d4c6caSJames Hogan 
1774e91335SJames Hogan /* Used by PM helper macros in asm/pm.h */
1874e91335SJames Hogan struct mips_static_suspend_state mips_static_suspend_state;
1974e91335SJames Hogan 
20b1d4c6caSJames Hogan /**
21b1d4c6caSJames Hogan  * mips_cpu_save() - Save general CPU state.
22b1d4c6caSJames Hogan  * Ensures that general CPU context is saved, notably FPU and DSP.
23b1d4c6caSJames Hogan  */
mips_cpu_save(void)24b1d4c6caSJames Hogan static int mips_cpu_save(void)
25b1d4c6caSJames Hogan {
26b1d4c6caSJames Hogan 	/* Save FPU state */
27b1d4c6caSJames Hogan 	lose_fpu(1);
28b1d4c6caSJames Hogan 
29b1d4c6caSJames Hogan 	/* Save DSP state */
30b1d4c6caSJames Hogan 	save_dsp(current);
31b1d4c6caSJames Hogan 
32b1d4c6caSJames Hogan 	return 0;
33b1d4c6caSJames Hogan }
34b1d4c6caSJames Hogan 
35b1d4c6caSJames Hogan /**
36b1d4c6caSJames Hogan  * mips_cpu_restore() - Restore general CPU state.
37b1d4c6caSJames Hogan  * Restores important CPU context.
38b1d4c6caSJames Hogan  */
mips_cpu_restore(void)39b1d4c6caSJames Hogan static void mips_cpu_restore(void)
40b1d4c6caSJames Hogan {
41b1d4c6caSJames Hogan 	unsigned int cpu = smp_processor_id();
42b1d4c6caSJames Hogan 
43b1d4c6caSJames Hogan 	/* Restore ASID */
44b1d4c6caSJames Hogan 	if (current->mm)
45b1d4c6caSJames Hogan 		write_c0_entryhi(cpu_asid(cpu, current->mm));
46b1d4c6caSJames Hogan 
47b1d4c6caSJames Hogan 	/* Restore DSP state */
48b1d4c6caSJames Hogan 	restore_dsp(current);
49b1d4c6caSJames Hogan 
50b1d4c6caSJames Hogan 	/* Restore UserLocal */
51b1d4c6caSJames Hogan 	if (cpu_has_userlocal)
52b1d4c6caSJames Hogan 		write_c0_userlocal(current_thread_info()->tp_value);
53b1d4c6caSJames Hogan 
54b1d4c6caSJames Hogan 	/* Restore watch registers */
55a7e89326SJames Hogan 	__restore_watch(current);
56b1d4c6caSJames Hogan }
57b1d4c6caSJames Hogan 
58b1d4c6caSJames Hogan /**
59b1d4c6caSJames Hogan  * mips_pm_notifier() - Notifier for preserving general CPU context.
60b1d4c6caSJames Hogan  * @self:	Notifier block.
61b1d4c6caSJames Hogan  * @cmd:	CPU PM event.
62b1d4c6caSJames Hogan  * @v:		Private data (unused).
63b1d4c6caSJames Hogan  *
64b1d4c6caSJames Hogan  * This is called when a CPU power management event occurs, and is used to
65b1d4c6caSJames Hogan  * ensure that important CPU context is preserved across a CPU power down.
66b1d4c6caSJames Hogan  */
mips_pm_notifier(struct notifier_block * self,unsigned long cmd,void * v)67b1d4c6caSJames Hogan static int mips_pm_notifier(struct notifier_block *self, unsigned long cmd,
68b1d4c6caSJames Hogan 			    void *v)
69b1d4c6caSJames Hogan {
70b1d4c6caSJames Hogan 	int ret;
71b1d4c6caSJames Hogan 
72b1d4c6caSJames Hogan 	switch (cmd) {
73b1d4c6caSJames Hogan 	case CPU_PM_ENTER:
74b1d4c6caSJames Hogan 		ret = mips_cpu_save();
75b1d4c6caSJames Hogan 		if (ret)
76b1d4c6caSJames Hogan 			return NOTIFY_STOP;
77b1d4c6caSJames Hogan 		break;
78b1d4c6caSJames Hogan 	case CPU_PM_ENTER_FAILED:
79b1d4c6caSJames Hogan 	case CPU_PM_EXIT:
80b1d4c6caSJames Hogan 		mips_cpu_restore();
81b1d4c6caSJames Hogan 		break;
82b1d4c6caSJames Hogan 	}
83b1d4c6caSJames Hogan 
84b1d4c6caSJames Hogan 	return NOTIFY_OK;
85b1d4c6caSJames Hogan }
86b1d4c6caSJames Hogan 
87b1d4c6caSJames Hogan static struct notifier_block mips_pm_notifier_block = {
88b1d4c6caSJames Hogan 	.notifier_call = mips_pm_notifier,
89b1d4c6caSJames Hogan };
90b1d4c6caSJames Hogan 
mips_pm_init(void)91b1d4c6caSJames Hogan static int __init mips_pm_init(void)
92b1d4c6caSJames Hogan {
93b1d4c6caSJames Hogan 	return cpu_pm_register_notifier(&mips_pm_notifier_block);
94b1d4c6caSJames Hogan }
95b1d4c6caSJames Hogan arch_initcall(mips_pm_init);
96