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

📄 nand_util_func.c

📁 MTK手机平台下载工具FLASHTOOL驱动源码
💻 C
📖 第 1 页 / 共 3 页
字号:
		if( S_DONE == ret ) {
			*p_row_addr = block_addr;
			return S_DONE;
		}
		else {
			block_addr += NUTL_PAGES_PER_BLOCK(nand_info);
		}
	}

	return S_NO_GOOD_BLOCK_FOUND;
}

//------------------------------------------------------------------------------
// Block Erase                                                                  
//------------------------------------------------------------------------------
STATUS_E  NUTL_BlockErase(
				const NAND_DeviceInfo_S  *nand_info
				,const uint32  c_timeout
				,const uint32 row_addr
				,NUTL_EraseFlag_E	flag
) {
	uint32		i;
	uint32		block_addr;
	uint32		timeout = c_timeout;
	uint32		spare32[NAND_MAX_SPARE_SIZE_BYTE>>2];
	STATUS_E	ret=S_UNKNOWN_ERR;

	// search block addr 
	block_addr = NUTL_RowAddrToBlockAddr(nand_info, row_addr);

	// NUTL_ERASE -> good block will be erased, bad block will be skip. 
	// NUTL_FORCE_ERASE -> target block will be erased forcedly.        
	// NUTL_MARK_BAD_BLOCK -> target block will be erased forcedly.     
	if(	(NUTL_ERASE == flag) && 
		(S_DONE != (ret=NUTL_BadBlock_Check(nand_info, c_timeout, block_addr))) 
	) {
		// bad block or fail to read spare to check bad block 
		return ret;
	}

	// erase block 
	if( S_DONE != (ret=CB_NAND_BLOCK_ERASE(nand_info, block_addr)) ) {
		goto erase_fail;
	}
	timeout = c_timeout;
	NFI_Wait( (S_IN_PROGRESS==(ret=CB_NAND_READ_STATUS(nand_info, c_timeout))), timeout);
	if( 0 == timeout ) {
		goto erase_fail;
	} 
	else if( S_DONE != ret ) {
		goto erase_fail;
	}

	if( NUTL_MARK_BAD_BLOCK == flag ) {
		// goto mark as bad block 
		goto erase_fail;
	}

	return S_DONE;

erase_fail:
	// mark bad block symbol 
	CB_NAND_BAD_BLOCK_SYMBOL_SET(nand_info, spare32);

	// write bad block symbol in 1st and 2nd page of this block 
	for(i=0; i<2; i++) {
		// program spare 
		CB_NAND_SPARE_PROGRAM(nand_info, c_timeout, block_addr+i, spare32);
		timeout = c_timeout;
		NFI_Wait( (S_IN_PROGRESS==CB_NAND_READ_STATUS(nand_info, c_timeout)), timeout);
	}

	if( S_UNKNOWN_ERR == ret ) {
		return S_ERASE_FAILED;
	}
	else {
		return ret;
	}
}

//------------------------------------------------------------------------------
// Spare Area CheckSum Encode/Decode Related Function                           
//------------------------------------------------------------------------------
STATUS_E  NUTL_SpareCheckSum_Encode(
				const NAND_DeviceInfo_S  *nand_info
				,uint32  *p_spare32 /* MUST be 32bits alignment addr */
) {
	uint32	page_size;
	uint32	spare_size;
	uint32	i;
	uint16	checksum;
//	uint8	*p_spare8 = (uint8 *)p_spare32;
	uint16	*p_spare16 = (uint16 *)p_spare32;

	page_size = NUTL_PAGE_SIZE(nand_info);
	spare_size = NUTL_SPARE_SIZE(nand_info);

	if( 512 < page_size ) {
		//------------------------------------------------------- 
		// 2048 page size spare area definition                   
		//------------------------------------------------------- 
		//                                                        
		// |... PAGE DATA ...|...SPARE...|E0|E1|E2|E3|NG|CHK|     
		//                                                        
		//  We store the ECC parity, next good block address and  
		//  spare checksum in the last 5 DWORDs of spare data.    
		//                                                        
		//  E0 -> 4 bytes block-0 ECC parity. (PARITY 0~1)        
		//  E1 -> 4 bytes block-1 ECC parity. (PARITY 2~3)        
		//  E2 -> 4 bytes block-2 ECC parity. (PARITY 4~5)        
		//  E3 -> 4 bytes block-3 ECC parity. (PARITY 6~7)        
		//  NG -> 2 bytes row addr point to next good block.      
		//  CHK -> 2 bytes 16bits checksum.                       
		//                                                        
	}
	else {
		//------------------------------------------------------- 
		// 512 page size spare area definition                    
		//------------------------------------------------------- 
		//                                                        
		// |... PAGE DATA ...|...SPARE...|E0|NG|CHK|              
		//                                                        
		//  We store the ECC parity, next good block address and  
		//  spare checksum in the last 2 DWORDs of spare data.    
		//                                                        
		//  E0 -> 4 bytes block-0 ECC parity. (PARITY 6~7)        
		//  NG -> 2 bytes row addr point to next good block.      
		//  CHK -> 2 bytes (16bits) checksum.                     
		//                                                        
	}

	// encode checksum 
	checksum = 0;
	for(i=0; i<((spare_size>>1)-1); i++) {
		checksum += p_spare16[i];
	}
	p_spare16[i] = checksum;

	return S_DONE;
}

STATUS_E  NUTL_SpareCheckSum_Decode(
				const NAND_DeviceInfo_S  *nand_info
				,const uint32  *p_spare32 /* MUST be 32bits alignment addr */
) {
	uint32	page_size;
	uint32	spare_size;
	uint32	i;
	uint16	checksum;
//	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);

	if( 512 < page_size ) {
		//------------------------------------------------------- 
		// 2048 page size spare area definition                   
		//------------------------------------------------------- 
		//                                                        
		//  |... PAGE DATA ...|...SPARE...|E0|E1|E2|E3|NG|CHK|    
		//                                                        
		//  We store the ECC parity, next good block address and  
		//  spare checksum in the last 5 DWORDs of spare data.    
		//                                                        
		//  E0 -> 4 bytes block-0 ECC parity. (PARITY 0~1)        
		//  E1 -> 4 bytes block-1 ECC parity. (PARITY 2~3)        
		//  E2 -> 4 bytes block-2 ECC parity. (PARITY 4~5)        
		//  E3 -> 4 bytes block-3 ECC parity. (PARITY 6~7)        
		//  NG -> 2 bytes row addr point to next good block.      
		//  CHK -> 2 bytes 16bits checksum.                       
		//                                                        
	}
	else {
		//------------------------------------------------------- 
		// 512 page size spare area definition                    
		//------------------------------------------------------- 
		//                                                        
		//  |... PAGE DATA ...|...SPARE...|E0|NG|CHK|             
		//                                                        
		//  We store the ECC parity, next good block address and  
		//  spare checksum in the last 2 DWORDs of spare data.    
		//                                                        
		//  E0 -> 4 bytes block-0 ECC parity. (PARITY 6~7)        
		//  NG -> 2 bytes row addr point to next good block.      
		//  CHK -> 2 bytes (16bits) checksum.                     
		//                                                        
	}

	// decode checksum 
	checksum = 0;
	for(i=0; i<((spare_size>>1)-1); i++) {
		checksum += p_spare16[i];
	}

	if( checksum != p_spare16[(spare_size>>1)-1] ) {
		return S_SPARE_CHKSUM_ERR;
	}

	return S_DONE;
}

//------------------------------------------------------------------------------
// Spare Area Compose/Decompose Related Function                                
//------------------------------------------------------------------------------
STATUS_E  NUTL_SpareCompose(
				const NAND_DeviceInfo_S  *nand_info
				,const uint32  ecc_parity_from_reg[4]
				,uint32  *p_spare32 /* MUST be 32bits alignment addr */
) {
	uint32	page_size;
	uint32	spare_size;
	uint32	i;
	uint32	*p_ptr32 = p_spare32;

	page_size = NUTL_PAGE_SIZE(nand_info);
	spare_size = NUTL_SPARE_SIZE(nand_info);

	// fill spare to 0xFF 
	for(i=0; i<(spare_size>>2); i++) {
		p_spare32[i] = 0xFFFFFFFF;
	}

	// store ECC parity 
	if( 512 < page_size ) {
		//------------------------------------------------------- 
		// 2048 page size spare area definition                   
		//------------------------------------------------------- 
		//                                                        
		//  |... PAGE DATA ...|...SPARE...|E0|E1|E2|E3|NG|CHK|    
		//                                                        
		//  We store the ECC parity, next good block address and  
		//  spare checksum in the last 5 DWORDs of spare data.    
		//                                                        
		//  E0 -> 4 bytes block-0 ECC parity. (PARITY 0~1)        
		//  E1 -> 4 bytes block-1 ECC parity. (PARITY 2~3)        
		//  E2 -> 4 bytes block-2 ECC parity. (PARITY 4~5)        
		//  E3 -> 4 bytes block-3 ECC parity. (PARITY 6~7)        
		//  NG -> 2 bytes row addr point to next good block.      
		//  CHK -> 2 bytes 16bits checksum.                       
		//                                                        
		p_ptr32 = p_spare32 + ((spare_size>>2)-5);
		*p_ptr32++ = ecc_parity_from_reg[0];
		*p_ptr32++ = ecc_parity_from_reg[1];
		*p_ptr32++ = ecc_parity_from_reg[2];
		*p_ptr32++ = ecc_parity_from_reg[3];
	}
	else {
		//------------------------------------------------------- 
		// 512 page size spare area definition                    
		//------------------------------------------------------- 
		//                                                        
		//  |... PAGE DATA ...|...SPARE...|E0|NG|CHK|             
		//                                                        
		//  We store the ECC parity, next good block address and  
		//  spare checksum in the last 2 DWORDs of spare data.    
		//                                                        
		//  E0 -> 4 bytes block-0 ECC parity. (PARITY 6~7)        
		//  NG -> 2 bytes row addr point to next good block.      
		//  CHK -> 2 bytes (16bits) checksum.                     
		//                                                        
		p_ptr32 = p_spare32 + ((spare_size>>2)-2);
		*p_ptr32++ = ecc_parity_from_reg[0];
	}

	// calculate spare area checksum 
	NUTL_SpareCheckSum_Encode(nand_info, p_spare32);

	return S_DONE;
}

STATUS_E  NUTL_SpareDecompose(
				const NAND_DeviceInfo_S  *nand_info
				,const uint32  *p_spare32 /* MUST be 32bits alignment addr */
				,uint32  ecc_parity_from_spare[4]
) {
	uint32	page_size;
	uint32	spare_size;
	const uint32	*p_ptr32 = p_spare32;

	page_size = NUTL_PAGE_SIZE(nand_info);
	spare_size = NUTL_SPARE_SIZE(nand_info);

	// calculate spare area checksum 
	if( S_DONE != NUTL_SpareCheckSum_Decode(nand_info, p_spare32) ) {
		return S_SPARE_CHKSUM_ERR;
	}

	// store ECC parity 
	if( 512 < page_size ) {
		//------------------------------------------------------- 
		// 2048 page size spare area definition                   
		//------------------------------------------------------- 
		//                                                        
		//  |... PAGE DATA ...|...SPARE...|E0|E1|E2|E3|NG|CHK|    
		//                                                        
		//  We store the ECC parity, next good block address and  
		//  spare checksum in the last 5 DWORDs of spare data.    
		//                                                        
		//  E0 -> 4 bytes block-0 ECC parity. (PARITY 0~1)        
		//  E1 -> 4 bytes block-1 ECC parity. (PARITY 2~3)        
		//  E2 -> 4 bytes block-2 ECC parity. (PARITY 4~5)        
		//  E3 -> 4 bytes block-3 ECC parity. (PARITY 6~7)        
		//  NG -> 2 bytes row addr point to next good block.      
		//  CHK -> 2 bytes 16bits checksum.                       
		//                                                        
		p_ptr32 = p_spare32 + ((spare_size>>2)-5);
		ecc_parity_from_spare[0] = *p_ptr32++;
		ecc_parity_from_spare[1] = *p_ptr32++;
		ecc_parity_from_spare[2] = *p_ptr32++;
		ecc_parity_from_spare[3] = *p_ptr32++;
	}
	else {
		//------------------------------------------------------- 
		// 512 page size spare area definition                    
		//------------------------------------------------------- 
		//                                                        
		//  |... PAGE DATA ...|...SPARE...|E0|NG|CHK|             
		//                                                        
		//  We store the ECC parity, next good block address and  
		//  spare checksum in the last 2 DWORDs of spare data.    
		//                                                        
		//  E0 -> 4 bytes block-0 ECC parity. (PARITY 6~7)        
		//  NG -> 2 bytes row addr point to next good block.      
		//  CHK -> 2 bytes (16bits) checksum.                     
		//                                                        
		p_ptr32 = p_spare32 + ((spare_size>>2)-2);
		ecc_parity_from_spare[0] = *p_ptr32++;
		ecc_parity_from_spare[1] = 0;
		ecc_parity_from_spare[2] = 0;
		ecc_parity_from_spare[3] = 0;
	}

	return S_DONE;
}

//------------------------------------------------------------------------------
// ECC Correction                                                               
//------------------------------------------------------------------------------
STATUS_E  NUTL_ECC_Correction(
				const NAND_DeviceInfo_S  *nand_info
				,const uint32  ecc_block_size
				,const uint32  ecc_parity_from_reg[4]
				,const uint32  ecc_parity_from_spare[4]
				,uint32  *p_data32 /* MUST be 32bits alignment addr */
) {
	uint32	page_size;
	uint32	spare_size;
	uint32	addr_cycle;
	uint32	i;
	uint32	error_bit_address;
	uint32	error_bit_offset;
	uint8	*p_data8 = (uint8 *)p_data32;
	uint8	update_data;
	UnionData_U	xor_ecc_parity[4];

	page_size = NUTL_PAGE_SIZE(nand_info);
	spare_size = NUTL_SPARE_SIZE(nand_info);
	addr_cycle = NUTL_ADDR_CYCLE(nand_info);

	// XOR two ECC parity bit strings 
	// ecc_parity_from_reg[4]: current ECC parity generated by reading whole page 
	// ecc_parity_from_spare[4]: original ECC parity stored in spare area 
	xor_ecc_parity[0].d32 = (ecc_parity_from_reg[0]^ecc_parity_from_spare[0])&0x0FFF0FFF;
	xor_ecc_parity[1].d32 = (ecc_parity_from_reg[1]^ecc_parity_from_spare[1])&0x0FFF0FFF;
	xor_ecc_parity[2].d32 = (ecc_parity_from_reg[2]^ecc_parity_from_spare[2])&0x0FFF0FFF;
	xor_ecc_parity[3].d32 = (ecc_parity_from_reg[3]^ecc_parity_from_spare[3])&0x0FFF0FFF;

	// compare ECC parity between reg and spare 
	for(i=0; i<(page_size/ecc_block_size); i++) {
		if( 0 != xor_ecc_parity[i].d32 ) {
			if( 0x0FFF == ((xor_ecc_parity[i].d16[0]^xor_ecc_parity[i].d16[1])&0x0FFF) ) {
				// one-bit correctable error 
				error_bit_address = xor_ecc_parity[i].d16[1]&(~xor_ecc_parity[i].d16[0]);
				error_bit_offset = ecc_block_size*i + (error_bit_address>>3);
				update_data = p_data8[error_bit_offset];
				update_data = update_data^(1<<(uint8)(error_bit_address&0x0007));
				p_data8[error_bit_offset] = update_data;
				return S_ECC_1BIT_CORRECT;
			} 
			else {
				return S_ECC_2BITS_ERR;
			}
		}
	}

	return S_DONE;
}

//------------------------------------------------------------------------------
// Page Read                                                                    
//------------------------------------------------------------------------------
STATUS_E  NUTL_PageRead(
				const NAND_DeviceInfo_S  *nand_info
				,const uint32  c_timeout
				,const uint32  row_addr
				,uint32 *p_data32 /* MUST be 32bits alignment addr */
				,uint32 *p_spare32 /* MUST be 32bits alignment addr */
				,uint32  ecc_parity_from_reg[4]
				,uint32  ecc_parity_from_spare[4]
				,NUTL_ReadFlag_E  flag
) {
	uint32		page_size;
	uint32		spare_size;
	uint32		*p_ecc_parity_from_reg;
	uint32		*p_ecc_parity_from_spare;
	uint32		*p_page;
	uint32		*p_spare;
	STATUS_E	ret=S_UNKNOWN_ERR;
	uint32		i;
	bool		bIsEmptyPage = TRUE;

	spare_size = NUTL_SPARE_SIZE(nand_info);

⌨️ 快捷键说明

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