@@ -156,130 +156,149 @@ static void imx_epit_reload_compare_timer(IMXEPITState *s)
}
}
-static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
+static void imx_epit_write_cr(IMXEPITState *s, uint32_t value)
{
- IMXEPITState *s = IMX_EPIT(opaque);
- uint64_t freq = 0;
- uint64_t oldcr;
-
- DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2),
- (uint32_t)value);
+ uint32_t freq = 0;
+ uint32_t oldcr = s->cr;
- switch (offset >> 2) {
- case 0: /* CR */
-
- oldcr = s->cr;
- /* SWR bit is never persisted, it clears itself once reset is done */
- s->cr = (value & ~CR_SWR) & 0x03ffffff;
- if (value & CR_SWR) {
- /* handle the reset */
- imx_epit_reset(DEVICE(s));
- /*
- * TODO: could we 'break' here? following operations appear
- * to duplicate the work imx_epit_reset() already did.
- */
- }
-
- ptimer_transaction_begin(s->timer_cmp);
- ptimer_transaction_begin(s->timer_reload);
+ /* SWR bit is never persisted, it clears itself once reset is done */
+ s->cr = (value & ~CR_SWR) & 0x03ffffff;
+ if (value & CR_SWR) {
+ /* handle the reset */
+ imx_epit_reset(DEVICE(s));
/*
- * Update the frequency. In case of a reset the input clock was
- * switched off, so this can be skipped.
+ * TODO: could we 'break' here? following operations appear
+ * to duplicate the work imx_epit_reset() already did.
*/
- if (!(value & CR_SWR)) {
- freq = imx_epit_get_freq(s);
- if (freq) {
- ptimer_set_freq(s->timer_reload, freq);
- ptimer_set_freq(s->timer_cmp, freq);
- }
- }
+ }
- if (freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) {
- if (s->cr & CR_ENMOD) {
- if (s->cr & CR_RLD) {
- ptimer_set_limit(s->timer_reload, s->lr, 1);
- ptimer_set_limit(s->timer_cmp, s->lr, 1);
- } else {
- ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
- ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
- }
- }
+ ptimer_transaction_begin(s->timer_cmp);
+ ptimer_transaction_begin(s->timer_reload);
- imx_epit_reload_compare_timer(s);
- ptimer_run(s->timer_reload, 0);
- if (s->cr & CR_OCIEN) {
- ptimer_run(s->timer_cmp, 0);
+ /*
+ * Update the frequency. In case of a reset the input clock was
+ * switched off, so this can be skipped.
+ */
+ if (!(value & CR_SWR)) {
+ freq = imx_epit_get_freq(s);
+ if (freq) {
+ ptimer_set_freq(s->timer_reload, freq);
+ ptimer_set_freq(s->timer_cmp, freq);
+ }
+ }
+
+ if (freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) {
+ if (s->cr & CR_ENMOD) {
+ if (s->cr & CR_RLD) {
+ ptimer_set_limit(s->timer_reload, s->lr, 1);
+ ptimer_set_limit(s->timer_cmp, s->lr, 1);
} else {
- ptimer_stop(s->timer_cmp);
- }
- } else if (!(s->cr & CR_EN)) {
- /* stop both timers */
- ptimer_stop(s->timer_reload);
- ptimer_stop(s->timer_cmp);
- } else if (s->cr & CR_OCIEN) {
- if (!(oldcr & CR_OCIEN)) {
- imx_epit_reload_compare_timer(s);
- ptimer_run(s->timer_cmp, 0);
+ ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
+ ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
}
+ }
+
+ imx_epit_reload_compare_timer(s);
+ ptimer_run(s->timer_reload, 0);
+ if (s->cr & CR_OCIEN) {
+ ptimer_run(s->timer_cmp, 0);
} else {
ptimer_stop(s->timer_cmp);
}
+ } else if (!(s->cr & CR_EN)) {
+ /* stop both timers */
+ ptimer_stop(s->timer_reload);
+ ptimer_stop(s->timer_cmp);
+ } else if (s->cr & CR_OCIEN) {
+ if (!(oldcr & CR_OCIEN)) {
+ imx_epit_reload_compare_timer(s);
+ ptimer_run(s->timer_cmp, 0);
+ }
+ } else {
+ ptimer_stop(s->timer_cmp);
+ }
+
+ ptimer_transaction_commit(s->timer_cmp);
+ ptimer_transaction_commit(s->timer_reload);
+}
+
+static void imx_epit_write_sr(IMXEPITState *s, uint32_t value)
+{
+ /* writing 1 to OCIF clears the OCIF bit and the interrupt */
+ if (value & 0x01) {
+ s->sr = 0;
+ qemu_irq_lower(s->irq);
+ }
+}
+
+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 change to s->timer_reload, so it can propagate. Otherwise
+ * the timer interrupt may not fire properly. The commit must happen
+ * before calling imx_epit_reload_compare_timer(), which reads
+ * s->timer_reload internally again.
+ */
+ ptimer_transaction_commit(s->timer_reload);
+ imx_epit_reload_compare_timer(s);
+ ptimer_transaction_commit(s->timer_cmp);
+}
+
+static void imx_epit_write_cmp(IMXEPITState *s, uint32_t value)
+{
+ s->cmp = value;
+
+ ptimer_transaction_begin(s->timer_cmp);
+ imx_epit_reload_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);
- ptimer_transaction_commit(s->timer_cmp);
- ptimer_transaction_commit(s->timer_reload);
+ switch (offset >> 2) {
+ case 0: /* CR */
+ imx_epit_write_cr(s, (uint32_t)value);
break;
- case 1: /* SR - ACK*/
- /* writing 1 to OCIF clears the OCIF bit and the interrupt */
- if (value & 0x01) {
- s->sr = 0;
- qemu_irq_lower(s->irq);
- }
+ case 1: /* SR */
+ imx_epit_write_sr(s, (uint32_t)value);
break;
- case 2: /* LR - set ticks */
- 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 change to s->timer_reload, so it can propagate. Otherwise
- * the timer interrupt may not fire properly. The commit must happen
- * before calling imx_epit_reload_compare_timer(), which reads
- * s->timer_reload internally again.
- */
- ptimer_transaction_commit(s->timer_reload);
- imx_epit_reload_compare_timer(s);
- ptimer_transaction_commit(s->timer_cmp);
+ case 2: /* LR */
+ imx_epit_write_lr(s, (uint32_t)value);
break;
case 3: /* CMP */
- s->cmp = value;
-
- ptimer_transaction_begin(s->timer_cmp);
- imx_epit_reload_compare_timer(s);
- ptimer_transaction_commit(s->timer_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);