cpuidle-big_little.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2013 ARM/Linaro
  4. *
  5. * Authors: Daniel Lezcano <daniel.lezcano@linaro.org>
  6. * Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
  7. * Nicolas Pitre <nicolas.pitre@linaro.org>
  8. *
  9. * Maintainer: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
  10. * Maintainer: Daniel Lezcano <daniel.lezcano@linaro.org>
  11. */
  12. #include <linux/cpuidle.h>
  13. #include <linux/cpu_pm.h>
  14. #include <linux/slab.h>
  15. #include <linux/of.h>
  16. #include <asm/cpu.h>
  17. #include <asm/cputype.h>
  18. #include <asm/cpuidle.h>
  19. #include <asm/mcpm.h>
  20. #include <asm/smp_plat.h>
  21. #include <asm/suspend.h>
  22. #include "dt_idle_states.h"
  23. static int bl_enter_powerdown(struct cpuidle_device *dev,
  24. struct cpuidle_driver *drv, int idx);
  25. /*
  26. * NB: Owing to current menu governor behaviour big and LITTLE
  27. * index 1 states have to define exit_latency and target_residency for
  28. * cluster state since, when all CPUs in a cluster hit it, the cluster
  29. * can be shutdown. This means that when a single CPU enters this state
  30. * the exit_latency and target_residency values are somewhat overkill.
  31. * There is no notion of cluster states in the menu governor, so CPUs
  32. * have to define CPU states where possibly the cluster will be shutdown
  33. * depending on the state of other CPUs. idle states entry and exit happen
  34. * at random times; however the cluster state provides target_residency
  35. * values as if all CPUs in a cluster enter the state at once; this is
  36. * somewhat optimistic and behaviour should be fixed either in the governor
  37. * or in the MCPM back-ends.
  38. * To make this driver 100% generic the number of states and the exit_latency
  39. * target_residency values must be obtained from device tree bindings.
  40. *
  41. * exit_latency: refers to the TC2 vexpress test chip and depends on the
  42. * current cluster operating point. It is the time it takes to get the CPU
  43. * up and running when the CPU is powered up on cluster wake-up from shutdown.
  44. * Current values for big and LITTLE clusters are provided for clusters
  45. * running at default operating points.
  46. *
  47. * target_residency: it is the minimum amount of time the cluster has
  48. * to be down to break even in terms of power consumption. cluster
  49. * shutdown has inherent dynamic power costs (L2 writebacks to DRAM
  50. * being the main factor) that depend on the current operating points.
  51. * The current values for both clusters are provided for a CPU whose half
  52. * of L2 lines are dirty and require cleaning to DRAM, and takes into
  53. * account leakage static power values related to the vexpress TC2 testchip.
  54. */
  55. static struct cpuidle_driver bl_idle_little_driver = {
  56. .name = "little_idle",
  57. .owner = THIS_MODULE,
  58. .states[0] = ARM_CPUIDLE_WFI_STATE,
  59. .states[1] = {
  60. .enter = bl_enter_powerdown,
  61. .exit_latency = 700,
  62. .target_residency = 2500,
  63. .flags = CPUIDLE_FLAG_TIMER_STOP,
  64. .name = "C1",
  65. .desc = "ARM little-cluster power down",
  66. },
  67. .state_count = 2,
  68. };
  69. static const struct of_device_id bl_idle_state_match[] __initconst = {
  70. { .compatible = "arm,idle-state",
  71. .data = bl_enter_powerdown },
  72. { },
  73. };
  74. static struct cpuidle_driver bl_idle_big_driver = {
  75. .name = "big_idle",
  76. .owner = THIS_MODULE,
  77. .states[0] = ARM_CPUIDLE_WFI_STATE,
  78. .states[1] = {
  79. .enter = bl_enter_powerdown,
  80. .exit_latency = 500,
  81. .target_residency = 2000,
  82. .flags = CPUIDLE_FLAG_TIMER_STOP,
  83. .name = "C1",
  84. .desc = "ARM big-cluster power down",
  85. },
  86. .state_count = 2,
  87. };
  88. /*
  89. * notrace prevents trace shims from getting inserted where they
  90. * should not. Global jumps and ldrex/strex must not be inserted
  91. * in power down sequences where caches and MMU may be turned off.
  92. */
  93. static int notrace bl_powerdown_finisher(unsigned long arg)
  94. {
  95. /* MCPM works with HW CPU identifiers */
  96. unsigned int mpidr = read_cpuid_mpidr();
  97. unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
  98. unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
  99. mcpm_set_entry_vector(cpu, cluster, cpu_resume);
  100. mcpm_cpu_suspend();
  101. /* return value != 0 means failure */
  102. return 1;
  103. }
  104. /**
  105. * bl_enter_powerdown - Programs CPU to enter the specified state
  106. * @dev: cpuidle device
  107. * @drv: The target state to be programmed
  108. * @idx: state index
  109. *
  110. * Called from the CPUidle framework to program the device to the
  111. * specified target state selected by the governor.
  112. */
  113. static int bl_enter_powerdown(struct cpuidle_device *dev,
  114. struct cpuidle_driver *drv, int idx)
  115. {
  116. cpu_pm_enter();
  117. cpu_suspend(0, bl_powerdown_finisher);
  118. /* signals the MCPM core that CPU is out of low power state */
  119. mcpm_cpu_powered_up();
  120. cpu_pm_exit();
  121. return idx;
  122. }
  123. static int __init bl_idle_driver_init(struct cpuidle_driver *drv, int part_id)
  124. {
  125. struct cpumask *cpumask;
  126. int cpu;
  127. cpumask = kzalloc(cpumask_size(), GFP_KERNEL);
  128. if (!cpumask)
  129. return -ENOMEM;
  130. for_each_possible_cpu(cpu)
  131. if (smp_cpuid_part(cpu) == part_id)
  132. cpumask_set_cpu(cpu, cpumask);
  133. drv->cpumask = cpumask;
  134. return 0;
  135. }
  136. static const struct of_device_id compatible_machine_match[] = {
  137. { .compatible = "arm,vexpress,v2p-ca15_a7" },
  138. { .compatible = "samsung,exynos5420" },
  139. { .compatible = "samsung,exynos5800" },
  140. {},
  141. };
  142. static int __init bl_idle_init(void)
  143. {
  144. int ret;
  145. struct device_node *root = of_find_node_by_path("/");
  146. const struct of_device_id *match_id;
  147. if (!root)
  148. return -ENODEV;
  149. /*
  150. * Initialize the driver just for a compliant set of machines
  151. */
  152. match_id = of_match_node(compatible_machine_match, root);
  153. of_node_put(root);
  154. if (!match_id)
  155. return -ENODEV;
  156. if (!mcpm_is_available())
  157. return -EUNATCH;
  158. /*
  159. * For now the differentiation between little and big cores
  160. * is based on the part number. A7 cores are considered little
  161. * cores, A15 are considered big cores. This distinction may
  162. * evolve in the future with a more generic matching approach.
  163. */
  164. ret = bl_idle_driver_init(&bl_idle_little_driver,
  165. ARM_CPU_PART_CORTEX_A7);
  166. if (ret)
  167. return ret;
  168. ret = bl_idle_driver_init(&bl_idle_big_driver, ARM_CPU_PART_CORTEX_A15);
  169. if (ret)
  170. goto out_uninit_little;
  171. /* Start at index 1, index 0 standard WFI */
  172. ret = dt_init_idle_driver(&bl_idle_big_driver, bl_idle_state_match, 1);
  173. if (ret < 0)
  174. goto out_uninit_big;
  175. /* Start at index 1, index 0 standard WFI */
  176. ret = dt_init_idle_driver(&bl_idle_little_driver,
  177. bl_idle_state_match, 1);
  178. if (ret < 0)
  179. goto out_uninit_big;
  180. ret = cpuidle_register(&bl_idle_little_driver, NULL);
  181. if (ret)
  182. goto out_uninit_big;
  183. ret = cpuidle_register(&bl_idle_big_driver, NULL);
  184. if (ret)
  185. goto out_unregister_little;
  186. return 0;
  187. out_unregister_little:
  188. cpuidle_unregister(&bl_idle_little_driver);
  189. out_uninit_big:
  190. kfree(bl_idle_big_driver.cpumask);
  191. out_uninit_little:
  192. kfree(bl_idle_little_driver.cpumask);
  193. return ret;
  194. }
  195. device_initcall(bl_idle_init);