1 /* $Id: imx23_timrot.c,v 1.3 2013/10/07 17:36:40 matt 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 #include <sys/bus.h>
34 #include <sys/device.h>
35 #include <sys/errno.h>
36 #include <sys/systm.h>
37
38 #include <arm/pic/picvar.h>
39
40 #include <arm/imx/imx23_icollreg.h>
41 #include <arm/imx/imx23_timrotreg.h>
42 #include <arm/imx/imx23var.h>
43
44 extern int hz;
45 extern int stathz;
46
47 static int timrot_match(device_t, cfdata_t, void *);
48 static void timrot_attach(device_t, device_t, void *);
49 static int timrot_activate(device_t, enum devact);
50
51 static void timrot_reset(void);
52
53 /*
54 * Timer IRQ handler definitions.
55 */
56 static int systimer_irq(void *);
57 static int stattimer_irq(void *);
58
59 void cpu_initclocks(void);
60 void setstatclockrate(int);
61
62 /* Allocated for each timer instance. */
63 struct timrot_softc {
64 device_t sc_dev;
65 bus_space_tag_t sc_iot;
66 bus_space_handle_t sc_hdl;
67 int8_t sc_irq;
68 int (*irq_handler)(void *);
69 int freq;
70 };
71
72 static bus_space_tag_t timrot_iot;
73 static bus_space_handle_t timrot_hdl;
74
75 CFATTACH_DECL3_NEW(timrot,
76 sizeof(struct timrot_softc),
77 timrot_match,
78 timrot_attach,
79 NULL,
80 timrot_activate,
81 NULL,
82 NULL,
83 0);
84
85 #define MAX_TIMERS 4
86 #define SYS_TIMER 0
87 #define STAT_TIMER 1
88 #define SCHED_TIMER 2
89
90 struct timrot_softc *timer_sc[MAX_TIMERS];
91
92 static void timer_init(struct timrot_softc *);
93
94 #define TIMROT_SOFT_RST_LOOP 455 /* At least 1 us ... */
95 #define TIMROT_READ(reg) \
96 bus_space_read_4(timrot_iot, timrot_hdl, (reg))
97 #define TIMROT_WRITE(reg, val) \
98 bus_space_write_4(timrot_iot, timrot_hdl, (reg), (val))
99
100 #define TIMER_REGS_SIZE 0x20
101
102 #define TIMER_CTRL 0x00
103 #define TIMER_CTRL_SET 0x04
104 #define TIMER_CTRL_CLR 0x08
105 #define TIMER_CTRL_TOG 0x0C
106 #define TIMER_COUNT 0x10
107
108 #define TIMER_READ(sc, reg) \
109 bus_space_read_4(sc->sc_iot, sc->sc_hdl, (reg))
110 #define TIMER_WRITE(sc, reg, val) \
111 bus_space_write_4(sc->sc_iot, sc->sc_hdl, (reg), (val))
112 #define TIMER_WRITE_2(sc, reg, val) \
113 bus_space_write_2(sc->sc_iot, sc->sc_hdl, (reg), (val))
114
115 #define SELECT_32KHZ 0x8 /* Use 32kHz clock source. */
116 #define SOURCE_32KHZ_HZ 32000 /* Above source in Hz. */
117
118 #define IRQ HW_TIMROT_TIMCTRL0_IRQ
119 #define IRQ_EN HW_TIMROT_TIMCTRL0_IRQ_EN
120 #define UPDATE HW_TIMROT_TIMCTRL0_UPDATE
121 #define RELOAD HW_TIMROT_TIMCTRL0_RELOAD
122
123 static int
timrot_match(device_t parent,cfdata_t match,void * aux)124 timrot_match(device_t parent, cfdata_t match, void *aux)
125 {
126 struct apb_attach_args *aa = aux;
127
128 if ((aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL0
129 && aa->aa_size == TIMER_REGS_SIZE))
130 return 1;
131
132 if ((aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL1
133 && aa->aa_size == TIMER_REGS_SIZE))
134 return 1;
135
136 #if 0
137 if ((aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL2
138 && aa->aa_size == TIMER_REGS_SIZE))
139 return 1;
140
141 if ((aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL3
142 && aa->aa_size == TIMER_REGS_SIZE))
143 return 1;
144 #endif
145 return 0;
146 }
147
148 static void
timrot_attach(device_t parent,device_t self,void * aux)149 timrot_attach(device_t parent, device_t self, void *aux)
150 {
151 struct apb_attach_args *aa = aux;
152 struct timrot_softc *sc = device_private(self);
153 static int timrot_attached = 0;
154
155 if (!timrot_attached) {
156 timrot_iot = aa->aa_iot;
157 if (bus_space_map(timrot_iot, HW_TIMROT_BASE, HW_TIMROT_SIZE,
158 0, &timrot_hdl)) {
159 aprint_error_dev(sc->sc_dev,
160 "unable to map bus space\n");
161 return;
162 }
163 timrot_reset();
164 timrot_attached = 1;
165 }
166
167 if (aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL0
168 && aa->aa_size == TIMER_REGS_SIZE
169 && timer_sc[SYS_TIMER] == NULL) {
170 if (bus_space_subregion(timrot_iot, timrot_hdl,
171 HW_TIMROT_TIMCTRL0, TIMER_REGS_SIZE,
172 &sc->sc_hdl)) {
173 aprint_error_dev(sc->sc_dev,
174 "unable to map subregion\n");
175 return;
176 }
177
178 sc->sc_iot = aa->aa_iot;
179 sc->sc_irq = aa->aa_irq;
180 sc->irq_handler = &systimer_irq;
181 sc->freq = hz;
182
183 timer_sc[SYS_TIMER] = sc;
184
185 aprint_normal("\n");
186
187 } else if (aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL1
188 && aa->aa_size == TIMER_REGS_SIZE
189 && timer_sc[STAT_TIMER] == NULL) {
190 if (bus_space_subregion(timrot_iot, timrot_hdl,
191 HW_TIMROT_TIMCTRL1, TIMER_REGS_SIZE, &sc->sc_hdl)) {
192 aprint_error_dev(sc->sc_dev,
193 "unable to map subregion\n");
194 return;
195 }
196
197 sc->sc_iot = aa->aa_iot;
198 sc->sc_irq = aa->aa_irq;
199 sc->irq_handler = &stattimer_irq;
200 stathz = (hz>>1);
201 sc->freq = stathz;
202
203 timer_sc[STAT_TIMER] = sc;
204
205 aprint_normal("\n");
206 }
207
208 return;
209 }
210
211 static int
timrot_activate(device_t self,enum devact act)212 timrot_activate(device_t self, enum devact act)
213 {
214 return EOPNOTSUPP;
215 }
216
217 /*
218 * cpu_initclock is called once at the boot time.
219 */
220 void
cpu_initclocks(void)221 cpu_initclocks(void)
222 {
223 if (timer_sc[SYS_TIMER] != NULL)
224 timer_init(timer_sc[SYS_TIMER]);
225
226 if (timer_sc[STAT_TIMER] != NULL)
227 timer_init(timer_sc[STAT_TIMER]);
228
229 return;
230 }
231
232 /*
233 * Change statclock rate when profiling takes place.
234 */
235 void
setstatclockrate(int newhz)236 setstatclockrate(int newhz)
237 {
238 struct timrot_softc *sc = timer_sc[STAT_TIMER];
239 sc->freq = newhz;
240
241 TIMER_WRITE_2(sc, TIMER_COUNT,
242 __SHIFTIN(SOURCE_32KHZ_HZ / sc->freq - 1,
243 HW_TIMROT_TIMCOUNT0_FIXED_COUNT));
244
245 return;
246 }
247
248 /*
249 * Generic timer initialization function.
250 */
251 static void
timer_init(struct timrot_softc * sc)252 timer_init(struct timrot_softc *sc)
253 {
254 uint32_t ctrl;
255
256 TIMER_WRITE_2(sc, TIMER_COUNT,
257 __SHIFTIN(SOURCE_32KHZ_HZ / sc->freq - 1,
258 HW_TIMROT_TIMCOUNT0_FIXED_COUNT));
259 ctrl = IRQ_EN | UPDATE | RELOAD | SELECT_32KHZ;
260 TIMER_WRITE(sc, TIMER_CTRL, ctrl);
261
262 intr_establish(sc->sc_irq, IPL_SCHED, IST_LEVEL, sc->irq_handler, NULL);
263
264 return;
265 }
266
267 /*
268 * Timer IRQ handlers.
269 */
270 static int
systimer_irq(void * frame)271 systimer_irq(void *frame)
272 {
273 hardclock(frame);
274
275 TIMER_WRITE(timer_sc[SYS_TIMER], TIMER_CTRL_CLR, IRQ);
276
277 return 1;
278 }
279
280 static int
stattimer_irq(void * frame)281 stattimer_irq(void *frame)
282 {
283 statclock(frame);
284
285 TIMER_WRITE(timer_sc[STAT_TIMER], TIMER_CTRL_CLR, IRQ);
286
287 return 1;
288 }
289
290 /*
291 * Reset the TIMROT block.
292 *
293 * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
294 */
295 static void
timrot_reset(void)296 timrot_reset(void)
297 {
298 unsigned int loop;
299
300 /* Prepare for soft-reset by making sure that SFTRST is not currently
301 * asserted. Also clear CLKGATE so we can wait for its assertion below.
302 */
303 TIMROT_WRITE(HW_TIMROT_ROTCTRL_CLR, HW_TIMROT_ROTCTRL_SFTRST);
304
305 /* Wait at least a microsecond for SFTRST to deassert. */
306 loop = 0;
307 while ((TIMROT_READ(HW_TIMROT_ROTCTRL) & HW_TIMROT_ROTCTRL_SFTRST) ||
308 (loop < TIMROT_SOFT_RST_LOOP))
309 loop++;
310
311 /* Clear CLKGATE so we can wait for its assertion below. */
312 TIMROT_WRITE(HW_TIMROT_ROTCTRL_CLR, HW_TIMROT_ROTCTRL_CLKGATE);
313
314 /* Soft-reset the block. */
315 TIMROT_WRITE(HW_TIMROT_ROTCTRL_SET, HW_TIMROT_ROTCTRL_SFTRST);
316
317 /* Wait until clock is in the gated state. */
318 while (!(TIMROT_READ(HW_TIMROT_ROTCTRL) & HW_TIMROT_ROTCTRL_CLKGATE));
319
320 /* Bring block out of reset. */
321 TIMROT_WRITE(HW_TIMROT_ROTCTRL_CLR, HW_TIMROT_ROTCTRL_SFTRST);
322
323 loop = 0;
324 while ((TIMROT_READ(HW_TIMROT_ROTCTRL) & HW_TIMROT_ROTCTRL_SFTRST) ||
325 (loop < TIMROT_SOFT_RST_LOOP))
326 loop++;
327
328 TIMROT_WRITE(HW_TIMROT_ROTCTRL_CLR, HW_TIMROT_ROTCTRL_CLKGATE);
329 /* Wait until clock is in the NON-gated state. */
330 while (TIMROT_READ(HW_TIMROT_ROTCTRL) & HW_TIMROT_ROTCTRL_CLKGATE);
331
332 return;
333 }
334