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