/** * flush_qmu - stop qmu and align qmu start ptr t0 current ptr * @args - arg1: ep number, arg2: dir */ void mu3d_hal_flush_qmu(DEV_INT32 Q_num, USB_DIR dir) { TGPD *gpd_current; qmu_printk(K_CRIT, "%s flush QMU %s\n", __func__, ((dir == USB_TX) ? "TX" : "RX")); if (dir == USB_TX) { /*Stop QMU */ mu3d_hal_stop_qmu(Q_num, USB_TX); /*Get TX Queue Current Pointer Register */ gpd_current = (TGPD *) (os_readl(USB_QMU_TQCPR(Q_num))); /*If gpd_current = 0, it means QMU has not yet to execute GPD in QMU. */ if (!gpd_current) { /*Get TX Queue Starting Address Register */ gpd_current = (TGPD *) (os_readl(USB_QMU_TQSAR(Q_num))); } /*Switch physical to virtual address */ qmu_printk(K_CRIT, "gpd_current(P) %p\n", gpd_current); gpd_current = phys_to_virt((unsigned long)gpd_current); qmu_printk(K_CRIT, "gpd_current(V) %p\n", (void *)gpd_current); /*Reset the TX GPD list state */ Tx_gpd_end[Q_num] = Tx_gpd_last[Q_num] = gpd_current; gpd_ptr_align(dir, Q_num, Tx_gpd_end[Q_num]); free_gpd(dir, Q_num); /*FIXME: Do not know why... */ os_writel(USB_QMU_TQSAR(Q_num), virt_to_phys(Tx_gpd_last[Q_num])); qmu_printk(K_ERR, "USB_QMU_TQSAR %x\n", os_readl(USB_QMU_TQSAR(Q_num))); } else if (dir == USB_RX) { /*Stop QMU */ mu3d_hal_stop_qmu(Q_num, USB_RX); /*Get RX Queue Current Pointer Register */ gpd_current = (TGPD *) (os_readl(USB_QMU_RQCPR(Q_num))); if (!gpd_current) { /*Get RX Queue Starting Address Register */ gpd_current = (TGPD *) (os_readl(USB_QMU_RQSAR(Q_num))); } /*Switch physical to virtual address */ qmu_printk(K_CRIT, "gpd_current(P) %p\n", gpd_current); gpd_current = phys_to_virt((unsigned long)gpd_current); qmu_printk(K_CRIT, "gpd_current(V) %p\n", (void *)gpd_current); /*Reset the RX GPD list state */ Rx_gpd_end[Q_num] = Rx_gpd_last[Q_num] = gpd_current; gpd_ptr_align(dir, Q_num, Rx_gpd_end[Q_num]); free_gpd(dir, Q_num); /*FIXME: Do not know why... */ os_writel(USB_QMU_RQSAR(Q_num), virt_to_phys(Rx_gpd_end[Q_num])); qmu_printk(K_ERR, "USB_QMU_RQSAR %x\n", os_readl(USB_QMU_RQSAR(Q_num))); } }
/** * mu3d_hal_init_qmu - initialize qmu * */ void mu3d_hal_init_qmu(void) { DEV_UINT32 i; DEV_UINT32 QCR = 0; /* Initialize QMU Tx/Rx start address. */ for (i = 1; i <= MAX_QMU_EP; i++) { os_printk(K_DEBUG, "==EP[%d]==Start addr RXQ=0x%08x, TXQ=0x%08x\n", i, mu3d_hal_gpd_virt_to_phys(Rx_gpd_head[i], USB_RX, i), mu3d_hal_gpd_virt_to_phys(Tx_gpd_head[i], USB_TX, i)); QCR |= QMU_RX_EN(i); QCR |= QMU_TX_EN(i); os_writel(USB_QMU_RQSAR(i), mu3d_hal_gpd_virt_to_phys(Rx_gpd_head[i], USB_RX, i)); os_writel(USB_QMU_TQSAR(i), mu3d_hal_gpd_virt_to_phys(Tx_gpd_head[i], USB_TX, i)); Tx_gpd_end[i] = Tx_gpd_last[i] = Tx_gpd_head[i]; Rx_gpd_end[i] = Rx_gpd_last[i] = Rx_gpd_head[i]; gpd_ptr_align(USB_TX, i, Tx_gpd_end[i]); gpd_ptr_align(USB_RX, i, Rx_gpd_end[i]); } /* Enable QMU Tx/Rx. */ os_writel(U3D_QGCSR, QCR); os_writel(U3D_QIESR0, QCR); /* Enable QMU interrupt. */ os_writel(U3D_QIESR1, TXQ_EMPTY_IESR | TXQ_CSERR_IESR | TXQ_LENERR_IESR | RXQ_EMPTY_IESR | RXQ_CSERR_IESR | RXQ_LENERR_IESR | RXQ_ZLPERR_IESR); os_writel(U3D_EPIESR, EP0ISR); }
/* When receiving RXQ done interrupt, qmu_interrupt calls this function. 1. Traverse GPD/BD data structures to count actual transferred length. 2. Set the done flag to notify rxstate_qmu() to report status to upper gadget driver. ported from proc_qmu_rx() from test driver. caller:qmu_interrupt after getting QMU done interrupt and TX is raised */ void qmu_done_rx(struct musb *musb, u8 ep_num, unsigned long flags) { TGPD *gpd = Rx_gpd_last[ep_num]; TGPD *gpd_current = (TGPD *) (os_readl(USB_QMU_RQCPR(ep_num))); struct musb_ep *musb_ep = &musb->endpoints[ep_num].ep_out; struct usb_request *request = NULL; struct musb_request *req; /* trying to give_back the request to gadget driver. */ req = next_request(musb_ep); if (!req) { qmu_printk(K_ERR, "[RXD]" "%s Cannot get next request of %d, " "but QMU has done.\n", __func__, ep_num); return; } else { request = &req->request; } /*Transfer PHY addr got from QMU register to VIR addr */ gpd_current = phys_to_virt((unsigned long)gpd_current); qmu_printk(K_DEBUG, "[RXD]" "%s EP%d, Last=%p, Current=%p, End=%p\n", __func__, ep_num, gpd, gpd_current, Rx_gpd_end[ep_num]); /*gpd_current should at least point to the next GPD to the previous last one. */ if (gpd == gpd_current) { qmu_printk(K_ERR, "[RXD][ERROR]" "%s gpd(%p) == gpd_current(%p)\n", __func__, gpd, gpd_current); qmu_printk(K_ERR, "[RXD][ERROR]" "EP%d RQCSR=%x, RQSAR=%x, RQCPR=%x, RQLDPR=%x\n", ep_num, os_readl(USB_QMU_RQCSR(ep_num)), os_readl(USB_QMU_RQSAR(ep_num)), os_readl(USB_QMU_RQCPR(ep_num)), os_readl(USB_QMU_RQLDPR(ep_num))); qmu_printk(K_ERR, "[RXD][ERROR]" "QCR0=%x, QCR1=%x, QCR2=%x, QCR3=%x, " "QGCSR=%x\n", os_readl(U3D_QCR0), os_readl(U3D_QCR1), os_readl(U3D_QCR2), os_readl(U3D_QCR3), os_readl(U3D_QGCSR)); qmu_printk(K_INFO, "[RXD][ERROR]" "HWO=%d, Next_GPD=%x ,DataBufLen=%d, " "DataBuf=%x, RecvLen=%d, Endpoint=%d\n", (DEV_UINT32) TGPD_GET_FLAG(gpd), (DEV_UINT32) TGPD_GET_NEXT(gpd), (DEV_UINT32) TGPD_GET_DataBUF_LEN(gpd), (DEV_UINT32) TGPD_GET_DATA(gpd), (DEV_UINT32) TGPD_GET_BUF_LEN(gpd), (DEV_UINT32) TGPD_GET_EPaddr(gpd)); return; } spin_unlock_irqrestore(&musb->lock, flags); /* invalidate GPD data in CPU */ dma_sync_single_for_cpu(musb->controller, virt_to_phys(gpd), sizeof(TGPD), DMA_FROM_DEVICE); spin_lock_irqsave(&musb->lock, flags); if (!gpd || !gpd_current) { qmu_printk(K_ERR, "[RXD][ERROR]" "%s EP%d, gpd=%p, gpd_current=%p, ishwo=%d, \ rx_gpd_last=%p, RQCPR=0x%x\n", __func__, ep_num, gpd, gpd_current, ((gpd == NULL) ? 999 : TGPD_IS_FLAGS_HWO(gpd)), Rx_gpd_last[ep_num], os_readl(USB_QMU_RQCPR(ep_num))); return; }
/* When receiving RXQ done interrupt, qmu_interrupt calls this function. 1. Traverse GPD/BD data structures to count actual transferred length. 2. Set the done flag to notify rxstate_qmu() to report status to upper gadget driver. ported from proc_qmu_rx() from test driver. caller:qmu_interrupt after getting QMU done interrupt and TX is raised */ void qmu_done_rx(struct musb *musb, u8 ep_num, unsigned long flags) { TGPD* gpd = Rx_gpd_last[ep_num]; TGPD* gpd_current = (TGPD*)(uintptr_t)(os_readl(USB_QMU_RQCPR(ep_num))); //QMU GPD address --> CPU DMA address struct musb_ep *musb_ep = &musb->endpoints[ep_num].ep_out; struct usb_request *request = NULL; struct musb_request *req; //trying to give_back the request to gadget driver. req = next_request(musb_ep); if (!req) { qmu_printk(K_ERR, "[RXD]""%s Cannot get next request of %d, " "but QMU has done.\n", __func__, ep_num); return; } else { request = &req->request; } /*Transfer PHY addr got from QMU register to VIR addr*/ gpd_current = gpd_phys_to_virt(gpd_current, USB_RX, ep_num); qmu_printk(K_DEBUG, "[RXD]""%s EP%d, Last=%p, Current=%p, End=%p\n", __func__, ep_num, gpd, gpd_current, Rx_gpd_end[ep_num]); /*gpd_current should at least point to the next GPD to the previous last one.*/ if (gpd == gpd_current) { qmu_printk(K_ERR, "[RXD][ERROR]""%s gpd(%p) == gpd_current(%p)\n", __func__, gpd, \ gpd_current); qmu_printk(K_ERR, "[RXD][ERROR]""EP%d RQCSR=%x, RQSAR=%x, RQCPR=%x, RQLDPR=%x\n", ep_num, os_readl(USB_QMU_RQCSR(ep_num)), os_readl(USB_QMU_RQSAR(ep_num)), os_readl(USB_QMU_RQCPR(ep_num)), os_readl(USB_QMU_RQLDPR(ep_num))); qmu_printk(K_ERR, "[RXD][ERROR]""QCR0=%x, QCR1=%x, QCR2=%x, QCR3=%x, " "QGCSR=%x\n", os_readl(U3D_QCR0), os_readl(U3D_QCR1), os_readl(U3D_QCR2), \ os_readl(U3D_QCR3), os_readl(U3D_QGCSR)); qmu_printk(K_INFO,"[RXD][ERROR]""HWO=%d, Next_GPD=%lx ,DataBufLen=%d, " "DataBuf=%lx, RecvLen=%d, Endpoint=%d\n", (u32)TGPD_GET_FLAG(gpd), (uintptr_t)TGPD_GET_NEXT(gpd), (u32)TGPD_GET_DataBUF_LEN(gpd), (uintptr_t)TGPD_GET_DATA(gpd), (u32)TGPD_GET_BUF_LEN(gpd), (u32)TGPD_GET_EPaddr(gpd)); return; } if(!gpd || !gpd_current) { qmu_printk(K_ERR, "[RXD][ERROR]""%s EP%d, gpd=%p, gpd_current=%p, ishwo=%d, \ rx_gpd_last=%p, RQCPR=0x%x\n", __func__, ep_num, gpd, gpd_current, ((gpd==NULL) ? 999 : TGPD_IS_FLAGS_HWO(gpd)), Rx_gpd_last[ep_num], os_readl(USB_QMU_RQCPR(ep_num))); return; }
void mu3d_hal_flush_qmu(DEV_INT32 Q_num, USB_DIR dir) { TGPD* gpd_current; struct USB_REQ *req = mu3d_hal_get_req(Q_num, dir); os_printk(K_CRIT,"%s flush QMU %s\n", __func__, ((dir==USB_TX)?"TX":"RX")); if (dir == USB_TX) { /*Stop QMU*/ mu3d_hal_stop_qmu(Q_num, USB_TX); /*Get TX Queue Current Pointer Register*/ gpd_current = (TGPD*)(uintptr_t)(os_readl(USB_QMU_TQCPR(Q_num))); //QMU GPD address --> CPU DMA address /*If gpd_current = 0, it means QMU has not yet to execute GPD in QMU.*/ if(!gpd_current){ /*Get TX Queue Starting Address Register*/ gpd_current = (TGPD*)(uintptr_t)(os_readl(USB_QMU_TQSAR(Q_num))); //QMU GPD address --> CPU DMA address } /*Switch physical to virtual address*/ os_printk(K_CRIT,"gpd_current(P) %p\n", gpd_current); gpd_current = gpd_phys_to_virt(gpd_current, USB_TX, Q_num); os_printk(K_CRIT,"gpd_current(V) %p\n", gpd_current); /*Reset the TX GPD list state*/ Tx_gpd_end[Q_num] = Tx_gpd_last[Q_num] = gpd_current; gpd_ptr_align(dir,Q_num,Tx_gpd_end[Q_num]); free_gpd(dir,Q_num); /*FIXME: Do not know why...*/ os_writel(USB_QMU_TQSAR(Q_num), mu3d_hal_gpd_virt_to_phys(Tx_gpd_last[Q_num], USB_TX, Q_num)); os_printk(K_ERR,"USB_QMU_TQSAR %x\n", os_readl(USB_QMU_TQSAR(Q_num))); req->complete=true; //os_printk(K_ERR,"TxQ %d Flush Now!\n", Q_num); } else if(dir == USB_RX) { /*Stop QMU*/ mu3d_hal_stop_qmu(Q_num, USB_RX); /*Get RX Queue Current Pointer Register*/ gpd_current = (TGPD*)(uintptr_t)(os_readl(USB_QMU_RQCPR(Q_num))); //QMU GPD address --> CPU DMA address if(!gpd_current){ /*Get RX Queue Starting Address Register*/ gpd_current = (TGPD*)(uintptr_t)(os_readl(USB_QMU_RQSAR(Q_num))); //QMU GPD address --> CPU DMA address } /*Switch physical to virtual address*/ os_printk(K_CRIT,"gpd_current(P) %p\n", gpd_current); gpd_current = gpd_phys_to_virt(gpd_current,USB_RX,Q_num); os_printk(K_CRIT,"gpd_current(V) %p\n", gpd_current); /*Reset the RX GPD list state*/ Rx_gpd_end[Q_num] = Rx_gpd_last[Q_num] = gpd_current; gpd_ptr_align(dir,Q_num,Rx_gpd_end[Q_num]); free_gpd(dir,Q_num); /*FIXME: Do not know why...*/ os_writel(USB_QMU_RQSAR(Q_num), mu3d_hal_gpd_virt_to_phys(Rx_gpd_end[Q_num], USB_RX, Q_num)); os_printk(K_ERR,"USB_QMU_RQSAR %x\n", os_readl(USB_QMU_RQSAR(Q_num))); req->complete=true; //os_printk(K_ERR,"RxQ %d Flush Now!\n", Q_num); } }
/** * flush_qmu - stop qmu and align qmu start ptr t0 current ptr * @args - arg1: ep number, arg2: dir */ void _ex_mu3d_hal_flush_qmu(DEV_INT32 Q_num, USB_DIR dir) { TGPD* gpd_current; qmu_printk(K_CRIT, "%s flush QMU %s-EP[%d]\n", __func__, ((dir==USB_TX)?"TX":"RX"), Q_num); if (dir == USB_TX) { /*Stop QMU*/ mu3d_hal_stop_qmu(Q_num, USB_TX); /*Get TX Queue Current Pointer Register*/ gpd_current = (TGPD*)(uintptr_t)(os_readl(USB_QMU_TQCPR(Q_num))); //QMU GPD address --> CPU DMA address /*If gpd_current = 0, it means QMU has not yet to execute GPD in QMU.*/ if(!gpd_current){ /*Get TX Queue Starting Address Register*/ gpd_current = (TGPD*)(uintptr_t)(os_readl(USB_QMU_TQSAR(Q_num))); //QMU GPD address --> CPU DMA address } /* * Even if the GPD pointer got from SAR is corrupted. We should use the head of GPD list. * We know that Tx_gpd_head[Q_num] is always correct. */ if(!gpd_current) { gpd_current = Tx_gpd_head[Q_num]; qmu_printk(K_CRIT, "gpd is null, so use the head of GPD list %p\n", gpd_current); } else { /*Switch physical to virtual address*/ qmu_printk(K_CRIT, "gpd_current(P) %p\n", gpd_current); gpd_current = gpd_phys_to_virt((void *)gpd_current,USB_TX, Q_num); qmu_printk(K_CRIT, "gpd_current(V) %p\n", (void *)gpd_current); } /*Reset the TX GPD list state*/ Tx_gpd_end[Q_num] = Tx_gpd_last[Q_num] = gpd_current; gpd_ptr_align(dir,Q_num,Tx_gpd_end[Q_num]); free_gpd(dir,Q_num); /*FIXME: Do not know why...*/ os_writel(USB_QMU_TQSAR(Q_num), mu3d_hal_gpd_virt_to_phys(Tx_gpd_last[Q_num], USB_TX, Q_num)); qmu_printk(K_ERR, "USB_QMU_TQSAR %x\n", os_readl(USB_QMU_TQSAR(Q_num))); } else if(dir == USB_RX) { /*Stop QMU*/ mu3d_hal_stop_qmu(Q_num, USB_RX); /*Get RX Queue Current Pointer Register*/ gpd_current = (TGPD*)(uintptr_t)(os_readl(USB_QMU_RQCPR(Q_num))); //QMU GPD address --> CPU DMA address if(!gpd_current){ /*Get RX Queue Starting Address Register*/ gpd_current = (TGPD*)(uintptr_t)(os_readl(USB_QMU_RQSAR(Q_num))); //QMU GPD address --> CPU DMA address } /* * Even if the GPD pointer got from SAR is corrupted. We should use the head of GPD list. * We know that Rx_gpd_head[Q_num] is always correct. */ if(!gpd_current) { gpd_current = Rx_gpd_head[Q_num]; qmu_printk(K_CRIT, "gpd is null, so use the head of GPD list %p\n", gpd_current); } else { /*Switch physical to virtual address*/ qmu_printk(K_CRIT, "gpd_current(P) %p\n", gpd_current); gpd_current = gpd_phys_to_virt((void *)gpd_current, USB_RX, Q_num); qmu_printk(K_CRIT, "gpd_current(V) %p\n", (void *)gpd_current); } /*Reset the RX GPD list state*/ Rx_gpd_end[Q_num] = Rx_gpd_last[Q_num] = gpd_current; gpd_ptr_align(dir,Q_num,Rx_gpd_end[Q_num]); free_gpd(dir,Q_num); /*FIXME: Do not know why...*/ os_writel(USB_QMU_RQSAR(Q_num), mu3d_hal_gpd_virt_to_phys(Rx_gpd_end[Q_num], USB_RX, Q_num)); qmu_printk(K_ERR,"USB_QMU_RQSAR %x\n", os_readl(USB_QMU_RQSAR(Q_num))); } }