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