/**
*
* Reset the CompactFlash device. This function does not reset the System ACE
* controller.  An ATA soft-reset of the CompactFlash is performed.
*
* 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 to be worked on.
*
* @return
*
* - XST_SUCCESS if the reset was done successfully
* - 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.
*
******************************************************************************/
int XSysAce_ResetCF(XSysAce * InstancePtr)
{
    XASSERT_NONVOID(InstancePtr != NULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    /* If a lock has not been granted, return an error */
    if (!XSysAce_mIsMpuLocked(InstancePtr->BaseAddress)) {
        return XST_SYSACE_NO_LOCK;
    }

    /* See if the CF is ready for a command */
    if (!XSysAce_mIsReadyForCmd(InstancePtr->BaseAddress)) {
        return XST_DEVICE_BUSY;
    }

    /*
     * If interrupts are enabled, enable the error interrupt. A reset clears
     * the error status, so we're going to re-enable the interrupt here so any
     * new errors will be caught.
     */
    if (XSysAce_mIsIntrEnabled(InstancePtr->BaseAddress)) {
        XSysAce_mOrControlReg(InstancePtr->BaseAddress,
                              XSA_CR_ERRORIRQ_MASK);
    }

    /*
     * Send the reset command
     */
    XSysAce_RegWrite16(InstancePtr->BaseAddress + XSA_SCCR_OFFSET,
                       XSA_SCCR_RESET_MASK);

    return XST_SUCCESS;
}
Exemple #2
0
/**
*
* Write a CompactFlash sector. This is a blocking, low-level function which
* does not return until the specified sector is written in its entirety.
*
* @param BaseAddress is the base address of the device
* @param SectorId is the id of the sector to write
* @param BufferPtr is a pointer to a buffer used to write the sector.
*
* @return
*
* The number of bytes written. If this number is not equal to the sector size,
* 512 bytes, then an error occurred.
*
* @note
*
* None.
*
******************************************************************************/
int XSysAce_WriteSector(Xuint32 BaseAddress, Xuint32 SectorId, Xuint8 *BufferPtr)
{
    int NumSent;

    /* Get 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 write command of one sector to the controller */
    XSysAce_RegWrite16(BaseAddress + XSA_SCCR_OFFSET,
                        XSA_SCCR_WRITEDATA_MASK | 1);

    /* Reset configuration controller (be sure to keep the lock) */
    XSysAce_mOrControlReg(BaseAddress, XSA_CR_CFGRESET_MASK);

    /* Write a sector of data to the data buffer */
    NumSent = XSysAce_WriteDataBuffer(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 NumSent;
}
Exemple #3
0
/**
*
* Initialize a specific XSysAce instance. The configuration information for
* the given device ID is found and the driver instance data is initialized
* appropriately.
*
* @param InstancePtr is a pointer to the XSysAce instance to be worked on.
* @param DeviceId is the unique id of the device controlled by this XSysAce
*        instance.
*
* @return
*
* XST_SUCCESS if successful, or XST_DEVICE_NOT_FOUND if the device was not
* found in the configuration table in xsysace_g.c.
*
* @note
*
* We do not want to reset the configuration controller here since this could
* cause a reconfiguration of the JTAG target chain, depending on how the
* CFGMODEPIN of the device is wired.
*
******************************************************************************/
XStatus XSysAce_Initialize(XSysAce *InstancePtr, u16 DeviceId)
{
    XSysAce_Config *ConfigPtr;

    XASSERT_NONVOID(InstancePtr != NULL);

    InstancePtr->IsReady = 0;

    /*
     * Lookup configuration data in the device configuration table.
     * Use this configuration info down below when initializing this component.
     */
    ConfigPtr = XSysAce_LookupConfig(DeviceId);

    if (ConfigPtr == (XSysAce_Config *)NULL)
    {
        return XST_DEVICE_NOT_FOUND;
    }

    /*
     * Set some default values for the instance data
     */
    InstancePtr->BaseAddress = ConfigPtr->BaseAddress;
    InstancePtr->EventHandler = StubEventHandler;
    InstancePtr->NumRequested = 0;
    InstancePtr->NumRemaining = 0;
    InstancePtr->BufferPtr = NULL;

    /*
     * Put the device into 16-bit mode or 8-bit mode depending on compile-time
     * parameter
     */
#if (XPAR_XSYSACE_MEM_WIDTH == 16)
    XSysAce_RegWrite16(InstancePtr->BaseAddress + XSA_BMR_OFFSET,
                       XSA_BMR_16BIT_MASK);
#else
    XSysAce_RegWrite16(InstancePtr->BaseAddress + XSA_BMR_OFFSET, 0);
#endif

    /*
     * Disable interrupts. Interrupts must be enabled by the user using
     * XSysAce_EnableInterrupt(). Put the interrupt request line in reset and
     * clear the interrupt enable bits.
     */
    XSysAce_mOrControlReg(InstancePtr->BaseAddress, XSA_CR_RESETIRQ_MASK);
    XSysAce_mAndControlReg(InstancePtr->BaseAddress, ~(XSA_CR_DATARDYIRQ_MASK |
                           XSA_CR_ERRORIRQ_MASK | XSA_CR_CFGDONEIRQ_MASK));

    /*
     * Indicate the instance is now ready to use, initialized without error
     */
    InstancePtr->IsReady = XCOMPONENT_IS_READY;

    return XST_SUCCESS;
}
/**
*
* Enable System ACE interrupts. There are three interrupts that can be enabled.
* The error interrupt enable serves as the driver's means to determine whether
* interrupts have been enabled or not. The configuration-done interrupt is not
* enabled here, instead it is enabled during a reset - which can cause a
* configuration process to start. The data-buffer-ready interrupt is not enabled
* here either. It is enabled when a read or write operation is started. The
* reason for not enabling the latter two interrupts are because the status bits
* may be set as a leftover of an earlier occurrence of the interrupt.
*
* @param InstancePtr is a pointer to the XSysAce instance to work on.
*
* @return
*
* None.
*
* @note
*
* None.
*
******************************************************************************/
void XSysAce_EnableInterrupt(XSysAce * InstancePtr)
{
	XASSERT_VOID(InstancePtr != NULL);
	XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

	/* By default, enable only the error interrupt */
	XSysAce_mOrControlReg(InstancePtr->BaseAddress, XSA_CR_ERRORIRQ_MASK);

	/* Clear the reset on the interrupt line if it was in reset */
	XSysAce_mAndControlReg(InstancePtr->BaseAddress, ~XSA_CR_RESETIRQ_MASK);
}
Exemple #5
0
/**
*
* Disable all System ACE interrupts and hold the interrupt request line of
* the device in reset.
*
* @param InstancePtr is a pointer to the XSysAce instance that just interrupted.
*
* @return
*
* None.
*
* @note
*
* None.
*
******************************************************************************/
void XSysAce_DisableInterrupt(XSysAce *InstancePtr)
{
    XASSERT_VOID(InstancePtr != NULL);
    XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    /* Put the interrupt request line in reset */
    XSysAce_mOrControlReg(InstancePtr->BaseAddress, XSA_CR_RESETIRQ_MASK);

    /* Clear the interrupt enable bits */
    XSysAce_mAndControlReg(InstancePtr->BaseAddress, ~(XSA_CR_DATARDYIRQ_MASK |
                           XSA_CR_ERRORIRQ_MASK | XSA_CR_CFGDONEIRQ_MASK));
}
/**
*
* Reset the JTAG configuration controller. This comprises a reset of the JTAG
* configuration controller and the CompactFlash controller (if it is currently
* being accessed by the configuration controller). Note that the MPU controller
* is not reset, meaning the MPU registers remain unchanged. The configuration
* controller is reset then released from reset in this function.
*
* The CFGDONE status (and therefore interrupt) is cleared when the configuration
* controller is reset. If interrupts have been enabled, we go ahead and enable
* the CFGDONE interrupt here. This means that if and when a configuration
* process starts as a result of this reset, an interrupt will be received when
* it is complete.
*
* @param InstancePtr is a pointer to the XSysAce instance to be worked on.
*
* @return
*
* None.
*
* @note
*
* This function is not thread-safe.
*
******************************************************************************/
void XSysAce_ResetCfg(XSysAce * InstancePtr)
{
	XASSERT_VOID(InstancePtr != NULL);
	XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

	/* Reset the configuration controller */
	XSysAce_mOrControlReg(InstancePtr->BaseAddress, XSA_CR_CFGRESET_MASK);

	/*
	 * If in interrupt mode, enable the CFGDONE and error interrupts.
	 * A reset clears the CFGDONE and error statuses, so we're going to
	 * re-enable the interrupts here so any new errors or CFGDONEs will be
	 * caught.
	 */
	if (XSysAce_mIsIntrEnabled(InstancePtr->BaseAddress)) {
		XSysAce_mOrControlReg(InstancePtr->BaseAddress,
				      XSA_CR_CFGDONEIRQ_MASK |
				      XSA_CR_ERRORIRQ_MASK);
	}

	/* Release the reset of the configuration controller */
	XSysAce_mAndControlReg(InstancePtr->BaseAddress, ~XSA_CR_CFGRESET_MASK);
}
Exemple #7
0
/**
*
* Initialize a specific XSysAce instance. The configuration information is
* passed in as an argument and the driver instance data is initialized
* appropriately.
*
* @param InstancePtr is a pointer to the XSysAce instance to be worked on.
* @param Config is a reference to a structure containing information about a
*        specific SysAce device. This function initializes an InstancePtr object
*        for a specific device specified by the contents of Config. This function
*        can initialize multiple instance objects with the use of multiple calls
*        giving different Config information on each call.
* @param EffectiveAddr is the device base address in the virtual memory address
*        space. The caller is responsible for keeping the address mapping
*        from EffectiveAddr to the device physical base address unchanged
*        once this function is invoked. Unexpected errors may occur if the
*        address mapping changes after this function is called. If address
*        translation is not used, use Config->BaseAddress for this parameters,
*        passing the physical address instead.
*
* @return
*
* XST_SUCCESS if successful.
*
* @note
*
* We do not want to reset the configuration controller here since this could
* cause a reconfiguration of the JTAG target chain, depending on how the
* CFGMODEPIN of the device is wired.
* <br><br>
* The Config pointer argument is not used by this function, but is provided
* to keep the function signature consistent with other drivers.
*
******************************************************************************/
XStatus XSysAce_CfgInitialize(XSysAce * InstancePtr, XSysAce_Config * Config,
			      u32 EffectiveAddr)
{
	XASSERT_NONVOID(InstancePtr != NULL);

	InstancePtr->IsReady = 0;

	/*
	 * Set some default values for the instance data
	 */
	InstancePtr->BaseAddress = EffectiveAddr;
	InstancePtr->EventHandler = StubEventHandler;
	InstancePtr->NumRequested = 0;
	InstancePtr->NumRemaining = 0;
	InstancePtr->BufferPtr = NULL;

	/*
	 * Put the device into 16-bit mode or 8-bit mode depending on compile-time
	 * parameter
	 */
#if (XPAR_XSYSACE_MEM_WIDTH == 16)
	XSysAce_RegWrite16(InstancePtr->BaseAddress + XSA_BMR_OFFSET,
			   XSA_BMR_16BIT_MASK);
#else
	XSysAce_RegWrite16(InstancePtr->BaseAddress + XSA_BMR_OFFSET, 0);
#endif

	/*
	 * Disable interrupts. Interrupts must be enabled by the user using
	 * XSysAce_EnableInterrupt(). Put the interrupt request line in reset and
	 * clear the interrupt enable bits.
	 */
	XSysAce_mOrControlReg(InstancePtr->BaseAddress, XSA_CR_RESETIRQ_MASK);
	XSysAce_mAndControlReg(InstancePtr->BaseAddress,
			       ~(XSA_CR_DATARDYIRQ_MASK | XSA_CR_ERRORIRQ_MASK |
				 XSA_CR_CFGDONEIRQ_MASK));

	/*
	 * Indicate the instance is now ready to use, initialized without error
	 */
	InstancePtr->IsReady = XCOMPONENT_IS_READY;

	return XST_SUCCESS;
}
Exemple #8
0
/**
*
* The interrupt handler for the System ACE driver. This handler must be
* connected by the user to an interrupt controller or source. This function
* does not save or restore context.
*
* This function continues reading or writing to the compact flash if such an
* operation is in progress, and notifies the upper layer software through
* the event handler once the operation is complete or an error occurs. On an
* error, any command currently in progress is aborted.
*
* @param InstancePtr is a pointer to the XSysAce instance that just interrupted.
*
* @return
*
* None.
*
* @note
*
* None.
*
******************************************************************************/
void
XSysAce_InterruptHandler(void *InstancePtr)
{
	u32 StatusReg;
	XSysAce *AcePtr = (XSysAce *) InstancePtr;

	XASSERT_VOID(InstancePtr != NULL);

	/*
	 * Get the status in order to process each interrupt that has occurred
	 */
	StatusReg = XSysAce_mGetStatusReg(AcePtr->BaseAddress);

	/*
	 * Reset the interrupt line to effectively clear the interrupt conditions.
	 * We need to set the bit to clear the interrupts, then clear the bit so
	 * that new interrupts can be generated.
	 */
	XSysAce_mOrControlReg(AcePtr->BaseAddress, XSA_CR_RESETIRQ_MASK);
	XSysAce_mAndControlReg(AcePtr->BaseAddress, ~XSA_CR_RESETIRQ_MASK);

	/*
	 * Check for data buffer ready, which means an operation (either read or
	 * write) is in progress.
	 */
	if (StatusReg & XSA_SR_DATABUFRDY_MASK) {
		/*
		 * Handles the data buffer, and invokes the callback to the user for
		 * data transfer completion.
		 */
		HandleDataBuffer(AcePtr, StatusReg);
	}

	/*
	 * Check for completion of JTAG configuration and report the event up.
	 * We only do this if the CFGDONE interrupt is enabled since the CFGDONE
	 * status only gets cleared when the confguration controller is reset,
	 * which we do not do unless requested by the user because it may cause
	 * a configuration process to start. We could have gotten into this
	 * interrupt handler by another interrupt, yet have a leftover CFGDONE
	 * status from an earlier configuration process.
	 */
	if ((StatusReg & XSA_SR_CFGDONE_MASK) &&
	    (XSysAce_mGetControlReg(AcePtr->BaseAddress) &
	     XSA_CR_CFGDONEIRQ_MASK)) {
		/*
		 * Clear the bit indicating MPU is the source of configuration data
		 * since we're done configuring from the MPU for now. Also clear the
		 * force CFGMODE bit and the CFGSTART bit, basically undoing what was
		 * done in XSysAce_ProgramChain(). Disable the interrupts since the
		 * CFGDONE status does not get cleared unless a reset occurs - and in
		 * the meantime we may get into this interrupt handler again.
		 */
		XSysAce_mAndControlReg(AcePtr->BaseAddress,
				       ~(XSA_CR_CFGSEL_MASK |
					 XSA_CR_CFGSTART_MASK |
					 XSA_CR_CFGDONEIRQ_MASK |
					 XSA_CR_DATARDYIRQ_MASK |
					 XSA_CR_FORCECFGMODE_MASK));

		AcePtr->EventHandler(AcePtr->EventRef, XSA_EVENT_CFG_DONE);
	}

	/*
	 * Check for errors and report the event (the user is responsible for
	 * retrieving and interpreting the errors). We only do this if the error
	 * interrupt is enabled since the error status only gets cleared when the
	 * CompactFlash or confguration controller is reset, which we do not do
	 * because it may cause a configuration process to start. We could have
	 * entered this interrupt handler by another interrupt and have a leftover
	 * error status from a previous error.
	 */
	if ((StatusReg & (XSA_SR_CFGERROR_MASK | XSA_SR_CFCERROR_MASK)) &&
	    (XSysAce_mGetControlReg(AcePtr->BaseAddress) &
	     XSA_CR_ERRORIRQ_MASK)) {
		/* Clear the transfer state to effectively abort the operation */
		AcePtr->NumRequested = 0;
		AcePtr->NumRemaining = 0;
		AcePtr->BufferPtr = NULL;

		/*
		 * Disable the error interrupt since the only way to clear the
		 * error status is to reset the CF or the configuration controller,
		 * neither of which we want to do here since the consequences may
		 * be undesirable (i.e., may cause a reconfiguration). The user
		 * will need to perform the reset based on the error event.
		 */
		XSysAce_mAndControlReg(AcePtr->BaseAddress,
				       ~XSA_CR_ERRORIRQ_MASK);

		AcePtr->EventHandler(AcePtr->EventRef, XSA_EVENT_ERROR);
	}
}
Exemple #9
0
/**
*
* Attempt to lock access to the CompactFlash. The CompactFlash may be accessed
* by the MPU port as well as the JTAG configuration port within the System ACE
* device. This function requests exclusive access to the CompactFlash for the
* MPU port. This is a non-blocking request. If access cannot be locked
* (because the configuration controller has the lock), an appropriate status is
* returned. In this case, the user should call this function again until
* successful.
*
* If the user requests a forced lock, the JTAG configuration controller will
* be put into a reset state in case it currently has a lock on the CompactFlash.
* This effectively aborts any operation the configuration controller had in
* progress and makes the configuration controller restart its process the
* next time it is able to get a lock.
*
* A lock must be granted to the user before attempting to read or write the
* CompactFlash device.
*
* @param InstancePtr is a pointer to the XSysAce instance to be worked on.
* @param Force is a boolean value that, when set to TRUE, will force the MPU
*        lock to occur in the System ACE.  When set to FALSE, the lock is
*        requested and the device arbitrates between the MPU request and
*        JTAG requests. Forcing the MPU lock resets the configuration
*        controller, thus aborting any configuration operations in progress.
*
* @return
*
* XST_SUCCESS if the lock was granted, or XST_DEVICE_BUSY if the lock was
* not granted because the configuration controller currently has access to
* the CompactFlash.
*
* @note
*
* If the lock is not granted to the MPU immediately, this function removes its
* request for a lock so that a lock is not later granted at a time when the
* application is (a) not ready for the lock, or (b) cannot be informed
* asynchronously about the granted lock since there is no such interrupt event.
*
******************************************************************************/
XStatus XSysAce_Lock(XSysAce * InstancePtr, u32 Force)
{
	u32 IsLocked;

	XASSERT_NONVOID(InstancePtr != NULL);
	XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

	/*
	 * Check to see if the configuration controller currently has the lock
	 */
	IsLocked = (XSysAce_mGetStatusReg(InstancePtr->BaseAddress) &
		    XSA_SR_CFGLOCK_MASK);

	if (Force) {
		/*
		 * Reset the configuration controller if it has the lock. Per ASIC
		 * designer, this eliminates a potential deadlock if the FORCELOCK and
		 * LOCKREQ bits are both set and the RDYFORCFCMD is not set.
		 */
		if (IsLocked) {
			/* Reset the configuration controller */
			XSysAce_mOrControlReg(InstancePtr->BaseAddress,
					      XSA_CR_CFGRESET_MASK);
		}

		/* Force the MPU lock. The lock will occur immediately. */
		XSysAce_mOrControlReg(InstancePtr->BaseAddress,
				      XSA_CR_LOCKREQ_MASK |
				      XSA_CR_FORCELOCK_MASK);
	} else {
		/*
		 * Check to see if the configuration controller has the lock. If so,
		 * return a busy status.
		 */
		if (IsLocked) {
			return XST_DEVICE_BUSY;
		}

		/* Request the lock, but do not force it */
		XSysAce_mOrControlReg(InstancePtr->BaseAddress,
				      XSA_CR_LOCKREQ_MASK);
	}

	/*
	 * See if the lock was granted. Note that it is guaranteed to occur if
	 * the user forced it.
	 */
	if (!XSysAce_mIsMpuLocked(InstancePtr->BaseAddress)) {
		/* Lock was not granted, so remove request and return a busy */
		XSysAce_mAndControlReg(InstancePtr->BaseAddress,
				       ~(XSA_CR_LOCKREQ_MASK |
					 XSA_CR_FORCELOCK_MASK));

		return XST_DEVICE_BUSY;
	}

	/*
	 * Lock has been granted.
	 *
	 * If the configuration controller had the lock and has been reset,
	 * go ahead and release it from reset as it will not be able to get
	 * the lock again until the MPU lock is released.
	 */
	if (IsLocked && Force) {
		/* Release the reset of the configuration controller */
		XSysAce_mAndControlReg(InstancePtr->BaseAddress,
				       ~XSA_CR_CFGRESET_MASK);
	}

	return XST_SUCCESS;
}
/**
*
* Write data to the CompactFlash. The user specifies the starting sector ID
* and the number of sectors to be written. The minimum unit that can be written
* to the CompactFlash is a sector, which is 512 bytes.
*
* In polled mode, this write is blocking. If there are other tasks in the
* system that must run, it is best to keep the number of sectors to be written
* to a minimum (e.g., 1). In interrupt mode, this write is non-blocking and an
* event, XSA_EVENT_DATA_DONE, is returned to the user in the asynchronous
* event handler when the write 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 to be worked on.
* @param StartSector is the starting sector ID from where data will be written.
*        Sector IDs range from 0 (first sector) to 0x10000000.
* @param NumSectors is the number of sectors to write. The range can be from
*        1 to 256.
* @param BufferPtr is a pointer to the data buffer to be written. This buffer
*        must have at least (512 * NumSectors) bytes.
*
* @return
*
* - XST_SUCCESS if the write was successful. In interrupt mode, this does not
*   mean the write is complete, only that it has begun. An event is returned
*   to the user when the write 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 write. 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_SectorWrite(XSysAce * InstancePtr, u32 StartSector,
                        int NumSectors, u8 *BufferPtr)
{
    u16 SectorCmd;
    int NumSent;
    int BytesToSend;

    XASSERT_NONVOID(InstancePtr != NULL);
    XASSERT_NONVOID(NumSectors > 0 &&
                    NumSectors <= (XSA_SCCR_COUNT_MASK + 1));
    XASSERT_NONVOID(BufferPtr != NULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    /* If a lock has not been granted, return an error */
    if (!XSysAce_mIsMpuLocked(InstancePtr->BaseAddress)) {
        return XST_SYSACE_NO_LOCK;
    }

    /* See if the CF is ready for a command */
    if (!XSysAce_mIsReadyForCmd(InstancePtr->BaseAddress)) {
        return XST_DEVICE_BUSY;
    }

    /* Write the sector ID (LBA) */
    XSysAce_RegWrite32(InstancePtr->BaseAddress + XSA_MLR_OFFSET,
                       StartSector);

    /*
     * Send the write command for the number of sectors specified
     */
    SectorCmd =
        (NumSectors & XSA_SCCR_COUNT_MASK) | XSA_SCCR_WRITEDATA_MASK;
    XSysAce_RegWrite16(InstancePtr->BaseAddress + XSA_SCCR_OFFSET,
                       SectorCmd);

    BytesToSend = XSA_CF_SECTOR_SIZE * NumSectors;

    /*
     * If in interrupt mode, set up the state variables and enable the
     * data-buffer-ready interrupt. We do this after the write command above
     * is done in order to guarantee that the interrupt occurs only after the
     * first data buffer write is done below (an interrupt may or may not occur
     * after the write command is issued)
     */
    if (XSysAce_mIsIntrEnabled(InstancePtr->BaseAddress)) {
        /*
         * Set the state variables. We're going to send one data buffer here in
         * this routine, so adjust the buffer pointer and number remaining to
         * reflect this.
         */
        InstancePtr->NumRequested = BytesToSend;
        InstancePtr->NumRemaining = BytesToSend - XSA_DATA_BUFFER_SIZE;
        InstancePtr->BufferPtr = BufferPtr + XSA_DATA_BUFFER_SIZE;

        /* Send only one data buffer in interrupt mode */
        BytesToSend = XSA_DATA_BUFFER_SIZE;

        XSysAce_mOrControlReg(InstancePtr->BaseAddress,
                              XSA_CR_DATARDYIRQ_MASK);
    }

    NumSent = XSysAce_WriteDataBuffer(InstancePtr->BaseAddress, BufferPtr,
                                      BytesToSend);
    if (NumSent != BytesToSend) {
        /* an error occurred, report this to the user */
        return XST_FAILURE;
    }

    return XST_SUCCESS;
}
/**
*
* 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 to be worked on.
* @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;

    XASSERT_NONVOID(InstancePtr != NULL);
    XASSERT_NONVOID(NumSectors > 0 &&
                    NumSectors <= (XSA_SCCR_COUNT_MASK + 1));
    XASSERT_NONVOID(BufferPtr != NULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    /* If a lock has not been granted, return an error */
    if (!XSysAce_mIsMpuLocked(InstancePtr->BaseAddress)) {
        return XST_SYSACE_NO_LOCK;
    }

    /* See if the CF is ready for a command */
    if (!XSysAce_mIsReadyForCmd(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_mIsIntrEnabled(InstancePtr->BaseAddress)) {
        InstancePtr->NumRequested = BytesToRecv;
        InstancePtr->NumRemaining = BytesToRecv;
        InstancePtr->BufferPtr = BufferPtr;

        XSysAce_mOrControlReg(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_mIsIntrEnabled(InstancePtr->BaseAddress)) {
        int NumRead;

        /* Reset configuration controller (be sure to keep the lock) */
        /* This breaks mvl, beware! */
        /*XSysAce_mOrControlReg(InstancePtr->BaseAddress, XSA_CR_CFGRESET_MASK); */

        NumRead = XSysAce_ReadDataBuffer(InstancePtr->BaseAddress,
                                         BufferPtr, BytesToRecv);
        /* Clear reset of configuration controller */
        /* This breaks mvl, beware! */
        /*XSysAce_mAndControlReg(InstancePtr->BaseAddress, ~(XSA_CR_CFGRESET_MASK)); */

        if (NumRead != BytesToRecv) {
            /* an error occurred, report this to the user */
            return XST_FAILURE;
        }
    }

    return XST_SUCCESS;
}