imx23_timrot.c revision 1.5 1 /* $Id: imx23_timrot.c,v 1.5 2025/10/09 06:15:16 skrll Exp $ */
2
3 /*
4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Petri Laakso.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/param.h>
33
34 #include <sys/bus.h>
35 #include <sys/device.h>
36 #include <sys/errno.h>
37 #include <sys/systm.h>
38
39 #include <arm/imx/imx23_timrotreg.h>
40 #include <arm/imx/imx23_timrotvar.h>
41 #include <arm/imx/imx23var.h>
42
43 extern int hz;
44 extern int stathz;
45
46 static int timrot_match(device_t, cfdata_t, void *);
47 static void timrot_attach(device_t, device_t, void *);
48 static int timrot_activate(device_t, enum devact);
49
50 static int
51 timrot_init(struct timrot_softc *, bus_space_tag_t, bus_size_t, int8_t, int,
52 int (*)(void *));
53 static void timrot_reset(void);
54
55
56 void cpu_initclocks(void);
57 void setstatclockrate(int);
58
59 static bus_space_tag_t timrot_iot;
60 static bus_space_handle_t timrot_hdl;
61
62
63 CFATTACH_DECL3_NEW(imx23timrot,
64 sizeof(struct timrot_softc),
65 timrot_match,
66 timrot_attach,
67 NULL,
68 timrot_activate,
69 NULL,
70 NULL,
71 0);
72
73 #define MAX_TIMERS 4
74 #define SYS_TIMER 0
75 #define STAT_TIMER 1
76 #define SCHED_TIMER 2
77
78 struct timrot_softc *timer_sc[MAX_TIMERS];
79
80 static void timer_start(struct timrot_softc *);
81
82 #define TIMROT_SOFT_RST_LOOP 455 /* At least 1 us ... */
83 #define TIMROT_READ(reg) \
84 bus_space_read_4(timrot_iot, timrot_hdl, (reg))
85 #define TIMROT_WRITE(reg, val) \
86 bus_space_write_4(timrot_iot, timrot_hdl, (reg), (val))
87
88 #define TIMER_REGS_SIZE 0x20
89
90 #define TIMER_CTRL 0x00
91 #define TIMER_CTRL_SET 0x04
92 #define TIMER_CTRL_CLR 0x08
93 #define TIMER_CTRL_TOG 0x0C
94 #define TIMER_COUNT 0x10
95
96 #define TIMER_READ(sc, reg) \
97 bus_space_read_4(sc->sc_iot, sc->sc_hdl, (reg))
98 #define TIMER_WRITE(sc, reg, val) \
99 bus_space_write_4(sc->sc_iot, sc->sc_hdl, (reg), (val))
100 #define TIMER_WRITE_2(sc, reg, val) \
101 bus_space_write_2(sc->sc_iot, sc->sc_hdl, (reg), (val))
102
103 #define SELECT_32KHZ 0x8 /* Use 32kHz clock source. */
104 #define SOURCE_32KHZ_HZ 32000 /* Above source in Hz. */
105
106 #define IRQ HW_TIMROT_TIMCTRL0_IRQ
107 #define IRQ_EN HW_TIMROT_TIMCTRL0_IRQ_EN
108 #define UPDATE HW_TIMROT_TIMCTRL0_UPDATE
109 #define RELOAD HW_TIMROT_TIMCTRL0_RELOAD
110
111 static int
112 timrot_match(device_t parent, cfdata_t match, void *aux)
113 {
114 struct apb_attach_args *aa = aux;
115
116 if ((aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL0
117 && aa->aa_size == TIMER_REGS_SIZE))
118 return 1;
119
120 if ((aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL1
121 && aa->aa_size == TIMER_REGS_SIZE))
122 return 1;
123
124 #if 0
125 if ((aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL2
126 && aa->aa_size == TIMER_REGS_SIZE))
127 return 1;
128
129 if ((aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL3
130 && aa->aa_size == TIMER_REGS_SIZE))
131 return 1;
132 #endif
133 return 0;
134 }
135
136 static void
137 timrot_attach(device_t parent, device_t self, void *aux)
138 {
139 struct apb_attach_args *aa = aux;
140 struct timrot_softc *sc = device_private(self);
141
142 if (aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL0
143 && aa->aa_size == TIMER_REGS_SIZE
144 && timer_sc[SYS_TIMER] == NULL) {
145 imx23timrot_systimer_init(sc, aa->aa_iot, aa->aa_irq);
146
147 aprint_normal("\n");
148
149 } else if (aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL1
150 && aa->aa_size == TIMER_REGS_SIZE
151 && timer_sc[STAT_TIMER] == NULL) {
152 imx23timrot_stattimer_init(sc, aa->aa_iot, aa->aa_irq);
153
154 aprint_normal("\n");
155 }
156
157 return;
158 }
159
160 /*
161 * Initiates initialization of the systimer
162 */
163 int
164 imx23timrot_systimer_init(struct timrot_softc *sc, bus_space_tag_t iot,
165 int8_t irq)
166 {
167 int status;
168
169 status = timrot_init(sc, iot, HW_TIMROT_TIMCTRL0, irq, hz,
170 &imx23timrot_systimer_irq);
171 timer_sc[SYS_TIMER] = sc;
172
173 return status;
174 }
175
176 /*
177 * Initiates initialization of the stattimer
178 */
179 int
180 imx23timrot_stattimer_init(struct timrot_softc *sc, bus_space_tag_t iot,
181 int8_t irq)
182 {
183 int status;
184
185 stathz = (hz>>1);
186 status = timrot_init(sc, iot, HW_TIMROT_TIMCTRL1, irq, hz,
187 &imx23timrot_stattimer_irq);
188 timer_sc[STAT_TIMER] = sc;
189
190 return status;
191 }
192
193
194 /*
195 * Generic initialization code for a timer
196 */
197 static int
198 timrot_init(struct timrot_softc *sc, bus_space_tag_t iot,
199 bus_size_t timctrl_reg, int8_t irq, int freq,
200 int (*handler)(void *))
201 {
202 static int timrot_attached = 0;
203
204 if (!timrot_attached) {
205 timrot_iot = iot;
206 if (bus_space_map(timrot_iot, HW_TIMROT_BASE, HW_TIMROT_SIZE, 0,
207 &timrot_hdl)) {
208 aprint_error_dev(sc->sc_dev,
209 "unable to map bus space\n");
210 return 1;
211 }
212 timrot_reset();
213 timrot_attached = 1;
214 }
215
216 if (bus_space_subregion(timrot_iot, timrot_hdl, timctrl_reg,
217 TIMER_REGS_SIZE, &sc->sc_hdl)) {
218 aprint_error_dev(sc->sc_dev, "unable to map subregion\n");
219 return 1;
220 }
221
222 sc->sc_iot = iot;
223 sc->sc_irq = irq;
224 sc->irq_handler = handler;
225 sc->freq = freq;
226
227 return 0;
228 }
229
230 static int
231 timrot_activate(device_t self, enum devact act)
232 {
233 return EOPNOTSUPP;
234 }
235
236 /*
237 * imx23timrot_cpu_initclocks is called once at the boot time. It actually
238 * starts the timers.
239 */
240 void
241 imx23timrot_cpu_initclocks(void)
242 {
243 if (timer_sc[SYS_TIMER] != NULL)
244 timer_start(timer_sc[SYS_TIMER]);
245
246 if (timer_sc[STAT_TIMER] != NULL)
247 timer_start(timer_sc[STAT_TIMER]);
248
249 return;
250 }
251
252 /*
253 * Change statclock rate when profiling takes place.
254 */
255 void
256 setstatclockrate(int newhz)
257 {
258 struct timrot_softc *sc = timer_sc[STAT_TIMER];
259 sc->freq = newhz;
260
261 TIMER_WRITE_2(sc, TIMER_COUNT,
262 __SHIFTIN(SOURCE_32KHZ_HZ / sc->freq - 1,
263 HW_TIMROT_TIMCOUNT0_FIXED_COUNT));
264
265 return;
266 }
267
268 /*
269 * Generic function to actually start the timer
270 */
271 static void
272 timer_start(struct timrot_softc *sc)
273 {
274 uint32_t ctrl;
275
276 TIMER_WRITE_2(sc, TIMER_COUNT,
277 __SHIFTIN(SOURCE_32KHZ_HZ / sc->freq - 1,
278 HW_TIMROT_TIMCOUNT0_FIXED_COUNT));
279 ctrl = IRQ_EN | UPDATE | RELOAD | SELECT_32KHZ;
280 TIMER_WRITE(sc, TIMER_CTRL, ctrl);
281
282 if(sc->sc_irq != -1) {
283 intr_establish(sc->sc_irq, IPL_SCHED, IST_LEVEL,
284 sc->irq_handler, NULL);
285 }
286
287 return;
288 }
289
290 /*
291 * Timer IRQ handlers.
292 */
293 int
294 imx23timrot_systimer_irq(void *frame)
295 {
296 hardclock(frame);
297
298 TIMER_WRITE(timer_sc[SYS_TIMER], TIMER_CTRL_CLR, IRQ);
299
300 return 1;
301 }
302
303 int
304 imx23timrot_stattimer_irq(void *frame)
305 {
306 statclock(frame);
307
308 TIMER_WRITE(timer_sc[STAT_TIMER], TIMER_CTRL_CLR, IRQ);
309
310 return 1;
311 }
312
313 /*
314 * Reset the TIMROT block.
315 *
316 * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
317 */
318 static void
319 timrot_reset(void)
320 {
321 unsigned int loop;
322
323 /* Prepare for soft-reset by making sure that SFTRST is not currently
324 * asserted. Also clear CLKGATE so we can wait for its assertion below.
325 */
326 TIMROT_WRITE(HW_TIMROT_ROTCTRL_CLR, HW_TIMROT_ROTCTRL_SFTRST);
327
328 /* Wait at least a microsecond for SFTRST to deassert. */
329 loop = 0;
330 while ((TIMROT_READ(HW_TIMROT_ROTCTRL) & HW_TIMROT_ROTCTRL_SFTRST) ||
331 (loop < TIMROT_SOFT_RST_LOOP))
332 loop++;
333
334 /* Clear CLKGATE so we can wait for its assertion below. */
335 TIMROT_WRITE(HW_TIMROT_ROTCTRL_CLR, HW_TIMROT_ROTCTRL_CLKGATE);
336
337 /* Soft-reset the block. */
338 TIMROT_WRITE(HW_TIMROT_ROTCTRL_SET, HW_TIMROT_ROTCTRL_SFTRST);
339
340 /* Wait until clock is in the gated state. */
341 while (!(TIMROT_READ(HW_TIMROT_ROTCTRL) & HW_TIMROT_ROTCTRL_CLKGATE));
342
343 /* Bring block out of reset. */
344 TIMROT_WRITE(HW_TIMROT_ROTCTRL_CLR, HW_TIMROT_ROTCTRL_SFTRST);
345
346 loop = 0;
347 while ((TIMROT_READ(HW_TIMROT_ROTCTRL) & HW_TIMROT_ROTCTRL_SFTRST) ||
348 (loop < TIMROT_SOFT_RST_LOOP))
349 loop++;
350
351 TIMROT_WRITE(HW_TIMROT_ROTCTRL_CLR, HW_TIMROT_ROTCTRL_CLKGATE);
352 /* Wait until clock is in the NON-gated state. */
353 while (TIMROT_READ(HW_TIMROT_ROTCTRL) & HW_TIMROT_ROTCTRL_CLKGATE);
354
355 return;
356 }
357