embeddedsw/lib/sw_services/xilflash/src/xilflash_amd.c
Jagannadha Sutradharudu Teki 2c8f92039d embeddesw: Add initial code support
Added initial support Xilinx Embedded Software.

Signed-off-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
2014-06-24 16:45:01 +05:30

2441 lines
65 KiB
C
Executable file

/******************************************************************************
*
* Copyright (C) 2007 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xilflash_amd.c
*
* This file implements the AMD CFI Version of the XFlash Library.
*
* @note
*
* - Special consideration has to be given to varying data bus widths. To boost
* performance, multiple devices in parallel on the data bus are accessed
* in parallel. Therefore to reduce complexity and increase performance,
* many local primitive functions are duplicated with the only difference
* being the width of writes to the devices.
* <br><br>
* Even with the performance boosting optimizations, the overhead
* associated is rather high due to the general purpose nature of its
* design.
* <br><br>
* Flash block erasing is a time consuming operation with nearly all
* latency occurring due to the devices' themselves. It takes on the order
* of 1 second to erase each block.
* <br><br>
* Writes by comparison are much quicker so library overhead becomes an
* issue.
* The write algorithm has been optimized for bulk data programming and
* should provide relatively better performance.
*
* - This library and the underlying AMD flash memory does not allow re-
* programming while code is executing from the same memory.
* - If hardware is flakey or fails, then this library could hang a thread of
* execution.
* - This library is only tested on M29DW323DT device in 8 bit and 16 bit mode of
* operation.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -----------------------------------------------
* 1.01a ksu 04/10/08 First release.
* 1.02a ksu 06/16/09 Added Reset Bank function
* Added bank(s) reset operation at the top of the read
* function
* Fixed memory corruption issue in 16 bit read operation
* 2.01a ktn 03/31/10 Updated to support uniform sector WP modes.
* 2.02a sdm 07/07/10 Updated XFlashAmd_Initialize() to NOT change the erase
* region information of a top boot device, when the number
* of erase regions is not more than 1.
* </pre>
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "include/xilflash.h"
#ifdef XPAR_XFL_DEVICE_FAMILY_AMD
#include "include/xilflash_amd.h"
#include "include/xilflash_cfi.h"
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/*
* Define AMD specific data to be part of the instance. This structure will
* overlay the XFlash_PartData structure attribute of the base class.
*/
typedef struct XFlashVendorData_AmdTag {
/*
* The following functions are specific to the width of the data bus and
* will be assigned during initialization.
*
* SendCmd - Writes a single command to the devices.
* SendCmdSeq - Writes two commands in successive bus cycles to the
* devices.
* WriteBuffer - Programming algorithm optimized to perform bulk writes
* to devices.
* GetStatus - Retrieve and interpret the status registers of the
* devices.
* PollSR - Poll the status register of the devices until the device
* is ready.
*/
void (*SendCmd) (u32 BaseAddr, u32 Offset, u32 Cmd);
void (*SendCmdSeq) (u32 BaseAddr, u32 Offset1, u32 Offset2, u32 Cmd1,
u32 Cmd2);
void (*WriteFlash) (u32 BaseAddr, u32 Offset, u32 Cmd);
int (*WriteBuffer) (XFlash * InstancePtr, void *DestPtr,
void *SrcPtr, u32 Bytes);
int (*GetStatus) (u32 BaseAddr, u32 BlockAddr);
int (*PollSR) (u32 BaseAddr, u32 BlockAddr);
} XFlashVendorData_Amd;
/***************** Macros (Inline Functions) Definitions *********************/
/*****************************************************************************
* GET_PARTDATA - Type safe way to convert the base component VendorData type
* to the family specific VendorData_Amd type.
*
* Macro signature:
*
* XFlashVendorData_Amd *GET_PARTDATA(XFlash_PartData *BaseComponent)
*****************************************************************************/
#define GET_PARTDATA(BaseComponent) \
((XFlashVendorData_Amd*) ((u32)(&(BaseComponent->VendorData))))
/************************** Function Prototypes ******************************/
static void SendCmd8(u32 BaseAddr, u32 Offset, u32 Cmd);
static void SendCmd16(u32 BaseAddr, u32 Offset, u32 Cmd);
static void SendCmd32(u32 BaseAddr, u32 Offset, u32 Cmd);
static void SendCmdSeq8(u32 BaseAddr, u32 Offset1, u32 Offset2, u32 Cmd1,
u32 Cmd2);
static void SendCmdSeq16(u32 BaseAddr, u32 Offset1, u32 Offset2, u32 Cmd1,
u32 Cmd2);
static void SendCmdSeq32(u32 BaseAddr, u32 Offset1, u32 Offset2, u32 Cmd1,
u32 Cmd2);
static void WriteFlash8(u32 BaseAddr, u32 Offset, u32 Cmd);
static void WriteFlash16(u32 BaseAddr, u32 Offset, u32 Cmd);
static void WriteFlash32(u32 BaseAddr, u32 Offset, u32 Cmd);
static int WriteBuffer8(XFlash * InstancePtr, void *DestPtr,
void *SrcPtr, u32 Bytes);
static int WriteBuffer16(XFlash * InstancePtr, void *DestPtr,
void *SrcPtr, u32 Bytes);
static int WriteBuffer32(XFlash * InstancePtr, void *DestPtr,
void *SrcPtr, u32 Bytes);
static int GetStatus8(u32 BaseAddr, u32 BlockAddr);
static int GetStatus16(u32 BaseAddr, u32 BlockAddr);
static int GetStatus32(u32 BaseAddr, u32 BlockAddr);
static int PollSR8(u32 BaseAddr, u32 BlockAddr);
static int PollSR16(u32 BaseAddr, u32 BlockAddr);
static int PollSR32(u32 BaseAddr, u32 BlockAddr);
static void GetPartID(XFlash * InstancePtr);
static u16 EnqueueEraseBlocks(XFlash * InstancePtr, u16 *Region,
u16 *Block, u16 MaxBlocks);
static int EraseResume (XFlash * InstancePtr, u32 EraseAddrOff);
static int EraseSuspend (XFlash * InstancePtr, u32 EraseAddrOff);
static void EnterExtendedBlockMode(XFlash * InstancePtr);
static void ExitExtendedBlockMode(XFlash * InstancePtr);
static int CheckBlockProtection(XFlash * InstancePtr, u32 Offset);
static void FlashPause(u32 MicroSeconds);
static int XFlashAmd_ResetBank(XFlash * InstancePtr, u32 Offset, u32 Bytes);
extern int XFlashGeometry_ToBlock(XFlashGeometry * InstancePtr,
u32 AbsoluteOffset,
u16 *Region, u16 *Block, u32 *BlockOffset);
extern int XFlashGeometry_ToAbsolute(XFlashGeometry * InstancePtr,
u16 Region,
u16 Block,
u32 BlockOffset, u32 *AbsoluteOffsetPtr);
/************************** Variable Definitions *****************************/
/*****************************************************************************/
/**
*
* Initializes a XFlash instance with device family specific details. The
* initialization entails:
*
* - Assign part access primitive functions depending on bus width.
* - Reset the device.
*
* @param InstancePtr is a pointer to the XFlash instance.
*
* @return
* - XST_SUCCESS if successful.
* - XFLASH_PART_NOT_SUPPORTED if the command set algorithm or
* Layout is not supported by any specific flash device family
* compiled into the system.
* - XST_FAILURE if failed.
*
* @note None.
*
******************************************************************************/
int XFlashAmd_Initialize(XFlash * InstancePtr)
{
u8 Index;
u8 BusWidth;
u32 Layout;
u32 PartMode;
u32 ParamBlocks;
u32 ParamBlockSize;
u32 CurrentAbsoluteOffset;
u32 CurrentAbsoluteBlock;
XFlashVendorData_Amd *DevDataPtr;
/*
* Verify inputs are valid.
*/
if(InstancePtr == NULL) {
return (XST_FAILURE);
}
/*
* Grab layout and get Vendor specific part information.
*/
Layout = InstancePtr->Geometry.MemoryLayout;
DevDataPtr = GET_PARTDATA(InstancePtr);
/*
* Setup alignment of the write buffer.
*/
if (InstancePtr->Properties.ProgCap.WriteBufferSize != NULL) {
InstancePtr->Properties.ProgCap.WriteBufferAlignmentMask =
InstancePtr->Properties.ProgCap.WriteBufferSize - 1;
}
/*
* Setup layout dependent attributes. These include:
* - Part access primitive functions optimized for a specific bus
* width.
*/
switch (Layout) {
case XFL_LAYOUT_X16_X8_X1:
DevDataPtr->SendCmd = SendCmd8;
DevDataPtr->SendCmdSeq = SendCmdSeq8;
DevDataPtr->WriteFlash = WriteFlash8;
DevDataPtr->PollSR = PollSR8;
DevDataPtr->WriteBuffer = WriteBuffer8;
DevDataPtr->GetStatus = GetStatus8;
break;
case XFL_LAYOUT_X16_X16_X1:
DevDataPtr->SendCmd = SendCmd16;
DevDataPtr->SendCmdSeq = SendCmdSeq16;
DevDataPtr->WriteFlash = WriteFlash16;
DevDataPtr->PollSR = PollSR16;
DevDataPtr->WriteBuffer = WriteBuffer16;
DevDataPtr->GetStatus = GetStatus16;
break;
case XFL_LAYOUT_X16_X16_X2:
DevDataPtr->SendCmd = SendCmd32;
DevDataPtr->SendCmdSeq = SendCmdSeq32;
DevDataPtr->WriteFlash = WriteFlash32;
DevDataPtr->PollSR = PollSR32;
DevDataPtr->WriteBuffer = WriteBuffer32;
DevDataPtr->GetStatus = GetStatus32;
break;
default:
return (XFLASH_PART_NOT_SUPPORTED);
}
/*
* Get part ID and Reset the part.
*/
GetPartID(InstancePtr);
/*
* Setup bank information as per the boot block location.
*/
/*
* Get device operational mode.
*/
PartMode = (Layout & XFL_LAYOUT_PART_MODE_MASK);
if (PartMode == XFL_LAYOUT_PART_MODE_8) {
BusWidth = 1;
}
else if (PartMode == XFL_LAYOUT_PART_MODE_16) {
BusWidth = 2;
}
else {
return (XFLASH_PART_NOT_SUPPORTED);
}
InstancePtr->Geometry.DeviceSize = InstancePtr->Geometry.DeviceSize /
BusWidth;
for (Index = 0; Index < InstancePtr->Geometry.NumEraseRegions;
Index++) {
InstancePtr->Geometry.EraseRegion[Index].Size =
InstancePtr->Geometry.EraseRegion[Index].Size / BusWidth;
}
/*
* If device is top boot then change erase region information.
*/
if (((InstancePtr->Geometry.BootMode == XFL_AMD_TOP_BOOT) ||
(InstancePtr->Geometry.BootMode == XFL_AMD_TOP_WP_UNIFORM)) &&
(InstancePtr->Geometry.NumEraseRegions > 1)) {
/*
* Move boot block region to top.
*/
ParamBlocks = InstancePtr->Geometry.EraseRegion[0].Number;
ParamBlockSize = InstancePtr->Geometry.EraseRegion[0].Size;
InstancePtr->Geometry.EraseRegion[0].Number =
InstancePtr->Geometry.EraseRegion[1].Number;
InstancePtr->Geometry.EraseRegion[0].Size =
InstancePtr->Geometry.EraseRegion[1].Size ;
InstancePtr->Geometry.EraseRegion[1].Number = ParamBlocks ;
InstancePtr->Geometry.EraseRegion[1].Size = ParamBlockSize;
/*
* Calculate Erase region offset and block address.
*/
CurrentAbsoluteOffset = 0;
CurrentAbsoluteBlock = 0;
for (Index = 0;
Index < InstancePtr->Geometry.NumEraseRegions;
Index++) {
/*
* Calculate part offset.
*/
InstancePtr->Geometry.EraseRegion[Index].AbsoluteOffset
= CurrentAbsoluteOffset;
InstancePtr->Geometry.EraseRegion[Index].AbsoluteBlock
= CurrentAbsoluteBlock;
/*
* Increment absolute counters.
*/
CurrentAbsoluteOffset +=
(InstancePtr->Geometry.EraseRegion[Index].Size *
InstancePtr->Geometry.EraseRegion[Index].Number);
CurrentAbsoluteBlock +=
InstancePtr->Geometry.EraseRegion[Index].Number;
}
}
else if (BusWidth != 1) {
/*
* Calculate Erase region offset and block address.
*/
CurrentAbsoluteOffset = 0;
CurrentAbsoluteBlock = 0;
for (Index = 0;
Index < InstancePtr->Geometry.NumEraseRegions;
Index++) {
/*
* Calculate part offset.
*/
InstancePtr->Geometry.EraseRegion[Index].AbsoluteOffset
= CurrentAbsoluteOffset;
InstancePtr->Geometry.EraseRegion[Index].AbsoluteBlock
= CurrentAbsoluteBlock;
/*
* Increment absolute counters.
*/
CurrentAbsoluteOffset +=
(InstancePtr->Geometry.EraseRegion[Index].Size *
InstancePtr->Geometry.EraseRegion[Index].Number);
CurrentAbsoluteBlock +=
InstancePtr->Geometry.EraseRegion[Index].Number;
}
}
(void) XFlashAmd_Reset(InstancePtr);
return (XST_SUCCESS);
}
/*****************************************************************************/
/**
*
* The routine reads the data from the AMD flash device and copies it into
* user buffer.
*
* @param InstancePtr is the pointer to the XFlash instance.
* @param Offset is the offset into the device(s) address space from
* which to read.
* @param Bytes is the number of bytes to copy.
* @param DestPtr is the destination address to copy data to.
*
* @return
* - XST_SUCCESS if successful.
* - XFLASH_ADDRESS_ERROR if the source address does not start
* within the addressable areas of the device(s).
* - XFLASH_PART_NOT_SUPPORTED if the command set algorithm or
* Layout is not supported by any specific flash device family
* compiled into the system.
* - XST_FAILURE if failed.
*
* @note None.
*
******************************************************************************/
int XFlashAmd_Read(XFlash *InstancePtr, u32 Offset, u32 Bytes, void *DestPtr)
{
u8 *Dest8BitPtr;
u8 *Src8BitPtr;
u16 *Dest16BitPtr;
u16 *Src16BitPtr;
u32 PartMode;
u32 Index;
/*
* Verify inputs are valid.
*/
if(InstancePtr == NULL) {
return (XST_FAILURE);
}
if(DestPtr == NULL) {
return (XST_FAILURE);
}
if(Bytes == NULL) {
return (XST_FAILURE);
}
PartMode = (InstancePtr->Geometry.MemoryLayout &
XFL_LAYOUT_PART_MODE_MASK);
/*
* Check to make sure start address is within the device.
*/
if (!XFL_GEOMETRY_IS_ABSOLUTE_VALID(&InstancePtr->Geometry, Offset)) {
return (XFLASH_ADDRESS_ERROR);
}
/*
* Reset the bank(s) so that it returns to the read mode.
*/
if (XFlashAmd_ResetBank(InstancePtr, Offset, Bytes) != XST_SUCCESS) {
return (XST_FAILURE);
}
/*
* Perform copy to the user buffer from the flash buffer.
*/
if (PartMode == XFL_LAYOUT_PART_MODE_8) {
/*
* Perform copy to the user buffer from the buffer.
*/
Src8BitPtr = (u8*) (((volatile u8*)InstancePtr->Geometry.
BaseAddress) + Offset);
Dest8BitPtr = (u8*) DestPtr;
for (Index = 0; Index < Bytes; Index++) {
Dest8BitPtr[Index] = Src8BitPtr[Index];
}
}
else if (PartMode == XFL_LAYOUT_PART_MODE_16) {
/*
* Perform copy to the user buffer from the buffer.
*/
Src16BitPtr = (u16*) (((volatile u16*) InstancePtr->Geometry.
BaseAddress) + Offset);
Dest16BitPtr = (u16*) DestPtr;
for (Index = 0; Index < (Bytes/2); Index++) {
Dest16BitPtr[Index] = Src16BitPtr[Index];
}
}
else {
return (XFLASH_PART_NOT_SUPPORTED);
}
return (XST_SUCCESS);
}
/*****************************************************************************/
/**
*
* Programs the AMD flash device with data stored in the user buffer.
*
* @param InstancePtr is the pointer to the XFlash instance.
* @param Offset is the offset into the device(s) address space from which
* to begin programming. Must be aligned to the width of the
* flash's data bus.
* @param Bytes is the number of bytes to program.
* @param SrcPtr is the source address containing data to be programmed.
* Must be aligned to the width of the flash's data bus.
*
* @return
* - XST_SUCCESS if successful.
* - XFLASH_ADDRESS_ERROR if the destination address range is
* not completely within the addressable areas of the device(s).
* - XST_FAILURE if failed.
*
* @note None.
*
******************************************************************************/
int XFlashAmd_Write(XFlash * InstancePtr, u32 Offset, u32 Bytes, void *SrcPtr)
{
int Status;
XFlashVendorData_Amd *DevDataPtr;
/*
* Verify inputs are valid.
*/
if(InstancePtr == NULL) {
return (XST_FAILURE);
}
if(SrcPtr == NULL) {
return (XST_FAILURE);
}
/*
* Nothing specified to be programmed.
*/
if (Bytes == 0) {
return (XST_SUCCESS);
}
/*
* Verify the address range is within the part.
*/
if (!XFL_GEOMETRY_IS_ABSOLUTE_VALID(&InstancePtr->Geometry, Offset) ||
!XFL_GEOMETRY_IS_ABSOLUTE_VALID(&InstancePtr->Geometry,
Offset + Bytes - 1)) {
return (XFLASH_ADDRESS_ERROR);
}
/*
* Call the proper write buffer function.
*/
DevDataPtr = GET_PARTDATA(InstancePtr);
Status = DevDataPtr->WriteBuffer(InstancePtr, (void *)Offset, SrcPtr,
Bytes);
/*
* Reset the bank(s) so that it returns to the read mode.
*/
(void) XFlashAmd_ResetBank(InstancePtr, Offset, Bytes);
return (Status);
}
/*****************************************************************************/
/**
*
* Erases the specified address range in the AMD Flash device.
*
* @param InstancePtr is the pointer to the XFlash instance.
* @param Offset is the offset into the device(s) address space from which
* to begin erasure.
* @param Bytes is the number of bytes to erase.
*
* @return
* - XST_SUCCESS if successful.
* - XFLASH_ADDRESS_ERROR if the destination address range is
* not completely within the addressable areas of the device(s).
* - XST_FAILURE if failed.
*
* @note Application has to check block protection status of all the
* which needs to be erased before calling this API. If any block
* is protected then this API will return error.
*
******************************************************************************/
int XFlashAmd_Erase(XFlash * InstancePtr, u32 Offset, u32 Bytes)
{
u16 StartRegion;
u16 EndRegion;
u16 StartBlock;
u16 EndBlock;
u16 BlocksLeft;
u16 BlocksQueued;
u32 Dummy;
int Status;
XFlashGeometry *GeomPtr;
XFlashVendorData_Amd *DevDataPtr;
/*
* Verify inputs are valid.
*/
if(InstancePtr == NULL) {
return (XST_FAILURE);
}
GeomPtr = &InstancePtr->Geometry;
/*
* Handle case when zero bytes is provided.
*/
if (Bytes == 0) {
return (XST_SUCCESS);
}
/*
* Convert the starting address to block coordinates. This also verifies
* the starting address is within the instance's address space.
*/
Status = XFlashGeometry_ToBlock(GeomPtr, Offset, &StartRegion,
&StartBlock, &Dummy);
if (Status != XST_SUCCESS) {
return (XFLASH_ADDRESS_ERROR);
}
/*
* Convert the ending address to block coordinates. This also verifies
* the ending address is within the instance's address space.
*/
Status = XFlashGeometry_ToBlock(GeomPtr, Offset + Bytes - 1, &
EndRegion, &EndBlock, &Dummy);
if (Status != XST_SUCCESS) {
return (XFLASH_ADDRESS_ERROR);
}
/*
* Erase loop. Queue up as many blocks at a time until all are erased.
*/
DevDataPtr = GET_PARTDATA(InstancePtr);
BlocksLeft = XFL_GEOMETRY_BLOCK_DIFF(GeomPtr, StartRegion, StartBlock,
EndRegion, EndBlock);
while (BlocksLeft > 0) {
BlocksQueued = EnqueueEraseBlocks(InstancePtr, &StartRegion,
&StartBlock, BlocksLeft);
BlocksLeft -= BlocksQueued;
Status = DevDataPtr->PollSR(GeomPtr->BaseAddress, Offset);
if (Status != XFLASH_READY) {
(void) XFlashAmd_ResetBank(InstancePtr, Offset, Bytes);
return (Status);
}
}
/*
* Reset the bank(s) so that it returns to the read mode.
*/
(void) XFlashAmd_ResetBank(InstancePtr, Offset, Bytes);
return (XST_SUCCESS);
}
/*****************************************************************************/
/**
*
* Locks the blocks in the specified range of the AMD flash device.
*
* @param InstancePtr is the pointer to the XFlash instance.
* @param Offset is the offset into the device(s) address space from which
* to begin block locking.
* @param Bytes indicates the number of bytes to Lock in the Block
* starting from Offset.
*
* @return
* - XST_SUCCESS if successful.
* - XFLASH_ADDRESS_ERROR if the destination address range is
* not completely within the addressable areas of the device(s).
* - XST_FAILURE if failed.
*
* @note This API should be called after applying VID (voltage) to the RP
* pin of flash device. This API is not tested.
*
******************************************************************************/
int XFlashAmd_Lock(XFlash * InstancePtr, u32 Offset, u32 Bytes)
{
u8 Mode;
u8 AddrMul;
volatile u16 StatusReg;
u16 Region;
u16 Block;
u16 NumAttempt = 0;
u32 Dummy;
u32 BaseAddress;
u32 BlockAddress;
u32 GroupAddress;
int Status;
XFlashGeometry *GeomPtr;
XFlashVendorData_Amd *DevDataPtr;
/*
* Verify inputs are valid.
*/
if(InstancePtr == NULL) {
return (XST_FAILURE);
}
DevDataPtr = GET_PARTDATA(InstancePtr);
GeomPtr = &InstancePtr->Geometry;
BaseAddress = GeomPtr->BaseAddress;
Mode = (InstancePtr->Geometry.MemoryLayout &
XFL_LAYOUT_PART_MODE_MASK) >> 8;
if (Mode == 2) {
AddrMul = 1;
}
else if (Mode == 1) {
AddrMul = 2;
}
else {
return (XST_FAILURE);
}
/*
* Convert the starting address to block coordinates. This also verifies
* the starting address is within the instance's address space.
*/
Status = XFlashGeometry_ToBlock(GeomPtr, Offset, &Region, &Block,
&Dummy);
if (Status != XST_SUCCESS) {
return (XFLASH_ADDRESS_ERROR);
}
/*
* Get the physical address to write the command to and send command.
*/
(void) XFlashGeometry_ToAbsolute(GeomPtr, Region, Block, 0,
&BlockAddress);
GroupAddress = (BlockAddress | (XFL_AMD_PROT_STATUS_OFFSET * AddrMul));
/*
* Set-up Phase.
*/
DevDataPtr->WriteFlash(BaseAddress,
GroupAddress, XFL_AMD_CMD_GROUP_PROTECT1);
Status = XST_FAILURE;
do {
/*
* Protect Phase.
*/
DevDataPtr->WriteFlash(BaseAddress,
GroupAddress, XFL_AMD_CMD_GROUP_PROTECT1);
FlashPause(100);
/*
* Verify Phase.
*/
DevDataPtr->WriteFlash(BaseAddress,
GroupAddress, XFL_AMD_CMD_GROUP_PROTECT2);
FlashPause(4);
StatusReg = DevDataPtr->GetStatus(InstancePtr->Geometry.
BaseAddress, GroupAddress);
/*
* Check Protection completed.
*/
if(StatusReg == XFL_AMD_GROUP_PROTECTED) {
Status = XST_SUCCESS;
break;
}
}
while(++NumAttempt < 25);
/*
* Reset the bank(s) so that it returns to the read mode.
*/
(void) XFlashAmd_ResetBank(InstancePtr, Offset, Bytes);
return (Status);
}
/*****************************************************************************/
/**
*
* Unlocks the all blocks in the AMD flash device.
*
* @param InstancePtr is the pointer to the XFlash instance.
* @param Offset is the offset into the device(s) address space from which
* to begin block UnLocking. The first three bytes of every block
* is reserved for special purpose. The offset should be atleast
* three bytes from start of the block.
* @param Bytes indicates the number of bytes to UnLock in the Block
* starting from Offset.
*
* @return
* - XST_SUCCESS if successful.
* - XST_FAILURE if failed.
*
* @note This API should be called after applying VID (voltage) to the RP
* pin of flash device. This API is not tested.
*
******************************************************************************/
int XFlashAmd_Unlock(XFlash * InstancePtr, u32 Offset, u32 Bytes)
{
u8 Mode;
u8 AddrMul;
u8 TopBoot = 0;
u8 MakeUnprotectStep = 0;
u8 NoOfBlockInGroup;
volatile u16 StatusReg;
u16 Region = 0;
u16 NumAttempt = 0;
u16 Block = 0;
u32 BaseAddress;
u32 Index;
u32 GroupAddress;
int Status = XST_FAILURE;
XFlashGeometry *GeomPtr;
XFlashVendorData_Amd *DevDataPtr;
/*
* Verify inputs are valid.
*/
if(InstancePtr == NULL) {
return XST_FAILURE;
}
DevDataPtr = GET_PARTDATA(InstancePtr);
GeomPtr = &InstancePtr->Geometry;
BaseAddress = GeomPtr->BaseAddress;
if (InstancePtr->Geometry.BootMode == XFL_AMD_TOP_BOOT) {
TopBoot = 1;
}
Mode = (InstancePtr->Geometry.MemoryLayout &
XFL_LAYOUT_PART_MODE_MASK) >> 8;
if (Mode == 2) {
AddrMul = 1;
}
else if (Mode == 1) {
AddrMul = 2;
}
else {
return (XST_FAILURE);
}
/*
* Protect all groups of block in the device.
*/
for (Block = 0; Block < GeomPtr->NumBlocks; Block++) {
/*
* Get the physical address.
*/
(void) XFlashGeometry_ToAbsolute(GeomPtr, Region, Block, 0,
&GroupAddress);
if (XFlashAmd_Lock(InstancePtr, GroupAddress, NULL) !=
XST_SUCCESS ) {
return XST_FAILURE;
}
if (TopBoot) {
if ((Block == 0) || (Block >= 63)) {
NoOfBlockInGroup = 1;
}
else if ((Block == 1) || (Block == 60)) {
NoOfBlockInGroup = 3;
}
else {
NoOfBlockInGroup = 4;
}
}
else {
if ((Block <= 7) || (Block == 70)) {
NoOfBlockInGroup = 1;
}
else if ((Block == 8) || (Block == 67)) {
NoOfBlockInGroup = 3;
}
else {
NoOfBlockInGroup = 4;
}
}
for (Index = 0; Index < NoOfBlockInGroup; Index++) {
/*
* Increment Region/Block.
*/
XFL_GEOMETRY_INCREMENT(GeomPtr, Region, Block);
Block++;
}
}
/*
* Setup Phase.
*/
GroupAddress = (0x0000 | (AddrMul * XFL_AMD_CHIP_UNPROTECT_ADDR));
DevDataPtr->WriteFlash(BaseAddress,
GroupAddress, XFL_AMD_CMD_GROUP_PROTECT1);
Block = 0;
Region = 0;
MakeUnprotectStep = 0;
while (NumAttempt < 1000) {
(void) XFlashGeometry_ToAbsolute(GeomPtr, Region, Block, 0,
&GroupAddress);
GroupAddress = (GroupAddress |
(AddrMul * XFL_AMD_CHIP_UNPROTECT_ADDR));
if (MakeUnprotectStep == 0) {
/*
* Unprotect phase.
*/
DevDataPtr->WriteFlash(InstancePtr->Geometry.
BaseAddress,GroupAddress,
XFL_AMD_CMD_GROUP_PROTECT1);
FlashPause(10000);
}
/*
* Verify Phase.
*/
DevDataPtr->WriteFlash(InstancePtr->Geometry.
BaseAddress,GroupAddress,
XFL_AMD_CMD_GROUP_PROTECT2);
FlashPause(4);
StatusReg = DevDataPtr->GetStatus(InstancePtr->Geometry.
BaseAddress, GroupAddress);
if (StatusReg == XFL_AMD_GROUP_UNPROTECTED) {
if (Block == ((GeomPtr->NumBlocks) - 1)) {
Status = XST_SUCCESS;
break;
}
else {
MakeUnprotectStep = 1;
if (TopBoot) {
if ((Block == 0) || (Block >= 63)) {
NoOfBlockInGroup = 1;
}
else if ((Block == 1) || (Block == 60))
{
NoOfBlockInGroup = 3;
}
else {
NoOfBlockInGroup = 4;
}
}
else {
if ((Block <= 7) || (Block == 70)) {
NoOfBlockInGroup = 1;
}
else if ((Block == 8) || (Block == 67))
{
NoOfBlockInGroup = 3;
}
else {
NoOfBlockInGroup = 4;
}
}
for (Index = 0; Index < NoOfBlockInGroup;
Index++) {
/*
* Increment Region/Block.
*/
XFL_GEOMETRY_INCREMENT(GeomPtr, Region,
Block);
Block++;
}
}
}
else {
MakeUnprotectStep = 0;
NumAttempt++;
}
}
/*
* Reset the bank(s) so that it returns to the read mode.
*/
(void) XFlashAmd_ResetBank(InstancePtr, Offset, Bytes);
return (Status);
}
/*****************************************************************************/
/**
*
* The function can be used to erase the whole flash chip. Each Block is erased
* in turn. The function only returns when all of the Blocks have been erased or
* have generated an error..
*
* @param InstancePtr is the pointer to the XFlash instance.
*
* @return
* - XST_SUCCESS if successful.
* - XST_FAILURE if fail.
*
* @note Application has to check block protection status of all the
* blocks before calling this API. If any block is protected then
* this API will return error.
*
******************************************************************************/
int XFlashAmd_EraseChip(XFlash * InstancePtr)
{
int Status = XST_SUCCESS;
XFlashGeometry *GeomPtr;
XFlashVendorData_Amd *DevDataPtr;
/*
* Verify inputs are valid.
*/
if(InstancePtr == NULL) {
return (XST_FAILURE);
}
DevDataPtr = GET_PARTDATA(InstancePtr);
GeomPtr = &InstancePtr->Geometry;
/*
* Send Chip Erase command.
*/
DevDataPtr->SendCmdSeq(GeomPtr->BaseAddress,
XFL_AMD_CMD1_ADDR, XFL_AMD_CMD2_ADDR,
XFL_AMD_CMD1_DATA, XFL_AMD_CMD2_DATA);
DevDataPtr->SendCmd(GeomPtr->BaseAddress,
XFL_AMD_CMD1_ADDR, XFL_AMD_CMD_ERASE1);
DevDataPtr->SendCmdSeq(GeomPtr->BaseAddress,
XFL_AMD_CMD1_ADDR, XFL_AMD_CMD2_ADDR,
XFL_AMD_CMD1_DATA, XFL_AMD_CMD2_DATA);
DevDataPtr->SendCmd(GeomPtr->BaseAddress,
XFL_AMD_CMD1_ADDR, XFL_AMD_CMD_ERASE_CHIP);
/*
* Wait until Program/Erase Controller starts.
*/
Status = DevDataPtr->PollSR(GeomPtr->BaseAddress, NULL);
(void) XFlashAmd_Reset(InstancePtr);
if (Status != XFLASH_READY) {
return (Status);
}
return (XST_SUCCESS);
}
/*****************************************************************************/
/**
*
* This function places the flash in the Read Array mode. In this mode the flash
* can be read as normal memory. All of the other functions leave the flash in
* the Read Array mode so this is not strictly necessary. It is provided for
* completeness and in case of problems.
*
* @param None.
*
* @return
* - XST_SUCCESS if successful.
* - XST_FAILURE if failed to reset device.
*
* @note None.
*
******************************************************************************/
int XFlashAmd_Reset(XFlash * InstancePtr)
{
int Status;
/*
* Verify inputs are valid.
*/
if(InstancePtr == NULL) {
return XST_FAILURE;
}
/*
* Send reset for all region/bank(s) in the device.
*/
Status = XFlashAmd_ResetBank(InstancePtr, 0,
InstancePtr->Geometry.DeviceSize);
return Status;
}
/*****************************************************************************/
/**
*
* This function places the flash region in the Read Array mode. In this mode the
* flash can be read as normal memory. All of the other functions leave the flash
* in the Read Array mode so this is not strictly necessary. It is provided for
* completeness and in case of problems.
*
* @param InstancePtr is the pointer to the XFlash instance.
* @param Offset is the bank/region address.
*
* @return
* - XST_SUCCESS if successful.
* - XST_FAILURE if failed to reset device.
*
* @note None.
*
******************************************************************************/
static int XFlashAmd_ResetBank(XFlash * InstancePtr, u32 Offset, u32 Bytes)
{
XFlashVendorData_Amd *DevDataPtr;
u16 Region, Block;
u32 Dummy, Status;
XFlashGeometry *GeomPtr;
/*
* Verify inputs are valid.
*/
if(InstancePtr == NULL) {
return (XST_FAILURE);
}
/*
* Handle case when zero bytes is provided.
*/
if (Bytes == 0) {
return XST_SUCCESS;
}
DevDataPtr = GET_PARTDATA(InstancePtr);
GeomPtr = &InstancePtr->Geometry;
/*
* Convert the starting address to block coordinates. This also verifies
* the starting address is within the instance's address space.
*/
Status = XFlashGeometry_ToBlock(GeomPtr, Offset, &Region,
&Block, &Dummy);
if (Status != XST_SUCCESS) {
return (XFLASH_ADDRESS_ERROR);
}
while ((InstancePtr->Geometry.EraseRegion[Region].AbsoluteOffset <=
(Offset + Bytes - 1)) &&
(Region < InstancePtr->Geometry.NumEraseRegions)) {
/*
* Send the clear status register command. Use the max write
* width to notify parts of all layouts.
*/
DevDataPtr->SendCmdSeq(InstancePtr->Geometry.BaseAddress,
XFL_AMD_CMD1_ADDR, XFL_AMD_CMD2_ADDR,
XFL_AMD_CMD1_DATA, XFL_AMD_CMD2_DATA);
DevDataPtr->WriteFlash(InstancePtr->Geometry.BaseAddress,
InstancePtr->Geometry.EraseRegion
[Region].AbsoluteOffset,
XFL_AMD_CMD_RESET);
/*
* Increment the region/bank.
*/
Region++;
}
return (XST_SUCCESS);
}
/*****************************************************************************/
/**
*
* Performs the AMD device specific control functions.
*
* @param InstancePtr is the pointer to the XFlash instance.
* @param Command is the device specific command to issue.
* @param Parameters specifies the arguments passed to the device control
* function.
*
* @return
* - XST_SUCCESS if successful.
* - XFLASH_NOT_SUPPORTED if the command is not
* recognized/supported by the device(s).
*
* @note None.
*
******************************************************************************/
int XFlashAmd_DeviceControl(XFlash * InstancePtr, u32 Command,
DeviceCtrlParam *Parameters)
{
u32 BlockAddr;
u32 Offset;
int Status = XST_SUCCESS;
XFlashVendorData_Amd *DevDataPtr;
/*
* Verify inputs are valid.
*/
if(InstancePtr == NULL) {
return (XST_FAILURE);
}
DevDataPtr = GET_PARTDATA(InstancePtr);
switch (Command) {
case XFL_DEVCTL_GET_GEOMETRY:
Parameters->GeometryParam.GeometryPtr =
&InstancePtr->Geometry;
Status = (XST_SUCCESS);
break;
case XFL_DEVCTL_GET_PROPERTIES:
Parameters->PropertiesParam.PropertiesPtr =
&InstancePtr->Properties;
Status = (XST_SUCCESS);
break;
case XFL_DEVCTL_ERASE_RESUME:
BlockAddr = (*((u32*)Parameters));
Status = EraseResume (InstancePtr, BlockAddr);
break;
case XFL_DEVCTL_ERASE_SUSPEND:
BlockAddr = (*((u32*)Parameters));
Status = EraseSuspend (InstancePtr, BlockAddr);
break;
case XFL_DEVCTL_ENTER_EXT_MODE:
EnterExtendedBlockMode(InstancePtr);
Status = (XST_SUCCESS);
break;
case XFL_DEVCTL_EXIT_EXT_MODE:
ExitExtendedBlockMode(InstancePtr);
Status = (XST_SUCCESS);
break;
case XFL_DEVCTL_PROTECTION_STATUS:
Offset = (*((u32*)Parameters));
Status = CheckBlockProtection(InstancePtr, Offset);
break;
case XFL_DEVCTL_CHIP_ERASE:
Status = XFlashAmd_EraseChip(InstancePtr);
break;
default:
Status = (XFLASH_NOT_SUPPORTED);
}
return (Status);
}
/*****************************************************************************/
/**
*
* Writes a command using a 8-bit bus cycle.
*
* @param BaseAddr is the base address of device.
* @param Offset is the offset into the device(s) address space on which
* command is required to be written.
* @param Cmd is the command/data to write at BaseAddress + Offset.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void SendCmd8(u32 BaseAddr, u32 Offset, u32 Cmd)
{
Offset = ((2*Offset) + (!(Offset & 0x1)));
WRITE_FLASH_8(((volatile u8*)BaseAddr) + Offset, Cmd);
}
/*****************************************************************************/
/**
*
* Writes a command using a 16-bit bus cycle.
*
* @param BaseAddr is the base address of device.
* @param Offset is the offset into the device(s) address space on which
* command is required to be written.
* @param Cmd is the command/data to write at BaseAddress + Offset.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void SendCmd16(u32 BaseAddr, u32 Offset, u32 Cmd)
{
WRITE_FLASH_16(((volatile u16*)BaseAddr) + Offset, Cmd);
}
/*****************************************************************************/
/**
*
* Writes a command using a 32-bit bus cycle.
*
* @param BaseAddr is the base address of device.
* @param Offset is the offset into the device(s) address space on which
* command is required to be written.
* @param Cmd is the command/data to write at BaseAddress + Offset.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void SendCmd32(u32 BaseAddr, u32 Offset, u32 Cmd)
{
WRITE_FLASH_32(((volatile u32*)BaseAddr) + Offset, Cmd);
}
/*****************************************************************************/
/**
*
* Writes a command sequence using 8-bit bus cycles.
*
* @param BaseAddr is the base address of device.
* @param Offset1 is the first offset address into the device(s) address
* space on which first command (Cmd1) is required to be written.
* @param Offset2 is the second offset address into the device(s) address
* space on which second command (Cmd2) is required to be written.
* @param Cmd1 is the first command to write at BaseAddress + Offset1.
* @param Cmd2 is the second command to write at BaseAddress + Offset2.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void SendCmdSeq8(u32 BaseAddr, u32 Offset1, u32 Offset2, u32 Cmd1,
u32 Cmd2)
{
Offset1 = ((2*Offset1) + (!(Offset1 & 0x1)));
Offset2 = ((2*Offset2) + (!(Offset2 & 0x1)));
WRITE_FLASH_8(((volatile u8*)BaseAddr) + Offset1, Cmd1);
WRITE_FLASH_8(((volatile u8*)BaseAddr) + Offset2, Cmd2);
}
/*****************************************************************************/
/**
*
* Writes a command sequence using 16-bit bus cycles.
*
* @param BaseAddr is the base address of device.
* @param Offset1 is the first offset address into the device(s) address
* space on which first command (Cmd1) is required to be written.
* @param Offset2 is the second offset address into the device(s) address
* space on which second command (Cmd2) is required to be written.
* @param Cmd1 is the first command to write at BaseAddress + Offset1.
* @param Cmd2 is the second command to write at BaseAddress + Offset2.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void SendCmdSeq16(u32 BaseAddr, u32 Offset1, u32 Offset2, u32 Cmd1,
u32 Cmd2)
{
WRITE_FLASH_16(((volatile u16*)BaseAddr) + Offset1, Cmd1);
WRITE_FLASH_16(((volatile u16*)BaseAddr) + Offset2, Cmd2);
}
/*****************************************************************************/
/**
*
* Writes a command sequence using 32-bit bus cycles.
*
* @param BaseAddr is the base address of device.
* @param Offset1 is the first offset address into the device(s) address
* space on which first command (Cmd1) is required to be written.
* @param Offset2 is the second offset address into the device(s) address
* space on which second command (Cmd2) is required to be written.
* @param Cmd1 is the first command to write at BaseAddress + Offset1.
* @param Cmd2 is the second command to write at BaseAddress + Offset2.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void SendCmdSeq32(u32 BaseAddr, u32 Offset1, u32 Offset2, u32 Cmd1,
u32 Cmd2)
{
WRITE_FLASH_32(((volatile u32*)BaseAddr) + Offset1, Cmd1);
WRITE_FLASH_32(((volatile u32*)BaseAddr) + Offset2, Cmd2);
}
/*****************************************************************************/
/**
*
* Writes a command/data using a 8-bit bus cycle.
*
* @param BaseAddr is the base address of device.
* @param Offset is the offset into the device(s) address space on which
* command is required to be written.
* @param Cmd is the command/data to write at BaseAddress + Offset.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void WriteFlash8(u32 BaseAddr, u32 Offset, u32 Cmd)
{
WRITE_FLASH_8(((volatile u8*)BaseAddr) + Offset, Cmd);
}
/*****************************************************************************/
/**
*
* Writes a command/data using a 16-bit bus cycle.
*
* @param BaseAddr is the base address of device.
* @param Offset is the offset into the device(s) address space on which
* command is required to be written.
* @param Cmd is the command/data to write at BaseAddress + Offset.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void WriteFlash16(u32 BaseAddr, u32 Offset, u32 Cmd)
{
WRITE_FLASH_16(((volatile u16*)BaseAddr) + Offset, Cmd);
}
/*****************************************************************************/
/**
*
* Writes a command/data using a 32-bit bus cycle.
*
* @param BaseAddr is the base address of device.
* @param Offset is the offset into the device(s) address space on which
* command is required to be written.
* @param Cmd is the command/data to write at BaseAddress + Offset.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void WriteFlash32(u32 BaseAddr, u32 Offset, u32 Cmd)
{
WRITE_FLASH_32(((volatile u32*)BaseAddr) + Offset, Cmd);
}
/*****************************************************************************/
/**
*
* This function is used to program the memory in signal bank. It does not erase
* the flash first and will fail if the block(s) are not erased first. The
* device(s) are programmed in parallel.
*
* @param InstancePtr is the instance to work on.
* @param DestPtr is the physical destination address in flash memory
* space.
* @param SrcPtr is the source data.
* @param Bytes is the number of bytes to program.
*
* @return
* - XST_SUCCESS if successful.
* - XFLASH_ERROR if a write error occurred. This error is
* usually device specific.
*
* @note None.
*
******************************************************************************/
static int WriteBuffer8(XFlash * InstancePtr, void *DestPtr,
void *SrcPtr, u32 Bytes)
{
u8 *SourcePtr = (u8*)SrcPtr;
u8 *DestinationPtr = (u8*)DestPtr;
u32 BaseAddress;
u32 Index = 0;
int Status = XST_SUCCESS;
XFlashVendorData_Amd *DevDataPtr;
DevDataPtr = GET_PARTDATA(InstancePtr);
BaseAddress = InstancePtr->Geometry.BaseAddress;
/*
* Send the Unlock Bypass command.
*/
DevDataPtr->SendCmdSeq(BaseAddress,
XFL_AMD_CMD1_ADDR, XFL_AMD_CMD2_ADDR,
XFL_AMD_CMD1_DATA, XFL_AMD_CMD2_DATA);
DevDataPtr->SendCmd(BaseAddress,
XFL_AMD_CMD1_ADDR,
XFL_AMD_CMD_UNLOCK_BYPASS);
Index = 0;
while (Bytes != NULL) {
DevDataPtr->WriteFlash(BaseAddress,
NULL, XFL_AMD_CMD_PROGRAM);
DevDataPtr->WriteFlash(BaseAddress,
(u32)DestinationPtr, SourcePtr[Index]);
Status = DevDataPtr->PollSR(BaseAddress,
(u32)DestinationPtr);
if (Status != XFLASH_READY) {
(void) XFlashAmd_ResetBank(InstancePtr, (u32)DestPtr,
Bytes);
return (Status);
}
DestinationPtr++;
Index++;
Bytes -= 1;
}
/*
* Unlock Bypass Reset.
*/
DevDataPtr->WriteFlash(BaseAddress, NULL,
XFL_AMD_CMD_UNLOCK_BYPASS_RESET1);
DevDataPtr->WriteFlash(BaseAddress,NULL,
XFL_AMD_CMD_UNLOCK_BYPASS_RESET2);
return (XST_SUCCESS);
}
/*****************************************************************************/
/**
*
* This function is used to program the memory in signal bank. It does not erase
* the flash first and will fail if the block(s) are not erased first. The
* device(s) are programmed in parallel.
*
* @param InstancePtr is the instance to work on.
* @param DestPtr is the physical destination address in flash memory
* space.
* @param SrcPtr is the source data.
* @param Bytes is the number of bytes to program.
*
* @return
* - XST_SUCCESS if successful.
* - XFLASH_ERROR if a write error occurred. This error is
* usually device specific.
*
* @note None.
*
******************************************************************************/
static int WriteBuffer16(XFlash * InstancePtr, void *DestPtr,
void *SrcPtr, u32 Bytes)
{
u16 *SourcePtr = (u16*)SrcPtr;
u32 DestinationPtr = (u32)DestPtr;
u32 BaseAddress;
u32 Index = 0;
int Status = XST_SUCCESS;
XFlashVendorData_Amd *DevDataPtr;
DevDataPtr = GET_PARTDATA(InstancePtr);
BaseAddress = InstancePtr->Geometry.BaseAddress;
/*
* Send the Unlock Bypass command.
*/
DevDataPtr->SendCmdSeq(BaseAddress,
XFL_AMD_CMD1_ADDR, XFL_AMD_CMD2_ADDR,
XFL_AMD_CMD1_DATA, XFL_AMD_CMD2_DATA);
DevDataPtr->SendCmd(BaseAddress,
XFL_AMD_CMD1_ADDR,
XFL_AMD_CMD_UNLOCK_BYPASS);
Index = 0;
while (Bytes != NULL) {
DevDataPtr->WriteFlash(BaseAddress,
NULL, XFL_AMD_CMD_PROGRAM);
DevDataPtr->WriteFlash(BaseAddress,
(u32)DestinationPtr, SourcePtr[Index]);
Status = DevDataPtr->PollSR(BaseAddress,
(u32)DestinationPtr);
if (Status != XFLASH_READY) {
(void) XFlashAmd_ResetBank(InstancePtr, (u32)DestPtr,
Bytes);
return (Status);
}
DestinationPtr++;
Index++;
Bytes -= 2;
}
/*
* Unlock Bypass Reset.
*/
DevDataPtr->WriteFlash(BaseAddress, NULL,
XFL_AMD_CMD_UNLOCK_BYPASS_RESET1);
DevDataPtr->WriteFlash(BaseAddress, NULL,
XFL_AMD_CMD_UNLOCK_BYPASS_RESET2);
return (XST_SUCCESS);
}
/*****************************************************************************/
/**
*
* This function is used to program the memory in sin gal bank. It does not erase
* the flash first and will fail if the block(s) are not erased first. The
* device(s) are programmed in parallel.
*
* @param InstancePtr is the instance to work on.
* @param DestPtr is the physical destination address in flash memory
* space.
* @param SrcPtr is the source data.
* @param Bytes is the number of bytes to program.
*
* @return
* - XST_SUCCESS if successful.
* - XFLASH_ERROR if a write error occurred. This error is
* usually device specific.
* - XFLASH_NOT_SUPPORTED if the feature is not
* supported by the device(s)/library.
*
* @note None.
*
******************************************************************************/
static int WriteBuffer32(XFlash * InstancePtr, void *DestPtr,
void *SrcPtr, u32 Bytes)
{
u32 *SourcePtr = (u32*)SrcPtr;
u32 *DestinationPtr = (u32*)DestPtr;
u32 BaseAddress;
u32 Index = 0;
int Status = XST_SUCCESS;
XFlashVendorData_Amd *DevDataPtr;
DevDataPtr = GET_PARTDATA(InstancePtr);
BaseAddress = InstancePtr->Geometry.BaseAddress;
/*
* Send the Unlock Bypass command .
*/
DevDataPtr->SendCmdSeq(BaseAddress,
XFL_AMD_CMD1_ADDR, XFL_AMD_CMD2_ADDR,
XFL_AMD_CMD1_DATA, XFL_AMD_CMD2_DATA);
DevDataPtr->SendCmd(BaseAddress,
XFL_AMD_CMD1_ADDR,
XFL_AMD_CMD_UNLOCK_BYPASS);
Index = 0;
while (Bytes != NULL) {
DevDataPtr->WriteFlash(BaseAddress,
NULL, XFL_AMD_CMD_PROGRAM);
DevDataPtr->WriteFlash(BaseAddress,
(u32)DestinationPtr, SourcePtr[Index]);
Status = DevDataPtr->PollSR(BaseAddress,
(u32)DestinationPtr);
if (Status != XFLASH_READY) {
(void) XFlashAmd_ResetBank(InstancePtr, (u32)DestPtr,
Bytes);
return (Status);
}
DestinationPtr++;
Index++;
Bytes -= 4;
}
/*
* Unlock Bypass Reset.
*/
DevDataPtr->WriteFlash(BaseAddress, NULL,
XFL_AMD_CMD_UNLOCK_BYPASS_RESET1);
DevDataPtr->WriteFlash(BaseAddress,NULL,
XFL_AMD_CMD_UNLOCK_BYPASS_RESET2);
return (XST_SUCCESS);
}
/*****************************************************************************/
/**
*
* Retrieves and interprets status register data from part arrays that occupy a
* 8-bit bus.
*
* @param BaseAddr contains base address of the part.
* @param Offset is the offset into the device(s) address space from which
* to read status information.
*
* @return
* - Status register contents.
*
* @note None.
*
******************************************************************************/
static int GetStatus8(u32 BaseAddr, u32 Offset)
{
return (READ_FLASH_8(((volatile u8*)BaseAddr) + Offset));
}
/*****************************************************************************/
/**
*
* Retrieves and interprets status register data from part arrays that occupy a
* 16-bit bus.
*
* @param BaseAddr contains base address of the part.
* @param Offset is the offset into the device(s) address space from which
* to read status information.
*
* @return
* - Status register contents.
*
* @note None.
*
******************************************************************************/
static int GetStatus16(u32 BaseAddr, u32 Offset)
{
return (READ_FLASH_16(((volatile u16*)BaseAddr) + Offset));
}
/*****************************************************************************/
/**
*
* Retrieves and interprets status register data from part arrays that occupy a
* 32-bit bus.
*
* @param BaseAddr contains base address of the part.
* @param Offset is the offset into the device(s) address space from which
* to read status information.
*
* @return
* - Status register contents.
* - XFLASH_NOT_SUPPORTED if the feature is not
* supported by the device(s)/library.
*
* @note None.
*
******************************************************************************/
static int GetStatus32(u32 BaseAddr, u32 Offset)
{
return (READ_FLASH_32(((volatile u32*)BaseAddr) + Offset));
}
/*****************************************************************************/
/**
*
* Polls the status register until the erase or program operation is completed.
* The device(s) are polled by repeatedly reading the status register.
*
* @param BaseAddr contains base address of the part.
* @param BlockAddr contains address of block on which erase or program
* operation is performed.
*
* @return - XFLASH_READY if erase operation successful is ready.
* - XFLASH_ERROR if error occurs.
*
* @note It is assumed that the status register is currently visible.
*
******************************************************************************/
static int PollSR8(u32 BaseAddr, u32 BlockAddr)
{
u8 StatusReg1;
u8 StatusReg2;
while(TRUE) {
/*
* Read DQ5 and DQ6 (into word).
*/
StatusReg1 = READ_FLASH_8(((volatile u8*) BaseAddr) +
BlockAddr);
/*
* Read DQ6 (into another word).
*/
StatusReg2 = READ_FLASH_8(((volatile u8*) BaseAddr) +
BlockAddr);
/*
* If DQ6 did not toggle between two reads then return
* Flash_Success.
*/
if((StatusReg1 & XFL_AMD_SR_ERASE_COMPL_MASK) ==
(StatusReg2 & XFL_AMD_SR_ERASE_COMPL_MASK)) {
/*
* DQ6 == NO Toggle.
*/
return (XFLASH_READY);
}
/*
* If DQ5 is zero then operation is not yet complete.
*/
if((StatusReg2 & XFL_AMD_SR_ERASE_ERROR_MASK) !=
XFL_AMD_SR_ERASE_ERROR_MASK) {
continue;
}
/*
* Else (DQ5 == 1), read DQ6 twice.
*/
StatusReg1 = READ_FLASH_8(((volatile u8*) BaseAddr) +
BlockAddr);
StatusReg2 = READ_FLASH_8(((volatile u8*) BaseAddr) +
BlockAddr);
/*
* If DQ6 did not toggle between two reads then return
* Flash_Success.
*/
if((StatusReg1 & XFL_AMD_SR_ERASE_COMPL_MASK) ==
(StatusReg2 & XFL_AMD_SR_ERASE_COMPL_MASK)) {
/*
* DQ6 == NO Toggle.
*/
return (XFLASH_READY);
}
else {
/*
* Else return Flash_ToggleFail; DQ6 == Toggle here
* means fail.
*/
return (XFLASH_ERROR);
}
}
}
/*****************************************************************************/
/**
*
* Polls the status register until the erase or program operation is completed.
* The device(s) are polled by repeatedly reading the status register.
*
* @param BaseAddr contains base address of the part.
* @param BlockAddr contains address of block on which erase or program
* operation is performed.
*
* @return - XFLASH_READY if erase operation successful is ready.
* - XFLASH_ERROR if error occurs.
*
* @note It is assumed that the status register is currently visible.
*
******************************************************************************/
static int PollSR16(u32 BaseAddr, u32 BlockAddr)
{
u16 StatusReg1;
u16 StatusReg2;
while(TRUE) {
/*
* Read DQ5 and DQ6 (into word).
*/
StatusReg1 = READ_FLASH_16(((volatile u16*)BaseAddr) +
BlockAddr);
/*
* Read DQ6 (into another word).
*/
StatusReg2 = READ_FLASH_16(((volatile u16*)BaseAddr) +
BlockAddr);
/*
* If DQ6 did not toggle between two reads then return
* Flash_Success.
*/
if((StatusReg1 & XFL_AMD_SR_ERASE_COMPL_MASK) ==
(StatusReg2 & XFL_AMD_SR_ERASE_COMPL_MASK)) {
/*
* DQ6 == NO Toggle.
*/
return (XFLASH_READY);
}
/*
* If DQ5 is zero then operation is not yet complete.
*/
if((StatusReg2 & XFL_AMD_SR_ERASE_ERROR_MASK) !=
XFL_AMD_SR_ERASE_ERROR_MASK) {
continue;
}
/*
* Else (DQ5 == 1), read DQ6 twice.
*/
StatusReg1 = READ_FLASH_16(((volatile u16*)BaseAddr) +
BlockAddr);
StatusReg2 = READ_FLASH_16(((volatile u16*)BaseAddr) +
BlockAddr);
/*
* If DQ6 did not toggle between two reads then return
* Flash_Success.
*/
if((StatusReg1 & XFL_AMD_SR_ERASE_COMPL_MASK) ==
(StatusReg2 & XFL_AMD_SR_ERASE_COMPL_MASK)) {
/*
* DQ6 == NO Toggle.
*/
return (XFLASH_READY);
}
else {
/*
* Else return Flash_ToggleFail; DQ6 == Toggle here
* means fail.
*/
return (XFLASH_ERROR);
}
}
}
/*****************************************************************************/
/**
*
* Polls the status register until the erase or program operation is completed.
* The device(s) are polled by repeatedly reading the status register.
*
* @param BaseAddr contains base address of the part.
* @param BlockAddr contains address of block on which erase or program
* operation is performed.
*
* @return - XFLASH_READY if erase operation successful is ready.
* - XFLASH_ERROR if error occurs.
* - XFLASH_NOT_SUPPORTED if the feature is not
* supported by the device(s)/library.
*
* @note It is assumed that the status register is currently visible.
*
******************************************************************************/
static int PollSR32(u32 BaseAddr , u32 BlockAddr)
{
u32 StatusReg1;
u32 StatusReg2;
while(TRUE) {
/*
* Read DQ5 and DQ6 (into word).
*/
StatusReg1 = READ_FLASH_32(((volatile u32*)BaseAddr) +
BlockAddr);
/*
* Read DQ6 (into another word).
*/
StatusReg2 = READ_FLASH_32(((volatile u32*)BaseAddr) +
BlockAddr);
/*
* If DQ6 did not toggle between two reads then return
* Flash_Success.
*/
if((StatusReg1 & XFL_AMD_SR_ERASE_COMPL_MASK) ==
(StatusReg2 & XFL_AMD_SR_ERASE_COMPL_MASK)) {
/*
* DQ6 == NO Toggle.
*/
return (XFLASH_READY);
}
/*
* If DQ5 is zero then operation is not yet complete.
*/
if((StatusReg2 & XFL_AMD_SR_ERASE_ERROR_MASK) !=
XFL_AMD_SR_ERASE_ERROR_MASK) {
continue;
}
/*
* Else (DQ5 == 1), read DQ6 twice.
*/
StatusReg1 = READ_FLASH_32(((volatile u32*)BaseAddr) +
BlockAddr);
StatusReg2 = READ_FLASH_32(((volatile u32*)BaseAddr) +
BlockAddr);
/*
* If DQ6 did not toggle between two reads then return
* Flash_Success.
*/
if((StatusReg1 & XFL_AMD_SR_ERASE_COMPL_MASK) ==
(StatusReg2 & XFL_AMD_SR_ERASE_COMPL_MASK)) {
/*
* DQ6 == NO Toggle.
*/
return (XFLASH_READY);
}
else {
/*
* Else return Flash_ToggleFail; DQ6 == Toggle here
* means fail.
*/
return (XFLASH_ERROR);
}
}
}
/*****************************************************************************/
/**
*
* Reads and interprets part identification data.
*
* @param InstancePtr is the instance to work on.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void GetPartID(XFlash * InstancePtr)
{
void *Ptr;
u8 Mode;
u8 Interleave;
u32 CmdAddress;
XFlashVendorData_Amd *DevDataPtr;
DevDataPtr = GET_PARTDATA(InstancePtr);
CmdAddress = InstancePtr->Geometry.BaseAddress;
Interleave = (InstancePtr->Geometry.MemoryLayout &
XFL_LAYOUT_CFI_INTERL_MASK) >> 24;
Mode = (InstancePtr->Geometry.MemoryLayout &
XFL_LAYOUT_PART_MODE_MASK) >> 8;
/*
* Send Read id codes command.
*/
DevDataPtr->SendCmdSeq(CmdAddress,
XFL_AMD_CMD1_ADDR, XFL_AMD_CMD2_ADDR,
XFL_AMD_CMD1_DATA, XFL_AMD_CMD2_DATA);
DevDataPtr->SendCmd(CmdAddress,
XFL_AMD_CMD1_ADDR,
XFL_AMD_CMD_AUTO_SELECT);
/*
* Retrieve Manufacturer ID located at word offset 0.
*/
XFL_CFI_POSITION_PTR(Ptr, CmdAddress, Interleave,
XFL_AMD_MANUFECTURE_ID_OFFSET);
InstancePtr->Properties.PartID.ManufacturerID =
XFlashCFI_Read8((u8*)Ptr, Interleave, Mode);
/*
* Retrieve Device Code located at word offset 1.
*/
XFL_CFI_ADVANCE_PTR8(Ptr, Interleave);
InstancePtr->Properties.PartID.DeviceID =
XFlashCFI_Read8((u8*)Ptr, Interleave, Mode);
/*
* Place device(s) back into read-array mode.
*/
(void) XFlashAmd_Reset(InstancePtr);
}
/*****************************************************************************/
/**
*
* Sends commands to erase blocks.
*
* @param InstancePtr is the pointer to xflash object to work on.
* @param Region is the region which the first block appears.
* @param Block is the starting block to erase.
* @param MaxBlocks is the number of consecutive blocks to erase.
*
* @return The number of blocks enqueued to the part's erase buffer.
* Region and Block parameters are incremented the number of blocks
* queued.
*
* @note Limitation: Only support enqueuing one block at a time.
*
******************************************************************************/
static u16 EnqueueEraseBlocks(XFlash * InstancePtr, u16 *Region,
u16 *Block, u16 MaxBlocks)
{
u32 BlockAddress;
XFlashGeometry *GeomPtr;
XFlashVendorData_Amd *DevDataPtr;
/*
* If for some reason the maximum number of blocks to enqueue is
* zero, then don't do anything.
*/
if (MaxBlocks == 0) {
return (0);
}
GeomPtr = &InstancePtr->Geometry;
DevDataPtr = GET_PARTDATA(InstancePtr);
/*
* Get the physical address to write the command to and send command.
*/
(void) XFlashGeometry_ToAbsolute(GeomPtr, *Region, *Block, 0,
&BlockAddress);
/*
* Write Block Erase command.
*/
DevDataPtr->SendCmdSeq(GeomPtr->BaseAddress,
XFL_AMD_CMD1_ADDR, XFL_AMD_CMD2_ADDR,
XFL_AMD_CMD1_DATA, XFL_AMD_CMD2_DATA);
DevDataPtr->SendCmd(GeomPtr->BaseAddress,
XFL_AMD_CMD1_ADDR, XFL_AMD_CMD_ERASE1);
DevDataPtr->SendCmdSeq(GeomPtr->BaseAddress,
XFL_AMD_CMD1_ADDR, XFL_AMD_CMD2_ADDR,
XFL_AMD_CMD1_DATA, XFL_AMD_CMD2_DATA);
DevDataPtr->WriteFlash(GeomPtr->BaseAddress, BlockAddress,
XFL_AMD_CMD_ERASE_BLOCK);
/*
* Wait until Program/Erase Controller starts.
*/
while (((DevDataPtr->GetStatus(GeomPtr->BaseAddress,BlockAddress)) &
(XFL_AMD_SR_ERASE_START_MASK)) == NULL);
/*
* Increment Region/Block.
*/
XFL_GEOMETRY_INCREMENT(GeomPtr, *Region, *Block);
/*
* Return the number of blocks enqueued.
*/
return (1);
}
/*****************************************************************************/
/**
*
* This function resumes a suspended operation on a bank of the AMD flash
* device.
*
* @param InstancePtr is the pointer to the XFlash instance.
* @param EraseAddrOff holds the address inside the bank where the
* operation must be resumed.
*
* @return
* - XST_SUCCESS if successful.
* - XST_FAILURE if fail.
*
* @note This API can not be used in application, because Erase API is
* blocking function in this library. If user wants to use this
* feature than Flash library Erase function should be changed such
* Erase API will be non blocking function. In case of non blocking
* Erase API, application must check status of erase operation in
* the application.
*
******************************************************************************/
static int EraseResume(XFlash * InstancePtr, u32 EraseAddrOff)
{
XFlashVendorData_Amd *DevDataPtr;
/*
* Verify inputs are valid.
*/
if(InstancePtr == NULL) {
return (XST_FAILURE);
}
DevDataPtr = GET_PARTDATA(InstancePtr);
/*
* Send the erase resume command.
*/
DevDataPtr->WriteFlash(InstancePtr->Geometry.BaseAddress,
EraseAddrOff, XFL_AMD_CMD_ERASE_RESUME);
return (XST_SUCCESS);
}
/*****************************************************************************/
/**
*
* This function suspends an erase operation on a bank of the AMD flash device.
*
* @param InstancePtr is the pointer to the XFlash instance.
* @param EraseAddrOff holds the address inside the bank where the
* operation must be suspended.
*
* @return
* - XST_SUCCESS if successful.
* - XST_FAILURE if fail.
*
* @note This API can not be used in application, because Erase API is
* blocking function in this library. If user wants to use this
* feature than Flash library Erase function should be changed such
* Erase API will be non blocking function. In case of non blocking
* Erase API, application must check status of erase operation in
* the application.
*
******************************************************************************/
static int EraseSuspend(XFlash * InstancePtr, u32 EraseAddrOff)
{
XFlashVendorData_Amd *DevDataPtr;
/*
* Verify inputs are valid.
*/
if(InstancePtr == NULL) {
return (XST_FAILURE);
}
DevDataPtr = GET_PARTDATA(InstancePtr);
/*
* Send the erase suspend command.
*/
DevDataPtr->WriteFlash(InstancePtr->Geometry.BaseAddress,
EraseAddrOff, XFL_AMD_CMD_ERASE_SUSPEND);
/*
* Wait until Toggle Stops.
*/
(void) DevDataPtr->PollSR(InstancePtr->Geometry.BaseAddress,
EraseAddrOff);
/*
* Return to Read mode.
*/
(void) XFlashAmd_Reset(InstancePtr);
return (XST_SUCCESS);
}
/*****************************************************************************/
/**
*
* This function will make the device to enter into Extended Block Mode, where
* the Extended Block can be read and written, using the Boot block addresses.
*
* @param InstancePtr is the pointer to the XFlash instance.
*
* @return
* None.
*
* @note None.
*
******************************************************************************/
static void EnterExtendedBlockMode(XFlash * InstancePtr)
{
XFlashVendorData_Amd *DevDataPtr;
DevDataPtr = GET_PARTDATA(InstancePtr);
/*
* Issue Enter Extended Block Command.
*/
DevDataPtr->SendCmdSeq(InstancePtr->Geometry.BaseAddress,
XFL_AMD_CMD1_ADDR, XFL_AMD_CMD2_ADDR,
XFL_AMD_CMD1_DATA, XFL_AMD_CMD2_DATA);
DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress,
XFL_AMD_CMD1_ADDR,
XFL_AMD_CMD_ENTER_EXT_MODE);
}
/*****************************************************************************/
/**
*
* This command returns the device to Read mode from Extended Block Mode.
*
* @param InstancePtr is the pointer to the XFlash instance.
*
* @return
* None.
*
* @note None.
*
******************************************************************************/
static void ExitExtendedBlockMode(XFlash * InstancePtr)
{
XFlashVendorData_Amd *DevDataPtr;
DevDataPtr = GET_PARTDATA(InstancePtr);
/*
* Issue Exit Extended Block Command.
*/
DevDataPtr->SendCmdSeq(InstancePtr->Geometry.BaseAddress,
XFL_AMD_CMD1_ADDR, XFL_AMD_CMD2_ADDR,
XFL_AMD_CMD1_DATA, XFL_AMD_CMD2_DATA);
DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress,
XFL_AMD_CMD1_ADDR, XFL_AMD_CMD_EXIT_EXT_MODE);
DevDataPtr->WriteFlash(InstancePtr->Geometry.BaseAddress,
NULL, NULL);
}
/*****************************************************************************/
/**
*
* This function reads the protection status of a block group.
*
* @param InstancePtr is the pointer to the XFlash instance.
* @param Offset is the offset into the device(s) address space from where
* to read protection status.
*
* @return
* - XST_SUCCESS if block is not protected.
* - XFLASH_BLOCK_PROTECTED if block is protected.
* - XFLASH_ADDRESS_ERROR if the destination address range is
* not completely within the addressable areas of the device(s).
* - XST_FAILURE if block protection is unclear.
*
* @note None.
*
******************************************************************************/
static int CheckBlockProtection(XFlash * InstancePtr, u32 Offset)
{
u8 Mode;
u8 AddrMul;
u16 Region;
u16 Block;
u32 Dummy;
u32 BlockAddress;
u32 CmdAddress;
u32 ProtStatus;
int Status;
XFlashGeometry *GeomPtr;
XFlashVendorData_Amd *DevDataPtr;
/*
* Verify inputs are valid.
*/
if(InstancePtr == NULL) {
return (XST_FAILURE);
}
GeomPtr = &InstancePtr->Geometry;
DevDataPtr = GET_PARTDATA(InstancePtr);
Mode = (InstancePtr->Geometry.MemoryLayout &
XFL_LAYOUT_PART_MODE_MASK) >> 8;
if (Mode == 2) {
AddrMul = 1;
}
else if (Mode == 1) {
AddrMul = 2;
}
else {
return (XST_FAILURE);
}
/*
* Convert the starting address to block coordinates. This also verifies
* the starting address is within the instance's address space.
*/
Status = XFlashGeometry_ToBlock(GeomPtr, Offset, &Region, &Block,
&Dummy);
if (Status != XST_SUCCESS) {
return (XFLASH_ADDRESS_ERROR);
}
/*
* Get the physical address to write the command to and send command.
*/
(void) XFlashGeometry_ToAbsolute(GeomPtr, Region, Block, 0,
&BlockAddress);
CmdAddress = BlockAddress | ((XFL_AMD_CMD1_ADDR * AddrMul) + !(
XFL_AMD_CMD1_ADDR & 0x1));
/*
* Send the command.
*/
DevDataPtr->SendCmdSeq(GeomPtr->BaseAddress,
XFL_AMD_CMD1_ADDR, XFL_AMD_CMD2_ADDR,
XFL_AMD_CMD1_DATA, XFL_AMD_CMD2_DATA);
DevDataPtr->WriteFlash(InstancePtr->Geometry.BaseAddress,
CmdAddress, XFL_AMD_CMD_AUTO_SELECT);
/*
* Retrieve Protection Status located at word offset 2.
*/
CmdAddress = BlockAddress + (XFL_AMD_PROT_STATUS_OFFSET * AddrMul);
ProtStatus = DevDataPtr->GetStatus(GeomPtr->BaseAddress, CmdAddress);
if(ProtStatus == XFL_AMD_GROUP_UNPROTECTED) {
Status = XST_SUCCESS;
}
else if(ProtStatus == XFL_AMD_GROUP_PROTECTED) {
Status = XFLASH_BLOCK_PROTECTED;
}
else {
Status = XST_FAILURE;
}
/*
* Return to Read mode.
*/
(void) XFlashAmd_Reset(InstancePtr);
return (Status);
}
/*****************************************************************************/
/**
*
* This routine returns after MicroSeconds have elapsed. It is used in several
* parts of the code to generate a pause required for correct operation of the
* flash part.
*
* @param MicroSeconds is the length of the pause in microseconds.
*
* @return
* None
*
* @note None.
*
******************************************************************************/
static void FlashPause(u32 MicroSeconds)
{
static u32 Counter;
/*
* Compute the count size.
*/
Counter = MicroSeconds * XFL_COUNT_FOR_A_MICROSECOND ;
/*
* Count to the required size.
*/
while(Counter > 0) {
/*
* Count down.
*/
Counter--;
}
}
#endif /* XPAR_XFL_DEVICE_FAMILY_AMD */