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:
commit
df9330070e
@ -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),
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
83
hw/ds1338.c
83
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;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user