/** * * This function initiates a transfer on the bus and enables interrupts. * The transfer is completed by the interrupt handler. The messages passed are * all transferred on the bus between one CS assert and de-assert. * * @param InstancePtr is a pointer to the XQspiPsu instance. * @param Msg is a pointer to the structure containing transfer data. * @param NumMsg is the number of messages to be transferred. * * @return * - XST_SUCCESS if successful. * - XST_FAILURE if transfer fails. * - XST_DEVICE_BUSY if a transfer is already in progress. * * @note None. * ******************************************************************************/ s32 XQspiPsu_InterruptTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, u32 NumMsg) { u32 StatusReg; u32 ConfigReg; s32 Index; u32 BaseAddress; s32 Status; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); for (Index = 0; Index < (s32)NumMsg; Index++) { Xil_AssertNonvoid(Msg[Index].ByteCount > 0U); } /* Check whether there is another transfer in progress. Not thread-safe */ if (InstancePtr->IsBusy == TRUE) { return (s32)XST_DEVICE_BUSY; } /* Check for ByteCount upper limit - 2^28 for DMA */ for (Index = 0; Index < (s32)NumMsg; Index++) { if ((Msg[Index].ByteCount > XQSPIPSU_DMA_BYTES_MAX) && ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE)) { return (s32)XST_FAILURE; } } /* * Set the busy flag, which will be cleared when the transfer is * entirely done. */ InstancePtr->IsBusy = TRUE; BaseAddress = InstancePtr->Config.BaseAddress; InstancePtr->Msg = Msg; InstancePtr->NumMsg = (s32)NumMsg; InstancePtr->MsgCnt = 0; /* Enable */ XQspiPsu_Enable(InstancePtr); /* Select slave */ XQspiPsu_GenFifoEntryCSAssert(InstancePtr); /* This might not work if not manual start */ /* Put first message in FIFO along with the above slave select */ XQspiPsu_GenFifoEntryData(InstancePtr, Msg, 0); if (InstancePtr->IsManualstart == TRUE) { #ifdef DEBUG xil_printf("\nManual Start\r\n"); #endif XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET, XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) | XQSPIPSU_CFG_START_GEN_FIFO_MASK); } /* Enable interrupts */ XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_IER_OFFSET, (u32)XQSPIPSU_IER_TXNOT_FULL_MASK | (u32)XQSPIPSU_IER_TXEMPTY_MASK | (u32)XQSPIPSU_IER_RXNEMPTY_MASK | (u32)XQSPIPSU_IER_GENFIFOEMPTY_MASK | (u32)XQSPIPSU_IER_RXEMPTY_MASK); if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_QSPIDMA_DST_I_EN_OFFSET, XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK); } return XST_SUCCESS; }
/** * * This function initiates a transfer on the bus and enables interrupts. * The transfer is completed by the interrupt handler. The messages passed are * all transferred on the bus between one CS assert and de-assert. * * @param InstancePtr is a pointer to the XQspiPsu instance. * @param Msg is a pointer to the structure containing transfer data. * @param NumMsg is the number of messages to be transferred. * * @return * - XST_SUCCESS if successful. * - XST_FAILURE if transfer fails. * - XST_DEVICE_BUSY if a transfer is already in progress. * * @note None. * ******************************************************************************/ int XQspiPsu_InterruptTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, unsigned NumMsg) { u32 StatusReg; u32 ConfigReg; int Index; u8 IsManualStart = FALSE; u32 BaseAddress; int Status; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); for (Index = 0; Index < NumMsg; Index++) { Xil_AssertNonvoid(Msg[Index].ByteCount > 0); } /* Check whether there is another transfer in progress. Not thread-safe */ if (InstancePtr->IsBusy) { return XST_DEVICE_BUSY; } /* * Set the busy flag, which will be cleared when the transfer is * entirely done. */ InstancePtr->IsBusy = TRUE; BaseAddress = InstancePtr->Config.BaseAddress; /* Start if manual start */ IsManualStart = XQspiPsu_IsManualStart(InstancePtr); InstancePtr->Msg = Msg; InstancePtr->NumMsg = NumMsg; InstancePtr->MsgCnt = 0; /* Enable */ XQspiPsu_Enable(InstancePtr); /* Select slave */ XQspiPsu_GenFifoEntryCSAssert(InstancePtr); /* This might not work if not manual start */ /* Put first message in FIFO along with the above slave select */ Status = XQspiPsu_GenFifoEntryData(InstancePtr, Msg, 0); if (Status != XST_SUCCESS) { return Status; } if (IsManualStart) { XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET, XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) | XQSPIPSU_CFG_START_GEN_FIFO_MASK); } /* Enable interrupts */ XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_IER_OFFSET, XQSPIPSU_IER_TXNOT_FULL_MASK | XQSPIPSU_IER_TXEMPTY_MASK | XQSPIPSU_IER_RXNEMPTY_MASK | XQSPIPSU_IER_GENFIFOEMPTY_MASK); if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_QSPIDMA_DST_I_EN_OFFSET, XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK); } return XST_SUCCESS; }
/** * * This function performs a transfer on the bus in polled mode. The messages * passed are all transferred on the bus between one CS assert and de-assert. * * @param InstancePtr is a pointer to the XQspiPsu instance. * @param Msg is a pointer to the structure containing transfer data. * @param NumMsg is the number of messages to be transferred. * * @return * - XST_SUCCESS if successful. * - XST_FAILURE if transfer fails. * - XST_DEVICE_BUSY if a transfer is already in progress. * * @note None. * ******************************************************************************/ s32 XQspiPsu_PolledTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, u32 NumMsg) { u32 StatusReg; u32 ConfigReg; s32 Index; u32 QspiPsuStatusReg, DmaStatusReg; u32 BaseAddress; s32 Status; s32 RxThr; u32 IOPending = (u32)FALSE; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); for (Index = 0; Index < (s32)NumMsg; Index++) { Xil_AssertNonvoid(Msg[Index].ByteCount > 0U); } /* Check whether there is another transfer in progress. Not thread-safe */ if (InstancePtr->IsBusy == TRUE) { return (s32)XST_DEVICE_BUSY; } /* Check for ByteCount upper limit - 2^28 for DMA */ for (Index = 0; Index < (s32)NumMsg; Index++) { if ((Msg[Index].ByteCount > XQSPIPSU_DMA_BYTES_MAX) && ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE)) { return (s32)XST_FAILURE; } } /* * Set the busy flag, which will be cleared when the transfer is * entirely done. */ InstancePtr->IsBusy = TRUE; BaseAddress = InstancePtr->Config.BaseAddress; /* Enable */ XQspiPsu_Enable(InstancePtr); /* Select slave */ XQspiPsu_GenFifoEntryCSAssert(InstancePtr); /* list */ Index = 0; while (Index < (s32)NumMsg) { XQspiPsu_GenFifoEntryData(InstancePtr, Msg, Index); if (InstancePtr->IsManualstart == TRUE) { #ifdef DEBUG xil_printf("\nManual Start\r\n"); #endif XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET, XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) | XQSPIPSU_CFG_START_GEN_FIFO_MASK); } /* Use thresholds here */ /* If there is more data to be transmitted */ do { QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_ISR_OFFSET); /* Transmit more data if left */ if (((QspiPsuStatusReg & XQSPIPSU_ISR_TXNOT_FULL_MASK) != FALSE) && ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_TX) != FALSE) && (InstancePtr->TxBytes > 0)) { XQspiPsu_FillTxFifo(InstancePtr, &Msg[Index], XQSPIPSU_TXD_DEPTH); } /* Check if DMA RX is complete and update RxBytes */ if ((InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) && ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE)) { u32 DmaIntrSts; DmaIntrSts = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET); if ((DmaIntrSts & XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK) != FALSE) { XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, DmaIntrSts); /* Read remaining bytes using IO mode */ if((InstancePtr->RxBytes % 4) != 0 ) { XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) & ~XQSPIPSU_CFG_MODE_EN_MASK)); InstancePtr->ReadMode = XQSPIPSU_READMODE_IO; Msg[Index].ByteCount = (InstancePtr->RxBytes % 4); Msg[Index].RxBfrPtr += (InstancePtr->RxBytes - (InstancePtr->RxBytes % 4)); InstancePtr->IsUnaligned = 1; IOPending = (u32)TRUE; break; } InstancePtr->RxBytes = 0; } } else { if ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE) { /* Check if PIO RX is complete and update RxBytes */ RxThr = (s32)XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_RX_THRESHOLD_OFFSET); if ((QspiPsuStatusReg & XQSPIPSU_ISR_RXNEMPTY_MASK) != 0U) { XQspiPsu_ReadRxFifo(InstancePtr, &Msg[Index], RxThr*4); } else { if ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != 0U) { XQspiPsu_ReadRxFifo(InstancePtr, &Msg[Index], InstancePtr->RxBytes); } } } } } while (((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == FALSE) || (InstancePtr->TxBytes != 0) || ((QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) == FALSE) || (InstancePtr->RxBytes != 0)); if((InstancePtr->IsUnaligned != 0) && (IOPending == (u32)FALSE)) { InstancePtr->IsUnaligned = 0; XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg( BaseAddress, XQSPIPSU_CFG_OFFSET) | XQSPIPSU_CFG_MODE_EN_DMA_MASK)); InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA; } if (IOPending == (u32)TRUE) { IOPending = (u32)FALSE; } else { Index++; } } /* De-select slave */ XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr); if (InstancePtr->IsManualstart == TRUE) { #ifdef DEBUG xil_printf("\nManual Start\r\n"); #endif XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET, XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) | XQSPIPSU_CFG_START_GEN_FIFO_MASK); } QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_ISR_OFFSET); while ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == FALSE) { QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_ISR_OFFSET); } /* Clear the busy flag. */ InstancePtr->IsBusy = FALSE; /* Disable the device. */ XQspiPsu_Disable(InstancePtr); return XST_SUCCESS; }
/** * * This function performs a transfer on the bus in polled mode. The messages * passed are all transferred on the bus between one CS assert and de-assert. * * @param InstancePtr is a pointer to the XQspiPsu instance. * @param Msg is a pointer to the structure containing transfer data. * @param NumMsg is the number of messages to be transferred. * * @return * - XST_SUCCESS if successful. * - XST_FAILURE if transfer fails. * - XST_DEVICE_BUSY if a transfer is already in progress. * * @note None. * ******************************************************************************/ int XQspiPsu_PolledTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, unsigned NumMsg) { u32 StatusReg; u32 ConfigReg; int Index; u8 IsManualStart = FALSE; u32 QspiPsuStatusReg, DmaStatusReg; u32 BaseAddress; int Status; u32 RxThr; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); for (Index = 0; Index < NumMsg; Index++) { Xil_AssertNonvoid(Msg[Index].ByteCount > 0); } /* Check whether there is another transfer in progress. Not thread-safe */ if (InstancePtr->IsBusy) { return XST_DEVICE_BUSY; } /* * Set the busy flag, which will be cleared when the transfer is * entirely done. */ InstancePtr->IsBusy = TRUE; BaseAddress = InstancePtr->Config.BaseAddress; /* Start if manual start */ IsManualStart = XQspiPsu_IsManualStart(InstancePtr); /* Enable */ XQspiPsu_Enable(InstancePtr); /* Select slave */ XQspiPsu_GenFifoEntryCSAssert(InstancePtr); /* list */ for (Index = 0; Index < NumMsg; Index++) { GENFIFO: Status = XQspiPsu_GenFifoEntryData(InstancePtr, Msg, Index); if (Status != XST_SUCCESS) { return Status; } if (IsManualStart) { XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET, XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) | XQSPIPSU_CFG_START_GEN_FIFO_MASK); } /* Use thresholds here */ /* If there is more data to be transmitted */ do { QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_ISR_OFFSET); /* Transmit more data if left */ if ((QspiPsuStatusReg & XQSPIPSU_ISR_TXNOT_FULL_MASK) && (Msg[Index].TxBfrPtr != NULL) && (InstancePtr->TxBytes > 0)) { XQspiPsu_FillTxFifo(InstancePtr, &Msg[Index], XQSPIPSU_TXD_DEPTH); } /* Check if DMA RX is complete and update RxBytes */ if ((InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) && (Msg[Index].RxBfrPtr != NULL)) { u32 DmaIntrSts; DmaIntrSts = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET); if (DmaIntrSts & XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK) { XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, DmaIntrSts); /* Read remaining bytes using IO mode */ if(InstancePtr->RxBytes % 4 != 0 ) { XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) & ~XQSPIPSU_CFG_MODE_EN_MASK)); InstancePtr->ReadMode = XQSPIPSU_READMODE_IO; Msg[Index].ByteCount = (InstancePtr->RxBytes % 4); Msg[Index].RxBfrPtr += (InstancePtr->RxBytes - (InstancePtr->RxBytes % 4)); InstancePtr->IsUnaligned = 1; goto GENFIFO; } InstancePtr->RxBytes = 0; } } else if (Msg[Index].RxBfrPtr != NULL) { /* Check if PIO RX is complete and update RxBytes */ RxThr = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_RX_THRESHOLD_OFFSET); if ((QspiPsuStatusReg & XQSPIPSU_ISR_RXNEMPTY_MASK) != 0U) { XQspiPsu_ReadRxFifo(InstancePtr, &Msg[Index], RxThr); } else if ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != 0U) { XQspiPsu_ReadRxFifo(InstancePtr, &Msg[Index], InstancePtr->RxBytes); } } } while (!(QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) || (InstancePtr->TxBytes != 0) || !(QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) || (InstancePtr->RxBytes != 0)); if(InstancePtr->IsUnaligned) { InstancePtr->IsUnaligned = 0; XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg( BaseAddress, XQSPIPSU_CFG_OFFSET) | XQSPIPSU_CFG_MODE_EN_DMA_MASK)); InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA; } } /* De-select slave */ XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr); if (IsManualStart) { XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET, XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) | XQSPIPSU_CFG_START_GEN_FIFO_MASK); } QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_ISR_OFFSET); while (!(QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK)) { QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_ISR_OFFSET); } /* Clear the busy flag. */ InstancePtr->IsBusy = FALSE; /* Disable the device. */ XQspiPsu_Disable(InstancePtr); return XST_SUCCESS; }