aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/kernel/devtree.c5
-rw-r--r--arch/arm/kernel/topology.c61
-rw-r--r--arch/arm/mach-davinci/cpuidle.c2
-rw-r--r--arch/arm/mach-imx/mach-imx6q.c3
-rw-r--r--arch/arm/mach-mvebu/platsmp.c51
-rw-r--r--arch/arm/mach-ux500/Makefile1
-rw-r--r--arch/arm/mach-ux500/cpuidle.c128
7 files changed, 49 insertions, 202 deletions
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
index 5859c8bc727c..2ee8a17d2b01 100644
--- a/arch/arm/kernel/devtree.c
+++ b/arch/arm/kernel/devtree.c
@@ -169,6 +169,11 @@ void __init arm_dt_init_cpu_maps(void)
169 } 169 }
170} 170}
171 171
172bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
173{
174 return (phys_id & MPIDR_HWID_BITMASK) == cpu_logical_map(cpu);
175}
176
172/** 177/**
173 * setup_machine_fdt - Machine setup when an dtb was passed to the kernel 178 * setup_machine_fdt - Machine setup when an dtb was passed to the kernel
174 * @dt_phys: physical address of dt blob 179 * @dt_phys: physical address of dt blob
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index c5a59546a256..85a87370f144 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -74,12 +74,8 @@ struct cpu_efficiency table_efficiency[] = {
74 {NULL, }, 74 {NULL, },
75}; 75};
76 76
77struct cpu_capacity { 77unsigned long *__cpu_capacity;
78 unsigned long hwid; 78#define cpu_capacity(cpu) __cpu_capacity[cpu]
79 unsigned long capacity;
80};
81
82struct cpu_capacity *cpu_capacity;
83 79
84unsigned long middle_capacity = 1; 80unsigned long middle_capacity = 1;
85 81
@@ -100,15 +96,19 @@ static void __init parse_dt_topology(void)
100 unsigned long capacity = 0; 96 unsigned long capacity = 0;
101 int alloc_size, cpu = 0; 97 int alloc_size, cpu = 0;
102 98
103 alloc_size = nr_cpu_ids * sizeof(struct cpu_capacity); 99 alloc_size = nr_cpu_ids * sizeof(*__cpu_capacity);
104 cpu_capacity = kzalloc(alloc_size, GFP_NOWAIT); 100 __cpu_capacity = kzalloc(alloc_size, GFP_NOWAIT);
105 101
106 while ((cn = of_find_node_by_type(cn, "cpu"))) { 102 for_each_possible_cpu(cpu) {
107 const u32 *rate, *reg; 103 const u32 *rate;
108 int len; 104 int len;
109 105
110 if (cpu >= num_possible_cpus()) 106 /* too early to use cpu->of_node */
111 break; 107 cn = of_get_cpu_node(cpu, NULL);
108 if (!cn) {
109 pr_err("missing device node for CPU %d\n", cpu);
110 continue;
111 }
112 112
113 for (cpu_eff = table_efficiency; cpu_eff->compatible; cpu_eff++) 113 for (cpu_eff = table_efficiency; cpu_eff->compatible; cpu_eff++)
114 if (of_device_is_compatible(cn, cpu_eff->compatible)) 114 if (of_device_is_compatible(cn, cpu_eff->compatible))
@@ -124,12 +124,6 @@ static void __init parse_dt_topology(void)
124 continue; 124 continue;
125 } 125 }
126 126
127 reg = of_get_property(cn, "reg", &len);
128 if (!reg || len != 4) {
129 pr_err("%s missing reg property\n", cn->full_name);
130 continue;
131 }
132
133 capacity = ((be32_to_cpup(rate)) >> 20) * cpu_eff->efficiency; 127 capacity = ((be32_to_cpup(rate)) >> 20) * cpu_eff->efficiency;
134 128
135 /* Save min capacity of the system */ 129 /* Save min capacity of the system */
@@ -140,13 +134,9 @@ static void __init parse_dt_topology(void)
140 if (capacity > max_capacity) 134 if (capacity > max_capacity)
141 max_capacity = capacity; 135 max_capacity = capacity;
142 136
143 cpu_capacity[cpu].capacity = capacity; 137 cpu_capacity(cpu) = capacity;
144 cpu_capacity[cpu++].hwid = be32_to_cpup(reg);
145 } 138 }
146 139
147 if (cpu < num_possible_cpus())
148 cpu_capacity[cpu].hwid = (unsigned long)(-1);
149
150 /* If min and max capacities are equals, we bypass the update of the 140 /* If min and max capacities are equals, we bypass the update of the
151 * cpu_scale because all CPUs have the same capacity. Otherwise, we 141 * cpu_scale because all CPUs have the same capacity. Otherwise, we
152 * compute a middle_capacity factor that will ensure that the capacity 142 * compute a middle_capacity factor that will ensure that the capacity
@@ -154,9 +144,7 @@ static void __init parse_dt_topology(void)
154 * SCHED_POWER_SCALE, which is the default value, but with the 144 * SCHED_POWER_SCALE, which is the default value, but with the
155 * constraint explained near table_efficiency[]. 145 * constraint explained near table_efficiency[].
156 */ 146 */
157 if (min_capacity == max_capacity) 147 if (4*max_capacity < (3*(max_capacity + min_capacity)))
158 cpu_capacity[0].hwid = (unsigned long)(-1);
159 else if (4*max_capacity < (3*(max_capacity + min_capacity)))
160 middle_capacity = (min_capacity + max_capacity) 148 middle_capacity = (min_capacity + max_capacity)
161 >> (SCHED_POWER_SHIFT+1); 149 >> (SCHED_POWER_SHIFT+1);
162 else 150 else
@@ -170,23 +158,12 @@ static void __init parse_dt_topology(void)
170 * boot. The update of all CPUs is in O(n^2) for heteregeneous system but the 158 * boot. The update of all CPUs is in O(n^2) for heteregeneous system but the
171 * function returns directly for SMP system. 159 * function returns directly for SMP system.
172 */ 160 */
173void update_cpu_power(unsigned int cpu, unsigned long hwid) 161void update_cpu_power(unsigned int cpu)
174{ 162{
175 unsigned int idx = 0; 163 if (!cpu_capacity(cpu))
176
177 /* look for the cpu's hwid in the cpu capacity table */
178 for (idx = 0; idx < num_possible_cpus(); idx++) {
179 if (cpu_capacity[idx].hwid == hwid)
180 break;
181
182 if (cpu_capacity[idx].hwid == -1)
183 return;
184 }
185
186 if (idx == num_possible_cpus())
187 return; 164 return;
188 165
189 set_power_scale(cpu, cpu_capacity[idx].capacity / middle_capacity); 166 set_power_scale(cpu, cpu_capacity(cpu) / middle_capacity);
190 167
191 printk(KERN_INFO "CPU%u: update cpu_power %lu\n", 168 printk(KERN_INFO "CPU%u: update cpu_power %lu\n",
192 cpu, arch_scale_freq_power(NULL, cpu)); 169 cpu, arch_scale_freq_power(NULL, cpu));
@@ -194,7 +171,7 @@ void update_cpu_power(unsigned int cpu, unsigned long hwid)
194 171
195#else 172#else
196static inline void parse_dt_topology(void) {} 173static inline void parse_dt_topology(void) {}
197static inline void update_cpu_power(unsigned int cpuid, unsigned int mpidr) {} 174static inline void update_cpu_power(unsigned int cpuid) {}
198#endif 175#endif
199 176
200 /* 177 /*
@@ -281,7 +258,7 @@ void store_cpu_topology(unsigned int cpuid)
281 258
282 update_siblings_masks(cpuid); 259 update_siblings_masks(cpuid);
283 260
284 update_cpu_power(cpuid, mpidr & MPIDR_HWID_BITMASK); 261 update_cpu_power(cpuid);
285 262
286 printk(KERN_INFO "CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n", 263 printk(KERN_INFO "CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n",
287 cpuid, cpu_topology[cpuid].thread_id, 264 cpuid, cpu_topology[cpuid].thread_id,
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index 36aef3a7dedb..f1ac1c94ac0f 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -65,7 +65,7 @@ static struct cpuidle_driver davinci_idle_driver = {
65 .states[1] = { 65 .states[1] = {
66 .enter = davinci_enter_idle, 66 .enter = davinci_enter_idle,
67 .exit_latency = 10, 67 .exit_latency = 10,
68 .target_residency = 100000, 68 .target_residency = 10000,
69 .flags = CPUIDLE_FLAG_TIME_VALID, 69 .flags = CPUIDLE_FLAG_TIME_VALID,
70 .name = "DDR SR", 70 .name = "DDR SR",
71 .desc = "WFI and DDR Self Refresh", 71 .desc = "WFI and DDR Self Refresh",
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 7be13f8e69a0..a02f275a198d 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -254,13 +254,12 @@ static void __init imx6q_opp_init(struct device *cpu_dev)
254{ 254{
255 struct device_node *np; 255 struct device_node *np;
256 256
257 np = of_find_node_by_path("/cpus/cpu@0"); 257 np = of_node_get(cpu_dev->of_node);
258 if (!np) { 258 if (!np) {
259 pr_warn("failed to find cpu0 node\n"); 259 pr_warn("failed to find cpu0 node\n");
260 return; 260 return;
261 } 261 }
262 262
263 cpu_dev->of_node = np;
264 if (of_init_opp_table(cpu_dev)) { 263 if (of_init_opp_table(cpu_dev)) {
265 pr_warn("failed to init OPP table\n"); 264 pr_warn("failed to init OPP table\n");
266 goto put_node; 265 goto put_node;
diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c
index ce81d3031405..594b63db4215 100644
--- a/arch/arm/mach-mvebu/platsmp.c
+++ b/arch/arm/mach-mvebu/platsmp.c
@@ -29,45 +29,40 @@
29#include "pmsu.h" 29#include "pmsu.h"
30#include "coherency.h" 30#include "coherency.h"
31 31
32static struct clk *__init get_cpu_clk(int cpu)
33{
34 struct clk *cpu_clk;
35 struct device_node *np = of_get_cpu_node(cpu, NULL);
36
37 if (WARN(!np, "missing cpu node\n"))
38 return NULL;
39 cpu_clk = of_clk_get(np, 0);
40 if (WARN_ON(IS_ERR(cpu_clk)))
41 return NULL;
42 return cpu_clk;
43}
44
32void __init set_secondary_cpus_clock(void) 45void __init set_secondary_cpus_clock(void)
33{ 46{
34 int thiscpu; 47 int thiscpu, cpu;
35 unsigned long rate; 48 unsigned long rate;
36 struct clk *cpu_clk = NULL; 49 struct clk *cpu_clk;
37 struct device_node *np = NULL;
38 50
39 thiscpu = smp_processor_id(); 51 thiscpu = smp_processor_id();
40 for_each_node_by_type(np, "cpu") { 52 cpu_clk = get_cpu_clk(thiscpu);
41 int err; 53 if (!cpu_clk)
42 int cpu;
43
44 err = of_property_read_u32(np, "reg", &cpu);
45 if (WARN_ON(err))
46 return;
47
48 if (cpu == thiscpu) {
49 cpu_clk = of_clk_get(np, 0);
50 break;
51 }
52 }
53 if (WARN_ON(IS_ERR(cpu_clk)))
54 return; 54 return;
55 clk_prepare_enable(cpu_clk); 55 clk_prepare_enable(cpu_clk);
56 rate = clk_get_rate(cpu_clk); 56 rate = clk_get_rate(cpu_clk);
57 57
58 /* set all the other CPU clk to the same rate than the boot CPU */ 58 /* set all the other CPU clk to the same rate than the boot CPU */
59 for_each_node_by_type(np, "cpu") { 59 for_each_possible_cpu(cpu) {
60 int err; 60 if (cpu == thiscpu)
61 int cpu; 61 continue;
62 62 cpu_clk = get_cpu_clk(cpu);
63 err = of_property_read_u32(np, "reg", &cpu); 63 if (!cpu_clk)
64 if (WARN_ON(err))
65 return; 64 return;
66 65 clk_set_rate(cpu_clk, rate);
67 if (cpu != thiscpu) {
68 cpu_clk = of_clk_get(np, 0);
69 clk_set_rate(cpu_clk, rate);
70 }
71 } 66 }
72} 67}
73 68
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
index bf9b6be5b180..fe1f3e26b88b 100644
--- a/arch/arm/mach-ux500/Makefile
+++ b/arch/arm/mach-ux500/Makefile
@@ -4,7 +4,6 @@
4 4
5obj-y := cpu.o devices.o devices-common.o \ 5obj-y := cpu.o devices.o devices-common.o \
6 id.o usb.o timer.o pm.o 6 id.o usb.o timer.o pm.o
7obj-$(CONFIG_CPU_IDLE) += cpuidle.o
8obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o 7obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
9obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o 8obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o
10obj-$(CONFIG_MACH_MOP500) += board-mop500.o board-mop500-sdi.o \ 9obj-$(CONFIG_MACH_MOP500) += board-mop500.o board-mop500-sdi.o \
diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c
deleted file mode 100644
index a45dd09daed9..000000000000
--- a/arch/arm/mach-ux500/cpuidle.c
+++ /dev/null
@@ -1,128 +0,0 @@
1/*
2 * Copyright (c) 2012 Linaro : Daniel Lezcano <daniel.lezcano@linaro.org> (IBM)
3 *
4 * Based on the work of Rickard Andersson <rickard.andersson@stericsson.com>
5 * and Jonas Aaberg <jonas.aberg@stericsson.com>.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/module.h>
13#include <linux/cpuidle.h>
14#include <linux/spinlock.h>
15#include <linux/atomic.h>
16#include <linux/smp.h>
17#include <linux/mfd/dbx500-prcmu.h>
18#include <linux/platform_data/arm-ux500-pm.h>
19
20#include <asm/cpuidle.h>
21#include <asm/proc-fns.h>
22
23#include "db8500-regs.h"
24#include "id.h"
25
26static atomic_t master = ATOMIC_INIT(0);
27static DEFINE_SPINLOCK(master_lock);
28
29static inline int ux500_enter_idle(struct cpuidle_device *dev,
30 struct cpuidle_driver *drv, int index)
31{
32 int this_cpu = smp_processor_id();
33 bool recouple = false;
34
35 if (atomic_inc_return(&master) == num_online_cpus()) {
36
37 /* With this lock, we prevent the other cpu to exit and enter
38 * this function again and become the master */
39 if (!spin_trylock(&master_lock))
40 goto wfi;
41
42 /* decouple the gic from the A9 cores */
43 if (prcmu_gic_decouple()) {
44 spin_unlock(&master_lock);
45 goto out;
46 }
47
48 /* If an error occur, we will have to recouple the gic
49 * manually */
50 recouple = true;
51
52 /* At this state, as the gic is decoupled, if the other
53 * cpu is in WFI, we have the guarantee it won't be wake
54 * up, so we can safely go to retention */
55 if (!prcmu_is_cpu_in_wfi(this_cpu ? 0 : 1))
56 goto out;
57
58 /* The prcmu will be in charge of watching the interrupts
59 * and wake up the cpus */
60 if (prcmu_copy_gic_settings())
61 goto out;
62
63 /* Check in the meantime an interrupt did
64 * not occur on the gic ... */
65 if (prcmu_gic_pending_irq())
66 goto out;
67
68 /* ... and the prcmu */
69 if (prcmu_pending_irq())
70 goto out;
71
72 /* Go to the retention state, the prcmu will wait for the
73 * cpu to go WFI and this is what happens after exiting this
74 * 'master' critical section */
75 if (prcmu_set_power_state(PRCMU_AP_IDLE, true, true))
76 goto out;
77
78 /* When we switch to retention, the prcmu is in charge
79 * of recoupling the gic automatically */
80 recouple = false;
81
82 spin_unlock(&master_lock);
83 }
84wfi:
85 cpu_do_idle();
86out:
87 atomic_dec(&master);
88
89 if (recouple) {
90 prcmu_gic_recouple();
91 spin_unlock(&master_lock);
92 }
93
94 return index;
95}
96
97static struct cpuidle_driver ux500_idle_driver = {
98 .name = "ux500_idle",
99 .owner = THIS_MODULE,
100 .states = {
101 ARM_CPUIDLE_WFI_STATE,
102 {
103 .enter = ux500_enter_idle,
104 .exit_latency = 70,
105 .target_residency = 260,
106 .flags = CPUIDLE_FLAG_TIME_VALID |
107 CPUIDLE_FLAG_TIMER_STOP,
108 .name = "ApIdle",
109 .desc = "ARM Retention",
110 },
111 },
112 .safe_state_index = 0,
113 .state_count = 2,
114};
115
116int __init ux500_idle_init(void)
117{
118 if (!(cpu_is_u8500_family() || cpu_is_ux540_family()))
119 return -ENODEV;
120
121 /* Configure wake up reasons */
122 prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) |
123 PRCMU_WAKEUP(ABB));
124
125 return cpuidle_register(&ux500_idle_driver, NULL);
126}
127
128device_initcall(ux500_idle_init);