]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * IMX GPT Timer | |
3 | * | |
4 | * Copyright (c) 2008 OK Labs | |
5 | * Copyright (c) 2011 NICTA Pty Ltd | |
6 | * Originally written by Hans Jiang | |
7 | * Updated by Peter Chubb | |
8 | * Updated by Jean-Christophe Dubois <[email protected]> | |
9 | * | |
10 | * This code is licensed under GPL version 2 or later. See | |
11 | * the COPYING file in the top-level directory. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include "qemu/osdep.h" | |
16 | #include "hw/timer/imx_gpt.h" | |
17 | #include "qemu/main-loop.h" | |
18 | #include "qemu/log.h" | |
19 | ||
20 | #ifndef DEBUG_IMX_GPT | |
21 | #define DEBUG_IMX_GPT 0 | |
22 | #endif | |
23 | ||
24 | #define DPRINTF(fmt, args...) \ | |
25 | do { \ | |
26 | if (DEBUG_IMX_GPT) { \ | |
27 | fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPT, \ | |
28 | __func__, ##args); \ | |
29 | } \ | |
30 | } while (0) | |
31 | ||
32 | static const char *imx_gpt_reg_name(uint32_t reg) | |
33 | { | |
34 | switch (reg) { | |
35 | case 0: | |
36 | return "CR"; | |
37 | case 1: | |
38 | return "PR"; | |
39 | case 2: | |
40 | return "SR"; | |
41 | case 3: | |
42 | return "IR"; | |
43 | case 4: | |
44 | return "OCR1"; | |
45 | case 5: | |
46 | return "OCR2"; | |
47 | case 6: | |
48 | return "OCR3"; | |
49 | case 7: | |
50 | return "ICR1"; | |
51 | case 8: | |
52 | return "ICR2"; | |
53 | case 9: | |
54 | return "CNT"; | |
55 | default: | |
56 | return "[?]"; | |
57 | } | |
58 | } | |
59 | ||
60 | static const VMStateDescription vmstate_imx_timer_gpt = { | |
61 | .name = TYPE_IMX_GPT, | |
62 | .version_id = 3, | |
63 | .minimum_version_id = 3, | |
64 | .fields = (VMStateField[]) { | |
65 | VMSTATE_UINT32(cr, IMXGPTState), | |
66 | VMSTATE_UINT32(pr, IMXGPTState), | |
67 | VMSTATE_UINT32(sr, IMXGPTState), | |
68 | VMSTATE_UINT32(ir, IMXGPTState), | |
69 | VMSTATE_UINT32(ocr1, IMXGPTState), | |
70 | VMSTATE_UINT32(ocr2, IMXGPTState), | |
71 | VMSTATE_UINT32(ocr3, IMXGPTState), | |
72 | VMSTATE_UINT32(icr1, IMXGPTState), | |
73 | VMSTATE_UINT32(icr2, IMXGPTState), | |
74 | VMSTATE_UINT32(cnt, IMXGPTState), | |
75 | VMSTATE_UINT32(next_timeout, IMXGPTState), | |
76 | VMSTATE_UINT32(next_int, IMXGPTState), | |
77 | VMSTATE_UINT32(freq, IMXGPTState), | |
78 | VMSTATE_PTIMER(timer, IMXGPTState), | |
79 | VMSTATE_END_OF_LIST() | |
80 | } | |
81 | }; | |
82 | ||
83 | static const IMXClk imx25_gpt_clocks[] = { | |
84 | CLK_NONE, /* 000 No clock source */ | |
85 | CLK_IPG, /* 001 ipg_clk, 532MHz*/ | |
86 | CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ | |
87 | CLK_NONE, /* 011 not defined */ | |
88 | CLK_32k, /* 100 ipg_clk_32k */ | |
89 | CLK_32k, /* 101 ipg_clk_32k */ | |
90 | CLK_32k, /* 110 ipg_clk_32k */ | |
91 | CLK_32k, /* 111 ipg_clk_32k */ | |
92 | }; | |
93 | ||
94 | static const IMXClk imx31_gpt_clocks[] = { | |
95 | CLK_NONE, /* 000 No clock source */ | |
96 | CLK_IPG, /* 001 ipg_clk, 532MHz*/ | |
97 | CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ | |
98 | CLK_NONE, /* 011 not defined */ | |
99 | CLK_32k, /* 100 ipg_clk_32k */ | |
100 | CLK_NONE, /* 101 not defined */ | |
101 | CLK_NONE, /* 110 not defined */ | |
102 | CLK_NONE, /* 111 not defined */ | |
103 | }; | |
104 | ||
105 | static const IMXClk imx6_gpt_clocks[] = { | |
106 | CLK_NONE, /* 000 No clock source */ | |
107 | CLK_IPG, /* 001 ipg_clk, 532MHz*/ | |
108 | CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ | |
109 | CLK_EXT, /* 011 External clock */ | |
110 | CLK_32k, /* 100 ipg_clk_32k */ | |
111 | CLK_HIGH_DIV, /* 101 reference clock / 8 */ | |
112 | CLK_NONE, /* 110 not defined */ | |
113 | CLK_HIGH, /* 111 reference clock */ | |
114 | }; | |
115 | ||
116 | static const IMXClk imx7_gpt_clocks[] = { | |
117 | CLK_NONE, /* 000 No clock source */ | |
118 | CLK_IPG, /* 001 ipg_clk, 532MHz*/ | |
119 | CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ | |
120 | CLK_EXT, /* 011 External clock */ | |
121 | CLK_32k, /* 100 ipg_clk_32k */ | |
122 | CLK_HIGH, /* 101 reference clock */ | |
123 | CLK_NONE, /* 110 not defined */ | |
124 | CLK_NONE, /* 111 not defined */ | |
125 | }; | |
126 | ||
127 | static void imx_gpt_set_freq(IMXGPTState *s) | |
128 | { | |
129 | uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3); | |
130 | ||
131 | s->freq = imx_ccm_get_clock_frequency(s->ccm, | |
132 | s->clocks[clksrc]) / (1 + s->pr); | |
133 | ||
134 | DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, s->freq); | |
135 | ||
136 | if (s->freq) { | |
137 | ptimer_set_freq(s->timer, s->freq); | |
138 | } | |
139 | } | |
140 | ||
141 | static void imx_gpt_update_int(IMXGPTState *s) | |
142 | { | |
143 | if ((s->sr & s->ir) && (s->cr & GPT_CR_EN)) { | |
144 | qemu_irq_raise(s->irq); | |
145 | } else { | |
146 | qemu_irq_lower(s->irq); | |
147 | } | |
148 | } | |
149 | ||
150 | static uint32_t imx_gpt_update_count(IMXGPTState *s) | |
151 | { | |
152 | s->cnt = s->next_timeout - (uint32_t)ptimer_get_count(s->timer); | |
153 | ||
154 | return s->cnt; | |
155 | } | |
156 | ||
157 | static inline uint32_t imx_gpt_find_limit(uint32_t count, uint32_t reg, | |
158 | uint32_t timeout) | |
159 | { | |
160 | if ((count < reg) && (timeout > reg)) { | |
161 | timeout = reg; | |
162 | } | |
163 | ||
164 | return timeout; | |
165 | } | |
166 | ||
167 | static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event) | |
168 | { | |
169 | uint32_t timeout = GPT_TIMER_MAX; | |
170 | uint32_t count; | |
171 | long long limit; | |
172 | ||
173 | if (!(s->cr & GPT_CR_EN)) { | |
174 | /* if not enabled just return */ | |
175 | return; | |
176 | } | |
177 | ||
178 | /* update the count */ | |
179 | count = imx_gpt_update_count(s); | |
180 | ||
181 | if (event) { | |
182 | /* | |
183 | * This is an event (the ptimer reached 0 and stopped), and the | |
184 | * timer counter is now equal to s->next_timeout. | |
185 | */ | |
186 | if (!(s->cr & GPT_CR_FRR) && (count == s->ocr1)) { | |
187 | /* We are in restart mode and we crossed the compare channel 1 | |
188 | * value. We need to reset the counter to 0. | |
189 | */ | |
190 | count = s->cnt = s->next_timeout = 0; | |
191 | } else if (count == GPT_TIMER_MAX) { | |
192 | /* We reached GPT_TIMER_MAX so we need to rollover */ | |
193 | count = s->cnt = s->next_timeout = 0; | |
194 | } | |
195 | } | |
196 | ||
197 | /* now, find the next timeout related to count */ | |
198 | ||
199 | if (s->ir & GPT_IR_OF1IE) { | |
200 | timeout = imx_gpt_find_limit(count, s->ocr1, timeout); | |
201 | } | |
202 | if (s->ir & GPT_IR_OF2IE) { | |
203 | timeout = imx_gpt_find_limit(count, s->ocr2, timeout); | |
204 | } | |
205 | if (s->ir & GPT_IR_OF3IE) { | |
206 | timeout = imx_gpt_find_limit(count, s->ocr3, timeout); | |
207 | } | |
208 | ||
209 | /* find the next set of interrupts to raise for next timer event */ | |
210 | ||
211 | s->next_int = 0; | |
212 | if ((s->ir & GPT_IR_OF1IE) && (timeout == s->ocr1)) { | |
213 | s->next_int |= GPT_SR_OF1; | |
214 | } | |
215 | if ((s->ir & GPT_IR_OF2IE) && (timeout == s->ocr2)) { | |
216 | s->next_int |= GPT_SR_OF2; | |
217 | } | |
218 | if ((s->ir & GPT_IR_OF3IE) && (timeout == s->ocr3)) { | |
219 | s->next_int |= GPT_SR_OF3; | |
220 | } | |
221 | if ((s->ir & GPT_IR_ROVIE) && (timeout == GPT_TIMER_MAX)) { | |
222 | s->next_int |= GPT_SR_ROV; | |
223 | } | |
224 | ||
225 | /* the new range to count down from */ | |
226 | limit = timeout - imx_gpt_update_count(s); | |
227 | ||
228 | if (limit < 0) { | |
229 | /* | |
230 | * if we reach here, then QEMU is running too slow and we pass the | |
231 | * timeout limit while computing it. Let's deliver the interrupt | |
232 | * and compute a new limit. | |
233 | */ | |
234 | s->sr |= s->next_int; | |
235 | ||
236 | imx_gpt_compute_next_timeout(s, event); | |
237 | ||
238 | imx_gpt_update_int(s); | |
239 | } else { | |
240 | /* New timeout value */ | |
241 | s->next_timeout = timeout; | |
242 | ||
243 | /* reset the limit to the computed range */ | |
244 | ptimer_set_limit(s->timer, limit, 1); | |
245 | } | |
246 | } | |
247 | ||
248 | static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size) | |
249 | { | |
250 | IMXGPTState *s = IMX_GPT(opaque); | |
251 | uint32_t reg_value = 0; | |
252 | ||
253 | switch (offset >> 2) { | |
254 | case 0: /* Control Register */ | |
255 | reg_value = s->cr; | |
256 | break; | |
257 | ||
258 | case 1: /* prescaler */ | |
259 | reg_value = s->pr; | |
260 | break; | |
261 | ||
262 | case 2: /* Status Register */ | |
263 | reg_value = s->sr; | |
264 | break; | |
265 | ||
266 | case 3: /* Interrupt Register */ | |
267 | reg_value = s->ir; | |
268 | break; | |
269 | ||
270 | case 4: /* Output Compare Register 1 */ | |
271 | reg_value = s->ocr1; | |
272 | break; | |
273 | ||
274 | case 5: /* Output Compare Register 2 */ | |
275 | reg_value = s->ocr2; | |
276 | break; | |
277 | ||
278 | case 6: /* Output Compare Register 3 */ | |
279 | reg_value = s->ocr3; | |
280 | break; | |
281 | ||
282 | case 7: /* input Capture Register 1 */ | |
283 | qemu_log_mask(LOG_UNIMP, "[%s]%s: icr1 feature is not implemented\n", | |
284 | TYPE_IMX_GPT, __func__); | |
285 | reg_value = s->icr1; | |
286 | break; | |
287 | ||
288 | case 8: /* input Capture Register 2 */ | |
289 | qemu_log_mask(LOG_UNIMP, "[%s]%s: icr2 feature is not implemented\n", | |
290 | TYPE_IMX_GPT, __func__); | |
291 | reg_value = s->icr2; | |
292 | break; | |
293 | ||
294 | case 9: /* cnt */ | |
295 | imx_gpt_update_count(s); | |
296 | reg_value = s->cnt; | |
297 | break; | |
298 | ||
299 | default: | |
300 | qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" | |
301 | HWADDR_PRIx "\n", TYPE_IMX_GPT, __func__, offset); | |
302 | break; | |
303 | } | |
304 | ||
305 | DPRINTF("(%s) = 0x%08x\n", imx_gpt_reg_name(offset >> 2), reg_value); | |
306 | ||
307 | return reg_value; | |
308 | } | |
309 | ||
310 | ||
311 | static void imx_gpt_reset_common(IMXGPTState *s, bool is_soft_reset) | |
312 | { | |
313 | /* stop timer */ | |
314 | ptimer_stop(s->timer); | |
315 | ||
316 | /* Soft reset and hard reset differ only in their handling of the CR | |
317 | * register -- soft reset preserves the values of some bits there. | |
318 | */ | |
319 | if (is_soft_reset) { | |
320 | /* Clear all CR bits except those that are preserved by soft reset. */ | |
321 | s->cr &= GPT_CR_EN | GPT_CR_ENMOD | GPT_CR_STOPEN | GPT_CR_DOZEN | | |
322 | GPT_CR_WAITEN | GPT_CR_DBGEN | | |
323 | (GPT_CR_CLKSRC_MASK << GPT_CR_CLKSRC_SHIFT); | |
324 | } else { | |
325 | s->cr = 0; | |
326 | } | |
327 | s->sr = 0; | |
328 | s->pr = 0; | |
329 | s->ir = 0; | |
330 | s->cnt = 0; | |
331 | s->ocr1 = GPT_TIMER_MAX; | |
332 | s->ocr2 = GPT_TIMER_MAX; | |
333 | s->ocr3 = GPT_TIMER_MAX; | |
334 | s->icr1 = 0; | |
335 | s->icr2 = 0; | |
336 | ||
337 | s->next_timeout = GPT_TIMER_MAX; | |
338 | s->next_int = 0; | |
339 | ||
340 | /* compute new freq */ | |
341 | imx_gpt_set_freq(s); | |
342 | ||
343 | /* reset the limit to GPT_TIMER_MAX */ | |
344 | ptimer_set_limit(s->timer, GPT_TIMER_MAX, 1); | |
345 | ||
346 | /* if the timer is still enabled, restart it */ | |
347 | if (s->freq && (s->cr & GPT_CR_EN)) { | |
348 | ptimer_run(s->timer, 1); | |
349 | } | |
350 | } | |
351 | ||
352 | static void imx_gpt_soft_reset(DeviceState *dev) | |
353 | { | |
354 | IMXGPTState *s = IMX_GPT(dev); | |
355 | imx_gpt_reset_common(s, true); | |
356 | } | |
357 | ||
358 | static void imx_gpt_reset(DeviceState *dev) | |
359 | { | |
360 | IMXGPTState *s = IMX_GPT(dev); | |
361 | imx_gpt_reset_common(s, false); | |
362 | } | |
363 | ||
364 | static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, | |
365 | unsigned size) | |
366 | { | |
367 | IMXGPTState *s = IMX_GPT(opaque); | |
368 | uint32_t oldreg; | |
369 | ||
370 | DPRINTF("(%s, value = 0x%08x)\n", imx_gpt_reg_name(offset >> 2), | |
371 | (uint32_t)value); | |
372 | ||
373 | switch (offset >> 2) { | |
374 | case 0: | |
375 | oldreg = s->cr; | |
376 | s->cr = value & ~0x7c14; | |
377 | if (s->cr & GPT_CR_SWR) { /* force reset */ | |
378 | /* handle the reset */ | |
379 | imx_gpt_soft_reset(DEVICE(s)); | |
380 | } else { | |
381 | /* set our freq, as the source might have changed */ | |
382 | imx_gpt_set_freq(s); | |
383 | ||
384 | if ((oldreg ^ s->cr) & GPT_CR_EN) { | |
385 | if (s->cr & GPT_CR_EN) { | |
386 | if (s->cr & GPT_CR_ENMOD) { | |
387 | s->next_timeout = GPT_TIMER_MAX; | |
388 | ptimer_set_count(s->timer, GPT_TIMER_MAX); | |
389 | imx_gpt_compute_next_timeout(s, false); | |
390 | } | |
391 | ptimer_run(s->timer, 1); | |
392 | } else { | |
393 | /* stop timer */ | |
394 | ptimer_stop(s->timer); | |
395 | } | |
396 | } | |
397 | } | |
398 | break; | |
399 | ||
400 | case 1: /* Prescaler */ | |
401 | s->pr = value & 0xfff; | |
402 | imx_gpt_set_freq(s); | |
403 | break; | |
404 | ||
405 | case 2: /* SR */ | |
406 | s->sr &= ~(value & 0x3f); | |
407 | imx_gpt_update_int(s); | |
408 | break; | |
409 | ||
410 | case 3: /* IR -- interrupt register */ | |
411 | s->ir = value & 0x3f; | |
412 | imx_gpt_update_int(s); | |
413 | ||
414 | imx_gpt_compute_next_timeout(s, false); | |
415 | ||
416 | break; | |
417 | ||
418 | case 4: /* OCR1 -- output compare register */ | |
419 | s->ocr1 = value; | |
420 | ||
421 | /* In non-freerun mode, reset count when this register is written */ | |
422 | if (!(s->cr & GPT_CR_FRR)) { | |
423 | s->next_timeout = GPT_TIMER_MAX; | |
424 | ptimer_set_limit(s->timer, GPT_TIMER_MAX, 1); | |
425 | } | |
426 | ||
427 | /* compute the new timeout */ | |
428 | imx_gpt_compute_next_timeout(s, false); | |
429 | ||
430 | break; | |
431 | ||
432 | case 5: /* OCR2 -- output compare register */ | |
433 | s->ocr2 = value; | |
434 | ||
435 | /* compute the new timeout */ | |
436 | imx_gpt_compute_next_timeout(s, false); | |
437 | ||
438 | break; | |
439 | ||
440 | case 6: /* OCR3 -- output compare register */ | |
441 | s->ocr3 = value; | |
442 | ||
443 | /* compute the new timeout */ | |
444 | imx_gpt_compute_next_timeout(s, false); | |
445 | ||
446 | break; | |
447 | ||
448 | default: | |
449 | qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" | |
450 | HWADDR_PRIx "\n", TYPE_IMX_GPT, __func__, offset); | |
451 | break; | |
452 | } | |
453 | } | |
454 | ||
455 | static void imx_gpt_timeout(void *opaque) | |
456 | { | |
457 | IMXGPTState *s = IMX_GPT(opaque); | |
458 | ||
459 | DPRINTF("\n"); | |
460 | ||
461 | s->sr |= s->next_int; | |
462 | s->next_int = 0; | |
463 | ||
464 | imx_gpt_compute_next_timeout(s, true); | |
465 | ||
466 | imx_gpt_update_int(s); | |
467 | ||
468 | if (s->freq && (s->cr & GPT_CR_EN)) { | |
469 | ptimer_run(s->timer, 1); | |
470 | } | |
471 | } | |
472 | ||
473 | static const MemoryRegionOps imx_gpt_ops = { | |
474 | .read = imx_gpt_read, | |
475 | .write = imx_gpt_write, | |
476 | .endianness = DEVICE_NATIVE_ENDIAN, | |
477 | }; | |
478 | ||
479 | ||
480 | static void imx_gpt_realize(DeviceState *dev, Error **errp) | |
481 | { | |
482 | IMXGPTState *s = IMX_GPT(dev); | |
483 | SysBusDevice *sbd = SYS_BUS_DEVICE(dev); | |
484 | QEMUBH *bh; | |
485 | ||
486 | sysbus_init_irq(sbd, &s->irq); | |
487 | memory_region_init_io(&s->iomem, OBJECT(s), &imx_gpt_ops, s, TYPE_IMX_GPT, | |
488 | 0x00001000); | |
489 | sysbus_init_mmio(sbd, &s->iomem); | |
490 | ||
491 | bh = qemu_bh_new(imx_gpt_timeout, s); | |
492 | s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); | |
493 | } | |
494 | ||
495 | static void imx_gpt_class_init(ObjectClass *klass, void *data) | |
496 | { | |
497 | DeviceClass *dc = DEVICE_CLASS(klass); | |
498 | ||
499 | dc->realize = imx_gpt_realize; | |
500 | dc->reset = imx_gpt_reset; | |
501 | dc->vmsd = &vmstate_imx_timer_gpt; | |
502 | dc->desc = "i.MX general timer"; | |
503 | } | |
504 | ||
505 | static void imx25_gpt_init(Object *obj) | |
506 | { | |
507 | IMXGPTState *s = IMX_GPT(obj); | |
508 | ||
509 | s->clocks = imx25_gpt_clocks; | |
510 | } | |
511 | ||
512 | static void imx31_gpt_init(Object *obj) | |
513 | { | |
514 | IMXGPTState *s = IMX_GPT(obj); | |
515 | ||
516 | s->clocks = imx31_gpt_clocks; | |
517 | } | |
518 | ||
519 | static void imx6_gpt_init(Object *obj) | |
520 | { | |
521 | IMXGPTState *s = IMX_GPT(obj); | |
522 | ||
523 | s->clocks = imx6_gpt_clocks; | |
524 | } | |
525 | ||
526 | static void imx7_gpt_init(Object *obj) | |
527 | { | |
528 | IMXGPTState *s = IMX_GPT(obj); | |
529 | ||
530 | s->clocks = imx7_gpt_clocks; | |
531 | } | |
532 | ||
533 | static const TypeInfo imx25_gpt_info = { | |
534 | .name = TYPE_IMX25_GPT, | |
535 | .parent = TYPE_SYS_BUS_DEVICE, | |
536 | .instance_size = sizeof(IMXGPTState), | |
537 | .instance_init = imx25_gpt_init, | |
538 | .class_init = imx_gpt_class_init, | |
539 | }; | |
540 | ||
541 | static const TypeInfo imx31_gpt_info = { | |
542 | .name = TYPE_IMX31_GPT, | |
543 | .parent = TYPE_IMX25_GPT, | |
544 | .instance_init = imx31_gpt_init, | |
545 | }; | |
546 | ||
547 | static const TypeInfo imx6_gpt_info = { | |
548 | .name = TYPE_IMX6_GPT, | |
549 | .parent = TYPE_IMX25_GPT, | |
550 | .instance_init = imx6_gpt_init, | |
551 | }; | |
552 | ||
553 | static const TypeInfo imx7_gpt_info = { | |
554 | .name = TYPE_IMX7_GPT, | |
555 | .parent = TYPE_IMX25_GPT, | |
556 | .instance_init = imx7_gpt_init, | |
557 | }; | |
558 | ||
559 | static void imx_gpt_register_types(void) | |
560 | { | |
561 | type_register_static(&imx25_gpt_info); | |
562 | type_register_static(&imx31_gpt_info); | |
563 | type_register_static(&imx6_gpt_info); | |
564 | type_register_static(&imx7_gpt_info); | |
565 | } | |
566 | ||
567 | type_init(imx_gpt_register_types) |