/** * * Read a CompactFlash sector. This is a blocking, low-level function which * does not return until the specified sector is read. * * @param BaseAddress is the base address of the device * @param SectorId is the id of the sector to read * @param BufferPtr is a pointer to a buffer where the data will be stored. * * @return * * The number of bytes read. If this number is not equal to the sector size, * 512 bytes, then an error occurred. * * @note * * None. * ******************************************************************************/ int XSysAce_ReadSector(Xuint32 BaseAddress, Xuint32 SectorId, Xuint8 *BufferPtr) { int NumRead; /* Request and wait for the lock */ XSysAce_mWaitForLock(BaseAddress); /* See if the CF is ready for a command */ if (!XSysAce_mIsReadyForCmd(BaseAddress)) { return 0; } /* Write the sector ID (LBA) */ XSysAce_RegWrite32(BaseAddress + XSA_MLR_OFFSET, SectorId); /* Send a read command of one sector to the controller */ XSysAce_RegWrite16(BaseAddress + XSA_SCCR_OFFSET, XSA_SCCR_READDATA_MASK | 1); /* Reset configuration controller (be sure to keep the lock) */ XSysAce_mOrControlReg(BaseAddress, XSA_CR_CFGRESET_MASK); /* Read a sector of data from the data buffer */ NumRead = XSysAce_ReadDataBuffer(BaseAddress, BufferPtr, XSA_CF_SECTOR_SIZE); /* Clear reset of configuration controller and locks */ XSysAce_mAndControlReg(BaseAddress, ~(XSA_CR_CFGRESET_MASK | XSA_CR_LOCKREQ_MASK)); return NumRead; }
/** * * Handle a data-buffer-ready interrupt. If we get the interrupt when reading, * it means there is still data to read since the interrupt does not occur after * reading the last data buffer. If we get the interrupt when writing, there * may or may not be data left to write since the interrupt does occur after the * last data buffer is written. * * @param InstancePtr is a pointer to the XSysAce instance to be worked on. * @param StatusReg is the contents of the status register, read at the start * of the interrupt service routine. * * @return * * None. * * @note * * None. * ******************************************************************************/ static void HandleDataBuffer(XSysAce * InstancePtr, u32 StatusReg) { /* By default, transfer a whole data buffer */ int BytesToTransfer = XSA_DATA_BUFFER_SIZE; /* * Check to see if number of bytes remaining is less than the data buffer * size. If it is, we need to adjust the remaining bytes to transfer. */ if (InstancePtr->NumRemaining < XSA_DATA_BUFFER_SIZE) { BytesToTransfer = InstancePtr->NumRemaining; } /* * Transfer only one data buffer at a time, which is 32 bytes. Note that * errors will be handled by an error interrupt occurring, so no need to * check for them here. */ if (StatusReg & XSA_SR_DATABUFMODE_MASK) { /* * A write operation in progress, so if there is data remaining then * write the buffer. If no data is remaining, clean up. */ if (InstancePtr->NumRemaining > 0) { (void) XSysAce_WriteDataBuffer(InstancePtr->BaseAddress, InstancePtr->BufferPtr, BytesToTransfer); /* * Decrement the number of bytes remaining to be transferred and * adjust the buffer pointer appropriately. */ InstancePtr->NumRemaining -= BytesToTransfer; InstancePtr->BufferPtr += BytesToTransfer; } else { /* Done writing data, so clean up */ DataComplete(InstancePtr); } } else { /* A read operation in progress, so read the buffer */ (void) XSysAce_ReadDataBuffer(InstancePtr->BaseAddress, InstancePtr->BufferPtr, BytesToTransfer); /* * Decrement the number of bytes remaining to be transferred and * adjust the buffer pointer appropriately. If it was the last buffer, * we're done and we can cleanup. */ InstancePtr->NumRemaining -= BytesToTransfer; InstancePtr->BufferPtr += BytesToTransfer; if (InstancePtr->NumRemaining == 0) { /* Done reading data, so clean up */ DataComplete(InstancePtr); } } }
/** * * Read at least one sector of data from the CompactFlash. The user specifies * the starting sector ID and the number of sectors to be read. The minimum unit * that can be read from the CompactFlash is a sector, which is 512 bytes. * * In polled mode, this read is blocking. If there are other tasks in the system * that must run, it is best to keep the number of sectors to be read to a * minimum (e.g., 1). In interrupt mode, this read is non-blocking and an event, * XSA_EVENT_DATA_DONE, is returned to the user in the asynchronous event * handler when the read is complete. The user must call * XSysAce_EnableInterrupt() to put the driver/device into interrupt mode. * * An MPU lock, obtained using XSysAce_Lock(), must be granted before calling * this function. If a lock has not been granted, no action is taken and an * error is returned. * * @param InstancePtr is a pointer to the XSysAce instance. * @param StartSector is the starting sector ID from where data will * be read. * Sector IDs range from 0 (first sector) to 0x10000000. * @param NumSectors is the number of sectors to read. * The range can be from 1 to 256. * @param BufferPtr is a pointer to a buffer where the data will be * stored. The user must ensure it is big enough to hold * (512 * NumSectors) bytes. * * @return * - XST_SUCCESS if the read was successful. In interrupt mode, * this does not mean the read is complete, only that it has begun. * An event is returned to the user when the read is complete. * - XST_SYSACE_NO_LOCK if no MPU lock has yet been granted * - XST_DEVICE_BUSY if the ACE controller is not ready for a * command * - XST_FAILURE if an error occurred during the read. The user * should call XSysAce_GetErrors() to determine the cause of the * error. * * @note None. * * @internal * * Polled mode is blocking under the assumption that a single sector can be * transferred at a very fast rate (>20 Mbps). So, the user can choose to * transfer only single sectors when in polled mode, thus allowing time for * other work to be done. The biggest issue is that although data transfer * rates are high, seek time for CompactFlash cards is slow (5-20 ms on * average, depending on the type of device). We could move to a non-blocking * solution that transfers 32 bytes at a time (the entire data buffer) and * then returns. The user would then need to increment its buffer pointer * appropriately and call the read/write again. The driver would need some way * to know not to issue a new command to the CompactFlash, but instead continue * with the previous command. This can be done either with a NumSectors argument * of zero to indicate that there is already an operation in progress, or by * having the driver keep state to know there is an operation in progress. The * interface for either seems a bit awkward. Also, the hit for seek time needs * to be taken regardless of the blocking or non-blocking nature of the call, so * the additional few microseconds to transfer a sector of data seems acceptable. * ******************************************************************************/ int XSysAce_SectorRead(XSysAce *InstancePtr, u32 StartSector, int NumSectors, u8 *BufferPtr) { u16 SectorCmd; int BytesToRecv; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(NumSectors > 0 && NumSectors <= (XSA_SCCR_COUNT_MASK + 1)); Xil_AssertNonvoid(BufferPtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* If a lock has not been granted, return an error */ if (!XSysAce_IsMpuLocked(InstancePtr->BaseAddress)) { return XST_SYSACE_NO_LOCK; } /* See if the CF is ready for a command */ if (!XSysAce_IsReadyForCmd(InstancePtr->BaseAddress)) { return XST_DEVICE_BUSY; } BytesToRecv = XSA_CF_SECTOR_SIZE * NumSectors; /* * If in interrupt mode, set up the state variables and enable the * data-buffer-ready interrupt. This needs to be done before the command * is sent to the ACE, which will cause the interrupt to occur. */ if (XSysAce_IsIntrEnabled(InstancePtr->BaseAddress)) { InstancePtr->NumRequested = BytesToRecv; InstancePtr->NumRemaining = BytesToRecv; InstancePtr->BufferPtr = BufferPtr; XSysAce_OrControlReg(InstancePtr->BaseAddress, XSA_CR_DATARDYIRQ_MASK); } /* Write the sector ID (LBA) */ XSysAce_RegWrite32(InstancePtr->BaseAddress + XSA_MLR_OFFSET, StartSector); /* * Send the read command for the number of sectors specified */ SectorCmd = (NumSectors & XSA_SCCR_COUNT_MASK) | XSA_SCCR_READDATA_MASK; XSysAce_RegWrite16(InstancePtr->BaseAddress + XSA_SCCR_OFFSET, SectorCmd); /* * If in polled mode, receive the entire amount requested */ if (!XSysAce_IsIntrEnabled(InstancePtr->BaseAddress)) { int NumRead; /* Reset configuration controller (be sure to keep the lock) */ /* This breaks mvl, beware! */ /*XSysAce_OrControlReg(InstancePtr->BaseAddress, XSA_CR_CFGRESET_MASK); */ NumRead = XSysAce_ReadDataBuffer(InstancePtr->BaseAddress, BufferPtr, BytesToRecv); /* Clear reset of configuration controller */ /* This breaks mvl, beware! */ /*XSysAce_AndControlReg(InstancePtr->BaseAddress, ~(XSA_CR_CFGRESET_MASK)); */ if (NumRead != BytesToRecv) { /* an error occurred, report this to the user */ return XST_FAILURE; } } return XST_SUCCESS; }
/** * * Identify the CompactFlash device. Retrieves the parameters for the * CompactFlash storage device. Note that this is a polled read of one sector * of data. The data is read from the CompactFlash into a byte buffer, which * is then copied into the XSysAce_CFParameters structure passed in by the * user. The copy is necessary since we don't know how the compiler packs * the XSysAce_CFParameters structure. * * An MPU lock, obtained using XSysAce_Lock(), must be granted before calling * this function. If a lock has not been granted, no action is taken and an * error is returned. * * @param InstancePtr is a pointer to the XSysAce instance . * @param ParamPtr is a pointer to a XSysAce_CFParameters structure where * the information for the CompactFlash device will be stored. See * xsysace.h for details on the XSysAce_CFParameters structure. * * @return * - XST_SUCCESS if the identify was done successfully * - XST_FAILURE if an error occurs. Use XSysAce_GetErrors() to * determine cause. * - XST_SYSACE_NO_LOCK if no MPU lock has yet been granted * - XST_DEVICE_BUSY if the CompactFlash is not ready for a command * * @note None. * * @internal * * The identify command has the same protocol as the read sector command * according to the CompactFlash specification. However, there is a discepency * in that same specification on the size of the parameter structure. The word * addresses defined in the spec indicate the parameter information is a full * 512 bytes, the same size as a sector. The total bytes defined in the spec, * however, indicate that the parameter information is only 500 bytes. We * defined the parameter structure in xsysace.h assuming the parameters are the * full 512 bytes since that makes sense, and therefore ignored the "Total * Bytes" column in the spec. * * The SectorData variable was made static to avoid putting 512 bytes on the * stack every time this function is called. * ******************************************************************************/ int XSysAce_IdentifyCF(XSysAce *InstancePtr, XSysAce_CFParameters * ParamPtr) { int NumRead; u32 InterruptsOn; static u8 SectorData[XSA_CF_SECTOR_SIZE]; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(ParamPtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* If a lock has not been granted, return an error */ if (!XSysAce_IsMpuLocked(InstancePtr->BaseAddress)) { return XST_SYSACE_NO_LOCK; } /* See if the CF is ready for a command */ if (!XSysAce_IsReadyForCmd(InstancePtr->BaseAddress)) { return XST_DEVICE_BUSY; } /* * If interrupts are enabled, we disable them because we want to do this * identify in polled mode - due to the buffer endian conversion and copy * that takes place. */ InterruptsOn = XSysAce_IsIntrEnabled(InstancePtr->BaseAddress); if (InterruptsOn) { XSysAce_DisableInterrupt(InstancePtr); } /* * Send the identify command */ XSysAce_RegWrite16(InstancePtr->BaseAddress + XSA_SCCR_OFFSET, XSA_SCCR_IDENTIFY_MASK); /* Reset configuration controller (be sure to keep the lock) */ /* This breaks mvl, beware! */ /* XSysAce_OrControlReg(InstancePtr->BaseAddress, XSA_CR_CFGRESET_MASK); */ /* * Read a sector of data from the data buffer. The parameter info is * the same size as a sector. */ NumRead = XSysAce_ReadDataBuffer(InstancePtr->BaseAddress, SectorData, XSA_CF_SECTOR_SIZE); /* Clear reset of configuration controller */ /* This breaks mvl, beware! */ /*XSysAce_AndControlReg(InstancePtr->BaseAddress, ~(XSA_CR_CFGRESET_MASK)); */ /* If interrupts were on, re-enable interrupts (regardless of error) */ if (InterruptsOn) { XSysAce_EnableInterrupt(InstancePtr); } if (NumRead == 0) { /* an error occurred */ return XST_FAILURE; } /* * Copy the byte buffer to the parameter structure */ FillParam(ParamPtr, SectorData); return XST_SUCCESS; }