📄 nand.c
字号:
col = from & (mtd->oobblock - 1); /* Initialize return value */ *retlen = 0; /* Select the NAND device */ nand_select (); /* Loop until all data read */ while (*retlen < len) {#ifdef CONFIG_MTD_NAND_ECC /* Do we have this page in cache ? */ if (this->cache_page == page) goto readdata; /* Send the read command */ nand_command (mtd, NAND_CMD_READ0, 0x00, page); /* Read in a page + oob data*/ for (j=0 ; j < mtd->oobblock + mtd->oobsize ; j++) this->data_buf[j] = readb (this->IO_ADDR_R); nand_command (mtd, NAND_CMD_READ0, 0x00, page); /* copy data into cache, for read out of cache and if ecc fails */ if (this->data_cache) memcpy(this->data_cache,this->data_buf,mtd->oobblock+mtd->oobsize); /* Pick the ECC bytes out of the oob data*/ for (j=0 ; j < 6 ; j++) ecc_code[j] = this->data_buf[(mtd->oobblock + oob_config.ecc_pos[j])]; /* Calculate the ECC and verify it */ /* If block was not written with ECC, skip ECC */ if (oob_config.eccvalid_pos != -1 && (this->data_buf[mtd->oobblock+oob_config.eccvalid_pos] & 0x0f) != 0x0f ) { nand_calculate_ecc (&this->data_buf[0], &ecc_calc[0]); switch (nand_correct_data (&this->data_buf[0],&ecc_code[0], &ecc_calc[0])) { case -1: DEBUG (MTD_DEBUG_LEVEL0,"nand_read_ecc: " \ "Failed ECC read, page 0x%08x\n", page); ecc_failed++; break; case 1: case 2:/* transfer ECC corrected data to cache */ memcpy(this->data_cache,this->data_buf,256); break; } } if (oob_config.eccvalid_pos != -1 && mtd->oobblock == 512 && (this->data_buf[mtd->oobblock+oob_config.eccvalid_pos] & 0xf0) != 0xf0 ) { nand_calculate_ecc (&this->data_buf[256],&ecc_calc[3]); switch (nand_correct_data (&this->data_buf[256],&ecc_code[3], &ecc_calc[3])) { case -1: DEBUG (MTD_DEBUG_LEVEL0,"nand_read_ecc: " \ "Failed ECC read, page 0x%08x\n", page); ecc_failed++; break; case 1: case 2:/* transfer ECC corrected data to cache */ if (this->data_cache) memcpy(&this->data_cache[256],&this->data_buf[256],256); break; } }readdata: /* Read the data from ECC data buffer into return buffer */ data_poi = (this->data_cache) ? this->data_cache : this->data_buf; data_poi += col; if ((*retlen + (mtd->oobblock - col)) >= len) { while (*retlen < len) buf[(*retlen)++] = *data_poi++; } else { for (j=col ; j < mtd->oobblock ; j++) buf[(*retlen)++] = *data_poi++; } /* Set cache page address, invalidate, if ecc_failed */ this->cache_page = (this->data_cache && !ecc_failed) ? page : -1; ecc_status += ecc_failed; ecc_failed = 0; #else /* Send the read command */ nand_command (mtd, NAND_CMD_READ0, col, page); /* Read the data directly into the return buffer */ if ((*retlen + (mtd->oobblock - col)) >= len) { while (*retlen < len) buf[(*retlen)++] = readb (this->IO_ADDR_R); /* We're done */ continue; } else for (j=col ; j < mtd->oobblock; j++) buf[(*retlen)++] = readb (this->IO_ADDR_R);#endif /* For subsequent reads align to page boundary. */ col = 0; /* Increment page address */ page++; } /* De-select the NAND device */ nand_deselect (); /* Wake up anyone waiting on the device */ spin_lock_bh (&this->chip_lock); if (erase_state) this->state = FL_ERASING; else this->state = FL_READY; wake_up (&this->wq); spin_unlock_bh (&this->chip_lock); /* * Return success, if no ECC failures, else -EIO * fs driver will take care of that, because * retlen == desired len and result == -EIO */ return ecc_status ? -EIO : 0;}/* * NAND read out-of-band */static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){ int i, col, page; int erase_state = 0; struct nand_chip *this = mtd->priv; DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); /* Shift to get page */ page = ((int) from) >> this->page_shift; /* Mask to get column */ col = from & 0x0f; /* Initialize return length value */ *retlen = 0; /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n"); *retlen = 0; return -EINVAL; } /* Grab the lock and see if the device is available */ nand_get_chip(this,FL_READING,&erase_state); /* can we read out of cache ? */ if (this->cache_page == page && (col+len <= mtd->oobsize)) { /* Read the data */ memcpy(buf,&this->data_cache[mtd->oobblock+col],len); } else { /* Select the NAND device */ nand_select (); /* Send the read command */ nand_command (mtd, NAND_CMD_READOOB, col, page); /* * Read the data, if we read more than one page * oob data, let the device transfer the data ! */ for (i = 0 ; i < len ; i++) { buf[i] = readb (this->IO_ADDR_R); if ( (col++ & (mtd->oobsize-1)) == (mtd->oobsize-1) ) udelay(this->chip_delay); } /* De-select the NAND device */ nand_deselect (); } /* Wake up anyone waiting on the device */ spin_lock_bh (&this->chip_lock); if (erase_state) this->state = FL_ERASING; else this->state = FL_READY; wake_up (&this->wq); spin_unlock_bh (&this->chip_lock); /* Return happy */ *retlen = len; return 0;}/* * NAND write */static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf){#ifdef CONFIG_MTD_NAND_ECC struct nand_chip *this = mtd->priv; return nand_write_ecc (mtd, to, len, retlen, buf, this->ecc_code_buf);#else return nand_write_ecc (mtd, to, len, retlen, buf, NULL);#endif}/* * NAND write with ECC */static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *ecc_code){ int i, page, col, cnt, ret = 0; struct nand_chip *this = mtd->priv; DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Do not allow write past end of device */ if ((to + len) > mtd->size) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n"); return -EINVAL; } /* Grab the lock and see if the device is available */ nand_get_chip(this,FL_WRITING,NULL); /* Shift to get page */ page = ((int) to) >> this->page_shift; /* Get the starting column */ col = to & (mtd->oobblock - 1); /* Initialize return length value */ *retlen = 0; /* Select the NAND device */ nand_select (); /* Check the WP bit */ nand_command (mtd, NAND_CMD_STATUS, -1, -1); if (!(readb (this->IO_ADDR_R) & 0x80)) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Device is write protected!!!\n"); ret = -EIO; goto out; } /* Loop until all data is written */ while (*retlen < len) { /* Invalidate cache, if we write to this page */ if (this->cache_page == page) this->cache_page = -1; /* Write data into buffer */ if ((col + len) >= mtd->oobblock) for(i=col, cnt=0 ; i < mtd->oobblock ; i++, cnt++) this->data_buf[i] = buf[(*retlen + cnt)]; else for(i=col, cnt=0 ; cnt < (len - *retlen) ; i++, cnt++) this->data_buf[i] = buf[(*retlen + cnt)]; /* We use the same function for write and writev !) */ ret = nand_write_page(mtd,this,page,col,i,ecc_code); if (ret) goto out; /* Next data start at page boundary */ col = 0; /* Update written bytes count */ *retlen += cnt; /* Increment page address */ page++; } /* Return happy */ *retlen = len;out: /* De-select the NAND device */ nand_deselect (); /* Wake up anyone waiting on the device */ spin_lock_bh (&this->chip_lock); this->state = FL_READY; wake_up (&this->wq); spin_unlock_bh (&this->chip_lock); return ret;}/* * NAND write out-of-band */static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf){ int i, column, page, status, ret = 0; struct nand_chip *this = mtd->priv; DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Shift to get page */ page = ((int) to) >> this->page_shift; /* Mask to get column */ column = to & 0x1f; /* Initialize return length value */ *retlen = 0; /* Do not allow write past end of page */ if ((column + len) > mtd->oobsize) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n"); return -EINVAL; } /* Grab the lock and see if the device is available */ nand_get_chip(this,FL_WRITING,NULL); /* Select the NAND device */ nand_select (); /* Check the WP bit */ nand_command (mtd, NAND_CMD_STATUS, -1, -1); if (!(readb (this->IO_ADDR_R) & 0x80)) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n"); ret = -EIO; goto out; } /* Invalidate cache, if we write to this page */ if (this->cache_page == page) this->cache_page = -1; /* Write ones for partial page programming */ for (i=mtd->oobblock ; i < (mtd->oobblock + mtd->oobsize) ; i++) this->data_buf[i] = 0xff; /* Transfer data */ for (i = 0; i< len; i++) this->data_buf[i+mtd->oobblock+column] = buf[i]; /* Write out desired data */ nand_command (mtd, NAND_CMD_SEQIN, mtd->oobblock, page); for (i=0 ; i<mtd->oobsize ; i++) writeb (this->data_buf[i+mtd->oobblock], this->IO_ADDR_W); /* Send command to program the OOB data */ nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1); /* * Wait for program operation to complete. This could * take up to 3000us (3ms) on some devices, so we try * and exit as quickly as possible. */ status = 0; for (i=0 ; i<24 ; i++) { /* Delay for 125us */ udelay (125); /* Check the status */ if (this->dev_ready) if (!this->dev_ready()) continue; /* Check the status */ nand_command (mtd, NAND_CMD_STATUS, -1, -1); status = (int) readb (this->IO_ADDR_R); if (status & 0x40) break; } /* See if device thinks it succeeded */ if (status & 0x01) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " \ "Failed write, page 0x%08x\n", page); ret = -EIO; goto out; }#ifdef CONFIG_MTD_NAND_VERIFY_WRITE /* Send command to read back the data */ nand_command (mtd, NAND_CMD_READOOB, column, page); /* Loop through and verify the data */ for (i=0 ; i<len ; i++) { if (buf[i] != readb (this->IO_ADDR_R)) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " \ "Failed write verify, page 0x%08x\n", page); ret = -EIO; goto out; } }#endif /* Return happy */ *retlen = len;out: /* De-select the NAND device */ nand_deselect (); /* Wake up anyone waiting on the device */ spin_lock_bh (&this->chip_lock); this->state = FL_READY; wake_up (&this->wq); spin_unlock_bh (&this->chip_lock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -