1 /* 2 * Copyright (c) 2018, Impinj, Inc. 3 * 4 * Chipidea USB block emulation code 5 * 6 * Author: Andrey Smirnov <andrew.smirnov@gmail.com> 7 * 8 * This work is licensed under the terms of the GNU GPL, version 2 or later. 9 * See the COPYING file in the top-level directory. 10 */ 11 12 #include "qemu/osdep.h" 13 #include "hw/usb/hcd-ehci.h" 14 #include "hw/usb/chipidea.h" 15 #include "qemu/log.h" 16 #include "qemu/module.h" 17 18 enum { 19 CHIPIDEA_USBx_DCIVERSION = 0x000, 20 CHIPIDEA_USBx_DCCPARAMS = 0x004, 21 CHIPIDEA_USBx_DCCPARAMS_HC = BIT(8), 22 }; 23 24 static uint64_t chipidea_read(void *opaque, hwaddr offset, 25 unsigned size) 26 { 27 return 0; 28 } 29 30 static void chipidea_write(void *opaque, hwaddr offset, 31 uint64_t value, unsigned size) 32 { 33 } 34 35 static const struct MemoryRegionOps chipidea_ops = { 36 .read = chipidea_read, 37 .write = chipidea_write, 38 .endianness = DEVICE_NATIVE_ENDIAN, 39 .impl = { 40 /* 41 * Our device would not work correctly if the guest was doing 42 * unaligned access. This might not be a limitation on the 43 * real device but in practice there is no reason for a guest 44 * to access this device unaligned. 45 */ 46 .min_access_size = 4, 47 .max_access_size = 4, 48 .unaligned = false, 49 }, 50 }; 51 52 static uint64_t chipidea_dc_read(void *opaque, hwaddr offset, 53 unsigned size) 54 { 55 switch (offset) { 56 case CHIPIDEA_USBx_DCIVERSION: 57 return 0x1; 58 case CHIPIDEA_USBx_DCCPARAMS: 59 /* 60 * Real hardware (at least i.MX7) will also report the 61 * controller as "Device Capable" (and 8 supported endpoints), 62 * but there doesn't seem to be much point in doing so, since 63 * we don't emulate that part. 64 */ 65 return CHIPIDEA_USBx_DCCPARAMS_HC; 66 } 67 68 return 0; 69 } 70 71 static void chipidea_dc_write(void *opaque, hwaddr offset, 72 uint64_t value, unsigned size) 73 { 74 } 75 76 static const struct MemoryRegionOps chipidea_dc_ops = { 77 .read = chipidea_dc_read, 78 .write = chipidea_dc_write, 79 .endianness = DEVICE_NATIVE_ENDIAN, 80 .impl = { 81 /* 82 * Our device would not work correctly if the guest was doing 83 * unaligned access. This might not be a limitation on the real 84 * device but in practice there is no reason for a guest to access 85 * this device unaligned. 86 */ 87 .min_access_size = 4, 88 .max_access_size = 4, 89 .unaligned = false, 90 }, 91 }; 92 93 static void chipidea_init(Object *obj) 94 { 95 EHCIState *ehci = &SYS_BUS_EHCI(obj)->ehci; 96 ChipideaState *ci = CHIPIDEA(obj); 97 int i; 98 99 for (i = 0; i < ARRAY_SIZE(ci->iomem); i++) { 100 const struct { 101 const char *name; 102 hwaddr offset; 103 uint64_t size; 104 const struct MemoryRegionOps *ops; 105 } regions[ARRAY_SIZE(ci->iomem)] = { 106 /* 107 * Registers located between offsets 0x000 and 0xFC 108 */ 109 { 110 .name = TYPE_CHIPIDEA ".misc", 111 .offset = 0x000, 112 .size = 0x100, 113 .ops = &chipidea_ops, 114 }, 115 /* 116 * Registers located between offsets 0x1A4 and 0x1DC 117 */ 118 { 119 .name = TYPE_CHIPIDEA ".endpoints", 120 .offset = 0x1A4, 121 .size = 0x1DC - 0x1A4 + 4, 122 .ops = &chipidea_ops, 123 }, 124 /* 125 * USB_x_DCIVERSION and USB_x_DCCPARAMS 126 */ 127 { 128 .name = TYPE_CHIPIDEA ".dc", 129 .offset = 0x120, 130 .size = 8, 131 .ops = &chipidea_dc_ops, 132 }, 133 }; 134 135 memory_region_init_io(&ci->iomem[i], 136 obj, 137 regions[i].ops, 138 ci, 139 regions[i].name, 140 regions[i].size); 141 142 memory_region_add_subregion(&ehci->mem, 143 regions[i].offset, 144 &ci->iomem[i]); 145 } 146 } 147 148 static void chipidea_class_init(ObjectClass *klass, void *data) 149 { 150 DeviceClass *dc = DEVICE_CLASS(klass); 151 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass); 152 153 /* 154 * Offsets used were taken from i.MX7Dual Applications Processor 155 * Reference Manual, Rev 0.1, p. 3177, Table 11-59 156 */ 157 sec->capsbase = 0x100; 158 sec->opregbase = 0x140; 159 sec->portnr = 1; 160 161 set_bit(DEVICE_CATEGORY_USB, dc->categories); 162 dc->desc = "Chipidea USB Module"; 163 } 164 165 static const TypeInfo chipidea_info = { 166 .name = TYPE_CHIPIDEA, 167 .parent = TYPE_SYS_BUS_EHCI, 168 .instance_size = sizeof(ChipideaState), 169 .instance_init = chipidea_init, 170 .class_init = chipidea_class_init, 171 }; 172 173 static void chipidea_register_type(void) 174 { 175 type_register_static(&chipidea_info); 176 } 177 type_init(chipidea_register_type) 178