Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: smp_twd: add device tree support

Add bindings to support DT discovery of the ARM Timer Watchdog
(aka TWD). Only the timer side is converted by this patch.

Acked-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

+120 -13
+48
Documentation/devicetree/bindings/arm/twd.txt
··· 1 + * ARM Timer Watchdog 2 + 3 + ARM 11MP, Cortex-A5 and Cortex-A9 are often associated with a per-core 4 + Timer-Watchdog (aka TWD), which provides both a per-cpu local timer 5 + and watchdog. 6 + 7 + The TWD is usually attached to a GIC to deliver its two per-processor 8 + interrupts. 9 + 10 + ** Timer node required properties: 11 + 12 + - compatible : Should be one of: 13 + "arm,cortex-a9-twd-timer" 14 + "arm,cortex-a5-twd-timer" 15 + "arm,arm11mp-twd-timer" 16 + 17 + - interrupts : One interrupt to each core 18 + 19 + - reg : Specify the base address and the size of the TWD timer 20 + register window. 21 + 22 + Example: 23 + 24 + twd-timer@2c000600 { 25 + compatible = "arm,arm11mp-twd-timer""; 26 + reg = <0x2c000600 0x20>; 27 + interrupts = <1 13 0xf01>; 28 + }; 29 + 30 + ** Watchdog node properties: 31 + 32 + - compatible : Should be one of: 33 + "arm,cortex-a9-twd-wdt" 34 + "arm,cortex-a5-twd-wdt" 35 + "arm,arm11mp-twd-wdt" 36 + 37 + - interrupts : One interrupt to each core 38 + 39 + - reg : Specify the base address and the size of the TWD watchdog 40 + register window. 41 + 42 + Example: 43 + 44 + twd-watchdog@2c000620 { 45 + compatible = "arm,arm11mp-twd-wdt"; 46 + reg = <0x2c000620 0x20>; 47 + interrupts = <1 14 0xf01>; 48 + };
+8
arch/arm/include/asm/smp_twd.h
··· 40 40 41 41 int twd_local_timer_register(struct twd_local_timer *); 42 42 43 + #ifdef CONFIG_HAVE_ARM_TWD 44 + void twd_local_timer_of_register(void); 45 + #else 46 + static inline void twd_local_timer_of_register(void) 47 + { 48 + } 49 + #endif 50 + 43 51 #endif
+64 -13
arch/arm/kernel/smp_twd.c
··· 20 20 #include <linux/clockchips.h> 21 21 #include <linux/irq.h> 22 22 #include <linux/io.h> 23 + #include <linux/of_irq.h> 24 + #include <linux/of_address.h> 23 25 24 26 #include <asm/smp_twd.h> 25 27 #include <asm/localtimer.h> ··· 286 284 .stop = twd_timer_stop, 287 285 }; 288 286 289 - int __init twd_local_timer_register(struct twd_local_timer *tlt) 287 + static int __init twd_local_timer_common_register(void) 290 288 { 291 289 int err; 292 290 293 - if (twd_base || twd_evt) 294 - return -EBUSY; 295 - 296 - twd_ppi = tlt->res[1].start; 297 - 298 291 twd_evt = alloc_percpu(struct clock_event_device *); 299 - twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0])); 300 - if (!twd_base || !twd_evt) { 292 + if (!twd_evt) { 301 293 err = -ENOMEM; 302 - goto out; 294 + goto out_free; 303 295 } 304 296 305 297 err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_evt); 306 298 if (err) { 307 299 pr_err("twd: can't register interrupt %d (%d)\n", twd_ppi, err); 308 - goto out; 300 + goto out_free; 309 301 } 310 302 311 303 err = local_timer_register(&twd_lt_ops); 312 304 if (err) 313 - goto out; 305 + goto out_irq; 314 306 315 307 return 0; 316 308 317 - out: 309 + out_irq: 310 + free_percpu_irq(twd_ppi, twd_evt); 311 + out_free: 318 312 iounmap(twd_base); 313 + twd_base = NULL; 319 314 free_percpu(twd_evt); 320 - twd_base = twd_evt = NULL; 315 + 321 316 return err; 322 317 } 318 + 319 + int __init twd_local_timer_register(struct twd_local_timer *tlt) 320 + { 321 + if (twd_base || twd_evt) 322 + return -EBUSY; 323 + 324 + twd_ppi = tlt->res[1].start; 325 + 326 + twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0])); 327 + if (!twd_base) 328 + return -ENOMEM; 329 + 330 + return twd_local_timer_common_register(); 331 + } 332 + 333 + #ifdef CONFIG_OF 334 + const static struct of_device_id twd_of_match[] __initconst = { 335 + { .compatible = "arm,cortex-a9-twd-timer", }, 336 + { .compatible = "arm,cortex-a5-twd-timer", }, 337 + { .compatible = "arm,arm11mp-twd-timer", }, 338 + { }, 339 + }; 340 + 341 + void __init twd_local_timer_of_register(void) 342 + { 343 + struct device_node *np; 344 + int err; 345 + 346 + np = of_find_matching_node(NULL, twd_of_match); 347 + if (!np) { 348 + err = -ENODEV; 349 + goto out; 350 + } 351 + 352 + twd_ppi = irq_of_parse_and_map(np, 0); 353 + if (!twd_ppi) { 354 + err = -EINVAL; 355 + goto out; 356 + } 357 + 358 + twd_base = of_iomap(np, 0); 359 + if (!twd_base) { 360 + err = -ENOMEM; 361 + goto out; 362 + } 363 + 364 + err = twd_local_timer_common_register(); 365 + 366 + out: 367 + WARN(err, "twd_local_timer_of_register failed (%d)\n", err); 368 + } 369 + #endif