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/misc/npcm7xx_clk.h" 21 #include "hw/timer/npcm7xx_timer.h" 22 #include "migration/vmstate.h" 23 #include "qemu/bitops.h" 24 #include "qemu/error-report.h" 25 #include "qemu/log.h" 26 #include "qemu/module.h" 27 #include "qemu/timer.h" 28 #include "qemu/units.h" 29 #include "trace.h" 30 31 /* 32-bit register indices. */ 32 enum NPCM7xxTimerRegisters { 33 NPCM7XX_TIMER_TCSR0, 34 NPCM7XX_TIMER_TCSR1, 35 NPCM7XX_TIMER_TICR0, 36 NPCM7XX_TIMER_TICR1, 37 NPCM7XX_TIMER_TDR0, 38 NPCM7XX_TIMER_TDR1, 39 NPCM7XX_TIMER_TISR, 40 NPCM7XX_TIMER_WTCR, 41 NPCM7XX_TIMER_TCSR2, 42 NPCM7XX_TIMER_TCSR3, 43 NPCM7XX_TIMER_TICR2, 44 NPCM7XX_TIMER_TICR3, 45 NPCM7XX_TIMER_TDR2, 46 NPCM7XX_TIMER_TDR3, 47 NPCM7XX_TIMER_TCSR4 = 0x0040 / sizeof(uint32_t), 48 NPCM7XX_TIMER_TICR4 = 0x0048 / sizeof(uint32_t), 49 NPCM7XX_TIMER_TDR4 = 0x0050 / sizeof(uint32_t), 50 NPCM7XX_TIMER_REGS_END, 51 }; 52 53 /* Register field definitions. */ 54 #define NPCM7XX_TCSR_CEN BIT(30) 55 #define NPCM7XX_TCSR_IE BIT(29) 56 #define NPCM7XX_TCSR_PERIODIC BIT(27) 57 #define NPCM7XX_TCSR_CRST BIT(26) 58 #define NPCM7XX_TCSR_CACT BIT(25) 59 #define NPCM7XX_TCSR_RSVD 0x01ffff00 60 #define NPCM7XX_TCSR_PRESCALE_START 0 61 #define NPCM7XX_TCSR_PRESCALE_LEN 8 62 63 /* 64 * Returns the index of timer in the tc->timer array. This can be used to 65 * locate the registers that belong to this timer. 66 */ 67 static int npcm7xx_timer_index(NPCM7xxTimerCtrlState *tc, NPCM7xxTimer *timer) 68 { 69 int index = timer - tc->timer; 70 71 g_assert(index >= 0 && index < NPCM7XX_TIMERS_PER_CTRL); 72 73 return index; 74 } 75 76 /* Return the value by which to divide the reference clock rate. */ 77 static uint32_t npcm7xx_tcsr_prescaler(uint32_t tcsr) 78 { 79 return extract32(tcsr, NPCM7XX_TCSR_PRESCALE_START, 80 NPCM7XX_TCSR_PRESCALE_LEN) + 1; 81 } 82 83 /* Convert a timer cycle count to a time interval in nanoseconds. */ 84 static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer *t, uint32_t count) 85 { 86 int64_t ns = count; 87 88 ns *= NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ; 89 ns *= npcm7xx_tcsr_prescaler(t->tcsr); 90 91 return ns; 92 } 93 94 /* Convert a time interval in nanoseconds to a timer cycle count. */ 95 static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns) 96 { 97 int64_t count; 98 99 count = ns / (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ); 100 count /= npcm7xx_tcsr_prescaler(t->tcsr); 101 102 return count; 103 } 104 105 /* 106 * Raise the interrupt line if there's a pending interrupt and interrupts are 107 * enabled for this timer. If not, lower it. 108 */ 109 static void npcm7xx_timer_check_interrupt(NPCM7xxTimer *t) 110 { 111 NPCM7xxTimerCtrlState *tc = t->ctrl; 112 int index = npcm7xx_timer_index(tc, t); 113 bool pending = (t->tcsr & NPCM7XX_TCSR_IE) && (tc->tisr & BIT(index)); 114 115 qemu_set_irq(t->irq, pending); 116 trace_npcm7xx_timer_irq(DEVICE(tc)->canonical_path, index, pending); 117 } 118 119 /* Start or resume the timer. */ 120 static void npcm7xx_timer_start(NPCM7xxTimer *t) 121 { 122 int64_t now; 123 124 now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 125 t->expires_ns = now + t->remaining_ns; 126 timer_mod(&t->qtimer, t->expires_ns); 127 } 128 129 /* 130 * Called when the counter reaches zero. Sets the interrupt flag, and either 131 * restarts or disables the timer. 132 */ 133 static void npcm7xx_timer_reached_zero(NPCM7xxTimer *t) 134 { 135 NPCM7xxTimerCtrlState *tc = t->ctrl; 136 int index = npcm7xx_timer_index(tc, t); 137 138 tc->tisr |= BIT(index); 139 140 if (t->tcsr & NPCM7XX_TCSR_PERIODIC) { 141 t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr); 142 if (t->tcsr & NPCM7XX_TCSR_CEN) { 143 npcm7xx_timer_start(t); 144 } 145 } else { 146 t->tcsr &= ~(NPCM7XX_TCSR_CEN | NPCM7XX_TCSR_CACT); 147 } 148 149 npcm7xx_timer_check_interrupt(t); 150 } 151 152 /* Stop counting. Record the time remaining so we can continue later. */ 153 static void npcm7xx_timer_pause(NPCM7xxTimer *t) 154 { 155 int64_t now; 156 157 timer_del(&t->qtimer); 158 now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 159 t->remaining_ns = t->expires_ns - now; 160 if (t->remaining_ns <= 0) { 161 npcm7xx_timer_reached_zero(t); 162 } 163 } 164 165 /* 166 * Restart the timer from its initial value. If the timer was enabled and stays 167 * enabled, adjust the QEMU timer according to the new count. If the timer is 168 * transitioning from disabled to enabled, the caller is expected to start the 169 * timer later. 170 */ 171 static void npcm7xx_timer_restart(NPCM7xxTimer *t, uint32_t old_tcsr) 172 { 173 t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr); 174 175 if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) { 176 npcm7xx_timer_start(t); 177 } 178 } 179 180 /* Register read and write handlers */ 181 182 static uint32_t npcm7xx_timer_read_tdr(NPCM7xxTimer *t) 183 { 184 if (t->tcsr & NPCM7XX_TCSR_CEN) { 185 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 186 187 return npcm7xx_timer_ns_to_count(t, t->expires_ns - now); 188 } 189 190 return npcm7xx_timer_ns_to_count(t, t->remaining_ns); 191 } 192 193 static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr) 194 { 195 uint32_t old_tcsr = t->tcsr; 196 uint32_t tdr; 197 198 if (new_tcsr & NPCM7XX_TCSR_RSVD) { 199 qemu_log_mask(LOG_GUEST_ERROR, "%s: reserved bits in 0x%08x ignored\n", 200 __func__, new_tcsr); 201 new_tcsr &= ~NPCM7XX_TCSR_RSVD; 202 } 203 if (new_tcsr & NPCM7XX_TCSR_CACT) { 204 qemu_log_mask(LOG_GUEST_ERROR, "%s: read-only bits in 0x%08x ignored\n", 205 __func__, new_tcsr); 206 new_tcsr &= ~NPCM7XX_TCSR_CACT; 207 } 208 if ((new_tcsr & NPCM7XX_TCSR_CRST) && (new_tcsr & NPCM7XX_TCSR_CEN)) { 209 qemu_log_mask(LOG_GUEST_ERROR, 210 "%s: both CRST and CEN set; ignoring CEN.\n", 211 __func__); 212 new_tcsr &= ~NPCM7XX_TCSR_CEN; 213 } 214 215 /* Calculate the value of TDR before potentially changing the prescaler. */ 216 tdr = npcm7xx_timer_read_tdr(t); 217 218 t->tcsr = (t->tcsr & NPCM7XX_TCSR_CACT) | new_tcsr; 219 220 if (npcm7xx_tcsr_prescaler(old_tcsr) != npcm7xx_tcsr_prescaler(new_tcsr)) { 221 /* Recalculate time remaining based on the current TDR value. */ 222 t->remaining_ns = npcm7xx_timer_count_to_ns(t, tdr); 223 if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) { 224 npcm7xx_timer_start(t); 225 } 226 } 227 228 if ((old_tcsr ^ new_tcsr) & NPCM7XX_TCSR_IE) { 229 npcm7xx_timer_check_interrupt(t); 230 } 231 if (new_tcsr & NPCM7XX_TCSR_CRST) { 232 npcm7xx_timer_restart(t, old_tcsr); 233 t->tcsr &= ~NPCM7XX_TCSR_CRST; 234 } 235 if ((old_tcsr ^ new_tcsr) & NPCM7XX_TCSR_CEN) { 236 if (new_tcsr & NPCM7XX_TCSR_CEN) { 237 t->tcsr |= NPCM7XX_TCSR_CACT; 238 npcm7xx_timer_start(t); 239 } else { 240 t->tcsr &= ~NPCM7XX_TCSR_CACT; 241 npcm7xx_timer_pause(t); 242 } 243 } 244 } 245 246 static void npcm7xx_timer_write_ticr(NPCM7xxTimer *t, uint32_t new_ticr) 247 { 248 t->ticr = new_ticr; 249 250 npcm7xx_timer_restart(t, t->tcsr); 251 } 252 253 static void npcm7xx_timer_write_tisr(NPCM7xxTimerCtrlState *s, uint32_t value) 254 { 255 int i; 256 257 s->tisr &= ~value; 258 for (i = 0; i < ARRAY_SIZE(s->timer); i++) { 259 if (value & (1U << i)) { 260 npcm7xx_timer_check_interrupt(&s->timer[i]); 261 } 262 } 263 } 264 265 static hwaddr npcm7xx_tcsr_index(hwaddr reg) 266 { 267 switch (reg) { 268 case NPCM7XX_TIMER_TCSR0: 269 return 0; 270 case NPCM7XX_TIMER_TCSR1: 271 return 1; 272 case NPCM7XX_TIMER_TCSR2: 273 return 2; 274 case NPCM7XX_TIMER_TCSR3: 275 return 3; 276 case NPCM7XX_TIMER_TCSR4: 277 return 4; 278 default: 279 g_assert_not_reached(); 280 } 281 } 282 283 static hwaddr npcm7xx_ticr_index(hwaddr reg) 284 { 285 switch (reg) { 286 case NPCM7XX_TIMER_TICR0: 287 return 0; 288 case NPCM7XX_TIMER_TICR1: 289 return 1; 290 case NPCM7XX_TIMER_TICR2: 291 return 2; 292 case NPCM7XX_TIMER_TICR3: 293 return 3; 294 case NPCM7XX_TIMER_TICR4: 295 return 4; 296 default: 297 g_assert_not_reached(); 298 } 299 } 300 301 static hwaddr npcm7xx_tdr_index(hwaddr reg) 302 { 303 switch (reg) { 304 case NPCM7XX_TIMER_TDR0: 305 return 0; 306 case NPCM7XX_TIMER_TDR1: 307 return 1; 308 case NPCM7XX_TIMER_TDR2: 309 return 2; 310 case NPCM7XX_TIMER_TDR3: 311 return 3; 312 case NPCM7XX_TIMER_TDR4: 313 return 4; 314 default: 315 g_assert_not_reached(); 316 } 317 } 318 319 static uint64_t npcm7xx_timer_read(void *opaque, hwaddr offset, unsigned size) 320 { 321 NPCM7xxTimerCtrlState *s = opaque; 322 uint64_t value = 0; 323 hwaddr reg; 324 325 reg = offset / sizeof(uint32_t); 326 switch (reg) { 327 case NPCM7XX_TIMER_TCSR0: 328 case NPCM7XX_TIMER_TCSR1: 329 case NPCM7XX_TIMER_TCSR2: 330 case NPCM7XX_TIMER_TCSR3: 331 case NPCM7XX_TIMER_TCSR4: 332 value = s->timer[npcm7xx_tcsr_index(reg)].tcsr; 333 break; 334 335 case NPCM7XX_TIMER_TICR0: 336 case NPCM7XX_TIMER_TICR1: 337 case NPCM7XX_TIMER_TICR2: 338 case NPCM7XX_TIMER_TICR3: 339 case NPCM7XX_TIMER_TICR4: 340 value = s->timer[npcm7xx_ticr_index(reg)].ticr; 341 break; 342 343 case NPCM7XX_TIMER_TDR0: 344 case NPCM7XX_TIMER_TDR1: 345 case NPCM7XX_TIMER_TDR2: 346 case NPCM7XX_TIMER_TDR3: 347 case NPCM7XX_TIMER_TDR4: 348 value = npcm7xx_timer_read_tdr(&s->timer[npcm7xx_tdr_index(reg)]); 349 break; 350 351 case NPCM7XX_TIMER_TISR: 352 value = s->tisr; 353 break; 354 355 case NPCM7XX_TIMER_WTCR: 356 value = s->wtcr; 357 break; 358 359 default: 360 qemu_log_mask(LOG_GUEST_ERROR, 361 "%s: invalid offset 0x%04" HWADDR_PRIx "\n", 362 __func__, offset); 363 break; 364 } 365 366 trace_npcm7xx_timer_read(DEVICE(s)->canonical_path, offset, value); 367 368 return value; 369 } 370 371 static void npcm7xx_timer_write(void *opaque, hwaddr offset, 372 uint64_t v, unsigned size) 373 { 374 uint32_t reg = offset / sizeof(uint32_t); 375 NPCM7xxTimerCtrlState *s = opaque; 376 uint32_t value = v; 377 378 trace_npcm7xx_timer_write(DEVICE(s)->canonical_path, offset, value); 379 380 switch (reg) { 381 case NPCM7XX_TIMER_TCSR0: 382 case NPCM7XX_TIMER_TCSR1: 383 case NPCM7XX_TIMER_TCSR2: 384 case NPCM7XX_TIMER_TCSR3: 385 case NPCM7XX_TIMER_TCSR4: 386 npcm7xx_timer_write_tcsr(&s->timer[npcm7xx_tcsr_index(reg)], value); 387 return; 388 389 case NPCM7XX_TIMER_TICR0: 390 case NPCM7XX_TIMER_TICR1: 391 case NPCM7XX_TIMER_TICR2: 392 case NPCM7XX_TIMER_TICR3: 393 case NPCM7XX_TIMER_TICR4: 394 npcm7xx_timer_write_ticr(&s->timer[npcm7xx_ticr_index(reg)], value); 395 return; 396 397 case NPCM7XX_TIMER_TDR0: 398 case NPCM7XX_TIMER_TDR1: 399 case NPCM7XX_TIMER_TDR2: 400 case NPCM7XX_TIMER_TDR3: 401 case NPCM7XX_TIMER_TDR4: 402 qemu_log_mask(LOG_GUEST_ERROR, 403 "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n", 404 __func__, offset); 405 return; 406 407 case NPCM7XX_TIMER_TISR: 408 npcm7xx_timer_write_tisr(s, value); 409 return; 410 411 case NPCM7XX_TIMER_WTCR: 412 qemu_log_mask(LOG_UNIMP, "%s: WTCR write not implemented: 0x%08x\n", 413 __func__, value); 414 return; 415 } 416 417 qemu_log_mask(LOG_GUEST_ERROR, 418 "%s: invalid offset 0x%04" HWADDR_PRIx "\n", 419 __func__, offset); 420 } 421 422 static const struct MemoryRegionOps npcm7xx_timer_ops = { 423 .read = npcm7xx_timer_read, 424 .write = npcm7xx_timer_write, 425 .endianness = DEVICE_LITTLE_ENDIAN, 426 .valid = { 427 .min_access_size = 4, 428 .max_access_size = 4, 429 .unaligned = false, 430 }, 431 }; 432 433 /* Called when the QEMU timer expires. */ 434 static void npcm7xx_timer_expired(void *opaque) 435 { 436 NPCM7xxTimer *t = opaque; 437 438 if (t->tcsr & NPCM7XX_TCSR_CEN) { 439 npcm7xx_timer_reached_zero(t); 440 } 441 } 442 443 static void npcm7xx_timer_enter_reset(Object *obj, ResetType type) 444 { 445 NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj); 446 int i; 447 448 for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) { 449 NPCM7xxTimer *t = &s->timer[i]; 450 451 timer_del(&t->qtimer); 452 t->expires_ns = 0; 453 t->remaining_ns = 0; 454 t->tcsr = 0x00000005; 455 t->ticr = 0x00000000; 456 } 457 458 s->tisr = 0x00000000; 459 s->wtcr = 0x00000400; 460 } 461 462 static void npcm7xx_timer_hold_reset(Object *obj) 463 { 464 NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj); 465 int i; 466 467 for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) { 468 qemu_irq_lower(s->timer[i].irq); 469 } 470 } 471 472 static void npcm7xx_timer_realize(DeviceState *dev, Error **errp) 473 { 474 NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(dev); 475 SysBusDevice *sbd = &s->parent; 476 int i; 477 478 for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) { 479 NPCM7xxTimer *t = &s->timer[i]; 480 t->ctrl = s; 481 timer_init_ns(&t->qtimer, QEMU_CLOCK_VIRTUAL, npcm7xx_timer_expired, t); 482 sysbus_init_irq(sbd, &t->irq); 483 } 484 485 memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_timer_ops, s, 486 TYPE_NPCM7XX_TIMER, 4 * KiB); 487 sysbus_init_mmio(sbd, &s->iomem); 488 } 489 490 static const VMStateDescription vmstate_npcm7xx_timer = { 491 .name = "npcm7xx-timer", 492 .version_id = 0, 493 .minimum_version_id = 0, 494 .fields = (VMStateField[]) { 495 VMSTATE_TIMER(qtimer, NPCM7xxTimer), 496 VMSTATE_INT64(expires_ns, NPCM7xxTimer), 497 VMSTATE_INT64(remaining_ns, NPCM7xxTimer), 498 VMSTATE_UINT32(tcsr, NPCM7xxTimer), 499 VMSTATE_UINT32(ticr, NPCM7xxTimer), 500 VMSTATE_END_OF_LIST(), 501 }, 502 }; 503 504 static const VMStateDescription vmstate_npcm7xx_timer_ctrl = { 505 .name = "npcm7xx-timer-ctrl", 506 .version_id = 0, 507 .minimum_version_id = 0, 508 .fields = (VMStateField[]) { 509 VMSTATE_UINT32(tisr, NPCM7xxTimerCtrlState), 510 VMSTATE_UINT32(wtcr, NPCM7xxTimerCtrlState), 511 VMSTATE_STRUCT_ARRAY(timer, NPCM7xxTimerCtrlState, 512 NPCM7XX_TIMERS_PER_CTRL, 0, vmstate_npcm7xx_timer, 513 NPCM7xxTimer), 514 VMSTATE_END_OF_LIST(), 515 }, 516 }; 517 518 static void npcm7xx_timer_class_init(ObjectClass *klass, void *data) 519 { 520 ResettableClass *rc = RESETTABLE_CLASS(klass); 521 DeviceClass *dc = DEVICE_CLASS(klass); 522 523 QEMU_BUILD_BUG_ON(NPCM7XX_TIMER_REGS_END > NPCM7XX_TIMER_NR_REGS); 524 525 dc->desc = "NPCM7xx Timer Controller"; 526 dc->realize = npcm7xx_timer_realize; 527 dc->vmsd = &vmstate_npcm7xx_timer_ctrl; 528 rc->phases.enter = npcm7xx_timer_enter_reset; 529 rc->phases.hold = npcm7xx_timer_hold_reset; 530 } 531 532 static const TypeInfo npcm7xx_timer_info = { 533 .name = TYPE_NPCM7XX_TIMER, 534 .parent = TYPE_SYS_BUS_DEVICE, 535 .instance_size = sizeof(NPCM7xxTimerCtrlState), 536 .class_init = npcm7xx_timer_class_init, 537 }; 538 539 static void npcm7xx_timer_register_type(void) 540 { 541 type_register_static(&npcm7xx_timer_info); 542 } 543 type_init(npcm7xx_timer_register_type); 544