Пример #1
0
/**
 * 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);
	}
}
/**
 * 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);
		}
	}
}
/**
 * mu3d_hal_init_qmu - initialize qmu
 *
 */
void _ex_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++){
		qmu_printk(K_INFO, "==EP[%d]==Start addr RXQ=0x%08lx, TXQ=0x%08lx\n", i, \
			(uintptr_t)mu3d_hal_gpd_virt_to_phys(Rx_gpd_head[i], USB_RX, i), \
			(uintptr_t)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 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);
}
Пример #4
0
/**
 * 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);
	}
}
Пример #5
0
/**
 * 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)));
	}
}
Пример #6
0
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");
	}

}
Пример #7
0
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));
		}
/**
 * mu3d_hal_restart_qmu - clear toggle(or sequence) number and start qmu
 * @args - arg1: ep number, arg2: dir
 */
void mu3d_hal_restart_qmu(DEV_INT32 q_num,  USB_DIR dir)
{
	DEV_UINT32 ep_rst;

	qmu_printk(K_CRIT, "%s : Reset %s-EP[%d]\n", __func__, ((dir==USB_TX)?"TX":"RX"), q_num);

	if (dir == USB_TX) {
		ep_rst = BIT16<<q_num;
		os_writel(U3D_EP_RST, ep_rst);
		os_ms_delay(1);
		os_writel(U3D_EP_RST, 0);
	} else {
		ep_rst = 1<<q_num;
		os_writel(U3D_EP_RST, ep_rst);
		os_ms_delay(1);
		os_writel(U3D_EP_RST, 0);
	}
	mu3d_hal_start_qmu(q_num, dir);
}
Пример #9
0
/**
 * 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);
	}
}
Пример #10
0
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");
	}

}
Пример #11
0
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;
	}
}
Пример #12
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
}
Пример #13
0
PHY_INT32 U3PhyWriteReg32(PHY_UINT32 addr, PHY_UINT32 data)
{
	os_writel(addr, data);

	return 0;
}
void os_clearIrq(DEV_UINT32 irq)
{
	os_writel(U3D_LV1IECR, os_readl(U3D_LV1ISR));
}
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)));
	}
}
Пример #17
0
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");

}
/**
 * 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)&LTSSM)==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)&LTSSM)==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;
}