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

1888 lines
55 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
*
*/
#include "rawnand_ops.h"
#include "../../nfd/nand_osal_for_linux.h"
/*#include "../nand_boot.h"*/
#include "../nand-partition3/sunxi_nand_boot.h"
#include "rawnand_chip.h"
#include "controller/ndfc_ops.h"
#include "rawnand.h"
#include "rawnand_base.h"
#include "rawnand_cfg.h"
#include "rawnand_debug.h"
#include "rawnand_ids.h"
#include "rawnand_readretry.h"
extern unsigned int get_row_addr_2(unsigned int page_offset_for_next_blk, unsigned int block, unsigned int page);
struct nand_phy_write_lsb_cache nand_phy_w_cache[NAND_OPEN_BLOCK_CNT] = {
{0},
{0},
};
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_erase_block_start(struct _nand_physic_op_par *npo)
{
int ret;
unsigned int row_addr = 0, col_addr = 0;
struct nand_chip_info *nci = nci_get_from_nsi(g_nsi, npo->chip);
struct nand_controller_info *nctri = nci->nctri;
struct _nctri_cmd_seq *cmd_seq = &nci->nctri->nctri_cmd_seq;
//RAWNAND_DBG("%s: ch: %d chip: %d/%d block: %d/%d \n", __func__, nctri->channel_id, nci->nctri_chip_no, nctri->chip_cnt, npo->block, nci->blk_cnt_per_chip);
if ((nci->nctri_chip_no >= nctri->chip_cnt) || (npo->block >= nci->blk_cnt_per_chip)) {
RAWNAND_ERR("fatal err -0, wrong input parameter, ch: %d chip: %d/%d block: %d/%d \n", nctri->channel_id, nci->nctri_chip_no, nctri->chip_cnt, npo->block, nci->blk_cnt_per_chip);
return ERR_NO_10;
}
//wait nand ready before erase
nand_read_chip_status_ready(nci);
nand_enable_chip(nci);
ndfc_clean_cmd_seq(cmd_seq);
// cmd1: 0x60
cmd_seq->cmd_type = CMD_TYPE_NORMAL;
cmd_seq->nctri_cmd[0].cmd = CMD_ERASE_CMD1;
cmd_seq->nctri_cmd[0].cmd_valid = 1;
cmd_seq->nctri_cmd[0].cmd_send = 1;
if (nci->id[0] == 0xec &&
nci->id[1] == 0xde &&
nci->id[2] == 0x94 &&
nci->id[3] == 0xc3 &&
nci->id[4] == 0xa4 &&
nci->id[5] == 0xca) {
row_addr = get_row_addr_2(nci->page_offset_for_next_blk, npo->block, npo->page);
} else {
row_addr = get_row_addr(nci->page_offset_for_next_blk, npo->block, npo->page);
}
if (nci->npi->operation_opt & NAND_WITH_TWO_ROW_ADR) {
cmd_seq->nctri_cmd[0].cmd_acnt = 2;
fill_cmd_addr(col_addr, 0, row_addr, 2, cmd_seq->nctri_cmd[0].cmd_addr);
} else {
cmd_seq->nctri_cmd[0].cmd_acnt = 3;
fill_cmd_addr(col_addr, 0, row_addr, 3, cmd_seq->nctri_cmd[0].cmd_addr);
}
// cmd2: 0xD0
cmd_seq->nctri_cmd[1].cmd = CMD_ERASE_CMD2;
cmd_seq->nctri_cmd[1].cmd_valid = 1;
cmd_seq->nctri_cmd[1].cmd_send = 1;
cmd_seq->nctri_cmd[1].cmd_wait_rb = 0;
ret = ndfc_execute_cmd(nci->nctri, cmd_seq);
nand_disable_chip(nci);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_erase_block(struct _nand_physic_op_par *npo)
{
int ret;
//unsigned char status;
struct nand_chip_info *nci = nci_get_from_nsi(g_nsi, npo->chip);
ret = generic_erase_block_start(npo);
if (ret != 0) {
RAWNAND_ERR("erase_block wrong1\n");
return ret;
}
ret = nand_read_chip_status_ready(nci);
if (ret != 0) {
RAWNAND_ERR("erase_block wrong2\n");
}
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_read_page_start(struct _nand_physic_op_par *npo)
{
struct nand_chip_info *nci = nci_get_from_nsi(g_nsi, npo->chip);
struct _nctri_cmd_seq *cmd_seq = &nci->nctri->nctri_cmd_seq;
u32 row_addr = 0, col_addr = 0;
u32 def_spare[32];
int ret;
u32 ecc_block, sect_bitmap = 0;
if (npo->sect_bitmap % 2)
npo->sect_bitmap += 1;
if (npo->sect_bitmap == 0 || npo->sect_bitmap > nci->sector_cnt_per_page)
ecc_block = nci->sector_cnt_per_page / 2;
else
ecc_block = npo->sect_bitmap / 2;
sect_bitmap = ((unsigned int)1 << (ecc_block - 1)) | (((unsigned int)1 << (ecc_block - 1)) - 1);
//wait nand ready before read
nand_read_chip_status_ready(nci);
//set ecc mode & randomize
ndfc_set_ecc_mode(nci->nctri, nci->ecc_mode);
ndfc_enable_ecc(nci->nctri, 1, nci->randomizer);
if (nci->randomizer) {
ndfc_set_rand_seed(nci->nctri, npo->page);
ndfc_enable_randomize(nci->nctri);
}
nand_enable_chip(nci);
ndfc_clean_cmd_seq(cmd_seq);
//command
set_default_batch_read_cmd_seq(cmd_seq);
nci->nctri->random_addr_num = nci->random_addr_num;
nci->nctri->random_cmd2_send_flag = nci->random_cmd2_send_flag;
//address
if (nci->id[0] == 0xec &&
nci->id[1] == 0xde &&
nci->id[2] == 0x94 &&
nci->id[3] == 0xc3 &&
nci->id[4] == 0xa4 &&
nci->id[5] == 0xca) {
row_addr = get_row_addr_2(nci->page_offset_for_next_blk, npo->block, npo->page);
} else {
row_addr = get_row_addr(nci->page_offset_for_next_blk, npo->block, npo->page);
}
if (nci->npi->operation_opt & NAND_WITH_TWO_ROW_ADR) {
cmd_seq->nctri_cmd[0].cmd_acnt = 4;
fill_cmd_addr(col_addr, 2, row_addr, 2, cmd_seq->nctri_cmd[0].cmd_addr);
} else {
cmd_seq->nctri_cmd[0].cmd_acnt = 5;
fill_cmd_addr(col_addr, 2, row_addr, 3, cmd_seq->nctri_cmd[0].cmd_addr);
}
//data
cmd_seq->nctri_cmd[0].cmd_trans_data_nand_bus = 1;
if (npo->mdata != NULL) {
cmd_seq->nctri_cmd[0].cmd_swap_data = 1;
cmd_seq->nctri_cmd[0].cmd_swap_data_dma = 1;
} else {
//don't swap main data with host memory
cmd_seq->nctri_cmd[0].cmd_swap_data = 0;
cmd_seq->nctri_cmd[0].cmd_swap_data_dma = 0;
}
cmd_seq->nctri_cmd[0].cmd_direction = 0; //read
cmd_seq->nctri_cmd[0].cmd_mdata_addr = npo->mdata;
/*
*cmd_seq->nctri_cmd[0].cmd_mdata_len = nci->sector_cnt_per_page << 9;
*cmd_seq->nctri_cmd[0].cmd_data_block_mask = full_bitmap;
*/
cmd_seq->nctri_cmd[0].cmd_mdata_len = ecc_block << 10;
cmd_seq->nctri_cmd[0].cmd_data_block_mask = sect_bitmap;
if ((npo->mdata == NULL) && (npo->sdata != NULL) && (npo->sect_bitmap == 0)) {
if (nci->sector_cnt_per_page > 4) {
cmd_seq->nctri_cmd[0].cmd_mdata_len = 2 << 9; //12 byte spare data in 1K
cmd_seq->nctri_cmd[0].cmd_data_block_mask = 0x1;
} else {
cmd_seq->nctri_cmd[0].cmd_mdata_len = 4 << 9;
cmd_seq->nctri_cmd[0].cmd_data_block_mask = 0x3;
}
}
ndfc_set_user_data_len_cfg(nci->nctri, nci->sdata_bytes_per_page);
ndfc_set_user_data_len(nci->nctri);
memset(def_spare, 0x99, 128);
ndfc_set_spare_data(nci->nctri, (u8 *)def_spare, nci->sdata_bytes_per_page);
ret = batch_cmd_io_send(nci->nctri, cmd_seq);
if (ret) {
RAWNAND_ERR("read page start, batch cmd io send error:chip:%d block:%d page:%d sect_bitmap:%d mdata:%p slen:%d: !\n", npo->chip, npo->block, npo->page, npo->sect_bitmap, npo->mdata, npo->slen);
nand_disable_chip(nci);
return ret;
}
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_read_page_end_not_retry(struct _nand_physic_op_par *npo)
{
s32 ecc_sta = 0, ret = 0;
uchar spare[64];
struct nand_chip_info *nci = nci_get_from_nsi(g_nsi, npo->chip);
struct _nctri_cmd_seq *cmd_seq = &nci->nctri->nctri_cmd_seq;
ret = _batch_cmd_io_wait(nci->nctri, cmd_seq);
if (ret) {
RAWNAND_ERR("read page end, batch cmd io wait error:chip:%d block:%d page:%d sect_bitmap:%d mdata:%p slen:%d: !\n", npo->chip, npo->block, npo->page, npo->sect_bitmap, npo->mdata, npo->slen);
goto ERROR;
}
//check ecc
ecc_sta = ndfc_check_ecc(nci->nctri, nci->sector_cnt_per_page >> nci->ecc_sector);
//get spare data
ndfc_get_spare_data(nci->nctri, (u8 *)spare, nci->sdata_bytes_per_page);
if (npo->slen != 0) {
memcpy(npo->sdata, spare, npo->slen);
}
//update ecc status and spare data
//RAWNAND_DBG("npo: 0x%x %d 0x%x\n",npo, npo->slen, npo->sdata);
ret = ndfc_update_ecc_sta_and_spare_data(npo, ecc_sta, spare);
ERROR:
//disable ecc mode & randomize
ndfc_disable_ecc(nci->nctri);
if (nci->randomizer) {
ndfc_disable_randomize(nci->nctri);
}
nand_disable_chip(nci);
return ret; //ecc status
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_read_page_end(struct _nand_physic_op_par *npo)
{
int ret;
ret = df_read_page_end.read_page_end(npo);
if (ret == ECC_LIMIT) {
RAWNAND_DBG("read page ecc limit,chip=%d block=%d page=%d\n", npo->chip, npo->block, npo->page);
} else if (ret != 0) {
RAWNAND_ERR("ecc err!read page, read page end error %d,chip=%d block=%d page=%d\n", ret, npo->chip, npo->block, npo->page);
} else {
;
}
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_read_page(struct _nand_physic_op_par *npo)
{
int ret = 0;
struct nand_chip_info *nci = nci_get_from_nsi(g_nsi, npo->chip);
struct nand_controller_info *nctri = nci->nctri;
//RAWNAND_DBG("%s: ch: %d chip: %d/%d block: %d/%d page: %d/%d\n", __func__, nctri->channel_id, nci->nctri_chip_no, nctri->chip_cnt, npo->block, nci->blk_cnt_per_chip, npo->page, nci->page_cnt_per_blk);
if ((nci->nctri_chip_no >= nctri->chip_cnt) || (npo->block >= nci->blk_cnt_per_chip) || (npo->page >= nci->page_cnt_per_blk)) {
RAWNAND_ERR("fatal err -0, wrong input parameter, ch: %d chip: %d/%d block: %d/%d page: %d/%d\n", nctri->channel_id, nci->nctri_chip_no, nctri->chip_cnt, npo->block, nci->blk_cnt_per_chip, npo->page, nci->page_cnt_per_blk);
return ERR_NO_11;
}
if ((npo->mdata == NULL) && (npo->sdata == NULL) && (npo->sect_bitmap)) {
RAWNAND_ERR("fatal err -1, wrong input parameter, mdata: %p sdata: %p sect_bitmap: 0x%x\n", npo->mdata, npo->sdata, npo->sect_bitmap);
return ERR_NO_12;
}
if ((npo->mdata == NULL) && (npo->sdata == NULL) && (npo->sect_bitmap == 0)) {
//RAWNAND_DBG("warning -0, mdata: 0x%08x sdata: 0x%08x sect_bitmap: 0x%x\n",npo->mdata, npo->sdata, npo->sect_bitmap);
return 0;
}
ret = generic_read_page_start(npo);
if (ret) {
RAWNAND_ERR("read page, read page start error %d\n", ret);
return ret;
}
ret = generic_read_page_end(npo);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_write_page_start(struct _nand_physic_op_par *npo, int plane_no)
{
uchar spare[64];
struct nand_chip_info *nci = nci_get_from_nsi(g_nsi, npo->chip);
struct _nctri_cmd_seq *cmd_seq = &nci->nctri->nctri_cmd_seq;
u32 row_addr = 0, col_addr = 0;
int dummy_byte;
unsigned int ecc_block, sect_bitmap = 0;
int ret;
if (npo->mdata == NULL) {
RAWNAND_ERR("write page start, input parameter error!\n");
return ERR_NO_13;
}
if (npo->sect_bitmap == 0 || npo->sect_bitmap > nci->sector_cnt_per_page)
ecc_block = nci->sector_cnt_per_page / 2;
else
ecc_block = npo->sect_bitmap / 2;
sect_bitmap = ((unsigned int)1 << (ecc_block - 1)) | (((unsigned int)1 << (ecc_block - 1)) - 1);
if ((plane_no == 0) || (plane_no == 1))
//wait nand ready before write
nand_read_chip_status_ready(nci);
#if 0
if ((nci->driver_no == 1) && (hynix16nm_read_retry_mode == 0x4) && (nci->retry_count != 0)) {
hynix16nm_set_default_param(nci);
nci->retry_count = 0;
}
#endif
// RAWNAND_DBG("chip:%d block:%d page: %d buf:0x%x%x spare:0x%x%x%x \n",npo->chip,npo->block,npo->page,npo->mdata[0],npo->mdata[1],npo->sdata[2],npo->sdata[3],npo->sdata[4]);
// if((nci->driver_no == 2)&&((0x2 == hynix20nm_read_retry_mode)||(0x3 == hynix20nm_read_retry_mode))&&(nci->retry_count != 0))
// {
// hynix20nm_set_default_param(nci);
// nci->retry_count = 0;
// }
//get spare data
memset(spare, 0xff, 64);
if (npo->slen != 0) {
memcpy(spare, npo->sdata, npo->slen);
}
nand_enable_chip(nci);
ndfc_clean_cmd_seq(cmd_seq);
ndfc_set_spare_data(nci->nctri, (u8 *)spare, nci->sdata_bytes_per_page);
//set ecc mode & randomize
if (nci->randomizer) {
ndfc_set_rand_seed(nci->nctri, npo->page);
ndfc_enable_randomize(nci->nctri);
}
ndfc_set_ecc_mode(nci->nctri, nci->ecc_mode);
ndfc_enable_ecc(nci->nctri, 1, nci->randomizer);
nci->nctri->current_op_type = 1;
dummy_byte = get_dummy_byte(nci->nand_real_page_size, nci->ecc_mode, nci->sector_cnt_per_page / 2, nci->sdata_bytes_per_page);
if (dummy_byte > 0) {
ndfc_set_dummy_byte(nci->nctri, dummy_byte);
ndfc_enable_dummy_byte(nci->nctri);
}
nci->nctri->random_addr_num = nci->random_addr_num;
nci->nctri->random_cmd2_send_flag = nci->random_cmd2_send_flag;
if (nci->random_cmd2_send_flag) {
nci->nctri->random_cmd2 = get_random_cmd2(npo);
}
//command
if (plane_no == 0) {
set_default_batch_write_cmd_seq(cmd_seq, CMD_WRITE_PAGE_CMD1, CMD_WRITE_PAGE_CMD2);
} else if (plane_no == 1) {
//set_default_batch_write_cmd_seq(cmd_seq,CMD_WRITE_PAGE_CMD1,0x11);
set_default_batch_write_cmd_seq(cmd_seq,
nci->opt_phy_op_par->instr.multi_plane_write_instr[0],
nci->opt_phy_op_par->instr.multi_plane_write_instr[1]);
//set_default_batch_write_cmd_seq(cmd_seq,CMD_WRITE_PAGE_CMD1,CMD_WRITE_PAGE_CMD2);
} else {
//set_default_batch_write_cmd_seq(cmd_seq,0x81,CMD_WRITE_PAGE_CMD2);
set_default_batch_write_cmd_seq(cmd_seq,
nci->opt_phy_op_par->instr.multi_plane_write_instr[2],
nci->opt_phy_op_par->instr.multi_plane_write_instr[3]);
//set_default_batch_write_cmd_seq(cmd_seq,CMD_WRITE_PAGE_CMD1,CMD_WRITE_PAGE_CMD2);
}
//address
if (nci->id[0] == 0xec &&
nci->id[1] == 0xde &&
nci->id[2] == 0x94 &&
nci->id[3] == 0xc3 &&
nci->id[4] == 0xa4 &&
nci->id[5] == 0xca) {
row_addr = get_row_addr_2(nci->page_offset_for_next_blk, npo->block, npo->page);
} else {
row_addr = get_row_addr(nci->page_offset_for_next_blk, npo->block, npo->page);
}
if (nci->npi->operation_opt & NAND_WITH_TWO_ROW_ADR) {
cmd_seq->nctri_cmd[0].cmd_acnt = 4;
fill_cmd_addr(col_addr, 2, row_addr, 2, cmd_seq->nctri_cmd[0].cmd_addr);
} else {
cmd_seq->nctri_cmd[0].cmd_acnt = 5;
fill_cmd_addr(col_addr, 2, row_addr, 3, cmd_seq->nctri_cmd[0].cmd_addr);
}
//data
cmd_seq->nctri_cmd[0].cmd_trans_data_nand_bus = 1;
cmd_seq->nctri_cmd[0].cmd_swap_data = 1;
cmd_seq->nctri_cmd[0].cmd_swap_data_dma = 1;
cmd_seq->nctri_cmd[0].cmd_direction = 1; //write
// cmd_seq->nctri_cmd[0].cmd_mdata_addr = npo->mdata;
cmd_seq->nctri_cmd[0].cmd_mdata_addr = npo->mdata;
cmd_seq->nctri_cmd[0].cmd_data_block_mask = sect_bitmap;
/*cmd_seq->nctri_cmd[0].cmd_mdata_len = nci->sector_cnt_per_page << 9;*/
cmd_seq->nctri_cmd[0].cmd_mdata_len = ecc_block << 10;
ndfc_set_user_data_len_cfg(nci->nctri, nci->sdata_bytes_per_page);
ndfc_set_user_data_len(nci->nctri);
ret = batch_cmd_io_send(nci->nctri, cmd_seq);
if (ret) {
RAWNAND_ERR("read2 page start, batch cmd io send error:chip:%d block:%d page:%d sect_bitmap:%d mdata:%p slen:%d: !\n", npo->chip, npo->block, npo->page, npo->sect_bitmap, npo->mdata, npo->slen);
nand_disable_chip(nci);
return ret;
}
return 0;
}
int generic_write_page_end(struct _nand_physic_op_par *npo)
{
s32 ret = 0;
struct nand_chip_info *nci = nci_get_from_nsi(g_nsi, npo->chip);
struct _nctri_cmd_seq *cmd_seq = &nci->nctri->nctri_cmd_seq;
ret = _batch_cmd_io_wait(nci->nctri, cmd_seq);
if (ret) {
RAWNAND_ERR("write page end, batch cmd io wait error:chip:%d block:%d page:%d sect_bitmap:%d mdata:%p slen:%d: !\n", npo->chip, npo->block, npo->page, npo->sect_bitmap, npo->mdata, npo->slen);
}
//disable ecc mode & randomize
ndfc_disable_ecc(nci->nctri);
if (nci->randomizer) {
ndfc_disable_randomize(nci->nctri);
}
ndfc_set_dummy_byte(nci->nctri, 0);
ndfc_disable_dummy_byte(nci->nctri);
nci->nctri->random_cmd2_send_flag = 0;
nci->nctri->current_op_type = 0;
nand_disable_chip(nci);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_write_page(struct _nand_physic_op_par *npo)
{
int ret = 0;
struct nand_chip_info *nci = nci_get_from_nsi(g_nsi, npo->chip);
struct nand_controller_info *nctri = nci->nctri;
//RAWNAND_DBG("%s: ch: %d chip: %d/%d block: %d/%d page: %d/%d\n", __func__, nctri->channel_id, nci->nctri_chip_no, nctri->chip_cnt, npo->block, nci->blk_cnt_per_chip, npo->page, nci->page_cnt_per_blk);
if ((nci->nctri_chip_no >= nctri->chip_cnt) || (npo->block >= nci->blk_cnt_per_chip) || (npo->page >= nci->page_cnt_per_blk)) {
RAWNAND_ERR("wfatal err -0, wrong input parameter, ch: %d chip: %d/%d block: %d/%d page: %d/%d\n", nctri->channel_id, nci->nctri_chip_no, nctri->chip_cnt, npo->block, nci->blk_cnt_per_chip, npo->page, nci->page_cnt_per_blk);
return ERR_NO_14;
}
/*
*if (npo->sect_bitmap != nci->sector_cnt_per_page) {
* RAWNAND_ERR("wFatal err -2, wrong input parameter, unaligned write page SectBitmap: 0x%x/0x%x\n", npo->sect_bitmap, nci->sector_cnt_per_page);
* return ERR_NO_15;
*}
*/
ret = generic_write_page_start(npo, 0);
if (ret) {
RAWNAND_ERR("write page, write page start error %d\n", ret);
return ret;
}
ret = generic_write_page_end(npo);
if (ret) {
RAWNAND_ERR("write page, write page end error %d\n", ret);
return ret;
}
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_read_two_plane_page_start(struct _nand_physic_op_par *npo, struct _nand_physic_op_par *npo2)
{
int ret;
struct nand_chip_info *nci = nci_get_from_nsi(g_nsi, npo->chip);
struct _nctri_cmd_seq *cmd_seq = &nci->nctri->nctri_cmd_seq;
u32 row_addr = 0, col_addr = 0;
nand_enable_chip(nci);
ndfc_clean_cmd_seq(cmd_seq);
cmd_seq->cmd_type = CMD_TYPE_NORMAL;
cmd_seq->nctri_cmd[0].cmd_valid = 1;
cmd_seq->nctri_cmd[0].cmd = nci->opt_phy_op_par->instr.multi_plane_read_instr[0]; //multi_plane_read_instr_cmd[0];
cmd_seq->nctri_cmd[0].cmd_send = 1;
if (nci->id[0] == 0xec &&
nci->id[1] == 0xde &&
nci->id[2] == 0x94 &&
nci->id[3] == 0xc3 &&
nci->id[4] == 0xa4 &&
nci->id[5] == 0xca) {
row_addr = get_row_addr_2(nci->page_offset_for_next_blk, npo->block, npo->page);
} else {
row_addr = get_row_addr(nci->page_offset_for_next_blk, npo->block, npo->page);
}
if (nci->npi->operation_opt & NAND_WITH_TWO_ROW_ADR) {
cmd_seq->nctri_cmd[0].cmd_acnt = 2;
fill_cmd_addr(col_addr, 0, row_addr, 2, cmd_seq->nctri_cmd[0].cmd_addr);
} else {
cmd_seq->nctri_cmd[0].cmd_acnt = 3;
fill_cmd_addr(col_addr, 0, row_addr, 3, cmd_seq->nctri_cmd[0].cmd_addr);
}
cmd_seq->nctri_cmd[1].cmd_valid = 1;
cmd_seq->nctri_cmd[1].cmd = nci->opt_phy_op_par->instr.multi_plane_read_instr[2]; //multi_plane_read_instr_cmd[0];
cmd_seq->nctri_cmd[1].cmd_send = 1;
if (nci->id[0] == 0xec &&
nci->id[1] == 0xde &&
nci->id[2] == 0x94 &&
nci->id[3] == 0xc3 &&
nci->id[4] == 0xa4 &&
nci->id[5] == 0xca) {
row_addr = get_row_addr_2(nci->page_offset_for_next_blk, npo->block, npo->page);
} else {
row_addr = get_row_addr(nci->page_offset_for_next_blk, npo2->block, npo2->page);
}
if (nci->npi->operation_opt & NAND_WITH_TWO_ROW_ADR) {
cmd_seq->nctri_cmd[1].cmd_acnt = 2;
fill_cmd_addr(col_addr, 0, row_addr, 2, cmd_seq->nctri_cmd[1].cmd_addr);
} else {
cmd_seq->nctri_cmd[1].cmd_acnt = 3;
fill_cmd_addr(col_addr, 0, row_addr, 3, cmd_seq->nctri_cmd[1].cmd_addr);
}
cmd_seq->nctri_cmd[2].cmd_valid = 1;
cmd_seq->nctri_cmd[2].cmd = nci->opt_phy_op_par->instr.multi_plane_read_instr[3];
cmd_seq->nctri_cmd[2].cmd_send = 1;
cmd_seq->nctri_cmd[2].cmd_wait_rb = 1;
ret = ndfc_execute_cmd(nci->nctri, cmd_seq);
if (ret) {
RAWNAND_ERR("read_two_plane_page_start failed!\n");
}
nand_disable_chip(nci);
return ret;
}
int generic_read_two_plane_page_end(struct _nand_physic_op_par *npo)
{
int ret = 0;
// int ecc_sta = 0;
// struct nand_chip_info *nci = nci_get_from_nsi(g_nsi, npo->chip);
// struct _nctri_cmd_seq *cmd_seq = &nci->nctri->nctri_cmd_seq;
// u32 row_addr = 0, col_addr = 0;
// u32 def_spare[32];
//
// nand_enable_chip(nci);
//
// //set ecc mode & randomize
// ndfc_set_ecc_mode(nci->nctri, nci->ecc_mode);
// ndfc_enable_ecc(nci->nctri, 1, nci->randomizer);
// if (nci->randomizer)
// {
// ndfc_set_rand_seed(nci->nctri, npo->page);
// ndfc_enable_randomize(nci->nctri);
// }
//
// ndfc_clean_cmd_seq(cmd_seq);
// cmd_seq->cmd_type = CMD_TYPE_NORMAL;
//
// cmd_seq->nctri_cmd[0].cmd_valid = 1;
// cmd_seq->nctri_cmd[0].cmd = 0x00;
// cmd_seq->nctri_cmd[0].cmd_send = 1;
// row_addr = get_row_addr(nci->page_offset_for_next_blk, npo->block, npo->page);
// cmd_seq->nctri_cmd[0].cmd_acnt = 5;
// fill_cmd_addr(col_addr, 2, row_addr, 3, cmd_seq->nctri_cmd[0].cmd_addr);
// ret = ndfc_execute_cmd(nci->nctri, cmd_seq);
// if (ret)
// {
// RAWNAND_ERR("read_two_plane_page_start failed!\n");
// nand_disable_chip(nci);
// return ret;
// }
//
// //command
// ndfc_clean_cmd_seq(cmd_seq);
//
// cmd_seq->cmd_type = CMD_TYPE_BATCH;
// cmd_seq->ecc_layout = ECC_LAYOUT_INTERLEAVE;
//
// cmd_seq->nctri_cmd[0].cmd = 0x05;
// cmd_seq->nctri_cmd[1].cmd = 0xe0;
// cmd_seq->nctri_cmd[2].cmd = 0x05;
// cmd_seq->nctri_cmd[3].cmd = 0xe0;
//
// //address
// row_addr = get_row_addr(nci->page_offset_for_next_blk, npo->block, npo->page);
// cmd_seq->nctri_cmd[0].cmd_acnt = 2;
// fill_cmd_addr(col_addr, 2, row_addr, 0, cmd_seq->nctri_cmd[0].cmd_addr);
//
// //data
// cmd_seq->nctri_cmd[0].cmd_trans_data_nand_bus = 1;
// if (npo->mdata != NULL)
// {
// cmd_seq->nctri_cmd[0].cmd_swap_data = 1;
// cmd_seq->nctri_cmd[0].cmd_swap_data_dma = 1;
// }
// else
// {
// //don't swap main data with host memory
// cmd_seq->nctri_cmd[0].cmd_swap_data = 0;
// cmd_seq->nctri_cmd[0].cmd_swap_data_dma = 0;
// }
// cmd_seq->nctri_cmd[0].cmd_direction = 0; //read
// cmd_seq->nctri_cmd[0].cmd_mdata_addr = npo->mdata;
// cmd_seq->nctri_cmd[0].cmd_mdata_len = nci->sector_cnt_per_page << 9;
//
// memset(def_spare, 0x99, 128);
// ndfc_set_spare_data(nci->nctri, (u32*)def_spare, MAX_ECC_BLK_CNT);
// ret = rawnand_diff_func->cmd_ops.batch_cmd_io_send(nci->nctri, cmd_seq);
// if(ret)
// {
// RAWNAND_ERR("read3 page start, batch cmd io send error:chip:%d block:%d page:%d sect_bitmap:%d mdata:%x slen:%d: !\n",npo->chip,npo->block,npo->page,npo->sect_bitmap,npo->mdata,npo->slen);
// nand_disable_chip(nci);
// return ret;
// }
// ret = rawnand_diff_func->batch_cmd_io_wait(nci->nctri, cmd_seq);
// if (ret)
// {
// RAWNAND_ERR("read2 page end, batch cmd io wait error:chip:%d block:%d page:%d sect_bitmap:%d mdata:%x slen:%d: !\n",npo->chip,npo->block,npo->page,npo->sect_bitmap,npo->mdata,npo->slen);
// }
//
// //check ecc
// ecc_sta = rawnand_diff_func->ndfc_check_ecc(nci->nctri, nci->sector_cnt_per_page>>nci->ecc_sector);
// //get spare data
// ndfc_get_spare_data(nci->nctri, (u32*)def_spare, nci->sector_cnt_per_page>>nci->ecc_sector);
//
// if (npo->slen != 0)
// {
// memcpy(npo->sdata, def_spare, npo->slen);
// }
// //update ecc status and spare data
// //RAWNAND_DBG("npo: 0x%x %d 0x%x\n",npo, npo->slen, npo->sdata);
// ret = ndfc_update_ecc_sta_and_spare_data(npo, ecc_sta, def_spare);
//
// //disable ecc mode & randomize
// ndfc_disable_ecc(nci->nctri);
// if (nci->randomizer)
// {
// ndfc_disable_randomize(nci->nctri);
// }
//
// nand_disable_chip(nci);
return ret;
}
int generic_read_two_plane_page(struct _nand_physic_op_par *npo)
{
int ret = 0;
int ret0 = 0, ret1 = 0;
uchar spare[64];
int i;
int len_off = 0;
struct _nand_physic_op_par npo1;
struct _nand_physic_op_par npo2;
struct nand_chip_info *nci = nci_get_from_nsi(g_nsi, npo->chip);
//struct _nctri_cmd_seq* cmd_seq = &nci->nctri->nctri_cmd_seq;
npo1.chip = npo->chip;
npo1.block = (npo->block << 1);
npo1.page = npo->page;
/*npo1.sect_bitmap = nci->sector_cnt_per_page;*/
npo1.sect_bitmap = min(nci->sector_cnt_per_page, npo->sect_bitmap);;
npo1.mdata = npo->mdata;
npo1.sdata = npo->sdata;
npo1.slen = npo->slen;
if ((npo1.slen == 0) || (npo1.sdata == NULL)) {
npo1.sdata = spare;
npo1.slen = nci->sdata_bytes_per_page;
}
npo2.chip = npo->chip;
npo2.block = (npo->block << 1) + 1;
npo2.page = npo->page;
/*npo2.sect_bitmap = nci->sector_cnt_per_page;*/
len_off = npo->sect_bitmap - nci->sector_cnt_per_page;
npo2.sect_bitmap = (len_off > 0) ? len_off : 0;
if (npo->mdata != NULL) {
npo2.mdata = npo->mdata + (nci->sector_cnt_per_page << 9);
} else {
npo2.mdata = NULL;
}
npo2.sdata = spare;
npo2.slen = npo->slen;
if ((npo2.slen == 0) || (npo2.sdata == NULL)) {
npo2.sdata = spare;
npo2.slen = nci->sdata_bytes_per_page;
}
if ((npo->mdata == NULL) && (npo->sect_bitmap == 0)) {
npo1.sect_bitmap = 0;
npo2.sect_bitmap = 0;
npo2.sdata = NULL;
npo2.slen = 0;
}
if (nci->sector_cnt_per_page == 4) {
npo1.sdata = spare;
npo2.sdata = &spare[8];
npo2.slen = nci->sdata_bytes_per_page;
}
// ret |= generic_read_two_plane_page_start(&npo1,&npo2);
// ret |= generic_read_two_plane_page_end(&npo1);
// ret |= generic_read_two_plane_page_end(&npo2);
ret0 = generic_read_page(&npo1);
ret1 = generic_read_page(&npo2);
if (nci->sector_cnt_per_page == 4) {
for (i = 0; i < 16; i++) {
if (i < 8) {
*((unsigned char *)npo->sdata + i) = spare[i];
} else if (i == 15) {
*((unsigned char *)npo->sdata + i) = 0xff;
} else {
*((unsigned char *)npo->sdata + i) = spare[i + 1];
}
}
}
if ((ret0 == ERR_ECC) || (ret1 == ERR_ECC))
ret = ERR_ECC;
else if ((ret0 == ECC_LIMIT) || (ret1 == ECC_LIMIT))
ret = ECC_LIMIT;
else
ret = ret0 | ret1;
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_write_two_plane_page(struct _nand_physic_op_par *npo)
{
int ret = 0;
uchar spare[64];
int i;
struct _nand_physic_op_par npo1;
struct _nand_physic_op_par npo2;
struct nand_chip_info *nci = nci_get_from_nsi(g_nsi, npo->chip);
//struct _nctri_cmd_seq* cmd_seq = &nci->nctri->nctri_cmd_seq;
npo1.chip = npo->chip;
npo1.block = npo->block << 1;
npo1.page = npo->page;
npo1.sect_bitmap = nci->sector_cnt_per_page;
npo1.mdata = npo->mdata;
npo1.sdata = npo->sdata;
npo1.slen = npo->slen;
npo2.chip = npo->chip;
npo2.block = (npo->block << 1) + 1;
npo2.page = npo->page;
npo2.sect_bitmap = nci->sector_cnt_per_page;
npo2.mdata = npo->mdata + (nci->sector_cnt_per_page << 9);
npo2.sdata = npo->sdata;
npo2.slen = npo->slen;
if (nci->sector_cnt_per_page == 4) {
for (i = 0; i < 16; i++) {
if (i < 8) {
spare[i] = *((unsigned char *)npo->sdata + i);
} else if (i == 8) {
spare[i] = 0xff;
} else {
spare[i] = *((unsigned char *)npo->sdata + i - 1);
}
}
npo1.sdata = spare;
npo2.sdata = &spare[8];
}
// if(nci->driver_no == 2)
// {
// ret |= generic_write_page_start(&npo1,0);
// ret |= generic_write_page_end(&npo1);
//
// ret |= generic_write_page_start(&npo2,0);
// ret |= generic_write_page_end(&npo2);
// }
// else
{
ret |= generic_write_page_start(&npo1, 1);
ret |= generic_write_page_end(&npo1);
ret |= generic_write_page_start(&npo2, 2);
ret |= generic_write_page_end(&npo2);
}
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:good block -1:bad block
*Note :
*****************************************************************************/
int generic_bad_block_check(struct _nand_physic_op_par *npo)
{
int num, start_page, i;
unsigned char spare[64];
struct _nand_physic_op_par lnpo;
struct nand_chip_info *nci = nci_get_from_nsi(g_nsi, npo->chip);
struct nand_controller_info *nctri = nci->nctri;
//RAWNAND_DBG("%s: ch: %d chip: %d/%d block: %d/%d \n", __func__, nctri->channel_id, nci->nctri_chip_no, nctri->chip_cnt, npo->block, nci->blk_cnt_per_chip);
if ((nci->nctri_chip_no >= nctri->chip_cnt) || (npo->block >= nci->blk_cnt_per_chip)) {
RAWNAND_ERR("cfatal err -0, wrong input parameter, ch: %d chip: %d/%d block: %d/%d \n", nctri->channel_id, nci->nctri_chip_no, nctri->chip_cnt, npo->block, nci->blk_cnt_per_chip);
return ERR_NO_16;
}
lnpo.chip = npo->chip;
lnpo.block = npo->block;
lnpo.mdata = NULL;
lnpo.sdata = spare;
lnpo.sect_bitmap = npo->sect_bitmap;
lnpo.slen = nci->sdata_bytes_per_page;
if (nci->bad_block_flag_position == FIRST_PAGE) {
//the bad block flag is in the first page, same as the logical information, just read 1st page is ok
start_page = 0;
num = 1;
} else if (nci->bad_block_flag_position == FIRST_TWO_PAGES) {
//the bad block flag is in the first page or the second page, need read the first page and the second page
start_page = 0;
num = 2;
} else if (nci->bad_block_flag_position == LAST_PAGE) {
//the bad block flag is in the last page, need read the first page and the last page
start_page = nci->page_cnt_per_blk - 1;
num = 1;
} else if (nci->bad_block_flag_position == LAST_TWO_PAGES) {
//the bad block flag is in the last 2 page, so, need read the first page, the last page and the last-1 page
start_page = nci->page_cnt_per_blk - 2;
num = 2;
} else {
RAWNAND_ERR("bad block check, unknown bad block flag position\n");
return ERR_NO_17;
}
//read and check 1st page
lnpo.page = 0;
generic_read_page(&lnpo);
if (lnpo.sdata[0] != 0xff) {
RAWNAND_ERR("find a bad block: %d %d %d ", lnpo.chip, lnpo.block, lnpo.page);
RAWNAND_ERR("sdata: %02x %02x %02x %02x \n", lnpo.sdata[0], lnpo.sdata[1], lnpo.sdata[2], lnpo.sdata[3]);
return -1;
}
//read and check other pages
for (i = 0, lnpo.page = start_page; i < num; i++) {
generic_read_page(&lnpo);
if (lnpo.sdata[0] != 0xff) {
RAWNAND_ERR("find a bad block: %d %d %d ", lnpo.chip, lnpo.block, lnpo.page);
RAWNAND_ERR("sdata: %02x %02x %02x %02x \n", lnpo.sdata[0], lnpo.sdata[1], lnpo.sdata[2], lnpo.sdata[3]);
return -1;
}
lnpo.page++;
}
return 0;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_bad_block_mark(struct _nand_physic_op_par *npo)
{
int num, start_page, i, ret;
unsigned char spare[64];
struct _nand_physic_op_par lnpo;
struct nand_chip_info *nci = nci_get_from_nsi(g_nsi, npo->chip);
struct nand_controller_info *nctri = nci->nctri;
unsigned char *mbuf = nand_get_temp_buf(nctri->nci->sector_cnt_per_page << 9);
if (mbuf == NULL) {
RAWNAND_ERR("bad block mark no memory chip: %d block:%d\n", npo->chip, npo->block);
return ERR_NO_18;
}
//RAWNAND_ERR("%s: ch: %d chip: %d/%d block: %d/%d \n", __func__, nctri->channel_id, nci->nctri_chip_no, nctri->chip_cnt, npo->block, nci->blk_cnt_per_chip);
if ((nci->nctri_chip_no >= nctri->chip_cnt) || (npo->block >= nci->blk_cnt_per_chip)) {
RAWNAND_ERR("Mfatal err -0, wrong input parameter,channel:%d chip: %d/%d block: %d/%d\n", nctri->channel_id, nci->nctri_chip_no, nctri->chip_cnt, npo->block, nci->blk_cnt_per_chip);
return ERR_NO_18;
}
RAWNAND_DBG("bad block mark chip: %d block:%d\n", npo->chip, npo->block);
lnpo.chip = npo->chip;
lnpo.block = npo->block;
lnpo.page = 0;
lnpo.sect_bitmap = nci->sector_cnt_per_page;
lnpo.mdata = mbuf;
lnpo.sdata = spare;
lnpo.slen = nci->sdata_bytes_per_page;
if (nci->bad_block_flag_position == FIRST_PAGE) {
start_page = 0;
num = 1;
} else if (nci->bad_block_flag_position == FIRST_TWO_PAGES) {
start_page = 0;
num = 2;
} else if (nci->bad_block_flag_position == LAST_PAGE) {
start_page = nci->page_cnt_per_blk - 1;
num = 1;
} else if (nci->bad_block_flag_position == LAST_TWO_PAGES) {
start_page = nci->page_cnt_per_blk - 2;
num = 2;
} else {
nand_free_temp_buf(mbuf);
RAWNAND_ERR("bad block mark, unknown bad block flag position\n");
return ERR_NO_19;
}
ret = generic_erase_block(&lnpo);
if (ret) {
nand_free_temp_buf(mbuf);
RAWNAND_ERR("bad block mark, erase block failed, blk %d, chip %d, ch %d\n", lnpo.block, lnpo.chip, nci->nctri->channel_id);
return ret;
}
memset(lnpo.sdata, 0, 64);
generic_write_page(&lnpo);
for (i = 0, lnpo.page = start_page; i < num; i++) {
if (lnpo.page != 0) {
lnpo.chip = npo->chip;
lnpo.block = npo->block;
lnpo.sect_bitmap = nci->sector_cnt_per_page;
lnpo.mdata = mbuf;
lnpo.sdata = spare;
lnpo.slen = nci->sdata_bytes_per_page;
generic_write_page(&lnpo);
}
lnpo.page++;
}
//check bad block flag
memset(lnpo.sdata, 0xff, 64);
lnpo.chip = npo->chip;
lnpo.block = npo->block;
lnpo.page = 0;
lnpo.sect_bitmap = nci->sector_cnt_per_page;
lnpo.mdata = NULL;
lnpo.sdata = spare;
lnpo.slen = nci->sdata_bytes_per_page;
generic_read_page(&lnpo);
if (lnpo.sdata[0] != 0xff) {
nand_free_temp_buf(mbuf);
return 0;
}
for (i = 0, lnpo.page = start_page; i < num; i++) {
lnpo.chip = npo->chip;
lnpo.block = npo->block;
lnpo.sect_bitmap = nci->sector_cnt_per_page;
lnpo.mdata = NULL;
lnpo.sdata = spare;
lnpo.slen = nci->sdata_bytes_per_page;
generic_read_page(&lnpo);
if (lnpo.sdata[0] != 0xff) {
nand_free_temp_buf(mbuf);
return 0;
}
lnpo.page++;
}
nand_free_temp_buf(mbuf);
return ERR_NO_20;
}
int nand_phy_get_page_type(unsigned int page)
{
/*
for SPECTEK L04a/L05b 3D nand
page type:1-> independent page,
page type:2-> lsb page
page type:3-> msb page
*/
if ((page <= 15) || (page >= 496))
return 1;
if (page % 2 == 0)
return 2;
return 3;
}
int nand_phy_low_page_write_cache_set(struct _nand_physic_op_par *npo,
unsigned int two_plane)
{
int i = 0;
for (i = 0; i < NAND_OPEN_BLOCK_CNT; i++) {
if (nand_phy_w_cache[i].cache_use_status == 0) {
/*get a new lsb page cache and backup for L04a*/
nand_phy_w_cache[i].cache_use_status = 1;
nand_phy_w_cache[i].tmp_npo.chip = npo->chip;
nand_phy_w_cache[i].tmp_npo.block = npo->block;
nand_phy_w_cache[i].tmp_npo.page = npo->page;
nand_phy_w_cache[i].tmp_npo.sect_bitmap = npo->sect_bitmap;
nand_phy_w_cache[i].tmp_npo.slen = npo->slen;
if (nand_phy_w_cache[i].tmp_npo.mdata == NULL) {
if (two_plane == 1)
nand_phy_w_cache[i].tmp_npo.mdata =
nand_malloc(
2 * (npo->sect_bitmap << 9));
else
nand_phy_w_cache[i].tmp_npo.mdata =
nand_malloc(npo->sect_bitmap << 9);
}
if (nand_phy_w_cache[i].tmp_npo.sdata == NULL) {
nand_phy_w_cache[i].tmp_npo.sdata = nand_malloc(npo->slen);
memset(nand_phy_w_cache[i].tmp_npo.sdata, 0xff, npo->slen);
}
if (npo->mdata) {
if (two_plane == 1)
nand_memcpy(
nand_phy_w_cache[i].tmp_npo.mdata,
npo->mdata,
2 * (npo->sect_bitmap << 9));
else
nand_memcpy(
nand_phy_w_cache[i].tmp_npo.mdata,
npo->mdata,
(npo->sect_bitmap << 9));
}
if (npo->sdata)
memcpy(nand_phy_w_cache[i].tmp_npo.sdata, npo->sdata, npo->slen);
return 0;
}
}
RAWNAND_ERR("ERR! no cache buf for lsb page!\n");
return -1;
}
struct _nand_physic_op_par *nand_phy_low_page_cache_get_for_write(struct _nand_physic_op_par *npo)
{
int i = 0;
for (i = 0; i < NAND_OPEN_BLOCK_CNT; i++) {
if ((nand_phy_w_cache[i].cache_use_status == 1) &&
(nand_phy_w_cache[i].tmp_npo.chip == npo->chip) &&
((nand_phy_w_cache[i].tmp_npo.page + 1) == npo->page) &&
(nand_phy_w_cache[i].tmp_npo.block == npo->block) &&
(nand_phy_w_cache[i].tmp_npo.sect_bitmap == npo->sect_bitmap) &&
(nand_phy_w_cache[i].tmp_npo.slen == npo->slen) &&
(nand_phy_w_cache[i].tmp_npo.mdata != NULL) &&
(nand_phy_w_cache[i].tmp_npo.sdata != NULL)) {
return &(nand_phy_w_cache[i].tmp_npo);
}
}
RAWNAND_ERR("ERR! Not get LSB write cache!\n");
return NULL;
}
int nand_phy_low_page_write_cache_cancle(struct _nand_physic_op_par *npo)
{
int i = 0;
for (i = 0; i < NAND_OPEN_BLOCK_CNT; i++) {
if ((nand_phy_w_cache[i].cache_use_status == 1) &&
(nand_phy_w_cache[i].tmp_npo.chip == npo->chip) &&
(nand_phy_w_cache[i].tmp_npo.block == npo->block) &&
(nand_phy_w_cache[i].tmp_npo.page == npo->page)) {
nand_phy_w_cache[i].cache_use_status = 0;
return 0;
}
}
return -1;
}
int nand_phy_low_page_cache_get_for_read(struct _nand_physic_op_par *npo,
unsigned int two_plane)
{
int i = 0;
for (i = 0; i < NAND_OPEN_BLOCK_CNT; i++) {
if ((nand_phy_w_cache[i].tmp_npo.chip == npo->chip) &&
(nand_phy_w_cache[i].tmp_npo.block == npo->block) &&
(nand_phy_w_cache[i].tmp_npo.page == npo->page) &&
(nand_phy_w_cache[i].tmp_npo.mdata != NULL) &&
(nand_phy_w_cache[i].tmp_npo.sdata != NULL)) {
if (npo->mdata) {
if (two_plane == 1)
nand_memcpy(
npo->mdata,
nand_phy_w_cache[i].tmp_npo.mdata,
2 * (npo->sect_bitmap << 9));
else
nand_memcpy(
npo->mdata,
nand_phy_w_cache[i].tmp_npo.mdata,
(npo->sect_bitmap << 9));
}
if (npo->sdata)
memcpy(npo->sdata, nand_phy_w_cache[i].tmp_npo.sdata, npo->slen);
return 0;
}
}
return -1;
}
int generic_rw_page(struct _nand_physic_op_par *npo, unsigned int function, unsigned int two_plane)
{
int ret = 0;
if ((function == 0) && (two_plane == 0)) {
ret |= generic_read_page(npo);
} else if ((function == 0) && (two_plane == 1)) {
ret |= generic_read_two_plane_page(npo);
} else if ((function == 1) && (two_plane == 0)) {
ret |= generic_write_page(npo);
} else if ((function == 1) && (two_plane == 1)) {
ret |= generic_write_two_plane_page(npo);
} else {
;
}
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_use_chip_function(struct _nand_physic_op_par *npo, unsigned int function)
{
int ret, i;
struct _nand_physic_op_par lnpo;
struct nand_chip_info *nci;
struct nand_super_chip_info *nsci = nsci_get_from_nssi(g_nssi, npo->chip);
unsigned int chip[8];
unsigned int block[8];
unsigned int block_num;
if (nsci->two_plane == 0) {
if ((nsci->vertical_interleave == 1) && (nsci->dual_channel == 1)) {
block_num = 4;
chip[0] = nsci->d_channel_nci_1->chip_no;
block[0] = npo->block;
chip[1] = nsci->d_channel_nci_2->chip_no;
block[1] = npo->block;
chip[2] = nsci->v_intl_nci_2->chip_no;
block[2] = npo->block;
nci = nci_get_from_nctri(nsci->d_channel_nci_2->nctri, nsci->v_intl_nci_1->chip_no);
chip[3] = nci->chip_no;
block[3] = npo->block;
} else if (nsci->vertical_interleave == 1) {
block_num = 2;
chip[0] = nsci->v_intl_nci_1->chip_no;
block[0] = npo->block;
chip[1] = nsci->v_intl_nci_2->chip_no;
block[1] = npo->block;
} else if (nsci->dual_channel == 1) {
block_num = 2;
chip[0] = nsci->d_channel_nci_1->chip_no;
block[0] = npo->block;
chip[1] = nsci->d_channel_nci_2->chip_no;
block[1] = npo->block;
} else {
block_num = 1;
chip[0] = npo->chip;
block[0] = npo->block;
}
} else {
if ((nsci->vertical_interleave == 1) && (nsci->dual_channel == 1)) {
block_num = 8;
chip[0] = nsci->d_channel_nci_1->chip_no;
block[0] = npo->block << 1;
chip[1] = nsci->d_channel_nci_1->chip_no;
block[1] = (npo->block << 1) + 1;
chip[2] = nsci->d_channel_nci_2->chip_no;
block[2] = npo->block << 1;
chip[3] = nsci->d_channel_nci_2->chip_no;
block[3] = (npo->block << 1) + 1;
chip[4] = nsci->v_intl_nci_2->chip_no;
block[4] = npo->block << 1;
chip[5] = nsci->v_intl_nci_2->chip_no;
block[5] = (npo->block << 1) + 1;
nci = nci_get_from_nctri(nsci->d_channel_nci_2->nctri, nsci->v_intl_nci_1->chip_no);
chip[6] = nci->chip_no;
block[6] = npo->block << 1;
chip[7] = nci->chip_no;
block[7] = (npo->block << 1) + 1;
} else if (nsci->vertical_interleave == 1) {
block_num = 4;
chip[0] = nsci->v_intl_nci_1->chip_no;
block[0] = npo->block << 1;
chip[1] = nsci->v_intl_nci_1->chip_no;
block[1] = (npo->block << 1) + 1;
chip[2] = nsci->v_intl_nci_2->chip_no;
block[2] = npo->block << 1;
chip[3] = nsci->v_intl_nci_2->chip_no;
block[3] = (npo->block << 1) + 1;
} else if (nsci->dual_channel == 1) {
block_num = 4;
chip[0] = nsci->d_channel_nci_1->chip_no;
block[0] = npo->block << 1;
chip[1] = nsci->d_channel_nci_1->chip_no;
block[1] = (npo->block << 1) + 1;
chip[2] = nsci->d_channel_nci_2->chip_no;
block[2] = npo->block << 1;
chip[3] = nsci->d_channel_nci_2->chip_no;
block[3] = (npo->block << 1) + 1;
} else {
block_num = 2;
chip[0] = npo->chip;
block[0] = npo->block << 1;
chip[1] = npo->chip;
block[1] = (npo->block << 1) + 1;
}
}
for (i = 0, ret = 0; i < block_num; i++) {
lnpo.chip = chip[i];
lnpo.block = block[i];
lnpo.page = 0;
if (function == 0) {
ret |= generic_erase_block(&lnpo);
//ret |= generic_erase_block_start(&lnpo);
} else if (function == 1) {
ret |= generic_bad_block_check(&lnpo);
if (ret != 0) {
break;
}
} else if (function == 2) {
ret |= generic_bad_block_mark(&lnpo);
} else {
;
}
}
nand_wait_all_rb_ready();
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_rw_use_chip_function(struct _nand_physic_op_par *npo, unsigned int function)
{
int ret = 0;
struct _nand_physic_op_par lnpo;
struct _nand_physic_op_par *low_npo;
struct nand_super_chip_info *nsci = nsci_get_from_nssi(g_nssi, npo->chip);
struct nand_chip_info *nci = nci_get_from_nsi(g_nsi, npo->chip);
unsigned int chip[4];
unsigned int block[4];
unsigned int page[4];
unsigned char *mdata[4];
unsigned char *sdata[4];
unsigned int slen[4];
unsigned int sect_bitmap[4];
// unsigned int block_num;
unsigned char oob_temp[64];
unsigned int i;
if ((nsci->dual_channel == 1) && (nsci->two_plane == 1) && (function == 1)) {
// block_num = 4;
chip[0] = nsci->d_channel_nci_1->chip_no;
block[0] = npo->block << 1;
page[0] = npo->page;
mdata[0] = npo->mdata;
sect_bitmap[0] = nsci->d_channel_nci_1->sector_cnt_per_page;
sdata[0] = npo->sdata;
slen[0] = npo->slen;
chip[1] = nsci->d_channel_nci_2->chip_no;
block[1] = npo->block << 1;
page[1] = npo->page;
mdata[1] = npo->mdata + (nsci->d_channel_nci_1->sector_cnt_per_page << 10);
sect_bitmap[1] = nsci->d_channel_nci_2->sector_cnt_per_page;
sdata[1] = npo->sdata;
slen[1] = npo->slen;
chip[2] = nsci->d_channel_nci_1->chip_no;
block[2] = (npo->block << 1) + 1;
page[2] = npo->page;
mdata[2] = npo->mdata + (nsci->d_channel_nci_1->sector_cnt_per_page << 9);
sect_bitmap[2] = nsci->d_channel_nci_1->sector_cnt_per_page;
sdata[2] = npo->sdata;
slen[2] = npo->slen;
chip[3] = nsci->d_channel_nci_2->chip_no;
block[3] = (npo->block << 1) + 1;
page[3] = npo->page;
mdata[3] = npo->mdata + (nsci->d_channel_nci_2->sector_cnt_per_page << 10) + (nsci->d_channel_nci_2->sector_cnt_per_page << 9);
sect_bitmap[3] = nsci->d_channel_nci_2->sector_cnt_per_page;
sdata[3] = npo->sdata;
slen[3] = npo->slen;
if (nsci->d_channel_nci_1->sector_cnt_per_page == 4) {
for (i = 0; i < 16; i++) {
if (i < 8) {
oob_temp[i] = *((unsigned char *)npo->sdata + i);
} else if (i == 8) {
oob_temp[i] = 0xff;
} else {
oob_temp[i] = *((unsigned char *)npo->sdata + i - 1);
}
}
sdata[0] = &oob_temp[0];
sdata[1] = &oob_temp[0];
sdata[2] = &oob_temp[8];
sdata[3] = &oob_temp[8];
}
lnpo.chip = chip[0];
lnpo.block = block[0];
lnpo.page = page[0];
lnpo.mdata = mdata[0];
lnpo.sect_bitmap = sect_bitmap[0];
lnpo.sdata = sdata[0];
lnpo.slen = slen[0];
ret |= generic_write_page_start(&lnpo, 1);
lnpo.chip = chip[1];
lnpo.block = block[1];
lnpo.page = page[1];
lnpo.mdata = mdata[1];
lnpo.sect_bitmap = sect_bitmap[1];
lnpo.sdata = sdata[1];
lnpo.slen = slen[1];
ret |= generic_write_page_start(&lnpo, 1);
lnpo.chip = chip[0];
lnpo.block = block[0];
lnpo.page = page[0];
lnpo.mdata = mdata[0];
lnpo.sect_bitmap = sect_bitmap[0];
lnpo.sdata = sdata[0];
lnpo.slen = slen[0];
ret |= generic_write_page_end(&lnpo);
lnpo.chip = chip[2];
lnpo.block = block[2];
lnpo.page = page[2];
lnpo.mdata = mdata[2];
lnpo.sect_bitmap = sect_bitmap[2];
lnpo.sdata = sdata[2];
lnpo.slen = slen[2];
ret |= generic_write_page_start(&lnpo, 2);
lnpo.chip = chip[1];
lnpo.block = block[1];
lnpo.page = page[1];
lnpo.mdata = mdata[1];
lnpo.sect_bitmap = sect_bitmap[1];
lnpo.sdata = sdata[1];
lnpo.slen = slen[1];
ret |= generic_write_page_end(&lnpo);
lnpo.chip = chip[3];
lnpo.block = block[3];
lnpo.page = page[3];
lnpo.mdata = mdata[3];
lnpo.sect_bitmap = sect_bitmap[3];
lnpo.sdata = sdata[3];
lnpo.slen = slen[3];
ret |= generic_write_page_start(&lnpo, 2);
lnpo.chip = chip[2];
lnpo.block = block[2];
lnpo.page = page[2];
lnpo.mdata = mdata[2];
lnpo.sect_bitmap = sect_bitmap[2];
lnpo.sdata = sdata[2];
lnpo.slen = slen[2];
ret |= generic_write_page_end(&lnpo);
lnpo.chip = chip[3];
lnpo.block = block[3];
lnpo.page = page[3];
lnpo.mdata = mdata[3];
lnpo.sect_bitmap = sect_bitmap[3];
lnpo.sdata = sdata[3];
lnpo.slen = slen[3];
ret |= generic_write_page_end(&lnpo);
return ret;
}
if ((nsci->dual_channel == 1) && (nsci->two_plane == 1) && (function == 0)) {
// block_num = 4;
chip[0] = nsci->d_channel_nci_1->chip_no;
block[0] = npo->block << 1;
page[0] = npo->page;
mdata[0] = npo->mdata;
sect_bitmap[0] = nsci->d_channel_nci_1->sector_cnt_per_page;
sdata[0] = npo->sdata;
slen[0] = npo->slen;
chip[1] = nsci->d_channel_nci_2->chip_no;
block[1] = npo->block << 1;
page[1] = npo->page;
mdata[1] = npo->mdata + (nsci->d_channel_nci_1->sector_cnt_per_page << 10);
sect_bitmap[1] = sect_bitmap[0];
sdata[1] = NULL;
slen[1] = 0;
chip[2] = nsci->d_channel_nci_1->chip_no;
block[2] = (npo->block << 1) + 1;
page[2] = npo->page;
mdata[2] = npo->mdata + (nsci->d_channel_nci_1->sector_cnt_per_page << 9);
sect_bitmap[2] = sect_bitmap[0];
sdata[2] = NULL;
slen[2] = 0;
chip[3] = nsci->d_channel_nci_2->chip_no;
block[3] = (npo->block << 1) + 1;
page[3] = npo->page;
mdata[3] = npo->mdata + (nsci->d_channel_nci_2->sector_cnt_per_page << 10) + (nsci->d_channel_nci_2->sector_cnt_per_page << 9);
sect_bitmap[3] = sect_bitmap[0];
sdata[3] = NULL;
slen[3] = 0;
if (nsci->d_channel_nci_1->sector_cnt_per_page == 4) {
sdata[0] = &oob_temp[0];
sdata[1] = NULL;
sdata[2] = &oob_temp[8];
sdata[3] = NULL;
}
lnpo.chip = chip[0];
lnpo.block = block[0];
lnpo.page = page[0];
lnpo.mdata = mdata[0];
lnpo.sect_bitmap = sect_bitmap[0];
lnpo.sdata = sdata[0];
lnpo.slen = slen[0];
ret |= generic_read_page_start(&lnpo);
lnpo.chip = chip[1];
lnpo.block = block[1];
lnpo.page = page[1];
lnpo.mdata = mdata[1];
lnpo.sect_bitmap = sect_bitmap[0];
lnpo.sdata = sdata[1];
lnpo.slen = slen[1];
if (mdata[0] != NULL)
ret |= generic_read_page_start(&lnpo);
lnpo.chip = chip[0];
lnpo.block = block[0];
lnpo.page = page[0];
lnpo.mdata = mdata[0];
lnpo.sect_bitmap = sect_bitmap[0];
lnpo.sdata = sdata[0];
lnpo.slen = slen[0];
ret |= generic_read_page_end(&lnpo);
lnpo.chip = chip[2];
lnpo.block = block[2];
lnpo.page = page[2];
lnpo.mdata = mdata[2];
lnpo.sect_bitmap = sect_bitmap[0];
lnpo.sdata = sdata[2];
lnpo.slen = slen[2];
if (mdata[0] != NULL)
ret |= generic_read_page_start(&lnpo);
lnpo.chip = chip[1];
lnpo.block = block[1];
lnpo.page = page[1];
lnpo.mdata = mdata[1];
lnpo.sect_bitmap = sect_bitmap[0];
lnpo.sdata = sdata[1];
lnpo.slen = slen[1];
if (mdata[0] != NULL)
ret |= generic_read_page_end(&lnpo);
lnpo.chip = chip[3];
lnpo.block = block[3];
lnpo.page = page[3];
lnpo.mdata = mdata[3];
lnpo.sect_bitmap = sect_bitmap[0];
lnpo.sdata = sdata[3];
lnpo.slen = slen[3];
if (mdata[0] != NULL)
ret |= generic_read_page_start(&lnpo);
lnpo.chip = chip[2];
lnpo.block = block[2];
lnpo.page = page[2];
lnpo.mdata = mdata[2];
lnpo.sect_bitmap = sect_bitmap[0];
lnpo.sdata = sdata[2];
lnpo.slen = slen[2];
if (mdata[0] != NULL)
ret |= generic_read_page_end(&lnpo);
lnpo.chip = chip[3];
lnpo.block = block[3];
lnpo.page = page[3];
lnpo.mdata = mdata[3];
lnpo.sect_bitmap = sect_bitmap[0];
lnpo.sdata = sdata[3];
lnpo.slen = slen[3];
if (mdata[0] != NULL)
ret |= generic_read_page_end(&lnpo);
if (nsci->d_channel_nci_1->sector_cnt_per_page == 4) {
for (i = 0; i < 16; i++) {
if (i < 8) {
*((unsigned char *)npo->sdata + i) = oob_temp[i];
} else if (i == 15) {
*((unsigned char *)npo->sdata + i) = 0xff;
} else {
*((unsigned char *)npo->sdata + i) = oob_temp[i + 1];
}
}
}
return ret;
}
if (nsci->dual_channel == 1) {
// block_num = 2;
chip[0] = nsci->d_channel_nci_1->chip_no;
block[0] = npo->block;
page[0] = npo->page;
mdata[0] = npo->mdata;
sect_bitmap[0] = nsci->d_channel_nci_1->sector_cnt_per_page;
sdata[0] = npo->sdata;
slen[0] = npo->slen;
chip[1] = nsci->d_channel_nci_2->chip_no;
block[1] = npo->block;
page[1] = npo->page;
mdata[1] = npo->mdata + (nsci->d_channel_nci_1->sector_cnt_per_page << 9);
sect_bitmap[1] = sect_bitmap[0];
sdata[1] = npo->sdata;
slen[1] = npo->slen;
if (function == 0) {
sdata[1] = NULL;
slen[1] = 0;
}
lnpo.chip = chip[0];
lnpo.block = block[0];
lnpo.page = page[0];
lnpo.mdata = mdata[0];
lnpo.sect_bitmap = sect_bitmap[0];
lnpo.sdata = sdata[0];
lnpo.slen = slen[0];
if (function == 1) {
ret |= generic_write_page_start(&lnpo, 0);
} else {
ret |= generic_read_page_start(&lnpo);
}
lnpo.chip = chip[1];
lnpo.block = block[1];
lnpo.page = page[1];
lnpo.mdata = mdata[1];
lnpo.sect_bitmap = sect_bitmap[1];
lnpo.sdata = sdata[1];
lnpo.slen = slen[1];
if (function == 1) {
ret |= generic_write_page_start(&lnpo, 0);
} else {
if (mdata[0] != NULL)
ret |= generic_read_page_start(&lnpo);
}
lnpo.chip = chip[0];
lnpo.block = block[0];
lnpo.page = page[0];
lnpo.mdata = mdata[0];
lnpo.sect_bitmap = sect_bitmap[0];
lnpo.sdata = sdata[0];
lnpo.slen = slen[0];
if (function == 1) {
ret |= generic_write_page_end(&lnpo);
} else {
ret |= generic_read_page_end(&lnpo);
}
lnpo.chip = chip[1];
lnpo.block = block[1];
lnpo.page = page[1];
lnpo.mdata = mdata[1];
lnpo.sect_bitmap = sect_bitmap[1];
lnpo.sdata = sdata[1];
lnpo.slen = slen[1];
if (function == 1) {
ret |= generic_write_page_end(&lnpo);
} else {
if (mdata[0] != NULL)
ret |= generic_read_page_end(&lnpo);
}
return ret;
}
if (nsci->vertical_interleave == 1) {
if (npo->page & 0x01) {
lnpo.chip = nsci->v_intl_nci_2->chip_no;
} else {
lnpo.chip = nsci->v_intl_nci_1->chip_no;
}
lnpo.page = npo->page >> 1;
} else {
lnpo.chip = nsci->nci_first->chip_no;
lnpo.page = npo->page;
}
lnpo.block = npo->block;
lnpo.mdata = npo->mdata;
/*lnpo.sect_bitmap = nsci->nci_first->sector_cnt_per_page;*/
lnpo.sect_bitmap = npo->sect_bitmap;
lnpo.sdata = npo->sdata;
lnpo.slen = npo->slen;
if (lnpo.mdata == NULL)
lnpo.sect_bitmap = 0;
if ((nci->npi->operation_opt & NAND_PAIRED_PAGE_SYNC) && (function == 1)) {
if (nand_phy_get_page_type(lnpo.page) == 2) {
ret = nand_phy_low_page_write_cache_set(
&lnpo, nsci->two_plane);
return ret;
} else if (nand_phy_get_page_type(lnpo.page) == 3) {
low_npo = nand_phy_low_page_cache_get_for_write(&lnpo);
if (low_npo) {
ret |= generic_rw_page(low_npo, function, nsci->two_plane);
nand_phy_low_page_write_cache_cancle(low_npo);
} else {
RAWNAND_ERR("ERR! Not get low page cache when write uper page\n");
}
} else {
;
}
} else if ((nci->npi->operation_opt & NAND_PAIRED_PAGE_SYNC) &&
(function == 0)) {
if ((nand_phy_get_page_type(lnpo.page) == 2) &&
(nand_phy_low_page_cache_get_for_read(
&lnpo, nsci->two_plane) == 0))
return 0;
} else {
;
}
ret |= generic_rw_page(&lnpo, function, nsci->two_plane);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_erase_super_block(struct _nand_physic_op_par *npo)
{
int ret;
ret = generic_use_chip_function(npo, 0);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_read_super_page(struct _nand_physic_op_par *npo)
{
int ret;
ret = generic_rw_use_chip_function(npo, 0);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_write_super_page(struct _nand_physic_op_par *npo)
{
int ret;
ret = generic_rw_use_chip_function(npo, 1);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_super_bad_block_check(struct _nand_physic_op_par *npo)
{
int ret;
ret = generic_use_chip_function(npo, 1);
return ret;
}
/*****************************************************************************
*Name :
*Description :
*Parameter :
*Return : 0:ok -1:fail
*Note :
*****************************************************************************/
int generic_super_bad_block_mark(struct _nand_physic_op_par *npo)
{
int ret;
ret = generic_use_chip_function(npo, 2);
return ret;
}
struct df_read_page_end df_read_page_end = {
.read_page_end = generic_read_page_end_not_retry,
};
struct rawnand_ops rawnand_ops = {
.erase_single_block = generic_erase_block,
.write_single_page = generic_write_page,
.read_single_page = generic_read_page,
.single_bad_block_check = generic_bad_block_check,
.single_bad_block_mark = generic_bad_block_mark,
.erase_super_block = generic_erase_super_block,
.write_super_page = generic_write_super_page,
.read_super_page = generic_read_super_page,
.super_bad_block_check = generic_super_bad_block_check,
.super_bad_block_mark = generic_super_bad_block_mark,
};