1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/interrupt.h>
21#include <linux/irq.h>
22#include <linux/types.h>
23#include <linux/clocksource.h>
24#include <linux/clockchips.h>
25#include <linux/io.h>
26
27#include <asm/mach/time.h>
28#include <mach/zynq_soc.h>
29#include "common.h"
30
31#define IRQ_TIMERCOUNTER0 42
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47#define XTTCPSS_CLOCKSOURCE 0
48#define XTTCPSS_CLOCKEVENT 1
49
50#define XTTCPSS_TIMER_BASE TTC0_BASE
51#define XTTCPCC_EVENT_TIMER_IRQ (IRQ_TIMERCOUNTER0 + 1)
52
53
54
55
56#define XTTCPSS_CLK_CNTRL_OFFSET 0x00
57#define XTTCPSS_CNT_CNTRL_OFFSET 0x0C
58#define XTTCPSS_COUNT_VAL_OFFSET 0x18
59#define XTTCPSS_INTR_VAL_OFFSET 0x24
60#define XTTCPSS_MATCH_1_OFFSET 0x30
61#define XTTCPSS_MATCH_2_OFFSET 0x3C
62#define XTTCPSS_MATCH_3_OFFSET 0x48
63#define XTTCPSS_ISR_OFFSET 0x54
64#define XTTCPSS_IER_OFFSET 0x60
65
66#define XTTCPSS_CNT_CNTRL_DISABLE_MASK 0x1
67
68
69
70#define TIMER_RATE (PERIPHERAL_CLOCK_RATE / 32)
71
72
73
74
75
76
77struct xttcpss_timer {
78 void __iomem *base_addr;
79};
80
81static struct xttcpss_timer timers[2];
82static struct clock_event_device xttcpss_clockevent;
83
84
85
86
87
88
89
90static void xttcpss_set_interval(struct xttcpss_timer *timer,
91 unsigned long cycles)
92{
93 u32 ctrl_reg;
94
95
96 ctrl_reg = __raw_readl(timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
97 ctrl_reg |= XTTCPSS_CNT_CNTRL_DISABLE_MASK;
98 __raw_writel(ctrl_reg, timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
99
100 __raw_writel(cycles, timer->base_addr + XTTCPSS_INTR_VAL_OFFSET);
101
102
103
104 ctrl_reg |= 0x10;
105 ctrl_reg &= ~XTTCPSS_CNT_CNTRL_DISABLE_MASK;
106 __raw_writel(ctrl_reg, timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
107}
108
109
110
111
112
113
114
115
116
117static irqreturn_t xttcpss_clock_event_interrupt(int irq, void *dev_id)
118{
119 struct clock_event_device *evt = &xttcpss_clockevent;
120 struct xttcpss_timer *timer = dev_id;
121
122
123 __raw_writel(__raw_readl(timer->base_addr + XTTCPSS_ISR_OFFSET),
124 timer->base_addr + XTTCPSS_ISR_OFFSET);
125
126 evt->event_handler(evt);
127
128 return IRQ_HANDLED;
129}
130
131static struct irqaction event_timer_irq = {
132 .name = "xttcpss clockevent",
133 .flags = IRQF_DISABLED | IRQF_TIMER,
134 .handler = xttcpss_clock_event_interrupt,
135};
136
137
138
139
140
141
142
143static void __init xttcpss_timer_hardware_init(void)
144{
145
146
147
148
149 timers[XTTCPSS_CLOCKSOURCE].base_addr = XTTCPSS_TIMER_BASE;
150
151 __raw_writel(0x0, timers[XTTCPSS_CLOCKSOURCE].base_addr +
152 XTTCPSS_IER_OFFSET);
153 __raw_writel(0x9, timers[XTTCPSS_CLOCKSOURCE].base_addr +
154 XTTCPSS_CLK_CNTRL_OFFSET);
155 __raw_writel(0x10, timers[XTTCPSS_CLOCKSOURCE].base_addr +
156 XTTCPSS_CNT_CNTRL_OFFSET);
157
158
159
160
161
162
163 timers[XTTCPSS_CLOCKEVENT].base_addr = XTTCPSS_TIMER_BASE + 4;
164
165 __raw_writel(0x23, timers[XTTCPSS_CLOCKEVENT].base_addr +
166 XTTCPSS_CNT_CNTRL_OFFSET);
167 __raw_writel(0x9, timers[XTTCPSS_CLOCKEVENT].base_addr +
168 XTTCPSS_CLK_CNTRL_OFFSET);
169 __raw_writel(0x1, timers[XTTCPSS_CLOCKEVENT].base_addr +
170 XTTCPSS_IER_OFFSET);
171
172
173 event_timer_irq.dev_id = &timers[XTTCPSS_CLOCKEVENT];
174 setup_irq(XTTCPCC_EVENT_TIMER_IRQ, &event_timer_irq);
175}
176
177
178
179
180
181
182static cycle_t __raw_readl_cycles(struct clocksource *cs)
183{
184 struct xttcpss_timer *timer = &timers[XTTCPSS_CLOCKSOURCE];
185
186 return (cycle_t)__raw_readl(timer->base_addr +
187 XTTCPSS_COUNT_VAL_OFFSET);
188}
189
190
191
192
193
194static struct clocksource clocksource_xttcpss = {
195 .name = "xttcpss_timer1",
196 .rating = 200,
197 .read = __raw_readl_cycles,
198 .mask = CLOCKSOURCE_MASK(16),
199 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
200};
201
202
203
204
205
206
207
208
209
210
211static int xttcpss_set_next_event(unsigned long cycles,
212 struct clock_event_device *evt)
213{
214 struct xttcpss_timer *timer = &timers[XTTCPSS_CLOCKEVENT];
215
216 xttcpss_set_interval(timer, cycles);
217 return 0;
218}
219
220
221
222
223
224
225
226static void xttcpss_set_mode(enum clock_event_mode mode,
227 struct clock_event_device *evt)
228{
229 struct xttcpss_timer *timer = &timers[XTTCPSS_CLOCKEVENT];
230 u32 ctrl_reg;
231
232 switch (mode) {
233 case CLOCK_EVT_MODE_PERIODIC:
234 xttcpss_set_interval(timer, TIMER_RATE / HZ);
235 break;
236 case CLOCK_EVT_MODE_ONESHOT:
237 case CLOCK_EVT_MODE_UNUSED:
238 case CLOCK_EVT_MODE_SHUTDOWN:
239 ctrl_reg = __raw_readl(timer->base_addr +
240 XTTCPSS_CNT_CNTRL_OFFSET);
241 ctrl_reg |= XTTCPSS_CNT_CNTRL_DISABLE_MASK;
242 __raw_writel(ctrl_reg,
243 timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
244 break;
245 case CLOCK_EVT_MODE_RESUME:
246 ctrl_reg = __raw_readl(timer->base_addr +
247 XTTCPSS_CNT_CNTRL_OFFSET);
248 ctrl_reg &= ~XTTCPSS_CNT_CNTRL_DISABLE_MASK;
249 __raw_writel(ctrl_reg,
250 timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
251 break;
252 }
253}
254
255
256
257
258static struct clock_event_device xttcpss_clockevent = {
259 .name = "xttcpss_timer2",
260 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
261 .set_next_event = xttcpss_set_next_event,
262 .set_mode = xttcpss_set_mode,
263 .rating = 200,
264};
265
266
267
268
269
270
271
272static void __init xttcpss_timer_init(void)
273{
274 xttcpss_timer_hardware_init();
275 clocksource_register_hz(&clocksource_xttcpss, TIMER_RATE);
276
277
278
279
280 clockevents_calc_mult_shift(&xttcpss_clockevent, TIMER_RATE, 4);
281
282 xttcpss_clockevent.max_delta_ns =
283 clockevent_delta2ns(0xfffe, &xttcpss_clockevent);
284 xttcpss_clockevent.min_delta_ns =
285 clockevent_delta2ns(1, &xttcpss_clockevent);
286
287
288
289 xttcpss_clockevent.cpumask = cpumask_of(0);
290 clockevents_register_device(&xttcpss_clockevent);
291}
292
293
294
295
296struct sys_timer xttcpss_sys_timer = {
297 .init = xttcpss_timer_init,
298};
299