/** * mu3d_hal_resume_qmu - resume qmu function * @args - arg1: ep number, arg2: dir */ void mu3d_hal_resume_qmu(DEV_INT32 q_num, USB_DIR dir) { #if defined(USB_RISC_CACHE_ENABLED) os_flushinvalidateDcache(); #endif if (dir == USB_TX) { os_writel(USB_QMU_TQCSR(q_num), QMU_Q_RESUME); if (!os_readl(USB_QMU_TQCSR(q_num))) { os_printk(K_DEBUG, "%s QMU_TQCSR[%d]=%x\n", __func__, q_num, os_readl(USB_QMU_TQCSR(q_num))); os_writel(USB_QMU_TQCSR(q_num), QMU_Q_RESUME); } } else if (dir == USB_RX) { os_writel(USB_QMU_RQCSR(q_num), QMU_Q_RESUME); if (!os_readl(USB_QMU_RQCSR(q_num))) { os_printk(K_DEBUG, "%s QMU_RQCSR[%d]=%x\n", __func__, q_num, os_readl(USB_QMU_RQCSR(q_num))); os_writel(USB_QMU_RQCSR(q_num), QMU_Q_RESUME); } } else { os_printk(K_INFO, "%s wrong direction!!!\n", __func__); BUG_ON(1); } }
static irqreturn_t generic_interrupt(int irq, void *__hci) { unsigned long flags; irqreturn_t retval = IRQ_HANDLED; struct musb *musb = __hci; u32 dwL1Value = 0; u32 dwIntrUsbValue = 0; u32 dwDmaIntrValue = 0; u32 dwIntrEPValue = 0; u16 wIntrTxValue = 0; u16 wIntrRxValue = 0; u32 wIntrQMUValue = 0; u32 wIntrQMUDoneValue = 0; u32 dwLtssmValue = 0; u32 dwLinkIntValue = 0; #ifdef SUPPORT_OTG u32 dwOtgIntValue = 0; #endif spin_lock_irqsave(&musb->lock, flags); dwL1Value = os_readl(U3D_LV1ISR) & os_readl(U3D_LV1IER); if (dwL1Value & EP_CTRL_INTR) { u32 dwRxEpDataerrVal = os_readl(U3D_USB2_RX_EP_DATAERR_INTR); if (dwRxEpDataerrVal != 0) { /* Write 1 clear*/ os_writel(U3D_USB2_RX_EP_DATAERR_INTR, dwRxEpDataerrVal); os_printk(K_INFO, "===L1[%x] RxDataErr[%x]\n", dwL1Value, (dwRxEpDataerrVal>>USB2_RX_EP_DATAERR_INTR_EN_OFST && dwRxEpDataerrVal)); }
/* 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; }
static inline void mtu3d_u2_common_intr_handler(u32 dwIntrUsbValue) { if (dwIntrUsbValue & DISCONN_INTR) { mu3d_hal_pdn_ip_port(1, 0, 1, 1); os_printk(K_NOTICE, "[U2 DISCONN_INTR] Set SOFT_CONN=0\n"); os_clrmsk(U3D_POWER_MANAGEMENT, SOFT_CONN); /*TODO-J: ADD musb_g_disconnect(musb);??*/ } if (dwIntrUsbValue & LPM_INTR) { os_printk(K_NOTICE, "[U2 LPM interrupt]\n"); if (!((os_readl(U3D_POWER_MANAGEMENT) & LPM_HRWE))) { mu3d_hal_pdn_ip_port(0, 0, 0, 1); } } if (dwIntrUsbValue & LPM_RESUME_INTR) { if (!(os_readl(U3D_POWER_MANAGEMENT) & LPM_HRWE)) { mu3d_hal_pdn_ip_port(1, 0, 0, 1); os_writel(U3D_USB20_MISC_CONTROL, os_readl(U3D_USB20_MISC_CONTROL) | LPM_U3_ACK_EN); } } if(dwIntrUsbValue & SUSPEND_INTR) { os_printk(K_NOTICE, "[U2 SUSPEND_INTR]\n"); mu3d_hal_pdn_ip_port(0, 0, 0, 1); } if (dwIntrUsbValue & RESUME_INTR) { os_printk(K_NOTICE,"[U2 RESUME_INTR]\n"); mu3d_hal_pdn_ip_port(1, 0, 0, 1); } if (dwIntrUsbValue & RESET_INTR) { os_printk(K_NOTICE,"[U2 RESET_INTR]\n"); } }
/** * mu3d_hal_stop_qmu - stop qmu function (after qmu stop, fifo should be flushed) * @args - arg1: ep number, arg2: dir */ void mu3d_hal_stop_qmu(DEV_INT32 q_num, USB_DIR dir) { if (dir == USB_TX) { if (!(os_readl(USB_QMU_TQCSR(q_num)) & (QMU_Q_ACTIVE))) { qmu_printk(K_DEBUG, "Tx%d inActive Now!\n", q_num); return; } os_writel(USB_QMU_TQCSR(q_num), QMU_Q_STOP); while ((os_readl(USB_QMU_TQCSR(q_num)) & (QMU_Q_ACTIVE))); qmu_printk(K_CRIT, "Tx%d stop Now!\n", q_num); } else if (dir == USB_RX) { if (!(os_readl(USB_QMU_RQCSR(q_num)) & QMU_Q_ACTIVE)) { qmu_printk(K_DEBUG, "Rx%d inActive Now!\n", q_num); return; } os_writel(USB_QMU_RQCSR(q_num), QMU_Q_STOP); while ((os_readl(USB_QMU_RQCSR(q_num)) & (QMU_Q_ACTIVE))); qmu_printk(K_CRIT, "Rx%d stop now!\n", q_num); } }
/** * mu3d_hal_resume_qmu - resume qmu function * @args - arg1: ep number, arg2: dir */ void mu3d_hal_resume_qmu(DEV_INT32 q_num, USB_DIR dir) { if (dir == USB_TX) { /* qmu_printk(K_DEBUG, "%s EP%d CSR=%x, CPR=%x\n", __func__, q_num, os_readl(USB_QMU_TQCSR(q_num)), os_readl(USB_QMU_TQCPR(q_num))); */ os_writel(USB_QMU_TQCSR(q_num), QMU_Q_RESUME); if (!os_readl(USB_QMU_TQCSR(q_num))) { qmu_printk(K_WARNIN, "[ERROR]" "%s TQCSR[%d]=%x\n", __func__, q_num, os_readl(USB_QMU_TQCSR(q_num))); os_writel(USB_QMU_TQCSR(q_num), QMU_Q_RESUME); qmu_printk(K_WARNIN, "[ERROR]" "%s TQCSR[%d]=%x\n", __func__, q_num, os_readl(USB_QMU_TQCSR(q_num))); } } else if (dir == USB_RX) { os_writel(USB_QMU_RQCSR(q_num), QMU_Q_RESUME); if (!os_readl(USB_QMU_RQCSR(q_num))) { qmu_printk(K_WARNIN, "[ERROR]" "%s RQCSR[%d]=%x\n", __func__, q_num, os_readl(USB_QMU_RQCSR(q_num))); os_writel(USB_QMU_RQCSR(q_num), QMU_Q_RESUME); qmu_printk(K_WARNIN, "[ERROR]" "%s RQCSR[%d]=%x\n", __func__, q_num, os_readl(USB_QMU_RQCSR(q_num))); } } else { qmu_printk(K_ERR, "%s wrong direction!!!\n", __func__); BUG_ON(1); } }
/** * mu3d_hal_stop_qmu - stop qmu function (after qmu stop, fifo should be flushed) * @args - arg1: ep number, arg2: dir */ void mu3d_hal_stop_qmu(DEV_INT32 q_num, USB_DIR dir) { if (dir == USB_TX) { if(!(os_readl(USB_QMU_TQCSR(q_num)) & (QMU_Q_ACTIVE))){ qmu_printk(K_CRIT, "Tx%d inActive Now!\n", q_num); return; } os_writel(USB_QMU_TQCSR(q_num), QMU_Q_STOP); mb(); if(wait_for_value(USB_QMU_TQCSR(q_num), QMU_Q_ACTIVE, 0, 10, 100) == RET_SUCCESS) qmu_printk(K_CRIT, "Tx%d stop Now! CSR=0x%x\n", q_num, os_readl(USB_QMU_TQCSR(q_num))); else { qmu_printk(K_CRIT, "Tx%d UNSTOPABLE!! CSR=0x%x\n", q_num, os_readl(USB_QMU_TQCSR(q_num))); WARN_ON(1); } } else if(dir == USB_RX) { if(!(os_readl(USB_QMU_RQCSR(q_num)) & QMU_Q_ACTIVE)){ qmu_printk(K_CRIT, "Rx%d inActive Now!\n", q_num); return; } os_writel(USB_QMU_RQCSR(q_num), QMU_Q_STOP); mb(); if(wait_for_value(USB_QMU_RQCSR(q_num), QMU_Q_ACTIVE, 0, 10, 100) == RET_SUCCESS) qmu_printk(K_CRIT, "Rx%d stop Now! CSR=0x%x\n", q_num, os_readl(USB_QMU_RQCSR(q_num))); else { qmu_printk(K_CRIT, "Rx%d UNSTOPABLE!! CSR=0x%x\n", q_num, os_readl(USB_QMU_RQCSR(q_num))); WARN_ON(1); } } }
DEV_INT32 wait_until_true(DEV_INT32 addr, DEV_INT32 msk, DEV_INT32 value, DEV_INT32 ms_intvl, DEV_INT32 count) { DEV_UINT32 i; for (i = 0; i < count; i++) { if ((os_readl(addr) & msk) == value) return RET_SUCCESS; os_ms_sleep(ms_intvl); } return RET_FAIL; }
/** * 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))); } }
static inline void mtu3d_u2_common_intr_handler(u32 dwIntrUsbValue) { if (dwIntrUsbValue & DISCONN_INTR) { mu3d_hal_pdn_ip_port(1, 0, 1, 1); os_printk(K_NOTICE, "[U2 DISCONN_INTR] Set SOFT_CONN=0\n"); os_clrmsk(U3D_POWER_MANAGEMENT, SOFT_CONN); /*TODO-J: ADD musb_g_disconnect(musb);??*/ } if (dwIntrUsbValue & LPM_INTR) { u32 rmwake ; rmwake = os_readl(U3D_POWER_MANAGEMENT); os_printk(K_NOTICE, "[U2 LPM interrupt] last rmwake is 0x%x\n", rmwake & LPM_RWP); if (!((os_readl(U3D_POWER_MANAGEMENT) & LPM_HRWE))) { mu3d_hal_pdn_ip_port(0, 0, 0, 1); } #ifdef CONFIG_USBIF_COMPLIANCE // SW word around for USBIF test with Fresco FL1100 with LPM L1C enabling #if 0 if (rmwake & LPM_RWP){ os_writel(U3D_USB20_MISC_CONTROL, os_readl(U3D_USB20_MISC_CONTROL) | LPM_U3_ACK_EN); os_writel(U3D_POWER_MANAGEMENT, os_readl(U3D_POWER_MANAGEMENT) | RESUME); } #endif #endif } if (dwIntrUsbValue & LPM_RESUME_INTR) { if (!(os_readl(U3D_POWER_MANAGEMENT) & LPM_HRWE)) { mu3d_hal_pdn_ip_port(1, 0, 0, 1); os_writel(U3D_USB20_MISC_CONTROL, os_readl(U3D_USB20_MISC_CONTROL) | LPM_U3_ACK_EN); } } if(dwIntrUsbValue & SUSPEND_INTR) { os_printk(K_NOTICE, "[U2 SUSPEND_INTR]\n"); mu3d_hal_pdn_ip_port(0, 0, 0, 1); } if (dwIntrUsbValue & RESUME_INTR) { os_printk(K_NOTICE,"[U2 RESUME_INTR]\n"); mu3d_hal_pdn_ip_port(1, 0, 0, 1); } if (dwIntrUsbValue & RESET_INTR) { os_printk(K_NOTICE,"[U2 RESET_INTR]\n"); } }
/** * 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))); } }
static inline void mtu3d_u3_ltssm_intr_handler(struct musb *musb, u32 dwLtssmValue) { static u32 soft_conn_num = 0; if (dwLtssmValue & SS_DISABLE_INTR) { os_printk(K_INFO, "LTSSM: SS_DISABLE_INTR [%d] & Set SOFT_CONN=1\n", soft_conn_num++); //enable U2 link. after host reset, HS/FS EP0 configuration is applied in musb_g_reset os_clrmsk(U3D_SSUSB_U2_CTRL_0P, SSUSB_U2_PORT_PDN); os_setmsk(U3D_POWER_MANAGEMENT, SOFT_CONN); } if (dwLtssmValue & ENTER_U0_INTR) { soft_conn_num = 0; //do not apply U3 EP0 setting again, if the speed is already U3 //LTSSM may go to recovery and back to U0 if (musb->g.speed != USB_SPEED_SUPER) { os_printk(K_INFO, "LTSSM: ENTER_U0_INTR %d\n", musb->g.speed); musb_conifg_ep0(musb); } } if (dwLtssmValue & VBUS_FALL_INTR) { os_printk(K_INFO, "LTSSM: VBUS_FALL_INTR\n"); mu3d_hal_pdn_ip_port(1, 1, 1, 1); mu3d_hal_u3dev_dis(); } if (dwLtssmValue & VBUS_RISE_INTR) { os_printk(K_INFO, "LTSSM: VBUS_RISE_INTR\n"); mu3d_hal_u3dev_en(); } if (dwLtssmValue & ENTER_U3_INTR) { os_printk(K_INFO, "LTSSM: ENTER_U3_INTR\n"); mu3d_hal_pdn_ip_port(0, 0, 1, 0); } if (dwLtssmValue & EXIT_U3_INTR) { os_printk(K_INFO, "LTSSM: EXIT_U3_INTR\n"); mu3d_hal_pdn_ip_port(1, 0, 1, 0); } #ifndef POWER_SAVING_MODE if (dwLtssmValue & U3_RESUME_INTR) { os_printk(K_INFO, "LTSSM: RESUME_INTR\n"); mu3d_hal_pdn_ip_port(1, 0, 1, 0); os_writel(U3D_LINK_POWER_CONTROL, os_readl(U3D_LINK_POWER_CONTROL) | UX_EXIT); } #endif /*7.5.12.2 Hot Reset Requirements * 1. A downstream port shall reset its Link Error Count as defined in Section 7.4.2. * 2. A downstream port shall reset its PM timers and the associated U1 and U2 timeout values to zero. * 3. The port Configuration information shall remain unchanged (refer to Section 8.4.6 for details). * 4. The port shall maintain its transmitter specifications defined in Table 6-10. * 5. The port shall maintain its low-impedance receiver termination (RRX-DC) defined in Table 6-13. */ if (dwLtssmValue & HOT_RST_INTR) { DEV_INT32 link_err_cnt; DEV_INT32 timeout_val; os_printk(K_INFO, "LTSSM: HOT_RST_INTR\n"); /* Clear link error count */ link_err_cnt=os_readl(U3D_LINK_ERR_COUNT); os_printk(K_INFO, "LTSSM: link_err_cnt=%x\n", link_err_cnt); os_writel(U3D_LINK_ERR_COUNT, CLR_LINK_ERR_CNT); /* Clear U1 & U2 Enable*/ os_clrmsk(U3D_LINK_POWER_CONTROL, (SW_U1_ACCEPT_ENABLE|SW_U2_ACCEPT_ENABLE)); musb->g.pwr_params.bU1Enabled = 0; musb->g.pwr_params.bU2Enabled = 0; /* Reset U1 & U2 timeout value*/ timeout_val = os_readl(U3D_LINK_UX_INACT_TIMER); os_printk(K_INFO, "LTSSM: timer_val =%x\n", timeout_val); timeout_val &= ~ (U1_INACT_TIMEOUT_VALUE | DEV_U2_INACT_TIMEOUT_VALUE); os_writel(U3D_LINK_UX_INACT_TIMER, timeout_val); } if (dwLtssmValue & SS_INACTIVE_INTR) os_printk(K_INFO, "LTSSM: SS_INACTIVE_INTR\n"); if (dwLtssmValue & RECOVERY_INTR) os_printk(K_DEBUG, "LTSSM: RECOVERY_INTR\n"); /* A completion of a Warm Reset shall result in the following. * 1. A downstream port shall reset its Link Error Count. * 2. Port configuration information of an upstream port shall be reset to default values. Refer to * Sections 8.4.5 and 8.4.6 for details. * 3. The PHY level variables (such as Rx equalization settings) shall be reinitialized or retrained. * 4. The LTSSM of a port shall transition to U0 through RxDetect and Polling. */ if (dwLtssmValue & WARM_RST_INTR) { DEV_INT32 link_err_cnt; os_printk(K_INFO, "LTSSM: WARM_RST_INTR\n"); /* Clear link error count */ link_err_cnt=os_readl(U3D_LINK_ERR_COUNT); os_printk(K_INFO, "LTSSM: link_err_cnt=%x\n", link_err_cnt); os_writel(U3D_LINK_ERR_COUNT, CLR_LINK_ERR_CNT); } if (dwLtssmValue & ENTER_U2_INTR) os_printk(K_DEBUG, "LTSSM: ENTER_U2_INTR\n"); if (dwLtssmValue & ENTER_U1_INTR) os_printk(K_DEBUG, "LTSSM: ENTER_U1_INTR\n"); if (dwLtssmValue & RXDET_SUCCESS_INTR) os_printk(K_INFO, "LTSSM: RXDET_SUCCESS_INTR\n"); }
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); } }
static inline void mtu3d_link_intr_handler(u32 dwLinkIntValue) { u32 dwTemp; dwTemp = os_readl(U3D_DEVICE_CONF) & SSUSB_DEV_SPEED; mu3d_hal_pdn_cg_en(); switch (dwTemp) { case SSUSB_SPEED_FULL: os_printk(K_ALET,"USB Speed = Full Speed\n"); #ifdef CONFIG_PROJECT_PHY /* Comment from CC Chou. * When detecting HS or FS and setting RG_USB20_SW_PLLMODE=1, It is OK to enter LPM L1 with BESL=0. * When disconnecting, set RG_USB20_SW_PLLMODE=0 back. */ os_setmsk(U3D_U2PHYDCR1, (0x1<<E60802_RG_USB20_SW_PLLMODE_OFST)); /*BESLCK = 0 < BESLCK_U3 = 1 < BESLDCK = 15*/ os_writel(U3D_USB20_LPM_PARAMETER, 0x10f0); /* * The default value of LPM_BESL_STALL and LPM_BESLD_STALL are 1. * So Does _NOT_ need to set. */ /*os_setmsk(U3D_POWER_MANAGEMENT, (LPM_BESL_STALL|LPM_BESLD_STALL));*/ #else /*BESLCK = 4 < BESLCK_U3 = 10 < BESLDCK = 15*/ os_writel(U3D_USB20_LPM_PARAMETER, 0xa4f0); os_setmsk(U3D_POWER_MANAGEMENT, (LPM_BESL_STALL|LPM_BESLD_STALL)); #endif break; case SSUSB_SPEED_HIGH: os_printk(K_ALET,"USB Speed = High Speed\n"); #ifdef CONFIG_PROJECT_PHY /* Comment from CC Chou. * When detecting HS or FS and setting RG_USB20_SW_PLLMODE=1, It is OK to enter LPM L1 with BESL=0. * When disconnecting, set RG_USB20_SW_PLLMODE=0 back. */ os_setmsk(U3D_U2PHYDCR1, (0x1<<E60802_RG_USB20_SW_PLLMODE_OFST)); /*BESLCK = 0 < BESLCK_U3 = 1 < BESLDCK = 15*/ os_writel(U3D_USB20_LPM_PARAMETER, 0x10f0); /* * The default value of LPM_BESL_STALL and LPM_BESLD_STALL are 1. * So Does _NOT_ need to set. */ /*os_setmsk(U3D_POWER_MANAGEMENT, (LPM_BESL_STALL|LPM_BESLD_STALL));*/ #else /*BESLCK = 4 < BESLCK_U3 = 10 < BESLDCK = 15*/ os_writel(U3D_USB20_LPM_PARAMETER, 0xa4f0); os_setmsk(U3D_POWER_MANAGEMENT, (LPM_BESL_STALL|LPM_BESLD_STALL)); #endif break; case SSUSB_SPEED_SUPER: os_printk(K_ALET,"USB Speed = Super Speed\n"); break; default: os_printk(K_ALET,"USB Speed = Invalid\n"); break; } }
u32 dwOtgIntValue = 0; #endif spin_lock_irqsave(&musb->lock, flags); dwL1Value = os_readl(U3D_LV1ISR) & os_readl(U3D_LV1IER); if (dwL1Value & EP_CTRL_INTR) { u32 dwRxEpDataerrVal = os_readl(U3D_USB2_RX_EP_DATAERR_INTR); if (dwRxEpDataerrVal != 0) { /* Write 1 clear*/ os_writel(U3D_USB2_RX_EP_DATAERR_INTR, dwRxEpDataerrVal); os_printk(K_INFO, "===L1[%x] RxDataErr[%x]\n", dwL1Value, (dwRxEpDataerrVal>>USB2_RX_EP_DATAERR_INTR_EN_OFST && dwRxEpDataerrVal)); } dwLinkIntValue = os_readl(U3D_DEV_LINK_INTR) & os_readl(U3D_DEV_LINK_INTR_ENABLE); if (dwLinkIntValue != 0) { /* Write 1 clear*/ os_writel(U3D_DEV_LINK_INTR, dwLinkIntValue); os_printk(K_INFO, "===L1[%x] LinkInt[%x]\n", dwL1Value, dwLinkIntValue); } } if (dwL1Value & MAC2_INTR) { dwIntrUsbValue = os_readl(U3D_COMMON_USB_INTR) & os_readl(U3D_COMMON_USB_INTR_ENABLE); /* Write 1 clear*/ os_writel(U3D_COMMON_USB_INTR, dwIntrUsbValue); os_printk(K_INFO, "===L1[%x] U2[%x]\n", dwL1Value, dwIntrUsbValue); } if (dwL1Value & DMA_INTR) {
void os_clearIrq(DEV_UINT32 irq) { os_writel(U3D_LV1IECR, os_readl(U3D_LV1ISR)); }
/* 1. Find the last gpd HW has executed and update Tx_gpd_last[] 2. Set the flag for txstate to know that TX has been completed ported from proc_qmu_tx() from test driver. caller:qmu_interrupt after getting QMU done interrupt and TX is raised */ void qmu_done_tx(struct musb *musb, u8 ep_num, unsigned long flags) { TGPD* gpd = Tx_gpd_last[ep_num]; TGPD* gpd_current = (TGPD*)(uintptr_t)(os_readl(USB_QMU_TQCPR(ep_num))); //QMU GPD address --> CPU DMA address struct musb_ep *musb_ep = &musb->endpoints[ep_num].ep_in; struct usb_request *request = NULL; struct musb_request *req = NULL; /*Transfer PHY addr got from QMU register to VIR addr*/ gpd_current = gpd_phys_to_virt((void *)gpd_current, USB_TX, ep_num); /* gpd or Last gdp_current | | |-> GPD1 --> GPD2 --> GPD3 --> GPD4 --> GPD5 -| |----------------------------------------------| */ qmu_printk(K_DEBUG, "[TXD]""%s EP%d, Last=%p, Current=%p, End=%p\n", __func__, ep_num, gpd, gpd_current, Tx_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, "[TXD]""%s gpd(%p) == gpd_current(%p)\n", __func__, gpd, \ gpd_current); return; } if(TGPD_IS_FLAGS_HWO(gpd)) { qmu_printk(K_DEBUG, "[TXD]""%s HWO=1, CPR=%x\n", __func__, os_readl(USB_QMU_TQCPR(ep_num))); BUG_ON(1); } while (gpd!=gpd_current && !TGPD_IS_FLAGS_HWO(gpd)) { qmu_printk(K_DEBUG, "[TXD]""gpd=%p ->HWO=%d, BPD=%d, Next_GPD=%lx, DataBuffer=%lx, " "BufferLen=%d request=%p\n", gpd, (u32)TGPD_GET_FLAG(gpd), (u32)TGPD_GET_FORMAT(gpd), \ (uintptr_t)TGPD_GET_NEXT(gpd), (uintptr_t)TGPD_GET_DATA(gpd), (u32)TGPD_GET_BUF_LEN(gpd), req); if(!TGPD_GET_NEXT(gpd)) { qmu_printk(K_ERR, "[TXD][ERROR]""Next GPD is null!!\n"); //BUG_ON(1); break; } gpd = TGPD_GET_NEXT(gpd); gpd = gpd_phys_to_virt(gpd, USB_TX, ep_num); /* trying to give_back the request to gadget driver. */ req = next_request(musb_ep); if (!req) { qmu_printk(K_INFO, "[TXD]""%s Cannot get next request of %d, " "but QMU has done.\n", __func__, ep_num); return; } else { request = &req->request; } Tx_gpd_last[ep_num] = gpd; musb_g_giveback(musb_ep, request, 0); req = next_request(musb_ep); if (req != NULL) { request = &req->request; } } if(gpd!=gpd_current && TGPD_IS_FLAGS_HWO(gpd)) { qmu_printk(K_ERR, "[TXD][ERROR]""EP%d TQCSR=%x, TQSAR=%x, TQCPR=%x\n", ep_num, os_readl(USB_QMU_TQCSR(ep_num)), os_readl(USB_QMU_TQSAR(ep_num)), os_readl(USB_QMU_TQCPR(ep_num))); qmu_printk(K_ERR, "[TXD][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_ERR, "[TXD][ERROR]""HWO=%d, BPD=%d, Next_GPD=%lx, DataBuffer=%lx, " "BufferLen=%d, Endpoint=%d\n", (u32)TGPD_GET_FLAG(gpd), \ (u32)TGPD_GET_FORMAT(gpd), (uintptr_t)TGPD_GET_NEXT(gpd), \ (uintptr_t)TGPD_GET_DATA(gpd), (u32)TGPD_GET_BUF_LEN(gpd), \ (u32)TGPD_GET_EPaddr(gpd)); } qmu_printk(K_DEBUG, "[TXD]""%s EP%d, Last=%p, End=%p, complete\n", __func__, ep_num, Tx_gpd_last[ep_num], Tx_gpd_end[ep_num]); if (req != NULL) { if (request->length == 0) { u32 val = 0; qmu_printk(K_DEBUG, "[TXD]""==Send ZLP== %p\n", req); if (wait_for_value_us(USB_END_OFFSET(req->epnum, U3D_TX1CSR0), TX_FIFOEMPTY, TX_FIFOEMPTY, 1, 10) == RET_SUCCESS) qmu_printk(K_DEBUG, "Tx[%d] 0x%x\n", req->epnum, USB_ReadCsr32(U3D_TX1CSR0, req->epnum)); else { qmu_printk(K_CRIT, "Tx[%d] NOT FIFOEMPTY 0x%x\n", req->epnum, USB_ReadCsr32(U3D_TX1CSR0, req->epnum)); return; } /*Disable Tx_DMAREQEN*/ val = USB_ReadCsr32(U3D_TX1CSR0, req->epnum) & ~TX_DMAREQEN; mb(); USB_WriteCsr32(U3D_TX1CSR0, req->epnum, val); val = USB_ReadCsr32(U3D_TX1CSR0, req->epnum) | TX_TXPKTRDY; mb(); USB_WriteCsr32(U3D_TX1CSR0, req->epnum, val); qmu_printk(K_DEBUG, "[TXD]""Giveback ZLP of EP%d, actual:%d, length:%d %p\n", req->epnum, request->actual, request->length, request); musb_g_giveback(musb_ep, request, 0); } } }
/** * mu3d_hal_start_qmu - start qmu function (QMU flow : mu3d_hal_init_qmu ->mu3d_hal_start_qmu -> mu3d_hal_insert_transfer_gpd -> mu3d_hal_resume_qmu) * @args - arg1: ep number, arg2: dir */ void mu3d_hal_start_qmu(DEV_INT32 Q_num, USB_DIR dir) { DEV_UINT32 QCR; DEV_UINT32 txcsr; if (dir == USB_TX) { txcsr = USB_ReadCsr32(U3D_TX1CSR0, Q_num) & 0xFFFEFFFF; USB_WriteCsr32(U3D_TX1CSR0, Q_num, txcsr | TX_DMAREQEN); QCR = os_readl(U3D_QCR0); os_writel(U3D_QCR0, QCR | QMU_TX_CS_EN(Q_num)); #if (TXZLP == HW_MODE) QCR = os_readl(U3D_QCR1); os_writel(U3D_QCR1, QCR & ~QMU_TX_ZLP(Q_num)); QCR = os_readl(U3D_QCR2); os_writel(U3D_QCR2, QCR | QMU_TX_ZLP(Q_num)); #elif (TXZLP == GPD_MODE) QCR = os_readl(U3D_QCR1); os_writel(U3D_QCR1, QCR | QMU_TX_ZLP(Q_num)); #endif os_writel(U3D_QEMIESR, os_readl(U3D_QEMIESR) | QMU_TX_EMPTY(Q_num)); os_writel(U3D_TQERRIESR0, QMU_TX_LEN_ERR(Q_num) | QMU_TX_CS_ERR(Q_num)); qmu_printk(K_INFO, "USB_QMU_TQCSR:0x%08X\n", os_readl(USB_QMU_TQCSR(Q_num))); if (os_readl(USB_QMU_TQCSR(Q_num)) & QMU_Q_ACTIVE) { qmu_printk(K_INFO, "Tx %d Active Now!\n", Q_num); return; } os_writel(USB_QMU_TQCSR(Q_num), QMU_Q_START); qmu_printk(K_INFO, "USB_QMU_TQCSR:0x%08X\n", os_readl(USB_QMU_TQCSR(Q_num))); } else if (dir == USB_RX) { USB_WriteCsr32(U3D_RX1CSR0, Q_num, USB_ReadCsr32(U3D_RX1CSR0, Q_num) | (RX_DMAREQEN)); QCR = os_readl(U3D_QCR0); os_writel(U3D_QCR0, QCR | QMU_RX_CS_EN(Q_num)); #ifdef CFG_RX_ZLP_EN QCR = os_readl(U3D_QCR3); os_writel(U3D_QCR3, QCR | QMU_RX_ZLP(Q_num)); #else QCR = os_readl(U3D_QCR3); os_writel(U3D_QCR3, QCR & ~(QMU_RX_ZLP(Q_num))); #endif #ifdef CFG_RX_COZ_EN QCR = os_readl(U3D_QCR3); os_writel(U3D_QCR3, QCR | QMU_RX_COZ(Q_num)); #else QCR = os_readl(U3D_QCR3); os_writel(U3D_QCR3, QCR & ~(QMU_RX_COZ(Q_num))); #endif os_writel(U3D_QEMIESR, os_readl(U3D_QEMIESR) | QMU_RX_EMPTY(Q_num)); os_writel(U3D_RQERRIESR0, QMU_RX_LEN_ERR(Q_num) | QMU_RX_CS_ERR(Q_num)); os_writel(U3D_RQERRIESR1, QMU_RX_EP_ERR(Q_num) | QMU_RX_ZLP_ERR(Q_num)); qmu_printk(K_INFO, "USB_QMU_RQCSR:0x%08X\n", os_readl(USB_QMU_RQCSR(Q_num))); if (os_readl(USB_QMU_RQCSR(Q_num)) & QMU_Q_ACTIVE) { qmu_printk(K_INFO, "Rx %d Active Now!\n", Q_num); return; } os_writel(USB_QMU_RQCSR(Q_num), QMU_Q_START); qmu_printk(K_INFO, "USB_QMU_RQCSR:0x%08X\n", os_readl(USB_QMU_RQCSR(Q_num))); } #if (CHECKSUM_TYPE == CS_16B) os_writel(U3D_QCR0, os_readl(U3D_QCR0) | CS16B_EN); #else os_writel(U3D_QCR0, os_readl(U3D_QCR0) & ~CS16B_EN); #endif }
PHY_INT32 U3PhyReadReg32(PHY_UINT32 addr) { return os_readl(addr); }
/* 1. Find the last gpd HW has executed and update Tx_gpd_last[] 2. Set the flag for txstate to know that TX has been completed ported from proc_qmu_tx() from test driver. caller:qmu_interrupt after getting QMU done interrupt and TX is raised */ void qmu_done_tx(struct musb *musb, u8 ep_num, unsigned long flags) { TGPD *gpd = Tx_gpd_last[ep_num]; TGPD *gpd_current = (TGPD *) (os_readl(USB_QMU_TQCPR(ep_num))); struct musb_ep *musb_ep = &musb->endpoints[ep_num].ep_in; 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_INFO, "[TXD]" "%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); /* gpd or Last gdp_current | | |-> GPD1 --> GPD2 --> GPD3 --> GPD4 --> GPD5 -| |----------------------------------------------| */ qmu_printk(K_DEBUG, "[TXD]" "%s EP%d, Last=%p, Current=%p, End=%p\n", __func__, ep_num, gpd, gpd_current, Tx_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, "[TXD][ERROR]" "%s gpd(%p) == gpd_current(%p)\n", __func__, gpd, gpd_current); return; } spin_unlock_irqrestore(&musb->lock, flags); /* flush data from device to CPU */ dma_sync_single_for_cpu(musb->controller, virt_to_phys(gpd), sizeof(TGPD), DMA_FROM_DEVICE); spin_lock_irqsave(&musb->lock, flags); if (TGPD_IS_FLAGS_HWO(gpd)) { qmu_printk(K_DEBUG, "[TXD]" "%s HWO=1, CPR=%x\n", __func__, os_readl(USB_QMU_TQCPR(ep_num))); BUG_ON(1); } while (gpd != gpd_current && !TGPD_IS_FLAGS_HWO(gpd)) { qmu_printk(K_DEBUG, "[TXD]" "gpd=%p ->HWO=%d, BPD=%d, Next_GPD=%x, DataBuffer=%x, " "BufferLen=%d request=%p\n", gpd, (u32) TGPD_GET_FLAG(gpd), (u32) TGPD_GET_FORMAT(gpd), (u32) TGPD_GET_NEXT(gpd), (u32) TGPD_GET_DATA(gpd), (u32) TGPD_GET_BUF_LEN(gpd), req); if (!TGPD_GET_NEXT(gpd)) { qmu_printk(K_ERR, "[TXD][ERROR]" "Next GPD is null!!\n"); /* BUG_ON(1); */ break; } gpd = TGPD_GET_NEXT(gpd); spin_unlock_irqrestore(&musb->lock, flags); /*flush data from device to CPU */ dma_sync_single_for_cpu(musb->controller, (dma_addr_t) gpd, sizeof(TGPD), DMA_FROM_DEVICE); spin_lock_irqsave(&musb->lock, flags); gpd = phys_to_virt((unsigned long)gpd); Tx_gpd_last[ep_num] = gpd; musb_g_giveback(musb_ep, request, 0); req = next_request(musb_ep); request = &req->request; } if (gpd != gpd_current && TGPD_IS_FLAGS_HWO(gpd)) { qmu_printk(K_ERR, "[TXD][ERROR]" "EP%d TQCSR=%x, TQSAR=%x, TQCPR=%x\n", ep_num, os_readl(USB_QMU_TQCSR(ep_num)), os_readl(USB_QMU_TQSAR(ep_num)), os_readl(USB_QMU_TQCPR(ep_num))); qmu_printk(K_ERR, "[TXD][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_ERR, "[TXD][ERROR]" "HWO=%d, BPD=%d, Next_GPD=%x, DataBuffer=%x, " "BufferLen=%d, Endpoint=%d\n", (DEV_UINT32) TGPD_GET_FLAG(gpd), (DEV_UINT32) TGPD_GET_FORMAT(gpd), (DEV_UINT32) TGPD_GET_NEXT(gpd), (DEV_UINT32) TGPD_GET_DATA(gpd), (DEV_UINT32) TGPD_GET_BUF_LEN(gpd), (DEV_UINT32) TGPD_GET_EPaddr(gpd)); } qmu_printk(K_DEBUG, "[TXD]" "%s EP%d, Last=%p, End=%p, complete\n", __func__, ep_num, Tx_gpd_last[ep_num], Tx_gpd_end[ep_num]); if (req != NULL) { if (request->length == 0) { qmu_printk(K_DEBUG, "[TXD]" "==Send ZLP== %p\n", req); while (!(USB_ReadCsr32(U3D_TX1CSR0, req->epnum) & TX_FIFOFULL)) { USB_WriteCsr32(U3D_TX1CSR0, req->epnum, USB_ReadCsr32(U3D_TX1CSR0, req->epnum) | TX_TXPKTRDY); break; } qmu_printk(K_DEBUG, "[TXD]" "Giveback ZLP of EP%d, actual:%d, length:%d %p\n", req->epnum, request->actual, request->length, request); musb_g_giveback(musb_ep, request, 0); } } }
/** * mu3d_hal_phy_scan - u3 phy clock phase scan * */ DEV_INT32 mu3d_hal_phy_scan(DEV_INT32 latch_val, DEV_UINT8 driving){ #ifdef CONFIG_U3_PHY_GPIO_SUPPORT DEV_INT32 count,fset_phase_val,recov_cnt,link_error_count,U0_count; DEV_UINT8 phase_val; //DEV_UINT8 driving; /* disable ip power down,disable U2/U3 ip power down. */ mu3d_hal_ssusb_en(); //mu3d_hal_pdn_dis(); u3phy_ops->change_pipe_phase(u3phy, 0, 0); os_writel(U3D_PIPE_LATCH_SELECT, latch_val);//set tx/rx latch sel //driving = 2; u3phy_ops->change_pipe_phase(u3phy, driving, 0); phase_val=0; count=0; fset_phase_val=TRUE; while(TRUE){ if(fset_phase_val){ u3phy_ops->change_pipe_phase(u3phy, driving, phase_val); mu3d_hal_rst_dev(); mdelay(50); os_writel(U3D_USB3_CONFIG, USB3_EN); os_writel(U3D_PIPE_LATCH_SELECT, latch_val);//set tx/rx latch sel fset_phase_val=FALSE; U0_count=0; link_error_count=0; recov_cnt=0; count=0; } mdelay(50); count++; recov_cnt=os_readl(U3D_RECOVERY_COUNT);//read U0 recovery count link_error_count=os_readl(U3D_LINK_ERR_COUNT);//read link error count if((os_readl(U3D_LINK_STATE_MACHINE)<SSM)==STATE_U0_STATE){//enter U0 state U0_count++; } if(U0_count>ENTER_U0_TH){//link up mdelay(1000);//1s recov_cnt=os_readl(U3D_RECOVERY_COUNT); link_error_count=os_readl(U3D_LINK_ERR_COUNT); os_writel(U3D_RECOVERY_COUNT, CLR_RECOV_CNT);//clear recovery count os_writel(U3D_LINK_ERR_COUNT, CLR_LINK_ERR_CNT);//clear link error count printk("[PASS] Link Error Count=%d, Recovery Count=%d, I2C(0x%02x) : [0x%02x], I2C(0x%02x) : [0x%02x], Reg(0x130) : [0x%02x], PhaseDelay[0x%02x], Driving[0x%02x], Latch[0x%02x]\n" , link_error_count, recov_cnt, U3_PHY_I2C_PCLK_DRV_REG,_U3Read_Reg(U3_PHY_I2C_PCLK_DRV_REG), U3_PHY_I2C_PCLK_PHASE_REG,_U3Read_Reg(U3_PHY_I2C_PCLK_PHASE_REG), os_readl(U3D_PIPE_LATCH_SELECT), phase_val, driving, latch_val); phase_val++; fset_phase_val=TRUE; } else if((os_readl(U3D_LINK_STATE_MACHINE)<SSM)==STATE_DISABLE){//link fail printk("[FAIL] STATE_DISABLE, PhaseDelay[0x%02x]\n", phase_val); phase_val++; fset_phase_val=TRUE; } else if(count>MAX_TIMEOUT_COUNT){//link timeout printk("[FAIL] TIMEOUT, PhaseDelay[0x%02x]\n", phase_val); phase_val++; fset_phase_val=TRUE; } if(phase_val>MAX_PHASE_RANGE){ //reset device mu3d_hal_rst_dev(); mdelay(50); /* disable ip power down,disable U2/U3 ip power down. */ mu3d_hal_ssusb_en(); //mu3d_hal_pdn_dis(); mdelay(10); break; } } #endif return 0; }