ibex_timer.c (9265B)
1/* 2 * QEMU lowRISC Ibex Timer device 3 * 4 * Copyright (c) 2021 Western Digital 5 * 6 * For details check the documentation here: 7 * https://docs.opentitan.org/hw/ip/rv_timer/doc/ 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a copy 10 * of this software and associated documentation files (the "Software"), to deal 11 * in the Software without restriction, including without limitation the rights 12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 * copies of the Software, and to permit persons to whom the Software is 14 * furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included in 17 * all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 * THE SOFTWARE. 26 */ 27 28#include "qemu/osdep.h" 29#include "qemu/log.h" 30#include "qemu/timer.h" 31#include "hw/timer/ibex_timer.h" 32#include "hw/irq.h" 33#include "hw/qdev-properties.h" 34#include "target/riscv/cpu.h" 35#include "migration/vmstate.h" 36 37REG32(CTRL, 0x00) 38 FIELD(CTRL, ACTIVE, 0, 1) 39REG32(CFG0, 0x100) 40 FIELD(CFG0, PRESCALE, 0, 12) 41 FIELD(CFG0, STEP, 16, 8) 42REG32(LOWER0, 0x104) 43REG32(UPPER0, 0x108) 44REG32(COMPARE_LOWER0, 0x10C) 45REG32(COMPARE_UPPER0, 0x110) 46REG32(INTR_ENABLE, 0x114) 47 FIELD(INTR_ENABLE, IE_0, 0, 1) 48REG32(INTR_STATE, 0x118) 49 FIELD(INTR_STATE, IS_0, 0, 1) 50REG32(INTR_TEST, 0x11C) 51 FIELD(INTR_TEST, T_0, 0, 1) 52 53static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq) 54{ 55 return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 56 timebase_freq, NANOSECONDS_PER_SECOND); 57} 58 59static void ibex_timer_update_irqs(IbexTimerState *s) 60{ 61 CPUState *cs = qemu_get_cpu(0); 62 RISCVCPU *cpu = RISCV_CPU(cs); 63 uint64_t value = s->timer_compare_lower0 | 64 ((uint64_t)s->timer_compare_upper0 << 32); 65 uint64_t next, diff; 66 uint64_t now = cpu_riscv_read_rtc(s->timebase_freq); 67 68 if (!(s->timer_ctrl & R_CTRL_ACTIVE_MASK)) { 69 /* Timer isn't active */ 70 return; 71 } 72 73 /* Update the CPUs mtimecmp */ 74 cpu->env.timecmp = value; 75 76 if (cpu->env.timecmp <= now) { 77 /* 78 * If the mtimecmp was in the past raise the interrupt now. 79 */ 80 qemu_irq_raise(s->m_timer_irq); 81 if (s->timer_intr_enable & R_INTR_ENABLE_IE_0_MASK) { 82 s->timer_intr_state |= R_INTR_STATE_IS_0_MASK; 83 qemu_set_irq(s->irq, true); 84 } 85 return; 86 } 87 88 /* Setup a timer to trigger the interrupt in the future */ 89 qemu_irq_lower(s->m_timer_irq); 90 qemu_set_irq(s->irq, false); 91 92 diff = cpu->env.timecmp - now; 93 next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 94 muldiv64(diff, 95 NANOSECONDS_PER_SECOND, 96 s->timebase_freq); 97 98 if (next < qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) { 99 /* We overflowed the timer, just set it as large as we can */ 100 timer_mod(cpu->env.timer, 0x7FFFFFFFFFFFFFFF); 101 } else { 102 timer_mod(cpu->env.timer, next); 103 } 104} 105 106static void ibex_timer_cb(void *opaque) 107{ 108 IbexTimerState *s = opaque; 109 110 qemu_irq_raise(s->m_timer_irq); 111 if (s->timer_intr_enable & R_INTR_ENABLE_IE_0_MASK) { 112 s->timer_intr_state |= R_INTR_STATE_IS_0_MASK; 113 qemu_set_irq(s->irq, true); 114 } 115} 116 117static void ibex_timer_reset(DeviceState *dev) 118{ 119 IbexTimerState *s = IBEX_TIMER(dev); 120 121 CPUState *cpu = qemu_get_cpu(0); 122 CPURISCVState *env = cpu->env_ptr; 123 env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 124 &ibex_timer_cb, s); 125 env->timecmp = 0; 126 127 s->timer_ctrl = 0x00000000; 128 s->timer_cfg0 = 0x00010000; 129 s->timer_compare_lower0 = 0xFFFFFFFF; 130 s->timer_compare_upper0 = 0xFFFFFFFF; 131 s->timer_intr_enable = 0x00000000; 132 s->timer_intr_state = 0x00000000; 133 s->timer_intr_test = 0x00000000; 134 135 ibex_timer_update_irqs(s); 136} 137 138static uint64_t ibex_timer_read(void *opaque, hwaddr addr, 139 unsigned int size) 140{ 141 IbexTimerState *s = opaque; 142 uint64_t now = cpu_riscv_read_rtc(s->timebase_freq); 143 uint64_t retvalue = 0; 144 145 switch (addr >> 2) { 146 case R_CTRL: 147 retvalue = s->timer_ctrl; 148 break; 149 case R_CFG0: 150 retvalue = s->timer_cfg0; 151 break; 152 case R_LOWER0: 153 retvalue = now; 154 break; 155 case R_UPPER0: 156 retvalue = now >> 32; 157 break; 158 case R_COMPARE_LOWER0: 159 retvalue = s->timer_compare_lower0; 160 break; 161 case R_COMPARE_UPPER0: 162 retvalue = s->timer_compare_upper0; 163 break; 164 case R_INTR_ENABLE: 165 retvalue = s->timer_intr_enable; 166 break; 167 case R_INTR_STATE: 168 retvalue = s->timer_intr_state; 169 break; 170 case R_INTR_TEST: 171 retvalue = s->timer_intr_test; 172 break; 173 default: 174 qemu_log_mask(LOG_GUEST_ERROR, 175 "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 176 return 0; 177 } 178 179 return retvalue; 180} 181 182static void ibex_timer_write(void *opaque, hwaddr addr, 183 uint64_t val64, unsigned int size) 184{ 185 IbexTimerState *s = opaque; 186 uint32_t val = val64; 187 188 switch (addr >> 2) { 189 case R_CTRL: 190 s->timer_ctrl = val; 191 break; 192 case R_CFG0: 193 qemu_log_mask(LOG_UNIMP, "Changing prescale or step not supported"); 194 s->timer_cfg0 = val; 195 break; 196 case R_LOWER0: 197 qemu_log_mask(LOG_UNIMP, "Changing timer value is not supported"); 198 break; 199 case R_UPPER0: 200 qemu_log_mask(LOG_UNIMP, "Changing timer value is not supported"); 201 break; 202 case R_COMPARE_LOWER0: 203 s->timer_compare_lower0 = val; 204 ibex_timer_update_irqs(s); 205 break; 206 case R_COMPARE_UPPER0: 207 s->timer_compare_upper0 = val; 208 ibex_timer_update_irqs(s); 209 break; 210 case R_INTR_ENABLE: 211 s->timer_intr_enable = val; 212 break; 213 case R_INTR_STATE: 214 /* Write 1 to clear */ 215 s->timer_intr_state &= ~val; 216 break; 217 case R_INTR_TEST: 218 s->timer_intr_test = val; 219 if (s->timer_intr_enable & 220 s->timer_intr_test & 221 R_INTR_ENABLE_IE_0_MASK) { 222 s->timer_intr_state |= R_INTR_STATE_IS_0_MASK; 223 qemu_set_irq(s->irq, true); 224 } 225 break; 226 default: 227 qemu_log_mask(LOG_GUEST_ERROR, 228 "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 229 } 230} 231 232static const MemoryRegionOps ibex_timer_ops = { 233 .read = ibex_timer_read, 234 .write = ibex_timer_write, 235 .endianness = DEVICE_NATIVE_ENDIAN, 236 .impl.min_access_size = 4, 237 .impl.max_access_size = 4, 238}; 239 240static int ibex_timer_post_load(void *opaque, int version_id) 241{ 242 IbexTimerState *s = opaque; 243 244 ibex_timer_update_irqs(s); 245 return 0; 246} 247 248static const VMStateDescription vmstate_ibex_timer = { 249 .name = TYPE_IBEX_TIMER, 250 .version_id = 1, 251 .minimum_version_id = 1, 252 .post_load = ibex_timer_post_load, 253 .fields = (VMStateField[]) { 254 VMSTATE_UINT32(timer_ctrl, IbexTimerState), 255 VMSTATE_UINT32(timer_cfg0, IbexTimerState), 256 VMSTATE_UINT32(timer_compare_lower0, IbexTimerState), 257 VMSTATE_UINT32(timer_compare_upper0, IbexTimerState), 258 VMSTATE_UINT32(timer_intr_enable, IbexTimerState), 259 VMSTATE_UINT32(timer_intr_state, IbexTimerState), 260 VMSTATE_UINT32(timer_intr_test, IbexTimerState), 261 VMSTATE_END_OF_LIST() 262 } 263}; 264 265static Property ibex_timer_properties[] = { 266 DEFINE_PROP_UINT32("timebase-freq", IbexTimerState, timebase_freq, 10000), 267 DEFINE_PROP_END_OF_LIST(), 268}; 269 270static void ibex_timer_init(Object *obj) 271{ 272 IbexTimerState *s = IBEX_TIMER(obj); 273 274 sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); 275 276 memory_region_init_io(&s->mmio, obj, &ibex_timer_ops, s, 277 TYPE_IBEX_TIMER, 0x400); 278 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 279} 280 281static void ibex_timer_realize(DeviceState *dev, Error **errp) 282{ 283 IbexTimerState *s = IBEX_TIMER(dev); 284 285 qdev_init_gpio_out(dev, &s->m_timer_irq, 1); 286} 287 288 289static void ibex_timer_class_init(ObjectClass *klass, void *data) 290{ 291 DeviceClass *dc = DEVICE_CLASS(klass); 292 293 dc->reset = ibex_timer_reset; 294 dc->vmsd = &vmstate_ibex_timer; 295 dc->realize = ibex_timer_realize; 296 device_class_set_props(dc, ibex_timer_properties); 297} 298 299static const TypeInfo ibex_timer_info = { 300 .name = TYPE_IBEX_TIMER, 301 .parent = TYPE_SYS_BUS_DEVICE, 302 .instance_size = sizeof(IbexTimerState), 303 .instance_init = ibex_timer_init, 304 .class_init = ibex_timer_class_init, 305}; 306 307static void ibex_timer_register_types(void) 308{ 309 type_register_static(&ibex_timer_info); 310} 311 312type_init(ibex_timer_register_types)