graph-lock: TSA annotations for lock/unlock functions
[qemu.git] / hw / usb / imx-usb-phy.c
blob5d7a549e34d15f6d5fc9646a0fc75229a8926ad9
1 /*
2 * i.MX USB PHY
4 * Copyright (c) 2020 Guenter Roeck <linux@roeck-us.net>
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.
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.
13 #include "qemu/osdep.h"
14 #include "hw/usb/imx-usb-phy.h"
15 #include "migration/vmstate.h"
16 #include "qemu/module.h"
18 static 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()
28 static void imx_usbphy_softreset(IMXUSBPHYState *s)
30 s->usbphy[USBPHY_PWD] = 0x001e1c00;
31 s->usbphy[USBPHY_TX] = 0x10060607;
32 s->usbphy[USBPHY_RX] = 0x00000000;
33 s->usbphy[USBPHY_CTRL] = 0xc0200000;
36 static void imx_usbphy_reset(DeviceState *dev)
38 IMXUSBPHYState *s = IMX_USBPHY(dev);
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;
46 imx_usbphy_softreset(s);
49 static uint64_t imx_usbphy_read(void *opaque, hwaddr offset, unsigned size)
51 IMXUSBPHYState *s = (IMXUSBPHYState *)opaque;
52 uint32_t index = offset >> 2;
53 uint32_t value;
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:
63 * All REG_NAME_SET register access are in fact targeting the
64 * REG_NAME register.
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:
75 * All REG_NAME_CLR register access are in fact targeting the
76 * REG_NAME register.
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:
87 * All REG_NAME_TOG register access are in fact targeting the
88 * REG_NAME register.
90 value = s->usbphy[index - 3];
91 break;
92 default:
93 value = s->usbphy[index];
94 break;
96 return (uint64_t)value;
99 static void imx_usbphy_write(void *opaque, hwaddr offset, uint64_t value,
100 unsigned size)
102 IMXUSBPHYState *s = (IMXUSBPHYState *)opaque;
103 uint32_t index = offset >> 2;
105 switch (index) {
106 case USBPHY_CTRL:
107 s->usbphy[index] = value;
108 if (value & USBPHY_CTRL_SFTRST) {
109 imx_usbphy_softreset(s);
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);
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:
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.
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:
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.
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);
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:
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.
168 s->usbphy[index - 3] ^= value;
169 break;
170 default:
171 /* Other registers are read-only */
172 break;
176 static const struct MemoryRegionOps imx_usbphy_ops = {
177 .read = imx_usbphy_read,
178 .write = imx_usbphy_write,
179 .endianness = DEVICE_NATIVE_ENDIAN,
180 .valid = {
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.
187 .min_access_size = 4,
188 .max_access_size = 4,
189 .unaligned = false,
193 static void imx_usbphy_realize(DeviceState *dev, Error **errp)
195 IMXUSBPHYState *s = IMX_USBPHY(dev);
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);
202 static void imx_usbphy_class_init(ObjectClass *klass, void *data)
204 DeviceClass *dc = DEVICE_CLASS(klass);
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;
212 static 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,
219 static void imx_usbphy_register_types(void)
221 type_register_static(&imx_usbphy_info);
224 type_init(imx_usbphy_register_types)