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