예제 #1
0
static zx_status_t ufshc_configure_descs(ufshc_dev_t* dev) {
    ufs_hba_t* hba = &dev->ufs_hba;
    volatile void* ufshc_regs = dev->ufshc_mmio.vaddr;
    zx_paddr_t tfr_desc_phys = io_buffer_phys(&hba->utrl_dma_buf);
    zx_paddr_t req_desc_phys = io_buffer_phys(&hba->utmrl_dma_buf);
    zx_status_t status;

    if ((status = ufshc_wait_for_active(ufshc_regs, CONTROLLER_ENABLE,
                                        ZX_SEC(1))) != ZX_OK) {
        UFS_ERROR("UFS Host controller not active!\n");
        return status;
    }

    // Configure UTRL nd UTMRL base addr registers
    writel(LOWER_32_BITS(tfr_desc_phys), ufshc_regs +
                                             REG_UTP_TRANSFER_REQ_LIST_BASE_L);
    writel(UPPER_32_BITS(tfr_desc_phys), ufshc_regs +
                                             REG_UTP_TRANSFER_REQ_LIST_BASE_H);

    writel(LOWER_32_BITS(req_desc_phys), ufshc_regs +
                                             REG_UTP_TASK_REQ_LIST_BASE_L);
    writel(UPPER_32_BITS(req_desc_phys), ufshc_regs +
                                             REG_UTP_TASK_REQ_LIST_BASE_H);

    writel(UFS_UTP_RUN_BIT, ufshc_regs + REG_UTP_TRANSFER_REQ_LIST_RUN_STOP);
    writel(UFS_UTP_RUN_BIT, ufshc_regs + REG_UTP_TASK_REQ_LIST_RUN_STOP);

    // Enable auto H8
    writel(UFS_AHT_AH8ITV_MASK, ufshc_regs + REG_CONTROLLER_AHIT);

    return status;
}
예제 #2
0
static void ufshc_memory_configure(ufshc_dev_t* dev) {
    ufs_hba_t* hba = &dev->ufs_hba;
    utp_tfr_req_desc_t* utrdl_desc;
    utp_tfr_cmd_desc_t* ucmd_desc;
    zx_paddr_t ucmd_desc_addr;
    zx_paddr_t ucmd_desc_element_addr;
    uint32_t resp_upiu_len;
    uint32_t resp_upiu_offset;
    uint32_t prdt_offset;
    uint32_t ucmd_desc_size;
    uint32_t i;

    utrdl_desc = hba->tfr_desc;
    ucmd_desc = hba->cmd_desc;

    resp_upiu_offset = (uint32_t)offsetof(utp_tfr_cmd_desc_t, resp_upiu);
    resp_upiu_len = ALIGNED_UPIU_SIZE;
    prdt_offset = (uint32_t)offsetof(utp_tfr_cmd_desc_t, prd_table);

    ucmd_desc_size = sizeof(utp_tfr_cmd_desc_t);
    ucmd_desc_addr = io_buffer_phys(&hba->ucdl_dma_buf);

    for (i = 0; i < hba->nutrs; i++) {
        // Configure UTRD with command descriptor base address
        ucmd_desc_element_addr = (ucmd_desc_addr + (ucmd_desc_size * i));
        utrdl_desc[i].ucdba = LE32(LOWER_32_BITS(ucmd_desc_element_addr));
        utrdl_desc[i].ucdbau = LE32(UPPER_32_BITS(ucmd_desc_element_addr));

        // Response upiu and prdt offset should be in double words
        utrdl_desc[i].resp_upiu_off = LE16((uint16_t)(resp_upiu_offset >> 2));
        utrdl_desc[i].resp_upiu_len = LE16((uint16_t)(resp_upiu_len >> 2));

        utrdl_desc[i].prd_table_off = LE16((uint16_t)(prdt_offset >> 2));
        utrdl_desc[i].prd_table_len = LE16(0);
        hba->lrb_buf[i].utrd = (utrdl_desc + i);
        hba->lrb_buf[i].cmd_upiu = (ufs_utp_cmd_upiu_t*)(ucmd_desc + i);
        hba->lrb_buf[i].resp_upiu = (ufs_utp_resp_upiu_t*)ucmd_desc[i].resp_upiu;
        hba->lrb_buf[i].prdt = (ufshcd_prd_t*)ucmd_desc[i].prd_table;
    }
}
예제 #3
0
/**
 * This function does one simple transfer submission
 *
 * It checks in the following sequence:
 *	- if engine is busy, cannot submit
 *	- if software is still handling the completion of the previous simple
 *		transfer, cannot submit
 *	- if engine is in SG mode and cannot switch to simple mode, cannot submit
 *
 * @param	InstancePtr is the pointer to the driver instance
 * @param	SrcAddr is the address of the source buffer
 * @param	DstAddr is the address of the destination buffer
 * @param	Length is the length of the transfer
 * @param	SimpleCallBack is the callback function for the simple transfer
 * @param	CallBackRef is the callback reference pointer
 *
 * @return
 *		- XST_SUCCESS for success of submission
 *		- XST_FAILURE for submission failure, maybe caused by:
 *			Another simple transfer is still going
 *   . 		Another SG transfer is still going
 *		- XST_INVALID_PARAM if:
 *		Length out of valid range [1:8M]
 *		Or, address not aligned when DRE is not built in
 *
 * @note	Only set the callback function if using interrupt to signal
 *		the completion.If used in polling mode, please set the callback
 * 		function to be NULL.
 *
 *****************************************************************************/
u32 XAxiCdma_SimpleTransfer(XAxiCdma *InstancePtr, UINTPTR SrcAddr, UINTPTR DstAddr,
	int Length, XAxiCdma_CallBackFn SimpleCallBack, void *CallBackRef)
{
	u32 WordBits;

	if ((Length < 1) || (Length > XAXICDMA_MAX_TRANSFER_LEN)) {
		return XST_INVALID_PARAM;
	}

	WordBits = (u32)(InstancePtr->WordLength - 1);

	if ((SrcAddr & WordBits) || (DstAddr & WordBits)) {

		if (!InstancePtr->HasDRE) {
			xdbg_printf(XDBG_DEBUG_ERROR,
			    "Unaligned transfer without DRE %x/%x\r\n",
			    (unsigned int)SrcAddr, (unsigned int)DstAddr);

			return XST_INVALID_PARAM;
		}
	}

	/* If the engine is doing transfer, cannot submit
	 */
	if (XAxiCdma_IsBusy(InstancePtr)) {
		xdbg_printf(XDBG_DEBUG_ERROR, "Engine is busy\r\n");

		return XST_FAILURE;
	}

	/* The driver is still handling the previous simple transfer
	 */
	if (InstancePtr->SimpleNotDone) {
		xdbg_printf(XDBG_DEBUG_ERROR, "Simple ongoing\r\n");

		return XST_FAILURE;
	}

	/* If the engine is in scatter gather mode, try switch to simple mode
	 */
	if (!XAxiCdma_IsSimpleMode(InstancePtr)) {

		if (XAxiCdma_SwitchMode(InstancePtr, XAXICDMA_SIMPLE_MODE) !=
		    XST_SUCCESS) {

			xdbg_printf(XDBG_DEBUG_ERROR,
			    "Cannot switch to simple mode\r\n");

			return XST_FAILURE;
		}
	}

	/* Setup the flag so that others will not step on us
	 *
	 * This flag is only set if callback function is used and if the
	 * system is in interrupt mode; otherwise, when the hardware is done
	 * with the transfer, the driver is done with the transfer
	 */
	if ((SimpleCallBack != NULL) ||
	       ((XAxiCdma_IntrGetEnabled(InstancePtr) &
	        XAXICDMA_XR_IRQ_SIMPLE_ALL_MASK) != 0x0)) {

		InstancePtr->SimpleNotDone = 1;
	}

	InstancePtr->SimpleCallBackFn = SimpleCallBack;
	InstancePtr->SimpleCallBackRef = CallBackRef;

	XAxiCdma_WriteReg(InstancePtr->BaseAddr, XAXICDMA_SRCADDR_OFFSET,
			  LOWER_32_BITS(SrcAddr));
	if (InstancePtr->AddrWidth > 32)
		XAxiCdma_WriteReg(InstancePtr->BaseAddr,
				  XAXICDMA_SRCADDR_MSB_OFFSET,
				  UPPER_32_BITS(SrcAddr));

	XAxiCdma_WriteReg(InstancePtr->BaseAddr, XAXICDMA_DSTADDR_OFFSET,
			  LOWER_32_BITS(DstAddr));
	if (InstancePtr->AddrWidth > 32)
		XAxiCdma_WriteReg(InstancePtr->BaseAddr,
				  XAXICDMA_DSTADDR_MSB_OFFSET,
				  UPPER_32_BITS(DstAddr));

	/* Writing to the BTT register starts the transfer
	 */
	XAxiCdma_WriteReg(InstancePtr->BaseAddr, XAXICDMA_BTT_OFFSET,
		Length);

	return XST_SUCCESS;
}
/**
 * Configure buffer addresses for one DMA channel
 *
 * The buffer addresses are physical addresses.
 * Access to 32 Frame Buffer Addresses in direct mode is done through
 * XAxiVdma_ChannelHiFrmAddrEnable/Disable Functions.
 * 0 - Access Bank0 Registers (0x5C - 0x98)
 * 1 - Access Bank1 Registers (0x5C - 0x98)
 *
 * @param Channel is the pointer to the channel to work on
 * @param BufferAddrSet is the set of addresses for the transfers
 * @param NumFrames is the number of frames to set the address
 *
 * @return
 * - XST_SUCCESS if successful
 * - XST_FAILURE if channel has not being initialized
 * - XST_DEVICE_BUSY if the DMA channel is not idle, BDs are still being used
 * - XST_INVAID_PARAM if buffer address not valid, for example, unaligned
 * address with no DRE built in the hardware
 *
 *****************************************************************************/
int XAxiVdma_ChannelSetBufferAddr(XAxiVdma_Channel *Channel,
        UINTPTR *BufferAddrSet, int NumFrames)
{
	int i;
	u32 WordLenBits;
	int HiFrmAddr = 0;
	int FrmBound;
	if (Channel->AddrWidth > 32) {
		FrmBound = (XAXIVDMA_MAX_FRAMESTORE_64)/2 - 1;
	} else {
		FrmBound = (XAXIVDMA_MAX_FRAMESTORE)/2 - 1;
	}
	int Loop16 = 0;

	if (!Channel->IsValid) {
		//xil_printf("channel not initialized \r\n");
		xdbg_printf(XDBG_DEBUG_ERROR, "Channel not initialized\r\n");

		return XST_FAILURE;
	}

	WordLenBits = (u32)(Channel->WordLength - 1);

	/* If hardware has no DRE, then buffer addresses must
	 * be word-aligned
	 */
	for (i = 0; i < NumFrames; i++) {
		if (!Channel->HasDRE) {
			if (BufferAddrSet[i] & WordLenBits) {
				xdbg_printf(XDBG_DEBUG_ERROR,
				    "Unaligned address %d: %x without DRE\r\n",
				    i, BufferAddrSet[i]);
				//xil_printf("Unaligned address %d: %x without DRE\r\n",
					    //i, BufferAddrSet[i]);/////////////
				return XST_INVALID_PARAM;
			}
		}
	}

	for (i = 0; i < NumFrames; i++, Loop16++) {
		XAxiVdma_Bd *BdPtr = (XAxiVdma_Bd *)(Channel->HeadBdAddr +
		         i * sizeof(XAxiVdma_Bd));

		if (Channel->HasSG) {
			XAxiVdma_BdSetAddr(BdPtr, BufferAddrSet[i]);
		}
		else {
			if ((i > FrmBound) && !HiFrmAddr) {
				XAxiVdma_ChannelHiFrmAddrEnable(Channel);
				HiFrmAddr = 1;
				Loop16 = 0;
			}

			if (Channel->AddrWidth > 32) {
				/* For a 40-bit address XAXIVDMA_MAX_FRAMESTORE
				 * value should be set to 16 */
				XAxiVdma_WriteReg(Channel->StartAddrBase,
					XAXIVDMA_START_ADDR_OFFSET +
					Loop16 * XAXIVDMA_START_ADDR_LEN + i*4,
					LOWER_32_BITS(BufferAddrSet[i]));

				XAxiVdma_WriteReg(Channel->StartAddrBase,
					XAXIVDMA_START_ADDR_MSB_OFFSET +
					Loop16 * XAXIVDMA_START_ADDR_LEN + i*4,
					UPPER_32_BITS((u64)BufferAddrSet[i]));
			} else {
				XAxiVdma_WriteReg(Channel->StartAddrBase,
					XAXIVDMA_START_ADDR_OFFSET +
					Loop16 * XAXIVDMA_START_ADDR_LEN,
					BufferAddrSet[i]);
			}


			if ((NumFrames > FrmBound) && (i == (NumFrames - 1)))
				XAxiVdma_ChannelHiFrmAddrDisable(Channel);
		}
	}

	return XST_SUCCESS;
}