target-arm queue:

* hw/intc/arm_gic: Allow to use QTest without crashing
  * hw/char/exynos4210_uart: Fix buffer size reporting with FIFO disabled
  * hw/char/exynos4210_uart: Fix missing call to report ready for input
  * hw/arm/smmuv3: Fix addr_mask for range-based invalidation
  * hw/ssi/imx_spi: Fix various minor bugs
  * hw/intc/arm_gic: Fix interrupt ID in GICD_SGIR register
  * hw/arm: Add missing Kconfig dependencies
  * hw/arm: Display CPU type in machine description
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmAaeAQZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3tWFD/9VTSSTmGMtSLGpuVt6t07x
 zqaFvRe+xUjrunwt25yx9tu9o4txXTk6mekgAz51QSeijESVIQQUKArZjbLWxRjl
 EXZAedOCF+f+lpzdQCO/GZtsHOfcWa158qm51NlEIM3cn1NiSASs0ky3r52MjjAR
 g0NFYTiZNplq8ah/0RljhHMhnAHzUbp/IErIxknWOVKvaH45+eji7mKxUk2vaCXB
 L5HCEzGCbPCqMMi3DFcwm9nNIYRu7X0hs9nR0AXTvdXbCoDqSyD4dEpjEcK/2IFM
 4zbS4NFRD7ndjD0C502+EUFav3tfd5/UfIjNg3oquMTDQrMCvh5Y1i3II0lVVWe5
 eSfbqV2eBzJHBanf7P64fRpk9mBNduJ8BZrozICvkCJxj5y3nTofKA9hXeGaDAdy
 7sA7Uzkpb1vnnMFzYk/0t2D6BSSFiknYuDHnfMY0nRoHsuDvY5yHw9Tt181D+qST
 UyLcmS8BB227WGgQPKSsFiUu7U423BIoiD5pp8cRyAg+FojqH6BZrcVluUWng6Ru
 ZVG0349lTmZ4mgv2hZI1qqIh80o40TI6K7OerQuMkZlq+4xseZvyb6+SQHaQ/j3I
 CKBiN15y/UzE5eivG6Siq3MR2myCBCSevTxDw4s+zR9FhoRQqFKoDhPGXTR9btWo
 1mgDNUQfyWtCcdoJKb7jEg==
 =kWoi
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210203' into staging

target-arm queue:
 * hw/intc/arm_gic: Allow to use QTest without crashing
 * hw/char/exynos4210_uart: Fix buffer size reporting with FIFO disabled
 * hw/char/exynos4210_uart: Fix missing call to report ready for input
 * hw/arm/smmuv3: Fix addr_mask for range-based invalidation
 * hw/ssi/imx_spi: Fix various minor bugs
 * hw/intc/arm_gic: Fix interrupt ID in GICD_SGIR register
 * hw/arm: Add missing Kconfig dependencies
 * hw/arm: Display CPU type in machine description

# gpg: Signature made Wed 03 Feb 2021 10:16:36 GMT
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20210203: (21 commits)
  hw/arm: Display CPU type in machine description
  hw/net/can: ZynqMP CAN device requires PTIMER
  hw/arm/xlnx-versal: Versal SoC requires ZynqMP peripherals
  hw/arm/xlnx-versal: Versal SoC requires ZDMA
  hw/arm/exynos4210: Add missing dependency on OR_IRQ
  hw/arm/stm32f405_soc: Add missing dependency on OR_IRQ
  hw/intc/arm_gic: Fix interrupt ID in GICD_SGIR register
  hw/ssi: imx_spi: Correct tx and rx fifo endianness
  hw/ssi: imx_spi: Correct the burst length > 32 bit transfer logic
  hw/ssi: imx_spi: Round up the burst length to be multiple of 8
  hw/ssi: imx_spi: Disable chip selects when controller is disabled
  hw/ssi: imx_spi: Rework imx_spi_write() to handle block disabled
  hw/ssi: imx_spi: Rework imx_spi_read() to handle block disabled
  hw/ssi: imx_spi: Rework imx_spi_reset() to keep CONREG register value
  hw/ssi: imx_spi: Remove pointless variable initialization
  hw/ssi: imx_spi: Remove imx_spi_update_irq() in imx_spi_reset()
  hw/ssi: imx_spi: Use a macro for number of chip selects supported
  hw/arm/smmuv3: Fix addr_mask for range-based invalidation
  hw/char/exynos4210_uart: Fix missing call to report ready for input
  hw/char/exynos4210_uart: Fix buffer size reporting with FIFO disabled
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-02-03 12:55:44 +00:00
commit 99ae0cd90d
15 changed files with 130 additions and 69 deletions

View File

@ -81,3 +81,4 @@ config XLNX_ZYNQMP
bool bool
select REGISTER select REGISTER
select CAN_BUS select CAN_BUS
select PTIMER

View File

@ -52,6 +52,7 @@ config EXYNOS4
select PTIMER select PTIMER
select SDHCI select SDHCI
select USB_EHCI_SYSBUS select USB_EHCI_SYSBUS
select OR_IRQ
config HIGHBANK config HIGHBANK
bool bool
@ -336,6 +337,7 @@ config STM32F205_SOC
config STM32F405_SOC config STM32F405_SOC
bool bool
select ARM_V7M select ARM_V7M
select OR_IRQ
select STM32F4XX_SYSCFG select STM32F4XX_SYSCFG
select STM32F4XX_EXTI select STM32F4XX_EXTI
@ -352,6 +354,7 @@ config XLNX_ZYNQMP_ARM
select XILINX_AXI select XILINX_AXI
select XILINX_SPIPS select XILINX_SPIPS
select XLNX_ZYNQMP select XLNX_ZYNQMP
select XLNX_ZDMA
config XLNX_VERSAL config XLNX_VERSAL
bool bool
@ -360,6 +363,8 @@ config XLNX_VERSAL
select CADENCE select CADENCE
select VIRTIO_MMIO select VIRTIO_MMIO
select UNIMP select UNIMP
select XLNX_ZDMA
select XLNX_ZYNQMP
config NPCM7XX config NPCM7XX
bool bool

View File

@ -142,7 +142,7 @@ static void canon_a1100_init(MachineState *machine)
static void canon_a1100_machine_init(MachineClass *mc) static void canon_a1100_machine_init(MachineClass *mc)
{ {
mc->desc = "Canon PowerShot A1100 IS"; mc->desc = "Canon PowerShot A1100 IS (ARM946)";
mc->init = &canon_a1100_init; mc->init = &canon_a1100_init;
mc->ignore_memory_transaction_failures = true; mc->ignore_memory_transaction_failures = true;
mc->default_ram_size = 64 * MiB; mc->default_ram_size = 64 * MiB;

View File

@ -64,7 +64,7 @@ static void microbit_machine_class_init(ObjectClass *oc, void *data)
{ {
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "BBC micro:bit"; mc->desc = "BBC micro:bit (Cortex-M0)";
mc->init = microbit_init; mc->init = microbit_init;
mc->max_cpus = 1; mc->max_cpus = 1;
} }

View File

@ -54,7 +54,7 @@ static void netduino2_init(MachineState *machine)
static void netduino2_machine_init(MachineClass *mc) static void netduino2_machine_init(MachineClass *mc)
{ {
mc->desc = "Netduino 2 Machine"; mc->desc = "Netduino 2 Machine (Cortex-M3)";
mc->init = netduino2_init; mc->init = netduino2_init;
mc->ignore_memory_transaction_failures = true; mc->ignore_memory_transaction_failures = true;
} }

View File

@ -55,7 +55,7 @@ static void netduinoplus2_init(MachineState *machine)
static void netduinoplus2_machine_init(MachineClass *mc) static void netduinoplus2_machine_init(MachineClass *mc)
{ {
mc->desc = "Netduino Plus 2 Machine"; mc->desc = "Netduino Plus 2 Machine (Cortex-M4)";
mc->init = netduinoplus2_init; mc->init = netduinoplus2_init;
} }

View File

@ -113,7 +113,7 @@ static void orangepi_init(MachineState *machine)
static void orangepi_machine_init(MachineClass *mc) static void orangepi_machine_init(MachineClass *mc)
{ {
mc->desc = "Orange Pi PC"; mc->desc = "Orange Pi PC (Cortex-A7)";
mc->init = orangepi_init; mc->init = orangepi_init;
mc->block_default_type = IF_SD; mc->block_default_type = IF_SD;
mc->units_per_default_bus = 1; mc->units_per_default_bus = 1;

View File

@ -801,7 +801,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
{ {
SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu); SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
IOMMUTLBEvent event; IOMMUTLBEvent event;
uint8_t granule = tg; uint8_t granule;
if (!tg) { if (!tg) {
SMMUEventInfo event = {.inval_ste_allowed = true}; SMMUEventInfo event = {.inval_ste_allowed = true};
@ -821,6 +821,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
return; return;
} }
granule = tt->granule_sz; granule = tt->granule_sz;
} else {
granule = tg * 2 + 10;
} }
event.type = IOMMU_NOTIFIER_UNMAP; event.type = IOMMU_NOTIFIER_UNMAP;

View File

@ -1538,7 +1538,7 @@ static void lm3s811evb_class_init(ObjectClass *oc, void *data)
{ {
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "Stellaris LM3S811EVB"; mc->desc = "Stellaris LM3S811EVB (Cortex-M3)";
mc->init = lm3s811evb_init; mc->init = lm3s811evb_init;
mc->ignore_memory_transaction_failures = true; mc->ignore_memory_transaction_failures = true;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3"); mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
@ -1554,7 +1554,7 @@ static void lm3s6965evb_class_init(ObjectClass *oc, void *data)
{ {
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "Stellaris LM3S6965EVB"; mc->desc = "Stellaris LM3S6965EVB (Cortex-M3)";
mc->init = lm3s6965evb_init; mc->init = lm3s6965evb_init;
mc->ignore_memory_transaction_failures = true; mc->ignore_memory_transaction_failures = true;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3"); mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");

View File

@ -519,6 +519,7 @@ static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset,
s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY; s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
res = s->reg[I_(URXH)]; res = s->reg[I_(URXH)];
} }
qemu_chr_fe_accept_input(&s->chr);
exynos4210_uart_update_dmabusy(s); exynos4210_uart_update_dmabusy(s);
trace_exynos_uart_read(s->channel, offset, trace_exynos_uart_read(s->channel, offset,
exynos4210_uart_regname(offset), res); exynos4210_uart_regname(offset), res);
@ -553,7 +554,11 @@ static int exynos4210_uart_can_receive(void *opaque)
{ {
Exynos4210UartState *s = (Exynos4210UartState *)opaque; Exynos4210UartState *s = (Exynos4210UartState *)opaque;
return fifo_empty_elements_number(&s->rx); if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
return fifo_empty_elements_number(&s->rx);
} else {
return !(s->reg[I_(UTRSTAT)] & UTRSTAT_Rx_BUFFER_DATA_READY);
}
} }
static void exynos4210_uart_receive(void *opaque, const uint8_t *buf, int size) static void exynos4210_uart_receive(void *opaque, const uint8_t *buf, int size)

View File

@ -18,6 +18,9 @@ config ZYNQ_DEVCFG
bool bool
select REGISTER select REGISTER
config XLNX_ZDMA
bool
config STP2000 config STP2000
bool bool

View File

@ -9,7 +9,7 @@ softmmu_ss.add(when: 'CONFIG_ZYNQ_DEVCFG', if_true: files('xlnx-zynq-devcfg.c'))
softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_dma.c')) softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_dma.c'))
softmmu_ss.add(when: 'CONFIG_STP2000', if_true: files('sparc32_dma.c')) softmmu_ss.add(when: 'CONFIG_STP2000', if_true: files('sparc32_dma.c'))
softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx_dpdma.c')) softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx_dpdma.c'))
softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zdma.c')) softmmu_ss.add(when: 'CONFIG_XLNX_ZDMA', if_true: files('xlnx-zdma.c'))
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_dma.c', 'soc_dma.c')) softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_dma.c', 'soc_dma.c'))
softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_dma.c')) softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_dma.c'))
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_dma.c')) softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_dma.c'))

View File

@ -28,6 +28,7 @@
#include "qemu/module.h" #include "qemu/module.h"
#include "trace.h" #include "trace.h"
#include "sysemu/kvm.h" #include "sysemu/kvm.h"
#include "sysemu/qtest.h"
/* #define DEBUG_GIC */ /* #define DEBUG_GIC */
@ -57,7 +58,7 @@ static const uint8_t gic_id_gicv2[] = {
static inline int gic_get_current_cpu(GICState *s) static inline int gic_get_current_cpu(GICState *s)
{ {
if (s->num_cpu > 1) { if (!qtest_enabled() && s->num_cpu > 1) {
return current_cpu->cpu_index; return current_cpu->cpu_index;
} }
return 0; return 0;
@ -1476,7 +1477,7 @@ static void gic_dist_writel(void *opaque, hwaddr offset,
int target_cpu; int target_cpu;
cpu = gic_get_current_cpu(s); cpu = gic_get_current_cpu(s);
irq = value & 0x3ff; irq = value & 0xf;
switch ((value >> 24) & 3) { switch ((value >> 24) & 3) {
case 0: case 0:
mask = (value >> 16) & ALL_CPU_MASK; mask = (value >> 16) & ALL_CPU_MASK;

View File

@ -128,7 +128,14 @@ static uint8_t imx_spi_selected_channel(IMXSPIState *s)
static uint32_t imx_spi_burst_length(IMXSPIState *s) static uint32_t imx_spi_burst_length(IMXSPIState *s)
{ {
return EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1; uint32_t burst;
burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
if (burst % 8) {
burst = ROUND_UP(burst, 8);
}
return burst;
} }
static bool imx_spi_is_enabled(IMXSPIState *s) static bool imx_spi_is_enabled(IMXSPIState *s)
@ -162,7 +169,6 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
while (!fifo32_is_empty(&s->tx_fifo)) { while (!fifo32_is_empty(&s->tx_fifo)) {
int tx_burst = 0; int tx_burst = 0;
int index = 0;
if (s->burst_length <= 0) { if (s->burst_length <= 0) {
s->burst_length = imx_spi_burst_length(s); s->burst_length = imx_spi_burst_length(s);
@ -178,12 +184,12 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
DPRINTF("data tx:0x%08x\n", tx); DPRINTF("data tx:0x%08x\n", tx);
tx_burst = MIN(s->burst_length, 32); tx_burst = (s->burst_length % 32) ? : 32;
rx = 0; rx = 0;
while (tx_burst > 0) { while (tx_burst > 0) {
uint8_t byte = tx & 0xff; uint8_t byte = tx >> (tx_burst - 8);
DPRINTF("writing 0x%02x\n", (uint32_t)byte); DPRINTF("writing 0x%02x\n", (uint32_t)byte);
@ -192,13 +198,11 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
DPRINTF("0x%02x read\n", (uint32_t)byte); DPRINTF("0x%02x read\n", (uint32_t)byte);
tx = tx >> 8; rx = (rx << 8) | byte;
rx |= (byte << (index * 8));
/* Remove 8 bits from the actual burst */ /* Remove 8 bits from the actual burst */
tx_burst -= 8; tx_burst -= 8;
s->burst_length -= 8; s->burst_length -= 8;
index++;
} }
DPRINTF("data rx:0x%08x\n", rx); DPRINTF("data rx:0x%08x\n", rx);
@ -228,22 +232,49 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo)); fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
} }
static void imx_spi_reset(DeviceState *dev) static void imx_spi_common_reset(IMXSPIState *s)
{ {
IMXSPIState *s = IMX_SPI(dev); int i;
DPRINTF("\n"); for (i = 0; i < ARRAY_SIZE(s->regs); i++) {
switch (i) {
memset(s->regs, 0, sizeof(s->regs)); case ECSPI_CONREG:
/* CONREG is not updated on soft reset */
s->regs[ECSPI_STATREG] = 0x00000003; break;
case ECSPI_STATREG:
s->regs[i] = 0x00000003;
break;
default:
s->regs[i] = 0;
break;
}
}
imx_spi_rxfifo_reset(s); imx_spi_rxfifo_reset(s);
imx_spi_txfifo_reset(s); imx_spi_txfifo_reset(s);
s->burst_length = 0;
}
static void imx_spi_soft_reset(IMXSPIState *s)
{
int i;
imx_spi_common_reset(s);
imx_spi_update_irq(s); imx_spi_update_irq(s);
s->burst_length = 0; for (i = 0; i < ECSPI_NUM_CS; i++) {
qemu_set_irq(s->cs_lines[i], 1);
}
}
static void imx_spi_reset(DeviceState *dev)
{
IMXSPIState *s = IMX_SPI(dev);
imx_spi_common_reset(s);
s->regs[ECSPI_CONREG] = 0;
} }
static uint64_t imx_spi_read(void *opaque, hwaddr offset, unsigned size) static uint64_t imx_spi_read(void *opaque, hwaddr offset, unsigned size)
@ -258,42 +289,40 @@ static uint64_t imx_spi_read(void *opaque, hwaddr offset, unsigned size)
return 0; return 0;
} }
switch (index) { value = s->regs[index];
case ECSPI_RXDATA:
if (!imx_spi_is_enabled(s)) { if (imx_spi_is_enabled(s)) {
value = 0; switch (index) {
} else if (fifo32_is_empty(&s->rx_fifo)) { case ECSPI_RXDATA:
/* value is undefined */ if (fifo32_is_empty(&s->rx_fifo)) {
value = 0xdeadbeef; /* value is undefined */
} else { value = 0xdeadbeef;
/* read from the RX FIFO */ } else {
value = fifo32_pop(&s->rx_fifo); /* read from the RX FIFO */
value = fifo32_pop(&s->rx_fifo);
}
break;
case ECSPI_TXDATA:
qemu_log_mask(LOG_GUEST_ERROR,
"[%s]%s: Trying to read from TX FIFO\n",
TYPE_IMX_SPI, __func__);
/* Reading from TXDATA gives 0 */
break;
case ECSPI_MSGDATA:
qemu_log_mask(LOG_GUEST_ERROR,
"[%s]%s: Trying to read from MSG FIFO\n",
TYPE_IMX_SPI, __func__);
/* Reading from MSGDATA gives 0 */
break;
default:
break;
} }
break; imx_spi_update_irq(s);
case ECSPI_TXDATA:
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read from TX FIFO\n",
TYPE_IMX_SPI, __func__);
/* Reading from TXDATA gives 0 */
break;
case ECSPI_MSGDATA:
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read from MSG FIFO\n",
TYPE_IMX_SPI, __func__);
/* Reading from MSGDATA gives 0 */
break;
default:
value = s->regs[index];
break;
} }
DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx_spi_reg_name(index), value); DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx_spi_reg_name(index), value);
imx_spi_update_irq(s);
return (uint64_t)value; return (uint64_t)value;
} }
@ -303,6 +332,7 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
IMXSPIState *s = opaque; IMXSPIState *s = opaque;
uint32_t index = offset >> 2; uint32_t index = offset >> 2;
uint32_t change_mask; uint32_t change_mask;
uint32_t burst;
if (index >= ECSPI_MAX) { if (index >= ECSPI_MAX) {
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
@ -313,6 +343,14 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx_spi_reg_name(index), DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx_spi_reg_name(index),
(uint32_t)value); (uint32_t)value);
if (!imx_spi_is_enabled(s)) {
/* Block is disabled */
if (index != ECSPI_CONREG) {
/* Ignore access */
return;
}
}
change_mask = s->regs[index] ^ value; change_mask = s->regs[index] ^ value;
switch (index) { switch (index) {
@ -321,10 +359,7 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
TYPE_IMX_SPI, __func__); TYPE_IMX_SPI, __func__);
break; break;
case ECSPI_TXDATA: case ECSPI_TXDATA:
if (!imx_spi_is_enabled(s)) { if (fifo32_is_full(&s->tx_fifo)) {
/* Ignore writes if device is disabled */
break;
} else if (fifo32_is_full(&s->tx_fifo)) {
/* Ignore writes if queue is full */ /* Ignore writes if queue is full */
break; break;
} }
@ -350,9 +385,17 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
case ECSPI_CONREG: case ECSPI_CONREG:
s->regs[ECSPI_CONREG] = value; s->regs[ECSPI_CONREG] = value;
burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
if (burst % 8) {
qemu_log_mask(LOG_UNIMP,
"[%s]%s: burst length %d not supported: rounding up to next multiple of 8\n",
TYPE_IMX_SPI, __func__, burst);
}
if (!imx_spi_is_enabled(s)) { if (!imx_spi_is_enabled(s)) {
/* device is disabled, so this is a reset */ /* device is disabled, so this is a soft reset */
imx_spi_reset(DEVICE(s)); imx_spi_soft_reset(s);
return; return;
} }
@ -361,7 +404,7 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
/* We are in master mode */ /* We are in master mode */
for (i = 0; i < 4; i++) { for (i = 0; i < ECSPI_NUM_CS; i++) {
qemu_set_irq(s->cs_lines[i], qemu_set_irq(s->cs_lines[i],
i == imx_spi_selected_channel(s) ? 0 : 1); i == imx_spi_selected_channel(s) ? 0 : 1);
} }
@ -424,12 +467,10 @@ static void imx_spi_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
for (i = 0; i < 4; ++i) { for (i = 0; i < ECSPI_NUM_CS; ++i) {
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->cs_lines[i]); sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->cs_lines[i]);
} }
s->burst_length = 0;
fifo32_create(&s->tx_fifo, ECSPI_FIFO_SIZE); fifo32_create(&s->tx_fifo, ECSPI_FIFO_SIZE);
fifo32_create(&s->rx_fifo, ECSPI_FIFO_SIZE); fifo32_create(&s->rx_fifo, ECSPI_FIFO_SIZE);
} }

View File

@ -77,6 +77,9 @@
#define EXTRACT(value, name) extract32(value, name##_SHIFT, name##_LENGTH) #define EXTRACT(value, name) extract32(value, name##_SHIFT, name##_LENGTH)
/* number of chip selects supported */
#define ECSPI_NUM_CS 4
#define TYPE_IMX_SPI "imx.spi" #define TYPE_IMX_SPI "imx.spi"
OBJECT_DECLARE_SIMPLE_TYPE(IMXSPIState, IMX_SPI) OBJECT_DECLARE_SIMPLE_TYPE(IMXSPIState, IMX_SPI)
@ -89,7 +92,7 @@ struct IMXSPIState {
qemu_irq irq; qemu_irq irq;
qemu_irq cs_lines[4]; qemu_irq cs_lines[ECSPI_NUM_CS];
SSIBus *bus; SSIBus *bus;