qemu

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

arm_timer.c (11354B)


      1 /*
      2  * ARM PrimeCell Timer modules.
      3  *
      4  * Copyright (c) 2005-2006 CodeSourcery.
      5  * Written by Paul Brook
      6  *
      7  * This code is licensed under the GPL.
      8  */
      9 
     10 #include "qemu/osdep.h"
     11 #include "hw/sysbus.h"
     12 #include "migration/vmstate.h"
     13 #include "qemu/timer.h"
     14 #include "hw/irq.h"
     15 #include "hw/ptimer.h"
     16 #include "hw/qdev-properties.h"
     17 #include "qemu/module.h"
     18 #include "qemu/log.h"
     19 #include "qom/object.h"
     20 
     21 /* Common timer implementation.  */
     22 
     23 #define TIMER_CTRL_ONESHOT      (1 << 0)
     24 #define TIMER_CTRL_32BIT        (1 << 1)
     25 #define TIMER_CTRL_DIV1         (0 << 2)
     26 #define TIMER_CTRL_DIV16        (1 << 2)
     27 #define TIMER_CTRL_DIV256       (2 << 2)
     28 #define TIMER_CTRL_IE           (1 << 5)
     29 #define TIMER_CTRL_PERIODIC     (1 << 6)
     30 #define TIMER_CTRL_ENABLE       (1 << 7)
     31 
     32 typedef struct {
     33     ptimer_state *timer;
     34     uint32_t control;
     35     uint32_t limit;
     36     int freq;
     37     int int_level;
     38     qemu_irq irq;
     39 } arm_timer_state;
     40 
     41 /* Check all active timers, and schedule the next timer interrupt.  */
     42 
     43 static void arm_timer_update(arm_timer_state *s)
     44 {
     45     /* Update interrupts.  */
     46     if (s->int_level && (s->control & TIMER_CTRL_IE)) {
     47         qemu_irq_raise(s->irq);
     48     } else {
     49         qemu_irq_lower(s->irq);
     50     }
     51 }
     52 
     53 static uint32_t arm_timer_read(void *opaque, hwaddr offset)
     54 {
     55     arm_timer_state *s = (arm_timer_state *)opaque;
     56 
     57     switch (offset >> 2) {
     58     case 0: /* TimerLoad */
     59     case 6: /* TimerBGLoad */
     60         return s->limit;
     61     case 1: /* TimerValue */
     62         return ptimer_get_count(s->timer);
     63     case 2: /* TimerControl */
     64         return s->control;
     65     case 4: /* TimerRIS */
     66         return s->int_level;
     67     case 5: /* TimerMIS */
     68         if ((s->control & TIMER_CTRL_IE) == 0)
     69             return 0;
     70         return s->int_level;
     71     default:
     72         qemu_log_mask(LOG_GUEST_ERROR,
     73                       "%s: Bad offset %x\n", __func__, (int)offset);
     74         return 0;
     75     }
     76 }
     77 
     78 /*
     79  * Reset the timer limit after settings have changed.
     80  * May only be called from inside a ptimer transaction block.
     81  */
     82 static void arm_timer_recalibrate(arm_timer_state *s, int reload)
     83 {
     84     uint32_t limit;
     85 
     86     if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
     87         /* Free running.  */
     88         if (s->control & TIMER_CTRL_32BIT)
     89             limit = 0xffffffff;
     90         else
     91             limit = 0xffff;
     92     } else {
     93           /* Periodic.  */
     94           limit = s->limit;
     95     }
     96     ptimer_set_limit(s->timer, limit, reload);
     97 }
     98 
     99 static void arm_timer_write(void *opaque, hwaddr offset,
    100                             uint32_t value)
    101 {
    102     arm_timer_state *s = (arm_timer_state *)opaque;
    103     int freq;
    104 
    105     switch (offset >> 2) {
    106     case 0: /* TimerLoad */
    107         s->limit = value;
    108         ptimer_transaction_begin(s->timer);
    109         arm_timer_recalibrate(s, 1);
    110         ptimer_transaction_commit(s->timer);
    111         break;
    112     case 1: /* TimerValue */
    113         /* ??? Linux seems to want to write to this readonly register.
    114            Ignore it.  */
    115         break;
    116     case 2: /* TimerControl */
    117         ptimer_transaction_begin(s->timer);
    118         if (s->control & TIMER_CTRL_ENABLE) {
    119             /* Pause the timer if it is running.  This may cause some
    120                inaccuracy dure to rounding, but avoids a whole lot of other
    121                messyness.  */
    122             ptimer_stop(s->timer);
    123         }
    124         s->control = value;
    125         freq = s->freq;
    126         /* ??? Need to recalculate expiry time after changing divisor.  */
    127         switch ((value >> 2) & 3) {
    128         case 1: freq >>= 4; break;
    129         case 2: freq >>= 8; break;
    130         }
    131         arm_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE);
    132         ptimer_set_freq(s->timer, freq);
    133         if (s->control & TIMER_CTRL_ENABLE) {
    134             /* Restart the timer if still enabled.  */
    135             ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
    136         }
    137         ptimer_transaction_commit(s->timer);
    138         break;
    139     case 3: /* TimerIntClr */
    140         s->int_level = 0;
    141         break;
    142     case 6: /* TimerBGLoad */
    143         s->limit = value;
    144         ptimer_transaction_begin(s->timer);
    145         arm_timer_recalibrate(s, 0);
    146         ptimer_transaction_commit(s->timer);
    147         break;
    148     default:
    149         qemu_log_mask(LOG_GUEST_ERROR,
    150                       "%s: Bad offset %x\n", __func__, (int)offset);
    151     }
    152     arm_timer_update(s);
    153 }
    154 
    155 static void arm_timer_tick(void *opaque)
    156 {
    157     arm_timer_state *s = (arm_timer_state *)opaque;
    158     s->int_level = 1;
    159     arm_timer_update(s);
    160 }
    161 
    162 static const VMStateDescription vmstate_arm_timer = {
    163     .name = "arm_timer",
    164     .version_id = 1,
    165     .minimum_version_id = 1,
    166     .fields = (VMStateField[]) {
    167         VMSTATE_UINT32(control, arm_timer_state),
    168         VMSTATE_UINT32(limit, arm_timer_state),
    169         VMSTATE_INT32(int_level, arm_timer_state),
    170         VMSTATE_PTIMER(timer, arm_timer_state),
    171         VMSTATE_END_OF_LIST()
    172     }
    173 };
    174 
    175 static arm_timer_state *arm_timer_init(uint32_t freq)
    176 {
    177     arm_timer_state *s;
    178 
    179     s = g_new0(arm_timer_state, 1);
    180     s->freq = freq;
    181     s->control = TIMER_CTRL_IE;
    182 
    183     s->timer = ptimer_init(arm_timer_tick, s, PTIMER_POLICY_LEGACY);
    184     vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_arm_timer, s);
    185     return s;
    186 }
    187 
    188 /*
    189  * ARM PrimeCell SP804 dual timer module.
    190  * Docs at
    191  * https://developer.arm.com/documentation/ddi0271/latest/
    192  */
    193 
    194 #define TYPE_SP804 "sp804"
    195 OBJECT_DECLARE_SIMPLE_TYPE(SP804State, SP804)
    196 
    197 struct SP804State {
    198     SysBusDevice parent_obj;
    199 
    200     MemoryRegion iomem;
    201     arm_timer_state *timer[2];
    202     uint32_t freq0, freq1;
    203     int level[2];
    204     qemu_irq irq;
    205 };
    206 
    207 static const uint8_t sp804_ids[] = {
    208     /* Timer ID */
    209     0x04, 0x18, 0x14, 0,
    210     /* PrimeCell ID */
    211     0xd, 0xf0, 0x05, 0xb1
    212 };
    213 
    214 /* Merge the IRQs from the two component devices.  */
    215 static void sp804_set_irq(void *opaque, int irq, int level)
    216 {
    217     SP804State *s = (SP804State *)opaque;
    218 
    219     s->level[irq] = level;
    220     qemu_set_irq(s->irq, s->level[0] || s->level[1]);
    221 }
    222 
    223 static uint64_t sp804_read(void *opaque, hwaddr offset,
    224                            unsigned size)
    225 {
    226     SP804State *s = (SP804State *)opaque;
    227 
    228     if (offset < 0x20) {
    229         return arm_timer_read(s->timer[0], offset);
    230     }
    231     if (offset < 0x40) {
    232         return arm_timer_read(s->timer[1], offset - 0x20);
    233     }
    234 
    235     /* TimerPeriphID */
    236     if (offset >= 0xfe0 && offset <= 0xffc) {
    237         return sp804_ids[(offset - 0xfe0) >> 2];
    238     }
    239 
    240     switch (offset) {
    241     /* Integration Test control registers, which we won't support */
    242     case 0xf00: /* TimerITCR */
    243     case 0xf04: /* TimerITOP (strictly write only but..) */
    244         qemu_log_mask(LOG_UNIMP,
    245                       "%s: integration test registers unimplemented\n",
    246                       __func__);
    247         return 0;
    248     }
    249 
    250     qemu_log_mask(LOG_GUEST_ERROR,
    251                   "%s: Bad offset %x\n", __func__, (int)offset);
    252     return 0;
    253 }
    254 
    255 static void sp804_write(void *opaque, hwaddr offset,
    256                         uint64_t value, unsigned size)
    257 {
    258     SP804State *s = (SP804State *)opaque;
    259 
    260     if (offset < 0x20) {
    261         arm_timer_write(s->timer[0], offset, value);
    262         return;
    263     }
    264 
    265     if (offset < 0x40) {
    266         arm_timer_write(s->timer[1], offset - 0x20, value);
    267         return;
    268     }
    269 
    270     /* Technically we could be writing to the Test Registers, but not likely */
    271     qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n",
    272                   __func__, (int)offset);
    273 }
    274 
    275 static const MemoryRegionOps sp804_ops = {
    276     .read = sp804_read,
    277     .write = sp804_write,
    278     .endianness = DEVICE_NATIVE_ENDIAN,
    279 };
    280 
    281 static const VMStateDescription vmstate_sp804 = {
    282     .name = "sp804",
    283     .version_id = 1,
    284     .minimum_version_id = 1,
    285     .fields = (VMStateField[]) {
    286         VMSTATE_INT32_ARRAY(level, SP804State, 2),
    287         VMSTATE_END_OF_LIST()
    288     }
    289 };
    290 
    291 static void sp804_init(Object *obj)
    292 {
    293     SP804State *s = SP804(obj);
    294     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    295 
    296     sysbus_init_irq(sbd, &s->irq);
    297     memory_region_init_io(&s->iomem, obj, &sp804_ops, s,
    298                           "sp804", 0x1000);
    299     sysbus_init_mmio(sbd, &s->iomem);
    300 }
    301 
    302 static void sp804_realize(DeviceState *dev, Error **errp)
    303 {
    304     SP804State *s = SP804(dev);
    305 
    306     s->timer[0] = arm_timer_init(s->freq0);
    307     s->timer[1] = arm_timer_init(s->freq1);
    308     s->timer[0]->irq = qemu_allocate_irq(sp804_set_irq, s, 0);
    309     s->timer[1]->irq = qemu_allocate_irq(sp804_set_irq, s, 1);
    310 }
    311 
    312 /* Integrator/CP timer module.  */
    313 
    314 #define TYPE_INTEGRATOR_PIT "integrator_pit"
    315 OBJECT_DECLARE_SIMPLE_TYPE(icp_pit_state, INTEGRATOR_PIT)
    316 
    317 struct icp_pit_state {
    318     SysBusDevice parent_obj;
    319 
    320     MemoryRegion iomem;
    321     arm_timer_state *timer[3];
    322 };
    323 
    324 static uint64_t icp_pit_read(void *opaque, hwaddr offset,
    325                              unsigned size)
    326 {
    327     icp_pit_state *s = (icp_pit_state *)opaque;
    328     int n;
    329 
    330     /* ??? Don't know the PrimeCell ID for this device.  */
    331     n = offset >> 8;
    332     if (n > 2) {
    333         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
    334         return 0;
    335     }
    336 
    337     return arm_timer_read(s->timer[n], offset & 0xff);
    338 }
    339 
    340 static void icp_pit_write(void *opaque, hwaddr offset,
    341                           uint64_t value, unsigned size)
    342 {
    343     icp_pit_state *s = (icp_pit_state *)opaque;
    344     int n;
    345 
    346     n = offset >> 8;
    347     if (n > 2) {
    348         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
    349         return;
    350     }
    351 
    352     arm_timer_write(s->timer[n], offset & 0xff, value);
    353 }
    354 
    355 static const MemoryRegionOps icp_pit_ops = {
    356     .read = icp_pit_read,
    357     .write = icp_pit_write,
    358     .endianness = DEVICE_NATIVE_ENDIAN,
    359 };
    360 
    361 static void icp_pit_init(Object *obj)
    362 {
    363     icp_pit_state *s = INTEGRATOR_PIT(obj);
    364     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
    365 
    366     /* Timer 0 runs at the system clock speed (40MHz).  */
    367     s->timer[0] = arm_timer_init(40000000);
    368     /* The other two timers run at 1MHz.  */
    369     s->timer[1] = arm_timer_init(1000000);
    370     s->timer[2] = arm_timer_init(1000000);
    371 
    372     sysbus_init_irq(dev, &s->timer[0]->irq);
    373     sysbus_init_irq(dev, &s->timer[1]->irq);
    374     sysbus_init_irq(dev, &s->timer[2]->irq);
    375 
    376     memory_region_init_io(&s->iomem, obj, &icp_pit_ops, s,
    377                           "icp_pit", 0x1000);
    378     sysbus_init_mmio(dev, &s->iomem);
    379     /* This device has no state to save/restore.  The component timers will
    380        save themselves.  */
    381 }
    382 
    383 static const TypeInfo icp_pit_info = {
    384     .name          = TYPE_INTEGRATOR_PIT,
    385     .parent        = TYPE_SYS_BUS_DEVICE,
    386     .instance_size = sizeof(icp_pit_state),
    387     .instance_init = icp_pit_init,
    388 };
    389 
    390 static Property sp804_properties[] = {
    391     DEFINE_PROP_UINT32("freq0", SP804State, freq0, 1000000),
    392     DEFINE_PROP_UINT32("freq1", SP804State, freq1, 1000000),
    393     DEFINE_PROP_END_OF_LIST(),
    394 };
    395 
    396 static void sp804_class_init(ObjectClass *klass, void *data)
    397 {
    398     DeviceClass *k = DEVICE_CLASS(klass);
    399 
    400     k->realize = sp804_realize;
    401     device_class_set_props(k, sp804_properties);
    402     k->vmsd = &vmstate_sp804;
    403 }
    404 
    405 static const TypeInfo sp804_info = {
    406     .name          = TYPE_SP804,
    407     .parent        = TYPE_SYS_BUS_DEVICE,
    408     .instance_size = sizeof(SP804State),
    409     .instance_init = sp804_init,
    410     .class_init    = sp804_class_init,
    411 };
    412 
    413 static void arm_timer_register_types(void)
    414 {
    415     type_register_static(&icp_pit_info);
    416     type_register_static(&sp804_info);
    417 }
    418 
    419 type_init(arm_timer_register_types)