/******************************************************************************
*
* 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.
*
* Even with the performance boosting optimizations, the overhead
* associated is rather high due to the general purpose nature of its
* design.
*
* 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.
*
* 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.
*
*
* 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. ** ******************************************************************************/ /***************************** 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 */