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