summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2013-03-19 15:27:22 +0100
committerArnd Bergmann <arnd@arndb.de>2013-03-25 12:29:41 +0100
commit275786b71d42bb54c03c15197128d7cb05d4dd8b (patch)
treef617b3c2c278798da79f832f14faa81fa57f2c6c /arch
parent67bdb28718ae6dbdfbfa541161529acfa0f3c137 (diff)
ARM: sirf: use clocksource_of infrastructure
This moves the two sirf clocksource drivers to drivers/clocksource and integrates them into the framework for locating the clock sources automatically. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Tested-by: Barry Song <Baohua.Song@csr.com> Cc: John Stultz <john.stultz@linaro.org> Cc: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-prima2/Makefile2
-rw-r--r--arch/arm/mach-prima2/common.c14
-rw-r--r--arch/arm/mach-prima2/common.h3
-rw-r--r--arch/arm/mach-prima2/timer-marco.c316
-rw-r--r--arch/arm/mach-prima2/timer-prima2.c239
5 files changed, 11 insertions, 563 deletions
diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile
index 5fdff7e3229..52ac738881c 100644
--- a/arch/arm/mach-prima2/Makefile
+++ b/arch/arm/mach-prima2/Makefile
@@ -6,5 +6,3 @@ obj-$(CONFIG_CACHE_L2X0) += l2x0.o
obj-$(CONFIG_SUSPEND) += pm.o sleep.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
-obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o
-obj-$(CONFIG_ARCH_MARCO) += timer-marco.o
diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c
index 31f43eac142..4f94cd87972 100644
--- a/arch/arm/mach-prima2/common.c
+++ b/arch/arm/mach-prima2/common.c
@@ -6,6 +6,7 @@
* Licensed under GPLv2 or later.
*/
+#include <linux/clocksource.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/irqchip.h>
@@ -31,6 +32,13 @@ void __init sirfsoc_init_late(void)
sirfsoc_pm_init();
}
+static __init void sirfsoc_init_time(void)
+{
+ /* initialize clocking early, we want to set the OS timer */
+ sirfsoc_of_clk_init();
+ clocksource_of_init();
+}
+
static __init void sirfsoc_map_io(void)
{
sirfsoc_map_lluart();
@@ -48,7 +56,7 @@ DT_MACHINE_START(ATLAS6_DT, "Generic ATLAS6 (Flattened Device Tree)")
.nr_irqs = 128,
.map_io = sirfsoc_map_io,
.init_irq = irqchip_init,
- .init_time = sirfsoc_prima2_timer_init,
+ .init_time = sirfsoc_init_time,
.init_machine = sirfsoc_mach_init,
.init_late = sirfsoc_init_late,
.dt_compat = atlas6_dt_match,
@@ -67,7 +75,7 @@ DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)")
.nr_irqs = 128,
.map_io = sirfsoc_map_io,
.init_irq = irqchip_init,
- .init_time = sirfsoc_prima2_timer_init,
+ .init_time = sirfsoc_init_time,
.dma_zone_size = SZ_256M,
.init_machine = sirfsoc_mach_init,
.init_late = sirfsoc_init_late,
@@ -87,7 +95,7 @@ DT_MACHINE_START(MARCO_DT, "Generic MARCO (Flattened Device Tree)")
.smp = smp_ops(sirfsoc_smp_ops),
.map_io = sirfsoc_map_io,
.init_irq = irqchip_init,
- .init_time = sirfsoc_marco_timer_init,
+ .init_time = sirfsoc_init_time,
.init_machine = sirfsoc_mach_init,
.init_late = sirfsoc_init_late,
.dt_compat = marco_dt_match,
diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h
index b7c26b62e4a..54262cf063c 100644
--- a/arch/arm/mach-prima2/common.h
+++ b/arch/arm/mach-prima2/common.h
@@ -13,9 +13,6 @@
#include <asm/mach/time.h>
#include <asm/exception.h>
-extern void sirfsoc_prima2_timer_init(void);
-extern void sirfsoc_marco_timer_init(void);
-
extern struct smp_operations sirfsoc_smp_ops;
extern void sirfsoc_secondary_startup(void);
extern void sirfsoc_cpu_die(unsigned int cpu);
diff --git a/arch/arm/mach-prima2/timer-marco.c b/arch/arm/mach-prima2/timer-marco.c
deleted file mode 100644
index f4eea2e97eb..00000000000
--- a/arch/arm/mach-prima2/timer-marco.c
+++ /dev/null
@@ -1,316 +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 <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/clockchips.h>
-#include <linux/clocksource.h>
-#include <linux/bitops.h>
-#include <linux/irq.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
-#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <linux/of_address.h>
-#include <asm/sched_clock.h>
-#include <asm/localtimer.h>
-#include <asm/mach/time.h>
-
-#include "common.h"
-
-#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 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;
-static void __init sirfsoc_of_timer_map(void);
-
-/* 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) | 0x7,
- 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();
-
- 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 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 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,
- .dev_id = &sirfsoc_clockevent,
-};
-
-#ifdef CONFIG_LOCAL_TIMERS
-
-static struct irqaction sirfsoc_timer1_irq = {
- .name = "sirfsoc_timer1",
- .flags = IRQF_TIMER | IRQF_NOBALANCING,
- .handler = sirfsoc_timer_interrupt,
-};
-
-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;
-
- ce->irq = sirfsoc_timer1_irq.irq;
- ce->name = "local_timer";
- ce->features = sirfsoc_clockevent.features;
- ce->rating = sirfsoc_clockevent.rating;
- 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;
-
- 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));
-
- clockevents_register_device(ce);
- return 0;
-}
-
-static void sirfsoc_local_timer_stop(struct clock_event_device *ce)
-{
- sirfsoc_timer_count_disable(1);
-
- 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,
-};
-#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
-}
-
-/* initialize the kernel jiffy timer source */
-void __init sirfsoc_marco_timer_init(void)
-{
- unsigned long rate;
- u32 timer_div;
- struct clk *clk;
-
- /* initialize clocking early, we want to set the OS timer */
- sirfsoc_of_clk_init();
-
- /* timer's input clock is io clock */
- clk = clk_get_sys("io", NULL);
-
- BUG_ON(IS_ERR(clk));
- rate = clk_get_rate(clk);
-
- BUG_ON(rate < CLOCK_TICK_RATE);
- BUG_ON(rate % CLOCK_TICK_RATE);
-
- sirfsoc_of_timer_map();
-
- /* Initialize the timer dividers */
- timer_div = rate / CLOCK_TICK_RATE - 1;
- writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
- writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL);
- writel_relaxed(timer_div << 16, 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, CLOCK_TICK_RATE));
-
- BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq));
-
- sirfsoc_clockevent_init();
-}
-
-static struct of_device_id timer_ids[] = {
- { .compatible = "sirf,marco-tick" },
- {},
-};
-
-static void __init sirfsoc_of_timer_map(void)
-{
- struct device_node *np;
-
- np = of_find_matching_node(NULL, timer_ids);
- if (!np)
- return;
- 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");
-
-#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
-
- of_node_put(np);
-}
diff --git a/arch/arm/mach-prima2/timer-prima2.c b/arch/arm/mach-prima2/timer-prima2.c
deleted file mode 100644
index 982908350b4..00000000000
--- a/arch/arm/mach-prima2/timer-prima2.c
+++ /dev/null
@@ -1,239 +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 <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/clockchips.h>
-#include <linux/clocksource.h>
-#include <linux/bitops.h>
-#include <linux/irq.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <linux/of_address.h>
-#include <mach/map.h>
-#include <asm/sched_clock.h>
-#include <asm/mach/time.h>
-
-#include "common.h"
-
-#define SIRFSOC_TIMER_COUNTER_LO 0x0000
-#define SIRFSOC_TIMER_COUNTER_HI 0x0004
-#define SIRFSOC_TIMER_MATCH_0 0x0008
-#define SIRFSOC_TIMER_MATCH_1 0x000C
-#define SIRFSOC_TIMER_MATCH_2 0x0010
-#define SIRFSOC_TIMER_MATCH_3 0x0014
-#define SIRFSOC_TIMER_MATCH_4 0x0018
-#define SIRFSOC_TIMER_MATCH_5 0x001C
-#define SIRFSOC_TIMER_STATUS 0x0020
-#define SIRFSOC_TIMER_INT_EN 0x0024
-#define SIRFSOC_TIMER_WATCHDOG_EN 0x0028
-#define SIRFSOC_TIMER_DIV 0x002C
-#define SIRFSOC_TIMER_LATCH 0x0030
-#define SIRFSOC_TIMER_LATCHED_LO 0x0034
-#define SIRFSOC_TIMER_LATCHED_HI 0x0038
-
-#define SIRFSOC_TIMER_WDT_INDEX 5
-
-#define SIRFSOC_TIMER_LATCH_BIT BIT(0)
-
-#define SIRFSOC_TIMER_REG_CNT 11
-
-static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
- SIRFSOC_TIMER_MATCH_0, SIRFSOC_TIMER_MATCH_1, SIRFSOC_TIMER_MATCH_2,
- SIRFSOC_TIMER_MATCH_3, SIRFSOC_TIMER_MATCH_4, SIRFSOC_TIMER_MATCH_5,
- SIRFSOC_TIMER_INT_EN, SIRFSOC_TIMER_WATCHDOG_EN, SIRFSOC_TIMER_DIV,
- SIRFSOC_TIMER_LATCHED_LO, SIRFSOC_TIMER_LATCHED_HI,
-};
-
-static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT];
-
-static void __iomem *sirfsoc_timer_base;
-static void __init sirfsoc_of_timer_map(void);
-
-/* timer0 interrupt handler */
-static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
-{
- struct clock_event_device *ce = dev_id;
-
- WARN_ON(!(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_STATUS) & BIT(0)));
-
- /* clear timer0 interrupt */
- writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
-
- ce->event_handler(ce);
-
- return IRQ_HANDLED;
-}
-
-/* read 64-bit timer counter */
-static cycle_t sirfsoc_timer_read(struct clocksource *cs)
-{
- u64 cycles;
-
- /* latch the 64-bit timer counter */
- writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
- cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_HI);
- cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
-
- return cycles;
-}
-
-static int sirfsoc_timer_set_next_event(unsigned long delta,
- struct clock_event_device *ce)
-{
- unsigned long now, next;
-
- writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
- now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
- next = now + delta;
- writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0);
- writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
- now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
-
- return next - now > delta ? -ETIME : 0;
-}
-
-static void sirfsoc_timer_set_mode(enum clock_event_mode mode,
- struct clock_event_device *ce)
-{
- u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
- switch (mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- WARN_ON(1);
- break;
- case CLOCK_EVT_MODE_ONESHOT:
- writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
- break;
- case CLOCK_EVT_MODE_SHUTDOWN:
- writel_relaxed(val & ~BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
- break;
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_RESUME:
- break;
- }
-}
-
-static void sirfsoc_clocksource_suspend(struct clocksource *cs)
-{
- int i;
-
- writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
-
- 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_COUNTER_LO);
- writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1], sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
-}
-
-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 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,
- .irq = 0,
- .handler = sirfsoc_timer_interrupt,
- .dev_id = &sirfsoc_clockevent,
-};
-
-/* Overwrite weak default sched_clock with more precise one */
-static u32 notrace sirfsoc_read_sched_clock(void)
-{
- return (u32)(sirfsoc_timer_read(NULL) & 0xffffffff);
-}
-
-static void __init sirfsoc_clockevent_init(void)
-{
- sirfsoc_clockevent.cpumask = cpumask_of(0);
- clockevents_config_and_register(&sirfsoc_clockevent, CLOCK_TICK_RATE,
- 2, -2);
-}
-
-/* initialize the kernel jiffy timer source */
-void __init sirfsoc_prima2_timer_init(void)
-{
- unsigned long rate;
- struct clk *clk;
-
- /* initialize clocking early, we want to set the OS timer */
- sirfsoc_of_clk_init();
-
- /* timer's input clock is io clock */
- clk = clk_get_sys("io", NULL);
-
- BUG_ON(IS_ERR(clk));
-
- rate = clk_get_rate(clk);
-
- BUG_ON(rate < CLOCK_TICK_RATE);
- BUG_ON(rate % CLOCK_TICK_RATE);
-
- sirfsoc_of_timer_map();
-
- writel_relaxed(rate / CLOCK_TICK_RATE / 2 - 1, sirfsoc_timer_base + SIRFSOC_TIMER_DIV);
- writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO);
- writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
- writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
-
- BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE));
-
- setup_sched_clock(sirfsoc_read_sched_clock, 32, CLOCK_TICK_RATE);
-
- BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq));
-
- sirfsoc_clockevent_init();
-}
-
-static struct of_device_id timer_ids[] = {
- { .compatible = "sirf,prima2-tick" },
- {},
-};
-
-static void __init sirfsoc_of_timer_map(void)
-{
- struct device_node *np;
-
- np = of_find_matching_node(NULL, timer_ids);
- if (!np)
- return;
- sirfsoc_timer_base = of_iomap(np, 0);
- if (!sirfsoc_timer_base)
- panic("unable to map timer cpu registers\n");
-
- /* Get the interrupts property */
- sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0);
-
- of_node_put(np);
-}