1 /* 2 * Copyright (C) 2014 Imagination Technologies 3 * Author: Paul Burton <paul.burton@imgtec.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License as published by the 7 * Free Software Foundation; either version 2 of the License, or (at your 8 * option) any later version. 9 */ 10 11 #include <linux/cpu_pm.h> 12 #include <linux/cpuidle.h> 13 #include <linux/init.h> 14 15 #include <asm/idle.h> 16 #include <asm/pm-cps.h> 17 18 /* Enumeration of the various idle states this driver may enter */ 19 enum cps_idle_state { 20 STATE_WAIT = 0, /* MIPS wait instruction, coherent */ 21 STATE_NC_WAIT, /* MIPS wait instruction, non-coherent */ 22 STATE_CLOCK_GATED, /* Core clock gated */ 23 STATE_POWER_GATED, /* Core power gated */ 24 STATE_COUNT 25 }; 26 27 static int cps_nc_enter(struct cpuidle_device *dev, 28 struct cpuidle_driver *drv, int index) 29 { 30 enum cps_pm_state pm_state; 31 int err; 32 33 /* 34 * At least one core must remain powered up & clocked in order for the 35 * system to have any hope of functioning. 36 * 37 * TODO: don't treat core 0 specially, just prevent the final core 38 * TODO: remap interrupt affinity temporarily 39 */ 40 if (!cpu_data[dev->cpu].core && (index > STATE_NC_WAIT)) 41 index = STATE_NC_WAIT; 42 43 /* Select the appropriate cps_pm_state */ 44 switch (index) { 45 case STATE_NC_WAIT: 46 pm_state = CPS_PM_NC_WAIT; 47 break; 48 case STATE_CLOCK_GATED: 49 pm_state = CPS_PM_CLOCK_GATED; 50 break; 51 case STATE_POWER_GATED: 52 pm_state = CPS_PM_POWER_GATED; 53 break; 54 default: 55 BUG(); 56 return -EINVAL; 57 } 58 59 /* Notify listeners the CPU is about to power down */ 60 if ((pm_state == CPS_PM_POWER_GATED) && cpu_pm_enter()) 61 return -EINTR; 62 63 /* Enter that state */ 64 err = cps_pm_enter_state(pm_state); 65 66 /* Notify listeners the CPU is back up */ 67 if (pm_state == CPS_PM_POWER_GATED) 68 cpu_pm_exit(); 69 70 return err ?: index; 71 } 72 73 static struct cpuidle_driver cps_driver = { 74 .name = "cpc_cpuidle", 75 .owner = THIS_MODULE, 76 .states = { 77 [STATE_WAIT] = MIPS_CPUIDLE_WAIT_STATE, 78 [STATE_NC_WAIT] = { 79 .enter = cps_nc_enter, 80 .exit_latency = 200, 81 .target_residency = 450, 82 .flags = CPUIDLE_FLAG_TIME_VALID, 83 .name = "nc-wait", 84 .desc = "non-coherent MIPS wait", 85 }, 86 [STATE_CLOCK_GATED] = { 87 .enter = cps_nc_enter, 88 .exit_latency = 300, 89 .target_residency = 700, 90 .flags = CPUIDLE_FLAG_TIME_VALID | 91 CPUIDLE_FLAG_TIMER_STOP, 92 .name = "clock-gated", 93 .desc = "core clock gated", 94 }, 95 [STATE_POWER_GATED] = { 96 .enter = cps_nc_enter, 97 .exit_latency = 600, 98 .target_residency = 1000, 99 .flags = CPUIDLE_FLAG_TIME_VALID | 100 CPUIDLE_FLAG_TIMER_STOP, 101 .name = "power-gated", 102 .desc = "core power gated", 103 }, 104 }, 105 .state_count = STATE_COUNT, 106 .safe_state_index = 0, 107 }; 108 109 static void __init cps_cpuidle_unregister(void) 110 { 111 int cpu; 112 struct cpuidle_device *device; 113 114 for_each_possible_cpu(cpu) { 115 device = &per_cpu(cpuidle_dev, cpu); 116 cpuidle_unregister_device(device); 117 } 118 119 cpuidle_unregister_driver(&cps_driver); 120 } 121 122 static int __init cps_cpuidle_init(void) 123 { 124 int err, cpu, core, i; 125 struct cpuidle_device *device; 126 127 /* Detect supported states */ 128 if (!cps_pm_support_state(CPS_PM_POWER_GATED)) 129 cps_driver.state_count = STATE_CLOCK_GATED + 1; 130 if (!cps_pm_support_state(CPS_PM_CLOCK_GATED)) 131 cps_driver.state_count = STATE_NC_WAIT + 1; 132 if (!cps_pm_support_state(CPS_PM_NC_WAIT)) 133 cps_driver.state_count = STATE_WAIT + 1; 134 135 /* Inform the user if some states are unavailable */ 136 if (cps_driver.state_count < STATE_COUNT) { 137 pr_info("cpuidle-cps: limited to "); 138 switch (cps_driver.state_count - 1) { 139 case STATE_WAIT: 140 pr_cont("coherent wait\n"); 141 break; 142 case STATE_NC_WAIT: 143 pr_cont("non-coherent wait\n"); 144 break; 145 case STATE_CLOCK_GATED: 146 pr_cont("clock gating\n"); 147 break; 148 } 149 } 150 151 /* 152 * Set the coupled flag on the appropriate states if this system 153 * requires it. 154 */ 155 if (coupled_coherence) 156 for (i = STATE_NC_WAIT; i < cps_driver.state_count; i++) 157 cps_driver.states[i].flags |= CPUIDLE_FLAG_COUPLED; 158 159 err = cpuidle_register_driver(&cps_driver); 160 if (err) { 161 pr_err("Failed to register CPS cpuidle driver\n"); 162 return err; 163 } 164 165 for_each_possible_cpu(cpu) { 166 core = cpu_data[cpu].core; 167 device = &per_cpu(cpuidle_dev, cpu); 168 device->cpu = cpu; 169 #ifdef CONFIG_MIPS_MT 170 cpumask_copy(&device->coupled_cpus, &cpu_sibling_map[cpu]); 171 #endif 172 173 err = cpuidle_register_device(device); 174 if (err) { 175 pr_err("Failed to register CPU%d cpuidle device\n", 176 cpu); 177 goto err_out; 178 } 179 } 180 181 return 0; 182 err_out: 183 cps_cpuidle_unregister(); 184 return err; 185 } 186 device_initcall(cps_cpuidle_init); 187