Esempio n. 1
0
/**
 * mu3d_hal_init_qmu - initialize qmu
 *
 */
void mu3d_hal_init_qmu(void)
{
	DEV_UINT32 i;
	DEV_UINT32 QCR = 0;

	/* Initialize QMU Tx/Rx start address. */
	for (i = 1; i <= MAX_QMU_EP; i++) {
		os_printk(K_DEBUG, "==EP[%d]==Start addr RXQ=0x%08x, TXQ=0x%08x\n", i,
			  mu3d_hal_gpd_virt_to_phys(Rx_gpd_head[i], USB_RX, i),
			  mu3d_hal_gpd_virt_to_phys(Tx_gpd_head[i], USB_TX, i));
		QCR |= QMU_RX_EN(i);
		QCR |= QMU_TX_EN(i);
		os_writel(USB_QMU_RQSAR(i), mu3d_hal_gpd_virt_to_phys(Rx_gpd_head[i], USB_RX, i));
		os_writel(USB_QMU_TQSAR(i), mu3d_hal_gpd_virt_to_phys(Tx_gpd_head[i], USB_TX, i));
		Tx_gpd_end[i] = Tx_gpd_last[i] = Tx_gpd_head[i];
		Rx_gpd_end[i] = Rx_gpd_last[i] = Rx_gpd_head[i];
		gpd_ptr_align(USB_TX, i, Tx_gpd_end[i]);
		gpd_ptr_align(USB_RX, i, Rx_gpd_end[i]);
	}
	/* Enable QMU Tx/Rx. */
	os_writel(U3D_QGCSR, QCR);
	os_writel(U3D_QIESR0, QCR);
	/* Enable QMU interrupt. */
	os_writel(U3D_QIESR1,
		  TXQ_EMPTY_IESR | TXQ_CSERR_IESR | TXQ_LENERR_IESR | RXQ_EMPTY_IESR |
		  RXQ_CSERR_IESR | RXQ_LENERR_IESR | RXQ_ZLPERR_IESR);
	os_writel(U3D_EPIESR, EP0ISR);
}
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_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* _ex_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, pBuf=%08lx\n", __func__, \
		gpd, ep_num, data_len, (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);
	/*
	 * 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, (unsigned long)mu3d_hal_gpd_virt_to_phys(Rx_gpd_end[ep_num], USB_RX, 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));

	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;
}
Esempio n. 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;

	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 *) (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 */
		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 *) (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 */
		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); */
	}
}
Esempio n. 6
0
/**
 * 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)
{
	DEV_UINT32 offset;
	DEV_INT32 i;
	DEV_INT32 bd_num;
	DEV_UINT32 length;

	TBD *bd_next;
	TBD *bd_head;
	TBD *bd;
	DEV_UINT8 *pBuffer;

	/*If data length is less than the GPD buffer size, just use GPD */
	if (data_len < GPD_BUF_SIZE) {
		_is_bdp = 0;
	}

	os_printk(K_INFO, "%s gpd=%p, epnum=%d, len=%d, _is_bdp=%d, maxp=%d\n", __func__,
		  gpd, ep_num, data_len, _is_bdp, cMaxPacketSize);

	if (!_is_bdp) {
		/*Set actual data point to "DATA Buffer" */
		TGPD_SET_DATA(gpd, pBuf);
		/*Clear "BDP(Buffer Descriptor Present)" flag */
		TGPD_CLR_FORMAT_BDP(gpd);
	} else {
		/*Get the first BD */
		bd_head = (TBD *) get_bd(USB_RX, ep_num);
		os_printk(K_INFO, "bd_head=x%p\n", bd_head);

		bd = bd_head;
		os_memset(bd, 0, sizeof(TBD));

		/*Date length for transfer */
		length = data_len;

		/*Point of data buffer */
		pBuffer = (DEV_UINT8 *) (pBuf);

		/*The size of BD buffer */
		offset = BD_BUF_SIZE;

		/*Count how many BD this transfer need. */
		bd_num = (!(length % offset)) ? (length / offset) : ((length / offset) + 1);

		os_printk(K_INFO, "%s bd_num=%d\n", __func__, bd_num);

		/*Insert data into each BD */
		for (i = 0; i < bd_num; i++) {
			os_printk(K_INFO, "%s bd[%d]=%p\n", __func__, i, bd);
			if (i == (bd_num - 1)) {
				TBD_SET_BUF_LEN(bd, 0);	/*Set "Transferred Data Length" = 0 */

				/*The last one's data buffer lengnth must be precise, or the GPD will never done unless ZLP or short packet. */
				/*"Allow Data Buffer Length" = the rest of data length* */
				length =
				    (!(length % cMaxPacketSize)) ? (length) : ((length /
										cMaxPacketSize) +
									       1) * cMaxPacketSize;
				TBD_SET_DataBUF_LEN(bd, length);

				TBD_SET_DATA(bd, pBuffer);	/*Store the data pointer to "Data Buffer" */

				TBD_SET_FLAGS_EOL(bd);	/*Set "EOL" */
				TBD_SET_NEXT(bd, 0);	/*Set "Next BD pointer" = 0 */
				TBD_SET_CHKSUM(bd, CHECKSUM_LENGTH);	/*Set "BD Checksum" */

				/*Flush the data of BD stuct to device */
				dma_sync_single_for_device(NULL,
							   bd_virt_to_phys(bd, USB_RX, ep_num),
							   sizeof(TBD), DMA_BIDIRECTIONAL);

				break;
			} else {
				TBD_SET_BUF_LEN(bd, 0);	/*Set "Transferred Data Length" = 0 */

				/*"Allow Data Buffer Length" = the MAX BD transfer size */
				TBD_SET_DataBUF_LEN(bd, offset);

				TBD_SET_DATA(bd, pBuffer);	/*Store the data pointer to "Data Buffer" */

				TBD_CLR_FLAGS_EOL(bd);	/*Clear "EOL" */
				/*Get the next BD */
				bd_next = (TBD *) get_bd(USB_RX, ep_num);
				os_memset(bd_next, 0, sizeof(TBD));

				/*Set "Next BD pointer" as the next BD */
				TBD_SET_NEXT(bd, bd_virt_to_phys(bd_next, USB_RX, ep_num));
				TBD_SET_CHKSUM(bd, CHECKSUM_LENGTH);	/*Set BD Checksum */

				/*Flush the data of BD stuct to device */
				dma_sync_single_for_device(NULL,
							   bd_virt_to_phys(bd, USB_RX, ep_num),
							   sizeof(TBD), DMA_BIDIRECTIONAL);

				/*Calculate the left data length */
				length -= offset;

				/*Move to pointer of buffer */
				pBuffer += offset;

				/*Move to next BD */
				bd = bd_next;
			}
		}

		/*Set the BD pointer into "BD Pointer" at GPD */
		TGPD_SET_DATA(gpd, bd_virt_to_phys(bd_head, USB_RX, ep_num));

		/*Set "BDP(Buffer Descriptor Present)" flag */
		TGPD_SET_FORMAT_BDP(gpd);
	}

	os_printk(K_INFO, "%s GPD data_length=%d\n", __func__, data_len);

	/*
	 * 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);
	/* TGPD_SET_DataBUF_LEN(gpd, gpd_buf_size); */

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

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

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

	/*Get the next GPD */
	Rx_gpd_end[ep_num] = get_gpd(USB_RX, ep_num);
	os_printk(K_INFO, "%s Rx_gpd_end[%d]=%p\n", __func__, ep_num, Tx_gpd_end[ep_num]);

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

	/*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, mu3d_hal_gpd_virt_to_phys(Rx_gpd_end[ep_num], USB_RX, ep_num));

	/*Default: isHWO=true */
	if (isHWO) {
		TGPD_SET_CHKSUM(gpd, CHECKSUM_LENGTH);	/*Set GPD Checksum */
		TGPD_SET_FLAGS_HWO(gpd);	/*Set HWO flag */
	} else {
		TGPD_CLR_FLAGS_HWO(gpd);
		TGPD_SET_CHKSUM_HWO(gpd, CHECKSUM_LENGTH);
	}

	/* 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, mu3d_hal_gpd_virt_to_phys(gpd, USB_RX, ep_num),
				   sizeof(TGPD), DMA_BIDIRECTIONAL);

	return gpd;
}
Esempio n. 7
0
/**
 * 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)
{
	DEV_UINT32 offset;
	DEV_INT32 i;
	DEV_INT32 bd_num;
	DEV_UINT32 length;

	TBD *bd_next;
	TBD *bd_head;
	TBD *bd;
	DEV_UINT8 *pBuffer;

	/*If data length is less than the GPD buffer size, just use GPD */
	/* if (data_len <= GPD_BUF_SIZE) { */
	/* _is_bdp = 0; */
	/* } */

	os_printk(K_INFO, "%s gpd=%p, epnum=%d, len=%d, _is_bdp=%d\n", __func__,
		  gpd, ep_num, data_len, _is_bdp);

	if (!_is_bdp) {
		/*Set actual data point to "DATA Buffer" */
		TGPD_SET_DATA(gpd, pBuf);
		/*Clear "BDP(Buffer Descriptor Present)" flag */
		TGPD_CLR_FORMAT_BDP(gpd);
	} else {
		/*Get the first BD */
		bd_head = (TBD *) get_bd(USB_TX, ep_num);
		os_printk(K_INFO, "bd_head=x%p\n", bd_head);

		bd = bd_head;
		os_memset(bd, 0, sizeof(TBD));

		/*Date length for transfer */
		length = data_len;

		/*Point of data buffer */
		pBuffer = (DEV_UINT8 *) (pBuf);

		/*The size of BD buffer */
		offset = BD_BUF_SIZE;

		/*Count how many BD this transfer need. */
		bd_num = (!(length % offset)) ? (length / offset) : ((length / offset) + 1);

		os_printk(K_INFO, "bd_num=%d\n", bd_num);

		/*If the size of BD buffer is bigger than the length of actual transfer, use the actual length */
		if (offset > length)
			offset = length;

		/*Insert data into each BD */
		for (i = 0; i < bd_num; i++) {
			os_printk(K_INFO, "bd[%d]=%p\n", i, bd);
			if (i == (bd_num - 1)) {	/*The last BD */
				TBD_SET_EXT_LEN(bd, 0);	/*"BD Extension Length" = 0. Does not use BD EXT!! */
				TBD_SET_BUF_LEN(bd, length);	/*"Data Buffer Length" = the rest of data length */
				TBD_SET_DATA(bd, pBuffer);	/*Store the data pointer to "Data Buffer" */

				TBD_SET_FLAGS_EOL(bd);	/*Set "EOL" */
				TBD_SET_NEXT(bd, 0);	/*Set "Next BD pointer" = 0 */
				TBD_SET_CHKSUM(bd, CHECKSUM_LENGTH);	/*Set "BD Checksum" */

				/*Flush the data of BD stuct to device */
				dma_sync_single_for_device(NULL,
							   bd_virt_to_phys(bd, USB_RX, ep_num),
							   sizeof(TBD), DMA_BIDIRECTIONAL);

				/*There is no data left to be transfered by GPD */
				/* data_len=length; */
				data_len = 0;

				/*There is no data left to insert BD */
				length = 0;
			} else {
				TBD_SET_EXT_LEN(bd, 0);	/*"BD Extension length" = 0. Does not use BD EXT!! */
				TBD_SET_BUF_LEN(bd, offset);	/*"Data Buffer Length" = the MAX BD transfer size */
				TBD_SET_DATA(bd, pBuffer);	/*Store the data pointer to "Data Buffer" */

				TBD_CLR_FLAGS_EOL(bd);	/*Clear "EOL" */
				/*Get the next BD */
				bd_next = (TBD *) get_bd(USB_TX, ep_num);
				os_memset(bd_next, 0, sizeof(TBD));

				/*Set "Next BD pointer" as the next BD */
				TBD_SET_NEXT(bd, bd_virt_to_phys(bd_next, USB_TX, ep_num));
				TBD_SET_CHKSUM(bd, CHECKSUM_LENGTH);	/*Set BD Checksum */

				/*Flush the data of BD stuct to device */
				dma_sync_single_for_device(NULL,
							   bd_virt_to_phys(bd, USB_RX, ep_num),
							   sizeof(TBD), DMA_BIDIRECTIONAL);

				/*Calculate the left data length */
				length -= offset;

				/*Move to pointer of buffer */
				pBuffer += offset;

				/*Move to next BD */
				bd = bd_next;
			}
		}

		/*Set the BD pointer into "BD Pointer" at GPD */
		TGPD_SET_DATA(gpd, bd_virt_to_phys(bd_head, USB_TX, ep_num));

		/*Set "BDP(Buffer Descriptor Present)" flag */
		TGPD_SET_FORMAT_BDP(gpd);
	}

	os_printk(K_INFO, "%s GPD data_length=%d\n", __func__, data_len);

	/*
	 * "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 */
	if (zlp)
		TGPD_SET_FORMAT_ZLP(gpd);
	else
		TGPD_CLR_FORMAT_ZLP(gpd);

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

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

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

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

	/*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, mu3d_hal_gpd_virt_to_phys(Tx_gpd_end[ep_num], USB_TX, ep_num));

	/*Default: isHWO=true */
	if (isHWO) {
		TGPD_SET_CHKSUM(gpd, CHECKSUM_LENGTH);	/*Set GPD Checksum */
		TGPD_SET_FLAGS_HWO(gpd);	/*Set HWO flag */
	} else {
		TGPD_CLR_FLAGS_HWO(gpd);
		TGPD_SET_CHKSUM_HWO(gpd, CHECKSUM_LENGTH);
	}

	/*Flush the data of GPD stuct to device */
	dma_sync_single_for_device(NULL, mu3d_hal_gpd_virt_to_phys(gpd, USB_TX, ep_num),
				   sizeof(TGPD), DMA_BIDIRECTIONAL);

#if defined(USB_RISC_CACHE_ENABLED)
	os_flushinvalidateDcache();
#endif

	return gpd;
}
Esempio n. 8
0
/**
 * 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;
	TBD *bptr, *io_bptr;

	for (i = 1; i <= MAX_QMU_EP; i++) {
		/* Allocate Tx GPD */
		size = sizeof(TGPD);
		size *= MAX_GPD_NUM;
		ptr = (TGPD *) os_mem_alloc(size);
		os_memset(ptr, 0, size);

		io_ptr = (TGPD *) dma_map_single(NULL, ptr, size, DMA_TO_DEVICE);
		/* io_ptr = (TGPD*)os_ioremap(os_virt_to_phys(ptr),size); */
		/* io_ptr = (TGPD*)(os_virt_to_phys(ptr)); */
		/* init_gpd_list(USB_RX,i,ptr,io_ptr,MAX_GPD_NUM); */
		init_gpd_list(USB_RX, i, ptr, io_ptr, MAX_GPD_NUM);
		Rx_gpd_end[i] = ptr;
		os_printk(K_DEBUG, "ALLOC RX GPD End [%d] Virtual Mem=%p, DMA addr=%p\n", i,
			  Rx_gpd_end[i], io_ptr);
		/* os_memset(Rx_gpd_end[i], 0 , sizeof(TGPD)); */
		TGPD_CLR_FLAGS_HWO(Rx_gpd_end[i]);
		Rx_gpd_head[i] = Rx_gpd_last[i] = Rx_gpd_end[i];
		os_printk(K_DEBUG, "RQSAR[%d]=%p\n", i,
			  (void *)mu3d_hal_gpd_virt_to_phys(Rx_gpd_end[i], USB_RX, i));

		/* Allocate Rx GPD */
		size = sizeof(TGPD);
		size += AT_GPD_EXT_LEN;
		size *= MAX_GPD_NUM;
		ptr = (TGPD *) os_mem_alloc(size);
		os_memset(ptr, 0, size);

		io_ptr = (TGPD *) dma_map_single(NULL, ptr, size, DMA_TO_DEVICE);
		/* io_ptr = (TGPD*)os_ioremap(os_virt_to_phys(ptr),size); */
		init_gpd_list(USB_TX, i, ptr, io_ptr, MAX_GPD_NUM);
		Tx_gpd_end[i] = ptr;
		os_printk(K_DEBUG, "ALLOC TX GPD End [%d] Virtual Mem=%p, DMA addr=%p\n", i,
			  Tx_gpd_end[i], io_ptr);
		/* os_memset(Tx_gpd_end[i], 0 , sizeof(TGPD)+AT_GPD_EXT_LEN); */
		TGPD_CLR_FLAGS_HWO(Tx_gpd_end[i]);
		Tx_gpd_head[i] = Tx_gpd_last[i] = Tx_gpd_end[i];
		os_printk(K_DEBUG, "TQSAR[%d]=%p\n", i,
			  (void *)mu3d_hal_gpd_virt_to_phys(Tx_gpd_end[i], USB_TX, i));

		/* Allocate Tx BD */
		size = (sizeof(TBD));
		size *= MAX_BD_NUM;
		bptr = (TBD *) os_mem_alloc(size);
		os_memset(bptr, 0, size);
		io_bptr = (TBD *) dma_map_single(NULL, bptr, size, DMA_TO_DEVICE);
		/* io_bptr = (TBD*)os_ioremap(os_virt_to_phys(bptr),size); */
		init_bd_list(USB_RX, i, bptr, io_bptr, MAX_BD_NUM);

		/* Allocate Rx BD */
		size = (sizeof(TBD));
		size += AT_BD_EXT_LEN;
		size *= MAX_BD_NUM;
		bptr = (TBD *) os_mem_alloc(size);
		os_memset(bptr, 0, size);
		io_bptr = (TBD *) dma_map_single(NULL, bptr, size, DMA_TO_DEVICE);
		/* io_bptr = (TBD*)os_ioremap(os_virt_to_phys(bptr),size); */
		init_bd_list(USB_TX, i, bptr, io_bptr, MAX_BD_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)));
	}
}