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