qemu/hw/timer/imx_epit.c
<<
>>
Prefs
   1/*
   2 * IMX EPIT Timer
   3 *
   4 * Copyright (c) 2008 OK Labs
   5 * Copyright (c) 2011 NICTA Pty Ltd
   6 * Originally written by Hans Jiang
   7 * Updated by Peter Chubb
   8 * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
   9 *
  10 * This code is licensed under GPL version 2 or later.  See
  11 * the COPYING file in the top-level directory.
  12 *
  13 */
  14
  15#include "qemu/osdep.h"
  16#include "hw/timer/imx_epit.h"
  17#include "hw/misc/imx_ccm.h"
  18#include "qemu/main-loop.h"
  19#include "qemu/module.h"
  20#include "qemu/log.h"
  21
  22#ifndef DEBUG_IMX_EPIT
  23#define DEBUG_IMX_EPIT 0
  24#endif
  25
  26#define DPRINTF(fmt, args...) \
  27    do { \
  28        if (DEBUG_IMX_EPIT) { \
  29            fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_EPIT, \
  30                                             __func__, ##args); \
  31        } \
  32    } while (0)
  33
  34static const char *imx_epit_reg_name(uint32_t reg)
  35{
  36    switch (reg) {
  37    case 0:
  38        return "CR";
  39    case 1:
  40        return "SR";
  41    case 2:
  42        return "LR";
  43    case 3:
  44        return "CMP";
  45    case 4:
  46        return "CNT";
  47    default:
  48        return "[?]";
  49    }
  50}
  51
  52/*
  53 * Exact clock frequencies vary from board to board.
  54 * These are typical.
  55 */
  56static const IMXClk imx_epit_clocks[] =  {
  57    CLK_NONE,      /* 00 disabled */
  58    CLK_IPG,       /* 01 ipg_clk, ~532MHz */
  59    CLK_IPG_HIGH,  /* 10 ipg_clk_highfreq */
  60    CLK_32k,       /* 11 ipg_clk_32k -- ~32kHz */
  61};
  62
  63/*
  64 * Update interrupt status
  65 */
  66static void imx_epit_update_int(IMXEPITState *s)
  67{
  68    if (s->sr && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) {
  69        qemu_irq_raise(s->irq);
  70    } else {
  71        qemu_irq_lower(s->irq);
  72    }
  73}
  74
  75static void imx_epit_set_freq(IMXEPITState *s)
  76{
  77    uint32_t clksrc;
  78    uint32_t prescaler;
  79
  80    clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2);
  81    prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12);
  82
  83    s->freq = imx_ccm_get_clock_frequency(s->ccm,
  84                                imx_epit_clocks[clksrc]) / prescaler;
  85
  86    DPRINTF("Setting ptimer frequency to %u\n", s->freq);
  87
  88    if (s->freq) {
  89        ptimer_set_freq(s->timer_reload, s->freq);
  90        ptimer_set_freq(s->timer_cmp, s->freq);
  91    }
  92}
  93
  94static void imx_epit_reset(DeviceState *dev)
  95{
  96    IMXEPITState *s = IMX_EPIT(dev);
  97
  98    /*
  99     * Soft reset doesn't touch some bits; hard reset clears them
 100     */
 101    s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
 102    s->sr = 0;
 103    s->lr = EPIT_TIMER_MAX;
 104    s->cmp = 0;
 105    s->cnt = 0;
 106    /* stop both timers */
 107    ptimer_stop(s->timer_cmp);
 108    ptimer_stop(s->timer_reload);
 109    /* compute new frequency */
 110    imx_epit_set_freq(s);
 111    /* init both timers to EPIT_TIMER_MAX */
 112    ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
 113    ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
 114    if (s->freq && (s->cr & CR_EN)) {
 115        /* if the timer is still enabled, restart it */
 116        ptimer_run(s->timer_reload, 0);
 117    }
 118}
 119
 120static uint32_t imx_epit_update_count(IMXEPITState *s)
 121{
 122    s->cnt = ptimer_get_count(s->timer_reload);
 123
 124    return s->cnt;
 125}
 126
 127static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
 128{
 129    IMXEPITState *s = IMX_EPIT(opaque);
 130    uint32_t reg_value = 0;
 131
 132    switch (offset >> 2) {
 133    case 0: /* Control Register */
 134        reg_value = s->cr;
 135        break;
 136
 137    case 1: /* Status Register */
 138        reg_value = s->sr;
 139        break;
 140
 141    case 2: /* LR - ticks*/
 142        reg_value = s->lr;
 143        break;
 144
 145    case 3: /* CMP */
 146        reg_value = s->cmp;
 147        break;
 148
 149    case 4: /* CNT */
 150        imx_epit_update_count(s);
 151        reg_value = s->cnt;
 152        break;
 153
 154    default:
 155        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
 156                      HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset);
 157        break;
 158    }
 159
 160    DPRINTF("(%s) = 0x%08x\n", imx_epit_reg_name(offset >> 2), reg_value);
 161
 162    return reg_value;
 163}
 164
 165static void imx_epit_reload_compare_timer(IMXEPITState *s)
 166{
 167    if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN))  {
 168        /* if the compare feature is on and timers are running */
 169        uint32_t tmp = imx_epit_update_count(s);
 170        uint64_t next;
 171        if (tmp > s->cmp) {
 172            /* It'll fire in this round of the timer */
 173            next = tmp - s->cmp;
 174        } else { /* catch it next time around */
 175            next = tmp - s->cmp + ((s->cr & CR_RLD) ? EPIT_TIMER_MAX : s->lr);
 176        }
 177        ptimer_set_count(s->timer_cmp, next);
 178    }
 179}
 180
 181static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
 182                           unsigned size)
 183{
 184    IMXEPITState *s = IMX_EPIT(opaque);
 185    uint64_t oldcr;
 186
 187    DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2),
 188            (uint32_t)value);
 189
 190    switch (offset >> 2) {
 191    case 0: /* CR */
 192
 193        oldcr = s->cr;
 194        s->cr = value & 0x03ffffff;
 195        if (s->cr & CR_SWR) {
 196            /* handle the reset */
 197            imx_epit_reset(DEVICE(s));
 198        } else {
 199            imx_epit_set_freq(s);
 200        }
 201
 202        if (s->freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) {
 203            if (s->cr & CR_ENMOD) {
 204                if (s->cr & CR_RLD) {
 205                    ptimer_set_limit(s->timer_reload, s->lr, 1);
 206                    ptimer_set_limit(s->timer_cmp, s->lr, 1);
 207                } else {
 208                    ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
 209                    ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
 210                }
 211            }
 212
 213            imx_epit_reload_compare_timer(s);
 214            ptimer_run(s->timer_reload, 0);
 215            if (s->cr & CR_OCIEN) {
 216                ptimer_run(s->timer_cmp, 0);
 217            } else {
 218                ptimer_stop(s->timer_cmp);
 219            }
 220        } else if (!(s->cr & CR_EN)) {
 221            /* stop both timers */
 222            ptimer_stop(s->timer_reload);
 223            ptimer_stop(s->timer_cmp);
 224        } else  if (s->cr & CR_OCIEN) {
 225            if (!(oldcr & CR_OCIEN)) {
 226                imx_epit_reload_compare_timer(s);
 227                ptimer_run(s->timer_cmp, 0);
 228            }
 229        } else {
 230            ptimer_stop(s->timer_cmp);
 231        }
 232        break;
 233
 234    case 1: /* SR - ACK*/
 235        /* writing 1 to OCIF clear the OCIF bit */
 236        if (value & 0x01) {
 237            s->sr = 0;
 238            imx_epit_update_int(s);
 239        }
 240        break;
 241
 242    case 2: /* LR - set ticks */
 243        s->lr = value;
 244
 245        if (s->cr & CR_RLD) {
 246            /* Also set the limit if the LRD bit is set */
 247            /* If IOVW bit is set then set the timer value */
 248            ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW);
 249            ptimer_set_limit(s->timer_cmp, s->lr, 0);
 250        } else if (s->cr & CR_IOVW) {
 251            /* If IOVW bit is set then set the timer value */
 252            ptimer_set_count(s->timer_reload, s->lr);
 253        }
 254
 255        imx_epit_reload_compare_timer(s);
 256        break;
 257
 258    case 3: /* CMP */
 259        s->cmp = value;
 260
 261        imx_epit_reload_compare_timer(s);
 262
 263        break;
 264
 265    default:
 266        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
 267                      HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset);
 268
 269        break;
 270    }
 271}
 272static void imx_epit_cmp(void *opaque)
 273{
 274    IMXEPITState *s = IMX_EPIT(opaque);
 275
 276    DPRINTF("sr was %d\n", s->sr);
 277
 278    s->sr = 1;
 279    imx_epit_update_int(s);
 280}
 281
 282static const MemoryRegionOps imx_epit_ops = {
 283    .read = imx_epit_read,
 284    .write = imx_epit_write,
 285    .endianness = DEVICE_NATIVE_ENDIAN,
 286};
 287
 288static const VMStateDescription vmstate_imx_timer_epit = {
 289    .name = TYPE_IMX_EPIT,
 290    .version_id = 2,
 291    .minimum_version_id = 2,
 292    .fields = (VMStateField[]) {
 293        VMSTATE_UINT32(cr, IMXEPITState),
 294        VMSTATE_UINT32(sr, IMXEPITState),
 295        VMSTATE_UINT32(lr, IMXEPITState),
 296        VMSTATE_UINT32(cmp, IMXEPITState),
 297        VMSTATE_UINT32(cnt, IMXEPITState),
 298        VMSTATE_UINT32(freq, IMXEPITState),
 299        VMSTATE_PTIMER(timer_reload, IMXEPITState),
 300        VMSTATE_PTIMER(timer_cmp, IMXEPITState),
 301        VMSTATE_END_OF_LIST()
 302    }
 303};
 304
 305static void imx_epit_realize(DeviceState *dev, Error **errp)
 306{
 307    IMXEPITState *s = IMX_EPIT(dev);
 308    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 309    QEMUBH *bh;
 310
 311    DPRINTF("\n");
 312
 313    sysbus_init_irq(sbd, &s->irq);
 314    memory_region_init_io(&s->iomem, OBJECT(s), &imx_epit_ops, s, TYPE_IMX_EPIT,
 315                          0x00001000);
 316    sysbus_init_mmio(sbd, &s->iomem);
 317
 318    s->timer_reload = ptimer_init(NULL, PTIMER_POLICY_DEFAULT);
 319
 320    bh = qemu_bh_new(imx_epit_cmp, s);
 321    s->timer_cmp = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
 322}
 323
 324static void imx_epit_class_init(ObjectClass *klass, void *data)
 325{
 326    DeviceClass *dc  = DEVICE_CLASS(klass);
 327
 328    dc->realize = imx_epit_realize;
 329    dc->reset = imx_epit_reset;
 330    dc->vmsd = &vmstate_imx_timer_epit;
 331    dc->desc = "i.MX periodic timer";
 332}
 333
 334static const TypeInfo imx_epit_info = {
 335    .name = TYPE_IMX_EPIT,
 336    .parent = TYPE_SYS_BUS_DEVICE,
 337    .instance_size = sizeof(IMXEPITState),
 338    .class_init = imx_epit_class_init,
 339};
 340
 341static void imx_epit_register_types(void)
 342{
 343    type_register_static(&imx_epit_info);
 344}
 345
 346type_init(imx_epit_register_types)
 347