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