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