Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/nios2/kernel/time.c
26424 views
1
/*
2
* Copyright (C) 2013-2014 Altera Corporation
3
* Copyright (C) 2010 Tobias Klauser <[email protected]>
4
* Copyright (C) 2004 Microtronix Datacom Ltd.
5
*
6
* This file is subject to the terms and conditions of the GNU General Public
7
* License. See the file "COPYING" in the main directory of this archive
8
* for more details.
9
*/
10
11
#include <linux/export.h>
12
#include <linux/interrupt.h>
13
#include <linux/clockchips.h>
14
#include <linux/clocksource.h>
15
#include <linux/delay.h>
16
#include <linux/of.h>
17
#include <linux/of_address.h>
18
#include <linux/of_irq.h>
19
#include <linux/io.h>
20
#include <linux/slab.h>
21
22
#define ALTR_TIMER_COMPATIBLE "altr,timer-1.0"
23
24
#define ALTERA_TIMER_STATUS_REG 0
25
#define ALTERA_TIMER_CONTROL_REG 4
26
#define ALTERA_TIMER_PERIODL_REG 8
27
#define ALTERA_TIMER_PERIODH_REG 12
28
#define ALTERA_TIMER_SNAPL_REG 16
29
#define ALTERA_TIMER_SNAPH_REG 20
30
31
#define ALTERA_TIMER_CONTROL_ITO_MSK (0x1)
32
#define ALTERA_TIMER_CONTROL_CONT_MSK (0x2)
33
#define ALTERA_TIMER_CONTROL_START_MSK (0x4)
34
#define ALTERA_TIMER_CONTROL_STOP_MSK (0x8)
35
36
struct nios2_timer {
37
void __iomem *base;
38
unsigned long freq;
39
};
40
41
struct nios2_clockevent_dev {
42
struct nios2_timer timer;
43
struct clock_event_device ced;
44
};
45
46
struct nios2_clocksource {
47
struct nios2_timer timer;
48
struct clocksource cs;
49
};
50
51
static inline struct nios2_clockevent_dev *
52
to_nios2_clkevent(struct clock_event_device *evt)
53
{
54
return container_of(evt, struct nios2_clockevent_dev, ced);
55
}
56
57
static inline struct nios2_clocksource *
58
to_nios2_clksource(struct clocksource *cs)
59
{
60
return container_of(cs, struct nios2_clocksource, cs);
61
}
62
63
static u16 timer_readw(struct nios2_timer *timer, u32 offs)
64
{
65
return readw(timer->base + offs);
66
}
67
68
static void timer_writew(struct nios2_timer *timer, u16 val, u32 offs)
69
{
70
writew(val, timer->base + offs);
71
}
72
73
static inline unsigned long read_timersnapshot(struct nios2_timer *timer)
74
{
75
unsigned long count;
76
77
timer_writew(timer, 0, ALTERA_TIMER_SNAPL_REG);
78
count = timer_readw(timer, ALTERA_TIMER_SNAPH_REG) << 16 |
79
timer_readw(timer, ALTERA_TIMER_SNAPL_REG);
80
81
return count;
82
}
83
84
static u64 nios2_timer_read(struct clocksource *cs)
85
{
86
struct nios2_clocksource *nios2_cs = to_nios2_clksource(cs);
87
unsigned long flags;
88
u32 count;
89
90
local_irq_save(flags);
91
count = read_timersnapshot(&nios2_cs->timer);
92
local_irq_restore(flags);
93
94
/* Counter is counting down */
95
return ~count;
96
}
97
98
static struct nios2_clocksource nios2_cs = {
99
.cs = {
100
.name = "nios2-clksrc",
101
.rating = 250,
102
.read = nios2_timer_read,
103
.mask = CLOCKSOURCE_MASK(32),
104
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
105
},
106
};
107
108
cycles_t get_cycles(void)
109
{
110
/* Only read timer if it has been initialized */
111
if (nios2_cs.timer.base)
112
return nios2_timer_read(&nios2_cs.cs);
113
return 0;
114
}
115
EXPORT_SYMBOL(get_cycles);
116
117
static void nios2_timer_start(struct nios2_timer *timer)
118
{
119
u16 ctrl;
120
121
ctrl = timer_readw(timer, ALTERA_TIMER_CONTROL_REG);
122
ctrl |= ALTERA_TIMER_CONTROL_START_MSK;
123
timer_writew(timer, ctrl, ALTERA_TIMER_CONTROL_REG);
124
}
125
126
static void nios2_timer_stop(struct nios2_timer *timer)
127
{
128
u16 ctrl;
129
130
ctrl = timer_readw(timer, ALTERA_TIMER_CONTROL_REG);
131
ctrl |= ALTERA_TIMER_CONTROL_STOP_MSK;
132
timer_writew(timer, ctrl, ALTERA_TIMER_CONTROL_REG);
133
}
134
135
static void nios2_timer_config(struct nios2_timer *timer, unsigned long period,
136
bool periodic)
137
{
138
u16 ctrl;
139
140
/* The timer's actual period is one cycle greater than the value
141
* stored in the period register. */
142
period--;
143
144
ctrl = timer_readw(timer, ALTERA_TIMER_CONTROL_REG);
145
/* stop counter */
146
timer_writew(timer, ctrl | ALTERA_TIMER_CONTROL_STOP_MSK,
147
ALTERA_TIMER_CONTROL_REG);
148
149
/* write new count */
150
timer_writew(timer, period, ALTERA_TIMER_PERIODL_REG);
151
timer_writew(timer, period >> 16, ALTERA_TIMER_PERIODH_REG);
152
153
ctrl |= ALTERA_TIMER_CONTROL_START_MSK | ALTERA_TIMER_CONTROL_ITO_MSK;
154
if (periodic)
155
ctrl |= ALTERA_TIMER_CONTROL_CONT_MSK;
156
else
157
ctrl &= ~ALTERA_TIMER_CONTROL_CONT_MSK;
158
timer_writew(timer, ctrl, ALTERA_TIMER_CONTROL_REG);
159
}
160
161
static int nios2_timer_set_next_event(unsigned long delta,
162
struct clock_event_device *evt)
163
{
164
struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt);
165
166
nios2_timer_config(&nios2_ced->timer, delta, false);
167
168
return 0;
169
}
170
171
static int nios2_timer_shutdown(struct clock_event_device *evt)
172
{
173
struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt);
174
struct nios2_timer *timer = &nios2_ced->timer;
175
176
nios2_timer_stop(timer);
177
return 0;
178
}
179
180
static int nios2_timer_set_periodic(struct clock_event_device *evt)
181
{
182
unsigned long period;
183
struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt);
184
struct nios2_timer *timer = &nios2_ced->timer;
185
186
period = DIV_ROUND_UP(timer->freq, HZ);
187
nios2_timer_config(timer, period, true);
188
return 0;
189
}
190
191
static int nios2_timer_resume(struct clock_event_device *evt)
192
{
193
struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt);
194
struct nios2_timer *timer = &nios2_ced->timer;
195
196
nios2_timer_start(timer);
197
return 0;
198
}
199
200
irqreturn_t timer_interrupt(int irq, void *dev_id)
201
{
202
struct clock_event_device *evt = (struct clock_event_device *) dev_id;
203
struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt);
204
205
/* Clear the interrupt condition */
206
timer_writew(&nios2_ced->timer, 0, ALTERA_TIMER_STATUS_REG);
207
evt->event_handler(evt);
208
209
return IRQ_HANDLED;
210
}
211
212
static int __init nios2_timer_get_base_and_freq(struct device_node *np,
213
void __iomem **base, u32 *freq)
214
{
215
*base = of_iomap(np, 0);
216
if (!*base) {
217
pr_crit("Unable to map reg for %pOFn\n", np);
218
return -ENXIO;
219
}
220
221
if (of_property_read_u32(np, "clock-frequency", freq)) {
222
pr_crit("Unable to get %pOFn clock frequency\n", np);
223
return -EINVAL;
224
}
225
226
return 0;
227
}
228
229
static struct nios2_clockevent_dev nios2_ce = {
230
.ced = {
231
.name = "nios2-clkevent",
232
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
233
.rating = 250,
234
.shift = 32,
235
.set_next_event = nios2_timer_set_next_event,
236
.set_state_shutdown = nios2_timer_shutdown,
237
.set_state_periodic = nios2_timer_set_periodic,
238
.set_state_oneshot = nios2_timer_shutdown,
239
.tick_resume = nios2_timer_resume,
240
},
241
};
242
243
static __init int nios2_clockevent_init(struct device_node *timer)
244
{
245
void __iomem *iobase;
246
u32 freq;
247
int irq, ret;
248
249
ret = nios2_timer_get_base_and_freq(timer, &iobase, &freq);
250
if (ret)
251
return ret;
252
253
irq = irq_of_parse_and_map(timer, 0);
254
if (!irq) {
255
pr_crit("Unable to parse timer irq\n");
256
return -EINVAL;
257
}
258
259
nios2_ce.timer.base = iobase;
260
nios2_ce.timer.freq = freq;
261
262
nios2_ce.ced.cpumask = cpumask_of(0);
263
nios2_ce.ced.irq = irq;
264
265
nios2_timer_stop(&nios2_ce.timer);
266
/* clear pending interrupt */
267
timer_writew(&nios2_ce.timer, 0, ALTERA_TIMER_STATUS_REG);
268
269
ret = request_irq(irq, timer_interrupt, IRQF_TIMER, timer->name,
270
&nios2_ce.ced);
271
if (ret) {
272
pr_crit("Unable to setup timer irq\n");
273
return ret;
274
}
275
276
clockevents_config_and_register(&nios2_ce.ced, freq, 1, ULONG_MAX);
277
278
return 0;
279
}
280
281
static __init int nios2_clocksource_init(struct device_node *timer)
282
{
283
unsigned int ctrl;
284
void __iomem *iobase;
285
u32 freq;
286
int ret;
287
288
ret = nios2_timer_get_base_and_freq(timer, &iobase, &freq);
289
if (ret)
290
return ret;
291
292
nios2_cs.timer.base = iobase;
293
nios2_cs.timer.freq = freq;
294
295
ret = clocksource_register_hz(&nios2_cs.cs, freq);
296
if (ret)
297
return ret;
298
299
timer_writew(&nios2_cs.timer, USHRT_MAX, ALTERA_TIMER_PERIODL_REG);
300
timer_writew(&nios2_cs.timer, USHRT_MAX, ALTERA_TIMER_PERIODH_REG);
301
302
/* interrupt disable + continuous + start */
303
ctrl = ALTERA_TIMER_CONTROL_CONT_MSK | ALTERA_TIMER_CONTROL_START_MSK;
304
timer_writew(&nios2_cs.timer, ctrl, ALTERA_TIMER_CONTROL_REG);
305
306
/* Calibrate the delay loop directly */
307
lpj_fine = freq / HZ;
308
309
return 0;
310
}
311
312
/*
313
* The first timer instance will use as a clockevent. If there are two or
314
* more instances, the second one gets used as clocksource and all
315
* others are unused.
316
*/
317
static int __init nios2_time_init(struct device_node *timer)
318
{
319
static int num_called;
320
int ret;
321
322
switch (num_called) {
323
case 0:
324
ret = nios2_clockevent_init(timer);
325
break;
326
case 1:
327
ret = nios2_clocksource_init(timer);
328
break;
329
default:
330
ret = 0;
331
break;
332
}
333
334
num_called++;
335
336
return ret;
337
}
338
339
void read_persistent_clock64(struct timespec64 *ts)
340
{
341
ts->tv_sec = mktime64(2007, 1, 1, 0, 0, 0);
342
ts->tv_nsec = 0;
343
}
344
345
void __init time_init(void)
346
{
347
struct device_node *np;
348
int count = 0;
349
350
for_each_compatible_node(np, NULL, ALTR_TIMER_COMPATIBLE)
351
count++;
352
353
if (count < 2)
354
panic("%d timer is found, it needs 2 timers in system\n", count);
355
356
timer_probe();
357
}
358
359
TIMER_OF_DECLARE(nios2_timer, ALTR_TIMER_COMPATIBLE, nios2_time_init);
360
361