sdk-hwV1.3/lichee/linux-4.9/modules/nand/sun8iw15p1/phy-nand/physic/nand_scan.c

1075 lines
31 KiB
C

/*
* Copyright (c) 2007-2017 Allwinnertech Co., Ltd.
*
* 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 "nand_scan.h"
#include "../physic_common/nand_common_interface.h"
#include "spic.h"
extern struct __NandStorageInfo_t NandStorageInfo;
extern struct __NandPhyInfoPar_t DefaultNandTbl;
extern struct __NandPhyInfoPar_t GigaDeviceNandTbl;
extern struct __NandPhyInfoPar_t AtoNandTbl;
extern struct __NandPhyInfoPar_t MicronNandTbl;
extern struct __NandPhyInfoPar_t WinbondNandTbl;
extern struct __NandPhyInfoPar_t MxicNandTbl;
extern __u32 storage_type;
extern struct _boot_info *phyinfo_buf;
__u32 NandIDNumber = 0xffffff;
__u32 NandSupportTwoPlaneOp;
__u32 CurrentDriverTwoPlaneOPCfg;
__u32 spinand_get_twoplane_flag(void)
{
return SUPPORT_MULTI_PROGRAM ? 1 : 0;
}
__u32 SPINAND_GetLsbblksize(void)
{
return (NandStorageInfo.SectorCntPerPage * 512 *
NandStorageInfo.PageCntPerPhyBlk);
}
__u32 SPINAND_GetLsbPages(void)
{
return NandStorageInfo.PageCntPerPhyBlk;
}
__u32 SPINAND_UsedLsbPages(void)
{
return 0;
}
u32 SPINAND_GetPageNo(u32 lsb_page_no)
{
return lsb_page_no;
}
__u32 NAND_GetPlaneCnt(void)
{
return NandStorageInfo.PlaneCntPerDie;
}
__u32 SPINAND_GetPageSize(void)
{
return (NandStorageInfo.SectorCntPerPage * 512);
}
__u32 SPINAND_GetPhyblksize(void)
{
return (NandStorageInfo.SectorCntPerPage * 512 *
NandStorageInfo.PageCntPerPhyBlk);
}
__u32 SPINAND_GetPageCntPerBlk(void)
{
return NandStorageInfo.PageCntPerPhyBlk;
}
__u32 SPINAND_GetBlkCntPerChip(void)
{
return NandStorageInfo.BlkCntPerDie * NandStorageInfo.DieCntPerChip;
}
__u32 SPINAND_GetChipCnt(void)
{
return NandStorageInfo.ChipCnt;
}
__u32 NAND_GetChipConnect(void)
{
return NandStorageInfo.ChipConnectInfo;
}
__u32 NAND_GetBadBlockFlagPos(void)
{
return 2;
}
__u32 NAND_GetFrequencePar(void)
{
return NandStorageInfo.FrequencePar;
}
__s32 NAND_SetFrequencePar(__u32 FrequencePar)
{
NandStorageInfo.FrequencePar = (__u8)FrequencePar;
return 0;
}
__s32 NAND_GetBlkCntOfDie(void)
{
return NandStorageInfo.BlkCntPerDie;
}
__u32 NAND_GetOperationOpt(void)
{
return NandStorageInfo.OperationOpt;
}
__u32 NAND_GetNandVersion(void)
{
__u32 nand_version;
nand_version = 0;
nand_version |= 0xff;
nand_version |= 0x00 << 8;
nand_version |= NAND_VERSION_0 << 16;
nand_version |= NAND_VERSION_1 << 24;
return nand_version;
}
__u32 NAND_GetVersion(__u8 *nand_version)
{
__u32 ret;
ret = NAND_GetNandVersion();
*(__u32 *)nand_version = ret;
return ret;
}
__u32 NAND_GetNandVersionDate(void)
{
return 0x20121209;
}
#if 0
__s32 NAND_GetParam(boot_spinand_para_t *nand_param)
{
__u32 i;
nand_param->ChipCnt = NandStorageInfo.ChipCnt;
nand_param->ChipConnectInfo = NandStorageInfo.ChipConnectInfo;
nand_param->ConnectMode = NandStorageInfo.ConnectMode;
nand_param->BankCntPerChip = NandStorageInfo.BankCntPerChip;
nand_param->DieCntPerChip = NandStorageInfo.DieCntPerChip;
nand_param->PlaneCntPerDie = NandStorageInfo.PlaneCntPerDie;
nand_param->SectorCntPerPage = NandStorageInfo.SectorCntPerPage;
nand_param->PageCntPerPhyBlk = NandStorageInfo.PageCntPerPhyBlk;
nand_param->BlkCntPerDie = NandStorageInfo.BlkCntPerDie;
nand_param->OperationOpt = NandStorageInfo.OperationOpt;
nand_param->FrequencePar = NandStorageInfo.FrequencePar;
nand_param->SpiMode = NandStorageInfo.SpiMode;
nand_param->MaxEraseTimes = NandStorageInfo.MaxEraseTimes;
nand_param->MultiPlaneBlockOffset = NandStorageInfo.MultiPlaneBlockOffset;
nand_param->pagewithbadflag = NandStorageInfo.pagewithbadflag;
nand_param->EccLimitBits = NandStorageInfo.EccLimitBits;
nand_param->MaxEccBits = NandStorageInfo.MaxEccBits;
// nand_param->spi_nand_function = NandStorageInfo.spi_nand_function;
// spic_set_trans_mode(0, NandStorageInfo.SpiMode);
for (i = 0; i < 8; i++)
nand_param->NandChipId[i] = NandStorageInfo.NandChipId[i];
return 0;
}
#endif
__s32 NAND_GetFlashInfo(boot_flash_info_t *param)
{
param->chip_cnt = NandStorageInfo.ChipCnt;
param->blk_cnt_per_chip =
NandStorageInfo.BlkCntPerDie * NandStorageInfo.DieCntPerChip;
param->blocksize = SECTOR_CNT_OF_SINGLE_PAGE * PAGE_CNT_OF_PHY_BLK;
param->pagesize = SECTOR_CNT_OF_SINGLE_PAGE;
param->pagewithbadflag = NandStorageInfo.pagewithbadflag;
return 0;
}
__s32 _GetOldPhysicArch(void *phy_arch, __u32 *good_blk_no)
{
__s32 ret, ret2 = 0;
__u32 b, chip = 0;
__u32 start_blk = 20, blk_cnt = 30;
__u8 oob[32];
struct __NandStorageInfo_t *parch;
struct boot_physical_param nand_op;
// parch = (struct __NandStorageInfo_t *)PHY_TMP_PAGE_CACHE;
parch = (struct __NandStorageInfo_t *)MALLOC(32 * 1024);
if (!parch) {
PRINT("%s,malloc fail\n", __func__);
ret2 = -1;
goto EXIT;
}
for (b = start_blk; b < start_blk + blk_cnt; b++) {
nand_op.chip = chip;
nand_op.block = b;
nand_op.page = 0;
nand_op.sectorbitmap = FULL_BITMAP_OF_SINGLE_PAGE;
nand_op.mainbuf = (void *)parch;
nand_op.oobbuf = oob;
ret =
PHY_SimpleRead(&nand_op); // PHY_SimpleRead_CurCH(&nand_op);
PHY_DBG("_GetOldPhysicArch: chip %d, block %d, page 0, oob: "
"0x%x, 0x%x, 0x%x, 0x%x\n",
nand_op.chip, nand_op.block, oob[0], oob[1], oob[2],
oob[3]);
if (ret >= 0) {
if (oob[0] == 0x00) {
if ((oob[1] == 0x50) && (oob[2] == 0x48) &&
(oob[3] == 0x59) && (oob[4] == 0x41) &&
(oob[5] == 0x52) && (oob[6] == 0x43) &&
(oob[7] == 0x48)) {
//*((struct __NandStorageInfo_t
//*)phy_arch) = *parch;
if ((parch->PlaneCntPerDie != 1) &&
(parch->PlaneCntPerDie != 2)) {
PHY_DBG("_GetOldPhysicArch: "
"get old physic arch "
"ok,but para error: "
"0x%x 0x%x!\n",
parch->OperationOpt,
parch->PlaneCntPerDie);
} else {
MEMCPY(
phy_arch, parch,
sizeof(
struct
__NandStorageInfo_t));
PHY_DBG("_GetOldPhysicArch: "
"get old physic arch "
"ok, 0x%x 0x%x!\n",
parch->OperationOpt,
parch->PlaneCntPerDie);
ret2 = 1;
break;
}
} else {
PHY_DBG("_GetOldPhysicArch: mark bad "
"block!\n");
}
} else if (oob[0] == 0xff) {
PHY_DBG("_GetOldPhysicArch: find a good block, "
"but no physic arch info.\n");
ret2 = 2; // blank page
break;
} else {
PHY_DBG("_GetOldPhysicArch: unkonwn1!\n");
}
} else {
if (oob[0] == 0xff) {
PHY_DBG("_GetOldPhysicArch: blank block!\n");
ret2 = 2;
break;
} else if (oob[0] == 0) {
PHY_DBG("_GetOldPhysicArch: bad block!\n");
} else {
PHY_DBG("_GetOldPhysicArch: unkonwn2!\n");
}
}
}
if (b == (start_blk + blk_cnt)) {
ret2 = -1;
*good_blk_no = 0;
} else
*good_blk_no = b;
EXIT:
FREE(parch, 32 * 1024);
return ret2;
}
__s32 _SetNewPhysicArch(void *phy_arch)
{
__s32 ret;
__u32 i, b, p, chip = 0;
__u32 start_blk = 20, blk_cnt = 30;
__u8 oob[32];
__u32 good_blk_no;
struct __NandStorageInfo_t *parch;
struct __NandStorageInfo_t arch_tmp = {0};
struct boot_physical_param nand_op;
// parch = (struct __NandStorageInfo_t *)PHY_TMP_PAGE_CACHE;
parch = (struct __NandStorageInfo_t *)MALLOC(32 * 1024);
/* in order to get good block, get old physic arch info */
ret = _GetOldPhysicArch(&arch_tmp, &good_blk_no);
if (ret == -1) {
/* can not find good block */
PHY_ERR("_SetNewPhysicArch: can not find good block: 12~112\n");
FREE(parch, 32 * 1024);
return ret;
}
PHY_DBG("_SetNewPhysicArch: write physic arch to blk %d...\n",
good_blk_no);
for (b = good_blk_no; b < start_blk + blk_cnt; b++) {
nand_op.chip = chip;
nand_op.block = b;
nand_op.page = 0;
nand_op.sectorbitmap = FULL_BITMAP_OF_SINGLE_PAGE;
nand_op.mainbuf = (void *)parch; // PHY_TMP_PAGE_CACHE;
nand_op.oobbuf = oob;
ret = PHY_SimpleErase(
&nand_op); // PHY_SimpleErase_CurCH(&nand_op);
if (ret < 0) {
PHY_ERR("_SetNewPhysicArch: erase chip %d, block %d "
"error\n",
nand_op.chip, nand_op.block);
for (i = 0; i < 32; i++)
oob[i] = 0x0;
for (p = 0; p < NandStorageInfo.PageCntPerPhyBlk; p++) {
nand_op.page = p;
ret = PHY_SimpleWrite(
&nand_op);//PHY_SimpleWrite_CurCH(&nand_op);
if (ret < 0) {
PHY_ERR("_SetNewPhysicArch: mark bad "
"block, write chip %d, block "
"%d, page %d error\n",
nand_op.chip, nand_op.block,
nand_op.page);
}
}
} else {
PHY_DBG("_SetNewPhysicArch: erase block %d ok.\n", b);
for (i = 0; i < 32; i++)
oob[i] = 0x88;
oob[0] = 0x00; // bad block flag
oob[1] = 0x50; // 80; //'P'
oob[2] = 0x48; // 72; //'H'
oob[3] = 0x59; // 89; //'Y'
oob[4] = 0x41; // 65; //'A'
oob[5] = 0x52; // 82; //'R'
oob[6] = 0x43; // 67; //'C'
oob[7] = 0x48; // 72; //'H'
// MEMSET(parch, 0x0, 1024);
MEMCPY(parch, phy_arch,
sizeof(struct __NandStorageInfo_t));
//*parch = *((struct __NandStorageInfo_t *)phy_arch);
for (p = 0; p < NandStorageInfo.PageCntPerPhyBlk; p++) {
nand_op.page = p;
ret = PHY_SimpleWrite(
&nand_op);//PHY_SimpleWrite_CurCH(&nand_op);
if (ret < 0) {
PHY_ERR("_SetNewPhysicArch: write chip "
"%d, block %d, page %d error\n",
nand_op.chip, nand_op.block,
nand_op.page);
FREE(parch, 32 * 1024);
return -1;
}
}
break;
}
}
PHY_DBG("_SetNewPhysicArch: ============\n");
ret = _GetOldPhysicArch(&arch_tmp, &good_blk_no);
if (ret == -1) {
/* can not find good block */
PHY_ERR("_SetNewPhysicArch: can not find good block: 12~112\n");
FREE(parch, 32 * 1024);
return ret;
}
FREE(parch, 32 * 1024);
return 0;
}
__s32 _UpdateExtMultiPlanePara(void)
{
__u32 id_number_ctl;
__u32 script_twoplane, para;
id_number_ctl = NAND_GetNandIDNumCtrl();
if (0x0 != id_number_ctl) {
if (id_number_ctl & (1U << 1)) {// bit 1, set twoplane para
para = NAND_GetNandExtPara(1);
if (0xffffffff != para) {// get script success
if (((para & 0xffffff) == NandIDNumber) ||
((para & 0xffffff) == 0xeeeeee)) {
script_twoplane = (para >> 24) & 0xff;
PHY_DBG("_UpdateExtMultiPlanePara: get "
"twoplane para from script "
"success: ",
script_twoplane);
if (script_twoplane == 1) {
PHY_DBG("%d\n",
script_twoplane);
if (NandSupportTwoPlaneOp) {
// PHY_DBG("NAND_UpdatePhyArch:
// current nand support
// two plane op!\n");
NandStorageInfo
.PlaneCntPerDie = 2;
NandStorageInfo
.OperationOpt |=
SPINAND_MULTI_READ;
NandStorageInfo
.OperationOpt |=
SPINAND_MULTI_PROGRAM;
} else {
PHY_DBG(
"_UpdateExtMultiPla"
"nePara: current "
"nand do not "
"support two plane "
"op, set to 0!\n");
NandStorageInfo
.PlaneCntPerDie = 1;
NandStorageInfo
.OperationOpt &=
~SPINAND_MULTI_READ;
NandStorageInfo
.OperationOpt &=
~SPINAND_MULTI_PROGRAM;
}
} else if (script_twoplane == 0) {
PHY_DBG("%d\n",
script_twoplane);
NandStorageInfo.PlaneCntPerDie =
1;
NandStorageInfo.OperationOpt &=
~SPINAND_MULTI_READ;
NandStorageInfo.OperationOpt &=
~SPINAND_MULTI_PROGRAM;
} else {
PHY_DBG("%d, wrong "
"parameter(0,1)\n",
script_twoplane);
return -1;
}
} else {
PHY_ERR("_UpdateExtMultiPlanePara: "
"wrong id number, 0x%x/0x%x\n",
(para & 0xffffff),
NandIDNumber);
return -1;
}
} else {
PHY_ERR("_UpdateExtMultiPlanePara: wrong two "
"plane para, 0x%x\n",
para);
return -1;
}
} else {
PHY_ERR("_UpdateExtMultiPlanePara: wrong id ctrl "
"number: %d/%d\n",
id_number_ctl, (1U << 1));
return -1;
}
} else {
PHY_ERR("_UpdateExtMultiPlanePara: no para.\n");
return -1;
}
return 0;
}
__s32 _UpdateExtAccessFreqPara(void)
{
__u32 id_number_ctl;
__u32 script_frequence, para;
id_number_ctl = NAND_GetNandIDNumCtrl();
if (0x0 != id_number_ctl) {
if (id_number_ctl & (1U << 0)) { // bit 0, set freq para
para = NAND_GetNandExtPara(0);
if (0xffffffff != para) { // get script success
if (((para & 0xffffff) == NandIDNumber) ||
((para & 0xffffff) == 0xeeeeee)) {
script_frequence = (para >> 24) & 0xff;
if ((script_frequence > 10) &&
(script_frequence < 100)) {
NandStorageInfo.FrequencePar =
script_frequence;
PHY_ERR("_UpdateExtAccessFreqPa"
"ra: update freq from "
"script, %d\n",
script_frequence);
} else {
PHY_ERR("_UpdateExtAccessFreqPa"
"ra: wrong freq, %d\n",
script_frequence);
return -1;
}
} else {
PHY_ERR("_UpdateExtAccessFreqPara: "
"wrong id number, 0x%x/0x%x\n",
(para & 0xffffff),
NandIDNumber);
return -1;
}
} else {
PHY_ERR("_UpdateExtAccessFreqPara: wrong freq "
"para, 0x%x\n",
para);
return -1;
}
} else {
PHY_ERR("_UpdateExtAccessFreqPara: wrong id ctrl "
"number, %d/%d.\n",
id_number_ctl, (1U << 0));
return -1;
}
} else {
PHY_DBG("_UpdateExtAccessFreqPara: no para.\n");
return -1;
}
return 0;
}
#if 0
__s32 NAND_UpdatePhyArch(void)
{
__s32 ret = 0;
/*
* when erase chip during update firmware, it means that we will ignore
* previous physical archtecture, erase all good blocks and write new
* data.
*
* we should write new physical architecture to block 12~12+100 for
* next update.
*/
ret = _UpdateExtMultiPlanePara();
if (ret < 0) {
if (CurrentDriverTwoPlaneOPCfg) {
NandStorageInfo.PlaneCntPerDie = 2;
NandStorageInfo.OperationOpt |= SPINAND_MULTI_READ;
NandStorageInfo.OperationOpt |= SPINAND_MULTI_PROGRAM;
} else {
NandStorageInfo.PlaneCntPerDie = 1;
NandStorageInfo.OperationOpt &= ~SPINAND_MULTI_READ;
NandStorageInfo.OperationOpt &= ~SPINAND_MULTI_PROGRAM;
}
PHY_ERR("NAND_UpdatePhyArch: get script error,"
"use current driver cfg!\n");
}
PHY_ERR("NAND_UpdatePhyArch: before set new arch: 0x%x 0x%x.\n",
NandStorageInfo.OperationOpt, NandStorageInfo.PlaneCntPerDie);
ret = _SetNewPhysicArch(&NandStorageInfo);
if (ret < 0)
PHY_ERR("NAND_UpdatePhyArch: write physic arch to nand failed!\n");
return ret;
}
#endif
__s32 NAND_ReadPhyArch(void)
{
__s32 ret = 0;
struct __NandStorageInfo_t old_storage_info = {0};
__u32 good_blk_no;
struct _spinand_config_para_info config_para;
if (is_phyinfo_empty(phyinfo_buf) != 1) {
NandStorageInfo.FrequencePar =
phyinfo_buf->storage_info.config.frequence;
if (phyinfo_buf->storage_info.config.support_two_plane == 1) {
NandStorageInfo.OperationOpt |= SPINAND_MULTI_READ;
NandStorageInfo.OperationOpt |= SPINAND_MULTI_PROGRAM;
NandStorageInfo.PlaneCntPerDie = 2;
} else {
NandStorageInfo.OperationOpt &= ~SPINAND_MULTI_READ;
NandStorageInfo.OperationOpt &= ~SPINAND_MULTI_PROGRAM;
NandStorageInfo.PlaneCntPerDie = 1;
}
if (phyinfo_buf->storage_info.config.support_dual_read == 1)
NandStorageInfo.OperationOpt |= SPINAND_DUAL_READ;
else
NandStorageInfo.OperationOpt &= ~SPINAND_DUAL_READ;
if (phyinfo_buf->storage_info.config.support_dual_write == 1)
NandStorageInfo.OperationOpt |= SPINAND_DUAL_PROGRAM;
else
NandStorageInfo.OperationOpt &= ~SPINAND_DUAL_PROGRAM;
if (phyinfo_buf->storage_info.config.support_quad_write == 1)
NandStorageInfo.OperationOpt |= SPINAND_QUAD_PROGRAM;
else
NandStorageInfo.OperationOpt &= ~SPINAND_QUAD_PROGRAM;
if (phyinfo_buf->storage_info.config.support_quad_read == 1)
NandStorageInfo.OperationOpt |= SPINAND_QUAD_READ;
else
NandStorageInfo.OperationOpt &= ~SPINAND_QUAD_READ;
return 0;
}
ret = _GetOldPhysicArch(&old_storage_info, &good_blk_no);
if (ret == 1) {
PHY_ERR("NAND_ReadPhyArch: get old physic arch ok, use old "
"cfg, now:0x%x 0x%x - old:0x%x 0x%x!\n",
NandStorageInfo.PlaneCntPerDie,
NandStorageInfo.OperationOpt,
old_storage_info.PlaneCntPerDie,
old_storage_info.OperationOpt);
NandStorageInfo.PlaneCntPerDie =
old_storage_info.PlaneCntPerDie;
if (NandStorageInfo.PlaneCntPerDie == 1) {
NandStorageInfo.OperationOpt &= ~SPINAND_MULTI_READ;
NandStorageInfo.OperationOpt &= ~SPINAND_MULTI_PROGRAM;
}
if (NandStorageInfo.PlaneCntPerDie == 2) {
NandStorageInfo.OperationOpt |= SPINAND_MULTI_READ;
NandStorageInfo.OperationOpt |= SPINAND_MULTI_PROGRAM;
}
} else if (ret == 2) {
PHY_ERR("NAND_ReadPhyArch: blank page!\n");
} else {
PHY_ERR("NAND_ReadPhyArch: get para error!\n");
}
return ret;
}
/*
******************************************************************************
* SEARCH NAND PHYSICAL ARCHITECTURE PARAMETER
*
*Description: Search the nand flash physical architecture parameter from the
*parameter table
* by nand chip ID.
*
*Arguments : pNandID the pointer to nand flash chip ID;
* pNandArchiInfo the pointer to nand flash physical architecture
*parameter.
*
*Return : search result;
* = 0 search successful, find the parameter in the table;
* < 0 search failed, can't find the parameter in the table.
******************************************************************************
*/
__s32 _SearchNandArchi(__u8 *pNandID, struct __NandPhyInfoPar_t *pNandArchInfo)
{
__s32 i = 0, j = 0, k = 0;
__u32 id_match_tbl[5] = {0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
__u32 id_bcnt;
struct __NandPhyInfoPar_t *tmpNandManu;
// analyze the manufacture of the nand flash
switch (pNandID[0]) {
case GD_NAND:
tmpNandManu = &GigaDeviceNandTbl;
break;
case ATO_NAND:
tmpNandManu = &AtoNandTbl;
break;
case MICRON_NAND:
tmpNandManu = &MicronNandTbl;
break;
case WINBOND_NAND:
tmpNandManu = &WinbondNandTbl;
break;
case MXIC_NAND:
tmpNandManu = &MxicNandTbl;
break;
// manufacture is unknown, search parameter from default nand table
default:
tmpNandManu = &DefaultNandTbl;
break;
}
MEMCPY(pNandArchInfo, tmpNandManu, sizeof(struct __NandPhyInfoPar_t));
#if 1
// search the nand architecture parameter from the given manufacture
// nand table by nand ID
while (tmpNandManu[i].NandID[0] != 0xff) {
// compare 6 byte id
id_bcnt = 1;
for (j = 1; j < 6; j++) {
// 0xff is matching all ID value
if ((pNandID[j] != tmpNandManu[i].NandID[j]) &&
(tmpNandManu[i].NandID[j] != 0xff))
break;
if (tmpNandManu[i].NandID[j] != 0xff)
id_bcnt++;
}
if (j == 6) {
/*4 bytes of the nand chip ID are all matching, search
* parameter successful
* */
if (id_bcnt == 2)
id_match_tbl[0] = i;
else if (id_bcnt == 3)
id_match_tbl[1] = i;
else if (id_bcnt == 4)
id_match_tbl[2] = i;
else if (id_bcnt == 5)
id_match_tbl[3] = i;
else if (id_bcnt == 6)
id_match_tbl[4] = i;
}
// prepare to search the next table item
i++;
}
for (k = 4; k >= 0; k--) {
if (id_match_tbl[k] != 0xffff) {
i = id_match_tbl[k];
MEMCPY(pNandArchInfo, tmpNandManu + i,
sizeof(struct __NandPhyInfoPar_t));
return 0;
}
}
#endif
// search nand architecture parameter failed
return -1;
}
/*
******************************************************************************
* ANALYZE NAND FLASH STORAGE SYSTEM
*
*Description: Analyze nand flash storage system, generate the nand flash
*physical
* architecture parameter and connect information.
*
*Arguments : none
*
*Return : analyze result;
* = 0 analyze successful;
* < 0 analyze failed, can't recognize or some other error.
******************************************************************************
*/
// struct __NandPhyInfoPar_t tmpNandPhyInfo;
__s32 SCN_AnalyzeNandSystem(void)
{
__s32 i, result;
__u8 tmpChipID[8];
__u8 status_lock;
__u8 status_otp;
// __u8 uniqueID[32];
struct __NandPhyInfoPar_t tmpNandPhyInfo;
// __u32 val[8];
// init nand flash storage information to default value
NandStorageInfo.ChipCnt = 1;
NandStorageInfo.ChipConnectInfo = 1;
NandStorageInfo.ConnectMode = 1;
// NandStorageInfo.RbCnt= 1;
// NandStorageInfo.RbConnectInfo= 1;
NandStorageInfo.BankCntPerChip = 1;
NandStorageInfo.DieCntPerChip = 1;
NandStorageInfo.PlaneCntPerDie = 1;
NandStorageInfo.SectorCntPerPage = 4;
NandStorageInfo.PageCntPerPhyBlk = 64;
NandStorageInfo.BlkCntPerDie = 1024;
NandStorageInfo.OperationOpt = 0;
NandStorageInfo.FrequencePar = 10;
NandStorageInfo.SpiMode = 0;
NandStorageInfo.pagewithbadflag = 0;
NandStorageInfo.MultiPlaneBlockOffset = 1;
NandStorageInfo.MaxEraseTimes = 50000;
NandStorageInfo.MaxEccBits = 1;
NandStorageInfo.EccLimitBits = 1;
// NandStorageInfo.ReadRetryType= 0;
// read nand flash chip ID from boot chip
result = PHY_ReadNandId_0(BOOT_CHIP_SELECT_NUM, tmpChipID);
if (result) {
PHY_ERR("read id fail 0\n");
return -1;
}
PHY_DBG("SPI nand ID: %x %x\n", *((__u32 *)tmpChipID),
*((__u32 *)tmpChipID + 1));
// search the nand flash physical architecture parameter by nand ID
result = _SearchNandArchi(tmpChipID, &tmpNandPhyInfo);
if (result) {
// read nand flash chip ID from boot chip
result = PHY_ReadNandId_1(BOOT_CHIP_SELECT_NUM, tmpChipID);
if (result) {
PHY_ERR("read id fail 1\n");
return -1;
}
// search the nand flash physical architecture parameter by nand
// ID
result = _SearchNandArchi(tmpChipID, &tmpNandPhyInfo);
if (result) {
PHY_ERR("_SearchNandArchi fail\n");
return -1;
}
}
storage_type = 2;
// set the nand flash physical architecture parameter
NandStorageInfo.BankCntPerChip = tmpNandPhyInfo.DieCntPerChip;
NandStorageInfo.DieCntPerChip = tmpNandPhyInfo.DieCntPerChip;
NandStorageInfo.PlaneCntPerDie = 2;
NandStorageInfo.SectorCntPerPage = tmpNandPhyInfo.SectCntPerPage;
NandStorageInfo.PageCntPerPhyBlk = tmpNandPhyInfo.PageCntPerBlk;
NandStorageInfo.BlkCntPerDie = tmpNandPhyInfo.BlkCntPerDie;
NandStorageInfo.OperationOpt = tmpNandPhyInfo.OperationOpt;
NandStorageInfo.FrequencePar = tmpNandPhyInfo.AccessFreq;
NandStorageInfo.NandChipId[0] = tmpNandPhyInfo.NandID[0];
NandStorageInfo.NandChipId[1] = tmpNandPhyInfo.NandID[1];
NandStorageInfo.NandChipId[2] = tmpNandPhyInfo.NandID[2];
NandStorageInfo.NandChipId[3] = tmpNandPhyInfo.NandID[3];
NandStorageInfo.NandChipId[4] = tmpNandPhyInfo.NandID[4];
NandStorageInfo.NandChipId[5] = tmpNandPhyInfo.NandID[5];
NandStorageInfo.NandChipId[6] = tmpNandPhyInfo.NandID[6];
NandStorageInfo.NandChipId[7] = tmpNandPhyInfo.NandID[7];
NandStorageInfo.SpiMode = tmpNandPhyInfo.SpiMode;
NandStorageInfo.pagewithbadflag = tmpNandPhyInfo.pagewithbadflag;
NandStorageInfo.MaxEraseTimes = tmpNandPhyInfo.MaxEraseTimes;
NandStorageInfo.MaxEccBits = tmpNandPhyInfo.MaxEccBits;
NandStorageInfo.EccLimitBits = tmpNandPhyInfo.EccLimitBits;
NandStorageInfo.MultiPlaneBlockOffset =
tmpNandPhyInfo.MultiPlaneBlockOffset;
NandStorageInfo.spi_nand_function = tmpNandPhyInfo.spi_nand_function;
NandStorageInfo.Idnumber = tmpNandPhyInfo.Idnumber;
Spic_set_trans_mode(0, NandStorageInfo.SpiMode);
// reset the nand flash chip on boot chip select
result = PHY_ResetChip(BOOT_CHIP_SELECT_NUM);
// result |= PHY_SynchBank(BOOT_CHIP_SELECT_NUM);
if (result)
return -1;
/* set max block erase cnt and enable read reclaim flag */
// MaxBlkEraseTimes = tmpNandPhyInfo.MaxEraseTimes;
/* in order to support to parse external script, record id ctl number */
NandIDNumber = tmpNandPhyInfo.Idnumber;
/* record current nand flash whether support two plane program */
if (NandStorageInfo.OperationOpt & SPINAND_MULTI_PROGRAM)
NandSupportTwoPlaneOp = 1;
else
NandSupportTwoPlaneOp = 0;
/* record current driver cfg for two plane operation */
if (CFG_SUPPORT_MULTI_PLANE_PROGRAM == 0)
CurrentDriverTwoPlaneOPCfg = 0;
else {
if (NandSupportTwoPlaneOp)
CurrentDriverTwoPlaneOPCfg = 1;
else
CurrentDriverTwoPlaneOPCfg = 0;
}
PHY_DBG(
"[SCAN_DBG] NandTwoPlaneOp: %d, DriverTwoPlaneOPCfg: %d, 0x%x\n",
NandSupportTwoPlaneOp, CurrentDriverTwoPlaneOPCfg,
((NandIDNumber << 4) ^ 0xffffffff));
/* update access frequency from script */
if (SUPPORT_UPDATE_EXTERNAL_ACCESS_FREQ)
_UpdateExtAccessFreqPara();
if (!CFG_SUPPORT_READ_RECLAIM)
NandStorageInfo.OperationOpt &= ~SPINAND_READ_RECLAIM;
if (!CFG_SUPPORT_DUAL_PROGRAM)
NandStorageInfo.OperationOpt &= ~SPINAND_DUAL_PROGRAM;
if (!CFG_SUPPORT_DUAL_READ)
NandStorageInfo.OperationOpt &= ~SPINAND_DUAL_READ;
for (i = 1; i < MAX_CHIP_SELECT_CNT; i++) {
// read the nand chip ID from current nand flash chip
PHY_ReadNandId_0((__u32)i, tmpChipID);
// check if the nand flash id same as the boot chip
if ((tmpChipID[0] == NandStorageInfo.NandChipId[0]) &&
(tmpChipID[1] == NandStorageInfo.NandChipId[1]) &&
((tmpChipID[2] == NandStorageInfo.NandChipId[2]) ||
(NandStorageInfo.NandChipId[2] == 0xff)) &&
((tmpChipID[4] == NandStorageInfo.NandChipId[3]) ||
(NandStorageInfo.NandChipId[3] == 0xff)) &&
((tmpChipID[4] == NandStorageInfo.NandChipId[4]) ||
(NandStorageInfo.NandChipId[4] == 0xff)) &&
((tmpChipID[5] == NandStorageInfo.NandChipId[5]) ||
(NandStorageInfo.NandChipId[5] == 0xff))) {
NandStorageInfo.ChipCnt++;
NandStorageInfo.ChipConnectInfo |= (1 << i);
} else {
// reset current nand flash chip
PHY_ResetChip((__u32)i);
PHY_ReadNandId_1((__u32)i, tmpChipID);
if ((tmpChipID[0] == NandStorageInfo.NandChipId[0]) &&
(tmpChipID[1] == NandStorageInfo.NandChipId[1]) &&
((tmpChipID[2] == NandStorageInfo.NandChipId[2]) ||
(NandStorageInfo.NandChipId[2] == 0xff)) &&
((tmpChipID[4] == NandStorageInfo.NandChipId[3]) ||
(NandStorageInfo.NandChipId[3] == 0xff)) &&
((tmpChipID[4] == NandStorageInfo.NandChipId[4]) ||
(NandStorageInfo.NandChipId[4] == 0xff)) &&
((tmpChipID[5] == NandStorageInfo.NandChipId[5]) ||
(NandStorageInfo.NandChipId[5] == 0xff))) {
NandStorageInfo.ChipCnt++;
NandStorageInfo.ChipConnectInfo |= (1 << i);
}
}
// reset current nand flash chip
PHY_ResetChip((__u32)i);
}
// process the rb connect information
{
NandStorageInfo.ConnectMode = 0xff;
if ((NandStorageInfo.ChipCnt == 1) &&
(NandStorageInfo.ChipConnectInfo & (1 << 0))) {
NandStorageInfo.ConnectMode = 1;
} else if (NandStorageInfo.ChipCnt == 2) {
if ((NandStorageInfo.ChipConnectInfo & (1 << 0)) &&
(NandStorageInfo.ChipConnectInfo & (1 << 1)))
NandStorageInfo.ConnectMode = 2;
else if ((NandStorageInfo.ChipConnectInfo & (1 << 0)) &&
(NandStorageInfo.ChipConnectInfo & (1 << 2)))
NandStorageInfo.ConnectMode = 3;
else if ((NandStorageInfo.ChipConnectInfo & (1 << 0)) &&
(NandStorageInfo.ChipConnectInfo & (1 << 3)))
NandStorageInfo.ConnectMode = 4;
else if ((NandStorageInfo.ChipConnectInfo & (1 << 0)) &&
(NandStorageInfo.ChipConnectInfo & (1 << 4)))
NandStorageInfo.ConnectMode = 5;
}
else if (NandStorageInfo.ChipCnt == 4) {
NandStorageInfo.ConnectMode = 6;
}
if (NandStorageInfo.ConnectMode == 0xff) {
PHY_ERR("%s : check spi nand connect fail, ChipCnt = "
"%x, ChipConnectInfo = %x\n",
__FUNCTION__, NandStorageInfo.ChipCnt,
NandStorageInfo.ChipConnectInfo);
return -1;
}
}
if (!CFG_SUPPORT_MULTI_PLANE_PROGRAM) {
NandStorageInfo.OperationOpt &= ~SPINAND_MULTI_READ;
NandStorageInfo.OperationOpt &= ~SPINAND_MULTI_PROGRAM;
}
// process the plane count of a die and the bank count of a chip
if (!SUPPORT_MULTI_PROGRAM)
NandStorageInfo.PlaneCntPerDie = 1;
for (i = 0; i < NandStorageInfo.ChipCnt; i++) {
// NandStorageInfo.spi_nand_function->spi_nand_getblocklock(0,
// i, &status_lock);
// NandStorageInfo.spi_nand_function->spi_nand_getotp(0, i,
// &status_otp);
NandStorageInfo.spi_nand_function->spi_nand_setblocklock(0, i,
0);
NandStorageInfo.spi_nand_function->spi_nand_setotp(
0, i, 0x18); // winbond:0x18,bit3 is BUF mode;
// other:0x10,bit3 don't care
NandStorageInfo.spi_nand_function->spi_nand_getblocklock(
0, i, &status_lock);
NandStorageInfo.spi_nand_function->spi_nand_getotp(0, i,
&status_otp);
}
// process the external inter-leave operation
if (CFG_SUPPORT_EXT_INTERLEAVE) {
if (NandStorageInfo.ChipCnt > 1) {
NandStorageInfo.OperationOpt |= SPINAND_EXT_INTERLEAVE;
} else {
NandStorageInfo.OperationOpt &=
(~SPINAND_EXT_INTERLEAVE);
}
} else {
NandStorageInfo.OperationOpt &= (~SPINAND_EXT_INTERLEAVE);
}
PHY_ChangeMode();
PHY_Scan_DelayMode(NAND_ACCESS_FREQUENCE);
physic_info_read();
if (SUPPORT_UPDATE_WITH_OLD_PHYSIC_ARCH)
NAND_ReadPhyArch();
if ((!CFG_SUPPORT_MULTI_PLANE_PROGRAM) ||
(SECTOR_CNT_OF_SINGLE_PAGE > 8)) {
NandStorageInfo.OperationOpt &= ~SPINAND_MULTI_READ;
NandStorageInfo.OperationOpt &= ~SPINAND_MULTI_PROGRAM;
}
// process the plane count of a die and the bank count of a chip
if (!SUPPORT_MULTI_PROGRAM)
NandStorageInfo.PlaneCntPerDie = 1;
// print nand flash physical architecture parameter
SCAN_DBG("\n\n");
SCAN_DBG("[SCAN_DBG] ==============Nand Architecture "
"Parameter==============\n");
SCAN_DBG("[SCAN_DBG] Nand Chip ID: 0x%x 0x%x\n",
(NandStorageInfo.NandChipId[0] << 0) |
(NandStorageInfo.NandChipId[1] << 8) |
(NandStorageInfo.NandChipId[2] << 16) |
(NandStorageInfo.NandChipId[3] << 24),
(NandStorageInfo.NandChipId[4] << 0) |
(NandStorageInfo.NandChipId[5] << 8) |
(NandStorageInfo.NandChipId[6] << 16) |
(NandStorageInfo.NandChipId[7] << 24));
SCAN_DBG("[SCAN_DBG] Nand Chip Count: 0x%x\n",
NandStorageInfo.ChipCnt);
SCAN_DBG("[SCAN_DBG] Nand Chip Connect: 0x%x\n",
NandStorageInfo.ChipConnectInfo);
SCAN_DBG("[SCAN_DBG] Sector Count Of Page: 0x%x\n",
NandStorageInfo.SectorCntPerPage);
SCAN_DBG("[SCAN_DBG] Page Count Of Block: 0x%x\n",
NandStorageInfo.PageCntPerPhyBlk);
SCAN_DBG("[SCAN_DBG] Block Count Of Die: 0x%x\n",
NandStorageInfo.BlkCntPerDie);
SCAN_DBG("[SCAN_DBG] Plane Count Of Die: 0x%x\n",
NandStorageInfo.PlaneCntPerDie);
SCAN_DBG("[SCAN_DBG] Die Count Of Chip: 0x%x\n",
NandStorageInfo.DieCntPerChip);
SCAN_DBG("[SCAN_DBG] Bank Count Of Chip: 0x%x\n",
NandStorageInfo.BankCntPerChip);
SCAN_DBG("[SCAN_DBG] Optional Operation: 0x%x\n",
NandStorageInfo.OperationOpt);
SCAN_DBG("[SCAN_DBG] Access Frequence: 0x%x\n",
NandStorageInfo.FrequencePar);
SCAN_DBG("[SCAN_DBG] "
"=======================================================\n\n");
return 0;
}