📄 nf_mngt.c
字号:
//! @file nf_mngt.c,v
//!
//! Copyright (c) 2004 Atmel.
//!
//! Please read file license.txt for copyright notice.
//!
//! @brief This file contains the high level management for nand-flash
//! memory devices.
//!
//! It supports 1, 2 or 4 Nands of same type. Type can be 512B or 2kB Nand.
//!
//! @version 1.62 snd3-refd1-1_9_5 $Id: nf_mngt.c,v 1.62 2007/07/27 12:57:17 sguyon Exp $
//!
//! @todo
//! @bug
// TODO: remplacer les s_shift_xxx en (1<<s_shift_xxx): et ainsi faire des DIV/MUL plutot que des shift
// TODO: decomposer g_phys_page_addr en s_phys_block et s_phys_page (offset dans le block)
//_____ I N C L U D E S ___________________________________________________
//#define _TRACE_ (DISABLE)
#define NF_ECC_MNGT (ENABLE)
#include "config.h"
#include "conf\conf_nf.h"
#include "lib_mcu\nfc\nfc_drv.h"
#include "nf_mngt.h"
#include "modules\control_access\dfc_mngt.h"
#include "lib_mcu\int\int_drv.h"
#include "conf\conf_clock.h"
#include "lib_mcu\debug.h"
//_____ D E F I N I T I O N ________________________________________________
//#error Attention au modulo, call uidiv, uldiv, ...
//Se servir plus souvent du Random Data Input pour le code 2K (cr閍tion de LUT)
#if( NF_BAD_CONFIG==(FALSE) )
//_____ M A C R O S ________________________________________________________
//_____ P R I V A T E D E C L A R A T I O N _____________________________
// Static definition, which can be optimized by the compiler
//
#if (NF_GENERIC_DRIVER==TRUE) || (defined NF_AUTO_DETECT_2KB) ||(defined NF_AUTO_DETECT_512B)
extern _MEM_TYPE_SLOW_ U8 g_n_zones ; // number of zones (=1024 blocks) per device
extern _MEM_TYPE_SLOW_ U16 g_n_blocks ; // number of blocks per device
extern _MEM_TYPE_FAST_ U8 g_n_row_cycles ; // number of row cycles to access a page of the NF memory
extern _MEM_TYPE_SLOW_ U8 g_copy_back_cont ; // 0 = copy back not supported, N = number of CONTINUE subdivision contraint on copyback
extern _MEM_TYPE_SLOW_ U8 g_copy_back_discont ; // 0 = copy back not supported, N = number of DISCONTINUE subdivision contraint on copyback
#endif
#if (NF_GENERIC_DRIVER==TRUE)
_MEM_TYPE_FAST_ U8 g_shift_page_byte ; // (1<<n) size of page, unit in bytes
_MEM_TYPE_FAST_ U8 g_shift_block_page ; // (1<<n) size of physical block, unit in pages
_MEM_TYPE_SLOW_ U8 g_ofst_blk_status ; // Offset of Block Status information in spare zone
static _MEM_TYPE_SLOW_ U8 s_shift_sector_byte ; // (1<<n) size of sector, unit in bytes
static _MEM_TYPE_SLOW_ U8 s_shift_log_page_sector ; // (1<<n) size of logical page, unit in sectors
static _MEM_TYPE_SLOW_ U8 s_shift_log_block_sector; // (1<<n) size of logical block, unit in sectors
#endif
Bool g_fatal ; // Used in LUT/FBB building and ECC management...
static Bool s_mem ;
#if (defined ATMEL_WARNING)
# warning In waiting for a recoding of the control_access module.
#endif
static Bool s_start ;
_MEM_TYPE_SLOW_ U32 g_copy_src ; // Used to copy NF pages (source page)
_MEM_TYPE_SLOW_ U16 g_nf_first_block=0 ; // Block addr of the beginning of dynamic area
typedef enum
{
STATE_READ_INIT=0 // The very first open_read must be done
, STATE_READ_RESUME_PAGE // A page has been read
, STATE_WRITE_INIT // The very first open_write must be done
, STATE_WRITE_RESUME_PAGE // A page has been written
, STATE_COMPLETE // The read or write session is over.
} Nf_state;
_MEM_TYPE_SLOW_ Cache_lut g_cache_lut; // LUT cache
_MEM_TYPE_SLOW_ Cache_fbb g_cache_fbb; // Free-Blocks block cache
_MEM_TYPE_SLOW_ U8 g_page_buffer[NF_FULL_PAGE_BUFFER_SIZE] ; // Used to bufferize a page
// Dynamic variables
//
static _MEM_TYPE_SLOW_ U32 s_save_log_addr ; // Used for Stand-by / Restart operations
static _MEM_TYPE_SLOW_ U16 s_save_n_sector ; // Used for Stand-by / Restart operations
static _MEM_TYPE_SLOW_ U32 s_save2_log_addr ; // Used for Stand-by / Restart operations
static _MEM_TYPE_SLOW_ U16 s_save2_n_sector ; // Used for Stand-by / Restart operations
_MEM_TYPE_BIT_ bit g_nf_init ; // Boolean set when driver is initialized
_MEM_TYPE_MEDFAST_ U16 g_log_block_id ; // Logical Block address
_MEM_TYPE_SLOW_ U16 g_n_export_blocks=(U16)-1 ; // Number of physical blocks exported for mass-storage use
_MEM_TYPE_SLOW_ U16 g_n_free_blocks ; // Number of free physical blocks
_MEM_TYPE_SLOW_ U8 g_n_sub_lut ; // Holds the number of sub-Lut
_MEM_TYPE_SLOW_ U16 g_sub_lut_log_sz ; // Size of the sub-LUT. Unit in number of logical blocks
_MEM_TYPE_SLOW_ U16 g_last_sub_lut_log_sz ; // Size of the last sub-LUT. Unit in number of logical blocks
_MEM_TYPE_SLOW_ U16 g_fbb_block_addr ; // Free-Blocks block address
_MEM_TYPE_SLOW_ U8 g_fbb_block_index ; // Free-Blocks block index
_MEM_TYPE_SLOW_ U16 g_lut_block_addr [ N_SUBLUT ]; // LUT block address
_MEM_TYPE_SLOW_ U8 g_lut_block_index[ N_SUBLUT ]; // LUT index, unit in (LUT size/page size)
static _MEM_TYPE_FAST_ U16 s_n_sectors ; // Holds the number of sectors to read/write
static _MEM_TYPE_FAST_ U8 s_nb_sectors_step ; // Holds the number of sectors read after each page
_MEM_TYPE_FAST_ U8 g_curr_dev_id ; // Holds the current device number that is used
static _MEM_TYPE_FAST_ U16 s_curr_n_byte ; // Holds the position in the page
static _MEM_TYPE_FAST_ U32 s_curr_log_sector ; // Holds the logical sector number
_MEM_TYPE_SLOW_ U32 g_last_log_sector = -1 ; // Holds the last logical sector number on which a Write has been done
static _MEM_TYPE_FAST_ Nf_state s_state ; // Holds the current state of the driver
_MEM_TYPE_SLOW_ U16 g_block_to_kill[ NF_N_DEVICES] ; // Holds the blocks number which will be erased
_MEM_TYPE_FAST_ U32 g_phys_page_addr[NF_N_DEVICES] ; // Holds the current phys page number for each device
_MEM_TYPE_SLOW_ U32 g_save_phys_page_addr ; // Holds the previous phys page number
_MEM_TYPE_SLOW_ U8 g_save_curr_dev_id ; // Holds the previous device number that is used
_MEM_TYPE_FAST_ U32 g_next_phys_page_addr ; // Holds the previous phys page number
typedef enum
{
NF_TRANS_NORMAL // make simple translation.
, NF_TRANS_FLUSH // make simple translation. Force flush of LUT and FBB caches.
, NF_TRANS_SWAP // Swap blocks LUT <-> FBB
} Nf_translate_mode;
//_____ P R I V A T E F U N C T I O N S _________________________________
//
static void nf_translate( Nf_translate_mode mode );
static Status_bool nf_open_read( bit check_pending_write );
static Status_bool nf_open_write( bit check_pending_write );
static void nf_cache_lut_refill( U16 log_block_id );
static void nf_cache_lut_flush( void );
static void nf_erase_old_blocks( void );
//_____ F U N C T I O N S __________________________________________________
//
//! Ensure that the memory is in a good state before starting to use it
//!
//! @param none
//!
//! @return a status:
//! PASS if the command has been succesfully executed;
//! FAIL else
//!
Status_bool nf_verify( void )
{
if ( g_nf_init ) return PASS;
return nf_verify_resume();
}
//! Initializes the NF driver on the first USB Test Unit Ready.
//!
//! @param none
//!
//! @return CTRL_GOOD if ok,
//! CTRL_NO_PRESENT in case of problems.
//!
Ctrl_status nf_test_unit_ready ( void )
{
return ( nf_verify()==PASS ) ? CTRL_GOOD : CTRL_FAIL;
}
//! Returns the address of the last valid logical sector.
//!
//! @param none
//!
//! @return CTRL_GOOD if ok,
//! CTRL_NO_PRESENT in case of problems.
//!
Ctrl_status nf_read_capacity (U32 *u32_nb_sector )
{
Status_bool status_bool=nf_verify();
*u32_nb_sector = nf_get_sectors_number()-1;
return ( status_bool==PASS ) ? CTRL_GOOD : CTRL_FAIL;
}
Bool nf_wr_protect ( void )
{
return FALSE;
}
#if 0
Bool nf_removal ( void )
{
return TRUE;
}
#endif
//! Returns a pointer on the internal buffer address.
//!
//! This function is used for test only.
//!
//! @param none
//!
//! @return pointer on an internal buffer of 2112 bytes.
//!
#if 0
U8* nf_get_buffer_addr ( void ) { return g_page_buffer; }
#endif
//! Returns the total number of sectors that can be used on
//! the memory.
//!
//! This number is computed during the power on, after a scan
//! of the memory.
//!
//! @param none
//!
//! @return Number of sectors.
//!
U32 nf_get_sectors_number ( void )
{
return
(U32)g_n_export_blocks
<< (G_SHIFT_BLOCK_PAGE +G_SHIFT_PAGE_BYTE -S_SHIFT_SECTOR_BYTE)
;
}
U32 nf_block_2_page(U16 block_addr)
{
return (U32)block_addr<<G_SHIFT_BLOCK_PAGE;
}
//! This function initializes the Nand Flash for a read operation.
//!
//! @param log_sector Logical sector address to start read
//! @param nb_sector Number of sectors to transfer
//! @param sense NF_READ for a read, NF_WRITE for a write
//!
//! @return CTRL_GOOD if ok, CTRL_FAIL if read outside memory
//!
Ctrl_status nf_10( U32 log_sector , U16 n_sectors, Nf_sense sense )
{
if ( !g_nf_init )
while(1); // You shall call once mem_test_unit_ready() before.
// Test that the logical sector address is valid
//
if ( 0==n_sectors ) { return CTRL_GOOD; }
if ( (log_sector+n_sectors)>nf_get_sectors_number() ) { return CTRL_FAIL; }
trace("nf_10 ["); trace_hex32(log_sector); trace("-"); trace_hex32(log_sector+n_sectors-1);
trace( (NF_READ==sense) ? "] Read" : "] Write" );
trace("\n\r");
s_n_sectors = n_sectors;
s_curr_log_sector = log_sector;
trace("nf_10 s_curr_log_sector="); trace_hex32(s_curr_log_sector); trace_nl();
s_state = (NF_READ==sense) ? STATE_READ_INIT : STATE_WRITE_INIT;
s_save_log_addr = log_sector + n_sectors;
g_fatal = FALSE;
s_mem = TRUE;
s_start = TRUE;
return CTRL_GOOD;
}
//_____ P R I V A T E F U N C T I O N S _________________________________
//
//! This function interrupts the current transfer and save the value necessary to restart it later.
//!
//! @param u16_nb_sector_remaining number of sector remaining after the stop
//!
void nf_dfc_read_standby(U16 u16_nb_sector_remaining)
{
// not tested since abort is not possible on 1st silicon
s_save_log_addr-= u16_nb_sector_remaining;
s_save_n_sector = u16_nb_sector_remaining;
nf_dfc_read_stop( u16_nb_sector_remaining );
s_mem = FALSE;
s_start = FALSE;
s_save2_log_addr = s_save_log_addr;
s_save2_n_sector = s_save_n_sector;
}
//! This function restarts the transfer which was interrupted.
//!
void nf_dfc_read_restart(void)
{
// not tested since abort is not possible on 1st silicon
nf_10( s_save2_log_addr , s_save2_n_sector, NF_READ );
}
//! This function interrupts the current transfer and save the value necessary to restart it later.
//!
//! @param u16_nb_sector_remaining number of sector remaining after the stop
//!
//void nf_dfc_write_standby(U16 u16_nb_sector_remaining)
//{
// not tested
// ... lot of stuff to do...
// Determiner ou on en est rest
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -