On Wed, Jun 9, 2021 at 11:44 AM Bin Meng <bmeng...@gmail.com> wrote: > > On Wed, Jun 9, 2021 at 7:49 AM Alistair Francis > <alistair.fran...@wdc.com> wrote: > > > > Add support for the Ibex timer. This is used with the RISC-V > > mtime/mtimecmp similar to the SiFive CLINT. > > > > We currently don't support changing the prescale or the timervalue. > > > > Signed-off-by: Alistair Francis <alistair.fran...@wdc.com> > > --- > > include/hw/timer/ibex_timer.h | 52 ++++++ > > hw/timer/ibex_timer.c | 305 ++++++++++++++++++++++++++++++++++ > > MAINTAINERS | 6 +- > > hw/timer/meson.build | 1 + > > 4 files changed, 360 insertions(+), 4 deletions(-) > > create mode 100644 include/hw/timer/ibex_timer.h > > create mode 100644 hw/timer/ibex_timer.c > > > > diff --git a/include/hw/timer/ibex_timer.h b/include/hw/timer/ibex_timer.h > > new file mode 100644 > > index 0000000000..6a43537003 > > --- /dev/null > > +++ b/include/hw/timer/ibex_timer.h > > @@ -0,0 +1,52 @@ > > +/* > > + * QEMU lowRISC Ibex Timer device > > + * > > + * Copyright (c) 2021 Western Digital > > + * > > + * Permission is hereby granted, free of charge, to any person obtaining a > > copy > > + * of this software and associated documentation files (the "Software"), > > to deal > > + * in the Software without restriction, including without limitation the > > rights > > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or > > sell > > + * copies of the Software, and to permit persons to whom the Software is > > + * furnished to do so, subject to the following conditions: > > + * > > + * The above copyright notice and this permission notice shall be included > > in > > + * all copies or substantial portions of the Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS > > OR > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR > > OTHER > > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > > FROM, > > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > > IN > > + * THE SOFTWARE. > > + */ > > + > > +#ifndef HW_IBEX_TIMER_H > > +#define HW_IBEX_TIMER_H > > + > > +#include "hw/sysbus.h" > > + > > +#define TYPE_IBEX_TIMER "ibex-timer" > > +OBJECT_DECLARE_SIMPLE_TYPE(IbexTimerState, IBEX_TIMER) > > + > > +struct IbexTimerState { > > + /* <private> */ > > + SysBusDevice parent_obj; > > + > > + /* <public> */ > > + MemoryRegion mmio; > > + > > + uint32_t timer_ctrl; > > + uint32_t timer_cfg0; > > + uint32_t timer_compare_lower0; > > + uint32_t timer_compare_upper0; > > + uint32_t timer_intr_enable; > > + uint32_t timer_intr_state; > > + uint32_t timer_intr_test; > > + > > + uint32_t timebase_freq; > > + > > + qemu_irq irq; > > +}; > > +#endif /* HW_IBEX_TIMER_H */ > > diff --git a/hw/timer/ibex_timer.c b/hw/timer/ibex_timer.c > > new file mode 100644 > > index 0000000000..4d55eb5088 > > --- /dev/null > > +++ b/hw/timer/ibex_timer.c > > @@ -0,0 +1,305 @@ > > +/* > > + * QEMU lowRISC Ibex Timer device > > + * > > + * Copyright (c) 2021 Western Digital > > + * > > + * For details check the documentation here: > > + * https://docs.opentitan.org/hw/ip/rv_timer/doc/ > > + * > > + * Permission is hereby granted, free of charge, to any person obtaining a > > copy > > + * of this software and associated documentation files (the "Software"), > > to deal > > + * in the Software without restriction, including without limitation the > > rights > > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or > > sell > > + * copies of the Software, and to permit persons to whom the Software is > > + * furnished to do so, subject to the following conditions: > > + * > > + * The above copyright notice and this permission notice shall be included > > in > > + * all copies or substantial portions of the Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS > > OR > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR > > OTHER > > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > > FROM, > > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > > IN > > + * THE SOFTWARE. > > + */ > > + > > +#include "qemu/osdep.h" > > +#include "qemu/log.h" > > +#include "qemu/timer.h" > > +#include "hw/timer/ibex_timer.h" > > +#include "hw/irq.h" > > +#include "hw/qdev-properties.h" > > +#include "target/riscv/cpu.h" > > +#include "migration/vmstate.h" > > + > > +REG32(CTRL, 0x00) > > + FIELD(CTRL, ACTIVE, 0, 1) > > +REG32(CFG0, 0x100) > > + FIELD(CFG0, PRESCALE, 0, 12) > > + FIELD(CFG0, STEP, 16, 8) > > +REG32(LOWER0, 0x104) > > +REG32(UPPER0, 0x108) > > +REG32(COMPARE_LOWER0, 0x10C) > > +REG32(COMPARE_UPPER0, 0x110) > > +REG32(INTR_ENABLE, 0x114) > > + FIELD(INTR_ENABLE, IE_0, 0, 1) > > +REG32(INTR_STATE, 0x118) > > + FIELD(INTR_STATE, IS_0, 0, 1) > > +REG32(INTR_TEST, 0x11C) > > + FIELD(INTR_TEST, T_0, 0, 1) > > + > > +static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq) > > +{ > > + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), > > + timebase_freq, NANOSECONDS_PER_SECOND); > > +} > > + > > +static void ibex_timer_update_irqs(IbexTimerState *s) > > +{ > > + CPUState *cs = qemu_get_cpu(0); > > + RISCVCPU *cpu = RISCV_CPU(cs); > > + uint64_t value = s->timer_compare_lower0 | > > + ((uint64_t)s->timer_compare_upper0 << 32); > > + uint64_t next, diff; > > + uint64_t now = cpu_riscv_read_rtc(s->timebase_freq); > > + > > + if (!(s->timer_ctrl & R_CTRL_ACTIVE_MASK)) { > > + /* Timer isn't active */ > > + return; > > + } > > + > > + /* Update the CPUs mtimecmp */ > > + cpu->env.timecmp = value; > > + > > + if (cpu->env.timecmp <= now) { > > + /* > > + * If the mtimecmp was in the past raise the interrupt now. > > + */ > > + riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1)); > > + if (s->timer_intr_enable & R_INTR_ENABLE_IE_0_MASK) { > > + s->timer_intr_state |= R_INTR_STATE_IS_0_MASK; > > + qemu_set_irq(s->irq, true); > > + } > > + return; > > + } > > + > > + /* Setup a timer to trigger the interrupt in the future */ > > + riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0)); > > + qemu_set_irq(s->irq, false); > > + > > + diff = cpu->env.timecmp - now; > > + next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + > > + muldiv64(diff, > > + NANOSECONDS_PER_SECOND, > > + s->timebase_freq); > > + > > + if (next < qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) { > > + /* We overflowed the timer, just set it as large as we can */ > > + timer_mod(cpu->env.timer, 0x07FFFFFFFFFFFFFF); > > Still not correct? should be 0x7FFFFFFFFFFFFFFF?
Argh! Thanks I have actually fixed this. Alistair > > > + } else { > > + timer_mod(cpu->env.timer, next); > > + } > > +} > > + > > Regards, > Bin