sdk-hwV1.3/lichee/linux-4.9/modules/nand/common1/phy-nand/rawnand/rawnand_boot1.c

1342 lines
37 KiB
C
Executable File

/* SPDX-License-Identifier: GPL-2.0 */
/*
************************************************************************************************************************
* eNand
* Nand flash driver scan module
*
* Copyright(C), 2008-2009, SoftWinners Microelectronic Co., Ltd.
* All Rights Reserved
*
* File Name : nand_chip_interface.c
*
* Author :
*
* Version : v0.1
*
* Date : 2013-11-20
*
* Description :
*
* Others : None at present.
*
*
*
************************************************************************************************************************
*/
#define _UBOOTT_RAWNAND_C_
/*#include "../nand_boot.h"*/
#include "../nand_errno.h"
#include "../nand_physic_interface.h"
#include "../nand_secure_storage.h"
#include "rawnand_boot.h"
#include "rawnand_chip.h"
#include "rawnand_readretry.h"
#include "rawnand.h"
#include "rawnand_base.h"
#include "rawnand_cfg.h"
#include "rawnand_debug.h"
#include "../version.h"
#include <linux/sunxi-boot.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include "../nand-partition3/sunxi_nand_boot.h"
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int rawnand_write_uboot_one_in_block(unsigned char *buf, unsigned int len, struct _boot_info *info_buf, unsigned int info_len, unsigned int counter)
{
int ret;
unsigned int j, boot_len, page_index, t_len;
unsigned char oob_buf[64];
struct _nand_physic_op_par lnpo;
struct nand_chip_info *nci;
int uboot_flag, info_flag;
unsigned char *kernel_buf;
unsigned char *ptr;
RAWNAND_DBG("burn uboot in one block!\n");
nci = g_nctri->nci;
uboot_flag = 0;
info_flag = 0;
boot_len = 0;
t_len = 0;
kernel_buf = nand_get_temp_buf(nci->sector_cnt_per_page << 9);
memset(oob_buf, 0xff, 64);
nand_get_version(oob_buf);
if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) {
RAWNAND_ERR("get flash driver version error!");
nand_free_temp_buf(kernel_buf);
return ERR_NO_105;
}
if (len % (nci->sector_cnt_per_page << 9)) {
RAWNAND_ERR("uboot length check error!\n");
nand_free_temp_buf(kernel_buf);
return ERR_NO_104;
}
lnpo.chip = 0;
lnpo.block = info_buf->uboot_start_block + counter;
lnpo.page = 0;
nand_wait_all_rb_ready();
ret = nci->nand_physic_erase_block(&lnpo);
if (ret) {
RAWNAND_ERR("Fail in erasing block %d!\n", lnpo.block);
//return ret;
}
page_index = 0;
for (j = 0; j < nci->page_cnt_per_blk; j++) {
lnpo.chip = 0;
lnpo.block = info_buf->uboot_start_block + counter;
if (0 == nci->is_lsb_page(j)) {
continue;
}
lnpo.page = j;
lnpo.sect_bitmap = nci->sector_cnt_per_page;
lnpo.sdata = oob_buf;
lnpo.slen = 64;
if (uboot_flag == 0) {
boot_len = page_index * (nci->sector_cnt_per_page << 9);
memcpy(kernel_buf, buf + boot_len, nci->sector_cnt_per_page << 9);
ptr = kernel_buf;
if ((len - boot_len) == (nci->sector_cnt_per_page << 9)) {
uboot_flag = page_index + 1;
}
} else if (info_flag == 0) {
RAWNAND_DBG("uboot info: page %d in block %d.\n", lnpo.page, lnpo.block);
t_len = (page_index - uboot_flag) * (nci->sector_cnt_per_page << 9);
ptr = (unsigned char *)info_buf;
ptr += t_len;
if ((info_len - t_len) == (nci->sector_cnt_per_page << 9)) {
info_flag = page_index;
}
} else {
ptr = kernel_buf;
}
lnpo.mdata = ptr;
nand_wait_all_rb_ready();
if (nci->nand_physic_write_page(&lnpo) != 0) {
RAWNAND_ERR("Warning. Fail in writing page %d in block %d.\n", lnpo.page, lnpo.block);
}
page_index++;
}
nand_wait_all_rb_ready();
nand_free_temp_buf(kernel_buf);
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int rawnand_write_uboot_one_in_many_block(unsigned char *buf, unsigned int len, struct _boot_info *info_buf, unsigned int info_len, unsigned int counter)
{
int ret;
unsigned int j, boot_len, page_index, total_len, t_len, total_pages, pages_per_block, good_block_offset, blocks_one_uboot, uboot_block_offset, m;
unsigned int write_blocks;
unsigned char oob_buf[64];
struct _nand_physic_op_par lnpo;
struct nand_chip_info *nci;
int uboot_flag, info_flag;
unsigned char *kernel_buf;
unsigned char *ptr;
RAWNAND_DBG("burn uboot in many block %d!\n", counter);
nci = g_nctri->nci;
uboot_flag = 0;
info_flag = 0;
boot_len = 0;
t_len = 0;
kernel_buf = nand_get_temp_buf(nci->sector_cnt_per_page << 9);
memset(oob_buf, 0xff, 64);
nand_get_version(oob_buf);
if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) {
RAWNAND_ERR("get flash driver version error!");
nand_free_temp_buf(kernel_buf);
return ERR_NO_105;
}
if (len % (nci->sector_cnt_per_page << 9)) {
RAWNAND_ERR("uboot length check error!\n");
nand_free_temp_buf(kernel_buf);
return ERR_NO_104;
}
total_len = len + info_len;
if (total_len % (nci->sector_cnt_per_page << 9)) {
RAWNAND_ERR("uboot length check error!\n");
nand_free_temp_buf(kernel_buf);
return ERR_NO_104;
}
total_pages = total_len / (nci->sector_cnt_per_page << 9);
pages_per_block = nand_get_lsb_pages();
blocks_one_uboot = total_pages / pages_per_block;
if (total_pages % pages_per_block) {
blocks_one_uboot++;
}
good_block_offset = blocks_one_uboot * counter;
for (m = 0, j = info_buf->uboot_start_block; j < info_buf->uboot_next_block; j++) {
if (m == good_block_offset) {
break;
}
lnpo.chip = 0;
lnpo.block = j;
lnpo.page = 0;
lnpo.sect_bitmap = 0;
lnpo.mdata = NULL;
lnpo.sdata = NULL;
ret = nci->nand_physic_bad_block_check(&lnpo);
if (ret == 0) {
m++;
}
}
uboot_block_offset = j;
if ((uboot_block_offset + blocks_one_uboot) > info_buf->uboot_next_block) {
nand_free_temp_buf(kernel_buf);
return 0;
}
/////////////////////////////////////////////////////
uboot_flag = 0;
info_flag = 0;
boot_len = 0;
page_index = 0;
write_blocks = 0;
for (j = uboot_block_offset; j < info_buf->uboot_next_block; j++) {
lnpo.chip = 0;
lnpo.block = j;
lnpo.page = 0;
nand_wait_all_rb_ready();
ret = nci->nand_physic_bad_block_check(&lnpo);
if (ret != 0) {
continue;
}
ret = nci->nand_physic_erase_block(&lnpo);
if (ret != 0) {
RAWNAND_ERR("Fail in erasing block %d!\n", lnpo.block);
//return ret;
}
write_blocks++;
RAWNAND_DBG("write uboot many block %d!\n", lnpo.block);
for (m = 0; m < nci->page_cnt_per_blk; m++) {
lnpo.chip = 0;
lnpo.block = j;
lnpo.page = m;
lnpo.sect_bitmap = nci->sector_cnt_per_page;
lnpo.sdata = oob_buf;
lnpo.slen = 64;
if (nci->is_lsb_page(m) != 0) {
if (uboot_flag == 0) {
boot_len = page_index * (nci->sector_cnt_per_page << 9);
memcpy(kernel_buf, buf + boot_len, nci->sector_cnt_per_page << 9);
ptr = kernel_buf;
if ((len - boot_len) == (nci->sector_cnt_per_page << 9)) {
uboot_flag = page_index + 1;
}
} else if (info_flag == 0) {
RAWNAND_DBG("uboot info: page %d in block %d.\n", lnpo.page, lnpo.block);
t_len = (page_index - uboot_flag) * (nci->sector_cnt_per_page << 9);
ptr = (unsigned char *)info_buf;
ptr += t_len;
if ((info_len - t_len) == (nci->sector_cnt_per_page << 9)) {
info_flag = page_index;
}
} else {
ptr = kernel_buf;
}
lnpo.mdata = ptr;
nand_wait_all_rb_ready();
if (nci->nand_physic_write_page(&lnpo) != 0) {
RAWNAND_ERR("Warning. Fail in writing page %d in block %d.\n", lnpo.page, lnpo.block);
}
page_index++;
}
}
if (blocks_one_uboot == write_blocks) {
break;
}
}
nand_wait_all_rb_ready();
nand_free_temp_buf(kernel_buf);
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int rawnand_write_uboot_one(unsigned char *buf, unsigned int len, struct _boot_info *info_buf, unsigned int info_len, unsigned int counter)
{
int ret;
struct nand_chip_info *nci;
int real_len;
RAWNAND_DBG("burn uboot one!\n");
nci = g_nctri->nci;
real_len = rawnand_add_len_to_uboot_tail(len);
//print_physic_info(phyinfo_buf);
if (((0 == nci->lsb_page_type) && (real_len <= nand_get_phy_block_size())) || ((0 != nci->lsb_page_type) && (real_len <= nand_get_lsb_block_size()))) {
ret = rawnand_write_uboot_one_in_block(buf, len, phyinfo_buf, PHY_INFO_SIZE, counter);
} else {
ret = rawnand_write_uboot_one_in_many_block(buf, len, phyinfo_buf, PHY_INFO_SIZE, counter);
}
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail 1: ecc limit
*Note :
*****************************************************************************/
int rawnand_read_uboot_one_in_block(unsigned char *buf, unsigned int len, unsigned int counter)
{
int ret = 0, data_error = 0, ecc_limit = 0;
unsigned int j, page_index, total_pages;
unsigned char oob_buf[64];
struct _nand_physic_op_par lnpo;
struct nand_chip_info *nci;
// int uboot_flag = 0;
unsigned char *ptr;
RAWNAND_DBG("read uboot in one block %d!\n", counter);
nci = g_nctri->nci;
// uboot_flag = 0;
// info_flag = 0;
// boot_len = 0;
// t_len = 0;
ptr = nand_get_temp_buf(nci->sector_cnt_per_page << 9);
memset(oob_buf, 0xff, 64);
if (len % (nci->sector_cnt_per_page << 9)) {
RAWNAND_ERR("uboot length check error!\n");
nand_free_temp_buf(ptr);
return 0;
}
total_pages = len / (nci->sector_cnt_per_page << 9);
for (j = 0, page_index = 0; j < nci->page_cnt_per_blk; j++) {
lnpo.chip = 0;
lnpo.block = phyinfo_buf->uboot_start_block + counter;
if (0 == nci->is_lsb_page(j)) {
continue;
}
lnpo.page = j;
lnpo.sect_bitmap = nci->sector_cnt_per_page;
lnpo.sdata = oob_buf;
lnpo.slen = 64;
lnpo.mdata = ptr;
nand_wait_all_rb_ready();
ret = nci->nand_physic_read_page(&lnpo);
if (ret == 0) {
;
} else if (ret == ECC_LIMIT) {
ecc_limit = 1;
RAWNAND_ERR("Warning. Fail in read page %d in block %d \n", lnpo.page, lnpo.block);
} else {
data_error = 1;
break;
}
if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) {
RAWNAND_ERR("get uboot flash driver version error!\n");
data_error = 1;
break;
}
memcpy(buf + page_index * (nci->sector_cnt_per_page << 9), ptr, nci->sector_cnt_per_page << 9);
page_index++;
if (total_pages == page_index) {
break;
}
}
nand_wait_all_rb_ready();
nand_free_temp_buf(ptr);
if (data_error == 1) {
ret = -1;
} else if (ecc_limit == 1) {
ret = 1;
} else {
ret = 0;
}
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail 1: ecc limit
*Note :
*****************************************************************************/
int rawnand_read_uboot_one_in_many_block(unsigned char *buf, unsigned int len, unsigned int counter)
{
int ret = 0, data_error = 0, ecc_limit = 0;
unsigned int j, page_index, total_len, total_pages, pages_per_block, good_block_offset, blocks_one_uboot, uboot_block_offset, m;
unsigned char oob_buf[64];
struct _nand_physic_op_par lnpo;
struct nand_chip_info *nci;
// int uboot_flag = 0;
unsigned char *kernel_buf;
// unsigned char* ptr;
RAWNAND_DBG("read uboot in many block %d!\n", counter);
nci = g_nctri->nci;
// uboot_flag = 0;
// info_flag = 0;
// boot_len = 0;
// t_len = 0;
kernel_buf = nand_get_temp_buf(nci->sector_cnt_per_page << 9);
memset(oob_buf, 0xff, 64);
nand_get_version(oob_buf);
if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) {
RAWNAND_ERR("get flash driver version error!");
nand_free_temp_buf(kernel_buf);
return ERR_NO_105;
}
if (len % (nci->sector_cnt_per_page << 9)) {
RAWNAND_ERR("uboot length check error!\n");
nand_free_temp_buf(kernel_buf);
return ERR_NO_104;
}
total_len = len;
total_pages = total_len / (nci->sector_cnt_per_page << 9);
pages_per_block = nand_get_lsb_pages();
blocks_one_uboot = total_pages / pages_per_block;
if (total_pages % pages_per_block) {
blocks_one_uboot++;
}
good_block_offset = blocks_one_uboot * counter;
for (m = 0, j = phyinfo_buf->uboot_start_block; j < phyinfo_buf->uboot_next_block; j++) {
if (m == good_block_offset) {
break;
}
lnpo.chip = 0;
lnpo.block = j;
lnpo.page = 0;
lnpo.sect_bitmap = 0;
lnpo.mdata = NULL;
lnpo.sdata = NULL;
ret = nci->nand_physic_bad_block_check(&lnpo);
if (ret == 0) {
m++;
}
}
uboot_block_offset = j;
if ((uboot_block_offset + blocks_one_uboot) > phyinfo_buf->uboot_next_block) {
nand_free_temp_buf(kernel_buf);
return 0;
}
/////////////////////////////////////////////////////
// uboot_flag = 0;
// info_flag = 0;
// boot_len = 0;
page_index = 0;
for (j = uboot_block_offset; j < phyinfo_buf->uboot_next_block; j++) {
lnpo.chip = 0;
lnpo.block = j;
lnpo.page = 0;
nand_wait_all_rb_ready();
ret = nci->nand_physic_bad_block_check(&lnpo);
if (ret != 0) {
continue;
}
RAWNAND_DBG("read uboot many block %d!\n", lnpo.block);
for (m = 0; m < nci->page_cnt_per_blk; m++) {
lnpo.chip = 0;
lnpo.block = j;
lnpo.page = m;
lnpo.sect_bitmap = nci->sector_cnt_per_page;
lnpo.sdata = oob_buf;
lnpo.slen = 64;
if (nci->is_lsb_page(m) != 0) {
lnpo.mdata = kernel_buf;
nand_wait_all_rb_ready();
ret = nci->nand_physic_read_page(&lnpo);
if (ret == 0) {
;
} else if (ret == ECC_LIMIT) {
ecc_limit = 1;
RAWNAND_ERR("Warning. Fail in read page %d in block %d \n", lnpo.page, lnpo.block);
} else {
RAWNAND_ERR("error read page: %d in block %d \n", lnpo.page, lnpo.block);
data_error = 1;
break;
}
if ((oob_buf[0] != 0xff) || (oob_buf[1] != 0x00)) {
RAWNAND_ERR("get uboot flash driver version error!\n");
data_error = 1;
break;
}
memcpy(buf + page_index * (nci->sector_cnt_per_page << 9), lnpo.mdata, nci->sector_cnt_per_page << 9);
page_index++;
if (total_pages == page_index) {
break;
}
}
}
if (total_pages == page_index) {
break;
}
if (data_error == 1) {
break;
}
}
nand_wait_all_rb_ready();
nand_free_temp_buf(kernel_buf);
if (data_error == 1) {
ret = -1;
} else if (ecc_limit == 1) {
ret = 1;
} else {
ret = 0;
}
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok <0:fail 1: ecc limit
*Note :
*****************************************************************************/
int rawnand_read_uboot_one(unsigned char *buf, unsigned int len, unsigned int counter)
{
int ret = 0;
struct nand_chip_info *nci;
nci = g_nctri->nci;
RAWNAND_DBG("read uboot one %d!\n", counter);
if (((0 == nci->lsb_page_type) && (len <= nand_get_phy_block_size())) || ((0 != nci->lsb_page_type) && (len <= nand_get_lsb_block_size()))) {
ret = rawnand_read_uboot_one_in_block(buf, len, counter);
} else {
ret = rawnand_read_uboot_one_in_many_block(buf, len, counter);
}
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :NAND_GetParam
*****************************************************************************/
int rawnand_get_param(void *nand_param)
{
int i;
struct nand_chip_info *nci;
boot_nand_para_t *nand_param_temp;
nand_param_temp = (boot_nand_para_t *)nand_param;
nci = g_nctri->nci;
nand_param_temp->ChannelCnt = g_nand_storage_info->ChannelCnt;
nand_param_temp->ChipCnt = g_nand_storage_info->ChipCnt;
nand_param_temp->ChipConnectInfo = g_nand_storage_info->ChipConnectInfo;
nand_param_temp->RbCnt = g_nand_storage_info->ChipConnectInfo;
nand_param_temp->RbConnectInfo = g_nand_storage_info->RbConnectInfo;
nand_param_temp->RbConnectMode = g_nand_storage_info->RbConnectMode;
nand_param_temp->BankCntPerChip = g_nand_storage_info->BankCntPerChip;
nand_param_temp->DieCntPerChip = g_nand_storage_info->DieCntPerChip;
nand_param_temp->PlaneCntPerDie = g_nand_storage_info->PlaneCntPerDie;
nand_param_temp->SectorCntPerPage = g_nand_storage_info->SectorCntPerPage;
nand_param_temp->PageCntPerPhyBlk = g_nand_storage_info->PageCntPerPhyBlk;
nand_param_temp->BlkCntPerDie = g_nand_storage_info->BlkCntPerDie;
nand_param_temp->OperationOpt = g_nand_storage_info->OperationOpt;
nand_param_temp->FrequencePar = g_nand_storage_info->FrequencePar;
nand_param_temp->EccMode = g_nand_storage_info->EccMode;
nand_param_temp->ValidBlkRatio = g_nand_storage_info->ValidBlkRatio;
nand_param_temp->good_block_ratio = 0;
nand_param_temp->ReadRetryType = g_nand_storage_info->ReadRetryType;
nand_param_temp->DDRType = g_nand_storage_info->DDRType;
nand_param_temp->random_addr_num = g_nand_storage_info->random_addr_num;
nand_param_temp->random_cmd2_send_flag = g_nand_storage_info->random_cmd2_send_flag;
nand_param_temp->nand_real_page_size = g_nand_storage_info->nand_real_page_size;
//boot0 not support DDR mode, only SDR or toggle!!!!
if ((nand_param_temp->DDRType == 0x2) || (nand_param_temp->DDRType == 0x12)) {
RAWNAND_DBG("set ddrtype 0, freq 30Mhz\n");
nand_param_temp->DDRType = 0;
nand_param_temp->FrequencePar = 30;
} else if ((nci->support_toggle_only == 0) && ((nand_param_temp->DDRType == 0x3) || (nand_param_temp->DDRType == 0x13))) {
RAWNAND_DBG("set ddrtype 0\n");
nand_param_temp->DDRType = 0;
nand_param_temp->FrequencePar = 30;
} else if (nand_param_temp->DDRType == 0x13) {
RAWNAND_DBG("set ddrtype 3, freq 30Mhz\n");
nand_param_temp->DDRType = 3;
nand_param_temp->FrequencePar = 20;
} else {
;
}
for (i = 0; i < 8; i++)
nand_param_temp->NandChipId[i] = g_nand_storage_info->NandChipId[i];
RAWNAND_DBG("nand get param end 0x%x\n", nand_param_temp->DDRType);
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :NAND_GetParam
*****************************************************************************/
int rawnand_get_param_for_uboottail(void *nand_param)
{
boot_nand_para_t *nand_param_temp;
nand_param_temp = (boot_nand_para_t *)nand_param;
nand_param_temp->uboot_start_block = aw_nand_info.boot->uboot_start_block;
nand_param_temp->uboot_next_block = aw_nand_info.boot->uboot_next_block;
nand_param_temp->logic_start_block = aw_nand_info.boot->logic_start_block;
nand_param_temp->nand_specialinfo_page = aw_nand_info.boot->nand_specialinfo_page;
nand_param_temp->nand_specialinfo_offset = aw_nand_info.boot->nand_specialinfo_offset;
nand_param_temp->physic_block_reserved = aw_nand_info.boot->physic_block_reserved;
RAWNAND_DBG("uboot_start_block: %x\n", nand_param_temp->uboot_start_block);
RAWNAND_DBG("uboot_next_block: %x\n", nand_param_temp->uboot_next_block);
RAWNAND_DBG("logic_start_block:%x\n", nand_param_temp->logic_start_block);
RAWNAND_DBG("nand_specialinfo_page:%x\n", nand_param_temp->nand_specialinfo_page);
RAWNAND_DBG("nand_specialinfo_offset: %x\n", nand_param_temp->nand_specialinfo_offset);
RAWNAND_DBG("physic_block_reserved: %x\n", nand_param_temp->physic_block_reserved);
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
__s32 RAWNAND_SetPhyArch_V3(struct _boot_info *ram_arch, void *phy_arch)
{
struct _nand_super_storage_info *phy_arch_temp;
phy_arch_temp = (struct _nand_super_storage_info *)phy_arch;
ram_arch->storage_info.data.support_two_plane = phy_arch_temp->support_two_plane;
ram_arch->storage_info.data.support_v_interleave = phy_arch_temp->support_v_interleave;
ram_arch->storage_info.data.support_dual_channel = phy_arch_temp->support_dual_channel;
if (phy_arch_temp->support_two_plane == 0) {
ram_arch->storage_info.data.plane_cnt = 1;
} else {
ram_arch->storage_info.data.plane_cnt = 2;
}
// RAWNAND_DBG("===========NAND_SetPhyArch_V3================\n");
// for(i=-0;i<128;i++)
// {
// RAWNAND_DBG("%x ",ram_arch[i]);
// if(((i+1) % 16) == 0)
// {
// RAWNAND_DBG("\n");
// }
// }
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int rawnand_update_phyarch(void)
{
int ret;
unsigned int id_number_ctl, para;
g_nssi->support_two_plane = 0;
g_nssi->support_v_interleave = 1;
g_nssi->support_dual_channel = 1;
nand_permanent_data.magic_data = MAGIC_DATA_FOR_PERMANENT_DATA;
nand_permanent_data.support_two_plane = 0;
nand_permanent_data.support_vertical_interleave = 1;
nand_permanent_data.support_dual_channel = 1;
RAWNAND_DBG("NAND UpdatePhyArch\n");
g_nssi->support_two_plane = g_phy_cfg->phy_support_two_plane;
nand_permanent_data.support_two_plane = g_nssi->support_two_plane;
g_nssi->support_v_interleave = g_phy_cfg->phy_nand_support_vertical_interleave;
nand_permanent_data.support_vertical_interleave = g_nssi->support_v_interleave;
g_nssi->support_dual_channel = g_phy_cfg->phy_support_dual_channel;
nand_permanent_data.support_dual_channel = g_nssi->support_dual_channel;
id_number_ctl = nand_get_nand_id_number_ctrl(&aw_ndfc);
if ((id_number_ctl & 0x0e) != 0) {
para = nand_get_nand_extern_para(&aw_ndfc, 1);
if ((para != 0xffffffff) && (id_number_ctl & 0x02)) {
/*get script success*/
if (((para & 0xffffff) == g_nctri->nci->npi->id_number) || ((para & 0xffffff) == 0xeeeeee)) {
RAWNAND_DBG("script support_two_plane %d\n", para);
g_nssi->support_two_plane = (para >> 24) & 0xff;
if (g_nssi->support_two_plane == 1) {
g_nssi->support_two_plane = 1;
} else {
g_nssi->support_two_plane = 0;
}
nand_permanent_data.support_two_plane = g_nssi->support_two_plane;
}
}
para = nand_get_nand_extern_para(&aw_ndfc, 2);
if ((para != 0xffffffff) && (id_number_ctl & 0x04)) {
/*get script success*/
if (((para & 0xffffff) == g_nctri->nci->npi->id_number) || ((para & 0xffffff) == 0xeeeeee)) {
RAWNAND_DBG("script support_v_interleave %d\n", para);
g_nssi->support_v_interleave = (para >> 24) & 0xff;
nand_permanent_data.support_vertical_interleave = g_nssi->support_v_interleave;
}
}
para = nand_get_nand_extern_para(&aw_ndfc, 3);
if ((para != 0xffffffff) && (id_number_ctl & 0x08)) {
/*get script success*/
if (((para & 0xffffff) == g_nctri->nci->npi->id_number) || ((para & 0xffffff) == 0xeeeeee)) {
RAWNAND_DBG("script support_dual_channel %d\n", para);
g_nssi->support_dual_channel = (para >> 24) & 0xff;
nand_permanent_data.support_dual_channel = g_nssi->support_dual_channel;
}
}
}
//ret = set_nand_structure((void*)&nand_permanent_data);
ret = RAWNAND_SetPhyArch_V3(aw_nand_info.boot, (void *)g_nssi);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
int rawnand_is_blank(void)
{
int i, ret;
int block_blank_flag = 1;
int read_retry_mode;
int start_blk = 4, blk_cnt = 30;
unsigned char oob[64];
struct _nand_physic_op_par npo;
struct nand_chip_info *nci;
nci = nci_get_from_nsi(g_nsi, 0);
read_retry_mode = (nci->npi->read_retry_type >> 16) & 0xff;
if ((read_retry_mode != 0x32) && (read_retry_mode != 0x33) && (read_retry_mode != 0x34) && (read_retry_mode != 0x35))
return 0;
for (i = start_blk; i < (start_blk + blk_cnt); i++) {
npo.chip = 0;
npo.block = i;
npo.page = 0;
npo.sect_bitmap = nci->sector_cnt_per_page;
npo.mdata = NULL;
npo.sdata = oob;
npo.slen = 64;
ret = nci->nand_physic_read_page(&npo);
if (ret >= 0) {
if ((oob[0] == 0xff) && (oob[1] == 0xaa) && (oob[2] == 0x5c)) {
block_blank_flag = 0;
break;
}
if ((oob[0] == 0xff) && (oob[1] == 0x00)) {
block_blank_flag = 0;
break;
}
}
}
if (block_blank_flag == 1)
RAWNAND_DBG("nand is blank!!\n");
else
RAWNAND_DBG("nand has valid data!!\n");
return block_blank_flag;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
int nand_check_bad_block_before_first_erase(struct _nand_physic_op_par *npo)
{
int ret;
int read_retry_mode;
struct nand_chip_info *nci;
nci = nci_get_from_nsi(g_nsi, npo->chip);
read_retry_mode = (nci->npi->read_retry_type >> 16) & 0xff;
if ((read_retry_mode != 0x34) && (read_retry_mode != 0x35)) {
RAWNAND_DBG("not slc program\n");
return 1;
}
ret = sandisk_A19_check_bad_block_first_burn(npo);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int rawnand_erase_chip(unsigned int chip, unsigned int start_block, unsigned int end_block, unsigned int force_flag)
{
int ret, i;
int read_retry_mode;
struct _nand_physic_op_par npo;
struct nand_chip_info *nci;
nci = nci_get_from_nsi(g_nsi, chip);
read_retry_mode = (nci->npi->read_retry_type >> 16) & 0xff;
if ((end_block >= nci->blk_cnt_per_chip) || (end_block == 0))
end_block = nci->blk_cnt_per_chip;
if (start_block > end_block)
return 0;
for (i = start_block; i < end_block; i++) {
npo.chip = nci->chip_no;
npo.block = i;
npo.page = 0;
npo.sect_bitmap = nci->sector_cnt_per_page;
npo.mdata = NULL;
npo.sdata = NULL;
if ((read_retry_mode == 0x32) || (read_retry_mode == 0x33)) {
ret = 0;
} else if ((read_retry_mode == 0x34) || (read_retry_mode == 0x35)) {
ret = nand_check_bad_block_before_first_erase(&npo);
if (ret != 0)
RAWNAND_DBG("find a bad block %d %d\n", npo.chip, npo.block);
if (force_flag == 1)
ret = 0;
} else {
ret = nci->nand_physic_bad_block_check(&npo);
if (force_flag == 1)
ret = 0;
}
if (ret == 0) {
ret = nci->nand_physic_erase_block(&npo);
nand_wait_all_rb_ready();
if (ret != 0)
nci->nand_physic_bad_block_mark(&npo);
}
}
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
void rawnand_erase_special_block(void)
{
int i, j, flag, ret;
struct _nand_physic_op_par npo;
u8 oob[64];
struct nand_chip_info *nci;
nci = nci_get_from_nsi(g_nsi, 0);
for (j = 0; j < g_nsi->chip_cnt; j++) {
for (i = 7; i < 50; i++) {
flag = 0;
npo.chip = j;
npo.block = i;
npo.page = 0;
npo.sect_bitmap = nci->sector_cnt_per_page;
npo.mdata = NULL;
npo.sdata = NULL;
ret = nci->nand_physic_bad_block_check(&npo);
if (ret != 0) {
npo.chip = j;
npo.block = i;
npo.page = 0;
npo.sect_bitmap = nci->sector_cnt_per_page;
npo.mdata = NULL;
npo.sdata = oob;
npo.slen = 16;
ret = nci->nand_physic_read_page(&npo);
if ((oob[1] == 0x78) && (oob[2] == 0x69) && (oob[3] == 0x87) && (oob[4] == 0x41) && (oob[5] == 0x52) && (oob[6] == 0x43) && (oob[7] == 0x48)) {
flag = 1;
RAWNAND_DBG("this is nand struct block %d\n", i);
}
if ((oob[1] == 0x50) && (oob[2] == 0x48) && (oob[3] == 0x59) && (oob[4] == 0x41) && (oob[5] == 0x52) && (oob[6] == 0x43) && (oob[7] == 0x48)) {
flag = 1;
RAWNAND_DBG("this is old nand struct block %d\n", i);
}
if ((oob[0] == 0x00) && (oob[1] == 0x4F) && (oob[2] == 0x4F) && (oob[3] == 0x42)) {
flag = 1;
RAWNAND_DBG("this is hynix otp data save block %d\n", i);
}
if (flag == 1) {
ret = nci->nand_physic_erase_block(&npo);
nand_wait_all_rb_ready();
if (ret != 0) {
nci->nand_physic_bad_block_mark(&npo);
}
}
}
}
}
return;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int rawnand_uboot_erase_all_chip(UINT32 force_flag)
{
int i, start, end, secure_block_start;
int uboot_start_block, uboot_next_block;
uboot_start_block = get_uboot_start_block();
uboot_next_block = get_uboot_next_block();
secure_block_start = uboot_next_block;
for (i = 0; i < g_nsi->chip_cnt; i++) {
start = 0;
end = 0xfffff;
if (i == 0) {
if ((force_flag == 1) || (rawnand_is_blank()) == 1)
start = secure_block_start;
else
start = nand_secure_storage_first_build(secure_block_start);
}
rawnand_erase_chip(i, start, end, force_flag);
}
rawnand_erase_special_block();
clean_physic_info();
aw_nand_info.boot->uboot_start_block = uboot_start_block;
aw_nand_info.boot->uboot_next_block = uboot_next_block;
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int rawnand_dragonborad_test_one(unsigned char *buf, unsigned char *oob, unsigned int blk_num)
{
int ret;
unsigned int j;
unsigned char oob_buf[64];
struct _nand_physic_op_par lnpo;
struct nand_chip_info *nci;
// RAWNAND_DBG("dragonborad test in one block!\n");
nci = g_nctri->nci;
lnpo.chip = 0;
lnpo.block = blk_num;
lnpo.page = 0;
nand_wait_all_rb_ready();
ret = nci->nand_physic_erase_block(&lnpo);
if (ret) {
RAWNAND_ERR("Fail in erasing block %d!\n", lnpo.block);
return 0;
}
for (j = 0; j < nci->page_cnt_per_blk; j++) {
lnpo.chip = 0;
lnpo.block = blk_num;
lnpo.page = j;
lnpo.sect_bitmap = nci->sector_cnt_per_page;
lnpo.sdata = oob;
lnpo.slen = 64;
lnpo.mdata = buf;
nand_wait_all_rb_ready();
if (nci->nand_physic_write_page(&lnpo) != 0) {
RAWNAND_ERR("Warning. Fail in writing page %d in block %d.\n", lnpo.page, lnpo.block);
}
}
for (j = 0; j < nci->page_cnt_per_blk; j++) {
lnpo.chip = 0;
lnpo.block = blk_num;
lnpo.page = j;
lnpo.sdata = (unsigned char *)oob_buf;
lnpo.sect_bitmap = nci->sector_cnt_per_page;
lnpo.slen = 64;
lnpo.mdata = buf;
memset(oob_buf, 0xff, 64);
if (nci->nand_physic_read_page(&lnpo) != 0) {
RAWNAND_ERR("Warning. Fail in read page %d in block %d.\n", j, lnpo.block);
return -1;
}
if ((oob_buf[0] != oob[0]) || (oob_buf[1] != oob[1]) || (oob_buf[2] != oob[2]) || (oob_buf[3] != oob[3])) {
RAWNAND_ERR("oob data error\n!");
return -1;
}
}
nand_wait_all_rb_ready();
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok 1:ecc limit -1:fail
*Note :
*****************************************************************************/
int change_uboot_start_block(struct _boot_info *info, unsigned int start_block)
{
if (nand_secure_storage_block != 0) {
if (info->storage_info.data.support_two_plane == 1) {
info->uboot_start_block = NAND_UBOOT_BLK_START;
info->uboot_next_block = NAND_UBOOT_BLK_START + NAND_UBOOT_BLK_CNT;
info->logic_start_block = (nand_secure_storage_block_bak / 2) + 1 + PHYSIC_RECV_BLOCK / 2;
info->no_use_block = info->logic_start_block;
} else {
info->uboot_start_block = NAND_UBOOT_BLK_START;
info->uboot_next_block = NAND_UBOOT_BLK_START + NAND_UBOOT_BLK_CNT;
info->logic_start_block = nand_secure_storage_block_bak + 1 + PHYSIC_RECV_BLOCK;
info->no_use_block = info->logic_start_block;
}
return 0;
} else {
//first build
RAWNAND_ERR("change_uboot_start_block error!!!! \n");
return -1;
}
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
int rawnand_physic_info_get_one_copy(unsigned int start_block, unsigned int pages_offset, unsigned int *block_per_copy, unsigned int *buf)
{
unsigned int page, block;
unsigned int flag;
unsigned int size_per_page, pages_per_block, lsbblock_size;
unsigned char sdata[64];
int ret;
unsigned int phyinfo_page_cnt, page_cnt;
unsigned int badblk_num = 0;
unsigned int pages_per_phyinfo;
void *tempbuf = NULL;
struct _nand_physic_op_par lnpo;
struct nand_chip_info *nci = g_nctri->nci;
RAWNAND_DBG("physic_info_get_one_copy start!!\n");
size_per_page = nci->sector_cnt_per_page << 9;
pages_per_block = nci->page_cnt_per_blk;
pages_per_phyinfo = PHY_INFO_SIZE / size_per_page;
if (PHY_INFO_SIZE % size_per_page)
pages_per_phyinfo++;
// RAWNAND_DBG("pages_per_phyinfo %d\n",pages_per_phyinfo);
tempbuf = nand_get_temp_buf(32 * 1024);
if (tempbuf == NULL) {
RAWNAND_ERR("tempbuf malloc fail\n");
return -1;
}
page_cnt = 0;
phyinfo_page_cnt = 0;
flag = 0;
for (block = start_block;; block++) {
lnpo.chip = 0;
lnpo.block = block;
lnpo.page = 0;
lnpo.sdata = sdata;
lnpo.sect_bitmap = 0;
lnpo.slen = 64;
lnpo.mdata = NULL;
ret = nci->nand_physic_read_page(&lnpo);
if ((sdata[0] == 0x0)) {
badblk_num++;
RAWNAND_DBG("bad block:chip %d block %d\n", lnpo.chip, lnpo.block);
continue;
}
for (page = 0; page < pages_per_block; page++) {
if (nci->is_lsb_page(page) == 1) {
if (page_cnt >= pages_offset) {
lnpo.chip = 0;
lnpo.block = block;
lnpo.page = page;
lnpo.sdata = sdata;
lnpo.sect_bitmap = nci->sector_cnt_per_page;
lnpo.slen = 64;
lnpo.mdata = (void *)((char *)tempbuf + phyinfo_page_cnt * size_per_page);
RAWNAND_DBG("block %d page %d\n", lnpo.block, lnpo.page);
ret = nci->nand_physic_read_page(&lnpo);
if (ret == ERR_ECC) {
RAWNAND_ERR("ecc err:chip %d block %d page %d\n", lnpo.chip, lnpo.block, lnpo.page);
break;
}
phyinfo_page_cnt++;
if (phyinfo_page_cnt == pages_per_phyinfo) {
flag = 1;
break;
}
}
page_cnt++;
}
}
if (ret == ERR_ECC)
break;
if (flag == 1)
break;
}
memcpy(buf, tempbuf, PHY_INFO_SIZE);
lsbblock_size = nand_get_lsb_block_size();
*block_per_copy = (pages_offset + pages_per_phyinfo) * size_per_page / lsbblock_size + badblk_num;
if (((pages_offset + pages_per_phyinfo) * size_per_page) % lsbblock_size)
*block_per_copy = (*block_per_copy) + 1;
// RAWNAND_DBG("block_per_copy %d pages_offset+pages_per_phyinfo %d\n",*block_per_copy,(pages_offset+pages_per_phyinfo));
if (tempbuf) {
nand_free_temp_buf(tempbuf);
}
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
int rawnand_add_len_to_uboot_tail(unsigned int uboot_size)
{
unsigned int size_per_page, pages_per_uboot, page_no, lsb_pages, page_in_lsb_block;
unsigned int jump_size;
size_per_page = g_nctri->nci->sector_cnt_per_page << 9;
pages_per_uboot = uboot_size / size_per_page;
if (uboot_size % size_per_page)
pages_per_uboot++;
jump_size = size_per_page * pages_per_uboot - uboot_size;
lsb_pages = nand_get_lsb_pages();
page_in_lsb_block = pages_per_uboot % lsb_pages;
if (size_per_page == 8192) {
page_no = nand_get_pageno(page_in_lsb_block + 1);
phyinfo_buf->nand_specialinfo_page = page_no;
phyinfo_buf->nand_specialinfo_offset = 512 * 3;
} else if (size_per_page == 16384) {
page_no = nand_get_pageno(page_in_lsb_block);
phyinfo_buf->nand_specialinfo_page = page_no;
phyinfo_buf->nand_specialinfo_offset = 512 * 19;
}
return (uboot_size + jump_size + PHY_INFO_SIZE);
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return :
*Note :
*****************************************************************************/
int set_hynix_special_info(void)
{
u32 i, chip_cnt;
u8 sum;
u32 len;
u8 *srcbuf;
u8 read_retry_mode;
struct nand_chip_info *nci = g_nsi->nci;
read_retry_mode = (nci->npi->read_retry_type >> 16) & 0xff;
if ((read_retry_mode == 2) || (read_retry_mode == 3)) {
len = 64;
} else if (read_retry_mode == 4) {
len = 32;
} else {
return -1;
}
chip_cnt = 0;
sum = 0;
while (nci != NULL) {
srcbuf = (u8 *)(nci->readretry_value);
for (i = 0; i < len; i++) {
sum += srcbuf[i];
aw_nand_info.boot->nand_special_info.data[i + 2 + chip_cnt * len] = srcbuf[i];
}
chip_cnt++;
nci = nci->nsi_next;
}
aw_nand_info.boot->nand_special_info.data[0] = 0xa5;
for (i = (chip_cnt * len + 2); i < 1024; i++) {
aw_nand_info.boot->nand_special_info.data[i] = 0;
}
aw_nand_info.boot->nand_special_info.data[1] = sum;
return 0;
}