From 31c7177fc41b32ac832d8880b8486a935db910c0 Mon Sep 17 00:00:00 2001 From: Shakti Bhatnagar Date: Mon, 2 Feb 2015 10:21:09 +0530 Subject: [PATCH] nandps_v2_2: Deprecated exiting version of nandps driver, Added new version. Deprecated existing version v2_1, Added new version V2_2. Signed-off-by: Shakti Bhatnagar --- .../drivers/nandps/data/nandps.mdd | 42 + .../drivers/nandps/data/nandps.tcl | 194 ++ .../drivers/nandps/examples/index.html | 19 + .../nandps/examples/xnandps_cache_example.c | 258 +++ .../drivers/nandps/examples/xnandps_example.c | 255 +++ .../nandps/examples/xnandps_skip_example.c | 514 +++++ .../drivers/nandps/src/Makefile | 40 + .../drivers/nandps/src/xnandps.c | 1963 +++++++++++++++++ .../drivers/nandps/src/xnandps.h | 447 ++++ .../drivers/nandps/src/xnandps_bbm.c | 869 ++++++++ .../drivers/nandps/src/xnandps_bbm.h | 185 ++ .../drivers/nandps/src/xnandps_g.c | 84 + .../drivers/nandps/src/xnandps_hw.h | 570 +++++ .../drivers/nandps/src/xnandps_onfi.c | 654 ++++++ .../drivers/nandps/src/xnandps_onfi.h | 314 +++ .../drivers/nandps/src/xnandps_sinit.c | 98 + 16 files changed, 6506 insertions(+) create mode 100755 XilinxProcessorIPLib/drivers/nandps/data/nandps.mdd create mode 100755 XilinxProcessorIPLib/drivers/nandps/data/nandps.tcl create mode 100755 XilinxProcessorIPLib/drivers/nandps/examples/index.html create mode 100755 XilinxProcessorIPLib/drivers/nandps/examples/xnandps_cache_example.c create mode 100755 XilinxProcessorIPLib/drivers/nandps/examples/xnandps_example.c create mode 100755 XilinxProcessorIPLib/drivers/nandps/examples/xnandps_skip_example.c create mode 100755 XilinxProcessorIPLib/drivers/nandps/src/Makefile create mode 100755 XilinxProcessorIPLib/drivers/nandps/src/xnandps.c create mode 100755 XilinxProcessorIPLib/drivers/nandps/src/xnandps.h create mode 100755 XilinxProcessorIPLib/drivers/nandps/src/xnandps_bbm.c create mode 100755 XilinxProcessorIPLib/drivers/nandps/src/xnandps_bbm.h create mode 100755 XilinxProcessorIPLib/drivers/nandps/src/xnandps_g.c create mode 100755 XilinxProcessorIPLib/drivers/nandps/src/xnandps_hw.h create mode 100755 XilinxProcessorIPLib/drivers/nandps/src/xnandps_onfi.c create mode 100755 XilinxProcessorIPLib/drivers/nandps/src/xnandps_onfi.h create mode 100755 XilinxProcessorIPLib/drivers/nandps/src/xnandps_sinit.c diff --git a/XilinxProcessorIPLib/drivers/nandps/data/nandps.mdd b/XilinxProcessorIPLib/drivers/nandps/data/nandps.mdd new file mode 100755 index 00000000..29bbc423 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/nandps/data/nandps.mdd @@ -0,0 +1,42 @@ +############################################################################### +# +# 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. +# +############################################################################### +OPTION psf_version = 2.1; + +BEGIN driver nandps + + OPTION supported_peripherals = (ps7_nand); + OPTION driver_state = ACTIVE; + OPTION copyfiles = all; + OPTION VERSION = 2.2; + OPTION NAME = nandps; + +END driver diff --git a/XilinxProcessorIPLib/drivers/nandps/data/nandps.tcl b/XilinxProcessorIPLib/drivers/nandps/data/nandps.tcl new file mode 100755 index 00000000..4dfb4233 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/nandps/data/nandps.tcl @@ -0,0 +1,194 @@ +############################################################################### +# +# Copyright (C) 2012 - 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. +# +############################################################################### +############################################################################## +# +# Modification History +# +# Ver Who Date Changes +# ----- ---- -------- ----------------------------------------------- +# 1.00a sdm 11/22/11 Created +# 2.0 adk 12/10/13 Updated as per the New Tcl API's +# +############################################################################## + +#uses "xillib.tcl" + +proc generate {drv_handle} { + xdefine_zynq_include_file $drv_handle "xparameters.h" "XNandPs" "NUM_INSTANCES" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_S_AXI_HIGHADDR" "C_NAND_CLK_FREQ_HZ" "C_SMC_BASEADDR" "C_NAND_WIDTH" + + xdefine_zynq_config_file $drv_handle "xnandps_g.c" "XNandPs" "DEVICE_ID" "C_SMC_BASEADDR" "C_S_AXI_BASEADDR" "C_NAND_WIDTH" + + xdefine_zynq_canonical_xpars $drv_handle "xparameters.h" "XNandPs" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_S_AXI_HIGHADDR" "C_NAND_CLK_FREQ_HZ" "C_SMC_BASEADDR" "C_NAND_WIDTH" + +} + + +# +# Given a list of arguments, define them all in an include file. +# Similar to proc xdefine_include_file, except that uses regsub +# to replace "S_AXI_" with "". +# +proc xdefine_zynq_include_file {drv_handle file_name drv_string args} { + # Open include file + set file_handle [::hsi::utils::open_include_file $file_name] + + # Get all peripherals connected to this driver + set periphs [::hsi::utils::get_common_driver_ips $drv_handle] + + # Handle special cases + set arg "NUM_INSTANCES" + set posn [lsearch -exact $args $arg] + if {$posn > -1} { + puts $file_handle "/* Definitions for driver [string toupper [common::get_property NAME $drv_handle]] */" + # Define NUM_INSTANCES + puts $file_handle "#define [::hsi::utils::get_driver_param_name $drv_string $arg] [llength $periphs]" + set args [lreplace $args $posn $posn] + } + # Check if it is a driver parameter + + lappend newargs + foreach arg $args { + set value [common::get_property CONFIG.$arg $drv_handle] + if {[llength $value] == 0} { + lappend newargs $arg + } else { + puts $file_handle "#define [::hsi::utils::get_driver_param_name $drv_string $arg] [common::get_property CONFIG.$arg $drv_handle]" + } + } + set args $newargs + + # Print all parameters for all peripherals + set device_id 0 + foreach periph $periphs { + puts $file_handle "" + puts $file_handle "/* Definitions for peripheral [string toupper [common::get_property NAME $periph]] */" + foreach arg $args { + if {[string compare -nocase "DEVICE_ID" $arg] == 0} { + set value $device_id + incr device_id + } elseif {[string compare -nocase "C_SMC_BASEADDR" $arg] == 0} { + set value 0xE000E000 + } else { + set value [::hsi::utils::get_param_value $periph $arg] + } + if {[llength $value] == 0} { + set value 0 + } + set value [::hsi::utils::format_addr_string $value $arg] + set arg_name [::hsi::utils::get_ip_param_name $periph $arg] + regsub "S_AXI_" $arg_name "" arg_name + if {[string compare -nocase "HW_VER" $arg] == 0} { + puts $file_handle "#define $arg_name \"$value\"" + } else { + puts $file_handle "#define $arg_name $value" + } + } + puts $file_handle "" + } + puts $file_handle "\n/******************************************************************/\n" + close $file_handle +} + +#----------------------------------------------------------------------------- +# xdefine_zynq_canonical_xpars - Used to print out canonical defines for a driver. +# Similar to proc xdefine_config_file, except that uses regsub to replace "S_AXI_" +# with "". +#----------------------------------------------------------------------------- +proc xdefine_zynq_canonical_xpars {drv_handle file_name drv_string args} { + # Open include file + set file_handle [::hsi::utils::open_include_file $file_name] + + # Get all the peripherals connected to this driver + set periphs [::hsi::utils::get_common_driver_ips $drv_handle] + + # Get the names of all the peripherals connected to this driver + foreach periph $periphs { + set peripheral_name [string toupper [common::get_property NAME $periph]] + lappend peripherals $peripheral_name + } + + # Get possible canonical names for all the peripherals connected to this + # driver + set device_id 0 + foreach periph $periphs { + set canonical_name [string toupper [format "%s_%s" $drv_string $device_id]] + lappend canonicals $canonical_name + + # Create a list of IDs of the peripherals whose hardware instance name + # doesn't match the canonical name. These IDs can be used later to + # generate canonical definitions + if { [lsearch $peripherals $canonical_name] < 0 } { + lappend indices $device_id + } + incr device_id + } + + set i 0 + foreach periph $periphs { + set periph_name [string toupper [common::get_property NAME $periph]] + + # Generate canonical definitions only for the peripherals whose + # canonical name is not the same as hardware instance name + if { [lsearch $canonicals $periph_name] < 0 } { + puts $file_handle "/* Canonical definitions for peripheral $periph_name */" + set canonical_name [format "%s_%s" $drv_string [lindex $indices $i]] + + foreach arg $args { + set lvalue [::hsi::utils::get_driver_param_name $canonical_name $arg] + # replace S_SXI_ with CPU_. This is a temporary fix. Revist when the + # S_AXI_DIST_BASEADDR is generated by the tools + regsub "S_AXI_" $lvalue "CPU_" lvalue + + # The commented out rvalue is the name of the instance-specific constant + # set rvalue [::hsi::utils::get_ip_param_name $periph $arg] + # The rvalue set below is the actual value of the parameter + if {[string compare -nocase "C_SMC_BASEADDR" $arg] == 0} { + set rvalue 0xE000E000 + } else { + set rvalue [::hsi::utils::get_param_value $periph $arg] + } + if {[llength $rvalue] == 0} { + set rvalue 0 + } + set rvalue [::hsi::utils::format_addr_string $rvalue $arg] + + puts $file_handle "#define $lvalue $rvalue" + + } + puts $file_handle "" + incr i + } + } + + puts $file_handle "\n/******************************************************************/\n" + close $file_handle +} diff --git a/XilinxProcessorIPLib/drivers/nandps/examples/index.html b/XilinxProcessorIPLib/drivers/nandps/examples/index.html new file mode 100755 index 00000000..6baefaaf --- /dev/null +++ b/XilinxProcessorIPLib/drivers/nandps/examples/index.html @@ -0,0 +1,19 @@ + + + + + +Driver example applications + + + +

Example Applications for the driver nandps_v2_1

+
+ +

Copyright � 2009-2014 Xilinx, Inc. All rights reserved.

+ + diff --git a/XilinxProcessorIPLib/drivers/nandps/examples/xnandps_cache_example.c b/XilinxProcessorIPLib/drivers/nandps/examples/xnandps_cache_example.c new file mode 100755 index 00000000..df59fc06 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/nandps/examples/xnandps_cache_example.c @@ -0,0 +1,258 @@ +/****************************************************************************** +* +* Copyright (C) 2013 - 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_cache_example.c +** +* This file contains a design example using the NAND driver (XNandPs). +* This example tests NAND page cache read and write commands. The page cache +* commands are not supported by OnDie ECC flash since ECC is enabled by +* default. Tested Spansion S34ML04G100TFI00 flash with this example. +* +* This example tests the block erase, block read and block write features. +* The flash blocks are erased and written. The data is read back and compared +* with the data written for correctness. The bad blocks are not erased/programmed. +* +* @note +* +* None. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date        Changes
+* ----- ---- ----------  -----------------------------------------------
+* 1.00  nm   04/25/2013  First release.
+*
+*
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include +#include +#include +#include +#include +#include +#include +/************************** Constant Definitions *****************************/ +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define NAND_DEVICE_ID XPAR_XNANDPS_0_DEVICE_ID +/* Test parameters */ +#define NAND_TEST_START_BLOCK 64 /**< Starting block to test */ +#define NAND_TEST_NUM_BLOCKS 16 /**< Number of blocks to test */ +#define NAND_TEST_BLOCK_SIZE 0x20000 /**< Test Block Size, must be same as + the flash block size */ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +int NandReadWriteCacheExample(u32 NandDeviceId); + +/************************** Variable Definitions *****************************/ +XNandPs NandInstance; /* XNand Instance. */ +XNandPs *NandInstPtr = &NandInstance; +/* + * Buffers used during read and write transactions. + */ +u8 ReadBuffer[NAND_TEST_BLOCK_SIZE]; /**< Block sized Read buffer */ +u8 WriteBuffer[NAND_TEST_BLOCK_SIZE]; /**< Block sized write buffer */ +/************************** Function Definitions ******************************/ + +/****************************************************************************/ +/** +* +* Main function to execute the Nand Flash read write example. +* +* @param None. +* +* @return +* - XST_SUCCESS if the example has completed successfully. +* - XST_FAILURE if the example has failed. +* +* @note None. +* +*****************************************************************************/ +int main(void) +{ + int Status; + + xil_printf("Nand Flash Read Write Example Test\r\n"); + /* + * Run the NAND read write example, specify the Base Address that + * is generated in xparameters.h . + */ + Status = NandReadWriteCacheExample(NAND_DEVICE_ID); + + if (Status != XST_SUCCESS) { + xil_printf("Nand Flash Read Write Example Test Failed\r\n"); + return XST_FAILURE; + } + + xil_printf("Successfully ran Nand Flash Read Write Example Test\r\n"); + + return XST_SUCCESS; +} + +/****************************************************************************/ +/** +* +* This function runs a test on the NAND flash device using the basic driver +* functions. +* The function does the following tasks: +* - Initialize the driver. +* - Erase the blocks. +* - Write in to all the blocks. +* - Read back the data from the blocks. +* - Compare the data read against the data Written. +* +* @param NandDeviceId is is the XPAR__DEVICE_ID value +* from xparameters.h. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note When bad blocks are encountered, they are not erased and +* programmed. +* +****************************************************************************/ +int NandReadWriteCacheExample(u32 NandDeviceId) +{ + int Status; + u32 Index; + u32 BlockIndex; + XNandPs_Config *ConfigPtr; + u64 Offset; + u32 Length; + u32 StartBlock; + u32 EndBlock; + + /* + * Initialize the flash driver. + */ + ConfigPtr = XNandPs_LookupConfig(NandDeviceId); + if (ConfigPtr == NULL) { + return XST_FAILURE; + } + + Status = XNandPs_CfgInitialize(NandInstPtr, ConfigPtr, + ConfigPtr->SmcBase,ConfigPtr->FlashBase); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + StartBlock = NAND_TEST_START_BLOCK; + EndBlock = NAND_TEST_START_BLOCK + NAND_TEST_NUM_BLOCKS; + Length = NAND_TEST_BLOCK_SIZE; + /* + * Prepare the write buffer. Fill in the data need to be written into + * Flash Device. + */ + for (Index = 0; Index < Length; Index++) { + WriteBuffer[Index] = Index % 256; + } + + /* + * Erase the blocks in the flash + */ + for (BlockIndex = StartBlock; BlockIndex < EndBlock; BlockIndex++) { + /* + * Don't erase bad blocks. + */ + if (XNandPs_IsBlockBad(NandInstPtr, BlockIndex) == XST_SUCCESS) + { + continue; + } + /* + * Perform erase operation. + */ + Status = XNandPs_EraseBlock(NandInstPtr, BlockIndex); + if (Status != XST_SUCCESS) { + return Status; + } + } + + /* + * Perform the read/write operation + */ + for (BlockIndex = StartBlock; BlockIndex < EndBlock; BlockIndex++) { + /* + * Don't program bad blocks. + */ + if (XNandPs_IsBlockBad(NandInstPtr, BlockIndex) == XST_SUCCESS) + { + continue; + } + Offset = BlockIndex * NandInstPtr->Geometry.BlockSize; + + /* + * Perform the write operation. + */ + Status = XNandPs_WriteCache(NandInstPtr, Offset, Length, WriteBuffer, NULL); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Perform the read operation. + */ + Status = XNandPs_ReadCache(NandInstPtr, Offset, Length, ReadBuffer, NULL); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Compare the data read against the data Written. + */ + for (Index = 0; Index < Length; Index++) { + if (ReadBuffer[Index] != WriteBuffer[Index]) { + return XST_FAILURE; + } + } + + /* + * Clear the Receive buffer for next iteration + */ + memset(ReadBuffer, 0, Length); + } + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/nandps/examples/xnandps_example.c b/XilinxProcessorIPLib/drivers/nandps/examples/xnandps_example.c new file mode 100755 index 00000000..8fa27542 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/nandps/examples/xnandps_example.c @@ -0,0 +1,255 @@ +/****************************************************************************** +* +* 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_example.c +** +* This file contains a design example using the NAND driver (XNandPs). +* This example tests the block erase, block read and block write features. +* The flash blocks are erased and written. The data is read back and compared +* with the data written for correctness. The bad blocks are not erased/programmed. +* +* @note +* +* None. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date        Changes
+* ----- ---- ----------  -----------------------------------------------
+* 1.00  nm   12/10/2010  First release.
+* 1.01a nm   28/02/2012  Modified the test offsets.
+*
+*
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include +#include +#include +#include +#include +#include +#include +/************************** Constant Definitions *****************************/ +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define NAND_DEVICE_ID XPAR_XNANDPS_0_DEVICE_ID +/* Test parameters */ +#define NAND_TEST_START_BLOCK 64 /**< Starting block to test */ +#define NAND_TEST_NUM_BLOCKS 16 /**< Number of blocks to test */ +#define NAND_TEST_BLOCK_SIZE 0x20000 /**< Test Block Size, must be same as + the flash block size */ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +int NandReadWriteExample(u32 NandDeviceId); + +/************************** Variable Definitions *****************************/ +XNandPs NandInstance; /* XNand Instance. */ +XNandPs *NandInstPtr = &NandInstance; +/* + * Buffers used during read and write transactions. + */ +u8 ReadBuffer[NAND_TEST_BLOCK_SIZE]; /**< Block sized Read buffer */ +u8 WriteBuffer[NAND_TEST_BLOCK_SIZE]; /**< Block sized write buffer */ +/************************** Function Definitions ******************************/ + +/****************************************************************************/ +/** +* +* Main function to execute the Nand Flash read write example. +* +* @param None. +* +* @return +* - XST_SUCCESS if the example has completed successfully. +* - XST_FAILURE if the example has failed. +* +* @note None. +* +*****************************************************************************/ +int main(void) +{ + int Status; + + xil_printf("Nand Flash Read Write Example Test\r\n"); + /* + * Run the NAND read write example, specify the Base Address that + * is generated in xparameters.h . + */ + Status = NandReadWriteExample(NAND_DEVICE_ID); + + if (Status != XST_SUCCESS) { + xil_printf("Nand Flash Read Write Example Test Failed\r\n"); + return XST_FAILURE; + } + + xil_printf("Successfully ran Nand Flash Read Write Example Test\r\n"); + + return XST_SUCCESS; +} + +/****************************************************************************/ +/** +* +* This function runs a test on the NAND flash device using the basic driver +* functions. +* The function does the following tasks: +* - Initialize the driver. +* - Erase the blocks. +* - Write in to all the blocks. +* - Read back the data from the blocks. +* - Compare the data read against the data Written. +* +* @param NandDeviceId is is the XPAR__DEVICE_ID value +* from xparameters.h. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note When bad blocks are encountered, they are not erased and +* programmed. +* +****************************************************************************/ +int NandReadWriteExample(u32 NandDeviceId) +{ + int Status; + u32 Index; + u32 BlockIndex; + XNandPs_Config *ConfigPtr; + u64 Offset; + u32 Length; + u32 StartBlock; + u32 EndBlock; + + /* + * Initialize the flash driver. + */ + ConfigPtr = XNandPs_LookupConfig(NandDeviceId); + if (ConfigPtr == NULL) { + return XST_FAILURE; + } + + Status = XNandPs_CfgInitialize(NandInstPtr, ConfigPtr, + ConfigPtr->SmcBase,ConfigPtr->FlashBase); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + StartBlock = NAND_TEST_START_BLOCK; + EndBlock = NAND_TEST_START_BLOCK + NAND_TEST_NUM_BLOCKS; + Length = NAND_TEST_BLOCK_SIZE; + /* + * Prepare the write buffer. Fill in the data need to be written into + * Flash Device. + */ + for (Index = 0; Index < Length; Index++) { + WriteBuffer[Index] = Index % 256; + } + + /* + * Erase the blocks in the flash + */ + for (BlockIndex = StartBlock; BlockIndex < EndBlock; BlockIndex++) { + /* + * Don't erase bad blocks. + */ + if (XNandPs_IsBlockBad(NandInstPtr, BlockIndex) == XST_SUCCESS) + { + continue; + } + /* + * Perform erase operation. + */ + Status = XNandPs_EraseBlock(NandInstPtr, BlockIndex); + if (Status != XST_SUCCESS) { + return Status; + } + } + + /* + * Perform the read/write operation + */ + for (BlockIndex = StartBlock; BlockIndex < EndBlock; BlockIndex++) { + /* + * Don't program bad blocks. + */ + if (XNandPs_IsBlockBad(NandInstPtr, BlockIndex) == XST_SUCCESS) + { + continue; + } + Offset = BlockIndex * NandInstPtr->Geometry.BlockSize; + + /* + * Perform the write operation. + */ + Status = XNandPs_Write(NandInstPtr, Offset, Length, WriteBuffer, NULL); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Perform the read operation. + */ + Status = XNandPs_Read(NandInstPtr, Offset, Length, ReadBuffer, NULL); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Compare the data read against the data Written. + */ + for (Index = 0; Index < Length; Index++) { + if (ReadBuffer[Index] != WriteBuffer[Index]) { + return XST_FAILURE; + } + } + + /* + * Clear the Receive buffer for next iteration + */ + memset(ReadBuffer, 0, Length); + } + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/nandps/examples/xnandps_skip_example.c b/XilinxProcessorIPLib/drivers/nandps/examples/xnandps_skip_example.c new file mode 100755 index 00000000..00139e69 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/nandps/examples/xnandps_skip_example.c @@ -0,0 +1,514 @@ +/****************************************************************************** +* +* 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_skip_example.c +** +* This file contains a design example using the NAND driver (XNandPs). +* This example tests the skip block method of erase/read/write operations. +* The skip block method is useful while reading/writing images on to the flash. +* The flash is erased and programming by considering the bad blocks. The data is +* read back and compared with the data written for correctness. +* +* @note +* +* None. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date         Changes
+* ----- ---- ----------   -----------------------------------------------
+* 1.00  nm   12/10/2010   First release
+* 1.01a nm   28/02/2012   Modified the test offsets.
+*
+*
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include +#include +#include +#include +#include +#include +#include +/************************** Constant Definitions *****************************/ +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define NAND_DEVICE_ID XPAR_XNANDPS_0_DEVICE_ID +/* Test parameters */ +#define NAND_TEST_OFFSET 0x01000000 /**< Flash Test Offset */ +#define NAND_TEST_LENGTH 0x00080000 /**< Test Length */ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +int NandSkipBlockExample(u32 NandDeviceId); + +int XNandPs_SkipRead(XNandPs *InstancePtr, u64 Offset, u32 Length, void + *DestPtr); + +int XNandPs_SkipWrite(XNandPs *InstancePtr, u64 Offset, u32 Length, void + *SrcPtr); + +int XNandPs_SkipErase(XNandPs *InstancePtr, u64 Offset, u32 Length); + +/************************** Variable Definitions *****************************/ +XNandPs NandInstance; /* XNand Instance. */ +XNandPs *NandInstPtr = &NandInstance; +/* + * Buffers used during read and write transactions. + */ +u8 ReadBuffer[NAND_TEST_LENGTH]; +u8 WriteBuffer[NAND_TEST_LENGTH]; +/************************** Function Definitions ******************************/ + +/****************************************************************************/ +/** +* +* Main function to execute the Skip Block based Nand read/write example. +* +* @param None. +* +* @return +* - XST_SUCCESS if the example has completed successfully. +* - XST_FAILURE if the example has failed. +* +* @note None. +* +*****************************************************************************/ +int main(void) +{ + int Status; + + xil_printf("Nand Flash Skip Block Method Example Test\r\n"); + + /* + * Run the NAND read write example, specify the Base Address that + * is generated in xparameters.h . + */ + Status = NandSkipBlockExample(NAND_DEVICE_ID); + + if (Status != XST_SUCCESS) { + xil_printf("Nand Flash Skip Block Method Example Test Failed\r\n"); + return XST_FAILURE; + } + xil_printf("Successfully ran Nand Flash Skip Block Method Example Test\r\n"); + + return XST_SUCCESS; +} + +/****************************************************************************/ +/** +* +* This function runs a test on the NAND flash device using the basic driver +* functions. +* The function does the following tasks: +* - Initialize the driver. +* - Erase the required length of bytes by taking bad blocks into account. +* - Write the number of bytes from given offset by taking bad blocks +* into account. +* - Read the number of bytes from given offset by taking bad blocks +* into account. +* - Compare the data read against the data Written. +* +* @param NandDeviceId is the XPAR__DEVICE_ID value +* from xparameters.h. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if failed. +* +* @note None. +* +****************************************************************************/ +int NandSkipBlockExample(u32 NandDeviceId) +{ + int Status; + u32 Index; + XNandPs_Config *ConfigPtr; + u64 Offset; + u32 Length; + + /* + * Initialize the flash driver. + */ + ConfigPtr = XNandPs_LookupConfig(NandDeviceId); + if (ConfigPtr == NULL) { + return XST_FAILURE; + } + + Status = XNandPs_CfgInitialize(NandInstPtr, ConfigPtr, + ConfigPtr->SmcBase,ConfigPtr->FlashBase); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + Offset = NAND_TEST_OFFSET; + Length = NAND_TEST_LENGTH; + + /* + * Prepare the write buffer. Fill in the data need to be written into + * Flash Device. + */ + for (Index = 0; Index < Length; Index++) { + WriteBuffer[Index] = Index % 256; + } + + /* + * Erase the blocks using skip block method + */ + Status = XNandPs_SkipErase(NandInstPtr, Offset, Length); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Write into the flash offset. + */ + Status = XNandPs_SkipWrite(NandInstPtr, Offset, Length, WriteBuffer); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Read back from the flash. + */ + Status = XNandPs_SkipRead(NandInstPtr, Offset, Length, ReadBuffer); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Compare the data read against the data Written. + */ + for (Index = 0; Index < Length; Index++) { + if (ReadBuffer[Index] != WriteBuffer[Index]) { + return XST_FAILURE; + } + } + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function returns the length including bad blocks from a given offset and +* length. +* +* @param InstancePtr is the pointer to the XNandPs instance. +* @param Offset is the flash data address to read from. +* @param Length is number of bytes to read. +* +* @return +* - Return actual length including bad blocks. +* +* @note None. +* +******************************************************************************/ +u32 XNandPs_CalculateLength(XNandPs *InstancePtr, u64 Offset, u32 Length) +{ + u32 BlockSize = InstancePtr->Geometry.BlockSize; + u32 CurBlockLen; + u32 CurBlock; + u32 Status; + u32 TempLen = 0; + u32 ActLen = 0; + + while (TempLen < Length) { + CurBlockLen = BlockSize - (Offset & (BlockSize - 1)); + CurBlock = (Offset & ~(BlockSize - 1))/BlockSize; + + /* + * Check if the block is bad + */ + Status = XNandPs_IsBlockBad(InstancePtr, CurBlock); + if (Status != XST_SUCCESS) { + /* Good Block */ + TempLen += CurBlockLen; + } + ActLen += CurBlockLen; + Offset += CurBlockLen; + if (Offset >= InstancePtr->Geometry.DeviceSize) { + break; + } + } + + return ActLen; +} +/*****************************************************************************/ +/** +* +* This function reads the data from the Flash device and copies it into the +* specified user buffer. This function considers bad blocks and skips them +* to read next blocks. +* +* @param InstancePtr is the pointer to the XNandPs instance. +* @param Offset is the flash data address to read from. +* @param Length is number of bytes to read. +* @param DestPtr is the destination address to copy data to. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +int XNandPs_SkipRead(XNandPs *InstancePtr, u64 Offset, u32 Length, void + *DestPtr) +{ + u32 ActLen; + u32 BlockOffset; + u32 Block; + u32 Status; + u32 BytesLeft = Length; + u32 BlockSize = InstancePtr->Geometry.BlockSize; + u8 *BufPtr = (u8 *)DestPtr; + u32 ReadLen; + u32 BlockReadLen; + + /* + * Calculate the actual length including bad blocks + */ + ActLen = XNandPs_CalculateLength(InstancePtr, Offset, Length); + + /* + * Check if the actual length cross flash size + */ + if (Offset + ActLen > InstancePtr->Geometry.DeviceSize) { + return XST_FAILURE; + } + + while (BytesLeft > 0) { + BlockOffset = Offset & (BlockSize - 1); + Block = (Offset & ~(BlockSize - 1))/BlockSize; + BlockReadLen = BlockSize - BlockOffset; + + Status = XNandPs_IsBlockBad(InstancePtr, Block); + if (Status == XST_SUCCESS) { + /* Move to next block */ + Offset += BlockReadLen; + continue; + } + + /* + * Check if we cross block boundary + */ + if (BytesLeft < BlockReadLen) { + ReadLen = BytesLeft; + } else { + ReadLen = BlockReadLen; + } + + /* + * Read from the NAND flash + */ + Status = XNandPs_Read(InstancePtr, Offset, ReadLen, BufPtr, NULL); + if (Status != XST_SUCCESS) { + return Status; + } + BytesLeft -= ReadLen; + Offset += ReadLen; + BufPtr += ReadLen; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function programs the flash device(s) with data specified in the user +* buffer. This function considers bad blocks and skips them. +* +* @param InstancePtr is the pointer to the XNandPs instance. +* @param Offset is the flash data address to write to. +* @param Length is number of bytes to write. +* @param SrcPtr is the source address to write the data from. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +int XNandPs_SkipWrite(XNandPs *InstancePtr, u64 Offset, u32 Length, void + *SrcPtr) +{ + u32 ActLen; + u32 BlockOffset; + u32 Block; + u32 Status; + u32 BytesLeft = Length; + u32 BlockSize = InstancePtr->Geometry.BlockSize; + u8 *BufPtr = (u8 *)SrcPtr; + u32 WriteLen; + u32 BlockWriteLen; + + /* + * Calculate the actual length including bad blocks + */ + ActLen = XNandPs_CalculateLength(InstancePtr, Offset, Length); + + /* + * Check if the actual length cross flash size + */ + if (Offset + ActLen > InstancePtr->Geometry.DeviceSize) { + return XST_FAILURE; + } + while (BytesLeft > 0) { + BlockOffset = Offset & (BlockSize - 1); + Block = (Offset & ~(BlockSize - 1))/BlockSize; + BlockWriteLen = BlockSize - BlockOffset; + + /* + * Check if the block is bad + */ + Status = XNandPs_IsBlockBad(InstancePtr, Block); + if (Status == XST_SUCCESS) { + /* Move to next block */ + Offset += BlockWriteLen; + continue; + } + + /* + * Check if we cross block boundary + */ + if (BytesLeft < BlockWriteLen) { + WriteLen = BytesLeft; + } else { + WriteLen = BlockWriteLen; + } + + /* + * Read from the NAND flash + */ + Status = XNandPs_Write(InstancePtr, Offset, WriteLen, BufPtr, NULL); + if (Status != XST_SUCCESS) { + return Status; + } + + BytesLeft -= WriteLen; + Offset += WriteLen; + BufPtr += WriteLen; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function erases length bytes in the flash device from a given offset. +* The Offset and Length must be block aligned. This functions skips bad blocks. +* +* @param InstancePtr is the pointer to the XNand instance. +* @param Offset is the flash address to start erasing from. +* @param Length is number of bytes to erase. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if error in erase. +* +* @note None. +* +******************************************************************************/ +int XNandPs_SkipErase(XNandPs *InstancePtr, u64 Offset, u32 Length) +{ + u32 StartBlock; + u32 NumOfBlocks; + u32 BlockSize; + u32 Block; + int Status; + + BlockSize = InstancePtr->Geometry.BlockSize; + /* + * Start address must align on block boundary + */ + if (Offset & (BlockSize - 1)) { + /* Unalinged offset */ + return XST_FAILURE; + } + + /* + * Length must align on block boundary + */ + if (Length & (BlockSize - 1)) { + /* Length is not block aligned */ + return XST_FAILURE; + } + + StartBlock = (Offset & ~(BlockSize - 1))/BlockSize; + NumOfBlocks = (Length & ~(BlockSize - 1))/BlockSize; + + for (Block = StartBlock; Block < (StartBlock + NumOfBlocks) + ; Block++) { + /* + * Check if the block is bad + */ + Status = XNandPs_IsBlockBad(InstancePtr, Block); + if (Status == XST_SUCCESS) { + NumOfBlocks++; + if ((StartBlock + NumOfBlocks) >= + InstancePtr->Geometry.NumBlocks) { + return XST_FAILURE; + } + /* Increase the block count for skip block method */ + continue; + } + + /* + * Erase the Nand flash block + */ + Status = XNandPs_EraseBlock(InstancePtr, Block); + if (Status == XST_NAND_WRITE_PROTECTED) { + /* Flash is write protected */ + return XST_FAILURE; + } + if (Status != XST_SUCCESS) { + /* Erase operation error */ + return XST_FAILURE; + } + } + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/nandps/src/Makefile b/XilinxProcessorIPLib/drivers/nandps/src/Makefile new file mode 100755 index 00000000..bd3eacec --- /dev/null +++ b/XilinxProcessorIPLib/drivers/nandps/src/Makefile @@ -0,0 +1,40 @@ +COMPILER= +ARCHIVER= +CP=cp +COMPILER_FLAGS= +EXTRA_COMPILER_FLAGS= +LIB=libxil.a + +CC_FLAGS = $(COMPILER_FLAGS) +ECC_FLAGS = $(EXTRA_COMPILER_FLAGS) + +RELEASEDIR=../../../lib +INCLUDEDIR=../../../include +INCLUDES=-I./. -I${INCLUDEDIR} + +OUTS = *.o + +LIBSOURCES:=*.c +INCLUDEFILES:=*.h + +OBJECTS = $(addsuffix .o, $(basename $(wildcard *.c))) + +libs: banner xnandps_libs clean + +%.o: %.c + ${COMPILER} $(CC_FLAGS) $(ECC_FLAGS) $(INCLUDES) -o $@ $< + +banner: + echo "Compiling nandps" + +xnandps_libs: ${OBJECTS} + $(ARCHIVER) -r ${RELEASEDIR}/${LIB} ${OBJECTS} + +.PHONY: include +include: xnandps_includes + +xnandps_includes: + ${CP} ${INCLUDEFILES} ${INCLUDEDIR} + +clean: + rm -rf ${OBJECTS} diff --git a/XilinxProcessorIPLib/drivers/nandps/src/xnandps.c b/XilinxProcessorIPLib/drivers/nandps/src/xnandps.c new file mode 100755 index 00000000..ee506db6 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/nandps/src/xnandps.c @@ -0,0 +1,1963 @@ +/****************************************************************************** +* +* 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.c +* +* This file contains the implementation of the interface functions for +* XNandPs driver. Refer to the header file xnandps.h for more detailed +* information. +* +* This module supports for NAND flash memory devices that conform to the +* "Open NAND Flash Interface" (ONFI) Specification. This modules implements +* basic flash operations like read, write and erase. +* +* @note None +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date    	   Changes
+* ----- ----   ----------  -----------------------------------------------
+* 1.00a nm     12/10/2010  First release
+* 1.01a nm     28/02/2012  Fixed 16-bit issue with ONFI commands like
+*                          read, write and read status command. The config
+*                          structure width is updated after ONFI query
+*                          with the parameter page width.
+* 1.02a nm     20/09/2012  Removed setting of set_cycles and set_opmode
+*                          register values as it is now done in FSBL using
+*                          the PCW generated files. CR#678949.
+* 1.03a nm     10/22/2012  Fixed CR# 673348.
+* 1.04a nm     04/15/2013  Fixed CR# 704401. Removed warnings when compiled
+* 			   with -Wall and -Wextra option in bsp.
+*	       04/25/2013  Implemented PR# 699544. Added page cache read
+*			   and program support. Added API's XNandPs_ReadCache
+*			   and XNandPs_WriteCache for page cache support.
+*			   Added ECC handling functions XNandPs_EccSetCfg,
+*			   XNandPs_EccSetMemCmd1...etc, to support better
+*			   usage of ECC block for page cache commands.
+*			   Modified Read/Write API's so that there is common
+*			   code for normal read/write and page cache commands.
+*			   Disabling/Re-enabling ECC block in read/write API's
+*			   of spare bytes since we don't calculate ECC for
+*			   spare bytes.
+* 2.01 kpc    07/24/2014   Fixed CR#808770. Update command register twice only
+                           if flash device requires >= four address cycles.
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "xnandps.h" +#include "xnandps_bbm.h" +#include "xnandps_onfi.h" +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ +static int XNandPs_EccHwInit(XNandPs *InstancePtr); + +static int XNandPs_EccSwInit(XNandPs *InstancePtr); + +static int XNandPs_ReadPage_HwEcc(XNandPs *InstancePtr, u8 *DstPtr); + +static int XNandPs_ReadPage(XNandPs *InstancePtr, u8 *DstPtr); + +static int XNandPs_WritePage_HwEcc(XNandPs *InstancePtr, u8 *SrcPtr); + +static int XNandPs_WritePage(XNandPs *InstancePtr, u8 *SrcPtr); + +static int XNandPs_EccCalculate(XNandPs *InstancePtr, u8 *EccData); + +static int XNandPs_EccCorrect(u8 *Buf, u8 *EccCalc, u8 *EccCode); + +static void XNandPs_ReadBuf(XNandPs *InstancePtr, u8 *Buf, u32 Length); + +static void XNandPs_WriteBuf(XNandPs *InstancePtr, u8 *Buf, u32 Length); + +static int XNandPs_IsBusy(XNandPs *InstancePtr); + +void XNandPs_SendCommand(XNandPs *InstancePtr, XNandPs_CommandFormat + *Command, int Page, int Column); + +static void XNandPs_EccSetCfg(XNandPs *InstancePtr, u32 EccConfig); + +static void XNandPs_EccSetMemCmd1(XNandPs *InstancePtr, u32 EccCmd); + +static void XNandPs_EccSetMemCmd2(XNandPs *InstancePtr, u32 EccCmd); + +static void XNandPs_EccDisable(XNandPs *InstancePtr); + +/* Bad block management routines */ +extern void XNandPs_InitBbtDesc(XNandPs *InstancePtr); + +extern int XNandPs_ScanBbt(XNandPs *InstancePtr); +/* ONFI routines */ +extern u8 Onfi_CmdReadStatus(XNandPs *InstancePtr); + +extern int Onfi_NandInit(XNandPs *InstancePtr); +/************************** Variable Definitions *****************************/ +/* ECC data position in the spare data area for different page sizes */ +u32 NandOob16[] = {13, 14, 15}; /**< Ecc position for 16 bytes spare area */ + +u32 NandOob32[] = {26, 27, 28, 29, 30, 31}; + /**< Ecc position for 32 bytes spare area */ + +u32 NandOob64[] = {52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63}; + /**< Ecc position for 64 bytes spare area */ + +extern XNandPs_CommandFormat OnfiCommands[]; /**< ONFI commands */ + +/*****************************************************************************/ +/** +* +* This function initializes a specific XNandPs device/instance. This function +* must be called prior to using the flash device to read or write any data. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* @param ConfigPtr points to the XNandPs device configuration structure. +* @param SmcBaseAddr is the base address of SMC controller. +* @param FlashBaseAddr is the base address of NAND flash. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note The user needs to first call the XNandPs_LookupConfig() API +* which returns the Configuration structure pointer which is +* passed as a parameter to the XNandPs_CfgInitialize() API. +* +******************************************************************************/ +int XNandPs_CfgInitialize(XNandPs *InstancePtr, XNandPs_Config *ConfigPtr, + u32 SmcBaseAddr, u32 FlashBaseAddr) +{ + u32 PageSize; + int Status; + + /* + * Assert the input arguments. + */ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(ConfigPtr != NULL); + + /* + * Set the values read from the device config and the base address. + */ + InstancePtr->Config.DeviceId = ConfigPtr->DeviceId; + InstancePtr->Config.SmcBase = SmcBaseAddr; + InstancePtr->Config.FlashBase = FlashBaseAddr; + InstancePtr->Config.FlashWidth = ConfigPtr->FlashWidth; + + XNandPs_WriteReg(InstancePtr->Config.SmcBase + + XNANDPS_MEMC_CLR_CONFIG_OFFSET, + XNANDPS_CLR_CONFIG); /* Disable interrupts */ + + /* + * ONFI query to get geometry + */ + Status = Onfi_NandInit(InstancePtr); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Updating Config structure flash width + */ + InstancePtr->Config.FlashWidth = InstancePtr->Geometry.FlashWidth; + + /* + * Fill the spare buffer pointer + */ + PageSize = InstancePtr->Geometry.BytesPerPage; + InstancePtr->SpareBufPtr = &InstancePtr->DataBuf[PageSize]; + + /* + * Initialize ECC Block Parameters + */ + switch (InstancePtr->EccMode) + { + case XNANDPS_ECC_NONE: + /* Fall through */ + case XNANDPS_ECC_ONDIE: + /* Bypass the ECC block in the SMC controller */ + XNandPs_EccDisable(InstancePtr); + + /* Initialize the Read/Write page routines */ + InstancePtr->ReadPage = XNandPs_ReadPage; + InstancePtr->WritePage = XNandPs_WritePage; + break; + case XNANDPS_ECC_HW: + /* Use SMC ECC controller ECC block */ + Status = XNandPs_EccHwInit(InstancePtr); + if (Status != XST_SUCCESS) + return Status; + + /* Initialize ECC SW parameters */ + Status = XNandPs_EccSwInit(InstancePtr); + if (Status != XST_SUCCESS) + return Status; + + /* Initialize the Read/Write page routines */ + InstancePtr->ReadPage = XNandPs_ReadPage_HwEcc; + InstancePtr->WritePage = XNandPs_WritePage_HwEcc; + break; + default: + return XST_FAILURE; + } + + /* + * Indicate the instance is now ready to use, initialized without error. + */ + InstancePtr->IsReady = XIL_COMPONENT_IS_READY; + + /* + * Scan for the bad block table(bbt) stored in the flash & load it in + * memory(RAM). If bbt is not found, create bbt by scanning factory + * marked bad blocks and store it in last good blocks of flash. + */ + XNandPs_InitBbtDesc(InstancePtr); + Status = XNandPs_ScanBbt(InstancePtr); + if (Status != XST_SUCCESS) { + return Status; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function initializes the HW ECC block based on flash. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* @param EccConfig is the value of ECC config to update. +* +* @return None +* +* @note None +* +*****************************************************************************/ +static void XNandPs_EccSetCfg(XNandPs *InstancePtr, u32 EccConfig) +{ + /* + * Check the busy status of the ECC block + */ + while (XNandPs_ReadReg(InstancePtr->Config.SmcBase + + XNANDPS_ECC_STATUS_OFFSET(XNANDPS_IF1_ECC_OFFSET)) & + XNANDPS_ECC_STATUS_MASK); + /* + * Write ECC configuration register + */ + XNandPs_WriteReg(InstancePtr->Config.SmcBase + + (XNANDPS_ECC_MEMCFG_OFFSET(XNANDPS_IF1_ECC_OFFSET)), + EccConfig); +} + +/*****************************************************************************/ +/** +* +* This function writes ECC MEM CMD1 register with EccCmd value. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* @param EccCmd is register value to write. +* +* @return None +* +* @note None +* +*****************************************************************************/ +static void XNandPs_EccSetMemCmd1(XNandPs *InstancePtr, u32 EccCmd) +{ + /* + * Set the ECC mem command1 register + */ + XNandPs_WriteReg(InstancePtr->Config.SmcBase + + (XNANDPS_ECC_MEMCMD1_OFFSET(XNANDPS_IF1_ECC_OFFSET)), + EccCmd); +} + +/*****************************************************************************/ +/** +* +* This function writes ECC MEM CMD2 register with EccCmd value. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* @param EccCmd is register value to write. +* +* @return None +* +* @note None +* +*****************************************************************************/ +static void XNandPs_EccSetMemCmd2(XNandPs *InstancePtr, u32 EccCmd) +{ + /* + * Set the ECC mem command2 register + */ + XNandPs_WriteReg(InstancePtr->Config.SmcBase + + (XNANDPS_ECC_MEMCMD2_OFFSET(XNANDPS_IF1_ECC_OFFSET)), + EccCmd); +} + +/*****************************************************************************/ +/** +* +* This function disables ECC block. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* +* @return None +* +* @note None +* +*****************************************************************************/ +static void XNandPs_EccDisable(XNandPs *InstancePtr) +{ + u32 EccConfig = 0; + /* + * Bypass the ECC block in the SMC controller + */ + EccConfig = XNandPs_ReadReg(InstancePtr->Config.SmcBase + + (XNANDPS_ECC_MEMCFG_OFFSET(XNANDPS_IF1_ECC_OFFSET))); + + EccConfig &= ~XNANDPS_ECC_MEMCFG_ECC_MODE_MASK; + XNandPs_EccSetCfg(InstancePtr, EccConfig); +} + +/*****************************************************************************/ +/** +* +* This function initializes the HW ECC block based on flash. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if the flash is not supported. +* +* @note None +* +*****************************************************************************/ +static int XNandPs_EccHwInit(XNandPs *InstancePtr) +{ + u32 PageSize; + u32 EccConfig = 0; + + PageSize = InstancePtr->Geometry.BytesPerPage; + /* + * Set the ECC mem command1 and ECC mem command2 register + */ + XNandPs_EccSetMemCmd1(InstancePtr, XNANDPS_ECC_CMD1); + XNandPs_EccSetMemCmd2(InstancePtr, XNANDPS_ECC_CMD2); + /* + * Configure HW ECC block + */ + switch(PageSize) { + case XNANDPS_PAGE_SIZE_512: + EccConfig = (XNANDPS_ECC_MEMCFG | + XNANDPS_ECC_MEMCFG_PAGE_SIZE_512); + break; + case XNANDPS_PAGE_SIZE_1024: + EccConfig = (XNANDPS_ECC_MEMCFG | + XNANDPS_ECC_MEMCFG_PAGE_SIZE_1024); + break; + case XNANDPS_PAGE_SIZE_2048: + EccConfig = (XNANDPS_ECC_MEMCFG | + XNANDPS_ECC_MEMCFG_PAGE_SIZE_2048); + break; + default: + /* + * Page size 256 bytes & 4096 bytes not supported + * by ECC block + */ + return XST_FAILURE; + } + XNandPs_EccSetCfg(InstancePtr, EccConfig); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function initializes the software variables related +* to ECC generation, ECC checking and writing ECC bytes in spare bytes. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if the flash is not supported. +* +* @note None +* +*****************************************************************************/ +static int XNandPs_EccSwInit(XNandPs *InstancePtr) +{ + u32 PageSize; + u32 SpareBytesSize; + u32 Index; + + PageSize = InstancePtr->Geometry.BytesPerPage; + SpareBytesSize = InstancePtr->Geometry.SpareBytesPerPage; + + /* + * Initialize ECC config structure parameters + */ + InstancePtr->EccConfig.BytesPerBlock = XNANDPS_ECC_BYTES; + InstancePtr->EccConfig.BlockSize = XNANDPS_ECC_BLOCK_SIZE; + InstancePtr->EccConfig.TotalBytes = (PageSize/XNANDPS_ECC_BLOCK_SIZE) + * XNANDPS_ECC_BYTES; + InstancePtr->EccConfig.NumSteps = PageSize/XNANDPS_ECC_BLOCK_SIZE; + + /* + * Ecc write position in spare data area as per Linux mtd subsystem + */ + switch(SpareBytesSize) { + case XNANDPS_SPARE_SIZE_16: + for(Index = 0; Index < + InstancePtr->EccConfig.TotalBytes; + Index++) { + InstancePtr->EccConfig.EccPos[Index] = + NandOob16[Index]; + } + break; + case XNANDPS_SPARE_SIZE_32: + for(Index = 0; Index < + InstancePtr->EccConfig.TotalBytes; + Index++) { + InstancePtr->EccConfig.EccPos[Index] = + NandOob32[Index]; + } + break; + case XNANDPS_SPARE_SIZE_64: + for(Index = 0; Index < + InstancePtr->EccConfig.TotalBytes; + Index++) { + InstancePtr->EccConfig.EccPos[Index] = + NandOob64[Index]; + } + break; + default: + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function reads the data from the Flash device and copies it into the +* specified user buffer. It doesn't check for the bad blocks while reading +* the flash pages that cross block boundary. User must take care of handling +* bad blocks. +* +* @param InstancePtr is the pointer to the XNandPs instance. +* @param Offset is the flash data address to read from. +* @param Length is number of bytes to read. +* @param DestPtr is the destination address to copy data to. +* @param UserSparePtr is the user buffer to which spare data must be +* copied. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note This function reads sequential pages from the Flash device. +* +******************************************************************************/ +int XNandPs_Read(XNandPs *InstancePtr, u64 Offset, u32 Length, void *DestPtr, + u8 *UserSparePtr) +{ + u32 Page; + u32 Col; + u32 PartialBytes; + u32 NumOfBytes; + int Status; + u32 PartialPageRead = 0; + u32 CopyOffset; + u8 *BufPtr; + u8 *Ptr = (u8 *)DestPtr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(DestPtr != NULL); + Xil_AssertNonvoid((Offset + Length) < InstancePtr->Geometry.DeviceSize); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Length != 0); + + Page = (u32) (Offset/InstancePtr->Geometry.BytesPerPage); + Col = (u32) (Offset & (InstancePtr->Geometry.BytesPerPage - 1)); + PartialBytes = InstancePtr->Geometry.BytesPerPage - Col; + NumOfBytes = (PartialBytes < Length) ? PartialBytes:Length; + CopyOffset = InstancePtr->Geometry.BytesPerPage - PartialBytes; + + /* + * Restore the ECC mem command1 and ECC mem command2 register + * if the previous command is read page cache. + */ + XNandPs_EccSetMemCmd1(InstancePtr, XNANDPS_ECC_CMD1); + XNandPs_EccSetMemCmd2(InstancePtr, XNANDPS_ECC_CMD2); + + while (Length) { + /* + * Check if partial read + */ + if (NumOfBytes < InstancePtr->Geometry.BytesPerPage) { + BufPtr = &InstancePtr->DataBuf[0]; + PartialPageRead = 1; + } else { + BufPtr = (u8 *)Ptr; + PartialPageRead = 0; + } + + /* + * Send the ONFI Read command + */ + XNandPs_SendCommand(InstancePtr, &OnfiCommands[READ], Page, 0); + + /* + * Poll the Memory controller status register + */ + while (XNandPs_IsBusy(InstancePtr) == TRUE) { + } + + /* + * Clear the interrupt condition + */ + XNandPs_WriteReg((InstancePtr->Config.SmcBase + + XNANDPS_MEMC_CLR_CONFIG_OFFSET), + XNANDPS_MEMC_CLR_CONFIG_INT_CLR1_MASK); + + /* + * Read the page data + */ + Status = InstancePtr->ReadPage(InstancePtr, BufPtr); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Fill the partial data in the buffer + */ + if (PartialPageRead) { + memcpy(Ptr, BufPtr + CopyOffset, NumOfBytes); + } + + Ptr += NumOfBytes; + Length -= NumOfBytes; + Page++; + NumOfBytes = (Length > InstancePtr->Geometry.BytesPerPage) ? + InstancePtr->Geometry.BytesPerPage:Length; + CopyOffset = 0; + } + + /* + * Copy the spare data to user spare buffer + */ + if (UserSparePtr) { + memcpy(UserSparePtr, InstancePtr->SpareBufPtr, + InstancePtr->Geometry.SpareBytesPerPage); + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function reads the data from the Flash device using read page cache +* command and copies it into the specified user buffer. +* It doesn't check for the bad blocks while reading the flash pages that +* cross block boundary. User must take care of handling bad blocks. +* +* @param InstancePtr is the pointer to the XNandPs instance. +* @param Offset is the flash data address to read from. +* @param Length is number of bytes to read. +* @param DestPtr is the destination address to copy data to. +* @param UserSparePtr is the user buffer to which spare data must be +* copied. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note This function reads sequential pages from the Flash device. +* +******************************************************************************/ +int XNandPs_ReadCache(XNandPs *InstancePtr, u64 Offset, u32 Length, + void *DestPtr, u8 *UserSparePtr) +{ + u32 Page; + u32 Col; + u32 PartialBytes; + u32 NumOfBytes; + int Status; + u32 PartialPageRead = 0; + u32 CopyOffset; + u8 *BufPtr; + u8 *Ptr = (u8 *)DestPtr; + u32 NumPages; + u32 EccConfig = 0; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(DestPtr != NULL); + Xil_AssertNonvoid((Offset + Length) < InstancePtr->Geometry.DeviceSize); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Length != 0); + + /* + * Check if the flash supports read cache + */ + if (!InstancePtr->Features.ReadCache) { + return XNandPs_Read(InstancePtr, Offset, Length, DestPtr, + UserSparePtr); + } + + Page = (u32) (Offset/InstancePtr->Geometry.BytesPerPage); + Col = (u32) (Offset & (InstancePtr->Geometry.BytesPerPage - 1)); + PartialBytes = InstancePtr->Geometry.BytesPerPage - Col; + NumOfBytes = (PartialBytes < Length) ? PartialBytes:Length; + CopyOffset = InstancePtr->Geometry.BytesPerPage - PartialBytes; + /* + * Calculate number of pages to read + */ + NumPages = Length/InstancePtr->Geometry.BytesPerPage; + NumPages += (Length % InstancePtr->Geometry.BytesPerPage) ? 1:0; + /* + * Read, Read Cache start, Read Cache end + */ + if (NumPages <= 1) { + return XNandPs_Read(InstancePtr, Offset, Length, DestPtr, + UserSparePtr); + } + + /* + * Change ECC commands in ECC registers for page cache support + */ + EccConfig |= ONFI_CMD_PAGE_CACHE_PROGRAM1; + EccConfig |= ONFI_CMD_READ_CACHE_ENHANCED1 << 8; + EccConfig |= ONFI_CMD_READ_CACHE_ENHANCED2 << 16; + EccConfig |= (XNANDPS_ECC_MEMCOMMAND1_RD_CMD_END_VALID_MASK); + XNandPs_EccSetMemCmd1(InstancePtr, EccConfig); + + /* + * Send the ONFI Read command + */ + XNandPs_SendCommand(InstancePtr, &OnfiCommands[READ], Page, 0); + + /* + * Poll the Memory controller status register + */ + while (XNandPs_IsBusy(InstancePtr) == TRUE) { + } + + /* + * Clear the interrupt condition + */ + XNandPs_WriteReg((InstancePtr->Config.SmcBase + + XNANDPS_MEMC_CLR_CONFIG_OFFSET), + XNANDPS_MEMC_CLR_CONFIG_INT_CLR1_MASK); + + /* + * Check ONFI Status Register + */ + Status = Onfi_CmdReadStatus(InstancePtr); + if (Status & ONFI_STATUS_FAIL) { + return XST_FAILURE; + } + + while (Length && (NumPages > 0)) { + /* + * Check if partial read + */ + if (NumOfBytes < InstancePtr->Geometry.BytesPerPage) { + BufPtr = &InstancePtr->DataBuf[0]; + PartialPageRead = 1; + } else { + BufPtr = (u8 *)Ptr; + PartialPageRead = 0; + } + + /* Increment the page */ + Page++; + + if (NumPages <= 1) { + /* + * Change ECC commands in ECC registers to check + * change read column for ECC calculation + */ + EccConfig = 0; + EccConfig |= ONFI_CMD_PAGE_CACHE_PROGRAM1; + EccConfig |= ONFI_CMD_CHANGE_READ_COLUMN1 << 8; + EccConfig |= ONFI_CMD_CHANGE_READ_COLUMN2 << 16; + EccConfig |= + XNANDPS_ECC_MEMCOMMAND1_RD_CMD_END_VALID_MASK; + XNandPs_EccSetMemCmd1(InstancePtr, EccConfig); + + /* + * Send NAND page cache end command 0x3F + */ + XNandPs_SendCommand(InstancePtr, + &OnfiCommands[READ_CACHE_END_SEQ], + XNANDPS_PAGE_NOT_VALID, + XNANDPS_COLUMN_NOT_VALID); + } else { + XNandPs_SendCommand(InstancePtr, + &OnfiCommands[READ_CACHE_RANDOM], + Page, 0); + } + + /* + * Poll the Memory controller status register + */ + while (XNandPs_IsBusy(InstancePtr) == TRUE) { + } + + /* + * Clear the interrupt condition + */ + XNandPs_WriteReg((InstancePtr->Config.SmcBase + + XNANDPS_MEMC_CLR_CONFIG_OFFSET), + XNANDPS_MEMC_CLR_CONFIG_INT_CLR1_MASK); + + if (NumPages <= 1) { + XNandPs_SendCommand(InstancePtr, + &OnfiCommands[CHANGE_READ_COLUMN], + XNANDPS_PAGE_NOT_VALID, + 0); + } + + /* + * Read the page data + */ + Status = InstancePtr->ReadPage(InstancePtr, BufPtr); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Fill the partial data in the buffer + */ + if (PartialPageRead) { + memcpy(Ptr, BufPtr + CopyOffset, NumOfBytes); + } + + Ptr += NumOfBytes; + Length -= NumOfBytes; + NumPages--; + NumOfBytes = (Length > InstancePtr->Geometry.BytesPerPage) ? + InstancePtr->Geometry.BytesPerPage:Length; + CopyOffset = 0; + } + + /* + * Copy the spare data to user spare buffer + */ + if (UserSparePtr) { + memcpy(UserSparePtr, InstancePtr->SpareBufPtr, + InstancePtr->Geometry.SpareBytesPerPage); + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function programs the flash device(s) with data specified in the user +* buffer. The source and destination address must be aligned to the width of the +* flash's data bus. It doesn't check for the bad blocks while writing to +* the flash pages that cross block boundary. User must take care of handling +* bad blocks. +* +* @param InstancePtr is the pointer to the XNandPs instance. +* @param Offset is the flash data address to write to. +* @param Length is number of bytes to write. +* @param SrcPtr is the source address to write the data from. +* @param UserSparePtr is the user buffer which contains buffer to write +* into spare data area. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* - XST_NAND_WRITE_PROTECTED if the flash is write protected. +* +* @note This function writes number of sequential pages into the +* Flash device. +* +******************************************************************************/ +int XNandPs_Write(XNandPs *InstancePtr, u64 Offset, u32 Length, void *SrcPtr, + u8 *UserSparePtr) +{ + u32 Page; + u32 Col; + u32 PartialBytes; + u32 NumOfBytes; + u32 CopyOffset; + u32 Status; + u8 *BufPtr; + u8 OnfiStatus; + u8 *Ptr = (u8 *)SrcPtr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(SrcPtr != NULL); + Xil_AssertNonvoid((Offset + Length) < InstancePtr->Geometry.DeviceSize); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Length != 0); + + /* + * Check if the flash is write protected + */ + OnfiStatus = Onfi_CmdReadStatus(InstancePtr); + if (!(OnfiStatus & ONFI_STATUS_WP)) { + return XST_NAND_WRITE_PROTECTED; + } + + /* + * Copy the user spare data buffer + */ + if (UserSparePtr == NULL) { + memset(InstancePtr->SpareBufPtr, 0xff, + InstancePtr->Geometry.SpareBytesPerPage); + } else { + memcpy(InstancePtr->SpareBufPtr, UserSparePtr, + InstancePtr->Geometry.SpareBytesPerPage); + } + + Page = (u32) (Offset/InstancePtr->Geometry.BytesPerPage); + Col = (u32) (Offset & (InstancePtr->Geometry.BytesPerPage - 1)); + PartialBytes = InstancePtr->Geometry.BytesPerPage - Col; + NumOfBytes = (PartialBytes < Length) ? PartialBytes:Length; + CopyOffset = InstancePtr->Geometry.BytesPerPage - PartialBytes; + + while (Length) + { + /* + * Partial write, fill the remaining buffer with 0xff + */ + if (NumOfBytes < InstancePtr->Geometry.BytesPerPage) { + BufPtr = &InstancePtr->DataBuf[0]; + memset(BufPtr, 0xff, + InstancePtr->Geometry.BytesPerPage); + memcpy(BufPtr + CopyOffset, Ptr, NumOfBytes); + } else { + BufPtr = (u8 *)Ptr; + } + + /* + * Send ONFI Program command + */ + XNandPs_SendCommand(InstancePtr, &OnfiCommands[PAGE_PROGRAM], + Page, 0); + + /* + * Write the page data + */ + Status = InstancePtr->WritePage(InstancePtr, BufPtr); + if (Status != XST_SUCCESS) { + return Status; + } + + Ptr += NumOfBytes; + Length -= NumOfBytes; + Page++; + NumOfBytes = (Length > InstancePtr->Geometry.BytesPerPage) ? + InstancePtr->Geometry.BytesPerPage:Length; + CopyOffset = 0; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function programs the flash device(s) with data specified in the user +* buffer using program cache command. +* The source and destination address must be aligned to the width of the +* flash's data bus. It doesn't check for the bad blocks while writing to +* the flash pages that cross block boundary. User must take care of handling +* bad blocks. +* +* @param InstancePtr is the pointer to the XNandPs instance. +* @param Offset is the flash data address to write to. +* @param Length is number of bytes to write. +* @param SrcPtr is the source address to write the data from. +* @param UserSparePtr is the user buffer which contains buffer to write +* into spare data area. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* - XST_NAND_WRITE_PROTECTED if the flash is write protected. +* +* @note This function writes number of sequential pages into the +* Flash device. +* +******************************************************************************/ +int XNandPs_WriteCache(XNandPs *InstancePtr, u64 Offset, u32 Length, + void *SrcPtr, u8 *UserSparePtr) +{ + u32 Page; + u32 Col; + u32 PartialBytes; + u32 NumOfBytes; + u32 CopyOffset; + u32 Status; + u8 *BufPtr; + u8 OnfiStatus; + u8 *Ptr = (u8 *)SrcPtr; + u32 NumPages; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(SrcPtr != NULL); + Xil_AssertNonvoid((Offset + Length) < InstancePtr->Geometry.DeviceSize); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Length != 0); + + + /* + * Check if the flash is write protected + */ + OnfiStatus = Onfi_CmdReadStatus(InstancePtr); + if (!(OnfiStatus & ONFI_STATUS_WP)) { + return XST_NAND_WRITE_PROTECTED; + } + + /* + * Copy the user spare data buffer + */ + if (UserSparePtr == NULL) { + memset(InstancePtr->SpareBufPtr, 0xff, + InstancePtr->Geometry.SpareBytesPerPage); + } else { + memcpy(InstancePtr->SpareBufPtr, UserSparePtr, + InstancePtr->Geometry.SpareBytesPerPage); + } + + Page = (u32) (Offset/InstancePtr->Geometry.BytesPerPage); + Col = (u32) (Offset & (InstancePtr->Geometry.BytesPerPage - 1)); + PartialBytes = InstancePtr->Geometry.BytesPerPage - Col; + NumOfBytes = (PartialBytes < Length) ? PartialBytes:Length; + CopyOffset = InstancePtr->Geometry.BytesPerPage - PartialBytes; + /* + * Calculate number of pages to write + */ + NumPages = Length/InstancePtr->Geometry.BytesPerPage; + NumPages += (Length % InstancePtr->Geometry.BytesPerPage) ? 1:0; + /* + * Check for enough pages for cache programming + */ + if (NumPages <= 1) { + return XNandPs_Write(InstancePtr, Offset, Length, SrcPtr, + UserSparePtr); + } + + while (Length && (NumPages > 0)) + { + /* + * Partial write, fill the remaining buffer with 0xff + */ + if (NumOfBytes < InstancePtr->Geometry.BytesPerPage) { + BufPtr = &InstancePtr->DataBuf[0]; + memset(BufPtr, 0xff, + InstancePtr->Geometry.BytesPerPage); + memcpy(BufPtr + CopyOffset, Ptr, NumOfBytes); + } else { + BufPtr = (u8 *)Ptr; + } + + if (NumPages > 1) { + /* + * Send ONFI Program cache command + */ + XNandPs_SendCommand(InstancePtr, + &OnfiCommands[PAGE_CACHE_PROGRAM], + Page, 0); + /* + * Write the page data + */ + Status = InstancePtr->WritePage(InstancePtr, BufPtr); + if (Status != XST_SUCCESS) { + return Status; + } + } else { + /* + * Send ONFI Program command + */ + XNandPs_SendCommand(InstancePtr, + &OnfiCommands[PAGE_PROGRAM], + Page, 0); + /* + * Write the page data + */ + Status = InstancePtr->WritePage(InstancePtr, BufPtr); + if (Status != XST_SUCCESS) { + return Status; + } + } + + Ptr += NumOfBytes; + Length -= NumOfBytes; + Page++; + NumPages--; + NumOfBytes = (Length > InstancePtr->Geometry.BytesPerPage) ? + InstancePtr->Geometry.BytesPerPage:Length; + CopyOffset = 0; + } + + return XST_SUCCESS; +} + +/**************************************************************************/ +/** +* +* This function sends a NAND command to the flash device. +* +* @param InstancePtr is the pointer to XNandPs struture +* @param Command is the NAND command to send +* @param Page is the page offset required for specific commands +* @param Column the column offset required for specific commands +* +* @return None +* +* @note None +* +***************************************************************************/ +void XNandPs_SendCommand(XNandPs *InstancePtr, XNandPs_CommandFormat + *Command, int Page, int Column) +{ + u32 EndCmdReq = 0; + u32 EccLast = 0; + u32 ClearCs = 0; + u32 CmdPhaseAddr; + u32 DataPhaseAddr; + u32 CmdPhaseData=0; + u32 PageShift; + + Xil_AssertVoid(Command != NULL); + + if (Command->EndCmdValid == XNANDPS_CMD_PHASE) { + EndCmdReq = 1; + } + + /* + * Construct command phase address + */ + CmdPhaseAddr = InstancePtr->Config.FlashBase | + (Command->AddrCycles << XNANDPS_ADDR_CYCLES_SHIFT) | + (EndCmdReq << XNANDPS_END_CMD_VALID_SHIFT) | + XNANDPS_COMMAND_PHASE_MASK | + (Command->EndCmd << XNANDPS_END_CMD_SHIFT) | + (Command->StartCmd << XNANDPS_START_CMD_SHIFT); + + InstancePtr->CommandPhaseAddr = CmdPhaseAddr; + + EndCmdReq = 0; + + /* + * Some NAND commands require end command to be sent after data phase + */ + if (Command->EndCmdValid == XNANDPS_DATA_PHASE) { + EndCmdReq = 1; + } + + /* + * Construct data phase address + */ + DataPhaseAddr = InstancePtr->Config.FlashBase | + (ClearCs << XNANDPS_CLEAR_CS_SHIFT) | + (EndCmdReq << XNANDPS_END_CMD_VALID_SHIFT) | + XNANDPS_DATA_PHASE_MASK | + (Command->EndCmd << XNANDPS_END_CMD_SHIFT) | + (EccLast << XNANDPS_ECC_LAST_SHIFT); + + InstancePtr->DataPhaseAddr = DataPhaseAddr; + + /* + * Command phase data + */ + if (Column != XNANDPS_COLUMN_NOT_VALID && Page != + XNANDPS_PAGE_NOT_VALID) { + if (InstancePtr->Geometry.FlashWidth == + XNANDPS_FLASH_WIDTH_16) { + Column >>= 1; + } + CmdPhaseData = Column; + PageShift = InstancePtr->Geometry.ColAddrCycles * 8; + CmdPhaseData |= Page << PageShift; + if (Command->AddrCycles > 4) { + /* + * Send lower bytes of page address in first address + * cycle + */ + XNandPs_WriteReg(CmdPhaseAddr, CmdPhaseData); + /* + * Send the upper bytes of the page address in second + * address cycle + */ + CmdPhaseData = Page >> (32 - PageShift); + } + } else if (Page != XNANDPS_PAGE_NOT_VALID) { + CmdPhaseData = Page; + } else { + if (InstancePtr->Geometry.FlashWidth == + XNANDPS_FLASH_WIDTH_16) { + Column >>= 1; + } + CmdPhaseData = Column; + } + + /* + * Send command phase + */ + XNandPs_WriteReg(CmdPhaseAddr, CmdPhaseData); +} + +/*****************************************************************************/ +/** +* +* This function reads the spare area of a page. +* +* @param InstancePtr is the pointer to the XNandPs instance. +* @param Page is the page number from where spare data is read. +* @param Buf is pointer to the buffer where the spare data is filled. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +int XNandPs_ReadSpareBytes(XNandPs *InstancePtr, u32 Page, u8 *Buf) +{ + u32 Col; + u32 Length; + u32 DataPhaseAddr; + u32 ZeroCommand; + u32 Status; + + Xil_AssertNonvoid(Buf != NULL); + + /* + * Bypass the ECC block in the SMC controller since + * we don't calculate ECC for spare bytes. + */ + if (InstancePtr->EccMode == XNANDPS_ECC_HW) { + XNandPs_EccDisable(InstancePtr); + } + + Col = InstancePtr->Geometry.BytesPerPage; + Length = InstancePtr->Geometry.SpareBytesPerPage; + + XNandPs_SendCommand(InstancePtr, &OnfiCommands[READ], Page, Col); + /* + * Poll the Memory controller status register for BUSY input signal + */ + while (XNandPs_IsBusy(InstancePtr) == TRUE) { + } + + /* + * Clear the interrupt condition + */ + XNandPs_WriteReg((InstancePtr->Config.SmcBase + + XNANDPS_MEMC_CLR_CONFIG_OFFSET), + XNANDPS_MEMC_CLR_CONFIG_INT_CLR1_MASK); + + /* + * Check ONFI Status Register + */ + Status = Onfi_CmdReadStatus(InstancePtr); + if (Status & ONFI_STATUS_FAIL) { + return XST_FAILURE; + } + + /* + * 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); + + /* + * AXI transaction for sending command 0x00 to the flash + */ + Xil_Out32(ZeroCommand, 0x00); + + /* + * Read the spare data + */ + XNandPs_ReadBuf(InstancePtr, Buf, (Length - XNANDPS_AXI_DATA_WIDTH)); + + /* + * Clear chip select for last AXI transaction + */ + DataPhaseAddr = InstancePtr->DataPhaseAddr; + DataPhaseAddr |= XNANDPS_CLR_CS; + InstancePtr->DataPhaseAddr = DataPhaseAddr; + Buf += (Length - XNANDPS_AXI_DATA_WIDTH); + XNandPs_ReadBuf(InstancePtr, Buf, XNANDPS_AXI_DATA_WIDTH); + + /* + * Re-enable ECC block in the SMC controller + */ + if (InstancePtr->EccMode == XNANDPS_ECC_HW) { + Status = XNandPs_EccHwInit(InstancePtr); + if (Status != XST_SUCCESS) + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function write to the spare area of a page. +* +* @param InstancePtr is the pointer to the XNandPs instance. +* @param Page is the page number to write. +* @param Buf is pointer to the buffer which holds the data. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +int XNandPs_WriteSpareBytes(XNandPs *InstancePtr, u32 Page, u8 *Buf) +{ + u32 Col; + u32 Length; + u32 DataPhaseAddr; + u32 Status; + + Xil_AssertNonvoid(Buf != NULL); + + /* + * Bypass the ECC block in the SMC controller since + * we don't calculate ECC for spare bytes. + */ + if (InstancePtr->EccMode == XNANDPS_ECC_HW) { + XNandPs_EccDisable(InstancePtr); + } + + Col = InstancePtr->Geometry.BytesPerPage; + Length = InstancePtr->Geometry.SpareBytesPerPage; + + XNandPs_SendCommand(InstancePtr, &OnfiCommands[PAGE_PROGRAM], Page, Col); + + /* + * Write to the spare area + */ + XNandPs_WriteBuf(InstancePtr, Buf, (Length - + XNANDPS_AXI_DATA_WIDTH)); + /* + * Last transaction clear chip select + */ + DataPhaseAddr = InstancePtr->DataPhaseAddr; + DataPhaseAddr |= XNANDPS_CLR_CS; + InstancePtr->DataPhaseAddr = DataPhaseAddr; + Buf += (Length - XNANDPS_AXI_DATA_WIDTH); + XNandPs_WriteBuf(InstancePtr, Buf, XNANDPS_AXI_DATA_WIDTH); + + /* + * Poll the Memory controller status register for BUSY input signal + */ + while (XNandPs_IsBusy(InstancePtr) == TRUE) { + } + + /* + * Clear the interrupt condition + */ + XNandPs_WriteReg((InstancePtr->Config.SmcBase + + XNANDPS_MEMC_CLR_CONFIG_OFFSET), + XNANDPS_MEMC_CLR_CONFIG_INT_CLR1_MASK); + /* + * Check SR[0] bit + */ + Status = Onfi_CmdReadStatus(InstancePtr); + if (Status & ONFI_STATUS_FAIL) { + return XST_FAILURE; + } + + /* + * Re-enable ECC block in the SMC controller + */ + if (InstancePtr->EccMode == XNANDPS_ECC_HW) { + Status = XNandPs_EccHwInit(InstancePtr); + if (Status != XST_SUCCESS) + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function checks whether SMC controller busy in processing a request. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* +* @return - TRUE if SMC is busy +* - FALSE if SMC is free +* +* @note None. +* +******************************************************************************/ +static int XNandPs_IsBusy(XNandPs *InstancePtr) +{ + u32 Status; + + /* + * Read the memory controller status register + */ + Status = XNandPs_ReadReg(InstancePtr->Config.SmcBase + + XNANDPS_MEMC_STATUS_OFFSET) & + XNANDPS_MEMC_STATUS_RAW_INT_STATUS1_MASK; + + if (Status) { + return FALSE; + } else { + return TRUE; + } +} +/*****************************************************************************/ +/** +* +* This function calculates the ECC value from the ECC registers. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* @param EccData is the buffer to fill the ECC value. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None +* +******************************************************************************/ +static int XNandPs_EccCalculate(XNandPs *InstancePtr, u8 *EccData) +{ + u32 EccReg; + u32 EccValue; + u32 EccByte; + u32 EccStatus; + + /* + * Check the busy status of the ECC block + */ + while (XNandPs_ReadReg(InstancePtr->Config.SmcBase + + XNANDPS_ECC_STATUS_OFFSET(XNANDPS_IF1_ECC_OFFSET)) & + XNANDPS_ECC_STATUS_MASK); + + for(EccReg = 0; EccReg < 4; EccReg++) { + + EccValue = XNandPs_ReadReg(InstancePtr->Config.SmcBase + + XNANDPS_ECC_VALUE0_OFFSET(XNANDPS_IF1_ECC_OFFSET + + (EccReg * 4))); + EccStatus = (EccValue >> 24) & 0xFF; + + /* + * Check if the ECC value not valid + */ + if ((EccStatus >> 6) & 0x1) { + for(EccByte = 0; EccByte < 3; EccByte++) { + *EccData = EccValue & 0xFF; + EccValue = EccValue >> 8; + EccData++; + } + } else { + return XST_FAILURE; + } + } + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function corrects the ECC errors. +* +* @param Buf is the buffer which holds the data read from the page. +* @param EccCalc is the calculated ECC value. +* @param EccCode is the ECC read from the spare area. +* +* @return +* - XST_SUCCESS if the ECC error is corrected. +* - XST_FAILURE if the ECC error is not corrected. +* +* @note None +* +******************************************************************************/ +static int XNandPs_EccCorrect(u8 *Buf, u8 *EccCalc, u8 *EccCode) +{ + u8 BitPos; + u32 BytePos; + u16 EccOdd, EccEven; + u16 ReadEccLow, ReadEccHigh; + u16 CalcEccLow, CalcEccHigh; + + /* + * Lower 12 bits of ECC Read + */ + ReadEccLow = (EccCode[0] | (EccCode[1] << 8)) & 0xfff; + /* + * Upper 12 bits of ECC Read + */ + ReadEccHigh = ((EccCode[1] >> 4) | (EccCode[2] << 4)) & 0xfff; + + /* + * Lower 12 bits of ECC calculated + */ + CalcEccLow = (EccCalc[0] | (EccCalc[1] << 8)) & 0xfff; + /* + * Upper 12 bits of ECC Calculated + */ + CalcEccHigh = ((EccCalc[1] >> 4) | (EccCalc[2] << 4)) & 0xfff; + + EccOdd = ReadEccLow ^ CalcEccLow; + EccEven = ReadEccHigh ^ CalcEccHigh; + + /* + * No Error + */ + if ((EccOdd == 0) && (EccEven == 0)) { + return XST_SUCCESS; + } + + /* + * Single bit error, correct it + */ + if (EccOdd == (~EccEven & 0xfff)) { + BytePos = (EccOdd >> 3) & XNANDPS_ECC_CORRECT_BYTE_MASK; + BitPos = EccOdd & XNANDPS_ECC_CORRECT_BIT_MASK; + /* + * Toggling error bit + */ + Buf[BytePos] ^= (1 << BitPos); + return XST_SUCCESS; + } + + /* + * Parity error + */ + if (OneHot((EccOdd | EccEven)) == XST_SUCCESS) { + return XST_SUCCESS; + } + + /* + * Multiple bit errors + */ + return XST_FAILURE; +} + +/*****************************************************************************/ +/** +* +* This function reads a specific page from NAND device using HW ECC block. +* It checks for the ECC errors and corrects single bit errors. The multiple bit +* error are reported as failure. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* @param DstPtr is a pointer to the destination buffer. +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None +* +******************************************************************************/ +static int XNandPs_ReadPage_HwEcc(XNandPs *InstancePtr, u8 *DstPtr) +{ + u32 Status; + u32 BytesPerPage; + u32 SpareBytesPerPage; + u32 EccSteps; + u32 EccOffset; + u32 DataPhaseAddr; + u32 Index; + u32 *EccPos; + u8 *EccCode; + u8 *EccCalc; + u8 *Ptr = DstPtr; + u8 *SparePtr = InstancePtr->SpareBufPtr; + + BytesPerPage = InstancePtr->Geometry.BytesPerPage; + SpareBytesPerPage = InstancePtr->Geometry.SpareBytesPerPage; + + EccSteps = InstancePtr->EccConfig.NumSteps; + EccCode = &InstancePtr->EccCode[0]; + EccCalc = &InstancePtr->EccCalc[0]; + + /* + * Read page sized bytes in one less AXI data width + */ + XNandPs_ReadBuf(InstancePtr, Ptr, + (BytesPerPage - XNANDPS_AXI_DATA_WIDTH)); + + Ptr += (BytesPerPage - XNANDPS_AXI_DATA_WIDTH); + + /* + * Set the ECC Last bit + */ + DataPhaseAddr = InstancePtr->DataPhaseAddr; + DataPhaseAddr |= XNANDPS_ECC_LAST; + InstancePtr->DataPhaseAddr = DataPhaseAddr; + + /* + * Read transaction with ECC enabled + */ + XNandPs_ReadBuf(InstancePtr, Ptr, XNANDPS_AXI_DATA_WIDTH); + + /* + * Calculate the hardware ECC + */ + Ptr = DstPtr; + Status = XNandPs_EccCalculate(InstancePtr, EccCalc); + if (Status != XST_SUCCESS) { + return Status; + } + DataPhaseAddr = InstancePtr->DataPhaseAddr; + DataPhaseAddr &= ~XNANDPS_ECC_LAST; + InstancePtr->DataPhaseAddr = DataPhaseAddr; + XNandPs_ReadBuf(InstancePtr, SparePtr, + (SpareBytesPerPage - XNANDPS_AXI_DATA_WIDTH)); + + /* + * Clear chip select for last AXI transaction + */ + DataPhaseAddr = InstancePtr->DataPhaseAddr; + DataPhaseAddr |= XNANDPS_CLR_CS; + InstancePtr->DataPhaseAddr = DataPhaseAddr; + SparePtr += (SpareBytesPerPage - XNANDPS_AXI_DATA_WIDTH); + XNandPs_ReadBuf(InstancePtr, SparePtr, XNANDPS_AXI_DATA_WIDTH); + + /* + * Read the stored ECC code + */ + EccPos = &InstancePtr->EccConfig.EccPos[0]; + for(Index = 0; Index < InstancePtr->EccConfig.TotalBytes; Index++) { + EccCode[Index] = ~(InstancePtr->SpareBufPtr[EccPos[Index]]); + } + + /* + * Check for ECC errors + */ + EccOffset = 0; + for(; EccSteps; EccSteps--) { + Status = XNandPs_EccCorrect(DstPtr, + &EccCalc[EccOffset],&EccCode[EccOffset]); + if (Status != XST_SUCCESS) { + return Status; + } + DstPtr += InstancePtr->EccConfig.BlockSize; + EccOffset += InstancePtr->EccConfig.BytesPerBlock; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function reads a specific page from NAND device. This doesn't use the +* HW ECC block for checking ECC errors. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* @param DstPtr is a pointer to the destination buffer. +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None +* +******************************************************************************/ +static int XNandPs_ReadPage(XNandPs *InstancePtr, u8 *DstPtr) +{ + u32 Status; + u32 ZeroCommand; + u32 BytesPerPage; + u16 SpareBytesPerPage; + u32 DataPhaseAddr; + u8 *Ptr = DstPtr; + u8 *SparePtr = InstancePtr->SpareBufPtr; + + BytesPerPage = InstancePtr->Geometry.BytesPerPage; + SpareBytesPerPage = InstancePtr->Geometry.SpareBytesPerPage; + + /* + * Check ONFI Status Register + */ + Status = Onfi_CmdReadStatus(InstancePtr); + if (Status & ONFI_STATUS_FAIL) { + return XST_FAILURE; + } + + /* + * 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); + + /* + * AXI transaction for sending command 0x00 to the flash + */ + Xil_Out32(ZeroCommand, 0x00); + + /* + * Read page data + */ + XNandPs_ReadBuf(InstancePtr, Ptr, BytesPerPage); + + /* + * Read spare bytes in one less AXI data width + */ + XNandPs_ReadBuf(InstancePtr, SparePtr, + (SpareBytesPerPage - XNANDPS_AXI_DATA_WIDTH)); + + /* + * Clear chip select for last AXI transaction + */ + DataPhaseAddr = InstancePtr->DataPhaseAddr; + DataPhaseAddr |= XNANDPS_CLR_CS; + InstancePtr->DataPhaseAddr = DataPhaseAddr; + SparePtr += (SpareBytesPerPage - XNANDPS_AXI_DATA_WIDTH); + XNandPs_ReadBuf(InstancePtr, SparePtr, XNANDPS_AXI_DATA_WIDTH); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function writes a specific page in the NAND device using HW ECC block. +* The ECC code is written into the spare bytes of the page. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* @param SrcPtr is a pointer to the source buffer. +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None +* +******************************************************************************/ +static int XNandPs_WritePage_HwEcc(XNandPs *InstancePtr, u8 *SrcPtr) +{ + u32 Status; + u32 BytesPerPage; + u32 SpareBytesPerPage; + u32 DataPhaseAddr; + u32 Index; + u32 *EccPos; + u8 *EccCalc; + u8 *Ptr = SrcPtr; + u8 *SparePtr = InstancePtr->SpareBufPtr; + + BytesPerPage = InstancePtr->Geometry.BytesPerPage; + SpareBytesPerPage = InstancePtr->Geometry.SpareBytesPerPage; + + EccCalc = &InstancePtr->EccCalc[0]; + + /* + * Transfer page sized bytes in one less AXI data width + */ + XNandPs_WriteBuf(InstancePtr, Ptr, + (BytesPerPage - XNANDPS_AXI_DATA_WIDTH)); + + Ptr += (BytesPerPage - XNANDPS_AXI_DATA_WIDTH); + + /* + * Last page transaction with ECC set + */ + DataPhaseAddr = InstancePtr->DataPhaseAddr; + DataPhaseAddr |= XNANDPS_ECC_LAST; + InstancePtr->DataPhaseAddr = DataPhaseAddr; + XNandPs_WriteBuf(InstancePtr, Ptr, XNANDPS_AXI_DATA_WIDTH); + + /* + * Calculate the ECC + */ + Ptr = SrcPtr; + Status = XNandPs_EccCalculate(InstancePtr, EccCalc); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Fill the Spare buffer with calculated ECC + */ + EccPos = &InstancePtr->EccConfig.EccPos[0]; + for(Index = 0; Index < InstancePtr->EccConfig.TotalBytes; Index++) { + InstancePtr->SpareBufPtr[EccPos[Index]] = ~(EccCalc[Index]); + } + + /* + * Write the spare area with the ECC + */ + DataPhaseAddr = InstancePtr->DataPhaseAddr; + DataPhaseAddr &= ~XNANDPS_ECC_LAST; + InstancePtr->DataPhaseAddr = DataPhaseAddr; + XNandPs_WriteBuf(InstancePtr, SparePtr, + (SpareBytesPerPage - XNANDPS_AXI_DATA_WIDTH)); + + /* + * Clear chip select for last AXI transaction + */ + DataPhaseAddr = InstancePtr->DataPhaseAddr; + DataPhaseAddr |= XNANDPS_CLR_CS; + InstancePtr->DataPhaseAddr = DataPhaseAddr; + SparePtr += (SpareBytesPerPage - XNANDPS_AXI_DATA_WIDTH); + XNandPs_WriteBuf(InstancePtr, SparePtr, XNANDPS_AXI_DATA_WIDTH); + + /* + * Poll the Memory controller status register + */ + while (XNandPs_IsBusy(InstancePtr) == TRUE) { + } + + /* + * Clear the interrupt condition + */ + XNandPs_WriteReg((InstancePtr->Config.SmcBase + + XNANDPS_MEMC_CLR_CONFIG_OFFSET), + XNANDPS_MEMC_CLR_CONFIG_INT_CLR1_MASK); + + /* + * Check SR[0] bit + */ + Status = Onfi_CmdReadStatus(InstancePtr); + if (Status & ONFI_STATUS_FAIL) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function writes a specific page in the NAND device. This doesn't use the +* HW ECC block for ECC code generation. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* @param SrcPtr is a pointer to the source buffer. +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None +* +******************************************************************************/ +static int XNandPs_WritePage(XNandPs *InstancePtr, u8 *SrcPtr) +{ + u32 Status; + u32 DataPhaseAddr; + u32 BytesPerPage; + u16 SpareBytesPerPage; + u8 *Ptr = SrcPtr; + u8 *SparePtr = InstancePtr->SpareBufPtr; + + BytesPerPage = InstancePtr->Geometry.BytesPerPage; + SpareBytesPerPage = InstancePtr->Geometry.SpareBytesPerPage; + + /* + * Transfer page sized bytes + */ + XNandPs_WriteBuf(InstancePtr, Ptr, BytesPerPage); + + /* + * Write the spare data bytes + */ + XNandPs_WriteBuf(InstancePtr, SparePtr, + (SpareBytesPerPage - XNANDPS_AXI_DATA_WIDTH)); + + /* + * Clear chip select for last AXI transaction + */ + DataPhaseAddr = InstancePtr->DataPhaseAddr; + DataPhaseAddr |= XNANDPS_CLR_CS; + InstancePtr->DataPhaseAddr = DataPhaseAddr; + SparePtr += (SpareBytesPerPage - XNANDPS_AXI_DATA_WIDTH); + XNandPs_WriteBuf(InstancePtr, SparePtr, XNANDPS_AXI_DATA_WIDTH); + + /* + * Poll the Memory controller status register + */ + while (XNandPs_IsBusy(InstancePtr) == TRUE) { + } + + /* + * Clear the interrupt condition + */ + XNandPs_WriteReg((InstancePtr->Config.SmcBase + + XNANDPS_MEMC_CLR_CONFIG_OFFSET), + XNANDPS_MEMC_CLR_CONFIG_INT_CLR1_MASK); + + /* + * Check SR[0] bit + */ + Status = Onfi_CmdReadStatus(InstancePtr); + if (Status & ONFI_STATUS_FAIL) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function erases a specific block in the NAND device. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* @param BlockNum is the block number of the device. +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* - XST_NAND_WRITE_PROTECTED if the flash is write +* protected. +* +* @note None +* +******************************************************************************/ +int XNandPs_EraseBlock(XNandPs *InstancePtr, u32 BlockNum) +{ + u8 OnfiStatus; + u32 Status; + u32 Page; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(BlockNum < InstancePtr->Geometry.NumBlocks); + + /* + * Check if the flash is write protected + */ + OnfiStatus = Onfi_CmdReadStatus(InstancePtr); + if (!(OnfiStatus & ONFI_STATUS_WP)) { + return XST_NAND_WRITE_PROTECTED; + } + + Page = BlockNum * InstancePtr->Geometry.PagesPerBlock; + XNandPs_SendCommand(InstancePtr, &OnfiCommands[BLOCK_ERASE], Page, + XNANDPS_COLUMN_NOT_VALID); + + /* + * Poll the Memory controller status register + */ + while (XNandPs_IsBusy(InstancePtr) == TRUE) { + } + + /* + * Clear the interrupt condition + */ + XNandPs_WriteReg((InstancePtr->Config.SmcBase + + XNANDPS_MEMC_CLR_CONFIG_OFFSET), + XNANDPS_MEMC_CLR_CONFIG_INT_CLR1_MASK); + + /* + * Check the SR[0] whether the erase operation is successful or not + */ + Status = Onfi_CmdReadStatus(InstancePtr); + if (Status & ONFI_STATUS_FAIL) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} +/*****************************************************************************/ +/** +* +* This function reads the page data from the AXI Data Phase Address. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* @param Buf is the buffer pointer to store the byte. +* @param Length is the number of bytes to read. +* +* @return +* - None. +* +******************************************************************************/ +static void XNandPs_ReadBuf(XNandPs *InstancePtr, u8 *Buf, u32 Length) +{ + u32 Index; + u32 AxiLen = Length >> 2; + u32 *Ptr = (u32 *)Buf; + + for(Index = 0; Index < AxiLen; Index++) { + Ptr[Index] = XNandPs_ReadReg(InstancePtr->DataPhaseAddr); + } +} + +/*****************************************************************************/ +/** +* +* This function writes the data to the AXI Data Phase Address. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* @param Buf is the buffer pointer to write the data from. +* @param Length is the number of bytes to write. +* +* @return +* - None. +* +******************************************************************************/ +static void XNandPs_WriteBuf(XNandPs *InstancePtr, u8 *Buf, u32 Length) +{ + u32 Index; + u32 AxiLen = Length >> 2; + u32 *Ptr = (u32 *)Buf; + + for(Index = 0; Index < AxiLen; Index++) { + XNandPs_WriteReg(InstancePtr->DataPhaseAddr, Ptr[Index]); + } +} diff --git a/XilinxProcessorIPLib/drivers/nandps/src/xnandps.h b/XilinxProcessorIPLib/drivers/nandps/src/xnandps.h new file mode 100755 index 00000000..804ad337 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/nandps/src/xnandps.h @@ -0,0 +1,447 @@ +/****************************************************************************** +* +* 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.h +* +* This file implements a driver for the NAND flash controller. +* +* Driver Initialization +* +* The function call XNandPs_CfgInitialize() should be called by the application +* before any other function in the driver. The initialization function takes +* device specific data (like device id, instance id, and base address) and +* initializes the XNandPs instance with the device specific data. +* +* Device Geometry +* +* NAND flash device is memory device and it is segmented into areas called +* Logical Unit(s) (LUN) and further in to blocks and pages. A NAND flash device +* can have multiple LUN. LUN is sequential raw of multiple blocks of the same +* size. A block is the smallest erasable unit of data within the Flash array of +* a LUN. The size of each block is based on a power of 2. There is no +* restriction on the number of blocks within the LUN. A block contains a number +* of pages. A page is the smallest addressable unit for read and program +* operations. The arrangement of LUN, blocks, and pages is referred to by this +* module as the part's geometry. +* +* The cells within the part can be programmed from a logic 1 to a logic 0 +* and not the other way around. To change a cell back to a logic 1, the +* entire block containing that cell must be erased. When a block is erased +* all bytes contain the value 0xFF. The number of times a block can be +* erased is finite. Eventually the block will wear out and will no longer +* be capable of erasure. As of this writing, the typical flash block can +* be erased 100,000 or more times. +* +* The jobs done by this driver typically are: +* - 8/16 bit operational mode +* - Read, Write, and Erase operation +* - Read, Write cache operation +* - Read, Write Spare area operation +* - HW Error Check and Correction (ECC) +* +* Write Operation +* +* The write call can be used to write a minimum of one byte and a maximum +* entire flash. If the address offset specified to write is out of flash or if +* the number of bytes specified from the offset exceed flash boundaries +* an error is reported back to the user. The write is blocking in nature in that +* the control is returned back to user only after the write operation is +* completed successfully or an error is reported. +* +* Read Operation +* +* The read call can be used to read a minimum of one byte and maximum of +* entire flash. If the address offset specified to read is out of flash or if +* the number of bytes specified from the offset exceed flash boundaries +* an error is reported back to the user. The read is blocking in nature in that +* the control is returned back to user only after the read operation is +* completed successfully or an error is reported. +* +* Erase Operation +* +* The erase operations are provided to erase a Block in the Flash memory. The +* erase call is blocking in nature in that the control is returned back to user +* only after the erase operation is completed successfully or an error is +* reported. +* +* Page Cache Write Operation +* +* The page cache write call is same as write call except that it uses cache +* commands to write. This enhances the performance. This operation can't be +* performed on OnDie ECC with internal ECC enabled. There is no way to disable +* internal ECC for OnDie ECC flash parts in current driver. This operation +* is tested with Spansion S34ML04G100TFI00 flash. We have to use this operation +* only on the flash parts which supports program page cache command. +* +* Page Cache Read Operation +* +* The page cache read call is same as read call except that it uses cache +* commands to read. This enhances the performance. +* The read cache random command is used since the HW ECC block doesn't +* support commands without address for starting ECC. +* This operation can't be performed on OnDie ECC with internal ECC enabled. +* There is no way to disable internal ECC for OnDie ECC flash parts in current +* driver. This operation is tested with Spansion S34ML04G100TFI00 flash. +* We have to use this operation only on the flash parts which supports +* read page cache command (random). +* +* Write Spare Bytes Operation +* +* This call writes to user specified buffer into spare bytes of a page. +* +* Read Spare Bytes Operation +* +* This call reads spare bytes of a page into user specified buffer. +* +* @note +* +* This driver is intended to be RTOS and processor independent. It works with +* physical addresses only. Any needs for dynamic memory management, threads, +* mutual exclusion, virtual memory, cache control, or HW write protection +* management must be satisfied by the layer above this driver. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date    	   Changes
+* ----- ----   ----------  -----------------------------------------------
+* 1.00a nm     12/10/2010  First release
+* 	nm     29/09/2011  Added support for On-Die ECC NAND and Clean NAND
+*                          flash parts.
+*                          Added user spare buffer pointer to read/write
+*                          API's. Added new API's for reading and writing
+*                          spare buffer area.
+*                          Changes nand_cycles with ONFI timing mode 0.
+*                          Modified ONFI parameter page reading to read 3
+*                          mandatory pages.
+* 1.01a nm     28/02/2012  Added tcl file to generate xparameters.h.
+*                          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.02a nm     20/09/2012  Removed setting of set_cycles and set_opmode
+*                          register values as it is now done in FSBL using
+*                          the PCW generated files. CR#678949.
+* 1.03a nm     10/22/2012  Fixed CR# 683787,673348.
+* 1.04a nm     04/15/2013  Fixed CR# 704401. Removed warnings when compiled
+* 			   with -Wall and -Wextra option in bsp.
+*	       04/25/2013  Implemented PR# 699544. Added page cache read
+*			   and program support. Added API's XNandPs_ReadCache
+*			   and XNandPs_WriteCache for page cache support.
+*			   Added XNandPs_Features structure to XNandPs instance
+*			   which contains features handled by driver.
+*			   Added function prototypes for Page cache read/write
+*			   and spare byte read/write API's.
+* 2.0   adk    12/10/13    Updated as per the New Tcl API's
+* 2.1   kpc    07/24/13    Fixed CR#808770. Update command register twice only
+*                          if flash device requires >= four address cycles.
+* 
+* +******************************************************************************/ + +#ifndef XNANDPS_H /* prevent circular inclusions */ +#define XNANDPS_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ +#include /* For memcpy, memset */ +#include "xil_types.h" +#include "xil_assert.h" +#include "xil_io.h" +#include "xstatus.h" +#include "xnandps_hw.h" +/************************** Constant Definitions *****************************/ +#define XNANDPS_MAX_TARGETS 1 /**< Max number of targets + supported */ +#define XNANDPS_MAX_BLOCKS 32768 /**< Max number of Blocks */ +#define XNANDPS_MAX_PAGE_SIZE 16384 /**< Max page size of NAND + flash */ +#define XNANDPS_MAX_SPARE_SIZE 512 /**< Max spare bytes of a NAND + flash page */ +#define XNANDPS_ECC_BLOCK_SIZE 512 /**< ECC block size */ +#define XNANDPS_ECC_BYTES 3 /**< ECC bytes per ECC block */ + +#define XNANDPS_PAGE_SIZE_512 512 /**< Page size 512 */ +#define XNANDPS_PAGE_SIZE_1024 1024 /**< Page size 1024 */ +#define XNANDPS_PAGE_SIZE_2048 2048 /**< Page size 2048 */ +#define XNANDPS_PAGE_SIZE_4096 4096 /**< Page size 4096 */ +#define XNANDPS_PAGE_SIZE_8192 8192 /**< Page size 8192 */ + +#define XNANDPS_SPARE_SIZE_8 8 /**< Spare bytes size 8 */ +#define XNANDPS_SPARE_SIZE_16 16 /**< Spare bytes size 16 */ +#define XNANDPS_SPARE_SIZE_32 32 /**< Spare bytes size 32 */ +#define XNANDPS_SPARE_SIZE_64 64 /**< Spare bytes size 64 */ +#define XNANDPS_SPARE_SIZE_128 128 /**< Spare bytes size 128 */ +#define XNANDPS_SPARE_SIZE_256 256 /**< Spare bytes size 256 */ + +#define XNANDPS_FLASH_WIDTH_8 8 /**< NAND Flash width 8-bit */ +#define XNANDPS_FLASH_WIDTH_16 16 /**< NAND Flash width 16-bit */ + +/* Macros used for framing SMC AXI command phase and Data phase address */ +#define XNANDPS_END_CMD_NONE 0 /**< No End command */ +#define XNANDPS_END_CMD_INVALID 0 /**< End command invalid */ +#define XNANDPS_CMD_PHASE 1 /**< End command in command + phase */ +#define XNANDPS_DATA_PHASE 2 /**< End command in data + phase */ + +#define XNANDPS_PAGE_NOT_VALID -1 /**< Page is not valid in + command phase */ +#define XNANDPS_COLUMN_NOT_VALID -1 /**< Column is not valid in + command phase */ + +#define XNANDPS_AXI_DATA_WIDTH 4 /**< AXI Data width for last + transaction while reading + and writing */ + +/* Bit shift for AXI Command/Data phase address calculation */ +#define XNANDPS_START_CMD_SHIFT 3 /**< Start command shift */ +#define XNANDPS_END_CMD_SHIFT 11 /**< End command shift */ +#define XNANDPS_END_CMD_VALID_SHIFT 20 /**< End command valid shift */ +#define XNANDPS_ADDR_CYCLES_SHIFT 21 /**< Address cycles shift */ +#define XNANDPS_CHIP_ADDR_SHIFT 24 /**< Chip address shift */ +#define XNANDPS_ECC_LAST_SHIFT 10 /**< Ecc last shift */ +#define XNANDPS_CLEAR_CS_SHIFT 21 /**< clear chip select shift */ +#define XNANDPS_COMMAND_PHASE_MASK 0x00000000 /**< Command + phase mask */ +#define XNANDPS_DATA_PHASE_MASK 0x00080000 /**< Data phase mask */ + +/* Macros used for correcting ECC errors */ +#define XNANDPS_ECC_CORRECT_BYTE_MASK 0x1FF /**< ECC error correction byte + position mask, bits[11:3] of + error code */ +#define XNANDPS_ECC_CORRECT_BIT_MASK 0x7 /**< ECC error correction bit + position mask, bits[0:2] of + error code */ + +/* Flash memory controller operating parameters */ +#define XNANDPS_CLR_CONFIG \ + ((XNANDPS_MEMC_CLR_CONFIG_INT_DISABLE1_MASK) | \ + (XNANDPS_MEMC_CLR_CONFIG_INT_CLR1_MASK) | \ + (XNANDPS_MEMC_CLR_CONFIG_ECC_INT_DISABLE1_MASK)) + /**< Interrupt settings */ + +#define XNANDPS_ECC_MEMCFG \ + ((0x1 << XNANDPS_ECC_MEMCFG_ECC_MODE_SHIFT) | \ + (0x1 << XNANDPS_ECC_MEMCFG_ECC_READ_END_SHIFT) | \ + (0x0 << XNANDPS_ECC_MEMCFG_ECC_JUMP_SHIFT)) + /**< ECC memory configuration settings */ + +#define XNANDPS_ECC_CMD1 \ + ((0x80 << XNANDPS_ECC_MEMCOMMAND1_WR_CMD_SHIFT) | \ + (0x00 << XNANDPS_ECC_MEMCOMMAND1_RD_CMD_SHIFT) | \ + (0x30 << XNANDPS_ECC_MEMCOMMAND1_RD_CMD_END_SHIFT) | \ + (0x1 << XNANDPS_ECC_MEMCOMMAND1_RD_CMD_END_VALID_SHIFT)) + /**< ECC command 1 settings */ + +#define XNANDPS_ECC_CMD2 \ + ((0x85 << XNANDPS_ECC_MEMCOMMAND2_WR_COL_CHANGE_SHIFT) | \ + (0x05 << XNANDPS_ECC_MEMCOMMAND2_RD_COL_CHANGE_SHIFT) | \ + (0xE0 << XNANDPS_ECC_MEMCOMMAND2_RD_COL_CHANGE_END_SHIFT) | \ + (0x1 << XNANDPS_ECC_MEMCOMMAND2_RD_COL_CHANGE_END_VALID_SHIFT)) + /**< ECC command 2 settings */ + +#define XNANDPS_CLR_CS (0x1 << XNANDPS_CLEAR_CS_SHIFT) + /**< set Clear chip select */ +#define XNANDPS_ECC_LAST (0x1 << XNANDPS_ECC_LAST_SHIFT) + /**< set Ecc last */ + +/**************************** Type Definitions *******************************/ +/* + * This enum contains ECC Mode + */ +typedef enum { + XNANDPS_ECC_NONE = 0, /**< No ECC */ + XNANDPS_ECC_SW, /**< Software ECC */ + XNANDPS_ECC_HW, /**< Hardware controller ECC */ + XNANDPS_ECC_ONDIE /**< On-Die ECC */ +} XNandPs_EccMode; + +/** + * This typedef contains configuration information for the flash device. + */ +typedef struct { + u16 DeviceId; /**< Instance ID of device */ + u32 SmcBase; /**< SMC Base address */ + u32 FlashBase; /**< NAND base address */ + u32 FlashWidth; /**< Flash width */ +} XNandPs_Config; +/** + * Flash geometry + */ +typedef struct { + u32 BytesPerPage; /**< Bytes per page */ + u16 SpareBytesPerPage; /**< Size of spare area in bytes */ + u32 PagesPerBlock; /**< Pages per block */ + u32 BlocksPerLun; /**< Bocks per LUN */ + u8 NumLun; /**< Total number of LUN */ + u8 FlashWidth; /**< Data width of flash device */ + u64 NumPages; /**< Total number of pages in device */ + u64 NumBlocks; /**< Total number of blocks in device */ + u64 BlockSize; /**< Size of a block in bytes */ + u64 DeviceSize; /**< Total device size in bytes */ + u8 RowAddrCycles; /**< Row address cycles */ + u8 ColAddrCycles; /**< Column address cycles */ +} XNandPs_Geometry; + +/** + * ONFI Features and Optional commands supported + * See parameter page byte 6-7 and 8-9 + */ +typedef struct { + int ProgramCache; + int ReadCache; +} XNandPs_Features; + +/** + * Bad block table descriptor + */ +typedef struct { + u32 PageOffset; /**< Page offset where BBT resides */ + u32 SigOffset; /**< Signature offset in Spare area */ + u32 VerOffset; /**< Offset of BBT version */ + u32 SigLength; /**< Length of the signature */ + u32 MaxBlocks; /**< Max blocks to search for BBT */ + char Signature[4]; /**< BBT signature */ + u8 Version; /**< BBT version */ + u32 Valid; /**< BBT descriptor is valid or not */ +} XNandPs_BbtDesc; + +/** + * Bad block pattern + */ +typedef struct { + u32 Options; /**< Options to search the bad block pattern */ + u32 Offset; /**< Offset to search for specified pattern */ + u32 Length; /**< Number of bytes to check the pattern */ + u8 Pattern[2]; /**< Pattern format to search for */ +} XNandPs_BadBlockPattern; + +/** + * ECC configuration structure. + * Contains information related to ECC. + */ +typedef struct { + u32 NumSteps; /**< Number of ECC steps for the flash page */ + u32 BlockSize; /**< ECC block size */ + u32 BytesPerBlock; /**< Number of ECC bytes for a block */ + u32 TotalBytes; /**< Total number of ECC bytes for Page */ + u32 EccPos[XNANDPS_MAX_SPARE_SIZE]; + /**< ECC position in the spare area */ +} XNandPs_EccConfig; + +/** + * The XNandPs driver instance data. The user is required to allocate a + * variable of this type for every flash device in the system. A pointer to a + * variable of this type is then passed to the driver API functions. + */ +typedef struct XNandPsTag { + u32 IsReady; /**< Device is initialized and ready */ + XNandPs_Config Config; /**< XNandPs_Config of current + device */ + XNandPs_Geometry Geometry; /**< Part geometry */ + XNandPs_Features Features; /**< Features and Optional commands */ + u32 CommandPhaseAddr; /**< NAND command phase address */ + u32 DataPhaseAddr; /**< NAND Data phase address */ + XNandPs_EccConfig EccConfig; /**< ECC configuration parameters */ + /* Bad block table definitions */ + XNandPs_BbtDesc BbtDesc; /**< Bad block table descriptor */ + XNandPs_BbtDesc BbtMirrorDesc; /**< Mirror BBT descriptor */ + XNandPs_BadBlockPattern BbPattern; /**< Bad block pattern to + search */ + u8 Bbt[XNANDPS_MAX_BLOCKS >> 2]; /**< Bad block table array */ + u8 DataBuf[XNANDPS_MAX_PAGE_SIZE + XNANDPS_MAX_SPARE_SIZE]; + /**< Data buffer for partial read/writes */ + u8 *SpareBufPtr; /**< Pointer to store spare buffer */ + u8 EccCalc[XNANDPS_MAX_SPARE_SIZE]; /**< Buffer for calculated + ECC */ + u8 EccCode[XNANDPS_MAX_SPARE_SIZE]; /**< Buffer for stored ECC */ + XNandPs_EccMode EccMode; /**< ECC Mode */ + int (*ReadPage) (struct XNandPsTag *InstancePtr, u8 *DstPtr); + /**< Read Page routine */ + int (*WritePage) (struct XNandPsTag *InstancePtr, u8 *SrcPtr); + /**< Write Page routine */ +} XNandPs; + +/** + * NAND Command format structures + */ +typedef struct { + int StartCmd; /**< Start command */ + int EndCmd; /**< End command */ + u8 AddrCycles; /**< Number of address cycles */ + u8 EndCmdValid; /**< End command valid */ +} XNandPs_CommandFormat; +/***************** Macros (Inline Functions) Definitions *********************/ + +/** + * OneHot is used to check if one and only one bit is set. + * This Macro returns 1 if the value passed is OneHot. + */ +#define OneHot(Value) (!((Value) & (Value - 1))) + +/************************** Function Prototypes ******************************/ + +/* + * Functions in xnandps_sinit.c + */ +XNandPs_Config *XNandPs_LookupConfig(u16 DeviceId); + +/* + * Functions in xnandps.c + */ +/* + * Initialization, read, write and erase functions. + */ +int XNandPs_CfgInitialize(XNandPs *InstancePtr, XNandPs_Config *ConfigPtr, + u32 SmcBaseAddr, u32 FlashBaseAddr); +int XNandPs_Read(XNandPs *InstancePtr, u64 Offset, u32 Bytes, void *DestPtr, + u8 *UserSparePtr); +int XNandPs_ReadCache(XNandPs *InstancePtr, u64 Offset, u32 Bytes, + void *SrcPtr, u8 *UserSparePtr); +int XNandPs_Write(XNandPs *InstancePtr, u64 Offset, u32 Bytes, void *SrcPtr, + u8 *UserSparePtr); +int XNandPs_WriteCache(XNandPs *InstancePtr, u64 Offset, u32 Length, + void *SrcPtr, u8 *UserSparePtr); +int XNandPs_ReadSpareBytes(XNandPs *InstancePtr, u32 Page, u8 *Buf); +int XNandPs_WriteSpareBytes(XNandPs *InstancePtr, u32 Page, u8 *Buf); +int XNandPs_EraseBlock(XNandPs *InstancePtr, u32 BlockNum); +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/nandps/src/xnandps_bbm.c b/XilinxProcessorIPLib/drivers/nandps/src/xnandps_bbm.c new file mode 100755 index 00000000..48694400 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/nandps/src/xnandps_bbm.c @@ -0,0 +1,869 @@ +/****************************************************************************** +* +* 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_bbm.c +* This file implements the Bad Block Management (BBM) functionality. +* See xnandps_bbm.h for more details. +* +* @note None +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date    	   Changes
+* ----- ----   ----------  -----------------------------------------------
+* 1.00a nm     12/10/2010  First release
+* 1.03a nm     10/22/2012  Fixed CR# 683787.
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include /**< For memcpy and memset */ +#include "xil_types.h" +#include "xnandps_bbm.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ +static int XNandPs_ReadBbt(XNandPs *InstancePtr); + +static int XNandPs_SearchBbt(XNandPs *InstancePtr, XNandPs_BbtDesc *Desc); + +static void XNandPs_CreateBbt(XNandPs *InstancePtr); + +static void XNandPs_ConvertBbt(XNandPs *InstancePtr, u8 *Buf); + +static int XNandPs_WriteBbt(XNandPs *InstancePtr, XNandPs_BbtDesc *Desc, + XNandPs_BbtDesc *MirrorDesc); + +static int XNandPs_MarkBbt(XNandPs* InstancePtr, XNandPs_BbtDesc *Desc); + +static int XNandPs_UpdateBbt(XNandPs *InstancePtr); + +extern int XNandPs_ReadSpareBytes(XNandPs *InstancePtr, u32 Page, u8 *Buf); +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ +/** +* This function initializes the Bad Block Table(BBT) descriptors with a +* predefined pattern for searching Bad Block Table(BBT) in flash. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* +* @return +* - NONE +* +******************************************************************************/ +void XNandPs_InitBbtDesc(XNandPs *InstancePtr) +{ + int Index; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Initialize primary Bad Block Table(BBT) + */ + InstancePtr->BbtDesc.PageOffset = XNANDPS_BBT_DESC_PAGE_OFFSET; + if (InstancePtr->EccMode == XNANDPS_ECC_ONDIE) { + InstancePtr->BbtDesc.SigOffset = 0x4; + InstancePtr->BbtDesc.VerOffset = 0x14; + } else { + InstancePtr->BbtDesc.SigOffset = XNANDPS_BBT_DESC_SIG_OFFSET; + InstancePtr->BbtDesc.VerOffset = XNANDPS_BBT_DESC_VER_OFFSET; + } + InstancePtr->BbtDesc.SigLength = XNANDPS_BBT_DESC_SIG_LEN; + InstancePtr->BbtDesc.MaxBlocks = XNANDPS_BBT_DESC_MAX_BLOCKS; + strcpy(&InstancePtr->BbtDesc.Signature[0], "Bbt0"); + InstancePtr->BbtDesc.Version = 0; + InstancePtr->BbtDesc.Valid = 0; + + /* + * Initialize mirror Bad Block Table(BBT) + */ + InstancePtr->BbtMirrorDesc.PageOffset = XNANDPS_BBT_DESC_PAGE_OFFSET; + if (InstancePtr->EccMode == XNANDPS_ECC_ONDIE) { + InstancePtr->BbtMirrorDesc.SigOffset = 0x4; + InstancePtr->BbtMirrorDesc.VerOffset = 0x14; + } else { + InstancePtr->BbtMirrorDesc.SigOffset = XNANDPS_BBT_DESC_SIG_OFFSET; + InstancePtr->BbtMirrorDesc.VerOffset = XNANDPS_BBT_DESC_VER_OFFSET; + } + InstancePtr->BbtMirrorDesc.SigLength = XNANDPS_BBT_DESC_SIG_LEN; + InstancePtr->BbtMirrorDesc.MaxBlocks = XNANDPS_BBT_DESC_MAX_BLOCKS; + strcpy(&InstancePtr->BbtMirrorDesc.Signature[0], "1tbB"); + InstancePtr->BbtMirrorDesc.Version = 0; + InstancePtr->BbtMirrorDesc.Valid = 0; + + /* + * Initialize Bad block search pattern structure + */ + if (InstancePtr->Geometry.BytesPerPage > 512) { + /* For flash page size > 512 bytes */ + InstancePtr->BbPattern.Options = XNANDPS_BBT_SCAN_2ND_PAGE; + InstancePtr->BbPattern.Offset = + XNANDPS_BB_PATTERN_OFFSET_LARGE_PAGE; + InstancePtr->BbPattern.Length = + XNANDPS_BB_PATTERN_LENGTH_LARGE_PAGE; + } else { + InstancePtr->BbPattern.Options = XNANDPS_BBT_SCAN_2ND_PAGE; + InstancePtr->BbPattern.Offset = + XNANDPS_BB_PATTERN_OFFSET_SMALL_PAGE; + InstancePtr->BbPattern.Length = + XNANDPS_BB_PATTERN_LENGTH_SMALL_PAGE; + } + for(Index=0; Index < XNANDPS_BB_PATTERN_LENGTH_LARGE_PAGE; Index++) { + InstancePtr->BbPattern.Pattern[Index] = XNANDPS_BB_PATTERN; + } +} +/*****************************************************************************/ +/** +* This function scans the NAND flash for factory marked bad blocks and creates +* a RAM based Bad Block Table(BBT). +* +* @param InstancePtr is a pointer to the XNandPs instance. +* +* @return +* - NONE +* +******************************************************************************/ +static void XNandPs_CreateBbt(XNandPs *InstancePtr) +{ + u32 BlockIndex; + u32 PageIndex; + u32 Length; + u32 BlockOffset; + u32 BlockShift; + u32 NumPages; + u32 Page; + u8 Buf[XNANDPS_MAX_SPARE_SIZE]; + u32 BbtLen = InstancePtr->Geometry.NumBlocks >> + XNANDPS_BBT_BLOCK_SHIFT; + int Status; + + /* + * Number of pages to search for bad block pattern + */ + if (InstancePtr->BbPattern.Options & XNANDPS_BBT_SCAN_2ND_PAGE) { + NumPages = 2; + } else { + NumPages = 1; + } + + /* + * Zero the RAM based Bad Block Table(BBT) entries + */ + memset(&InstancePtr->Bbt[0], 0, BbtLen); + + /* + * Scan all the blocks for factory marked bad blocks + */ + for(BlockIndex = 0; BlockIndex < + InstancePtr->Geometry.NumBlocks; BlockIndex++) { + /* + * Block offset in Bad Block Table(BBT) entry + */ + BlockOffset = BlockIndex >> XNANDPS_BBT_BLOCK_SHIFT; + /* + * Block shift value in the byte + */ + BlockShift = XNandPs_BbtBlockShift(BlockIndex); + Page = BlockIndex * InstancePtr->Geometry.PagesPerBlock; + + /* + * Search for the bad block pattern + */ + for(PageIndex = 0; PageIndex < NumPages; PageIndex++) { + Status = XNandPs_ReadSpareBytes(InstancePtr, + (Page + PageIndex), &Buf[0]); + + if (Status != XST_SUCCESS) { + /* Marking as bad block */ + InstancePtr->Bbt[BlockOffset] |= + (XNANDPS_BLOCK_FACTORY_BAD << + BlockShift); + break; + } + + /* + * Read the spare bytes to check for bad block + * pattern + */ + for(Length = 0; Length < + InstancePtr->BbPattern.Length; Length++) { + if (Buf[InstancePtr->BbPattern.Offset + Length] + != + InstancePtr->BbPattern.Pattern[Length]) + { + /* Bad block found */ + InstancePtr->Bbt[BlockOffset] |= + (XNANDPS_BLOCK_FACTORY_BAD << + BlockShift); + break; + } + } + } + } +} +/*****************************************************************************/ +/** +* This function reads the Bad Block Table(BBT) if present in flash. If not it +* scans the flash for detecting factory marked bad blocks and creates a bad +* block table and write the Bad Block Table(BBT) into the flash. +* +* @param InstancePtr is a pointer to the XNandPs instance. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +int XNandPs_ScanBbt(XNandPs *InstancePtr) +{ + int Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + if (XNandPs_ReadBbt(InstancePtr) != XST_SUCCESS) { + /* + * Create memory based Bad Block Table(BBT) + */ + XNandPs_CreateBbt(InstancePtr); + + /* + * Write the Bad Block Table(BBT) to the flash + */ + Status = XNandPs_WriteBbt(InstancePtr, + &InstancePtr->BbtDesc, + &InstancePtr->BbtMirrorDesc); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Write the Mirror Bad Block Table(BBT) to the flash + */ + Status = XNandPs_WriteBbt(InstancePtr, + &InstancePtr->BbtMirrorDesc, + &InstancePtr->BbtDesc); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Mark the blocks containing Bad Block Table(BBT) as Reserved + */ + XNandPs_MarkBbt(InstancePtr, &InstancePtr->BbtDesc); + XNandPs_MarkBbt(InstancePtr, &InstancePtr->BbtMirrorDesc); + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function converts the Bad Block Table(BBT) read from the flash to the RAM +* based Bad Block Table(BBT). +* +* @param InstancePtr is a pointer to the XNandPs instance. +* @param Buf is the buffer which contains BBT read from flash. +* +* @return +* - NONE. +* +******************************************************************************/ +static void XNandPs_ConvertBbt(XNandPs *InstancePtr, u8 *Buf) +{ + u32 BlockOffset; + u32 BlockShift; + u32 Data; + u8 BlockType; + u32 BlockIndex; + u32 BbtLen = InstancePtr->Geometry.NumBlocks >> + XNANDPS_BBT_BLOCK_SHIFT; + + for(BlockOffset = 0; BlockOffset < BbtLen; BlockOffset++) { + Data = Buf[BlockOffset]; + + /* + * Clear the RAM based Bad Block Table(BBT) contents + */ + InstancePtr->Bbt[BlockOffset] = 0x0; + + /* + * Loop through the every 4 blocks in the bitmap + */ + for(BlockIndex = 0; BlockIndex < XNANDPS_BBT_ENTRY_NUM_BLOCKS; + BlockIndex++) { + BlockShift = XNandPs_BbtBlockShift(BlockIndex); + BlockType = (Data >> BlockShift) & + XNANDPS_BLOCK_TYPE_MASK; + switch(BlockType) { + case XNANDPS_FLASH_BLOCK_FACTORY_BAD: + /* Factory bad block */ + InstancePtr->Bbt[BlockOffset] |= + XNANDPS_BLOCK_FACTORY_BAD << + BlockShift; + break; + case XNANDPS_FLASH_BLOCK_RESERVED: + /* Reserved block */ + InstancePtr->Bbt[BlockOffset] |= + XNANDPS_BLOCK_RESERVED << + BlockShift; + break; + case XNANDPS_FLASH_BLOCK_BAD: + /* Bad block due to wear */ + InstancePtr->Bbt[BlockOffset] |= + XNANDPS_BLOCK_BAD << + BlockShift; + break; + default: + /* Good block */ + /* The BBT entry already defaults to + * zero */ + break; + } + } + } +} +/*****************************************************************************/ +/** +* This function searches the Bad Bloock Table(BBT) in flash and loads into the +* memory based Bad Block Table(BBT). +* +* @param InstancePtr is the pointer to the XNandPs instance. +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +static int XNandPs_ReadBbt(XNandPs *InstancePtr) +{ + u64 Offset; + u8 Buf[XNANDPS_MAX_BLOCKS >> XNANDPS_BBT_BLOCK_SHIFT]; + u32 Status1; + u32 Status2; + u32 Status; + u32 BbtLen; + + XNandPs_BbtDesc *Desc = &InstancePtr->BbtDesc; + XNandPs_BbtDesc *MirrorDesc = &InstancePtr->BbtMirrorDesc; + BbtLen = InstancePtr->Geometry.NumBlocks >> XNANDPS_BBT_BLOCK_SHIFT; + + /* + * Search the Bad Block Table(BBT) in flash + */ + Status1 = XNandPs_SearchBbt(InstancePtr, Desc); + Status2 = XNandPs_SearchBbt(InstancePtr, MirrorDesc); + if ((Status1 != XST_SUCCESS) && (Status2 != XST_SUCCESS)) { + return XST_FAILURE; + } + + /* + * Bad Block Table found + */ + if (Desc->Valid && MirrorDesc->Valid) { + /* + * Valid BBT & Mirror BBT found + */ + if (Desc->Version > MirrorDesc->Version) { + Offset = Desc->PageOffset * + InstancePtr->Geometry.BytesPerPage; + XNandPs_Read(InstancePtr, Offset, BbtLen, &Buf, NULL); + + /* + * Convert flash BBT to memory based BBT + */ + XNandPs_ConvertBbt(InstancePtr, &Buf[0]); + MirrorDesc->Version = Desc->Version; + + /* + * Write the BBT to Mirror BBT location in flash + */ + Status = XNandPs_WriteBbt(InstancePtr, MirrorDesc, + Desc); + if (Status != XST_SUCCESS) { + return Status; + } + } else if (Desc->Version < MirrorDesc->Version) { + Offset = MirrorDesc->PageOffset * + InstancePtr->Geometry.BytesPerPage; + XNandPs_Read(InstancePtr, Offset, BbtLen, &Buf, NULL); + + /* + * Convert flash BBT to memory based BBT + */ + XNandPs_ConvertBbt(InstancePtr, &Buf[0]); + Desc->Version = MirrorDesc->Version; + + /* + * Write the Mirror BBT to BBT location in flash + */ + Status = XNandPs_WriteBbt(InstancePtr, Desc, + MirrorDesc); + if (Status != XST_SUCCESS) { + return Status; + } + } else { + /* Both are up-to-date */ + Offset = Desc->PageOffset * + InstancePtr->Geometry.BytesPerPage; + XNandPs_Read(InstancePtr, Offset, BbtLen, &Buf, NULL); + + /* + * Convert flash BBT to memory based BBT + */ + XNandPs_ConvertBbt(InstancePtr, &Buf[0]); + } + } else if (Desc->Valid) { + /* + * Valid Primary BBT found + */ + Offset = Desc->PageOffset * InstancePtr->Geometry.BytesPerPage; + XNandPs_Read(InstancePtr, Offset, BbtLen, &Buf, NULL); + + /* + * Convert flash BBT to memory based BBT + */ + XNandPs_ConvertBbt(InstancePtr, &Buf[0]); + MirrorDesc->Version = Desc->Version; + + /* + * Write the BBT to Mirror BBT location in flash + */ + Status = XNandPs_WriteBbt(InstancePtr, MirrorDesc, Desc); + if (Status != XST_SUCCESS) { + return Status; + } + } else { + /* + * Valid Mirror BBT found + */ + Offset = MirrorDesc->PageOffset * + InstancePtr->Geometry.BytesPerPage; + XNandPs_Read(InstancePtr, Offset, BbtLen, &Buf, NULL); + + /* + * Convert flash BBT to memory based BBT + */ + XNandPs_ConvertBbt(InstancePtr, &Buf[0]); + Desc->Version = MirrorDesc->Version; + + /* + * Write the Mirror BBT to BBT location in flash + */ + Status = XNandPs_WriteBbt(InstancePtr, Desc, MirrorDesc); + if (Status != XST_SUCCESS) { + return Status; + } + } + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function searches the BBT in flash. +* +* @param InstancePtr is the pointer to the XNandPs instance. +* @param Desc is the BBT descriptor pattern to search. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +static int XNandPs_SearchBbt(XNandPs *InstancePtr, XNandPs_BbtDesc *Desc) +{ + u32 StartBlock; + u32 SigOffset; + u32 VerOffset; + u32 MaxBlocks; + u32 PageOff; + u32 SigLength; + u8 Buf[XNANDPS_MAX_SPARE_SIZE]; + u32 Block; + u32 Offset; + int Status; + + StartBlock = InstancePtr->Geometry.NumBlocks - 1; + SigOffset = Desc->SigOffset; + VerOffset = Desc->VerOffset; + MaxBlocks = Desc->MaxBlocks; + SigLength = Desc->SigLength; + + /* + * Read the last 4 blocks for Bad Block Table(BBT) signature + */ + for(Block = 0; Block < MaxBlocks; Block++) { + PageOff = (StartBlock - Block) * + InstancePtr->Geometry.PagesPerBlock; + + Status = XNandPs_ReadSpareBytes(InstancePtr, PageOff, &Buf[0]); + if (Status != XST_SUCCESS) { + continue; + } + + /* + * Check the Bad Block Table(BBT) signature + */ + for(Offset = 0; Offset < SigLength; Offset++) { + if (Buf[Offset + SigOffset] != Desc->Signature[Offset]) + { + break; /* Check the next blocks */ + } + } + if (Offset >= SigLength) { + /* + * Bad Block Table(BBT) found + */ + Desc->PageOffset = PageOff; + Desc->Version = Buf[VerOffset]; + Desc->Valid = 1; + return XST_SUCCESS; + } + } + /* + * Bad Block Table(BBT) not found + */ + return XST_FAILURE; +} + +/*****************************************************************************/ +/** +* This function writes Bad Block Table(BBT) from RAM to flash. +* +* @param InstancePtr is the pointer to the XNandPs instance. +* @param Desc is the BBT descriptor to be written to flash. +* @param MirrorDesc is the mirror BBT descriptor. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +static int XNandPs_WriteBbt(XNandPs *InstancePtr, XNandPs_BbtDesc *Desc, + XNandPs_BbtDesc *MirrorDesc) +{ + u64 Offset; + u32 Block = InstancePtr->Geometry.NumBlocks - 1; + u8 Buf[XNANDPS_MAX_BLOCKS >> XNANDPS_BBT_BLOCK_SHIFT]; + u8 SpareBuf[XNANDPS_MAX_SPARE_SIZE]; + u8 Mask[4] = {0x00, 0x01, 0x02, 0x03}; + u8 Data; + u32 BlockOffset; + u32 BlockShift; + u32 Status; + u32 BlockIndex; + u32 Index; + u8 BlockType; + u32 BbtLen = InstancePtr->Geometry.NumBlocks >> + XNANDPS_BBT_BLOCK_SHIFT; + + /* + * Find a valid block to write the Bad Block Table(BBT) + */ + if (!Desc->Valid) { + for(Index = 0; Index < Desc->MaxBlocks; Index++) { + Block = (Block - Index); + BlockOffset = Block >> XNANDPS_BBT_BLOCK_SHIFT; + BlockShift = XNandPs_BbtBlockShift(Block); + BlockType = (InstancePtr->Bbt[BlockOffset] >> + BlockShift) & XNANDPS_BLOCK_TYPE_MASK; + switch(BlockType) + { + case XNANDPS_BLOCK_BAD: + case XNANDPS_BLOCK_FACTORY_BAD: + continue; + default: + /* Good Block */ + break; + } + Desc->PageOffset = Block * + InstancePtr->Geometry.PagesPerBlock; + if (Desc->PageOffset != MirrorDesc->PageOffset) { + /* Free block found */ + Desc->Valid = 1; + break; + } + } + + /* + * Block not found for writing Bad Block Table(BBT) + */ + if (Index >= Desc->MaxBlocks) { + return XST_FAILURE; + } + } else { + Block = Desc->PageOffset/InstancePtr->Geometry.PagesPerBlock; + } + + /* + * Convert the memory based BBT to flash based table + */ + memset(Buf, 0xff, BbtLen); + + /* + * Loop through the number of blocks + */ + for(BlockOffset = 0; BlockOffset < BbtLen; BlockOffset++) { + Data = InstancePtr->Bbt[BlockOffset]; + /* + * Calculate the bit mask for 4 blocks at a time in loop + */ + for(BlockIndex = 0; BlockIndex < XNANDPS_BBT_ENTRY_NUM_BLOCKS; + BlockIndex++) { + BlockShift = XNandPs_BbtBlockShift(BlockIndex); + Buf[BlockOffset] &= ~(Mask[Data & + XNANDPS_BLOCK_TYPE_MASK] << + BlockShift); + Data >>= XNANDPS_BBT_BLOCK_SHIFT; + } + } + + /* + * Write the Bad Block Table(BBT) to flash + */ + Status = XNandPs_EraseBlock(InstancePtr, Block); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Write the signature and version in the spare data area + */ + memset(SpareBuf, 0xff, InstancePtr->Geometry.SpareBytesPerPage); + memcpy(SpareBuf + Desc->SigOffset, &Desc->Signature[0], + Desc->SigLength); + memcpy(SpareBuf + Desc->VerOffset, &Desc->Version, 1); + + /* + * Write the BBT to page offset + */ + Offset = Desc->PageOffset * InstancePtr->Geometry.BytesPerPage; + Status = XNandPs_Write(InstancePtr, Offset, BbtLen, &Buf[0], SpareBuf); + if (Status != XST_SUCCESS) { + return Status; + } + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function updates the primary and mirror Bad Block Table(BBT) in the +* flash. +* +* @param InstancePtr is the pointer to the XNandPs instance. +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +static int XNandPs_UpdateBbt(XNandPs *InstancePtr) +{ + int Status; + u8 Version; + + /* + * Update the version number + */ + Version = InstancePtr->BbtDesc.Version; + InstancePtr->BbtDesc.Version = (Version + 1) % 256; + Version = InstancePtr->BbtMirrorDesc.Version; + InstancePtr->BbtMirrorDesc.Version = (Version + 1) % 256; + + /* + * Update the primary Bad Block Table(BBT) in flash + */ + Status = XNandPs_WriteBbt(InstancePtr, &InstancePtr->BbtDesc, + &InstancePtr->BbtMirrorDesc); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Update the mirrored Bad Block Table(BBT) in flash + */ + Status = XNandPs_WriteBbt(InstancePtr, &InstancePtr->BbtMirrorDesc, + &InstancePtr->BbtDesc); + if (Status != XST_SUCCESS) { + return Status; + } + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function marks the block containing Bad Block Table as reserved +* and updates the BBT. +* +* @param InstancePtr is the pointer to the XNandPs instance. +* @param Desc is the BBT descriptor pointer. +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +static int XNandPs_MarkBbt(XNandPs* InstancePtr, XNandPs_BbtDesc *Desc) +{ + u32 BlockIndex; + u32 BlockOffset; + u8 BlockShift; + u8 OldVal; + u8 NewVal; + int Status; + u32 UpdateBbt = 0; + u32 Index; + + /* + * Mark the last four blocks as Reserved + */ + BlockIndex = InstancePtr->Geometry.NumBlocks - Desc->MaxBlocks - 1; + + for(Index = 0; Index < Desc->MaxBlocks; Index++,BlockIndex++) { + + BlockOffset = BlockIndex >> XNANDPS_BBT_BLOCK_SHIFT; + BlockShift = XNandPs_BbtBlockShift(BlockIndex); + OldVal = InstancePtr->Bbt[BlockOffset]; + NewVal = OldVal | (XNANDPS_BLOCK_RESERVED << BlockShift); + InstancePtr->Bbt[BlockOffset] = NewVal; + + if (OldVal != NewVal) { + UpdateBbt = 1; + } + } + + /* + * Update the BBT to flash + */ + if (UpdateBbt) { + Status = XNandPs_UpdateBbt(InstancePtr); + if (Status != XST_SUCCESS) { + return Status; + } + } + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function checks whether a block is bad or not. +* +* @param InstancePtr is the pointer to the XNandPs instance. +* +* @param Block is the block number. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +int XNandPs_IsBlockBad(XNandPs *InstancePtr, u32 Block) +{ + u8 Data; + u8 BlockShift; + u8 BlockType; + u32 BlockOffset; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks); + + BlockOffset = Block >> XNANDPS_BBT_BLOCK_SHIFT; + BlockShift = XNandPs_BbtBlockShift(Block); + Data = InstancePtr->Bbt[BlockOffset]; /* Block information in BBT */ + BlockType = (Data >> BlockShift) & XNANDPS_BLOCK_TYPE_MASK; + + if (BlockType != XNANDPS_BLOCK_GOOD) + return XST_SUCCESS; + else + return XST_FAILURE; +} + +/*****************************************************************************/ +/** +* This function marks a block as bad in the RAM based Bad Block Table(BBT). It +* also updates the Bad Block Table(BBT) in the flash. +* +* @param InstancePtr is the pointer to the XNandPs instance. +* @param Block is the block number. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +******************************************************************************/ +int XNandPs_MarkBlockBad(XNandPs *InstancePtr, u32 Block) +{ + u8 Data; + u8 BlockShift; + u32 BlockOffset; + u8 OldVal; + u8 NewVal; + u32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Block < InstancePtr->Geometry.NumBlocks); + + BlockOffset = Block >> XNANDPS_BBT_BLOCK_SHIFT; + BlockShift = XNandPs_BbtBlockShift(Block); + Data = InstancePtr->Bbt[BlockOffset]; /* Block information in BBT */ + + /* + * Mark the block as bad in the RAM based Bad Block Table + */ + OldVal = Data; + Data &= ~(XNANDPS_BLOCK_TYPE_MASK << BlockShift); + Data |= (XNANDPS_BLOCK_BAD << BlockShift); + NewVal = Data; + InstancePtr->Bbt[BlockOffset] = Data; + + /* + * Update the Bad Block Table(BBT) in flash + */ + if (OldVal != NewVal) { + Status = XNandPs_UpdateBbt(InstancePtr); + if (Status != XST_SUCCESS) { + return Status; + } + } + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/nandps/src/xnandps_bbm.h b/XilinxProcessorIPLib/drivers/nandps/src/xnandps_bbm.h new file mode 100755 index 00000000..988e1ac7 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/nandps/src/xnandps_bbm.h @@ -0,0 +1,185 @@ +/****************************************************************************** +* +* 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_bbm.h +* +* This file implements the Bad Block Management(BBM) functionality. This is +* similar to the Bad Block Management which is a part of the MTD subsystem in +* Linux. The factory marked bad blocks are scanned initially and a Bad Block +* Table(BBT) is created in the memory. This table is also written to the flash +* so that upon reboot, the BBT is read back from the flash and loaded into the +* memory instead of scanning every time. The Bad Block Table(BBT) is written +* into one of the the last four blocks in the flash memory. The last four +* blocks are marked as Reserved so that user can't erase/program those blocks. +* +* There are two bad block tables, a primary table and a mirror table. The +* tables are versioned and incrementing version number is used to detect and +* recover from interrupted updates. Each table is stored in a separate block, +* beginning in the first page of that block. Only two blocks would be necessary +* in the absence of bad blocks within the last four; the range of four provides +* a little slack in case one or two of those blocks is bad. These blocks are +* marked as reserved and cannot be programmed by the user. A NAND Flash device +* with 3 or more factory bad blocks in the last 4 cannot be used. The bad block +* table signature is written into the spare data area of the pages containing +* bad block table so that upon rebooting the bad block table signature is +* searched and the bad block table is loaded into RAM. The signature is "Bbt0" +* for primary Bad Block Table and "1tbB" for Mirror Bad Block Table. The +* version offset follows the signature offset in the spare data area. The +* version number increments on every update to the bad block table and the +* version wraps at 0xff. +* +* Each block in the Bad Block Table(BBT) is represented by 2 bits. +* The two bits are encoded as follows in RAM BBT. +* 0'b00 -> Good Block +* 0'b01 -> Block is bad due to wear +* 0'b10 -> Reserved block +* 0'b11 -> Factory marked bad block +* +* While writing to the flash the two bits are encoded as follows. +* 0'b00 -> Factory marked bad block +* 0'b01 -> Reserved block +* 0'b10 -> Block is bad due to wear +* 0'b11 -> Good Block +* +* The user can check for the validity of the block using the API +* XNandPs_IsBlockBad and take the action based on the return value. Also user +* can update the bad block table using XNandPs_MarkBlockBad API. +* +* @note None +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date    	   Changes
+* ----- ----   ----------  -----------------------------------------------
+* 1.00a nm     12/10/2010  First release
+* 
+* +******************************************************************************/ +#ifndef BBM_H /* prevent circular inclusions */ +#define BBM_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ +#include "xnandps.h" + +/************************** Constant Definitions *****************************/ +/* + * Block definitions for RAM based Bad Block Table (BBT) + */ +#define XNANDPS_BLOCK_GOOD 0x0 /**< Block is good */ +#define XNANDPS_BLOCK_BAD 0x1 /**< Block is bad */ +#define XNANDPS_BLOCK_RESERVED 0x2 /**< Reserved block */ +#define XNANDPS_BLOCK_FACTORY_BAD 0x3 /**< Factory marked bad + block */ +/* + * Block definitions for FLASH based Bad Block Table (BBT) + */ +#define XNANDPS_FLASH_BLOCK_GOOD 0x3 /**< Block is good */ +#define XNANDPS_FLASH_BLOCK_BAD 0x2 /**< Block is bad */ +#define XNANDPS_FLASH_BLOCK_RESERVED 0x1 /**< Reserved block */ +#define XNANDPS_FLASH_BLOCK_FACTORY_BAD 0x0 /**< Factory marked bad + block */ + +#define XNANDPS_BBT_SCAN_2ND_PAGE 0x00000001 /**< Scan the + second page + for bad block + information + */ +#define XNANDPS_BBT_DESC_PAGE_OFFSET 0 /**< Page offset of Bad + Block Table Desc */ +#define XNANDPS_BBT_DESC_SIG_OFFSET 8 /**< Bad Block Table + signature offset */ +#define XNANDPS_BBT_DESC_VER_OFFSET 12 /**< Bad block Table + version offset */ +#define XNANDPS_BBT_DESC_SIG_LEN 4 /**< Bad block Table + signature length */ +#define XNANDPS_BBT_DESC_MAX_BLOCKS 4 /**< Bad block Table + max blocks */ + +#define XNANDPS_BBT_BLOCK_SHIFT 2 /**< Block shift value + for a block in BBT */ +#define XNANDPS_BBT_ENTRY_NUM_BLOCKS 4 /**< Num of blocks in + one BBT entry */ +#define XNANDPS_BB_PATTERN_OFFSET_SMALL_PAGE 5 /**< Bad block pattern + offset in a page */ +#define XNANDPS_BB_PATTERN_LENGTH_SMALL_PAGE 1 /**< Bad block pattern + length */ +#define XNANDPS_BB_PATTERN_OFFSET_LARGE_PAGE 0 /**< Bad block pattern + offset in a large + page */ +#define XNANDPS_BB_PATTERN_LENGTH_LARGE_PAGE 2 /**< Bad block pattern + length */ +#define XNANDPS_BB_PATTERN 0xFF /**< Bad block pattern + to search in a page + */ +#define XNANDPS_BLOCK_TYPE_MASK 0x03 /**< Block type mask */ +#define XNANDPS_BLOCK_SHIFT_MASK 0x06 /**< Block shift mask + for a Bad Block Table + entry byte */ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/****************************************************************************/ +/** +* +* This macro returns the Block shift value corresponding to a Block. +* +* @param Block is the block number. +* +* @return Block shift value +* +* @note None. +* +*****************************************************************************/ +#define XNandPs_BbtBlockShift(Block) \ + ((Block * 2) & XNANDPS_BLOCK_SHIFT_MASK) + +/************************** Variable Definitions *****************************/ + +/************************** Function Prototypes ******************************/ + +int XNandPs_IsBlockBad(XNandPs *InstancePtr, u32 Block); +int XNandPs_MarkBlockBad(XNandPs *InstancePtr, u32 Block); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/nandps/src/xnandps_g.c b/XilinxProcessorIPLib/drivers/nandps/src/xnandps_g.c new file mode 100755 index 00000000..5b0c778b --- /dev/null +++ b/XilinxProcessorIPLib/drivers/nandps/src/xnandps_g.c @@ -0,0 +1,84 @@ +/****************************************************************************** +* +* 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_g.c +* +* This file contains a configuration table that specifies the configuration +* of NAND flash devices in the system. +* +* See xnandps.h for more information about this driver. +* +* @note None. +* +*
+*
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date    	   Changes
+* ----- ----   ----------  -----------------------------------------------
+* 1.00a nm     12/10/2010  First release
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xnandps.h" +#include "xparameters.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Prototypes ******************************/ + +/** + * This table contains configuration information for each System Monitor/ADC + * device in the system. + */ +XNandPs_Config XNandPs_ConfigTable[XPAR_XNANDPS_NUM_INSTANCES] = +{ + { + XPAR_XNANDPS_0_DEVICE_ID, /**< Device ID of device */ + XPAR_XPARPORTPS_CTRL_BASEADDR, /**< SMC Base address + 0xE000E000 */ + XPAR_XNANDPS_0_BASEADDR, /**< NAND flash Base address + 0xE1000000 */ + XPAR_XNANDPS_0_FLASH_WIDTH /**< Flash data width */ + } +}; diff --git a/XilinxProcessorIPLib/drivers/nandps/src/xnandps_hw.h b/XilinxProcessorIPLib/drivers/nandps/src/xnandps_hw.h new file mode 100755 index 00000000..9615020d --- /dev/null +++ b/XilinxProcessorIPLib/drivers/nandps/src/xnandps_hw.h @@ -0,0 +1,570 @@ +/****************************************************************************** +* +* 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_hw.h +* +* This file contains identifiers and low-level macros/functions for the NAND +* Flash controller driver. +* See xnandps.h for more information. +* +* @note None +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date    	   Changes
+* ----- ----   ----------  -----------------------------------------------
+* 1.00a nm     12/10/2010  First release
+* 
+* +******************************************************************************/ + +#ifndef XNANDPS_HW_H /* prevent circular inclusions */ +#define XNANDPS_HW_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + + +/************************** Constant Definitions *****************************/ + +/* + * Memory controller configuration register offset + */ +#define XNANDPS_MEMC_STATUS_OFFSET 0x000 /**< Controller status + reg, RO */ +#define XNANDPS_MEMC_IF_CONFIG_OFFSET 0x004 /**< Interface config + reg, RO */ +#define XNANDPS_MEMC_SET_CONFIG_OFFSET 0x008 /**< Set configuration + reg, WO */ +#define XNANDPS_MEMC_CLR_CONFIG_OFFSET 0x00C /**< Clear config reg, + WO */ +#define XNANDPS_DIRECT_CMD_OFFSET 0x010 /**< Direct command + reg, WO */ +#define XNANDPS_SET_CYCLES_OFFSET 0x014 /**< Set cycles + register, WO */ +#define XNANDPS_SET_OPMODE_OFFSET 0x018 /**< Set opmode + register, WO */ +#define XNANDPS_REFRESH_PERIOD_0_OFFSET 0x020 /**< Refresh period_0 + reg, RW */ +#define XNANDPS_REFRESH_PERIOD_1_OFFSET 0x024 /**< Refresh period_1 + reg, RW */ + +/* + * Chip configuration register offset + */ +#define XNANDPS_IF0_CHIP_0_CONFIG_OFFSET 0x100 /**< Interface 0 chip 0 + config */ +#define XNANDPS_IF0_CHIP_1_CONFIG_OFFSET 0x120 /**< Interface 0 chip 1 + config */ +#define XNANDPS_IF0_CHIP_2_CONFIG_OFFSET 0x140 /**< Interface 0 chip 2 + config */ +#define XNANDPS_IF0_CHIP_3_CONFIG_OFFSET 0x160 /**< Interface 0 chip 3 + config */ +#define XNANDPS_IF1_CHIP_0_CONFIG_OFFSET 0x180 /**< Interface 1 chip 0 + config */ +#define XNANDPS_IF1_CHIP_1_CONFIG_OFFSET 0x1A0 /**< Interface 1 chip 1 + config */ +#define XNANDPS_IF1_CHIP_2_CONFIG_OFFSET 0x1C0 /**< Interface 1 chip 2 + config */ +#define XNANDPS_IF1_CHIP_3_CONFIG_OFFSET 0x1E0 /**< Interface 1 chip 3 + config */ + +/* + * nand_cycles (RO), sram_cycles (RO) and opmode_x_n (RO) registers offsets + */ +#define XNANDPS_FLASH_CYCLES(addr) (0x000 + addr) /**< NAND & SRAM + cycle,RO*/ +#define XNANDPS_OPMODE(addr) (0x004 + addr) /**< Chip opmode + reg, RO */ + +/* + * User configuration register offset + */ +#define XNANDPS_USER_STATUS_OFFSET 0x200 /**< User status reg, + RO */ +#define XNANDPS_USER_CONFIG_OFFSET 0x204 /**< User config reg, + WO */ + +/* + * ECC register offset + */ +#define XNANDPS_IF0_ECC_OFFSET 0x300 /**< Interface 0 ECC + register */ +#define XNANDPS_IF1_ECC_OFFSET 0x400 /**< Interface 1 ECC + register */ +#define XNANDPS_ECC_STATUS_OFFSET(addr) (0x000 + addr) /**< ECC status + register */ +#define XNANDPS_ECC_MEMCFG_OFFSET(addr) (0x004 + addr) /**< ECC mem + config reg */ +#define XNANDPS_ECC_MEMCMD1_OFFSET(addr) (0x008 + addr) /**< ECC mem + com1 reg*/ +#define XNANDPS_ECC_MEMCMD2_OFFSET(addr) (0x00C + addr) /**< ECC mem + com2 reg*/ +#define XNANDPS_ECC_ADDR0_OFFSET(addr) (0x010 + addr) /**< ECC + address0 reg + */ +#define XNANDPS_ECC_ADDR1_OFFSET(addr) (0x014 + addr) /**< ECC + address1 reg + */ +#define XNANDPS_ECC_VALUE0_OFFSET(addr) (0x018 + addr) /**< ECC value 0 + reg */ +#define XNANDPS_ECC_VALUE1_OFFSET(addr) (0x01C + addr) /**< ECC value 1 + reg */ +#define XNANDPS_ECC_VALUE2_OFFSET(addr) (0x020 + addr) /**< ECC value 2 + reg */ +#define XNANDPS_ECC_VALUE3_OFFSET(addr) (0x024 + addr) /**< ECC value 3 + reg */ +#define XNANDPS_ECC_VALUE4_OFFSET(addr) (0x028 + addr) /**< ECC value 4 + reg */ + +/* + * Integration test register offset + */ +#define XNANDPS_INTGTEST_OFFSET 0xE00 /**< Integration test + offset */ + +/* + * ID configuration register offset + */ +#define XNANDPS_PERIPH_ID0_OFFSET 0xFE0 /**< Peripheral id0 + register */ +#define XNANDPS_PERIPH_ID1_OFFSET 0xFE4 /**< Peripheral id1 + register */ +#define XNANDPS_PERIPH_ID2_OFFSET 0xFE8 /**< Peripheral id2 + register */ +#define XNANDPS_PERIPH_ID3_OFFSET 0xFEC /**< Peripheral id3 + register */ +#define XNANDPS_PCELL_ID0_OFFSET 0xFF0 /**< Primecell id0 + register */ +#define XNANDPS_PCELL_ID1_OFFSET 0xFF4 /**< Primecell id1 + register */ +#define XNANDPS_PCELL_ID2_OFFSET 0xFF8 /**< Primecell id2 + register */ +#define XNANDPS_PCELL_ID3_OFFSET 0xFFC /**< Primecell id3 + register */ + +/** @name Memory controller status register bit definitions and masks + * @{ + */ +#define XNANDPS_MEMC_STATUS_STATE_MASK 0x00000001 /**< Memory + controller operating state mask */ +#define XNANDPS_MEMC_STATUS_INT_EN0_MASK 0x00000002 /**< Memory + controller interface 0 interrupt enable mask */ +#define XNANDPS_MEMC_STATUS_INT_EN1_MASK 0x00000004 /**< Memory + controller interface 1 interrupt enable mask */ +#define XNANDPS_MEMC_STATUS_INT_STATUS0_MASK 0x00000008 /**< Memory + controller interface 0 interrupt status mask */ +#define XNANDPS_MEMC_STATUS_INT_STATUS1_MASK 0x00000010 /**< Memory + controller interface 1 interrupt status mask */ +#define XNANDPS_MEMC_STATUS_RAW_INT_STATUS0_MASK 0x00000020 /**< Memory + controller interface 0 raw interrupt status mask */ +#define XNANDPS_MEMC_STATUS_RAW_INT_STATUS1_MASK 0x00000040 /**< Memory + controller interface 1 raw interrupt status mask */ +#define XNANDPS_MEMC_STATUS_ECC_INT_EN0_MASK 0x00000080 /**< Memory + controller interface 0 ECC interrupt enable mask */ +#define XNANDPS_MEMC_STATUS_ECC_INT_EN1_MASK 0x00000100 /**< Memory + controller interface 1 ECC interrupt enable mask */ +#define XNANDPS_MEMC_STATUS_ECC_INT0_MASK 0x00000200 /**< Memory + controller interface 0 ECC interrupt status mask */ +#define XNANDPS_MEMC_STATUS_ECC_INT1_MASK 0x00000400 /**< Memory + controller interface 1 ECC interrupt status mask */ +#define XNANDPS_MEMC_STATUS_RAW_ECC_INT0_MASK 0x00000800 /**< Memory + controller interface 0 raw ECC interrupt status mask */ +#define XNANDPS_MEMC_STATUS_RAW_ECC_INT1_MASK 0x00001000 /**< Memory + controller interface 1 raw ECC interrupt status mask */ +/* @} */ + +/** @name Memory interface configurartion register bit definitions and masks + * @{ + */ +#define XNANDPS_MEMC_IF_CONFIG_MEMORY_TYPE0_MASK 0x00000003 /**< Memory + controller interface 0 type mask */ +#define XNANDPS_MEMC_IF_CONFIG_MEMORY_CHIPS0_MASK 0x0000000C /**< Memory + controller interface 0 chip select mask */ +#define XNANDPS_MEMC_IF_CONFIG_MEMORY_WIDTH0_MASK 0x00000030 /**< Memory + controller interface 0 data width mask */ +#define XNANDPS_MEMC_IF_CONFIG_REMAP0_MASK 0x00000040 /**< Memory + controller interface 0 remap0 mask */ +#define XNANDPS_MEMC_IF_CONFIG_MEMORY_TYPE1_MASK 0x00000300 /**< Memory + controller interface 1 type mask */ +#define XNANDPS_MEMC_IF_CONFIG_MEMORY_CHIPS1_MASK 0x00000C00 /**< Memory + controller interface 1 chip select mask */ +#define XNANDPS_MEMC_IF_CONFIG_MEMORY_WIDTH1_MASK 0x00003000 /**< Memory + controller interface 1 data width mask */ +#define XNANDPS_MEMC_IF_CONFIG_REMAP1_MASK 0x00004000 /**< Memory + controller interface 1 remap0 mask */ +#define XNANDPS_MEMC_IF_CONFIG_EX_MONITORS_MASK 0x00030000 /**< Memory + controller interface exclusive masks mask */ +/* @} */ + +/** @name Set configuration register bit definitions and masks + * @{ + */ +#define XNANDPS_MEMC_SET_CONFIG_INT_ENABLE0_MASK 0x00000001 /**< Memory + controller interfce0 interrupt enable mask */ +#define XNANDPS_MEMC_SET_CONFIG_INT_ENABLE1_MASK 0x00000002 /**< Memory + controller interfce1 interrupt enable mask */ +#define XNANDPS_MEMC_SET_CONFIG_LOW_POWER_REQ_MASK 0x00000004 /**< Memory + controller low power state mask */ +#define XNANDPS_MEMC_SET_CONFIG_ECC_INT_ENABLE0_MASK 0x00000020 /**< Memory + controller interfce0 ECC interrupt enable mask */ +#define XNANDPS_MEMC_SET_CONFIG_ECC_INT_ENABLE1_MASK 0x00000040 /**< Memory + controller interfce1 ECC interrupt enable mask */ +/* @} */ + +/** @name Clear configuration register bit definitions and masks + * @{ + */ +#define XNANDPS_MEMC_CLR_CONFIG_INT_DISABLE0_MASK 0x00000001 /**< Memory + controller interface 0 interrupt disable mask */ +#define XNANDPS_MEMC_CLR_CONFIG_INT_DISABLE1_MASK 0x00000002 /**< Memory + controller interface 1 interrupt disable mask */ +#define XNANDPS_MEMC_CLR_CONFIG_LOW_POWER_EXIT_MASK 0x00000004 /**< Memory + controller low power exit mask */ +#define XNANDPS_MEMC_CLR_CONFIG_INT_CLR0_MASK 0x00000008 /**< Memory + controller interface0 interrupt clear mask */ +#define XNANDPS_MEMC_CLR_CONFIG_INT_CLR1_MASK 0x00000010 /**< Memory + controller interface1 interrupt clear mask */ +#define XNANDPS_MEMC_CLR_CONFIG_ECC_INT_DISABLE0_MASK 0x00000020 /**< Memory + controller interface0 ECC interrupt disable mask */ +#define XNANDPS_MEMC_CLR_CONFIG_ECC_INT_DISABLE1_MASK 0x00000040 /**< Memory + controller interface1 ECC interrupt disable mask */ +/* @} */ + +/** @name Clear configuration register bit definitions and masks and shift + * @{ + */ +#define XNANDPS_DIRECT_CMD_ADDR_MASK 0x000FFFFF /**< Direct + command address mask */ +#define XNANDPS_DIRECT_CMD_SET_CRE_MASK 0x00100000 /**< Direct + command set cre mask */ +#define XNANDPS_DIRECT_CMD_TYPE_MASK 0x00600000 /**< Direct + command type mask */ +#define XNANDPS_DIRECT_CMD_CHIP_SELECT_MASK 0x03800000 /**< Direct + command chip select mask */ + +#define XNANDPS_DIRECT_CMD_SET_CRE_SHIFT 20 /**< Direct command + set_cre shift */ +#define XNANDPS_DIRECT_CMD_CMD_TYPE_SHIFT 21 /**< Direct command + cmd_type shift */ +#define XNANDPS_DIRECT_CMD_CHIP_SELECT_SHIFT 23 /**< Direct command + chip select shift */ +/* @} */ + +/** @name Set cycles register bit definitions and masks and shift + * @{ + */ +#define XNANDPS_SET_CYCLES_SET_T0_MASK 0x0000000F /**< Set + cycles set_t0 mask */ +#define XNANDPS_SET_CYCLES_SET_T1_MASK 0x000000F0 /**< Set + cycles set_t1 mask */ +#define XNANDPS_SET_CYCLES_SET_T2_MASK 0x00000700 /**< Set + cycles set_t2 mask */ +#define XNANDPS_SET_CYCLES_SET_T3_MASK 0x00003800 /**< Set + cycles set_t3 mask */ +#define XNANDPS_SET_CYCLES_SET_T4_MASK 0x0001C000 /**< Set + cycles set_t4 mask */ +#define XNANDPS_SET_CYCLES_SET_T5_MASK 0x000E0000 /**< Set + cycles set_t5 mask */ +#define XNANDPS_SET_CYCLES_SET_T6_MASK 0x00F00000 /**< Set + cycles set_t6 mask */ + +#define XNANDPS_SET_CYCLES_SET_T0_SHIFT 0 /**< Set cycles set_t0 + shift */ +#define XNANDPS_SET_CYCLES_SET_T1_SHIFT 4 /**< Set cycles set_t1 + shift */ +#define XNANDPS_SET_CYCLES_SET_T2_SHIFT 8 /**< Set cycles set_t2 + shift */ +#define XNANDPS_SET_CYCLES_SET_T3_SHIFT 11 /**< Set cycles set_t3 + shift */ +#define XNANDPS_SET_CYCLES_SET_T4_SHIFT 14 /**< Set cycles set_t4 + shift */ +#define XNANDPS_SET_CYCLES_SET_T5_SHIFT 17 /**< Set cycles set_t5 + shift */ +#define XNANDPS_SET_CYCLES_SET_T6_SHIFT 20 /**< Set cycles set_t6 + shift */ + +/* @} */ + +/** @name Set opmode register bit definitions and masks + * @{ + */ +#define XNANDPS_SET_OPMODE_SET_MW_MASK 0x00000003 /**< Set + opmode set memory width mask */ +#define XNANDPS_SET_OPMODE_SET_RD_SYNC_MASK 0x00000004 /**< Set + opmode set rd_sync mask */ +#define XNANDPS_SET_OPMODE_SET_RD_BL_MASK 0x00000038 /**< Set + opmode set rd_bl mask */ +#define XNANDPS_SET_OPMODE_SET_WR_SYNC_MASK 0x00000040 /**< Set + opmode set wr_sync mask */ +#define XNANDPS_SET_OPMODE_SET_WR_BL_MASK 0x00000380 /**< Set + opmode set wr_bl mask */ +#define XNANDPS_SET_OPMODE_SET_BAA_MASK 0x00000400 /**< Set + opmode set baa mask */ +#define XNANDPS_SET_OPMODE_SET_ADV_MASK 0x00000800 /**< Set + opmode set adv mask */ +#define XNANDPS_SET_OPMODE_SET_BLS_MASK 0x00001000 /**< Set + opmode set bls mask */ +#define XNANDPS_SET_OPMODE_SET_BURST_ALIGN_MASK 0x0000E000 /**< Set + opmode set burst align mask */ + +#define XNANDPS_SET_OPMODE_MW_8_BITS 0x0 /**< Set opmode + memory width value for 8-bit flash */ +#define XNANDPS_SET_OPMODE_MW_16_BITS 0x1 /**< Set opmode + memory width value for 16-bit flash */ +#define XNANDPS_SET_OPMODE_MW_32_BITS 0x2 /**< Set opmode + memory width value for 32-bit flash */ +/* @} */ + +/** @name Refresh period register bit definitions and masks + * @{ + */ +#define XNANDPS_REFRESH_PERIOD_0_MASK 0x0000000F + /**< Interface 0 refresh period mask */ +#define XNANDPS_REFRESH_PERIOD_1_MASK 0x0000000F + /**< Interface 1 refresh period mask */ +/* @} */ + +/** @name Opmode register bit definitions and masks + * @{ + */ +#define XNANDPS_OPMODE_MW_MASK 0x00000003 + /**< Opmode Memory width mask */ +#define XNANDPS_OPMODE_RD_SYNC_MASK 0x00000004 + /**< Opmode rd_sync mask */ +#define XNANDPS_OPMODE_RD_BL_MASK 0x00000038 + /**< Opmode rd_bl mask */ +#define XNANDPS_OPMODE_WR_SYNC_MASK 0x00000040 + /**< Opmode wr_sync mask */ +#define XNANDPS_OPMODE_WR_BL_MASK 0x00000380 + /**< Opmode BAA mask */ +#define XNANDPS_OPMODE_BAA_MASK 0x00000400 + /**< Opmode ADV mask */ +#define XNANDPS_OPMODE_ADV_MASK 0x00000800 + /**< Opmode BLS mask */ +#define XNANDPS_OPMODE_BLS_MASK 0x00001000 + /**< Opmode Burst align mask */ +#define XNANDPS_OPMODE_BURST_ALIGN_MASK 0x0000E000 + /**< Opmode Address mask */ +#define XNANDPS_OPMODE_ADDRESS_MASK 0x00FF0000 + /**< Opmode Address match mask */ +#define XNANDPS_OPMODE_ADDRESS_MATCH_MASK 0xFF000000 +/* @} */ + +/** @name User status register bit definitions and masks + * @{ + */ +#define XNANDPS_USER_STATUS_MASK 0x000000FF /**< User + status mask */ +/* @} */ + +/** @name User config register bit definitions and masks + * @{ + */ +#define XNANDPS_USER_CONFIG_MASK 0x000000FF /**< User + config mask */ +/* @} */ + +/** @name ECC status register bit definitions and masks + * @{ + */ +#define XNANDPS_ECC_STATUS_RAW_INT_STATUS_MASK 0x0000003F /**< Ecc + status raw_int_status mask */ +#define XNANDPS_ECC_STATUS_MASK 0x00000040 /**< Ecc + status ecc_status mask */ +#define XNANDPS_ECC_LAST_MASK 0x00000180 /**< Ecc + status ecc_last mask */ +#define XNANDPS_ECC_READ_NOT_WRITE_MASK 0x00000200 /**< Ecc + status ecc_read_not_write mask */ +#define XNANDPS_ECC_VALID_MASK 0x00007C00 /**< Ecc + status ecc_valid mask */ +#define XNANDPS_ECC_FAIL_MASK 0x000F8000 /**< Ecc + status ecc_fail mask */ +#define XNANDPS_ECC_CAN_CORRECT_MASK 0x01F00000 /**< Ecc + status ecc_can_correct mask */ +#define XNANDPS_ECC_READ_MASK 0x37000000 /**< Ecc + status ecc_read mask */ +/* @} */ + +/** @name ECC mem config register bit definitions and masks and shifts + * @{ + */ +#define XNANDPS_ECC_MEMCFG_PAGE_SIZE_MASK 0x00000003 + /**< Ecc cfg page_size mask */ +#define XNANDPS_ECC_MEMCFG_ECC_MODE_MASK 0x0000000C + /**< Ecc cfg ecc_mode mask */ +#define XNANDPS_ECC_MEMCFG_ECC_READ_END_MASK 0x00000010 + /**< Ecc cfg ecc_read_end mask */ +#define XNANDPS_ECC_MEMCFG_ECC_JUMP_MASK 0x00000060 + /**< Ecc cfg ecc_jump mask */ +#define XNANDPS_ECC_MEMCFG_IGNORE_ADD8_MASK 0x00000080 + /**< Ecc cfg ecc_ignore_add_eight mask */ +#define XNANDPS_ECC_MEMCFG_ECC_INT_PASS_MASK 0x00000100 + /**< Ecc cfg ecc_int_pass mask */ +#define XNANDPS_ECC_MEMCFG_ECC_INT_ABORT_MASK 0x00000200 + /**< Ecc cfg ecc_int_abort mask */ +#define XNANDPS_ECC_MEMCFG_ECC_EXTRA_BLOCK_MASK 0x00000400 + /**< Ecc cfg ecc_extra_block mask */ +#define XNANDPS_ECC_MEMCFG_ECC_EXTRA_BLOCK_SIZE_MASK 0x00001800 + /**< Ecc cfg ecc_extra_block_size mask */ + +#define XNANDPS_ECC_MEMCFG_PAGE_SIZE_SHIFT 0 + /**< Ecc cfg page_size shift */ +#define XNANDPS_ECC_MEMCFG_ECC_MODE_SHIFT 2 + /**< Ecc cfg ecc_mode shift */ +#define XNANDPS_ECC_MEMCFG_ECC_READ_END_SHIFT 4 + /**< Ecc cfg ecc_read_end shift */ +#define XNANDPS_ECC_MEMCFG_ECC_JUMP_SHIFT 5 + /**< Ecc cfg ecc_jump shift */ +#define XNANDPS_ECC_MEMCFG_IGNORE_ADD8_SHIFT 7 + /**< Ecc cfg ecc_ignore_add_eight shift */ +#define XNANDPS_ECC_MEMCFG_ECC_INT_PASS_SHIFT 8 + /**< Ecc cfg ecc_int_pass shift */ +#define XNANDPS_ECC_MEMCFG_ECC_INT_ABORT_SHIFT 9 + /**< Ecc cfg ecc_int_abort shift */ +#define XNANDPS_ECC_MEMCFG_ECC_EXTRA_BLOCK_SHIFT 10 + /**< Ecc cfg ecc_extra_block shift */ +#define XNANDPS_ECC_MEMCFG_ECC_EXTRA_BLOCK_SIZE_SHIFT 11 + /**< Ecc cfg ecc_extra_block_size shift */ + +#define XNANDPS_ECC_MEMCFG_PAGE_SIZE_512 0x1 /**< ECC cfg + page size value for 512 byte page */ +#define XNANDPS_ECC_MEMCFG_PAGE_SIZE_1024 0x2 /**< ECC cfg + page size value for 1024 byte page */ +#define XNANDPS_ECC_MEMCFG_PAGE_SIZE_2048 0x3 /**< ECC cfg + page size value for 2048 byte page */ +/* @} */ +/* @} */ + +/** @name ECC mem command1 register bit definitions and masks and shifts + * @{ + */ +#define XNANDPS_ECC_MEMCOMMAND1_WR_CMD_MASK 0x000000FF + /**< Ecc command 1 nand_wr_cmd mask */ +#define XNANDPS_ECC_MEMCOMMAND1_RD_CMD_MASK 0x0000FF00 + /**< Ecc command 1 nand_rd_cmd mask */ +#define XNANDPS_ECC_MEMCOMMAND1_RD_CMD_END_MASK 0x00FF0000 + /**< Ecc command 1 nand_rd_cmd_end mask */ +#define XNANDPS_ECC_MEMCOMMAND1_RD_CMD_END_VALID_MASK 0x01000000 + /**< Ecc command 1 nand_rd_cmd_end_valid mask */ + +#define XNANDPS_ECC_MEMCOMMAND1_WR_CMD_SHIFT 0 + /**< Ecc command 1 nand_wr_cmd shift */ +#define XNANDPS_ECC_MEMCOMMAND1_RD_CMD_SHIFT 8 + /**< Ecc command 1 nand_rd_cmd shift */ +#define XNANDPS_ECC_MEMCOMMAND1_RD_CMD_END_SHIFT 16 + /**< Ecc command 1 nand_rd_cmd_end shift */ +#define XNANDPS_ECC_MEMCOMMAND1_RD_CMD_END_VALID_SHIFT 24 + /**< Ecc command 1 nand_rd_cmd_end_valid shift */ +/* @} */ + +/** @name ECC mem command2 register bit definitions and masks + * @{ + */ +#define XNANDPS_ECC_MEMCOMMAND2_WR_COL_CHANGE_MASK 0x000000FF + /**< Ecc command2 nand_wr_col_change mask */ +#define XNANDPS_ECC_MEMCOMMAND2_RD_COL_CHANGE_MASK 0x0000FF00 + /**< Ecc command2 nand_rd_col_change mask */ +#define XNANDPS_ECC_MEMCOMMAND2_RD_COL_CHANGE_END_MASK 0x00FF0000 + /**< Ecc command2 nand_rd_col_change_end mask */ +#define XNANDPS_ECC_MEMCOMMAND2_RD_COL_CHANGE_END_VALID_MASK 0x00FF0000 + /**< Ecc command2 nand_rd_col_change_end_valid mask */ + + +#define XNANDPS_ECC_MEMCOMMAND2_WR_COL_CHANGE_SHIFT 0 + /**< Ecc command2 nand_wr_col_change shift */ +#define XNANDPS_ECC_MEMCOMMAND2_RD_COL_CHANGE_SHIFT 8 + /**< Ecc command2 nand_rd_col_change shift */ +#define XNANDPS_ECC_MEMCOMMAND2_RD_COL_CHANGE_END_SHIFT 16 + /**< Ecc command2 nand_rd_col_change_end shift */ +#define XNANDPS_ECC_MEMCOMMAND2_RD_COL_CHANGE_END_VALID_SHIFT 24 + /**< Ecc command2 nand_rd_col_change_end_valid shift */ +/* @} */ + +/** @name ECC value register bit definitions and masks + * @{ + */ +#define XNANDPS_ECC_VALUE_MASK 0x00FFFFFF + /**< Ecc value ecc_value mask */ +#define XNANDPS_ECC_VALUE_CORRECT_MASK 0x08000000 + /**< Ecc value ecc_correct mask */ +#define XNANDPS_ECC_VALUE_FAIL_MASK 0x10000000 + /**< Ecc value ecc_fail mask */ +#define XNANDPS_ECC_VALUE_READ_MASK 0x20000000 + /**< Ecc value ecc_read mask */ +#define XNANDPS_ECC_VALUE_VALID_MASK 0x40000000 + /**< Ecc value ecc_valid mask */ +#define XNANDPS_ECC_VALUE_INT_MASK 0x80000000 + /**< Ecc value ecc_int mask */ +/* @} */ + +/** @name Peripheral ID register bit definitions and masks + * @{ + */ +#define XNANDPS_PERIPH_ID_PART_NUM_MASK 0x00000FFF + /**< Peripheral ID part_num mask */ +#define XNANDPS_PERIPH_ID_DESIGNER_ID_MASK 0x000FF000 + /**< Peripheral ID designed id mask */ +#define XNANDPS_PERIPH_ID_REVISION_MASK 0x00F00000 + /**< Peripheral ID revision mask */ +#define XNANDPS_PERIPH_ID_INTG_CFG_MASK 0x01000000 + /**< Peripheral ID integration_cfg mask */ +/* @} */ + +/** @name Peripheral ID register bit definitions and masks + * @{ + */ +#define XNANDPS_PCELL_ID_MASK 0x000000FF + /**< Primecell identification register mask */ +/* @} */ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ +#define XNandPs_ReadReg Xil_In32 /**< XNandPs Register register */ +#define XNandPs_WriteReg Xil_Out32 /**< XNandPs register write */ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/nandps/src/xnandps_onfi.c b/XilinxProcessorIPLib/drivers/nandps/src/xnandps_onfi.c new file mode 100755 index 00000000..a9bbe28e --- /dev/null +++ b/XilinxProcessorIPLib/drivers/nandps/src/xnandps_onfi.c @@ -0,0 +1,654 @@ +/****************************************************************************** +* +* 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; +} diff --git a/XilinxProcessorIPLib/drivers/nandps/src/xnandps_onfi.h b/XilinxProcessorIPLib/drivers/nandps/src/xnandps_onfi.h new file mode 100755 index 00000000..f6907cd7 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/nandps/src/xnandps_onfi.h @@ -0,0 +1,314 @@ +/****************************************************************************** +* +* 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.h +* +* This file implements ONFI specific commands which are used to get the +* parameter page information. +* +* The following commands are supported currently. +* - Reset +* - Read ID +* - READ Parameter Page +* - Read Status +* - Change Read Column +* - Get Features +* - Set Features +* +* @note None +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date    	   Changes
+* ----- ----   ----------  -----------------------------------------------
+* 1.00a nm     12/10/2010  First release
+* 1.04a nm     04/25/2013  Implemented PR# 699544. Added page cache read
+*			   and program commands to ONFI command list.
+* 
+* +******************************************************************************/ +#ifndef ONFI_H /* prevent circular inclusions */ +#define ONFI_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ +#include "xnandps.h" +/************************** Constant Definitions *****************************/ +/* + * Standard ONFI NAND flash commands + */ + +/* + * Mandatory commands + */ +#define ONFI_CMD_READ1 0x00 /**< ONFI Read command + (1st cycle) */ +#define ONFI_CMD_READ2 0x30 /**< ONFI Read command + (2nd cycle) */ +#define ONFI_CMD_CHANGE_READ_COLUMN1 0x05 /**< ONFI Change Read + Column command (1st + cycle) */ +#define ONFI_CMD_CHANGE_READ_COLUMN2 0xE0 /**< ONFI Change Read + Column command (2nd + cycle) */ +#define ONFI_CMD_BLOCK_ERASE1 0x60 /**< ONFI Block Erase + (1st cycle) */ +#define ONFI_CMD_BLOCK_ERASE2 0xD0 /**< ONFI Block Erase + (2nd cycle) */ +#define ONFI_CMD_READ_STATUS 0x70 /**< ONFI Read status + command */ +#define ONFI_CMD_PAGE_PROG1 0x80 /**< ONFI Page Program + command (1st cycle) + */ +#define ONFI_CMD_PAGE_PROG2 0x10 /**< ONFI Page Program + command (2nd cycle) + */ +#define ONFI_CMD_CHANGE_WRITE_COLUMN 0x85 /**< ONFI Change Write + Column command */ +#define ONFI_CMD_READ_ID 0x90 /**< ONFI Read ID + command */ +#define ONFI_CMD_READ_PARAM_PAGE 0xEC /**< ONFI Read + Parameter Page + command */ +#define ONFI_CMD_RESET 0xFF /**< ONFI Reset + command */ +/* + * Optional commands + */ +#define ONFI_CMD_COPYBACK_READ1 0x00 /**< ONFI Copyback Read + command (1st cycle) + */ +#define ONFI_CMD_COPYBACK_READ2 0x35 /**< ONFI Copyback Read + command (2nd cycle) + */ +#define ONFI_CMD_READ_CACHE_ENHANCED1 0x00 /**< ONFI Read cache + enhanced command (1st + cycle) */ +#define ONFI_CMD_READ_CACHE_ENHANCED2 0x31 /**< ONFI Read cache + enhanced command (2nd + cycle) */ +#define ONFI_CMD_READ_CACHE 0x31 /**< ONFI Read cache + command */ +#define ONFI_CMD_READ_CACHE_END 0x3F /**< ONFI Read cache + end command */ +#define ONFI_CMD_BLOCK_ERASE_INTERLEAVED2 0xD1 /**< ONFI Block Erase + interleaved command + (2nd cycle) */ +#define ONFI_CMD_READ_STATUS_ENHANCED 0x78 /**< ONFI Read Status + enhanced command */ +#define ONFI_CMD_PAGE_PROGRAM_INTERLEAVED2 0x11 /**< ONFI Page Program + interleaved command + (2nd cycle) */ +#define ONFI_CMD_PAGE_CACHE_PROGRAM1 0x80 /**< ONFI Page cache + program (1st cycle) + */ +#define ONFI_CMD_PAGE_CACHE_PROGRAM2 0x15 /**< ONFI Page cache + program (2nd cycle) + */ +#define ONFI_CMD_COPYBACK_PROGRAM1 0x85 /**< ONFI Copyback + program command (1st + cycle) */ +#define ONFI_CMD_COPYBACK_PROGRAM2 0x10 /**< ONFI Copyback + program command (2nd + cycle) */ +#define ONFI_CMD_COPYBACK_PROGRAM_INTERLEAVED2 0x11 /**< ONFI Copyback + program interleaved + command (2nd cycle) + */ +#define ONFI_CMD_READ_UNIQUEID 0xED /**< ONFI Read Unique + ID command */ +#define ONFI_CMD_GET_FEATURES 0xEE /**< ONFI Get features + command */ +#define ONFI_CMD_SET_FEATURES 0xEF /**< ONFI Set features + command */ + +/* + * ONFI Status Register bit offsets + */ +#define ONFI_STATUS_FAIL 0x01 /**< ONFI Status + Register : FAIL */ +#define ONFI_STATUS_FAILC 0x02 /**< ONFI Status + Register : FAILC */ +#define ONFI_STATUS_ARDY 0x20 /**< ONFI Status + Register : ARDY */ +#define ONFI_STATUS_RDY 0x40 /**< ONFI Status + Register : RDY */ +#define ONFI_STATUS_WP 0x80 /**< ONFI Status + Register : WR */ +/* + * ONFI constants + */ +#define ONFI_ID_LEN 4 /**< ONFI ID Length */ +#define ONFI_CRC_INIT 0x4F4E /**< ONFI CRC16 + Inititialization constant */ +#define ONFI_CRC_POLYNOM 0x8005 /**< ONFI CRC16 polynomial */ +#define ONFI_CRC_ORDER 16 /**< ONFI CRC16 order */ +#define ONFI_PARAM_PAGE_LEN 256 /**< ONFI Parameter page length + */ +#define ONFI_CRC_LEN 254 /**< ONFI CRC16 length */ +#define ONFI_SIGNATURE_LEN 4 /**< ONFI Signature Length */ + + +/** + * This enum defines the onfi commands. + */ +enum OnfiCommandsEnum { + READ=0, /**< ONFI Read */ + CHANGE_READ_COLUMN, /**< ONFI Change Read Column */ + BLOCK_ERASE, /**< ONFI Block Erase */ + READ_STATUS, /**< ONFI Read Status */ + PAGE_PROGRAM, /**< ONFI Page Program */ + CHANGE_WRITE_COLUMN, /**< ONFI Change Write Column */ + READ_ID, /**< ONFI Read ID */ + READ_PARAM_PAGE, /**< ONFI Read Parameter Page */ + RESET, /**< ONFI Reset */ + GET_FEATURES, /**< ONFI Get Features */ + SET_FEATURES, /**< ONFI Set Features */ + READ_CACHE_RANDOM, /**< ONFI Read page cache random */ + READ_CACHE_END_SEQ, /**< ONFI Read page cache end */ + PAGE_CACHE_PROGRAM /**< ONFI Program page cache */ +}; + +/**************************** Type Definitions *******************************/ +/** + * ONFI 1.0 support + */ +/* + * Parameter page structure of ONFI 1.0 specification. + * Enhanced this sturcture to include ONFI 2.3 information for EZ NAND support. + */ +typedef struct { + /* + * Revision information and features block + */ + u8 Signature[4]; /**< Parameter page signature */ + u16 Revision; /**< Revision Number */ + u16 Features; /**< Features supported */ + u16 OptionalCmds; /**< Optional commands supported */ + u8 Reserved0[2]; /**< ONFI 2.3: Reserved */ + u16 ExtParamPageLen; /**< ONFI 2.3: extended parameter page + length */ + u8 NumOfParamPages; /**< ONFI 2.3: No of parameter pages */ + u8 Reserved1[17]; /**< Reserved */ + /* + * Manufacturer information block + */ + u8 DeviceManufacturer[12]; /**< Device manufacturer */ + u8 DeviceModel[20]; /**< Device model */ + u8 JedecManufacturerId; /**< JEDEC Manufacturer ID */ + u8 DateCode[2]; /**< Date code */ + u8 Reserved2[13]; /**< Reserved */ + /* + * Memory organization block + */ + u32 BytesPerPage; /**< Number of data bytes per page */ + u16 SpareBytesPerPage; /**< Number of spare bytes per page */ + u32 BytesPerPartialPage; /**< Number of data bytes per partial + page */ + u16 SpareBytesPerPartialPage; /**< Number of spare bytes per partial + page */ + u32 PagesPerBlock; /**< Number of pages per block */ + u32 BlocksPerLun; /**< Number of blocks per logical unit + (LUN) */ + u8 NumLuns; /**< Number of LUN's */ + u8 AddrCycles; /**< Number of address cycles */ + u8 BitsPerCell; /**< Number of bits per cell */ + u16 MaxBadBlocksPerLun; /**< Bad blocks maximum per LUN */ + u16 BlockEndurance; /**< Block endurance */ + u8 GuaranteedValidBlock; /**< Guaranteed valid blocks at + beginning of target */ + u16 BlockEnduranceGvb; /**< Block endurance for guaranteed + valid block */ + u8 ProgramsPerPage; /**< Number of programs per page */ + u8 PartialProgAttr; /**< Partial programming attributes */ + u8 EccBits; /**< Number of bits ECC + correctability */ + u8 InterleavedAddrBits; /**< Number of interleaved address + bits */ + u8 InterleavedOperation; /**< Interleaved operation + attributes */ + u8 EzNandSupport; /**< ONFI 2.3: EZ NAND support + parameters */ + u8 Reserved3[12]; /**< Reserved */ + /* + * Electrical parameters block + */ + u8 IOPinCapacitance; /**< I/O pin capacitance */ + u16 TimingMode; /**< Timing mode support */ + u16 PagecacheTimingMode; /**< Program cache timing mode */ + u16 TProg; /**< Maximum page program time */ + u16 TBers; /**< Maximum block erase time */ + u16 TR; /**< Maximum page read time */ + u16 TCcs; /**< Maximum change column setup + time */ + u16 SynTimingMode; /**< ONFI 2.3: Source synchronous + timing mode support */ + u8 SynFeatures; /**< ONFI 2.3: Source synchronous + features */ + u16 ClkInputPinCap; /**< ONFI 2.3: CLK input pin + capacitance */ + u16 IOPinCap; /**< ONFI 2.3: I/O pin capacitance */ + u16 InputPinCap; /**< ONFI 2.3: Input pin capacitance + typical */ + u8 InputPinCapMax; /**< ONFI 2.3: Input pin capacitance + maximum */ + u8 DrvStrength; /**< ONFI 2.3: Driver strength + support */ + u16 TMr; /**< ONFI 2.3: Maximum multi-plane + read time */ + u16 TAdl; /**< ONFI 2.3: Program page register + clear enhancement value */ + u16 TEr; /**< ONFI 2.3: Typical page read time + for EZ NAND */ + u8 Reserved4[6]; /**< Reserved */ + /* + * Vendor block + */ + u16 VendorRevisionNum; /**< Vendor specific revision + number */ + u8 VendorSpecific[88]; /**< Vendor specific */ + u16 Crc; /**< Integrity CRC */ +}__attribute__((packed))OnfiNand_Geometry; + +/************************** Function Prototypes ******************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/nandps/src/xnandps_sinit.c b/XilinxProcessorIPLib/drivers/nandps/src/xnandps_sinit.c new file mode 100755 index 00000000..240f14d6 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/nandps/src/xnandps_sinit.c @@ -0,0 +1,98 @@ +/****************************************************************************** +* +* 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_sinit.c +* +* This file contains the implementation of the XNand driver's static +* initialization functionality. +* +* @note None. +* +*
+*
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date    	   Changes
+* ----- ---- ----------  -----------------------------------------------
+* 1.00a nm   12/10/2010  First release
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xnandps.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ +extern XNandPs_Config XNandPs_ConfigTable[]; + +/*****************************************************************************/ +/** +* +* This function looks up the device configuration based on the unique device ID. +* The table XNandPs_ConfigTable contains the configuration info for each device +* in the system. +* +* @param DeviceId contains the ID of the device for which the +* device configuration pointer is to be returned. +* +* @return +* - A pointer to the configuration found. +* - NULL if the specified device ID was not found. +* +* @note None. +* +******************************************************************************/ +XNandPs_Config *XNandPs_LookupConfig(u16 DeviceId) +{ + XNandPs_Config *CfgPtr = NULL; + u32 Index; + + for (Index=0; Index < XPAR_XNANDPS_NUM_INSTANCES; Index++) { + if (XNandPs_ConfigTable[Index].DeviceId == DeviceId) { + CfgPtr = &XNandPs_ConfigTable[Index]; + break; + } + } + return CfgPtr; +}