diff options
Diffstat (limited to 'hw/exynos4210_mct.c')
-rw-r--r-- | hw/exynos4210_mct.c | 1482 |
1 files changed, 0 insertions, 1482 deletions
diff --git a/hw/exynos4210_mct.c b/hw/exynos4210_mct.c deleted file mode 100644 index 862c96212b..0000000000 --- a/hw/exynos4210_mct.c +++ /dev/null @@ -1,1482 +0,0 @@ -/* - * Samsung exynos4210 Multi Core timer - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. - * All rights reserved. - * - * Evgeny Voevodin <e.voevodin@samsung.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -/* - * Global Timer: - * - * Consists of two timers. First represents Free Running Counter and second - * is used to measure interval from FRC to nearest comparator. - * - * 0 UINT64_MAX - * | timer0 | - * | <-------------------------------------------------------------- | - * | --------------------------------------------frc---------------> | - * |______________________________________________|__________________| - * CMP0 CMP1 CMP2 | CMP3 - * __| |_ - * | timer1 | - * | -------------> | - * frc CMPx - * - * Problem: when implementing global timer as is, overflow arises. - * next_time = cur_time + period * count; - * period and count are 64 bits width. - * Lets arm timer for MCT_GT_COUNTER_STEP count and update internal G_CNT - * register during each event. - * - * Problem: both timers need to be implemented using MCT_XT_COUNTER_STEP because - * local timer contains two counters: TCNT and ICNT. TCNT == 0 -> ICNT--. - * IRQ is generated when ICNT riches zero. Implementation where TCNT == 0 - * generates IRQs suffers from too frequently events. Better to have one - * uint64_t counter equal to TCNT*ICNT and arm ptimer.c for a minimum(TCNT*ICNT, - * MCT_GT_COUNTER_STEP); (yes, if target tunes ICNT * TCNT to be too low values, - * there is no way to avoid frequently events). - */ - -#include "hw/sysbus.h" -#include "qemu/timer.h" -#include "qemu-common.h" -#include "hw/ptimer.h" - -#include "hw/exynos4210.h" - -//#define DEBUG_MCT - -#ifdef DEBUG_MCT -#define DPRINTF(fmt, ...) \ - do { fprintf(stdout, "MCT: [%24s:%5d] " fmt, __func__, __LINE__, \ - ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif - -#define MCT_CFG 0x000 -#define G_CNT_L 0x100 -#define G_CNT_U 0x104 -#define G_CNT_WSTAT 0x110 -#define G_COMP0_L 0x200 -#define G_COMP0_U 0x204 -#define G_COMP0_ADD_INCR 0x208 -#define G_COMP1_L 0x210 -#define G_COMP1_U 0x214 -#define G_COMP1_ADD_INCR 0x218 -#define G_COMP2_L 0x220 -#define G_COMP2_U 0x224 -#define G_COMP2_ADD_INCR 0x228 -#define G_COMP3_L 0x230 -#define G_COMP3_U 0x234 -#define G_COMP3_ADD_INCR 0x238 -#define G_TCON 0x240 -#define G_INT_CSTAT 0x244 -#define G_INT_ENB 0x248 -#define G_WSTAT 0x24C -#define L0_TCNTB 0x300 -#define L0_TCNTO 0x304 -#define L0_ICNTB 0x308 -#define L0_ICNTO 0x30C -#define L0_FRCNTB 0x310 -#define L0_FRCNTO 0x314 -#define L0_TCON 0x320 -#define L0_INT_CSTAT 0x330 -#define L0_INT_ENB 0x334 -#define L0_WSTAT 0x340 -#define L1_TCNTB 0x400 -#define L1_TCNTO 0x404 -#define L1_ICNTB 0x408 -#define L1_ICNTO 0x40C -#define L1_FRCNTB 0x410 -#define L1_FRCNTO 0x414 -#define L1_TCON 0x420 -#define L1_INT_CSTAT 0x430 -#define L1_INT_ENB 0x434 -#define L1_WSTAT 0x440 - -#define MCT_CFG_GET_PRESCALER(x) ((x) & 0xFF) -#define MCT_CFG_GET_DIVIDER(x) (1 << ((x) >> 8 & 7)) - -#define GET_G_COMP_IDX(offset) (((offset) - G_COMP0_L) / 0x10) -#define GET_G_COMP_ADD_INCR_IDX(offset) (((offset) - G_COMP0_ADD_INCR) / 0x10) - -#define G_COMP_L(x) (G_COMP0_L + (x) * 0x10) -#define G_COMP_U(x) (G_COMP0_U + (x) * 0x10) - -#define G_COMP_ADD_INCR(x) (G_COMP0_ADD_INCR + (x) * 0x10) - -/* MCT bits */ -#define G_TCON_COMP_ENABLE(x) (1 << 2 * (x)) -#define G_TCON_AUTO_ICREMENT(x) (1 << (2 * (x) + 1)) -#define G_TCON_TIMER_ENABLE (1 << 8) - -#define G_INT_ENABLE(x) (1 << (x)) -#define G_INT_CSTAT_COMP(x) (1 << (x)) - -#define G_CNT_WSTAT_L 1 -#define G_CNT_WSTAT_U 2 - -#define G_WSTAT_COMP_L(x) (1 << 4 * (x)) -#define G_WSTAT_COMP_U(x) (1 << ((4 * (x)) + 1)) -#define G_WSTAT_COMP_ADDINCR(x) (1 << ((4 * (x)) + 2)) -#define G_WSTAT_TCON_WRITE (1 << 16) - -#define GET_L_TIMER_IDX(offset) ((((offset) & 0xF00) - L0_TCNTB) / 0x100) -#define GET_L_TIMER_CNT_REG_IDX(offset, lt_i) \ - (((offset) - (L0_TCNTB + 0x100 * (lt_i))) >> 2) - -#define L_ICNTB_MANUAL_UPDATE (1 << 31) - -#define L_TCON_TICK_START (1) -#define L_TCON_INT_START (1 << 1) -#define L_TCON_INTERVAL_MODE (1 << 2) -#define L_TCON_FRC_START (1 << 3) - -#define L_INT_CSTAT_INTCNT (1 << 0) -#define L_INT_CSTAT_FRCCNT (1 << 1) - -#define L_INT_INTENB_ICNTEIE (1 << 0) -#define L_INT_INTENB_FRCEIE (1 << 1) - -#define L_WSTAT_TCNTB_WRITE (1 << 0) -#define L_WSTAT_ICNTB_WRITE (1 << 1) -#define L_WSTAT_FRCCNTB_WRITE (1 << 2) -#define L_WSTAT_TCON_WRITE (1 << 3) - -enum LocalTimerRegCntIndexes { - L_REG_CNT_TCNTB, - L_REG_CNT_TCNTO, - L_REG_CNT_ICNTB, - L_REG_CNT_ICNTO, - L_REG_CNT_FRCCNTB, - L_REG_CNT_FRCCNTO, - - L_REG_CNT_AMOUNT -}; - -#define MCT_NIRQ 6 -#define MCT_SFR_SIZE 0x444 - -#define MCT_GT_CMP_NUM 4 - -#define MCT_GT_MAX_VAL UINT64_MAX - -#define MCT_GT_COUNTER_STEP 0x100000000ULL -#define MCT_LT_COUNTER_STEP 0x100000000ULL -#define MCT_LT_CNT_LOW_LIMIT 0x100 - -/* global timer */ -typedef struct { - qemu_irq irq[MCT_GT_CMP_NUM]; - - struct gregs { - uint64_t cnt; - uint32_t cnt_wstat; - uint32_t tcon; - uint32_t int_cstat; - uint32_t int_enb; - uint32_t wstat; - uint64_t comp[MCT_GT_CMP_NUM]; - uint32_t comp_add_incr[MCT_GT_CMP_NUM]; - } reg; - - uint64_t count; /* Value FRC was armed with */ - int32_t curr_comp; /* Current comparator FRC is running to */ - - ptimer_state *ptimer_frc; /* FRC timer */ - -} Exynos4210MCTGT; - -/* local timer */ -typedef struct { - int id; /* timer id */ - qemu_irq irq; /* local timer irq */ - - struct tick_timer { - uint32_t cnt_run; /* cnt timer is running */ - uint32_t int_run; /* int timer is running */ - - uint32_t last_icnto; - uint32_t last_tcnto; - uint32_t tcntb; /* initial value for TCNTB */ - uint32_t icntb; /* initial value for ICNTB */ - - /* for step mode */ - uint64_t distance; /* distance to count to the next event */ - uint64_t progress; /* progress when counting by steps */ - uint64_t count; /* count to arm timer with */ - - ptimer_state *ptimer_tick; /* timer for tick counter */ - } tick_timer; - - /* use ptimer.c to represent count down timer */ - - ptimer_state *ptimer_frc; /* timer for free running counter */ - - /* registers */ - struct lregs { - uint32_t cnt[L_REG_CNT_AMOUNT]; - uint32_t tcon; - uint32_t int_cstat; - uint32_t int_enb; - uint32_t wstat; - } reg; - -} Exynos4210MCTLT; - -typedef struct Exynos4210MCTState { - SysBusDevice busdev; - MemoryRegion iomem; - - /* Registers */ - uint32_t reg_mct_cfg; - - Exynos4210MCTLT l_timer[2]; - Exynos4210MCTGT g_timer; - - uint32_t freq; /* all timers tick frequency, TCLK */ -} Exynos4210MCTState; - -/*** VMState ***/ -static const VMStateDescription vmstate_tick_timer = { - .name = "exynos4210.mct.tick_timer", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(cnt_run, struct tick_timer), - VMSTATE_UINT32(int_run, struct tick_timer), - VMSTATE_UINT32(last_icnto, struct tick_timer), - VMSTATE_UINT32(last_tcnto, struct tick_timer), - VMSTATE_UINT32(tcntb, struct tick_timer), - VMSTATE_UINT32(icntb, struct tick_timer), - VMSTATE_UINT64(distance, struct tick_timer), - VMSTATE_UINT64(progress, struct tick_timer), - VMSTATE_UINT64(count, struct tick_timer), - VMSTATE_PTIMER(ptimer_tick, struct tick_timer), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_lregs = { - .name = "exynos4210.mct.lregs", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(cnt, struct lregs, L_REG_CNT_AMOUNT), - VMSTATE_UINT32(tcon, struct lregs), - VMSTATE_UINT32(int_cstat, struct lregs), - VMSTATE_UINT32(int_enb, struct lregs), - VMSTATE_UINT32(wstat, struct lregs), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_exynos4210_mct_lt = { - .name = "exynos4210.mct.lt", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32(id, Exynos4210MCTLT), - VMSTATE_STRUCT(tick_timer, Exynos4210MCTLT, 0, - vmstate_tick_timer, - struct tick_timer), - VMSTATE_PTIMER(ptimer_frc, Exynos4210MCTLT), - VMSTATE_STRUCT(reg, Exynos4210MCTLT, 0, - vmstate_lregs, - struct lregs), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_gregs = { - .name = "exynos4210.mct.lregs", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT64(cnt, struct gregs), - VMSTATE_UINT32(cnt_wstat, struct gregs), - VMSTATE_UINT32(tcon, struct gregs), - VMSTATE_UINT32(int_cstat, struct gregs), - VMSTATE_UINT32(int_enb, struct gregs), - VMSTATE_UINT32(wstat, struct gregs), - VMSTATE_UINT64_ARRAY(comp, struct gregs, MCT_GT_CMP_NUM), - VMSTATE_UINT32_ARRAY(comp_add_incr, struct gregs, - MCT_GT_CMP_NUM), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_exynos4210_mct_gt = { - .name = "exynos4210.mct.lt", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(reg, Exynos4210MCTGT, 0, vmstate_gregs, - struct gregs), - VMSTATE_UINT64(count, Exynos4210MCTGT), - VMSTATE_INT32(curr_comp, Exynos4210MCTGT), - VMSTATE_PTIMER(ptimer_frc, Exynos4210MCTGT), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_exynos4210_mct_state = { - .name = "exynos4210.mct", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(reg_mct_cfg, Exynos4210MCTState), - VMSTATE_STRUCT_ARRAY(l_timer, Exynos4210MCTState, 2, 0, - vmstate_exynos4210_mct_lt, Exynos4210MCTLT), - VMSTATE_STRUCT(g_timer, Exynos4210MCTState, 0, - vmstate_exynos4210_mct_gt, Exynos4210MCTGT), - VMSTATE_UINT32(freq, Exynos4210MCTState), - VMSTATE_END_OF_LIST() - } -}; - -static void exynos4210_mct_update_freq(Exynos4210MCTState *s); - -/* - * Set counter of FRC global timer. - */ -static void exynos4210_gfrc_set_count(Exynos4210MCTGT *s, uint64_t count) -{ - s->count = count; - DPRINTF("global timer frc set count 0x%llx\n", count); - ptimer_set_count(s->ptimer_frc, count); -} - -/* - * Get counter of FRC global timer. - */ -static uint64_t exynos4210_gfrc_get_count(Exynos4210MCTGT *s) -{ - uint64_t count = 0; - count = ptimer_get_count(s->ptimer_frc); - count = s->count - count; - return s->reg.cnt + count; -} - -/* - * Stop global FRC timer - */ -static void exynos4210_gfrc_stop(Exynos4210MCTGT *s) -{ - DPRINTF("global timer frc stop\n"); - - ptimer_stop(s->ptimer_frc); -} - -/* - * Start global FRC timer - */ -static void exynos4210_gfrc_start(Exynos4210MCTGT *s) -{ - DPRINTF("global timer frc start\n"); - - ptimer_run(s->ptimer_frc, 1); -} - -/* - * Find next nearest Comparator. If current Comparator value equals to other - * Comparator value, skip them both - */ -static int32_t exynos4210_gcomp_find(Exynos4210MCTState *s) -{ - int res; - int i; - int enabled; - uint64_t min; - int min_comp_i; - uint64_t gfrc; - uint64_t distance; - uint64_t distance_min; - int comp_i; - - /* get gfrc count */ - gfrc = exynos4210_gfrc_get_count(&s->g_timer); - - min = UINT64_MAX; - distance_min = UINT64_MAX; - comp_i = MCT_GT_CMP_NUM; - min_comp_i = MCT_GT_CMP_NUM; - enabled = 0; - - /* lookup for nearest comparator */ - for (i = 0; i < MCT_GT_CMP_NUM; i++) { - - if (s->g_timer.reg.tcon & G_TCON_COMP_ENABLE(i)) { - - enabled = 1; - - if (s->g_timer.reg.comp[i] > gfrc) { - /* Comparator is upper then FRC */ - distance = s->g_timer.reg.comp[i] - gfrc; - - if (distance <= distance_min) { - distance_min = distance; - comp_i = i; - } - } else { - /* Comparator is below FRC, find the smallest */ - - if (s->g_timer.reg.comp[i] <= min) { - min = s->g_timer.reg.comp[i]; - min_comp_i = i; - } - } - } - } - - if (!enabled) { - /* All Comparators disabled */ - res = -1; - } else if (comp_i < MCT_GT_CMP_NUM) { - /* Found upper Comparator */ - res = comp_i; - } else { - /* All Comparators are below or equal to FRC */ - res = min_comp_i; - } - - DPRINTF("found comparator %d: comp 0x%llx distance 0x%llx, gfrc 0x%llx\n", - res, - s->g_timer.reg.comp[res], - distance_min, - gfrc); - - return res; -} - -/* - * Get distance to nearest Comparator - */ -static uint64_t exynos4210_gcomp_get_distance(Exynos4210MCTState *s, int32_t id) -{ - if (id == -1) { - /* no enabled Comparators, choose max distance */ - return MCT_GT_COUNTER_STEP; - } - if (s->g_timer.reg.comp[id] - s->g_timer.reg.cnt < MCT_GT_COUNTER_STEP) { - return s->g_timer.reg.comp[id] - s->g_timer.reg.cnt; - } else { - return MCT_GT_COUNTER_STEP; - } -} - -/* - * Restart global FRC timer - */ -static void exynos4210_gfrc_restart(Exynos4210MCTState *s) -{ - uint64_t distance; - - exynos4210_gfrc_stop(&s->g_timer); - - s->g_timer.curr_comp = exynos4210_gcomp_find(s); - - distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp); - - if (distance > MCT_GT_COUNTER_STEP || !distance) { - distance = MCT_GT_COUNTER_STEP; - } - - exynos4210_gfrc_set_count(&s->g_timer, distance); - exynos4210_gfrc_start(&s->g_timer); -} - -/* - * Raise global timer CMP IRQ - */ -static void exynos4210_gcomp_raise_irq(void *opaque, uint32_t id) -{ - Exynos4210MCTGT *s = opaque; - - /* If CSTAT is pending and IRQ is enabled */ - if ((s->reg.int_cstat & G_INT_CSTAT_COMP(id)) && - (s->reg.int_enb & G_INT_ENABLE(id))) { - DPRINTF("gcmp timer[%d] IRQ\n", id); - qemu_irq_raise(s->irq[id]); - } -} - -/* - * Lower global timer CMP IRQ - */ -static void exynos4210_gcomp_lower_irq(void *opaque, uint32_t id) -{ - Exynos4210MCTGT *s = opaque; - qemu_irq_lower(s->irq[id]); -} - -/* - * Global timer FRC event handler. - * Each event occurs when internal counter reaches counter + MCT_GT_COUNTER_STEP - * Every time we arm global FRC timer to count for MCT_GT_COUNTER_STEP value - */ -static void exynos4210_gfrc_event(void *opaque) -{ - Exynos4210MCTState *s = (Exynos4210MCTState *)opaque; - int i; - uint64_t distance; - - DPRINTF("\n"); - - s->g_timer.reg.cnt += s->g_timer.count; - - /* Process all comparators */ - for (i = 0; i < MCT_GT_CMP_NUM; i++) { - - if (s->g_timer.reg.cnt == s->g_timer.reg.comp[i]) { - /* reached nearest comparator */ - - s->g_timer.reg.int_cstat |= G_INT_CSTAT_COMP(i); - - /* Auto increment */ - if (s->g_timer.reg.tcon & G_TCON_AUTO_ICREMENT(i)) { - s->g_timer.reg.comp[i] += s->g_timer.reg.comp_add_incr[i]; - } - - /* IRQ */ - exynos4210_gcomp_raise_irq(&s->g_timer, i); - } - } - - /* Reload FRC to reach nearest comparator */ - s->g_timer.curr_comp = exynos4210_gcomp_find(s); - distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp); - if (distance > MCT_GT_COUNTER_STEP || !distance) { - distance = MCT_GT_COUNTER_STEP; - } - exynos4210_gfrc_set_count(&s->g_timer, distance); - - exynos4210_gfrc_start(&s->g_timer); -} - -/* - * Get counter of FRC local timer. - */ -static uint64_t exynos4210_lfrc_get_count(Exynos4210MCTLT *s) -{ - return ptimer_get_count(s->ptimer_frc); -} - -/* - * Set counter of FRC local timer. - */ -static void exynos4210_lfrc_update_count(Exynos4210MCTLT *s) -{ - if (!s->reg.cnt[L_REG_CNT_FRCCNTB]) { - ptimer_set_count(s->ptimer_frc, MCT_LT_COUNTER_STEP); - } else { - ptimer_set_count(s->ptimer_frc, s->reg.cnt[L_REG_CNT_FRCCNTB]); - } -} - -/* - * Start local FRC timer - */ -static void exynos4210_lfrc_start(Exynos4210MCTLT *s) -{ - ptimer_run(s->ptimer_frc, 1); -} - -/* - * Stop local FRC timer - */ -static void exynos4210_lfrc_stop(Exynos4210MCTLT *s) -{ - ptimer_stop(s->ptimer_frc); -} - -/* - * Local timer free running counter tick handler - */ -static void exynos4210_lfrc_event(void *opaque) -{ - Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque; - - /* local frc expired */ - - DPRINTF("\n"); - - s->reg.int_cstat |= L_INT_CSTAT_FRCCNT; - - /* update frc counter */ - exynos4210_lfrc_update_count(s); - - /* raise irq */ - if (s->reg.int_enb & L_INT_INTENB_FRCEIE) { - qemu_irq_raise(s->irq); - } - - /* we reached here, this means that timer is enabled */ - exynos4210_lfrc_start(s); -} - -static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s); -static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s); -static void exynos4210_ltick_recalc_count(struct tick_timer *s); - -/* - * Action on enabling local tick int timer - */ -static void exynos4210_ltick_int_start(struct tick_timer *s) -{ - if (!s->int_run) { - s->int_run = 1; - } -} - -/* - * Action on disabling local tick int timer - */ -static void exynos4210_ltick_int_stop(struct tick_timer *s) -{ - if (s->int_run) { - s->last_icnto = exynos4210_ltick_int_get_cnto(s); - s->int_run = 0; - } -} - -/* - * Get count for INT timer - */ -static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s) -{ - uint32_t icnto; - uint64_t remain; - uint64_t count; - uint64_t counted; - uint64_t cur_progress; - - count = ptimer_get_count(s->ptimer_tick); - if (count) { - /* timer is still counting, called not from event */ - counted = s->count - ptimer_get_count(s->ptimer_tick); - cur_progress = s->progress + counted; - } else { - /* timer expired earlier */ - cur_progress = s->progress; - } - - remain = s->distance - cur_progress; - - if (!s->int_run) { - /* INT is stopped. */ - icnto = s->last_icnto; - } else { - /* Both are counting */ - icnto = remain / s->tcntb; - } - - return icnto; -} - -/* - * Start local tick cnt timer. - */ -static void exynos4210_ltick_cnt_start(struct tick_timer *s) -{ - if (!s->cnt_run) { - - exynos4210_ltick_recalc_count(s); - ptimer_set_count(s->ptimer_tick, s->count); - ptimer_run(s->ptimer_tick, 1); - - s->cnt_run = 1; - } -} - -/* - * Stop local tick cnt timer. - */ -static void exynos4210_ltick_cnt_stop(struct tick_timer *s) -{ - if (s->cnt_run) { - - s->last_tcnto = exynos4210_ltick_cnt_get_cnto(s); - - if (s->int_run) { - exynos4210_ltick_int_stop(s); - } - - ptimer_stop(s->ptimer_tick); - - s->cnt_run = 0; - } -} - -/* - * Get counter for CNT timer - */ -static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s) -{ - uint32_t tcnto; - uint32_t icnto; - uint64_t remain; - uint64_t counted; - uint64_t count; - uint64_t cur_progress; - - count = ptimer_get_count(s->ptimer_tick); - if (count) { - /* timer is still counting, called not from event */ - counted = s->count - ptimer_get_count(s->ptimer_tick); - cur_progress = s->progress + counted; - } else { - /* timer expired earlier */ - cur_progress = s->progress; - } - - remain = s->distance - cur_progress; - - if (!s->cnt_run) { - /* Both are stopped. */ - tcnto = s->last_tcnto; - } else if (!s->int_run) { - /* INT counter is stopped, progress is by CNT timer */ - tcnto = remain % s->tcntb; - } else { - /* Both are counting */ - icnto = remain / s->tcntb; - if (icnto) { - tcnto = remain % (icnto * s->tcntb); - } else { - tcnto = remain % s->tcntb; - } - } - - return tcnto; -} - -/* - * Set new values of counters for CNT and INT timers - */ -static void exynos4210_ltick_set_cntb(struct tick_timer *s, uint32_t new_cnt, - uint32_t new_int) -{ - uint32_t cnt_stopped = 0; - uint32_t int_stopped = 0; - - if (s->cnt_run) { - exynos4210_ltick_cnt_stop(s); - cnt_stopped = 1; - } - - if (s->int_run) { - exynos4210_ltick_int_stop(s); - int_stopped = 1; - } - - s->tcntb = new_cnt + 1; - s->icntb = new_int + 1; - - if (cnt_stopped) { - exynos4210_ltick_cnt_start(s); - } - if (int_stopped) { - exynos4210_ltick_int_start(s); - } - -} - -/* - * Calculate new counter value for tick timer - */ -static void exynos4210_ltick_recalc_count(struct tick_timer *s) -{ - uint64_t to_count; - - if ((s->cnt_run && s->last_tcnto) || (s->int_run && s->last_icnto)) { - /* - * one or both timers run and not counted to the end; - * distance is not passed, recalculate with last_tcnto * last_icnto - */ - - if (s->last_tcnto) { - to_count = s->last_tcnto * s->last_icnto; - } else { - to_count = s->last_icnto; - } - } else { - /* distance is passed, recalculate with tcnto * icnto */ - if (s->icntb) { - s->distance = s->tcntb * s->icntb; - } else { - s->distance = s->tcntb; - } - - to_count = s->distance; - s->progress = 0; - } - - if (to_count > MCT_LT_COUNTER_STEP) { - /* count by step */ - s->count = MCT_LT_COUNTER_STEP; - } else { - s->count = to_count; - } -} - -/* - * Initialize tick_timer - */ -static void exynos4210_ltick_timer_init(struct tick_timer *s) -{ - exynos4210_ltick_int_stop(s); - exynos4210_ltick_cnt_stop(s); - - s->count = 0; - s->distance = 0; - s->progress = 0; - s->icntb = 0; - s->tcntb = 0; -} - -/* - * tick_timer event. - * Raises when abstract tick_timer expires. - */ -static void exynos4210_ltick_timer_event(struct tick_timer *s) -{ - s->progress += s->count; -} - -/* - * Local timer tick counter handler. - * Don't use reloaded timers. If timer counter = zero - * then handler called but after handler finished no - * timer reload occurs. - */ -static void exynos4210_ltick_event(void *opaque) -{ - Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque; - uint32_t tcnto; - uint32_t icnto; -#ifdef DEBUG_MCT - static uint64_t time1[2] = {0}; - static uint64_t time2[2] = {0}; -#endif - - /* Call tick_timer event handler, it will update its tcntb and icntb. */ - exynos4210_ltick_timer_event(&s->tick_timer); - - /* get tick_timer cnt */ - tcnto = exynos4210_ltick_cnt_get_cnto(&s->tick_timer); - - /* get tick_timer int */ - icnto = exynos4210_ltick_int_get_cnto(&s->tick_timer); - - /* raise IRQ if needed */ - if (!icnto && s->reg.tcon & L_TCON_INT_START) { - /* INT counter enabled and expired */ - - s->reg.int_cstat |= L_INT_CSTAT_INTCNT; - - /* raise interrupt if enabled */ - if (s->reg.int_enb & L_INT_INTENB_ICNTEIE) { -#ifdef DEBUG_MCT - time2[s->id] = qemu_get_clock_ns(vm_clock); - DPRINTF("local timer[%d] IRQ: %llx\n", s->id, - time2[s->id] - time1[s->id]); - time1[s->id] = time2[s->id]; -#endif - qemu_irq_raise(s->irq); - } - - /* reload ICNTB */ - if (s->reg.tcon & L_TCON_INTERVAL_MODE) { - exynos4210_ltick_set_cntb(&s->tick_timer, - s->reg.cnt[L_REG_CNT_TCNTB], - s->reg.cnt[L_REG_CNT_ICNTB]); - } - } else { - /* reload TCNTB */ - if (!tcnto) { - exynos4210_ltick_set_cntb(&s->tick_timer, - s->reg.cnt[L_REG_CNT_TCNTB], - icnto); - } - } - - /* start tick_timer cnt */ - exynos4210_ltick_cnt_start(&s->tick_timer); - - /* start tick_timer int */ - exynos4210_ltick_int_start(&s->tick_timer); -} - -/* update timer frequency */ -static void exynos4210_mct_update_freq(Exynos4210MCTState *s) -{ - uint32_t freq = s->freq; - s->freq = 24000000 / - ((MCT_CFG_GET_PRESCALER(s->reg_mct_cfg)+1) * - MCT_CFG_GET_DIVIDER(s->reg_mct_cfg)); - - if (freq != s->freq) { - DPRINTF("freq=%dHz\n", s->freq); - - /* global timer */ - ptimer_set_freq(s->g_timer.ptimer_frc, s->freq); - - /* local timer */ - ptimer_set_freq(s->l_timer[0].tick_timer.ptimer_tick, s->freq); - ptimer_set_freq(s->l_timer[0].ptimer_frc, s->freq); - ptimer_set_freq(s->l_timer[1].tick_timer.ptimer_tick, s->freq); - ptimer_set_freq(s->l_timer[1].ptimer_frc, s->freq); - } -} - -/* set defaul_timer values for all fields */ -static void exynos4210_mct_reset(DeviceState *d) -{ - Exynos4210MCTState *s = (Exynos4210MCTState *)d; - uint32_t i; - - s->reg_mct_cfg = 0; - - /* global timer */ - memset(&s->g_timer.reg, 0, sizeof(s->g_timer.reg)); - exynos4210_gfrc_stop(&s->g_timer); - - /* local timer */ - memset(s->l_timer[0].reg.cnt, 0, sizeof(s->l_timer[0].reg.cnt)); - memset(s->l_timer[1].reg.cnt, 0, sizeof(s->l_timer[1].reg.cnt)); - for (i = 0; i < 2; i++) { - s->l_timer[i].reg.int_cstat = 0; - s->l_timer[i].reg.int_enb = 0; - s->l_timer[i].reg.tcon = 0; - s->l_timer[i].reg.wstat = 0; - s->l_timer[i].tick_timer.count = 0; - s->l_timer[i].tick_timer.distance = 0; - s->l_timer[i].tick_timer.progress = 0; - ptimer_stop(s->l_timer[i].ptimer_frc); - - exynos4210_ltick_timer_init(&s->l_timer[i].tick_timer); - } - - exynos4210_mct_update_freq(s); - -} - -/* Multi Core Timer read */ -static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset, - unsigned size) -{ - Exynos4210MCTState *s = (Exynos4210MCTState *)opaque; - int index; - int shift; - uint64_t count; - uint32_t value; - int lt_i; - - switch (offset) { - - case MCT_CFG: - value = s->reg_mct_cfg; - break; - - case G_CNT_L: case G_CNT_U: - shift = 8 * (offset & 0x4); - count = exynos4210_gfrc_get_count(&s->g_timer); - value = UINT32_MAX & (count >> shift); - DPRINTF("read FRC=0x%llx\n", count); - break; - - case G_CNT_WSTAT: - value = s->g_timer.reg.cnt_wstat; - break; - - case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3): - case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3): - index = GET_G_COMP_IDX(offset); - shift = 8 * (offset & 0x4); - value = UINT32_MAX & (s->g_timer.reg.comp[index] >> shift); - break; - - case G_TCON: - value = s->g_timer.reg.tcon; - break; - - case G_INT_CSTAT: - value = s->g_timer.reg.int_cstat; - break; - - case G_INT_ENB: - value = s->g_timer.reg.int_enb; - break; - break; - case G_WSTAT: - value = s->g_timer.reg.wstat; - break; - - case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR: - case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR: - value = s->g_timer.reg.comp_add_incr[GET_G_COMP_ADD_INCR_IDX(offset)]; - break; - - /* Local timers */ - case L0_TCNTB: case L0_ICNTB: case L0_FRCNTB: - case L1_TCNTB: case L1_ICNTB: case L1_FRCNTB: - lt_i = GET_L_TIMER_IDX(offset); - index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); - value = s->l_timer[lt_i].reg.cnt[index]; - break; - - case L0_TCNTO: case L1_TCNTO: - lt_i = GET_L_TIMER_IDX(offset); - - value = exynos4210_ltick_cnt_get_cnto(&s->l_timer[lt_i].tick_timer); - DPRINTF("local timer[%d] read TCNTO %x\n", lt_i, value); - break; - - case L0_ICNTO: case L1_ICNTO: - lt_i = GET_L_TIMER_IDX(offset); - - value = exynos4210_ltick_int_get_cnto(&s->l_timer[lt_i].tick_timer); - DPRINTF("local timer[%d] read ICNTO %x\n", lt_i, value); - break; - - case L0_FRCNTO: case L1_FRCNTO: - lt_i = GET_L_TIMER_IDX(offset); - - value = exynos4210_lfrc_get_count(&s->l_timer[lt_i]); - - break; - - case L0_TCON: case L1_TCON: - lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100; - value = s->l_timer[lt_i].reg.tcon; - break; - - case L0_INT_CSTAT: case L1_INT_CSTAT: - lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100; - value = s->l_timer[lt_i].reg.int_cstat; - break; - - case L0_INT_ENB: case L1_INT_ENB: - lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100; - value = s->l_timer[lt_i].reg.int_enb; - break; - - case L0_WSTAT: case L1_WSTAT: - lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100; - value = s->l_timer[lt_i].reg.wstat; - break; - - default: - hw_error("exynos4210.mct: bad read offset " - TARGET_FMT_plx "\n", offset); - break; - } - return value; -} - -/* MCT write */ -static void exynos4210_mct_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - Exynos4210MCTState *s = (Exynos4210MCTState *)opaque; - int index; /* index in buffer which represents register set */ - int shift; - int lt_i; - uint64_t new_frc; - uint32_t i; - uint32_t old_val; -#ifdef DEBUG_MCT - static uint32_t icntb_max[2] = {0}; - static uint32_t icntb_min[2] = {UINT32_MAX, UINT32_MAX}; - static uint32_t tcntb_max[2] = {0}; - static uint32_t tcntb_min[2] = {UINT32_MAX, UINT32_MAX}; -#endif - - new_frc = s->g_timer.reg.cnt; - - switch (offset) { - - case MCT_CFG: - s->reg_mct_cfg = value; - exynos4210_mct_update_freq(s); - break; - - case G_CNT_L: - case G_CNT_U: - if (offset == G_CNT_L) { - - DPRINTF("global timer write to reg.cntl %llx\n", value); - - new_frc = (s->g_timer.reg.cnt & (uint64_t)UINT32_MAX << 32) + value; - s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_L; - } - if (offset == G_CNT_U) { - - DPRINTF("global timer write to reg.cntu %llx\n", value); - - new_frc = (s->g_timer.reg.cnt & UINT32_MAX) + - ((uint64_t)value << 32); - s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_U; - } - - s->g_timer.reg.cnt = new_frc; - exynos4210_gfrc_restart(s); - break; - - case G_CNT_WSTAT: - s->g_timer.reg.cnt_wstat &= ~(value); - break; - - case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3): - case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3): - index = GET_G_COMP_IDX(offset); - shift = 8 * (offset & 0x4); - s->g_timer.reg.comp[index] = - (s->g_timer.reg.comp[index] & - (((uint64_t)UINT32_MAX << 32) >> shift)) + - (value << shift); - - DPRINTF("comparator %d write 0x%llx val << %d\n", index, value, shift); - - if (offset&0x4) { - s->g_timer.reg.wstat |= G_WSTAT_COMP_U(index); - } else { - s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index); - } - - exynos4210_gfrc_restart(s); - break; - - case G_TCON: - old_val = s->g_timer.reg.tcon; - s->g_timer.reg.tcon = value; - s->g_timer.reg.wstat |= G_WSTAT_TCON_WRITE; - - DPRINTF("global timer write to reg.g_tcon %llx\n", value); - - /* Start FRC if transition from disabled to enabled */ - if ((value & G_TCON_TIMER_ENABLE) > (old_val & - G_TCON_TIMER_ENABLE)) { - exynos4210_gfrc_start(&s->g_timer); - } - if ((value & G_TCON_TIMER_ENABLE) < (old_val & - G_TCON_TIMER_ENABLE)) { - exynos4210_gfrc_stop(&s->g_timer); - } - - /* Start CMP if transition from disabled to enabled */ - for (i = 0; i < MCT_GT_CMP_NUM; i++) { - if ((value & G_TCON_COMP_ENABLE(i)) != (old_val & - G_TCON_COMP_ENABLE(i))) { - exynos4210_gfrc_restart(s); - } - } - break; - - case G_INT_CSTAT: - s->g_timer.reg.int_cstat &= ~(value); - for (i = 0; i < MCT_GT_CMP_NUM; i++) { - if (value & G_INT_CSTAT_COMP(i)) { - exynos4210_gcomp_lower_irq(&s->g_timer, i); - } - } - break; - - case G_INT_ENB: - - /* Raise IRQ if transition from disabled to enabled and CSTAT pending */ - for (i = 0; i < MCT_GT_CMP_NUM; i++) { - if ((value & G_INT_ENABLE(i)) > (s->g_timer.reg.tcon & - G_INT_ENABLE(i))) { - if (s->g_timer.reg.int_cstat & G_INT_CSTAT_COMP(i)) { - exynos4210_gcomp_raise_irq(&s->g_timer, i); - } - } - - if ((value & G_INT_ENABLE(i)) < (s->g_timer.reg.tcon & - G_INT_ENABLE(i))) { - exynos4210_gcomp_lower_irq(&s->g_timer, i); - } - } - - DPRINTF("global timer INT enable %llx\n", value); - s->g_timer.reg.int_enb = value; - break; - - case G_WSTAT: - s->g_timer.reg.wstat &= ~(value); - break; - - case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR: - case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR: - index = GET_G_COMP_ADD_INCR_IDX(offset); - s->g_timer.reg.comp_add_incr[index] = value; - s->g_timer.reg.wstat |= G_WSTAT_COMP_ADDINCR(index); - break; - - /* Local timers */ - case L0_TCON: case L1_TCON: - lt_i = GET_L_TIMER_IDX(offset); - old_val = s->l_timer[lt_i].reg.tcon; - - s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCON_WRITE; - s->l_timer[lt_i].reg.tcon = value; - - /* Stop local CNT */ - if ((value & L_TCON_TICK_START) < - (old_val & L_TCON_TICK_START)) { - DPRINTF("local timer[%d] stop cnt\n", lt_i); - exynos4210_ltick_cnt_stop(&s->l_timer[lt_i].tick_timer); - } - - /* Stop local INT */ - if ((value & L_TCON_INT_START) < - (old_val & L_TCON_INT_START)) { - DPRINTF("local timer[%d] stop int\n", lt_i); - exynos4210_ltick_int_stop(&s->l_timer[lt_i].tick_timer); - } - - /* Start local CNT */ - if ((value & L_TCON_TICK_START) > - (old_val & L_TCON_TICK_START)) { - DPRINTF("local timer[%d] start cnt\n", lt_i); - exynos4210_ltick_cnt_start(&s->l_timer[lt_i].tick_timer); - } - - /* Start local INT */ - if ((value & L_TCON_INT_START) > - (old_val & L_TCON_INT_START)) { - DPRINTF("local timer[%d] start int\n", lt_i); - exynos4210_ltick_int_start(&s->l_timer[lt_i].tick_timer); - } - - /* Start or Stop local FRC if TCON changed */ - if ((value & L_TCON_FRC_START) > - (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) { - DPRINTF("local timer[%d] start frc\n", lt_i); - exynos4210_lfrc_start(&s->l_timer[lt_i]); - } - if ((value & L_TCON_FRC_START) < - (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) { - DPRINTF("local timer[%d] stop frc\n", lt_i); - exynos4210_lfrc_stop(&s->l_timer[lt_i]); - } - break; - - case L0_TCNTB: case L1_TCNTB: - - lt_i = GET_L_TIMER_IDX(offset); - index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); - - /* - * TCNTB is updated to internal register only after CNT expired. - * Due to this we should reload timer to nearest moment when CNT is - * expired and then in event handler update tcntb to new TCNTB value. - */ - exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer, value, - s->l_timer[lt_i].tick_timer.icntb); - - s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCNTB_WRITE; - s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] = value; - -#ifdef DEBUG_MCT - if (tcntb_min[lt_i] > value) { - tcntb_min[lt_i] = value; - } - if (tcntb_max[lt_i] < value) { - tcntb_max[lt_i] = value; - } - DPRINTF("local timer[%d] TCNTB write %llx; max=%x, min=%x\n", - lt_i, value, tcntb_max[lt_i], tcntb_min[lt_i]); -#endif - break; - - case L0_ICNTB: case L1_ICNTB: - - lt_i = GET_L_TIMER_IDX(offset); - index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); - - s->l_timer[lt_i].reg.wstat |= L_WSTAT_ICNTB_WRITE; - s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = value & - ~L_ICNTB_MANUAL_UPDATE; - - /* - * We need to avoid too small values for TCNTB*ICNTB. If not, IRQ event - * could raise too fast disallowing QEMU to execute target code. - */ - if (s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] * - s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] < MCT_LT_CNT_LOW_LIMIT) { - if (!s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB]) { - s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = - MCT_LT_CNT_LOW_LIMIT; - } else { - s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = - MCT_LT_CNT_LOW_LIMIT / - s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB]; - } - } - - if (value & L_ICNTB_MANUAL_UPDATE) { - exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer, - s->l_timer[lt_i].tick_timer.tcntb, - s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB]); - } - -#ifdef DEBUG_MCT - if (icntb_min[lt_i] > value) { - icntb_min[lt_i] = value; - } - if (icntb_max[lt_i] < value) { - icntb_max[lt_i] = value; - } -DPRINTF("local timer[%d] ICNTB write %llx; max=%x, min=%x\n\n", - lt_i, value, icntb_max[lt_i], icntb_min[lt_i]); -#endif -break; - - case L0_FRCNTB: case L1_FRCNTB: - - lt_i = GET_L_TIMER_IDX(offset); - index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); - - DPRINTF("local timer[%d] FRCNTB write %llx\n", lt_i, value); - - s->l_timer[lt_i].reg.wstat |= L_WSTAT_FRCCNTB_WRITE; - s->l_timer[lt_i].reg.cnt[L_REG_CNT_FRCCNTB] = value; - - break; - - case L0_TCNTO: case L1_TCNTO: - case L0_ICNTO: case L1_ICNTO: - case L0_FRCNTO: case L1_FRCNTO: - fprintf(stderr, "\n[exynos4210.mct: write to RO register " - TARGET_FMT_plx "]\n\n", offset); - break; - - case L0_INT_CSTAT: case L1_INT_CSTAT: - lt_i = GET_L_TIMER_IDX(offset); - - DPRINTF("local timer[%d] CSTAT write %llx\n", lt_i, value); - - s->l_timer[lt_i].reg.int_cstat &= ~value; - if (!s->l_timer[lt_i].reg.int_cstat) { - qemu_irq_lower(s->l_timer[lt_i].irq); - } - break; - - case L0_INT_ENB: case L1_INT_ENB: - lt_i = GET_L_TIMER_IDX(offset); - old_val = s->l_timer[lt_i].reg.int_enb; - - /* Raise Local timer IRQ if cstat is pending */ - if ((value & L_INT_INTENB_ICNTEIE) > (old_val & L_INT_INTENB_ICNTEIE)) { - if (s->l_timer[lt_i].reg.int_cstat & L_INT_CSTAT_INTCNT) { - qemu_irq_raise(s->l_timer[lt_i].irq); - } - } - - s->l_timer[lt_i].reg.int_enb = value; - - break; - - case L0_WSTAT: case L1_WSTAT: - lt_i = GET_L_TIMER_IDX(offset); - - s->l_timer[lt_i].reg.wstat &= ~value; - break; - - default: - hw_error("exynos4210.mct: bad write offset " - TARGET_FMT_plx "\n", offset); - break; - } -} - -static const MemoryRegionOps exynos4210_mct_ops = { - .read = exynos4210_mct_read, - .write = exynos4210_mct_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -/* MCT init */ -static int exynos4210_mct_init(SysBusDevice *dev) -{ - int i; - Exynos4210MCTState *s = FROM_SYSBUS(Exynos4210MCTState, dev); - QEMUBH *bh[2]; - - /* Global timer */ - bh[0] = qemu_bh_new(exynos4210_gfrc_event, s); - s->g_timer.ptimer_frc = ptimer_init(bh[0]); - memset(&s->g_timer.reg, 0, sizeof(struct gregs)); - - /* Local timers */ - for (i = 0; i < 2; i++) { - bh[0] = qemu_bh_new(exynos4210_ltick_event, &s->l_timer[i]); - bh[1] = qemu_bh_new(exynos4210_lfrc_event, &s->l_timer[i]); - s->l_timer[i].tick_timer.ptimer_tick = ptimer_init(bh[0]); - s->l_timer[i].ptimer_frc = ptimer_init(bh[1]); - s->l_timer[i].id = i; - } - - /* IRQs */ - for (i = 0; i < MCT_GT_CMP_NUM; i++) { - sysbus_init_irq(dev, &s->g_timer.irq[i]); - } - for (i = 0; i < 2; i++) { - sysbus_init_irq(dev, &s->l_timer[i].irq); - } - - memory_region_init_io(&s->iomem, &exynos4210_mct_ops, s, "exynos4210-mct", - MCT_SFR_SIZE); - sysbus_init_mmio(dev, &s->iomem); - - return 0; -} - -static void exynos4210_mct_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = exynos4210_mct_init; - dc->reset = exynos4210_mct_reset; - dc->vmsd = &vmstate_exynos4210_mct_state; -} - -static const TypeInfo exynos4210_mct_info = { - .name = "exynos4210.mct", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(Exynos4210MCTState), - .class_init = exynos4210_mct_class_init, -}; - -static void exynos4210_mct_register_types(void) -{ - type_register_static(&exynos4210_mct_info); -} - -type_init(exynos4210_mct_register_types) |