?? bl_nfi.c
字號:
/*****************************************************************************
* 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
*
* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
* NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
* SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
*
* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
* LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
* RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
* THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
*
*****************************************************************************/
/*****************************************************************************
*
* Filename:
* ---------
* bl_NFI.c
*
* Project:
* --------
* Bootloader
*
* Description:
* ------------
* NANDFlash driver.
*
* Author:
* -------
* -------
*
*============================================================================
* HISTORY
* Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
*------------------------------------------------------------------------------
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
*
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
* removed!
*------------------------------------------------------------------------------
* Upper this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
*============================================================================
****************************************************************************/
#include <kal_release.h>
#include <bl_loader.h>
#include <bl_NFI.h>
//-------------------------------------------------------
// 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.
//
//-------------------------------------------------------
// 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.
//
typedef union
{
kal_uint8 d8[4];
kal_uint16 d16[2];
kal_uint32 d32;
} UnionData_U;
#ifdef BIT_ERROR_TEST
extern BOOTL_HEADER BLHeader;
void EmulateBitError(kal_uint32 *destination, kal_uint32 *parity, kal_uint16 addr_no, kal_uint32 addr1, kal_uint16 addr2, kal_uint16 pageSize)
{
kal_uint8 BitNo, status, Sector, Mask;
kal_uint32 Offset, MagicNum;
kal_bool EmulatedBitError;
kal_uint8 *Ptr = (kal_uint8 *)destination;
NFI_PageRead(destination, parity, pageSize, addr_no, addr1, addr2, pageSize, KAL_TRUE, KAL_FALSE);
status = NFI_ParityCheck(destination, parity, addr_no, addr1, addr2, \
pageSize, BLHeader.NFIinfo.IOInterface, \
BLHeader.NFIinfo.pageSize*BLHeader.pagesPerBlock);
if (status != NFI_SUCCESS) {
dbg_print(" Original data has error. No need to emulate bit error. status=%x \n\r", status);
return;
}
for(Sector=0; Sector<(pageSize/0x200); Sector++) {
EmulatedBitError = KAL_FALSE;
if(pageSize < 1024) {
MagicNum = (addr1>>16) ^ (addr1>>8);
} else {
MagicNum = (addr1>>16) ^ (addr1>>24);
}
for(Offset=(MagicNum & 0x1ff); Offset<0x200; Offset++) {
Mask = 0x01;
for(BitNo=0; BitNo<8; BitNo++) {
if(Ptr[Sector*0x200+Offset] & Mask) {
dbg_print("***[Emulate] Offset = %x, Original data = %x", addr1+(Sector*0x200)+Offset, Ptr[Sector*0x200+Offset]);
Ptr[Sector*0x200+Offset] = Ptr[Sector*0x200+Offset] & (~Mask);
dbg_print(" New data = %x \n\r", Ptr[Sector*0x200+Offset]);
EmulatedBitError = KAL_TRUE;
break;
}
Mask = Mask << 1;
}
if(EmulatedBitError==KAL_TRUE) {
break;
}
}
}
*NFI_FIFOCON = RESET;
*NFI_CON = 0;
if(pageSize<1024) {
*NFI_CMD = RD_1ST_CMD; // Set poiner to 0.
while (*NFI_PSTA & STATUS_CMD);
*NFI_OPCON = 0;
while (*NFI_PSTA & STATUS_CMD);
*NFI_FIFOCON = RESET;
}
*NFI_CMD = INPUT_DATA_CMD; // Issue data input command
while (*NFI_PSTA & STATUS_CMD);
*NFI_ADDRL = addr1;
if (addr_no == 5)
*NFI_ADDRM = addr2;
*NFI_ADDNOB = addr_no; // no. of bytes for address
while (*NFI_PSTA & STATUS_ADDR);
*NFI_OPCON = BURST_WR; // set burst write
*NFI_CON = DMA_WR_EN;
*(volatile kal_uint32 *)(0x80030118) = 0x0000;
*(volatile kal_uint32 *)(0x80030100) = (kal_uint32)destination;
*(volatile kal_uint32 *)(0x80030104) = (kal_uint32)NFI_DATAW;
*(volatile kal_uint32 *)(0x80030110) = pageSize>>2;
*(volatile kal_uint32 *)(0x80030114) = 0x01000016;
*(volatile kal_uint32 *)(0x80030128) = 0;
*(volatile kal_uint32 *)(0x80030118) = 0x8000;
while ( ((*(volatile kal_uint32 *)(0x80030000)&0x03)==0x01) );
*NFI_CMD = PROG_DATA_CMD; // Issue program command
while (*NFI_PSTA & STATUS_CMD);
while (*NFI_PSTA & STATUS_BUSY);
*NFI_OPCON = 0;
return;
}
#endif
/**********************************************************
Description : NUTL_ECC_Correction
Input : .......
Output : _RET_CODE
***********************************************************/
_RET_CODE NUTL_ECC_Correction(kal_uint32 *dataPtr, kal_uint32 *parityPtr, kal_uint32 *sparePtr, \
kal_uint16 pageSize, kal_uint32 blockSize)
{
kal_uint8 update_data;
kal_uint32 i;
kal_uint32 error_bit_address;
kal_uint32 error_bit_offset;
kal_uint8 *p_data8 = (kal_uint8 *)dataPtr;
kal_uint32 ecc_parity_from_spare[5] = {0,0,0,0,0};
kal_uint32 *ecc_parity_from_reg = parityPtr;
UnionData_U xor_ecc_parity[4];
kal_uint8 status = NFI_SUCCESS;
if ( pageSize==512 )
{
ecc_parity_from_spare[0] = *(sparePtr + 2);
}
else
{
ecc_parity_from_spare[0] = *(sparePtr + 11);
ecc_parity_from_spare[1] = *(sparePtr + 12);
ecc_parity_from_spare[2] = *(sparePtr + 13);
ecc_parity_from_spare[3] = *(sparePtr + 14);
}
// 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<(pageSize/0x200); 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 = 0x200*i + (error_bit_address>>3);
update_data = p_data8[error_bit_offset];
update_data = update_data^(1<<(kal_uint8)(error_bit_address&0x0007));
#ifdef BIT_ERROR_TEST
dbg_print(" ECC error address=%x error bit=%x Original=%x corrected data=%x \n\r",
error_bit_offset, error_bit_address & 0x07, p_data8[error_bit_offset], update_data);
#endif
p_data8[error_bit_offset] = update_data;
if(status==NFI_SUCCESS) {
status = NFI_ECC_1BIT_CORRECT;
}
}
else
{
kal_uint32 iIndex=0,iEccsum=0;
for(iIndex = 0; iIndex < 12; iIndex++)
{
iEccsum += ((xor_ecc_parity[i].d16[0] >> iIndex) & 0x01);
iEccsum += ((xor_ecc_parity[i].d16[1] >> iIndex) & 0x01);
}
if(iEccsum ==1)
{
// ECC code error.
dbg_print(" ECC code error... \n\r");
continue;
}
/* dbg_print(" ECC error ... \n\r");
dbg_print(" Register %x \n\r", ecc_parity_from_reg[i]);
dbg_print(" Spare %x \n\r", ecc_parity_from_spare[i]);*/
if(status!=NFI_ECC_2BITS_ERR) {
status = NFI_ECC_2BITS_ERR;
}
}
}
}
return status;
}
/**********************************************************
Description : NFI_PageRead
Input : .......
Output : _RET_CODE
Remark : Must be page alignment
***********************************************************/
_RET_CODE NFI_PageRead(kal_uint32 *destination, kal_uint32 *parity, kal_uint32 length, \
kal_uint16 addr_no, kal_uint32 addr1, kal_uint16 addr2, kal_uint16 pageSize, \
kal_bool ECC, kal_bool continous)
{
kal_int16 timeout=0xfff;
kal_uint32 *parity_ptr = parity;
*NFI_OPCON = 0x00;
*NFI_CON = 0x00;
*NFI_FIFOCON = 0x30; // Flushing FIFO
if ( pageSize<1024 )
{
*NFI_CMD = RD_1ST_CMD; // read command
while (*NFI_PSTA & STATUS_CMD);
*NFI_ADDRL = addr1;
if ( addr_no>4 )
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -