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 -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAl/YwVIZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3lOpD/9FjasMvZqYeanyNlv+4Swk 4MFeYouIzXKSFu9tj5eDTHzN1TJl5iSwhkIcr9NBqxppuv2eqzxfWWMEfCZ06pxz BR2HoSlSLUih8cKpu40cQg0TTMEOGEOV9RAHtt8vSGE0FesoiXG2ORUPcxm3NxbN l9XZ1x3Yb5ZLqVZViFjlZ5gXnTzJ//uPEzbl7N9+pa0mXDKvmvwAl19DLmF6N2Jj D+gmrLGeEbkJ358RGO/VF7r/1bOkrhwKrb8MzeqFRmjIqaOGbGqs/71+amiSjS8n hC1HKf6KQOLrklMVaYg1pRxHLbHpQR+haeeX4Xt9jxx8EUrwXojlyaD8p4V9Hcu8 L5haTIBhPrnTkUfHZYL0qYkqRpzbNq97oX2Gmk967FfsZME5fxNa3kS6zM0GkIBx YKghaZtFInAFODUbG1hHdUc+WbvfQDhj/mBQ6wWw669vYpoab/3nfVq8YVoupVM/ RntcqpBfqtGgPzuJ2dJEEsm6QlK4SZaGlmPkz542OzcHxw3SgeqkbIuDW/CtNI+b c5PgX0C2S2AnFAAHURnsXdqt6+O01FZqOU7SCLjmwrBrpDG69lum+JLCqXFe9iMW XgrTrxyPIcz5+Bv63AqKcm6rpcQs5ekwmLLEjT0OJtr+5ef9MeRil0aChj1j4i+2 H/82yKR4JWW1egEvTJhskQ== =lHZA -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20201215' into staging 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 # gpg: Signature made Tue 15 Dec 2020 13:59:46 GMT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20201215: hw/block/m25p80: Fix Numonyx fast read dummy cycle count hw/block/m25p80: Check SPI mode before running some Numonyx commands hw/block/m25p80: Fix when VCFG XIP bit is set for Numonyx hw/block/m25p80: Make Numonyx config field names more accurate hw/misc/zynq_slcr: Avoid #DIV/0! error arm: xlnx-versal: Connect usb to virt-versal usb: xlnx-usb-subsystem: Add xilinx usb subsystem usb: Add DWC3 model usb: Add versal-usb2-ctrl-regs module elf_ops.h: Be more verbose with ROM blob names elf_ops.h: Don't truncate name of the ROM blobs we create hw/core/loader.c: Improve reporting of ROM overlap errors hw/core/loader.c: Track last-seen ROM in rom_check_and_register_reset() target/nios2: Use deposit32() to update ipending register target/nios2: Move nios2_check_interrupts() into target/nios2 target/nios2: Move IIC code into CPU object proper target/openrisc: Move pic_cpu code into CPU object proper hw/openrisc/openrisc_sim: Abstract out "get IRQ x of CPU y" hw/openrisc/openrisc_sim: Use IRQ splitter when connecting IRQ to multiple CPUs gdbstub: Correct misparsing of vCont C/S requests Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
657ee88ef3
@ -259,7 +259,6 @@ 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
|
||||
|
||||
|
@ -1243,7 +1243,7 @@ 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;
|
||||
}
|
||||
|
@ -39,6 +39,8 @@ 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;
|
||||
|
||||
@ -66,6 +68,8 @@ 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");
|
||||
|
||||
@ -148,6 +152,56 @@ 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 };
|
||||
@ -515,6 +569,7 @@ 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);
|
||||
|
@ -145,6 +145,31 @@ 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;
|
||||
@ -333,6 +358,7 @@ 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);
|
||||
|
@ -136,7 +136,7 @@ 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
|
||||
@ -144,9 +144,9 @@ 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)
|
||||
|
||||
@ -413,6 +413,12 @@ 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 {
|
||||
@ -768,8 +774,8 @@ 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) {
|
||||
s->volatile_cfg |= VCFG_XIP_MODE_ENABLED;
|
||||
== NVCFG_XIP_MODE_DISABLED) {
|
||||
s->volatile_cfg |= VCFG_XIP_MODE_DISABLED;
|
||||
}
|
||||
s->volatile_cfg |= deposit32(s->volatile_cfg,
|
||||
VCFG_DUMMY_CLK_POS,
|
||||
@ -784,10 +790,10 @@ 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;
|
||||
@ -820,6 +826,41 @@ 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 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);
|
||||
@ -829,7 +870,7 @@ 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) {
|
||||
@ -868,7 +909,7 @@ 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)) {
|
||||
@ -908,7 +949,7 @@ 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)) {
|
||||
@ -950,14 +991,8 @@ 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:
|
||||
@ -966,24 +1001,84 @@ 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:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
@ -1035,6 +1130,7 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
||||
break;
|
||||
|
||||
case JEDEC_READ:
|
||||
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];
|
||||
@ -1046,6 +1142,10 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
||||
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:
|
||||
|
@ -1166,34 +1166,77 @@ 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
hwaddr addr = 0;
|
||||
MemoryRegionSection section;
|
||||
Rom *rom;
|
||||
AddressSpace *as = NULL;
|
||||
Rom *rom, *last_rom = NULL;
|
||||
bool found_overlap = false;
|
||||
|
||||
QTAILQ_FOREACH(rom, &roms, next) {
|
||||
if (rom->fw_file) {
|
||||
continue;
|
||||
}
|
||||
if (!rom->mr) {
|
||||
if ((addr > rom->addr) && (as == rom->as)) {
|
||||
fprintf(stderr, "rom: requested regions overlap "
|
||||
"(rom %s. free=0x" TARGET_FMT_plx
|
||||
", addr=0x" TARGET_FMT_plx ")\n",
|
||||
rom->name, addr, rom->addr);
|
||||
return -1;
|
||||
if (roms_overlap(last_rom, rom)) {
|
||||
if (!found_overlap) {
|
||||
found_overlap = true;
|
||||
rom_print_overlap_error_header();
|
||||
}
|
||||
addr = rom->addr;
|
||||
addr += rom->romsize;
|
||||
as = rom->as;
|
||||
rom_print_one_overlap_error(last_rom, rom);
|
||||
/* Keep going through the list so we report all overlaps */
|
||||
}
|
||||
last_rom = rom;
|
||||
}
|
||||
section = memory_region_find(rom->mr ? rom->mr : get_system_memory(),
|
||||
rom->addr, 1);
|
||||
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;
|
||||
|
@ -37,7 +37,6 @@ 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'))
|
||||
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* 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)
|
@ -217,6 +217,11 @@ 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;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ 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 */
|
||||
@ -75,17 +75,8 @@ 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 */
|
||||
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
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 &&
|
||||
(env->regs[CR_STATUS] & CR_STATUS_PIE)) {
|
||||
env->irq_pending = 0;
|
||||
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);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
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'))
|
||||
|
||||
|
@ -3,3 +3,4 @@ config OR1K_SIM
|
||||
select SERIAL
|
||||
select OPENCORES_ETH
|
||||
select OMPIC
|
||||
select SPLIT_IRQ
|
||||
|
@ -1,5 +1,5 @@
|
||||
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}
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "hw/core/split-irq.h"
|
||||
|
||||
#define KERNEL_LOAD_ADDR 0x100
|
||||
|
||||
@ -51,8 +52,13 @@ 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 qdev_get_gpio_in_named(DEVICE(cpus[cpunum]), "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;
|
||||
@ -64,15 +70,23 @@ static void openrisc_sim_net_init(hwaddr base, hwaddr descriptors,
|
||||
|
||||
s = SYS_BUS_DEVICE(dev);
|
||||
sysbus_realize_and_unref(s, &error_fatal);
|
||||
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++) {
|
||||
sysbus_connect_irq(s, 0, 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, 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;
|
||||
@ -84,7 +98,7 @@ 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);
|
||||
}
|
||||
@ -127,26 +141,23 @@ 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_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));
|
||||
@ -155,15 +166,16 @@ 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,
|
||||
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* 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];
|
||||
}
|
||||
}
|
@ -112,3 +112,13 @@ config IMX_USBPHY
|
||||
bool
|
||||
default y
|
||||
depends on USB
|
||||
|
||||
config USB_DWC3
|
||||
bool
|
||||
select USB_XHCI_SYSBUS
|
||||
select REGISTER
|
||||
|
||||
config XLNX_USB_SUBSYS
|
||||
bool
|
||||
default y if XLNX_VERSAL
|
||||
select USB_DWC3
|
||||
|
689
hw/usb/hcd-dwc3.c
Normal file
689
hw/usb/hcd-dwc3.c
Normal file
@ -0,0 +1,689 @@
|
||||
/*
|
||||
* 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)
|
@ -26,10 +26,13 @@ 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'))
|
||||
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'))
|
||||
|
94
hw/usb/xlnx-usb-subsystem.c
Normal file
94
hw/usb/xlnx-usb-subsystem.c
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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)
|
229
hw/usb/xlnx-versal-usb2-ctrl-regs.c
Normal file
229
hw/usb/xlnx-versal-usb2-ctrl-regs.c
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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)
|
@ -21,6 +21,7 @@
|
||||
#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)
|
||||
@ -59,6 +60,7 @@ struct Versal {
|
||||
PL011State uart[XLNX_VERSAL_NR_UARTS];
|
||||
CadenceGEMState gem[XLNX_VERSAL_NR_GEMS];
|
||||
XlnxZDMA adma[XLNX_VERSAL_NR_ADMAS];
|
||||
VersalUsb2 usb;
|
||||
} iou;
|
||||
} lpd;
|
||||
|
||||
@ -88,6 +90,7 @@ 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
|
||||
@ -125,6 +128,12 @@ 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
|
||||
|
@ -330,7 +330,6 @@ 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))
|
||||
@ -544,7 +543,9 @@ 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("%s ELF program header segment %d",
|
||||
name, i);
|
||||
|
||||
/*
|
||||
* rom_add_elf_program() takes its own reference to
|
||||
|
55
include/hw/usb/hcd-dwc3.h
Normal file
55
include/hw/usb/hcd-dwc3.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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
|
45
include/hw/usb/xlnx-usb-subsystem.h
Normal file
45
include/hw/usb/xlnx-usb-subsystem.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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
|
45
include/hw/usb/xlnx-versal-usb2-ctrl-regs.h
Normal file
45
include/hw/usb/xlnx-versal-usb2-ctrl-regs.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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
|
@ -3278,7 +3278,6 @@ 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);
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,26 @@ 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] = deposit32(env->regs[CR_IPENDING], irq, 1, !!level);
|
||||
|
||||
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);
|
||||
@ -72,6 +92,15 @@ 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
|
||||
}
|
||||
|
||||
|
@ -201,9 +201,6 @@ 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);
|
||||
|
||||
#define CPU_RESOLVING_TYPE TYPE_NIOS2_CPU
|
||||
|
@ -36,6 +36,15 @@ 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();
|
||||
|
@ -65,6 +65,34 @@ 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);
|
||||
@ -88,6 +116,10 @@ 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 */
|
||||
|
@ -293,7 +293,6 @@ typedef struct CPUOpenRISCState {
|
||||
uint32_t picmr; /* Interrupt mask register */
|
||||
uint32_t picsr; /* Interrupt contrl register*/
|
||||
#endif
|
||||
void *irq[32]; /* Interrupt irq input */
|
||||
} CPUOpenRISCState;
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user