/**
 * 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);
	}
}
/**
 * init_gpd_list - initialize gpd management list
 * @args - arg1: dir, arg2: ep number, arg3: gpd virtual addr, arg4: gpd ioremap addr, arg5: gpd number
 */
void init_gpd_list(USB_DIR dir, int num, PGPD ptr, PGPD io_ptr, DEV_UINT32 size)
{
	if (dir == USB_RX) {
		Rx_gpd_List[num].pStart = ptr;
		Rx_gpd_List[num].pEnd = (PGPD) ((DEV_UINT8 *) (ptr + size) + AT_GPD_EXT_LEN * size);
		Rx_gpd_Offset[num] = (DEV_UINT32) ptr - (DEV_UINT32) io_ptr;
		ptr++;
		Rx_gpd_List[num].pNext = (PGPD) ((DEV_UINT8 *) ptr + AT_GPD_EXT_LEN);
		qmu_printk(K_INFO, "Rx_gpd_List[%d].pStart=%p, pNext=%p, pEnd=%p\n",
			   num, Rx_gpd_List[num].pStart, Rx_gpd_List[num].pNext,
			   Rx_gpd_List[num].pEnd);
		qmu_printk(K_INFO, "Rx_gpd_Offset[%d]=0x%08X\n", num, Rx_gpd_Offset[num]);
		qmu_printk(K_INFO, "virtual start=%p, end=%p\n", ptr, ptr + size);
		qmu_printk(K_INFO, "dma addr start=%p, end=%p\n", io_ptr, io_ptr + size);
		qmu_printk(K_INFO, "dma addr start=%p, end=%p\n", (void *)virt_to_phys(ptr),
			   (void *)virt_to_phys(ptr + size));
	} else {
		Tx_gpd_List[num].pStart = ptr;
		Tx_gpd_List[num].pEnd = (PGPD) ((DEV_UINT8 *) (ptr + size) + AT_GPD_EXT_LEN * size);
		Tx_gpd_Offset[num] = (DEV_UINT32) ptr - (DEV_UINT32) io_ptr;
		ptr++;
		Tx_gpd_List[num].pNext = (PGPD) ((DEV_UINT8 *) ptr + AT_GPD_EXT_LEN);
		qmu_printk(K_INFO, "Tx_gpd_List[%d].pStart=%p, pNext=%p, pEnd=%p\n",
			   num, Tx_gpd_List[num].pStart, Tx_gpd_List[num].pNext,
			   Tx_gpd_List[num].pEnd);
		qmu_printk(K_INFO, "Tx_gpd_Offset[%d]=0x%08X\n", num, Tx_gpd_Offset[num]);
		qmu_printk(K_INFO, "virtual start=%p, end=%p\n", ptr, ptr + size);
		qmu_printk(K_INFO, "dma addr start=%p, end=%p\n", io_ptr, io_ptr + size);
		qmu_printk(K_INFO, "dma addr start=%p, end=%p\n", (void *)virt_to_phys(ptr),
			   (void *)virt_to_phys(ptr + size));
	}
}
/**
 * mu3d_hal_alloc_qmu_mem - allocate gpd and bd memory for all ep
 *
 */
void mu3d_hal_alloc_qmu_mem(void)
{
	DEV_UINT32 i, size;
	TGPD *ptr, *io_ptr;

	for (i = 1; i <= MAX_QMU_EP; i++) {
		/* Allocate Rx GPD */
		size = (sizeof(TGPD) + AT_GPD_EXT_LEN) * MAX_GPD_NUM;
		ptr = (TGPD *) kmalloc(size, GFP_KERNEL);
		memset(ptr, 0, size);

		io_ptr = (TGPD *) dma_map_single(NULL, ptr, size, DMA_BIDIRECTIONAL);
		init_gpd_list(USB_RX, i, ptr, io_ptr, MAX_GPD_NUM);
		Rx_gpd_end[i] = ptr;
		qmu_printk(K_INFO, "ALLOC RX GPD End [%d] Virtual Mem=%p, DMA addr=%p\n", i,
			   Rx_gpd_end[i], io_ptr);
		TGPD_CLR_FLAGS_HWO(Rx_gpd_end[i]);
		Rx_gpd_head[i] = Rx_gpd_last[i] = Rx_gpd_end[i];
		qmu_printk(K_INFO, "RQSAR[%d]=%p\n", i, (void *)virt_to_phys(Rx_gpd_end[i]));

		/* Allocate Tx GPD */
		size = (sizeof(TGPD) + AT_GPD_EXT_LEN) * MAX_GPD_NUM;
		ptr = (TGPD *) kmalloc(size, GFP_KERNEL);
		memset(ptr, 0, size);

		io_ptr = (TGPD *) dma_map_single(NULL, ptr, size, DMA_BIDIRECTIONAL);
		init_gpd_list(USB_TX, i, ptr, io_ptr, MAX_GPD_NUM);
		Tx_gpd_end[i] = ptr;
		qmu_printk(K_INFO, "ALLOC TX GPD End [%d] Virtual Mem=%p, DMA addr=%p\n", i,
			   Tx_gpd_end[i], io_ptr);
		TGPD_CLR_FLAGS_HWO(Tx_gpd_end[i]);
		Tx_gpd_head[i] = Tx_gpd_last[i] = Tx_gpd_end[i];
		qmu_printk(K_INFO, "TQSAR[%d]=%p\n", i, (void *)virt_to_phys(Tx_gpd_end[i]));
	}
}
/**
 * mu3d_hal_prepare_rx_gpd - prepare rx gpd/bd
 * @args - arg1: gpd address, arg2: data buffer address, arg3: data length, arg4: ep number, arg5: with bd or not, arg6: write hwo bit or not,  arg7: write ioc bit or not
 */
TGPD *mu3d_hal_prepare_rx_gpd(TGPD *gpd, dma_addr_t pBuf, DEV_UINT32 data_len,
			      DEV_UINT8 ep_num, DEV_UINT8 _is_bdp, DEV_UINT8 isHWO,
			      DEV_UINT8 ioc, DEV_UINT8 bps, DEV_UINT32 cMaxPacketSize)
{
	qmu_printk(K_DEBUG, "[RX]" "%s gpd=%p, epnum=%d, len=%d\n", __func__,
		   gpd, ep_num, data_len);

	/*Set actual data point to "DATA Buffer" */
	TGPD_SET_DATA(gpd, pBuf);
	/*Clear "BDP(Buffer Descriptor Present)" flag */
	TGPD_CLR_FORMAT_BDP(gpd);
	/*
	 * Set "Allow Data Buffer Length" =
	 * 0        (If data length > GPD buffer length, use BDs),
	 * data_len (If data length < GPD buffer length, only use GPD)
	 */
	TGPD_SET_DataBUF_LEN(gpd, data_len);

	/*Set "Transferred Data Length" = 0 */
	TGPD_SET_BUF_LEN(gpd, 0);

	/*Default: bps=false */
	TGPD_CLR_FORMAT_BPS(gpd);

	/*Default: ioc=true */
	TGPD_SET_FORMAT_IOC(gpd);

	/*Get the next GPD */
	Rx_gpd_end[ep_num] = get_gpd(USB_RX, ep_num);
	qmu_printk(K_DEBUG, "[RX]" "Rx_gpd_end[%d]=%p gpd=%p\n", ep_num, Rx_gpd_end[ep_num], gpd);

	/* BUG_ON(!check_next_gpd(gpd, Rx_gpd_end[ep_num])); */

	/*Initialize the new GPD */
	memset(Rx_gpd_end[ep_num], 0, sizeof(TGPD) + AT_GPD_EXT_LEN);

	/*Clear "HWO(Hardware Own)" flag */
	TGPD_CLR_FLAGS_HWO(Rx_gpd_end[ep_num]);

	/*Set Next GDP pointer to the next GPD */
	TGPD_SET_NEXT(gpd, virt_to_phys(Rx_gpd_end[ep_num]));

	/*Default: isHWO=true */
	TGPD_SET_CHKSUM(gpd, CHECKSUM_LENGTH);	/*Set GPD Checksum */
	TGPD_SET_FLAGS_HWO(gpd);	/*Set HWO flag */

	/* os_printk(K_DEBUG,"Rx gpd info { HWO %d, Next_GPD %x ,DataBufferLength %d, DataBuffer %x, Recived Len %d, Endpoint %d, TGL %d, ZLP %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), */
	/* (DEV_UINT32)TGPD_GET_TGL(gpd), (DEV_UINT32)TGPD_GET_ZLP(gpd)); */

	/*Flush the data of GPD stuct to device */
	dma_sync_single_for_device(NULL, virt_to_phys(gpd), sizeof(TGPD) + AT_GPD_EXT_LEN,
				   DMA_TO_DEVICE);

	return gpd;
}
/**
 * mu3d_hal_prepare_tx_gpd - prepare tx gpd/bd
 * @args - arg1: gpd address, arg2: data buffer address, arg3: data length, arg4: ep number, arg5: with bd or not, arg6: write hwo bit or not,  arg7: write ioc bit or not
 */
TGPD *mu3d_hal_prepare_tx_gpd(TGPD *gpd, dma_addr_t pBuf, DEV_UINT32 data_len,
			      DEV_UINT8 ep_num, DEV_UINT8 _is_bdp, DEV_UINT8 isHWO,
			      DEV_UINT8 ioc, DEV_UINT8 bps, DEV_UINT8 zlp)
{
	qmu_printk(K_DEBUG, "[TX]" "%s gpd=%p, epnum=%d, len=%d, _is_bdp=%d size(TGPD)=%d\n",
		   __func__, gpd, ep_num, data_len, _is_bdp, sizeof(TGPD));

	/*Set actual data point to "DATA Buffer" */
	TGPD_SET_DATA(gpd, pBuf);
	/*Clear "BDP(Buffer Descriptor Present)" flag */
	TGPD_CLR_FORMAT_BDP(gpd);
	/*
	 * "Data Buffer Length" =
	 * 0        (If data length > GPD buffer length, use BDs),
	 * data_len (If data length < GPD buffer length, only use GPD)
	 */
	TGPD_SET_BUF_LEN(gpd, data_len);

	/*"GPD extension length" = 0. Does not use GPD EXT!! */
	TGPD_SET_EXT_LEN(gpd, 0);

	/*Default: zlp=false, except type=ISOC */
	TGPD_CLR_FORMAT_ZLP(gpd);

	/*Default: bps=false */
	TGPD_CLR_FORMAT_BPS(gpd);

	/*Default: ioc=true */
	TGPD_SET_FORMAT_IOC(gpd);

	/*Get the next GPD */
	Tx_gpd_end[ep_num] = get_gpd(USB_TX, ep_num);
	qmu_printk(K_DEBUG, "[TX]" "Tx_gpd_end[%d]=%p\n", ep_num, Tx_gpd_end[ep_num]);

	/*Initialize the new GPD */
	memset(Tx_gpd_end[ep_num], 0, sizeof(TGPD) + AT_GPD_EXT_LEN);

	/*Clear "HWO(Hardware Own)" flag */
	TGPD_CLR_FLAGS_HWO(Tx_gpd_end[ep_num]);

	/*Set "Next GDP pointer" as the next GPD */
	TGPD_SET_NEXT(gpd, virt_to_phys(Tx_gpd_end[ep_num]));

	/*Default: isHWO=true */
	TGPD_SET_CHKSUM(gpd, CHECKSUM_LENGTH);	/*Set GPD Checksum */
	TGPD_SET_FLAGS_HWO(gpd);	/*Set HWO flag */

	/*Flush the data of GPD stuct to device */
	dma_sync_single_for_device(NULL, virt_to_phys(gpd), sizeof(TGPD) + AT_GPD_EXT_LEN,
				   DMA_TO_DEVICE);

	return gpd;
}
/**
 * mu3d_hal_prepare_tx_gpd - prepare tx gpd/bd
 * @args - arg1: gpd address, arg2: data buffer address, arg3: data length, arg4: ep number, arg5: with bd or not, arg6: write hwo bit or not,  arg7: write ioc bit or not
 */
TGPD* _ex_mu3d_hal_prepare_tx_gpd(TGPD* gpd, dma_addr_t pBuf, DEV_UINT32 data_len,
					DEV_UINT8 ep_num, DEV_UINT8 _is_bdp, DEV_UINT8 isHWO,
					DEV_UINT8 ioc, DEV_UINT8 bps, DEV_UINT8 zlp)
{
	qmu_printk(K_DEBUG, "[TX]""%s gpd=%p, epnum=%d, len=%d, zlp=%d, size(TGPD)=%lld, pBuf=%08lx\n", __func__, \
		gpd, ep_num, data_len, zlp, (u64)sizeof(TGPD), (unsigned long)pBuf);

	/*Set actual data point to "DATA Buffer"*/
	TGPD_SET_DATA(gpd, (unsigned long)pBuf);
	/*Clear "BDP(Buffer Descriptor Present)" flag*/
	TGPD_CLR_FORMAT_BDP(gpd);
	/*
	 * "Data Buffer Length" =
	 * 0        (If data length > GPD buffer length, use BDs),
	 * data_len (If data length < GPD buffer length, only use GPD)
	 */
	TGPD_SET_BUF_LEN(gpd, data_len);

	/*"GPD extension length" = 0. Does not use GPD EXT!!*/
	TGPD_SET_EXT_LEN(gpd, 0);

	if (zlp)
		TGPD_SET_FORMAT_ZLP(gpd);
	else
		TGPD_CLR_FORMAT_ZLP(gpd);

	/*Default: bps=false*/
	TGPD_CLR_FORMAT_BPS(gpd);

	/*Default: ioc=true*/
	TGPD_SET_FORMAT_IOC(gpd);

	/*Get the next GPD*/
	Tx_gpd_end[ep_num] = get_gpd( USB_TX, ep_num);
	qmu_printk(K_DEBUG, "[TX]""Tx_gpd_end[%d]=%p\n", ep_num, Tx_gpd_end[ep_num]);

	/*Initialize the new GPD*/
	memset(Tx_gpd_end[ep_num], 0, sizeof(TGPD)+AT_GPD_EXT_LEN);

	/*Clear "HWO(Hardware Own)" flag*/
	TGPD_CLR_FLAGS_HWO(Tx_gpd_end[ep_num]);

	/*Set "Next GDP pointer" as the next GPD*/
	TGPD_SET_NEXT(gpd, (unsigned long)mu3d_hal_gpd_virt_to_phys(Tx_gpd_end[ep_num], USB_TX, ep_num));

	/*Default: isHWO=true*/
	TGPD_SET_CHKSUM( gpd, CHECKSUM_LENGTH); /*Set GPD Checksum*/
	TGPD_SET_FLAGS_HWO(gpd); /*Set HWO flag*/

	return gpd;
}
void _ex_mu3d_hal_alloc_qmu_mem(struct device *dev)
{
	DEV_UINT32 i, size;
	TGPD *ptr;
	dma_addr_t io_ptr;
	dma_addr_t dma_handle;

	/*TODO: dma_pool_alloc() is an alternative choice
	  once the memory size is a concern
	 */
	for ( i=1; i<=MAX_QMU_EP; i++) {
		/* Allocate Rx GPD */
		size = (sizeof(TGPD) + AT_GPD_EXT_LEN) * MAX_GPD_NUM;
		ptr = (TGPD*)dma_alloc_coherent(dev, size, &dma_handle, GFP_KERNEL);
		memset(ptr, 0 , size);
		Rx_gpd_ioptr[i] = io_ptr = dma_handle ;

		init_gpd_list( USB_RX, i, ptr, io_ptr, MAX_GPD_NUM);
		Rx_gpd_end[i] = ptr;

		qmu_printk(K_INFO, "ALLOC RX GPD End [%d] Virtual Mem=%p, DMA addr=%08llx\n",
			i, Rx_gpd_end[i], (unsigned long long) io_ptr);

		TGPD_CLR_FLAGS_HWO(Rx_gpd_end[i]);
		Rx_gpd_head[i] = Rx_gpd_last[i] = Rx_gpd_end[i];

		qmu_printk(K_INFO, "RQSAR[%d]=%08llx\n", i,
			(unsigned long long) mu3d_hal_gpd_virt_to_phys(Rx_gpd_end[i], USB_RX, i));

		/* Allocate Tx GPD */
		size = (sizeof(TGPD) + AT_GPD_EXT_LEN) * MAX_GPD_NUM;
		ptr = (TGPD*)dma_alloc_coherent(dev, size, &dma_handle, GFP_KERNEL);
		memset(ptr, 0 , size);
		Tx_gpd_ioptr[i] = io_ptr = dma_handle ;

		init_gpd_list( USB_TX, i, ptr, io_ptr, MAX_GPD_NUM);
		Tx_gpd_end[i]= ptr;

		qmu_printk(K_INFO, "ALLOC TX GPD End [%d] Virtual Mem=%p, DMA addr=%08llx\n",
			i, Tx_gpd_end[i], (unsigned long long) io_ptr);

		TGPD_CLR_FLAGS_HWO(Tx_gpd_end[i]);
		Tx_gpd_head[i] = Tx_gpd_last[i] = Tx_gpd_end[i];

		qmu_printk(K_INFO, "TQSAR[%d]=%08llx\n", i,
			(unsigned long long) mu3d_hal_gpd_virt_to_phys(Tx_gpd_end[i], USB_TX, i));
    }
}
/**
 * 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);
}
/**
 * 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)));
	}
}
Example #10
0
static inline int check_next_gpd(TGPD *gpd, TGPD *next_gpd)
{
	if (((u32) next_gpd - (u32) gpd) == 0x40)
		return 1;
	else if (((u32) gpd - (u32) next_gpd) == 0x7c0)
		return 1;
	else {
		qmu_printk(K_ERR, "[RX]" "%p <-> %p\n", gpd, next_gpd);
		return 0;
	}
}
void _ex_mu3d_hal_free_qmu_mem(struct device *dev)
{
	DEV_UINT32 i ;
	DEV_UINT32 size = (sizeof(TGPD) + AT_GPD_EXT_LEN) * MAX_GPD_NUM;

	qmu_printk(K_INFO, "_ex_mu3d_hal_free_qmu_mem +\n");
	/*TODO:dma_free_coherent() is needed
	  if _ex_mu3d_hal_alloc_qmu_mem() would be called more than once
	  */
	for ( i=1; i<=MAX_QMU_EP; i++) {
#if 0
		kfree(Rx_gpd_head[i]) ;
		kfree(Tx_gpd_head[i]) ;
#else
		dma_free_coherent(dev, size, Rx_gpd_head[i], Rx_gpd_ioptr[i]) ;
		dma_free_coherent(dev, size, Tx_gpd_head[i], Tx_gpd_ioptr[i]) ;
#endif
	}
	qmu_printk(K_INFO, "_ex_mu3d_hal_free_qmu_mem -\n");
}
Example #12
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);
	}
}
/**
 * init_gpd_list - initialize gpd management list
 * @args - arg1: dir, arg2: ep number, arg3: gpd virtual addr, arg4: gpd ioremap addr, arg5: gpd number
 */
void init_gpd_list(USB_DIR dir, int num, PGPD ptr, dma_addr_t io_ptr, DEV_UINT32 size)
{
	if (dir == USB_RX) {
		Rx_gpd_List[num].pStart = ptr;
		Rx_gpd_List[num].pEnd = (PGPD)((DEV_UINT8*)(ptr + size) + AT_GPD_EXT_LEN*size);
		rx_gpd_map[num].p_desc = (void *)ptr;
		rx_gpd_map[num].p_desc_dma = io_ptr;
		ptr++;
		Rx_gpd_List[num].pNext = (PGPD)((DEV_UINT8*)ptr + AT_GPD_EXT_LEN);

		qmu_printk(K_INFO, "Rx_gpd_List[%d].pStart=%p, pNext=%p, pEnd=%p\n", \
			num, Rx_gpd_List[num].pStart, Rx_gpd_List[num].pNext, Rx_gpd_List[num].pEnd);

		qmu_printk(K_INFO, "rx_gpd_map[%d] vir=%p dma=%08llx\n", num,
			rx_gpd_map[num].p_desc, (unsigned long long)rx_gpd_map[num].p_desc_dma);

		qmu_printk(K_INFO, "vir=%p, dma=%08llx\n", ptr, (unsigned long long)io_ptr);
	} else {
		Tx_gpd_List[num].pStart = ptr;
	 	Tx_gpd_List[num].pEnd = (PGPD)((DEV_UINT8*)(ptr + size) + AT_GPD_EXT_LEN*size);
		tx_gpd_map[num].p_desc = (void *)ptr;
		tx_gpd_map[num].p_desc_dma = io_ptr;
		ptr++;
	 	Tx_gpd_List[num].pNext = (PGPD)((DEV_UINT8*)ptr + AT_GPD_EXT_LEN);

		qmu_printk(K_INFO, "Tx_gpd_List[%d].pStart=%p, pNext=%p, pEnd=%p\n",
			num, Tx_gpd_List[num].pStart, Tx_gpd_List[num].pNext, Tx_gpd_List[num].pEnd);

		qmu_printk(K_INFO, "tx_gpd_map[%d] vir=%p dma=%08llx\n", num,
			tx_gpd_map[num].p_desc, (unsigned long long)tx_gpd_map[num].p_desc_dma);

		qmu_printk(K_INFO, "vir=%p, dma=%08llx\n", ptr, (unsigned long long)io_ptr);
	}
}
/**
 * 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);
		}
	}
}
Example #15
0
/*
   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;
	}
/**
 * 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);
}
Example #18
0
/*
    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);
		}
	}
}
/*
    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);
		}
	}
}
/**
 * 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)));
	}
}
Example #21
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
}