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>
This commit is contained in:
Anthony Liguori 2012-12-13 11:41:57 -06:00
commit df9330070e
9 changed files with 106 additions and 37 deletions

View File

@ -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),

View File

@ -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) {

View File

@ -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++) {
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;

View File

@ -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);

View File

@ -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;
}
} else {
data = from_bcd(data);
if (tmp == 24) {
tmp = 0;
}
now.tm_hour = tmp;
} else {
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;
}

View File

@ -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 */

View File

@ -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);

View File

@ -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 */

View File

@ -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);
}
}