npcm7xx_timer.c (20757B)
1/* 2 * Nuvoton NPCM7xx Timer Controller 3 * 4 * Copyright 2020 Google LLC 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * for more details. 15 */ 16 17#include "qemu/osdep.h" 18 19#include "hw/irq.h" 20#include "hw/qdev-clock.h" 21#include "hw/qdev-properties.h" 22#include "hw/timer/npcm7xx_timer.h" 23#include "migration/vmstate.h" 24#include "qemu/bitops.h" 25#include "qemu/error-report.h" 26#include "qemu/log.h" 27#include "qemu/module.h" 28#include "qemu/timer.h" 29#include "qemu/units.h" 30#include "trace.h" 31 32/* 32-bit register indices. */ 33enum NPCM7xxTimerRegisters { 34 NPCM7XX_TIMER_TCSR0, 35 NPCM7XX_TIMER_TCSR1, 36 NPCM7XX_TIMER_TICR0, 37 NPCM7XX_TIMER_TICR1, 38 NPCM7XX_TIMER_TDR0, 39 NPCM7XX_TIMER_TDR1, 40 NPCM7XX_TIMER_TISR, 41 NPCM7XX_TIMER_WTCR, 42 NPCM7XX_TIMER_TCSR2, 43 NPCM7XX_TIMER_TCSR3, 44 NPCM7XX_TIMER_TICR2, 45 NPCM7XX_TIMER_TICR3, 46 NPCM7XX_TIMER_TDR2, 47 NPCM7XX_TIMER_TDR3, 48 NPCM7XX_TIMER_TCSR4 = 0x0040 / sizeof(uint32_t), 49 NPCM7XX_TIMER_TICR4 = 0x0048 / sizeof(uint32_t), 50 NPCM7XX_TIMER_TDR4 = 0x0050 / sizeof(uint32_t), 51 NPCM7XX_TIMER_REGS_END, 52}; 53 54/* Register field definitions. */ 55#define NPCM7XX_TCSR_CEN BIT(30) 56#define NPCM7XX_TCSR_IE BIT(29) 57#define NPCM7XX_TCSR_PERIODIC BIT(27) 58#define NPCM7XX_TCSR_CRST BIT(26) 59#define NPCM7XX_TCSR_CACT BIT(25) 60#define NPCM7XX_TCSR_RSVD 0x01ffff00 61#define NPCM7XX_TCSR_PRESCALE_START 0 62#define NPCM7XX_TCSR_PRESCALE_LEN 8 63 64#define NPCM7XX_WTCR_WTCLK(rv) extract32(rv, 10, 2) 65#define NPCM7XX_WTCR_FREEZE_EN BIT(9) 66#define NPCM7XX_WTCR_WTE BIT(7) 67#define NPCM7XX_WTCR_WTIE BIT(6) 68#define NPCM7XX_WTCR_WTIS(rv) extract32(rv, 4, 2) 69#define NPCM7XX_WTCR_WTIF BIT(3) 70#define NPCM7XX_WTCR_WTRF BIT(2) 71#define NPCM7XX_WTCR_WTRE BIT(1) 72#define NPCM7XX_WTCR_WTR BIT(0) 73 74/* 75 * The number of clock cycles between interrupt and reset in watchdog, used 76 * by the software to handle the interrupt before system is reset. 77 */ 78#define NPCM7XX_WATCHDOG_INTERRUPT_TO_RESET_CYCLES 1024 79 80/* Start or resume the timer. */ 81static void npcm7xx_timer_start(NPCM7xxBaseTimer *t) 82{ 83 int64_t now; 84 85 now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 86 t->expires_ns = now + t->remaining_ns; 87 timer_mod(&t->qtimer, t->expires_ns); 88} 89 90/* Stop counting. Record the time remaining so we can continue later. */ 91static void npcm7xx_timer_pause(NPCM7xxBaseTimer *t) 92{ 93 int64_t now; 94 95 timer_del(&t->qtimer); 96 now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 97 t->remaining_ns = t->expires_ns - now; 98} 99 100/* Delete the timer and reset it to default state. */ 101static void npcm7xx_timer_clear(NPCM7xxBaseTimer *t) 102{ 103 timer_del(&t->qtimer); 104 t->expires_ns = 0; 105 t->remaining_ns = 0; 106} 107 108/* 109 * Returns the index of timer in the tc->timer array. This can be used to 110 * locate the registers that belong to this timer. 111 */ 112static int npcm7xx_timer_index(NPCM7xxTimerCtrlState *tc, NPCM7xxTimer *timer) 113{ 114 int index = timer - tc->timer; 115 116 g_assert(index >= 0 && index < NPCM7XX_TIMERS_PER_CTRL); 117 118 return index; 119} 120 121/* Return the value by which to divide the reference clock rate. */ 122static uint32_t npcm7xx_tcsr_prescaler(uint32_t tcsr) 123{ 124 return extract32(tcsr, NPCM7XX_TCSR_PRESCALE_START, 125 NPCM7XX_TCSR_PRESCALE_LEN) + 1; 126} 127 128/* Convert a timer cycle count to a time interval in nanoseconds. */ 129static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer *t, uint32_t count) 130{ 131 int64_t ticks = count; 132 133 ticks *= npcm7xx_tcsr_prescaler(t->tcsr); 134 135 return clock_ticks_to_ns(t->ctrl->clock, ticks); 136} 137 138/* Convert a time interval in nanoseconds to a timer cycle count. */ 139static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns) 140{ 141 return clock_ns_to_ticks(t->ctrl->clock, ns) / 142 npcm7xx_tcsr_prescaler(t->tcsr); 143} 144 145static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t) 146{ 147 switch (NPCM7XX_WTCR_WTCLK(t->wtcr)) { 148 case 0: 149 return 1; 150 case 1: 151 return 256; 152 case 2: 153 return 2048; 154 case 3: 155 return 65536; 156 default: 157 g_assert_not_reached(); 158 } 159} 160 161static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t, 162 int64_t cycles) 163{ 164 int64_t ticks = cycles * npcm7xx_watchdog_timer_prescaler(t); 165 int64_t ns = clock_ticks_to_ns(t->ctrl->clock, ticks); 166 167 /* 168 * The reset function always clears the current timer. The caller of the 169 * this needs to decide whether to start the watchdog timer based on 170 * specific flag in WTCR. 171 */ 172 npcm7xx_timer_clear(&t->base_timer); 173 174 t->base_timer.remaining_ns = ns; 175} 176 177static void npcm7xx_watchdog_timer_reset(NPCM7xxWatchdogTimer *t) 178{ 179 int64_t cycles = 1; 180 uint32_t s = NPCM7XX_WTCR_WTIS(t->wtcr); 181 182 g_assert(s <= 3); 183 184 cycles <<= NPCM7XX_WATCHDOG_BASETIME_SHIFT; 185 cycles <<= 2 * s; 186 187 npcm7xx_watchdog_timer_reset_cycles(t, cycles); 188} 189 190/* 191 * Raise the interrupt line if there's a pending interrupt and interrupts are 192 * enabled for this timer. If not, lower it. 193 */ 194static void npcm7xx_timer_check_interrupt(NPCM7xxTimer *t) 195{ 196 NPCM7xxTimerCtrlState *tc = t->ctrl; 197 int index = npcm7xx_timer_index(tc, t); 198 bool pending = (t->tcsr & NPCM7XX_TCSR_IE) && (tc->tisr & BIT(index)); 199 200 qemu_set_irq(t->irq, pending); 201 trace_npcm7xx_timer_irq(DEVICE(tc)->canonical_path, index, pending); 202} 203 204/* 205 * Called when the counter reaches zero. Sets the interrupt flag, and either 206 * restarts or disables the timer. 207 */ 208static void npcm7xx_timer_reached_zero(NPCM7xxTimer *t) 209{ 210 NPCM7xxTimerCtrlState *tc = t->ctrl; 211 int index = npcm7xx_timer_index(tc, t); 212 213 tc->tisr |= BIT(index); 214 215 if (t->tcsr & NPCM7XX_TCSR_PERIODIC) { 216 t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr); 217 if (t->tcsr & NPCM7XX_TCSR_CEN) { 218 npcm7xx_timer_start(&t->base_timer); 219 } 220 } else { 221 t->tcsr &= ~(NPCM7XX_TCSR_CEN | NPCM7XX_TCSR_CACT); 222 } 223 224 npcm7xx_timer_check_interrupt(t); 225} 226 227 228/* 229 * Restart the timer from its initial value. If the timer was enabled and stays 230 * enabled, adjust the QEMU timer according to the new count. If the timer is 231 * transitioning from disabled to enabled, the caller is expected to start the 232 * timer later. 233 */ 234static void npcm7xx_timer_restart(NPCM7xxTimer *t, uint32_t old_tcsr) 235{ 236 t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr); 237 238 if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) { 239 npcm7xx_timer_start(&t->base_timer); 240 } 241} 242 243/* Register read and write handlers */ 244 245static uint32_t npcm7xx_timer_read_tdr(NPCM7xxTimer *t) 246{ 247 if (t->tcsr & NPCM7XX_TCSR_CEN) { 248 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 249 250 return npcm7xx_timer_ns_to_count(t, t->base_timer.expires_ns - now); 251 } 252 253 return npcm7xx_timer_ns_to_count(t, t->base_timer.remaining_ns); 254} 255 256static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr) 257{ 258 uint32_t old_tcsr = t->tcsr; 259 uint32_t tdr; 260 261 if (new_tcsr & NPCM7XX_TCSR_RSVD) { 262 qemu_log_mask(LOG_GUEST_ERROR, "%s: reserved bits in 0x%08x ignored\n", 263 __func__, new_tcsr); 264 new_tcsr &= ~NPCM7XX_TCSR_RSVD; 265 } 266 if (new_tcsr & NPCM7XX_TCSR_CACT) { 267 qemu_log_mask(LOG_GUEST_ERROR, "%s: read-only bits in 0x%08x ignored\n", 268 __func__, new_tcsr); 269 new_tcsr &= ~NPCM7XX_TCSR_CACT; 270 } 271 if ((new_tcsr & NPCM7XX_TCSR_CRST) && (new_tcsr & NPCM7XX_TCSR_CEN)) { 272 qemu_log_mask(LOG_GUEST_ERROR, 273 "%s: both CRST and CEN set; ignoring CEN.\n", 274 __func__); 275 new_tcsr &= ~NPCM7XX_TCSR_CEN; 276 } 277 278 /* Calculate the value of TDR before potentially changing the prescaler. */ 279 tdr = npcm7xx_timer_read_tdr(t); 280 281 t->tcsr = (t->tcsr & NPCM7XX_TCSR_CACT) | new_tcsr; 282 283 if (npcm7xx_tcsr_prescaler(old_tcsr) != npcm7xx_tcsr_prescaler(new_tcsr)) { 284 /* Recalculate time remaining based on the current TDR value. */ 285 t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, tdr); 286 if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) { 287 npcm7xx_timer_start(&t->base_timer); 288 } 289 } 290 291 if ((old_tcsr ^ new_tcsr) & NPCM7XX_TCSR_IE) { 292 npcm7xx_timer_check_interrupt(t); 293 } 294 if (new_tcsr & NPCM7XX_TCSR_CRST) { 295 npcm7xx_timer_restart(t, old_tcsr); 296 t->tcsr &= ~NPCM7XX_TCSR_CRST; 297 } 298 if ((old_tcsr ^ new_tcsr) & NPCM7XX_TCSR_CEN) { 299 if (new_tcsr & NPCM7XX_TCSR_CEN) { 300 t->tcsr |= NPCM7XX_TCSR_CACT; 301 npcm7xx_timer_start(&t->base_timer); 302 } else { 303 t->tcsr &= ~NPCM7XX_TCSR_CACT; 304 npcm7xx_timer_pause(&t->base_timer); 305 if (t->base_timer.remaining_ns <= 0) { 306 npcm7xx_timer_reached_zero(t); 307 } 308 } 309 } 310} 311 312static void npcm7xx_timer_write_ticr(NPCM7xxTimer *t, uint32_t new_ticr) 313{ 314 t->ticr = new_ticr; 315 316 npcm7xx_timer_restart(t, t->tcsr); 317} 318 319static void npcm7xx_timer_write_tisr(NPCM7xxTimerCtrlState *s, uint32_t value) 320{ 321 int i; 322 323 s->tisr &= ~value; 324 for (i = 0; i < ARRAY_SIZE(s->timer); i++) { 325 if (value & (1U << i)) { 326 npcm7xx_timer_check_interrupt(&s->timer[i]); 327 } 328 329 } 330} 331 332static void npcm7xx_timer_write_wtcr(NPCM7xxWatchdogTimer *t, uint32_t new_wtcr) 333{ 334 uint32_t old_wtcr = t->wtcr; 335 336 /* 337 * WTIF and WTRF are cleared by writing 1. Writing 0 makes these bits 338 * unchanged. 339 */ 340 if (new_wtcr & NPCM7XX_WTCR_WTIF) { 341 new_wtcr &= ~NPCM7XX_WTCR_WTIF; 342 } else if (old_wtcr & NPCM7XX_WTCR_WTIF) { 343 new_wtcr |= NPCM7XX_WTCR_WTIF; 344 } 345 if (new_wtcr & NPCM7XX_WTCR_WTRF) { 346 new_wtcr &= ~NPCM7XX_WTCR_WTRF; 347 } else if (old_wtcr & NPCM7XX_WTCR_WTRF) { 348 new_wtcr |= NPCM7XX_WTCR_WTRF; 349 } 350 351 t->wtcr = new_wtcr; 352 353 if (new_wtcr & NPCM7XX_WTCR_WTR) { 354 t->wtcr &= ~NPCM7XX_WTCR_WTR; 355 npcm7xx_watchdog_timer_reset(t); 356 if (new_wtcr & NPCM7XX_WTCR_WTE) { 357 npcm7xx_timer_start(&t->base_timer); 358 } 359 } else if ((old_wtcr ^ new_wtcr) & NPCM7XX_WTCR_WTE) { 360 if (new_wtcr & NPCM7XX_WTCR_WTE) { 361 npcm7xx_timer_start(&t->base_timer); 362 } else { 363 npcm7xx_timer_pause(&t->base_timer); 364 } 365 } 366 367} 368 369static hwaddr npcm7xx_tcsr_index(hwaddr reg) 370{ 371 switch (reg) { 372 case NPCM7XX_TIMER_TCSR0: 373 return 0; 374 case NPCM7XX_TIMER_TCSR1: 375 return 1; 376 case NPCM7XX_TIMER_TCSR2: 377 return 2; 378 case NPCM7XX_TIMER_TCSR3: 379 return 3; 380 case NPCM7XX_TIMER_TCSR4: 381 return 4; 382 default: 383 g_assert_not_reached(); 384 } 385} 386 387static hwaddr npcm7xx_ticr_index(hwaddr reg) 388{ 389 switch (reg) { 390 case NPCM7XX_TIMER_TICR0: 391 return 0; 392 case NPCM7XX_TIMER_TICR1: 393 return 1; 394 case NPCM7XX_TIMER_TICR2: 395 return 2; 396 case NPCM7XX_TIMER_TICR3: 397 return 3; 398 case NPCM7XX_TIMER_TICR4: 399 return 4; 400 default: 401 g_assert_not_reached(); 402 } 403} 404 405static hwaddr npcm7xx_tdr_index(hwaddr reg) 406{ 407 switch (reg) { 408 case NPCM7XX_TIMER_TDR0: 409 return 0; 410 case NPCM7XX_TIMER_TDR1: 411 return 1; 412 case NPCM7XX_TIMER_TDR2: 413 return 2; 414 case NPCM7XX_TIMER_TDR3: 415 return 3; 416 case NPCM7XX_TIMER_TDR4: 417 return 4; 418 default: 419 g_assert_not_reached(); 420 } 421} 422 423static uint64_t npcm7xx_timer_read(void *opaque, hwaddr offset, unsigned size) 424{ 425 NPCM7xxTimerCtrlState *s = opaque; 426 uint64_t value = 0; 427 hwaddr reg; 428 429 reg = offset / sizeof(uint32_t); 430 switch (reg) { 431 case NPCM7XX_TIMER_TCSR0: 432 case NPCM7XX_TIMER_TCSR1: 433 case NPCM7XX_TIMER_TCSR2: 434 case NPCM7XX_TIMER_TCSR3: 435 case NPCM7XX_TIMER_TCSR4: 436 value = s->timer[npcm7xx_tcsr_index(reg)].tcsr; 437 break; 438 439 case NPCM7XX_TIMER_TICR0: 440 case NPCM7XX_TIMER_TICR1: 441 case NPCM7XX_TIMER_TICR2: 442 case NPCM7XX_TIMER_TICR3: 443 case NPCM7XX_TIMER_TICR4: 444 value = s->timer[npcm7xx_ticr_index(reg)].ticr; 445 break; 446 447 case NPCM7XX_TIMER_TDR0: 448 case NPCM7XX_TIMER_TDR1: 449 case NPCM7XX_TIMER_TDR2: 450 case NPCM7XX_TIMER_TDR3: 451 case NPCM7XX_TIMER_TDR4: 452 value = npcm7xx_timer_read_tdr(&s->timer[npcm7xx_tdr_index(reg)]); 453 break; 454 455 case NPCM7XX_TIMER_TISR: 456 value = s->tisr; 457 break; 458 459 case NPCM7XX_TIMER_WTCR: 460 value = s->watchdog_timer.wtcr; 461 break; 462 463 default: 464 qemu_log_mask(LOG_GUEST_ERROR, 465 "%s: invalid offset 0x%04" HWADDR_PRIx "\n", 466 __func__, offset); 467 break; 468 } 469 470 trace_npcm7xx_timer_read(DEVICE(s)->canonical_path, offset, value); 471 472 return value; 473} 474 475static void npcm7xx_timer_write(void *opaque, hwaddr offset, 476 uint64_t v, unsigned size) 477{ 478 uint32_t reg = offset / sizeof(uint32_t); 479 NPCM7xxTimerCtrlState *s = opaque; 480 uint32_t value = v; 481 482 trace_npcm7xx_timer_write(DEVICE(s)->canonical_path, offset, value); 483 484 switch (reg) { 485 case NPCM7XX_TIMER_TCSR0: 486 case NPCM7XX_TIMER_TCSR1: 487 case NPCM7XX_TIMER_TCSR2: 488 case NPCM7XX_TIMER_TCSR3: 489 case NPCM7XX_TIMER_TCSR4: 490 npcm7xx_timer_write_tcsr(&s->timer[npcm7xx_tcsr_index(reg)], value); 491 return; 492 493 case NPCM7XX_TIMER_TICR0: 494 case NPCM7XX_TIMER_TICR1: 495 case NPCM7XX_TIMER_TICR2: 496 case NPCM7XX_TIMER_TICR3: 497 case NPCM7XX_TIMER_TICR4: 498 npcm7xx_timer_write_ticr(&s->timer[npcm7xx_ticr_index(reg)], value); 499 return; 500 501 case NPCM7XX_TIMER_TDR0: 502 case NPCM7XX_TIMER_TDR1: 503 case NPCM7XX_TIMER_TDR2: 504 case NPCM7XX_TIMER_TDR3: 505 case NPCM7XX_TIMER_TDR4: 506 qemu_log_mask(LOG_GUEST_ERROR, 507 "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n", 508 __func__, offset); 509 return; 510 511 case NPCM7XX_TIMER_TISR: 512 npcm7xx_timer_write_tisr(s, value); 513 return; 514 515 case NPCM7XX_TIMER_WTCR: 516 npcm7xx_timer_write_wtcr(&s->watchdog_timer, value); 517 return; 518 } 519 520 qemu_log_mask(LOG_GUEST_ERROR, 521 "%s: invalid offset 0x%04" HWADDR_PRIx "\n", 522 __func__, offset); 523} 524 525static const struct MemoryRegionOps npcm7xx_timer_ops = { 526 .read = npcm7xx_timer_read, 527 .write = npcm7xx_timer_write, 528 .endianness = DEVICE_LITTLE_ENDIAN, 529 .valid = { 530 .min_access_size = 4, 531 .max_access_size = 4, 532 .unaligned = false, 533 }, 534}; 535 536/* Called when the QEMU timer expires. */ 537static void npcm7xx_timer_expired(void *opaque) 538{ 539 NPCM7xxTimer *t = opaque; 540 541 if (t->tcsr & NPCM7XX_TCSR_CEN) { 542 npcm7xx_timer_reached_zero(t); 543 } 544} 545 546static void npcm7xx_timer_enter_reset(Object *obj, ResetType type) 547{ 548 NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj); 549 int i; 550 551 for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) { 552 NPCM7xxTimer *t = &s->timer[i]; 553 554 npcm7xx_timer_clear(&t->base_timer); 555 t->tcsr = 0x00000005; 556 t->ticr = 0x00000000; 557 } 558 559 s->tisr = 0x00000000; 560 /* 561 * Set WTCLK to 1(default) and reset all flags except WTRF. 562 * WTRF is not reset during a core domain reset. 563 */ 564 s->watchdog_timer.wtcr = 0x00000400 | (s->watchdog_timer.wtcr & 565 NPCM7XX_WTCR_WTRF); 566} 567 568static void npcm7xx_watchdog_timer_expired(void *opaque) 569{ 570 NPCM7xxWatchdogTimer *t = opaque; 571 572 if (t->wtcr & NPCM7XX_WTCR_WTE) { 573 if (t->wtcr & NPCM7XX_WTCR_WTIF) { 574 if (t->wtcr & NPCM7XX_WTCR_WTRE) { 575 t->wtcr |= NPCM7XX_WTCR_WTRF; 576 /* send reset signal to CLK module*/ 577 qemu_irq_raise(t->reset_signal); 578 } 579 } else { 580 t->wtcr |= NPCM7XX_WTCR_WTIF; 581 if (t->wtcr & NPCM7XX_WTCR_WTIE) { 582 /* send interrupt */ 583 qemu_irq_raise(t->irq); 584 } 585 npcm7xx_watchdog_timer_reset_cycles(t, 586 NPCM7XX_WATCHDOG_INTERRUPT_TO_RESET_CYCLES); 587 npcm7xx_timer_start(&t->base_timer); 588 } 589 } 590} 591 592static void npcm7xx_timer_hold_reset(Object *obj) 593{ 594 NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj); 595 int i; 596 597 for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) { 598 qemu_irq_lower(s->timer[i].irq); 599 } 600 qemu_irq_lower(s->watchdog_timer.irq); 601} 602 603static void npcm7xx_timer_init(Object *obj) 604{ 605 NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj); 606 DeviceState *dev = DEVICE(obj); 607 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 608 int i; 609 NPCM7xxWatchdogTimer *w; 610 611 for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) { 612 NPCM7xxTimer *t = &s->timer[i]; 613 t->ctrl = s; 614 timer_init_ns(&t->base_timer.qtimer, QEMU_CLOCK_VIRTUAL, 615 npcm7xx_timer_expired, t); 616 sysbus_init_irq(sbd, &t->irq); 617 } 618 619 w = &s->watchdog_timer; 620 w->ctrl = s; 621 timer_init_ns(&w->base_timer.qtimer, QEMU_CLOCK_VIRTUAL, 622 npcm7xx_watchdog_timer_expired, w); 623 sysbus_init_irq(sbd, &w->irq); 624 625 memory_region_init_io(&s->iomem, obj, &npcm7xx_timer_ops, s, 626 TYPE_NPCM7XX_TIMER, 4 * KiB); 627 sysbus_init_mmio(sbd, &s->iomem); 628 qdev_init_gpio_out_named(dev, &w->reset_signal, 629 NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 1); 630 s->clock = qdev_init_clock_in(dev, "clock", NULL, NULL, 0); 631} 632 633static const VMStateDescription vmstate_npcm7xx_base_timer = { 634 .name = "npcm7xx-base-timer", 635 .version_id = 0, 636 .minimum_version_id = 0, 637 .fields = (VMStateField[]) { 638 VMSTATE_TIMER(qtimer, NPCM7xxBaseTimer), 639 VMSTATE_INT64(expires_ns, NPCM7xxBaseTimer), 640 VMSTATE_INT64(remaining_ns, NPCM7xxBaseTimer), 641 VMSTATE_END_OF_LIST(), 642 }, 643}; 644 645static const VMStateDescription vmstate_npcm7xx_timer = { 646 .name = "npcm7xx-timer", 647 .version_id = 1, 648 .minimum_version_id = 1, 649 .fields = (VMStateField[]) { 650 VMSTATE_STRUCT(base_timer, NPCM7xxTimer, 651 0, vmstate_npcm7xx_base_timer, 652 NPCM7xxBaseTimer), 653 VMSTATE_UINT32(tcsr, NPCM7xxTimer), 654 VMSTATE_UINT32(ticr, NPCM7xxTimer), 655 VMSTATE_END_OF_LIST(), 656 }, 657}; 658 659static const VMStateDescription vmstate_npcm7xx_watchdog_timer = { 660 .name = "npcm7xx-watchdog-timer", 661 .version_id = 0, 662 .minimum_version_id = 0, 663 .fields = (VMStateField[]) { 664 VMSTATE_STRUCT(base_timer, NPCM7xxWatchdogTimer, 665 0, vmstate_npcm7xx_base_timer, 666 NPCM7xxBaseTimer), 667 VMSTATE_UINT32(wtcr, NPCM7xxWatchdogTimer), 668 VMSTATE_END_OF_LIST(), 669 }, 670}; 671 672static const VMStateDescription vmstate_npcm7xx_timer_ctrl = { 673 .name = "npcm7xx-timer-ctrl", 674 .version_id = 2, 675 .minimum_version_id = 2, 676 .fields = (VMStateField[]) { 677 VMSTATE_UINT32(tisr, NPCM7xxTimerCtrlState), 678 VMSTATE_CLOCK(clock, NPCM7xxTimerCtrlState), 679 VMSTATE_STRUCT_ARRAY(timer, NPCM7xxTimerCtrlState, 680 NPCM7XX_TIMERS_PER_CTRL, 0, vmstate_npcm7xx_timer, 681 NPCM7xxTimer), 682 VMSTATE_STRUCT(watchdog_timer, NPCM7xxTimerCtrlState, 683 0, vmstate_npcm7xx_watchdog_timer, 684 NPCM7xxWatchdogTimer), 685 VMSTATE_END_OF_LIST(), 686 }, 687}; 688 689static void npcm7xx_timer_class_init(ObjectClass *klass, void *data) 690{ 691 ResettableClass *rc = RESETTABLE_CLASS(klass); 692 DeviceClass *dc = DEVICE_CLASS(klass); 693 694 QEMU_BUILD_BUG_ON(NPCM7XX_TIMER_REGS_END > NPCM7XX_TIMER_NR_REGS); 695 696 dc->desc = "NPCM7xx Timer Controller"; 697 dc->vmsd = &vmstate_npcm7xx_timer_ctrl; 698 rc->phases.enter = npcm7xx_timer_enter_reset; 699 rc->phases.hold = npcm7xx_timer_hold_reset; 700} 701 702static const TypeInfo npcm7xx_timer_info = { 703 .name = TYPE_NPCM7XX_TIMER, 704 .parent = TYPE_SYS_BUS_DEVICE, 705 .instance_size = sizeof(NPCM7xxTimerCtrlState), 706 .class_init = npcm7xx_timer_class_init, 707 .instance_init = npcm7xx_timer_init, 708}; 709 710static void npcm7xx_timer_register_type(void) 711{ 712 type_register_static(&npcm7xx_timer_info); 713} 714type_init(npcm7xx_timer_register_type);