/** * * 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; }
/** * * Handles interrupt based transfers by acting on GENFIFO and DMA interurpts. * * @param InstancePtr is a pointer to the XQspiPsu instance. * * @return * - XST_SUCCESS if successful. * - XST_FAILURE if transfer fails. * * @note None. * ******************************************************************************/ s32 XQspiPsu_InterruptHandler(XQspiPsu *InstancePtr) { u32 QspiPsuStatusReg, DmaIntrStatusReg = 0; u32 BaseAddress; XQspiPsu_Msg *Msg; s32 NumMsg; s32 MsgCnt; u8 DeltaMsgCnt = 0; s32 RxThr; u32 TxRxFlag; Xil_AssertNonvoid(InstancePtr != NULL); BaseAddress = InstancePtr->Config.BaseAddress; Msg = InstancePtr->Msg; NumMsg = InstancePtr->NumMsg; MsgCnt = InstancePtr->MsgCnt; TxRxFlag = Msg[MsgCnt].Flags; /* QSPIPSU Intr cleared on read */ QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_ISR_OFFSET); if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { /* DMA Intr write to clear */ DmaIntrStatusReg = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET); XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, DmaIntrStatusReg); } if (((QspiPsuStatusReg & XQSPIPSU_ISR_POLL_TIME_EXPIRE_MASK) != FALSE) || ((DmaIntrStatusReg & XQSPIPSU_QSPIDMA_DST_INTR_ERR_MASK) != FALSE)) { /* Call status handler to indicate error */ InstancePtr->StatusHandler(InstancePtr->StatusRef, XST_SPI_COMMAND_ERROR, 0); } /* Fill more data to be txed if required */ if ((MsgCnt < NumMsg) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) != FALSE) && ((QspiPsuStatusReg & XQSPIPSU_ISR_TXNOT_FULL_MASK) != FALSE) && (InstancePtr->TxBytes > 0)) { XQspiPsu_FillTxFifo(InstancePtr, &Msg[MsgCnt], XQSPIPSU_TXD_DEPTH); } /* * Check if the entry is ONLY TX and increase MsgCnt. * This is to allow TX and RX together in one entry - corner case. */ if ((MsgCnt < NumMsg) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) != FALSE) && ((QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) != FALSE) && ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != FALSE) && (InstancePtr->TxBytes == 0) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) == FALSE)) { MsgCnt += 1; DeltaMsgCnt = 1U; } if ((InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) && (MsgCnt < NumMsg) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) != FALSE)) { if ((DmaIntrStatusReg & XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK) != FALSE) { /* 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[MsgCnt].ByteCount = (InstancePtr->RxBytes % 4); Msg[MsgCnt].RxBfrPtr += (InstancePtr->RxBytes - (InstancePtr->RxBytes % 4)); InstancePtr->IsUnaligned = 1; XQspiPsu_GenFifoEntryData(InstancePtr, Msg, MsgCnt); 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); } } else { InstancePtr->RxBytes = 0; MsgCnt += 1; DeltaMsgCnt = 1U; } } } else { if ((MsgCnt < NumMsg) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) != FALSE)) { if (InstancePtr->RxBytes != 0) { if ((QspiPsuStatusReg & XQSPIPSU_ISR_RXNEMPTY_MASK) != FALSE) { RxThr = (s32)XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_RX_THRESHOLD_OFFSET); XQspiPsu_ReadRxFifo(InstancePtr, &Msg[MsgCnt], RxThr*4); } else { if (((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != FALSE) && ((QspiPsuStatusReg & XQSPIPSU_ISR_RXEMPTY_MASK) == FALSE)) { XQspiPsu_ReadRxFifo(InstancePtr, &Msg[MsgCnt], InstancePtr->RxBytes); } } if (InstancePtr->RxBytes == 0) { MsgCnt += 1; DeltaMsgCnt = 1U; } } } } /* * Dummy byte transfer * MsgCnt < NumMsg check is to ensure is it a valid dummy cycle message * If one of the above conditions increased MsgCnt, then * the new message is yet to be placed in the FIFO; hence !DeltaMsgCnt. */ if ((MsgCnt < NumMsg) && (DeltaMsgCnt == FALSE) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) == FALSE) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) == FALSE) && ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != FALSE)) { MsgCnt += 1; DeltaMsgCnt = 1U; } InstancePtr->MsgCnt = MsgCnt; /* * DeltaMsgCnt is to handle conditions where genfifo empty can be set * while tx is still not empty or rx dma is not yet done. * MsgCnt > NumMsg indicates CS de-assert entry was also executed. */ if (((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != FALSE) && ((DeltaMsgCnt != FALSE) || (MsgCnt > NumMsg))) { if (MsgCnt < NumMsg) { if(InstancePtr->IsUnaligned != 0) { InstancePtr->IsUnaligned = 0; XQspiPsu_WriteReg(InstancePtr->Config. BaseAddress, XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg(InstancePtr->Config. BaseAddress, XQSPIPSU_CFG_OFFSET) | XQSPIPSU_CFG_MODE_EN_DMA_MASK)); InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA; } /* This might not work if not manual start */ XQspiPsu_GenFifoEntryData(InstancePtr, Msg, MsgCnt); 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); } } else if (MsgCnt == NumMsg) { /* This is just to keep track of the de-assert entry */ MsgCnt += 1; InstancePtr->MsgCnt = MsgCnt; /* 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); } } else { /* Disable interrupts */ XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_IDR_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_DIS_OFFSET, XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK); } /* Clear the busy flag. */ InstancePtr->IsBusy = FALSE; /* Disable the device. */ XQspiPsu_Disable(InstancePtr); /* Call status handler to indicate completion */ InstancePtr->StatusHandler(InstancePtr->StatusRef, XST_SPI_TRANSFER_DONE, 0); } } 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; }