aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@codeaurora.org>2013-03-14 23:31:38 -0400
committerDavid Brown <davidb@codeaurora.org>2013-03-22 13:46:16 -0400
commiteebdb0c1e1d63532399f7cbb65ade5969d63df06 (patch)
tree0fb67b3ab00115d0e0078f51c721c60f7d4ef9be /arch/arm
parentf6161aa153581da4a3867a2d1a7caf4be19b6ec9 (diff)
ARM: msm: Rework timer binding to be more general
The msm timer binding I wrote is bad. First off, the clock frequency in the binding for the dgt is wrong. Software divides down the input rate by 4 to achieve the rate listed in the binding. We also treat each individual timer as a separate hardware component, when in reality there is one timer block (that may be duplicated per cpu) with multiple timers within it. Depending on the version of the hardware there can be one or two general purpose timers, status and divider control registers, and an entirely different register layout. In the next patch we'll need to know about the different register layouts so that we can properly check the status register after clearing the count. The current binding makes this complicated because the general purpose timer's reg property doesn't indicate where that status register is, and in fact it is beyond the size of the reg property. Clean all this up by just having one node for the timer hardware, and describe all the interrupts and clock frequencies supported while having one reg property that covers the entire timer register region. We'll use the compatible field in the future to determine different register layouts and if we should read the status registers, etc. Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> Signed-off-by: David Brown <davidb@codeaurora.org>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/boot/dts/msm8660-surf.dts20
-rw-r--r--arch/arm/boot/dts/msm8960-cdp.dts22
-rw-r--r--arch/arm/mach-msm/timer.c79
3 files changed, 48 insertions, 73 deletions
diff --git a/arch/arm/boot/dts/msm8660-surf.dts b/arch/arm/boot/dts/msm8660-surf.dts
index 31f2157cd7d7..743ef42df23e 100644
--- a/arch/arm/boot/dts/msm8660-surf.dts
+++ b/arch/arm/boot/dts/msm8660-surf.dts
@@ -16,19 +16,13 @@
16 }; 16 };
17 17
18 timer@2000004 { 18 timer@2000004 {
19 compatible = "qcom,msm-gpt", "qcom,msm-timer"; 19 compatible = "qcom,scss-timer", "qcom,msm-timer";
20 interrupts = <1 1 0x301>; 20 interrupts = <1 0 0x301>,
21 reg = <0x02000004 0x10>; 21 <1 1 0x301>,
22 clock-frequency = <32768>; 22 <1 2 0x301>;
23 cpu-offset = <0x40000>; 23 reg = <0x02000000 0x100>;
24 }; 24 clock-frequency = <27000000>,
25 25 <32768>;
26 timer@2000024 {
27 compatible = "qcom,msm-dgt", "qcom,msm-timer";
28 interrupts = <1 0 0x301>;
29 reg = <0x02000024 0x10>,
30 <0x02000034 0x4>;
31 clock-frequency = <6750000>;
32 cpu-offset = <0x40000>; 26 cpu-offset = <0x40000>;
33 }; 27 };
34 28
diff --git a/arch/arm/boot/dts/msm8960-cdp.dts b/arch/arm/boot/dts/msm8960-cdp.dts
index 9e621b5ad3dd..3ae51fb02e17 100644
--- a/arch/arm/boot/dts/msm8960-cdp.dts
+++ b/arch/arm/boot/dts/msm8960-cdp.dts
@@ -15,20 +15,14 @@
15 < 0x02002000 0x1000 >; 15 < 0x02002000 0x1000 >;
16 }; 16 };
17 17
18 timer@200a004 { 18 timer@200a000 {
19 compatible = "qcom,msm-gpt", "qcom,msm-timer"; 19 compatible = "qcom,kpss-timer", "qcom,msm-timer";
20 interrupts = <1 2 0x301>; 20 interrupts = <1 1 0x301>,
21 reg = <0x0200a004 0x10>; 21 <1 2 0x301>,
22 clock-frequency = <32768>; 22 <1 3 0x301>;
23 cpu-offset = <0x80000>; 23 reg = <0x0200a000 0x100>;
24 }; 24 clock-frequency = <27000000>,
25 25 <32768>;
26 timer@200a024 {
27 compatible = "qcom,msm-dgt", "qcom,msm-timer";
28 interrupts = <1 1 0x301>;
29 reg = <0x0200a024 0x10>,
30 <0x0200a034 0x4>;
31 clock-frequency = <6750000>;
32 cpu-offset = <0x80000>; 26 cpu-offset = <0x80000>;
33 }; 27 };
34 28
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 2969027f02fa..165e33b9b1ee 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -36,6 +36,7 @@
36#define TIMER_ENABLE_CLR_ON_MATCH_EN BIT(1) 36#define TIMER_ENABLE_CLR_ON_MATCH_EN BIT(1)
37#define TIMER_ENABLE_EN BIT(0) 37#define TIMER_ENABLE_EN BIT(0)
38#define TIMER_CLEAR 0x000C 38#define TIMER_CLEAR 0x000C
39#define DGT_CLK_CTL 0x10
39#define DGT_CLK_CTL_DIV_4 0x3 40#define DGT_CLK_CTL_DIV_4 0x3
40 41
41#define GPT_HZ 32768 42#define GPT_HZ 32768
@@ -214,13 +215,9 @@ err:
214} 215}
215 216
216#ifdef CONFIG_OF 217#ifdef CONFIG_OF
217static const struct of_device_id msm_dgt_match[] __initconst = { 218static const struct of_device_id msm_timer_match[] __initconst = {
218 { .compatible = "qcom,msm-dgt" }, 219 { .compatible = "qcom,kpss-timer" },
219 { }, 220 { .compatible = "qcom,scss-timer" },
220};
221
222static const struct of_device_id msm_gpt_match[] __initconst = {
223 { .compatible = "qcom,msm-gpt" },
224 { }, 221 { },
225}; 222};
226 223
@@ -231,33 +228,29 @@ void __init msm_dt_timer_init(void)
231 int irq; 228 int irq;
232 struct resource res; 229 struct resource res;
233 u32 percpu_offset; 230 u32 percpu_offset;
234 void __iomem *dgt_clk_ctl; 231 void __iomem *base;
232 void __iomem *cpu0_base;
235 233
236 np = of_find_matching_node(NULL, msm_gpt_match); 234 np = of_find_matching_node(NULL, msm_timer_match);
237 if (!np) { 235 if (!np) {
238 pr_err("Can't find GPT DT node\n"); 236 pr_err("Can't find msm timer DT node\n");
239 return; 237 return;
240 } 238 }
241 239
242 event_base = of_iomap(np, 0); 240 base = of_iomap(np, 0);
243 if (!event_base) { 241 if (!base) {
244 pr_err("Failed to map event base\n"); 242 pr_err("Failed to map event base\n");
245 return; 243 return;
246 } 244 }
247 245
248 irq = irq_of_parse_and_map(np, 0); 246 /* We use GPT0 for the clockevent */
247 irq = irq_of_parse_and_map(np, 1);
249 if (irq <= 0) { 248 if (irq <= 0) {
250 pr_err("Can't get irq\n"); 249 pr_err("Can't get irq\n");
251 return; 250 return;
252 } 251 }
253 of_node_put(np);
254
255 np = of_find_matching_node(NULL, msm_dgt_match);
256 if (!np) {
257 pr_err("Can't find DGT DT node\n");
258 return;
259 }
260 252
253 /* We use CPU0's DGT for the clocksource */
261 if (of_property_read_u32(np, "cpu-offset", &percpu_offset)) 254 if (of_property_read_u32(np, "cpu-offset", &percpu_offset))
262 percpu_offset = 0; 255 percpu_offset = 0;
263 256
@@ -266,45 +259,39 @@ void __init msm_dt_timer_init(void)
266 return; 259 return;
267 } 260 }
268 261
269 source_base = ioremap(res.start + percpu_offset, resource_size(&res)); 262 cpu0_base = ioremap(res.start + percpu_offset, resource_size(&res));
270 if (!source_base) { 263 if (!cpu0_base) {
271 pr_err("Failed to map source base\n"); 264 pr_err("Failed to map source base\n");
272 return; 265 return;
273 } 266 }
274 267
275 if (!of_address_to_resource(np, 1, &res)) {
276 dgt_clk_ctl = ioremap(res.start + percpu_offset,
277 resource_size(&res));
278 if (!dgt_clk_ctl) {
279 pr_err("Failed to map DGT control base\n");
280 return;
281 }
282 writel_relaxed(DGT_CLK_CTL_DIV_4, dgt_clk_ctl);
283 iounmap(dgt_clk_ctl);
284 }
285
286 if (of_property_read_u32(np, "clock-frequency", &freq)) { 268 if (of_property_read_u32(np, "clock-frequency", &freq)) {
287 pr_err("Unknown frequency\n"); 269 pr_err("Unknown frequency\n");
288 return; 270 return;
289 } 271 }
290 of_node_put(np); 272 of_node_put(np);
291 273
274 event_base = base + 0x4;
275 source_base = cpu0_base + 0x24;
276 freq /= 4;
277 writel_relaxed(DGT_CLK_CTL_DIV_4, source_base + DGT_CLK_CTL);
278
292 msm_timer_init(freq, 32, irq, !!percpu_offset); 279 msm_timer_init(freq, 32, irq, !!percpu_offset);
293} 280}
294#endif 281#endif
295 282
296static int __init msm_timer_map(phys_addr_t event, phys_addr_t source) 283static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source)
297{ 284{
298 event_base = ioremap(event, SZ_64); 285 void __iomem *base;
299 if (!event_base) { 286
300 pr_err("Failed to map event base\n"); 287 base = ioremap(addr, SZ_256);
301 return 1; 288 if (!base) {
302 } 289 pr_err("Failed to map timer base\n");
303 source_base = ioremap(source, SZ_64); 290 return -ENOMEM;
304 if (!source_base) {
305 pr_err("Failed to map source base\n");
306 return 1;
307 } 291 }
292 event_base = base + event;
293 source_base = base + source;
294
308 return 0; 295 return 0;
309} 296}
310 297
@@ -312,7 +299,7 @@ void __init msm7x01_timer_init(void)
312{ 299{
313 struct clocksource *cs = &msm_clocksource; 300 struct clocksource *cs = &msm_clocksource;
314 301
315 if (msm_timer_map(0xc0100000, 0xc0100010)) 302 if (msm_timer_map(0xc0100000, 0x0, 0x10))
316 return; 303 return;
317 cs->read = msm_read_timer_count_shift; 304 cs->read = msm_read_timer_count_shift;
318 cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)); 305 cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT));
@@ -323,14 +310,14 @@ void __init msm7x01_timer_init(void)
323 310
324void __init msm7x30_timer_init(void) 311void __init msm7x30_timer_init(void)
325{ 312{
326 if (msm_timer_map(0xc0100004, 0xc0100024)) 313 if (msm_timer_map(0xc0100000, 0x4, 0x24))
327 return; 314 return;
328 msm_timer_init(24576000 / 4, 32, 1, false); 315 msm_timer_init(24576000 / 4, 32, 1, false);
329} 316}
330 317
331void __init qsd8x50_timer_init(void) 318void __init qsd8x50_timer_init(void)
332{ 319{
333 if (msm_timer_map(0xAC100000, 0xAC100010)) 320 if (msm_timer_map(0xAC100000, 0x0, 0x10))
334 return; 321 return;
335 msm_timer_init(19200000 / 4, 32, 7, false); 322 msm_timer_init(19200000 / 4, 32, 7, false);
336} 323}