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