Main Page | Data Structures | File List | Data Fields | Globals | Related Pages

dwc_otg_hcd.c

Go to the documentation of this file.
00001 /* ==========================================================================
00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $
00003  * $Revision: #104 $
00004  * $Date: 2011/10/24 $
00005  * $Change: 1871159 $
00006  *
00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
00009  * otherwise expressly agreed to in writing between Synopsys and you.
00010  *
00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
00012  * any End User Software License Agreement or Agreement for Licensed Product
00013  * with Synopsys or any supplement thereto. You are permitted to use and
00014  * redistribute this Software in source and binary forms, with or without
00015  * modification, provided that redistributions of source code must retain this
00016  * notice. You may not view, use, disclose, copy or distribute this file or
00017  * any information contained herein except pursuant to this license grant from
00018  * Synopsys. If you do not agree with this notice, including the disclaimer
00019  * below, then you are not authorized to use the Software.
00020  *
00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00031  * DAMAGE.
00032  * ========================================================================== */
00033 #ifndef DWC_DEVICE_ONLY
00034 
00042 #include "dwc_otg_hcd.h"
00043 #include "dwc_otg_regs.h"
00044 
00045 dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
00046 {
00047         return DWC_ALLOC(sizeof(dwc_otg_hcd_t));
00048 }
00049 
00054 void dwc_otg_hcd_connect_timeout(void *ptr)
00055 {
00056         DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, ptr);
00057         DWC_PRINTF("Connect Timeout\n");
00058         __DWC_ERROR("Device Not Connected/Responding\n");
00059 }
00060 
00061 #ifdef DEBUG
00062 static void dump_channel_info(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00063 {
00064         if (qh->channel != NULL) {
00065                 dwc_hc_t *hc = qh->channel;
00066                 dwc_list_link_t *item;
00067                 dwc_otg_qh_t *qh_item;
00068                 int num_channels = hcd->core_if->core_params->host_channels;
00069                 int i;
00070 
00071                 dwc_otg_hc_regs_t *hc_regs;
00072                 hcchar_data_t hcchar;
00073                 hcsplt_data_t hcsplt;
00074                 hctsiz_data_t hctsiz;
00075                 uint32_t hcdma;
00076 
00077                 hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
00078                 hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
00079                 hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
00080                 hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz);
00081                 hcdma = DWC_READ_REG32(&hc_regs->hcdma);
00082 
00083                 DWC_PRINTF("  Assigned to channel %p:\n", hc);
00084                 DWC_PRINTF("    hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32,
00085                            hcsplt.d32);
00086                 DWC_PRINTF("    hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32,
00087                            hcdma);
00088                 DWC_PRINTF("    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
00089                            hc->dev_addr, hc->ep_num, hc->ep_is_in);
00090                 DWC_PRINTF("    ep_type: %d\n", hc->ep_type);
00091                 DWC_PRINTF("    max_packet: %d\n", hc->max_packet);
00092                 DWC_PRINTF("    data_pid_start: %d\n", hc->data_pid_start);
00093                 DWC_PRINTF("    xfer_started: %d\n", hc->xfer_started);
00094                 DWC_PRINTF("    halt_status: %d\n", hc->halt_status);
00095                 DWC_PRINTF("    xfer_buff: %p\n", hc->xfer_buff);
00096                 DWC_PRINTF("    xfer_len: %d\n", hc->xfer_len);
00097                 DWC_PRINTF("    qh: %p\n", hc->qh);
00098                 DWC_PRINTF("  NP inactive sched:\n");
00099                 DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_inactive) {
00100                         qh_item =
00101                             DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
00102                         DWC_PRINTF("    %p\n", qh_item);
00103                 }
00104                 DWC_PRINTF("  NP active sched:\n");
00105                 DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_active) {
00106                         qh_item =
00107                             DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
00108                         DWC_PRINTF("    %p\n", qh_item);
00109                 }
00110                 DWC_PRINTF("  Channels: \n");
00111                 for (i = 0; i < num_channels; i++) {
00112                         dwc_hc_t *hc = hcd->hc_ptr_array[i];
00113                         DWC_PRINTF("    %2d: %p\n", i, hc);
00114                 }
00115         }
00116 }
00117 #endif /* DEBUG */
00118 
00123 static void hcd_start_func(void *_vp)
00124 {
00125         dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) _vp;
00126 
00127         DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, hcd);
00128         if (hcd) {
00129                 hcd->fops->start(hcd);
00130         }
00131 }
00132 
00133 static void del_xfer_timers(dwc_otg_hcd_t * hcd)
00134 {
00135 #ifdef DEBUG
00136         int i;
00137         int num_channels = hcd->core_if->core_params->host_channels;
00138         for (i = 0; i < num_channels; i++) {
00139                 DWC_TIMER_CANCEL(hcd->core_if->hc_xfer_timer[i]);
00140         }
00141 #endif
00142 }
00143 
00144 static void del_timers(dwc_otg_hcd_t * hcd)
00145 {
00146         del_xfer_timers(hcd);
00147         DWC_TIMER_CANCEL(hcd->conn_timer);
00148 }
00149 
00154 static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
00155 {
00156         dwc_list_link_t *qh_item;
00157         dwc_otg_qh_t *qh;
00158         dwc_otg_qtd_t *qtd, *qtd_tmp;
00159 
00160         DWC_LIST_FOREACH(qh_item, qh_list) {
00161                 qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
00162                 DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
00163                                          &qh->qtd_list, qtd_list_entry) {
00164                         qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
00165                         if (qtd->urb != NULL) {
00166                                 hcd->fops->complete(hcd, qtd->urb->priv,
00167                                                     qtd->urb, -DWC_E_TIMEOUT);
00168                                 dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
00169                         }
00170 
00171                 }
00172         }
00173 }
00174 
00181 static void kill_all_urbs(dwc_otg_hcd_t * hcd)
00182 {
00183         kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive);
00184         kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active);
00185         kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive);
00186         kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready);
00187         kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned);
00188         kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued);
00189 }
00190 
00197 static void dwc_otg_hcd_start_connect_timer(dwc_otg_hcd_t * hcd)
00198 {
00199         DWC_TIMER_SCHEDULE(hcd->conn_timer, 10000 /* 10 secs */ );
00200 }
00201 
00207 static int32_t dwc_otg_hcd_session_start_cb(void *p)
00208 {
00209         dwc_otg_hcd_t *dwc_otg_hcd;
00210         DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
00211         dwc_otg_hcd = p;
00212         dwc_otg_hcd_start_connect_timer(dwc_otg_hcd);
00213         return 1;
00214 }
00215 
00222 static int32_t dwc_otg_hcd_start_cb(void *p)
00223 {
00224         dwc_otg_hcd_t *dwc_otg_hcd = p;
00225         dwc_otg_core_if_t *core_if;
00226         hprt0_data_t hprt0;
00227 
00228         core_if = dwc_otg_hcd->core_if;
00229 
00230         if (core_if->op_state == B_HOST) {
00231                 /*
00232                  * Reset the port.  During a HNP mode switch the reset
00233                  * needs to occur within 1ms and have a duration of at
00234                  * least 50ms.
00235                  */
00236                 hprt0.d32 = dwc_otg_read_hprt0(core_if);
00237                 hprt0.b.prtrst = 1;
00238                 DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
00239         }
00240         DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg,
00241                                    hcd_start_func, dwc_otg_hcd, 50,
00242                                    "start hcd");
00243 
00244         return 1;
00245 }
00246 
00252 static int32_t dwc_otg_hcd_disconnect_cb(void *p)
00253 {
00254         gintsts_data_t intr;
00255         dwc_otg_hcd_t *dwc_otg_hcd = p;
00256 
00257         /*
00258          * Set status flags for the hub driver.
00259          */
00260         dwc_otg_hcd->flags.b.port_connect_status_change = 1;
00261         dwc_otg_hcd->flags.b.port_connect_status = 0;
00262 
00263         /*
00264          * Shutdown any transfers in process by clearing the Tx FIFO Empty
00265          * interrupt mask and status bits and disabling subsequent host
00266          * channel interrupts.
00267          */
00268         intr.d32 = 0;
00269         intr.b.nptxfempty = 1;
00270         intr.b.ptxfempty = 1;
00271         intr.b.hcintr = 1;
00272         DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk,
00273                          intr.d32, 0);
00274         DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintsts,
00275                          intr.d32, 0);
00276 
00277         del_timers(dwc_otg_hcd);
00278 
00279         /*
00280          * Turn off the vbus power only if the core has transitioned to device
00281          * mode. If still in host mode, need to keep power on to detect a
00282          * reconnection.
00283          */
00284         if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) {
00285                 if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) {
00286                         hprt0_data_t hprt0 = {.d32 = 0 };
00287                         DWC_PRINTF("Disconnect: PortPower off\n");
00288                         hprt0.b.prtpwr = 0;
00289                         DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0,
00290                                         hprt0.d32);
00291                 }
00292 
00293                 dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if);
00294         }
00295 
00296         /* Respond with an error status to all URBs in the schedule. */
00297         kill_all_urbs(dwc_otg_hcd);
00298 
00299         if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) {
00300                 /* Clean up any host channels that were in use. */
00301                 int num_channels;
00302                 int i;
00303                 dwc_hc_t *channel;
00304                 dwc_otg_hc_regs_t *hc_regs;
00305                 hcchar_data_t hcchar;
00306 
00307                 num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
00308 
00309                 if (!dwc_otg_hcd->core_if->dma_enable) {
00310                         /* Flush out any channel requests in slave mode. */
00311                         for (i = 0; i < num_channels; i++) {
00312                                 channel = dwc_otg_hcd->hc_ptr_array[i];
00313                                 if (DWC_CIRCLEQ_EMPTY_ENTRY
00314                                     (channel, hc_list_entry)) {
00315                                         hc_regs =
00316                                             dwc_otg_hcd->core_if->
00317                                             host_if->hc_regs[i];
00318                                         hcchar.d32 =
00319                                             DWC_READ_REG32(&hc_regs->hcchar);
00320                                         if (hcchar.b.chen) {
00321                                                 hcchar.b.chen = 0;
00322                                                 hcchar.b.chdis = 1;
00323                                                 hcchar.b.epdir = 0;
00324                                                 DWC_WRITE_REG32
00325                                                     (&hc_regs->hcchar,
00326                                                      hcchar.d32);
00327                                         }
00328                                 }
00329                         }
00330                 }
00331 
00332                 for (i = 0; i < num_channels; i++) {
00333                         channel = dwc_otg_hcd->hc_ptr_array[i];
00334                         if (DWC_CIRCLEQ_EMPTY_ENTRY(channel, hc_list_entry)) {
00335                                 hc_regs =
00336                                     dwc_otg_hcd->core_if->host_if->hc_regs[i];
00337                                 hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
00338                                 if (hcchar.b.chen) {
00339                                         /* Halt the channel. */
00340                                         hcchar.b.chdis = 1;
00341                                         DWC_WRITE_REG32(&hc_regs->hcchar,
00342                                                         hcchar.d32);
00343                                 }
00344 
00345                                 dwc_otg_hc_cleanup(dwc_otg_hcd->core_if,
00346                                                    channel);
00347                                 DWC_CIRCLEQ_INSERT_TAIL
00348                                     (&dwc_otg_hcd->free_hc_list, channel,
00349                                      hc_list_entry);
00350                                 /*
00351                                  * Added for Descriptor DMA to prevent channel double cleanup
00352                                  * in release_channel_ddma(). Which called from ep_disable
00353                                  * when device disconnect.
00354                                  */
00355                                 channel->qh = NULL;
00356                         }
00357                 }
00358         }
00359 
00360         if (dwc_otg_hcd->fops->disconnect) {
00361                 dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
00362         }
00363 
00364         return 1;
00365 }
00366 
00372 static int32_t dwc_otg_hcd_stop_cb(void *p)
00373 {
00374         dwc_otg_hcd_t *dwc_otg_hcd = p;
00375 
00376         DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
00377         dwc_otg_hcd_stop(dwc_otg_hcd);
00378         return 1;
00379 }
00380 
00381 #ifdef CONFIG_USB_DWC_OTG_LPM
00382 
00387 static int dwc_otg_hcd_sleep_cb(void *p)
00388 {
00389         dwc_otg_hcd_t *hcd = p;
00390 
00391         dwc_otg_hcd_free_hc_from_lpm(hcd);
00392 
00393         return 0;
00394 }
00395 #endif
00396 
00402 static int dwc_otg_hcd_rem_wakeup_cb(void *p)
00403 {
00404         dwc_otg_hcd_t *hcd = p;
00405 
00406         if (hcd->core_if->lx_state == DWC_OTG_L2) {
00407                 hcd->flags.b.port_suspend_change = 1;
00408         }
00409 #ifdef CONFIG_USB_DWC_OTG_LPM
00410         else {
00411                 hcd->flags.b.port_l1_change = 1;
00412         }
00413 #endif
00414         return 0;
00415 }
00416 
00421 void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd)
00422 {
00423         hprt0_data_t hprt0 = {.d32 = 0 };
00424 
00425         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");
00426 
00427         /*
00428          * The root hub should be disconnected before this function is called.
00429          * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
00430          * and the QH lists (via ..._hcd_endpoint_disable).
00431          */
00432 
00433         /* Turn off all host-specific interrupts. */
00434         dwc_otg_disable_host_interrupts(hcd->core_if);
00435 
00436         /* Turn off the vbus power */
00437         DWC_PRINTF("PortPower off\n");
00438         hprt0.b.prtpwr = 0;
00439         DWC_WRITE_REG32(hcd->core_if->host_if->hprt0, hprt0.d32);
00440         dwc_mdelay(1);
00441 }
00442 
00443 int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
00444                             dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle,
00445                             int atomic_alloc)
00446 {
00447         dwc_irqflags_t flags;
00448         int retval = 0;
00449         dwc_otg_qtd_t *qtd;
00450         gintmsk_data_t intr_mask = {.d32 = 0 };
00451 
00452         if (!hcd->flags.b.port_connect_status) {
00453                 /* No longer connected. */
00454                 DWC_ERROR("Not connected\n");
00455                 return -DWC_E_NO_DEVICE;
00456         }
00457 
00458         qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb, atomic_alloc);
00459         if (qtd == NULL) {
00460                 DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
00461                 return -DWC_E_NO_MEMORY;
00462         }
00463 
00464         retval =
00465             dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
00466         if (retval < 0) {
00467                 DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
00468                           "Error status %d\n", retval);
00469                 dwc_otg_hcd_qtd_free(qtd);
00470         } else {
00471                 qtd->qh = *ep_handle;
00472         }
00473         intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
00474         if (!intr_mask.b.sofintr && retval == 0) {
00475                 dwc_otg_transaction_type_e tr_type;
00476                 if ((qtd->qh->ep_type == UE_BULK)
00477                     && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) {
00478                         /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
00479                         return 0;
00480                 }
00481                 DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
00482                 tr_type = dwc_otg_hcd_select_transactions(hcd);
00483                 if (tr_type != DWC_OTG_TRANSACTION_NONE) {
00484                         dwc_otg_hcd_queue_transactions(hcd, tr_type);
00485                 }
00486                 DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
00487         }
00488 
00489         return retval;
00490 }
00491 
00492 int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
00493                             dwc_otg_hcd_urb_t * dwc_otg_urb)
00494 {
00495         dwc_otg_qh_t *qh;
00496         dwc_otg_qtd_t *urb_qtd;
00497 
00498         urb_qtd = dwc_otg_urb->qtd;
00499         qh = urb_qtd->qh;
00500 #ifdef DEBUG
00501         if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
00502                 if (urb_qtd->in_process) {
00503                         dump_channel_info(hcd, qh);
00504                 }
00505         }
00506 #endif
00507         if (urb_qtd->in_process && qh->channel) {
00508                 /* The QTD is in process (it has been assigned to a channel). */
00509                 if (hcd->flags.b.port_connect_status) {
00510                         /*
00511                          * If still connected (i.e. in host mode), halt the
00512                          * channel so it can be used for other transfers. If
00513                          * no longer connected, the host registers can't be
00514                          * written to halt the channel since the core is in
00515                          * device mode.
00516                          */
00517                         dwc_otg_hc_halt(hcd->core_if, qh->channel,
00518                                         DWC_OTG_HC_XFER_URB_DEQUEUE);
00519                 }
00520         }
00521 
00522         /*
00523          * Free the QTD and clean up the associated QH. Leave the QH in the
00524          * schedule if it has any remaining QTDs.
00525          */
00526 
00527         if (!hcd->core_if->dma_desc_enable) {
00528                 uint8_t b = urb_qtd->in_process;
00529                 dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
00530                 if (b) {
00531                         dwc_otg_hcd_qh_deactivate(hcd, qh, 0);
00532                         qh->channel = NULL;
00533                 } else if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
00534                         dwc_otg_hcd_qh_remove(hcd, qh);
00535                 }
00536         } else {
00537                 dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
00538         }
00539         return 0;
00540 }
00541 
00542 int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
00543                                  int retry)
00544 {
00545         dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
00546         int retval = 0;
00547         dwc_irqflags_t flags;
00548 
00549         if (retry < 0) {
00550                 retval = -DWC_E_INVALID;
00551                 goto done;
00552         }
00553 
00554         if (!qh) {
00555                 retval = -DWC_E_INVALID;
00556                 goto done;
00557         }
00558 
00559         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
00560 
00561         while (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list) && retry) {
00562                 DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
00563                 retry--;
00564                 dwc_msleep(5);
00565                 DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
00566         }
00567 
00568         dwc_otg_hcd_qh_remove(hcd, qh);
00569 
00570         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
00571         /*
00572          * Split dwc_otg_hcd_qh_remove_and_free() into qh_remove
00573          * and qh_free to prevent stack dump on DWC_DMA_FREE() with
00574          * irq_disabled (spinlock_irqsave) in dwc_otg_hcd_desc_list_free()
00575          * and dwc_otg_hcd_frame_list_alloc().
00576          */
00577         dwc_otg_hcd_qh_free(hcd, qh);
00578 
00579 done:
00580         return retval;
00581 }
00582 
00583 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
00584 int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle)
00585 {
00586         int retval = 0;
00587         dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
00588         if (!qh)
00589                 return -DWC_E_INVALID;
00590 
00591         qh->data_toggle = DWC_OTG_HC_PID_DATA0;
00592         return retval;
00593 }
00594 #endif
00595 
00599 static dwc_otg_cil_callbacks_t hcd_cil_callbacks = {
00600         .start = dwc_otg_hcd_start_cb,
00601         .stop = dwc_otg_hcd_stop_cb,
00602         .disconnect = dwc_otg_hcd_disconnect_cb,
00603         .session_start = dwc_otg_hcd_session_start_cb,
00604         .resume_wakeup = dwc_otg_hcd_rem_wakeup_cb,
00605 #ifdef CONFIG_USB_DWC_OTG_LPM
00606         .sleep = dwc_otg_hcd_sleep_cb,
00607 #endif
00608         .p = 0,
00609 };
00610 
00614 static void reset_tasklet_func(void *data)
00615 {
00616         dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *) data;
00617         dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
00618         hprt0_data_t hprt0;
00619 
00620         DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n");
00621 
00622         hprt0.d32 = dwc_otg_read_hprt0(core_if);
00623         hprt0.b.prtrst = 1;
00624         DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
00625         dwc_mdelay(60);
00626 
00627         hprt0.b.prtrst = 0;
00628         DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
00629         dwc_otg_hcd->flags.b.port_reset_change = 1;
00630 }
00631 
00632 static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
00633 {
00634         dwc_list_link_t *item;
00635         dwc_otg_qh_t *qh;
00636         dwc_irqflags_t flags;
00637 
00638         if (!qh_list->next) {
00639                 /* The list hasn't been initialized yet. */
00640                 return;
00641         }
00642         /*
00643          * Hold spinlock here. Not needed in that case if bellow 
00644          * function is being called from ISR 
00645          */
00646         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
00647         /* Ensure there are no QTDs or URBs left. */
00648         kill_urbs_in_qh_list(hcd, qh_list);
00649         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
00650 
00651         DWC_LIST_FOREACH(item, qh_list) {
00652                 qh = DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
00653                 dwc_otg_hcd_qh_remove_and_free(hcd, qh);
00654         }
00655 }
00656 
00661 void dwc_otg_hcd_power_up(void *ptr)
00662 {
00663         gpwrdn_data_t gpwrdn = {.d32 = 0 };
00664         dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
00665 
00666         DWC_PRINTF("%s called\n", __FUNCTION__);
00667 
00668         if (!core_if->hibernation_suspend) {
00669                 DWC_PRINTF("Already exited from Hibernation\n");
00670                 return;
00671         }
00672 
00673         /* Switch on the voltage to the core */
00674         gpwrdn.b.pwrdnswtch = 1;
00675         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
00676         dwc_udelay(10);
00677 
00678         /* Reset the core */
00679         gpwrdn.d32 = 0;
00680         gpwrdn.b.pwrdnrstn = 1;
00681         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
00682         dwc_udelay(10);
00683 
00684         /* Disable power clamps */
00685         gpwrdn.d32 = 0;
00686         gpwrdn.b.pwrdnclmp = 1;
00687         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
00688 
00689         /* Remove reset the core signal */
00690         gpwrdn.d32 = 0;
00691         gpwrdn.b.pwrdnrstn = 1;
00692         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
00693         dwc_udelay(10);
00694 
00695         /* Disable PMU interrupt */
00696         gpwrdn.d32 = 0;
00697         gpwrdn.b.pmuintsel = 1;
00698         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
00699 
00700         core_if->hibernation_suspend = 0;
00701 
00702         /* Disable PMU */
00703         gpwrdn.d32 = 0;
00704         gpwrdn.b.pmuactv = 1;
00705         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
00706         dwc_udelay(10);
00707 
00708         /* Enable VBUS */
00709         gpwrdn.d32 = 0;
00710         gpwrdn.b.dis_vbus = 1;
00711         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
00712 
00713         core_if->op_state = A_HOST;
00714         dwc_otg_core_init(core_if);
00715         dwc_otg_enable_global_interrupts(core_if);
00716         cil_hcd_start(core_if);
00717 }
00718 
00723 static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)
00724 {
00725         int i;
00726 
00727         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
00728 
00729         del_timers(dwc_otg_hcd);
00730 
00731         /* Free memory for QH/QTD lists */
00732         qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
00733         qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);
00734         qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);
00735         qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
00736         qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
00737         qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
00738 
00739         /* Free memory for the host channels. */
00740         for (i = 0; i < MAX_EPS_CHANNELS; i++) {
00741                 dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i];
00742 
00743 #ifdef DEBUG
00744                 if (dwc_otg_hcd->core_if->hc_xfer_timer[i]) {
00745                         DWC_TIMER_FREE(dwc_otg_hcd->core_if->hc_xfer_timer[i]);
00746                 }
00747 #endif
00748                 if (hc != NULL) {
00749                         DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n",
00750                                     i, hc);
00751                         DWC_FREE(hc);
00752                 }
00753         }
00754 
00755         if (dwc_otg_hcd->core_if->dma_enable) {
00756                 if (dwc_otg_hcd->status_buf_dma) {
00757                         DWC_DMA_FREE(DWC_OTG_HCD_STATUS_BUF_SIZE,
00758                                      dwc_otg_hcd->status_buf,
00759                                      dwc_otg_hcd->status_buf_dma);
00760                 }
00761         } else if (dwc_otg_hcd->status_buf != NULL) {
00762                 DWC_FREE(dwc_otg_hcd->status_buf);
00763         }
00764         DWC_SPINLOCK_FREE(dwc_otg_hcd->lock);
00765         /* Set core_if's lock pointer to NULL */
00766         dwc_otg_hcd->core_if->lock = NULL;
00767 
00768         DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
00769         DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
00770 
00771 #ifdef DWC_DEV_SRPCAP
00772         if (dwc_otg_hcd->core_if->power_down == 2 &&
00773             dwc_otg_hcd->core_if->pwron_timer) {
00774                 DWC_TIMER_FREE(dwc_otg_hcd->core_if->pwron_timer);
00775         }
00776 #endif
00777         DWC_FREE(dwc_otg_hcd);
00778 }
00779 
00780 int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
00781 {
00782         int retval = 0;
00783         int num_channels;
00784         int i;
00785         dwc_hc_t *channel;
00786 
00787         hcd->lock = DWC_SPINLOCK_ALLOC();
00788         if (!hcd->lock) {
00789                 DWC_ERROR("Could not allocate lock for pcd");
00790                 DWC_FREE(hcd);
00791                 retval = -DWC_E_NO_MEMORY;
00792                 goto out;
00793         }
00794         hcd->core_if = core_if;
00795 
00796         /* Register the HCD CIL Callbacks */
00797         dwc_otg_cil_register_hcd_callbacks(hcd->core_if,
00798                                            &hcd_cil_callbacks, hcd);
00799 
00800         /* Initialize the non-periodic schedule. */
00801         DWC_LIST_INIT(&hcd->non_periodic_sched_inactive);
00802         DWC_LIST_INIT(&hcd->non_periodic_sched_active);
00803 
00804         /* Initialize the periodic schedule. */
00805         DWC_LIST_INIT(&hcd->periodic_sched_inactive);
00806         DWC_LIST_INIT(&hcd->periodic_sched_ready);
00807         DWC_LIST_INIT(&hcd->periodic_sched_assigned);
00808         DWC_LIST_INIT(&hcd->periodic_sched_queued);
00809 
00810         /*
00811          * Create a host channel descriptor for each host channel implemented
00812          * in the controller. Initialize the channel descriptor array.
00813          */
00814         DWC_CIRCLEQ_INIT(&hcd->free_hc_list);
00815         num_channels = hcd->core_if->core_params->host_channels;
00816         DWC_MEMSET(hcd->hc_ptr_array, 0, sizeof(hcd->hc_ptr_array));
00817         for (i = 0; i < num_channels; i++) {
00818                 channel = DWC_ALLOC(sizeof(dwc_hc_t));
00819                 if (channel == NULL) {
00820                         retval = -DWC_E_NO_MEMORY;
00821                         DWC_ERROR("%s: host channel allocation failed\n",
00822                                   __func__);
00823                         dwc_otg_hcd_free(hcd);
00824                         goto out;
00825                 }
00826                 channel->hc_num = i;
00827                 hcd->hc_ptr_array[i] = channel;
00828 #ifdef DEBUG
00829                 hcd->core_if->hc_xfer_timer[i] =
00830                     DWC_TIMER_ALLOC("hc timer", hc_xfer_timeout,
00831                                     &hcd->core_if->hc_xfer_info[i]);
00832 #endif
00833                 DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i,
00834                             channel);
00835         }
00836 
00837         /* Initialize the Connection timeout timer. */
00838         hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer",
00839                                           dwc_otg_hcd_connect_timeout, 0);
00840 
00841         /* Initialize reset tasklet. */
00842         hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd);
00843 #ifdef DWC_DEV_SRPCAP
00844         if (hcd->core_if->power_down == 2) {
00845                 /* Initialize Power on timer for Host power up in case hibernation */
00846                 hcd->core_if->pwron_timer = DWC_TIMER_ALLOC("PWRON TIMER",
00847                                                                         dwc_otg_hcd_power_up, core_if);
00848         }
00849 #endif  
00850 
00851         /*
00852          * Allocate space for storing data on status transactions. Normally no
00853          * data is sent, but this space acts as a bit bucket. This must be
00854          * done after usb_add_hcd since that function allocates the DMA buffer
00855          * pool.
00856          */
00857         if (hcd->core_if->dma_enable) {
00858                 hcd->status_buf =
00859                     DWC_DMA_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE,
00860                                   &hcd->status_buf_dma);
00861         } else {
00862                 hcd->status_buf = DWC_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE);
00863         }
00864         if (!hcd->status_buf) {
00865                 retval = -DWC_E_NO_MEMORY;
00866                 DWC_ERROR("%s: status_buf allocation failed\n", __func__);
00867                 dwc_otg_hcd_free(hcd);
00868                 goto out;
00869         }
00870 
00871         hcd->otg_port = 1;
00872         hcd->frame_list = NULL;
00873         hcd->frame_list_dma = 0;
00874         hcd->periodic_qh_count = 0;
00875 out:
00876         return retval;
00877 }
00878 
00879 void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd)
00880 {
00881         /* Turn off all host-specific interrupts. */
00882         dwc_otg_disable_host_interrupts(hcd->core_if);
00883 
00884         dwc_otg_hcd_free(hcd);
00885 }
00886 
00890 static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd)
00891 {
00892         int num_channels;
00893         int i;
00894         dwc_hc_t *channel;
00895         dwc_hc_t *channel_tmp;
00896 
00897         hcd->flags.d32 = 0;
00898 
00899         hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active;
00900         hcd->non_periodic_channels = 0;
00901         hcd->periodic_channels = 0;
00902 
00903         /*
00904          * Put all channels in the free channel list and clean up channel
00905          * states.
00906          */
00907         DWC_CIRCLEQ_FOREACH_SAFE(channel, channel_tmp,
00908                                  &hcd->free_hc_list, hc_list_entry) {
00909                 DWC_CIRCLEQ_REMOVE(&hcd->free_hc_list, channel, hc_list_entry);
00910         }
00911 
00912         num_channels = hcd->core_if->core_params->host_channels;
00913         for (i = 0; i < num_channels; i++) {
00914                 channel = hcd->hc_ptr_array[i];
00915                 DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, channel,
00916                                         hc_list_entry);
00917                 dwc_otg_hc_cleanup(hcd->core_if, channel);
00918         }
00919 
00920         /* Initialize the DWC core for host mode operation. */
00921         dwc_otg_core_host_init(hcd->core_if);
00922 
00923         /* Set core_if's lock pointer to the hcd->lock */
00924         hcd->core_if->lock = hcd->lock;
00925 }
00926 
00936 static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00937 {
00938         dwc_hc_t *hc;
00939         dwc_otg_qtd_t *qtd;
00940         dwc_otg_hcd_urb_t *urb;
00941         void* ptr = NULL;
00942 
00943         DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p)\n", __func__, hcd, qh);
00944 
00945         hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
00946 
00947         /* Remove the host channel from the free list. */
00948         DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
00949 
00950         qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
00951 
00952         urb = qtd->urb;
00953         qh->channel = hc;
00954 
00955         qtd->in_process = 1;
00956 
00957         /*
00958          * Use usb_pipedevice to determine device address. This address is
00959          * 0 before the SET_ADDRESS command and the correct address afterward.
00960          */
00961         hc->dev_addr = dwc_otg_hcd_get_dev_addr(&urb->pipe_info);
00962         hc->ep_num = dwc_otg_hcd_get_ep_num(&urb->pipe_info);
00963         hc->speed = qh->dev_speed;
00964         hc->max_packet = dwc_max_packet(qh->maxp);
00965 
00966         hc->xfer_started = 0;
00967         hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;
00968         hc->error_state = (qtd->error_count > 0);
00969         hc->halt_on_queue = 0;
00970         hc->halt_pending = 0;
00971         hc->requests = 0;
00972 
00973         /*
00974          * The following values may be modified in the transfer type section
00975          * below. The xfer_len value may be reduced when the transfer is
00976          * started to accommodate the max widths of the XferSize and PktCnt
00977          * fields in the HCTSIZn register.
00978          */
00979 
00980         hc->ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0);
00981         if (hc->ep_is_in) {
00982                 hc->do_ping = 0;
00983         } else {
00984                 hc->do_ping = qh->ping_state;
00985         }
00986 
00987         hc->data_pid_start = qh->data_toggle;
00988         hc->multi_count = 1;
00989 
00990         if (hcd->core_if->dma_enable) {
00991                 hc->xfer_buff = (uint8_t *) urb->dma + urb->actual_length;
00992 
00993                 /* For non-dword aligned case */
00994                 if (((unsigned long)hc->xfer_buff & 0x3)
00995                     && !hcd->core_if->dma_desc_enable) {
00996                         ptr = (uint8_t *) urb->buf + urb->actual_length;
00997                 }
00998         } else {
00999                 hc->xfer_buff = (uint8_t *) urb->buf + urb->actual_length;
01000         }
01001         hc->xfer_len = urb->length - urb->actual_length;
01002         hc->xfer_count = 0;
01003 
01004         /*
01005          * Set the split attributes
01006          */
01007         hc->do_split = 0;
01008         if (qh->do_split) {
01009                 uint32_t hub_addr, port_addr;
01010                 hc->do_split = 1;
01011                 hc->xact_pos = qtd->isoc_split_pos;
01012                 hc->complete_split = qtd->complete_split;
01013                 hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr);
01014                 hc->hub_addr = (uint8_t) hub_addr;
01015                 hc->port_addr = (uint8_t) port_addr;
01016         }
01017 
01018         switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
01019         case UE_CONTROL:
01020                 hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;
01021                 switch (qtd->control_phase) {
01022                 case DWC_OTG_CONTROL_SETUP:
01023                         DWC_DEBUGPL(DBG_HCDV, "  Control setup transaction\n");
01024                         hc->do_ping = 0;
01025                         hc->ep_is_in = 0;
01026                         hc->data_pid_start = DWC_OTG_HC_PID_SETUP;
01027                         if (hcd->core_if->dma_enable) {
01028                                 hc->xfer_buff = (uint8_t *) urb->setup_dma;
01029                         } else {
01030                                 hc->xfer_buff = (uint8_t *) urb->setup_packet;
01031                         }
01032                         hc->xfer_len = 8;
01033                         ptr = NULL;
01034                         break;
01035                 case DWC_OTG_CONTROL_DATA:
01036                         DWC_DEBUGPL(DBG_HCDV, "  Control data transaction\n");
01037                         hc->data_pid_start = qtd->data_toggle;
01038                         break;
01039                 case DWC_OTG_CONTROL_STATUS:
01040                         /*
01041                          * Direction is opposite of data direction or IN if no
01042                          * data.
01043                          */
01044                         DWC_DEBUGPL(DBG_HCDV, "  Control status transaction\n");
01045                         if (urb->length == 0) {
01046                                 hc->ep_is_in = 1;
01047                         } else {
01048                                 hc->ep_is_in =
01049                                     dwc_otg_hcd_is_pipe_out(&urb->pipe_info);
01050                         }
01051                         if (hc->ep_is_in) {
01052                                 hc->do_ping = 0;
01053                         }
01054 
01055                         hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
01056 
01057                         hc->xfer_len = 0;
01058                         if (hcd->core_if->dma_enable) {
01059                                 hc->xfer_buff = (uint8_t *) hcd->status_buf_dma;
01060                         } else {
01061                                 hc->xfer_buff = (uint8_t *) hcd->status_buf;
01062                         }
01063                         ptr = NULL;
01064                         break;
01065                 }
01066                 break;
01067         case UE_BULK:
01068                 hc->ep_type = DWC_OTG_EP_TYPE_BULK;
01069                 break;
01070         case UE_INTERRUPT:
01071                 hc->ep_type = DWC_OTG_EP_TYPE_INTR;
01072                 break;
01073         case UE_ISOCHRONOUS:
01074                 {
01075                         struct dwc_otg_hcd_iso_packet_desc *frame_desc;
01076 
01077                         hc->ep_type = DWC_OTG_EP_TYPE_ISOC;
01078 
01079                         if (hcd->core_if->dma_desc_enable)
01080                                 break;
01081 
01082                         frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
01083 
01084                         frame_desc->status = 0;
01085 
01086                         if (hcd->core_if->dma_enable) {
01087                                 hc->xfer_buff = (uint8_t *) urb->dma;
01088                         } else {
01089                                 hc->xfer_buff = (uint8_t *) urb->buf;
01090                         }
01091                         hc->xfer_buff +=
01092                             frame_desc->offset + qtd->isoc_split_offset;
01093                         hc->xfer_len =
01094                             frame_desc->length - qtd->isoc_split_offset;
01095 
01096                         /* For non-dword aligned buffers */
01097                         if (((unsigned long)hc->xfer_buff & 0x3)
01098                             && hcd->core_if->dma_enable) {
01099                                 ptr =
01100                                     (uint8_t *) urb->buf + frame_desc->offset +
01101                                     qtd->isoc_split_offset;
01102                         } else
01103                                 ptr = NULL;
01104 
01105                         if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {
01106                                 if (hc->xfer_len <= 188) {
01107                                         hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;
01108                                 } else {
01109                                         hc->xact_pos =
01110                                             DWC_HCSPLIT_XACTPOS_BEGIN;
01111                                 }
01112                         }
01113                 }
01114                 break;
01115         }
01116         /* non DWORD-aligned buffer case */     
01117         if (ptr) {
01118                 uint32_t buf_size;
01119                 if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
01120                         buf_size = hcd->core_if->core_params->max_transfer_size;
01121                 } else {                                
01122                         buf_size = 4096;
01123                 }
01124                 if (!qh->dw_align_buf) {
01125                         qh->dw_align_buf = DWC_DMA_ALLOC_ATOMIC(buf_size,
01126                                                          &qh->dw_align_buf_dma);
01127                         if (!qh->dw_align_buf) {
01128                                 DWC_ERROR
01129                                     ("%s: Failed to allocate memory to handle "
01130                                      "non-dword aligned buffer case\n",
01131                                      __func__);
01132                                 return;
01133                         }
01134                 }
01135                 if (!hc->ep_is_in) {
01136                         dwc_memcpy(qh->dw_align_buf, ptr, hc->xfer_len);
01137                 }
01138                 hc->align_buff = qh->dw_align_buf_dma;
01139         } else {
01140                 hc->align_buff = 0;
01141         }
01142 
01143         if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
01144             hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
01145                 /*
01146                  * This value may be modified when the transfer is started to
01147                  * reflect the actual transfer length.
01148                  */
01149                 hc->multi_count = dwc_hb_mult(qh->maxp);
01150         }
01151 
01152         if (hcd->core_if->dma_desc_enable)
01153                 hc->desc_list_addr = qh->desc_list_dma;
01154 
01155         dwc_otg_hc_init(hcd->core_if, hc);
01156         hc->qh = qh;
01157 }
01158 
01168 dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
01169 {
01170         dwc_list_link_t *qh_ptr;
01171         dwc_otg_qh_t *qh;
01172         int num_channels;
01173         dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;
01174 
01175 #ifdef DEBUG_SOF
01176         DWC_DEBUGPL(DBG_HCD, "  Select Transactions\n");
01177 #endif
01178 
01179         /* Process entries in the periodic ready list. */
01180         qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready);
01181 
01182         while (qh_ptr != &hcd->periodic_sched_ready &&
01183                !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
01184 
01185                 qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
01186                 assign_and_init_hc(hcd, qh);
01187 
01188                 /*
01189                  * Move the QH from the periodic ready schedule to the
01190                  * periodic assigned schedule.
01191                  */
01192                 qh_ptr = DWC_LIST_NEXT(qh_ptr);
01193                 DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
01194                                    &qh->qh_list_entry);
01195 
01196                 ret_val = DWC_OTG_TRANSACTION_PERIODIC;
01197         }
01198 
01199         /*
01200          * Process entries in the inactive portion of the non-periodic
01201          * schedule. Some free host channels may not be used if they are
01202          * reserved for periodic transfers.
01203          */
01204         qh_ptr = hcd->non_periodic_sched_inactive.next;
01205         num_channels = hcd->core_if->core_params->host_channels;
01206         while (qh_ptr != &hcd->non_periodic_sched_inactive &&
01207                (hcd->non_periodic_channels <
01208                 num_channels - hcd->periodic_channels) &&
01209                !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
01210 
01211                 qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
01212 
01213                 assign_and_init_hc(hcd, qh);
01214 
01215                 /*
01216                  * Move the QH from the non-periodic inactive schedule to the
01217                  * non-periodic active schedule.
01218                  */
01219                 qh_ptr = DWC_LIST_NEXT(qh_ptr);
01220                 DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active,
01221                                    &qh->qh_list_entry);
01222 
01223                 if (ret_val == DWC_OTG_TRANSACTION_NONE) {
01224                         ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
01225                 } else {
01226                         ret_val = DWC_OTG_TRANSACTION_ALL;
01227                 }
01228 
01229                 hcd->non_periodic_channels++;
01230         }
01231 
01232         return ret_val;
01233 }
01234 
01253 static int queue_transaction(dwc_otg_hcd_t * hcd,
01254                              dwc_hc_t * hc, uint16_t fifo_dwords_avail)
01255 {
01256         int retval;
01257 
01258         if (hcd->core_if->dma_enable) {
01259                 if (hcd->core_if->dma_desc_enable) {
01260                         if (!hc->xfer_started
01261                             || (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) {
01262                                 dwc_otg_hcd_start_xfer_ddma(hcd, hc->qh);
01263                                 hc->qh->ping_state = 0;
01264                         }
01265                 } else if (!hc->xfer_started) {
01266                         dwc_otg_hc_start_transfer(hcd->core_if, hc);
01267                         hc->qh->ping_state = 0;
01268                 }
01269                 retval = 0;
01270         } else if (hc->halt_pending) {
01271                 /* Don't queue a request if the channel has been halted. */
01272                 retval = 0;
01273         } else if (hc->halt_on_queue) {
01274                 dwc_otg_hc_halt(hcd->core_if, hc, hc->halt_status);
01275                 retval = 0;
01276         } else if (hc->do_ping) {
01277                 if (!hc->xfer_started) {
01278                         dwc_otg_hc_start_transfer(hcd->core_if, hc);
01279                 }
01280                 retval = 0;
01281         } else if (!hc->ep_is_in || hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
01282                 if ((fifo_dwords_avail * 4) >= hc->max_packet) {
01283                         if (!hc->xfer_started) {
01284                                 dwc_otg_hc_start_transfer(hcd->core_if, hc);
01285                                 retval = 1;
01286                         } else {
01287                                 retval =
01288                                     dwc_otg_hc_continue_transfer(hcd->core_if,
01289                                                                  hc);
01290                         }
01291                 } else {
01292                         retval = -1;
01293                 }
01294         } else {
01295                 if (!hc->xfer_started) {
01296                         dwc_otg_hc_start_transfer(hcd->core_if, hc);
01297                         retval = 1;
01298                 } else {
01299                         retval = dwc_otg_hc_continue_transfer(hcd->core_if, hc);
01300                 }
01301         }
01302 
01303         return retval;
01304 }
01305 
01313 static void process_periodic_channels(dwc_otg_hcd_t * hcd)
01314 {
01315         hptxsts_data_t tx_status;
01316         dwc_list_link_t *qh_ptr;
01317         dwc_otg_qh_t *qh;
01318         int status;
01319         int no_queue_space = 0;
01320         int no_fifo_space = 0;
01321 
01322         dwc_otg_host_global_regs_t *host_regs;
01323         host_regs = hcd->core_if->host_if->host_global_regs;
01324 
01325         DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n");
01326 #ifdef DEBUG
01327         tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
01328         DWC_DEBUGPL(DBG_HCDV,
01329                     "  P Tx Req Queue Space Avail (before queue): %d\n",
01330                     tx_status.b.ptxqspcavail);
01331         DWC_DEBUGPL(DBG_HCDV, "  P Tx FIFO Space Avail (before queue): %d\n",
01332                     tx_status.b.ptxfspcavail);
01333 #endif
01334 
01335         qh_ptr = hcd->periodic_sched_assigned.next;
01336         while (qh_ptr != &hcd->periodic_sched_assigned) {
01337                 tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
01338                 if (tx_status.b.ptxqspcavail == 0) {
01339                         no_queue_space = 1;
01340                         break;
01341                 }
01342 
01343                 qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
01344 
01345                 /*
01346                  * Set a flag if we're queuing high-bandwidth in slave mode.
01347                  * The flag prevents any halts to get into the request queue in
01348                  * the middle of multiple high-bandwidth packets getting queued.
01349                  */
01350                 if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) {
01351                         hcd->core_if->queuing_high_bandwidth = 1;
01352                 }
01353                 status =
01354                     queue_transaction(hcd, qh->channel,
01355                                       tx_status.b.ptxfspcavail);
01356                 if (status < 0) {
01357                         no_fifo_space = 1;
01358                         break;
01359                 }
01360 
01361                 /*
01362                  * In Slave mode, stay on the current transfer until there is
01363                  * nothing more to do or the high-bandwidth request count is
01364                  * reached. In DMA mode, only need to queue one request. The
01365                  * controller automatically handles multiple packets for
01366                  * high-bandwidth transfers.
01367                  */
01368                 if (hcd->core_if->dma_enable || status == 0 ||
01369                     qh->channel->requests == qh->channel->multi_count) {
01370                         qh_ptr = qh_ptr->next;
01371                         /*
01372                          * Move the QH from the periodic assigned schedule to
01373                          * the periodic queued schedule.
01374                          */
01375                         DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_queued,
01376                                            &qh->qh_list_entry);
01377 
01378                         /* done queuing high bandwidth */
01379                         hcd->core_if->queuing_high_bandwidth = 0;
01380                 }
01381         }
01382 
01383         if (!hcd->core_if->dma_enable) {
01384                 dwc_otg_core_global_regs_t *global_regs;
01385                 gintmsk_data_t intr_mask = {.d32 = 0 };
01386 
01387                 global_regs = hcd->core_if->core_global_regs;
01388                 intr_mask.b.ptxfempty = 1;
01389 #ifdef DEBUG
01390                 tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts);
01391                 DWC_DEBUGPL(DBG_HCDV,
01392                             "  P Tx Req Queue Space Avail (after queue): %d\n",
01393                             tx_status.b.ptxqspcavail);
01394                 DWC_DEBUGPL(DBG_HCDV,
01395                             "  P Tx FIFO Space Avail (after queue): %d\n",
01396                             tx_status.b.ptxfspcavail);
01397 #endif
01398                 if (!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned) ||
01399                     no_queue_space || no_fifo_space) {
01400                         /*
01401                          * May need to queue more transactions as the request
01402                          * queue or Tx FIFO empties. Enable the periodic Tx
01403                          * FIFO empty interrupt. (Always use the half-empty
01404                          * level to ensure that new requests are loaded as
01405                          * soon as possible.)
01406                          */
01407                         DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
01408                                          intr_mask.d32);
01409                 } else {
01410                         /*
01411                          * Disable the Tx FIFO empty interrupt since there are
01412                          * no more transactions that need to be queued right
01413                          * now. This function is called from interrupt
01414                          * handlers to queue more transactions as transfer
01415                          * states change.
01416                          */
01417                         DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
01418                                          0);
01419                 }
01420         }
01421 }
01422 
01430 static void process_non_periodic_channels(dwc_otg_hcd_t * hcd)
01431 {
01432         gnptxsts_data_t tx_status;
01433         dwc_list_link_t *orig_qh_ptr;
01434         dwc_otg_qh_t *qh;
01435         int status;
01436         int no_queue_space = 0;
01437         int no_fifo_space = 0;
01438         int more_to_do = 0;
01439 
01440         dwc_otg_core_global_regs_t *global_regs =
01441             hcd->core_if->core_global_regs;
01442 
01443         DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n");
01444 #ifdef DEBUG
01445         tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
01446         DWC_DEBUGPL(DBG_HCDV,
01447                     "  NP Tx Req Queue Space Avail (before queue): %d\n",
01448                     tx_status.b.nptxqspcavail);
01449         DWC_DEBUGPL(DBG_HCDV, "  NP Tx FIFO Space Avail (before queue): %d\n",
01450                     tx_status.b.nptxfspcavail);
01451 #endif
01452         /*
01453          * Keep track of the starting point. Skip over the start-of-list
01454          * entry.
01455          */
01456         if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
01457                 hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
01458         }
01459         orig_qh_ptr = hcd->non_periodic_qh_ptr;
01460 
01461         /*
01462          * Process once through the active list or until no more space is
01463          * available in the request queue or the Tx FIFO.
01464          */
01465         do {
01466                 tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
01467                 if (!hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) {
01468                         no_queue_space = 1;
01469                         break;
01470                 }
01471 
01472                 qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t,
01473                                     qh_list_entry);
01474                 status =
01475                     queue_transaction(hcd, qh->channel,
01476                                       tx_status.b.nptxfspcavail);
01477 
01478                 if (status > 0) {
01479                         more_to_do = 1;
01480                 } else if (status < 0) {
01481                         no_fifo_space = 1;
01482                         break;
01483                 }
01484 
01485                 /* Advance to next QH, skipping start-of-list entry. */
01486                 hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
01487                 if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
01488                         hcd->non_periodic_qh_ptr =
01489                             hcd->non_periodic_qh_ptr->next;
01490                 }
01491 
01492         } while (hcd->non_periodic_qh_ptr != orig_qh_ptr);
01493 
01494         if (!hcd->core_if->dma_enable) {
01495                 gintmsk_data_t intr_mask = {.d32 = 0 };
01496                 intr_mask.b.nptxfempty = 1;
01497 
01498 #ifdef DEBUG
01499                 tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
01500                 DWC_DEBUGPL(DBG_HCDV,
01501                             "  NP Tx Req Queue Space Avail (after queue): %d\n",
01502                             tx_status.b.nptxqspcavail);
01503                 DWC_DEBUGPL(DBG_HCDV,
01504                             "  NP Tx FIFO Space Avail (after queue): %d\n",
01505                             tx_status.b.nptxfspcavail);
01506 #endif
01507                 if (more_to_do || no_queue_space || no_fifo_space) {
01508                         /*
01509                          * May need to queue more transactions as the request
01510                          * queue or Tx FIFO empties. Enable the non-periodic
01511                          * Tx FIFO empty interrupt. (Always use the half-empty
01512                          * level to ensure that new requests are loaded as
01513                          * soon as possible.)
01514                          */
01515                         DWC_MODIFY_REG32(&global_regs->gintmsk, 0,
01516                                          intr_mask.d32);
01517                 } else {
01518                         /*
01519                          * Disable the Tx FIFO empty interrupt since there are
01520                          * no more transactions that need to be queued right
01521                          * now. This function is called from interrupt
01522                          * handlers to queue more transactions as transfer
01523                          * states change.
01524                          */
01525                         DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32,
01526                                          0);
01527                 }
01528         }
01529 }
01530 
01540 void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
01541                                     dwc_otg_transaction_type_e tr_type)
01542 {
01543 #ifdef DEBUG_SOF
01544         DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n");
01545 #endif
01546         /* Process host channels associated with periodic transfers. */
01547         if ((tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
01548              tr_type == DWC_OTG_TRANSACTION_ALL) &&
01549             !DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) {
01550 
01551                 process_periodic_channels(hcd);
01552         }
01553 
01554         /* Process host channels associated with non-periodic transfers. */
01555         if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC ||
01556             tr_type == DWC_OTG_TRANSACTION_ALL) {
01557                 if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) {
01558                         process_non_periodic_channels(hcd);
01559                 } else {
01560                         /*
01561                          * Ensure NP Tx FIFO empty interrupt is disabled when
01562                          * there are no non-periodic transfers to process.
01563                          */
01564                         gintmsk_data_t gintmsk = {.d32 = 0 };
01565                         gintmsk.b.nptxfempty = 1;
01566                         DWC_MODIFY_REG32(&hcd->core_if->
01567                                          core_global_regs->gintmsk, gintmsk.d32,
01568                                          0);
01569                 }
01570         }
01571 }
01572 
01573 #ifdef DWC_HS_ELECT_TST
01574 /*
01575  * Quick and dirty hack to implement the HS Electrical Test
01576  * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
01577  *
01578  * This code was copied from our userspace app "hset". It sends a
01579  * Get Device Descriptor control sequence in two parts, first the
01580  * Setup packet by itself, followed some time later by the In and
01581  * Ack packets. Rather than trying to figure out how to add this
01582  * functionality to the normal driver code, we just hijack the
01583  * hardware, using these two function to drive the hardware
01584  * directly.
01585  */
01586 
01587 static dwc_otg_core_global_regs_t *global_regs;
01588 static dwc_otg_host_global_regs_t *hc_global_regs;
01589 static dwc_otg_hc_regs_t *hc_regs;
01590 static uint32_t *data_fifo;
01591 
01592 static void do_setup(void)
01593 {
01594         gintsts_data_t gintsts;
01595         hctsiz_data_t hctsiz;
01596         hcchar_data_t hcchar;
01597         haint_data_t haint;
01598         hcint_data_t hcint;
01599 
01600         /* Enable HAINTs */
01601         DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
01602 
01603         /* Enable HCINTs */
01604         DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
01605 
01606         /* Read GINTSTS */
01607         gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01608 
01609         /* Read HAINT */
01610         haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
01611 
01612         /* Read HCINT */
01613         hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
01614 
01615         /* Read HCCHAR */
01616         hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01617 
01618         /* Clear HCINT */
01619         DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
01620 
01621         /* Clear HAINT */
01622         DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
01623 
01624         /* Clear GINTSTS */
01625         DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
01626 
01627         /* Read GINTSTS */
01628         gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01629 
01630         /*
01631          * Send Setup packet (Get Device Descriptor)
01632          */
01633 
01634         /* Make sure channel is disabled */
01635         hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01636         if (hcchar.b.chen) {
01637                 hcchar.b.chdis = 1;
01638 //              hcchar.b.chen = 1;
01639                 DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
01640                 //sleep(1);
01641                 dwc_mdelay(1000);
01642 
01643                 /* Read GINTSTS */
01644                 gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01645 
01646                 /* Read HAINT */
01647                 haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
01648 
01649                 /* Read HCINT */
01650                 hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
01651 
01652                 /* Read HCCHAR */
01653                 hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01654 
01655                 /* Clear HCINT */
01656                 DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
01657 
01658                 /* Clear HAINT */
01659                 DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
01660 
01661                 /* Clear GINTSTS */
01662                 DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
01663 
01664                 hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01665         }
01666 
01667         /* Set HCTSIZ */
01668         hctsiz.d32 = 0;
01669         hctsiz.b.xfersize = 8;
01670         hctsiz.b.pktcnt = 1;
01671         hctsiz.b.pid = DWC_OTG_HC_PID_SETUP;
01672         DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
01673 
01674         /* Set HCCHAR */
01675         hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01676         hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
01677         hcchar.b.epdir = 0;
01678         hcchar.b.epnum = 0;
01679         hcchar.b.mps = 8;
01680         hcchar.b.chen = 1;
01681         DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
01682 
01683         /* Fill FIFO with Setup data for Get Device Descriptor */
01684         data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
01685         DWC_WRITE_REG32(data_fifo++, 0x01000680);
01686         DWC_WRITE_REG32(data_fifo++, 0x00080000);
01687 
01688         gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01689 
01690         /* Wait for host channel interrupt */
01691         do {
01692                 gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01693         } while (gintsts.b.hcintr == 0);
01694 
01695         /* Disable HCINTs */
01696         DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
01697 
01698         /* Disable HAINTs */
01699         DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
01700 
01701         /* Read HAINT */
01702         haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
01703 
01704         /* Read HCINT */
01705         hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
01706 
01707         /* Read HCCHAR */
01708         hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01709 
01710         /* Clear HCINT */
01711         DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
01712 
01713         /* Clear HAINT */
01714         DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
01715 
01716         /* Clear GINTSTS */
01717         DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
01718 
01719         /* Read GINTSTS */
01720         gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01721 }
01722 
01723 static void do_in_ack(void)
01724 {
01725         gintsts_data_t gintsts;
01726         hctsiz_data_t hctsiz;
01727         hcchar_data_t hcchar;
01728         haint_data_t haint;
01729         hcint_data_t hcint;
01730         host_grxsts_data_t grxsts;
01731 
01732         /* Enable HAINTs */
01733         DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001);
01734 
01735         /* Enable HCINTs */
01736         DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3);
01737 
01738         /* Read GINTSTS */
01739         gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01740 
01741         /* Read HAINT */
01742         haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
01743 
01744         /* Read HCINT */
01745         hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
01746 
01747         /* Read HCCHAR */
01748         hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01749 
01750         /* Clear HCINT */
01751         DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
01752 
01753         /* Clear HAINT */
01754         DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
01755 
01756         /* Clear GINTSTS */
01757         DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
01758 
01759         /* Read GINTSTS */
01760         gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01761 
01762         /*
01763          * Receive Control In packet
01764          */
01765 
01766         /* Make sure channel is disabled */
01767         hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01768         if (hcchar.b.chen) {
01769                 hcchar.b.chdis = 1;
01770                 hcchar.b.chen = 1;
01771                 DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
01772                 //sleep(1);
01773                 dwc_mdelay(1000);
01774 
01775                 /* Read GINTSTS */
01776                 gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01777 
01778                 /* Read HAINT */
01779                 haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
01780 
01781                 /* Read HCINT */
01782                 hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
01783 
01784                 /* Read HCCHAR */
01785                 hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01786 
01787                 /* Clear HCINT */
01788                 DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
01789 
01790                 /* Clear HAINT */
01791                 DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
01792 
01793                 /* Clear GINTSTS */
01794                 DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
01795 
01796                 hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01797         }
01798 
01799         /* Set HCTSIZ */
01800         hctsiz.d32 = 0;
01801         hctsiz.b.xfersize = 8;
01802         hctsiz.b.pktcnt = 1;
01803         hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
01804         DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
01805 
01806         /* Set HCCHAR */
01807         hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01808         hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
01809         hcchar.b.epdir = 1;
01810         hcchar.b.epnum = 0;
01811         hcchar.b.mps = 8;
01812         hcchar.b.chen = 1;
01813         DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
01814 
01815         gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01816 
01817         /* Wait for receive status queue interrupt */
01818         do {
01819                 gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01820         } while (gintsts.b.rxstsqlvl == 0);
01821 
01822         /* Read RXSTS */
01823         grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
01824 
01825         /* Clear RXSTSQLVL in GINTSTS */
01826         gintsts.d32 = 0;
01827         gintsts.b.rxstsqlvl = 1;
01828         DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
01829 
01830         switch (grxsts.b.pktsts) {
01831         case DWC_GRXSTS_PKTSTS_IN:
01832                 /* Read the data into the host buffer */
01833                 if (grxsts.b.bcnt > 0) {
01834                         int i;
01835                         int word_count = (grxsts.b.bcnt + 3) / 4;
01836 
01837                         data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
01838 
01839                         for (i = 0; i < word_count; i++) {
01840                                 (void)DWC_READ_REG32(data_fifo++);
01841                         }
01842                 }
01843                 break;
01844 
01845         default:
01846                 break;
01847         }
01848 
01849         gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01850 
01851         /* Wait for receive status queue interrupt */
01852         do {
01853                 gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01854         } while (gintsts.b.rxstsqlvl == 0);
01855 
01856         /* Read RXSTS */
01857         grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp);
01858 
01859         /* Clear RXSTSQLVL in GINTSTS */
01860         gintsts.d32 = 0;
01861         gintsts.b.rxstsqlvl = 1;
01862         DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
01863 
01864         switch (grxsts.b.pktsts) {
01865         case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
01866                 break;
01867 
01868         default:
01869                 break;
01870         }
01871 
01872         gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01873 
01874         /* Wait for host channel interrupt */
01875         do {
01876                 gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01877         } while (gintsts.b.hcintr == 0);
01878 
01879         /* Read HAINT */
01880         haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
01881 
01882         /* Read HCINT */
01883         hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
01884 
01885         /* Read HCCHAR */
01886         hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01887 
01888         /* Clear HCINT */
01889         DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
01890 
01891         /* Clear HAINT */
01892         DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
01893 
01894         /* Clear GINTSTS */
01895         DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
01896 
01897         /* Read GINTSTS */
01898         gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01899 
01900 //      usleep(100000);
01901 //      mdelay(100);
01902         dwc_mdelay(1);
01903 
01904         /*
01905          * Send handshake packet
01906          */
01907 
01908         /* Read HAINT */
01909         haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
01910 
01911         /* Read HCINT */
01912         hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
01913 
01914         /* Read HCCHAR */
01915         hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01916 
01917         /* Clear HCINT */
01918         DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
01919 
01920         /* Clear HAINT */
01921         DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
01922 
01923         /* Clear GINTSTS */
01924         DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
01925 
01926         /* Read GINTSTS */
01927         gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01928 
01929         /* Make sure channel is disabled */
01930         hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01931         if (hcchar.b.chen) {
01932                 hcchar.b.chdis = 1;
01933                 hcchar.b.chen = 1;
01934                 DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
01935                 //sleep(1);
01936                 dwc_mdelay(1000);
01937 
01938                 /* Read GINTSTS */
01939                 gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01940 
01941                 /* Read HAINT */
01942                 haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
01943 
01944                 /* Read HCINT */
01945                 hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
01946 
01947                 /* Read HCCHAR */
01948                 hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01949 
01950                 /* Clear HCINT */
01951                 DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
01952 
01953                 /* Clear HAINT */
01954                 DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
01955 
01956                 /* Clear GINTSTS */
01957                 DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
01958 
01959                 hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01960         }
01961 
01962         /* Set HCTSIZ */
01963         hctsiz.d32 = 0;
01964         hctsiz.b.xfersize = 0;
01965         hctsiz.b.pktcnt = 1;
01966         hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
01967         DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
01968 
01969         /* Set HCCHAR */
01970         hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01971         hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
01972         hcchar.b.epdir = 0;
01973         hcchar.b.epnum = 0;
01974         hcchar.b.mps = 8;
01975         hcchar.b.chen = 1;
01976         DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
01977 
01978         gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01979 
01980         /* Wait for host channel interrupt */
01981         do {
01982                 gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
01983         } while (gintsts.b.hcintr == 0);
01984 
01985         /* Disable HCINTs */
01986         DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000);
01987 
01988         /* Disable HAINTs */
01989         DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000);
01990 
01991         /* Read HAINT */
01992         haint.d32 = DWC_READ_REG32(&hc_global_regs->haint);
01993 
01994         /* Read HCINT */
01995         hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
01996 
01997         /* Read HCCHAR */
01998         hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
01999 
02000         /* Clear HCINT */
02001         DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
02002 
02003         /* Clear HAINT */
02004         DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32);
02005 
02006         /* Clear GINTSTS */
02007         DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32);
02008 
02009         /* Read GINTSTS */
02010         gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts);
02011 }
02012 #endif
02013 
02015 int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
02016                             uint16_t typeReq,
02017                             uint16_t wValue,
02018                             uint16_t wIndex, uint8_t * buf, uint16_t wLength)
02019 {
02020         int retval = 0;
02021 
02022         dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
02023         usb_hub_descriptor_t *hub_desc;
02024         hprt0_data_t hprt0 = {.d32 = 0 };
02025 
02026         uint32_t port_status;
02027 
02028         switch (typeReq) {
02029         case UCR_CLEAR_HUB_FEATURE:
02030                 DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
02031                             "ClearHubFeature 0x%x\n", wValue);
02032                 switch (wValue) {
02033                 case UHF_C_HUB_LOCAL_POWER:
02034                 case UHF_C_HUB_OVER_CURRENT:
02035                         /* Nothing required here */
02036                         break;
02037                 default:
02038                         retval = -DWC_E_INVALID;
02039                         DWC_ERROR("DWC OTG HCD - "
02040                                   "ClearHubFeature request %xh unknown\n",
02041                                   wValue);
02042                 }
02043                 break;
02044         case UCR_CLEAR_PORT_FEATURE:
02045 #ifdef CONFIG_USB_DWC_OTG_LPM
02046                 if (wValue != UHF_PORT_L1)
02047 #endif
02048                         if (!wIndex || wIndex > 1)
02049                                 goto error;
02050 
02051                 switch (wValue) {
02052                 case UHF_PORT_ENABLE:
02053                         DWC_DEBUGPL(DBG_ANY, "DWC OTG HCD HUB CONTROL - "
02054                                     "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
02055                         hprt0.d32 = dwc_otg_read_hprt0(core_if);
02056                         hprt0.b.prtena = 1;
02057                         DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
02058                         break;
02059                 case UHF_PORT_SUSPEND:
02060                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
02061                                     "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
02062 
02063                         if (core_if->power_down == 2) {
02064                                 dwc_otg_host_hibernation_restore(core_if, 0, 0);
02065                         } else {
02066                                 DWC_WRITE_REG32(core_if->pcgcctl, 0);
02067                                 dwc_mdelay(5);
02068 
02069                                 hprt0.d32 = dwc_otg_read_hprt0(core_if);
02070                                 hprt0.b.prtres = 1;
02071                                 DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
02072                                 hprt0.b.prtsusp = 0;
02073                                 /* Clear Resume bit */
02074                                 dwc_mdelay(100);
02075                                 hprt0.b.prtres = 0;
02076                                 DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
02077                         }
02078                         break;
02079 #ifdef CONFIG_USB_DWC_OTG_LPM
02080                 case UHF_PORT_L1:
02081                         {
02082                                 pcgcctl_data_t pcgcctl = {.d32 = 0 };
02083                                 glpmcfg_data_t lpmcfg = {.d32 = 0 };
02084 
02085                                 lpmcfg.d32 =
02086                                     DWC_READ_REG32(&core_if->
02087                                                    core_global_regs->glpmcfg);
02088                                 lpmcfg.b.en_utmi_sleep = 0;
02089                                 lpmcfg.b.hird_thres &= (~(1 << 4));
02090                                 lpmcfg.b.prt_sleep_sts = 1;
02091                                 DWC_WRITE_REG32(&core_if->
02092                                                 core_global_regs->glpmcfg,
02093                                                 lpmcfg.d32);
02094 
02095                                 /* Clear Enbl_L1Gating bit. */
02096                                 pcgcctl.b.enbl_sleep_gating = 1;
02097                                 DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
02098                                                  0);
02099 
02100                                 dwc_mdelay(5);
02101 
02102                                 hprt0.d32 = dwc_otg_read_hprt0(core_if);
02103                                 hprt0.b.prtres = 1;
02104                                 DWC_WRITE_REG32(core_if->host_if->hprt0,
02105                                                 hprt0.d32);
02106                                 /* This bit will be cleared in wakeup interrupt handle */
02107                                 break;
02108                         }
02109 #endif
02110                 case UHF_PORT_POWER:
02111                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
02112                                     "ClearPortFeature USB_PORT_FEAT_POWER\n");
02113                         hprt0.d32 = dwc_otg_read_hprt0(core_if);
02114                         hprt0.b.prtpwr = 0;
02115                         DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
02116                         break;
02117                 case UHF_PORT_INDICATOR:
02118                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
02119                                     "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
02120                         /* Port inidicator not supported */
02121                         break;
02122                 case UHF_C_PORT_CONNECTION:
02123                         /* Clears drivers internal connect status change
02124                          * flag */
02125                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
02126                                     "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
02127                         dwc_otg_hcd->flags.b.port_connect_status_change = 0;
02128                         break;
02129                 case UHF_C_PORT_RESET:
02130                         /* Clears the driver's internal Port Reset Change
02131                          * flag */
02132                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
02133                                     "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
02134                         dwc_otg_hcd->flags.b.port_reset_change = 0;
02135                         break;
02136                 case UHF_C_PORT_ENABLE:
02137                         /* Clears the driver's internal Port
02138                          * Enable/Disable Change flag */
02139                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
02140                                     "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
02141                         dwc_otg_hcd->flags.b.port_enable_change = 0;
02142                         break;
02143                 case UHF_C_PORT_SUSPEND:
02144                         /* Clears the driver's internal Port Suspend
02145                          * Change flag, which is set when resume signaling on
02146                          * the host port is complete */
02147                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
02148                                     "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
02149                         dwc_otg_hcd->flags.b.port_suspend_change = 0;
02150                         break;
02151 #ifdef CONFIG_USB_DWC_OTG_LPM
02152                 case UHF_C_PORT_L1:
02153                         dwc_otg_hcd->flags.b.port_l1_change = 0;
02154                         break;
02155 #endif
02156                 case UHF_C_PORT_OVER_CURRENT:
02157                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
02158                                     "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
02159                         dwc_otg_hcd->flags.b.port_over_current_change = 0;
02160                         break;
02161                 default:
02162                         retval = -DWC_E_INVALID;
02163                         DWC_ERROR("DWC OTG HCD - "
02164                                   "ClearPortFeature request %xh "
02165                                   "unknown or unsupported\n", wValue);
02166                 }
02167                 break;
02168         case UCR_GET_HUB_DESCRIPTOR:
02169                 DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
02170                             "GetHubDescriptor\n");
02171                 hub_desc = (usb_hub_descriptor_t *) buf;
02172                 hub_desc->bDescLength = 9;
02173                 hub_desc->bDescriptorType = 0x29;
02174                 hub_desc->bNbrPorts = 1;
02175                 USETW(hub_desc->wHubCharacteristics, 0x08);
02176                 hub_desc->bPwrOn2PwrGood = 1;
02177                 hub_desc->bHubContrCurrent = 0;
02178                 hub_desc->DeviceRemovable[0] = 0;
02179                 hub_desc->DeviceRemovable[1] = 0xff;
02180                 break;
02181         case UCR_GET_HUB_STATUS:
02182                 DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
02183                             "GetHubStatus\n");
02184                 DWC_MEMSET(buf, 0, 4);
02185                 break;
02186         case UCR_GET_PORT_STATUS:
02187                 DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
02188                             "GetPortStatus wIndex = 0x%04x FLAGS=0x%08x\n",
02189                             wIndex, dwc_otg_hcd->flags.d32);
02190                 if (!wIndex || wIndex > 1)
02191                         goto error;
02192 
02193                 port_status = 0;
02194 
02195                 if (dwc_otg_hcd->flags.b.port_connect_status_change)
02196                         port_status |= (1 << UHF_C_PORT_CONNECTION);
02197 
02198                 if (dwc_otg_hcd->flags.b.port_enable_change)
02199                         port_status |= (1 << UHF_C_PORT_ENABLE);
02200 
02201                 if (dwc_otg_hcd->flags.b.port_suspend_change)
02202                         port_status |= (1 << UHF_C_PORT_SUSPEND);
02203 
02204                 if (dwc_otg_hcd->flags.b.port_l1_change)
02205                         port_status |= (1 << UHF_C_PORT_L1);
02206 
02207                 if (dwc_otg_hcd->flags.b.port_reset_change) {
02208                         port_status |= (1 << UHF_C_PORT_RESET);
02209                 }
02210 
02211                 if (dwc_otg_hcd->flags.b.port_over_current_change) {
02212                         DWC_WARN("Overcurrent change detected\n");
02213                         port_status |= (1 << UHF_C_PORT_OVER_CURRENT);
02214                 }
02215 
02216                 if (!dwc_otg_hcd->flags.b.port_connect_status) {
02217                         /*
02218                          * The port is disconnected, which means the core is
02219                          * either in device mode or it soon will be. Just
02220                          * return 0's for the remainder of the port status
02221                          * since the port register can't be read if the core
02222                          * is in device mode.
02223                          */
02224                         *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
02225                         break;
02226                 }
02227 
02228                 hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
02229                 DWC_DEBUGPL(DBG_HCDV, "  HPRT0: 0x%08x\n", hprt0.d32);
02230 
02231                 if (hprt0.b.prtconnsts)
02232                         port_status |= (1 << UHF_PORT_CONNECTION);
02233 
02234                 if (hprt0.b.prtena)
02235                         port_status |= (1 << UHF_PORT_ENABLE);
02236 
02237                 if (hprt0.b.prtsusp)
02238                         port_status |= (1 << UHF_PORT_SUSPEND);
02239 
02240                 if (hprt0.b.prtovrcurract)
02241                         port_status |= (1 << UHF_PORT_OVER_CURRENT);
02242 
02243                 if (hprt0.b.prtrst)
02244                         port_status |= (1 << UHF_PORT_RESET);
02245 
02246                 if (hprt0.b.prtpwr)
02247                         port_status |= (1 << UHF_PORT_POWER);
02248 
02249                 if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
02250                         port_status |= (1 << UHF_PORT_HIGH_SPEED);
02251                 else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
02252                         port_status |= (1 << UHF_PORT_LOW_SPEED);
02253 
02254                 if (hprt0.b.prttstctl)
02255                         port_status |= (1 << UHF_PORT_TEST);
02256                 if (dwc_otg_get_lpm_portsleepstatus(dwc_otg_hcd->core_if)) {
02257                         port_status |= (1 << UHF_PORT_L1);
02258                 }
02259                 /*
02260                    For Synopsys HW emulation of Power down wkup_control asserts the 
02261                    hreset_n and prst_n on suspned. This causes the HPRT0 to be zero. 
02262                    We intentionally tell the software that port is in L2Suspend state. 
02263                    Only for STE.
02264                 */
02265                 if ((core_if->power_down == 2)
02266                     && (core_if->hibernation_suspend == 1)) {
02267                         port_status |= (1 << UHF_PORT_SUSPEND);
02268                 }
02269                 /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
02270 
02271                 *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
02272 
02273                 break;
02274         case UCR_SET_HUB_FEATURE:
02275                 DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
02276                             "SetHubFeature\n");
02277                 /* No HUB features supported */
02278                 break;
02279         case UCR_SET_PORT_FEATURE:
02280                 if (wValue != UHF_PORT_TEST && (!wIndex || wIndex > 1))
02281                         goto error;
02282 
02283                 if (!dwc_otg_hcd->flags.b.port_connect_status) {
02284                         /*
02285                          * The port is disconnected, which means the core is
02286                          * either in device mode or it soon will be. Just
02287                          * return without doing anything since the port
02288                          * register can't be written if the core is in device
02289                          * mode.
02290                          */
02291                         break;
02292                 }
02293 
02294                 switch (wValue) {
02295                 case UHF_PORT_SUSPEND:
02296                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
02297                                     "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
02298                         if (dwc_otg_hcd_otg_port(dwc_otg_hcd) != wIndex) {
02299                                 goto error;
02300                         }
02301                         if (core_if->power_down == 2) {
02302                                 int timeout = 300;
02303                                 dwc_irqflags_t flags;
02304                                 pcgcctl_data_t pcgcctl = {.d32 = 0 };
02305                                 gpwrdn_data_t gpwrdn = {.d32 = 0 };
02306                                 gusbcfg_data_t gusbcfg = {.d32 = 0 };
02307 #ifdef DWC_DEV_SRPCAP
02308                                 int32_t otg_cap_param = core_if->core_params->otg_cap;
02309 #endif
02310                                 DWC_PRINTF("Preparing for complete power-off\n");
02311 
02312                                 /* Save registers before hibernation */
02313                                 dwc_otg_save_global_regs(core_if);
02314                                 dwc_otg_save_host_regs(core_if);
02315 
02316                                 hprt0.d32 = dwc_otg_read_hprt0(core_if);
02317                                 hprt0.b.prtsusp = 1;
02318                                 hprt0.b.prtena = 0;
02319                                 DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
02320                                 /* Spin hprt0.b.prtsusp to became 1 */
02321                                 do {
02322                                         hprt0.d32 = dwc_otg_read_hprt0(core_if);
02323                                         if (hprt0.b.prtsusp) {
02324                                                 break;
02325                                         }
02326                                         dwc_mdelay(1);
02327                                 } while (--timeout);
02328                                 if (!timeout) {
02329                                         DWC_WARN("Suspend wasn't genereted\n");
02330                                 }
02331                                 dwc_udelay(10);
02332 
02333                                 /*
02334                                  * We need to disable interrupts to prevent servicing of any IRQ
02335                                  * during going to hibernation
02336                                  */
02337                                 DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
02338                                 core_if->lx_state = DWC_OTG_L2;
02339 #ifdef DWC_DEV_SRPCAP
02340                                 hprt0.d32 = dwc_otg_read_hprt0(core_if);
02341                                 hprt0.b.prtpwr = 0;
02342                                 hprt0.b.prtena = 0;
02343                                 DWC_WRITE_REG32(core_if->host_if->hprt0,
02344                                                 hprt0.d32);
02345 #endif
02346                                 gusbcfg.d32 =
02347                                     DWC_READ_REG32(&core_if->core_global_regs->
02348                                                    gusbcfg);
02349                                 if (gusbcfg.b.ulpi_utmi_sel == 1) {
02350                                         /* ULPI interface */
02351                                         /* Suspend the Phy Clock */
02352                                         pcgcctl.d32 = 0;
02353                                         pcgcctl.b.stoppclk = 1;
02354                                         DWC_MODIFY_REG32(core_if->pcgcctl, 0,
02355                                                          pcgcctl.d32);
02356                                         dwc_udelay(10);
02357                                         gpwrdn.b.pmuactv = 1;
02358                                         DWC_MODIFY_REG32(&core_if->
02359                                                          core_global_regs->
02360                                                          gpwrdn, 0, gpwrdn.d32);
02361                                 } else {
02362                                         /* UTMI+ Interface */
02363                                         gpwrdn.b.pmuactv = 1;
02364                                         DWC_MODIFY_REG32(&core_if->
02365                                                          core_global_regs->
02366                                                          gpwrdn, 0, gpwrdn.d32);
02367                                         dwc_udelay(10);
02368                                         pcgcctl.b.stoppclk = 1;
02369                                         DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
02370                                         dwc_udelay(10);
02371                                 }
02372 #ifdef DWC_DEV_SRPCAP                           
02373                                 gpwrdn.d32 = 0;
02374                                 gpwrdn.b.dis_vbus = 1;
02375                                 DWC_MODIFY_REG32(&core_if->core_global_regs->
02376                                                  gpwrdn, 0, gpwrdn.d32);
02377 #endif
02378                                 gpwrdn.d32 = 0;
02379                                 gpwrdn.b.pmuintsel = 1;
02380                                 DWC_MODIFY_REG32(&core_if->core_global_regs->
02381                                                  gpwrdn, 0, gpwrdn.d32);
02382                                 dwc_udelay(10);
02383 
02384                                 gpwrdn.d32 = 0;
02385 #ifdef DWC_DEV_SRPCAP
02386                                 gpwrdn.b.srp_det_msk = 1;
02387 #endif
02388                                 gpwrdn.b.disconn_det_msk = 1;
02389                                 gpwrdn.b.lnstchng_msk = 1;
02390                                 gpwrdn.b.sts_chngint_msk = 1;
02391                                 DWC_MODIFY_REG32(&core_if->core_global_regs->
02392                                                  gpwrdn, 0, gpwrdn.d32);
02393                                 dwc_udelay(10);
02394 
02395                                 /* Enable Power Down Clamp and all interrupts in GPWRDN */
02396                                 gpwrdn.d32 = 0;
02397                                 gpwrdn.b.pwrdnclmp = 1;
02398                                 DWC_MODIFY_REG32(&core_if->core_global_regs->
02399                                                  gpwrdn, 0, gpwrdn.d32);
02400                                 dwc_udelay(10);
02401 
02402                                 /* Switch off VDD */
02403                                 gpwrdn.d32 = 0;
02404                                 gpwrdn.b.pwrdnswtch = 1;
02405                                 DWC_MODIFY_REG32(&core_if->core_global_regs->
02406                                                  gpwrdn, 0, gpwrdn.d32);
02407 
02408 #ifdef DWC_DEV_SRPCAP
02409                                 if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
02410                                 {
02411                                         core_if->pwron_timer_started = 1;
02412                                         DWC_TIMER_SCHEDULE(core_if->pwron_timer, 6000 /* 6 secs */ );
02413                                 }
02414 #endif
02415                                 /* Save gpwrdn register for further usage if stschng interrupt */
02416                                 core_if->gr_backup->gpwrdn_local =
02417                                                 DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
02418 
02419                                 /* Set flag to indicate that we are in hibernation */
02420                                 core_if->hibernation_suspend = 1;
02421                                 DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock,flags);
02422 
02423                                 DWC_PRINTF("Host hibernation completed\n");
02424                                 // Exit from case statement
02425                                 break;
02426 
02427                         }
02428                         if (dwc_otg_hcd_otg_port(dwc_otg_hcd) == wIndex &&
02429                             dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
02430                                 gotgctl_data_t gotgctl = {.d32 = 0 };
02431                                 gotgctl.b.hstsethnpen = 1;
02432                                 DWC_MODIFY_REG32(&core_if->core_global_regs->
02433                                                  gotgctl, 0, gotgctl.d32);
02434                                 core_if->op_state = A_SUSPEND;
02435                         }
02436                         hprt0.d32 = dwc_otg_read_hprt0(core_if);
02437                         hprt0.b.prtsusp = 1;
02438                         DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
02439                         {
02440                                 dwc_irqflags_t flags;
02441                                 /* Update lx_state */
02442                                 DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
02443                                 core_if->lx_state = DWC_OTG_L2;
02444                                 DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
02445                         }
02446                         /* Suspend the Phy Clock */
02447                         {
02448                                 pcgcctl_data_t pcgcctl = {.d32 = 0 };
02449                                 pcgcctl.b.stoppclk = 1;
02450                                 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
02451                                                  pcgcctl.d32);
02452                                 dwc_udelay(10);
02453                         }
02454 
02455                         /* For HNP the bus must be suspended for at least 200ms. */
02456                         if (dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
02457                                 pcgcctl_data_t pcgcctl = {.d32 = 0 };
02458                                 pcgcctl.b.stoppclk = 1;
02459                 DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
02460                                 dwc_mdelay(200);
02461                         }
02462 
02464 #if 0 //vahrama !!!!!!!!!!!!!!!!!!
02465                         if (core_if->adp_enable) {
02466                                 gotgctl_data_t gotgctl = {.d32 = 0 };
02467                                 gpwrdn_data_t gpwrdn;
02468 
02469                                 while (gotgctl.b.asesvld == 1) {
02470                                         gotgctl.d32 =
02471                                             DWC_READ_REG32(&core_if->
02472                                                            core_global_regs->
02473                                                            gotgctl);
02474                                         dwc_mdelay(100);
02475                                 }
02476 
02477                                 /* Enable Power Down Logic */
02478                                 gpwrdn.d32 = 0;
02479                                 gpwrdn.b.pmuactv = 1;
02480                                 DWC_MODIFY_REG32(&core_if->core_global_regs->
02481                                                  gpwrdn, 0, gpwrdn.d32);
02482 
02483                                 /* Unmask SRP detected interrupt from Power Down Logic */
02484                                 gpwrdn.d32 = 0;
02485                                 gpwrdn.b.srp_det_msk = 1;
02486                                 DWC_MODIFY_REG32(&core_if->core_global_regs->
02487                                                  gpwrdn, 0, gpwrdn.d32);
02488 
02489                                 dwc_otg_adp_probe_start(core_if);
02490                         }
02491 #endif
02492                         break;
02493                 case UHF_PORT_POWER:
02494                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
02495                                     "SetPortFeature - USB_PORT_FEAT_POWER\n");
02496                         hprt0.d32 = dwc_otg_read_hprt0(core_if);
02497                         hprt0.b.prtpwr = 1;
02498                         DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
02499                         break;
02500                 case UHF_PORT_RESET:
02501                         if ((core_if->power_down == 2)
02502                             && (core_if->hibernation_suspend == 1)) {
02503                                 /* If we are going to exit from Hibernated
02504                                  * state via USB RESET.
02505                                  */
02506                                 dwc_otg_host_hibernation_restore(core_if, 0, 1);
02507                         } else {
02508                                 hprt0.d32 = dwc_otg_read_hprt0(core_if);
02509 
02510                                 DWC_DEBUGPL(DBG_HCD,
02511                                             "DWC OTG HCD HUB CONTROL - "
02512                                             "SetPortFeature - USB_PORT_FEAT_RESET\n");
02513                                 {
02514                                         pcgcctl_data_t pcgcctl = {.d32 = 0 };
02515                                         pcgcctl.b.enbl_sleep_gating = 1;
02516                                         pcgcctl.b.stoppclk = 1;
02517                                         DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
02518                                         DWC_WRITE_REG32(core_if->pcgcctl, 0);
02519                                 }
02520 #ifdef CONFIG_USB_DWC_OTG_LPM
02521                                 {
02522                                         glpmcfg_data_t lpmcfg;
02523                                         lpmcfg.d32 =
02524                                                 DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
02525                                         if (lpmcfg.b.prt_sleep_sts) {
02526                                                 lpmcfg.b.en_utmi_sleep = 0;
02527                                                 lpmcfg.b.hird_thres &= (~(1 << 4));
02528                                                 DWC_WRITE_REG32
02529                                                     (&core_if->core_global_regs->glpmcfg,
02530                                                      lpmcfg.d32);
02531                                                 dwc_mdelay(1);
02532                                         }
02533                                 }
02534 #endif
02535                                 hprt0.d32 = dwc_otg_read_hprt0(core_if);
02536                                 /* Clear suspend bit if resetting from suspended state. */
02537                                 hprt0.b.prtsusp = 0;
02538                                 /* When B-Host the Port reset bit is set in
02539                                  * the Start HCD Callback function, so that
02540                                  * the reset is started within 1ms of the HNP
02541                                  * success interrupt. */
02542                                 if (!dwc_otg_hcd_is_b_host(dwc_otg_hcd)) {
02543                                         hprt0.b.prtpwr = 1;
02544                                         hprt0.b.prtrst = 1;
02545                                         DWC_PRINTF("Indeed it is in host mode hprt0 = %08x\n",hprt0.d32);
02546                                         DWC_WRITE_REG32(core_if->host_if->hprt0,
02547                                                         hprt0.d32);
02548                                 }
02549                                 /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
02550                                 dwc_mdelay(60);
02551                                 hprt0.b.prtrst = 0;
02552                                 DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
02553                                 core_if->lx_state = DWC_OTG_L0; /* Now back to the on state */
02554                         }
02555                         break;
02556 #ifdef DWC_HS_ELECT_TST
02557                 case UHF_PORT_TEST:
02558                         {
02559                                 uint32_t t;
02560                                 gintmsk_data_t gintmsk;
02561 
02562                                 t = (wIndex >> 8);      /* MSB wIndex USB */
02563                                 DWC_DEBUGPL(DBG_HCD,
02564                                             "DWC OTG HCD HUB CONTROL - "
02565                                             "SetPortFeature - USB_PORT_FEAT_TEST %d\n",
02566                                             t);
02567                                 DWC_WARN("USB_PORT_FEAT_TEST %d\n", t);
02568                                 if (t < 6) {
02569                                         hprt0.d32 = dwc_otg_read_hprt0(core_if);
02570                                         hprt0.b.prttstctl = t;
02571                                         DWC_WRITE_REG32(core_if->host_if->hprt0,
02572                                                         hprt0.d32);
02573                                 } else {
02574                                         /* Setup global vars with reg addresses (quick and
02575                                          * dirty hack, should be cleaned up)
02576                                          */
02577                                         global_regs = core_if->core_global_regs;
02578                                         hc_global_regs =
02579                                             core_if->host_if->host_global_regs;
02580                                         hc_regs =
02581                                             (dwc_otg_hc_regs_t *) ((char *)
02582                                                                    global_regs +
02583                                                                    0x500);
02584                                         data_fifo =
02585                                             (uint32_t *) ((char *)global_regs +
02586                                                           0x1000);
02587 
02588                                         if (t == 6) {   /* HS_HOST_PORT_SUSPEND_RESUME */
02589                                                 /* Save current interrupt mask */
02590                                                 gintmsk.d32 =
02591                                                     DWC_READ_REG32
02592                                                     (&global_regs->gintmsk);
02593 
02594                                                 /* Disable all interrupts while we muck with
02595                                                  * the hardware directly
02596                                                  */
02597                                                 DWC_WRITE_REG32(&global_regs->gintmsk, 0);
02598 
02599                                                 /* 15 second delay per the test spec */
02600                                                 dwc_mdelay(15000);
02601 
02602                                                 /* Drive suspend on the root port */
02603                                                 hprt0.d32 =
02604                                                     dwc_otg_read_hprt0(core_if);
02605                                                 hprt0.b.prtsusp = 1;
02606                                                 hprt0.b.prtres = 0;
02607                                                 DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
02608 
02609                                                 /* 15 second delay per the test spec */
02610                                                 dwc_mdelay(15000);
02611 
02612                                                 /* Drive resume on the root port */
02613                                                 hprt0.d32 =
02614                                                     dwc_otg_read_hprt0(core_if);
02615                                                 hprt0.b.prtsusp = 0;
02616                                                 hprt0.b.prtres = 1;
02617                                                 DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
02618                                                 dwc_mdelay(100);
02619 
02620                                                 /* Clear the resume bit */
02621                                                 hprt0.b.prtres = 0;
02622                                                 DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
02623 
02624                                                 /* Restore interrupts */
02625                                                 DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
02626                                         } else if (t == 7) {    /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
02627                                                 /* Save current interrupt mask */
02628                                                 gintmsk.d32 =
02629                                                     DWC_READ_REG32
02630                                                     (&global_regs->gintmsk);
02631 
02632                                                 /* Disable all interrupts while we muck with
02633                                                  * the hardware directly
02634                                                  */
02635                                                 DWC_WRITE_REG32(&global_regs->gintmsk, 0);
02636 
02637                                                 /* 15 second delay per the test spec */
02638                                                 dwc_mdelay(15000);
02639 
02640                                                 /* Send the Setup packet */
02641                                                 do_setup();
02642 
02643                                                 /* 15 second delay so nothing else happens for awhile */
02644                                                 dwc_mdelay(15000);
02645 
02646                                                 /* Restore interrupts */
02647                                                 DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
02648                                         } else if (t == 8) {    /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
02649                                                 /* Save current interrupt mask */
02650                                                 gintmsk.d32 =
02651                                                     DWC_READ_REG32
02652                                                     (&global_regs->gintmsk);
02653 
02654                                                 /* Disable all interrupts while we muck with
02655                                                  * the hardware directly
02656                                                  */
02657                                                 DWC_WRITE_REG32(&global_regs->gintmsk, 0);
02658 
02659                                                 /* Send the Setup packet */
02660                                                 do_setup();
02661 
02662                                                 /* 15 second delay so nothing else happens for awhile */
02663                                                 dwc_mdelay(15000);
02664 
02665                                                 /* Send the In and Ack packets */
02666                                                 do_in_ack();
02667 
02668                                                 /* 15 second delay so nothing else happens for awhile */
02669                                                 dwc_mdelay(15000);
02670 
02671                                                 /* Restore interrupts */
02672                                                 DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32);
02673                                         }
02674                                 }
02675                                 break;
02676                         }
02677 #endif /* DWC_HS_ELECT_TST */
02678 
02679                 case UHF_PORT_INDICATOR:
02680                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
02681                                     "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
02682                         /* Not supported */
02683                         break;
02684                 default:
02685                         retval = -DWC_E_INVALID;
02686                         DWC_ERROR("DWC OTG HCD - "
02687                                   "SetPortFeature request %xh "
02688                                   "unknown or unsupported\n", wValue);
02689                         break;
02690                 }
02691                 break;
02692 #ifdef CONFIG_USB_DWC_OTG_LPM
02693         case UCR_SET_AND_TEST_PORT_FEATURE:
02694                 if (wValue != UHF_PORT_L1) {
02695                         goto error;
02696                 }
02697                 {
02698                         int portnum, hird, devaddr, remwake;
02699                         glpmcfg_data_t lpmcfg;
02700                         uint32_t time_usecs;
02701                         gintsts_data_t gintsts;
02702                         gintmsk_data_t gintmsk;
02703 
02704                         if (!dwc_otg_get_param_lpm_enable(core_if)) {
02705                                 goto error;
02706                         }
02707                         if (wValue != UHF_PORT_L1 || wLength != 1) {
02708                                 goto error;
02709                         }
02710                         /* Check if the port currently is in SLEEP state */
02711                         lpmcfg.d32 =
02712                             DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
02713                         if (lpmcfg.b.prt_sleep_sts) {
02714                                 DWC_INFO("Port is already in sleep mode\n");
02715                                 buf[0] = 0;     /* Return success */
02716                                 break;
02717                         }
02718 
02719                         portnum = wIndex & 0xf;
02720                         hird = (wIndex >> 4) & 0xf;
02721                         devaddr = (wIndex >> 8) & 0x7f;
02722                         remwake = (wIndex >> 15);
02723 
02724                         if (portnum != 1) {
02725                                 retval = -DWC_E_INVALID;
02726                                 DWC_WARN
02727                                     ("Wrong port number(%d) in SetandTestPortFeature request\n",
02728                                      portnum);
02729                                 break;
02730                         }
02731 
02732                         DWC_PRINTF
02733                             ("SetandTestPortFeature request: portnum = %d, hird = %d, devaddr = %d, rewake = %d\n",
02734                              portnum, hird, devaddr, remwake);
02735                         /* Disable LPM interrupt */
02736                         gintmsk.d32 = 0;
02737                         gintmsk.b.lpmtranrcvd = 1;
02738                         DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
02739                                          gintmsk.d32, 0);
02740 
02741                         if (dwc_otg_hcd_send_lpm
02742                             (dwc_otg_hcd, devaddr, hird, remwake)) {
02743                                 retval = -DWC_E_INVALID;
02744                                 break;
02745                         }
02746 
02747                         time_usecs = 10 * (lpmcfg.b.retry_count + 1);
02748                         /* We will consider timeout if time_usecs microseconds pass,
02749                          * and we don't receive LPM transaction status.
02750                          * After receiving non-error responce(ACK/NYET/STALL) from device,
02751                          *  core will set lpmtranrcvd bit.
02752                          */
02753                         do {
02754                                 gintsts.d32 =
02755                                     DWC_READ_REG32(&core_if->core_global_regs->gintsts);
02756                                 if (gintsts.b.lpmtranrcvd) {
02757                                         break;
02758                                 }
02759                                 dwc_udelay(1);
02760                         } while (--time_usecs);
02761                         /* lpm_int bit will be cleared in LPM interrupt handler */
02762 
02763                         /* Now fill status
02764                          * 0x00 - Success
02765                          * 0x10 - NYET
02766                          * 0x11 - Timeout
02767                          */
02768                         if (!gintsts.b.lpmtranrcvd) {
02769                                 buf[0] = 0x3;   /* Completion code is Timeout */
02770                                 dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd);
02771                         } else {
02772                                 lpmcfg.d32 =
02773                                     DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
02774                                 if (lpmcfg.b.lpm_resp == 0x3) {
02775                                         /* ACK responce from the device */
02776                                         buf[0] = 0x00;  /* Success */
02777                                 } else if (lpmcfg.b.lpm_resp == 0x2) {
02778                                         /* NYET responce from the device */
02779                                         buf[0] = 0x2;
02780                                 } else {
02781                                         /* Otherwise responce with Timeout */
02782                                         buf[0] = 0x3;
02783                                 }
02784                         }
02785                         DWC_PRINTF("Device responce to LPM trans is %x\n",
02786                                    lpmcfg.b.lpm_resp);
02787                         DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0,
02788                                          gintmsk.d32);
02789 
02790                         break;
02791                 }
02792 #endif /* CONFIG_USB_DWC_OTG_LPM */
02793         default:
02794 error:
02795                 retval = -DWC_E_INVALID;
02796                 DWC_WARN("DWC OTG HCD - "
02797                          "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n",
02798                          typeReq, wIndex, wValue);
02799                 break;
02800         }
02801 
02802         return retval;
02803 }
02804 
02805 #ifdef CONFIG_USB_DWC_OTG_LPM
02806 
02807 int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, uint8_t devaddr)
02808 {
02809         dwc_otg_core_if_t *core_if = hcd->core_if;
02810         dwc_hc_t *hc;
02811         hcchar_data_t hcchar;
02812         gintmsk_data_t gintmsk = {.d32 = 0 };
02813 
02814         if (DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
02815                 DWC_PRINTF("No free channel to select for LPM transaction\n");
02816                 return -1;
02817         }
02818 
02819         hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
02820 
02821         /* Mask host channel interrupts. */
02822         gintmsk.b.hcintr = 1;
02823         DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
02824 
02825         /* Fill fields that core needs for LPM transaction */
02826         hcchar.b.devaddr = devaddr;
02827         hcchar.b.epnum = 0;
02828         hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
02829         hcchar.b.mps = 64;
02830         hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
02831         hcchar.b.epdir = 0;     /* OUT */
02832         DWC_WRITE_REG32(&core_if->host_if->hc_regs[hc->hc_num]->hcchar,
02833                         hcchar.d32);
02834 
02835         /* Remove the host channel from the free list. */
02836         DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
02837 
02838         DWC_PRINTF("hcnum = %d devaddr = %d\n", hc->hc_num, devaddr);
02839 
02840         return hc->hc_num;
02841 }
02842 
02844 void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd)
02845 {
02846         dwc_hc_t *hc;
02847         glpmcfg_data_t lpmcfg;
02848         uint8_t hc_num;
02849 
02850         lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
02851         hc_num = lpmcfg.b.lpm_chan_index;
02852 
02853         hc = hcd->hc_ptr_array[hc_num];
02854 
02855         DWC_PRINTF("Freeing channel %d after LPM\n", hc_num);
02856         /* Return host channel to free list */
02857         DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
02858 }
02859 
02860 int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, uint8_t hird,
02861                          uint8_t bRemoteWake)
02862 {
02863         glpmcfg_data_t lpmcfg;
02864         pcgcctl_data_t pcgcctl = {.d32 = 0 };
02865         int channel;
02866 
02867         channel = dwc_otg_hcd_get_hc_for_lpm_tran(hcd, devaddr);
02868         if (channel < 0) {
02869                 return channel;
02870         }
02871 
02872         pcgcctl.b.enbl_sleep_gating = 1;
02873         DWC_MODIFY_REG32(hcd->core_if->pcgcctl, 0, pcgcctl.d32);
02874 
02875         /* Read LPM config register */
02876         lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg);
02877 
02878         /* Program LPM transaction fields */
02879         lpmcfg.b.rem_wkup_en = bRemoteWake;
02880         lpmcfg.b.hird = hird;
02881         lpmcfg.b.hird_thres = 0x1c;
02882         lpmcfg.b.lpm_chan_index = channel;
02883         lpmcfg.b.en_utmi_sleep = 1;
02884         /* Program LPM config register */
02885         DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
02886 
02887         /* Send LPM transaction */
02888         lpmcfg.b.send_lpm = 1;
02889         DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
02890 
02891         return 0;
02892 }
02893 
02894 #endif /* CONFIG_USB_DWC_OTG_LPM */
02895 
02896 int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port)
02897 {
02898         int retval;
02899 
02900         if (port != 1) {
02901                 return -DWC_E_INVALID;
02902         }
02903 
02904         retval = (hcd->flags.b.port_connect_status_change ||
02905                   hcd->flags.b.port_reset_change ||
02906                   hcd->flags.b.port_enable_change ||
02907                   hcd->flags.b.port_suspend_change ||
02908                   hcd->flags.b.port_over_current_change);
02909 #ifdef DEBUG
02910         if (retval) {
02911                 DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:"
02912                             " Root port status changed\n");
02913                 DWC_DEBUGPL(DBG_HCDV, "  port_connect_status_change: %d\n",
02914                             hcd->flags.b.port_connect_status_change);
02915                 DWC_DEBUGPL(DBG_HCDV, "  port_reset_change: %d\n",
02916                             hcd->flags.b.port_reset_change);
02917                 DWC_DEBUGPL(DBG_HCDV, "  port_enable_change: %d\n",
02918                             hcd->flags.b.port_enable_change);
02919                 DWC_DEBUGPL(DBG_HCDV, "  port_suspend_change: %d\n",
02920                             hcd->flags.b.port_suspend_change);
02921                 DWC_DEBUGPL(DBG_HCDV, "  port_over_current_change: %d\n",
02922                             hcd->flags.b.port_over_current_change);
02923         }
02924 #endif
02925         return retval;
02926 }
02927 
02928 int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * dwc_otg_hcd)
02929 {
02930         hfnum_data_t hfnum;
02931         hfnum.d32 =
02932             DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->
02933                            hfnum);
02934 
02935 #ifdef DEBUG_SOF
02936         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n",
02937                     hfnum.b.frnum);
02938 #endif
02939         return hfnum.b.frnum;
02940 }
02941 
02942 int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
02943                       struct dwc_otg_hcd_function_ops *fops)
02944 {
02945         int retval = 0;
02946 
02947         hcd->fops = fops;
02948         if (!dwc_otg_is_device_mode(hcd->core_if) && 
02949                 (!hcd->core_if->adp_enable || hcd->core_if->adp.adp_started)) {
02950                 dwc_otg_hcd_reinit(hcd);
02951         } else {
02952                 retval = -DWC_E_NO_DEVICE;
02953         }
02954 
02955         return retval;
02956 }
02957 
02958 void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd)
02959 {
02960         return hcd->priv;
02961 }
02962 
02963 void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data)
02964 {
02965         hcd->priv = priv_data;
02966 }
02967 
02968 uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd)
02969 {
02970         return hcd->otg_port;
02971 }
02972 
02973 uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd)
02974 {
02975         uint32_t is_b_host;
02976         if (hcd->core_if->op_state == B_HOST) {
02977                 is_b_host = 1;
02978         } else {
02979                 is_b_host = 0;
02980         }
02981 
02982         return is_b_host;
02983 }
02984 
02985 dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
02986                                          int iso_desc_count, int atomic_alloc)
02987 {
02988         dwc_otg_hcd_urb_t *dwc_otg_urb;
02989         uint32_t size;
02990 
02991         size =
02992             sizeof(*dwc_otg_urb) +
02993             iso_desc_count * sizeof(struct dwc_otg_hcd_iso_packet_desc);
02994         if (atomic_alloc)
02995                 dwc_otg_urb = DWC_ALLOC_ATOMIC(size);
02996         else
02997                 dwc_otg_urb = DWC_ALLOC(size);
02998 
02999         dwc_otg_urb->packet_count = iso_desc_count;
03000 
03001         return dwc_otg_urb;
03002 }
03003 
03004 void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * dwc_otg_urb,
03005                                   uint8_t dev_addr, uint8_t ep_num,
03006                                   uint8_t ep_type, uint8_t ep_dir, uint16_t mps)
03007 {
03008         dwc_otg_hcd_fill_pipe(&dwc_otg_urb->pipe_info, dev_addr, ep_num,
03009                               ep_type, ep_dir, mps);
03010 #if 0
03011         DWC_PRINTF
03012             ("addr = %d, ep_num = %d, ep_dir = 0x%x, ep_type = 0x%x, mps = %d\n",
03013              dev_addr, ep_num, ep_dir, ep_type, mps);
03014 #endif
03015 }
03016 
03017 void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
03018                                 void *urb_handle, void *buf, dwc_dma_t dma,
03019                                 uint32_t buflen, void *setup_packet,
03020                                 dwc_dma_t setup_dma, uint32_t flags,
03021                                 uint16_t interval)
03022 {
03023         dwc_otg_urb->priv = urb_handle;
03024         dwc_otg_urb->buf = buf;
03025         dwc_otg_urb->dma = dma;
03026         dwc_otg_urb->length = buflen;
03027         dwc_otg_urb->setup_packet = setup_packet;
03028         dwc_otg_urb->setup_dma = setup_dma;
03029         dwc_otg_urb->flags = flags;
03030         dwc_otg_urb->interval = interval;
03031         dwc_otg_urb->status = -DWC_E_IN_PROGRESS;
03032 }
03033 
03034 uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb)
03035 {
03036         return dwc_otg_urb->status;
03037 }
03038 
03039 uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * dwc_otg_urb)
03040 {
03041         return dwc_otg_urb->actual_length;
03042 }
03043 
03044 uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * dwc_otg_urb)
03045 {
03046         return dwc_otg_urb->error_count;
03047 }
03048 
03049 void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
03050                                          int desc_num, uint32_t offset,
03051                                          uint32_t length)
03052 {
03053         dwc_otg_urb->iso_descs[desc_num].offset = offset;
03054         dwc_otg_urb->iso_descs[desc_num].length = length;
03055 }
03056 
03057 uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * dwc_otg_urb,
03058                                              int desc_num)
03059 {
03060         return dwc_otg_urb->iso_descs[desc_num].status;
03061 }
03062 
03063 uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
03064                                                     dwc_otg_urb, int desc_num)
03065 {
03066         return dwc_otg_urb->iso_descs[desc_num].actual_length;
03067 }
03068 
03069 int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, void *ep_handle)
03070 {
03071         int allocated = 0;
03072         dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
03073 
03074         if (qh) {
03075                 if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
03076                         allocated = 1;
03077                 }
03078         }
03079         return allocated;
03080 }
03081 
03082 int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle)
03083 {
03084         dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
03085         int freed = 0;
03086         DWC_ASSERT(qh, "qh is not allocated\n");
03087 
03088         if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
03089                 freed = 1;
03090         }
03091 
03092         return freed;
03093 }
03094 
03095 uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, void *ep_handle)
03096 {
03097         dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
03098         DWC_ASSERT(qh, "qh is not allocated\n");
03099         return qh->usecs;
03100 }
03101 
03102 void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd)
03103 {
03104 #ifdef DEBUG
03105         int num_channels;
03106         int i;
03107         gnptxsts_data_t np_tx_status;
03108         hptxsts_data_t p_tx_status;
03109 
03110         num_channels = hcd->core_if->core_params->host_channels;
03111         DWC_PRINTF("\n");
03112         DWC_PRINTF
03113             ("************************************************************\n");
03114         DWC_PRINTF("HCD State:\n");
03115         DWC_PRINTF("  Num channels: %d\n", num_channels);
03116         for (i = 0; i < num_channels; i++) {
03117                 dwc_hc_t *hc = hcd->hc_ptr_array[i];
03118                 DWC_PRINTF("  Channel %d:\n", i);
03119                 DWC_PRINTF("    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
03120                            hc->dev_addr, hc->ep_num, hc->ep_is_in);
03121                 DWC_PRINTF("    speed: %d\n", hc->speed);
03122                 DWC_PRINTF("    ep_type: %d\n", hc->ep_type);
03123                 DWC_PRINTF("    max_packet: %d\n", hc->max_packet);
03124                 DWC_PRINTF("    data_pid_start: %d\n", hc->data_pid_start);
03125                 DWC_PRINTF("    multi_count: %d\n", hc->multi_count);
03126                 DWC_PRINTF("    xfer_started: %d\n", hc->xfer_started);
03127                 DWC_PRINTF("    xfer_buff: %p\n", hc->xfer_buff);
03128                 DWC_PRINTF("    xfer_len: %d\n", hc->xfer_len);
03129                 DWC_PRINTF("    xfer_count: %d\n", hc->xfer_count);
03130                 DWC_PRINTF("    halt_on_queue: %d\n", hc->halt_on_queue);
03131                 DWC_PRINTF("    halt_pending: %d\n", hc->halt_pending);
03132                 DWC_PRINTF("    halt_status: %d\n", hc->halt_status);
03133                 DWC_PRINTF("    do_split: %d\n", hc->do_split);
03134                 DWC_PRINTF("    complete_split: %d\n", hc->complete_split);
03135                 DWC_PRINTF("    hub_addr: %d\n", hc->hub_addr);
03136                 DWC_PRINTF("    port_addr: %d\n", hc->port_addr);
03137                 DWC_PRINTF("    xact_pos: %d\n", hc->xact_pos);
03138                 DWC_PRINTF("    requests: %d\n", hc->requests);
03139                 DWC_PRINTF("    qh: %p\n", hc->qh);
03140                 if (hc->xfer_started) {
03141                         hfnum_data_t hfnum;
03142                         hcchar_data_t hcchar;
03143                         hctsiz_data_t hctsiz;
03144                         hcint_data_t hcint;
03145                         hcintmsk_data_t hcintmsk;
03146                         hfnum.d32 =
03147                             DWC_READ_REG32(&hcd->core_if->
03148                                            host_if->host_global_regs->hfnum);
03149                         hcchar.d32 =
03150                             DWC_READ_REG32(&hcd->core_if->host_if->
03151                                            hc_regs[i]->hcchar);
03152                         hctsiz.d32 =
03153                             DWC_READ_REG32(&hcd->core_if->host_if->
03154                                            hc_regs[i]->hctsiz);
03155                         hcint.d32 =
03156                             DWC_READ_REG32(&hcd->core_if->host_if->
03157                                            hc_regs[i]->hcint);
03158                         hcintmsk.d32 =
03159                             DWC_READ_REG32(&hcd->core_if->host_if->
03160                                            hc_regs[i]->hcintmsk);
03161                         DWC_PRINTF("    hfnum: 0x%08x\n", hfnum.d32);
03162                         DWC_PRINTF("    hcchar: 0x%08x\n", hcchar.d32);
03163                         DWC_PRINTF("    hctsiz: 0x%08x\n", hctsiz.d32);
03164                         DWC_PRINTF("    hcint: 0x%08x\n", hcint.d32);
03165                         DWC_PRINTF("    hcintmsk: 0x%08x\n", hcintmsk.d32);
03166                 }
03167                 if (hc->xfer_started && hc->qh) {
03168                         dwc_otg_qtd_t *qtd;
03169                         dwc_otg_hcd_urb_t *urb;
03170                         
03171                         DWC_CIRCLEQ_FOREACH(qtd, &hc->qh->qtd_list, qtd_list_entry) {
03172                                 if (!qtd->in_process)
03173                                         break;
03174                                 
03175                                 urb = qtd->urb;
03176                         DWC_PRINTF("    URB Info:\n");
03177                         DWC_PRINTF("      qtd: %p, urb: %p\n", qtd, urb);
03178                         if (urb) {
03179                                 DWC_PRINTF("      Dev: %d, EP: %d %s\n",
03180                                            dwc_otg_hcd_get_dev_addr(&urb->
03181                                                                     pipe_info),
03182                                            dwc_otg_hcd_get_ep_num(&urb->
03183                                                                   pipe_info),
03184                                            dwc_otg_hcd_is_pipe_in(&urb->
03185                                                                   pipe_info) ?
03186                                            "IN" : "OUT");
03187                                 DWC_PRINTF("      Max packet size: %d\n",
03188                                            dwc_otg_hcd_get_mps(&urb->
03189                                                                pipe_info));
03190                                 DWC_PRINTF("      transfer_buffer: %p\n",
03191                                            urb->buf);
03192                                 DWC_PRINTF("      transfer_dma: %p\n",
03193                                            (void *)urb->dma);
03194                                 DWC_PRINTF("      transfer_buffer_length: %d\n",
03195                                            urb->length);
03196                                         DWC_PRINTF("      actual_length: %d\n",
03197                                                    urb->actual_length);
03198                                 }
03199                         }
03200                 }
03201         }
03202         DWC_PRINTF("  non_periodic_channels: %d\n", hcd->non_periodic_channels);
03203         DWC_PRINTF("  periodic_channels: %d\n", hcd->periodic_channels);
03204         DWC_PRINTF("  periodic_usecs: %d\n", hcd->periodic_usecs);
03205         np_tx_status.d32 =
03206             DWC_READ_REG32(&hcd->core_if->core_global_regs->gnptxsts);
03207         DWC_PRINTF("  NP Tx Req Queue Space Avail: %d\n",
03208                    np_tx_status.b.nptxqspcavail);
03209         DWC_PRINTF("  NP Tx FIFO Space Avail: %d\n",
03210                    np_tx_status.b.nptxfspcavail);
03211         p_tx_status.d32 =
03212             DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hptxsts);
03213         DWC_PRINTF("  P Tx Req Queue Space Avail: %d\n",
03214                    p_tx_status.b.ptxqspcavail);
03215         DWC_PRINTF("  P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail);
03216         dwc_otg_hcd_dump_frrem(hcd);
03217         dwc_otg_dump_global_registers(hcd->core_if);
03218         dwc_otg_dump_host_registers(hcd->core_if);
03219         DWC_PRINTF
03220             ("************************************************************\n");
03221         DWC_PRINTF("\n");
03222 #endif
03223 }
03224 
03225 #ifdef DEBUG
03226 void dwc_print_setup_data(uint8_t * setup)
03227 {
03228         int i;
03229         if (CHK_DEBUG_LEVEL(DBG_HCD)) {
03230                 DWC_PRINTF("Setup Data = MSB ");
03231                 for (i = 7; i >= 0; i--)
03232                         DWC_PRINTF("%02x ", setup[i]);
03233                 DWC_PRINTF("\n");
03234                 DWC_PRINTF("  bmRequestType Tranfer = %s\n",
03235                            (setup[0] & 0x80) ? "Device-to-Host" :
03236                            "Host-to-Device");
03237                 DWC_PRINTF("  bmRequestType Type = ");
03238                 switch ((setup[0] & 0x60) >> 5) {
03239                 case 0:
03240                         DWC_PRINTF("Standard\n");
03241                         break;
03242                 case 1:
03243                         DWC_PRINTF("Class\n");
03244                         break;
03245                 case 2:
03246                         DWC_PRINTF("Vendor\n");
03247                         break;
03248                 case 3:
03249                         DWC_PRINTF("Reserved\n");
03250                         break;
03251                 }
03252                 DWC_PRINTF("  bmRequestType Recipient = ");
03253                 switch (setup[0] & 0x1f) {
03254                 case 0:
03255                         DWC_PRINTF("Device\n");
03256                         break;
03257                 case 1:
03258                         DWC_PRINTF("Interface\n");
03259                         break;
03260                 case 2:
03261                         DWC_PRINTF("Endpoint\n");
03262                         break;
03263                 case 3:
03264                         DWC_PRINTF("Other\n");
03265                         break;
03266                 default:
03267                         DWC_PRINTF("Reserved\n");
03268                         break;
03269                 }
03270                 DWC_PRINTF("  bRequest = 0x%0x\n", setup[1]);
03271                 DWC_PRINTF("  wValue = 0x%0x\n", *((uint16_t *) & setup[2]));
03272                 DWC_PRINTF("  wIndex = 0x%0x\n", *((uint16_t *) & setup[4]));
03273                 DWC_PRINTF("  wLength = 0x%0x\n\n", *((uint16_t *) & setup[6]));
03274         }
03275 }
03276 #endif
03277 
03278 void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd)
03279 {
03280 #if 0
03281         DWC_PRINTF("Frame remaining at SOF:\n");
03282         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
03283                    hcd->frrem_samples, hcd->frrem_accum,
03284                    (hcd->frrem_samples > 0) ?
03285                    hcd->frrem_accum / hcd->frrem_samples : 0);
03286 
03287         DWC_PRINTF("\n");
03288         DWC_PRINTF("Frame remaining at start_transfer (uframe 7):\n");
03289         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
03290                    hcd->core_if->hfnum_7_samples,
03291                    hcd->core_if->hfnum_7_frrem_accum,
03292                    (hcd->core_if->hfnum_7_samples >
03293                     0) ? hcd->core_if->hfnum_7_frrem_accum /
03294                    hcd->core_if->hfnum_7_samples : 0);
03295         DWC_PRINTF("Frame remaining at start_transfer (uframe 0):\n");
03296         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
03297                    hcd->core_if->hfnum_0_samples,
03298                    hcd->core_if->hfnum_0_frrem_accum,
03299                    (hcd->core_if->hfnum_0_samples >
03300                     0) ? hcd->core_if->hfnum_0_frrem_accum /
03301                    hcd->core_if->hfnum_0_samples : 0);
03302         DWC_PRINTF("Frame remaining at start_transfer (uframe 1-6):\n");
03303         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
03304                    hcd->core_if->hfnum_other_samples,
03305                    hcd->core_if->hfnum_other_frrem_accum,
03306                    (hcd->core_if->hfnum_other_samples >
03307                     0) ? hcd->core_if->hfnum_other_frrem_accum /
03308                    hcd->core_if->hfnum_other_samples : 0);
03309 
03310         DWC_PRINTF("\n");
03311         DWC_PRINTF("Frame remaining at sample point A (uframe 7):\n");
03312         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
03313                    hcd->hfnum_7_samples_a, hcd->hfnum_7_frrem_accum_a,
03314                    (hcd->hfnum_7_samples_a > 0) ?
03315                    hcd->hfnum_7_frrem_accum_a / hcd->hfnum_7_samples_a : 0);
03316         DWC_PRINTF("Frame remaining at sample point A (uframe 0):\n");
03317         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
03318                    hcd->hfnum_0_samples_a, hcd->hfnum_0_frrem_accum_a,
03319                    (hcd->hfnum_0_samples_a > 0) ?
03320                    hcd->hfnum_0_frrem_accum_a / hcd->hfnum_0_samples_a : 0);
03321         DWC_PRINTF("Frame remaining at sample point A (uframe 1-6):\n");
03322         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
03323                    hcd->hfnum_other_samples_a, hcd->hfnum_other_frrem_accum_a,
03324                    (hcd->hfnum_other_samples_a > 0) ?
03325                    hcd->hfnum_other_frrem_accum_a /
03326                    hcd->hfnum_other_samples_a : 0);
03327 
03328         DWC_PRINTF("\n");
03329         DWC_PRINTF("Frame remaining at sample point B (uframe 7):\n");
03330         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
03331                    hcd->hfnum_7_samples_b, hcd->hfnum_7_frrem_accum_b,
03332                    (hcd->hfnum_7_samples_b > 0) ?
03333                    hcd->hfnum_7_frrem_accum_b / hcd->hfnum_7_samples_b : 0);
03334         DWC_PRINTF("Frame remaining at sample point B (uframe 0):\n");
03335         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
03336                    hcd->hfnum_0_samples_b, hcd->hfnum_0_frrem_accum_b,
03337                    (hcd->hfnum_0_samples_b > 0) ?
03338                    hcd->hfnum_0_frrem_accum_b / hcd->hfnum_0_samples_b : 0);
03339         DWC_PRINTF("Frame remaining at sample point B (uframe 1-6):\n");
03340         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
03341                    hcd->hfnum_other_samples_b, hcd->hfnum_other_frrem_accum_b,
03342                    (hcd->hfnum_other_samples_b > 0) ?
03343                    hcd->hfnum_other_frrem_accum_b /
03344                    hcd->hfnum_other_samples_b : 0);
03345 #endif
03346 }
03347 
03348 #endif /* DWC_DEVICE_ONLY */

Generated on Thu Oct 27 03:56:37 2011 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  doxygen 1.3.9.1