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 9995669e69SJean-Christophe DUBOIS static void imx_epit_reset(DeviceState *dev) 100a50c0d6fSJean-Christophe DUBOIS { 10195669e69SJean-Christophe DUBOIS IMXEPITState *s = IMX_EPIT(dev); 102a50c0d6fSJean-Christophe DUBOIS 103a50c0d6fSJean-Christophe DUBOIS /* 104a50c0d6fSJean-Christophe DUBOIS * Soft reset doesn't touch some bits; hard reset clears them 105a50c0d6fSJean-Christophe DUBOIS */ 10623005810SPeter Chubb s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN); 107a50c0d6fSJean-Christophe DUBOIS s->sr = 0; 108203d65a4SMichael Tokarev s->lr = EPIT_TIMER_MAX; 109a50c0d6fSJean-Christophe DUBOIS s->cmp = 0; 110a50c0d6fSJean-Christophe DUBOIS s->cnt = 0; 111cc2722ecSPeter Maydell ptimer_transaction_begin(s->timer_cmp); 112cc2722ecSPeter Maydell ptimer_transaction_begin(s->timer_reload); 113a50c0d6fSJean-Christophe DUBOIS /* stop both timers */ 114a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer_cmp); 115a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer_reload); 116a50c0d6fSJean-Christophe DUBOIS /* compute new frequency */ 11795669e69SJean-Christophe DUBOIS imx_epit_set_freq(s); 118203d65a4SMichael Tokarev /* init both timers to EPIT_TIMER_MAX */ 119203d65a4SMichael Tokarev ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1); 120203d65a4SMichael Tokarev ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1); 121a50c0d6fSJean-Christophe DUBOIS if (s->freq && (s->cr & CR_EN)) { 122a50c0d6fSJean-Christophe DUBOIS /* if the timer is still enabled, restart it */ 12323005810SPeter Chubb ptimer_run(s->timer_reload, 0); 124a50c0d6fSJean-Christophe DUBOIS } 125cc2722ecSPeter Maydell ptimer_transaction_commit(s->timer_cmp); 126cc2722ecSPeter Maydell ptimer_transaction_commit(s->timer_reload); 127a50c0d6fSJean-Christophe DUBOIS } 128a50c0d6fSJean-Christophe DUBOIS 12995669e69SJean-Christophe DUBOIS static uint32_t imx_epit_update_count(IMXEPITState *s) 130a50c0d6fSJean-Christophe DUBOIS { 131a50c0d6fSJean-Christophe DUBOIS s->cnt = ptimer_get_count(s->timer_reload); 132a50c0d6fSJean-Christophe DUBOIS 133a50c0d6fSJean-Christophe DUBOIS return s->cnt; 134a50c0d6fSJean-Christophe DUBOIS } 135a50c0d6fSJean-Christophe DUBOIS 13695669e69SJean-Christophe DUBOIS static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size) 137a50c0d6fSJean-Christophe DUBOIS { 13895669e69SJean-Christophe DUBOIS IMXEPITState *s = IMX_EPIT(opaque); 13995669e69SJean-Christophe DUBOIS uint32_t reg_value = 0; 140a50c0d6fSJean-Christophe DUBOIS 1414929f656SJean-Christophe Dubois switch (offset >> 2) { 142a50c0d6fSJean-Christophe DUBOIS case 0: /* Control Register */ 14395669e69SJean-Christophe DUBOIS reg_value = s->cr; 14495669e69SJean-Christophe DUBOIS break; 145a50c0d6fSJean-Christophe DUBOIS 146a50c0d6fSJean-Christophe DUBOIS case 1: /* Status Register */ 14795669e69SJean-Christophe DUBOIS reg_value = s->sr; 14895669e69SJean-Christophe DUBOIS break; 149a50c0d6fSJean-Christophe DUBOIS 150a50c0d6fSJean-Christophe DUBOIS case 2: /* LR - ticks*/ 15195669e69SJean-Christophe DUBOIS reg_value = s->lr; 15295669e69SJean-Christophe DUBOIS break; 153a50c0d6fSJean-Christophe DUBOIS 154a50c0d6fSJean-Christophe DUBOIS case 3: /* CMP */ 15595669e69SJean-Christophe DUBOIS reg_value = s->cmp; 15695669e69SJean-Christophe DUBOIS break; 157a50c0d6fSJean-Christophe DUBOIS 158a50c0d6fSJean-Christophe DUBOIS case 4: /* CNT */ 15995669e69SJean-Christophe DUBOIS imx_epit_update_count(s); 16095669e69SJean-Christophe DUBOIS reg_value = s->cnt; 16195669e69SJean-Christophe DUBOIS break; 16295669e69SJean-Christophe DUBOIS 16395669e69SJean-Christophe DUBOIS default: 1644929f656SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" 1654929f656SJean-Christophe Dubois HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset); 16695669e69SJean-Christophe DUBOIS break; 167a50c0d6fSJean-Christophe DUBOIS } 168a50c0d6fSJean-Christophe DUBOIS 1694929f656SJean-Christophe Dubois DPRINTF("(%s) = 0x%08x\n", imx_epit_reg_name(offset >> 2), reg_value); 17095669e69SJean-Christophe DUBOIS 17195669e69SJean-Christophe DUBOIS return reg_value; 172a50c0d6fSJean-Christophe DUBOIS } 173a50c0d6fSJean-Christophe DUBOIS 174cc2722ecSPeter Maydell /* Must be called from ptimer_transaction_begin/commit block for s->timer_cmp */ 17595669e69SJean-Christophe DUBOIS static void imx_epit_reload_compare_timer(IMXEPITState *s) 176a50c0d6fSJean-Christophe DUBOIS { 17723005810SPeter Chubb if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN)) { 17823005810SPeter Chubb /* if the compare feature is on and timers are running */ 17995669e69SJean-Christophe DUBOIS uint32_t tmp = imx_epit_update_count(s); 18023005810SPeter Chubb uint64_t next; 181a50c0d6fSJean-Christophe DUBOIS if (tmp > s->cmp) { 18223005810SPeter Chubb /* It'll fire in this round of the timer */ 18323005810SPeter Chubb next = tmp - s->cmp; 18423005810SPeter Chubb } else { /* catch it next time around */ 185203d65a4SMichael Tokarev next = tmp - s->cmp + ((s->cr & CR_RLD) ? EPIT_TIMER_MAX : s->lr); 186a50c0d6fSJean-Christophe DUBOIS } 18723005810SPeter Chubb ptimer_set_count(s->timer_cmp, next); 188a50c0d6fSJean-Christophe DUBOIS } 189a50c0d6fSJean-Christophe DUBOIS } 190a50c0d6fSJean-Christophe DUBOIS 19195669e69SJean-Christophe DUBOIS static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, 19295669e69SJean-Christophe DUBOIS unsigned size) 193a50c0d6fSJean-Christophe DUBOIS { 19495669e69SJean-Christophe DUBOIS IMXEPITState *s = IMX_EPIT(opaque); 19523005810SPeter Chubb uint64_t oldcr; 196a50c0d6fSJean-Christophe DUBOIS 1974929f656SJean-Christophe Dubois DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2), 1984929f656SJean-Christophe Dubois (uint32_t)value); 19995669e69SJean-Christophe DUBOIS 2004929f656SJean-Christophe Dubois switch (offset >> 2) { 201a50c0d6fSJean-Christophe DUBOIS case 0: /* CR */ 20223005810SPeter Chubb 20323005810SPeter Chubb oldcr = s->cr; 204a50c0d6fSJean-Christophe DUBOIS s->cr = value & 0x03ffffff; 205a50c0d6fSJean-Christophe DUBOIS if (s->cr & CR_SWR) { 206a50c0d6fSJean-Christophe DUBOIS /* handle the reset */ 20795669e69SJean-Christophe DUBOIS imx_epit_reset(DEVICE(s)); 20813557fd3SPeter Maydell /* 20913557fd3SPeter Maydell * TODO: could we 'break' here? following operations appear 21013557fd3SPeter Maydell * to duplicate the work imx_epit_reset() already did. 21113557fd3SPeter Maydell */ 21213557fd3SPeter Maydell } 21313557fd3SPeter Maydell 21413557fd3SPeter Maydell ptimer_transaction_begin(s->timer_cmp); 21513557fd3SPeter Maydell ptimer_transaction_begin(s->timer_reload); 21613557fd3SPeter Maydell 21713557fd3SPeter Maydell if (!(s->cr & CR_SWR)) { 21895669e69SJean-Christophe DUBOIS imx_epit_set_freq(s); 219a50c0d6fSJean-Christophe DUBOIS } 220a50c0d6fSJean-Christophe DUBOIS 22123005810SPeter Chubb if (s->freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) { 222a50c0d6fSJean-Christophe DUBOIS if (s->cr & CR_ENMOD) { 223a50c0d6fSJean-Christophe DUBOIS if (s->cr & CR_RLD) { 224a50c0d6fSJean-Christophe DUBOIS ptimer_set_limit(s->timer_reload, s->lr, 1); 22523005810SPeter Chubb ptimer_set_limit(s->timer_cmp, s->lr, 1); 226a50c0d6fSJean-Christophe DUBOIS } else { 227203d65a4SMichael Tokarev ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1); 228203d65a4SMichael Tokarev ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1); 229a50c0d6fSJean-Christophe DUBOIS } 230a50c0d6fSJean-Christophe DUBOIS } 231a50c0d6fSJean-Christophe DUBOIS 23295669e69SJean-Christophe DUBOIS imx_epit_reload_compare_timer(s); 23323005810SPeter Chubb ptimer_run(s->timer_reload, 0); 23423005810SPeter Chubb if (s->cr & CR_OCIEN) { 23523005810SPeter Chubb ptimer_run(s->timer_cmp, 0); 236a50c0d6fSJean-Christophe DUBOIS } else { 23723005810SPeter Chubb ptimer_stop(s->timer_cmp); 23823005810SPeter Chubb } 23923005810SPeter Chubb } else if (!(s->cr & CR_EN)) { 240a50c0d6fSJean-Christophe DUBOIS /* stop both timers */ 241a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer_reload); 242a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer_cmp); 24323005810SPeter Chubb } else if (s->cr & CR_OCIEN) { 24423005810SPeter Chubb if (!(oldcr & CR_OCIEN)) { 24523005810SPeter Chubb imx_epit_reload_compare_timer(s); 24623005810SPeter Chubb ptimer_run(s->timer_cmp, 0); 24723005810SPeter Chubb } 24823005810SPeter Chubb } else { 24923005810SPeter Chubb ptimer_stop(s->timer_cmp); 250a50c0d6fSJean-Christophe DUBOIS } 251cc2722ecSPeter Maydell 252cc2722ecSPeter Maydell ptimer_transaction_commit(s->timer_cmp); 253cc2722ecSPeter Maydell ptimer_transaction_commit(s->timer_reload); 254a50c0d6fSJean-Christophe DUBOIS break; 255a50c0d6fSJean-Christophe DUBOIS 256a50c0d6fSJean-Christophe DUBOIS case 1: /* SR - ACK*/ 257a50c0d6fSJean-Christophe DUBOIS /* writing 1 to OCIF clear the OCIF bit */ 258a50c0d6fSJean-Christophe DUBOIS if (value & 0x01) { 259a50c0d6fSJean-Christophe DUBOIS s->sr = 0; 26095669e69SJean-Christophe DUBOIS imx_epit_update_int(s); 261a50c0d6fSJean-Christophe DUBOIS } 262a50c0d6fSJean-Christophe DUBOIS break; 263a50c0d6fSJean-Christophe DUBOIS 264a50c0d6fSJean-Christophe DUBOIS case 2: /* LR - set ticks */ 265a50c0d6fSJean-Christophe DUBOIS s->lr = value; 266a50c0d6fSJean-Christophe DUBOIS 267cc2722ecSPeter Maydell ptimer_transaction_begin(s->timer_cmp); 268cc2722ecSPeter Maydell ptimer_transaction_begin(s->timer_reload); 269a50c0d6fSJean-Christophe DUBOIS if (s->cr & CR_RLD) { 270a50c0d6fSJean-Christophe DUBOIS /* Also set the limit if the LRD bit is set */ 271a50c0d6fSJean-Christophe DUBOIS /* If IOVW bit is set then set the timer value */ 272a50c0d6fSJean-Christophe DUBOIS ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW); 27323005810SPeter Chubb ptimer_set_limit(s->timer_cmp, s->lr, 0); 274a50c0d6fSJean-Christophe DUBOIS } else if (s->cr & CR_IOVW) { 275a50c0d6fSJean-Christophe DUBOIS /* If IOVW bit is set then set the timer value */ 276a50c0d6fSJean-Christophe DUBOIS ptimer_set_count(s->timer_reload, s->lr); 277a50c0d6fSJean-Christophe DUBOIS } 278*7719419dSAxel Heider /* 279*7719419dSAxel Heider * Commit the change to s->timer_reload, so it can propagate. Otherwise 280*7719419dSAxel Heider * the timer interrupt may not fire properly. The commit must happen 281*7719419dSAxel Heider * before calling imx_epit_reload_compare_timer(), which reads 282*7719419dSAxel Heider * s->timer_reload internally again. 283*7719419dSAxel Heider */ 284*7719419dSAxel Heider ptimer_transaction_commit(s->timer_reload); 28595669e69SJean-Christophe DUBOIS imx_epit_reload_compare_timer(s); 286cc2722ecSPeter Maydell ptimer_transaction_commit(s->timer_cmp); 287a50c0d6fSJean-Christophe DUBOIS break; 288a50c0d6fSJean-Christophe DUBOIS 289a50c0d6fSJean-Christophe DUBOIS case 3: /* CMP */ 290a50c0d6fSJean-Christophe DUBOIS s->cmp = value; 291a50c0d6fSJean-Christophe DUBOIS 292cc2722ecSPeter Maydell ptimer_transaction_begin(s->timer_cmp); 29395669e69SJean-Christophe DUBOIS imx_epit_reload_compare_timer(s); 294cc2722ecSPeter Maydell ptimer_transaction_commit(s->timer_cmp); 295a50c0d6fSJean-Christophe DUBOIS 296a50c0d6fSJean-Christophe DUBOIS break; 297a50c0d6fSJean-Christophe DUBOIS 298a50c0d6fSJean-Christophe DUBOIS default: 2994929f656SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" 3004929f656SJean-Christophe Dubois HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset); 30195669e69SJean-Christophe DUBOIS 30295669e69SJean-Christophe DUBOIS break; 303a50c0d6fSJean-Christophe DUBOIS } 304a50c0d6fSJean-Christophe DUBOIS } 30595669e69SJean-Christophe DUBOIS static void imx_epit_cmp(void *opaque) 306a50c0d6fSJean-Christophe DUBOIS { 30795669e69SJean-Christophe DUBOIS IMXEPITState *s = IMX_EPIT(opaque); 308a50c0d6fSJean-Christophe DUBOIS 30923005810SPeter Chubb DPRINTF("sr was %d\n", s->sr); 310a50c0d6fSJean-Christophe DUBOIS 311a50c0d6fSJean-Christophe DUBOIS s->sr = 1; 31295669e69SJean-Christophe DUBOIS imx_epit_update_int(s); 313a50c0d6fSJean-Christophe DUBOIS } 314a50c0d6fSJean-Christophe DUBOIS 315cc2722ecSPeter Maydell static void imx_epit_reload(void *opaque) 316cc2722ecSPeter Maydell { 317cc2722ecSPeter Maydell /* No action required on rollover of timer_reload */ 318cc2722ecSPeter Maydell } 319cc2722ecSPeter Maydell 32095669e69SJean-Christophe DUBOIS static const MemoryRegionOps imx_epit_ops = { 32195669e69SJean-Christophe DUBOIS .read = imx_epit_read, 32295669e69SJean-Christophe DUBOIS .write = imx_epit_write, 323a50c0d6fSJean-Christophe DUBOIS .endianness = DEVICE_NATIVE_ENDIAN, 324a50c0d6fSJean-Christophe DUBOIS }; 325a50c0d6fSJean-Christophe DUBOIS 32695669e69SJean-Christophe DUBOIS static const VMStateDescription vmstate_imx_timer_epit = { 327565328fcSJean-Christophe Dubois .name = TYPE_IMX_EPIT, 328a50c0d6fSJean-Christophe DUBOIS .version_id = 2, 329a50c0d6fSJean-Christophe DUBOIS .minimum_version_id = 2, 330a50c0d6fSJean-Christophe DUBOIS .fields = (VMStateField[]) { 33195669e69SJean-Christophe DUBOIS VMSTATE_UINT32(cr, IMXEPITState), 33295669e69SJean-Christophe DUBOIS VMSTATE_UINT32(sr, IMXEPITState), 33395669e69SJean-Christophe DUBOIS VMSTATE_UINT32(lr, IMXEPITState), 33495669e69SJean-Christophe DUBOIS VMSTATE_UINT32(cmp, IMXEPITState), 33595669e69SJean-Christophe DUBOIS VMSTATE_UINT32(cnt, IMXEPITState), 33695669e69SJean-Christophe DUBOIS VMSTATE_UINT32(freq, IMXEPITState), 33795669e69SJean-Christophe DUBOIS VMSTATE_PTIMER(timer_reload, IMXEPITState), 33895669e69SJean-Christophe DUBOIS VMSTATE_PTIMER(timer_cmp, IMXEPITState), 339a50c0d6fSJean-Christophe DUBOIS VMSTATE_END_OF_LIST() 340a50c0d6fSJean-Christophe DUBOIS } 341a50c0d6fSJean-Christophe DUBOIS }; 342a50c0d6fSJean-Christophe DUBOIS 34395669e69SJean-Christophe DUBOIS static void imx_epit_realize(DeviceState *dev, Error **errp) 344a50c0d6fSJean-Christophe DUBOIS { 34595669e69SJean-Christophe DUBOIS IMXEPITState *s = IMX_EPIT(dev); 34695669e69SJean-Christophe DUBOIS SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 347a50c0d6fSJean-Christophe DUBOIS 34895669e69SJean-Christophe DUBOIS DPRINTF("\n"); 349a50c0d6fSJean-Christophe DUBOIS 35095669e69SJean-Christophe DUBOIS sysbus_init_irq(sbd, &s->irq); 351853dca12SPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &imx_epit_ops, s, TYPE_IMX_EPIT, 35295669e69SJean-Christophe DUBOIS 0x00001000); 35395669e69SJean-Christophe DUBOIS sysbus_init_mmio(sbd, &s->iomem); 35495669e69SJean-Christophe DUBOIS 3559598c1bbSPeter Maydell s->timer_reload = ptimer_init(imx_epit_reload, s, PTIMER_POLICY_LEGACY); 356a50c0d6fSJean-Christophe DUBOIS 3579598c1bbSPeter Maydell s->timer_cmp = ptimer_init(imx_epit_cmp, s, PTIMER_POLICY_LEGACY); 358a50c0d6fSJean-Christophe DUBOIS } 359a50c0d6fSJean-Christophe DUBOIS 36095669e69SJean-Christophe DUBOIS static void imx_epit_class_init(ObjectClass *klass, void *data) 361a50c0d6fSJean-Christophe DUBOIS { 362a50c0d6fSJean-Christophe DUBOIS DeviceClass *dc = DEVICE_CLASS(klass); 36395669e69SJean-Christophe DUBOIS 36495669e69SJean-Christophe DUBOIS dc->realize = imx_epit_realize; 36595669e69SJean-Christophe DUBOIS dc->reset = imx_epit_reset; 36695669e69SJean-Christophe DUBOIS dc->vmsd = &vmstate_imx_timer_epit; 367a50c0d6fSJean-Christophe DUBOIS dc->desc = "i.MX periodic timer"; 368a50c0d6fSJean-Christophe DUBOIS } 369a50c0d6fSJean-Christophe DUBOIS 37095669e69SJean-Christophe DUBOIS static const TypeInfo imx_epit_info = { 37195669e69SJean-Christophe DUBOIS .name = TYPE_IMX_EPIT, 372a50c0d6fSJean-Christophe DUBOIS .parent = TYPE_SYS_BUS_DEVICE, 37395669e69SJean-Christophe DUBOIS .instance_size = sizeof(IMXEPITState), 37495669e69SJean-Christophe DUBOIS .class_init = imx_epit_class_init, 375a50c0d6fSJean-Christophe DUBOIS }; 376a50c0d6fSJean-Christophe DUBOIS 37795669e69SJean-Christophe DUBOIS static void imx_epit_register_types(void) 378a50c0d6fSJean-Christophe DUBOIS { 37995669e69SJean-Christophe DUBOIS type_register_static(&imx_epit_info); 380a50c0d6fSJean-Christophe DUBOIS } 381a50c0d6fSJean-Christophe DUBOIS 38295669e69SJean-Christophe DUBOIS type_init(imx_epit_register_types) 383