📄 nf_loader.c
字号:
//! @file nf_loader.c,v
//!
//! Copyright (c) 2004 Atmel.
//!
//! Please read file license.txt for copyright notice.
//!
//! @brief This file is the header file for the management of PHYSICAL access of the nand flash memory devices.
//!
//! @version 1.37 snd3-refd1-1_9_5 $Id: nf_loader.c,v 1.37 2007/03/30 12:15:29 sguyon Exp $
//!
//! @todo SG !!!WARNING!!!it must be no bad block in the first block (3 or 24)
//! @bug
#ifndef _nf_loader_c_
#define _nf_loader_c_
//_____ I N C L U D E S ___________________________________________________
#include "config.h"
#include "conf\conf_nf.h"
#include "conf\conf_access.h"
#include "conf\conf_update.h"
#include "lib_mcu\nfc\nfc_drv.h"
#include "lib_mem\nand_flash\nf_mngt.h"
#include "modules\audio\audio.h" // Player module definition
#include "modules\update\update_file.h" // for Zone_info structure definition
#include "modules\update\nf_update.h"
#if (FUNC_UPDATE == ENABLE)
# if (UPDATE_DO_FW_COPY == ENABLE)
# include "lib_mcu\dfc\dfc_drv.h"
# endif
# if (UPDATE_DO_CODEC_COPY == ENABLE)
# include "modules\control_access\ctrl_access.h"
# endif
#endif
#include "nf_loader.h"
//_____ M A C R O S ________________________________________________________
// Data zone size of a NF 512Bytes/page
#define NF512_DATA_SIZE 512 // in bytes
// Spare zone size of a NF 512Bytes/page.
#define NF512_SPAREZONE_SIZE 16 // in bytes
//_____ R E F E R E N C E S ________________________________________________
#if (NF_GENERIC_DRIVER==TRUE)
extern _MEM_TYPE_FAST_ U8 g_shift_page_byte ; // Defined in nf_mngt.c
#endif
#if (FUNC_UPDATE == ENABLE)
# if ((UPDATE_DO_FW_COPY == ENABLE) || (UPDATE_DO_CODEC_COPY == ENABLE))
extern _MEM_TYPE_SLOW_ Zone_info g_zone_info;
# endif
#endif
//_____ P R I V A T E D E C L A R A T I O N S ____________________________
// Pattern table to identify zones
// The storage order of these patterns must have matched
// with the enumeration Zones defined in "nf_loader.h"
U8 code zone_patterns[NB_ZONES][SZ_PATTERN_IN_BYTE] =
{
{ PATTERN_FIRMWARE }
, { PATTERN_FIRMWARE }
, { PATTERN_CODEC }
, { PATTERN_CODEC }
, { PATTERN_PICTURE }
, { PATTERN_FONT }
};
U32 _MEM_TYPE_SLOW_ s_zone_page_addr[NB_ZONES];
static U8 _MEM_TYPE_SLOW_ s_curr_module_id = 0xFF;
static U8 _MEM_TYPE_SLOW_ s_curr_zone_id = 0xFF;
static Module_struct _MEM_TYPE_SLOW_ s_module;
Module_hdl_struct _MEM_TYPE_SLOW_ s_mod_hdl;
//static Zones nfloader_get_zone( U8 module_id ); //old version
#if (FUNC_UPDATE == ENABLE)
# if (UPDATE_DO_FW_COPY == ENABLE)
extern Bool g_b_update_copy_fw;
Bool nfloader_ckeck_fw_crc( void );
Bool nfloader_check_bank_crc ( void );
# endif
# if (UPDATE_DO_CODEC_COPY == ENABLE)
extern Bool g_b_update_copy_codec;
Bool nfloader_check_codec_crc( void );
Bool nfloader_is_codec_crc_is_good( U16 u16_crc );
# endif
// Global variable that holds the bank id of the currently active bank.
// Global shared with the l51_bank.a51 assembly file.
extern U8 data g_current_bank; // Initialized to 0(i.e. bank0) in l51_bank.a51.
extern U8 Bank_load(void);
#endif
//_____ D E F I N I T I O N S ______________________________________________
//! Loads in RAM table "zone_page_addr" the page addresses of the zone stored in NF memory.
//!
//! The location of these zone are retrieved by scanning their unique patterns through the NF.
//! The zones always begins at page 0 in blocks in the device 0.
//!
void nfloader_init( void )
{
_MEM_TYPE_FAST_ U32 u32_page_addr;
_MEM_TYPE_FAST_ U16 u16_nb_blocks;
_MEM_TYPE_FAST_ U8 code* ptr_pattern_data;
_MEM_TYPE_FAST_ U8 i,j;
for( i=0; i<NB_ZONES; i++)
{
Nfc_action(NFC_ACT_DEV_SELECT, 0);
// Zone patterns always located at page 0 in blocks
u32_page_addr = 0;
ptr_pattern_data = &zone_patterns[i];
// Scan the NF to detect a zone pattern
for( u16_nb_blocks = G_N_BLOCKS; u16_nb_blocks != 0; u16_nb_blocks-- )
{
// Do not find twice the same zone for the two copy of FW zone
if ( ((ZONE_FIRMWARE_COPY != i) || ( s_zone_page_addr[ZONE_FIRMWARE] != u32_page_addr) )
&& ((ZONE_CODEC_COPY != i) || ( s_zone_page_addr[ZONE_CODEC] != u32_page_addr) ))
{
nfc_open_page_read( u32_page_addr , 0 );
// "j" makes it possible here a required dummy read
j = Nfc_rd_data_fetch_next();
if (ZONE_FIRMWARE_COPY>=i)
{ // Firmware zone
U8 u8_pattern3, u8_pattern4, u8_pattern5;
j = 0;
if((ptr_pattern_data[0] == Nfc_rd_data_fetch_next())
&& (ptr_pattern_data[1] == Nfc_rd_data_fetch_next()) )
{
u8_pattern3 = Nfc_rd_data_fetch_next();
u8_pattern4 = Nfc_rd_data_fetch_next();
u8_pattern5 = Nfc_rd_data_fetch_next();
if((Nfc_rd_data_fetch_next() == ~u8_pattern3)
&& (Nfc_rd_data_fetch_next() == ~u8_pattern4)
&& (Nfc_rd_data_fetch_next() == ~u8_pattern5))
{
j = SZ_PATTERN_IN_BYTE;
}
}
}
else
{
for( j=0; j<SZ_PATTERN_IN_BYTE; j++ )
{
if( ptr_pattern_data[j] != Nfc_rd_data_fetch_next() ) { break; }
}
}
// If success in pattern location, shorten the loop
if( SZ_PATTERN_IN_BYTE == j ) { break; }
}
// Else try the next block
u32_page_addr += (U32)NF_NB_PAGE_PER_BLOCK;
}
if( SZ_PATTERN_IN_BYTE == j )
{ s_zone_page_addr[i] = u32_page_addr; }
else
{ s_zone_page_addr[i] = UNFOUND_PATTERN; }
}
#if (UPDATE_DO_FW_COPY == ENABLE) // FW update is implemented
g_b_update_copy_fw = !nfloader_ckeck_fw_crc();
#endif //#if ((FUNC_UPDATE == ENABLE) && (UPDATE_DO_FW_COPY = ENABLE))
#if (UPDATE_DO_CODEC_COPY == ENABLE) // Codec update is implemented
g_b_update_copy_codec = !nfloader_check_codec_crc();
#endif //#if ((FUNC_UPDATE == ENABLE) && (UPDATE_DO_CODEC_COPY = ENABLE))
}
//! Fills the dedicated module structure "s_module" from the module header data stored in NF
//!
//! @param id_module : id of the module
//! id_zone : id of the zone in which this module is stored
//! @return status PASS or FAIL
//!
U8 nfloader_init_load_module( U8 id_module, Zone id_zone )
{
_MEM_TYPE_FAST_ U8 i;
_MEM_TYPE_FAST_ U8 device_number;
_MEM_TYPE_FAST_ U16 nb_pages_remaining;
_MEM_TYPE_FAST_ U16 contiguous_block_addr;
_MEM_TYPE_FAST_ U16 u16_nb_pages;
_MEM_TYPE_FAST_ U16 u16_block_addr;
Bool b_first_block;
union
{
U16 offset;
U8 dummy;
} _MEM_TYPE_SLOW_ v0;
union
{
U8 header_size;
U8 nb_blocks;
} _MEM_TYPE_SLOW_ v1;
if( (id_module == s_curr_module_id) && (id_zone == s_curr_zone_id) )
{ return PASS; }
else
{
// Loading of the zone header's data from the NF in the RAM structure "s_mod_hdl"
Mcu_set_sfr_page_nfc();
Nfc_action(NFC_ACT_DEV_SELECT, 0);
if ( s_zone_page_addr[id_zone] != UNFOUND_PATTERN)
{
s_mod_hdl.page_addr = s_zone_page_addr[id_zone];
}
else { return FAIL; }
v0.offset = SZ_PATTERN_IN_BYTE;
// Scan the zone to search the module with the help of its id
do
{
nfc_open_page_read( s_mod_hdl.page_addr, v0.offset );
i = Nfc_rd_data_fetch_next(); // Dummy read required when manual reads
v1.header_size = Nfc_rd_data_fetch_next(); // Read of the module header size
if (0 == v1.header_size) { return FAIL; } // Structure searched not found => RETURN FAIL
else { v0.offset += v1.header_size +1; } // Point the next structure
// NOTE: we add +1 to take into account the
// size information Byte itself.
} while( id_module != Nfc_rd_data_fetch_next() ); // Module searched has been found?
s_curr_module_id = id_module;
s_curr_zone_id = id_zone;
#if (UPDATE_DO_FW_COPY == ENABLE) // FW update & FW copy is implemented
s_module.option = Nfc_rd_data_fetch_next(); // Read option value
#else
v0.dummy = Nfc_rd_data_fetch_next(); // Option value discarded but dummy read required
#endif
MSB0(s_module.data_amount) = Nfc_rd_data_fetch_next(); // Size in 32 bits
MSB1(s_module.data_amount) = Nfc_rd_data_fetch_next();
MSB2(s_module.data_amount) = Nfc_rd_data_fetch_next();
MSB3(s_module.data_amount) = Nfc_rd_data_fetch_next();
s_module.true_size = s_module.data_amount;
// This amount of data is aligned on the sector size ...
// DANGER If fw size gets close to the prog zone size and (prog zone size)%512 != 0
#if (defined ATMEL_WARNING)
# warning: the code zone size of the chip(cf. MEMCSX) must be a multiple of 512.
#endif
s_module.data_amount = Align_up(s_module.data_amount, 512);
// and gives the number of NF pages used to store the data
nb_pages_remaining = s_module.data_amount / (U16)NF_NB_BYTE_PER_PAGE;
if( 0 != s_module.data_amount % (U16)NF_NB_BYTE_PER_PAGE )
{ nb_pages_remaining++; }
v0.dummy = Nfc_rd_data_fetch_next(); // CRC (32 bits)
v0.dummy = Nfc_rd_data_fetch_next(); // only the LSW is read
MSB(s_module.CRC) = Nfc_rd_data_fetch_next();
LSB(s_module.CRC) = Nfc_rd_data_fetch_next();
v0.dummy = Nfc_rd_data_fetch_next(); // Total number of blocks for firmware zone,
v1.nb_blocks = Nfc_rd_data_fetch_next(); // fragments for other zones
// ( only defined in 8 bits in our application )
s_module.start_page = Nfc_rd_data_fetch_next(); // Start page (8 bits)
i=0;
if(( ZONE_FIRMWARE == id_zone ) || ( ZONE_FIRMWARE_COPY == id_zone ))
{
// To force the initialization of the fragment 0 in the loop below
s_module.frag[0].device_number = 0xFF;
b_first_block = TRUE;
do
{
device_number = Nfc_rd_data_fetch_next(); // Device number
MSB(u16_block_addr) = Nfc_rd_data_fetch_next(); // Address of the block (16 bits)
LSB(u16_block_addr) = Nfc_rd_data_fetch_next();
if( 1 == v1.nb_blocks )
{
// The last block to integrate : its number of pages is equal to "nb_pages_remaining"
u16_nb_pages = nb_pages_remaining;
// Compute the number of fragments whose the module data is composed of
s_module.nb_frag = i+1;
}
else
{
u16_nb_pages = NF_NB_PAGE_PER_BLOCK;
if( b_first_block )
{
// The fisrt block to integrate : its number of pages is reduced of the start page offset
u16_nb_pages -= s_module.start_page;
}
// Compute the number of pages remaining for the next blocks to integrate
nb_pages_remaining -= u16_nb_pages;
}
if( (u16_block_addr == contiguous_block_addr)
&& (device_number == s_module.frag[i].device_number) )
{
// The block read is contiguous to the current fragment.
// So, this block is integrated to this fragment.
s_module.frag[i].nb_pages += u16_nb_pages;
contiguous_block_addr++;
}
else
{
// The block read is not contiguous to the current fragment.
// So, fill the new fragment and set the new contiguous block address
if( !b_first_block ) { i++; }
b_first_block = FALSE;
s_module.frag[i].nb_pages = u16_nb_pages;
s_module.frag[i].device_number = device_number;
s_module.frag[i].block_addr = u16_block_addr;
contiguous_block_addr = u16_block_addr;
}
}
while( --v1.nb_blocks != 0 );
}
else
{
s_module.nb_frag = v1.nb_blocks;
while(1)
{
s_module.frag[i].device_number = Nfc_rd_data_fetch_next(); // Device number
MSB(s_module.frag[i].block_addr) = Nfc_rd_data_fetch_next(); // Address of the block (16 bits)
LSB(s_module.frag[i].block_addr) = Nfc_rd_data_fetch_next();
s_module.frag[i].nb_pages = Nfc_rd_data_fetch_next(); // Number of blocks in the fragment (8 bits)
s_module.frag[i].nb_pages *= NF_NB_PAGE_PER_BLOCK;
// Compute the number of pages for the first fragment
if( 0 == i )
{ s_module.frag[0].nb_pages -= (U16) s_module.start_page; }
if( i == s_module.nb_frag-1 )
{
s_module.frag[i].nb_pages = nb_pages_remaining;
break; // End of computing
}
nb_pages_remaining -= s_module.frag[i].nb_pages;
i++;
}
}
}
return PASS;
}
//! Get the number of sectors used to store the module
//! The size of the module must not exceed 64K
//! (sector = 512B)
//!
//! @param none
//! @return U8 Number of sectors
//!
U8 nfloader_get_module_sector_number( void )
{
return( s_module.data_amount /512 );
}
#if 0
//! Get the number of bytes used to store the module
//! The size of the module must not exceed 64K
//!
//!
//! @param none
//! @return U16 Number of bytes
//!
U16 nfloader_get_module_size( void )
{
return( s_module.true_size );
}
#endif
//! Get the remaining number of Bytes in a module after a given offset.
//! The size of the module must not exceed 64K
//!
//! @param U16 u16_offset
//! @return U16 Number of remaining bytes
//!
#if (CODE_BANKING == ENABLE) && (BANK_DECIPHER == ENABLE)
U16 nfloader_get_remaining_size( U16 u16_offset )
{
return( (U16)s_module.data_amount - u16_offset);
}
#endif
//! Get the number of sectors used to store the module data from a given logical address
//! The size of the module must not exceed 64K
//! (sector = 512B)
//!
//! @param U16 log_addr : logical address on the module data section
//! @return U8 Number of sectors
//!
#if (CODE_BANKING == ENABLE)
U8 nfloader_get_sector_number( U16 log_addr )
{
log_addr = Align_down(log_addr, 512);
log_addr = s_module.data_amount - log_addr;
return( log_addr /512 );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -