aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/include/asm/cpuidle.h21
-rw-r--r--arch/arm/kernel/cpuidle.c72
-rw-r--r--arch/arm64/include/asm/cpuidle.h5
-rw-r--r--include/asm-generic/vmlinux.lds.h2
4 files changed, 99 insertions, 1 deletions
diff --git a/arch/arm/include/asm/cpuidle.h b/arch/arm/include/asm/cpuidle.h
index 348dc817b9f3..0f8424924902 100644
--- a/arch/arm/include/asm/cpuidle.h
+++ b/arch/arm/include/asm/cpuidle.h
@@ -27,4 +27,25 @@ static inline int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
27 */ 27 */
28#define ARM_CPUIDLE_WFI_STATE ARM_CPUIDLE_WFI_STATE_PWR(UINT_MAX) 28#define ARM_CPUIDLE_WFI_STATE ARM_CPUIDLE_WFI_STATE_PWR(UINT_MAX)
29 29
30struct device_node;
31
32struct cpuidle_ops {
33 int (*suspend)(int cpu, unsigned long arg);
34 int (*init)(struct device_node *, int cpu);
35};
36
37struct of_cpuidle_method {
38 const char *method;
39 struct cpuidle_ops *ops;
40};
41
42#define CPUIDLE_METHOD_OF_DECLARE(name, _method, _ops) \
43 static const struct of_cpuidle_method __cpuidle_method_of_table_##name \
44 __used __section(__cpuidle_method_of_table) \
45 = { .method = _method, .ops = _ops }
46
47extern int arm_cpuidle_suspend(int index);
48
49extern int arm_cpuidle_init(int cpu);
50
30#endif 51#endif
diff --git a/arch/arm/kernel/cpuidle.c b/arch/arm/kernel/cpuidle.c
index 45969f89f05c..2b0dae3cd058 100644
--- a/arch/arm/kernel/cpuidle.c
+++ b/arch/arm/kernel/cpuidle.c
@@ -10,8 +10,17 @@
10 */ 10 */
11 11
12#include <linux/cpuidle.h> 12#include <linux/cpuidle.h>
13#include <linux/of.h>
14#include <linux/of_device.h>
13#include <asm/cpuidle.h> 15#include <asm/cpuidle.h>
14 16
17extern struct of_cpuidle_method __cpuidle_method_of_table[];
18
19static const struct of_cpuidle_method __cpuidle_method_of_table_sentinel
20 __used __section(__cpuidle_method_of_table_end);
21
22static struct cpuidle_ops cpuidle_ops[NR_CPUS];
23
15int arm_cpuidle_simple_enter(struct cpuidle_device *dev, 24int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
16 struct cpuidle_driver *drv, int index) 25 struct cpuidle_driver *drv, int index)
17{ 26{
@@ -19,3 +28,66 @@ int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
19 28
20 return index; 29 return index;
21} 30}
31
32int arm_cpuidle_suspend(int index)
33{
34 int ret = -EOPNOTSUPP;
35 int cpu = smp_processor_id();
36
37 if (cpuidle_ops[cpu].suspend)
38 ret = cpuidle_ops[cpu].suspend(cpu, index);
39
40 return ret;
41}
42
43static struct cpuidle_ops *__init arm_cpuidle_get_ops(const char *method)
44{
45 struct of_cpuidle_method *m = __cpuidle_method_of_table;
46
47 for (; m->method; m++)
48 if (!strcmp(m->method, method))
49 return m->ops;
50
51 return NULL;
52}
53
54static int __init arm_cpuidle_read_ops(struct device_node *dn, int cpu)
55{
56 const char *enable_method;
57 struct cpuidle_ops *ops;
58
59 enable_method = of_get_property(dn, "enable-method", NULL);
60 if (!enable_method)
61 return -ENOENT;
62
63 ops = arm_cpuidle_get_ops(enable_method);
64 if (!ops) {
65 pr_warn("%s: unsupported enable-method property: %s\n",
66 dn->full_name, enable_method);
67 return -EOPNOTSUPP;
68 }
69
70 cpuidle_ops[cpu] = *ops; /* structure copy */
71
72 pr_notice("cpuidle: enable-method property '%s'"
73 " found operations\n", enable_method);
74
75 return 0;
76}
77
78int __init arm_cpuidle_init(int cpu)
79{
80 struct device_node *cpu_node = of_cpu_device_node_get(cpu);
81 int ret;
82
83 if (!cpu_node)
84 return -ENODEV;
85
86 ret = arm_cpuidle_read_ops(cpu_node, cpu);
87 if (!ret && cpuidle_ops[cpu].init)
88 ret = cpuidle_ops[cpu].init(cpu_node, cpu);
89
90 of_node_put(cpu_node);
91
92 return ret;
93}
diff --git a/arch/arm64/include/asm/cpuidle.h b/arch/arm64/include/asm/cpuidle.h
index c60643f14cda..460a38bb84b9 100644
--- a/arch/arm64/include/asm/cpuidle.h
+++ b/arch/arm64/include/asm/cpuidle.h
@@ -17,5 +17,8 @@ static inline int cpu_suspend(unsigned long arg)
17 return -EOPNOTSUPP; 17 return -EOPNOTSUPP;
18} 18}
19#endif 19#endif
20 20static inline int arm_cpuidle_suspend(int index)
21{
22 return cpu_suspend(index);
23}
21#endif 24#endif
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index ac78910d7416..91c09305106d 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -167,6 +167,7 @@
167#define IOMMU_OF_TABLES() OF_TABLE(CONFIG_OF_IOMMU, iommu) 167#define IOMMU_OF_TABLES() OF_TABLE(CONFIG_OF_IOMMU, iommu)
168#define RESERVEDMEM_OF_TABLES() OF_TABLE(CONFIG_OF_RESERVED_MEM, reservedmem) 168#define RESERVEDMEM_OF_TABLES() OF_TABLE(CONFIG_OF_RESERVED_MEM, reservedmem)
169#define CPU_METHOD_OF_TABLES() OF_TABLE(CONFIG_SMP, cpu_method) 169#define CPU_METHOD_OF_TABLES() OF_TABLE(CONFIG_SMP, cpu_method)
170#define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method)
170#define EARLYCON_OF_TABLES() OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon) 171#define EARLYCON_OF_TABLES() OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
171 172
172#define KERNEL_DTB() \ 173#define KERNEL_DTB() \
@@ -501,6 +502,7 @@
501 CLKSRC_OF_TABLES() \ 502 CLKSRC_OF_TABLES() \
502 IOMMU_OF_TABLES() \ 503 IOMMU_OF_TABLES() \
503 CPU_METHOD_OF_TABLES() \ 504 CPU_METHOD_OF_TABLES() \
505 CPUIDLE_METHOD_OF_TABLES() \
504 KERNEL_DTB() \ 506 KERNEL_DTB() \
505 IRQCHIP_OF_MATCH_TABLE() \ 507 IRQCHIP_OF_MATCH_TABLE() \
506 EARLYCON_OF_TABLES() 508 EARLYCON_OF_TABLES()