?? nand_util_func.c
字號(hào):
/*******************************************************************************
* Copyright Statement:
* --------------------
* This software is protected by Copyright and the information contained
* herein is confidential. The software may not be copied and the information
* contained herein may not be used or disclosed except with the written
* permission of MediaTek Inc. (C) 2005
*
*******************************************************************************/
/*******************************************************************************
*
* Filename:
* ---------
* nand_util_func.c
*
* Project:
* --------
* FlashTool Download Agent
*
* Description:
* ------------
* NAND flash related utility functions.
*
* Author:
* -------
* Amos Hsu
*
*==============================================================================
* HISTORY
* Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
*------------------------------------------------------------------------------
* $Revision: 1.3 $
* $Modtime: Jan 04 2006 14:32:44 $
* $Log: //mtkvs01/vmdata/new_flash_tool/archives/DA/SRC/nand_util_func.c-arc $
*
* Mar 8 2006 mtk00539
* [STP100000669] [DA] Support RENESAS superAND flash read back and format operation.
*
*
* Feb 23 2006 mtk00539
* [STP100000625] FlashTool v2.7.1016
*
*
* Rev 1.3 Jan 04 2006 14:40:10 mtk00539
* Bug fixes:
* 1. [DA] Fix Spansion S71PLXXXN detection problem by reading CFI info.
* 2. [DA] Fix TOSHIBA NAND flash callback function set, because TOSHIBA NAND flash doesn't support CopyBack command.
*
* New features:
* 1. [DA] Supports Spansion MirrorBit Buffer-Program method.
* 2. [DA] Supports new NOR flash device.
* [SPANSION] S71PL129N
*
* Enhancements:
* 1. [DA] Halt program when external RAM is less than 128KB.
* Resolution for 158: [FlashTool v2.7.1014][New] Support Spansion MirrorBit Buffer-Program method.
*
* Rev 1.2 Dec 29 2005 10:53:18 mtk00539
* 1. [DA] Add pre-process callback function to unlock all the blocks to meet ST NAND flash requirement.
* Resolution for 156: [FlashTool v2.7.1013][BUG FIX] Fix BootROM start command failure while manually selecting NMT6226 or MT6227 baseband chip.
*
* Rev 1.1 Nov 27 2005 16:38:54 mtk00539
* 1. [DA][BUG FIX] Add NUTL_VERIFY_AFTER_PROGRAM flash to perform read back verification after program operation.
* 2. [DA][BUG FIX] Use mem_overlap_copy() instead of memcpy() to fix RegionRelocation() failure.
* Resolution for 151: [BROM_DLL v2.7.1012][BUG FIX] Cannot recognize 05B ROM_INFO header.
*
* Rev 1.0 Oct 19 2005 14:41:08 mtk00539
* Initial revision.
* Resolution for 140: [BROM_DLL v2.7.1008][New] Support NFB download and many new features.
*
*------------------------------------------------------------------------------
* Upper this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
*==============================================================================
*******************************************************************************/
#include "nand_dev_tbl.h"
#include "nand_util_func.h"
#include "NFI.h"
#include "hw_config.h"
typedef struct {
NAND_PageBuffer_U m_PageBuf;
uint32 m_ecc_parity_from_reg[4];
uint32 m_ecc_parity_from_spare[4];
} NUTL_InternalTempBuf_S;
NUTL_InternalTempBuf_S g_NUTL_PageRead_Var;
NUTL_InternalTempBuf_S g_NUTL_PageProgram_Var;
NUTL_InternalTempBuf_S g_NUTL_CopyBack_Var;
//------------------------------------------------------------------------------
// NFI Initialization
//------------------------------------------------------------------------------
STATUS_E NUTL_NFI_Init(uint32 nfi_acccon, bool bEnableCS1) {
volatile uint16 *p_reg_power_down_clear_0;
volatile uint16 *p_reg_power_down_clear_1;
p_reg_power_down_clear_0 = g_HW_DevCfg.m_hw_bbcfg->m_PDN->m_reg_power_down_clear_0;
p_reg_power_down_clear_1 = g_HW_DevCfg.m_hw_bbcfg->m_PDN->m_reg_power_down_clear_1;
g_pNandInfo = &g_NandFlashInfo;
// assign a default H/W device info
g_pNandInfo->m_dev = &(g_NandFlashDevTbl[0]);
// power on NFI
*(p_reg_power_down_clear_1) = 0x1000;
// power on DMA
*(p_reg_power_down_clear_0) = 0x0001;
// NFI access control
*NFI_ACCCON = nfi_acccon;
// NFI format (default 8bits, 512 page size)
*NFI_PAGEFMT = PAGEFMT_512|PAGEFMT_8BITS;
// setup chip-select
return NUTL_NFI_SelectCS(g_pNandInfo, bEnableCS1);
}
//------------------------------------------------------------------------------
// NFI Enable Chip Select 1
//------------------------------------------------------------------------------
STATUS_E NUTL_NFI_SelectCS(
const NAND_DeviceInfo_S *nand_info
,bool bEnableCS1
) {
uint16 gpio_cfg;
volatile uint16 *p_reg_gpio_mod_ctrl_4;
p_reg_gpio_mod_ctrl_4 = g_HW_DevCfg.m_hw_bbcfg->m_GPIO->m_reg_gpio_mod_ctrl_4;
// check if NFI CS1 is supported on this baseband chip
if( bEnableCS1 && !(g_HW_DevCfg.m_hw_bbcfg->m_NFI->m_nfi_v2) ) {
return S_NFI_CS1_NOT_SUPPORT;
}
// choose NFI chip select
if(bEnableCS1) {
gpio_cfg = g_HW_DevCfg.m_hw_bbcfg->m_GPIO->m_nfi_cs1;
*NFI_CSEL = 1;
}
else {
gpio_cfg = g_HW_DevCfg.m_hw_bbcfg->m_GPIO->m_nfi_cs0;
*NFI_CSEL = 0;
}
// GPIO configuration
*(p_reg_gpio_mod_ctrl_4) &= g_HW_DevCfg.m_hw_bbcfg->m_GPIO->m_nfi_mask;
*(p_reg_gpio_mod_ctrl_4) |= gpio_cfg;
return S_DONE;
}
//------------------------------------------------------------------------------
// Check Device
//------------------------------------------------------------------------------
STATUS_E NUTL_CheckDevice(NAND_DeviceInfo_S *nand_info) {
uint32 shift_bits;
uint32 page_size;
uint32 io_interface;
uint32 i;
uint16 maker_code, device_code, ext_code_1, ext_code_2;
// search device table
for(i=0; 0!=g_NandFlashDevTbl[i].m_hw_info.m_id.m_maker_code; i++) {
// H/W device info
nand_info->m_dev = &(g_NandFlashDevTbl[i]);
// reset device
CB_NAND_RESET(nand_info, 0x7FFF);
// check device
if( S_DONE == CB_NAND_READ_ID(nand_info, NUTL_DEFAULT_TIMEOUT, &maker_code, &device_code, &ext_code_1, &ext_code_2) ) {
// compare maker code
if( maker_code != NUTL_MAKER_CODE(nand_info) ) {
// no match, skip
continue;
}
// if maker code exist, temporarily record flash id to g_HW_DetectionResult
g_HW_DetectionResult.m_flash_dev_code_1 = maker_code;
g_HW_DetectionResult.m_flash_dev_code_2 = device_code;
g_HW_DetectionResult.m_flash_dev_code_3 = ext_code_1;
g_HW_DetectionResult.m_flash_dev_code_4 = ext_code_2;
// compare device code
if( device_code != NUTL_DEVICE_CODE(nand_info) ) {
// no match, skip
continue;
}
// match! initialize rest of data
page_size = NUTL_PAGE_SIZE(nand_info);
io_interface = NUTL_IO_INTERFACE(nand_info);
// check if I/O interface is supported on this baseband chip
if( (NAND_IO_16BITS==io_interface) && !(g_HW_DevCfg.m_hw_bbcfg->m_NFI->m_nfi_v2) ) {
return S_NFI_16BITS_IO_NOT_SUPPORT;
}
// setup NFI page format and I/O interface
if( 512 < page_size ) {
if( NAND_IO_16BITS == io_interface ) {
*NFI_PAGEFMT = PAGEFMT_2K|PAGEFMT_16BITS;
}
else {
*NFI_PAGEFMT = PAGEFMT_2K|PAGEFMT_8BITS;
}
}
else {
if( NAND_IO_16BITS == io_interface ) {
*NFI_PAGEFMT = PAGEFMT_512|PAGEFMT_16BITS;
}
else {
*NFI_PAGEFMT = PAGEFMT_512|PAGEFMT_8BITS;
}
}
// m_block_size
nand_info->m_block_size = NUTL_PAGES_PER_BLOCK(nand_info)*page_size;
// total block count
nand_info->m_total_blocks = NUTL_TOTAL_SIZE(nand_info)/NUTL_BLOCK_SIZE(nand_info);
// total page count
nand_info->m_total_pages = NUTL_PAGES_PER_BLOCK(nand_info)*NUTL_TOTAL_BLOCK_COUNT(nand_info);
// spare size
nand_info->m_spare_size = page_size/512*16;
// page addr shift bits
if( 512 < page_size ) {
nand_info->m_page_addr_shift_bits = 16;
}
else {
nand_info->m_page_addr_shift_bits = 8;
}
// block addr shift bits
for(shift_bits=0; 0<(NUTL_PAGES_PER_BLOCK(nand_info)>>(shift_bits+1)); shift_bits++);
nand_info->m_block_addr_shift_bits = shift_bits+NUTL_PAGE_ADDR_SHIFT_BITS(nand_info);
// pre-process callback
if( NULL != FP_CB_NAND_PRE_PROCESS(nand_info) ) {
CB_NAND_PRE_PROCESS(nand_info, NUTL_DEFAULT_TIMEOUT);
}
return S_DONE;
}
}
return S_DEVICE_NOT_FOUND;
}
//------------------------------------------------------------------------------
// Read From NFI FIFO
//------------------------------------------------------------------------------
STATUS_E NUTL_FIFO_Read(
const uint32 c_timeout
,const bool bUsingDMA
,uint32 *p_data32 /* MUST be 32bits alignment addr */
,const uint32 data_len
) {
uint32 timeout = c_timeout;
uint32 i;
if(bUsingDMA) {
// read page data with DMA
// receive page data
*(volatile uint32 *)(0x80030118) = 0x0000;
*(volatile uint32 *)(0x80030100) = (uint32)NFI_DATAR;
*(volatile uint32 *)(0x80030104) = (uint32)p_data32;
*(volatile uint32 *)(0x80030110) = data_len>>2;
*(volatile uint32 *)(0x80030114) = 0x00f4001a;
*(volatile uint32 *)(0x80030128) = 0;
*(volatile uint32 *)(0x80030118) = 0x8000;
// wait for DMA transmission complete
timeout = c_timeout;
NFI_Wait( (0x01 == ((*(volatile uint32 *)(0x80030000))&0x01)), timeout);
if( 0 == timeout ) {
return S_TIMEOUT;
}
}
else {
// read page data
for(i=0; i<data_len; i+=4, p_data32++) {
// wait for data ready
// when RD_EMPTY_MASK flag is poll-down, it means data is ready in FIFO at least 4 bytes.
timeout = c_timeout;
NFI_Wait( (*NFI_FIFOCON & RD_EMPTY_MASK), timeout);
if( 0 == timeout ) {
return S_TIMEOUT;
}
*p_data32 = *NFI_DATAR;
}
}
return S_DONE;
}
//------------------------------------------------------------------------------
// Write To NFI FIFO
//------------------------------------------------------------------------------
STATUS_E NUTL_FIFO_Write(
const uint32 c_timeout
,const bool bUsingDMA
,const uint32 *p_data32 /* MUST be 32bits alignment addr */
,const uint32 data_len
) {
uint32 timeout = c_timeout;
uint32 i;
if(bUsingDMA) {
// program page data with DMA
// program page data
*(volatile uint32 *)(0x80030118) = 0x0000;
*(volatile uint32 *)(0x80030100) = (uint32)p_data32;
*(volatile uint32 *)(0x80030104) = (uint32)NFI_DATAW;
*(volatile uint32 *)(0x80030110) = data_len>>2;
*(volatile uint32 *)(0x80030114) = 0x00f00016;
*(volatile uint32 *)(0x80030128) = 0;
*(volatile uint32 *)(0x80030118) = 0x8000;
// wait for DMA transmission complete
timeout = c_timeout;
NFI_Wait( (0x01 == ((*(volatile uint32 *)(0x80030000))&0x01)), timeout);
if( 0 == timeout ) {
return S_TIMEOUT;
}
}
else {
// program page data
for(i=0; i<data_len; i+=4, p_data32++) {
// wait for FIFO has space to enqueue
// when WR_FULL_MASK flag is poll-down, it means there are at least 4 bytes free space in FIFO.
timeout = c_timeout;
NFI_Wait( (*NFI_FIFOCON & WR_FULL_MASK), timeout);
if( 0 == timeout ) {
return S_TIMEOUT;
}
*NFI_DATAW = *p_data32;
}
}
return S_DONE;
}
//------------------------------------------------------------------------------
// Bad Block Check
//------------------------------------------------------------------------------
STATUS_E NUTL_BadBlock_Check(
const NAND_DeviceInfo_S *nand_info
,const uint32 c_timeout
,const uint32 row_addr
) {
uint32 i;
uint32 block_addr;
uint32 internal_spare[NAND_MAX_SPARE_SIZE_BYTE>>2];
STATUS_E ret=S_UNKNOWN_ERR;
// search block addr
block_addr = NUTL_RowAddrToBlockAddr(nand_info, row_addr);
// check bad block symbol in 1st and 2nd page of this block
for(i=0; i<2; i++) {
// read spare
if( S_DONE != (ret=CB_NAND_SPARE_READ(nand_info, c_timeout, block_addr+i, internal_spare)) ) {
return ret;
}
// check bad block symbol
if( S_DONE != (ret=CB_NAND_BAD_BLOCK_SYMBOL_CHECK(nand_info, internal_spare)) ) {
return ret;
}
}
return S_DONE;
}
//------------------------------------------------------------------------------
// Find Good Block
//------------------------------------------------------------------------------
STATUS_E NUTL_FindGoodBlock(
const NAND_DeviceInfo_S *nand_info
,const uint32 c_timeout
,uint32 *p_row_addr
) {
uint32 block_addr;
uint32 last_block_addr;
STATUS_E ret=S_UNKNOWN_ERR;
// calculate the last block addr
last_block_addr = (NUTL_TOTAL_SIZE(nand_info)/NUTL_BLOCK_SIZE(nand_info)-1)*NUTL_PAGES_PER_BLOCK(nand_info);
if( NULL == p_row_addr ) {
return S_INVALID_BEGIN_ADDR;
}
// search block addr
block_addr = NUTL_RowAddrToBlockAddr(nand_info, *p_row_addr);
if( block_addr > last_block_addr ) {
return S_INVALID_BEGIN_ADDR;
}
while( block_addr <= last_block_addr ) {
ret = NUTL_BadBlock_Check(nand_info, c_timeout, block_addr);
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -