⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nand_util_func.c

📁 MTK手机平台下载工具FLASHTOOL驱动源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*******************************************************************************
*  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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -