*/
#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "hw/sysbus.h"
+#include "migration/vmstate.h"
#include "qemu/timer.h"
-#include "qemu-common.h"
-#include "qemu/main-loop.h"
+#include "qemu/module.h"
#include "hw/ptimer.h"
#include "hw/arm/exynos4210.h"
+#include "hw/irq.h"
+#include "qom/object.h"
//#define DEBUG_PWM
} Exynos4210PWM;
#define TYPE_EXYNOS4210_PWM "exynos4210.pwm"
-#define EXYNOS4210_PWM(obj) \
- OBJECT_CHECK(Exynos4210PWMState, (obj), TYPE_EXYNOS4210_PWM)
+OBJECT_DECLARE_SIMPLE_TYPE(Exynos4210PWMState, EXYNOS4210_PWM)
-typedef struct Exynos4210PWMState {
+struct Exynos4210PWMState {
SysBusDevice parent_obj;
MemoryRegion iomem;
Exynos4210PWM timer[EXYNOS4210_PWM_TIMERS_NUM];
-} Exynos4210PWMState;
+};
/*** VMState ***/
static const VMStateDescription vmstate_exynos4210_pwm = {
};
/*
- * PWM update frequency
+ * PWM update frequency.
+ * Must be called within a ptimer_transaction_begin/commit block
+ * for s->timer[id].ptimer.
*/
static void exynos4210_pwm_update_freq(Exynos4210PWMState *s, uint32_t id)
{
if (freq != s->timer[id].freq) {
ptimer_set_freq(s->timer[id].ptimer, s->timer[id].freq);
- DPRINTF("freq=%dHz\n", s->timer[id].freq);
+ DPRINTF("freq=%uHz\n", s->timer[id].freq);
}
}
uint32_t id = s->id;
bool cmp;
- DPRINTF("timer %d tick\n", id);
+ DPRINTF("timer %u tick\n", id);
/* set irq status */
p->reg_tint_cstat |= TINT_CSTAT_STATUS(id);
/* raise IRQ */
if (p->reg_tint_cstat & TINT_CSTAT_ENABLE(id)) {
- DPRINTF("timer %d IRQ\n", id);
+ DPRINTF("timer %u IRQ\n", id);
qemu_irq_raise(p->timer[id].irq);
}
}
if (cmp) {
- DPRINTF("auto reload timer %d count to %x\n", id,
+ DPRINTF("auto reload timer %u count to %x\n", id,
p->timer[id].reg_tcntb);
ptimer_set_count(p->timer[id].ptimer, p->timer[id].reg_tcntb);
ptimer_run(p->timer[id].ptimer, 1);
break;
default:
- fprintf(stderr,
- "[exynos4210.pwm: bad read offset " TARGET_FMT_plx "]\n",
- offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "exynos4210.pwm: bad read offset " HWADDR_FMT_plx,
+ offset);
break;
}
return value;
/* update timers frequencies */
for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
+ ptimer_transaction_begin(s->timer[i].ptimer);
exynos4210_pwm_update_freq(s, s->timer[i].id);
+ ptimer_transaction_commit(s->timer[i].ptimer);
}
break;
case TCON:
for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
+ ptimer_transaction_begin(s->timer[i].ptimer);
if ((value & TCON_TIMER_MANUAL_UPD(i)) >
(s->reg_tcon & TCON_TIMER_MANUAL_UPD(i))) {
/*
ptimer_stop(s->timer[i].ptimer);
DPRINTF("stop timer %d\n", i);
}
+ ptimer_transaction_commit(s->timer[i].ptimer);
}
s->reg_tcon = value;
break;
break;
default:
- fprintf(stderr,
- "[exynos4210.pwm: bad write offset " TARGET_FMT_plx "]\n",
- offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "exynos4210.pwm: bad write offset " HWADDR_FMT_plx,
+ offset);
break;
}
s->timer[i].reg_tcmpb = 0;
s->timer[i].reg_tcntb = 0;
+ ptimer_transaction_begin(s->timer[i].ptimer);
exynos4210_pwm_update_freq(s, s->timer[i].id);
ptimer_stop(s->timer[i].ptimer);
+ ptimer_transaction_commit(s->timer[i].ptimer);
}
}
Exynos4210PWMState *s = EXYNOS4210_PWM(obj);
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
int i;
- QEMUBH *bh;
for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
- bh = qemu_bh_new(exynos4210_pwm_tick, &s->timer[i]);
sysbus_init_irq(dev, &s->timer[i].irq);
- s->timer[i].ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
+ s->timer[i].ptimer = ptimer_init(exynos4210_pwm_tick,
+ &s->timer[i],
+ PTIMER_POLICY_LEGACY);
s->timer[i].id = i;
s->timer[i].parent = s;
}
sysbus_init_mmio(dev, &s->iomem);
}
+static void exynos4210_pwm_finalize(Object *obj)
+{
+ Exynos4210PWMState *s = EXYNOS4210_PWM(obj);
+ int i;
+
+ for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
+ ptimer_free(s->timer[i].ptimer);
+ }
+}
+
static void exynos4210_pwm_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Exynos4210PWMState),
.instance_init = exynos4210_pwm_init,
+ .instance_finalize = exynos4210_pwm_finalize,
.class_init = exynos4210_pwm_class_init,
};