Annotation of qemu/hw/exynos4210_mct.c, revision 1.1.1.1

1.1       root        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 <[email protected]>
                      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 "sysbus.h"
                     56: #include "qemu-timer.h"
                     57: #include "qemu-common.h"
                     58: #include "ptimer.h"
                     59: 
                     60: #include "exynos4210.h"
                     61: 
                     62: //#define DEBUG_MCT
                     63: 
                     64: #ifdef DEBUG_MCT
                     65: #define DPRINTF(fmt, ...) \
                     66:         do { fprintf(stdout, "MCT: [%24s:%5d] " fmt, __func__, __LINE__, \
                     67:                      ## __VA_ARGS__); } while (0)
                     68: #else
                     69: #define DPRINTF(fmt, ...) do {} while (0)
                     70: #endif
                     71: 
                     72: #define    MCT_CFG          0x000
                     73: #define    G_CNT_L          0x100
                     74: #define    G_CNT_U          0x104
                     75: #define    G_CNT_WSTAT      0x110
                     76: #define    G_COMP0_L        0x200
                     77: #define    G_COMP0_U        0x204
                     78: #define    G_COMP0_ADD_INCR 0x208
                     79: #define    G_COMP1_L        0x210
                     80: #define    G_COMP1_U        0x214
                     81: #define    G_COMP1_ADD_INCR 0x218
                     82: #define    G_COMP2_L        0x220
                     83: #define    G_COMP2_U        0x224
                     84: #define    G_COMP2_ADD_INCR 0x228
                     85: #define    G_COMP3_L        0x230
                     86: #define    G_COMP3_U        0x234
                     87: #define    G_COMP3_ADD_INCR 0x238
                     88: #define    G_TCON           0x240
                     89: #define    G_INT_CSTAT      0x244
                     90: #define    G_INT_ENB        0x248
                     91: #define    G_WSTAT          0x24C
                     92: #define    L0_TCNTB         0x300
                     93: #define    L0_TCNTO         0x304
                     94: #define    L0_ICNTB         0x308
                     95: #define    L0_ICNTO         0x30C
                     96: #define    L0_FRCNTB        0x310
                     97: #define    L0_FRCNTO        0x314
                     98: #define    L0_TCON          0x320
                     99: #define    L0_INT_CSTAT     0x330
                    100: #define    L0_INT_ENB       0x334
                    101: #define    L0_WSTAT         0x340
                    102: #define    L1_TCNTB         0x400
                    103: #define    L1_TCNTO         0x404
                    104: #define    L1_ICNTB         0x408
                    105: #define    L1_ICNTO         0x40C
                    106: #define    L1_FRCNTB        0x410
                    107: #define    L1_FRCNTO        0x414
                    108: #define    L1_TCON          0x420
                    109: #define    L1_INT_CSTAT     0x430
                    110: #define    L1_INT_ENB       0x434
                    111: #define    L1_WSTAT         0x440
                    112: 
                    113: #define MCT_CFG_GET_PRESCALER(x)    ((x) & 0xFF)
                    114: #define MCT_CFG_GET_DIVIDER(x)      (1 << ((x) >> 8 & 7))
                    115: 
                    116: #define GET_G_COMP_IDX(offset)          (((offset) - G_COMP0_L) / 0x10)
                    117: #define GET_G_COMP_ADD_INCR_IDX(offset) (((offset) - G_COMP0_ADD_INCR) / 0x10)
                    118: 
                    119: #define G_COMP_L(x) (G_COMP0_L + (x) * 0x10)
                    120: #define G_COMP_U(x) (G_COMP0_U + (x) * 0x10)
                    121: 
                    122: #define G_COMP_ADD_INCR(x)  (G_COMP0_ADD_INCR + (x) * 0x10)
                    123: 
                    124: /* MCT bits */
                    125: #define G_TCON_COMP_ENABLE(x)   (1 << 2 * (x))
                    126: #define G_TCON_AUTO_ICREMENT(x) (1 << (2 * (x) + 1))
                    127: #define G_TCON_TIMER_ENABLE     (1 << 8)
                    128: 
                    129: #define G_INT_ENABLE(x)         (1 << (x))
                    130: #define G_INT_CSTAT_COMP(x)     (1 << (x))
                    131: 
                    132: #define G_CNT_WSTAT_L           1
                    133: #define G_CNT_WSTAT_U           2
                    134: 
                    135: #define G_WSTAT_COMP_L(x)       (1 << 4 * (x))
                    136: #define G_WSTAT_COMP_U(x)       (1 << ((4 * (x)) + 1))
                    137: #define G_WSTAT_COMP_ADDINCR(x) (1 << ((4 * (x)) + 2))
                    138: #define G_WSTAT_TCON_WRITE      (1 << 16)
                    139: 
                    140: #define GET_L_TIMER_IDX(offset) ((((offset) & 0xF00) - L0_TCNTB) / 0x100)
                    141: #define GET_L_TIMER_CNT_REG_IDX(offset, lt_i) \
                    142:         (((offset) - (L0_TCNTB + 0x100 * (lt_i))) >> 2)
                    143: 
                    144: #define L_ICNTB_MANUAL_UPDATE   (1 << 31)
                    145: 
                    146: #define L_TCON_TICK_START       (1)
                    147: #define L_TCON_INT_START        (1 << 1)
                    148: #define L_TCON_INTERVAL_MODE    (1 << 2)
                    149: #define L_TCON_FRC_START        (1 << 3)
                    150: 
                    151: #define L_INT_CSTAT_INTCNT      (1 << 0)
                    152: #define L_INT_CSTAT_FRCCNT      (1 << 1)
                    153: 
                    154: #define L_INT_INTENB_ICNTEIE    (1 << 0)
                    155: #define L_INT_INTENB_FRCEIE     (1 << 1)
                    156: 
                    157: #define L_WSTAT_TCNTB_WRITE     (1 << 0)
                    158: #define L_WSTAT_ICNTB_WRITE     (1 << 1)
                    159: #define L_WSTAT_FRCCNTB_WRITE   (1 << 2)
                    160: #define L_WSTAT_TCON_WRITE      (1 << 3)
                    161: 
                    162: enum LocalTimerRegCntIndexes {
                    163:     L_REG_CNT_TCNTB,
                    164:     L_REG_CNT_TCNTO,
                    165:     L_REG_CNT_ICNTB,
                    166:     L_REG_CNT_ICNTO,
                    167:     L_REG_CNT_FRCCNTB,
                    168:     L_REG_CNT_FRCCNTO,
                    169: 
                    170:     L_REG_CNT_AMOUNT
                    171: };
                    172: 
                    173: #define MCT_NIRQ                6
                    174: #define MCT_SFR_SIZE            0x444
                    175: 
                    176: #define MCT_GT_CMP_NUM          4
                    177: 
                    178: #define MCT_GT_MAX_VAL          UINT64_MAX
                    179: 
                    180: #define MCT_GT_COUNTER_STEP     0x100000000ULL
                    181: #define MCT_LT_COUNTER_STEP     0x100000000ULL
                    182: #define MCT_LT_CNT_LOW_LIMIT    0x100
                    183: 
                    184: /* global timer */
                    185: typedef struct {
                    186:     qemu_irq  irq[MCT_GT_CMP_NUM];
                    187: 
                    188:     struct gregs {
                    189:         uint64_t cnt;
                    190:         uint32_t cnt_wstat;
                    191:         uint32_t tcon;
                    192:         uint32_t int_cstat;
                    193:         uint32_t int_enb;
                    194:         uint32_t wstat;
                    195:         uint64_t comp[MCT_GT_CMP_NUM];
                    196:         uint32_t comp_add_incr[MCT_GT_CMP_NUM];
                    197:     } reg;
                    198: 
                    199:     uint64_t count;            /* Value FRC was armed with */
                    200:     int32_t curr_comp;             /* Current comparator FRC is running to */
                    201: 
                    202:     ptimer_state *ptimer_frc;                   /* FRC timer */
                    203: 
                    204: } Exynos4210MCTGT;
                    205: 
                    206: /* local timer */
                    207: typedef struct {
                    208:     int         id;             /* timer id */
                    209:     qemu_irq    irq;            /* local timer irq */
                    210: 
                    211:     struct tick_timer {
                    212:         uint32_t cnt_run;           /* cnt timer is running */
                    213:         uint32_t int_run;           /* int timer is running */
                    214: 
                    215:         uint32_t last_icnto;
                    216:         uint32_t last_tcnto;
                    217:         uint32_t tcntb;             /* initial value for TCNTB */
                    218:         uint32_t icntb;             /* initial value for ICNTB */
                    219: 
                    220:         /* for step mode */
                    221:         uint64_t    distance;       /* distance to count to the next event */
                    222:         uint64_t    progress;       /* progress when counting by steps */
                    223:         uint64_t    count;          /* count to arm timer with */
                    224: 
                    225:         ptimer_state *ptimer_tick;  /* timer for tick counter */
                    226:     } tick_timer;
                    227: 
                    228:     /* use ptimer.c to represent count down timer */
                    229: 
                    230:     ptimer_state *ptimer_frc;   /* timer for free running counter */
                    231: 
                    232:     /* registers */
                    233:     struct lregs {
                    234:         uint32_t    cnt[L_REG_CNT_AMOUNT];
                    235:         uint32_t    tcon;
                    236:         uint32_t    int_cstat;
                    237:         uint32_t    int_enb;
                    238:         uint32_t    wstat;
                    239:     } reg;
                    240: 
                    241: } Exynos4210MCTLT;
                    242: 
                    243: typedef struct Exynos4210MCTState {
                    244:     SysBusDevice busdev;
                    245:     MemoryRegion iomem;
                    246: 
                    247:     /* Registers */
                    248:     uint32_t    reg_mct_cfg;
                    249: 
                    250:     Exynos4210MCTLT l_timer[2];
                    251:     Exynos4210MCTGT g_timer;
                    252: 
                    253:     uint32_t    freq;                   /* all timers tick frequency, TCLK */
                    254: } Exynos4210MCTState;
                    255: 
                    256: /*** VMState ***/
                    257: static const VMStateDescription vmstate_tick_timer = {
                    258:     .name = "exynos4210.mct.tick_timer",
                    259:     .version_id = 1,
                    260:     .minimum_version_id = 1,
                    261:     .minimum_version_id_old = 1,
                    262:     .fields = (VMStateField[]) {
                    263:         VMSTATE_UINT32(cnt_run, struct tick_timer),
                    264:         VMSTATE_UINT32(int_run, struct tick_timer),
                    265:         VMSTATE_UINT32(last_icnto, struct tick_timer),
                    266:         VMSTATE_UINT32(last_tcnto, struct tick_timer),
                    267:         VMSTATE_UINT32(tcntb, struct tick_timer),
                    268:         VMSTATE_UINT32(icntb, struct tick_timer),
                    269:         VMSTATE_UINT64(distance, struct tick_timer),
                    270:         VMSTATE_UINT64(progress, struct tick_timer),
                    271:         VMSTATE_UINT64(count, struct tick_timer),
                    272:         VMSTATE_PTIMER(ptimer_tick, struct tick_timer),
                    273:         VMSTATE_END_OF_LIST()
                    274:     }
                    275: };
                    276: 
                    277: static const VMStateDescription vmstate_lregs = {
                    278:     .name = "exynos4210.mct.lregs",
                    279:     .version_id = 1,
                    280:     .minimum_version_id = 1,
                    281:     .minimum_version_id_old = 1,
                    282:     .fields = (VMStateField[]) {
                    283:         VMSTATE_UINT32_ARRAY(cnt, struct lregs, L_REG_CNT_AMOUNT),
                    284:         VMSTATE_UINT32(tcon, struct lregs),
                    285:         VMSTATE_UINT32(int_cstat, struct lregs),
                    286:         VMSTATE_UINT32(int_enb, struct lregs),
                    287:         VMSTATE_UINT32(wstat, struct lregs),
                    288:         VMSTATE_END_OF_LIST()
                    289:     }
                    290: };
                    291: 
                    292: static const VMStateDescription vmstate_exynos4210_mct_lt = {
                    293:     .name = "exynos4210.mct.lt",
                    294:     .version_id = 1,
                    295:     .minimum_version_id = 1,
                    296:     .minimum_version_id_old = 1,
                    297:     .fields = (VMStateField[]) {
                    298:         VMSTATE_INT32(id, Exynos4210MCTLT),
                    299:         VMSTATE_STRUCT(tick_timer, Exynos4210MCTLT, 0,
                    300:                 vmstate_tick_timer,
                    301:                 struct tick_timer),
                    302:         VMSTATE_PTIMER(ptimer_frc, Exynos4210MCTLT),
                    303:         VMSTATE_STRUCT(reg, Exynos4210MCTLT, 0,
                    304:                 vmstate_lregs,
                    305:                 struct lregs),
                    306:         VMSTATE_END_OF_LIST()
                    307:     }
                    308: };
                    309: 
                    310: static const VMStateDescription vmstate_gregs = {
                    311:     .name = "exynos4210.mct.lregs",
                    312:     .version_id = 1,
                    313:     .minimum_version_id = 1,
                    314:     .minimum_version_id_old = 1,
                    315:     .fields = (VMStateField[]) {
                    316:         VMSTATE_UINT64(cnt, struct gregs),
                    317:         VMSTATE_UINT32(cnt_wstat, struct gregs),
                    318:         VMSTATE_UINT32(tcon, struct gregs),
                    319:         VMSTATE_UINT32(int_cstat, struct gregs),
                    320:         VMSTATE_UINT32(int_enb, struct gregs),
                    321:         VMSTATE_UINT32(wstat, struct gregs),
                    322:         VMSTATE_UINT64_ARRAY(comp, struct gregs, MCT_GT_CMP_NUM),
                    323:         VMSTATE_UINT32_ARRAY(comp_add_incr, struct gregs,
                    324:                 MCT_GT_CMP_NUM),
                    325:         VMSTATE_END_OF_LIST()
                    326:     }
                    327: };
                    328: 
                    329: static const VMStateDescription vmstate_exynos4210_mct_gt = {
                    330:     .name = "exynos4210.mct.lt",
                    331:     .version_id = 1,
                    332:     .minimum_version_id = 1,
                    333:     .minimum_version_id_old = 1,
                    334:     .fields = (VMStateField[]) {
                    335:         VMSTATE_STRUCT(reg, Exynos4210MCTGT, 0, vmstate_gregs,
                    336:                 struct gregs),
                    337:         VMSTATE_UINT64(count, Exynos4210MCTGT),
                    338:         VMSTATE_INT32(curr_comp, Exynos4210MCTGT),
                    339:         VMSTATE_PTIMER(ptimer_frc, Exynos4210MCTGT),
                    340:         VMSTATE_END_OF_LIST()
                    341:     }
                    342: };
                    343: 
                    344: static const VMStateDescription vmstate_exynos4210_mct_state = {
                    345:     .name = "exynos4210.mct",
                    346:     .version_id = 1,
                    347:     .minimum_version_id = 1,
                    348:     .minimum_version_id_old = 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:  */
                    365: static void exynos4210_gfrc_set_count(Exynos4210MCTGT *s, uint64_t count)
                    366: {
                    367:     s->count = count;
                    368:     DPRINTF("global timer frc set count 0x%llx\n", count);
                    369:     ptimer_set_count(s->ptimer_frc, count);
                    370: }
                    371: 
                    372: /*
                    373:  * Get counter of FRC global timer.
                    374:  */
                    375: static uint64_t exynos4210_gfrc_get_count(Exynos4210MCTGT *s)
                    376: {
                    377:     uint64_t count = 0;
                    378:     count = ptimer_get_count(s->ptimer_frc);
                    379:     if (!count) {
                    380:         /* Timer event was generated and s->reg.cnt holds adequate value */
                    381:         return s->reg.cnt;
                    382:     }
                    383:     count = s->count - count;
                    384:     return s->reg.cnt + count;
                    385: }
                    386: 
                    387: /*
                    388:  * Stop global FRC timer
                    389:  */
                    390: static void exynos4210_gfrc_stop(Exynos4210MCTGT *s)
                    391: {
                    392:     DPRINTF("global timer frc stop\n");
                    393: 
                    394:     ptimer_stop(s->ptimer_frc);
                    395: }
                    396: 
                    397: /*
                    398:  * Start global FRC timer
                    399:  */
                    400: static void exynos4210_gfrc_start(Exynos4210MCTGT *s)
                    401: {
                    402:     DPRINTF("global timer frc start\n");
                    403: 
                    404:     ptimer_run(s->ptimer_frc, 1);
                    405: }
                    406: 
                    407: /*
                    408:  * Find next nearest Comparator. If current Comparator value equals to other
                    409:  * Comparator value, skip them both
                    410:  */
                    411: static int32_t exynos4210_gcomp_find(Exynos4210MCTState *s)
                    412: {
                    413:     int res;
                    414:     int i;
                    415:     int enabled;
                    416:     uint64_t min;
                    417:     int min_comp_i;
                    418:     uint64_t gfrc;
                    419:     uint64_t distance;
                    420:     uint64_t distance_min;
                    421:     int comp_i;
                    422: 
                    423:     /* get gfrc count */
                    424:     gfrc = exynos4210_gfrc_get_count(&s->g_timer);
                    425: 
                    426:     min = UINT64_MAX;
                    427:     distance_min = UINT64_MAX;
                    428:     comp_i = MCT_GT_CMP_NUM;
                    429:     min_comp_i = MCT_GT_CMP_NUM;
                    430:     enabled = 0;
                    431: 
                    432:     /* lookup for nearest comparator */
                    433:     for (i = 0; i < MCT_GT_CMP_NUM; i++) {
                    434: 
                    435:         if (s->g_timer.reg.tcon & G_TCON_COMP_ENABLE(i)) {
                    436: 
                    437:             enabled = 1;
                    438: 
                    439:             if (s->g_timer.reg.comp[i] > gfrc) {
                    440:                 /* Comparator is upper then FRC */
                    441:                 distance = s->g_timer.reg.comp[i] - gfrc;
                    442: 
                    443:                 if (distance <= distance_min) {
                    444:                     distance_min = distance;
                    445:                     comp_i = i;
                    446:                 }
                    447:             } else {
                    448:                 /* Comparator is below FRC, find the smallest */
                    449: 
                    450:                 if (s->g_timer.reg.comp[i] <= min) {
                    451:                     min = s->g_timer.reg.comp[i];
                    452:                     min_comp_i = i;
                    453:                 }
                    454:             }
                    455:         }
                    456:     }
                    457: 
                    458:     if (!enabled) {
                    459:         /* All Comparators disabled */
                    460:         res = -1;
                    461:     } else if (comp_i < MCT_GT_CMP_NUM) {
                    462:         /* Found upper Comparator */
                    463:         res = comp_i;
                    464:     } else {
                    465:         /* All Comparators are below or equal to FRC  */
                    466:         res = min_comp_i;
                    467:     }
                    468: 
                    469:     DPRINTF("found comparator %d: comp 0x%llx distance 0x%llx, gfrc 0x%llx\n",
                    470:             res,
                    471:             s->g_timer.reg.comp[res],
                    472:             distance_min,
                    473:             gfrc);
                    474: 
                    475:     return res;
                    476: }
                    477: 
                    478: /*
                    479:  * Get distance to nearest Comparator
                    480:  */
                    481: static uint64_t exynos4210_gcomp_get_distance(Exynos4210MCTState *s, int32_t id)
                    482: {
                    483:     if (id == -1) {
                    484:         /* no enabled Comparators, choose max distance */
                    485:         return MCT_GT_COUNTER_STEP;
                    486:     }
                    487:     if (s->g_timer.reg.comp[id] - s->g_timer.reg.cnt < MCT_GT_COUNTER_STEP) {
                    488:         return s->g_timer.reg.comp[id] - s->g_timer.reg.cnt;
                    489:     } else {
                    490:         return MCT_GT_COUNTER_STEP;
                    491:     }
                    492: }
                    493: 
                    494: /*
                    495:  * Restart global FRC timer
                    496:  */
                    497: static void exynos4210_gfrc_restart(Exynos4210MCTState *s)
                    498: {
                    499:     uint64_t distance;
                    500: 
                    501:     exynos4210_gfrc_stop(&s->g_timer);
                    502: 
                    503:     s->g_timer.curr_comp = exynos4210_gcomp_find(s);
                    504: 
                    505:     distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp);
                    506: 
                    507:     if (distance > MCT_GT_COUNTER_STEP || !distance) {
                    508:         distance = MCT_GT_COUNTER_STEP;
                    509:     }
                    510: 
                    511:     exynos4210_gfrc_set_count(&s->g_timer, distance);
                    512:     exynos4210_gfrc_start(&s->g_timer);
                    513: }
                    514: 
                    515: /*
                    516:  * Raise global timer CMP IRQ
                    517:  */
                    518: static void exynos4210_gcomp_raise_irq(void *opaque, uint32_t id)
                    519: {
                    520:     Exynos4210MCTGT *s = opaque;
                    521: 
                    522:     /* If CSTAT is pending and IRQ is enabled */
                    523:     if ((s->reg.int_cstat & G_INT_CSTAT_COMP(id)) &&
                    524:             (s->reg.int_enb & G_INT_ENABLE(id))) {
                    525:         DPRINTF("gcmp timer[%d] IRQ\n", id);
                    526:         qemu_irq_raise(s->irq[id]);
                    527:     }
                    528: }
                    529: 
                    530: /*
                    531:  * Lower global timer CMP IRQ
                    532:  */
                    533: static void exynos4210_gcomp_lower_irq(void *opaque, uint32_t id)
                    534: {
                    535:     Exynos4210MCTGT *s = opaque;
                    536:     qemu_irq_lower(s->irq[id]);
                    537: }
                    538: 
                    539: /*
                    540:  * Global timer FRC event handler.
                    541:  * Each event occurs when internal counter reaches counter + MCT_GT_COUNTER_STEP
                    542:  * Every time we arm global FRC timer to count for MCT_GT_COUNTER_STEP value
                    543:  */
                    544: static void exynos4210_gfrc_event(void *opaque)
                    545: {
                    546:     Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
                    547:     int i;
                    548:     uint64_t distance;
                    549: 
                    550:     DPRINTF("\n");
                    551: 
                    552:     s->g_timer.reg.cnt += s->g_timer.count;
                    553: 
                    554:     /* Process all comparators */
                    555:     for (i = 0; i < MCT_GT_CMP_NUM; i++) {
                    556: 
                    557:         if (s->g_timer.reg.cnt == s->g_timer.reg.comp[i]) {
                    558:             /* reached nearest comparator */
                    559: 
                    560:             s->g_timer.reg.int_cstat |= G_INT_CSTAT_COMP(i);
                    561: 
                    562:             /* Auto increment */
                    563:             if (s->g_timer.reg.tcon & G_TCON_AUTO_ICREMENT(i)) {
                    564:                 s->g_timer.reg.comp[i] += s->g_timer.reg.comp_add_incr[i];
                    565:             }
                    566: 
                    567:             /* IRQ */
                    568:             exynos4210_gcomp_raise_irq(&s->g_timer, i);
                    569:         }
                    570:     }
                    571: 
                    572:     /* Reload FRC to reach nearest comparator */
                    573:     s->g_timer.curr_comp = exynos4210_gcomp_find(s);
                    574:     distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp);
                    575:     if (distance > MCT_GT_COUNTER_STEP) {
                    576:         distance = MCT_GT_COUNTER_STEP;
                    577:     }
                    578:     exynos4210_gfrc_set_count(&s->g_timer, distance);
                    579: 
                    580:     exynos4210_gfrc_start(&s->g_timer);
                    581: 
                    582:     return;
                    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_get_clock_ns(vm_clock);
                    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 = (Exynos4210MCTState *)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, target_phys_addr_t 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:         break;
                   1040:     case G_WSTAT:
                   1041:         value = s->g_timer.reg.wstat;
                   1042:         break;
                   1043: 
                   1044:     case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR:
                   1045:     case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR:
                   1046:         value = s->g_timer.reg.comp_add_incr[GET_G_COMP_ADD_INCR_IDX(offset)];
                   1047:         break;
                   1048: 
                   1049:         /* Local timers */
                   1050:     case L0_TCNTB: case L0_ICNTB: case L0_FRCNTB:
                   1051:     case L1_TCNTB: case L1_ICNTB: case L1_FRCNTB:
                   1052:         lt_i = GET_L_TIMER_IDX(offset);
                   1053:         index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
                   1054:         value = s->l_timer[lt_i].reg.cnt[index];
                   1055:         break;
                   1056: 
                   1057:     case L0_TCNTO: case L1_TCNTO:
                   1058:         lt_i = GET_L_TIMER_IDX(offset);
                   1059: 
                   1060:         value = exynos4210_ltick_cnt_get_cnto(&s->l_timer[lt_i].tick_timer);
                   1061:         DPRINTF("local timer[%d] read TCNTO %x\n", lt_i, value);
                   1062:         break;
                   1063: 
                   1064:     case L0_ICNTO: case L1_ICNTO:
                   1065:         lt_i = GET_L_TIMER_IDX(offset);
                   1066: 
                   1067:         value = exynos4210_ltick_int_get_cnto(&s->l_timer[lt_i].tick_timer);
                   1068:         DPRINTF("local timer[%d] read ICNTO %x\n", lt_i, value);
                   1069:         break;
                   1070: 
                   1071:     case L0_FRCNTO: case L1_FRCNTO:
                   1072:         lt_i = GET_L_TIMER_IDX(offset);
                   1073: 
                   1074:         value = exynos4210_lfrc_get_count(&s->l_timer[lt_i]);
                   1075: 
                   1076:         break;
                   1077: 
                   1078:     case L0_TCON: case L1_TCON:
                   1079:         lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
                   1080:         value = s->l_timer[lt_i].reg.tcon;
                   1081:         break;
                   1082: 
                   1083:     case L0_INT_CSTAT: case L1_INT_CSTAT:
                   1084:         lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
                   1085:         value = s->l_timer[lt_i].reg.int_cstat;
                   1086:         break;
                   1087: 
                   1088:     case L0_INT_ENB: case L1_INT_ENB:
                   1089:         lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
                   1090:         value = s->l_timer[lt_i].reg.int_enb;
                   1091:         break;
                   1092: 
                   1093:     case L0_WSTAT: case L1_WSTAT:
                   1094:         lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
                   1095:         value = s->l_timer[lt_i].reg.wstat;
                   1096:         break;
                   1097: 
                   1098:     default:
                   1099:         hw_error("exynos4210.mct: bad read offset "
                   1100:                 TARGET_FMT_plx "\n", offset);
                   1101:         break;
                   1102:     }
                   1103:     return value;
                   1104: }
                   1105: 
                   1106: /* MCT write */
                   1107: static void exynos4210_mct_write(void *opaque, target_phys_addr_t offset,
                   1108:         uint64_t value, unsigned size)
                   1109: {
                   1110:     Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
                   1111:     int index;  /* index in buffer which represents register set */
                   1112:     int shift;
                   1113:     int lt_i;
                   1114:     uint64_t new_frc;
                   1115:     uint32_t i;
                   1116:     uint32_t old_val;
                   1117: #ifdef DEBUG_MCT
                   1118:     static uint32_t icntb_max[2] = {0};
                   1119:     static uint32_t icntb_min[2] = {UINT32_MAX, UINT32_MAX};
                   1120:     static uint32_t tcntb_max[2] = {0};
                   1121:     static uint32_t tcntb_min[2] = {UINT32_MAX, UINT32_MAX};
                   1122: #endif
                   1123: 
                   1124:     new_frc = s->g_timer.reg.cnt;
                   1125: 
                   1126:     switch (offset) {
                   1127: 
                   1128:     case MCT_CFG:
                   1129:         s->reg_mct_cfg = value;
                   1130:         exynos4210_mct_update_freq(s);
                   1131:         break;
                   1132: 
                   1133:     case G_CNT_L:
                   1134:     case G_CNT_U:
                   1135:         if (offset == G_CNT_L) {
                   1136: 
                   1137:             DPRINTF("global timer write to reg.cntl %llx\n", value);
                   1138: 
                   1139:             new_frc = (s->g_timer.reg.cnt & (uint64_t)UINT32_MAX << 32) + value;
                   1140:             s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_L;
                   1141:         }
                   1142:         if (offset == G_CNT_U) {
                   1143: 
                   1144:             DPRINTF("global timer write to reg.cntu %llx\n", value);
                   1145: 
                   1146:             new_frc = (s->g_timer.reg.cnt & UINT32_MAX) +
                   1147:                     ((uint64_t)value << 32);
                   1148:             s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_U;
                   1149:         }
                   1150: 
                   1151:         s->g_timer.reg.cnt = new_frc;
                   1152:         exynos4210_gfrc_restart(s);
                   1153:         break;
                   1154: 
                   1155:     case G_CNT_WSTAT:
                   1156:         s->g_timer.reg.cnt_wstat &= ~(value);
                   1157:         break;
                   1158: 
                   1159:     case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3):
                   1160:     case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3):
                   1161:     index = GET_G_COMP_IDX(offset);
                   1162:     shift = 8 * (offset & 0x4);
                   1163:     s->g_timer.reg.comp[index] =
                   1164:             (s->g_timer.reg.comp[index] &
                   1165:             (((uint64_t)UINT32_MAX << 32) >> shift)) +
                   1166:             (value << shift);
                   1167: 
                   1168:     DPRINTF("comparator %d write 0x%llx val << %d\n", index, value, shift);
                   1169: 
                   1170:     if (offset&0x4) {
                   1171:         s->g_timer.reg.wstat |= G_WSTAT_COMP_U(index);
                   1172:     } else {
                   1173:         s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index);
                   1174:     }
                   1175: 
                   1176:     exynos4210_gfrc_restart(s);
                   1177:     break;
                   1178: 
                   1179:     case G_TCON:
                   1180:         old_val = s->g_timer.reg.tcon;
                   1181:         s->g_timer.reg.tcon = value;
                   1182:         s->g_timer.reg.wstat |= G_WSTAT_TCON_WRITE;
                   1183: 
                   1184:         DPRINTF("global timer write to reg.g_tcon %llx\n", value);
                   1185: 
                   1186:         /* Start FRC if transition from disabled to enabled */
                   1187:         if ((value & G_TCON_TIMER_ENABLE) > (old_val &
                   1188:                 G_TCON_TIMER_ENABLE)) {
                   1189:             exynos4210_gfrc_start(&s->g_timer);
                   1190:         }
                   1191:         if ((value & G_TCON_TIMER_ENABLE) < (old_val &
                   1192:                 G_TCON_TIMER_ENABLE)) {
                   1193:             exynos4210_gfrc_stop(&s->g_timer);
                   1194:         }
                   1195: 
                   1196:         /* Start CMP if transition from disabled to enabled */
                   1197:         for (i = 0; i < MCT_GT_CMP_NUM; i++) {
                   1198:             if ((value & G_TCON_COMP_ENABLE(i)) != (old_val &
                   1199:                     G_TCON_COMP_ENABLE(i))) {
                   1200:                 exynos4210_gfrc_restart(s);
                   1201:             }
                   1202:         }
                   1203:         break;
                   1204: 
                   1205:     case G_INT_CSTAT:
                   1206:         s->g_timer.reg.int_cstat &= ~(value);
                   1207:         for (i = 0; i < MCT_GT_CMP_NUM; i++) {
                   1208:             if (value & G_INT_CSTAT_COMP(i)) {
                   1209:                 exynos4210_gcomp_lower_irq(&s->g_timer, i);
                   1210:             }
                   1211:         }
                   1212:         break;
                   1213: 
                   1214:     case G_INT_ENB:
                   1215: 
                   1216:         /* Raise IRQ if transition from disabled to enabled and CSTAT pending */
                   1217:         for (i = 0; i < MCT_GT_CMP_NUM; i++) {
                   1218:             if ((value & G_INT_ENABLE(i)) > (s->g_timer.reg.tcon &
                   1219:                     G_INT_ENABLE(i))) {
                   1220:                 if (s->g_timer.reg.int_cstat & G_INT_CSTAT_COMP(i)) {
                   1221:                     exynos4210_gcomp_raise_irq(&s->g_timer, i);
                   1222:                 }
                   1223:             }
                   1224: 
                   1225:             if ((value & G_INT_ENABLE(i)) < (s->g_timer.reg.tcon &
                   1226:                     G_INT_ENABLE(i))) {
                   1227:                 exynos4210_gcomp_lower_irq(&s->g_timer, i);
                   1228:             }
                   1229:         }
                   1230: 
                   1231:         DPRINTF("global timer INT enable %llx\n", value);
                   1232:         s->g_timer.reg.int_enb = value;
                   1233:         break;
                   1234: 
                   1235:     case G_WSTAT:
                   1236:         s->g_timer.reg.wstat &= ~(value);
                   1237:         break;
                   1238: 
                   1239:     case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR:
                   1240:     case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR:
                   1241:         index = GET_G_COMP_ADD_INCR_IDX(offset);
                   1242:         s->g_timer.reg.comp_add_incr[index] = value;
                   1243:         s->g_timer.reg.wstat |= G_WSTAT_COMP_ADDINCR(index);
                   1244:         break;
                   1245: 
                   1246:         /* Local timers */
                   1247:     case L0_TCON: case L1_TCON:
                   1248:         lt_i = GET_L_TIMER_IDX(offset);
                   1249:         old_val = s->l_timer[lt_i].reg.tcon;
                   1250: 
                   1251:         s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCON_WRITE;
                   1252:         s->l_timer[lt_i].reg.tcon = value;
                   1253: 
                   1254:         /* Stop local CNT */
                   1255:         if ((value & L_TCON_TICK_START) <
                   1256:                 (old_val & L_TCON_TICK_START)) {
                   1257:             DPRINTF("local timer[%d] stop cnt\n", lt_i);
                   1258:             exynos4210_ltick_cnt_stop(&s->l_timer[lt_i].tick_timer);
                   1259:         }
                   1260: 
                   1261:         /* Stop local INT */
                   1262:         if ((value & L_TCON_INT_START) <
                   1263:                 (old_val & L_TCON_INT_START)) {
                   1264:             DPRINTF("local timer[%d] stop int\n", lt_i);
                   1265:             exynos4210_ltick_int_stop(&s->l_timer[lt_i].tick_timer);
                   1266:         }
                   1267: 
                   1268:         /* Start local CNT */
                   1269:         if ((value & L_TCON_TICK_START) >
                   1270:         (old_val & L_TCON_TICK_START)) {
                   1271:             DPRINTF("local timer[%d] start cnt\n", lt_i);
                   1272:             exynos4210_ltick_cnt_start(&s->l_timer[lt_i].tick_timer);
                   1273:         }
                   1274: 
                   1275:         /* Start local INT */
                   1276:         if ((value & L_TCON_INT_START) >
                   1277:         (old_val & L_TCON_INT_START)) {
                   1278:             DPRINTF("local timer[%d] start int\n", lt_i);
                   1279:             exynos4210_ltick_int_start(&s->l_timer[lt_i].tick_timer);
                   1280:         }
                   1281: 
                   1282:         /* Start or Stop local FRC if TCON changed */
                   1283:         if ((value & L_TCON_FRC_START) >
                   1284:         (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) {
                   1285:             DPRINTF("local timer[%d] start frc\n", lt_i);
                   1286:             exynos4210_lfrc_start(&s->l_timer[lt_i]);
                   1287:         }
                   1288:         if ((value & L_TCON_FRC_START) <
                   1289:                 (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) {
                   1290:             DPRINTF("local timer[%d] stop frc\n", lt_i);
                   1291:             exynos4210_lfrc_stop(&s->l_timer[lt_i]);
                   1292:         }
                   1293:         break;
                   1294: 
                   1295:     case L0_TCNTB: case L1_TCNTB:
                   1296: 
                   1297:         lt_i = GET_L_TIMER_IDX(offset);
                   1298:         index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
                   1299: 
                   1300:         /*
                   1301:          * TCNTB is updated to internal register only after CNT expired.
                   1302:          * Due to this we should reload timer to nearest moment when CNT is
                   1303:          * expired and then in event handler update tcntb to new TCNTB value.
                   1304:          */
                   1305:         exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer, value,
                   1306:                 s->l_timer[lt_i].tick_timer.icntb);
                   1307: 
                   1308:         s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCNTB_WRITE;
                   1309:         s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] = value;
                   1310: 
                   1311: #ifdef DEBUG_MCT
                   1312:         if (tcntb_min[lt_i] > value) {
                   1313:             tcntb_min[lt_i] = value;
                   1314:         }
                   1315:         if (tcntb_max[lt_i] < value) {
                   1316:             tcntb_max[lt_i] = value;
                   1317:         }
                   1318:         DPRINTF("local timer[%d] TCNTB write %llx; max=%x, min=%x\n",
                   1319:                 lt_i, value, tcntb_max[lt_i], tcntb_min[lt_i]);
                   1320: #endif
                   1321:         break;
                   1322: 
                   1323:     case L0_ICNTB: case L1_ICNTB:
                   1324: 
                   1325:         lt_i = GET_L_TIMER_IDX(offset);
                   1326:         index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
                   1327: 
                   1328:         s->l_timer[lt_i].reg.wstat |= L_WSTAT_ICNTB_WRITE;
                   1329:         s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = value &
                   1330:                 ~L_ICNTB_MANUAL_UPDATE;
                   1331: 
                   1332:         /*
                   1333:          * We need to avoid too small values for TCNTB*ICNTB. If not, IRQ event
                   1334:          * could raise too fast disallowing QEMU to execute target code.
                   1335:          */
                   1336:         if (s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] *
                   1337:             s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] < MCT_LT_CNT_LOW_LIMIT) {
                   1338:             if (!s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB]) {
                   1339:                 s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] =
                   1340:                         MCT_LT_CNT_LOW_LIMIT;
                   1341:             } else {
                   1342:                 s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] =
                   1343:                         MCT_LT_CNT_LOW_LIMIT /
                   1344:                         s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB];
                   1345:             }
                   1346:         }
                   1347: 
                   1348:         if (value & L_ICNTB_MANUAL_UPDATE) {
                   1349:             exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer,
                   1350:                     s->l_timer[lt_i].tick_timer.tcntb,
                   1351:                     s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB]);
                   1352:         }
                   1353: 
                   1354: #ifdef DEBUG_MCT
                   1355:         if (icntb_min[lt_i] > value) {
                   1356:             icntb_min[lt_i] = value;
                   1357:         }
                   1358:         if (icntb_max[lt_i] < value) {
                   1359:             icntb_max[lt_i] = value;
                   1360:         }
                   1361: DPRINTF("local timer[%d] ICNTB write %llx; max=%x, min=%x\n\n",
                   1362:         lt_i, value, icntb_max[lt_i], icntb_min[lt_i]);
                   1363: #endif
                   1364: break;
                   1365: 
                   1366:     case L0_FRCNTB: case L1_FRCNTB:
                   1367: 
                   1368:         lt_i = GET_L_TIMER_IDX(offset);
                   1369:         index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
                   1370: 
                   1371:         DPRINTF("local timer[%d] FRCNTB write %llx\n", lt_i, value);
                   1372: 
                   1373:         s->l_timer[lt_i].reg.wstat |= L_WSTAT_FRCCNTB_WRITE;
                   1374:         s->l_timer[lt_i].reg.cnt[L_REG_CNT_FRCCNTB] = value;
                   1375: 
                   1376:         break;
                   1377: 
                   1378:     case L0_TCNTO: case L1_TCNTO:
                   1379:     case L0_ICNTO: case L1_ICNTO:
                   1380:     case L0_FRCNTO: case L1_FRCNTO:
                   1381:         fprintf(stderr, "\n[exynos4210.mct: write to RO register "
                   1382:                 TARGET_FMT_plx "]\n\n", offset);
                   1383:         break;
                   1384: 
                   1385:     case L0_INT_CSTAT: case L1_INT_CSTAT:
                   1386:         lt_i = GET_L_TIMER_IDX(offset);
                   1387: 
                   1388:         DPRINTF("local timer[%d] CSTAT write %llx\n", lt_i, value);
                   1389: 
                   1390:         s->l_timer[lt_i].reg.int_cstat &= ~value;
                   1391:         if (!s->l_timer[lt_i].reg.int_cstat) {
                   1392:             qemu_irq_lower(s->l_timer[lt_i].irq);
                   1393:         }
                   1394:         break;
                   1395: 
                   1396:     case L0_INT_ENB: case L1_INT_ENB:
                   1397:         lt_i = GET_L_TIMER_IDX(offset);
                   1398:         old_val = s->l_timer[lt_i].reg.int_enb;
                   1399: 
                   1400:         /* Raise Local timer IRQ if cstat is pending */
                   1401:         if ((value & L_INT_INTENB_ICNTEIE) > (old_val & L_INT_INTENB_ICNTEIE)) {
                   1402:             if (s->l_timer[lt_i].reg.int_cstat & L_INT_CSTAT_INTCNT) {
                   1403:                 qemu_irq_raise(s->l_timer[lt_i].irq);
                   1404:             }
                   1405:         }
                   1406: 
                   1407:         s->l_timer[lt_i].reg.int_enb = value;
                   1408: 
                   1409:         break;
                   1410: 
                   1411:     case L0_WSTAT: case L1_WSTAT:
                   1412:         lt_i = GET_L_TIMER_IDX(offset);
                   1413: 
                   1414:         s->l_timer[lt_i].reg.wstat &= ~value;
                   1415:         break;
                   1416: 
                   1417:     default:
                   1418:         hw_error("exynos4210.mct: bad write offset "
                   1419:                 TARGET_FMT_plx "\n", offset);
                   1420:         break;
                   1421:     }
                   1422: }
                   1423: 
                   1424: static const MemoryRegionOps exynos4210_mct_ops = {
                   1425:     .read = exynos4210_mct_read,
                   1426:     .write = exynos4210_mct_write,
                   1427:     .endianness = DEVICE_NATIVE_ENDIAN,
                   1428: };
                   1429: 
                   1430: /* MCT init */
                   1431: static int exynos4210_mct_init(SysBusDevice *dev)
                   1432: {
                   1433:     int i;
                   1434:     Exynos4210MCTState *s = FROM_SYSBUS(Exynos4210MCTState, dev);
                   1435:     QEMUBH *bh[2];
                   1436: 
                   1437:     /* Global timer */
                   1438:     bh[0] = qemu_bh_new(exynos4210_gfrc_event, s);
                   1439:     s->g_timer.ptimer_frc = ptimer_init(bh[0]);
                   1440:     memset(&s->g_timer.reg, 0, sizeof(struct gregs));
                   1441: 
                   1442:     /* Local timers */
                   1443:     for (i = 0; i < 2; i++) {
                   1444:         bh[0] = qemu_bh_new(exynos4210_ltick_event, &s->l_timer[i]);
                   1445:         bh[1] = qemu_bh_new(exynos4210_lfrc_event, &s->l_timer[i]);
                   1446:         s->l_timer[i].tick_timer.ptimer_tick = ptimer_init(bh[0]);
                   1447:         s->l_timer[i].ptimer_frc = ptimer_init(bh[1]);
                   1448:         s->l_timer[i].id = i;
                   1449:     }
                   1450: 
                   1451:     /* IRQs */
                   1452:     for (i = 0; i < MCT_GT_CMP_NUM; i++) {
                   1453:         sysbus_init_irq(dev, &s->g_timer.irq[i]);
                   1454:     }
                   1455:     for (i = 0; i < 2; i++) {
                   1456:         sysbus_init_irq(dev, &s->l_timer[i].irq);
                   1457:     }
                   1458: 
                   1459:     memory_region_init_io(&s->iomem, &exynos4210_mct_ops, s, "exynos4210-mct",
                   1460:             MCT_SFR_SIZE);
                   1461:     sysbus_init_mmio(dev, &s->iomem);
                   1462: 
                   1463:     return 0;
                   1464: }
                   1465: 
                   1466: static void exynos4210_mct_class_init(ObjectClass *klass, void *data)
                   1467: {
                   1468:     DeviceClass *dc = DEVICE_CLASS(klass);
                   1469:     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
                   1470: 
                   1471:     k->init = exynos4210_mct_init;
                   1472:     dc->reset = exynos4210_mct_reset;
                   1473:     dc->vmsd = &vmstate_exynos4210_mct_state;
                   1474: }
                   1475: 
                   1476: static TypeInfo exynos4210_mct_info = {
                   1477:     .name          = "exynos4210.mct",
                   1478:     .parent        = TYPE_SYS_BUS_DEVICE,
                   1479:     .instance_size = sizeof(Exynos4210MCTState),
                   1480:     .class_init    = exynos4210_mct_class_init,
                   1481: };
                   1482: 
                   1483: static void exynos4210_mct_register_types(void)
                   1484: {
                   1485:     type_register_static(&exynos4210_mct_info);
                   1486: }
                   1487: 
                   1488: type_init(exynos4210_mct_register_types)

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.