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