/*
* Set counter of FRC global timer.
+ * Must be called within exynos4210_gfrc_tx_begin/commit block.
*/
static void exynos4210_gfrc_set_count(Exynos4210MCTGT *s, uint64_t count)
{
/*
* Stop global FRC timer
+ * Must be called within exynos4210_gfrc_tx_begin/commit block.
*/
static void exynos4210_gfrc_stop(Exynos4210MCTGT *s)
{
/*
* Start global FRC timer
+ * Must be called within exynos4210_gfrc_tx_begin/commit block.
*/
static void exynos4210_gfrc_start(Exynos4210MCTGT *s)
{
ptimer_run(s->ptimer_frc, 1);
}
+/*
+ * Start ptimer transaction for global FRC timer; this is just for
+ * consistency with the way we wrap operations like stop and run.
+ */
+static void exynos4210_gfrc_tx_begin(Exynos4210MCTGT *s)
+{
+ ptimer_transaction_begin(s->ptimer_frc);
+}
+
+/* Commit ptimer transaction for global FRC timer. */
+static void exynos4210_gfrc_tx_commit(Exynos4210MCTGT *s)
+{
+ ptimer_transaction_commit(s->ptimer_frc);
+}
+
/*
* Find next nearest Comparator. If current Comparator value equals to other
* Comparator value, skip them both
/*
* Restart global FRC timer
+ * Must be called within exynos4210_gfrc_tx_begin/commit block.
*/
static void exynos4210_gfrc_restart(Exynos4210MCTState *s)
{
exynos4210_ltick_int_start(&s->tick_timer);
}
+static void tx_ptimer_set_freq(ptimer_state *s, uint32_t freq)
+{
+ /*
+ * callers of exynos4210_mct_update_freq() never do anything
+ * else that needs to be in the same ptimer transaction, so
+ * to avoid a lot of repetition we have a convenience function
+ * for begin/set_freq/commit.
+ */
+ ptimer_transaction_begin(s);
+ ptimer_set_freq(s, freq);
+ ptimer_transaction_commit(s);
+}
+
/* update timer frequency */
static void exynos4210_mct_update_freq(Exynos4210MCTState *s)
{
DPRINTF("freq=%dHz\n", s->freq);
/* global timer */
- ptimer_set_freq(s->g_timer.ptimer_frc, s->freq);
+ tx_ptimer_set_freq(s->g_timer.ptimer_frc, s->freq);
/* local timer */
ptimer_set_freq(s->l_timer[0].tick_timer.ptimer_tick, s->freq);
/* global timer */
memset(&s->g_timer.reg, 0, sizeof(s->g_timer.reg));
+ exynos4210_gfrc_tx_begin(&s->g_timer);
exynos4210_gfrc_stop(&s->g_timer);
+ exynos4210_gfrc_tx_commit(&s->g_timer);
/* local timer */
memset(s->l_timer[0].reg.cnt, 0, sizeof(s->l_timer[0].reg.cnt));
}
s->g_timer.reg.cnt = new_frc;
+ exynos4210_gfrc_tx_begin(&s->g_timer);
exynos4210_gfrc_restart(s);
+ exynos4210_gfrc_tx_commit(&s->g_timer);
break;
case G_CNT_WSTAT:
s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index);
}
+ exynos4210_gfrc_tx_begin(&s->g_timer);
exynos4210_gfrc_restart(s);
+ exynos4210_gfrc_tx_commit(&s->g_timer);
break;
case G_TCON:
DPRINTF("global timer write to reg.g_tcon %llx\n", value);
+ exynos4210_gfrc_tx_begin(&s->g_timer);
+
/* Start FRC if transition from disabled to enabled */
if ((value & G_TCON_TIMER_ENABLE) > (old_val &
G_TCON_TIMER_ENABLE)) {
exynos4210_gfrc_restart(s);
}
}
+
+ exynos4210_gfrc_tx_commit(&s->g_timer);
break;
case G_INT_CSTAT:
QEMUBH *bh[2];
/* Global timer */
- bh[0] = qemu_bh_new(exynos4210_gfrc_event, s);
- s->g_timer.ptimer_frc = ptimer_init_with_bh(bh[0], PTIMER_POLICY_DEFAULT);
+ s->g_timer.ptimer_frc = ptimer_init(exynos4210_gfrc_event, s,
+ PTIMER_POLICY_DEFAULT);
memset(&s->g_timer.reg, 0, sizeof(struct gregs));
/* Local timers */