Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/microblaze/kernel/timer.c
26424 views
1
/*
2
* Copyright (C) 2007-2013 Michal Simek <[email protected]>
3
* Copyright (C) 2012-2013 Xilinx, Inc.
4
* Copyright (C) 2007-2009 PetaLogix
5
* Copyright (C) 2006 Atmark Techno, Inc.
6
*
7
* This file is subject to the terms and conditions of the GNU General Public
8
* License. See the file "COPYING" in the main directory of this archive
9
* for more details.
10
*/
11
12
#include <linux/interrupt.h>
13
#include <linux/delay.h>
14
#include <linux/sched.h>
15
#include <linux/sched/clock.h>
16
#include <linux/sched_clock.h>
17
#include <linux/clk.h>
18
#include <linux/clockchips.h>
19
#include <linux/of_address.h>
20
#include <linux/of_irq.h>
21
#include <linux/timecounter.h>
22
#include <asm/cpuinfo.h>
23
24
static void __iomem *timer_baseaddr;
25
26
static unsigned int freq_div_hz;
27
static unsigned int timer_clock_freq;
28
29
#define TCSR0 (0x00)
30
#define TLR0 (0x04)
31
#define TCR0 (0x08)
32
#define TCSR1 (0x10)
33
#define TLR1 (0x14)
34
#define TCR1 (0x18)
35
36
#define TCSR_MDT (1<<0)
37
#define TCSR_UDT (1<<1)
38
#define TCSR_GENT (1<<2)
39
#define TCSR_CAPT (1<<3)
40
#define TCSR_ARHT (1<<4)
41
#define TCSR_LOAD (1<<5)
42
#define TCSR_ENIT (1<<6)
43
#define TCSR_ENT (1<<7)
44
#define TCSR_TINT (1<<8)
45
#define TCSR_PWMA (1<<9)
46
#define TCSR_ENALL (1<<10)
47
48
static unsigned int (*read_fn)(void __iomem *);
49
static void (*write_fn)(u32, void __iomem *);
50
51
static void timer_write32(u32 val, void __iomem *addr)
52
{
53
iowrite32(val, addr);
54
}
55
56
static unsigned int timer_read32(void __iomem *addr)
57
{
58
return ioread32(addr);
59
}
60
61
static void timer_write32_be(u32 val, void __iomem *addr)
62
{
63
iowrite32be(val, addr);
64
}
65
66
static unsigned int timer_read32_be(void __iomem *addr)
67
{
68
return ioread32be(addr);
69
}
70
71
static inline void xilinx_timer0_stop(void)
72
{
73
write_fn(read_fn(timer_baseaddr + TCSR0) & ~TCSR_ENT,
74
timer_baseaddr + TCSR0);
75
}
76
77
static inline void xilinx_timer0_start_periodic(unsigned long load_val)
78
{
79
if (!load_val)
80
load_val = 1;
81
/* loading value to timer reg */
82
write_fn(load_val, timer_baseaddr + TLR0);
83
84
/* load the initial value */
85
write_fn(TCSR_LOAD, timer_baseaddr + TCSR0);
86
87
/* see timer data sheet for detail
88
* !ENALL - don't enable 'em all
89
* !PWMA - disable pwm
90
* TINT - clear interrupt status
91
* ENT- enable timer itself
92
* ENIT - enable interrupt
93
* !LOAD - clear the bit to let go
94
* ARHT - auto reload
95
* !CAPT - no external trigger
96
* !GENT - no external signal
97
* UDT - set the timer as down counter
98
* !MDT0 - generate mode
99
*/
100
write_fn(TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT,
101
timer_baseaddr + TCSR0);
102
}
103
104
static inline void xilinx_timer0_start_oneshot(unsigned long load_val)
105
{
106
if (!load_val)
107
load_val = 1;
108
/* loading value to timer reg */
109
write_fn(load_val, timer_baseaddr + TLR0);
110
111
/* load the initial value */
112
write_fn(TCSR_LOAD, timer_baseaddr + TCSR0);
113
114
write_fn(TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT,
115
timer_baseaddr + TCSR0);
116
}
117
118
static int xilinx_timer_set_next_event(unsigned long delta,
119
struct clock_event_device *dev)
120
{
121
pr_debug("%s: next event, delta %x\n", __func__, (u32)delta);
122
xilinx_timer0_start_oneshot(delta);
123
return 0;
124
}
125
126
static int xilinx_timer_shutdown(struct clock_event_device *evt)
127
{
128
pr_info("%s\n", __func__);
129
xilinx_timer0_stop();
130
return 0;
131
}
132
133
static int xilinx_timer_set_periodic(struct clock_event_device *evt)
134
{
135
pr_info("%s\n", __func__);
136
xilinx_timer0_start_periodic(freq_div_hz);
137
return 0;
138
}
139
140
static struct clock_event_device clockevent_xilinx_timer = {
141
.name = "xilinx_clockevent",
142
.features = CLOCK_EVT_FEAT_ONESHOT |
143
CLOCK_EVT_FEAT_PERIODIC,
144
.shift = 8,
145
.rating = 300,
146
.set_next_event = xilinx_timer_set_next_event,
147
.set_state_shutdown = xilinx_timer_shutdown,
148
.set_state_periodic = xilinx_timer_set_periodic,
149
};
150
151
static inline void timer_ack(void)
152
{
153
write_fn(read_fn(timer_baseaddr + TCSR0), timer_baseaddr + TCSR0);
154
}
155
156
static irqreturn_t timer_interrupt(int irq, void *dev_id)
157
{
158
struct clock_event_device *evt = &clockevent_xilinx_timer;
159
timer_ack();
160
evt->event_handler(evt);
161
return IRQ_HANDLED;
162
}
163
164
static __init int xilinx_clockevent_init(void)
165
{
166
clockevent_xilinx_timer.mult =
167
div_sc(timer_clock_freq, NSEC_PER_SEC,
168
clockevent_xilinx_timer.shift);
169
clockevent_xilinx_timer.max_delta_ns =
170
clockevent_delta2ns((u32)~0, &clockevent_xilinx_timer);
171
clockevent_xilinx_timer.max_delta_ticks = (u32)~0;
172
clockevent_xilinx_timer.min_delta_ns =
173
clockevent_delta2ns(1, &clockevent_xilinx_timer);
174
clockevent_xilinx_timer.min_delta_ticks = 1;
175
clockevent_xilinx_timer.cpumask = cpumask_of(0);
176
clockevents_register_device(&clockevent_xilinx_timer);
177
178
return 0;
179
}
180
181
static u64 xilinx_clock_read(void)
182
{
183
return read_fn(timer_baseaddr + TCR1);
184
}
185
186
static u64 xilinx_read(struct clocksource *cs)
187
{
188
/* reading actual value of timer 1 */
189
return (u64)xilinx_clock_read();
190
}
191
192
static struct timecounter xilinx_tc = {
193
.cc = NULL,
194
};
195
196
static u64 xilinx_cc_read(struct cyclecounter *cc)
197
{
198
return xilinx_read(NULL);
199
}
200
201
static struct cyclecounter xilinx_cc = {
202
.read = xilinx_cc_read,
203
.mask = CLOCKSOURCE_MASK(32),
204
.shift = 8,
205
};
206
207
static int __init init_xilinx_timecounter(void)
208
{
209
xilinx_cc.mult = div_sc(timer_clock_freq, NSEC_PER_SEC,
210
xilinx_cc.shift);
211
212
timecounter_init(&xilinx_tc, &xilinx_cc, sched_clock());
213
214
return 0;
215
}
216
217
static struct clocksource clocksource_microblaze = {
218
.name = "xilinx_clocksource",
219
.rating = 300,
220
.read = xilinx_read,
221
.mask = CLOCKSOURCE_MASK(32),
222
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
223
};
224
225
static int __init xilinx_clocksource_init(void)
226
{
227
int ret;
228
229
ret = clocksource_register_hz(&clocksource_microblaze,
230
timer_clock_freq);
231
if (ret) {
232
pr_err("failed to register clocksource");
233
return ret;
234
}
235
236
/* stop timer1 */
237
write_fn(read_fn(timer_baseaddr + TCSR1) & ~TCSR_ENT,
238
timer_baseaddr + TCSR1);
239
/* start timer1 - up counting without interrupt */
240
write_fn(TCSR_TINT|TCSR_ENT|TCSR_ARHT, timer_baseaddr + TCSR1);
241
242
/* register timecounter - for ftrace support */
243
return init_xilinx_timecounter();
244
}
245
246
static int __init xilinx_timer_init(struct device_node *timer)
247
{
248
struct clk *clk;
249
static int initialized;
250
u32 irq;
251
u32 timer_num = 1;
252
int ret;
253
254
/* If this property is present, the device is a PWM and not a timer */
255
if (of_property_present(timer, "#pwm-cells"))
256
return 0;
257
258
if (initialized)
259
return -EINVAL;
260
261
initialized = 1;
262
263
timer_baseaddr = of_iomap(timer, 0);
264
if (!timer_baseaddr) {
265
pr_err("ERROR: invalid timer base address\n");
266
return -ENXIO;
267
}
268
269
write_fn = timer_write32;
270
read_fn = timer_read32;
271
272
write_fn(TCSR_MDT, timer_baseaddr + TCSR0);
273
if (!(read_fn(timer_baseaddr + TCSR0) & TCSR_MDT)) {
274
write_fn = timer_write32_be;
275
read_fn = timer_read32_be;
276
}
277
278
irq = irq_of_parse_and_map(timer, 0);
279
if (irq <= 0) {
280
pr_err("Failed to parse and map irq");
281
return -EINVAL;
282
}
283
284
of_property_read_u32(timer, "xlnx,one-timer-only", &timer_num);
285
if (timer_num) {
286
pr_err("Please enable two timers in HW\n");
287
return -EINVAL;
288
}
289
290
pr_info("%pOF: irq=%d\n", timer, irq);
291
292
clk = of_clk_get(timer, 0);
293
if (IS_ERR(clk)) {
294
pr_err("ERROR: timer CCF input clock not found\n");
295
/* If there is clock-frequency property than use it */
296
of_property_read_u32(timer, "clock-frequency",
297
&timer_clock_freq);
298
} else {
299
timer_clock_freq = clk_get_rate(clk);
300
}
301
302
if (!timer_clock_freq) {
303
pr_err("ERROR: Using CPU clock frequency\n");
304
timer_clock_freq = cpuinfo.cpu_clock_freq;
305
}
306
307
freq_div_hz = timer_clock_freq / HZ;
308
309
ret = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer",
310
&clockevent_xilinx_timer);
311
if (ret) {
312
pr_err("Failed to setup IRQ");
313
return ret;
314
}
315
316
ret = xilinx_clocksource_init();
317
if (ret)
318
return ret;
319
320
ret = xilinx_clockevent_init();
321
if (ret)
322
return ret;
323
324
sched_clock_register(xilinx_clock_read, 32, timer_clock_freq);
325
326
return 0;
327
}
328
329
TIMER_OF_DECLARE(xilinx_timer, "xlnx,xps-timer-1.00.a",
330
xilinx_timer_init);
331
332