xref: /openbmc/qemu/hw/timer/imx_epit.c (revision b45c03f5)
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
8  * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
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/arm/imx.h"
16 #include "hw/timer/imx_epit.h"
17 #include "hw/misc/imx_ccm.h"
18 #include "qemu/main-loop.h"
19 
20 #define DEBUG_TIMER 0
21 #if DEBUG_TIMER
22 
23 static 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 
41 #  define DPRINTF(fmt, args...) \
42     do { fprintf(stderr, "%s: " fmt , __func__, ##args); } while (0)
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
53 #  define IPRINTF(fmt, args...) \
54           do { fprintf(stderr, "%s: " fmt, __func__, ##args); } while (0)
55 #else
56 #  define IPRINTF(fmt, args...) do {} while (0)
57 #endif
58 
59 /*
60  * Exact clock frequencies vary from board to board.
61  * These are typical.
62  */
63 static const IMXClk imx_epit_clocks[] =  {
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 
70 /*
71  * Update interrupt status
72  */
73 static void imx_epit_update_int(IMXEPITState *s)
74 {
75     if (s->sr && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) {
76         qemu_irq_raise(s->irq);
77     } else {
78         qemu_irq_lower(s->irq);
79     }
80 }
81 
82 static void imx_epit_set_freq(IMXEPITState *s)
83 {
84     uint32_t clksrc;
85     uint32_t prescaler;
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 
91     freq = imx_clock_frequency(s->ccm, imx_epit_clocks[clksrc]) / prescaler;
92 
93     s->freq = freq;
94 
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 
103 static void imx_epit_reset(DeviceState *dev)
104 {
105     IMXEPITState *s = IMX_EPIT(dev);
106 
107     /*
108      * Soft reset doesn't touch some bits; hard reset clears them
109      */
110     s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
111     s->sr = 0;
112     s->lr = EPIT_TIMER_MAX;
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 */
119     imx_epit_set_freq(s);
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);
123     if (s->freq && (s->cr & CR_EN)) {
124         /* if the timer is still enabled, restart it */
125         ptimer_run(s->timer_reload, 0);
126     }
127 }
128 
129 static uint32_t imx_epit_update_count(IMXEPITState *s)
130 {
131     s->cnt = ptimer_get_count(s->timer_reload);
132 
133     return s->cnt;
134 }
135 
136 static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
137 {
138     IMXEPITState *s = IMX_EPIT(opaque);
139     uint32_t reg_value = 0;
140     uint32_t reg = offset >> 2;
141 
142     switch (reg) {
143     case 0: /* Control Register */
144         reg_value = s->cr;
145         break;
146 
147     case 1: /* Status Register */
148         reg_value = s->sr;
149         break;
150 
151     case 2: /* LR - ticks*/
152         reg_value = s->lr;
153         break;
154 
155     case 3: /* CMP */
156         reg_value = s->cmp;
157         break;
158 
159     case 4: /* CNT */
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;
167     }
168 
169     DPRINTF("(%s) = 0x%08x\n", imx_epit_reg_name(reg), reg_value);
170 
171     return reg_value;
172 }
173 
174 static void imx_epit_reload_compare_timer(IMXEPITState *s)
175 {
176     if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN))  {
177         /* if the compare feature is on and timers are running */
178         uint32_t tmp = imx_epit_update_count(s);
179         uint64_t next;
180         if (tmp > s->cmp) {
181             /* It'll fire in this round of the timer */
182             next = tmp - s->cmp;
183         } else { /* catch it next time around */
184             next = tmp - s->cmp + ((s->cr & CR_RLD) ? EPIT_TIMER_MAX : s->lr);
185         }
186         ptimer_set_count(s->timer_cmp, next);
187     }
188 }
189 
190 static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
191                            unsigned size)
192 {
193     IMXEPITState *s = IMX_EPIT(opaque);
194     uint32_t reg = offset >> 2;
195     uint64_t oldcr;
196 
197     DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(reg), (uint32_t)value);
198 
199     switch (reg) {
200     case 0: /* CR */
201 
202         oldcr = s->cr;
203         s->cr = value & 0x03ffffff;
204         if (s->cr & CR_SWR) {
205             /* handle the reset */
206             imx_epit_reset(DEVICE(s));
207         } else {
208             imx_epit_set_freq(s);
209         }
210 
211         if (s->freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) {
212             if (s->cr & CR_ENMOD) {
213                 if (s->cr & CR_RLD) {
214                     ptimer_set_limit(s->timer_reload, s->lr, 1);
215                     ptimer_set_limit(s->timer_cmp, s->lr, 1);
216                 } else {
217                     ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
218                     ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
219                 }
220             }
221 
222             imx_epit_reload_compare_timer(s);
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)) {
230             /* stop both timers */
231             ptimer_stop(s->timer_reload);
232             ptimer_stop(s->timer_cmp);
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);
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;
247             imx_epit_update_int(s);
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);
258             ptimer_set_limit(s->timer_cmp, s->lr, 0);
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 
264         imx_epit_reload_compare_timer(s);
265         break;
266 
267     case 3: /* CMP */
268         s->cmp = value;
269 
270         imx_epit_reload_compare_timer(s);
271 
272         break;
273 
274     default:
275         IPRINTF("Bad offset %x\n", reg);
276 
277         break;
278     }
279 }
280 static void imx_epit_cmp(void *opaque)
281 {
282     IMXEPITState *s = IMX_EPIT(opaque);
283 
284     DPRINTF("sr was %d\n", s->sr);
285 
286     s->sr = 1;
287     imx_epit_update_int(s);
288 }
289 
290 void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm)
291 {
292     IMXEPITState *pp;
293     DeviceState *dev;
294 
295     dev = sysbus_create_simple(TYPE_IMX_EPIT, addr, irq);
296     pp = IMX_EPIT(dev);
297     pp->ccm = ccm;
298 }
299 
300 static const MemoryRegionOps imx_epit_ops = {
301     .read = imx_epit_read,
302     .write = imx_epit_write,
303     .endianness = DEVICE_NATIVE_ENDIAN,
304 };
305 
306 static const VMStateDescription vmstate_imx_timer_epit = {
307     .name = TYPE_IMX_EPIT,
308     .version_id = 2,
309     .minimum_version_id = 2,
310     .fields = (VMStateField[]) {
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),
319         VMSTATE_END_OF_LIST()
320     }
321 };
322 
323 static void imx_epit_realize(DeviceState *dev, Error **errp)
324 {
325     IMXEPITState *s = IMX_EPIT(dev);
326     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
327     QEMUBH *bh;
328 
329     DPRINTF("\n");
330 
331     sysbus_init_irq(sbd, &s->irq);
332     memory_region_init_io(&s->iomem, OBJECT(s), &imx_epit_ops, s, TYPE_IMX_EPIT,
333                           0x00001000);
334     sysbus_init_mmio(sbd, &s->iomem);
335 
336     s->timer_reload = ptimer_init(NULL);
337 
338     bh = qemu_bh_new(imx_epit_cmp, s);
339     s->timer_cmp = ptimer_init(bh);
340 }
341 
342 static void imx_epit_class_init(ObjectClass *klass, void *data)
343 {
344     DeviceClass *dc  = DEVICE_CLASS(klass);
345 
346     dc->realize = imx_epit_realize;
347     dc->reset = imx_epit_reset;
348     dc->vmsd = &vmstate_imx_timer_epit;
349     dc->desc = "i.MX periodic timer";
350 }
351 
352 static const TypeInfo imx_epit_info = {
353     .name = TYPE_IMX_EPIT,
354     .parent = TYPE_SYS_BUS_DEVICE,
355     .instance_size = sizeof(IMXEPITState),
356     .class_init = imx_epit_class_init,
357 };
358 
359 static void imx_epit_register_types(void)
360 {
361     type_register_static(&imx_epit_info);
362 }
363 
364 type_init(imx_epit_register_types)
365