qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

hw/timer: RX62N 8-Bit timer (TMR)

renesas_tmr: 8bit timer modules.
This part use many renesas's CPU.
Hardware manual.
https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01uh0033ej0140_rx62n.pdf

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20200224141923.82118-16-ysato@users.sourceforge.jp>
[PMD: Split from CMT, filled VMStateField for migration]
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

authored by

Yoshinori Sato and committed by
Philippe Mathieu-Daudé
7adca78e e78597cc

+538
+2
MAINTAINERS
··· 1972 1972 R: Magnus Damm <magnus.damm@gmail.com> 1973 1973 S: Maintained 1974 1974 F: hw/char/sh_serial.c 1975 + F: hw/timer/renesas_tmr.c 1975 1976 F: hw/timer/sh_timer.c 1976 1977 F: include/hw/sh4/sh.h 1978 + F: include/hw/timer/renesas_tmr.h 1977 1979 1978 1980 Renesas RX peripherals 1979 1981 M: Yoshinori Sato <ysato@users.sourceforge.jp>
+3
hw/timer/Kconfig
··· 35 35 config CMSDK_APB_DUALTIMER 36 36 bool 37 37 select PTIMER 38 + 39 + config RENESAS_TMR 40 + bool
+1
hw/timer/Makefile.objs
··· 23 23 common-obj-$(CONFIG_OMAP) += omap_synctimer.o 24 24 common-obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o 25 25 common-obj-$(CONFIG_SH4) += sh_timer.o 26 + common-obj-$(CONFIG_RENESAS_TMR) += renesas_tmr.o 26 27 common-obj-$(CONFIG_DIGIC) += digic-timer.o 27 28 common-obj-$(CONFIG_MIPS_CPS) += mips_gictimer.o 28 29
+477
hw/timer/renesas_tmr.c
··· 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 + 32 + REG8(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) 37 + REG8(TCSR, 2) 38 + FIELD(TCSR, OSA, 0, 2) 39 + FIELD(TCSR, OSB, 2, 2) 40 + FIELD(TCSR, ADTE, 4, 2) 41 + REG8(TCORA, 4) 42 + REG8(TCORB, 6) 43 + REG8(TCNT, 8) 44 + REG8(TCCR, 10) 45 + FIELD(TCCR, CKS, 0, 3) 46 + FIELD(TCCR, CSS, 3, 2) 47 + FIELD(TCCR, TMRIS, 7, 1) 48 + 49 + #define INTERNAL 0x01 50 + #define CASCADING 0x03 51 + #define CCLR_A 0x01 52 + #define CCLR_B 0x02 53 + 54 + static const int clkdiv[] = {0, 1, 2, 8, 32, 64, 1024, 8192}; 55 + 56 + static uint8_t concat_reg(uint8_t *reg) 57 + { 58 + return (reg[0] << 8) | reg[1]; 59 + } 60 + 61 + static void update_events(RTMRState *tmr, int ch) 62 + { 63 + uint16_t diff[TMR_NR_EVENTS], min; 64 + int64_t next_time; 65 + int i, event; 66 + 67 + if (tmr->tccr[ch] == 0) { 68 + return ; 69 + } 70 + if (FIELD_EX8(tmr->tccr[ch], TCCR, CSS) == 0) { 71 + /* external clock mode */ 72 + /* event not happened */ 73 + return ; 74 + } 75 + if (FIELD_EX8(tmr->tccr[0], TCCR, CSS) == CASCADING) { 76 + /* cascading mode */ 77 + if (ch == 1) { 78 + tmr->next[ch] = none; 79 + return ; 80 + } 81 + diff[cmia] = concat_reg(tmr->tcora) - concat_reg(tmr->tcnt); 82 + diff[cmib] = concat_reg(tmr->tcorb) - concat_reg(tmr->tcnt); 83 + diff[ovi] = 0x10000 - concat_reg(tmr->tcnt); 84 + } else { 85 + /* separate mode */ 86 + diff[cmia] = tmr->tcora[ch] - tmr->tcnt[ch]; 87 + diff[cmib] = tmr->tcorb[ch] - tmr->tcnt[ch]; 88 + diff[ovi] = 0x100 - tmr->tcnt[ch]; 89 + } 90 + /* Search for the most recently occurring event. */ 91 + for (event = 0, min = diff[0], i = 1; i < none; i++) { 92 + if (min > diff[i]) { 93 + event = i; 94 + min = diff[i]; 95 + } 96 + } 97 + tmr->next[ch] = event; 98 + next_time = diff[event]; 99 + next_time *= clkdiv[FIELD_EX8(tmr->tccr[ch], TCCR, CKS)]; 100 + next_time *= NANOSECONDS_PER_SECOND; 101 + next_time /= tmr->input_freq; 102 + next_time += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 103 + timer_mod(&tmr->timer[ch], next_time); 104 + } 105 + 106 + static int elapsed_time(RTMRState *tmr, int ch, int64_t delta) 107 + { 108 + int divrate = clkdiv[FIELD_EX8(tmr->tccr[ch], TCCR, CKS)]; 109 + int et; 110 + 111 + tmr->div_round[ch] += delta; 112 + if (divrate > 0) { 113 + et = tmr->div_round[ch] / divrate; 114 + tmr->div_round[ch] %= divrate; 115 + } else { 116 + /* disble clock. so no update */ 117 + et = 0; 118 + } 119 + return et; 120 + } 121 + 122 + static uint16_t read_tcnt(RTMRState *tmr, unsigned size, int ch) 123 + { 124 + int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 125 + int elapsed, ovf = 0; 126 + uint16_t tcnt[2]; 127 + uint32_t ret; 128 + 129 + delta = (now - tmr->tick) * NANOSECONDS_PER_SECOND / tmr->input_freq; 130 + if (delta > 0) { 131 + tmr->tick = now; 132 + 133 + if (FIELD_EX8(tmr->tccr[1], TCCR, CSS) == INTERNAL) { 134 + /* timer1 count update */ 135 + elapsed = elapsed_time(tmr, 1, delta); 136 + if (elapsed >= 0x100) { 137 + ovf = elapsed >> 8; 138 + } 139 + tcnt[1] = tmr->tcnt[1] + (elapsed & 0xff); 140 + } 141 + switch (FIELD_EX8(tmr->tccr[0], TCCR, CSS)) { 142 + case INTERNAL: 143 + elapsed = elapsed_time(tmr, 0, delta); 144 + tcnt[0] = tmr->tcnt[0] + elapsed; 145 + break; 146 + case CASCADING: 147 + if (ovf > 0) { 148 + tcnt[0] = tmr->tcnt[0] + ovf; 149 + } 150 + break; 151 + } 152 + } else { 153 + tcnt[0] = tmr->tcnt[0]; 154 + tcnt[1] = tmr->tcnt[1]; 155 + } 156 + if (size == 1) { 157 + return tcnt[ch]; 158 + } else { 159 + ret = 0; 160 + ret = deposit32(ret, 0, 8, tcnt[1]); 161 + ret = deposit32(ret, 8, 8, tcnt[0]); 162 + return ret; 163 + } 164 + } 165 + 166 + static uint8_t read_tccr(uint8_t r) 167 + { 168 + uint8_t tccr = 0; 169 + tccr = FIELD_DP8(tccr, TCCR, TMRIS, 170 + FIELD_EX8(r, TCCR, TMRIS)); 171 + tccr = FIELD_DP8(tccr, TCCR, CSS, 172 + FIELD_EX8(r, TCCR, CSS)); 173 + tccr = FIELD_DP8(tccr, TCCR, CKS, 174 + FIELD_EX8(r, TCCR, CKS)); 175 + return tccr; 176 + } 177 + 178 + static uint64_t tmr_read(void *opaque, hwaddr addr, unsigned size) 179 + { 180 + RTMRState *tmr = opaque; 181 + int ch = addr & 1; 182 + uint64_t ret; 183 + 184 + if (size == 2 && (ch != 0 || addr == A_TCR || addr == A_TCSR)) { 185 + qemu_log_mask(LOG_GUEST_ERROR, "renesas_tmr: Invalid read size 0x%" 186 + HWADDR_PRIX "\n", 187 + addr); 188 + return UINT64_MAX; 189 + } 190 + switch (addr & 0x0e) { 191 + case A_TCR: 192 + ret = 0; 193 + ret = FIELD_DP8(ret, TCR, CCLR, 194 + FIELD_EX8(tmr->tcr[ch], TCR, CCLR)); 195 + ret = FIELD_DP8(ret, TCR, OVIE, 196 + FIELD_EX8(tmr->tcr[ch], TCR, OVIE)); 197 + ret = FIELD_DP8(ret, TCR, CMIEA, 198 + FIELD_EX8(tmr->tcr[ch], TCR, CMIEA)); 199 + ret = FIELD_DP8(ret, TCR, CMIEB, 200 + FIELD_EX8(tmr->tcr[ch], TCR, CMIEB)); 201 + return ret; 202 + case A_TCSR: 203 + ret = 0; 204 + ret = FIELD_DP8(ret, TCSR, OSA, 205 + FIELD_EX8(tmr->tcsr[ch], TCSR, OSA)); 206 + ret = FIELD_DP8(ret, TCSR, OSB, 207 + FIELD_EX8(tmr->tcsr[ch], TCSR, OSB)); 208 + switch (ch) { 209 + case 0: 210 + ret = FIELD_DP8(ret, TCSR, ADTE, 211 + FIELD_EX8(tmr->tcsr[ch], TCSR, ADTE)); 212 + break; 213 + case 1: /* CH1 ADTE unimplement always 1 */ 214 + ret = FIELD_DP8(ret, TCSR, ADTE, 1); 215 + break; 216 + } 217 + return ret; 218 + case A_TCORA: 219 + if (size == 1) { 220 + return tmr->tcora[ch]; 221 + } else if (ch == 0) { 222 + return concat_reg(tmr->tcora); 223 + } 224 + case A_TCORB: 225 + if (size == 1) { 226 + return tmr->tcorb[ch]; 227 + } else { 228 + return concat_reg(tmr->tcorb); 229 + } 230 + case A_TCNT: 231 + return read_tcnt(tmr, size, ch); 232 + case A_TCCR: 233 + if (size == 1) { 234 + return read_tccr(tmr->tccr[ch]); 235 + } else { 236 + return read_tccr(tmr->tccr[0]) << 8 | read_tccr(tmr->tccr[1]); 237 + } 238 + default: 239 + qemu_log_mask(LOG_UNIMP, "renesas_tmr: Register 0x%" HWADDR_PRIX 240 + " not implemented\n", 241 + addr); 242 + break; 243 + } 244 + return UINT64_MAX; 245 + } 246 + 247 + static void tmr_write_count(RTMRState *tmr, int ch, unsigned size, 248 + uint8_t *reg, uint64_t val) 249 + { 250 + if (size == 1) { 251 + reg[ch] = val; 252 + update_events(tmr, ch); 253 + } else { 254 + reg[0] = extract32(val, 8, 8); 255 + reg[1] = extract32(val, 0, 8); 256 + update_events(tmr, 0); 257 + update_events(tmr, 1); 258 + } 259 + } 260 + 261 + static void tmr_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) 262 + { 263 + RTMRState *tmr = opaque; 264 + int ch = addr & 1; 265 + 266 + if (size == 2 && (ch != 0 || addr == A_TCR || addr == A_TCSR)) { 267 + qemu_log_mask(LOG_GUEST_ERROR, 268 + "renesas_tmr: Invalid write size 0x%" HWADDR_PRIX "\n", 269 + addr); 270 + return; 271 + } 272 + switch (addr & 0x0e) { 273 + case A_TCR: 274 + tmr->tcr[ch] = val; 275 + break; 276 + case A_TCSR: 277 + tmr->tcsr[ch] = val; 278 + break; 279 + case A_TCORA: 280 + tmr_write_count(tmr, ch, size, tmr->tcora, val); 281 + break; 282 + case A_TCORB: 283 + tmr_write_count(tmr, ch, size, tmr->tcorb, val); 284 + break; 285 + case A_TCNT: 286 + tmr_write_count(tmr, ch, size, tmr->tcnt, val); 287 + break; 288 + case A_TCCR: 289 + tmr_write_count(tmr, ch, size, tmr->tccr, val); 290 + break; 291 + default: 292 + qemu_log_mask(LOG_UNIMP, "renesas_tmr: Register 0x%" HWADDR_PRIX 293 + " not implemented\n", 294 + addr); 295 + break; 296 + } 297 + } 298 + 299 + static const MemoryRegionOps tmr_ops = { 300 + .write = tmr_write, 301 + .read = tmr_read, 302 + .endianness = DEVICE_LITTLE_ENDIAN, 303 + .impl = { 304 + .min_access_size = 1, 305 + .max_access_size = 2, 306 + }, 307 + .valid = { 308 + .min_access_size = 1, 309 + .max_access_size = 2, 310 + }, 311 + }; 312 + 313 + static void timer_events(RTMRState *tmr, int ch); 314 + 315 + static uint16_t issue_event(RTMRState *tmr, int ch, int sz, 316 + uint16_t tcnt, uint16_t tcora, uint16_t tcorb) 317 + { 318 + uint16_t ret = tcnt; 319 + 320 + switch (tmr->next[ch]) { 321 + case none: 322 + break; 323 + case cmia: 324 + if (tcnt >= tcora) { 325 + if (FIELD_EX8(tmr->tcr[ch], TCR, CCLR) == CCLR_A) { 326 + ret = tcnt - tcora; 327 + } 328 + if (FIELD_EX8(tmr->tcr[ch], TCR, CMIEA)) { 329 + qemu_irq_pulse(tmr->cmia[ch]); 330 + } 331 + if (sz == 8 && ch == 0 && 332 + FIELD_EX8(tmr->tccr[1], TCCR, CSS) == CASCADING) { 333 + tmr->tcnt[1]++; 334 + timer_events(tmr, 1); 335 + } 336 + } 337 + break; 338 + case cmib: 339 + if (tcnt >= tcorb) { 340 + if (FIELD_EX8(tmr->tcr[ch], TCR, CCLR) == CCLR_B) { 341 + ret = tcnt - tcorb; 342 + } 343 + if (FIELD_EX8(tmr->tcr[ch], TCR, CMIEB)) { 344 + qemu_irq_pulse(tmr->cmib[ch]); 345 + } 346 + } 347 + break; 348 + case ovi: 349 + if ((tcnt >= (1 << sz)) && FIELD_EX8(tmr->tcr[ch], TCR, OVIE)) { 350 + qemu_irq_pulse(tmr->ovi[ch]); 351 + } 352 + break; 353 + default: 354 + g_assert_not_reached(); 355 + } 356 + return ret; 357 + } 358 + 359 + static void timer_events(RTMRState *tmr, int ch) 360 + { 361 + uint16_t tcnt; 362 + 363 + tmr->tcnt[ch] = read_tcnt(tmr, 1, ch); 364 + if (FIELD_EX8(tmr->tccr[0], TCCR, CSS) != CASCADING) { 365 + tmr->tcnt[ch] = issue_event(tmr, ch, 8, 366 + tmr->tcnt[ch], 367 + tmr->tcora[ch], 368 + tmr->tcorb[ch]) & 0xff; 369 + } else { 370 + if (ch == 1) { 371 + return ; 372 + } 373 + tcnt = issue_event(tmr, ch, 16, 374 + concat_reg(tmr->tcnt), 375 + concat_reg(tmr->tcora), 376 + concat_reg(tmr->tcorb)); 377 + tmr->tcnt[0] = (tcnt >> 8) & 0xff; 378 + tmr->tcnt[1] = tcnt & 0xff; 379 + } 380 + update_events(tmr, ch); 381 + } 382 + 383 + static void timer_event0(void *opaque) 384 + { 385 + RTMRState *tmr = opaque; 386 + 387 + timer_events(tmr, 0); 388 + } 389 + 390 + static void timer_event1(void *opaque) 391 + { 392 + RTMRState *tmr = opaque; 393 + 394 + timer_events(tmr, 1); 395 + } 396 + 397 + static void rtmr_reset(DeviceState *dev) 398 + { 399 + RTMRState *tmr = RTMR(dev); 400 + tmr->tcr[0] = tmr->tcr[1] = 0x00; 401 + tmr->tcsr[0] = 0x00; 402 + tmr->tcsr[1] = 0x10; 403 + tmr->tcnt[0] = tmr->tcnt[1] = 0x00; 404 + tmr->tcora[0] = tmr->tcora[1] = 0xff; 405 + tmr->tcorb[0] = tmr->tcorb[1] = 0xff; 406 + tmr->tccr[0] = tmr->tccr[1] = 0x00; 407 + tmr->next[0] = tmr->next[1] = none; 408 + tmr->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 409 + } 410 + 411 + static void rtmr_init(Object *obj) 412 + { 413 + SysBusDevice *d = SYS_BUS_DEVICE(obj); 414 + RTMRState *tmr = RTMR(obj); 415 + int i; 416 + 417 + memory_region_init_io(&tmr->memory, OBJECT(tmr), &tmr_ops, 418 + tmr, "renesas-tmr", 0x10); 419 + sysbus_init_mmio(d, &tmr->memory); 420 + 421 + for (i = 0; i < ARRAY_SIZE(tmr->ovi); i++) { 422 + sysbus_init_irq(d, &tmr->cmia[i]); 423 + sysbus_init_irq(d, &tmr->cmib[i]); 424 + sysbus_init_irq(d, &tmr->ovi[i]); 425 + } 426 + timer_init_ns(&tmr->timer[0], QEMU_CLOCK_VIRTUAL, timer_event0, tmr); 427 + timer_init_ns(&tmr->timer[1], QEMU_CLOCK_VIRTUAL, timer_event1, tmr); 428 + } 429 + 430 + static const VMStateDescription vmstate_rtmr = { 431 + .name = "rx-tmr", 432 + .version_id = 1, 433 + .minimum_version_id = 1, 434 + .fields = (VMStateField[]) { 435 + VMSTATE_INT64(tick, RTMRState), 436 + VMSTATE_UINT8_ARRAY(tcnt, RTMRState, TMR_CH), 437 + VMSTATE_UINT8_ARRAY(tcora, RTMRState, TMR_CH), 438 + VMSTATE_UINT8_ARRAY(tcorb, RTMRState, TMR_CH), 439 + VMSTATE_UINT8_ARRAY(tcr, RTMRState, TMR_CH), 440 + VMSTATE_UINT8_ARRAY(tccr, RTMRState, TMR_CH), 441 + VMSTATE_UINT8_ARRAY(tcor, RTMRState, TMR_CH), 442 + VMSTATE_UINT8_ARRAY(tcsr, RTMRState, TMR_CH), 443 + VMSTATE_INT64_ARRAY(div_round, RTMRState, TMR_CH), 444 + VMSTATE_UINT8_ARRAY(next, RTMRState, TMR_CH), 445 + VMSTATE_TIMER_ARRAY(timer, RTMRState, TMR_CH), 446 + VMSTATE_END_OF_LIST() 447 + } 448 + }; 449 + 450 + static Property rtmr_properties[] = { 451 + DEFINE_PROP_UINT64("input-freq", RTMRState, input_freq, 0), 452 + DEFINE_PROP_END_OF_LIST(), 453 + }; 454 + 455 + static void rtmr_class_init(ObjectClass *klass, void *data) 456 + { 457 + DeviceClass *dc = DEVICE_CLASS(klass); 458 + 459 + dc->vmsd = &vmstate_rtmr; 460 + dc->reset = rtmr_reset; 461 + device_class_set_props(dc, rtmr_properties); 462 + } 463 + 464 + static const TypeInfo rtmr_info = { 465 + .name = TYPE_RENESAS_TMR, 466 + .parent = TYPE_SYS_BUS_DEVICE, 467 + .instance_size = sizeof(RTMRState), 468 + .instance_init = rtmr_init, 469 + .class_init = rtmr_class_init, 470 + }; 471 + 472 + static void rtmr_register_types(void) 473 + { 474 + type_register_static(&rtmr_info); 475 + } 476 + 477 + type_init(rtmr_register_types)
+55
include/hw/timer/renesas_tmr.h
··· 1 + /* 2 + * Renesas 8bit timer Object 3 + * 4 + * Copyright (c) 2018 Yoshinori Sato 5 + * 6 + * SPDX-License-Identifier: GPL-2.0-or-later 7 + */ 8 + 9 + #ifndef HW_TIMER_RENESAS_TMR_H 10 + #define HW_TIMER_RENESAS_TMR_H 11 + 12 + #include "qemu/timer.h" 13 + #include "hw/sysbus.h" 14 + 15 + #define TYPE_RENESAS_TMR "renesas-tmr" 16 + #define RTMR(obj) OBJECT_CHECK(RTMRState, (obj), TYPE_RENESAS_TMR) 17 + 18 + enum timer_event { 19 + cmia = 0, 20 + cmib = 1, 21 + ovi = 2, 22 + none = 3, 23 + TMR_NR_EVENTS = 4 24 + }; 25 + 26 + enum { 27 + TMR_CH = 2, 28 + TMR_NR_IRQ = 3 * TMR_CH 29 + }; 30 + 31 + typedef struct RTMRState { 32 + /*< private >*/ 33 + SysBusDevice parent_obj; 34 + /*< public >*/ 35 + 36 + uint64_t input_freq; 37 + MemoryRegion memory; 38 + 39 + int64_t tick; 40 + uint8_t tcnt[TMR_CH]; 41 + uint8_t tcora[TMR_CH]; 42 + uint8_t tcorb[TMR_CH]; 43 + uint8_t tcr[TMR_CH]; 44 + uint8_t tccr[TMR_CH]; 45 + uint8_t tcor[TMR_CH]; 46 + uint8_t tcsr[TMR_CH]; 47 + int64_t div_round[TMR_CH]; 48 + uint8_t next[TMR_CH]; 49 + qemu_irq cmia[TMR_CH]; 50 + qemu_irq cmib[TMR_CH]; 51 + qemu_irq ovi[TMR_CH]; 52 + QEMUTimer timer[TMR_CH]; 53 + } RTMRState; 54 + 55 + #endif