Merge branch 'marco-timer-cleanup-rebase' of git://gitorious.org/sirfprima2-kernel...
authorOlof Johansson <olof@lixom.net>
Mon, 28 Jan 2013 07:03:42 +0000 (23:03 -0800)
committerOlof Johansson <olof@lixom.net>
Mon, 28 Jan 2013 07:03:42 +0000 (23:03 -0800)
From Barry Song, this adds support for a new SoC from CSR; marco. It's
SMP, uses GIC instead of VIC and in general needs a bit of rework of
the platform code for setup, which this branch contains.

* 'marco-timer-cleanup-rebase' of git://gitorious.org/sirfprima2-kernel/sirfprima2-kernel:
  ARM: PRIMA2: provide two DEBUG_LL ports for prima2 and marco
  ARM: PRIMA2: add new SiRFmarco SMP SoC infrastructures
  ARM: PRIMA2: irq: make prima2 irq can work even we enable GIC for Marco
  ARM: PRIMA2: rtciobg: it is also compatible with marco
  ARM: PRIMA2: rstc: enable the support for Marco
  ARM: PRIMA2: mv timer to timer-prima2 as we will add timer-marco
  ARM: PRIMA2: initialize l2x0 according to mach from DT
  ARM: PRIMA2: enable AUTO_ZRELADDR for SIRF in Kconfig
  ARM: PRIMA2: add CSR SiRFmarco device tree .dts

Signed-off-by: Olof Johansson <olof@lixom.net>
1  2 
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/boot/dts/Makefile
arch/arm/mach-prima2/rtciobrg.c
arch/arm/mach-prima2/timer-prima2.c

Simple merge
Simple merge
Simple merge
Simple merge
index 0000000000000000000000000000000000000000,309e724735b74153a1b286921f62dfd6eee2a63d..6da584f8a949482091ce3a9666fa7993f5cf978b
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,247 +1,241 @@@
 -      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);
 -
+ /*
+  * 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_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)
+ {
 -      clockevents_register_device(&sirfsoc_clockevent);
+       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;
+       const unsigned int *intspec;
+       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 */
+       intspec = of_get_property(np, "interrupts", NULL);
+       BUG_ON(!intspec);
+       sirfsoc_timer_irq.irq = be32_to_cpup(intspec);
+       of_node_put(np);
+ }
This page took 0.033153 seconds and 5 git commands to generate.