qemu/hw/timer/arm_generic_timer.c
<<
>>
Prefs
   1/*
   2 * QEMU model of the ARM Generic Timer
   3 *
   4 * Copyright (c) 2014 Xilinx Inc.
   5 *
   6 * Autogenerated by xregqemu.py 2014-09-10.
   7 *
   8 * Permission is hereby granted, free of charge, to any person obtaining a copy
   9 * of this software and associated documentation files (the "Software"), to deal
  10 * in the Software without restriction, including without limitation the rights
  11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12 * copies of the Software, and to permit persons to whom the Software is
  13 * furnished to do so, subject to the following conditions:
  14 *
  15 * The above copyright notice and this permission notice shall be included in
  16 * all copies or substantial portions of the Software.
  17 *
  18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24 * THE SOFTWARE.
  25 */
  26
  27#include "qemu/osdep.h"
  28#include "hw/sysbus.h"
  29#include "hw/register.h"
  30#include "qemu/bitops.h"
  31#include "qapi/error.h"
  32#include "qemu/log.h"
  33#include "qemu/timer.h"
  34#include "migration/vmstate.h"
  35#include "hw/qdev-properties.h"
  36#include "hw/irq.h"
  37
  38#ifndef ARM_GEN_TIMER_ERR_DEBUG
  39#define ARM_GEN_TIMER_ERR_DEBUG 0
  40#endif
  41
  42#define TYPE_ARM_GEN_TIMER "arm.generic-timer"
  43
  44#define ARM_GEN_TIMER(obj) \
  45     OBJECT_CHECK(ARMGenTimer, (obj), TYPE_ARM_GEN_TIMER)
  46
  47REG32(COUNTER_CONTROL_REGISTER, 0x0)
  48    FIELD(COUNTER_CONTROL_REGISTER, EN, 1, 1)
  49    FIELD(COUNTER_CONTROL_REGISTER, HDBG, 0, 1)
  50REG32(COUNTER_STATUS_REGISTER, 0x4)
  51    FIELD(COUNTER_STATUS_REGISTER, DBGH, 1, 1)
  52REG32(CURRENT_COUNTER_VALUE_LOWER_REGISTER, 0x8)
  53REG32(CURRENT_COUNTER_VALUE_UPPER_REGISTER, 0xc)
  54REG32(BASE_FREQUENCY_ID_REGISTER, 0x20)
  55
  56#define R_MAX (R_BASE_FREQUENCY_ID_REGISTER + 1)
  57
  58typedef struct ARMGenTimer {
  59    SysBusDevice parent_obj;
  60    MemoryRegion iomem;
  61
  62    bool enabled;
  63    uint64_t tick_offset;
  64
  65    uint32_t regs[R_MAX];
  66    RegisterInfo regs_info[R_MAX];
  67} ARMGenTimer;
  68
  69static void counter_control_postw(RegisterInfo *reg, uint64_t val64)
  70{
  71    ARMGenTimer *s = ARM_GEN_TIMER(reg->opaque);
  72    bool new_status = extract32(s->regs[R_COUNTER_CONTROL_REGISTER],
  73                                R_COUNTER_CONTROL_REGISTER_EN_SHIFT,
  74                                R_COUNTER_CONTROL_REGISTER_EN_LENGTH);
  75    uint64_t current_ticks;
  76
  77    current_ticks = muldiv64(qemu_clock_get_us(QEMU_CLOCK_VIRTUAL),
  78                             NANOSECONDS_PER_SECOND, 1000000);
  79
  80    if ((s->enabled && !new_status) ||
  81        (!s->enabled && new_status)) {
  82        /* The timer is being disabled or enabled */
  83        s->tick_offset = current_ticks - s->tick_offset;
  84    }
  85
  86    s->enabled = new_status;
  87}
  88
  89static uint64_t couter_low_value_postr(RegisterInfo *reg, uint64_t val64)
  90{
  91    ARMGenTimer *s = ARM_GEN_TIMER(reg->opaque);
  92    uint64_t current_ticks, total_ticks;
  93    uint32_t low_ticks;
  94
  95    if (s->enabled) {
  96        current_ticks = muldiv64(qemu_clock_get_us(QEMU_CLOCK_VIRTUAL),
  97                                 NANOSECONDS_PER_SECOND, 1000000);
  98        total_ticks = current_ticks - s->tick_offset;
  99        low_ticks = (uint32_t) total_ticks;
 100    } else {
 101        /* Timer is disabled, return the time when it was disabled */
 102        low_ticks = (uint32_t) s->tick_offset;
 103    }
 104
 105    return low_ticks;
 106}
 107
 108static uint64_t couter_high_value_postr(RegisterInfo *reg, uint64_t val64)
 109{
 110    ARMGenTimer *s = ARM_GEN_TIMER(reg->opaque);
 111    uint64_t current_ticks, total_ticks;
 112    uint32_t high_ticks;
 113
 114    if (s->enabled) {
 115        current_ticks = muldiv64(qemu_clock_get_us(QEMU_CLOCK_VIRTUAL),
 116                                 NANOSECONDS_PER_SECOND, 1000000);
 117        total_ticks = current_ticks - s->tick_offset;
 118        high_ticks = (uint32_t) (total_ticks >> 32);
 119    } else {
 120        /* Timer is disabled, return the time when it was disabled */
 121        high_ticks = (uint32_t) (s->tick_offset >> 32);
 122    }
 123
 124    return high_ticks;
 125}
 126
 127
 128static RegisterAccessInfo arm_gen_timer_regs_info[] = {
 129    {   .name = "COUNTER_CONTROL_REGISTER",
 130        .addr = A_COUNTER_CONTROL_REGISTER,
 131        .rsvd = 0xfffffffc,
 132        .post_write = counter_control_postw,
 133    },{ .name = "COUNTER_STATUS_REGISTER",
 134        .addr = A_COUNTER_STATUS_REGISTER,
 135        .rsvd = 0xfffffffd, .ro = 0x2,
 136    },{ .name = "CURRENT_COUNTER_VALUE_LOWER_REGISTER",
 137        .addr = A_CURRENT_COUNTER_VALUE_LOWER_REGISTER,
 138        .post_read = couter_low_value_postr,
 139    },{ .name = "CURRENT_COUNTER_VALUE_UPPER_REGISTER",
 140        .addr = A_CURRENT_COUNTER_VALUE_UPPER_REGISTER,
 141        .post_read = couter_high_value_postr,
 142    },{ .name = "BASE_FREQUENCY_ID_REGISTER",
 143        .addr = A_BASE_FREQUENCY_ID_REGISTER,
 144    }
 145};
 146
 147static void arm_gen_timer_reset(DeviceState *dev)
 148{
 149    ARMGenTimer *s = ARM_GEN_TIMER(dev);
 150    unsigned int i;
 151
 152    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
 153        register_reset(&s->regs_info[i]);
 154    }
 155
 156    s->tick_offset = 0;
 157    s->enabled = false;
 158}
 159
 160static MemTxResult arm_gen_timer_access(MemoryTransaction *tr)
 161{
 162    MemTxAttrs attr = tr->attr;
 163    void *opaque = tr->opaque;
 164    hwaddr addr = tr->addr;
 165    unsigned size = tr->size;
 166    uint64_t value = tr->data.u64;;
 167    bool is_write = tr->rw;
 168
 169    if (is_write && !attr.secure) {
 170        /* Ignore NS writes  */
 171        qemu_log_mask(LOG_GUEST_ERROR,
 172                      "Non secure writes to the system timestamp generator " \
 173                      "are invalid\n");
 174        return MEMTX_ERROR;
 175    }
 176
 177    if (is_write) {
 178        register_write_memory(opaque, addr, value, size);
 179    } else {
 180        tr->data.u64 = register_read_memory(opaque, addr, size);
 181    }
 182
 183    return MEMTX_OK;
 184}
 185
 186static const MemoryRegionOps arm_gen_timer_ops = {
 187    .access = arm_gen_timer_access,
 188    .endianness = DEVICE_LITTLE_ENDIAN,
 189    .valid = {
 190        .min_access_size = 4,
 191        .max_access_size = 4,
 192    },
 193};
 194
 195static void arm_gen_timer_init(Object *obj)
 196{
 197    ARMGenTimer *s = ARM_GEN_TIMER(obj);
 198    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 199    RegisterInfoArray *reg_array;
 200
 201    memory_region_init(&s->iomem, obj, TYPE_ARM_GEN_TIMER,
 202                       R_MAX * 4);
 203    reg_array =
 204        register_init_block32(DEVICE(obj), arm_gen_timer_regs_info,
 205                              ARRAY_SIZE(arm_gen_timer_regs_info),
 206                              s->regs_info, s->regs,
 207                              &arm_gen_timer_ops,
 208                              ARM_GEN_TIMER_ERR_DEBUG,
 209                              R_MAX * 4);
 210    memory_region_add_subregion(&s->iomem,
 211                                0x0,
 212                                &reg_array->mem);
 213    sysbus_init_mmio(sbd, &s->iomem);
 214}
 215
 216static const VMStateDescription vmstate_arm_gen_timer = {
 217    .name = TYPE_ARM_GEN_TIMER,
 218    .version_id = 1,
 219    .minimum_version_id = 1,
 220    .fields = (VMStateField[]) {
 221        VMSTATE_UINT32_ARRAY(regs, ARMGenTimer, R_MAX),
 222        VMSTATE_END_OF_LIST(),
 223    }
 224};
 225
 226static void arm_gen_timer_class_init(ObjectClass *klass, void *data)
 227{
 228    DeviceClass *dc = DEVICE_CLASS(klass);
 229
 230    dc->reset = arm_gen_timer_reset;
 231    dc->vmsd = &vmstate_arm_gen_timer;
 232}
 233
 234static const TypeInfo arm_gen_timer_info = {
 235    .name          = TYPE_ARM_GEN_TIMER,
 236    .parent        = TYPE_SYS_BUS_DEVICE,
 237    .instance_size = sizeof(ARMGenTimer),
 238    .class_init    = arm_gen_timer_class_init,
 239    .instance_init = arm_gen_timer_init,
 240};
 241
 242static void arm_gen_timer_register_types(void)
 243{
 244    type_register_static(&arm_gen_timer_info);
 245}
 246
 247type_init(arm_gen_timer_register_types)
 248