/** * * Resets the QSPIPSU device. Reset must only be called after the driver has * been initialized. Any data transfer that is in progress is aborted. * * The upper layer software is responsible for re-configuring (if necessary) * and restarting the QSPIPSU device after the reset. * * @param InstancePtr is a pointer to the XQspiPsu instance. * * @return None. * * @note None. * ******************************************************************************/ void XQspiPsu_Reset(XQspiPsu *InstancePtr) { u32 ConfigReg; Xil_AssertVoid(InstancePtr != NULL); /* Abort any transfer that is in progress */ XQspiPsu_Abort(InstancePtr); /* Default value to config register */ ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET); /* DMA mode */ ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK; ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK; /* Manual start */ ConfigReg |= XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK; /* Little endain by default */ ConfigReg &= ~XQSPIPSU_CFG_ENDIAN_MASK; /* Disable poll timeout */ ConfigReg &= ~XQSPIPSU_CFG_EN_POLL_TO_MASK; /* Set hold bit */ ConfigReg |= XQSPIPSU_CFG_WP_HOLD_MASK; /* Clear prescalar by default */ ConfigReg &= (u32)(~XQSPIPSU_CFG_BAUD_RATE_DIV_MASK); /* CPOL CPHA 00 */ ConfigReg &= (u32)(~XQSPIPSU_CFG_CLK_PHA_MASK); ConfigReg &= (u32)(~XQSPIPSU_CFG_CLK_POL_MASK); XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, ConfigReg); /* Set by default to allow for high frequencies */ XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_LPBK_DLY_ADJ_OFFSET, XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_LPBK_DLY_ADJ_OFFSET) | XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_MASK); /* Reset thresholds */ XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_TX_THRESHOLD_OFFSET, XQSPIPSU_TX_FIFO_THRESHOLD_RESET_VAL); XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_RX_THRESHOLD_OFFSET, XQSPIPSU_RX_FIFO_THRESHOLD_RESET_VAL); XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GF_THRESHOLD_OFFSET, XQSPIPSU_GEN_FIFO_THRESHOLD_RESET_VAL); /* DMA init */ XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_CTRL_OFFSET, XQSPIPSU_QSPIDMA_DST_CTRL_RESET_VAL); }
/** * * Read the specified number of bytes from RX FIFO * * @param InstancePtr is a pointer to the XQspiPsu instance. * @param Msg is a pointer to the structure containing transfer data. * @param Size is the number of bytes to be read. * * @return None * * @note None. * ******************************************************************************/ static inline void XQspiPsu_ReadRxFifo(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, s32 Size) { s32 Count = 0; u32 Data; #ifdef DEBUG xil_printf("\nXQspiPsu_ReadRxFifo\r\n"); #endif Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(Msg != NULL); while ((InstancePtr->RxBytes != 0) && (Count < Size)) { Data = XQspiPsu_ReadReg(InstancePtr-> Config.BaseAddress, XQSPIPSU_RXD_OFFSET); #ifdef DEBUG xil_printf("\nData is %08x\r\n", Data); #endif if (InstancePtr->RxBytes >= 4) { (void)memcpy(Msg->RxBfrPtr, &Data, 4); InstancePtr->RxBytes -= 4; Msg->RxBfrPtr += 4; Count += 4; } else { /* Read unaligned bytes (< 4 bytes) */ (void)memcpy(Msg->RxBfrPtr, &Data, InstancePtr->RxBytes); Msg->RxBfrPtr += InstancePtr->RxBytes; Count += InstancePtr->RxBytes; InstancePtr->RxBytes = 0; } } }
/** * * Read the specified number of bytes from RX FIFO * * @param InstancePtr is a pointer to the XQspiPsu instance. * @param Msg is a pointer to the structure containing transfer data. * @param Size is the number of bytes to be read. * * @return None * * @note None. * ******************************************************************************/ static inline void XQspiPsu_ReadRxFifo(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, int Size) { int Count = 0; u32 Data; Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(Msg != NULL); while (InstancePtr->RxBytes != 0 && Count < Size) { Data = XQspiPsu_ReadReg(InstancePtr-> Config.BaseAddress, XQSPIPSU_RXD_OFFSET); if (InstancePtr->RxBytes >= 4) { *(u32 *)Msg->RxBfrPtr = Data; InstancePtr->RxBytes -= 4; Msg->RxBfrPtr += 4; Count += 4; } else { /* Read unaligned bytes (< 4 bytes) */ while (InstancePtr->RxBytes != 0) { *Msg->RxBfrPtr = Data; InstancePtr->RxBytes--; Msg->RxBfrPtr++; Count++; Data >>= 8; } } } }
/** * * 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; }
/** * * Aborts a transfer in progress by * * @param InstancePtr is a pointer to the XQspiPsu instance. * * @return None. * * @note * ******************************************************************************/ void XQspiPsu_Abort(XQspiPsu *InstancePtr) { u32 IntrStatus, ConfigReg; IntrStatus = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_ISR_OFFSET); /* Clear and disable interrupts */ XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_ISR_OFFSET, IntrStatus | XQSPIPSU_ISR_WR_TO_CLR_MASK); XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET)); XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_STS_OFFSET, XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_STS_OFFSET) | XQSPIPSU_QSPIDMA_DST_STS_WTC); XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_IDR_OFFSET, XQSPIPSU_IDR_ALL_MASK); XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_I_DIS_OFFSET, XQSPIPSU_QSPIDMA_DST_INTR_ALL_MASK); /* Clear FIFO */ if((XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_ISR_OFFSET) & XQSPIPSU_ISR_RXEMPTY_MASK) != FALSE) { XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_FIFO_CTRL_OFFSET, XQSPIPSU_FIFO_CTRL_RST_TX_FIFO_MASK | XQSPIPSU_FIFO_CTRL_RST_GEN_FIFO_MASK); } /* * Switch to IO mode to Clear RX FIFO. This is becuase of DMA behaviour * where it waits on RX empty and goes busy assuming there is data * to be transfered even if there is no request. */ if ((IntrStatus & XQSPIPSU_ISR_RXEMPTY_MASK) != 0U) { ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET); ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK; XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, ConfigReg); XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_FIFO_CTRL_OFFSET, XQSPIPSU_FIFO_CTRL_RST_RX_FIFO_MASK); if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK; XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, ConfigReg); } } /* Disable QSPIPSU */ XQspiPsu_Disable(InstancePtr); InstancePtr->TxBytes = 0; InstancePtr->RxBytes = 0; InstancePtr->GenFifoEntries = 0; InstancePtr->IsBusy = FALSE; }
/** * * This function writes the GENFIFO entries to transmit the messages requested. * * @param InstancePtr is a pointer to the XQspiPsu instance. * @param Msg is a pointer to the structure containing transfer data. * @param Index of the current message to be handled. * * @return * - XST_SUCCESS if successful. * - XST_FAILURE if transfer fails. * - XST_DEVICE_BUSY if a transfer is already in progress. * * @note None. * ******************************************************************************/ static inline void XQspiPsu_GenFifoEntryData(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, s32 Index) { u32 GenFifoEntry; u32 BaseAddress; u32 TempCount; u32 ImmData; #ifdef DEBUG xil_printf("\nXQspiPsu_GenFifoEntryData\r\n"); #endif BaseAddress = InstancePtr->Config.BaseAddress; GenFifoEntry = 0x0U; /* Bus width */ GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_MODE_MASK); GenFifoEntry |= XQspiPsu_SelectSpiMode((u8)Msg[Index].BusWidth); GenFifoEntry |= InstancePtr->GenFifoCS; GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_BUS_MASK); GenFifoEntry |= InstancePtr->GenFifoBus; /* Data */ if (((Msg[Index].Flags) & XQSPIPSU_MSG_FLAG_STRIPE) != FALSE) { GenFifoEntry |= XQSPIPSU_GENFIFO_STRIPE; } else { GenFifoEntry &= ~XQSPIPSU_GENFIFO_STRIPE; } /* If Byte Count is less than 8 bytes do the transfer in IO mode */ if ((Msg[Index].ByteCount < 8U) && (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA)) { InstancePtr->ReadMode = XQSPIPSU_READMODE_IO; XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) & ~XQSPIPSU_CFG_MODE_EN_MASK)); InstancePtr->IsUnaligned = 1; } XQspiPsu_TXRXSetup(InstancePtr, &Msg[Index], &GenFifoEntry); if (Msg[Index].ByteCount < XQSPIPSU_GENFIFO_IMM_DATA_MASK) { GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_IMM_DATA_MASK); GenFifoEntry |= Msg[Index].ByteCount; #ifdef DEBUG xil_printf("\nFifoEntry=%08x\r\n",GenFifoEntry); #endif XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry); } else { TempCount = Msg[Index].ByteCount; u32 Exponent = 8; /* 2^8 = 256 */ ImmData = TempCount & 0xFFU; /* Exponent entries */ GenFifoEntry |= XQSPIPSU_GENFIFO_EXP; while (TempCount != 0U) { if ((TempCount & XQSPIPSU_GENFIFO_EXP_START) != FALSE) { GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_IMM_DATA_MASK); GenFifoEntry |= Exponent; #ifdef DEBUG xil_printf("\nFifoEntry=%08x\r\n",GenFifoEntry); #endif XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry); } TempCount = TempCount >> 1; Exponent++; } /* Immediate entry */ GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_EXP); if ((ImmData & 0xFFU) != FALSE) { GenFifoEntry &= (u32)(~XQSPIPSU_GENFIFO_IMM_DATA_MASK); GenFifoEntry |= ImmData & 0xFFU; #ifdef DEBUG xil_printf("\nFifoEntry=%08x\r\n",GenFifoEntry); #endif XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry); } } /* One dummy GenFifo entry in case of IO mode */ if ((InstancePtr->ReadMode == XQSPIPSU_READMODE_IO) && ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != FALSE)) { GenFifoEntry = 0x0U; #ifdef DEBUG xil_printf("\nDummy FifoEntry=%08x\r\n",GenFifoEntry); #endif XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry); } }
/** * * 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; }
/** * * 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. * ******************************************************************************/ 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; }