qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

hw/usb: Add basic i.MX USB Phy support

Add basic USB PHY support as implemented in i.MX23, i.MX28, i.MX6,
and i.MX7 SoCs.

The only support really needed - at least to boot Linux - is support
for soft reset, which needs to reset various registers to their initial
value. Otherwise, just record register values.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Message-id: 20200313014551.12554-2-linux@roeck-us.net
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

authored by

Guenter Roeck and committed by
Peter Maydell
0701a5ef a98135f7

+288
+2
MAINTAINERS
··· 764 764 F: hw/arm/fsl-imx6.c 765 765 F: hw/misc/imx6_*.c 766 766 F: hw/ssi/imx_spi.c 767 + F: hw/usb/imx-usb-phy.c 768 + F: include/hw/usb/imx-usb-phy.h 767 769 F: include/hw/arm/fsl-imx6.h 768 770 F: include/hw/misc/imx6_*.h 769 771 F: include/hw/ssi/imx_spi.h
+1
hw/arm/Kconfig
··· 373 373 select IMX 374 374 select IMX_FEC 375 375 select IMX_I2C 376 + select IMX_USBPHY 376 377 select SDHCI 377 378 378 379 config ASPEED_SOC
+5
hw/usb/Kconfig
··· 91 91 bool 92 92 default y 93 93 depends on USB 94 + 95 + config IMX_USBPHY 96 + bool 97 + default y 98 + depends on USB
+2
hw/usb/Makefile.objs
··· 61 61 xen-usb.o-cflags := $(LIBUSB_CFLAGS) 62 62 xen-usb.o-libs := $(LIBUSB_LIBS) 63 63 endif 64 + 65 + common-obj-$(CONFIG_IMX_USBPHY) += imx-usb-phy.o
+225
hw/usb/imx-usb-phy.c
··· 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 = (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 + value = s->usbphy[index]; 95 + break; 96 + } 97 + return (uint64_t)value; 98 + } 99 + 100 + static void imx_usbphy_write(void *opaque, hwaddr offset, uint64_t value, 101 + unsigned size) 102 + { 103 + IMXUSBPHYState *s = (IMXUSBPHYState *)opaque; 104 + uint32_t index = offset >> 2; 105 + 106 + switch (index) { 107 + case USBPHY_CTRL: 108 + s->usbphy[index] = value; 109 + if (value & USBPHY_CTRL_SFTRST) { 110 + imx_usbphy_softreset(s); 111 + } 112 + break; 113 + case USBPHY_PWD: 114 + case USBPHY_TX: 115 + case USBPHY_RX: 116 + case USBPHY_STATUS: 117 + case USBPHY_DEBUG: 118 + case USBPHY_DEBUG1: 119 + s->usbphy[index] = value; 120 + break; 121 + case USBPHY_CTRL_SET: 122 + s->usbphy[index - 1] |= value; 123 + if (value & USBPHY_CTRL_SFTRST) { 124 + imx_usbphy_softreset(s); 125 + } 126 + break; 127 + case USBPHY_PWD_SET: 128 + case USBPHY_TX_SET: 129 + case USBPHY_RX_SET: 130 + case USBPHY_DEBUG_SET: 131 + case USBPHY_DEBUG1_SET: 132 + /* 133 + * All REG_NAME_SET register access are in fact targeting the 134 + * REG_NAME register. So we change the value of the REG_NAME 135 + * register, setting bits passed in the value. 136 + */ 137 + s->usbphy[index - 1] |= value; 138 + break; 139 + case USBPHY_PWD_CLR: 140 + case USBPHY_TX_CLR: 141 + case USBPHY_RX_CLR: 142 + case USBPHY_CTRL_CLR: 143 + case USBPHY_DEBUG_CLR: 144 + case USBPHY_DEBUG1_CLR: 145 + /* 146 + * All REG_NAME_CLR register access are in fact targeting the 147 + * REG_NAME register. So we change the value of the REG_NAME 148 + * register, unsetting bits passed in the value. 149 + */ 150 + s->usbphy[index - 2] &= ~value; 151 + break; 152 + case USBPHY_CTRL_TOG: 153 + s->usbphy[index - 3] ^= value; 154 + if ((value & USBPHY_CTRL_SFTRST) && 155 + (s->usbphy[index - 3] & USBPHY_CTRL_SFTRST)) { 156 + imx_usbphy_softreset(s); 157 + } 158 + break; 159 + case USBPHY_PWD_TOG: 160 + case USBPHY_TX_TOG: 161 + case USBPHY_RX_TOG: 162 + case USBPHY_DEBUG_TOG: 163 + case USBPHY_DEBUG1_TOG: 164 + /* 165 + * All REG_NAME_TOG register access are in fact targeting the 166 + * REG_NAME register. So we change the value of the REG_NAME 167 + * register, toggling bits passed in the value. 168 + */ 169 + s->usbphy[index - 3] ^= value; 170 + break; 171 + default: 172 + /* Other registers are read-only */ 173 + break; 174 + } 175 + } 176 + 177 + static const struct MemoryRegionOps imx_usbphy_ops = { 178 + .read = imx_usbphy_read, 179 + .write = imx_usbphy_write, 180 + .endianness = DEVICE_NATIVE_ENDIAN, 181 + .valid = { 182 + /* 183 + * Our device would not work correctly if the guest was doing 184 + * unaligned access. This might not be a limitation on the real 185 + * device but in practice there is no reason for a guest to access 186 + * this device unaligned. 187 + */ 188 + .min_access_size = 4, 189 + .max_access_size = 4, 190 + .unaligned = false, 191 + }, 192 + }; 193 + 194 + static void imx_usbphy_realize(DeviceState *dev, Error **errp) 195 + { 196 + IMXUSBPHYState *s = IMX_USBPHY(dev); 197 + 198 + memory_region_init_io(&s->iomem, OBJECT(s), &imx_usbphy_ops, s, 199 + "imx-usbphy", 0x1000); 200 + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); 201 + } 202 + 203 + static void imx_usbphy_class_init(ObjectClass *klass, void *data) 204 + { 205 + DeviceClass *dc = DEVICE_CLASS(klass); 206 + 207 + dc->reset = imx_usbphy_reset; 208 + dc->vmsd = &vmstate_imx_usbphy; 209 + dc->desc = "i.MX USB PHY Module"; 210 + dc->realize = imx_usbphy_realize; 211 + } 212 + 213 + static const TypeInfo imx_usbphy_info = { 214 + .name = TYPE_IMX_USBPHY, 215 + .parent = TYPE_SYS_BUS_DEVICE, 216 + .instance_size = sizeof(IMXUSBPHYState), 217 + .class_init = imx_usbphy_class_init, 218 + }; 219 + 220 + static void imx_usbphy_register_types(void) 221 + { 222 + type_register_static(&imx_usbphy_info); 223 + } 224 + 225 + type_init(imx_usbphy_register_types)
+53
include/hw/usb/imx-usb-phy.h
··· 1 + #ifndef IMX_USB_PHY_H 2 + #define IMX_USB_PHY_H 3 + 4 + #include "hw/sysbus.h" 5 + #include "qemu/bitops.h" 6 + 7 + enum IMXUsbPhyRegisters { 8 + USBPHY_PWD, 9 + USBPHY_PWD_SET, 10 + USBPHY_PWD_CLR, 11 + USBPHY_PWD_TOG, 12 + USBPHY_TX, 13 + USBPHY_TX_SET, 14 + USBPHY_TX_CLR, 15 + USBPHY_TX_TOG, 16 + USBPHY_RX, 17 + USBPHY_RX_SET, 18 + USBPHY_RX_CLR, 19 + USBPHY_RX_TOG, 20 + USBPHY_CTRL, 21 + USBPHY_CTRL_SET, 22 + USBPHY_CTRL_CLR, 23 + USBPHY_CTRL_TOG, 24 + USBPHY_STATUS, 25 + USBPHY_DEBUG = 0x14, 26 + USBPHY_DEBUG_SET, 27 + USBPHY_DEBUG_CLR, 28 + USBPHY_DEBUG_TOG, 29 + USBPHY_DEBUG0_STATUS, 30 + USBPHY_DEBUG1 = 0x1c, 31 + USBPHY_DEBUG1_SET, 32 + USBPHY_DEBUG1_CLR, 33 + USBPHY_DEBUG1_TOG, 34 + USBPHY_VERSION, 35 + USBPHY_MAX 36 + }; 37 + 38 + #define USBPHY_CTRL_SFTRST BIT(31) 39 + 40 + #define TYPE_IMX_USBPHY "imx.usbphy" 41 + #define IMX_USBPHY(obj) OBJECT_CHECK(IMXUSBPHYState, (obj), TYPE_IMX_USBPHY) 42 + 43 + typedef struct IMXUSBPHYState { 44 + /* <private> */ 45 + SysBusDevice parent_obj; 46 + 47 + /* <public> */ 48 + MemoryRegion iomem; 49 + 50 + uint32_t usbphy[USBPHY_MAX]; 51 + } IMXUSBPHYState; 52 + 53 + #endif /* IMX_USB_PHY_H */