target-arm queue:

* raspi: add model of cprman clock manager
  * sbsa-ref: add an SBSA generic watchdog device
  * arm/trace: Fix hex printing
  * raspi: Add models of Pi 3 model A+, Pi Zero and Pi A+
  * hw/arm/smmuv3: Set the restoration priority of the vSMMUv3 explicitly
  * Nuvoton NPCM7xx: Add USB, RNG, GPIO and watchdog support
  * hw/arm: fix min_cpus for xlnx-versal-virt platform
  * hw/arm/highbank: Silence warnings about missing fallthrough statements
  * linux-user: Support Aarch64 BTI
  * Armv7M systick: fix corner case bugs by rewriting to use ptimer
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAl+YBA4ZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3rWRD/9hqjzL4d7xKcFQdQdRXsxv
 7zX82arHdxg9pNvusie/tuhX0PLswQ8TPEHEBVQvngxF7y/HqLBFuZAQvFf4ou6R
 9+myTXE2RuWHOYKlrr/M6p4csABXNMm7PiA3VMeKcTEh4DoamLyBz6j1X4obPiA+
 tLaRw4azzYAZnHoCaF6BX+4uf4bQZoqAtAS4IodJAAbDXJStl0VUFoS34MPhgW6/
 dwGF8DbQJVYRqa7xEXck4Yx7dkx13I66+iYUf9kCyoCkdyz1sIq58fbKhXQP4lqN
 I3e5XGBVJfeku7w/TGOpsw8OCyTng0z636iglfLVOrsj5N03fT8j72ehY7jJsN9f
 CgHvQ1JAX1DvA/v23oxs3WccwAOfJJsOERtf9QxyMbTR1czCeIY1LYMnkOFtyL87
 6IQpwM0WF1z4lja0dmrvhKJWjqn+kVI2cDtxrprsulCHi+pcIdJMq8vJDfxjpqqe
 SnDXVSAn8KjBrClaJRqHfbi+5ggsTwsLpBtEToQ4AOR342XVRfEY8IfTLb1D2+6q
 z99BFiyJtZ6iiJq5jgGMhppN6tEuHFK7Vr6IwhGDgFTchWb6by+K3i8/VzrbWVk9
 O+KEeO92dg6jVd+6FyXOPnJ3DcUXEp6EVUVrKBBUC+LTU8Lf1MCgeprjSi87UHIX
 xQg635uOQU3gxkqxCaE0XA==
 =OFlu
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20201027-1' into staging

target-arm queue:
 * raspi: add model of cprman clock manager
 * sbsa-ref: add an SBSA generic watchdog device
 * arm/trace: Fix hex printing
 * raspi: Add models of Pi 3 model A+, Pi Zero and Pi A+
 * hw/arm/smmuv3: Set the restoration priority of the vSMMUv3 explicitly
 * Nuvoton NPCM7xx: Add USB, RNG, GPIO and watchdog support
 * hw/arm: fix min_cpus for xlnx-versal-virt platform
 * hw/arm/highbank: Silence warnings about missing fallthrough statements
 * linux-user: Support Aarch64 BTI
 * Armv7M systick: fix corner case bugs by rewriting to use ptimer

# gpg: Signature made Tue 27 Oct 2020 11:27:10 GMT
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20201027-1: (48 commits)
  hw/timer/armv7m_systick: Rewrite to use ptimers
  hw/core/ptimer: Support ptimer being disabled by timer callback
  hw/arm/sbsa-ref: add SBSA watchdog device
  hw/watchdog: Implement SBSA watchdog device
  hw/arm/bcm2835_peripherals: connect the UART clock
  hw/char/pl011: add a clock input
  hw/misc/bcm2835_cprman: add sane reset values to the registers
  hw/misc/bcm2835_cprman: add the DSI0HSCK multiplexer
  hw/misc/bcm2835_cprman: implement clock mux behaviour
  hw/misc/bcm2835_cprman: add a clock mux skeleton implementation
  hw/misc/bcm2835_cprman: implement PLL channels behaviour
  hw/misc/bcm2835_cprman: add a PLL channel skeleton implementation
  hw/misc/bcm2835_cprman: implement PLLs behaviour
  hw/misc/bcm2835_cprman: add a PLL skeleton implementation
  hw/arm/raspi: add a skeleton implementation of the CPRMAN
  hw/arm/raspi: fix CPRMAN base address
  hw/core/clock: trace clock values in Hz instead of ns
  hw/core/clock: provide the VMSTATE_ARRAY_CLOCK macro
  arm/trace: Fix hex printing
  hw/arm/raspi: Add the Raspberry Pi 3 model A+
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-10-29 11:40:04 +00:00
commit 802427bcda
64 changed files with 5461 additions and 279 deletions

View file

@ -39,26 +39,6 @@ static inline int64_t systick_scale(SysTickState *s)
}
}
static void systick_reload(SysTickState *s, int reset)
{
/* The Cortex-M3 Devices Generic User Guide says that "When the
* ENABLE bit is set to 1, the counter loads the RELOAD value from the
* SYST RVR register and then counts down". So, we need to check the
* ENABLE bit before reloading the value.
*/
trace_systick_reload();
if ((s->control & SYSTICK_ENABLE) == 0) {
return;
}
if (reset) {
s->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
}
s->tick += (s->reload + 1) * systick_scale(s);
timer_mod(s->timer, s->tick);
}
static void systick_timer_tick(void *opaque)
{
SysTickState *s = (SysTickState *)opaque;
@ -70,10 +50,12 @@ static void systick_timer_tick(void *opaque)
/* Tell the NVIC to pend the SysTick exception */
qemu_irq_pulse(s->irq);
}
if (s->reload == 0) {
s->control &= ~SYSTICK_ENABLE;
} else {
systick_reload(s, 0);
if (ptimer_get_limit(s->ptimer) == 0) {
/*
* Timer expiry with SYST_RVR zero disables the timer
* (but doesn't clear SYST_CSR.ENABLE)
*/
ptimer_stop(s->ptimer);
}
}
@ -94,30 +76,11 @@ static MemTxResult systick_read(void *opaque, hwaddr addr, uint64_t *data,
s->control &= ~SYSTICK_COUNTFLAG;
break;
case 0x4: /* SysTick Reload Value. */
val = s->reload;
val = ptimer_get_limit(s->ptimer);
break;
case 0x8: /* SysTick Current Value. */
{
int64_t t;
if ((s->control & SYSTICK_ENABLE) == 0) {
val = 0;
break;
}
t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
if (t >= s->tick) {
val = 0;
break;
}
val = ((s->tick - (t + 1)) / systick_scale(s)) + 1;
/* The interrupt in triggered when the timer reaches zero.
However the counter is not reloaded until the next clock
tick. This is a hack to return zero during the first tick. */
if (val > s->reload) {
val = 0;
}
val = ptimer_get_count(s->ptimer);
break;
}
case 0xc: /* SysTick Calibration Value. */
val = 10000;
break;
@ -149,39 +112,50 @@ static MemTxResult systick_write(void *opaque, hwaddr addr,
switch (addr) {
case 0x0: /* SysTick Control and Status. */
{
uint32_t oldval = s->control;
uint32_t oldval;
ptimer_transaction_begin(s->ptimer);
oldval = s->control;
s->control &= 0xfffffff8;
s->control |= value & 7;
if ((oldval ^ value) & SYSTICK_ENABLE) {
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
if (value & SYSTICK_ENABLE) {
if (s->tick) {
s->tick += now;
timer_mod(s->timer, s->tick);
} else {
systick_reload(s, 1);
}
/*
* Always reload the period in case board code has
* changed system_clock_scale. If we ever replace that
* global with a more sensible API then we might be able
* to set the period only when it actually changes.
*/
ptimer_set_period(s->ptimer, systick_scale(s));
ptimer_run(s->ptimer, 0);
} else {
timer_del(s->timer);
s->tick -= now;
if (s->tick < 0) {
s->tick = 0;
}
ptimer_stop(s->ptimer);
}
} else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
/* This is a hack. Force the timer to be reloaded
when the reference clock is changed. */
systick_reload(s, 1);
ptimer_set_period(s->ptimer, systick_scale(s));
}
ptimer_transaction_commit(s->ptimer);
break;
}
case 0x4: /* SysTick Reload Value. */
s->reload = value;
ptimer_transaction_begin(s->ptimer);
ptimer_set_limit(s->ptimer, value & 0xffffff, 0);
ptimer_transaction_commit(s->ptimer);
break;
case 0x8: /* SysTick Current Value. Writes reload the timer. */
systick_reload(s, 1);
case 0x8: /* SysTick Current Value. */
/*
* Writing any value clears SYST_CVR to zero and clears
* SYST_CSR.COUNTFLAG. The counter will then reload from SYST_RVR
* on the next clock edge unless SYST_RVR is zero.
*/
ptimer_transaction_begin(s->ptimer);
if (ptimer_get_limit(s->ptimer) == 0) {
ptimer_stop(s->ptimer);
}
ptimer_set_count(s->ptimer, 0);
s->control &= ~SYSTICK_COUNTFLAG;
ptimer_transaction_commit(s->ptimer);
break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
@ -210,10 +184,13 @@ static void systick_reset(DeviceState *dev)
*/
assert(system_clock_scale != 0);
ptimer_transaction_begin(s->ptimer);
s->control = 0;
s->reload = 0;
s->tick = 0;
timer_del(s->timer);
ptimer_stop(s->ptimer);
ptimer_set_count(s->ptimer, 0);
ptimer_set_limit(s->ptimer, 0, 0);
ptimer_set_period(s->ptimer, systick_scale(s));
ptimer_transaction_commit(s->ptimer);
}
static void systick_instance_init(Object *obj)
@ -229,18 +206,21 @@ static void systick_instance_init(Object *obj)
static void systick_realize(DeviceState *dev, Error **errp)
{
SysTickState *s = SYSTICK(dev);
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, systick_timer_tick, s);
s->ptimer = ptimer_init(systick_timer_tick, s,
PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
PTIMER_POLICY_NO_COUNTER_ROUND_DOWN |
PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT);
}
static const VMStateDescription vmstate_systick = {
.name = "armv7m_systick",
.version_id = 1,
.minimum_version_id = 1,
.version_id = 2,
.minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_UINT32(control, SysTickState),
VMSTATE_UINT32(reload, SysTickState),
VMSTATE_INT64(tick, SysTickState),
VMSTATE_TIMER_PTR(timer, SysTickState),
VMSTATE_PTIMER(ptimer, SysTickState),
VMSTATE_END_OF_LIST()
}
};

View file

@ -17,6 +17,7 @@
#include "qemu/osdep.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "hw/misc/npcm7xx_clk.h"
#include "hw/timer/npcm7xx_timer.h"
#include "migration/vmstate.h"
@ -60,6 +61,50 @@ enum NPCM7xxTimerRegisters {
#define NPCM7XX_TCSR_PRESCALE_START 0
#define NPCM7XX_TCSR_PRESCALE_LEN 8
#define NPCM7XX_WTCR_WTCLK(rv) extract32(rv, 10, 2)
#define NPCM7XX_WTCR_FREEZE_EN BIT(9)
#define NPCM7XX_WTCR_WTE BIT(7)
#define NPCM7XX_WTCR_WTIE BIT(6)
#define NPCM7XX_WTCR_WTIS(rv) extract32(rv, 4, 2)
#define NPCM7XX_WTCR_WTIF BIT(3)
#define NPCM7XX_WTCR_WTRF BIT(2)
#define NPCM7XX_WTCR_WTRE BIT(1)
#define NPCM7XX_WTCR_WTR BIT(0)
/*
* The number of clock cycles between interrupt and reset in watchdog, used
* by the software to handle the interrupt before system is reset.
*/
#define NPCM7XX_WATCHDOG_INTERRUPT_TO_RESET_CYCLES 1024
/* Start or resume the timer. */
static void npcm7xx_timer_start(NPCM7xxBaseTimer *t)
{
int64_t now;
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
t->expires_ns = now + t->remaining_ns;
timer_mod(&t->qtimer, t->expires_ns);
}
/* Stop counting. Record the time remaining so we can continue later. */
static void npcm7xx_timer_pause(NPCM7xxBaseTimer *t)
{
int64_t now;
timer_del(&t->qtimer);
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
t->remaining_ns = t->expires_ns - now;
}
/* Delete the timer and reset it to default state. */
static void npcm7xx_timer_clear(NPCM7xxBaseTimer *t)
{
timer_del(&t->qtimer);
t->expires_ns = 0;
t->remaining_ns = 0;
}
/*
* Returns the index of timer in the tc->timer array. This can be used to
* locate the registers that belong to this timer.
@ -102,6 +147,52 @@ static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
return count;
}
static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
{
switch (NPCM7XX_WTCR_WTCLK(t->wtcr)) {
case 0:
return 1;
case 1:
return 256;
case 2:
return 2048;
case 3:
return 65536;
default:
g_assert_not_reached();
}
}
static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
int64_t cycles)
{
uint32_t prescaler = npcm7xx_watchdog_timer_prescaler(t);
int64_t ns = (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ) * cycles;
/*
* The reset function always clears the current timer. The caller of the
* this needs to decide whether to start the watchdog timer based on
* specific flag in WTCR.
*/
npcm7xx_timer_clear(&t->base_timer);
ns *= prescaler;
t->base_timer.remaining_ns = ns;
}
static void npcm7xx_watchdog_timer_reset(NPCM7xxWatchdogTimer *t)
{
int64_t cycles = 1;
uint32_t s = NPCM7XX_WTCR_WTIS(t->wtcr);
g_assert(s <= 3);
cycles <<= NPCM7XX_WATCHDOG_BASETIME_SHIFT;
cycles <<= 2 * s;
npcm7xx_watchdog_timer_reset_cycles(t, cycles);
}
/*
* Raise the interrupt line if there's a pending interrupt and interrupts are
* enabled for this timer. If not, lower it.
@ -116,16 +207,6 @@ static void npcm7xx_timer_check_interrupt(NPCM7xxTimer *t)
trace_npcm7xx_timer_irq(DEVICE(tc)->canonical_path, index, pending);
}
/* Start or resume the timer. */
static void npcm7xx_timer_start(NPCM7xxTimer *t)
{
int64_t now;
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
t->expires_ns = now + t->remaining_ns;
timer_mod(&t->qtimer, t->expires_ns);
}
/*
* Called when the counter reaches zero. Sets the interrupt flag, and either
* restarts or disables the timer.
@ -138,9 +219,9 @@ static void npcm7xx_timer_reached_zero(NPCM7xxTimer *t)
tc->tisr |= BIT(index);
if (t->tcsr & NPCM7XX_TCSR_PERIODIC) {
t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
if (t->tcsr & NPCM7XX_TCSR_CEN) {
npcm7xx_timer_start(t);
npcm7xx_timer_start(&t->base_timer);
}
} else {
t->tcsr &= ~(NPCM7XX_TCSR_CEN | NPCM7XX_TCSR_CACT);
@ -149,18 +230,6 @@ static void npcm7xx_timer_reached_zero(NPCM7xxTimer *t)
npcm7xx_timer_check_interrupt(t);
}
/* Stop counting. Record the time remaining so we can continue later. */
static void npcm7xx_timer_pause(NPCM7xxTimer *t)
{
int64_t now;
timer_del(&t->qtimer);
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
t->remaining_ns = t->expires_ns - now;
if (t->remaining_ns <= 0) {
npcm7xx_timer_reached_zero(t);
}
}
/*
* Restart the timer from its initial value. If the timer was enabled and stays
@ -170,10 +239,10 @@ static void npcm7xx_timer_pause(NPCM7xxTimer *t)
*/
static void npcm7xx_timer_restart(NPCM7xxTimer *t, uint32_t old_tcsr)
{
t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) {
npcm7xx_timer_start(t);
npcm7xx_timer_start(&t->base_timer);
}
}
@ -184,10 +253,10 @@ static uint32_t npcm7xx_timer_read_tdr(NPCM7xxTimer *t)
if (t->tcsr & NPCM7XX_TCSR_CEN) {
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
return npcm7xx_timer_ns_to_count(t, t->expires_ns - now);
return npcm7xx_timer_ns_to_count(t, t->base_timer.expires_ns - now);
}
return npcm7xx_timer_ns_to_count(t, t->remaining_ns);
return npcm7xx_timer_ns_to_count(t, t->base_timer.remaining_ns);
}
static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
@ -219,9 +288,9 @@ static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
if (npcm7xx_tcsr_prescaler(old_tcsr) != npcm7xx_tcsr_prescaler(new_tcsr)) {
/* Recalculate time remaining based on the current TDR value. */
t->remaining_ns = npcm7xx_timer_count_to_ns(t, tdr);
t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, tdr);
if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) {
npcm7xx_timer_start(t);
npcm7xx_timer_start(&t->base_timer);
}
}
@ -235,10 +304,13 @@ static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
if ((old_tcsr ^ new_tcsr) & NPCM7XX_TCSR_CEN) {
if (new_tcsr & NPCM7XX_TCSR_CEN) {
t->tcsr |= NPCM7XX_TCSR_CACT;
npcm7xx_timer_start(t);
npcm7xx_timer_start(&t->base_timer);
} else {
t->tcsr &= ~NPCM7XX_TCSR_CACT;
npcm7xx_timer_pause(t);
npcm7xx_timer_pause(&t->base_timer);
if (t->base_timer.remaining_ns <= 0) {
npcm7xx_timer_reached_zero(t);
}
}
}
}
@ -259,9 +331,47 @@ static void npcm7xx_timer_write_tisr(NPCM7xxTimerCtrlState *s, uint32_t value)
if (value & (1U << i)) {
npcm7xx_timer_check_interrupt(&s->timer[i]);
}
}
}
static void npcm7xx_timer_write_wtcr(NPCM7xxWatchdogTimer *t, uint32_t new_wtcr)
{
uint32_t old_wtcr = t->wtcr;
/*
* WTIF and WTRF are cleared by writing 1. Writing 0 makes these bits
* unchanged.
*/
if (new_wtcr & NPCM7XX_WTCR_WTIF) {
new_wtcr &= ~NPCM7XX_WTCR_WTIF;
} else if (old_wtcr & NPCM7XX_WTCR_WTIF) {
new_wtcr |= NPCM7XX_WTCR_WTIF;
}
if (new_wtcr & NPCM7XX_WTCR_WTRF) {
new_wtcr &= ~NPCM7XX_WTCR_WTRF;
} else if (old_wtcr & NPCM7XX_WTCR_WTRF) {
new_wtcr |= NPCM7XX_WTCR_WTRF;
}
t->wtcr = new_wtcr;
if (new_wtcr & NPCM7XX_WTCR_WTR) {
t->wtcr &= ~NPCM7XX_WTCR_WTR;
npcm7xx_watchdog_timer_reset(t);
if (new_wtcr & NPCM7XX_WTCR_WTE) {
npcm7xx_timer_start(&t->base_timer);
}
} else if ((old_wtcr ^ new_wtcr) & NPCM7XX_WTCR_WTE) {
if (new_wtcr & NPCM7XX_WTCR_WTE) {
npcm7xx_timer_start(&t->base_timer);
} else {
npcm7xx_timer_pause(&t->base_timer);
}
}
}
static hwaddr npcm7xx_tcsr_index(hwaddr reg)
{
switch (reg) {
@ -353,7 +463,7 @@ static uint64_t npcm7xx_timer_read(void *opaque, hwaddr offset, unsigned size)
break;
case NPCM7XX_TIMER_WTCR:
value = s->wtcr;
value = s->watchdog_timer.wtcr;
break;
default:
@ -409,8 +519,7 @@ static void npcm7xx_timer_write(void *opaque, hwaddr offset,
return;
case NPCM7XX_TIMER_WTCR:
qemu_log_mask(LOG_UNIMP, "%s: WTCR write not implemented: 0x%08x\n",
__func__, value);
npcm7xx_timer_write_wtcr(&s->watchdog_timer, value);
return;
}
@ -448,15 +557,42 @@ static void npcm7xx_timer_enter_reset(Object *obj, ResetType type)
for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
NPCM7xxTimer *t = &s->timer[i];
timer_del(&t->qtimer);
t->expires_ns = 0;
t->remaining_ns = 0;
npcm7xx_timer_clear(&t->base_timer);
t->tcsr = 0x00000005;
t->ticr = 0x00000000;
}
s->tisr = 0x00000000;
s->wtcr = 0x00000400;
/*
* Set WTCLK to 1(default) and reset all flags except WTRF.
* WTRF is not reset during a core domain reset.
*/
s->watchdog_timer.wtcr = 0x00000400 | (s->watchdog_timer.wtcr &
NPCM7XX_WTCR_WTRF);
}
static void npcm7xx_watchdog_timer_expired(void *opaque)
{
NPCM7xxWatchdogTimer *t = opaque;
if (t->wtcr & NPCM7XX_WTCR_WTE) {
if (t->wtcr & NPCM7XX_WTCR_WTIF) {
if (t->wtcr & NPCM7XX_WTCR_WTRE) {
t->wtcr |= NPCM7XX_WTCR_WTRF;
/* send reset signal to CLK module*/
qemu_irq_raise(t->reset_signal);
}
} else {
t->wtcr |= NPCM7XX_WTCR_WTIF;
if (t->wtcr & NPCM7XX_WTCR_WTIE) {
/* send interrupt */
qemu_irq_raise(t->irq);
}
npcm7xx_watchdog_timer_reset_cycles(t,
NPCM7XX_WATCHDOG_INTERRUPT_TO_RESET_CYCLES);
npcm7xx_timer_start(&t->base_timer);
}
}
}
static void npcm7xx_timer_hold_reset(Object *obj)
@ -467,6 +603,7 @@ static void npcm7xx_timer_hold_reset(Object *obj)
for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
qemu_irq_lower(s->timer[i].irq);
}
qemu_irq_lower(s->watchdog_timer.irq);
}
static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
@ -474,43 +611,80 @@ static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(dev);
SysBusDevice *sbd = &s->parent;
int i;
NPCM7xxWatchdogTimer *w;
for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
NPCM7xxTimer *t = &s->timer[i];
t->ctrl = s;
timer_init_ns(&t->qtimer, QEMU_CLOCK_VIRTUAL, npcm7xx_timer_expired, t);
timer_init_ns(&t->base_timer.qtimer, QEMU_CLOCK_VIRTUAL,
npcm7xx_timer_expired, t);
sysbus_init_irq(sbd, &t->irq);
}
w = &s->watchdog_timer;
w->ctrl = s;
timer_init_ns(&w->base_timer.qtimer, QEMU_CLOCK_VIRTUAL,
npcm7xx_watchdog_timer_expired, w);
sysbus_init_irq(sbd, &w->irq);
memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_timer_ops, s,
TYPE_NPCM7XX_TIMER, 4 * KiB);
sysbus_init_mmio(sbd, &s->iomem);
qdev_init_gpio_out_named(dev, &w->reset_signal,
NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 1);
}
static const VMStateDescription vmstate_npcm7xx_timer = {
.name = "npcm7xx-timer",
static const VMStateDescription vmstate_npcm7xx_base_timer = {
.name = "npcm7xx-base-timer",
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_TIMER(qtimer, NPCM7xxTimer),
VMSTATE_INT64(expires_ns, NPCM7xxTimer),
VMSTATE_INT64(remaining_ns, NPCM7xxTimer),
VMSTATE_TIMER(qtimer, NPCM7xxBaseTimer),
VMSTATE_INT64(expires_ns, NPCM7xxBaseTimer),
VMSTATE_INT64(remaining_ns, NPCM7xxBaseTimer),
VMSTATE_END_OF_LIST(),
},
};
static const VMStateDescription vmstate_npcm7xx_timer = {
.name = "npcm7xx-timer",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(base_timer, NPCM7xxTimer,
0, vmstate_npcm7xx_base_timer,
NPCM7xxBaseTimer),
VMSTATE_UINT32(tcsr, NPCM7xxTimer),
VMSTATE_UINT32(ticr, NPCM7xxTimer),
VMSTATE_END_OF_LIST(),
},
};
static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
.name = "npcm7xx-timer-ctrl",
static const VMStateDescription vmstate_npcm7xx_watchdog_timer = {
.name = "npcm7xx-watchdog-timer",
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(base_timer, NPCM7xxWatchdogTimer,
0, vmstate_npcm7xx_base_timer,
NPCM7xxBaseTimer),
VMSTATE_UINT32(wtcr, NPCM7xxWatchdogTimer),
VMSTATE_END_OF_LIST(),
},
};
static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
.name = "npcm7xx-timer-ctrl",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(tisr, NPCM7xxTimerCtrlState),
VMSTATE_UINT32(wtcr, NPCM7xxTimerCtrlState),
VMSTATE_STRUCT_ARRAY(timer, NPCM7xxTimerCtrlState,
NPCM7XX_TIMERS_PER_CTRL, 0, vmstate_npcm7xx_timer,
NPCM7xxTimer),
VMSTATE_STRUCT(watchdog_timer, NPCM7xxTimerCtrlState,
0, vmstate_npcm7xx_watchdog_timer,
NPCM7xxWatchdogTimer),
VMSTATE_END_OF_LIST(),
},
};