Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/allwinner/aw_timer.c
39563 views
1
/*-
2
* Copyright (c) 2012 Ganbold Tsagaankhuu <[email protected]>
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
* SUCH DAMAGE.
25
*/
26
27
#include <sys/param.h>
28
#include <sys/systm.h>
29
#include <sys/bus.h>
30
#include <sys/kernel.h>
31
#include <sys/malloc.h>
32
#include <sys/module.h>
33
#include <sys/rman.h>
34
#include <sys/timeet.h>
35
#include <sys/timetc.h>
36
#include <sys/watchdog.h>
37
38
#include <machine/bus.h>
39
#include <machine/intr.h>
40
#include <machine/machdep.h>
41
42
#include <dev/ofw/openfirm.h>
43
#include <dev/ofw/ofw_bus.h>
44
#include <dev/ofw/ofw_bus_subr.h>
45
46
#include <dev/clk/clk.h>
47
48
#if defined(__aarch64__) || defined(__riscv)
49
#include "opt_soc.h"
50
#else
51
#include <arm/allwinner/aw_machdep.h>
52
#endif
53
54
/**
55
* Timer registers addr
56
*
57
*/
58
#define TIMER_IRQ_EN_REG 0x00
59
#define TIMER_IRQ_ENABLE(x) (1 << x)
60
61
#define TIMER_IRQ_STA_REG 0x04
62
#define TIMER_IRQ_PENDING(x) (1 << x)
63
64
/*
65
* On A10, A13, A20 and A31/A31s 6 timers are available
66
*/
67
#define TIMER_CTRL_REG(x) (0x10 + 0x10 * x)
68
#define TIMER_CTRL_START (1 << 0)
69
#define TIMER_CTRL_AUTORELOAD (1 << 1)
70
#define TIMER_CTRL_CLKSRC_MASK (3 << 2)
71
#define TIMER_CTRL_OSC24M (1 << 2)
72
#define TIMER_CTRL_PRESCALAR_MASK (0x7 << 4)
73
#define TIMER_CTRL_PRESCALAR(x) ((x - 1) << 4)
74
#define TIMER_CTRL_MODE_MASK (1 << 7)
75
#define TIMER_CTRL_MODE_SINGLE (1 << 7)
76
#define TIMER_CTRL_MODE_CONTINUOUS (0 << 7)
77
#define TIMER_INTV_REG(x) (0x14 + 0x10 * x)
78
#define TIMER_CURV_REG(x) (0x18 + 0x10 * x)
79
80
/* 64 bit counter, available in A10 and A13 */
81
#define CNT64_CTRL_REG 0xa0
82
#define CNT64_CTRL_RL_EN 0x02 /* read latch enable */
83
#define CNT64_LO_REG 0xa4
84
#define CNT64_HI_REG 0xa8
85
86
#define SYS_TIMER_CLKSRC 24000000 /* clock source */
87
88
enum aw_timer_type {
89
A10_TIMER = 1,
90
A23_TIMER,
91
D1_TIMER,
92
};
93
94
struct aw_timer_softc {
95
device_t sc_dev;
96
struct resource *res[2];
97
void *sc_ih; /* interrupt handler */
98
uint32_t sc_period;
99
uint64_t timer0_freq;
100
struct eventtimer et;
101
enum aw_timer_type type;
102
};
103
104
#define timer_read_4(sc, reg) \
105
bus_read_4(sc->res[AW_TIMER_MEMRES], reg)
106
#define timer_write_4(sc, reg, val) \
107
bus_write_4(sc->res[AW_TIMER_MEMRES], reg, val)
108
109
#if defined(__arm__)
110
static u_int a10_timer_get_timecount(struct timecounter *);
111
static uint64_t a10_timer_read_counter64(struct aw_timer_softc *sc);
112
static void a10_timer_timecounter_setup(struct aw_timer_softc *sc);
113
#endif
114
115
#if defined(__arm__) || defined(__riscv)
116
#define USE_EVENTTIMER
117
static void aw_timer_eventtimer_setup(struct aw_timer_softc *sc);
118
static int aw_timer_eventtimer_start(struct eventtimer *, sbintime_t first,
119
sbintime_t period);
120
static int aw_timer_eventtimer_stop(struct eventtimer *);
121
#endif
122
123
#if defined(__aarch64__)
124
static void a23_timer_timecounter_setup(struct aw_timer_softc *sc);
125
static u_int a23_timer_get_timecount(struct timecounter *tc);
126
#endif
127
128
static int aw_timer_irq(void *);
129
static int aw_timer_probe(device_t);
130
static int aw_timer_attach(device_t);
131
132
#if defined(__arm__)
133
#define AW_TIMER_QUALITY 1000
134
135
static delay_func a10_timer_delay;
136
137
static struct timecounter a10_timer_timecounter = {
138
.tc_name = "aw_timer timer0",
139
.tc_get_timecount = a10_timer_get_timecount,
140
.tc_counter_mask = ~0u,
141
.tc_frequency = 0,
142
.tc_quality = AW_TIMER_QUALITY,
143
};
144
#endif
145
146
#if defined(__aarch64__)
147
/* We want it to be selected over the arm generic timecounter */
148
#define AW_TIMER_QUALITY 2000
149
150
static struct timecounter a23_timer_timecounter = {
151
.tc_name = "aw_timer timer0",
152
.tc_get_timecount = a23_timer_get_timecount,
153
.tc_counter_mask = ~0u,
154
.tc_frequency = 0,
155
.tc_quality = AW_TIMER_QUALITY,
156
};
157
#endif
158
159
#if defined(__riscv)
160
/* We want it to be selected over the generic RISC-V eventtimer */
161
#define AW_TIMER_QUALITY 2000
162
#endif
163
164
#define AW_TIMER_MEMRES 0
165
#define AW_TIMER_IRQRES 1
166
167
static struct resource_spec aw_timer_spec[] = {
168
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
169
{ SYS_RES_IRQ, 0, RF_ACTIVE },
170
{ -1, 0 }
171
};
172
173
static struct ofw_compat_data compat_data[] = {
174
{"allwinner,sun4i-a10-timer", A10_TIMER},
175
#if defined(__aarch64__)
176
{"allwinner,sun8i-a23-timer", A23_TIMER},
177
#elif defined(__riscv)
178
{"allwinner,sun20i-d1-timer", D1_TIMER},
179
#endif
180
{NULL, 0},
181
};
182
183
static int
184
aw_timer_probe(device_t dev)
185
{
186
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
187
return (ENXIO);
188
189
#if defined(__arm__)
190
/* For SoC >= A10 we have the ARM Timecounter/Eventtimer */
191
u_int soc_family = allwinner_soc_family();
192
if (soc_family != ALLWINNERSOC_SUN4I &&
193
soc_family != ALLWINNERSOC_SUN5I)
194
return (ENXIO);
195
#endif
196
197
device_set_desc(dev, "Allwinner timer");
198
return (BUS_PROBE_DEFAULT);
199
}
200
201
static int
202
aw_timer_attach(device_t dev)
203
{
204
struct aw_timer_softc *sc;
205
clk_t clk;
206
int err;
207
208
sc = device_get_softc(dev);
209
sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
210
211
if (bus_alloc_resources(dev, aw_timer_spec, sc->res)) {
212
device_printf(dev, "could not allocate resources\n");
213
return (ENXIO);
214
}
215
216
sc->sc_dev = dev;
217
218
/* Setup and enable the timer interrupt */
219
err = bus_setup_intr(dev, sc->res[AW_TIMER_IRQRES], INTR_TYPE_CLK,
220
aw_timer_irq, NULL, sc, &sc->sc_ih);
221
if (err != 0) {
222
bus_release_resources(dev, aw_timer_spec, sc->res);
223
device_printf(dev, "Unable to setup the clock irq handler, "
224
"err = %d\n", err);
225
return (ENXIO);
226
}
227
228
if (clk_get_by_ofw_index(dev, 0, 0, &clk) != 0) {
229
sc->timer0_freq = SYS_TIMER_CLKSRC;
230
} else {
231
if (clk_get_freq(clk, &sc->timer0_freq) != 0) {
232
device_printf(dev, "Cannot get clock source frequency\n");
233
return (ENXIO);
234
}
235
}
236
237
if (bootverbose) {
238
device_printf(sc->sc_dev, "clock: hz=%d stathz = %d\n", hz,
239
stathz);
240
}
241
242
/* Set up eventtimer (if applicable) */
243
#if defined(USE_EVENTTIMER)
244
aw_timer_eventtimer_setup(sc);
245
#endif
246
247
/* Set up timercounter (if applicable) */
248
#if defined(__arm__)
249
a10_timer_timecounter_setup(sc);
250
#elif defined(__aarch64__)
251
a23_timer_timecounter_setup(sc);
252
#endif
253
254
return (0);
255
}
256
257
static int
258
aw_timer_irq(void *arg)
259
{
260
struct aw_timer_softc *sc;
261
uint32_t val;
262
263
sc = (struct aw_timer_softc *)arg;
264
265
/* Clear interrupt pending bit. */
266
timer_write_4(sc, TIMER_IRQ_STA_REG, TIMER_IRQ_PENDING(0));
267
268
val = timer_read_4(sc, TIMER_CTRL_REG(0));
269
270
/*
271
* Disabled autoreload and sc_period > 0 means
272
* timer_start was called with non NULL first value.
273
* Now we will set periodic timer with the given period
274
* value.
275
*/
276
if ((val & (1<<1)) == 0 && sc->sc_period > 0) {
277
/* Update timer */
278
timer_write_4(sc, TIMER_CURV_REG(0), sc->sc_period);
279
280
/* Make periodic and enable */
281
val |= TIMER_CTRL_AUTORELOAD | TIMER_CTRL_START;
282
timer_write_4(sc, TIMER_CTRL_REG(0), val);
283
}
284
285
if (sc->et.et_active)
286
sc->et.et_event_cb(&sc->et, sc->et.et_arg);
287
288
return (FILTER_HANDLED);
289
}
290
291
/*
292
* Event timer function for A10, A13, and D1.
293
*/
294
#if defined(USE_EVENTTIMER)
295
static void
296
aw_timer_eventtimer_setup(struct aw_timer_softc *sc)
297
{
298
uint32_t val;
299
300
/* Set clock source to OSC24M, 1 pre-division, continuous mode */
301
val = timer_read_4(sc, TIMER_CTRL_REG(0));
302
val &= ~TIMER_CTRL_PRESCALAR_MASK | ~TIMER_CTRL_MODE_MASK | ~TIMER_CTRL_CLKSRC_MASK;
303
val |= TIMER_CTRL_PRESCALAR(1) | TIMER_CTRL_OSC24M;
304
timer_write_4(sc, TIMER_CTRL_REG(0), val);
305
306
/* Enable timer0 */
307
val = timer_read_4(sc, TIMER_IRQ_EN_REG);
308
val |= TIMER_IRQ_ENABLE(0);
309
timer_write_4(sc, TIMER_IRQ_EN_REG, val);
310
311
/* Set desired frequency in event timer and timecounter */
312
sc->et.et_frequency = sc->timer0_freq;
313
sc->et.et_name = "aw_timer Eventtimer";
314
sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERIODIC;
315
sc->et.et_quality = AW_TIMER_QUALITY;
316
sc->et.et_min_period = (0x00000005LLU << 32) / sc->et.et_frequency;
317
sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency;
318
sc->et.et_start = aw_timer_eventtimer_start;
319
sc->et.et_stop = aw_timer_eventtimer_stop;
320
sc->et.et_priv = sc;
321
et_register(&sc->et);
322
323
if (bootverbose) {
324
device_printf(sc->sc_dev, "event timer clock frequency %ju\n",
325
sc->timer0_freq);
326
}
327
}
328
329
static int
330
aw_timer_eventtimer_start(struct eventtimer *et, sbintime_t first,
331
sbintime_t period)
332
{
333
struct aw_timer_softc *sc;
334
uint32_t count;
335
uint32_t val;
336
337
sc = (struct aw_timer_softc *)et->et_priv;
338
339
if (period != 0)
340
sc->sc_period = ((uint32_t)et->et_frequency * period) >> 32;
341
else
342
sc->sc_period = 0;
343
if (first != 0)
344
count = ((uint32_t)et->et_frequency * first) >> 32;
345
else
346
count = sc->sc_period;
347
348
/* Update timer values */
349
timer_write_4(sc, TIMER_INTV_REG(0), sc->sc_period);
350
timer_write_4(sc, TIMER_CURV_REG(0), count);
351
352
val = timer_read_4(sc, TIMER_CTRL_REG(0));
353
if (period != 0) {
354
/* periodic */
355
val |= TIMER_CTRL_AUTORELOAD;
356
} else {
357
/* oneshot */
358
val &= ~TIMER_CTRL_AUTORELOAD;
359
}
360
/* Enable timer0 */
361
val |= TIMER_IRQ_ENABLE(0);
362
timer_write_4(sc, TIMER_CTRL_REG(0), val);
363
364
return (0);
365
}
366
367
static int
368
aw_timer_eventtimer_stop(struct eventtimer *et)
369
{
370
struct aw_timer_softc *sc;
371
uint32_t val;
372
373
sc = (struct aw_timer_softc *)et->et_priv;
374
375
/* Disable timer0 */
376
val = timer_read_4(sc, TIMER_CTRL_REG(0));
377
val &= ~TIMER_CTRL_START;
378
timer_write_4(sc, TIMER_CTRL_REG(0), val);
379
380
sc->sc_period = 0;
381
382
return (0);
383
}
384
#endif /* USE_EVENTTIMER */
385
386
/*
387
* Timecounter functions for A23 and above
388
*/
389
390
#if defined(__aarch64__)
391
static void
392
a23_timer_timecounter_setup(struct aw_timer_softc *sc)
393
{
394
uint32_t val;
395
396
/* Set clock source to OSC24M, 1 pre-division, continuous mode */
397
val = timer_read_4(sc, TIMER_CTRL_REG(0));
398
val &= ~TIMER_CTRL_PRESCALAR_MASK | ~TIMER_CTRL_MODE_MASK | ~TIMER_CTRL_CLKSRC_MASK;
399
val |= TIMER_CTRL_PRESCALAR(1) | TIMER_CTRL_OSC24M;
400
timer_write_4(sc, TIMER_CTRL_REG(0), val);
401
402
/* Set reload value */
403
timer_write_4(sc, TIMER_INTV_REG(0), ~0);
404
val = timer_read_4(sc, TIMER_INTV_REG(0));
405
406
/* Enable timer0 */
407
val = timer_read_4(sc, TIMER_CTRL_REG(0));
408
val |= TIMER_CTRL_AUTORELOAD | TIMER_CTRL_START;
409
timer_write_4(sc, TIMER_CTRL_REG(0), val);
410
411
val = timer_read_4(sc, TIMER_CURV_REG(0));
412
413
a23_timer_timecounter.tc_priv = sc;
414
a23_timer_timecounter.tc_frequency = sc->timer0_freq;
415
tc_init(&a23_timer_timecounter);
416
417
if (bootverbose) {
418
device_printf(sc->sc_dev, "timecounter clock frequency %jd\n",
419
a23_timer_timecounter.tc_frequency);
420
}
421
}
422
423
static u_int
424
a23_timer_get_timecount(struct timecounter *tc)
425
{
426
struct aw_timer_softc *sc;
427
uint32_t val;
428
429
sc = (struct aw_timer_softc *)tc->tc_priv;
430
if (sc == NULL)
431
return (0);
432
433
val = timer_read_4(sc, TIMER_CURV_REG(0));
434
/* Counter count backwards */
435
return (~0u - val);
436
}
437
#endif /* __aarch64__ */
438
439
/*
440
* Timecounter functions for A10 and A13, using the 64 bits counter
441
*/
442
443
#if defined(__arm__)
444
static uint64_t
445
a10_timer_read_counter64(struct aw_timer_softc *sc)
446
{
447
uint32_t lo, hi;
448
449
/* Latch counter, wait for it to be ready to read. */
450
timer_write_4(sc, CNT64_CTRL_REG, CNT64_CTRL_RL_EN);
451
while (timer_read_4(sc, CNT64_CTRL_REG) & CNT64_CTRL_RL_EN)
452
continue;
453
454
hi = timer_read_4(sc, CNT64_HI_REG);
455
lo = timer_read_4(sc, CNT64_LO_REG);
456
457
return (((uint64_t)hi << 32) | lo);
458
}
459
460
static void
461
a10_timer_delay(int usec, void *arg)
462
{
463
struct aw_timer_softc *sc = arg;
464
uint64_t end, now;
465
466
now = a10_timer_read_counter64(sc);
467
end = now + (sc->timer0_freq / 1000000) * (usec + 1);
468
469
while (now < end)
470
now = a10_timer_read_counter64(sc);
471
}
472
473
static u_int
474
a10_timer_get_timecount(struct timecounter *tc)
475
{
476
if (tc->tc_priv == NULL)
477
return (0);
478
479
return ((u_int)a10_timer_read_counter64(tc->tc_priv));
480
}
481
482
static void
483
a10_timer_timecounter_setup(struct aw_timer_softc *sc)
484
{
485
arm_set_delay(a10_timer_delay, sc);
486
a10_timer_timecounter.tc_priv = sc;
487
a10_timer_timecounter.tc_frequency = sc->timer0_freq;
488
tc_init(&a10_timer_timecounter);
489
490
if (bootverbose) {
491
device_printf(sc->sc_dev, "timecounter clock frequency %jd\n",
492
a10_timer_timecounter.tc_frequency);
493
}
494
}
495
#endif /* __arm__ */
496
497
static device_method_t aw_timer_methods[] = {
498
DEVMETHOD(device_probe, aw_timer_probe),
499
DEVMETHOD(device_attach, aw_timer_attach),
500
501
DEVMETHOD_END
502
};
503
504
static driver_t aw_timer_driver = {
505
"aw_timer",
506
aw_timer_methods,
507
sizeof(struct aw_timer_softc),
508
};
509
510
EARLY_DRIVER_MODULE(aw_timer, simplebus, aw_timer_driver, 0, 0,
511
BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
512
513