qemu

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

grlib_gptimer.c (12218B)


      1 /*
      2  * QEMU GRLIB GPTimer Emulator
      3  *
      4  * Copyright (c) 2010-2019 AdaCore
      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/sparc/grlib.h"
     27 #include "hw/sysbus.h"
     28 #include "qemu/timer.h"
     29 #include "hw/irq.h"
     30 #include "hw/ptimer.h"
     31 #include "hw/qdev-properties.h"
     32 #include "qemu/module.h"
     33 
     34 #include "trace.h"
     35 #include "qom/object.h"
     36 
     37 #define UNIT_REG_SIZE    16     /* Size of memory mapped regs for the unit */
     38 #define GPTIMER_REG_SIZE 16     /* Size of memory mapped regs for a GPTimer */
     39 
     40 #define GPTIMER_MAX_TIMERS 8
     41 
     42 /* GPTimer Config register fields */
     43 #define GPTIMER_ENABLE      (1 << 0)
     44 #define GPTIMER_RESTART     (1 << 1)
     45 #define GPTIMER_LOAD        (1 << 2)
     46 #define GPTIMER_INT_ENABLE  (1 << 3)
     47 #define GPTIMER_INT_PENDING (1 << 4)
     48 #define GPTIMER_CHAIN       (1 << 5) /* Not supported */
     49 #define GPTIMER_DEBUG_HALT  (1 << 6) /* Not supported */
     50 
     51 /* Memory mapped register offsets */
     52 #define SCALER_OFFSET         0x00
     53 #define SCALER_RELOAD_OFFSET  0x04
     54 #define CONFIG_OFFSET         0x08
     55 #define COUNTER_OFFSET        0x00
     56 #define COUNTER_RELOAD_OFFSET 0x04
     57 #define TIMER_BASE            0x10
     58 
     59 OBJECT_DECLARE_SIMPLE_TYPE(GPTimerUnit, GRLIB_GPTIMER)
     60 
     61 typedef struct GPTimer     GPTimer;
     62 
     63 struct GPTimer {
     64     struct ptimer_state *ptimer;
     65 
     66     qemu_irq     irq;
     67     int          id;
     68     GPTimerUnit *unit;
     69 
     70     /* registers */
     71     uint32_t counter;
     72     uint32_t reload;
     73     uint32_t config;
     74 };
     75 
     76 struct GPTimerUnit {
     77     SysBusDevice  parent_obj;
     78 
     79     MemoryRegion iomem;
     80 
     81     uint32_t nr_timers;         /* Number of timers available */
     82     uint32_t freq_hz;           /* System frequency */
     83     uint32_t irq_line;          /* Base irq line */
     84 
     85     GPTimer *timers;
     86 
     87     /* registers */
     88     uint32_t scaler;
     89     uint32_t reload;
     90     uint32_t config;
     91 };
     92 
     93 static void grlib_gptimer_tx_begin(GPTimer *timer)
     94 {
     95     ptimer_transaction_begin(timer->ptimer);
     96 }
     97 
     98 static void grlib_gptimer_tx_commit(GPTimer *timer)
     99 {
    100     ptimer_transaction_commit(timer->ptimer);
    101 }
    102 
    103 /* Must be called within grlib_gptimer_tx_begin/commit block */
    104 static void grlib_gptimer_enable(GPTimer *timer)
    105 {
    106     assert(timer != NULL);
    107 
    108 
    109     ptimer_stop(timer->ptimer);
    110 
    111     if (!(timer->config & GPTIMER_ENABLE)) {
    112         /* Timer disabled */
    113         trace_grlib_gptimer_disabled(timer->id, timer->config);
    114         return;
    115     }
    116 
    117     /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
    118        underflow. Set count + 1 to simulate the GPTimer behavior. */
    119 
    120     trace_grlib_gptimer_enable(timer->id, timer->counter);
    121 
    122     ptimer_set_count(timer->ptimer, (uint64_t)timer->counter + 1);
    123     ptimer_run(timer->ptimer, 1);
    124 }
    125 
    126 /* Must be called within grlib_gptimer_tx_begin/commit block */
    127 static void grlib_gptimer_restart(GPTimer *timer)
    128 {
    129     assert(timer != NULL);
    130 
    131     trace_grlib_gptimer_restart(timer->id, timer->reload);
    132 
    133     timer->counter = timer->reload;
    134     grlib_gptimer_enable(timer);
    135 }
    136 
    137 static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
    138 {
    139     int i = 0;
    140     uint32_t value = 0;
    141 
    142     assert(unit != NULL);
    143 
    144     if (scaler > 0) {
    145         value = unit->freq_hz / (scaler + 1);
    146     } else {
    147         value = unit->freq_hz;
    148     }
    149 
    150     trace_grlib_gptimer_set_scaler(scaler, value);
    151 
    152     for (i = 0; i < unit->nr_timers; i++) {
    153         ptimer_transaction_begin(unit->timers[i].ptimer);
    154         ptimer_set_freq(unit->timers[i].ptimer, value);
    155         ptimer_transaction_commit(unit->timers[i].ptimer);
    156     }
    157 }
    158 
    159 static void grlib_gptimer_hit(void *opaque)
    160 {
    161     GPTimer *timer = opaque;
    162     assert(timer != NULL);
    163 
    164     trace_grlib_gptimer_hit(timer->id);
    165 
    166     /* Timer expired */
    167 
    168     if (timer->config & GPTIMER_INT_ENABLE) {
    169         /* Set the pending bit (only unset by write in the config register) */
    170         timer->config |= GPTIMER_INT_PENDING;
    171         qemu_irq_pulse(timer->irq);
    172     }
    173 
    174     if (timer->config & GPTIMER_RESTART) {
    175         grlib_gptimer_restart(timer);
    176     }
    177 }
    178 
    179 static uint64_t grlib_gptimer_read(void *opaque, hwaddr addr,
    180                                    unsigned size)
    181 {
    182     GPTimerUnit        *unit  = opaque;
    183     hwaddr  timer_addr;
    184     int                 id;
    185     uint32_t            value = 0;
    186 
    187     addr &= 0xff;
    188 
    189     /* Unit registers */
    190     switch (addr) {
    191     case SCALER_OFFSET:
    192         trace_grlib_gptimer_readl(-1, addr, unit->scaler);
    193         return unit->scaler;
    194 
    195     case SCALER_RELOAD_OFFSET:
    196         trace_grlib_gptimer_readl(-1, addr, unit->reload);
    197         return unit->reload;
    198 
    199     case CONFIG_OFFSET:
    200         trace_grlib_gptimer_readl(-1, addr, unit->config);
    201         return unit->config;
    202 
    203     default:
    204         break;
    205     }
    206 
    207     timer_addr = (addr % TIMER_BASE);
    208     id         = (addr - TIMER_BASE) / TIMER_BASE;
    209 
    210     if (id >= 0 && id < unit->nr_timers) {
    211 
    212         /* GPTimer registers */
    213         switch (timer_addr) {
    214         case COUNTER_OFFSET:
    215             value = ptimer_get_count(unit->timers[id].ptimer);
    216             trace_grlib_gptimer_readl(id, addr, value);
    217             return value;
    218 
    219         case COUNTER_RELOAD_OFFSET:
    220             value = unit->timers[id].reload;
    221             trace_grlib_gptimer_readl(id, addr, value);
    222             return value;
    223 
    224         case CONFIG_OFFSET:
    225             trace_grlib_gptimer_readl(id, addr, unit->timers[id].config);
    226             return unit->timers[id].config;
    227 
    228         default:
    229             break;
    230         }
    231 
    232     }
    233 
    234     trace_grlib_gptimer_readl(-1, addr, 0);
    235     return 0;
    236 }
    237 
    238 static void grlib_gptimer_write(void *opaque, hwaddr addr,
    239                                 uint64_t value, unsigned size)
    240 {
    241     GPTimerUnit        *unit = opaque;
    242     hwaddr  timer_addr;
    243     int                 id;
    244 
    245     addr &= 0xff;
    246 
    247     /* Unit registers */
    248     switch (addr) {
    249     case SCALER_OFFSET:
    250         value &= 0xFFFF; /* clean up the value */
    251         unit->scaler = value;
    252         trace_grlib_gptimer_writel(-1, addr, unit->scaler);
    253         return;
    254 
    255     case SCALER_RELOAD_OFFSET:
    256         value &= 0xFFFF; /* clean up the value */
    257         unit->reload = value;
    258         trace_grlib_gptimer_writel(-1, addr, unit->reload);
    259         grlib_gptimer_set_scaler(unit, value);
    260         return;
    261 
    262     case CONFIG_OFFSET:
    263         /* Read Only (disable timer freeze not supported) */
    264         trace_grlib_gptimer_writel(-1, addr, 0);
    265         return;
    266 
    267     default:
    268         break;
    269     }
    270 
    271     timer_addr = (addr % TIMER_BASE);
    272     id         = (addr - TIMER_BASE) / TIMER_BASE;
    273 
    274     if (id >= 0 && id < unit->nr_timers) {
    275 
    276         /* GPTimer registers */
    277         switch (timer_addr) {
    278         case COUNTER_OFFSET:
    279             trace_grlib_gptimer_writel(id, addr, value);
    280             grlib_gptimer_tx_begin(&unit->timers[id]);
    281             unit->timers[id].counter = value;
    282             grlib_gptimer_enable(&unit->timers[id]);
    283             grlib_gptimer_tx_commit(&unit->timers[id]);
    284             return;
    285 
    286         case COUNTER_RELOAD_OFFSET:
    287             trace_grlib_gptimer_writel(id, addr, value);
    288             unit->timers[id].reload = value;
    289             return;
    290 
    291         case CONFIG_OFFSET:
    292             trace_grlib_gptimer_writel(id, addr, value);
    293 
    294             if (value & GPTIMER_INT_PENDING) {
    295                 /* clear pending bit */
    296                 value &= ~GPTIMER_INT_PENDING;
    297             } else {
    298                 /* keep pending bit */
    299                 value |= unit->timers[id].config & GPTIMER_INT_PENDING;
    300             }
    301 
    302             unit->timers[id].config = value;
    303 
    304             /* gptimer_restart calls gptimer_enable, so if "enable" and "load"
    305                bits are present, we just have to call restart. */
    306 
    307             grlib_gptimer_tx_begin(&unit->timers[id]);
    308             if (value & GPTIMER_LOAD) {
    309                 grlib_gptimer_restart(&unit->timers[id]);
    310             } else if (value & GPTIMER_ENABLE) {
    311                 grlib_gptimer_enable(&unit->timers[id]);
    312             }
    313 
    314             /* These fields must always be read as 0 */
    315             value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
    316 
    317             unit->timers[id].config = value;
    318             grlib_gptimer_tx_commit(&unit->timers[id]);
    319             return;
    320 
    321         default:
    322             break;
    323         }
    324 
    325     }
    326 
    327     trace_grlib_gptimer_writel(-1, addr, value);
    328 }
    329 
    330 static const MemoryRegionOps grlib_gptimer_ops = {
    331     .read = grlib_gptimer_read,
    332     .write = grlib_gptimer_write,
    333     .endianness = DEVICE_NATIVE_ENDIAN,
    334     .valid = {
    335         .min_access_size = 4,
    336         .max_access_size = 4,
    337     },
    338 };
    339 
    340 static void grlib_gptimer_reset(DeviceState *d)
    341 {
    342     GPTimerUnit *unit = GRLIB_GPTIMER(d);
    343     int          i    = 0;
    344 
    345     assert(unit != NULL);
    346 
    347     unit->scaler = 0;
    348     unit->reload = 0;
    349 
    350     unit->config  = unit->nr_timers;
    351     unit->config |= unit->irq_line << 3;
    352     unit->config |= 1 << 8;     /* separate interrupt */
    353     unit->config |= 1 << 9;     /* Disable timer freeze */
    354 
    355 
    356     for (i = 0; i < unit->nr_timers; i++) {
    357         GPTimer *timer = &unit->timers[i];
    358 
    359         timer->counter = 0;
    360         timer->reload = 0;
    361         timer->config = 0;
    362         ptimer_transaction_begin(timer->ptimer);
    363         ptimer_stop(timer->ptimer);
    364         ptimer_set_count(timer->ptimer, 0);
    365         ptimer_set_freq(timer->ptimer, unit->freq_hz);
    366         ptimer_transaction_commit(timer->ptimer);
    367     }
    368 }
    369 
    370 static void grlib_gptimer_realize(DeviceState *dev, Error **errp)
    371 {
    372     GPTimerUnit  *unit = GRLIB_GPTIMER(dev);
    373     unsigned int  i;
    374     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    375 
    376     assert(unit->nr_timers > 0);
    377     assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
    378 
    379     unit->timers = g_malloc0(sizeof unit->timers[0] * unit->nr_timers);
    380 
    381     for (i = 0; i < unit->nr_timers; i++) {
    382         GPTimer *timer = &unit->timers[i];
    383 
    384         timer->unit   = unit;
    385         timer->ptimer = ptimer_init(grlib_gptimer_hit, timer,
    386                                     PTIMER_POLICY_LEGACY);
    387         timer->id     = i;
    388 
    389         /* One IRQ line for each timer */
    390         sysbus_init_irq(sbd, &timer->irq);
    391 
    392         ptimer_transaction_begin(timer->ptimer);
    393         ptimer_set_freq(timer->ptimer, unit->freq_hz);
    394         ptimer_transaction_commit(timer->ptimer);
    395     }
    396 
    397     memory_region_init_io(&unit->iomem, OBJECT(unit), &grlib_gptimer_ops,
    398                           unit, "gptimer",
    399                           UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers);
    400 
    401     sysbus_init_mmio(sbd, &unit->iomem);
    402 }
    403 
    404 static Property grlib_gptimer_properties[] = {
    405     DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz,   40000000),
    406     DEFINE_PROP_UINT32("irq-line",  GPTimerUnit, irq_line,  8),
    407     DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
    408     DEFINE_PROP_END_OF_LIST(),
    409 };
    410 
    411 static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
    412 {
    413     DeviceClass *dc = DEVICE_CLASS(klass);
    414 
    415     dc->realize = grlib_gptimer_realize;
    416     dc->reset = grlib_gptimer_reset;
    417     device_class_set_props(dc, grlib_gptimer_properties);
    418 }
    419 
    420 static const TypeInfo grlib_gptimer_info = {
    421     .name          = TYPE_GRLIB_GPTIMER,
    422     .parent        = TYPE_SYS_BUS_DEVICE,
    423     .instance_size = sizeof(GPTimerUnit),
    424     .class_init    = grlib_gptimer_class_init,
    425 };
    426 
    427 static void grlib_gptimer_register_types(void)
    428 {
    429     type_register_static(&grlib_gptimer_info);
    430 }
    431 
    432 type_init(grlib_gptimer_register_types)