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