Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/freescale/imx/imx_epit.c
39536 views
1
/*-
2
* Copyright (c) 2017 Ian Lepore <[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/cdefs.h>
28
/*
29
* Driver for imx Enhanced Programmable Interval Timer, a simple free-running
30
* counter device that can be used as the system timecounter. On imx5 a second
31
* instance of the device is used as the system eventtimer.
32
*/
33
34
#include <sys/param.h>
35
#include <sys/systm.h>
36
#include <sys/bus.h>
37
#include <sys/kernel.h>
38
#include <sys/module.h>
39
#include <sys/malloc.h>
40
#include <sys/rman.h>
41
#include <sys/timeet.h>
42
#include <sys/timetc.h>
43
#include <sys/watchdog.h>
44
#include <machine/bus.h>
45
#include <machine/cpu.h>
46
#include <machine/intr.h>
47
#include <machine/machdep.h>
48
49
#include <dev/fdt/fdt_common.h>
50
#include <dev/ofw/openfirm.h>
51
#include <dev/ofw/ofw_bus.h>
52
#include <dev/ofw/ofw_bus_subr.h>
53
54
#include <arm/freescale/imx/imx_ccmvar.h>
55
#include <arm/freescale/imx/imx_machdep.h>
56
57
#define EPIT_CR 0x00 /* Control register */
58
#define EPIT_CR_CLKSRC_SHIFT 24
59
#define EPIT_CR_CLKSRC_OFF 0
60
#define EPIT_CR_CLKSRC_IPG 1
61
#define EPIT_CR_CLKSRC_HFCLK 2
62
#define EPIT_CR_CLKSRC_LFCLK 3
63
#define EPIT_CR_STOPEN (1u << 21)
64
#define EPIT_CR_WAITEN (1u << 19)
65
#define EPIT_CR_DBGEN (1u << 18)
66
#define EPIT_CR_IOVW (1u << 17)
67
#define EPIT_CR_SWR (1u << 16)
68
#define EPIT_CR_RLD (1u << 3)
69
#define EPIT_CR_OCIEN (1u << 2)
70
#define EPIT_CR_ENMOD (1u << 1)
71
#define EPIT_CR_EN (1u << 0)
72
73
#define EPIT_SR 0x04 /* Status register */
74
#define EPIT_SR_OCIF (1u << 0)
75
76
#define EPIT_LR 0x08 /* Load register */
77
#define EPIT_CMPR 0x0c /* Compare register */
78
#define EPIT_CNR 0x10 /* Counter register */
79
80
/*
81
* Define event timer limits.
82
*
83
* In theory our minimum period is 1 tick, because to setup a oneshot we don't
84
* need a read-modify-write sequence to calculate and set a compare register
85
* value while the counter is running. In practice the waveform diagrams in the
86
* manual make it appear that a setting of 1 might cause it to miss the event,
87
* so I'm setting the lower limit to 2 ticks.
88
*/
89
#define ET_MIN_TICKS 2
90
#define ET_MAX_TICKS 0xfffffffe
91
92
static u_int epit_tc_get_timecount(struct timecounter *tc);
93
94
struct epit_softc {
95
device_t dev;
96
struct resource * memres;
97
struct resource * intres;
98
void * inthandle;
99
uint32_t clkfreq;
100
uint32_t ctlreg;
101
uint32_t period;
102
struct timecounter tc;
103
struct eventtimer et;
104
bool oneshot;
105
};
106
107
/*
108
* Probe data. For some reason, the standard linux dts files don't have
109
* compatible properties on the epit devices (other properties are missing too,
110
* like clocks, but we don't care as much about that). So our probe routine
111
* uses the name of the node (must contain "epit") and the address of the
112
* registers as identifying marks.
113
*/
114
static const uint32_t imx51_epit_ioaddr[2] = {0x73fac000, 0x73fb0000};
115
static const uint32_t imx53_epit_ioaddr[2] = {0x53fac000, 0x53fb0000};
116
static const uint32_t imx6_epit_ioaddr[2] = {0x020d0000, 0x020d4000};
117
118
/* ocd_data is number of units to instantiate on the platform */
119
static struct ofw_compat_data compat_data[] = {
120
{"fsl,imx6ul-epit", 1},
121
{"fsl,imx6sx-epit", 1},
122
{"fsl,imx6q-epit", 1},
123
{"fsl,imx6dl-epit", 1},
124
{"fsl,imx53-epit", 2},
125
{"fsl,imx51-epit", 2},
126
{"fsl,imx31-epit", 2},
127
{"fsl,imx27-epit", 2},
128
{"fsl,imx25-epit", 2},
129
{NULL, 0}
130
};
131
132
static inline uint32_t
133
RD4(struct epit_softc *sc, bus_size_t offset)
134
{
135
136
return (bus_read_4(sc->memres, offset));
137
}
138
139
static inline void
140
WR4(struct epit_softc *sc, bus_size_t offset, uint32_t value)
141
{
142
143
bus_write_4(sc->memres, offset, value);
144
}
145
146
static inline void
147
WR4B(struct epit_softc *sc, bus_size_t offset, uint32_t value)
148
{
149
150
bus_write_4(sc->memres, offset, value);
151
bus_barrier(sc->memres, offset, 4, BUS_SPACE_BARRIER_WRITE);
152
}
153
154
static u_int
155
epit_read_counter(struct epit_softc *sc)
156
{
157
158
/*
159
* Hardware is a downcounter, adjust to look like it counts up for use
160
* with timecounter and DELAY.
161
*/
162
return (0xffffffff - RD4(sc, EPIT_CNR));
163
}
164
165
static void
166
epit_do_delay(int usec, void *arg)
167
{
168
struct epit_softc *sc = arg;
169
uint64_t curcnt, endcnt, startcnt, ticks;
170
171
/*
172
* Calculate the tick count with 64-bit values so that it works for any
173
* clock frequency. Loop until the hardware count reaches start+ticks.
174
* If the 32-bit hardware count rolls over while we're looping, just
175
* manually do a carry into the high bits after each read; don't worry
176
* that doing this on each loop iteration is inefficient -- we're trying
177
* to waste time here.
178
*/
179
ticks = 1 + ((uint64_t)usec * sc->clkfreq) / 1000000;
180
curcnt = startcnt = epit_read_counter(sc);
181
endcnt = startcnt + ticks;
182
while (curcnt < endcnt) {
183
curcnt = epit_read_counter(sc);
184
if (curcnt < startcnt)
185
curcnt += 1ULL << 32;
186
}
187
}
188
189
static u_int
190
epit_tc_get_timecount(struct timecounter *tc)
191
{
192
193
return (epit_read_counter(tc->tc_priv));
194
}
195
196
static int
197
epit_tc_attach(struct epit_softc *sc)
198
{
199
200
/* When the counter hits zero, reload with 0xffffffff. Start it. */
201
WR4(sc, EPIT_LR, 0xffffffff);
202
WR4(sc, EPIT_CR, sc->ctlreg | EPIT_CR_EN);
203
204
/* Register as a timecounter. */
205
sc->tc.tc_name = "EPIT";
206
sc->tc.tc_quality = 1000;
207
sc->tc.tc_frequency = sc->clkfreq;
208
sc->tc.tc_counter_mask = 0xffffffff;
209
sc->tc.tc_get_timecount = epit_tc_get_timecount;
210
sc->tc.tc_priv = sc;
211
tc_init(&sc->tc);
212
213
/* We are the DELAY() implementation. */
214
arm_set_delay(epit_do_delay, sc);
215
216
return (0);
217
}
218
219
static int
220
epit_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
221
{
222
struct epit_softc *sc;
223
uint32_t ticks;
224
225
sc = (struct epit_softc *)et->et_priv;
226
227
/*
228
* Disable the timer and clear any pending status. The timer may be
229
* running or may have just expired if we're called to reschedule the
230
* next event before the previous event time arrives.
231
*/
232
WR4(sc, EPIT_CR, sc->ctlreg);
233
WR4(sc, EPIT_SR, EPIT_SR_OCIF);
234
if (period != 0) {
235
sc->oneshot = false;
236
ticks = ((uint32_t)et->et_frequency * period) >> 32;
237
} else if (first != 0) {
238
sc->oneshot = true;
239
ticks = ((uint32_t)et->et_frequency * first) >> 32;
240
} else {
241
return (EINVAL);
242
}
243
244
/* Set the countdown load register and start the timer. */
245
WR4(sc, EPIT_LR, ticks);
246
WR4B(sc, EPIT_CR, sc->ctlreg | EPIT_CR_EN);
247
248
return (0);
249
}
250
251
static int
252
epit_et_stop(struct eventtimer *et)
253
{
254
struct epit_softc *sc;
255
256
sc = (struct epit_softc *)et->et_priv;
257
258
/* Disable the timer and clear any pending status. */
259
WR4(sc, EPIT_CR, sc->ctlreg);
260
WR4B(sc, EPIT_SR, EPIT_SR_OCIF);
261
262
return (0);
263
}
264
265
static int
266
epit_intr(void *arg)
267
{
268
struct epit_softc *sc;
269
uint32_t status;
270
271
sc = arg;
272
273
/*
274
* Disable a one-shot timer until a new event is scheduled so that the
275
* counter doesn't wrap and fire again. Do this before clearing the
276
* status since a short period would make it fire again really soon.
277
*
278
* Clear interrupt status before invoking event callbacks. The callback
279
* often sets up a new one-shot timer event and if the interval is short
280
* enough it can fire before we get out of this function. If we cleared
281
* at the bottom we'd miss the interrupt and hang until the clock wraps.
282
*/
283
if (sc->oneshot)
284
WR4(sc, EPIT_CR, sc->ctlreg);
285
286
status = RD4(sc, EPIT_SR);
287
WR4B(sc, EPIT_SR, status);
288
289
if ((status & EPIT_SR_OCIF) == 0)
290
return (FILTER_STRAY);
291
292
if (sc->et.et_active)
293
sc->et.et_event_cb(&sc->et, sc->et.et_arg);
294
295
return (FILTER_HANDLED);
296
}
297
298
static int
299
epit_et_attach(struct epit_softc *sc)
300
{
301
int err, rid;
302
303
rid = 0;
304
sc->intres = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &rid,
305
RF_ACTIVE);
306
if (sc->intres == NULL) {
307
device_printf(sc->dev, "could not allocate interrupt\n");
308
return (ENXIO);
309
}
310
311
err = bus_setup_intr(sc->dev, sc->intres, INTR_TYPE_CLK | INTR_MPSAFE,
312
epit_intr, NULL, sc, &sc->inthandle);
313
if (err != 0) {
314
device_printf(sc->dev, "unable to setup the irq handler\n");
315
return (err);
316
}
317
318
/* To be an eventtimer, we need interrupts enabled. */
319
sc->ctlreg |= EPIT_CR_OCIEN;
320
321
/* Register as an eventtimer. */
322
sc->et.et_name = "EPIT";
323
sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERIODIC;
324
sc->et.et_quality = 1000;
325
sc->et.et_frequency = sc->clkfreq;
326
sc->et.et_min_period = ((uint64_t)ET_MIN_TICKS << 32) / sc->clkfreq;
327
sc->et.et_max_period = ((uint64_t)ET_MAX_TICKS << 32) / sc->clkfreq;
328
sc->et.et_start = epit_et_start;
329
sc->et.et_stop = epit_et_stop;
330
sc->et.et_priv = sc;
331
et_register(&sc->et);
332
333
return (0);
334
}
335
336
static int
337
epit_probe(device_t dev)
338
{
339
struct resource *memres;
340
rman_res_t ioaddr;
341
int num_units, rid, unit;
342
343
if (!ofw_bus_status_okay(dev))
344
return (ENXIO);
345
346
/*
347
* The FDT data for imx5 and imx6 EPIT hardware is missing or broken,
348
* but it may get fixed some day, so first just do a normal check. We
349
* return success if the compatible string matches and we haven't
350
* already instantiated the number of units needed on this platform.
351
*/
352
unit = device_get_unit(dev);
353
num_units = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
354
if (unit < num_units) {
355
device_set_desc(dev, "i.MX EPIT timer");
356
return (BUS_PROBE_DEFAULT);
357
}
358
359
/*
360
* No compat string match, but for imx6 all the data we need is in the
361
* node except the compat string, so do our own compatibility check
362
* using the device name of the node and the register block address.
363
*/
364
if (strstr(ofw_bus_get_name(dev), "epit") == NULL)
365
return (ENXIO);
366
367
rid = 0;
368
memres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_UNMAPPED);
369
if (memres == NULL)
370
return (ENXIO);
371
ioaddr = rman_get_start(memres);
372
bus_free_resource(dev, SYS_RES_MEMORY, memres);
373
374
if (imx_soc_family() == 6) {
375
if (unit > 0)
376
return (ENXIO);
377
if (ioaddr != imx6_epit_ioaddr[unit])
378
return (ENXIO);
379
} else {
380
if (unit > 1)
381
return (ENXIO);
382
switch (imx_soc_type()) {
383
case IMXSOC_51:
384
if (ioaddr != imx51_epit_ioaddr[unit])
385
return (ENXIO);
386
break;
387
case IMXSOC_53:
388
if (ioaddr != imx53_epit_ioaddr[unit])
389
return (ENXIO);
390
break;
391
default:
392
return (ENXIO);
393
}
394
/*
395
* XXX Right now we have no way to handle the fact that the
396
* entire EPIT node is missing, which means no interrupt data.
397
*/
398
return (ENXIO);
399
}
400
401
device_set_desc(dev, "i.MX EPIT timer");
402
return (BUS_PROBE_DEFAULT);
403
}
404
405
static int
406
epit_attach(device_t dev)
407
{
408
struct epit_softc *sc;
409
int err, rid;
410
uint32_t clksrc;
411
412
sc = device_get_softc(dev);
413
sc->dev = dev;
414
415
rid = 0;
416
sc->memres = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, &rid,
417
RF_ACTIVE);
418
if (sc->memres == NULL) {
419
device_printf(sc->dev, "could not allocate registers\n");
420
return (ENXIO);
421
}
422
423
/*
424
* For now, use ipg (66 MHz). Some day we should get this from fdt.
425
*/
426
clksrc = EPIT_CR_CLKSRC_IPG;
427
428
switch (clksrc) {
429
default:
430
device_printf(dev,
431
"Unsupported clock source '%d', using IPG\n", clksrc);
432
/* FALLTHROUGH */
433
case EPIT_CR_CLKSRC_IPG:
434
sc->clkfreq = imx_ccm_ipg_hz();
435
break;
436
case EPIT_CR_CLKSRC_HFCLK:
437
sc->clkfreq = imx_ccm_perclk_hz();
438
break;
439
case EPIT_CR_CLKSRC_LFCLK:
440
sc->clkfreq = 32768;
441
break;
442
}
443
444
/*
445
* Init: stop operations and clear all options, then set up options and
446
* clock source, then do a soft-reset and wait for it to complete.
447
*/
448
WR4(sc, EPIT_CR, 0);
449
450
sc->ctlreg =
451
(clksrc << EPIT_CR_CLKSRC_SHIFT) | /* Use selected clock */
452
EPIT_CR_ENMOD | /* Reload counter on enable */
453
EPIT_CR_RLD | /* Reload counter from LR */
454
EPIT_CR_STOPEN | /* Run in STOP mode */
455
EPIT_CR_WAITEN | /* Run in WAIT mode */
456
EPIT_CR_DBGEN; /* Run in DEBUG mode */
457
458
WR4B(sc, EPIT_CR, sc->ctlreg | EPIT_CR_SWR);
459
while (RD4(sc, EPIT_CR) & EPIT_CR_SWR)
460
continue;
461
462
/*
463
* Unit 0 is the timecounter, 1 (if instantiated) is the eventtimer.
464
*/
465
if (device_get_unit(sc->dev) == 0)
466
err = epit_tc_attach(sc);
467
else
468
err = epit_et_attach(sc);
469
470
return (err);
471
}
472
473
static device_method_t epit_methods[] = {
474
DEVMETHOD(device_probe, epit_probe),
475
DEVMETHOD(device_attach, epit_attach),
476
477
DEVMETHOD_END
478
};
479
480
static driver_t epit_driver = {
481
"imx_epit",
482
epit_methods,
483
sizeof(struct epit_softc),
484
};
485
486
EARLY_DRIVER_MODULE(imx_epit, simplebus, epit_driver, 0, 0, BUS_PASS_TIMER);
487
488