📄 nandflash.c
字号:
/**
* @FILENAME nandflash.c
* @BRIEF 并口NAND FLASH控制器驱
* Copyright (C) 2006 Anyka (Guangzhou) Software Technology Co., LTD
* @AUTHOR dengjian
* @DATE 2006-1-11
* @VERSION 1.0
* @REF Please refer to…
* @NOTE 1.只支持目前市面上大量生产的samsung 和hynix的驱动(这样运行速度会快一些
果要支持比较特殊 的nandflash驱动,需要调整程序和宏定义
* 2. 多片选择的相关细节目前没有在驱动中体现,大多数都是针对单片flash编写。
*/
//#define OS_ANYKA
#ifdef OS_ANYKA
//#define CHK_STA_BEFORE
//#define CHK_STA_AFTER
//#define STORE_ALL_INT
#include "akdefine.h"
#include "nandflash.h"
#include "nand_list.h"
#include "CRCDrv.h"
// ECC flag bit
#define RS1_NO_ERR_BIT (1 << 11)
#define RS2_NO_ERR_BIT (1 << 12)
#define BCH_NO_ERR_BIT (1 << 13)
#define RS1_CANT_CORRECT_BIT (1 << 5)
#define RS2_CANT_CORRECT_BIT (1 << 7)
#define BCH_CANT_CORRECT_BIT (1 << 9)
#define RS1_CORRECT_END_BIT (1 << 6)
#define RS2_CORRECT_END_BIT (1 << 8)
#define BCH_CORRECT_END_BIT (1 << 10)
// ECC error code(留16个错误码)
/*
* 函数do_ECC_coerr()设置两个阀值:
* 一个是16, 一个是2;
* 当do_ECC_coerr()返回值>=ECC_CANT_CORRECT, 表示错不可纠, 此时不执行CRC校验;
* 当do_ECC_coerr返回值小于ECC_CANT_CORRECT而大于等于ECC_NEED_CRC_CHECK, 表示错误较多, 可能会错纠, 此时执行CRC校验;
* 当do_ECC_coerr返回值为0时, 表示无错或已经正确纠错;
*/
#define ECC_NEED_CRC_CHECK (2)
#define ECC_CANT_CORRECT (1 << 4) //
#define RS1_CANT_CORRECT (1 << 4)
#define RS2_CANT_CORRECT (1 << 5)
#define BCH_CANT_CORRECT (1 << 6)
#define RS1_COERR 1
#define RS2_COERR 2
static T_S16 read_chipinfo();
static T_BOOL check_cmd_done(T_VOID);
static T_VOID CPU_setFIFO(T_U32 addr, T_U32 val);
static T_U32 CPU_readFIFO(T_U32 addr);
static T_VOID CPU_FIFO2memory(T_U32 *dest, T_U32 fifo_start, T_U8 count);
static T_VOID CPU_memory2FIFO(T_U32 fifo_start, T_U32 *src, T_U8 count);
static T_VOID DMA_FIFO2memory(T_U32 *dest, T_U32 fifo_start, T_U8 count);
static T_VOID DMA_memory2FIFO(T_U32 fifo_start, T_U32 *src, T_U8 count);
static T_U8 nf_read_status(T_U8 chip);
//#######excute comamnd,ctrl reg22 command configuration define ################
//所有的配置定义针对发送命令的方式。
//必须进行片选或片保护、操作模式、以及是否使能的省电模式flag
//片选使用宏NCHIP_SELECT(x)
//同时打该片的写保护,使用宏WRITE_PROTECT(x),
#define NCHIP_SELECT(x) (((0x01 << (chipInfo.pos[x])) << 10) | (0xF << 15))
//*****************************************************************************************
//*************from lgj******************************************************************
// regisger 0x44 命令组合
#define comb_ctrl_reg(ps, staff, ce_keep, ce, wp, go) (ps | (staff << 1) | (ce_keep << 9) \
| (ce << 10) | (wp << 15) | (go << 30))
#define FLASH_CE_VALID 0 // (配置此值可选择不同FLASH)
#define SELECT_FLASH_CE (1 << FLASH_CE_VALID)
#define SELECT_FLASH_WP 0x1
//static volatile T_BOOL NC_DMARun = AK_FALSE;
//static volatile T_BOOL NChip_Busy = AK_FALSE;
//static T_BOOL bNandInit = AK_FALSE;
T_NANDCHIP_INFO chipInfo;
T_NAND_LOG_INFO Nand_SysInfo;
/**
* @BRIEF read chip id for head file
* @AUTHOR dengjian
* @DATE 2006-01-05
* @PARAM
* @RETURN chip id
* @RETVAL
*/
static T_S16 read_chipinfo()
{
T_U16 i, chip_cnt = 0;
T_U32 nand_id = ERROR_CHIP_ID;
T_NAND_PHY_INFO *nand_info;
nand_info = (T_NAND_PHY_INFO *)0x40000020;
chipInfo.count = 0;
chipInfo.id = ERROR_CHIP_ID;
for(i=0;i<NFC_SUPPORT_CHIPNUM;i++)
chipInfo.pos[i] = i;
for(i=0;i<NFC_SUPPORT_CHIPNUM;i++)
{
nand_id = ERROR_CHIP_ID;
HAL_WRITE_UINT32(FLASH_CTRL_REG22, 0x00);
HAL_WRITE_UINT32(FLASH_CTRL_REG0, (NFLASH_READ_ID << 11) | COMMAND_CYCLES_CONF);
HAL_WRITE_UINT32(FLASH_CTRL_REG0+0x04, (0x00 << 11) | ADDRESS_CYCLES_CONF);
//wait > 10 ns < 30????(84M, 1 clock =12ns)//wait 2 clocks
HAL_WRITE_UINT32(FLASH_CTRL_REG0+0x08, 0 | DELAY_CNT_CONF);
//ID information is 4 byte,read it to register 22
HAL_WRITE_UINT32(FLASH_CTRL_REG0+0x0C, (0x03 << 11) | READ_INFO_CONF | LAST_CMD_FLAG);
// excute operation, , enable power saving, CE# keep LOW wait R/B
//printf("%d is 0x%x", i, NCHIP_SELECT(i));
HAL_WRITE_UINT32(FLASH_CTRL_REG22, NCHIP_SELECT(i)|DEFAULT_GO);
//HAL_READ_UINT32(FLASH_CTRL_REG22, nand_id);
//printf("\r\nreg22 is 0x%x\r\n",nand_id );
// wait end & read data (data at where)
while(!check_cmd_done());
// read status
HAL_READ_UINT32(FLASH_CTRL_REG20, nand_id);
//printf("\n*********************detect nand********************\n");
//printf("bios detect %d nandid is 0x%x\n", i, nand_id);
if(nand_id != ERROR_CHIP_ID)
{
printf("nand_info->chip_id nand_id is 0x%x 0x%x\n", nand_info->chip_id, nand_id);
if(chipInfo.id != nand_id)
{
if(nand_info->chip_id == nand_id)
{
if (chipInfo.id == ERROR_CHIP_ID)
{
chipInfo.id = nand_id;
//printf("\r\ncurrent nandflash:");
//printf(SUPPORT_NAND_TABLE[id_cnt].des_str);
//printf("\r\n");
chipInfo.col_cycle = nand_info->col_cycle;
printf("chipInfo.col_cycle %x\n", chipInfo.col_cycle);
chipInfo.row_cycle = nand_info->row_cycle;
printf("chipInfo.row_cycle %x\n", chipInfo.row_cycle);
chipInfo.lst_col_mask = nand_info->lst_col_mask;
printf("chipInfo.lst_col_mask %x\n", chipInfo.lst_col_mask);
chipInfo.last_row_mask = nand_info->last_row_mask;
printf("chipInfo.last_row_mask %x\n", chipInfo.last_row_mask);
chipInfo.phy_page_size = nand_info->page_size;
printf("chipInfo.phy_page_size %x\n", chipInfo.phy_page_size);
chipInfo.chip_blk_num = nand_info->blk_num;
printf("chipInfo.chip_blk_num %x\n", chipInfo.chip_blk_num);
chipInfo.group_blk_num = nand_info->group_blk_num;
printf("chipInfo.group_blk_num %x\n", chipInfo.group_blk_num);
chipInfo.plane_blk_num = nand_info->plane_blk_num;
printf("chipInfo.plane_blk_num %x\n", chipInfo.plane_blk_num);
chipInfo.phy_page_per_blk = nand_info->page_per_blk;
printf("chipInfo.phy_page_per_blk %x\n", chipInfo.phy_page_per_blk);
}
}
else
{
printf("We dont support different chip type in one machine!!\r\n");
return NF_FAIL;
}
}
if (nand_id == chipInfo.id)
{
chipInfo.pos[chipInfo.count] = i;
chipInfo.count++;
printf("now count is %d\n", chipInfo.count);
}
}
}
if (chipInfo.count>0)
{
printf("\r\n chip ID is 0x%x\r\n count= %d \n", chipInfo.id, chipInfo.count);
return NF_SUCCESS;
}
printf("Cannot find chip!\r\n");
return NF_FAIL;
}
//******************************************init,read chipID and set information done*******************************//
static T_S32 do_RS_coerr(T_U8 RS_type, T_pDATA buf)
{
T_S32 errCnt;
T_U32 regAddr, offset, tmp;
T_U32 errValue, errAddr;
if (RS_type == RS1_COERR)
{
printf("do RS1 coerr\r\n");
regAddr = FLASH_ECC_REG4 + 0x04;
offset = 0;
}
else if (RS_type == RS2_COERR)
{
printf("do RS2 coerr\r\n");
regAddr = FLASH_ECC_REG4 + 0x08;
/* phy structure, must offset value is 255(251B + 4B)
* phy structure conver to logic structure !!!
* 减去1个RS占的长度(4B*1), rs2 logic offset value is 251B(no RS code)
*/
offset = 255 - 4;
}
errCnt = 0;
HAL_READ_UINT32(regAddr, tmp);
errValue = (tmp >> 16) & 0xFF;
errAddr = (tmp >> 24) & 0xFF;
if ((251 <= errAddr) && (errAddr <= 254)) // 是否是ECC本身错
{
printf("Is RS_err1 ECC itself error, ignore it\r\n");
errCnt++;
}
else if (errAddr != 255)
{
errAddr += offset;
printf("rs err1 value is 0x%x, location is 0x%x\r\n", errValue, errAddr);
printf("excute corect rs err1: 0x%x --> 0x%x\r\n",
buf[errAddr], buf[errAddr] ^ errValue);
buf[errAddr] = buf[errAddr] ^ errValue; // correct
errCnt++;
}
errValue = tmp & 0xFF;
errAddr = (tmp >> 8) & 0xFF;
if ((251 <= errAddr) && (errAddr <= 254)) // 是否是ECC本身错
{
printf("errAddr = 0x%x, errValue = 0x%x\r\n", errAddr, errValue);
printf("Is RS_err2 ECC itself error, ignore it\r\n");
errCnt++;
}
else if (errAddr != 255) // have error
{
errAddr += offset;
printf("rs err2 value is 0x%x, location is 0x%x\r\n", errValue, errAddr);
printf("excute corect rs err2: 0x%x --> 0x%x\r\n",
buf[errAddr], buf[errAddr] ^ errValue);
buf[errAddr] = buf[errAddr] ^ errValue; // correct
errCnt++;
}
return errCnt;
}
/**
* @BRIEF 根据ECC进行纠错
* @AUTHOR lgj
* @DATE 2005-10-25
* @PARAM
* buf
* 518Byte data for coerror.
* fileSysBuf
* file system information buffer.
* @RETURN
* @RETVAL
* >=ECC_CANT_CORRECT, 表示错不可纠, 此时不执行CRC校验;
* 小于ECC_CANT_CORRECT而大于等于ECC_NEED_CRC_CHECK, 表示错误较多, 可能会错纠, 此时执行CRC校验;
* 为0时, 表示无错或已经正确纠错;
* @NOTE
* 1.
* buf: is logic structure: 512B data + 6B file system
* ECC: is phy structure: 251B data + 4B rs1 + 251B data + 4B rs2 + 16B data + 2B bch
*
* 2. 校验码本身错时不用纠
*
* 3. 纠错过程:
*
* @to do
* 1. 当错不可纠时的处理.
*/
T_S32 do_ECC_coerr(T_pDATA buf, T_pDATA fileSysBuf)
{
T_S32 ret;
T_U32 tmp, status;
T_U8 bit_loc;
T_U16 byte_loc;
T_U16 ecc_loc;
T_U32 *reg_addr = (T_U32 *) FLASH_ECC_REG4;
ret = 0;
HAL_READ_UINT32(FLASH_ECC_REG4, status);
if ((status & RS1_NO_ERR_BIT) != RS1_NO_ERR_BIT)
{
// RS1 have error
if (status & RS1_CANT_CORRECT_BIT)
{
printf("RS1 have error, but can't correct(too many error)\r\n");
ret |= RS1_CANT_CORRECT;
}
else
{
// 等待纠错过程结束
while (1)
{
HAL_READ_UINT32(FLASH_ECC_REG4, status);
if (status & RS1_CORRECT_END_BIT)
break;
}
ret += do_RS_coerr(RS1_COERR, buf);
}
}
else
{
// printf("RS1 no error\r\n");
}
// 使用最新的status
if ((status & RS2_NO_ERR_BIT) != RS2_NO_ERR_BIT)
{
// RS2 have error
if (status & RS2_CANT_CORRECT_BIT)
{
printf("RS2 have error, but can't correct(too many error)\r\n");
ret |= RS2_CANT_CORRECT;
}
else
{
// 等待纠错过程结束
while (1)
{
HAL_READ_UINT32(FLASH_ECC_REG4, status);
if (status & RS2_CORRECT_END_BIT)
break;
}
ret += do_RS_coerr(RS2_COERR, buf);
}
}
else
{
// printf("RS2 no error\r\n");
}
// 使用最新的status
if ((status & BCH_NO_ERR_BIT) != BCH_NO_ERR_BIT)
{
// BCH have error
if (status & BCH_CANT_CORRECT_BIT)
{
printf("BCH have error, but can't correct(too many error)\r\n");
ret |= BCH_CANT_CORRECT;
}
else
{
T_U8 cnt;
// 等待纠错过程结束
while (1)
{
HAL_READ_UINT32(FLASH_ECC_REG4, status);
if (status & BCH_CORRECT_END_BIT)
break;
}
// corect bch
HAL_READ_UINT32(FLASH_ECC_REG4 + 0x0C, tmp);
for (cnt=0; cnt<2; cnt++)
{
ecc_loc = (tmp >> 8*cnt) & 0xFF;
if (ecc_loc == 0xFF)
{
// 不是BCH2有错
// printf("BCH %d no error\r\n", cnt);
}
else
{
ret++;
byte_loc = (ecc_loc - 111) / 8 + 510; // ?
bit_loc = (byte_loc - 510) * 8 + 111 + 7 - ecc_loc;
// phy structure conver to logic structure !!!
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -