第一部分:Nandflash控制部分
arch/mips/lib/board.c -> driver/mtd/nand/nand.c
-
void nand_init(void)
-
{
-
int i;
-
unsigned int size = 0;
-
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
-
nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
-
size += nand_info[i].size / 1024;
-
if (nand_curr_device == -1)
-
nand_curr_device = i;
-
}
-
if(size)
-
printf("%u MiB\n", size / 1024);
-
-
#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
-
/*
-
* Select the chip in the board/cpu specific driver
-
*/
-
board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
-
#endif
-
}
nand初始化最先调用nand_init(),然后调用 nand_init_chip()对nand进行初始化
-
static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand,
-
ulong base_addr)
-
{
-
int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;
-
int __attribute__((unused)) i = 0;
-
-
if (maxchips < 1)
-
maxchips = 1;
-
mtd->priv = nand; //用mtd->priv指向nand_chip结构的nand
-
-
nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr; //base_addr = 0xbc045300,在blx.h中定义
-
if (board_nand_init(nand) == 0) { //调用board_nand_init(nand)对板子初始化
-
if (nand_scan(mtd, maxchips) == 0) {
-
if (!mtd->name)
-
mtd->name = (char *)default_nand_name;
-
#ifdef CONFIG_NEEDS_MANUAL_RELOC
-
else
-
mtd->name += gd->reloc_off;
-
#endif
-
-
#ifdef CONFIG_MTD_DEVICE
-
/*
-
* Add MTD device so that we can reference it later
-
* via the mtdcore infrastructure (e.g. ubi).
-
*/
-
sprintf(dev_name[i], "nand%d", i);
-
mtd->name = dev_name[i++];
-
add_mtd_device(mtd);
-
#endif
-
board_nand_init_snd(mtd);
-
} else
-
mtd->name = NULL;
-
} else {
-
mtd->name = NULL;
-
mtd->size = 0;
-
}
-
}
-
int board_nand_init(struct nand_chip *nand)
-
{
-
u_int32_t cfg;
-
u_int32_t ctrl;
-
-
cfg = GSC3280_FLCONF_PSM;
-
cfg |= GSC3280_FLCONF_TWB;
-
cfg |= GSC3280_FLCONF_TWHR;
-
cfg |= GSC3280_FLCONF_TWP;
-
cfg |= GSC3280_FLCONF_TRP;
-
cfg |= GSC3280_FLCONF_TWH;
-
writel(cfg,GSC3280_REGADDR_NFC_CONF);
-
-
/* initialize nand_chip data structure */
-
nand->IO_ADDR_R = (void *)GSC3280_REGADDR_NFC_DATA;
-
nand->IO_ADDR_W = (void *)GSC3280_REGADDR_NFC_DATA;
-
nand->select_chip = NULL;
-
-
/* hwcontrol always must be implemented */
-
nand->cmd_ctrl = gsc3280_hwcontrol;
-
nand->dev_ready = gsc3280_dev_ready;
-
nand->set_pb = gsc3280_set_pb;
-
#ifdef CONFIG_GSC3280_USE_DMA
-
nand->dma_trans=gsc3280_nand_dma_transfer;
-
#endif
-
nand->write_page=gsc3280_nand_write_page;
-
nand->ecc.read_page=gsc3280_nand_read_page_ecc;
-
nand->ecc.write_page=gsc3280_nand_write_page_ecc;
-
nand->ecc.read_page_raw = gsc3280_nand_read_page_raw;
-
nand->ecc.write_page_raw = gsc3280_nand_write_page_raw;
-
nand->ecc.size = 256;
-
nand->ecc.bytes = 3;
-
#ifdef CONFIG_GSC3280_NAND_HWECC
-
nand->ecc.mode = NAND_ECC_HW;
-
nand->ecc.correct = gsc3280_nand_check_hwecc;
-
#else
-
nand->ecc.mode = NAND_ECC_SOFT;
-
#endif
-
#ifdef CONFIG_GSC3280_NAND_BBT
-
nand->options = NAND_USE_FLASH_BBT;
-
#else
-
nand->options = NAND_SKIP_BBTSCAN;
-
#endif
-
return 0;
-
}
这部分的详细注释看第二部分。
-
int nand_scan(struct mtd_info *mtd, int maxchips)
-
{
-
int ret;
-
-
ret = nand_scan_ident(mtd, maxchips);
-
if (!ret)
-
ret = nand_scan_tail(mtd);
-
return ret;
-
}
-
int nand_scan_ident(struct mtd_info *mtd, int maxchips)
-
{
-
int i, busw, nand_maf_id;
-
struct nand_chip *chip = mtd->priv;
-
struct nand_flash_dev *type;
-
-
/* Get buswidth to select the correct functions */
-
busw = chip->options & NAND_BUSWIDTH_16;
-
/* Set the default functions */
-
nand_set_defaults(chip, busw);
-
-
/* Read the flash type */
-
type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);
-
-
if (IS_ERR(type)) {
-
#ifndef CONFIG_SYS_NAND_QUIET_TEST
-
printk(KERN_WARNING "No NAND device found!!!\n");
-
#endif
-
chip->select_chip(mtd, -1);
-
return PTR_ERR(type);
-
}
-
-
/* Check for a chip array */
-
for (i = 1; i < maxchips; i++) {
-
chip->select_chip(mtd, i);
-
/* See comment in nand_get_flash_type for reset */
-
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
-
/* Send the command for reading device ID */
-
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
-
/* Read manufacturer and device IDs */
-
if (nand_maf_id != chip->read_byte(mtd) ||
-
type->id != chip->read_byte(mtd))
-
break;
-
}
-
#ifdef DEBUG
-
if (i > 1)
-
printk(KERN_INFO "%d NAND chips detected\n", i);
-
#endif
-
-
/* Store the number of chips and calc total size for mtd */
-
chip->numchips = i;
-
mtd->size = i * chip->chipsize;
-
-
return 0;
-
}
第二部分:GSC3280控制部分
nandflash-S34ML01G1_04G1参数图如下:
-
int board_nand_init(struct nand_chip *nand)
-
{
-
u_int32_t cfg;
-
u_int32_t ctrl;
-
//hclk = 166M,所以thclk = 1/(0.166 G) = 6 ns,根据上表,再将这个值带入
-
cfg = GSC3280_FLCONF_PSM; //GSC3280_FLCONF_PSM = (1<<31),表示正常模式
-
cfg |= GSC3280_FLCONF_TWB; //GSC3280_FLCONF_TWB (0x13)<<23 , twb = thclk*(TWB+1)>100,可得TWB>15.6 或TWB>0x10;
-
cfg |= GSC3280_FLCONF_TWHR; //GSC3280_FLCONF_TWHR (0x13)<<17, twhr = thclk*(TWHR+1)>60,可得TWHR>9
-
cfg |= GSC3280_FLCONF_TWP; //GSC3280_FLCONF_TWP (0x9)<<11, twp = thclk*(TWP+1)>12,可得TWP>1
-
cfg |= GSC3280_FLCONF_TRP; //GSC3280_FLCONF_TRP (0x9)<<5 , trp = thclk*(TRP+1)>12,可得TRP>1
-
cfg |= GSC3280_FLCONF_TWH; //GSC3280_FLCONF_TWH 0x4, twh = thclk*(TWH+1)>10,可得TWH>1
-
writel(cfg,GSC3280_REGADDR_NFC_CONF);
-
-
/* initialize nand_chip data structure */
-
nand->IO_ADDR_R = (void *)GSC3280_REGADDR_NFC_DATA; //设置IO_ADDR_X的地址为数据寄存器
-
nand->IO_ADDR_W = (void *)GSC3280_REGADDR_NFC_DATA;
-
nand->select_chip = NULL;
-
-
/* hwcontrol always must be implemented */
-
nand->cmd_ctrl = gsc3280_hwcontrol; //根据控制命令来设置IO_ADDR_X
-
nand->dev_ready = gsc3280_dev_ready;
-
nand->set_pb = gsc3280_set_pb;
-
#ifdef CONFIG_GSC3280_USE_DMA
-
nand->dma_trans=gsc3280_nand_dma_transfer;
-
#endif
-
nand->write_page=gsc3280_nand_write_page;
-
nand->ecc.read_page=gsc3280_nand_read_page_ecc;
-
nand->ecc.write_page=gsc3280_nand_write_page_ecc;
-
nand->ecc.read_page_raw = gsc3280_nand_read_page_raw;
-
nand->ecc.write_page_raw = gsc3280_nand_write_page_raw;
-
nand->ecc.size = 256;
-
nand->ecc.bytes = 3;
-
#ifdef CONFIG_GSC3280_NAND_HWECC
-
nand->ecc.mode = NAND_ECC_HW;
-
nand->ecc.correct = gsc3280_nand_check_hwecc;
-
#else
-
nand->ecc.mode = NAND_ECC_SOFT;
-
#endif
-
#ifdef CONFIG_GSC3280_NAND_BBT
-
nand->options = NAND_USE_FLASH_BBT;
-
#else
-
nand->options = NAND_SKIP_BBTSCAN;
-
#endif
-
return 0;
-
}
-
int board_nand_init_snd(struct mtd_info *mtd)
-
{
-
uint32_t ctrl;
-
-
ctrl=readl((void*)GSC3280_REGADDR_NFC_CTRL);
-
-
#ifdef CONFIG_MTD_GSC3280_NAND_HWECC
-
ctrl |= GSC3280_FLCTRL_EEN;
-
-
#endif
-
if(mtd->writesize == 0x800)
-
ctrl |= GSC3280_FLCTRL_PS;/*page=2k*/
-
if(mtd->erasesize/mtd->writesize == 128)
-
ctrl |= GSC3280_FLCTRL_BS;/*Block=128pages*/
-
if(mtd->oobsize != 0x40 && mtd->oobsize != 0x80)
-
ctrl |= GSC3280_FLCTRL_SS;/*Extended mode*/
-
ctrl |= GSC3280_FLCTRL_ADDRC;/*Default 5 ADDR CYCLES*/
-
writel(ctrl, (void *)GSC3280_REGADDR_NFC_CTRL);
-
return 0;
-
-
}
-
static void gsc3280_hwcontrol(struct mtd_info *mtd, long cmd, unsigned int ctrl)
-
{
-
struct nand_chip *chip = mtd->priv;
-
-
-
if(ctrl & NAND_CA){
-
switch(cmd){
-
case NAND_CMD_READ0:
-
// chip->addrflag=3;//dma buffer
-
case NAND_CMD_READ1:
-
case NAND_CMD_READID:
-
case NAND_CMD_READOOB:
-
case NAND_CMD_RNDOUT:
-
// case NAND_CMD_RNDOUTSTART:
-
chip->addrflag=0;
-
break;
-
case NAND_CMD_WRITE0:
-
case NAND_CMD_SEQIN:
-
chip->addrflag=1;
-
break;
-
case NAND_CMD_ERASE1:
-
chip->addrflag=2;
-
break;
-
}
-
-
}
-
-
if (ctrl & NAND_CTRL_CHANGE) {
-
ulong IO_ADDR_W = GSC3280_REGADDR_NFC_CONF;
-
if (ctrl & NAND_CLE){
-
IO_ADDR_W = GSC3280_REGADDR_NFC_COMM;//cmd reg
-
}
-
else if (ctrl & NAND_ALE){
-
-
switch(chip->addrflag){
-
case 0:
-
IO_ADDR_W = GSC3280_REGADDR_NFC_ADDR0L;
-
break;
-
case 1:
-
IO_ADDR_W = GSC3280_REGADDR_NFC_ADDR1L;
-
break;
-
case 2:
-
IO_ADDR_W = GSC3280_REGADDR_NFC_ADDR1L;
-
break;
-
case 3:
-
IO_ADDR_W = GSC3280_NFC_BASEADDR;
-
break;
-
}
-
}
-
else{
-
IO_ADDR_W = GSC3280_REGADDR_NFC_DATA;//data reg
-
}
-
chip->IO_ADDR_W = (void *)IO_ADDR_W;
-
chip->IO_ADDR_R = (void *)IO_ADDR_W;
-
}
-
if (cmd != NAND_CMD_NONE && !(ctrl & NAND_CA) ){
-
writel(cmd, chip->IO_ADDR_W);
-
}
-
}
gsc3280_hwcontrol功能:主要是根据命令来设定IO_ADDR_W和IO_ADDR_R地址。
这个函数会在 nand_command(struct mtd_info *mtd, unsigned int command,int column, int page_addr) 中被调用,如下
-
static void nand_command(struct mtd_info *mtd, unsigned int command,
-
int column, int page_addr)
-
{
-
register struct nand_chip *chip = mtd->priv;
-
int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; //#define NAND_CTRL_CLE (NAND_NCE | NAND_CLE), 用来设置命令
-
//#define NAND_CTRL_ALE (NAND_NCE | NAND_ALE), 用来设置读写地址
-
//#define NAND_CTRL_CHANGE 0x80
-
uint32_t rst_sts_cnt = CONFIG_SYS_NAND_RESET_CNT;
-
-
/*
-
* Write out the command to the device.
-
*/
-
if (command == NAND_CMD_SEQIN) {
-
int readcmd;
-
-
if (column >= mtd->writesize) {
-
/* OOB area */
-
column -= mtd->writesize;
-
readcmd = NAND_CMD_READOOB;
-
} else if (column < 256) {
-
/* First 256 bytes --> READ0 */
-
readcmd = NAND_CMD_READ0;
-
} else {
-
column -= 256;
-
readcmd = NAND_CMD_READ1;
-
}
-
chip->cmd_ctrl(mtd, readcmd, ctrl);
-
ctrl &= ~NAND_CTRL_CHANGE;
-
}
-
chip->cmd_ctrl(mtd, command, ctrl); //写入命令
-
-
/*
-
* Address cycle, when necessary
-
*/
-
ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
-
/* Serially input address */
-
if (column != -1) {
-
/* Adjust columns for 16 bit buswidth */
-
if (chip->options & NAND_BUSWIDTH_16)
-
column >>= 1;
-
chip->cmd_ctrl(mtd, column, ctrl);
-
ctrl &= ~NAND_CTRL_CHANGE;
-
}
-
if (page_addr != -1) {
-
chip->cmd_ctrl(mtd, page_addr, ctrl);
-
ctrl &= ~NAND_CTRL_CHANGE;
-
chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);
-
/* One more address cycle for devices > 32MiB */
-
if (chip->chipsize > (32 << 20))
-
chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);
-
}
-
chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-
-
/*
-
* program and erase have their own busy handlers
-
* status and sequential in needs no delay
-
*/
-
switch (command) {
-
-
case NAND_CMD_PAGEPROG:
-
case NAND_CMD_ERASE1:
-
case NAND_CMD_ERASE2:
-
case NAND_CMD_SEQIN:
-
case NAND_CMD_STATUS:
-
return;
-
-
case NAND_CMD_RESET:
-
if (chip->dev_ready)
-
break;
-
udelay(chip->chip_delay);
-
chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
-
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
-
chip->cmd_ctrl(mtd,
-
NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-
while (!(chip->read_byte(mtd) & NAND_STATUS_READY) &&
-
(rst_sts_cnt--));
-
return;
-
-
/* This applies to read commands */
-
default:
-
/*
-
* If we don't have access to the busy pin, we apply the given
-
* command delay
-
*/
-
if (!chip->dev_ready) {
-
udelay(chip->chip_delay);
-
return;
-
}
-
}
-
/* Apply this short delay always to ensure that we do wait tWB in
-
* any case on any machine. */
-
ndelay(100);
-
-
nand_wait_ready(mtd);
-
}
-
static int gsc3280_dev_ready(struct mtd_info *mtd)
-
{
-
uint8_t state = readb((const void *)GSC3280_REGADDR_NFC_STATE);
-
return (state&0x61)==0x1;
-
}
gsc3280_dev_ready:读取NFC_STATE状态标志位,0x61=1100001,第0位表示输入信号此时是否为忙,为1表示不忙,0表示忙,5-6为表示控制器是否为空闲状态,00表示空闲,01表示控制器正在处理
命令。gsc3280_dev_ready返回1表示空闲。
-
static int gsc3280_set_pb(struct mtd_info *mtd, loff_t lower_block ,loff_t upper_block)
-
{
-
u_int32_t pb0;
-
-
struct nand_chip *chip=mtd->priv;
-
-
if((lower_block*mtd->erasesize)>chip->chipsize||(upper_block*mtd->erasesize)>chip->chipsize){
-
printf("outside the flash area \n");
-
return -1;
-
}
-
-
pb0=(lower_block>>16)|(upper_block&0x0000ffff); //????????
-
-
writel(pb0,GSC3280_REGADDR_NFC_PB0);
-
printf("the blocks from %lld to %lld is protected!\n",lower_block,upper_block);
-
return 0;
-
}
gsc3280_set_pb:设置保护块的起始地址与结束地址,保护块区间不能进行写与擦除操作。
??????:pb0=(lower_block>>16)|(upper_block&0x0000ffff);
-
int gsc3280_nand_dma_transfer(struct mtd_info *mtd, uint8_t *buffer, int size, int col, int isread){
-
u_int32_t cntr;
-
unsigned long memaddr=virt_to_phys((void *)buffer); //????
-
-
int state;
-
if(!col){
-
cntr=(size>>2)<<16;
-
}
-
else{
-
cntr=((mtd->writesize-col)>>2)<<16 | col; //?????
-
}
-
writel(cntr,GSC3280_REGADDR_NFC_DMACNTR);
-
writel(memaddr,GSC3280_REGADDR_NFC_DMAADDR); //用于设置传输块大小以及要传输的地址
-
-
if(isread){
-
// 0x0101d000
-
writel(0x0101d000,GSC3280_REGADDR_NFC_DMACTRL);//使能DMA、读取buffer数据到AHB(DMA_DIR=1)、??、单向传输地址递增(DMA_BURST=010)
-
}
-
else
-
//ox0100d000
-
writel(0x0100d000,GSC3280_REGADDR_NFC_DMACTRL); //使能DMA,将AHB总线数据写到buffer
-
-
do{
-
state=readl(GSC3280_REGADDR_NFC_STATE); //一直等待到DMA传输完毕
-
}while(state&0x80);
-
return 0;
-
-
}
-
static int gsc3280_nand_check_hwecc(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc
-
)
-
{
-
u32 eccstatus;
-
u8 eccerror;
-
u8 ecccorrect;
-
-
eccstatus=readl(GSC3280_REGADDR_NFC_ECCSTATUS); //读取校验信息
-
-
if(readl(GSC3280_REGADDR_NFC_CTRL)&GSC3280_FLCTRL_PS){ //检验需要校验多少位
-
eccerror=(eccstatus>>16)&&0xff;
-
ecccorrect=eccstatus&&0xff;
-
}
-
else{
-
eccerror=(eccstatus>>16)&&0xf;
-
ecccorrect=eccstatus&&0xf;
-
}
-
-
-
if(!eccerror||!(eccerror^ecccorrect)){ //检测校验是否正确
-
return 0;
-
}
-
else{
-
printf("gsc3280_nand_correct_data: not implemented\n");
-
return -1;
-
}
-
}
-
static int gsc3280_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-
uint8_t *buf, int page)
-
{
-
#ifdef CONFIG_GSC3280_USE_DMA
-
chip->dma_trans(mtd,buf,mtd->writesize,0,1);
-
#else
-
memcpy(buf,(const void *)GSC3280_NFC_BASEADDR,mtd->writesize); //读取页
-
#endif
-
return chip->ecc.read_oob(mtd, chip, page, 1); //??????????
-
}
-
static int gsc3280_nand_read_page_ecc(struct mtd_info *mtd, struct nand_chip *chip,
-
uint8_t *buf, int page)
-
{
-
#ifdef CONFIG_GSC3280_NAND_HWECC
-
int ret;
-
ret=chip->ecc.correct(NULL,NULL,NULL,NULL);
-
if(ret)
-
return -1;
-
else{
-
chip->ecc.read_page_raw(mtd, chip, buf, page);
-
}
-
#else
-
int i, eccsize = chip->ecc.size;
-
int eccbytes = chip->ecc.bytes;
-
int eccsteps = chip->ecc.steps;
-
uint8_t *p = buf;
-
uint8_t *ecc_calc = chip->buffers->ecccalc;
-
uint8_t *ecc_code = chip->buffers->ecccode;
-
uint32_t *eccpos = chip->ecc.layout->eccpos;
-
-
chip->ecc.read_page_raw(mtd, chip, buf, page);
-
-
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
-
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
-
-
for (i = 0; i < chip->ecc.total; i++){
-
ecc_code[i] = chip->oob_poi[eccpos[i]];
-
}
-
-
eccsteps = chip->ecc.steps;
-
p = buf;
-
-
for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-
int stat;
-
-
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
-
if (stat < 0)
-
mtd->ecc_stats.failed++;
-
else
-
mtd->ecc_stats.corrected += stat;
-
}
-
#endif
-
return 0;
-
}
-
static void gsc3280_nand_write_page_ecc(struct mtd_info *mtd, struct nand_chip *chip,
-
uint8_t *buf)
-
{
-
#ifndef CONFIG_GSC3280_NAND_HWECC
-
int i, eccsize = chip->ecc.size;
-
int eccbytes = chip->ecc.bytes;
-
int eccsteps = chip->ecc.steps;
-
uint8_t *ecc_calc = chip->buffers->ecccalc;
-
const uint8_t *p = buf;
-
uint32_t *eccpos = chip->ecc.layout->eccpos;
-
-
/* Software ecc calculation */
-
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
-
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
-
-
for (i = 0; i < chip->ecc.total; i++)
-
chip->oob_poi[eccpos[i]] = ecc_calc[i];
-
#endif
-
chip->ecc.write_page_raw(mtd, chip, buf);
-
-
}
-
static void gsc3280_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-
const uint8_t *buf)
-
{
-
#ifdef CONFIG_GSC3280_USE_DMA
-
chip->dma_trans(mtd,buf,mtd->writesize,0,0);
-
#else
-
memcpy((void*)GSC3280_NFC_BASEADDR,buf,mtd->writesize);
-
#endif
-
memset((void*)GSC3280_NFC_BASEADDR+mtd->writesize,0xff,mtd->oobsize);
-
}
-
static int gsc3280_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-
const uint8_t *buf, int page, int cached, int raw)
-
{
-
int status;
-
-
chip->ecc.write_page(mtd, chip, buf);
-
chip->cmdfunc(mtd, NAND_CMD_WRITE0, -1, page);
-
status = chip->waitfunc(mtd, chip);
-
/*
-
* See if operation failed and additional status checks are
-
* available
-
*/
-
if ((status & NAND_STATUS_FAIL) && (chip->errstat))
-
status = chip->errstat(mtd, chip, FL_WRITING, status, page);
-
-
if (status & NAND_STATUS_FAIL){
-
return -1;
-
}
-
-
chip->ecc.write_oob(mtd, chip, page&chip->pagemask);
-
return 0;
-
}
阅读(1128) | 评论(0) | 转发(0) |