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