qemu

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

xilinx_timer.c (7636B)


      1 /*
      2  * QEMU model of the Xilinx timer block.
      3  *
      4  * Copyright (c) 2009 Edgar E. Iglesias.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 
     25 #include "qemu/osdep.h"
     26 #include "hw/sysbus.h"
     27 #include "hw/irq.h"
     28 #include "hw/ptimer.h"
     29 #include "hw/qdev-properties.h"
     30 #include "qemu/log.h"
     31 #include "qemu/module.h"
     32 #include "qom/object.h"
     33 
     34 #define D(x)
     35 
     36 #define R_TCSR     0
     37 #define R_TLR      1
     38 #define R_TCR      2
     39 #define R_MAX      4
     40 
     41 #define TCSR_MDT        (1<<0)
     42 #define TCSR_UDT        (1<<1)
     43 #define TCSR_GENT       (1<<2)
     44 #define TCSR_CAPT       (1<<3)
     45 #define TCSR_ARHT       (1<<4)
     46 #define TCSR_LOAD       (1<<5)
     47 #define TCSR_ENIT       (1<<6)
     48 #define TCSR_ENT        (1<<7)
     49 #define TCSR_TINT       (1<<8)
     50 #define TCSR_PWMA       (1<<9)
     51 #define TCSR_ENALL      (1<<10)
     52 
     53 struct xlx_timer
     54 {
     55     ptimer_state *ptimer;
     56     void *parent;
     57     int nr; /* for debug.  */
     58 
     59     unsigned long timer_div;
     60 
     61     uint32_t regs[R_MAX];
     62 };
     63 
     64 #define TYPE_XILINX_TIMER "xlnx.xps-timer"
     65 DECLARE_INSTANCE_CHECKER(struct timerblock, XILINX_TIMER,
     66                          TYPE_XILINX_TIMER)
     67 
     68 struct timerblock
     69 {
     70     SysBusDevice parent_obj;
     71 
     72     MemoryRegion mmio;
     73     qemu_irq irq;
     74     uint8_t one_timer_only;
     75     uint32_t freq_hz;
     76     struct xlx_timer *timers;
     77 };
     78 
     79 static inline unsigned int num_timers(struct timerblock *t)
     80 {
     81     return 2 - t->one_timer_only;
     82 }
     83 
     84 static inline unsigned int timer_from_addr(hwaddr addr)
     85 {
     86     /* Timers get a 4x32bit control reg area each.  */
     87     return addr >> 2;
     88 }
     89 
     90 static void timer_update_irq(struct timerblock *t)
     91 {
     92     unsigned int i, irq = 0;
     93     uint32_t csr;
     94 
     95     for (i = 0; i < num_timers(t); i++) {
     96         csr = t->timers[i].regs[R_TCSR];
     97         irq |= (csr & TCSR_TINT) && (csr & TCSR_ENIT);
     98     }
     99 
    100     /* All timers within the same slave share a single IRQ line.  */
    101     qemu_set_irq(t->irq, !!irq);
    102 }
    103 
    104 static uint64_t
    105 timer_read(void *opaque, hwaddr addr, unsigned int size)
    106 {
    107     struct timerblock *t = opaque;
    108     struct xlx_timer *xt;
    109     uint32_t r = 0;
    110     unsigned int timer;
    111 
    112     addr >>= 2;
    113     timer = timer_from_addr(addr);
    114     xt = &t->timers[timer];
    115     /* Further decoding to address a specific timers reg.  */
    116     addr &= 0x3;
    117     switch (addr)
    118     {
    119         case R_TCR:
    120                 r = ptimer_get_count(xt->ptimer);
    121                 if (!(xt->regs[R_TCSR] & TCSR_UDT))
    122                     r = ~r;
    123                 D(qemu_log("xlx_timer t=%d read counter=%x udt=%d\n",
    124                          timer, r, xt->regs[R_TCSR] & TCSR_UDT));
    125             break;
    126         default:
    127             if (addr < ARRAY_SIZE(xt->regs))
    128                 r = xt->regs[addr];
    129             break;
    130 
    131     }
    132     D(fprintf(stderr, "%s timer=%d %x=%x\n", __func__, timer, addr * 4, r));
    133     return r;
    134 }
    135 
    136 /* Must be called inside ptimer transaction block */
    137 static void timer_enable(struct xlx_timer *xt)
    138 {
    139     uint64_t count;
    140 
    141     D(fprintf(stderr, "%s timer=%d down=%d\n", __func__,
    142               xt->nr, xt->regs[R_TCSR] & TCSR_UDT));
    143 
    144     ptimer_stop(xt->ptimer);
    145 
    146     if (xt->regs[R_TCSR] & TCSR_UDT)
    147         count = xt->regs[R_TLR];
    148     else
    149         count = ~0 - xt->regs[R_TLR];
    150     ptimer_set_limit(xt->ptimer, count, 1);
    151     ptimer_run(xt->ptimer, 1);
    152 }
    153 
    154 static void
    155 timer_write(void *opaque, hwaddr addr,
    156             uint64_t val64, unsigned int size)
    157 {
    158     struct timerblock *t = opaque;
    159     struct xlx_timer *xt;
    160     unsigned int timer;
    161     uint32_t value = val64;
    162 
    163     addr >>= 2;
    164     timer = timer_from_addr(addr);
    165     xt = &t->timers[timer];
    166     D(fprintf(stderr, "%s addr=%x val=%x (timer=%d off=%d)\n",
    167              __func__, addr * 4, value, timer, addr & 3));
    168     /* Further decoding to address a specific timers reg.  */
    169     addr &= 3;
    170     switch (addr) 
    171     {
    172         case R_TCSR:
    173             if (value & TCSR_TINT)
    174                 value &= ~TCSR_TINT;
    175 
    176             xt->regs[addr] = value & 0x7ff;
    177             if (value & TCSR_ENT) {
    178                 ptimer_transaction_begin(xt->ptimer);
    179                 timer_enable(xt);
    180                 ptimer_transaction_commit(xt->ptimer);
    181             }
    182             break;
    183  
    184         default:
    185             if (addr < ARRAY_SIZE(xt->regs))
    186                 xt->regs[addr] = value;
    187             break;
    188     }
    189     timer_update_irq(t);
    190 }
    191 
    192 static const MemoryRegionOps timer_ops = {
    193     .read = timer_read,
    194     .write = timer_write,
    195     .endianness = DEVICE_NATIVE_ENDIAN,
    196     .valid = {
    197         .min_access_size = 4,
    198         .max_access_size = 4
    199     }
    200 };
    201 
    202 static void timer_hit(void *opaque)
    203 {
    204     struct xlx_timer *xt = opaque;
    205     struct timerblock *t = xt->parent;
    206     D(fprintf(stderr, "%s %d\n", __func__, xt->nr));
    207     xt->regs[R_TCSR] |= TCSR_TINT;
    208 
    209     if (xt->regs[R_TCSR] & TCSR_ARHT)
    210         timer_enable(xt);
    211     timer_update_irq(t);
    212 }
    213 
    214 static void xilinx_timer_realize(DeviceState *dev, Error **errp)
    215 {
    216     struct timerblock *t = XILINX_TIMER(dev);
    217     unsigned int i;
    218 
    219     /* Init all the ptimers.  */
    220     t->timers = g_malloc0(sizeof t->timers[0] * num_timers(t));
    221     for (i = 0; i < num_timers(t); i++) {
    222         struct xlx_timer *xt = &t->timers[i];
    223 
    224         xt->parent = t;
    225         xt->nr = i;
    226         xt->ptimer = ptimer_init(timer_hit, xt, PTIMER_POLICY_LEGACY);
    227         ptimer_transaction_begin(xt->ptimer);
    228         ptimer_set_freq(xt->ptimer, t->freq_hz);
    229         ptimer_transaction_commit(xt->ptimer);
    230     }
    231 
    232     memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, "xlnx.xps-timer",
    233                           R_MAX * 4 * num_timers(t));
    234     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &t->mmio);
    235 }
    236 
    237 static void xilinx_timer_init(Object *obj)
    238 {
    239     struct timerblock *t = XILINX_TIMER(obj);
    240 
    241     /* All timers share a single irq line.  */
    242     sysbus_init_irq(SYS_BUS_DEVICE(obj), &t->irq);
    243 }
    244 
    245 static Property xilinx_timer_properties[] = {
    246     DEFINE_PROP_UINT32("clock-frequency", struct timerblock, freq_hz,
    247                                                                 62 * 1000000),
    248     DEFINE_PROP_UINT8("one-timer-only", struct timerblock, one_timer_only, 0),
    249     DEFINE_PROP_END_OF_LIST(),
    250 };
    251 
    252 static void xilinx_timer_class_init(ObjectClass *klass, void *data)
    253 {
    254     DeviceClass *dc = DEVICE_CLASS(klass);
    255 
    256     dc->realize = xilinx_timer_realize;
    257     device_class_set_props(dc, xilinx_timer_properties);
    258 }
    259 
    260 static const TypeInfo xilinx_timer_info = {
    261     .name          = TYPE_XILINX_TIMER,
    262     .parent        = TYPE_SYS_BUS_DEVICE,
    263     .instance_size = sizeof(struct timerblock),
    264     .instance_init = xilinx_timer_init,
    265     .class_init    = xilinx_timer_class_init,
    266 };
    267 
    268 static void xilinx_timer_register_types(void)
    269 {
    270     type_register_static(&xilinx_timer_info);
    271 }
    272 
    273 type_init(xilinx_timer_register_types)