]>
Commit | Line | Data |
---|---|---|
78d1404d PC |
1 | /* |
2 | * IMX31 Timer | |
3 | * | |
4 | * Copyright (c) 2008 OK Labs | |
5 | * Copyright (c) 2011 NICTA Pty Ltd | |
aade7b91 | 6 | * Originally written by Hans Jiang |
78d1404d PC |
7 | * Updated by Peter Chubb |
8 | * | |
aade7b91 | 9 | * This code is licensed under GPL version 2 or later. See |
78d1404d PC |
10 | * the COPYING file in the top-level directory. |
11 | * | |
12 | */ | |
13 | ||
14 | #include "hw.h" | |
1de7afc9 | 15 | #include "qemu/timer.h" |
78d1404d PC |
16 | #include "ptimer.h" |
17 | #include "sysbus.h" | |
18 | #include "imx.h" | |
19 | ||
20 | //#define DEBUG_TIMER 1 | |
21 | #ifdef DEBUG_TIMER | |
22 | # define DPRINTF(fmt, args...) \ | |
23 | do { printf("imx_timer: " fmt , ##args); } while (0) | |
24 | #else | |
25 | # define DPRINTF(fmt, args...) do {} while (0) | |
26 | #endif | |
27 | ||
28 | /* | |
29 | * Define to 1 for messages about attempts to | |
30 | * access unimplemented registers or similar. | |
31 | */ | |
32 | #define DEBUG_IMPLEMENTATION 1 | |
33 | #if DEBUG_IMPLEMENTATION | |
34 | # define IPRINTF(fmt, args...) \ | |
35 | do { fprintf(stderr, "imx_timer: " fmt, ##args); } while (0) | |
36 | #else | |
37 | # define IPRINTF(fmt, args...) do {} while (0) | |
38 | #endif | |
39 | ||
40 | /* | |
41 | * GPT : General purpose timer | |
42 | * | |
43 | * This timer counts up continuously while it is enabled, resetting itself | |
44 | * to 0 when it reaches TIMER_MAX (in freerun mode) or when it | |
45 | * reaches the value of ocr1 (in periodic mode). WE simulate this using a | |
46 | * QEMU ptimer counting down from ocr1 and reloading from ocr1 in | |
47 | * periodic mode, or counting from ocr1 to zero, then TIMER_MAX - ocr1. | |
48 | * waiting_rov is set when counting from TIMER_MAX. | |
49 | * | |
50 | * In the real hardware, there are three comparison registers that can | |
51 | * trigger interrupts, and compare channel 1 can be used to | |
52 | * force-reset the timer. However, this is a `bare-bones' | |
53 | * implementation: only what Linux 3.x uses has been implemented | |
54 | * (free-running timer from 0 to OCR1 or TIMER_MAX) . | |
55 | */ | |
56 | ||
57 | ||
58 | #define TIMER_MAX 0XFFFFFFFFUL | |
59 | ||
60 | /* Control register. Not all of these bits have any effect (yet) */ | |
61 | #define GPT_CR_EN (1 << 0) /* GPT Enable */ | |
62 | #define GPT_CR_ENMOD (1 << 1) /* GPT Enable Mode */ | |
63 | #define GPT_CR_DBGEN (1 << 2) /* GPT Debug mode enable */ | |
64 | #define GPT_CR_WAITEN (1 << 3) /* GPT Wait Mode Enable */ | |
65 | #define GPT_CR_DOZEN (1 << 4) /* GPT Doze mode enable */ | |
66 | #define GPT_CR_STOPEN (1 << 5) /* GPT Stop Mode Enable */ | |
67 | #define GPT_CR_CLKSRC_SHIFT (6) | |
68 | #define GPT_CR_CLKSRC_MASK (0x7) | |
69 | ||
70 | #define GPT_CR_FRR (1 << 9) /* Freerun or Restart */ | |
71 | #define GPT_CR_SWR (1 << 15) /* Software Reset */ | |
72 | #define GPT_CR_IM1 (3 << 16) /* Input capture channel 1 mode (2 bits) */ | |
73 | #define GPT_CR_IM2 (3 << 18) /* Input capture channel 2 mode (2 bits) */ | |
74 | #define GPT_CR_OM1 (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */ | |
75 | #define GPT_CR_OM2 (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */ | |
76 | #define GPT_CR_OM3 (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */ | |
77 | #define GPT_CR_FO1 (1 << 29) /* Force Output Compare Channel 1 */ | |
78 | #define GPT_CR_FO2 (1 << 30) /* Force Output Compare Channel 2 */ | |
79 | #define GPT_CR_FO3 (1 << 31) /* Force Output Compare Channel 3 */ | |
80 | ||
81 | #define GPT_SR_OF1 (1 << 0) | |
82 | #define GPT_SR_ROV (1 << 5) | |
83 | ||
84 | #define GPT_IR_OF1IE (1 << 0) | |
85 | #define GPT_IR_ROVIE (1 << 5) | |
86 | ||
87 | typedef struct { | |
88 | SysBusDevice busdev; | |
89 | ptimer_state *timer; | |
90 | MemoryRegion iomem; | |
91 | DeviceState *ccm; | |
92 | ||
93 | uint32_t cr; | |
94 | uint32_t pr; | |
95 | uint32_t sr; | |
96 | uint32_t ir; | |
97 | uint32_t ocr1; | |
98 | uint32_t cnt; | |
99 | ||
100 | uint32_t waiting_rov; | |
101 | qemu_irq irq; | |
102 | } IMXTimerGState; | |
103 | ||
104 | static const VMStateDescription vmstate_imx_timerg = { | |
105 | .name = "imx-timerg", | |
106 | .version_id = 1, | |
107 | .minimum_version_id = 1, | |
108 | .minimum_version_id_old = 1, | |
109 | .fields = (VMStateField[]) { | |
110 | VMSTATE_UINT32(cr, IMXTimerGState), | |
111 | VMSTATE_UINT32(pr, IMXTimerGState), | |
112 | VMSTATE_UINT32(sr, IMXTimerGState), | |
113 | VMSTATE_UINT32(ir, IMXTimerGState), | |
114 | VMSTATE_UINT32(ocr1, IMXTimerGState), | |
115 | VMSTATE_UINT32(cnt, IMXTimerGState), | |
116 | VMSTATE_UINT32(waiting_rov, IMXTimerGState), | |
117 | VMSTATE_PTIMER(timer, IMXTimerGState), | |
118 | VMSTATE_END_OF_LIST() | |
119 | } | |
120 | }; | |
121 | ||
122 | static const IMXClk imx_timerg_clocks[] = { | |
123 | NOCLK, /* 000 No clock source */ | |
124 | IPG, /* 001 ipg_clk, 532MHz*/ | |
125 | IPG, /* 010 ipg_clk_highfreq */ | |
126 | NOCLK, /* 011 not defined */ | |
127 | CLK_32k, /* 100 ipg_clk_32k */ | |
128 | NOCLK, /* 101 not defined */ | |
129 | NOCLK, /* 110 not defined */ | |
130 | NOCLK, /* 111 not defined */ | |
131 | }; | |
132 | ||
133 | ||
134 | static void imx_timerg_set_freq(IMXTimerGState *s) | |
135 | { | |
136 | int clksrc; | |
137 | uint32_t freq; | |
138 | ||
139 | clksrc = (s->cr >> GPT_CR_CLKSRC_SHIFT) & GPT_CR_CLKSRC_MASK; | |
140 | freq = imx_clock_frequency(s->ccm, imx_timerg_clocks[clksrc]) / (1 + s->pr); | |
141 | ||
142 | DPRINTF("Setting gtimer clksrc %d to frequency %d\n", clksrc, freq); | |
143 | if (freq) { | |
144 | ptimer_set_freq(s->timer, freq); | |
145 | } | |
146 | } | |
147 | ||
148 | static void imx_timerg_update(IMXTimerGState *s) | |
149 | { | |
150 | uint32_t flags = s->sr & s->ir & (GPT_SR_OF1 | GPT_SR_ROV); | |
151 | ||
152 | DPRINTF("g-timer SR: %s %s IR=%s %s, %s\n", | |
153 | s->sr & GPT_SR_OF1 ? "OF1" : "", | |
154 | s->sr & GPT_SR_ROV ? "ROV" : "", | |
155 | s->ir & GPT_SR_OF1 ? "OF1" : "", | |
156 | s->ir & GPT_SR_ROV ? "ROV" : "", | |
157 | s->cr & GPT_CR_EN ? "CR_EN" : "Not Enabled"); | |
158 | ||
159 | ||
160 | qemu_set_irq(s->irq, (s->cr & GPT_CR_EN) && flags); | |
161 | } | |
162 | ||
163 | static uint32_t imx_timerg_update_counts(IMXTimerGState *s) | |
164 | { | |
165 | uint64_t target = s->waiting_rov ? TIMER_MAX : s->ocr1; | |
166 | uint64_t cnt = ptimer_get_count(s->timer); | |
167 | s->cnt = target - cnt; | |
168 | return s->cnt; | |
169 | } | |
170 | ||
171 | static void imx_timerg_reload(IMXTimerGState *s, uint32_t timeout) | |
172 | { | |
173 | uint64_t diff_cnt; | |
174 | ||
175 | if (!(s->cr & GPT_CR_FRR)) { | |
176 | IPRINTF("IMX_timerg_reload --- called in reset-mode\n"); | |
177 | return; | |
178 | } | |
179 | ||
180 | /* | |
181 | * For small timeouts, qemu sometimes runs too slow. | |
182 | * Better deliver a late interrupt than none. | |
183 | * | |
184 | * In Reset mode (FRR bit clear) | |
185 | * the ptimer reloads itself from OCR1; | |
186 | * in free-running mode we need to fake | |
187 | * running from 0 to ocr1 to TIMER_MAX | |
188 | */ | |
189 | if (timeout > s->cnt) { | |
190 | diff_cnt = timeout - s->cnt; | |
191 | } else { | |
192 | diff_cnt = 0; | |
193 | } | |
194 | ptimer_set_count(s->timer, diff_cnt); | |
195 | } | |
196 | ||
a8170e5e | 197 | static uint64_t imx_timerg_read(void *opaque, hwaddr offset, |
78d1404d PC |
198 | unsigned size) |
199 | { | |
200 | IMXTimerGState *s = (IMXTimerGState *)opaque; | |
201 | ||
202 | DPRINTF("g-read(offset=%x)", offset >> 2); | |
203 | switch (offset >> 2) { | |
204 | case 0: /* Control Register */ | |
205 | DPRINTF(" cr = %x\n", s->cr); | |
206 | return s->cr; | |
207 | ||
208 | case 1: /* prescaler */ | |
209 | DPRINTF(" pr = %x\n", s->pr); | |
210 | return s->pr; | |
211 | ||
212 | case 2: /* Status Register */ | |
213 | DPRINTF(" sr = %x\n", s->sr); | |
214 | return s->sr; | |
215 | ||
216 | case 3: /* Interrupt Register */ | |
217 | DPRINTF(" ir = %x\n", s->ir); | |
218 | return s->ir; | |
219 | ||
220 | case 4: /* Output Compare Register 1 */ | |
221 | DPRINTF(" ocr1 = %x\n", s->ocr1); | |
222 | return s->ocr1; | |
223 | ||
224 | ||
225 | case 9: /* cnt */ | |
226 | imx_timerg_update_counts(s); | |
227 | DPRINTF(" cnt = %x\n", s->cnt); | |
228 | return s->cnt; | |
229 | } | |
230 | ||
231 | IPRINTF("imx_timerg_read: Bad offset %x\n", | |
232 | (int)offset >> 2); | |
233 | return 0; | |
234 | } | |
235 | ||
236 | static void imx_timerg_reset(DeviceState *dev) | |
237 | { | |
238 | IMXTimerGState *s = container_of(dev, IMXTimerGState, busdev.qdev); | |
239 | ||
240 | /* | |
241 | * Soft reset doesn't touch some bits; hard reset clears them | |
242 | */ | |
243 | s->cr &= ~(GPT_CR_EN|GPT_CR_DOZEN|GPT_CR_WAITEN|GPT_CR_DBGEN); | |
244 | s->sr = 0; | |
245 | s->pr = 0; | |
246 | s->ir = 0; | |
247 | s->cnt = 0; | |
248 | s->ocr1 = TIMER_MAX; | |
249 | ptimer_stop(s->timer); | |
250 | ptimer_set_limit(s->timer, TIMER_MAX, 1); | |
251 | imx_timerg_set_freq(s); | |
252 | } | |
253 | ||
a8170e5e | 254 | static void imx_timerg_write(void *opaque, hwaddr offset, |
78d1404d PC |
255 | uint64_t value, unsigned size) |
256 | { | |
257 | IMXTimerGState *s = (IMXTimerGState *)opaque; | |
258 | DPRINTF("g-write(offset=%x, value = 0x%x)\n", (unsigned int)offset >> 2, | |
259 | (unsigned int)value); | |
260 | ||
261 | switch (offset >> 2) { | |
262 | case 0: { | |
263 | uint32_t oldcr = s->cr; | |
264 | /* CR */ | |
265 | if (value & GPT_CR_SWR) { /* force reset */ | |
266 | value &= ~GPT_CR_SWR; | |
267 | imx_timerg_reset(&s->busdev.qdev); | |
268 | imx_timerg_update(s); | |
269 | } | |
270 | ||
271 | s->cr = value & ~0x7c00; | |
272 | imx_timerg_set_freq(s); | |
273 | if ((oldcr ^ value) & GPT_CR_EN) { | |
274 | if (value & GPT_CR_EN) { | |
275 | if (value & GPT_CR_ENMOD) { | |
276 | ptimer_set_count(s->timer, s->ocr1); | |
277 | s->cnt = 0; | |
278 | } | |
279 | ptimer_run(s->timer, | |
280 | (value & GPT_CR_FRR) && (s->ocr1 != TIMER_MAX)); | |
281 | } else { | |
282 | ptimer_stop(s->timer); | |
283 | }; | |
284 | } | |
285 | return; | |
286 | } | |
287 | ||
288 | case 1: /* Prescaler */ | |
289 | s->pr = value & 0xfff; | |
290 | imx_timerg_set_freq(s); | |
291 | return; | |
292 | ||
293 | case 2: /* SR */ | |
294 | /* | |
295 | * No point in implementing the status register bits to do with | |
296 | * external interrupt sources. | |
297 | */ | |
298 | value &= GPT_SR_OF1 | GPT_SR_ROV; | |
299 | s->sr &= ~value; | |
300 | imx_timerg_update(s); | |
301 | return; | |
302 | ||
303 | case 3: /* IR -- interrupt register */ | |
304 | s->ir = value & 0x3f; | |
305 | imx_timerg_update(s); | |
306 | return; | |
307 | ||
308 | case 4: /* OCR1 -- output compare register */ | |
309 | /* In non-freerun mode, reset count when this register is written */ | |
310 | if (!(s->cr & GPT_CR_FRR)) { | |
311 | s->waiting_rov = 0; | |
312 | ptimer_set_limit(s->timer, value, 1); | |
313 | } else { | |
314 | imx_timerg_update_counts(s); | |
315 | if (value > s->cnt) { | |
316 | s->waiting_rov = 0; | |
317 | imx_timerg_reload(s, value); | |
318 | } else { | |
319 | s->waiting_rov = 1; | |
320 | imx_timerg_reload(s, TIMER_MAX - s->cnt); | |
321 | } | |
322 | } | |
323 | s->ocr1 = value; | |
324 | return; | |
325 | ||
326 | default: | |
327 | IPRINTF("imx_timerg_write: Bad offset %x\n", | |
328 | (int)offset >> 2); | |
329 | } | |
330 | } | |
331 | ||
332 | static void imx_timerg_timeout(void *opaque) | |
333 | { | |
334 | IMXTimerGState *s = (IMXTimerGState *)opaque; | |
335 | ||
336 | DPRINTF("imx_timerg_timeout, waiting rov=%d\n", s->waiting_rov); | |
337 | if (s->cr & GPT_CR_FRR) { | |
338 | /* | |
339 | * Free running timer from 0 -> TIMERMAX | |
340 | * Generates interrupt at TIMER_MAX and at cnt==ocr1 | |
341 | * If ocr1 == TIMER_MAX, then no need to reload timer. | |
342 | */ | |
343 | if (s->ocr1 == TIMER_MAX) { | |
344 | DPRINTF("s->ocr1 == TIMER_MAX, FRR\n"); | |
345 | s->sr |= GPT_SR_OF1 | GPT_SR_ROV; | |
346 | imx_timerg_update(s); | |
347 | return; | |
348 | } | |
349 | ||
350 | if (s->waiting_rov) { | |
351 | /* | |
352 | * We were waiting for cnt==TIMER_MAX | |
353 | */ | |
354 | s->sr |= GPT_SR_ROV; | |
355 | s->waiting_rov = 0; | |
356 | s->cnt = 0; | |
357 | imx_timerg_reload(s, s->ocr1); | |
358 | } else { | |
359 | /* Must have got a cnt==ocr1 timeout. */ | |
360 | s->sr |= GPT_SR_OF1; | |
361 | s->cnt = s->ocr1; | |
362 | s->waiting_rov = 1; | |
363 | imx_timerg_reload(s, TIMER_MAX); | |
364 | } | |
365 | imx_timerg_update(s); | |
366 | return; | |
367 | } | |
368 | ||
369 | s->sr |= GPT_SR_OF1; | |
370 | imx_timerg_update(s); | |
371 | } | |
372 | ||
373 | static const MemoryRegionOps imx_timerg_ops = { | |
374 | .read = imx_timerg_read, | |
375 | .write = imx_timerg_write, | |
376 | .endianness = DEVICE_NATIVE_ENDIAN, | |
377 | }; | |
378 | ||
379 | ||
380 | static int imx_timerg_init(SysBusDevice *dev) | |
381 | { | |
382 | IMXTimerGState *s = FROM_SYSBUS(IMXTimerGState, dev); | |
383 | QEMUBH *bh; | |
384 | ||
385 | sysbus_init_irq(dev, &s->irq); | |
386 | memory_region_init_io(&s->iomem, &imx_timerg_ops, | |
387 | s, "imxg-timer", | |
388 | 0x00001000); | |
389 | sysbus_init_mmio(dev, &s->iomem); | |
390 | ||
391 | bh = qemu_bh_new(imx_timerg_timeout, s); | |
392 | s->timer = ptimer_init(bh); | |
393 | ||
394 | /* Hard reset resets extra bits in CR */ | |
395 | s->cr = 0; | |
396 | return 0; | |
397 | } | |
398 | ||
399 | ||
400 | ||
401 | /* | |
402 | * EPIT: Enhanced periodic interrupt timer | |
403 | */ | |
404 | ||
405 | #define CR_EN (1 << 0) | |
406 | #define CR_ENMOD (1 << 1) | |
407 | #define CR_OCIEN (1 << 2) | |
408 | #define CR_RLD (1 << 3) | |
409 | #define CR_PRESCALE_SHIFT (4) | |
410 | #define CR_PRESCALE_MASK (0xfff) | |
411 | #define CR_SWR (1 << 16) | |
412 | #define CR_IOVW (1 << 17) | |
413 | #define CR_DBGEN (1 << 18) | |
414 | #define CR_EPIT (1 << 19) | |
415 | #define CR_DOZEN (1 << 20) | |
416 | #define CR_STOPEN (1 << 21) | |
417 | #define CR_CLKSRC_SHIFT (24) | |
418 | #define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT) | |
419 | ||
420 | ||
421 | /* | |
422 | * Exact clock frequencies vary from board to board. | |
423 | * These are typical. | |
424 | */ | |
425 | static const IMXClk imx_timerp_clocks[] = { | |
426 | 0, /* disabled */ | |
427 | IPG, /* ipg_clk, ~532MHz */ | |
428 | IPG, /* ipg_clk_highfreq */ | |
429 | CLK_32k, /* ipg_clk_32k -- ~32kHz */ | |
430 | }; | |
431 | ||
432 | typedef struct { | |
433 | SysBusDevice busdev; | |
434 | ptimer_state *timer; | |
435 | MemoryRegion iomem; | |
436 | DeviceState *ccm; | |
437 | ||
438 | uint32_t cr; | |
439 | uint32_t lr; | |
440 | uint32_t cmp; | |
441 | ||
442 | uint32_t freq; | |
443 | int int_level; | |
444 | qemu_irq irq; | |
445 | } IMXTimerPState; | |
446 | ||
447 | /* | |
448 | * Update interrupt status | |
449 | */ | |
450 | static void imx_timerp_update(IMXTimerPState *s) | |
451 | { | |
452 | if (s->int_level && (s->cr & CR_OCIEN)) { | |
453 | qemu_irq_raise(s->irq); | |
454 | } else { | |
455 | qemu_irq_lower(s->irq); | |
456 | } | |
457 | } | |
458 | ||
459 | static void imx_timerp_reset(DeviceState *dev) | |
460 | { | |
461 | IMXTimerPState *s = container_of(dev, IMXTimerPState, busdev.qdev); | |
462 | ||
463 | s->cr = 0; | |
464 | s->lr = TIMER_MAX; | |
465 | s->int_level = 0; | |
466 | s->cmp = 0; | |
467 | ptimer_stop(s->timer); | |
468 | ptimer_set_count(s->timer, TIMER_MAX); | |
469 | } | |
470 | ||
a8170e5e | 471 | static uint64_t imx_timerp_read(void *opaque, hwaddr offset, |
78d1404d PC |
472 | unsigned size) |
473 | { | |
474 | IMXTimerPState *s = (IMXTimerPState *)opaque; | |
475 | ||
476 | DPRINTF("p-read(offset=%x)", offset >> 2); | |
477 | switch (offset >> 2) { | |
478 | case 0: /* Control Register */ | |
479 | DPRINTF("cr %x\n", s->cr); | |
480 | return s->cr; | |
481 | ||
482 | case 1: /* Status Register */ | |
483 | DPRINTF("int_level %x\n", s->int_level); | |
484 | return s->int_level; | |
485 | ||
486 | case 2: /* LR - ticks*/ | |
487 | DPRINTF("lr %x\n", s->lr); | |
488 | return s->lr; | |
489 | ||
490 | case 3: /* CMP */ | |
491 | DPRINTF("cmp %x\n", s->cmp); | |
492 | return s->cmp; | |
493 | ||
494 | case 4: /* CNT */ | |
495 | return ptimer_get_count(s->timer); | |
496 | } | |
497 | IPRINTF("imx_timerp_read: Bad offset %x\n", | |
498 | (int)offset >> 2); | |
499 | return 0; | |
500 | } | |
501 | ||
502 | static void set_timerp_freq(IMXTimerPState *s) | |
503 | { | |
504 | int clksrc; | |
505 | unsigned prescaler; | |
506 | uint32_t freq; | |
507 | ||
508 | clksrc = (s->cr & CR_CLKSRC_MASK) >> CR_CLKSRC_SHIFT; | |
509 | prescaler = 1 + ((s->cr >> CR_PRESCALE_SHIFT) & CR_PRESCALE_MASK); | |
510 | freq = imx_clock_frequency(s->ccm, imx_timerp_clocks[clksrc]) / prescaler; | |
511 | ||
512 | s->freq = freq; | |
513 | DPRINTF("Setting ptimer frequency to %u\n", freq); | |
514 | ||
515 | if (freq) { | |
516 | ptimer_set_freq(s->timer, freq); | |
517 | } | |
518 | } | |
519 | ||
a8170e5e | 520 | static void imx_timerp_write(void *opaque, hwaddr offset, |
78d1404d PC |
521 | uint64_t value, unsigned size) |
522 | { | |
523 | IMXTimerPState *s = (IMXTimerPState *)opaque; | |
524 | DPRINTF("p-write(offset=%x, value = %x)\n", (unsigned int)offset >> 2, | |
525 | (unsigned int)value); | |
526 | ||
527 | switch (offset >> 2) { | |
528 | case 0: /* CR */ | |
529 | if (value & CR_SWR) { | |
530 | imx_timerp_reset(&s->busdev.qdev); | |
531 | value &= ~CR_SWR; | |
532 | } | |
533 | s->cr = value & 0x03ffffff; | |
534 | set_timerp_freq(s); | |
535 | ||
536 | if (s->freq && (s->cr & CR_EN)) { | |
537 | if (!(s->cr & CR_ENMOD)) { | |
538 | ptimer_set_count(s->timer, s->lr); | |
539 | } | |
540 | ptimer_run(s->timer, 0); | |
541 | } else { | |
542 | ptimer_stop(s->timer); | |
543 | } | |
544 | break; | |
545 | ||
546 | case 1: /* SR - ACK*/ | |
547 | s->int_level = 0; | |
548 | imx_timerp_update(s); | |
549 | break; | |
550 | ||
551 | case 2: /* LR - set ticks */ | |
552 | s->lr = value; | |
553 | ptimer_set_limit(s->timer, value, !!(s->cr & CR_IOVW)); | |
554 | break; | |
555 | ||
556 | case 3: /* CMP */ | |
557 | s->cmp = value; | |
558 | if (value) { | |
559 | IPRINTF( | |
560 | "Values for EPIT comparison other than zero not supported\n" | |
561 | ); | |
562 | } | |
563 | break; | |
564 | ||
565 | default: | |
566 | IPRINTF("imx_timerp_write: Bad offset %x\n", | |
567 | (int)offset >> 2); | |
568 | } | |
569 | } | |
570 | ||
571 | static void imx_timerp_tick(void *opaque) | |
572 | { | |
573 | IMXTimerPState *s = (IMXTimerPState *)opaque; | |
574 | ||
575 | DPRINTF("imxp tick\n"); | |
576 | if (!(s->cr & CR_RLD)) { | |
577 | ptimer_set_count(s->timer, TIMER_MAX); | |
578 | } | |
579 | s->int_level = 1; | |
580 | imx_timerp_update(s); | |
581 | } | |
582 | ||
a8170e5e | 583 | void imx_timerp_create(const hwaddr addr, |
78d1404d PC |
584 | qemu_irq irq, |
585 | DeviceState *ccm) | |
586 | { | |
587 | IMXTimerPState *pp; | |
588 | DeviceState *dev; | |
589 | ||
590 | dev = sysbus_create_simple("imx_timerp", addr, irq); | |
591 | pp = container_of(dev, IMXTimerPState, busdev.qdev); | |
592 | pp->ccm = ccm; | |
593 | } | |
594 | ||
595 | static const MemoryRegionOps imx_timerp_ops = { | |
596 | .read = imx_timerp_read, | |
597 | .write = imx_timerp_write, | |
598 | .endianness = DEVICE_NATIVE_ENDIAN, | |
599 | }; | |
600 | ||
601 | static const VMStateDescription vmstate_imx_timerp = { | |
602 | .name = "imx-timerp", | |
603 | .version_id = 1, | |
604 | .minimum_version_id = 1, | |
605 | .minimum_version_id_old = 1, | |
606 | .fields = (VMStateField[]) { | |
607 | VMSTATE_UINT32(cr, IMXTimerPState), | |
608 | VMSTATE_UINT32(lr, IMXTimerPState), | |
609 | VMSTATE_UINT32(cmp, IMXTimerPState), | |
610 | VMSTATE_UINT32(freq, IMXTimerPState), | |
611 | VMSTATE_INT32(int_level, IMXTimerPState), | |
612 | VMSTATE_PTIMER(timer, IMXTimerPState), | |
613 | VMSTATE_END_OF_LIST() | |
614 | } | |
615 | }; | |
616 | ||
617 | static int imx_timerp_init(SysBusDevice *dev) | |
618 | { | |
619 | IMXTimerPState *s = FROM_SYSBUS(IMXTimerPState, dev); | |
620 | QEMUBH *bh; | |
621 | ||
622 | DPRINTF("imx_timerp_init\n"); | |
623 | ||
624 | sysbus_init_irq(dev, &s->irq); | |
625 | memory_region_init_io(&s->iomem, &imx_timerp_ops, | |
626 | s, "imxp-timer", | |
627 | 0x00001000); | |
628 | sysbus_init_mmio(dev, &s->iomem); | |
629 | ||
630 | bh = qemu_bh_new(imx_timerp_tick, s); | |
631 | s->timer = ptimer_init(bh); | |
632 | ||
633 | return 0; | |
634 | } | |
635 | ||
636 | ||
a8170e5e | 637 | void imx_timerg_create(const hwaddr addr, |
78d1404d PC |
638 | qemu_irq irq, |
639 | DeviceState *ccm) | |
640 | { | |
641 | IMXTimerGState *pp; | |
642 | DeviceState *dev; | |
643 | ||
644 | dev = sysbus_create_simple("imx_timerg", addr, irq); | |
645 | pp = container_of(dev, IMXTimerGState, busdev.qdev); | |
646 | pp->ccm = ccm; | |
647 | } | |
648 | ||
649 | static void imx_timerg_class_init(ObjectClass *klass, void *data) | |
650 | { | |
651 | DeviceClass *dc = DEVICE_CLASS(klass); | |
652 | SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); | |
653 | k->init = imx_timerg_init; | |
654 | dc->vmsd = &vmstate_imx_timerg; | |
655 | dc->reset = imx_timerg_reset; | |
656 | dc->desc = "i.MX general timer"; | |
657 | } | |
658 | ||
659 | static void imx_timerp_class_init(ObjectClass *klass, void *data) | |
660 | { | |
661 | DeviceClass *dc = DEVICE_CLASS(klass); | |
662 | SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); | |
663 | k->init = imx_timerp_init; | |
664 | dc->vmsd = &vmstate_imx_timerp; | |
665 | dc->reset = imx_timerp_reset; | |
666 | dc->desc = "i.MX periodic timer"; | |
667 | } | |
668 | ||
669 | static const TypeInfo imx_timerp_info = { | |
670 | .name = "imx_timerp", | |
671 | .parent = TYPE_SYS_BUS_DEVICE, | |
672 | .instance_size = sizeof(IMXTimerPState), | |
673 | .class_init = imx_timerp_class_init, | |
674 | }; | |
675 | ||
676 | static const TypeInfo imx_timerg_info = { | |
677 | .name = "imx_timerg", | |
678 | .parent = TYPE_SYS_BUS_DEVICE, | |
679 | .instance_size = sizeof(IMXTimerGState), | |
680 | .class_init = imx_timerg_class_init, | |
681 | }; | |
682 | ||
683 | static void imx_timer_register_types(void) | |
684 | { | |
685 | type_register_static(&imx_timerp_info); | |
686 | type_register_static(&imx_timerg_info); | |
687 | } | |
688 | ||
689 | type_init(imx_timer_register_types) |