1*7804a487Sskrll /* $NetBSD: epclk.c,v 1.23 2021/11/21 08:25:26 skrll Exp $ */
2e98c2a1dSjoff
3e98c2a1dSjoff /*
4e98c2a1dSjoff * Copyright (c) 2004 Jesse Off
5e98c2a1dSjoff * All rights reserved.
6e98c2a1dSjoff *
7e98c2a1dSjoff * Redistribution and use in source and binary forms, with or without
8e98c2a1dSjoff * modification, are permitted provided that the following conditions
9e98c2a1dSjoff * are met:
10e98c2a1dSjoff * 1. Redistributions of source code must retain the above copyright
11e98c2a1dSjoff * notice, this list of conditions and the following disclaimer.
12e98c2a1dSjoff * 2. Redistributions in binary form must reproduce the above copyright
13e98c2a1dSjoff * notice, this list of conditions and the following disclaimer in the
14e98c2a1dSjoff * documentation and/or other materials provided with the distribution.
15e98c2a1dSjoff *
16e98c2a1dSjoff * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17e98c2a1dSjoff * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18e98c2a1dSjoff * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19e98c2a1dSjoff * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20e98c2a1dSjoff * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21e98c2a1dSjoff * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22e98c2a1dSjoff * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23e98c2a1dSjoff * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24e98c2a1dSjoff * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25e98c2a1dSjoff * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26e98c2a1dSjoff * POSSIBILITY OF SUCH DAMAGE.
27e98c2a1dSjoff */
28e98c2a1dSjoff
29e98c2a1dSjoff /*
30e98c2a1dSjoff * Driver for the ep93xx clock tick.
31e98c2a1dSjoff *
32e98c2a1dSjoff * We use the 64Hz RTC interrupt as its the only thing that allows for timekeeping
33e98c2a1dSjoff * of a second (crystal error only). There are two general purpose timers
34e98c2a1dSjoff * on the ep93xx, but they run at a frequency that makes a perfect integer
35e98c2a1dSjoff * number of ticks per second impossible. Note that there was an errata with
36e98c2a1dSjoff * the ep93xx processor and many early boards (including the Cirrus eval board) have
37e98c2a1dSjoff * a broken crystal oscillator input that may make this 64Hz unreliable. However,
38e98c2a1dSjoff * not all boards are susceptible, the Technologic Systems TS-7200 is a notable
39e98c2a1dSjoff * exception that is immune to this errata. --joff
40e98c2a1dSjoff */
41e98c2a1dSjoff
42e98c2a1dSjoff #include <sys/cdefs.h>
43*7804a487Sskrll __KERNEL_RCSID(0, "$NetBSD: epclk.c,v 1.23 2021/11/21 08:25:26 skrll Exp $");
44e98c2a1dSjoff
45e98c2a1dSjoff #include <sys/types.h>
46e98c2a1dSjoff #include <sys/param.h>
47e98c2a1dSjoff #include <sys/systm.h>
48e98c2a1dSjoff #include <sys/kernel.h>
49e98c2a1dSjoff #include <sys/time.h>
504e56cdd2Sjoerg #include <sys/timetc.h>
51e98c2a1dSjoff #include <sys/device.h>
52e98c2a1dSjoff
53cf10107dSdyoung #include <sys/bus.h>
54e98c2a1dSjoff #include <machine/intr.h>
55e98c2a1dSjoff
56e98c2a1dSjoff #include <arm/cpufunc.h>
57e98c2a1dSjoff
58e98c2a1dSjoff #include <arm/ep93xx/epsocvar.h>
59e98c2a1dSjoff #include <arm/ep93xx/epclkreg.h>
607959c31aShamajima #include <arm/ep93xx/ep93xxreg.h>
61e98c2a1dSjoff #include <arm/ep93xx/ep93xxvar.h>
6260b9b5a6Sjoff #include <dev/clock_subr.h>
63e98c2a1dSjoff
647959c31aShamajima #include "opt_hz.h"
657959c31aShamajima
664e56cdd2Sjoerg #define TIMER_FREQ 983040
674e56cdd2Sjoerg
68cbab9cadSchs static int epclk_match(device_t, cfdata_t, void *);
69cbab9cadSchs static void epclk_attach(device_t, device_t, void *);
704e56cdd2Sjoerg static u_int epclk_get_timecount(struct timecounter *);
71e98c2a1dSjoff
72e98c2a1dSjoff void rtcinit(void);
73e98c2a1dSjoff
74e98c2a1dSjoff /* callback functions for intr_functions */
75e98c2a1dSjoff static int epclk_intr(void* arg);
76e98c2a1dSjoff
77e98c2a1dSjoff struct epclk_softc {
78e98c2a1dSjoff bus_addr_t sc_baseaddr;
79e98c2a1dSjoff bus_space_tag_t sc_iot;
80e98c2a1dSjoff bus_space_handle_t sc_ioh;
817959c31aShamajima #if defined(HZ) && (HZ == 64)
82e98c2a1dSjoff bus_space_handle_t sc_teoi_ioh;
837959c31aShamajima #endif
84e98c2a1dSjoff int sc_intr;
85e98c2a1dSjoff };
86e98c2a1dSjoff
874e56cdd2Sjoerg static struct timecounter epclk_timecounter = {
88482eef70Srin .tc_get_timecount = epclk_get_timecount,
89482eef70Srin .tc_counter_mask = ~0u,
90482eef70Srin .tc_frequency = TIMER_FREQ,
91482eef70Srin .tc_name = "epclk",
92482eef70Srin .tc_quality = 100,
934e56cdd2Sjoerg };
944e56cdd2Sjoerg
95e98c2a1dSjoff static struct epclk_softc *epclk_sc = NULL;
96e98c2a1dSjoff
97cbab9cadSchs CFATTACH_DECL_NEW(epclk, sizeof(struct epclk_softc),
98e98c2a1dSjoff epclk_match, epclk_attach, NULL, NULL);
99e98c2a1dSjoff
100abc88641Skenh /* This is a quick ARM way to multiply by 983040/1000000 (w/o overflow) */
101abc88641Skenh #define US_TO_TIMER4VAL(x, y) { \
10208a4aba7Sskrll uint32_t hi, lo, scalar = 4222124650UL; \
103abc88641Skenh __asm volatile ( \
104abc88641Skenh "umull %0, %1, %2, %3;" \
105abc88641Skenh : "=&r"(lo), "=&r"(hi) \
106abc88641Skenh : "r"((x)), "r"(scalar) \
107abc88641Skenh ); \
108abc88641Skenh (y) = hi; \
109abc88641Skenh }
110abc88641Skenh
11108a4aba7Sskrll #define TIMER4VAL() (*(volatile uint32_t *)(EP93XX_APB_VBASE + \
112e98c2a1dSjoff EP93XX_APB_TIMERS + EP93XX_TIMERS_Timer4ValueLow))
113e98c2a1dSjoff
114e98c2a1dSjoff static int
epclk_match(device_t parent,cfdata_t match,void * aux)115cbab9cadSchs epclk_match(device_t parent, cfdata_t match, void *aux)
116e98c2a1dSjoff {
117e98c2a1dSjoff
118e98c2a1dSjoff return 2;
119e98c2a1dSjoff }
120e98c2a1dSjoff
121e98c2a1dSjoff static void
epclk_attach(device_t parent,device_t self,void * aux)122cbab9cadSchs epclk_attach(device_t parent, device_t self, void *aux)
123e98c2a1dSjoff {
124e98c2a1dSjoff struct epclk_softc *sc;
125e98c2a1dSjoff struct epsoc_attach_args *sa;
1264e56cdd2Sjoerg bool first_run;
127e98c2a1dSjoff
128e98c2a1dSjoff printf("\n");
129e98c2a1dSjoff
130cbab9cadSchs sc = device_private(self);
131e98c2a1dSjoff sa = aux;
132e98c2a1dSjoff sc->sc_iot = sa->sa_iot;
133e98c2a1dSjoff sc->sc_baseaddr = sa->sa_addr;
134e98c2a1dSjoff sc->sc_intr = sa->sa_intr;
135e98c2a1dSjoff
1364e56cdd2Sjoerg if (epclk_sc == NULL) {
1374e56cdd2Sjoerg first_run = true;
138e98c2a1dSjoff epclk_sc = sc;
13932f6fb01Smaxv } else
14032f6fb01Smaxv first_run = false;
141e98c2a1dSjoff
142e98c2a1dSjoff if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size,
143e98c2a1dSjoff 0, &sc->sc_ioh))
144cbab9cadSchs panic("%s: Cannot map registers", device_xname(self));
1457959c31aShamajima #if defined(HZ) && (HZ == 64)
146e98c2a1dSjoff if (bus_space_map(sa->sa_iot, EP93XX_APB_HWBASE + EP93XX_APB_SYSCON +
147e98c2a1dSjoff EP93XX_SYSCON_TEOI, 4, 0, &sc->sc_teoi_ioh))
148cbab9cadSchs panic("%s: Cannot map registers", device_xname(self));
1497959c31aShamajima #endif
150e98c2a1dSjoff
151e98c2a1dSjoff /* clear and start the debug timer (Timer4) */
152e98c2a1dSjoff bus_space_write_4(sc->sc_iot, sc->sc_ioh, EP93XX_TIMERS_Timer4Enable, 0);
153e98c2a1dSjoff bus_space_write_4(sc->sc_iot, sc->sc_ioh, EP93XX_TIMERS_Timer4Enable, 0x100);
1544e56cdd2Sjoerg
1554e56cdd2Sjoerg if (first_run)
1564e56cdd2Sjoerg tc_init(&epclk_timecounter);
157e98c2a1dSjoff }
158e98c2a1dSjoff
159e98c2a1dSjoff /*
160e98c2a1dSjoff * epclk_intr:
161e98c2a1dSjoff *
162e98c2a1dSjoff * Handle the hardclock interrupt.
163e98c2a1dSjoff */
164e98c2a1dSjoff static int
epclk_intr(void * arg)165e98c2a1dSjoff epclk_intr(void *arg)
166e98c2a1dSjoff {
167e98c2a1dSjoff struct epclk_softc* sc;
168e98c2a1dSjoff
169e98c2a1dSjoff sc = epclk_sc;
170e98c2a1dSjoff
1717959c31aShamajima #if defined(HZ) && (HZ == 64)
172e98c2a1dSjoff bus_space_write_4(sc->sc_iot, sc->sc_teoi_ioh, 0, 1);
1737959c31aShamajima #else
1747959c31aShamajima bus_space_write_4(sc->sc_iot, sc->sc_ioh, EP93XX_TIMERS_Timer1Clear, 1);
1757959c31aShamajima #endif
176e98c2a1dSjoff hardclock((struct clockframe*) arg);
177e98c2a1dSjoff return (1);
178e98c2a1dSjoff }
179e98c2a1dSjoff
180e98c2a1dSjoff /*
181e98c2a1dSjoff * setstatclockrate:
182e98c2a1dSjoff *
183e98c2a1dSjoff * Set the rate of the statistics clock.
184e98c2a1dSjoff *
185e98c2a1dSjoff * We assume that hz is either stathz or profhz, and that neither
186e98c2a1dSjoff * will change after being set by cpu_initclocks(). We could
187e98c2a1dSjoff * recalculate the intervals here, but that would be a pain.
188e98c2a1dSjoff */
189e98c2a1dSjoff void
setstatclockrate(int newhz)19082ea600cShe setstatclockrate(int newhz)
191e98c2a1dSjoff {
192e98c2a1dSjoff
193e98c2a1dSjoff /* use hardclock */
194e98c2a1dSjoff }
195e98c2a1dSjoff
196e98c2a1dSjoff /*
197e98c2a1dSjoff * cpu_initclocks:
198e98c2a1dSjoff *
199e98c2a1dSjoff * Initialize the clock and get them going.
200e98c2a1dSjoff */
201e98c2a1dSjoff void
cpu_initclocks(void)202e98c2a1dSjoff cpu_initclocks(void)
203e98c2a1dSjoff {
204e98c2a1dSjoff struct epclk_softc* sc;
205e98c2a1dSjoff
206e98c2a1dSjoff sc = epclk_sc;
207e98c2a1dSjoff stathz = profhz = 0;
208e98c2a1dSjoff
2097959c31aShamajima #if defined(HZ) && (HZ == 64)
210e98c2a1dSjoff if (hz != 64) panic("HZ must be 64!");
211e98c2a1dSjoff
212e98c2a1dSjoff /* clear 64Hz interrupt status */
213e98c2a1dSjoff bus_space_write_4(sc->sc_iot, sc->sc_teoi_ioh, 0, 1);
2147959c31aShamajima #else
2157959c31aShamajima #define CLOCK_SOURCE_RATE 14745600UL
2167959c31aShamajima #define CLOCK_TICK_DIV 29
2177959c31aShamajima #define CLOCK_TICK_RATE \
2187959c31aShamajima (((CLOCK_SOURCE_RATE+(CLOCK_TICK_DIV*hz-1))/(CLOCK_TICK_DIV*hz))*hz)
2197959c31aShamajima #define LATCH ((CLOCK_TICK_RATE + hz/2) / hz)
2207959c31aShamajima /* setup and start the 16bit timer (Timer1) */
2217959c31aShamajima bus_space_write_4(sc->sc_iot, sc->sc_ioh,
2227959c31aShamajima EP93XX_TIMERS_Timer1Control,
2237959c31aShamajima (TimerControl_MODE)|(TimerControl_CLKSEL));
2247959c31aShamajima bus_space_write_4(sc->sc_iot, sc->sc_ioh,
2257959c31aShamajima EP93XX_TIMERS_Timer1Load, LATCH-1);
2267959c31aShamajima bus_space_write_4(sc->sc_iot, sc->sc_ioh,
2277959c31aShamajima EP93XX_TIMERS_Timer1Control,
2287959c31aShamajima (TimerControl_ENABLE)|(TimerControl_MODE)|(TimerControl_CLKSEL));
2297959c31aShamajima #endif
230e98c2a1dSjoff
231e98c2a1dSjoff ep93xx_intr_establish(sc->sc_intr, IPL_CLOCK, epclk_intr, NULL);
232e98c2a1dSjoff }
233e98c2a1dSjoff
234e98c2a1dSjoff /*
235e98c2a1dSjoff * delay:
236e98c2a1dSjoff *
237e98c2a1dSjoff * Delay for at least N microseconds.
238e98c2a1dSjoff */
239e98c2a1dSjoff void
delay(unsigned int n)2404e56cdd2Sjoerg delay(unsigned int n)
241e98c2a1dSjoff {
2424e56cdd2Sjoerg unsigned int cur_tick, initial_tick;
2434e56cdd2Sjoerg int remaining;
244e98c2a1dSjoff
245e98c2a1dSjoff #ifdef DEBUG
246e98c2a1dSjoff if (epclk_sc == NULL) {
247e98c2a1dSjoff printf("delay: called before start epclk\n");
248e98c2a1dSjoff return;
249e98c2a1dSjoff }
250e98c2a1dSjoff #endif
251e98c2a1dSjoff
2524e56cdd2Sjoerg /*
2534e56cdd2Sjoerg * Read the counter first, so that the rest of the setup overhead is
2544e56cdd2Sjoerg * counted.
2554e56cdd2Sjoerg */
2564e56cdd2Sjoerg initial_tick = TIMER4VAL();
2574e56cdd2Sjoerg
258abc88641Skenh US_TO_TIMER4VAL(n, remaining);
2594e56cdd2Sjoerg
2604e56cdd2Sjoerg while (remaining > 0) {
2614e56cdd2Sjoerg cur_tick = TIMER4VAL();
26287c715ebShamajima if (cur_tick >= initial_tick)
26387c715ebShamajima remaining -= cur_tick - initial_tick;
2644e56cdd2Sjoerg else
26587c715ebShamajima remaining -= UINT_MAX - initial_tick + cur_tick + 1;
2664e56cdd2Sjoerg initial_tick = cur_tick;
267e98c2a1dSjoff }
268e98c2a1dSjoff }
2694e56cdd2Sjoerg
2704e56cdd2Sjoerg static u_int
epclk_get_timecount(struct timecounter * tc)2714e56cdd2Sjoerg epclk_get_timecount(struct timecounter *tc)
2724e56cdd2Sjoerg {
2734e56cdd2Sjoerg return TIMER4VAL();
2744e56cdd2Sjoerg }
275