From: Axel Heider <axel.hei...@hensoldt.net> Signed-off-by: Axel Heider <axel.hei...@hensoldt.net> --- hw/timer/imx_epit.c | 189 ++++++++++++++++++++++++-------------------- 1 file changed, 103 insertions(+), 86 deletions(-)
diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c index b6c013292f..a79f58c963 100644 --- a/hw/timer/imx_epit.c +++ b/hw/timer/imx_epit.c @@ -188,111 +188,128 @@ 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 oldcr; - - DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2), - (uint32_t)value); - - switch (offset >> 2) { - case 0: /* CR */ - - oldcr = s->cr; - s->cr = value & 0x03ffffff; - if (s->cr & 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); + uint32_t oldcr = s->cr; + s->cr = value & 0x03ffffff; + if (s->cr & 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. + */ + } - if (!(s->cr & CR_SWR)) { - imx_epit_set_freq(s); - } + ptimer_transaction_begin(s->timer_cmp); + ptimer_transaction_begin(s->timer_reload); - if (s->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); - } - } + if (!(s->cr & CR_SWR)) { + imx_epit_set_freq(s); + } - imx_epit_reload_compare_timer(s); - ptimer_run(s->timer_reload, 0); - if (s->cr & CR_OCIEN) { - ptimer_run(s->timer_cmp, 0); + if (s->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 */ + if (value & 0x01) { + s->sr = 0; + 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 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); +} - ptimer_transaction_commit(s->timer_cmp); - ptimer_transaction_commit(s->timer_reload); +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 - ACK*/ - /* writing 1 to OCIF clears the OCIF bit */ - if (value & 0x01) { - s->sr = 0; - imx_epit_update_int(s); - } + 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); + 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: -- 2.34.5