1*482eef70Srin /* $NetBSD: imxclock.c,v 1.9 2020/05/29 12:30:38 rin Exp $ */
2554cfb29Sbsh /*
3554cfb29Sbsh * Copyright (c) 2009, 2010 Genetec corp. All rights reserved.
4554cfb29Sbsh * Written by Hashimoto Kenichi for Genetec corp.
5554cfb29Sbsh *
6554cfb29Sbsh * Redistribution and use in source and binary forms, with or without
7554cfb29Sbsh * modification, are permitted provided that the following conditions
8554cfb29Sbsh * are met:
9554cfb29Sbsh * 1. Redistributions of source code must retain the above copyright
10554cfb29Sbsh * notice, this list of conditions and the following disclaimer.
11554cfb29Sbsh * 2. Redistributions in binary form must reproduce the above copyright
12554cfb29Sbsh * notice, this list of conditions and the following disclaimer in the
13554cfb29Sbsh * documentation and/or other materials provided with the distribution.
14554cfb29Sbsh *
15554cfb29Sbsh * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``AS IS'' AND
16554cfb29Sbsh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17554cfb29Sbsh * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18554cfb29Sbsh * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORP.
19554cfb29Sbsh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20554cfb29Sbsh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21554cfb29Sbsh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22554cfb29Sbsh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23554cfb29Sbsh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24554cfb29Sbsh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25554cfb29Sbsh * POSSIBILITY OF SUCH DAMAGE.
26554cfb29Sbsh */
27554cfb29Sbsh
28554cfb29Sbsh /*
29554cfb29Sbsh * common part for i.MX31 and i.MX51
30554cfb29Sbsh */
31554cfb29Sbsh
322868f5bcShkenken #include <sys/cdefs.h>
33*482eef70Srin __KERNEL_RCSID(0, "$NetBSD: imxclock.c,v 1.9 2020/05/29 12:30:38 rin Exp $");
342868f5bcShkenken
352868f5bcShkenken #include "opt_imx.h"
362868f5bcShkenken
37554cfb29Sbsh #include <sys/param.h>
38554cfb29Sbsh #include <sys/systm.h>
39554cfb29Sbsh #include <sys/kernel.h>
40554cfb29Sbsh #include <sys/evcnt.h>
41554cfb29Sbsh #include <sys/atomic.h>
42825088edSmatt #include <sys/time.h>
43554cfb29Sbsh #include <sys/timetc.h>
44554cfb29Sbsh
45554cfb29Sbsh #include <sys/types.h>
46554cfb29Sbsh #include <sys/device.h>
47554cfb29Sbsh
48554cfb29Sbsh #include <machine/intr.h>
49ed9977b1Sdyoung #include <sys/bus.h>
50554cfb29Sbsh
51554cfb29Sbsh #include <arm/cpu.h>
52554cfb29Sbsh #include <arm/armreg.h>
53554cfb29Sbsh #include <arm/cpufunc.h>
54554cfb29Sbsh
55554cfb29Sbsh #include <arm/imx/imxclockvar.h>
56554cfb29Sbsh #include <arm/imx/imxepitreg.h>
57554cfb29Sbsh
58554cfb29Sbsh static u_int imx_epit_get_timecount(struct timecounter *);
59554cfb29Sbsh static int imxclock_intr(void *);
60554cfb29Sbsh
61554cfb29Sbsh static struct timecounter imx_epit_timecounter = {
62*482eef70Srin .tc_get_timecount = imx_epit_get_timecount,
63*482eef70Srin .tc_counter_mask = 0xffffffff,
64*482eef70Srin .tc_name = "epit",
65*482eef70Srin .tc_quality = 100,
66554cfb29Sbsh };
67554cfb29Sbsh
68554cfb29Sbsh static volatile uint32_t imxclock_base;
692868f5bcShkenken struct imxclock_softc *imxclock = NULL;
70825088edSmatt
71825088edSmatt void
cpu_initclocks(void)72825088edSmatt cpu_initclocks(void)
73825088edSmatt {
74554cfb29Sbsh uint32_t reg;
75056b7b23Sbsh u_int freq;
76554cfb29Sbsh
772868f5bcShkenken if (epit1_sc != NULL)
782868f5bcShkenken imxclock = epit1_sc;
792868f5bcShkenken else if (epit2_sc != NULL)
802868f5bcShkenken imxclock = epit2_sc;
812868f5bcShkenken else
82554cfb29Sbsh panic("%s: driver has not been initialized!", __FUNCTION__);
83554cfb29Sbsh
842868f5bcShkenken freq = imxclock_get_timerfreq(imxclock);
85554cfb29Sbsh imx_epit_timecounter.tc_frequency = freq;
86554cfb29Sbsh tc_init(&imx_epit_timecounter);
87554cfb29Sbsh
882868f5bcShkenken aprint_verbose_dev(imxclock->sc_dev,
89056b7b23Sbsh "timer clock frequency %d\n", freq);
90056b7b23Sbsh
912868f5bcShkenken imxclock->sc_reload_value = freq / hz - 1;
92554cfb29Sbsh
932868f5bcShkenken /* stop timers */
942868f5bcShkenken bus_space_write_4(imxclock->sc_iot, imxclock->sc_ioh, EPIT_EPITCR, 0);
95554cfb29Sbsh
96554cfb29Sbsh aprint_normal("clock: hz=%d stathz = %d\n", hz, stathz);
97554cfb29Sbsh
982868f5bcShkenken bus_space_write_4(imxclock->sc_iot, imxclock->sc_ioh, EPIT_EPITLR,
992868f5bcShkenken imxclock->sc_reload_value);
1002868f5bcShkenken bus_space_write_4(imxclock->sc_iot, imxclock->sc_ioh, EPIT_EPITCMPR, 0);
101554cfb29Sbsh
1022868f5bcShkenken reg = EPITCR_ENMOD | EPITCR_IOVW | EPITCR_RLD | imxclock->sc_clksrc;
1032868f5bcShkenken bus_space_write_4(imxclock->sc_iot, imxclock->sc_ioh,
104056b7b23Sbsh EPIT_EPITCR, reg);
105056b7b23Sbsh reg |= EPITCR_EN | EPITCR_OCIEN | EPITCR_WAITEN | EPITCR_DOZEN |
106056b7b23Sbsh EPITCR_STOPEN;
1072868f5bcShkenken bus_space_write_4(imxclock->sc_iot, imxclock->sc_ioh,
108056b7b23Sbsh EPIT_EPITCR, reg);
109554cfb29Sbsh
110574919ebShkenken imxclock->sc_ih = intr_establish(imxclock->sc_intr, IPL_CLOCK,
1119f15a74bSmatt IST_LEVEL, imxclock_intr, NULL);
112825088edSmatt }
113825088edSmatt
114825088edSmatt void
setstatclockrate(int schz)115825088edSmatt setstatclockrate(int schz)
116825088edSmatt {
117825088edSmatt }
118554cfb29Sbsh
119554cfb29Sbsh static int
imxclock_intr(void * arg)120554cfb29Sbsh imxclock_intr(void *arg)
121554cfb29Sbsh {
1222868f5bcShkenken struct imxclock_softc *sc = imxclock;
123554cfb29Sbsh
124554cfb29Sbsh bus_space_write_4(sc->sc_iot, sc->sc_ioh, EPIT_EPITSR, 1);
125554cfb29Sbsh atomic_add_32(&imxclock_base, sc->sc_reload_value);
126554cfb29Sbsh
127554cfb29Sbsh hardclock((struct clockframe *)arg);
128554cfb29Sbsh
129554cfb29Sbsh return 1;
130554cfb29Sbsh }
131554cfb29Sbsh
132554cfb29Sbsh u_int
imx_epit_get_timecount(struct timecounter * tc)133554cfb29Sbsh imx_epit_get_timecount(struct timecounter *tc)
134554cfb29Sbsh {
135554cfb29Sbsh uint32_t counter;
136554cfb29Sbsh uint32_t base;
137554cfb29Sbsh u_int oldirqstate;
138554cfb29Sbsh
139554cfb29Sbsh oldirqstate = disable_interrupts(I32_bit);
1402868f5bcShkenken counter = bus_space_read_4(imxclock->sc_iot, imxclock->sc_ioh, EPIT_EPITCNT);
141554cfb29Sbsh base = imxclock_base;
142554cfb29Sbsh restore_interrupts(oldirqstate);
143554cfb29Sbsh
144554cfb29Sbsh return base - counter;
145554cfb29Sbsh }
146