From ee98d27df6827b5ba4bd99cb7d5cb1239b6a1a31 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 15 Feb 2013 16:40:51 -0800 Subject: ARM: EXYNOS4: Divorce mct from local timer API Separate the mct local timers from the local timer API. This will allow us to remove ARM local timer support in the near future and gets us closer to moving this driver to drivers/clocksource. Acked-by: Kukjin Kim Acked-by: Marc Zyngier Cc: Thomas Abraham Signed-off-by: Stephen Boyd --- drivers/clocksource/exynos_mct.c | 60 ++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 17 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 662fcc06582..1c3f5a65204 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -24,7 +25,6 @@ #include #include -#include #include #define EXYNOS4_MCTREG(x) (x) @@ -80,7 +80,7 @@ static unsigned int mct_int_type; static int mct_irqs[MCT_NR_IRQS]; struct mct_clock_event_device { - struct clock_event_device *evt; + struct clock_event_device evt; unsigned long base; char name[10]; }; @@ -295,8 +295,6 @@ static void exynos4_clockevent_init(void) setup_irq(mct_irqs[MCT_G0_IRQ], &mct_comp_event_irq); } -#ifdef CONFIG_LOCAL_TIMERS - static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick); /* Clock event handling */ @@ -369,7 +367,7 @@ static inline void exynos4_tick_set_mode(enum clock_event_mode mode, static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) { - struct clock_event_device *evt = mevt->evt; + struct clock_event_device *evt = &mevt->evt; /* * This is for supporting oneshot mode. @@ -391,7 +389,7 @@ static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) { struct mct_clock_event_device *mevt = dev_id; - struct clock_event_device *evt = mevt->evt; + struct clock_event_device *evt = &mevt->evt; exynos4_mct_tick_clear(mevt); @@ -417,8 +415,7 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt) struct mct_clock_event_device *mevt; unsigned int cpu = smp_processor_id(); - mevt = this_cpu_ptr(&percpu_mct_tick); - mevt->evt = evt; + mevt = container_of(evt, struct mct_clock_event_device, evt); mevt->base = EXYNOS4_MCT_L_BASE(cpu); sprintf(mevt->name, "mct_tick%d", cpu); @@ -452,7 +449,7 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt) return 0; } -static void exynos4_local_timer_stop(struct clock_event_device *evt) +static void __cpuinit exynos4_local_timer_stop(struct clock_event_device *evt) { unsigned int cpu = smp_processor_id(); evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); @@ -465,14 +462,37 @@ static void exynos4_local_timer_stop(struct clock_event_device *evt) disable_percpu_irq(mct_irqs[MCT_L0_IRQ]); } -static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = { - .setup = exynos4_local_timer_setup, - .stop = exynos4_local_timer_stop, +static int __cpuinit exynos4_mct_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + struct mct_clock_event_device *mevt; + + /* + * Grab cpu pointer in each case to avoid spurious + * preemptible warnings + */ + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_STARTING: + mevt = this_cpu_ptr(&percpu_mct_tick); + exynos4_local_timer_setup(&mevt->evt); + break; + case CPU_DYING: + mevt = this_cpu_ptr(&percpu_mct_tick); + exynos4_local_timer_stop(&mevt->evt); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block exynos4_mct_cpu_nb __cpuinitdata = { + .notifier_call = exynos4_mct_cpu_notify, }; -#endif /* CONFIG_LOCAL_TIMERS */ static void __init exynos4_timer_resources(struct device_node *np, void __iomem *base) { + int err; + struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick); struct clk *mct_clk, *tick_clk; tick_clk = np ? of_clk_get_by_name(np, "fin_pll") : @@ -490,9 +510,7 @@ static void __init exynos4_timer_resources(struct device_node *np, void __iomem if (!reg_base) panic("%s: unable to ioremap mct address space\n", __func__); -#ifdef CONFIG_LOCAL_TIMERS if (mct_int_type == MCT_INT_PPI) { - int err; err = request_percpu_irq(mct_irqs[MCT_L0_IRQ], exynos4_mct_tick_isr, "MCT", @@ -501,8 +519,16 @@ static void __init exynos4_timer_resources(struct device_node *np, void __iomem mct_irqs[MCT_L0_IRQ], err); } - local_timer_register(&exynos4_mct_tick_ops); -#endif /* CONFIG_LOCAL_TIMERS */ + err = register_cpu_notifier(&exynos4_mct_cpu_nb); + if (err) + goto out_irq; + + /* Immediately configure the timer on the boot CPU */ + exynos4_local_timer_setup(&mevt->evt); + return; + +out_irq: + free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick); } void __init mct_init(void __iomem *base, int irq_g0, int irq_l0, int irq_l1) -- cgit v1.2.3-70-g09d2 From 05a6548556d007143fcb291bfdfa6b2bb3e63e95 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 15 Feb 2013 17:02:16 -0800 Subject: ARM: PRIMA2: Divorce timer-marco from local timer API Separate the marco local timers from the local timer API. This will allow us to remove ARM local timer support in the near future and gets us closer to moving this driver to drivers/clocksource. Acked-by: Marc Zyngier Cc: Barry Song Signed-off-by: Stephen Boyd --- drivers/clocksource/timer-marco.c | 100 ++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 46 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/timer-marco.c b/drivers/clocksource/timer-marco.c index e5dc9129ca2..01b9683557b 100644 --- a/drivers/clocksource/timer-marco.c +++ b/drivers/clocksource/timer-marco.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -18,7 +19,6 @@ #include #include #include -#include #include #define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000 @@ -151,13 +151,7 @@ static void sirfsoc_clocksource_resume(struct clocksource *cs) BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); } -static struct clock_event_device sirfsoc_clockevent = { - .name = "sirfsoc_clockevent", - .rating = 200, - .features = CLOCK_EVT_FEAT_ONESHOT, - .set_mode = sirfsoc_timer_set_mode, - .set_next_event = sirfsoc_timer_set_next_event, -}; +static struct clock_event_device __percpu *sirfsoc_clockevent; static struct clocksource sirfsoc_clocksource = { .name = "sirfsoc_clocksource", @@ -173,11 +167,8 @@ static struct irqaction sirfsoc_timer_irq = { .name = "sirfsoc_timer0", .flags = IRQF_TIMER | IRQF_NOBALANCING, .handler = sirfsoc_timer_interrupt, - .dev_id = &sirfsoc_clockevent, }; -#ifdef CONFIG_LOCAL_TIMERS - static struct irqaction sirfsoc_timer1_irq = { .name = "sirfsoc_timer1", .flags = IRQF_TIMER | IRQF_NOBALANCING, @@ -186,56 +177,77 @@ static struct irqaction sirfsoc_timer1_irq = { static int __cpuinit sirfsoc_local_timer_setup(struct clock_event_device *ce) { - /* Use existing clock_event for cpu 0 */ - if (!smp_processor_id()) - return 0; + int cpu = smp_processor_id(); + struct irqaction *action; + + if (cpu == 0) + action = &sirfsoc_timer_irq; + else + action = &sirfsoc_timer1_irq; - ce->irq = sirfsoc_timer1_irq.irq; + ce->irq = action->irq; ce->name = "local_timer"; - ce->features = sirfsoc_clockevent.features; - ce->rating = sirfsoc_clockevent.rating; + ce->features = CLOCK_EVT_FEAT_ONESHOT; + ce->rating = 200; ce->set_mode = sirfsoc_timer_set_mode; ce->set_next_event = sirfsoc_timer_set_next_event; - ce->shift = sirfsoc_clockevent.shift; - ce->mult = sirfsoc_clockevent.mult; - ce->max_delta_ns = sirfsoc_clockevent.max_delta_ns; - ce->min_delta_ns = sirfsoc_clockevent.min_delta_ns; + clockevents_calc_mult_shift(ce, CLOCK_TICK_RATE, 60); + ce->max_delta_ns = clockevent_delta2ns(-2, ce); + ce->min_delta_ns = clockevent_delta2ns(2, ce); + ce->cpumask = cpumask_of(cpu); - sirfsoc_timer1_irq.dev_id = ce; - BUG_ON(setup_irq(ce->irq, &sirfsoc_timer1_irq)); - irq_set_affinity(sirfsoc_timer1_irq.irq, cpumask_of(1)); + action->dev_id = ce; + BUG_ON(setup_irq(ce->irq, action)); + irq_set_affinity(action->irq, cpumask_of(cpu)); clockevents_register_device(ce); return 0; } -static void sirfsoc_local_timer_stop(struct clock_event_device *ce) +static void __cpuinit sirfsoc_local_timer_stop(struct clock_event_device *ce) { + int cpu = smp_processor_id(); + sirfsoc_timer_count_disable(1); - remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq); + if (cpu == 0) + remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq); + else + remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq); } -static struct local_timer_ops sirfsoc_local_timer_ops __cpuinitdata = { - .setup = sirfsoc_local_timer_setup, - .stop = sirfsoc_local_timer_stop, +static int __cpuinit sirfsoc_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + /* + * Grab cpu pointer in each case to avoid spurious + * preemptible warnings + */ + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_STARTING: + sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent)); + break; + case CPU_DYING: + sirfsoc_local_timer_stop(this_cpu_ptr(sirfsoc_clockevent)); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block sirfsoc_cpu_nb __cpuinitdata = { + .notifier_call = sirfsoc_cpu_notify, }; -#endif /* CONFIG_LOCAL_TIMERS */ static void __init sirfsoc_clockevent_init(void) { - clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60); - - sirfsoc_clockevent.max_delta_ns = - clockevent_delta2ns(-2, &sirfsoc_clockevent); - sirfsoc_clockevent.min_delta_ns = - clockevent_delta2ns(2, &sirfsoc_clockevent); - - sirfsoc_clockevent.cpumask = cpumask_of(0); - clockevents_register_device(&sirfsoc_clockevent); -#ifdef CONFIG_LOCAL_TIMERS - local_timer_register(&sirfsoc_local_timer_ops); -#endif + sirfsoc_clockevent = alloc_percpu(struct clock_event_device); + BUG_ON(!sirfsoc_clockevent); + + BUG_ON(register_cpu_notifier(&sirfsoc_cpu_nb)); + + /* Immediately configure the timer on the boot CPU */ + sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent)); } /* initialize the kernel jiffy timer source */ @@ -273,8 +285,6 @@ static void __init sirfsoc_marco_timer_init(void) BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE)); - BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq)); - sirfsoc_clockevent_init(); } @@ -288,11 +298,9 @@ static void __init sirfsoc_of_timer_init(struct device_node *np) if (!sirfsoc_timer_irq.irq) panic("No irq passed for timer0 via DT\n"); -#ifdef CONFIG_LOCAL_TIMERS sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1); if (!sirfsoc_timer1_irq.irq) panic("No irq passed for timer1 via DT\n"); -#endif sirfsoc_marco_timer_init(); } -- cgit v1.2.3-70-g09d2 From faef31b482549640e2d0095afdf3dedb992cfa80 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 21 Feb 2013 15:04:08 -0800 Subject: clocksource: time-armada-370-xp: Fix sparse warning drivers/clocksource/time-armada-370-xp.c:217:13: warning: symbol 'armada_370_xp_timer_init' was not declared. Should it be static? Also remove the __init marking in the prototype as it's unnecessary and drop the init.h file. Acked-by: Gregory CLEMENT Acked-by: Marc Zyngier Signed-off-by: Stephen Boyd --- drivers/clocksource/time-armada-370-xp.c | 3 ++- include/linux/time-armada-370-xp.h | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index efdca3263af..b1e1d92a883 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -28,9 +28,10 @@ #include #include #include +#include +#include #include -#include /* * Timer block registers. */ diff --git a/include/linux/time-armada-370-xp.h b/include/linux/time-armada-370-xp.h index dfdfdc03115..6fb0856b940 100644 --- a/include/linux/time-armada-370-xp.h +++ b/include/linux/time-armada-370-xp.h @@ -11,8 +11,6 @@ #ifndef __TIME_ARMADA_370_XPPRCMU_H #define __TIME_ARMADA_370_XPPRCMU_H -#include - -void __init armada_370_xp_timer_init(void); +void armada_370_xp_timer_init(void); #endif -- cgit v1.2.3-70-g09d2 From 5ddb6d21c30d10ae4a740a788bb9101bd384fea5 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 15 Feb 2013 17:02:16 -0800 Subject: clocksource: time-armada-370-xp: Divorce from local timer API Separate the armada 370xp local timers from the local timer API. This will allow us to remove ARM local timer support in the near future and makes this driver multi-architecture friendly. Acked-by: Gregory CLEMENT Tested-by: Gregory CLEMENT Acked-by: Marc Zyngier Signed-off-by: Stephen Boyd --- drivers/clocksource/time-armada-370-xp.c | 89 +++++++++++++++----------------- 1 file changed, 41 insertions(+), 48 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index b1e1d92a883..f86542002ee 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,6 @@ #include #include -#include /* * Timer block registers. */ @@ -70,7 +70,7 @@ static bool timer25Mhz = true; */ static u32 ticks_per_jiffy; -static struct clock_event_device __percpu **percpu_armada_370_xp_evt; +static struct clock_event_device __percpu *armada_370_xp_evt; static u32 notrace armada_370_xp_read_sched_clock(void) { @@ -143,21 +143,14 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode, } } -static struct clock_event_device armada_370_xp_clkevt = { - .name = "armada_370_xp_per_cpu_tick", - .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .shift = 32, - .rating = 300, - .set_next_event = armada_370_xp_clkevt_next_event, - .set_mode = armada_370_xp_clkevt_mode, -}; +static int armada_370_xp_clkevt_irq; static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) { /* * ACK timer interrupt and call event handler. */ - struct clock_event_device *evt = *(struct clock_event_device **)dev_id; + struct clock_event_device *evt = dev_id; writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); evt->event_handler(evt); @@ -173,42 +166,55 @@ static int __cpuinit armada_370_xp_timer_setup(struct clock_event_device *evt) u32 u; int cpu = smp_processor_id(); - /* Use existing clock_event for cpu 0 */ - if (!smp_processor_id()) - return 0; - u = readl(local_base + TIMER_CTRL_OFF); if (timer25Mhz) writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); else writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); - evt->name = armada_370_xp_clkevt.name; - evt->irq = armada_370_xp_clkevt.irq; - evt->features = armada_370_xp_clkevt.features; - evt->shift = armada_370_xp_clkevt.shift; - evt->rating = armada_370_xp_clkevt.rating, + evt->name = "armada_370_xp_per_cpu_tick", + evt->features = CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_PERIODIC; + evt->shift = 32, + evt->rating = 300, evt->set_next_event = armada_370_xp_clkevt_next_event, evt->set_mode = armada_370_xp_clkevt_mode, + evt->irq = armada_370_xp_clkevt_irq; evt->cpumask = cpumask_of(cpu); - *__this_cpu_ptr(percpu_armada_370_xp_evt) = evt; - clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe); enable_percpu_irq(evt->irq, 0); return 0; } -static void armada_370_xp_timer_stop(struct clock_event_device *evt) +static void __cpuinit armada_370_xp_timer_stop(struct clock_event_device *evt) { evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); disable_percpu_irq(evt->irq); } -static struct local_timer_ops armada_370_xp_local_timer_ops __cpuinitdata = { - .setup = armada_370_xp_timer_setup, - .stop = armada_370_xp_timer_stop, +static int __cpuinit armada_370_xp_timer_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + /* + * Grab cpu pointer in each case to avoid spurious + * preemptible warnings + */ + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_STARTING: + armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); + break; + case CPU_DYING: + armada_370_xp_timer_stop(this_cpu_ptr(armada_370_xp_evt)); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block armada_370_xp_timer_cpu_nb __cpuinitdata = { + .notifier_call = armada_370_xp_timer_cpu_notify, }; void __init armada_370_xp_timer_init(void) @@ -224,9 +230,6 @@ void __init armada_370_xp_timer_init(void) if (of_find_property(np, "marvell,timer-25Mhz", NULL)) { /* The fixed 25MHz timer is available so let's use it */ - u = readl(local_base + TIMER_CTRL_OFF); - writel(u | TIMER0_25MHZ, - local_base + TIMER_CTRL_OFF); u = readl(timer_base + TIMER_CTRL_OFF); writel(u | TIMER0_25MHZ, timer_base + TIMER_CTRL_OFF); @@ -236,9 +239,6 @@ void __init armada_370_xp_timer_init(void) struct clk *clk = of_clk_get(np, 0); WARN_ON(IS_ERR(clk)); rate = clk_get_rate(clk); - u = readl(local_base + TIMER_CTRL_OFF); - writel(u & ~(TIMER0_25MHZ), - local_base + TIMER_CTRL_OFF); u = readl(timer_base + TIMER_CTRL_OFF); writel(u & ~(TIMER0_25MHZ), @@ -252,7 +252,7 @@ void __init armada_370_xp_timer_init(void) * We use timer 0 as clocksource, and private(local) timer 0 * for clockevents */ - armada_370_xp_clkevt.irq = irq_of_parse_and_map(np, 4); + armada_370_xp_clkevt_irq = irq_of_parse_and_map(np, 4); ticks_per_jiffy = (timer_clk + HZ / 2) / HZ; @@ -277,26 +277,19 @@ void __init armada_370_xp_timer_init(void) "armada_370_xp_clocksource", timer_clk, 300, 32, clocksource_mmio_readl_down); - /* Register the clockevent on the private timer of CPU 0 */ - armada_370_xp_clkevt.cpumask = cpumask_of(0); - clockevents_config_and_register(&armada_370_xp_clkevt, - timer_clk, 1, 0xfffffffe); + register_cpu_notifier(&armada_370_xp_timer_cpu_nb); - percpu_armada_370_xp_evt = alloc_percpu(struct clock_event_device *); + armada_370_xp_evt = alloc_percpu(struct clock_event_device); /* * Setup clockevent timer (interrupt-driven). */ - *__this_cpu_ptr(percpu_armada_370_xp_evt) = &armada_370_xp_clkevt; - res = request_percpu_irq(armada_370_xp_clkevt.irq, + res = request_percpu_irq(armada_370_xp_clkevt_irq, armada_370_xp_timer_interrupt, - armada_370_xp_clkevt.name, - percpu_armada_370_xp_evt); - if (!res) { - enable_percpu_irq(armada_370_xp_clkevt.irq, 0); -#ifdef CONFIG_LOCAL_TIMERS - local_timer_register(&armada_370_xp_local_timer_ops); -#endif - } + "armada_370_xp_per_cpu_tick", + armada_370_xp_evt); + /* Immediately configure the timer on the boot CPU */ + if (!res) + armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); } -- cgit v1.2.3-70-g09d2 From 8c37bb3ac95b8ff953bd3c8bc8dd0a393d5ae989 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Wed, 19 Jun 2013 11:32:08 -0400 Subject: clocksource+irqchip: delete __cpuinit usage from all related files The __cpuinit type of throwaway sections might have made sense some time ago when RAM was more constrained, but now the savings do not offset the cost and complications. For example, the fix in commit 5e427ec2d0 ("x86: Fix bit corruption at CPU resume time") is a good example of the nasty type of bugs that can be created with improper use of the various __init prefixes. After a discussion on LKML[1] it was decided that cpuinit should go the way of devinit and be phased out. Once all the users are gone, we can then finally remove the macros themselves from linux/init.h. This removes all the drivers/clocksource and drivers/irqchip uses of the __cpuinit macros from all C files. [1] https://lkml.org/lkml/2013/5/20/589 Cc: John Stultz Cc: Thomas Gleixner Acked-by: Thomas Gleixner Signed-off-by: Paul Gortmaker --- drivers/clocksource/arm_arch_timer.c | 8 ++++---- drivers/clocksource/arm_global_timer.c | 8 ++++---- drivers/clocksource/dummy_timer.c | 6 +++--- drivers/clocksource/exynos_mct.c | 4 ++-- drivers/clocksource/metag_generic.c | 6 +++--- drivers/clocksource/time-armada-370-xp.c | 4 ++-- drivers/clocksource/timer-marco.c | 4 ++-- drivers/irqchip/irq-gic.c | 8 ++++---- 8 files changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 053d846ab5b..ffadd836e0b 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -123,7 +123,7 @@ static int arch_timer_set_next_event_phys(unsigned long evt, return 0; } -static int __cpuinit arch_timer_setup(struct clock_event_device *clk) +static int arch_timer_setup(struct clock_event_device *clk) { clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP; clk->name = "arch_sys_timer"; @@ -221,7 +221,7 @@ struct timecounter *arch_timer_get_timecounter(void) return &timecounter; } -static void __cpuinit arch_timer_stop(struct clock_event_device *clk) +static void arch_timer_stop(struct clock_event_device *clk) { pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n", clk->irq, smp_processor_id()); @@ -237,7 +237,7 @@ static void __cpuinit arch_timer_stop(struct clock_event_device *clk) clk->set_mode(CLOCK_EVT_MODE_UNUSED, clk); } -static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self, +static int arch_timer_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { /* @@ -256,7 +256,7 @@ static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self, return NOTIFY_OK; } -static struct notifier_block arch_timer_cpu_nb __cpuinitdata = { +static struct notifier_block arch_timer_cpu_nb = { .notifier_call = arch_timer_cpu_notify, }; diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c index db8afc7427a..b66c1f36066 100644 --- a/drivers/clocksource/arm_global_timer.c +++ b/drivers/clocksource/arm_global_timer.c @@ -164,7 +164,7 @@ static irqreturn_t gt_clockevent_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __cpuinit gt_clockevents_init(struct clock_event_device *clk) +static int gt_clockevents_init(struct clock_event_device *clk) { int cpu = smp_processor_id(); @@ -221,8 +221,8 @@ static void __init gt_clocksource_init(void) clocksource_register_hz(>_clocksource, gt_clk_rate); } -static int __cpuinit gt_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) +static int gt_cpu_notify(struct notifier_block *self, unsigned long action, + void *hcpu) { switch (action & ~CPU_TASKS_FROZEN) { case CPU_STARTING: @@ -235,7 +235,7 @@ static int __cpuinit gt_cpu_notify(struct notifier_block *self, return NOTIFY_OK; } -static struct notifier_block gt_cpu_nb __cpuinitdata = { +static struct notifier_block gt_cpu_nb = { .notifier_call = gt_cpu_notify, }; diff --git a/drivers/clocksource/dummy_timer.c b/drivers/clocksource/dummy_timer.c index 1f55f962033..b3eb582d6a6 100644 --- a/drivers/clocksource/dummy_timer.c +++ b/drivers/clocksource/dummy_timer.c @@ -25,7 +25,7 @@ static void dummy_timer_set_mode(enum clock_event_mode mode, */ } -static void __cpuinit dummy_timer_setup(void) +static void dummy_timer_setup(void) { int cpu = smp_processor_id(); struct clock_event_device *evt = __this_cpu_ptr(&dummy_timer_evt); @@ -41,7 +41,7 @@ static void __cpuinit dummy_timer_setup(void) clockevents_register_device(evt); } -static int __cpuinit dummy_timer_cpu_notify(struct notifier_block *self, +static int dummy_timer_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING) @@ -50,7 +50,7 @@ static int __cpuinit dummy_timer_cpu_notify(struct notifier_block *self, return NOTIFY_OK; } -static struct notifier_block dummy_timer_cpu_nb __cpuinitdata = { +static struct notifier_block dummy_timer_cpu_nb = { .notifier_call = dummy_timer_cpu_notify, }; diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index a70480409ea..b2bbc415f12 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -400,7 +400,7 @@ static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt) +static int exynos4_local_timer_setup(struct clock_event_device *evt) { struct mct_clock_event_device *mevt; unsigned int cpu = smp_processor_id(); @@ -448,7 +448,7 @@ static void exynos4_local_timer_stop(struct clock_event_device *evt) disable_percpu_irq(mct_irqs[MCT_L0_IRQ]); } -static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = { +static struct local_timer_ops exynos4_mct_tick_ops = { .setup = exynos4_local_timer_setup, .stop = exynos4_local_timer_stop, }; diff --git a/drivers/clocksource/metag_generic.c b/drivers/clocksource/metag_generic.c index 6722f0e2fe4..9e4db41abe3 100644 --- a/drivers/clocksource/metag_generic.c +++ b/drivers/clocksource/metag_generic.c @@ -109,7 +109,7 @@ unsigned long long sched_clock(void) return ticks << HARDWARE_TO_NS_SHIFT; } -static void __cpuinit arch_timer_setup(unsigned int cpu) +static void arch_timer_setup(unsigned int cpu) { unsigned int txdivtime; struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); @@ -154,7 +154,7 @@ static void __cpuinit arch_timer_setup(unsigned int cpu) } } -static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self, +static int arch_timer_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { int cpu = (long)hcpu; @@ -169,7 +169,7 @@ static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self, return NOTIFY_OK; } -static struct notifier_block __cpuinitdata arch_timer_cpu_nb = { +static struct notifier_block arch_timer_cpu_nb = { .notifier_call = arch_timer_cpu_notify, }; diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index efdca3263af..1b04b7e1d39 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -167,7 +167,7 @@ static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) /* * Setup the local clock events for a CPU. */ -static int __cpuinit armada_370_xp_timer_setup(struct clock_event_device *evt) +static int armada_370_xp_timer_setup(struct clock_event_device *evt) { u32 u; int cpu = smp_processor_id(); @@ -205,7 +205,7 @@ static void armada_370_xp_timer_stop(struct clock_event_device *evt) disable_percpu_irq(evt->irq); } -static struct local_timer_ops armada_370_xp_local_timer_ops __cpuinitdata = { +static struct local_timer_ops armada_370_xp_local_timer_ops = { .setup = armada_370_xp_timer_setup, .stop = armada_370_xp_timer_stop, }; diff --git a/drivers/clocksource/timer-marco.c b/drivers/clocksource/timer-marco.c index e5dc9129ca2..62876baa3ab 100644 --- a/drivers/clocksource/timer-marco.c +++ b/drivers/clocksource/timer-marco.c @@ -184,7 +184,7 @@ static struct irqaction sirfsoc_timer1_irq = { .handler = sirfsoc_timer_interrupt, }; -static int __cpuinit sirfsoc_local_timer_setup(struct clock_event_device *ce) +static int sirfsoc_local_timer_setup(struct clock_event_device *ce) { /* Use existing clock_event for cpu 0 */ if (!smp_processor_id()) @@ -216,7 +216,7 @@ static void sirfsoc_local_timer_stop(struct clock_event_device *ce) remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq); } -static struct local_timer_ops sirfsoc_local_timer_ops __cpuinitdata = { +static struct local_timer_ops sirfsoc_local_timer_ops = { .setup = sirfsoc_local_timer_setup, .stop = sirfsoc_local_timer_stop, }; diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 19ceaa60e0f..ee7c5031206 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -414,7 +414,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic) writel_relaxed(1, base + GIC_DIST_CTRL); } -static void __cpuinit gic_cpu_init(struct gic_chip_data *gic) +static void gic_cpu_init(struct gic_chip_data *gic) { void __iomem *dist_base = gic_data_dist_base(gic); void __iomem *base = gic_data_cpu_base(gic); @@ -702,8 +702,8 @@ static int gic_irq_domain_xlate(struct irq_domain *d, } #ifdef CONFIG_SMP -static int __cpuinit gic_secondary_init(struct notifier_block *nfb, - unsigned long action, void *hcpu) +static int gic_secondary_init(struct notifier_block *nfb, unsigned long action, + void *hcpu) { if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) gic_cpu_init(&gic_data[0]); @@ -714,7 +714,7 @@ static int __cpuinit gic_secondary_init(struct notifier_block *nfb, * Notifier for enabling the GIC CPU interface. Set an arbitrarily high * priority because the GIC needs to be up before the ARM generic timers. */ -static struct notifier_block __cpuinitdata gic_cpu_notifier = { +static struct notifier_block gic_cpu_notifier = { .notifier_call = gic_secondary_init, .priority = 100, }; -- cgit v1.2.3-70-g09d2 From 19b0a1e5ac5a7f1dafd5ee2479a5db72b330246b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 17 Jul 2013 19:39:19 -0700 Subject: clocksource: orion: Use linux/sched_clock.h The sched_clock.h include is under include/linux now. Cc: Sebastian Hesselbarth Signed-off-by: Stephen Boyd Signed-off-by: John Stultz --- drivers/clocksource/time-orion.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c index ecbeb681021..9c7f018a67c 100644 --- a/drivers/clocksource/time-orion.c +++ b/drivers/clocksource/time-orion.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #define TIMER_CTRL 0x00 #define TIMER0_EN BIT(0) -- cgit v1.2.3-70-g09d2 From 40777645eb7fe5b9184b339e1a8aa889993f6d75 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 16 Jul 2013 16:45:37 +0200 Subject: clocksource: sun4i: Use the BIT macros where possible Signed-off-by: Maxime Ripard Signed-off-by: Daniel Lezcano --- drivers/clocksource/sun4i_timer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index d4674e78ef3..bdf34d9910c 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -24,12 +24,12 @@ #include #define TIMER_IRQ_EN_REG 0x00 -#define TIMER_IRQ_EN(val) (1 << val) +#define TIMER_IRQ_EN(val) BIT(val) #define TIMER_IRQ_ST_REG 0x04 #define TIMER_CTL_REG(val) (0x10 * val + 0x10) -#define TIMER_CTL_ENABLE (1 << 0) -#define TIMER_CTL_AUTORELOAD (1 << 1) -#define TIMER_CTL_ONESHOT (1 << 7) +#define TIMER_CTL_ENABLE BIT(0) +#define TIMER_CTL_AUTORELOAD BIT(1) +#define TIMER_CTL_ONESHOT BIT(7) #define TIMER_INTVAL_REG(val) (0x10 * val + 0x14) #define TIMER_CNTVAL_REG(val) (0x10 * val + 0x18) -- cgit v1.2.3-70-g09d2 From bb008b9e873f5544120dcd401316b4c0e7743dde Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 16 Jul 2013 16:45:37 +0200 Subject: clocksource: sun4i: Wrap macros arguments in parenthesis The macros were not using parenthesis to escape the arguments passed to them. It is pretty unsafe, so add those parenthesis. Signed-off-by: Maxime Ripard Signed-off-by: Daniel Lezcano --- drivers/clocksource/sun4i_timer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index bdf34d9910c..34ab6580ad1 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -30,8 +30,8 @@ #define TIMER_CTL_ENABLE BIT(0) #define TIMER_CTL_AUTORELOAD BIT(1) #define TIMER_CTL_ONESHOT BIT(7) -#define TIMER_INTVAL_REG(val) (0x10 * val + 0x14) -#define TIMER_CNTVAL_REG(val) (0x10 * val + 0x18) +#define TIMER_INTVAL_REG(val) (0x10 * (val) + 0x14) +#define TIMER_CNTVAL_REG(val) (0x10 * (val) + 0x18) #define TIMER_SCAL 16 -- cgit v1.2.3-70-g09d2 From 9eded23215e99338155c18f6d860859106568bb0 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 16 Jul 2013 16:45:37 +0200 Subject: clocksource: sun4i: rename AUTORELOAD define to RELOAD The name AUTORELOAD was actually pretty bad since it doesn't make the register reload the previous interval when it expires, but setting this value pushes the new programmed interval to the internal timer counter. Rename it to RELOAD instead. Signed-off-by: Maxime Ripard Signed-off-by: Daniel Lezcano --- drivers/clocksource/sun4i_timer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index 34ab6580ad1..f5e227b06ad 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -28,7 +28,7 @@ #define TIMER_IRQ_ST_REG 0x04 #define TIMER_CTL_REG(val) (0x10 * val + 0x10) #define TIMER_CTL_ENABLE BIT(0) -#define TIMER_CTL_AUTORELOAD BIT(1) +#define TIMER_CTL_RELOAD BIT(1) #define TIMER_CTL_ONESHOT BIT(7) #define TIMER_INTVAL_REG(val) (0x10 * (val) + 0x14) #define TIMER_CNTVAL_REG(val) (0x10 * (val) + 0x18) @@ -129,7 +129,7 @@ static void __init sun4i_timer_init(struct device_node *node) /* set mode to auto reload */ val = readl(timer_base + TIMER_CTL_REG(0)); - writel(val | TIMER_CTL_AUTORELOAD, timer_base + TIMER_CTL_REG(0)); + writel(val | TIMER_CTL_RELOAD, timer_base + TIMER_CTL_REG(0)); ret = setup_irq(irq, &sun4i_timer_irq); if (ret) -- cgit v1.2.3-70-g09d2 From 137c6b3c7c63944a9cb51de0870b72f62d240f62 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 16 Jul 2013 16:45:37 +0200 Subject: clocksource: sun4i: Add clocksource and sched clock drivers Use the second timer found on the Allwinner SoCs as a clock source and sched clock, that were both not used yet on these platforms. Signed-off-by: Maxime Ripard Signed-off-by: Daniel Lezcano --- drivers/clocksource/sun4i_timer.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index f5e227b06ad..b581c93f20b 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -96,6 +97,11 @@ static struct irqaction sun4i_timer_irq = { .dev_id = &sun4i_clockevent, }; +static u32 sun4i_timer_sched_read(void) +{ + return ~readl(timer_base + TIMER_CNTVAL_REG(1)); +} + static void __init sun4i_timer_init(struct device_node *node) { unsigned long rate = 0; @@ -117,6 +123,15 @@ static void __init sun4i_timer_init(struct device_node *node) rate = clk_get_rate(clk); + writel(~0, timer_base + TIMER_INTVAL_REG(1)); + writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD | + TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M), + timer_base + TIMER_CTL_REG(1)); + + setup_sched_clock(sun4i_timer_sched_read, 32, rate); + clocksource_mmio_init(timer_base + TIMER_CNTVAL_REG(1), node->name, + rate, 300, 32, clocksource_mmio_readl_down); + writel(rate / (TIMER_SCAL * HZ), timer_base + TIMER_INTVAL_REG(0)); -- cgit v1.2.3-70-g09d2 From 8c31bec28b69a86aa83f072e6e00225380853a9e Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 16 Jul 2013 16:45:38 +0200 Subject: clocksource: sun4i: Don't forget to enable the clock we use Even if in our case, this clock was non-gatable, used as a parent clock for several IPs, it still is a good idea to enable it. Signed-off-by: Maxime Ripard Signed-off-by: Daniel Lezcano --- drivers/clocksource/sun4i_timer.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index b581c93f20b..8e9c6513645 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -120,6 +120,7 @@ static void __init sun4i_timer_init(struct device_node *node) clk = of_clk_get(node, 0); if (IS_ERR(clk)) panic("Can't get timer clock"); + clk_prepare_enable(clk); rate = clk_get_rate(clk); -- cgit v1.2.3-70-g09d2 From 63d88f1ac71173e47c40ea116e4489f71c6ed9c7 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 16 Jul 2013 16:45:38 +0200 Subject: clocksource: sun4i: Fix the next event code The next_event logic was setting the next interval to fire in the current timer value instead of the interval value register, which is obviously wrong. Plus, the logic to set the actual value was wrong as well: the interval register can only be modified when the timer is disabled, and then enable it back, otherwise, it'll have no effect. Fix this logic as well since that code couldn't possibly work. Signed-off-by: Maxime Ripard Signed-off-by: Daniel Lezcano --- drivers/clocksource/sun4i_timer.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index 8e9c6513645..7123f654ce7 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -38,6 +38,20 @@ static void __iomem *timer_base; +/* + * When we disable a timer, we need to wait at least for 2 cycles of + * the timer source clock. We will use for that the clocksource timer + * that is already setup and runs at the same frequency than the other + * timers, and we never will be disabled. + */ +static void sun4i_clkevt_sync(void) +{ + u32 old = readl(timer_base + TIMER_CNTVAL_REG(1)); + + while ((old - readl(timer_base + TIMER_CNTVAL_REG(1))) < 3) + cpu_relax(); +} + static void sun4i_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *clk) { @@ -63,9 +77,14 @@ static void sun4i_clkevt_mode(enum clock_event_mode mode, static int sun4i_clkevt_next_event(unsigned long evt, struct clock_event_device *unused) { - u32 u = readl(timer_base + TIMER_CTL_REG(0)); - writel(evt, timer_base + TIMER_CNTVAL_REG(0)); - writel(u | TIMER_CTL_ENABLE | TIMER_CTL_AUTORELOAD, + u32 val = readl(timer_base + TIMER_CTL_REG(0)); + writel(val & ~TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(0)); + sun4i_clkevt_sync(); + + writel(evt, timer_base + TIMER_INTVAL_REG(0)); + + val = readl(timer_base + TIMER_CTL_REG(0)); + writel(val | TIMER_CTL_ENABLE | TIMER_CTL_AUTORELOAD, timer_base + TIMER_CTL_REG(0)); return 0; -- cgit v1.2.3-70-g09d2 From 96651a0732d148f7e4a59cec6aa174049866cd0e Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 16 Jul 2013 16:45:38 +0200 Subject: clocksource: sun4i: Factor out some timer code The set_next_event and set_mode callbacks share a lot of common code we can easily factor to avoid duplication and mistakes. Signed-off-by: Maxime Ripard Signed-off-by: Daniel Lezcano --- drivers/clocksource/sun4i_timer.c | 48 ++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 16 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index 7123f654ce7..dd78b63f3a2 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -52,24 +52,46 @@ static void sun4i_clkevt_sync(void) cpu_relax(); } +static void sun4i_clkevt_time_stop(u8 timer) +{ + u32 val = readl(timer_base + TIMER_CTL_REG(timer)); + writel(val & ~TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(timer)); + sun4i_clkevt_sync(); +} + +static void sun4i_clkevt_time_setup(u8 timer, unsigned long delay) +{ + writel(delay, timer_base + TIMER_INTVAL_REG(timer)); +} + +static void sun4i_clkevt_time_start(u8 timer, bool periodic) +{ + u32 val = readl(timer_base + TIMER_CTL_REG(timer)); + + if (periodic) + val &= ~TIMER_CTL_ONESHOT; + else + val |= TIMER_CTL_ONESHOT; + + writel(val | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(timer)); +} + static void sun4i_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *clk) { - u32 u = readl(timer_base + TIMER_CTL_REG(0)); - switch (mode) { case CLOCK_EVT_MODE_PERIODIC: - u &= ~(TIMER_CTL_ONESHOT); - writel(u | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(0)); + sun4i_clkevt_time_stop(0); + sun4i_clkevt_time_start(0, true); break; - case CLOCK_EVT_MODE_ONESHOT: - writel(u | TIMER_CTL_ONESHOT, timer_base + TIMER_CTL_REG(0)); + sun4i_clkevt_time_stop(0); + sun4i_clkevt_time_start(0, false); break; case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_SHUTDOWN: default: - writel(u & ~(TIMER_CTL_ENABLE), timer_base + TIMER_CTL_REG(0)); + sun4i_clkevt_time_stop(0); break; } } @@ -77,15 +99,9 @@ static void sun4i_clkevt_mode(enum clock_event_mode mode, static int sun4i_clkevt_next_event(unsigned long evt, struct clock_event_device *unused) { - u32 val = readl(timer_base + TIMER_CTL_REG(0)); - writel(val & ~TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(0)); - sun4i_clkevt_sync(); - - writel(evt, timer_base + TIMER_INTVAL_REG(0)); - - val = readl(timer_base + TIMER_CTL_REG(0)); - writel(val | TIMER_CTL_ENABLE | TIMER_CTL_AUTORELOAD, - timer_base + TIMER_CTL_REG(0)); + sun4i_clkevt_time_stop(0); + sun4i_clkevt_time_setup(0, evt); + sun4i_clkevt_time_start(0, false); return 0; } -- cgit v1.2.3-70-g09d2 From c2b852f77b0d4c71967b61848d666c7a25e17627 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 16 Jul 2013 16:45:38 +0200 Subject: clocksource: sun4i: Remove TIMER_SCAL variable The prescaler is only used when using the internal low frequency oscillator (at 32kHz). Since we're using the higher frequency oscillator at 24MHz, we can just remove it. Signed-off-by: Maxime Ripard Signed-off-by: Daniel Lezcano --- drivers/clocksource/sun4i_timer.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index dd78b63f3a2..3217adc7457 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -34,8 +34,6 @@ #define TIMER_INTVAL_REG(val) (0x10 * (val) + 0x14) #define TIMER_CNTVAL_REG(val) (0x10 * (val) + 0x18) -#define TIMER_SCAL 16 - static void __iomem *timer_base; /* @@ -168,8 +166,7 @@ static void __init sun4i_timer_init(struct device_node *node) clocksource_mmio_init(timer_base + TIMER_CNTVAL_REG(1), node->name, rate, 300, 32, clocksource_mmio_readl_down); - writel(rate / (TIMER_SCAL * HZ), - timer_base + TIMER_INTVAL_REG(0)); + writel(rate / HZ, timer_base + TIMER_INTVAL_REG(0)); /* set clock source to HOSC, 16 pre-division */ val = readl(timer_base + TIMER_CTL_REG(0)); @@ -192,8 +189,8 @@ static void __init sun4i_timer_init(struct device_node *node) sun4i_clockevent.cpumask = cpumask_of(0); - clockevents_config_and_register(&sun4i_clockevent, rate / TIMER_SCAL, - 0x1, 0xff); + clockevents_config_and_register(&sun4i_clockevent, rate, 0x1, + 0xffffffff); } CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-timer", sun4i_timer_init); -- cgit v1.2.3-70-g09d2 From a2c49e7b553a28f10ab34e5da538ed4a45a697a7 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 16 Jul 2013 16:45:38 +0200 Subject: clocksource: sun4i: Cleanup parent clock setup The current bring-up code for the timer was overly complicated. The only thing we need is actually which clock we want to use as source and that's pretty much all. Let's keep it that way. Signed-off-by: Maxime Ripard Signed-off-by: Daniel Lezcano --- drivers/clocksource/sun4i_timer.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index 3217adc7457..2fadb3ba59d 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -30,6 +30,9 @@ #define TIMER_CTL_REG(val) (0x10 * val + 0x10) #define TIMER_CTL_ENABLE BIT(0) #define TIMER_CTL_RELOAD BIT(1) +#define TIMER_CTL_CLK_SRC(val) (((val) & 0x3) << 2) +#define TIMER_CTL_CLK_SRC_OSC24M (1) +#define TIMER_CTL_CLK_PRES(val) (((val) & 0x7) << 4) #define TIMER_CTL_ONESHOT BIT(7) #define TIMER_INTVAL_REG(val) (0x10 * (val) + 0x14) #define TIMER_CNTVAL_REG(val) (0x10 * (val) + 0x18) @@ -168,16 +171,8 @@ static void __init sun4i_timer_init(struct device_node *node) writel(rate / HZ, timer_base + TIMER_INTVAL_REG(0)); - /* set clock source to HOSC, 16 pre-division */ - val = readl(timer_base + TIMER_CTL_REG(0)); - val &= ~(0x07 << 4); - val &= ~(0x03 << 2); - val |= (4 << 4) | (1 << 2); - writel(val, timer_base + TIMER_CTL_REG(0)); - - /* set mode to auto reload */ - val = readl(timer_base + TIMER_CTL_REG(0)); - writel(val | TIMER_CTL_RELOAD, timer_base + TIMER_CTL_REG(0)); + writel(TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M) | TIMER_CTL_RELOAD, + timer_base + TIMER_CTL_REG(0)); ret = setup_irq(irq, &sun4i_timer_irq); if (ret) -- cgit v1.2.3-70-g09d2 From 7e14183469d8aa2c7aa7675a6156e7846dda7748 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 16 Jul 2013 16:45:38 +0200 Subject: clocksource: sun4i: Fix bug when switching from periodic to oneshot modes The interval was firing at was set up at probe time, and only changed in the set_next_event, and never changed back, which is not really what is expected. When enabling the periodic mode, now set an interval to tick every jiffy. Signed-off-by: Maxime Ripard Signed-off-by: Daniel Lezcano --- drivers/clocksource/sun4i_timer.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index 2fadb3ba59d..8ead0258740 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -38,6 +38,7 @@ #define TIMER_CNTVAL_REG(val) (0x10 * (val) + 0x18) static void __iomem *timer_base; +static u32 ticks_per_jiffy; /* * When we disable a timer, we need to wait at least for 2 cycles of @@ -74,7 +75,8 @@ static void sun4i_clkevt_time_start(u8 timer, bool periodic) else val |= TIMER_CTL_ONESHOT; - writel(val | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(timer)); + writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, + timer_base + TIMER_CTL_REG(timer)); } static void sun4i_clkevt_mode(enum clock_event_mode mode, @@ -83,6 +85,7 @@ static void sun4i_clkevt_mode(enum clock_event_mode mode, switch (mode) { case CLOCK_EVT_MODE_PERIODIC: sun4i_clkevt_time_stop(0); + sun4i_clkevt_time_setup(0, ticks_per_jiffy); sun4i_clkevt_time_start(0, true); break; case CLOCK_EVT_MODE_ONESHOT: @@ -169,9 +172,9 @@ static void __init sun4i_timer_init(struct device_node *node) clocksource_mmio_init(timer_base + TIMER_CNTVAL_REG(1), node->name, rate, 300, 32, clocksource_mmio_readl_down); - writel(rate / HZ, timer_base + TIMER_INTVAL_REG(0)); + ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); - writel(TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M) | TIMER_CTL_RELOAD, + writel(TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M), timer_base + TIMER_CTL_REG(0)); ret = setup_irq(irq, &sun4i_timer_irq); -- cgit v1.2.3-70-g09d2 From 9bbf914043e04f65e619f3c0ff67c387812f9458 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Mon, 8 Jul 2013 09:51:37 -0700 Subject: clocksource: cadence_ttc: Remove unused header The clk-provider.h header is not required by this driver. Signed-off-by: Soren Brinkmann Signed-off-by: Daniel Lezcano --- drivers/clocksource/cadence_ttc_timer.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c index 4cbe28c7463..0eefc8d8622 100644 --- a/drivers/clocksource/cadence_ttc_timer.c +++ b/drivers/clocksource/cadence_ttc_timer.c @@ -21,7 +21,6 @@ #include #include #include -#include /* * This driver configures the 2 16-bit count-up timers as follows: -- cgit v1.2.3-70-g09d2 From 3d77b30efc72d126c2b74070b41a03869611228d Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Mon, 8 Jul 2013 09:51:38 -0700 Subject: clocksource: cadence_ttc: Reuse clocksource as sched_clock Reuse the TTC clocksource timer as sched clock provider. Signed-off-by: Soren Brinkmann Signed-off-by: Daniel Lezcano Acked-by: Michal Simek --- drivers/clocksource/cadence_ttc_timer.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c index 0eefc8d8622..b2bb3a4bc20 100644 --- a/drivers/clocksource/cadence_ttc_timer.c +++ b/drivers/clocksource/cadence_ttc_timer.c @@ -21,6 +21,7 @@ #include #include #include +#include /* * This driver configures the 2 16-bit count-up timers as follows: @@ -94,6 +95,8 @@ struct ttc_timer_clockevent { #define to_ttc_timer_clkevent(x) \ container_of(x, struct ttc_timer_clockevent, ce) +static void __iomem *ttc_sched_clock_val_reg; + /** * ttc_set_interval - Set the timer interval value * @@ -155,6 +158,11 @@ static cycle_t __ttc_clocksource_read(struct clocksource *cs) TTC_COUNT_VAL_OFFSET); } +static u32 notrace ttc_sched_clock_read(void) +{ + return __raw_readl(ttc_sched_clock_val_reg); +} + /** * ttc_set_next_event - Sets the time interval for next event * @@ -296,6 +304,10 @@ static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base) kfree(ttccs); return; } + + ttc_sched_clock_val_reg = base + TTC_COUNT_VAL_OFFSET; + setup_sched_clock(ttc_sched_clock_read, 16, + clk_get_rate(ttccs->ttc.clk) / PRESCALE); } static int ttc_rate_change_clockevent_cb(struct notifier_block *nb, -- cgit v1.2.3-70-g09d2 From 07862c1cd6675cde2dd4bd64e64d704ea2185b79 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 17 Jul 2013 10:04:57 +0200 Subject: ARM: clocksource: Add support for MOXA ART SoCs This patch adds an clocksource driver for the main timer(s) found on MOXA ART SoCs. The MOXA ART SoC provides three separate timers with individual count/load/match registers, two are used here: TIMER1: clockevents, used to support oneshot and periodic events TIMER2: set up as a free running counter, used as clocksource Timers are preconfigured by bootloader to count down and interrupt on match or zero. Count increments every APB clock cycle and is automatically reloaded when it reaches zero. Signed-off-by: Jonas Jensen Signed-off-by: Daniel Lezcano --- .../bindings/timer/moxa,moxart-timer.txt | 17 +++ drivers/clocksource/Makefile | 1 + drivers/clocksource/moxart_timer.c | 164 +++++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 Documentation/devicetree/bindings/timer/moxa,moxart-timer.txt create mode 100644 drivers/clocksource/moxart_timer.c (limited to 'drivers/clocksource') diff --git a/Documentation/devicetree/bindings/timer/moxa,moxart-timer.txt b/Documentation/devicetree/bindings/timer/moxa,moxart-timer.txt new file mode 100644 index 00000000000..77c4cfa198e --- /dev/null +++ b/Documentation/devicetree/bindings/timer/moxa,moxart-timer.txt @@ -0,0 +1,17 @@ +MOXA ART timer + +Required properties: + +- compatible : Should be "moxa,moxart-timer" +- reg : Should contain registers location and length +- interrupts : Should contain the timer interrupt number +- clocks : Should contain phandle for APB clock "clkapb" + +Example: + + timer: timer@98400000 { + compatible = "moxa,moxart-timer"; + reg = <0x98400000 0x42>; + interrupts = <19 1>; + clocks = <&clkapb>; + }; diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 8b00c5cebfa..704d6d342ad 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o obj-$(CONFIG_ORION_TIMER) += time-orion.o obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o obj-$(CONFIG_ARCH_MARCO) += timer-marco.o +obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o obj-$(CONFIG_ARCH_MXS) += mxs_timer.o obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o diff --git a/drivers/clocksource/moxart_timer.c b/drivers/clocksource/moxart_timer.c new file mode 100644 index 00000000000..08a5943b3e4 --- /dev/null +++ b/drivers/clocksource/moxart_timer.c @@ -0,0 +1,164 @@ +/* + * MOXA ART SoCs timer handling. + * + * Copyright (C) 2013 Jonas Jensen + * + * Jonas Jensen + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TIMER1_BASE 0x00 +#define TIMER2_BASE 0x10 +#define TIMER3_BASE 0x20 + +#define REG_COUNT 0x0 /* writable */ +#define REG_LOAD 0x4 +#define REG_MATCH1 0x8 +#define REG_MATCH2 0xC + +#define TIMER_CR 0x30 +#define TIMER_INTR_STATE 0x34 +#define TIMER_INTR_MASK 0x38 + +/* + * TIMER_CR flags: + * + * TIMEREG_CR_*_CLOCK 0: PCLK, 1: EXT1CLK + * TIMEREG_CR_*_INT overflow interrupt enable bit + */ +#define TIMEREG_CR_1_ENABLE BIT(0) +#define TIMEREG_CR_1_CLOCK BIT(1) +#define TIMEREG_CR_1_INT BIT(2) +#define TIMEREG_CR_2_ENABLE BIT(3) +#define TIMEREG_CR_2_CLOCK BIT(4) +#define TIMEREG_CR_2_INT BIT(5) +#define TIMEREG_CR_3_ENABLE BIT(6) +#define TIMEREG_CR_3_CLOCK BIT(7) +#define TIMEREG_CR_3_INT BIT(8) +#define TIMEREG_CR_COUNT_UP BIT(9) + +#define TIMER1_ENABLE (TIMEREG_CR_2_ENABLE | TIMEREG_CR_1_ENABLE) +#define TIMER1_DISABLE (TIMEREG_CR_2_ENABLE) + +static void __iomem *base; +static unsigned int clock_count_per_tick; + +static void moxart_clkevt_mode(enum clock_event_mode mode, + struct clock_event_device *clk) +{ + switch (mode) { + case CLOCK_EVT_MODE_RESUME: + case CLOCK_EVT_MODE_ONESHOT: + writel(TIMER1_DISABLE, base + TIMER_CR); + writel(~0, base + TIMER1_BASE + REG_LOAD); + break; + case CLOCK_EVT_MODE_PERIODIC: + writel(clock_count_per_tick, base + TIMER1_BASE + REG_LOAD); + writel(TIMER1_ENABLE, base + TIMER_CR); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + writel(TIMER1_DISABLE, base + TIMER_CR); + break; + } +} + +static int moxart_clkevt_next_event(unsigned long cycles, + struct clock_event_device *unused) +{ + u32 u; + + writel(TIMER1_DISABLE, base + TIMER_CR); + + u = readl(base + TIMER1_BASE + REG_COUNT) - cycles; + writel(u, base + TIMER1_BASE + REG_MATCH1); + + writel(TIMER1_ENABLE, base + TIMER_CR); + + return 0; +} + +static struct clock_event_device moxart_clockevent = { + .name = "moxart_timer", + .rating = 200, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = moxart_clkevt_mode, + .set_next_event = moxart_clkevt_next_event, +}; + +static irqreturn_t moxart_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + evt->event_handler(evt); + return IRQ_HANDLED; +} + +static struct irqaction moxart_timer_irq = { + .name = "moxart-timer", + .flags = IRQF_TIMER, + .handler = moxart_timer_interrupt, + .dev_id = &moxart_clockevent, +}; + +static void __init moxart_timer_init(struct device_node *node) +{ + int ret, irq; + unsigned long pclk; + struct clk *clk; + + base = of_iomap(node, 0); + if (!base) + panic("%s: of_iomap failed\n", node->full_name); + + irq = irq_of_parse_and_map(node, 0); + if (irq <= 0) + panic("%s: irq_of_parse_and_map failed\n", node->full_name); + + ret = setup_irq(irq, &moxart_timer_irq); + if (ret) + panic("%s: setup_irq failed\n", node->full_name); + + clk = of_clk_get(node, 0); + if (IS_ERR(clk)) + panic("%s: of_clk_get failed\n", node->full_name); + + pclk = clk_get_rate(clk); + + if (clocksource_mmio_init(base + TIMER2_BASE + REG_COUNT, + "moxart_timer", pclk, 200, 32, + clocksource_mmio_readl_down)) + panic("%s: clocksource_mmio_init failed\n", node->full_name); + + clock_count_per_tick = DIV_ROUND_CLOSEST(pclk, HZ); + + writel(~0, base + TIMER2_BASE + REG_LOAD); + writel(TIMEREG_CR_2_ENABLE, base + TIMER_CR); + + moxart_clockevent.cpumask = cpumask_of(0); + moxart_clockevent.irq = irq; + + /* + * documentation is not publicly available: + * min_delta / max_delta obtained by trial-and-error, + * max_delta 0xfffffffe should be ok because count + * register size is u32 + */ + clockevents_config_and_register(&moxart_clockevent, pclk, + 0x4, 0xfffffffe); +} +CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", moxart_timer_init); -- cgit v1.2.3-70-g09d2 From adf157ebf6097aa2abc7f05120e7dda6ed238252 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Fri, 26 Jul 2013 16:03:38 +0200 Subject: ARM: clocksource: moxart: Add bitops.h include bitops.h included implicitly, add #include Signed-off-by: Jonas Jensen Signed-off-by: Daniel Lezcano --- drivers/clocksource/moxart_timer.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/moxart_timer.c b/drivers/clocksource/moxart_timer.c index 08a5943b3e4..5eb2c35932b 100644 --- a/drivers/clocksource/moxart_timer.c +++ b/drivers/clocksource/moxart_timer.c @@ -20,6 +20,7 @@ #include #include #include +#include #define TIMER1_BASE 0x00 #define TIMER2_BASE 0x10 -- cgit v1.2.3-70-g09d2 From e09f3cc0184d6b5c3816f921b7ffb67623e5e834 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 18 Jul 2013 16:59:28 -0700 Subject: clocksource: arch_timer: Make register accessors less error-prone Using an enum for the register we wish to access allows newer compilers to determine if we've forgotten a case in our switch statement. This allows us to remove the BUILD_BUG() instances in the arm64 port, avoiding problems where optimizations may not happen. To try and force better code generation we're currently marking the accessor functions as inline, but newer compilers can ignore the inline keyword unless it's marked __always_inline. Luckily on arm and arm64 inline is __always_inline, but let's make everything __always_inline to be explicit. Suggested-by: Thomas Gleixner Cc: Thomas Gleixner Cc: Mark Rutland Cc: Marc Zyngier Signed-off-by: Stephen Boyd Signed-off-by: Daniel Lezcano Acked-by: Mark Rutland --- arch/arm/include/asm/arch_timer.h | 14 ++++++-------- arch/arm64/include/asm/arch_timer.h | 23 +++++++++-------------- drivers/clocksource/arm_arch_timer.c | 6 +++--- include/clocksource/arm_arch_timer.h | 6 ++++-- 4 files changed, 22 insertions(+), 27 deletions(-) (limited to 'drivers/clocksource') diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h index accefe09918..aeb93f38e9c 100644 --- a/arch/arm/include/asm/arch_timer.h +++ b/arch/arm/include/asm/arch_timer.h @@ -17,7 +17,8 @@ int arch_timer_arch_init(void); * nicely work out which register we want, and chuck away the rest of * the code. At least it does so with a recent GCC (4.6.3). */ -static inline void arch_timer_reg_write(const int access, const int reg, u32 val) +static __always_inline +void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val) { if (access == ARCH_TIMER_PHYS_ACCESS) { switch (reg) { @@ -28,9 +29,7 @@ static inline void arch_timer_reg_write(const int access, const int reg, u32 val asm volatile("mcr p15, 0, %0, c14, c2, 0" : : "r" (val)); break; } - } - - if (access == ARCH_TIMER_VIRT_ACCESS) { + } else if (access == ARCH_TIMER_VIRT_ACCESS) { switch (reg) { case ARCH_TIMER_REG_CTRL: asm volatile("mcr p15, 0, %0, c14, c3, 1" : : "r" (val)); @@ -44,7 +43,8 @@ static inline void arch_timer_reg_write(const int access, const int reg, u32 val isb(); } -static inline u32 arch_timer_reg_read(const int access, const int reg) +static __always_inline +u32 arch_timer_reg_read(int access, enum arch_timer_reg reg) { u32 val = 0; @@ -57,9 +57,7 @@ static inline u32 arch_timer_reg_read(const int access, const int reg) asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val)); break; } - } - - if (access == ARCH_TIMER_VIRT_ACCESS) { + } else if (access == ARCH_TIMER_VIRT_ACCESS) { switch (reg) { case ARCH_TIMER_REG_CTRL: asm volatile("mrc p15, 0, %0, c14, c3, 1" : "=r" (val)); diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h index d56ed11ba9a..dbca77168e8 100644 --- a/arch/arm64/include/asm/arch_timer.h +++ b/arch/arm64/include/asm/arch_timer.h @@ -26,7 +26,13 @@ #include -static inline void arch_timer_reg_write(int access, int reg, u32 val) +/* + * These register accessors are marked inline so the compiler can + * nicely work out which register we want, and chuck away the rest of + * the code. + */ +static __always_inline +void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val) { if (access == ARCH_TIMER_PHYS_ACCESS) { switch (reg) { @@ -36,8 +42,6 @@ static inline void arch_timer_reg_write(int access, int reg, u32 val) case ARCH_TIMER_REG_TVAL: asm volatile("msr cntp_tval_el0, %0" : : "r" (val)); break; - default: - BUILD_BUG(); } } else if (access == ARCH_TIMER_VIRT_ACCESS) { switch (reg) { @@ -47,17 +51,14 @@ static inline void arch_timer_reg_write(int access, int reg, u32 val) case ARCH_TIMER_REG_TVAL: asm volatile("msr cntv_tval_el0, %0" : : "r" (val)); break; - default: - BUILD_BUG(); } - } else { - BUILD_BUG(); } isb(); } -static inline u32 arch_timer_reg_read(int access, int reg) +static __always_inline +u32 arch_timer_reg_read(int access, enum arch_timer_reg reg) { u32 val; @@ -69,8 +70,6 @@ static inline u32 arch_timer_reg_read(int access, int reg) case ARCH_TIMER_REG_TVAL: asm volatile("mrs %0, cntp_tval_el0" : "=r" (val)); break; - default: - BUILD_BUG(); } } else if (access == ARCH_TIMER_VIRT_ACCESS) { switch (reg) { @@ -80,11 +79,7 @@ static inline u32 arch_timer_reg_read(int access, int reg) case ARCH_TIMER_REG_TVAL: asm volatile("mrs %0, cntv_tval_el0" : "=r" (val)); break; - default: - BUILD_BUG(); } - } else { - BUILD_BUG(); } return val; diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 053d846ab5b..aa0703847e5 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -43,7 +43,7 @@ static bool arch_timer_use_virtual = true; * Architected system timer support. */ -static inline irqreturn_t timer_handler(const int access, +static __always_inline irqreturn_t timer_handler(const int access, struct clock_event_device *evt) { unsigned long ctrl; @@ -72,7 +72,7 @@ static irqreturn_t arch_timer_handler_phys(int irq, void *dev_id) return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt); } -static inline void timer_set_mode(const int access, int mode) +static __always_inline void timer_set_mode(const int access, int mode) { unsigned long ctrl; switch (mode) { @@ -99,7 +99,7 @@ static void arch_timer_set_mode_phys(enum clock_event_mode mode, timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode); } -static inline void set_next_event(const int access, unsigned long evt) +static __always_inline void set_next_event(const int access, unsigned long evt) { unsigned long ctrl; ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL); diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h index c463ce990c4..f3da817b9b8 100644 --- a/include/clocksource/arm_arch_timer.h +++ b/include/clocksource/arm_arch_timer.h @@ -23,8 +23,10 @@ #define ARCH_TIMER_CTRL_IT_MASK (1 << 1) #define ARCH_TIMER_CTRL_IT_STAT (1 << 2) -#define ARCH_TIMER_REG_CTRL 0 -#define ARCH_TIMER_REG_TVAL 1 +enum arch_timer_reg { + ARCH_TIMER_REG_CTRL, + ARCH_TIMER_REG_TVAL, +}; #define ARCH_TIMER_PHYS_ACCESS 0 #define ARCH_TIMER_VIRT_ACCESS 1 -- cgit v1.2.3-70-g09d2 From 1ff99ea65687d921cb71f330491ec4205c00eb9f Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 18 Jul 2013 16:59:30 -0700 Subject: clocksource: arch_timer: Pass clock event to set_mode callback There isn't any reason why we don't pass the event here and we'll need it in the near future for memory mapped arch timers anyway. Cc: Mark Rutland Cc: Marc Zyngier Signed-off-by: Stephen Boyd Signed-off-by: Daniel Lezcano Acked-by: Mark Rutland --- drivers/clocksource/arm_arch_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index aa0703847e5..7624ba57414 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -140,7 +140,7 @@ static int __cpuinit arch_timer_setup(struct clock_event_device *clk) clk->cpumask = cpumask_of(smp_processor_id()); - clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, NULL); + clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, clk); clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); -- cgit v1.2.3-70-g09d2 From 60faddf6eb3aba16068032bdcf35e18ace4bfb21 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 18 Jul 2013 16:59:31 -0700 Subject: clocksource: arch_timer: Push the read/write wrappers deeper We're going to introduce support to read and write the memory mapped timer registers in the next patch, so push the cp15 read/write functions one level deeper. This simplifies the next patch and makes it clearer what's going on. Cc: Mark Rutland Cc: Marc Zyngier Signed-off-by: Stephen Boyd Signed-off-by: Daniel Lezcano Acked-by: Mark Rutland --- arch/arm/include/asm/arch_timer.h | 4 ++-- arch/arm64/include/asm/arch_timer.h | 4 ++-- drivers/clocksource/arm_arch_timer.c | 46 ++++++++++++++++++++++++------------ 3 files changed, 35 insertions(+), 19 deletions(-) (limited to 'drivers/clocksource') diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h index aeb93f38e9c..55609468972 100644 --- a/arch/arm/include/asm/arch_timer.h +++ b/arch/arm/include/asm/arch_timer.h @@ -18,7 +18,7 @@ int arch_timer_arch_init(void); * the code. At least it does so with a recent GCC (4.6.3). */ static __always_inline -void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val) +void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val) { if (access == ARCH_TIMER_PHYS_ACCESS) { switch (reg) { @@ -44,7 +44,7 @@ void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val) } static __always_inline -u32 arch_timer_reg_read(int access, enum arch_timer_reg reg) +u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg) { u32 val = 0; diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h index dbca77168e8..7181e777c2c 100644 --- a/arch/arm64/include/asm/arch_timer.h +++ b/arch/arm64/include/asm/arch_timer.h @@ -32,7 +32,7 @@ * the code. */ static __always_inline -void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val) +void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val) { if (access == ARCH_TIMER_PHYS_ACCESS) { switch (reg) { @@ -58,7 +58,7 @@ void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val) } static __always_inline -u32 arch_timer_reg_read(int access, enum arch_timer_reg reg) +u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg) { u32 val; diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 7624ba57414..a9ca28447b4 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -43,14 +43,28 @@ static bool arch_timer_use_virtual = true; * Architected system timer support. */ +static __always_inline +void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val, + struct clock_event_device *clk) +{ + arch_timer_reg_write_cp15(access, reg, val); +} + +static __always_inline +u32 arch_timer_reg_read(int access, enum arch_timer_reg reg, + struct clock_event_device *clk) +{ + return arch_timer_reg_read_cp15(access, reg); +} + static __always_inline irqreturn_t timer_handler(const int access, struct clock_event_device *evt) { unsigned long ctrl; - ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL); + ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, evt); if (ctrl & ARCH_TIMER_CTRL_IT_STAT) { ctrl |= ARCH_TIMER_CTRL_IT_MASK; - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl); + arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, evt); evt->event_handler(evt); return IRQ_HANDLED; } @@ -72,15 +86,16 @@ static irqreturn_t arch_timer_handler_phys(int irq, void *dev_id) return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt); } -static __always_inline void timer_set_mode(const int access, int mode) +static __always_inline void timer_set_mode(const int access, int mode, + struct clock_event_device *clk) { unsigned long ctrl; switch (mode) { case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_SHUTDOWN: - ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL); + ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); ctrl &= ~ARCH_TIMER_CTRL_ENABLE; - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl); + arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); break; default: break; @@ -90,36 +105,37 @@ static __always_inline void timer_set_mode(const int access, int mode) static void arch_timer_set_mode_virt(enum clock_event_mode mode, struct clock_event_device *clk) { - timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode); + timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode, clk); } static void arch_timer_set_mode_phys(enum clock_event_mode mode, struct clock_event_device *clk) { - timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode); + timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode, clk); } -static __always_inline void set_next_event(const int access, unsigned long evt) +static __always_inline void set_next_event(const int access, unsigned long evt, + struct clock_event_device *clk) { unsigned long ctrl; - ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL); + ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); ctrl |= ARCH_TIMER_CTRL_ENABLE; ctrl &= ~ARCH_TIMER_CTRL_IT_MASK; - arch_timer_reg_write(access, ARCH_TIMER_REG_TVAL, evt); - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl); + arch_timer_reg_write(access, ARCH_TIMER_REG_TVAL, evt, clk); + arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); } static int arch_timer_set_next_event_virt(unsigned long evt, - struct clock_event_device *unused) + struct clock_event_device *clk) { - set_next_event(ARCH_TIMER_VIRT_ACCESS, evt); + set_next_event(ARCH_TIMER_VIRT_ACCESS, evt, clk); return 0; } static int arch_timer_set_next_event_phys(unsigned long evt, - struct clock_event_device *unused) + struct clock_event_device *clk) { - set_next_event(ARCH_TIMER_PHYS_ACCESS, evt); + set_next_event(ARCH_TIMER_PHYS_ACCESS, evt, clk); return 0; } -- cgit v1.2.3-70-g09d2 From 220069945b298d3998c6598b081c466dca259929 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 18 Jul 2013 16:59:32 -0700 Subject: clocksource: arch_timer: Add support for memory mapped timers Add support for the memory mapped timers by filling in the read/write functions and adding some parsing code. Note that we only register one clocksource, preferring the cp15 based clocksource over the mmio one. To keep things simple we register one global clockevent. This covers the case of UP and SMP systems with only mmio hardware and systems where the memory mapped timers are used as the broadcast timer in low power modes. The DT binding allows for per-CPU memory mapped timers in case we want to support that in the future, but the code isn't added here. We also don't do much for hypervisor support, although it should be possible to support it by searching for at least two frames where one frame has the virtual capability and then updating KVM timers to support it. Cc: Mark Rutland Cc: Marc Zyngier Cc: Rob Herring Signed-off-by: Stephen Boyd Signed-off-by: Daniel Lezcano Acked-by: Mark Rutland --- drivers/clocksource/arm_arch_timer.c | 402 ++++++++++++++++++++++++++++++----- include/clocksource/arm_arch_timer.h | 4 +- 2 files changed, 350 insertions(+), 56 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index a9ca28447b4..b3df46d9918 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -16,13 +16,39 @@ #include #include #include +#include #include +#include #include #include #include +#define CNTTIDR 0x08 +#define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4)) + +#define CNTVCT_LO 0x08 +#define CNTVCT_HI 0x0c +#define CNTFRQ 0x10 +#define CNTP_TVAL 0x28 +#define CNTP_CTL 0x2c +#define CNTV_TVAL 0x38 +#define CNTV_CTL 0x3c + +#define ARCH_CP15_TIMER BIT(0) +#define ARCH_MEM_TIMER BIT(1) +static unsigned arch_timers_present __initdata; + +static void __iomem *arch_counter_base; + +struct arch_timer { + void __iomem *base; + struct clock_event_device evt; +}; + +#define to_arch_timer(e) container_of(e, struct arch_timer, evt) + static u32 arch_timer_rate; enum ppi_nr { @@ -38,6 +64,7 @@ static int arch_timer_ppi[MAX_TIMER_PPI]; static struct clock_event_device __percpu *arch_timer_evt; static bool arch_timer_use_virtual = true; +static bool arch_timer_mem_use_virtual; /* * Architected system timer support. @@ -47,14 +74,62 @@ static __always_inline void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val, struct clock_event_device *clk) { - arch_timer_reg_write_cp15(access, reg, val); + if (access == ARCH_TIMER_MEM_PHYS_ACCESS) { + struct arch_timer *timer = to_arch_timer(clk); + switch (reg) { + case ARCH_TIMER_REG_CTRL: + writel_relaxed(val, timer->base + CNTP_CTL); + break; + case ARCH_TIMER_REG_TVAL: + writel_relaxed(val, timer->base + CNTP_TVAL); + break; + } + } else if (access == ARCH_TIMER_MEM_VIRT_ACCESS) { + struct arch_timer *timer = to_arch_timer(clk); + switch (reg) { + case ARCH_TIMER_REG_CTRL: + writel_relaxed(val, timer->base + CNTV_CTL); + break; + case ARCH_TIMER_REG_TVAL: + writel_relaxed(val, timer->base + CNTV_TVAL); + break; + } + } else { + arch_timer_reg_write_cp15(access, reg, val); + } } static __always_inline u32 arch_timer_reg_read(int access, enum arch_timer_reg reg, struct clock_event_device *clk) { - return arch_timer_reg_read_cp15(access, reg); + u32 val; + + if (access == ARCH_TIMER_MEM_PHYS_ACCESS) { + struct arch_timer *timer = to_arch_timer(clk); + switch (reg) { + case ARCH_TIMER_REG_CTRL: + val = readl_relaxed(timer->base + CNTP_CTL); + break; + case ARCH_TIMER_REG_TVAL: + val = readl_relaxed(timer->base + CNTP_TVAL); + break; + } + } else if (access == ARCH_TIMER_MEM_VIRT_ACCESS) { + struct arch_timer *timer = to_arch_timer(clk); + switch (reg) { + case ARCH_TIMER_REG_CTRL: + val = readl_relaxed(timer->base + CNTV_CTL); + break; + case ARCH_TIMER_REG_TVAL: + val = readl_relaxed(timer->base + CNTV_TVAL); + break; + } + } else { + val = arch_timer_reg_read_cp15(access, reg); + } + + return val; } static __always_inline irqreturn_t timer_handler(const int access, @@ -86,6 +161,20 @@ static irqreturn_t arch_timer_handler_phys(int irq, void *dev_id) return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt); } +static irqreturn_t arch_timer_handler_phys_mem(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + return timer_handler(ARCH_TIMER_MEM_PHYS_ACCESS, evt); +} + +static irqreturn_t arch_timer_handler_virt_mem(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + return timer_handler(ARCH_TIMER_MEM_VIRT_ACCESS, evt); +} + static __always_inline void timer_set_mode(const int access, int mode, struct clock_event_device *clk) { @@ -114,6 +203,18 @@ static void arch_timer_set_mode_phys(enum clock_event_mode mode, timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode, clk); } +static void arch_timer_set_mode_virt_mem(enum clock_event_mode mode, + struct clock_event_device *clk) +{ + timer_set_mode(ARCH_TIMER_MEM_VIRT_ACCESS, mode, clk); +} + +static void arch_timer_set_mode_phys_mem(enum clock_event_mode mode, + struct clock_event_device *clk) +{ + timer_set_mode(ARCH_TIMER_MEM_PHYS_ACCESS, mode, clk); +} + static __always_inline void set_next_event(const int access, unsigned long evt, struct clock_event_device *clk) { @@ -139,27 +240,62 @@ static int arch_timer_set_next_event_phys(unsigned long evt, return 0; } -static int __cpuinit arch_timer_setup(struct clock_event_device *clk) +static int arch_timer_set_next_event_virt_mem(unsigned long evt, + struct clock_event_device *clk) { - clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP; - clk->name = "arch_sys_timer"; - clk->rating = 450; - if (arch_timer_use_virtual) { - clk->irq = arch_timer_ppi[VIRT_PPI]; - clk->set_mode = arch_timer_set_mode_virt; - clk->set_next_event = arch_timer_set_next_event_virt; + set_next_event(ARCH_TIMER_MEM_VIRT_ACCESS, evt, clk); + return 0; +} + +static int arch_timer_set_next_event_phys_mem(unsigned long evt, + struct clock_event_device *clk) +{ + set_next_event(ARCH_TIMER_MEM_PHYS_ACCESS, evt, clk); + return 0; +} + +static void __cpuinit __arch_timer_setup(unsigned type, + struct clock_event_device *clk) +{ + clk->features = CLOCK_EVT_FEAT_ONESHOT; + + if (type == ARCH_CP15_TIMER) { + clk->features |= CLOCK_EVT_FEAT_C3STOP; + clk->name = "arch_sys_timer"; + clk->rating = 450; + clk->cpumask = cpumask_of(smp_processor_id()); + if (arch_timer_use_virtual) { + clk->irq = arch_timer_ppi[VIRT_PPI]; + clk->set_mode = arch_timer_set_mode_virt; + clk->set_next_event = arch_timer_set_next_event_virt; + } else { + clk->irq = arch_timer_ppi[PHYS_SECURE_PPI]; + clk->set_mode = arch_timer_set_mode_phys; + clk->set_next_event = arch_timer_set_next_event_phys; + } } else { - clk->irq = arch_timer_ppi[PHYS_SECURE_PPI]; - clk->set_mode = arch_timer_set_mode_phys; - clk->set_next_event = arch_timer_set_next_event_phys; + clk->name = "arch_mem_timer"; + clk->rating = 400; + clk->cpumask = cpu_all_mask; + if (arch_timer_mem_use_virtual) { + clk->set_mode = arch_timer_set_mode_virt_mem; + clk->set_next_event = + arch_timer_set_next_event_virt_mem; + } else { + clk->set_mode = arch_timer_set_mode_phys_mem; + clk->set_next_event = + arch_timer_set_next_event_phys_mem; + } } - clk->cpumask = cpumask_of(smp_processor_id()); - clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, clk); - clockevents_config_and_register(clk, arch_timer_rate, - 0xf, 0x7fffffff); + clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); +} + +static int __cpuinit arch_timer_setup(struct clock_event_device *clk) +{ + __arch_timer_setup(ARCH_CP15_TIMER, clk); if (arch_timer_use_virtual) enable_percpu_irq(arch_timer_ppi[VIRT_PPI], 0); @@ -174,27 +310,41 @@ static int __cpuinit arch_timer_setup(struct clock_event_device *clk) return 0; } -static int arch_timer_available(void) +static void +arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np) { - u32 freq; - - if (arch_timer_rate == 0) { - freq = arch_timer_get_cntfrq(); - - /* Check the timer frequency. */ - if (freq == 0) { - pr_warn("Architected timer frequency not available\n"); - return -EINVAL; - } + /* Who has more than one independent system counter? */ + if (arch_timer_rate) + return; - arch_timer_rate = freq; + /* Try to determine the frequency from the device tree or CNTFRQ */ + if (of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) { + if (cntbase) + arch_timer_rate = readl_relaxed(cntbase + CNTFRQ); + else + arch_timer_rate = arch_timer_get_cntfrq(); } - pr_info_once("Architected local timer running at %lu.%02luMHz (%s).\n", + /* Check the timer frequency. */ + if (arch_timer_rate == 0) + pr_warn("Architected timer frequency not available\n"); +} + +static void arch_timer_banner(unsigned type) +{ + pr_info("Architected %s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n", + type & ARCH_CP15_TIMER ? "cp15" : "", + type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? " and " : "", + type & ARCH_MEM_TIMER ? "mmio" : "", (unsigned long)arch_timer_rate / 1000000, (unsigned long)(arch_timer_rate / 10000) % 100, - arch_timer_use_virtual ? "virt" : "phys"); - return 0; + type & ARCH_CP15_TIMER ? + arch_timer_use_virtual ? "virt" : "phys" : + "", + type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ? "/" : "", + type & ARCH_MEM_TIMER ? + arch_timer_mem_use_virtual ? "virt" : "phys" : + ""); } u32 arch_timer_get_rate(void) @@ -202,19 +352,35 @@ u32 arch_timer_get_rate(void) return arch_timer_rate; } -u64 arch_timer_read_counter(void) +static u64 arch_counter_get_cntvct_mem(void) { - return arch_counter_get_cntvct(); + u32 vct_lo, vct_hi, tmp_hi; + + do { + vct_hi = readl_relaxed(arch_counter_base + CNTVCT_HI); + vct_lo = readl_relaxed(arch_counter_base + CNTVCT_LO); + tmp_hi = readl_relaxed(arch_counter_base + CNTVCT_HI); + } while (vct_hi != tmp_hi); + + return ((u64) vct_hi << 32) | vct_lo; } +/* + * Default to cp15 based access because arm64 uses this function for + * sched_clock() before DT is probed and the cp15 method is guaranteed + * to exist on arm64. arm doesn't use this before DT is probed so even + * if we don't have the cp15 accessors we won't have a problem. + */ +u64 (*arch_timer_read_counter)(void) = arch_counter_get_cntvct; + static cycle_t arch_counter_read(struct clocksource *cs) { - return arch_counter_get_cntvct(); + return arch_timer_read_counter(); } static cycle_t arch_counter_read_cc(const struct cyclecounter *cc) { - return arch_counter_get_cntvct(); + return arch_timer_read_counter(); } static struct clocksource clocksource_counter = { @@ -237,6 +403,23 @@ struct timecounter *arch_timer_get_timecounter(void) return &timecounter; } +static void __init arch_counter_register(unsigned type) +{ + u64 start_count; + + /* Register the CP15 based counter if we have one */ + if (type & ARCH_CP15_TIMER) + arch_timer_read_counter = arch_counter_get_cntvct; + else + arch_timer_read_counter = arch_counter_get_cntvct_mem; + + start_count = arch_timer_read_counter(); + clocksource_register_hz(&clocksource_counter, arch_timer_rate); + cyclecounter.mult = clocksource_counter.mult; + cyclecounter.shift = clocksource_counter.shift; + timecounter_init(&timecounter, &cyclecounter, start_count); +} + static void __cpuinit arch_timer_stop(struct clock_event_device *clk) { pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n", @@ -281,22 +464,12 @@ static int __init arch_timer_register(void) int err; int ppi; - err = arch_timer_available(); - if (err) - goto out; - arch_timer_evt = alloc_percpu(struct clock_event_device); if (!arch_timer_evt) { err = -ENOMEM; goto out; } - clocksource_register_hz(&clocksource_counter, arch_timer_rate); - cyclecounter.mult = clocksource_counter.mult; - cyclecounter.shift = clocksource_counter.shift; - timecounter_init(&timecounter, &cyclecounter, - arch_counter_get_cntvct()); - if (arch_timer_use_virtual) { ppi = arch_timer_ppi[VIRT_PPI]; err = request_percpu_irq(ppi, arch_timer_handler_virt, @@ -347,24 +520,77 @@ out: return err; } +static int __init arch_timer_mem_register(void __iomem *base, unsigned int irq) +{ + int ret; + irq_handler_t func; + struct arch_timer *t; + + t = kzalloc(sizeof(*t), GFP_KERNEL); + if (!t) + return -ENOMEM; + + t->base = base; + t->evt.irq = irq; + __arch_timer_setup(ARCH_MEM_TIMER, &t->evt); + + if (arch_timer_mem_use_virtual) + func = arch_timer_handler_virt_mem; + else + func = arch_timer_handler_phys_mem; + + ret = request_irq(irq, func, IRQF_TIMER, "arch_mem_timer", &t->evt); + if (ret) { + pr_err("arch_timer: Failed to request mem timer irq\n"); + kfree(t); + } + + return ret; +} + +static const struct of_device_id arch_timer_of_match[] __initconst = { + { .compatible = "arm,armv7-timer", }, + { .compatible = "arm,armv8-timer", }, + {}, +}; + +static const struct of_device_id arch_timer_mem_of_match[] __initconst = { + { .compatible = "arm,armv7-timer-mem", }, + {}, +}; + +static void __init arch_timer_common_init(void) +{ + unsigned mask = ARCH_CP15_TIMER | ARCH_MEM_TIMER; + + /* Wait until both nodes are probed if we have two timers */ + if ((arch_timers_present & mask) != mask) { + if (of_find_matching_node(NULL, arch_timer_mem_of_match) && + !(arch_timers_present & ARCH_MEM_TIMER)) + return; + if (of_find_matching_node(NULL, arch_timer_of_match) && + !(arch_timers_present & ARCH_CP15_TIMER)) + return; + } + + arch_timer_banner(arch_timers_present); + arch_counter_register(arch_timers_present); + arch_timer_arch_init(); +} + static void __init arch_timer_init(struct device_node *np) { - u32 freq; int i; - if (arch_timer_get_rate()) { + if (arch_timers_present & ARCH_CP15_TIMER) { pr_warn("arch_timer: multiple nodes in dt, skipping\n"); return; } - /* Try to determine the frequency from the device tree or CNTFRQ */ - if (!of_property_read_u32(np, "clock-frequency", &freq)) - arch_timer_rate = freq; - + arch_timers_present |= ARCH_CP15_TIMER; for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) arch_timer_ppi[i] = irq_of_parse_and_map(np, i); - - of_node_put(np); + arch_timer_detect_rate(NULL, np); /* * If HYP mode is available, we know that the physical timer @@ -385,7 +611,73 @@ static void __init arch_timer_init(struct device_node *np) } arch_timer_register(); - arch_timer_arch_init(); + arch_timer_common_init(); } CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init); + +static void __init arch_timer_mem_init(struct device_node *np) +{ + struct device_node *frame, *best_frame = NULL; + void __iomem *cntctlbase, *base; + unsigned int irq; + u32 cnttidr; + + arch_timers_present |= ARCH_MEM_TIMER; + cntctlbase = of_iomap(np, 0); + if (!cntctlbase) { + pr_err("arch_timer: Can't find CNTCTLBase\n"); + return; + } + + cnttidr = readl_relaxed(cntctlbase + CNTTIDR); + iounmap(cntctlbase); + + /* + * Try to find a virtual capable frame. Otherwise fall back to a + * physical capable frame. + */ + for_each_available_child_of_node(np, frame) { + int n; + + if (of_property_read_u32(frame, "frame-number", &n)) { + pr_err("arch_timer: Missing frame-number\n"); + of_node_put(best_frame); + of_node_put(frame); + return; + } + + if (cnttidr & CNTTIDR_VIRT(n)) { + of_node_put(best_frame); + best_frame = frame; + arch_timer_mem_use_virtual = true; + break; + } + of_node_put(best_frame); + best_frame = of_node_get(frame); + } + + base = arch_counter_base = of_iomap(best_frame, 0); + if (!base) { + pr_err("arch_timer: Can't map frame's registers\n"); + of_node_put(best_frame); + return; + } + + if (arch_timer_mem_use_virtual) + irq = irq_of_parse_and_map(best_frame, 1); + else + irq = irq_of_parse_and_map(best_frame, 0); + of_node_put(best_frame); + if (!irq) { + pr_err("arch_timer: Frame missing %s irq", + arch_timer_mem_use_virtual ? "virt" : "phys"); + return; + } + + arch_timer_detect_rate(base, np); + arch_timer_mem_register(base, irq); + arch_timer_common_init(); +} +CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", + arch_timer_mem_init); diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h index f3da817b9b8..93b7f96f9c5 100644 --- a/include/clocksource/arm_arch_timer.h +++ b/include/clocksource/arm_arch_timer.h @@ -30,11 +30,13 @@ enum arch_timer_reg { #define ARCH_TIMER_PHYS_ACCESS 0 #define ARCH_TIMER_VIRT_ACCESS 1 +#define ARCH_TIMER_MEM_PHYS_ACCESS 2 +#define ARCH_TIMER_MEM_VIRT_ACCESS 3 #ifdef CONFIG_ARM_ARCH_TIMER extern u32 arch_timer_get_rate(void); -extern u64 arch_timer_read_counter(void); +extern u64 (*arch_timer_read_counter)(void); extern struct timecounter *arch_timer_get_timecounter(void); #else -- cgit v1.2.3-70-g09d2 From e24154896e2f60b0c20bda492d662ad77ffa5c32 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 13 Jun 2013 21:22:44 +0200 Subject: clocksource: samsung_pwm_timer: Do not request PWM mem region PWM registers are shared between clocksource and PWM drivers and so can not be claimed for exclusive use. Signed-off-by: Tomasz Figa Reviewed-by: Sylwester Nawrocki Tested-by: Heiko Stuebner Tested-by: Mark Brown Tested-by: Sylwester Nawrocki Acked-by: Arnd Bergmann --- drivers/clocksource/samsung_pwm_timer.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index 584b5472eea..3fa5b07fa50 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -404,7 +404,6 @@ void __init samsung_pwm_clocksource_init(void __iomem *base, static void __init samsung_pwm_alloc(struct device_node *np, const struct samsung_pwm_variant *variant) { - struct resource res; struct property *prop; const __be32 *cur; u32 val; @@ -423,17 +422,9 @@ static void __init samsung_pwm_alloc(struct device_node *np, pwm.variant.output_mask |= 1 << val; } - of_address_to_resource(np, 0, &res); - if (!request_mem_region(res.start, - resource_size(&res), "samsung-pwm")) { - pr_err("%s: failed to request IO mem region\n", __func__); - return; - } - - pwm.base = ioremap(res.start, resource_size(&res)); + pwm.base = of_iomap(np, 0); if (!pwm.base) { pr_err("%s: failed to map PWM registers\n", __func__); - release_mem_region(res.start, resource_size(&res)); return; } -- cgit v1.2.3-70-g09d2 From ceea124103c6f00561491b45133be5ccefc8ea1d Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Mon, 17 Jun 2013 02:10:24 +0200 Subject: clocksource: samsung_pwm_timer: Correct definition of AUTORELOAD bit PWM channel 4 has its autoreload bit located at different position. This patch fixes the driver to account for that. This fixes a problem with the clocksource hanging after it overflows because it is not reloaded any more. Signed-off-by: Tomasz Figa Reviewed-by: Sylwester Nawrocki Tested-by: Heiko Stuebner Tested-by: Mark Brown Tested-by: Sylwester Nawrocki Acked-by: Arnd Bergmann --- drivers/clocksource/samsung_pwm_timer.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index 3fa5b07fa50..5d0049f07af 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -44,10 +44,21 @@ #define TCFG1_SHIFT(x) ((x) * 4) #define TCFG1_MUX_MASK 0xf +/* + * Each channel occupies 4 bits in TCON register, but there is a gap of 4 + * bits (one channel) after channel 0, so channels have different numbering + * when accessing TCON register. + * + * In addition, the location of autoreload bit for channel 4 (TCON channel 5) + * in its set of bits is 2 as opposed to 3 for other channels. + */ #define TCON_START(chan) (1 << (4 * (chan) + 0)) #define TCON_MANUALUPDATE(chan) (1 << (4 * (chan) + 1)) #define TCON_INVERT(chan) (1 << (4 * (chan) + 2)) -#define TCON_AUTORELOAD(chan) (1 << (4 * (chan) + 3)) +#define _TCON_AUTORELOAD(chan) (1 << (4 * (chan) + 3)) +#define _TCON_AUTORELOAD4(chan) (1 << (4 * (chan) + 2)) +#define TCON_AUTORELOAD(chan) \ + ((chan < 5) ? _TCON_AUTORELOAD(chan) : _TCON_AUTORELOAD4(chan)) DEFINE_SPINLOCK(samsung_pwm_lock); EXPORT_SYMBOL(samsung_pwm_lock); -- cgit v1.2.3-70-g09d2 From 61d7e2056eb6147824a8689c6e6ab62396e26321 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Mon, 17 Jun 2013 00:07:03 +0200 Subject: clocksource: samsung_pwm_timer: Cache clocksource register address Instead of calculating register every time the timer should be read, we can just do it one time at initialization and store the address in driver data. Signed-off-by: Tomasz Figa Reviewed-by: Sylwester Nawrocki Tested-by: Heiko Stuebner Tested-by: Mark Brown Tested-by: Sylwester Nawrocki Acked-by: Arnd Bergmann --- drivers/clocksource/samsung_pwm_timer.c | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index 5d0049f07af..0c005f4fa29 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -65,6 +65,7 @@ EXPORT_SYMBOL(samsung_pwm_lock); struct samsung_pwm_clocksource { void __iomem *base; + void __iomem *source_reg; unsigned int irq[SAMSUNG_PWM_NUM]; struct samsung_pwm_variant variant; @@ -297,23 +298,6 @@ static void __init samsung_clockevent_init(void) } } -static void __iomem *samsung_timer_reg(void) -{ - switch (pwm.source_id) { - case 0: - case 1: - case 2: - case 3: - return pwm.base + pwm.source_id * 0x0c + 0x14; - - case 4: - return pwm.base + 0x40; - - default: - BUG(); - } -} - /* * Override the global weak sched_clock symbol with this * local implementation which uses the clocksource to get some @@ -323,17 +307,11 @@ static void __iomem *samsung_timer_reg(void) */ static u32 notrace samsung_read_sched_clock(void) { - void __iomem *reg = samsung_timer_reg(); - - if (!reg) - return 0; - - return ~__raw_readl(reg); + return ~__raw_readl(pwm.source_reg); } static void __init samsung_clocksource_init(void) { - void __iomem *reg = samsung_timer_reg(); unsigned long pclk; unsigned long clock_rate; int ret; @@ -348,10 +326,15 @@ static void __init samsung_clocksource_init(void) samsung_time_setup(pwm.source_id, pwm.tcnt_max); samsung_time_start(pwm.source_id, true); + if (pwm.source_id == 4) + pwm.source_reg = pwm.base + 0x40; + else + pwm.source_reg = pwm.base + pwm.source_id * 0x0c + 0x14; + setup_sched_clock(samsung_read_sched_clock, pwm.variant.bits, clock_rate); - ret = clocksource_mmio_init(reg, "samsung_clocksource_timer", + ret = clocksource_mmio_init(pwm.source_reg, "samsung_clocksource_timer", clock_rate, 250, pwm.variant.bits, clocksource_mmio_readl_down); if (ret) -- cgit v1.2.3-70-g09d2 From 6792e636d5bfc1b26c25e7ed056b358e1144c6df Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Mon, 17 Jun 2013 00:13:06 +0200 Subject: clocksource: samsung_pwm_timer: Do not use clocksource_mmio In case of Samsung PWM timer, clocksource MMIO can not be used, because custom suspend/resume callbacks are required. Signed-off-by: Tomasz Figa Reviewed-by: Daniel Lezcano Reviewed-by: Sylwester Nawrocki Tested-by: Heiko Stuebner Tested-by: Mark Brown Tested-by: Sylwester Nawrocki Acked-by: Arnd Bergmann --- drivers/clocksource/Kconfig | 1 - drivers/clocksource/samsung_pwm_timer.c | 19 +++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index b7b9b040a89..41c69469ce2 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -99,7 +99,6 @@ config CLKSRC_EXYNOS_MCT config CLKSRC_SAMSUNG_PWM bool - select CLKSRC_MMIO help This is a new clocksource driver for the PWM timer found in Samsung S3C, S5P and Exynos SoCs, replacing an earlier driver diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index 0c005f4fa29..b3112dc293b 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -298,6 +298,18 @@ static void __init samsung_clockevent_init(void) } } +static cycle_t samsung_clocksource_read(struct clocksource *c) +{ + return ~readl_relaxed(pwm.source_reg); +} + +static struct clocksource samsung_clocksource = { + .name = "samsung_clocksource_timer", + .rating = 250, + .read = samsung_clocksource_read, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + /* * Override the global weak sched_clock symbol with this * local implementation which uses the clocksource to get some @@ -307,7 +319,7 @@ static void __init samsung_clockevent_init(void) */ static u32 notrace samsung_read_sched_clock(void) { - return ~__raw_readl(pwm.source_reg); + return samsung_clocksource_read(NULL); } static void __init samsung_clocksource_init(void) @@ -334,9 +346,8 @@ static void __init samsung_clocksource_init(void) setup_sched_clock(samsung_read_sched_clock, pwm.variant.bits, clock_rate); - ret = clocksource_mmio_init(pwm.source_reg, "samsung_clocksource_timer", - clock_rate, 250, pwm.variant.bits, - clocksource_mmio_readl_down); + samsung_clocksource.mask = CLOCKSOURCE_MASK(pwm.variant.bits); + ret = clocksource_register_hz(&samsung_clocksource, clock_rate); if (ret) panic("samsung_clocksource_timer: can't register clocksource\n"); } -- cgit v1.2.3-70-g09d2 From 0b96258b420208ebaacc0ef4b21b67dba262badf Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Mon, 17 Jun 2013 01:11:31 +0200 Subject: clocksource: samsung_pwm_timer: Handle suspend/resume correctly Current suspend/resume handling of the driver was broken, because: - periodic timer was being enabled in CLOCK_EVT_MODE_RESUME mode, which does not seem to be correct behavior looking at other platforms, - PWM divisors need to be restored, but they were not, - clockevent interrupt mask needs to be restored, but it was not, - clocksource was being restored in clockevent resume callback. This patch fixes issues mentioned above, making suspend/resume handling in the driver correct. Signed-off-by: Tomasz Figa Reviewed-by: Sylwester Nawrocki Tested-by: Heiko Stuebner Tested-by: Mark Brown Tested-by: Sylwester Nawrocki Acked-by: Arnd Bergmann Acked-by: Daniel Lezcano --- drivers/clocksource/samsung_pwm_timer.c | 42 ++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 14 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index b3112dc293b..ac60f8b8a5f 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -207,17 +207,6 @@ static int samsung_set_next_event(unsigned long cycles, return 0; } -static void samsung_timer_resume(void) -{ - /* event timer restart */ - samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick - 1); - samsung_time_start(pwm.event_id, true); - - /* source timer restart */ - samsung_time_setup(pwm.source_id, pwm.tcnt_max); - samsung_time_start(pwm.source_id, true); -} - static void samsung_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { @@ -234,20 +223,29 @@ static void samsung_set_mode(enum clock_event_mode mode, case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_SHUTDOWN: - break; - case CLOCK_EVT_MODE_RESUME: - samsung_timer_resume(); break; } } +static void samsung_clockevent_resume(struct clock_event_device *cev) +{ + samsung_timer_set_prescale(pwm.event_id, pwm.tscaler_div); + samsung_timer_set_divisor(pwm.event_id, pwm.tdiv); + + if (pwm.variant.has_tint_cstat) { + u32 mask = (1 << pwm.event_id); + writel(mask | (mask << 5), pwm.base + REG_TINT_CSTAT); + } +} + static struct clock_event_device time_event_device = { .name = "samsung_event_timer", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .rating = 200, .set_next_event = samsung_set_next_event, .set_mode = samsung_set_mode, + .resume = samsung_clockevent_resume, }; static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id) @@ -298,6 +296,20 @@ static void __init samsung_clockevent_init(void) } } +static void samsung_clocksource_suspend(struct clocksource *cs) +{ + samsung_time_stop(pwm.source_id); +} + +static void samsung_clocksource_resume(struct clocksource *cs) +{ + samsung_timer_set_prescale(pwm.source_id, pwm.tscaler_div); + samsung_timer_set_divisor(pwm.source_id, pwm.tdiv); + + samsung_time_setup(pwm.source_id, pwm.tcnt_max); + samsung_time_start(pwm.source_id, true); +} + static cycle_t samsung_clocksource_read(struct clocksource *c) { return ~readl_relaxed(pwm.source_reg); @@ -307,6 +319,8 @@ static struct clocksource samsung_clocksource = { .name = "samsung_clocksource_timer", .rating = 250, .read = samsung_clocksource_read, + .suspend = samsung_clocksource_suspend, + .resume = samsung_clocksource_resume, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -- cgit v1.2.3-70-g09d2 From aea237bfa0a8ce8fe364e3fa7de6850777044a60 Mon Sep 17 00:00:00 2001 From: Christian Daudt Date: Tue, 20 Aug 2013 08:37:19 -0700 Subject: ARM: DT: binding fixup to align with vendor-prefixes.txt (drivers) [ this is a follow-up to this discussion: http://archive.arm.linux.org.uk/lurker/message/20130730.230827.a1ceb12a.en.html ] This patchset renames all uses of "bcm," name bindings to "brcm," as they were done prior to knowing that brcm had already been standardized as Broadcom vendor prefix (in Documentation/devicetree/bindings/vendor-prefixes.txt). This will not cause any churn on devices because none of these bindings have made it into production yet. Signed-off-by: Christian Daudt Acked-by: Stephen Warren --- arch/arm/mach-bcm/bcm_kona_smc.c | 3 ++- arch/arm/mach-bcm/board_bcm281xx.c | 4 ++-- drivers/clocksource/bcm_kona_timer.c | 8 +++++++- drivers/mmc/host/sdhci-bcm-kona.c | 3 ++- 4 files changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/clocksource') diff --git a/arch/arm/mach-bcm/bcm_kona_smc.c b/arch/arm/mach-bcm/bcm_kona_smc.c index 56d9d19b247..bcc1c5903fb 100644 --- a/arch/arm/mach-bcm/bcm_kona_smc.c +++ b/arch/arm/mach-bcm/bcm_kona_smc.c @@ -36,7 +36,8 @@ struct bcm_kona_smc_data { }; static const struct of_device_id bcm_kona_smc_ids[] __initconst = { - {.compatible = "bcm,kona-smc"}, + {.compatible = "brcm,kona-smc"}, + {.compatible = "bcm,kona-smc"}, /* deprecated name */ {}, }; diff --git a/arch/arm/mach-bcm/board_bcm281xx.c b/arch/arm/mach-bcm/board_bcm281xx.c index 1e49ec0399a..3fe1e4d2e9a 100644 --- a/arch/arm/mach-bcm/board_bcm281xx.c +++ b/arch/arm/mach-bcm/board_bcm281xx.c @@ -44,7 +44,7 @@ static void bcm_board_setup_restart(void) { struct device_node *np; - np = of_find_compatible_node(NULL, NULL, "bcm,bcm11351"); + np = of_find_compatible_node(NULL, NULL, "brcm,bcm11351"); if (np) { if (of_device_is_available(np)) bcm_kona_setup_restart(); @@ -63,7 +63,7 @@ static void __init board_init(void) kona_l2_cache_init(); } -static const char * const bcm11351_dt_compat[] = { "bcm,bcm11351", NULL, }; +static const char * const bcm11351_dt_compat[] = { "brcm,bcm11351", NULL, }; DT_MACHINE_START(BCM11351_DT, "Broadcom Application Processor") .init_time = clocksource_of_init, diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c index ba3d85904c9..0d7d8c3ed6b 100644 --- a/drivers/clocksource/bcm_kona_timer.c +++ b/drivers/clocksource/bcm_kona_timer.c @@ -99,7 +99,8 @@ kona_timer_get_counter(void *timer_base, uint32_t *msw, uint32_t *lsw) } static const struct of_device_id bcm_timer_ids[] __initconst = { - {.compatible = "bcm,kona-timer"}, + {.compatible = "brcm,kona-timer"}, + {.compatible = "bcm,kona-timer"}, /* deprecated name */ {}, }; @@ -201,4 +202,9 @@ static void __init kona_timer_init(struct device_node *node) kona_timer_set_next_event((arch_timer_rate / HZ), NULL); } +CLOCKSOURCE_OF_DECLARE(brcm_kona, "brcm,kona-timer", kona_timer_init); +/* + * bcm,kona-timer is deprecated by brcm,kona-timer + * being kept here for driver compatibility + */ CLOCKSOURCE_OF_DECLARE(bcm_kona, "bcm,kona-timer", kona_timer_init); diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c index 90a93673292..9ec7ca5dbce 100644 --- a/drivers/mmc/host/sdhci-bcm-kona.c +++ b/drivers/mmc/host/sdhci-bcm-kona.c @@ -222,7 +222,8 @@ static struct sdhci_pltfm_data sdhci_pltfm_data_kona = { }; static struct __initconst of_device_id sdhci_bcm_kona_of_match[] = { - { .compatible = "bcm,kona-sdhci"}, + { .compatible = "brcm,kona-sdhci"}, + { .compatible = "bcm,kona-sdhci"}, /* deprecated name */ {} }; MODULE_DEVICE_TABLE(of, sdhci_bcm_kona_of_match); -- cgit v1.2.3-70-g09d2 From 1745e696e174b54e37c057882970e50af1e80a7f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 30 Jul 2013 16:24:37 +0200 Subject: clocksource: em_sti: Convert to devm_* managed helpers Replace kzalloc, clk_get, ioremap and request_irq by their managed counterparts to simplify error paths. Signed-off-by: Laurent Pinchart Reviewed-by: Daniel Lezcano --- drivers/clocksource/em_sti.c | 49 +++++++++++++------------------------------- 1 file changed, 14 insertions(+), 35 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c index 4329a29a531..b9c81b7c3a3 100644 --- a/drivers/clocksource/em_sti.c +++ b/drivers/clocksource/em_sti.c @@ -315,68 +315,47 @@ static int em_sti_probe(struct platform_device *pdev) { struct em_sti_priv *p; struct resource *res; - int irq, ret; + int irq; - p = kzalloc(sizeof(*p), GFP_KERNEL); + p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); if (p == NULL) { dev_err(&pdev->dev, "failed to allocate driver data\n"); - ret = -ENOMEM; - goto err0; + return -ENOMEM; } p->pdev = pdev; platform_set_drvdata(pdev, p); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get I/O memory\n"); - ret = -EINVAL; - goto err0; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "failed to get irq\n"); - ret = -EINVAL; - goto err0; + return -EINVAL; } /* map memory, let base point to the STI instance */ - p->base = ioremap_nocache(res->start, resource_size(res)); - if (p->base == NULL) { - dev_err(&pdev->dev, "failed to remap I/O memory\n"); - ret = -ENXIO; - goto err0; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + p->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(p->base)) + return PTR_ERR(p->base); /* get hold of clock */ - p->clk = clk_get(&pdev->dev, "sclk"); + p->clk = devm_clk_get(&pdev->dev, "sclk"); if (IS_ERR(p->clk)) { dev_err(&pdev->dev, "cannot get clock\n"); - ret = PTR_ERR(p->clk); - goto err1; + return PTR_ERR(p->clk); } - if (request_irq(irq, em_sti_interrupt, - IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, - dev_name(&pdev->dev), p)) { + if (devm_request_irq(&pdev->dev, irq, em_sti_interrupt, + IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, + dev_name(&pdev->dev), p)) { dev_err(&pdev->dev, "failed to request low IRQ\n"); - ret = -ENOENT; - goto err2; + return -ENOENT; } raw_spin_lock_init(&p->lock); em_sti_register_clockevent(p); em_sti_register_clocksource(p); return 0; - -err2: - clk_put(p->clk); -err1: - iounmap(p->base); -err0: - kfree(p); - return ret; } static int em_sti_remove(struct platform_device *pdev) -- cgit v1.2.3-70-g09d2 From 8874c5e3b92fc23af4fd4da8830f7d4de41d03a0 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 17 Jun 2013 15:40:52 +0900 Subject: clocksource: sh_cmt: 32-bit control register support Add support for CMT hardware with 32-bit control and counter registers, as found on r8a73a4 and r8a7790. To use the CMT with 32-bit hardware a second I/O memory resource needs to point out the CMSTR register and it needs to be 32 bit wide. Signed-off-by: Magnus Damm Reviewed-by: Daniel Lezcano Signed-off-by: Simon Horman --- drivers/clocksource/sh_cmt.c | 50 +++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 14 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 08d0c418c94..0965e9848b3 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -37,6 +37,7 @@ struct sh_cmt_priv { void __iomem *mapbase; + void __iomem *mapbase_str; struct clk *clk; unsigned long width; /* 16 or 32 bit version of hardware block */ unsigned long overflow_bit; @@ -79,6 +80,12 @@ struct sh_cmt_priv { * CMCSR 0xffca0060 16-bit * CMCNT 0xffca0064 32-bit * CMCOR 0xffca0068 32-bit + * + * "32-bit counter and 32-bit control" as found on r8a73a4 and r8a7790: + * CMSTR 0xffca0500 32-bit + * CMCSR 0xffca0510 32-bit + * CMCNT 0xffca0514 32-bit + * CMCOR 0xffca0518 32-bit */ static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs) @@ -109,9 +116,7 @@ static void sh_cmt_write32(void __iomem *base, unsigned long offs, static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_priv *p) { - struct sh_timer_config *cfg = p->pdev->dev.platform_data; - - return p->read_control(p->mapbase - cfg->channel_offset, 0); + return p->read_control(p->mapbase_str, 0); } static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_priv *p) @@ -127,9 +132,7 @@ static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_priv *p) static inline void sh_cmt_write_cmstr(struct sh_cmt_priv *p, unsigned long value) { - struct sh_timer_config *cfg = p->pdev->dev.platform_data; - - p->write_control(p->mapbase - cfg->channel_offset, 0, value); + p->write_control(p->mapbase_str, 0, value); } static inline void sh_cmt_write_cmcsr(struct sh_cmt_priv *p, @@ -676,7 +679,7 @@ static int sh_cmt_register(struct sh_cmt_priv *p, char *name, static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) { struct sh_timer_config *cfg = pdev->dev.platform_data; - struct resource *res; + struct resource *res, *res2; int irq, ret; ret = -ENXIO; @@ -694,6 +697,9 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) goto err0; } + /* optional resource for the shared timer start/stop register */ + res2 = platform_get_resource(p->pdev, IORESOURCE_MEM, 1); + irq = platform_get_irq(p->pdev, 0); if (irq < 0) { dev_err(&p->pdev->dev, "failed to get irq\n"); @@ -707,6 +713,15 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) goto err0; } + /* map second resource for CMSTR */ + p->mapbase_str = ioremap_nocache(res2 ? res2->start : + res->start - cfg->channel_offset, + res2 ? resource_size(res2) : 2); + if (p->mapbase_str == NULL) { + dev_err(&p->pdev->dev, "failed to remap I/O second memory\n"); + goto err1; + } + /* request irq using setup_irq() (too early for request_irq()) */ p->irqaction.name = dev_name(&p->pdev->dev); p->irqaction.handler = sh_cmt_interrupt; @@ -719,11 +734,17 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) if (IS_ERR(p->clk)) { dev_err(&p->pdev->dev, "cannot get clock\n"); ret = PTR_ERR(p->clk); - goto err1; + goto err2; } - p->read_control = sh_cmt_read16; - p->write_control = sh_cmt_write16; + if (res2 && (resource_size(res2) == 4)) { + /* assume both CMSTR and CMCSR to be 32-bit */ + p->read_control = sh_cmt_read32; + p->write_control = sh_cmt_write32; + } else { + p->read_control = sh_cmt_read16; + p->write_control = sh_cmt_write16; + } if (resource_size(res) == 6) { p->width = 16; @@ -752,22 +773,23 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) cfg->clocksource_rating); if (ret) { dev_err(&p->pdev->dev, "registration failed\n"); - goto err2; + goto err3; } p->cs_enabled = false; ret = setup_irq(irq, &p->irqaction); if (ret) { dev_err(&p->pdev->dev, "failed to request irq %d\n", irq); - goto err2; + goto err3; } platform_set_drvdata(pdev, p); return 0; -err2: +err3: clk_put(p->clk); - +err2: + iounmap(p->mapbase_str); err1: iounmap(p->mapbase); err0: -- cgit v1.2.3-70-g09d2 From 74adcbffa8f4d9d39d72d20d80ee62be279ebf44 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Sat, 2 Mar 2013 11:10:12 +0100 Subject: ARM: nomadik: add dynamic irq flag to the timer Add the dynamic irq affinity feature to the timer clock device. Signed-off-by: Daniel Lezcano Reviewed-by: Vincent Guittot Acked-by: Rickard Andersson --- drivers/clocksource/nomadik-mtu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c index 7d2c2c56f73..1b74bea1238 100644 --- a/drivers/clocksource/nomadik-mtu.c +++ b/drivers/clocksource/nomadik-mtu.c @@ -165,7 +165,8 @@ static void nmdk_clkevt_resume(struct clock_event_device *cedev) static struct clock_event_device nmdk_clkevt = { .name = "mtu_1", - .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, + .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_DYNIRQ, .rating = 200, .set_mode = nmdk_clkevt_mode, .set_next_event = nmdk_clkevt_next, -- cgit v1.2.3-70-g09d2 From 8e33a52fadddcfc9f85594a7ab4802c60ee0046a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 25 Jul 2013 11:53:25 -0700 Subject: treewide: Fix printks with 0x%# Using 0x%# emits 0x0x. Only one is necessary. Signed-off-by: Joe Perches Acked-by: Takashi Iwai Signed-off-by: Jiri Kosina --- arch/parisc/kernel/signal.c | 2 +- drivers/clocksource/acpi_pm.c | 4 ++-- drivers/net/ethernet/sis/sis900.c | 2 +- mm/memory-failure.c | 2 +- sound/pci/ens1370.c | 2 +- sound/pci/via82xx.c | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/clocksource') diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 940188d1942..35c5bf1307a 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -85,7 +85,7 @@ restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs) err |= __copy_from_user(regs->iaoq, sc->sc_iaoq, sizeof(regs->iaoq)); err |= __copy_from_user(regs->iasq, sc->sc_iasq, sizeof(regs->iasq)); err |= __get_user(regs->sar, &sc->sc_sar); - DBG(2,"restore_sigcontext: iaoq is 0x%#lx / 0x%#lx\n", + DBG(2,"restore_sigcontext: iaoq is %#lx / %#lx\n", regs->iaoq[0],regs->iaoq[1]); DBG(2,"restore_sigcontext: r28 is %ld\n", regs->gr[28]); return err; diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 6efe4d1ab3a..6eab8898567 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -200,14 +200,14 @@ static int __init init_acpi_pm_clocksource(void) if ((value2 < value1) && ((value2) < 0xFFF)) break; printk(KERN_INFO "PM-Timer had inconsistent results:" - " 0x%#llx, 0x%#llx - aborting.\n", + " %#llx, %#llx - aborting.\n", value1, value2); pmtmr_ioport = 0; return -EINVAL; } if (i == ACPI_PM_READ_CHECKS) { printk(KERN_INFO "PM-Timer failed consistency check " - " (0x%#llx) - aborting.\n", value1); + " (%#llx) - aborting.\n", value1); pmtmr_ioport = 0; return -ENODEV; } diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c index eb4aea3fe79..6c1e34cd8ae 100644 --- a/drivers/net/ethernet/sis/sis900.c +++ b/drivers/net/ethernet/sis/sis900.c @@ -1723,7 +1723,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance) if(netif_msg_intr(sis_priv)) printk(KERN_DEBUG "%s: exiting interrupt, " - "interrupt status = 0x%#8.8x.\n", + "interrupt status = %#8.8x\n", net_dev->name, sr32(isr)); spin_unlock (&sis_priv->lock); diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 2c13aa7a016..b6fefcf13cb 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1265,7 +1265,7 @@ void memory_failure_queue(unsigned long pfn, int trapno, int flags) if (kfifo_put(&mf_cpu->fifo, &entry)) schedule_work_on(smp_processor_id(), &mf_cpu->work); else - pr_err("Memory failure: buffer overflow when queuing memory failure at 0x%#lx\n", + pr_err("Memory failure: buffer overflow when queuing memory failure at %#lx\n", pfn); spin_unlock_irqrestore(&mf_cpu->lock, proc_flags); put_cpu_var(memory_failure_cpu); diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index ca8929b9a5d..61262f39600 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -1842,7 +1842,7 @@ static int snd_ensoniq_create_gameport(struct ensoniq *ensoniq, int dev) default: if (!request_region(io_port, 8, "ens137x: gameport")) { - printk(KERN_WARNING "ens137x: gameport io port 0x%#x in use\n", + printk(KERN_WARNING "ens137x: gameport io port %#x in use\n", io_port); return -EBUSY; } diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 3c511d0caf9..5ae6f042c58 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -1940,7 +1940,7 @@ static int snd_via686_create_gameport(struct via82xx *chip, unsigned char *legac r = request_region(JOYSTICK_ADDR, 8, "VIA686 gameport"); if (!r) { - printk(KERN_WARNING "via82xx: cannot reserve joystick port 0x%#x\n", + printk(KERN_WARNING "via82xx: cannot reserve joystick port %#x\n", JOYSTICK_ADDR); return -EBUSY; } -- cgit v1.2.3-70-g09d2 From ad48bd618f3761922c53f08e05fe00f3c85ca275 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 13 Aug 2013 11:43:10 -0300 Subject: clocksource: armada-370-xp: Use BIT() This is a purely cosmetic commit: we replace hardcoded values that representing bits by BIT(), which is slightly more readable. Signed-off-by: Ezequiel Garcia Signed-off-by: Daniel Lezcano Reviewed-by: Andrew Lunn --- drivers/clocksource/time-armada-370-xp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index 1b04b7e1d39..a3d273943bc 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -35,13 +35,13 @@ * Timer block registers. */ #define TIMER_CTRL_OFF 0x0000 -#define TIMER0_EN 0x0001 -#define TIMER0_RELOAD_EN 0x0002 -#define TIMER0_25MHZ 0x0800 +#define TIMER0_EN BIT(0) +#define TIMER0_RELOAD_EN BIT(1) +#define TIMER0_25MHZ BIT(11) #define TIMER0_DIV(div) ((div) << 19) -#define TIMER1_EN 0x0004 -#define TIMER1_RELOAD_EN 0x0008 -#define TIMER1_25MHZ 0x1000 +#define TIMER1_EN BIT(2) +#define TIMER1_RELOAD_EN BIT(3) +#define TIMER1_25MHZ BIT(12) #define TIMER1_DIV(div) ((div) << 22) #define TIMER_EVENTS_STATUS 0x0004 #define TIMER0_CLR_MASK (~0x1) -- cgit v1.2.3-70-g09d2 From 3579698e85ef9984e698ac3d8e2257a1adeeb722 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 13 Aug 2013 11:43:11 -0300 Subject: clocksource: armada-370-xp: Simplify TIMER_CTRL register access This commit creates two functions to access the TIMER_CTRL register: one for global one for the per-cpu. This makes the code much more readable. In addition, since the TIMER_CTRL register is also used for watchdog, this is preparation work for future thread-safe improvements. Acked-by: Gregory CLEMENT Reviewed-by: Andrew Lunn Signed-off-by: Ezequiel Garcia Signed-off-by: Daniel Lezcano --- drivers/clocksource/time-armada-370-xp.c | 69 ++++++++++++++------------------ 1 file changed, 30 insertions(+), 39 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index a3d273943bc..abc2c9f0482 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -71,6 +71,18 @@ static u32 ticks_per_jiffy; static struct clock_event_device __percpu **percpu_armada_370_xp_evt; +static void timer_ctrl_clrset(u32 clr, u32 set) +{ + writel((readl(timer_base + TIMER_CTRL_OFF) & ~clr) | set, + timer_base + TIMER_CTRL_OFF); +} + +static void local_timer_ctrl_clrset(u32 clr, u32 set) +{ + writel((readl(local_base + TIMER_CTRL_OFF) & ~clr) | set, + local_base + TIMER_CTRL_OFF); +} + static u32 notrace armada_370_xp_read_sched_clock(void) { return ~readl(timer_base + TIMER0_VAL_OFF); @@ -83,7 +95,6 @@ static int armada_370_xp_clkevt_next_event(unsigned long delta, struct clock_event_device *dev) { - u32 u; /* * Clear clockevent timer interrupt. */ @@ -97,11 +108,8 @@ armada_370_xp_clkevt_next_event(unsigned long delta, /* * Enable the timer. */ - u = readl(local_base + TIMER_CTRL_OFF); - u = ((u & ~TIMER0_RELOAD_EN) | TIMER0_EN | - TIMER0_DIV(TIMER_DIVIDER_SHIFT)); - writel(u, local_base + TIMER_CTRL_OFF); - + local_timer_ctrl_clrset(TIMER0_RELOAD_EN, + TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); return 0; } @@ -109,8 +117,6 @@ static void armada_370_xp_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) { - u32 u; - if (mode == CLOCK_EVT_MODE_PERIODIC) { /* @@ -122,18 +128,14 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode, /* * Enable timer. */ - - u = readl(local_base + TIMER_CTRL_OFF); - - writel((u | TIMER0_EN | TIMER0_RELOAD_EN | - TIMER0_DIV(TIMER_DIVIDER_SHIFT)), - local_base + TIMER_CTRL_OFF); + local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | + TIMER0_EN | + TIMER0_DIV(TIMER_DIVIDER_SHIFT)); } else { /* * Disable timer. */ - u = readl(local_base + TIMER_CTRL_OFF); - writel(u & ~TIMER0_EN, local_base + TIMER_CTRL_OFF); + local_timer_ctrl_clrset(TIMER0_EN, 0); /* * ACK pending timer interrupt. @@ -169,18 +171,18 @@ static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) */ static int armada_370_xp_timer_setup(struct clock_event_device *evt) { - u32 u; + u32 clr = 0, set = 0; int cpu = smp_processor_id(); /* Use existing clock_event for cpu 0 */ if (!smp_processor_id()) return 0; - u = readl(local_base + TIMER_CTRL_OFF); if (timer25Mhz) - writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); + set = TIMER0_25MHZ; else - writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); + clr = TIMER0_25MHZ; + local_timer_ctrl_clrset(clr, set); evt->name = armada_370_xp_clkevt.name; evt->irq = armada_370_xp_clkevt.irq; @@ -212,7 +214,7 @@ static struct local_timer_ops armada_370_xp_local_timer_ops = { void __init armada_370_xp_timer_init(void) { - u32 u; + u32 clr = 0, set = 0; struct device_node *np; int res; @@ -223,29 +225,20 @@ void __init armada_370_xp_timer_init(void) if (of_find_property(np, "marvell,timer-25Mhz", NULL)) { /* The fixed 25MHz timer is available so let's use it */ - u = readl(local_base + TIMER_CTRL_OFF); - writel(u | TIMER0_25MHZ, - local_base + TIMER_CTRL_OFF); - u = readl(timer_base + TIMER_CTRL_OFF); - writel(u | TIMER0_25MHZ, - timer_base + TIMER_CTRL_OFF); + set = TIMER0_25MHZ; timer_clk = 25000000; } else { unsigned long rate = 0; struct clk *clk = of_clk_get(np, 0); WARN_ON(IS_ERR(clk)); rate = clk_get_rate(clk); - u = readl(local_base + TIMER_CTRL_OFF); - writel(u & ~(TIMER0_25MHZ), - local_base + TIMER_CTRL_OFF); - - u = readl(timer_base + TIMER_CTRL_OFF); - writel(u & ~(TIMER0_25MHZ), - timer_base + TIMER_CTRL_OFF); - timer_clk = rate / TIMER_DIVIDER; + + clr = TIMER0_25MHZ; timer25Mhz = false; } + timer_ctrl_clrset(clr, set); + local_timer_ctrl_clrset(clr, set); /* * We use timer 0 as clocksource, and private(local) timer 0 @@ -267,10 +260,8 @@ void __init armada_370_xp_timer_init(void) writel(0xffffffff, timer_base + TIMER0_VAL_OFF); writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); - u = readl(timer_base + TIMER_CTRL_OFF); - - writel((u | TIMER0_EN | TIMER0_RELOAD_EN | - TIMER0_DIV(TIMER_DIVIDER_SHIFT)), timer_base + TIMER_CTRL_OFF); + timer_ctrl_clrset(0, TIMER0_EN | TIMER0_RELOAD_EN | + TIMER0_DIV(TIMER_DIVIDER_SHIFT)); clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, "armada_370_xp_clocksource", -- cgit v1.2.3-70-g09d2 From 573145f08c2b92c45498468afbbba909f6ce6135 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 13 Aug 2013 11:43:12 -0300 Subject: clocksource: armada-370-xp: Use CLOCKSOURCE_OF_DECLARE This is almost cosmetic: we achieve a bit of consistency with other clocksource drivers by using the CLOCKSOURCE_OF_DECLARE macro for the boilerplate code. Signed-off-by: Ezequiel Garcia Signed-off-by: Daniel Lezcano Reviewed-by: Andrew Lunn --- arch/arm/mach-mvebu/armada-370-xp.c | 4 ++-- drivers/clocksource/time-armada-370-xp.c | 6 +++--- include/linux/time-armada-370-xp.h | 18 ------------------ 3 files changed, 5 insertions(+), 23 deletions(-) delete mode 100644 include/linux/time-armada-370-xp.h (limited to 'drivers/clocksource') diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c index 97cbb802191..4ea03ad4117 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.c +++ b/arch/arm/mach-mvebu/armada-370-xp.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -69,7 +69,7 @@ static void __init armada_370_xp_mbus_init(void) static void __init armada_370_xp_timer_and_clk_init(void) { of_clk_init(NULL); - armada_370_xp_timer_init(); + clocksource_of_init(); coherency_init(); armada_370_xp_mbus_init(); #ifdef CONFIG_CACHE_L2X0 diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index abc2c9f0482..1e4b523f27c 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -212,13 +212,11 @@ static struct local_timer_ops armada_370_xp_local_timer_ops = { .stop = armada_370_xp_timer_stop, }; -void __init armada_370_xp_timer_init(void) +static void __init armada_370_xp_timer_init(struct device_node *np) { u32 clr = 0, set = 0; - struct device_node *np; int res; - np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer"); timer_base = of_iomap(np, 0); WARN_ON(!timer_base); local_base = of_iomap(np, 1); @@ -290,3 +288,5 @@ void __init armada_370_xp_timer_init(void) #endif } } +CLOCKSOURCE_OF_DECLARE(armada_370_xp, "marvell,armada-370-xp-timer", + armada_370_xp_timer_init); diff --git a/include/linux/time-armada-370-xp.h b/include/linux/time-armada-370-xp.h deleted file mode 100644 index dfdfdc03115..00000000000 --- a/include/linux/time-armada-370-xp.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Marvell Armada 370/XP SoC timer handling. - * - * Copyright (C) 2012 Marvell - * - * Lior Amsalem - * Gregory CLEMENT - * Thomas Petazzoni - * - */ -#ifndef __TIME_ARMADA_370_XPPRCMU_H -#define __TIME_ARMADA_370_XPPRCMU_H - -#include - -void __init armada_370_xp_timer_init(void); - -#endif -- cgit v1.2.3-70-g09d2 From 7cd6392c9bf5da6986103fcf5ca1b6fd0489d9b4 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 13 Aug 2013 11:43:13 -0300 Subject: clocksource: armada-370-xp: Introduce new compatibles The Armada XP SoC clocksource driver cannot work without the 25 MHz fixed timer. Therefore it's appropriate to introduce a new compatible string and use it to set the 25 MHz fixed timer. The 'marvell,timer-25MHz' property will be marked as deprecated. Signed-off-by: Ezequiel Garcia Signed-off-by: Daniel Lezcano Reviewed-by: Andrew Lunn --- drivers/clocksource/time-armada-370-xp.c | 54 +++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 15 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index 1e4b523f27c..86a354cca21 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -13,6 +13,19 @@ * * Timer 0 is used as free-running clocksource, while timer 1 is * used as clock_event_device. + * + * --- + * Clocksource driver for Armada 370 and Armada XP SoC. + * This driver implements one compatible string for each SoC, given + * each has its own characteristics: + * + * * Armada 370 has no 25 MHz fixed timer. + * + * * Armada XP cannot work properly without such 25 MHz fixed timer as + * doing otherwise leads to using a clocksource whose frequency varies + * when doing cpufreq frequency changes. + * + * See Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt */ #include @@ -212,7 +225,7 @@ static struct local_timer_ops armada_370_xp_local_timer_ops = { .stop = armada_370_xp_timer_stop, }; -static void __init armada_370_xp_timer_init(struct device_node *np) +static void __init armada_370_xp_timer_common_init(struct device_node *np) { u32 clr = 0, set = 0; int res; @@ -221,20 +234,10 @@ static void __init armada_370_xp_timer_init(struct device_node *np) WARN_ON(!timer_base); local_base = of_iomap(np, 1); - if (of_find_property(np, "marvell,timer-25Mhz", NULL)) { - /* The fixed 25MHz timer is available so let's use it */ + if (timer25Mhz) set = TIMER0_25MHZ; - timer_clk = 25000000; - } else { - unsigned long rate = 0; - struct clk *clk = of_clk_get(np, 0); - WARN_ON(IS_ERR(clk)); - rate = clk_get_rate(clk); - timer_clk = rate / TIMER_DIVIDER; - + else clr = TIMER0_25MHZ; - timer25Mhz = false; - } timer_ctrl_clrset(clr, set); local_timer_ctrl_clrset(clr, set); @@ -288,5 +291,26 @@ static void __init armada_370_xp_timer_init(struct device_node *np) #endif } } -CLOCKSOURCE_OF_DECLARE(armada_370_xp, "marvell,armada-370-xp-timer", - armada_370_xp_timer_init); + +static void __init armada_xp_timer_init(struct device_node *np) +{ + /* The fixed 25MHz timer is required, timer25Mhz is true by default */ + timer_clk = 25000000; + + armada_370_xp_timer_common_init(np); +} +CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer", + armada_xp_timer_init); + +static void __init armada_370_timer_init(struct device_node *np) +{ + struct clk *clk = of_clk_get(np, 0); + + WARN_ON(IS_ERR(clk)); + timer_clk = clk_get_rate(clk) / TIMER_DIVIDER; + timer25Mhz = false; + + armada_370_xp_timer_common_init(np); +} +CLOCKSOURCE_OF_DECLARE(armada_370, "marvell,armada-370-timer", + armada_370_timer_init); -- cgit v1.2.3-70-g09d2 From ec8e51120a5b167e22ee29f4f427a0cb66eb445b Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 20 Aug 2013 12:45:52 -0300 Subject: clocksource: armada-370-xp: Replace WARN_ON with BUG_ON If the clock fails to be obtained and the timer fails to be properly registered, the kernel will freeze real soon. Instead, let's BUG() where the actual problem is located. Signed-off-by: Ezequiel Garcia Signed-off-by: Daniel Lezcano Acked-by: Jason Cooper Acked-by: Gregory CLEMENT --- drivers/clocksource/time-armada-370-xp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index 86a354cca21..6ca185df48c 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -306,7 +306,7 @@ static void __init armada_370_timer_init(struct device_node *np) { struct clk *clk = of_clk_get(np, 0); - WARN_ON(IS_ERR(clk)); + BUG_ON(IS_ERR(clk)); timer_clk = clk_get_rate(clk) / TIMER_DIVIDER; timer25Mhz = false; -- cgit v1.2.3-70-g09d2 From 5e9fe6cb1ba5ad321473e7b9c39fbe164129520d Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 20 Aug 2013 12:45:53 -0300 Subject: clocksource: armada-370-xp: Get reference fixed-clock by name The Armada XP timer has two mandatory clock inputs: nbclk and refclk, as specified by the device-tree binding. This commit fixes the clock selection. Instead of hard-coding the clock rate for the 25 MHz reference fixed-clock, obtain the clock by its name. Signed-off-by: Ezequiel Garcia Signed-off-by: Daniel Lezcano Acked-by: Jason Cooper Acked-by: Gregory CLEMENT --- drivers/clocksource/time-armada-370-xp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index 6ca185df48c..44c4fff2f58 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -294,8 +294,11 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np) static void __init armada_xp_timer_init(struct device_node *np) { - /* The fixed 25MHz timer is required, timer25Mhz is true by default */ - timer_clk = 25000000; + struct clk *clk = of_clk_get_by_name(np, "fixed"); + + /* The 25Mhz fixed clock is mandatory, and must always be available */ + BUG_ON(IS_ERR(clk)); + timer_clk = clk_get_rate(clk); armada_370_xp_timer_common_init(np); } -- cgit v1.2.3-70-g09d2 From a1fa6f503aad8da91c4cc8dd0e71d2789d78d3f6 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Mon, 26 Aug 2013 19:08:58 +0200 Subject: clocksource: samsung_pwm_timer: Get clock from device tree When booting with device tree static clkdev aliases should not be used. This patch modifies the samsung_pwm_timer driver to use DT-based clock lookup when booting with device tree. Signed-off-by: Tomasz Figa Signed-off-by: Kyungmin Park Reviewed-by: Sylwester Nawrocki Signed-off-by: Mike Turquette --- drivers/clocksource/samsung_pwm_timer.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/clocksource') diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index 584b5472eea..32950c3ed37 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -349,10 +349,6 @@ static void __init samsung_clocksource_init(void) static void __init samsung_timer_resources(void) { - pwm.timerclk = clk_get(NULL, "timers"); - if (IS_ERR(pwm.timerclk)) - panic("failed to get timers clock for timer"); - clk_prepare_enable(pwm.timerclk); pwm.tcnt_max = (1UL << pwm.variant.bits) - 1; @@ -397,6 +393,10 @@ void __init samsung_pwm_clocksource_init(void __iomem *base, memcpy(&pwm.variant, variant, sizeof(pwm.variant)); memcpy(pwm.irq, irqs, SAMSUNG_PWM_NUM * sizeof(*irqs)); + pwm.timerclk = clk_get(NULL, "timers"); + if (IS_ERR(pwm.timerclk)) + panic("failed to get timers clock for timer"); + _samsung_pwm_clocksource_init(); } @@ -437,6 +437,10 @@ static void __init samsung_pwm_alloc(struct device_node *np, return; } + pwm.timerclk = of_clk_get_by_name(np, "timers"); + if (IS_ERR(pwm.timerclk)) + panic("failed to get timers clock for timer"); + _samsung_pwm_clocksource_init(); } -- cgit v1.2.3-70-g09d2