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; }
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; } }
/** * 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; }