2 * dwc-hsotg (dwc2) USB host controller emulation
4 * Based on hw/usb/hcd-ehci.c and hw/usb/hcd-ohci.c
6 * Note that to use this emulation with the dwc-otg driver in the
7 * Raspbian kernel, you must pass the option "dwc_otg.fiq_fsm_enable=0"
8 * on the kernel command line.
10 * Some useful documentation used to develop this emulation can be
11 * found online (as of April 2020) at:
13 * http://www.capital-micro.com/PDF/CME-M7_Family_User_Guide_EN.pdf
14 * which has a pretty complete description of the controller starting
17 * https://sourceforge.net/p/wive-ng/wive-ng-mt/ci/master/tree/docs/DataSheets/RT3050_5x_V2.0_081408_0902.pdf
18 * which has a description of the controller registers starting on
21 * Copyright (c) 2020 Paul Zimmerman <pauldzim@gmail.com>
23 * This program is free software; you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License as published by
25 * the Free Software Foundation; either version 2 of the License, or
26 * (at your option) any later version.
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
34 #include "qemu/osdep.h"
35 #include "qemu/units.h"
36 #include "qapi/error.h"
37 #include "hw/usb/dwc2-regs.h"
38 #include "hw/usb/hcd-dwc2.h"
39 #include "migration/vmstate.h"
42 #include "qemu/error-report.h"
43 #include "qemu/main-loop.h"
44 #include "hw/qdev-properties.h"
46 #define USB_HZ_FS 12000000
47 #define USB_HZ_HS 96000000
48 #define USB_FRMINTVL 12000
50 /* nifty macros from Arnon's EHCI version */
51 #define get_field(data, field) \
52 (((data) & field##_MASK) >> field##_SHIFT)
54 #define set_field(data, newval, field) do { \
55 uint32_t val = *(data); \
56 val &= ~field##_MASK; \
57 val |= ((newval) << field##_SHIFT) & field##_MASK; \
61 #define get_bit(data, bitmask) \
62 (!!((data) & (bitmask)))
65 static inline void dwc2_update_irq(DWC2State
*s
)
70 if ((s
->gintsts
& s
->gintmsk
) && (s
->gahbcfg
& GAHBCFG_GLBL_INTR_EN
)) {
73 if (level
!= oldlevel
) {
75 trace_usb_dwc2_update_irq(level
);
76 qemu_set_irq(s
->irq
, level
);
80 /* flag interrupt condition */
81 static inline void dwc2_raise_global_irq(DWC2State
*s
, uint32_t intr
)
83 if (!(s
->gintsts
& intr
)) {
85 trace_usb_dwc2_raise_global_irq(intr
);
90 static inline void dwc2_lower_global_irq(DWC2State
*s
, uint32_t intr
)
92 if (s
->gintsts
& intr
) {
94 trace_usb_dwc2_lower_global_irq(intr
);
99 static inline void dwc2_raise_host_irq(DWC2State
*s
, uint32_t host_intr
)
101 if (!(s
->haint
& host_intr
)) {
102 s
->haint
|= host_intr
;
104 trace_usb_dwc2_raise_host_irq(host_intr
);
105 if (s
->haint
& s
->haintmsk
) {
106 dwc2_raise_global_irq(s
, GINTSTS_HCHINT
);
111 static inline void dwc2_lower_host_irq(DWC2State
*s
, uint32_t host_intr
)
113 if (s
->haint
& host_intr
) {
114 s
->haint
&= ~host_intr
;
115 trace_usb_dwc2_lower_host_irq(host_intr
);
116 if (!(s
->haint
& s
->haintmsk
)) {
117 dwc2_lower_global_irq(s
, GINTSTS_HCHINT
);
122 static inline void dwc2_update_hc_irq(DWC2State
*s
, int index
)
124 uint32_t host_intr
= 1 << (index
>> 3);
126 if (s
->hreg1
[index
+ 2] & s
->hreg1
[index
+ 3]) {
127 dwc2_raise_host_irq(s
, host_intr
);
129 dwc2_lower_host_irq(s
, host_intr
);
133 /* set a timer for EOF */
134 static void dwc2_eof_timer(DWC2State
*s
)
136 timer_mod(s
->eof_timer
, s
->sof_time
+ s
->usb_frame_time
);
139 /* Set a timer for EOF and generate SOF event */
140 static void dwc2_sof(DWC2State
*s
)
142 s
->sof_time
+= s
->usb_frame_time
;
143 trace_usb_dwc2_sof(s
->sof_time
);
145 dwc2_raise_global_irq(s
, GINTSTS_SOF
);
148 /* Do frame processing on frame boundary */
149 static void dwc2_frame_boundary(void *opaque
)
151 DWC2State
*s
= opaque
;
155 now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
157 /* Frame boundary, so do EOF stuff here */
159 /* Increment frame number */
160 frcnt
= (uint16_t)((now
- s
->sof_time
) / s
->fi
);
161 s
->frame_number
= (s
->frame_number
+ frcnt
) & 0xffff;
162 s
->hfnum
= s
->frame_number
& HFNUM_MAX_FRNUM
;
164 /* Do SOF stuff here */
168 /* Start sending SOF tokens on the USB bus */
169 static void dwc2_bus_start(DWC2State
*s
)
171 trace_usb_dwc2_bus_start();
172 s
->sof_time
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
176 /* Stop sending SOF tokens on the USB bus */
177 static void dwc2_bus_stop(DWC2State
*s
)
179 trace_usb_dwc2_bus_stop();
180 timer_del(s
->eof_timer
);
183 static USBDevice
*dwc2_find_device(DWC2State
*s
, uint8_t addr
)
187 trace_usb_dwc2_find_device(addr
);
189 if (!(s
->hprt0
& HPRT0_ENA
)) {
190 trace_usb_dwc2_port_disabled(0);
192 dev
= usb_find_device(&s
->uport
, addr
);
194 trace_usb_dwc2_device_found(0);
199 trace_usb_dwc2_device_not_found();
203 static const char *pstatus
[] = {
204 "USB_RET_SUCCESS", "USB_RET_NODEV", "USB_RET_NAK", "USB_RET_STALL",
205 "USB_RET_BABBLE", "USB_RET_IOERROR", "USB_RET_ASYNC",
206 "USB_RET_ADD_TO_QUEUE", "USB_RET_REMOVE_FROM_QUEUE"
209 static uint32_t pintr
[] = {
210 HCINTMSK_XFERCOMPL
, HCINTMSK_XACTERR
, HCINTMSK_NAK
, HCINTMSK_STALL
,
211 HCINTMSK_BBLERR
, HCINTMSK_XACTERR
, HCINTMSK_XACTERR
, HCINTMSK_XACTERR
,
215 static const char *types
[] = {
216 "Ctrl", "Isoc", "Bulk", "Intr"
219 static const char *dirs
[] = {
223 static void dwc2_handle_packet(DWC2State
*s
, uint32_t devadr
, USBDevice
*dev
,
224 USBEndpoint
*ep
, uint32_t index
, bool send
)
227 uint32_t hcchar
= s
->hreg1
[index
];
228 uint32_t hctsiz
= s
->hreg1
[index
+ 4];
229 uint32_t hcdma
= s
->hreg1
[index
+ 5];
230 uint32_t chan
, epnum
, epdir
, eptype
, mps
, pid
, pcnt
, len
, tlen
, intr
= 0;
231 uint32_t tpcnt
, stsidx
, actual
= 0;
232 bool do_intr
= false, done
= false;
234 epnum
= get_field(hcchar
, HCCHAR_EPNUM
);
235 epdir
= get_bit(hcchar
, HCCHAR_EPDIR
);
236 eptype
= get_field(hcchar
, HCCHAR_EPTYPE
);
237 mps
= get_field(hcchar
, HCCHAR_MPS
);
238 pid
= get_field(hctsiz
, TSIZ_SC_MC_PID
);
239 pcnt
= get_field(hctsiz
, TSIZ_PKTCNT
);
240 len
= get_field(hctsiz
, TSIZ_XFERSIZE
);
241 assert(len
<= DWC2_MAX_XFER_SIZE
);
243 p
= &s
->packet
[chan
];
245 trace_usb_dwc2_handle_packet(chan
, dev
, &p
->packet
, epnum
, types
[eptype
],
246 dirs
[epdir
], mps
, len
, pcnt
);
248 if (eptype
== USB_ENDPOINT_XFER_CONTROL
&& pid
== TSIZ_SC_MC_PID_SETUP
) {
249 pid
= USB_TOKEN_SETUP
;
251 pid
= epdir
? USB_TOKEN_IN
: USB_TOKEN_OUT
;
262 if (pid
!= USB_TOKEN_IN
) {
263 trace_usb_dwc2_memory_read(hcdma
, tlen
);
264 if (dma_memory_read(&s
->dma_as
, hcdma
,
265 s
->usb_buf
[chan
], tlen
) != MEMTX_OK
) {
266 qemu_log_mask(LOG_GUEST_ERROR
, "%s: dma_memory_read failed\n",
271 usb_packet_init(&p
->packet
);
272 usb_packet_setup(&p
->packet
, pid
, ep
, 0, hcdma
,
273 pid
!= USB_TOKEN_IN
, true);
274 usb_packet_addbuf(&p
->packet
, s
->usb_buf
[chan
], tlen
);
275 p
->async
= DWC2_ASYNC_NONE
;
276 usb_handle_packet(dev
, &p
->packet
);
281 stsidx
= -p
->packet
.status
;
282 assert(stsidx
< sizeof(pstatus
) / sizeof(*pstatus
));
283 actual
= p
->packet
.actual_length
;
284 trace_usb_dwc2_packet_status(pstatus
[stsidx
], actual
);
287 if (p
->packet
.status
!= USB_RET_SUCCESS
&&
288 p
->packet
.status
!= USB_RET_NAK
&&
289 p
->packet
.status
!= USB_RET_STALL
&&
290 p
->packet
.status
!= USB_RET_ASYNC
) {
291 trace_usb_dwc2_packet_error(pstatus
[stsidx
]);
294 if (p
->packet
.status
== USB_RET_ASYNC
) {
295 trace_usb_dwc2_async_packet(&p
->packet
, chan
, dev
, epnum
,
297 usb_device_flush_ep_queue(dev
, ep
);
298 assert(p
->async
!= DWC2_ASYNC_INFLIGHT
);
307 p
->async
= DWC2_ASYNC_INFLIGHT
;
308 p
->needs_service
= false;
312 if (p
->packet
.status
== USB_RET_SUCCESS
) {
314 p
->packet
.status
= USB_RET_BABBLE
;
318 if (pid
== USB_TOKEN_IN
) {
319 trace_usb_dwc2_memory_write(hcdma
, actual
);
320 if (dma_memory_write(&s
->dma_as
, hcdma
, s
->usb_buf
[chan
],
321 actual
) != MEMTX_OK
) {
322 qemu_log_mask(LOG_GUEST_ERROR
, "%s: dma_memory_write failed\n",
327 tpcnt
= actual
/ mps
;
330 if (pid
== USB_TOKEN_IN
) {
335 pcnt
-= tpcnt
< pcnt
? tpcnt
: pcnt
;
336 set_field(&hctsiz
, pcnt
, TSIZ_PKTCNT
);
337 len
-= actual
< len
? actual
: len
;
338 set_field(&hctsiz
, len
, TSIZ_XFERSIZE
);
339 s
->hreg1
[index
+ 4] = hctsiz
;
341 s
->hreg1
[index
+ 5] = hcdma
;
343 if (!pcnt
|| len
== 0 || actual
== 0) {
347 intr
|= pintr
[stsidx
];
348 if (p
->packet
.status
== USB_RET_NAK
&&
349 (eptype
== USB_ENDPOINT_XFER_CONTROL
||
350 eptype
== USB_ENDPOINT_XFER_BULK
)) {
352 * for ctrl/bulk, automatically retry on NAK,
353 * but send the interrupt anyway
355 intr
&= ~HCINTMSK_RESERVED14_31
;
356 s
->hreg1
[index
+ 2] |= intr
;
359 intr
|= HCINTMSK_CHHLTD
;
364 usb_packet_cleanup(&p
->packet
);
367 hcchar
&= ~HCCHAR_CHENA
;
368 s
->hreg1
[index
] = hcchar
;
369 if (!(intr
& HCINTMSK_CHHLTD
)) {
370 intr
|= HCINTMSK_CHHLTD
| HCINTMSK_XFERCOMPL
;
372 intr
&= ~HCINTMSK_RESERVED14_31
;
373 s
->hreg1
[index
+ 2] |= intr
;
374 p
->needs_service
= false;
375 trace_usb_dwc2_packet_done(pstatus
[stsidx
], actual
, len
, pcnt
);
376 dwc2_update_hc_irq(s
, index
);
388 p
->needs_service
= true;
389 trace_usb_dwc2_packet_next(pstatus
[stsidx
], len
, pcnt
);
391 dwc2_update_hc_irq(s
, index
);
395 /* Attach or detach a device on root hub */
397 static const char *speeds
[] = {
398 "low", "full", "high"
401 static void dwc2_attach(USBPort
*port
)
403 DWC2State
*s
= port
->opaque
;
406 trace_usb_dwc2_attach(port
);
407 assert(port
->index
== 0);
409 if (!port
->dev
|| !port
->dev
->attached
) {
413 assert(port
->dev
->speed
<= USB_SPEED_HIGH
);
414 trace_usb_dwc2_attach_speed(speeds
[port
->dev
->speed
]);
415 s
->hprt0
&= ~HPRT0_SPD_MASK
;
417 switch (port
->dev
->speed
) {
419 s
->hprt0
|= HPRT0_SPD_LOW_SPEED
<< HPRT0_SPD_SHIFT
;
422 s
->hprt0
|= HPRT0_SPD_FULL_SPEED
<< HPRT0_SPD_SHIFT
;
425 s
->hprt0
|= HPRT0_SPD_HIGH_SPEED
<< HPRT0_SPD_SHIFT
;
431 s
->usb_frame_time
= NANOSECONDS_PER_SECOND
/ 8000; /* 125000 */
432 if (NANOSECONDS_PER_SECOND
>= USB_HZ_HS
) {
433 s
->usb_bit_time
= NANOSECONDS_PER_SECOND
/ USB_HZ_HS
; /* 10.4 */
438 s
->usb_frame_time
= NANOSECONDS_PER_SECOND
/ 1000; /* 1000000 */
439 if (NANOSECONDS_PER_SECOND
>= USB_HZ_FS
) {
440 s
->usb_bit_time
= NANOSECONDS_PER_SECOND
/ USB_HZ_FS
; /* 83.3 */
446 s
->fi
= USB_FRMINTVL
- 1;
447 s
->hprt0
|= HPRT0_CONNDET
| HPRT0_CONNSTS
;
450 dwc2_raise_global_irq(s
, GINTSTS_PRTINT
);
453 static void dwc2_detach(USBPort
*port
)
455 DWC2State
*s
= port
->opaque
;
457 trace_usb_dwc2_detach(port
);
458 assert(port
->index
== 0);
462 s
->hprt0
&= ~(HPRT0_SPD_MASK
| HPRT0_SUSP
| HPRT0_ENA
| HPRT0_CONNSTS
);
463 s
->hprt0
|= HPRT0_CONNDET
| HPRT0_ENACHG
;
465 dwc2_raise_global_irq(s
, GINTSTS_PRTINT
);
468 static void dwc2_child_detach(USBPort
*port
, USBDevice
*child
)
470 trace_usb_dwc2_child_detach(port
, child
);
471 assert(port
->index
== 0);
474 static void dwc2_wakeup(USBPort
*port
)
476 DWC2State
*s
= port
->opaque
;
478 trace_usb_dwc2_wakeup(port
);
479 assert(port
->index
== 0);
481 if (s
->hprt0
& HPRT0_SUSP
) {
482 s
->hprt0
|= HPRT0_RES
;
483 dwc2_raise_global_irq(s
, GINTSTS_PRTINT
);
486 qemu_bh_schedule(s
->async_bh
);
489 static void dwc2_async_packet_complete(USBPort
*port
, USBPacket
*packet
)
491 DWC2State
*s
= port
->opaque
;
496 assert(port
->index
== 0);
497 p
= container_of(packet
, DWC2Packet
, packet
);
498 dev
= dwc2_find_device(s
, p
->devadr
);
499 ep
= usb_ep_get(dev
, p
->pid
, p
->epnum
);
500 trace_usb_dwc2_async_packet_complete(port
, packet
, p
->index
>> 3, dev
,
501 p
->epnum
, dirs
[p
->epdir
], p
->len
);
502 assert(p
->async
== DWC2_ASYNC_INFLIGHT
);
504 if (packet
->status
== USB_RET_REMOVE_FROM_QUEUE
) {
505 usb_cancel_packet(packet
);
506 usb_packet_cleanup(packet
);
510 dwc2_handle_packet(s
, p
->devadr
, dev
, ep
, p
->index
, false);
512 p
->async
= DWC2_ASYNC_FINISHED
;
513 qemu_bh_schedule(s
->async_bh
);
516 static USBPortOps dwc2_port_ops
= {
517 .attach
= dwc2_attach
,
518 .detach
= dwc2_detach
,
519 .child_detach
= dwc2_child_detach
,
520 .wakeup
= dwc2_wakeup
,
521 .complete
= dwc2_async_packet_complete
,
524 static uint32_t dwc2_get_frame_remaining(DWC2State
*s
)
529 tks
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) - s
->sof_time
;
534 /* avoid muldiv if possible */
535 if (tks
>= s
->usb_frame_time
) {
538 if (tks
< s
->usb_bit_time
) {
543 /* tks = number of ns since SOF, divided by 83 (fs) or 10 (hs) */
544 tks
= tks
/ s
->usb_bit_time
;
545 if (tks
>= (int64_t)s
->fi
) {
549 /* remaining = frame interval minus tks */
550 fr
= (uint32_t)((int64_t)s
->fi
- tks
);
556 static void dwc2_work_bh(void *opaque
)
558 DWC2State
*s
= opaque
;
562 int64_t t_now
, expire_time
;
566 trace_usb_dwc2_work_bh();
572 t_now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
576 p
= &s
->packet
[chan
];
577 if (p
->needs_service
) {
578 dev
= dwc2_find_device(s
, p
->devadr
);
579 ep
= usb_ep_get(dev
, p
->pid
, p
->epnum
);
580 trace_usb_dwc2_work_bh_service(s
->next_chan
, chan
, dev
, p
->epnum
);
581 dwc2_handle_packet(s
, p
->devadr
, dev
, ep
, p
->index
, true);
584 if (++chan
== DWC2_NB_CHAN
) {
589 trace_usb_dwc2_work_bh_next(chan
);
591 } while (chan
!= s
->next_chan
);
594 expire_time
= t_now
+ NANOSECONDS_PER_SECOND
/ 4000;
595 timer_mod(s
->frame_timer
, expire_time
);
600 static void dwc2_enable_chan(DWC2State
*s
, uint32_t index
)
606 uint32_t devadr
, epnum
, epdir
, eptype
, pid
, len
;
609 assert((index
>> 3) < DWC2_NB_CHAN
);
610 p
= &s
->packet
[index
>> 3];
611 hcchar
= s
->hreg1
[index
];
612 hctsiz
= s
->hreg1
[index
+ 4];
613 devadr
= get_field(hcchar
, HCCHAR_DEVADDR
);
614 epnum
= get_field(hcchar
, HCCHAR_EPNUM
);
615 epdir
= get_bit(hcchar
, HCCHAR_EPDIR
);
616 eptype
= get_field(hcchar
, HCCHAR_EPTYPE
);
617 pid
= get_field(hctsiz
, TSIZ_SC_MC_PID
);
618 len
= get_field(hctsiz
, TSIZ_XFERSIZE
);
620 dev
= dwc2_find_device(s
, devadr
);
622 trace_usb_dwc2_enable_chan(index
>> 3, dev
, &p
->packet
, epnum
);
627 if (eptype
== USB_ENDPOINT_XFER_CONTROL
&& pid
== TSIZ_SC_MC_PID_SETUP
) {
628 pid
= USB_TOKEN_SETUP
;
630 pid
= epdir
? USB_TOKEN_IN
: USB_TOKEN_OUT
;
633 ep
= usb_ep_get(dev
, pid
, epnum
);
636 * Hack: Networking doesn't like us delivering large transfers, it kind
637 * of works but the latency is horrible. So if the transfer is <= the mtu
638 * size, we take that as a hint that this might be a network transfer,
639 * and do the transfer packet-by-packet.
647 dwc2_handle_packet(s
, devadr
, dev
, ep
, index
, true);
648 qemu_bh_schedule(s
->async_bh
);
651 static const char *glbregnm
[] = {
652 "GOTGCTL ", "GOTGINT ", "GAHBCFG ", "GUSBCFG ", "GRSTCTL ",
653 "GINTSTS ", "GINTMSK ", "GRXSTSR ", "GRXSTSP ", "GRXFSIZ ",
654 "GNPTXFSIZ", "GNPTXSTS ", "GI2CCTL ", "GPVNDCTL ", "GGPIO ",
655 "GUID ", "GSNPSID ", "GHWCFG1 ", "GHWCFG2 ", "GHWCFG3 ",
656 "GHWCFG4 ", "GLPMCFG ", "GPWRDN ", "GDFIFOCFG", "GADPCTL ",
657 "GREFCLK ", "GINTMSK2 ", "GINTSTS2 "
660 static uint64_t dwc2_glbreg_read(void *ptr
, hwaddr addr
, int index
,
666 assert(addr
<= GINTSTS2
);
667 val
= s
->glbreg
[index
];
671 /* clear any self-clearing bits that were set */
672 val
&= ~(GRSTCTL_TXFFLSH
| GRSTCTL_RXFFLSH
| GRSTCTL_IN_TKNQ_FLSH
|
673 GRSTCTL_FRMCNTRRST
| GRSTCTL_HSFTRST
| GRSTCTL_CSFTRST
);
674 s
->glbreg
[index
] = val
;
680 trace_usb_dwc2_glbreg_read(addr
, glbregnm
[index
], val
);
684 static void dwc2_glbreg_write(void *ptr
, hwaddr addr
, int index
, uint64_t val
,
693 assert(addr
<= GINTSTS2
);
694 mmio
= &s
->glbreg
[index
];
699 /* don't allow setting of read-only bits */
700 val
&= ~(GOTGCTL_MULT_VALID_BC_MASK
| GOTGCTL_BSESVLD
|
701 GOTGCTL_ASESVLD
| GOTGCTL_DBNC_SHORT
| GOTGCTL_CONID_B
|
702 GOTGCTL_HSTNEGSCS
| GOTGCTL_SESREQSCS
);
703 /* don't allow clearing of read-only bits */
704 val
|= old
& (GOTGCTL_MULT_VALID_BC_MASK
| GOTGCTL_BSESVLD
|
705 GOTGCTL_ASESVLD
| GOTGCTL_DBNC_SHORT
| GOTGCTL_CONID_B
|
706 GOTGCTL_HSTNEGSCS
| GOTGCTL_SESREQSCS
);
709 if ((val
& GAHBCFG_GLBL_INTR_EN
) && !(old
& GAHBCFG_GLBL_INTR_EN
)) {
714 val
|= GRSTCTL_AHBIDLE
;
715 val
&= ~GRSTCTL_DMAREQ
;
716 if (!(old
& GRSTCTL_TXFFLSH
) && (val
& GRSTCTL_TXFFLSH
)) {
717 /* TODO - TX fifo flush */
718 qemu_log_mask(LOG_UNIMP
, "Tx FIFO flush not implemented\n");
720 if (!(old
& GRSTCTL_RXFFLSH
) && (val
& GRSTCTL_RXFFLSH
)) {
721 /* TODO - RX fifo flush */
722 qemu_log_mask(LOG_UNIMP
, "Rx FIFO flush not implemented\n");
724 if (!(old
& GRSTCTL_IN_TKNQ_FLSH
) && (val
& GRSTCTL_IN_TKNQ_FLSH
)) {
725 /* TODO - device IN token queue flush */
726 qemu_log_mask(LOG_UNIMP
, "Token queue flush not implemented\n");
728 if (!(old
& GRSTCTL_FRMCNTRRST
) && (val
& GRSTCTL_FRMCNTRRST
)) {
729 /* TODO - host frame counter reset */
730 qemu_log_mask(LOG_UNIMP
, "Frame counter reset not implemented\n");
732 if (!(old
& GRSTCTL_HSFTRST
) && (val
& GRSTCTL_HSFTRST
)) {
733 /* TODO - host soft reset */
734 qemu_log_mask(LOG_UNIMP
, "Host soft reset not implemented\n");
736 if (!(old
& GRSTCTL_CSFTRST
) && (val
& GRSTCTL_CSFTRST
)) {
737 /* TODO - core soft reset */
738 qemu_log_mask(LOG_UNIMP
, "Core soft reset not implemented\n");
740 /* don't allow clearing of self-clearing bits */
741 val
|= old
& (GRSTCTL_TXFFLSH
| GRSTCTL_RXFFLSH
|
742 GRSTCTL_IN_TKNQ_FLSH
| GRSTCTL_FRMCNTRRST
|
743 GRSTCTL_HSFTRST
| GRSTCTL_CSFTRST
);
746 /* clear the write-1-to-clear bits */
749 /* don't allow clearing of read-only bits */
750 val
|= old
& (GINTSTS_PTXFEMP
| GINTSTS_HCHINT
| GINTSTS_PRTINT
|
751 GINTSTS_OEPINT
| GINTSTS_IEPINT
| GINTSTS_GOUTNAKEFF
|
752 GINTSTS_GINNAKEFF
| GINTSTS_NPTXFEMP
| GINTSTS_RXFLVL
|
753 GINTSTS_OTGINT
| GINTSTS_CURMODE_HOST
);
763 trace_usb_dwc2_glbreg_write(addr
, glbregnm
[index
], orig
, old
, val
);
771 static uint64_t dwc2_fszreg_read(void *ptr
, hwaddr addr
, int index
,
777 assert(addr
== HPTXFSIZ
);
778 val
= s
->fszreg
[index
];
780 trace_usb_dwc2_fszreg_read(addr
, val
);
784 static void dwc2_fszreg_write(void *ptr
, hwaddr addr
, int index
, uint64_t val
,
792 assert(addr
== HPTXFSIZ
);
793 mmio
= &s
->fszreg
[index
];
796 trace_usb_dwc2_fszreg_write(addr
, orig
, old
, val
);
800 static const char *hreg0nm
[] = {
801 "HCFG ", "HFIR ", "HFNUM ", "<rsvd> ", "HPTXSTS ",
802 "HAINT ", "HAINTMSK ", "HFLBADDR ", "<rsvd> ", "<rsvd> ",
803 "<rsvd> ", "<rsvd> ", "<rsvd> ", "<rsvd> ", "<rsvd> ",
807 static uint64_t dwc2_hreg0_read(void *ptr
, hwaddr addr
, int index
,
813 assert(addr
>= HCFG
&& addr
<= HPRT0
);
814 val
= s
->hreg0
[index
];
818 val
= (dwc2_get_frame_remaining(s
) << HFNUM_FRREM_SHIFT
) |
819 (s
->hfnum
<< HFNUM_FRNUM_SHIFT
);
825 trace_usb_dwc2_hreg0_read(addr
, hreg0nm
[index
], val
);
829 static void dwc2_hreg0_write(void *ptr
, hwaddr addr
, int index
, uint64_t val
,
833 USBDevice
*dev
= s
->uport
.dev
;
836 uint32_t tval
, told
, old
;
840 assert(addr
>= HCFG
&& addr
<= HPRT0
);
841 mmio
= &s
->hreg0
[index
];
850 qemu_log_mask(LOG_GUEST_ERROR
, "%s: write to read-only register\n",
857 /* don't allow clearing of read-only bits */
858 val
|= old
& (HPRT0_SPD_MASK
| HPRT0_LNSTS_MASK
| HPRT0_OVRCURRACT
|
860 /* don't allow clearing of self-clearing bits */
861 val
|= old
& (HPRT0_SUSP
| HPRT0_RES
);
862 /* don't allow setting of self-setting bits */
863 if (!(old
& HPRT0_ENA
) && (val
& HPRT0_ENA
)) {
866 /* clear the write-1-to-clear bits */
867 tval
= val
& (HPRT0_OVRCURRCHG
| HPRT0_ENACHG
| HPRT0_ENA
|
869 told
= old
& (HPRT0_OVRCURRCHG
| HPRT0_ENACHG
| HPRT0_ENA
|
873 tval
&= (HPRT0_OVRCURRCHG
| HPRT0_ENACHG
| HPRT0_ENA
|
875 val
&= ~(HPRT0_OVRCURRCHG
| HPRT0_ENACHG
| HPRT0_ENA
|
878 if (!(val
& HPRT0_RST
) && (old
& HPRT0_RST
)) {
879 if (dev
&& dev
->attached
) {
880 val
|= HPRT0_ENA
| HPRT0_ENACHG
;
884 if (val
& (HPRT0_OVRCURRCHG
| HPRT0_ENACHG
| HPRT0_CONNDET
)) {
895 trace_usb_dwc2_hreg0_write(addr
, hreg0nm
[index
], orig
, old
,
896 val
& ~HPRT0_CONNDET
);
897 trace_usb_dwc2_hreg0_action("call usb_port_reset");
898 usb_port_reset(&s
->uport
);
899 val
&= ~HPRT0_CONNDET
;
901 trace_usb_dwc2_hreg0_write(addr
, hreg0nm
[index
], orig
, old
, val
);
907 trace_usb_dwc2_hreg0_action("enable PRTINT");
908 dwc2_raise_global_irq(s
, GINTSTS_PRTINT
);
909 } else if (iflg
< 0) {
910 trace_usb_dwc2_hreg0_action("disable PRTINT");
911 dwc2_lower_global_irq(s
, GINTSTS_PRTINT
);
915 static const char *hreg1nm
[] = {
916 "HCCHAR ", "HCSPLT ", "HCINT ", "HCINTMSK", "HCTSIZ ", "HCDMA ",
920 static uint64_t dwc2_hreg1_read(void *ptr
, hwaddr addr
, int index
,
926 assert(addr
>= HCCHAR(0) && addr
<= HCDMAB(DWC2_NB_CHAN
- 1));
927 val
= s
->hreg1
[index
];
929 trace_usb_dwc2_hreg1_read(addr
, hreg1nm
[index
& 7], addr
>> 5, val
);
933 static void dwc2_hreg1_write(void *ptr
, hwaddr addr
, int index
, uint64_t val
,
944 assert(addr
>= HCCHAR(0) && addr
<= HCDMAB(DWC2_NB_CHAN
- 1));
945 mmio
= &s
->hreg1
[index
];
948 switch (HSOTG_REG(0x500) + (addr
& 0x1c)) {
950 if ((val
& HCCHAR_CHDIS
) && !(old
& HCCHAR_CHDIS
)) {
951 val
&= ~(HCCHAR_CHENA
| HCCHAR_CHDIS
);
954 val
|= old
& HCCHAR_CHDIS
;
955 if ((val
& HCCHAR_CHENA
) && !(old
& HCCHAR_CHENA
)) {
956 val
&= ~HCCHAR_CHDIS
;
959 val
|= old
& HCCHAR_CHENA
;
964 /* clear the write-1-to-clear bits */
967 val
&= ~HCINTMSK_RESERVED14_31
;
971 val
&= ~HCINTMSK_RESERVED14_31
;
975 qemu_log_mask(LOG_GUEST_ERROR
, "%s: write to read-only register\n",
982 trace_usb_dwc2_hreg1_write(addr
, hreg1nm
[index
& 7], index
>> 3, orig
,
987 /* set ChHltd in HCINT */
988 s
->hreg1
[(index
& ~7) + 2] |= HCINTMSK_CHHLTD
;
993 dwc2_enable_chan(s
, index
& ~7);
997 dwc2_update_hc_irq(s
, index
& ~7);
1001 static const char *pcgregnm
[] = {
1002 "PCGCTL ", "PCGCCTL1 "
1005 static uint64_t dwc2_pcgreg_read(void *ptr
, hwaddr addr
, int index
,
1011 assert(addr
>= PCGCTL
&& addr
<= PCGCCTL1
);
1012 val
= s
->pcgreg
[index
];
1014 trace_usb_dwc2_pcgreg_read(addr
, pcgregnm
[index
], val
);
1018 static void dwc2_pcgreg_write(void *ptr
, hwaddr addr
, int index
,
1019 uint64_t val
, unsigned size
)
1022 uint64_t orig
= val
;
1026 assert(addr
>= PCGCTL
&& addr
<= PCGCCTL1
);
1027 mmio
= &s
->pcgreg
[index
];
1030 trace_usb_dwc2_pcgreg_write(addr
, pcgregnm
[index
], orig
, old
, val
);
1034 static uint64_t dwc2_hsotg_read(void *ptr
, hwaddr addr
, unsigned size
)
1039 case HSOTG_REG(0x000) ... HSOTG_REG(0x0fc):
1040 val
= dwc2_glbreg_read(ptr
, addr
, (addr
- HSOTG_REG(0x000)) >> 2, size
);
1042 case HSOTG_REG(0x100):
1043 val
= dwc2_fszreg_read(ptr
, addr
, (addr
- HSOTG_REG(0x100)) >> 2, size
);
1045 case HSOTG_REG(0x104) ... HSOTG_REG(0x3fc):
1046 /* Gadget-mode registers, just return 0 for now */
1049 case HSOTG_REG(0x400) ... HSOTG_REG(0x4fc):
1050 val
= dwc2_hreg0_read(ptr
, addr
, (addr
- HSOTG_REG(0x400)) >> 2, size
);
1052 case HSOTG_REG(0x500) ... HSOTG_REG(0x7fc):
1053 val
= dwc2_hreg1_read(ptr
, addr
, (addr
- HSOTG_REG(0x500)) >> 2, size
);
1055 case HSOTG_REG(0x800) ... HSOTG_REG(0xdfc):
1056 /* Gadget-mode registers, just return 0 for now */
1059 case HSOTG_REG(0xe00) ... HSOTG_REG(0xffc):
1060 val
= dwc2_pcgreg_read(ptr
, addr
, (addr
- HSOTG_REG(0xe00)) >> 2, size
);
1063 g_assert_not_reached();
1069 static void dwc2_hsotg_write(void *ptr
, hwaddr addr
, uint64_t val
,
1073 case HSOTG_REG(0x000) ... HSOTG_REG(0x0fc):
1074 dwc2_glbreg_write(ptr
, addr
, (addr
- HSOTG_REG(0x000)) >> 2, val
, size
);
1076 case HSOTG_REG(0x100):
1077 dwc2_fszreg_write(ptr
, addr
, (addr
- HSOTG_REG(0x100)) >> 2, val
, size
);
1079 case HSOTG_REG(0x104) ... HSOTG_REG(0x3fc):
1080 /* Gadget-mode registers, do nothing for now */
1082 case HSOTG_REG(0x400) ... HSOTG_REG(0x4fc):
1083 dwc2_hreg0_write(ptr
, addr
, (addr
- HSOTG_REG(0x400)) >> 2, val
, size
);
1085 case HSOTG_REG(0x500) ... HSOTG_REG(0x7fc):
1086 dwc2_hreg1_write(ptr
, addr
, (addr
- HSOTG_REG(0x500)) >> 2, val
, size
);
1088 case HSOTG_REG(0x800) ... HSOTG_REG(0xdfc):
1089 /* Gadget-mode registers, do nothing for now */
1091 case HSOTG_REG(0xe00) ... HSOTG_REG(0xffc):
1092 dwc2_pcgreg_write(ptr
, addr
, (addr
- HSOTG_REG(0xe00)) >> 2, val
, size
);
1095 g_assert_not_reached();
1099 static const MemoryRegionOps dwc2_mmio_hsotg_ops
= {
1100 .read
= dwc2_hsotg_read
,
1101 .write
= dwc2_hsotg_write
,
1102 .impl
.min_access_size
= 4,
1103 .impl
.max_access_size
= 4,
1104 .endianness
= DEVICE_LITTLE_ENDIAN
,
1107 static uint64_t dwc2_hreg2_read(void *ptr
, hwaddr addr
, unsigned size
)
1109 /* TODO - implement FIFOs to support slave mode */
1110 trace_usb_dwc2_hreg2_read(addr
, addr
>> 12, 0);
1111 qemu_log_mask(LOG_UNIMP
, "FIFO read not implemented\n");
1115 static void dwc2_hreg2_write(void *ptr
, hwaddr addr
, uint64_t val
,
1118 uint64_t orig
= val
;
1120 /* TODO - implement FIFOs to support slave mode */
1121 trace_usb_dwc2_hreg2_write(addr
, addr
>> 12, orig
, 0, val
);
1122 qemu_log_mask(LOG_UNIMP
, "FIFO write not implemented\n");
1125 static const MemoryRegionOps dwc2_mmio_hreg2_ops
= {
1126 .read
= dwc2_hreg2_read
,
1127 .write
= dwc2_hreg2_write
,
1128 .impl
.min_access_size
= 4,
1129 .impl
.max_access_size
= 4,
1130 .endianness
= DEVICE_LITTLE_ENDIAN
,
1133 static void dwc2_wakeup_endpoint(USBBus
*bus
, USBEndpoint
*ep
,
1134 unsigned int stream
)
1136 DWC2State
*s
= container_of(bus
, DWC2State
, bus
);
1138 trace_usb_dwc2_wakeup_endpoint(ep
, stream
);
1140 /* TODO - do something here? */
1141 qemu_bh_schedule(s
->async_bh
);
1144 static USBBusOps dwc2_bus_ops
= {
1145 .wakeup_endpoint
= dwc2_wakeup_endpoint
,
1148 static void dwc2_work_timer(void *opaque
)
1150 DWC2State
*s
= opaque
;
1152 trace_usb_dwc2_work_timer();
1153 qemu_bh_schedule(s
->async_bh
);
1156 static void dwc2_reset_enter(Object
*obj
, ResetType type
)
1158 DWC2Class
*c
= DWC2_GET_CLASS(obj
);
1159 DWC2State
*s
= DWC2_USB(obj
);
1162 trace_usb_dwc2_reset_enter();
1164 if (c
->parent_phases
.enter
) {
1165 c
->parent_phases
.enter(obj
, type
);
1168 timer_del(s
->frame_timer
);
1169 qemu_bh_cancel(s
->async_bh
);
1171 if (s
->uport
.dev
&& s
->uport
.dev
->attached
) {
1172 usb_detach(&s
->uport
);
1177 s
->gotgctl
= GOTGCTL_BSESVLD
| GOTGCTL_ASESVLD
| GOTGCTL_CONID_B
;
1180 s
->gusbcfg
= 5 << GUSBCFG_USBTRDTIM_SHIFT
;
1181 s
->grstctl
= GRSTCTL_AHBIDLE
;
1182 s
->gintsts
= GINTSTS_CONIDSTSCHNG
| GINTSTS_PTXFEMP
| GINTSTS_NPTXFEMP
|
1183 GINTSTS_CURMODE_HOST
;
1188 s
->gnptxfsiz
= 1024 << FIFOSIZE_DEPTH_SHIFT
;
1189 s
->gnptxsts
= (4 << FIFOSIZE_DEPTH_SHIFT
) | 1024;
1190 s
->gi2cctl
= GI2CCTL_I2CDATSE0
| GI2CCTL_ACK
;
1194 s
->gsnpsid
= 0x4f54294a;
1196 s
->ghwcfg2
= (8 << GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT
) |
1197 (4 << GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT
) |
1198 (4 << GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT
) |
1199 GHWCFG2_DYNAMIC_FIFO
|
1200 GHWCFG2_PERIO_EP_SUPPORTED
|
1201 ((DWC2_NB_CHAN
- 1) << GHWCFG2_NUM_HOST_CHAN_SHIFT
) |
1202 (GHWCFG2_INT_DMA_ARCH
<< GHWCFG2_ARCHITECTURE_SHIFT
) |
1203 (GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST
<< GHWCFG2_OP_MODE_SHIFT
);
1204 s
->ghwcfg3
= (4096 << GHWCFG3_DFIFO_DEPTH_SHIFT
) |
1205 (4 << GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT
) |
1206 (4 << GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT
);
1209 s
->gpwrdn
= GPWRDN_PWRDNRSTN
;
1216 s
->hptxfsiz
= 500 << FIFOSIZE_DEPTH_SHIFT
;
1218 s
->hcfg
= 2 << HCFG_RESVALID_SHIFT
;
1221 s
->hptxsts
= (16 << TXSTS_QSPCAVAIL_SHIFT
) | 32768;
1226 memset(s
->hreg1
, 0, sizeof(s
->hreg1
));
1227 memset(s
->pcgreg
, 0, sizeof(s
->pcgreg
));
1230 s
->frame_number
= 0;
1231 s
->fi
= USB_FRMINTVL
- 1;
1235 for (i
= 0; i
< DWC2_NB_CHAN
; i
++) {
1236 s
->packet
[i
].needs_service
= false;
1240 static void dwc2_reset_hold(Object
*obj
)
1242 DWC2Class
*c
= DWC2_GET_CLASS(obj
);
1243 DWC2State
*s
= DWC2_USB(obj
);
1245 trace_usb_dwc2_reset_hold();
1247 if (c
->parent_phases
.hold
) {
1248 c
->parent_phases
.hold(obj
);
1254 static void dwc2_reset_exit(Object
*obj
)
1256 DWC2Class
*c
= DWC2_GET_CLASS(obj
);
1257 DWC2State
*s
= DWC2_USB(obj
);
1259 trace_usb_dwc2_reset_exit();
1261 if (c
->parent_phases
.exit
) {
1262 c
->parent_phases
.exit(obj
);
1265 s
->hprt0
= HPRT0_PWR
;
1266 if (s
->uport
.dev
&& s
->uport
.dev
->attached
) {
1267 usb_attach(&s
->uport
);
1268 usb_device_reset(s
->uport
.dev
);
1272 static void dwc2_realize(DeviceState
*dev
, Error
**errp
)
1274 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
1275 DWC2State
*s
= DWC2_USB(dev
);
1279 obj
= object_property_get_link(OBJECT(dev
), "dma-mr", &err
);
1281 error_setg(errp
, "dwc2: required dma-mr link not found: %s",
1282 error_get_pretty(err
));
1285 assert(obj
!= NULL
);
1287 s
->dma_mr
= MEMORY_REGION(obj
);
1288 address_space_init(&s
->dma_as
, s
->dma_mr
, "dwc2");
1290 usb_bus_new(&s
->bus
, sizeof(s
->bus
), &dwc2_bus_ops
, dev
);
1291 usb_register_port(&s
->bus
, &s
->uport
, s
, 0, &dwc2_port_ops
,
1292 USB_SPEED_MASK_LOW
| USB_SPEED_MASK_FULL
|
1293 (s
->usb_version
== 2 ? USB_SPEED_MASK_HIGH
: 0));
1296 s
->usb_frame_time
= NANOSECONDS_PER_SECOND
/ 1000; /* 1000000 */
1297 if (NANOSECONDS_PER_SECOND
>= USB_HZ_FS
) {
1298 s
->usb_bit_time
= NANOSECONDS_PER_SECOND
/ USB_HZ_FS
; /* 83.3 */
1300 s
->usb_bit_time
= 1;
1303 s
->fi
= USB_FRMINTVL
- 1;
1304 s
->eof_timer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
, dwc2_frame_boundary
, s
);
1305 s
->frame_timer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
, dwc2_work_timer
, s
);
1306 s
->async_bh
= qemu_bh_new(dwc2_work_bh
, s
);
1308 sysbus_init_irq(sbd
, &s
->irq
);
1311 static void dwc2_init(Object
*obj
)
1313 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
1314 DWC2State
*s
= DWC2_USB(obj
);
1316 memory_region_init(&s
->container
, obj
, "dwc2", DWC2_MMIO_SIZE
);
1317 sysbus_init_mmio(sbd
, &s
->container
);
1319 memory_region_init_io(&s
->hsotg
, obj
, &dwc2_mmio_hsotg_ops
, s
,
1320 "dwc2-io", 4 * KiB
);
1321 memory_region_add_subregion(&s
->container
, 0x0000, &s
->hsotg
);
1323 memory_region_init_io(&s
->fifos
, obj
, &dwc2_mmio_hreg2_ops
, s
,
1324 "dwc2-fifo", 64 * KiB
);
1325 memory_region_add_subregion(&s
->container
, 0x1000, &s
->fifos
);
1328 static const VMStateDescription vmstate_dwc2_state_packet
= {
1329 .name
= "dwc2/packet",
1331 .minimum_version_id
= 1,
1332 .fields
= (VMStateField
[]) {
1333 VMSTATE_UINT32(devadr
, DWC2Packet
),
1334 VMSTATE_UINT32(epnum
, DWC2Packet
),
1335 VMSTATE_UINT32(epdir
, DWC2Packet
),
1336 VMSTATE_UINT32(mps
, DWC2Packet
),
1337 VMSTATE_UINT32(pid
, DWC2Packet
),
1338 VMSTATE_UINT32(index
, DWC2Packet
),
1339 VMSTATE_UINT32(pcnt
, DWC2Packet
),
1340 VMSTATE_UINT32(len
, DWC2Packet
),
1341 VMSTATE_INT32(async
, DWC2Packet
),
1342 VMSTATE_BOOL(small
, DWC2Packet
),
1343 VMSTATE_BOOL(needs_service
, DWC2Packet
),
1344 VMSTATE_END_OF_LIST()
1348 const VMStateDescription vmstate_dwc2_state
= {
1351 .minimum_version_id
= 1,
1352 .fields
= (VMStateField
[]) {
1353 VMSTATE_UINT32_ARRAY(glbreg
, DWC2State
,
1354 DWC2_GLBREG_SIZE
/ sizeof(uint32_t)),
1355 VMSTATE_UINT32_ARRAY(fszreg
, DWC2State
,
1356 DWC2_FSZREG_SIZE
/ sizeof(uint32_t)),
1357 VMSTATE_UINT32_ARRAY(hreg0
, DWC2State
,
1358 DWC2_HREG0_SIZE
/ sizeof(uint32_t)),
1359 VMSTATE_UINT32_ARRAY(hreg1
, DWC2State
,
1360 DWC2_HREG1_SIZE
/ sizeof(uint32_t)),
1361 VMSTATE_UINT32_ARRAY(pcgreg
, DWC2State
,
1362 DWC2_PCGREG_SIZE
/ sizeof(uint32_t)),
1364 VMSTATE_TIMER_PTR(eof_timer
, DWC2State
),
1365 VMSTATE_TIMER_PTR(frame_timer
, DWC2State
),
1366 VMSTATE_INT64(sof_time
, DWC2State
),
1367 VMSTATE_INT64(usb_frame_time
, DWC2State
),
1368 VMSTATE_INT64(usb_bit_time
, DWC2State
),
1369 VMSTATE_UINT32(usb_version
, DWC2State
),
1370 VMSTATE_UINT16(frame_number
, DWC2State
),
1371 VMSTATE_UINT16(fi
, DWC2State
),
1372 VMSTATE_UINT16(next_chan
, DWC2State
),
1373 VMSTATE_BOOL(working
, DWC2State
),
1375 VMSTATE_STRUCT_ARRAY(packet
, DWC2State
, DWC2_NB_CHAN
, 1,
1376 vmstate_dwc2_state_packet
, DWC2Packet
),
1377 VMSTATE_UINT8_2DARRAY(usb_buf
, DWC2State
, DWC2_NB_CHAN
,
1378 DWC2_MAX_XFER_SIZE
),
1380 VMSTATE_END_OF_LIST()
1384 static Property dwc2_usb_properties
[] = {
1385 DEFINE_PROP_UINT32("usb_version", DWC2State
, usb_version
, 2),
1386 DEFINE_PROP_END_OF_LIST(),
1389 static void dwc2_class_init(ObjectClass
*klass
, void *data
)
1391 DeviceClass
*dc
= DEVICE_CLASS(klass
);
1392 DWC2Class
*c
= DWC2_CLASS(klass
);
1393 ResettableClass
*rc
= RESETTABLE_CLASS(klass
);
1395 dc
->realize
= dwc2_realize
;
1396 dc
->vmsd
= &vmstate_dwc2_state
;
1397 set_bit(DEVICE_CATEGORY_USB
, dc
->categories
);
1398 device_class_set_props(dc
, dwc2_usb_properties
);
1399 resettable_class_set_parent_phases(rc
, dwc2_reset_enter
, dwc2_reset_hold
,
1400 dwc2_reset_exit
, &c
->parent_phases
);
1403 static const TypeInfo dwc2_usb_type_info
= {
1404 .name
= TYPE_DWC2_USB
,
1405 .parent
= TYPE_SYS_BUS_DEVICE
,
1406 .instance_size
= sizeof(DWC2State
),
1407 .instance_init
= dwc2_init
,
1408 .class_size
= sizeof(DWC2Class
),
1409 .class_init
= dwc2_class_init
,
1412 static void dwc2_usb_register_types(void)
1414 type_register_static(&dwc2_usb_type_info
);
1417 type_init(dwc2_usb_register_types
)