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