1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <assert.h> 6#include <ddk/debug.h> 7#include <zircon/assert.h> 8 9#include <ddk/usb-request/usb-request.h> 10 11#include "dwc3.h" 12#include "dwc3-regs.h" 13#include "dwc3-types.h" 14 15#include <stdio.h> 16#include <string.h> 17 18#define EP_FIFO_SIZE PAGE_SIZE 19 20static zx_paddr_t dwc3_ep_trb_phys(dwc3_endpoint_t* ep, dwc3_trb_t* trb) { 21 return io_buffer_phys(&ep->fifo.buffer) + ((void *)trb - (void *)ep->fifo.first); 22} 23 24static void dwc3_enable_ep(dwc3_t* dwc, unsigned ep_num, bool enable) { 25 volatile void* reg = dwc3_mmio(dwc) + DALEPENA; 26 27 mtx_lock(&dwc->lock); 28 29 uint32_t temp = DWC3_READ32(reg); 30 uint32_t bit = 1 << ep_num; 31 32 if (enable) { 33 temp |= bit; 34 } else { 35 temp &= ~bit; 36 } 37 DWC3_WRITE32(reg, temp); 38 39 mtx_unlock(&dwc->lock); 40} 41 42zx_status_t dwc3_ep_fifo_init(dwc3_t* dwc, unsigned ep_num) { 43 ZX_DEBUG_ASSERT(ep_num < countof(dwc->eps)); 44 dwc3_endpoint_t* ep = &dwc->eps[ep_num]; 45 dwc3_fifo_t* fifo = &ep->fifo; 46 47 static_assert(EP_FIFO_SIZE <= PAGE_SIZE, ""); 48 zx_status_t status = io_buffer_init(&fifo->buffer, dwc->bti_handle, EP_FIFO_SIZE, 49 IO_BUFFER_RW | IO_BUFFER_CONTIG); 50 if (status != ZX_OK) { 51 return status; 52 } 53 54 fifo->first = io_buffer_virt(&fifo->buffer); 55 fifo->next = fifo->first; 56 fifo->current = NULL; 57 fifo->last = (void *)fifo->first + EP_FIFO_SIZE - sizeof(dwc3_trb_t); 58 59 // set up link TRB pointing back to the start of the fifo 60 dwc3_trb_t* trb = fifo->last; 61 zx_paddr_t trb_phys = io_buffer_phys(&fifo->buffer); 62 trb->ptr_low = (uint32_t)trb_phys; 63 trb->ptr_high = (uint32_t)(trb_phys >> 32); 64 trb->status = 0; 65 trb->control = TRB_TRBCTL_LINK | TRB_HWO; 66 io_buffer_cache_flush(&ep->fifo.buffer, (trb - ep->fifo.first) * sizeof(*trb), sizeof(*trb)); 67 68 return ZX_OK; 69} 70 71void dwc3_ep_fifo_release(dwc3_t* dwc, unsigned ep_num) { 72 ZX_DEBUG_ASSERT(ep_num < countof(dwc->eps)); 73 dwc3_endpoint_t* ep = &dwc->eps[ep_num]; 74 75 io_buffer_release(&ep->fifo.buffer); 76} 77 78void dwc3_ep_start_transfer(dwc3_t* dwc, unsigned ep_num, unsigned type, zx_paddr_t buffer, 79 size_t length, bool send_zlp) { 80 zxlogf(LTRACE, "dwc3_ep_start_transfer ep %u type %u length %zu\n", ep_num, type, length); 81 82 // special case: EP0_OUT and EP0_IN use the same fifo 83 dwc3_endpoint_t* ep = (ep_num == EP0_IN ? &dwc->eps[EP0_OUT] : &dwc->eps[ep_num]); 84 85 dwc3_trb_t* trb = ep->fifo.next++; 86 if (ep->fifo.next == ep->fifo.last) { 87 ep->fifo.next = ep->fifo.first; 88 } 89 if (ep->fifo.current == NULL) { 90 ep->fifo.current = trb; 91 } 92 93 trb->ptr_low = (uint32_t)buffer; 94 trb->ptr_high = (uint32_t)(buffer >> 32); 95 trb->status = TRB_BUFSIZ(length); 96 if (send_zlp) { 97 trb->control = type | TRB_HWO; 98 } else { 99 trb->control = type | TRB_LST | TRB_IOC | TRB_HWO; 100 } 101 io_buffer_cache_flush(&ep->fifo.buffer, (trb - ep->fifo.first) * sizeof(*trb), sizeof(*trb)); 102 103 if (send_zlp) { 104 dwc3_trb_t* zlp_trb = ep->fifo.next++; 105 if (ep->fifo.next == ep->fifo.last) { 106 ep->fifo.next = ep->fifo.first; 107 } 108 zlp_trb->ptr_low = 0; 109 zlp_trb->ptr_high = 0; 110 zlp_trb->status = TRB_BUFSIZ(0); 111 zlp_trb->control = type | TRB_LST | TRB_IOC | TRB_HWO; 112 io_buffer_cache_flush(&ep->fifo.buffer, (zlp_trb - ep->fifo.first) * sizeof(*trb), sizeof(*trb)); 113 } 114 115 dwc3_cmd_ep_start_transfer(dwc, ep_num, dwc3_ep_trb_phys(ep, trb)); 116} 117 118static void dwc3_ep_queue_next_locked(dwc3_t* dwc, dwc3_endpoint_t* ep) { 119 usb_request_t* req; 120 121 if (ep->current_req == NULL && ep->got_not_ready && 122 (req = list_remove_head_type(&ep->queued_reqs, usb_request_t, node)) != NULL) { 123 ep->current_req = req; 124 ep->got_not_ready = false; 125 if (EP_IN(ep->ep_num)) { 126 usb_request_cache_flush(req, 0, req->header.length); 127 } else { 128 usb_request_cache_flush_invalidate(req, 0, req->header.length); 129 } 130 131 // TODO(voydanoff) scatter/gather support 132 phys_iter_t iter; 133 zx_paddr_t phys; 134 usb_request_physmap(req, dwc->bti_handle); 135 usb_request_phys_iter_init(&iter, req, PAGE_SIZE); 136 usb_request_phys_iter_next(&iter, &phys); 137 bool send_zlp = req->header.send_zlp && (req->header.length % ep->max_packet_size) == 0; 138 dwc3_ep_start_transfer(dwc, ep->ep_num, TRB_TRBCTL_NORMAL, phys, req->header.length, 139 send_zlp); 140 } 141} 142 143zx_status_t dwc3_ep_config(dwc3_t* dwc, usb_endpoint_descriptor_t* ep_desc, 144 usb_ss_ep_comp_descriptor_t* ss_comp_desc) { 145 // convert address to index in range 0 - 31 146 // low bit is IN/OUT 147 unsigned ep_num = dwc3_ep_num(ep_desc->bEndpointAddress); 148 if (ep_num < 2) { 149 // index 0 and 1 are for endpoint zero 150 return ZX_ERR_INVALID_ARGS; 151 } 152 153 unsigned ep_type = usb_ep_type(ep_desc); 154 if (ep_type == USB_ENDPOINT_ISOCHRONOUS) { 155 zxlogf(ERROR, "dwc3_ep_config: isochronous endpoints are not supported\n"); 156 return ZX_ERR_NOT_SUPPORTED; 157 } 158 159 dwc3_endpoint_t* ep = &dwc->eps[ep_num]; 160 161 mtx_lock(&ep->lock); 162 zx_status_t status = dwc3_ep_fifo_init(dwc, ep_num); 163 if (status != ZX_OK) { 164 zxlogf(ERROR, "dwc3_config_ep: dwc3_ep_fifo_init failed %d\n", status); 165 mtx_unlock(&ep->lock); 166 return status; 167 } 168 ep->max_packet_size = usb_ep_max_packet(ep_desc); 169 ep->type = ep_type; 170 ep->interval = ep_desc->bInterval; 171 // TODO(voydanoff) USB3 support 172 173 ep->enabled = true; 174 175 if (dwc->configured) { 176 dwc3_ep_queue_next_locked(dwc, ep); 177 } 178 179 mtx_unlock(&ep->lock); 180 181 return ZX_OK; 182} 183 184zx_status_t dwc3_ep_disable(dwc3_t* dwc, uint8_t ep_addr) { 185 // convert address to index in range 0 - 31 186 // low bit is IN/OUT 187 unsigned ep_num = dwc3_ep_num(ep_addr); 188 if (ep_num < 2) { 189 // index 0 and 1 are for endpoint zero 190 return ZX_ERR_INVALID_ARGS; 191 } 192 193 dwc3_endpoint_t* ep = &dwc->eps[ep_num]; 194 mtx_lock(&ep->lock); 195 dwc3_ep_fifo_release(dwc, ep_num); 196 ep->enabled = false; 197 mtx_unlock(&ep->lock); 198 199 return ZX_OK; 200} 201 202void dwc3_ep_queue(dwc3_t* dwc, unsigned ep_num, usb_request_t* req) { 203 dwc3_endpoint_t* ep = &dwc->eps[ep_num]; 204 205 // OUT transactions must have length > 0 and multiple of max packet size 206 if (EP_OUT(ep_num)) { 207 if (req->header.length == 0 || req->header.length % ep->max_packet_size != 0) { 208 zxlogf(ERROR, "dwc3_ep_queue: OUT transfers must be multiple of max packet size\n"); 209 usb_request_complete(req, ZX_ERR_INVALID_ARGS, 0); 210 return; 211 } 212 } 213 214 mtx_lock(&ep->lock); 215 216 if (!ep->enabled) { 217 mtx_unlock(&ep->lock); 218 usb_request_complete(req, ZX_ERR_BAD_STATE, 0); 219 return; 220 } 221 222 list_add_tail(&ep->queued_reqs, &req->node); 223 224 if (dwc->configured) { 225 dwc3_ep_queue_next_locked(dwc, ep); 226 } 227 228 mtx_unlock(&ep->lock); 229} 230 231void dwc3_ep_set_config(dwc3_t* dwc, unsigned ep_num, bool enable) { 232 zxlogf(TRACE, "dwc3_ep_set_config %u\n", ep_num); 233 234 dwc3_endpoint_t* ep = &dwc->eps[ep_num]; 235 236 if (enable) { 237 dwc3_cmd_ep_set_config(dwc, ep_num, ep->type, ep->max_packet_size, ep->interval, false); 238 dwc3_cmd_ep_transfer_config(dwc, ep_num); 239 dwc3_enable_ep(dwc, ep_num, true); 240 } else { 241 dwc3_enable_ep(dwc, ep_num, false); 242 } 243} 244 245void dwc3_start_eps(dwc3_t* dwc) { 246 zxlogf(TRACE, "dwc3_start_eps\n"); 247 248 dwc3_cmd_ep_set_config(dwc, EP0_IN, USB_ENDPOINT_CONTROL, dwc->eps[EP0_IN].max_packet_size, 0, 249 true); 250 dwc3_cmd_start_new_config(dwc, EP0_OUT, 2); 251 252 for (unsigned ep_num = 2; ep_num < countof(dwc->eps); ep_num++) { 253 dwc3_endpoint_t* ep = &dwc->eps[ep_num]; 254 if (ep->enabled) { 255 dwc3_ep_set_config(dwc, ep_num, true); 256 257 mtx_lock(&ep->lock); 258 dwc3_ep_queue_next_locked(dwc, ep); 259 mtx_unlock(&ep->lock); 260 } 261 } 262} 263 264static void dwc_ep_read_trb(dwc3_endpoint_t* ep, dwc3_trb_t* trb, dwc3_trb_t* out_trb) { 265 if (trb >= ep->fifo.first && trb < ep->fifo.last) { 266 io_buffer_cache_flush_invalidate(&ep->fifo.buffer, (trb - ep->fifo.first) * sizeof(*trb), 267 sizeof(*trb)); 268 memcpy((void *)out_trb, (void *)trb, sizeof(*trb)); 269 } else { 270 zxlogf(ERROR, "dwc_ep_read_trb: bad trb\n"); 271 } 272} 273 274void dwc3_ep_xfer_started(dwc3_t* dwc, unsigned ep_num, unsigned rsrc_id) { 275 dwc3_endpoint_t* ep = &dwc->eps[ep_num]; 276 mtx_lock(&ep->lock); 277 ep->rsrc_id = rsrc_id; 278 mtx_unlock(&ep->lock); 279} 280 281void dwc3_ep_xfer_not_ready(dwc3_t* dwc, unsigned ep_num, unsigned stage) { 282 zxlogf(LTRACE, "dwc3_ep_xfer_not_ready ep %u state %d\n", ep_num, dwc->ep0_state); 283 284 if (ep_num == EP0_OUT || ep_num == EP0_IN) { 285 dwc3_ep0_xfer_not_ready(dwc, ep_num, stage); 286 } else { 287 dwc3_endpoint_t* ep = &dwc->eps[ep_num]; 288 289 mtx_lock(&ep->lock); 290 ep->got_not_ready = true; 291 dwc3_ep_queue_next_locked(dwc, ep); 292 mtx_unlock(&ep->lock); 293 } 294} 295 296void dwc3_ep_xfer_complete(dwc3_t* dwc, unsigned ep_num) { 297 zxlogf(LTRACE, "dwc3_ep_xfer_complete ep %u state %d\n", ep_num, dwc->ep0_state); 298 299 if (ep_num >= countof(dwc->eps)) { 300 zxlogf(ERROR, "dwc3_ep_xfer_complete: bad ep_num %u\n", ep_num); 301 return; 302 } 303 304 if (ep_num == EP0_OUT || ep_num == EP0_IN) { 305 dwc3_ep0_xfer_complete(dwc, ep_num); 306 } else { 307 dwc3_endpoint_t* ep = &dwc->eps[ep_num]; 308 309 mtx_lock(&ep->lock); 310 usb_request_t* req = ep->current_req; 311 ep->current_req = NULL; 312 313 if (req) { 314 dwc3_trb_t trb; 315 dwc_ep_read_trb(ep, ep->fifo.current, &trb); 316 ep->fifo.current = NULL; 317 if (trb.control & TRB_HWO) { 318 zxlogf(ERROR, "TRB_HWO still set in dwc3_ep_xfer_complete\n"); 319 } 320 321 zx_off_t actual = req->header.length - TRB_BUFSIZ(trb.status); 322// dwc3_ep_queue_next_locked(dwc, ep); 323 324 mtx_unlock(&ep->lock); 325 326 usb_request_complete(req, ZX_OK, actual); 327 } else { 328 mtx_unlock(&ep->lock); 329 zxlogf(ERROR, "dwc3_ep_xfer_complete: no usb request found to complete!\n"); 330 } 331 } 332} 333 334zx_status_t dwc3_ep_set_stall(dwc3_t* dwc, unsigned ep_num, bool stall) { 335 if (ep_num >= countof(dwc->eps)) { 336 return ZX_ERR_INVALID_ARGS; 337 } 338 339 dwc3_endpoint_t* ep = &dwc->eps[ep_num]; 340 mtx_lock(&ep->lock); 341 342 if (!ep->enabled) { 343 mtx_unlock(&ep->lock); 344 return ZX_ERR_BAD_STATE; 345 } 346 if (stall && !ep->stalled) { 347 dwc3_cmd_ep_set_stall(dwc, ep_num); 348 } else if (!stall && ep->stalled) { 349 dwc3_cmd_ep_clear_stall(dwc, ep_num); 350 } 351 ep->stalled = stall; 352 mtx_unlock(&ep->lock); 353 354 return ZX_OK; 355} 356 357void dwc3_ep_end_transfers(dwc3_t* dwc, unsigned ep_num, zx_status_t reason) { 358 dwc3_endpoint_t* ep = &dwc->eps[ep_num]; 359 mtx_lock(&ep->lock); 360 361 if (ep->current_req) { 362 dwc3_cmd_ep_end_transfer(dwc, ep_num); 363 usb_request_complete(ep->current_req, reason, 0); 364 ep->current_req = NULL; 365 } 366 367 usb_request_t* req; 368 while ((req = list_remove_head_type(&ep->queued_reqs, usb_request_t, node)) != NULL) { 369 usb_request_complete(req, reason, 0); 370 } 371 372 mtx_unlock(&ep->lock); 373} 374