diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2017-01-27 16:59:17 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2017-01-27 16:59:17 +0000 |
commit | 3aca12f841fcd6f3a7477076dad0d564360500de (patch) | |
tree | 269f5bbbc7ab4601758ed53938fb334cd5e699b2 /hw | |
parent | 29ba0cdc1fd1300f910d150c03a0f74236083bf7 (diff) | |
parent | 146871c33eb70ca7090a0a55e69e5a8f9b5eb102 (diff) |
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20170127' into staging
target-arm queue:
* various minor M profile bugfixes
* aspeed/smc: handle dummy bytes when doing fast reads in command mode
* pflash_cfi01: fix per-device sector length in CFI table
* arm: stellaris: make MII accesses complete immediately
* hw/char/exynos4210_uart: Drop unused local variable frame_size
* arm_gicv3: Fix broken logic in ELRSR calculation
* dma: omap: check dma channel data_type
# gpg: Signature made Fri 27 Jan 2017 15:29:39 GMT
# gpg: using RSA key 0x3C2525ED14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"
# gpg: aka "Peter Maydell <pmaydell@gmail.com>"
# gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>"
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE
* remotes/pmaydell/tags/pull-target-arm-20170127: (22 commits)
dma: omap: check dma channel data_type
arm_gicv3: Fix broken logic in ELRSR calculation
hw/char/exynos4210_uart: Drop unused local variable frame_size
arm: stellaris: make MII accesses complete immediately
armv7m: R14 should reset to 0xffffffff
armv7m: FAULTMASK should be 0 on reset
armv7m: Honour CCR.USERSETMPEND
armv7m: Report no-coprocessor faults correctly
armv7m: set CFSR.UNDEFINSTR on undefined instructions
armv7m: honour CCR.STACKALIGN on exception entry
armv7m: implement CCR, CFSR, HFSR, DFSR, BFAR, and MMFAR
armv7m: add state for v7M CCR, CFSR, HFSR, DFSR, MMFAR, BFAR
armv7m_nvic: keep a pointer to the CPU
target/arm: Drop IS_M() macro
pflash_cfi01: fix per-device sector length in CFI table
armv7m: Clear FAULTMASK on return from non-NMI exceptions
armv7m: Fix reads of CONTROL register bit 1
hw/registerfields.h: Pull FIELD etc macros out of hw/register.h
armv7m: Explicit error for bad vector table
armv7m: Replace armv7m.hack with unassigned_access handler
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/arm/armv7m.c | 8 | ||||
-rw-r--r-- | hw/block/pflash_cfi01.c | 22 | ||||
-rw-r--r-- | hw/char/exynos4210_uart.c | 6 | ||||
-rw-r--r-- | hw/dma/omap_dma.c | 10 | ||||
-rw-r--r-- | hw/intc/arm_gicv3_cpuif.c | 2 | ||||
-rw-r--r-- | hw/intc/armv7m_nvic.c | 58 | ||||
-rw-r--r-- | hw/net/stellaris_enet.c | 5 | ||||
-rw-r--r-- | hw/ssi/aspeed_smc.c | 21 |
8 files changed, 92 insertions, 40 deletions
diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 49d30782c8..0c9ca7bfa0 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -180,7 +180,6 @@ DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, uint64_t entry; uint64_t lowaddr; int big_endian; - MemoryRegion *hack = g_new(MemoryRegion, 1); if (cpu_model == NULL) { cpu_model = "cortex-m3"; @@ -225,13 +224,6 @@ DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, } } - /* Hack to map an additional page of ram at the top of the address - space. This stops qemu complaining about executing code outside RAM - when returning from an exception. */ - memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000, &error_fatal); - vmstate_register_ram_global(hack); - memory_region_add_subregion(system_memory, 0xfffff000, hack); - qemu_register_reset(armv7m_reset, cpu); return nvic; } diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 5f0ee9db00..71b98a3eef 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -99,6 +99,7 @@ struct pflash_t { char *name; void *storage; VMChangeStateEntry *vmstate; + bool old_multiple_chip_handling; }; static int pflash_post_load(void *opaque, int version_id); @@ -703,7 +704,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) pflash_t *pfl = CFI_PFLASH01(dev); uint64_t total_len; int ret; - uint64_t blocks_per_device, device_len; + uint64_t blocks_per_device, sector_len_per_device, device_len; int num_devices; Error *local_err = NULL; @@ -726,8 +727,14 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) * in the cfi_table[]. */ num_devices = pfl->device_width ? (pfl->bank_width / pfl->device_width) : 1; - blocks_per_device = pfl->nb_blocs / num_devices; - device_len = pfl->sector_len * blocks_per_device; + if (pfl->old_multiple_chip_handling) { + blocks_per_device = pfl->nb_blocs / num_devices; + sector_len_per_device = pfl->sector_len; + } else { + blocks_per_device = pfl->nb_blocs; + sector_len_per_device = pfl->sector_len / num_devices; + } + device_len = sector_len_per_device * blocks_per_device; /* XXX: to be fixed */ #if 0 @@ -832,6 +839,9 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) pfl->cfi_table[0x2A] = 0x0B; } pfl->writeblock_size = 1 << pfl->cfi_table[0x2A]; + if (!pfl->old_multiple_chip_handling && num_devices > 1) { + pfl->writeblock_size *= num_devices; + } pfl->cfi_table[0x2B] = 0x00; /* Number of erase block regions (uniform) */ @@ -839,8 +849,8 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) /* Erase block region 1 */ pfl->cfi_table[0x2D] = blocks_per_device - 1; pfl->cfi_table[0x2E] = (blocks_per_device - 1) >> 8; - pfl->cfi_table[0x2F] = pfl->sector_len >> 8; - pfl->cfi_table[0x30] = pfl->sector_len >> 16; + pfl->cfi_table[0x2F] = sector_len_per_device >> 8; + pfl->cfi_table[0x30] = sector_len_per_device >> 16; /* Extended */ pfl->cfi_table[0x31] = 'P'; @@ -898,6 +908,8 @@ static Property pflash_cfi01_properties[] = { DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0), DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0), DEFINE_PROP_STRING("name", struct pflash_t, name), + DEFINE_PROP_BOOL("old-multiple-chip-handling", struct pflash_t, + old_multiple_chip_handling, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c index 820d1abeb9..0cd3dd3958 100644 --- a/hw/char/exynos4210_uart.c +++ b/hw/char/exynos4210_uart.c @@ -306,7 +306,7 @@ static void exynos4210_uart_update_irq(Exynos4210UartState *s) static void exynos4210_uart_update_parameters(Exynos4210UartState *s) { - int speed, parity, data_bits, stop_bits, frame_size; + int speed, parity, data_bits, stop_bits; QEMUSerialSetParams ssp; uint64_t uclk_rate; @@ -314,9 +314,7 @@ static void exynos4210_uart_update_parameters(Exynos4210UartState *s) return; } - frame_size = 1; /* start bit */ if (s->reg[I_(ULCON)] & 0x20) { - frame_size++; /* parity bit */ if (s->reg[I_(ULCON)] & 0x28) { parity = 'E'; } else { @@ -334,8 +332,6 @@ static void exynos4210_uart_update_parameters(Exynos4210UartState *s) data_bits = (s->reg[I_(ULCON)] & 0x3) + 5; - frame_size += data_bits + stop_bits; - uclk_rate = 24000000; speed = uclk_rate / ((16 * (s->reg[I_(UBRDIV)]) & 0xffff) + diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c index f6f86f9639..45dfe7aadd 100644 --- a/hw/dma/omap_dma.c +++ b/hw/dma/omap_dma.c @@ -878,15 +878,17 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, ch->burst[0] = (value & 0x0180) >> 7; ch->pack[0] = (value & 0x0040) >> 6; ch->port[0] = (enum omap_dma_port) ((value & 0x003c) >> 2); - ch->data_type = 1 << (value & 3); if (ch->port[0] >= __omap_dma_port_last) printf("%s: invalid DMA port %i\n", __FUNCTION__, ch->port[0]); if (ch->port[1] >= __omap_dma_port_last) printf("%s: invalid DMA port %i\n", __FUNCTION__, ch->port[1]); - if ((value & 3) == 3) + ch->data_type = 1 << (value & 3); + if ((value & 3) == 3) { printf("%s: bad data_type for DMA channel\n", __FUNCTION__); + ch->data_type >>= 1; + } break; case 0x02: /* SYS_DMA_CCR_CH0 */ @@ -1988,8 +1990,10 @@ static void omap_dma4_write(void *opaque, hwaddr addr, fprintf(stderr, "%s: bad MReqAddressTranslate sideband signal\n", __FUNCTION__); ch->data_type = 1 << (value & 3); - if ((value & 3) == 3) + if ((value & 3) == 3) { printf("%s: bad data_type for DMA channel\n", __FUNCTION__); + ch->data_type >>= 1; + } break; case 0x14: /* DMA4_CEN */ diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index a9ee7fddf9..c25ee03556 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -2430,7 +2430,7 @@ static uint64_t ich_elrsr_read(CPUARMState *env, const ARMCPRegInfo *ri) uint64_t lr = cs->ich_lr_el2[i]; if ((lr & ICH_LR_EL2_STATE_MASK) == 0 && - ((lr & ICH_LR_EL2_HW) == 1 || (lr & ICH_LR_EL2_EOI) == 0)) { + ((lr & ICH_LR_EL2_HW) != 0 || (lr & ICH_LR_EL2_EOI) == 0)) { value |= (1 << i); } } diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 06d8db6bd6..fe5c303de9 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -23,6 +23,7 @@ typedef struct { GICState gic; + ARMCPU *cpu; struct { uint32_t control; uint32_t reload; @@ -155,7 +156,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq) static uint32_t nvic_readl(nvic_state *s, uint32_t offset) { - ARMCPU *cpu; + ARMCPU *cpu = s->cpu; uint32_t val; int irq; @@ -187,11 +188,9 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset) case 0x1c: /* SysTick Calibration Value. */ return 10000; case 0xd00: /* CPUID Base. */ - cpu = ARM_CPU(qemu_get_cpu(0)); return cpu->midr; case 0xd04: /* Interrupt Control State. */ /* VECTACTIVE */ - cpu = ARM_CPU(qemu_get_cpu(0)); val = cpu->env.v7m.exception; if (val == 1023) { val = 0; @@ -222,7 +221,6 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset) val |= (1 << 31); return val; case 0xd08: /* Vector Table Offset. */ - cpu = ARM_CPU(qemu_get_cpu(0)); return cpu->env.v7m.vecbase; case 0xd0c: /* Application Interrupt/Reset Control. */ return 0xfa050000; @@ -230,8 +228,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset) /* TODO: Implement SLEEPONEXIT. */ return 0; case 0xd14: /* Configuration Control. */ - /* TODO: Implement Configuration Control bits. */ - return 0; + return cpu->env.v7m.ccr; case 0xd24: /* System Handler Status. */ val = 0; if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0); @@ -250,16 +247,19 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset) if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18); return val; case 0xd28: /* Configurable Fault Status. */ - /* TODO: Implement Fault Status. */ - qemu_log_mask(LOG_UNIMP, "Configurable Fault Status unimplemented\n"); - return 0; + return cpu->env.v7m.cfsr; case 0xd2c: /* Hard Fault Status. */ + return cpu->env.v7m.hfsr; case 0xd30: /* Debug Fault Status. */ - case 0xd34: /* Mem Manage Address. */ + return cpu->env.v7m.dfsr; + case 0xd34: /* MMFAR MemManage Fault Address */ + return cpu->env.v7m.mmfar; case 0xd38: /* Bus Fault Address. */ + return cpu->env.v7m.bfar; case 0xd3c: /* Aux Fault Status. */ /* TODO: Implement fault status registers. */ - qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n"); + qemu_log_mask(LOG_UNIMP, + "Aux Fault status registers unimplemented\n"); return 0; case 0xd40: /* PFR0. */ return 0x00000030; @@ -296,7 +296,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset) static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value) { - ARMCPU *cpu; + ARMCPU *cpu = s->cpu; uint32_t oldval; switch (offset) { case 0x10: /* SysTick Control and Status. */ @@ -349,7 +349,6 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value) } break; case 0xd08: /* Vector Table Offset. */ - cpu = ARM_CPU(qemu_get_cpu(0)); cpu->env.v7m.vecbase = value & 0xffffff80; break; case 0xd0c: /* Application Interrupt/Reset Control. */ @@ -369,9 +368,19 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value) } break; case 0xd10: /* System Control. */ - case 0xd14: /* Configuration Control. */ /* TODO: Implement control registers. */ - qemu_log_mask(LOG_UNIMP, "NVIC: SCR and CCR unimplemented\n"); + qemu_log_mask(LOG_UNIMP, "NVIC: SCR unimplemented\n"); + break; + case 0xd14: /* Configuration Control. */ + /* Enforce RAZ/WI on reserved and must-RAZ/WI bits */ + value &= (R_V7M_CCR_STKALIGN_MASK | + R_V7M_CCR_BFHFNMIGN_MASK | + R_V7M_CCR_DIV_0_TRP_MASK | + R_V7M_CCR_UNALIGN_TRP_MASK | + R_V7M_CCR_USERSETMPEND_MASK | + R_V7M_CCR_NONBASETHRDENA_MASK); + + cpu->env.v7m.ccr = value; break; case 0xd24: /* System Handler Control. */ /* TODO: Real hardware allows you to set/clear the active bits @@ -381,16 +390,29 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value) s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0; break; case 0xd28: /* Configurable Fault Status. */ + cpu->env.v7m.cfsr &= ~value; /* W1C */ + break; case 0xd2c: /* Hard Fault Status. */ + cpu->env.v7m.hfsr &= ~value; /* W1C */ + break; case 0xd30: /* Debug Fault Status. */ + cpu->env.v7m.dfsr &= ~value; /* W1C */ + break; case 0xd34: /* Mem Manage Address. */ + cpu->env.v7m.mmfar = value; + return; case 0xd38: /* Bus Fault Address. */ + cpu->env.v7m.bfar = value; + return; case 0xd3c: /* Aux Fault Status. */ qemu_log_mask(LOG_UNIMP, - "NVIC: fault status registers unimplemented\n"); + "NVIC: Aux fault status registers unimplemented\n"); break; case 0xf00: /* Software Triggered Interrupt Register */ - if ((value & 0x1ff) < s->num_irq) { + /* user mode can only write to STIR if CCR.USERSETMPEND permits it */ + if ((value & 0x1ff) < s->num_irq && + (arm_current_el(&cpu->env) || + (cpu->env.v7m.ccr & R_V7M_CCR_USERSETMPEND_MASK))) { gic_set_pending_private(&s->gic, 0, value & 0x1ff); } break; @@ -495,6 +517,8 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) NVICClass *nc = NVIC_GET_CLASS(s); Error *local_err = NULL; + s->cpu = ARM_CPU(qemu_get_cpu(0)); + assert(s->cpu); /* The NVIC always has only one CPU */ s->gic.num_cpu = 1; /* Tell the common code we're an NVIC */ diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c index 957730e023..04bd10ada3 100644 --- a/hw/net/stellaris_enet.c +++ b/hw/net/stellaris_enet.c @@ -416,7 +416,10 @@ static void stellaris_enet_write(void *opaque, hwaddr offset, s->thr = value; break; case 0x20: /* MCTL */ - s->mctl = value; + /* TODO: MII registers aren't modelled. + * Clear START, indicating that the operation completes immediately. + */ + s->mctl = value & ~1; break; case 0x24: /* MDV */ s->mdv = value; diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index ae1ad2dba6..087b29e8da 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -69,7 +69,9 @@ #define R_CTRL0 (0x10 / 4) #define CTRL_CMD_SHIFT 16 #define CTRL_CMD_MASK 0xff +#define CTRL_DUMMY_HIGH_SHIFT 14 #define CTRL_AST2400_SPI_4BYTE (1 << 13) +#define CTRL_DUMMY_LOW_SHIFT 6 /* 2 bits [7:6] */ #define CTRL_CE_STOP_ACTIVE (1 << 2) #define CTRL_CMD_MODE_MASK 0x3 #define CTRL_READMODE 0x0 @@ -485,6 +487,16 @@ static uint32_t aspeed_smc_check_segment_addr(const AspeedSMCFlash *fl, return addr; } +static int aspeed_smc_flash_dummies(const AspeedSMCFlash *fl) +{ + const AspeedSMCState *s = fl->controller; + uint32_t r_ctrl0 = s->regs[s->r_ctrl0 + fl->id]; + uint32_t dummy_high = (r_ctrl0 >> CTRL_DUMMY_HIGH_SHIFT) & 0x1; + uint32_t dummy_low = (r_ctrl0 >> CTRL_DUMMY_LOW_SHIFT) & 0x3; + + return ((dummy_high << 2) | dummy_low) * 8; +} + static void aspeed_smc_flash_send_addr(AspeedSMCFlash *fl, uint32_t addr) { const AspeedSMCState *s = fl->controller; @@ -521,6 +533,15 @@ static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size) aspeed_smc_flash_select(fl); aspeed_smc_flash_send_addr(fl, addr); + /* + * Use fake transfers to model dummy bytes. The value should + * be configured to some non-zero value in fast read mode and + * zero in read mode. + */ + for (i = 0; i < aspeed_smc_flash_dummies(fl); i++) { + ssi_transfer(fl->controller->spi, 0xFF); + } + for (i = 0; i < size; i++) { ret |= ssi_transfer(s->spi, 0x0) << (8 * i); } |