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