qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

mips_gictimer.c (4463B)


      1 /*
      2  * This file is subject to the terms and conditions of the GNU General Public
      3  * License.  See the file "COPYING" in the main directory of this archive
      4  * for more details.
      5  *
      6  * Copyright (C) 2016 Imagination Technologies
      7  */
      8 
      9 #include "qemu/osdep.h"
     10 #include "qemu/timer.h"
     11 #include "hw/timer/mips_gictimer.h"
     12 
     13 #define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */
     14 
     15 uint32_t mips_gictimer_get_freq(MIPSGICTimerState *gic)
     16 {
     17     return NANOSECONDS_PER_SECOND / TIMER_PERIOD;
     18 }
     19 
     20 static void gic_vptimer_update(MIPSGICTimerState *gictimer,
     21                                    uint32_t vp_index, uint64_t now)
     22 {
     23     uint64_t next;
     24     uint32_t wait;
     25 
     26     wait = gictimer->vptimers[vp_index].comparelo - gictimer->sh_counterlo -
     27            (uint32_t)(now / TIMER_PERIOD);
     28     next = now + (uint64_t)wait * TIMER_PERIOD;
     29 
     30     timer_mod(gictimer->vptimers[vp_index].qtimer, next);
     31 }
     32 
     33 static void gic_vptimer_expire(MIPSGICTimerState *gictimer, uint32_t vp_index,
     34                                uint64_t now)
     35 {
     36     if (gictimer->countstop) {
     37         /* timer stopped */
     38         return;
     39     }
     40     gictimer->cb(gictimer->opaque, vp_index);
     41     gic_vptimer_update(gictimer, vp_index, now);
     42 }
     43 
     44 static void gic_vptimer_cb(void *opaque)
     45 {
     46     MIPSGICTimerVPState *vptimer = opaque;
     47     MIPSGICTimerState *gictimer = vptimer->gictimer;
     48     gic_vptimer_expire(gictimer, vptimer->vp_index,
     49                        qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
     50 }
     51 
     52 uint32_t mips_gictimer_get_sh_count(MIPSGICTimerState *gictimer)
     53 {
     54     int i;
     55     if (gictimer->countstop) {
     56         return gictimer->sh_counterlo;
     57     } else {
     58         uint64_t now;
     59         now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
     60         for (i = 0; i < gictimer->num_vps; i++) {
     61             if (timer_pending(gictimer->vptimers[i].qtimer)
     62                 && timer_expired(gictimer->vptimers[i].qtimer, now)) {
     63                 /* The timer has already expired.  */
     64                 gic_vptimer_expire(gictimer, i, now);
     65             }
     66         }
     67         return gictimer->sh_counterlo + (uint32_t)(now / TIMER_PERIOD);
     68     }
     69 }
     70 
     71 void mips_gictimer_store_sh_count(MIPSGICTimerState *gictimer, uint64_t count)
     72 {
     73     int i;
     74     uint64_t now;
     75 
     76     if (gictimer->countstop || !gictimer->vptimers[0].qtimer) {
     77         gictimer->sh_counterlo = count;
     78     } else {
     79         /* Store new count register */
     80         now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
     81         gictimer->sh_counterlo = count - (uint32_t)(now / TIMER_PERIOD);
     82         /* Update timer timer */
     83         for (i = 0; i < gictimer->num_vps; i++) {
     84             gic_vptimer_update(gictimer, i, now);
     85         }
     86     }
     87 }
     88 
     89 uint32_t mips_gictimer_get_vp_compare(MIPSGICTimerState *gictimer,
     90                                       uint32_t vp_index)
     91 {
     92     return gictimer->vptimers[vp_index].comparelo;
     93 }
     94 
     95 void mips_gictimer_store_vp_compare(MIPSGICTimerState *gictimer,
     96                                     uint32_t vp_index, uint64_t compare)
     97 {
     98     gictimer->vptimers[vp_index].comparelo = (uint32_t) compare;
     99     gic_vptimer_update(gictimer, vp_index,
    100                        qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
    101 }
    102 
    103 uint8_t mips_gictimer_get_countstop(MIPSGICTimerState *gictimer)
    104 {
    105     return gictimer->countstop;
    106 }
    107 
    108 void mips_gictimer_start_count(MIPSGICTimerState *gictimer)
    109 {
    110     gictimer->countstop = 0;
    111     mips_gictimer_store_sh_count(gictimer, gictimer->sh_counterlo);
    112 }
    113 
    114 void mips_gictimer_stop_count(MIPSGICTimerState *gictimer)
    115 {
    116     int i;
    117 
    118     gictimer->countstop = 1;
    119     /* Store the current value */
    120     gictimer->sh_counterlo +=
    121         (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD);
    122     for (i = 0; i < gictimer->num_vps; i++) {
    123         timer_del(gictimer->vptimers[i].qtimer);
    124     }
    125 }
    126 
    127 MIPSGICTimerState *mips_gictimer_init(void *opaque, uint32_t nvps,
    128                                       MIPSGICTimerCB *cb)
    129 {
    130     int i;
    131     MIPSGICTimerState *gictimer = g_new(MIPSGICTimerState, 1);
    132     gictimer->vptimers = g_new(MIPSGICTimerVPState, nvps);
    133     gictimer->countstop = 1;
    134     gictimer->num_vps = nvps;
    135     gictimer->opaque = opaque;
    136     gictimer->cb = cb;
    137     for (i = 0; i < nvps; i++) {
    138         gictimer->vptimers[i].gictimer = gictimer;
    139         gictimer->vptimers[i].vp_index = i;
    140         gictimer->vptimers[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
    141                                             &gic_vptimer_cb,
    142                                             &gictimer->vptimers[i]);
    143     }
    144     return gictimer;
    145 }