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

📄 nand_util_func.c

📁 MTK手机平台下载工具FLASHTOOL驱动源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	page_size = NUTL_PAGE_SIZE(nand_info);

	// initialize internal buffer pointer 
	p_ecc_parity_from_reg   = g_NUTL_PageRead_Var.m_ecc_parity_from_reg;
	p_ecc_parity_from_spare = g_NUTL_PageRead_Var.m_ecc_parity_from_spare;
	if( 512 < page_size ) {
		p_page  = &(g_NUTL_PageRead_Var.m_PageBuf.m_2048.m_pagespare32.m_data[0]);
		p_spare = &(g_NUTL_PageRead_Var.m_PageBuf.m_2048.m_pagespare32.m_spare[0]);
	}
	else {
		p_page  = &(g_NUTL_PageRead_Var.m_PageBuf.m_512.m_pagespare32.m_data[0]);
		p_spare = &(g_NUTL_PageRead_Var.m_PageBuf.m_512.m_pagespare32.m_spare[0]);
	}

	// reset ecc parity and spare 
	for(i=0; i<4; i++) {
		p_ecc_parity_from_reg[i] = 0xAAAAAAAA;
		p_ecc_parity_from_spare[i] = 0xAAAAAAAA;
	}
	for(i=0; i<(spare_size>>2); i++) {
		p_spare[i] = 0xAAAAAAAA;
	}

	if( NUTL_READ_PAGE_WITH_ECC == flag ) {
		if( S_DONE != (ret=NUTL_BadBlock_Check(nand_info, c_timeout, row_addr)) ) {
			// bad block, skip reading 
			return S_BAD_BLOCK;
		}
	}

	// read page 
	if( NUTL_READ_SPARE_ONLY != flag ) {
		if( S_DONE != (ret=CB_NAND_PAGE_READ(nand_info, c_timeout, row_addr, p_data32, p_ecc_parity_from_reg)) ) {
			goto end;
		}
	}

	// read spare 
	if( NUTL_READ_PAGE_ONLY != flag ) {
		if( S_DONE != (ret=CB_NAND_SPARE_READ(nand_info, c_timeout, row_addr, p_spare)) ) {
			goto end;
		}
	}

	if( NUTL_READ_PAGE_WITH_ECC==flag || NUTL_VERIFY_AFTER_PROGRAM==flag ) {

		// check if all the page data are 0xFF 
		for(i=0; bIsEmptyPage && i<(page_size/512); i++) {
			if( 0xAAAAAAAA!=p_ecc_parity_from_reg[i] && 0!=p_ecc_parity_from_reg[i] ) {
				bIsEmptyPage = FALSE;
				break;
			}
		}

		// check if all the spare data are 0xFF 
		for(i=0; bIsEmptyPage && i<(spare_size>>2); i++) {
			if( 0xFFFFFFFF != p_spare[i] ) {
				bIsEmptyPage = FALSE;
				break;
			}
		}

		// if it's erased page, skip spare checksum and ECC correction 
		if( NUTL_VERIFY_AFTER_PROGRAM==flag || !bIsEmptyPage ) {
			// decompose spare area 
			if( S_DONE != (ret=NUTL_SpareDecompose(nand_info, p_spare, p_ecc_parity_from_spare)) ) {
				goto end;
			}
			// ECC correction 
			if( S_DONE != (ret=NUTL_ECC_Correction(nand_info, 512, p_ecc_parity_from_reg, p_ecc_parity_from_spare, p_data32)) ) {
				goto end;
			}
		}
	}

	ret = S_DONE;

end:
	// assign return value 
	if( NULL != p_spare32 ) {
		for(i=0; i<(spare_size>>2); i++) {
			p_spare32[i] = p_spare[i];
		}
	}

	if( NULL != ecc_parity_from_reg ) {
		ecc_parity_from_reg[0] = p_ecc_parity_from_reg[0];
		ecc_parity_from_reg[1] = p_ecc_parity_from_reg[1];
		ecc_parity_from_reg[2] = p_ecc_parity_from_reg[2];
		ecc_parity_from_reg[3] = p_ecc_parity_from_reg[3];
	}

	if( NULL != ecc_parity_from_spare ) {
		ecc_parity_from_spare[0] = p_ecc_parity_from_spare[0];
		ecc_parity_from_spare[1] = p_ecc_parity_from_spare[1];
		ecc_parity_from_spare[2] = p_ecc_parity_from_spare[2];
		ecc_parity_from_spare[3] = p_ecc_parity_from_spare[3];
	}

	return ret;
}

//------------------------------------------------------------------------------
// Page Program Related Callback Function                                       
//------------------------------------------------------------------------------
STATUS_E  NUTL_PageProgram(
				const NAND_DeviceInfo_S  *nand_info
				,const uint32  c_timeout
				,const uint32  row_addr
				,const 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]
) {
	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;
	uint32		timeout = c_timeout;

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

	// initialize internal buffer pointer 
	p_ecc_parity_from_reg   = g_NUTL_PageProgram_Var.m_ecc_parity_from_reg;
	p_ecc_parity_from_spare = g_NUTL_PageProgram_Var.m_ecc_parity_from_spare;
	if( 512 < page_size ) {
		p_page  = &(g_NUTL_PageProgram_Var.m_PageBuf.m_2048.m_pagespare32.m_data[0]);
		p_spare = &(g_NUTL_PageProgram_Var.m_PageBuf.m_2048.m_pagespare32.m_spare[0]);
	}
	else {
		p_page  = &(g_NUTL_PageProgram_Var.m_PageBuf.m_512.m_pagespare32.m_data[0]);
		p_spare = &(g_NUTL_PageProgram_Var.m_PageBuf.m_512.m_pagespare32.m_spare[0]);
	}

	// reset ecc parity and spare 
	for(i=0; i<4; i++) {
		p_ecc_parity_from_reg[i] = 0xAAAAAAAA;
		p_ecc_parity_from_spare[i] = 0xAAAAAAAA;
	}
	for(i=0; i<(spare_size>>2); i++) {
		p_spare[i] = 0xAAAAAAAA;
	}

	// program page 
	if( S_DONE != (ret=CB_NAND_PAGE_PROGRAM(nand_info, c_timeout, row_addr, p_data32, p_ecc_parity_from_reg)) ) {
		goto end;
	}
	timeout = c_timeout;
	NFI_Wait( (S_IN_PROGRESS==(ret=CB_NAND_READ_STATUS(nand_info, c_timeout))), timeout);
	if( 0 == timeout ) {
		ret = S_TIMEOUT;
		goto end;
	} 
	else if( S_UNKNOWN_ERR == ret ) {
		ret = S_PGM_FAILED;
		goto end;
	}
	else if( S_DONE != ret ) {
		goto end;
	}

	// compose spare area 
	NUTL_SpareCompose(nand_info, p_ecc_parity_from_reg, p_spare);

	// program spare area 
	if( S_DONE != (ret=CB_NAND_SPARE_PROGRAM(nand_info, c_timeout, row_addr, p_spare)) ) {
		return ret;
	}
	timeout = c_timeout;
	NFI_Wait( (S_IN_PROGRESS==(ret=CB_NAND_READ_STATUS(nand_info, c_timeout))), timeout);
	if( 0 == timeout ) {
		ret = S_TIMEOUT;
		goto end;
	} 
	else if( S_UNKNOWN_ERR == ret ) {
		ret = S_PGM_FAILED;
		goto end;
	}
	else if( S_DONE != ret ) {
		goto end;
	}

	// read back page to verify 
	if( S_DONE != (ret=NUTL_PageRead(nand_info, c_timeout, row_addr, p_page, p_spare, NULL, p_ecc_parity_from_spare, NUTL_VERIFY_AFTER_PROGRAM)) ) {
		goto end;
	}

	ret = S_DONE;

end:
	// assign return value 
	if( NULL != p_spare32 ) {
		for(i=0; i<(spare_size>>2); i++) {
			p_spare32[i] = p_spare[i];
		}
	}

	if( NULL != ecc_parity_from_reg ) {
		ecc_parity_from_reg[0] = p_ecc_parity_from_reg[0];
		ecc_parity_from_reg[1] = p_ecc_parity_from_reg[1];
		ecc_parity_from_reg[2] = p_ecc_parity_from_reg[2];
		ecc_parity_from_reg[3] = p_ecc_parity_from_reg[3];
	}

	if( NULL != ecc_parity_from_spare ) {
		ecc_parity_from_spare[0] = p_ecc_parity_from_spare[0];
		ecc_parity_from_spare[1] = p_ecc_parity_from_spare[1];
		ecc_parity_from_spare[2] = p_ecc_parity_from_spare[2];
		ecc_parity_from_spare[3] = p_ecc_parity_from_spare[3];
	}

	return ret;
}

//------------------------------------------------------------------------------
// CopyBack                                                                     
//------------------------------------------------------------------------------
STATUS_E  NUTL_CopyBack(
				const NAND_DeviceInfo_S  *nand_info
				,const uint32  c_timeout
				,const uint32  src_row_addr
				,const uint32  dest_row_addr
) {
	uint32		page_size;
	uint32		spare_size;
	uint32		*p_ecc_parity_from_src_spare;
	uint32		*p_ecc_parity_from_dest_spare;
	uint32		*p_page;
	uint32		*p_spare;
	STATUS_E	ret=S_UNKNOWN_ERR;
	uint32		i;
	uint32		timeout = c_timeout;

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

	// initialize internal buffer pointer 
	p_ecc_parity_from_src_spare  = g_NUTL_CopyBack_Var.m_ecc_parity_from_reg;
	p_ecc_parity_from_dest_spare = g_NUTL_CopyBack_Var.m_ecc_parity_from_spare;
	if( 512 < page_size ) {
		p_page  = &(g_NUTL_CopyBack_Var.m_PageBuf.m_2048.m_pagespare32.m_data[0]);
		p_spare = &(g_NUTL_CopyBack_Var.m_PageBuf.m_2048.m_pagespare32.m_spare[0]);
	}
	else {
		p_page  = &(g_NUTL_CopyBack_Var.m_PageBuf.m_512.m_pagespare32.m_data[0]);
		p_spare = &(g_NUTL_CopyBack_Var.m_PageBuf.m_512.m_pagespare32.m_spare[0]);
	}

	// reset ecc parity and spare 
	for(i=0; i<4; i++) {
		p_ecc_parity_from_src_spare[i] = 0xAAAAAAAA;
		p_ecc_parity_from_dest_spare[i] = 0xAAAAAAAA;
	}
	for(i=0; i<(spare_size>>2); i++) {
		p_spare[i] = 0xAAAAAAAA;
	}

	// if flash support H/W page copyback function 
	if( NULL != FP_CB_NAND_COPYBACK(nand_info) ) {
		// check if src_row_addr and dest_row_addr are in the same memory plane 
		if( 0 == ((src_row_addr^dest_row_addr)&nand_info->m_dev->m_hw_info.m_copyback_plane_rowaddr_mask) ) {
			if( S_DONE != (ret=CB_NAND_COPYBACK(nand_info, c_timeout, src_row_addr, dest_row_addr)) ) {
				return ret;
			}
			timeout = c_timeout;
			NFI_Wait( (S_IN_PROGRESS==(ret=CB_NAND_READ_STATUS(nand_info, c_timeout))), timeout);
			if( 0 == timeout ) {
				return S_TIMEOUT;
			} 
			else if( S_UNKNOWN_ERR == ret ) {
				return S_PGM_FAILED;
			}
			else if( S_DONE != ret ) {
				return ret;
			}

			// read src spare 
			if( S_DONE != (ret=CB_NAND_SPARE_READ(nand_info, c_timeout, src_row_addr, p_spare)) ) {
				return ret;
			}
			if( S_DONE != (ret=NUTL_SpareDecompose(nand_info, p_spare, p_ecc_parity_from_src_spare)) ) {
				return ret;
			}

			// read dest spare 
			if( S_DONE != (ret=CB_NAND_SPARE_READ(nand_info, c_timeout, dest_row_addr, p_spare)) ) {
				return ret;
			}
			if( S_DONE != (ret=NUTL_SpareDecompose(nand_info, p_spare, p_ecc_parity_from_dest_spare)) ) {
				return ret;
			}

			// compare src and dest ecc parity 
			for(i=0; i<4; i++) {
				if(	p_ecc_parity_from_src_spare[i] != p_ecc_parity_from_dest_spare[i] ) {
					return S_HW_COPYBACK_ERR;
				}
			}

			return S_DONE;
		}
	}

	// otherwise, use software to simulate 

	// read from source page 
	ret = NUTL_PageRead(nand_info, c_timeout, src_row_addr, p_page, NULL, NULL, p_ecc_parity_from_src_spare, NUTL_READ_PAGE_WITH_ECC);
	if( (S_DONE!=ret) && (S_ECC_1BIT_CORRECT!=ret) ) {
		return ret;
	}

	// program to destination page 
	ret = NUTL_PageProgram(nand_info, c_timeout, dest_row_addr, p_page, NULL, NULL, p_ecc_parity_from_dest_spare);
	if( (S_DONE!=ret) && (S_ECC_1BIT_CORRECT!=ret) ) {
		return ret;
	}

	return S_DONE;
}

//------------------------------------------------------------------------------
// Block Replacement                                                            
//------------------------------------------------------------------------------
STATUS_E  NUTL_BlockReplacement(
				const NAND_DeviceInfo_S  *nand_info
				,const uint32  c_timeout
				,const uint32  src_row_addr /* any row_addr within source block */
				,const uint32  dest_row_addr /* any row_addr within destination block */
				,const uint32  err_page_index /* page index within block, 1st page index is 0 */
				,const uint32  *p_err_page_data32 /* MUST be 32bits alignment addr */
) {
	uint32		i;
	uint32		src_block_addr;
	uint32		dest_block_addr;
	uint32		max_block_addr;
	STATUS_E	ret=S_UNKNOWN_ERR;

	max_block_addr = (NUTL_TOTAL_BLOCK_COUNT(g_pNandInfo)-1)*NUTL_PAGES_PER_BLOCK(g_pNandInfo);

	// check if err_page_index is valid 
	if( err_page_index >= nand_info->m_dev->m_hw_info.m_pages_per_block ) {
		return S_INVALID_PAGE_INDEX;
	}

	// search block addr 
	src_block_addr = NUTL_RowAddrToBlockAddr(nand_info, src_row_addr);
	dest_block_addr = NUTL_RowAddrToBlockAddr(nand_info, dest_row_addr);

	// check if src and dest block_addr is in valid range 
	if( max_block_addr<src_block_addr || max_block_addr<dest_block_addr ) {
		return S_INVALID_BEGIN_ADDR;
	}

	// erase dest block first 
	if( S_DONE != (ret=NUTL_BlockErase(nand_info, c_timeout, dest_block_addr, NUTL_ERASE)) ) {
		return ret;
	}

	// copy healthy pages to dest block 
	for(i=0; i<err_page_index; i++) {
		ret = NUTL_CopyBack(nand_info, c_timeout, src_block_addr+i, dest_block_addr+i);
		if( (S_DONE!=ret) && (S_ECC_1BIT_CORRECT!=ret) ) {
			goto error;
		}
	}

	// program the error page to dest block again 
	ret = NUTL_PageProgram(nand_info, c_timeout, dest_block_addr+err_page_index, p_err_page_data32, NULL, NULL, NULL);
	if( (S_DONE!=ret) && (S_ECC_1BIT_CORRECT!=ret) ) {
		goto error;
	}
	goto end;

error:
	// mark as bad block 
	NUTL_BlockErase(nand_info, c_timeout, dest_block_addr, NUTL_MARK_BAD_BLOCK);
end:
	return ret;
}


//------------------------------------------------------------------------------
// Range Validation                                                             
//------------------------------------------------------------------------------
STATUS_E  NUTL_CheckRange(
				const NAND_DeviceInfo_S  *nand_info
				,const uint32  absolute_addr
				,const uint32  length
) {
	uint32		total_size;

	total_size = NUTL_TOTAL_SIZE(g_pNandInfo);

	// check base addr 
	if( absolute_addr >= total_size ) {
		return S_INVALID_BEGIN_ADDR;
	}
	
	// check length 
	if( 0==length || (absolute_addr+length)>total_size  ) {
		return S_INVALID_RANGE;
	}

	return S_DONE;
}

⌨️ 快捷键说明

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