123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- /*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2016 Imagination Technologies
- */
- #include "qemu/osdep.h"
- #include "hw/sysbus.h"
- #include "qemu/timer.h"
- #include "hw/timer/mips_gictimer.h"
- #define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */
- uint32_t mips_gictimer_get_freq(MIPSGICTimerState *gic)
- {
- return NANOSECONDS_PER_SECOND / TIMER_PERIOD;
- }
- static void gic_vptimer_update(MIPSGICTimerState *gictimer,
- uint32_t vp_index, uint64_t now)
- {
- uint64_t next;
- uint32_t wait;
- wait = gictimer->vptimers[vp_index].comparelo - gictimer->sh_counterlo -
- (uint32_t)(now / TIMER_PERIOD);
- next = now + (uint64_t)wait * TIMER_PERIOD;
- timer_mod(gictimer->vptimers[vp_index].qtimer, next);
- }
- static void gic_vptimer_expire(MIPSGICTimerState *gictimer, uint32_t vp_index,
- uint64_t now)
- {
- if (gictimer->countstop) {
- /* timer stopped */
- return;
- }
- gictimer->cb(gictimer->opaque, vp_index);
- gic_vptimer_update(gictimer, vp_index, now);
- }
- static void gic_vptimer_cb(void *opaque)
- {
- MIPSGICTimerVPState *vptimer = opaque;
- MIPSGICTimerState *gictimer = vptimer->gictimer;
- gic_vptimer_expire(gictimer, vptimer->vp_index,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
- }
- uint32_t mips_gictimer_get_sh_count(MIPSGICTimerState *gictimer)
- {
- int i;
- if (gictimer->countstop) {
- return gictimer->sh_counterlo;
- } else {
- uint64_t now;
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- for (i = 0; i < gictimer->num_vps; i++) {
- if (timer_pending(gictimer->vptimers[i].qtimer)
- && timer_expired(gictimer->vptimers[i].qtimer, now)) {
- /* The timer has already expired. */
- gic_vptimer_expire(gictimer, i, now);
- }
- }
- return gictimer->sh_counterlo + (uint32_t)(now / TIMER_PERIOD);
- }
- }
- void mips_gictimer_store_sh_count(MIPSGICTimerState *gictimer, uint64_t count)
- {
- int i;
- uint64_t now;
- if (gictimer->countstop || !gictimer->vptimers[0].qtimer) {
- gictimer->sh_counterlo = count;
- } else {
- /* Store new count register */
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- gictimer->sh_counterlo = count - (uint32_t)(now / TIMER_PERIOD);
- /* Update timer timer */
- for (i = 0; i < gictimer->num_vps; i++) {
- gic_vptimer_update(gictimer, i, now);
- }
- }
- }
- uint32_t mips_gictimer_get_vp_compare(MIPSGICTimerState *gictimer,
- uint32_t vp_index)
- {
- return gictimer->vptimers[vp_index].comparelo;
- }
- void mips_gictimer_store_vp_compare(MIPSGICTimerState *gictimer,
- uint32_t vp_index, uint64_t compare)
- {
- gictimer->vptimers[vp_index].comparelo = (uint32_t) compare;
- gic_vptimer_update(gictimer, vp_index,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
- }
- uint8_t mips_gictimer_get_countstop(MIPSGICTimerState *gictimer)
- {
- return gictimer->countstop;
- }
- void mips_gictimer_start_count(MIPSGICTimerState *gictimer)
- {
- gictimer->countstop = 0;
- mips_gictimer_store_sh_count(gictimer, gictimer->sh_counterlo);
- }
- void mips_gictimer_stop_count(MIPSGICTimerState *gictimer)
- {
- int i;
- gictimer->countstop = 1;
- /* Store the current value */
- gictimer->sh_counterlo +=
- (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD);
- for (i = 0; i < gictimer->num_vps; i++) {
- timer_del(gictimer->vptimers[i].qtimer);
- }
- }
- MIPSGICTimerState *mips_gictimer_init(void *opaque, uint32_t nvps,
- MIPSGICTimerCB *cb)
- {
- int i;
- MIPSGICTimerState *gictimer = g_new(MIPSGICTimerState, 1);
- gictimer->vptimers = g_new(MIPSGICTimerVPState, nvps);
- gictimer->countstop = 1;
- gictimer->num_vps = nvps;
- gictimer->opaque = opaque;
- gictimer->cb = cb;
- for (i = 0; i < nvps; i++) {
- gictimer->vptimers[i].gictimer = gictimer;
- gictimer->vptimers[i].vp_index = i;
- gictimer->vptimers[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- &gic_vptimer_cb,
- &gictimer->vptimers[i]);
- }
- return gictimer;
- }
|