1888 lines
55 KiB
C
Executable File
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,
|
|
};
|