]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/ti/am335x/am335x_dmtimer.c
Update Subversion to 1.14.0 LTS. See contrib/subversion/CHANGES for a
[FreeBSD/FreeBSD.git] / sys / arm / ti / am335x / am335x_dmtimer.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35 #include <sys/kernel.h>
36 #include <sys/module.h>
37 #include <sys/malloc.h>
38 #include <sys/rman.h>
39 #include <sys/timeet.h>
40 #include <sys/timetc.h>
41 #include <machine/bus.h>
42
43 #include <machine/machdep.h> /* For arm_set_delay */
44
45 #include <dev/ofw/openfirm.h>
46 #include <dev/ofw/ofw_bus.h>
47 #include <dev/ofw/ofw_bus_subr.h>
48
49 #include <arm/ti/ti_prcm.h>
50 #include <arm/ti/ti_hwmods.h>
51
52 #include "am335x_dmtreg.h"
53
54 struct am335x_dmtimer_softc {
55         device_t                dev;
56         int                     tmr_mem_rid;
57         struct resource *       tmr_mem_res;
58         int                     tmr_irq_rid;
59         struct resource *       tmr_irq_res;
60         void                    *tmr_irq_handler;
61         uint32_t                sysclk_freq;
62         uint32_t                tclr;           /* Cached TCLR register. */
63         union {
64                 struct timecounter tc;
65                 struct eventtimer et;
66         } func;
67         int                     tmr_num;        /* Hardware unit number. */
68         char                    tmr_name[12];   /* "DMTimerN", N = tmr_num */
69 };
70
71 static struct am335x_dmtimer_softc *am335x_dmtimer_et_sc = NULL;
72 static struct am335x_dmtimer_softc *am335x_dmtimer_tc_sc = NULL;
73
74 static void am335x_dmtimer_delay(int, void *);
75
76 /*
77  * We use dmtimer2 for eventtimer and dmtimer3 for timecounter.
78  */
79 #define ET_TMR_NUM      2
80 #define TC_TMR_NUM      3
81
82 /* List of compatible strings for FDT tree */
83 static struct ofw_compat_data compat_data[] = {
84         {"ti,am335x-timer",     1},
85         {"ti,am335x-timer-1ms", 1},
86         {NULL,                  0},
87 };
88
89 #define DMTIMER_READ4(sc, reg)          bus_read_4((sc)->tmr_mem_res, (reg))
90 #define DMTIMER_WRITE4(sc, reg, val)    bus_write_4((sc)->tmr_mem_res, (reg), (val))
91
92 static int
93 am335x_dmtimer_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
94 {
95         struct am335x_dmtimer_softc *sc;
96         uint32_t initial_count, reload_count;
97
98         sc = et->et_priv;
99
100         /*
101          * Stop the timer before changing it.  This routine will often be called
102          * while the timer is still running, to either lengthen or shorten the
103          * current event time.  We need to ensure the timer doesn't expire while
104          * we're working with it.
105          *
106          * Also clear any pending interrupt status, because it's at least
107          * theoretically possible that we're running in a primary interrupt
108          * context now, and a timer interrupt could be pending even before we
109          * stopped the timer.  The more likely case is that we're being called
110          * from the et_event_cb() routine dispatched from our own handler, but
111          * it's not clear to me that that's the only case possible.
112          */
113         sc->tclr &= ~(DMT_TCLR_START | DMT_TCLR_AUTOLOAD);
114         DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr);
115         DMTIMER_WRITE4(sc, DMT_IRQSTATUS, DMT_IRQ_OVF);
116
117         if (period != 0) {
118                 reload_count = ((uint32_t)et->et_frequency * period) >> 32;
119                 sc->tclr |= DMT_TCLR_AUTOLOAD;
120         } else {
121                 reload_count = 0;
122         }
123
124         if (first != 0)
125                 initial_count = ((uint32_t)et->et_frequency * first) >> 32;
126         else
127                 initial_count = reload_count;
128
129         /*
130          * Set auto-reload and current-count values.  This timer hardware counts
131          * up from the initial/reload value and interrupts on the zero rollover.
132          */
133         DMTIMER_WRITE4(sc, DMT_TLDR, 0xFFFFFFFF - reload_count);
134         DMTIMER_WRITE4(sc, DMT_TCRR, 0xFFFFFFFF - initial_count);
135
136         /* Enable overflow interrupt, and start the timer. */
137         DMTIMER_WRITE4(sc, DMT_IRQENABLE_SET, DMT_IRQ_OVF);
138         sc->tclr |= DMT_TCLR_START;
139         DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr);
140
141         return (0);
142 }
143
144 static int
145 am335x_dmtimer_et_stop(struct eventtimer *et)
146 {
147         struct am335x_dmtimer_softc *sc;
148
149         sc = et->et_priv;
150
151         /* Stop timer, disable and clear interrupt. */
152         sc->tclr &= ~(DMT_TCLR_START | DMT_TCLR_AUTOLOAD);
153         DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr);
154         DMTIMER_WRITE4(sc, DMT_IRQENABLE_CLR, DMT_IRQ_OVF);
155         DMTIMER_WRITE4(sc, DMT_IRQSTATUS, DMT_IRQ_OVF);
156         return (0);
157 }
158
159 static int
160 am335x_dmtimer_et_intr(void *arg)
161 {
162         struct am335x_dmtimer_softc *sc;
163
164         sc = arg;
165
166         /* Ack the interrupt, and invoke the callback if it's still enabled. */
167         DMTIMER_WRITE4(sc, DMT_IRQSTATUS, DMT_IRQ_OVF);
168         if (sc->func.et.et_active)
169                 sc->func.et.et_event_cb(&sc->func.et, sc->func.et.et_arg);
170
171         return (FILTER_HANDLED);
172 }
173
174 static int
175 am335x_dmtimer_et_init(struct am335x_dmtimer_softc *sc)
176 {
177         KASSERT(am335x_dmtimer_et_sc == NULL, ("already have an eventtimer"));
178
179         /*
180          * Setup eventtimer interrupt handling.  Panic if anything goes wrong,
181          * because the system just isn't going to run without an eventtimer.
182          */
183         sc->tmr_irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
184             &sc->tmr_irq_rid, RF_ACTIVE);
185         if (sc->tmr_irq_res == NULL)
186                 panic("am335x_dmtimer: could not allocate irq resources");
187         if (bus_setup_intr(sc->dev, sc->tmr_irq_res, INTR_TYPE_CLK,
188             am335x_dmtimer_et_intr, NULL, sc, &sc->tmr_irq_handler) != 0)
189                 panic("am335x_dmtimer: count not setup irq handler");
190
191         sc->func.et.et_name = sc->tmr_name;
192         sc->func.et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT;
193         sc->func.et.et_quality = 500;
194         sc->func.et.et_frequency = sc->sysclk_freq;
195         sc->func.et.et_min_period =
196             ((0x00000005LLU << 32) / sc->func.et.et_frequency);
197         sc->func.et.et_max_period =
198             (0xfffffffeLLU << 32) / sc->func.et.et_frequency;
199         sc->func.et.et_start = am335x_dmtimer_et_start;
200         sc->func.et.et_stop = am335x_dmtimer_et_stop;
201         sc->func.et.et_priv = sc;
202
203         am335x_dmtimer_et_sc = sc;
204         et_register(&sc->func.et);
205
206         return (0);
207 }
208
209 static unsigned
210 am335x_dmtimer_tc_get_timecount(struct timecounter *tc)
211 {
212         struct am335x_dmtimer_softc *sc;
213
214         sc = tc->tc_priv;
215
216         return (DMTIMER_READ4(sc, DMT_TCRR));
217 }
218
219 static int
220 am335x_dmtimer_tc_init(struct am335x_dmtimer_softc *sc)
221 {
222         KASSERT(am335x_dmtimer_tc_sc == NULL, ("already have a timecounter"));
223
224         /* Set up timecounter, start it, register it. */
225         DMTIMER_WRITE4(sc, DMT_TSICR, DMT_TSICR_RESET);
226         while (DMTIMER_READ4(sc, DMT_TIOCP_CFG) & DMT_TIOCP_RESET)
227                 continue;
228
229         sc->tclr |= DMT_TCLR_START | DMT_TCLR_AUTOLOAD;
230         DMTIMER_WRITE4(sc, DMT_TLDR, 0);
231         DMTIMER_WRITE4(sc, DMT_TCRR, 0);
232         DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr);
233
234         sc->func.tc.tc_name           = sc->tmr_name;
235         sc->func.tc.tc_get_timecount  = am335x_dmtimer_tc_get_timecount;
236         sc->func.tc.tc_counter_mask   = ~0u;
237         sc->func.tc.tc_frequency      = sc->sysclk_freq;
238         sc->func.tc.tc_quality        = 500;
239         sc->func.tc.tc_priv           = sc;
240
241         am335x_dmtimer_tc_sc = sc;
242         tc_init(&sc->func.tc);
243
244         arm_set_delay(am335x_dmtimer_delay, sc);
245
246         return (0);
247 }
248
249 static int
250 am335x_dmtimer_probe(device_t dev)
251 {
252         char strbuf[32];
253         int tmr_num;
254
255         if (!ofw_bus_status_okay(dev))
256                 return (ENXIO);
257
258         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
259                 return (ENXIO);
260
261         /*
262          * Get the hardware unit number (the N from ti,hwmods="timerN").
263          * If this isn't the hardware unit we're going to use for either the
264          * eventtimer or the timecounter, no point in instantiating the device.
265          */
266         tmr_num = ti_hwmods_get_unit(dev, "timer");
267         if (tmr_num != ET_TMR_NUM && tmr_num != TC_TMR_NUM)
268                 return (ENXIO);
269
270         snprintf(strbuf, sizeof(strbuf), "AM335x DMTimer%d", tmr_num);
271         device_set_desc_copy(dev, strbuf);
272
273         return(BUS_PROBE_DEFAULT);
274 }
275
276 static int
277 am335x_dmtimer_attach(device_t dev)
278 {
279         struct am335x_dmtimer_softc *sc;
280         clk_ident_t timer_id;
281         int err;
282
283         sc = device_get_softc(dev);
284         sc->dev = dev;
285
286         /* Get the base clock frequency. */
287         if ((err = ti_prcm_clk_get_source_freq(SYS_CLK, &sc->sysclk_freq)) != 0)
288                 return (err);
289
290         /* Enable clocks and power on the device. */
291         if ((timer_id = ti_hwmods_get_clock(dev)) == INVALID_CLK_IDENT)
292                 return (ENXIO);
293         if ((err = ti_prcm_clk_set_source(timer_id, SYSCLK_CLK)) != 0)
294                 return (err);
295         if ((err = ti_prcm_clk_enable(timer_id)) != 0)
296                 return (err);
297
298         /* Request the memory resources. */
299         sc->tmr_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
300             &sc->tmr_mem_rid, RF_ACTIVE);
301         if (sc->tmr_mem_res == NULL) {
302                 return (ENXIO);
303         }
304
305         sc->tmr_num = ti_hwmods_get_unit(dev, "timer");
306         snprintf(sc->tmr_name, sizeof(sc->tmr_name), "DMTimer%d", sc->tmr_num);
307
308         /*
309          * Go set up either a timecounter or eventtimer.  We wouldn't have
310          * attached if we weren't one or the other.
311          */
312         if (sc->tmr_num == ET_TMR_NUM)
313                 am335x_dmtimer_et_init(sc);
314         else if (sc->tmr_num == TC_TMR_NUM)
315                 am335x_dmtimer_tc_init(sc);
316         else
317                 panic("am335x_dmtimer: bad timer number %d", sc->tmr_num);
318
319         return (0);
320 }
321
322 static device_method_t am335x_dmtimer_methods[] = {
323         DEVMETHOD(device_probe,         am335x_dmtimer_probe),
324         DEVMETHOD(device_attach,        am335x_dmtimer_attach),
325         { 0, 0 }
326 };
327
328 static driver_t am335x_dmtimer_driver = {
329         "am335x_dmtimer",
330         am335x_dmtimer_methods,
331         sizeof(struct am335x_dmtimer_softc),
332 };
333
334 static devclass_t am335x_dmtimer_devclass;
335
336 DRIVER_MODULE(am335x_dmtimer, simplebus, am335x_dmtimer_driver, am335x_dmtimer_devclass, 0, 0);
337 MODULE_DEPEND(am335x_dmtimer, am335x_prcm, 1, 1, 1);
338
339 static void
340 am335x_dmtimer_delay(int usec, void *arg)
341 {
342         struct am335x_dmtimer_softc *sc = arg;
343         int32_t counts;
344         uint32_t first, last;
345
346         /* Get the number of times to count */
347         counts = (usec + 1) * (sc->sysclk_freq / 1000000);
348
349         first = DMTIMER_READ4(sc, DMT_TCRR);
350
351         while (counts > 0) {
352                 last = DMTIMER_READ4(sc, DMT_TCRR);
353                 if (last > first) {
354                         counts -= (int32_t)(last - first);
355                 } else {
356                         counts -= (int32_t)((0xFFFFFFFF - first) + last);
357                 }
358                 first = last;
359         }
360 }