static void pl031_timer_event(struct vmm_timer_event * event) { struct pl031_state *s = (struct pl031_state *)event->priv; s->im = 1; pl031_update(s); }
static void pl031_write(void * opaque, hwaddr offset, uint64_t value, unsigned size) { PL031State *s = (PL031State *)opaque; switch (offset) { case RTC_LR: s->tick_offset += value - pl031_get_count(s); pl031_set_alarm(s); break; case RTC_MR: s->mr = value; pl031_set_alarm(s); break; case RTC_IMSC: s->im = value & 1; DPRINTF("Interrupt mask %d\n", s->im); pl031_update(s); break; case RTC_ICR: /* The PL031 documentation (DDI0224B) states that the interrupt is cleared when bit 0 of the written value is set. However the arm926e documentation (DDI0287B) states that the interrupt is cleared when any value is written. */ DPRINTF("Interrupt cleared"); s->is = 0; pl031_update(s); break; case RTC_CR: /* Written value is ignored. */ break; case RTC_DR: case RTC_MIS: case RTC_RIS: qemu_log_mask(LOG_GUEST_ERROR, "pl031: write to read-only register at offset 0x%x\n", (int)offset); break; default: qemu_log_mask(LOG_GUEST_ERROR, "pl031_write: Bad offset 0x%x\n", (int)offset); break; } }
static void pl031_write(void * opaque, target_phys_addr_t offset, uint32_t value) { pl031_state *s = (pl031_state *)opaque; offset -= s->base; switch (offset) { case RTC_LR: s->tick_offset += value - pl031_get_count(s); pl031_set_alarm(s); break; case RTC_MR: s->mr = value; pl031_set_alarm(s); break; case RTC_IMSC: s->im = value & 1; DPRINTF("Interrupt mask %d\n", s->im); pl031_update(s); break; case RTC_ICR: /* The PL031 documentation (DDI0224B) states that the interupt is cleared when bit 0 of the written value is set. However the arm926e documentation (DDI0287B) states that the interrupt is cleared when any value is written. */ DPRINTF("Interrupt cleared"); s->is = 0; pl031_update(s); break; case RTC_CR: /* Written value is ignored. */ break; case RTC_DR: case RTC_MIS: case RTC_RIS: fprintf(stderr, "qemu: pl031_write: Unexpected offset 0x%x\n", (int)offset); break; default: cpu_abort(cpu_single_env, "pl031_write: Bad offset 0x%x\n", (int)offset); break; } }
static void pl031_interrupt(void * opaque) { PL031State *s = (PL031State *)opaque; s->is = 1; DPRINTF("Alarm raised\n"); pl031_update(s); }
static void pl031_set_alarm(struct pl031_state *s) { u32 ticks = pl031_get_count(s); /* If timer wraps around then subtraction also wraps in the same way, * and gives correct results when alarm < now_ticks. */ ticks = s->mr - ticks; if (ticks == 0) { vmm_timer_event_stop(&s->event); s->im = 1; pl031_update(s); } else { vmm_timer_event_start(&s->event, ((u64)ticks) * ((u64)1000000000)); } }