qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

imx_epit.c (10619B)


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