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>
This commit is contained in:
parent
81e46f7b6d
commit
d8e0364364
3 changed files with 120 additions and 13 deletions
48
Documentation/devicetree/bindings/arm/twd.txt
Normal file
48
Documentation/devicetree/bindings/arm/twd.txt
Normal file
|
@ -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>;
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue