xref: /openbmc/qemu/hw/timer/exynos4210_mct.c (revision 50f07d76f4920988c9bddeb9854240ac9f761e2e)
1 /*
2  * Samsung exynos4210 Multi Core timer
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
5  * All rights reserved.
6  *
7  * Evgeny Voevodin <e.voevodin@samsung.com>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by the
11  * Free Software Foundation; either version 2 of the License, or (at your
12  * option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17  * See the GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 /*
24  * Global Timer:
25  *
26  * Consists of two timers. First represents Free Running Counter and second
27  * is used to measure interval from FRC to nearest comparator.
28  *
29  *        0                                                           UINT64_MAX
30  *        |                              timer0                             |
31  *        | <-------------------------------------------------------------- |
32  *        | --------------------------------------------frc---------------> |
33  *        |______________________________________________|__________________|
34  *                CMP0          CMP1             CMP2    |           CMP3
35  *                                                     __|            |_
36  *                                                     |     timer1     |
37  *                                                     | -------------> |
38  *                                                    frc              CMPx
39  *
40  * Problem: when implementing global timer as is, overflow arises.
41  * next_time = cur_time + period * count;
42  * period and count are 64 bits width.
43  * Lets arm timer for MCT_GT_COUNTER_STEP count and update internal G_CNT
44  * register during each event.
45  *
46  * Problem: both timers need to be implemented using MCT_XT_COUNTER_STEP because
47  * local timer contains two counters: TCNT and ICNT. TCNT == 0 -> ICNT--.
48  * IRQ is generated when ICNT riches zero. Implementation where TCNT == 0
49  * generates IRQs suffers from too frequently events. Better to have one
50  * uint64_t counter equal to TCNT*ICNT and arm ptimer.c for a minimum(TCNT*ICNT,
51  * MCT_GT_COUNTER_STEP); (yes, if target tunes ICNT * TCNT to be too low values,
52  * there is no way to avoid frequently events).
53  */
54 
55 #include "qemu/osdep.h"
56 #include "qemu/log.h"
57 #include "hw/hw.h"
58 #include "hw/sysbus.h"
59 #include "migration/vmstate.h"
60 #include "qemu/timer.h"
61 #include "qemu/main-loop.h"
62 #include "qemu/module.h"
63 #include "hw/ptimer.h"
64 
65 #include "hw/arm/exynos4210.h"
66 #include "hw/hw.h"
67 #include "hw/irq.h"
68 
69 //#define DEBUG_MCT
70 
71 #ifdef DEBUG_MCT
72 #define DPRINTF(fmt, ...) \
73         do { fprintf(stdout, "MCT: [%24s:%5d] " fmt, __func__, __LINE__, \
74                      ## __VA_ARGS__); } while (0)
75 #else
76 #define DPRINTF(fmt, ...) do {} while (0)
77 #endif
78 
79 #define    MCT_CFG          0x000
80 #define    G_CNT_L          0x100
81 #define    G_CNT_U          0x104
82 #define    G_CNT_WSTAT      0x110
83 #define    G_COMP0_L        0x200
84 #define    G_COMP0_U        0x204
85 #define    G_COMP0_ADD_INCR 0x208
86 #define    G_COMP1_L        0x210
87 #define    G_COMP1_U        0x214
88 #define    G_COMP1_ADD_INCR 0x218
89 #define    G_COMP2_L        0x220
90 #define    G_COMP2_U        0x224
91 #define    G_COMP2_ADD_INCR 0x228
92 #define    G_COMP3_L        0x230
93 #define    G_COMP3_U        0x234
94 #define    G_COMP3_ADD_INCR 0x238
95 #define    G_TCON           0x240
96 #define    G_INT_CSTAT      0x244
97 #define    G_INT_ENB        0x248
98 #define    G_WSTAT          0x24C
99 #define    L0_TCNTB         0x300
100 #define    L0_TCNTO         0x304
101 #define    L0_ICNTB         0x308
102 #define    L0_ICNTO         0x30C
103 #define    L0_FRCNTB        0x310
104 #define    L0_FRCNTO        0x314
105 #define    L0_TCON          0x320
106 #define    L0_INT_CSTAT     0x330
107 #define    L0_INT_ENB       0x334
108 #define    L0_WSTAT         0x340
109 #define    L1_TCNTB         0x400
110 #define    L1_TCNTO         0x404
111 #define    L1_ICNTB         0x408
112 #define    L1_ICNTO         0x40C
113 #define    L1_FRCNTB        0x410
114 #define    L1_FRCNTO        0x414
115 #define    L1_TCON          0x420
116 #define    L1_INT_CSTAT     0x430
117 #define    L1_INT_ENB       0x434
118 #define    L1_WSTAT         0x440
119 
120 #define MCT_CFG_GET_PRESCALER(x)    ((x) & 0xFF)
121 #define MCT_CFG_GET_DIVIDER(x)      (1 << ((x) >> 8 & 7))
122 
123 #define GET_G_COMP_IDX(offset)          (((offset) - G_COMP0_L) / 0x10)
124 #define GET_G_COMP_ADD_INCR_IDX(offset) (((offset) - G_COMP0_ADD_INCR) / 0x10)
125 
126 #define G_COMP_L(x) (G_COMP0_L + (x) * 0x10)
127 #define G_COMP_U(x) (G_COMP0_U + (x) * 0x10)
128 
129 #define G_COMP_ADD_INCR(x)  (G_COMP0_ADD_INCR + (x) * 0x10)
130 
131 /* MCT bits */
132 #define G_TCON_COMP_ENABLE(x)   (1 << 2 * (x))
133 #define G_TCON_AUTO_ICREMENT(x) (1 << (2 * (x) + 1))
134 #define G_TCON_TIMER_ENABLE     (1 << 8)
135 
136 #define G_INT_ENABLE(x)         (1 << (x))
137 #define G_INT_CSTAT_COMP(x)     (1 << (x))
138 
139 #define G_CNT_WSTAT_L           1
140 #define G_CNT_WSTAT_U           2
141 
142 #define G_WSTAT_COMP_L(x)       (1 << 4 * (x))
143 #define G_WSTAT_COMP_U(x)       (1 << ((4 * (x)) + 1))
144 #define G_WSTAT_COMP_ADDINCR(x) (1 << ((4 * (x)) + 2))
145 #define G_WSTAT_TCON_WRITE      (1 << 16)
146 
147 #define GET_L_TIMER_IDX(offset) ((((offset) & 0xF00) - L0_TCNTB) / 0x100)
148 #define GET_L_TIMER_CNT_REG_IDX(offset, lt_i) \
149         (((offset) - (L0_TCNTB + 0x100 * (lt_i))) >> 2)
150 
151 #define L_ICNTB_MANUAL_UPDATE   (1 << 31)
152 
153 #define L_TCON_TICK_START       (1)
154 #define L_TCON_INT_START        (1 << 1)
155 #define L_TCON_INTERVAL_MODE    (1 << 2)
156 #define L_TCON_FRC_START        (1 << 3)
157 
158 #define L_INT_CSTAT_INTCNT      (1 << 0)
159 #define L_INT_CSTAT_FRCCNT      (1 << 1)
160 
161 #define L_INT_INTENB_ICNTEIE    (1 << 0)
162 #define L_INT_INTENB_FRCEIE     (1 << 1)
163 
164 #define L_WSTAT_TCNTB_WRITE     (1 << 0)
165 #define L_WSTAT_ICNTB_WRITE     (1 << 1)
166 #define L_WSTAT_FRCCNTB_WRITE   (1 << 2)
167 #define L_WSTAT_TCON_WRITE      (1 << 3)
168 
169 enum LocalTimerRegCntIndexes {
170     L_REG_CNT_TCNTB,
171     L_REG_CNT_TCNTO,
172     L_REG_CNT_ICNTB,
173     L_REG_CNT_ICNTO,
174     L_REG_CNT_FRCCNTB,
175     L_REG_CNT_FRCCNTO,
176 
177     L_REG_CNT_AMOUNT
178 };
179 
180 #define MCT_SFR_SIZE            0x444
181 
182 #define MCT_GT_CMP_NUM          4
183 
184 #define MCT_GT_COUNTER_STEP     0x100000000ULL
185 #define MCT_LT_COUNTER_STEP     0x100000000ULL
186 #define MCT_LT_CNT_LOW_LIMIT    0x100
187 
188 /* global timer */
189 typedef struct {
190     qemu_irq  irq[MCT_GT_CMP_NUM];
191 
192     struct gregs {
193         uint64_t cnt;
194         uint32_t cnt_wstat;
195         uint32_t tcon;
196         uint32_t int_cstat;
197         uint32_t int_enb;
198         uint32_t wstat;
199         uint64_t comp[MCT_GT_CMP_NUM];
200         uint32_t comp_add_incr[MCT_GT_CMP_NUM];
201     } reg;
202 
203     uint64_t count;            /* Value FRC was armed with */
204     int32_t curr_comp;             /* Current comparator FRC is running to */
205 
206     ptimer_state *ptimer_frc;                   /* FRC timer */
207 
208 } Exynos4210MCTGT;
209 
210 /* local timer */
211 typedef struct {
212     int         id;             /* timer id */
213     qemu_irq    irq;            /* local timer irq */
214 
215     struct tick_timer {
216         uint32_t cnt_run;           /* cnt timer is running */
217         uint32_t int_run;           /* int timer is running */
218 
219         uint32_t last_icnto;
220         uint32_t last_tcnto;
221         uint32_t tcntb;             /* initial value for TCNTB */
222         uint32_t icntb;             /* initial value for ICNTB */
223 
224         /* for step mode */
225         uint64_t    distance;       /* distance to count to the next event */
226         uint64_t    progress;       /* progress when counting by steps */
227         uint64_t    count;          /* count to arm timer with */
228 
229         ptimer_state *ptimer_tick;  /* timer for tick counter */
230     } tick_timer;
231 
232     /* use ptimer.c to represent count down timer */
233 
234     ptimer_state *ptimer_frc;   /* timer for free running counter */
235 
236     /* registers */
237     struct lregs {
238         uint32_t    cnt[L_REG_CNT_AMOUNT];
239         uint32_t    tcon;
240         uint32_t    int_cstat;
241         uint32_t    int_enb;
242         uint32_t    wstat;
243     } reg;
244 
245 } Exynos4210MCTLT;
246 
247 #define TYPE_EXYNOS4210_MCT "exynos4210.mct"
248 #define EXYNOS4210_MCT(obj) \
249     OBJECT_CHECK(Exynos4210MCTState, (obj), TYPE_EXYNOS4210_MCT)
250 
251 typedef struct Exynos4210MCTState {
252     SysBusDevice parent_obj;
253 
254     MemoryRegion iomem;
255 
256     /* Registers */
257     uint32_t    reg_mct_cfg;
258 
259     Exynos4210MCTLT l_timer[2];
260     Exynos4210MCTGT g_timer;
261 
262     uint32_t    freq;                   /* all timers tick frequency, TCLK */
263 } Exynos4210MCTState;
264 
265 /*** VMState ***/
266 static const VMStateDescription vmstate_tick_timer = {
267     .name = "exynos4210.mct.tick_timer",
268     .version_id = 1,
269     .minimum_version_id = 1,
270     .fields = (VMStateField[]) {
271         VMSTATE_UINT32(cnt_run, struct tick_timer),
272         VMSTATE_UINT32(int_run, struct tick_timer),
273         VMSTATE_UINT32(last_icnto, struct tick_timer),
274         VMSTATE_UINT32(last_tcnto, struct tick_timer),
275         VMSTATE_UINT32(tcntb, struct tick_timer),
276         VMSTATE_UINT32(icntb, struct tick_timer),
277         VMSTATE_UINT64(distance, struct tick_timer),
278         VMSTATE_UINT64(progress, struct tick_timer),
279         VMSTATE_UINT64(count, struct tick_timer),
280         VMSTATE_PTIMER(ptimer_tick, struct tick_timer),
281         VMSTATE_END_OF_LIST()
282     }
283 };
284 
285 static const VMStateDescription vmstate_lregs = {
286     .name = "exynos4210.mct.lregs",
287     .version_id = 1,
288     .minimum_version_id = 1,
289     .fields = (VMStateField[]) {
290         VMSTATE_UINT32_ARRAY(cnt, struct lregs, L_REG_CNT_AMOUNT),
291         VMSTATE_UINT32(tcon, struct lregs),
292         VMSTATE_UINT32(int_cstat, struct lregs),
293         VMSTATE_UINT32(int_enb, struct lregs),
294         VMSTATE_UINT32(wstat, struct lregs),
295         VMSTATE_END_OF_LIST()
296     }
297 };
298 
299 static const VMStateDescription vmstate_exynos4210_mct_lt = {
300     .name = "exynos4210.mct.lt",
301     .version_id = 1,
302     .minimum_version_id = 1,
303     .fields = (VMStateField[]) {
304         VMSTATE_INT32(id, Exynos4210MCTLT),
305         VMSTATE_STRUCT(tick_timer, Exynos4210MCTLT, 0,
306                 vmstate_tick_timer,
307                 struct tick_timer),
308         VMSTATE_PTIMER(ptimer_frc, Exynos4210MCTLT),
309         VMSTATE_STRUCT(reg, Exynos4210MCTLT, 0,
310                 vmstate_lregs,
311                 struct lregs),
312         VMSTATE_END_OF_LIST()
313     }
314 };
315 
316 static const VMStateDescription vmstate_gregs = {
317     .name = "exynos4210.mct.lregs",
318     .version_id = 1,
319     .minimum_version_id = 1,
320     .fields = (VMStateField[]) {
321         VMSTATE_UINT64(cnt, struct gregs),
322         VMSTATE_UINT32(cnt_wstat, struct gregs),
323         VMSTATE_UINT32(tcon, struct gregs),
324         VMSTATE_UINT32(int_cstat, struct gregs),
325         VMSTATE_UINT32(int_enb, struct gregs),
326         VMSTATE_UINT32(wstat, struct gregs),
327         VMSTATE_UINT64_ARRAY(comp, struct gregs, MCT_GT_CMP_NUM),
328         VMSTATE_UINT32_ARRAY(comp_add_incr, struct gregs,
329                 MCT_GT_CMP_NUM),
330         VMSTATE_END_OF_LIST()
331     }
332 };
333 
334 static const VMStateDescription vmstate_exynos4210_mct_gt = {
335     .name = "exynos4210.mct.lt",
336     .version_id = 1,
337     .minimum_version_id = 1,
338     .fields = (VMStateField[]) {
339         VMSTATE_STRUCT(reg, Exynos4210MCTGT, 0, vmstate_gregs,
340                 struct gregs),
341         VMSTATE_UINT64(count, Exynos4210MCTGT),
342         VMSTATE_INT32(curr_comp, Exynos4210MCTGT),
343         VMSTATE_PTIMER(ptimer_frc, Exynos4210MCTGT),
344         VMSTATE_END_OF_LIST()
345     }
346 };
347 
348 static const VMStateDescription vmstate_exynos4210_mct_state = {
349     .name = "exynos4210.mct",
350     .version_id = 1,
351     .minimum_version_id = 1,
352     .fields = (VMStateField[]) {
353         VMSTATE_UINT32(reg_mct_cfg, Exynos4210MCTState),
354         VMSTATE_STRUCT_ARRAY(l_timer, Exynos4210MCTState, 2, 0,
355             vmstate_exynos4210_mct_lt, Exynos4210MCTLT),
356         VMSTATE_STRUCT(g_timer, Exynos4210MCTState, 0,
357             vmstate_exynos4210_mct_gt, Exynos4210MCTGT),
358         VMSTATE_UINT32(freq, Exynos4210MCTState),
359         VMSTATE_END_OF_LIST()
360     }
361 };
362 
363 static void exynos4210_mct_update_freq(Exynos4210MCTState *s);
364 
365 /*
366  * Set counter of FRC global timer.
367  * Must be called within exynos4210_gfrc_tx_begin/commit block.
368  */
369 static void exynos4210_gfrc_set_count(Exynos4210MCTGT *s, uint64_t count)
370 {
371     s->count = count;
372     DPRINTF("global timer frc set count 0x%llx\n", count);
373     ptimer_set_count(s->ptimer_frc, count);
374 }
375 
376 /*
377  * Get counter of FRC global timer.
378  */
379 static uint64_t exynos4210_gfrc_get_count(Exynos4210MCTGT *s)
380 {
381     uint64_t count = 0;
382     count = ptimer_get_count(s->ptimer_frc);
383     count = s->count - count;
384     return s->reg.cnt + count;
385 }
386 
387 /*
388  * Stop global FRC timer
389  * Must be called within exynos4210_gfrc_tx_begin/commit block.
390  */
391 static void exynos4210_gfrc_stop(Exynos4210MCTGT *s)
392 {
393     DPRINTF("global timer frc stop\n");
394 
395     ptimer_stop(s->ptimer_frc);
396 }
397 
398 /*
399  * Start global FRC timer
400  * Must be called within exynos4210_gfrc_tx_begin/commit block.
401  */
402 static void exynos4210_gfrc_start(Exynos4210MCTGT *s)
403 {
404     DPRINTF("global timer frc start\n");
405 
406     ptimer_run(s->ptimer_frc, 1);
407 }
408 
409 /*
410  * Start ptimer transaction for global FRC timer; this is just for
411  * consistency with the way we wrap operations like stop and run.
412  */
413 static void exynos4210_gfrc_tx_begin(Exynos4210MCTGT *s)
414 {
415     ptimer_transaction_begin(s->ptimer_frc);
416 }
417 
418 /* Commit ptimer transaction for global FRC timer. */
419 static void exynos4210_gfrc_tx_commit(Exynos4210MCTGT *s)
420 {
421     ptimer_transaction_commit(s->ptimer_frc);
422 }
423 
424 /*
425  * Find next nearest Comparator. If current Comparator value equals to other
426  * Comparator value, skip them both
427  */
428 static int32_t exynos4210_gcomp_find(Exynos4210MCTState *s)
429 {
430     int res;
431     int i;
432     int enabled;
433     uint64_t min;
434     int min_comp_i;
435     uint64_t gfrc;
436     uint64_t distance;
437     uint64_t distance_min;
438     int comp_i;
439 
440     /* get gfrc count */
441     gfrc = exynos4210_gfrc_get_count(&s->g_timer);
442 
443     min = UINT64_MAX;
444     distance_min = UINT64_MAX;
445     comp_i = MCT_GT_CMP_NUM;
446     min_comp_i = MCT_GT_CMP_NUM;
447     enabled = 0;
448 
449     /* lookup for nearest comparator */
450     for (i = 0; i < MCT_GT_CMP_NUM; i++) {
451 
452         if (s->g_timer.reg.tcon & G_TCON_COMP_ENABLE(i)) {
453 
454             enabled = 1;
455 
456             if (s->g_timer.reg.comp[i] > gfrc) {
457                 /* Comparator is upper then FRC */
458                 distance = s->g_timer.reg.comp[i] - gfrc;
459 
460                 if (distance <= distance_min) {
461                     distance_min = distance;
462                     comp_i = i;
463                 }
464             } else {
465                 /* Comparator is below FRC, find the smallest */
466 
467                 if (s->g_timer.reg.comp[i] <= min) {
468                     min = s->g_timer.reg.comp[i];
469                     min_comp_i = i;
470                 }
471             }
472         }
473     }
474 
475     if (!enabled) {
476         /* All Comparators disabled */
477         res = -1;
478     } else if (comp_i < MCT_GT_CMP_NUM) {
479         /* Found upper Comparator */
480         res = comp_i;
481     } else {
482         /* All Comparators are below or equal to FRC  */
483         res = min_comp_i;
484     }
485 
486     DPRINTF("found comparator %d: comp 0x%llx distance 0x%llx, gfrc 0x%llx\n",
487             res,
488             s->g_timer.reg.comp[res],
489             distance_min,
490             gfrc);
491 
492     return res;
493 }
494 
495 /*
496  * Get distance to nearest Comparator
497  */
498 static uint64_t exynos4210_gcomp_get_distance(Exynos4210MCTState *s, int32_t id)
499 {
500     if (id == -1) {
501         /* no enabled Comparators, choose max distance */
502         return MCT_GT_COUNTER_STEP;
503     }
504     if (s->g_timer.reg.comp[id] - s->g_timer.reg.cnt < MCT_GT_COUNTER_STEP) {
505         return s->g_timer.reg.comp[id] - s->g_timer.reg.cnt;
506     } else {
507         return MCT_GT_COUNTER_STEP;
508     }
509 }
510 
511 /*
512  * Restart global FRC timer
513  * Must be called within exynos4210_gfrc_tx_begin/commit block.
514  */
515 static void exynos4210_gfrc_restart(Exynos4210MCTState *s)
516 {
517     uint64_t distance;
518 
519     exynos4210_gfrc_stop(&s->g_timer);
520 
521     s->g_timer.curr_comp = exynos4210_gcomp_find(s);
522 
523     distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp);
524 
525     if (distance > MCT_GT_COUNTER_STEP || !distance) {
526         distance = MCT_GT_COUNTER_STEP;
527     }
528 
529     exynos4210_gfrc_set_count(&s->g_timer, distance);
530     exynos4210_gfrc_start(&s->g_timer);
531 }
532 
533 /*
534  * Raise global timer CMP IRQ
535  */
536 static void exynos4210_gcomp_raise_irq(void *opaque, uint32_t id)
537 {
538     Exynos4210MCTGT *s = opaque;
539 
540     /* If CSTAT is pending and IRQ is enabled */
541     if ((s->reg.int_cstat & G_INT_CSTAT_COMP(id)) &&
542             (s->reg.int_enb & G_INT_ENABLE(id))) {
543         DPRINTF("gcmp timer[%d] IRQ\n", id);
544         qemu_irq_raise(s->irq[id]);
545     }
546 }
547 
548 /*
549  * Lower global timer CMP IRQ
550  */
551 static void exynos4210_gcomp_lower_irq(void *opaque, uint32_t id)
552 {
553     Exynos4210MCTGT *s = opaque;
554     qemu_irq_lower(s->irq[id]);
555 }
556 
557 /*
558  * Global timer FRC event handler.
559  * Each event occurs when internal counter reaches counter + MCT_GT_COUNTER_STEP
560  * Every time we arm global FRC timer to count for MCT_GT_COUNTER_STEP value
561  */
562 static void exynos4210_gfrc_event(void *opaque)
563 {
564     Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
565     int i;
566     uint64_t distance;
567 
568     DPRINTF("\n");
569 
570     s->g_timer.reg.cnt += s->g_timer.count;
571 
572     /* Process all comparators */
573     for (i = 0; i < MCT_GT_CMP_NUM; i++) {
574 
575         if (s->g_timer.reg.cnt == s->g_timer.reg.comp[i]) {
576             /* reached nearest comparator */
577 
578             s->g_timer.reg.int_cstat |= G_INT_CSTAT_COMP(i);
579 
580             /* Auto increment */
581             if (s->g_timer.reg.tcon & G_TCON_AUTO_ICREMENT(i)) {
582                 s->g_timer.reg.comp[i] += s->g_timer.reg.comp_add_incr[i];
583             }
584 
585             /* IRQ */
586             exynos4210_gcomp_raise_irq(&s->g_timer, i);
587         }
588     }
589 
590     /* Reload FRC to reach nearest comparator */
591     s->g_timer.curr_comp = exynos4210_gcomp_find(s);
592     distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp);
593     if (distance > MCT_GT_COUNTER_STEP || !distance) {
594         distance = MCT_GT_COUNTER_STEP;
595     }
596     exynos4210_gfrc_set_count(&s->g_timer, distance);
597 
598     exynos4210_gfrc_start(&s->g_timer);
599 }
600 
601 /*
602  * Get counter of FRC local timer.
603  */
604 static uint64_t exynos4210_lfrc_get_count(Exynos4210MCTLT *s)
605 {
606     return ptimer_get_count(s->ptimer_frc);
607 }
608 
609 /*
610  * Set counter of FRC local timer.
611  * Must be called from within exynos4210_lfrc_tx_begin/commit block.
612  */
613 static void exynos4210_lfrc_update_count(Exynos4210MCTLT *s)
614 {
615     if (!s->reg.cnt[L_REG_CNT_FRCCNTB]) {
616         ptimer_set_count(s->ptimer_frc, MCT_LT_COUNTER_STEP);
617     } else {
618         ptimer_set_count(s->ptimer_frc, s->reg.cnt[L_REG_CNT_FRCCNTB]);
619     }
620 }
621 
622 /*
623  * Start local FRC timer
624  * Must be called from within exynos4210_lfrc_tx_begin/commit block.
625  */
626 static void exynos4210_lfrc_start(Exynos4210MCTLT *s)
627 {
628     ptimer_run(s->ptimer_frc, 1);
629 }
630 
631 /*
632  * Stop local FRC timer
633  * Must be called from within exynos4210_lfrc_tx_begin/commit block.
634  */
635 static void exynos4210_lfrc_stop(Exynos4210MCTLT *s)
636 {
637     ptimer_stop(s->ptimer_frc);
638 }
639 
640 /* Start ptimer transaction for local FRC timer */
641 static void exynos4210_lfrc_tx_begin(Exynos4210MCTLT *s)
642 {
643     ptimer_transaction_begin(s->ptimer_frc);
644 }
645 
646 /* Commit ptimer transaction for local FRC timer */
647 static void exynos4210_lfrc_tx_commit(Exynos4210MCTLT *s)
648 {
649     ptimer_transaction_commit(s->ptimer_frc);
650 }
651 
652 /*
653  * Local timer free running counter tick handler
654  */
655 static void exynos4210_lfrc_event(void *opaque)
656 {
657     Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque;
658 
659     /* local frc expired */
660 
661     DPRINTF("\n");
662 
663     s->reg.int_cstat |= L_INT_CSTAT_FRCCNT;
664 
665     /* update frc counter */
666     exynos4210_lfrc_update_count(s);
667 
668     /* raise irq */
669     if (s->reg.int_enb & L_INT_INTENB_FRCEIE) {
670         qemu_irq_raise(s->irq);
671     }
672 
673     /*  we reached here, this means that timer is enabled */
674     exynos4210_lfrc_start(s);
675 }
676 
677 static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s);
678 static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s);
679 static void exynos4210_ltick_recalc_count(struct tick_timer *s);
680 
681 /*
682  * Action on enabling local tick int timer
683  */
684 static void exynos4210_ltick_int_start(struct tick_timer *s)
685 {
686     if (!s->int_run) {
687         s->int_run = 1;
688     }
689 }
690 
691 /*
692  * Action on disabling local tick int timer
693  */
694 static void exynos4210_ltick_int_stop(struct tick_timer *s)
695 {
696     if (s->int_run) {
697         s->last_icnto = exynos4210_ltick_int_get_cnto(s);
698         s->int_run = 0;
699     }
700 }
701 
702 /*
703  * Get count for INT timer
704  */
705 static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s)
706 {
707     uint32_t icnto;
708     uint64_t remain;
709     uint64_t count;
710     uint64_t counted;
711     uint64_t cur_progress;
712 
713     count = ptimer_get_count(s->ptimer_tick);
714     if (count) {
715         /* timer is still counting, called not from event */
716         counted = s->count - ptimer_get_count(s->ptimer_tick);
717         cur_progress = s->progress + counted;
718     } else {
719         /* timer expired earlier */
720         cur_progress = s->progress;
721     }
722 
723     remain = s->distance - cur_progress;
724 
725     if (!s->int_run) {
726         /* INT is stopped. */
727         icnto = s->last_icnto;
728     } else {
729         /* Both are counting */
730         icnto = remain / s->tcntb;
731     }
732 
733     return icnto;
734 }
735 
736 /*
737  * Start local tick cnt timer.
738  */
739 static void exynos4210_ltick_cnt_start(struct tick_timer *s)
740 {
741     if (!s->cnt_run) {
742 
743         exynos4210_ltick_recalc_count(s);
744         ptimer_set_count(s->ptimer_tick, s->count);
745         ptimer_run(s->ptimer_tick, 1);
746 
747         s->cnt_run = 1;
748     }
749 }
750 
751 /*
752  * Stop local tick cnt timer.
753  */
754 static void exynos4210_ltick_cnt_stop(struct tick_timer *s)
755 {
756     if (s->cnt_run) {
757 
758         s->last_tcnto = exynos4210_ltick_cnt_get_cnto(s);
759 
760         if (s->int_run) {
761             exynos4210_ltick_int_stop(s);
762         }
763 
764         ptimer_stop(s->ptimer_tick);
765 
766         s->cnt_run = 0;
767     }
768 }
769 
770 /*
771  * Get counter for CNT timer
772  */
773 static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s)
774 {
775     uint32_t tcnto;
776     uint32_t icnto;
777     uint64_t remain;
778     uint64_t counted;
779     uint64_t count;
780     uint64_t cur_progress;
781 
782     count = ptimer_get_count(s->ptimer_tick);
783     if (count) {
784         /* timer is still counting, called not from event */
785         counted = s->count - ptimer_get_count(s->ptimer_tick);
786         cur_progress = s->progress + counted;
787     } else {
788         /* timer expired earlier */
789         cur_progress = s->progress;
790     }
791 
792     remain = s->distance - cur_progress;
793 
794     if (!s->cnt_run) {
795         /* Both are stopped. */
796         tcnto = s->last_tcnto;
797     } else if (!s->int_run) {
798         /* INT counter is stopped, progress is by CNT timer */
799         tcnto = remain % s->tcntb;
800     } else {
801         /* Both are counting */
802         icnto = remain / s->tcntb;
803         if (icnto) {
804             tcnto = remain % (icnto * s->tcntb);
805         } else {
806             tcnto = remain % s->tcntb;
807         }
808     }
809 
810     return tcnto;
811 }
812 
813 /*
814  * Set new values of counters for CNT and INT timers
815  */
816 static void exynos4210_ltick_set_cntb(struct tick_timer *s, uint32_t new_cnt,
817         uint32_t new_int)
818 {
819     uint32_t cnt_stopped = 0;
820     uint32_t int_stopped = 0;
821 
822     if (s->cnt_run) {
823         exynos4210_ltick_cnt_stop(s);
824         cnt_stopped = 1;
825     }
826 
827     if (s->int_run) {
828         exynos4210_ltick_int_stop(s);
829         int_stopped = 1;
830     }
831 
832     s->tcntb = new_cnt + 1;
833     s->icntb = new_int + 1;
834 
835     if (cnt_stopped) {
836         exynos4210_ltick_cnt_start(s);
837     }
838     if (int_stopped) {
839         exynos4210_ltick_int_start(s);
840     }
841 
842 }
843 
844 /*
845  * Calculate new counter value for tick timer
846  */
847 static void exynos4210_ltick_recalc_count(struct tick_timer *s)
848 {
849     uint64_t to_count;
850 
851     if ((s->cnt_run && s->last_tcnto) || (s->int_run && s->last_icnto)) {
852         /*
853          * one or both timers run and not counted to the end;
854          * distance is not passed, recalculate with last_tcnto * last_icnto
855          */
856 
857         if (s->last_tcnto) {
858             to_count = (uint64_t)s->last_tcnto * s->last_icnto;
859         } else {
860             to_count = s->last_icnto;
861         }
862     } else {
863         /* distance is passed, recalculate with tcnto * icnto */
864         if (s->icntb) {
865             s->distance = (uint64_t)s->tcntb * s->icntb;
866         } else {
867             s->distance = s->tcntb;
868         }
869 
870         to_count = s->distance;
871         s->progress = 0;
872     }
873 
874     if (to_count > MCT_LT_COUNTER_STEP) {
875         /* count by step */
876         s->count = MCT_LT_COUNTER_STEP;
877     } else {
878         s->count = to_count;
879     }
880 }
881 
882 /*
883  * Initialize tick_timer
884  */
885 static void exynos4210_ltick_timer_init(struct tick_timer *s)
886 {
887     exynos4210_ltick_int_stop(s);
888     exynos4210_ltick_cnt_stop(s);
889 
890     s->count = 0;
891     s->distance = 0;
892     s->progress = 0;
893     s->icntb = 0;
894     s->tcntb = 0;
895 }
896 
897 /*
898  * tick_timer event.
899  * Raises when abstract tick_timer expires.
900  */
901 static void exynos4210_ltick_timer_event(struct tick_timer *s)
902 {
903     s->progress += s->count;
904 }
905 
906 /*
907  * Local timer tick counter handler.
908  * Don't use reloaded timers. If timer counter = zero
909  * then handler called but after handler finished no
910  * timer reload occurs.
911  */
912 static void exynos4210_ltick_event(void *opaque)
913 {
914     Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque;
915     uint32_t tcnto;
916     uint32_t icnto;
917 #ifdef DEBUG_MCT
918     static uint64_t time1[2] = {0};
919     static uint64_t time2[2] = {0};
920 #endif
921 
922     /* Call tick_timer event handler, it will update its tcntb and icntb. */
923     exynos4210_ltick_timer_event(&s->tick_timer);
924 
925     /* get tick_timer cnt */
926     tcnto = exynos4210_ltick_cnt_get_cnto(&s->tick_timer);
927 
928     /* get tick_timer int */
929     icnto = exynos4210_ltick_int_get_cnto(&s->tick_timer);
930 
931     /* raise IRQ if needed */
932     if (!icnto && s->reg.tcon & L_TCON_INT_START) {
933         /* INT counter enabled and expired */
934 
935         s->reg.int_cstat |= L_INT_CSTAT_INTCNT;
936 
937         /* raise interrupt if enabled */
938         if (s->reg.int_enb & L_INT_INTENB_ICNTEIE) {
939 #ifdef DEBUG_MCT
940             time2[s->id] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
941             DPRINTF("local timer[%d] IRQ: %llx\n", s->id,
942                     time2[s->id] - time1[s->id]);
943             time1[s->id] = time2[s->id];
944 #endif
945             qemu_irq_raise(s->irq);
946         }
947 
948         /* reload ICNTB */
949         if (s->reg.tcon & L_TCON_INTERVAL_MODE) {
950             exynos4210_ltick_set_cntb(&s->tick_timer,
951                     s->reg.cnt[L_REG_CNT_TCNTB],
952                     s->reg.cnt[L_REG_CNT_ICNTB]);
953         }
954     } else {
955         /* reload TCNTB */
956         if (!tcnto) {
957             exynos4210_ltick_set_cntb(&s->tick_timer,
958                     s->reg.cnt[L_REG_CNT_TCNTB],
959                     icnto);
960         }
961     }
962 
963     /* start tick_timer cnt */
964     exynos4210_ltick_cnt_start(&s->tick_timer);
965 
966     /* start tick_timer int */
967     exynos4210_ltick_int_start(&s->tick_timer);
968 }
969 
970 static void tx_ptimer_set_freq(ptimer_state *s, uint32_t freq)
971 {
972     /*
973      * callers of exynos4210_mct_update_freq() never do anything
974      * else that needs to be in the same ptimer transaction, so
975      * to avoid a lot of repetition we have a convenience function
976      * for begin/set_freq/commit.
977      */
978     ptimer_transaction_begin(s);
979     ptimer_set_freq(s, freq);
980     ptimer_transaction_commit(s);
981 }
982 
983 /* update timer frequency */
984 static void exynos4210_mct_update_freq(Exynos4210MCTState *s)
985 {
986     uint32_t freq = s->freq;
987     s->freq = 24000000 /
988             ((MCT_CFG_GET_PRESCALER(s->reg_mct_cfg) + 1) *
989                     MCT_CFG_GET_DIVIDER(s->reg_mct_cfg));
990 
991     if (freq != s->freq) {
992         DPRINTF("freq=%dHz\n", s->freq);
993 
994         /* global timer */
995         tx_ptimer_set_freq(s->g_timer.ptimer_frc, s->freq);
996 
997         /* local timer */
998         ptimer_set_freq(s->l_timer[0].tick_timer.ptimer_tick, s->freq);
999         tx_ptimer_set_freq(s->l_timer[0].ptimer_frc, s->freq);
1000         ptimer_set_freq(s->l_timer[1].tick_timer.ptimer_tick, s->freq);
1001         tx_ptimer_set_freq(s->l_timer[1].ptimer_frc, s->freq);
1002     }
1003 }
1004 
1005 /* set defaul_timer values for all fields */
1006 static void exynos4210_mct_reset(DeviceState *d)
1007 {
1008     Exynos4210MCTState *s = EXYNOS4210_MCT(d);
1009     uint32_t i;
1010 
1011     s->reg_mct_cfg = 0;
1012 
1013     /* global timer */
1014     memset(&s->g_timer.reg, 0, sizeof(s->g_timer.reg));
1015     exynos4210_gfrc_tx_begin(&s->g_timer);
1016     exynos4210_gfrc_stop(&s->g_timer);
1017     exynos4210_gfrc_tx_commit(&s->g_timer);
1018 
1019     /* local timer */
1020     memset(s->l_timer[0].reg.cnt, 0, sizeof(s->l_timer[0].reg.cnt));
1021     memset(s->l_timer[1].reg.cnt, 0, sizeof(s->l_timer[1].reg.cnt));
1022     for (i = 0; i < 2; i++) {
1023         s->l_timer[i].reg.int_cstat = 0;
1024         s->l_timer[i].reg.int_enb = 0;
1025         s->l_timer[i].reg.tcon = 0;
1026         s->l_timer[i].reg.wstat = 0;
1027         s->l_timer[i].tick_timer.count = 0;
1028         s->l_timer[i].tick_timer.distance = 0;
1029         s->l_timer[i].tick_timer.progress = 0;
1030         exynos4210_lfrc_tx_begin(&s->l_timer[i]);
1031         ptimer_stop(s->l_timer[i].ptimer_frc);
1032         exynos4210_lfrc_tx_commit(&s->l_timer[i]);
1033 
1034         exynos4210_ltick_timer_init(&s->l_timer[i].tick_timer);
1035     }
1036 
1037     exynos4210_mct_update_freq(s);
1038 
1039 }
1040 
1041 /* Multi Core Timer read */
1042 static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset,
1043         unsigned size)
1044 {
1045     Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
1046     int index;
1047     int shift;
1048     uint64_t count;
1049     uint32_t value;
1050     int lt_i;
1051 
1052     switch (offset) {
1053 
1054     case MCT_CFG:
1055         value = s->reg_mct_cfg;
1056         break;
1057 
1058     case G_CNT_L: case G_CNT_U:
1059         shift = 8 * (offset & 0x4);
1060         count = exynos4210_gfrc_get_count(&s->g_timer);
1061         value = UINT32_MAX & (count >> shift);
1062         DPRINTF("read FRC=0x%llx\n", count);
1063         break;
1064 
1065     case G_CNT_WSTAT:
1066         value = s->g_timer.reg.cnt_wstat;
1067         break;
1068 
1069     case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3):
1070     case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3):
1071         index = GET_G_COMP_IDX(offset);
1072         shift = 8 * (offset & 0x4);
1073         value = UINT32_MAX & (s->g_timer.reg.comp[index] >> shift);
1074     break;
1075 
1076     case G_TCON:
1077         value = s->g_timer.reg.tcon;
1078         break;
1079 
1080     case G_INT_CSTAT:
1081         value = s->g_timer.reg.int_cstat;
1082         break;
1083 
1084     case G_INT_ENB:
1085         value = s->g_timer.reg.int_enb;
1086         break;
1087     case G_WSTAT:
1088         value = s->g_timer.reg.wstat;
1089         break;
1090 
1091     case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR:
1092     case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR:
1093         value = s->g_timer.reg.comp_add_incr[GET_G_COMP_ADD_INCR_IDX(offset)];
1094         break;
1095 
1096         /* Local timers */
1097     case L0_TCNTB: case L0_ICNTB: case L0_FRCNTB:
1098     case L1_TCNTB: case L1_ICNTB: case L1_FRCNTB:
1099         lt_i = GET_L_TIMER_IDX(offset);
1100         index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
1101         value = s->l_timer[lt_i].reg.cnt[index];
1102         break;
1103 
1104     case L0_TCNTO: case L1_TCNTO:
1105         lt_i = GET_L_TIMER_IDX(offset);
1106 
1107         value = exynos4210_ltick_cnt_get_cnto(&s->l_timer[lt_i].tick_timer);
1108         DPRINTF("local timer[%d] read TCNTO %x\n", lt_i, value);
1109         break;
1110 
1111     case L0_ICNTO: case L1_ICNTO:
1112         lt_i = GET_L_TIMER_IDX(offset);
1113 
1114         value = exynos4210_ltick_int_get_cnto(&s->l_timer[lt_i].tick_timer);
1115         DPRINTF("local timer[%d] read ICNTO %x\n", lt_i, value);
1116         break;
1117 
1118     case L0_FRCNTO: case L1_FRCNTO:
1119         lt_i = GET_L_TIMER_IDX(offset);
1120 
1121         value = exynos4210_lfrc_get_count(&s->l_timer[lt_i]);
1122         break;
1123 
1124     case L0_TCON: case L1_TCON:
1125         lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
1126         value = s->l_timer[lt_i].reg.tcon;
1127         break;
1128 
1129     case L0_INT_CSTAT: case L1_INT_CSTAT:
1130         lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
1131         value = s->l_timer[lt_i].reg.int_cstat;
1132         break;
1133 
1134     case L0_INT_ENB: case L1_INT_ENB:
1135         lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
1136         value = s->l_timer[lt_i].reg.int_enb;
1137         break;
1138 
1139     case L0_WSTAT: case L1_WSTAT:
1140         lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
1141         value = s->l_timer[lt_i].reg.wstat;
1142         break;
1143 
1144     default:
1145         hw_error("exynos4210.mct: bad read offset "
1146                 TARGET_FMT_plx "\n", offset);
1147         break;
1148     }
1149     return value;
1150 }
1151 
1152 /* MCT write */
1153 static void exynos4210_mct_write(void *opaque, hwaddr offset,
1154         uint64_t value, unsigned size)
1155 {
1156     Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
1157     int index;  /* index in buffer which represents register set */
1158     int shift;
1159     int lt_i;
1160     uint64_t new_frc;
1161     uint32_t i;
1162     uint32_t old_val;
1163 #ifdef DEBUG_MCT
1164     static uint32_t icntb_max[2] = {0};
1165     static uint32_t icntb_min[2] = {UINT32_MAX, UINT32_MAX};
1166     static uint32_t tcntb_max[2] = {0};
1167     static uint32_t tcntb_min[2] = {UINT32_MAX, UINT32_MAX};
1168 #endif
1169 
1170     new_frc = s->g_timer.reg.cnt;
1171 
1172     switch (offset) {
1173 
1174     case MCT_CFG:
1175         s->reg_mct_cfg = value;
1176         exynos4210_mct_update_freq(s);
1177         break;
1178 
1179     case G_CNT_L:
1180     case G_CNT_U:
1181         if (offset == G_CNT_L) {
1182 
1183             DPRINTF("global timer write to reg.cntl %llx\n", value);
1184 
1185             new_frc = (s->g_timer.reg.cnt & (uint64_t)UINT32_MAX << 32) + value;
1186             s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_L;
1187         }
1188         if (offset == G_CNT_U) {
1189 
1190             DPRINTF("global timer write to reg.cntu %llx\n", value);
1191 
1192             new_frc = (s->g_timer.reg.cnt & UINT32_MAX) +
1193                     ((uint64_t)value << 32);
1194             s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_U;
1195         }
1196 
1197         s->g_timer.reg.cnt = new_frc;
1198         exynos4210_gfrc_tx_begin(&s->g_timer);
1199         exynos4210_gfrc_restart(s);
1200         exynos4210_gfrc_tx_commit(&s->g_timer);
1201         break;
1202 
1203     case G_CNT_WSTAT:
1204         s->g_timer.reg.cnt_wstat &= ~(value);
1205         break;
1206 
1207     case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3):
1208     case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3):
1209         index = GET_G_COMP_IDX(offset);
1210         shift = 8 * (offset & 0x4);
1211         s->g_timer.reg.comp[index] =
1212                 (s->g_timer.reg.comp[index] &
1213                 (((uint64_t)UINT32_MAX << 32) >> shift)) +
1214                 (value << shift);
1215 
1216         DPRINTF("comparator %d write 0x%llx val << %d\n", index, value, shift);
1217 
1218         if (offset & 0x4) {
1219             s->g_timer.reg.wstat |= G_WSTAT_COMP_U(index);
1220         } else {
1221             s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index);
1222         }
1223 
1224         exynos4210_gfrc_tx_begin(&s->g_timer);
1225         exynos4210_gfrc_restart(s);
1226         exynos4210_gfrc_tx_commit(&s->g_timer);
1227         break;
1228 
1229     case G_TCON:
1230         old_val = s->g_timer.reg.tcon;
1231         s->g_timer.reg.tcon = value;
1232         s->g_timer.reg.wstat |= G_WSTAT_TCON_WRITE;
1233 
1234         DPRINTF("global timer write to reg.g_tcon %llx\n", value);
1235 
1236         exynos4210_gfrc_tx_begin(&s->g_timer);
1237 
1238         /* Start FRC if transition from disabled to enabled */
1239         if ((value & G_TCON_TIMER_ENABLE) > (old_val &
1240                 G_TCON_TIMER_ENABLE)) {
1241             exynos4210_gfrc_start(&s->g_timer);
1242         }
1243         if ((value & G_TCON_TIMER_ENABLE) < (old_val &
1244                 G_TCON_TIMER_ENABLE)) {
1245             exynos4210_gfrc_stop(&s->g_timer);
1246         }
1247 
1248         /* Start CMP if transition from disabled to enabled */
1249         for (i = 0; i < MCT_GT_CMP_NUM; i++) {
1250             if ((value & G_TCON_COMP_ENABLE(i)) != (old_val &
1251                     G_TCON_COMP_ENABLE(i))) {
1252                 exynos4210_gfrc_restart(s);
1253             }
1254         }
1255 
1256         exynos4210_gfrc_tx_commit(&s->g_timer);
1257         break;
1258 
1259     case G_INT_CSTAT:
1260         s->g_timer.reg.int_cstat &= ~(value);
1261         for (i = 0; i < MCT_GT_CMP_NUM; i++) {
1262             if (value & G_INT_CSTAT_COMP(i)) {
1263                 exynos4210_gcomp_lower_irq(&s->g_timer, i);
1264             }
1265         }
1266         break;
1267 
1268     case G_INT_ENB:
1269         /* Raise IRQ if transition from disabled to enabled and CSTAT pending */
1270         for (i = 0; i < MCT_GT_CMP_NUM; i++) {
1271             if ((value & G_INT_ENABLE(i)) > (s->g_timer.reg.tcon &
1272                     G_INT_ENABLE(i))) {
1273                 if (s->g_timer.reg.int_cstat & G_INT_CSTAT_COMP(i)) {
1274                     exynos4210_gcomp_raise_irq(&s->g_timer, i);
1275                 }
1276             }
1277 
1278             if ((value & G_INT_ENABLE(i)) < (s->g_timer.reg.tcon &
1279                     G_INT_ENABLE(i))) {
1280                 exynos4210_gcomp_lower_irq(&s->g_timer, i);
1281             }
1282         }
1283 
1284         DPRINTF("global timer INT enable %llx\n", value);
1285         s->g_timer.reg.int_enb = value;
1286         break;
1287 
1288     case G_WSTAT:
1289         s->g_timer.reg.wstat &= ~(value);
1290         break;
1291 
1292     case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR:
1293     case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR:
1294         index = GET_G_COMP_ADD_INCR_IDX(offset);
1295         s->g_timer.reg.comp_add_incr[index] = value;
1296         s->g_timer.reg.wstat |= G_WSTAT_COMP_ADDINCR(index);
1297         break;
1298 
1299         /* Local timers */
1300     case L0_TCON: case L1_TCON:
1301         lt_i = GET_L_TIMER_IDX(offset);
1302         old_val = s->l_timer[lt_i].reg.tcon;
1303 
1304         s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCON_WRITE;
1305         s->l_timer[lt_i].reg.tcon = value;
1306 
1307         /* Stop local CNT */
1308         if ((value & L_TCON_TICK_START) <
1309                 (old_val & L_TCON_TICK_START)) {
1310             DPRINTF("local timer[%d] stop cnt\n", lt_i);
1311             exynos4210_ltick_cnt_stop(&s->l_timer[lt_i].tick_timer);
1312         }
1313 
1314         /* Stop local INT */
1315         if ((value & L_TCON_INT_START) <
1316                 (old_val & L_TCON_INT_START)) {
1317             DPRINTF("local timer[%d] stop int\n", lt_i);
1318             exynos4210_ltick_int_stop(&s->l_timer[lt_i].tick_timer);
1319         }
1320 
1321         /* Start local CNT */
1322         if ((value & L_TCON_TICK_START) >
1323         (old_val & L_TCON_TICK_START)) {
1324             DPRINTF("local timer[%d] start cnt\n", lt_i);
1325             exynos4210_ltick_cnt_start(&s->l_timer[lt_i].tick_timer);
1326         }
1327 
1328         /* Start local INT */
1329         if ((value & L_TCON_INT_START) >
1330         (old_val & L_TCON_INT_START)) {
1331             DPRINTF("local timer[%d] start int\n", lt_i);
1332             exynos4210_ltick_int_start(&s->l_timer[lt_i].tick_timer);
1333         }
1334 
1335         /* Start or Stop local FRC if TCON changed */
1336         exynos4210_lfrc_tx_begin(&s->l_timer[lt_i]);
1337         if ((value & L_TCON_FRC_START) >
1338         (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) {
1339             DPRINTF("local timer[%d] start frc\n", lt_i);
1340             exynos4210_lfrc_start(&s->l_timer[lt_i]);
1341         }
1342         if ((value & L_TCON_FRC_START) <
1343                 (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) {
1344             DPRINTF("local timer[%d] stop frc\n", lt_i);
1345             exynos4210_lfrc_stop(&s->l_timer[lt_i]);
1346         }
1347         exynos4210_lfrc_tx_commit(&s->l_timer[lt_i]);
1348         break;
1349 
1350     case L0_TCNTB: case L1_TCNTB:
1351         lt_i = GET_L_TIMER_IDX(offset);
1352         index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
1353 
1354         /*
1355          * TCNTB is updated to internal register only after CNT expired.
1356          * Due to this we should reload timer to nearest moment when CNT is
1357          * expired and then in event handler update tcntb to new TCNTB value.
1358          */
1359         exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer, value,
1360                 s->l_timer[lt_i].tick_timer.icntb);
1361 
1362         s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCNTB_WRITE;
1363         s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] = value;
1364 
1365 #ifdef DEBUG_MCT
1366         if (tcntb_min[lt_i] > value) {
1367             tcntb_min[lt_i] = value;
1368         }
1369         if (tcntb_max[lt_i] < value) {
1370             tcntb_max[lt_i] = value;
1371         }
1372         DPRINTF("local timer[%d] TCNTB write %llx; max=%x, min=%x\n",
1373                 lt_i, value, tcntb_max[lt_i], tcntb_min[lt_i]);
1374 #endif
1375         break;
1376 
1377     case L0_ICNTB: case L1_ICNTB:
1378         lt_i = GET_L_TIMER_IDX(offset);
1379         index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
1380 
1381         s->l_timer[lt_i].reg.wstat |= L_WSTAT_ICNTB_WRITE;
1382         s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = value &
1383                 ~L_ICNTB_MANUAL_UPDATE;
1384 
1385         /*
1386          * We need to avoid too small values for TCNTB*ICNTB. If not, IRQ event
1387          * could raise too fast disallowing QEMU to execute target code.
1388          */
1389         if (s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] *
1390             s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] < MCT_LT_CNT_LOW_LIMIT) {
1391             if (!s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB]) {
1392                 s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] =
1393                         MCT_LT_CNT_LOW_LIMIT;
1394             } else {
1395                 s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] =
1396                         MCT_LT_CNT_LOW_LIMIT /
1397                         s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB];
1398             }
1399         }
1400 
1401         if (value & L_ICNTB_MANUAL_UPDATE) {
1402             exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer,
1403                     s->l_timer[lt_i].tick_timer.tcntb,
1404                     s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB]);
1405         }
1406 
1407 #ifdef DEBUG_MCT
1408         if (icntb_min[lt_i] > value) {
1409             icntb_min[lt_i] = value;
1410         }
1411         if (icntb_max[lt_i] < value) {
1412             icntb_max[lt_i] = value;
1413         }
1414         DPRINTF("local timer[%d] ICNTB write %llx; max=%x, min=%x\n\n",
1415                 lt_i, value, icntb_max[lt_i], icntb_min[lt_i]);
1416 #endif
1417         break;
1418 
1419     case L0_FRCNTB: case L1_FRCNTB:
1420         lt_i = GET_L_TIMER_IDX(offset);
1421         index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
1422 
1423         DPRINTF("local timer[%d] FRCNTB write %llx\n", lt_i, value);
1424 
1425         s->l_timer[lt_i].reg.wstat |= L_WSTAT_FRCCNTB_WRITE;
1426         s->l_timer[lt_i].reg.cnt[L_REG_CNT_FRCCNTB] = value;
1427 
1428         break;
1429 
1430     case L0_TCNTO: case L1_TCNTO:
1431     case L0_ICNTO: case L1_ICNTO:
1432     case L0_FRCNTO: case L1_FRCNTO:
1433         qemu_log_mask(LOG_GUEST_ERROR,
1434                       "exynos4210.mct: write to RO register " TARGET_FMT_plx,
1435                       offset);
1436         break;
1437 
1438     case L0_INT_CSTAT: case L1_INT_CSTAT:
1439         lt_i = GET_L_TIMER_IDX(offset);
1440 
1441         DPRINTF("local timer[%d] CSTAT write %llx\n", lt_i, value);
1442 
1443         s->l_timer[lt_i].reg.int_cstat &= ~value;
1444         if (!s->l_timer[lt_i].reg.int_cstat) {
1445             qemu_irq_lower(s->l_timer[lt_i].irq);
1446         }
1447         break;
1448 
1449     case L0_INT_ENB: case L1_INT_ENB:
1450         lt_i = GET_L_TIMER_IDX(offset);
1451         old_val = s->l_timer[lt_i].reg.int_enb;
1452 
1453         /* Raise Local timer IRQ if cstat is pending */
1454         if ((value & L_INT_INTENB_ICNTEIE) > (old_val & L_INT_INTENB_ICNTEIE)) {
1455             if (s->l_timer[lt_i].reg.int_cstat & L_INT_CSTAT_INTCNT) {
1456                 qemu_irq_raise(s->l_timer[lt_i].irq);
1457             }
1458         }
1459 
1460         s->l_timer[lt_i].reg.int_enb = value;
1461 
1462         break;
1463 
1464     case L0_WSTAT: case L1_WSTAT:
1465         lt_i = GET_L_TIMER_IDX(offset);
1466 
1467         s->l_timer[lt_i].reg.wstat &= ~value;
1468         break;
1469 
1470     default:
1471         hw_error("exynos4210.mct: bad write offset "
1472                 TARGET_FMT_plx "\n", offset);
1473         break;
1474     }
1475 }
1476 
1477 static const MemoryRegionOps exynos4210_mct_ops = {
1478     .read = exynos4210_mct_read,
1479     .write = exynos4210_mct_write,
1480     .endianness = DEVICE_NATIVE_ENDIAN,
1481 };
1482 
1483 /* MCT init */
1484 static void exynos4210_mct_init(Object *obj)
1485 {
1486     int i;
1487     Exynos4210MCTState *s = EXYNOS4210_MCT(obj);
1488     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
1489     QEMUBH *bh[2];
1490 
1491     /* Global timer */
1492     s->g_timer.ptimer_frc = ptimer_init(exynos4210_gfrc_event, s,
1493                                         PTIMER_POLICY_DEFAULT);
1494     memset(&s->g_timer.reg, 0, sizeof(struct gregs));
1495 
1496     /* Local timers */
1497     for (i = 0; i < 2; i++) {
1498         bh[0] = qemu_bh_new(exynos4210_ltick_event, &s->l_timer[i]);
1499         s->l_timer[i].tick_timer.ptimer_tick =
1500             ptimer_init_with_bh(bh[0], PTIMER_POLICY_DEFAULT);
1501         s->l_timer[i].ptimer_frc =
1502             ptimer_init(exynos4210_lfrc_event, &s->l_timer[i],
1503                         PTIMER_POLICY_DEFAULT);
1504         s->l_timer[i].id = i;
1505     }
1506 
1507     /* IRQs */
1508     for (i = 0; i < MCT_GT_CMP_NUM; i++) {
1509         sysbus_init_irq(dev, &s->g_timer.irq[i]);
1510     }
1511     for (i = 0; i < 2; i++) {
1512         sysbus_init_irq(dev, &s->l_timer[i].irq);
1513     }
1514 
1515     memory_region_init_io(&s->iomem, obj, &exynos4210_mct_ops, s,
1516                           "exynos4210-mct", MCT_SFR_SIZE);
1517     sysbus_init_mmio(dev, &s->iomem);
1518 }
1519 
1520 static void exynos4210_mct_class_init(ObjectClass *klass, void *data)
1521 {
1522     DeviceClass *dc = DEVICE_CLASS(klass);
1523 
1524     dc->reset = exynos4210_mct_reset;
1525     dc->vmsd = &vmstate_exynos4210_mct_state;
1526 }
1527 
1528 static const TypeInfo exynos4210_mct_info = {
1529     .name          = TYPE_EXYNOS4210_MCT,
1530     .parent        = TYPE_SYS_BUS_DEVICE,
1531     .instance_size = sizeof(Exynos4210MCTState),
1532     .instance_init = exynos4210_mct_init,
1533     .class_init    = exynos4210_mct_class_init,
1534 };
1535 
1536 static void exynos4210_mct_register_types(void)
1537 {
1538     type_register_static(&exynos4210_mct_info);
1539 }
1540 
1541 type_init(exynos4210_mct_register_types)
1542