|  | /* | 
|  | * IMX EPIT Timer | 
|  | * | 
|  | * Copyright (c) 2008 OK Labs | 
|  | * Copyright (c) 2011 NICTA Pty Ltd | 
|  | * Originally written by Hans Jiang | 
|  | * Updated by Peter Chubb | 
|  | * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> | 
|  | * Updated by Axel Heider | 
|  | * | 
|  | * This code is licensed under GPL version 2 or later.  See | 
|  | * the COPYING file in the top-level directory. | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include "qemu/osdep.h" | 
|  | #include "hw/timer/imx_epit.h" | 
|  | #include "migration/vmstate.h" | 
|  | #include "hw/irq.h" | 
|  | #include "hw/misc/imx_ccm.h" | 
|  | #include "qemu/module.h" | 
|  | #include "qemu/log.h" | 
|  |  | 
|  | #ifndef DEBUG_IMX_EPIT | 
|  | #define DEBUG_IMX_EPIT 0 | 
|  | #endif | 
|  |  | 
|  | #define DPRINTF(fmt, args...) \ | 
|  | do { \ | 
|  | if (DEBUG_IMX_EPIT) { \ | 
|  | fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_EPIT, \ | 
|  | __func__, ##args); \ | 
|  | } \ | 
|  | } while (0) | 
|  |  | 
|  | static const char *imx_epit_reg_name(uint32_t reg) | 
|  | { | 
|  | switch (reg) { | 
|  | case 0: | 
|  | return "CR"; | 
|  | case 1: | 
|  | return "SR"; | 
|  | case 2: | 
|  | return "LR"; | 
|  | case 3: | 
|  | return "CMP"; | 
|  | case 4: | 
|  | return "CNT"; | 
|  | default: | 
|  | return "[?]"; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Exact clock frequencies vary from board to board. | 
|  | * These are typical. | 
|  | */ | 
|  | static const IMXClk imx_epit_clocks[] =  { | 
|  | CLK_NONE,      /* 00 disabled */ | 
|  | CLK_IPG,       /* 01 ipg_clk, ~532MHz */ | 
|  | CLK_IPG_HIGH,  /* 10 ipg_clk_highfreq */ | 
|  | CLK_32k,       /* 11 ipg_clk_32k -- ~32kHz */ | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * Update interrupt status | 
|  | */ | 
|  | static void imx_epit_update_int(IMXEPITState *s) | 
|  | { | 
|  | if ((s->sr & SR_OCIF) && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) { | 
|  | qemu_irq_raise(s->irq); | 
|  | } else { | 
|  | qemu_irq_lower(s->irq); | 
|  | } | 
|  | } | 
|  |  | 
|  | static uint32_t imx_epit_get_freq(IMXEPITState *s) | 
|  | { | 
|  | uint32_t clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, CR_CLKSRC_BITS); | 
|  | uint32_t prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, CR_PRESCALE_BITS); | 
|  | uint32_t f_in = imx_ccm_get_clock_frequency(s->ccm, imx_epit_clocks[clksrc]); | 
|  | uint32_t freq = f_in / prescaler; | 
|  | DPRINTF("ptimer frequency is %u\n", freq); | 
|  | return freq; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * This is called both on hardware (device) reset and software reset. | 
|  | */ | 
|  | static void imx_epit_reset(IMXEPITState *s, bool is_hard_reset) | 
|  | { | 
|  | /* Soft reset doesn't touch some bits; hard reset clears them */ | 
|  | if (is_hard_reset) { | 
|  | s->cr = 0; | 
|  | } else { | 
|  | s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN); | 
|  | } | 
|  | s->sr = 0; | 
|  | s->lr = EPIT_TIMER_MAX; | 
|  | s->cmp = 0; | 
|  | ptimer_transaction_begin(s->timer_cmp); | 
|  | ptimer_transaction_begin(s->timer_reload); | 
|  |  | 
|  | /* | 
|  | * The reset switches off the input clock, so even if the CR.EN is still | 
|  | * set, the timers are no longer running. | 
|  | */ | 
|  | assert(imx_epit_get_freq(s) == 0); | 
|  | ptimer_stop(s->timer_cmp); | 
|  | ptimer_stop(s->timer_reload); | 
|  | /* init both timers to EPIT_TIMER_MAX */ | 
|  | ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1); | 
|  | ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1); | 
|  | ptimer_transaction_commit(s->timer_cmp); | 
|  | ptimer_transaction_commit(s->timer_reload); | 
|  | } | 
|  |  | 
|  | static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size) | 
|  | { | 
|  | IMXEPITState *s = IMX_EPIT(opaque); | 
|  | uint32_t reg_value = 0; | 
|  |  | 
|  | switch (offset >> 2) { | 
|  | case 0: /* Control Register */ | 
|  | reg_value = s->cr; | 
|  | break; | 
|  |  | 
|  | case 1: /* Status Register */ | 
|  | reg_value = s->sr; | 
|  | break; | 
|  |  | 
|  | case 2: /* LR - ticks*/ | 
|  | reg_value = s->lr; | 
|  | break; | 
|  |  | 
|  | case 3: /* CMP */ | 
|  | reg_value = s->cmp; | 
|  | break; | 
|  |  | 
|  | case 4: /* CNT */ | 
|  | reg_value = ptimer_get_count(s->timer_reload); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" | 
|  | HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset); | 
|  | break; | 
|  | } | 
|  |  | 
|  | DPRINTF("(%s) = 0x%08x\n", imx_epit_reg_name(offset >> 2), reg_value); | 
|  |  | 
|  | return reg_value; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Must be called from a ptimer_transaction_begin/commit block for | 
|  | * s->timer_cmp, but outside of a transaction block of s->timer_reload, | 
|  | * so the proper counter value is read. | 
|  | */ | 
|  | static void imx_epit_update_compare_timer(IMXEPITState *s) | 
|  | { | 
|  | uint64_t counter = 0; | 
|  | bool is_oneshot = false; | 
|  | /* | 
|  | * The compare timer only has to run if the timer peripheral is active | 
|  | * and there is an input clock, Otherwise it can be switched off. | 
|  | */ | 
|  | bool is_active = (s->cr & CR_EN) && imx_epit_get_freq(s); | 
|  | if (is_active) { | 
|  | /* | 
|  | * Calculate next timeout for compare timer. Reading the reload | 
|  | * counter returns proper results only if pending transactions | 
|  | * on it are committed here. Otherwise stale values are be read. | 
|  | */ | 
|  | counter = ptimer_get_count(s->timer_reload); | 
|  | uint64_t limit = ptimer_get_limit(s->timer_cmp); | 
|  | /* | 
|  | * The compare timer is a periodic timer if the limit is at least | 
|  | * the compare value. Otherwise it may fire at most once in the | 
|  | * current round. | 
|  | */ | 
|  | is_oneshot = (limit < s->cmp); | 
|  | if (counter >= s->cmp) { | 
|  | /* The compare timer fires in the current round. */ | 
|  | counter -= s->cmp; | 
|  | } else if (!is_oneshot) { | 
|  | /* | 
|  | * The compare timer fires after a reload, as it is below the | 
|  | * compare value already in this round. Note that the counter | 
|  | * value calculated below can be above the 32-bit limit, which | 
|  | * is legal here because the compare timer is an internal | 
|  | * helper ptimer only. | 
|  | */ | 
|  | counter += limit - s->cmp; | 
|  | } else { | 
|  | /* | 
|  | * The compare timer won't fire in this round, and the limit is | 
|  | * set to a value below the compare value. This practically means | 
|  | * it will never fire, so it can be switched off. | 
|  | */ | 
|  | is_active = false; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Set the compare timer and let it run, or stop it. This is agnostic | 
|  | * of CR.OCIEN bit, as this bit affects interrupt generation only. The | 
|  | * compare timer needs to run even if no interrupts are to be generated, | 
|  | * because the SR.OCIF bit must be updated also. | 
|  | * Note that the timer might already be stopped or be running with | 
|  | * counter values. However, finding out when an update is needed and | 
|  | * when not is not trivial. It's much easier applying the setting again, | 
|  | * as this does not harm either and the overhead is negligible. | 
|  | */ | 
|  | if (is_active) { | 
|  | ptimer_set_count(s->timer_cmp, counter); | 
|  | ptimer_run(s->timer_cmp, is_oneshot ? 1 : 0); | 
|  | } else { | 
|  | ptimer_stop(s->timer_cmp); | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | static void imx_epit_write_cr(IMXEPITState *s, uint32_t value) | 
|  | { | 
|  | uint32_t oldcr = s->cr; | 
|  |  | 
|  | s->cr = value & 0x03ffffff; | 
|  |  | 
|  | if (s->cr & CR_SWR) { | 
|  | /* | 
|  | * Reset clears CR.SWR again. It does not touch CR.EN, but the timers | 
|  | * are still stopped because the input clock is disabled. | 
|  | */ | 
|  | imx_epit_reset(s, false); | 
|  | } else { | 
|  | uint32_t freq; | 
|  | uint32_t toggled_cr_bits = oldcr ^ s->cr; | 
|  | /* re-initialize the limits if CR.RLD has changed */ | 
|  | bool set_limit = toggled_cr_bits & CR_RLD; | 
|  | /* set the counter if the timer got just enabled and CR.ENMOD is set */ | 
|  | bool is_switched_on = (toggled_cr_bits & s->cr) & CR_EN; | 
|  | bool set_counter = is_switched_on && (s->cr & CR_ENMOD); | 
|  |  | 
|  | ptimer_transaction_begin(s->timer_cmp); | 
|  | ptimer_transaction_begin(s->timer_reload); | 
|  | freq = imx_epit_get_freq(s); | 
|  | if (freq) { | 
|  | ptimer_set_freq(s->timer_reload, freq); | 
|  | ptimer_set_freq(s->timer_cmp, freq); | 
|  | } | 
|  |  | 
|  | if (set_limit || set_counter) { | 
|  | uint64_t limit = (s->cr & CR_RLD) ? s->lr : EPIT_TIMER_MAX; | 
|  | ptimer_set_limit(s->timer_reload, limit, set_counter ? 1 : 0); | 
|  | if (set_limit) { | 
|  | ptimer_set_limit(s->timer_cmp, limit, 0); | 
|  | } | 
|  | } | 
|  | /* | 
|  | * If there is an input clock and the peripheral is enabled, then | 
|  | * ensure the wall clock timer is ticking. Otherwise stop the timers. | 
|  | * The compare timer will be updated later. | 
|  | */ | 
|  | if (freq && (s->cr & CR_EN)) { | 
|  | ptimer_run(s->timer_reload, 0); | 
|  | } else { | 
|  | ptimer_stop(s->timer_reload); | 
|  | } | 
|  | /* Commit changes to reload timer, so they can propagate. */ | 
|  | ptimer_transaction_commit(s->timer_reload); | 
|  | /* Update compare timer based on the committed reload timer value. */ | 
|  | imx_epit_update_compare_timer(s); | 
|  | ptimer_transaction_commit(s->timer_cmp); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * The interrupt state can change due to: | 
|  | * - reset clears both SR.OCIF and CR.OCIE | 
|  | * - write to CR.EN or CR.OCIE | 
|  | */ | 
|  | imx_epit_update_int(s); | 
|  | } | 
|  |  | 
|  | static void imx_epit_write_sr(IMXEPITState *s, uint32_t value) | 
|  | { | 
|  | /* writing 1 to SR.OCIF clears this bit and turns the interrupt off */ | 
|  | if (value & SR_OCIF) { | 
|  | s->sr = 0; /* SR.OCIF is the only bit in this register anyway */ | 
|  | imx_epit_update_int(s); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void imx_epit_write_lr(IMXEPITState *s, uint32_t value) | 
|  | { | 
|  | s->lr = value; | 
|  |  | 
|  | ptimer_transaction_begin(s->timer_cmp); | 
|  | ptimer_transaction_begin(s->timer_reload); | 
|  | if (s->cr & CR_RLD) { | 
|  | /* Also set the limit if the LRD bit is set */ | 
|  | /* If IOVW bit is set then set the timer value */ | 
|  | ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW); | 
|  | ptimer_set_limit(s->timer_cmp, s->lr, 0); | 
|  | } else if (s->cr & CR_IOVW) { | 
|  | /* If IOVW bit is set then set the timer value */ | 
|  | ptimer_set_count(s->timer_reload, s->lr); | 
|  | } | 
|  | /* Commit the changes to s->timer_reload, so they can propagate. */ | 
|  | ptimer_transaction_commit(s->timer_reload); | 
|  | /* Update the compare timer based on the committed reload timer value. */ | 
|  | imx_epit_update_compare_timer(s); | 
|  | ptimer_transaction_commit(s->timer_cmp); | 
|  | } | 
|  |  | 
|  | static void imx_epit_write_cmp(IMXEPITState *s, uint32_t value) | 
|  | { | 
|  | s->cmp = value; | 
|  |  | 
|  | /* Update the compare timer based on the committed reload timer value. */ | 
|  | ptimer_transaction_begin(s->timer_cmp); | 
|  | imx_epit_update_compare_timer(s); | 
|  | ptimer_transaction_commit(s->timer_cmp); | 
|  | } | 
|  |  | 
|  | static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, | 
|  | unsigned size) | 
|  | { | 
|  | IMXEPITState *s = IMX_EPIT(opaque); | 
|  |  | 
|  | DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2), | 
|  | (uint32_t)value); | 
|  |  | 
|  | switch (offset >> 2) { | 
|  | case 0: /* CR */ | 
|  | imx_epit_write_cr(s, (uint32_t)value); | 
|  | break; | 
|  |  | 
|  | case 1: /* SR */ | 
|  | imx_epit_write_sr(s, (uint32_t)value); | 
|  | break; | 
|  |  | 
|  | case 2: /* LR */ | 
|  | imx_epit_write_lr(s, (uint32_t)value); | 
|  | break; | 
|  |  | 
|  | case 3: /* CMP */ | 
|  | imx_epit_write_cmp(s, (uint32_t)value); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" | 
|  | HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void imx_epit_cmp(void *opaque) | 
|  | { | 
|  | IMXEPITState *s = IMX_EPIT(opaque); | 
|  |  | 
|  | /* The cmp ptimer can't be running when the peripheral is disabled */ | 
|  | assert(s->cr & CR_EN); | 
|  |  | 
|  | DPRINTF("sr was %d\n", s->sr); | 
|  | /* Set interrupt status bit SR.OCIF and update the interrupt state */ | 
|  | s->sr |= SR_OCIF; | 
|  | imx_epit_update_int(s); | 
|  | } | 
|  |  | 
|  | static void imx_epit_reload(void *opaque) | 
|  | { | 
|  | /* No action required on rollover of timer_reload */ | 
|  | } | 
|  |  | 
|  | static const MemoryRegionOps imx_epit_ops = { | 
|  | .read = imx_epit_read, | 
|  | .write = imx_epit_write, | 
|  | .endianness = DEVICE_NATIVE_ENDIAN, | 
|  | }; | 
|  |  | 
|  | static const VMStateDescription vmstate_imx_timer_epit = { | 
|  | .name = TYPE_IMX_EPIT, | 
|  | .version_id = 3, | 
|  | .minimum_version_id = 3, | 
|  | .fields = (const VMStateField[]) { | 
|  | VMSTATE_UINT32(cr, IMXEPITState), | 
|  | VMSTATE_UINT32(sr, IMXEPITState), | 
|  | VMSTATE_UINT32(lr, IMXEPITState), | 
|  | VMSTATE_UINT32(cmp, IMXEPITState), | 
|  | VMSTATE_PTIMER(timer_reload, IMXEPITState), | 
|  | VMSTATE_PTIMER(timer_cmp, IMXEPITState), | 
|  | VMSTATE_END_OF_LIST() | 
|  | } | 
|  | }; | 
|  |  | 
|  | static void imx_epit_realize(DeviceState *dev, Error **errp) | 
|  | { | 
|  | IMXEPITState *s = IMX_EPIT(dev); | 
|  | SysBusDevice *sbd = SYS_BUS_DEVICE(dev); | 
|  |  | 
|  | DPRINTF("\n"); | 
|  |  | 
|  | sysbus_init_irq(sbd, &s->irq); | 
|  | memory_region_init_io(&s->iomem, OBJECT(s), &imx_epit_ops, s, TYPE_IMX_EPIT, | 
|  | 0x00001000); | 
|  | sysbus_init_mmio(sbd, &s->iomem); | 
|  |  | 
|  | /* | 
|  | * The reload timer keeps running when the peripheral is enabled. It is a | 
|  | * kind of wall clock that does not generate any interrupts. The callback | 
|  | * needs to be provided, but it does nothing as the ptimer already supports | 
|  | * all necessary reloading functionality. | 
|  | */ | 
|  | s->timer_reload = ptimer_init(imx_epit_reload, s, PTIMER_POLICY_LEGACY); | 
|  |  | 
|  | /* | 
|  | * The compare timer is running only when the peripheral configuration is | 
|  | * in a state that will generate compare interrupts. | 
|  | */ | 
|  | s->timer_cmp = ptimer_init(imx_epit_cmp, s, PTIMER_POLICY_LEGACY); | 
|  | } | 
|  |  | 
|  | static void imx_epit_dev_reset(DeviceState *dev) | 
|  | { | 
|  | IMXEPITState *s = IMX_EPIT(dev); | 
|  | imx_epit_reset(s, true); | 
|  | } | 
|  |  | 
|  | static void imx_epit_class_init(ObjectClass *klass, const void *data) | 
|  | { | 
|  | DeviceClass *dc  = DEVICE_CLASS(klass); | 
|  |  | 
|  | dc->realize = imx_epit_realize; | 
|  | device_class_set_legacy_reset(dc, imx_epit_dev_reset); | 
|  | dc->vmsd = &vmstate_imx_timer_epit; | 
|  | dc->desc = "i.MX periodic timer"; | 
|  | } | 
|  |  | 
|  | static const TypeInfo imx_epit_info = { | 
|  | .name = TYPE_IMX_EPIT, | 
|  | .parent = TYPE_SYS_BUS_DEVICE, | 
|  | .instance_size = sizeof(IMXEPITState), | 
|  | .class_init = imx_epit_class_init, | 
|  | }; | 
|  |  | 
|  | static void imx_epit_register_types(void) | 
|  | { | 
|  | type_register_static(&imx_epit_info); | 
|  | } | 
|  |  | 
|  | type_init(imx_epit_register_types) |