linux/drivers/clocksource/timer-prima2.c
<<
>>
Prefs
   1/*
   2 * System timer for CSR SiRFprimaII
   3 *
   4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
   5 *
   6 * Licensed under GPLv2 or later.
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/interrupt.h>
  11#include <linux/clockchips.h>
  12#include <linux/clocksource.h>
  13#include <linux/bitops.h>
  14#include <linux/irq.h>
  15#include <linux/clk.h>
  16#include <linux/err.h>
  17#include <linux/slab.h>
  18#include <linux/of.h>
  19#include <linux/of_irq.h>
  20#include <linux/of_address.h>
  21#include <linux/sched_clock.h>
  22#include <asm/mach/time.h>
  23
  24#define PRIMA2_CLOCK_FREQ 1000000
  25
  26#define SIRFSOC_TIMER_COUNTER_LO        0x0000
  27#define SIRFSOC_TIMER_COUNTER_HI        0x0004
  28#define SIRFSOC_TIMER_MATCH_0           0x0008
  29#define SIRFSOC_TIMER_MATCH_1           0x000C
  30#define SIRFSOC_TIMER_MATCH_2           0x0010
  31#define SIRFSOC_TIMER_MATCH_3           0x0014
  32#define SIRFSOC_TIMER_MATCH_4           0x0018
  33#define SIRFSOC_TIMER_MATCH_5           0x001C
  34#define SIRFSOC_TIMER_STATUS            0x0020
  35#define SIRFSOC_TIMER_INT_EN            0x0024
  36#define SIRFSOC_TIMER_WATCHDOG_EN       0x0028
  37#define SIRFSOC_TIMER_DIV               0x002C
  38#define SIRFSOC_TIMER_LATCH             0x0030
  39#define SIRFSOC_TIMER_LATCHED_LO        0x0034
  40#define SIRFSOC_TIMER_LATCHED_HI        0x0038
  41
  42#define SIRFSOC_TIMER_WDT_INDEX         5
  43
  44#define SIRFSOC_TIMER_LATCH_BIT  BIT(0)
  45
  46#define SIRFSOC_TIMER_REG_CNT 11
  47
  48static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
  49        SIRFSOC_TIMER_MATCH_0, SIRFSOC_TIMER_MATCH_1, SIRFSOC_TIMER_MATCH_2,
  50        SIRFSOC_TIMER_MATCH_3, SIRFSOC_TIMER_MATCH_4, SIRFSOC_TIMER_MATCH_5,
  51        SIRFSOC_TIMER_INT_EN, SIRFSOC_TIMER_WATCHDOG_EN, SIRFSOC_TIMER_DIV,
  52        SIRFSOC_TIMER_LATCHED_LO, SIRFSOC_TIMER_LATCHED_HI,
  53};
  54
  55static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT];
  56
  57static void __iomem *sirfsoc_timer_base;
  58
  59/* timer0 interrupt handler */
  60static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
  61{
  62        struct clock_event_device *ce = dev_id;
  63
  64        WARN_ON(!(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_STATUS) &
  65                BIT(0)));
  66
  67        /* clear timer0 interrupt */
  68        writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
  69
  70        ce->event_handler(ce);
  71
  72        return IRQ_HANDLED;
  73}
  74
  75/* read 64-bit timer counter */
  76static cycle_t notrace sirfsoc_timer_read(struct clocksource *cs)
  77{
  78        u64 cycles;
  79
  80        /* latch the 64-bit timer counter */
  81        writel_relaxed(SIRFSOC_TIMER_LATCH_BIT,
  82                sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
  83        cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_HI);
  84        cycles = (cycles << 32) |
  85                readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
  86
  87        return cycles;
  88}
  89
  90static int sirfsoc_timer_set_next_event(unsigned long delta,
  91        struct clock_event_device *ce)
  92{
  93        unsigned long now, next;
  94
  95        writel_relaxed(SIRFSOC_TIMER_LATCH_BIT,
  96                sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
  97        now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
  98        next = now + delta;
  99        writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0);
 100        writel_relaxed(SIRFSOC_TIMER_LATCH_BIT,
 101                sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
 102        now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
 103
 104        return next - now > delta ? -ETIME : 0;
 105}
 106
 107static int sirfsoc_timer_shutdown(struct clock_event_device *evt)
 108{
 109        u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
 110
 111        writel_relaxed(val & ~BIT(0),
 112                       sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
 113        return 0;
 114}
 115
 116static int sirfsoc_timer_set_oneshot(struct clock_event_device *evt)
 117{
 118        u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
 119
 120        writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
 121        return 0;
 122}
 123
 124static void sirfsoc_clocksource_suspend(struct clocksource *cs)
 125{
 126        int i;
 127
 128        writel_relaxed(SIRFSOC_TIMER_LATCH_BIT,
 129                sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
 130
 131        for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++)
 132                sirfsoc_timer_reg_val[i] =
 133                        readl_relaxed(sirfsoc_timer_base +
 134                                sirfsoc_timer_reg_list[i]);
 135}
 136
 137static void sirfsoc_clocksource_resume(struct clocksource *cs)
 138{
 139        int i;
 140
 141        for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++)
 142                writel_relaxed(sirfsoc_timer_reg_val[i],
 143                        sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
 144
 145        writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2],
 146                sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO);
 147        writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1],
 148                sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
 149}
 150
 151static struct clock_event_device sirfsoc_clockevent = {
 152        .name = "sirfsoc_clockevent",
 153        .rating = 200,
 154        .features = CLOCK_EVT_FEAT_ONESHOT,
 155        .set_state_shutdown = sirfsoc_timer_shutdown,
 156        .set_state_oneshot = sirfsoc_timer_set_oneshot,
 157        .set_next_event = sirfsoc_timer_set_next_event,
 158};
 159
 160static struct clocksource sirfsoc_clocksource = {
 161        .name = "sirfsoc_clocksource",
 162        .rating = 200,
 163        .mask = CLOCKSOURCE_MASK(64),
 164        .flags = CLOCK_SOURCE_IS_CONTINUOUS,
 165        .read = sirfsoc_timer_read,
 166        .suspend = sirfsoc_clocksource_suspend,
 167        .resume = sirfsoc_clocksource_resume,
 168};
 169
 170static struct irqaction sirfsoc_timer_irq = {
 171        .name = "sirfsoc_timer0",
 172        .flags = IRQF_TIMER,
 173        .irq = 0,
 174        .handler = sirfsoc_timer_interrupt,
 175        .dev_id = &sirfsoc_clockevent,
 176};
 177
 178/* Overwrite weak default sched_clock with more precise one */
 179static u64 notrace sirfsoc_read_sched_clock(void)
 180{
 181        return sirfsoc_timer_read(NULL);
 182}
 183
 184static void __init sirfsoc_clockevent_init(void)
 185{
 186        sirfsoc_clockevent.cpumask = cpumask_of(0);
 187        clockevents_config_and_register(&sirfsoc_clockevent, PRIMA2_CLOCK_FREQ,
 188                                        2, -2);
 189}
 190
 191/* initialize the kernel jiffy timer source */
 192static void __init sirfsoc_prima2_timer_init(struct device_node *np)
 193{
 194        unsigned long rate;
 195        struct clk *clk;
 196
 197        clk = of_clk_get(np, 0);
 198        BUG_ON(IS_ERR(clk));
 199
 200        BUG_ON(clk_prepare_enable(clk));
 201
 202        rate = clk_get_rate(clk);
 203
 204        BUG_ON(rate < PRIMA2_CLOCK_FREQ);
 205        BUG_ON(rate % PRIMA2_CLOCK_FREQ);
 206
 207        sirfsoc_timer_base = of_iomap(np, 0);
 208        if (!sirfsoc_timer_base)
 209                panic("unable to map timer cpu registers\n");
 210
 211        sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0);
 212
 213        writel_relaxed(rate / PRIMA2_CLOCK_FREQ / 2 - 1,
 214                sirfsoc_timer_base + SIRFSOC_TIMER_DIV);
 215        writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO);
 216        writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
 217        writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
 218
 219        BUG_ON(clocksource_register_hz(&sirfsoc_clocksource,
 220                                       PRIMA2_CLOCK_FREQ));
 221
 222        sched_clock_register(sirfsoc_read_sched_clock, 64, PRIMA2_CLOCK_FREQ);
 223
 224        BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq));
 225
 226        sirfsoc_clockevent_init();
 227}
 228CLOCKSOURCE_OF_DECLARE(sirfsoc_prima2_timer,
 229        "sirf,prima2-tick", sirfsoc_prima2_timer_init);
 230