qemu/hw/xilinx_timer.c
<<
>>
Prefs
   1/*
   2 * QEMU model of the Xilinx timer block.
   3 *
   4 * Copyright (c) 2009 Edgar E. Iglesias.
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "sysbus.h"
  26#include "ptimer.h"
  27#include "qemu-log.h"
  28
  29#define D(x)
  30
  31#define R_TCSR     0
  32#define R_TLR      1
  33#define R_TCR      2
  34#define R_MAX      4
  35
  36#define TCSR_MDT        (1<<0)
  37#define TCSR_UDT        (1<<1)
  38#define TCSR_GENT       (1<<2)
  39#define TCSR_CAPT       (1<<3)
  40#define TCSR_ARHT       (1<<4)
  41#define TCSR_LOAD       (1<<5)
  42#define TCSR_ENIT       (1<<6)
  43#define TCSR_ENT        (1<<7)
  44#define TCSR_TINT       (1<<8)
  45#define TCSR_PWMA       (1<<9)
  46#define TCSR_ENALL      (1<<10)
  47
  48struct xlx_timer
  49{
  50    QEMUBH *bh;
  51    ptimer_state *ptimer;
  52    void *parent;
  53    int nr; /* for debug.  */
  54
  55    unsigned long timer_div;
  56
  57    uint32_t regs[R_MAX];
  58};
  59
  60struct timerblock
  61{
  62    SysBusDevice busdev;
  63    MemoryRegion mmio;
  64    qemu_irq irq;
  65    uint8_t one_timer_only;
  66    uint32_t freq_hz;
  67    struct xlx_timer *timers;
  68};
  69
  70static inline unsigned int num_timers(struct timerblock *t)
  71{
  72    return 2 - t->one_timer_only;
  73}
  74
  75static inline unsigned int timer_from_addr(hwaddr addr)
  76{
  77    /* Timers get a 4x32bit control reg area each.  */
  78    return addr >> 2;
  79}
  80
  81static void timer_update_irq(struct timerblock *t)
  82{
  83    unsigned int i, irq = 0;
  84    uint32_t csr;
  85
  86    for (i = 0; i < num_timers(t); i++) {
  87        csr = t->timers[i].regs[R_TCSR];
  88        irq |= (csr & TCSR_TINT) && (csr & TCSR_ENIT);
  89    }
  90
  91    /* All timers within the same slave share a single IRQ line.  */
  92    qemu_set_irq(t->irq, !!irq);
  93}
  94
  95static uint64_t
  96timer_read(void *opaque, hwaddr addr, unsigned int size)
  97{
  98    struct timerblock *t = opaque;
  99    struct xlx_timer *xt;
 100    uint32_t r = 0;
 101    unsigned int timer;
 102
 103    addr >>= 2;
 104    timer = timer_from_addr(addr);
 105    xt = &t->timers[timer];
 106    /* Further decoding to address a specific timers reg.  */
 107    addr &= 0x3;
 108    switch (addr)
 109    {
 110        case R_TCR:
 111                r = ptimer_get_count(xt->ptimer);
 112                if (!(xt->regs[R_TCSR] & TCSR_UDT))
 113                    r = ~r;
 114                D(qemu_log("xlx_timer t=%d read counter=%x udt=%d\n",
 115                         timer, r, xt->regs[R_TCSR] & TCSR_UDT));
 116            break;
 117        default:
 118            if (addr < ARRAY_SIZE(xt->regs))
 119                r = xt->regs[addr];
 120            break;
 121
 122    }
 123    D(fprintf(stderr, "%s timer=%d %x=%x\n", __func__, timer, addr * 4, r));
 124    return r;
 125}
 126
 127static void timer_enable(struct xlx_timer *xt)
 128{
 129    uint64_t count;
 130
 131    D(fprintf(stderr, "%s timer=%d down=%d\n", __func__,
 132              xt->nr, xt->regs[R_TCSR] & TCSR_UDT));
 133
 134    ptimer_stop(xt->ptimer);
 135
 136    if (xt->regs[R_TCSR] & TCSR_UDT)
 137        count = xt->regs[R_TLR];
 138    else
 139        count = ~0 - xt->regs[R_TLR];
 140    ptimer_set_limit(xt->ptimer, count, 1);
 141    ptimer_run(xt->ptimer, 1);
 142}
 143
 144static void
 145timer_write(void *opaque, hwaddr addr,
 146            uint64_t val64, unsigned int size)
 147{
 148    struct timerblock *t = opaque;
 149    struct xlx_timer *xt;
 150    unsigned int timer;
 151    uint32_t value = val64;
 152
 153    addr >>= 2;
 154    timer = timer_from_addr(addr);
 155    xt = &t->timers[timer];
 156    D(fprintf(stderr, "%s addr=%x val=%x (timer=%d off=%d)\n",
 157             __func__, addr * 4, value, timer, addr & 3));
 158    /* Further decoding to address a specific timers reg.  */
 159    addr &= 3;
 160    switch (addr) 
 161    {
 162        case R_TCSR:
 163            if (value & TCSR_TINT)
 164                value &= ~TCSR_TINT;
 165
 166            xt->regs[addr] = value;
 167            if (value & TCSR_ENT)
 168                timer_enable(xt);
 169            break;
 170 
 171        default:
 172            if (addr < ARRAY_SIZE(xt->regs))
 173                xt->regs[addr] = value;
 174            break;
 175    }
 176    timer_update_irq(t);
 177}
 178
 179static const MemoryRegionOps timer_ops = {
 180    .read = timer_read,
 181    .write = timer_write,
 182    .endianness = DEVICE_NATIVE_ENDIAN,
 183    .valid = {
 184        .min_access_size = 4,
 185        .max_access_size = 4
 186    }
 187};
 188
 189static void timer_hit(void *opaque)
 190{
 191    struct xlx_timer *xt = opaque;
 192    struct timerblock *t = xt->parent;
 193    D(fprintf(stderr, "%s %d\n", __func__, xt->nr));
 194    xt->regs[R_TCSR] |= TCSR_TINT;
 195
 196    if (xt->regs[R_TCSR] & TCSR_ARHT)
 197        timer_enable(xt);
 198    timer_update_irq(t);
 199}
 200
 201static int xilinx_timer_init(SysBusDevice *dev)
 202{
 203    struct timerblock *t = FROM_SYSBUS(typeof (*t), dev);
 204    unsigned int i;
 205
 206    /* All timers share a single irq line.  */
 207    sysbus_init_irq(dev, &t->irq);
 208
 209    /* Init all the ptimers.  */
 210    t->timers = g_malloc0(sizeof t->timers[0] * num_timers(t));
 211    for (i = 0; i < num_timers(t); i++) {
 212        struct xlx_timer *xt = &t->timers[i];
 213
 214        xt->parent = t;
 215        xt->nr = i;
 216        xt->bh = qemu_bh_new(timer_hit, xt);
 217        xt->ptimer = ptimer_init(xt->bh);
 218        ptimer_set_freq(xt->ptimer, t->freq_hz);
 219    }
 220
 221    memory_region_init_io(&t->mmio, &timer_ops, t, "xlnx.xps-timer",
 222                          R_MAX * 4 * num_timers(t));
 223    sysbus_init_mmio(dev, &t->mmio);
 224    return 0;
 225}
 226
 227static Property xilinx_timer_properties[] = {
 228    DEFINE_PROP_UINT32("clock-frequency", struct timerblock, freq_hz,
 229                                                                62 * 1000000),
 230    DEFINE_PROP_UINT8("one-timer-only", struct timerblock, one_timer_only, 0),
 231    DEFINE_PROP_END_OF_LIST(),
 232};
 233
 234static void xilinx_timer_class_init(ObjectClass *klass, void *data)
 235{
 236    DeviceClass *dc = DEVICE_CLASS(klass);
 237    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 238
 239    k->init = xilinx_timer_init;
 240    dc->props = xilinx_timer_properties;
 241}
 242
 243static TypeInfo xilinx_timer_info = {
 244    .name          = "xlnx.xps-timer",
 245    .parent        = TYPE_SYS_BUS_DEVICE,
 246    .instance_size = sizeof(struct timerblock),
 247    .class_init    = xilinx_timer_class_init,
 248};
 249
 250static void xilinx_timer_register_types(void)
 251{
 252    type_register_static(&xilinx_timer_info);
 253}
 254
 255type_init(xilinx_timer_register_types)
 256