/****************************************************************************** * * Copyright (C) 2009 - 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 xnandps_onfi.c * * This module implements the ONFI specific commands. * See xnandps_onfi.h for more information. * * @note None * *
* MODIFICATION HISTORY:
*
* Ver   Who    Date    	   Changes
* ----- ----   ----------  -----------------------------------------------
* 1.00a nm     12/10/2010  First release
* 1.01a nm     28/02/2012  Added support for 8Gb On-Die ECC NAND flash
*                          parts (CR 648463).
*                          Fixed 16-bit issue with ONFI commands like
*                          read, write and read status command.
* 1.03a nm     10/22/2012  Fixed CR# 673348.
* 1.04a nm     04/25/2013  Implemented PR# 699544. Added page cache read
*			   and program commands to ONFI command list.
*			   Reading the cache features during read param page.
* 
* ******************************************************************************/ /***************************** Include Files *********************************/ #include "xnandps_onfi.h" /************************** Constant Definitions *****************************/ /**************************** Type Definitions *******************************/ /***************** Macros (Inline Functions) Definitions *********************/ /************************** Function Prototypes ******************************/ static void Onfi_ReadData(XNandPs *InstancePtr, u8 *Buf, u32 Length); static void Onfi_CmdReset(XNandPs *InstancePtr); static void Onfi_CmdReadId(XNandPs *InstancePtr, u8 Address); static void Onfi_CmdReadParamPage(XNandPs *InstancePtr); static unsigned long Onfi_Crc16(u8 *Buf); static int Onfi_ReadParamPage(XNandPs *InstancePtr, u8 *Buf); extern void XNandPs_SendCommand(XNandPs *InstancePtr, XNandPs_CommandFormat *Command, int Page, int Column); /************************** Variable Definitions *****************************/ /** * This structure defines the onfi command format sent to the flash. */ XNandPs_CommandFormat OnfiCommands[] = { {ONFI_CMD_READ1, ONFI_CMD_READ2, 5, XNANDPS_CMD_PHASE}, /*<< Read command format */ {ONFI_CMD_CHANGE_READ_COLUMN1, ONFI_CMD_CHANGE_READ_COLUMN2, 2, XNANDPS_CMD_PHASE}, /*<< Change Read column format */ {ONFI_CMD_BLOCK_ERASE1, ONFI_CMD_BLOCK_ERASE2, 3, XNANDPS_CMD_PHASE}, /*<Config.FlashWidth == XNANDPS_FLASH_WIDTH_16) Buf[Index] = (u8)Xil_In16(InstancePtr->DataPhaseAddr); else Buf[Index] = Xil_In8(InstancePtr->DataPhaseAddr); } } /**************************************************************************/ /** * * This function writes command data to flash. It is used for writing the * control information like set features. * * @param InstancePtr is a pointer to the XNandPs instance. * @param Buf is the buffer pointer to write the data. * @param Length is the length of data to write. * * @return None * * @note None * ***************************************************************************/ static void Onfi_WriteData(XNandPs *InstancePtr, u8 *Buf, u32 Length) { u32 Index; /* * 8-bit/16-bit access for basic write operations */ for(Index = 0; Index < Length; Index++) { if (InstancePtr->Config.FlashWidth == XNANDPS_FLASH_WIDTH_16) Xil_Out16(InstancePtr->DataPhaseAddr, Buf[Index]); else Xil_Out8(InstancePtr->DataPhaseAddr, Buf[Index]); } } /**************************************************************************/ /** * * This function sends read status command to the flash device. * * @param InstancePtr is a pointer to the XNandPs instance. * * @return flash status value read * * @note None * ***************************************************************************/ u8 Onfi_CmdReadStatus(XNandPs *InstancePtr) { u8 Status; XNandPs_SendCommand(InstancePtr, &OnfiCommands[READ_STATUS], XNANDPS_PAGE_NOT_VALID, XNANDPS_COLUMN_NOT_VALID); if(InstancePtr->Config.FlashWidth == XNANDPS_FLASH_WIDTH_16) Status = (u8) Xil_In16(InstancePtr->DataPhaseAddr); else Status = Xil_In8(InstancePtr->DataPhaseAddr); return Status; } /**************************************************************************/ /** * * This function sends reset command to the flash device. * * @param InstancePtr is a pointer to the XNandPs instance. * * @return None * * @note None * ***************************************************************************/ static void Onfi_CmdReset(XNandPs *InstancePtr) { u8 Status; XNandPs_SendCommand(InstancePtr, &OnfiCommands[RESET], XNANDPS_PAGE_NOT_VALID, XNANDPS_COLUMN_NOT_VALID); /* * Check the Status Register SR[6] */ do { Status = Onfi_CmdReadStatus(InstancePtr); }while ((Status & ONFI_STATUS_RDY) != ONFI_STATUS_RDY); } /**************************************************************************/ /** * * This function sends read ID command to the flash device. * * @param InstancePtr is a pointer to the XNandPs instance. * * @return None * * @note None * ***************************************************************************/ static void Onfi_CmdReadId(XNandPs *InstancePtr, u8 Address) { XNandPs_SendCommand(InstancePtr, &OnfiCommands[READ_ID], XNANDPS_PAGE_NOT_VALID, Address); } /**************************************************************************/ /** * * This function sends read parameter page command to the flash device. * * @param InstancePtr is a pointer to the XNandPs instance. * * @return None * * @note None * ***************************************************************************/ static void Onfi_CmdReadParamPage(XNandPs *InstancePtr) { u8 Status; u32 ZeroCommand; XNandPs_SendCommand(InstancePtr, &OnfiCommands[READ_PARAM_PAGE], XNANDPS_PAGE_NOT_VALID, 0x00); /* * Check the Status Register SR[6] */ do { Status = Onfi_CmdReadStatus(InstancePtr); }while ((Status & ONFI_STATUS_RDY) != ONFI_STATUS_RDY); /* * ONFI : Reissue the 0x00 on the command line to start reading data */ ZeroCommand = InstancePtr->Config.FlashBase | (0 << XNANDPS_ADDR_CYCLES_SHIFT)| (0 << XNANDPS_END_CMD_VALID_SHIFT)| (XNANDPS_COMMAND_PHASE_MASK)| (0 << XNANDPS_END_CMD_SHIFT)| (0 << XNANDPS_START_CMD_SHIFT); /* * Dummy AXI transaction for sending command 0x00 to the flash */ Xil_Out32(ZeroCommand, 0x0); } /**************************************************************************/ /** * * This function sends Get Feature command to the flash device. * * @param InstancePtr is a pointer to the XNandPs instance. * @param Feature is the feature value to read. * * @return None * * @note None * ***************************************************************************/ static void Onfi_GetFeature(XNandPs *InstancePtr, u8 Feature, u8 *Val) { u8 Status; u32 ZeroCommand; XNandPs_SendCommand(InstancePtr, &OnfiCommands[GET_FEATURES], XNANDPS_PAGE_NOT_VALID, Feature); /* * Check the Status Register SR[6] */ do { Status = Onfi_CmdReadStatus(InstancePtr); }while ((Status & ONFI_STATUS_RDY) != ONFI_STATUS_RDY); /* * ONFI 2.3: Reissue the 0x00 on the command line to start reading * data. */ ZeroCommand = InstancePtr->Config.FlashBase | (0 << XNANDPS_ADDR_CYCLES_SHIFT)| (0 << XNANDPS_END_CMD_VALID_SHIFT)| (XNANDPS_COMMAND_PHASE_MASK)| (0 << XNANDPS_END_CMD_SHIFT)| (0 << XNANDPS_START_CMD_SHIFT); /* * Dummy AXI transaction for sending command 0x00 to the flash */ Xil_Out32(ZeroCommand, 0x00); /* * Read the feature value */ Onfi_ReadData(InstancePtr, Val, 4); } /**************************************************************************/ /** * * This function sends Set Feature command to the flash device. * * @param InstancePtr is a pointer to the XNandPs instance. * @param Feature is the feature value to Set. * * @return None * * @note None * ***************************************************************************/ static void Onfi_SetFeature(XNandPs *InstancePtr, u8 Feature, u8 *Val) { u8 Status; XNandPs_SendCommand(InstancePtr, &OnfiCommands[SET_FEATURES], XNANDPS_PAGE_NOT_VALID, Feature); Onfi_WriteData(InstancePtr, Val, 4); /* * Check the Status Register SR[6] */ do { Status = Onfi_CmdReadStatus(InstancePtr); }while ((Status & ONFI_STATUS_RDY) != ONFI_STATUS_RDY); } /**************************************************************************/ /** * * This function calculates the CRC on the parameter page buffer. This is taken * from the ONFI 1.0 specification. * * @param Buf is the parameter page buffer. * * @return CRC value calculated. * * @note None * ***************************************************************************/ static unsigned long Onfi_Crc16(u8 *Buf) { const int Order = ONFI_CRC_ORDER; const unsigned long Polynom = ONFI_CRC_POLYNOM; u32 Crc = ONFI_CRC_INIT; u32 Index; u32 j; u32 c; u32 Bit; u32 DataIn; int DataByteCount = 0; u32 CrcMask = ((((u32)1 << (Order - 1)) -1) << 1) | 1; u32 CrcHighBit = (u32)1 << (Order - 1); /* * CRC covers the data bytes between byte 0 and byte 253 (ONFI 1.0, sec * 5.4.1.36) */ for(Index = 0; Index < ONFI_CRC_LEN; Index++) { DataIn = Buf[Index]; c = (u32)DataIn; DataByteCount++; for(j = 0x80; j; j >>= 1) { Bit = Crc & CrcHighBit; Crc <<= 1; if (c & j) Bit ^= CrcHighBit; if (Bit) Crc ^= Polynom; } Crc &= CrcMask; } return Crc; } /**************************************************************************/ /** * * This function reads the NAND flash parameter page defined by ONFI 1.0 * specfication. * * @param InstancePtr is a pointer to the XNandPs instance. * @param Buf is a buffer pointer to fill the data. * * @return * - XST_SUCCESS if parameter page read successfully. * - XST_FAILURE if parameter page is not read successfully. * * @note None * ***************************************************************************/ static int Onfi_ReadParamPage(XNandPs *InstancePtr, u8 *Buf) { u32 Index; u32 CrcCalc; OnfiNand_Geometry *Geometry; /* * Read the first 256 bytes of parameter page */ Onfi_CmdReadParamPage(InstancePtr); /* Read the 3 mandatory parameter pages */ for(Index = 0; Index < 3; Index++) { Onfi_ReadData(InstancePtr, Buf, ONFI_PARAM_PAGE_LEN); Geometry = (OnfiNand_Geometry *)Buf; /* Check the CRC */ CrcCalc = Onfi_Crc16(Buf); if(CrcCalc == Geometry->Crc) { break; } } if (Index == 3) { return XST_FAILURE; } return XST_SUCCESS; } /**************************************************************************/ /** * * This function initializes the NAND flash and gets the geometry information. * * @param InstancePtr is a pointer to the XNandPs instance. * * @return * - XST_SUCCESS if successful. * - XST_FAILURE if failed. * * @note None * ***************************************************************************/ int Onfi_NandInit(XNandPs *InstancePtr) { u32 Target; int Status; u8 Id[ONFI_ID_LEN]; u8 JedecId[2]; u8 EccSetFeature[4] = {0x08, 0x00, 0x00, 0x00}; u8 EccGetFeature[4]; OnfiNand_Geometry Nand_Geometry; Xil_AssertNonvoid(InstancePtr != NULL); for(Target=0; Target < XNANDPS_MAX_TARGETS; Target++) { /* * Reset the target */ Onfi_CmdReset(InstancePtr); /* * Read the ONFI ID */ Onfi_CmdReadId(InstancePtr, 0x20); Onfi_ReadData(InstancePtr, &Id[0], ONFI_ID_LEN); /* * Check the ONFI signature to know that the target supports * ONFI */ if (Id[0]=='O' && Id[1]=='N' && Id[2]=='F' && Id[3]=='I') { /* Read the parameter page structure */ Status = Onfi_ReadParamPage(InstancePtr, (u8 *)&Nand_Geometry); if (Status != XST_FAILURE) { InstancePtr->Geometry.NumLun = Nand_Geometry.NumLuns; InstancePtr->Geometry.PagesPerBlock = Nand_Geometry.PagesPerBlock; InstancePtr->Geometry.SpareBytesPerPage = Nand_Geometry.SpareBytesPerPage; InstancePtr->Geometry.BytesPerPage = Nand_Geometry.BytesPerPage; InstancePtr->Geometry.BlocksPerLun = Nand_Geometry.BlocksPerLun; InstancePtr->Geometry.NumBlocks = (Nand_Geometry.NumLuns * InstancePtr->Geometry.BlocksPerLun); InstancePtr->Geometry.NumPages = (Nand_Geometry.NumLuns * Nand_Geometry.BlocksPerLun * Nand_Geometry.PagesPerBlock); InstancePtr->Geometry.BlockSize = (Nand_Geometry.PagesPerBlock * Nand_Geometry.BytesPerPage); InstancePtr->Geometry.DeviceSize = (InstancePtr->Geometry.NumBlocks * InstancePtr->Geometry.PagesPerBlock * InstancePtr->Geometry.BytesPerPage); /* * Calculate the address cycles */ InstancePtr->Geometry.RowAddrCycles = (Nand_Geometry.AddrCycles & 0xf); InstancePtr->Geometry.ColAddrCycles = ((Nand_Geometry.AddrCycles >> 4) & 0xf); OnfiCommands[READ].AddrCycles = (InstancePtr->Geometry.RowAddrCycles + InstancePtr->Geometry.ColAddrCycles); OnfiCommands[PAGE_PROGRAM].AddrCycles = (InstancePtr->Geometry.RowAddrCycles + InstancePtr->Geometry.ColAddrCycles); OnfiCommands[BLOCK_ERASE].AddrCycles = InstancePtr->Geometry.RowAddrCycles; OnfiCommands[CHANGE_READ_COLUMN].AddrCycles = InstancePtr->Geometry.ColAddrCycles; OnfiCommands[CHANGE_WRITE_COLUMN].AddrCycles = InstancePtr->Geometry.ColAddrCycles; /* * Read JEDEC ID */ Onfi_CmdReadId(InstancePtr, 0x00); Onfi_ReadData(InstancePtr, &JedecId[0], 2); if ((JedecId[0] == 0x2C) && /* 1 Gb flash devices */ ((JedecId[1] == 0xF1) || (JedecId[1] == 0xA1) || (JedecId[1] == 0xB1) || /* 2 Gb flash devices */ (JedecId[1] == 0xAA) || (JedecId[1] == 0xBA) || (JedecId[1] == 0xDA) || (JedecId[1] == 0xCA) || /* 4 Gb flash devices */ (JedecId[1] == 0xAC) || (JedecId[1] == 0xBC) || (JedecId[1] == 0xDC) || (JedecId[1] == 0xCC) || /* 8 Gb flash devices */ (JedecId[1] == 0xA3) || (JedecId[1] == 0xB3) || (JedecId[1] == 0xD3) || (JedecId[1] == 0xC3))) { /* * Check if this flash supports On-Die ECC. * Micron Flash: MT29F1G08ABADA, MT29F1G08ABBDA * MT29F1G16ABBDA, * MT29F2G08ABBEA, MT29F2G16ABBEA, * MT29F2G08ABAEA, MT29F2G16ABAEA, * MT29F4G08ABBDA, MT29F4G16ABBDA, * MT29F4G08ABADA, MT29F4G16ABADA, * MT29F8G08ADBDA, MT29F8G16ADBDA, * MT29F8G08ADADA, MT29F8G16ADADA */ Onfi_SetFeature(InstancePtr, 0x90, &EccSetFeature[0]); /* Check to see if ECC feature is set */ Onfi_GetFeature(InstancePtr, 0x90, &EccGetFeature[0]); if (EccGetFeature[0] & 0x08) { InstancePtr->EccMode = XNANDPS_ECC_ONDIE; } else { InstancePtr->EccMode = XNANDPS_ECC_HW; } } else if (Nand_Geometry.BytesPerPage < 512 || Nand_Geometry.BytesPerPage > 2048) { /* * This controller doesn't support ECC for * page size < 512 & > 2048 bytes. */ InstancePtr->EccMode = XNANDPS_ECC_NONE; } else { /* SMC controller ECC (1-bit correction) */ InstancePtr->EccMode = XNANDPS_ECC_HW; } /* * Updating the instance flash width after checking * for on-die ECC */ InstancePtr->Geometry.FlashWidth = (Nand_Geometry.Features & 0x1) ? XNANDPS_FLASH_WIDTH_16 : XNANDPS_FLASH_WIDTH_8; /* * Features and Optional commands supported. * On-Die ECC flash doesn't support these * commands when ECC is enabled. */ if (InstancePtr->EccMode != XNANDPS_ECC_ONDIE) { InstancePtr->Features.ProgramCache = (Nand_Geometry.OptionalCmds & 0x1) ? 1:0; InstancePtr->Features.ReadCache = (Nand_Geometry.OptionalCmds & 0x2) ? 1:0; } } else { return XST_FAILURE; } } else { return XST_FAILURE; } } return XST_SUCCESS; }