1 /* 2 * Copyright (C) 2014 Imagination Technologies Ltd. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License as published by the 6 * Free Software Foundation; either version 2 of the License, or (at your 7 * option) any later version. 8 * 9 * CPU PM notifiers for saving/restoring general CPU state. 10 */ 11 12 #include <linux/cpu_pm.h> 13 #include <linux/init.h> 14 15 #include <asm/dsp.h> 16 #include <asm/fpu.h> 17 #include <asm/mmu_context.h> 18 #include <asm/pm.h> 19 #include <asm/watch.h> 20 21 /* Used by PM helper macros in asm/pm.h */ 22 struct mips_static_suspend_state mips_static_suspend_state; 23 24 /** 25 * mips_cpu_save() - Save general CPU state. 26 * Ensures that general CPU context is saved, notably FPU and DSP. 27 */ 28 static int mips_cpu_save(void) 29 { 30 /* Save FPU state */ 31 lose_fpu(1); 32 33 /* Save DSP state */ 34 save_dsp(current); 35 36 return 0; 37 } 38 39 /** 40 * mips_cpu_restore() - Restore general CPU state. 41 * Restores important CPU context. 42 */ 43 static void mips_cpu_restore(void) 44 { 45 unsigned int cpu = smp_processor_id(); 46 47 /* Restore ASID */ 48 if (current->mm) 49 write_c0_entryhi(cpu_asid(cpu, current->mm)); 50 51 /* Restore DSP state */ 52 restore_dsp(current); 53 54 /* Restore UserLocal */ 55 if (cpu_has_userlocal) 56 write_c0_userlocal(current_thread_info()->tp_value); 57 58 /* Restore watch registers */ 59 __restore_watch(); 60 } 61 62 /** 63 * mips_pm_notifier() - Notifier for preserving general CPU context. 64 * @self: Notifier block. 65 * @cmd: CPU PM event. 66 * @v: Private data (unused). 67 * 68 * This is called when a CPU power management event occurs, and is used to 69 * ensure that important CPU context is preserved across a CPU power down. 70 */ 71 static int mips_pm_notifier(struct notifier_block *self, unsigned long cmd, 72 void *v) 73 { 74 int ret; 75 76 switch (cmd) { 77 case CPU_PM_ENTER: 78 ret = mips_cpu_save(); 79 if (ret) 80 return NOTIFY_STOP; 81 break; 82 case CPU_PM_ENTER_FAILED: 83 case CPU_PM_EXIT: 84 mips_cpu_restore(); 85 break; 86 } 87 88 return NOTIFY_OK; 89 } 90 91 static struct notifier_block mips_pm_notifier_block = { 92 .notifier_call = mips_pm_notifier, 93 }; 94 95 static int __init mips_pm_init(void) 96 { 97 return cpu_pm_register_notifier(&mips_pm_notifier_block); 98 } 99 arch_initcall(mips_pm_init); 100