1 /* 2 * i.MX USB PHY 3 * 4 * Copyright (c) 2020 Guenter Roeck <linux@roeck-us.net> 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 * 9 * We need to implement basic reset control in the PHY control register. 10 * For everything else, it is sufficient to set whatever is written. 11 */ 12 13 #include "qemu/osdep.h" 14 #include "hw/usb/imx-usb-phy.h" 15 #include "migration/vmstate.h" 16 #include "qemu/log.h" 17 #include "qemu/module.h" 18 19 static const VMStateDescription vmstate_imx_usbphy = { 20 .name = TYPE_IMX_USBPHY, 21 .version_id = 1, 22 .minimum_version_id = 1, 23 .fields = (const VMStateField[]) { 24 VMSTATE_UINT32_ARRAY(usbphy, IMXUSBPHYState, USBPHY_MAX), 25 VMSTATE_END_OF_LIST() 26 }, 27 }; 28 29 static void imx_usbphy_softreset(IMXUSBPHYState *s) 30 { 31 s->usbphy[USBPHY_PWD] = 0x001e1c00; 32 s->usbphy[USBPHY_TX] = 0x10060607; 33 s->usbphy[USBPHY_RX] = 0x00000000; 34 s->usbphy[USBPHY_CTRL] = 0xc0200000; 35 } 36 37 static void imx_usbphy_reset(DeviceState *dev) 38 { 39 IMXUSBPHYState *s = IMX_USBPHY(dev); 40 41 s->usbphy[USBPHY_STATUS] = 0x00000000; 42 s->usbphy[USBPHY_DEBUG] = 0x7f180000; 43 s->usbphy[USBPHY_DEBUG0_STATUS] = 0x00000000; 44 s->usbphy[USBPHY_DEBUG1] = 0x00001000; 45 s->usbphy[USBPHY_VERSION] = 0x04020000; 46 47 imx_usbphy_softreset(s); 48 } 49 50 static uint64_t imx_usbphy_read(void *opaque, hwaddr offset, unsigned size) 51 { 52 IMXUSBPHYState *s = (IMXUSBPHYState *)opaque; 53 uint32_t index = offset >> 2; 54 uint32_t value; 55 56 switch (index) { 57 case USBPHY_PWD_SET: 58 case USBPHY_TX_SET: 59 case USBPHY_RX_SET: 60 case USBPHY_CTRL_SET: 61 case USBPHY_DEBUG_SET: 62 case USBPHY_DEBUG1_SET: 63 /* 64 * All REG_NAME_SET register access are in fact targeting the 65 * REG_NAME register. 66 */ 67 value = s->usbphy[index - 1]; 68 break; 69 case USBPHY_PWD_CLR: 70 case USBPHY_TX_CLR: 71 case USBPHY_RX_CLR: 72 case USBPHY_CTRL_CLR: 73 case USBPHY_DEBUG_CLR: 74 case USBPHY_DEBUG1_CLR: 75 /* 76 * All REG_NAME_CLR register access are in fact targeting the 77 * REG_NAME register. 78 */ 79 value = s->usbphy[index - 2]; 80 break; 81 case USBPHY_PWD_TOG: 82 case USBPHY_TX_TOG: 83 case USBPHY_RX_TOG: 84 case USBPHY_CTRL_TOG: 85 case USBPHY_DEBUG_TOG: 86 case USBPHY_DEBUG1_TOG: 87 /* 88 * All REG_NAME_TOG register access are in fact targeting the 89 * REG_NAME register. 90 */ 91 value = s->usbphy[index - 3]; 92 break; 93 default: 94 if (index < USBPHY_MAX) { 95 value = s->usbphy[index]; 96 } else { 97 qemu_log_mask(LOG_GUEST_ERROR, 98 "%s: Read from non-existing USB PHY register 0x%" 99 HWADDR_PRIx "\n", 100 __func__, offset); 101 value = 0; 102 } 103 break; 104 } 105 return (uint64_t)value; 106 } 107 108 static void imx_usbphy_write(void *opaque, hwaddr offset, uint64_t value, 109 unsigned size) 110 { 111 IMXUSBPHYState *s = (IMXUSBPHYState *)opaque; 112 uint32_t index = offset >> 2; 113 114 switch (index) { 115 case USBPHY_CTRL: 116 s->usbphy[index] = value; 117 if (value & USBPHY_CTRL_SFTRST) { 118 imx_usbphy_softreset(s); 119 } 120 break; 121 case USBPHY_PWD: 122 case USBPHY_TX: 123 case USBPHY_RX: 124 case USBPHY_STATUS: 125 case USBPHY_DEBUG: 126 case USBPHY_DEBUG1: 127 s->usbphy[index] = value; 128 break; 129 case USBPHY_CTRL_SET: 130 s->usbphy[index - 1] |= value; 131 if (value & USBPHY_CTRL_SFTRST) { 132 imx_usbphy_softreset(s); 133 } 134 break; 135 case USBPHY_PWD_SET: 136 case USBPHY_TX_SET: 137 case USBPHY_RX_SET: 138 case USBPHY_DEBUG_SET: 139 case USBPHY_DEBUG1_SET: 140 /* 141 * All REG_NAME_SET register access are in fact targeting the 142 * REG_NAME register. So we change the value of the REG_NAME 143 * register, setting bits passed in the value. 144 */ 145 s->usbphy[index - 1] |= value; 146 break; 147 case USBPHY_PWD_CLR: 148 case USBPHY_TX_CLR: 149 case USBPHY_RX_CLR: 150 case USBPHY_CTRL_CLR: 151 case USBPHY_DEBUG_CLR: 152 case USBPHY_DEBUG1_CLR: 153 /* 154 * All REG_NAME_CLR register access are in fact targeting the 155 * REG_NAME register. So we change the value of the REG_NAME 156 * register, unsetting bits passed in the value. 157 */ 158 s->usbphy[index - 2] &= ~value; 159 break; 160 case USBPHY_CTRL_TOG: 161 s->usbphy[index - 3] ^= value; 162 if ((value & USBPHY_CTRL_SFTRST) && 163 (s->usbphy[index - 3] & USBPHY_CTRL_SFTRST)) { 164 imx_usbphy_softreset(s); 165 } 166 break; 167 case USBPHY_PWD_TOG: 168 case USBPHY_TX_TOG: 169 case USBPHY_RX_TOG: 170 case USBPHY_DEBUG_TOG: 171 case USBPHY_DEBUG1_TOG: 172 /* 173 * All REG_NAME_TOG register access are in fact targeting the 174 * REG_NAME register. So we change the value of the REG_NAME 175 * register, toggling bits passed in the value. 176 */ 177 s->usbphy[index - 3] ^= value; 178 break; 179 default: 180 /* Other registers are read-only or do not exist */ 181 qemu_log_mask(LOG_GUEST_ERROR, 182 "%s: Write to %s USB PHY register 0x%" 183 HWADDR_PRIx "\n", 184 __func__, 185 index >= USBPHY_MAX ? "non-existing" : "read-only", 186 offset); 187 break; 188 } 189 } 190 191 static const struct MemoryRegionOps imx_usbphy_ops = { 192 .read = imx_usbphy_read, 193 .write = imx_usbphy_write, 194 .endianness = DEVICE_NATIVE_ENDIAN, 195 .valid = { 196 /* 197 * Our device would not work correctly if the guest was doing 198 * unaligned access. This might not be a limitation on the real 199 * device but in practice there is no reason for a guest to access 200 * this device unaligned. 201 */ 202 .min_access_size = 4, 203 .max_access_size = 4, 204 .unaligned = false, 205 }, 206 }; 207 208 static void imx_usbphy_realize(DeviceState *dev, Error **errp) 209 { 210 IMXUSBPHYState *s = IMX_USBPHY(dev); 211 212 memory_region_init_io(&s->iomem, OBJECT(s), &imx_usbphy_ops, s, 213 "imx-usbphy", 0x1000); 214 sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); 215 } 216 217 static void imx_usbphy_class_init(ObjectClass *klass, void *data) 218 { 219 DeviceClass *dc = DEVICE_CLASS(klass); 220 221 device_class_set_legacy_reset(dc, imx_usbphy_reset); 222 dc->vmsd = &vmstate_imx_usbphy; 223 dc->desc = "i.MX USB PHY Module"; 224 dc->realize = imx_usbphy_realize; 225 } 226 227 static const TypeInfo imx_usbphy_info = { 228 .name = TYPE_IMX_USBPHY, 229 .parent = TYPE_SYS_BUS_DEVICE, 230 .instance_size = sizeof(IMXUSBPHYState), 231 .class_init = imx_usbphy_class_init, 232 }; 233 234 static void imx_usbphy_register_types(void) 235 { 236 type_register_static(&imx_usbphy_info); 237 } 238 239 type_init(imx_usbphy_register_types) 240