Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d8e03643 authored by Marc Zyngier's avatar Marc Zyngier
Browse files

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: default avatarRob Herring <rob.herring@calxeda.com>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
parent 81e46f7b
Loading
Loading
Loading
Loading
+48 −0
Original line number Original line Diff line number Diff line
* 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 −0
Original line number Original line Diff line number Diff line
@@ -40,4 +40,12 @@ struct twd_local_timer name __initdata = { \


int twd_local_timer_register(struct twd_local_timer *);
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
#endif
+64 −13
Original line number Original line Diff line number Diff line
@@ -20,6 +20,8 @@
#include <linux/clockchips.h>
#include <linux/clockchips.h>
#include <linux/irq.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>


#include <asm/smp_twd.h>
#include <asm/smp_twd.h>
#include <asm/localtimer.h>
#include <asm/localtimer.h>
@@ -284,37 +286,86 @@ static struct local_timer_ops twd_lt_ops __cpuinitdata = {
	.stop	= twd_timer_stop,
	.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;
	int err;


	if (twd_base || twd_evt)
		return -EBUSY;

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

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


	err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_evt);
	err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_evt);
	if (err) {
	if (err) {
		pr_err("twd: can't register interrupt %d (%d)\n", twd_ppi, 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);
	err = local_timer_register(&twd_lt_ops);
	if (err)
	if (err)
		goto out;
		goto out_irq;


	return 0;
	return 0;


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

	return err;
	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