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