1526 lines
52 KiB
C
Executable File
1526 lines
52 KiB
C
Executable File
/*
|
|
* drvSPINAND_api.c- Sigmastar
|
|
*
|
|
* Copyright (C) 2018 Sigmastar Technology Corp.
|
|
*
|
|
* Author: edie.chen <edie.chen@sigmastar.com.tw>
|
|
*
|
|
* This software is licensed under the terms of the GNU General Public
|
|
* License version 2, as published by the Free Software Foundation, and
|
|
* may be copied, distributed, and modified under those terms.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <malloc.h>
|
|
#include <linux/err.h>
|
|
//#include <linux/compat.h>
|
|
#include <linux/mtd/mtd.h>
|
|
#include <linux/mtd/nand.h>
|
|
#include <linux/mtd/nand_ecc.h>
|
|
#include <asm/io.h>
|
|
#include <asm/errno.h>
|
|
#include "MsCommon.h"
|
|
#include "MsTypes.h"
|
|
#include "spinand.h"
|
|
|
|
/* SPI NAND messages */
|
|
|
|
// static U32 CheckSum(U8 *pu8_Data, U16 u16_ByteCnt)
|
|
// {
|
|
// U32 u32_Sum = 0;
|
|
//
|
|
// while (u16_ByteCnt--)
|
|
// u32_Sum += *pu8_Data++;
|
|
//
|
|
// return u32_Sum;
|
|
// }
|
|
|
|
void dumpPartition(PARTITION_INFO_t *ptPartInfo, SPI_NAND_DRIVER_t *pSpiNandDrv)
|
|
{
|
|
printf("PartInfo(.pni) isn't equal to CISInfo(.sni)!\n");
|
|
printf("PartInfo(.pni)\n");
|
|
printf(" Spare %d\n",ptPartInfo->u16_SpareByteCnt);
|
|
printf(" Page %d\n",ptPartInfo->u16_PageByteCnt);
|
|
printf(" BlkPage %d\n",ptPartInfo->u16_BlkPageCnt);
|
|
printf(" BlkCnt %d\n",ptPartInfo->u16_BlkCnt);
|
|
|
|
printf("CISInfo(.sni) \n");
|
|
printf(" Spare %d\n",pSpiNandDrv->tSpinandInfo.u16_SpareByteCnt);
|
|
printf(" Page %d\n",pSpiNandDrv->tSpinandInfo.u16_PageByteCnt);
|
|
printf(" BlkPage %d\n",pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt);
|
|
printf(" BlkCnt %d\n",pSpiNandDrv->tSpinandInfo.u16_BlkCnt);
|
|
}
|
|
|
|
/* return 1: Good block, 0: Bad block */
|
|
U32 MDrv_SPINAND_IsGoodBlk(U16 u16_PBA)
|
|
{
|
|
U32 u32_PageIdx;
|
|
U32 u32_Err;
|
|
SPI_NAND_DRIVER_t *pSpiNandDrv = (SPI_NAND_DRIVER_t*)drvSPINAND_get_DrvContext_address();
|
|
u32_PageIdx = u16_PBA * pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt;
|
|
u32_Err = MDrv_SPINAND_Read(u32_PageIdx, pSpiNandDrv->pu8_pagebuf, pSpiNandDrv->pu8_sparebuf);
|
|
|
|
if(u32_Err != ERR_SPINAND_SUCCESS)
|
|
spi_nand_err("MDrv_SPINAND_Read(0x%x)=0x%x\n", u32_PageIdx, u32_Err);
|
|
|
|
if(pSpiNandDrv->pu8_sparebuf[0] != 0xFF)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int MDrv_SPINAND_WriteCIS_for_ROM(SPINAND_FLASH_INFO_TAG_t *pSpiNandInfoTagOut, int nCopies)
|
|
{
|
|
U32 u32_Err = ERR_SPINAND_SUCCESS;
|
|
U16 u16_PBA;
|
|
U32 u32_PageIdx;
|
|
|
|
SPI_NAND_DRIVER_t *pSpiNandDrv = (SPI_NAND_DRIVER_t*)drvSPINAND_get_DrvContext_address();
|
|
|
|
/* Search for two good blocks within the first 10 physical blocks */
|
|
for (u16_PBA = 0; u16_PBA < nCopies * 2; u16_PBA += 2)
|
|
{
|
|
/* Check first page of block */
|
|
u32_PageIdx = u16_PBA * pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt;
|
|
u32_Err = MDrv_SPINAND_Read(u32_PageIdx, pSpiNandDrv->pu8_pagebuf, pSpiNandDrv->pu8_sparebuf);
|
|
|
|
if(u32_Err != ERR_SPINAND_SUCCESS)
|
|
spi_nand_err("MDrv_SPINAND_Read(0x%x)=0x%x\n", u32_PageIdx, u32_Err);
|
|
u32_Err = MDrv_SPINAND_BLOCK_ERASE(u32_PageIdx);
|
|
|
|
if(u32_Err != ERR_SPINAND_SUCCESS)
|
|
{
|
|
spi_nand_err("MDrv_SPINAND_BLOCK_ERASE(0x%X)=0x%x\n", u16_PBA, u32_Err);
|
|
continue;
|
|
}
|
|
|
|
memset(pSpiNandDrv->pu8_pagebuf, 0xFF, pSpiNandDrv->tSpinandInfo.u16_PageByteCnt);
|
|
memcpy(pSpiNandDrv->pu8_pagebuf, pSpiNandInfoTagOut, sizeof(SPINAND_FLASH_INFO_TAG_t));
|
|
memset(pSpiNandDrv->pu8_sparebuf, 0xFF, pSpiNandDrv->tSpinandInfo.u16_SpareByteCnt);
|
|
u32_Err = MDrv_SPINAND_Write(u32_PageIdx, pSpiNandDrv->pu8_pagebuf, pSpiNandDrv->pu8_sparebuf);
|
|
if(u32_Err != ERR_SPINAND_SUCCESS)
|
|
{
|
|
spi_nand_err("MDrv_SPINAND_Write(0x%x)=0x%x\n", u32_PageIdx, u32_Err);
|
|
continue;
|
|
}
|
|
|
|
/**
|
|
** Write Partition Info the 2nd page
|
|
**/
|
|
|
|
if(pSpiNandDrv->u8_HasPNI == 1)
|
|
{
|
|
memset(pSpiNandDrv->pu8_pagebuf, 0xFF, pSpiNandDrv->tSpinandInfo.u16_PageByteCnt);
|
|
memcpy(pSpiNandDrv->pu8_pagebuf, &pSpiNandDrv->tPartInfo, 0x200);
|
|
u32_Err = MDrv_SPINAND_Write(u32_PageIdx + 1, pSpiNandDrv->pu8_pagebuf, pSpiNandDrv->pu8_sparebuf);
|
|
if(u32_Err != ERR_SPINAND_SUCCESS)
|
|
{
|
|
spi_nand_err("MDrv_SPINAND_Write(0x%x)=0x%x\n", u32_PageIdx + 1, u32_Err);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
spi_nand_msg("CIS is written to blk 0x%04x", u16_PBA);
|
|
|
|
}
|
|
|
|
return ERR_SPINAND_SUCCESS;
|
|
}
|
|
|
|
static U32 _MDrv_SPINAND_checkSum(U8 *pu8_Data, U16 u16_ByteCnt)
|
|
{
|
|
U32 u32_Sum = 0;
|
|
|
|
while (u16_ByteCnt--)
|
|
u32_Sum += *pu8_Data++;
|
|
return u32_Sum;
|
|
}
|
|
|
|
|
|
static int _MDrv_SPINAND_GetMtdPartsFromSNI(char *buf)
|
|
{
|
|
char *mtd_buf=buf, tmp[32];
|
|
int len, u8_i, Maxlen = 512;
|
|
SPI_NAND_DRIVER_t *pSpiNandDrv = (SPI_NAND_DRIVER_t*)drvSPINAND_get_DrvContext_address();
|
|
u32 blockSize = pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt * pSpiNandDrv->tSpinandInfo.u16_PageByteCnt;
|
|
|
|
sprintf(mtd_buf, "mtdparts=nand0:");
|
|
mtd_buf += strlen(mtd_buf);
|
|
Maxlen -= strlen(mtd_buf);
|
|
|
|
for(u8_i = 0; u8_i < IPL_BACKUP; u8_i++)
|
|
{
|
|
if(u8_i == 0)
|
|
sprintf(tmp, "0x%X@0x%X(IPL%d)", SBOOT_MAXBLOCK * blockSize, CIS_DEFAULT_BACKUP * blockSize, u8_i);
|
|
else
|
|
sprintf(tmp, ",0x%X(IPL%d)", SBOOT_MAXBLOCK * blockSize, u8_i);
|
|
len = strlen(tmp);
|
|
memcpy(mtd_buf, tmp, len);
|
|
mtd_buf += len;
|
|
if (Maxlen < len)
|
|
goto cleanup;
|
|
Maxlen -= len;
|
|
}
|
|
for(u8_i = 0; u8_i < IPL_CUST_BACKUP; u8_i++)
|
|
{
|
|
sprintf(tmp, ",0x%X(IPL_CUST%d)", SBOOT_MAXBLOCK * blockSize, u8_i);
|
|
len = strlen(tmp);
|
|
memcpy(mtd_buf, tmp, len);
|
|
mtd_buf += len;
|
|
if (Maxlen < len)
|
|
goto cleanup;
|
|
Maxlen -= len;
|
|
}
|
|
for(u8_i = 0; u8_i < UBOOT_BACKUP; u8_i++)
|
|
{
|
|
sprintf(tmp, ",0x%X(UBOOT%d)", UBOOT_MAXBLOCK * blockSize, u8_i);
|
|
len = strlen(tmp);
|
|
memcpy(mtd_buf, tmp, len);
|
|
mtd_buf += len;
|
|
if (Maxlen < len)
|
|
goto cleanup;
|
|
Maxlen -= len;
|
|
}
|
|
/* env */
|
|
sprintf(tmp, ",0x%X(ENV)", blockSize);
|
|
len = strlen(tmp);
|
|
memcpy(mtd_buf, tmp, len);
|
|
mtd_buf += len;
|
|
if (Maxlen < len)
|
|
goto cleanup;
|
|
Maxlen -= len;
|
|
*mtd_buf = '\0';
|
|
return 0;
|
|
cleanup:
|
|
buf[0] = '\0';
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int _MDrv_SPINAND_GetMtdPartsFromPNI(char *buf)
|
|
{
|
|
SPI_NAND_DRIVER_t *pSpiNandDrv = (SPI_NAND_DRIVER_t*)drvSPINAND_get_DrvContext_address();
|
|
PARTITION_INFO_t *pPartInfo = &pSpiNandDrv->tPartInfo;
|
|
U8 u8_i, u8_PartNo = 0;
|
|
int len, Maxlen = 512;
|
|
U32 PartSize = 0;
|
|
char *mtd_buf=buf, tmp[32], PartName[32];
|
|
U16 u16_LastPartType;
|
|
BOOL bFound;
|
|
BOOL bLogic = FALSE;
|
|
BOOL bFirst = TRUE;
|
|
U16 nMaxPart;
|
|
U32 nPartTypeNoFlag;
|
|
|
|
sprintf(mtd_buf, "mtdparts=nand0:");
|
|
mtd_buf += 15;
|
|
Maxlen -= 15;
|
|
|
|
u16_LastPartType = 0;
|
|
bFound = FALSE;
|
|
nMaxPart = sizeof(pPartInfo->records) / sizeof(pPartInfo->records[0]);
|
|
for(u8_i = 0; u8_i < pPartInfo->u16_PartCnt && u8_i < nMaxPart; u8_i ++)
|
|
{
|
|
if( (pPartInfo->records[u8_i].u16_PartType & UNFD_LOGI_PART) == UNFD_LOGI_PART)
|
|
bLogic = TRUE;
|
|
else
|
|
bLogic = FALSE;
|
|
if( (pPartInfo->records[u8_i].u16_PartType & UNFD_HIDDEN_PART) == UNFD_HIDDEN_PART)
|
|
continue;
|
|
|
|
nPartTypeNoFlag = pPartInfo->records[u8_i].u16_PartType & 0x0FFF;
|
|
|
|
PartSize = 0;
|
|
if( bFound )
|
|
{
|
|
memcpy(mtd_buf, ",", 1);
|
|
mtd_buf ++;
|
|
Maxlen --;
|
|
}
|
|
bFound = FALSE;
|
|
|
|
PartSize = pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt * pSpiNandDrv->tSpinandInfo.u16_PageByteCnt *
|
|
(pPartInfo->records[u8_i].u16_BackupBlkCnt + pPartInfo->records[u8_i].u16_BlkCnt);
|
|
|
|
if(u16_LastPartType != pPartInfo->records[u8_i].u16_PartType)
|
|
{
|
|
u8_PartNo = 0;
|
|
}
|
|
else
|
|
{
|
|
u8_PartNo++;
|
|
}
|
|
u16_LastPartType = pPartInfo->records[u8_i].u16_PartType;
|
|
|
|
switch(nPartTypeNoFlag)
|
|
{
|
|
case UNFD_PART_CIS:
|
|
sprintf(PartName,"CIS");
|
|
break;
|
|
case UNFD_PART_IPL_CUST:
|
|
sprintf(PartName,"IPL_CUST%d",u8_PartNo );
|
|
break;
|
|
case UNFD_PART_BOOTLOGO:
|
|
sprintf(PartName,"LOGO" );
|
|
break;
|
|
case UNFD_PART_IPL:
|
|
sprintf(PartName,"IPL%d",u8_PartNo );
|
|
break;
|
|
case UNFD_PART_CUS:
|
|
sprintf(PartName,"CUS" );
|
|
break;
|
|
case UNFD_PART_UBOOT:
|
|
sprintf(PartName,"UBOOT%d",u8_PartNo );
|
|
break;
|
|
case UNFD_PART_OS:
|
|
sprintf(PartName,"KERNEL" );
|
|
break;
|
|
case UNFD_PART_SECINFO:
|
|
sprintf(PartName,"SECINFO" );
|
|
break;
|
|
case UNFD_PART_OTP:
|
|
sprintf(PartName,"OTP" );
|
|
break;
|
|
case UNFD_PART_RECOVERY:
|
|
sprintf(PartName,"RECOVERY" );
|
|
break;
|
|
case UNFD_PART_E2PBAK:
|
|
sprintf(PartName,"E2PBAK" );
|
|
break;
|
|
case UNFD_PART_NVRAMBAK:
|
|
sprintf(PartName,"NVRAMBAK" );
|
|
break;
|
|
case UNFD_PART_NPT:
|
|
sprintf(PartName,"NPT" );
|
|
break;
|
|
case UNFD_PART_ENV:
|
|
if(!u8_PartNo)
|
|
{
|
|
sprintf(PartName,"ENV");
|
|
}
|
|
else
|
|
{
|
|
sprintf(PartName,"ENV%d",u8_PartNo );
|
|
}
|
|
break;
|
|
case UNFD_PART_MISC:
|
|
sprintf(PartName,"MISC" );
|
|
break;
|
|
case UNFD_PART_RTOS:
|
|
sprintf(PartName,"RTOS" );
|
|
break;
|
|
case UNFD_PART_RTOS_BAK:
|
|
sprintf(PartName,"RTOS_BACKUP" );
|
|
break;
|
|
case UNFD_PART_KERNEL:
|
|
sprintf(PartName,"KERNEL" );
|
|
break;
|
|
case UNFD_PART_KERNEL_BAK:
|
|
sprintf(PartName,"KERNEL_BACKUP" );
|
|
break;
|
|
case UNFD_PART_UBI:
|
|
sprintf(PartName,"UBI" );
|
|
break;
|
|
case UNFD_PART_ROOTFS:
|
|
sprintf(PartName,"rootfs" );
|
|
break;
|
|
case UNFD_PART_ROOTFS_BAK:
|
|
sprintf(PartName,"rootfs_bak" );
|
|
break;
|
|
case UNFD_PART_KEY_CUST:
|
|
sprintf(PartName,"KEY_CUST" );
|
|
break;
|
|
default:
|
|
if(nPartTypeNoFlag >= UNFD_PART_CUST0 &&
|
|
nPartTypeNoFlag <= UNFD_PART_CUSTf)
|
|
{
|
|
sprintf(PartName,"CUST%d", nPartTypeNoFlag - UNFD_PART_CUST0);
|
|
}
|
|
else
|
|
{
|
|
sprintf(PartName,"UNKNOWN%d",u8_i );
|
|
}
|
|
break;
|
|
}
|
|
bFound = TRUE;
|
|
if (bFirst)
|
|
{
|
|
sprintf(tmp, "0x%X@0x%X(%s)", (unsigned int)PartSize,
|
|
pPartInfo->records[u8_i].u16_StartBlk * pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt *
|
|
pSpiNandDrv->tSpinandInfo.u16_PageByteCnt, PartName); //,pPartInfo->records[u8_i].u16_PartType);
|
|
bFirst = FALSE;
|
|
}
|
|
else
|
|
sprintf(tmp, "0x%X(%s)", (unsigned int)PartSize, PartName); //,pPartInfo->records[u8_i].u16_PartType);
|
|
|
|
len = strlen(tmp);
|
|
memcpy(mtd_buf, tmp, len);
|
|
mtd_buf += len;
|
|
if (Maxlen < len)
|
|
goto cleanup;
|
|
Maxlen -= len;
|
|
|
|
}
|
|
|
|
while(bLogic && u8_i > 0)
|
|
{
|
|
if(pPartInfo->records[u8_i - 1].u16_PartType == 0xC000)
|
|
sprintf(tmp,",-(UBI)");
|
|
else if((pPartInfo->records[u8_i - 1].u16_PartType & UNFD_HIDDEN_PART) == 0)
|
|
sprintf(tmp,",-(%s)", PartName);
|
|
else
|
|
{
|
|
//spi_nand_err("Unable to parse type 0x%X\n", pPartInfo->records[u8_i - 1].u16_PartType);
|
|
break;
|
|
}
|
|
len= strlen(tmp);
|
|
memcpy(mtd_buf, tmp, len);
|
|
mtd_buf += len;
|
|
if (Maxlen < len)
|
|
goto cleanup;
|
|
Maxlen -= len;
|
|
break;
|
|
}
|
|
|
|
*mtd_buf = '\0';
|
|
return 0;
|
|
|
|
cleanup:
|
|
buf[0] = '\0';
|
|
return -1;
|
|
}
|
|
|
|
int MDrv_SPINAND_SearchCIS_in_DRAM(U8 *pu8_CISAddr, U8 *pu8_PNIAddr, SPINAND_FLASH_INFO_TAG_t *pSpiNandInfoTagOut)
|
|
{
|
|
SPINAND_FLASH_INFO_TAG_t *pSpiNandInfoTag;
|
|
SPINAND_FLASH_INFO_t *ptSpinandInfo;
|
|
PARTITION_INFO_t *ptPartInfo;
|
|
SPI_NAND_DRIVER_t *pSpiNandDrv = (SPI_NAND_DRIVER_t*)drvSPINAND_get_DrvContext_address();
|
|
U32 u32_i, u32_j, u32_chkSum;
|
|
U8 u8_IsEnd = 0;
|
|
|
|
spi_nand_err("Search CIS in DRAM");
|
|
|
|
//Search 20 pieces of possiable cis memory
|
|
u32_i = 0;
|
|
// printf("pu8_CISAddr %x\n",pu8_CISAddr);
|
|
// printf("pSpiNandDrv->tSpinandInfo.au8_ID[0] %x\n",pSpiNandDrv->tSpinandInfo.au8_ID[0]);
|
|
|
|
while(1)
|
|
{
|
|
pSpiNandInfoTag = (SPINAND_FLASH_INFO_TAG_t *)(pu8_CISAddr + u32_i);
|
|
ptSpinandInfo = &pSpiNandInfoTag->tSpiNandInfo;
|
|
|
|
if(u32_i == 0)
|
|
{
|
|
if(ptSpinandInfo->u8_IDByteCnt == 5 &&
|
|
ptSpinandInfo->au8_ID[0] == 0xEE && ptSpinandInfo->au8_ID[1] == 0xEE)
|
|
{
|
|
spi_nand_err("SNI v:%d.%d.%d", ptSpinandInfo->au8_ID[2], ptSpinandInfo->au8_ID[3], ptSpinandInfo->au8_ID[4]);
|
|
}
|
|
}
|
|
|
|
for(u32_j = 0; u32_j < pSpiNandDrv->tSpinandInfo.u8_IDByteCnt; u32_j++)
|
|
{
|
|
if(pSpiNandDrv->tSpinandInfo.au8_ID[u32_j] != ptSpinandInfo->au8_ID[u32_j])
|
|
break;
|
|
}
|
|
|
|
if(u32_j == pSpiNandDrv->tSpinandInfo.u8_IDByteCnt)
|
|
break;
|
|
|
|
if(memcmp((const void *) pSpiNandInfoTag->au8_Tag, (const void *) SPINAND_FLASH_INFO_TAG, 16))
|
|
{
|
|
u8_IsEnd = 1;
|
|
break;
|
|
}
|
|
u32_i += 0x200;
|
|
}
|
|
|
|
if(u8_IsEnd == 1)
|
|
{
|
|
spi_nand_err("No available SNI match with current SPINAND flash");
|
|
return ERR_SPINAND_INVALID;
|
|
}
|
|
spi_nand_err("Found SNI in given memory");
|
|
|
|
memcpy(&pSpiNandDrv->tSpinandInfo, ptSpinandInfo, sizeof(SPINAND_FLASH_INFO_t));
|
|
//MDrv_SPINAND_ForceInit(ptSpinandInfo);
|
|
|
|
/*Search pni*/
|
|
pSpiNandDrv->u8_HasPNI = 0;
|
|
|
|
if(pu8_PNIAddr != NULL)
|
|
{
|
|
ptPartInfo = (PARTITION_INFO_t*) (pu8_PNIAddr);
|
|
memcpy(&pSpiNandDrv->tPartInfo, ptPartInfo, 0x200);
|
|
/*Add checksum*/
|
|
u32_chkSum = _MDrv_SPINAND_checkSum((U8*)ptPartInfo + 0x04, 0x200 - 0x04);
|
|
if(u32_chkSum== ptPartInfo->u32_ChkSum)
|
|
{
|
|
spi_nand_msg("PNI match success");
|
|
pSpiNandDrv->u8_HasPNI = 1;
|
|
}
|
|
else
|
|
{
|
|
spi_nand_err("PNI mismatch \x1b[33m%X\x1b[0m", u32_chkSum);
|
|
pSpiNandDrv->u8_HasPNI = 0;
|
|
return ERR_SPINAND_INVALID;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
spi_nand_err("CIS doesn't contain part info");
|
|
pSpiNandDrv->u8_HasPNI = 0;
|
|
}
|
|
memcpy(pSpiNandInfoTagOut, pSpiNandInfoTag , sizeof(SPINAND_FLASH_INFO_TAG_t));
|
|
return ERR_SPINAND_SUCCESS;
|
|
}
|
|
|
|
int MDrv_SPINAND_GetMtdParts(char *buf)
|
|
{
|
|
SPI_NAND_DRIVER_t *pSpiNandDrv = (SPI_NAND_DRIVER_t*)drvSPINAND_get_DrvContext_address();
|
|
|
|
if(1 == pSpiNandDrv->u8_HasPNI && 0 == (pSpiNandDrv->tSpinandInfo.u8_UBOOTPBA))
|
|
{
|
|
spi_nand_err("Force Search mtdparts from PNI...\n");
|
|
return _MDrv_SPINAND_GetMtdPartsFromPNI(buf);
|
|
}
|
|
else if(1 == pSpiNandDrv->u8_HasPNI)
|
|
{
|
|
spi_nand_err("Search mtdparts from PNI...\n");
|
|
return _MDrv_SPINAND_GetMtdPartsFromPNI(buf);
|
|
}
|
|
else if (0 != (pSpiNandDrv->tSpinandInfo.u8_BL0PBA))
|
|
{
|
|
spi_nand_err("Search mtdparts from SNI...\n");
|
|
return _MDrv_SPINAND_GetMtdPartsFromSNI(buf);
|
|
}
|
|
else
|
|
{
|
|
spi_nand_err("Search mtdparts fail...\n");
|
|
return -1;
|
|
}
|
|
}
|
|
/* Search for partition of type @u16_PartType, begin from @pRecord */
|
|
PARTITION_RECORD_t *MDrv_SPINAND_SearchPartition(PARTITION_RECORD_t *pRecord,
|
|
U16 u16_PartType)
|
|
{
|
|
SPI_NAND_DRIVER_t *pSpiNandDrv = (SPI_NAND_DRIVER_t*)drvSPINAND_get_DrvContext_address();
|
|
PARTITION_INFO_t *pPartInfo = &pSpiNandDrv->tPartInfo;
|
|
|
|
while (pRecord - pPartInfo->records < pPartInfo->u16_PartCnt) {
|
|
|
|
if (pRecord->u16_PartType == u16_PartType)
|
|
return pRecord;
|
|
|
|
pRecord++;
|
|
}
|
|
|
|
return (void*)0;
|
|
}
|
|
|
|
int MDrv_SPINAND_GetPartOffset(U16 u16_PartType, U32* u32_Offset, U8 u8_backup)
|
|
{
|
|
SPI_NAND_DRIVER_t *pSpiNandDrv = (SPI_NAND_DRIVER_t*)drvSPINAND_get_DrvContext_address();
|
|
u16 ENVPBA = 0;
|
|
u32 blockSize = pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt * pSpiNandDrv->tSpinandInfo.u16_PageByteCnt;
|
|
|
|
if (0 != (pSpiNandDrv->tSpinandInfo.u8_UBOOTPBA))
|
|
{
|
|
ENVPBA = ((CIS_DEFAULT_BACKUP + IPL_BACKUP + IPL_CUST_BACKUP) * SBOOT_MAXBLOCK)+(UBOOT_BACKUP * UBOOT_MAXBLOCK);
|
|
if(u8_backup)
|
|
{
|
|
ENVPBA += 2;
|
|
}
|
|
*u32_Offset = ENVPBA * blockSize;
|
|
return 0;
|
|
}
|
|
else if(1 == pSpiNandDrv->u8_HasPNI)
|
|
{
|
|
PARTITION_INFO_t *pPartInfo = &pSpiNandDrv->tPartInfo;
|
|
PARTITION_RECORD_t *pRecord = pPartInfo->records;
|
|
pRecord = MDrv_SPINAND_SearchPartition(pRecord, u16_PartType);
|
|
|
|
if (!pRecord)
|
|
{
|
|
*u32_Offset = 0;
|
|
return -1;
|
|
}
|
|
if(u8_backup)
|
|
{
|
|
pRecord ++;
|
|
}
|
|
*u32_Offset = pRecord->u16_StartBlk * pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt * pSpiNandDrv->tSpinandInfo.u16_PageByteCnt;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
ENVPBA = ((CIS_DEFAULT_BACKUP + IPL_BACKUP + IPL_CUST_BACKUP) * SBOOT_MAXBLOCK)+(UBOOT_BACKUP * UBOOT_MAXBLOCK);
|
|
if(u8_backup)
|
|
{
|
|
ENVPBA += 2;
|
|
}
|
|
*u32_Offset = ENVPBA * blockSize;
|
|
spi_nand_err("UBOOT_PBA==0 and no PNI: %d %d %d", pSpiNandDrv->tSpinandInfo.u8_BL0PBA, pSpiNandDrv->tSpinandInfo.u8_BL1PBA, pSpiNandDrv->tSpinandInfo.u8_UBOOTPBA);
|
|
spi_nand_err("use offset %X", *u32_Offset);
|
|
return 0;
|
|
//spi_nand_err("Search part fail...\n");
|
|
//return -1;
|
|
}
|
|
}
|
|
|
|
int MDrv_SPINAND_ReadCISBlk(U8* pu8_DataBuf)
|
|
{
|
|
U32 u32_Err = ERR_SPINAND_SUCCESS;
|
|
U16 u16Idx = 0;
|
|
U16 u16PageIndex = 0;
|
|
U16 u16BlkIndex = 10;
|
|
U16 page_off = 0;
|
|
|
|
SPI_NAND_DRIVER_t *pSpiNandDrv = (SPI_NAND_DRIVER_t*)drvSPINAND_get_DrvContext_address();
|
|
page_off = pSpiNandDrv->tSpinandInfo.u16_PageByteCnt + pSpiNandDrv->tSpinandInfo.u16_SpareByteCnt;
|
|
u16PageIndex = (u16BlkIndex * pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt) - 1;
|
|
|
|
for(u16Idx = 0; u16Idx <= u16PageIndex; u16Idx++)
|
|
{
|
|
u32_Err = MDrv_SPINAND_Read(u16Idx, pu8_DataBuf, pu8_DataBuf + pSpiNandDrv->tSpinandInfo.u16_PageByteCnt);
|
|
pu8_DataBuf += page_off;
|
|
}
|
|
printf("Read total size 0x%X\n", page_off * (u16Idx));
|
|
return u32_Err;
|
|
}
|
|
|
|
|
|
static __inline void dump_mem_line(unsigned char *buf, int cnt)
|
|
{
|
|
int i;
|
|
|
|
printk(KERN_NOTICE" 0x%x: ", (U32)buf);
|
|
for (i= 0; i < cnt; i++)
|
|
printk(KERN_NOTICE"%02X ", buf[i]);
|
|
|
|
printk(KERN_NOTICE" | ");
|
|
|
|
for (i = 0; i < cnt; i++)
|
|
printk(KERN_NOTICE"%c", (buf[i] >= 32 && buf[i] < 128) ? buf[i] : '.');
|
|
|
|
printk(KERN_NOTICE"\n");
|
|
}
|
|
|
|
void dump_mem(unsigned char *buf, int cnt)
|
|
{
|
|
int i;
|
|
|
|
for (i= 0; i < cnt; i+= 16)
|
|
dump_mem_line(buf + i, 16);
|
|
}
|
|
|
|
#if 0
|
|
void HWTimer_Start(void)
|
|
{
|
|
// reset HW timer
|
|
(*(volatile U16*)(TIMER1_MAX_LOW)) = 0xFFFF;
|
|
(*(volatile U16*)(TIMER1_MAX_HIGH)) = 0xFFFF;
|
|
(*(volatile U16*)(TIMER1_ENABLE)) = 0;
|
|
|
|
// start HW timer
|
|
(*(volatile U16*)(TIMER1_ENABLE)) |= 0x0001;
|
|
}
|
|
|
|
U32 HWTimer_End(void)
|
|
{
|
|
U32 u32HWTimer = 0;
|
|
U16 u16TimerLow = 0;
|
|
U16 u16TimerHigh = 0;
|
|
|
|
// Get HW timer
|
|
u16TimerLow = (*(volatile U16*)(TIMER1_CAP_LOW));
|
|
u16TimerHigh = (*(volatile U16*)(TIMER1_CAP_HIGH));
|
|
|
|
u32HWTimer = (u16TimerHigh<<16) | u16TimerLow;
|
|
|
|
return u32HWTimer;
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
int MDrv_SPINAND_write_bootloader(U32 u32_Row,U8 * pu8_addr, U32 u32_size, U8 u8_BootStageId)
|
|
{
|
|
U8 *pu8_DataBuf = pu8_addr;
|
|
U16 u16_BlkPageCnt;
|
|
U32 u32_pagecnt, u32_Err, u32_size_tmp = u32_size, u32_Row_Read = u32_Row;
|
|
U16 u16_i;
|
|
SPI_NAND_DRIVER_t *pSpiNandDrv = (SPI_NAND_DRIVER_t*)drvSPINAND_get_DrvContext_address();
|
|
u16_BlkPageCnt = pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt;
|
|
u32_pagecnt = (u32_size+pSpiNandDrv->tSpinandInfo.u16_PageByteCnt-1)/pSpiNandDrv->tSpinandInfo.u16_PageByteCnt;
|
|
|
|
//add register status for polling by TV Tool
|
|
REG(RIU_BASE + (0x1980 << 2) + (0x41 << 2) ) = 0x0000;
|
|
|
|
while(u32_pagecnt >= u16_BlkPageCnt)
|
|
{
|
|
while (MDrv_SPINAND_IsGoodBlk(u32_Row / pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt) == 0)
|
|
{
|
|
u32_Row += pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt;
|
|
//bad block jump to next block
|
|
if(u32_Row == (pSpiNandDrv->tSpinandInfo.u16_BlkCnt*pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt))
|
|
{
|
|
printk(KERN_NOTICE"Error : There is no available GOOD block in current nand device\n");
|
|
REG(RIU_BASE + (0x1980 << 2) + (0x41 << 2) ) = 0x0004;
|
|
return -1;
|
|
}
|
|
}
|
|
u32_Err = MDrv_SPINAND_BLOCK_ERASE(u32_Row);
|
|
if(u32_Err != ERR_SPINAND_SUCCESS)
|
|
{
|
|
//jump to next block
|
|
u32_Row += pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt;
|
|
continue;
|
|
}
|
|
|
|
memset(pSpiNandDrv->pu8_sparebuf, 0xFF, pSpiNandDrv->tSpinandInfo.u16_SpareByteCnt);
|
|
pSpiNandDrv->pu8_sparebuf[4] = u8_BootStageId;
|
|
|
|
for(u16_i = 0 ; u16_i<pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt ; u16_i++)
|
|
{
|
|
u32_Err = MDrv_SPINAND_Write(u32_Row+u16_i, pu8_DataBuf+(u16_i*pSpiNandDrv->tSpinandInfo.u16_PageByteCnt), gtSpiNandDrv.pu8_sparebuf);
|
|
if(u32_Err != ERR_SPINAND_SUCCESS)
|
|
{
|
|
//jump to next block
|
|
u32_Row += pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt;
|
|
continue;
|
|
}
|
|
}
|
|
pu8_DataBuf += u16_BlkPageCnt*pSpiNandDrv->tSpinandInfo.u16_PageByteCnt;
|
|
|
|
u32_pagecnt -= u16_BlkPageCnt;
|
|
u32_size -= u16_BlkPageCnt*pSpiNandDrv->tSpinandInfo.u16_PageByteCnt;
|
|
u32_Row += pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt;
|
|
}
|
|
|
|
while(u32_size)
|
|
{
|
|
while (MDrv_SPINAND_IsGoodBlk(u32_Row/pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt) == 0)
|
|
{
|
|
u32_Row += pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt;
|
|
//bad block jump to next block
|
|
if(u32_Row == (pSpiNandDrv->tSpinandInfo.u16_BlkCnt*pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt))
|
|
{
|
|
printk(KERN_NOTICE"Error : There is no available GOOD block in current nand device\n");
|
|
REG(RIU_BASE + (0x1980 << 2) + (0x41 << 2) ) = 0x0004;
|
|
return -1;
|
|
}
|
|
}
|
|
u32_Err = MDrv_SPINAND_BLOCK_ERASE(u32_Row);
|
|
if(u32_Err != ERR_SPINAND_SUCCESS)
|
|
{
|
|
//jump to next block
|
|
u32_Row += pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt;
|
|
continue;
|
|
}
|
|
|
|
memset(pSpiNandDrv->pu8_sparebuf, 0xFF, pSpiNandDrv->tSpinandInfo.u16_SpareByteCnt);
|
|
pSpiNandDrv->pu8_sparebuf[4] = u8_BootStageId;
|
|
|
|
for(u16_i = 0 ; u16_i<u32_pagecnt ; u16_i++)
|
|
{
|
|
u32_Err = MDrv_SPINAND_Write(u32_Row+u16_i, pu8_DataBuf+(u16_i*pSpiNandDrv->tSpinandInfo.u16_PageByteCnt), gtSpiNandDrv.pu8_sparebuf);
|
|
if(u32_Err != ERR_SPINAND_SUCCESS)
|
|
{
|
|
//jump to next block
|
|
u32_Row += pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
u32_size-= u32_size;
|
|
}
|
|
//finish programming
|
|
//Add register checking
|
|
//read back check
|
|
// TODO
|
|
u32_size = u32_size_tmp;
|
|
u32_pagecnt = (u32_size+pSpiNandDrv->tSpinandInfo.u16_PageByteCnt-1)/pSpiNandDrv->tSpinandInfo.u16_PageByteCnt;
|
|
pu8_DataBuf = pu8_addr;
|
|
u32_Row = u32_Row_Read;
|
|
|
|
while(u32_pagecnt >= u16_BlkPageCnt)
|
|
{
|
|
while (MDrv_SPINAND_IsGoodBlk(u32_Row / pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt) == 0)
|
|
{
|
|
u32_Row += pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt;
|
|
//bad block jump to next block
|
|
if(u32_Row == (pSpiNandDrv->tSpinandInfo.u16_BlkCnt*pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt))
|
|
{
|
|
printk(KERN_NOTICE"Error : There is no available GOOD block in current nand device\n");
|
|
REG(RIU_BASE + (0x1980 << 2) + (0x41 << 2) ) = 0x0004;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
for(u16_i =0; u16_i < u16_BlkPageCnt; u16_i ++)
|
|
{
|
|
u32_Err = MDrv_SPINAND_Read(u32_Row+u16_i, pSpiNandDrv->pu8_pagebuf, pSpiNandDrv->pu8_sparebuf);
|
|
if(u32_Err != ERR_SPINAND_SUCCESS)
|
|
{
|
|
printk(KERN_NOTICE"Error: ECC fail when read back checking\n");
|
|
REG(RIU_BASE + (0x1980 << 2) + (0x41 << 2) ) = 0x0002;
|
|
return -1;
|
|
}
|
|
if(memcmp(pSpiNandDrv->pu8_pagebuf, pu8_DataBuf, pSpiNandDrv->tSpinandInfo.u16_PageByteCnt))
|
|
{
|
|
printk(KERN_NOTICE"Error: compare fail when read back checking\n");
|
|
printf("RAM--->\n");
|
|
dump_mem((unsigned char *) pu8_DataBuf, pSpiNandDrv->tSpinandInfo.u16_PageByteCnt);
|
|
printf("NAND--->\n");
|
|
dump_mem((unsigned char *) pSpiNandDrv->pu8_pagebuf, pSpiNandDrv->tSpinandInfo.u16_PageByteCnt);
|
|
REG(RIU_BASE + (0x1980 << 2) + (0x41 << 2) ) = 0x0003;
|
|
return -1;
|
|
}
|
|
pu8_DataBuf += pSpiNandDrv->tSpinandInfo.u16_PageByteCnt;
|
|
}
|
|
|
|
|
|
u32_pagecnt -= u16_BlkPageCnt;
|
|
u32_size -= (u16_BlkPageCnt*pSpiNandDrv->tSpinandInfo.u16_PageByteCnt);
|
|
u32_Row += pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt;
|
|
}
|
|
|
|
while(u32_size)
|
|
{
|
|
while (MDrv_SPINAND_IsGoodBlk(u32_Row / pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt) == 0)
|
|
{
|
|
u32_Row += pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt;
|
|
//bad block jump to next block
|
|
if(u32_Row == (pSpiNandDrv->tSpinandInfo.u16_BlkCnt*pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt))
|
|
{
|
|
printk(KERN_NOTICE"Error : There is no available GOOD block in current nand device\n");
|
|
REG(RIU_BASE + (0x1980 << 2) + (0x41 << 2) ) = 0x0004;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
for(u16_i=0; u16_i<u32_pagecnt; u16_i++)
|
|
{
|
|
u32_Err = MDrv_SPINAND_Read(u32_Row+u16_i, pSpiNandDrv->pu8_pagebuf, pSpiNandDrv->pu8_sparebuf);
|
|
if(u32_Err != ERR_SPINAND_SUCCESS)
|
|
{
|
|
printk(KERN_NOTICE"Error: ECC fail when read back checking\n");
|
|
REG(RIU_BASE + (0x1980 << 2) + (0x41 << 2) ) = 0x0002;
|
|
return -1;
|
|
}
|
|
|
|
if(memcmp(pSpiNandDrv->pu8_pagebuf, pu8_DataBuf, pSpiNandDrv->tSpinandInfo.u16_PageByteCnt))
|
|
{
|
|
printk(KERN_NOTICE"Error: compare fail when read back checking\n");
|
|
printf("RAM--->\n");
|
|
dump_mem((unsigned char *) pu8_DataBuf, pSpiNandDrv->tSpinandInfo.u16_PageByteCnt);
|
|
printf("NAND--->\n");
|
|
dump_mem((unsigned char *) pSpiNandDrv->pu8_pagebuf, pSpiNandDrv->tSpinandInfo.u16_PageByteCnt);
|
|
REG(RIU_BASE + (0x1980 << 2) + (0x41 << 2) ) = 0x0003;
|
|
return -1;
|
|
}
|
|
pu8_DataBuf += pSpiNandDrv->tSpinandInfo.u16_PageByteCnt;
|
|
}
|
|
|
|
u32_size -= u32_size;
|
|
}
|
|
//Register status Ok
|
|
REG(RIU_BASE + (0x1980 << 2) + (0x41 << 2) ) = 0x0001;
|
|
return 0;
|
|
}
|
|
#endif
|
|
#if 0
|
|
static u32 empty_check(const void *buf, u32 len)
|
|
{
|
|
int i;
|
|
SPI_NAND_DRIVER_t *pSpiNandDrv = (SPI_NAND_DRIVER_t*)drvSPINAND_get_DrvContext_address();
|
|
for (i = (len >> 2) - 1; i >= 0; i--)
|
|
if (((const uint32_t *)buf)[i] != 0xFFFFFFFF)
|
|
break;
|
|
|
|
/* The resulting length must be aligned to the minimum flash I/O size */
|
|
len = ALIGN((i + 1) << 2, pSpiNandDrv->tSpinandInfo.u16_PageByteCnt + pSpiNandDrv->tSpinandInfo.u16_SpareByteCnt);
|
|
return len;
|
|
}
|
|
#endif
|
|
#if 0
|
|
int MDrv_SPINAND_ReadCISBlk(U32 u32_off, U8* pu8_DataBuf)
|
|
{
|
|
U32 u32_Err, i;// pglen;
|
|
SPI_NAND_DRIVER_t *pSpiNandDrv = (SPI_NAND_DRIVER_t*)drvSPINAND_get_DrvContext_address();
|
|
#if 0
|
|
#ifdef FULL_BLOCK_PROGRAM_SCRUB
|
|
U32 chk_len;
|
|
#endif
|
|
#endif
|
|
U32 u32_Row = u32_off/pSpiNandDrv->tSpinandInfo.u16_PageByteCnt;
|
|
U32 page_off = pSpiNandDrv->tSpinandInfo.u16_PageByteCnt + pSpiNandDrv->tSpinandInfo.u16_SpareByteCnt;
|
|
|
|
// pglen = pSpiNandDrv->tSpinandInfo.u16_PageByteCnt + pSpiNandDrv->tSpinandInfo.u16_SpareByteCnt;
|
|
for(i=0 ; i<pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt; i++)
|
|
{
|
|
u32_Err = MDrv_SPINAND_Read(u32_Row+i, pu8_DataBuf+page_off*i, pu8_DataBuf+page_off*i+pSpiNandDrv->tSpinandInfo.u16_PageByteCnt);
|
|
if(u32_Err != ERR_SPINAND_SUCCESS)
|
|
return u32_Err;
|
|
|
|
/*
|
|
*For SLC, full block program is not necessary
|
|
*Turn on this switch if Spinand is MLC
|
|
*/
|
|
#if 0
|
|
#ifdef FULL_BLOCK_PROGRAM_SCRUB
|
|
chk_len = empty_check(pu8_DataBuf+page_off*i, pglen);
|
|
if (!chk_len)
|
|
{
|
|
(pu8_DataBuf + page_off * i)[0] = 0xfe; // indicate empty page
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
return ERR_SPINAND_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
static U8 MDrv_SPINAND_CheckAll0xFF(U8* pu8_Buf, U32 u32_ByteCnt)
|
|
{
|
|
register U32 u32_i;
|
|
|
|
for(u32_i=0; u32_i<u32_ByteCnt; u32_i++)
|
|
if(0xFF != pu8_Buf[u32_i])
|
|
return 0;
|
|
|
|
return 0xFF;
|
|
}
|
|
|
|
U32 MDrv_SPINAND_RefreshCIS(void)
|
|
{
|
|
SPI_NAND_DRIVER_t *pSpiNandDrv = (SPI_NAND_DRIVER_t*)drvSPINAND_get_DrvContext_address();
|
|
SPINAND_FLASH_INFO_t *ptSpinandInfo;
|
|
SPINAND_FLASH_INFO_TAG_t *pSpiNandInfoTag;
|
|
PARTITION_INFO_t *pPartInfo = &pSpiNandDrv->tPartInfo;
|
|
U32 u32_BlkIdx, u32_MBootBegin = 0, u32_MBootEnd = 0;
|
|
U32 u32_Err;
|
|
U8 u8_i;
|
|
int bl_count = 0;
|
|
|
|
pSpiNandInfoTag = (SPINAND_FLASH_INFO_TAG_t *)malloc(512);
|
|
if(!pSpiNandInfoTag)
|
|
{
|
|
printk(KERN_NOTICE"Memory Allocate fail for pSpiNandInfoTag\n");
|
|
return -1;
|
|
}
|
|
|
|
memset(pSpiNandInfoTag, 0, 512);
|
|
memcpy(pSpiNandInfoTag->au8_Tag, SPINAND_FLASH_INFO_TAG, 16);
|
|
ptSpinandInfo = &pSpiNandInfoTag->tSpiNandInfo;
|
|
memcpy(ptSpinandInfo, &pSpiNandDrv->tSpinandInfo, sizeof(SPINAND_FLASH_INFO_t));
|
|
|
|
//search MBOOT partition in partinfo
|
|
|
|
if(pSpiNandDrv->u8_HasPNI == 1)
|
|
{
|
|
for(u8_i=0 ; u8_i<pPartInfo->u16_PartCnt ; u8_i++)
|
|
{
|
|
if(pPartInfo->records[u8_i].u16_PartType == MTD_LOGI_PART)
|
|
{
|
|
u32_MBootBegin = pPartInfo->records[u8_i].u16_StartBlk;
|
|
u32_MBootEnd = pPartInfo->records[u8_i].u16_StartBlk
|
|
+ pPartInfo->records[u8_i].u16_BlkCnt
|
|
+ pPartInfo->records[u8_i].u16_BackupBlkCnt;
|
|
break;
|
|
}
|
|
}
|
|
if(u8_i == pPartInfo->u16_PartCnt)
|
|
{
|
|
printk(KERN_NOTICE"ERROR: Partition info does not contain MBOOT partition\n");
|
|
return -1;
|
|
}
|
|
|
|
//search sboot uboot/ HashX location for update nni infomation
|
|
|
|
if(pSpiNandDrv->tSpinandInfo.u8_BL0PBA != 0) //for bl uboot
|
|
{
|
|
bl_count = 0;
|
|
//search bl location in MBOOT PARTITION
|
|
for(u32_BlkIdx=u32_MBootBegin ; u32_BlkIdx<u32_MBootEnd ; u32_BlkIdx++)
|
|
{
|
|
u32_Err = MDrv_SPINAND_Read(u32_BlkIdx*pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt,
|
|
pSpiNandDrv->pu8_pagebuf, pSpiNandDrv->pu8_sparebuf);
|
|
if(u32_Err!=ERR_SPINAND_SUCCESS || pSpiNandDrv->pu8_sparebuf[0]!=0xFF)
|
|
continue;
|
|
|
|
if(!MDrv_SPINAND_CheckAll0xFF(pSpiNandDrv->pu8_pagebuf, pSpiNandDrv->tSpinandInfo.u16_PageByteCnt))
|
|
{
|
|
if(bl_count == 0)
|
|
ptSpinandInfo->u8_BL0PBA = pSpiNandDrv->tSpinandInfo.u8_BL0PBA = (U8)u32_BlkIdx;
|
|
else if(bl_count == 1)
|
|
{
|
|
ptSpinandInfo->u8_BL1PBA = pSpiNandDrv->tSpinandInfo.u8_BL1PBA = (U8)u32_BlkIdx;
|
|
bl_count ++;
|
|
break;
|
|
}
|
|
bl_count ++;
|
|
}
|
|
}
|
|
|
|
printk(KERN_NOTICE"BL0_PBA %X, BL1_PBA %X\n", pSpiNandDrv->tSpinandInfo.u8_BL0PBA, pSpiNandDrv->tSpinandInfo.u8_BL1PBA);
|
|
if(bl_count != 2)
|
|
{
|
|
printk(KERN_NOTICE"WARNING: there is no two sboots in SPI NAND Flash, Please Reupgrade Sboot\n");
|
|
return -1;
|
|
}
|
|
|
|
if(pSpiNandDrv->tSpinandInfo.u8_UBOOTPBA != 0)
|
|
{
|
|
bl_count = 0;
|
|
for(/*u32_BlkIdx = u32_MBootBegin*/; u32_BlkIdx < u32_MBootEnd; u32_BlkIdx ++)
|
|
{
|
|
u32_Err = MDrv_SPINAND_Read(u32_BlkIdx*pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt,
|
|
pSpiNandDrv->pu8_pagebuf, pSpiNandDrv->pu8_sparebuf);
|
|
if(u32_Err!=ERR_SPINAND_SUCCESS || pSpiNandDrv->pu8_sparebuf[0]!=0xFF)
|
|
continue;
|
|
|
|
if(((U32 *)pSpiNandDrv->pu8_pagebuf)[0x7] == 0x0000B007)
|
|
{
|
|
if(bl_count == 1)
|
|
{
|
|
ptSpinandInfo->u8_UBOOTPBA = pSpiNandDrv->tSpinandInfo.u8_UBOOTPBA = (U8)u32_BlkIdx;
|
|
bl_count ++;
|
|
break;
|
|
}
|
|
bl_count ++;
|
|
}
|
|
}
|
|
if(bl_count != 2)
|
|
{
|
|
printk(KERN_NOTICE"WARNING: there is no two Mboots in SPI NAND Flash, Please Reupgrade Mboot\n");
|
|
return -1;
|
|
}
|
|
|
|
printk(KERN_NOTICE"UBOOTPBA %X\n", pSpiNandDrv->tSpinandInfo.u8_UBOOTPBA);
|
|
}
|
|
}
|
|
else if(pSpiNandDrv->tSpinandInfo.u8_HashPBA[0][0] != 0) //for hash
|
|
{
|
|
bl_count = 0;
|
|
//search bl location in MBOOT PARTITION
|
|
for(u32_BlkIdx = u32_MBootBegin; u32_BlkIdx < u32_MBootEnd; u32_BlkIdx ++)
|
|
{
|
|
u32_Err = MDrv_SPINAND_Read(u32_BlkIdx*pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt,
|
|
pSpiNandDrv->pu8_pagebuf, pSpiNandDrv->pu8_sparebuf);
|
|
if(u32_Err!=ERR_SPINAND_SUCCESS || pSpiNandDrv->pu8_sparebuf[0]!=0xFF)
|
|
continue;
|
|
if(!MDrv_SPINAND_CheckAll0xFF(pSpiNandDrv->pu8_pagebuf, pSpiNandDrv->tSpinandInfo.u16_PageByteCnt))
|
|
{
|
|
ptSpinandInfo->u8_HashPBA[bl_count>>1][bl_count&1] = pSpiNandDrv->tSpinandInfo.u8_HashPBA[bl_count>>1][bl_count&1] = (U8)u32_BlkIdx;
|
|
if(++bl_count == 4)
|
|
break;
|
|
}
|
|
}
|
|
|
|
printk(KERN_NOTICE"HASH00_PBA %X, HASH01_PBA %X\n", pSpiNandDrv->tSpinandInfo.u8_HashPBA[0][0], gtSpiNandDrv.tSpinandInfo.u8_HashPBA[0][1]);
|
|
printk(KERN_NOTICE"HASH10_PBA %X, HASH11_PBA %X\n", pSpiNandDrv->tSpinandInfo.u8_HashPBA[1][0], gtSpiNandDrv.tSpinandInfo.u8_HashPBA[1][1]);
|
|
if(bl_count != 4)
|
|
{
|
|
printk(KERN_NOTICE"WARNING: there is no two sboots in SPI NAND Flash, Please Reupgrade Sboot\n");
|
|
return -1;
|
|
}
|
|
|
|
bl_count = 0;
|
|
for(u32_BlkIdx = pSpiNandDrv->tSpinandInfo.u8_HashPBA[1][1]+1; u32_BlkIdx < u32_MBootEnd; u32_BlkIdx ++)
|
|
{
|
|
u32_Err = MDrv_SPINAND_Read(u32_BlkIdx*pSpiNandDrv->tSpinandInfo.u16_BlkPageCnt,
|
|
pSpiNandDrv->pu8_pagebuf, pSpiNandDrv->pu8_sparebuf);
|
|
if(u32_Err!=ERR_SPINAND_SUCCESS || pSpiNandDrv->pu8_sparebuf[0]!=0xFF)
|
|
continue;
|
|
|
|
if(((U32 *)pSpiNandDrv->pu8_pagebuf)[0x7] == 0x0000B007)
|
|
{
|
|
ptSpinandInfo->u8_HashPBA[2][bl_count] = pSpiNandDrv->tSpinandInfo.u8_HashPBA[2][bl_count] = (U8)u32_BlkIdx;
|
|
if(++bl_count == 2)
|
|
break;
|
|
}
|
|
}
|
|
if(bl_count != 2)
|
|
{
|
|
printk(KERN_NOTICE"WARNING: there is no two Mboots in SPI NAND Flash, Please Reupgrade Mboot\n");
|
|
return -1;
|
|
}
|
|
|
|
printk(KERN_NOTICE"HASH20_PBA %X, HASH21_PBA %X\n", pSpiNandDrv->tSpinandInfo.u8_HashPBA[2][0], gtSpiNandDrv.tSpinandInfo.u8_HashPBA[2][1]);
|
|
}
|
|
}
|
|
|
|
u32_Err = MDrv_SPINAND_WriteCIS_for_ROM(pSpiNandInfoTag);
|
|
|
|
free(pSpiNandInfoTag);
|
|
|
|
return u32_Err;
|
|
}
|
|
#endif
|
|
|
|
|
|
#if 0
|
|
U32 MDrv_SPINAND_WriteBlkByteOffset(U8 *pu8_DestAddr, U16 u16_PBA, U32 u32_StartByte, U32 u32_ByteCnt)
|
|
{
|
|
#if 1
|
|
return ERR_SPINAND_W_FAIL;
|
|
#else
|
|
NAND_DRIVER *pNandDrv = drvNAND_get_DrvContext_address();
|
|
U8 *au8_PageBuf = (U8*)pNandDrv->PlatCtx_t.pu8_PageDataBuf;
|
|
U8 *au8_SpareBuf = (U8*)pNandDrv->PlatCtx_t.pu8_PageSpareBuf;
|
|
U32 u32_Err;
|
|
//MBBS_INFO_t* SPAREINFO =(MBBS_INFO_t*) pNandDrv->PlatCtx_t.pu8_PageSpareBuf;
|
|
U32 u32_SrcPageIdx, u32_BakPageIdx;
|
|
U16 u16_PageCnt;
|
|
U16 u16_ByteCntRead;
|
|
U16 u16_ByteIdxInPage;
|
|
U16 u16_i;
|
|
U16 u16_LastWrittenPage = 0;
|
|
U16 u16_BakBlkIdx;
|
|
U8 u8_GoodBlkCnt;
|
|
U16 u16_BlkPageCnt;
|
|
U16 *pu16_BlkPBA = (U16 *)(pNandDrv->PlatCtx_t.pu8_PageSpareBuf + pNandDrv->u16_SectorSpareByteCnt);
|
|
|
|
#if defined(FCIE_LFSR) && FCIE_LFSR
|
|
if(pNandDrv->u8_RequireRandomizer)
|
|
{
|
|
NC_DisableLFSR();
|
|
}
|
|
#endif
|
|
|
|
u16_BlkPageCnt = pNandDrv->u16_BlkPageCnt;
|
|
if(pNandDrv->u8_CellType == 1) // MLC
|
|
u16_BlkPageCnt = u16_BlkPageCnt>>1;
|
|
|
|
/* sector size from AP is 512 Bytes, not NAND sector size */
|
|
nand_debug(UNFD_DEBUG_LEVEL_HIGH, 1, "BlkIdx:%d, BlkNo:%d, StartByte:0x%X, ByteCnt:0x%X\n", (int)u16_PBA, (int)u16_LBA, (int)u32_StartByte, (int)u32_ByteCnt);
|
|
|
|
/* Find physical Backup BlkIdx in CIS remain block */
|
|
u16_BakBlkIdx = 9;
|
|
u8_GoodBlkCnt = 0;
|
|
while(1)
|
|
{
|
|
if(!drvNAND_IsGoodBlk(u16_BakBlkIdx))
|
|
{
|
|
nand_debug(UNFD_DEBUG_LEVEL_WARNING, 1, "Skip bad blk: 0x%04x\n", u16_BakBlkIdx);
|
|
}
|
|
else
|
|
{
|
|
if(++u8_GoodBlkCnt == 1)
|
|
break;
|
|
}
|
|
|
|
if((--u16_BakBlkIdx) < 5)
|
|
{
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "too many bad block\n");
|
|
return UNFD_ST_ERR_LACK_BLK;
|
|
}
|
|
}
|
|
nand_debug(UNFD_DEBUG_LEVEL_HIGH, 1, "u16_BakBlkIdx:%d\n", u16_BakBlkIdx);
|
|
|
|
//nand_debug(UNFD_DEBUG_LEVEL_WARNING, 1, "erase u16_BakBlkIdx:%d\n", u16_BakBlkIdx);
|
|
|
|
// erase bak block
|
|
u32_Err = drvNAND_ErasePhyBlk(u16_BakBlkIdx);
|
|
if (u32_Err != UNFD_ST_SUCCESS) {
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Erase Blk 0x%04x failed with EC: 0x%08lx\n",
|
|
u16_BakBlkIdx, u32_Err);
|
|
drvNAND_MarkBadBlk(u16_BakBlkIdx);
|
|
return u32_Err;
|
|
}
|
|
|
|
//copy data from src block to backup block before the startbyte
|
|
for(u16_i=0 ; u16_i<(u32_StartByte>>pNandDrv->u8_PageByteCntBits) ; u16_i++)
|
|
{
|
|
u32_SrcPageIdx = (u16_PBA << pNandDrv->u8_BlkPageCntBits) + ga_tPairedPageMap[u16_i].u16_LSB;
|
|
|
|
//nand_debug(UNFD_DEBUG_LEVEL_WARNING, 1, "copy data before start byte read page :0x%X\n", u32_SrcPageIdx);
|
|
u32_Err = NC_ReadPages(u32_SrcPageIdx, au8_PageBuf, au8_SpareBuf, 1);
|
|
if (u32_Err != UNFD_ST_SUCCESS)
|
|
{
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Reading page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_SrcPageIdx, u32_Err);
|
|
|
|
return u32_Err;
|
|
}
|
|
// SPAREINFO->u8_BadBlkMarker = 0xFF;
|
|
// SPAREINFO->u16_BackupPBA = u16_PBA;
|
|
// au8_SpareBuf[3] = 0x36;
|
|
// au8_SpareBuf[4] = 0x97;
|
|
|
|
au8_SpareBuf[0] = 0xFF;
|
|
*pu16_BlkPBA = u16_PBA;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 2] = 0x36;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 2 + 1] = 0x97;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 3] = 0xA1;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 3 + 1] = 1;
|
|
u32_BakPageIdx = (u16_BakBlkIdx << pNandDrv->u8_BlkPageCntBits) + ga_tPairedPageMap[u16_i].u16_LSB;
|
|
//nand_debug(UNFD_DEBUG_LEVEL_WARNING, 1, "write page :0x%X\n", u32_BakPageIdx);
|
|
|
|
u32_Err = NC_WritePages(u32_BakPageIdx, au8_PageBuf, au8_SpareBuf, 1);
|
|
if (u32_Err != UNFD_ST_SUCCESS)
|
|
{
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Writing page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_BakPageIdx, u32_Err);
|
|
drvNAND_MarkBadBlk(u16_BakBlkIdx);
|
|
return u32_Err;
|
|
}
|
|
memset(au8_PageBuf, 0xFF, pNandDrv->u16_PageByteCnt);
|
|
|
|
u32_Err = drvNAND_WriteDummyToMSBPage(u16_i, (u16_BakBlkIdx << pNandDrv->u8_BlkPageCntBits), au8_PageBuf, au8_SpareBuf, NULL);
|
|
if(u32_Err != UNFD_ST_SUCCESS)
|
|
{
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Writing page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_BakPageIdx, u32_Err);
|
|
return u32_Err;
|
|
}
|
|
u16_LastWrittenPage = u16_i;
|
|
}
|
|
|
|
/* Read unaligned Byte first */
|
|
if( u32_StartByte & pNandDrv->u16_PageByteCntMask)
|
|
{
|
|
u32_SrcPageIdx = (u16_PBA << pNandDrv->u8_BlkPageCntBits) + ga_tPairedPageMap[(u32_StartByte>>pNandDrv->u8_PageByteCntBits)].u16_LSB;
|
|
|
|
//nand_debug(UNFD_DEBUG_LEVEL_WARNING, 1, "unaligned byte first read page :0x%X\n", u32_SrcPageIdx);
|
|
u32_Err = NC_ReadPages(u32_SrcPageIdx, au8_PageBuf, au8_SpareBuf, 1);
|
|
if (u32_Err != UNFD_ST_SUCCESS) {
|
|
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Reading page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_SrcPageIdx, u32_Err);
|
|
|
|
return u32_Err;
|
|
}
|
|
u16_ByteIdxInPage = u32_StartByte & pNandDrv->u16_PageByteCntMask;
|
|
u16_ByteCntRead = (u32_ByteCnt > ((U32)pNandDrv->u16_PageByteCnt-(U32)u16_ByteIdxInPage)) ? ((U32)pNandDrv->u16_PageByteCnt-(U32)u16_ByteIdxInPage) : (u32_ByteCnt);
|
|
|
|
memcpy((au8_PageBuf+u16_ByteIdxInPage), pu8_DestAddr, u16_ByteCntRead);
|
|
u32_BakPageIdx = (u16_BakBlkIdx << pNandDrv->u8_BlkPageCntBits) + ga_tPairedPageMap[(u32_StartByte>>pNandDrv->u8_PageByteCntBits)].u16_LSB;
|
|
|
|
// SPAREINFO->u8_BadBlkMarker = 0xFF;
|
|
// SPAREINFO->u16_BackupPBA = u16_PBA;
|
|
// au8_SpareBuf[3] = 0x36;
|
|
// au8_SpareBuf[4] = 0x97;
|
|
|
|
au8_SpareBuf[0] = 0xFF;
|
|
*pu16_BlkPBA = u16_PBA;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 2] = 0x36;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 2 + 1] = 0x97;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 3] = 0xA1;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 3 + 1] = 1;
|
|
//nand_debug(UNFD_DEBUG_LEVEL_WARNING, 1, "write page :0x%X\n", u32_BakPageIdx);
|
|
u32_Err = NC_WritePages(u32_BakPageIdx, au8_PageBuf, au8_SpareBuf, 1);
|
|
if (u32_Err != UNFD_ST_SUCCESS) {
|
|
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Writing page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_BakPageIdx, u32_Err);
|
|
drvNAND_MarkBadBlk(u16_BakBlkIdx);
|
|
return u32_Err;
|
|
}
|
|
|
|
memset(au8_PageBuf, 0xFF, pNandDrv->u16_PageByteCnt);
|
|
u32_Err = drvNAND_WriteDummyToMSBPage((u32_StartByte>>pNandDrv->u8_PageByteCntBits), (u16_BakBlkIdx << pNandDrv->u8_BlkPageCntBits), au8_PageBuf, au8_SpareBuf, NULL);
|
|
if(u32_Err != UNFD_ST_SUCCESS)
|
|
{
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Writing page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_BakPageIdx, u32_Err);
|
|
return u32_Err;
|
|
}
|
|
|
|
pu8_DestAddr += u16_ByteCntRead;
|
|
u32_StartByte += u16_ByteCntRead;
|
|
u32_ByteCnt -= u16_ByteCntRead;
|
|
u16_LastWrittenPage = (u32_StartByte>>pNandDrv->u8_PageByteCntBits);
|
|
}
|
|
|
|
/* Read aligned sectors then */
|
|
// SPAREINFO->u8_BadBlkMarker = 0xFF;
|
|
// SPAREINFO->u16_BackupPBA = u16_PBA;
|
|
// au8_SpareBuf[3] = 0x36;
|
|
// au8_SpareBuf[4] = 0x97;
|
|
|
|
au8_SpareBuf[0] = 0xFF;
|
|
*pu16_BlkPBA = u16_PBA;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 2] = 0x36;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 2 + 1] = 0x97;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 3] = 0xA1;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 3 + 1] = 1;
|
|
|
|
u32_BakPageIdx = (u16_BakBlkIdx << pNandDrv->u8_BlkPageCntBits) + ga_tPairedPageMap[(u32_StartByte>>pNandDrv->u8_PageByteCntBits)].u16_LSB;
|
|
u16_PageCnt = (u32_ByteCnt>>pNandDrv->u8_PageByteCntBits);
|
|
while (u16_PageCnt)
|
|
{
|
|
|
|
//nand_debug(UNFD_DEBUG_LEVEL_WARNING, 1, "aligned write page :0x%X\n", u32_BakPageIdx);
|
|
u32_Err = NC_WritePages(u32_BakPageIdx, pu8_DestAddr, au8_SpareBuf, 1);
|
|
if (u32_Err != UNFD_ST_SUCCESS) {
|
|
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Writing page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_BakPageIdx, u32_Err);
|
|
drvNAND_MarkBadBlk(u16_BakBlkIdx);
|
|
return u32_Err;
|
|
}
|
|
|
|
memset(au8_PageBuf, 0xFF, pNandDrv->u16_PageByteCnt);
|
|
u32_Err = drvNAND_WriteDummyToMSBPage((u32_StartByte>>pNandDrv->u8_PageByteCntBits), (u16_BakBlkIdx << pNandDrv->u8_BlkPageCntBits), au8_PageBuf, au8_SpareBuf, NULL);
|
|
if(u32_Err != UNFD_ST_SUCCESS)
|
|
{
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Writing page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_BakPageIdx, u32_Err);
|
|
return u32_Err;
|
|
}
|
|
|
|
u16_LastWrittenPage = u32_BakPageIdx -(u16_BakBlkIdx << pNandDrv->u8_BlkPageCntBits);
|
|
pu8_DestAddr += pNandDrv->u16_PageByteCnt;
|
|
u16_PageCnt--;
|
|
u32_StartByte += pNandDrv->u16_PageByteCnt;
|
|
u32_BakPageIdx = (u16_BakBlkIdx << pNandDrv->u8_BlkPageCntBits) + ga_tPairedPageMap[(u32_StartByte>>pNandDrv->u8_PageByteCntBits)].u16_LSB;
|
|
u32_ByteCnt -= pNandDrv->u16_PageByteCnt;
|
|
}
|
|
|
|
/* Read remaining unaligned sectors finally */
|
|
if( u32_ByteCnt)
|
|
{
|
|
u32_SrcPageIdx = (u16_PBA << pNandDrv->u8_BlkPageCntBits) + ga_tPairedPageMap[(u32_StartByte>>pNandDrv->u8_PageByteCntBits)].u16_LSB;
|
|
//nand_debug(UNFD_DEBUG_LEVEL_WARNING, 1, "remaining unaligned read page :0x%X\n", u32_SrcPageIdx);
|
|
|
|
u32_Err = NC_ReadPages(u32_SrcPageIdx, au8_PageBuf, au8_SpareBuf, 1);
|
|
if (u32_Err != UNFD_ST_SUCCESS) {
|
|
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Reading page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_SrcPageIdx, u32_Err);
|
|
|
|
return u32_Err;
|
|
}
|
|
|
|
// SPAREINFO->u8_BadBlkMarker = 0xFF;
|
|
// SPAREINFO->u16_BackupPBA = u16_PBA;
|
|
// au8_SpareBuf[3] = 0x36;
|
|
// au8_SpareBuf[4] = 0x97;
|
|
|
|
au8_SpareBuf[0] = 0xFF;
|
|
*pu16_BlkPBA = u16_PBA;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 2] = 0x36;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 2 + 1] = 0x97;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 3] = 0xA1;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 3 + 1] = 1;
|
|
|
|
memcpy(au8_PageBuf, pu8_DestAddr, u32_ByteCnt);
|
|
u32_BakPageIdx = (u16_BakBlkIdx << pNandDrv->u8_BlkPageCntBits) + ga_tPairedPageMap[(u32_StartByte>>pNandDrv->u8_PageByteCntBits)].u16_LSB;
|
|
//nand_debug(UNFD_DEBUG_LEVEL_WARNING, 1, "write page :0x%X\n", u32_BakPageIdx);
|
|
|
|
u32_Err = NC_WritePages(u32_BakPageIdx, au8_PageBuf, au8_SpareBuf, 1);
|
|
if (u32_Err != UNFD_ST_SUCCESS) {
|
|
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Writing page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_BakPageIdx, u32_Err);
|
|
drvNAND_MarkBadBlk(u16_BakBlkIdx);
|
|
return u32_Err;
|
|
}
|
|
|
|
memset(au8_PageBuf, 0xFF, pNandDrv->u16_PageByteCnt);
|
|
u32_Err = drvNAND_WriteDummyToMSBPage((u32_StartByte>>pNandDrv->u8_PageByteCntBits), (u16_BakBlkIdx << pNandDrv->u8_BlkPageCntBits), au8_PageBuf, au8_SpareBuf, NULL);
|
|
if(u32_Err != UNFD_ST_SUCCESS)
|
|
{
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Writing page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_BakPageIdx, u32_Err);
|
|
return u32_Err;
|
|
}
|
|
|
|
u16_LastWrittenPage = (u32_StartByte>>pNandDrv->u8_PageByteCntBits);
|
|
}
|
|
|
|
//copy remain data from PBA to Backup block
|
|
for(u16_i=(u16_LastWrittenPage+1) ; u16_i<u16_BlkPageCnt; u16_i++)
|
|
{
|
|
u32_SrcPageIdx = (u16_PBA << pNandDrv->u8_BlkPageCntBits) + ga_tPairedPageMap[u16_i].u16_LSB;
|
|
//nand_debug(UNFD_DEBUG_LEVEL_WARNING, 1, "remain data read page :0x%X\n", u32_SrcPageIdx);
|
|
|
|
u32_Err = NC_ReadPages(u32_SrcPageIdx, au8_PageBuf, au8_SpareBuf, 1);
|
|
if (u32_Err != UNFD_ST_SUCCESS)
|
|
{
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Reading page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_SrcPageIdx, u32_Err);
|
|
|
|
return u32_Err;
|
|
}
|
|
// SPAREINFO->u8_BadBlkMarker = 0xFF;
|
|
// SPAREINFO->u16_BackupPBA = u16_PBA;
|
|
// au8_SpareBuf[3] = 0x36;
|
|
// au8_SpareBuf[4] = 0x97;
|
|
|
|
au8_SpareBuf[0] = 0xFF;
|
|
*pu16_BlkPBA = u16_PBA;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 2] = 0x36;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 2 + 1] = 0x97;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 3] = 0xA1;
|
|
au8_SpareBuf[pNandDrv->u16_SectorSpareByteCnt * 3 + 1] = 1;
|
|
|
|
u32_BakPageIdx = (u16_BakBlkIdx << pNandDrv->u8_BlkPageCntBits) + ga_tPairedPageMap[u16_i].u16_LSB;
|
|
|
|
//nand_debug(UNFD_DEBUG_LEVEL_WARNING, 1, "write page :0x%X\n", u32_BakPageIdx);
|
|
u32_Err = NC_WritePages(u32_BakPageIdx, au8_PageBuf, au8_SpareBuf, 1);
|
|
if (u32_Err != UNFD_ST_SUCCESS)
|
|
{
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Writing page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_BakPageIdx, u32_Err);
|
|
drvNAND_MarkBadBlk(u16_BakBlkIdx);
|
|
return u32_Err;
|
|
}
|
|
|
|
memset(au8_PageBuf, 0xFF, pNandDrv->u16_PageByteCnt);
|
|
u32_Err = drvNAND_WriteDummyToMSBPage(u16_i, (u16_BakBlkIdx << pNandDrv->u8_BlkPageCntBits), au8_PageBuf, au8_SpareBuf, NULL);
|
|
if(u32_Err != UNFD_ST_SUCCESS)
|
|
{
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Writing page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_BakPageIdx, u32_Err);
|
|
return u32_Err;
|
|
}
|
|
|
|
}
|
|
|
|
// erase src block
|
|
|
|
//nand_debug(UNFD_DEBUG_LEVEL_WARNING, 1, "erase src block :0x%X\n", u16_PBA);
|
|
u32_Err = drvNAND_ErasePhyBlk(u16_PBA);
|
|
if (u32_Err != UNFD_ST_SUCCESS) {
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Erase Blk 0x%04x failed with EC: 0x%08x\n",
|
|
(unsigned int)u16_PBA, (unsigned int)u32_Err);
|
|
drvNAND_MarkBadBlk(u16_PBA);
|
|
return u32_Err;
|
|
}
|
|
|
|
// copy bak to src
|
|
for(u16_i=0 ; u16_i<u16_BlkPageCnt; u16_i++)
|
|
{
|
|
u32_BakPageIdx = (u16_BakBlkIdx << pNandDrv->u8_BlkPageCntBits) + ga_tPairedPageMap[u16_i].u16_LSB;
|
|
//nand_debug(UNFD_DEBUG_LEVEL_WARNING, 1, "read page :0x%X\n", u32_BakPageIdx);
|
|
|
|
u32_Err = NC_ReadPages(u32_BakPageIdx, au8_PageBuf, au8_SpareBuf, 1);
|
|
if (u32_Err != UNFD_ST_SUCCESS)
|
|
{
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Reading page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_BakPageIdx, u32_Err);
|
|
|
|
return u32_Err;
|
|
}
|
|
|
|
u32_SrcPageIdx = (u16_PBA << pNandDrv->u8_BlkPageCntBits) + ga_tPairedPageMap[u16_i].u16_LSB;
|
|
//nand_debug(UNFD_DEBUG_LEVEL_WARNING, 1, "write page :0x%X\n", u32_SrcPageIdx);
|
|
|
|
memset(au8_SpareBuf, 0xFF, pNandDrv->u16_SpareByteCnt);
|
|
u32_Err = NC_WritePages(u32_SrcPageIdx, au8_PageBuf, au8_SpareBuf, 1);
|
|
if (u32_Err != UNFD_ST_SUCCESS)
|
|
{
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Reading page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_SrcPageIdx, u32_Err);
|
|
drvNAND_MarkBadBlk(u16_PBA);
|
|
return u32_Err;
|
|
}
|
|
|
|
memset(au8_PageBuf, 0xFF, pNandDrv->u16_PageByteCnt);
|
|
u32_Err = drvNAND_WriteDummyToMSBPage(u16_i, (u16_PBA << pNandDrv->u8_BlkPageCntBits), au8_PageBuf, au8_SpareBuf, NULL);
|
|
if(u32_Err != UNFD_ST_SUCCESS)
|
|
{
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Writing page 0x%04lx failed with EC: 0x%04lx\n",
|
|
u32_BakPageIdx, u32_Err);
|
|
return u32_Err;
|
|
}
|
|
}
|
|
|
|
// erase bak block
|
|
u32_Err = drvNAND_ErasePhyBlk(u16_BakBlkIdx);
|
|
if (u32_Err != UNFD_ST_SUCCESS) {
|
|
nand_debug(UNFD_DEBUG_LEVEL_ERROR, 1, "Erase Blk 0x%04x failed with EC: 0x%08lx\n",
|
|
u16_BakBlkIdx, u32_Err);
|
|
drvNAND_MarkBadBlk(u16_BakBlkIdx);
|
|
return u32_Err;
|
|
}
|
|
|
|
return UNFD_ST_SUCCESS;
|
|
#endif
|
|
}
|
|
#if 0
|
|
U32 MDrv_SPINAND_ReadBlkByteOffset(U8 *pu8_DestAddr, U16 u16_PBA, U32 u32_StartByte, U32 u32_ByteCnt)
|
|
{
|
|
SPI_NAND_DRIVER_t *pSpiNandDrv = (SPI_NAND_DRIVER_t*)drvSPINAND_get_DrvContext_address();
|
|
U8 *au8_PageBuf = (U8*)pSpiNandDrv->pu8_pagebuf;
|
|
U8 *au8_SpareBuf = (U8*)pSpiNandDrv->pu8_sparebuf;
|
|
U32 u32_Err;
|
|
U32 u32_PageIdx;
|
|
U16 u16_PageCnt;
|
|
U16 u16_ByteCntRead;
|
|
U16 u16_ByteInPage;
|
|
|
|
/* Read unaligned sectors first */
|
|
if( u32_StartByte & (pSpiNandDrv->tSpinandInfo.u16_PageByteCnt-1))
|
|
{
|
|
u16_ByteInPage = u32_StartByte & (pSpiNandDrv->tSpinandInfo.u16_PageByteCnt-1);
|
|
u16_ByteCntRead = u32_ByteCnt > ((U32)pSpiNandDrv->tSpinandInfo.u16_PageByteCnt-(U32)u16_ByteInPage) ? ((U32)gtSpiNandDrv.tSpinandInfo.u16_PageByteCnt-(U32)u16_ByteInPage) : (u32_ByteCnt);
|
|
u32_PageIdx = (u16_PBA << pSpiNandDrv->u8_BlkPageCntBits) + (u32_StartByte >> pSpiNandDrv->u8_PageByteCntBits);
|
|
|
|
u32_Err = MDrv_SPINAND_Read(u32_PageIdx, au8_PageBuf, au8_SpareBuf);
|
|
if (u32_Err != ERR_SPINAND_SUCCESS) {
|
|
|
|
spi_nand_err("Reading page 0x%04x failed with EC: 0x%04x\n",
|
|
(unsigned int)u32_PageIdx, (unsigned int)u32_Err);
|
|
return u32_Err;
|
|
}
|
|
|
|
memcpy(pu8_DestAddr, au8_PageBuf + u16_ByteInPage, u16_ByteCntRead);
|
|
pu8_DestAddr += u16_ByteCntRead;
|
|
u32_StartByte += u16_ByteCntRead;
|
|
u32_ByteCnt -= u16_ByteCntRead;
|
|
}
|
|
|
|
/* Read aligned sectors then */
|
|
u32_PageIdx = (u16_PBA << pSpiNandDrv->u8_BlkPageCntBits) + (u32_StartByte >> pSpiNandDrv->u8_PageByteCntBits);
|
|
u16_PageCnt = (u32_ByteCnt >> pSpiNandDrv->u8_PageByteCntBits);
|
|
|
|
while (u16_PageCnt)
|
|
{
|
|
u32_Err = MDrv_SPINAND_Read(u32_PageIdx, pu8_DestAddr, au8_SpareBuf);
|
|
if (u32_Err != ERR_SPINAND_SUCCESS) {
|
|
|
|
spi_nand_err("Reading page 0x%04x failed with EC: 0x%04x\n",
|
|
(unsigned int)u32_PageIdx, (unsigned int)u32_Err);
|
|
return u32_Err;
|
|
}
|
|
|
|
pu8_DestAddr += pSpiNandDrv->tSpinandInfo.u16_PageByteCnt;
|
|
u16_PageCnt--;
|
|
u32_StartByte += pSpiNandDrv->tSpinandInfo.u16_PageByteCnt;
|
|
u32_ByteCnt -= pSpiNandDrv->tSpinandInfo.u16_PageByteCnt;
|
|
u32_PageIdx = (u16_PBA << pSpiNandDrv->u8_BlkPageCntBits) + (u32_StartByte >> pSpiNandDrv->u8_PageByteCntBits);
|
|
|
|
}
|
|
|
|
/* Read remaining unaligned sectors finally */
|
|
if( u32_ByteCnt )
|
|
{
|
|
u32_PageIdx = (u16_PBA << pSpiNandDrv->u8_BlkPageCntBits) + (u32_StartByte >> pSpiNandDrv->u8_PageByteCntBits);
|
|
u32_Err = MDrv_SPINAND_Read(u32_PageIdx, au8_PageBuf, au8_SpareBuf);
|
|
if (u32_Err != ERR_SPINAND_SUCCESS) {
|
|
|
|
spi_nand_err("Reading page 0x%04x failed with EC: 0x%04x\n",
|
|
(unsigned int)u32_PageIdx, (unsigned int)u32_Err);
|
|
return u32_Err;
|
|
}
|
|
memcpy(pu8_DestAddr, au8_PageBuf, u32_ByteCnt);
|
|
}
|
|
return ERR_SPINAND_SUCCESS;
|
|
}
|
|
#endif
|
|
#endif
|