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 struct am335x_dmtimer {
104 bus_space_handle_t bsh;
105 struct eventtimer et;
106 } t[AM335X_NUM_TIMERS];
109 static struct resource_spec am335x_dmtimer_mem_spec[] = {
110 { SYS_RES_MEMORY, 0, RF_ACTIVE },
111 { SYS_RES_MEMORY, 1, RF_ACTIVE },
112 { SYS_RES_MEMORY, 2, RF_ACTIVE },
113 { SYS_RES_MEMORY, 3, RF_ACTIVE },
114 { SYS_RES_MEMORY, 4, RF_ACTIVE },
115 { SYS_RES_MEMORY, 5, RF_ACTIVE },
116 { SYS_RES_MEMORY, 6, RF_ACTIVE },
117 { SYS_RES_MEMORY, 7, RF_ACTIVE },
120 static struct resource_spec am335x_dmtimer_irq_spec[] = {
121 { SYS_RES_IRQ, 0, RF_ACTIVE },
122 { SYS_RES_IRQ, 1, RF_ACTIVE },
123 { SYS_RES_IRQ, 2, RF_ACTIVE },
124 { SYS_RES_IRQ, 3, RF_ACTIVE },
125 { SYS_RES_IRQ, 4, RF_ACTIVE },
126 { SYS_RES_IRQ, 5, RF_ACTIVE },
127 { SYS_RES_IRQ, 6, RF_ACTIVE },
128 { SYS_RES_IRQ, 7, RF_ACTIVE },
132 static struct am335x_dmtimer *am335x_dmtimer_tc_tmr = NULL;
134 /* Read/Write macros for Timer used as timecounter */
135 #define am335x_dmtimer_tc_read_4(reg) \
136 bus_space_read_4(am335x_dmtimer_tc_tmr->bst, \
137 am335x_dmtimer_tc_tmr->bsh, reg)
139 #define am335x_dmtimer_tc_write_4(reg, val) \
140 bus_space_write_4(am335x_dmtimer_tc_tmr->bst, \
141 am335x_dmtimer_tc_tmr->bsh, reg, val)
143 /* Read/Write macros for Timer used as eventtimer */
144 #define am335x_dmtimer_et_read_4(reg) \
145 bus_space_read_4(tmr->bst, tmr->bsh, reg)
147 #define am335x_dmtimer_et_write_4(reg, val) \
148 bus_space_write_4(tmr->bst, tmr->bsh, reg, val)
150 static unsigned am335x_dmtimer_tc_get_timecount(struct timecounter *);
152 static struct timecounter am335x_dmtimer_tc = {
153 .tc_name = "AM335x Timecounter",
154 .tc_get_timecount = am335x_dmtimer_tc_get_timecount,
156 .tc_counter_mask = ~0u,
162 am335x_dmtimer_tc_get_timecount(struct timecounter *tc)
164 return am335x_dmtimer_tc_read_4(DMT_TCRR);
168 am335x_dmtimer_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
170 struct am335x_dmtimer *tmr = (struct am335x_dmtimer *)et->et_priv;
171 uint32_t load, count;
175 load = ((uint32_t)et->et_frequency * period) >> 32;
176 tclr |= 2; /* autoreload bit */
177 panic("periodic timer not implemented\n");
183 count = ((uint32_t)et->et_frequency * first) >> 32;
188 am335x_dmtimer_et_write_4(DMT_TSICR, 2);
190 /* Wait for reset to complete */
191 while (am335x_dmtimer_et_read_4(DMT_TIOCP_CFG) & 1);
194 am335x_dmtimer_et_write_4(DMT_TLDR, 0xFFFFFFFE - load);
196 /* set counter value */
197 am335x_dmtimer_et_write_4(DMT_TCRR, 0xFFFFFFFE - count);
199 /* enable overflow interrupt */
200 am335x_dmtimer_et_write_4(DMT_IRQENABLE_SET, 2);
202 /* start timer(ST) */
204 am335x_dmtimer_et_write_4(DMT_TCLR, tclr);
210 am335x_dmtimer_stop(struct eventtimer *et)
212 struct am335x_dmtimer *tmr = (struct am335x_dmtimer *)et->et_priv;
214 /* Disable all interrupts */
215 am335x_dmtimer_et_write_4(DMT_IRQENABLE_CLR, 7);
218 am335x_dmtimer_et_write_4(DMT_TCLR, 0);
224 am335x_dmtimer_intr(void *arg)
226 struct am335x_dmtimer *tmr = (struct am335x_dmtimer *)arg;
229 am335x_dmtimer_et_write_4(DMT_IRQSTATUS, 7);
230 if (tmr->et.et_active)
231 tmr->et.et_event_cb(&tmr->et, tmr->et.et_arg);
233 return (FILTER_HANDLED);
237 am335x_dmtimer_probe(device_t dev)
239 struct am335x_dmtimer_softc *sc;
240 sc = (struct am335x_dmtimer_softc *)device_get_softc(dev);
242 if (ofw_bus_is_compatible(dev, "ti,am335x-dmtimer")) {
243 device_set_desc(dev, "AM335x DMTimer");
244 return(BUS_PROBE_DEFAULT);
251 am335x_dmtimer_attach(device_t dev)
253 struct am335x_dmtimer_softc *sc = device_get_softc(dev);
258 if (am335x_dmtimer_tc_tmr != NULL)
261 /* Get the base clock frequency */
262 err = ti_prcm_clk_get_source_freq(SYS_CLK, &sc->sysclk_freq);
264 device_printf(dev, "Error: could not get sysclk frequency\n");
268 /* Request the memory resources */
269 err = bus_alloc_resources(dev, am335x_dmtimer_mem_spec,
272 device_printf(dev, "Error: could not allocate mem resources\n");
276 /* Request the IRQ resources */
277 err = bus_alloc_resources(dev, am335x_dmtimer_irq_spec,
280 device_printf(dev, "Error: could not allocate irq resources\n");
284 for(i=0;i<AM335X_NUM_TIMERS;i++) {
285 sc->t[i].bst = rman_get_bustag(sc->tmr_mem_res[i]);
286 sc->t[i].bsh = rman_get_bushandle(sc->tmr_mem_res[i]);
289 /* Configure DMTimer2 and DMTimer3 source and enable them */
290 err = ti_prcm_clk_set_source(DMTIMER2_CLK, SYSCLK_CLK);
291 err |= ti_prcm_clk_enable(DMTIMER2_CLK);
292 err |= ti_prcm_clk_set_source(DMTIMER3_CLK, SYSCLK_CLK);
293 err |= ti_prcm_clk_enable(DMTIMER3_CLK);
295 device_printf(dev, "Error: could not setup timer clock\n");
299 /* Take DMTimer2 for TC */
300 am335x_dmtimer_tc_tmr = &sc->t[2];
303 am335x_dmtimer_tc_write_4(DMT_TSICR, 2);
305 /* Wait for reset to complete */
306 while (am335x_dmtimer_tc_read_4(DMT_TIOCP_CFG) & 1);
309 am335x_dmtimer_tc_write_4(DMT_TLDR, 0);
311 /* set counter value */
312 am335x_dmtimer_tc_write_4(DMT_TCRR, 0);
314 /* Set Timer autoreload(AR) and start timer(ST) */
315 am335x_dmtimer_tc_write_4(DMT_TCLR, 3);
317 am335x_dmtimer_tc.tc_frequency = sc->sysclk_freq;
318 tc_init(&am335x_dmtimer_tc);
320 /* Register DMTimer3 as ET */
322 /* Setup and enable the timer */
323 if (bus_setup_intr(dev, sc->tmr_irq_res[3], INTR_TYPE_CLK,
324 am335x_dmtimer_intr, NULL, &sc->t[3], &ihl) != 0) {
325 bus_release_resources(dev, am335x_dmtimer_irq_spec,
327 device_printf(dev, "Unable to setup the clock irq handler.\n");
331 sc->t[3].et.et_name = "AM335x Eventtimer0";
332 sc->t[3].et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT;
333 sc->t[3].et.et_quality = 1000;
334 sc->t[3].et.et_frequency = sc->sysclk_freq;
335 sc->t[3].et.et_min_period =
336 (0x00000002LLU << 32) / sc->t[3].et.et_frequency;
337 sc->t[3].et.et_max_period =
338 (0xfffffffeLLU << 32) / sc->t[3].et.et_frequency;
339 sc->t[3].et.et_start = am335x_dmtimer_start;
340 sc->t[3].et.et_stop = am335x_dmtimer_stop;
341 sc->t[3].et.et_priv = &sc->t[3];
342 et_register(&sc->t[3].et);
347 static device_method_t am335x_dmtimer_methods[] = {
348 DEVMETHOD(device_probe, am335x_dmtimer_probe),
349 DEVMETHOD(device_attach, am335x_dmtimer_attach),
353 static driver_t am335x_dmtimer_driver = {
355 am335x_dmtimer_methods,
356 sizeof(struct am335x_dmtimer_softc),
359 static devclass_t am335x_dmtimer_devclass;
361 DRIVER_MODULE(am335x_dmtimer, simplebus, am335x_dmtimer_driver, am335x_dmtimer_devclass, 0, 0);
362 MODULE_DEPEND(am335x_dmtimer, am335x_prcm, 1, 1, 1);
367 cpu_initclocks_bsp();
374 uint32_t first, last;
376 if (am335x_dmtimer_tc_tmr == NULL) {
377 for (; usec > 0; usec--)
378 for (counts = 200; counts > 0; counts--)
379 /* Prevent gcc from optimizing out the loop */
384 /* Get the number of times to count */
385 counts = usec * (am335x_dmtimer_tc.tc_frequency / 1000000) + 1;
387 first = am335x_dmtimer_tc_read_4(DMT_TCRR);
390 last = am335x_dmtimer_tc_read_4(DMT_TCRR);
392 counts -= (int32_t)(last - first);
394 counts -= (int32_t)((0xFFFFFFFF - first) + last);