Merge remote-tracking branch 'remotes/philmd-gitlab/tags/renesas-20201027' into staging
[qemu.git] / 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)