1a50c0d6fSJean-Christophe DUBOIS /* 2a50c0d6fSJean-Christophe DUBOIS * IMX EPIT Timer 3a50c0d6fSJean-Christophe DUBOIS * 4a50c0d6fSJean-Christophe DUBOIS * Copyright (c) 2008 OK Labs 5a50c0d6fSJean-Christophe DUBOIS * Copyright (c) 2011 NICTA Pty Ltd 6a50c0d6fSJean-Christophe DUBOIS * Originally written by Hans Jiang 7a50c0d6fSJean-Christophe DUBOIS * Updated by Peter Chubb 8951cd00eSJean-Christophe Dubois * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> 9a50c0d6fSJean-Christophe DUBOIS * 10a50c0d6fSJean-Christophe DUBOIS * This code is licensed under GPL version 2 or later. See 11a50c0d6fSJean-Christophe DUBOIS * the COPYING file in the top-level directory. 12a50c0d6fSJean-Christophe DUBOIS * 13a50c0d6fSJean-Christophe DUBOIS */ 14a50c0d6fSJean-Christophe DUBOIS 158ef94f0bSPeter Maydell #include "qemu/osdep.h" 16951cd00eSJean-Christophe Dubois #include "hw/timer/imx_epit.h" 17d6454270SMarkus Armbruster #include "migration/vmstate.h" 1864552b6bSMarkus Armbruster #include "hw/irq.h" 19951cd00eSJean-Christophe Dubois #include "hw/misc/imx_ccm.h" 200b8fa32fSMarkus Armbruster #include "qemu/module.h" 2103dd024fSPaolo Bonzini #include "qemu/log.h" 22a50c0d6fSJean-Christophe DUBOIS 234929f656SJean-Christophe Dubois #ifndef DEBUG_IMX_EPIT 244929f656SJean-Christophe Dubois #define DEBUG_IMX_EPIT 0 254929f656SJean-Christophe Dubois #endif 264929f656SJean-Christophe Dubois 274929f656SJean-Christophe Dubois #define DPRINTF(fmt, args...) \ 284929f656SJean-Christophe Dubois do { \ 294929f656SJean-Christophe Dubois if (DEBUG_IMX_EPIT) { \ 304929f656SJean-Christophe Dubois fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_EPIT, \ 314929f656SJean-Christophe Dubois __func__, ##args); \ 324929f656SJean-Christophe Dubois } \ 334929f656SJean-Christophe Dubois } while (0) 3495669e69SJean-Christophe DUBOIS 35d675765aSPeter Maydell static const char *imx_epit_reg_name(uint32_t reg) 3695669e69SJean-Christophe DUBOIS { 3795669e69SJean-Christophe DUBOIS switch (reg) { 3895669e69SJean-Christophe DUBOIS case 0: 3995669e69SJean-Christophe DUBOIS return "CR"; 4095669e69SJean-Christophe DUBOIS case 1: 4195669e69SJean-Christophe DUBOIS return "SR"; 4295669e69SJean-Christophe DUBOIS case 2: 4395669e69SJean-Christophe DUBOIS return "LR"; 4495669e69SJean-Christophe DUBOIS case 3: 4595669e69SJean-Christophe DUBOIS return "CMP"; 4695669e69SJean-Christophe DUBOIS case 4: 4795669e69SJean-Christophe DUBOIS return "CNT"; 4895669e69SJean-Christophe DUBOIS default: 4995669e69SJean-Christophe DUBOIS return "[?]"; 5095669e69SJean-Christophe DUBOIS } 5195669e69SJean-Christophe DUBOIS } 5295669e69SJean-Christophe DUBOIS 53a50c0d6fSJean-Christophe DUBOIS /* 54a50c0d6fSJean-Christophe DUBOIS * Exact clock frequencies vary from board to board. 55a50c0d6fSJean-Christophe DUBOIS * These are typical. 56a50c0d6fSJean-Christophe DUBOIS */ 5795669e69SJean-Christophe DUBOIS static const IMXClk imx_epit_clocks[] = { 58c91a5883SJean-Christophe Dubois CLK_NONE, /* 00 disabled */ 59aaa9ec3bSJean-Christophe Dubois CLK_IPG, /* 01 ipg_clk, ~532MHz */ 60d552f675SJean-Christophe Dubois CLK_IPG_HIGH, /* 10 ipg_clk_highfreq */ 61a50c0d6fSJean-Christophe DUBOIS CLK_32k, /* 11 ipg_clk_32k -- ~32kHz */ 62a50c0d6fSJean-Christophe DUBOIS }; 63a50c0d6fSJean-Christophe DUBOIS 64a50c0d6fSJean-Christophe DUBOIS /* 65a50c0d6fSJean-Christophe DUBOIS * Update interrupt status 66a50c0d6fSJean-Christophe DUBOIS */ 6795669e69SJean-Christophe DUBOIS static void imx_epit_update_int(IMXEPITState *s) 68a50c0d6fSJean-Christophe DUBOIS { 6995669e69SJean-Christophe DUBOIS if (s->sr && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) { 70a50c0d6fSJean-Christophe DUBOIS qemu_irq_raise(s->irq); 71a50c0d6fSJean-Christophe DUBOIS } else { 72a50c0d6fSJean-Christophe DUBOIS qemu_irq_lower(s->irq); 73a50c0d6fSJean-Christophe DUBOIS } 74a50c0d6fSJean-Christophe DUBOIS } 75a50c0d6fSJean-Christophe DUBOIS 76cc2722ecSPeter Maydell /* 77cc2722ecSPeter Maydell * Must be called from within a ptimer_transaction_begin/commit block 78cc2722ecSPeter Maydell * for both s->timer_cmp and s->timer_reload. 79cc2722ecSPeter Maydell */ 8095669e69SJean-Christophe DUBOIS static void imx_epit_set_freq(IMXEPITState *s) 81a50c0d6fSJean-Christophe DUBOIS { 8295669e69SJean-Christophe DUBOIS uint32_t clksrc; 8395669e69SJean-Christophe DUBOIS uint32_t prescaler; 84a50c0d6fSJean-Christophe DUBOIS 85a50c0d6fSJean-Christophe DUBOIS clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2); 86a50c0d6fSJean-Christophe DUBOIS prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12); 87a50c0d6fSJean-Christophe DUBOIS 88aaa9ec3bSJean-Christophe Dubois s->freq = imx_ccm_get_clock_frequency(s->ccm, 89aaa9ec3bSJean-Christophe Dubois imx_epit_clocks[clksrc]) / prescaler; 90a50c0d6fSJean-Christophe DUBOIS 91aaa9ec3bSJean-Christophe Dubois DPRINTF("Setting ptimer frequency to %u\n", s->freq); 9295669e69SJean-Christophe DUBOIS 93aaa9ec3bSJean-Christophe Dubois if (s->freq) { 94aaa9ec3bSJean-Christophe Dubois ptimer_set_freq(s->timer_reload, s->freq); 95aaa9ec3bSJean-Christophe Dubois ptimer_set_freq(s->timer_cmp, s->freq); 96a50c0d6fSJean-Christophe DUBOIS } 97a50c0d6fSJean-Christophe DUBOIS } 98a50c0d6fSJean-Christophe DUBOIS 99*b9c993aaSAxel Heider /* 100*b9c993aaSAxel Heider * This is called both on hardware (device) reset and software reset. 101*b9c993aaSAxel Heider */ 10295669e69SJean-Christophe DUBOIS static void imx_epit_reset(DeviceState *dev) 103a50c0d6fSJean-Christophe DUBOIS { 10495669e69SJean-Christophe DUBOIS IMXEPITState *s = IMX_EPIT(dev); 105a50c0d6fSJean-Christophe DUBOIS 106*b9c993aaSAxel Heider /* Soft reset doesn't touch some bits; hard reset clears them */ 10723005810SPeter Chubb s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN); 108a50c0d6fSJean-Christophe DUBOIS s->sr = 0; 109203d65a4SMichael Tokarev s->lr = EPIT_TIMER_MAX; 110a50c0d6fSJean-Christophe DUBOIS s->cmp = 0; 111a50c0d6fSJean-Christophe DUBOIS s->cnt = 0; 112cc2722ecSPeter Maydell ptimer_transaction_begin(s->timer_cmp); 113cc2722ecSPeter Maydell ptimer_transaction_begin(s->timer_reload); 114a50c0d6fSJean-Christophe DUBOIS /* stop both timers */ 115a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer_cmp); 116a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer_reload); 117a50c0d6fSJean-Christophe DUBOIS /* compute new frequency */ 11895669e69SJean-Christophe DUBOIS imx_epit_set_freq(s); 119203d65a4SMichael Tokarev /* init both timers to EPIT_TIMER_MAX */ 120203d65a4SMichael Tokarev ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1); 121203d65a4SMichael Tokarev ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1); 122a50c0d6fSJean-Christophe DUBOIS if (s->freq && (s->cr & CR_EN)) { 123a50c0d6fSJean-Christophe DUBOIS /* if the timer is still enabled, restart it */ 12423005810SPeter Chubb ptimer_run(s->timer_reload, 0); 125a50c0d6fSJean-Christophe DUBOIS } 126cc2722ecSPeter Maydell ptimer_transaction_commit(s->timer_cmp); 127cc2722ecSPeter Maydell ptimer_transaction_commit(s->timer_reload); 128a50c0d6fSJean-Christophe DUBOIS } 129a50c0d6fSJean-Christophe DUBOIS 13095669e69SJean-Christophe DUBOIS static uint32_t imx_epit_update_count(IMXEPITState *s) 131a50c0d6fSJean-Christophe DUBOIS { 132a50c0d6fSJean-Christophe DUBOIS s->cnt = ptimer_get_count(s->timer_reload); 133a50c0d6fSJean-Christophe DUBOIS 134a50c0d6fSJean-Christophe DUBOIS return s->cnt; 135a50c0d6fSJean-Christophe DUBOIS } 136a50c0d6fSJean-Christophe DUBOIS 13795669e69SJean-Christophe DUBOIS static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size) 138a50c0d6fSJean-Christophe DUBOIS { 13995669e69SJean-Christophe DUBOIS IMXEPITState *s = IMX_EPIT(opaque); 14095669e69SJean-Christophe DUBOIS uint32_t reg_value = 0; 141a50c0d6fSJean-Christophe DUBOIS 1424929f656SJean-Christophe Dubois switch (offset >> 2) { 143a50c0d6fSJean-Christophe DUBOIS case 0: /* Control Register */ 14495669e69SJean-Christophe DUBOIS reg_value = s->cr; 14595669e69SJean-Christophe DUBOIS break; 146a50c0d6fSJean-Christophe DUBOIS 147a50c0d6fSJean-Christophe DUBOIS case 1: /* Status Register */ 14895669e69SJean-Christophe DUBOIS reg_value = s->sr; 14995669e69SJean-Christophe DUBOIS break; 150a50c0d6fSJean-Christophe DUBOIS 151a50c0d6fSJean-Christophe DUBOIS case 2: /* LR - ticks*/ 15295669e69SJean-Christophe DUBOIS reg_value = s->lr; 15395669e69SJean-Christophe DUBOIS break; 154a50c0d6fSJean-Christophe DUBOIS 155a50c0d6fSJean-Christophe DUBOIS case 3: /* CMP */ 15695669e69SJean-Christophe DUBOIS reg_value = s->cmp; 15795669e69SJean-Christophe DUBOIS break; 158a50c0d6fSJean-Christophe DUBOIS 159a50c0d6fSJean-Christophe DUBOIS case 4: /* CNT */ 16095669e69SJean-Christophe DUBOIS imx_epit_update_count(s); 16195669e69SJean-Christophe DUBOIS reg_value = s->cnt; 16295669e69SJean-Christophe DUBOIS break; 16395669e69SJean-Christophe DUBOIS 16495669e69SJean-Christophe DUBOIS default: 1654929f656SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" 1664929f656SJean-Christophe Dubois HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset); 16795669e69SJean-Christophe DUBOIS break; 168a50c0d6fSJean-Christophe DUBOIS } 169a50c0d6fSJean-Christophe DUBOIS 1704929f656SJean-Christophe Dubois DPRINTF("(%s) = 0x%08x\n", imx_epit_reg_name(offset >> 2), reg_value); 17195669e69SJean-Christophe DUBOIS 17295669e69SJean-Christophe DUBOIS return reg_value; 173a50c0d6fSJean-Christophe DUBOIS } 174a50c0d6fSJean-Christophe DUBOIS 175cc2722ecSPeter Maydell /* Must be called from ptimer_transaction_begin/commit block for s->timer_cmp */ 17695669e69SJean-Christophe DUBOIS static void imx_epit_reload_compare_timer(IMXEPITState *s) 177a50c0d6fSJean-Christophe DUBOIS { 17823005810SPeter Chubb if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN)) { 17923005810SPeter Chubb /* if the compare feature is on and timers are running */ 18095669e69SJean-Christophe DUBOIS uint32_t tmp = imx_epit_update_count(s); 18123005810SPeter Chubb uint64_t next; 182a50c0d6fSJean-Christophe DUBOIS if (tmp > s->cmp) { 18323005810SPeter Chubb /* It'll fire in this round of the timer */ 18423005810SPeter Chubb next = tmp - s->cmp; 18523005810SPeter Chubb } else { /* catch it next time around */ 186203d65a4SMichael Tokarev next = tmp - s->cmp + ((s->cr & CR_RLD) ? EPIT_TIMER_MAX : s->lr); 187a50c0d6fSJean-Christophe DUBOIS } 18823005810SPeter Chubb ptimer_set_count(s->timer_cmp, next); 189a50c0d6fSJean-Christophe DUBOIS } 190a50c0d6fSJean-Christophe DUBOIS } 191a50c0d6fSJean-Christophe DUBOIS 19295669e69SJean-Christophe DUBOIS static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, 19395669e69SJean-Christophe DUBOIS unsigned size) 194a50c0d6fSJean-Christophe DUBOIS { 19595669e69SJean-Christophe DUBOIS IMXEPITState *s = IMX_EPIT(opaque); 19623005810SPeter Chubb uint64_t oldcr; 197a50c0d6fSJean-Christophe DUBOIS 1984929f656SJean-Christophe Dubois DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2), 1994929f656SJean-Christophe Dubois (uint32_t)value); 20095669e69SJean-Christophe DUBOIS 2014929f656SJean-Christophe Dubois switch (offset >> 2) { 202a50c0d6fSJean-Christophe DUBOIS case 0: /* CR */ 20323005810SPeter Chubb 20423005810SPeter Chubb oldcr = s->cr; 205a50c0d6fSJean-Christophe DUBOIS s->cr = value & 0x03ffffff; 206a50c0d6fSJean-Christophe DUBOIS if (s->cr & CR_SWR) { 207a50c0d6fSJean-Christophe DUBOIS /* handle the reset */ 20895669e69SJean-Christophe DUBOIS imx_epit_reset(DEVICE(s)); 20913557fd3SPeter Maydell /* 21013557fd3SPeter Maydell * TODO: could we 'break' here? following operations appear 21113557fd3SPeter Maydell * to duplicate the work imx_epit_reset() already did. 21213557fd3SPeter Maydell */ 21313557fd3SPeter Maydell } 21413557fd3SPeter Maydell 21513557fd3SPeter Maydell ptimer_transaction_begin(s->timer_cmp); 21613557fd3SPeter Maydell ptimer_transaction_begin(s->timer_reload); 21713557fd3SPeter Maydell 218*b9c993aaSAxel Heider /* Update the frequency. Has been done already in case of a reset. */ 21913557fd3SPeter Maydell if (!(s->cr & CR_SWR)) { 22095669e69SJean-Christophe DUBOIS imx_epit_set_freq(s); 221a50c0d6fSJean-Christophe DUBOIS } 222a50c0d6fSJean-Christophe DUBOIS 22323005810SPeter Chubb if (s->freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) { 224a50c0d6fSJean-Christophe DUBOIS if (s->cr & CR_ENMOD) { 225a50c0d6fSJean-Christophe DUBOIS if (s->cr & CR_RLD) { 226a50c0d6fSJean-Christophe DUBOIS ptimer_set_limit(s->timer_reload, s->lr, 1); 22723005810SPeter Chubb ptimer_set_limit(s->timer_cmp, s->lr, 1); 228a50c0d6fSJean-Christophe DUBOIS } else { 229203d65a4SMichael Tokarev ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1); 230203d65a4SMichael Tokarev ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1); 231a50c0d6fSJean-Christophe DUBOIS } 232a50c0d6fSJean-Christophe DUBOIS } 233a50c0d6fSJean-Christophe DUBOIS 23495669e69SJean-Christophe DUBOIS imx_epit_reload_compare_timer(s); 23523005810SPeter Chubb ptimer_run(s->timer_reload, 0); 23623005810SPeter Chubb if (s->cr & CR_OCIEN) { 23723005810SPeter Chubb ptimer_run(s->timer_cmp, 0); 238a50c0d6fSJean-Christophe DUBOIS } else { 23923005810SPeter Chubb ptimer_stop(s->timer_cmp); 24023005810SPeter Chubb } 24123005810SPeter Chubb } else if (!(s->cr & CR_EN)) { 242a50c0d6fSJean-Christophe DUBOIS /* stop both timers */ 243a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer_reload); 244a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer_cmp); 24523005810SPeter Chubb } else if (s->cr & CR_OCIEN) { 24623005810SPeter Chubb if (!(oldcr & CR_OCIEN)) { 24723005810SPeter Chubb imx_epit_reload_compare_timer(s); 24823005810SPeter Chubb ptimer_run(s->timer_cmp, 0); 24923005810SPeter Chubb } 25023005810SPeter Chubb } else { 25123005810SPeter Chubb ptimer_stop(s->timer_cmp); 252a50c0d6fSJean-Christophe DUBOIS } 253cc2722ecSPeter Maydell 254cc2722ecSPeter Maydell ptimer_transaction_commit(s->timer_cmp); 255cc2722ecSPeter Maydell ptimer_transaction_commit(s->timer_reload); 256a50c0d6fSJean-Christophe DUBOIS break; 257a50c0d6fSJean-Christophe DUBOIS 258a50c0d6fSJean-Christophe DUBOIS case 1: /* SR - ACK*/ 259*b9c993aaSAxel Heider /* writing 1 to OCIF clears the OCIF bit */ 260a50c0d6fSJean-Christophe DUBOIS if (value & 0x01) { 261a50c0d6fSJean-Christophe DUBOIS s->sr = 0; 26295669e69SJean-Christophe DUBOIS imx_epit_update_int(s); 263a50c0d6fSJean-Christophe DUBOIS } 264a50c0d6fSJean-Christophe DUBOIS break; 265a50c0d6fSJean-Christophe DUBOIS 266a50c0d6fSJean-Christophe DUBOIS case 2: /* LR - set ticks */ 267a50c0d6fSJean-Christophe DUBOIS s->lr = value; 268a50c0d6fSJean-Christophe DUBOIS 269cc2722ecSPeter Maydell ptimer_transaction_begin(s->timer_cmp); 270cc2722ecSPeter Maydell ptimer_transaction_begin(s->timer_reload); 271a50c0d6fSJean-Christophe DUBOIS if (s->cr & CR_RLD) { 272a50c0d6fSJean-Christophe DUBOIS /* Also set the limit if the LRD bit is set */ 273a50c0d6fSJean-Christophe DUBOIS /* If IOVW bit is set then set the timer value */ 274a50c0d6fSJean-Christophe DUBOIS ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW); 27523005810SPeter Chubb ptimer_set_limit(s->timer_cmp, s->lr, 0); 276a50c0d6fSJean-Christophe DUBOIS } else if (s->cr & CR_IOVW) { 277a50c0d6fSJean-Christophe DUBOIS /* If IOVW bit is set then set the timer value */ 278a50c0d6fSJean-Christophe DUBOIS ptimer_set_count(s->timer_reload, s->lr); 279a50c0d6fSJean-Christophe DUBOIS } 2807719419dSAxel Heider /* 2817719419dSAxel Heider * Commit the change to s->timer_reload, so it can propagate. Otherwise 2827719419dSAxel Heider * the timer interrupt may not fire properly. The commit must happen 2837719419dSAxel Heider * before calling imx_epit_reload_compare_timer(), which reads 2847719419dSAxel Heider * s->timer_reload internally again. 2857719419dSAxel Heider */ 2867719419dSAxel Heider ptimer_transaction_commit(s->timer_reload); 28795669e69SJean-Christophe DUBOIS imx_epit_reload_compare_timer(s); 288cc2722ecSPeter Maydell ptimer_transaction_commit(s->timer_cmp); 289a50c0d6fSJean-Christophe DUBOIS break; 290a50c0d6fSJean-Christophe DUBOIS 291a50c0d6fSJean-Christophe DUBOIS case 3: /* CMP */ 292a50c0d6fSJean-Christophe DUBOIS s->cmp = value; 293a50c0d6fSJean-Christophe DUBOIS 294cc2722ecSPeter Maydell ptimer_transaction_begin(s->timer_cmp); 29595669e69SJean-Christophe DUBOIS imx_epit_reload_compare_timer(s); 296cc2722ecSPeter Maydell ptimer_transaction_commit(s->timer_cmp); 297a50c0d6fSJean-Christophe DUBOIS 298a50c0d6fSJean-Christophe DUBOIS break; 299a50c0d6fSJean-Christophe DUBOIS 300a50c0d6fSJean-Christophe DUBOIS default: 3014929f656SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" 3024929f656SJean-Christophe Dubois HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset); 30395669e69SJean-Christophe DUBOIS 30495669e69SJean-Christophe DUBOIS break; 305a50c0d6fSJean-Christophe DUBOIS } 306a50c0d6fSJean-Christophe DUBOIS } 30795669e69SJean-Christophe DUBOIS static void imx_epit_cmp(void *opaque) 308a50c0d6fSJean-Christophe DUBOIS { 30995669e69SJean-Christophe DUBOIS IMXEPITState *s = IMX_EPIT(opaque); 310a50c0d6fSJean-Christophe DUBOIS 31123005810SPeter Chubb DPRINTF("sr was %d\n", s->sr); 312a50c0d6fSJean-Christophe DUBOIS 313a50c0d6fSJean-Christophe DUBOIS s->sr = 1; 31495669e69SJean-Christophe DUBOIS imx_epit_update_int(s); 315a50c0d6fSJean-Christophe DUBOIS } 316a50c0d6fSJean-Christophe DUBOIS 317cc2722ecSPeter Maydell static void imx_epit_reload(void *opaque) 318cc2722ecSPeter Maydell { 319cc2722ecSPeter Maydell /* No action required on rollover of timer_reload */ 320cc2722ecSPeter Maydell } 321cc2722ecSPeter Maydell 32295669e69SJean-Christophe DUBOIS static const MemoryRegionOps imx_epit_ops = { 32395669e69SJean-Christophe DUBOIS .read = imx_epit_read, 32495669e69SJean-Christophe DUBOIS .write = imx_epit_write, 325a50c0d6fSJean-Christophe DUBOIS .endianness = DEVICE_NATIVE_ENDIAN, 326a50c0d6fSJean-Christophe DUBOIS }; 327a50c0d6fSJean-Christophe DUBOIS 32895669e69SJean-Christophe DUBOIS static const VMStateDescription vmstate_imx_timer_epit = { 329565328fcSJean-Christophe Dubois .name = TYPE_IMX_EPIT, 330a50c0d6fSJean-Christophe DUBOIS .version_id = 2, 331a50c0d6fSJean-Christophe DUBOIS .minimum_version_id = 2, 332a50c0d6fSJean-Christophe DUBOIS .fields = (VMStateField[]) { 33395669e69SJean-Christophe DUBOIS VMSTATE_UINT32(cr, IMXEPITState), 33495669e69SJean-Christophe DUBOIS VMSTATE_UINT32(sr, IMXEPITState), 33595669e69SJean-Christophe DUBOIS VMSTATE_UINT32(lr, IMXEPITState), 33695669e69SJean-Christophe DUBOIS VMSTATE_UINT32(cmp, IMXEPITState), 33795669e69SJean-Christophe DUBOIS VMSTATE_UINT32(cnt, IMXEPITState), 33895669e69SJean-Christophe DUBOIS VMSTATE_UINT32(freq, IMXEPITState), 33995669e69SJean-Christophe DUBOIS VMSTATE_PTIMER(timer_reload, IMXEPITState), 34095669e69SJean-Christophe DUBOIS VMSTATE_PTIMER(timer_cmp, IMXEPITState), 341a50c0d6fSJean-Christophe DUBOIS VMSTATE_END_OF_LIST() 342a50c0d6fSJean-Christophe DUBOIS } 343a50c0d6fSJean-Christophe DUBOIS }; 344a50c0d6fSJean-Christophe DUBOIS 34595669e69SJean-Christophe DUBOIS static void imx_epit_realize(DeviceState *dev, Error **errp) 346a50c0d6fSJean-Christophe DUBOIS { 34795669e69SJean-Christophe DUBOIS IMXEPITState *s = IMX_EPIT(dev); 34895669e69SJean-Christophe DUBOIS SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 349a50c0d6fSJean-Christophe DUBOIS 35095669e69SJean-Christophe DUBOIS DPRINTF("\n"); 351a50c0d6fSJean-Christophe DUBOIS 35295669e69SJean-Christophe DUBOIS sysbus_init_irq(sbd, &s->irq); 353853dca12SPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &imx_epit_ops, s, TYPE_IMX_EPIT, 35495669e69SJean-Christophe DUBOIS 0x00001000); 35595669e69SJean-Christophe DUBOIS sysbus_init_mmio(sbd, &s->iomem); 35695669e69SJean-Christophe DUBOIS 357*b9c993aaSAxel Heider /* 358*b9c993aaSAxel Heider * The reload timer keeps running when the peripheral is enabled. It is a 359*b9c993aaSAxel Heider * kind of wall clock that does not generate any interrupts. The callback 360*b9c993aaSAxel Heider * needs to be provided, but it does nothing as the ptimer already supports 361*b9c993aaSAxel Heider * all necessary reloading functionality. 362*b9c993aaSAxel Heider */ 3639598c1bbSPeter Maydell s->timer_reload = ptimer_init(imx_epit_reload, s, PTIMER_POLICY_LEGACY); 364a50c0d6fSJean-Christophe DUBOIS 365*b9c993aaSAxel Heider /* 366*b9c993aaSAxel Heider * The compare timer is running only when the peripheral configuration is 367*b9c993aaSAxel Heider * in a state that will generate compare interrupts. 368*b9c993aaSAxel Heider */ 3699598c1bbSPeter Maydell s->timer_cmp = ptimer_init(imx_epit_cmp, s, PTIMER_POLICY_LEGACY); 370a50c0d6fSJean-Christophe DUBOIS } 371a50c0d6fSJean-Christophe DUBOIS 37295669e69SJean-Christophe DUBOIS static void imx_epit_class_init(ObjectClass *klass, void *data) 373a50c0d6fSJean-Christophe DUBOIS { 374a50c0d6fSJean-Christophe DUBOIS DeviceClass *dc = DEVICE_CLASS(klass); 37595669e69SJean-Christophe DUBOIS 37695669e69SJean-Christophe DUBOIS dc->realize = imx_epit_realize; 37795669e69SJean-Christophe DUBOIS dc->reset = imx_epit_reset; 37895669e69SJean-Christophe DUBOIS dc->vmsd = &vmstate_imx_timer_epit; 379a50c0d6fSJean-Christophe DUBOIS dc->desc = "i.MX periodic timer"; 380a50c0d6fSJean-Christophe DUBOIS } 381a50c0d6fSJean-Christophe DUBOIS 38295669e69SJean-Christophe DUBOIS static const TypeInfo imx_epit_info = { 38395669e69SJean-Christophe DUBOIS .name = TYPE_IMX_EPIT, 384a50c0d6fSJean-Christophe DUBOIS .parent = TYPE_SYS_BUS_DEVICE, 38595669e69SJean-Christophe DUBOIS .instance_size = sizeof(IMXEPITState), 38695669e69SJean-Christophe DUBOIS .class_init = imx_epit_class_init, 387a50c0d6fSJean-Christophe DUBOIS }; 388a50c0d6fSJean-Christophe DUBOIS 38995669e69SJean-Christophe DUBOIS static void imx_epit_register_types(void) 390a50c0d6fSJean-Christophe DUBOIS { 39195669e69SJean-Christophe DUBOIS type_register_static(&imx_epit_info); 392a50c0d6fSJean-Christophe DUBOIS } 393a50c0d6fSJean-Christophe DUBOIS 39495669e69SJean-Christophe DUBOIS type_init(imx_epit_register_types) 395