aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2012-12-13 11:41:57 -0600
committerAnthony Liguori <aliguori@us.ibm.com>2012-12-13 11:41:57 -0600
commitdf9330070e671134544f872dc5c027443878b764 (patch)
treeb1387f5f3f1c86a1ba2efeced0fef37b492844b8
parentaa1246aee2914424f101a7e462bd1393ececef95 (diff)
parent871edc5fdba884929102b89d28ff363c94f0822d (diff)
downloadqemu-df9330070e671134544f872dc5c027443878b764.zip
qemu-df9330070e671134544f872dc5c027443878b764.tar.gz
qemu-df9330070e671134544f872dc5c027443878b764.tar.bz2
Merge remote-tracking branch 'pmaydell/arm-devs.next' into staging
* pmaydell/arm-devs.next: hw/ds1338.c: Fix handling of DAY (wday) register. hw/ds1338.c: Implement support for the control register. hw/ds1338.c: Ensure state is properly initialized. hw/ds1338.c: Fix handling of HOURS register. hw/ds1338.c: Add definitions for various flags in the RTC registers. hw/ds1338.c: Correct bug in conversion to BCD. exynos4210/mct: Avoid infinite loop on non incremental timers hw/arm_gic: fix target CPUs affected by set enable/pending ops xilinx_zynq: Add one variable to avoid overwriting QSPI bus hw/arm_gic_common: Correct GICC_PMR reset value for newer GICs hw/arm_gic: Fix comparison with priority mask register hw/arm_boot, exynos4210, highbank: Fix secondary boot GIC init Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
-rw-r--r--hw/arm_boot.c17
-rw-r--r--hw/arm_gic.c7
-rw-r--r--hw/arm_gic_common.c6
-rw-r--r--hw/armv7m_nvic.c4
-rw-r--r--hw/ds1338.c81
-rw-r--r--hw/exynos4210.c10
-rw-r--r--hw/exynos4210_mct.c2
-rw-r--r--hw/highbank.c7
-rw-r--r--hw/xilinx_zynq.c9
9 files changed, 106 insertions, 37 deletions
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index 92e2cab..ec3b8d5 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -44,11 +44,17 @@ static uint32_t bootloader[] = {
* for an interprocessor interrupt and polling a configurable
* location for the kernel secondary CPU entry point.
*/
+#define DSB_INSN 0xf57ff04f
+#define CP15_DSB_INSN 0xee070f9a /* mcr cp15, 0, r0, c7, c10, 4 */
+
static uint32_t smpboot[] = {
- 0xe59f201c, /* ldr r2, gic_cpu_if */
- 0xe59f001c, /* ldr r0, startaddr */
+ 0xe59f2028, /* ldr r2, gic_cpu_if */
+ 0xe59f0028, /* ldr r0, startaddr */
0xe3a01001, /* mov r1, #1 */
- 0xe5821000, /* str r1, [r2] */
+ 0xe5821000, /* str r1, [r2] - set GICC_CTLR.Enable */
+ 0xe3a010ff, /* mov r1, #0xff */
+ 0xe5821004, /* str r1, [r2, 4] - set GIC_PMR.Priority to 0xff */
+ DSB_INSN, /* dsb */
0xe320f003, /* wfi */
0xe5901000, /* ldr r1, [r0] */
0xe1110001, /* tst r1, r1 */
@@ -65,6 +71,11 @@ static void default_write_secondary(ARMCPU *cpu,
smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr;
for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
+ /* Replace DSB with the pre-v7 DSB if necessary. */
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V7) &&
+ smpboot[n] == DSB_INSN) {
+ smpboot[n] = CP15_DSB_INSN;
+ }
smpboot[n] = tswap32(smpboot[n]);
}
rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index f9e423f..8d769de 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -73,7 +73,7 @@ void gic_update(GICState *s)
}
}
level = 0;
- if (best_prio <= s->priority_mask[cpu]) {
+ if (best_prio < s->priority_mask[cpu]) {
s->current_pending[cpu] = best_irq;
if (best_prio < s->running_priority[cpu]) {
DPRINTF("Raised pending IRQ %d\n", best_irq);
@@ -374,7 +374,8 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
value = 0xff;
for (i = 0; i < 8; i++) {
if (value & (1 << i)) {
- int mask = (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq);
+ int mask =
+ (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i);
int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
if (!GIC_TEST_ENABLED(irq + i, cm)) {
@@ -417,7 +418,7 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
for (i = 0; i < 8; i++) {
if (value & (1 << i)) {
- GIC_SET_PENDING(irq + i, GIC_TARGET(irq));
+ GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i));
}
}
} else if (offset < 0x300) {
diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c
index 8369309..73ae331 100644
--- a/hw/arm_gic_common.c
+++ b/hw/arm_gic_common.c
@@ -127,7 +127,11 @@ static void arm_gic_common_reset(DeviceState *dev)
int i;
memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
for (i = 0 ; i < s->num_cpu; i++) {
- s->priority_mask[i] = 0xf0;
+ if (s->revision == REV_11MPCORE) {
+ s->priority_mask[i] = 0xf0;
+ } else {
+ s->priority_mask[i] = 0;
+ }
s->current_pending[i] = 1023;
s->running_irq[i] = 1023;
s->running_priority[i] = 0x100;
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index f0a2e7b..4963678 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -455,9 +455,11 @@ static void armv7m_nvic_reset(DeviceState *dev)
nc->parent_reset(dev);
/* Common GIC reset resets to disabled; the NVIC doesn't have
* per-CPU interfaces so mark our non-existent CPU interface
- * as enabled by default.
+ * as enabled by default, and with a priority mask which allows
+ * all interrupts through.
*/
s->gic.cpu_enabled[0] = 1;
+ s->gic.priority_mask[0] = 0x100;
/* The NVIC as a whole is always enabled. */
s->gic.enabled = 1;
systick_reset(s);
diff --git a/hw/ds1338.c b/hw/ds1338.c
index b576d56..1aefa3b 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -17,9 +17,16 @@
*/
#define NVRAM_SIZE 64
+/* Flags definitions */
+#define SECONDS_CH 0x80
+#define HOURS_12 0x40
+#define HOURS_PM 0x20
+#define CTRL_OSF 0x20
+
typedef struct {
I2CSlave i2c;
int64_t offset;
+ uint8_t wday_offset;
uint8_t nvram[NVRAM_SIZE];
int32_t ptr;
bool addr_byte;
@@ -27,12 +34,13 @@ typedef struct {
static const VMStateDescription vmstate_ds1338 = {
.name = "ds1338",
- .version_id = 1,
+ .version_id = 2,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_I2C_SLAVE(i2c, DS1338State),
VMSTATE_INT64(offset, DS1338State),
+ VMSTATE_UINT8_V(wday_offset, DS1338State, 2),
VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE),
VMSTATE_INT32(ptr, DS1338State),
VMSTATE_BOOL(addr_byte, DS1338State),
@@ -49,17 +57,22 @@ static void capture_current_time(DS1338State *s)
qemu_get_timedate(&now, s->offset);
s->nvram[0] = to_bcd(now.tm_sec);
s->nvram[1] = to_bcd(now.tm_min);
- if (s->nvram[2] & 0x40) {
- s->nvram[2] = (to_bcd((now.tm_hour % 12)) + 1) | 0x40;
- if (now.tm_hour >= 12) {
- s->nvram[2] |= 0x20;
+ if (s->nvram[2] & HOURS_12) {
+ int tmp = now.tm_hour;
+ if (tmp == 0) {
+ tmp = 24;
+ }
+ if (tmp <= 12) {
+ s->nvram[2] = HOURS_12 | to_bcd(tmp);
+ } else {
+ s->nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
}
} else {
s->nvram[2] = to_bcd(now.tm_hour);
}
- s->nvram[3] = to_bcd(now.tm_wday) + 1;
+ s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
s->nvram[4] = to_bcd(now.tm_mday);
- s->nvram[5] = to_bcd(now.tm_mon) + 1;
+ s->nvram[5] = to_bcd(now.tm_mon + 1);
s->nvram[6] = to_bcd(now.tm_year - 100);
}
@@ -114,7 +127,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
s->addr_byte = false;
return 0;
}
- if (s->ptr < 8) {
+ if (s->ptr < 7) {
+ /* Time register. */
struct tm now;
qemu_get_timedate(&now, s->offset);
switch(s->ptr) {
@@ -126,19 +140,27 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
now.tm_min = from_bcd(data & 0x7f);
break;
case 2:
- if (data & 0x40) {
- if (data & 0x20) {
- data = from_bcd(data & 0x4f) + 11;
- } else {
- data = from_bcd(data & 0x1f) - 1;
+ if (data & HOURS_12) {
+ int tmp = from_bcd(data & (HOURS_PM - 1));
+ if (data & HOURS_PM) {
+ tmp += 12;
+ }
+ if (tmp == 24) {
+ tmp = 0;
}
+ now.tm_hour = tmp;
} else {
- data = from_bcd(data);
+ now.tm_hour = from_bcd(data & (HOURS_12 - 1));
}
- now.tm_hour = data;
break;
case 3:
- now.tm_wday = from_bcd(data & 7) - 1;
+ {
+ /* The day field is supposed to contain a value in
+ the range 1-7. Otherwise behavior is undefined.
+ */
+ int user_wday = (data & 7) - 1;
+ s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
+ }
break;
case 4:
now.tm_mday = from_bcd(data & 0x3f);
@@ -149,11 +171,19 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
case 6:
now.tm_year = from_bcd(data) + 100;
break;
- case 7:
- /* Control register. Currently ignored. */
- break;
}
s->offset = qemu_timedate_diff(&now);
+ } else if (s->ptr == 7) {
+ /* Control register. */
+
+ /* Ensure bits 2, 3 and 6 will read back as zero. */
+ data &= 0xB3;
+
+ /* Attempting to write the OSF flag to logic 1 leaves the
+ value unchanged. */
+ data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
+
+ s->nvram[s->ptr] = data;
} else {
s->nvram[s->ptr] = data;
}
@@ -166,6 +196,18 @@ static int ds1338_init(I2CSlave *i2c)
return 0;
}
+static void ds1338_reset(DeviceState *dev)
+{
+ DS1338State *s = FROM_I2C_SLAVE(DS1338State, I2C_SLAVE_FROM_QDEV(dev));
+
+ /* The clock is running and synchronized with the host */
+ s->offset = 0;
+ s->wday_offset = 0;
+ memset(s->nvram, 0, NVRAM_SIZE);
+ s->ptr = 0;
+ s->addr_byte = false;
+}
+
static void ds1338_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -175,6 +217,7 @@ static void ds1338_class_init(ObjectClass *klass, void *data)
k->event = ds1338_event;
k->recv = ds1338_recv;
k->send = ds1338_send;
+ dc->reset = ds1338_reset;
dc->vmsd = &vmstate_ds1338;
}
diff --git a/hw/exynos4210.c b/hw/exynos4210.c
index 00d4db8..22148cd 100644
--- a/hw/exynos4210.c
+++ b/hw/exynos4210.c
@@ -80,12 +80,16 @@ void exynos4210_write_secondary(ARMCPU *cpu,
{
int n;
uint32_t smpboot[] = {
- 0xe59f3024, /* ldr r3, External gic_cpu_if */
- 0xe59f2024, /* ldr r2, Internal gic_cpu_if */
- 0xe59f0024, /* ldr r0, startaddr */
+ 0xe59f3034, /* ldr r3, External gic_cpu_if */
+ 0xe59f2034, /* ldr r2, Internal gic_cpu_if */
+ 0xe59f0034, /* ldr r0, startaddr */
0xe3a01001, /* mov r1, #1 */
0xe5821000, /* str r1, [r2] */
0xe5831000, /* str r1, [r3] */
+ 0xe3a010ff, /* mov r1, #0xff */
+ 0xe5821004, /* str r1, [r2, #4] */
+ 0xe5831004, /* str r1, [r3, #4] */
+ 0xf57ff04f, /* dsb */
0xe320f003, /* wfi */
0xe5901000, /* ldr r1, [r0] */
0xe1110001, /* tst r1, r1 */
diff --git a/hw/exynos4210_mct.c b/hw/exynos4210_mct.c
index e79cd6a..37dbda9 100644
--- a/hw/exynos4210_mct.c
+++ b/hw/exynos4210_mct.c
@@ -568,7 +568,7 @@ static void exynos4210_gfrc_event(void *opaque)
/* Reload FRC to reach nearest comparator */
s->g_timer.curr_comp = exynos4210_gcomp_find(s);
distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp);
- if (distance > MCT_GT_COUNTER_STEP) {
+ if (distance > MCT_GT_COUNTER_STEP || !distance) {
distance = MCT_GT_COUNTER_STEP;
}
exynos4210_gfrc_set_count(&s->g_timer, distance);
diff --git a/hw/highbank.c b/hw/highbank.c
index afbb005..447e57d 100644
--- a/hw/highbank.c
+++ b/hw/highbank.c
@@ -44,9 +44,12 @@ static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
0xe210000f, /* ands r0, r0, #0x0f */
0xe3a03040, /* mov r3, #0x40 - jump address is 0x40 + 0x10 * core id */
0xe0830200, /* add r0, r3, r0, lsl #4 */
- 0xe59f2018, /* ldr r2, privbase */
+ 0xe59f2024, /* ldr r2, privbase */
0xe3a01001, /* mov r1, #1 */
- 0xe5821100, /* str r1, [r2, #256] */
+ 0xe5821100, /* str r1, [r2, #256] - set GICC_CTLR.Enable */
+ 0xe3a010ff, /* mov r1, #0xff */
+ 0xe5821104, /* str r1, [r2, #260] - set GICC_PMR.Priority to 0xff */
+ 0xf57ff04f, /* dsb */
0xe320f003, /* wfi */
0xe5901000, /* ldr r1, [r0] */
0xe1110001, /* tst r1, r1 */
diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c
index 1f12a3d..49233d8 100644
--- a/hw/xilinx_zynq.c
+++ b/hw/xilinx_zynq.c
@@ -57,6 +57,7 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
DeviceState *dev;
SysBusDevice *busdev;
SSIBus *spi;
+ DeviceState *flash_dev;
int i, j;
int num_busses = is_qspi ? NUM_QSPI_BUSSES : 1;
int num_ss = is_qspi ? NUM_QSPI_FLASHES : NUM_SPI_FLASHES;
@@ -81,11 +82,11 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
spi = (SSIBus *)qdev_get_child_bus(dev, bus_name);
for (j = 0; j < num_ss; ++j) {
- dev = ssi_create_slave_no_init(spi, "m25p80");
- qdev_prop_set_string(dev, "partname", "n25q128");
- qdev_init_nofail(dev);
+ flash_dev = ssi_create_slave_no_init(spi, "m25p80");
+ qdev_prop_set_string(flash_dev, "partname", "n25q128");
+ qdev_init_nofail(flash_dev);
- cs_line = qdev_get_gpio_in(dev, 0);
+ cs_line = qdev_get_gpio_in(flash_dev, 0);
sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line);
}
}