renesas_tmr.c (14238B)
1/* 2 * Renesas 8bit timer 3 * 4 * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware 5 * (Rev.1.40 R01UH0033EJ0140) 6 * 7 * Copyright (c) 2019 Yoshinori Sato 8 * 9 * SPDX-License-Identifier: GPL-2.0-or-later 10 * 11 * This program is free software; you can redistribute it and/or modify it 12 * under the terms and conditions of the GNU General Public License, 13 * version 2 or later, as published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope it will be useful, but WITHOUT 16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 18 * more details. 19 * 20 * You should have received a copy of the GNU General Public License along with 21 * this program. If not, see <http://www.gnu.org/licenses/>. 22 */ 23 24#include "qemu/osdep.h" 25#include "qemu/log.h" 26#include "hw/irq.h" 27#include "hw/registerfields.h" 28#include "hw/qdev-properties.h" 29#include "hw/timer/renesas_tmr.h" 30#include "migration/vmstate.h" 31 32REG8(TCR, 0) 33 FIELD(TCR, CCLR, 3, 2) 34 FIELD(TCR, OVIE, 5, 1) 35 FIELD(TCR, CMIEA, 6, 1) 36 FIELD(TCR, CMIEB, 7, 1) 37REG8(TCSR, 2) 38 FIELD(TCSR, OSA, 0, 2) 39 FIELD(TCSR, OSB, 2, 2) 40 FIELD(TCSR, ADTE, 4, 2) 41REG8(TCORA, 4) 42REG8(TCORB, 6) 43REG8(TCNT, 8) 44REG8(TCCR, 10) 45 FIELD(TCCR, CKS, 0, 3) 46 FIELD(TCCR, CSS, 3, 2) 47 FIELD(TCCR, TMRIS, 7, 1) 48 49#define CSS_EXTERNAL 0x00 50#define CSS_INTERNAL 0x01 51#define CSS_INVALID 0x02 52#define CSS_CASCADING 0x03 53#define CCLR_A 0x01 54#define CCLR_B 0x02 55 56static const int clkdiv[] = {0, 1, 2, 8, 32, 64, 1024, 8192}; 57 58static uint8_t concat_reg(uint8_t *reg) 59{ 60 return (reg[0] << 8) | reg[1]; 61} 62 63static void update_events(RTMRState *tmr, int ch) 64{ 65 uint16_t diff[TMR_NR_EVENTS], min; 66 int64_t next_time; 67 int i, event; 68 69 if (tmr->tccr[ch] == 0) { 70 return ; 71 } 72 if (FIELD_EX8(tmr->tccr[ch], TCCR, CSS) == 0) { 73 /* external clock mode */ 74 /* event not happened */ 75 return ; 76 } 77 if (FIELD_EX8(tmr->tccr[0], TCCR, CSS) == CSS_CASCADING) { 78 /* cascading mode */ 79 if (ch == 1) { 80 tmr->next[ch] = none; 81 return ; 82 } 83 diff[cmia] = concat_reg(tmr->tcora) - concat_reg(tmr->tcnt); 84 diff[cmib] = concat_reg(tmr->tcorb) - concat_reg(tmr->tcnt); 85 diff[ovi] = 0x10000 - concat_reg(tmr->tcnt); 86 } else { 87 /* separate mode */ 88 diff[cmia] = tmr->tcora[ch] - tmr->tcnt[ch]; 89 diff[cmib] = tmr->tcorb[ch] - tmr->tcnt[ch]; 90 diff[ovi] = 0x100 - tmr->tcnt[ch]; 91 } 92 /* Search for the most recently occurring event. */ 93 for (event = 0, min = diff[0], i = 1; i < none; i++) { 94 if (min > diff[i]) { 95 event = i; 96 min = diff[i]; 97 } 98 } 99 tmr->next[ch] = event; 100 next_time = diff[event]; 101 next_time *= clkdiv[FIELD_EX8(tmr->tccr[ch], TCCR, CKS)]; 102 next_time *= NANOSECONDS_PER_SECOND; 103 next_time /= tmr->input_freq; 104 next_time += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 105 timer_mod(&tmr->timer[ch], next_time); 106} 107 108static int elapsed_time(RTMRState *tmr, int ch, int64_t delta) 109{ 110 int divrate = clkdiv[FIELD_EX8(tmr->tccr[ch], TCCR, CKS)]; 111 int et; 112 113 tmr->div_round[ch] += delta; 114 if (divrate > 0) { 115 et = tmr->div_round[ch] / divrate; 116 tmr->div_round[ch] %= divrate; 117 } else { 118 /* disble clock. so no update */ 119 et = 0; 120 } 121 return et; 122} 123 124static uint16_t read_tcnt(RTMRState *tmr, unsigned size, int ch) 125{ 126 int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 127 int elapsed, ovf = 0; 128 uint16_t tcnt[2]; 129 uint32_t ret; 130 131 delta = (now - tmr->tick) * NANOSECONDS_PER_SECOND / tmr->input_freq; 132 if (delta > 0) { 133 tmr->tick = now; 134 135 switch (FIELD_EX8(tmr->tccr[1], TCCR, CSS)) { 136 case CSS_INTERNAL: 137 /* timer1 count update */ 138 elapsed = elapsed_time(tmr, 1, delta); 139 if (elapsed >= 0x100) { 140 ovf = elapsed >> 8; 141 } 142 tcnt[1] = tmr->tcnt[1] + (elapsed & 0xff); 143 break; 144 case CSS_INVALID: /* guest error to have set this */ 145 case CSS_EXTERNAL: /* QEMU doesn't implement these */ 146 case CSS_CASCADING: 147 tcnt[1] = tmr->tcnt[1]; 148 break; 149 default: 150 g_assert_not_reached(); 151 } 152 switch (FIELD_EX8(tmr->tccr[0], TCCR, CSS)) { 153 case CSS_INTERNAL: 154 elapsed = elapsed_time(tmr, 0, delta); 155 tcnt[0] = tmr->tcnt[0] + elapsed; 156 break; 157 case CSS_CASCADING: 158 tcnt[0] = tmr->tcnt[0] + ovf; 159 break; 160 case CSS_INVALID: /* guest error to have set this */ 161 case CSS_EXTERNAL: /* QEMU doesn't implement this */ 162 tcnt[0] = tmr->tcnt[0]; 163 break; 164 default: 165 g_assert_not_reached(); 166 } 167 } else { 168 tcnt[0] = tmr->tcnt[0]; 169 tcnt[1] = tmr->tcnt[1]; 170 } 171 if (size == 1) { 172 return tcnt[ch]; 173 } else { 174 ret = 0; 175 ret = deposit32(ret, 0, 8, tcnt[1]); 176 ret = deposit32(ret, 8, 8, tcnt[0]); 177 return ret; 178 } 179} 180 181static uint8_t read_tccr(uint8_t r) 182{ 183 uint8_t tccr = 0; 184 tccr = FIELD_DP8(tccr, TCCR, TMRIS, 185 FIELD_EX8(r, TCCR, TMRIS)); 186 tccr = FIELD_DP8(tccr, TCCR, CSS, 187 FIELD_EX8(r, TCCR, CSS)); 188 tccr = FIELD_DP8(tccr, TCCR, CKS, 189 FIELD_EX8(r, TCCR, CKS)); 190 return tccr; 191} 192 193static uint64_t tmr_read(void *opaque, hwaddr addr, unsigned size) 194{ 195 RTMRState *tmr = opaque; 196 int ch = addr & 1; 197 uint64_t ret; 198 199 if (size == 2 && (ch != 0 || addr == A_TCR || addr == A_TCSR)) { 200 qemu_log_mask(LOG_GUEST_ERROR, "renesas_tmr: Invalid read size 0x%" 201 HWADDR_PRIX "\n", 202 addr); 203 return UINT64_MAX; 204 } 205 switch (addr & 0x0e) { 206 case A_TCR: 207 ret = 0; 208 ret = FIELD_DP8(ret, TCR, CCLR, 209 FIELD_EX8(tmr->tcr[ch], TCR, CCLR)); 210 ret = FIELD_DP8(ret, TCR, OVIE, 211 FIELD_EX8(tmr->tcr[ch], TCR, OVIE)); 212 ret = FIELD_DP8(ret, TCR, CMIEA, 213 FIELD_EX8(tmr->tcr[ch], TCR, CMIEA)); 214 ret = FIELD_DP8(ret, TCR, CMIEB, 215 FIELD_EX8(tmr->tcr[ch], TCR, CMIEB)); 216 return ret; 217 case A_TCSR: 218 ret = 0; 219 ret = FIELD_DP8(ret, TCSR, OSA, 220 FIELD_EX8(tmr->tcsr[ch], TCSR, OSA)); 221 ret = FIELD_DP8(ret, TCSR, OSB, 222 FIELD_EX8(tmr->tcsr[ch], TCSR, OSB)); 223 switch (ch) { 224 case 0: 225 ret = FIELD_DP8(ret, TCSR, ADTE, 226 FIELD_EX8(tmr->tcsr[ch], TCSR, ADTE)); 227 break; 228 case 1: /* CH1 ADTE unimplement always 1 */ 229 ret = FIELD_DP8(ret, TCSR, ADTE, 1); 230 break; 231 } 232 return ret; 233 case A_TCORA: 234 if (size == 1) { 235 return tmr->tcora[ch]; 236 } else if (ch == 0) { 237 return concat_reg(tmr->tcora); 238 } 239 /* fall through */ 240 case A_TCORB: 241 if (size == 1) { 242 return tmr->tcorb[ch]; 243 } else { 244 return concat_reg(tmr->tcorb); 245 } 246 case A_TCNT: 247 return read_tcnt(tmr, size, ch); 248 case A_TCCR: 249 if (size == 1) { 250 return read_tccr(tmr->tccr[ch]); 251 } else { 252 return read_tccr(tmr->tccr[0]) << 8 | read_tccr(tmr->tccr[1]); 253 } 254 default: 255 qemu_log_mask(LOG_UNIMP, "renesas_tmr: Register 0x%" HWADDR_PRIX 256 " not implemented\n", 257 addr); 258 break; 259 } 260 return UINT64_MAX; 261} 262 263static void tmr_write_count(RTMRState *tmr, int ch, unsigned size, 264 uint8_t *reg, uint64_t val) 265{ 266 if (size == 1) { 267 reg[ch] = val; 268 update_events(tmr, ch); 269 } else { 270 reg[0] = extract32(val, 8, 8); 271 reg[1] = extract32(val, 0, 8); 272 update_events(tmr, 0); 273 update_events(tmr, 1); 274 } 275} 276 277static void tmr_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) 278{ 279 RTMRState *tmr = opaque; 280 int ch = addr & 1; 281 282 if (size == 2 && (ch != 0 || addr == A_TCR || addr == A_TCSR)) { 283 qemu_log_mask(LOG_GUEST_ERROR, 284 "renesas_tmr: Invalid write size 0x%" HWADDR_PRIX "\n", 285 addr); 286 return; 287 } 288 switch (addr & 0x0e) { 289 case A_TCR: 290 tmr->tcr[ch] = val; 291 break; 292 case A_TCSR: 293 tmr->tcsr[ch] = val; 294 break; 295 case A_TCORA: 296 tmr_write_count(tmr, ch, size, tmr->tcora, val); 297 break; 298 case A_TCORB: 299 tmr_write_count(tmr, ch, size, tmr->tcorb, val); 300 break; 301 case A_TCNT: 302 tmr_write_count(tmr, ch, size, tmr->tcnt, val); 303 break; 304 case A_TCCR: 305 tmr_write_count(tmr, ch, size, tmr->tccr, val); 306 break; 307 default: 308 qemu_log_mask(LOG_UNIMP, "renesas_tmr: Register 0x%" HWADDR_PRIX 309 " not implemented\n", 310 addr); 311 break; 312 } 313} 314 315static const MemoryRegionOps tmr_ops = { 316 .write = tmr_write, 317 .read = tmr_read, 318 .endianness = DEVICE_LITTLE_ENDIAN, 319 .impl = { 320 .min_access_size = 1, 321 .max_access_size = 2, 322 }, 323 .valid = { 324 .min_access_size = 1, 325 .max_access_size = 2, 326 }, 327}; 328 329static void timer_events(RTMRState *tmr, int ch); 330 331static uint16_t issue_event(RTMRState *tmr, int ch, int sz, 332 uint16_t tcnt, uint16_t tcora, uint16_t tcorb) 333{ 334 uint16_t ret = tcnt; 335 336 switch (tmr->next[ch]) { 337 case none: 338 break; 339 case cmia: 340 if (tcnt >= tcora) { 341 if (FIELD_EX8(tmr->tcr[ch], TCR, CCLR) == CCLR_A) { 342 ret = tcnt - tcora; 343 } 344 if (FIELD_EX8(tmr->tcr[ch], TCR, CMIEA)) { 345 qemu_irq_pulse(tmr->cmia[ch]); 346 } 347 if (sz == 8 && ch == 0 && 348 FIELD_EX8(tmr->tccr[1], TCCR, CSS) == CSS_CASCADING) { 349 tmr->tcnt[1]++; 350 timer_events(tmr, 1); 351 } 352 } 353 break; 354 case cmib: 355 if (tcnt >= tcorb) { 356 if (FIELD_EX8(tmr->tcr[ch], TCR, CCLR) == CCLR_B) { 357 ret = tcnt - tcorb; 358 } 359 if (FIELD_EX8(tmr->tcr[ch], TCR, CMIEB)) { 360 qemu_irq_pulse(tmr->cmib[ch]); 361 } 362 } 363 break; 364 case ovi: 365 if ((tcnt >= (1 << sz)) && FIELD_EX8(tmr->tcr[ch], TCR, OVIE)) { 366 qemu_irq_pulse(tmr->ovi[ch]); 367 } 368 break; 369 default: 370 g_assert_not_reached(); 371 } 372 return ret; 373} 374 375static void timer_events(RTMRState *tmr, int ch) 376{ 377 uint16_t tcnt; 378 379 tmr->tcnt[ch] = read_tcnt(tmr, 1, ch); 380 if (FIELD_EX8(tmr->tccr[0], TCCR, CSS) != CSS_CASCADING) { 381 tmr->tcnt[ch] = issue_event(tmr, ch, 8, 382 tmr->tcnt[ch], 383 tmr->tcora[ch], 384 tmr->tcorb[ch]) & 0xff; 385 } else { 386 if (ch == 1) { 387 return ; 388 } 389 tcnt = issue_event(tmr, ch, 16, 390 concat_reg(tmr->tcnt), 391 concat_reg(tmr->tcora), 392 concat_reg(tmr->tcorb)); 393 tmr->tcnt[0] = (tcnt >> 8) & 0xff; 394 tmr->tcnt[1] = tcnt & 0xff; 395 } 396 update_events(tmr, ch); 397} 398 399static void timer_event0(void *opaque) 400{ 401 RTMRState *tmr = opaque; 402 403 timer_events(tmr, 0); 404} 405 406static void timer_event1(void *opaque) 407{ 408 RTMRState *tmr = opaque; 409 410 timer_events(tmr, 1); 411} 412 413static void rtmr_reset(DeviceState *dev) 414{ 415 RTMRState *tmr = RTMR(dev); 416 tmr->tcr[0] = tmr->tcr[1] = 0x00; 417 tmr->tcsr[0] = 0x00; 418 tmr->tcsr[1] = 0x10; 419 tmr->tcnt[0] = tmr->tcnt[1] = 0x00; 420 tmr->tcora[0] = tmr->tcora[1] = 0xff; 421 tmr->tcorb[0] = tmr->tcorb[1] = 0xff; 422 tmr->tccr[0] = tmr->tccr[1] = 0x00; 423 tmr->next[0] = tmr->next[1] = none; 424 tmr->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 425} 426 427static void rtmr_init(Object *obj) 428{ 429 SysBusDevice *d = SYS_BUS_DEVICE(obj); 430 RTMRState *tmr = RTMR(obj); 431 int i; 432 433 memory_region_init_io(&tmr->memory, OBJECT(tmr), &tmr_ops, 434 tmr, "renesas-tmr", 0x10); 435 sysbus_init_mmio(d, &tmr->memory); 436 437 for (i = 0; i < ARRAY_SIZE(tmr->ovi); i++) { 438 sysbus_init_irq(d, &tmr->cmia[i]); 439 sysbus_init_irq(d, &tmr->cmib[i]); 440 sysbus_init_irq(d, &tmr->ovi[i]); 441 } 442 timer_init_ns(&tmr->timer[0], QEMU_CLOCK_VIRTUAL, timer_event0, tmr); 443 timer_init_ns(&tmr->timer[1], QEMU_CLOCK_VIRTUAL, timer_event1, tmr); 444} 445 446static const VMStateDescription vmstate_rtmr = { 447 .name = "rx-tmr", 448 .version_id = 1, 449 .minimum_version_id = 1, 450 .fields = (VMStateField[]) { 451 VMSTATE_INT64(tick, RTMRState), 452 VMSTATE_UINT8_ARRAY(tcnt, RTMRState, TMR_CH), 453 VMSTATE_UINT8_ARRAY(tcora, RTMRState, TMR_CH), 454 VMSTATE_UINT8_ARRAY(tcorb, RTMRState, TMR_CH), 455 VMSTATE_UINT8_ARRAY(tcr, RTMRState, TMR_CH), 456 VMSTATE_UINT8_ARRAY(tccr, RTMRState, TMR_CH), 457 VMSTATE_UINT8_ARRAY(tcor, RTMRState, TMR_CH), 458 VMSTATE_UINT8_ARRAY(tcsr, RTMRState, TMR_CH), 459 VMSTATE_INT64_ARRAY(div_round, RTMRState, TMR_CH), 460 VMSTATE_UINT8_ARRAY(next, RTMRState, TMR_CH), 461 VMSTATE_TIMER_ARRAY(timer, RTMRState, TMR_CH), 462 VMSTATE_END_OF_LIST() 463 } 464}; 465 466static Property rtmr_properties[] = { 467 DEFINE_PROP_UINT64("input-freq", RTMRState, input_freq, 0), 468 DEFINE_PROP_END_OF_LIST(), 469}; 470 471static void rtmr_class_init(ObjectClass *klass, void *data) 472{ 473 DeviceClass *dc = DEVICE_CLASS(klass); 474 475 dc->vmsd = &vmstate_rtmr; 476 dc->reset = rtmr_reset; 477 device_class_set_props(dc, rtmr_properties); 478} 479 480static const TypeInfo rtmr_info = { 481 .name = TYPE_RENESAS_TMR, 482 .parent = TYPE_SYS_BUS_DEVICE, 483 .instance_size = sizeof(RTMRState), 484 .instance_init = rtmr_init, 485 .class_init = rtmr_class_init, 486}; 487 488static void rtmr_register_types(void) 489{ 490 type_register_static(&rtmr_info); 491} 492 493type_init(rtmr_register_types)