]> git.proxmox.com Git - mirror_qemu.git/blame - hw/timer/imx_epit.c
Merge remote-tracking branch 'remotes/mdroth/qga-pull-2014-08-08' into staging
[mirror_qemu.git] / hw / timer / imx_epit.c
CommitLineData
a50c0d6f
JCD
1/*
2 * IMX EPIT 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
95669e69 8 * Updated by Jean-Christophe Dubois
a50c0d6f
JCD
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 "hw/hw.h"
16#include "qemu/bitops.h"
17#include "qemu/timer.h"
18#include "hw/ptimer.h"
19#include "hw/sysbus.h"
20#include "hw/arm/imx.h"
6a1751b7 21#include "qemu/main-loop.h"
a50c0d6f 22
95669e69
JCD
23#define TYPE_IMX_EPIT "imx.epit"
24
25#define DEBUG_TIMER 0
26#if DEBUG_TIMER
27
28static char const *imx_epit_reg_name(uint32_t reg)
29{
30 switch (reg) {
31 case 0:
32 return "CR";
33 case 1:
34 return "SR";
35 case 2:
36 return "LR";
37 case 3:
38 return "CMP";
39 case 4:
40 return "CNT";
41 default:
42 return "[?]";
43 }
44}
45
a50c0d6f 46# define DPRINTF(fmt, args...) \
23005810 47 do { fprintf(stderr, "%s: " fmt , __func__, ##args); } while (0)
a50c0d6f
JCD
48#else
49# define DPRINTF(fmt, args...) do {} while (0)
50#endif
51
52/*
53 * Define to 1 for messages about attempts to
54 * access unimplemented registers or similar.
55 */
56#define DEBUG_IMPLEMENTATION 1
57#if DEBUG_IMPLEMENTATION
95669e69
JCD
58# define IPRINTF(fmt, args...) \
59 do { fprintf(stderr, "%s: " fmt, __func__, ##args); } while (0)
a50c0d6f
JCD
60#else
61# define IPRINTF(fmt, args...) do {} while (0)
62#endif
63
95669e69
JCD
64#define IMX_EPIT(obj) \
65 OBJECT_CHECK(IMXEPITState, (obj), TYPE_IMX_EPIT)
66
a50c0d6f
JCD
67/*
68 * EPIT: Enhanced periodic interrupt timer
69 */
70
71#define CR_EN (1 << 0)
72#define CR_ENMOD (1 << 1)
73#define CR_OCIEN (1 << 2)
74#define CR_RLD (1 << 3)
75#define CR_PRESCALE_SHIFT (4)
76#define CR_PRESCALE_MASK (0xfff)
77#define CR_SWR (1 << 16)
78#define CR_IOVW (1 << 17)
79#define CR_DBGEN (1 << 18)
80#define CR_WAITEN (1 << 19)
81#define CR_DOZEN (1 << 20)
82#define CR_STOPEN (1 << 21)
83#define CR_CLKSRC_SHIFT (24)
84#define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT)
85
86#define TIMER_MAX 0XFFFFFFFFUL
87
88/*
89 * Exact clock frequencies vary from board to board.
90 * These are typical.
91 */
95669e69 92static const IMXClk imx_epit_clocks[] = {
a50c0d6f
JCD
93 0, /* 00 disabled */
94 IPG, /* 01 ipg_clk, ~532MHz */
95 IPG, /* 10 ipg_clk_highfreq */
96 CLK_32k, /* 11 ipg_clk_32k -- ~32kHz */
97};
98
99typedef struct {
100 SysBusDevice busdev;
101 ptimer_state *timer_reload;
102 ptimer_state *timer_cmp;
103 MemoryRegion iomem;
104 DeviceState *ccm;
105
106 uint32_t cr;
107 uint32_t sr;
108 uint32_t lr;
109 uint32_t cmp;
110 uint32_t cnt;
111
112 uint32_t freq;
113 qemu_irq irq;
95669e69 114} IMXEPITState;
a50c0d6f
JCD
115
116/*
117 * Update interrupt status
118 */
95669e69 119static void imx_epit_update_int(IMXEPITState *s)
a50c0d6f 120{
95669e69 121 if (s->sr && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) {
a50c0d6f
JCD
122 qemu_irq_raise(s->irq);
123 } else {
124 qemu_irq_lower(s->irq);
125 }
126}
127
95669e69 128static void imx_epit_set_freq(IMXEPITState *s)
a50c0d6f 129{
95669e69
JCD
130 uint32_t clksrc;
131 uint32_t prescaler;
a50c0d6f
JCD
132 uint32_t freq;
133
134 clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2);
135 prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12);
136
95669e69 137 freq = imx_clock_frequency(s->ccm, imx_epit_clocks[clksrc]) / prescaler;
a50c0d6f
JCD
138
139 s->freq = freq;
95669e69 140
a50c0d6f
JCD
141 DPRINTF("Setting ptimer frequency to %u\n", freq);
142
143 if (freq) {
144 ptimer_set_freq(s->timer_reload, freq);
145 ptimer_set_freq(s->timer_cmp, freq);
146 }
147}
148
95669e69 149static void imx_epit_reset(DeviceState *dev)
a50c0d6f 150{
95669e69 151 IMXEPITState *s = IMX_EPIT(dev);
a50c0d6f
JCD
152
153 /*
154 * Soft reset doesn't touch some bits; hard reset clears them
155 */
23005810 156 s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
a50c0d6f
JCD
157 s->sr = 0;
158 s->lr = TIMER_MAX;
159 s->cmp = 0;
160 s->cnt = 0;
161 /* stop both timers */
162 ptimer_stop(s->timer_cmp);
163 ptimer_stop(s->timer_reload);
164 /* compute new frequency */
95669e69 165 imx_epit_set_freq(s);
a50c0d6f
JCD
166 /* init both timers to TIMER_MAX */
167 ptimer_set_limit(s->timer_cmp, TIMER_MAX, 1);
168 ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
169 if (s->freq && (s->cr & CR_EN)) {
170 /* if the timer is still enabled, restart it */
23005810 171 ptimer_run(s->timer_reload, 0);
a50c0d6f
JCD
172 }
173}
174
95669e69 175static uint32_t imx_epit_update_count(IMXEPITState *s)
a50c0d6f
JCD
176{
177 s->cnt = ptimer_get_count(s->timer_reload);
178
179 return s->cnt;
180}
181
95669e69 182static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
a50c0d6f 183{
95669e69
JCD
184 IMXEPITState *s = IMX_EPIT(opaque);
185 uint32_t reg_value = 0;
186 uint32_t reg = offset >> 2;
a50c0d6f 187
95669e69 188 switch (reg) {
a50c0d6f 189 case 0: /* Control Register */
95669e69
JCD
190 reg_value = s->cr;
191 break;
a50c0d6f
JCD
192
193 case 1: /* Status Register */
95669e69
JCD
194 reg_value = s->sr;
195 break;
a50c0d6f
JCD
196
197 case 2: /* LR - ticks*/
95669e69
JCD
198 reg_value = s->lr;
199 break;
a50c0d6f
JCD
200
201 case 3: /* CMP */
95669e69
JCD
202 reg_value = s->cmp;
203 break;
a50c0d6f
JCD
204
205 case 4: /* CNT */
95669e69
JCD
206 imx_epit_update_count(s);
207 reg_value = s->cnt;
208 break;
209
210 default:
211 IPRINTF("Bad offset %x\n", reg);
212 break;
a50c0d6f
JCD
213 }
214
95669e69
JCD
215 DPRINTF("(%s) = 0x%08x\n", imx_epit_reg_name(reg), reg_value);
216
217 return reg_value;
a50c0d6f
JCD
218}
219
95669e69 220static void imx_epit_reload_compare_timer(IMXEPITState *s)
a50c0d6f 221{
23005810
PC
222 if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN)) {
223 /* if the compare feature is on and timers are running */
95669e69 224 uint32_t tmp = imx_epit_update_count(s);
23005810 225 uint64_t next;
a50c0d6f 226 if (tmp > s->cmp) {
23005810
PC
227 /* It'll fire in this round of the timer */
228 next = tmp - s->cmp;
229 } else { /* catch it next time around */
230 next = tmp - s->cmp + ((s->cr & CR_RLD) ? TIMER_MAX : s->lr);
a50c0d6f 231 }
23005810 232 ptimer_set_count(s->timer_cmp, next);
a50c0d6f
JCD
233 }
234}
235
95669e69
JCD
236static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
237 unsigned size)
a50c0d6f 238{
95669e69
JCD
239 IMXEPITState *s = IMX_EPIT(opaque);
240 uint32_t reg = offset >> 2;
23005810 241 uint64_t oldcr;
95669e69
JCD
242
243 DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(reg), (uint32_t)value);
a50c0d6f 244
95669e69 245 switch (reg) {
a50c0d6f 246 case 0: /* CR */
23005810
PC
247
248 oldcr = s->cr;
a50c0d6f
JCD
249 s->cr = value & 0x03ffffff;
250 if (s->cr & CR_SWR) {
251 /* handle the reset */
95669e69 252 imx_epit_reset(DEVICE(s));
a50c0d6f 253 } else {
95669e69 254 imx_epit_set_freq(s);
a50c0d6f
JCD
255 }
256
23005810 257 if (s->freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) {
a50c0d6f
JCD
258 if (s->cr & CR_ENMOD) {
259 if (s->cr & CR_RLD) {
260 ptimer_set_limit(s->timer_reload, s->lr, 1);
23005810 261 ptimer_set_limit(s->timer_cmp, s->lr, 1);
a50c0d6f
JCD
262 } else {
263 ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
23005810 264 ptimer_set_limit(s->timer_cmp, TIMER_MAX, 1);
a50c0d6f
JCD
265 }
266 }
267
95669e69 268 imx_epit_reload_compare_timer(s);
23005810
PC
269 ptimer_run(s->timer_reload, 0);
270 if (s->cr & CR_OCIEN) {
271 ptimer_run(s->timer_cmp, 0);
272 } else {
273 ptimer_stop(s->timer_cmp);
274 }
275 } else if (!(s->cr & CR_EN)) {
a50c0d6f
JCD
276 /* stop both timers */
277 ptimer_stop(s->timer_reload);
278 ptimer_stop(s->timer_cmp);
23005810
PC
279 } else if (s->cr & CR_OCIEN) {
280 if (!(oldcr & CR_OCIEN)) {
281 imx_epit_reload_compare_timer(s);
282 ptimer_run(s->timer_cmp, 0);
283 }
284 } else {
285 ptimer_stop(s->timer_cmp);
a50c0d6f
JCD
286 }
287 break;
288
289 case 1: /* SR - ACK*/
290 /* writing 1 to OCIF clear the OCIF bit */
291 if (value & 0x01) {
292 s->sr = 0;
95669e69 293 imx_epit_update_int(s);
a50c0d6f
JCD
294 }
295 break;
296
297 case 2: /* LR - set ticks */
298 s->lr = value;
299
300 if (s->cr & CR_RLD) {
301 /* Also set the limit if the LRD bit is set */
302 /* If IOVW bit is set then set the timer value */
303 ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW);
23005810 304 ptimer_set_limit(s->timer_cmp, s->lr, 0);
a50c0d6f
JCD
305 } else if (s->cr & CR_IOVW) {
306 /* If IOVW bit is set then set the timer value */
307 ptimer_set_count(s->timer_reload, s->lr);
308 }
309
95669e69 310 imx_epit_reload_compare_timer(s);
a50c0d6f
JCD
311 break;
312
313 case 3: /* CMP */
314 s->cmp = value;
315
95669e69 316 imx_epit_reload_compare_timer(s);
a50c0d6f
JCD
317
318 break;
319
320 default:
95669e69
JCD
321 IPRINTF("Bad offset %x\n", reg);
322
323 break;
a50c0d6f
JCD
324 }
325}
95669e69 326static void imx_epit_cmp(void *opaque)
a50c0d6f 327{
95669e69 328 IMXEPITState *s = IMX_EPIT(opaque);
a50c0d6f 329
23005810 330 DPRINTF("sr was %d\n", s->sr);
a50c0d6f 331
23005810
PC
332 s->sr = 1;
333 imx_epit_update_int(s);
a50c0d6f
JCD
334}
335
95669e69 336void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm)
a50c0d6f 337{
95669e69 338 IMXEPITState *pp;
a50c0d6f
JCD
339 DeviceState *dev;
340
95669e69
JCD
341 dev = sysbus_create_simple(TYPE_IMX_EPIT, addr, irq);
342 pp = IMX_EPIT(dev);
a50c0d6f
JCD
343 pp->ccm = ccm;
344}
345
95669e69
JCD
346static const MemoryRegionOps imx_epit_ops = {
347 .read = imx_epit_read,
348 .write = imx_epit_write,
a50c0d6f
JCD
349 .endianness = DEVICE_NATIVE_ENDIAN,
350};
351
95669e69 352static const VMStateDescription vmstate_imx_timer_epit = {
6783ecf1 353 .name = "imx.epit",
a50c0d6f
JCD
354 .version_id = 2,
355 .minimum_version_id = 2,
8f1e884b 356 .fields = (VMStateField[]) {
95669e69
JCD
357 VMSTATE_UINT32(cr, IMXEPITState),
358 VMSTATE_UINT32(sr, IMXEPITState),
359 VMSTATE_UINT32(lr, IMXEPITState),
360 VMSTATE_UINT32(cmp, IMXEPITState),
361 VMSTATE_UINT32(cnt, IMXEPITState),
362 VMSTATE_UINT32(freq, IMXEPITState),
363 VMSTATE_PTIMER(timer_reload, IMXEPITState),
364 VMSTATE_PTIMER(timer_cmp, IMXEPITState),
a50c0d6f
JCD
365 VMSTATE_END_OF_LIST()
366 }
367};
368
95669e69 369static void imx_epit_realize(DeviceState *dev, Error **errp)
a50c0d6f 370{
95669e69
JCD
371 IMXEPITState *s = IMX_EPIT(dev);
372 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
a50c0d6f
JCD
373 QEMUBH *bh;
374
95669e69
JCD
375 DPRINTF("\n");
376
377 sysbus_init_irq(sbd, &s->irq);
853dca12 378 memory_region_init_io(&s->iomem, OBJECT(s), &imx_epit_ops, s, TYPE_IMX_EPIT,
a50c0d6f 379 0x00001000);
95669e69 380 sysbus_init_mmio(sbd, &s->iomem);
a50c0d6f 381
23005810 382 s->timer_reload = ptimer_init(NULL);
a50c0d6f 383
95669e69 384 bh = qemu_bh_new(imx_epit_cmp, s);
a50c0d6f 385 s->timer_cmp = ptimer_init(bh);
a50c0d6f
JCD
386}
387
95669e69 388static void imx_epit_class_init(ObjectClass *klass, void *data)
a50c0d6f
JCD
389{
390 DeviceClass *dc = DEVICE_CLASS(klass);
95669e69
JCD
391
392 dc->realize = imx_epit_realize;
393 dc->reset = imx_epit_reset;
394 dc->vmsd = &vmstate_imx_timer_epit;
a50c0d6f
JCD
395 dc->desc = "i.MX periodic timer";
396}
397
95669e69
JCD
398static const TypeInfo imx_epit_info = {
399 .name = TYPE_IMX_EPIT,
a50c0d6f 400 .parent = TYPE_SYS_BUS_DEVICE,
95669e69
JCD
401 .instance_size = sizeof(IMXEPITState),
402 .class_init = imx_epit_class_init,
a50c0d6f
JCD
403};
404
95669e69 405static void imx_epit_register_types(void)
a50c0d6f 406{
95669e69 407 type_register_static(&imx_epit_info);
a50c0d6f
JCD
408}
409
95669e69 410type_init(imx_epit_register_types)