1 /* 2 * Nuvoton NPCM7xx PWM Module 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 #include "hw/irq.h" 19 #include "hw/qdev-clock.h" 20 #include "hw/qdev-properties.h" 21 #include "hw/misc/npcm7xx_pwm.h" 22 #include "hw/registerfields.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/units.h" 29 #include "trace.h" 30 31 REG32(NPCM7XX_PWM_PPR, 0x00); 32 REG32(NPCM7XX_PWM_CSR, 0x04); 33 REG32(NPCM7XX_PWM_PCR, 0x08); 34 REG32(NPCM7XX_PWM_CNR0, 0x0c); 35 REG32(NPCM7XX_PWM_CMR0, 0x10); 36 REG32(NPCM7XX_PWM_PDR0, 0x14); 37 REG32(NPCM7XX_PWM_CNR1, 0x18); 38 REG32(NPCM7XX_PWM_CMR1, 0x1c); 39 REG32(NPCM7XX_PWM_PDR1, 0x20); 40 REG32(NPCM7XX_PWM_CNR2, 0x24); 41 REG32(NPCM7XX_PWM_CMR2, 0x28); 42 REG32(NPCM7XX_PWM_PDR2, 0x2c); 43 REG32(NPCM7XX_PWM_CNR3, 0x30); 44 REG32(NPCM7XX_PWM_CMR3, 0x34); 45 REG32(NPCM7XX_PWM_PDR3, 0x38); 46 REG32(NPCM7XX_PWM_PIER, 0x3c); 47 REG32(NPCM7XX_PWM_PIIR, 0x40); 48 REG32(NPCM7XX_PWM_PWDR0, 0x44); 49 REG32(NPCM7XX_PWM_PWDR1, 0x48); 50 REG32(NPCM7XX_PWM_PWDR2, 0x4c); 51 REG32(NPCM7XX_PWM_PWDR3, 0x50); 52 53 /* Register field definitions. */ 54 #define NPCM7XX_PPR(rv, index) extract32((rv), npcm7xx_ppr_base[index], 8) 55 #define NPCM7XX_CSR(rv, index) extract32((rv), npcm7xx_csr_base[index], 3) 56 #define NPCM7XX_CH(rv, index) extract32((rv), npcm7xx_ch_base[index], 4) 57 #define NPCM7XX_CH_EN BIT(0) 58 #define NPCM7XX_CH_INV BIT(2) 59 #define NPCM7XX_CH_MOD BIT(3) 60 61 #define NPCM7XX_MAX_CMR 65535 62 #define NPCM7XX_MAX_CNR 65535 63 64 /* Offset of each PWM channel's prescaler in the PPR register. */ 65 static const int npcm7xx_ppr_base[] = { 0, 0, 8, 8 }; 66 /* Offset of each PWM channel's clock selector in the CSR register. */ 67 static const int npcm7xx_csr_base[] = { 0, 4, 8, 12 }; 68 /* Offset of each PWM channel's control variable in the PCR register. */ 69 static const int npcm7xx_ch_base[] = { 0, 8, 12, 16 }; 70 71 static uint32_t npcm7xx_pwm_calculate_freq(NPCM7xxPWM *p) 72 { 73 uint32_t ppr; 74 uint32_t csr; 75 uint32_t freq; 76 77 if (!p->running) { 78 return 0; 79 } 80 81 csr = NPCM7XX_CSR(p->module->csr, p->index); 82 ppr = NPCM7XX_PPR(p->module->ppr, p->index); 83 freq = clock_get_hz(p->module->clock); 84 freq /= ppr + 1; 85 /* csr can only be 0~4 */ 86 if (csr > 4) { 87 qemu_log_mask(LOG_GUEST_ERROR, 88 "%s: invalid csr value %u\n", 89 __func__, csr); 90 csr = 4; 91 } 92 /* freq won't be changed if csr == 4. */ 93 if (csr < 4) { 94 freq >>= csr + 1; 95 } 96 97 return freq / (p->cnr + 1); 98 } 99 100 static uint32_t npcm7xx_pwm_calculate_duty(NPCM7xxPWM *p) 101 { 102 uint32_t duty; 103 104 if (p->running) { 105 if (p->cnr == 0) { 106 duty = 0; 107 } else if (p->cmr >= p->cnr) { 108 duty = NPCM7XX_PWM_MAX_DUTY; 109 } else { 110 duty = (uint64_t)NPCM7XX_PWM_MAX_DUTY * (p->cmr + 1) / (p->cnr + 1); 111 } 112 } else { 113 duty = 0; 114 } 115 116 if (p->inverted) { 117 duty = NPCM7XX_PWM_MAX_DUTY - duty; 118 } 119 120 return duty; 121 } 122 123 static void npcm7xx_pwm_update_freq(NPCM7xxPWM *p) 124 { 125 uint32_t freq = npcm7xx_pwm_calculate_freq(p); 126 127 if (freq != p->freq) { 128 trace_npcm7xx_pwm_update_freq(DEVICE(p->module)->canonical_path, 129 p->index, p->freq, freq); 130 p->freq = freq; 131 } 132 } 133 134 static void npcm7xx_pwm_update_duty(NPCM7xxPWM *p) 135 { 136 uint32_t duty = npcm7xx_pwm_calculate_duty(p); 137 138 if (duty != p->duty) { 139 trace_npcm7xx_pwm_update_duty(DEVICE(p->module)->canonical_path, 140 p->index, p->duty, duty); 141 p->duty = duty; 142 qemu_set_irq(p->module->duty_gpio_out[p->index], p->duty); 143 } 144 } 145 146 static void npcm7xx_pwm_update_output(NPCM7xxPWM *p) 147 { 148 npcm7xx_pwm_update_freq(p); 149 npcm7xx_pwm_update_duty(p); 150 } 151 152 static void npcm7xx_pwm_write_ppr(NPCM7xxPWMState *s, uint32_t new_ppr) 153 { 154 int i; 155 uint32_t old_ppr = s->ppr; 156 157 QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_ppr_base) != NPCM7XX_PWM_PER_MODULE); 158 s->ppr = new_ppr; 159 for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) { 160 if (NPCM7XX_PPR(old_ppr, i) != NPCM7XX_PPR(new_ppr, i)) { 161 npcm7xx_pwm_update_freq(&s->pwm[i]); 162 } 163 } 164 } 165 166 static void npcm7xx_pwm_write_csr(NPCM7xxPWMState *s, uint32_t new_csr) 167 { 168 int i; 169 uint32_t old_csr = s->csr; 170 171 QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_csr_base) != NPCM7XX_PWM_PER_MODULE); 172 s->csr = new_csr; 173 for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) { 174 if (NPCM7XX_CSR(old_csr, i) != NPCM7XX_CSR(new_csr, i)) { 175 npcm7xx_pwm_update_freq(&s->pwm[i]); 176 } 177 } 178 } 179 180 static void npcm7xx_pwm_write_pcr(NPCM7xxPWMState *s, uint32_t new_pcr) 181 { 182 int i; 183 bool inverted; 184 uint32_t pcr; 185 NPCM7xxPWM *p; 186 187 s->pcr = new_pcr; 188 QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_ch_base) != NPCM7XX_PWM_PER_MODULE); 189 for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) { 190 p = &s->pwm[i]; 191 pcr = NPCM7XX_CH(new_pcr, i); 192 inverted = pcr & NPCM7XX_CH_INV; 193 194 /* 195 * We only run a PWM channel with toggle mode. Single-shot mode does not 196 * generate frequency and duty-cycle values. 197 */ 198 if ((pcr & NPCM7XX_CH_EN) && (pcr & NPCM7XX_CH_MOD)) { 199 if (p->running) { 200 /* Re-run this PWM channel if inverted changed. */ 201 if (p->inverted ^ inverted) { 202 p->inverted = inverted; 203 npcm7xx_pwm_update_duty(p); 204 } 205 } else { 206 /* Run this PWM channel. */ 207 p->running = true; 208 p->inverted = inverted; 209 npcm7xx_pwm_update_output(p); 210 } 211 } else { 212 /* Clear this PWM channel. */ 213 p->running = false; 214 p->inverted = inverted; 215 npcm7xx_pwm_update_output(p); 216 } 217 } 218 219 } 220 221 static hwaddr npcm7xx_cnr_index(hwaddr offset) 222 { 223 switch (offset) { 224 case A_NPCM7XX_PWM_CNR0: 225 return 0; 226 case A_NPCM7XX_PWM_CNR1: 227 return 1; 228 case A_NPCM7XX_PWM_CNR2: 229 return 2; 230 case A_NPCM7XX_PWM_CNR3: 231 return 3; 232 default: 233 g_assert_not_reached(); 234 } 235 } 236 237 static hwaddr npcm7xx_cmr_index(hwaddr offset) 238 { 239 switch (offset) { 240 case A_NPCM7XX_PWM_CMR0: 241 return 0; 242 case A_NPCM7XX_PWM_CMR1: 243 return 1; 244 case A_NPCM7XX_PWM_CMR2: 245 return 2; 246 case A_NPCM7XX_PWM_CMR3: 247 return 3; 248 default: 249 g_assert_not_reached(); 250 } 251 } 252 253 static hwaddr npcm7xx_pdr_index(hwaddr offset) 254 { 255 switch (offset) { 256 case A_NPCM7XX_PWM_PDR0: 257 return 0; 258 case A_NPCM7XX_PWM_PDR1: 259 return 1; 260 case A_NPCM7XX_PWM_PDR2: 261 return 2; 262 case A_NPCM7XX_PWM_PDR3: 263 return 3; 264 default: 265 g_assert_not_reached(); 266 } 267 } 268 269 static hwaddr npcm7xx_pwdr_index(hwaddr offset) 270 { 271 switch (offset) { 272 case A_NPCM7XX_PWM_PWDR0: 273 return 0; 274 case A_NPCM7XX_PWM_PWDR1: 275 return 1; 276 case A_NPCM7XX_PWM_PWDR2: 277 return 2; 278 case A_NPCM7XX_PWM_PWDR3: 279 return 3; 280 default: 281 g_assert_not_reached(); 282 } 283 } 284 285 static uint64_t npcm7xx_pwm_read(void *opaque, hwaddr offset, unsigned size) 286 { 287 NPCM7xxPWMState *s = opaque; 288 uint64_t value = 0; 289 290 switch (offset) { 291 case A_NPCM7XX_PWM_CNR0: 292 case A_NPCM7XX_PWM_CNR1: 293 case A_NPCM7XX_PWM_CNR2: 294 case A_NPCM7XX_PWM_CNR3: 295 value = s->pwm[npcm7xx_cnr_index(offset)].cnr; 296 break; 297 298 case A_NPCM7XX_PWM_CMR0: 299 case A_NPCM7XX_PWM_CMR1: 300 case A_NPCM7XX_PWM_CMR2: 301 case A_NPCM7XX_PWM_CMR3: 302 value = s->pwm[npcm7xx_cmr_index(offset)].cmr; 303 break; 304 305 case A_NPCM7XX_PWM_PDR0: 306 case A_NPCM7XX_PWM_PDR1: 307 case A_NPCM7XX_PWM_PDR2: 308 case A_NPCM7XX_PWM_PDR3: 309 value = s->pwm[npcm7xx_pdr_index(offset)].pdr; 310 break; 311 312 case A_NPCM7XX_PWM_PWDR0: 313 case A_NPCM7XX_PWM_PWDR1: 314 case A_NPCM7XX_PWM_PWDR2: 315 case A_NPCM7XX_PWM_PWDR3: 316 value = s->pwm[npcm7xx_pwdr_index(offset)].pwdr; 317 break; 318 319 case A_NPCM7XX_PWM_PPR: 320 value = s->ppr; 321 break; 322 323 case A_NPCM7XX_PWM_CSR: 324 value = s->csr; 325 break; 326 327 case A_NPCM7XX_PWM_PCR: 328 value = s->pcr; 329 break; 330 331 case A_NPCM7XX_PWM_PIER: 332 value = s->pier; 333 break; 334 335 case A_NPCM7XX_PWM_PIIR: 336 value = s->piir; 337 break; 338 339 default: 340 qemu_log_mask(LOG_GUEST_ERROR, 341 "%s: invalid offset 0x%04" HWADDR_PRIx "\n", 342 __func__, offset); 343 break; 344 } 345 346 trace_npcm7xx_pwm_read(DEVICE(s)->canonical_path, offset, value); 347 return value; 348 } 349 350 static void npcm7xx_pwm_write(void *opaque, hwaddr offset, 351 uint64_t v, unsigned size) 352 { 353 NPCM7xxPWMState *s = opaque; 354 NPCM7xxPWM *p; 355 uint32_t value = v; 356 357 trace_npcm7xx_pwm_write(DEVICE(s)->canonical_path, offset, value); 358 switch (offset) { 359 case A_NPCM7XX_PWM_CNR0: 360 case A_NPCM7XX_PWM_CNR1: 361 case A_NPCM7XX_PWM_CNR2: 362 case A_NPCM7XX_PWM_CNR3: 363 p = &s->pwm[npcm7xx_cnr_index(offset)]; 364 if (value > NPCM7XX_MAX_CNR) { 365 qemu_log_mask(LOG_GUEST_ERROR, 366 "%s: invalid cnr value: %u", __func__, value); 367 p->cnr = NPCM7XX_MAX_CNR; 368 } else { 369 p->cnr = value; 370 } 371 npcm7xx_pwm_update_output(p); 372 break; 373 374 case A_NPCM7XX_PWM_CMR0: 375 case A_NPCM7XX_PWM_CMR1: 376 case A_NPCM7XX_PWM_CMR2: 377 case A_NPCM7XX_PWM_CMR3: 378 p = &s->pwm[npcm7xx_cmr_index(offset)]; 379 if (value > NPCM7XX_MAX_CMR) { 380 qemu_log_mask(LOG_GUEST_ERROR, 381 "%s: invalid cmr value: %u", __func__, value); 382 p->cmr = NPCM7XX_MAX_CMR; 383 } else { 384 p->cmr = value; 385 } 386 npcm7xx_pwm_update_output(p); 387 break; 388 389 case A_NPCM7XX_PWM_PDR0: 390 case A_NPCM7XX_PWM_PDR1: 391 case A_NPCM7XX_PWM_PDR2: 392 case A_NPCM7XX_PWM_PDR3: 393 qemu_log_mask(LOG_GUEST_ERROR, 394 "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n", 395 __func__, offset); 396 break; 397 398 case A_NPCM7XX_PWM_PWDR0: 399 case A_NPCM7XX_PWM_PWDR1: 400 case A_NPCM7XX_PWM_PWDR2: 401 case A_NPCM7XX_PWM_PWDR3: 402 qemu_log_mask(LOG_UNIMP, 403 "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n", 404 __func__, offset); 405 break; 406 407 case A_NPCM7XX_PWM_PPR: 408 npcm7xx_pwm_write_ppr(s, value); 409 break; 410 411 case A_NPCM7XX_PWM_CSR: 412 npcm7xx_pwm_write_csr(s, value); 413 break; 414 415 case A_NPCM7XX_PWM_PCR: 416 npcm7xx_pwm_write_pcr(s, value); 417 break; 418 419 case A_NPCM7XX_PWM_PIER: 420 qemu_log_mask(LOG_UNIMP, 421 "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n", 422 __func__, offset); 423 break; 424 425 case A_NPCM7XX_PWM_PIIR: 426 qemu_log_mask(LOG_UNIMP, 427 "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n", 428 __func__, offset); 429 break; 430 431 default: 432 qemu_log_mask(LOG_GUEST_ERROR, 433 "%s: invalid offset 0x%04" HWADDR_PRIx "\n", 434 __func__, offset); 435 break; 436 } 437 } 438 439 static const struct MemoryRegionOps npcm7xx_pwm_ops = { 440 .read = npcm7xx_pwm_read, 441 .write = npcm7xx_pwm_write, 442 .endianness = DEVICE_LITTLE_ENDIAN, 443 .valid = { 444 .min_access_size = 4, 445 .max_access_size = 4, 446 .unaligned = false, 447 }, 448 }; 449 450 static void npcm7xx_pwm_enter_reset(Object *obj, ResetType type) 451 { 452 NPCM7xxPWMState *s = NPCM7XX_PWM(obj); 453 int i; 454 455 for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) { 456 NPCM7xxPWM *p = &s->pwm[i]; 457 458 p->cnr = 0x00000000; 459 p->cmr = 0x00000000; 460 p->pdr = 0x00000000; 461 p->pwdr = 0x00000000; 462 } 463 464 s->ppr = 0x00000000; 465 s->csr = 0x00000000; 466 s->pcr = 0x00000000; 467 s->pier = 0x00000000; 468 s->piir = 0x00000000; 469 } 470 471 static void npcm7xx_pwm_hold_reset(Object *obj) 472 { 473 NPCM7xxPWMState *s = NPCM7XX_PWM(obj); 474 int i; 475 476 for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) { 477 qemu_irq_lower(s->pwm[i].irq); 478 } 479 } 480 481 static void npcm7xx_pwm_init(Object *obj) 482 { 483 NPCM7xxPWMState *s = NPCM7XX_PWM(obj); 484 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 485 int i; 486 487 QEMU_BUILD_BUG_ON(ARRAY_SIZE(s->pwm) != NPCM7XX_PWM_PER_MODULE); 488 for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) { 489 NPCM7xxPWM *p = &s->pwm[i]; 490 p->module = s; 491 p->index = i; 492 sysbus_init_irq(sbd, &p->irq); 493 } 494 495 memory_region_init_io(&s->iomem, obj, &npcm7xx_pwm_ops, s, 496 TYPE_NPCM7XX_PWM, 4 * KiB); 497 sysbus_init_mmio(sbd, &s->iomem); 498 s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL, 0); 499 500 for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) { 501 object_property_add_uint32_ptr(obj, "freq[*]", 502 &s->pwm[i].freq, OBJ_PROP_FLAG_READ); 503 object_property_add_uint32_ptr(obj, "duty[*]", 504 &s->pwm[i].duty, OBJ_PROP_FLAG_READ); 505 } 506 qdev_init_gpio_out_named(DEVICE(s), s->duty_gpio_out, 507 "duty-gpio-out", NPCM7XX_PWM_PER_MODULE); 508 } 509 510 static const VMStateDescription vmstate_npcm7xx_pwm = { 511 .name = "npcm7xx-pwm", 512 .version_id = 0, 513 .minimum_version_id = 0, 514 .fields = (const VMStateField[]) { 515 VMSTATE_BOOL(running, NPCM7xxPWM), 516 VMSTATE_BOOL(inverted, NPCM7xxPWM), 517 VMSTATE_UINT8(index, NPCM7xxPWM), 518 VMSTATE_UINT32(cnr, NPCM7xxPWM), 519 VMSTATE_UINT32(cmr, NPCM7xxPWM), 520 VMSTATE_UINT32(pdr, NPCM7xxPWM), 521 VMSTATE_UINT32(pwdr, NPCM7xxPWM), 522 VMSTATE_UINT32(freq, NPCM7xxPWM), 523 VMSTATE_UINT32(duty, NPCM7xxPWM), 524 VMSTATE_END_OF_LIST(), 525 }, 526 }; 527 528 static const VMStateDescription vmstate_npcm7xx_pwm_module = { 529 .name = "npcm7xx-pwm-module", 530 .version_id = 0, 531 .minimum_version_id = 0, 532 .fields = (const VMStateField[]) { 533 VMSTATE_CLOCK(clock, NPCM7xxPWMState), 534 VMSTATE_STRUCT_ARRAY(pwm, NPCM7xxPWMState, 535 NPCM7XX_PWM_PER_MODULE, 0, vmstate_npcm7xx_pwm, 536 NPCM7xxPWM), 537 VMSTATE_UINT32(ppr, NPCM7xxPWMState), 538 VMSTATE_UINT32(csr, NPCM7xxPWMState), 539 VMSTATE_UINT32(pcr, NPCM7xxPWMState), 540 VMSTATE_UINT32(pier, NPCM7xxPWMState), 541 VMSTATE_UINT32(piir, NPCM7xxPWMState), 542 VMSTATE_END_OF_LIST(), 543 }, 544 }; 545 546 static void npcm7xx_pwm_class_init(ObjectClass *klass, void *data) 547 { 548 ResettableClass *rc = RESETTABLE_CLASS(klass); 549 DeviceClass *dc = DEVICE_CLASS(klass); 550 551 dc->desc = "NPCM7xx PWM Controller"; 552 dc->vmsd = &vmstate_npcm7xx_pwm_module; 553 rc->phases.enter = npcm7xx_pwm_enter_reset; 554 rc->phases.hold = npcm7xx_pwm_hold_reset; 555 } 556 557 static const TypeInfo npcm7xx_pwm_info = { 558 .name = TYPE_NPCM7XX_PWM, 559 .parent = TYPE_SYS_BUS_DEVICE, 560 .instance_size = sizeof(NPCM7xxPWMState), 561 .class_init = npcm7xx_pwm_class_init, 562 .instance_init = npcm7xx_pwm_init, 563 }; 564 565 static void npcm7xx_pwm_register_type(void) 566 { 567 type_register_static(&npcm7xx_pwm_info); 568 } 569 type_init(npcm7xx_pwm_register_type); 570