2 * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/module.h>
35 #include <sys/malloc.h>
37 #include <sys/timeet.h>
38 #include <sys/timetc.h>
39 #include <sys/watchdog.h>
40 #include <machine/bus.h>
41 #include <machine/cpu.h>
42 #include <machine/intr.h>
44 #include <dev/fdt/fdt_common.h>
45 #include <dev/ofw/openfirm.h>
46 #include <dev/ofw/ofw_bus.h>
47 #include <dev/ofw/ofw_bus_subr.h>
49 #include <machine/bus.h>
50 #include <machine/fdt.h>
52 #include <arm/ti/ti_prcm.h>
54 #define AM335X_NUM_TIMERS 8
56 #define DMT_TIDR 0x00 /* Identification Register */
57 #define DMT_TIOCP_CFG 0x10 /* OCP Configuration Reg */
58 #define DMT_TIOCP_RESET (1 << 0) /* TIOCP perform soft reset */
59 #define DMT_IQR_EOI 0x20 /* IRQ End-Of-Interrupt Reg */
60 #define DMT_IRQSTATUS_RAW 0x24 /* IRQSTATUS Raw Reg */
61 #define DMT_IRQSTATUS 0x28 /* IRQSTATUS Reg */
62 #define DMT_IRQENABLE_SET 0x2c /* IRQSTATUS Set Reg */
63 #define DMT_IRQENABLE_CLR 0x30 /* IRQSTATUS Clear Reg */
64 #define DMT_IRQWAKEEN 0x34 /* IRQ Wakeup Enable Reg */
65 #define DMT_IRQ_TCAR (1 << 0) /* IRQ: Capture */
66 #define DMT_IRQ_OVF (1 << 1) /* IRQ: Overflow */
67 #define DMT_IRQ_MAT (1 << 2) /* IRQ: Match */
68 #define DMT_IRQ_MASK (DMT_IRQ_TCAR | DMT_IRQ_OVF | DMT_IRQ_MAT)
69 #define DMT_TCLR 0x38 /* Control Register */
70 #define DMT_TCLR_START (1 << 0) /* Start timer */
71 #define DMT_TCLR_AUTOLOAD (1 << 1) /* Auto-reload on overflow */
72 #define DMT_TCLR_PRES_MASK (7 << 2) /* Prescaler mask */
73 #define DMT_TCLR_PRES_ENABLE (1 << 5) /* Prescaler enable */
74 #define DMT_TCLR_COMP_ENABLE (1 << 6) /* Compare enable */
75 #define DMT_TCLR_PWM_HIGH (1 << 7) /* PWM default output high */
76 #define DMT_TCLR_CAPTRAN_MASK (3 << 8) /* Capture transition mask */
77 #define DMT_TCLR_CAPTRAN_NONE (0 << 8) /* Capture: none */
78 #define DMT_TCLR_CAPTRAN_LOHI (1 << 8) /* Capture lo->hi transition */
79 #define DMT_TCLR_CAPTRAN_HILO (2 << 8) /* Capture hi->lo transition */
80 #define DMT_TCLR_CAPTRAN_BOTH (3 << 8) /* Capture both transitions */
81 #define DMT_TCLR_TRGMODE_MASK (3 << 10) /* Trigger output mode mask */
82 #define DMT_TCLR_TRGMODE_NONE (0 << 10) /* Trigger off */
83 #define DMT_TCLR_TRGMODE_OVFL (1 << 10) /* Trigger on overflow */
84 #define DMT_TCLR_TRGMODE_BOTH (2 << 10) /* Trigger on match + ovflow */
85 #define DMT_TCLR_PWM_PTOGGLE (1 << 12) /* PWM toggles */
86 #define DMT_TCLR_CAP_MODE_2ND (1 << 13) /* Capture second event mode */
87 #define DMT_TCLR_GPO_CFG (1 << 14) /* (no descr in datasheet) */
88 #define DMT_TCRR 0x3C /* Counter Register */
89 #define DMT_TLDR 0x40 /* Load Reg */
90 #define DMT_TTGR 0x44 /* Trigger Reg */
91 #define DMT_TWPS 0x48 /* Write Posted Status Reg */
92 #define DMT_TMAR 0x4C /* Match Reg */
93 #define DMT_TCAR1 0x50 /* Capture Reg */
94 #define DMT_TSICR 0x54 /* Synchr. Interface Ctrl Reg */
95 #define DMT_TSICR_RESET 0x02 /* TSICR perform soft reset */
96 #define DMT_TCAR2 0x48 /* Capture Reg */
98 struct am335x_dmtimer_softc {
99 struct resource * tmr_mem_res[AM335X_NUM_TIMERS];
100 struct resource * tmr_irq_res[AM335X_NUM_TIMERS];
101 uint32_t sysclk_freq;
102 uint32_t tc_num; /* Which timer number is tc. */
103 uint32_t et_num; /* Which timer number is et. */
104 struct resource * tc_memres; /* Resources for tc timer. */
105 struct resource * et_memres; /* Resources for et timer. */
106 struct timecounter tc;
107 struct eventtimer et;
110 static struct am335x_dmtimer_softc *am335x_dmtimer_sc;
112 static struct resource_spec am335x_dmtimer_mem_spec[] = {
113 { SYS_RES_MEMORY, 0, RF_ACTIVE },
114 { SYS_RES_MEMORY, 1, RF_ACTIVE },
115 { SYS_RES_MEMORY, 2, RF_ACTIVE },
116 { SYS_RES_MEMORY, 3, RF_ACTIVE },
117 { SYS_RES_MEMORY, 4, RF_ACTIVE },
118 { SYS_RES_MEMORY, 5, RF_ACTIVE },
119 { SYS_RES_MEMORY, 6, RF_ACTIVE },
120 { SYS_RES_MEMORY, 7, RF_ACTIVE },
123 static struct resource_spec am335x_dmtimer_irq_spec[] = {
124 { SYS_RES_IRQ, 0, RF_ACTIVE },
125 { SYS_RES_IRQ, 1, RF_ACTIVE },
126 { SYS_RES_IRQ, 2, RF_ACTIVE },
127 { SYS_RES_IRQ, 3, RF_ACTIVE },
128 { SYS_RES_IRQ, 4, RF_ACTIVE },
129 { SYS_RES_IRQ, 5, RF_ACTIVE },
130 { SYS_RES_IRQ, 6, RF_ACTIVE },
131 { SYS_RES_IRQ, 7, RF_ACTIVE },
135 static inline uint32_t
136 am335x_dmtimer_tc_read_4(struct am335x_dmtimer_softc *sc, uint32_t reg)
139 return (bus_read_4(sc->tc_memres, reg));
143 am335x_dmtimer_tc_write_4(struct am335x_dmtimer_softc *sc, uint32_t reg,
147 bus_write_4(sc->tc_memres, reg, val);
150 static inline uint32_t
151 am335x_dmtimer_et_read_4(struct am335x_dmtimer_softc *sc, uint32_t reg)
154 return (bus_read_4(sc->et_memres, reg));
158 am335x_dmtimer_et_write_4(struct am335x_dmtimer_softc *sc, uint32_t reg,
162 bus_write_4(sc->et_memres, reg, val);
166 am335x_dmtimer_tc_get_timecount(struct timecounter *tc)
168 struct am335x_dmtimer_softc *sc;
172 return (am335x_dmtimer_tc_read_4(sc, DMT_TCRR));
176 am335x_dmtimer_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
178 struct am335x_dmtimer_softc *sc;
179 uint32_t count, load, tclr;
185 load = ((uint32_t)et->et_frequency * period) >> 32;
186 tclr |= DMT_TCLR_AUTOLOAD;
187 panic("periodic timer not implemented\n");
193 count = ((uint32_t)et->et_frequency * first) >> 32;
198 am335x_dmtimer_et_write_4(sc, DMT_TSICR, DMT_TSICR_RESET);
200 /* Wait for reset to complete */
201 while (am335x_dmtimer_et_read_4(sc, DMT_TIOCP_CFG) & DMT_TIOCP_RESET)
205 am335x_dmtimer_et_write_4(sc, DMT_TLDR, 0xFFFFFFFE - load);
207 /* set counter value */
208 am335x_dmtimer_et_write_4(sc, DMT_TCRR, 0xFFFFFFFE - count);
210 /* enable overflow interrupt */
211 am335x_dmtimer_et_write_4(sc, DMT_IRQENABLE_SET, DMT_IRQ_OVF);
213 /* start timer(ST) */
214 tclr |= DMT_TCLR_START;
215 am335x_dmtimer_et_write_4(sc, DMT_TCLR, tclr);
221 am335x_dmtimer_stop(struct eventtimer *et)
223 struct am335x_dmtimer_softc *sc;
227 /* Disable all interrupts */
228 am335x_dmtimer_et_write_4(sc, DMT_IRQENABLE_CLR, DMT_IRQ_MASK);
231 am335x_dmtimer_et_write_4(sc, DMT_TCLR, 0);
237 am335x_dmtimer_intr(void *arg)
239 struct am335x_dmtimer_softc *sc;
243 am335x_dmtimer_et_write_4(sc, DMT_IRQSTATUS, DMT_IRQ_OVF);
244 if (sc->et.et_active)
245 sc->et.et_event_cb(&sc->et, sc->et.et_arg);
247 return (FILTER_HANDLED);
251 am335x_dmtimer_probe(device_t dev)
254 if (ofw_bus_is_compatible(dev, "ti,am335x-dmtimer")) {
255 device_set_desc(dev, "AM335x DMTimer");
256 return(BUS_PROBE_DEFAULT);
263 am335x_dmtimer_attach(device_t dev)
265 struct am335x_dmtimer_softc *sc;
270 * Note that if this routine returns an error status rather than running
271 * to completion it makes no attempt to clean up allocated resources;
272 * the system is essentially dead anyway without functional timers.
275 sc = device_get_softc(dev);
277 if (am335x_dmtimer_sc != NULL)
280 /* Get the base clock frequency. */
281 err = ti_prcm_clk_get_source_freq(SYS_CLK, &sc->sysclk_freq);
283 device_printf(dev, "Error: could not get sysclk frequency\n");
287 /* Request the memory resources. */
288 err = bus_alloc_resources(dev, am335x_dmtimer_mem_spec,
291 device_printf(dev, "Error: could not allocate mem resources\n");
295 /* Request the IRQ resources. */
296 err = bus_alloc_resources(dev, am335x_dmtimer_irq_spec,
299 device_printf(dev, "Error: could not allocate irq resources\n");
303 /* Configure DMTimer3 as eventtimer and DMTimer4 as timecounter. */
306 sc->et_memres = sc->tmr_mem_res[sc->et_num];
307 sc->tc_memres = sc->tmr_mem_res[sc->tc_num];
309 err = ti_prcm_clk_set_source(DMTIMER0_CLK + sc->et_num, SYSCLK_CLK);
310 err |= ti_prcm_clk_enable(DMTIMER0_CLK + sc->et_num);
311 err |= ti_prcm_clk_set_source(DMTIMER0_CLK + sc->tc_num, SYSCLK_CLK);
312 err |= ti_prcm_clk_enable(DMTIMER0_CLK + sc->tc_num);
314 device_printf(dev, "Error: could not setup timer clock\n");
318 /* Set up timecounter; register tc. */
319 am335x_dmtimer_tc_write_4(sc, DMT_TSICR, DMT_TSICR_RESET);
320 while (am335x_dmtimer_tc_read_4(sc, DMT_TIOCP_CFG) & DMT_TIOCP_RESET)
323 am335x_dmtimer_tc_write_4(sc, DMT_TLDR, 0);
324 am335x_dmtimer_tc_write_4(sc, DMT_TCRR, 0);
325 am335x_dmtimer_tc_write_4(sc, DMT_TCLR,
326 DMT_TCLR_START | DMT_TCLR_AUTOLOAD);
328 sc->tc.tc_name = "AM335x Timecounter";
329 sc->tc.tc_get_timecount = am335x_dmtimer_tc_get_timecount;
330 sc->tc.tc_poll_pps = NULL;
331 sc->tc.tc_counter_mask = ~0u;
332 sc->tc.tc_frequency = sc->sysclk_freq;
333 sc->tc.tc_quality = 1000;
337 /* Setup eventtimer; register et. */
338 if (bus_setup_intr(dev, sc->tmr_irq_res[sc->et_num], INTR_TYPE_CLK,
339 am335x_dmtimer_intr, NULL, sc, &ihl) != 0) {
340 bus_release_resources(dev, am335x_dmtimer_irq_spec,
342 device_printf(dev, "Unable to setup the clock irq handler.\n");
346 sc->et.et_name = "AM335x Eventtimer";
347 sc->et.et_flags = ET_FLAGS_ONESHOT;
348 sc->et.et_quality = 1000;
349 sc->et.et_frequency = sc->sysclk_freq;
350 sc->et.et_min_period =
351 ((0x00000005LLU << 32) / sc->et.et_frequency);
352 sc->et.et_max_period =
353 (0xfffffffeLLU << 32) / sc->et.et_frequency;
354 sc->et.et_start = am335x_dmtimer_start;
355 sc->et.et_stop = am335x_dmtimer_stop;
357 et_register(&sc->et);
359 /* Store a pointer to the softc for use in DELAY(). */
360 am335x_dmtimer_sc = sc;
365 static device_method_t am335x_dmtimer_methods[] = {
366 DEVMETHOD(device_probe, am335x_dmtimer_probe),
367 DEVMETHOD(device_attach, am335x_dmtimer_attach),
371 static driver_t am335x_dmtimer_driver = {
373 am335x_dmtimer_methods,
374 sizeof(struct am335x_dmtimer_softc),
377 static devclass_t am335x_dmtimer_devclass;
379 DRIVER_MODULE(am335x_dmtimer, simplebus, am335x_dmtimer_driver, am335x_dmtimer_devclass, 0, 0);
380 MODULE_DEPEND(am335x_dmtimer, am335x_prcm, 1, 1, 1);
385 cpu_initclocks_bsp();
391 struct am335x_dmtimer_softc *sc;
393 uint32_t first, last;
395 sc = am335x_dmtimer_sc;
398 for (; usec > 0; usec--)
399 for (counts = 200; counts > 0; counts--)
400 /* Prevent gcc from optimizing out the loop */
405 /* Get the number of times to count */
406 counts = (usec + 1) * (sc->sysclk_freq / 1000000);
408 first = am335x_dmtimer_tc_read_4(sc, DMT_TCRR);
411 last = am335x_dmtimer_tc_read_4(sc, DMT_TCRR);
413 counts -= (int32_t)(last - first);
415 counts -= (int32_t)((0xFFFFFFFF - first) + last);