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