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