aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/arm/aspeed.c23
-rw-r--r--hw/arm/bcm2835_peripherals.c30
-rw-r--r--hw/arm/bcm2836.c44
-rw-r--r--hw/arm/highbank.c3
-rw-r--r--hw/arm/raspi.c14
-rw-r--r--hw/dma/xilinx_axidma.c9
-rw-r--r--hw/gpio/aspeed_gpio.c8
-rw-r--r--hw/intc/armv7m_nvic.c22
-rw-r--r--hw/m68k/mcf5206.c15
-rw-r--r--hw/misc/Makefile.objs1
-rw-r--r--hw/misc/bcm2835_thermal.c135
-rw-r--r--hw/net/fsl_etsec/etsec.c9
-rw-r--r--hw/net/fsl_etsec/etsec.h1
-rw-r--r--hw/timer/Makefile.objs1
-rw-r--r--hw/timer/bcm2835_systmr.c163
-rw-r--r--hw/timer/grlib_gptimer.c28
-rw-r--r--hw/timer/milkymist-sysctl.c25
-rw-r--r--hw/timer/slavio_timer.c32
-rw-r--r--hw/timer/trace-events5
-rw-r--r--hw/timer/xilinx_timer.c13
20 files changed, 497 insertions, 84 deletions
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 52993f8..028191f 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -88,6 +88,10 @@ struct AspeedBoardState {
/* Witherspoon hardware value: 0xF10AD216 (but use romulus definition) */
#define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1
+/* AST2600 evb hardware value */
+#define AST2600_EVB_HW_STRAP1 0x000000C0
+#define AST2600_EVB_HW_STRAP2 0x00000003
+
/*
* The max ram region is for firmwares that scan the address space
* with load/store to guess how much RAM the SoC has.
@@ -187,6 +191,8 @@ static void aspeed_board_init(MachineState *machine,
&error_abort);
object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap1, "hw-strap1",
&error_abort);
+ object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap2, "hw-strap2",
+ &error_abort);
object_property_set_int(OBJECT(&bmc->soc), cfg->num_cs, "num-cs",
&error_abort);
object_property_set_int(OBJECT(&bmc->soc), machine->smp.cpus, "num-cpus",
@@ -308,6 +314,12 @@ static void ast2500_evb_i2c_init(AspeedBoardState *bmc)
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32);
}
+static void ast2600_evb_i2c_init(AspeedBoardState *bmc)
+{
+ /* Start with some devices on our I2C busses */
+ ast2500_evb_i2c_init(bmc);
+}
+
static void romulus_bmc_i2c_init(AspeedBoardState *bmc)
{
AspeedSoCState *soc = &bmc->soc;
@@ -455,6 +467,17 @@ static const AspeedBoardConfig aspeed_boards[] = {
.num_cs = 2,
.i2c_init = witherspoon_bmc_i2c_init,
.ram = 512 * MiB,
+ }, {
+ .name = MACHINE_TYPE_NAME("ast2600-evb"),
+ .desc = "Aspeed AST2600 EVB (Cortex A7)",
+ .soc_name = "ast2600-a0",
+ .hw_strap1 = AST2600_EVB_HW_STRAP1,
+ .hw_strap2 = AST2600_EVB_HW_STRAP2,
+ .fmc_model = "w25q512jv",
+ .spi_model = "mx66u51235f",
+ .num_cs = 1,
+ .i2c_init = ast2600_evb_i2c_init,
+ .ram = 1 * GiB,
},
};
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
index fdcf616..17207ae 100644
--- a/hw/arm/bcm2835_peripherals.c
+++ b/hw/arm/bcm2835_peripherals.c
@@ -58,6 +58,10 @@ static void bcm2835_peripherals_init(Object *obj)
/* Interrupt Controller */
sysbus_init_child_obj(obj, "ic", &s->ic, sizeof(s->ic), TYPE_BCM2835_IC);
+ /* SYS Timer */
+ sysbus_init_child_obj(obj, "systimer", &s->systmr, sizeof(s->systmr),
+ TYPE_BCM2835_SYSTIMER);
+
/* UART0 */
sysbus_init_child_obj(obj, "uart0", &s->uart0, sizeof(s->uart0),
TYPE_PL011);
@@ -111,6 +115,10 @@ static void bcm2835_peripherals_init(Object *obj)
object_property_add_const_link(OBJECT(&s->dma), "dma-mr",
OBJECT(&s->gpu_bus_mr), &error_abort);
+ /* Thermal */
+ sysbus_init_child_obj(obj, "thermal", &s->thermal, sizeof(s->thermal),
+ TYPE_BCM2835_THERMAL);
+
/* GPIO */
sysbus_init_child_obj(obj, "gpio", &s->gpio, sizeof(s->gpio),
TYPE_BCM2835_GPIO);
@@ -167,6 +175,18 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0));
sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic));
+ /* Sys Timer */
+ object_property_set_bool(OBJECT(&s->systmr), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ memory_region_add_subregion(&s->peri_mr, ST_OFFSET,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systmr), 0));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->systmr), 0,
+ qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_ARM_IRQ,
+ INTERRUPT_ARM_TIMER));
+
/* UART0 */
qdev_prop_set_chr(DEVICE(&s->uart0), "chardev", serial_hd(0));
object_property_set_bool(OBJECT(&s->uart0), true, "realized", &err);
@@ -321,6 +341,15 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
INTERRUPT_DMA0 + n));
}
+ /* THERMAL */
+ object_property_set_bool(OBJECT(&s->thermal), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ memory_region_add_subregion(&s->peri_mr, THERMAL_OFFSET,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->thermal), 0));
+
/* GPIO */
object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err);
if (err) {
@@ -339,7 +368,6 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
}
create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40);
- create_unimp(s, &s->systmr, "bcm2835-systimer", ST_OFFSET, 0x20);
create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x1000);
create_unimp(s, &s->a2w, "bcm2835-a2w", A2W_OFFSET, 0x1000);
create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100);
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
index 723aef6..221ff06 100644
--- a/hw/arm/bcm2836.c
+++ b/hw/arm/bcm2836.c
@@ -16,15 +16,11 @@
#include "hw/arm/raspi_platform.h"
#include "hw/sysbus.h"
-/* Peripheral base address seen by the CPU */
-#define BCM2836_PERI_BASE 0x3F000000
-
-/* "QA7" (Pi2) interrupt controller and mailboxes etc. */
-#define BCM2836_CONTROL_BASE 0x40000000
-
struct BCM283XInfo {
const char *name;
const char *cpu_type;
+ hwaddr peri_base; /* Peripheral base address seen by the CPU */
+ hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */
int clusterid;
};
@@ -32,12 +28,16 @@ static const BCM283XInfo bcm283x_socs[] = {
{
.name = TYPE_BCM2836,
.cpu_type = ARM_CPU_TYPE_NAME("cortex-a7"),
+ .peri_base = 0x3f000000,
+ .ctrl_base = 0x40000000,
.clusterid = 0xf,
},
#ifdef TARGET_AARCH64
{
.name = TYPE_BCM2837,
.cpu_type = ARM_CPU_TYPE_NAME("cortex-a53"),
+ .peri_base = 0x3f000000,
+ .ctrl_base = 0x40000000,
.clusterid = 0x0,
},
#endif
@@ -51,8 +51,9 @@ static void bcm2836_init(Object *obj)
int n;
for (n = 0; n < BCM283X_NCPUS; n++) {
- object_initialize_child(obj, "cpu[*]", &s->cpus[n], sizeof(s->cpus[n]),
- info->cpu_type, &error_abort, NULL);
+ object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
+ sizeof(s->cpu[n].core), info->cpu_type,
+ &error_abort, NULL);
}
sysbus_init_child_obj(obj, "control", &s->control, sizeof(s->control),
@@ -104,7 +105,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
}
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
- BCM2836_PERI_BASE, 1);
+ info->peri_base, 1);
/* bcm2836 interrupt controller (and mailboxes, etc.) */
object_property_set_bool(OBJECT(&s->control), true, "realized", &err);
@@ -113,7 +114,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
return;
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, BCM2836_CONTROL_BASE);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, info->ctrl_base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0));
@@ -122,11 +123,11 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
for (n = 0; n < BCM283X_NCPUS; n++) {
/* TODO: this should be converted to a property of ARM_CPU */
- s->cpus[n].mp_affinity = (info->clusterid << 8) | n;
+ s->cpu[n].core.mp_affinity = (info->clusterid << 8) | n;
/* set periphbase/CBAR value for CPU-local registers */
- object_property_set_int(OBJECT(&s->cpus[n]),
- BCM2836_PERI_BASE + MSYNC_OFFSET,
+ object_property_set_int(OBJECT(&s->cpu[n].core),
+ info->peri_base,
"reset-cbar", &err);
if (err) {
error_propagate(errp, err);
@@ -134,14 +135,15 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
}
/* start powered off if not enabled */
- object_property_set_bool(OBJECT(&s->cpus[n]), n >= s->enabled_cpus,
+ object_property_set_bool(OBJECT(&s->cpu[n].core), n >= s->enabled_cpus,
"start-powered-off", &err);
if (err) {
error_propagate(errp, err);
return;
}
- object_property_set_bool(OBJECT(&s->cpus[n]), true, "realized", &err);
+ object_property_set_bool(OBJECT(&s->cpu[n].core), true,
+ "realized", &err);
if (err) {
error_propagate(errp, err);
return;
@@ -149,18 +151,18 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
/* Connect irq/fiq outputs from the interrupt controller. */
qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n,
- qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_IRQ));
+ qdev_get_gpio_in(DEVICE(&s->cpu[n].core), ARM_CPU_IRQ));
qdev_connect_gpio_out_named(DEVICE(&s->control), "fiq", n,
- qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_FIQ));
+ qdev_get_gpio_in(DEVICE(&s->cpu[n].core), ARM_CPU_FIQ));
/* Connect timers from the CPU to the interrupt controller */
- qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_PHYS,
+ qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_PHYS,
qdev_get_gpio_in_named(DEVICE(&s->control), "cntpnsirq", n));
- qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_VIRT,
+ qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_VIRT,
qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", n));
- qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_HYP,
+ qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_HYP,
qdev_get_gpio_in_named(DEVICE(&s->control), "cnthpirq", n));
- qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_SEC,
+ qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_SEC,
qdev_get_gpio_in_named(DEVICE(&s->control), "cntpsirq", n));
}
}
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
index f1724d6..518d935 100644
--- a/hw/arm/highbank.c
+++ b/hw/arm/highbank.c
@@ -78,7 +78,8 @@ static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
smpboot[n] = tswap32(smpboot[n]);
}
- rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR);
+ rom_add_blob_fixed_as("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR,
+ arm_boot_address_space(cpu, info));
}
static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
index 615d755..6a510aa 100644
--- a/hw/arm/raspi.c
+++ b/hw/arm/raspi.c
@@ -60,12 +60,14 @@ static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info)
QEMU_BUILD_BUG_ON((BOARDSETUP_ADDR & 0xf) != 0
|| (BOARDSETUP_ADDR >> 4) >= 0x100);
- rom_add_blob_fixed("raspi_smpboot", smpboot, sizeof(smpboot),
- info->smp_loader_start);
+ rom_add_blob_fixed_as("raspi_smpboot", smpboot, sizeof(smpboot),
+ info->smp_loader_start,
+ arm_boot_address_space(cpu, info));
}
static void write_smpboot64(ARMCPU *cpu, const struct arm_boot_info *info)
{
+ AddressSpace *as = arm_boot_address_space(cpu, info);
/* Unlike the AArch32 version we don't need to call the board setup hook.
* The mechanism for doing the spin-table is also entirely different.
* We must have four 64-bit fields at absolute addresses
@@ -92,10 +94,10 @@ static void write_smpboot64(ARMCPU *cpu, const struct arm_boot_info *info)
0, 0, 0, 0
};
- rom_add_blob_fixed("raspi_smpboot", smpboot, sizeof(smpboot),
- info->smp_loader_start);
- rom_add_blob_fixed("raspi_spintables", spintables, sizeof(spintables),
- SPINTABLE_ADDR);
+ rom_add_blob_fixed_as("raspi_smpboot", smpboot, sizeof(smpboot),
+ info->smp_loader_start, as);
+ rom_add_blob_fixed_as("raspi_spintables", spintables, sizeof(spintables),
+ SPINTABLE_ADDR, as);
}
static void write_board_setup(ARMCPU *cpu, const struct arm_boot_info *info)
diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c
index e035d1f..fb3a978 100644
--- a/hw/dma/xilinx_axidma.c
+++ b/hw/dma/xilinx_axidma.c
@@ -31,7 +31,6 @@
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
#include "qemu/log.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "hw/stream.h"
@@ -104,7 +103,6 @@ enum {
};
struct Stream {
- QEMUBH *bh;
ptimer_state *ptimer;
qemu_irq irq;
@@ -242,6 +240,7 @@ static void stream_complete(struct Stream *s)
unsigned int comp_delay;
/* Start the delayed timer. */
+ ptimer_transaction_begin(s->ptimer);
comp_delay = s->regs[R_DMACR] >> 24;
if (comp_delay) {
ptimer_stop(s->ptimer);
@@ -255,6 +254,7 @@ static void stream_complete(struct Stream *s)
s->regs[R_DMASR] |= DMASR_IOC_IRQ;
stream_reload_complete_cnt(s);
}
+ ptimer_transaction_commit(s->ptimer);
}
static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev,
@@ -551,9 +551,10 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
struct Stream *st = &s->streams[i];
st->nr = i;
- st->bh = qemu_bh_new(timer_hit, st);
- st->ptimer = ptimer_init_with_bh(st->bh, PTIMER_POLICY_DEFAULT);
+ st->ptimer = ptimer_init(timer_hit, st, PTIMER_POLICY_DEFAULT);
+ ptimer_transaction_begin(st->ptimer);
ptimer_set_freq(st->ptimer, s->freqhz);
+ ptimer_transaction_commit(st->ptimer);
}
return;
diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 196e47c..7acc5fa 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -733,13 +733,13 @@ static void aspeed_gpio_get_pin(Object *obj, Visitor *v, const char *name,
{
int pin = 0xfff;
bool level = true;
- char group[3];
+ char group[4];
AspeedGPIOState *s = ASPEED_GPIO(obj);
int set_idx, group_idx = 0;
if (sscanf(name, "gpio%2[A-Z]%1d", group, &pin) != 2) {
/* 1.8V gpio */
- if (sscanf(name, "gpio%3s%1d", group, &pin) != 2) {
+ if (sscanf(name, "gpio%3[18A-E]%1d", group, &pin) != 2) {
error_setg(errp, "%s: error reading %s", __func__, name);
return;
}
@@ -760,7 +760,7 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, const char *name,
Error *local_err = NULL;
bool level;
int pin = 0xfff;
- char group[3];
+ char group[4];
AspeedGPIOState *s = ASPEED_GPIO(obj);
int set_idx, group_idx = 0;
@@ -771,7 +771,7 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, const char *name,
}
if (sscanf(name, "gpio%2[A-Z]%1d", group, &pin) != 2) {
/* 1.8V gpio */
- if (sscanf(name, "gpio%3s%1d", group, &pin) != 2) {
+ if (sscanf(name, "gpio%3[18A-E]%1d", group, &pin) != 2) {
error_setg(errp, "%s: error reading %s", __func__, name);
return;
}
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 8e93e51..e8c74f9 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -2251,7 +2251,7 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
}
}
nvic_irq_update(s);
- return MEMTX_OK;
+ goto exit_ok;
case 0x200 ... 0x23f: /* NVIC Set pend */
/* the special logic in armv7m_nvic_set_pending()
* is not needed since IRQs are never escalated
@@ -2269,9 +2269,9 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
}
}
nvic_irq_update(s);
- return MEMTX_OK;
+ goto exit_ok;
case 0x300 ... 0x33f: /* NVIC Active */
- return MEMTX_OK; /* R/O */
+ goto exit_ok; /* R/O */
case 0x400 ... 0x5ef: /* NVIC Priority */
startvec = (offset - 0x400) + NVIC_FIRST_IRQ; /* vector # */
@@ -2281,10 +2281,10 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
}
}
nvic_irq_update(s);
- return MEMTX_OK;
+ goto exit_ok;
case 0xd18 ... 0xd1b: /* System Handler Priority (SHPR1) */
if (!arm_feature(&s->cpu->env, ARM_FEATURE_M_MAIN)) {
- return MEMTX_OK;
+ goto exit_ok;
}
/* fall through */
case 0xd1c ... 0xd23: /* System Handler Priority (SHPR2, SHPR3) */
@@ -2299,10 +2299,10 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
set_prio(s, hdlidx, sbank, newprio);
}
nvic_irq_update(s);
- return MEMTX_OK;
+ goto exit_ok;
case 0xd28 ... 0xd2b: /* Configurable Fault Status (CFSR) */
if (!arm_feature(&s->cpu->env, ARM_FEATURE_M_MAIN)) {
- return MEMTX_OK;
+ goto exit_ok;
}
/* All bits are W1C, so construct 32 bit value with 0s in
* the parts not written by the access size
@@ -2322,15 +2322,19 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
*/
s->cpu->env.v7m.cfsr[M_REG_NS] &= ~(value & R_V7M_CFSR_BFSR_MASK);
}
- return MEMTX_OK;
+ goto exit_ok;
}
if (size == 4) {
nvic_writel(s, offset, value, attrs);
- return MEMTX_OK;
+ goto exit_ok;
}
qemu_log_mask(LOG_GUEST_ERROR,
"NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
/* This is UNPREDICTABLE; treat as RAZ/WI */
+
+ exit_ok:
+ /* Ensure any changes made are reflected in the cached hflags. */
+ arm_rebuild_hflags(&s->cpu->env);
return MEMTX_OK;
}
diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c
index a490963..b155dd8 100644
--- a/hw/m68k/mcf5206.c
+++ b/hw/m68k/mcf5206.c
@@ -8,7 +8,6 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
-#include "qemu/main-loop.h"
#include "cpu.h"
#include "hw/hw.h"
#include "hw/irq.h"
@@ -57,10 +56,12 @@ static void m5206_timer_recalibrate(m5206_timer_state *s)
int prescale;
int mode;
+ ptimer_transaction_begin(s->timer);
ptimer_stop(s->timer);
- if ((s->tmr & TMR_RST) == 0)
- return;
+ if ((s->tmr & TMR_RST) == 0) {
+ goto exit;
+ }
prescale = (s->tmr >> 8) + 1;
mode = (s->tmr >> 1) & 3;
@@ -78,6 +79,8 @@ static void m5206_timer_recalibrate(m5206_timer_state *s)
ptimer_set_limit(s->timer, s->trr, 0);
ptimer_run(s->timer, 0);
+exit:
+ ptimer_transaction_commit(s->timer);
}
static void m5206_timer_trigger(void *opaque)
@@ -123,7 +126,9 @@ static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val)
s->tcr = val;
break;
case 0xc:
+ ptimer_transaction_begin(s->timer);
ptimer_set_count(s->timer, val);
+ ptimer_transaction_commit(s->timer);
break;
case 0x11:
s->ter &= ~val;
@@ -137,11 +142,9 @@ static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val)
static m5206_timer_state *m5206_timer_init(qemu_irq irq)
{
m5206_timer_state *s;
- QEMUBH *bh;
s = g_new0(m5206_timer_state, 1);
- bh = qemu_bh_new(m5206_timer_trigger, s);
- s->timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT);
+ s->timer = ptimer_init(m5206_timer_trigger, s, PTIMER_POLICY_DEFAULT);
s->irq = irq;
m5206_timer_reset(s);
return s;
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index a150680..c89f381 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -53,6 +53,7 @@ common-obj-$(CONFIG_OMAP) += omap_tap.o
common-obj-$(CONFIG_RASPI) += bcm2835_mbox.o
common-obj-$(CONFIG_RASPI) += bcm2835_property.o
common-obj-$(CONFIG_RASPI) += bcm2835_rng.o
+common-obj-$(CONFIG_RASPI) += bcm2835_thermal.o
common-obj-$(CONFIG_SLAVIO) += slavio_misc.o
common-obj-$(CONFIG_ZYNQ) += zynq_slcr.o
common-obj-$(CONFIG_ZYNQ) += zynq-xadc.o
diff --git a/hw/misc/bcm2835_thermal.c b/hw/misc/bcm2835_thermal.c
new file mode 100644
index 0000000..c6f3b1a
--- /dev/null
+++ b/hw/misc/bcm2835_thermal.c
@@ -0,0 +1,135 @@
+/*
+ * BCM2835 dummy thermal sensor
+ *
+ * Copyright (C) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "hw/misc/bcm2835_thermal.h"
+#include "hw/registerfields.h"
+#include "migration/vmstate.h"
+
+REG32(CTL, 0)
+FIELD(CTL, POWER_DOWN, 0, 1)
+FIELD(CTL, RESET, 1, 1)
+FIELD(CTL, BANDGAP_CTRL, 2, 3)
+FIELD(CTL, INTERRUPT_ENABLE, 5, 1)
+FIELD(CTL, DIRECT, 6, 1)
+FIELD(CTL, INTERRUPT_CLEAR, 7, 1)
+FIELD(CTL, HOLD, 8, 10)
+FIELD(CTL, RESET_DELAY, 18, 8)
+FIELD(CTL, REGULATOR_ENABLE, 26, 1)
+
+REG32(STAT, 4)
+FIELD(STAT, DATA, 0, 10)
+FIELD(STAT, VALID, 10, 1)
+FIELD(STAT, INTERRUPT, 11, 1)
+
+#define THERMAL_OFFSET_C 412
+#define THERMAL_COEFF (-0.538f)
+
+static uint16_t bcm2835_thermal_temp2adc(int temp_C)
+{
+ return (temp_C - THERMAL_OFFSET_C) / THERMAL_COEFF;
+}
+
+static uint64_t bcm2835_thermal_read(void *opaque, hwaddr addr, unsigned size)
+{
+ Bcm2835ThermalState *s = BCM2835_THERMAL(opaque);
+ uint32_t val = 0;
+
+ switch (addr) {
+ case A_CTL:
+ val = s->ctl;
+ break;
+ case A_STAT:
+ /* Temperature is constantly 25°C. */
+ val = FIELD_DP32(bcm2835_thermal_temp2adc(25), STAT, VALID, true);
+ break;
+ default:
+ /* MemoryRegionOps are aligned, so this can not happen. */
+ g_assert_not_reached();
+ }
+ return val;
+}
+
+static void bcm2835_thermal_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ Bcm2835ThermalState *s = BCM2835_THERMAL(opaque);
+
+ switch (addr) {
+ case A_CTL:
+ s->ctl = value;
+ break;
+ case A_STAT:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: write 0x%" PRIx64
+ " to 0x%" HWADDR_PRIx "\n",
+ __func__, value, addr);
+ break;
+ default:
+ /* MemoryRegionOps are aligned, so this can not happen. */
+ g_assert_not_reached();
+ }
+}
+
+static const MemoryRegionOps bcm2835_thermal_ops = {
+ .read = bcm2835_thermal_read,
+ .write = bcm2835_thermal_write,
+ .impl.max_access_size = 4,
+ .valid.min_access_size = 4,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void bcm2835_thermal_reset(DeviceState *dev)
+{
+ Bcm2835ThermalState *s = BCM2835_THERMAL(dev);
+
+ s->ctl = 0;
+}
+
+static void bcm2835_thermal_realize(DeviceState *dev, Error **errp)
+{
+ Bcm2835ThermalState *s = BCM2835_THERMAL(dev);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_thermal_ops,
+ s, TYPE_BCM2835_THERMAL, 8);
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
+}
+
+static const VMStateDescription bcm2835_thermal_vmstate = {
+ .name = "bcm2835_thermal",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(ctl, Bcm2835ThermalState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void bcm2835_thermal_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = bcm2835_thermal_realize;
+ dc->reset = bcm2835_thermal_reset;
+ dc->vmsd = &bcm2835_thermal_vmstate;
+}
+
+static const TypeInfo bcm2835_thermal_info = {
+ .name = TYPE_BCM2835_THERMAL,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Bcm2835ThermalState),
+ .class_init = bcm2835_thermal_class_init,
+};
+
+static void bcm2835_thermal_register_types(void)
+{
+ type_register_static(&bcm2835_thermal_info);
+}
+
+type_init(bcm2835_thermal_register_types)
diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c
index d9b3e8c..717de76 100644
--- a/hw/net/fsl_etsec/etsec.c
+++ b/hw/net/fsl_etsec/etsec.c
@@ -34,7 +34,6 @@
#include "etsec.h"
#include "registers.h"
#include "qemu/log.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
/* #define HEX_DUMP */
@@ -195,9 +194,11 @@ static void write_dmactrl(eTSEC *etsec,
if (!(value & DMACTRL_WOP)) {
/* Start polling */
+ ptimer_transaction_begin(etsec->ptimer);
ptimer_stop(etsec->ptimer);
ptimer_set_count(etsec->ptimer, 1);
ptimer_run(etsec->ptimer, 1);
+ ptimer_transaction_commit(etsec->ptimer);
}
}
@@ -391,10 +392,10 @@ static void etsec_realize(DeviceState *dev, Error **errp)
object_get_typename(OBJECT(dev)), dev->id, etsec);
qemu_format_nic_info_str(qemu_get_queue(etsec->nic), etsec->conf.macaddr.a);
-
- etsec->bh = qemu_bh_new(etsec_timer_hit, etsec);
- etsec->ptimer = ptimer_init_with_bh(etsec->bh, PTIMER_POLICY_DEFAULT);
+ etsec->ptimer = ptimer_init(etsec_timer_hit, etsec, PTIMER_POLICY_DEFAULT);
+ ptimer_transaction_begin(etsec->ptimer);
ptimer_set_freq(etsec->ptimer, 100);
+ ptimer_transaction_commit(etsec->ptimer);
}
static void etsec_instance_init(Object *obj)
diff --git a/hw/net/fsl_etsec/etsec.h b/hw/net/fsl_etsec/etsec.h
index 09d05c2..7951c3a 100644
--- a/hw/net/fsl_etsec/etsec.h
+++ b/hw/net/fsl_etsec/etsec.h
@@ -141,7 +141,6 @@ typedef struct eTSEC {
uint16_t phy_control;
/* Polling */
- QEMUBH *bh;
struct ptimer_state *ptimer;
/* Whether we should flush the rx queue when buffer becomes available. */
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index 123d92c..696cda5 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -47,3 +47,4 @@ common-obj-$(CONFIG_SUN4V_RTC) += sun4v-rtc.o
common-obj-$(CONFIG_CMSDK_APB_TIMER) += cmsdk-apb-timer.o
common-obj-$(CONFIG_CMSDK_APB_DUALTIMER) += cmsdk-apb-dualtimer.o
common-obj-$(CONFIG_MSF2) += mss-timer.o
+common-obj-$(CONFIG_RASPI) += bcm2835_systmr.o
diff --git a/hw/timer/bcm2835_systmr.c b/hw/timer/bcm2835_systmr.c
new file mode 100644
index 0000000..3387a62
--- /dev/null
+++ b/hw/timer/bcm2835_systmr.c
@@ -0,0 +1,163 @@
+/*
+ * BCM2835 SYS timer emulation
+ *
+ * Copyright (C) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Datasheet: BCM2835 ARM Peripherals (C6357-M-1398)
+ * https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
+ *
+ * Only the free running 64-bit counter is implemented.
+ * The 4 COMPARE registers and the interruption are not implemented.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/timer.h"
+#include "hw/timer/bcm2835_systmr.h"
+#include "hw/registerfields.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+REG32(CTRL_STATUS, 0x00)
+REG32(COUNTER_LOW, 0x04)
+REG32(COUNTER_HIGH, 0x08)
+REG32(COMPARE0, 0x0c)
+REG32(COMPARE1, 0x10)
+REG32(COMPARE2, 0x14)
+REG32(COMPARE3, 0x18)
+
+static void bcm2835_systmr_update_irq(BCM2835SystemTimerState *s)
+{
+ bool enable = !!s->reg.status;
+
+ trace_bcm2835_systmr_irq(enable);
+ qemu_set_irq(s->irq, enable);
+}
+
+static void bcm2835_systmr_update_compare(BCM2835SystemTimerState *s,
+ unsigned timer_index)
+{
+ /* TODO fow now, since neither Linux nor U-boot use these timers. */
+ qemu_log_mask(LOG_UNIMP, "COMPARE register %u not implemented\n",
+ timer_index);
+}
+
+static uint64_t bcm2835_systmr_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ BCM2835SystemTimerState *s = BCM2835_SYSTIMER(opaque);
+ uint64_t r = 0;
+
+ switch (offset) {
+ case A_CTRL_STATUS:
+ r = s->reg.status;
+ break;
+ case A_COMPARE0 ... A_COMPARE3:
+ r = s->reg.compare[(offset - A_COMPARE0) >> 2];
+ break;
+ case A_COUNTER_LOW:
+ case A_COUNTER_HIGH:
+ /* Free running counter at 1MHz */
+ r = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
+ r >>= 8 * (offset - A_COUNTER_LOW);
+ r &= UINT32_MAX;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ break;
+ }
+ trace_bcm2835_systmr_read(offset, r);
+
+ return r;
+}
+
+static void bcm2835_systmr_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ BCM2835SystemTimerState *s = BCM2835_SYSTIMER(opaque);
+
+ trace_bcm2835_systmr_write(offset, value);
+ switch (offset) {
+ case A_CTRL_STATUS:
+ s->reg.status &= ~value; /* Ack */
+ bcm2835_systmr_update_irq(s);
+ break;
+ case A_COMPARE0 ... A_COMPARE3:
+ s->reg.compare[(offset - A_COMPARE0) >> 2] = value;
+ bcm2835_systmr_update_compare(s, (offset - A_COMPARE0) >> 2);
+ break;
+ case A_COUNTER_LOW:
+ case A_COUNTER_HIGH:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: read-only ofs 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ break;
+ }
+}
+
+static const MemoryRegionOps bcm2835_systmr_ops = {
+ .read = bcm2835_systmr_read,
+ .write = bcm2835_systmr_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void bcm2835_systmr_reset(DeviceState *dev)
+{
+ BCM2835SystemTimerState *s = BCM2835_SYSTIMER(dev);
+
+ memset(&s->reg, 0, sizeof(s->reg));
+}
+
+static void bcm2835_systmr_realize(DeviceState *dev, Error **errp)
+{
+ BCM2835SystemTimerState *s = BCM2835_SYSTIMER(dev);
+
+ memory_region_init_io(&s->iomem, OBJECT(dev), &bcm2835_systmr_ops,
+ s, "bcm2835-sys-timer", 0x20);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
+}
+
+static const VMStateDescription bcm2835_systmr_vmstate = {
+ .name = "bcm2835_sys_timer",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(reg.status, BCM2835SystemTimerState),
+ VMSTATE_UINT32_ARRAY(reg.compare, BCM2835SystemTimerState, 4),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void bcm2835_systmr_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = bcm2835_systmr_realize;
+ dc->reset = bcm2835_systmr_reset;
+ dc->vmsd = &bcm2835_systmr_vmstate;
+}
+
+static const TypeInfo bcm2835_systmr_info = {
+ .name = TYPE_BCM2835_SYSTIMER,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(BCM2835SystemTimerState),
+ .class_init = bcm2835_systmr_class_init,
+};
+
+static void bcm2835_systmr_register_types(void)
+{
+ type_register_static(&bcm2835_systmr_info);
+}
+
+type_init(bcm2835_systmr_register_types);
diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c
index bb09268..7a9371c 100644
--- a/hw/timer/grlib_gptimer.c
+++ b/hw/timer/grlib_gptimer.c
@@ -29,7 +29,6 @@
#include "hw/irq.h"
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "trace.h"
@@ -63,7 +62,6 @@ typedef struct GPTimer GPTimer;
typedef struct GPTimerUnit GPTimerUnit;
struct GPTimer {
- QEMUBH *bh;
struct ptimer_state *ptimer;
qemu_irq irq;
@@ -93,6 +91,17 @@ struct GPTimerUnit {
uint32_t config;
};
+static void grlib_gptimer_tx_begin(GPTimer *timer)
+{
+ ptimer_transaction_begin(timer->ptimer);
+}
+
+static void grlib_gptimer_tx_commit(GPTimer *timer)
+{
+ ptimer_transaction_commit(timer->ptimer);
+}
+
+/* Must be called within grlib_gptimer_tx_begin/commit block */
static void grlib_gptimer_enable(GPTimer *timer)
{
assert(timer != NULL);
@@ -115,6 +124,7 @@ static void grlib_gptimer_enable(GPTimer *timer)
ptimer_run(timer->ptimer, 1);
}
+/* Must be called within grlib_gptimer_tx_begin/commit block */
static void grlib_gptimer_restart(GPTimer *timer)
{
assert(timer != NULL);
@@ -141,7 +151,9 @@ static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
trace_grlib_gptimer_set_scaler(scaler, value);
for (i = 0; i < unit->nr_timers; i++) {
+ ptimer_transaction_begin(unit->timers[i].ptimer);
ptimer_set_freq(unit->timers[i].ptimer, value);
+ ptimer_transaction_commit(unit->timers[i].ptimer);
}
}
@@ -266,8 +278,10 @@ static void grlib_gptimer_write(void *opaque, hwaddr addr,
switch (timer_addr) {
case COUNTER_OFFSET:
trace_grlib_gptimer_writel(id, addr, value);
+ grlib_gptimer_tx_begin(&unit->timers[id]);
unit->timers[id].counter = value;
grlib_gptimer_enable(&unit->timers[id]);
+ grlib_gptimer_tx_commit(&unit->timers[id]);
return;
case COUNTER_RELOAD_OFFSET:
@@ -291,6 +305,7 @@ static void grlib_gptimer_write(void *opaque, hwaddr addr,
/* gptimer_restart calls gptimer_enable, so if "enable" and "load"
bits are present, we just have to call restart. */
+ grlib_gptimer_tx_begin(&unit->timers[id]);
if (value & GPTIMER_LOAD) {
grlib_gptimer_restart(&unit->timers[id]);
} else if (value & GPTIMER_ENABLE) {
@@ -301,6 +316,7 @@ static void grlib_gptimer_write(void *opaque, hwaddr addr,
value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
unit->timers[id].config = value;
+ grlib_gptimer_tx_commit(&unit->timers[id]);
return;
default:
@@ -344,9 +360,11 @@ static void grlib_gptimer_reset(DeviceState *d)
timer->counter = 0;
timer->reload = 0;
timer->config = 0;
+ ptimer_transaction_begin(timer->ptimer);
ptimer_stop(timer->ptimer);
ptimer_set_count(timer->ptimer, 0);
ptimer_set_freq(timer->ptimer, unit->freq_hz);
+ ptimer_transaction_commit(timer->ptimer);
}
}
@@ -365,14 +383,16 @@ static void grlib_gptimer_realize(DeviceState *dev, Error **errp)
GPTimer *timer = &unit->timers[i];
timer->unit = unit;
- timer->bh = qemu_bh_new(grlib_gptimer_hit, timer);
- timer->ptimer = ptimer_init_with_bh(timer->bh, PTIMER_POLICY_DEFAULT);
+ timer->ptimer = ptimer_init(grlib_gptimer_hit, timer,
+ PTIMER_POLICY_DEFAULT);
timer->id = i;
/* One IRQ line for each timer */
sysbus_init_irq(sbd, &timer->irq);
+ ptimer_transaction_begin(timer->ptimer);
ptimer_set_freq(timer->ptimer, unit->freq_hz);
+ ptimer_transaction_commit(timer->ptimer);
}
memory_region_init_io(&unit->iomem, OBJECT(unit), &grlib_gptimer_ops,
diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c
index 5193c03..7a62e21 100644
--- a/hw/timer/milkymist-sysctl.c
+++ b/hw/timer/milkymist-sysctl.c
@@ -31,7 +31,6 @@
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
#include "qemu/error-report.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
enum {
@@ -71,8 +70,6 @@ struct MilkymistSysctlState {
MemoryRegion regs_region;
- QEMUBH *bh0;
- QEMUBH *bh1;
ptimer_state *ptimer0;
ptimer_state *ptimer1;
@@ -161,14 +158,19 @@ static void sysctl_write(void *opaque, hwaddr addr, uint64_t value,
s->regs[addr] = value;
break;
case R_TIMER0_COMPARE:
+ ptimer_transaction_begin(s->ptimer0);
ptimer_set_limit(s->ptimer0, value, 0);
s->regs[addr] = value;
+ ptimer_transaction_commit(s->ptimer0);
break;
case R_TIMER1_COMPARE:
+ ptimer_transaction_begin(s->ptimer1);
ptimer_set_limit(s->ptimer1, value, 0);
s->regs[addr] = value;
+ ptimer_transaction_commit(s->ptimer1);
break;
case R_TIMER0_CONTROL:
+ ptimer_transaction_begin(s->ptimer0);
s->regs[addr] = value;
if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
trace_milkymist_sysctl_start_timer0();
@@ -179,8 +181,10 @@ static void sysctl_write(void *opaque, hwaddr addr, uint64_t value,
trace_milkymist_sysctl_stop_timer0();
ptimer_stop(s->ptimer0);
}
+ ptimer_transaction_commit(s->ptimer0);
break;
case R_TIMER1_CONTROL:
+ ptimer_transaction_begin(s->ptimer1);
s->regs[addr] = value;
if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
trace_milkymist_sysctl_start_timer1();
@@ -191,6 +195,7 @@ static void sysctl_write(void *opaque, hwaddr addr, uint64_t value,
trace_milkymist_sysctl_stop_timer1();
ptimer_stop(s->ptimer1);
}
+ ptimer_transaction_commit(s->ptimer1);
break;
case R_ICAP:
sysctl_icap_write(s, value);
@@ -263,8 +268,12 @@ static void milkymist_sysctl_reset(DeviceState *d)
s->regs[i] = 0;
}
+ ptimer_transaction_begin(s->ptimer0);
ptimer_stop(s->ptimer0);
+ ptimer_transaction_commit(s->ptimer0);
+ ptimer_transaction_begin(s->ptimer1);
ptimer_stop(s->ptimer1);
+ ptimer_transaction_commit(s->ptimer1);
/* defaults */
s->regs[R_ICAP] = ICAP_READY;
@@ -292,13 +301,15 @@ static void milkymist_sysctl_realize(DeviceState *dev, Error **errp)
{
MilkymistSysctlState *s = MILKYMIST_SYSCTL(dev);
- s->bh0 = qemu_bh_new(timer0_hit, s);
- s->bh1 = qemu_bh_new(timer1_hit, s);
- s->ptimer0 = ptimer_init_with_bh(s->bh0, PTIMER_POLICY_DEFAULT);
- s->ptimer1 = ptimer_init_with_bh(s->bh1, PTIMER_POLICY_DEFAULT);
+ s->ptimer0 = ptimer_init(timer0_hit, s, PTIMER_POLICY_DEFAULT);
+ s->ptimer1 = ptimer_init(timer1_hit, s, PTIMER_POLICY_DEFAULT);
+ ptimer_transaction_begin(s->ptimer0);
ptimer_set_freq(s->ptimer0, s->freq_hz);
+ ptimer_transaction_commit(s->ptimer0);
+ ptimer_transaction_begin(s->ptimer1);
ptimer_set_freq(s->ptimer1, s->freq_hz);
+ ptimer_transaction_commit(s->ptimer1);
}
static const VMStateDescription vmstate_milkymist_sysctl = {
diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
index 692d213..c55e8d0 100644
--- a/hw/timer/slavio_timer.c
+++ b/hw/timer/slavio_timer.c
@@ -30,7 +30,6 @@
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "trace.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
/*
@@ -213,6 +212,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
saddr = addr >> 2;
switch (saddr) {
case TIMER_LIMIT:
+ ptimer_transaction_begin(t->timer);
if (slavio_timer_is_user(tc)) {
uint64_t count;
@@ -227,15 +227,14 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
// set limit, reset counter
qemu_irq_lower(t->irq);
t->limit = val & TIMER_MAX_COUNT32;
- if (t->timer) {
- if (t->limit == 0) { /* free-run */
- ptimer_set_limit(t->timer,
- LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
- } else {
- ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1);
- }
+ if (t->limit == 0) { /* free-run */
+ ptimer_set_limit(t->timer,
+ LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
+ } else {
+ ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1);
}
}
+ ptimer_transaction_commit(t->timer);
break;
case TIMER_COUNTER:
if (slavio_timer_is_user(tc)) {
@@ -247,7 +246,9 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
t->reached = 0;
count = ((uint64_t)t->counthigh) << 32 | t->count;
trace_slavio_timer_mem_writel_limit(timer_index, count);
+ ptimer_transaction_begin(t->timer);
ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
+ ptimer_transaction_commit(t->timer);
} else {
trace_slavio_timer_mem_writel_counter_invalid();
}
@@ -255,13 +256,16 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
case TIMER_COUNTER_NORST:
// set limit without resetting counter
t->limit = val & TIMER_MAX_COUNT32;
+ ptimer_transaction_begin(t->timer);
if (t->limit == 0) { /* free-run */
ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
} else {
ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0);
}
+ ptimer_transaction_commit(t->timer);
break;
case TIMER_STATUS:
+ ptimer_transaction_begin(t->timer);
if (slavio_timer_is_user(tc)) {
// start/stop user counter
if (val & 1) {
@@ -273,6 +277,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
}
}
t->run = val & 1;
+ ptimer_transaction_commit(t->timer);
break;
case TIMER_MODE:
if (timer_index == 0) {
@@ -282,6 +287,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
unsigned int processor = 1 << i;
CPUTimerState *curr_timer = &s->cputimer[i + 1];
+ ptimer_transaction_begin(curr_timer->timer);
// check for a change in timer mode for this processor
if ((val & processor) != (s->cputimer_mode & processor)) {
if (val & processor) { // counter -> user timer
@@ -308,6 +314,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
trace_slavio_timer_mem_writel_mode_counter(timer_index);
}
}
+ ptimer_transaction_commit(curr_timer->timer);
}
} else {
trace_slavio_timer_mem_writel_mode_invalid();
@@ -367,10 +374,12 @@ static void slavio_timer_reset(DeviceState *d)
curr_timer->count = 0;
curr_timer->reached = 0;
if (i <= s->num_cpus) {
+ ptimer_transaction_begin(curr_timer->timer);
ptimer_set_limit(curr_timer->timer,
LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
ptimer_run(curr_timer->timer, 0);
curr_timer->run = 1;
+ ptimer_transaction_commit(curr_timer->timer);
}
}
s->cputimer_mode = 0;
@@ -380,7 +389,6 @@ static void slavio_timer_init(Object *obj)
{
SLAVIO_TIMERState *s = SLAVIO_TIMER(obj);
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
- QEMUBH *bh;
unsigned int i;
TimerContext *tc;
@@ -392,9 +400,11 @@ static void slavio_timer_init(Object *obj)
tc->s = s;
tc->timer_index = i;
- bh = qemu_bh_new(slavio_timer_irq, tc);
- s->cputimer[i].timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT);
+ s->cputimer[i].timer = ptimer_init(slavio_timer_irq, tc,
+ PTIMER_POLICY_DEFAULT);
+ ptimer_transaction_begin(s->cputimer[i].timer);
ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD);
+ ptimer_transaction_commit(s->cputimer[i].timer);
size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE;
snprintf(timer_name, sizeof(timer_name), "timer-%i", i);
diff --git a/hw/timer/trace-events b/hw/timer/trace-events
index db02a91..0aa399a 100644
--- a/hw/timer/trace-events
+++ b/hw/timer/trace-events
@@ -87,3 +87,8 @@ pl031_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
pl031_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
pl031_alarm_raised(void) "alarm raised"
pl031_set_alarm(uint32_t ticks) "alarm set for %u ticks"
+
+# bcm2835_systmr.c
+bcm2835_systmr_irq(bool enable) "timer irq state %u"
+bcm2835_systmr_read(uint64_t offset, uint64_t data) "timer read: offset 0x%" PRIx64 " data 0x%" PRIx64
+bcm2835_systmr_write(uint64_t offset, uint64_t data) "timer write: offset 0x%" PRIx64 " data 0x%" PRIx64
diff --git a/hw/timer/xilinx_timer.c b/hw/timer/xilinx_timer.c
index 92dbff3..7191ea5 100644
--- a/hw/timer/xilinx_timer.c
+++ b/hw/timer/xilinx_timer.c
@@ -28,7 +28,6 @@
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
#include "qemu/log.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
#define D(x)
@@ -52,7 +51,6 @@
struct xlx_timer
{
- QEMUBH *bh;
ptimer_state *ptimer;
void *parent;
int nr; /* for debug. */
@@ -134,6 +132,7 @@ timer_read(void *opaque, hwaddr addr, unsigned int size)
return r;
}
+/* Must be called inside ptimer transaction block */
static void timer_enable(struct xlx_timer *xt)
{
uint64_t count;
@@ -174,8 +173,11 @@ timer_write(void *opaque, hwaddr addr,
value &= ~TCSR_TINT;
xt->regs[addr] = value & 0x7ff;
- if (value & TCSR_ENT)
+ if (value & TCSR_ENT) {
+ ptimer_transaction_begin(xt->ptimer);
timer_enable(xt);
+ ptimer_transaction_commit(xt->ptimer);
+ }
break;
default:
@@ -220,9 +222,10 @@ static void xilinx_timer_realize(DeviceState *dev, Error **errp)
xt->parent = t;
xt->nr = i;
- xt->bh = qemu_bh_new(timer_hit, xt);
- xt->ptimer = ptimer_init_with_bh(xt->bh, PTIMER_POLICY_DEFAULT);
+ xt->ptimer = ptimer_init(timer_hit, xt, PTIMER_POLICY_DEFAULT);
+ ptimer_transaction_begin(xt->ptimer);
ptimer_set_freq(xt->ptimer, t->freq_hz);
+ ptimer_transaction_commit(xt->ptimer);
}
memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, "xlnx.xps-timer",