qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

renesas_tmr.c (14234B)


      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 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 
     56 static const int clkdiv[] = {0, 1, 2, 8, 32, 64, 1024, 8192};
     57 
     58 static uint8_t concat_reg(uint8_t *reg)
     59 {
     60     return (reg[0] << 8) | reg[1];
     61 }
     62 
     63 static 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 
    108 static 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 
    124 static 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 
    181 static 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 
    193 static 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 
    263 static 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 
    277 static 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 
    315 static 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 
    329 static void timer_events(RTMRState *tmr, int ch);
    330 
    331 static 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 
    375 static 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 
    399 static void timer_event0(void *opaque)
    400 {
    401     RTMRState *tmr = opaque;
    402 
    403     timer_events(tmr, 0);
    404 }
    405 
    406 static void timer_event1(void *opaque)
    407 {
    408     RTMRState *tmr = opaque;
    409 
    410     timer_events(tmr, 1);
    411 }
    412 
    413 static 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 
    427 static 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 
    446 static 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 
    466 static Property rtmr_properties[] = {
    467     DEFINE_PROP_UINT64("input-freq", RTMRState, input_freq, 0),
    468     DEFINE_PROP_END_OF_LIST(),
    469 };
    470 
    471 static 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 
    480 static 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 
    488 static void rtmr_register_types(void)
    489 {
    490     type_register_static(&rtmr_info);
    491 }
    492 
    493 type_init(rtmr_register_types)