qemu

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

cmsdk-apb-dualtimer.c (17675B)


      1 /*
      2  * ARM CMSDK APB dual-timer emulation
      3  *
      4  * Copyright (c) 2018 Linaro Limited
      5  * Written by Peter Maydell
      6  *
      7  *  This program is free software; you can redistribute it and/or modify
      8  *  it under the terms of the GNU General Public License version 2 or
      9  *  (at your option) any later version.
     10  */
     11 
     12 /*
     13  * This is a model of the "APB dual-input timer" which is part of the Cortex-M
     14  * System Design Kit (CMSDK) and documented in the Cortex-M System
     15  * Design Kit Technical Reference Manual (ARM DDI0479C):
     16  * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
     17  */
     18 
     19 #include "qemu/osdep.h"
     20 #include "qemu/log.h"
     21 #include "trace.h"
     22 #include "qapi/error.h"
     23 #include "qemu/module.h"
     24 #include "hw/sysbus.h"
     25 #include "hw/irq.h"
     26 #include "hw/qdev-properties.h"
     27 #include "hw/registerfields.h"
     28 #include "hw/qdev-clock.h"
     29 #include "hw/timer/cmsdk-apb-dualtimer.h"
     30 #include "migration/vmstate.h"
     31 
     32 REG32(TIMER1LOAD, 0x0)
     33 REG32(TIMER1VALUE, 0x4)
     34 REG32(TIMER1CONTROL, 0x8)
     35     FIELD(CONTROL, ONESHOT, 0, 1)
     36     FIELD(CONTROL, SIZE, 1, 1)
     37     FIELD(CONTROL, PRESCALE, 2, 2)
     38     FIELD(CONTROL, INTEN, 5, 1)
     39     FIELD(CONTROL, MODE, 6, 1)
     40     FIELD(CONTROL, ENABLE, 7, 1)
     41 #define R_CONTROL_VALID_MASK (R_CONTROL_ONESHOT_MASK | R_CONTROL_SIZE_MASK | \
     42                               R_CONTROL_PRESCALE_MASK | R_CONTROL_INTEN_MASK | \
     43                               R_CONTROL_MODE_MASK | R_CONTROL_ENABLE_MASK)
     44 REG32(TIMER1INTCLR, 0xc)
     45 REG32(TIMER1RIS, 0x10)
     46 REG32(TIMER1MIS, 0x14)
     47 REG32(TIMER1BGLOAD, 0x18)
     48 REG32(TIMER2LOAD, 0x20)
     49 REG32(TIMER2VALUE, 0x24)
     50 REG32(TIMER2CONTROL, 0x28)
     51 REG32(TIMER2INTCLR, 0x2c)
     52 REG32(TIMER2RIS, 0x30)
     53 REG32(TIMER2MIS, 0x34)
     54 REG32(TIMER2BGLOAD, 0x38)
     55 REG32(TIMERITCR, 0xf00)
     56     FIELD(TIMERITCR, ENABLE, 0, 1)
     57 #define R_TIMERITCR_VALID_MASK R_TIMERITCR_ENABLE_MASK
     58 REG32(TIMERITOP, 0xf04)
     59     FIELD(TIMERITOP, TIMINT1, 0, 1)
     60     FIELD(TIMERITOP, TIMINT2, 1, 1)
     61 #define R_TIMERITOP_VALID_MASK (R_TIMERITOP_TIMINT1_MASK | \
     62                                 R_TIMERITOP_TIMINT2_MASK)
     63 REG32(PID4, 0xfd0)
     64 REG32(PID5, 0xfd4)
     65 REG32(PID6, 0xfd8)
     66 REG32(PID7, 0xfdc)
     67 REG32(PID0, 0xfe0)
     68 REG32(PID1, 0xfe4)
     69 REG32(PID2, 0xfe8)
     70 REG32(PID3, 0xfec)
     71 REG32(CID0, 0xff0)
     72 REG32(CID1, 0xff4)
     73 REG32(CID2, 0xff8)
     74 REG32(CID3, 0xffc)
     75 
     76 /* PID/CID values */
     77 static const int timer_id[] = {
     78     0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
     79     0x23, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
     80     0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
     81 };
     82 
     83 static bool cmsdk_dualtimermod_intstatus(CMSDKAPBDualTimerModule *m)
     84 {
     85     /* Return masked interrupt status for the timer module */
     86     return m->intstatus && (m->control & R_CONTROL_INTEN_MASK);
     87 }
     88 
     89 static void cmsdk_apb_dualtimer_update(CMSDKAPBDualTimer *s)
     90 {
     91     bool timint1, timint2, timintc;
     92 
     93     if (s->timeritcr) {
     94         /* Integration test mode: outputs driven directly from TIMERITOP bits */
     95         timint1 = s->timeritop & R_TIMERITOP_TIMINT1_MASK;
     96         timint2 = s->timeritop & R_TIMERITOP_TIMINT2_MASK;
     97     } else {
     98         timint1 = cmsdk_dualtimermod_intstatus(&s->timermod[0]);
     99         timint2 = cmsdk_dualtimermod_intstatus(&s->timermod[1]);
    100     }
    101 
    102     timintc = timint1 || timint2;
    103 
    104     qemu_set_irq(s->timermod[0].timerint, timint1);
    105     qemu_set_irq(s->timermod[1].timerint, timint2);
    106     qemu_set_irq(s->timerintc, timintc);
    107 }
    108 
    109 static int cmsdk_dualtimermod_divisor(CMSDKAPBDualTimerModule *m)
    110 {
    111     /* Return the divisor set by the current CONTROL.PRESCALE value */
    112     switch (FIELD_EX32(m->control, CONTROL, PRESCALE)) {
    113     case 0:
    114         return 1;
    115     case 1:
    116         return 16;
    117     case 2:
    118     case 3: /* UNDEFINED, we treat like 2 (and complained when it was set) */
    119         return 256;
    120     default:
    121         g_assert_not_reached();
    122     }
    123 }
    124 
    125 static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule *m,
    126                                              uint32_t newctrl)
    127 {
    128     /* Handle a write to the CONTROL register */
    129     uint32_t changed;
    130 
    131     ptimer_transaction_begin(m->timer);
    132 
    133     newctrl &= R_CONTROL_VALID_MASK;
    134 
    135     changed = m->control ^ newctrl;
    136 
    137     if (changed & ~newctrl & R_CONTROL_ENABLE_MASK) {
    138         /* ENABLE cleared, stop timer before any further changes */
    139         ptimer_stop(m->timer);
    140     }
    141 
    142     if (changed & R_CONTROL_PRESCALE_MASK) {
    143         int divisor;
    144 
    145         switch (FIELD_EX32(newctrl, CONTROL, PRESCALE)) {
    146         case 0:
    147             divisor = 1;
    148             break;
    149         case 1:
    150             divisor = 16;
    151             break;
    152         case 2:
    153             divisor = 256;
    154             break;
    155         case 3:
    156             /* UNDEFINED; complain, and arbitrarily treat like 2 */
    157             qemu_log_mask(LOG_GUEST_ERROR,
    158                           "CMSDK APB dual-timer: CONTROL.PRESCALE==0b11"
    159                           " is undefined behaviour\n");
    160             divisor = 256;
    161             break;
    162         default:
    163             g_assert_not_reached();
    164         }
    165         ptimer_set_period_from_clock(m->timer, m->parent->timclk, divisor);
    166     }
    167 
    168     if (changed & R_CONTROL_MODE_MASK) {
    169         uint32_t load;
    170         if (newctrl & R_CONTROL_MODE_MASK) {
    171             /* Periodic: the limit is the LOAD register value */
    172             load = m->load;
    173         } else {
    174             /* Free-running: counter wraps around */
    175             load = ptimer_get_limit(m->timer);
    176             if (!(m->control & R_CONTROL_SIZE_MASK)) {
    177                 load = deposit32(m->load, 0, 16, load);
    178             }
    179             m->load = load;
    180             load = 0xffffffff;
    181         }
    182         if (!(m->control & R_CONTROL_SIZE_MASK)) {
    183             load &= 0xffff;
    184         }
    185         ptimer_set_limit(m->timer, load, 0);
    186     }
    187 
    188     if (changed & R_CONTROL_SIZE_MASK) {
    189         /* Timer switched between 16 and 32 bit count */
    190         uint32_t value, load;
    191 
    192         value = ptimer_get_count(m->timer);
    193         load = ptimer_get_limit(m->timer);
    194         if (newctrl & R_CONTROL_SIZE_MASK) {
    195             /* 16 -> 32, top half of VALUE is in struct field */
    196             value = deposit32(m->value, 0, 16, value);
    197         } else {
    198             /* 32 -> 16: save top half to struct field and truncate */
    199             m->value = value;
    200             value &= 0xffff;
    201         }
    202 
    203         if (newctrl & R_CONTROL_MODE_MASK) {
    204             /* Periodic, timer limit has LOAD value */
    205             if (newctrl & R_CONTROL_SIZE_MASK) {
    206                 load = deposit32(m->load, 0, 16, load);
    207             } else {
    208                 m->load = load;
    209                 load &= 0xffff;
    210             }
    211         } else {
    212             /* Free-running, timer limit is set to give wraparound */
    213             if (newctrl & R_CONTROL_SIZE_MASK) {
    214                 load = 0xffffffff;
    215             } else {
    216                 load = 0xffff;
    217             }
    218         }
    219         ptimer_set_count(m->timer, value);
    220         ptimer_set_limit(m->timer, load, 0);
    221     }
    222 
    223     if (newctrl & R_CONTROL_ENABLE_MASK) {
    224         /*
    225          * ENABLE is set; start the timer after all other changes.
    226          * We start it even if the ENABLE bit didn't actually change,
    227          * in case the timer was an expired one-shot timer that has
    228          * now been changed into a free-running or periodic timer.
    229          */
    230         ptimer_run(m->timer, !!(newctrl & R_CONTROL_ONESHOT_MASK));
    231     }
    232 
    233     m->control = newctrl;
    234 
    235     ptimer_transaction_commit(m->timer);
    236 }
    237 
    238 static uint64_t cmsdk_apb_dualtimer_read(void *opaque, hwaddr offset,
    239                                           unsigned size)
    240 {
    241     CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
    242     uint64_t r;
    243 
    244     if (offset >= A_TIMERITCR) {
    245         switch (offset) {
    246         case A_TIMERITCR:
    247             r = s->timeritcr;
    248             break;
    249         case A_PID4 ... A_CID3:
    250             r = timer_id[(offset - A_PID4) / 4];
    251             break;
    252         default:
    253         bad_offset:
    254             qemu_log_mask(LOG_GUEST_ERROR,
    255                           "CMSDK APB dual-timer read: bad offset %x\n",
    256                           (int) offset);
    257             r = 0;
    258             break;
    259         }
    260     } else {
    261         int timer = offset >> 5;
    262         CMSDKAPBDualTimerModule *m;
    263 
    264         if (timer >= ARRAY_SIZE(s->timermod)) {
    265             goto bad_offset;
    266         }
    267 
    268         m = &s->timermod[timer];
    269 
    270         switch (offset & 0x1F) {
    271         case A_TIMER1LOAD:
    272         case A_TIMER1BGLOAD:
    273             if (m->control & R_CONTROL_MODE_MASK) {
    274                 /*
    275                  * Periodic: the ptimer limit is the LOAD register value, (or
    276                  * just the low 16 bits of it if the timer is in 16-bit mode)
    277                  */
    278                 r = ptimer_get_limit(m->timer);
    279                 if (!(m->control & R_CONTROL_SIZE_MASK)) {
    280                     r = deposit32(m->load, 0, 16, r);
    281                 }
    282             } else {
    283                 /* Free-running: LOAD register value is just in m->load */
    284                 r = m->load;
    285             }
    286             break;
    287         case A_TIMER1VALUE:
    288             r = ptimer_get_count(m->timer);
    289             if (!(m->control & R_CONTROL_SIZE_MASK)) {
    290                 r = deposit32(m->value, 0, 16, r);
    291             }
    292             break;
    293         case A_TIMER1CONTROL:
    294             r = m->control;
    295             break;
    296         case A_TIMER1RIS:
    297             r = m->intstatus;
    298             break;
    299         case A_TIMER1MIS:
    300             r = cmsdk_dualtimermod_intstatus(m);
    301             break;
    302         default:
    303             goto bad_offset;
    304         }
    305     }
    306 
    307     trace_cmsdk_apb_dualtimer_read(offset, r, size);
    308     return r;
    309 }
    310 
    311 static void cmsdk_apb_dualtimer_write(void *opaque, hwaddr offset,
    312                                        uint64_t value, unsigned size)
    313 {
    314     CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
    315 
    316     trace_cmsdk_apb_dualtimer_write(offset, value, size);
    317 
    318     if (offset >= A_TIMERITCR) {
    319         switch (offset) {
    320         case A_TIMERITCR:
    321             s->timeritcr = value & R_TIMERITCR_VALID_MASK;
    322             cmsdk_apb_dualtimer_update(s);
    323             break;
    324         case A_TIMERITOP:
    325             s->timeritop = value & R_TIMERITOP_VALID_MASK;
    326             cmsdk_apb_dualtimer_update(s);
    327             break;
    328         default:
    329         bad_offset:
    330             qemu_log_mask(LOG_GUEST_ERROR,
    331                           "CMSDK APB dual-timer write: bad offset %x\n",
    332                           (int) offset);
    333             break;
    334         }
    335     } else {
    336         int timer = offset >> 5;
    337         CMSDKAPBDualTimerModule *m;
    338 
    339         if (timer >= ARRAY_SIZE(s->timermod)) {
    340             goto bad_offset;
    341         }
    342 
    343         m = &s->timermod[timer];
    344 
    345         switch (offset & 0x1F) {
    346         case A_TIMER1LOAD:
    347             /* Set the limit, and immediately reload the count from it */
    348             m->load = value;
    349             m->value = value;
    350             if (!(m->control & R_CONTROL_SIZE_MASK)) {
    351                 value &= 0xffff;
    352             }
    353             ptimer_transaction_begin(m->timer);
    354             if (!(m->control & R_CONTROL_MODE_MASK)) {
    355                 /*
    356                  * In free-running mode this won't set the limit but will
    357                  * still change the current count value.
    358                  */
    359                 ptimer_set_count(m->timer, value);
    360             } else {
    361                 if (!value) {
    362                     ptimer_stop(m->timer);
    363                 }
    364                 ptimer_set_limit(m->timer, value, 1);
    365                 if (value && (m->control & R_CONTROL_ENABLE_MASK)) {
    366                     /* Force possibly-expired oneshot timer to restart */
    367                     ptimer_run(m->timer, 1);
    368                 }
    369             }
    370             ptimer_transaction_commit(m->timer);
    371             break;
    372         case A_TIMER1BGLOAD:
    373             /* Set the limit, but not the current count */
    374             m->load = value;
    375             if (!(m->control & R_CONTROL_MODE_MASK)) {
    376                 /* In free-running mode there is no limit */
    377                 break;
    378             }
    379             if (!(m->control & R_CONTROL_SIZE_MASK)) {
    380                 value &= 0xffff;
    381             }
    382             ptimer_transaction_begin(m->timer);
    383             ptimer_set_limit(m->timer, value, 0);
    384             ptimer_transaction_commit(m->timer);
    385             break;
    386         case A_TIMER1CONTROL:
    387             cmsdk_dualtimermod_write_control(m, value);
    388             cmsdk_apb_dualtimer_update(s);
    389             break;
    390         case A_TIMER1INTCLR:
    391             m->intstatus = 0;
    392             cmsdk_apb_dualtimer_update(s);
    393             break;
    394         default:
    395             goto bad_offset;
    396         }
    397     }
    398 }
    399 
    400 static const MemoryRegionOps cmsdk_apb_dualtimer_ops = {
    401     .read = cmsdk_apb_dualtimer_read,
    402     .write = cmsdk_apb_dualtimer_write,
    403     .endianness = DEVICE_LITTLE_ENDIAN,
    404     /* byte/halfword accesses are just zero-padded on reads and writes */
    405     .impl.min_access_size = 4,
    406     .impl.max_access_size = 4,
    407     .valid.min_access_size = 1,
    408     .valid.max_access_size = 4,
    409 };
    410 
    411 static void cmsdk_dualtimermod_tick(void *opaque)
    412 {
    413     CMSDKAPBDualTimerModule *m = opaque;
    414 
    415     m->intstatus = 1;
    416     cmsdk_apb_dualtimer_update(m->parent);
    417 }
    418 
    419 static void cmsdk_dualtimermod_reset(CMSDKAPBDualTimerModule *m)
    420 {
    421     m->control = R_CONTROL_INTEN_MASK;
    422     m->intstatus = 0;
    423     m->load = 0;
    424     m->value = 0xffffffff;
    425     ptimer_transaction_begin(m->timer);
    426     ptimer_stop(m->timer);
    427     /*
    428      * We start in free-running mode, with VALUE at 0xffffffff, and
    429      * in 16-bit counter mode. This means that the ptimer count and
    430      * limit must both be set to 0xffff, so we wrap at 16 bits.
    431      */
    432     ptimer_set_limit(m->timer, 0xffff, 1);
    433     ptimer_set_period_from_clock(m->timer, m->parent->timclk,
    434                                  cmsdk_dualtimermod_divisor(m));
    435     ptimer_transaction_commit(m->timer);
    436 }
    437 
    438 static void cmsdk_apb_dualtimer_reset(DeviceState *dev)
    439 {
    440     CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(dev);
    441     int i;
    442 
    443     trace_cmsdk_apb_dualtimer_reset();
    444 
    445     for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
    446         cmsdk_dualtimermod_reset(&s->timermod[i]);
    447     }
    448     s->timeritcr = 0;
    449     s->timeritop = 0;
    450 }
    451 
    452 static void cmsdk_apb_dualtimer_clk_update(void *opaque, ClockEvent event)
    453 {
    454     CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
    455     int i;
    456 
    457     for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
    458         CMSDKAPBDualTimerModule *m = &s->timermod[i];
    459         ptimer_transaction_begin(m->timer);
    460         ptimer_set_period_from_clock(m->timer, m->parent->timclk,
    461                                      cmsdk_dualtimermod_divisor(m));
    462         ptimer_transaction_commit(m->timer);
    463     }
    464 }
    465 
    466 static void cmsdk_apb_dualtimer_init(Object *obj)
    467 {
    468     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    469     CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(obj);
    470     int i;
    471 
    472     memory_region_init_io(&s->iomem, obj, &cmsdk_apb_dualtimer_ops,
    473                           s, "cmsdk-apb-dualtimer", 0x1000);
    474     sysbus_init_mmio(sbd, &s->iomem);
    475     sysbus_init_irq(sbd, &s->timerintc);
    476 
    477     for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
    478         sysbus_init_irq(sbd, &s->timermod[i].timerint);
    479     }
    480     s->timclk = qdev_init_clock_in(DEVICE(s), "TIMCLK",
    481                                    cmsdk_apb_dualtimer_clk_update, s,
    482                                    ClockUpdate);
    483 }
    484 
    485 static void cmsdk_apb_dualtimer_realize(DeviceState *dev, Error **errp)
    486 {
    487     CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(dev);
    488     int i;
    489 
    490     if (!clock_has_source(s->timclk)) {
    491         error_setg(errp, "CMSDK APB dualtimer: TIMCLK clock must be connected");
    492         return;
    493     }
    494 
    495     for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
    496         CMSDKAPBDualTimerModule *m = &s->timermod[i];
    497 
    498         m->parent = s;
    499         m->timer = ptimer_init(cmsdk_dualtimermod_tick, m,
    500                                PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
    501                                PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT |
    502                                PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
    503                                PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
    504     }
    505 }
    506 
    507 static const VMStateDescription cmsdk_dualtimermod_vmstate = {
    508     .name = "cmsdk-apb-dualtimer-module",
    509     .version_id = 1,
    510     .minimum_version_id = 1,
    511     .fields = (VMStateField[]) {
    512         VMSTATE_PTIMER(timer, CMSDKAPBDualTimerModule),
    513         VMSTATE_UINT32(load, CMSDKAPBDualTimerModule),
    514         VMSTATE_UINT32(value, CMSDKAPBDualTimerModule),
    515         VMSTATE_UINT32(control, CMSDKAPBDualTimerModule),
    516         VMSTATE_UINT32(intstatus, CMSDKAPBDualTimerModule),
    517         VMSTATE_END_OF_LIST()
    518     }
    519 };
    520 
    521 static const VMStateDescription cmsdk_apb_dualtimer_vmstate = {
    522     .name = "cmsdk-apb-dualtimer",
    523     .version_id = 2,
    524     .minimum_version_id = 2,
    525     .fields = (VMStateField[]) {
    526         VMSTATE_CLOCK(timclk, CMSDKAPBDualTimer),
    527         VMSTATE_STRUCT_ARRAY(timermod, CMSDKAPBDualTimer,
    528                              CMSDK_APB_DUALTIMER_NUM_MODULES,
    529                              1, cmsdk_dualtimermod_vmstate,
    530                              CMSDKAPBDualTimerModule),
    531         VMSTATE_UINT32(timeritcr, CMSDKAPBDualTimer),
    532         VMSTATE_UINT32(timeritop, CMSDKAPBDualTimer),
    533         VMSTATE_END_OF_LIST()
    534     }
    535 };
    536 
    537 static void cmsdk_apb_dualtimer_class_init(ObjectClass *klass, void *data)
    538 {
    539     DeviceClass *dc = DEVICE_CLASS(klass);
    540 
    541     dc->realize = cmsdk_apb_dualtimer_realize;
    542     dc->vmsd = &cmsdk_apb_dualtimer_vmstate;
    543     dc->reset = cmsdk_apb_dualtimer_reset;
    544 }
    545 
    546 static const TypeInfo cmsdk_apb_dualtimer_info = {
    547     .name = TYPE_CMSDK_APB_DUALTIMER,
    548     .parent = TYPE_SYS_BUS_DEVICE,
    549     .instance_size = sizeof(CMSDKAPBDualTimer),
    550     .instance_init = cmsdk_apb_dualtimer_init,
    551     .class_init = cmsdk_apb_dualtimer_class_init,
    552 };
    553 
    554 static void cmsdk_apb_dualtimer_register_types(void)
    555 {
    556     type_register_static(&cmsdk_apb_dualtimer_info);
    557 }
    558 
    559 type_init(cmsdk_apb_dualtimer_register_types);