xref: /openbmc/qemu/hw/usb/imx-usb-phy.c (revision 4d87fcdd)
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 
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()
25     },
26 };
27 
28 static 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 
36 static 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 
49 static 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 
99 static 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 
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 = {
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 
193 static 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 
202 static 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 
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,
217 };
218 
219 static void imx_usbphy_register_types(void)
220 {
221     type_register_static(&imx_usbphy_info);
222 }
223 
224 type_init(imx_usbphy_register_types)
225