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