?? nand_drv_common.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_drv_COMMON.c
*
* Project:
* --------
* FlashTool Download Agent
*
* Description:
* ------------
* General NAND flash driver compatible with most of SAMSUNG devices.
*
* Author:
* -------
* Amos Hsu
*
*==============================================================================
* HISTORY
* Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
*------------------------------------------------------------------------------
* $Revision: 1.1 $
* $Modtime: Dec 19 2005 15:41:24 $
* $Log: //mtkvs01/vmdata/new_flash_tool/archives/DA/SRC/nand_drv_COMMON.c-arc $
*
* Feb 23 2006 mtk00539
* [STP100000625] FlashTool v2.7.1016
*
*
* Rev 1.1 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.0 Oct 19 2005 14:41:06 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_drv_COMMON.h"
#include "nand_util_func.h"
#include "NFI.h"
//------------------------------------------------------------------------------
// COMMON Callback Function Set
//------------------------------------------------------------------------------
const NAND_CMD_Callback_S g_NAND_COMMON_CB_FUNC_SET={
NAND_COMMON_ReadID
,NAND_COMMON_Reset
,NULL
,NAND_COMMON_ReadStatus
,NAND_COMMON_BlockErase
,NAND_COMMON_BadBlockSymbol_Check
,NAND_COMMON_BadBlockSymbol_Set
,NAND_COMMON_PageRead
,NAND_COMMON_PageProgram
,NAND_COMMON_SpareRead
,NAND_COMMON_SpareProgram
,NAND_COMMON_CopyBack
};
//------------------------------------------------------------------------------
// COMMON Callback Function Set Without H/W CopyBack Function
//------------------------------------------------------------------------------
const NAND_CMD_Callback_S g_NAND_COMMON_CB_FUNC_SET_WITHOUT_COPYBACK={
NAND_COMMON_ReadID
,NAND_COMMON_Reset
,NULL
,NAND_COMMON_ReadStatus
,NAND_COMMON_BlockErase
,NAND_COMMON_BadBlockSymbol_Check
,NAND_COMMON_BadBlockSymbol_Set
,NAND_COMMON_PageRead
,NAND_COMMON_PageProgram
,NAND_COMMON_SpareRead
,NAND_COMMON_SpareProgram
,NULL
};
//------------------------------------------------------------------------------
// Read Device ID Callback Function
//------------------------------------------------------------------------------
STATUS_E NAND_COMMON_ReadID(
const NAND_DeviceInfo_S *nand_info
,const uint32 c_timeout
,uint16 *p_maker_code
,uint16 *p_device_code
,uint16 *p_ext_code1
,uint16 *p_ext_code2
) {
uint32 id1 = 0;
uint16 nfi_pagefmt;
STATUS_E ret=S_UNKNOWN_ERR;
// reset the NFI core state machine, data FIFO and flushing FIFO
*NFI_OPCON = 0x0;
*NFI_CON = 0x0;
*NFI_FIFOCON = 0x30;
// always use 8bits I/O interface to read device id
nfi_pagefmt = *NFI_PAGEFMT;
*NFI_PAGEFMT = nfi_pagefmt&(~PAGEFMT_16BITS)|PAGEFMT_8BITS;
// read id cmd
*NFI_CMD = nand_info->m_dev->m_cmd_set->m_read_id.m_cmd;
// wait til CMD is completely issued
while( *NFI_PSTA & STATUS_CMD );
// issue addr
*NFI_ADDRL = 0;
*NFI_ADDNOB = 1;
// wait til ADDR is completely issued
while( *NFI_PSTA & STATUS_ADDR );
// set single read by DWORD
*NFI_OPCON = SINGLE_RD | NOB_DWORD;
// wait til DATA_READ is completely issued
while( *NFI_PSTA & STATUS_DATAR );
// single read doesn't need to polling FIFO
id1 = *NFI_DATAR;
*p_maker_code = (id1&0xFF);
*p_device_code = ((id1>>8)&0xFF);
*p_ext_code1 = ((id1>>16)&0xFF);
*p_ext_code2 = ((id1>>24)&0xFF);
ret = S_DONE;
// restore original page format setting
*NFI_PAGEFMT = nfi_pagefmt;
return ret;
}
//------------------------------------------------------------------------------
// Reset Device Callback Function
//------------------------------------------------------------------------------
STATUS_E NAND_COMMON_Reset(
const NAND_DeviceInfo_S *nand_info
,const uint32 c_timeout
) {
uint32 timeout = c_timeout;
STATUS_E ret=S_UNKNOWN_ERR;
// reset the NFI core state machine, data FIFO and flushing FIFO
*NFI_OPCON = 0x0;
*NFI_CON = 0x0;
*NFI_FIFOCON = 0x30;
// enable interrupt
*NFI_INTR_EN = BUSY_RETURN_EN;
// reset cmd
*NFI_CMD = nand_info->m_dev->m_cmd_set->m_reset.m_cmd;
// wait til CMD is completely issued
while( *NFI_PSTA & STATUS_CMD );
// wait for reset finish
timeout = c_timeout;
NFI_Wait( !(*NFI_INTR & BUSY_RETURN), timeout);
if( 0 == timeout ) {
ret = S_TIMEOUT;
goto end;
}
ret = S_DONE;
end:
// disable interrupt
*NFI_INTR_EN = 0;
return ret;
}
//------------------------------------------------------------------------------
// Read Status Callback Function
//------------------------------------------------------------------------------
STATUS_E NAND_COMMON_ReadStatus(
const NAND_DeviceInfo_S *nand_info
,const uint32 c_timeout
) {
uint32 status;
// read status cmd
*NFI_CMD = nand_info->m_dev->m_cmd_set->m_status.m_cmd;
// wait til CMD is completely issued
while( *NFI_PSTA & STATUS_CMD );
// set single read by DWORD
*NFI_OPCON = SINGLE_RD | NOB_DWORD;
// wait til DATA_READ is completely issued
while( *NFI_PSTA & STATUS_DATAR );
// single read doesn't need to polling FIFO
status = *NFI_DATAR;
// check READY/BUSY status first
if( !(STATUS_READY&status) ) {
return S_IN_PROGRESS;
}
// flash is ready now, check status code
if( STATUS_FAIL & status ) {
if( !(STATUS_WR_ALLOW&status) ) {
return S_BLOCK_LOCKED_ERR;
}
else {
return S_UNKNOWN_ERR;
}
}
else {
return S_DONE;
}
}
//------------------------------------------------------------------------------
// Block Erase Related Callback Function
//------------------------------------------------------------------------------
STATUS_E NAND_COMMON_BlockErase(
const NAND_DeviceInfo_S *nand_info
,const uint32 row_addr
) {
uint32 page_size;
uint32 spare_size;
uint32 addr_cycle;
page_size = NUTL_PAGE_SIZE(nand_info);
spare_size = NUTL_SPARE_SIZE(nand_info);
addr_cycle = NUTL_ADDR_CYCLE(nand_info);
// reset the NFI core state machine, data FIFO and flushing FIFO
*NFI_OPCON = 0x0;
*NFI_CON = 0x0;
*NFI_FIFOCON = 0x30;
// block erase cmd
*NFI_CMD = nand_info->m_dev->m_cmd_set->m_erase.m_cmd;
// wait til CMD is completely issued
while( *NFI_PSTA & STATUS_CMD );
// fill 1~4 cycle addr, erase command only fill row address, so column bits shift is unnecessary
*NFI_ADDRL = row_addr;
*NFI_ADDRM = 0;
// no. of addr cycle
if( 512 < page_size ) {
*NFI_ADDNOB = addr_cycle-2;
}
else {
*NFI_ADDNOB = addr_cycle-1;
}
// wait til ADDR is completely issued
while( *NFI_PSTA & STATUS_ADDR );
// block erase confirm
*NFI_CMD = nand_info->m_dev->m_cmd_set->m_erase_cnf.m_cmd;
// wait til CMD is completely issued
while( *NFI_PSTA & STATUS_CMD );
return S_DONE;
}
//------------------------------------------------------------------------------
// Bad Block Symbol Identification Related Callback Function
//------------------------------------------------------------------------------
STATUS_E NAND_COMMON_BadBlockSymbol_Check(
const NAND_DeviceInfo_S *nand_info
,const uint32 *p_spare32 /* MUST be 32bits alignment addr */
) {
uint32 page_size;
uint32 spare_size;
uint32 column_addr_bits;
uint32 addr_cycle;
uint32 io_interface;
const uint8 *p_spare8 = (const uint8 *)p_spare32;
const uint16 *p_spare16 = (const uint16 *)p_spare32;
page_size = NUTL_PAGE_SIZE(nand_info);
spare_size = NUTL_SPARE_SIZE(nand_info);
column_addr_bits = NUTL_PAGE_ADDR_SHIFT_BITS(nand_info);
addr_cycle = NUTL_ADDR_CYCLE(nand_info);
io_interface = NUTL_IO_INTERFACE(nand_info);
// check the invalid block status from spare area
if( 512 < page_size ) {
// for 2048 page size flash, the invalid block status is defined by the 1st byte/word in spare area
if( NAND_IO_16BITS == io_interface ) {
if( 0xFFFF != p_spare16[0] ) {
return S_BAD_BLOCK;
}
}
else {
if( 0xFF != p_spare8[0] ) {
return S_BAD_BLOCK;
}
}
}
else {
// for 512 page size flash
if( NAND_IO_16BITS == io_interface ) {
#if 0
// for 16 bits I/O, the invalid block status is defined by the 1st and 6th word in spare area
if( 0xFFFF!=p_spare16[0] || 0xFFFF!=p_spare16[5] ) {
#else
// for 16 bits I/O, the invalid block status is defined by the 1st word in spare area
if( 0xFFFF != p_spare16[0] ) {
#endif
return S_BAD_BLOCK;
}
}
else {
// for 8 bits I/O, the invalid block status is defined by the 6th byte in spare area
if( 0xFF != p_spare8[5] ) {
return S_BAD_BLOCK;
}
}
}
return S_DONE;
}
STATUS_E NAND_COMMON_BadBlockSymbol_Set(
const NAND_DeviceInfo_S *nand_info
,uint32 *p_spare32 /* MUST be 32bits alignment addr */
) {
uint32 page_size;
uint32 spare_size;
uint32 io_interface;
uint8 *p_spare8 = (uint8 *)p_spare32;
uint16 *p_spare16 = (uint16 *)p_spare32;
uint32 i;
page_size = NUTL_PAGE_SIZE(nand_info);
spare_size = NUTL_SPARE_SIZE(nand_info);
io_interface = NUTL_IO_INTERFACE(nand_info);
// reset spare
for(i=0; i<(spare_size>>2); i++) {
p_spare32[i] = 0xAAAAAAAA;
}
// check the invalid block status from spare area
if( 512 < page_size ) {
// for 2048 page size flash, the invalid block status is defined by the 1st byte/word in spare area
if( NAND_IO_16BITS == io_interface ) {
p_spare16[0] = 0x0;
}
else {
p_spare8[0] = 0x0;
}
}
else {
// for 512 page size flash
if( NAND_IO_16BITS == io_interface ) {
#if 0
// for 16 bits I/O, the invalid block status is defined by the 1st and 6th word in spare area
p_spare16[0] = 0x0;
p_spare16[5] = 0x0;
#else
// for 16 bits I/O, the invalid block status is defined by the 1st word in spare area
p_spare16[0] = 0x0;
#endif
}
else {
// for 8 bits I/O, the invalid block status is defined by the 6th byte in spare area
p_spare8[5] = 0x0;
}
}
return S_DONE;
}
//------------------------------------------------------------------------------
// Page Read Callback Function
//------------------------------------------------------------------------------
STATUS_E NAND_COMMON_PageRead(
const NAND_DeviceInfo_S *nand_info
,const uint32 c_timeout
,const uint32 row_addr
,uint32 *p_data32 /* MUST be 32bits alignment addr */
,uint32 ecc_parity_from_reg[4]
) {
uint32 page_size;
uint32 spare_size;
uint32 column_addr_bits;
uint32 addr_cycle;
STATUS_E ret=S_UNKNOWN_ERR;
bool bUsingDMA=TRUE;
page_size = NUTL_PAGE_SIZE(nand_info);
spare_size = NUTL_SPARE_SIZE(nand_info);
column_addr_bits = NUTL_PAGE_ADDR_SHIFT_BITS(nand_info);
addr_cycle = NUTL_ADDR_CYCLE(nand_info);
// reset the NFI core state machine, data FIFO and flushing FIFO
*NFI_OPCON = 0x0;
*NFI_CON = 0x0;
*NFI_FIFOCON = 0x30;
// read cmd
*NFI_CMD = nand_info->m_dev->m_cmd_set->m_read.m_cmd;
// wait til CMD is completely issued
while( *NFI_PSTA & STATUS_CMD );
// fill 1~4 cycle addr
*NFI_ADDRL = (row_addr<<column_addr_bits);
*NFI_ADDRM = 0;
if( 4 < addr_cycle ) {
// if addr cycle is more than 4, you have to fill 5th cycle addr
*NFI_ADDRM = (row_addr>>(32-column_addr_bits));
}
// no. of addr cycle
*NFI_ADDNOB = addr_cycle;
// wait til ADDR is completely issued
while( *NFI_PSTA & STATUS_ADDR );
// read confirm
if(nand_info->m_dev->m_cmd_set->m_read_cnf.m_enable) {
*NFI_CMD = nand_info->m_dev->m_cmd_set->m_read_cnf.m_cmd;
}
// set burst read by DWORD
*NFI_OPCON = BURST_RD | NOB_DWORD;
// wait til DATA_READ is completely issued
while( *NFI_PSTA & STATUS_DATAR );
#ifdef DISABLE_NFI_DMA
bUsingDMA = FALSE;
#else
bUsingDMA = TRUE;
// activating DMA transfer
*NFI_CON |= DMA_RD_EN;
#endif
// read page data
if( S_DONE != (ret=NUTL_FIFO_Read(c_timeout, bUsingDMA, p_data32, page_size)) ) {
goto end;
}
// <<<< WARNING!! >>>>
// 1. You MUST wait until the NFI FIFO is empty.
// It means all data in the FIFO had been read out, and then you can start to read
// ECC parity registers.
while(!(*NFI_FIFOCON & RD_EMPTY_MASK));
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -