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