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