~ubuntu-branches/ubuntu/saucy/qemu/saucy-proposed

« back to all changes in this revision

Viewing changes to hw/timer/exynos4210_mct.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2013-05-28 08:18:30 UTC
  • mfrom: (1.8.2) (10.1.37 sid)
  • Revision ID: package-import@ubuntu.com-20130528081830-87xl2z9fq516a814
Tags: 1.5.0+dfsg-2ubuntu1
* Merge 1.5.0+dfs-2 from debian unstable.  Remaining changes:
  - debian/control
    * update maintainer
    * remove libiscsi, usb-redir, vde, vnc-jpeg, and libssh2-1-dev
      from build-deps
    * enable rbd
    * add qemu-system and qemu-common B/R to qemu-keymaps
    * add D:udev, R:qemu, R:qemu-common and B:qemu-common to
      qemu-system-common
    * qemu-system-arm, qemu-system-ppc, qemu-system-sparc:
      - add qemu-kvm to Provides
      - add qemu-common, qemu-kvm, kvm to B/R
      - remove openbios-sparc from qemu-system-sparc D
    * qemu-system-x86:
      - add qemu-common to Breaks/Replaces.
      - add cpu-checker to Recommends.
    * qemu-user: add B/R:qemu-kvm
    * qemu-kvm:
      - add armhf armel powerpc sparc to Architecture
      - C/R/P: qemu-kvm-spice
    * add qemu-common package
    * drop qemu-slof which is not packaged in ubuntu
  - add qemu-system-common.links for tap ifup/down scripts and OVMF link.
  - qemu-system-x86.links:
    * remove pxe rom links which are in kvm-ipxe
    * add symlink for kvm.1 manpage
  - debian/rules
    * add kvm-spice symlink to qemu-kvm
    * call dh_installmodules for qemu-system-x86
    * update dh_installinit to install upstart script
    * run dh_installman (Closes: #709241) (cherrypicked from 1.5.0+dfsg-2)
  - Add qemu-utils.links for kvm-* symlinks.
  - Add qemu-system-x86.qemu-kvm.upstart and .default
  - Add qemu-system-x86.modprobe to set nesting=1
  - Add qemu-system-common.preinst to add kvm group
  - qemu-system-common.postinst: remove bad group acl if there, then have
    udev relabel /dev/kvm.
  - Dropped patches:
    * 0001-fix-wrong-output-with-info-chardev-for-tcp-socket.patch
  - Kept patches:
    * expose_vms_qemu64cpu.patch - updated
    * gridcentric patch - updated
    * linaro arm patches from qemu-linaro rebasing branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Samsung exynos4210 Multi Core timer
 
3
 *
 
4
 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
 
5
 * All rights reserved.
 
6
 *
 
7
 * Evgeny Voevodin <e.voevodin@samsung.com>
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or modify it
 
10
 * under the terms of the GNU General Public License as published by the
 
11
 * Free Software Foundation; either version 2 of the License, or (at your
 
12
 * option) any later version.
 
13
 *
 
14
 * This program is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
17
 * See the GNU General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU General Public License along
 
20
 * with this program; if not, see <http://www.gnu.org/licenses/>.
 
21
 */
 
22
 
 
23
/*
 
24
 * Global Timer:
 
25
 *
 
26
 * Consists of two timers. First represents Free Running Counter and second
 
27
 * is used to measure interval from FRC to nearest comparator.
 
28
 *
 
29
 *        0                                                           UINT64_MAX
 
30
 *        |                              timer0                             |
 
31
 *        | <-------------------------------------------------------------- |
 
32
 *        | --------------------------------------------frc---------------> |
 
33
 *        |______________________________________________|__________________|
 
34
 *                CMP0          CMP1             CMP2    |           CMP3
 
35
 *                                                     __|            |_
 
36
 *                                                     |     timer1     |
 
37
 *                                                     | -------------> |
 
38
 *                                                    frc              CMPx
 
39
 *
 
40
 * Problem: when implementing global timer as is, overflow arises.
 
41
 * next_time = cur_time + period * count;
 
42
 * period and count are 64 bits width.
 
43
 * Lets arm timer for MCT_GT_COUNTER_STEP count and update internal G_CNT
 
44
 * register during each event.
 
45
 *
 
46
 * Problem: both timers need to be implemented using MCT_XT_COUNTER_STEP because
 
47
 * local timer contains two counters: TCNT and ICNT. TCNT == 0 -> ICNT--.
 
48
 * IRQ is generated when ICNT riches zero. Implementation where TCNT == 0
 
49
 * generates IRQs suffers from too frequently events. Better to have one
 
50
 * uint64_t counter equal to TCNT*ICNT and arm ptimer.c for a minimum(TCNT*ICNT,
 
51
 * MCT_GT_COUNTER_STEP); (yes, if target tunes ICNT * TCNT to be too low values,
 
52
 * there is no way to avoid frequently events).
 
53
 */
 
54
 
 
55
#include "hw/sysbus.h"
 
56
#include "qemu/timer.h"
 
57
#include "qemu-common.h"
 
58
#include "hw/ptimer.h"
 
59
 
 
60
#include "hw/arm/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
    count = s->count - count;
 
380
    return s->reg.cnt + count;
 
381
}
 
382
 
 
383
/*
 
384
 * Stop global FRC timer
 
385
 */
 
386
static void exynos4210_gfrc_stop(Exynos4210MCTGT *s)
 
387
{
 
388
    DPRINTF("global timer frc stop\n");
 
389
 
 
390
    ptimer_stop(s->ptimer_frc);
 
391
}
 
392
 
 
393
/*
 
394
 * Start global FRC timer
 
395
 */
 
396
static void exynos4210_gfrc_start(Exynos4210MCTGT *s)
 
397
{
 
398
    DPRINTF("global timer frc start\n");
 
399
 
 
400
    ptimer_run(s->ptimer_frc, 1);
 
401
}
 
402
 
 
403
/*
 
404
 * Find next nearest Comparator. If current Comparator value equals to other
 
405
 * Comparator value, skip them both
 
406
 */
 
407
static int32_t exynos4210_gcomp_find(Exynos4210MCTState *s)
 
408
{
 
409
    int res;
 
410
    int i;
 
411
    int enabled;
 
412
    uint64_t min;
 
413
    int min_comp_i;
 
414
    uint64_t gfrc;
 
415
    uint64_t distance;
 
416
    uint64_t distance_min;
 
417
    int comp_i;
 
418
 
 
419
    /* get gfrc count */
 
420
    gfrc = exynos4210_gfrc_get_count(&s->g_timer);
 
421
 
 
422
    min = UINT64_MAX;
 
423
    distance_min = UINT64_MAX;
 
424
    comp_i = MCT_GT_CMP_NUM;
 
425
    min_comp_i = MCT_GT_CMP_NUM;
 
426
    enabled = 0;
 
427
 
 
428
    /* lookup for nearest comparator */
 
429
    for (i = 0; i < MCT_GT_CMP_NUM; i++) {
 
430
 
 
431
        if (s->g_timer.reg.tcon & G_TCON_COMP_ENABLE(i)) {
 
432
 
 
433
            enabled = 1;
 
434
 
 
435
            if (s->g_timer.reg.comp[i] > gfrc) {
 
436
                /* Comparator is upper then FRC */
 
437
                distance = s->g_timer.reg.comp[i] - gfrc;
 
438
 
 
439
                if (distance <= distance_min) {
 
440
                    distance_min = distance;
 
441
                    comp_i = i;
 
442
                }
 
443
            } else {
 
444
                /* Comparator is below FRC, find the smallest */
 
445
 
 
446
                if (s->g_timer.reg.comp[i] <= min) {
 
447
                    min = s->g_timer.reg.comp[i];
 
448
                    min_comp_i = i;
 
449
                }
 
450
            }
 
451
        }
 
452
    }
 
453
 
 
454
    if (!enabled) {
 
455
        /* All Comparators disabled */
 
456
        res = -1;
 
457
    } else if (comp_i < MCT_GT_CMP_NUM) {
 
458
        /* Found upper Comparator */
 
459
        res = comp_i;
 
460
    } else {
 
461
        /* All Comparators are below or equal to FRC  */
 
462
        res = min_comp_i;
 
463
    }
 
464
 
 
465
    DPRINTF("found comparator %d: comp 0x%llx distance 0x%llx, gfrc 0x%llx\n",
 
466
            res,
 
467
            s->g_timer.reg.comp[res],
 
468
            distance_min,
 
469
            gfrc);
 
470
 
 
471
    return res;
 
472
}
 
473
 
 
474
/*
 
475
 * Get distance to nearest Comparator
 
476
 */
 
477
static uint64_t exynos4210_gcomp_get_distance(Exynos4210MCTState *s, int32_t id)
 
478
{
 
479
    if (id == -1) {
 
480
        /* no enabled Comparators, choose max distance */
 
481
        return MCT_GT_COUNTER_STEP;
 
482
    }
 
483
    if (s->g_timer.reg.comp[id] - s->g_timer.reg.cnt < MCT_GT_COUNTER_STEP) {
 
484
        return s->g_timer.reg.comp[id] - s->g_timer.reg.cnt;
 
485
    } else {
 
486
        return MCT_GT_COUNTER_STEP;
 
487
    }
 
488
}
 
489
 
 
490
/*
 
491
 * Restart global FRC timer
 
492
 */
 
493
static void exynos4210_gfrc_restart(Exynos4210MCTState *s)
 
494
{
 
495
    uint64_t distance;
 
496
 
 
497
    exynos4210_gfrc_stop(&s->g_timer);
 
498
 
 
499
    s->g_timer.curr_comp = exynos4210_gcomp_find(s);
 
500
 
 
501
    distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp);
 
502
 
 
503
    if (distance > MCT_GT_COUNTER_STEP || !distance) {
 
504
        distance = MCT_GT_COUNTER_STEP;
 
505
    }
 
506
 
 
507
    exynos4210_gfrc_set_count(&s->g_timer, distance);
 
508
    exynos4210_gfrc_start(&s->g_timer);
 
509
}
 
510
 
 
511
/*
 
512
 * Raise global timer CMP IRQ
 
513
 */
 
514
static void exynos4210_gcomp_raise_irq(void *opaque, uint32_t id)
 
515
{
 
516
    Exynos4210MCTGT *s = opaque;
 
517
 
 
518
    /* If CSTAT is pending and IRQ is enabled */
 
519
    if ((s->reg.int_cstat & G_INT_CSTAT_COMP(id)) &&
 
520
            (s->reg.int_enb & G_INT_ENABLE(id))) {
 
521
        DPRINTF("gcmp timer[%d] IRQ\n", id);
 
522
        qemu_irq_raise(s->irq[id]);
 
523
    }
 
524
}
 
525
 
 
526
/*
 
527
 * Lower global timer CMP IRQ
 
528
 */
 
529
static void exynos4210_gcomp_lower_irq(void *opaque, uint32_t id)
 
530
{
 
531
    Exynos4210MCTGT *s = opaque;
 
532
    qemu_irq_lower(s->irq[id]);
 
533
}
 
534
 
 
535
/*
 
536
 * Global timer FRC event handler.
 
537
 * Each event occurs when internal counter reaches counter + MCT_GT_COUNTER_STEP
 
538
 * Every time we arm global FRC timer to count for MCT_GT_COUNTER_STEP value
 
539
 */
 
540
static void exynos4210_gfrc_event(void *opaque)
 
541
{
 
542
    Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
 
543
    int i;
 
544
    uint64_t distance;
 
545
 
 
546
    DPRINTF("\n");
 
547
 
 
548
    s->g_timer.reg.cnt += s->g_timer.count;
 
549
 
 
550
    /* Process all comparators */
 
551
    for (i = 0; i < MCT_GT_CMP_NUM; i++) {
 
552
 
 
553
        if (s->g_timer.reg.cnt == s->g_timer.reg.comp[i]) {
 
554
            /* reached nearest comparator */
 
555
 
 
556
            s->g_timer.reg.int_cstat |= G_INT_CSTAT_COMP(i);
 
557
 
 
558
            /* Auto increment */
 
559
            if (s->g_timer.reg.tcon & G_TCON_AUTO_ICREMENT(i)) {
 
560
                s->g_timer.reg.comp[i] += s->g_timer.reg.comp_add_incr[i];
 
561
            }
 
562
 
 
563
            /* IRQ */
 
564
            exynos4210_gcomp_raise_irq(&s->g_timer, i);
 
565
        }
 
566
    }
 
567
 
 
568
    /* Reload FRC to reach nearest comparator */
 
569
    s->g_timer.curr_comp = exynos4210_gcomp_find(s);
 
570
    distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp);
 
571
    if (distance > MCT_GT_COUNTER_STEP || !distance) {
 
572
        distance = MCT_GT_COUNTER_STEP;
 
573
    }
 
574
    exynos4210_gfrc_set_count(&s->g_timer, distance);
 
575
 
 
576
    exynos4210_gfrc_start(&s->g_timer);
 
577
}
 
578
 
 
579
/*
 
580
 * Get counter of FRC local timer.
 
581
 */
 
582
static uint64_t exynos4210_lfrc_get_count(Exynos4210MCTLT *s)
 
583
{
 
584
    return ptimer_get_count(s->ptimer_frc);
 
585
}
 
586
 
 
587
/*
 
588
 * Set counter of FRC local timer.
 
589
 */
 
590
static void exynos4210_lfrc_update_count(Exynos4210MCTLT *s)
 
591
{
 
592
    if (!s->reg.cnt[L_REG_CNT_FRCCNTB]) {
 
593
        ptimer_set_count(s->ptimer_frc, MCT_LT_COUNTER_STEP);
 
594
    } else {
 
595
        ptimer_set_count(s->ptimer_frc, s->reg.cnt[L_REG_CNT_FRCCNTB]);
 
596
    }
 
597
}
 
598
 
 
599
/*
 
600
 * Start local FRC timer
 
601
 */
 
602
static void exynos4210_lfrc_start(Exynos4210MCTLT *s)
 
603
{
 
604
    ptimer_run(s->ptimer_frc, 1);
 
605
}
 
606
 
 
607
/*
 
608
 * Stop local FRC timer
 
609
 */
 
610
static void exynos4210_lfrc_stop(Exynos4210MCTLT *s)
 
611
{
 
612
    ptimer_stop(s->ptimer_frc);
 
613
}
 
614
 
 
615
/*
 
616
 * Local timer free running counter tick handler
 
617
 */
 
618
static void exynos4210_lfrc_event(void *opaque)
 
619
{
 
620
    Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque;
 
621
 
 
622
    /* local frc expired */
 
623
 
 
624
    DPRINTF("\n");
 
625
 
 
626
    s->reg.int_cstat |= L_INT_CSTAT_FRCCNT;
 
627
 
 
628
    /* update frc counter */
 
629
    exynos4210_lfrc_update_count(s);
 
630
 
 
631
    /* raise irq */
 
632
    if (s->reg.int_enb & L_INT_INTENB_FRCEIE) {
 
633
        qemu_irq_raise(s->irq);
 
634
    }
 
635
 
 
636
    /*  we reached here, this means that timer is enabled */
 
637
    exynos4210_lfrc_start(s);
 
638
}
 
639
 
 
640
static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s);
 
641
static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s);
 
642
static void exynos4210_ltick_recalc_count(struct tick_timer *s);
 
643
 
 
644
/*
 
645
 * Action on enabling local tick int timer
 
646
 */
 
647
static void exynos4210_ltick_int_start(struct tick_timer *s)
 
648
{
 
649
    if (!s->int_run) {
 
650
        s->int_run = 1;
 
651
    }
 
652
}
 
653
 
 
654
/*
 
655
 * Action on disabling local tick int timer
 
656
 */
 
657
static void exynos4210_ltick_int_stop(struct tick_timer *s)
 
658
{
 
659
    if (s->int_run) {
 
660
        s->last_icnto = exynos4210_ltick_int_get_cnto(s);
 
661
        s->int_run = 0;
 
662
    }
 
663
}
 
664
 
 
665
/*
 
666
 * Get count for INT timer
 
667
 */
 
668
static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s)
 
669
{
 
670
    uint32_t icnto;
 
671
    uint64_t remain;
 
672
    uint64_t count;
 
673
    uint64_t counted;
 
674
    uint64_t cur_progress;
 
675
 
 
676
    count = ptimer_get_count(s->ptimer_tick);
 
677
    if (count) {
 
678
        /* timer is still counting, called not from event */
 
679
        counted = s->count - ptimer_get_count(s->ptimer_tick);
 
680
        cur_progress = s->progress + counted;
 
681
    } else {
 
682
        /* timer expired earlier */
 
683
        cur_progress = s->progress;
 
684
    }
 
685
 
 
686
    remain = s->distance - cur_progress;
 
687
 
 
688
    if (!s->int_run) {
 
689
        /* INT is stopped. */
 
690
        icnto = s->last_icnto;
 
691
    } else {
 
692
        /* Both are counting */
 
693
        icnto = remain / s->tcntb;
 
694
    }
 
695
 
 
696
    return icnto;
 
697
}
 
698
 
 
699
/*
 
700
 * Start local tick cnt timer.
 
701
 */
 
702
static void exynos4210_ltick_cnt_start(struct tick_timer *s)
 
703
{
 
704
    if (!s->cnt_run) {
 
705
 
 
706
        exynos4210_ltick_recalc_count(s);
 
707
        ptimer_set_count(s->ptimer_tick, s->count);
 
708
        ptimer_run(s->ptimer_tick, 1);
 
709
 
 
710
        s->cnt_run = 1;
 
711
    }
 
712
}
 
713
 
 
714
/*
 
715
 * Stop local tick cnt timer.
 
716
 */
 
717
static void exynos4210_ltick_cnt_stop(struct tick_timer *s)
 
718
{
 
719
    if (s->cnt_run) {
 
720
 
 
721
        s->last_tcnto = exynos4210_ltick_cnt_get_cnto(s);
 
722
 
 
723
        if (s->int_run) {
 
724
            exynos4210_ltick_int_stop(s);
 
725
        }
 
726
 
 
727
        ptimer_stop(s->ptimer_tick);
 
728
 
 
729
        s->cnt_run = 0;
 
730
    }
 
731
}
 
732
 
 
733
/*
 
734
 * Get counter for CNT timer
 
735
 */
 
736
static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s)
 
737
{
 
738
    uint32_t tcnto;
 
739
    uint32_t icnto;
 
740
    uint64_t remain;
 
741
    uint64_t counted;
 
742
    uint64_t count;
 
743
    uint64_t cur_progress;
 
744
 
 
745
    count = ptimer_get_count(s->ptimer_tick);
 
746
    if (count) {
 
747
        /* timer is still counting, called not from event */
 
748
        counted = s->count - ptimer_get_count(s->ptimer_tick);
 
749
        cur_progress = s->progress + counted;
 
750
    } else {
 
751
        /* timer expired earlier */
 
752
        cur_progress = s->progress;
 
753
    }
 
754
 
 
755
    remain = s->distance - cur_progress;
 
756
 
 
757
    if (!s->cnt_run) {
 
758
        /* Both are stopped. */
 
759
        tcnto = s->last_tcnto;
 
760
    } else if (!s->int_run) {
 
761
        /* INT counter is stopped, progress is by CNT timer */
 
762
        tcnto = remain % s->tcntb;
 
763
    } else {
 
764
        /* Both are counting */
 
765
        icnto = remain / s->tcntb;
 
766
        if (icnto) {
 
767
            tcnto = remain % (icnto * s->tcntb);
 
768
        } else {
 
769
            tcnto = remain % s->tcntb;
 
770
        }
 
771
    }
 
772
 
 
773
    return tcnto;
 
774
}
 
775
 
 
776
/*
 
777
 * Set new values of counters for CNT and INT timers
 
778
 */
 
779
static void exynos4210_ltick_set_cntb(struct tick_timer *s, uint32_t new_cnt,
 
780
        uint32_t new_int)
 
781
{
 
782
    uint32_t cnt_stopped = 0;
 
783
    uint32_t int_stopped = 0;
 
784
 
 
785
    if (s->cnt_run) {
 
786
        exynos4210_ltick_cnt_stop(s);
 
787
        cnt_stopped = 1;
 
788
    }
 
789
 
 
790
    if (s->int_run) {
 
791
        exynos4210_ltick_int_stop(s);
 
792
        int_stopped = 1;
 
793
    }
 
794
 
 
795
    s->tcntb = new_cnt + 1;
 
796
    s->icntb = new_int + 1;
 
797
 
 
798
    if (cnt_stopped) {
 
799
        exynos4210_ltick_cnt_start(s);
 
800
    }
 
801
    if (int_stopped) {
 
802
        exynos4210_ltick_int_start(s);
 
803
    }
 
804
 
 
805
}
 
806
 
 
807
/*
 
808
 * Calculate new counter value for tick timer
 
809
 */
 
810
static void exynos4210_ltick_recalc_count(struct tick_timer *s)
 
811
{
 
812
    uint64_t to_count;
 
813
 
 
814
    if ((s->cnt_run && s->last_tcnto) || (s->int_run && s->last_icnto)) {
 
815
        /*
 
816
         * one or both timers run and not counted to the end;
 
817
         * distance is not passed, recalculate with last_tcnto * last_icnto
 
818
         */
 
819
 
 
820
        if (s->last_tcnto) {
 
821
            to_count = s->last_tcnto * s->last_icnto;
 
822
        } else {
 
823
            to_count = s->last_icnto;
 
824
        }
 
825
    } else {
 
826
        /* distance is passed, recalculate with tcnto * icnto */
 
827
        if (s->icntb) {
 
828
            s->distance = s->tcntb * s->icntb;
 
829
        } else {
 
830
            s->distance = s->tcntb;
 
831
        }
 
832
 
 
833
        to_count = s->distance;
 
834
        s->progress = 0;
 
835
    }
 
836
 
 
837
    if (to_count > MCT_LT_COUNTER_STEP) {
 
838
        /* count by step */
 
839
        s->count = MCT_LT_COUNTER_STEP;
 
840
    } else {
 
841
        s->count = to_count;
 
842
    }
 
843
}
 
844
 
 
845
/*
 
846
 * Initialize tick_timer
 
847
 */
 
848
static void exynos4210_ltick_timer_init(struct tick_timer *s)
 
849
{
 
850
    exynos4210_ltick_int_stop(s);
 
851
    exynos4210_ltick_cnt_stop(s);
 
852
 
 
853
    s->count = 0;
 
854
    s->distance = 0;
 
855
    s->progress = 0;
 
856
    s->icntb = 0;
 
857
    s->tcntb = 0;
 
858
}
 
859
 
 
860
/*
 
861
 * tick_timer event.
 
862
 * Raises when abstract tick_timer expires.
 
863
 */
 
864
static void exynos4210_ltick_timer_event(struct tick_timer *s)
 
865
{
 
866
    s->progress += s->count;
 
867
}
 
868
 
 
869
/*
 
870
 * Local timer tick counter handler.
 
871
 * Don't use reloaded timers. If timer counter = zero
 
872
 * then handler called but after handler finished no
 
873
 * timer reload occurs.
 
874
 */
 
875
static void exynos4210_ltick_event(void *opaque)
 
876
{
 
877
    Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque;
 
878
    uint32_t tcnto;
 
879
    uint32_t icnto;
 
880
#ifdef DEBUG_MCT
 
881
    static uint64_t time1[2] = {0};
 
882
    static uint64_t time2[2] = {0};
 
883
#endif
 
884
 
 
885
    /* Call tick_timer event handler, it will update its tcntb and icntb. */
 
886
    exynos4210_ltick_timer_event(&s->tick_timer);
 
887
 
 
888
    /* get tick_timer cnt */
 
889
    tcnto = exynos4210_ltick_cnt_get_cnto(&s->tick_timer);
 
890
 
 
891
    /* get tick_timer int */
 
892
    icnto = exynos4210_ltick_int_get_cnto(&s->tick_timer);
 
893
 
 
894
    /* raise IRQ if needed */
 
895
    if (!icnto && s->reg.tcon & L_TCON_INT_START) {
 
896
        /* INT counter enabled and expired */
 
897
 
 
898
        s->reg.int_cstat |= L_INT_CSTAT_INTCNT;
 
899
 
 
900
        /* raise interrupt if enabled */
 
901
        if (s->reg.int_enb & L_INT_INTENB_ICNTEIE) {
 
902
#ifdef DEBUG_MCT
 
903
            time2[s->id] = qemu_get_clock_ns(vm_clock);
 
904
            DPRINTF("local timer[%d] IRQ: %llx\n", s->id,
 
905
                    time2[s->id] - time1[s->id]);
 
906
            time1[s->id] = time2[s->id];
 
907
#endif
 
908
            qemu_irq_raise(s->irq);
 
909
        }
 
910
 
 
911
        /* reload ICNTB */
 
912
        if (s->reg.tcon & L_TCON_INTERVAL_MODE) {
 
913
            exynos4210_ltick_set_cntb(&s->tick_timer,
 
914
                    s->reg.cnt[L_REG_CNT_TCNTB],
 
915
                    s->reg.cnt[L_REG_CNT_ICNTB]);
 
916
        }
 
917
    } else {
 
918
        /* reload TCNTB */
 
919
        if (!tcnto) {
 
920
            exynos4210_ltick_set_cntb(&s->tick_timer,
 
921
                    s->reg.cnt[L_REG_CNT_TCNTB],
 
922
                    icnto);
 
923
        }
 
924
    }
 
925
 
 
926
    /* start tick_timer cnt */
 
927
    exynos4210_ltick_cnt_start(&s->tick_timer);
 
928
 
 
929
    /* start tick_timer int */
 
930
    exynos4210_ltick_int_start(&s->tick_timer);
 
931
}
 
932
 
 
933
/* update timer frequency */
 
934
static void exynos4210_mct_update_freq(Exynos4210MCTState *s)
 
935
{
 
936
    uint32_t freq = s->freq;
 
937
    s->freq = 24000000 /
 
938
            ((MCT_CFG_GET_PRESCALER(s->reg_mct_cfg)+1) *
 
939
                    MCT_CFG_GET_DIVIDER(s->reg_mct_cfg));
 
940
 
 
941
    if (freq != s->freq) {
 
942
        DPRINTF("freq=%dHz\n", s->freq);
 
943
 
 
944
        /* global timer */
 
945
        ptimer_set_freq(s->g_timer.ptimer_frc, s->freq);
 
946
 
 
947
        /* local timer */
 
948
        ptimer_set_freq(s->l_timer[0].tick_timer.ptimer_tick, s->freq);
 
949
        ptimer_set_freq(s->l_timer[0].ptimer_frc, s->freq);
 
950
        ptimer_set_freq(s->l_timer[1].tick_timer.ptimer_tick, s->freq);
 
951
        ptimer_set_freq(s->l_timer[1].ptimer_frc, s->freq);
 
952
    }
 
953
}
 
954
 
 
955
/* set defaul_timer values for all fields */
 
956
static void exynos4210_mct_reset(DeviceState *d)
 
957
{
 
958
    Exynos4210MCTState *s = (Exynos4210MCTState *)d;
 
959
    uint32_t i;
 
960
 
 
961
    s->reg_mct_cfg = 0;
 
962
 
 
963
    /* global timer */
 
964
    memset(&s->g_timer.reg, 0, sizeof(s->g_timer.reg));
 
965
    exynos4210_gfrc_stop(&s->g_timer);
 
966
 
 
967
    /* local timer */
 
968
    memset(s->l_timer[0].reg.cnt, 0, sizeof(s->l_timer[0].reg.cnt));
 
969
    memset(s->l_timer[1].reg.cnt, 0, sizeof(s->l_timer[1].reg.cnt));
 
970
    for (i = 0; i < 2; i++) {
 
971
        s->l_timer[i].reg.int_cstat = 0;
 
972
        s->l_timer[i].reg.int_enb = 0;
 
973
        s->l_timer[i].reg.tcon = 0;
 
974
        s->l_timer[i].reg.wstat = 0;
 
975
        s->l_timer[i].tick_timer.count = 0;
 
976
        s->l_timer[i].tick_timer.distance = 0;
 
977
        s->l_timer[i].tick_timer.progress = 0;
 
978
        ptimer_stop(s->l_timer[i].ptimer_frc);
 
979
 
 
980
        exynos4210_ltick_timer_init(&s->l_timer[i].tick_timer);
 
981
    }
 
982
 
 
983
    exynos4210_mct_update_freq(s);
 
984
 
 
985
}
 
986
 
 
987
/* Multi Core Timer read */
 
988
static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset,
 
989
        unsigned size)
 
990
{
 
991
    Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
 
992
    int index;
 
993
    int shift;
 
994
    uint64_t count;
 
995
    uint32_t value;
 
996
    int lt_i;
 
997
 
 
998
    switch (offset) {
 
999
 
 
1000
    case MCT_CFG:
 
1001
        value = s->reg_mct_cfg;
 
1002
        break;
 
1003
 
 
1004
    case G_CNT_L: case G_CNT_U:
 
1005
        shift = 8 * (offset & 0x4);
 
1006
        count = exynos4210_gfrc_get_count(&s->g_timer);
 
1007
        value = UINT32_MAX & (count >> shift);
 
1008
        DPRINTF("read FRC=0x%llx\n", count);
 
1009
        break;
 
1010
 
 
1011
    case G_CNT_WSTAT:
 
1012
        value = s->g_timer.reg.cnt_wstat;
 
1013
        break;
 
1014
 
 
1015
    case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3):
 
1016
    case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3):
 
1017
    index = GET_G_COMP_IDX(offset);
 
1018
    shift = 8 * (offset & 0x4);
 
1019
    value = UINT32_MAX & (s->g_timer.reg.comp[index] >> shift);
 
1020
    break;
 
1021
 
 
1022
    case G_TCON:
 
1023
        value = s->g_timer.reg.tcon;
 
1024
        break;
 
1025
 
 
1026
    case G_INT_CSTAT:
 
1027
        value = s->g_timer.reg.int_cstat;
 
1028
        break;
 
1029
 
 
1030
    case G_INT_ENB:
 
1031
        value = s->g_timer.reg.int_enb;
 
1032
        break;
 
1033
        break;
 
1034
    case G_WSTAT:
 
1035
        value = s->g_timer.reg.wstat;
 
1036
        break;
 
1037
 
 
1038
    case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR:
 
1039
    case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR:
 
1040
        value = s->g_timer.reg.comp_add_incr[GET_G_COMP_ADD_INCR_IDX(offset)];
 
1041
        break;
 
1042
 
 
1043
        /* Local timers */
 
1044
    case L0_TCNTB: case L0_ICNTB: case L0_FRCNTB:
 
1045
    case L1_TCNTB: case L1_ICNTB: case L1_FRCNTB:
 
1046
        lt_i = GET_L_TIMER_IDX(offset);
 
1047
        index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
 
1048
        value = s->l_timer[lt_i].reg.cnt[index];
 
1049
        break;
 
1050
 
 
1051
    case L0_TCNTO: case L1_TCNTO:
 
1052
        lt_i = GET_L_TIMER_IDX(offset);
 
1053
 
 
1054
        value = exynos4210_ltick_cnt_get_cnto(&s->l_timer[lt_i].tick_timer);
 
1055
        DPRINTF("local timer[%d] read TCNTO %x\n", lt_i, value);
 
1056
        break;
 
1057
 
 
1058
    case L0_ICNTO: case L1_ICNTO:
 
1059
        lt_i = GET_L_TIMER_IDX(offset);
 
1060
 
 
1061
        value = exynos4210_ltick_int_get_cnto(&s->l_timer[lt_i].tick_timer);
 
1062
        DPRINTF("local timer[%d] read ICNTO %x\n", lt_i, value);
 
1063
        break;
 
1064
 
 
1065
    case L0_FRCNTO: case L1_FRCNTO:
 
1066
        lt_i = GET_L_TIMER_IDX(offset);
 
1067
 
 
1068
        value = exynos4210_lfrc_get_count(&s->l_timer[lt_i]);
 
1069
 
 
1070
        break;
 
1071
 
 
1072
    case L0_TCON: case L1_TCON:
 
1073
        lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
 
1074
        value = s->l_timer[lt_i].reg.tcon;
 
1075
        break;
 
1076
 
 
1077
    case L0_INT_CSTAT: case L1_INT_CSTAT:
 
1078
        lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
 
1079
        value = s->l_timer[lt_i].reg.int_cstat;
 
1080
        break;
 
1081
 
 
1082
    case L0_INT_ENB: case L1_INT_ENB:
 
1083
        lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
 
1084
        value = s->l_timer[lt_i].reg.int_enb;
 
1085
        break;
 
1086
 
 
1087
    case L0_WSTAT: case L1_WSTAT:
 
1088
        lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
 
1089
        value = s->l_timer[lt_i].reg.wstat;
 
1090
        break;
 
1091
 
 
1092
    default:
 
1093
        hw_error("exynos4210.mct: bad read offset "
 
1094
                TARGET_FMT_plx "\n", offset);
 
1095
        break;
 
1096
    }
 
1097
    return value;
 
1098
}
 
1099
 
 
1100
/* MCT write */
 
1101
static void exynos4210_mct_write(void *opaque, hwaddr offset,
 
1102
        uint64_t value, unsigned size)
 
1103
{
 
1104
    Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
 
1105
    int index;  /* index in buffer which represents register set */
 
1106
    int shift;
 
1107
    int lt_i;
 
1108
    uint64_t new_frc;
 
1109
    uint32_t i;
 
1110
    uint32_t old_val;
 
1111
#ifdef DEBUG_MCT
 
1112
    static uint32_t icntb_max[2] = {0};
 
1113
    static uint32_t icntb_min[2] = {UINT32_MAX, UINT32_MAX};
 
1114
    static uint32_t tcntb_max[2] = {0};
 
1115
    static uint32_t tcntb_min[2] = {UINT32_MAX, UINT32_MAX};
 
1116
#endif
 
1117
 
 
1118
    new_frc = s->g_timer.reg.cnt;
 
1119
 
 
1120
    switch (offset) {
 
1121
 
 
1122
    case MCT_CFG:
 
1123
        s->reg_mct_cfg = value;
 
1124
        exynos4210_mct_update_freq(s);
 
1125
        break;
 
1126
 
 
1127
    case G_CNT_L:
 
1128
    case G_CNT_U:
 
1129
        if (offset == G_CNT_L) {
 
1130
 
 
1131
            DPRINTF("global timer write to reg.cntl %llx\n", value);
 
1132
 
 
1133
            new_frc = (s->g_timer.reg.cnt & (uint64_t)UINT32_MAX << 32) + value;
 
1134
            s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_L;
 
1135
        }
 
1136
        if (offset == G_CNT_U) {
 
1137
 
 
1138
            DPRINTF("global timer write to reg.cntu %llx\n", value);
 
1139
 
 
1140
            new_frc = (s->g_timer.reg.cnt & UINT32_MAX) +
 
1141
                    ((uint64_t)value << 32);
 
1142
            s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_U;
 
1143
        }
 
1144
 
 
1145
        s->g_timer.reg.cnt = new_frc;
 
1146
        exynos4210_gfrc_restart(s);
 
1147
        break;
 
1148
 
 
1149
    case G_CNT_WSTAT:
 
1150
        s->g_timer.reg.cnt_wstat &= ~(value);
 
1151
        break;
 
1152
 
 
1153
    case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3):
 
1154
    case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3):
 
1155
    index = GET_G_COMP_IDX(offset);
 
1156
    shift = 8 * (offset & 0x4);
 
1157
    s->g_timer.reg.comp[index] =
 
1158
            (s->g_timer.reg.comp[index] &
 
1159
            (((uint64_t)UINT32_MAX << 32) >> shift)) +
 
1160
            (value << shift);
 
1161
 
 
1162
    DPRINTF("comparator %d write 0x%llx val << %d\n", index, value, shift);
 
1163
 
 
1164
    if (offset&0x4) {
 
1165
        s->g_timer.reg.wstat |= G_WSTAT_COMP_U(index);
 
1166
    } else {
 
1167
        s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index);
 
1168
    }
 
1169
 
 
1170
    exynos4210_gfrc_restart(s);
 
1171
    break;
 
1172
 
 
1173
    case G_TCON:
 
1174
        old_val = s->g_timer.reg.tcon;
 
1175
        s->g_timer.reg.tcon = value;
 
1176
        s->g_timer.reg.wstat |= G_WSTAT_TCON_WRITE;
 
1177
 
 
1178
        DPRINTF("global timer write to reg.g_tcon %llx\n", value);
 
1179
 
 
1180
        /* Start FRC if transition from disabled to enabled */
 
1181
        if ((value & G_TCON_TIMER_ENABLE) > (old_val &
 
1182
                G_TCON_TIMER_ENABLE)) {
 
1183
            exynos4210_gfrc_start(&s->g_timer);
 
1184
        }
 
1185
        if ((value & G_TCON_TIMER_ENABLE) < (old_val &
 
1186
                G_TCON_TIMER_ENABLE)) {
 
1187
            exynos4210_gfrc_stop(&s->g_timer);
 
1188
        }
 
1189
 
 
1190
        /* Start CMP if transition from disabled to enabled */
 
1191
        for (i = 0; i < MCT_GT_CMP_NUM; i++) {
 
1192
            if ((value & G_TCON_COMP_ENABLE(i)) != (old_val &
 
1193
                    G_TCON_COMP_ENABLE(i))) {
 
1194
                exynos4210_gfrc_restart(s);
 
1195
            }
 
1196
        }
 
1197
        break;
 
1198
 
 
1199
    case G_INT_CSTAT:
 
1200
        s->g_timer.reg.int_cstat &= ~(value);
 
1201
        for (i = 0; i < MCT_GT_CMP_NUM; i++) {
 
1202
            if (value & G_INT_CSTAT_COMP(i)) {
 
1203
                exynos4210_gcomp_lower_irq(&s->g_timer, i);
 
1204
            }
 
1205
        }
 
1206
        break;
 
1207
 
 
1208
    case G_INT_ENB:
 
1209
 
 
1210
        /* Raise IRQ if transition from disabled to enabled and CSTAT pending */
 
1211
        for (i = 0; i < MCT_GT_CMP_NUM; i++) {
 
1212
            if ((value & G_INT_ENABLE(i)) > (s->g_timer.reg.tcon &
 
1213
                    G_INT_ENABLE(i))) {
 
1214
                if (s->g_timer.reg.int_cstat & G_INT_CSTAT_COMP(i)) {
 
1215
                    exynos4210_gcomp_raise_irq(&s->g_timer, i);
 
1216
                }
 
1217
            }
 
1218
 
 
1219
            if ((value & G_INT_ENABLE(i)) < (s->g_timer.reg.tcon &
 
1220
                    G_INT_ENABLE(i))) {
 
1221
                exynos4210_gcomp_lower_irq(&s->g_timer, i);
 
1222
            }
 
1223
        }
 
1224
 
 
1225
        DPRINTF("global timer INT enable %llx\n", value);
 
1226
        s->g_timer.reg.int_enb = value;
 
1227
        break;
 
1228
 
 
1229
    case G_WSTAT:
 
1230
        s->g_timer.reg.wstat &= ~(value);
 
1231
        break;
 
1232
 
 
1233
    case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR:
 
1234
    case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR:
 
1235
        index = GET_G_COMP_ADD_INCR_IDX(offset);
 
1236
        s->g_timer.reg.comp_add_incr[index] = value;
 
1237
        s->g_timer.reg.wstat |= G_WSTAT_COMP_ADDINCR(index);
 
1238
        break;
 
1239
 
 
1240
        /* Local timers */
 
1241
    case L0_TCON: case L1_TCON:
 
1242
        lt_i = GET_L_TIMER_IDX(offset);
 
1243
        old_val = s->l_timer[lt_i].reg.tcon;
 
1244
 
 
1245
        s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCON_WRITE;
 
1246
        s->l_timer[lt_i].reg.tcon = value;
 
1247
 
 
1248
        /* Stop local CNT */
 
1249
        if ((value & L_TCON_TICK_START) <
 
1250
                (old_val & L_TCON_TICK_START)) {
 
1251
            DPRINTF("local timer[%d] stop cnt\n", lt_i);
 
1252
            exynos4210_ltick_cnt_stop(&s->l_timer[lt_i].tick_timer);
 
1253
        }
 
1254
 
 
1255
        /* Stop local INT */
 
1256
        if ((value & L_TCON_INT_START) <
 
1257
                (old_val & L_TCON_INT_START)) {
 
1258
            DPRINTF("local timer[%d] stop int\n", lt_i);
 
1259
            exynos4210_ltick_int_stop(&s->l_timer[lt_i].tick_timer);
 
1260
        }
 
1261
 
 
1262
        /* Start local CNT */
 
1263
        if ((value & L_TCON_TICK_START) >
 
1264
        (old_val & L_TCON_TICK_START)) {
 
1265
            DPRINTF("local timer[%d] start cnt\n", lt_i);
 
1266
            exynos4210_ltick_cnt_start(&s->l_timer[lt_i].tick_timer);
 
1267
        }
 
1268
 
 
1269
        /* Start local INT */
 
1270
        if ((value & L_TCON_INT_START) >
 
1271
        (old_val & L_TCON_INT_START)) {
 
1272
            DPRINTF("local timer[%d] start int\n", lt_i);
 
1273
            exynos4210_ltick_int_start(&s->l_timer[lt_i].tick_timer);
 
1274
        }
 
1275
 
 
1276
        /* Start or Stop local FRC if TCON changed */
 
1277
        if ((value & L_TCON_FRC_START) >
 
1278
        (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) {
 
1279
            DPRINTF("local timer[%d] start frc\n", lt_i);
 
1280
            exynos4210_lfrc_start(&s->l_timer[lt_i]);
 
1281
        }
 
1282
        if ((value & L_TCON_FRC_START) <
 
1283
                (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) {
 
1284
            DPRINTF("local timer[%d] stop frc\n", lt_i);
 
1285
            exynos4210_lfrc_stop(&s->l_timer[lt_i]);
 
1286
        }
 
1287
        break;
 
1288
 
 
1289
    case L0_TCNTB: case L1_TCNTB:
 
1290
 
 
1291
        lt_i = GET_L_TIMER_IDX(offset);
 
1292
        index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
 
1293
 
 
1294
        /*
 
1295
         * TCNTB is updated to internal register only after CNT expired.
 
1296
         * Due to this we should reload timer to nearest moment when CNT is
 
1297
         * expired and then in event handler update tcntb to new TCNTB value.
 
1298
         */
 
1299
        exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer, value,
 
1300
                s->l_timer[lt_i].tick_timer.icntb);
 
1301
 
 
1302
        s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCNTB_WRITE;
 
1303
        s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] = value;
 
1304
 
 
1305
#ifdef DEBUG_MCT
 
1306
        if (tcntb_min[lt_i] > value) {
 
1307
            tcntb_min[lt_i] = value;
 
1308
        }
 
1309
        if (tcntb_max[lt_i] < value) {
 
1310
            tcntb_max[lt_i] = value;
 
1311
        }
 
1312
        DPRINTF("local timer[%d] TCNTB write %llx; max=%x, min=%x\n",
 
1313
                lt_i, value, tcntb_max[lt_i], tcntb_min[lt_i]);
 
1314
#endif
 
1315
        break;
 
1316
 
 
1317
    case L0_ICNTB: case L1_ICNTB:
 
1318
 
 
1319
        lt_i = GET_L_TIMER_IDX(offset);
 
1320
        index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
 
1321
 
 
1322
        s->l_timer[lt_i].reg.wstat |= L_WSTAT_ICNTB_WRITE;
 
1323
        s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = value &
 
1324
                ~L_ICNTB_MANUAL_UPDATE;
 
1325
 
 
1326
        /*
 
1327
         * We need to avoid too small values for TCNTB*ICNTB. If not, IRQ event
 
1328
         * could raise too fast disallowing QEMU to execute target code.
 
1329
         */
 
1330
        if (s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] *
 
1331
            s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] < MCT_LT_CNT_LOW_LIMIT) {
 
1332
            if (!s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB]) {
 
1333
                s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] =
 
1334
                        MCT_LT_CNT_LOW_LIMIT;
 
1335
            } else {
 
1336
                s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] =
 
1337
                        MCT_LT_CNT_LOW_LIMIT /
 
1338
                        s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB];
 
1339
            }
 
1340
        }
 
1341
 
 
1342
        if (value & L_ICNTB_MANUAL_UPDATE) {
 
1343
            exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer,
 
1344
                    s->l_timer[lt_i].tick_timer.tcntb,
 
1345
                    s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB]);
 
1346
        }
 
1347
 
 
1348
#ifdef DEBUG_MCT
 
1349
        if (icntb_min[lt_i] > value) {
 
1350
            icntb_min[lt_i] = value;
 
1351
        }
 
1352
        if (icntb_max[lt_i] < value) {
 
1353
            icntb_max[lt_i] = value;
 
1354
        }
 
1355
DPRINTF("local timer[%d] ICNTB write %llx; max=%x, min=%x\n\n",
 
1356
        lt_i, value, icntb_max[lt_i], icntb_min[lt_i]);
 
1357
#endif
 
1358
break;
 
1359
 
 
1360
    case L0_FRCNTB: case L1_FRCNTB:
 
1361
 
 
1362
        lt_i = GET_L_TIMER_IDX(offset);
 
1363
        index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
 
1364
 
 
1365
        DPRINTF("local timer[%d] FRCNTB write %llx\n", lt_i, value);
 
1366
 
 
1367
        s->l_timer[lt_i].reg.wstat |= L_WSTAT_FRCCNTB_WRITE;
 
1368
        s->l_timer[lt_i].reg.cnt[L_REG_CNT_FRCCNTB] = value;
 
1369
 
 
1370
        break;
 
1371
 
 
1372
    case L0_TCNTO: case L1_TCNTO:
 
1373
    case L0_ICNTO: case L1_ICNTO:
 
1374
    case L0_FRCNTO: case L1_FRCNTO:
 
1375
        fprintf(stderr, "\n[exynos4210.mct: write to RO register "
 
1376
                TARGET_FMT_plx "]\n\n", offset);
 
1377
        break;
 
1378
 
 
1379
    case L0_INT_CSTAT: case L1_INT_CSTAT:
 
1380
        lt_i = GET_L_TIMER_IDX(offset);
 
1381
 
 
1382
        DPRINTF("local timer[%d] CSTAT write %llx\n", lt_i, value);
 
1383
 
 
1384
        s->l_timer[lt_i].reg.int_cstat &= ~value;
 
1385
        if (!s->l_timer[lt_i].reg.int_cstat) {
 
1386
            qemu_irq_lower(s->l_timer[lt_i].irq);
 
1387
        }
 
1388
        break;
 
1389
 
 
1390
    case L0_INT_ENB: case L1_INT_ENB:
 
1391
        lt_i = GET_L_TIMER_IDX(offset);
 
1392
        old_val = s->l_timer[lt_i].reg.int_enb;
 
1393
 
 
1394
        /* Raise Local timer IRQ if cstat is pending */
 
1395
        if ((value & L_INT_INTENB_ICNTEIE) > (old_val & L_INT_INTENB_ICNTEIE)) {
 
1396
            if (s->l_timer[lt_i].reg.int_cstat & L_INT_CSTAT_INTCNT) {
 
1397
                qemu_irq_raise(s->l_timer[lt_i].irq);
 
1398
            }
 
1399
        }
 
1400
 
 
1401
        s->l_timer[lt_i].reg.int_enb = value;
 
1402
 
 
1403
        break;
 
1404
 
 
1405
    case L0_WSTAT: case L1_WSTAT:
 
1406
        lt_i = GET_L_TIMER_IDX(offset);
 
1407
 
 
1408
        s->l_timer[lt_i].reg.wstat &= ~value;
 
1409
        break;
 
1410
 
 
1411
    default:
 
1412
        hw_error("exynos4210.mct: bad write offset "
 
1413
                TARGET_FMT_plx "\n", offset);
 
1414
        break;
 
1415
    }
 
1416
}
 
1417
 
 
1418
static const MemoryRegionOps exynos4210_mct_ops = {
 
1419
    .read = exynos4210_mct_read,
 
1420
    .write = exynos4210_mct_write,
 
1421
    .endianness = DEVICE_NATIVE_ENDIAN,
 
1422
};
 
1423
 
 
1424
/* MCT init */
 
1425
static int exynos4210_mct_init(SysBusDevice *dev)
 
1426
{
 
1427
    int i;
 
1428
    Exynos4210MCTState *s = FROM_SYSBUS(Exynos4210MCTState, dev);
 
1429
    QEMUBH *bh[2];
 
1430
 
 
1431
    /* Global timer */
 
1432
    bh[0] = qemu_bh_new(exynos4210_gfrc_event, s);
 
1433
    s->g_timer.ptimer_frc = ptimer_init(bh[0]);
 
1434
    memset(&s->g_timer.reg, 0, sizeof(struct gregs));
 
1435
 
 
1436
    /* Local timers */
 
1437
    for (i = 0; i < 2; i++) {
 
1438
        bh[0] = qemu_bh_new(exynos4210_ltick_event, &s->l_timer[i]);
 
1439
        bh[1] = qemu_bh_new(exynos4210_lfrc_event, &s->l_timer[i]);
 
1440
        s->l_timer[i].tick_timer.ptimer_tick = ptimer_init(bh[0]);
 
1441
        s->l_timer[i].ptimer_frc = ptimer_init(bh[1]);
 
1442
        s->l_timer[i].id = i;
 
1443
    }
 
1444
 
 
1445
    /* IRQs */
 
1446
    for (i = 0; i < MCT_GT_CMP_NUM; i++) {
 
1447
        sysbus_init_irq(dev, &s->g_timer.irq[i]);
 
1448
    }
 
1449
    for (i = 0; i < 2; i++) {
 
1450
        sysbus_init_irq(dev, &s->l_timer[i].irq);
 
1451
    }
 
1452
 
 
1453
    memory_region_init_io(&s->iomem, &exynos4210_mct_ops, s, "exynos4210-mct",
 
1454
            MCT_SFR_SIZE);
 
1455
    sysbus_init_mmio(dev, &s->iomem);
 
1456
 
 
1457
    return 0;
 
1458
}
 
1459
 
 
1460
static void exynos4210_mct_class_init(ObjectClass *klass, void *data)
 
1461
{
 
1462
    DeviceClass *dc = DEVICE_CLASS(klass);
 
1463
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
1464
 
 
1465
    k->init = exynos4210_mct_init;
 
1466
    dc->reset = exynos4210_mct_reset;
 
1467
    dc->vmsd = &vmstate_exynos4210_mct_state;
 
1468
}
 
1469
 
 
1470
static const TypeInfo exynos4210_mct_info = {
 
1471
    .name          = "exynos4210.mct",
 
1472
    .parent        = TYPE_SYS_BUS_DEVICE,
 
1473
    .instance_size = sizeof(Exynos4210MCTState),
 
1474
    .class_init    = exynos4210_mct_class_init,
 
1475
};
 
1476
 
 
1477
static void exynos4210_mct_register_types(void)
 
1478
{
 
1479
    type_register_static(&exynos4210_mct_info);
 
1480
}
 
1481
 
 
1482
type_init(exynos4210_mct_register_types)