/* * 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; }