Пример #1
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;
}
Пример #2
0
/**
*
* 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);
		}
	}
}
Пример #3
0
/**
*
* 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;

	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;
	}

	/* 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_IsIntrEnabled(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_OrControlReg(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;
}
Пример #4
0
/**
*
* Program the target FPGA chain through the configuration JTAG port. This
* allows the user to program the devices on the target FPGA chain from the MPU
* port instead of from CompactFlash. The user specifies a buffer and the number
* of bytes to write. The buffer should be equivalent to an ACE (.ace) file.
*
* Note that when loading the ACE file via the MPU port, the first sector of the
* ACE file is discarded. The CF filesystem controller in the System ACE device
* knows to skip the first sector when the ACE file comes from the CF, but the
* CF filesystem controller is bypassed when the ACE file comes from the MPU
* port. For this reason, this function skips the first sector of the buffer
* passed in.
*
* In polled mode, the write is blocking. In interrupt mode, the write is
* non-blocking and an event, XSA_EVENT_CFG_DONE, is returned to the user in
* the asynchronous event handler when the configuration is complete.
*
* 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 BufferPtr is a pointer to a buffer that will be used to program
*        the configuration JTAG devices.
* @param NumBytes is the number of bytes in the buffer. We assume that there
*        is at least one sector of data in the .ace file, which is the
*        information sector.
*
* @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_FAILURE if an error occurred during the write. The user should call
*   XSysAce_GetErrors() to determine the cause of the error.
*
* @note
*
* None.
*
* @internal
*
* The System ACE controller has a 32-byte buffer which holds data. The entire
* buffer must be written to ensure that it gets sent to the configuration
* JTAG port. If the number of bytes specified by the user is not a multiple
* of 32, the driver will pad the remaining bytes of the System ACE buffer with
* zeroes in order to write the entire buffer.
*
******************************************************************************/
XStatus
XSysAce_ProgramChain(XSysAce * InstancePtr, u8 * BufferPtr, int NumBytes)
{
	u32 ControlMask;
	int BytesToSend;
	int NumSent;

	XASSERT_NONVOID(InstancePtr != NULL);
	XASSERT_NONVOID(BufferPtr != NULL);
	XASSERT_NONVOID(NumBytes > XSA_CF_SECTOR_SIZE);
	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;
	}

	/*
	 * Set up the configuration controller to use the MPU port as the
	 * source of configuration data (instead of the CF). The following
	 * control flow comes directly from the System ACE specification, except
	 * the reset was moved to after the other control register bits are set.
	 * Putting it into reset before the bits are set seemed to produce
	 * configuration errors occasionally.
	 */
	ControlMask = XSysAce_mGetControlReg(InstancePtr->BaseAddress);

	/* Select MPU as the source */
	ControlMask |= XSA_CR_CFGSEL_MASK;
	XSysAce_mSetControlReg(InstancePtr->BaseAddress, ControlMask);

	/* Tell controller to wait for start bit from MPU */
	ControlMask |= XSA_CR_FORCECFGMODE_MASK;
	ControlMask &= ~XSA_CR_CFGMODE_MASK;
	XSysAce_mSetControlReg(InstancePtr->BaseAddress, ControlMask);

	/* Set the start bit */
	ControlMask |= XSA_CR_CFGSTART_MASK;
	XSysAce_mSetControlReg(InstancePtr->BaseAddress, ControlMask);

	/* Put the configuration controller into a reset condition */
	ControlMask |= XSA_CR_CFGRESET_MASK;
	XSysAce_mSetControlReg(InstancePtr->BaseAddress, ControlMask);

	/* Clear the reset condition, which starts the process */
	ControlMask &= ~XSA_CR_CFGRESET_MASK;
	XSysAce_mSetControlReg(InstancePtr->BaseAddress, ControlMask);

	/*
	 * Set up number of bytes to send. Default to the entire buffer, which
	 * will be true in polled mode. In interrupt mode, modify this value to
	 * send only one data buffer of data.  Always skip the first sector per
	 * the comment above.
	 */
	BytesToSend = NumBytes - XSA_CF_SECTOR_SIZE;

	/*
	 * The number of bytes to write depends on interrupt or polled mode
	 */
	if (XSysAce_mIsIntrEnabled(InstancePtr->BaseAddress)) {
		/*
		 * In interrupt mode, so enable the data-buffer-ready and
		 * configuration-done interrupts. Also, set up the state variables for
		 * the interrupt handler to transfer the remaining data after the
		 * initial write below. We need to write one data buffer here in this
		 * function in order to cause the data-buffer-ready interrupt to occur
		 * for subsequent writes.
		 */
		ControlMask |= XSA_CR_DATARDYIRQ_MASK | XSA_CR_CFGDONEIRQ_MASK;
		XSysAce_mSetControlReg(InstancePtr->BaseAddress, ControlMask);

		/* Send only one data buffer to begin with (if there is that much) */
		if (BytesToSend > XSA_DATA_BUFFER_SIZE) {
			BytesToSend = XSA_DATA_BUFFER_SIZE;
		}

		/*
		 * Setup state variables for the interrupt handler. Skip the first
		 * sector per the comment above, and also skip the first data buffer
		 * since it is written below.
		 */
		InstancePtr->NumRequested = NumBytes - XSA_CF_SECTOR_SIZE;
		InstancePtr->BufferPtr =
		    BufferPtr + XSA_CF_SECTOR_SIZE + BytesToSend;
		InstancePtr->NumRemaining =
		    NumBytes - XSA_CF_SECTOR_SIZE - BytesToSend;
	}

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

	/*
	 * If in polled mode, restore the control register to the way it was
	 */
	if (!XSysAce_mIsIntrEnabled(InstancePtr->BaseAddress)) {
		/*
		 * Unselect MPU as the source, tell controller to use CFGMODE pin,
		 * and clear the start bit.
		 */
		ControlMask &= ~(XSA_CR_CFGSEL_MASK | XSA_CR_FORCECFGMODE_MASK |
				 XSA_CR_CFGSTART_MASK);
		XSysAce_mSetControlReg(InstancePtr->BaseAddress, ControlMask);
	}

	return XST_SUCCESS;
}