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