qemu/hw/timer/lm32_timer.c
<<
>>
Prefs
   1/*
   2 *  QEMU model of the LatticeMico32 timer block.
   3 *
   4 *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 *
  19 *
  20 * Specification available at:
  21 *   http://www.latticesemi.com/documents/mico32timer.pdf
  22 */
  23
  24#include "qemu/osdep.h"
  25#include "hw/irq.h"
  26#include "hw/sysbus.h"
  27#include "migration/vmstate.h"
  28#include "trace.h"
  29#include "qemu/timer.h"
  30#include "hw/ptimer.h"
  31#include "hw/qdev-properties.h"
  32#include "qemu/error-report.h"
  33#include "qemu/module.h"
  34
  35#define DEFAULT_FREQUENCY (50*1000000)
  36
  37enum {
  38    R_SR = 0,
  39    R_CR,
  40    R_PERIOD,
  41    R_SNAPSHOT,
  42    R_MAX
  43};
  44
  45enum {
  46    SR_TO    = (1 << 0),
  47    SR_RUN   = (1 << 1),
  48};
  49
  50enum {
  51    CR_ITO   = (1 << 0),
  52    CR_CONT  = (1 << 1),
  53    CR_START = (1 << 2),
  54    CR_STOP  = (1 << 3),
  55};
  56
  57#define TYPE_LM32_TIMER "lm32-timer"
  58#define LM32_TIMER(obj) OBJECT_CHECK(LM32TimerState, (obj), TYPE_LM32_TIMER)
  59
  60struct LM32TimerState {
  61    SysBusDevice parent_obj;
  62
  63    MemoryRegion iomem;
  64
  65    ptimer_state *ptimer;
  66
  67    qemu_irq irq;
  68    uint32_t freq_hz;
  69
  70    uint32_t regs[R_MAX];
  71};
  72typedef struct LM32TimerState LM32TimerState;
  73
  74static void timer_update_irq(LM32TimerState *s)
  75{
  76    int state = (s->regs[R_SR] & SR_TO) && (s->regs[R_CR] & CR_ITO);
  77
  78    trace_lm32_timer_irq_state(state);
  79    qemu_set_irq(s->irq, state);
  80}
  81
  82static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size)
  83{
  84    LM32TimerState *s = opaque;
  85    uint32_t r = 0;
  86
  87    addr >>= 2;
  88    switch (addr) {
  89    case R_SR:
  90    case R_CR:
  91    case R_PERIOD:
  92        r = s->regs[addr];
  93        break;
  94    case R_SNAPSHOT:
  95        r = (uint32_t)ptimer_get_count(s->ptimer);
  96        break;
  97    default:
  98        error_report("lm32_timer: read access to unknown register 0x"
  99                TARGET_FMT_plx, addr << 2);
 100        break;
 101    }
 102
 103    trace_lm32_timer_memory_read(addr << 2, r);
 104    return r;
 105}
 106
 107static void timer_write(void *opaque, hwaddr addr,
 108                        uint64_t value, unsigned size)
 109{
 110    LM32TimerState *s = opaque;
 111
 112    trace_lm32_timer_memory_write(addr, value);
 113
 114    addr >>= 2;
 115    switch (addr) {
 116    case R_SR:
 117        s->regs[R_SR] &= ~SR_TO;
 118        break;
 119    case R_CR:
 120        ptimer_transaction_begin(s->ptimer);
 121        s->regs[R_CR] = value;
 122        if (s->regs[R_CR] & CR_START) {
 123            ptimer_run(s->ptimer, 1);
 124        }
 125        if (s->regs[R_CR] & CR_STOP) {
 126            ptimer_stop(s->ptimer);
 127        }
 128        ptimer_transaction_commit(s->ptimer);
 129        break;
 130    case R_PERIOD:
 131        s->regs[R_PERIOD] = value;
 132        ptimer_transaction_begin(s->ptimer);
 133        ptimer_set_count(s->ptimer, value);
 134        ptimer_transaction_commit(s->ptimer);
 135        break;
 136    case R_SNAPSHOT:
 137        error_report("lm32_timer: write access to read only register 0x"
 138                TARGET_FMT_plx, addr << 2);
 139        break;
 140    default:
 141        error_report("lm32_timer: write access to unknown register 0x"
 142                TARGET_FMT_plx, addr << 2);
 143        break;
 144    }
 145    timer_update_irq(s);
 146}
 147
 148static const MemoryRegionOps timer_ops = {
 149    .read = timer_read,
 150    .write = timer_write,
 151    .endianness = DEVICE_NATIVE_ENDIAN,
 152    .valid = {
 153        .min_access_size = 4,
 154        .max_access_size = 4,
 155    },
 156};
 157
 158static void timer_hit(void *opaque)
 159{
 160    LM32TimerState *s = opaque;
 161
 162    trace_lm32_timer_hit();
 163
 164    s->regs[R_SR] |= SR_TO;
 165
 166    if (s->regs[R_CR] & CR_CONT) {
 167        ptimer_set_count(s->ptimer, s->regs[R_PERIOD]);
 168        ptimer_run(s->ptimer, 1);
 169    }
 170    timer_update_irq(s);
 171}
 172
 173static void timer_reset(DeviceState *d)
 174{
 175    LM32TimerState *s = LM32_TIMER(d);
 176    int i;
 177
 178    for (i = 0; i < R_MAX; i++) {
 179        s->regs[i] = 0;
 180    }
 181    ptimer_transaction_begin(s->ptimer);
 182    ptimer_stop(s->ptimer);
 183    ptimer_transaction_commit(s->ptimer);
 184}
 185
 186static void lm32_timer_init(Object *obj)
 187{
 188    LM32TimerState *s = LM32_TIMER(obj);
 189    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 190
 191    sysbus_init_irq(dev, &s->irq);
 192
 193    memory_region_init_io(&s->iomem, obj, &timer_ops, s,
 194                          "timer", R_MAX * 4);
 195    sysbus_init_mmio(dev, &s->iomem);
 196}
 197
 198static void lm32_timer_realize(DeviceState *dev, Error **errp)
 199{
 200    LM32TimerState *s = LM32_TIMER(dev);
 201
 202    s->ptimer = ptimer_init(timer_hit, s, PTIMER_POLICY_DEFAULT);
 203
 204    ptimer_transaction_begin(s->ptimer);
 205    ptimer_set_freq(s->ptimer, s->freq_hz);
 206    ptimer_transaction_commit(s->ptimer);
 207}
 208
 209static const VMStateDescription vmstate_lm32_timer = {
 210    .name = "lm32-timer",
 211    .version_id = 1,
 212    .minimum_version_id = 1,
 213    .fields = (VMStateField[]) {
 214        VMSTATE_PTIMER(ptimer, LM32TimerState),
 215        VMSTATE_UINT32(freq_hz, LM32TimerState),
 216        VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX),
 217        VMSTATE_END_OF_LIST()
 218    }
 219};
 220
 221static Property lm32_timer_properties[] = {
 222    DEFINE_PROP_UINT32("frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY),
 223    DEFINE_PROP_END_OF_LIST(),
 224};
 225
 226static void lm32_timer_class_init(ObjectClass *klass, void *data)
 227{
 228    DeviceClass *dc = DEVICE_CLASS(klass);
 229
 230    dc->realize = lm32_timer_realize;
 231    dc->reset = timer_reset;
 232    dc->vmsd = &vmstate_lm32_timer;
 233    dc->props = lm32_timer_properties;
 234}
 235
 236static const TypeInfo lm32_timer_info = {
 237    .name          = TYPE_LM32_TIMER,
 238    .parent        = TYPE_SYS_BUS_DEVICE,
 239    .instance_size = sizeof(LM32TimerState),
 240    .instance_init = lm32_timer_init,
 241    .class_init    = lm32_timer_class_init,
 242};
 243
 244static void lm32_timer_register_types(void)
 245{
 246    type_register_static(&lm32_timer_info);
 247}
 248
 249type_init(lm32_timer_register_types)
 250