From d072c9658c3c2aa204c22e3ef27a0db6b4e3befa Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 15 Dec 2014 16:59:20 +0100 Subject: clocksource: sirf: Remove unused variable Commit ef89af1f4380 ("clocksource: sirf: Remove hard-coded clock rate") removes all uses of the timer_div variable. Since the variable is no longer used it should be removed. Signed-off-by: Thierry Reding Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/timer-marco.c b/drivers/clocksource/timer-marco.c index 361a789..3ddb81f 100644 --- a/drivers/clocksource/timer-marco.c +++ b/drivers/clocksource/timer-marco.c @@ -257,7 +257,6 @@ static void __init sirfsoc_clockevent_init(void) /* initialize the kernel jiffy timer source */ static void __init sirfsoc_marco_timer_init(struct device_node *np) { - u32 timer_div; struct clk *clk; clk = of_clk_get(np, 0); -- cgit v0.10.2 From 5833ac98651f7985037e52d4b41f7d4e02e32064 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Mon, 12 Jan 2015 00:04:43 +0800 Subject: clocksource: marco: Rename marco to atlas7 marco project is replaced by atlas7 and we should obliterate its all traces. Signed-off-by: Barry Song Acked-by: Arnd Bergmann Acked-by: Daniel Lezcano Signed-off-by: Daniel Lezcano diff --git a/MAINTAINERS b/MAINTAINERS index 2fa3853..f6923cf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -958,7 +958,7 @@ S: Maintained F: arch/arm/mach-prima2/ F: drivers/clk/sirf/ F: drivers/clocksource/timer-prima2.c -F: drivers/clocksource/timer-marco.c +F: drivers/clocksource/timer-atlas7.c N: [^a-z]sirf ARM/EBSA110 MACHINE SUPPORT diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 94d90b2..306bc47 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -18,7 +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_CLPS711X) += clps711x-timer.o -obj-$(CONFIG_ARCH_MARCO) += timer-marco.o +obj-$(CONFIG_ARCH_ATLAS7) += timer-atlas7.o obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o obj-$(CONFIG_ARCH_MXS) += mxs_timer.o obj-$(CONFIG_ARCH_PXA) += pxa_timer.o diff --git a/drivers/clocksource/timer-atlas7.c b/drivers/clocksource/timer-atlas7.c new file mode 100644 index 0000000..60f9de3 --- /dev/null +++ b/drivers/clocksource/timer-atlas7.c @@ -0,0 +1,306 @@ +/* + * System timer for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000 +#define SIRFSOC_TIMER_32COUNTER_1_CTRL 0x0004 +#define SIRFSOC_TIMER_MATCH_0 0x0018 +#define SIRFSOC_TIMER_MATCH_1 0x001c +#define SIRFSOC_TIMER_COUNTER_0 0x0048 +#define SIRFSOC_TIMER_COUNTER_1 0x004c +#define SIRFSOC_TIMER_INTR_STATUS 0x0060 +#define SIRFSOC_TIMER_WATCHDOG_EN 0x0064 +#define SIRFSOC_TIMER_64COUNTER_CTRL 0x0068 +#define SIRFSOC_TIMER_64COUNTER_LO 0x006c +#define SIRFSOC_TIMER_64COUNTER_HI 0x0070 +#define SIRFSOC_TIMER_64COUNTER_LOAD_LO 0x0074 +#define SIRFSOC_TIMER_64COUNTER_LOAD_HI 0x0078 +#define SIRFSOC_TIMER_64COUNTER_RLATCHED_LO 0x007c +#define SIRFSOC_TIMER_64COUNTER_RLATCHED_HI 0x0080 + +#define SIRFSOC_TIMER_REG_CNT 6 + +static unsigned long atlas7_timer_rate; + +static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = { + SIRFSOC_TIMER_WATCHDOG_EN, + SIRFSOC_TIMER_32COUNTER_0_CTRL, + SIRFSOC_TIMER_32COUNTER_1_CTRL, + SIRFSOC_TIMER_64COUNTER_CTRL, + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO, + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI, +}; + +static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT]; + +static void __iomem *sirfsoc_timer_base; + +/* disable count and interrupt */ +static inline void sirfsoc_timer_count_disable(int idx) +{ + writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) & ~0x7, + sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx); +} + +/* enable count and interrupt */ +static inline void sirfsoc_timer_count_enable(int idx) +{ + writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) | 0x3, + sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx); +} + +/* timer interrupt handler */ +static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *ce = dev_id; + int cpu = smp_processor_id(); + + /* clear timer interrupt */ + writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS); + + if (ce->mode == CLOCK_EVT_MODE_ONESHOT) + sirfsoc_timer_count_disable(cpu); + + ce->event_handler(ce); + + return IRQ_HANDLED; +} + +/* read 64-bit timer counter */ +static cycle_t sirfsoc_timer_read(struct clocksource *cs) +{ + u64 cycles; + + writel_relaxed((readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) | + BIT(0)) & ~BIT(1), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); + + cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI); + cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO); + + return cycles; +} + +static int sirfsoc_timer_set_next_event(unsigned long delta, + struct clock_event_device *ce) +{ + int cpu = smp_processor_id(); + + /* disable timer first, then modify the related registers */ + sirfsoc_timer_count_disable(cpu); + + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0 + + 4 * cpu); + writel_relaxed(delta, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0 + + 4 * cpu); + + /* enable the tick */ + sirfsoc_timer_count_enable(cpu); + + return 0; +} + +static void sirfsoc_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *ce) +{ + switch (mode) { + case CLOCK_EVT_MODE_ONESHOT: + /* enable in set_next_event */ + break; + default: + break; + } + + sirfsoc_timer_count_disable(smp_processor_id()); +} + +static void sirfsoc_clocksource_suspend(struct clocksource *cs) +{ + int i; + + for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++) + sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); +} + +static void sirfsoc_clocksource_resume(struct clocksource *cs) +{ + int i; + + for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++) + writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); + + writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2], + sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO); + writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1], + sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI); + + writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) | + BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); +} + +static struct clock_event_device __percpu *sirfsoc_clockevent; + +static struct clocksource sirfsoc_clocksource = { + .name = "sirfsoc_clocksource", + .rating = 200, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .read = sirfsoc_timer_read, + .suspend = sirfsoc_clocksource_suspend, + .resume = sirfsoc_clocksource_resume, +}; + +static struct irqaction sirfsoc_timer_irq = { + .name = "sirfsoc_timer0", + .flags = IRQF_TIMER | IRQF_NOBALANCING, + .handler = sirfsoc_timer_interrupt, +}; + +static struct irqaction sirfsoc_timer1_irq = { + .name = "sirfsoc_timer1", + .flags = IRQF_TIMER | IRQF_NOBALANCING, + .handler = sirfsoc_timer_interrupt, +}; + +static int sirfsoc_local_timer_setup(struct clock_event_device *ce) +{ + int cpu = smp_processor_id(); + struct irqaction *action; + + if (cpu == 0) + action = &sirfsoc_timer_irq; + else + action = &sirfsoc_timer1_irq; + + ce->irq = action->irq; + ce->name = "local_timer"; + 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; + clockevents_calc_mult_shift(ce, atlas7_timer_rate, 60); + ce->max_delta_ns = clockevent_delta2ns(-2, ce); + ce->min_delta_ns = clockevent_delta2ns(2, ce); + ce->cpumask = cpumask_of(cpu); + + action->dev_id = ce; + BUG_ON(setup_irq(ce->irq, action)); + irq_force_affinity(action->irq, cpumask_of(cpu)); + + clockevents_register_device(ce); + return 0; +} + +static void sirfsoc_local_timer_stop(struct clock_event_device *ce) +{ + int cpu = smp_processor_id(); + + sirfsoc_timer_count_disable(1); + + if (cpu == 0) + remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq); + else + remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq); +} + +static int 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 = { + .notifier_call = sirfsoc_cpu_notify, +}; + +static void __init sirfsoc_clockevent_init(void) +{ + 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 */ +static void __init sirfsoc_atlas7_timer_init(struct device_node *np) +{ + struct clk *clk; + + clk = of_clk_get(np, 0); + BUG_ON(IS_ERR(clk)); + + BUG_ON(clk_prepare_enable(clk)); + + atlas7_timer_rate = clk_get_rate(clk); + + /* timer dividers: 0, not divided */ + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL); + + /* Initialize timer counters to 0 */ + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI); + writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) | + BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_1); + + /* Clear all interrupts */ + writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS); + + BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, atlas7_timer_rate)); + + sirfsoc_clockevent_init(); +} + +static void __init sirfsoc_of_timer_init(struct device_node *np) +{ + sirfsoc_timer_base = of_iomap(np, 0); + if (!sirfsoc_timer_base) + panic("unable to map timer cpu registers\n"); + + sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0); + if (!sirfsoc_timer_irq.irq) + panic("No irq passed for timer0 via DT\n"); + + 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"); + + sirfsoc_atlas7_timer_init(np); +} +CLOCKSOURCE_OF_DECLARE(sirfsoc_atlas7_timer, "sirf,atlas7-tick", sirfsoc_of_timer_init); diff --git a/drivers/clocksource/timer-marco.c b/drivers/clocksource/timer-marco.c deleted file mode 100644 index 3ddb81f..0000000 --- a/drivers/clocksource/timer-marco.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * System timer for CSR SiRFprimaII - * - * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. - * - * Licensed under GPLv2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000 -#define SIRFSOC_TIMER_32COUNTER_1_CTRL 0x0004 -#define SIRFSOC_TIMER_MATCH_0 0x0018 -#define SIRFSOC_TIMER_MATCH_1 0x001c -#define SIRFSOC_TIMER_COUNTER_0 0x0048 -#define SIRFSOC_TIMER_COUNTER_1 0x004c -#define SIRFSOC_TIMER_INTR_STATUS 0x0060 -#define SIRFSOC_TIMER_WATCHDOG_EN 0x0064 -#define SIRFSOC_TIMER_64COUNTER_CTRL 0x0068 -#define SIRFSOC_TIMER_64COUNTER_LO 0x006c -#define SIRFSOC_TIMER_64COUNTER_HI 0x0070 -#define SIRFSOC_TIMER_64COUNTER_LOAD_LO 0x0074 -#define SIRFSOC_TIMER_64COUNTER_LOAD_HI 0x0078 -#define SIRFSOC_TIMER_64COUNTER_RLATCHED_LO 0x007c -#define SIRFSOC_TIMER_64COUNTER_RLATCHED_HI 0x0080 - -#define SIRFSOC_TIMER_REG_CNT 6 - -static unsigned long marco_timer_rate; - -static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = { - SIRFSOC_TIMER_WATCHDOG_EN, - SIRFSOC_TIMER_32COUNTER_0_CTRL, - SIRFSOC_TIMER_32COUNTER_1_CTRL, - SIRFSOC_TIMER_64COUNTER_CTRL, - SIRFSOC_TIMER_64COUNTER_RLATCHED_LO, - SIRFSOC_TIMER_64COUNTER_RLATCHED_HI, -}; - -static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT]; - -static void __iomem *sirfsoc_timer_base; - -/* disable count and interrupt */ -static inline void sirfsoc_timer_count_disable(int idx) -{ - writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) & ~0x7, - sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx); -} - -/* enable count and interrupt */ -static inline void sirfsoc_timer_count_enable(int idx) -{ - writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) | 0x3, - sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx); -} - -/* timer interrupt handler */ -static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *ce = dev_id; - int cpu = smp_processor_id(); - - /* clear timer interrupt */ - writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS); - - if (ce->mode == CLOCK_EVT_MODE_ONESHOT) - sirfsoc_timer_count_disable(cpu); - - ce->event_handler(ce); - - return IRQ_HANDLED; -} - -/* read 64-bit timer counter */ -static cycle_t sirfsoc_timer_read(struct clocksource *cs) -{ - u64 cycles; - - writel_relaxed((readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) | - BIT(0)) & ~BIT(1), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); - - cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI); - cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO); - - return cycles; -} - -static int sirfsoc_timer_set_next_event(unsigned long delta, - struct clock_event_device *ce) -{ - int cpu = smp_processor_id(); - - /* disable timer first, then modify the related registers */ - sirfsoc_timer_count_disable(cpu); - - writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0 + - 4 * cpu); - writel_relaxed(delta, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0 + - 4 * cpu); - - /* enable the tick */ - sirfsoc_timer_count_enable(cpu); - - return 0; -} - -static void sirfsoc_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *ce) -{ - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - /* enable in set_next_event */ - break; - default: - break; - } - - sirfsoc_timer_count_disable(smp_processor_id()); -} - -static void sirfsoc_clocksource_suspend(struct clocksource *cs) -{ - int i; - - for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++) - sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); -} - -static void sirfsoc_clocksource_resume(struct clocksource *cs) -{ - int i; - - for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++) - writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); - - writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2], - sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO); - writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1], - sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI); - - writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) | - BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); -} - -static struct clock_event_device __percpu *sirfsoc_clockevent; - -static struct clocksource sirfsoc_clocksource = { - .name = "sirfsoc_clocksource", - .rating = 200, - .mask = CLOCKSOURCE_MASK(64), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, - .read = sirfsoc_timer_read, - .suspend = sirfsoc_clocksource_suspend, - .resume = sirfsoc_clocksource_resume, -}; - -static struct irqaction sirfsoc_timer_irq = { - .name = "sirfsoc_timer0", - .flags = IRQF_TIMER | IRQF_NOBALANCING, - .handler = sirfsoc_timer_interrupt, -}; - -static struct irqaction sirfsoc_timer1_irq = { - .name = "sirfsoc_timer1", - .flags = IRQF_TIMER | IRQF_NOBALANCING, - .handler = sirfsoc_timer_interrupt, -}; - -static int sirfsoc_local_timer_setup(struct clock_event_device *ce) -{ - int cpu = smp_processor_id(); - struct irqaction *action; - - if (cpu == 0) - action = &sirfsoc_timer_irq; - else - action = &sirfsoc_timer1_irq; - - ce->irq = action->irq; - ce->name = "local_timer"; - 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; - clockevents_calc_mult_shift(ce, marco_timer_rate, 60); - ce->max_delta_ns = clockevent_delta2ns(-2, ce); - ce->min_delta_ns = clockevent_delta2ns(2, ce); - ce->cpumask = cpumask_of(cpu); - - action->dev_id = ce; - BUG_ON(setup_irq(ce->irq, action)); - irq_force_affinity(action->irq, cpumask_of(cpu)); - - clockevents_register_device(ce); - return 0; -} - -static void sirfsoc_local_timer_stop(struct clock_event_device *ce) -{ - int cpu = smp_processor_id(); - - sirfsoc_timer_count_disable(1); - - if (cpu == 0) - remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq); - else - remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq); -} - -static int 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 = { - .notifier_call = sirfsoc_cpu_notify, -}; - -static void __init sirfsoc_clockevent_init(void) -{ - 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 */ -static void __init sirfsoc_marco_timer_init(struct device_node *np) -{ - struct clk *clk; - - clk = of_clk_get(np, 0); - BUG_ON(IS_ERR(clk)); - - BUG_ON(clk_prepare_enable(clk)); - - marco_timer_rate = clk_get_rate(clk); - - /* timer dividers: 0, not divided */ - writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); - writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL); - writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL); - - /* Initialize timer counters to 0 */ - writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO); - writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI); - writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) | - BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); - writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0); - writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_1); - - /* Clear all interrupts */ - writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS); - - BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, marco_timer_rate)); - - sirfsoc_clockevent_init(); -} - -static void __init sirfsoc_of_timer_init(struct device_node *np) -{ - sirfsoc_timer_base = of_iomap(np, 0); - if (!sirfsoc_timer_base) - panic("unable to map timer cpu registers\n"); - - sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0); - if (!sirfsoc_timer_irq.irq) - panic("No irq passed for timer0 via DT\n"); - - 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"); - - sirfsoc_marco_timer_init(np); -} -CLOCKSOURCE_OF_DECLARE(sirfsoc_marco_timer, "sirf,marco-tick", sirfsoc_of_timer_init ); -- cgit v0.10.2 From 8d8bd7be8bf0981564fd557d4b68eeeaaa2325d0 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 8 Jan 2015 10:07:22 +0100 Subject: ARM: clocksource: Add asm9260_timer driver In some cases asm9260 looks similar to iMX2x. One of exceptions is timer controller. So this patch introduces new driver for this special case. Signed-off-by: Oleksij Rempel Acked-by: Daniel Lezcano Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index fc01ec2..bfaaae4 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -229,4 +229,14 @@ config CLKSRC_MIPS_GIC depends on MIPS_GIC select CLKSRC_OF +config ASM9260_TIMER + bool "Alphascale ASM9260 timer driver" + depends on GENERIC_CLOCKEVENTS + select CLKSRC_MMIO + select CLKSRC_OF + default y if MACH_ASM9260 + help + This enables build of a clocksource and clockevent driver for + the 32-bit System Timer hardware available on a Alphascale ASM9260. + endmenu diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 306bc47..e5661cc 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -48,3 +48,4 @@ obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o +obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o diff --git a/drivers/clocksource/asm9260_timer.c b/drivers/clocksource/asm9260_timer.c new file mode 100644 index 0000000..2c9c993 --- /dev/null +++ b/drivers/clocksource/asm9260_timer.c @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2014 Oleksij Rempel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "asm9260-timer" + +/* + * this device provide 4 offsets for each register: + * 0x0 - plain read write mode + * 0x4 - set mode, OR logic. + * 0x8 - clr mode, XOR logic. + * 0xc - togle mode. + */ +#define SET_REG 4 +#define CLR_REG 8 + +#define HW_IR 0x0000 /* RW. Interrupt */ +#define BM_IR_CR0 BIT(4) +#define BM_IR_MR3 BIT(3) +#define BM_IR_MR2 BIT(2) +#define BM_IR_MR1 BIT(1) +#define BM_IR_MR0 BIT(0) + +#define HW_TCR 0x0010 /* RW. Timer controller */ +/* BM_C*_RST + * Timer Counter and the Prescale Counter are synchronously reset on the + * next positive edge of PCLK. The counters remain reset until TCR[1] is + * returned to zero. */ +#define BM_C3_RST BIT(7) +#define BM_C2_RST BIT(6) +#define BM_C1_RST BIT(5) +#define BM_C0_RST BIT(4) +/* BM_C*_EN + * 1 - Timer Counter and Prescale Counter are enabled for counting + * 0 - counters are disabled */ +#define BM_C3_EN BIT(3) +#define BM_C2_EN BIT(2) +#define BM_C1_EN BIT(1) +#define BM_C0_EN BIT(0) + +#define HW_DIR 0x0020 /* RW. Direction? */ +/* 00 - count up + * 01 - count down + * 10 - ?? 2^n/2 */ +#define BM_DIR_COUNT_UP 0 +#define BM_DIR_COUNT_DOWN 1 +#define BM_DIR0_SHIFT 0 +#define BM_DIR1_SHIFT 4 +#define BM_DIR2_SHIFT 8 +#define BM_DIR3_SHIFT 12 +#define BM_DIR_DEFAULT (BM_DIR_COUNT_UP << BM_DIR0_SHIFT | \ + BM_DIR_COUNT_UP << BM_DIR1_SHIFT | \ + BM_DIR_COUNT_UP << BM_DIR2_SHIFT | \ + BM_DIR_COUNT_UP << BM_DIR3_SHIFT) + +#define HW_TC0 0x0030 /* RO. Timer counter 0 */ +/* HW_TC*. Timer counter owerflow (0xffff.ffff to 0x0000.0000) do not generate + * interrupt. This registers can be used to detect overflow */ +#define HW_TC1 0x0040 +#define HW_TC2 0x0050 +#define HW_TC3 0x0060 + +#define HW_PR 0x0070 /* RW. prescaler */ +#define BM_PR_DISABLE 0 +#define HW_PC 0x0080 /* RO. Prescaler counter */ +#define HW_MCR 0x0090 /* RW. Match control */ +/* enable interrupt on match */ +#define BM_MCR_INT_EN(n) (1 << (n * 3 + 0)) +/* enable TC reset on match */ +#define BM_MCR_RES_EN(n) (1 << (n * 3 + 1)) +/* enable stop TC on match */ +#define BM_MCR_STOP_EN(n) (1 << (n * 3 + 2)) + +#define HW_MR0 0x00a0 /* RW. Match reg */ +#define HW_MR1 0x00b0 +#define HW_MR2 0x00C0 +#define HW_MR3 0x00D0 + +#define HW_CTCR 0x0180 /* Counter control */ +#define BM_CTCR0_SHIFT 0 +#define BM_CTCR1_SHIFT 2 +#define BM_CTCR2_SHIFT 4 +#define BM_CTCR3_SHIFT 6 +#define BM_CTCR_TM 0 /* Timer mode. Every rising PCLK edge. */ +#define BM_CTCR_DEFAULT (BM_CTCR_TM << BM_CTCR0_SHIFT | \ + BM_CTCR_TM << BM_CTCR1_SHIFT | \ + BM_CTCR_TM << BM_CTCR2_SHIFT | \ + BM_CTCR_TM << BM_CTCR3_SHIFT) + +static struct asm9260_timer_priv { + void __iomem *base; + unsigned long ticks_per_jiffy; +} priv; + +static int asm9260_timer_set_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + /* configure match count for TC0 */ + writel_relaxed(delta, priv.base + HW_MR0); + /* enable TC0 */ + writel_relaxed(BM_C0_EN, priv.base + HW_TCR + SET_REG); + return 0; +} + +static void asm9260_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + /* stop timer0 */ + writel_relaxed(BM_C0_EN, priv.base + HW_TCR + CLR_REG); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + /* disable reset and stop on match */ + writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0), + priv.base + HW_MCR + CLR_REG); + /* configure match count for TC0 */ + writel_relaxed(priv.ticks_per_jiffy, priv.base + HW_MR0); + /* enable TC0 */ + writel_relaxed(BM_C0_EN, priv.base + HW_TCR + SET_REG); + break; + case CLOCK_EVT_MODE_ONESHOT: + /* enable reset and stop on match */ + writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0), + priv.base + HW_MCR + SET_REG); + break; + default: + break; + } +} + +static struct clock_event_device event_dev = { + .name = DRIVER_NAME, + .rating = 200, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_next_event = asm9260_timer_set_next_event, + .set_mode = asm9260_timer_set_mode, +}; + +static irqreturn_t asm9260_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + evt->event_handler(evt); + + writel_relaxed(BM_IR_MR0, priv.base + HW_IR); + + return IRQ_HANDLED; +} + +/* + * --------------------------------------------------------------------------- + * Timer initialization + * --------------------------------------------------------------------------- + */ +static void __init asm9260_timer_init(struct device_node *np) +{ + int irq; + struct clk *clk; + int ret; + unsigned long rate; + + priv.base = of_io_request_and_map(np, 0, np->name); + if (!priv.base) + panic("%s: unable to map resource", np->name); + + clk = of_clk_get(np, 0); + + ret = clk_prepare_enable(clk); + if (ret) + panic("Failed to enable clk!\n"); + + irq = irq_of_parse_and_map(np, 0); + ret = request_irq(irq, asm9260_timer_interrupt, IRQF_TIMER, + DRIVER_NAME, &event_dev); + if (ret) + panic("Failed to setup irq!\n"); + + /* set all timers for count-up */ + writel_relaxed(BM_DIR_DEFAULT, priv.base + HW_DIR); + /* disable divider */ + writel_relaxed(BM_PR_DISABLE, priv.base + HW_PR); + /* make sure all timers use every rising PCLK edge. */ + writel_relaxed(BM_CTCR_DEFAULT, priv.base + HW_CTCR); + /* enable interrupt for TC0 and clean setting for all other lines */ + writel_relaxed(BM_MCR_INT_EN(0) , priv.base + HW_MCR); + + rate = clk_get_rate(clk); + clocksource_mmio_init(priv.base + HW_TC1, DRIVER_NAME, rate, + 200, 32, clocksource_mmio_readl_up); + + /* Seems like we can't use counter without match register even if + * actions for MR are disabled. So, set MR to max value. */ + writel_relaxed(0xffffffff, priv.base + HW_MR1); + /* enable TC1 */ + writel_relaxed(BM_C1_EN, priv.base + HW_TCR + SET_REG); + + priv.ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ); + event_dev.cpumask = cpumask_of(0); + clockevents_config_and_register(&event_dev, rate, 0x2c00, 0xfffffffe); +} +CLOCKSOURCE_OF_DECLARE(asm9260_timer, "alphascale,asm9260-timer", + asm9260_timer_init); -- cgit v0.10.2 From 468b8c4cf3962d4d24eca58da18bb63368ff4fcd Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Sun, 25 Jan 2015 22:06:02 +0100 Subject: clockevents: rockchip: Add rockchip timer for rk3288 The rk3288 board uses the architected timers and these ones are shutdown when the cpu is powered down. There is a need of a broadcast timer in this case to ensure proper wakeup when the cpus are in sleep mode and a timer expires. This driver provides the basic timer functionnality as a backup for the local timers at sleep time. The timer belongs to the alive subsystem. It includes two programmables 64 bits timer channels but the driver only uses 32bits. It works with two operations mode: free running and user defined count. Programing sequence: 1. Timer initialization: * Disable the timer by writing '0' to the CONTROLREG register * Program the timer mode by writing the mode to the CONTROLREG register * Set the interrupt mask 2. Setting the count value: * Load the count value to the registers COUNT0 and COUNT1 (not used). 3. Enable the timer * Write '1' to the CONTROLREG register with the mode (free running or user) Signed-off-by: Daniel Lezcano Reviewed-by: Heiko Stuebner diff --git a/Documentation/devicetree/bindings/timer/rockchip,rk3288-timer.txt b/Documentation/devicetree/bindings/timer/rockchip,rk3288-timer.txt new file mode 100644 index 0000000..87f0b00 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/rockchip,rk3288-timer.txt @@ -0,0 +1,18 @@ +Rockchip rk3288 timer + +Required properties: +- compatible: shall be "rockchip,rk3288-timer" +- reg: base address of the timer register starting with TIMERS CONTROL register +- interrupts: should contain the interrupts for Timer0 +- clocks : must contain an entry for each entry in clock-names +- clock-names : must include the following entries: + "timer", "pclk" + +Example: + timer: timer@ff810000 { + compatible = "rockchip,rk3288-timer"; + reg = <0xff810000 0x20>; + interrupts = ; + clocks = <&xin24m>, <&cru PCLK_TIMER>; + clock-names = "timer", "pclk"; + }; diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig index ac5803c..5078932 100644 --- a/arch/arm/mach-rockchip/Kconfig +++ b/arch/arm/mach-rockchip/Kconfig @@ -11,6 +11,7 @@ config ARCH_ROCKCHIP select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP select DW_APB_TIMER_OF + select ROCKCHIP_TIMER select ARM_GLOBAL_TIMER select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK help diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index bfaaae4..a89120b 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -26,6 +26,10 @@ config DW_APB_TIMER_OF select DW_APB_TIMER select CLKSRC_OF +config ROCKCHIP_TIMER + bool + select CLKSRC_OF + config ARMADA_370_XP_TIMER bool select CLKSRC_OF diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index e5661cc..21c11e2 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_CLKBLD_I8253) += i8253.o obj-$(CONFIG_CLKSRC_MMIO) += mmio.o obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o +obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c new file mode 100644 index 0000000..a35993b --- /dev/null +++ b/drivers/clocksource/rockchip_timer.c @@ -0,0 +1,180 @@ +/* + * Rockchip timer support + * + * Copyright (C) Daniel Lezcano + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include + +#define TIMER_NAME "rk_timer" + +#define TIMER_LOAD_COUNT0 0x00 +#define TIMER_LOAD_COUNT1 0x04 +#define TIMER_CONTROL_REG 0x10 +#define TIMER_INT_STATUS 0x18 + +#define TIMER_DISABLE 0x0 +#define TIMER_ENABLE 0x1 +#define TIMER_MODE_FREE_RUNNING (0 << 1) +#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1) +#define TIMER_INT_UNMASK (1 << 2) + +struct bc_timer { + struct clock_event_device ce; + void __iomem *base; + u32 freq; +}; + +static struct bc_timer bc_timer; + +static inline struct bc_timer *rk_timer(struct clock_event_device *ce) +{ + return container_of(ce, struct bc_timer, ce); +} + +static inline void __iomem *rk_base(struct clock_event_device *ce) +{ + return rk_timer(ce)->base; +} + +static inline void rk_timer_disable(struct clock_event_device *ce) +{ + writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG); + dsb(); +} + +static inline void rk_timer_enable(struct clock_event_device *ce, u32 flags) +{ + writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags, + rk_base(ce) + TIMER_CONTROL_REG); + dsb(); +} + +static void rk_timer_update_counter(unsigned long cycles, + struct clock_event_device *ce) +{ + writel_relaxed(cycles, rk_base(ce) + TIMER_LOAD_COUNT0); + writel_relaxed(0, rk_base(ce) + TIMER_LOAD_COUNT1); + dsb(); +} + +static void rk_timer_interrupt_clear(struct clock_event_device *ce) +{ + writel_relaxed(1, rk_base(ce) + TIMER_INT_STATUS); + dsb(); +} + +static inline int rk_timer_set_next_event(unsigned long cycles, + struct clock_event_device *ce) +{ + rk_timer_disable(ce); + rk_timer_update_counter(cycles, ce); + rk_timer_enable(ce, TIMER_MODE_USER_DEFINED_COUNT); + return 0; +} + +static inline void rk_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *ce) +{ + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + rk_timer_disable(ce); + rk_timer_update_counter(rk_timer(ce)->freq / HZ - 1, ce); + rk_timer_enable(ce, TIMER_MODE_FREE_RUNNING); + break; + case CLOCK_EVT_MODE_ONESHOT: + case CLOCK_EVT_MODE_RESUME: + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + rk_timer_disable(ce); + break; + } +} + +static irqreturn_t rk_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *ce = dev_id; + + rk_timer_interrupt_clear(ce); + + if (ce->mode == CLOCK_EVT_MODE_ONESHOT) + rk_timer_disable(ce); + + ce->event_handler(ce); + + return IRQ_HANDLED; +} + +static void __init rk_timer_init(struct device_node *np) +{ + struct clock_event_device *ce = &bc_timer.ce; + struct clk *timer_clk; + struct clk *pclk; + int ret, irq; + + bc_timer.base = of_iomap(np, 0); + if (!bc_timer.base) { + pr_err("Failed to get base address for '%s'\n", TIMER_NAME); + return; + } + + pclk = of_clk_get_by_name(np, "pclk"); + if (IS_ERR(pclk)) { + pr_err("Failed to get pclk for '%s'\n", TIMER_NAME); + return; + } + + if (clk_prepare_enable(pclk)) { + pr_err("Failed to enable pclk for '%s'\n", TIMER_NAME); + return; + } + + timer_clk = of_clk_get_by_name(np, "timer"); + if (IS_ERR(timer_clk)) { + pr_err("Failed to get timer clock for '%s'\n", TIMER_NAME); + return; + } + + if (clk_prepare_enable(timer_clk)) { + pr_err("Failed to enable timer clock\n"); + return; + } + + bc_timer.freq = clk_get_rate(timer_clk); + + irq = irq_of_parse_and_map(np, 0); + if (irq == NO_IRQ) { + pr_err("Failed to map interrupts for '%s'\n", TIMER_NAME); + return; + } + + ce->name = TIMER_NAME; + ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + ce->set_next_event = rk_timer_set_next_event; + ce->set_mode = rk_timer_set_mode; + ce->irq = irq; + ce->cpumask = cpumask_of(0); + ce->rating = 250; + + rk_timer_interrupt_clear(ce); + rk_timer_disable(ce); + + ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce); + if (ret) { + pr_err("Failed to initialize '%s': %d\n", TIMER_NAME, ret); + return; + } + + clockevents_config_and_register(ce, bc_timer.freq, 1, UINT_MAX); +} +CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init); -- cgit v0.10.2 From 9ff99be7dc69a56ec16d5a928a4e7622023abda5 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Mon, 26 Jan 2015 20:35:17 +0200 Subject: clocksource: devicetree: Document Conexant Digicolor timer binding The Conexant CX92755 SoC provides 8 32-bit timers as part of its so called "Agent Communication" block. Timers can be configures either as free running or one shot. Each timer has a dedicated interrupt source in the CX92755 interrupts controller. The first timer (Timer A) can also be configured as watchdog. This commit adds devicetree binding definition of this hardware module. The binding defined here should be reusable for other SoCs in the Digicolor series. Signed-off-by: Baruch Siach Signed-off-by: Daniel Lezcano diff --git a/Documentation/devicetree/bindings/timer/digicolor-timer.txt b/Documentation/devicetree/bindings/timer/digicolor-timer.txt new file mode 100644 index 0000000..d1b659b --- /dev/null +++ b/Documentation/devicetree/bindings/timer/digicolor-timer.txt @@ -0,0 +1,18 @@ +Conexant Digicolor SoCs Timer Controller + +Required properties: + +- compatible : should be "cnxt,cx92755-timer" +- reg : Specifies base physical address and size of the "Agent Communication" + timer registers +- interrupts : Contains 8 interrupts, one for each timer +- clocks: phandle to the main clock + +Example: + + timer@f0000fc0 { + compatible = "cnxt,cx92755-timer"; + reg = <0xf0000fc0 0x40>; + interrupts = <19>, <31>, <34>, <35>, <52>, <53>, <54>, <55>; + clocks = <&main_clk>; + }; -- cgit v0.10.2 From 9b8bb7736b78e954044e12b94a2b16aafb0ee0e3 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Mon, 26 Jan 2015 20:35:18 +0200 Subject: clocksource: Driver for Conexant Digicolor SoC timer Add clocksource driver to the Conexant CX92755 SoC, part of the Digicolor SoCs series. Hardware provides 8 timers, A to H. Timer A is dedicated to a future watchdog driver so we don't use it here. Use timer B for sched_clock, and timer C for clock_event. Signed-off-by: Baruch Siach Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index a89120b..72a3827 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -18,6 +18,9 @@ config CLKBLD_I8253 config CLKSRC_MMIO bool +config DIGICOLOR_TIMER + bool + config DW_APB_TIMER bool diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 21c11e2..0f8003d 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o obj-$(CONFIG_EM_TIMER_STI) += em_sti.o obj-$(CONFIG_CLKBLD_I8253) += i8253.o obj-$(CONFIG_CLKSRC_MMIO) += mmio.o +obj-$(CONFIG_DIGICOLOR_TIMER) += timer-digicolor.o obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o diff --git a/drivers/clocksource/timer-digicolor.c b/drivers/clocksource/timer-digicolor.c new file mode 100644 index 0000000..7f8388c --- /dev/null +++ b/drivers/clocksource/timer-digicolor.c @@ -0,0 +1,199 @@ +/* + * Conexant Digicolor timer driver + * + * Author: Baruch Siach + * + * Copyright (C) 2014 Paradox Innovation Ltd. + * + * Based on: + * Allwinner SoCs hstimer driver + * + * Copyright (C) 2013 Maxime Ripard + * + * Maxime Ripard + * + * 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. + */ + +/* + * Conexant Digicolor SoCs have 8 configurable timers, named from "Timer A" to + * "Timer H". Timer A is the only one with watchdog support, so it is dedicated + * to the watchdog driver. This driver uses Timer B for sched_clock(), and + * Timer C for clockevents. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + TIMER_A, + TIMER_B, + TIMER_C, + TIMER_D, + TIMER_E, + TIMER_F, + TIMER_G, + TIMER_H, +}; + +#define CONTROL(t) ((t)*8) +#define COUNT(t) ((t)*8 + 4) + +#define CONTROL_DISABLE 0 +#define CONTROL_ENABLE BIT(0) +#define CONTROL_MODE(m) ((m) << 4) +#define CONTROL_MODE_ONESHOT CONTROL_MODE(1) +#define CONTROL_MODE_PERIODIC CONTROL_MODE(2) + +struct digicolor_timer { + struct clock_event_device ce; + void __iomem *base; + u32 ticks_per_jiffy; + int timer_id; /* one of TIMER_* */ +}; + +struct digicolor_timer *dc_timer(struct clock_event_device *ce) +{ + return container_of(ce, struct digicolor_timer, ce); +} + +static inline void dc_timer_disable(struct clock_event_device *ce) +{ + struct digicolor_timer *dt = dc_timer(ce); + writeb(CONTROL_DISABLE, dt->base + CONTROL(dt->timer_id)); +} + +static inline void dc_timer_enable(struct clock_event_device *ce, u32 mode) +{ + struct digicolor_timer *dt = dc_timer(ce); + writeb(CONTROL_ENABLE | mode, dt->base + CONTROL(dt->timer_id)); +} + +static inline void dc_timer_set_count(struct clock_event_device *ce, + unsigned long count) +{ + struct digicolor_timer *dt = dc_timer(ce); + writel(count, dt->base + COUNT(dt->timer_id)); +} + +static void digicolor_clkevt_mode(enum clock_event_mode mode, + struct clock_event_device *ce) +{ + struct digicolor_timer *dt = dc_timer(ce); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + dc_timer_disable(ce); + dc_timer_set_count(ce, dt->ticks_per_jiffy); + dc_timer_enable(ce, CONTROL_MODE_PERIODIC); + break; + case CLOCK_EVT_MODE_ONESHOT: + dc_timer_disable(ce); + dc_timer_enable(ce, CONTROL_MODE_ONESHOT); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + dc_timer_disable(ce); + break; + } +} + +static int digicolor_clkevt_next_event(unsigned long evt, + struct clock_event_device *ce) +{ + dc_timer_disable(ce); + dc_timer_set_count(ce, evt); + dc_timer_enable(ce, CONTROL_MODE_ONESHOT); + + return 0; +} + +static struct digicolor_timer dc_timer_dev = { + .ce = { + .name = "digicolor_tick", + .rating = 340, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = digicolor_clkevt_mode, + .set_next_event = digicolor_clkevt_next_event, + }, + .timer_id = TIMER_C, +}; + +static irqreturn_t digicolor_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static u64 digicolor_timer_sched_read(void) +{ + return ~readl(dc_timer_dev.base + COUNT(TIMER_B)); +} + +static void __init digicolor_timer_init(struct device_node *node) +{ + unsigned long rate; + struct clk *clk; + int ret, irq; + + /* + * timer registers are shared with the watchdog timer; + * don't map exclusively + */ + dc_timer_dev.base = of_iomap(node, 0); + if (!dc_timer_dev.base) { + pr_err("Can't map registers"); + return; + } + + irq = irq_of_parse_and_map(node, dc_timer_dev.timer_id); + if (irq <= 0) { + pr_err("Can't parse IRQ"); + return; + } + + clk = of_clk_get(node, 0); + if (IS_ERR(clk)) { + pr_err("Can't get timer clock"); + return; + } + clk_prepare_enable(clk); + rate = clk_get_rate(clk); + dc_timer_dev.ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); + + writeb(CONTROL_DISABLE, dc_timer_dev.base + CONTROL(TIMER_B)); + writel(UINT_MAX, dc_timer_dev.base + COUNT(TIMER_B)); + writeb(CONTROL_ENABLE, dc_timer_dev.base + CONTROL(TIMER_B)); + + sched_clock_register(digicolor_timer_sched_read, 32, rate); + clocksource_mmio_init(dc_timer_dev.base + COUNT(TIMER_B), node->name, + rate, 340, 32, clocksource_mmio_readl_down); + + ret = request_irq(irq, digicolor_timer_interrupt, + IRQF_TIMER | IRQF_IRQPOLL, "digicolor_timerC", + &dc_timer_dev.ce); + if (ret) + pr_warn("request of timer irq %d failed (%d)\n", irq, ret); + + dc_timer_dev.ce.cpumask = cpu_possible_mask; + dc_timer_dev.ce.irq = irq; + + clockevents_config_and_register(&dc_timer_dev.ce, rate, 0, 0xffffffff); +} +CLOCKSOURCE_OF_DECLARE(conexant_digicolor, "cnxt,cx92755-timer", + digicolor_timer_init); -- cgit v0.10.2 From 1a18554b969861aae99e3b002b96d26b2233463d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 28 Jan 2015 11:56:30 -0600 Subject: dt/bindings: Add binding for Versatile system registers Add binding for Versatile board system registers found in the FPGA of the Versatile/AB and Versatile/PB boards. Signed-off-by: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Cc: devicetree@vger.kernel.org Signed-off-by: Daniel Lezcano diff --git a/Documentation/devicetree/bindings/arm/versatile-sysreg.txt b/Documentation/devicetree/bindings/arm/versatile-sysreg.txt new file mode 100644 index 0000000..a4f1526 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/versatile-sysreg.txt @@ -0,0 +1,10 @@ +ARM Versatile system registers +-------------------------------------- + +This is a system control registers block, providing multiple low level +platform functions like board detection and identification, software +interrupt generation, MMC and NOR Flash control etc. + +Required node properties: +- compatible value : = "arm,versatile-sysreg", "syscon" +- reg : physical base address and the size of the registers window -- cgit v0.10.2 From f2fa0299d34236d7e6ed213a28dca380b8c68ac0 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 28 Jan 2015 11:56:31 -0600 Subject: clocksource: versatile: Adapt for Versatile AB and PB boards The same 24MHz counter is also present on Versatile AB and PB boards, so add the compatible string for them. Signed-off-by: Rob Herring Acked-by: Liviu Dudau Cc: Liviu Dudau Cc: Sudeep Holla Cc: Lorenzo Pieralisi Cc: Daniel Lezcano Cc: Thomas Gleixner Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/versatile.c b/drivers/clocksource/versatile.c index 2798e74..0a26d3d 100644 --- a/drivers/clocksource/versatile.c +++ b/drivers/clocksource/versatile.c @@ -36,5 +36,7 @@ static void __init versatile_sched_clock_init(struct device_node *node) sched_clock_register(versatile_sys_24mhz_read, 32, 24000000); } -CLOCKSOURCE_OF_DECLARE(versatile, "arm,vexpress-sysreg", +CLOCKSOURCE_OF_DECLARE(vexpress, "arm,vexpress-sysreg", + versatile_sched_clock_init); +CLOCKSOURCE_OF_DECLARE(versatile, "arm,versatile-sysreg", versatile_sched_clock_init); -- cgit v0.10.2 From 35a8578e8b83eb13f8d57ab40b98bcfd5199d3d4 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 28 Jan 2015 11:56:32 -0600 Subject: dts: versatile: Add sysregs node The Versatile boards have the same sysregs as other ARM Ltd boards. Add the nodes in order to enable support for 24MHz counter as sched_clock. This is a minimal node definition as the existing sub node definition used on VExpress has some issues raised by Linus W. Signed-off-by: Rob Herring Cc: Russell King Cc: Linus Walleij Cc: devicetree@vger.kernel.org Signed-off-by: Daniel Lezcano diff --git a/arch/arm/boot/dts/versatile-ab.dts b/arch/arm/boot/dts/versatile-ab.dts index 27d0d9c..01f4019 100644 --- a/arch/arm/boot/dts/versatile-ab.dts +++ b/arch/arm/boot/dts/versatile-ab.dts @@ -252,6 +252,11 @@ #size-cells = <1>; ranges = <0 0x10000000 0x10000>; + sysreg@0 { + compatible = "arm,versatile-sysreg", "syscon"; + reg = <0x00000 0x1000>; + }; + aaci@4000 { compatible = "arm,primecell"; reg = <0x4000 0x1000>; -- cgit v0.10.2