xref: /freebsd/sys/arm/ti/am335x/am335x_dmtimer.c (revision 332f00cdbafa944472a5c2d9d1701466ab762f90)
1e53470feSOleksandr Tymoshenko /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3af3dc4a7SPedro F. Giffuni  *
4e53470feSOleksandr Tymoshenko  * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org>
5e53470feSOleksandr Tymoshenko  * All rights reserved.
6e53470feSOleksandr Tymoshenko  *
7e53470feSOleksandr Tymoshenko  * Redistribution and use in source and binary forms, with or without
8e53470feSOleksandr Tymoshenko  * modification, are permitted provided that the following conditions
9e53470feSOleksandr Tymoshenko  * are met:
10e53470feSOleksandr Tymoshenko  * 1. Redistributions of source code must retain the above copyright
11e53470feSOleksandr Tymoshenko  *    notice, this list of conditions and the following disclaimer.
12e53470feSOleksandr Tymoshenko  * 2. Redistributions in binary form must reproduce the above copyright
13e53470feSOleksandr Tymoshenko  *    notice, this list of conditions and the following disclaimer in the
14e53470feSOleksandr Tymoshenko  *    documentation and/or other materials provided with the distribution.
15e53470feSOleksandr Tymoshenko  *
16e53470feSOleksandr Tymoshenko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17e53470feSOleksandr Tymoshenko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18e53470feSOleksandr Tymoshenko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19e53470feSOleksandr Tymoshenko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20e53470feSOleksandr Tymoshenko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21e53470feSOleksandr Tymoshenko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22e53470feSOleksandr Tymoshenko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23e53470feSOleksandr Tymoshenko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24e53470feSOleksandr Tymoshenko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25e53470feSOleksandr Tymoshenko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26e53470feSOleksandr Tymoshenko  * SUCH DAMAGE.
27e53470feSOleksandr Tymoshenko  */
28e53470feSOleksandr Tymoshenko 
29e53470feSOleksandr Tymoshenko #include <sys/param.h>
30e53470feSOleksandr Tymoshenko #include <sys/systm.h>
31e53470feSOleksandr Tymoshenko #include <sys/bus.h>
32e53470feSOleksandr Tymoshenko #include <sys/kernel.h>
33e53470feSOleksandr Tymoshenko #include <sys/module.h>
34e53470feSOleksandr Tymoshenko #include <sys/malloc.h>
35e53470feSOleksandr Tymoshenko #include <sys/rman.h>
36e53470feSOleksandr Tymoshenko #include <sys/timeet.h>
37e53470feSOleksandr Tymoshenko #include <sys/timetc.h>
38e53470feSOleksandr Tymoshenko #include <machine/bus.h>
39e53470feSOleksandr Tymoshenko 
408fcbb323SAndrew Turner #include <machine/machdep.h> /* For arm_set_delay */
418fcbb323SAndrew Turner 
42be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
430050ea24SMichal Meloun 
44e53470feSOleksandr Tymoshenko #include <dev/ofw/openfirm.h>
45e53470feSOleksandr Tymoshenko #include <dev/ofw/ofw_bus.h>
46e53470feSOleksandr Tymoshenko #include <dev/ofw/ofw_bus_subr.h>
47e53470feSOleksandr Tymoshenko 
480050ea24SMichal Meloun #include <arm/ti/ti_sysc.h>
49e53470feSOleksandr Tymoshenko 
50479e7c44SIan Lepore #include "am335x_dmtreg.h"
515b03aba6SOleksandr Tymoshenko 
52e53470feSOleksandr Tymoshenko struct am335x_dmtimer_softc {
535b03aba6SOleksandr Tymoshenko 	device_t		dev;
545b03aba6SOleksandr Tymoshenko 	int			tmr_mem_rid;
555b03aba6SOleksandr Tymoshenko 	struct resource *	tmr_mem_res;
565b03aba6SOleksandr Tymoshenko 	int			tmr_irq_rid;
575b03aba6SOleksandr Tymoshenko 	struct resource *	tmr_irq_res;
585b03aba6SOleksandr Tymoshenko 	void			*tmr_irq_handler;
590050ea24SMichal Meloun 	clk_t			clk_fck;
600050ea24SMichal Meloun 	uint64_t		sysclk_freq;
615b03aba6SOleksandr Tymoshenko 	uint32_t		tclr;		/* Cached TCLR register. */
625b03aba6SOleksandr Tymoshenko 	union {
6397247a2aSIan Lepore 		struct timecounter tc;
64e53470feSOleksandr Tymoshenko 		struct eventtimer et;
655b03aba6SOleksandr Tymoshenko 	} func;
66479e7c44SIan Lepore 	int			tmr_num;	/* Hardware unit number. */
67479e7c44SIan Lepore 	char			tmr_name[12];	/* "DMTimerN", N = tmr_num */
68e53470feSOleksandr Tymoshenko };
69e53470feSOleksandr Tymoshenko 
705b03aba6SOleksandr Tymoshenko static struct am335x_dmtimer_softc *am335x_dmtimer_et_sc = NULL;
715b03aba6SOleksandr Tymoshenko static struct am335x_dmtimer_softc *am335x_dmtimer_tc_sc = NULL;
7297247a2aSIan Lepore 
738fcbb323SAndrew Turner static void am335x_dmtimer_delay(int, void *);
748fcbb323SAndrew Turner 
75fb962e6dSIan Lepore /*
76479e7c44SIan Lepore  * We use dmtimer2 for eventtimer and dmtimer3 for timecounter.
77fb962e6dSIan Lepore  */
78479e7c44SIan Lepore #define ET_TMR_NUM      2
79479e7c44SIan Lepore #define TC_TMR_NUM      3
80fb962e6dSIan Lepore 
81479e7c44SIan Lepore /* List of compatible strings for FDT tree */
82479e7c44SIan Lepore static struct ofw_compat_data compat_data[] = {
83479e7c44SIan Lepore 	{"ti,am335x-timer",     1},
84479e7c44SIan Lepore 	{"ti,am335x-timer-1ms", 1},
85479e7c44SIan Lepore 	{NULL,                  0},
86fb962e6dSIan Lepore };
87fb962e6dSIan Lepore 
88479e7c44SIan Lepore #define	DMTIMER_READ4(sc, reg)		bus_read_4((sc)->tmr_mem_res, (reg))
89479e7c44SIan Lepore #define	DMTIMER_WRITE4(sc, reg, val)	bus_write_4((sc)->tmr_mem_res, (reg), (val))
90e53470feSOleksandr Tymoshenko 
91e53470feSOleksandr Tymoshenko static int
am335x_dmtimer_et_start(struct eventtimer * et,sbintime_t first,sbintime_t period)92479e7c44SIan Lepore am335x_dmtimer_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
93e53470feSOleksandr Tymoshenko {
9497247a2aSIan Lepore 	struct am335x_dmtimer_softc *sc;
95fb962e6dSIan Lepore 	uint32_t initial_count, reload_count;
96e53470feSOleksandr Tymoshenko 
9797247a2aSIan Lepore 	sc = et->et_priv;
9897247a2aSIan Lepore 
99fb962e6dSIan Lepore 	/*
100fb962e6dSIan Lepore 	 * Stop the timer before changing it.  This routine will often be called
101fb962e6dSIan Lepore 	 * while the timer is still running, to either lengthen or shorten the
102fb962e6dSIan Lepore 	 * current event time.  We need to ensure the timer doesn't expire while
103fb962e6dSIan Lepore 	 * we're working with it.
104fb962e6dSIan Lepore 	 *
105fb962e6dSIan Lepore 	 * Also clear any pending interrupt status, because it's at least
106fb962e6dSIan Lepore 	 * theoretically possible that we're running in a primary interrupt
107fb962e6dSIan Lepore 	 * context now, and a timer interrupt could be pending even before we
108fb962e6dSIan Lepore 	 * stopped the timer.  The more likely case is that we're being called
109fb962e6dSIan Lepore 	 * from the et_event_cb() routine dispatched from our own handler, but
110fb962e6dSIan Lepore 	 * it's not clear to me that that's the only case possible.
111fb962e6dSIan Lepore 	 */
1125b03aba6SOleksandr Tymoshenko 	sc->tclr &= ~(DMT_TCLR_START | DMT_TCLR_AUTOLOAD);
1135b03aba6SOleksandr Tymoshenko 	DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr);
1145b03aba6SOleksandr Tymoshenko 	DMTIMER_WRITE4(sc, DMT_IRQSTATUS, DMT_IRQ_OVF);
115fb962e6dSIan Lepore 
116fdc5dd2dSAlexander Motin 	if (period != 0) {
117fb962e6dSIan Lepore 		reload_count = ((uint32_t)et->et_frequency * period) >> 32;
1185b03aba6SOleksandr Tymoshenko 		sc->tclr |= DMT_TCLR_AUTOLOAD;
119e53470feSOleksandr Tymoshenko 	} else {
120fb962e6dSIan Lepore 		reload_count = 0;
121e53470feSOleksandr Tymoshenko 	}
122e53470feSOleksandr Tymoshenko 
123fdc5dd2dSAlexander Motin 	if (first != 0)
124fb962e6dSIan Lepore 		initial_count = ((uint32_t)et->et_frequency * first) >> 32;
125fdc5dd2dSAlexander Motin 	else
126fb962e6dSIan Lepore 		initial_count = reload_count;
127e53470feSOleksandr Tymoshenko 
128fb962e6dSIan Lepore 	/*
129fb962e6dSIan Lepore 	 * Set auto-reload and current-count values.  This timer hardware counts
130fb962e6dSIan Lepore 	 * up from the initial/reload value and interrupts on the zero rollover.
131fb962e6dSIan Lepore 	 */
1325b03aba6SOleksandr Tymoshenko 	DMTIMER_WRITE4(sc, DMT_TLDR, 0xFFFFFFFF - reload_count);
1335b03aba6SOleksandr Tymoshenko 	DMTIMER_WRITE4(sc, DMT_TCRR, 0xFFFFFFFF - initial_count);
134e53470feSOleksandr Tymoshenko 
135fb962e6dSIan Lepore 	/* Enable overflow interrupt, and start the timer. */
1365b03aba6SOleksandr Tymoshenko 	DMTIMER_WRITE4(sc, DMT_IRQENABLE_SET, DMT_IRQ_OVF);
1375b03aba6SOleksandr Tymoshenko 	sc->tclr |= DMT_TCLR_START;
1385b03aba6SOleksandr Tymoshenko 	DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr);
139e53470feSOleksandr Tymoshenko 
140e53470feSOleksandr Tymoshenko 	return (0);
141e53470feSOleksandr Tymoshenko }
142e53470feSOleksandr Tymoshenko 
143e53470feSOleksandr Tymoshenko static int
am335x_dmtimer_et_stop(struct eventtimer * et)144479e7c44SIan Lepore am335x_dmtimer_et_stop(struct eventtimer *et)
145e53470feSOleksandr Tymoshenko {
14697247a2aSIan Lepore 	struct am335x_dmtimer_softc *sc;
14797247a2aSIan Lepore 
14897247a2aSIan Lepore 	sc = et->et_priv;
149e53470feSOleksandr Tymoshenko 
150fb962e6dSIan Lepore 	/* Stop timer, disable and clear interrupt. */
1515b03aba6SOleksandr Tymoshenko 	sc->tclr &= ~(DMT_TCLR_START | DMT_TCLR_AUTOLOAD);
1525b03aba6SOleksandr Tymoshenko 	DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr);
1535b03aba6SOleksandr Tymoshenko 	DMTIMER_WRITE4(sc, DMT_IRQENABLE_CLR, DMT_IRQ_OVF);
1545b03aba6SOleksandr Tymoshenko 	DMTIMER_WRITE4(sc, DMT_IRQSTATUS, DMT_IRQ_OVF);
155e53470feSOleksandr Tymoshenko 	return (0);
156e53470feSOleksandr Tymoshenko }
157e53470feSOleksandr Tymoshenko 
158e53470feSOleksandr Tymoshenko static int
am335x_dmtimer_et_intr(void * arg)159479e7c44SIan Lepore am335x_dmtimer_et_intr(void *arg)
160e53470feSOleksandr Tymoshenko {
16197247a2aSIan Lepore 	struct am335x_dmtimer_softc *sc;
162e53470feSOleksandr Tymoshenko 
16397247a2aSIan Lepore 	sc = arg;
164fb962e6dSIan Lepore 
165fb962e6dSIan Lepore 	/* Ack the interrupt, and invoke the callback if it's still enabled. */
1665b03aba6SOleksandr Tymoshenko 	DMTIMER_WRITE4(sc, DMT_IRQSTATUS, DMT_IRQ_OVF);
1675b03aba6SOleksandr Tymoshenko 	if (sc->func.et.et_active)
1685b03aba6SOleksandr Tymoshenko 		sc->func.et.et_event_cb(&sc->func.et, sc->func.et.et_arg);
169e53470feSOleksandr Tymoshenko 
170e53470feSOleksandr Tymoshenko 	return (FILTER_HANDLED);
171e53470feSOleksandr Tymoshenko }
172e53470feSOleksandr Tymoshenko 
173479e7c44SIan Lepore static int
am335x_dmtimer_et_init(struct am335x_dmtimer_softc * sc)174479e7c44SIan Lepore am335x_dmtimer_et_init(struct am335x_dmtimer_softc *sc)
175479e7c44SIan Lepore {
176479e7c44SIan Lepore 	KASSERT(am335x_dmtimer_et_sc == NULL, ("already have an eventtimer"));
177479e7c44SIan Lepore 
1785b03aba6SOleksandr Tymoshenko 	/*
179479e7c44SIan Lepore 	 * Setup eventtimer interrupt handling.  Panic if anything goes wrong,
180479e7c44SIan Lepore 	 * because the system just isn't going to run without an eventtimer.
1815b03aba6SOleksandr Tymoshenko 	 */
182479e7c44SIan Lepore 	sc->tmr_irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
183479e7c44SIan Lepore 	    &sc->tmr_irq_rid, RF_ACTIVE);
184479e7c44SIan Lepore 	if (sc->tmr_irq_res == NULL)
185479e7c44SIan Lepore 		panic("am335x_dmtimer: could not allocate irq resources");
1865b03aba6SOleksandr Tymoshenko 	if (bus_setup_intr(sc->dev, sc->tmr_irq_res, INTR_TYPE_CLK,
187479e7c44SIan Lepore 	    am335x_dmtimer_et_intr, NULL, sc, &sc->tmr_irq_handler) != 0)
188479e7c44SIan Lepore 		panic("am335x_dmtimer: count not setup irq handler");
1895b03aba6SOleksandr Tymoshenko 
190479e7c44SIan Lepore 	sc->func.et.et_name = sc->tmr_name;
1915b03aba6SOleksandr Tymoshenko 	sc->func.et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT;
192479e7c44SIan Lepore 	sc->func.et.et_quality = 500;
1935b03aba6SOleksandr Tymoshenko 	sc->func.et.et_frequency = sc->sysclk_freq;
1945b03aba6SOleksandr Tymoshenko 	sc->func.et.et_min_period =
1955b03aba6SOleksandr Tymoshenko 	    ((0x00000005LLU << 32) / sc->func.et.et_frequency);
1965b03aba6SOleksandr Tymoshenko 	sc->func.et.et_max_period =
1975b03aba6SOleksandr Tymoshenko 	    (0xfffffffeLLU << 32) / sc->func.et.et_frequency;
198479e7c44SIan Lepore 	sc->func.et.et_start = am335x_dmtimer_et_start;
199479e7c44SIan Lepore 	sc->func.et.et_stop = am335x_dmtimer_et_stop;
2005b03aba6SOleksandr Tymoshenko 	sc->func.et.et_priv = sc;
2015b03aba6SOleksandr Tymoshenko 
2025b03aba6SOleksandr Tymoshenko 	am335x_dmtimer_et_sc = sc;
203479e7c44SIan Lepore 	et_register(&sc->func.et);
2045b03aba6SOleksandr Tymoshenko 
2055b03aba6SOleksandr Tymoshenko 	return (0);
2065b03aba6SOleksandr Tymoshenko }
2075b03aba6SOleksandr Tymoshenko 
208479e7c44SIan Lepore static unsigned
am335x_dmtimer_tc_get_timecount(struct timecounter * tc)209479e7c44SIan Lepore am335x_dmtimer_tc_get_timecount(struct timecounter *tc)
2105b03aba6SOleksandr Tymoshenko {
211479e7c44SIan Lepore 	struct am335x_dmtimer_softc *sc;
212479e7c44SIan Lepore 
213479e7c44SIan Lepore 	sc = tc->tc_priv;
214479e7c44SIan Lepore 
215479e7c44SIan Lepore 	return (DMTIMER_READ4(sc, DMT_TCRR));
216479e7c44SIan Lepore }
217479e7c44SIan Lepore 
218479e7c44SIan Lepore static int
am335x_dmtimer_tc_init(struct am335x_dmtimer_softc * sc)219479e7c44SIan Lepore am335x_dmtimer_tc_init(struct am335x_dmtimer_softc *sc)
220479e7c44SIan Lepore {
221479e7c44SIan Lepore 	KASSERT(am335x_dmtimer_tc_sc == NULL, ("already have a timecounter"));
2225b03aba6SOleksandr Tymoshenko 
2235b03aba6SOleksandr Tymoshenko 	/* Set up timecounter, start it, register it. */
2245b03aba6SOleksandr Tymoshenko 	DMTIMER_WRITE4(sc, DMT_TSICR, DMT_TSICR_RESET);
2255b03aba6SOleksandr Tymoshenko 	while (DMTIMER_READ4(sc, DMT_TIOCP_CFG) & DMT_TIOCP_RESET)
2265b03aba6SOleksandr Tymoshenko 		continue;
2275b03aba6SOleksandr Tymoshenko 
2285b03aba6SOleksandr Tymoshenko 	sc->tclr |= DMT_TCLR_START | DMT_TCLR_AUTOLOAD;
2295b03aba6SOleksandr Tymoshenko 	DMTIMER_WRITE4(sc, DMT_TLDR, 0);
2305b03aba6SOleksandr Tymoshenko 	DMTIMER_WRITE4(sc, DMT_TCRR, 0);
2315b03aba6SOleksandr Tymoshenko 	DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr);
2325b03aba6SOleksandr Tymoshenko 
233479e7c44SIan Lepore 	sc->func.tc.tc_name           = sc->tmr_name;
2345b03aba6SOleksandr Tymoshenko 	sc->func.tc.tc_get_timecount  = am335x_dmtimer_tc_get_timecount;
2355b03aba6SOleksandr Tymoshenko 	sc->func.tc.tc_counter_mask   = ~0u;
2365b03aba6SOleksandr Tymoshenko 	sc->func.tc.tc_frequency      = sc->sysclk_freq;
237479e7c44SIan Lepore 	sc->func.tc.tc_quality        = 500;
2385b03aba6SOleksandr Tymoshenko 	sc->func.tc.tc_priv           = sc;
2395b03aba6SOleksandr Tymoshenko 
2405b03aba6SOleksandr Tymoshenko 	am335x_dmtimer_tc_sc = sc;
241479e7c44SIan Lepore 	tc_init(&sc->func.tc);
2425b03aba6SOleksandr Tymoshenko 
2438fcbb323SAndrew Turner 	arm_set_delay(am335x_dmtimer_delay, sc);
2448fcbb323SAndrew Turner 
2455b03aba6SOleksandr Tymoshenko 	return (0);
2465b03aba6SOleksandr Tymoshenko }
2475b03aba6SOleksandr Tymoshenko 
248e53470feSOleksandr Tymoshenko static int
am335x_dmtimer_probe(device_t dev)249e53470feSOleksandr Tymoshenko am335x_dmtimer_probe(device_t dev)
250e53470feSOleksandr Tymoshenko {
251479e7c44SIan Lepore 	int tmr_num;
2520050ea24SMichal Meloun 	uint64_t rev_address;
253e53470feSOleksandr Tymoshenko 
254add35ed5SIan Lepore 	if (!ofw_bus_status_okay(dev))
255add35ed5SIan Lepore 		return (ENXIO);
256add35ed5SIan Lepore 
257479e7c44SIan Lepore 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
258e53470feSOleksandr Tymoshenko 		return (ENXIO);
259479e7c44SIan Lepore 
260479e7c44SIan Lepore 	/*
2610050ea24SMichal Meloun 	 * Get the hardware unit number from address of rev register.
262479e7c44SIan Lepore 	 * If this isn't the hardware unit we're going to use for either the
263479e7c44SIan Lepore 	 * eventtimer or the timecounter, no point in instantiating the device.
264479e7c44SIan Lepore 	 */
2650050ea24SMichal Meloun 	rev_address = ti_sysc_get_rev_address(device_get_parent(dev));
2660050ea24SMichal Meloun 	switch (rev_address) {
2670050ea24SMichal Meloun 		case DMTIMER2_REV:
2680050ea24SMichal Meloun 			tmr_num = 2;
2690050ea24SMichal Meloun 			break;
2700050ea24SMichal Meloun 		case DMTIMER3_REV:
2710050ea24SMichal Meloun 			tmr_num = 3;
2720050ea24SMichal Meloun 			break;
2730050ea24SMichal Meloun 		default:
2740050ea24SMichal Meloun 			/* Not DMTIMER2 or DMTIMER3 */
275479e7c44SIan Lepore 			return (ENXIO);
2760050ea24SMichal Meloun 	}
277479e7c44SIan Lepore 
278*332f00cdSOskar Holmlund 	device_set_descf(dev, "AM335x DMTimer%d", tmr_num);
279479e7c44SIan Lepore 
280479e7c44SIan Lepore 	return(BUS_PROBE_DEFAULT);
281e53470feSOleksandr Tymoshenko }
282e53470feSOleksandr Tymoshenko 
283e53470feSOleksandr Tymoshenko static int
am335x_dmtimer_attach(device_t dev)284e53470feSOleksandr Tymoshenko am335x_dmtimer_attach(device_t dev)
285e53470feSOleksandr Tymoshenko {
28697247a2aSIan Lepore 	struct am335x_dmtimer_softc *sc;
287479e7c44SIan Lepore 	int err;
2880050ea24SMichal Meloun 	uint64_t rev_address;
2890050ea24SMichal Meloun 	clk_t sys_clkin;
290e53470feSOleksandr Tymoshenko 
29197247a2aSIan Lepore 	sc = device_get_softc(dev);
2925b03aba6SOleksandr Tymoshenko 	sc->dev = dev;
293e53470feSOleksandr Tymoshenko 
2940050ea24SMichal Meloun 	/* expect one clock */
2950050ea24SMichal Meloun 	err = clk_get_by_ofw_index(dev, 0, 0, &sc->clk_fck);
2960050ea24SMichal Meloun 	if (err != 0) {
2970050ea24SMichal Meloun 		device_printf(dev, "Cant find clock index 0. err: %d\n", err);
2980050ea24SMichal Meloun 		return (ENXIO);
2990050ea24SMichal Meloun 	}
3000050ea24SMichal Meloun 
3010050ea24SMichal Meloun 	err = clk_get_by_name(dev, "sys_clkin_ck@40", &sys_clkin);
3020050ea24SMichal Meloun 	if (err != 0) {
3030050ea24SMichal Meloun 		device_printf(dev, "Cant find sys_clkin_ck@40 err: %d\n", err);
3040050ea24SMichal Meloun 		return (ENXIO);
3050050ea24SMichal Meloun 	}
3060050ea24SMichal Meloun 
3070050ea24SMichal Meloun 	/* Select M_OSC as DPLL parent */
3080050ea24SMichal Meloun 	err = clk_set_parent_by_clk(sc->clk_fck, sys_clkin);
3090050ea24SMichal Meloun 	if (err != 0) {
3100050ea24SMichal Meloun 		device_printf(dev, "Cant set mux to CLK_M_OSC\n");
3110050ea24SMichal Meloun 		return (ENXIO);
3120050ea24SMichal Meloun 	}
313479e7c44SIan Lepore 
314479e7c44SIan Lepore 	/* Enable clocks and power on the device. */
3150050ea24SMichal Meloun 	err = ti_sysc_clock_enable(device_get_parent(dev));
3160050ea24SMichal Meloun 	if (err != 0) {
3170050ea24SMichal Meloun 		device_printf(dev, "Cant enable sysc clkctrl, err %d\n", err);
318e53470feSOleksandr Tymoshenko 		return (ENXIO);
3190050ea24SMichal Meloun 	}
3200050ea24SMichal Meloun 
3210050ea24SMichal Meloun 	/* Get the base clock frequency. */
3220050ea24SMichal Meloun 	err = clk_get_freq(sc->clk_fck, &sc->sysclk_freq);
3230050ea24SMichal Meloun 	if (err != 0) {
3240050ea24SMichal Meloun 		device_printf(dev, "Cant get sysclk frequency, err %d\n", err);
3250050ea24SMichal Meloun 		return (ENXIO);
3260050ea24SMichal Meloun 	}
327e53470feSOleksandr Tymoshenko 
32897247a2aSIan Lepore 	/* Request the memory resources. */
3295b03aba6SOleksandr Tymoshenko 	sc->tmr_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
3305b03aba6SOleksandr Tymoshenko 	    &sc->tmr_mem_rid, RF_ACTIVE);
3315b03aba6SOleksandr Tymoshenko 	if (sc->tmr_mem_res == NULL) {
332e53470feSOleksandr Tymoshenko 		return (ENXIO);
333e53470feSOleksandr Tymoshenko 	}
334e53470feSOleksandr Tymoshenko 
3350050ea24SMichal Meloun 	rev_address = ti_sysc_get_rev_address(device_get_parent(dev));
3360050ea24SMichal Meloun 	switch (rev_address) {
3370050ea24SMichal Meloun 		case DMTIMER2_REV:
3380050ea24SMichal Meloun 			sc->tmr_num = 2;
3390050ea24SMichal Meloun 			break;
3400050ea24SMichal Meloun 		case DMTIMER3_REV:
3410050ea24SMichal Meloun 			sc->tmr_num = 3;
3420050ea24SMichal Meloun 			break;
3430050ea24SMichal Meloun 		default:
3440050ea24SMichal Meloun 			device_printf(dev, "Not timer 2 or 3! %#jx\n",
3450050ea24SMichal Meloun 			    rev_address);
3460050ea24SMichal Meloun 			return (ENXIO);
3470050ea24SMichal Meloun 	}
3480050ea24SMichal Meloun 
349479e7c44SIan Lepore 	snprintf(sc->tmr_name, sizeof(sc->tmr_name), "DMTimer%d", sc->tmr_num);
350e53470feSOleksandr Tymoshenko 
351479e7c44SIan Lepore 	/*
352479e7c44SIan Lepore 	 * Go set up either a timecounter or eventtimer.  We wouldn't have
353479e7c44SIan Lepore 	 * attached if we weren't one or the other.
354479e7c44SIan Lepore 	 */
355479e7c44SIan Lepore 	if (sc->tmr_num == ET_TMR_NUM)
356479e7c44SIan Lepore 		am335x_dmtimer_et_init(sc);
357479e7c44SIan Lepore 	else if (sc->tmr_num == TC_TMR_NUM)
358479e7c44SIan Lepore 		am335x_dmtimer_tc_init(sc);
359479e7c44SIan Lepore 	else
360479e7c44SIan Lepore 		panic("am335x_dmtimer: bad timer number %d", sc->tmr_num);
361fb962e6dSIan Lepore 
362e53470feSOleksandr Tymoshenko 	return (0);
363e53470feSOleksandr Tymoshenko }
364e53470feSOleksandr Tymoshenko 
365e53470feSOleksandr Tymoshenko static device_method_t am335x_dmtimer_methods[] = {
366e53470feSOleksandr Tymoshenko 	DEVMETHOD(device_probe,		am335x_dmtimer_probe),
367e53470feSOleksandr Tymoshenko 	DEVMETHOD(device_attach,	am335x_dmtimer_attach),
368e53470feSOleksandr Tymoshenko 	{ 0, 0 }
369e53470feSOleksandr Tymoshenko };
370e53470feSOleksandr Tymoshenko 
371e53470feSOleksandr Tymoshenko static driver_t am335x_dmtimer_driver = {
372e53470feSOleksandr Tymoshenko 	"am335x_dmtimer",
373e53470feSOleksandr Tymoshenko 	am335x_dmtimer_methods,
374e53470feSOleksandr Tymoshenko 	sizeof(struct am335x_dmtimer_softc),
375e53470feSOleksandr Tymoshenko };
376e53470feSOleksandr Tymoshenko 
3778537e671SJohn Baldwin DRIVER_MODULE(am335x_dmtimer, simplebus, am335x_dmtimer_driver, 0, 0);
3780050ea24SMichal Meloun MODULE_DEPEND(am335x_dmtimer, ti_sysc, 1, 1, 1);
379e53470feSOleksandr Tymoshenko 
3808fcbb323SAndrew Turner static void
am335x_dmtimer_delay(int usec,void * arg)3818fcbb323SAndrew Turner am335x_dmtimer_delay(int usec, void *arg)
382e53470feSOleksandr Tymoshenko {
3838fcbb323SAndrew Turner 	struct am335x_dmtimer_softc *sc = arg;
384e53470feSOleksandr Tymoshenko 	int32_t counts;
385e53470feSOleksandr Tymoshenko 	uint32_t first, last;
386e53470feSOleksandr Tymoshenko 
387e53470feSOleksandr Tymoshenko 	/* Get the number of times to count */
38897247a2aSIan Lepore 	counts = (usec + 1) * (sc->sysclk_freq / 1000000);
389e53470feSOleksandr Tymoshenko 
3905b03aba6SOleksandr Tymoshenko 	first = DMTIMER_READ4(sc, DMT_TCRR);
391e53470feSOleksandr Tymoshenko 
392e53470feSOleksandr Tymoshenko 	while (counts > 0) {
3935b03aba6SOleksandr Tymoshenko 		last = DMTIMER_READ4(sc, DMT_TCRR);
394e53470feSOleksandr Tymoshenko 		if (last > first) {
395e53470feSOleksandr Tymoshenko 			counts -= (int32_t)(last - first);
396e53470feSOleksandr Tymoshenko 		} else {
397e53470feSOleksandr Tymoshenko 			counts -= (int32_t)((0xFFFFFFFF - first) + last);
398e53470feSOleksandr Tymoshenko 		}
399e53470feSOleksandr Tymoshenko 		first = last;
400e53470feSOleksandr Tymoshenko 	}
401e53470feSOleksandr Tymoshenko }
402