1 /* 2 * QEMU model of the VersalUsb2CtrlRegs Register control/Status block for 3 * USB2.0 controller 4 * 5 * This module should control phy_reset, permanent device plugs, frame length 6 * time adjust & setting of coherency paths. None of which are emulated in 7 * present model. 8 * 9 * Copyright (c) 2020 Xilinx Inc. Vikram Garhwal <fnu.vikram@xilinx.com> 10 * 11 * Permission is hereby granted, free of charge, to any person obtaining a copy 12 * of this software and associated documentation files (the "Software"), to deal 13 * in the Software without restriction, including without limitation the rights 14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 * copies of the Software, and to permit persons to whom the Software is 16 * furnished to do so, subject to the following conditions: 17 * 18 * The above copyright notice and this permission notice shall be included in 19 * all copies or substantial portions of the Software. 20 * 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 * THE SOFTWARE. 28 */ 29 30 #include "qemu/osdep.h" 31 #include "hw/sysbus.h" 32 #include "hw/irq.h" 33 #include "hw/register.h" 34 #include "qemu/bitops.h" 35 #include "qom/object.h" 36 #include "migration/vmstate.h" 37 #include "hw/usb/xlnx-versal-usb2-ctrl-regs.h" 38 39 #ifndef XILINX_VERSAL_USB2_CTRL_REGS_ERR_DEBUG 40 #define XILINX_VERSAL_USB2_CTRL_REGS_ERR_DEBUG 0 41 #endif 42 43 REG32(BUS_FILTER, 0x30) 44 FIELD(BUS_FILTER, BYPASS, 0, 4) 45 REG32(PORT, 0x34) 46 FIELD(PORT, HOST_SMI_BAR_WR, 4, 1) 47 FIELD(PORT, HOST_SMI_PCI_CMD_REG_WR, 3, 1) 48 FIELD(PORT, HOST_MSI_ENABLE, 2, 1) 49 FIELD(PORT, PWR_CTRL_PRSNT, 1, 1) 50 FIELD(PORT, HUB_PERM_ATTACH, 0, 1) 51 REG32(JITTER_ADJUST, 0x38) 52 FIELD(JITTER_ADJUST, FLADJ, 0, 6) 53 REG32(BIGENDIAN, 0x40) 54 FIELD(BIGENDIAN, ENDIAN_GS, 0, 1) 55 REG32(COHERENCY, 0x44) 56 FIELD(COHERENCY, USB_COHERENCY, 0, 1) 57 REG32(XHC_BME, 0x48) 58 FIELD(XHC_BME, XHC_BME, 0, 1) 59 REG32(REG_CTRL, 0x60) 60 FIELD(REG_CTRL, SLVERR_ENABLE, 0, 1) 61 REG32(IR_STATUS, 0x64) 62 FIELD(IR_STATUS, HOST_SYS_ERR, 1, 1) 63 FIELD(IR_STATUS, ADDR_DEC_ERR, 0, 1) 64 REG32(IR_MASK, 0x68) 65 FIELD(IR_MASK, HOST_SYS_ERR, 1, 1) 66 FIELD(IR_MASK, ADDR_DEC_ERR, 0, 1) 67 REG32(IR_ENABLE, 0x6c) 68 FIELD(IR_ENABLE, HOST_SYS_ERR, 1, 1) 69 FIELD(IR_ENABLE, ADDR_DEC_ERR, 0, 1) 70 REG32(IR_DISABLE, 0x70) 71 FIELD(IR_DISABLE, HOST_SYS_ERR, 1, 1) 72 FIELD(IR_DISABLE, ADDR_DEC_ERR, 0, 1) 73 REG32(USB3, 0x78) 74 75 static void ir_update_irq(VersalUsb2CtrlRegs *s) 76 { 77 bool pending = s->regs[R_IR_STATUS] & ~s->regs[R_IR_MASK]; 78 qemu_set_irq(s->irq_ir, pending); 79 } 80 81 static void ir_status_postw(RegisterInfo *reg, uint64_t val64) 82 { 83 VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(reg->opaque); 84 /* 85 * TODO: This should also clear USBSTS.HSE field in USB XHCI register. 86 * May be combine both the modules. 87 */ 88 ir_update_irq(s); 89 } 90 91 static uint64_t ir_enable_prew(RegisterInfo *reg, uint64_t val64) 92 { 93 VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(reg->opaque); 94 uint32_t val = val64; 95 96 s->regs[R_IR_MASK] &= ~val; 97 ir_update_irq(s); 98 return 0; 99 } 100 101 static uint64_t ir_disable_prew(RegisterInfo *reg, uint64_t val64) 102 { 103 VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(reg->opaque); 104 uint32_t val = val64; 105 106 s->regs[R_IR_MASK] |= val; 107 ir_update_irq(s); 108 return 0; 109 } 110 111 static const RegisterAccessInfo usb2_ctrl_regs_regs_info[] = { 112 { .name = "BUS_FILTER", .addr = A_BUS_FILTER, 113 .rsvd = 0xfffffff0, 114 },{ .name = "PORT", .addr = A_PORT, 115 .rsvd = 0xffffffe0, 116 },{ .name = "JITTER_ADJUST", .addr = A_JITTER_ADJUST, 117 .reset = 0x20, 118 .rsvd = 0xffffffc0, 119 },{ .name = "BIGENDIAN", .addr = A_BIGENDIAN, 120 .rsvd = 0xfffffffe, 121 },{ .name = "COHERENCY", .addr = A_COHERENCY, 122 .rsvd = 0xfffffffe, 123 },{ .name = "XHC_BME", .addr = A_XHC_BME, 124 .reset = 0x1, 125 .rsvd = 0xfffffffe, 126 },{ .name = "REG_CTRL", .addr = A_REG_CTRL, 127 .rsvd = 0xfffffffe, 128 },{ .name = "IR_STATUS", .addr = A_IR_STATUS, 129 .rsvd = 0xfffffffc, 130 .w1c = 0x3, 131 .post_write = ir_status_postw, 132 },{ .name = "IR_MASK", .addr = A_IR_MASK, 133 .reset = 0x3, 134 .rsvd = 0xfffffffc, 135 .ro = 0x3, 136 },{ .name = "IR_ENABLE", .addr = A_IR_ENABLE, 137 .rsvd = 0xfffffffc, 138 .pre_write = ir_enable_prew, 139 },{ .name = "IR_DISABLE", .addr = A_IR_DISABLE, 140 .rsvd = 0xfffffffc, 141 .pre_write = ir_disable_prew, 142 },{ .name = "USB3", .addr = A_USB3, 143 } 144 }; 145 146 static void usb2_ctrl_regs_reset_init(Object *obj, ResetType type) 147 { 148 VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(obj); 149 unsigned int i; 150 151 for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { 152 register_reset(&s->regs_info[i]); 153 } 154 } 155 156 static void usb2_ctrl_regs_reset_hold(Object *obj, ResetType type) 157 { 158 VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(obj); 159 160 ir_update_irq(s); 161 } 162 163 static const MemoryRegionOps usb2_ctrl_regs_ops = { 164 .read = register_read_memory, 165 .write = register_write_memory, 166 .endianness = DEVICE_LITTLE_ENDIAN, 167 .valid = { 168 .min_access_size = 4, 169 .max_access_size = 4, 170 }, 171 }; 172 173 static void usb2_ctrl_regs_init(Object *obj) 174 { 175 VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(obj); 176 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 177 RegisterInfoArray *reg_array; 178 179 memory_region_init(&s->iomem, obj, TYPE_XILINX_VERSAL_USB2_CTRL_REGS, 180 USB2_REGS_R_MAX * 4); 181 reg_array = 182 register_init_block32(DEVICE(obj), usb2_ctrl_regs_regs_info, 183 ARRAY_SIZE(usb2_ctrl_regs_regs_info), 184 s->regs_info, s->regs, 185 &usb2_ctrl_regs_ops, 186 XILINX_VERSAL_USB2_CTRL_REGS_ERR_DEBUG, 187 USB2_REGS_R_MAX * 4); 188 memory_region_add_subregion(&s->iomem, 189 0x0, 190 ®_array->mem); 191 sysbus_init_mmio(sbd, &s->iomem); 192 sysbus_init_irq(sbd, &s->irq_ir); 193 } 194 195 static const VMStateDescription vmstate_usb2_ctrl_regs = { 196 .name = TYPE_XILINX_VERSAL_USB2_CTRL_REGS, 197 .version_id = 1, 198 .minimum_version_id = 1, 199 .fields = (const VMStateField[]) { 200 VMSTATE_UINT32_ARRAY(regs, VersalUsb2CtrlRegs, USB2_REGS_R_MAX), 201 VMSTATE_END_OF_LIST(), 202 } 203 }; 204 205 static void usb2_ctrl_regs_class_init(ObjectClass *klass, void *data) 206 { 207 DeviceClass *dc = DEVICE_CLASS(klass); 208 ResettableClass *rc = RESETTABLE_CLASS(klass); 209 210 rc->phases.enter = usb2_ctrl_regs_reset_init; 211 rc->phases.hold = usb2_ctrl_regs_reset_hold; 212 dc->vmsd = &vmstate_usb2_ctrl_regs; 213 } 214 215 static const TypeInfo usb2_ctrl_regs_info = { 216 .name = TYPE_XILINX_VERSAL_USB2_CTRL_REGS, 217 .parent = TYPE_SYS_BUS_DEVICE, 218 .instance_size = sizeof(VersalUsb2CtrlRegs), 219 .class_init = usb2_ctrl_regs_class_init, 220 .instance_init = usb2_ctrl_regs_init, 221 }; 222 223 static void usb2_ctrl_regs_register_types(void) 224 { 225 type_register_static(&usb2_ctrl_regs_info); 226 } 227 228 type_init(usb2_ctrl_regs_register_types) 229