0001
0002
0003
0004
0005
0006
0007 #include <linux/cpu_pm.h>
0008 #include <linux/cpuidle.h>
0009 #include <linux/init.h>
0010
0011 #include <asm/idle.h>
0012 #include <asm/pm-cps.h>
0013
0014
0015 enum cps_idle_state {
0016 STATE_WAIT = 0,
0017 STATE_NC_WAIT,
0018 STATE_CLOCK_GATED,
0019 STATE_POWER_GATED,
0020 STATE_COUNT
0021 };
0022
0023 static int cps_nc_enter(struct cpuidle_device *dev,
0024 struct cpuidle_driver *drv, int index)
0025 {
0026 enum cps_pm_state pm_state;
0027 int err;
0028
0029
0030
0031
0032
0033
0034
0035
0036 if (cpus_are_siblings(0, dev->cpu) && (index > STATE_NC_WAIT))
0037 index = STATE_NC_WAIT;
0038
0039
0040 switch (index) {
0041 case STATE_NC_WAIT:
0042 pm_state = CPS_PM_NC_WAIT;
0043 break;
0044 case STATE_CLOCK_GATED:
0045 pm_state = CPS_PM_CLOCK_GATED;
0046 break;
0047 case STATE_POWER_GATED:
0048 pm_state = CPS_PM_POWER_GATED;
0049 break;
0050 default:
0051 BUG();
0052 return -EINVAL;
0053 }
0054
0055
0056 if ((pm_state == CPS_PM_POWER_GATED) && cpu_pm_enter())
0057 return -EINTR;
0058
0059
0060 err = cps_pm_enter_state(pm_state);
0061
0062
0063 if (pm_state == CPS_PM_POWER_GATED)
0064 cpu_pm_exit();
0065
0066 return err ?: index;
0067 }
0068
0069 static struct cpuidle_driver cps_driver = {
0070 .name = "cpc_cpuidle",
0071 .owner = THIS_MODULE,
0072 .states = {
0073 [STATE_WAIT] = MIPS_CPUIDLE_WAIT_STATE,
0074 [STATE_NC_WAIT] = {
0075 .enter = cps_nc_enter,
0076 .exit_latency = 200,
0077 .target_residency = 450,
0078 .name = "nc-wait",
0079 .desc = "non-coherent MIPS wait",
0080 },
0081 [STATE_CLOCK_GATED] = {
0082 .enter = cps_nc_enter,
0083 .exit_latency = 300,
0084 .target_residency = 700,
0085 .flags = CPUIDLE_FLAG_TIMER_STOP,
0086 .name = "clock-gated",
0087 .desc = "core clock gated",
0088 },
0089 [STATE_POWER_GATED] = {
0090 .enter = cps_nc_enter,
0091 .exit_latency = 600,
0092 .target_residency = 1000,
0093 .flags = CPUIDLE_FLAG_TIMER_STOP,
0094 .name = "power-gated",
0095 .desc = "core power gated",
0096 },
0097 },
0098 .state_count = STATE_COUNT,
0099 .safe_state_index = 0,
0100 };
0101
0102 static void __init cps_cpuidle_unregister(void)
0103 {
0104 int cpu;
0105 struct cpuidle_device *device;
0106
0107 for_each_possible_cpu(cpu) {
0108 device = &per_cpu(cpuidle_dev, cpu);
0109 cpuidle_unregister_device(device);
0110 }
0111
0112 cpuidle_unregister_driver(&cps_driver);
0113 }
0114
0115 static int __init cps_cpuidle_init(void)
0116 {
0117 int err, cpu, i;
0118 struct cpuidle_device *device;
0119
0120
0121 if (!cps_pm_support_state(CPS_PM_POWER_GATED))
0122 cps_driver.state_count = STATE_CLOCK_GATED + 1;
0123 if (!cps_pm_support_state(CPS_PM_CLOCK_GATED))
0124 cps_driver.state_count = STATE_NC_WAIT + 1;
0125 if (!cps_pm_support_state(CPS_PM_NC_WAIT))
0126 cps_driver.state_count = STATE_WAIT + 1;
0127
0128
0129 if (cps_driver.state_count < STATE_COUNT) {
0130 pr_info("cpuidle-cps: limited to ");
0131 switch (cps_driver.state_count - 1) {
0132 case STATE_WAIT:
0133 pr_cont("coherent wait\n");
0134 break;
0135 case STATE_NC_WAIT:
0136 pr_cont("non-coherent wait\n");
0137 break;
0138 case STATE_CLOCK_GATED:
0139 pr_cont("clock gating\n");
0140 break;
0141 }
0142 }
0143
0144
0145
0146
0147
0148 if (coupled_coherence)
0149 for (i = STATE_NC_WAIT; i < cps_driver.state_count; i++)
0150 cps_driver.states[i].flags |= CPUIDLE_FLAG_COUPLED;
0151
0152 err = cpuidle_register_driver(&cps_driver);
0153 if (err) {
0154 pr_err("Failed to register CPS cpuidle driver\n");
0155 return err;
0156 }
0157
0158 for_each_possible_cpu(cpu) {
0159 device = &per_cpu(cpuidle_dev, cpu);
0160 device->cpu = cpu;
0161 #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
0162 cpumask_copy(&device->coupled_cpus, &cpu_sibling_map[cpu]);
0163 #endif
0164
0165 err = cpuidle_register_device(device);
0166 if (err) {
0167 pr_err("Failed to register CPU%d cpuidle device\n",
0168 cpu);
0169 goto err_out;
0170 }
0171 }
0172
0173 return 0;
0174 err_out:
0175 cps_cpuidle_unregister();
0176 return err;
0177 }
0178 device_initcall(cps_cpuidle_init);