* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+
+#include "qemu/osdep.h"
#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
+#include "sysemu/reset.h"
+#include "sysemu/runstate.h"
+#include "qemu/module.h"
#include "qemu/timer.h"
+#include "hw/irq.h"
#include "hw/ptimer.h"
+#include "qom/object.h"
#define D(x)
#define R_INTR 0x50
#define R_MASKED_INTR 0x54
-struct etrax_timer {
- SysBusDevice busdev;
+#define TYPE_ETRAX_FS_TIMER "etraxfs,timer"
+typedef struct ETRAXTimerState ETRAXTimerState;
+DECLARE_INSTANCE_CHECKER(ETRAXTimerState, ETRAX_TIMER,
+ TYPE_ETRAX_FS_TIMER)
+
+struct ETRAXTimerState {
+ SysBusDevice parent_obj;
+
MemoryRegion mmio;
qemu_irq irq;
qemu_irq nmi;
- QEMUBH *bh_t0;
- QEMUBH *bh_t1;
- QEMUBH *bh_wd;
ptimer_state *ptimer_t0;
ptimer_state *ptimer_t1;
ptimer_state *ptimer_wd;
static uint64_t
timer_read(void *opaque, hwaddr addr, unsigned int size)
{
- struct etrax_timer *t = opaque;
+ ETRAXTimerState *t = opaque;
uint32_t r = 0;
switch (addr) {
r = ptimer_get_count(t->ptimer_t1);
break;
case R_TIME:
- r = qemu_get_clock_ns(vm_clock) / 10;
+ r = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 10;
break;
case RW_INTR_MASK:
r = t->rw_intr_mask;
return r;
}
-static void update_ctrl(struct etrax_timer *t, int tnum)
+static void update_ctrl(ETRAXTimerState *t, int tnum)
{
unsigned int op;
unsigned int freq;
}
D(printf ("freq_hz=%d div=%d\n", freq_hz, div));
+ ptimer_transaction_begin(timer);
ptimer_set_freq(timer, freq_hz);
ptimer_set_limit(timer, div, 0);
abort();
break;
}
+ ptimer_transaction_commit(timer);
}
-static void timer_update_irq(struct etrax_timer *t)
+static void timer_update_irq(ETRAXTimerState *t)
{
t->r_intr &= ~(t->rw_ack_intr);
t->r_masked_intr = t->r_intr & t->rw_intr_mask;
static void timer0_hit(void *opaque)
{
- struct etrax_timer *t = opaque;
+ ETRAXTimerState *t = opaque;
t->r_intr |= 1;
timer_update_irq(t);
}
static void timer1_hit(void *opaque)
{
- struct etrax_timer *t = opaque;
+ ETRAXTimerState *t = opaque;
t->r_intr |= 2;
timer_update_irq(t);
}
static void watchdog_hit(void *opaque)
{
- struct etrax_timer *t = opaque;
+ ETRAXTimerState *t = opaque;
if (t->wd_hits == 0) {
/* real hw gives a single tick before reseting but we are
a bit friendlier to compensate for our slower execution. */
qemu_irq_raise(t->nmi);
}
else
- qemu_system_reset_request();
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
t->wd_hits++;
}
-static inline void timer_watchdog_update(struct etrax_timer *t, uint32_t value)
+static inline void timer_watchdog_update(ETRAXTimerState *t, uint32_t value)
{
unsigned int wd_en = t->rw_wd_ctrl & (1 << 8);
unsigned int wd_key = t->rw_wd_ctrl >> 9;
t->wd_hits = 0;
+ ptimer_transaction_begin(t->ptimer_wd);
ptimer_set_freq(t->ptimer_wd, 760);
if (wd_cnt == 0)
wd_cnt = 256;
ptimer_stop(t->ptimer_wd);
t->rw_wd_ctrl = value;
+ ptimer_transaction_commit(t->ptimer_wd);
}
static void
timer_write(void *opaque, hwaddr addr,
uint64_t val64, unsigned int size)
{
- struct etrax_timer *t = opaque;
+ ETRAXTimerState *t = opaque;
uint32_t value = val64;
switch (addr)
static void etraxfs_timer_reset(void *opaque)
{
- struct etrax_timer *t = opaque;
+ ETRAXTimerState *t = opaque;
+ ptimer_transaction_begin(t->ptimer_t0);
ptimer_stop(t->ptimer_t0);
+ ptimer_transaction_commit(t->ptimer_t0);
+ ptimer_transaction_begin(t->ptimer_t1);
ptimer_stop(t->ptimer_t1);
+ ptimer_transaction_commit(t->ptimer_t1);
+ ptimer_transaction_begin(t->ptimer_wd);
ptimer_stop(t->ptimer_wd);
+ ptimer_transaction_commit(t->ptimer_wd);
t->rw_wd_ctrl = 0;
t->r_intr = 0;
t->rw_intr_mask = 0;
qemu_irq_lower(t->irq);
}
-static int etraxfs_timer_init(SysBusDevice *dev)
+static void etraxfs_timer_realize(DeviceState *dev, Error **errp)
{
- struct etrax_timer *t = FROM_SYSBUS(typeof (*t), dev);
+ ETRAXTimerState *t = ETRAX_TIMER(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- t->bh_t0 = qemu_bh_new(timer0_hit, t);
- t->bh_t1 = qemu_bh_new(timer1_hit, t);
- t->bh_wd = qemu_bh_new(watchdog_hit, t);
- t->ptimer_t0 = ptimer_init(t->bh_t0);
- t->ptimer_t1 = ptimer_init(t->bh_t1);
- t->ptimer_wd = ptimer_init(t->bh_wd);
+ t->ptimer_t0 = ptimer_init(timer0_hit, t, PTIMER_POLICY_DEFAULT);
+ t->ptimer_t1 = ptimer_init(timer1_hit, t, PTIMER_POLICY_DEFAULT);
+ t->ptimer_wd = ptimer_init(watchdog_hit, t, PTIMER_POLICY_DEFAULT);
- sysbus_init_irq(dev, &t->irq);
- sysbus_init_irq(dev, &t->nmi);
+ sysbus_init_irq(sbd, &t->irq);
+ sysbus_init_irq(sbd, &t->nmi);
memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t,
"etraxfs-timer", 0x5c);
- sysbus_init_mmio(dev, &t->mmio);
+ sysbus_init_mmio(sbd, &t->mmio);
qemu_register_reset(etraxfs_timer_reset, t);
- return 0;
}
static void etraxfs_timer_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
- sdc->init = etraxfs_timer_init;
+ dc->realize = etraxfs_timer_realize;
}
static const TypeInfo etraxfs_timer_info = {
- .name = "etraxfs,timer",
+ .name = TYPE_ETRAX_FS_TIMER,
.parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof (struct etrax_timer),
+ .instance_size = sizeof(ETRAXTimerState),
.class_init = etraxfs_timer_class_init,
};