1*153ef166SPaul Zimmerman /* 2*153ef166SPaul Zimmerman * dwc-hsotg (dwc2) USB host controller emulation 3*153ef166SPaul Zimmerman * 4*153ef166SPaul Zimmerman * Based on hw/usb/hcd-ehci.c and hw/usb/hcd-ohci.c 5*153ef166SPaul Zimmerman * 6*153ef166SPaul Zimmerman * Note that to use this emulation with the dwc-otg driver in the 7*153ef166SPaul Zimmerman * Raspbian kernel, you must pass the option "dwc_otg.fiq_fsm_enable=0" 8*153ef166SPaul Zimmerman * on the kernel command line. 9*153ef166SPaul Zimmerman * 10*153ef166SPaul Zimmerman * Some useful documentation used to develop this emulation can be 11*153ef166SPaul Zimmerman * found online (as of April 2020) at: 12*153ef166SPaul Zimmerman * 13*153ef166SPaul Zimmerman * http://www.capital-micro.com/PDF/CME-M7_Family_User_Guide_EN.pdf 14*153ef166SPaul Zimmerman * which has a pretty complete description of the controller starting 15*153ef166SPaul Zimmerman * on page 370. 16*153ef166SPaul Zimmerman * 17*153ef166SPaul Zimmerman * https://sourceforge.net/p/wive-ng/wive-ng-mt/ci/master/tree/docs/DataSheets/RT3050_5x_V2.0_081408_0902.pdf 18*153ef166SPaul Zimmerman * which has a description of the controller registers starting on 19*153ef166SPaul Zimmerman * page 130. 20*153ef166SPaul Zimmerman * 21*153ef166SPaul Zimmerman * Copyright (c) 2020 Paul Zimmerman <pauldzim@gmail.com> 22*153ef166SPaul Zimmerman * 23*153ef166SPaul Zimmerman * This program is free software; you can redistribute it and/or modify 24*153ef166SPaul Zimmerman * it under the terms of the GNU General Public License as published by 25*153ef166SPaul Zimmerman * the Free Software Foundation; either version 2 of the License, or 26*153ef166SPaul Zimmerman * (at your option) any later version. 27*153ef166SPaul Zimmerman * 28*153ef166SPaul Zimmerman * This program is distributed in the hope that it will be useful, 29*153ef166SPaul Zimmerman * but WITHOUT ANY WARRANTY; without even the implied warranty of 30*153ef166SPaul Zimmerman * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31*153ef166SPaul Zimmerman * GNU General Public License for more details. 32*153ef166SPaul Zimmerman */ 33*153ef166SPaul Zimmerman 34*153ef166SPaul Zimmerman #include "qemu/osdep.h" 35*153ef166SPaul Zimmerman #include "qemu/units.h" 36*153ef166SPaul Zimmerman #include "qapi/error.h" 37*153ef166SPaul Zimmerman #include "hw/usb/dwc2-regs.h" 38*153ef166SPaul Zimmerman #include "hw/usb/hcd-dwc2.h" 39*153ef166SPaul Zimmerman #include "migration/vmstate.h" 40*153ef166SPaul Zimmerman #include "trace.h" 41*153ef166SPaul Zimmerman #include "qemu/log.h" 42*153ef166SPaul Zimmerman #include "qemu/error-report.h" 43*153ef166SPaul Zimmerman #include "qemu/main-loop.h" 44*153ef166SPaul Zimmerman #include "hw/qdev-properties.h" 45*153ef166SPaul Zimmerman 46*153ef166SPaul Zimmerman #define USB_HZ_FS 12000000 47*153ef166SPaul Zimmerman #define USB_HZ_HS 96000000 48*153ef166SPaul Zimmerman #define USB_FRMINTVL 12000 49*153ef166SPaul Zimmerman 50*153ef166SPaul Zimmerman /* nifty macros from Arnon's EHCI version */ 51*153ef166SPaul Zimmerman #define get_field(data, field) \ 52*153ef166SPaul Zimmerman (((data) & field##_MASK) >> field##_SHIFT) 53*153ef166SPaul Zimmerman 54*153ef166SPaul Zimmerman #define set_field(data, newval, field) do { \ 55*153ef166SPaul Zimmerman uint32_t val = *(data); \ 56*153ef166SPaul Zimmerman val &= ~field##_MASK; \ 57*153ef166SPaul Zimmerman val |= ((newval) << field##_SHIFT) & field##_MASK; \ 58*153ef166SPaul Zimmerman *(data) = val; \ 59*153ef166SPaul Zimmerman } while (0) 60*153ef166SPaul Zimmerman 61*153ef166SPaul Zimmerman #define get_bit(data, bitmask) \ 62*153ef166SPaul Zimmerman (!!((data) & (bitmask))) 63*153ef166SPaul Zimmerman 64*153ef166SPaul Zimmerman /* update irq line */ 65*153ef166SPaul Zimmerman static inline void dwc2_update_irq(DWC2State *s) 66*153ef166SPaul Zimmerman { 67*153ef166SPaul Zimmerman static int oldlevel; 68*153ef166SPaul Zimmerman int level = 0; 69*153ef166SPaul Zimmerman 70*153ef166SPaul Zimmerman if ((s->gintsts & s->gintmsk) && (s->gahbcfg & GAHBCFG_GLBL_INTR_EN)) { 71*153ef166SPaul Zimmerman level = 1; 72*153ef166SPaul Zimmerman } 73*153ef166SPaul Zimmerman if (level != oldlevel) { 74*153ef166SPaul Zimmerman oldlevel = level; 75*153ef166SPaul Zimmerman trace_usb_dwc2_update_irq(level); 76*153ef166SPaul Zimmerman qemu_set_irq(s->irq, level); 77*153ef166SPaul Zimmerman } 78*153ef166SPaul Zimmerman } 79*153ef166SPaul Zimmerman 80*153ef166SPaul Zimmerman /* flag interrupt condition */ 81*153ef166SPaul Zimmerman static inline void dwc2_raise_global_irq(DWC2State *s, uint32_t intr) 82*153ef166SPaul Zimmerman { 83*153ef166SPaul Zimmerman if (!(s->gintsts & intr)) { 84*153ef166SPaul Zimmerman s->gintsts |= intr; 85*153ef166SPaul Zimmerman trace_usb_dwc2_raise_global_irq(intr); 86*153ef166SPaul Zimmerman dwc2_update_irq(s); 87*153ef166SPaul Zimmerman } 88*153ef166SPaul Zimmerman } 89*153ef166SPaul Zimmerman 90*153ef166SPaul Zimmerman static inline void dwc2_lower_global_irq(DWC2State *s, uint32_t intr) 91*153ef166SPaul Zimmerman { 92*153ef166SPaul Zimmerman if (s->gintsts & intr) { 93*153ef166SPaul Zimmerman s->gintsts &= ~intr; 94*153ef166SPaul Zimmerman trace_usb_dwc2_lower_global_irq(intr); 95*153ef166SPaul Zimmerman dwc2_update_irq(s); 96*153ef166SPaul Zimmerman } 97*153ef166SPaul Zimmerman } 98*153ef166SPaul Zimmerman 99*153ef166SPaul Zimmerman static inline void dwc2_raise_host_irq(DWC2State *s, uint32_t host_intr) 100*153ef166SPaul Zimmerman { 101*153ef166SPaul Zimmerman if (!(s->haint & host_intr)) { 102*153ef166SPaul Zimmerman s->haint |= host_intr; 103*153ef166SPaul Zimmerman s->haint &= 0xffff; 104*153ef166SPaul Zimmerman trace_usb_dwc2_raise_host_irq(host_intr); 105*153ef166SPaul Zimmerman if (s->haint & s->haintmsk) { 106*153ef166SPaul Zimmerman dwc2_raise_global_irq(s, GINTSTS_HCHINT); 107*153ef166SPaul Zimmerman } 108*153ef166SPaul Zimmerman } 109*153ef166SPaul Zimmerman } 110*153ef166SPaul Zimmerman 111*153ef166SPaul Zimmerman static inline void dwc2_lower_host_irq(DWC2State *s, uint32_t host_intr) 112*153ef166SPaul Zimmerman { 113*153ef166SPaul Zimmerman if (s->haint & host_intr) { 114*153ef166SPaul Zimmerman s->haint &= ~host_intr; 115*153ef166SPaul Zimmerman trace_usb_dwc2_lower_host_irq(host_intr); 116*153ef166SPaul Zimmerman if (!(s->haint & s->haintmsk)) { 117*153ef166SPaul Zimmerman dwc2_lower_global_irq(s, GINTSTS_HCHINT); 118*153ef166SPaul Zimmerman } 119*153ef166SPaul Zimmerman } 120*153ef166SPaul Zimmerman } 121*153ef166SPaul Zimmerman 122*153ef166SPaul Zimmerman static inline void dwc2_update_hc_irq(DWC2State *s, int index) 123*153ef166SPaul Zimmerman { 124*153ef166SPaul Zimmerman uint32_t host_intr = 1 << (index >> 3); 125*153ef166SPaul Zimmerman 126*153ef166SPaul Zimmerman if (s->hreg1[index + 2] & s->hreg1[index + 3]) { 127*153ef166SPaul Zimmerman dwc2_raise_host_irq(s, host_intr); 128*153ef166SPaul Zimmerman } else { 129*153ef166SPaul Zimmerman dwc2_lower_host_irq(s, host_intr); 130*153ef166SPaul Zimmerman } 131*153ef166SPaul Zimmerman } 132*153ef166SPaul Zimmerman 133*153ef166SPaul Zimmerman /* set a timer for EOF */ 134*153ef166SPaul Zimmerman static void dwc2_eof_timer(DWC2State *s) 135*153ef166SPaul Zimmerman { 136*153ef166SPaul Zimmerman timer_mod(s->eof_timer, s->sof_time + s->usb_frame_time); 137*153ef166SPaul Zimmerman } 138*153ef166SPaul Zimmerman 139*153ef166SPaul Zimmerman /* Set a timer for EOF and generate SOF event */ 140*153ef166SPaul Zimmerman static void dwc2_sof(DWC2State *s) 141*153ef166SPaul Zimmerman { 142*153ef166SPaul Zimmerman s->sof_time += s->usb_frame_time; 143*153ef166SPaul Zimmerman trace_usb_dwc2_sof(s->sof_time); 144*153ef166SPaul Zimmerman dwc2_eof_timer(s); 145*153ef166SPaul Zimmerman dwc2_raise_global_irq(s, GINTSTS_SOF); 146*153ef166SPaul Zimmerman } 147*153ef166SPaul Zimmerman 148*153ef166SPaul Zimmerman /* Do frame processing on frame boundary */ 149*153ef166SPaul Zimmerman static void dwc2_frame_boundary(void *opaque) 150*153ef166SPaul Zimmerman { 151*153ef166SPaul Zimmerman DWC2State *s = opaque; 152*153ef166SPaul Zimmerman int64_t now; 153*153ef166SPaul Zimmerman uint16_t frcnt; 154*153ef166SPaul Zimmerman 155*153ef166SPaul Zimmerman now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 156*153ef166SPaul Zimmerman 157*153ef166SPaul Zimmerman /* Frame boundary, so do EOF stuff here */ 158*153ef166SPaul Zimmerman 159*153ef166SPaul Zimmerman /* Increment frame number */ 160*153ef166SPaul Zimmerman frcnt = (uint16_t)((now - s->sof_time) / s->fi); 161*153ef166SPaul Zimmerman s->frame_number = (s->frame_number + frcnt) & 0xffff; 162*153ef166SPaul Zimmerman s->hfnum = s->frame_number & HFNUM_MAX_FRNUM; 163*153ef166SPaul Zimmerman 164*153ef166SPaul Zimmerman /* Do SOF stuff here */ 165*153ef166SPaul Zimmerman dwc2_sof(s); 166*153ef166SPaul Zimmerman } 167*153ef166SPaul Zimmerman 168*153ef166SPaul Zimmerman /* Start sending SOF tokens on the USB bus */ 169*153ef166SPaul Zimmerman static void dwc2_bus_start(DWC2State *s) 170*153ef166SPaul Zimmerman { 171*153ef166SPaul Zimmerman trace_usb_dwc2_bus_start(); 172*153ef166SPaul Zimmerman s->sof_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 173*153ef166SPaul Zimmerman dwc2_eof_timer(s); 174*153ef166SPaul Zimmerman } 175*153ef166SPaul Zimmerman 176*153ef166SPaul Zimmerman /* Stop sending SOF tokens on the USB bus */ 177*153ef166SPaul Zimmerman static void dwc2_bus_stop(DWC2State *s) 178*153ef166SPaul Zimmerman { 179*153ef166SPaul Zimmerman trace_usb_dwc2_bus_stop(); 180*153ef166SPaul Zimmerman timer_del(s->eof_timer); 181*153ef166SPaul Zimmerman } 182*153ef166SPaul Zimmerman 183*153ef166SPaul Zimmerman static USBDevice *dwc2_find_device(DWC2State *s, uint8_t addr) 184*153ef166SPaul Zimmerman { 185*153ef166SPaul Zimmerman USBDevice *dev; 186*153ef166SPaul Zimmerman 187*153ef166SPaul Zimmerman trace_usb_dwc2_find_device(addr); 188*153ef166SPaul Zimmerman 189*153ef166SPaul Zimmerman if (!(s->hprt0 & HPRT0_ENA)) { 190*153ef166SPaul Zimmerman trace_usb_dwc2_port_disabled(0); 191*153ef166SPaul Zimmerman } else { 192*153ef166SPaul Zimmerman dev = usb_find_device(&s->uport, addr); 193*153ef166SPaul Zimmerman if (dev != NULL) { 194*153ef166SPaul Zimmerman trace_usb_dwc2_device_found(0); 195*153ef166SPaul Zimmerman return dev; 196*153ef166SPaul Zimmerman } 197*153ef166SPaul Zimmerman } 198*153ef166SPaul Zimmerman 199*153ef166SPaul Zimmerman trace_usb_dwc2_device_not_found(); 200*153ef166SPaul Zimmerman return NULL; 201*153ef166SPaul Zimmerman } 202*153ef166SPaul Zimmerman 203*153ef166SPaul Zimmerman static const char *pstatus[] = { 204*153ef166SPaul Zimmerman "USB_RET_SUCCESS", "USB_RET_NODEV", "USB_RET_NAK", "USB_RET_STALL", 205*153ef166SPaul Zimmerman "USB_RET_BABBLE", "USB_RET_IOERROR", "USB_RET_ASYNC", 206*153ef166SPaul Zimmerman "USB_RET_ADD_TO_QUEUE", "USB_RET_REMOVE_FROM_QUEUE" 207*153ef166SPaul Zimmerman }; 208*153ef166SPaul Zimmerman 209*153ef166SPaul Zimmerman static uint32_t pintr[] = { 210*153ef166SPaul Zimmerman HCINTMSK_XFERCOMPL, HCINTMSK_XACTERR, HCINTMSK_NAK, HCINTMSK_STALL, 211*153ef166SPaul Zimmerman HCINTMSK_BBLERR, HCINTMSK_XACTERR, HCINTMSK_XACTERR, HCINTMSK_XACTERR, 212*153ef166SPaul Zimmerman HCINTMSK_XACTERR 213*153ef166SPaul Zimmerman }; 214*153ef166SPaul Zimmerman 215*153ef166SPaul Zimmerman static const char *types[] = { 216*153ef166SPaul Zimmerman "Ctrl", "Isoc", "Bulk", "Intr" 217*153ef166SPaul Zimmerman }; 218*153ef166SPaul Zimmerman 219*153ef166SPaul Zimmerman static const char *dirs[] = { 220*153ef166SPaul Zimmerman "Out", "In" 221*153ef166SPaul Zimmerman }; 222*153ef166SPaul Zimmerman 223*153ef166SPaul Zimmerman static void dwc2_handle_packet(DWC2State *s, uint32_t devadr, USBDevice *dev, 224*153ef166SPaul Zimmerman USBEndpoint *ep, uint32_t index, bool send) 225*153ef166SPaul Zimmerman { 226*153ef166SPaul Zimmerman DWC2Packet *p; 227*153ef166SPaul Zimmerman uint32_t hcchar = s->hreg1[index]; 228*153ef166SPaul Zimmerman uint32_t hctsiz = s->hreg1[index + 4]; 229*153ef166SPaul Zimmerman uint32_t hcdma = s->hreg1[index + 5]; 230*153ef166SPaul Zimmerman uint32_t chan, epnum, epdir, eptype, mps, pid, pcnt, len, tlen, intr = 0; 231*153ef166SPaul Zimmerman uint32_t tpcnt, stsidx, actual = 0; 232*153ef166SPaul Zimmerman bool do_intr = false, done = false; 233*153ef166SPaul Zimmerman 234*153ef166SPaul Zimmerman epnum = get_field(hcchar, HCCHAR_EPNUM); 235*153ef166SPaul Zimmerman epdir = get_bit(hcchar, HCCHAR_EPDIR); 236*153ef166SPaul Zimmerman eptype = get_field(hcchar, HCCHAR_EPTYPE); 237*153ef166SPaul Zimmerman mps = get_field(hcchar, HCCHAR_MPS); 238*153ef166SPaul Zimmerman pid = get_field(hctsiz, TSIZ_SC_MC_PID); 239*153ef166SPaul Zimmerman pcnt = get_field(hctsiz, TSIZ_PKTCNT); 240*153ef166SPaul Zimmerman len = get_field(hctsiz, TSIZ_XFERSIZE); 241*153ef166SPaul Zimmerman assert(len <= DWC2_MAX_XFER_SIZE); 242*153ef166SPaul Zimmerman chan = index >> 3; 243*153ef166SPaul Zimmerman p = &s->packet[chan]; 244*153ef166SPaul Zimmerman 245*153ef166SPaul Zimmerman trace_usb_dwc2_handle_packet(chan, dev, &p->packet, epnum, types[eptype], 246*153ef166SPaul Zimmerman dirs[epdir], mps, len, pcnt); 247*153ef166SPaul Zimmerman 248*153ef166SPaul Zimmerman if (eptype == USB_ENDPOINT_XFER_CONTROL && pid == TSIZ_SC_MC_PID_SETUP) { 249*153ef166SPaul Zimmerman pid = USB_TOKEN_SETUP; 250*153ef166SPaul Zimmerman } else { 251*153ef166SPaul Zimmerman pid = epdir ? USB_TOKEN_IN : USB_TOKEN_OUT; 252*153ef166SPaul Zimmerman } 253*153ef166SPaul Zimmerman 254*153ef166SPaul Zimmerman if (send) { 255*153ef166SPaul Zimmerman tlen = len; 256*153ef166SPaul Zimmerman if (p->small) { 257*153ef166SPaul Zimmerman if (tlen > mps) { 258*153ef166SPaul Zimmerman tlen = mps; 259*153ef166SPaul Zimmerman } 260*153ef166SPaul Zimmerman } 261*153ef166SPaul Zimmerman 262*153ef166SPaul Zimmerman if (pid != USB_TOKEN_IN) { 263*153ef166SPaul Zimmerman trace_usb_dwc2_memory_read(hcdma, tlen); 264*153ef166SPaul Zimmerman if (dma_memory_read(&s->dma_as, hcdma, 265*153ef166SPaul Zimmerman s->usb_buf[chan], tlen) != MEMTX_OK) { 266*153ef166SPaul Zimmerman qemu_log_mask(LOG_GUEST_ERROR, "%s: dma_memory_read failed\n", 267*153ef166SPaul Zimmerman __func__); 268*153ef166SPaul Zimmerman } 269*153ef166SPaul Zimmerman } 270*153ef166SPaul Zimmerman 271*153ef166SPaul Zimmerman usb_packet_init(&p->packet); 272*153ef166SPaul Zimmerman usb_packet_setup(&p->packet, pid, ep, 0, hcdma, 273*153ef166SPaul Zimmerman pid != USB_TOKEN_IN, true); 274*153ef166SPaul Zimmerman usb_packet_addbuf(&p->packet, s->usb_buf[chan], tlen); 275*153ef166SPaul Zimmerman p->async = DWC2_ASYNC_NONE; 276*153ef166SPaul Zimmerman usb_handle_packet(dev, &p->packet); 277*153ef166SPaul Zimmerman } else { 278*153ef166SPaul Zimmerman tlen = p->len; 279*153ef166SPaul Zimmerman } 280*153ef166SPaul Zimmerman 281*153ef166SPaul Zimmerman stsidx = -p->packet.status; 282*153ef166SPaul Zimmerman assert(stsidx < sizeof(pstatus) / sizeof(*pstatus)); 283*153ef166SPaul Zimmerman actual = p->packet.actual_length; 284*153ef166SPaul Zimmerman trace_usb_dwc2_packet_status(pstatus[stsidx], actual); 285*153ef166SPaul Zimmerman 286*153ef166SPaul Zimmerman babble: 287*153ef166SPaul Zimmerman if (p->packet.status != USB_RET_SUCCESS && 288*153ef166SPaul Zimmerman p->packet.status != USB_RET_NAK && 289*153ef166SPaul Zimmerman p->packet.status != USB_RET_STALL && 290*153ef166SPaul Zimmerman p->packet.status != USB_RET_ASYNC) { 291*153ef166SPaul Zimmerman trace_usb_dwc2_packet_error(pstatus[stsidx]); 292*153ef166SPaul Zimmerman } 293*153ef166SPaul Zimmerman 294*153ef166SPaul Zimmerman if (p->packet.status == USB_RET_ASYNC) { 295*153ef166SPaul Zimmerman trace_usb_dwc2_async_packet(&p->packet, chan, dev, epnum, 296*153ef166SPaul Zimmerman dirs[epdir], tlen); 297*153ef166SPaul Zimmerman usb_device_flush_ep_queue(dev, ep); 298*153ef166SPaul Zimmerman assert(p->async != DWC2_ASYNC_INFLIGHT); 299*153ef166SPaul Zimmerman p->devadr = devadr; 300*153ef166SPaul Zimmerman p->epnum = epnum; 301*153ef166SPaul Zimmerman p->epdir = epdir; 302*153ef166SPaul Zimmerman p->mps = mps; 303*153ef166SPaul Zimmerman p->pid = pid; 304*153ef166SPaul Zimmerman p->index = index; 305*153ef166SPaul Zimmerman p->pcnt = pcnt; 306*153ef166SPaul Zimmerman p->len = tlen; 307*153ef166SPaul Zimmerman p->async = DWC2_ASYNC_INFLIGHT; 308*153ef166SPaul Zimmerman p->needs_service = false; 309*153ef166SPaul Zimmerman return; 310*153ef166SPaul Zimmerman } 311*153ef166SPaul Zimmerman 312*153ef166SPaul Zimmerman if (p->packet.status == USB_RET_SUCCESS) { 313*153ef166SPaul Zimmerman if (actual > tlen) { 314*153ef166SPaul Zimmerman p->packet.status = USB_RET_BABBLE; 315*153ef166SPaul Zimmerman goto babble; 316*153ef166SPaul Zimmerman } 317*153ef166SPaul Zimmerman 318*153ef166SPaul Zimmerman if (pid == USB_TOKEN_IN) { 319*153ef166SPaul Zimmerman trace_usb_dwc2_memory_write(hcdma, actual); 320*153ef166SPaul Zimmerman if (dma_memory_write(&s->dma_as, hcdma, s->usb_buf[chan], 321*153ef166SPaul Zimmerman actual) != MEMTX_OK) { 322*153ef166SPaul Zimmerman qemu_log_mask(LOG_GUEST_ERROR, "%s: dma_memory_write failed\n", 323*153ef166SPaul Zimmerman __func__); 324*153ef166SPaul Zimmerman } 325*153ef166SPaul Zimmerman } 326*153ef166SPaul Zimmerman 327*153ef166SPaul Zimmerman tpcnt = actual / mps; 328*153ef166SPaul Zimmerman if (actual % mps) { 329*153ef166SPaul Zimmerman tpcnt++; 330*153ef166SPaul Zimmerman if (pid == USB_TOKEN_IN) { 331*153ef166SPaul Zimmerman done = true; 332*153ef166SPaul Zimmerman } 333*153ef166SPaul Zimmerman } 334*153ef166SPaul Zimmerman 335*153ef166SPaul Zimmerman pcnt -= tpcnt < pcnt ? tpcnt : pcnt; 336*153ef166SPaul Zimmerman set_field(&hctsiz, pcnt, TSIZ_PKTCNT); 337*153ef166SPaul Zimmerman len -= actual < len ? actual : len; 338*153ef166SPaul Zimmerman set_field(&hctsiz, len, TSIZ_XFERSIZE); 339*153ef166SPaul Zimmerman s->hreg1[index + 4] = hctsiz; 340*153ef166SPaul Zimmerman hcdma += actual; 341*153ef166SPaul Zimmerman s->hreg1[index + 5] = hcdma; 342*153ef166SPaul Zimmerman 343*153ef166SPaul Zimmerman if (!pcnt || len == 0 || actual == 0) { 344*153ef166SPaul Zimmerman done = true; 345*153ef166SPaul Zimmerman } 346*153ef166SPaul Zimmerman } else { 347*153ef166SPaul Zimmerman intr |= pintr[stsidx]; 348*153ef166SPaul Zimmerman if (p->packet.status == USB_RET_NAK && 349*153ef166SPaul Zimmerman (eptype == USB_ENDPOINT_XFER_CONTROL || 350*153ef166SPaul Zimmerman eptype == USB_ENDPOINT_XFER_BULK)) { 351*153ef166SPaul Zimmerman /* 352*153ef166SPaul Zimmerman * for ctrl/bulk, automatically retry on NAK, 353*153ef166SPaul Zimmerman * but send the interrupt anyway 354*153ef166SPaul Zimmerman */ 355*153ef166SPaul Zimmerman intr &= ~HCINTMSK_RESERVED14_31; 356*153ef166SPaul Zimmerman s->hreg1[index + 2] |= intr; 357*153ef166SPaul Zimmerman do_intr = true; 358*153ef166SPaul Zimmerman } else { 359*153ef166SPaul Zimmerman intr |= HCINTMSK_CHHLTD; 360*153ef166SPaul Zimmerman done = true; 361*153ef166SPaul Zimmerman } 362*153ef166SPaul Zimmerman } 363*153ef166SPaul Zimmerman 364*153ef166SPaul Zimmerman usb_packet_cleanup(&p->packet); 365*153ef166SPaul Zimmerman 366*153ef166SPaul Zimmerman if (done) { 367*153ef166SPaul Zimmerman hcchar &= ~HCCHAR_CHENA; 368*153ef166SPaul Zimmerman s->hreg1[index] = hcchar; 369*153ef166SPaul Zimmerman if (!(intr & HCINTMSK_CHHLTD)) { 370*153ef166SPaul Zimmerman intr |= HCINTMSK_CHHLTD | HCINTMSK_XFERCOMPL; 371*153ef166SPaul Zimmerman } 372*153ef166SPaul Zimmerman intr &= ~HCINTMSK_RESERVED14_31; 373*153ef166SPaul Zimmerman s->hreg1[index + 2] |= intr; 374*153ef166SPaul Zimmerman p->needs_service = false; 375*153ef166SPaul Zimmerman trace_usb_dwc2_packet_done(pstatus[stsidx], actual, len, pcnt); 376*153ef166SPaul Zimmerman dwc2_update_hc_irq(s, index); 377*153ef166SPaul Zimmerman return; 378*153ef166SPaul Zimmerman } 379*153ef166SPaul Zimmerman 380*153ef166SPaul Zimmerman p->devadr = devadr; 381*153ef166SPaul Zimmerman p->epnum = epnum; 382*153ef166SPaul Zimmerman p->epdir = epdir; 383*153ef166SPaul Zimmerman p->mps = mps; 384*153ef166SPaul Zimmerman p->pid = pid; 385*153ef166SPaul Zimmerman p->index = index; 386*153ef166SPaul Zimmerman p->pcnt = pcnt; 387*153ef166SPaul Zimmerman p->len = len; 388*153ef166SPaul Zimmerman p->needs_service = true; 389*153ef166SPaul Zimmerman trace_usb_dwc2_packet_next(pstatus[stsidx], len, pcnt); 390*153ef166SPaul Zimmerman if (do_intr) { 391*153ef166SPaul Zimmerman dwc2_update_hc_irq(s, index); 392*153ef166SPaul Zimmerman } 393*153ef166SPaul Zimmerman } 394*153ef166SPaul Zimmerman 395*153ef166SPaul Zimmerman /* Attach or detach a device on root hub */ 396*153ef166SPaul Zimmerman 397*153ef166SPaul Zimmerman static const char *speeds[] = { 398*153ef166SPaul Zimmerman "low", "full", "high" 399*153ef166SPaul Zimmerman }; 400*153ef166SPaul Zimmerman 401*153ef166SPaul Zimmerman static void dwc2_attach(USBPort *port) 402*153ef166SPaul Zimmerman { 403*153ef166SPaul Zimmerman DWC2State *s = port->opaque; 404*153ef166SPaul Zimmerman int hispd = 0; 405*153ef166SPaul Zimmerman 406*153ef166SPaul Zimmerman trace_usb_dwc2_attach(port); 407*153ef166SPaul Zimmerman assert(port->index == 0); 408*153ef166SPaul Zimmerman 409*153ef166SPaul Zimmerman if (!port->dev || !port->dev->attached) { 410*153ef166SPaul Zimmerman return; 411*153ef166SPaul Zimmerman } 412*153ef166SPaul Zimmerman 413*153ef166SPaul Zimmerman assert(port->dev->speed <= USB_SPEED_HIGH); 414*153ef166SPaul Zimmerman trace_usb_dwc2_attach_speed(speeds[port->dev->speed]); 415*153ef166SPaul Zimmerman s->hprt0 &= ~HPRT0_SPD_MASK; 416*153ef166SPaul Zimmerman 417*153ef166SPaul Zimmerman switch (port->dev->speed) { 418*153ef166SPaul Zimmerman case USB_SPEED_LOW: 419*153ef166SPaul Zimmerman s->hprt0 |= HPRT0_SPD_LOW_SPEED << HPRT0_SPD_SHIFT; 420*153ef166SPaul Zimmerman break; 421*153ef166SPaul Zimmerman case USB_SPEED_FULL: 422*153ef166SPaul Zimmerman s->hprt0 |= HPRT0_SPD_FULL_SPEED << HPRT0_SPD_SHIFT; 423*153ef166SPaul Zimmerman break; 424*153ef166SPaul Zimmerman case USB_SPEED_HIGH: 425*153ef166SPaul Zimmerman s->hprt0 |= HPRT0_SPD_HIGH_SPEED << HPRT0_SPD_SHIFT; 426*153ef166SPaul Zimmerman hispd = 1; 427*153ef166SPaul Zimmerman break; 428*153ef166SPaul Zimmerman } 429*153ef166SPaul Zimmerman 430*153ef166SPaul Zimmerman if (hispd) { 431*153ef166SPaul Zimmerman s->usb_frame_time = NANOSECONDS_PER_SECOND / 8000; /* 125000 */ 432*153ef166SPaul Zimmerman if (NANOSECONDS_PER_SECOND >= USB_HZ_HS) { 433*153ef166SPaul Zimmerman s->usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ_HS; /* 10.4 */ 434*153ef166SPaul Zimmerman } else { 435*153ef166SPaul Zimmerman s->usb_bit_time = 1; 436*153ef166SPaul Zimmerman } 437*153ef166SPaul Zimmerman } else { 438*153ef166SPaul Zimmerman s->usb_frame_time = NANOSECONDS_PER_SECOND / 1000; /* 1000000 */ 439*153ef166SPaul Zimmerman if (NANOSECONDS_PER_SECOND >= USB_HZ_FS) { 440*153ef166SPaul Zimmerman s->usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ_FS; /* 83.3 */ 441*153ef166SPaul Zimmerman } else { 442*153ef166SPaul Zimmerman s->usb_bit_time = 1; 443*153ef166SPaul Zimmerman } 444*153ef166SPaul Zimmerman } 445*153ef166SPaul Zimmerman 446*153ef166SPaul Zimmerman s->fi = USB_FRMINTVL - 1; 447*153ef166SPaul Zimmerman s->hprt0 |= HPRT0_CONNDET | HPRT0_CONNSTS; 448*153ef166SPaul Zimmerman 449*153ef166SPaul Zimmerman dwc2_bus_start(s); 450*153ef166SPaul Zimmerman dwc2_raise_global_irq(s, GINTSTS_PRTINT); 451*153ef166SPaul Zimmerman } 452*153ef166SPaul Zimmerman 453*153ef166SPaul Zimmerman static void dwc2_detach(USBPort *port) 454*153ef166SPaul Zimmerman { 455*153ef166SPaul Zimmerman DWC2State *s = port->opaque; 456*153ef166SPaul Zimmerman 457*153ef166SPaul Zimmerman trace_usb_dwc2_detach(port); 458*153ef166SPaul Zimmerman assert(port->index == 0); 459*153ef166SPaul Zimmerman 460*153ef166SPaul Zimmerman dwc2_bus_stop(s); 461*153ef166SPaul Zimmerman 462*153ef166SPaul Zimmerman s->hprt0 &= ~(HPRT0_SPD_MASK | HPRT0_SUSP | HPRT0_ENA | HPRT0_CONNSTS); 463*153ef166SPaul Zimmerman s->hprt0 |= HPRT0_CONNDET | HPRT0_ENACHG; 464*153ef166SPaul Zimmerman 465*153ef166SPaul Zimmerman dwc2_raise_global_irq(s, GINTSTS_PRTINT); 466*153ef166SPaul Zimmerman } 467*153ef166SPaul Zimmerman 468*153ef166SPaul Zimmerman static void dwc2_child_detach(USBPort *port, USBDevice *child) 469*153ef166SPaul Zimmerman { 470*153ef166SPaul Zimmerman trace_usb_dwc2_child_detach(port, child); 471*153ef166SPaul Zimmerman assert(port->index == 0); 472*153ef166SPaul Zimmerman } 473*153ef166SPaul Zimmerman 474*153ef166SPaul Zimmerman static void dwc2_wakeup(USBPort *port) 475*153ef166SPaul Zimmerman { 476*153ef166SPaul Zimmerman DWC2State *s = port->opaque; 477*153ef166SPaul Zimmerman 478*153ef166SPaul Zimmerman trace_usb_dwc2_wakeup(port); 479*153ef166SPaul Zimmerman assert(port->index == 0); 480*153ef166SPaul Zimmerman 481*153ef166SPaul Zimmerman if (s->hprt0 & HPRT0_SUSP) { 482*153ef166SPaul Zimmerman s->hprt0 |= HPRT0_RES; 483*153ef166SPaul Zimmerman dwc2_raise_global_irq(s, GINTSTS_PRTINT); 484*153ef166SPaul Zimmerman } 485*153ef166SPaul Zimmerman 486*153ef166SPaul Zimmerman qemu_bh_schedule(s->async_bh); 487*153ef166SPaul Zimmerman } 488*153ef166SPaul Zimmerman 489*153ef166SPaul Zimmerman static void dwc2_async_packet_complete(USBPort *port, USBPacket *packet) 490*153ef166SPaul Zimmerman { 491*153ef166SPaul Zimmerman DWC2State *s = port->opaque; 492*153ef166SPaul Zimmerman DWC2Packet *p; 493*153ef166SPaul Zimmerman USBDevice *dev; 494*153ef166SPaul Zimmerman USBEndpoint *ep; 495*153ef166SPaul Zimmerman 496*153ef166SPaul Zimmerman assert(port->index == 0); 497*153ef166SPaul Zimmerman p = container_of(packet, DWC2Packet, packet); 498*153ef166SPaul Zimmerman dev = dwc2_find_device(s, p->devadr); 499*153ef166SPaul Zimmerman ep = usb_ep_get(dev, p->pid, p->epnum); 500*153ef166SPaul Zimmerman trace_usb_dwc2_async_packet_complete(port, packet, p->index >> 3, dev, 501*153ef166SPaul Zimmerman p->epnum, dirs[p->epdir], p->len); 502*153ef166SPaul Zimmerman assert(p->async == DWC2_ASYNC_INFLIGHT); 503*153ef166SPaul Zimmerman 504*153ef166SPaul Zimmerman if (packet->status == USB_RET_REMOVE_FROM_QUEUE) { 505*153ef166SPaul Zimmerman usb_cancel_packet(packet); 506*153ef166SPaul Zimmerman usb_packet_cleanup(packet); 507*153ef166SPaul Zimmerman return; 508*153ef166SPaul Zimmerman } 509*153ef166SPaul Zimmerman 510*153ef166SPaul Zimmerman dwc2_handle_packet(s, p->devadr, dev, ep, p->index, false); 511*153ef166SPaul Zimmerman 512*153ef166SPaul Zimmerman p->async = DWC2_ASYNC_FINISHED; 513*153ef166SPaul Zimmerman qemu_bh_schedule(s->async_bh); 514*153ef166SPaul Zimmerman } 515*153ef166SPaul Zimmerman 516*153ef166SPaul Zimmerman static USBPortOps dwc2_port_ops = { 517*153ef166SPaul Zimmerman .attach = dwc2_attach, 518*153ef166SPaul Zimmerman .detach = dwc2_detach, 519*153ef166SPaul Zimmerman .child_detach = dwc2_child_detach, 520*153ef166SPaul Zimmerman .wakeup = dwc2_wakeup, 521*153ef166SPaul Zimmerman .complete = dwc2_async_packet_complete, 522*153ef166SPaul Zimmerman }; 523*153ef166SPaul Zimmerman 524*153ef166SPaul Zimmerman static uint32_t dwc2_get_frame_remaining(DWC2State *s) 525*153ef166SPaul Zimmerman { 526*153ef166SPaul Zimmerman uint32_t fr = 0; 527*153ef166SPaul Zimmerman int64_t tks; 528*153ef166SPaul Zimmerman 529*153ef166SPaul Zimmerman tks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->sof_time; 530*153ef166SPaul Zimmerman if (tks < 0) { 531*153ef166SPaul Zimmerman tks = 0; 532*153ef166SPaul Zimmerman } 533*153ef166SPaul Zimmerman 534*153ef166SPaul Zimmerman /* avoid muldiv if possible */ 535*153ef166SPaul Zimmerman if (tks >= s->usb_frame_time) { 536*153ef166SPaul Zimmerman goto out; 537*153ef166SPaul Zimmerman } 538*153ef166SPaul Zimmerman if (tks < s->usb_bit_time) { 539*153ef166SPaul Zimmerman fr = s->fi; 540*153ef166SPaul Zimmerman goto out; 541*153ef166SPaul Zimmerman } 542*153ef166SPaul Zimmerman 543*153ef166SPaul Zimmerman /* tks = number of ns since SOF, divided by 83 (fs) or 10 (hs) */ 544*153ef166SPaul Zimmerman tks = tks / s->usb_bit_time; 545*153ef166SPaul Zimmerman if (tks >= (int64_t)s->fi) { 546*153ef166SPaul Zimmerman goto out; 547*153ef166SPaul Zimmerman } 548*153ef166SPaul Zimmerman 549*153ef166SPaul Zimmerman /* remaining = frame interval minus tks */ 550*153ef166SPaul Zimmerman fr = (uint32_t)((int64_t)s->fi - tks); 551*153ef166SPaul Zimmerman 552*153ef166SPaul Zimmerman out: 553*153ef166SPaul Zimmerman return fr; 554*153ef166SPaul Zimmerman } 555*153ef166SPaul Zimmerman 556*153ef166SPaul Zimmerman static void dwc2_work_bh(void *opaque) 557*153ef166SPaul Zimmerman { 558*153ef166SPaul Zimmerman DWC2State *s = opaque; 559*153ef166SPaul Zimmerman DWC2Packet *p; 560*153ef166SPaul Zimmerman USBDevice *dev; 561*153ef166SPaul Zimmerman USBEndpoint *ep; 562*153ef166SPaul Zimmerman int64_t t_now, expire_time; 563*153ef166SPaul Zimmerman int chan; 564*153ef166SPaul Zimmerman bool found = false; 565*153ef166SPaul Zimmerman 566*153ef166SPaul Zimmerman trace_usb_dwc2_work_bh(); 567*153ef166SPaul Zimmerman if (s->working) { 568*153ef166SPaul Zimmerman return; 569*153ef166SPaul Zimmerman } 570*153ef166SPaul Zimmerman s->working = true; 571*153ef166SPaul Zimmerman 572*153ef166SPaul Zimmerman t_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 573*153ef166SPaul Zimmerman chan = s->next_chan; 574*153ef166SPaul Zimmerman 575*153ef166SPaul Zimmerman do { 576*153ef166SPaul Zimmerman p = &s->packet[chan]; 577*153ef166SPaul Zimmerman if (p->needs_service) { 578*153ef166SPaul Zimmerman dev = dwc2_find_device(s, p->devadr); 579*153ef166SPaul Zimmerman ep = usb_ep_get(dev, p->pid, p->epnum); 580*153ef166SPaul Zimmerman trace_usb_dwc2_work_bh_service(s->next_chan, chan, dev, p->epnum); 581*153ef166SPaul Zimmerman dwc2_handle_packet(s, p->devadr, dev, ep, p->index, true); 582*153ef166SPaul Zimmerman found = true; 583*153ef166SPaul Zimmerman } 584*153ef166SPaul Zimmerman if (++chan == DWC2_NB_CHAN) { 585*153ef166SPaul Zimmerman chan = 0; 586*153ef166SPaul Zimmerman } 587*153ef166SPaul Zimmerman if (found) { 588*153ef166SPaul Zimmerman s->next_chan = chan; 589*153ef166SPaul Zimmerman trace_usb_dwc2_work_bh_next(chan); 590*153ef166SPaul Zimmerman } 591*153ef166SPaul Zimmerman } while (chan != s->next_chan); 592*153ef166SPaul Zimmerman 593*153ef166SPaul Zimmerman if (found) { 594*153ef166SPaul Zimmerman expire_time = t_now + NANOSECONDS_PER_SECOND / 4000; 595*153ef166SPaul Zimmerman timer_mod(s->frame_timer, expire_time); 596*153ef166SPaul Zimmerman } 597*153ef166SPaul Zimmerman s->working = false; 598*153ef166SPaul Zimmerman } 599*153ef166SPaul Zimmerman 600*153ef166SPaul Zimmerman static void dwc2_enable_chan(DWC2State *s, uint32_t index) 601*153ef166SPaul Zimmerman { 602*153ef166SPaul Zimmerman USBDevice *dev; 603*153ef166SPaul Zimmerman USBEndpoint *ep; 604*153ef166SPaul Zimmerman uint32_t hcchar; 605*153ef166SPaul Zimmerman uint32_t hctsiz; 606*153ef166SPaul Zimmerman uint32_t devadr, epnum, epdir, eptype, pid, len; 607*153ef166SPaul Zimmerman DWC2Packet *p; 608*153ef166SPaul Zimmerman 609*153ef166SPaul Zimmerman assert((index >> 3) < DWC2_NB_CHAN); 610*153ef166SPaul Zimmerman p = &s->packet[index >> 3]; 611*153ef166SPaul Zimmerman hcchar = s->hreg1[index]; 612*153ef166SPaul Zimmerman hctsiz = s->hreg1[index + 4]; 613*153ef166SPaul Zimmerman devadr = get_field(hcchar, HCCHAR_DEVADDR); 614*153ef166SPaul Zimmerman epnum = get_field(hcchar, HCCHAR_EPNUM); 615*153ef166SPaul Zimmerman epdir = get_bit(hcchar, HCCHAR_EPDIR); 616*153ef166SPaul Zimmerman eptype = get_field(hcchar, HCCHAR_EPTYPE); 617*153ef166SPaul Zimmerman pid = get_field(hctsiz, TSIZ_SC_MC_PID); 618*153ef166SPaul Zimmerman len = get_field(hctsiz, TSIZ_XFERSIZE); 619*153ef166SPaul Zimmerman 620*153ef166SPaul Zimmerman dev = dwc2_find_device(s, devadr); 621*153ef166SPaul Zimmerman 622*153ef166SPaul Zimmerman trace_usb_dwc2_enable_chan(index >> 3, dev, &p->packet, epnum); 623*153ef166SPaul Zimmerman if (dev == NULL) { 624*153ef166SPaul Zimmerman return; 625*153ef166SPaul Zimmerman } 626*153ef166SPaul Zimmerman 627*153ef166SPaul Zimmerman if (eptype == USB_ENDPOINT_XFER_CONTROL && pid == TSIZ_SC_MC_PID_SETUP) { 628*153ef166SPaul Zimmerman pid = USB_TOKEN_SETUP; 629*153ef166SPaul Zimmerman } else { 630*153ef166SPaul Zimmerman pid = epdir ? USB_TOKEN_IN : USB_TOKEN_OUT; 631*153ef166SPaul Zimmerman } 632*153ef166SPaul Zimmerman 633*153ef166SPaul Zimmerman ep = usb_ep_get(dev, pid, epnum); 634*153ef166SPaul Zimmerman 635*153ef166SPaul Zimmerman /* 636*153ef166SPaul Zimmerman * Hack: Networking doesn't like us delivering large transfers, it kind 637*153ef166SPaul Zimmerman * of works but the latency is horrible. So if the transfer is <= the mtu 638*153ef166SPaul Zimmerman * size, we take that as a hint that this might be a network transfer, 639*153ef166SPaul Zimmerman * and do the transfer packet-by-packet. 640*153ef166SPaul Zimmerman */ 641*153ef166SPaul Zimmerman if (len > 1536) { 642*153ef166SPaul Zimmerman p->small = false; 643*153ef166SPaul Zimmerman } else { 644*153ef166SPaul Zimmerman p->small = true; 645*153ef166SPaul Zimmerman } 646*153ef166SPaul Zimmerman 647*153ef166SPaul Zimmerman dwc2_handle_packet(s, devadr, dev, ep, index, true); 648*153ef166SPaul Zimmerman qemu_bh_schedule(s->async_bh); 649*153ef166SPaul Zimmerman } 650*153ef166SPaul Zimmerman 651*153ef166SPaul Zimmerman static const char *glbregnm[] = { 652*153ef166SPaul Zimmerman "GOTGCTL ", "GOTGINT ", "GAHBCFG ", "GUSBCFG ", "GRSTCTL ", 653*153ef166SPaul Zimmerman "GINTSTS ", "GINTMSK ", "GRXSTSR ", "GRXSTSP ", "GRXFSIZ ", 654*153ef166SPaul Zimmerman "GNPTXFSIZ", "GNPTXSTS ", "GI2CCTL ", "GPVNDCTL ", "GGPIO ", 655*153ef166SPaul Zimmerman "GUID ", "GSNPSID ", "GHWCFG1 ", "GHWCFG2 ", "GHWCFG3 ", 656*153ef166SPaul Zimmerman "GHWCFG4 ", "GLPMCFG ", "GPWRDN ", "GDFIFOCFG", "GADPCTL ", 657*153ef166SPaul Zimmerman "GREFCLK ", "GINTMSK2 ", "GINTSTS2 " 658*153ef166SPaul Zimmerman }; 659*153ef166SPaul Zimmerman 660*153ef166SPaul Zimmerman static uint64_t dwc2_glbreg_read(void *ptr, hwaddr addr, int index, 661*153ef166SPaul Zimmerman unsigned size) 662*153ef166SPaul Zimmerman { 663*153ef166SPaul Zimmerman DWC2State *s = ptr; 664*153ef166SPaul Zimmerman uint32_t val; 665*153ef166SPaul Zimmerman 666*153ef166SPaul Zimmerman assert(addr <= GINTSTS2); 667*153ef166SPaul Zimmerman val = s->glbreg[index]; 668*153ef166SPaul Zimmerman 669*153ef166SPaul Zimmerman switch (addr) { 670*153ef166SPaul Zimmerman case GRSTCTL: 671*153ef166SPaul Zimmerman /* clear any self-clearing bits that were set */ 672*153ef166SPaul Zimmerman val &= ~(GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH | GRSTCTL_IN_TKNQ_FLSH | 673*153ef166SPaul Zimmerman GRSTCTL_FRMCNTRRST | GRSTCTL_HSFTRST | GRSTCTL_CSFTRST); 674*153ef166SPaul Zimmerman s->glbreg[index] = val; 675*153ef166SPaul Zimmerman break; 676*153ef166SPaul Zimmerman default: 677*153ef166SPaul Zimmerman break; 678*153ef166SPaul Zimmerman } 679*153ef166SPaul Zimmerman 680*153ef166SPaul Zimmerman trace_usb_dwc2_glbreg_read(addr, glbregnm[index], val); 681*153ef166SPaul Zimmerman return val; 682*153ef166SPaul Zimmerman } 683*153ef166SPaul Zimmerman 684*153ef166SPaul Zimmerman static void dwc2_glbreg_write(void *ptr, hwaddr addr, int index, uint64_t val, 685*153ef166SPaul Zimmerman unsigned size) 686*153ef166SPaul Zimmerman { 687*153ef166SPaul Zimmerman DWC2State *s = ptr; 688*153ef166SPaul Zimmerman uint64_t orig = val; 689*153ef166SPaul Zimmerman uint32_t *mmio; 690*153ef166SPaul Zimmerman uint32_t old; 691*153ef166SPaul Zimmerman int iflg = 0; 692*153ef166SPaul Zimmerman 693*153ef166SPaul Zimmerman assert(addr <= GINTSTS2); 694*153ef166SPaul Zimmerman mmio = &s->glbreg[index]; 695*153ef166SPaul Zimmerman old = *mmio; 696*153ef166SPaul Zimmerman 697*153ef166SPaul Zimmerman switch (addr) { 698*153ef166SPaul Zimmerman case GOTGCTL: 699*153ef166SPaul Zimmerman /* don't allow setting of read-only bits */ 700*153ef166SPaul Zimmerman val &= ~(GOTGCTL_MULT_VALID_BC_MASK | GOTGCTL_BSESVLD | 701*153ef166SPaul Zimmerman GOTGCTL_ASESVLD | GOTGCTL_DBNC_SHORT | GOTGCTL_CONID_B | 702*153ef166SPaul Zimmerman GOTGCTL_HSTNEGSCS | GOTGCTL_SESREQSCS); 703*153ef166SPaul Zimmerman /* don't allow clearing of read-only bits */ 704*153ef166SPaul Zimmerman val |= old & (GOTGCTL_MULT_VALID_BC_MASK | GOTGCTL_BSESVLD | 705*153ef166SPaul Zimmerman GOTGCTL_ASESVLD | GOTGCTL_DBNC_SHORT | GOTGCTL_CONID_B | 706*153ef166SPaul Zimmerman GOTGCTL_HSTNEGSCS | GOTGCTL_SESREQSCS); 707*153ef166SPaul Zimmerman break; 708*153ef166SPaul Zimmerman case GAHBCFG: 709*153ef166SPaul Zimmerman if ((val & GAHBCFG_GLBL_INTR_EN) && !(old & GAHBCFG_GLBL_INTR_EN)) { 710*153ef166SPaul Zimmerman iflg = 1; 711*153ef166SPaul Zimmerman } 712*153ef166SPaul Zimmerman break; 713*153ef166SPaul Zimmerman case GRSTCTL: 714*153ef166SPaul Zimmerman val |= GRSTCTL_AHBIDLE; 715*153ef166SPaul Zimmerman val &= ~GRSTCTL_DMAREQ; 716*153ef166SPaul Zimmerman if (!(old & GRSTCTL_TXFFLSH) && (val & GRSTCTL_TXFFLSH)) { 717*153ef166SPaul Zimmerman /* TODO - TX fifo flush */ 718*153ef166SPaul Zimmerman qemu_log_mask(LOG_UNIMP, "Tx FIFO flush not implemented\n"); 719*153ef166SPaul Zimmerman } 720*153ef166SPaul Zimmerman if (!(old & GRSTCTL_RXFFLSH) && (val & GRSTCTL_RXFFLSH)) { 721*153ef166SPaul Zimmerman /* TODO - RX fifo flush */ 722*153ef166SPaul Zimmerman qemu_log_mask(LOG_UNIMP, "Rx FIFO flush not implemented\n"); 723*153ef166SPaul Zimmerman } 724*153ef166SPaul Zimmerman if (!(old & GRSTCTL_IN_TKNQ_FLSH) && (val & GRSTCTL_IN_TKNQ_FLSH)) { 725*153ef166SPaul Zimmerman /* TODO - device IN token queue flush */ 726*153ef166SPaul Zimmerman qemu_log_mask(LOG_UNIMP, "Token queue flush not implemented\n"); 727*153ef166SPaul Zimmerman } 728*153ef166SPaul Zimmerman if (!(old & GRSTCTL_FRMCNTRRST) && (val & GRSTCTL_FRMCNTRRST)) { 729*153ef166SPaul Zimmerman /* TODO - host frame counter reset */ 730*153ef166SPaul Zimmerman qemu_log_mask(LOG_UNIMP, "Frame counter reset not implemented\n"); 731*153ef166SPaul Zimmerman } 732*153ef166SPaul Zimmerman if (!(old & GRSTCTL_HSFTRST) && (val & GRSTCTL_HSFTRST)) { 733*153ef166SPaul Zimmerman /* TODO - host soft reset */ 734*153ef166SPaul Zimmerman qemu_log_mask(LOG_UNIMP, "Host soft reset not implemented\n"); 735*153ef166SPaul Zimmerman } 736*153ef166SPaul Zimmerman if (!(old & GRSTCTL_CSFTRST) && (val & GRSTCTL_CSFTRST)) { 737*153ef166SPaul Zimmerman /* TODO - core soft reset */ 738*153ef166SPaul Zimmerman qemu_log_mask(LOG_UNIMP, "Core soft reset not implemented\n"); 739*153ef166SPaul Zimmerman } 740*153ef166SPaul Zimmerman /* don't allow clearing of self-clearing bits */ 741*153ef166SPaul Zimmerman val |= old & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH | 742*153ef166SPaul Zimmerman GRSTCTL_IN_TKNQ_FLSH | GRSTCTL_FRMCNTRRST | 743*153ef166SPaul Zimmerman GRSTCTL_HSFTRST | GRSTCTL_CSFTRST); 744*153ef166SPaul Zimmerman break; 745*153ef166SPaul Zimmerman case GINTSTS: 746*153ef166SPaul Zimmerman /* clear the write-1-to-clear bits */ 747*153ef166SPaul Zimmerman val |= ~old; 748*153ef166SPaul Zimmerman val = ~val; 749*153ef166SPaul Zimmerman /* don't allow clearing of read-only bits */ 750*153ef166SPaul Zimmerman val |= old & (GINTSTS_PTXFEMP | GINTSTS_HCHINT | GINTSTS_PRTINT | 751*153ef166SPaul Zimmerman GINTSTS_OEPINT | GINTSTS_IEPINT | GINTSTS_GOUTNAKEFF | 752*153ef166SPaul Zimmerman GINTSTS_GINNAKEFF | GINTSTS_NPTXFEMP | GINTSTS_RXFLVL | 753*153ef166SPaul Zimmerman GINTSTS_OTGINT | GINTSTS_CURMODE_HOST); 754*153ef166SPaul Zimmerman iflg = 1; 755*153ef166SPaul Zimmerman break; 756*153ef166SPaul Zimmerman case GINTMSK: 757*153ef166SPaul Zimmerman iflg = 1; 758*153ef166SPaul Zimmerman break; 759*153ef166SPaul Zimmerman default: 760*153ef166SPaul Zimmerman break; 761*153ef166SPaul Zimmerman } 762*153ef166SPaul Zimmerman 763*153ef166SPaul Zimmerman trace_usb_dwc2_glbreg_write(addr, glbregnm[index], orig, old, val); 764*153ef166SPaul Zimmerman *mmio = val; 765*153ef166SPaul Zimmerman 766*153ef166SPaul Zimmerman if (iflg) { 767*153ef166SPaul Zimmerman dwc2_update_irq(s); 768*153ef166SPaul Zimmerman } 769*153ef166SPaul Zimmerman } 770*153ef166SPaul Zimmerman 771*153ef166SPaul Zimmerman static uint64_t dwc2_fszreg_read(void *ptr, hwaddr addr, int index, 772*153ef166SPaul Zimmerman unsigned size) 773*153ef166SPaul Zimmerman { 774*153ef166SPaul Zimmerman DWC2State *s = ptr; 775*153ef166SPaul Zimmerman uint32_t val; 776*153ef166SPaul Zimmerman 777*153ef166SPaul Zimmerman assert(addr == HPTXFSIZ); 778*153ef166SPaul Zimmerman val = s->fszreg[index]; 779*153ef166SPaul Zimmerman 780*153ef166SPaul Zimmerman trace_usb_dwc2_fszreg_read(addr, val); 781*153ef166SPaul Zimmerman return val; 782*153ef166SPaul Zimmerman } 783*153ef166SPaul Zimmerman 784*153ef166SPaul Zimmerman static void dwc2_fszreg_write(void *ptr, hwaddr addr, int index, uint64_t val, 785*153ef166SPaul Zimmerman unsigned size) 786*153ef166SPaul Zimmerman { 787*153ef166SPaul Zimmerman DWC2State *s = ptr; 788*153ef166SPaul Zimmerman uint64_t orig = val; 789*153ef166SPaul Zimmerman uint32_t *mmio; 790*153ef166SPaul Zimmerman uint32_t old; 791*153ef166SPaul Zimmerman 792*153ef166SPaul Zimmerman assert(addr == HPTXFSIZ); 793*153ef166SPaul Zimmerman mmio = &s->fszreg[index]; 794*153ef166SPaul Zimmerman old = *mmio; 795*153ef166SPaul Zimmerman 796*153ef166SPaul Zimmerman trace_usb_dwc2_fszreg_write(addr, orig, old, val); 797*153ef166SPaul Zimmerman *mmio = val; 798*153ef166SPaul Zimmerman } 799*153ef166SPaul Zimmerman 800*153ef166SPaul Zimmerman static const char *hreg0nm[] = { 801*153ef166SPaul Zimmerman "HCFG ", "HFIR ", "HFNUM ", "<rsvd> ", "HPTXSTS ", 802*153ef166SPaul Zimmerman "HAINT ", "HAINTMSK ", "HFLBADDR ", "<rsvd> ", "<rsvd> ", 803*153ef166SPaul Zimmerman "<rsvd> ", "<rsvd> ", "<rsvd> ", "<rsvd> ", "<rsvd> ", 804*153ef166SPaul Zimmerman "<rsvd> ", "HPRT0 " 805*153ef166SPaul Zimmerman }; 806*153ef166SPaul Zimmerman 807*153ef166SPaul Zimmerman static uint64_t dwc2_hreg0_read(void *ptr, hwaddr addr, int index, 808*153ef166SPaul Zimmerman unsigned size) 809*153ef166SPaul Zimmerman { 810*153ef166SPaul Zimmerman DWC2State *s = ptr; 811*153ef166SPaul Zimmerman uint32_t val; 812*153ef166SPaul Zimmerman 813*153ef166SPaul Zimmerman assert(addr >= HCFG && addr <= HPRT0); 814*153ef166SPaul Zimmerman val = s->hreg0[index]; 815*153ef166SPaul Zimmerman 816*153ef166SPaul Zimmerman switch (addr) { 817*153ef166SPaul Zimmerman case HFNUM: 818*153ef166SPaul Zimmerman val = (dwc2_get_frame_remaining(s) << HFNUM_FRREM_SHIFT) | 819*153ef166SPaul Zimmerman (s->hfnum << HFNUM_FRNUM_SHIFT); 820*153ef166SPaul Zimmerman break; 821*153ef166SPaul Zimmerman default: 822*153ef166SPaul Zimmerman break; 823*153ef166SPaul Zimmerman } 824*153ef166SPaul Zimmerman 825*153ef166SPaul Zimmerman trace_usb_dwc2_hreg0_read(addr, hreg0nm[index], val); 826*153ef166SPaul Zimmerman return val; 827*153ef166SPaul Zimmerman } 828*153ef166SPaul Zimmerman 829*153ef166SPaul Zimmerman static void dwc2_hreg0_write(void *ptr, hwaddr addr, int index, uint64_t val, 830*153ef166SPaul Zimmerman unsigned size) 831*153ef166SPaul Zimmerman { 832*153ef166SPaul Zimmerman DWC2State *s = ptr; 833*153ef166SPaul Zimmerman USBDevice *dev = s->uport.dev; 834*153ef166SPaul Zimmerman uint64_t orig = val; 835*153ef166SPaul Zimmerman uint32_t *mmio; 836*153ef166SPaul Zimmerman uint32_t tval, told, old; 837*153ef166SPaul Zimmerman int prst = 0; 838*153ef166SPaul Zimmerman int iflg = 0; 839*153ef166SPaul Zimmerman 840*153ef166SPaul Zimmerman assert(addr >= HCFG && addr <= HPRT0); 841*153ef166SPaul Zimmerman mmio = &s->hreg0[index]; 842*153ef166SPaul Zimmerman old = *mmio; 843*153ef166SPaul Zimmerman 844*153ef166SPaul Zimmerman switch (addr) { 845*153ef166SPaul Zimmerman case HFIR: 846*153ef166SPaul Zimmerman break; 847*153ef166SPaul Zimmerman case HFNUM: 848*153ef166SPaul Zimmerman case HPTXSTS: 849*153ef166SPaul Zimmerman case HAINT: 850*153ef166SPaul Zimmerman qemu_log_mask(LOG_GUEST_ERROR, "%s: write to read-only register\n", 851*153ef166SPaul Zimmerman __func__); 852*153ef166SPaul Zimmerman return; 853*153ef166SPaul Zimmerman case HAINTMSK: 854*153ef166SPaul Zimmerman val &= 0xffff; 855*153ef166SPaul Zimmerman break; 856*153ef166SPaul Zimmerman case HPRT0: 857*153ef166SPaul Zimmerman /* don't allow clearing of read-only bits */ 858*153ef166SPaul Zimmerman val |= old & (HPRT0_SPD_MASK | HPRT0_LNSTS_MASK | HPRT0_OVRCURRACT | 859*153ef166SPaul Zimmerman HPRT0_CONNSTS); 860*153ef166SPaul Zimmerman /* don't allow clearing of self-clearing bits */ 861*153ef166SPaul Zimmerman val |= old & (HPRT0_SUSP | HPRT0_RES); 862*153ef166SPaul Zimmerman /* don't allow setting of self-setting bits */ 863*153ef166SPaul Zimmerman if (!(old & HPRT0_ENA) && (val & HPRT0_ENA)) { 864*153ef166SPaul Zimmerman val &= ~HPRT0_ENA; 865*153ef166SPaul Zimmerman } 866*153ef166SPaul Zimmerman /* clear the write-1-to-clear bits */ 867*153ef166SPaul Zimmerman tval = val & (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA | 868*153ef166SPaul Zimmerman HPRT0_CONNDET); 869*153ef166SPaul Zimmerman told = old & (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA | 870*153ef166SPaul Zimmerman HPRT0_CONNDET); 871*153ef166SPaul Zimmerman tval |= ~told; 872*153ef166SPaul Zimmerman tval = ~tval; 873*153ef166SPaul Zimmerman tval &= (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA | 874*153ef166SPaul Zimmerman HPRT0_CONNDET); 875*153ef166SPaul Zimmerman val &= ~(HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_ENA | 876*153ef166SPaul Zimmerman HPRT0_CONNDET); 877*153ef166SPaul Zimmerman val |= tval; 878*153ef166SPaul Zimmerman if (!(val & HPRT0_RST) && (old & HPRT0_RST)) { 879*153ef166SPaul Zimmerman if (dev && dev->attached) { 880*153ef166SPaul Zimmerman val |= HPRT0_ENA | HPRT0_ENACHG; 881*153ef166SPaul Zimmerman prst = 1; 882*153ef166SPaul Zimmerman } 883*153ef166SPaul Zimmerman } 884*153ef166SPaul Zimmerman if (val & (HPRT0_OVRCURRCHG | HPRT0_ENACHG | HPRT0_CONNDET)) { 885*153ef166SPaul Zimmerman iflg = 1; 886*153ef166SPaul Zimmerman } else { 887*153ef166SPaul Zimmerman iflg = -1; 888*153ef166SPaul Zimmerman } 889*153ef166SPaul Zimmerman break; 890*153ef166SPaul Zimmerman default: 891*153ef166SPaul Zimmerman break; 892*153ef166SPaul Zimmerman } 893*153ef166SPaul Zimmerman 894*153ef166SPaul Zimmerman if (prst) { 895*153ef166SPaul Zimmerman trace_usb_dwc2_hreg0_write(addr, hreg0nm[index], orig, old, 896*153ef166SPaul Zimmerman val & ~HPRT0_CONNDET); 897*153ef166SPaul Zimmerman trace_usb_dwc2_hreg0_action("call usb_port_reset"); 898*153ef166SPaul Zimmerman usb_port_reset(&s->uport); 899*153ef166SPaul Zimmerman val &= ~HPRT0_CONNDET; 900*153ef166SPaul Zimmerman } else { 901*153ef166SPaul Zimmerman trace_usb_dwc2_hreg0_write(addr, hreg0nm[index], orig, old, val); 902*153ef166SPaul Zimmerman } 903*153ef166SPaul Zimmerman 904*153ef166SPaul Zimmerman *mmio = val; 905*153ef166SPaul Zimmerman 906*153ef166SPaul Zimmerman if (iflg > 0) { 907*153ef166SPaul Zimmerman trace_usb_dwc2_hreg0_action("enable PRTINT"); 908*153ef166SPaul Zimmerman dwc2_raise_global_irq(s, GINTSTS_PRTINT); 909*153ef166SPaul Zimmerman } else if (iflg < 0) { 910*153ef166SPaul Zimmerman trace_usb_dwc2_hreg0_action("disable PRTINT"); 911*153ef166SPaul Zimmerman dwc2_lower_global_irq(s, GINTSTS_PRTINT); 912*153ef166SPaul Zimmerman } 913*153ef166SPaul Zimmerman } 914*153ef166SPaul Zimmerman 915*153ef166SPaul Zimmerman static const char *hreg1nm[] = { 916*153ef166SPaul Zimmerman "HCCHAR ", "HCSPLT ", "HCINT ", "HCINTMSK", "HCTSIZ ", "HCDMA ", 917*153ef166SPaul Zimmerman "<rsvd> ", "HCDMAB " 918*153ef166SPaul Zimmerman }; 919*153ef166SPaul Zimmerman 920*153ef166SPaul Zimmerman static uint64_t dwc2_hreg1_read(void *ptr, hwaddr addr, int index, 921*153ef166SPaul Zimmerman unsigned size) 922*153ef166SPaul Zimmerman { 923*153ef166SPaul Zimmerman DWC2State *s = ptr; 924*153ef166SPaul Zimmerman uint32_t val; 925*153ef166SPaul Zimmerman 926*153ef166SPaul Zimmerman assert(addr >= HCCHAR(0) && addr <= HCDMAB(DWC2_NB_CHAN - 1)); 927*153ef166SPaul Zimmerman val = s->hreg1[index]; 928*153ef166SPaul Zimmerman 929*153ef166SPaul Zimmerman trace_usb_dwc2_hreg1_read(addr, hreg1nm[index & 7], addr >> 5, val); 930*153ef166SPaul Zimmerman return val; 931*153ef166SPaul Zimmerman } 932*153ef166SPaul Zimmerman 933*153ef166SPaul Zimmerman static void dwc2_hreg1_write(void *ptr, hwaddr addr, int index, uint64_t val, 934*153ef166SPaul Zimmerman unsigned size) 935*153ef166SPaul Zimmerman { 936*153ef166SPaul Zimmerman DWC2State *s = ptr; 937*153ef166SPaul Zimmerman uint64_t orig = val; 938*153ef166SPaul Zimmerman uint32_t *mmio; 939*153ef166SPaul Zimmerman uint32_t old; 940*153ef166SPaul Zimmerman int iflg = 0; 941*153ef166SPaul Zimmerman int enflg = 0; 942*153ef166SPaul Zimmerman int disflg = 0; 943*153ef166SPaul Zimmerman 944*153ef166SPaul Zimmerman assert(addr >= HCCHAR(0) && addr <= HCDMAB(DWC2_NB_CHAN - 1)); 945*153ef166SPaul Zimmerman mmio = &s->hreg1[index]; 946*153ef166SPaul Zimmerman old = *mmio; 947*153ef166SPaul Zimmerman 948*153ef166SPaul Zimmerman switch (HSOTG_REG(0x500) + (addr & 0x1c)) { 949*153ef166SPaul Zimmerman case HCCHAR(0): 950*153ef166SPaul Zimmerman if ((val & HCCHAR_CHDIS) && !(old & HCCHAR_CHDIS)) { 951*153ef166SPaul Zimmerman val &= ~(HCCHAR_CHENA | HCCHAR_CHDIS); 952*153ef166SPaul Zimmerman disflg = 1; 953*153ef166SPaul Zimmerman } else { 954*153ef166SPaul Zimmerman val |= old & HCCHAR_CHDIS; 955*153ef166SPaul Zimmerman if ((val & HCCHAR_CHENA) && !(old & HCCHAR_CHENA)) { 956*153ef166SPaul Zimmerman val &= ~HCCHAR_CHDIS; 957*153ef166SPaul Zimmerman enflg = 1; 958*153ef166SPaul Zimmerman } else { 959*153ef166SPaul Zimmerman val |= old & HCCHAR_CHENA; 960*153ef166SPaul Zimmerman } 961*153ef166SPaul Zimmerman } 962*153ef166SPaul Zimmerman break; 963*153ef166SPaul Zimmerman case HCINT(0): 964*153ef166SPaul Zimmerman /* clear the write-1-to-clear bits */ 965*153ef166SPaul Zimmerman val |= ~old; 966*153ef166SPaul Zimmerman val = ~val; 967*153ef166SPaul Zimmerman val &= ~HCINTMSK_RESERVED14_31; 968*153ef166SPaul Zimmerman iflg = 1; 969*153ef166SPaul Zimmerman break; 970*153ef166SPaul Zimmerman case HCINTMSK(0): 971*153ef166SPaul Zimmerman val &= ~HCINTMSK_RESERVED14_31; 972*153ef166SPaul Zimmerman iflg = 1; 973*153ef166SPaul Zimmerman break; 974*153ef166SPaul Zimmerman case HCDMAB(0): 975*153ef166SPaul Zimmerman qemu_log_mask(LOG_GUEST_ERROR, "%s: write to read-only register\n", 976*153ef166SPaul Zimmerman __func__); 977*153ef166SPaul Zimmerman return; 978*153ef166SPaul Zimmerman default: 979*153ef166SPaul Zimmerman break; 980*153ef166SPaul Zimmerman } 981*153ef166SPaul Zimmerman 982*153ef166SPaul Zimmerman trace_usb_dwc2_hreg1_write(addr, hreg1nm[index & 7], index >> 3, orig, 983*153ef166SPaul Zimmerman old, val); 984*153ef166SPaul Zimmerman *mmio = val; 985*153ef166SPaul Zimmerman 986*153ef166SPaul Zimmerman if (disflg) { 987*153ef166SPaul Zimmerman /* set ChHltd in HCINT */ 988*153ef166SPaul Zimmerman s->hreg1[(index & ~7) + 2] |= HCINTMSK_CHHLTD; 989*153ef166SPaul Zimmerman iflg = 1; 990*153ef166SPaul Zimmerman } 991*153ef166SPaul Zimmerman 992*153ef166SPaul Zimmerman if (enflg) { 993*153ef166SPaul Zimmerman dwc2_enable_chan(s, index & ~7); 994*153ef166SPaul Zimmerman } 995*153ef166SPaul Zimmerman 996*153ef166SPaul Zimmerman if (iflg) { 997*153ef166SPaul Zimmerman dwc2_update_hc_irq(s, index & ~7); 998*153ef166SPaul Zimmerman } 999*153ef166SPaul Zimmerman } 1000*153ef166SPaul Zimmerman 1001*153ef166SPaul Zimmerman static const char *pcgregnm[] = { 1002*153ef166SPaul Zimmerman "PCGCTL ", "PCGCCTL1 " 1003*153ef166SPaul Zimmerman }; 1004*153ef166SPaul Zimmerman 1005*153ef166SPaul Zimmerman static uint64_t dwc2_pcgreg_read(void *ptr, hwaddr addr, int index, 1006*153ef166SPaul Zimmerman unsigned size) 1007*153ef166SPaul Zimmerman { 1008*153ef166SPaul Zimmerman DWC2State *s = ptr; 1009*153ef166SPaul Zimmerman uint32_t val; 1010*153ef166SPaul Zimmerman 1011*153ef166SPaul Zimmerman assert(addr >= PCGCTL && addr <= PCGCCTL1); 1012*153ef166SPaul Zimmerman val = s->pcgreg[index]; 1013*153ef166SPaul Zimmerman 1014*153ef166SPaul Zimmerman trace_usb_dwc2_pcgreg_read(addr, pcgregnm[index], val); 1015*153ef166SPaul Zimmerman return val; 1016*153ef166SPaul Zimmerman } 1017*153ef166SPaul Zimmerman 1018*153ef166SPaul Zimmerman static void dwc2_pcgreg_write(void *ptr, hwaddr addr, int index, 1019*153ef166SPaul Zimmerman uint64_t val, unsigned size) 1020*153ef166SPaul Zimmerman { 1021*153ef166SPaul Zimmerman DWC2State *s = ptr; 1022*153ef166SPaul Zimmerman uint64_t orig = val; 1023*153ef166SPaul Zimmerman uint32_t *mmio; 1024*153ef166SPaul Zimmerman uint32_t old; 1025*153ef166SPaul Zimmerman 1026*153ef166SPaul Zimmerman assert(addr >= PCGCTL && addr <= PCGCCTL1); 1027*153ef166SPaul Zimmerman mmio = &s->pcgreg[index]; 1028*153ef166SPaul Zimmerman old = *mmio; 1029*153ef166SPaul Zimmerman 1030*153ef166SPaul Zimmerman trace_usb_dwc2_pcgreg_write(addr, pcgregnm[index], orig, old, val); 1031*153ef166SPaul Zimmerman *mmio = val; 1032*153ef166SPaul Zimmerman } 1033*153ef166SPaul Zimmerman 1034*153ef166SPaul Zimmerman static uint64_t dwc2_hsotg_read(void *ptr, hwaddr addr, unsigned size) 1035*153ef166SPaul Zimmerman { 1036*153ef166SPaul Zimmerman uint64_t val; 1037*153ef166SPaul Zimmerman 1038*153ef166SPaul Zimmerman switch (addr) { 1039*153ef166SPaul Zimmerman case HSOTG_REG(0x000) ... HSOTG_REG(0x0fc): 1040*153ef166SPaul Zimmerman val = dwc2_glbreg_read(ptr, addr, (addr - HSOTG_REG(0x000)) >> 2, size); 1041*153ef166SPaul Zimmerman break; 1042*153ef166SPaul Zimmerman case HSOTG_REG(0x100): 1043*153ef166SPaul Zimmerman val = dwc2_fszreg_read(ptr, addr, (addr - HSOTG_REG(0x100)) >> 2, size); 1044*153ef166SPaul Zimmerman break; 1045*153ef166SPaul Zimmerman case HSOTG_REG(0x104) ... HSOTG_REG(0x3fc): 1046*153ef166SPaul Zimmerman /* Gadget-mode registers, just return 0 for now */ 1047*153ef166SPaul Zimmerman val = 0; 1048*153ef166SPaul Zimmerman break; 1049*153ef166SPaul Zimmerman case HSOTG_REG(0x400) ... HSOTG_REG(0x4fc): 1050*153ef166SPaul Zimmerman val = dwc2_hreg0_read(ptr, addr, (addr - HSOTG_REG(0x400)) >> 2, size); 1051*153ef166SPaul Zimmerman break; 1052*153ef166SPaul Zimmerman case HSOTG_REG(0x500) ... HSOTG_REG(0x7fc): 1053*153ef166SPaul Zimmerman val = dwc2_hreg1_read(ptr, addr, (addr - HSOTG_REG(0x500)) >> 2, size); 1054*153ef166SPaul Zimmerman break; 1055*153ef166SPaul Zimmerman case HSOTG_REG(0x800) ... HSOTG_REG(0xdfc): 1056*153ef166SPaul Zimmerman /* Gadget-mode registers, just return 0 for now */ 1057*153ef166SPaul Zimmerman val = 0; 1058*153ef166SPaul Zimmerman break; 1059*153ef166SPaul Zimmerman case HSOTG_REG(0xe00) ... HSOTG_REG(0xffc): 1060*153ef166SPaul Zimmerman val = dwc2_pcgreg_read(ptr, addr, (addr - HSOTG_REG(0xe00)) >> 2, size); 1061*153ef166SPaul Zimmerman break; 1062*153ef166SPaul Zimmerman default: 1063*153ef166SPaul Zimmerman g_assert_not_reached(); 1064*153ef166SPaul Zimmerman } 1065*153ef166SPaul Zimmerman 1066*153ef166SPaul Zimmerman return val; 1067*153ef166SPaul Zimmerman } 1068*153ef166SPaul Zimmerman 1069*153ef166SPaul Zimmerman static void dwc2_hsotg_write(void *ptr, hwaddr addr, uint64_t val, 1070*153ef166SPaul Zimmerman unsigned size) 1071*153ef166SPaul Zimmerman { 1072*153ef166SPaul Zimmerman switch (addr) { 1073*153ef166SPaul Zimmerman case HSOTG_REG(0x000) ... HSOTG_REG(0x0fc): 1074*153ef166SPaul Zimmerman dwc2_glbreg_write(ptr, addr, (addr - HSOTG_REG(0x000)) >> 2, val, size); 1075*153ef166SPaul Zimmerman break; 1076*153ef166SPaul Zimmerman case HSOTG_REG(0x100): 1077*153ef166SPaul Zimmerman dwc2_fszreg_write(ptr, addr, (addr - HSOTG_REG(0x100)) >> 2, val, size); 1078*153ef166SPaul Zimmerman break; 1079*153ef166SPaul Zimmerman case HSOTG_REG(0x104) ... HSOTG_REG(0x3fc): 1080*153ef166SPaul Zimmerman /* Gadget-mode registers, do nothing for now */ 1081*153ef166SPaul Zimmerman break; 1082*153ef166SPaul Zimmerman case HSOTG_REG(0x400) ... HSOTG_REG(0x4fc): 1083*153ef166SPaul Zimmerman dwc2_hreg0_write(ptr, addr, (addr - HSOTG_REG(0x400)) >> 2, val, size); 1084*153ef166SPaul Zimmerman break; 1085*153ef166SPaul Zimmerman case HSOTG_REG(0x500) ... HSOTG_REG(0x7fc): 1086*153ef166SPaul Zimmerman dwc2_hreg1_write(ptr, addr, (addr - HSOTG_REG(0x500)) >> 2, val, size); 1087*153ef166SPaul Zimmerman break; 1088*153ef166SPaul Zimmerman case HSOTG_REG(0x800) ... HSOTG_REG(0xdfc): 1089*153ef166SPaul Zimmerman /* Gadget-mode registers, do nothing for now */ 1090*153ef166SPaul Zimmerman break; 1091*153ef166SPaul Zimmerman case HSOTG_REG(0xe00) ... HSOTG_REG(0xffc): 1092*153ef166SPaul Zimmerman dwc2_pcgreg_write(ptr, addr, (addr - HSOTG_REG(0xe00)) >> 2, val, size); 1093*153ef166SPaul Zimmerman break; 1094*153ef166SPaul Zimmerman default: 1095*153ef166SPaul Zimmerman g_assert_not_reached(); 1096*153ef166SPaul Zimmerman } 1097*153ef166SPaul Zimmerman } 1098*153ef166SPaul Zimmerman 1099*153ef166SPaul Zimmerman static const MemoryRegionOps dwc2_mmio_hsotg_ops = { 1100*153ef166SPaul Zimmerman .read = dwc2_hsotg_read, 1101*153ef166SPaul Zimmerman .write = dwc2_hsotg_write, 1102*153ef166SPaul Zimmerman .impl.min_access_size = 4, 1103*153ef166SPaul Zimmerman .impl.max_access_size = 4, 1104*153ef166SPaul Zimmerman .endianness = DEVICE_LITTLE_ENDIAN, 1105*153ef166SPaul Zimmerman }; 1106*153ef166SPaul Zimmerman 1107*153ef166SPaul Zimmerman static uint64_t dwc2_hreg2_read(void *ptr, hwaddr addr, unsigned size) 1108*153ef166SPaul Zimmerman { 1109*153ef166SPaul Zimmerman /* TODO - implement FIFOs to support slave mode */ 1110*153ef166SPaul Zimmerman trace_usb_dwc2_hreg2_read(addr, addr >> 12, 0); 1111*153ef166SPaul Zimmerman qemu_log_mask(LOG_UNIMP, "FIFO read not implemented\n"); 1112*153ef166SPaul Zimmerman return 0; 1113*153ef166SPaul Zimmerman } 1114*153ef166SPaul Zimmerman 1115*153ef166SPaul Zimmerman static void dwc2_hreg2_write(void *ptr, hwaddr addr, uint64_t val, 1116*153ef166SPaul Zimmerman unsigned size) 1117*153ef166SPaul Zimmerman { 1118*153ef166SPaul Zimmerman uint64_t orig = val; 1119*153ef166SPaul Zimmerman 1120*153ef166SPaul Zimmerman /* TODO - implement FIFOs to support slave mode */ 1121*153ef166SPaul Zimmerman trace_usb_dwc2_hreg2_write(addr, addr >> 12, orig, 0, val); 1122*153ef166SPaul Zimmerman qemu_log_mask(LOG_UNIMP, "FIFO write not implemented\n"); 1123*153ef166SPaul Zimmerman } 1124*153ef166SPaul Zimmerman 1125*153ef166SPaul Zimmerman static const MemoryRegionOps dwc2_mmio_hreg2_ops = { 1126*153ef166SPaul Zimmerman .read = dwc2_hreg2_read, 1127*153ef166SPaul Zimmerman .write = dwc2_hreg2_write, 1128*153ef166SPaul Zimmerman .impl.min_access_size = 4, 1129*153ef166SPaul Zimmerman .impl.max_access_size = 4, 1130*153ef166SPaul Zimmerman .endianness = DEVICE_LITTLE_ENDIAN, 1131*153ef166SPaul Zimmerman }; 1132*153ef166SPaul Zimmerman 1133*153ef166SPaul Zimmerman static void dwc2_wakeup_endpoint(USBBus *bus, USBEndpoint *ep, 1134*153ef166SPaul Zimmerman unsigned int stream) 1135*153ef166SPaul Zimmerman { 1136*153ef166SPaul Zimmerman DWC2State *s = container_of(bus, DWC2State, bus); 1137*153ef166SPaul Zimmerman 1138*153ef166SPaul Zimmerman trace_usb_dwc2_wakeup_endpoint(ep, stream); 1139*153ef166SPaul Zimmerman 1140*153ef166SPaul Zimmerman /* TODO - do something here? */ 1141*153ef166SPaul Zimmerman qemu_bh_schedule(s->async_bh); 1142*153ef166SPaul Zimmerman } 1143*153ef166SPaul Zimmerman 1144*153ef166SPaul Zimmerman static USBBusOps dwc2_bus_ops = { 1145*153ef166SPaul Zimmerman .wakeup_endpoint = dwc2_wakeup_endpoint, 1146*153ef166SPaul Zimmerman }; 1147*153ef166SPaul Zimmerman 1148*153ef166SPaul Zimmerman static void dwc2_work_timer(void *opaque) 1149*153ef166SPaul Zimmerman { 1150*153ef166SPaul Zimmerman DWC2State *s = opaque; 1151*153ef166SPaul Zimmerman 1152*153ef166SPaul Zimmerman trace_usb_dwc2_work_timer(); 1153*153ef166SPaul Zimmerman qemu_bh_schedule(s->async_bh); 1154*153ef166SPaul Zimmerman } 1155*153ef166SPaul Zimmerman 1156*153ef166SPaul Zimmerman static void dwc2_reset_enter(Object *obj, ResetType type) 1157*153ef166SPaul Zimmerman { 1158*153ef166SPaul Zimmerman DWC2Class *c = DWC2_GET_CLASS(obj); 1159*153ef166SPaul Zimmerman DWC2State *s = DWC2_USB(obj); 1160*153ef166SPaul Zimmerman int i; 1161*153ef166SPaul Zimmerman 1162*153ef166SPaul Zimmerman trace_usb_dwc2_reset_enter(); 1163*153ef166SPaul Zimmerman 1164*153ef166SPaul Zimmerman if (c->parent_phases.enter) { 1165*153ef166SPaul Zimmerman c->parent_phases.enter(obj, type); 1166*153ef166SPaul Zimmerman } 1167*153ef166SPaul Zimmerman 1168*153ef166SPaul Zimmerman timer_del(s->frame_timer); 1169*153ef166SPaul Zimmerman qemu_bh_cancel(s->async_bh); 1170*153ef166SPaul Zimmerman 1171*153ef166SPaul Zimmerman if (s->uport.dev && s->uport.dev->attached) { 1172*153ef166SPaul Zimmerman usb_detach(&s->uport); 1173*153ef166SPaul Zimmerman } 1174*153ef166SPaul Zimmerman 1175*153ef166SPaul Zimmerman dwc2_bus_stop(s); 1176*153ef166SPaul Zimmerman 1177*153ef166SPaul Zimmerman s->gotgctl = GOTGCTL_BSESVLD | GOTGCTL_ASESVLD | GOTGCTL_CONID_B; 1178*153ef166SPaul Zimmerman s->gotgint = 0; 1179*153ef166SPaul Zimmerman s->gahbcfg = 0; 1180*153ef166SPaul Zimmerman s->gusbcfg = 5 << GUSBCFG_USBTRDTIM_SHIFT; 1181*153ef166SPaul Zimmerman s->grstctl = GRSTCTL_AHBIDLE; 1182*153ef166SPaul Zimmerman s->gintsts = GINTSTS_CONIDSTSCHNG | GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP | 1183*153ef166SPaul Zimmerman GINTSTS_CURMODE_HOST; 1184*153ef166SPaul Zimmerman s->gintmsk = 0; 1185*153ef166SPaul Zimmerman s->grxstsr = 0; 1186*153ef166SPaul Zimmerman s->grxstsp = 0; 1187*153ef166SPaul Zimmerman s->grxfsiz = 1024; 1188*153ef166SPaul Zimmerman s->gnptxfsiz = 1024 << FIFOSIZE_DEPTH_SHIFT; 1189*153ef166SPaul Zimmerman s->gnptxsts = (4 << FIFOSIZE_DEPTH_SHIFT) | 1024; 1190*153ef166SPaul Zimmerman s->gi2cctl = GI2CCTL_I2CDATSE0 | GI2CCTL_ACK; 1191*153ef166SPaul Zimmerman s->gpvndctl = 0; 1192*153ef166SPaul Zimmerman s->ggpio = 0; 1193*153ef166SPaul Zimmerman s->guid = 0; 1194*153ef166SPaul Zimmerman s->gsnpsid = 0x4f54294a; 1195*153ef166SPaul Zimmerman s->ghwcfg1 = 0; 1196*153ef166SPaul Zimmerman s->ghwcfg2 = (8 << GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT) | 1197*153ef166SPaul Zimmerman (4 << GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT) | 1198*153ef166SPaul Zimmerman (4 << GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT) | 1199*153ef166SPaul Zimmerman GHWCFG2_DYNAMIC_FIFO | 1200*153ef166SPaul Zimmerman GHWCFG2_PERIO_EP_SUPPORTED | 1201*153ef166SPaul Zimmerman ((DWC2_NB_CHAN - 1) << GHWCFG2_NUM_HOST_CHAN_SHIFT) | 1202*153ef166SPaul Zimmerman (GHWCFG2_INT_DMA_ARCH << GHWCFG2_ARCHITECTURE_SHIFT) | 1203*153ef166SPaul Zimmerman (GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST << GHWCFG2_OP_MODE_SHIFT); 1204*153ef166SPaul Zimmerman s->ghwcfg3 = (4096 << GHWCFG3_DFIFO_DEPTH_SHIFT) | 1205*153ef166SPaul Zimmerman (4 << GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT) | 1206*153ef166SPaul Zimmerman (4 << GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT); 1207*153ef166SPaul Zimmerman s->ghwcfg4 = 0; 1208*153ef166SPaul Zimmerman s->glpmcfg = 0; 1209*153ef166SPaul Zimmerman s->gpwrdn = GPWRDN_PWRDNRSTN; 1210*153ef166SPaul Zimmerman s->gdfifocfg = 0; 1211*153ef166SPaul Zimmerman s->gadpctl = 0; 1212*153ef166SPaul Zimmerman s->grefclk = 0; 1213*153ef166SPaul Zimmerman s->gintmsk2 = 0; 1214*153ef166SPaul Zimmerman s->gintsts2 = 0; 1215*153ef166SPaul Zimmerman 1216*153ef166SPaul Zimmerman s->hptxfsiz = 500 << FIFOSIZE_DEPTH_SHIFT; 1217*153ef166SPaul Zimmerman 1218*153ef166SPaul Zimmerman s->hcfg = 2 << HCFG_RESVALID_SHIFT; 1219*153ef166SPaul Zimmerman s->hfir = 60000; 1220*153ef166SPaul Zimmerman s->hfnum = 0x3fff; 1221*153ef166SPaul Zimmerman s->hptxsts = (16 << TXSTS_QSPCAVAIL_SHIFT) | 32768; 1222*153ef166SPaul Zimmerman s->haint = 0; 1223*153ef166SPaul Zimmerman s->haintmsk = 0; 1224*153ef166SPaul Zimmerman s->hprt0 = 0; 1225*153ef166SPaul Zimmerman 1226*153ef166SPaul Zimmerman memset(s->hreg1, 0, sizeof(s->hreg1)); 1227*153ef166SPaul Zimmerman memset(s->pcgreg, 0, sizeof(s->pcgreg)); 1228*153ef166SPaul Zimmerman 1229*153ef166SPaul Zimmerman s->sof_time = 0; 1230*153ef166SPaul Zimmerman s->frame_number = 0; 1231*153ef166SPaul Zimmerman s->fi = USB_FRMINTVL - 1; 1232*153ef166SPaul Zimmerman s->next_chan = 0; 1233*153ef166SPaul Zimmerman s->working = false; 1234*153ef166SPaul Zimmerman 1235*153ef166SPaul Zimmerman for (i = 0; i < DWC2_NB_CHAN; i++) { 1236*153ef166SPaul Zimmerman s->packet[i].needs_service = false; 1237*153ef166SPaul Zimmerman } 1238*153ef166SPaul Zimmerman } 1239*153ef166SPaul Zimmerman 1240*153ef166SPaul Zimmerman static void dwc2_reset_hold(Object *obj) 1241*153ef166SPaul Zimmerman { 1242*153ef166SPaul Zimmerman DWC2Class *c = DWC2_GET_CLASS(obj); 1243*153ef166SPaul Zimmerman DWC2State *s = DWC2_USB(obj); 1244*153ef166SPaul Zimmerman 1245*153ef166SPaul Zimmerman trace_usb_dwc2_reset_hold(); 1246*153ef166SPaul Zimmerman 1247*153ef166SPaul Zimmerman if (c->parent_phases.hold) { 1248*153ef166SPaul Zimmerman c->parent_phases.hold(obj); 1249*153ef166SPaul Zimmerman } 1250*153ef166SPaul Zimmerman 1251*153ef166SPaul Zimmerman dwc2_update_irq(s); 1252*153ef166SPaul Zimmerman } 1253*153ef166SPaul Zimmerman 1254*153ef166SPaul Zimmerman static void dwc2_reset_exit(Object *obj) 1255*153ef166SPaul Zimmerman { 1256*153ef166SPaul Zimmerman DWC2Class *c = DWC2_GET_CLASS(obj); 1257*153ef166SPaul Zimmerman DWC2State *s = DWC2_USB(obj); 1258*153ef166SPaul Zimmerman 1259*153ef166SPaul Zimmerman trace_usb_dwc2_reset_exit(); 1260*153ef166SPaul Zimmerman 1261*153ef166SPaul Zimmerman if (c->parent_phases.exit) { 1262*153ef166SPaul Zimmerman c->parent_phases.exit(obj); 1263*153ef166SPaul Zimmerman } 1264*153ef166SPaul Zimmerman 1265*153ef166SPaul Zimmerman s->hprt0 = HPRT0_PWR; 1266*153ef166SPaul Zimmerman if (s->uport.dev && s->uport.dev->attached) { 1267*153ef166SPaul Zimmerman usb_attach(&s->uport); 1268*153ef166SPaul Zimmerman usb_device_reset(s->uport.dev); 1269*153ef166SPaul Zimmerman } 1270*153ef166SPaul Zimmerman } 1271*153ef166SPaul Zimmerman 1272*153ef166SPaul Zimmerman static void dwc2_realize(DeviceState *dev, Error **errp) 1273*153ef166SPaul Zimmerman { 1274*153ef166SPaul Zimmerman SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 1275*153ef166SPaul Zimmerman DWC2State *s = DWC2_USB(dev); 1276*153ef166SPaul Zimmerman Object *obj; 1277*153ef166SPaul Zimmerman Error *err = NULL; 1278*153ef166SPaul Zimmerman 1279*153ef166SPaul Zimmerman obj = object_property_get_link(OBJECT(dev), "dma-mr", &err); 1280*153ef166SPaul Zimmerman if (err) { 1281*153ef166SPaul Zimmerman error_setg(errp, "dwc2: required dma-mr link not found: %s", 1282*153ef166SPaul Zimmerman error_get_pretty(err)); 1283*153ef166SPaul Zimmerman return; 1284*153ef166SPaul Zimmerman } 1285*153ef166SPaul Zimmerman assert(obj != NULL); 1286*153ef166SPaul Zimmerman 1287*153ef166SPaul Zimmerman s->dma_mr = MEMORY_REGION(obj); 1288*153ef166SPaul Zimmerman address_space_init(&s->dma_as, s->dma_mr, "dwc2"); 1289*153ef166SPaul Zimmerman 1290*153ef166SPaul Zimmerman usb_bus_new(&s->bus, sizeof(s->bus), &dwc2_bus_ops, dev); 1291*153ef166SPaul Zimmerman usb_register_port(&s->bus, &s->uport, s, 0, &dwc2_port_ops, 1292*153ef166SPaul Zimmerman USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL | 1293*153ef166SPaul Zimmerman (s->usb_version == 2 ? USB_SPEED_MASK_HIGH : 0)); 1294*153ef166SPaul Zimmerman s->uport.dev = 0; 1295*153ef166SPaul Zimmerman 1296*153ef166SPaul Zimmerman s->usb_frame_time = NANOSECONDS_PER_SECOND / 1000; /* 1000000 */ 1297*153ef166SPaul Zimmerman if (NANOSECONDS_PER_SECOND >= USB_HZ_FS) { 1298*153ef166SPaul Zimmerman s->usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ_FS; /* 83.3 */ 1299*153ef166SPaul Zimmerman } else { 1300*153ef166SPaul Zimmerman s->usb_bit_time = 1; 1301*153ef166SPaul Zimmerman } 1302*153ef166SPaul Zimmerman 1303*153ef166SPaul Zimmerman s->fi = USB_FRMINTVL - 1; 1304*153ef166SPaul Zimmerman s->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, dwc2_frame_boundary, s); 1305*153ef166SPaul Zimmerman s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, dwc2_work_timer, s); 1306*153ef166SPaul Zimmerman s->async_bh = qemu_bh_new(dwc2_work_bh, s); 1307*153ef166SPaul Zimmerman 1308*153ef166SPaul Zimmerman sysbus_init_irq(sbd, &s->irq); 1309*153ef166SPaul Zimmerman } 1310*153ef166SPaul Zimmerman 1311*153ef166SPaul Zimmerman static void dwc2_init(Object *obj) 1312*153ef166SPaul Zimmerman { 1313*153ef166SPaul Zimmerman SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 1314*153ef166SPaul Zimmerman DWC2State *s = DWC2_USB(obj); 1315*153ef166SPaul Zimmerman 1316*153ef166SPaul Zimmerman memory_region_init(&s->container, obj, "dwc2", DWC2_MMIO_SIZE); 1317*153ef166SPaul Zimmerman sysbus_init_mmio(sbd, &s->container); 1318*153ef166SPaul Zimmerman 1319*153ef166SPaul Zimmerman memory_region_init_io(&s->hsotg, obj, &dwc2_mmio_hsotg_ops, s, 1320*153ef166SPaul Zimmerman "dwc2-io", 4 * KiB); 1321*153ef166SPaul Zimmerman memory_region_add_subregion(&s->container, 0x0000, &s->hsotg); 1322*153ef166SPaul Zimmerman 1323*153ef166SPaul Zimmerman memory_region_init_io(&s->fifos, obj, &dwc2_mmio_hreg2_ops, s, 1324*153ef166SPaul Zimmerman "dwc2-fifo", 64 * KiB); 1325*153ef166SPaul Zimmerman memory_region_add_subregion(&s->container, 0x1000, &s->fifos); 1326*153ef166SPaul Zimmerman } 1327*153ef166SPaul Zimmerman 1328*153ef166SPaul Zimmerman static const VMStateDescription vmstate_dwc2_state_packet = { 1329*153ef166SPaul Zimmerman .name = "dwc2/packet", 1330*153ef166SPaul Zimmerman .version_id = 1, 1331*153ef166SPaul Zimmerman .minimum_version_id = 1, 1332*153ef166SPaul Zimmerman .fields = (VMStateField[]) { 1333*153ef166SPaul Zimmerman VMSTATE_UINT32(devadr, DWC2Packet), 1334*153ef166SPaul Zimmerman VMSTATE_UINT32(epnum, DWC2Packet), 1335*153ef166SPaul Zimmerman VMSTATE_UINT32(epdir, DWC2Packet), 1336*153ef166SPaul Zimmerman VMSTATE_UINT32(mps, DWC2Packet), 1337*153ef166SPaul Zimmerman VMSTATE_UINT32(pid, DWC2Packet), 1338*153ef166SPaul Zimmerman VMSTATE_UINT32(index, DWC2Packet), 1339*153ef166SPaul Zimmerman VMSTATE_UINT32(pcnt, DWC2Packet), 1340*153ef166SPaul Zimmerman VMSTATE_UINT32(len, DWC2Packet), 1341*153ef166SPaul Zimmerman VMSTATE_INT32(async, DWC2Packet), 1342*153ef166SPaul Zimmerman VMSTATE_BOOL(small, DWC2Packet), 1343*153ef166SPaul Zimmerman VMSTATE_BOOL(needs_service, DWC2Packet), 1344*153ef166SPaul Zimmerman VMSTATE_END_OF_LIST() 1345*153ef166SPaul Zimmerman }, 1346*153ef166SPaul Zimmerman }; 1347*153ef166SPaul Zimmerman 1348*153ef166SPaul Zimmerman const VMStateDescription vmstate_dwc2_state = { 1349*153ef166SPaul Zimmerman .name = "dwc2", 1350*153ef166SPaul Zimmerman .version_id = 1, 1351*153ef166SPaul Zimmerman .minimum_version_id = 1, 1352*153ef166SPaul Zimmerman .fields = (VMStateField[]) { 1353*153ef166SPaul Zimmerman VMSTATE_UINT32_ARRAY(glbreg, DWC2State, 1354*153ef166SPaul Zimmerman DWC2_GLBREG_SIZE / sizeof(uint32_t)), 1355*153ef166SPaul Zimmerman VMSTATE_UINT32_ARRAY(fszreg, DWC2State, 1356*153ef166SPaul Zimmerman DWC2_FSZREG_SIZE / sizeof(uint32_t)), 1357*153ef166SPaul Zimmerman VMSTATE_UINT32_ARRAY(hreg0, DWC2State, 1358*153ef166SPaul Zimmerman DWC2_HREG0_SIZE / sizeof(uint32_t)), 1359*153ef166SPaul Zimmerman VMSTATE_UINT32_ARRAY(hreg1, DWC2State, 1360*153ef166SPaul Zimmerman DWC2_HREG1_SIZE / sizeof(uint32_t)), 1361*153ef166SPaul Zimmerman VMSTATE_UINT32_ARRAY(pcgreg, DWC2State, 1362*153ef166SPaul Zimmerman DWC2_PCGREG_SIZE / sizeof(uint32_t)), 1363*153ef166SPaul Zimmerman 1364*153ef166SPaul Zimmerman VMSTATE_TIMER_PTR(eof_timer, DWC2State), 1365*153ef166SPaul Zimmerman VMSTATE_TIMER_PTR(frame_timer, DWC2State), 1366*153ef166SPaul Zimmerman VMSTATE_INT64(sof_time, DWC2State), 1367*153ef166SPaul Zimmerman VMSTATE_INT64(usb_frame_time, DWC2State), 1368*153ef166SPaul Zimmerman VMSTATE_INT64(usb_bit_time, DWC2State), 1369*153ef166SPaul Zimmerman VMSTATE_UINT32(usb_version, DWC2State), 1370*153ef166SPaul Zimmerman VMSTATE_UINT16(frame_number, DWC2State), 1371*153ef166SPaul Zimmerman VMSTATE_UINT16(fi, DWC2State), 1372*153ef166SPaul Zimmerman VMSTATE_UINT16(next_chan, DWC2State), 1373*153ef166SPaul Zimmerman VMSTATE_BOOL(working, DWC2State), 1374*153ef166SPaul Zimmerman 1375*153ef166SPaul Zimmerman VMSTATE_STRUCT_ARRAY(packet, DWC2State, DWC2_NB_CHAN, 1, 1376*153ef166SPaul Zimmerman vmstate_dwc2_state_packet, DWC2Packet), 1377*153ef166SPaul Zimmerman VMSTATE_UINT8_2DARRAY(usb_buf, DWC2State, DWC2_NB_CHAN, 1378*153ef166SPaul Zimmerman DWC2_MAX_XFER_SIZE), 1379*153ef166SPaul Zimmerman 1380*153ef166SPaul Zimmerman VMSTATE_END_OF_LIST() 1381*153ef166SPaul Zimmerman } 1382*153ef166SPaul Zimmerman }; 1383*153ef166SPaul Zimmerman 1384*153ef166SPaul Zimmerman static Property dwc2_usb_properties[] = { 1385*153ef166SPaul Zimmerman DEFINE_PROP_UINT32("usb_version", DWC2State, usb_version, 2), 1386*153ef166SPaul Zimmerman DEFINE_PROP_END_OF_LIST(), 1387*153ef166SPaul Zimmerman }; 1388*153ef166SPaul Zimmerman 1389*153ef166SPaul Zimmerman static void dwc2_class_init(ObjectClass *klass, void *data) 1390*153ef166SPaul Zimmerman { 1391*153ef166SPaul Zimmerman DeviceClass *dc = DEVICE_CLASS(klass); 1392*153ef166SPaul Zimmerman DWC2Class *c = DWC2_CLASS(klass); 1393*153ef166SPaul Zimmerman ResettableClass *rc = RESETTABLE_CLASS(klass); 1394*153ef166SPaul Zimmerman 1395*153ef166SPaul Zimmerman dc->realize = dwc2_realize; 1396*153ef166SPaul Zimmerman dc->vmsd = &vmstate_dwc2_state; 1397*153ef166SPaul Zimmerman set_bit(DEVICE_CATEGORY_USB, dc->categories); 1398*153ef166SPaul Zimmerman device_class_set_props(dc, dwc2_usb_properties); 1399*153ef166SPaul Zimmerman resettable_class_set_parent_phases(rc, dwc2_reset_enter, dwc2_reset_hold, 1400*153ef166SPaul Zimmerman dwc2_reset_exit, &c->parent_phases); 1401*153ef166SPaul Zimmerman } 1402*153ef166SPaul Zimmerman 1403*153ef166SPaul Zimmerman static const TypeInfo dwc2_usb_type_info = { 1404*153ef166SPaul Zimmerman .name = TYPE_DWC2_USB, 1405*153ef166SPaul Zimmerman .parent = TYPE_SYS_BUS_DEVICE, 1406*153ef166SPaul Zimmerman .instance_size = sizeof(DWC2State), 1407*153ef166SPaul Zimmerman .instance_init = dwc2_init, 1408*153ef166SPaul Zimmerman .class_size = sizeof(DWC2Class), 1409*153ef166SPaul Zimmerman .class_init = dwc2_class_init, 1410*153ef166SPaul Zimmerman }; 1411*153ef166SPaul Zimmerman 1412*153ef166SPaul Zimmerman static void dwc2_usb_register_types(void) 1413*153ef166SPaul Zimmerman { 1414*153ef166SPaul Zimmerman type_register_static(&dwc2_usb_type_info); 1415*153ef166SPaul Zimmerman } 1416*153ef166SPaul Zimmerman 1417*153ef166SPaul Zimmerman type_init(dwc2_usb_register_types) 1418