diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/arm/aspeed.c | 4 | ||||
-rw-r--r-- | hw/arm/aspeed_soc.c | 74 | ||||
-rw-r--r-- | hw/arm/boot.c | 4 | ||||
-rw-r--r-- | hw/arm/pxa2xx.c | 2 | ||||
-rw-r--r-- | hw/arm/virt-acpi-build.c | 14 | ||||
-rw-r--r-- | hw/arm/virt.c | 15 | ||||
-rw-r--r-- | hw/char/pl011.c | 71 | ||||
-rw-r--r-- | hw/char/trace-events | 9 | ||||
-rw-r--r-- | hw/dma/pl080.c | 2 | ||||
-rw-r--r-- | hw/dma/xilinx_axidma.c | 8 | ||||
-rw-r--r-- | hw/intc/arm_gic_kvm.c | 14 | ||||
-rw-r--r-- | hw/intc/arm_gicv3_cpuif.c | 23 | ||||
-rw-r--r-- | hw/intc/trace-events | 14 | ||||
-rw-r--r-- | hw/ssi/aspeed_smc.c | 194 |
14 files changed, 337 insertions, 111 deletions
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 6b18c7f172..c7206fda6d 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -128,8 +128,8 @@ static void aspeed_board_init(MachineState *machine, object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram), &error_abort); - aspeed_board_init_flashes(&bmc->soc.smc, "n25q256a", &error_abort); - aspeed_board_init_flashes(&bmc->soc.spi, "mx25l25635e", &error_abort); + aspeed_board_init_flashes(&bmc->soc.fmc, "n25q256a", &error_abort); + aspeed_board_init_flashes(&bmc->soc.spi[0], "mx25l25635e", &error_abort); aspeed_board_binfo.kernel_filename = machine->kernel_filename; aspeed_board_binfo.initrd_filename = machine->initrd_filename; diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index c0a3102058..e14f5c217e 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -25,25 +25,37 @@ #define ASPEED_SOC_IOMEM_BASE 0x1E600000 #define ASPEED_SOC_FMC_BASE 0x1E620000 #define ASPEED_SOC_SPI_BASE 0x1E630000 +#define ASPEED_SOC_SPI2_BASE 0x1E631000 #define ASPEED_SOC_VIC_BASE 0x1E6C0000 #define ASPEED_SOC_SDMC_BASE 0x1E6E0000 #define ASPEED_SOC_SCU_BASE 0x1E6E2000 #define ASPEED_SOC_TIMER_BASE 0x1E782000 #define ASPEED_SOC_I2C_BASE 0x1E78A000 -#define ASPEED_SOC_FMC_FLASH_BASE 0x20000000 -#define ASPEED_SOC_SPI_FLASH_BASE 0x30000000 - static const int uart_irqs[] = { 9, 32, 33, 34, 10 }; static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; #define AST2400_SDRAM_BASE 0x40000000 #define AST2500_SDRAM_BASE 0x80000000 +static const hwaddr aspeed_soc_ast2400_spi_bases[] = { ASPEED_SOC_SPI_BASE }; +static const char *aspeed_soc_ast2400_typenames[] = { "aspeed.smc.spi" }; + +static const hwaddr aspeed_soc_ast2500_spi_bases[] = { ASPEED_SOC_SPI_BASE, + ASPEED_SOC_SPI2_BASE}; +static const char *aspeed_soc_ast2500_typenames[] = { + "aspeed.smc.ast2500-spi1", "aspeed.smc.ast2500-spi2" }; + static const AspeedSoCInfo aspeed_socs[] = { - { "ast2400-a0", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE }, - { "ast2400", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE }, - { "ast2500-a1", "arm1176", AST2500_A1_SILICON_REV, AST2500_SDRAM_BASE }, + { "ast2400-a0", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE, + 1, aspeed_soc_ast2400_spi_bases, + "aspeed.smc.fmc", aspeed_soc_ast2400_typenames }, + { "ast2400", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE, + 1, aspeed_soc_ast2400_spi_bases, + "aspeed.smc.fmc", aspeed_soc_ast2400_typenames }, + { "ast2500-a1", "arm1176", AST2500_A1_SILICON_REV, AST2500_SDRAM_BASE, + 2, aspeed_soc_ast2500_spi_bases, + "aspeed.smc.ast2500-fmc", aspeed_soc_ast2500_typenames }, }; /* @@ -75,6 +87,7 @@ static void aspeed_soc_init(Object *obj) { AspeedSoCState *s = ASPEED_SOC(obj); AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + int i; s->cpu = cpu_arm_init(sc->info->cpu_model); @@ -100,13 +113,16 @@ static void aspeed_soc_init(Object *obj) object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), "hw-strap2", &error_abort); - object_initialize(&s->smc, sizeof(s->smc), "aspeed.smc.fmc"); - object_property_add_child(obj, "smc", OBJECT(&s->smc), NULL); - qdev_set_parent_bus(DEVICE(&s->smc), sysbus_get_default()); + object_initialize(&s->fmc, sizeof(s->fmc), sc->info->fmc_typename); + object_property_add_child(obj, "fmc", OBJECT(&s->fmc), NULL); + qdev_set_parent_bus(DEVICE(&s->fmc), sysbus_get_default()); - object_initialize(&s->spi, sizeof(s->spi), "aspeed.smc.spi"); - object_property_add_child(obj, "spi", OBJECT(&s->spi), NULL); - qdev_set_parent_bus(DEVICE(&s->spi), sysbus_get_default()); + for (i = 0; i < sc->info->spis_num; i++) { + object_initialize(&s->spi[i], sizeof(s->spi[i]), + sc->info->spi_typename[i]); + object_property_add_child(obj, "spi", OBJECT(&s->spi[i]), NULL); + qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default()); + } object_initialize(&s->sdmc, sizeof(s->sdmc), TYPE_ASPEED_SDMC); object_property_add_child(obj, "sdmc", OBJECT(&s->sdmc), NULL); @@ -121,6 +137,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) { int i; AspeedSoCState *s = ASPEED_SOC(dev); + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); Error *err = NULL, *local_err = NULL; /* IO space */ @@ -178,29 +195,34 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0, qdev_get_gpio_in(DEVICE(&s->vic), 12)); - /* SMC */ - object_property_set_int(OBJECT(&s->smc), 1, "num-cs", &err); - object_property_set_bool(OBJECT(&s->smc), true, "realized", &local_err); + /* FMC */ + object_property_set_int(OBJECT(&s->fmc), 1, "num-cs", &err); + object_property_set_bool(OBJECT(&s->fmc), true, "realized", &local_err); error_propagate(&err, local_err); if (err) { error_propagate(errp, err); return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 0, ASPEED_SOC_FMC_BASE); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 1, ASPEED_SOC_FMC_FLASH_BASE); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->smc), 0, + sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, ASPEED_SOC_FMC_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1, + s->fmc.ctrl->flash_window_base); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0, qdev_get_gpio_in(DEVICE(&s->vic), 19)); /* SPI */ - object_property_set_int(OBJECT(&s->spi), 1, "num-cs", &err); - object_property_set_bool(OBJECT(&s->spi), true, "realized", &local_err); - error_propagate(&err, local_err); - if (err) { - error_propagate(errp, err); - return; + for (i = 0; i < sc->info->spis_num; i++) { + object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &err); + object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", + &local_err); + error_propagate(&err, local_err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, sc->info->spi_bases[i]); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1, + s->spi[i].ctrl->flash_window_base); } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 0, ASPEED_SOC_SPI_BASE); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 1, ASPEED_SOC_SPI_FLASH_BASE); /* SDMC - SDRAM Memory Controller */ object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err); diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 1b913a43ca..942416d95a 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -773,6 +773,8 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) */ assert(!(info->secure_board_setup && kvm_enabled())); + info->dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb"); + /* Load the kernel. */ if (!info->kernel_filename || info->firmware_loaded) { @@ -833,8 +835,6 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) elf_machine = EM_ARM; } - info->dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb"); - if (!info->secondary_cpu_reset_hook) { info->secondary_cpu_reset_hook = default_reset_secondary; } diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 0241e07d84..98982872d7 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -1505,7 +1505,7 @@ static void pxa2xx_i2c_initfn(Object *obj) PXA2xxI2CState *s = PXA2XX_I2C(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - s->bus = i2c_init_bus(dev, "i2c"); + s->bus = i2c_init_bus(dev, NULL); memory_region_init_io(&s->iomem, obj, &pxa2xx_i2c_ops, s, "pxa2xx-i2c", s->region_size); diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index c77525d33a..fa0655a775 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -554,15 +554,13 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base); gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size); - if (!its_class_name()) { - return; + if (its_class_name() && !guest_info->no_its) { + gic_its = acpi_data_push(table_data, sizeof *gic_its); + gic_its->type = ACPI_APIC_GENERIC_TRANSLATOR; + gic_its->length = sizeof(*gic_its); + gic_its->translation_id = 0; + gic_its->base_address = cpu_to_le64(memmap[VIRT_GIC_ITS].base); } - - gic_its = acpi_data_push(table_data, sizeof *gic_its); - gic_its->type = ACPI_APIC_GENERIC_TRANSLATOR; - gic_its->length = sizeof(*gic_its); - gic_its->translation_id = 0; - gic_its->base_address = cpu_to_le64(memmap[VIRT_GIC_ITS].base); } else { gic_msi = acpi_data_push(table_data, sizeof *gic_msi); gic_msi->type = ACPI_APIC_GENERIC_MSI_FRAME; diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 795740d9bf..895446f17c 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -84,6 +84,7 @@ typedef struct { MachineClass parent; VirtBoardInfo *daughterboard; bool disallow_affinity_adjustment; + bool no_its; } VirtMachineClass; typedef struct { @@ -551,7 +552,8 @@ static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic) fdt_add_v2m_gic_node(vbi); } -static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure) +static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, + bool secure, bool no_its) { /* We create a standalone GIC */ DeviceState *gicdev; @@ -615,9 +617,9 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure) fdt_add_gic_node(vbi, type); - if (type == 3) { + if (type == 3 && !no_its) { create_its(vbi, gicdev); - } else { + } else if (type == 2) { create_v2m(vbi, pic); } } @@ -1375,7 +1377,7 @@ static void machvirt_init(MachineState *machine) create_flash(vbi, sysmem, secure_sysmem ? secure_sysmem : sysmem); - create_gic(vbi, pic, gic_version, vms->secure); + create_gic(vbi, pic, gic_version, vms->secure, vmc->no_its); fdt_add_pmu_nodes(vbi, gic_version); @@ -1407,6 +1409,7 @@ static void machvirt_init(MachineState *machine) guest_info->irqmap = vbi->irqmap; guest_info->use_highmem = vms->highmem; guest_info->gic_version = gic_version; + guest_info->no_its = vmc->no_its; guest_info_state->machine_done.notify = virt_guest_info_machine_done; qemu_add_machine_init_done_notifier(&guest_info_state->machine_done); @@ -1561,8 +1564,12 @@ static void virt_2_7_instance_init(Object *obj) static void virt_machine_2_7_options(MachineClass *mc) { + VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc)); + virt_machine_2_8_options(mc); SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_7); + /* ITS was introduced with 2.8 */ + vmc->no_its = true; } DEFINE_VIRT_MACHINE(2, 7) diff --git a/hw/char/pl011.c b/hw/char/pl011.c index 786e605fdd..1a7911f81f 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -11,6 +11,7 @@ #include "hw/sysbus.h" #include "sysemu/char.h" #include "qemu/log.h" +#include "trace.h" #define TYPE_PL011 "pl011" #define PL011(obj) OBJECT_CHECK(PL011State, (obj), TYPE_PL011) @@ -58,6 +59,7 @@ static void pl011_update(PL011State *s) uint32_t flags; flags = s->int_level & s->int_enabled; + trace_pl011_irq_state(flags != 0); qemu_set_irq(s->irq, flags != 0); } @@ -66,10 +68,8 @@ static uint64_t pl011_read(void *opaque, hwaddr offset, { PL011State *s = (PL011State *)opaque; uint32_t c; + uint64_t r; - if (offset >= 0xfe0 && offset < 0x1000) { - return s->id[(offset - 0xfe0) >> 2]; - } switch (offset >> 2) { case 0: /* UARTDR */ s->flags &= ~PL011_FLAG_RXFF; @@ -84,41 +84,62 @@ static uint64_t pl011_read(void *opaque, hwaddr offset, } if (s->read_count == s->read_trigger - 1) s->int_level &= ~ PL011_INT_RX; + trace_pl011_read_fifo(s->read_count); s->rsr = c >> 8; pl011_update(s); if (s->chr) { qemu_chr_accept_input(s->chr); } - return c; + r = c; + break; case 1: /* UARTRSR */ - return s->rsr; + r = s->rsr; + break; case 6: /* UARTFR */ - return s->flags; + r = s->flags; + break; case 8: /* UARTILPR */ - return s->ilpr; + r = s->ilpr; + break; case 9: /* UARTIBRD */ - return s->ibrd; + r = s->ibrd; + break; case 10: /* UARTFBRD */ - return s->fbrd; + r = s->fbrd; + break; case 11: /* UARTLCR_H */ - return s->lcr; + r = s->lcr; + break; case 12: /* UARTCR */ - return s->cr; + r = s->cr; + break; case 13: /* UARTIFLS */ - return s->ifl; + r = s->ifl; + break; case 14: /* UARTIMSC */ - return s->int_enabled; + r = s->int_enabled; + break; case 15: /* UARTRIS */ - return s->int_level; + r = s->int_level; + break; case 16: /* UARTMIS */ - return s->int_level & s->int_enabled; + r = s->int_level & s->int_enabled; + break; case 18: /* UARTDMACR */ - return s->dmacr; + r = s->dmacr; + break; + case 0x3f8 ... 0x400: + r = s->id[(offset - 0xfe0) >> 2]; + break; default: qemu_log_mask(LOG_GUEST_ERROR, "pl011_read: Bad offset %x\n", (int)offset); - return 0; + r = 0; + break; } + + trace_pl011_read(offset, r); + return r; } static void pl011_set_read_trigger(PL011State *s) @@ -141,6 +162,8 @@ static void pl011_write(void *opaque, hwaddr offset, PL011State *s = (PL011State *)opaque; unsigned char ch; + trace_pl011_write(offset, value); + switch (offset >> 2) { case 0: /* UARTDR */ /* ??? Check if transmitter is enabled. */ @@ -207,11 +230,15 @@ static void pl011_write(void *opaque, hwaddr offset, static int pl011_can_receive(void *opaque) { PL011State *s = (PL011State *)opaque; + int r; - if (s->lcr & 0x10) - return s->read_count < 16; - else - return s->read_count < 1; + if (s->lcr & 0x10) { + r = s->read_count < 16; + } else { + r = s->read_count < 1; + } + trace_pl011_can_receive(s->lcr, s->read_count, r); + return r; } static void pl011_put_fifo(void *opaque, uint32_t value) @@ -225,7 +252,9 @@ static void pl011_put_fifo(void *opaque, uint32_t value) s->read_fifo[slot] = value; s->read_count++; s->flags &= ~PL011_FLAG_RXFE; + trace_pl011_put_fifo(value, s->read_count); if (!(s->lcr & 0x10) || s->read_count == 16) { + trace_pl011_put_fifo_full(); s->flags |= PL011_FLAG_RXFF; } if (s->read_count == s->read_trigger) { diff --git a/hw/char/trace-events b/hw/char/trace-events index d53577c99d..7fd48bb80d 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -47,3 +47,12 @@ escc_sunkbd_event_in(int ch, const char *name, int down) "QKeyCode 0x%2.2x [%s], escc_sunkbd_event_out(int ch) "Translated keycode 0x%2.2x" escc_kbd_command(int val) "Command %d" escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=%01x" + +# hw/char/pl011.c +pl011_irq_state(int level) "irq state %d" +pl011_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" +pl011_read_fifo(int read_count) "FIFO read, read_count now %d" +pl011_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" +pl011_can_receive(uint32_t lcr, int read_count, int r) "LCR %08x read_count %d returning %d" +pl011_put_fifo(uint32_t c, int read_count) "new char 0x%x read_count now %d" +pl011_put_fifo_full(void) "FIFO now full, RXFF set" diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c index 3bed5c3390..7724c93b8f 100644 --- a/hw/dma/pl080.c +++ b/hw/dma/pl080.c @@ -351,7 +351,7 @@ static void pl080_write(void *opaque, hwaddr offset, break; case 12: /* Configuration */ s->conf = value; - if (s->conf & (PL080_CONF_M1 | PL080_CONF_M1)) { + if (s->conf & (PL080_CONF_M1 | PL080_CONF_M2)) { qemu_log_mask(LOG_UNIMP, "pl080_write: Big-endian DMA not implemented\n"); } diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index b135a5ff12..6065689ad1 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -111,6 +111,7 @@ struct Stream { unsigned int complete_cnt; uint32_t regs[R_MAX]; uint8_t app[20]; + unsigned char txbuf[16 * 1024]; }; struct XilinxAXIDMAStreamSlave { @@ -256,7 +257,6 @@ static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev, StreamSlave *tx_control_dev) { uint32_t prev_d; - unsigned char txbuf[16 * 1024]; unsigned int txlen; if (!stream_running(s) || stream_idle(s)) { @@ -277,17 +277,17 @@ static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev, } txlen = s->desc.control & SDESC_CTRL_LEN_MASK; - if ((txlen + s->pos) > sizeof txbuf) { + if ((txlen + s->pos) > sizeof s->txbuf) { hw_error("%s: too small internal txbuf! %d\n", __func__, txlen + s->pos); } cpu_physical_memory_read(s->desc.buffer_address, - txbuf + s->pos, txlen); + s->txbuf + s->pos, txlen); s->pos += txlen; if (stream_desc_eof(&s->desc)) { - stream_push(tx_data_dev, txbuf, s->pos); + stream_push(tx_data_dev, s->txbuf, s->pos); s->pos = 0; stream_complete(s); } diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index ae7ac58ffd..11729ee902 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -30,20 +30,6 @@ #include "gic_internal.h" #include "vgic_common.h" -//#define DEBUG_GIC_KVM - -#ifdef DEBUG_GIC_KVM -static const int debug_gic_kvm = 1; -#else -static const int debug_gic_kvm = 0; -#endif - -#define DPRINTF(fmt, ...) do { \ - if (debug_gic_kvm) { \ - printf("arm_gic: " fmt , ## __VA_ARGS__); \ - } \ - } while (0) - #define TYPE_KVM_ARM_GIC "kvm-arm-gic" #define KVM_ARM_GIC(obj) \ OBJECT_CHECK(GICState, (obj), TYPE_KVM_ARM_GIC) diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 4633172bec..bca30c49da 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -454,7 +454,8 @@ static void icc_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri, int irq = value & 0xffffff; int grp; - trace_gicv3_icc_eoir_write(gicv3_redist_affid(cs), value); + trace_gicv3_icc_eoir_write(ri->crm == 8 ? 0 : 1, + gicv3_redist_affid(cs), value); if (ri->crm == 8) { /* EOIR0 */ @@ -542,7 +543,7 @@ static uint64_t icc_bpr_read(CPUARMState *env, const ARMCPRegInfo *ri) bpr = MIN(bpr, 7); } - trace_gicv3_icc_bpr_read(gicv3_redist_affid(cs), bpr); + trace_gicv3_icc_bpr_read(ri->crm == 8 ? 0 : 1, gicv3_redist_affid(cs), bpr); return bpr; } @@ -553,7 +554,8 @@ static void icc_bpr_write(CPUARMState *env, const ARMCPRegInfo *ri, GICv3CPUState *cs = icc_cs_from_env(env); int grp = (ri->crm == 8) ? GICV3_G0 : GICV3_G1; - trace_gicv3_icc_pmr_write(gicv3_redist_affid(cs), value); + trace_gicv3_icc_bpr_write(ri->crm == 8 ? 0 : 1, + gicv3_redist_affid(cs), value); if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) { grp = GICV3_G1NS; @@ -591,7 +593,7 @@ static uint64_t icc_ap_read(CPUARMState *env, const ARMCPRegInfo *ri) value = cs->icc_apr[grp][regno]; - trace_gicv3_icc_ap_read(regno, gicv3_redist_affid(cs), value); + trace_gicv3_icc_ap_read(ri->crm & 1, regno, gicv3_redist_affid(cs), value); return value; } @@ -603,7 +605,7 @@ static void icc_ap_write(CPUARMState *env, const ARMCPRegInfo *ri, int regno = ri->opc2 & 3; int grp = ri->crm & 1 ? GICV3_G0 : GICV3_G1; - trace_gicv3_icc_ap_write(regno, gicv3_redist_affid(cs), value); + trace_gicv3_icc_ap_write(ri->crm & 1, regno, gicv3_redist_affid(cs), value); if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) { grp = GICV3_G1NS; @@ -820,7 +822,8 @@ static uint64_t icc_igrpen_read(CPUARMState *env, const ARMCPRegInfo *ri) } value = cs->icc_igrpen[grp]; - trace_gicv3_icc_igrpen_read(gicv3_redist_affid(cs), value); + trace_gicv3_icc_igrpen_read(ri->opc2 & 1 ? 1 : 0, + gicv3_redist_affid(cs), value); return value; } @@ -830,7 +833,8 @@ static void icc_igrpen_write(CPUARMState *env, const ARMCPRegInfo *ri, GICv3CPUState *cs = icc_cs_from_env(env); int grp = ri->opc2 & 1 ? GICV3_G1 : GICV3_G0; - trace_gicv3_icc_igrpen_write(gicv3_redist_affid(cs), value); + trace_gicv3_icc_igrpen_write(ri->opc2 & 1 ? 1 : 0, + gicv3_redist_affid(cs), value); if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) { grp = GICV3_G1NS; @@ -843,9 +847,12 @@ static void icc_igrpen_write(CPUARMState *env, const ARMCPRegInfo *ri, static uint64_t icc_igrpen1_el3_read(CPUARMState *env, const ARMCPRegInfo *ri) { GICv3CPUState *cs = icc_cs_from_env(env); + uint64_t value; /* IGRPEN1_EL3 bits 0 and 1 are r/w aliases into IGRPEN1_EL1 NS and S */ - return cs->icc_igrpen[GICV3_G1NS] | (cs->icc_igrpen[GICV3_G1] << 1); + value = cs->icc_igrpen[GICV3_G1NS] | (cs->icc_igrpen[GICV3_G1] << 1); + trace_gicv3_icc_igrpen1_el3_read(gicv3_redist_affid(cs), value); + return value; } static void icc_igrpen1_el3_write(CPUARMState *env, const ARMCPRegInfo *ri, diff --git a/hw/intc/trace-events b/hw/intc/trace-events index a367b46b1c..340f617761 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -85,12 +85,12 @@ gic_acknowledge_irq(int cpu, int irq) "cpu %d acknowledged irq %d" # hw/intc/arm_gicv3_cpuif.c gicv3_icc_pmr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_PMR read cpu %x value 0x%" PRIx64 gicv3_icc_pmr_write(uint32_t cpu, uint64_t val) "GICv3 ICC_PMR write cpu %x value 0x%" PRIx64 -gicv3_icc_bpr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_BPR read cpu %x value 0x%" PRIx64 -gicv3_icc_bpr_write(uint32_t cpu, uint64_t val) "GICv3 ICC_BPR write cpu %x value 0x%" PRIx64 -gicv3_icc_ap_read(int regno, uint32_t cpu, uint64_t val) "GICv3 ICC_AP%dR read cpu %x value 0x%" PRIx64 -gicv3_icc_ap_write(int regno, uint32_t cpu, uint64_t val) "GICv3 ICC_AP%dR write cpu %x value 0x%" PRIx64 -gicv3_icc_igrpen_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN read cpu %x value 0x%" PRIx64 -gicv3_icc_igrpen_write(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN write cpu %x value 0x%" PRIx64 +gicv3_icc_bpr_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICC_BPR%d read cpu %x value 0x%" PRIx64 +gicv3_icc_bpr_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICC_BPR%d write cpu %x value 0x%" PRIx64 +gicv3_icc_ap_read(int grp, int regno, uint32_t cpu, uint64_t val) "GICv3 ICC_AP%dR%d read cpu %x value 0x%" PRIx64 +gicv3_icc_ap_write(int grp, int regno, uint32_t cpu, uint64_t val) "GICv3 ICC_AP%dR%d write cpu %x value 0x%" PRIx64 +gicv3_icc_igrpen_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN%d read cpu %x value 0x%" PRIx64 +gicv3_icc_igrpen_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN%d write cpu %x value 0x%" PRIx64 gicv3_icc_igrpen1_el3_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN1_EL3 read cpu %x value 0x%" PRIx64 gicv3_icc_igrpen1_el3_write(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN1_EL3 write cpu %x value 0x%" PRIx64 gicv3_icc_ctlr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR read cpu %x value 0x%" PRIx64 @@ -102,7 +102,7 @@ gicv3_cpuif_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f gicv3_icc_generate_sgi(uint32_t cpuid, int irq, int irm, uint32_t aff, uint32_t targetlist) "GICv3 CPU i/f %x generating SGI %d IRM %d target affinity 0x%xxx targetlist 0x%x" gicv3_icc_iar0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IAR0 read cpu %x value 0x%" PRIx64 gicv3_icc_iar1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IAR1 read cpu %x value 0x%" PRIx64 -gicv3_icc_eoir_write(uint32_t cpu, uint64_t val) "GICv3 ICC_EOIR write cpu %x value 0x%" PRIx64 +gicv3_icc_eoir_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICC_EOIR%d write cpu %x value 0x%" PRIx64 gicv3_icc_hppir0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR0 read cpu %x value 0x%" PRIx64 gicv3_icc_hppir1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR1 read cpu %x value 0x%" PRIx64 gicv3_icc_dir_write(uint32_t cpu, uint64_t val) "GICv3 ICC_DIR write cpu %x value 0x%" PRIx64 diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index d319e04a27..6e8403ebc2 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -79,10 +79,10 @@ /* CEx Segment Address Register */ #define R_SEG_ADDR0 (0x30 / 4) -#define SEG_SIZE_SHIFT 24 /* 8MB units */ -#define SEG_SIZE_MASK 0x7f +#define SEG_END_SHIFT 24 /* 8MB units */ +#define SEG_END_MASK 0xff #define SEG_START_SHIFT 16 /* address bit [A29-A23] */ -#define SEG_START_MASK 0x7f +#define SEG_START_MASK 0xff #define R_SEG_ADDR1 (0x34 / 4) #define R_SEG_ADDR2 (0x38 / 4) #define R_SEG_ADDR3 (0x3C / 4) @@ -127,18 +127,22 @@ #define R_SPI_MISC_CTRL (0x10 / 4) #define R_SPI_TIMINGS (0x14 / 4) +#define ASPEED_SOC_SMC_FLASH_BASE 0x10000000 +#define ASPEED_SOC_FMC_FLASH_BASE 0x20000000 +#define ASPEED_SOC_SPI_FLASH_BASE 0x30000000 +#define ASPEED_SOC_SPI2_FLASH_BASE 0x38000000 + /* * Default segments mapping addresses and size for each slave per * controller. These can be changed when board is initialized with the - * Segment Address Registers but they don't seem do be used on the - * field. + * Segment Address Registers. */ static const AspeedSegments aspeed_segments_legacy[] = { { 0x10000000, 32 * 1024 * 1024 }, }; static const AspeedSegments aspeed_segments_fmc[] = { - { 0x20000000, 64 * 1024 * 1024 }, + { 0x20000000, 64 * 1024 * 1024 }, /* start address is readonly */ { 0x24000000, 32 * 1024 * 1024 }, { 0x26000000, 32 * 1024 * 1024 }, { 0x28000000, 32 * 1024 * 1024 }, @@ -149,15 +153,155 @@ static const AspeedSegments aspeed_segments_spi[] = { { 0x30000000, 64 * 1024 * 1024 }, }; +static const AspeedSegments aspeed_segments_ast2500_fmc[] = { + { 0x20000000, 128 * 1024 * 1024 }, /* start address is readonly */ + { 0x28000000, 32 * 1024 * 1024 }, + { 0x2A000000, 32 * 1024 * 1024 }, +}; + +static const AspeedSegments aspeed_segments_ast2500_spi1[] = { + { 0x30000000, 32 * 1024 * 1024 }, /* start address is readonly */ + { 0x32000000, 96 * 1024 * 1024 }, /* end address is readonly */ +}; + +static const AspeedSegments aspeed_segments_ast2500_spi2[] = { + { 0x38000000, 32 * 1024 * 1024 }, /* start address is readonly */ + { 0x3A000000, 96 * 1024 * 1024 }, /* end address is readonly */ +}; + static const AspeedSMCController controllers[] = { { "aspeed.smc.smc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS, - CONF_ENABLE_W0, 5, aspeed_segments_legacy, 0x6000000 }, + CONF_ENABLE_W0, 5, aspeed_segments_legacy, + ASPEED_SOC_SMC_FLASH_BASE, 0x6000000 }, { "aspeed.smc.fmc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS, - CONF_ENABLE_W0, 5, aspeed_segments_fmc, 0x10000000 }, + CONF_ENABLE_W0, 5, aspeed_segments_fmc, + ASPEED_SOC_FMC_FLASH_BASE, 0x10000000 }, { "aspeed.smc.spi", R_SPI_CONF, 0xff, R_SPI_CTRL0, R_SPI_TIMINGS, - SPI_CONF_ENABLE_W0, 1, aspeed_segments_spi, 0x10000000 }, + SPI_CONF_ENABLE_W0, 1, aspeed_segments_spi, + ASPEED_SOC_SPI_FLASH_BASE, 0x10000000 }, + { "aspeed.smc.ast2500-fmc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS, + CONF_ENABLE_W0, 3, aspeed_segments_ast2500_fmc, + ASPEED_SOC_FMC_FLASH_BASE, 0x10000000 }, + { "aspeed.smc.ast2500-spi1", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS, + CONF_ENABLE_W0, 2, aspeed_segments_ast2500_spi1, + ASPEED_SOC_SPI_FLASH_BASE, 0x8000000 }, + { "aspeed.smc.ast2500-spi2", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS, + CONF_ENABLE_W0, 2, aspeed_segments_ast2500_spi2, + ASPEED_SOC_SPI2_FLASH_BASE, 0x8000000 }, }; +/* + * The Segment Register uses a 8MB unit to encode the start address + * and the end address of the mapping window of a flash SPI slave : + * + * | byte 1 | byte 2 | byte 3 | byte 4 | + * +--------+--------+--------+--------+ + * | end | start | 0 | 0 | + * + */ +static inline uint32_t aspeed_smc_segment_to_reg(const AspeedSegments *seg) +{ + uint32_t reg = 0; + reg |= ((seg->addr >> 23) & SEG_START_MASK) << SEG_START_SHIFT; + reg |= (((seg->addr + seg->size) >> 23) & SEG_END_MASK) << SEG_END_SHIFT; + return reg; +} + +static inline void aspeed_smc_reg_to_segment(uint32_t reg, AspeedSegments *seg) +{ + seg->addr = ((reg >> SEG_START_SHIFT) & SEG_START_MASK) << 23; + seg->size = (((reg >> SEG_END_SHIFT) & SEG_END_MASK) << 23) - seg->addr; +} + +static bool aspeed_smc_flash_overlap(const AspeedSMCState *s, + const AspeedSegments *new, + int cs) +{ + AspeedSegments seg; + int i; + + for (i = 0; i < s->ctrl->max_slaves; i++) { + if (i == cs) { + continue; + } + + aspeed_smc_reg_to_segment(s->regs[R_SEG_ADDR0 + i], &seg); + + if (new->addr + new->size > seg.addr && + new->addr < seg.addr + seg.size) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment CS%d [ 0x%" + HWADDR_PRIx" - 0x%"HWADDR_PRIx" ] overlaps with " + "CS%d [ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n", + s->ctrl->name, cs, new->addr, new->addr + new->size, + i, seg.addr, seg.addr + seg.size); + return true; + } + } + return false; +} + +static void aspeed_smc_flash_set_segment(AspeedSMCState *s, int cs, + uint64_t new) +{ + AspeedSMCFlash *fl = &s->flashes[cs]; + AspeedSegments seg; + + aspeed_smc_reg_to_segment(new, &seg); + + /* The start address of CS0 is read-only */ + if (cs == 0 && seg.addr != s->ctrl->flash_window_base) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Tried to change CS0 start address to 0x%" + HWADDR_PRIx "\n", s->ctrl->name, seg.addr); + return; + } + + /* + * The end address of the AST2500 spi controllers is also + * read-only. + */ + if ((s->ctrl->segments == aspeed_segments_ast2500_spi1 || + s->ctrl->segments == aspeed_segments_ast2500_spi2) && + cs == s->ctrl->max_slaves && + seg.addr + seg.size != s->ctrl->segments[cs].addr + + s->ctrl->segments[cs].size) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Tried to change CS%d end address to 0x%" + HWADDR_PRIx "\n", s->ctrl->name, cs, seg.addr); + return; + } + + /* Keep the segment in the overall flash window */ + if (seg.addr + seg.size <= s->ctrl->flash_window_base || + seg.addr > s->ctrl->flash_window_base + s->ctrl->flash_window_size) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment for CS%d is invalid : " + "[ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n", + s->ctrl->name, cs, seg.addr, seg.addr + seg.size); + return; + } + + /* Check start address vs. alignment */ + if (seg.addr % seg.size) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment for CS%d is not " + "aligned : [ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n", + s->ctrl->name, cs, seg.addr, seg.addr + seg.size); + } + + /* And segments should not overlap */ + if (aspeed_smc_flash_overlap(s, &seg, cs)) { + return; + } + + /* All should be fine now to move the region */ + memory_region_transaction_begin(); + memory_region_set_size(&fl->mmio, seg.size); + memory_region_set_address(&fl->mmio, seg.addr - s->ctrl->flash_window_base); + memory_region_set_enabled(&fl->mmio, true); + memory_region_transaction_commit(); + + s->regs[R_SEG_ADDR0 + cs] = new; +} + static uint64_t aspeed_smc_flash_default_read(void *opaque, hwaddr addr, unsigned size) { @@ -281,6 +425,12 @@ static void aspeed_smc_reset(DeviceState *d) s->regs[s->r_ctrl0 + i] |= CTRL_CE_STOP_ACTIVE; } + /* setup default segment register values for all */ + for (i = 0; i < s->ctrl->max_slaves; ++i) { + s->regs[R_SEG_ADDR0 + i] = + aspeed_smc_segment_to_reg(&s->ctrl->segments[i]); + } + aspeed_smc_update_cs(s); } @@ -301,6 +451,7 @@ static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size) addr == s->r_timings || addr == s->r_ce_ctrl || addr == R_INTR_CTRL || + (addr >= R_SEG_ADDR0 && addr < R_SEG_ADDR0 + s->ctrl->max_slaves) || (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs)) { return s->regs[addr]; } else { @@ -332,6 +483,13 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data, } else if (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs) { s->regs[addr] = value; aspeed_smc_update_cs(s); + } else if (addr >= R_SEG_ADDR0 && + addr < R_SEG_ADDR0 + s->ctrl->max_slaves) { + int cs = addr - R_SEG_ADDR0; + + if (value != s->regs[R_SEG_ADDR0 + cs]) { + aspeed_smc_flash_set_segment(s, cs, value); + } } else { qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n", __func__, addr); @@ -384,23 +542,33 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) aspeed_smc_reset(dev); + /* The memory region for the controller registers */ memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_smc_ops, s, s->ctrl->name, ASPEED_SMC_R_MAX * 4); sysbus_init_mmio(sbd, &s->mmio); /* - * Memory region where flash modules are remapped + * The container memory region representing the address space + * window in which the flash modules are mapped. The size and + * address depends on the SoC model and controller type. */ snprintf(name, sizeof(name), "%s.flash", s->ctrl->name); memory_region_init_io(&s->mmio_flash, OBJECT(s), &aspeed_smc_flash_default_ops, s, name, - s->ctrl->mapping_window_size); + s->ctrl->flash_window_size); sysbus_init_mmio(sbd, &s->mmio_flash); - s->flashes = g_new0(AspeedSMCFlash, s->num_cs); + s->flashes = g_new0(AspeedSMCFlash, s->ctrl->max_slaves); - for (i = 0; i < s->num_cs; ++i) { + /* + * Let's create a sub memory region for each possible slave. All + * have a configurable memory segment in the overall flash mapping + * window of the controller but, there is not necessarily a flash + * module behind to handle the memory accesses. This depends on + * the board configuration. + */ + for (i = 0; i < s->ctrl->max_slaves; ++i) { AspeedSMCFlash *fl = &s->flashes[i]; snprintf(name, sizeof(name), "%s.%d", s->ctrl->name, i); |