xref: /openbmc/qemu/hw/usb/imx-usb-phy.c (revision ff788b70)
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