xref: /openbmc/qemu/hw/usb/hcd-dwc2.c (revision 69958d8a)
1153ef166SPaul Zimmerman /*
2153ef166SPaul Zimmerman  * dwc-hsotg (dwc2) USB host controller emulation
3153ef166SPaul Zimmerman  *
4153ef166SPaul Zimmerman  * Based on hw/usb/hcd-ehci.c and hw/usb/hcd-ohci.c
5153ef166SPaul Zimmerman  *
6153ef166SPaul Zimmerman  * Note that to use this emulation with the dwc-otg driver in the
7153ef166SPaul Zimmerman  * Raspbian kernel, you must pass the option "dwc_otg.fiq_fsm_enable=0"
8153ef166SPaul Zimmerman  * on the kernel command line.
9153ef166SPaul Zimmerman  *
10153ef166SPaul Zimmerman  * Some useful documentation used to develop this emulation can be
11153ef166SPaul Zimmerman  * found online (as of April 2020) at:
12153ef166SPaul Zimmerman  *
13153ef166SPaul Zimmerman  * http://www.capital-micro.com/PDF/CME-M7_Family_User_Guide_EN.pdf
14153ef166SPaul Zimmerman  * which has a pretty complete description of the controller starting
15153ef166SPaul Zimmerman  * on page 370.
16153ef166SPaul Zimmerman  *
17153ef166SPaul Zimmerman  * https://sourceforge.net/p/wive-ng/wive-ng-mt/ci/master/tree/docs/DataSheets/RT3050_5x_V2.0_081408_0902.pdf
18153ef166SPaul Zimmerman  * which has a description of the controller registers starting on
19153ef166SPaul Zimmerman  * page 130.
20153ef166SPaul Zimmerman  *
21153ef166SPaul Zimmerman  * Copyright (c) 2020 Paul Zimmerman <pauldzim@gmail.com>
22153ef166SPaul Zimmerman  *
23153ef166SPaul Zimmerman  * This program is free software; you can redistribute it and/or modify
24153ef166SPaul Zimmerman  * it under the terms of the GNU General Public License as published by
25153ef166SPaul Zimmerman  * the Free Software Foundation; either version 2 of the License, or
26153ef166SPaul Zimmerman  * (at your option) any later version.
27153ef166SPaul Zimmerman  *
28153ef166SPaul Zimmerman  * This program is distributed in the hope that it will be useful,
29153ef166SPaul Zimmerman  * but WITHOUT ANY WARRANTY; without even the implied warranty of
30153ef166SPaul Zimmerman  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31153ef166SPaul Zimmerman  * GNU General Public License for more details.
32153ef166SPaul Zimmerman  */
33153ef166SPaul Zimmerman 
34153ef166SPaul Zimmerman #include "qemu/osdep.h"
35153ef166SPaul Zimmerman #include "qemu/units.h"
36153ef166SPaul Zimmerman #include "qapi/error.h"
37153ef166SPaul Zimmerman #include "hw/usb/dwc2-regs.h"
38153ef166SPaul Zimmerman #include "hw/usb/hcd-dwc2.h"
39153ef166SPaul Zimmerman #include "migration/vmstate.h"
40153ef166SPaul Zimmerman #include "trace.h"
41153ef166SPaul Zimmerman #include "qemu/log.h"
42153ef166SPaul Zimmerman #include "qemu/error-report.h"
43153ef166SPaul Zimmerman #include "qemu/main-loop.h"
44153ef166SPaul Zimmerman #include "hw/qdev-properties.h"
45153ef166SPaul Zimmerman 
46153ef166SPaul Zimmerman #define USB_HZ_FS       12000000
47153ef166SPaul Zimmerman #define USB_HZ_HS       96000000
48153ef166SPaul Zimmerman #define USB_FRMINTVL    12000
49153ef166SPaul Zimmerman 
50153ef166SPaul Zimmerman /* nifty macros from Arnon's EHCI version  */
51153ef166SPaul Zimmerman #define get_field(data, field) \
52153ef166SPaul Zimmerman     (((data) & field##_MASK) >> field##_SHIFT)
53153ef166SPaul Zimmerman 
54153ef166SPaul Zimmerman #define set_field(data, newval, field) do { \
55153ef166SPaul Zimmerman     uint32_t val = *(data); \
56153ef166SPaul Zimmerman     val &= ~field##_MASK; \
57153ef166SPaul Zimmerman     val |= ((newval) << field##_SHIFT) & field##_MASK; \
58153ef166SPaul Zimmerman     *(data) = val; \
59153ef166SPaul Zimmerman } while (0)
60153ef166SPaul Zimmerman 
61153ef166SPaul Zimmerman #define get_bit(data, bitmask) \
62153ef166SPaul Zimmerman     (!!((data) & (bitmask)))
63153ef166SPaul Zimmerman 
64153ef166SPaul Zimmerman /* update irq line */
65153ef166SPaul Zimmerman static inline void dwc2_update_irq(DWC2State *s)
66153ef166SPaul Zimmerman {
67153ef166SPaul Zimmerman     static int oldlevel;
68153ef166SPaul Zimmerman     int level = 0;
69153ef166SPaul Zimmerman 
70153ef166SPaul Zimmerman     if ((s->gintsts & s->gintmsk) && (s->gahbcfg & GAHBCFG_GLBL_INTR_EN)) {
71153ef166SPaul Zimmerman         level = 1;
72153ef166SPaul Zimmerman     }
73153ef166SPaul Zimmerman     if (level != oldlevel) {
74153ef166SPaul Zimmerman         oldlevel = level;
75153ef166SPaul Zimmerman         trace_usb_dwc2_update_irq(level);
76153ef166SPaul Zimmerman         qemu_set_irq(s->irq, level);
77153ef166SPaul Zimmerman     }
78153ef166SPaul Zimmerman }
79153ef166SPaul Zimmerman 
80153ef166SPaul Zimmerman /* flag interrupt condition */
81153ef166SPaul Zimmerman static inline void dwc2_raise_global_irq(DWC2State *s, uint32_t intr)
82153ef166SPaul Zimmerman {
83153ef166SPaul Zimmerman     if (!(s->gintsts & intr)) {
84153ef166SPaul Zimmerman         s->gintsts |= intr;
85153ef166SPaul Zimmerman         trace_usb_dwc2_raise_global_irq(intr);
86153ef166SPaul Zimmerman         dwc2_update_irq(s);
87153ef166SPaul Zimmerman     }
88153ef166SPaul Zimmerman }
89153ef166SPaul Zimmerman 
90153ef166SPaul Zimmerman static inline void dwc2_lower_global_irq(DWC2State *s, uint32_t intr)
91153ef166SPaul Zimmerman {
92153ef166SPaul Zimmerman     if (s->gintsts & intr) {
93153ef166SPaul Zimmerman         s->gintsts &= ~intr;
94153ef166SPaul Zimmerman         trace_usb_dwc2_lower_global_irq(intr);
95153ef166SPaul Zimmerman         dwc2_update_irq(s);
96153ef166SPaul Zimmerman     }
97153ef166SPaul Zimmerman }
98153ef166SPaul Zimmerman 
99153ef166SPaul Zimmerman static inline void dwc2_raise_host_irq(DWC2State *s, uint32_t host_intr)
100153ef166SPaul Zimmerman {
101153ef166SPaul Zimmerman     if (!(s->haint & host_intr)) {
102153ef166SPaul Zimmerman         s->haint |= host_intr;
103153ef166SPaul Zimmerman         s->haint &= 0xffff;
104153ef166SPaul Zimmerman         trace_usb_dwc2_raise_host_irq(host_intr);
105153ef166SPaul Zimmerman         if (s->haint & s->haintmsk) {
106153ef166SPaul Zimmerman             dwc2_raise_global_irq(s, GINTSTS_HCHINT);
107153ef166SPaul Zimmerman         }
108153ef166SPaul Zimmerman     }
109153ef166SPaul Zimmerman }
110153ef166SPaul Zimmerman 
111153ef166SPaul Zimmerman static inline void dwc2_lower_host_irq(DWC2State *s, uint32_t host_intr)
112153ef166SPaul Zimmerman {
113153ef166SPaul Zimmerman     if (s->haint & host_intr) {
114153ef166SPaul Zimmerman         s->haint &= ~host_intr;
115153ef166SPaul Zimmerman         trace_usb_dwc2_lower_host_irq(host_intr);
116153ef166SPaul Zimmerman         if (!(s->haint & s->haintmsk)) {
117153ef166SPaul Zimmerman             dwc2_lower_global_irq(s, GINTSTS_HCHINT);
118153ef166SPaul Zimmerman         }
119153ef166SPaul Zimmerman     }
120153ef166SPaul Zimmerman }
121153ef166SPaul Zimmerman 
122153ef166SPaul Zimmerman static inline void dwc2_update_hc_irq(DWC2State *s, int index)
123153ef166SPaul Zimmerman {
124153ef166SPaul Zimmerman     uint32_t host_intr = 1 << (index >> 3);
125153ef166SPaul Zimmerman 
126153ef166SPaul Zimmerman     if (s->hreg1[index + 2] & s->hreg1[index + 3]) {
127153ef166SPaul Zimmerman         dwc2_raise_host_irq(s, host_intr);
128153ef166SPaul Zimmerman     } else {
129153ef166SPaul Zimmerman         dwc2_lower_host_irq(s, host_intr);
130153ef166SPaul Zimmerman     }
131153ef166SPaul Zimmerman }
132153ef166SPaul Zimmerman 
133153ef166SPaul Zimmerman /* set a timer for EOF */
134153ef166SPaul Zimmerman static void dwc2_eof_timer(DWC2State *s)
135153ef166SPaul Zimmerman {
136153ef166SPaul Zimmerman     timer_mod(s->eof_timer, s->sof_time + s->usb_frame_time);
137153ef166SPaul Zimmerman }
138153ef166SPaul Zimmerman 
139153ef166SPaul Zimmerman /* Set a timer for EOF and generate SOF event */
140153ef166SPaul Zimmerman static void dwc2_sof(DWC2State *s)
141153ef166SPaul Zimmerman {
142153ef166SPaul Zimmerman     s->sof_time += s->usb_frame_time;
143153ef166SPaul Zimmerman     trace_usb_dwc2_sof(s->sof_time);
144153ef166SPaul Zimmerman     dwc2_eof_timer(s);
145153ef166SPaul Zimmerman     dwc2_raise_global_irq(s, GINTSTS_SOF);
146153ef166SPaul Zimmerman }
147153ef166SPaul Zimmerman 
148153ef166SPaul Zimmerman /* Do frame processing on frame boundary */
149153ef166SPaul Zimmerman static void dwc2_frame_boundary(void *opaque)
150153ef166SPaul Zimmerman {
151153ef166SPaul Zimmerman     DWC2State *s = opaque;
152153ef166SPaul Zimmerman     int64_t now;
153153ef166SPaul Zimmerman     uint16_t frcnt;
154153ef166SPaul Zimmerman 
155153ef166SPaul Zimmerman     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
156153ef166SPaul Zimmerman 
157153ef166SPaul Zimmerman     /* Frame boundary, so do EOF stuff here */
158153ef166SPaul Zimmerman 
159153ef166SPaul Zimmerman     /* Increment frame number */
160153ef166SPaul Zimmerman     frcnt = (uint16_t)((now - s->sof_time) / s->fi);
161153ef166SPaul Zimmerman     s->frame_number = (s->frame_number + frcnt) & 0xffff;
162153ef166SPaul Zimmerman     s->hfnum = s->frame_number & HFNUM_MAX_FRNUM;
163153ef166SPaul Zimmerman 
164153ef166SPaul Zimmerman     /* Do SOF stuff here */
165153ef166SPaul Zimmerman     dwc2_sof(s);
166153ef166SPaul Zimmerman }
167153ef166SPaul Zimmerman 
168153ef166SPaul Zimmerman /* Start sending SOF tokens on the USB bus */
169153ef166SPaul Zimmerman static void dwc2_bus_start(DWC2State *s)
170153ef166SPaul Zimmerman {
171153ef166SPaul Zimmerman     trace_usb_dwc2_bus_start();
172153ef166SPaul Zimmerman     s->sof_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
173153ef166SPaul Zimmerman     dwc2_eof_timer(s);
174153ef166SPaul Zimmerman }
175153ef166SPaul Zimmerman 
176153ef166SPaul Zimmerman /* Stop sending SOF tokens on the USB bus */
177153ef166SPaul Zimmerman static void dwc2_bus_stop(DWC2State *s)
178153ef166SPaul Zimmerman {
179153ef166SPaul Zimmerman     trace_usb_dwc2_bus_stop();
180153ef166SPaul Zimmerman     timer_del(s->eof_timer);
181153ef166SPaul Zimmerman }
182153ef166SPaul Zimmerman 
183153ef166SPaul Zimmerman static USBDevice *dwc2_find_device(DWC2State *s, uint8_t addr)
184153ef166SPaul Zimmerman {
185153ef166SPaul Zimmerman     USBDevice *dev;
186153ef166SPaul Zimmerman 
187153ef166SPaul Zimmerman     trace_usb_dwc2_find_device(addr);
188153ef166SPaul Zimmerman 
189153ef166SPaul Zimmerman     if (!(s->hprt0 & HPRT0_ENA)) {
190153ef166SPaul Zimmerman         trace_usb_dwc2_port_disabled(0);
191153ef166SPaul Zimmerman     } else {
192153ef166SPaul Zimmerman         dev = usb_find_device(&s->uport, addr);
193153ef166SPaul Zimmerman         if (dev != NULL) {
194153ef166SPaul Zimmerman             trace_usb_dwc2_device_found(0);
195153ef166SPaul Zimmerman             return dev;
196153ef166SPaul Zimmerman         }
197153ef166SPaul Zimmerman     }
198153ef166SPaul Zimmerman 
199153ef166SPaul Zimmerman     trace_usb_dwc2_device_not_found();
200153ef166SPaul Zimmerman     return NULL;
201153ef166SPaul Zimmerman }
202153ef166SPaul Zimmerman 
203153ef166SPaul Zimmerman static const char *pstatus[] = {
204153ef166SPaul Zimmerman     "USB_RET_SUCCESS", "USB_RET_NODEV", "USB_RET_NAK", "USB_RET_STALL",
205153ef166SPaul Zimmerman     "USB_RET_BABBLE", "USB_RET_IOERROR", "USB_RET_ASYNC",
206153ef166SPaul Zimmerman     "USB_RET_ADD_TO_QUEUE", "USB_RET_REMOVE_FROM_QUEUE"
207153ef166SPaul Zimmerman };
208153ef166SPaul Zimmerman 
209153ef166SPaul Zimmerman static uint32_t pintr[] = {
210153ef166SPaul Zimmerman     HCINTMSK_XFERCOMPL, HCINTMSK_XACTERR, HCINTMSK_NAK, HCINTMSK_STALL,
211153ef166SPaul Zimmerman     HCINTMSK_BBLERR, HCINTMSK_XACTERR, HCINTMSK_XACTERR, HCINTMSK_XACTERR,
212153ef166SPaul Zimmerman     HCINTMSK_XACTERR
213153ef166SPaul Zimmerman };
214153ef166SPaul Zimmerman 
215153ef166SPaul Zimmerman static const char *types[] = {
216153ef166SPaul Zimmerman     "Ctrl", "Isoc", "Bulk", "Intr"
217153ef166SPaul Zimmerman };
218153ef166SPaul Zimmerman 
219153ef166SPaul Zimmerman static const char *dirs[] = {
220153ef166SPaul Zimmerman     "Out", "In"
221153ef166SPaul Zimmerman };
222153ef166SPaul Zimmerman 
223153ef166SPaul Zimmerman static void dwc2_handle_packet(DWC2State *s, uint32_t devadr, USBDevice *dev,
224153ef166SPaul Zimmerman                                USBEndpoint *ep, uint32_t index, bool send)
225153ef166SPaul Zimmerman {
226153ef166SPaul Zimmerman     DWC2Packet *p;
227153ef166SPaul Zimmerman     uint32_t hcchar = s->hreg1[index];
228153ef166SPaul Zimmerman     uint32_t hctsiz = s->hreg1[index + 4];
229153ef166SPaul Zimmerman     uint32_t hcdma = s->hreg1[index + 5];
230153ef166SPaul Zimmerman     uint32_t chan, epnum, epdir, eptype, mps, pid, pcnt, len, tlen, intr = 0;
231153ef166SPaul Zimmerman     uint32_t tpcnt, stsidx, actual = 0;
232153ef166SPaul Zimmerman     bool do_intr = false, done = false;
233153ef166SPaul Zimmerman 
234153ef166SPaul Zimmerman     epnum = get_field(hcchar, HCCHAR_EPNUM);
235153ef166SPaul Zimmerman     epdir = get_bit(hcchar, HCCHAR_EPDIR);
236153ef166SPaul Zimmerman     eptype = get_field(hcchar, HCCHAR_EPTYPE);
237153ef166SPaul Zimmerman     mps = get_field(hcchar, HCCHAR_MPS);
238153ef166SPaul Zimmerman     pid = get_field(hctsiz, TSIZ_SC_MC_PID);
239153ef166SPaul Zimmerman     pcnt = get_field(hctsiz, TSIZ_PKTCNT);
240153ef166SPaul Zimmerman     len = get_field(hctsiz, TSIZ_XFERSIZE);
241*69958d8aSPaul Zimmerman     if (len > DWC2_MAX_XFER_SIZE) {
242*69958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR,
243*69958d8aSPaul Zimmerman                       "%s: HCTSIZ transfer size too large\n", __func__);
244*69958d8aSPaul Zimmerman         return;
245*69958d8aSPaul Zimmerman     }
246*69958d8aSPaul Zimmerman 
247153ef166SPaul Zimmerman     chan = index >> 3;
248153ef166SPaul Zimmerman     p = &s->packet[chan];
249153ef166SPaul Zimmerman 
250153ef166SPaul Zimmerman     trace_usb_dwc2_handle_packet(chan, dev, &p->packet, epnum, types[eptype],
251153ef166SPaul Zimmerman                                  dirs[epdir], mps, len, pcnt);
252153ef166SPaul Zimmerman 
253153ef166SPaul Zimmerman     if (eptype == USB_ENDPOINT_XFER_CONTROL && pid == TSIZ_SC_MC_PID_SETUP) {
254153ef166SPaul Zimmerman         pid = USB_TOKEN_SETUP;
255153ef166SPaul Zimmerman     } else {
256153ef166SPaul Zimmerman         pid = epdir ? USB_TOKEN_IN : USB_TOKEN_OUT;
257153ef166SPaul Zimmerman     }
258153ef166SPaul Zimmerman 
259153ef166SPaul Zimmerman     if (send) {
260153ef166SPaul Zimmerman         tlen = len;
261153ef166SPaul Zimmerman         if (p->small) {
262153ef166SPaul Zimmerman             if (tlen > mps) {
263153ef166SPaul Zimmerman                 tlen = mps;
264153ef166SPaul Zimmerman             }
265153ef166SPaul Zimmerman         }
266153ef166SPaul Zimmerman 
267153ef166SPaul Zimmerman         if (pid != USB_TOKEN_IN) {
268153ef166SPaul Zimmerman             trace_usb_dwc2_memory_read(hcdma, tlen);
269153ef166SPaul Zimmerman             if (dma_memory_read(&s->dma_as, hcdma,
270153ef166SPaul Zimmerman                                 s->usb_buf[chan], tlen) != MEMTX_OK) {
271153ef166SPaul Zimmerman                 qemu_log_mask(LOG_GUEST_ERROR, "%s: dma_memory_read failed\n",
272153ef166SPaul Zimmerman                               __func__);
273153ef166SPaul Zimmerman             }
274153ef166SPaul Zimmerman         }
275153ef166SPaul Zimmerman 
276153ef166SPaul Zimmerman         usb_packet_init(&p->packet);
277153ef166SPaul Zimmerman         usb_packet_setup(&p->packet, pid, ep, 0, hcdma,
278153ef166SPaul Zimmerman                          pid != USB_TOKEN_IN, true);
279153ef166SPaul Zimmerman         usb_packet_addbuf(&p->packet, s->usb_buf[chan], tlen);
280153ef166SPaul Zimmerman         p->async = DWC2_ASYNC_NONE;
281153ef166SPaul Zimmerman         usb_handle_packet(dev, &p->packet);
282153ef166SPaul Zimmerman     } else {
283153ef166SPaul Zimmerman         tlen = p->len;
284153ef166SPaul Zimmerman     }
285153ef166SPaul Zimmerman 
286153ef166SPaul Zimmerman     stsidx = -p->packet.status;
287153ef166SPaul Zimmerman     assert(stsidx < sizeof(pstatus) / sizeof(*pstatus));
288153ef166SPaul Zimmerman     actual = p->packet.actual_length;
289153ef166SPaul Zimmerman     trace_usb_dwc2_packet_status(pstatus[stsidx], actual);
290153ef166SPaul Zimmerman 
291153ef166SPaul Zimmerman babble:
292153ef166SPaul Zimmerman     if (p->packet.status != USB_RET_SUCCESS &&
293153ef166SPaul Zimmerman             p->packet.status != USB_RET_NAK &&
294153ef166SPaul Zimmerman             p->packet.status != USB_RET_STALL &&
295153ef166SPaul Zimmerman             p->packet.status != USB_RET_ASYNC) {
296153ef166SPaul Zimmerman         trace_usb_dwc2_packet_error(pstatus[stsidx]);
297153ef166SPaul Zimmerman     }
298153ef166SPaul Zimmerman 
299153ef166SPaul Zimmerman     if (p->packet.status == USB_RET_ASYNC) {
300153ef166SPaul Zimmerman         trace_usb_dwc2_async_packet(&p->packet, chan, dev, epnum,
301153ef166SPaul Zimmerman                                     dirs[epdir], tlen);
302153ef166SPaul Zimmerman         usb_device_flush_ep_queue(dev, ep);
303153ef166SPaul Zimmerman         assert(p->async != DWC2_ASYNC_INFLIGHT);
304153ef166SPaul Zimmerman         p->devadr = devadr;
305153ef166SPaul Zimmerman         p->epnum = epnum;
306153ef166SPaul Zimmerman         p->epdir = epdir;
307153ef166SPaul Zimmerman         p->mps = mps;
308153ef166SPaul Zimmerman         p->pid = pid;
309153ef166SPaul Zimmerman         p->index = index;
310153ef166SPaul Zimmerman         p->pcnt = pcnt;
311153ef166SPaul Zimmerman         p->len = tlen;
312153ef166SPaul Zimmerman         p->async = DWC2_ASYNC_INFLIGHT;
313153ef166SPaul Zimmerman         p->needs_service = false;
314153ef166SPaul Zimmerman         return;
315153ef166SPaul Zimmerman     }
316153ef166SPaul Zimmerman 
317153ef166SPaul Zimmerman     if (p->packet.status == USB_RET_SUCCESS) {
318153ef166SPaul Zimmerman         if (actual > tlen) {
319153ef166SPaul Zimmerman             p->packet.status = USB_RET_BABBLE;
320153ef166SPaul Zimmerman             goto babble;
321153ef166SPaul Zimmerman         }
322153ef166SPaul Zimmerman 
323153ef166SPaul Zimmerman         if (pid == USB_TOKEN_IN) {
324153ef166SPaul Zimmerman             trace_usb_dwc2_memory_write(hcdma, actual);
325153ef166SPaul Zimmerman             if (dma_memory_write(&s->dma_as, hcdma, s->usb_buf[chan],
326153ef166SPaul Zimmerman                                  actual) != MEMTX_OK) {
327153ef166SPaul Zimmerman                 qemu_log_mask(LOG_GUEST_ERROR, "%s: dma_memory_write failed\n",
328153ef166SPaul Zimmerman                               __func__);
329153ef166SPaul Zimmerman             }
330153ef166SPaul Zimmerman         }
331153ef166SPaul Zimmerman 
332153ef166SPaul Zimmerman         tpcnt = actual / mps;
333153ef166SPaul Zimmerman         if (actual % mps) {
334153ef166SPaul Zimmerman             tpcnt++;
335153ef166SPaul Zimmerman             if (pid == USB_TOKEN_IN) {
336153ef166SPaul Zimmerman                 done = true;
337153ef166SPaul Zimmerman             }
338153ef166SPaul Zimmerman         }
339153ef166SPaul Zimmerman 
340153ef166SPaul Zimmerman         pcnt -= tpcnt < pcnt ? tpcnt : pcnt;
341153ef166SPaul Zimmerman         set_field(&hctsiz, pcnt, TSIZ_PKTCNT);
342153ef166SPaul Zimmerman         len -= actual < len ? actual : len;
343153ef166SPaul Zimmerman         set_field(&hctsiz, len, TSIZ_XFERSIZE);
344153ef166SPaul Zimmerman         s->hreg1[index + 4] = hctsiz;
345153ef166SPaul Zimmerman         hcdma += actual;
346153ef166SPaul Zimmerman         s->hreg1[index + 5] = hcdma;
347153ef166SPaul Zimmerman 
348153ef166SPaul Zimmerman         if (!pcnt || len == 0 || actual == 0) {
349153ef166SPaul Zimmerman             done = true;
350153ef166SPaul Zimmerman         }
351153ef166SPaul Zimmerman     } else {
352153ef166SPaul Zimmerman         intr |= pintr[stsidx];
353153ef166SPaul Zimmerman         if (p->packet.status == USB_RET_NAK &&
354153ef166SPaul Zimmerman             (eptype == USB_ENDPOINT_XFER_CONTROL ||
355153ef166SPaul Zimmerman              eptype == USB_ENDPOINT_XFER_BULK)) {
356153ef166SPaul Zimmerman             /*
357153ef166SPaul Zimmerman              * for ctrl/bulk, automatically retry on NAK,
358153ef166SPaul Zimmerman              * but send the interrupt anyway
359153ef166SPaul Zimmerman              */
360153ef166SPaul Zimmerman             intr &= ~HCINTMSK_RESERVED14_31;
361153ef166SPaul Zimmerman             s->hreg1[index + 2] |= intr;
362153ef166SPaul Zimmerman             do_intr = true;
363153ef166SPaul Zimmerman         } else {
364153ef166SPaul Zimmerman             intr |= HCINTMSK_CHHLTD;
365153ef166SPaul Zimmerman             done = true;
366153ef166SPaul Zimmerman         }
367153ef166SPaul Zimmerman     }
368153ef166SPaul Zimmerman 
369153ef166SPaul Zimmerman     usb_packet_cleanup(&p->packet);
370153ef166SPaul Zimmerman 
371153ef166SPaul Zimmerman     if (done) {
372153ef166SPaul Zimmerman         hcchar &= ~HCCHAR_CHENA;
373153ef166SPaul Zimmerman         s->hreg1[index] = hcchar;
374153ef166SPaul Zimmerman         if (!(intr & HCINTMSK_CHHLTD)) {
375153ef166SPaul Zimmerman             intr |= HCINTMSK_CHHLTD | HCINTMSK_XFERCOMPL;
376153ef166SPaul Zimmerman         }
377153ef166SPaul Zimmerman         intr &= ~HCINTMSK_RESERVED14_31;
378153ef166SPaul Zimmerman         s->hreg1[index + 2] |= intr;
379153ef166SPaul Zimmerman         p->needs_service = false;
380153ef166SPaul Zimmerman         trace_usb_dwc2_packet_done(pstatus[stsidx], actual, len, pcnt);
381153ef166SPaul Zimmerman         dwc2_update_hc_irq(s, index);
382153ef166SPaul Zimmerman         return;
383153ef166SPaul Zimmerman     }
384153ef166SPaul Zimmerman 
385153ef166SPaul Zimmerman     p->devadr = devadr;
386153ef166SPaul Zimmerman     p->epnum = epnum;
387153ef166SPaul Zimmerman     p->epdir = epdir;
388153ef166SPaul Zimmerman     p->mps = mps;
389153ef166SPaul Zimmerman     p->pid = pid;
390153ef166SPaul Zimmerman     p->index = index;
391153ef166SPaul Zimmerman     p->pcnt = pcnt;
392153ef166SPaul Zimmerman     p->len = len;
393153ef166SPaul Zimmerman     p->needs_service = true;
394153ef166SPaul Zimmerman     trace_usb_dwc2_packet_next(pstatus[stsidx], len, pcnt);
395153ef166SPaul Zimmerman     if (do_intr) {
396153ef166SPaul Zimmerman         dwc2_update_hc_irq(s, index);
397153ef166SPaul Zimmerman     }
398153ef166SPaul Zimmerman }
399153ef166SPaul Zimmerman 
400153ef166SPaul Zimmerman /* Attach or detach a device on root hub */
401153ef166SPaul Zimmerman 
402153ef166SPaul Zimmerman static const char *speeds[] = {
403153ef166SPaul Zimmerman     "low", "full", "high"
404153ef166SPaul Zimmerman };
405153ef166SPaul Zimmerman 
406153ef166SPaul Zimmerman static void dwc2_attach(USBPort *port)
407153ef166SPaul Zimmerman {
408153ef166SPaul Zimmerman     DWC2State *s = port->opaque;
409153ef166SPaul Zimmerman     int hispd = 0;
410153ef166SPaul Zimmerman 
411153ef166SPaul Zimmerman     trace_usb_dwc2_attach(port);
412153ef166SPaul Zimmerman     assert(port->index == 0);
413153ef166SPaul Zimmerman 
414153ef166SPaul Zimmerman     if (!port->dev || !port->dev->attached) {
415153ef166SPaul Zimmerman         return;
416153ef166SPaul Zimmerman     }
417153ef166SPaul Zimmerman 
418153ef166SPaul Zimmerman     assert(port->dev->speed <= USB_SPEED_HIGH);
419153ef166SPaul Zimmerman     trace_usb_dwc2_attach_speed(speeds[port->dev->speed]);
420153ef166SPaul Zimmerman     s->hprt0 &= ~HPRT0_SPD_MASK;
421153ef166SPaul Zimmerman 
422153ef166SPaul Zimmerman     switch (port->dev->speed) {
423153ef166SPaul Zimmerman     case USB_SPEED_LOW:
424153ef166SPaul Zimmerman         s->hprt0 |= HPRT0_SPD_LOW_SPEED << HPRT0_SPD_SHIFT;
425153ef166SPaul Zimmerman         break;
426153ef166SPaul Zimmerman     case USB_SPEED_FULL:
427153ef166SPaul Zimmerman         s->hprt0 |= HPRT0_SPD_FULL_SPEED << HPRT0_SPD_SHIFT;
428153ef166SPaul Zimmerman         break;
429153ef166SPaul Zimmerman     case USB_SPEED_HIGH:
430153ef166SPaul Zimmerman         s->hprt0 |= HPRT0_SPD_HIGH_SPEED << HPRT0_SPD_SHIFT;
431153ef166SPaul Zimmerman         hispd = 1;
432153ef166SPaul Zimmerman         break;
433153ef166SPaul Zimmerman     }
434153ef166SPaul Zimmerman 
435153ef166SPaul Zimmerman     if (hispd) {
436153ef166SPaul Zimmerman         s->usb_frame_time = NANOSECONDS_PER_SECOND / 8000;        /* 125000 */
437153ef166SPaul Zimmerman         if (NANOSECONDS_PER_SECOND >= USB_HZ_HS) {
438153ef166SPaul Zimmerman             s->usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ_HS; /* 10.4 */
439153ef166SPaul Zimmerman         } else {
440153ef166SPaul Zimmerman             s->usb_bit_time = 1;
441153ef166SPaul Zimmerman         }
442153ef166SPaul Zimmerman     } else {
443153ef166SPaul Zimmerman         s->usb_frame_time = NANOSECONDS_PER_SECOND / 1000;        /* 1000000 */
444153ef166SPaul Zimmerman         if (NANOSECONDS_PER_SECOND >= USB_HZ_FS) {
445153ef166SPaul Zimmerman             s->usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ_FS; /* 83.3 */
446153ef166SPaul Zimmerman         } else {
447153ef166SPaul Zimmerman             s->usb_bit_time = 1;
448153ef166SPaul Zimmerman         }
449153ef166SPaul Zimmerman     }
450153ef166SPaul Zimmerman 
451153ef166SPaul Zimmerman     s->fi = USB_FRMINTVL - 1;
452153ef166SPaul Zimmerman     s->hprt0 |= HPRT0_CONNDET | HPRT0_CONNSTS;
453153ef166SPaul Zimmerman 
454153ef166SPaul Zimmerman     dwc2_bus_start(s);
455153ef166SPaul Zimmerman     dwc2_raise_global_irq(s, GINTSTS_PRTINT);
456153ef166SPaul Zimmerman }
457153ef166SPaul Zimmerman 
458153ef166SPaul Zimmerman static void dwc2_detach(USBPort *port)
459153ef166SPaul Zimmerman {
460153ef166SPaul Zimmerman     DWC2State *s = port->opaque;
461153ef166SPaul Zimmerman 
462153ef166SPaul Zimmerman     trace_usb_dwc2_detach(port);
463153ef166SPaul Zimmerman     assert(port->index == 0);
464153ef166SPaul Zimmerman 
465153ef166SPaul Zimmerman     dwc2_bus_stop(s);
466153ef166SPaul Zimmerman 
467153ef166SPaul Zimmerman     s->hprt0 &= ~(HPRT0_SPD_MASK | HPRT0_SUSP | HPRT0_ENA | HPRT0_CONNSTS);
468153ef166SPaul Zimmerman     s->hprt0 |= HPRT0_CONNDET | HPRT0_ENACHG;
469153ef166SPaul Zimmerman 
470153ef166SPaul Zimmerman     dwc2_raise_global_irq(s, GINTSTS_PRTINT);
471153ef166SPaul Zimmerman }
472153ef166SPaul Zimmerman 
473153ef166SPaul Zimmerman static void dwc2_child_detach(USBPort *port, USBDevice *child)
474153ef166SPaul Zimmerman {
475153ef166SPaul Zimmerman     trace_usb_dwc2_child_detach(port, child);
476153ef166SPaul Zimmerman     assert(port->index == 0);
477153ef166SPaul Zimmerman }
478153ef166SPaul Zimmerman 
479153ef166SPaul Zimmerman static void dwc2_wakeup(USBPort *port)
480153ef166SPaul Zimmerman {
481153ef166SPaul Zimmerman     DWC2State *s = port->opaque;
482153ef166SPaul Zimmerman 
483153ef166SPaul Zimmerman     trace_usb_dwc2_wakeup(port);
484153ef166SPaul Zimmerman     assert(port->index == 0);
485153ef166SPaul Zimmerman 
486153ef166SPaul Zimmerman     if (s->hprt0 & HPRT0_SUSP) {
487153ef166SPaul Zimmerman         s->hprt0 |= HPRT0_RES;
488153ef166SPaul Zimmerman         dwc2_raise_global_irq(s, GINTSTS_PRTINT);
489153ef166SPaul Zimmerman     }
490153ef166SPaul Zimmerman 
491153ef166SPaul Zimmerman     qemu_bh_schedule(s->async_bh);
492153ef166SPaul Zimmerman }
493153ef166SPaul Zimmerman 
494153ef166SPaul Zimmerman static void dwc2_async_packet_complete(USBPort *port, USBPacket *packet)
495153ef166SPaul Zimmerman {
496153ef166SPaul Zimmerman     DWC2State *s = port->opaque;
497153ef166SPaul Zimmerman     DWC2Packet *p;
498153ef166SPaul Zimmerman     USBDevice *dev;
499153ef166SPaul Zimmerman     USBEndpoint *ep;
500153ef166SPaul Zimmerman 
501153ef166SPaul Zimmerman     assert(port->index == 0);
502153ef166SPaul Zimmerman     p = container_of(packet, DWC2Packet, packet);
503153ef166SPaul Zimmerman     dev = dwc2_find_device(s, p->devadr);
504153ef166SPaul Zimmerman     ep = usb_ep_get(dev, p->pid, p->epnum);
505153ef166SPaul Zimmerman     trace_usb_dwc2_async_packet_complete(port, packet, p->index >> 3, dev,
506153ef166SPaul Zimmerman                                          p->epnum, dirs[p->epdir], p->len);
507153ef166SPaul Zimmerman     assert(p->async == DWC2_ASYNC_INFLIGHT);
508153ef166SPaul Zimmerman 
509153ef166SPaul Zimmerman     if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
510153ef166SPaul Zimmerman         usb_cancel_packet(packet);
511153ef166SPaul Zimmerman         usb_packet_cleanup(packet);
512153ef166SPaul Zimmerman         return;
513153ef166SPaul Zimmerman     }
514153ef166SPaul Zimmerman 
515153ef166SPaul Zimmerman     dwc2_handle_packet(s, p->devadr, dev, ep, p->index, false);
516153ef166SPaul Zimmerman 
517153ef166SPaul Zimmerman     p->async = DWC2_ASYNC_FINISHED;
518153ef166SPaul Zimmerman     qemu_bh_schedule(s->async_bh);
519153ef166SPaul Zimmerman }
520153ef166SPaul Zimmerman 
521153ef166SPaul Zimmerman static USBPortOps dwc2_port_ops = {
522153ef166SPaul Zimmerman     .attach = dwc2_attach,
523153ef166SPaul Zimmerman     .detach = dwc2_detach,
524153ef166SPaul Zimmerman     .child_detach = dwc2_child_detach,
525153ef166SPaul Zimmerman     .wakeup = dwc2_wakeup,
526153ef166SPaul Zimmerman     .complete = dwc2_async_packet_complete,
527153ef166SPaul Zimmerman };
528153ef166SPaul Zimmerman 
529153ef166SPaul Zimmerman static uint32_t dwc2_get_frame_remaining(DWC2State *s)
530153ef166SPaul Zimmerman {
531153ef166SPaul Zimmerman     uint32_t fr = 0;
532153ef166SPaul Zimmerman     int64_t tks;
533153ef166SPaul Zimmerman 
534153ef166SPaul Zimmerman     tks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->sof_time;
535153ef166SPaul Zimmerman     if (tks < 0) {
536153ef166SPaul Zimmerman         tks = 0;
537153ef166SPaul Zimmerman     }
538153ef166SPaul Zimmerman 
539153ef166SPaul Zimmerman     /* avoid muldiv if possible */
540153ef166SPaul Zimmerman     if (tks >= s->usb_frame_time) {
541153ef166SPaul Zimmerman         goto out;
542153ef166SPaul Zimmerman     }
543153ef166SPaul Zimmerman     if (tks < s->usb_bit_time) {
544153ef166SPaul Zimmerman         fr = s->fi;
545153ef166SPaul Zimmerman         goto out;
546153ef166SPaul Zimmerman     }
547153ef166SPaul Zimmerman 
548153ef166SPaul Zimmerman     /* tks = number of ns since SOF, divided by 83 (fs) or 10 (hs) */
549153ef166SPaul Zimmerman     tks = tks / s->usb_bit_time;
550153ef166SPaul Zimmerman     if (tks >= (int64_t)s->fi) {
551153ef166SPaul Zimmerman         goto out;
552153ef166SPaul Zimmerman     }
553153ef166SPaul Zimmerman 
554153ef166SPaul Zimmerman     /* remaining = frame interval minus tks */
555153ef166SPaul Zimmerman     fr = (uint32_t)((int64_t)s->fi - tks);
556153ef166SPaul Zimmerman 
557153ef166SPaul Zimmerman out:
558153ef166SPaul Zimmerman     return fr;
559153ef166SPaul Zimmerman }
560153ef166SPaul Zimmerman 
561153ef166SPaul Zimmerman static void dwc2_work_bh(void *opaque)
562153ef166SPaul Zimmerman {
563153ef166SPaul Zimmerman     DWC2State *s = opaque;
564153ef166SPaul Zimmerman     DWC2Packet *p;
565153ef166SPaul Zimmerman     USBDevice *dev;
566153ef166SPaul Zimmerman     USBEndpoint *ep;
567153ef166SPaul Zimmerman     int64_t t_now, expire_time;
568153ef166SPaul Zimmerman     int chan;
569153ef166SPaul Zimmerman     bool found = false;
570153ef166SPaul Zimmerman 
571153ef166SPaul Zimmerman     trace_usb_dwc2_work_bh();
572153ef166SPaul Zimmerman     if (s->working) {
573153ef166SPaul Zimmerman         return;
574153ef166SPaul Zimmerman     }
575153ef166SPaul Zimmerman     s->working = true;
576153ef166SPaul Zimmerman 
577153ef166SPaul Zimmerman     t_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
578153ef166SPaul Zimmerman     chan = s->next_chan;
579153ef166SPaul Zimmerman 
580153ef166SPaul Zimmerman     do {
581153ef166SPaul Zimmerman         p = &s->packet[chan];
582153ef166SPaul Zimmerman         if (p->needs_service) {
583153ef166SPaul Zimmerman             dev = dwc2_find_device(s, p->devadr);
584153ef166SPaul Zimmerman             ep = usb_ep_get(dev, p->pid, p->epnum);
585153ef166SPaul Zimmerman             trace_usb_dwc2_work_bh_service(s->next_chan, chan, dev, p->epnum);
586153ef166SPaul Zimmerman             dwc2_handle_packet(s, p->devadr, dev, ep, p->index, true);
587153ef166SPaul Zimmerman             found = true;
588153ef166SPaul Zimmerman         }
589153ef166SPaul Zimmerman         if (++chan == DWC2_NB_CHAN) {
590153ef166SPaul Zimmerman             chan = 0;
591153ef166SPaul Zimmerman         }
592153ef166SPaul Zimmerman         if (found) {
593153ef166SPaul Zimmerman             s->next_chan = chan;
594153ef166SPaul Zimmerman             trace_usb_dwc2_work_bh_next(chan);
595153ef166SPaul Zimmerman         }
596153ef166SPaul Zimmerman     } while (chan != s->next_chan);
597153ef166SPaul Zimmerman 
598153ef166SPaul Zimmerman     if (found) {
599153ef166SPaul Zimmerman         expire_time = t_now + NANOSECONDS_PER_SECOND / 4000;
600153ef166SPaul Zimmerman         timer_mod(s->frame_timer, expire_time);
601153ef166SPaul Zimmerman     }
602153ef166SPaul Zimmerman     s->working = false;
603153ef166SPaul Zimmerman }
604153ef166SPaul Zimmerman 
605153ef166SPaul Zimmerman static void dwc2_enable_chan(DWC2State *s,  uint32_t index)
606153ef166SPaul Zimmerman {
607153ef166SPaul Zimmerman     USBDevice *dev;
608153ef166SPaul Zimmerman     USBEndpoint *ep;
609153ef166SPaul Zimmerman     uint32_t hcchar;
610153ef166SPaul Zimmerman     uint32_t hctsiz;
611153ef166SPaul Zimmerman     uint32_t devadr, epnum, epdir, eptype, pid, len;
612153ef166SPaul Zimmerman     DWC2Packet *p;
613153ef166SPaul Zimmerman 
614153ef166SPaul Zimmerman     assert((index >> 3) < DWC2_NB_CHAN);
615153ef166SPaul Zimmerman     p = &s->packet[index >> 3];
616153ef166SPaul Zimmerman     hcchar = s->hreg1[index];
617153ef166SPaul Zimmerman     hctsiz = s->hreg1[index + 4];
618153ef166SPaul Zimmerman     devadr = get_field(hcchar, HCCHAR_DEVADDR);
619153ef166SPaul Zimmerman     epnum = get_field(hcchar, HCCHAR_EPNUM);
620153ef166SPaul Zimmerman     epdir = get_bit(hcchar, HCCHAR_EPDIR);
621153ef166SPaul Zimmerman     eptype = get_field(hcchar, HCCHAR_EPTYPE);
622153ef166SPaul Zimmerman     pid = get_field(hctsiz, TSIZ_SC_MC_PID);
623153ef166SPaul Zimmerman     len = get_field(hctsiz, TSIZ_XFERSIZE);
624153ef166SPaul Zimmerman 
625153ef166SPaul Zimmerman     dev = dwc2_find_device(s, devadr);
626153ef166SPaul Zimmerman 
627153ef166SPaul Zimmerman     trace_usb_dwc2_enable_chan(index >> 3, dev, &p->packet, epnum);
628153ef166SPaul Zimmerman     if (dev == NULL) {
629153ef166SPaul Zimmerman         return;
630153ef166SPaul Zimmerman     }
631153ef166SPaul Zimmerman 
632153ef166SPaul Zimmerman     if (eptype == USB_ENDPOINT_XFER_CONTROL && pid == TSIZ_SC_MC_PID_SETUP) {
633153ef166SPaul Zimmerman         pid = USB_TOKEN_SETUP;
634153ef166SPaul Zimmerman     } else {
635153ef166SPaul Zimmerman         pid = epdir ? USB_TOKEN_IN : USB_TOKEN_OUT;
636153ef166SPaul Zimmerman     }
637153ef166SPaul Zimmerman 
638153ef166SPaul Zimmerman     ep = usb_ep_get(dev, pid, epnum);
639153ef166SPaul Zimmerman 
640153ef166SPaul Zimmerman     /*
641153ef166SPaul Zimmerman      * Hack: Networking doesn't like us delivering large transfers, it kind
642153ef166SPaul Zimmerman      * of works but the latency is horrible. So if the transfer is <= the mtu
643153ef166SPaul Zimmerman      * size, we take that as a hint that this might be a network transfer,
644153ef166SPaul Zimmerman      * and do the transfer packet-by-packet.
645153ef166SPaul Zimmerman      */
646153ef166SPaul Zimmerman     if (len > 1536) {
647153ef166SPaul Zimmerman         p->small = false;
648153ef166SPaul Zimmerman     } else {
649153ef166SPaul Zimmerman         p->small = true;
650153ef166SPaul Zimmerman     }
651153ef166SPaul Zimmerman 
652153ef166SPaul Zimmerman     dwc2_handle_packet(s, devadr, dev, ep, index, true);
653153ef166SPaul Zimmerman     qemu_bh_schedule(s->async_bh);
654153ef166SPaul Zimmerman }
655153ef166SPaul Zimmerman 
656153ef166SPaul Zimmerman static const char *glbregnm[] = {
657153ef166SPaul Zimmerman     "GOTGCTL  ", "GOTGINT  ", "GAHBCFG  ", "GUSBCFG  ", "GRSTCTL  ",
658153ef166SPaul Zimmerman     "GINTSTS  ", "GINTMSK  ", "GRXSTSR  ", "GRXSTSP  ", "GRXFSIZ  ",
659153ef166SPaul Zimmerman     "GNPTXFSIZ", "GNPTXSTS ", "GI2CCTL  ", "GPVNDCTL ", "GGPIO    ",
660153ef166SPaul Zimmerman     "GUID     ", "GSNPSID  ", "GHWCFG1  ", "GHWCFG2  ", "GHWCFG3  ",
661153ef166SPaul Zimmerman     "GHWCFG4  ", "GLPMCFG  ", "GPWRDN   ", "GDFIFOCFG", "GADPCTL  ",
662153ef166SPaul Zimmerman     "GREFCLK  ", "GINTMSK2 ", "GINTSTS2 "
663153ef166SPaul Zimmerman };
664153ef166SPaul Zimmerman 
665153ef166SPaul Zimmerman static uint64_t dwc2_glbreg_read(void *ptr, hwaddr addr, int index,
666153ef166SPaul Zimmerman                                  unsigned size)
667153ef166SPaul Zimmerman {
668153ef166SPaul Zimmerman     DWC2State *s = ptr;
669153ef166SPaul Zimmerman     uint32_t val;
670153ef166SPaul Zimmerman 
671*69958d8aSPaul Zimmerman     if (addr > GINTSTS2) {
672*69958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
673*69958d8aSPaul Zimmerman                       __func__, addr);
674*69958d8aSPaul Zimmerman         return 0;
675*69958d8aSPaul Zimmerman     }
676*69958d8aSPaul Zimmerman 
677153ef166SPaul Zimmerman     val = s->glbreg[index];
678153ef166SPaul Zimmerman 
679153ef166SPaul Zimmerman     switch (addr) {
680153ef166SPaul Zimmerman     case GRSTCTL:
681153ef166SPaul Zimmerman         /* clear any self-clearing bits that were set */
682153ef166SPaul Zimmerman         val &= ~(GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH | GRSTCTL_IN_TKNQ_FLSH |
683153ef166SPaul Zimmerman                  GRSTCTL_FRMCNTRRST | GRSTCTL_HSFTRST | GRSTCTL_CSFTRST);
684153ef166SPaul Zimmerman         s->glbreg[index] = val;
685153ef166SPaul Zimmerman         break;
686153ef166SPaul Zimmerman     default:
687153ef166SPaul Zimmerman         break;
688153ef166SPaul Zimmerman     }
689153ef166SPaul Zimmerman 
690153ef166SPaul Zimmerman     trace_usb_dwc2_glbreg_read(addr, glbregnm[index], val);
691153ef166SPaul Zimmerman     return val;
692153ef166SPaul Zimmerman }
693153ef166SPaul Zimmerman 
694153ef166SPaul Zimmerman static void dwc2_glbreg_write(void *ptr, hwaddr addr, int index, uint64_t val,
695153ef166SPaul Zimmerman                               unsigned size)
696153ef166SPaul Zimmerman {
697153ef166SPaul Zimmerman     DWC2State *s = ptr;
698153ef166SPaul Zimmerman     uint64_t orig = val;
699153ef166SPaul Zimmerman     uint32_t *mmio;
700153ef166SPaul Zimmerman     uint32_t old;
701153ef166SPaul Zimmerman     int iflg = 0;
702153ef166SPaul Zimmerman 
703*69958d8aSPaul Zimmerman     if (addr > GINTSTS2) {
704*69958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
705*69958d8aSPaul Zimmerman                       __func__, addr);
706*69958d8aSPaul Zimmerman         return;
707*69958d8aSPaul Zimmerman     }
708*69958d8aSPaul Zimmerman 
709153ef166SPaul Zimmerman     mmio = &s->glbreg[index];
710153ef166SPaul Zimmerman     old = *mmio;
711153ef166SPaul Zimmerman 
712153ef166SPaul Zimmerman     switch (addr) {
713153ef166SPaul Zimmerman     case GOTGCTL:
714153ef166SPaul Zimmerman         /* don't allow setting of read-only bits */
715153ef166SPaul Zimmerman         val &= ~(GOTGCTL_MULT_VALID_BC_MASK | GOTGCTL_BSESVLD |
716153ef166SPaul Zimmerman                  GOTGCTL_ASESVLD | GOTGCTL_DBNC_SHORT | GOTGCTL_CONID_B |
717153ef166SPaul Zimmerman                  GOTGCTL_HSTNEGSCS | GOTGCTL_SESREQSCS);
718153ef166SPaul Zimmerman         /* don't allow clearing of read-only bits */
719153ef166SPaul Zimmerman         val |= old & (GOTGCTL_MULT_VALID_BC_MASK | GOTGCTL_BSESVLD |
720153ef166SPaul Zimmerman                       GOTGCTL_ASESVLD | GOTGCTL_DBNC_SHORT | GOTGCTL_CONID_B |
721153ef166SPaul Zimmerman                       GOTGCTL_HSTNEGSCS | GOTGCTL_SESREQSCS);
722153ef166SPaul Zimmerman         break;
723153ef166SPaul Zimmerman     case GAHBCFG:
724153ef166SPaul Zimmerman         if ((val & GAHBCFG_GLBL_INTR_EN) && !(old & GAHBCFG_GLBL_INTR_EN)) {
725153ef166SPaul Zimmerman             iflg = 1;
726153ef166SPaul Zimmerman         }
727153ef166SPaul Zimmerman         break;
728153ef166SPaul Zimmerman     case GRSTCTL:
729153ef166SPaul Zimmerman         val |= GRSTCTL_AHBIDLE;
730153ef166SPaul Zimmerman         val &= ~GRSTCTL_DMAREQ;
731153ef166SPaul Zimmerman         if (!(old & GRSTCTL_TXFFLSH) && (val & GRSTCTL_TXFFLSH)) {
732153ef166SPaul Zimmerman                 /* TODO - TX fifo flush */
733*69958d8aSPaul Zimmerman             qemu_log_mask(LOG_UNIMP, "%s: Tx FIFO flush not implemented\n",
734*69958d8aSPaul Zimmerman                           __func__);
735153ef166SPaul Zimmerman         }
736153ef166SPaul Zimmerman         if (!(old & GRSTCTL_RXFFLSH) && (val & GRSTCTL_RXFFLSH)) {
737153ef166SPaul Zimmerman                 /* TODO - RX fifo flush */
738*69958d8aSPaul Zimmerman             qemu_log_mask(LOG_UNIMP, "%s: Rx FIFO flush not implemented\n",
739*69958d8aSPaul Zimmerman                           __func__);
740153ef166SPaul Zimmerman         }
741153ef166SPaul Zimmerman         if (!(old & GRSTCTL_IN_TKNQ_FLSH) && (val & GRSTCTL_IN_TKNQ_FLSH)) {
742153ef166SPaul Zimmerman                 /* TODO - device IN token queue flush */
743*69958d8aSPaul Zimmerman             qemu_log_mask(LOG_UNIMP, "%s: Token queue flush not implemented\n",
744*69958d8aSPaul Zimmerman                           __func__);
745153ef166SPaul Zimmerman         }
746153ef166SPaul Zimmerman         if (!(old & GRSTCTL_FRMCNTRRST) && (val & GRSTCTL_FRMCNTRRST)) {
747153ef166SPaul Zimmerman                 /* TODO - host frame counter reset */
748*69958d8aSPaul Zimmerman             qemu_log_mask(LOG_UNIMP,
749*69958d8aSPaul Zimmerman                           "%s: Frame counter reset not implemented\n",
750*69958d8aSPaul Zimmerman                           __func__);
751153ef166SPaul Zimmerman         }
752153ef166SPaul Zimmerman         if (!(old & GRSTCTL_HSFTRST) && (val & GRSTCTL_HSFTRST)) {
753153ef166SPaul Zimmerman                 /* TODO - host soft reset */
754*69958d8aSPaul Zimmerman             qemu_log_mask(LOG_UNIMP, "%s: Host soft reset not implemented\n",
755*69958d8aSPaul Zimmerman                           __func__);
756153ef166SPaul Zimmerman         }
757153ef166SPaul Zimmerman         if (!(old & GRSTCTL_CSFTRST) && (val & GRSTCTL_CSFTRST)) {
758153ef166SPaul Zimmerman                 /* TODO - core soft reset */
759*69958d8aSPaul Zimmerman             qemu_log_mask(LOG_UNIMP, "%s: Core soft reset not implemented\n",
760*69958d8aSPaul Zimmerman                           __func__);
761153ef166SPaul Zimmerman         }
762153ef166SPaul Zimmerman         /* don't allow clearing of self-clearing bits */
763153ef166SPaul Zimmerman         val |= old & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH |
764153ef166SPaul Zimmerman                       GRSTCTL_IN_TKNQ_FLSH | GRSTCTL_FRMCNTRRST |
765153ef166SPaul Zimmerman                       GRSTCTL_HSFTRST | GRSTCTL_CSFTRST);
766153ef166SPaul Zimmerman         break;
767153ef166SPaul Zimmerman     case GINTSTS:
768153ef166SPaul Zimmerman         /* clear the write-1-to-clear bits */
769153ef166SPaul Zimmerman         val |= ~old;
770153ef166SPaul Zimmerman         val = ~val;
771153ef166SPaul Zimmerman         /* don't allow clearing of read-only bits */
772153ef166SPaul Zimmerman         val |= old & (GINTSTS_PTXFEMP | GINTSTS_HCHINT | GINTSTS_PRTINT |
773153ef166SPaul Zimmerman                       GINTSTS_OEPINT | GINTSTS_IEPINT | GINTSTS_GOUTNAKEFF |
774153ef166SPaul Zimmerman                       GINTSTS_GINNAKEFF | GINTSTS_NPTXFEMP | GINTSTS_RXFLVL |
775153ef166SPaul Zimmerman                       GINTSTS_OTGINT | GINTSTS_CURMODE_HOST);
776153ef166SPaul Zimmerman         iflg = 1;
777153ef166SPaul Zimmerman         break;
778153ef166SPaul Zimmerman     case GINTMSK:
779153ef166SPaul Zimmerman         iflg = 1;
780153ef166SPaul Zimmerman         break;
781153ef166SPaul Zimmerman     default:
782153ef166SPaul Zimmerman         break;
783153ef166SPaul Zimmerman     }
784153ef166SPaul Zimmerman 
785153ef166SPaul Zimmerman     trace_usb_dwc2_glbreg_write(addr, glbregnm[index], orig, old, val);
786153ef166SPaul Zimmerman     *mmio = val;
787153ef166SPaul Zimmerman 
788153ef166SPaul Zimmerman     if (iflg) {
789153ef166SPaul Zimmerman         dwc2_update_irq(s);
790153ef166SPaul Zimmerman     }
791153ef166SPaul Zimmerman }
792153ef166SPaul Zimmerman 
793153ef166SPaul Zimmerman static uint64_t dwc2_fszreg_read(void *ptr, hwaddr addr, int index,
794153ef166SPaul Zimmerman                                  unsigned size)
795153ef166SPaul Zimmerman {
796153ef166SPaul Zimmerman     DWC2State *s = ptr;
797153ef166SPaul Zimmerman     uint32_t val;
798153ef166SPaul Zimmerman 
799*69958d8aSPaul Zimmerman     if (addr != HPTXFSIZ) {
800*69958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
801*69958d8aSPaul Zimmerman                       __func__, addr);
802*69958d8aSPaul Zimmerman         return 0;
803*69958d8aSPaul Zimmerman     }
804*69958d8aSPaul Zimmerman 
805153ef166SPaul Zimmerman     val = s->fszreg[index];
806153ef166SPaul Zimmerman 
807153ef166SPaul Zimmerman     trace_usb_dwc2_fszreg_read(addr, val);
808153ef166SPaul Zimmerman     return val;
809153ef166SPaul Zimmerman }
810153ef166SPaul Zimmerman 
811153ef166SPaul Zimmerman static void dwc2_fszreg_write(void *ptr, hwaddr addr, int index, uint64_t val,
812153ef166SPaul Zimmerman                               unsigned size)
813153ef166SPaul Zimmerman {
814153ef166SPaul Zimmerman     DWC2State *s = ptr;
815153ef166SPaul Zimmerman     uint64_t orig = val;
816153ef166SPaul Zimmerman     uint32_t *mmio;
817153ef166SPaul Zimmerman     uint32_t old;
818153ef166SPaul Zimmerman 
819*69958d8aSPaul Zimmerman     if (addr != HPTXFSIZ) {
820*69958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
821*69958d8aSPaul Zimmerman                       __func__, addr);
822*69958d8aSPaul Zimmerman         return;
823*69958d8aSPaul Zimmerman     }
824*69958d8aSPaul Zimmerman 
825153ef166SPaul Zimmerman     mmio = &s->fszreg[index];
826153ef166SPaul Zimmerman     old = *mmio;
827153ef166SPaul Zimmerman 
828153ef166SPaul Zimmerman     trace_usb_dwc2_fszreg_write(addr, orig, old, val);
829153ef166SPaul Zimmerman     *mmio = val;
830153ef166SPaul Zimmerman }
831153ef166SPaul Zimmerman 
832153ef166SPaul Zimmerman static const char *hreg0nm[] = {
833153ef166SPaul Zimmerman     "HCFG     ", "HFIR     ", "HFNUM    ", "<rsvd>   ", "HPTXSTS  ",
834153ef166SPaul Zimmerman     "HAINT    ", "HAINTMSK ", "HFLBADDR ", "<rsvd>   ", "<rsvd>   ",
835153ef166SPaul Zimmerman     "<rsvd>   ", "<rsvd>   ", "<rsvd>   ", "<rsvd>   ", "<rsvd>   ",
836153ef166SPaul Zimmerman     "<rsvd>   ", "HPRT0    "
837153ef166SPaul Zimmerman };
838153ef166SPaul Zimmerman 
839153ef166SPaul Zimmerman static uint64_t dwc2_hreg0_read(void *ptr, hwaddr addr, int index,
840153ef166SPaul Zimmerman                                 unsigned size)
841153ef166SPaul Zimmerman {
842153ef166SPaul Zimmerman     DWC2State *s = ptr;
843153ef166SPaul Zimmerman     uint32_t val;
844153ef166SPaul Zimmerman 
845*69958d8aSPaul Zimmerman     if (addr < HCFG || addr > HPRT0) {
846*69958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
847*69958d8aSPaul Zimmerman                       __func__, addr);
848*69958d8aSPaul Zimmerman         return 0;
849*69958d8aSPaul Zimmerman     }
850*69958d8aSPaul Zimmerman 
851153ef166SPaul Zimmerman     val = s->hreg0[index];
852153ef166SPaul Zimmerman 
853153ef166SPaul Zimmerman     switch (addr) {
854153ef166SPaul Zimmerman     case HFNUM:
855153ef166SPaul Zimmerman         val = (dwc2_get_frame_remaining(s) << HFNUM_FRREM_SHIFT) |
856153ef166SPaul Zimmerman               (s->hfnum << HFNUM_FRNUM_SHIFT);
857153ef166SPaul Zimmerman         break;
858153ef166SPaul Zimmerman     default:
859153ef166SPaul Zimmerman         break;
860153ef166SPaul Zimmerman     }
861153ef166SPaul Zimmerman 
862153ef166SPaul Zimmerman     trace_usb_dwc2_hreg0_read(addr, hreg0nm[index], val);
863153ef166SPaul Zimmerman     return val;
864153ef166SPaul Zimmerman }
865153ef166SPaul Zimmerman 
866153ef166SPaul Zimmerman static void dwc2_hreg0_write(void *ptr, hwaddr addr, int index, uint64_t val,
867153ef166SPaul Zimmerman                              unsigned size)
868153ef166SPaul Zimmerman {
869153ef166SPaul Zimmerman     DWC2State *s = ptr;
870153ef166SPaul Zimmerman     USBDevice *dev = s->uport.dev;
871153ef166SPaul Zimmerman     uint64_t orig = val;
872153ef166SPaul Zimmerman     uint32_t *mmio;
873153ef166SPaul Zimmerman     uint32_t tval, told, old;
874153ef166SPaul Zimmerman     int prst = 0;
875153ef166SPaul Zimmerman     int iflg = 0;
876153ef166SPaul Zimmerman 
877*69958d8aSPaul Zimmerman     if (addr < HCFG || addr > HPRT0) {
878*69958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
879*69958d8aSPaul Zimmerman                       __func__, addr);
880*69958d8aSPaul Zimmerman         return;
881*69958d8aSPaul Zimmerman     }
882*69958d8aSPaul Zimmerman 
883153ef166SPaul Zimmerman     mmio = &s->hreg0[index];
884153ef166SPaul Zimmerman     old = *mmio;
885153ef166SPaul Zimmerman 
886153ef166SPaul Zimmerman     switch (addr) {
887153ef166SPaul Zimmerman     case HFIR:
888153ef166SPaul Zimmerman         break;
889153ef166SPaul Zimmerman     case HFNUM:
890153ef166SPaul Zimmerman     case HPTXSTS:
891153ef166SPaul Zimmerman     case HAINT:
892153ef166SPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: write to read-only register\n",
893153ef166SPaul Zimmerman                       __func__);
894153ef166SPaul Zimmerman         return;
895153ef166SPaul Zimmerman     case HAINTMSK:
896153ef166SPaul Zimmerman         val &= 0xffff;
897153ef166SPaul Zimmerman         break;
898153ef166SPaul Zimmerman     case HPRT0:
899153ef166SPaul Zimmerman         /* don't allow clearing of read-only bits */
900153ef166SPaul Zimmerman         val |= old & (HPRT0_SPD_MASK | HPRT0_LNSTS_MASK | HPRT0_OVRCURRACT |
901153ef166SPaul Zimmerman                       HPRT0_CONNSTS);
902153ef166SPaul Zimmerman         /* don't allow clearing of self-clearing bits */
903153ef166SPaul Zimmerman         val |= old & (HPRT0_SUSP | HPRT0_RES);
904153ef166SPaul Zimmerman         /* don't allow setting of self-setting bits */
905153ef166SPaul Zimmerman         if (!(old & HPRT0_ENA) && (val & HPRT0_ENA)) {
906153ef166SPaul Zimmerman             val &= ~HPRT0_ENA;
907153ef166SPaul Zimmerman         }
908153ef166SPaul Zimmerman         /* clear the write-1-to-clear bits */
909153ef166SPaul Zimmerman         tval = val & (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA |
910153ef166SPaul Zimmerman                       HPRT0_CONNDET);
911153ef166SPaul Zimmerman         told = old & (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA |
912153ef166SPaul Zimmerman                       HPRT0_CONNDET);
913153ef166SPaul Zimmerman         tval |= ~told;
914153ef166SPaul Zimmerman         tval = ~tval;
915153ef166SPaul Zimmerman         tval &= (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA |
916153ef166SPaul Zimmerman                  HPRT0_CONNDET);
917153ef166SPaul Zimmerman         val &= ~(HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA |
918153ef166SPaul Zimmerman                  HPRT0_CONNDET);
919153ef166SPaul Zimmerman         val |= tval;
920153ef166SPaul Zimmerman         if (!(val & HPRT0_RST) && (old & HPRT0_RST)) {
921153ef166SPaul Zimmerman             if (dev && dev->attached) {
922153ef166SPaul Zimmerman                 val |= HPRT0_ENA | HPRT0_ENACHG;
923153ef166SPaul Zimmerman                 prst = 1;
924153ef166SPaul Zimmerman             }
925153ef166SPaul Zimmerman         }
926153ef166SPaul Zimmerman         if (val & (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_CONNDET)) {
927153ef166SPaul Zimmerman             iflg = 1;
928153ef166SPaul Zimmerman         } else {
929153ef166SPaul Zimmerman             iflg = -1;
930153ef166SPaul Zimmerman         }
931153ef166SPaul Zimmerman         break;
932153ef166SPaul Zimmerman     default:
933153ef166SPaul Zimmerman         break;
934153ef166SPaul Zimmerman     }
935153ef166SPaul Zimmerman 
936153ef166SPaul Zimmerman     if (prst) {
937153ef166SPaul Zimmerman         trace_usb_dwc2_hreg0_write(addr, hreg0nm[index], orig, old,
938153ef166SPaul Zimmerman                                    val & ~HPRT0_CONNDET);
939153ef166SPaul Zimmerman         trace_usb_dwc2_hreg0_action("call usb_port_reset");
940153ef166SPaul Zimmerman         usb_port_reset(&s->uport);
941153ef166SPaul Zimmerman         val &= ~HPRT0_CONNDET;
942153ef166SPaul Zimmerman     } else {
943153ef166SPaul Zimmerman         trace_usb_dwc2_hreg0_write(addr, hreg0nm[index], orig, old, val);
944153ef166SPaul Zimmerman     }
945153ef166SPaul Zimmerman 
946153ef166SPaul Zimmerman     *mmio = val;
947153ef166SPaul Zimmerman 
948153ef166SPaul Zimmerman     if (iflg > 0) {
949153ef166SPaul Zimmerman         trace_usb_dwc2_hreg0_action("enable PRTINT");
950153ef166SPaul Zimmerman         dwc2_raise_global_irq(s, GINTSTS_PRTINT);
951153ef166SPaul Zimmerman     } else if (iflg < 0) {
952153ef166SPaul Zimmerman         trace_usb_dwc2_hreg0_action("disable PRTINT");
953153ef166SPaul Zimmerman         dwc2_lower_global_irq(s, GINTSTS_PRTINT);
954153ef166SPaul Zimmerman     }
955153ef166SPaul Zimmerman }
956153ef166SPaul Zimmerman 
957153ef166SPaul Zimmerman static const char *hreg1nm[] = {
958153ef166SPaul Zimmerman     "HCCHAR  ", "HCSPLT  ", "HCINT   ", "HCINTMSK", "HCTSIZ  ", "HCDMA   ",
959153ef166SPaul Zimmerman     "<rsvd>  ", "HCDMAB  "
960153ef166SPaul Zimmerman };
961153ef166SPaul Zimmerman 
962153ef166SPaul Zimmerman static uint64_t dwc2_hreg1_read(void *ptr, hwaddr addr, int index,
963153ef166SPaul Zimmerman                                 unsigned size)
964153ef166SPaul Zimmerman {
965153ef166SPaul Zimmerman     DWC2State *s = ptr;
966153ef166SPaul Zimmerman     uint32_t val;
967153ef166SPaul Zimmerman 
968*69958d8aSPaul Zimmerman     if (addr < HCCHAR(0) || addr > HCDMAB(DWC2_NB_CHAN - 1)) {
969*69958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
970*69958d8aSPaul Zimmerman                       __func__, addr);
971*69958d8aSPaul Zimmerman         return 0;
972*69958d8aSPaul Zimmerman     }
973*69958d8aSPaul Zimmerman 
974153ef166SPaul Zimmerman     val = s->hreg1[index];
975153ef166SPaul Zimmerman 
976153ef166SPaul Zimmerman     trace_usb_dwc2_hreg1_read(addr, hreg1nm[index & 7], addr >> 5, val);
977153ef166SPaul Zimmerman     return val;
978153ef166SPaul Zimmerman }
979153ef166SPaul Zimmerman 
980153ef166SPaul Zimmerman static void dwc2_hreg1_write(void *ptr, hwaddr addr, int index, uint64_t val,
981153ef166SPaul Zimmerman                              unsigned size)
982153ef166SPaul Zimmerman {
983153ef166SPaul Zimmerman     DWC2State *s = ptr;
984153ef166SPaul Zimmerman     uint64_t orig = val;
985153ef166SPaul Zimmerman     uint32_t *mmio;
986153ef166SPaul Zimmerman     uint32_t old;
987153ef166SPaul Zimmerman     int iflg = 0;
988153ef166SPaul Zimmerman     int enflg = 0;
989153ef166SPaul Zimmerman     int disflg = 0;
990153ef166SPaul Zimmerman 
991*69958d8aSPaul Zimmerman     if (addr < HCCHAR(0) || addr > HCDMAB(DWC2_NB_CHAN - 1)) {
992*69958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
993*69958d8aSPaul Zimmerman                       __func__, addr);
994*69958d8aSPaul Zimmerman         return;
995*69958d8aSPaul Zimmerman     }
996*69958d8aSPaul Zimmerman 
997153ef166SPaul Zimmerman     mmio = &s->hreg1[index];
998153ef166SPaul Zimmerman     old = *mmio;
999153ef166SPaul Zimmerman 
1000153ef166SPaul Zimmerman     switch (HSOTG_REG(0x500) + (addr & 0x1c)) {
1001153ef166SPaul Zimmerman     case HCCHAR(0):
1002153ef166SPaul Zimmerman         if ((val & HCCHAR_CHDIS) && !(old & HCCHAR_CHDIS)) {
1003153ef166SPaul Zimmerman             val &= ~(HCCHAR_CHENA | HCCHAR_CHDIS);
1004153ef166SPaul Zimmerman             disflg = 1;
1005153ef166SPaul Zimmerman         } else {
1006153ef166SPaul Zimmerman             val |= old & HCCHAR_CHDIS;
1007153ef166SPaul Zimmerman             if ((val & HCCHAR_CHENA) && !(old & HCCHAR_CHENA)) {
1008153ef166SPaul Zimmerman                 val &= ~HCCHAR_CHDIS;
1009153ef166SPaul Zimmerman                 enflg = 1;
1010153ef166SPaul Zimmerman             } else {
1011153ef166SPaul Zimmerman                 val |= old & HCCHAR_CHENA;
1012153ef166SPaul Zimmerman             }
1013153ef166SPaul Zimmerman         }
1014153ef166SPaul Zimmerman         break;
1015153ef166SPaul Zimmerman     case HCINT(0):
1016153ef166SPaul Zimmerman         /* clear the write-1-to-clear bits */
1017153ef166SPaul Zimmerman         val |= ~old;
1018153ef166SPaul Zimmerman         val = ~val;
1019153ef166SPaul Zimmerman         val &= ~HCINTMSK_RESERVED14_31;
1020153ef166SPaul Zimmerman         iflg = 1;
1021153ef166SPaul Zimmerman         break;
1022153ef166SPaul Zimmerman     case HCINTMSK(0):
1023153ef166SPaul Zimmerman         val &= ~HCINTMSK_RESERVED14_31;
1024153ef166SPaul Zimmerman         iflg = 1;
1025153ef166SPaul Zimmerman         break;
1026153ef166SPaul Zimmerman     case HCDMAB(0):
1027153ef166SPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: write to read-only register\n",
1028153ef166SPaul Zimmerman                       __func__);
1029153ef166SPaul Zimmerman         return;
1030153ef166SPaul Zimmerman     default:
1031153ef166SPaul Zimmerman         break;
1032153ef166SPaul Zimmerman     }
1033153ef166SPaul Zimmerman 
1034153ef166SPaul Zimmerman     trace_usb_dwc2_hreg1_write(addr, hreg1nm[index & 7], index >> 3, orig,
1035153ef166SPaul Zimmerman                                old, val);
1036153ef166SPaul Zimmerman     *mmio = val;
1037153ef166SPaul Zimmerman 
1038153ef166SPaul Zimmerman     if (disflg) {
1039153ef166SPaul Zimmerman         /* set ChHltd in HCINT */
1040153ef166SPaul Zimmerman         s->hreg1[(index & ~7) + 2] |= HCINTMSK_CHHLTD;
1041153ef166SPaul Zimmerman         iflg = 1;
1042153ef166SPaul Zimmerman     }
1043153ef166SPaul Zimmerman 
1044153ef166SPaul Zimmerman     if (enflg) {
1045153ef166SPaul Zimmerman         dwc2_enable_chan(s, index & ~7);
1046153ef166SPaul Zimmerman     }
1047153ef166SPaul Zimmerman 
1048153ef166SPaul Zimmerman     if (iflg) {
1049153ef166SPaul Zimmerman         dwc2_update_hc_irq(s, index & ~7);
1050153ef166SPaul Zimmerman     }
1051153ef166SPaul Zimmerman }
1052153ef166SPaul Zimmerman 
1053153ef166SPaul Zimmerman static const char *pcgregnm[] = {
1054153ef166SPaul Zimmerman         "PCGCTL   ", "PCGCCTL1 "
1055153ef166SPaul Zimmerman };
1056153ef166SPaul Zimmerman 
1057153ef166SPaul Zimmerman static uint64_t dwc2_pcgreg_read(void *ptr, hwaddr addr, int index,
1058153ef166SPaul Zimmerman                                  unsigned size)
1059153ef166SPaul Zimmerman {
1060153ef166SPaul Zimmerman     DWC2State *s = ptr;
1061153ef166SPaul Zimmerman     uint32_t val;
1062153ef166SPaul Zimmerman 
1063*69958d8aSPaul Zimmerman     if (addr < PCGCTL || addr > PCGCCTL1) {
1064*69958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
1065*69958d8aSPaul Zimmerman                       __func__, addr);
1066*69958d8aSPaul Zimmerman         return 0;
1067*69958d8aSPaul Zimmerman     }
1068*69958d8aSPaul Zimmerman 
1069153ef166SPaul Zimmerman     val = s->pcgreg[index];
1070153ef166SPaul Zimmerman 
1071153ef166SPaul Zimmerman     trace_usb_dwc2_pcgreg_read(addr, pcgregnm[index], val);
1072153ef166SPaul Zimmerman     return val;
1073153ef166SPaul Zimmerman }
1074153ef166SPaul Zimmerman 
1075153ef166SPaul Zimmerman static void dwc2_pcgreg_write(void *ptr, hwaddr addr, int index,
1076153ef166SPaul Zimmerman                               uint64_t val, unsigned size)
1077153ef166SPaul Zimmerman {
1078153ef166SPaul Zimmerman     DWC2State *s = ptr;
1079153ef166SPaul Zimmerman     uint64_t orig = val;
1080153ef166SPaul Zimmerman     uint32_t *mmio;
1081153ef166SPaul Zimmerman     uint32_t old;
1082153ef166SPaul Zimmerman 
1083*69958d8aSPaul Zimmerman     if (addr < PCGCTL || addr > PCGCCTL1) {
1084*69958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
1085*69958d8aSPaul Zimmerman                       __func__, addr);
1086*69958d8aSPaul Zimmerman         return;
1087*69958d8aSPaul Zimmerman     }
1088*69958d8aSPaul Zimmerman 
1089153ef166SPaul Zimmerman     mmio = &s->pcgreg[index];
1090153ef166SPaul Zimmerman     old = *mmio;
1091153ef166SPaul Zimmerman 
1092153ef166SPaul Zimmerman     trace_usb_dwc2_pcgreg_write(addr, pcgregnm[index], orig, old, val);
1093153ef166SPaul Zimmerman     *mmio = val;
1094153ef166SPaul Zimmerman }
1095153ef166SPaul Zimmerman 
1096153ef166SPaul Zimmerman static uint64_t dwc2_hsotg_read(void *ptr, hwaddr addr, unsigned size)
1097153ef166SPaul Zimmerman {
1098153ef166SPaul Zimmerman     uint64_t val;
1099153ef166SPaul Zimmerman 
1100153ef166SPaul Zimmerman     switch (addr) {
1101153ef166SPaul Zimmerman     case HSOTG_REG(0x000) ... HSOTG_REG(0x0fc):
1102153ef166SPaul Zimmerman         val = dwc2_glbreg_read(ptr, addr, (addr - HSOTG_REG(0x000)) >> 2, size);
1103153ef166SPaul Zimmerman         break;
1104153ef166SPaul Zimmerman     case HSOTG_REG(0x100):
1105153ef166SPaul Zimmerman         val = dwc2_fszreg_read(ptr, addr, (addr - HSOTG_REG(0x100)) >> 2, size);
1106153ef166SPaul Zimmerman         break;
1107153ef166SPaul Zimmerman     case HSOTG_REG(0x104) ... HSOTG_REG(0x3fc):
1108153ef166SPaul Zimmerman         /* Gadget-mode registers, just return 0 for now */
1109153ef166SPaul Zimmerman         val = 0;
1110153ef166SPaul Zimmerman         break;
1111153ef166SPaul Zimmerman     case HSOTG_REG(0x400) ... HSOTG_REG(0x4fc):
1112153ef166SPaul Zimmerman         val = dwc2_hreg0_read(ptr, addr, (addr - HSOTG_REG(0x400)) >> 2, size);
1113153ef166SPaul Zimmerman         break;
1114153ef166SPaul Zimmerman     case HSOTG_REG(0x500) ... HSOTG_REG(0x7fc):
1115153ef166SPaul Zimmerman         val = dwc2_hreg1_read(ptr, addr, (addr - HSOTG_REG(0x500)) >> 2, size);
1116153ef166SPaul Zimmerman         break;
1117153ef166SPaul Zimmerman     case HSOTG_REG(0x800) ... HSOTG_REG(0xdfc):
1118153ef166SPaul Zimmerman         /* Gadget-mode registers, just return 0 for now */
1119153ef166SPaul Zimmerman         val = 0;
1120153ef166SPaul Zimmerman         break;
1121153ef166SPaul Zimmerman     case HSOTG_REG(0xe00) ... HSOTG_REG(0xffc):
1122153ef166SPaul Zimmerman         val = dwc2_pcgreg_read(ptr, addr, (addr - HSOTG_REG(0xe00)) >> 2, size);
1123153ef166SPaul Zimmerman         break;
1124153ef166SPaul Zimmerman     default:
1125153ef166SPaul Zimmerman         g_assert_not_reached();
1126153ef166SPaul Zimmerman     }
1127153ef166SPaul Zimmerman 
1128153ef166SPaul Zimmerman     return val;
1129153ef166SPaul Zimmerman }
1130153ef166SPaul Zimmerman 
1131153ef166SPaul Zimmerman static void dwc2_hsotg_write(void *ptr, hwaddr addr, uint64_t val,
1132153ef166SPaul Zimmerman                              unsigned size)
1133153ef166SPaul Zimmerman {
1134153ef166SPaul Zimmerman     switch (addr) {
1135153ef166SPaul Zimmerman     case HSOTG_REG(0x000) ... HSOTG_REG(0x0fc):
1136153ef166SPaul Zimmerman         dwc2_glbreg_write(ptr, addr, (addr - HSOTG_REG(0x000)) >> 2, val, size);
1137153ef166SPaul Zimmerman         break;
1138153ef166SPaul Zimmerman     case HSOTG_REG(0x100):
1139153ef166SPaul Zimmerman         dwc2_fszreg_write(ptr, addr, (addr - HSOTG_REG(0x100)) >> 2, val, size);
1140153ef166SPaul Zimmerman         break;
1141153ef166SPaul Zimmerman     case HSOTG_REG(0x104) ... HSOTG_REG(0x3fc):
1142153ef166SPaul Zimmerman         /* Gadget-mode registers, do nothing for now */
1143153ef166SPaul Zimmerman         break;
1144153ef166SPaul Zimmerman     case HSOTG_REG(0x400) ... HSOTG_REG(0x4fc):
1145153ef166SPaul Zimmerman         dwc2_hreg0_write(ptr, addr, (addr - HSOTG_REG(0x400)) >> 2, val, size);
1146153ef166SPaul Zimmerman         break;
1147153ef166SPaul Zimmerman     case HSOTG_REG(0x500) ... HSOTG_REG(0x7fc):
1148153ef166SPaul Zimmerman         dwc2_hreg1_write(ptr, addr, (addr - HSOTG_REG(0x500)) >> 2, val, size);
1149153ef166SPaul Zimmerman         break;
1150153ef166SPaul Zimmerman     case HSOTG_REG(0x800) ... HSOTG_REG(0xdfc):
1151153ef166SPaul Zimmerman         /* Gadget-mode registers, do nothing for now */
1152153ef166SPaul Zimmerman         break;
1153153ef166SPaul Zimmerman     case HSOTG_REG(0xe00) ... HSOTG_REG(0xffc):
1154153ef166SPaul Zimmerman         dwc2_pcgreg_write(ptr, addr, (addr - HSOTG_REG(0xe00)) >> 2, val, size);
1155153ef166SPaul Zimmerman         break;
1156153ef166SPaul Zimmerman     default:
1157153ef166SPaul Zimmerman         g_assert_not_reached();
1158153ef166SPaul Zimmerman     }
1159153ef166SPaul Zimmerman }
1160153ef166SPaul Zimmerman 
1161153ef166SPaul Zimmerman static const MemoryRegionOps dwc2_mmio_hsotg_ops = {
1162153ef166SPaul Zimmerman     .read = dwc2_hsotg_read,
1163153ef166SPaul Zimmerman     .write = dwc2_hsotg_write,
1164153ef166SPaul Zimmerman     .impl.min_access_size = 4,
1165153ef166SPaul Zimmerman     .impl.max_access_size = 4,
1166153ef166SPaul Zimmerman     .endianness = DEVICE_LITTLE_ENDIAN,
1167153ef166SPaul Zimmerman };
1168153ef166SPaul Zimmerman 
1169153ef166SPaul Zimmerman static uint64_t dwc2_hreg2_read(void *ptr, hwaddr addr, unsigned size)
1170153ef166SPaul Zimmerman {
1171153ef166SPaul Zimmerman     /* TODO - implement FIFOs to support slave mode */
1172153ef166SPaul Zimmerman     trace_usb_dwc2_hreg2_read(addr, addr >> 12, 0);
1173*69958d8aSPaul Zimmerman     qemu_log_mask(LOG_UNIMP, "%s: FIFO read not implemented\n", __func__);
1174153ef166SPaul Zimmerman     return 0;
1175153ef166SPaul Zimmerman }
1176153ef166SPaul Zimmerman 
1177153ef166SPaul Zimmerman static void dwc2_hreg2_write(void *ptr, hwaddr addr, uint64_t val,
1178153ef166SPaul Zimmerman                              unsigned size)
1179153ef166SPaul Zimmerman {
1180153ef166SPaul Zimmerman     uint64_t orig = val;
1181153ef166SPaul Zimmerman 
1182153ef166SPaul Zimmerman     /* TODO - implement FIFOs to support slave mode */
1183153ef166SPaul Zimmerman     trace_usb_dwc2_hreg2_write(addr, addr >> 12, orig, 0, val);
1184*69958d8aSPaul Zimmerman     qemu_log_mask(LOG_UNIMP, "%s: FIFO write not implemented\n", __func__);
1185153ef166SPaul Zimmerman }
1186153ef166SPaul Zimmerman 
1187153ef166SPaul Zimmerman static const MemoryRegionOps dwc2_mmio_hreg2_ops = {
1188153ef166SPaul Zimmerman     .read = dwc2_hreg2_read,
1189153ef166SPaul Zimmerman     .write = dwc2_hreg2_write,
1190153ef166SPaul Zimmerman     .impl.min_access_size = 4,
1191153ef166SPaul Zimmerman     .impl.max_access_size = 4,
1192153ef166SPaul Zimmerman     .endianness = DEVICE_LITTLE_ENDIAN,
1193153ef166SPaul Zimmerman };
1194153ef166SPaul Zimmerman 
1195153ef166SPaul Zimmerman static void dwc2_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
1196153ef166SPaul Zimmerman                                  unsigned int stream)
1197153ef166SPaul Zimmerman {
1198153ef166SPaul Zimmerman     DWC2State *s = container_of(bus, DWC2State, bus);
1199153ef166SPaul Zimmerman 
1200153ef166SPaul Zimmerman     trace_usb_dwc2_wakeup_endpoint(ep, stream);
1201153ef166SPaul Zimmerman 
1202153ef166SPaul Zimmerman     /* TODO - do something here? */
1203153ef166SPaul Zimmerman     qemu_bh_schedule(s->async_bh);
1204153ef166SPaul Zimmerman }
1205153ef166SPaul Zimmerman 
1206153ef166SPaul Zimmerman static USBBusOps dwc2_bus_ops = {
1207153ef166SPaul Zimmerman     .wakeup_endpoint = dwc2_wakeup_endpoint,
1208153ef166SPaul Zimmerman };
1209153ef166SPaul Zimmerman 
1210153ef166SPaul Zimmerman static void dwc2_work_timer(void *opaque)
1211153ef166SPaul Zimmerman {
1212153ef166SPaul Zimmerman     DWC2State *s = opaque;
1213153ef166SPaul Zimmerman 
1214153ef166SPaul Zimmerman     trace_usb_dwc2_work_timer();
1215153ef166SPaul Zimmerman     qemu_bh_schedule(s->async_bh);
1216153ef166SPaul Zimmerman }
1217153ef166SPaul Zimmerman 
1218153ef166SPaul Zimmerman static void dwc2_reset_enter(Object *obj, ResetType type)
1219153ef166SPaul Zimmerman {
122079f6cf7eSEduardo Habkost     DWC2Class *c = DWC2_USB_GET_CLASS(obj);
1221153ef166SPaul Zimmerman     DWC2State *s = DWC2_USB(obj);
1222153ef166SPaul Zimmerman     int i;
1223153ef166SPaul Zimmerman 
1224153ef166SPaul Zimmerman     trace_usb_dwc2_reset_enter();
1225153ef166SPaul Zimmerman 
1226153ef166SPaul Zimmerman     if (c->parent_phases.enter) {
1227153ef166SPaul Zimmerman         c->parent_phases.enter(obj, type);
1228153ef166SPaul Zimmerman     }
1229153ef166SPaul Zimmerman 
1230153ef166SPaul Zimmerman     timer_del(s->frame_timer);
1231153ef166SPaul Zimmerman     qemu_bh_cancel(s->async_bh);
1232153ef166SPaul Zimmerman 
1233153ef166SPaul Zimmerman     if (s->uport.dev && s->uport.dev->attached) {
1234153ef166SPaul Zimmerman         usb_detach(&s->uport);
1235153ef166SPaul Zimmerman     }
1236153ef166SPaul Zimmerman 
1237153ef166SPaul Zimmerman     dwc2_bus_stop(s);
1238153ef166SPaul Zimmerman 
1239153ef166SPaul Zimmerman     s->gotgctl = GOTGCTL_BSESVLD | GOTGCTL_ASESVLD | GOTGCTL_CONID_B;
1240153ef166SPaul Zimmerman     s->gotgint = 0;
1241153ef166SPaul Zimmerman     s->gahbcfg = 0;
1242153ef166SPaul Zimmerman     s->gusbcfg = 5 << GUSBCFG_USBTRDTIM_SHIFT;
1243153ef166SPaul Zimmerman     s->grstctl = GRSTCTL_AHBIDLE;
1244153ef166SPaul Zimmerman     s->gintsts = GINTSTS_CONIDSTSCHNG | GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP |
1245153ef166SPaul Zimmerman                  GINTSTS_CURMODE_HOST;
1246153ef166SPaul Zimmerman     s->gintmsk = 0;
1247153ef166SPaul Zimmerman     s->grxstsr = 0;
1248153ef166SPaul Zimmerman     s->grxstsp = 0;
1249153ef166SPaul Zimmerman     s->grxfsiz = 1024;
1250153ef166SPaul Zimmerman     s->gnptxfsiz = 1024 << FIFOSIZE_DEPTH_SHIFT;
1251153ef166SPaul Zimmerman     s->gnptxsts = (4 << FIFOSIZE_DEPTH_SHIFT) | 1024;
1252153ef166SPaul Zimmerman     s->gi2cctl = GI2CCTL_I2CDATSE0 | GI2CCTL_ACK;
1253153ef166SPaul Zimmerman     s->gpvndctl = 0;
1254153ef166SPaul Zimmerman     s->ggpio = 0;
1255153ef166SPaul Zimmerman     s->guid = 0;
1256153ef166SPaul Zimmerman     s->gsnpsid = 0x4f54294a;
1257153ef166SPaul Zimmerman     s->ghwcfg1 = 0;
1258153ef166SPaul Zimmerman     s->ghwcfg2 = (8 << GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT) |
1259153ef166SPaul Zimmerman                  (4 << GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT) |
1260153ef166SPaul Zimmerman                  (4 << GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT) |
1261153ef166SPaul Zimmerman                  GHWCFG2_DYNAMIC_FIFO |
1262153ef166SPaul Zimmerman                  GHWCFG2_PERIO_EP_SUPPORTED |
1263153ef166SPaul Zimmerman                  ((DWC2_NB_CHAN - 1) << GHWCFG2_NUM_HOST_CHAN_SHIFT) |
1264153ef166SPaul Zimmerman                  (GHWCFG2_INT_DMA_ARCH << GHWCFG2_ARCHITECTURE_SHIFT) |
1265153ef166SPaul Zimmerman                  (GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST << GHWCFG2_OP_MODE_SHIFT);
1266153ef166SPaul Zimmerman     s->ghwcfg3 = (4096 << GHWCFG3_DFIFO_DEPTH_SHIFT) |
1267153ef166SPaul Zimmerman                  (4 << GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT) |
1268153ef166SPaul Zimmerman                  (4 << GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT);
1269153ef166SPaul Zimmerman     s->ghwcfg4 = 0;
1270153ef166SPaul Zimmerman     s->glpmcfg = 0;
1271153ef166SPaul Zimmerman     s->gpwrdn = GPWRDN_PWRDNRSTN;
1272153ef166SPaul Zimmerman     s->gdfifocfg = 0;
1273153ef166SPaul Zimmerman     s->gadpctl = 0;
1274153ef166SPaul Zimmerman     s->grefclk = 0;
1275153ef166SPaul Zimmerman     s->gintmsk2 = 0;
1276153ef166SPaul Zimmerman     s->gintsts2 = 0;
1277153ef166SPaul Zimmerman 
1278153ef166SPaul Zimmerman     s->hptxfsiz = 500 << FIFOSIZE_DEPTH_SHIFT;
1279153ef166SPaul Zimmerman 
1280153ef166SPaul Zimmerman     s->hcfg = 2 << HCFG_RESVALID_SHIFT;
1281153ef166SPaul Zimmerman     s->hfir = 60000;
1282153ef166SPaul Zimmerman     s->hfnum = 0x3fff;
1283153ef166SPaul Zimmerman     s->hptxsts = (16 << TXSTS_QSPCAVAIL_SHIFT) | 32768;
1284153ef166SPaul Zimmerman     s->haint = 0;
1285153ef166SPaul Zimmerman     s->haintmsk = 0;
1286153ef166SPaul Zimmerman     s->hprt0 = 0;
1287153ef166SPaul Zimmerman 
1288153ef166SPaul Zimmerman     memset(s->hreg1, 0, sizeof(s->hreg1));
1289153ef166SPaul Zimmerman     memset(s->pcgreg, 0, sizeof(s->pcgreg));
1290153ef166SPaul Zimmerman 
1291153ef166SPaul Zimmerman     s->sof_time = 0;
1292153ef166SPaul Zimmerman     s->frame_number = 0;
1293153ef166SPaul Zimmerman     s->fi = USB_FRMINTVL - 1;
1294153ef166SPaul Zimmerman     s->next_chan = 0;
1295153ef166SPaul Zimmerman     s->working = false;
1296153ef166SPaul Zimmerman 
1297153ef166SPaul Zimmerman     for (i = 0; i < DWC2_NB_CHAN; i++) {
1298153ef166SPaul Zimmerman         s->packet[i].needs_service = false;
1299153ef166SPaul Zimmerman     }
1300153ef166SPaul Zimmerman }
1301153ef166SPaul Zimmerman 
1302153ef166SPaul Zimmerman static void dwc2_reset_hold(Object *obj)
1303153ef166SPaul Zimmerman {
130479f6cf7eSEduardo Habkost     DWC2Class *c = DWC2_USB_GET_CLASS(obj);
1305153ef166SPaul Zimmerman     DWC2State *s = DWC2_USB(obj);
1306153ef166SPaul Zimmerman 
1307153ef166SPaul Zimmerman     trace_usb_dwc2_reset_hold();
1308153ef166SPaul Zimmerman 
1309153ef166SPaul Zimmerman     if (c->parent_phases.hold) {
1310153ef166SPaul Zimmerman         c->parent_phases.hold(obj);
1311153ef166SPaul Zimmerman     }
1312153ef166SPaul Zimmerman 
1313153ef166SPaul Zimmerman     dwc2_update_irq(s);
1314153ef166SPaul Zimmerman }
1315153ef166SPaul Zimmerman 
1316153ef166SPaul Zimmerman static void dwc2_reset_exit(Object *obj)
1317153ef166SPaul Zimmerman {
131879f6cf7eSEduardo Habkost     DWC2Class *c = DWC2_USB_GET_CLASS(obj);
1319153ef166SPaul Zimmerman     DWC2State *s = DWC2_USB(obj);
1320153ef166SPaul Zimmerman 
1321153ef166SPaul Zimmerman     trace_usb_dwc2_reset_exit();
1322153ef166SPaul Zimmerman 
1323153ef166SPaul Zimmerman     if (c->parent_phases.exit) {
1324153ef166SPaul Zimmerman         c->parent_phases.exit(obj);
1325153ef166SPaul Zimmerman     }
1326153ef166SPaul Zimmerman 
1327153ef166SPaul Zimmerman     s->hprt0 = HPRT0_PWR;
1328153ef166SPaul Zimmerman     if (s->uport.dev && s->uport.dev->attached) {
1329153ef166SPaul Zimmerman         usb_attach(&s->uport);
1330153ef166SPaul Zimmerman         usb_device_reset(s->uport.dev);
1331153ef166SPaul Zimmerman     }
1332153ef166SPaul Zimmerman }
1333153ef166SPaul Zimmerman 
1334153ef166SPaul Zimmerman static void dwc2_realize(DeviceState *dev, Error **errp)
1335153ef166SPaul Zimmerman {
1336153ef166SPaul Zimmerman     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
1337153ef166SPaul Zimmerman     DWC2State *s = DWC2_USB(dev);
1338153ef166SPaul Zimmerman     Object *obj;
1339153ef166SPaul Zimmerman 
13404d21fcd5SMarkus Armbruster     obj = object_property_get_link(OBJECT(dev), "dma-mr", &error_abort);
1341153ef166SPaul Zimmerman 
1342153ef166SPaul Zimmerman     s->dma_mr = MEMORY_REGION(obj);
1343153ef166SPaul Zimmerman     address_space_init(&s->dma_as, s->dma_mr, "dwc2");
1344153ef166SPaul Zimmerman 
1345153ef166SPaul Zimmerman     usb_bus_new(&s->bus, sizeof(s->bus), &dwc2_bus_ops, dev);
1346153ef166SPaul Zimmerman     usb_register_port(&s->bus, &s->uport, s, 0, &dwc2_port_ops,
1347153ef166SPaul Zimmerman                       USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL |
1348153ef166SPaul Zimmerman                       (s->usb_version == 2 ? USB_SPEED_MASK_HIGH : 0));
1349153ef166SPaul Zimmerman     s->uport.dev = 0;
1350153ef166SPaul Zimmerman 
1351153ef166SPaul Zimmerman     s->usb_frame_time = NANOSECONDS_PER_SECOND / 1000;          /* 1000000 */
1352153ef166SPaul Zimmerman     if (NANOSECONDS_PER_SECOND >= USB_HZ_FS) {
1353153ef166SPaul Zimmerman         s->usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ_FS;   /* 83.3 */
1354153ef166SPaul Zimmerman     } else {
1355153ef166SPaul Zimmerman         s->usb_bit_time = 1;
1356153ef166SPaul Zimmerman     }
1357153ef166SPaul Zimmerman 
1358153ef166SPaul Zimmerman     s->fi = USB_FRMINTVL - 1;
1359153ef166SPaul Zimmerman     s->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, dwc2_frame_boundary, s);
1360153ef166SPaul Zimmerman     s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, dwc2_work_timer, s);
1361153ef166SPaul Zimmerman     s->async_bh = qemu_bh_new(dwc2_work_bh, s);
1362153ef166SPaul Zimmerman 
1363153ef166SPaul Zimmerman     sysbus_init_irq(sbd, &s->irq);
1364153ef166SPaul Zimmerman }
1365153ef166SPaul Zimmerman 
1366153ef166SPaul Zimmerman static void dwc2_init(Object *obj)
1367153ef166SPaul Zimmerman {
1368153ef166SPaul Zimmerman     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1369153ef166SPaul Zimmerman     DWC2State *s = DWC2_USB(obj);
1370153ef166SPaul Zimmerman 
1371153ef166SPaul Zimmerman     memory_region_init(&s->container, obj, "dwc2", DWC2_MMIO_SIZE);
1372153ef166SPaul Zimmerman     sysbus_init_mmio(sbd, &s->container);
1373153ef166SPaul Zimmerman 
1374153ef166SPaul Zimmerman     memory_region_init_io(&s->hsotg, obj, &dwc2_mmio_hsotg_ops, s,
1375153ef166SPaul Zimmerman                           "dwc2-io", 4 * KiB);
1376153ef166SPaul Zimmerman     memory_region_add_subregion(&s->container, 0x0000, &s->hsotg);
1377153ef166SPaul Zimmerman 
1378153ef166SPaul Zimmerman     memory_region_init_io(&s->fifos, obj, &dwc2_mmio_hreg2_ops, s,
1379153ef166SPaul Zimmerman                           "dwc2-fifo", 64 * KiB);
1380153ef166SPaul Zimmerman     memory_region_add_subregion(&s->container, 0x1000, &s->fifos);
1381153ef166SPaul Zimmerman }
1382153ef166SPaul Zimmerman 
1383153ef166SPaul Zimmerman static const VMStateDescription vmstate_dwc2_state_packet = {
1384153ef166SPaul Zimmerman     .name = "dwc2/packet",
1385153ef166SPaul Zimmerman     .version_id = 1,
1386153ef166SPaul Zimmerman     .minimum_version_id = 1,
1387153ef166SPaul Zimmerman     .fields = (VMStateField[]) {
1388153ef166SPaul Zimmerman         VMSTATE_UINT32(devadr, DWC2Packet),
1389153ef166SPaul Zimmerman         VMSTATE_UINT32(epnum, DWC2Packet),
1390153ef166SPaul Zimmerman         VMSTATE_UINT32(epdir, DWC2Packet),
1391153ef166SPaul Zimmerman         VMSTATE_UINT32(mps, DWC2Packet),
1392153ef166SPaul Zimmerman         VMSTATE_UINT32(pid, DWC2Packet),
1393153ef166SPaul Zimmerman         VMSTATE_UINT32(index, DWC2Packet),
1394153ef166SPaul Zimmerman         VMSTATE_UINT32(pcnt, DWC2Packet),
1395153ef166SPaul Zimmerman         VMSTATE_UINT32(len, DWC2Packet),
1396153ef166SPaul Zimmerman         VMSTATE_INT32(async, DWC2Packet),
1397153ef166SPaul Zimmerman         VMSTATE_BOOL(small, DWC2Packet),
1398153ef166SPaul Zimmerman         VMSTATE_BOOL(needs_service, DWC2Packet),
1399153ef166SPaul Zimmerman         VMSTATE_END_OF_LIST()
1400153ef166SPaul Zimmerman     },
1401153ef166SPaul Zimmerman };
1402153ef166SPaul Zimmerman 
1403153ef166SPaul Zimmerman const VMStateDescription vmstate_dwc2_state = {
1404153ef166SPaul Zimmerman     .name = "dwc2",
1405153ef166SPaul Zimmerman     .version_id = 1,
1406153ef166SPaul Zimmerman     .minimum_version_id = 1,
1407153ef166SPaul Zimmerman     .fields = (VMStateField[]) {
1408153ef166SPaul Zimmerman         VMSTATE_UINT32_ARRAY(glbreg, DWC2State,
1409153ef166SPaul Zimmerman                              DWC2_GLBREG_SIZE / sizeof(uint32_t)),
1410153ef166SPaul Zimmerman         VMSTATE_UINT32_ARRAY(fszreg, DWC2State,
1411153ef166SPaul Zimmerman                              DWC2_FSZREG_SIZE / sizeof(uint32_t)),
1412153ef166SPaul Zimmerman         VMSTATE_UINT32_ARRAY(hreg0, DWC2State,
1413153ef166SPaul Zimmerman                              DWC2_HREG0_SIZE / sizeof(uint32_t)),
1414153ef166SPaul Zimmerman         VMSTATE_UINT32_ARRAY(hreg1, DWC2State,
1415153ef166SPaul Zimmerman                              DWC2_HREG1_SIZE / sizeof(uint32_t)),
1416153ef166SPaul Zimmerman         VMSTATE_UINT32_ARRAY(pcgreg, DWC2State,
1417153ef166SPaul Zimmerman                              DWC2_PCGREG_SIZE / sizeof(uint32_t)),
1418153ef166SPaul Zimmerman 
1419153ef166SPaul Zimmerman         VMSTATE_TIMER_PTR(eof_timer, DWC2State),
1420153ef166SPaul Zimmerman         VMSTATE_TIMER_PTR(frame_timer, DWC2State),
1421153ef166SPaul Zimmerman         VMSTATE_INT64(sof_time, DWC2State),
1422153ef166SPaul Zimmerman         VMSTATE_INT64(usb_frame_time, DWC2State),
1423153ef166SPaul Zimmerman         VMSTATE_INT64(usb_bit_time, DWC2State),
1424153ef166SPaul Zimmerman         VMSTATE_UINT32(usb_version, DWC2State),
1425153ef166SPaul Zimmerman         VMSTATE_UINT16(frame_number, DWC2State),
1426153ef166SPaul Zimmerman         VMSTATE_UINT16(fi, DWC2State),
1427153ef166SPaul Zimmerman         VMSTATE_UINT16(next_chan, DWC2State),
1428153ef166SPaul Zimmerman         VMSTATE_BOOL(working, DWC2State),
1429153ef166SPaul Zimmerman 
1430153ef166SPaul Zimmerman         VMSTATE_STRUCT_ARRAY(packet, DWC2State, DWC2_NB_CHAN, 1,
1431153ef166SPaul Zimmerman                              vmstate_dwc2_state_packet, DWC2Packet),
1432153ef166SPaul Zimmerman         VMSTATE_UINT8_2DARRAY(usb_buf, DWC2State, DWC2_NB_CHAN,
1433153ef166SPaul Zimmerman                               DWC2_MAX_XFER_SIZE),
1434153ef166SPaul Zimmerman 
1435153ef166SPaul Zimmerman         VMSTATE_END_OF_LIST()
1436153ef166SPaul Zimmerman     }
1437153ef166SPaul Zimmerman };
1438153ef166SPaul Zimmerman 
1439153ef166SPaul Zimmerman static Property dwc2_usb_properties[] = {
1440153ef166SPaul Zimmerman     DEFINE_PROP_UINT32("usb_version", DWC2State, usb_version, 2),
1441153ef166SPaul Zimmerman     DEFINE_PROP_END_OF_LIST(),
1442153ef166SPaul Zimmerman };
1443153ef166SPaul Zimmerman 
1444153ef166SPaul Zimmerman static void dwc2_class_init(ObjectClass *klass, void *data)
1445153ef166SPaul Zimmerman {
1446153ef166SPaul Zimmerman     DeviceClass *dc = DEVICE_CLASS(klass);
144779f6cf7eSEduardo Habkost     DWC2Class *c = DWC2_USB_CLASS(klass);
1448153ef166SPaul Zimmerman     ResettableClass *rc = RESETTABLE_CLASS(klass);
1449153ef166SPaul Zimmerman 
1450153ef166SPaul Zimmerman     dc->realize = dwc2_realize;
1451153ef166SPaul Zimmerman     dc->vmsd = &vmstate_dwc2_state;
1452153ef166SPaul Zimmerman     set_bit(DEVICE_CATEGORY_USB, dc->categories);
1453153ef166SPaul Zimmerman     device_class_set_props(dc, dwc2_usb_properties);
1454153ef166SPaul Zimmerman     resettable_class_set_parent_phases(rc, dwc2_reset_enter, dwc2_reset_hold,
1455153ef166SPaul Zimmerman                                        dwc2_reset_exit, &c->parent_phases);
1456153ef166SPaul Zimmerman }
1457153ef166SPaul Zimmerman 
1458153ef166SPaul Zimmerman static const TypeInfo dwc2_usb_type_info = {
1459153ef166SPaul Zimmerman     .name          = TYPE_DWC2_USB,
1460153ef166SPaul Zimmerman     .parent        = TYPE_SYS_BUS_DEVICE,
1461153ef166SPaul Zimmerman     .instance_size = sizeof(DWC2State),
1462153ef166SPaul Zimmerman     .instance_init = dwc2_init,
1463153ef166SPaul Zimmerman     .class_size    = sizeof(DWC2Class),
1464153ef166SPaul Zimmerman     .class_init    = dwc2_class_init,
1465153ef166SPaul Zimmerman };
1466153ef166SPaul Zimmerman 
1467153ef166SPaul Zimmerman static void dwc2_usb_register_types(void)
1468153ef166SPaul Zimmerman {
1469153ef166SPaul Zimmerman     type_register_static(&dwc2_usb_type_info);
1470153ef166SPaul Zimmerman }
1471153ef166SPaul Zimmerman 
1472153ef166SPaul Zimmerman type_init(dwc2_usb_register_types)
1473