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 8*95669e69SJean-Christophe DUBOIS * Updated by Jean-Christophe Dubois 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 15a50c0d6fSJean-Christophe DUBOIS #include "hw/hw.h" 16a50c0d6fSJean-Christophe DUBOIS #include "qemu/bitops.h" 17a50c0d6fSJean-Christophe DUBOIS #include "qemu/timer.h" 18a50c0d6fSJean-Christophe DUBOIS #include "hw/ptimer.h" 19a50c0d6fSJean-Christophe DUBOIS #include "hw/sysbus.h" 20a50c0d6fSJean-Christophe DUBOIS #include "hw/arm/imx.h" 21a50c0d6fSJean-Christophe DUBOIS 22*95669e69SJean-Christophe DUBOIS #define TYPE_IMX_EPIT "imx.epit" 23*95669e69SJean-Christophe DUBOIS 24*95669e69SJean-Christophe DUBOIS #define DEBUG_TIMER 0 25*95669e69SJean-Christophe DUBOIS #if DEBUG_TIMER 26*95669e69SJean-Christophe DUBOIS 27*95669e69SJean-Christophe DUBOIS static char const *imx_epit_reg_name(uint32_t reg) 28*95669e69SJean-Christophe DUBOIS { 29*95669e69SJean-Christophe DUBOIS switch (reg) { 30*95669e69SJean-Christophe DUBOIS case 0: 31*95669e69SJean-Christophe DUBOIS return "CR"; 32*95669e69SJean-Christophe DUBOIS case 1: 33*95669e69SJean-Christophe DUBOIS return "SR"; 34*95669e69SJean-Christophe DUBOIS case 2: 35*95669e69SJean-Christophe DUBOIS return "LR"; 36*95669e69SJean-Christophe DUBOIS case 3: 37*95669e69SJean-Christophe DUBOIS return "CMP"; 38*95669e69SJean-Christophe DUBOIS case 4: 39*95669e69SJean-Christophe DUBOIS return "CNT"; 40*95669e69SJean-Christophe DUBOIS default: 41*95669e69SJean-Christophe DUBOIS return "[?]"; 42*95669e69SJean-Christophe DUBOIS } 43*95669e69SJean-Christophe DUBOIS } 44*95669e69SJean-Christophe DUBOIS 45a50c0d6fSJean-Christophe DUBOIS # define DPRINTF(fmt, args...) \ 46*95669e69SJean-Christophe DUBOIS do { printf("%s: " fmt , __func__, ##args); } while (0) 47a50c0d6fSJean-Christophe DUBOIS #else 48a50c0d6fSJean-Christophe DUBOIS # define DPRINTF(fmt, args...) do {} while (0) 49a50c0d6fSJean-Christophe DUBOIS #endif 50a50c0d6fSJean-Christophe DUBOIS 51a50c0d6fSJean-Christophe DUBOIS /* 52a50c0d6fSJean-Christophe DUBOIS * Define to 1 for messages about attempts to 53a50c0d6fSJean-Christophe DUBOIS * access unimplemented registers or similar. 54a50c0d6fSJean-Christophe DUBOIS */ 55a50c0d6fSJean-Christophe DUBOIS #define DEBUG_IMPLEMENTATION 1 56a50c0d6fSJean-Christophe DUBOIS #if DEBUG_IMPLEMENTATION 57a50c0d6fSJean-Christophe DUBOIS # define IPRINTF(fmt, args...) \ 58*95669e69SJean-Christophe DUBOIS do { fprintf(stderr, "%s: " fmt, __func__, ##args); } while (0) 59a50c0d6fSJean-Christophe DUBOIS #else 60a50c0d6fSJean-Christophe DUBOIS # define IPRINTF(fmt, args...) do {} while (0) 61a50c0d6fSJean-Christophe DUBOIS #endif 62a50c0d6fSJean-Christophe DUBOIS 63*95669e69SJean-Christophe DUBOIS #define IMX_EPIT(obj) \ 64*95669e69SJean-Christophe DUBOIS OBJECT_CHECK(IMXEPITState, (obj), TYPE_IMX_EPIT) 65*95669e69SJean-Christophe DUBOIS 66a50c0d6fSJean-Christophe DUBOIS /* 67a50c0d6fSJean-Christophe DUBOIS * EPIT: Enhanced periodic interrupt timer 68a50c0d6fSJean-Christophe DUBOIS */ 69a50c0d6fSJean-Christophe DUBOIS 70a50c0d6fSJean-Christophe DUBOIS #define CR_EN (1 << 0) 71a50c0d6fSJean-Christophe DUBOIS #define CR_ENMOD (1 << 1) 72a50c0d6fSJean-Christophe DUBOIS #define CR_OCIEN (1 << 2) 73a50c0d6fSJean-Christophe DUBOIS #define CR_RLD (1 << 3) 74a50c0d6fSJean-Christophe DUBOIS #define CR_PRESCALE_SHIFT (4) 75a50c0d6fSJean-Christophe DUBOIS #define CR_PRESCALE_MASK (0xfff) 76a50c0d6fSJean-Christophe DUBOIS #define CR_SWR (1 << 16) 77a50c0d6fSJean-Christophe DUBOIS #define CR_IOVW (1 << 17) 78a50c0d6fSJean-Christophe DUBOIS #define CR_DBGEN (1 << 18) 79a50c0d6fSJean-Christophe DUBOIS #define CR_WAITEN (1 << 19) 80a50c0d6fSJean-Christophe DUBOIS #define CR_DOZEN (1 << 20) 81a50c0d6fSJean-Christophe DUBOIS #define CR_STOPEN (1 << 21) 82a50c0d6fSJean-Christophe DUBOIS #define CR_CLKSRC_SHIFT (24) 83a50c0d6fSJean-Christophe DUBOIS #define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT) 84a50c0d6fSJean-Christophe DUBOIS 85a50c0d6fSJean-Christophe DUBOIS #define TIMER_MAX 0XFFFFFFFFUL 86a50c0d6fSJean-Christophe DUBOIS 87a50c0d6fSJean-Christophe DUBOIS /* 88a50c0d6fSJean-Christophe DUBOIS * Exact clock frequencies vary from board to board. 89a50c0d6fSJean-Christophe DUBOIS * These are typical. 90a50c0d6fSJean-Christophe DUBOIS */ 91*95669e69SJean-Christophe DUBOIS static const IMXClk imx_epit_clocks[] = { 92a50c0d6fSJean-Christophe DUBOIS 0, /* 00 disabled */ 93a50c0d6fSJean-Christophe DUBOIS IPG, /* 01 ipg_clk, ~532MHz */ 94a50c0d6fSJean-Christophe DUBOIS IPG, /* 10 ipg_clk_highfreq */ 95a50c0d6fSJean-Christophe DUBOIS CLK_32k, /* 11 ipg_clk_32k -- ~32kHz */ 96a50c0d6fSJean-Christophe DUBOIS }; 97a50c0d6fSJean-Christophe DUBOIS 98a50c0d6fSJean-Christophe DUBOIS typedef struct { 99a50c0d6fSJean-Christophe DUBOIS SysBusDevice busdev; 100a50c0d6fSJean-Christophe DUBOIS ptimer_state *timer_reload; 101a50c0d6fSJean-Christophe DUBOIS ptimer_state *timer_cmp; 102a50c0d6fSJean-Christophe DUBOIS MemoryRegion iomem; 103a50c0d6fSJean-Christophe DUBOIS DeviceState *ccm; 104a50c0d6fSJean-Christophe DUBOIS 105a50c0d6fSJean-Christophe DUBOIS uint32_t cr; 106a50c0d6fSJean-Christophe DUBOIS uint32_t sr; 107a50c0d6fSJean-Christophe DUBOIS uint32_t lr; 108a50c0d6fSJean-Christophe DUBOIS uint32_t cmp; 109a50c0d6fSJean-Christophe DUBOIS uint32_t cnt; 110a50c0d6fSJean-Christophe DUBOIS 111a50c0d6fSJean-Christophe DUBOIS uint32_t freq; 112a50c0d6fSJean-Christophe DUBOIS qemu_irq irq; 113*95669e69SJean-Christophe DUBOIS } IMXEPITState; 114a50c0d6fSJean-Christophe DUBOIS 115a50c0d6fSJean-Christophe DUBOIS /* 116a50c0d6fSJean-Christophe DUBOIS * Update interrupt status 117a50c0d6fSJean-Christophe DUBOIS */ 118*95669e69SJean-Christophe DUBOIS static void imx_epit_update_int(IMXEPITState *s) 119a50c0d6fSJean-Christophe DUBOIS { 120*95669e69SJean-Christophe DUBOIS if (s->sr && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) { 121a50c0d6fSJean-Christophe DUBOIS qemu_irq_raise(s->irq); 122a50c0d6fSJean-Christophe DUBOIS } else { 123a50c0d6fSJean-Christophe DUBOIS qemu_irq_lower(s->irq); 124a50c0d6fSJean-Christophe DUBOIS } 125a50c0d6fSJean-Christophe DUBOIS } 126a50c0d6fSJean-Christophe DUBOIS 127*95669e69SJean-Christophe DUBOIS static void imx_epit_set_freq(IMXEPITState *s) 128a50c0d6fSJean-Christophe DUBOIS { 129*95669e69SJean-Christophe DUBOIS uint32_t clksrc; 130*95669e69SJean-Christophe DUBOIS uint32_t prescaler; 131a50c0d6fSJean-Christophe DUBOIS uint32_t freq; 132a50c0d6fSJean-Christophe DUBOIS 133a50c0d6fSJean-Christophe DUBOIS clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2); 134a50c0d6fSJean-Christophe DUBOIS prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12); 135a50c0d6fSJean-Christophe DUBOIS 136*95669e69SJean-Christophe DUBOIS freq = imx_clock_frequency(s->ccm, imx_epit_clocks[clksrc]) / prescaler; 137a50c0d6fSJean-Christophe DUBOIS 138a50c0d6fSJean-Christophe DUBOIS s->freq = freq; 139*95669e69SJean-Christophe DUBOIS 140a50c0d6fSJean-Christophe DUBOIS DPRINTF("Setting ptimer frequency to %u\n", freq); 141a50c0d6fSJean-Christophe DUBOIS 142a50c0d6fSJean-Christophe DUBOIS if (freq) { 143a50c0d6fSJean-Christophe DUBOIS ptimer_set_freq(s->timer_reload, freq); 144a50c0d6fSJean-Christophe DUBOIS ptimer_set_freq(s->timer_cmp, freq); 145a50c0d6fSJean-Christophe DUBOIS } 146a50c0d6fSJean-Christophe DUBOIS } 147a50c0d6fSJean-Christophe DUBOIS 148*95669e69SJean-Christophe DUBOIS static void imx_epit_reset(DeviceState *dev) 149a50c0d6fSJean-Christophe DUBOIS { 150*95669e69SJean-Christophe DUBOIS IMXEPITState *s = IMX_EPIT(dev); 151a50c0d6fSJean-Christophe DUBOIS 152a50c0d6fSJean-Christophe DUBOIS /* 153a50c0d6fSJean-Christophe DUBOIS * Soft reset doesn't touch some bits; hard reset clears them 154a50c0d6fSJean-Christophe DUBOIS */ 155a50c0d6fSJean-Christophe DUBOIS s->cr &= ~(CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN); 156a50c0d6fSJean-Christophe DUBOIS s->sr = 0; 157a50c0d6fSJean-Christophe DUBOIS s->lr = TIMER_MAX; 158a50c0d6fSJean-Christophe DUBOIS s->cmp = 0; 159a50c0d6fSJean-Christophe DUBOIS s->cnt = 0; 160a50c0d6fSJean-Christophe DUBOIS /* stop both timers */ 161a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer_cmp); 162a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer_reload); 163a50c0d6fSJean-Christophe DUBOIS /* compute new frequency */ 164*95669e69SJean-Christophe DUBOIS imx_epit_set_freq(s); 165a50c0d6fSJean-Christophe DUBOIS /* init both timers to TIMER_MAX */ 166a50c0d6fSJean-Christophe DUBOIS ptimer_set_limit(s->timer_cmp, TIMER_MAX, 1); 167a50c0d6fSJean-Christophe DUBOIS ptimer_set_limit(s->timer_reload, TIMER_MAX, 1); 168a50c0d6fSJean-Christophe DUBOIS if (s->freq && (s->cr & CR_EN)) { 169a50c0d6fSJean-Christophe DUBOIS /* if the timer is still enabled, restart it */ 170a50c0d6fSJean-Christophe DUBOIS ptimer_run(s->timer_reload, 1); 171a50c0d6fSJean-Christophe DUBOIS } 172a50c0d6fSJean-Christophe DUBOIS } 173a50c0d6fSJean-Christophe DUBOIS 174*95669e69SJean-Christophe DUBOIS static uint32_t imx_epit_update_count(IMXEPITState *s) 175a50c0d6fSJean-Christophe DUBOIS { 176a50c0d6fSJean-Christophe DUBOIS s->cnt = ptimer_get_count(s->timer_reload); 177a50c0d6fSJean-Christophe DUBOIS 178a50c0d6fSJean-Christophe DUBOIS return s->cnt; 179a50c0d6fSJean-Christophe DUBOIS } 180a50c0d6fSJean-Christophe DUBOIS 181*95669e69SJean-Christophe DUBOIS static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size) 182a50c0d6fSJean-Christophe DUBOIS { 183*95669e69SJean-Christophe DUBOIS IMXEPITState *s = IMX_EPIT(opaque); 184*95669e69SJean-Christophe DUBOIS uint32_t reg_value = 0; 185*95669e69SJean-Christophe DUBOIS uint32_t reg = offset >> 2; 186a50c0d6fSJean-Christophe DUBOIS 187*95669e69SJean-Christophe DUBOIS switch (reg) { 188a50c0d6fSJean-Christophe DUBOIS case 0: /* Control Register */ 189*95669e69SJean-Christophe DUBOIS reg_value = s->cr; 190*95669e69SJean-Christophe DUBOIS break; 191a50c0d6fSJean-Christophe DUBOIS 192a50c0d6fSJean-Christophe DUBOIS case 1: /* Status Register */ 193*95669e69SJean-Christophe DUBOIS reg_value = s->sr; 194*95669e69SJean-Christophe DUBOIS break; 195a50c0d6fSJean-Christophe DUBOIS 196a50c0d6fSJean-Christophe DUBOIS case 2: /* LR - ticks*/ 197*95669e69SJean-Christophe DUBOIS reg_value = s->lr; 198*95669e69SJean-Christophe DUBOIS break; 199a50c0d6fSJean-Christophe DUBOIS 200a50c0d6fSJean-Christophe DUBOIS case 3: /* CMP */ 201*95669e69SJean-Christophe DUBOIS reg_value = s->cmp; 202*95669e69SJean-Christophe DUBOIS break; 203a50c0d6fSJean-Christophe DUBOIS 204a50c0d6fSJean-Christophe DUBOIS case 4: /* CNT */ 205*95669e69SJean-Christophe DUBOIS imx_epit_update_count(s); 206*95669e69SJean-Christophe DUBOIS reg_value = s->cnt; 207*95669e69SJean-Christophe DUBOIS break; 208*95669e69SJean-Christophe DUBOIS 209*95669e69SJean-Christophe DUBOIS default: 210*95669e69SJean-Christophe DUBOIS IPRINTF("Bad offset %x\n", reg); 211*95669e69SJean-Christophe DUBOIS break; 212a50c0d6fSJean-Christophe DUBOIS } 213a50c0d6fSJean-Christophe DUBOIS 214*95669e69SJean-Christophe DUBOIS DPRINTF("(%s) = 0x%08x\n", imx_epit_reg_name(reg), reg_value); 215*95669e69SJean-Christophe DUBOIS 216*95669e69SJean-Christophe DUBOIS return reg_value; 217a50c0d6fSJean-Christophe DUBOIS } 218a50c0d6fSJean-Christophe DUBOIS 219*95669e69SJean-Christophe DUBOIS static void imx_epit_reload_compare_timer(IMXEPITState *s) 220a50c0d6fSJean-Christophe DUBOIS { 221a50c0d6fSJean-Christophe DUBOIS if ((s->cr & CR_OCIEN) && s->cmp) { 222a50c0d6fSJean-Christophe DUBOIS /* if the compare feature is on */ 223*95669e69SJean-Christophe DUBOIS uint32_t tmp = imx_epit_update_count(s); 224a50c0d6fSJean-Christophe DUBOIS if (tmp > s->cmp) { 225a50c0d6fSJean-Christophe DUBOIS /* reinit the cmp timer if required */ 226a50c0d6fSJean-Christophe DUBOIS ptimer_set_count(s->timer_cmp, tmp - s->cmp); 227a50c0d6fSJean-Christophe DUBOIS if ((s->cr & CR_EN)) { 228a50c0d6fSJean-Christophe DUBOIS /* Restart the cmp timer if required */ 229a50c0d6fSJean-Christophe DUBOIS ptimer_run(s->timer_cmp, 0); 230a50c0d6fSJean-Christophe DUBOIS } 231a50c0d6fSJean-Christophe DUBOIS } 232a50c0d6fSJean-Christophe DUBOIS } 233a50c0d6fSJean-Christophe DUBOIS } 234a50c0d6fSJean-Christophe DUBOIS 235*95669e69SJean-Christophe DUBOIS static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, 236*95669e69SJean-Christophe DUBOIS unsigned size) 237a50c0d6fSJean-Christophe DUBOIS { 238*95669e69SJean-Christophe DUBOIS IMXEPITState *s = IMX_EPIT(opaque); 239*95669e69SJean-Christophe DUBOIS uint32_t reg = offset >> 2; 240a50c0d6fSJean-Christophe DUBOIS 241*95669e69SJean-Christophe DUBOIS DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(reg), (uint32_t)value); 242*95669e69SJean-Christophe DUBOIS 243*95669e69SJean-Christophe DUBOIS switch (reg) { 244a50c0d6fSJean-Christophe DUBOIS case 0: /* CR */ 245a50c0d6fSJean-Christophe DUBOIS s->cr = value & 0x03ffffff; 246a50c0d6fSJean-Christophe DUBOIS if (s->cr & CR_SWR) { 247a50c0d6fSJean-Christophe DUBOIS /* handle the reset */ 248*95669e69SJean-Christophe DUBOIS imx_epit_reset(DEVICE(s)); 249a50c0d6fSJean-Christophe DUBOIS } else { 250*95669e69SJean-Christophe DUBOIS imx_epit_set_freq(s); 251a50c0d6fSJean-Christophe DUBOIS } 252a50c0d6fSJean-Christophe DUBOIS 253a50c0d6fSJean-Christophe DUBOIS if (s->freq && (s->cr & CR_EN)) { 254a50c0d6fSJean-Christophe DUBOIS if (s->cr & CR_ENMOD) { 255a50c0d6fSJean-Christophe DUBOIS if (s->cr & CR_RLD) { 256a50c0d6fSJean-Christophe DUBOIS ptimer_set_limit(s->timer_reload, s->lr, 1); 257a50c0d6fSJean-Christophe DUBOIS } else { 258a50c0d6fSJean-Christophe DUBOIS ptimer_set_limit(s->timer_reload, TIMER_MAX, 1); 259a50c0d6fSJean-Christophe DUBOIS } 260a50c0d6fSJean-Christophe DUBOIS } 261a50c0d6fSJean-Christophe DUBOIS 262*95669e69SJean-Christophe DUBOIS imx_epit_reload_compare_timer(s); 263a50c0d6fSJean-Christophe DUBOIS 264a50c0d6fSJean-Christophe DUBOIS ptimer_run(s->timer_reload, 1); 265a50c0d6fSJean-Christophe DUBOIS } else { 266a50c0d6fSJean-Christophe DUBOIS /* stop both timers */ 267a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer_reload); 268a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer_cmp); 269a50c0d6fSJean-Christophe DUBOIS } 270a50c0d6fSJean-Christophe DUBOIS break; 271a50c0d6fSJean-Christophe DUBOIS 272a50c0d6fSJean-Christophe DUBOIS case 1: /* SR - ACK*/ 273a50c0d6fSJean-Christophe DUBOIS /* writing 1 to OCIF clear the OCIF bit */ 274a50c0d6fSJean-Christophe DUBOIS if (value & 0x01) { 275a50c0d6fSJean-Christophe DUBOIS s->sr = 0; 276*95669e69SJean-Christophe DUBOIS imx_epit_update_int(s); 277a50c0d6fSJean-Christophe DUBOIS } 278a50c0d6fSJean-Christophe DUBOIS break; 279a50c0d6fSJean-Christophe DUBOIS 280a50c0d6fSJean-Christophe DUBOIS case 2: /* LR - set ticks */ 281a50c0d6fSJean-Christophe DUBOIS s->lr = value; 282a50c0d6fSJean-Christophe DUBOIS 283a50c0d6fSJean-Christophe DUBOIS if (s->cr & CR_RLD) { 284a50c0d6fSJean-Christophe DUBOIS /* Also set the limit if the LRD bit is set */ 285a50c0d6fSJean-Christophe DUBOIS /* If IOVW bit is set then set the timer value */ 286a50c0d6fSJean-Christophe DUBOIS ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW); 287a50c0d6fSJean-Christophe DUBOIS } else if (s->cr & CR_IOVW) { 288a50c0d6fSJean-Christophe DUBOIS /* If IOVW bit is set then set the timer value */ 289a50c0d6fSJean-Christophe DUBOIS ptimer_set_count(s->timer_reload, s->lr); 290a50c0d6fSJean-Christophe DUBOIS } 291a50c0d6fSJean-Christophe DUBOIS 292*95669e69SJean-Christophe DUBOIS imx_epit_reload_compare_timer(s); 293a50c0d6fSJean-Christophe DUBOIS 294a50c0d6fSJean-Christophe DUBOIS break; 295a50c0d6fSJean-Christophe DUBOIS 296a50c0d6fSJean-Christophe DUBOIS case 3: /* CMP */ 297a50c0d6fSJean-Christophe DUBOIS s->cmp = value; 298a50c0d6fSJean-Christophe DUBOIS 299*95669e69SJean-Christophe DUBOIS imx_epit_reload_compare_timer(s); 300a50c0d6fSJean-Christophe DUBOIS 301a50c0d6fSJean-Christophe DUBOIS break; 302a50c0d6fSJean-Christophe DUBOIS 303a50c0d6fSJean-Christophe DUBOIS default: 304*95669e69SJean-Christophe DUBOIS IPRINTF("Bad offset %x\n", reg); 305*95669e69SJean-Christophe DUBOIS 306*95669e69SJean-Christophe DUBOIS break; 307a50c0d6fSJean-Christophe DUBOIS } 308a50c0d6fSJean-Christophe DUBOIS } 309a50c0d6fSJean-Christophe DUBOIS 310*95669e69SJean-Christophe DUBOIS static void imx_epit_timeout(void *opaque) 311a50c0d6fSJean-Christophe DUBOIS { 312*95669e69SJean-Christophe DUBOIS IMXEPITState *s = IMX_EPIT(opaque); 313a50c0d6fSJean-Christophe DUBOIS 314*95669e69SJean-Christophe DUBOIS DPRINTF("\n"); 315a50c0d6fSJean-Christophe DUBOIS 316a50c0d6fSJean-Christophe DUBOIS if (!(s->cr & CR_EN)) { 317a50c0d6fSJean-Christophe DUBOIS return; 318a50c0d6fSJean-Christophe DUBOIS } 319a50c0d6fSJean-Christophe DUBOIS 320a50c0d6fSJean-Christophe DUBOIS if (s->cr & CR_RLD) { 321a50c0d6fSJean-Christophe DUBOIS ptimer_set_limit(s->timer_reload, s->lr, 1); 322a50c0d6fSJean-Christophe DUBOIS } else { 323a50c0d6fSJean-Christophe DUBOIS ptimer_set_limit(s->timer_reload, TIMER_MAX, 1); 324a50c0d6fSJean-Christophe DUBOIS } 325a50c0d6fSJean-Christophe DUBOIS 326a50c0d6fSJean-Christophe DUBOIS if (s->cr & CR_OCIEN) { 327a50c0d6fSJean-Christophe DUBOIS /* if compare register is 0 then we handle the interrupt here */ 328a50c0d6fSJean-Christophe DUBOIS if (s->cmp == 0) { 329a50c0d6fSJean-Christophe DUBOIS s->sr = 1; 330*95669e69SJean-Christophe DUBOIS imx_epit_update_int(s); 331a50c0d6fSJean-Christophe DUBOIS } else if (s->cmp <= s->lr) { 332a50c0d6fSJean-Christophe DUBOIS /* We should launch the compare register */ 333a50c0d6fSJean-Christophe DUBOIS ptimer_set_count(s->timer_cmp, s->lr - s->cmp); 334a50c0d6fSJean-Christophe DUBOIS ptimer_run(s->timer_cmp, 0); 335a50c0d6fSJean-Christophe DUBOIS } else { 336*95669e69SJean-Christophe DUBOIS IPRINTF("s->lr < s->cmp\n"); 337a50c0d6fSJean-Christophe DUBOIS } 338a50c0d6fSJean-Christophe DUBOIS } 339a50c0d6fSJean-Christophe DUBOIS } 340a50c0d6fSJean-Christophe DUBOIS 341*95669e69SJean-Christophe DUBOIS static void imx_epit_cmp(void *opaque) 342a50c0d6fSJean-Christophe DUBOIS { 343*95669e69SJean-Christophe DUBOIS IMXEPITState *s = IMX_EPIT(opaque); 344a50c0d6fSJean-Christophe DUBOIS 345*95669e69SJean-Christophe DUBOIS DPRINTF("\n"); 346a50c0d6fSJean-Christophe DUBOIS 347a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer_cmp); 348a50c0d6fSJean-Christophe DUBOIS 349a50c0d6fSJean-Christophe DUBOIS /* compare register is not 0 */ 350a50c0d6fSJean-Christophe DUBOIS if (s->cmp) { 351a50c0d6fSJean-Christophe DUBOIS s->sr = 1; 352*95669e69SJean-Christophe DUBOIS imx_epit_update_int(s); 353a50c0d6fSJean-Christophe DUBOIS } 354a50c0d6fSJean-Christophe DUBOIS } 355a50c0d6fSJean-Christophe DUBOIS 356*95669e69SJean-Christophe DUBOIS void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm) 357a50c0d6fSJean-Christophe DUBOIS { 358*95669e69SJean-Christophe DUBOIS IMXEPITState *pp; 359a50c0d6fSJean-Christophe DUBOIS DeviceState *dev; 360a50c0d6fSJean-Christophe DUBOIS 361*95669e69SJean-Christophe DUBOIS dev = sysbus_create_simple(TYPE_IMX_EPIT, addr, irq); 362*95669e69SJean-Christophe DUBOIS pp = IMX_EPIT(dev); 363a50c0d6fSJean-Christophe DUBOIS pp->ccm = ccm; 364a50c0d6fSJean-Christophe DUBOIS } 365a50c0d6fSJean-Christophe DUBOIS 366*95669e69SJean-Christophe DUBOIS static const MemoryRegionOps imx_epit_ops = { 367*95669e69SJean-Christophe DUBOIS .read = imx_epit_read, 368*95669e69SJean-Christophe DUBOIS .write = imx_epit_write, 369a50c0d6fSJean-Christophe DUBOIS .endianness = DEVICE_NATIVE_ENDIAN, 370a50c0d6fSJean-Christophe DUBOIS }; 371a50c0d6fSJean-Christophe DUBOIS 372*95669e69SJean-Christophe DUBOIS static const VMStateDescription vmstate_imx_timer_epit = { 373*95669e69SJean-Christophe DUBOIS .name = TYPE_IMX_EPIT, 374a50c0d6fSJean-Christophe DUBOIS .version_id = 2, 375a50c0d6fSJean-Christophe DUBOIS .minimum_version_id = 2, 376a50c0d6fSJean-Christophe DUBOIS .minimum_version_id_old = 2, 377a50c0d6fSJean-Christophe DUBOIS .fields = (VMStateField[]) { 378*95669e69SJean-Christophe DUBOIS VMSTATE_UINT32(cr, IMXEPITState), 379*95669e69SJean-Christophe DUBOIS VMSTATE_UINT32(sr, IMXEPITState), 380*95669e69SJean-Christophe DUBOIS VMSTATE_UINT32(lr, IMXEPITState), 381*95669e69SJean-Christophe DUBOIS VMSTATE_UINT32(cmp, IMXEPITState), 382*95669e69SJean-Christophe DUBOIS VMSTATE_UINT32(cnt, IMXEPITState), 383*95669e69SJean-Christophe DUBOIS VMSTATE_UINT32(freq, IMXEPITState), 384*95669e69SJean-Christophe DUBOIS VMSTATE_PTIMER(timer_reload, IMXEPITState), 385*95669e69SJean-Christophe DUBOIS VMSTATE_PTIMER(timer_cmp, IMXEPITState), 386a50c0d6fSJean-Christophe DUBOIS VMSTATE_END_OF_LIST() 387a50c0d6fSJean-Christophe DUBOIS } 388a50c0d6fSJean-Christophe DUBOIS }; 389a50c0d6fSJean-Christophe DUBOIS 390*95669e69SJean-Christophe DUBOIS static void imx_epit_realize(DeviceState *dev, Error **errp) 391a50c0d6fSJean-Christophe DUBOIS { 392*95669e69SJean-Christophe DUBOIS IMXEPITState *s = IMX_EPIT(dev); 393*95669e69SJean-Christophe DUBOIS SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 394a50c0d6fSJean-Christophe DUBOIS QEMUBH *bh; 395a50c0d6fSJean-Christophe DUBOIS 396*95669e69SJean-Christophe DUBOIS DPRINTF("\n"); 397a50c0d6fSJean-Christophe DUBOIS 398*95669e69SJean-Christophe DUBOIS sysbus_init_irq(sbd, &s->irq); 399*95669e69SJean-Christophe DUBOIS memory_region_init_io(&s->iomem, &imx_epit_ops, s, TYPE_IMX_EPIT, 400*95669e69SJean-Christophe DUBOIS 0x00001000); 401*95669e69SJean-Christophe DUBOIS sysbus_init_mmio(sbd, &s->iomem); 402*95669e69SJean-Christophe DUBOIS 403*95669e69SJean-Christophe DUBOIS bh = qemu_bh_new(imx_epit_timeout, s); 404a50c0d6fSJean-Christophe DUBOIS s->timer_reload = ptimer_init(bh); 405a50c0d6fSJean-Christophe DUBOIS 406*95669e69SJean-Christophe DUBOIS bh = qemu_bh_new(imx_epit_cmp, s); 407a50c0d6fSJean-Christophe DUBOIS s->timer_cmp = ptimer_init(bh); 408a50c0d6fSJean-Christophe DUBOIS } 409a50c0d6fSJean-Christophe DUBOIS 410*95669e69SJean-Christophe DUBOIS static void imx_epit_class_init(ObjectClass *klass, void *data) 411a50c0d6fSJean-Christophe DUBOIS { 412a50c0d6fSJean-Christophe DUBOIS DeviceClass *dc = DEVICE_CLASS(klass); 413*95669e69SJean-Christophe DUBOIS 414*95669e69SJean-Christophe DUBOIS dc->realize = imx_epit_realize; 415*95669e69SJean-Christophe DUBOIS dc->reset = imx_epit_reset; 416*95669e69SJean-Christophe DUBOIS dc->vmsd = &vmstate_imx_timer_epit; 417a50c0d6fSJean-Christophe DUBOIS dc->desc = "i.MX periodic timer"; 418a50c0d6fSJean-Christophe DUBOIS } 419a50c0d6fSJean-Christophe DUBOIS 420*95669e69SJean-Christophe DUBOIS static const TypeInfo imx_epit_info = { 421*95669e69SJean-Christophe DUBOIS .name = TYPE_IMX_EPIT, 422a50c0d6fSJean-Christophe DUBOIS .parent = TYPE_SYS_BUS_DEVICE, 423*95669e69SJean-Christophe DUBOIS .instance_size = sizeof(IMXEPITState), 424*95669e69SJean-Christophe DUBOIS .class_init = imx_epit_class_init, 425a50c0d6fSJean-Christophe DUBOIS }; 426a50c0d6fSJean-Christophe DUBOIS 427*95669e69SJean-Christophe DUBOIS static void imx_epit_register_types(void) 428a50c0d6fSJean-Christophe DUBOIS { 429*95669e69SJean-Christophe DUBOIS type_register_static(&imx_epit_info); 430a50c0d6fSJean-Christophe DUBOIS } 431a50c0d6fSJean-Christophe DUBOIS 432*95669e69SJean-Christophe DUBOIS type_init(imx_epit_register_types) 433