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/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 * Must be called within exynos4210_gfrc_tx_begin/commit block. 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 * Must be called within exynos4210_gfrc_tx_begin/commit block. 389 */ 390 static void exynos4210_gfrc_stop(Exynos4210MCTGT *s) 391 { 392 DPRINTF("global timer frc stop\n"); 393 394 ptimer_stop(s->ptimer_frc); 395 } 396 397 /* 398 * Start global FRC timer 399 * Must be called within exynos4210_gfrc_tx_begin/commit block. 400 */ 401 static void exynos4210_gfrc_start(Exynos4210MCTGT *s) 402 { 403 DPRINTF("global timer frc start\n"); 404 405 ptimer_run(s->ptimer_frc, 1); 406 } 407 408 /* 409 * Start ptimer transaction for global FRC timer; this is just for 410 * consistency with the way we wrap operations like stop and run. 411 */ 412 static void exynos4210_gfrc_tx_begin(Exynos4210MCTGT *s) 413 { 414 ptimer_transaction_begin(s->ptimer_frc); 415 } 416 417 /* Commit ptimer transaction for global FRC timer. */ 418 static void exynos4210_gfrc_tx_commit(Exynos4210MCTGT *s) 419 { 420 ptimer_transaction_commit(s->ptimer_frc); 421 } 422 423 /* 424 * Find next nearest Comparator. If current Comparator value equals to other 425 * Comparator value, skip them both 426 */ 427 static int32_t exynos4210_gcomp_find(Exynos4210MCTState *s) 428 { 429 int res; 430 int i; 431 int enabled; 432 uint64_t min; 433 int min_comp_i; 434 uint64_t gfrc; 435 uint64_t distance; 436 uint64_t distance_min; 437 int comp_i; 438 439 /* get gfrc count */ 440 gfrc = exynos4210_gfrc_get_count(&s->g_timer); 441 442 min = UINT64_MAX; 443 distance_min = UINT64_MAX; 444 comp_i = MCT_GT_CMP_NUM; 445 min_comp_i = MCT_GT_CMP_NUM; 446 enabled = 0; 447 448 /* lookup for nearest comparator */ 449 for (i = 0; i < MCT_GT_CMP_NUM; i++) { 450 451 if (s->g_timer.reg.tcon & G_TCON_COMP_ENABLE(i)) { 452 453 enabled = 1; 454 455 if (s->g_timer.reg.comp[i] > gfrc) { 456 /* Comparator is upper then FRC */ 457 distance = s->g_timer.reg.comp[i] - gfrc; 458 459 if (distance <= distance_min) { 460 distance_min = distance; 461 comp_i = i; 462 } 463 } else { 464 /* Comparator is below FRC, find the smallest */ 465 466 if (s->g_timer.reg.comp[i] <= min) { 467 min = s->g_timer.reg.comp[i]; 468 min_comp_i = i; 469 } 470 } 471 } 472 } 473 474 if (!enabled) { 475 /* All Comparators disabled */ 476 res = -1; 477 } else if (comp_i < MCT_GT_CMP_NUM) { 478 /* Found upper Comparator */ 479 res = comp_i; 480 } else { 481 /* All Comparators are below or equal to FRC */ 482 res = min_comp_i; 483 } 484 485 DPRINTF("found comparator %d: comp 0x%llx distance 0x%llx, gfrc 0x%llx\n", 486 res, 487 s->g_timer.reg.comp[res], 488 distance_min, 489 gfrc); 490 491 return res; 492 } 493 494 /* 495 * Get distance to nearest Comparator 496 */ 497 static uint64_t exynos4210_gcomp_get_distance(Exynos4210MCTState *s, int32_t id) 498 { 499 if (id == -1) { 500 /* no enabled Comparators, choose max distance */ 501 return MCT_GT_COUNTER_STEP; 502 } 503 if (s->g_timer.reg.comp[id] - s->g_timer.reg.cnt < MCT_GT_COUNTER_STEP) { 504 return s->g_timer.reg.comp[id] - s->g_timer.reg.cnt; 505 } else { 506 return MCT_GT_COUNTER_STEP; 507 } 508 } 509 510 /* 511 * Restart global FRC timer 512 * Must be called within exynos4210_gfrc_tx_begin/commit block. 513 */ 514 static void exynos4210_gfrc_restart(Exynos4210MCTState *s) 515 { 516 uint64_t distance; 517 518 exynos4210_gfrc_stop(&s->g_timer); 519 520 s->g_timer.curr_comp = exynos4210_gcomp_find(s); 521 522 distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp); 523 524 if (distance > MCT_GT_COUNTER_STEP || !distance) { 525 distance = MCT_GT_COUNTER_STEP; 526 } 527 528 exynos4210_gfrc_set_count(&s->g_timer, distance); 529 exynos4210_gfrc_start(&s->g_timer); 530 } 531 532 /* 533 * Raise global timer CMP IRQ 534 */ 535 static void exynos4210_gcomp_raise_irq(void *opaque, uint32_t id) 536 { 537 Exynos4210MCTGT *s = opaque; 538 539 /* If CSTAT is pending and IRQ is enabled */ 540 if ((s->reg.int_cstat & G_INT_CSTAT_COMP(id)) && 541 (s->reg.int_enb & G_INT_ENABLE(id))) { 542 DPRINTF("gcmp timer[%d] IRQ\n", id); 543 qemu_irq_raise(s->irq[id]); 544 } 545 } 546 547 /* 548 * Lower global timer CMP IRQ 549 */ 550 static void exynos4210_gcomp_lower_irq(void *opaque, uint32_t id) 551 { 552 Exynos4210MCTGT *s = opaque; 553 qemu_irq_lower(s->irq[id]); 554 } 555 556 /* 557 * Global timer FRC event handler. 558 * Each event occurs when internal counter reaches counter + MCT_GT_COUNTER_STEP 559 * Every time we arm global FRC timer to count for MCT_GT_COUNTER_STEP value 560 */ 561 static void exynos4210_gfrc_event(void *opaque) 562 { 563 Exynos4210MCTState *s = (Exynos4210MCTState *)opaque; 564 int i; 565 uint64_t distance; 566 567 DPRINTF("\n"); 568 569 s->g_timer.reg.cnt += s->g_timer.count; 570 571 /* Process all comparators */ 572 for (i = 0; i < MCT_GT_CMP_NUM; i++) { 573 574 if (s->g_timer.reg.cnt == s->g_timer.reg.comp[i]) { 575 /* reached nearest comparator */ 576 577 s->g_timer.reg.int_cstat |= G_INT_CSTAT_COMP(i); 578 579 /* Auto increment */ 580 if (s->g_timer.reg.tcon & G_TCON_AUTO_ICREMENT(i)) { 581 s->g_timer.reg.comp[i] += s->g_timer.reg.comp_add_incr[i]; 582 } 583 584 /* IRQ */ 585 exynos4210_gcomp_raise_irq(&s->g_timer, i); 586 } 587 } 588 589 /* Reload FRC to reach nearest comparator */ 590 s->g_timer.curr_comp = exynos4210_gcomp_find(s); 591 distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp); 592 if (distance > MCT_GT_COUNTER_STEP || !distance) { 593 distance = MCT_GT_COUNTER_STEP; 594 } 595 exynos4210_gfrc_set_count(&s->g_timer, distance); 596 597 exynos4210_gfrc_start(&s->g_timer); 598 } 599 600 /* 601 * Get counter of FRC local timer. 602 */ 603 static uint64_t exynos4210_lfrc_get_count(Exynos4210MCTLT *s) 604 { 605 return ptimer_get_count(s->ptimer_frc); 606 } 607 608 /* 609 * Set counter of FRC local timer. 610 * Must be called from within exynos4210_lfrc_tx_begin/commit block. 611 */ 612 static void exynos4210_lfrc_update_count(Exynos4210MCTLT *s) 613 { 614 if (!s->reg.cnt[L_REG_CNT_FRCCNTB]) { 615 ptimer_set_count(s->ptimer_frc, MCT_LT_COUNTER_STEP); 616 } else { 617 ptimer_set_count(s->ptimer_frc, s->reg.cnt[L_REG_CNT_FRCCNTB]); 618 } 619 } 620 621 /* 622 * Start local FRC timer 623 * Must be called from within exynos4210_lfrc_tx_begin/commit block. 624 */ 625 static void exynos4210_lfrc_start(Exynos4210MCTLT *s) 626 { 627 ptimer_run(s->ptimer_frc, 1); 628 } 629 630 /* 631 * Stop local FRC timer 632 * Must be called from within exynos4210_lfrc_tx_begin/commit block. 633 */ 634 static void exynos4210_lfrc_stop(Exynos4210MCTLT *s) 635 { 636 ptimer_stop(s->ptimer_frc); 637 } 638 639 /* Start ptimer transaction for local FRC timer */ 640 static void exynos4210_lfrc_tx_begin(Exynos4210MCTLT *s) 641 { 642 ptimer_transaction_begin(s->ptimer_frc); 643 } 644 645 /* Commit ptimer transaction for local FRC timer */ 646 static void exynos4210_lfrc_tx_commit(Exynos4210MCTLT *s) 647 { 648 ptimer_transaction_commit(s->ptimer_frc); 649 } 650 651 /* 652 * Local timer free running counter tick handler 653 */ 654 static void exynos4210_lfrc_event(void *opaque) 655 { 656 Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque; 657 658 /* local frc expired */ 659 660 DPRINTF("\n"); 661 662 s->reg.int_cstat |= L_INT_CSTAT_FRCCNT; 663 664 /* update frc counter */ 665 exynos4210_lfrc_update_count(s); 666 667 /* raise irq */ 668 if (s->reg.int_enb & L_INT_INTENB_FRCEIE) { 669 qemu_irq_raise(s->irq); 670 } 671 672 /* we reached here, this means that timer is enabled */ 673 exynos4210_lfrc_start(s); 674 } 675 676 static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s); 677 static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s); 678 static void exynos4210_ltick_recalc_count(struct tick_timer *s); 679 680 /* 681 * Action on enabling local tick int timer 682 */ 683 static void exynos4210_ltick_int_start(struct tick_timer *s) 684 { 685 if (!s->int_run) { 686 s->int_run = 1; 687 } 688 } 689 690 /* 691 * Action on disabling local tick int timer 692 */ 693 static void exynos4210_ltick_int_stop(struct tick_timer *s) 694 { 695 if (s->int_run) { 696 s->last_icnto = exynos4210_ltick_int_get_cnto(s); 697 s->int_run = 0; 698 } 699 } 700 701 /* 702 * Get count for INT timer 703 */ 704 static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s) 705 { 706 uint32_t icnto; 707 uint64_t remain; 708 uint64_t count; 709 uint64_t counted; 710 uint64_t cur_progress; 711 712 count = ptimer_get_count(s->ptimer_tick); 713 if (count) { 714 /* timer is still counting, called not from event */ 715 counted = s->count - ptimer_get_count(s->ptimer_tick); 716 cur_progress = s->progress + counted; 717 } else { 718 /* timer expired earlier */ 719 cur_progress = s->progress; 720 } 721 722 remain = s->distance - cur_progress; 723 724 if (!s->int_run) { 725 /* INT is stopped. */ 726 icnto = s->last_icnto; 727 } else { 728 /* Both are counting */ 729 icnto = remain / s->tcntb; 730 } 731 732 return icnto; 733 } 734 735 /* 736 * Start local tick cnt timer. 737 * Must be called within exynos4210_ltick_tx_begin/commit block. 738 */ 739 static void exynos4210_ltick_cnt_start(struct tick_timer *s) 740 { 741 if (!s->cnt_run) { 742 743 exynos4210_ltick_recalc_count(s); 744 ptimer_set_count(s->ptimer_tick, s->count); 745 ptimer_run(s->ptimer_tick, 1); 746 747 s->cnt_run = 1; 748 } 749 } 750 751 /* 752 * Stop local tick cnt timer. 753 * Must be called within exynos4210_ltick_tx_begin/commit block. 754 */ 755 static void exynos4210_ltick_cnt_stop(struct tick_timer *s) 756 { 757 if (s->cnt_run) { 758 759 s->last_tcnto = exynos4210_ltick_cnt_get_cnto(s); 760 761 if (s->int_run) { 762 exynos4210_ltick_int_stop(s); 763 } 764 765 ptimer_stop(s->ptimer_tick); 766 767 s->cnt_run = 0; 768 } 769 } 770 771 /* Start ptimer transaction for local tick timer */ 772 static void exynos4210_ltick_tx_begin(struct tick_timer *s) 773 { 774 ptimer_transaction_begin(s->ptimer_tick); 775 } 776 777 /* Commit ptimer transaction for local tick timer */ 778 static void exynos4210_ltick_tx_commit(struct tick_timer *s) 779 { 780 ptimer_transaction_commit(s->ptimer_tick); 781 } 782 783 /* 784 * Get counter for CNT timer 785 */ 786 static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s) 787 { 788 uint32_t tcnto; 789 uint32_t icnto; 790 uint64_t remain; 791 uint64_t counted; 792 uint64_t count; 793 uint64_t cur_progress; 794 795 count = ptimer_get_count(s->ptimer_tick); 796 if (count) { 797 /* timer is still counting, called not from event */ 798 counted = s->count - ptimer_get_count(s->ptimer_tick); 799 cur_progress = s->progress + counted; 800 } else { 801 /* timer expired earlier */ 802 cur_progress = s->progress; 803 } 804 805 remain = s->distance - cur_progress; 806 807 if (!s->cnt_run) { 808 /* Both are stopped. */ 809 tcnto = s->last_tcnto; 810 } else if (!s->int_run) { 811 /* INT counter is stopped, progress is by CNT timer */ 812 tcnto = remain % s->tcntb; 813 } else { 814 /* Both are counting */ 815 icnto = remain / s->tcntb; 816 if (icnto) { 817 tcnto = remain % (icnto * s->tcntb); 818 } else { 819 tcnto = remain % s->tcntb; 820 } 821 } 822 823 return tcnto; 824 } 825 826 /* 827 * Set new values of counters for CNT and INT timers 828 * Must be called within exynos4210_ltick_tx_begin/commit block. 829 */ 830 static void exynos4210_ltick_set_cntb(struct tick_timer *s, uint32_t new_cnt, 831 uint32_t new_int) 832 { 833 uint32_t cnt_stopped = 0; 834 uint32_t int_stopped = 0; 835 836 if (s->cnt_run) { 837 exynos4210_ltick_cnt_stop(s); 838 cnt_stopped = 1; 839 } 840 841 if (s->int_run) { 842 exynos4210_ltick_int_stop(s); 843 int_stopped = 1; 844 } 845 846 s->tcntb = new_cnt + 1; 847 s->icntb = new_int + 1; 848 849 if (cnt_stopped) { 850 exynos4210_ltick_cnt_start(s); 851 } 852 if (int_stopped) { 853 exynos4210_ltick_int_start(s); 854 } 855 856 } 857 858 /* 859 * Calculate new counter value for tick timer 860 */ 861 static void exynos4210_ltick_recalc_count(struct tick_timer *s) 862 { 863 uint64_t to_count; 864 865 if ((s->cnt_run && s->last_tcnto) || (s->int_run && s->last_icnto)) { 866 /* 867 * one or both timers run and not counted to the end; 868 * distance is not passed, recalculate with last_tcnto * last_icnto 869 */ 870 871 if (s->last_tcnto) { 872 to_count = (uint64_t)s->last_tcnto * s->last_icnto; 873 } else { 874 to_count = s->last_icnto; 875 } 876 } else { 877 /* distance is passed, recalculate with tcnto * icnto */ 878 if (s->icntb) { 879 s->distance = (uint64_t)s->tcntb * s->icntb; 880 } else { 881 s->distance = s->tcntb; 882 } 883 884 to_count = s->distance; 885 s->progress = 0; 886 } 887 888 if (to_count > MCT_LT_COUNTER_STEP) { 889 /* count by step */ 890 s->count = MCT_LT_COUNTER_STEP; 891 } else { 892 s->count = to_count; 893 } 894 } 895 896 /* 897 * Initialize tick_timer 898 */ 899 static void exynos4210_ltick_timer_init(struct tick_timer *s) 900 { 901 exynos4210_ltick_int_stop(s); 902 exynos4210_ltick_tx_begin(s); 903 exynos4210_ltick_cnt_stop(s); 904 exynos4210_ltick_tx_commit(s); 905 906 s->count = 0; 907 s->distance = 0; 908 s->progress = 0; 909 s->icntb = 0; 910 s->tcntb = 0; 911 } 912 913 /* 914 * tick_timer event. 915 * Raises when abstract tick_timer expires. 916 */ 917 static void exynos4210_ltick_timer_event(struct tick_timer *s) 918 { 919 s->progress += s->count; 920 } 921 922 /* 923 * Local timer tick counter handler. 924 * Don't use reloaded timers. If timer counter = zero 925 * then handler called but after handler finished no 926 * timer reload occurs. 927 */ 928 static void exynos4210_ltick_event(void *opaque) 929 { 930 Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque; 931 uint32_t tcnto; 932 uint32_t icnto; 933 #ifdef DEBUG_MCT 934 static uint64_t time1[2] = {0}; 935 static uint64_t time2[2] = {0}; 936 #endif 937 938 /* Call tick_timer event handler, it will update its tcntb and icntb. */ 939 exynos4210_ltick_timer_event(&s->tick_timer); 940 941 /* get tick_timer cnt */ 942 tcnto = exynos4210_ltick_cnt_get_cnto(&s->tick_timer); 943 944 /* get tick_timer int */ 945 icnto = exynos4210_ltick_int_get_cnto(&s->tick_timer); 946 947 /* raise IRQ if needed */ 948 if (!icnto && s->reg.tcon & L_TCON_INT_START) { 949 /* INT counter enabled and expired */ 950 951 s->reg.int_cstat |= L_INT_CSTAT_INTCNT; 952 953 /* raise interrupt if enabled */ 954 if (s->reg.int_enb & L_INT_INTENB_ICNTEIE) { 955 #ifdef DEBUG_MCT 956 time2[s->id] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 957 DPRINTF("local timer[%d] IRQ: %llx\n", s->id, 958 time2[s->id] - time1[s->id]); 959 time1[s->id] = time2[s->id]; 960 #endif 961 qemu_irq_raise(s->irq); 962 } 963 964 /* reload ICNTB */ 965 if (s->reg.tcon & L_TCON_INTERVAL_MODE) { 966 exynos4210_ltick_set_cntb(&s->tick_timer, 967 s->reg.cnt[L_REG_CNT_TCNTB], 968 s->reg.cnt[L_REG_CNT_ICNTB]); 969 } 970 } else { 971 /* reload TCNTB */ 972 if (!tcnto) { 973 exynos4210_ltick_set_cntb(&s->tick_timer, 974 s->reg.cnt[L_REG_CNT_TCNTB], 975 icnto); 976 } 977 } 978 979 /* start tick_timer cnt */ 980 exynos4210_ltick_cnt_start(&s->tick_timer); 981 982 /* start tick_timer int */ 983 exynos4210_ltick_int_start(&s->tick_timer); 984 } 985 986 static void tx_ptimer_set_freq(ptimer_state *s, uint32_t freq) 987 { 988 /* 989 * callers of exynos4210_mct_update_freq() never do anything 990 * else that needs to be in the same ptimer transaction, so 991 * to avoid a lot of repetition we have a convenience function 992 * for begin/set_freq/commit. 993 */ 994 ptimer_transaction_begin(s); 995 ptimer_set_freq(s, freq); 996 ptimer_transaction_commit(s); 997 } 998 999 /* update timer frequency */ 1000 static void exynos4210_mct_update_freq(Exynos4210MCTState *s) 1001 { 1002 uint32_t freq = s->freq; 1003 s->freq = 24000000 / 1004 ((MCT_CFG_GET_PRESCALER(s->reg_mct_cfg) + 1) * 1005 MCT_CFG_GET_DIVIDER(s->reg_mct_cfg)); 1006 1007 if (freq != s->freq) { 1008 DPRINTF("freq=%dHz\n", s->freq); 1009 1010 /* global timer */ 1011 tx_ptimer_set_freq(s->g_timer.ptimer_frc, s->freq); 1012 1013 /* local timer */ 1014 tx_ptimer_set_freq(s->l_timer[0].tick_timer.ptimer_tick, s->freq); 1015 tx_ptimer_set_freq(s->l_timer[0].ptimer_frc, s->freq); 1016 tx_ptimer_set_freq(s->l_timer[1].tick_timer.ptimer_tick, s->freq); 1017 tx_ptimer_set_freq(s->l_timer[1].ptimer_frc, s->freq); 1018 } 1019 } 1020 1021 /* set defaul_timer values for all fields */ 1022 static void exynos4210_mct_reset(DeviceState *d) 1023 { 1024 Exynos4210MCTState *s = EXYNOS4210_MCT(d); 1025 uint32_t i; 1026 1027 s->reg_mct_cfg = 0; 1028 1029 /* global timer */ 1030 memset(&s->g_timer.reg, 0, sizeof(s->g_timer.reg)); 1031 exynos4210_gfrc_tx_begin(&s->g_timer); 1032 exynos4210_gfrc_stop(&s->g_timer); 1033 exynos4210_gfrc_tx_commit(&s->g_timer); 1034 1035 /* local timer */ 1036 memset(s->l_timer[0].reg.cnt, 0, sizeof(s->l_timer[0].reg.cnt)); 1037 memset(s->l_timer[1].reg.cnt, 0, sizeof(s->l_timer[1].reg.cnt)); 1038 for (i = 0; i < 2; i++) { 1039 s->l_timer[i].reg.int_cstat = 0; 1040 s->l_timer[i].reg.int_enb = 0; 1041 s->l_timer[i].reg.tcon = 0; 1042 s->l_timer[i].reg.wstat = 0; 1043 s->l_timer[i].tick_timer.count = 0; 1044 s->l_timer[i].tick_timer.distance = 0; 1045 s->l_timer[i].tick_timer.progress = 0; 1046 exynos4210_lfrc_tx_begin(&s->l_timer[i]); 1047 ptimer_stop(s->l_timer[i].ptimer_frc); 1048 exynos4210_lfrc_tx_commit(&s->l_timer[i]); 1049 1050 exynos4210_ltick_timer_init(&s->l_timer[i].tick_timer); 1051 } 1052 1053 exynos4210_mct_update_freq(s); 1054 1055 } 1056 1057 /* Multi Core Timer read */ 1058 static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset, 1059 unsigned size) 1060 { 1061 Exynos4210MCTState *s = (Exynos4210MCTState *)opaque; 1062 int index; 1063 int shift; 1064 uint64_t count; 1065 uint32_t value; 1066 int lt_i; 1067 1068 switch (offset) { 1069 1070 case MCT_CFG: 1071 value = s->reg_mct_cfg; 1072 break; 1073 1074 case G_CNT_L: case G_CNT_U: 1075 shift = 8 * (offset & 0x4); 1076 count = exynos4210_gfrc_get_count(&s->g_timer); 1077 value = UINT32_MAX & (count >> shift); 1078 DPRINTF("read FRC=0x%llx\n", count); 1079 break; 1080 1081 case G_CNT_WSTAT: 1082 value = s->g_timer.reg.cnt_wstat; 1083 break; 1084 1085 case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3): 1086 case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3): 1087 index = GET_G_COMP_IDX(offset); 1088 shift = 8 * (offset & 0x4); 1089 value = UINT32_MAX & (s->g_timer.reg.comp[index] >> shift); 1090 break; 1091 1092 case G_TCON: 1093 value = s->g_timer.reg.tcon; 1094 break; 1095 1096 case G_INT_CSTAT: 1097 value = s->g_timer.reg.int_cstat; 1098 break; 1099 1100 case G_INT_ENB: 1101 value = s->g_timer.reg.int_enb; 1102 break; 1103 case G_WSTAT: 1104 value = s->g_timer.reg.wstat; 1105 break; 1106 1107 case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR: 1108 case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR: 1109 value = s->g_timer.reg.comp_add_incr[GET_G_COMP_ADD_INCR_IDX(offset)]; 1110 break; 1111 1112 /* Local timers */ 1113 case L0_TCNTB: case L0_ICNTB: case L0_FRCNTB: 1114 case L1_TCNTB: case L1_ICNTB: case L1_FRCNTB: 1115 lt_i = GET_L_TIMER_IDX(offset); 1116 index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); 1117 value = s->l_timer[lt_i].reg.cnt[index]; 1118 break; 1119 1120 case L0_TCNTO: case L1_TCNTO: 1121 lt_i = GET_L_TIMER_IDX(offset); 1122 1123 value = exynos4210_ltick_cnt_get_cnto(&s->l_timer[lt_i].tick_timer); 1124 DPRINTF("local timer[%d] read TCNTO %x\n", lt_i, value); 1125 break; 1126 1127 case L0_ICNTO: case L1_ICNTO: 1128 lt_i = GET_L_TIMER_IDX(offset); 1129 1130 value = exynos4210_ltick_int_get_cnto(&s->l_timer[lt_i].tick_timer); 1131 DPRINTF("local timer[%d] read ICNTO %x\n", lt_i, value); 1132 break; 1133 1134 case L0_FRCNTO: case L1_FRCNTO: 1135 lt_i = GET_L_TIMER_IDX(offset); 1136 1137 value = exynos4210_lfrc_get_count(&s->l_timer[lt_i]); 1138 break; 1139 1140 case L0_TCON: case L1_TCON: 1141 lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100; 1142 value = s->l_timer[lt_i].reg.tcon; 1143 break; 1144 1145 case L0_INT_CSTAT: case L1_INT_CSTAT: 1146 lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100; 1147 value = s->l_timer[lt_i].reg.int_cstat; 1148 break; 1149 1150 case L0_INT_ENB: case L1_INT_ENB: 1151 lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100; 1152 value = s->l_timer[lt_i].reg.int_enb; 1153 break; 1154 1155 case L0_WSTAT: case L1_WSTAT: 1156 lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100; 1157 value = s->l_timer[lt_i].reg.wstat; 1158 break; 1159 1160 default: 1161 hw_error("exynos4210.mct: bad read offset " 1162 TARGET_FMT_plx "\n", offset); 1163 break; 1164 } 1165 return value; 1166 } 1167 1168 /* MCT write */ 1169 static void exynos4210_mct_write(void *opaque, hwaddr offset, 1170 uint64_t value, unsigned size) 1171 { 1172 Exynos4210MCTState *s = (Exynos4210MCTState *)opaque; 1173 int index; /* index in buffer which represents register set */ 1174 int shift; 1175 int lt_i; 1176 uint64_t new_frc; 1177 uint32_t i; 1178 uint32_t old_val; 1179 #ifdef DEBUG_MCT 1180 static uint32_t icntb_max[2] = {0}; 1181 static uint32_t icntb_min[2] = {UINT32_MAX, UINT32_MAX}; 1182 static uint32_t tcntb_max[2] = {0}; 1183 static uint32_t tcntb_min[2] = {UINT32_MAX, UINT32_MAX}; 1184 #endif 1185 1186 new_frc = s->g_timer.reg.cnt; 1187 1188 switch (offset) { 1189 1190 case MCT_CFG: 1191 s->reg_mct_cfg = value; 1192 exynos4210_mct_update_freq(s); 1193 break; 1194 1195 case G_CNT_L: 1196 case G_CNT_U: 1197 if (offset == G_CNT_L) { 1198 1199 DPRINTF("global timer write to reg.cntl %llx\n", value); 1200 1201 new_frc = (s->g_timer.reg.cnt & (uint64_t)UINT32_MAX << 32) + value; 1202 s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_L; 1203 } 1204 if (offset == G_CNT_U) { 1205 1206 DPRINTF("global timer write to reg.cntu %llx\n", value); 1207 1208 new_frc = (s->g_timer.reg.cnt & UINT32_MAX) + 1209 ((uint64_t)value << 32); 1210 s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_U; 1211 } 1212 1213 s->g_timer.reg.cnt = new_frc; 1214 exynos4210_gfrc_tx_begin(&s->g_timer); 1215 exynos4210_gfrc_restart(s); 1216 exynos4210_gfrc_tx_commit(&s->g_timer); 1217 break; 1218 1219 case G_CNT_WSTAT: 1220 s->g_timer.reg.cnt_wstat &= ~(value); 1221 break; 1222 1223 case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3): 1224 case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3): 1225 index = GET_G_COMP_IDX(offset); 1226 shift = 8 * (offset & 0x4); 1227 s->g_timer.reg.comp[index] = 1228 (s->g_timer.reg.comp[index] & 1229 (((uint64_t)UINT32_MAX << 32) >> shift)) + 1230 (value << shift); 1231 1232 DPRINTF("comparator %d write 0x%llx val << %d\n", index, value, shift); 1233 1234 if (offset & 0x4) { 1235 s->g_timer.reg.wstat |= G_WSTAT_COMP_U(index); 1236 } else { 1237 s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index); 1238 } 1239 1240 exynos4210_gfrc_tx_begin(&s->g_timer); 1241 exynos4210_gfrc_restart(s); 1242 exynos4210_gfrc_tx_commit(&s->g_timer); 1243 break; 1244 1245 case G_TCON: 1246 old_val = s->g_timer.reg.tcon; 1247 s->g_timer.reg.tcon = value; 1248 s->g_timer.reg.wstat |= G_WSTAT_TCON_WRITE; 1249 1250 DPRINTF("global timer write to reg.g_tcon %llx\n", value); 1251 1252 exynos4210_gfrc_tx_begin(&s->g_timer); 1253 1254 /* Start FRC if transition from disabled to enabled */ 1255 if ((value & G_TCON_TIMER_ENABLE) > (old_val & 1256 G_TCON_TIMER_ENABLE)) { 1257 exynos4210_gfrc_restart(s); 1258 } 1259 if ((value & G_TCON_TIMER_ENABLE) < (old_val & 1260 G_TCON_TIMER_ENABLE)) { 1261 exynos4210_gfrc_stop(&s->g_timer); 1262 } 1263 1264 /* Start CMP if transition from disabled to enabled */ 1265 for (i = 0; i < MCT_GT_CMP_NUM; i++) { 1266 if ((value & G_TCON_COMP_ENABLE(i)) != (old_val & 1267 G_TCON_COMP_ENABLE(i))) { 1268 exynos4210_gfrc_restart(s); 1269 } 1270 } 1271 1272 exynos4210_gfrc_tx_commit(&s->g_timer); 1273 break; 1274 1275 case G_INT_CSTAT: 1276 s->g_timer.reg.int_cstat &= ~(value); 1277 for (i = 0; i < MCT_GT_CMP_NUM; i++) { 1278 if (value & G_INT_CSTAT_COMP(i)) { 1279 exynos4210_gcomp_lower_irq(&s->g_timer, i); 1280 } 1281 } 1282 break; 1283 1284 case G_INT_ENB: 1285 /* Raise IRQ if transition from disabled to enabled and CSTAT pending */ 1286 for (i = 0; i < MCT_GT_CMP_NUM; i++) { 1287 if ((value & G_INT_ENABLE(i)) > (s->g_timer.reg.tcon & 1288 G_INT_ENABLE(i))) { 1289 if (s->g_timer.reg.int_cstat & G_INT_CSTAT_COMP(i)) { 1290 exynos4210_gcomp_raise_irq(&s->g_timer, i); 1291 } 1292 } 1293 1294 if ((value & G_INT_ENABLE(i)) < (s->g_timer.reg.tcon & 1295 G_INT_ENABLE(i))) { 1296 exynos4210_gcomp_lower_irq(&s->g_timer, i); 1297 } 1298 } 1299 1300 DPRINTF("global timer INT enable %llx\n", value); 1301 s->g_timer.reg.int_enb = value; 1302 break; 1303 1304 case G_WSTAT: 1305 s->g_timer.reg.wstat &= ~(value); 1306 break; 1307 1308 case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR: 1309 case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR: 1310 index = GET_G_COMP_ADD_INCR_IDX(offset); 1311 s->g_timer.reg.comp_add_incr[index] = value; 1312 s->g_timer.reg.wstat |= G_WSTAT_COMP_ADDINCR(index); 1313 break; 1314 1315 /* Local timers */ 1316 case L0_TCON: case L1_TCON: 1317 lt_i = GET_L_TIMER_IDX(offset); 1318 old_val = s->l_timer[lt_i].reg.tcon; 1319 1320 s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCON_WRITE; 1321 s->l_timer[lt_i].reg.tcon = value; 1322 1323 exynos4210_ltick_tx_begin(&s->l_timer[lt_i].tick_timer); 1324 /* Stop local CNT */ 1325 if ((value & L_TCON_TICK_START) < 1326 (old_val & L_TCON_TICK_START)) { 1327 DPRINTF("local timer[%d] stop cnt\n", lt_i); 1328 exynos4210_ltick_cnt_stop(&s->l_timer[lt_i].tick_timer); 1329 } 1330 1331 /* Stop local INT */ 1332 if ((value & L_TCON_INT_START) < 1333 (old_val & L_TCON_INT_START)) { 1334 DPRINTF("local timer[%d] stop int\n", lt_i); 1335 exynos4210_ltick_int_stop(&s->l_timer[lt_i].tick_timer); 1336 } 1337 1338 /* Start local CNT */ 1339 if ((value & L_TCON_TICK_START) > 1340 (old_val & L_TCON_TICK_START)) { 1341 DPRINTF("local timer[%d] start cnt\n", lt_i); 1342 exynos4210_ltick_cnt_start(&s->l_timer[lt_i].tick_timer); 1343 } 1344 1345 /* Start local INT */ 1346 if ((value & L_TCON_INT_START) > 1347 (old_val & L_TCON_INT_START)) { 1348 DPRINTF("local timer[%d] start int\n", lt_i); 1349 exynos4210_ltick_int_start(&s->l_timer[lt_i].tick_timer); 1350 } 1351 exynos4210_ltick_tx_commit(&s->l_timer[lt_i].tick_timer); 1352 1353 /* Start or Stop local FRC if TCON changed */ 1354 exynos4210_lfrc_tx_begin(&s->l_timer[lt_i]); 1355 if ((value & L_TCON_FRC_START) > 1356 (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) { 1357 DPRINTF("local timer[%d] start frc\n", lt_i); 1358 exynos4210_lfrc_start(&s->l_timer[lt_i]); 1359 } 1360 if ((value & L_TCON_FRC_START) < 1361 (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) { 1362 DPRINTF("local timer[%d] stop frc\n", lt_i); 1363 exynos4210_lfrc_stop(&s->l_timer[lt_i]); 1364 } 1365 exynos4210_lfrc_tx_commit(&s->l_timer[lt_i]); 1366 break; 1367 1368 case L0_TCNTB: case L1_TCNTB: 1369 lt_i = GET_L_TIMER_IDX(offset); 1370 1371 /* 1372 * TCNTB is updated to internal register only after CNT expired. 1373 * Due to this we should reload timer to nearest moment when CNT is 1374 * expired and then in event handler update tcntb to new TCNTB value. 1375 */ 1376 exynos4210_ltick_tx_begin(&s->l_timer[lt_i].tick_timer); 1377 exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer, value, 1378 s->l_timer[lt_i].tick_timer.icntb); 1379 exynos4210_ltick_tx_commit(&s->l_timer[lt_i].tick_timer); 1380 1381 s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCNTB_WRITE; 1382 s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] = value; 1383 1384 #ifdef DEBUG_MCT 1385 if (tcntb_min[lt_i] > value) { 1386 tcntb_min[lt_i] = value; 1387 } 1388 if (tcntb_max[lt_i] < value) { 1389 tcntb_max[lt_i] = value; 1390 } 1391 DPRINTF("local timer[%d] TCNTB write %llx; max=%x, min=%x\n", 1392 lt_i, value, tcntb_max[lt_i], tcntb_min[lt_i]); 1393 #endif 1394 break; 1395 1396 case L0_ICNTB: case L1_ICNTB: 1397 lt_i = GET_L_TIMER_IDX(offset); 1398 1399 s->l_timer[lt_i].reg.wstat |= L_WSTAT_ICNTB_WRITE; 1400 s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = value & 1401 ~L_ICNTB_MANUAL_UPDATE; 1402 1403 /* 1404 * We need to avoid too small values for TCNTB*ICNTB. If not, IRQ event 1405 * could raise too fast disallowing QEMU to execute target code. 1406 */ 1407 if (s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] * 1408 s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] < MCT_LT_CNT_LOW_LIMIT) { 1409 if (!s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB]) { 1410 s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = 1411 MCT_LT_CNT_LOW_LIMIT; 1412 } else { 1413 s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = 1414 MCT_LT_CNT_LOW_LIMIT / 1415 s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB]; 1416 } 1417 } 1418 1419 if (value & L_ICNTB_MANUAL_UPDATE) { 1420 exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer, 1421 s->l_timer[lt_i].tick_timer.tcntb, 1422 s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB]); 1423 } 1424 1425 #ifdef DEBUG_MCT 1426 if (icntb_min[lt_i] > value) { 1427 icntb_min[lt_i] = value; 1428 } 1429 if (icntb_max[lt_i] < value) { 1430 icntb_max[lt_i] = value; 1431 } 1432 DPRINTF("local timer[%d] ICNTB write %llx; max=%x, min=%x\n\n", 1433 lt_i, value, icntb_max[lt_i], icntb_min[lt_i]); 1434 #endif 1435 break; 1436 1437 case L0_FRCNTB: case L1_FRCNTB: 1438 lt_i = GET_L_TIMER_IDX(offset); 1439 DPRINTF("local timer[%d] FRCNTB write %llx\n", lt_i, value); 1440 1441 s->l_timer[lt_i].reg.wstat |= L_WSTAT_FRCCNTB_WRITE; 1442 s->l_timer[lt_i].reg.cnt[L_REG_CNT_FRCCNTB] = value; 1443 1444 break; 1445 1446 case L0_TCNTO: case L1_TCNTO: 1447 case L0_ICNTO: case L1_ICNTO: 1448 case L0_FRCNTO: case L1_FRCNTO: 1449 qemu_log_mask(LOG_GUEST_ERROR, 1450 "exynos4210.mct: write to RO register " TARGET_FMT_plx, 1451 offset); 1452 break; 1453 1454 case L0_INT_CSTAT: case L1_INT_CSTAT: 1455 lt_i = GET_L_TIMER_IDX(offset); 1456 1457 DPRINTF("local timer[%d] CSTAT write %llx\n", lt_i, value); 1458 1459 s->l_timer[lt_i].reg.int_cstat &= ~value; 1460 if (!s->l_timer[lt_i].reg.int_cstat) { 1461 qemu_irq_lower(s->l_timer[lt_i].irq); 1462 } 1463 break; 1464 1465 case L0_INT_ENB: case L1_INT_ENB: 1466 lt_i = GET_L_TIMER_IDX(offset); 1467 old_val = s->l_timer[lt_i].reg.int_enb; 1468 1469 /* Raise Local timer IRQ if cstat is pending */ 1470 if ((value & L_INT_INTENB_ICNTEIE) > (old_val & L_INT_INTENB_ICNTEIE)) { 1471 if (s->l_timer[lt_i].reg.int_cstat & L_INT_CSTAT_INTCNT) { 1472 qemu_irq_raise(s->l_timer[lt_i].irq); 1473 } 1474 } 1475 1476 s->l_timer[lt_i].reg.int_enb = value; 1477 1478 break; 1479 1480 case L0_WSTAT: case L1_WSTAT: 1481 lt_i = GET_L_TIMER_IDX(offset); 1482 1483 s->l_timer[lt_i].reg.wstat &= ~value; 1484 break; 1485 1486 default: 1487 hw_error("exynos4210.mct: bad write offset " 1488 TARGET_FMT_plx "\n", offset); 1489 break; 1490 } 1491 } 1492 1493 static const MemoryRegionOps exynos4210_mct_ops = { 1494 .read = exynos4210_mct_read, 1495 .write = exynos4210_mct_write, 1496 .endianness = DEVICE_NATIVE_ENDIAN, 1497 }; 1498 1499 /* MCT init */ 1500 static void exynos4210_mct_init(Object *obj) 1501 { 1502 int i; 1503 Exynos4210MCTState *s = EXYNOS4210_MCT(obj); 1504 SysBusDevice *dev = SYS_BUS_DEVICE(obj); 1505 1506 /* Global timer */ 1507 s->g_timer.ptimer_frc = ptimer_init(exynos4210_gfrc_event, s, 1508 PTIMER_POLICY_DEFAULT); 1509 memset(&s->g_timer.reg, 0, sizeof(struct gregs)); 1510 1511 /* Local timers */ 1512 for (i = 0; i < 2; i++) { 1513 s->l_timer[i].tick_timer.ptimer_tick = 1514 ptimer_init(exynos4210_ltick_event, &s->l_timer[i], 1515 PTIMER_POLICY_DEFAULT); 1516 s->l_timer[i].ptimer_frc = 1517 ptimer_init(exynos4210_lfrc_event, &s->l_timer[i], 1518 PTIMER_POLICY_DEFAULT); 1519 s->l_timer[i].id = i; 1520 } 1521 1522 /* IRQs */ 1523 for (i = 0; i < MCT_GT_CMP_NUM; i++) { 1524 sysbus_init_irq(dev, &s->g_timer.irq[i]); 1525 } 1526 for (i = 0; i < 2; i++) { 1527 sysbus_init_irq(dev, &s->l_timer[i].irq); 1528 } 1529 1530 memory_region_init_io(&s->iomem, obj, &exynos4210_mct_ops, s, 1531 "exynos4210-mct", MCT_SFR_SIZE); 1532 sysbus_init_mmio(dev, &s->iomem); 1533 } 1534 1535 static void exynos4210_mct_class_init(ObjectClass *klass, void *data) 1536 { 1537 DeviceClass *dc = DEVICE_CLASS(klass); 1538 1539 dc->reset = exynos4210_mct_reset; 1540 dc->vmsd = &vmstate_exynos4210_mct_state; 1541 } 1542 1543 static const TypeInfo exynos4210_mct_info = { 1544 .name = TYPE_EXYNOS4210_MCT, 1545 .parent = TYPE_SYS_BUS_DEVICE, 1546 .instance_size = sizeof(Exynos4210MCTState), 1547 .instance_init = exynos4210_mct_init, 1548 .class_init = exynos4210_mct_class_init, 1549 }; 1550 1551 static void exynos4210_mct_register_types(void) 1552 { 1553 type_register_static(&exynos4210_mct_info); 1554 } 1555 1556 type_init(exynos4210_mct_register_types) 1557