qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

exynos4210_mct.c (46029B)


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