00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #ifndef DWC_DEVICE_ONLY
00034
00042 #include "dwc_otg_hcd.h"
00043 #include "dwc_otg_regs.h"
00044
00053 void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00054 {
00055 dwc_otg_qtd_t *qtd, *qtd_tmp;
00056
00057
00058 DWC_SPINLOCK(hcd->lock);
00059 DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
00060 DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
00061 dwc_otg_hcd_qtd_free(qtd);
00062 }
00063
00064 if (hcd->core_if->dma_desc_enable) {
00065 dwc_otg_hcd_qh_free_ddma(hcd, qh);
00066 } else if (qh->dw_align_buf) {
00067 uint32_t buf_size;
00068 if (qh->ep_type == UE_ISOCHRONOUS) {
00069 buf_size = 4096;
00070 } else {
00071 buf_size = hcd->core_if->core_params->max_transfer_size;
00072 }
00073 DWC_DMA_FREE(buf_size, qh->dw_align_buf, qh->dw_align_buf_dma);
00074 }
00075
00076 DWC_FREE(qh);
00077 DWC_SPINUNLOCK(hcd->lock);
00078 return;
00079 }
00080
00081 #define BitStuffTime(bytecount) ((8 * 7* bytecount) / 6)
00082 #define HS_HOST_DELAY 5
00083 #define FS_LS_HOST_DELAY 1000
00084 #define HUB_LS_SETUP 333
00085 #define NS_TO_US(ns) ((ns + 500) / 1000)
00086
00087
00088 static uint32_t calc_bus_time(int speed, int is_in, int is_isoc, int bytecount)
00089 {
00090 unsigned long retval;
00091
00092 switch (speed) {
00093 case USB_SPEED_HIGH:
00094 if (is_isoc) {
00095 retval =
00096 ((38 * 8 * 2083) +
00097 (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
00098 HS_HOST_DELAY;
00099 } else {
00100 retval =
00101 ((55 * 8 * 2083) +
00102 (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
00103 HS_HOST_DELAY;
00104 }
00105 break;
00106 case USB_SPEED_FULL:
00107 if (is_isoc) {
00108 retval =
00109 (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
00110 if (is_in) {
00111 retval = 7268 + FS_LS_HOST_DELAY + retval;
00112 } else {
00113 retval = 6265 + FS_LS_HOST_DELAY + retval;
00114 }
00115 } else {
00116 retval =
00117 (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
00118 retval = 9107 + FS_LS_HOST_DELAY + retval;
00119 }
00120 break;
00121 case USB_SPEED_LOW:
00122 if (is_in) {
00123 retval =
00124 (67667 * (31 + 10 * BitStuffTime(bytecount))) /
00125 1000;
00126 retval =
00127 64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
00128 retval;
00129 } else {
00130 retval =
00131 (66700 * (31 + 10 * BitStuffTime(bytecount))) /
00132 1000;
00133 retval =
00134 64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
00135 retval;
00136 }
00137 break;
00138 default:
00139 DWC_WARN("Unknown device speed\n");
00140 retval = -1;
00141 }
00142
00143 return NS_TO_US(retval);
00144 }
00145
00154 #define SCHEDULE_SLOP 10
00155 void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
00156 {
00157 char *speed, *type;
00158 int dev_speed;
00159 uint32_t hub_addr, hub_port;
00160
00161 dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
00162
00163
00164 qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
00165 qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
00166
00167 qh->data_toggle = DWC_OTG_HC_PID_DATA0;
00168 qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info);
00169 DWC_CIRCLEQ_INIT(&qh->qtd_list);
00170 DWC_LIST_INIT(&qh->qh_list_entry);
00171 qh->channel = NULL;
00172
00173
00174
00175 dev_speed = hcd->fops->speed(hcd, urb->priv);
00176
00177 hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port);
00178 qh->do_split = 0;
00179
00180 if (((dev_speed == USB_SPEED_LOW) ||
00181 (dev_speed == USB_SPEED_FULL)) &&
00182 (hub_addr != 0 && hub_addr != 1)) {
00183 DWC_DEBUGPL(DBG_HCD,
00184 "QH init: EP %d: TT found at hub addr %d, for port %d\n",
00185 dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
00186 hub_port);
00187 qh->do_split = 1;
00188 }
00189
00190 if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
00191
00192 hprt0_data_t hprt;
00193
00195 int bytecount =
00196 dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);
00197
00198 qh->usecs =
00199 calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed),
00200 qh->ep_is_in, (qh->ep_type == UE_ISOCHRONOUS),
00201 bytecount);
00202
00203 qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
00204 SCHEDULE_SLOP);
00205 qh->interval = urb->interval;
00206
00207 #if 0
00208
00209 if (qh->ep_type == UE_INTERRUPT) {
00210 qh->interval = 8;
00211 }
00212 #endif
00213 hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
00214 if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
00215 ((dev_speed == USB_SPEED_LOW) ||
00216 (dev_speed == USB_SPEED_FULL))) {
00217 qh->interval *= 8;
00218 qh->sched_frame |= 0x7;
00219 qh->start_split_frame = qh->sched_frame;
00220 }
00221
00222 }
00223
00224 DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
00225 DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - qh = %p\n", qh);
00226 DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Device Address = %d\n",
00227 dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
00228 DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Endpoint %d, %s\n",
00229 dwc_otg_hcd_get_ep_num(&urb->pipe_info),
00230 dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
00231 switch (dev_speed) {
00232 case USB_SPEED_LOW:
00233 qh->dev_speed = DWC_OTG_EP_SPEED_LOW;
00234 speed = "low";
00235 break;
00236 case USB_SPEED_FULL:
00237 qh->dev_speed = DWC_OTG_EP_SPEED_FULL;
00238 speed = "full";
00239 break;
00240 case USB_SPEED_HIGH:
00241 qh->dev_speed = DWC_OTG_EP_SPEED_HIGH;
00242 speed = "high";
00243 break;
00244 default:
00245 speed = "?";
00246 break;
00247 }
00248 DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Speed = %s\n", speed);
00249
00250 switch (qh->ep_type) {
00251 case UE_ISOCHRONOUS:
00252 type = "isochronous";
00253 break;
00254 case UE_INTERRUPT:
00255 type = "interrupt";
00256 break;
00257 case UE_CONTROL:
00258 type = "control";
00259 break;
00260 case UE_BULK:
00261 type = "bulk";
00262 break;
00263 default:
00264 type = "?";
00265 break;
00266 }
00267
00268 DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Type = %s\n", type);
00269
00270 #ifdef DEBUG
00271 if (qh->ep_type == UE_INTERRUPT) {
00272 DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
00273 qh->usecs);
00274 DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
00275 qh->interval);
00276 }
00277 #endif
00278
00279 }
00280
00290 dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
00291 dwc_otg_hcd_urb_t * urb, int atomic_alloc)
00292 {
00293 dwc_otg_qh_t *qh;
00294
00295
00297 qh = dwc_otg_hcd_qh_alloc(atomic_alloc);
00298 if (qh == NULL) {
00299 DWC_ERROR("qh allocation failed");
00300 return NULL;
00301 }
00302
00303 qh_init(hcd, qh, urb);
00304
00305 if (hcd->core_if->dma_desc_enable
00306 && (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) {
00307 dwc_otg_hcd_qh_free(hcd, qh);
00308 return NULL;
00309 }
00310
00311 return qh;
00312 }
00313
00319 static int periodic_channel_available(dwc_otg_hcd_t * hcd)
00320 {
00321
00322
00323
00324
00325
00326 int status;
00327 int num_channels;
00328
00329 num_channels = hcd->core_if->core_params->host_channels;
00330 if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels)
00331 && (hcd->periodic_channels < num_channels - 1)) {
00332 status = 0;
00333 } else {
00334 DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
00335 __func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels);
00336 status = -DWC_E_NO_SPACE;
00337 }
00338
00339 return status;
00340 }
00341
00352 static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00353 {
00354 int status;
00355 int16_t max_claimed_usecs;
00356
00357 status = 0;
00358
00359 if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) {
00360
00361
00362
00363
00364
00365 max_claimed_usecs = 100 - qh->usecs;
00366 } else {
00367
00368
00369
00370
00371 max_claimed_usecs = 900 - qh->usecs;
00372 }
00373
00374 if (hcd->periodic_usecs > max_claimed_usecs) {
00375 DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs);
00376 status = -DWC_E_NO_SPACE;
00377 }
00378
00379 return status;
00380 }
00381
00392 static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00393 {
00394 int status;
00395 uint32_t max_xfer_size;
00396 uint32_t max_channel_xfer_size;
00397
00398 status = 0;
00399
00400 max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
00401 max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;
00402
00403 if (max_xfer_size > max_channel_xfer_size) {
00404 DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n",
00405 __func__, max_xfer_size, max_channel_xfer_size);
00406 status = -DWC_E_NO_SPACE;
00407 }
00408
00409 return status;
00410 }
00411
00421 static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00422 {
00423 int status = 0;
00424
00425 status = periodic_channel_available(hcd);
00426 if (status) {
00427 DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__);
00428 return status;
00429 }
00430
00431 status = check_periodic_bandwidth(hcd, qh);
00432 if (status) {
00433 DWC_INFO("%s: Insufficient periodic bandwidth for " "periodic transfer.\n", __func__);
00434 return status;
00435 }
00436
00437 status = check_max_xfer_size(hcd, qh);
00438 if (status) {
00439 DWC_INFO("%s: Channel max transfer size too small " "for periodic transfer.\n", __func__);
00440 return status;
00441 }
00442
00443 if (hcd->core_if->dma_desc_enable) {
00444
00445 DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
00446 }
00447 else {
00448
00449 DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
00450 }
00451
00452
00453 hcd->periodic_channels++;
00454
00455
00456 hcd->periodic_usecs += qh->usecs;
00457
00458 return status;
00459 }
00460
00468 int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00469 {
00470 int status = 0;
00471 gintmsk_data_t intr_mask = {.d32 = 0 };
00472
00473 if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
00474
00475 return status;
00476 }
00477
00478
00479 if (dwc_qh_is_non_per(qh)) {
00480
00481 DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive,
00482 &qh->qh_list_entry);
00483 } else {
00484 status = schedule_periodic(hcd, qh);
00485 if ( !hcd->periodic_qh_count ) {
00486 intr_mask.b.sofintr = 1;
00487 DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
00488 intr_mask.d32, intr_mask.d32);
00489 }
00490 hcd->periodic_qh_count++;
00491 }
00492
00493 return status;
00494 }
00495
00502 static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00503 {
00504 DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
00505
00506
00507 hcd->periodic_channels--;
00508
00509
00510 hcd->periodic_usecs -= qh->usecs;
00511 }
00512
00519 void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00520 {
00521 gintmsk_data_t intr_mask = {.d32 = 0 };
00522
00523 if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
00524
00525 return;
00526 }
00527
00528 if (dwc_qh_is_non_per(qh)) {
00529 if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) {
00530 hcd->non_periodic_qh_ptr =
00531 hcd->non_periodic_qh_ptr->next;
00532 }
00533 DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
00534 } else {
00535 deschedule_periodic(hcd, qh);
00536 hcd->periodic_qh_count--;
00537 if( !hcd->periodic_qh_count ) {
00538 intr_mask.b.sofintr = 1;
00539 DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
00540 intr_mask.d32, 0);
00541 }
00542 }
00543 }
00544
00558 void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
00559 int sched_next_periodic_split)
00560 {
00561 if (dwc_qh_is_non_per(qh)) {
00562 dwc_otg_hcd_qh_remove(hcd, qh);
00563 if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
00564
00565 dwc_otg_hcd_qh_add(hcd, qh);
00566 }
00567 } else {
00568 uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd);
00569
00570 if (qh->do_split) {
00571
00572 if (sched_next_periodic_split) {
00573
00574 qh->sched_frame = frame_number;
00575 if (dwc_frame_num_le(frame_number,
00576 dwc_frame_num_inc
00577 (qh->start_split_frame,
00578 1))) {
00579
00580
00581
00582
00583
00584
00585
00586 if ((qh->ep_type != UE_ISOCHRONOUS) ||
00587 (qh->ep_is_in != 0)) {
00588 qh->sched_frame =
00589 dwc_frame_num_inc(qh->sched_frame, 1);
00590 }
00591 }
00592 } else {
00593 qh->sched_frame =
00594 dwc_frame_num_inc(qh->start_split_frame,
00595 qh->interval);
00596 if (dwc_frame_num_le
00597 (qh->sched_frame, frame_number)) {
00598 qh->sched_frame = frame_number;
00599 }
00600 qh->sched_frame |= 0x7;
00601 qh->start_split_frame = qh->sched_frame;
00602 }
00603 } else {
00604 qh->sched_frame =
00605 dwc_frame_num_inc(qh->sched_frame, qh->interval);
00606 if (dwc_frame_num_le(qh->sched_frame, frame_number)) {
00607 qh->sched_frame = frame_number;
00608 }
00609 }
00610
00611 if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
00612 dwc_otg_hcd_qh_remove(hcd, qh);
00613 } else {
00614
00615
00616
00617
00618 if (qh->sched_frame == frame_number) {
00619 DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
00620 &qh->qh_list_entry);
00621 } else {
00622 DWC_LIST_MOVE_HEAD
00623 (&hcd->periodic_sched_inactive,
00624 &qh->qh_list_entry);
00625 }
00626 }
00627 }
00628 }
00629
00638 dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb, int atomic_alloc)
00639 {
00640 dwc_otg_qtd_t *qtd;
00641
00642 qtd = dwc_otg_hcd_qtd_alloc(atomic_alloc);
00643 if (qtd == NULL) {
00644 return NULL;
00645 }
00646
00647 dwc_otg_hcd_qtd_init(qtd, urb);
00648 return qtd;
00649 }
00650
00656 void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
00657 {
00658 dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t));
00659 qtd->urb = urb;
00660 if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) {
00661
00662
00663
00664
00665
00666 qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
00667 qtd->control_phase = DWC_OTG_CONTROL_SETUP;
00668 }
00669
00670
00671 qtd->complete_split = 0;
00672 qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
00673 qtd->isoc_split_offset = 0;
00674 qtd->in_process = 0;
00675
00676
00677 urb->qtd = qtd;
00678 return;
00679 }
00680
00694 int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
00695 dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc)
00696 {
00697 int retval = 0;
00698 dwc_irqflags_t flags;
00699
00700 dwc_otg_hcd_urb_t *urb = qtd->urb;
00701
00702
00703
00704
00705
00706 if (*qh == NULL) {
00707 *qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc);
00708 if (*qh == NULL) {
00709 retval = -1;
00710 goto done;
00711 }
00712 }
00713 DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
00714 retval = dwc_otg_hcd_qh_add(hcd, *qh);
00715 if (retval == 0) {
00716 DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
00717 qtd_list_entry);
00718 }
00719 DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
00720
00721 done:
00722
00723 return retval;
00724 }
00725
00726 #endif