Skip to content

Commit

Permalink
ARM: smp_twd: add device tree support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Marc Zyngier committed Mar 13, 2012
1 parent 81e46f7 commit d8e0364
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 13 deletions.
48 changes: 48 additions & 0 deletions Documentation/devicetree/bindings/arm/twd.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
* ARM Timer Watchdog

ARM 11MP, Cortex-A5 and Cortex-A9 are often associated with a per-core
Timer-Watchdog (aka TWD), which provides both a per-cpu local timer
and watchdog.

The TWD is usually attached to a GIC to deliver its two per-processor
interrupts.

** Timer node required properties:

- compatible : Should be one of:
"arm,cortex-a9-twd-timer"
"arm,cortex-a5-twd-timer"
"arm,arm11mp-twd-timer"

- interrupts : One interrupt to each core

- reg : Specify the base address and the size of the TWD timer
register window.

Example:

twd-timer@2c000600 {
compatible = "arm,arm11mp-twd-timer"";
reg = <0x2c000600 0x20>;
interrupts = <1 13 0xf01>;
};

** Watchdog node properties:

- compatible : Should be one of:
"arm,cortex-a9-twd-wdt"
"arm,cortex-a5-twd-wdt"
"arm,arm11mp-twd-wdt"

- interrupts : One interrupt to each core

- reg : Specify the base address and the size of the TWD watchdog
register window.

Example:

twd-watchdog@2c000620 {
compatible = "arm,arm11mp-twd-wdt";
reg = <0x2c000620 0x20>;
interrupts = <1 14 0xf01>;
};
8 changes: 8 additions & 0 deletions arch/arm/include/asm/smp_twd.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,12 @@ struct twd_local_timer name __initdata = { \

int twd_local_timer_register(struct twd_local_timer *);

#ifdef CONFIG_HAVE_ARM_TWD
void twd_local_timer_of_register(void);
#else
static inline void twd_local_timer_of_register(void)
{
}
#endif

#endif
77 changes: 64 additions & 13 deletions arch/arm/kernel/smp_twd.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include <linux/clockchips.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>

#include <asm/smp_twd.h>
#include <asm/localtimer.h>
Expand Down Expand Up @@ -284,37 +286,86 @@ static struct local_timer_ops twd_lt_ops __cpuinitdata = {
.stop = twd_timer_stop,
};

int __init twd_local_timer_register(struct twd_local_timer *tlt)
static int __init twd_local_timer_common_register(void)
{
int err;

if (twd_base || twd_evt)
return -EBUSY;

twd_ppi = tlt->res[1].start;

twd_evt = alloc_percpu(struct clock_event_device *);
twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0]));
if (!twd_base || !twd_evt) {
if (!twd_evt) {
err = -ENOMEM;
goto out;
goto out_free;
}

err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_evt);
if (err) {
pr_err("twd: can't register interrupt %d (%d)\n", twd_ppi, err);
goto out;
goto out_free;
}

err = local_timer_register(&twd_lt_ops);
if (err)
goto out;
goto out_irq;

return 0;

out:
out_irq:
free_percpu_irq(twd_ppi, twd_evt);
out_free:
iounmap(twd_base);
twd_base = NULL;
free_percpu(twd_evt);
twd_base = twd_evt = NULL;

return err;
}

int __init twd_local_timer_register(struct twd_local_timer *tlt)
{
if (twd_base || twd_evt)
return -EBUSY;

twd_ppi = tlt->res[1].start;

twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0]));
if (!twd_base)
return -ENOMEM;

return twd_local_timer_common_register();
}

#ifdef CONFIG_OF
const static struct of_device_id twd_of_match[] __initconst = {
{ .compatible = "arm,cortex-a9-twd-timer", },
{ .compatible = "arm,cortex-a5-twd-timer", },
{ .compatible = "arm,arm11mp-twd-timer", },
{ },
};

void __init twd_local_timer_of_register(void)
{
struct device_node *np;
int err;

np = of_find_matching_node(NULL, twd_of_match);
if (!np) {
err = -ENODEV;
goto out;
}

twd_ppi = irq_of_parse_and_map(np, 0);
if (!twd_ppi) {
err = -EINVAL;
goto out;
}

twd_base = of_iomap(np, 0);
if (!twd_base) {
err = -ENOMEM;
goto out;
}

err = twd_local_timer_common_register();

out:
WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
}
#endif

0 comments on commit d8e0364

Please sign in to comment.