[PATCH 0/7] add support for clocksource/clockevent DT selection
Hi, This series adds support to permit the selection of clocksource/clockevent via DT. In [1] I proposed a solution other than the one in this series, with parsing DT bindings and at probe time and passing it to timer specific probe function. Looking forward though the clocksource/clockevent drivers implementation and taking into account the response at [2] I sticked the implementation to timer-of specific library. The implementation in this series is using timer-of specific library to parse the DT bindings related to timers functions: clocksource or clockevent. With this implementation a timer's driver registers for probing an array of objects of type struct timer_of. In flags member of struct timer_of object it has to be passed the following new flags (related to how the driver will behave) as follows: - TIMER_OF_TYPE_CS: timer could work only as clocksource at a time - TIMER_OF_TYPE_CE: timer could work only as clockevent at a time - TIMER_OF_TYPE_CE_AND_CE: timer could work at a time as both, clocksource and clockevent. The timer registration macro (for probing) now gets a new argument which should be an array of struct timer_of objects: TIMER_OF_DECLARE(name, compat, handler, to) CLOCKSOURCE_OF_DECLARE(name, compat, handler, to) In case driver could work to feed only the clocksource subsystem or only the clockevent subsystem the struct timer_of array passed to TIMER_OF_DECLARE()/ CLOCKSOURCE_OF_DECLARE() should contain 2 entries: one to be filled if probed timer works as clocksource device, one to be filled if probed timer works as clockevent device. For such a case, the minimal format of struct timer_of array is as follows: struct timer_of to[] = { { .flags = TIMER_OF_TYPE_CS } { .flags = TIMER_OF_TYPE_CE } { /* sentinel. */ }; If timer could work as both, clocksource and clockevent at the same time, the struct timer_of array should look as follows: struct timer_of to[] = { { .flags = TIMER_OF_TYPE_CE_AND_CS } { /* sentinel. */ }; And in device tree there should be added chosen bindings as follows: chosen { linux,clocksource { timer = <&timer1> }; linux,clockevent { timer = <&timer2>; } }; timer1: t1@123 { compatible = "timerx-compatible"; /* the rest of DT bindings here */ }; timer2: t1@234 { compatible = "timerx-compatible"; /* the rest of DT bindings here */ }; At probing time (timer_probe()), timer_of_init() will check the DT bindings and try to match with one of the entries in struct timer_of array passed at probe. The used entry will be considered used if the timers' device_node pointer is set. If no matching b/w DT and what has been passed for probe via struct timer_of array then probe should fail. The patches in this series are organized as follows: 1/7 - avoid calling timer_of_init() for every CPU since it should not be needed 2/7 - changes timer registration macro by adding a new argument (pointer to struct timer_of) 3/7 - use BIT() macro 4/7 - add clocksource/clockevent selection documentation [3] 5/7 - implement support described above 6/7 - remove an unnecessary line 7/7 - implement this support for integrator-ap timer I implemented this support for timer published at [4]. Thank you, Claudiu Beznea [1] https://lore.kernel.org/lkml/34574b0f-7d09-eb92-ea62-4199c293b...@microchip.com/ [2] https://lore.kernel.org/lkml/1ebaa306-8a7f-fd58-56e0-a61b76735...@linaro.org/ [3] https://lore.kernel.org/lkml/20171213185313.20017-1-alexandre.bell...@free-electrons.com/ [4] https://lore.kernel.org/lkml/1552580772-8499-1-git-send-email-claudiu.bez...@microchip.com/ Alexandre Belloni (2): dt-bindings: chosen: Add clocksource and clockevent selection clocksource/drivers/integrator-ap: parse the chosen node Claudiu Beznea (5): clocksource/drivers/c-sky: request timer_of_init only for probing CPU clocksource: change timer registration macros clocksource/timer_of: use BIT() macro clocksource/drivers/timer-of: add support support for timer's functionalities drivers/clocksource/timer-of: keep declaration on one line Documentation/devicetree/bindings/chosen.txt | 20 + arch/arm/kernel/smp_twd.c| 10 ++- arch/arm/mach-davinci/time.c | 2 +- arch/microblaze/kernel/timer.c | 2 +- arch/mips/ralink/cevt-rt3352.c | 2 +- arch/nios2/kernel/time.c | 2 +- drivers/clocksource/Kconfig | 1 + drivers/clocksource/arc_timer.c | 6 +- drivers/clocksource/arm_arch_timer.c | 6 +- drivers/clocksource/arm_global_timer.c | 2 +- drivers/clocksource/armv7m_systick.c | 2 +- drivers/clocksource/asm9260_timer.c | 2 +- drivers/clocksource/bcm2835_timer.c | 2 +- drivers/clocksource/bcm_kona_timer.c
[PATCH 1/7] clocksource/drivers/c-sky: request timer_of_init only for probing CPU
timer_of_init() was initially called for all possible CPUs although it was requested clock with index 0 for the same device_node on behalf of all possible CPUs. This patch keeps the timer_of_init() only for probing CPU and use the information obtained by timer_of_init() to also initialize the timer_of structure for the rest of CPUs. Since the probing CPU was requested also a per CPU interrupt, and the timer_of_init() has such a mechanism implemented, the patch took also the chance to pass TIMER_OF_IRQ flag to timer_of_init(). Apart from this csky_mptimer_irq variable was removed and information in per CPU timer_of objects was used instead (to->clkevt.irq). Signed-off-by: Claudiu Beznea --- drivers/clocksource/timer-mp-csky.c | 45 +++-- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/drivers/clocksource/timer-mp-csky.c b/drivers/clocksource/timer-mp-csky.c index 183a9955160a..dd263c8de580 100644 --- a/drivers/clocksource/timer-mp-csky.c +++ b/drivers/clocksource/timer-mp-csky.c @@ -15,7 +15,7 @@ #define PTIM_LVR "cr<6, 14>" #define PTIM_TSR "cr<1, 14>" -static int csky_mptimer_irq; +static irqreturn_t csky_timer_interrupt(int irq, void *dev); static int csky_mptimer_set_next_event(unsigned long delta, struct clock_event_device *ce) @@ -47,7 +47,7 @@ static int csky_mptimer_oneshot_stopped(struct clock_event_device *ce) } static DEFINE_PER_CPU(struct timer_of, csky_to) = { - .flags = TIMER_OF_CLOCK, + .flags = TIMER_OF_CLOCK | TIMER_OF_IRQ, .clkevt = { .rating = 300, .features = CLOCK_EVT_FEAT_PERCPU | @@ -57,6 +57,10 @@ static DEFINE_PER_CPU(struct timer_of, csky_to) = { .set_state_oneshot_stopped = csky_mptimer_oneshot_stopped, .set_next_event = csky_mptimer_set_next_event, }, + .of_irq = { + .percpu = true, + .handler= csky_timer_interrupt, + }, }; static irqreturn_t csky_timer_interrupt(int irq, void *dev) @@ -79,7 +83,7 @@ static int csky_mptimer_starting_cpu(unsigned int cpu) to->clkevt.cpumask = cpumask_of(cpu); - enable_percpu_irq(csky_mptimer_irq, 0); + enable_percpu_irq(to->clkevt.irq, 0); clockevents_config_and_register(&to->clkevt, timer_of_rate(to), 2, ULONG_MAX); @@ -89,7 +93,9 @@ static int csky_mptimer_starting_cpu(unsigned int cpu) static int csky_mptimer_dying_cpu(unsigned int cpu) { - disable_percpu_irq(csky_mptimer_irq); + struct timer_of *to = per_cpu_ptr(&csky_to, cpu); + + disable_percpu_irq(to->clkevt.irq); return 0; } @@ -117,8 +123,8 @@ struct clocksource csky_clocksource = { static int __init csky_mptimer_init(struct device_node *np) { - int ret, cpu, cpu_rollback; - struct timer_of *to = NULL; + struct timer_of *to = this_cpu_ptr(&csky_to); + int ret, cpu; /* * Csky_mptimer is designed for C-SKY SMP multi-processors and @@ -132,20 +138,20 @@ static int __init csky_mptimer_init(struct device_node *np) * We use private irq for the mptimer and irq number is the same * for every core. So we use request_percpu_irq() in timer_of_init. */ - csky_mptimer_irq = irq_of_parse_and_map(np, 0); - if (csky_mptimer_irq <= 0) - return -EINVAL; - ret = request_percpu_irq(csky_mptimer_irq, csky_timer_interrupt, -"csky_mp_timer", &csky_to); + ret = timer_of_init(np, to); if (ret) return -EINVAL; for_each_possible_cpu(cpu) { - to = per_cpu_ptr(&csky_to, cpu); - ret = timer_of_init(np, to); - if (ret) - goto rollback; + struct timer_of *cpu_to = per_cpu_ptr(&csky_to, cpu); + + if (to == cpu_to) + continue; + + cpu_to->clkevt.irq = to->of_irq.irq; + cpu_to->of_clk.rate = to->of_clk.rate; + cpu_to->of_clk.period = to->of_clk.period; } clocksource_register_hz(&csky_clocksource, timer_of_rate(to)); @@ -156,18 +162,13 @@ static int __init csky_mptimer_init(struct device_node *np) csky_mptimer_starting_cpu, csky_mptimer_dying_cpu); if (ret) - return -EINVAL; + goto rollback; return 0; rollback: - for_each_possible_cpu(cpu_rollback) { - if (cpu_rollback == cpu) -
[PATCH 3/7] clocksource/timer_of: use BIT() macro
Use BIT() macro for timer_of flags. Signed-off-by: Claudiu Beznea --- drivers/clocksource/timer-of.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clocksource/timer-of.h b/drivers/clocksource/timer-of.h index ee467bb16ca3..df861ea2ec42 100644 --- a/drivers/clocksource/timer-of.h +++ b/drivers/clocksource/timer-of.h @@ -4,9 +4,9 @@ #include -#define TIMER_OF_BASE 0x1 -#define TIMER_OF_CLOCK 0x2 -#define TIMER_OF_IRQ 0x4 +#define TIMER_OF_BASE BIT(0) +#define TIMER_OF_CLOCK BIT(1) +#define TIMER_OF_IRQ BIT(2) struct of_timer_irq { int irq; -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH 2/7] clocksource: change timer registration macros
Change timer registration macros (TIMER_OF_DECLARE() and CLOCKSOURCE_OF_DECLARE()) by adding a new argument. This new argument is a pointer to an object of type struct timer_of and is used in timer_probe(). Based on the flags filled in the struct timer_of object the probing process will parse different DT bindings. Later on the drivers will use the result of this parsing. Even at the moment only few drivers are using this functionality there are other that could be converted to use it. Signed-off-by: Claudiu Beznea --- arch/arm/kernel/smp_twd.c | 10 ++-- arch/arm/mach-davinci/time.c | 2 +- arch/microblaze/kernel/timer.c| 2 +- arch/mips/ralink/cevt-rt3352.c| 2 +- arch/nios2/kernel/time.c | 2 +- drivers/clocksource/arc_timer.c | 6 +-- drivers/clocksource/arm_arch_timer.c | 6 +-- drivers/clocksource/arm_global_timer.c| 2 +- drivers/clocksource/armv7m_systick.c | 2 +- drivers/clocksource/asm9260_timer.c | 2 +- drivers/clocksource/bcm2835_timer.c | 2 +- drivers/clocksource/bcm_kona_timer.c | 4 +- drivers/clocksource/clksrc-dbx500-prcmu.c | 2 +- drivers/clocksource/clksrc_st_lpc.c | 2 +- drivers/clocksource/clps711x-timer.c | 2 +- drivers/clocksource/dw_apb_timer_of.c | 9 ++-- drivers/clocksource/exynos_mct.c | 4 +- drivers/clocksource/h8300_timer16.c | 2 +- drivers/clocksource/h8300_timer8.c| 2 +- drivers/clocksource/h8300_tpu.c | 2 +- drivers/clocksource/jcore-pit.c | 2 +- drivers/clocksource/mips-gic-timer.c | 2 +- drivers/clocksource/mps2-timer.c | 2 +- drivers/clocksource/mxs_timer.c | 2 +- drivers/clocksource/nomadik-mtu.c | 2 +- drivers/clocksource/renesas-ostm.c| 2 +- drivers/clocksource/samsung_pwm_timer.c | 12 +++-- drivers/clocksource/timer-armada-370-xp.c | 6 +-- drivers/clocksource/timer-atcpit100.c | 6 +-- drivers/clocksource/timer-atlas7.c| 3 +- drivers/clocksource/timer-atmel-pit.c | 2 +- drivers/clocksource/timer-atmel-st.c | 2 +- drivers/clocksource/timer-atmel-tcb.c | 2 +- drivers/clocksource/timer-cadence-ttc.c | 2 +- drivers/clocksource/timer-davinci.c | 3 +- drivers/clocksource/timer-digicolor.c | 2 +- drivers/clocksource/timer-efm32.c | 4 +- drivers/clocksource/timer-fsl-ftm.c | 2 +- drivers/clocksource/timer-fttmr010.c | 10 ++-- drivers/clocksource/timer-gx6605s.c | 7 +-- drivers/clocksource/timer-imx-gpt.c | 24 - drivers/clocksource/timer-imx-sysctr.c| 9 +--- drivers/clocksource/timer-imx-tpm.c | 6 +-- drivers/clocksource/timer-integrator-ap.c | 2 +- drivers/clocksource/timer-ixp4xx.c| 2 +- drivers/clocksource/timer-keystone.c | 2 +- drivers/clocksource/timer-lpc32xx.c | 2 +- drivers/clocksource/timer-mediatek.c | 84 --- drivers/clocksource/timer-meson6.c| 2 +- drivers/clocksource/timer-milbeaut.c | 7 +-- drivers/clocksource/timer-mp-csky.c | 15 ++ drivers/clocksource/timer-npcm7xx.c | 9 +--- drivers/clocksource/timer-nps.c | 6 +-- drivers/clocksource/timer-of.c| 8 ++- drivers/clocksource/timer-of.h| 11 drivers/clocksource/timer-orion.c | 2 +- drivers/clocksource/timer-owl.c | 6 +-- drivers/clocksource/timer-oxnas-rps.c | 4 +- drivers/clocksource/timer-pistachio.c | 2 +- drivers/clocksource/timer-prima2.c| 2 +- drivers/clocksource/timer-probe.c | 17 ++- drivers/clocksource/timer-pxa.c | 2 +- drivers/clocksource/timer-qcom.c | 4 +- drivers/clocksource/timer-rda.c | 8 +-- drivers/clocksource/timer-riscv.c | 2 +- drivers/clocksource/timer-rockchip.c | 4 +- drivers/clocksource/timer-sp804.c | 4 +- drivers/clocksource/timer-sprd.c | 16 +- drivers/clocksource/timer-stm32.c | 44 +++- drivers/clocksource/timer-sun4i.c | 12 ++--- drivers/clocksource/timer-sun5i.c | 4 +- drivers/clocksource/timer-tango-xtal.c| 2 +- drivers/clocksource/timer-tegra.c | 20 +++- drivers/clocksource/timer-ti-32k.c| 2 +- drivers/clocksource/timer-u300.c | 2 +- drivers/clocksource/timer-versatile.c | 4 +- drivers/clocksource/timer-vf-pit.c| 2 +- drivers/clocksource/timer-vt8500.c| 2 +- drivers/clocksource/timer-zevio.c | 2 +- include/linux/clocksource.h | 30 ++- 80 files changed, 266 insertions(+), 264 deletions(-) diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 9a14f721a2b0..02ea5ac511ff 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -335,6 +335,10 @@ static int __init
[PATCH 4/7] dt-bindings: chosen: Add clocksource and clockevent selection
From: Alexandre Belloni Some timer drivers may behave either as clocksource or clockevent or both. Until now, in case of platforms with multiple hardware resources of the same type, the drivers were chosing the first registered hardware resource as clocksource/clockevent and the next one as clockevent/clocksource. Other were using different compatibles (one for each functionality, although its about the same hardware). Add DT bindings to be able to choose the functionality of a timer. Signed-off-by: Alexandre Belloni Signed-off-by: Claudiu Beznea --- Documentation/devicetree/bindings/chosen.txt | 20 1 file changed, 20 insertions(+) diff --git a/Documentation/devicetree/bindings/chosen.txt b/Documentation/devicetree/bindings/chosen.txt index 45e79172a646..aad3034cdbdf 100644 --- a/Documentation/devicetree/bindings/chosen.txt +++ b/Documentation/devicetree/bindings/chosen.txt @@ -135,3 +135,23 @@ e.g. linux,initrd-end = <0x8280>; }; }; + +linux,clocksource and linux,clockevent +-- + +Those nodes have a timer property. This property is a phandle to the timer to be +chosen as the clocksource or clockevent. This is only useful when the platform +has multiple identical timers and it is not possible to let linux make the +correct choice. + +/ { + chosen { + linux,clocksource { + timer = <&timer0>; + }; + + linux,clockevent { + timer = <&timer1>; + }; + }; +}; -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH 5/7] clocksource/drivers/timer-of: add support support for timer's functionalities
Timers could feed clocksource and clockevent devices. Even so, there are timers that could work as clocksource only, clockevent only or both. For timers that could work only as clocksource or as clockevent there were used different mechanisms to register one hardware resource to feed a clocksource device and one hardware resource to feed a clockevent device. One of this is: first probed hardware works as clockevent, 2nd probed hardware works as clocksource device. Another one is to have different DT compatible for the same hardware but one to register a clocksource device, another to register a clockevent device. To avoid this, in [1] it was proposed a chosen node mechanism in DT. The changes in this patch integrate the proposals in [1] and goes further. It uses TIMER_OF library and adapt it. It passes to the probing macro arrays of objects of type struct timer_of. We need arrays here to cover the following scenario: One timer driver could be probe 2 times: 1st time to register a physical device to feed a clocksource device, 2nd timer to register another physical device (of the same type with the 1st one registered) but that will feed a clockevent device. If these are 2 different physical devices they are mapped to a different address, they use different clocks and also different IRQ numbers. So for every probe we need a different struct timer_of object. New flags were introduced in this patch to specify the functionality that timer drivers support: - TIMER_OF_TYPE_CE - TIMER_OF_TYPE_CS - TIMER_OF_TYPE_CE_AND_CS. Drivers that could work only as a clocksource could register a minimum struct timer_of array as follows: static struct timer_of to[] = { { .flags = TIMER_OF_TYPE_CS }, { /* sentinel */ } }; drivers that could work only as a clockevent could register a minimum struct timer_of array as follows: static struct timer_of to[] = { { .flags = TIMER_OF_TYPE_CE }, { /* sentinel */ } }; drivers that could work as both clocksource and clockevent at the same time could register a minimum struct timer_of array as follows: static struct timer_of to[] = { { .flags = TIMER_OF_TYPE_CE_AND_CS }, { /* sentinel*/ } }; And these arrays are passed to the probing system via: TIMER_OF_DECLARE() or CLOCKSOURCE_OF_DECLARE() macros. For backward compatibility all the current drivers that are using TIMER_OF library are registered with TIMER_OF_TYPE_CE_AND_CS flag. At the probing time, the probing CPU will call timer_of_probe() -> timer_of_init(). timer_of_init() parses the DT bindings looking for "linux,clocksource" and "linux,clockevent" chosen DT bindings, and is looking into the to[] array, passed via TIMER_OF_DELCARE()/ CLOCKSOURCE_OF_DECLARE(), for a unused entry which matches with the DT bindings (this is done by comparing TIMER_OF_TYPE* probing flags with TIMER_OF_TYPE* flags retrieved from DT). If there is a match the to[] entry will be used for the current probing and the entry is marked as used. to[] entry is considered to be used if to->np is set. Also the used to[] entry is saved into the data field of struct device_node used in the probe. In this way the probing functions of the timer drivers would retrieve the struct timer_of object to be used in the current probe. In case of timers which are registering percpu struct timer_of objects for probing only the percpu timer_of object is used in the probe time. Currently, these kind of drivers are using only the struct timer_of object corresponding to the probing CPU to retrieve DT bindings and then replicate/adapt this information for the other CPUs. All the drivers were adapted to this mechanism using TIMER_OF_TYPE_CE_AND_CS flag for backward compatibility. [1] https://lore.kernel.org/lkml/20171213185313.20017-3-alexandre.bell...@free-electrons.com/ Signed-off-by: Claudiu Beznea --- drivers/clocksource/timer-atcpit100.c | 70 +++- drivers/clocksource/timer-gx6605s.c| 53 - drivers/clocksource/timer-imx-sysctr.c | 56 -- drivers/clocksource/timer-imx-tpm.c| 65 ++ drivers/clocksource/timer-mediatek.c | 64 ++--- drivers/clocksource/timer-milbeaut.c | 54 +++-- drivers/clocksource/timer-mp-csky.c| 4 +- drivers/clocksource/timer-npcm7xx.c| 82 drivers/clocksource/timer-of.c | 85 -- drivers/clocksource/timer-of.h | 16 +++ drivers/clocksource/timer-rda.c| 60 +--- drivers/clocksource/timer-sprd.c | 67 +++ drivers/clocksource/timer-stm32.c | 33 +++-- drivers/clocksource/timer-sun4i.c | 74 +++-- drivers/clocksource/timer-tegra.c | 13 +++--- 15 files changed, 479 insertions(+), 317 deletions(-) diff --git a/drivers/clocksource/timer-atcpit100.c b
[PATCH 6/7] drivers/clocksource/timer-of: keep declaration on one line
timer_of_init() declaration could be kept on one line (80 chars per line rule is not broken). Signed-off-by: Claudiu Beznea --- drivers/clocksource/timer-of.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/clocksource/timer-of.h b/drivers/clocksource/timer-of.h index 9fb8c5523150..af72e29e2ea4 100644 --- a/drivers/clocksource/timer-of.h +++ b/drivers/clocksource/timer-of.h @@ -84,8 +84,7 @@ static inline unsigned int timer_of_is_clockevent(struct timer_of *to) (TIMER_OF_TYPE_CE | TIMER_OF_TYPE_CE_AND_CS)); } -extern int __init timer_of_init(struct device_node *np, - struct timer_of *to); +extern int __init timer_of_init(struct device_node *np, struct timer_of *to); extern void __init timer_of_cleanup(struct timer_of *to); -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH 7/7] clocksource/drivers/integrator-ap: parse the chosen node
From: Alexandre Belloni The driver currently uses aliases to know whether the timer is the clocksource or the clockevent. Add the /chosen/linux,clocksource and /chosen/linux,clockevent parsing while keeping backward compatibility. Signed-off-by: Alexandre Belloni Signed-off-by: Claudiu Beznea --- drivers/clocksource/Kconfig | 1 + drivers/clocksource/timer-integrator-ap.c | 21 - 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index a642c23b2fba..e1742c0abb03 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -240,6 +240,7 @@ config KEYSTONE_TIMER config INTEGRATOR_AP_TIMER bool "Integrator-ap timer driver" if COMPILE_TEST select CLKSRC_MMIO + select TIMER_OF help Enables support for the Integrator-ap timer. diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c index 8d6f814ace36..78af89e73125 100644 --- a/drivers/clocksource/timer-integrator-ap.c +++ b/drivers/clocksource/timer-integrator-ap.c @@ -14,6 +14,7 @@ #include #include +#include "timer-of.h" #include "timer-sp.h" static void __iomem * sched_clk_base; @@ -160,6 +161,12 @@ static int integrator_clockevent_init(unsigned long inrate, return 0; } +static struct timer_of to[] = { + { .flags = TIMER_OF_TYPE_CS, }, + { .flags = TIMER_OF_TYPE_CE, }, + { /* sentinel */ } +}; + static int __init integrator_ap_timer_init_of(struct device_node *node) { const char *path; @@ -169,6 +176,7 @@ static int __init integrator_ap_timer_init_of(struct device_node *node) struct clk *clk; unsigned long rate; struct device_node *alias_node; + struct timer_of *to = node->data; base = of_io_request_and_map(node, 0, "integrator-timer"); if (IS_ERR(base)) @@ -183,6 +191,17 @@ static int __init integrator_ap_timer_init_of(struct device_node *node) rate = clk_get_rate(clk); writel(0, base + TIMER_CTRL); + if (timer_of_is_clocksource(to)) + /* The primary timer lacks IRQ, use as clocksource */ + return integrator_clocksource_init(rate, base); + + if (timer_of_is_clockevent(to)) { + /* The secondary timer will drive the clock event */ + irq = irq_of_parse_and_map(node, 0); + return integrator_clockevent_init(rate, base, irq); + } + + /* DT ABI compatibility below */ err = of_property_read_string(of_aliases, "arm,timer-primary", &path); if (err) { @@ -227,4 +246,4 @@ static int __init integrator_ap_timer_init_of(struct device_node *node) } TIMER_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer", - integrator_ap_timer_init_of, NULL); + integrator_ap_timer_init_of, to); -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc