:p
atchew
Login
A grab-bag of minor stuff for the end of the year. My to-review queue is not empty, but it it at least in single figures... -- PMM The following changes since commit 5bfbd8170ce7acb98a1834ff49ed7340b0837144: Merge remote-tracking branch 'remotes/vivier2/tags/trivial-branch-for-6.0-pull-request' into staging (2020-12-14 20:32:38 +0000) are available in the Git repository at: https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20201215 for you to fetch changes up to 23af268566069183285bebbdf95b1b37cb7c0942: hw/block/m25p80: Fix Numonyx fast read dummy cycle count (2020-12-15 13:39:30 +0000) ---------------------------------------------------------------- target-arm queue: * gdbstub: Correct misparsing of vCont C/S requests * openrisc: Move pic_cpu code into CPU object proper * nios2: Move IIC code into CPU object proper * Improve reporting of ROM overlap errors * xlnx-versal: Add USB support * hw/misc/zynq_slcr: Avoid #DIV/0! error * Numonyx: Fix dummy cycles and check for SPI mode on cmds ---------------------------------------------------------------- Joe Komlodi (4): hw/block/m25p80: Make Numonyx config field names more accurate hw/block/m25p80: Fix when VCFG XIP bit is set for Numonyx hw/block/m25p80: Check SPI mode before running some Numonyx commands hw/block/m25p80: Fix Numonyx fast read dummy cycle count Peter Maydell (11): gdbstub: Correct misparsing of vCont C/S requests hw/openrisc/openrisc_sim: Use IRQ splitter when connecting IRQ to multiple CPUs hw/openrisc/openrisc_sim: Abstract out "get IRQ x of CPU y" target/openrisc: Move pic_cpu code into CPU object proper target/nios2: Move IIC code into CPU object proper target/nios2: Move nios2_check_interrupts() into target/nios2 target/nios2: Use deposit32() to update ipending register hw/core/loader.c: Track last-seen ROM in rom_check_and_register_reset() hw/core/loader.c: Improve reporting of ROM overlap errors elf_ops.h: Don't truncate name of the ROM blobs we create elf_ops.h: Be more verbose with ROM blob names Philippe Mathieu-Daudé (1): hw/misc/zynq_slcr: Avoid #DIV/0! error Sai Pavan Boddu (2): usb: Add versal-usb2-ctrl-regs module usb: xlnx-usb-subsystem: Add xilinx usb subsystem Vikram Garhwal (2): usb: Add DWC3 model arm: xlnx-versal: Connect usb to virt-versal include/hw/arm/xlnx-versal.h | 9 + include/hw/elf_ops.h | 5 +- include/hw/usb/hcd-dwc3.h | 55 +++ include/hw/usb/xlnx-usb-subsystem.h | 45 ++ include/hw/usb/xlnx-versal-usb2-ctrl-regs.h | 45 ++ target/nios2/cpu.h | 3 - target/openrisc/cpu.h | 1 - gdbstub.c | 2 +- hw/arm/xlnx-versal-virt.c | 55 +++ hw/arm/xlnx-versal.c | 26 ++ hw/block/m25p80.c | 158 +++++-- hw/core/loader.c | 67 ++- hw/intc/nios2_iic.c | 95 ---- hw/misc/zynq_slcr.c | 5 + hw/nios2/10m50_devboard.c | 13 +- hw/nios2/cpu_pic.c | 67 --- hw/openrisc/openrisc_sim.c | 46 +- hw/openrisc/pic_cpu.c | 61 --- hw/usb/hcd-dwc3.c | 689 ++++++++++++++++++++++++++++ hw/usb/xlnx-usb-subsystem.c | 94 ++++ hw/usb/xlnx-versal-usb2-ctrl-regs.c | 229 +++++++++ softmmu/vl.c | 1 - target/nios2/cpu.c | 29 ++ target/nios2/op_helper.c | 9 + target/openrisc/cpu.c | 32 ++ MAINTAINERS | 1 - hw/intc/meson.build | 1 - hw/nios2/meson.build | 2 +- hw/openrisc/Kconfig | 1 + hw/openrisc/meson.build | 2 +- hw/usb/Kconfig | 10 + hw/usb/meson.build | 3 + 32 files changed, 1557 insertions(+), 304 deletions(-) create mode 100644 include/hw/usb/hcd-dwc3.h create mode 100644 include/hw/usb/xlnx-usb-subsystem.h create mode 100644 include/hw/usb/xlnx-versal-usb2-ctrl-regs.h delete mode 100644 hw/intc/nios2_iic.c delete mode 100644 hw/nios2/cpu_pic.c delete mode 100644 hw/openrisc/pic_cpu.c create mode 100644 hw/usb/hcd-dwc3.c create mode 100644 hw/usb/xlnx-usb-subsystem.c create mode 100644 hw/usb/xlnx-versal-usb2-ctrl-regs.c
In the vCont packet, two of the command actions (C and S) take an argument specifying the signal to be sent to the process/thread, which is sent as an ASCII string of two hex digits which immediately follow the 'C' or 'S' character. Our code for parsing this packet accidentally skipped the first of the two bytes of the signal value, because it started parsing the hex string at 'p + 1' when the preceding code had already moved past the 'C' or 'S' with "cur_action = *p++". This meant that we would only do the right thing for signals below 10, and would misinterpret the rest. For instance, when the debugger wants to send the process a SIGPROF (27 on x86-64) we mangle this into a SIGSEGV (11). Remove the accidental double increment. Fixes: https://bugs.launchpad.net/qemu/+bug/1773743 Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20201121210342.10089-1-peter.maydell@linaro.org --- gdbstub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gdbstub.c b/gdbstub.c index XXXXXXX..XXXXXXX 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -XXX,XX +XXX,XX @@ static int gdb_handle_vcont(const char *p) cur_action = *p++; if (cur_action == 'C' || cur_action == 'S') { cur_action = qemu_tolower(cur_action); - res = qemu_strtoul(p + 1, &p, 16, &tmp); + res = qemu_strtoul(p, &p, 16, &tmp); if (res) { goto out; } -- 2.20.1
openrisc_sim_net_init() attempts to connect the IRQ line from the ethernet device to both CPUs in an SMP configuration by simply caling sysbus_connect_irq() for it twice. This doesn't work, because the second connection simply overrides the first. Fix this by creating a TYPE_SPLIT_IRQ to split the IRQ in the SMP case. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Stafford Horne <shorne@gmail.com> Message-id: 20201127225127.14770-2-peter.maydell@linaro.org --- hw/openrisc/openrisc_sim.c | 13 +++++++++++-- hw/openrisc/Kconfig | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index XXXXXXX..XXXXXXX 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -XXX,XX +XXX,XX @@ #include "hw/sysbus.h" #include "sysemu/qtest.h" #include "sysemu/reset.h" +#include "hw/core/split-irq.h" #define KERNEL_LOAD_ADDR 0x100 @@ -XXX,XX +XXX,XX @@ static void openrisc_sim_net_init(hwaddr base, hwaddr descriptors, s = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(s, &error_fatal); - for (i = 0; i < num_cpus; i++) { - sysbus_connect_irq(s, 0, cpu_irqs[i][irq_pin]); + if (num_cpus > 1) { + DeviceState *splitter = qdev_new(TYPE_SPLIT_IRQ); + qdev_prop_set_uint32(splitter, "num-lines", num_cpus); + qdev_realize_and_unref(splitter, NULL, &error_fatal); + for (i = 0; i < num_cpus; i++) { + qdev_connect_gpio_out(splitter, i, cpu_irqs[i][irq_pin]); + } + sysbus_connect_irq(s, 0, qdev_get_gpio_in(splitter, 0)); + } else { + sysbus_connect_irq(s, 0, cpu_irqs[0][irq_pin]); } sysbus_mmio_map(s, 0, base); sysbus_mmio_map(s, 1, descriptors); diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/openrisc/Kconfig +++ b/hw/openrisc/Kconfig @@ -XXX,XX +XXX,XX @@ config OR1K_SIM select SERIAL select OPENCORES_ETH select OMPIC + select SPLIT_IRQ -- 2.20.1
We're about to refactor the OpenRISC pic_cpu code in a way that means that just grabbing the whole qemu_irq[] array of inbound IRQs for a CPU won't be possible any more. Abstract out a function for "return the qemu_irq for IRQ x input of CPU y" so we can more easily replace the implementation. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Stafford Horne <shorne@gmail.com> Message-id: 20201127225127.14770-3-peter.maydell@linaro.org --- hw/openrisc/openrisc_sim.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index XXXXXXX..XXXXXXX 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -XXX,XX +XXX,XX @@ static void main_cpu_reset(void *opaque) cpu_set_pc(cs, boot_info.bootstrap_pc); } +static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) +{ + return cpus[cpunum]->env.irq[irq_pin]; +} + static void openrisc_sim_net_init(hwaddr base, hwaddr descriptors, - int num_cpus, qemu_irq **cpu_irqs, + int num_cpus, OpenRISCCPU *cpus[], int irq_pin, NICInfo *nd) { DeviceState *dev; @@ -XXX,XX +XXX,XX @@ static void openrisc_sim_net_init(hwaddr base, hwaddr descriptors, qdev_prop_set_uint32(splitter, "num-lines", num_cpus); qdev_realize_and_unref(splitter, NULL, &error_fatal); for (i = 0; i < num_cpus; i++) { - qdev_connect_gpio_out(splitter, i, cpu_irqs[i][irq_pin]); + qdev_connect_gpio_out(splitter, i, get_cpu_irq(cpus, i, irq_pin)); } sysbus_connect_irq(s, 0, qdev_get_gpio_in(splitter, 0)); } else { - sysbus_connect_irq(s, 0, cpu_irqs[0][irq_pin]); + sysbus_connect_irq(s, 0, get_cpu_irq(cpus, 0, irq_pin)); } sysbus_mmio_map(s, 0, base); sysbus_mmio_map(s, 1, descriptors); } static void openrisc_sim_ompic_init(hwaddr base, int num_cpus, - qemu_irq **cpu_irqs, int irq_pin) + OpenRISCCPU *cpus[], int irq_pin) { DeviceState *dev; SysBusDevice *s; @@ -XXX,XX +XXX,XX @@ static void openrisc_sim_ompic_init(hwaddr base, int num_cpus, s = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(s, &error_fatal); for (i = 0; i < num_cpus; i++) { - sysbus_connect_irq(s, i, cpu_irqs[i][irq_pin]); + sysbus_connect_irq(s, i, get_cpu_irq(cpus, i, irq_pin)); } sysbus_mmio_map(s, 0, base); } @@ -XXX,XX +XXX,XX @@ static void openrisc_sim_init(MachineState *machine) { ram_addr_t ram_size = machine->ram_size; const char *kernel_filename = machine->kernel_filename; - OpenRISCCPU *cpu = NULL; + OpenRISCCPU *cpus[2] = {}; MemoryRegion *ram; - qemu_irq *cpu_irqs[2]; qemu_irq serial_irq; int n; unsigned int smp_cpus = machine->smp.cpus; assert(smp_cpus >= 1 && smp_cpus <= 2); for (n = 0; n < smp_cpus; n++) { - cpu = OPENRISC_CPU(cpu_create(machine->cpu_type)); - if (cpu == NULL) { + cpus[n] = OPENRISC_CPU(cpu_create(machine->cpu_type)); + if (cpus[n] == NULL) { fprintf(stderr, "Unable to find CPU definition!\n"); exit(1); } - cpu_openrisc_pic_init(cpu); - cpu_irqs[n] = (qemu_irq *) cpu->env.irq; + cpu_openrisc_pic_init(cpus[n]); - cpu_openrisc_clock_init(cpu); + cpu_openrisc_clock_init(cpus[n]); - qemu_register_reset(main_cpu_reset, cpu); + qemu_register_reset(main_cpu_reset, cpus[n]); } ram = g_malloc(sizeof(*ram)); @@ -XXX,XX +XXX,XX @@ static void openrisc_sim_init(MachineState *machine) if (nd_table[0].used) { openrisc_sim_net_init(0x92000000, 0x92000400, smp_cpus, - cpu_irqs, 4, nd_table); + cpus, 4, nd_table); } if (smp_cpus > 1) { - openrisc_sim_ompic_init(0x98000000, smp_cpus, cpu_irqs, 1); + openrisc_sim_ompic_init(0x98000000, smp_cpus, cpus, 1); - serial_irq = qemu_irq_split(cpu_irqs[0][2], cpu_irqs[1][2]); + serial_irq = qemu_irq_split(get_cpu_irq(cpus, 0, 2), + get_cpu_irq(cpus, 1, 2)); } else { - serial_irq = cpu_irqs[0][2]; + serial_irq = get_cpu_irq(cpus, 0, 2); } serial_mm_init(get_system_memory(), 0x90000000, 0, serial_irq, -- 2.20.1
The openrisc code uses an old style of interrupt handling, where a separate standalone set of qemu_irqs invoke a function openrisc_pic_cpu_handler() which signals the interrupt to the CPU proper by directly calling cpu_interrupt() and cpu_reset_interrupt(). Because CPU objects now inherit (indirectly) from TYPE_DEVICE, they can have GPIO input lines themselves, and the neater modern way to implement this is to simply have the CPU object itself provide the input IRQ lines. Create GPIO inputs to the OpenRISC CPU object, and make the only user of cpu_openrisc_pic_init() wire up directly to those instead. This allows us to delete the hw/openrisc/pic_cpu.c file entirely. This fixes a trivial memory leak reported by Coverity of the IRQs allocated in cpu_openrisc_pic_init(). Fixes: Coverity CID 1421934 Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Stafford Horne <shorne@gmail.com> Message-id: 20201127225127.14770-4-peter.maydell@linaro.org --- target/openrisc/cpu.h | 1 - hw/openrisc/openrisc_sim.c | 3 +- hw/openrisc/pic_cpu.c | 61 -------------------------------------- target/openrisc/cpu.c | 32 ++++++++++++++++++++ hw/openrisc/meson.build | 2 +- 5 files changed, 34 insertions(+), 65 deletions(-) delete mode 100644 hw/openrisc/pic_cpu.c diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -XXX,XX +XXX,XX @@ typedef struct CPUOpenRISCState { uint32_t picmr; /* Interrupt mask register */ uint32_t picsr; /* Interrupt contrl register*/ #endif - void *irq[32]; /* Interrupt irq input */ } CPUOpenRISCState; /** diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index XXXXXXX..XXXXXXX 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -XXX,XX +XXX,XX @@ static void main_cpu_reset(void *opaque) static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) { - return cpus[cpunum]->env.irq[irq_pin]; + return qdev_get_gpio_in_named(DEVICE(cpus[cpunum]), "IRQ", irq_pin); } static void openrisc_sim_net_init(hwaddr base, hwaddr descriptors, @@ -XXX,XX +XXX,XX @@ static void openrisc_sim_init(MachineState *machine) fprintf(stderr, "Unable to find CPU definition!\n"); exit(1); } - cpu_openrisc_pic_init(cpus[n]); cpu_openrisc_clock_init(cpus[n]); diff --git a/hw/openrisc/pic_cpu.c b/hw/openrisc/pic_cpu.c deleted file mode 100644 index XXXXXXX..XXXXXXX --- a/hw/openrisc/pic_cpu.c +++ /dev/null @@ -XXX,XX +XXX,XX @@ -/* - * OpenRISC Programmable Interrupt Controller support. - * - * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> - * Feng Gao <gf91597@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "cpu.h" - -/* OpenRISC pic handler */ -static void openrisc_pic_cpu_handler(void *opaque, int irq, int level) -{ - OpenRISCCPU *cpu = (OpenRISCCPU *)opaque; - CPUState *cs = CPU(cpu); - uint32_t irq_bit; - - if (irq > 31 || irq < 0) { - return; - } - - irq_bit = 1U << irq; - - if (level) { - cpu->env.picsr |= irq_bit; - } else { - cpu->env.picsr &= ~irq_bit; - } - - if (cpu->env.picsr & cpu->env.picmr) { - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - cpu->env.picsr = 0; - } -} - -void cpu_openrisc_pic_init(OpenRISCCPU *cpu) -{ - int i; - qemu_irq *qi; - qi = qemu_allocate_irqs(openrisc_pic_cpu_handler, cpu, NR_IRQS); - - for (i = 0; i < NR_IRQS; i++) { - cpu->env.irq[i] = qi[i]; - } -} diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -XXX,XX +XXX,XX @@ static void openrisc_cpu_reset(DeviceState *dev) #endif } +#ifndef CONFIG_USER_ONLY +static void openrisc_cpu_set_irq(void *opaque, int irq, int level) +{ + OpenRISCCPU *cpu = (OpenRISCCPU *)opaque; + CPUState *cs = CPU(cpu); + uint32_t irq_bit; + + if (irq > 31 || irq < 0) { + return; + } + + irq_bit = 1U << irq; + + if (level) { + cpu->env.picsr |= irq_bit; + } else { + cpu->env.picsr &= ~irq_bit; + } + + if (cpu->env.picsr & cpu->env.picmr) { + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + cpu->env.picsr = 0; + } +} +#endif + static void openrisc_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); @@ -XXX,XX +XXX,XX @@ static void openrisc_cpu_initfn(Object *obj) OpenRISCCPU *cpu = OPENRISC_CPU(obj); cpu_set_cpustate_pointers(cpu); + +#ifndef CONFIG_USER_ONLY + qdev_init_gpio_in_named(DEVICE(cpu), openrisc_cpu_set_irq, "IRQ", NR_IRQS); +#endif } /* CPU models */ diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -XXX,XX +XXX,XX @@ openrisc_ss = ss.source_set() -openrisc_ss.add(files('pic_cpu.c', 'cputimer.c')) +openrisc_ss.add(files('cputimer.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: files('openrisc_sim.c')) hw_arch += {'openrisc': openrisc_ss} -- 2.20.1
The Nios2 architecture supports two different interrupt controller options: * The IIC (Internal Interrupt Controller) is part of the CPU itself; it has 32 IRQ input lines and no NMI support. Interrupt status is queried and controlled via the CPU's ipending and istatus registers. * The EIC (External Interrupt Controller) interface allows the CPU to connect to an external interrupt controller. The interface allows the interrupt controller to present a packet of information containing: - handler address - interrupt level - register set - NMI mode QEMU does not model an EIC currently. We do model the IIC, but its implementation is split across code in hw/nios2/cpu_pic.c and hw/intc/nios2_iic.c. The code in those two files has no state of its own -- the IIC state is in the Nios2CPU state struct. Because CPU objects now inherit (indirectly) from TYPE_DEVICE, they can have GPIO input lines themselves, so we can implement the IIC directly in the CPU object the same way that real hardware does. Create named "IRQ" GPIO inputs to the Nios2 CPU object, and make the only user of the IIC wire up directly to those instead. Note that the old code had an "NMI" concept which was entirely unused and also as far as I can see not architecturally correct, since only the EIC has a concept of an NMI. This fixes a Coverity-reported trivial memory leak of the IRQ array allocated in nios2_cpu_pic_init(). Fixes: Coverity CID 1421916 Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Message-id: 20201129174022.26530-2-peter.maydell@linaro.org Reviewed-by: Wentong Wu <wentong.wu@intel.com> Tested-by: Wentong Wu <wentong.wu@intel.com> --- target/nios2/cpu.h | 1 - hw/intc/nios2_iic.c | 95 --------------------------------------- hw/nios2/10m50_devboard.c | 13 +----- hw/nios2/cpu_pic.c | 31 ------------- target/nios2/cpu.c | 30 +++++++++++++ MAINTAINERS | 1 - hw/intc/meson.build | 1 - 7 files changed, 32 insertions(+), 140 deletions(-) delete mode 100644 hw/intc/nios2_iic.c diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/nios2/cpu.h +++ b/target/nios2/cpu.h @@ -XXX,XX +XXX,XX @@ void nios2_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr); -qemu_irq *nios2_cpu_pic_init(Nios2CPU *cpu); void nios2_check_interrupts(CPUNios2State *env); void do_nios2_semihosting(CPUNios2State *env); diff --git a/hw/intc/nios2_iic.c b/hw/intc/nios2_iic.c deleted file mode 100644 index XXXXXXX..XXXXXXX --- a/hw/intc/nios2_iic.c +++ /dev/null @@ -XXX,XX +XXX,XX @@ -/* - * QEMU Altera Internal Interrupt Controller. - * - * Copyright (c) 2012 Chris Wulff <crwulff@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * <http://www.gnu.org/licenses/lgpl-2.1.html> - */ - -#include "qemu/osdep.h" -#include "qemu/module.h" -#include "qapi/error.h" - -#include "hw/irq.h" -#include "hw/sysbus.h" -#include "cpu.h" -#include "qom/object.h" - -#define TYPE_ALTERA_IIC "altera,iic" -OBJECT_DECLARE_SIMPLE_TYPE(AlteraIIC, ALTERA_IIC) - -struct AlteraIIC { - SysBusDevice parent_obj; - void *cpu; - qemu_irq parent_irq; -}; - -static void update_irq(AlteraIIC *pv) -{ - CPUNios2State *env = &((Nios2CPU *)(pv->cpu))->env; - - qemu_set_irq(pv->parent_irq, - env->regs[CR_IPENDING] & env->regs[CR_IENABLE]); -} - -static void irq_handler(void *opaque, int irq, int level) -{ - AlteraIIC *pv = opaque; - CPUNios2State *env = &((Nios2CPU *)(pv->cpu))->env; - - env->regs[CR_IPENDING] &= ~(1 << irq); - env->regs[CR_IPENDING] |= !!level << irq; - - update_irq(pv); -} - -static void altera_iic_init(Object *obj) -{ - AlteraIIC *pv = ALTERA_IIC(obj); - - qdev_init_gpio_in(DEVICE(pv), irq_handler, 32); - sysbus_init_irq(SYS_BUS_DEVICE(obj), &pv->parent_irq); -} - -static void altera_iic_realize(DeviceState *dev, Error **errp) -{ - struct AlteraIIC *pv = ALTERA_IIC(dev); - - pv->cpu = object_property_get_link(OBJECT(dev), "cpu", &error_abort); -} - -static void altera_iic_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - /* Reason: needs to be wired up, e.g. by nios2_10m50_ghrd_init() */ - dc->user_creatable = false; - dc->realize = altera_iic_realize; -} - -static TypeInfo altera_iic_info = { - .name = TYPE_ALTERA_IIC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(AlteraIIC), - .instance_init = altera_iic_init, - .class_init = altera_iic_class_init, -}; - -static void altera_iic_register(void) -{ - type_register_static(&altera_iic_info); -} - -type_init(altera_iic_register) diff --git a/hw/nios2/10m50_devboard.c b/hw/nios2/10m50_devboard.c index XXXXXXX..XXXXXXX 100644 --- a/hw/nios2/10m50_devboard.c +++ b/hw/nios2/10m50_devboard.c @@ -XXX,XX +XXX,XX @@ static void nios2_10m50_ghrd_init(MachineState *machine) ram_addr_t tcm_size = 0x1000; /* 1 kiB, but QEMU limit is 4 kiB */ ram_addr_t ram_base = 0x08000000; ram_addr_t ram_size = 0x08000000; - qemu_irq *cpu_irq, irq[32]; + qemu_irq irq[32]; int i; /* Physical TCM (tb_ram_1k) with alias at 0xc0000000 */ @@ -XXX,XX +XXX,XX @@ static void nios2_10m50_ghrd_init(MachineState *machine) /* Create CPU -- FIXME */ cpu = NIOS2_CPU(cpu_create(TYPE_NIOS2_CPU)); - - /* Register: CPU interrupt controller (PIC) */ - cpu_irq = nios2_cpu_pic_init(cpu); - - /* Register: Internal Interrupt Controller (IIC) */ - dev = qdev_new("altera,iic"); - object_property_add_const_link(OBJECT(dev), "cpu", OBJECT(cpu)); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq[0]); for (i = 0; i < 32; i++) { - irq[i] = qdev_get_gpio_in(dev, i); + irq[i] = qdev_get_gpio_in_named(DEVICE(cpu), "IRQ", i); } /* Register: Altera 16550 UART */ diff --git a/hw/nios2/cpu_pic.c b/hw/nios2/cpu_pic.c index XXXXXXX..XXXXXXX 100644 --- a/hw/nios2/cpu_pic.c +++ b/hw/nios2/cpu_pic.c @@ -XXX,XX +XXX,XX @@ #include "boot.h" -static void nios2_pic_cpu_handler(void *opaque, int irq, int level) -{ - Nios2CPU *cpu = opaque; - CPUNios2State *env = &cpu->env; - CPUState *cs = CPU(cpu); - int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD; - - if (type == CPU_INTERRUPT_HARD) { - env->irq_pending = level; - - if (level && (env->regs[CR_STATUS] & CR_STATUS_PIE)) { - env->irq_pending = 0; - cpu_interrupt(cs, type); - } else if (!level) { - env->irq_pending = 0; - cpu_reset_interrupt(cs, type); - } - } else { - if (level) { - cpu_interrupt(cs, type); - } else { - cpu_reset_interrupt(cs, type); - } - } -} - void nios2_check_interrupts(CPUNios2State *env) { if (env->irq_pending && @@ -XXX,XX +XXX,XX @@ void nios2_check_interrupts(CPUNios2State *env) cpu_interrupt(env_cpu(env), CPU_INTERRUPT_HARD); } } - -qemu_irq *nios2_cpu_pic_init(Nios2CPU *cpu) -{ - return qemu_allocate_irqs(nios2_pic_cpu_handler, cpu, 2); -} diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/nios2/cpu.c +++ b/target/nios2/cpu.c @@ -XXX,XX +XXX,XX @@ static void nios2_cpu_reset(DeviceState *dev) #endif } +#ifndef CONFIG_USER_ONLY +static void nios2_cpu_set_irq(void *opaque, int irq, int level) +{ + Nios2CPU *cpu = opaque; + CPUNios2State *env = &cpu->env; + CPUState *cs = CPU(cpu); + + env->regs[CR_IPENDING] &= ~(1 << irq); + env->regs[CR_IPENDING] |= !!level << irq; + + env->irq_pending = env->regs[CR_IPENDING] & env->regs[CR_IENABLE]; + + if (env->irq_pending && (env->regs[CR_STATUS] & CR_STATUS_PIE)) { + env->irq_pending = 0; + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else if (!env->irq_pending) { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } +} +#endif + static void nios2_cpu_initfn(Object *obj) { Nios2CPU *cpu = NIOS2_CPU(obj); @@ -XXX,XX +XXX,XX @@ static void nios2_cpu_initfn(Object *obj) #if !defined(CONFIG_USER_ONLY) mmu_init(&cpu->env); + + /* + * These interrupt lines model the IIC (internal interrupt + * controller). QEMU does not currently support the EIC + * (external interrupt controller) -- if we did it would be + * a separate device in hw/intc with a custom interface to + * the CPU, and boards using it would not wire up these IRQ lines. + */ + qdev_init_gpio_in_named(DEVICE(cpu), nios2_cpu_set_irq, "IRQ", 32); #endif } diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ M: Marek Vasut <marex@denx.de> S: Maintained F: target/nios2/ F: hw/nios2/ -F: hw/intc/nios2_iic.c F: disas/nios2.c F: default-configs/nios2-softmmu.mak diff --git a/hw/intc/meson.build b/hw/intc/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -XXX,XX +XXX,XX @@ specific_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_plic.c')) specific_ss.add(when: 'CONFIG_IOAPIC', if_true: files('ioapic.c')) specific_ss.add(when: 'CONFIG_LOONGSON_LIOINTC', if_true: files('loongson_liointc.c')) specific_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_gic.c')) -specific_ss.add(when: 'CONFIG_NIOS2', if_true: files('nios2_iic.c')) specific_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_intc.c')) specific_ss.add(when: 'CONFIG_OMPIC', if_true: files('ompic.c')) specific_ss.add(when: 'CONFIG_OPENPIC_KVM', if_true: files('openpic_kvm.c')) -- 2.20.1
The function nios2_check_interrupts)() looks only at CPU-internal state; it belongs in target/nios2, not hw/nios2. Move it into the same file as its only caller, so it can just be local to that file. This removes the only remaining code from cpu_pic.c, so we can delete that file entirely. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Message-id: 20201129174022.26530-3-peter.maydell@linaro.org Reviewed-by: Wentong Wu <wentong.wu@intel.com> Tested-by: Wentong Wu <wentong.wu@intel.com> --- target/nios2/cpu.h | 2 -- hw/nios2/cpu_pic.c | 36 ------------------------------------ target/nios2/op_helper.c | 9 +++++++++ hw/nios2/meson.build | 2 +- 4 files changed, 10 insertions(+), 39 deletions(-) delete mode 100644 hw/nios2/cpu_pic.c diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/nios2/cpu.h +++ b/target/nios2/cpu.h @@ -XXX,XX +XXX,XX @@ void nios2_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr); -void nios2_check_interrupts(CPUNios2State *env); - void do_nios2_semihosting(CPUNios2State *env); #define CPU_RESOLVING_TYPE TYPE_NIOS2_CPU diff --git a/hw/nios2/cpu_pic.c b/hw/nios2/cpu_pic.c deleted file mode 100644 index XXXXXXX..XXXXXXX --- a/hw/nios2/cpu_pic.c +++ /dev/null @@ -XXX,XX +XXX,XX @@ -/* - * Altera Nios2 CPU PIC - * - * Copyright (c) 2016 Marek Vasut <marek.vasut@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * <http://www.gnu.org/licenses/lgpl-2.1.html> - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "hw/irq.h" - -#include "qemu/config-file.h" - -#include "boot.h" - -void nios2_check_interrupts(CPUNios2State *env) -{ - if (env->irq_pending && - (env->regs[CR_STATUS] & CR_STATUS_PIE)) { - env->irq_pending = 0; - cpu_interrupt(env_cpu(env), CPU_INTERRUPT_HARD); - } -} diff --git a/target/nios2/op_helper.c b/target/nios2/op_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/nios2/op_helper.c +++ b/target/nios2/op_helper.c @@ -XXX,XX +XXX,XX @@ void helper_mmu_write(CPUNios2State *env, uint32_t rn, uint32_t v) mmu_write(env, rn, v); } +static void nios2_check_interrupts(CPUNios2State *env) +{ + if (env->irq_pending && + (env->regs[CR_STATUS] & CR_STATUS_PIE)) { + env->irq_pending = 0; + cpu_interrupt(env_cpu(env), CPU_INTERRUPT_HARD); + } +} + void helper_check_interrupts(CPUNios2State *env) { qemu_mutex_lock_iothread(); diff --git a/hw/nios2/meson.build b/hw/nios2/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/nios2/meson.build +++ b/hw/nios2/meson.build @@ -XXX,XX +XXX,XX @@ nios2_ss = ss.source_set() -nios2_ss.add(files('boot.c', 'cpu_pic.c')) +nios2_ss.add(files('boot.c')) nios2_ss.add(when: 'CONFIG_NIOS2_10M50', if_true: files('10m50_devboard.c')) nios2_ss.add(when: 'CONFIG_NIOS2_GENERIC_NOMMU', if_true: files('generic_nommu.c')) -- 2.20.1
In nios2_cpu_set_irq(), use deposit32() rather than raw shift-and-mask operations to set the appropriate bit in the ipending register. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Message-id: 20201129174022.26530-4-peter.maydell@linaro.org --- target/nios2/cpu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/nios2/cpu.c +++ b/target/nios2/cpu.c @@ -XXX,XX +XXX,XX @@ static void nios2_cpu_set_irq(void *opaque, int irq, int level) CPUNios2State *env = &cpu->env; CPUState *cs = CPU(cpu); - env->regs[CR_IPENDING] &= ~(1 << irq); - env->regs[CR_IPENDING] |= !!level << irq; + env->regs[CR_IPENDING] = deposit32(env->regs[CR_IPENDING], irq, 1, !!level); env->irq_pending = env->regs[CR_IPENDING] & env->regs[CR_IENABLE]; -- 2.20.1
In rom_check_and_register_reset() we detect overlaps by looking at whether the ROM blob we're currently examining is in the same address space and starts before the previous ROM blob ends. (This works because the ROM list is kept sorted in order by AddressSpace and then by address.) Instead of keeping the AddressSpace and last address of the previous ROM blob in local variables, just keep a pointer to it. This will allow us to print more useful information when we do detect an overlap. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20201129203923.10622-2-peter.maydell@linaro.org --- hw/core/loader.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/hw/core/loader.c b/hw/core/loader.c index XXXXXXX..XXXXXXX 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -XXX,XX +XXX,XX @@ static void rom_reset(void *unused) } } +/* Return true if two consecutive ROMs in the ROM list overlap */ +static bool roms_overlap(Rom *last_rom, Rom *this_rom) +{ + if (!last_rom) { + return false; + } + return last_rom->as == this_rom->as && + last_rom->addr + last_rom->romsize > this_rom->addr; +} + int rom_check_and_register_reset(void) { - hwaddr addr = 0; MemoryRegionSection section; - Rom *rom; - AddressSpace *as = NULL; + Rom *rom, *last_rom = NULL; QTAILQ_FOREACH(rom, &roms, next) { if (rom->fw_file) { continue; } if (!rom->mr) { - if ((addr > rom->addr) && (as == rom->as)) { + if (roms_overlap(last_rom, rom)) { fprintf(stderr, "rom: requested regions overlap " "(rom %s. free=0x" TARGET_FMT_plx ", addr=0x" TARGET_FMT_plx ")\n", - rom->name, addr, rom->addr); + rom->name, last_rom->addr + last_rom->romsize, + rom->addr); return -1; } - addr = rom->addr; - addr += rom->romsize; - as = rom->as; + last_rom = rom; } section = memory_region_find(rom->mr ? rom->mr : get_system_memory(), rom->addr, 1); -- 2.20.1
In rom_check_and_register_reset() we report to the user if there is a "ROM region overlap". This has a couple of problems: * the reported information is not very easy to intepret * the function just prints the overlap to stderr (and relies on its single callsite in vl.c to do an error_report() and exit) * only the first overlap encountered is diagnosed Make this function use error_report() and error_printf() and report a more user-friendly report with all the overlaps diagnosed. Sample old output: rom: requested regions overlap (rom dtb. free=0x0000000000008000, addr=0x0000000000000000) qemu-system-aarch64: rom check and register reset failed Sample new output: qemu-system-aarch64: Some ROM regions are overlapping These ROM regions might have been loaded by direct user request or by default. They could be BIOS/firmware images, a guest kernel, initrd or some other file loaded into guest memory. Check whether you intended to load all this guest code, and whether it has been built to load to the correct addresses. The following two regions overlap (in the cpu-memory-0 address space): phdr #0: /home/petmay01/linaro/qemu-misc-tests/ldmia-fault.axf (addresses 0x0000000000000000 - 0x0000000000008000) dtb (addresses 0x0000000000000000 - 0x0000000000100000) The following two regions overlap (in the cpu-memory-0 address space): phdr #1: /home/petmay01/linaro/qemu-misc-tests/bad-psci-call.axf (addresses 0x0000000040000000 - 0x0000000040000010) phdr #0: /home/petmay01/linaro/qemu-misc-tests/bp-test.elf (addresses 0x0000000040000000 - 0x0000000040000020) Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20201129203923.10622-3-peter.maydell@linaro.org --- hw/core/loader.c | 48 ++++++++++++++++++++++++++++++++++++++++++------ softmmu/vl.c | 1 - 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/hw/core/loader.c b/hw/core/loader.c index XXXXXXX..XXXXXXX 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -XXX,XX +XXX,XX @@ static bool roms_overlap(Rom *last_rom, Rom *this_rom) last_rom->addr + last_rom->romsize > this_rom->addr; } +static const char *rom_as_name(Rom *rom) +{ + const char *name = rom->as ? rom->as->name : NULL; + return name ?: "anonymous"; +} + +static void rom_print_overlap_error_header(void) +{ + error_report("Some ROM regions are overlapping"); + error_printf( + "These ROM regions might have been loaded by " + "direct user request or by default.\n" + "They could be BIOS/firmware images, a guest kernel, " + "initrd or some other file loaded into guest memory.\n" + "Check whether you intended to load all this guest code, and " + "whether it has been built to load to the correct addresses.\n"); +} + +static void rom_print_one_overlap_error(Rom *last_rom, Rom *rom) +{ + error_printf( + "\nThe following two regions overlap (in the %s address space):\n", + rom_as_name(rom)); + error_printf( + " %s (addresses 0x" TARGET_FMT_plx " - 0x" TARGET_FMT_plx ")\n", + last_rom->name, last_rom->addr, last_rom->addr + last_rom->romsize); + error_printf( + " %s (addresses 0x" TARGET_FMT_plx " - 0x" TARGET_FMT_plx ")\n", + rom->name, rom->addr, rom->addr + rom->romsize); +} + int rom_check_and_register_reset(void) { MemoryRegionSection section; Rom *rom, *last_rom = NULL; + bool found_overlap = false; QTAILQ_FOREACH(rom, &roms, next) { if (rom->fw_file) { @@ -XXX,XX +XXX,XX @@ int rom_check_and_register_reset(void) } if (!rom->mr) { if (roms_overlap(last_rom, rom)) { - fprintf(stderr, "rom: requested regions overlap " - "(rom %s. free=0x" TARGET_FMT_plx - ", addr=0x" TARGET_FMT_plx ")\n", - rom->name, last_rom->addr + last_rom->romsize, - rom->addr); - return -1; + if (!found_overlap) { + found_overlap = true; + rom_print_overlap_error_header(); + } + rom_print_one_overlap_error(last_rom, rom); + /* Keep going through the list so we report all overlaps */ } last_rom = rom; } @@ -XXX,XX +XXX,XX @@ int rom_check_and_register_reset(void) rom->isrom = int128_nz(section.size) && memory_region_is_rom(section.mr); memory_region_unref(section.mr); } + if (found_overlap) { + return -1; + } + qemu_register_reset(rom_reset, NULL); roms_loaded = 1; return 0; diff --git a/softmmu/vl.c b/softmmu/vl.c index XXXXXXX..XXXXXXX 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -XXX,XX +XXX,XX @@ static void qemu_machine_creation_done(void) qemu_run_machine_init_done_notifiers(); if (rom_check_and_register_reset() != 0) { - error_report("rom check and register reset failed"); exit(1); } -- 2.20.1
Currently the load_elf code assembles the ROM blob name into a local 128 byte fixed-size array. Use g_strdup_printf() instead so that we don't truncate the pathname if it happens to be long. (This matters mostly for monitor 'info roms' output and for the error messages if ROM blobs overlap.) Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20201129203923.10622-4-peter.maydell@linaro.org --- include/hw/elf_ops.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/elf_ops.h +++ b/include/hw/elf_ops.h @@ -XXX,XX +XXX,XX @@ static int glue(load_elf, SZ)(const char *name, int fd, uint64_t addr, low = (uint64_t)-1, high = 0; GMappedFile *mapped_file = NULL; uint8_t *data = NULL; - char label[128]; int ret = ELF_LOAD_FAILED; if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) @@ -XXX,XX +XXX,XX @@ static int glue(load_elf, SZ)(const char *name, int fd, */ if (mem_size != 0) { if (load_rom) { - snprintf(label, sizeof(label), "phdr #%d: %s", i, name); + g_autofree char *label = + g_strdup_printf("phdr #%d: %s", i, name); /* * rom_add_elf_program() takes its own reference to -- 2.20.1
Instead of making the ROM blob name something like: phdr #0: /home/petmay01/linaro/qemu-misc-tests/ldmia-fault.axf make it a little more self-explanatory for people who don't know ELF format details: /home/petmay01/linaro/qemu-misc-tests/ldmia-fault.axf ELF program header segment 0 Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20201129203923.10622-5-peter.maydell@linaro.org --- include/hw/elf_ops.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/elf_ops.h +++ b/include/hw/elf_ops.h @@ -XXX,XX +XXX,XX @@ static int glue(load_elf, SZ)(const char *name, int fd, if (mem_size != 0) { if (load_rom) { g_autofree char *label = - g_strdup_printf("phdr #%d: %s", i, name); + g_strdup_printf("%s ELF program header segment %d", + name, i); /* * rom_add_elf_program() takes its own reference to -- 2.20.1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com> This module emulates control registers of versal usb2 controller, this is added just to make guest happy. In general this module would control the phy-reset signal from usb controller, data coherency of the transactions, signals the host system errors received from controller. Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com> Signed-off-by: Vikram Garhwal <fnu.vikram@xilinx.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 1607023357-5096-2-git-send-email-sai.pavan.boddu@xilinx.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- include/hw/usb/xlnx-versal-usb2-ctrl-regs.h | 45 ++++ hw/usb/xlnx-versal-usb2-ctrl-regs.c | 229 ++++++++++++++++++++ hw/usb/meson.build | 1 + 3 files changed, 275 insertions(+) create mode 100644 include/hw/usb/xlnx-versal-usb2-ctrl-regs.h create mode 100644 hw/usb/xlnx-versal-usb2-ctrl-regs.c diff --git a/include/hw/usb/xlnx-versal-usb2-ctrl-regs.h b/include/hw/usb/xlnx-versal-usb2-ctrl-regs.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/usb/xlnx-versal-usb2-ctrl-regs.h @@ -XXX,XX +XXX,XX @@ +/* + * QEMU model of the VersalUsb2CtrlRegs Register control/Status block for + * USB2.0 controller + * + * Copyright (c) 2020 Xilinx Inc. Vikram Garhwal <fnu.vikram@xilinx.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _XLNX_USB2_REGS_H_ +#define _XLNX_USB2_REGS_H_ + +#define TYPE_XILINX_VERSAL_USB2_CTRL_REGS "xlnx.versal-usb2-ctrl-regs" + +#define XILINX_VERSAL_USB2_CTRL_REGS(obj) \ + OBJECT_CHECK(VersalUsb2CtrlRegs, (obj), TYPE_XILINX_VERSAL_USB2_CTRL_REGS) + +#define USB2_REGS_R_MAX ((0x78 / 4) + 1) + +typedef struct VersalUsb2CtrlRegs { + SysBusDevice parent_obj; + MemoryRegion iomem; + qemu_irq irq_ir; + + uint32_t regs[USB2_REGS_R_MAX]; + RegisterInfo regs_info[USB2_REGS_R_MAX]; +} VersalUsb2CtrlRegs; + +#endif diff --git a/hw/usb/xlnx-versal-usb2-ctrl-regs.c b/hw/usb/xlnx-versal-usb2-ctrl-regs.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/usb/xlnx-versal-usb2-ctrl-regs.c @@ -XXX,XX +XXX,XX @@ +/* + * QEMU model of the VersalUsb2CtrlRegs Register control/Status block for + * USB2.0 controller + * + * This module should control phy_reset, permanent device plugs, frame length + * time adjust & setting of coherency paths. None of which are emulated in + * present model. + * + * Copyright (c) 2020 Xilinx Inc. Vikram Garhwal <fnu.vikram@xilinx.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/register.h" +#include "qemu/bitops.h" +#include "qemu/log.h" +#include "qom/object.h" +#include "migration/vmstate.h" +#include "hw/usb/xlnx-versal-usb2-ctrl-regs.h" + +#ifndef XILINX_VERSAL_USB2_CTRL_REGS_ERR_DEBUG +#define XILINX_VERSAL_USB2_CTRL_REGS_ERR_DEBUG 0 +#endif + +REG32(BUS_FILTER, 0x30) + FIELD(BUS_FILTER, BYPASS, 0, 4) +REG32(PORT, 0x34) + FIELD(PORT, HOST_SMI_BAR_WR, 4, 1) + FIELD(PORT, HOST_SMI_PCI_CMD_REG_WR, 3, 1) + FIELD(PORT, HOST_MSI_ENABLE, 2, 1) + FIELD(PORT, PWR_CTRL_PRSNT, 1, 1) + FIELD(PORT, HUB_PERM_ATTACH, 0, 1) +REG32(JITTER_ADJUST, 0x38) + FIELD(JITTER_ADJUST, FLADJ, 0, 6) +REG32(BIGENDIAN, 0x40) + FIELD(BIGENDIAN, ENDIAN_GS, 0, 1) +REG32(COHERENCY, 0x44) + FIELD(COHERENCY, USB_COHERENCY, 0, 1) +REG32(XHC_BME, 0x48) + FIELD(XHC_BME, XHC_BME, 0, 1) +REG32(REG_CTRL, 0x60) + FIELD(REG_CTRL, SLVERR_ENABLE, 0, 1) +REG32(IR_STATUS, 0x64) + FIELD(IR_STATUS, HOST_SYS_ERR, 1, 1) + FIELD(IR_STATUS, ADDR_DEC_ERR, 0, 1) +REG32(IR_MASK, 0x68) + FIELD(IR_MASK, HOST_SYS_ERR, 1, 1) + FIELD(IR_MASK, ADDR_DEC_ERR, 0, 1) +REG32(IR_ENABLE, 0x6c) + FIELD(IR_ENABLE, HOST_SYS_ERR, 1, 1) + FIELD(IR_ENABLE, ADDR_DEC_ERR, 0, 1) +REG32(IR_DISABLE, 0x70) + FIELD(IR_DISABLE, HOST_SYS_ERR, 1, 1) + FIELD(IR_DISABLE, ADDR_DEC_ERR, 0, 1) +REG32(USB3, 0x78) + +static void ir_update_irq(VersalUsb2CtrlRegs *s) +{ + bool pending = s->regs[R_IR_STATUS] & ~s->regs[R_IR_MASK]; + qemu_set_irq(s->irq_ir, pending); +} + +static void ir_status_postw(RegisterInfo *reg, uint64_t val64) +{ + VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(reg->opaque); + /* + * TODO: This should also clear USBSTS.HSE field in USB XHCI register. + * May be combine both the modules. + */ + ir_update_irq(s); +} + +static uint64_t ir_enable_prew(RegisterInfo *reg, uint64_t val64) +{ + VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(reg->opaque); + uint32_t val = val64; + + s->regs[R_IR_MASK] &= ~val; + ir_update_irq(s); + return 0; +} + +static uint64_t ir_disable_prew(RegisterInfo *reg, uint64_t val64) +{ + VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(reg->opaque); + uint32_t val = val64; + + s->regs[R_IR_MASK] |= val; + ir_update_irq(s); + return 0; +} + +static const RegisterAccessInfo usb2_ctrl_regs_regs_info[] = { + { .name = "BUS_FILTER", .addr = A_BUS_FILTER, + .rsvd = 0xfffffff0, + },{ .name = "PORT", .addr = A_PORT, + .rsvd = 0xffffffe0, + },{ .name = "JITTER_ADJUST", .addr = A_JITTER_ADJUST, + .reset = 0x20, + .rsvd = 0xffffffc0, + },{ .name = "BIGENDIAN", .addr = A_BIGENDIAN, + .rsvd = 0xfffffffe, + },{ .name = "COHERENCY", .addr = A_COHERENCY, + .rsvd = 0xfffffffe, + },{ .name = "XHC_BME", .addr = A_XHC_BME, + .reset = 0x1, + .rsvd = 0xfffffffe, + },{ .name = "REG_CTRL", .addr = A_REG_CTRL, + .rsvd = 0xfffffffe, + },{ .name = "IR_STATUS", .addr = A_IR_STATUS, + .rsvd = 0xfffffffc, + .w1c = 0x3, + .post_write = ir_status_postw, + },{ .name = "IR_MASK", .addr = A_IR_MASK, + .reset = 0x3, + .rsvd = 0xfffffffc, + .ro = 0x3, + },{ .name = "IR_ENABLE", .addr = A_IR_ENABLE, + .rsvd = 0xfffffffc, + .pre_write = ir_enable_prew, + },{ .name = "IR_DISABLE", .addr = A_IR_DISABLE, + .rsvd = 0xfffffffc, + .pre_write = ir_disable_prew, + },{ .name = "USB3", .addr = A_USB3, + } +}; + +static void usb2_ctrl_regs_reset_init(Object *obj, ResetType type) +{ + VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(obj); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { + register_reset(&s->regs_info[i]); + } +} + +static void usb2_ctrl_regs_reset_hold(Object *obj) +{ + VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(obj); + + ir_update_irq(s); +} + +static const MemoryRegionOps usb2_ctrl_regs_ops = { + .read = register_read_memory, + .write = register_write_memory, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static void usb2_ctrl_regs_init(Object *obj) +{ + VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + RegisterInfoArray *reg_array; + + memory_region_init(&s->iomem, obj, TYPE_XILINX_VERSAL_USB2_CTRL_REGS, + USB2_REGS_R_MAX * 4); + reg_array = + register_init_block32(DEVICE(obj), usb2_ctrl_regs_regs_info, + ARRAY_SIZE(usb2_ctrl_regs_regs_info), + s->regs_info, s->regs, + &usb2_ctrl_regs_ops, + XILINX_VERSAL_USB2_CTRL_REGS_ERR_DEBUG, + USB2_REGS_R_MAX * 4); + memory_region_add_subregion(&s->iomem, + 0x0, + ®_array->mem); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq_ir); +} + +static const VMStateDescription vmstate_usb2_ctrl_regs = { + .name = TYPE_XILINX_VERSAL_USB2_CTRL_REGS, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, VersalUsb2CtrlRegs, USB2_REGS_R_MAX), + VMSTATE_END_OF_LIST(), + } +}; + +static void usb2_ctrl_regs_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.enter = usb2_ctrl_regs_reset_init; + rc->phases.hold = usb2_ctrl_regs_reset_hold; + dc->vmsd = &vmstate_usb2_ctrl_regs; +} + +static const TypeInfo usb2_ctrl_regs_info = { + .name = TYPE_XILINX_VERSAL_USB2_CTRL_REGS, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(VersalUsb2CtrlRegs), + .class_init = usb2_ctrl_regs_class_init, + .instance_init = usb2_ctrl_regs_init, +}; + +static void usb2_ctrl_regs_register_types(void) +{ + type_register_static(&usb2_ctrl_regs_info); +} + +type_init(usb2_ctrl_regs_register_types) diff --git a/hw/usb/meson.build b/hw/usb/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/usb/meson.build +++ b/hw/usb/meson.build @@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_USB_DWC2', if_true: files('hcd-dwc2.c')) softmmu_ss.add(when: 'CONFIG_TUSB6010', if_true: files('tusb6010.c')) softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('chipidea.c')) softmmu_ss.add(when: 'CONFIG_IMX_USBPHY', if_true: files('imx-usb-phy.c')) +specific_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-usb2-ctrl-regs.c')) # emulated usb devices softmmu_ss.add(when: 'CONFIG_USB', if_true: files('dev-hub.c')) -- 2.20.1
From: Vikram Garhwal <fnu.vikram@xilinx.com> This patch adds skeleton model of dwc3 usb controller attached to xhci-sysbus device. It defines global register space of DWC3 controller, global registers control the AXI/AHB interfaces properties, external FIFO support and event count support. All of which are unimplemented at present,we are only supporting core reset and read of ID register. Signed-off-by: Vikram Garhwal <fnu.vikram@xilinx.com> Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> Message-id: 1607023357-5096-3-git-send-email-sai.pavan.boddu@xilinx.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- include/hw/usb/hcd-dwc3.h | 55 +++ hw/usb/hcd-dwc3.c | 689 ++++++++++++++++++++++++++++++++++++++ hw/usb/Kconfig | 5 + hw/usb/meson.build | 1 + 4 files changed, 750 insertions(+) create mode 100644 include/hw/usb/hcd-dwc3.h create mode 100644 hw/usb/hcd-dwc3.c diff --git a/include/hw/usb/hcd-dwc3.h b/include/hw/usb/hcd-dwc3.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/usb/hcd-dwc3.h @@ -XXX,XX +XXX,XX @@ +/* + * QEMU model of the USB DWC3 host controller emulation. + * + * Copyright (c) 2020 Xilinx Inc. + * + * Written by Vikram Garhwal<fnu.vikram@xilinx.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef HCD_DWC3_H +#define HCD_DWC3_H + +#include "hw/usb/hcd-xhci.h" +#include "hw/usb/hcd-xhci-sysbus.h" + +#define TYPE_USB_DWC3 "usb_dwc3" + +#define USB_DWC3(obj) \ + OBJECT_CHECK(USBDWC3, (obj), TYPE_USB_DWC3) + +#define USB_DWC3_R_MAX ((0x530 / 4) + 1) +#define DWC3_SIZE 0x10000 + +typedef struct USBDWC3 { + SysBusDevice parent_obj; + MemoryRegion iomem; + XHCISysbusState sysbus_xhci; + + uint32_t regs[USB_DWC3_R_MAX]; + RegisterInfo regs_info[USB_DWC3_R_MAX]; + + struct { + uint8_t mode; + uint32_t dwc_usb3_user; + } cfg; + +} USBDWC3; + +#endif diff --git a/hw/usb/hcd-dwc3.c b/hw/usb/hcd-dwc3.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/usb/hcd-dwc3.c @@ -XXX,XX +XXX,XX @@ +/* + * QEMU model of the USB DWC3 host controller emulation. + * + * This model defines global register space of DWC3 controller. Global + * registers control the AXI/AHB interfaces properties, external FIFO support + * and event count support. All of which are unimplemented at present. We are + * only supporting core reset and read of ID register. + * + * Copyright (c) 2020 Xilinx Inc. Vikram Garhwal<fnu.vikram@xilinx.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/register.h" +#include "qemu/bitops.h" +#include "qemu/log.h" +#include "qom/object.h" +#include "migration/vmstate.h" +#include "hw/qdev-properties.h" +#include "hw/usb/hcd-dwc3.h" +#include "qapi/error.h" + +#ifndef USB_DWC3_ERR_DEBUG +#define USB_DWC3_ERR_DEBUG 0 +#endif + +#define HOST_MODE 1 +#define FIFO_LEN 0x1000 + +REG32(GSBUSCFG0, 0x00) + FIELD(GSBUSCFG0, DATRDREQINFO, 28, 4) + FIELD(GSBUSCFG0, DESRDREQINFO, 24, 4) + FIELD(GSBUSCFG0, DATWRREQINFO, 20, 4) + FIELD(GSBUSCFG0, DESWRREQINFO, 16, 4) + FIELD(GSBUSCFG0, RESERVED_15_12, 12, 4) + FIELD(GSBUSCFG0, DATBIGEND, 11, 1) + FIELD(GSBUSCFG0, DESBIGEND, 10, 1) + FIELD(GSBUSCFG0, RESERVED_9_8, 8, 2) + FIELD(GSBUSCFG0, INCR256BRSTENA, 7, 1) + FIELD(GSBUSCFG0, INCR128BRSTENA, 6, 1) + FIELD(GSBUSCFG0, INCR64BRSTENA, 5, 1) + FIELD(GSBUSCFG0, INCR32BRSTENA, 4, 1) + FIELD(GSBUSCFG0, INCR16BRSTENA, 3, 1) + FIELD(GSBUSCFG0, INCR8BRSTENA, 2, 1) + FIELD(GSBUSCFG0, INCR4BRSTENA, 1, 1) + FIELD(GSBUSCFG0, INCRBRSTENA, 0, 1) +REG32(GSBUSCFG1, 0x04) + FIELD(GSBUSCFG1, RESERVED_31_13, 13, 19) + FIELD(GSBUSCFG1, EN1KPAGE, 12, 1) + FIELD(GSBUSCFG1, PIPETRANSLIMIT, 8, 4) + FIELD(GSBUSCFG1, RESERVED_7_0, 0, 8) +REG32(GTXTHRCFG, 0x08) + FIELD(GTXTHRCFG, RESERVED_31, 31, 1) + FIELD(GTXTHRCFG, RESERVED_30, 30, 1) + FIELD(GTXTHRCFG, USBTXPKTCNTSEL, 29, 1) + FIELD(GTXTHRCFG, RESERVED_28, 28, 1) + FIELD(GTXTHRCFG, USBTXPKTCNT, 24, 4) + FIELD(GTXTHRCFG, USBMAXTXBURSTSIZE, 16, 8) + FIELD(GTXTHRCFG, RESERVED_15, 15, 1) + FIELD(GTXTHRCFG, RESERVED_14, 14, 1) + FIELD(GTXTHRCFG, RESERVED_13_11, 11, 3) + FIELD(GTXTHRCFG, RESERVED_10_0, 0, 11) +REG32(GRXTHRCFG, 0x0c) + FIELD(GRXTHRCFG, RESERVED_31_30, 30, 2) + FIELD(GRXTHRCFG, USBRXPKTCNTSEL, 29, 1) + FIELD(GRXTHRCFG, RESERVED_28, 28, 1) + FIELD(GRXTHRCFG, USBRXPKTCNT, 24, 4) + FIELD(GRXTHRCFG, USBMAXRXBURSTSIZE, 19, 5) + FIELD(GRXTHRCFG, RESERVED_18_16, 16, 3) + FIELD(GRXTHRCFG, RESERVED_15, 15, 1) + FIELD(GRXTHRCFG, RESERVED_14_13, 13, 2) + FIELD(GRXTHRCFG, RESVISOCOUTSPC, 0, 13) +REG32(GCTL, 0x10) + FIELD(GCTL, PWRDNSCALE, 19, 13) + FIELD(GCTL, MASTERFILTBYPASS, 18, 1) + FIELD(GCTL, BYPSSETADDR, 17, 1) + FIELD(GCTL, U2RSTECN, 16, 1) + FIELD(GCTL, FRMSCLDWN, 14, 2) + FIELD(GCTL, PRTCAPDIR, 12, 2) + FIELD(GCTL, CORESOFTRESET, 11, 1) + FIELD(GCTL, U1U2TIMERSCALE, 9, 1) + FIELD(GCTL, DEBUGATTACH, 8, 1) + FIELD(GCTL, RAMCLKSEL, 6, 2) + FIELD(GCTL, SCALEDOWN, 4, 2) + FIELD(GCTL, DISSCRAMBLE, 3, 1) + FIELD(GCTL, U2EXIT_LFPS, 2, 1) + FIELD(GCTL, GBLHIBERNATIONEN, 1, 1) + FIELD(GCTL, DSBLCLKGTNG, 0, 1) +REG32(GPMSTS, 0x14) +REG32(GSTS, 0x18) + FIELD(GSTS, CBELT, 20, 12) + FIELD(GSTS, RESERVED_19_12, 12, 8) + FIELD(GSTS, SSIC_IP, 11, 1) + FIELD(GSTS, OTG_IP, 10, 1) + FIELD(GSTS, BC_IP, 9, 1) + FIELD(GSTS, ADP_IP, 8, 1) + FIELD(GSTS, HOST_IP, 7, 1) + FIELD(GSTS, DEVICE_IP, 6, 1) + FIELD(GSTS, CSRTIMEOUT, 5, 1) + FIELD(GSTS, BUSERRADDRVLD, 4, 1) + FIELD(GSTS, RESERVED_3_2, 2, 2) + FIELD(GSTS, CURMOD, 0, 2) +REG32(GUCTL1, 0x1c) + FIELD(GUCTL1, RESUME_OPMODE_HS_HOST, 10, 1) +REG32(GSNPSID, 0x20) +REG32(GGPIO, 0x24) + FIELD(GGPIO, GPO, 16, 16) + FIELD(GGPIO, GPI, 0, 16) +REG32(GUID, 0x28) +REG32(GUCTL, 0x2c) + FIELD(GUCTL, REFCLKPER, 22, 10) + FIELD(GUCTL, NOEXTRDL, 21, 1) + FIELD(GUCTL, RESERVED_20_18, 18, 3) + FIELD(GUCTL, SPRSCTRLTRANSEN, 17, 1) + FIELD(GUCTL, RESBWHSEPS, 16, 1) + FIELD(GUCTL, RESERVED_15, 15, 1) + FIELD(GUCTL, USBHSTINAUTORETRYEN, 14, 1) + FIELD(GUCTL, ENOVERLAPCHK, 13, 1) + FIELD(GUCTL, EXTCAPSUPPTEN, 12, 1) + FIELD(GUCTL, INSRTEXTRFSBODI, 11, 1) + FIELD(GUCTL, DTCT, 9, 2) + FIELD(GUCTL, DTFT, 0, 9) +REG32(GBUSERRADDRLO, 0x30) +REG32(GBUSERRADDRHI, 0x34) +REG32(GHWPARAMS0, 0x40) + FIELD(GHWPARAMS0, GHWPARAMS0_31_24, 24, 8) + FIELD(GHWPARAMS0, GHWPARAMS0_23_16, 16, 8) + FIELD(GHWPARAMS0, GHWPARAMS0_15_8, 8, 8) + FIELD(GHWPARAMS0, GHWPARAMS0_7_6, 6, 2) + FIELD(GHWPARAMS0, GHWPARAMS0_5_3, 3, 3) + FIELD(GHWPARAMS0, GHWPARAMS0_2_0, 0, 3) +REG32(GHWPARAMS1, 0x44) + FIELD(GHWPARAMS1, GHWPARAMS1_31, 31, 1) + FIELD(GHWPARAMS1, GHWPARAMS1_30, 30, 1) + FIELD(GHWPARAMS1, GHWPARAMS1_29, 29, 1) + FIELD(GHWPARAMS1, GHWPARAMS1_28, 28, 1) + FIELD(GHWPARAMS1, GHWPARAMS1_27, 27, 1) + FIELD(GHWPARAMS1, GHWPARAMS1_26, 26, 1) + FIELD(GHWPARAMS1, GHWPARAMS1_25_24, 24, 2) + FIELD(GHWPARAMS1, GHWPARAMS1_23, 23, 1) + FIELD(GHWPARAMS1, GHWPARAMS1_22_21, 21, 2) + FIELD(GHWPARAMS1, GHWPARAMS1_20_15, 15, 6) + FIELD(GHWPARAMS1, GHWPARAMS1_14_12, 12, 3) + FIELD(GHWPARAMS1, GHWPARAMS1_11_9, 9, 3) + FIELD(GHWPARAMS1, GHWPARAMS1_8_6, 6, 3) + FIELD(GHWPARAMS1, GHWPARAMS1_5_3, 3, 3) + FIELD(GHWPARAMS1, GHWPARAMS1_2_0, 0, 3) +REG32(GHWPARAMS2, 0x48) +REG32(GHWPARAMS3, 0x4c) + FIELD(GHWPARAMS3, GHWPARAMS3_31, 31, 1) + FIELD(GHWPARAMS3, GHWPARAMS3_30_23, 23, 8) + FIELD(GHWPARAMS3, GHWPARAMS3_22_18, 18, 5) + FIELD(GHWPARAMS3, GHWPARAMS3_17_12, 12, 6) + FIELD(GHWPARAMS3, GHWPARAMS3_11, 11, 1) + FIELD(GHWPARAMS3, GHWPARAMS3_10, 10, 1) + FIELD(GHWPARAMS3, GHWPARAMS3_9_8, 8, 2) + FIELD(GHWPARAMS3, GHWPARAMS3_7_6, 6, 2) + FIELD(GHWPARAMS3, GHWPARAMS3_5_4, 4, 2) + FIELD(GHWPARAMS3, GHWPARAMS3_3_2, 2, 2) + FIELD(GHWPARAMS3, GHWPARAMS3_1_0, 0, 2) +REG32(GHWPARAMS4, 0x50) + FIELD(GHWPARAMS4, GHWPARAMS4_31_28, 28, 4) + FIELD(GHWPARAMS4, GHWPARAMS4_27_24, 24, 4) + FIELD(GHWPARAMS4, GHWPARAMS4_23, 23, 1) + FIELD(GHWPARAMS4, GHWPARAMS4_22, 22, 1) + FIELD(GHWPARAMS4, GHWPARAMS4_21, 21, 1) + FIELD(GHWPARAMS4, GHWPARAMS4_20_17, 17, 4) + FIELD(GHWPARAMS4, GHWPARAMS4_16_13, 13, 4) + FIELD(GHWPARAMS4, GHWPARAMS4_12, 12, 1) + FIELD(GHWPARAMS4, GHWPARAMS4_11, 11, 1) + FIELD(GHWPARAMS4, GHWPARAMS4_10_9, 9, 2) + FIELD(GHWPARAMS4, GHWPARAMS4_8_7, 7, 2) + FIELD(GHWPARAMS4, GHWPARAMS4_6, 6, 1) + FIELD(GHWPARAMS4, GHWPARAMS4_5_0, 0, 6) +REG32(GHWPARAMS5, 0x54) + FIELD(GHWPARAMS5, GHWPARAMS5_31_28, 28, 4) + FIELD(GHWPARAMS5, GHWPARAMS5_27_22, 22, 6) + FIELD(GHWPARAMS5, GHWPARAMS5_21_16, 16, 6) + FIELD(GHWPARAMS5, GHWPARAMS5_15_10, 10, 6) + FIELD(GHWPARAMS5, GHWPARAMS5_9_4, 4, 6) + FIELD(GHWPARAMS5, GHWPARAMS5_3_0, 0, 4) +REG32(GHWPARAMS6, 0x58) + FIELD(GHWPARAMS6, GHWPARAMS6_31_16, 16, 16) + FIELD(GHWPARAMS6, BUSFLTRSSUPPORT, 15, 1) + FIELD(GHWPARAMS6, BCSUPPORT, 14, 1) + FIELD(GHWPARAMS6, OTG_SS_SUPPORT, 13, 1) + FIELD(GHWPARAMS6, ADPSUPPORT, 12, 1) + FIELD(GHWPARAMS6, HNPSUPPORT, 11, 1) + FIELD(GHWPARAMS6, SRPSUPPORT, 10, 1) + FIELD(GHWPARAMS6, GHWPARAMS6_9_8, 8, 2) + FIELD(GHWPARAMS6, GHWPARAMS6_7, 7, 1) + FIELD(GHWPARAMS6, GHWPARAMS6_6, 6, 1) + FIELD(GHWPARAMS6, GHWPARAMS6_5_0, 0, 6) +REG32(GHWPARAMS7, 0x5c) + FIELD(GHWPARAMS7, GHWPARAMS7_31_16, 16, 16) + FIELD(GHWPARAMS7, GHWPARAMS7_15_0, 0, 16) +REG32(GDBGFIFOSPACE, 0x60) + FIELD(GDBGFIFOSPACE, SPACE_AVAILABLE, 16, 16) + FIELD(GDBGFIFOSPACE, RESERVED_15_9, 9, 7) + FIELD(GDBGFIFOSPACE, FIFO_QUEUE_SELECT, 0, 9) +REG32(GUCTL2, 0x9c) + FIELD(GUCTL2, RESERVED_31_26, 26, 6) + FIELD(GUCTL2, EN_HP_PM_TIMER, 19, 7) + FIELD(GUCTL2, NOLOWPWRDUR, 15, 4) + FIELD(GUCTL2, RST_ACTBITLATER, 14, 1) + FIELD(GUCTL2, RESERVED_13, 13, 1) + FIELD(GUCTL2, DISABLECFC, 11, 1) +REG32(GUSB2PHYCFG, 0x100) + FIELD(GUSB2PHYCFG, U2_FREECLK_EXISTS, 30, 1) + FIELD(GUSB2PHYCFG, ULPI_LPM_WITH_OPMODE_CHK, 29, 1) + FIELD(GUSB2PHYCFG, RESERVED_25, 25, 1) + FIELD(GUSB2PHYCFG, LSTRD, 22, 3) + FIELD(GUSB2PHYCFG, LSIPD, 19, 3) + FIELD(GUSB2PHYCFG, ULPIEXTVBUSINDIACTOR, 18, 1) + FIELD(GUSB2PHYCFG, ULPIEXTVBUSDRV, 17, 1) + FIELD(GUSB2PHYCFG, RESERVED_16, 16, 1) + FIELD(GUSB2PHYCFG, ULPIAUTORES, 15, 1) + FIELD(GUSB2PHYCFG, RESERVED_14, 14, 1) + FIELD(GUSB2PHYCFG, USBTRDTIM, 10, 4) + FIELD(GUSB2PHYCFG, XCVRDLY, 9, 1) + FIELD(GUSB2PHYCFG, ENBLSLPM, 8, 1) + FIELD(GUSB2PHYCFG, PHYSEL, 7, 1) + FIELD(GUSB2PHYCFG, SUSPENDUSB20, 6, 1) + FIELD(GUSB2PHYCFG, FSINTF, 5, 1) + FIELD(GUSB2PHYCFG, ULPI_UTMI_SEL, 4, 1) + FIELD(GUSB2PHYCFG, PHYIF, 3, 1) + FIELD(GUSB2PHYCFG, TOUTCAL, 0, 3) +REG32(GUSB2I2CCTL, 0x140) +REG32(GUSB2PHYACC_ULPI, 0x180) + FIELD(GUSB2PHYACC_ULPI, RESERVED_31_27, 27, 5) + FIELD(GUSB2PHYACC_ULPI, DISUIPIDRVR, 26, 1) + FIELD(GUSB2PHYACC_ULPI, NEWREGREQ, 25, 1) + FIELD(GUSB2PHYACC_ULPI, VSTSDONE, 24, 1) + FIELD(GUSB2PHYACC_ULPI, VSTSBSY, 23, 1) + FIELD(GUSB2PHYACC_ULPI, REGWR, 22, 1) + FIELD(GUSB2PHYACC_ULPI, REGADDR, 16, 6) + FIELD(GUSB2PHYACC_ULPI, EXTREGADDR, 8, 8) + FIELD(GUSB2PHYACC_ULPI, REGDATA, 0, 8) +REG32(GTXFIFOSIZ0, 0x200) + FIELD(GTXFIFOSIZ0, TXFSTADDR_N, 16, 16) + FIELD(GTXFIFOSIZ0, TXFDEP_N, 0, 16) +REG32(GTXFIFOSIZ1, 0x204) + FIELD(GTXFIFOSIZ1, TXFSTADDR_N, 16, 16) + FIELD(GTXFIFOSIZ1, TXFDEP_N, 0, 16) +REG32(GTXFIFOSIZ2, 0x208) + FIELD(GTXFIFOSIZ2, TXFSTADDR_N, 16, 16) + FIELD(GTXFIFOSIZ2, TXFDEP_N, 0, 16) +REG32(GTXFIFOSIZ3, 0x20c) + FIELD(GTXFIFOSIZ3, TXFSTADDR_N, 16, 16) + FIELD(GTXFIFOSIZ3, TXFDEP_N, 0, 16) +REG32(GTXFIFOSIZ4, 0x210) + FIELD(GTXFIFOSIZ4, TXFSTADDR_N, 16, 16) + FIELD(GTXFIFOSIZ4, TXFDEP_N, 0, 16) +REG32(GTXFIFOSIZ5, 0x214) + FIELD(GTXFIFOSIZ5, TXFSTADDR_N, 16, 16) + FIELD(GTXFIFOSIZ5, TXFDEP_N, 0, 16) +REG32(GRXFIFOSIZ0, 0x280) + FIELD(GRXFIFOSIZ0, RXFSTADDR_N, 16, 16) + FIELD(GRXFIFOSIZ0, RXFDEP_N, 0, 16) +REG32(GRXFIFOSIZ1, 0x284) + FIELD(GRXFIFOSIZ1, RXFSTADDR_N, 16, 16) + FIELD(GRXFIFOSIZ1, RXFDEP_N, 0, 16) +REG32(GRXFIFOSIZ2, 0x288) + FIELD(GRXFIFOSIZ2, RXFSTADDR_N, 16, 16) + FIELD(GRXFIFOSIZ2, RXFDEP_N, 0, 16) +REG32(GEVNTADRLO_0, 0x300) +REG32(GEVNTADRHI_0, 0x304) +REG32(GEVNTSIZ_0, 0x308) + FIELD(GEVNTSIZ_0, EVNTINTRPTMASK, 31, 1) + FIELD(GEVNTSIZ_0, RESERVED_30_16, 16, 15) + FIELD(GEVNTSIZ_0, EVENTSIZ, 0, 16) +REG32(GEVNTCOUNT_0, 0x30c) + FIELD(GEVNTCOUNT_0, EVNT_HANDLER_BUSY, 31, 1) + FIELD(GEVNTCOUNT_0, RESERVED_30_16, 16, 15) + FIELD(GEVNTCOUNT_0, EVNTCOUNT, 0, 16) +REG32(GEVNTADRLO_1, 0x310) +REG32(GEVNTADRHI_1, 0x314) +REG32(GEVNTSIZ_1, 0x318) + FIELD(GEVNTSIZ_1, EVNTINTRPTMASK, 31, 1) + FIELD(GEVNTSIZ_1, RESERVED_30_16, 16, 15) + FIELD(GEVNTSIZ_1, EVENTSIZ, 0, 16) +REG32(GEVNTCOUNT_1, 0x31c) + FIELD(GEVNTCOUNT_1, EVNT_HANDLER_BUSY, 31, 1) + FIELD(GEVNTCOUNT_1, RESERVED_30_16, 16, 15) + FIELD(GEVNTCOUNT_1, EVNTCOUNT, 0, 16) +REG32(GEVNTADRLO_2, 0x320) +REG32(GEVNTADRHI_2, 0x324) +REG32(GEVNTSIZ_2, 0x328) + FIELD(GEVNTSIZ_2, EVNTINTRPTMASK, 31, 1) + FIELD(GEVNTSIZ_2, RESERVED_30_16, 16, 15) + FIELD(GEVNTSIZ_2, EVENTSIZ, 0, 16) +REG32(GEVNTCOUNT_2, 0x32c) + FIELD(GEVNTCOUNT_2, EVNT_HANDLER_BUSY, 31, 1) + FIELD(GEVNTCOUNT_2, RESERVED_30_16, 16, 15) + FIELD(GEVNTCOUNT_2, EVNTCOUNT, 0, 16) +REG32(GEVNTADRLO_3, 0x330) +REG32(GEVNTADRHI_3, 0x334) +REG32(GEVNTSIZ_3, 0x338) + FIELD(GEVNTSIZ_3, EVNTINTRPTMASK, 31, 1) + FIELD(GEVNTSIZ_3, RESERVED_30_16, 16, 15) + FIELD(GEVNTSIZ_3, EVENTSIZ, 0, 16) +REG32(GEVNTCOUNT_3, 0x33c) + FIELD(GEVNTCOUNT_3, EVNT_HANDLER_BUSY, 31, 1) + FIELD(GEVNTCOUNT_3, RESERVED_30_16, 16, 15) + FIELD(GEVNTCOUNT_3, EVNTCOUNT, 0, 16) +REG32(GHWPARAMS8, 0x500) +REG32(GTXFIFOPRIDEV, 0x510) + FIELD(GTXFIFOPRIDEV, RESERVED_31_N, 6, 26) + FIELD(GTXFIFOPRIDEV, GTXFIFOPRIDEV, 0, 6) +REG32(GTXFIFOPRIHST, 0x518) + FIELD(GTXFIFOPRIHST, RESERVED_31_16, 3, 29) + FIELD(GTXFIFOPRIHST, GTXFIFOPRIHST, 0, 3) +REG32(GRXFIFOPRIHST, 0x51c) + FIELD(GRXFIFOPRIHST, RESERVED_31_16, 3, 29) + FIELD(GRXFIFOPRIHST, GRXFIFOPRIHST, 0, 3) +REG32(GDMAHLRATIO, 0x524) + FIELD(GDMAHLRATIO, RESERVED_31_13, 13, 19) + FIELD(GDMAHLRATIO, HSTRXFIFO, 8, 5) + FIELD(GDMAHLRATIO, RESERVED_7_5, 5, 3) + FIELD(GDMAHLRATIO, HSTTXFIFO, 0, 5) +REG32(GFLADJ, 0x530) + FIELD(GFLADJ, GFLADJ_REFCLK_240MHZDECR_PLS1, 31, 1) + FIELD(GFLADJ, GFLADJ_REFCLK_240MHZ_DECR, 24, 7) + FIELD(GFLADJ, GFLADJ_REFCLK_LPM_SEL, 23, 1) + FIELD(GFLADJ, RESERVED_22, 22, 1) + FIELD(GFLADJ, GFLADJ_REFCLK_FLADJ, 8, 14) + FIELD(GFLADJ, GFLADJ_30MHZ_SDBND_SEL, 7, 1) + FIELD(GFLADJ, GFLADJ_30MHZ, 0, 6) + +#define DWC3_GLOBAL_OFFSET 0xC100 +static void reset_csr(USBDWC3 * s) +{ + int i = 0; + /* + * We reset all CSR regs except GCTL, GUCTL, GSTS, GSNPSID, GGPIO, GUID, + * GUSB2PHYCFGn registers and GUSB3PIPECTLn registers. We will skip PHY + * register as we don't implement them. + */ + for (i = 0; i < USB_DWC3_R_MAX; i++) { + switch (i) { + case R_GCTL: + break; + case R_GSTS: + break; + case R_GSNPSID: + break; + case R_GGPIO: + break; + case R_GUID: + break; + case R_GUCTL: + break; + case R_GHWPARAMS0...R_GHWPARAMS7: + break; + case R_GHWPARAMS8: + break; + default: + register_reset(&s->regs_info[i]); + break; + } + } + + xhci_sysbus_reset(DEVICE(&s->sysbus_xhci)); +} + +static void usb_dwc3_gctl_postw(RegisterInfo *reg, uint64_t val64) +{ + USBDWC3 *s = USB_DWC3(reg->opaque); + + if (ARRAY_FIELD_EX32(s->regs, GCTL, CORESOFTRESET)) { + reset_csr(s); + } +} + +static void usb_dwc3_guid_postw(RegisterInfo *reg, uint64_t val64) +{ + USBDWC3 *s = USB_DWC3(reg->opaque); + + s->regs[R_GUID] = s->cfg.dwc_usb3_user; +} + +static const RegisterAccessInfo usb_dwc3_regs_info[] = { + { .name = "GSBUSCFG0", .addr = A_GSBUSCFG0, + .ro = 0xf300, + .unimp = 0xffffffff, + },{ .name = "GSBUSCFG1", .addr = A_GSBUSCFG1, + .reset = 0x300, + .ro = 0xffffe0ff, + .unimp = 0xffffffff, + },{ .name = "GTXTHRCFG", .addr = A_GTXTHRCFG, + .ro = 0xd000ffff, + .unimp = 0xffffffff, + },{ .name = "GRXTHRCFG", .addr = A_GRXTHRCFG, + .ro = 0xd007e000, + .unimp = 0xffffffff, + },{ .name = "GCTL", .addr = A_GCTL, + .reset = 0x30c13004, .post_write = usb_dwc3_gctl_postw, + },{ .name = "GPMSTS", .addr = A_GPMSTS, + .ro = 0xfffffff, + .unimp = 0xffffffff, + },{ .name = "GSTS", .addr = A_GSTS, + .reset = 0x7e800000, + .ro = 0xffffffcf, + .w1c = 0x30, + .unimp = 0xffffffff, + },{ .name = "GUCTL1", .addr = A_GUCTL1, + .reset = 0x198a, + .ro = 0x7800, + .unimp = 0xffffffff, + },{ .name = "GSNPSID", .addr = A_GSNPSID, + .reset = 0x5533330a, + .ro = 0xffffffff, + },{ .name = "GGPIO", .addr = A_GGPIO, + .ro = 0xffff, + .unimp = 0xffffffff, + },{ .name = "GUID", .addr = A_GUID, + .reset = 0x12345678, .post_write = usb_dwc3_guid_postw, + },{ .name = "GUCTL", .addr = A_GUCTL, + .reset = 0x0c808010, + .ro = 0x1c8000, + .unimp = 0xffffffff, + },{ .name = "GBUSERRADDRLO", .addr = A_GBUSERRADDRLO, + .ro = 0xffffffff, + },{ .name = "GBUSERRADDRHI", .addr = A_GBUSERRADDRHI, + .ro = 0xffffffff, + },{ .name = "GHWPARAMS0", .addr = A_GHWPARAMS0, + .ro = 0xffffffff, + },{ .name = "GHWPARAMS1", .addr = A_GHWPARAMS1, + .ro = 0xffffffff, + },{ .name = "GHWPARAMS2", .addr = A_GHWPARAMS2, + .ro = 0xffffffff, + },{ .name = "GHWPARAMS3", .addr = A_GHWPARAMS3, + .ro = 0xffffffff, + },{ .name = "GHWPARAMS4", .addr = A_GHWPARAMS4, + .ro = 0xffffffff, + },{ .name = "GHWPARAMS5", .addr = A_GHWPARAMS5, + .ro = 0xffffffff, + },{ .name = "GHWPARAMS6", .addr = A_GHWPARAMS6, + .ro = 0xffffffff, + },{ .name = "GHWPARAMS7", .addr = A_GHWPARAMS7, + .ro = 0xffffffff, + },{ .name = "GDBGFIFOSPACE", .addr = A_GDBGFIFOSPACE, + .reset = 0xa0000, + .ro = 0xfffffe00, + .unimp = 0xffffffff, + },{ .name = "GUCTL2", .addr = A_GUCTL2, + .reset = 0x40d, + .ro = 0x2000, + .unimp = 0xffffffff, + },{ .name = "GUSB2PHYCFG", .addr = A_GUSB2PHYCFG, + .reset = 0x40102410, + .ro = 0x1e014030, + .unimp = 0xffffffff, + },{ .name = "GUSB2I2CCTL", .addr = A_GUSB2I2CCTL, + .ro = 0xffffffff, + .unimp = 0xffffffff, + },{ .name = "GUSB2PHYACC_ULPI", .addr = A_GUSB2PHYACC_ULPI, + .ro = 0xfd000000, + .unimp = 0xffffffff, + },{ .name = "GTXFIFOSIZ0", .addr = A_GTXFIFOSIZ0, + .reset = 0x2c7000a, + .unimp = 0xffffffff, + },{ .name = "GTXFIFOSIZ1", .addr = A_GTXFIFOSIZ1, + .reset = 0x2d10103, + .unimp = 0xffffffff, + },{ .name = "GTXFIFOSIZ2", .addr = A_GTXFIFOSIZ2, + .reset = 0x3d40103, + .unimp = 0xffffffff, + },{ .name = "GTXFIFOSIZ3", .addr = A_GTXFIFOSIZ3, + .reset = 0x4d70083, + .unimp = 0xffffffff, + },{ .name = "GTXFIFOSIZ4", .addr = A_GTXFIFOSIZ4, + .reset = 0x55a0083, + .unimp = 0xffffffff, + },{ .name = "GTXFIFOSIZ5", .addr = A_GTXFIFOSIZ5, + .reset = 0x5dd0083, + .unimp = 0xffffffff, + },{ .name = "GRXFIFOSIZ0", .addr = A_GRXFIFOSIZ0, + .reset = 0x1c20105, + .unimp = 0xffffffff, + },{ .name = "GRXFIFOSIZ1", .addr = A_GRXFIFOSIZ1, + .reset = 0x2c70000, + .unimp = 0xffffffff, + },{ .name = "GRXFIFOSIZ2", .addr = A_GRXFIFOSIZ2, + .reset = 0x2c70000, + .unimp = 0xffffffff, + },{ .name = "GEVNTADRLO_0", .addr = A_GEVNTADRLO_0, + .unimp = 0xffffffff, + },{ .name = "GEVNTADRHI_0", .addr = A_GEVNTADRHI_0, + .unimp = 0xffffffff, + },{ .name = "GEVNTSIZ_0", .addr = A_GEVNTSIZ_0, + .ro = 0x7fff0000, + .unimp = 0xffffffff, + },{ .name = "GEVNTCOUNT_0", .addr = A_GEVNTCOUNT_0, + .ro = 0x7fff0000, + .unimp = 0xffffffff, + },{ .name = "GEVNTADRLO_1", .addr = A_GEVNTADRLO_1, + .unimp = 0xffffffff, + },{ .name = "GEVNTADRHI_1", .addr = A_GEVNTADRHI_1, + .unimp = 0xffffffff, + },{ .name = "GEVNTSIZ_1", .addr = A_GEVNTSIZ_1, + .ro = 0x7fff0000, + .unimp = 0xffffffff, + },{ .name = "GEVNTCOUNT_1", .addr = A_GEVNTCOUNT_1, + .ro = 0x7fff0000, + .unimp = 0xffffffff, + },{ .name = "GEVNTADRLO_2", .addr = A_GEVNTADRLO_2, + .unimp = 0xffffffff, + },{ .name = "GEVNTADRHI_2", .addr = A_GEVNTADRHI_2, + .unimp = 0xffffffff, + },{ .name = "GEVNTSIZ_2", .addr = A_GEVNTSIZ_2, + .ro = 0x7fff0000, + .unimp = 0xffffffff, + },{ .name = "GEVNTCOUNT_2", .addr = A_GEVNTCOUNT_2, + .ro = 0x7fff0000, + .unimp = 0xffffffff, + },{ .name = "GEVNTADRLO_3", .addr = A_GEVNTADRLO_3, + .unimp = 0xffffffff, + },{ .name = "GEVNTADRHI_3", .addr = A_GEVNTADRHI_3, + .unimp = 0xffffffff, + },{ .name = "GEVNTSIZ_3", .addr = A_GEVNTSIZ_3, + .ro = 0x7fff0000, + .unimp = 0xffffffff, + },{ .name = "GEVNTCOUNT_3", .addr = A_GEVNTCOUNT_3, + .ro = 0x7fff0000, + .unimp = 0xffffffff, + },{ .name = "GHWPARAMS8", .addr = A_GHWPARAMS8, + .ro = 0xffffffff, + },{ .name = "GTXFIFOPRIDEV", .addr = A_GTXFIFOPRIDEV, + .ro = 0xffffffc0, + .unimp = 0xffffffff, + },{ .name = "GTXFIFOPRIHST", .addr = A_GTXFIFOPRIHST, + .ro = 0xfffffff8, + .unimp = 0xffffffff, + },{ .name = "GRXFIFOPRIHST", .addr = A_GRXFIFOPRIHST, + .ro = 0xfffffff8, + .unimp = 0xffffffff, + },{ .name = "GDMAHLRATIO", .addr = A_GDMAHLRATIO, + .ro = 0xffffe0e0, + .unimp = 0xffffffff, + },{ .name = "GFLADJ", .addr = A_GFLADJ, + .reset = 0xc83f020, + .rsvd = 0x40, + .ro = 0x400040, + .unimp = 0xffffffff, + } +}; + +static void usb_dwc3_reset(DeviceState *dev) +{ + USBDWC3 *s = USB_DWC3(dev); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { + switch (i) { + case R_GHWPARAMS0...R_GHWPARAMS7: + break; + case R_GHWPARAMS8: + break; + default: + register_reset(&s->regs_info[i]); + }; + } + + xhci_sysbus_reset(DEVICE(&s->sysbus_xhci)); +} + +static const MemoryRegionOps usb_dwc3_ops = { + .read = register_read_memory, + .write = register_write_memory, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static void usb_dwc3_realize(DeviceState *dev, Error **errp) +{ + USBDWC3 *s = USB_DWC3(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + Error *err = NULL; + + sysbus_realize(SYS_BUS_DEVICE(&s->sysbus_xhci), &err); + if (err) { + error_propagate(errp, err); + return; + } + + memory_region_add_subregion(&s->iomem, 0, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->sysbus_xhci), 0)); + sysbus_init_mmio(sbd, &s->iomem); + + /* + * Device Configuration + */ + s->regs[R_GHWPARAMS0] = 0x40204048 | s->cfg.mode; + s->regs[R_GHWPARAMS1] = 0x222493b; + s->regs[R_GHWPARAMS2] = 0x12345678; + s->regs[R_GHWPARAMS3] = 0x618c088; + s->regs[R_GHWPARAMS4] = 0x47822004; + s->regs[R_GHWPARAMS5] = 0x4202088; + s->regs[R_GHWPARAMS6] = 0x7850c20; + s->regs[R_GHWPARAMS7] = 0x0; + s->regs[R_GHWPARAMS8] = 0x478; +} + +static void usb_dwc3_init(Object *obj) +{ + USBDWC3 *s = USB_DWC3(obj); + RegisterInfoArray *reg_array; + + memory_region_init(&s->iomem, obj, TYPE_USB_DWC3, DWC3_SIZE); + reg_array = + register_init_block32(DEVICE(obj), usb_dwc3_regs_info, + ARRAY_SIZE(usb_dwc3_regs_info), + s->regs_info, s->regs, + &usb_dwc3_ops, + USB_DWC3_ERR_DEBUG, + USB_DWC3_R_MAX * 4); + memory_region_add_subregion(&s->iomem, + DWC3_GLOBAL_OFFSET, + ®_array->mem); + object_initialize_child(obj, "dwc3-xhci", &s->sysbus_xhci, + TYPE_XHCI_SYSBUS); + qdev_alias_all_properties(DEVICE(&s->sysbus_xhci), obj); + + s->cfg.mode = HOST_MODE; +} + +static const VMStateDescription vmstate_usb_dwc3 = { + .name = "usb-dwc3", + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, USBDWC3, USB_DWC3_R_MAX), + VMSTATE_UINT8(cfg.mode, USBDWC3), + VMSTATE_UINT32(cfg.dwc_usb3_user, USBDWC3), + VMSTATE_END_OF_LIST() + } +}; + +static Property usb_dwc3_properties[] = { + DEFINE_PROP_UINT32("DWC_USB3_USERID", USBDWC3, cfg.dwc_usb3_user, + 0x12345678), + DEFINE_PROP_END_OF_LIST(), +}; + +static void usb_dwc3_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = usb_dwc3_reset; + dc->realize = usb_dwc3_realize; + dc->vmsd = &vmstate_usb_dwc3; + device_class_set_props(dc, usb_dwc3_properties); +} + +static const TypeInfo usb_dwc3_info = { + .name = TYPE_USB_DWC3, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(USBDWC3), + .class_init = usb_dwc3_class_init, + .instance_init = usb_dwc3_init, +}; + +static void usb_dwc3_register_types(void) +{ + type_register_static(&usb_dwc3_info); +} + +type_init(usb_dwc3_register_types) diff --git a/hw/usb/Kconfig b/hw/usb/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/usb/Kconfig +++ b/hw/usb/Kconfig @@ -XXX,XX +XXX,XX @@ config IMX_USBPHY bool default y depends on USB + +config USB_DWC3 + bool + select USB_XHCI_SYSBUS + select REGISTER diff --git a/hw/usb/meson.build b/hw/usb/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/usb/meson.build +++ b/hw/usb/meson.build @@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_USB_XHCI_SYSBUS', if_true: files('hcd-xhci-sysbus.c softmmu_ss.add(when: 'CONFIG_USB_XHCI_NEC', if_true: files('hcd-xhci-nec.c')) softmmu_ss.add(when: 'CONFIG_USB_MUSB', if_true: files('hcd-musb.c')) softmmu_ss.add(when: 'CONFIG_USB_DWC2', if_true: files('hcd-dwc2.c')) +softmmu_ss.add(when: 'CONFIG_USB_DWC3', if_true: files('hcd-dwc3.c')) softmmu_ss.add(when: 'CONFIG_TUSB6010', if_true: files('tusb6010.c')) softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('chipidea.c')) -- 2.20.1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com> This model is a top level integration wrapper for hcd-dwc3 and versal-usb2-ctrl-regs modules, this is used by xilinx versal soc's and future xilinx usb subsystems would also be part of it. Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 1607023357-5096-4-git-send-email-sai.pavan.boddu@xilinx.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- include/hw/usb/xlnx-usb-subsystem.h | 45 ++++++++++++++ hw/usb/xlnx-usb-subsystem.c | 94 +++++++++++++++++++++++++++++ hw/usb/Kconfig | 5 ++ hw/usb/meson.build | 1 + 4 files changed, 145 insertions(+) create mode 100644 include/hw/usb/xlnx-usb-subsystem.h create mode 100644 hw/usb/xlnx-usb-subsystem.c diff --git a/include/hw/usb/xlnx-usb-subsystem.h b/include/hw/usb/xlnx-usb-subsystem.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/usb/xlnx-usb-subsystem.h @@ -XXX,XX +XXX,XX @@ +/* + * QEMU model of the Xilinx usb subsystem + * + * Copyright (c) 2020 Xilinx Inc. Sai Pavan Boddu <sai.pavan.boddu@xilinx.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _XLNX_VERSAL_USB_SUBSYSTEM_H_ +#define _XLNX_VERSAL_USB_SUBSYSTEM_H_ + +#include "hw/usb/xlnx-versal-usb2-ctrl-regs.h" +#include "hw/usb/hcd-dwc3.h" + +#define TYPE_XILINX_VERSAL_USB2 "xlnx.versal-usb2" + +#define VERSAL_USB2(obj) \ + OBJECT_CHECK(VersalUsb2, (obj), TYPE_XILINX_VERSAL_USB2) + +typedef struct VersalUsb2 { + SysBusDevice parent_obj; + MemoryRegion dwc3_mr; + MemoryRegion usb2Ctrl_mr; + + VersalUsb2CtrlRegs usb2Ctrl; + USBDWC3 dwc3; +} VersalUsb2; + +#endif diff --git a/hw/usb/xlnx-usb-subsystem.c b/hw/usb/xlnx-usb-subsystem.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/usb/xlnx-usb-subsystem.c @@ -XXX,XX +XXX,XX @@ +/* + * QEMU model of the Xilinx usb subsystem + * + * Copyright (c) 2020 Xilinx Inc. Sai Pavan Boddu <sai.pava.boddu@xilinx.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/register.h" +#include "qemu/bitops.h" +#include "qemu/log.h" +#include "qom/object.h" +#include "qapi/error.h" +#include "hw/qdev-properties.h" +#include "hw/usb/xlnx-usb-subsystem.h" + +static void versal_usb2_realize(DeviceState *dev, Error **errp) +{ + VersalUsb2 *s = VERSAL_USB2(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + Error *err = NULL; + + sysbus_realize(SYS_BUS_DEVICE(&s->dwc3), &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_realize(SYS_BUS_DEVICE(&s->usb2Ctrl), &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_init_mmio(sbd, &s->dwc3_mr); + sysbus_init_mmio(sbd, &s->usb2Ctrl_mr); + qdev_pass_gpios(DEVICE(&s->dwc3.sysbus_xhci), dev, SYSBUS_DEVICE_GPIO_IRQ); +} + +static void versal_usb2_init(Object *obj) +{ + VersalUsb2 *s = VERSAL_USB2(obj); + + object_initialize_child(obj, "versal.dwc3", &s->dwc3, + TYPE_USB_DWC3); + object_initialize_child(obj, "versal.usb2-ctrl", &s->usb2Ctrl, + TYPE_XILINX_VERSAL_USB2_CTRL_REGS); + memory_region_init_alias(&s->dwc3_mr, obj, "versal.dwc3_alias", + &s->dwc3.iomem, 0, DWC3_SIZE); + memory_region_init_alias(&s->usb2Ctrl_mr, obj, "versal.usb2Ctrl_alias", + &s->usb2Ctrl.iomem, 0, USB2_REGS_R_MAX * 4); + qdev_alias_all_properties(DEVICE(&s->dwc3), obj); + qdev_alias_all_properties(DEVICE(&s->dwc3.sysbus_xhci), obj); + object_property_add_alias(obj, "dma", OBJECT(&s->dwc3.sysbus_xhci), "dma"); +} + +static void versal_usb2_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = versal_usb2_realize; +} + +static const TypeInfo versal_usb2_info = { + .name = TYPE_XILINX_VERSAL_USB2, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(VersalUsb2), + .class_init = versal_usb2_class_init, + .instance_init = versal_usb2_init, +}; + +static void versal_usb_types(void) +{ + type_register_static(&versal_usb2_info); +} + +type_init(versal_usb_types) diff --git a/hw/usb/Kconfig b/hw/usb/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/usb/Kconfig +++ b/hw/usb/Kconfig @@ -XXX,XX +XXX,XX @@ config USB_DWC3 bool select USB_XHCI_SYSBUS select REGISTER + +config XLNX_USB_SUBSYS + bool + default y if XLNX_VERSAL + select USB_DWC3 diff --git a/hw/usb/meson.build b/hw/usb/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/usb/meson.build +++ b/hw/usb/meson.build @@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_TUSB6010', if_true: files('tusb6010.c')) softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('chipidea.c')) softmmu_ss.add(when: 'CONFIG_IMX_USBPHY', if_true: files('imx-usb-phy.c')) specific_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-usb2-ctrl-regs.c')) +specific_ss.add(when: 'CONFIG_XLNX_USB_SUBSYS', if_true: files('xlnx-usb-subsystem.c')) # emulated usb devices softmmu_ss.add(when: 'CONFIG_USB', if_true: files('dev-hub.c')) -- 2.20.1
From: Vikram Garhwal <fnu.vikram@xilinx.com> Connect VersalUsb2 subsystem to xlnx-versal SOC, its placed in iou of lpd domain and configure it as dual port host controller. Add the respective guest dts nodes for "xlnx-versal-virt" machine. Signed-off-by: Vikram Garhwal <fnu.vikram@xilinx.com> Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> Message-id: 1607023357-5096-5-git-send-email-sai.pavan.boddu@xilinx.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- include/hw/arm/xlnx-versal.h | 9 ++++++ hw/arm/xlnx-versal-virt.c | 55 ++++++++++++++++++++++++++++++++++++ hw/arm/xlnx-versal.c | 26 +++++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/xlnx-versal.h +++ b/include/hw/arm/xlnx-versal.h @@ -XXX,XX +XXX,XX @@ #include "hw/net/cadence_gem.h" #include "hw/rtc/xlnx-zynqmp-rtc.h" #include "qom/object.h" +#include "hw/usb/xlnx-usb-subsystem.h" #define TYPE_XLNX_VERSAL "xlnx-versal" OBJECT_DECLARE_SIMPLE_TYPE(Versal, XLNX_VERSAL) @@ -XXX,XX +XXX,XX @@ struct Versal { PL011State uart[XLNX_VERSAL_NR_UARTS]; CadenceGEMState gem[XLNX_VERSAL_NR_GEMS]; XlnxZDMA adma[XLNX_VERSAL_NR_ADMAS]; + VersalUsb2 usb; } iou; } lpd; @@ -XXX,XX +XXX,XX @@ struct Versal { #define VERSAL_UART0_IRQ_0 18 #define VERSAL_UART1_IRQ_0 19 +#define VERSAL_USB0_IRQ_0 22 #define VERSAL_GEM0_IRQ_0 56 #define VERSAL_GEM0_WAKE_IRQ_0 57 #define VERSAL_GEM1_IRQ_0 58 @@ -XXX,XX +XXX,XX @@ struct Versal { #define MM_OCM 0xfffc0000U #define MM_OCM_SIZE 0x40000 +#define MM_USB2_CTRL_REGS 0xFF9D0000 +#define MM_USB2_CTRL_REGS_SIZE 0x10000 + +#define MM_USB_0 0xFE200000 +#define MM_USB_0_SIZE 0x10000 + #define MM_TOP_DDR 0x0 #define MM_TOP_DDR_SIZE 0x80000000U #define MM_TOP_DDR_2 0x800000000ULL diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -XXX,XX +XXX,XX @@ struct VersalVirt { uint32_t ethernet_phy[2]; uint32_t clk_125Mhz; uint32_t clk_25Mhz; + uint32_t usb; + uint32_t dwc; } phandle; struct arm_boot_info binfo; @@ -XXX,XX +XXX,XX @@ static void fdt_create(VersalVirt *s) s->phandle.clk_25Mhz = qemu_fdt_alloc_phandle(s->fdt); s->phandle.clk_125Mhz = qemu_fdt_alloc_phandle(s->fdt); + s->phandle.usb = qemu_fdt_alloc_phandle(s->fdt); + s->phandle.dwc = qemu_fdt_alloc_phandle(s->fdt); /* Create /chosen node for load_dtb. */ qemu_fdt_add_subnode(s->fdt, "/chosen"); @@ -XXX,XX +XXX,XX @@ static void fdt_add_timer_nodes(VersalVirt *s) compat, sizeof(compat)); } +static void fdt_add_usb_xhci_nodes(VersalVirt *s) +{ + const char clocknames[] = "bus_clk\0ref_clk"; + const char irq_name[] = "dwc_usb3"; + const char compatVersalDWC3[] = "xlnx,versal-dwc3"; + const char compatDWC3[] = "snps,dwc3"; + char *name = g_strdup_printf("/usb@%" PRIx32, MM_USB2_CTRL_REGS); + + qemu_fdt_add_subnode(s->fdt, name); + qemu_fdt_setprop(s->fdt, name, "compatible", + compatVersalDWC3, sizeof(compatVersalDWC3)); + qemu_fdt_setprop_sized_cells(s->fdt, name, "reg", + 2, MM_USB2_CTRL_REGS, + 2, MM_USB2_CTRL_REGS_SIZE); + qemu_fdt_setprop(s->fdt, name, "clock-names", + clocknames, sizeof(clocknames)); + qemu_fdt_setprop_cells(s->fdt, name, "clocks", + s->phandle.clk_25Mhz, s->phandle.clk_125Mhz); + qemu_fdt_setprop(s->fdt, name, "ranges", NULL, 0); + qemu_fdt_setprop_cell(s->fdt, name, "#address-cells", 2); + qemu_fdt_setprop_cell(s->fdt, name, "#size-cells", 2); + qemu_fdt_setprop_cell(s->fdt, name, "phandle", s->phandle.usb); + g_free(name); + + name = g_strdup_printf("/usb@%" PRIx32 "/dwc3@%" PRIx32, + MM_USB2_CTRL_REGS, MM_USB_0); + qemu_fdt_add_subnode(s->fdt, name); + qemu_fdt_setprop(s->fdt, name, "compatible", + compatDWC3, sizeof(compatDWC3)); + qemu_fdt_setprop_sized_cells(s->fdt, name, "reg", + 2, MM_USB_0, 2, MM_USB_0_SIZE); + qemu_fdt_setprop(s->fdt, name, "interrupt-names", + irq_name, sizeof(irq_name)); + qemu_fdt_setprop_cells(s->fdt, name, "interrupts", + GIC_FDT_IRQ_TYPE_SPI, VERSAL_USB0_IRQ_0, + GIC_FDT_IRQ_FLAGS_LEVEL_HI); + qemu_fdt_setprop_cell(s->fdt, name, + "snps,quirk-frame-length-adjustment", 0x20); + qemu_fdt_setprop_cells(s->fdt, name, "#stream-id-cells", 1); + qemu_fdt_setprop_string(s->fdt, name, "dr_mode", "host"); + qemu_fdt_setprop_string(s->fdt, name, "phy-names", "usb3-phy"); + qemu_fdt_setprop(s->fdt, name, "snps,dis_u2_susphy_quirk", NULL, 0); + qemu_fdt_setprop(s->fdt, name, "snps,dis_u3_susphy_quirk", NULL, 0); + qemu_fdt_setprop(s->fdt, name, "snps,refclk_fladj", NULL, 0); + qemu_fdt_setprop(s->fdt, name, "snps,mask_phy_reset", NULL, 0); + qemu_fdt_setprop_cell(s->fdt, name, "phandle", s->phandle.dwc); + qemu_fdt_setprop_string(s->fdt, name, "maximum-speed", "high-speed"); + g_free(name); +} + static void fdt_add_uart_nodes(VersalVirt *s) { uint64_t addrs[] = { MM_UART1, MM_UART0 }; @@ -XXX,XX +XXX,XX @@ static void versal_virt_init(MachineState *machine) fdt_add_gic_nodes(s); fdt_add_timer_nodes(s); fdt_add_zdma_nodes(s); + fdt_add_usb_xhci_nodes(s); fdt_add_sd_nodes(s); fdt_add_rtc_node(s); fdt_add_cpu_nodes(s, psci_conduit); diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -XXX,XX +XXX,XX @@ static void versal_create_uarts(Versal *s, qemu_irq *pic) } } +static void versal_create_usbs(Versal *s, qemu_irq *pic) +{ + DeviceState *dev; + MemoryRegion *mr; + + object_initialize_child(OBJECT(s), "usb2", &s->lpd.iou.usb, + TYPE_XILINX_VERSAL_USB2); + dev = DEVICE(&s->lpd.iou.usb); + + object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps), + &error_abort); + qdev_prop_set_uint32(dev, "intrs", 1); + qdev_prop_set_uint32(dev, "slots", 2); + + sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); + + mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); + memory_region_add_subregion(&s->mr_ps, MM_USB_0, mr); + + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[VERSAL_USB0_IRQ_0]); + + mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); + memory_region_add_subregion(&s->mr_ps, MM_USB2_CTRL_REGS, mr); +} + static void versal_create_gems(Versal *s, qemu_irq *pic) { int i; @@ -XXX,XX +XXX,XX @@ static void versal_realize(DeviceState *dev, Error **errp) versal_create_apu_cpus(s); versal_create_apu_gic(s, pic); versal_create_uarts(s, pic); + versal_create_usbs(s, pic); versal_create_gems(s, pic); versal_create_admas(s, pic); versal_create_sds(s, pic); -- 2.20.1
From: Philippe Mathieu-Daudé <f4bug@amsat.org> Malicious user can set the feedback divisor for the PLLs to zero, triggering a floating-point exception (SIGFPE). As the datasheet [*] is not clear how hardware behaves when these bits are zeroes, use the maximum divisor possible (128) to avoid the software FPE. [*] Zynq-7000 TRM, UG585 (v1.12.2) B.28 System Level Control Registers (slcr) -> "Register (slcr) ARM_PLL_CTRL" 25.10.4 PLLs -> "Software-Controlled PLL Update" Fixes: 38867cb7ec9 ("hw/misc/zynq_slcr: add clock generation for uarts") Reported-by: Gaoning Pan <pgn@zju.edu.cn> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> Reviewed-by: Damien Hedde <damien.hedde@greensocs.com> Message-id: 20201210141610.884600-1-f4bug@amsat.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/misc/zynq_slcr.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/zynq_slcr.c +++ b/hw/misc/zynq_slcr.c @@ -XXX,XX +XXX,XX @@ static uint64_t zynq_slcr_compute_pll(uint64_t input, uint32_t ctrl_reg) return 0; } + /* Consider zero feedback as maximum divide ratio possible */ + if (!mult) { + mult = 1 << R_xxx_PLL_CTRL_PLL_FPDIV_LENGTH; + } + /* frequency multiplier -> period division */ return input / mult; } -- 2.20.1
From: Joe Komlodi <joe.komlodi@xilinx.com> The previous naming of the configuration registers made it sound like that if the bits were set the settings would be enabled, while the opposite is true. Signed-off-by: Joe Komlodi <komlodi@xilinx.com> Reviewed-by: Francisco Iglesias <francisco.iglesias@xilinx.com> Message-id: 1605568264-26376-2-git-send-email-komlodi@xilinx.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/block/m25p80.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index XXXXXXX..XXXXXXX 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -XXX,XX +XXX,XX @@ typedef struct FlashPartInfo { #define VCFG_WRAP_SEQUENTIAL 0x2 #define NVCFG_XIP_MODE_DISABLED (7 << 9) #define NVCFG_XIP_MODE_MASK (7 << 9) -#define VCFG_XIP_MODE_ENABLED (1 << 3) +#define VCFG_XIP_MODE_DISABLED (1 << 3) #define CFG_DUMMY_CLK_LEN 4 #define NVCFG_DUMMY_CLK_POS 12 #define VCFG_DUMMY_CLK_POS 4 @@ -XXX,XX +XXX,XX @@ typedef struct FlashPartInfo { #define EVCFG_VPP_ACCELERATOR (1 << 3) #define EVCFG_RESET_HOLD_ENABLED (1 << 4) #define NVCFG_DUAL_IO_MASK (1 << 2) -#define EVCFG_DUAL_IO_ENABLED (1 << 6) +#define EVCFG_DUAL_IO_DISABLED (1 << 6) #define NVCFG_QUAD_IO_MASK (1 << 3) -#define EVCFG_QUAD_IO_ENABLED (1 << 7) +#define EVCFG_QUAD_IO_DISABLED (1 << 7) #define NVCFG_4BYTE_ADDR_MASK (1 << 0) #define NVCFG_LOWER_SEGMENT_MASK (1 << 1) @@ -XXX,XX +XXX,XX @@ static void reset_memory(Flash *s) s->volatile_cfg |= VCFG_WRAP_SEQUENTIAL; if ((s->nonvolatile_cfg & NVCFG_XIP_MODE_MASK) != NVCFG_XIP_MODE_DISABLED) { - s->volatile_cfg |= VCFG_XIP_MODE_ENABLED; + s->volatile_cfg |= VCFG_XIP_MODE_DISABLED; } s->volatile_cfg |= deposit32(s->volatile_cfg, VCFG_DUMMY_CLK_POS, @@ -XXX,XX +XXX,XX @@ static void reset_memory(Flash *s) s->enh_volatile_cfg |= EVCFG_VPP_ACCELERATOR; s->enh_volatile_cfg |= EVCFG_RESET_HOLD_ENABLED; if (s->nonvolatile_cfg & NVCFG_DUAL_IO_MASK) { - s->enh_volatile_cfg |= EVCFG_DUAL_IO_ENABLED; + s->enh_volatile_cfg |= EVCFG_DUAL_IO_DISABLED; } if (s->nonvolatile_cfg & NVCFG_QUAD_IO_MASK) { - s->enh_volatile_cfg |= EVCFG_QUAD_IO_ENABLED; + s->enh_volatile_cfg |= EVCFG_QUAD_IO_DISABLED; } if (!(s->nonvolatile_cfg & NVCFG_4BYTE_ADDR_MASK)) { s->four_bytes_address_mode = true; -- 2.20.1
From: Joe Komlodi <joe.komlodi@xilinx.com> VCFG XIP is set (disabled) when the NVCFG XIP bits are all set (disabled). Signed-off-by: Joe Komlodi <komlodi@xilinx.com> Reviewed-by: Francisco Iglesias <francisco.iglesias@xilinx.com> Message-id: 1605568264-26376-3-git-send-email-komlodi@xilinx.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/block/m25p80.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index XXXXXXX..XXXXXXX 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -XXX,XX +XXX,XX @@ static void reset_memory(Flash *s) s->volatile_cfg |= VCFG_DUMMY; s->volatile_cfg |= VCFG_WRAP_SEQUENTIAL; if ((s->nonvolatile_cfg & NVCFG_XIP_MODE_MASK) - != NVCFG_XIP_MODE_DISABLED) { + == NVCFG_XIP_MODE_DISABLED) { s->volatile_cfg |= VCFG_XIP_MODE_DISABLED; } s->volatile_cfg |= deposit32(s->volatile_cfg, -- 2.20.1
From: Joe Komlodi <joe.komlodi@xilinx.com> Some Numonyx flash commands cannot be executed in DIO and QIO mode, such as trying to do DPP or DOR when in QIO mode. Signed-off-by: Joe Komlodi <komlodi@xilinx.com> Reviewed-by: Francisco Iglesias <francisco.iglesias@xilinx.com> Message-id: 1605568264-26376-4-git-send-email-komlodi@xilinx.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/block/m25p80.c | 114 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 19 deletions(-) diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index XXXXXXX..XXXXXXX 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -XXX,XX +XXX,XX @@ typedef enum { MAN_GENERIC, } Manufacturer; +typedef enum { + MODE_STD = 0, + MODE_DIO = 1, + MODE_QIO = 2 +} SPIMode; + #define M25P80_INTERNAL_DATA_BUFFER_SZ 16 struct Flash { @@ -XXX,XX +XXX,XX @@ static void reset_memory(Flash *s) trace_m25p80_reset_done(s); } +static uint8_t numonyx_mode(Flash *s) +{ + if (!(s->enh_volatile_cfg & EVCFG_QUAD_IO_DISABLED)) { + return MODE_QIO; + } else if (!(s->enh_volatile_cfg & EVCFG_DUAL_IO_DISABLED)) { + return MODE_DIO; + } else { + return MODE_STD; + } +} + static void decode_fast_read_cmd(Flash *s) { s->needed_bytes = get_addr_length(s); @@ -XXX,XX +XXX,XX @@ static void decode_new_cmd(Flash *s, uint32_t value) case ERASE4_32K: case ERASE_SECTOR: case ERASE4_SECTOR: - case READ: - case READ4: - case DPP: - case QPP: - case QPP_4: case PP: case PP4: - case PP4_4: case DIE_ERASE: case RDID_90: case RDID_AB: @@ -XXX,XX +XXX,XX @@ static void decode_new_cmd(Flash *s, uint32_t value) s->len = 0; s->state = STATE_COLLECTING_DATA; break; + case READ: + case READ4: + if (get_man(s) != MAN_NUMONYX || numonyx_mode(s) == MODE_STD) { + s->needed_bytes = get_addr_length(s); + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; + } else { + qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Cannot execute cmd %x in " + "DIO or QIO mode\n", s->cmd_in_progress); + } + break; + case DPP: + if (get_man(s) != MAN_NUMONYX || numonyx_mode(s) != MODE_QIO) { + s->needed_bytes = get_addr_length(s); + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; + } else { + qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Cannot execute cmd %x in " + "QIO mode\n", s->cmd_in_progress); + } + break; + case QPP: + case QPP_4: + case PP4_4: + if (get_man(s) != MAN_NUMONYX || numonyx_mode(s) != MODE_DIO) { + s->needed_bytes = get_addr_length(s); + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; + } else { + qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Cannot execute cmd %x in " + "DIO mode\n", s->cmd_in_progress); + } + break; case FAST_READ: case FAST_READ4: + decode_fast_read_cmd(s); + break; case DOR: case DOR4: + if (get_man(s) != MAN_NUMONYX || numonyx_mode(s) != MODE_QIO) { + decode_fast_read_cmd(s); + } else { + qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Cannot execute cmd %x in " + "QIO mode\n", s->cmd_in_progress); + } + break; case QOR: case QOR4: - decode_fast_read_cmd(s); + if (get_man(s) != MAN_NUMONYX || numonyx_mode(s) != MODE_DIO) { + decode_fast_read_cmd(s); + } else { + qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Cannot execute cmd %x in " + "DIO mode\n", s->cmd_in_progress); + } break; case DIOR: case DIOR4: - decode_dio_read_cmd(s); + if (get_man(s) != MAN_NUMONYX || numonyx_mode(s) != MODE_QIO) { + decode_dio_read_cmd(s); + } else { + qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Cannot execute cmd %x in " + "QIO mode\n", s->cmd_in_progress); + } break; case QIOR: case QIOR4: - decode_qio_read_cmd(s); + if (get_man(s) != MAN_NUMONYX || numonyx_mode(s) != MODE_DIO) { + decode_qio_read_cmd(s); + } else { + qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Cannot execute cmd %x in " + "DIO mode\n", s->cmd_in_progress); + } break; case WRSR: @@ -XXX,XX +XXX,XX @@ static void decode_new_cmd(Flash *s, uint32_t value) break; case JEDEC_READ: - trace_m25p80_populated_jedec(s); - for (i = 0; i < s->pi->id_len; i++) { - s->data[i] = s->pi->id[i]; - } - for (; i < SPI_NOR_MAX_ID_LEN; i++) { - s->data[i] = 0; - } + if (get_man(s) != MAN_NUMONYX || numonyx_mode(s) == MODE_STD) { + trace_m25p80_populated_jedec(s); + for (i = 0; i < s->pi->id_len; i++) { + s->data[i] = s->pi->id[i]; + } + for (; i < SPI_NOR_MAX_ID_LEN; i++) { + s->data[i] = 0; + } - s->len = SPI_NOR_MAX_ID_LEN; - s->pos = 0; - s->state = STATE_READING_DATA; + s->len = SPI_NOR_MAX_ID_LEN; + s->pos = 0; + s->state = STATE_READING_DATA; + } else { + qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Cannot execute JEDEC read " + "in DIO or QIO mode\n"); + } break; case RDCR: -- 2.20.1
From: Joe Komlodi <joe.komlodi@xilinx.com> Numonyx chips determine the number of cycles to wait based on bits 7:4 in the volatile configuration register. However, if these bits are 0x0 or 0xF, the number of dummy cycles to wait is 10 for QIOR and QIOR4 commands or when in QIO mode, and otherwise 8 for the currently supported fast read commands. [1] [1] https://www.micron.com/-/media/client/global/documents/products/data-sheet/nor-flash/serial-nor/mt25q/die-rev-b/mt25q_qlkt_u_02g_cbb_0.pdf?rev=9b167fbf2b3645efba6385949a72e453 Signed-off-by: Joe Komlodi <komlodi@xilinx.com> Reviewed-by: Francisco Iglesias <francisco.iglesias@xilinx.com> Message-id: 1605568264-26376-5-git-send-email-komlodi@xilinx.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/block/m25p80.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index XXXXXXX..XXXXXXX 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -XXX,XX +XXX,XX @@ static uint8_t numonyx_mode(Flash *s) } } +static uint8_t numonyx_extract_cfg_num_dummies(Flash *s) +{ + uint8_t num_dummies; + uint8_t mode; + assert(get_man(s) == MAN_NUMONYX); + + mode = numonyx_mode(s); + num_dummies = extract32(s->volatile_cfg, 4, 4); + + if (num_dummies == 0x0 || num_dummies == 0xf) { + switch (s->cmd_in_progress) { + case QIOR: + case QIOR4: + num_dummies = 10; + break; + default: + num_dummies = (mode == MODE_QIO) ? 10 : 8; + break; + } + } + + return num_dummies; +} + static void decode_fast_read_cmd(Flash *s) { s->needed_bytes = get_addr_length(s); @@ -XXX,XX +XXX,XX @@ static void decode_fast_read_cmd(Flash *s) s->needed_bytes += 8; break; case MAN_NUMONYX: - s->needed_bytes += extract32(s->volatile_cfg, 4, 4); + s->needed_bytes += numonyx_extract_cfg_num_dummies(s); break; case MAN_MACRONIX: if (extract32(s->volatile_cfg, 6, 2) == 1) { @@ -XXX,XX +XXX,XX @@ static void decode_dio_read_cmd(Flash *s) ); break; case MAN_NUMONYX: - s->needed_bytes += extract32(s->volatile_cfg, 4, 4); + s->needed_bytes += numonyx_extract_cfg_num_dummies(s); break; case MAN_MACRONIX: switch (extract32(s->volatile_cfg, 6, 2)) { @@ -XXX,XX +XXX,XX @@ static void decode_qio_read_cmd(Flash *s) ); break; case MAN_NUMONYX: - s->needed_bytes += extract32(s->volatile_cfg, 4, 4); + s->needed_bytes += numonyx_extract_cfg_num_dummies(s); break; case MAN_MACRONIX: switch (extract32(s->volatile_cfg, 6, 2)) { -- 2.20.1
v3->v4: Windows headers define an INT type which clashed with an enum value name in arm_gicv3_its.c... The following changes since commit eae587e8e3694b1aceab23239493fb4c7e1a80f5: Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2021-09-13' into staging (2021-09-13 11:00:30 +0100) are available in the Git repository at: https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20210913-3 for you to fetch changes up to 28e987a7e7edaa3ca7feeac65edca26145df8814: hw/arm/mps2.c: Mark internal-only I2C buses as 'full' (2021-09-13 21:01:08 +0100) ---------------------------------------------------------------- target-arm queue: * mark MPS2/MPS3 board-internal i2c buses as 'full' so that command line user-created devices are not plugged into them * Take an exception if PSTATE.IL is set * Support an emulated ITS in the virt board * Add support for kudo-bmc board * Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM * cadence_uart: Fix clock handling issues that prevented u-boot from running ---------------------------------------------------------------- Bin Meng (6): hw/misc: zynq_slcr: Correctly compute output clocks in the reset exit phase hw/char: cadence_uart: Disable transmit when input clock is disabled hw/char: cadence_uart: Move clock/reset check to uart_can_receive() hw/char: cadence_uart: Convert to memop_with_attrs() ops hw/char: cadence_uart: Ignore access when unclocked or in reset for uart_{read, write}() hw/char: cadence_uart: Log a guest error when device is unclocked or in reset Chris Rauer (1): hw/arm: Add support for kudo-bmc board. Marc Zyngier (1): hw/arm/virt: KVM: Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM Peter Maydell (5): target/arm: Take an exception if PSTATE.IL is set qdev: Support marking individual buses as 'full' hw/arm/mps2-tz.c: Add extra data parameter to MakeDevFn hw/arm/mps2-tz.c: Mark internal-only I2C buses as 'full' hw/arm/mps2.c: Mark internal-only I2C buses as 'full' Richard Henderson (1): target/arm: Merge disas_a64_insn into aarch64_tr_translate_insn Shashi Mallela (9): hw/intc: GICv3 ITS initial framework hw/intc: GICv3 ITS register definitions added hw/intc: GICv3 ITS command queue framework hw/intc: GICv3 ITS Command processing hw/intc: GICv3 ITS Feature enablement hw/intc: GICv3 redistributor ITS processing tests/data/acpi/virt: Add IORT files for ITS hw/arm/virt: add ITS support in virt GIC tests/data/acpi/virt: Update IORT files for ITS docs/system/arm/nuvoton.rst | 1 + hw/intc/gicv3_internal.h | 188 ++++- include/hw/arm/virt.h | 2 + include/hw/intc/arm_gicv3_common.h | 13 + include/hw/intc/arm_gicv3_its_common.h | 32 +- include/hw/qdev-core.h | 24 + target/arm/cpu.h | 1 + target/arm/kvm_arm.h | 4 +- target/arm/syndrome.h | 5 + target/arm/translate.h | 2 + hw/arm/mps2-tz.c | 92 ++- hw/arm/mps2.c | 12 +- hw/arm/npcm7xx_boards.c | 34 + hw/arm/virt.c | 29 +- hw/char/cadence_uart.c | 61 +- hw/intc/arm_gicv3.c | 14 + hw/intc/arm_gicv3_common.c | 13 + hw/intc/arm_gicv3_cpuif.c | 7 +- hw/intc/arm_gicv3_dist.c | 5 +- hw/intc/arm_gicv3_its.c | 1322 ++++++++++++++++++++++++++++++++ hw/intc/arm_gicv3_its_common.c | 7 +- hw/intc/arm_gicv3_its_kvm.c | 2 +- hw/intc/arm_gicv3_redist.c | 153 +++- hw/misc/zynq_slcr.c | 31 +- softmmu/qdev-monitor.c | 7 +- target/arm/helper-a64.c | 1 + target/arm/helper.c | 8 + target/arm/kvm.c | 7 +- target/arm/translate-a64.c | 255 +++--- target/arm/translate.c | 21 + hw/intc/meson.build | 1 + tests/data/acpi/virt/IORT | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.memhp | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.numamem | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.pxb | Bin 0 -> 124 bytes 35 files changed, 2144 insertions(+), 210 deletions(-) create mode 100644 hw/intc/arm_gicv3_its.c create mode 100644 tests/data/acpi/virt/IORT create mode 100644 tests/data/acpi/virt/IORT.memhp create mode 100644 tests/data/acpi/virt/IORT.numamem create mode 100644 tests/data/acpi/virt/IORT.pxb