1275970Scy/*$NetBSD: at91tctmr.c,v 1.9 2020/07/03 16:23:02 maxv Exp $*/
2275970Scy
3275970Scy/*
4275970Scy * AT91 Timer Counter (TC) based clock functions
5275970Scy * Copyright (c) 2007, Embedtronics Oy
6275970Scy * All rights reserved.
7275970Scy *
8275970Scy * Based on vx115_clk.c,
9275970Scy * Copyright (c) 2006, Jon Sevy <jsevy@cs.drexel.edu>
10275970Scy *
11275970Scy * Based on epclk.c
12275970Scy * Copyright (c) 2004 Jesse Off
13275970Scy * All rights reserved.
14275970Scy *
15275970Scy * Redistribution and use in source and binary forms, with or without
16275970Scy * modification, are permitted provided that the following conditions
17275970Scy * are met:
18275970Scy * 1. Redistributions of source code must retain the above copyright
19275970Scy *    notice, this list of conditions and the following disclaimer.
20275970Scy * 2. Redistributions in binary form must reproduce the above copyright
21275970Scy *    notice, this list of conditions and the following disclaimer in the
22275970Scy *    documentation and/or other materials provided with the distribution.
23275970Scy *
24275970Scy * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25275970Scy * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26275970Scy * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27275970Scy * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28275970Scy * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29275970Scy * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30275970Scy * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31275970Scy * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32275970Scy * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33275970Scy * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34275970Scy * POSSIBILITY OF SUCH DAMAGE.
35275970Scy */
36275970Scy
37275970Scy/*
38275970Scy * Driver for the AT91RM9200 clock tick.
39275970Scy * We use Timer 1 for the system clock
40275970Scy */
41275970Scy
42275970Scy#include <sys/cdefs.h>
43275970Scy__KERNEL_RCSID(0, "$NetBSD: at91tctmr.c,v 1.9 2020/07/03 16:23:02 maxv Exp $");
44275970Scy
45275970Scy#include <sys/types.h>
46275970Scy#include <sys/param.h>
47275970Scy#include <sys/systm.h>
48275970Scy#include <sys/kernel.h>
49275970Scy#include <sys/time.h>
50275970Scy#include <sys/timetc.h>
51275970Scy#include <sys/device.h>
52275970Scy
53275970Scy#include <dev/clock_subr.h>
54275970Scy
55275970Scy#include <sys/bus.h>
56275970Scy#include <machine/intr.h>
57275970Scy
58275970Scy#include <arm/cpufunc.h>
59275970Scy#include <arm/at91/at91reg.h>
60275970Scy#include <arm/at91/at91var.h>
61275970Scy#include <arm/at91/at91tcreg.h>
62275970Scy
63275970Scy#include <opt_hz.h>     /* for HZ */
64275970Scy
65275970Scy
66275970Scy#define DEBUG_CLK
67275970Scy#ifdef DEBUG_CLK
68275970Scy#define DPRINTF(fmt...)  printf(fmt)
69275970Scy#else
70275970Scy#define DPRINTF(fmt...)
71275970Scy#endif
72275970Scy
73275970Scy
74275970Scystatic int at91tctmr_match(device_t, cfdata_t, void *);
75275970Scystatic void at91tctmr_attach(device_t, device_t, void *);
76275970Scy
77275970Scyvoid rtcinit(void);
78275970Scy
79275970Scy/* callback functions for intr_functions */
80275970Scystatic int at91tctmr_intr(void* arg);
81275970Scy
82275970Scystruct at91tctmr_softc {
83275970Scy	device_t	sc_dev;
84275970Scy	u_char		*sc_addr;
85275970Scy	int		sc_pid;
86275970Scy	int		sc_initialized;
87275970Scy	uint32_t	sc_timerclock;
88275970Scy	uint32_t	sc_divider;
89275970Scy	uint32_t	sc_usec_per_tick;
90275970Scy};
91275970Scy
92275970Scystatic struct at91tctmr_softc *at91tctmr_sc = NULL;
93275970Scy#if 0
94275970Scystatic struct timeval lasttv;
95275970Scy#endif
96275970Scy
97275970Scy
98275970Scy
99275970Scy/* Match value for clock timer; running at master clock, want HZ ticks per second  */
100275970Scy/* NOTE: don't change there without visiting the functions below which      */
101275970Scy/* convert between timer counts and microseconds                            */
102275970Scy
103275970Scystatic inline uint32_t
104275970Scyat91tctmr_count_to_usec(struct at91tctmr_softc *sc, uint32_t count)
105275970Scy{
106275970Scy    uint64_t tmp;
107275970Scy
108275970Scy    tmp = count;
109275970Scy    tmp *= 1000000U;
110275970Scy
111275970Scy    return (tmp / sc->sc_timerclock);
112275970Scy}
113275970Scy
114275970Scy#if 0
115275970Scy/* This may only be called when overflow is avoided; typically, */
116275970Scy/* it will be used when usec < USEC_PER_TICK              */
117275970Scystatic uint32_t
118275970Scyusec_to_timer_count(uint32_t usec)
119275970Scy{
120275970Scy    uint32_t result;
121275970Scy
122275970Scy    /* convert specified number of usec to timer ticks, and round up */
123275970Scy    result = (AT91_SCLK * usec) / 1000000;
124275970Scy
125275970Scy    if ((result * 1000000) != (usec * AT91_SCLK))
126275970Scy    {
127275970Scy        /* round up */
128275970Scy        result += 1;
129275970Scy    }
130275970Scy
131275970Scy    return result;
132275970Scy
133275970Scy}
134275970Scy#endif
135275970Scy
136275970Scy/* macros to simplify writing to the timer controller */
137275970Scystatic inline uint32_t
138275970ScyREAD_TC(struct at91tctmr_softc *sc, uint offset)
139275970Scy{
140275970Scy	volatile uint32_t *addr = (void*)(sc->sc_addr + offset);
141275970Scy	return *addr;
142275970Scy}
143275970Scy
144275970Scy//bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset)
145275970Scystatic inline void
146275970ScyWRITE_TC(struct at91tctmr_softc *sc, uint offset, uint32_t value)
147275970Scy{
148275970Scy	volatile uint32_t *addr = (void*)(sc->sc_addr + offset);
149275970Scy	*addr = value;
150275970Scy}
151275970Scy
152275970Scy
153275970ScyCFATTACH_DECL_NEW(at91tctmr, sizeof(struct at91tctmr_softc),
154275970Scy    at91tctmr_match, at91tctmr_attach, NULL, NULL);
155275970Scy
156275970Scy#if 0
157275970Scystatic u_int at91tctmr_get_timecount(struct timecounter *);
158275970Scy
159275970Scystatic struct timecounter at91tctmr_timecounter = {
160275970Scy	.tc_get_timecount = at91tctmr_get_timecount,
161275970Scy	.tc_counter_mask = 0xffffffff,
162275970Scy	.tc_frequency = COUNTS_PER_SEC,
163275970Scy	.tc_name = "at91tctmr",
164275970Scy	.tc_quality = 100,
165275970Scy};
166275970Scy#endif
167275970Scy
168275970Scystatic int
169275970Scyat91tctmr_match(device_t parent, cfdata_t match, void *aux)
170275970Scy{
171275970Scy	if (strcmp(match->cf_name, "at91tctmr") == 0)
172275970Scy		return 2;
173275970Scy	return 0;
174275970Scy}
175275970Scy
176275970Scystatic void
177275970Scyat91tctmr_attach(device_t parent, device_t self, void *aux)
178275970Scy{
179275970Scy    struct at91tctmr_softc *sc = device_private(self);
180275970Scy    struct at91bus_attach_args *sa = aux;
181275970Scy
182275970Scy    aprint_normal("\n");
183275970Scy
184275970Scy    sc->sc_dev = self;
185275970Scy    sc->sc_addr = (void*)sa->sa_addr;
186275970Scy    sc->sc_pid = sa->sa_pid;
187275970Scy
188275970Scy    if (at91tctmr_sc == NULL)
189275970Scy        at91tctmr_sc = sc;
190275970Scy
191275970Scy    at91_peripheral_clock(sc->sc_pid, 1);
192275970Scy
193275970Scy    WRITE_TC(sc, TC_CCR, TC_CCR_CLKDIS);
194275970Scy    WRITE_TC(sc, TC_IDR, -1);	/* make sure interrupts are disabled	*/
195275970Scy
196275970Scy    /* find divider */
197275970Scy    uint32_t cmr = 0;
198275970Scy    if (AT91_MSTCLK / 2U / HZ <= 65536) {
199275970Scy      sc->sc_timerclock = AT91_MSTCLK / 2U;
200275970Scy      cmr = TC_CMR_TCCLKS_MCK_DIV_2;
201275970Scy    } else if (AT91_MSTCLK / 8U / HZ <= 65536) {
202275970Scy      sc->sc_timerclock = AT91_MSTCLK / 8U;
203275970Scy      cmr = TC_CMR_TCCLKS_MCK_DIV_8;
204275970Scy    } else if (AT91_MSTCLK / 32U / HZ <= 65536) {
205275970Scy      sc->sc_timerclock = AT91_MSTCLK / 32U;
206275970Scy      cmr = TC_CMR_TCCLKS_MCK_DIV_32;
207275970Scy    } else if (AT91_MSTCLK / 128U / HZ <= 65536) {
208275970Scy      sc->sc_timerclock = AT91_MSTCLK / 128U;
209275970Scy      cmr = TC_CMR_TCCLKS_MCK_DIV_128;
210275970Scy    } else
211275970Scy      panic("%s: cannot setup timer to reach HZ", device_xname(sc->sc_dev));
212275970Scy
213275970Scy    sc->sc_divider = (sc->sc_timerclock + HZ - 1) / HZ; /* round up */
214275970Scy    sc->sc_usec_per_tick = 1000000UL / (sc->sc_timerclock / sc->sc_divider);
215275970Scy
216275970Scy    WRITE_TC(sc, TC_CMR, TC_CMR_WAVE | cmr | TC_CMR_WAVSEL_UP_RC);
217275970Scy    WRITE_TC(sc, TC_CCR, TC_CCR_CLKEN);
218275970Scy    WRITE_TC(sc, TC_RC,  sc->sc_divider - 1);
219275970Scy    WRITE_TC(sc, TC_CCR, TC_CCR_SWTRG);
220275970Scy
221275970Scy    sc->sc_initialized = 1;
222275970Scy
223275970Scy    DPRINTF("%s: done, tclock=%"PRIu32" div=%"PRIu32" uspertick=%"PRIu32"\n", __FUNCTION__, sc->sc_timerclock, sc->sc_divider, sc->sc_usec_per_tick);
224275970Scy
225275970Scy}
226275970Scy
227275970Scy/*
228275970Scy * at91tctmr_intr:
229275970Scy *
230275970Scy *Handle the hardclock interrupt.
231275970Scy */
232275970Scystatic int
233275970Scyat91tctmr_intr(void *arg)
234275970Scy{
235275970Scy    struct at91tctmr_softc *sc = arg;
236275970Scy
237275970Scy    /* make sure it's the kernel timer that generated the interrupt  */
238275970Scy    /* need to do this since the interrupt line is shared by the    */
239275970Scy    /* other interval and PWM timers                                */
240275970Scy    if (READ_TC(sc, TC_SR) & TC_SR_CPCS) {
241275970Scy        /* call the kernel timer handler */
242275970Scy        hardclock((struct clockframe*) arg);
243275970Scy        return 1;
244275970Scy    } else {
245275970Scy        /* it's one of the other timers; just pass it on */
246275970Scy        return 0;
247275970Scy    }
248275970Scy}
249275970Scy
250275970Scy/*
251275970Scy * setstatclockrate:
252275970Scy *
253275970Scy *Set the rate of the statistics clock.
254275970Scy *
255275970Scy *We assume that hz is either stathz or profhz, and that neither
256275970Scy *will change after being set by cpu_initclocks().  We could
257275970Scy *recalculate the intervals here, but that would be a pain.
258275970Scy */
259275970Scyvoid
260275970Scysetstatclockrate(int hzz)
261275970Scy{
262275970Scy        /* use hardclock */
263275970Scy	(void)hzz;
264275970Scy}
265275970Scy
266275970Scy/*
267275970Scy * cpu_initclocks:
268275970Scy *
269275970Scy *Initialize the clock and get it going.
270275970Scy */
271275970Scystatic void udelay(unsigned int usec);
272275970Scy
273275970Scyvoid
274275970Scycpu_initclocks(void)
275275970Scy{
276275970Scy    struct at91tctmr_softc *sc = at91tctmr_sc;
277275970Scy
278275970Scy    if (!sc || !sc->sc_initialized)
279275970Scy	panic("%s: driver has not been initialized! (sc=%p)", __FUNCTION__, sc);
280275970Scy
281275970Scy    hz = sc->sc_timerclock / sc->sc_divider;
282275970Scy    stathz = profhz = 0;
283275970Scy
284275970Scy    /* set up and enable interval timer 1 as kernel timer, */
285275970Scy    /* using 32kHz clock source */
286275970Scy
287275970Scy    /* register interrupt handler */
288275970Scy    at91_intr_establish(sc->sc_pid, IPL_CLOCK, INTR_HIGH_LEVEL, at91tctmr_intr, sc);
289
290    /* enable interrupts from timer */
291    WRITE_TC(sc, TC_IER, TC_SR_CPCS);
292}
293
294
295
296
297static void udelay(unsigned int usec)
298{
299    struct at91tctmr_softc *sc = at91tctmr_sc;
300    uint32_t prev_cvr, cvr, divi = READ_TC(sc, TC_RC), diff;
301    int prev_ticks, ticks, ticks2;
302    unsigned footick = (sc->sc_timerclock * 64ULL / 1000000UL);
303
304    if (usec > 0) {
305      prev_ticks = getticks();
306      __insn_barrier();
307      prev_cvr = READ_TC(sc, TC_CV);
308      ticks = getticks();
309      __insn_barrier();
310      if (ticks != prev_ticks) {
311	prev_cvr = READ_TC(sc, TC_CV);
312	prev_ticks = ticks;
313      }
314      for (;;) {
315	ticks = getticks();
316	__insn_barrier();
317	cvr = READ_TC(sc, TC_CV);
318	ticks2 = getticks();
319	__insn_barrier();
320	if (ticks2 != ticks) {
321	  cvr = READ_TC(sc, TC_CV);
322	}
323	diff = (ticks2 - prev_ticks) * divi;
324	if (cvr < prev_cvr) {
325	  if (!diff)
326	    diff = divi;
327	  diff -= prev_cvr - cvr;
328	} else
329	  diff += cvr - prev_cvr;
330	diff = diff * 64 / footick;
331	if (diff) {
332	  if (usec <= diff)
333	    break;
334	  prev_ticks = ticks2;
335	  prev_cvr = (prev_cvr + footick * diff / 64) % divi;
336	  usec -= diff;
337	}
338      }
339    }
340}
341
342
343
344/*
345 * delay:
346 *
347 *Delay for at least N microseconds. Note that due to our coarse clock,
348 *  our resolution is 61 us. But we round up so we'll wait at least as
349 *  long as requested.
350 */
351void
352delay(unsigned int usec)
353{
354    struct at91tctmr_softc *sc = at91tctmr_sc;
355
356#ifdef DEBUG
357    if (sc == NULL) {
358        printf("delay: called before start at91tc\n");
359        return;
360    }
361#endif
362
363    if (usec >= sc->sc_usec_per_tick) {
364        /* have more than 1 tick; just do in ticks */
365        unsigned int ticks = (usec + sc->sc_usec_per_tick - 1) / sc->sc_usec_per_tick;
366        while (ticks-- > 0) {
367	  udelay(sc->sc_usec_per_tick);
368	}
369    } else {
370        /* less than 1 tick; can do as usec */
371        udelay(usec);
372    }
373
374}
375
376