qemu/hw/timer/renesas_tmr.c
<<
>>
Prefs
   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)
 494