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 Hoganstatic 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 Hoganstatic 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 Hoganstatic 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 Hoganstatic 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