xref: /openbmc/qemu/hw/usb/hcd-dwc2.c (revision f63192b0)
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 */
dwc2_update_irq(DWC2State * s)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 */
dwc2_raise_global_irq(DWC2State * s,uint32_t intr)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 
dwc2_lower_global_irq(DWC2State * s,uint32_t intr)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 
dwc2_raise_host_irq(DWC2State * s,uint32_t host_intr)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 
dwc2_lower_host_irq(DWC2State * s,uint32_t host_intr)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 
dwc2_update_hc_irq(DWC2State * s,int index)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 */
dwc2_eof_timer(DWC2State * s)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 */
dwc2_sof(DWC2State * s)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 */
dwc2_frame_boundary(void * opaque)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 */
dwc2_bus_start(DWC2State * s)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 */
dwc2_bus_stop(DWC2State * s)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 
dwc2_find_device(DWC2State * s,uint8_t addr)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 
dwc2_handle_packet(DWC2State * s,uint32_t devadr,USBDevice * dev,USBEndpoint * ep,uint32_t index,bool send)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);
24169958d8aSPaul Zimmerman     if (len > DWC2_MAX_XFER_SIZE) {
24269958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR,
24369958d8aSPaul Zimmerman                       "%s: HCTSIZ transfer size too large\n", __func__);
24469958d8aSPaul Zimmerman         return;
24569958d8aSPaul Zimmerman     }
24669958d8aSPaul 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 
253bea2a9e3SMauro Matteo Cascella     if (mps == 0) {
254bea2a9e3SMauro Matteo Cascella         qemu_log_mask(LOG_GUEST_ERROR,
255bea2a9e3SMauro Matteo Cascella                 "%s: Bad HCCHAR_MPS set to zero\n", __func__);
256bea2a9e3SMauro Matteo Cascella         return;
257bea2a9e3SMauro Matteo Cascella     }
258bea2a9e3SMauro Matteo Cascella 
259153ef166SPaul Zimmerman     if (eptype == USB_ENDPOINT_XFER_CONTROL && pid == TSIZ_SC_MC_PID_SETUP) {
260153ef166SPaul Zimmerman         pid = USB_TOKEN_SETUP;
261153ef166SPaul Zimmerman     } else {
262153ef166SPaul Zimmerman         pid = epdir ? USB_TOKEN_IN : USB_TOKEN_OUT;
263153ef166SPaul Zimmerman     }
264153ef166SPaul Zimmerman 
265153ef166SPaul Zimmerman     if (send) {
266153ef166SPaul Zimmerman         tlen = len;
267153ef166SPaul Zimmerman         if (p->small) {
268153ef166SPaul Zimmerman             if (tlen > mps) {
269153ef166SPaul Zimmerman                 tlen = mps;
270153ef166SPaul Zimmerman             }
271153ef166SPaul Zimmerman         }
272153ef166SPaul Zimmerman 
273153ef166SPaul Zimmerman         if (pid != USB_TOKEN_IN) {
274153ef166SPaul Zimmerman             trace_usb_dwc2_memory_read(hcdma, tlen);
275ba06fe8aSPhilippe Mathieu-Daudé             if (dma_memory_read(&s->dma_as, hcdma, s->usb_buf[chan], tlen,
276ba06fe8aSPhilippe Mathieu-Daudé                                 MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
277153ef166SPaul Zimmerman                 qemu_log_mask(LOG_GUEST_ERROR, "%s: dma_memory_read failed\n",
278153ef166SPaul Zimmerman                               __func__);
279153ef166SPaul Zimmerman             }
280153ef166SPaul Zimmerman         }
281153ef166SPaul Zimmerman 
282153ef166SPaul Zimmerman         usb_packet_init(&p->packet);
283153ef166SPaul Zimmerman         usb_packet_setup(&p->packet, pid, ep, 0, hcdma,
284153ef166SPaul Zimmerman                          pid != USB_TOKEN_IN, true);
285153ef166SPaul Zimmerman         usb_packet_addbuf(&p->packet, s->usb_buf[chan], tlen);
286153ef166SPaul Zimmerman         p->async = DWC2_ASYNC_NONE;
287153ef166SPaul Zimmerman         usb_handle_packet(dev, &p->packet);
288153ef166SPaul Zimmerman     } else {
289153ef166SPaul Zimmerman         tlen = p->len;
290153ef166SPaul Zimmerman     }
291153ef166SPaul Zimmerman 
292153ef166SPaul Zimmerman     stsidx = -p->packet.status;
293153ef166SPaul Zimmerman     assert(stsidx < sizeof(pstatus) / sizeof(*pstatus));
294153ef166SPaul Zimmerman     actual = p->packet.actual_length;
295153ef166SPaul Zimmerman     trace_usb_dwc2_packet_status(pstatus[stsidx], actual);
296153ef166SPaul Zimmerman 
297153ef166SPaul Zimmerman babble:
298153ef166SPaul Zimmerman     if (p->packet.status != USB_RET_SUCCESS &&
299153ef166SPaul Zimmerman             p->packet.status != USB_RET_NAK &&
300153ef166SPaul Zimmerman             p->packet.status != USB_RET_STALL &&
301153ef166SPaul Zimmerman             p->packet.status != USB_RET_ASYNC) {
302153ef166SPaul Zimmerman         trace_usb_dwc2_packet_error(pstatus[stsidx]);
303153ef166SPaul Zimmerman     }
304153ef166SPaul Zimmerman 
305153ef166SPaul Zimmerman     if (p->packet.status == USB_RET_ASYNC) {
306153ef166SPaul Zimmerman         trace_usb_dwc2_async_packet(&p->packet, chan, dev, epnum,
307153ef166SPaul Zimmerman                                     dirs[epdir], tlen);
308153ef166SPaul Zimmerman         usb_device_flush_ep_queue(dev, ep);
309153ef166SPaul Zimmerman         assert(p->async != DWC2_ASYNC_INFLIGHT);
310153ef166SPaul Zimmerman         p->devadr = devadr;
311153ef166SPaul Zimmerman         p->epnum = epnum;
312153ef166SPaul Zimmerman         p->epdir = epdir;
313153ef166SPaul Zimmerman         p->mps = mps;
314153ef166SPaul Zimmerman         p->pid = pid;
315153ef166SPaul Zimmerman         p->index = index;
316153ef166SPaul Zimmerman         p->pcnt = pcnt;
317153ef166SPaul Zimmerman         p->len = tlen;
318153ef166SPaul Zimmerman         p->async = DWC2_ASYNC_INFLIGHT;
319153ef166SPaul Zimmerman         p->needs_service = false;
320153ef166SPaul Zimmerman         return;
321153ef166SPaul Zimmerman     }
322153ef166SPaul Zimmerman 
323153ef166SPaul Zimmerman     if (p->packet.status == USB_RET_SUCCESS) {
324153ef166SPaul Zimmerman         if (actual > tlen) {
325153ef166SPaul Zimmerman             p->packet.status = USB_RET_BABBLE;
326153ef166SPaul Zimmerman             goto babble;
327153ef166SPaul Zimmerman         }
328153ef166SPaul Zimmerman 
329153ef166SPaul Zimmerman         if (pid == USB_TOKEN_IN) {
330153ef166SPaul Zimmerman             trace_usb_dwc2_memory_write(hcdma, actual);
331ba06fe8aSPhilippe Mathieu-Daudé             if (dma_memory_write(&s->dma_as, hcdma, s->usb_buf[chan], actual,
332ba06fe8aSPhilippe Mathieu-Daudé                                  MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
333153ef166SPaul Zimmerman                 qemu_log_mask(LOG_GUEST_ERROR, "%s: dma_memory_write failed\n",
334153ef166SPaul Zimmerman                               __func__);
335153ef166SPaul Zimmerman             }
336153ef166SPaul Zimmerman         }
337153ef166SPaul Zimmerman 
338153ef166SPaul Zimmerman         tpcnt = actual / mps;
339153ef166SPaul Zimmerman         if (actual % mps) {
340153ef166SPaul Zimmerman             tpcnt++;
341153ef166SPaul Zimmerman             if (pid == USB_TOKEN_IN) {
342153ef166SPaul Zimmerman                 done = true;
343153ef166SPaul Zimmerman             }
344153ef166SPaul Zimmerman         }
345153ef166SPaul Zimmerman 
346153ef166SPaul Zimmerman         pcnt -= tpcnt < pcnt ? tpcnt : pcnt;
347153ef166SPaul Zimmerman         set_field(&hctsiz, pcnt, TSIZ_PKTCNT);
348153ef166SPaul Zimmerman         len -= actual < len ? actual : len;
349153ef166SPaul Zimmerman         set_field(&hctsiz, len, TSIZ_XFERSIZE);
350153ef166SPaul Zimmerman         s->hreg1[index + 4] = hctsiz;
351153ef166SPaul Zimmerman         hcdma += actual;
352153ef166SPaul Zimmerman         s->hreg1[index + 5] = hcdma;
353153ef166SPaul Zimmerman 
354153ef166SPaul Zimmerman         if (!pcnt || len == 0 || actual == 0) {
355153ef166SPaul Zimmerman             done = true;
356153ef166SPaul Zimmerman         }
357153ef166SPaul Zimmerman     } else {
358153ef166SPaul Zimmerman         intr |= pintr[stsidx];
359153ef166SPaul Zimmerman         if (p->packet.status == USB_RET_NAK &&
360153ef166SPaul Zimmerman             (eptype == USB_ENDPOINT_XFER_CONTROL ||
361153ef166SPaul Zimmerman              eptype == USB_ENDPOINT_XFER_BULK)) {
362153ef166SPaul Zimmerman             /*
363153ef166SPaul Zimmerman              * for ctrl/bulk, automatically retry on NAK,
364153ef166SPaul Zimmerman              * but send the interrupt anyway
365153ef166SPaul Zimmerman              */
366153ef166SPaul Zimmerman             intr &= ~HCINTMSK_RESERVED14_31;
367153ef166SPaul Zimmerman             s->hreg1[index + 2] |= intr;
368153ef166SPaul Zimmerman             do_intr = true;
369153ef166SPaul Zimmerman         } else {
370153ef166SPaul Zimmerman             intr |= HCINTMSK_CHHLTD;
371153ef166SPaul Zimmerman             done = true;
372153ef166SPaul Zimmerman         }
373153ef166SPaul Zimmerman     }
374153ef166SPaul Zimmerman 
375153ef166SPaul Zimmerman     usb_packet_cleanup(&p->packet);
376153ef166SPaul Zimmerman 
377153ef166SPaul Zimmerman     if (done) {
378153ef166SPaul Zimmerman         hcchar &= ~HCCHAR_CHENA;
379153ef166SPaul Zimmerman         s->hreg1[index] = hcchar;
380153ef166SPaul Zimmerman         if (!(intr & HCINTMSK_CHHLTD)) {
381153ef166SPaul Zimmerman             intr |= HCINTMSK_CHHLTD | HCINTMSK_XFERCOMPL;
382153ef166SPaul Zimmerman         }
383153ef166SPaul Zimmerman         intr &= ~HCINTMSK_RESERVED14_31;
384153ef166SPaul Zimmerman         s->hreg1[index + 2] |= intr;
385153ef166SPaul Zimmerman         p->needs_service = false;
386153ef166SPaul Zimmerman         trace_usb_dwc2_packet_done(pstatus[stsidx], actual, len, pcnt);
387153ef166SPaul Zimmerman         dwc2_update_hc_irq(s, index);
388153ef166SPaul Zimmerman         return;
389153ef166SPaul Zimmerman     }
390153ef166SPaul Zimmerman 
391153ef166SPaul Zimmerman     p->devadr = devadr;
392153ef166SPaul Zimmerman     p->epnum = epnum;
393153ef166SPaul Zimmerman     p->epdir = epdir;
394153ef166SPaul Zimmerman     p->mps = mps;
395153ef166SPaul Zimmerman     p->pid = pid;
396153ef166SPaul Zimmerman     p->index = index;
397153ef166SPaul Zimmerman     p->pcnt = pcnt;
398153ef166SPaul Zimmerman     p->len = len;
399153ef166SPaul Zimmerman     p->needs_service = true;
400153ef166SPaul Zimmerman     trace_usb_dwc2_packet_next(pstatus[stsidx], len, pcnt);
401153ef166SPaul Zimmerman     if (do_intr) {
402153ef166SPaul Zimmerman         dwc2_update_hc_irq(s, index);
403153ef166SPaul Zimmerman     }
404153ef166SPaul Zimmerman }
405153ef166SPaul Zimmerman 
406153ef166SPaul Zimmerman /* Attach or detach a device on root hub */
407153ef166SPaul Zimmerman 
408153ef166SPaul Zimmerman static const char *speeds[] = {
409153ef166SPaul Zimmerman     "low", "full", "high"
410153ef166SPaul Zimmerman };
411153ef166SPaul Zimmerman 
dwc2_attach(USBPort * port)412153ef166SPaul Zimmerman static void dwc2_attach(USBPort *port)
413153ef166SPaul Zimmerman {
414153ef166SPaul Zimmerman     DWC2State *s = port->opaque;
415153ef166SPaul Zimmerman     int hispd = 0;
416153ef166SPaul Zimmerman 
417153ef166SPaul Zimmerman     trace_usb_dwc2_attach(port);
418153ef166SPaul Zimmerman     assert(port->index == 0);
419153ef166SPaul Zimmerman 
420153ef166SPaul Zimmerman     if (!port->dev || !port->dev->attached) {
421153ef166SPaul Zimmerman         return;
422153ef166SPaul Zimmerman     }
423153ef166SPaul Zimmerman 
424153ef166SPaul Zimmerman     assert(port->dev->speed <= USB_SPEED_HIGH);
425153ef166SPaul Zimmerman     trace_usb_dwc2_attach_speed(speeds[port->dev->speed]);
426153ef166SPaul Zimmerman     s->hprt0 &= ~HPRT0_SPD_MASK;
427153ef166SPaul Zimmerman 
428153ef166SPaul Zimmerman     switch (port->dev->speed) {
429153ef166SPaul Zimmerman     case USB_SPEED_LOW:
430153ef166SPaul Zimmerman         s->hprt0 |= HPRT0_SPD_LOW_SPEED << HPRT0_SPD_SHIFT;
431153ef166SPaul Zimmerman         break;
432153ef166SPaul Zimmerman     case USB_SPEED_FULL:
433153ef166SPaul Zimmerman         s->hprt0 |= HPRT0_SPD_FULL_SPEED << HPRT0_SPD_SHIFT;
434153ef166SPaul Zimmerman         break;
435153ef166SPaul Zimmerman     case USB_SPEED_HIGH:
436153ef166SPaul Zimmerman         s->hprt0 |= HPRT0_SPD_HIGH_SPEED << HPRT0_SPD_SHIFT;
437153ef166SPaul Zimmerman         hispd = 1;
438153ef166SPaul Zimmerman         break;
439153ef166SPaul Zimmerman     }
440153ef166SPaul Zimmerman 
441153ef166SPaul Zimmerman     if (hispd) {
442153ef166SPaul Zimmerman         s->usb_frame_time = NANOSECONDS_PER_SECOND / 8000;        /* 125000 */
443153ef166SPaul Zimmerman         if (NANOSECONDS_PER_SECOND >= USB_HZ_HS) {
444153ef166SPaul Zimmerman             s->usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ_HS; /* 10.4 */
445153ef166SPaul Zimmerman         } else {
446153ef166SPaul Zimmerman             s->usb_bit_time = 1;
447153ef166SPaul Zimmerman         }
448153ef166SPaul Zimmerman     } else {
449153ef166SPaul Zimmerman         s->usb_frame_time = NANOSECONDS_PER_SECOND / 1000;        /* 1000000 */
450153ef166SPaul Zimmerman         if (NANOSECONDS_PER_SECOND >= USB_HZ_FS) {
451153ef166SPaul Zimmerman             s->usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ_FS; /* 83.3 */
452153ef166SPaul Zimmerman         } else {
453153ef166SPaul Zimmerman             s->usb_bit_time = 1;
454153ef166SPaul Zimmerman         }
455153ef166SPaul Zimmerman     }
456153ef166SPaul Zimmerman 
457153ef166SPaul Zimmerman     s->fi = USB_FRMINTVL - 1;
458153ef166SPaul Zimmerman     s->hprt0 |= HPRT0_CONNDET | HPRT0_CONNSTS;
459153ef166SPaul Zimmerman 
460153ef166SPaul Zimmerman     dwc2_bus_start(s);
461153ef166SPaul Zimmerman     dwc2_raise_global_irq(s, GINTSTS_PRTINT);
462153ef166SPaul Zimmerman }
463153ef166SPaul Zimmerman 
dwc2_detach(USBPort * port)464153ef166SPaul Zimmerman static void dwc2_detach(USBPort *port)
465153ef166SPaul Zimmerman {
466153ef166SPaul Zimmerman     DWC2State *s = port->opaque;
467153ef166SPaul Zimmerman 
468153ef166SPaul Zimmerman     trace_usb_dwc2_detach(port);
469153ef166SPaul Zimmerman     assert(port->index == 0);
470153ef166SPaul Zimmerman 
471153ef166SPaul Zimmerman     dwc2_bus_stop(s);
472153ef166SPaul Zimmerman 
473153ef166SPaul Zimmerman     s->hprt0 &= ~(HPRT0_SPD_MASK | HPRT0_SUSP | HPRT0_ENA | HPRT0_CONNSTS);
474153ef166SPaul Zimmerman     s->hprt0 |= HPRT0_CONNDET | HPRT0_ENACHG;
475153ef166SPaul Zimmerman 
476153ef166SPaul Zimmerman     dwc2_raise_global_irq(s, GINTSTS_PRTINT);
477153ef166SPaul Zimmerman }
478153ef166SPaul Zimmerman 
dwc2_child_detach(USBPort * port,USBDevice * child)479153ef166SPaul Zimmerman static void dwc2_child_detach(USBPort *port, USBDevice *child)
480153ef166SPaul Zimmerman {
481153ef166SPaul Zimmerman     trace_usb_dwc2_child_detach(port, child);
482153ef166SPaul Zimmerman     assert(port->index == 0);
483153ef166SPaul Zimmerman }
484153ef166SPaul Zimmerman 
dwc2_wakeup(USBPort * port)485153ef166SPaul Zimmerman static void dwc2_wakeup(USBPort *port)
486153ef166SPaul Zimmerman {
487153ef166SPaul Zimmerman     DWC2State *s = port->opaque;
488153ef166SPaul Zimmerman 
489153ef166SPaul Zimmerman     trace_usb_dwc2_wakeup(port);
490153ef166SPaul Zimmerman     assert(port->index == 0);
491153ef166SPaul Zimmerman 
492153ef166SPaul Zimmerman     if (s->hprt0 & HPRT0_SUSP) {
493153ef166SPaul Zimmerman         s->hprt0 |= HPRT0_RES;
494153ef166SPaul Zimmerman         dwc2_raise_global_irq(s, GINTSTS_PRTINT);
495153ef166SPaul Zimmerman     }
496153ef166SPaul Zimmerman 
497153ef166SPaul Zimmerman     qemu_bh_schedule(s->async_bh);
498153ef166SPaul Zimmerman }
499153ef166SPaul Zimmerman 
dwc2_async_packet_complete(USBPort * port,USBPacket * packet)500153ef166SPaul Zimmerman static void dwc2_async_packet_complete(USBPort *port, USBPacket *packet)
501153ef166SPaul Zimmerman {
502153ef166SPaul Zimmerman     DWC2State *s = port->opaque;
503153ef166SPaul Zimmerman     DWC2Packet *p;
504153ef166SPaul Zimmerman     USBDevice *dev;
505153ef166SPaul Zimmerman     USBEndpoint *ep;
506153ef166SPaul Zimmerman 
507153ef166SPaul Zimmerman     assert(port->index == 0);
508153ef166SPaul Zimmerman     p = container_of(packet, DWC2Packet, packet);
509153ef166SPaul Zimmerman     dev = dwc2_find_device(s, p->devadr);
510153ef166SPaul Zimmerman     ep = usb_ep_get(dev, p->pid, p->epnum);
511153ef166SPaul Zimmerman     trace_usb_dwc2_async_packet_complete(port, packet, p->index >> 3, dev,
512153ef166SPaul Zimmerman                                          p->epnum, dirs[p->epdir], p->len);
513153ef166SPaul Zimmerman     assert(p->async == DWC2_ASYNC_INFLIGHT);
514153ef166SPaul Zimmerman 
515153ef166SPaul Zimmerman     if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
516153ef166SPaul Zimmerman         usb_cancel_packet(packet);
517153ef166SPaul Zimmerman         usb_packet_cleanup(packet);
518153ef166SPaul Zimmerman         return;
519153ef166SPaul Zimmerman     }
520153ef166SPaul Zimmerman 
521153ef166SPaul Zimmerman     dwc2_handle_packet(s, p->devadr, dev, ep, p->index, false);
522153ef166SPaul Zimmerman 
523153ef166SPaul Zimmerman     p->async = DWC2_ASYNC_FINISHED;
524153ef166SPaul Zimmerman     qemu_bh_schedule(s->async_bh);
525153ef166SPaul Zimmerman }
526153ef166SPaul Zimmerman 
527153ef166SPaul Zimmerman static USBPortOps dwc2_port_ops = {
528153ef166SPaul Zimmerman     .attach = dwc2_attach,
529153ef166SPaul Zimmerman     .detach = dwc2_detach,
530153ef166SPaul Zimmerman     .child_detach = dwc2_child_detach,
531153ef166SPaul Zimmerman     .wakeup = dwc2_wakeup,
532153ef166SPaul Zimmerman     .complete = dwc2_async_packet_complete,
533153ef166SPaul Zimmerman };
534153ef166SPaul Zimmerman 
dwc2_get_frame_remaining(DWC2State * s)535153ef166SPaul Zimmerman static uint32_t dwc2_get_frame_remaining(DWC2State *s)
536153ef166SPaul Zimmerman {
537153ef166SPaul Zimmerman     uint32_t fr = 0;
538153ef166SPaul Zimmerman     int64_t tks;
539153ef166SPaul Zimmerman 
540153ef166SPaul Zimmerman     tks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->sof_time;
541153ef166SPaul Zimmerman     if (tks < 0) {
542153ef166SPaul Zimmerman         tks = 0;
543153ef166SPaul Zimmerman     }
544153ef166SPaul Zimmerman 
545153ef166SPaul Zimmerman     /* avoid muldiv if possible */
546153ef166SPaul Zimmerman     if (tks >= s->usb_frame_time) {
547153ef166SPaul Zimmerman         goto out;
548153ef166SPaul Zimmerman     }
549153ef166SPaul Zimmerman     if (tks < s->usb_bit_time) {
550153ef166SPaul Zimmerman         fr = s->fi;
551153ef166SPaul Zimmerman         goto out;
552153ef166SPaul Zimmerman     }
553153ef166SPaul Zimmerman 
554153ef166SPaul Zimmerman     /* tks = number of ns since SOF, divided by 83 (fs) or 10 (hs) */
555153ef166SPaul Zimmerman     tks = tks / s->usb_bit_time;
556153ef166SPaul Zimmerman     if (tks >= (int64_t)s->fi) {
557153ef166SPaul Zimmerman         goto out;
558153ef166SPaul Zimmerman     }
559153ef166SPaul Zimmerman 
560153ef166SPaul Zimmerman     /* remaining = frame interval minus tks */
561153ef166SPaul Zimmerman     fr = (uint32_t)((int64_t)s->fi - tks);
562153ef166SPaul Zimmerman 
563153ef166SPaul Zimmerman out:
564153ef166SPaul Zimmerman     return fr;
565153ef166SPaul Zimmerman }
566153ef166SPaul Zimmerman 
dwc2_work_bh(void * opaque)567153ef166SPaul Zimmerman static void dwc2_work_bh(void *opaque)
568153ef166SPaul Zimmerman {
569153ef166SPaul Zimmerman     DWC2State *s = opaque;
570153ef166SPaul Zimmerman     DWC2Packet *p;
571153ef166SPaul Zimmerman     USBDevice *dev;
572153ef166SPaul Zimmerman     USBEndpoint *ep;
573153ef166SPaul Zimmerman     int64_t t_now, expire_time;
574153ef166SPaul Zimmerman     int chan;
575153ef166SPaul Zimmerman     bool found = false;
576153ef166SPaul Zimmerman 
577153ef166SPaul Zimmerman     trace_usb_dwc2_work_bh();
578153ef166SPaul Zimmerman     if (s->working) {
579153ef166SPaul Zimmerman         return;
580153ef166SPaul Zimmerman     }
581153ef166SPaul Zimmerman     s->working = true;
582153ef166SPaul Zimmerman 
583153ef166SPaul Zimmerman     t_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
584153ef166SPaul Zimmerman     chan = s->next_chan;
585153ef166SPaul Zimmerman 
586153ef166SPaul Zimmerman     do {
587153ef166SPaul Zimmerman         p = &s->packet[chan];
588153ef166SPaul Zimmerman         if (p->needs_service) {
589153ef166SPaul Zimmerman             dev = dwc2_find_device(s, p->devadr);
590153ef166SPaul Zimmerman             ep = usb_ep_get(dev, p->pid, p->epnum);
591153ef166SPaul Zimmerman             trace_usb_dwc2_work_bh_service(s->next_chan, chan, dev, p->epnum);
592153ef166SPaul Zimmerman             dwc2_handle_packet(s, p->devadr, dev, ep, p->index, true);
593153ef166SPaul Zimmerman             found = true;
594153ef166SPaul Zimmerman         }
595153ef166SPaul Zimmerman         if (++chan == DWC2_NB_CHAN) {
596153ef166SPaul Zimmerman             chan = 0;
597153ef166SPaul Zimmerman         }
598153ef166SPaul Zimmerman         if (found) {
599153ef166SPaul Zimmerman             s->next_chan = chan;
600153ef166SPaul Zimmerman             trace_usb_dwc2_work_bh_next(chan);
601153ef166SPaul Zimmerman         }
602153ef166SPaul Zimmerman     } while (chan != s->next_chan);
603153ef166SPaul Zimmerman 
604153ef166SPaul Zimmerman     if (found) {
605153ef166SPaul Zimmerman         expire_time = t_now + NANOSECONDS_PER_SECOND / 4000;
606153ef166SPaul Zimmerman         timer_mod(s->frame_timer, expire_time);
607153ef166SPaul Zimmerman     }
608153ef166SPaul Zimmerman     s->working = false;
609153ef166SPaul Zimmerman }
610153ef166SPaul Zimmerman 
dwc2_enable_chan(DWC2State * s,uint32_t index)611153ef166SPaul Zimmerman static void dwc2_enable_chan(DWC2State *s,  uint32_t index)
612153ef166SPaul Zimmerman {
613153ef166SPaul Zimmerman     USBDevice *dev;
614153ef166SPaul Zimmerman     USBEndpoint *ep;
615153ef166SPaul Zimmerman     uint32_t hcchar;
616153ef166SPaul Zimmerman     uint32_t hctsiz;
617153ef166SPaul Zimmerman     uint32_t devadr, epnum, epdir, eptype, pid, len;
618153ef166SPaul Zimmerman     DWC2Packet *p;
619153ef166SPaul Zimmerman 
620153ef166SPaul Zimmerman     assert((index >> 3) < DWC2_NB_CHAN);
621153ef166SPaul Zimmerman     p = &s->packet[index >> 3];
622153ef166SPaul Zimmerman     hcchar = s->hreg1[index];
623153ef166SPaul Zimmerman     hctsiz = s->hreg1[index + 4];
624153ef166SPaul Zimmerman     devadr = get_field(hcchar, HCCHAR_DEVADDR);
625153ef166SPaul Zimmerman     epnum = get_field(hcchar, HCCHAR_EPNUM);
626153ef166SPaul Zimmerman     epdir = get_bit(hcchar, HCCHAR_EPDIR);
627153ef166SPaul Zimmerman     eptype = get_field(hcchar, HCCHAR_EPTYPE);
628153ef166SPaul Zimmerman     pid = get_field(hctsiz, TSIZ_SC_MC_PID);
629153ef166SPaul Zimmerman     len = get_field(hctsiz, TSIZ_XFERSIZE);
630153ef166SPaul Zimmerman 
631153ef166SPaul Zimmerman     dev = dwc2_find_device(s, devadr);
632153ef166SPaul Zimmerman 
633153ef166SPaul Zimmerman     trace_usb_dwc2_enable_chan(index >> 3, dev, &p->packet, epnum);
634153ef166SPaul Zimmerman     if (dev == NULL) {
635153ef166SPaul Zimmerman         return;
636153ef166SPaul Zimmerman     }
637153ef166SPaul Zimmerman 
638153ef166SPaul Zimmerman     if (eptype == USB_ENDPOINT_XFER_CONTROL && pid == TSIZ_SC_MC_PID_SETUP) {
639153ef166SPaul Zimmerman         pid = USB_TOKEN_SETUP;
640153ef166SPaul Zimmerman     } else {
641153ef166SPaul Zimmerman         pid = epdir ? USB_TOKEN_IN : USB_TOKEN_OUT;
642153ef166SPaul Zimmerman     }
643153ef166SPaul Zimmerman 
644153ef166SPaul Zimmerman     ep = usb_ep_get(dev, pid, epnum);
645153ef166SPaul Zimmerman 
646153ef166SPaul Zimmerman     /*
647153ef166SPaul Zimmerman      * Hack: Networking doesn't like us delivering large transfers, it kind
648153ef166SPaul Zimmerman      * of works but the latency is horrible. So if the transfer is <= the mtu
649153ef166SPaul Zimmerman      * size, we take that as a hint that this might be a network transfer,
650153ef166SPaul Zimmerman      * and do the transfer packet-by-packet.
651153ef166SPaul Zimmerman      */
652153ef166SPaul Zimmerman     if (len > 1536) {
653153ef166SPaul Zimmerman         p->small = false;
654153ef166SPaul Zimmerman     } else {
655153ef166SPaul Zimmerman         p->small = true;
656153ef166SPaul Zimmerman     }
657153ef166SPaul Zimmerman 
658153ef166SPaul Zimmerman     dwc2_handle_packet(s, devadr, dev, ep, index, true);
659153ef166SPaul Zimmerman     qemu_bh_schedule(s->async_bh);
660153ef166SPaul Zimmerman }
661153ef166SPaul Zimmerman 
662153ef166SPaul Zimmerman static const char *glbregnm[] = {
663153ef166SPaul Zimmerman     "GOTGCTL  ", "GOTGINT  ", "GAHBCFG  ", "GUSBCFG  ", "GRSTCTL  ",
664153ef166SPaul Zimmerman     "GINTSTS  ", "GINTMSK  ", "GRXSTSR  ", "GRXSTSP  ", "GRXFSIZ  ",
665153ef166SPaul Zimmerman     "GNPTXFSIZ", "GNPTXSTS ", "GI2CCTL  ", "GPVNDCTL ", "GGPIO    ",
666153ef166SPaul Zimmerman     "GUID     ", "GSNPSID  ", "GHWCFG1  ", "GHWCFG2  ", "GHWCFG3  ",
667153ef166SPaul Zimmerman     "GHWCFG4  ", "GLPMCFG  ", "GPWRDN   ", "GDFIFOCFG", "GADPCTL  ",
668153ef166SPaul Zimmerman     "GREFCLK  ", "GINTMSK2 ", "GINTSTS2 "
669153ef166SPaul Zimmerman };
670153ef166SPaul Zimmerman 
dwc2_glbreg_read(void * ptr,hwaddr addr,int index,unsigned size)671153ef166SPaul Zimmerman static uint64_t dwc2_glbreg_read(void *ptr, hwaddr addr, int index,
672153ef166SPaul Zimmerman                                  unsigned size)
673153ef166SPaul Zimmerman {
674153ef166SPaul Zimmerman     DWC2State *s = ptr;
675153ef166SPaul Zimmerman     uint32_t val;
676153ef166SPaul Zimmerman 
67769958d8aSPaul Zimmerman     if (addr > GINTSTS2) {
67869958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
67969958d8aSPaul Zimmerman                       __func__, addr);
68069958d8aSPaul Zimmerman         return 0;
68169958d8aSPaul Zimmerman     }
68269958d8aSPaul Zimmerman 
683153ef166SPaul Zimmerman     val = s->glbreg[index];
684153ef166SPaul Zimmerman 
685153ef166SPaul Zimmerman     switch (addr) {
686153ef166SPaul Zimmerman     case GRSTCTL:
687153ef166SPaul Zimmerman         /* clear any self-clearing bits that were set */
688153ef166SPaul Zimmerman         val &= ~(GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH | GRSTCTL_IN_TKNQ_FLSH |
689153ef166SPaul Zimmerman                  GRSTCTL_FRMCNTRRST | GRSTCTL_HSFTRST | GRSTCTL_CSFTRST);
690153ef166SPaul Zimmerman         s->glbreg[index] = val;
691153ef166SPaul Zimmerman         break;
692153ef166SPaul Zimmerman     default:
693153ef166SPaul Zimmerman         break;
694153ef166SPaul Zimmerman     }
695153ef166SPaul Zimmerman 
696153ef166SPaul Zimmerman     trace_usb_dwc2_glbreg_read(addr, glbregnm[index], val);
697153ef166SPaul Zimmerman     return val;
698153ef166SPaul Zimmerman }
699153ef166SPaul Zimmerman 
dwc2_glbreg_write(void * ptr,hwaddr addr,int index,uint64_t val,unsigned size)700153ef166SPaul Zimmerman static void dwc2_glbreg_write(void *ptr, hwaddr addr, int index, uint64_t val,
701153ef166SPaul Zimmerman                               unsigned size)
702153ef166SPaul Zimmerman {
703153ef166SPaul Zimmerman     DWC2State *s = ptr;
704153ef166SPaul Zimmerman     uint64_t orig = val;
705153ef166SPaul Zimmerman     uint32_t *mmio;
706153ef166SPaul Zimmerman     uint32_t old;
707153ef166SPaul Zimmerman     int iflg = 0;
708153ef166SPaul Zimmerman 
70969958d8aSPaul Zimmerman     if (addr > GINTSTS2) {
71069958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
71169958d8aSPaul Zimmerman                       __func__, addr);
71269958d8aSPaul Zimmerman         return;
71369958d8aSPaul Zimmerman     }
71469958d8aSPaul Zimmerman 
715153ef166SPaul Zimmerman     mmio = &s->glbreg[index];
716153ef166SPaul Zimmerman     old = *mmio;
717153ef166SPaul Zimmerman 
718153ef166SPaul Zimmerman     switch (addr) {
719153ef166SPaul Zimmerman     case GOTGCTL:
720153ef166SPaul Zimmerman         /* don't allow setting of read-only bits */
721153ef166SPaul Zimmerman         val &= ~(GOTGCTL_MULT_VALID_BC_MASK | GOTGCTL_BSESVLD |
722153ef166SPaul Zimmerman                  GOTGCTL_ASESVLD | GOTGCTL_DBNC_SHORT | GOTGCTL_CONID_B |
723153ef166SPaul Zimmerman                  GOTGCTL_HSTNEGSCS | GOTGCTL_SESREQSCS);
724153ef166SPaul Zimmerman         /* don't allow clearing of read-only bits */
725153ef166SPaul Zimmerman         val |= old & (GOTGCTL_MULT_VALID_BC_MASK | GOTGCTL_BSESVLD |
726153ef166SPaul Zimmerman                       GOTGCTL_ASESVLD | GOTGCTL_DBNC_SHORT | GOTGCTL_CONID_B |
727153ef166SPaul Zimmerman                       GOTGCTL_HSTNEGSCS | GOTGCTL_SESREQSCS);
728153ef166SPaul Zimmerman         break;
729153ef166SPaul Zimmerman     case GAHBCFG:
730153ef166SPaul Zimmerman         if ((val & GAHBCFG_GLBL_INTR_EN) && !(old & GAHBCFG_GLBL_INTR_EN)) {
731153ef166SPaul Zimmerman             iflg = 1;
732153ef166SPaul Zimmerman         }
733153ef166SPaul Zimmerman         break;
734153ef166SPaul Zimmerman     case GRSTCTL:
735153ef166SPaul Zimmerman         val |= GRSTCTL_AHBIDLE;
736153ef166SPaul Zimmerman         val &= ~GRSTCTL_DMAREQ;
737153ef166SPaul Zimmerman         if (!(old & GRSTCTL_TXFFLSH) && (val & GRSTCTL_TXFFLSH)) {
738153ef166SPaul Zimmerman                 /* TODO - TX fifo flush */
73969958d8aSPaul Zimmerman             qemu_log_mask(LOG_UNIMP, "%s: Tx FIFO flush not implemented\n",
74069958d8aSPaul Zimmerman                           __func__);
741153ef166SPaul Zimmerman         }
742153ef166SPaul Zimmerman         if (!(old & GRSTCTL_RXFFLSH) && (val & GRSTCTL_RXFFLSH)) {
743153ef166SPaul Zimmerman                 /* TODO - RX fifo flush */
74469958d8aSPaul Zimmerman             qemu_log_mask(LOG_UNIMP, "%s: Rx FIFO flush not implemented\n",
74569958d8aSPaul Zimmerman                           __func__);
746153ef166SPaul Zimmerman         }
747153ef166SPaul Zimmerman         if (!(old & GRSTCTL_IN_TKNQ_FLSH) && (val & GRSTCTL_IN_TKNQ_FLSH)) {
748153ef166SPaul Zimmerman                 /* TODO - device IN token queue flush */
74969958d8aSPaul Zimmerman             qemu_log_mask(LOG_UNIMP, "%s: Token queue flush not implemented\n",
75069958d8aSPaul Zimmerman                           __func__);
751153ef166SPaul Zimmerman         }
752153ef166SPaul Zimmerman         if (!(old & GRSTCTL_FRMCNTRRST) && (val & GRSTCTL_FRMCNTRRST)) {
753153ef166SPaul Zimmerman                 /* TODO - host frame counter reset */
75469958d8aSPaul Zimmerman             qemu_log_mask(LOG_UNIMP,
75569958d8aSPaul Zimmerman                           "%s: Frame counter reset not implemented\n",
75669958d8aSPaul Zimmerman                           __func__);
757153ef166SPaul Zimmerman         }
758153ef166SPaul Zimmerman         if (!(old & GRSTCTL_HSFTRST) && (val & GRSTCTL_HSFTRST)) {
759153ef166SPaul Zimmerman                 /* TODO - host soft reset */
76069958d8aSPaul Zimmerman             qemu_log_mask(LOG_UNIMP, "%s: Host soft reset not implemented\n",
76169958d8aSPaul Zimmerman                           __func__);
762153ef166SPaul Zimmerman         }
763153ef166SPaul Zimmerman         if (!(old & GRSTCTL_CSFTRST) && (val & GRSTCTL_CSFTRST)) {
764153ef166SPaul Zimmerman                 /* TODO - core soft reset */
76569958d8aSPaul Zimmerman             qemu_log_mask(LOG_UNIMP, "%s: Core soft reset not implemented\n",
76669958d8aSPaul Zimmerman                           __func__);
767153ef166SPaul Zimmerman         }
768153ef166SPaul Zimmerman         /* don't allow clearing of self-clearing bits */
769153ef166SPaul Zimmerman         val |= old & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH |
770153ef166SPaul Zimmerman                       GRSTCTL_IN_TKNQ_FLSH | GRSTCTL_FRMCNTRRST |
771153ef166SPaul Zimmerman                       GRSTCTL_HSFTRST | GRSTCTL_CSFTRST);
772153ef166SPaul Zimmerman         break;
773153ef166SPaul Zimmerman     case GINTSTS:
774153ef166SPaul Zimmerman         /* clear the write-1-to-clear bits */
775153ef166SPaul Zimmerman         val |= ~old;
776153ef166SPaul Zimmerman         val = ~val;
777153ef166SPaul Zimmerman         /* don't allow clearing of read-only bits */
778153ef166SPaul Zimmerman         val |= old & (GINTSTS_PTXFEMP | GINTSTS_HCHINT | GINTSTS_PRTINT |
779153ef166SPaul Zimmerman                       GINTSTS_OEPINT | GINTSTS_IEPINT | GINTSTS_GOUTNAKEFF |
780153ef166SPaul Zimmerman                       GINTSTS_GINNAKEFF | GINTSTS_NPTXFEMP | GINTSTS_RXFLVL |
781153ef166SPaul Zimmerman                       GINTSTS_OTGINT | GINTSTS_CURMODE_HOST);
782153ef166SPaul Zimmerman         iflg = 1;
783153ef166SPaul Zimmerman         break;
784153ef166SPaul Zimmerman     case GINTMSK:
785153ef166SPaul Zimmerman         iflg = 1;
786153ef166SPaul Zimmerman         break;
787153ef166SPaul Zimmerman     default:
788153ef166SPaul Zimmerman         break;
789153ef166SPaul Zimmerman     }
790153ef166SPaul Zimmerman 
791153ef166SPaul Zimmerman     trace_usb_dwc2_glbreg_write(addr, glbregnm[index], orig, old, val);
792153ef166SPaul Zimmerman     *mmio = val;
793153ef166SPaul Zimmerman 
794153ef166SPaul Zimmerman     if (iflg) {
795153ef166SPaul Zimmerman         dwc2_update_irq(s);
796153ef166SPaul Zimmerman     }
797153ef166SPaul Zimmerman }
798153ef166SPaul Zimmerman 
dwc2_fszreg_read(void * ptr,hwaddr addr,int index,unsigned size)799153ef166SPaul Zimmerman static uint64_t dwc2_fszreg_read(void *ptr, hwaddr addr, int index,
800153ef166SPaul Zimmerman                                  unsigned size)
801153ef166SPaul Zimmerman {
802153ef166SPaul Zimmerman     DWC2State *s = ptr;
803153ef166SPaul Zimmerman     uint32_t val;
804153ef166SPaul Zimmerman 
80569958d8aSPaul Zimmerman     if (addr != HPTXFSIZ) {
80669958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
80769958d8aSPaul Zimmerman                       __func__, addr);
80869958d8aSPaul Zimmerman         return 0;
80969958d8aSPaul Zimmerman     }
81069958d8aSPaul Zimmerman 
811153ef166SPaul Zimmerman     val = s->fszreg[index];
812153ef166SPaul Zimmerman 
813153ef166SPaul Zimmerman     trace_usb_dwc2_fszreg_read(addr, val);
814153ef166SPaul Zimmerman     return val;
815153ef166SPaul Zimmerman }
816153ef166SPaul Zimmerman 
dwc2_fszreg_write(void * ptr,hwaddr addr,int index,uint64_t val,unsigned size)817153ef166SPaul Zimmerman static void dwc2_fszreg_write(void *ptr, hwaddr addr, int index, uint64_t val,
818153ef166SPaul Zimmerman                               unsigned size)
819153ef166SPaul Zimmerman {
820153ef166SPaul Zimmerman     DWC2State *s = ptr;
821153ef166SPaul Zimmerman     uint64_t orig = val;
822153ef166SPaul Zimmerman     uint32_t *mmio;
823153ef166SPaul Zimmerman     uint32_t old;
824153ef166SPaul Zimmerman 
82569958d8aSPaul Zimmerman     if (addr != HPTXFSIZ) {
82669958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
82769958d8aSPaul Zimmerman                       __func__, addr);
82869958d8aSPaul Zimmerman         return;
82969958d8aSPaul Zimmerman     }
83069958d8aSPaul Zimmerman 
831153ef166SPaul Zimmerman     mmio = &s->fszreg[index];
832153ef166SPaul Zimmerman     old = *mmio;
833153ef166SPaul Zimmerman 
834153ef166SPaul Zimmerman     trace_usb_dwc2_fszreg_write(addr, orig, old, val);
835153ef166SPaul Zimmerman     *mmio = val;
836153ef166SPaul Zimmerman }
837153ef166SPaul Zimmerman 
838153ef166SPaul Zimmerman static const char *hreg0nm[] = {
839153ef166SPaul Zimmerman     "HCFG     ", "HFIR     ", "HFNUM    ", "<rsvd>   ", "HPTXSTS  ",
840153ef166SPaul Zimmerman     "HAINT    ", "HAINTMSK ", "HFLBADDR ", "<rsvd>   ", "<rsvd>   ",
841153ef166SPaul Zimmerman     "<rsvd>   ", "<rsvd>   ", "<rsvd>   ", "<rsvd>   ", "<rsvd>   ",
842153ef166SPaul Zimmerman     "<rsvd>   ", "HPRT0    "
843153ef166SPaul Zimmerman };
844153ef166SPaul Zimmerman 
dwc2_hreg0_read(void * ptr,hwaddr addr,int index,unsigned size)845153ef166SPaul Zimmerman static uint64_t dwc2_hreg0_read(void *ptr, hwaddr addr, int index,
846153ef166SPaul Zimmerman                                 unsigned size)
847153ef166SPaul Zimmerman {
848153ef166SPaul Zimmerman     DWC2State *s = ptr;
849153ef166SPaul Zimmerman     uint32_t val;
850153ef166SPaul Zimmerman 
85169958d8aSPaul Zimmerman     if (addr < HCFG || addr > HPRT0) {
85269958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
85369958d8aSPaul Zimmerman                       __func__, addr);
85469958d8aSPaul Zimmerman         return 0;
85569958d8aSPaul Zimmerman     }
85669958d8aSPaul Zimmerman 
857153ef166SPaul Zimmerman     val = s->hreg0[index];
858153ef166SPaul Zimmerman 
859153ef166SPaul Zimmerman     switch (addr) {
860153ef166SPaul Zimmerman     case HFNUM:
861153ef166SPaul Zimmerman         val = (dwc2_get_frame_remaining(s) << HFNUM_FRREM_SHIFT) |
862153ef166SPaul Zimmerman               (s->hfnum << HFNUM_FRNUM_SHIFT);
863153ef166SPaul Zimmerman         break;
864153ef166SPaul Zimmerman     default:
865153ef166SPaul Zimmerman         break;
866153ef166SPaul Zimmerman     }
867153ef166SPaul Zimmerman 
868153ef166SPaul Zimmerman     trace_usb_dwc2_hreg0_read(addr, hreg0nm[index], val);
869153ef166SPaul Zimmerman     return val;
870153ef166SPaul Zimmerman }
871153ef166SPaul Zimmerman 
dwc2_hreg0_write(void * ptr,hwaddr addr,int index,uint64_t val,unsigned size)872153ef166SPaul Zimmerman static void dwc2_hreg0_write(void *ptr, hwaddr addr, int index, uint64_t val,
873153ef166SPaul Zimmerman                              unsigned size)
874153ef166SPaul Zimmerman {
875153ef166SPaul Zimmerman     DWC2State *s = ptr;
876153ef166SPaul Zimmerman     USBDevice *dev = s->uport.dev;
877153ef166SPaul Zimmerman     uint64_t orig = val;
878153ef166SPaul Zimmerman     uint32_t *mmio;
879153ef166SPaul Zimmerman     uint32_t tval, told, old;
880153ef166SPaul Zimmerman     int prst = 0;
881153ef166SPaul Zimmerman     int iflg = 0;
882153ef166SPaul Zimmerman 
88369958d8aSPaul Zimmerman     if (addr < HCFG || addr > HPRT0) {
88469958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
88569958d8aSPaul Zimmerman                       __func__, addr);
88669958d8aSPaul Zimmerman         return;
88769958d8aSPaul Zimmerman     }
88869958d8aSPaul Zimmerman 
889153ef166SPaul Zimmerman     mmio = &s->hreg0[index];
890153ef166SPaul Zimmerman     old = *mmio;
891153ef166SPaul Zimmerman 
892153ef166SPaul Zimmerman     switch (addr) {
893153ef166SPaul Zimmerman     case HFIR:
894153ef166SPaul Zimmerman         break;
895153ef166SPaul Zimmerman     case HFNUM:
896153ef166SPaul Zimmerman     case HPTXSTS:
897153ef166SPaul Zimmerman     case HAINT:
898153ef166SPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: write to read-only register\n",
899153ef166SPaul Zimmerman                       __func__);
900153ef166SPaul Zimmerman         return;
901153ef166SPaul Zimmerman     case HAINTMSK:
902153ef166SPaul Zimmerman         val &= 0xffff;
903153ef166SPaul Zimmerman         break;
904153ef166SPaul Zimmerman     case HPRT0:
905153ef166SPaul Zimmerman         /* don't allow clearing of read-only bits */
906153ef166SPaul Zimmerman         val |= old & (HPRT0_SPD_MASK | HPRT0_LNSTS_MASK | HPRT0_OVRCURRACT |
907153ef166SPaul Zimmerman                       HPRT0_CONNSTS);
908153ef166SPaul Zimmerman         /* don't allow clearing of self-clearing bits */
909153ef166SPaul Zimmerman         val |= old & (HPRT0_SUSP | HPRT0_RES);
910153ef166SPaul Zimmerman         /* don't allow setting of self-setting bits */
911153ef166SPaul Zimmerman         if (!(old & HPRT0_ENA) && (val & HPRT0_ENA)) {
912153ef166SPaul Zimmerman             val &= ~HPRT0_ENA;
913153ef166SPaul Zimmerman         }
914153ef166SPaul Zimmerman         /* clear the write-1-to-clear bits */
915153ef166SPaul Zimmerman         tval = val & (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA |
916153ef166SPaul Zimmerman                       HPRT0_CONNDET);
917153ef166SPaul Zimmerman         told = old & (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA |
918153ef166SPaul Zimmerman                       HPRT0_CONNDET);
919153ef166SPaul Zimmerman         tval |= ~told;
920153ef166SPaul Zimmerman         tval = ~tval;
921153ef166SPaul Zimmerman         tval &= (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA |
922153ef166SPaul Zimmerman                  HPRT0_CONNDET);
923153ef166SPaul Zimmerman         val &= ~(HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA |
924153ef166SPaul Zimmerman                  HPRT0_CONNDET);
925153ef166SPaul Zimmerman         val |= tval;
926153ef166SPaul Zimmerman         if (!(val & HPRT0_RST) && (old & HPRT0_RST)) {
927153ef166SPaul Zimmerman             if (dev && dev->attached) {
928153ef166SPaul Zimmerman                 val |= HPRT0_ENA | HPRT0_ENACHG;
929153ef166SPaul Zimmerman                 prst = 1;
930153ef166SPaul Zimmerman             }
931153ef166SPaul Zimmerman         }
932153ef166SPaul Zimmerman         if (val & (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_CONNDET)) {
933153ef166SPaul Zimmerman             iflg = 1;
934153ef166SPaul Zimmerman         } else {
935153ef166SPaul Zimmerman             iflg = -1;
936153ef166SPaul Zimmerman         }
937153ef166SPaul Zimmerman         break;
938153ef166SPaul Zimmerman     default:
939153ef166SPaul Zimmerman         break;
940153ef166SPaul Zimmerman     }
941153ef166SPaul Zimmerman 
942153ef166SPaul Zimmerman     if (prst) {
943153ef166SPaul Zimmerman         trace_usb_dwc2_hreg0_write(addr, hreg0nm[index], orig, old,
944153ef166SPaul Zimmerman                                    val & ~HPRT0_CONNDET);
945153ef166SPaul Zimmerman         trace_usb_dwc2_hreg0_action("call usb_port_reset");
946153ef166SPaul Zimmerman         usb_port_reset(&s->uport);
947153ef166SPaul Zimmerman         val &= ~HPRT0_CONNDET;
948153ef166SPaul Zimmerman     } else {
949153ef166SPaul Zimmerman         trace_usb_dwc2_hreg0_write(addr, hreg0nm[index], orig, old, val);
950153ef166SPaul Zimmerman     }
951153ef166SPaul Zimmerman 
952153ef166SPaul Zimmerman     *mmio = val;
953153ef166SPaul Zimmerman 
954153ef166SPaul Zimmerman     if (iflg > 0) {
955153ef166SPaul Zimmerman         trace_usb_dwc2_hreg0_action("enable PRTINT");
956153ef166SPaul Zimmerman         dwc2_raise_global_irq(s, GINTSTS_PRTINT);
957153ef166SPaul Zimmerman     } else if (iflg < 0) {
958153ef166SPaul Zimmerman         trace_usb_dwc2_hreg0_action("disable PRTINT");
959153ef166SPaul Zimmerman         dwc2_lower_global_irq(s, GINTSTS_PRTINT);
960153ef166SPaul Zimmerman     }
961153ef166SPaul Zimmerman }
962153ef166SPaul Zimmerman 
963153ef166SPaul Zimmerman static const char *hreg1nm[] = {
964153ef166SPaul Zimmerman     "HCCHAR  ", "HCSPLT  ", "HCINT   ", "HCINTMSK", "HCTSIZ  ", "HCDMA   ",
965153ef166SPaul Zimmerman     "<rsvd>  ", "HCDMAB  "
966153ef166SPaul Zimmerman };
967153ef166SPaul Zimmerman 
dwc2_hreg1_read(void * ptr,hwaddr addr,int index,unsigned size)968153ef166SPaul Zimmerman static uint64_t dwc2_hreg1_read(void *ptr, hwaddr addr, int index,
969153ef166SPaul Zimmerman                                 unsigned size)
970153ef166SPaul Zimmerman {
971153ef166SPaul Zimmerman     DWC2State *s = ptr;
972153ef166SPaul Zimmerman     uint32_t val;
973153ef166SPaul Zimmerman 
97469958d8aSPaul Zimmerman     if (addr < HCCHAR(0) || addr > HCDMAB(DWC2_NB_CHAN - 1)) {
97569958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
97669958d8aSPaul Zimmerman                       __func__, addr);
97769958d8aSPaul Zimmerman         return 0;
97869958d8aSPaul Zimmerman     }
97969958d8aSPaul Zimmerman 
980153ef166SPaul Zimmerman     val = s->hreg1[index];
981153ef166SPaul Zimmerman 
982153ef166SPaul Zimmerman     trace_usb_dwc2_hreg1_read(addr, hreg1nm[index & 7], addr >> 5, val);
983153ef166SPaul Zimmerman     return val;
984153ef166SPaul Zimmerman }
985153ef166SPaul Zimmerman 
dwc2_hreg1_write(void * ptr,hwaddr addr,int index,uint64_t val,unsigned size)986153ef166SPaul Zimmerman static void dwc2_hreg1_write(void *ptr, hwaddr addr, int index, uint64_t val,
987153ef166SPaul Zimmerman                              unsigned size)
988153ef166SPaul Zimmerman {
989153ef166SPaul Zimmerman     DWC2State *s = ptr;
990153ef166SPaul Zimmerman     uint64_t orig = val;
991153ef166SPaul Zimmerman     uint32_t *mmio;
992153ef166SPaul Zimmerman     uint32_t old;
993153ef166SPaul Zimmerman     int iflg = 0;
994153ef166SPaul Zimmerman     int enflg = 0;
995153ef166SPaul Zimmerman     int disflg = 0;
996153ef166SPaul Zimmerman 
99769958d8aSPaul Zimmerman     if (addr < HCCHAR(0) || addr > HCDMAB(DWC2_NB_CHAN - 1)) {
99869958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
99969958d8aSPaul Zimmerman                       __func__, addr);
100069958d8aSPaul Zimmerman         return;
100169958d8aSPaul Zimmerman     }
100269958d8aSPaul Zimmerman 
1003153ef166SPaul Zimmerman     mmio = &s->hreg1[index];
1004153ef166SPaul Zimmerman     old = *mmio;
1005153ef166SPaul Zimmerman 
1006153ef166SPaul Zimmerman     switch (HSOTG_REG(0x500) + (addr & 0x1c)) {
1007153ef166SPaul Zimmerman     case HCCHAR(0):
1008153ef166SPaul Zimmerman         if ((val & HCCHAR_CHDIS) && !(old & HCCHAR_CHDIS)) {
1009153ef166SPaul Zimmerman             val &= ~(HCCHAR_CHENA | HCCHAR_CHDIS);
1010153ef166SPaul Zimmerman             disflg = 1;
1011153ef166SPaul Zimmerman         } else {
1012153ef166SPaul Zimmerman             val |= old & HCCHAR_CHDIS;
1013153ef166SPaul Zimmerman             if ((val & HCCHAR_CHENA) && !(old & HCCHAR_CHENA)) {
1014153ef166SPaul Zimmerman                 val &= ~HCCHAR_CHDIS;
1015153ef166SPaul Zimmerman                 enflg = 1;
1016153ef166SPaul Zimmerman             } else {
1017153ef166SPaul Zimmerman                 val |= old & HCCHAR_CHENA;
1018153ef166SPaul Zimmerman             }
1019153ef166SPaul Zimmerman         }
1020153ef166SPaul Zimmerman         break;
1021153ef166SPaul Zimmerman     case HCINT(0):
1022153ef166SPaul Zimmerman         /* clear the write-1-to-clear bits */
1023153ef166SPaul Zimmerman         val |= ~old;
1024153ef166SPaul Zimmerman         val = ~val;
1025153ef166SPaul Zimmerman         val &= ~HCINTMSK_RESERVED14_31;
1026153ef166SPaul Zimmerman         iflg = 1;
1027153ef166SPaul Zimmerman         break;
1028153ef166SPaul Zimmerman     case HCINTMSK(0):
1029153ef166SPaul Zimmerman         val &= ~HCINTMSK_RESERVED14_31;
1030153ef166SPaul Zimmerman         iflg = 1;
1031153ef166SPaul Zimmerman         break;
1032153ef166SPaul Zimmerman     case HCDMAB(0):
1033153ef166SPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: write to read-only register\n",
1034153ef166SPaul Zimmerman                       __func__);
1035153ef166SPaul Zimmerman         return;
1036153ef166SPaul Zimmerman     default:
1037153ef166SPaul Zimmerman         break;
1038153ef166SPaul Zimmerman     }
1039153ef166SPaul Zimmerman 
1040153ef166SPaul Zimmerman     trace_usb_dwc2_hreg1_write(addr, hreg1nm[index & 7], index >> 3, orig,
1041153ef166SPaul Zimmerman                                old, val);
1042153ef166SPaul Zimmerman     *mmio = val;
1043153ef166SPaul Zimmerman 
1044153ef166SPaul Zimmerman     if (disflg) {
1045153ef166SPaul Zimmerman         /* set ChHltd in HCINT */
1046153ef166SPaul Zimmerman         s->hreg1[(index & ~7) + 2] |= HCINTMSK_CHHLTD;
1047153ef166SPaul Zimmerman         iflg = 1;
1048153ef166SPaul Zimmerman     }
1049153ef166SPaul Zimmerman 
1050153ef166SPaul Zimmerman     if (enflg) {
1051153ef166SPaul Zimmerman         dwc2_enable_chan(s, index & ~7);
1052153ef166SPaul Zimmerman     }
1053153ef166SPaul Zimmerman 
1054153ef166SPaul Zimmerman     if (iflg) {
1055153ef166SPaul Zimmerman         dwc2_update_hc_irq(s, index & ~7);
1056153ef166SPaul Zimmerman     }
1057153ef166SPaul Zimmerman }
1058153ef166SPaul Zimmerman 
1059153ef166SPaul Zimmerman static const char *pcgregnm[] = {
1060153ef166SPaul Zimmerman         "PCGCTL   ", "PCGCCTL1 "
1061153ef166SPaul Zimmerman };
1062153ef166SPaul Zimmerman 
dwc2_pcgreg_read(void * ptr,hwaddr addr,int index,unsigned size)1063153ef166SPaul Zimmerman static uint64_t dwc2_pcgreg_read(void *ptr, hwaddr addr, int index,
1064153ef166SPaul Zimmerman                                  unsigned size)
1065153ef166SPaul Zimmerman {
1066153ef166SPaul Zimmerman     DWC2State *s = ptr;
1067153ef166SPaul Zimmerman     uint32_t val;
1068153ef166SPaul Zimmerman 
106969958d8aSPaul Zimmerman     if (addr < PCGCTL || addr > PCGCCTL1) {
107069958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
107169958d8aSPaul Zimmerman                       __func__, addr);
107269958d8aSPaul Zimmerman         return 0;
107369958d8aSPaul Zimmerman     }
107469958d8aSPaul Zimmerman 
1075153ef166SPaul Zimmerman     val = s->pcgreg[index];
1076153ef166SPaul Zimmerman 
1077153ef166SPaul Zimmerman     trace_usb_dwc2_pcgreg_read(addr, pcgregnm[index], val);
1078153ef166SPaul Zimmerman     return val;
1079153ef166SPaul Zimmerman }
1080153ef166SPaul Zimmerman 
dwc2_pcgreg_write(void * ptr,hwaddr addr,int index,uint64_t val,unsigned size)1081153ef166SPaul Zimmerman static void dwc2_pcgreg_write(void *ptr, hwaddr addr, int index,
1082153ef166SPaul Zimmerman                               uint64_t val, unsigned size)
1083153ef166SPaul Zimmerman {
1084153ef166SPaul Zimmerman     DWC2State *s = ptr;
1085153ef166SPaul Zimmerman     uint64_t orig = val;
1086153ef166SPaul Zimmerman     uint32_t *mmio;
1087153ef166SPaul Zimmerman     uint32_t old;
1088153ef166SPaul Zimmerman 
108969958d8aSPaul Zimmerman     if (addr < PCGCTL || addr > PCGCCTL1) {
109069958d8aSPaul Zimmerman         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
109169958d8aSPaul Zimmerman                       __func__, addr);
109269958d8aSPaul Zimmerman         return;
109369958d8aSPaul Zimmerman     }
109469958d8aSPaul Zimmerman 
1095153ef166SPaul Zimmerman     mmio = &s->pcgreg[index];
1096153ef166SPaul Zimmerman     old = *mmio;
1097153ef166SPaul Zimmerman 
1098153ef166SPaul Zimmerman     trace_usb_dwc2_pcgreg_write(addr, pcgregnm[index], orig, old, val);
1099153ef166SPaul Zimmerman     *mmio = val;
1100153ef166SPaul Zimmerman }
1101153ef166SPaul Zimmerman 
dwc2_hsotg_read(void * ptr,hwaddr addr,unsigned size)1102153ef166SPaul Zimmerman static uint64_t dwc2_hsotg_read(void *ptr, hwaddr addr, unsigned size)
1103153ef166SPaul Zimmerman {
1104153ef166SPaul Zimmerman     uint64_t val;
1105153ef166SPaul Zimmerman 
1106153ef166SPaul Zimmerman     switch (addr) {
1107153ef166SPaul Zimmerman     case HSOTG_REG(0x000) ... HSOTG_REG(0x0fc):
1108153ef166SPaul Zimmerman         val = dwc2_glbreg_read(ptr, addr, (addr - HSOTG_REG(0x000)) >> 2, size);
1109153ef166SPaul Zimmerman         break;
1110153ef166SPaul Zimmerman     case HSOTG_REG(0x100):
1111153ef166SPaul Zimmerman         val = dwc2_fszreg_read(ptr, addr, (addr - HSOTG_REG(0x100)) >> 2, size);
1112153ef166SPaul Zimmerman         break;
1113153ef166SPaul Zimmerman     case HSOTG_REG(0x104) ... HSOTG_REG(0x3fc):
1114153ef166SPaul Zimmerman         /* Gadget-mode registers, just return 0 for now */
1115153ef166SPaul Zimmerman         val = 0;
1116153ef166SPaul Zimmerman         break;
1117153ef166SPaul Zimmerman     case HSOTG_REG(0x400) ... HSOTG_REG(0x4fc):
1118153ef166SPaul Zimmerman         val = dwc2_hreg0_read(ptr, addr, (addr - HSOTG_REG(0x400)) >> 2, size);
1119153ef166SPaul Zimmerman         break;
1120153ef166SPaul Zimmerman     case HSOTG_REG(0x500) ... HSOTG_REG(0x7fc):
1121153ef166SPaul Zimmerman         val = dwc2_hreg1_read(ptr, addr, (addr - HSOTG_REG(0x500)) >> 2, size);
1122153ef166SPaul Zimmerman         break;
1123153ef166SPaul Zimmerman     case HSOTG_REG(0x800) ... HSOTG_REG(0xdfc):
1124153ef166SPaul Zimmerman         /* Gadget-mode registers, just return 0 for now */
1125153ef166SPaul Zimmerman         val = 0;
1126153ef166SPaul Zimmerman         break;
1127153ef166SPaul Zimmerman     case HSOTG_REG(0xe00) ... HSOTG_REG(0xffc):
1128153ef166SPaul Zimmerman         val = dwc2_pcgreg_read(ptr, addr, (addr - HSOTG_REG(0xe00)) >> 2, size);
1129153ef166SPaul Zimmerman         break;
1130153ef166SPaul Zimmerman     default:
1131153ef166SPaul Zimmerman         g_assert_not_reached();
1132153ef166SPaul Zimmerman     }
1133153ef166SPaul Zimmerman 
1134153ef166SPaul Zimmerman     return val;
1135153ef166SPaul Zimmerman }
1136153ef166SPaul Zimmerman 
dwc2_hsotg_write(void * ptr,hwaddr addr,uint64_t val,unsigned size)1137153ef166SPaul Zimmerman static void dwc2_hsotg_write(void *ptr, hwaddr addr, uint64_t val,
1138153ef166SPaul Zimmerman                              unsigned size)
1139153ef166SPaul Zimmerman {
1140153ef166SPaul Zimmerman     switch (addr) {
1141153ef166SPaul Zimmerman     case HSOTG_REG(0x000) ... HSOTG_REG(0x0fc):
1142153ef166SPaul Zimmerman         dwc2_glbreg_write(ptr, addr, (addr - HSOTG_REG(0x000)) >> 2, val, size);
1143153ef166SPaul Zimmerman         break;
1144153ef166SPaul Zimmerman     case HSOTG_REG(0x100):
1145153ef166SPaul Zimmerman         dwc2_fszreg_write(ptr, addr, (addr - HSOTG_REG(0x100)) >> 2, val, size);
1146153ef166SPaul Zimmerman         break;
1147153ef166SPaul Zimmerman     case HSOTG_REG(0x104) ... HSOTG_REG(0x3fc):
1148153ef166SPaul Zimmerman         /* Gadget-mode registers, do nothing for now */
1149153ef166SPaul Zimmerman         break;
1150153ef166SPaul Zimmerman     case HSOTG_REG(0x400) ... HSOTG_REG(0x4fc):
1151153ef166SPaul Zimmerman         dwc2_hreg0_write(ptr, addr, (addr - HSOTG_REG(0x400)) >> 2, val, size);
1152153ef166SPaul Zimmerman         break;
1153153ef166SPaul Zimmerman     case HSOTG_REG(0x500) ... HSOTG_REG(0x7fc):
1154153ef166SPaul Zimmerman         dwc2_hreg1_write(ptr, addr, (addr - HSOTG_REG(0x500)) >> 2, val, size);
1155153ef166SPaul Zimmerman         break;
1156153ef166SPaul Zimmerman     case HSOTG_REG(0x800) ... HSOTG_REG(0xdfc):
1157153ef166SPaul Zimmerman         /* Gadget-mode registers, do nothing for now */
1158153ef166SPaul Zimmerman         break;
1159153ef166SPaul Zimmerman     case HSOTG_REG(0xe00) ... HSOTG_REG(0xffc):
1160153ef166SPaul Zimmerman         dwc2_pcgreg_write(ptr, addr, (addr - HSOTG_REG(0xe00)) >> 2, val, size);
1161153ef166SPaul Zimmerman         break;
1162153ef166SPaul Zimmerman     default:
1163153ef166SPaul Zimmerman         g_assert_not_reached();
1164153ef166SPaul Zimmerman     }
1165153ef166SPaul Zimmerman }
1166153ef166SPaul Zimmerman 
1167153ef166SPaul Zimmerman static const MemoryRegionOps dwc2_mmio_hsotg_ops = {
1168153ef166SPaul Zimmerman     .read = dwc2_hsotg_read,
1169153ef166SPaul Zimmerman     .write = dwc2_hsotg_write,
1170153ef166SPaul Zimmerman     .impl.min_access_size = 4,
1171153ef166SPaul Zimmerman     .impl.max_access_size = 4,
1172153ef166SPaul Zimmerman     .endianness = DEVICE_LITTLE_ENDIAN,
1173153ef166SPaul Zimmerman };
1174153ef166SPaul Zimmerman 
dwc2_hreg2_read(void * ptr,hwaddr addr,unsigned size)1175153ef166SPaul Zimmerman static uint64_t dwc2_hreg2_read(void *ptr, hwaddr addr, unsigned size)
1176153ef166SPaul Zimmerman {
1177153ef166SPaul Zimmerman     /* TODO - implement FIFOs to support slave mode */
1178153ef166SPaul Zimmerman     trace_usb_dwc2_hreg2_read(addr, addr >> 12, 0);
117969958d8aSPaul Zimmerman     qemu_log_mask(LOG_UNIMP, "%s: FIFO read not implemented\n", __func__);
1180153ef166SPaul Zimmerman     return 0;
1181153ef166SPaul Zimmerman }
1182153ef166SPaul Zimmerman 
dwc2_hreg2_write(void * ptr,hwaddr addr,uint64_t val,unsigned size)1183153ef166SPaul Zimmerman static void dwc2_hreg2_write(void *ptr, hwaddr addr, uint64_t val,
1184153ef166SPaul Zimmerman                              unsigned size)
1185153ef166SPaul Zimmerman {
1186153ef166SPaul Zimmerman     uint64_t orig = val;
1187153ef166SPaul Zimmerman 
1188153ef166SPaul Zimmerman     /* TODO - implement FIFOs to support slave mode */
1189153ef166SPaul Zimmerman     trace_usb_dwc2_hreg2_write(addr, addr >> 12, orig, 0, val);
119069958d8aSPaul Zimmerman     qemu_log_mask(LOG_UNIMP, "%s: FIFO write not implemented\n", __func__);
1191153ef166SPaul Zimmerman }
1192153ef166SPaul Zimmerman 
1193153ef166SPaul Zimmerman static const MemoryRegionOps dwc2_mmio_hreg2_ops = {
1194153ef166SPaul Zimmerman     .read = dwc2_hreg2_read,
1195153ef166SPaul Zimmerman     .write = dwc2_hreg2_write,
1196153ef166SPaul Zimmerman     .impl.min_access_size = 4,
1197153ef166SPaul Zimmerman     .impl.max_access_size = 4,
1198153ef166SPaul Zimmerman     .endianness = DEVICE_LITTLE_ENDIAN,
1199153ef166SPaul Zimmerman };
1200153ef166SPaul Zimmerman 
dwc2_wakeup_endpoint(USBBus * bus,USBEndpoint * ep,unsigned int stream)1201153ef166SPaul Zimmerman static void dwc2_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
1202153ef166SPaul Zimmerman                                  unsigned int stream)
1203153ef166SPaul Zimmerman {
1204153ef166SPaul Zimmerman     DWC2State *s = container_of(bus, DWC2State, bus);
1205153ef166SPaul Zimmerman 
1206153ef166SPaul Zimmerman     trace_usb_dwc2_wakeup_endpoint(ep, stream);
1207153ef166SPaul Zimmerman 
1208153ef166SPaul Zimmerman     /* TODO - do something here? */
1209153ef166SPaul Zimmerman     qemu_bh_schedule(s->async_bh);
1210153ef166SPaul Zimmerman }
1211153ef166SPaul Zimmerman 
1212153ef166SPaul Zimmerman static USBBusOps dwc2_bus_ops = {
1213153ef166SPaul Zimmerman     .wakeup_endpoint = dwc2_wakeup_endpoint,
1214153ef166SPaul Zimmerman };
1215153ef166SPaul Zimmerman 
dwc2_work_timer(void * opaque)1216153ef166SPaul Zimmerman static void dwc2_work_timer(void *opaque)
1217153ef166SPaul Zimmerman {
1218153ef166SPaul Zimmerman     DWC2State *s = opaque;
1219153ef166SPaul Zimmerman 
1220153ef166SPaul Zimmerman     trace_usb_dwc2_work_timer();
1221153ef166SPaul Zimmerman     qemu_bh_schedule(s->async_bh);
1222153ef166SPaul Zimmerman }
1223153ef166SPaul Zimmerman 
dwc2_reset_enter(Object * obj,ResetType type)1224153ef166SPaul Zimmerman static void dwc2_reset_enter(Object *obj, ResetType type)
1225153ef166SPaul Zimmerman {
122679f6cf7eSEduardo Habkost     DWC2Class *c = DWC2_USB_GET_CLASS(obj);
1227153ef166SPaul Zimmerman     DWC2State *s = DWC2_USB(obj);
1228153ef166SPaul Zimmerman     int i;
1229153ef166SPaul Zimmerman 
1230153ef166SPaul Zimmerman     trace_usb_dwc2_reset_enter();
1231153ef166SPaul Zimmerman 
1232153ef166SPaul Zimmerman     if (c->parent_phases.enter) {
1233153ef166SPaul Zimmerman         c->parent_phases.enter(obj, type);
1234153ef166SPaul Zimmerman     }
1235153ef166SPaul Zimmerman 
1236153ef166SPaul Zimmerman     timer_del(s->frame_timer);
1237153ef166SPaul Zimmerman     qemu_bh_cancel(s->async_bh);
1238153ef166SPaul Zimmerman 
1239153ef166SPaul Zimmerman     if (s->uport.dev && s->uport.dev->attached) {
1240153ef166SPaul Zimmerman         usb_detach(&s->uport);
1241153ef166SPaul Zimmerman     }
1242153ef166SPaul Zimmerman 
1243153ef166SPaul Zimmerman     dwc2_bus_stop(s);
1244153ef166SPaul Zimmerman 
1245153ef166SPaul Zimmerman     s->gotgctl = GOTGCTL_BSESVLD | GOTGCTL_ASESVLD | GOTGCTL_CONID_B;
1246153ef166SPaul Zimmerman     s->gotgint = 0;
1247153ef166SPaul Zimmerman     s->gahbcfg = 0;
1248153ef166SPaul Zimmerman     s->gusbcfg = 5 << GUSBCFG_USBTRDTIM_SHIFT;
1249153ef166SPaul Zimmerman     s->grstctl = GRSTCTL_AHBIDLE;
1250153ef166SPaul Zimmerman     s->gintsts = GINTSTS_CONIDSTSCHNG | GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP |
1251153ef166SPaul Zimmerman                  GINTSTS_CURMODE_HOST;
1252153ef166SPaul Zimmerman     s->gintmsk = 0;
1253153ef166SPaul Zimmerman     s->grxstsr = 0;
1254153ef166SPaul Zimmerman     s->grxstsp = 0;
1255153ef166SPaul Zimmerman     s->grxfsiz = 1024;
1256153ef166SPaul Zimmerman     s->gnptxfsiz = 1024 << FIFOSIZE_DEPTH_SHIFT;
1257153ef166SPaul Zimmerman     s->gnptxsts = (4 << FIFOSIZE_DEPTH_SHIFT) | 1024;
1258153ef166SPaul Zimmerman     s->gi2cctl = GI2CCTL_I2CDATSE0 | GI2CCTL_ACK;
1259153ef166SPaul Zimmerman     s->gpvndctl = 0;
1260153ef166SPaul Zimmerman     s->ggpio = 0;
1261153ef166SPaul Zimmerman     s->guid = 0;
1262153ef166SPaul Zimmerman     s->gsnpsid = 0x4f54294a;
1263153ef166SPaul Zimmerman     s->ghwcfg1 = 0;
1264153ef166SPaul Zimmerman     s->ghwcfg2 = (8 << GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT) |
1265153ef166SPaul Zimmerman                  (4 << GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT) |
1266153ef166SPaul Zimmerman                  (4 << GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT) |
1267153ef166SPaul Zimmerman                  GHWCFG2_DYNAMIC_FIFO |
1268153ef166SPaul Zimmerman                  GHWCFG2_PERIO_EP_SUPPORTED |
1269153ef166SPaul Zimmerman                  ((DWC2_NB_CHAN - 1) << GHWCFG2_NUM_HOST_CHAN_SHIFT) |
1270153ef166SPaul Zimmerman                  (GHWCFG2_INT_DMA_ARCH << GHWCFG2_ARCHITECTURE_SHIFT) |
1271153ef166SPaul Zimmerman                  (GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST << GHWCFG2_OP_MODE_SHIFT);
1272153ef166SPaul Zimmerman     s->ghwcfg3 = (4096 << GHWCFG3_DFIFO_DEPTH_SHIFT) |
1273153ef166SPaul Zimmerman                  (4 << GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT) |
1274153ef166SPaul Zimmerman                  (4 << GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT);
1275153ef166SPaul Zimmerman     s->ghwcfg4 = 0;
1276153ef166SPaul Zimmerman     s->glpmcfg = 0;
1277153ef166SPaul Zimmerman     s->gpwrdn = GPWRDN_PWRDNRSTN;
1278153ef166SPaul Zimmerman     s->gdfifocfg = 0;
1279153ef166SPaul Zimmerman     s->gadpctl = 0;
1280153ef166SPaul Zimmerman     s->grefclk = 0;
1281153ef166SPaul Zimmerman     s->gintmsk2 = 0;
1282153ef166SPaul Zimmerman     s->gintsts2 = 0;
1283153ef166SPaul Zimmerman 
1284153ef166SPaul Zimmerman     s->hptxfsiz = 500 << FIFOSIZE_DEPTH_SHIFT;
1285153ef166SPaul Zimmerman 
1286153ef166SPaul Zimmerman     s->hcfg = 2 << HCFG_RESVALID_SHIFT;
1287153ef166SPaul Zimmerman     s->hfir = 60000;
1288153ef166SPaul Zimmerman     s->hfnum = 0x3fff;
1289153ef166SPaul Zimmerman     s->hptxsts = (16 << TXSTS_QSPCAVAIL_SHIFT) | 32768;
1290153ef166SPaul Zimmerman     s->haint = 0;
1291153ef166SPaul Zimmerman     s->haintmsk = 0;
1292153ef166SPaul Zimmerman     s->hprt0 = 0;
1293153ef166SPaul Zimmerman 
1294153ef166SPaul Zimmerman     memset(s->hreg1, 0, sizeof(s->hreg1));
1295153ef166SPaul Zimmerman     memset(s->pcgreg, 0, sizeof(s->pcgreg));
1296153ef166SPaul Zimmerman 
1297153ef166SPaul Zimmerman     s->sof_time = 0;
1298153ef166SPaul Zimmerman     s->frame_number = 0;
1299153ef166SPaul Zimmerman     s->fi = USB_FRMINTVL - 1;
1300153ef166SPaul Zimmerman     s->next_chan = 0;
1301153ef166SPaul Zimmerman     s->working = false;
1302153ef166SPaul Zimmerman 
1303153ef166SPaul Zimmerman     for (i = 0; i < DWC2_NB_CHAN; i++) {
1304153ef166SPaul Zimmerman         s->packet[i].needs_service = false;
1305153ef166SPaul Zimmerman     }
1306153ef166SPaul Zimmerman }
1307153ef166SPaul Zimmerman 
dwc2_reset_hold(Object * obj)1308153ef166SPaul Zimmerman static void dwc2_reset_hold(Object *obj)
1309153ef166SPaul Zimmerman {
131079f6cf7eSEduardo Habkost     DWC2Class *c = DWC2_USB_GET_CLASS(obj);
1311153ef166SPaul Zimmerman     DWC2State *s = DWC2_USB(obj);
1312153ef166SPaul Zimmerman 
1313153ef166SPaul Zimmerman     trace_usb_dwc2_reset_hold();
1314153ef166SPaul Zimmerman 
1315153ef166SPaul Zimmerman     if (c->parent_phases.hold) {
1316153ef166SPaul Zimmerman         c->parent_phases.hold(obj);
1317153ef166SPaul Zimmerman     }
1318153ef166SPaul Zimmerman 
1319153ef166SPaul Zimmerman     dwc2_update_irq(s);
1320153ef166SPaul Zimmerman }
1321153ef166SPaul Zimmerman 
dwc2_reset_exit(Object * obj)1322153ef166SPaul Zimmerman static void dwc2_reset_exit(Object *obj)
1323153ef166SPaul Zimmerman {
132479f6cf7eSEduardo Habkost     DWC2Class *c = DWC2_USB_GET_CLASS(obj);
1325153ef166SPaul Zimmerman     DWC2State *s = DWC2_USB(obj);
1326153ef166SPaul Zimmerman 
1327153ef166SPaul Zimmerman     trace_usb_dwc2_reset_exit();
1328153ef166SPaul Zimmerman 
1329153ef166SPaul Zimmerman     if (c->parent_phases.exit) {
1330153ef166SPaul Zimmerman         c->parent_phases.exit(obj);
1331153ef166SPaul Zimmerman     }
1332153ef166SPaul Zimmerman 
1333153ef166SPaul Zimmerman     s->hprt0 = HPRT0_PWR;
1334153ef166SPaul Zimmerman     if (s->uport.dev && s->uport.dev->attached) {
1335153ef166SPaul Zimmerman         usb_attach(&s->uport);
1336153ef166SPaul Zimmerman         usb_device_reset(s->uport.dev);
1337153ef166SPaul Zimmerman     }
1338153ef166SPaul Zimmerman }
1339153ef166SPaul Zimmerman 
dwc2_realize(DeviceState * dev,Error ** errp)1340153ef166SPaul Zimmerman static void dwc2_realize(DeviceState *dev, Error **errp)
1341153ef166SPaul Zimmerman {
1342153ef166SPaul Zimmerman     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
1343153ef166SPaul Zimmerman     DWC2State *s = DWC2_USB(dev);
1344153ef166SPaul Zimmerman     Object *obj;
1345153ef166SPaul Zimmerman 
13464d21fcd5SMarkus Armbruster     obj = object_property_get_link(OBJECT(dev), "dma-mr", &error_abort);
1347153ef166SPaul Zimmerman 
1348153ef166SPaul Zimmerman     s->dma_mr = MEMORY_REGION(obj);
1349153ef166SPaul Zimmerman     address_space_init(&s->dma_as, s->dma_mr, "dwc2");
1350153ef166SPaul Zimmerman 
1351153ef166SPaul Zimmerman     usb_bus_new(&s->bus, sizeof(s->bus), &dwc2_bus_ops, dev);
1352153ef166SPaul Zimmerman     usb_register_port(&s->bus, &s->uport, s, 0, &dwc2_port_ops,
1353153ef166SPaul Zimmerman                       USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL |
1354153ef166SPaul Zimmerman                       (s->usb_version == 2 ? USB_SPEED_MASK_HIGH : 0));
1355153ef166SPaul Zimmerman     s->uport.dev = 0;
1356153ef166SPaul Zimmerman 
1357153ef166SPaul Zimmerman     s->usb_frame_time = NANOSECONDS_PER_SECOND / 1000;          /* 1000000 */
1358153ef166SPaul Zimmerman     if (NANOSECONDS_PER_SECOND >= USB_HZ_FS) {
1359153ef166SPaul Zimmerman         s->usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ_FS;   /* 83.3 */
1360153ef166SPaul Zimmerman     } else {
1361153ef166SPaul Zimmerman         s->usb_bit_time = 1;
1362153ef166SPaul Zimmerman     }
1363153ef166SPaul Zimmerman 
1364153ef166SPaul Zimmerman     s->fi = USB_FRMINTVL - 1;
1365153ef166SPaul Zimmerman     s->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, dwc2_frame_boundary, s);
1366153ef166SPaul Zimmerman     s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, dwc2_work_timer, s);
1367*f63192b0SAlexander Bulekov     s->async_bh = qemu_bh_new_guarded(dwc2_work_bh, s,
1368*f63192b0SAlexander Bulekov                                       &dev->mem_reentrancy_guard);
1369153ef166SPaul Zimmerman 
1370153ef166SPaul Zimmerman     sysbus_init_irq(sbd, &s->irq);
1371153ef166SPaul Zimmerman }
1372153ef166SPaul Zimmerman 
dwc2_init(Object * obj)1373153ef166SPaul Zimmerman static void dwc2_init(Object *obj)
1374153ef166SPaul Zimmerman {
1375153ef166SPaul Zimmerman     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1376153ef166SPaul Zimmerman     DWC2State *s = DWC2_USB(obj);
1377153ef166SPaul Zimmerman 
1378153ef166SPaul Zimmerman     memory_region_init(&s->container, obj, "dwc2", DWC2_MMIO_SIZE);
1379153ef166SPaul Zimmerman     sysbus_init_mmio(sbd, &s->container);
1380153ef166SPaul Zimmerman 
1381153ef166SPaul Zimmerman     memory_region_init_io(&s->hsotg, obj, &dwc2_mmio_hsotg_ops, s,
1382153ef166SPaul Zimmerman                           "dwc2-io", 4 * KiB);
1383153ef166SPaul Zimmerman     memory_region_add_subregion(&s->container, 0x0000, &s->hsotg);
1384153ef166SPaul Zimmerman 
1385153ef166SPaul Zimmerman     memory_region_init_io(&s->fifos, obj, &dwc2_mmio_hreg2_ops, s,
1386153ef166SPaul Zimmerman                           "dwc2-fifo", 64 * KiB);
1387153ef166SPaul Zimmerman     memory_region_add_subregion(&s->container, 0x1000, &s->fifos);
1388153ef166SPaul Zimmerman }
1389153ef166SPaul Zimmerman 
1390153ef166SPaul Zimmerman static const VMStateDescription vmstate_dwc2_state_packet = {
1391153ef166SPaul Zimmerman     .name = "dwc2/packet",
1392153ef166SPaul Zimmerman     .version_id = 1,
1393153ef166SPaul Zimmerman     .minimum_version_id = 1,
1394153ef166SPaul Zimmerman     .fields = (VMStateField[]) {
1395153ef166SPaul Zimmerman         VMSTATE_UINT32(devadr, DWC2Packet),
1396153ef166SPaul Zimmerman         VMSTATE_UINT32(epnum, DWC2Packet),
1397153ef166SPaul Zimmerman         VMSTATE_UINT32(epdir, DWC2Packet),
1398153ef166SPaul Zimmerman         VMSTATE_UINT32(mps, DWC2Packet),
1399153ef166SPaul Zimmerman         VMSTATE_UINT32(pid, DWC2Packet),
1400153ef166SPaul Zimmerman         VMSTATE_UINT32(index, DWC2Packet),
1401153ef166SPaul Zimmerman         VMSTATE_UINT32(pcnt, DWC2Packet),
1402153ef166SPaul Zimmerman         VMSTATE_UINT32(len, DWC2Packet),
1403153ef166SPaul Zimmerman         VMSTATE_INT32(async, DWC2Packet),
1404153ef166SPaul Zimmerman         VMSTATE_BOOL(small, DWC2Packet),
1405153ef166SPaul Zimmerman         VMSTATE_BOOL(needs_service, DWC2Packet),
1406153ef166SPaul Zimmerman         VMSTATE_END_OF_LIST()
1407153ef166SPaul Zimmerman     },
1408153ef166SPaul Zimmerman };
1409153ef166SPaul Zimmerman 
1410153ef166SPaul Zimmerman const VMStateDescription vmstate_dwc2_state = {
1411153ef166SPaul Zimmerman     .name = "dwc2",
1412153ef166SPaul Zimmerman     .version_id = 1,
1413153ef166SPaul Zimmerman     .minimum_version_id = 1,
1414153ef166SPaul Zimmerman     .fields = (VMStateField[]) {
1415153ef166SPaul Zimmerman         VMSTATE_UINT32_ARRAY(glbreg, DWC2State,
1416153ef166SPaul Zimmerman                              DWC2_GLBREG_SIZE / sizeof(uint32_t)),
1417153ef166SPaul Zimmerman         VMSTATE_UINT32_ARRAY(fszreg, DWC2State,
1418153ef166SPaul Zimmerman                              DWC2_FSZREG_SIZE / sizeof(uint32_t)),
1419153ef166SPaul Zimmerman         VMSTATE_UINT32_ARRAY(hreg0, DWC2State,
1420153ef166SPaul Zimmerman                              DWC2_HREG0_SIZE / sizeof(uint32_t)),
1421153ef166SPaul Zimmerman         VMSTATE_UINT32_ARRAY(hreg1, DWC2State,
1422153ef166SPaul Zimmerman                              DWC2_HREG1_SIZE / sizeof(uint32_t)),
1423153ef166SPaul Zimmerman         VMSTATE_UINT32_ARRAY(pcgreg, DWC2State,
1424153ef166SPaul Zimmerman                              DWC2_PCGREG_SIZE / sizeof(uint32_t)),
1425153ef166SPaul Zimmerman 
1426153ef166SPaul Zimmerman         VMSTATE_TIMER_PTR(eof_timer, DWC2State),
1427153ef166SPaul Zimmerman         VMSTATE_TIMER_PTR(frame_timer, DWC2State),
1428153ef166SPaul Zimmerman         VMSTATE_INT64(sof_time, DWC2State),
1429153ef166SPaul Zimmerman         VMSTATE_INT64(usb_frame_time, DWC2State),
1430153ef166SPaul Zimmerman         VMSTATE_INT64(usb_bit_time, DWC2State),
1431153ef166SPaul Zimmerman         VMSTATE_UINT32(usb_version, DWC2State),
1432153ef166SPaul Zimmerman         VMSTATE_UINT16(frame_number, DWC2State),
1433153ef166SPaul Zimmerman         VMSTATE_UINT16(fi, DWC2State),
1434153ef166SPaul Zimmerman         VMSTATE_UINT16(next_chan, DWC2State),
1435153ef166SPaul Zimmerman         VMSTATE_BOOL(working, DWC2State),
1436153ef166SPaul Zimmerman 
1437153ef166SPaul Zimmerman         VMSTATE_STRUCT_ARRAY(packet, DWC2State, DWC2_NB_CHAN, 1,
1438153ef166SPaul Zimmerman                              vmstate_dwc2_state_packet, DWC2Packet),
1439153ef166SPaul Zimmerman         VMSTATE_UINT8_2DARRAY(usb_buf, DWC2State, DWC2_NB_CHAN,
1440153ef166SPaul Zimmerman                               DWC2_MAX_XFER_SIZE),
1441153ef166SPaul Zimmerman 
1442153ef166SPaul Zimmerman         VMSTATE_END_OF_LIST()
1443153ef166SPaul Zimmerman     }
1444153ef166SPaul Zimmerman };
1445153ef166SPaul Zimmerman 
1446153ef166SPaul Zimmerman static Property dwc2_usb_properties[] = {
1447153ef166SPaul Zimmerman     DEFINE_PROP_UINT32("usb_version", DWC2State, usb_version, 2),
1448153ef166SPaul Zimmerman     DEFINE_PROP_END_OF_LIST(),
1449153ef166SPaul Zimmerman };
1450153ef166SPaul Zimmerman 
dwc2_class_init(ObjectClass * klass,void * data)1451153ef166SPaul Zimmerman static void dwc2_class_init(ObjectClass *klass, void *data)
1452153ef166SPaul Zimmerman {
1453153ef166SPaul Zimmerman     DeviceClass *dc = DEVICE_CLASS(klass);
145479f6cf7eSEduardo Habkost     DWC2Class *c = DWC2_USB_CLASS(klass);
1455153ef166SPaul Zimmerman     ResettableClass *rc = RESETTABLE_CLASS(klass);
1456153ef166SPaul Zimmerman 
1457153ef166SPaul Zimmerman     dc->realize = dwc2_realize;
1458153ef166SPaul Zimmerman     dc->vmsd = &vmstate_dwc2_state;
1459153ef166SPaul Zimmerman     set_bit(DEVICE_CATEGORY_USB, dc->categories);
1460153ef166SPaul Zimmerman     device_class_set_props(dc, dwc2_usb_properties);
1461153ef166SPaul Zimmerman     resettable_class_set_parent_phases(rc, dwc2_reset_enter, dwc2_reset_hold,
1462153ef166SPaul Zimmerman                                        dwc2_reset_exit, &c->parent_phases);
1463153ef166SPaul Zimmerman }
1464153ef166SPaul Zimmerman 
1465153ef166SPaul Zimmerman static const TypeInfo dwc2_usb_type_info = {
1466153ef166SPaul Zimmerman     .name          = TYPE_DWC2_USB,
1467153ef166SPaul Zimmerman     .parent        = TYPE_SYS_BUS_DEVICE,
1468153ef166SPaul Zimmerman     .instance_size = sizeof(DWC2State),
1469153ef166SPaul Zimmerman     .instance_init = dwc2_init,
1470153ef166SPaul Zimmerman     .class_size    = sizeof(DWC2Class),
1471153ef166SPaul Zimmerman     .class_init    = dwc2_class_init,
1472153ef166SPaul Zimmerman };
1473153ef166SPaul Zimmerman 
dwc2_usb_register_types(void)1474153ef166SPaul Zimmerman static void dwc2_usb_register_types(void)
1475153ef166SPaul Zimmerman {
1476153ef166SPaul Zimmerman     type_register_static(&dwc2_usb_type_info);
1477153ef166SPaul Zimmerman }
1478153ef166SPaul Zimmerman 
1479153ef166SPaul Zimmerman type_init(dwc2_usb_register_types)
1480