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