Merge tag 'late-omap' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[~shefty/rdma-dev.git] / drivers / clocksource / time-armada-370-xp.c
1 /*
2  * Marvell Armada 370/XP SoC timer handling.
3  *
4  * Copyright (C) 2012 Marvell
5  *
6  * Lior Amsalem <alior@marvell.com>
7  * Gregory CLEMENT <gregory.clement@free-electrons.com>
8  * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
9  *
10  * This file is licensed under the terms of the GNU General Public
11  * License version 2.  This program is licensed "as is" without any
12  * warranty of any kind, whether express or implied.
13  *
14  * Timer 0 is used as free-running clocksource, while timer 1 is
15  * used as clock_event_device.
16  */
17
18 #include <linux/init.h>
19 #include <linux/platform_device.h>
20 #include <linux/kernel.h>
21 #include <linux/clk.h>
22 #include <linux/timer.h>
23 #include <linux/clockchips.h>
24 #include <linux/interrupt.h>
25 #include <linux/of.h>
26 #include <linux/of_irq.h>
27 #include <linux/of_address.h>
28 #include <linux/irq.h>
29 #include <linux/module.h>
30 #include <asm/sched_clock.h>
31
32 /*
33  * Timer block registers.
34  */
35 #define TIMER_CTRL_OFF          0x0000
36 #define  TIMER0_EN               0x0001
37 #define  TIMER0_RELOAD_EN        0x0002
38 #define  TIMER0_25MHZ            0x0800
39 #define  TIMER0_DIV(div)         ((div) << 19)
40 #define  TIMER1_EN               0x0004
41 #define  TIMER1_RELOAD_EN        0x0008
42 #define  TIMER1_25MHZ            0x1000
43 #define  TIMER1_DIV(div)         ((div) << 22)
44 #define TIMER_EVENTS_STATUS     0x0004
45 #define  TIMER0_CLR_MASK         (~0x1)
46 #define  TIMER1_CLR_MASK         (~0x100)
47 #define TIMER0_RELOAD_OFF       0x0010
48 #define TIMER0_VAL_OFF          0x0014
49 #define TIMER1_RELOAD_OFF       0x0018
50 #define TIMER1_VAL_OFF          0x001c
51
52 /* Global timers are connected to the coherency fabric clock, and the
53    below divider reduces their incrementing frequency. */
54 #define TIMER_DIVIDER_SHIFT     5
55 #define TIMER_DIVIDER           (1 << TIMER_DIVIDER_SHIFT)
56
57 /*
58  * SoC-specific data.
59  */
60 static void __iomem *timer_base;
61 static int timer_irq;
62
63 /*
64  * Number of timer ticks per jiffy.
65  */
66 static u32 ticks_per_jiffy;
67
68 static u32 notrace armada_370_xp_read_sched_clock(void)
69 {
70         return ~readl(timer_base + TIMER0_VAL_OFF);
71 }
72
73 /*
74  * Clockevent handling.
75  */
76 static int
77 armada_370_xp_clkevt_next_event(unsigned long delta,
78                                 struct clock_event_device *dev)
79 {
80         u32 u;
81
82         /*
83          * Clear clockevent timer interrupt.
84          */
85         writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS);
86
87         /*
88          * Setup new clockevent timer value.
89          */
90         writel(delta, timer_base + TIMER1_VAL_OFF);
91
92         /*
93          * Enable the timer.
94          */
95         u = readl(timer_base + TIMER_CTRL_OFF);
96         u = ((u & ~TIMER1_RELOAD_EN) | TIMER1_EN |
97              TIMER1_DIV(TIMER_DIVIDER_SHIFT));
98         writel(u, timer_base + TIMER_CTRL_OFF);
99
100         return 0;
101 }
102
103 static void
104 armada_370_xp_clkevt_mode(enum clock_event_mode mode,
105                           struct clock_event_device *dev)
106 {
107         u32 u;
108
109         if (mode == CLOCK_EVT_MODE_PERIODIC) {
110                 /*
111                  * Setup timer to fire at 1/HZ intervals.
112                  */
113                 writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD_OFF);
114                 writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL_OFF);
115
116                 /*
117                  * Enable timer.
118                  */
119                 u = readl(timer_base + TIMER_CTRL_OFF);
120
121                 writel((u | TIMER1_EN | TIMER1_RELOAD_EN |
122                         TIMER1_DIV(TIMER_DIVIDER_SHIFT)),
123                        timer_base + TIMER_CTRL_OFF);
124         } else {
125                 /*
126                  * Disable timer.
127                  */
128                 u = readl(timer_base + TIMER_CTRL_OFF);
129                 writel(u & ~TIMER1_EN, timer_base + TIMER_CTRL_OFF);
130
131                 /*
132                  * ACK pending timer interrupt.
133                  */
134                 writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS);
135
136         }
137 }
138
139 static struct clock_event_device armada_370_xp_clkevt = {
140         .name           = "armada_370_xp_tick",
141         .features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
142         .shift          = 32,
143         .rating         = 300,
144         .set_next_event = armada_370_xp_clkevt_next_event,
145         .set_mode       = armada_370_xp_clkevt_mode,
146 };
147
148 static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id)
149 {
150         /*
151          * ACK timer interrupt and call event handler.
152          */
153
154         writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS);
155         armada_370_xp_clkevt.event_handler(&armada_370_xp_clkevt);
156
157         return IRQ_HANDLED;
158 }
159
160 static struct irqaction armada_370_xp_timer_irq = {
161         .name           = "armada_370_xp_tick",
162         .flags          = IRQF_DISABLED | IRQF_TIMER,
163         .handler        = armada_370_xp_timer_interrupt
164 };
165
166 void __init armada_370_xp_timer_init(void)
167 {
168         u32 u;
169         struct device_node *np;
170         unsigned int timer_clk;
171         np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer");
172         timer_base = of_iomap(np, 0);
173         WARN_ON(!timer_base);
174
175         if (of_find_property(np, "marvell,timer-25Mhz", NULL)) {
176                 /* The fixed 25MHz timer is available so let's use it */
177                 u = readl(timer_base + TIMER_CTRL_OFF);
178                 writel(u | TIMER0_25MHZ | TIMER1_25MHZ,
179                        timer_base + TIMER_CTRL_OFF);
180                 timer_clk = 25000000;
181         } else {
182                 unsigned long rate = 0;
183                 struct clk *clk = of_clk_get(np, 0);
184                 WARN_ON(IS_ERR(clk));
185                 rate =  clk_get_rate(clk);
186                 u = readl(timer_base + TIMER_CTRL_OFF);
187                 writel(u & ~(TIMER0_25MHZ | TIMER1_25MHZ),
188                        timer_base + TIMER_CTRL_OFF);
189                 timer_clk = rate / TIMER_DIVIDER;
190         }
191
192         /* We use timer 0 as clocksource, and timer 1 for
193            clockevents */
194         timer_irq = irq_of_parse_and_map(np, 1);
195
196         ticks_per_jiffy = (timer_clk + HZ / 2) / HZ;
197
198         /*
199          * Set scale and timer for sched_clock.
200          */
201         setup_sched_clock(armada_370_xp_read_sched_clock, 32, timer_clk);
202
203         /*
204          * Setup free-running clocksource timer (interrupts
205          * disabled).
206          */
207         writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
208         writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
209
210         u = readl(timer_base + TIMER_CTRL_OFF);
211
212         writel((u | TIMER0_EN | TIMER0_RELOAD_EN |
213                 TIMER0_DIV(TIMER_DIVIDER_SHIFT)), timer_base + TIMER_CTRL_OFF);
214
215         clocksource_mmio_init(timer_base + TIMER0_VAL_OFF,
216                               "armada_370_xp_clocksource",
217                               timer_clk, 300, 32, clocksource_mmio_readl_down);
218
219         /*
220          * Setup clockevent timer (interrupt-driven).
221          */
222         setup_irq(timer_irq, &armada_370_xp_timer_irq);
223         armada_370_xp_clkevt.cpumask = cpumask_of(0);
224         clockevents_config_and_register(&armada_370_xp_clkevt,
225                                         timer_clk, 1, 0xfffffffe);
226 }
227