Merge branch 'master' of git://git.denx.de/u-boot-nand-flash
This commit is contained in:
commit
d6639d10db
@ -120,7 +120,7 @@ int board_eth_init(bd_t *bis)
|
||||
#ifdef CONFIG_NAND_DAVINCI
|
||||
static int
|
||||
davinci_std_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int page)
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
int i, eccsize = chip->ecc.size;
|
||||
@ -167,8 +167,9 @@ davinci_std_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void davinci_std_write_page_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf)
|
||||
static int davinci_std_write_page_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required)
|
||||
{
|
||||
unsigned char davinci_ecc_buf[NAND_MAX_OOBSIZE];
|
||||
struct nand_chip *this = mtd->priv;
|
||||
@ -218,6 +219,7 @@ static void davinci_std_write_page_syndrome(struct mtd_info *mtd,
|
||||
i = mtd->oobsize - (oob - chip->oob_poi);
|
||||
if (i)
|
||||
chip->write_buf(mtd, oob, i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int davinci_std_write_oob_syndrome(struct mtd_info *mtd,
|
||||
@ -239,7 +241,7 @@ static int davinci_std_write_oob_syndrome(struct mtd_info *mtd,
|
||||
}
|
||||
|
||||
static int davinci_std_read_oob_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, int page, int sndcmd)
|
||||
struct nand_chip *chip, int page)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
uint8_t *buf = chip->oob_poi;
|
||||
@ -249,7 +251,7 @@ static int davinci_std_read_oob_syndrome(struct mtd_info *mtd,
|
||||
|
||||
chip->read_buf(mtd, bufpoi, mtd->oobsize);
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nand_dm365evm_select_chip(struct mtd_info *mtd, int chip)
|
||||
|
@ -62,8 +62,8 @@ static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat)
|
||||
ops.oobbuf = oobbuf;
|
||||
ops.len = nand->writesize;
|
||||
ops.ooblen = nand->oobsize;
|
||||
ops.mode = MTD_OOB_RAW;
|
||||
i = nand->read_oob(nand, addr, &ops);
|
||||
ops.mode = MTD_OPS_RAW;
|
||||
i = mtd_read_oob(nand, addr, &ops);
|
||||
if (i < 0) {
|
||||
printf("Error (%d) reading page %08lx\n", i, off);
|
||||
free(datbuf);
|
||||
@ -404,13 +404,13 @@ static int raw_access(nand_info_t *nand, ulong addr, loff_t off, ulong count,
|
||||
.oobbuf = ((u8 *)addr) + nand->writesize,
|
||||
.len = nand->writesize,
|
||||
.ooblen = nand->oobsize,
|
||||
.mode = MTD_OOB_RAW
|
||||
.mode = MTD_OPS_RAW
|
||||
};
|
||||
|
||||
if (read)
|
||||
ret = nand->read_oob(nand, off, &ops);
|
||||
ret = mtd_read_oob(nand, off, &ops);
|
||||
else
|
||||
ret = nand->write_oob(nand, off, &ops);
|
||||
ret = mtd_write_oob(nand, off, &ops);
|
||||
|
||||
if (ret) {
|
||||
printf("%s: error at offset %llx, ret %d\n",
|
||||
@ -425,6 +425,31 @@ static int raw_access(nand_info_t *nand, ulong addr, loff_t off, ulong count,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Adjust a chip/partition size down for bad blocks so we don't
|
||||
* read/write/erase past the end of a chip/partition by accident.
|
||||
*/
|
||||
static void adjust_size_for_badblocks(loff_t *size, loff_t offset, int dev)
|
||||
{
|
||||
/* We grab the nand info object here fresh because this is usually
|
||||
* called after arg_off_size() which can change the value of dev.
|
||||
*/
|
||||
nand_info_t *nand = &nand_info[dev];
|
||||
loff_t maxoffset = offset + *size;
|
||||
int badblocks = 0;
|
||||
|
||||
/* count badblocks in NAND from offset to offset + size */
|
||||
for (; offset < maxoffset; offset += nand->erasesize) {
|
||||
if (nand_block_isbad(nand, offset))
|
||||
badblocks++;
|
||||
}
|
||||
/* adjust size if any bad blocks found */
|
||||
if (badblocks) {
|
||||
*size -= badblocks * nand->erasesize;
|
||||
printf("size adjusted to 0x%llx (%d bad blocks)\n",
|
||||
(unsigned long long)*size, badblocks);
|
||||
}
|
||||
}
|
||||
|
||||
static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int i, ret = 0;
|
||||
@ -521,6 +546,7 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
int scrub = !strncmp(cmd, "scrub", 5);
|
||||
int spread = 0;
|
||||
int args = 2;
|
||||
int adjust_size = 0;
|
||||
const char *scrub_warn =
|
||||
"Warning: "
|
||||
"scrub option will erase all factory set bad blocks!\n"
|
||||
@ -537,8 +563,10 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
spread = 1;
|
||||
} else if (!strcmp(&cmd[5], ".part")) {
|
||||
args = 1;
|
||||
adjust_size = 1;
|
||||
} else if (!strcmp(&cmd[5], ".chip")) {
|
||||
args = 0;
|
||||
adjust_size = 1;
|
||||
} else {
|
||||
goto usage;
|
||||
}
|
||||
@ -558,6 +586,10 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
&maxsize) != 0)
|
||||
return 1;
|
||||
|
||||
/* size is unspecified */
|
||||
if (adjust_size && !scrub)
|
||||
adjust_size_for_badblocks(&size, off, dev);
|
||||
|
||||
nand = &nand_info[dev];
|
||||
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
@ -642,6 +674,9 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
&off, &size, &maxsize) != 0)
|
||||
return 1;
|
||||
|
||||
/* size is unspecified */
|
||||
if (argc < 5)
|
||||
adjust_size_for_badblocks(&size, off, dev);
|
||||
rwsize = size;
|
||||
}
|
||||
|
||||
@ -680,13 +715,13 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
mtd_oob_ops_t ops = {
|
||||
.oobbuf = (u8 *)addr,
|
||||
.ooblen = rwsize,
|
||||
.mode = MTD_OOB_RAW
|
||||
.mode = MTD_OPS_RAW
|
||||
};
|
||||
|
||||
if (read)
|
||||
ret = nand->read_oob(nand, off, &ops);
|
||||
ret = mtd_read_oob(nand, off, &ops);
|
||||
else
|
||||
ret = nand->write_oob(nand, off, &ops);
|
||||
ret = mtd_write_oob(nand, off, &ops);
|
||||
} else if (raw) {
|
||||
ret = raw_access(nand, addr, off, pagecount, read);
|
||||
} else {
|
||||
@ -729,7 +764,7 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
while (argc > 0) {
|
||||
addr = simple_strtoul(*argv, NULL, 16);
|
||||
|
||||
if (nand->block_markbad(nand, addr)) {
|
||||
if (mtd_block_markbad(nand, addr)) {
|
||||
printf("block 0x%08lx NOT marked "
|
||||
"as bad! ERROR %d\n",
|
||||
addr, ret);
|
||||
|
@ -83,7 +83,7 @@ static int onenand_block_read(loff_t from, size_t len,
|
||||
ops.len = blocksize;
|
||||
|
||||
while (blocks) {
|
||||
ret = mtd->block_isbad(mtd, ofs);
|
||||
ret = mtd_block_isbad(mtd, ofs);
|
||||
if (ret) {
|
||||
printk("Bad blocks %d at 0x%x\n",
|
||||
(u32)(ofs >> this->erase_shift), (u32)ofs);
|
||||
@ -97,7 +97,7 @@ static int onenand_block_read(loff_t from, size_t len,
|
||||
ops.datbuf = buf;
|
||||
|
||||
ops.retlen = 0;
|
||||
ret = mtd->read_oob(mtd, ofs, &ops);
|
||||
ret = mtd_read_oob(mtd, ofs, &ops);
|
||||
if (ret) {
|
||||
printk("Read failed 0x%x, %d\n", (u32)ofs, ret);
|
||||
ofs += blocksize;
|
||||
@ -118,7 +118,7 @@ static int onenand_write_oneblock_withoob(loff_t to, const u_char * buf,
|
||||
struct mtd_oob_ops ops = {
|
||||
.len = mtd->writesize,
|
||||
.ooblen = mtd->oobsize,
|
||||
.mode = MTD_OOB_AUTO,
|
||||
.mode = MTD_OPS_AUTO_OOB,
|
||||
};
|
||||
int page, ret = 0;
|
||||
for (page = 0; page < (mtd->erasesize / mtd->writesize); page ++) {
|
||||
@ -126,7 +126,7 @@ static int onenand_write_oneblock_withoob(loff_t to, const u_char * buf,
|
||||
buf += mtd->writesize;
|
||||
ops.oobbuf = (u_char *)buf;
|
||||
buf += mtd->oobsize;
|
||||
ret = mtd->write_oob(mtd, to, &ops);
|
||||
ret = mtd_write_oob(mtd, to, &ops);
|
||||
if (ret)
|
||||
break;
|
||||
to += mtd->writesize;
|
||||
@ -156,7 +156,7 @@ static int onenand_block_write(loff_t to, size_t len,
|
||||
ofs = to;
|
||||
|
||||
while (blocks) {
|
||||
ret = mtd->block_isbad(mtd, ofs);
|
||||
ret = mtd_block_isbad(mtd, ofs);
|
||||
if (ret) {
|
||||
printk("Bad blocks %d at 0x%x\n",
|
||||
(u32)(ofs >> this->erase_shift), (u32)ofs);
|
||||
@ -165,7 +165,7 @@ static int onenand_block_write(loff_t to, size_t len,
|
||||
}
|
||||
|
||||
if (!withoob)
|
||||
ret = mtd->write(mtd, ofs, blocksize, &_retlen, buf);
|
||||
ret = mtd_write(mtd, ofs, blocksize, &_retlen, buf);
|
||||
else
|
||||
ret = onenand_write_oneblock_withoob(ofs, buf, &_retlen);
|
||||
if (ret) {
|
||||
@ -195,7 +195,7 @@ static int onenand_block_erase(u32 start, u32 size, int force)
|
||||
int blocksize = 1 << this->erase_shift;
|
||||
|
||||
for (ofs = start; ofs < (start + size); ofs += blocksize) {
|
||||
ret = mtd->block_isbad(mtd, ofs);
|
||||
ret = mtd_block_isbad(mtd, ofs);
|
||||
if (ret && !force) {
|
||||
printf("Skip erase bad block %d at 0x%x\n",
|
||||
(u32)(ofs >> this->erase_shift), (u32)ofs);
|
||||
@ -206,7 +206,7 @@ static int onenand_block_erase(u32 start, u32 size, int force)
|
||||
instr.len = blocksize;
|
||||
instr.priv = force;
|
||||
instr.mtd = mtd;
|
||||
ret = mtd->erase(mtd, &instr);
|
||||
ret = mtd_erase(mtd, &instr);
|
||||
if (ret) {
|
||||
printf("erase failed block %d at 0x%x\n",
|
||||
(u32)(ofs >> this->erase_shift), (u32)ofs);
|
||||
@ -261,7 +261,7 @@ static int onenand_block_test(u32 start, u32 size)
|
||||
while (blocks < end_block) {
|
||||
printf("\rTesting block %d at 0x%x", (u32)(ofs >> this->erase_shift), (u32)ofs);
|
||||
|
||||
ret = mtd->block_isbad(mtd, ofs);
|
||||
ret = mtd_block_isbad(mtd, ofs);
|
||||
if (ret) {
|
||||
printf("Skip erase bad block %d at 0x%x\n",
|
||||
(u32)(ofs >> this->erase_shift), (u32)ofs);
|
||||
@ -270,19 +270,19 @@ static int onenand_block_test(u32 start, u32 size)
|
||||
|
||||
instr.addr = ofs;
|
||||
instr.len = blocksize;
|
||||
ret = mtd->erase(mtd, &instr);
|
||||
ret = mtd_erase(mtd, &instr);
|
||||
if (ret) {
|
||||
printk("Erase failed 0x%x, %d\n", (u32)ofs, ret);
|
||||
goto next;
|
||||
}
|
||||
|
||||
ret = mtd->write(mtd, ofs, blocksize, &retlen, buf);
|
||||
ret = mtd_write(mtd, ofs, blocksize, &retlen, buf);
|
||||
if (ret) {
|
||||
printk("Write failed 0x%x, %d\n", (u32)ofs, ret);
|
||||
goto next;
|
||||
}
|
||||
|
||||
ret = mtd->read(mtd, ofs, blocksize, &retlen, verify_buf);
|
||||
ret = mtd_read(mtd, ofs, blocksize, &retlen, verify_buf);
|
||||
if (ret) {
|
||||
printk("Read failed 0x%x, %d\n", (u32)ofs, ret);
|
||||
goto next;
|
||||
@ -324,7 +324,7 @@ static int onenand_dump(struct mtd_info *mtd, ulong off, int only_oob)
|
||||
ops.len = mtd->writesize;
|
||||
ops.ooblen = mtd->oobsize;
|
||||
ops.retlen = 0;
|
||||
i = mtd->read_oob(mtd, addr, &ops);
|
||||
i = mtd_read_oob(mtd, addr, &ops);
|
||||
if (i < 0) {
|
||||
printf("Error (%d) reading page %08lx\n", i, off);
|
||||
free(datbuf);
|
||||
@ -373,7 +373,7 @@ static int do_onenand_bad(cmd_tbl_t * cmdtp, int flag, int argc, char * const ar
|
||||
/* Currently only one OneNAND device is supported */
|
||||
printf("\nDevice %d bad blocks:\n", 0);
|
||||
for (ofs = 0; ofs < mtd->size; ofs += mtd->erasesize) {
|
||||
if (mtd->block_isbad(mtd, ofs))
|
||||
if (mtd_block_isbad(mtd, ofs))
|
||||
printf(" %08x\n", (u32)ofs);
|
||||
}
|
||||
|
||||
@ -530,7 +530,7 @@ static int do_onenand_markbad(cmd_tbl_t * cmdtp, int flag, int argc, char * cons
|
||||
while (argc > 0) {
|
||||
addr = simple_strtoul(*argv, NULL, 16);
|
||||
|
||||
if (mtd->block_markbad(mtd, addr)) {
|
||||
if (mtd_block_markbad(mtd, addr)) {
|
||||
printf("block 0x%08lx NOT marked "
|
||||
"as bad! ERROR %d\n",
|
||||
addr, ret);
|
||||
|
@ -68,7 +68,7 @@ void env_relocate_spec(void)
|
||||
/* Check OneNAND exist */
|
||||
if (mtd->writesize)
|
||||
/* Ignore read fail */
|
||||
mtd->read(mtd, env_addr, ONENAND_MAX_ENV_SIZE,
|
||||
mtd_read(mtd, env_addr, ONENAND_MAX_ENV_SIZE,
|
||||
&retlen, (u_char *)buf);
|
||||
else
|
||||
mtd->writesize = MAX_ONENAND_PAGESIZE;
|
||||
@ -113,12 +113,12 @@ int saveenv(void)
|
||||
#endif
|
||||
instr.addr = env_addr;
|
||||
instr.mtd = mtd;
|
||||
if (mtd->erase(mtd, &instr)) {
|
||||
if (mtd_erase(mtd, &instr)) {
|
||||
printf("OneNAND: erase failed at 0x%08llx\n", env_addr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mtd->write(mtd, env_addr, ONENAND_MAX_ENV_SIZE, &retlen,
|
||||
if (mtd_write(mtd, env_addr, ONENAND_MAX_ENV_SIZE, &retlen,
|
||||
(u_char *)&env_new)) {
|
||||
printf("OneNAND: write failed at 0x%llx\n", instr.addr);
|
||||
return 2;
|
||||
|
@ -25,7 +25,9 @@ include $(TOPDIR)/config.mk
|
||||
|
||||
LIB := $(obj)libmtd.o
|
||||
|
||||
COBJS-$(CONFIG_MTD_DEVICE) += mtdcore.o
|
||||
ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND)))
|
||||
COBJS-y += mtdcore.o
|
||||
endif
|
||||
COBJS-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
|
||||
COBJS-$(CONFIG_MTD_CONCAT) += mtdconcat.o
|
||||
COBJS-$(CONFIG_HAS_DATAFLASH) += at45.o
|
||||
|
@ -244,12 +244,12 @@ int cfi_mtd_init(void)
|
||||
mtd->size = fi->size;
|
||||
mtd->writesize = 1;
|
||||
|
||||
mtd->erase = cfi_mtd_erase;
|
||||
mtd->read = cfi_mtd_read;
|
||||
mtd->write = cfi_mtd_write;
|
||||
mtd->sync = cfi_mtd_sync;
|
||||
mtd->lock = cfi_mtd_lock;
|
||||
mtd->unlock = cfi_mtd_unlock;
|
||||
mtd->_erase = cfi_mtd_erase;
|
||||
mtd->_read = cfi_mtd_read;
|
||||
mtd->_write = cfi_mtd_write;
|
||||
mtd->_sync = cfi_mtd_sync;
|
||||
mtd->_lock = cfi_mtd_lock;
|
||||
mtd->_unlock = cfi_mtd_unlock;
|
||||
mtd->priv = fi;
|
||||
|
||||
if (add_mtd_device(mtd))
|
||||
|
@ -70,14 +70,14 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
/* Entire transaction goes into this subdev */
|
||||
size = len;
|
||||
|
||||
err = subdev->read(subdev, from, size, &retsize, buf);
|
||||
err = mtd_read(subdev, from, size, &retsize, buf);
|
||||
|
||||
/* Save information about bitflips! */
|
||||
if (unlikely(err)) {
|
||||
if (err == -EBADMSG) {
|
||||
if (mtd_is_eccerr(err)) {
|
||||
mtd->ecc_stats.failed++;
|
||||
ret = err;
|
||||
} else if (err == -EUCLEAN) {
|
||||
} else if (mtd_is_bitflip(err)) {
|
||||
mtd->ecc_stats.corrected++;
|
||||
/* Do not overwrite -EBADMSG !! */
|
||||
if (!ret)
|
||||
@ -105,9 +105,6 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
int err = -EINVAL;
|
||||
int i;
|
||||
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
|
||||
*retlen = 0;
|
||||
|
||||
for (i = 0; i < concat->num_subdev; i++) {
|
||||
@ -124,11 +121,7 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
else
|
||||
size = len;
|
||||
|
||||
if (!(subdev->flags & MTD_WRITEABLE))
|
||||
err = -EROFS;
|
||||
else
|
||||
err = subdev->write(subdev, to, size, &retsize, buf);
|
||||
|
||||
err = mtd_write(subdev, to, size, &retsize, buf);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -165,16 +158,16 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
|
||||
if (from + devops.len > subdev->size)
|
||||
devops.len = subdev->size - from;
|
||||
|
||||
err = subdev->read_oob(subdev, from, &devops);
|
||||
err = mtd_read_oob(subdev, from, &devops);
|
||||
ops->retlen += devops.retlen;
|
||||
ops->oobretlen += devops.oobretlen;
|
||||
|
||||
/* Save information about bitflips! */
|
||||
if (unlikely(err)) {
|
||||
if (err == -EBADMSG) {
|
||||
if (mtd_is_eccerr(err)) {
|
||||
mtd->ecc_stats.failed++;
|
||||
ret = err;
|
||||
} else if (err == -EUCLEAN) {
|
||||
} else if (mtd_is_bitflip(err)) {
|
||||
mtd->ecc_stats.corrected++;
|
||||
/* Do not overwrite -EBADMSG !! */
|
||||
if (!ret)
|
||||
@ -225,7 +218,7 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
|
||||
if (to + devops.len > subdev->size)
|
||||
devops.len = subdev->size - to;
|
||||
|
||||
err = subdev->write_oob(subdev, to, &devops);
|
||||
err = mtd_write_oob(subdev, to, &devops);
|
||||
ops->retlen += devops.retlen;
|
||||
if (err)
|
||||
return err;
|
||||
@ -271,7 +264,7 @@ static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
|
||||
* FIXME: Allow INTERRUPTIBLE. Which means
|
||||
* not having the wait_queue head on the stack.
|
||||
*/
|
||||
err = mtd->erase(mtd, erase);
|
||||
err = mtd_erase(mtd, erase);
|
||||
if (!err) {
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
add_wait_queue(&waitq, &wait);
|
||||
@ -294,15 +287,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
uint64_t length, offset = 0;
|
||||
struct erase_info *erase;
|
||||
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
|
||||
if (instr->addr > concat->mtd.size)
|
||||
return -EINVAL;
|
||||
|
||||
if (instr->len + instr->addr > concat->mtd.size)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Check for proper erase block alignment of the to-be-erased area.
|
||||
* It is easier to do this based on the super device's erase
|
||||
@ -350,8 +334,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
|
||||
|
||||
/* make a local copy of instr to avoid modifying the caller's struct */
|
||||
erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
|
||||
|
||||
@ -390,10 +372,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
else
|
||||
erase->len = length;
|
||||
|
||||
if (!(subdev->flags & MTD_WRITEABLE)) {
|
||||
err = -EROFS;
|
||||
break;
|
||||
}
|
||||
length -= erase->len;
|
||||
if ((err = concat_dev_erase(subdev, erase))) {
|
||||
/* sanity check: should never happen since
|
||||
@ -429,9 +407,6 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
struct mtd_concat *concat = CONCAT(mtd);
|
||||
int i, err = -EINVAL;
|
||||
|
||||
if ((len + ofs) > mtd->size)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < concat->num_subdev; i++) {
|
||||
struct mtd_info *subdev = concat->subdev[i];
|
||||
uint64_t size;
|
||||
@ -446,7 +421,7 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
else
|
||||
size = len;
|
||||
|
||||
err = subdev->lock(subdev, ofs, size);
|
||||
err = mtd_lock(subdev, ofs, size);
|
||||
|
||||
if (err)
|
||||
break;
|
||||
@ -467,9 +442,6 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
struct mtd_concat *concat = CONCAT(mtd);
|
||||
int i, err = 0;
|
||||
|
||||
if ((len + ofs) > mtd->size)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < concat->num_subdev; i++) {
|
||||
struct mtd_info *subdev = concat->subdev[i];
|
||||
uint64_t size;
|
||||
@ -484,7 +456,7 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
else
|
||||
size = len;
|
||||
|
||||
err = subdev->unlock(subdev, ofs, size);
|
||||
err = mtd_unlock(subdev, ofs, size);
|
||||
|
||||
if (err)
|
||||
break;
|
||||
@ -507,7 +479,7 @@ static void concat_sync(struct mtd_info *mtd)
|
||||
|
||||
for (i = 0; i < concat->num_subdev; i++) {
|
||||
struct mtd_info *subdev = concat->subdev[i];
|
||||
subdev->sync(subdev);
|
||||
mtd_sync(subdev);
|
||||
}
|
||||
}
|
||||
|
||||
@ -516,12 +488,9 @@ static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||
struct mtd_concat *concat = CONCAT(mtd);
|
||||
int i, res = 0;
|
||||
|
||||
if (!concat->subdev[0]->block_isbad)
|
||||
if (!mtd_can_have_bb(concat->subdev[0]))
|
||||
return res;
|
||||
|
||||
if (ofs > mtd->size)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < concat->num_subdev; i++) {
|
||||
struct mtd_info *subdev = concat->subdev[i];
|
||||
|
||||
@ -530,7 +499,7 @@ static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||
continue;
|
||||
}
|
||||
|
||||
res = subdev->block_isbad(subdev, ofs);
|
||||
res = mtd_block_isbad(subdev, ofs);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -542,12 +511,9 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
struct mtd_concat *concat = CONCAT(mtd);
|
||||
int i, err = -EINVAL;
|
||||
|
||||
if (!concat->subdev[0]->block_markbad)
|
||||
if (!mtd_can_have_bb(concat->subdev[0]))
|
||||
return 0;
|
||||
|
||||
if (ofs > mtd->size)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < concat->num_subdev; i++) {
|
||||
struct mtd_info *subdev = concat->subdev[i];
|
||||
|
||||
@ -556,7 +522,7 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
continue;
|
||||
}
|
||||
|
||||
err = subdev->block_markbad(subdev, ofs);
|
||||
err = mtd_block_markbad(subdev, ofs);
|
||||
if (!err)
|
||||
mtd->ecc_stats.badblocks++;
|
||||
break;
|
||||
@ -609,14 +575,14 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
||||
concat->mtd.subpage_sft = subdev[0]->subpage_sft;
|
||||
concat->mtd.oobsize = subdev[0]->oobsize;
|
||||
concat->mtd.oobavail = subdev[0]->oobavail;
|
||||
if (subdev[0]->read_oob)
|
||||
concat->mtd.read_oob = concat_read_oob;
|
||||
if (subdev[0]->write_oob)
|
||||
concat->mtd.write_oob = concat_write_oob;
|
||||
if (subdev[0]->block_isbad)
|
||||
concat->mtd.block_isbad = concat_block_isbad;
|
||||
if (subdev[0]->block_markbad)
|
||||
concat->mtd.block_markbad = concat_block_markbad;
|
||||
if (subdev[0]->_read_oob)
|
||||
concat->mtd._read_oob = concat_read_oob;
|
||||
if (subdev[0]->_write_oob)
|
||||
concat->mtd._write_oob = concat_write_oob;
|
||||
if (subdev[0]->_block_isbad)
|
||||
concat->mtd._block_isbad = concat_block_isbad;
|
||||
if (subdev[0]->_block_markbad)
|
||||
concat->mtd._block_markbad = concat_block_markbad;
|
||||
|
||||
concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
|
||||
|
||||
@ -653,8 +619,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
||||
if (concat->mtd.writesize != subdev[i]->writesize ||
|
||||
concat->mtd.subpage_sft != subdev[i]->subpage_sft ||
|
||||
concat->mtd.oobsize != subdev[i]->oobsize ||
|
||||
!concat->mtd.read_oob != !subdev[i]->read_oob ||
|
||||
!concat->mtd.write_oob != !subdev[i]->write_oob) {
|
||||
!concat->mtd._read_oob != !subdev[i]->_read_oob ||
|
||||
!concat->mtd._write_oob != !subdev[i]->_write_oob) {
|
||||
kfree(concat);
|
||||
printk("Incompatible OOB or ECC data on \"%s\"\n",
|
||||
subdev[i]->name);
|
||||
@ -669,12 +635,12 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
||||
concat->num_subdev = num_devs;
|
||||
concat->mtd.name = name;
|
||||
|
||||
concat->mtd.erase = concat_erase;
|
||||
concat->mtd.read = concat_read;
|
||||
concat->mtd.write = concat_write;
|
||||
concat->mtd.sync = concat_sync;
|
||||
concat->mtd.lock = concat_lock;
|
||||
concat->mtd.unlock = concat_unlock;
|
||||
concat->mtd._erase = concat_erase;
|
||||
concat->mtd._read = concat_read;
|
||||
concat->mtd._write = concat_write;
|
||||
concat->mtd._sync = concat_sync;
|
||||
concat->mtd._lock = concat_lock;
|
||||
concat->mtd._unlock = concat_unlock;
|
||||
|
||||
/*
|
||||
* Combine the erase block size info of the subdevices:
|
||||
|
@ -25,6 +25,11 @@ int add_mtd_device(struct mtd_info *mtd)
|
||||
mtd->index = i;
|
||||
mtd->usecount = 0;
|
||||
|
||||
/* default value if not set by driver */
|
||||
if (mtd->bitflip_threshold == 0)
|
||||
mtd->bitflip_threshold = mtd->ecc_strength;
|
||||
|
||||
|
||||
/* No need to get a refcount on the module containing
|
||||
the notifier, since we hold the mtd_table_mutex */
|
||||
|
||||
@ -186,3 +191,189 @@ void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
|
||||
}
|
||||
}
|
||||
#endif /* defined(CONFIG_CMD_MTDPARTS_SPREAD) */
|
||||
|
||||
/*
|
||||
* Erase is an asynchronous operation. Device drivers are supposed
|
||||
* to call instr->callback() whenever the operation completes, even
|
||||
* if it completes with a failure.
|
||||
* Callers are supposed to pass a callback function and wait for it
|
||||
* to be called before writing to the block.
|
||||
*/
|
||||
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
{
|
||||
if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr)
|
||||
return -EINVAL;
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
|
||||
if (!instr->len) {
|
||||
instr->state = MTD_ERASE_DONE;
|
||||
mtd_erase_callback(instr);
|
||||
return 0;
|
||||
}
|
||||
return mtd->_erase(mtd, instr);
|
||||
}
|
||||
|
||||
int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
||||
u_char *buf)
|
||||
{
|
||||
if (from < 0 || from > mtd->size || len > mtd->size - from)
|
||||
return -EINVAL;
|
||||
if (!len)
|
||||
return 0;
|
||||
return mtd->_read(mtd, from, len, retlen, buf);
|
||||
}
|
||||
|
||||
int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||
const u_char *buf)
|
||||
{
|
||||
*retlen = 0;
|
||||
if (to < 0 || to > mtd->size || len > mtd->size - to)
|
||||
return -EINVAL;
|
||||
if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
if (!len)
|
||||
return 0;
|
||||
return mtd->_write(mtd, to, len, retlen, buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* In blackbox flight recorder like scenarios we want to make successful writes
|
||||
* in interrupt context. panic_write() is only intended to be called when its
|
||||
* known the kernel is about to panic and we need the write to succeed. Since
|
||||
* the kernel is not going to be running for much longer, this function can
|
||||
* break locks and delay to ensure the write succeeds (but not sleep).
|
||||
*/
|
||||
int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||
const u_char *buf)
|
||||
{
|
||||
*retlen = 0;
|
||||
if (!mtd->_panic_write)
|
||||
return -EOPNOTSUPP;
|
||||
if (to < 0 || to > mtd->size || len > mtd->size - to)
|
||||
return -EINVAL;
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
if (!len)
|
||||
return 0;
|
||||
return mtd->_panic_write(mtd, to, len, retlen, buf);
|
||||
}
|
||||
|
||||
int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
|
||||
{
|
||||
ops->retlen = ops->oobretlen = 0;
|
||||
if (!mtd->_read_oob)
|
||||
return -EOPNOTSUPP;
|
||||
return mtd->_read_oob(mtd, from, ops);
|
||||
}
|
||||
|
||||
/*
|
||||
* Method to access the protection register area, present in some flash
|
||||
* devices. The user data is one time programmable but the factory data is read
|
||||
* only.
|
||||
*/
|
||||
int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
||||
size_t len)
|
||||
{
|
||||
if (!mtd->_get_fact_prot_info)
|
||||
return -EOPNOTSUPP;
|
||||
if (!len)
|
||||
return 0;
|
||||
return mtd->_get_fact_prot_info(mtd, buf, len);
|
||||
}
|
||||
|
||||
int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf)
|
||||
{
|
||||
*retlen = 0;
|
||||
if (!mtd->_read_fact_prot_reg)
|
||||
return -EOPNOTSUPP;
|
||||
if (!len)
|
||||
return 0;
|
||||
return mtd->_read_fact_prot_reg(mtd, from, len, retlen, buf);
|
||||
}
|
||||
|
||||
int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
||||
size_t len)
|
||||
{
|
||||
if (!mtd->_get_user_prot_info)
|
||||
return -EOPNOTSUPP;
|
||||
if (!len)
|
||||
return 0;
|
||||
return mtd->_get_user_prot_info(mtd, buf, len);
|
||||
}
|
||||
|
||||
int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf)
|
||||
{
|
||||
*retlen = 0;
|
||||
if (!mtd->_read_user_prot_reg)
|
||||
return -EOPNOTSUPP;
|
||||
if (!len)
|
||||
return 0;
|
||||
return mtd->_read_user_prot_reg(mtd, from, len, retlen, buf);
|
||||
}
|
||||
|
||||
int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, u_char *buf)
|
||||
{
|
||||
*retlen = 0;
|
||||
if (!mtd->_write_user_prot_reg)
|
||||
return -EOPNOTSUPP;
|
||||
if (!len)
|
||||
return 0;
|
||||
return mtd->_write_user_prot_reg(mtd, to, len, retlen, buf);
|
||||
}
|
||||
|
||||
int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len)
|
||||
{
|
||||
if (!mtd->_lock_user_prot_reg)
|
||||
return -EOPNOTSUPP;
|
||||
if (!len)
|
||||
return 0;
|
||||
return mtd->_lock_user_prot_reg(mtd, from, len);
|
||||
}
|
||||
|
||||
/* Chip-supported device locking */
|
||||
int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
{
|
||||
if (!mtd->_lock)
|
||||
return -EOPNOTSUPP;
|
||||
if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
|
||||
return -EINVAL;
|
||||
if (!len)
|
||||
return 0;
|
||||
return mtd->_lock(mtd, ofs, len);
|
||||
}
|
||||
|
||||
int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
{
|
||||
if (!mtd->_unlock)
|
||||
return -EOPNOTSUPP;
|
||||
if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
|
||||
return -EINVAL;
|
||||
if (!len)
|
||||
return 0;
|
||||
return mtd->_unlock(mtd, ofs, len);
|
||||
}
|
||||
|
||||
int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
if (!mtd->_block_isbad)
|
||||
return 0;
|
||||
if (ofs < 0 || ofs > mtd->size)
|
||||
return -EINVAL;
|
||||
return mtd->_block_isbad(mtd, ofs);
|
||||
}
|
||||
|
||||
int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
if (!mtd->_block_markbad)
|
||||
return -EOPNOTSUPP;
|
||||
if (ofs < 0 || ofs > mtd->size)
|
||||
return -EINVAL;
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
return mtd->_block_markbad(mtd, ofs);
|
||||
}
|
||||
|
||||
|
@ -52,17 +52,11 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
int res;
|
||||
|
||||
stats = part->master->ecc_stats;
|
||||
|
||||
if (from >= mtd->size)
|
||||
len = 0;
|
||||
else if (from + len > mtd->size)
|
||||
len = mtd->size - from;
|
||||
res = part->master->read(part->master, from + part->offset,
|
||||
len, retlen, buf);
|
||||
res = mtd_read(part->master, from + part->offset, len, retlen, buf);
|
||||
if (unlikely(res)) {
|
||||
if (res == -EUCLEAN)
|
||||
if (mtd_is_bitflip(res))
|
||||
mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
|
||||
if (res == -EBADMSG)
|
||||
if (mtd_is_eccerr(res))
|
||||
mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;
|
||||
}
|
||||
return res;
|
||||
@ -78,12 +72,12 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
|
||||
return -EINVAL;
|
||||
if (ops->datbuf && from + ops->len > mtd->size)
|
||||
return -EINVAL;
|
||||
res = part->master->read_oob(part->master, from + part->offset, ops);
|
||||
res = mtd_read_oob(part->master, from + part->offset, ops);
|
||||
|
||||
if (unlikely(res)) {
|
||||
if (res == -EUCLEAN)
|
||||
if (mtd_is_bitflip(res))
|
||||
mtd->ecc_stats.corrected++;
|
||||
if (res == -EBADMSG)
|
||||
if (mtd_is_eccerr(res))
|
||||
mtd->ecc_stats.failed++;
|
||||
}
|
||||
return res;
|
||||
@ -93,58 +87,35 @@ static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
||||
size_t len, size_t *retlen, u_char *buf)
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
return part->master->read_user_prot_reg(part->master, from,
|
||||
len, retlen, buf);
|
||||
return mtd_read_user_prot_reg(part->master, from, len, retlen, buf);
|
||||
}
|
||||
|
||||
static int part_get_user_prot_info(struct mtd_info *mtd,
|
||||
struct otp_info *buf, size_t len)
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
return part->master->get_user_prot_info(part->master, buf, len);
|
||||
return mtd_get_user_prot_info(part->master, buf, len);
|
||||
}
|
||||
|
||||
static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
|
||||
size_t len, size_t *retlen, u_char *buf)
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
return part->master->read_fact_prot_reg(part->master, from,
|
||||
len, retlen, buf);
|
||||
return mtd_read_fact_prot_reg(part->master, from, len, retlen, buf);
|
||||
}
|
||||
|
||||
static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
return part->master->get_fact_prot_info(part->master, buf, len);
|
||||
return mtd_get_fact_prot_info(part->master, buf, len);
|
||||
}
|
||||
|
||||
static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf)
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
if (to >= mtd->size)
|
||||
len = 0;
|
||||
else if (to + len > mtd->size)
|
||||
len = mtd->size - to;
|
||||
return part->master->write(part->master, to + part->offset,
|
||||
len, retlen, buf);
|
||||
}
|
||||
|
||||
static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf)
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
if (to >= mtd->size)
|
||||
len = 0;
|
||||
else if (to + len > mtd->size)
|
||||
len = mtd->size - to;
|
||||
return part->master->panic_write(part->master, to + part->offset,
|
||||
len, retlen, buf);
|
||||
return mtd_write(part->master, to + part->offset, len, retlen, buf);
|
||||
}
|
||||
|
||||
static int part_write_oob(struct mtd_info *mtd, loff_t to,
|
||||
@ -152,41 +123,34 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to,
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
|
||||
if (to >= mtd->size)
|
||||
return -EINVAL;
|
||||
if (ops->datbuf && to + ops->len > mtd->size)
|
||||
return -EINVAL;
|
||||
return part->master->write_oob(part->master, to + part->offset, ops);
|
||||
return mtd_write_oob(part->master, to + part->offset, ops);
|
||||
}
|
||||
|
||||
static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
||||
size_t len, size_t *retlen, u_char *buf)
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
return part->master->write_user_prot_reg(part->master, from,
|
||||
len, retlen, buf);
|
||||
return mtd_write_user_prot_reg(part->master, from, len, retlen, buf);
|
||||
}
|
||||
|
||||
static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
||||
size_t len)
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
return part->master->lock_user_prot_reg(part->master, from, len);
|
||||
return mtd_lock_user_prot_reg(part->master, from, len);
|
||||
}
|
||||
|
||||
static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
int ret;
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
if (instr->addr >= mtd->size)
|
||||
return -EINVAL;
|
||||
|
||||
instr->addr += part->offset;
|
||||
ret = part->master->erase(part->master, instr);
|
||||
ret = mtd_erase(part->master, instr);
|
||||
if (ret) {
|
||||
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
|
||||
instr->fail_addr -= part->offset;
|
||||
@ -197,7 +161,7 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
|
||||
void mtd_erase_callback(struct erase_info *instr)
|
||||
{
|
||||
if (instr->mtd->erase == part_erase) {
|
||||
if (instr->mtd->_erase == part_erase) {
|
||||
struct mtd_part *part = PART(instr->mtd);
|
||||
|
||||
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
|
||||
@ -211,32 +175,26 @@ void mtd_erase_callback(struct erase_info *instr)
|
||||
static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
if ((len + ofs) > mtd->size)
|
||||
return -EINVAL;
|
||||
return part->master->lock(part->master, ofs + part->offset, len);
|
||||
return mtd_lock(part->master, ofs + part->offset, len);
|
||||
}
|
||||
|
||||
static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
if ((len + ofs) > mtd->size)
|
||||
return -EINVAL;
|
||||
return part->master->unlock(part->master, ofs + part->offset, len);
|
||||
return mtd_unlock(part->master, ofs + part->offset, len);
|
||||
}
|
||||
|
||||
static void part_sync(struct mtd_info *mtd)
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
part->master->sync(part->master);
|
||||
mtd_sync(part->master);
|
||||
}
|
||||
|
||||
static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
if (ofs >= mtd->size)
|
||||
return -EINVAL;
|
||||
ofs += part->offset;
|
||||
return part->master->block_isbad(part->master, ofs);
|
||||
return mtd_block_isbad(part->master, ofs);
|
||||
}
|
||||
|
||||
static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
@ -244,12 +202,8 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
struct mtd_part *part = PART(mtd);
|
||||
int res;
|
||||
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
if (ofs >= mtd->size)
|
||||
return -EINVAL;
|
||||
ofs += part->offset;
|
||||
res = part->master->block_markbad(part->master, ofs);
|
||||
res = mtd_block_markbad(part->master, ofs);
|
||||
if (!res)
|
||||
mtd->ecc_stats.badblocks++;
|
||||
return res;
|
||||
@ -303,39 +257,36 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
|
||||
slave->mtd.name = part->name;
|
||||
slave->mtd.owner = master->owner;
|
||||
|
||||
slave->mtd.read = part_read;
|
||||
slave->mtd.write = part_write;
|
||||
slave->mtd._read = part_read;
|
||||
slave->mtd._write = part_write;
|
||||
|
||||
if (master->panic_write)
|
||||
slave->mtd.panic_write = part_panic_write;
|
||||
|
||||
if (master->read_oob)
|
||||
slave->mtd.read_oob = part_read_oob;
|
||||
if (master->write_oob)
|
||||
slave->mtd.write_oob = part_write_oob;
|
||||
if (master->read_user_prot_reg)
|
||||
slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
|
||||
if (master->read_fact_prot_reg)
|
||||
slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
|
||||
if (master->write_user_prot_reg)
|
||||
slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
|
||||
if (master->lock_user_prot_reg)
|
||||
slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
|
||||
if (master->get_user_prot_info)
|
||||
slave->mtd.get_user_prot_info = part_get_user_prot_info;
|
||||
if (master->get_fact_prot_info)
|
||||
slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
|
||||
if (master->sync)
|
||||
slave->mtd.sync = part_sync;
|
||||
if (master->lock)
|
||||
slave->mtd.lock = part_lock;
|
||||
if (master->unlock)
|
||||
slave->mtd.unlock = part_unlock;
|
||||
if (master->block_isbad)
|
||||
slave->mtd.block_isbad = part_block_isbad;
|
||||
if (master->block_markbad)
|
||||
slave->mtd.block_markbad = part_block_markbad;
|
||||
slave->mtd.erase = part_erase;
|
||||
if (master->_read_oob)
|
||||
slave->mtd._read_oob = part_read_oob;
|
||||
if (master->_write_oob)
|
||||
slave->mtd._write_oob = part_write_oob;
|
||||
if (master->_read_user_prot_reg)
|
||||
slave->mtd._read_user_prot_reg = part_read_user_prot_reg;
|
||||
if (master->_read_fact_prot_reg)
|
||||
slave->mtd._read_fact_prot_reg = part_read_fact_prot_reg;
|
||||
if (master->_write_user_prot_reg)
|
||||
slave->mtd._write_user_prot_reg = part_write_user_prot_reg;
|
||||
if (master->_lock_user_prot_reg)
|
||||
slave->mtd._lock_user_prot_reg = part_lock_user_prot_reg;
|
||||
if (master->_get_user_prot_info)
|
||||
slave->mtd._get_user_prot_info = part_get_user_prot_info;
|
||||
if (master->_get_fact_prot_info)
|
||||
slave->mtd._get_fact_prot_info = part_get_fact_prot_info;
|
||||
if (master->_sync)
|
||||
slave->mtd._sync = part_sync;
|
||||
if (master->_lock)
|
||||
slave->mtd._lock = part_lock;
|
||||
if (master->_unlock)
|
||||
slave->mtd._unlock = part_unlock;
|
||||
if (master->_block_isbad)
|
||||
slave->mtd._block_isbad = part_block_isbad;
|
||||
if (master->_block_markbad)
|
||||
slave->mtd._block_markbad = part_block_markbad;
|
||||
slave->mtd._erase = part_erase;
|
||||
slave->master = master;
|
||||
slave->offset = part->offset;
|
||||
slave->index = partno;
|
||||
@ -416,12 +367,11 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
|
||||
}
|
||||
|
||||
slave->mtd.ecclayout = master->ecclayout;
|
||||
if (master->block_isbad) {
|
||||
if (master->_block_isbad) {
|
||||
uint64_t offs = 0;
|
||||
|
||||
while (offs < slave->mtd.size) {
|
||||
if (master->block_isbad(master,
|
||||
offs + slave->offset))
|
||||
if (mtd_block_isbad(master, offs + slave->offset))
|
||||
slave->mtd.ecc_stats.badblocks++;
|
||||
offs += slave->mtd.erasesize;
|
||||
}
|
||||
|
@ -489,7 +489,7 @@ normal_check:
|
||||
}
|
||||
|
||||
static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, uint8_t *buf, int page)
|
||||
struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
|
||||
{
|
||||
struct atmel_nand_host *host = chip->priv;
|
||||
int eccsize = chip->ecc.size;
|
||||
@ -529,8 +529,9 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atmel_nand_pmecc_write_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf)
|
||||
static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required)
|
||||
{
|
||||
struct atmel_nand_host *host = chip->priv;
|
||||
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
||||
@ -557,7 +558,7 @@ static void atmel_nand_pmecc_write_page(struct mtd_info *mtd,
|
||||
|
||||
if (!timeout) {
|
||||
printk(KERN_ERR "atmel_nand : Timeout to read PMECC status, fail to write PMECC in oob\n");
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < host->pmecc_sector_number; i++) {
|
||||
@ -570,6 +571,8 @@ static void atmel_nand_pmecc_write_page(struct mtd_info *mtd,
|
||||
}
|
||||
}
|
||||
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atmel_pmecc_core_init(struct mtd_info *mtd)
|
||||
@ -706,6 +709,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
|
||||
|
||||
nand->ecc.read_page = atmel_nand_pmecc_read_page;
|
||||
nand->ecc.write_page = atmel_nand_pmecc_write_page;
|
||||
nand->ecc.strength = cap;
|
||||
|
||||
atmel_pmecc_core_init(mtd);
|
||||
|
||||
@ -775,9 +779,10 @@ static int atmel_nand_calculate(struct mtd_info *mtd,
|
||||
* mtd: mtd info structure
|
||||
* chip: nand chip info structure
|
||||
* buf: buffer to store read data
|
||||
* oob_required: caller expects OOB data read to chip->oob_poi
|
||||
*/
|
||||
static int atmel_nand_read_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, uint8_t *buf, int page)
|
||||
static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
{
|
||||
int eccsize = chip->ecc.size;
|
||||
int eccbytes = chip->ecc.bytes;
|
||||
|
@ -374,9 +374,11 @@ int board_nand_init(struct nand_chip *chip)
|
||||
if (!NAND_IS_512()) {
|
||||
chip->ecc.bytes = 3;
|
||||
chip->ecc.size = 256;
|
||||
chip->ecc.strength = 1;
|
||||
} else {
|
||||
chip->ecc.bytes = 6;
|
||||
chip->ecc.size = 512;
|
||||
chip->ecc.strength = 2;
|
||||
}
|
||||
chip->ecc.mode = NAND_ECC_HW;
|
||||
chip->ecc.calculate = bfin_nfc_calculate_ecc;
|
||||
|
@ -607,12 +607,13 @@ void davinci_nand_init(struct nand_chip *nand)
|
||||
{
|
||||
nand->chip_delay = 0;
|
||||
#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
|
||||
nand->options |= NAND_USE_FLASH_BBT;
|
||||
nand->bbt_options |= NAND_BBT_USE_FLASH;
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_NAND_HW_ECC
|
||||
nand->ecc.mode = NAND_ECC_HW;
|
||||
nand->ecc.size = 512;
|
||||
nand->ecc.bytes = 3;
|
||||
nand->ecc.strength = 1;
|
||||
nand->ecc.calculate = nand_davinci_calculate_ecc;
|
||||
nand->ecc.correct = nand_davinci_correct_data;
|
||||
nand->ecc.hwctl = nand_davinci_enable_hwecc;
|
||||
@ -623,6 +624,7 @@ void davinci_nand_init(struct nand_chip *nand)
|
||||
nand->ecc.mode = NAND_ECC_HW_OOB_FIRST;
|
||||
nand->ecc.size = 512;
|
||||
nand->ecc.bytes = 10;
|
||||
nand->ecc.strength = 4;
|
||||
nand->ecc.calculate = nand_davinci_4bit_calculate_ecc;
|
||||
nand->ecc.correct = nand_davinci_4bit_correct_data;
|
||||
nand->ecc.hwctl = nand_davinci_4bit_enable_hwecc;
|
||||
|
@ -134,7 +134,7 @@ static struct rs_control *rs_decoder;
|
||||
|
||||
/*
|
||||
* The HW decoder in the DoC ASIC's provides us a error syndrome,
|
||||
* which we must convert to a standard syndrom usable by the generic
|
||||
* which we must convert to a standard syndrome usable by the generic
|
||||
* Reed-Solomon library code.
|
||||
*
|
||||
* Fabrice Bellard figured this out in the old docecc code. I added
|
||||
@ -154,7 +154,7 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
|
||||
ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2);
|
||||
parity = ecc[1];
|
||||
|
||||
/* Initialize the syndrom buffer */
|
||||
/* Initialize the syndrome buffer */
|
||||
for (i = 0; i < NROOTS; i++)
|
||||
s[i] = ds[0];
|
||||
/*
|
||||
@ -1033,7 +1033,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||
WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
|
||||
else
|
||||
WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
|
||||
if (no_ecc_failures && (ret == -EBADMSG)) {
|
||||
if (no_ecc_failures && mtd_is_eccerr(ret)) {
|
||||
printk(KERN_ERR "suppressing ECC failure\n");
|
||||
ret = 0;
|
||||
}
|
||||
@ -1073,7 +1073,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch
|
||||
size_t retlen;
|
||||
|
||||
for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
|
||||
ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf);
|
||||
ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
|
||||
if (retlen != mtd->writesize)
|
||||
continue;
|
||||
if (ret) {
|
||||
@ -1098,7 +1098,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch
|
||||
/* Only one mediaheader was found. We want buf to contain a
|
||||
mediaheader on return, so we'll have to re-read the one we found. */
|
||||
offs = doc->mh0_page << this->page_shift;
|
||||
ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf);
|
||||
ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
|
||||
if (retlen != mtd->writesize) {
|
||||
/* Insanity. Give up. */
|
||||
printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n");
|
||||
@ -1658,7 +1658,8 @@ static int __init doc_probe(unsigned long physadr)
|
||||
nand->ecc.mode = NAND_ECC_HW_SYNDROME;
|
||||
nand->ecc.size = 512;
|
||||
nand->ecc.bytes = 6;
|
||||
nand->options = NAND_USE_FLASH_BBT;
|
||||
nand->ecc.strength = 2;
|
||||
nand->bbt_options = NAND_BBT_USE_FLASH;
|
||||
|
||||
doc->physadr = physadr;
|
||||
doc->virtadr = virtadr;
|
||||
|
@ -640,9 +640,8 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
return fsl_elbc_read_byte(mtd);
|
||||
}
|
||||
|
||||
static int fsl_elbc_read_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
uint8_t *buf, int page)
|
||||
static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
{
|
||||
fsl_elbc_read_buf(mtd, buf, mtd->writesize);
|
||||
fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
@ -656,12 +655,13 @@ static int fsl_elbc_read_page(struct mtd_info *mtd,
|
||||
/* ECC will be calculated automatically, and errors will be detected in
|
||||
* waitfunc.
|
||||
*/
|
||||
static void fsl_elbc_write_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
const uint8_t *buf)
|
||||
static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required)
|
||||
{
|
||||
fsl_elbc_write_buf(mtd, buf, mtd->writesize);
|
||||
fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct fsl_elbc_ctrl *elbc_ctrl;
|
||||
@ -747,8 +747,8 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr)
|
||||
nand->bbt_md = &bbt_mirror_descr;
|
||||
|
||||
/* set up nand options */
|
||||
nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR |
|
||||
NAND_USE_FLASH_BBT | NAND_NO_SUBPAGE_WRITE;
|
||||
nand->options = NAND_NO_SUBPAGE_WRITE;
|
||||
nand->bbt_options = NAND_BBT_USE_FLASH;
|
||||
|
||||
nand->controller = &elbc_ctrl->controller;
|
||||
nand->priv = priv;
|
||||
@ -756,20 +756,8 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr)
|
||||
nand->ecc.read_page = fsl_elbc_read_page;
|
||||
nand->ecc.write_page = fsl_elbc_write_page;
|
||||
|
||||
#ifdef CONFIG_FSL_ELBC_FMR
|
||||
priv->fmr = CONFIG_FSL_ELBC_FMR;
|
||||
#else
|
||||
priv->fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT);
|
||||
|
||||
/*
|
||||
* Hardware expects small page has ECCM0, large page has ECCM1
|
||||
* when booting from NAND. Board config can override if not
|
||||
* booting from NAND.
|
||||
*/
|
||||
if (or & OR_FCM_PGS)
|
||||
priv->fmr |= FMR_ECCM;
|
||||
#endif
|
||||
|
||||
/* If CS Base Register selects full hardware ECC then use it */
|
||||
if ((br & BR_DECC) == BR_DECC_CHK_GEN) {
|
||||
nand->ecc.mode = NAND_ECC_HW;
|
||||
@ -781,16 +769,32 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr)
|
||||
nand->ecc.size = 512;
|
||||
nand->ecc.bytes = 3;
|
||||
nand->ecc.steps = 1;
|
||||
nand->ecc.strength = 1;
|
||||
} else {
|
||||
/* otherwise fall back to default software ECC */
|
||||
nand->ecc.mode = NAND_ECC_SOFT;
|
||||
}
|
||||
|
||||
ret = nand_scan_ident(mtd, 1, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Large-page-specific setup */
|
||||
if (or & OR_FCM_PGS) {
|
||||
if (mtd->writesize == 2048) {
|
||||
setbits_be32(&elbc_ctrl->regs->bank[priv->bank].or,
|
||||
OR_FCM_PGS);
|
||||
in_be32(&elbc_ctrl->regs->bank[priv->bank].or);
|
||||
|
||||
priv->page_size = 1;
|
||||
nand->badblock_pattern = &largepage_memorybased;
|
||||
|
||||
/*
|
||||
* Hardware expects small page has ECCM0, large page has
|
||||
* ECCM1 when booting from NAND, and we follow that even
|
||||
* when not booting from NAND.
|
||||
*/
|
||||
priv->fmr |= FMR_ECCM;
|
||||
|
||||
/* adjust ecc setup if needed */
|
||||
if ((br & BR_DECC) == BR_DECC_CHK_GEN) {
|
||||
nand->ecc.steps = 4;
|
||||
@ -798,12 +802,14 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr)
|
||||
&fsl_elbc_oob_lp_eccm1 :
|
||||
&fsl_elbc_oob_lp_eccm0;
|
||||
}
|
||||
} else if (mtd->writesize == 512) {
|
||||
clrbits_be32(&elbc_ctrl->regs->bank[priv->bank].or,
|
||||
OR_FCM_PGS);
|
||||
in_be32(&elbc_ctrl->regs->bank[priv->bank].or);
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = nand_scan_ident(mtd, 1, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nand_scan_tail(mtd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <nand.h>
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
@ -41,7 +42,6 @@ struct fsl_ifc_ctrl;
|
||||
|
||||
/* mtd information per set */
|
||||
struct fsl_ifc_mtd {
|
||||
struct mtd_info mtd;
|
||||
struct nand_chip chip;
|
||||
struct fsl_ifc_ctrl *ctrl;
|
||||
|
||||
@ -686,9 +686,8 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
return nand_fsr;
|
||||
}
|
||||
|
||||
static int fsl_ifc_read_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
uint8_t *buf, int page)
|
||||
static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
{
|
||||
struct fsl_ifc_mtd *priv = chip->priv;
|
||||
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
||||
@ -705,12 +704,13 @@ static int fsl_ifc_read_page(struct mtd_info *mtd,
|
||||
/* ECC will be calculated automatically, and errors will be detected in
|
||||
* waitfunc.
|
||||
*/
|
||||
static void fsl_ifc_write_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
const uint8_t *buf)
|
||||
static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required)
|
||||
{
|
||||
fsl_ifc_write_buf(mtd, buf, mtd->writesize);
|
||||
fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fsl_ifc_ctrl_init(void)
|
||||
@ -794,11 +794,14 @@ static void fsl_ifc_sram_init(void)
|
||||
out_be32(&ifc_ctrl->regs->csor_cs[cs].csor_ext, csor_ext);
|
||||
}
|
||||
|
||||
int board_nand_init(struct nand_chip *nand)
|
||||
static int fsl_ifc_chip_init(int devnum, u8 *addr)
|
||||
{
|
||||
struct mtd_info *mtd = &nand_info[devnum];
|
||||
struct nand_chip *nand;
|
||||
struct fsl_ifc_mtd *priv;
|
||||
struct nand_ecclayout *layout;
|
||||
uint32_t cspr = 0, csor = 0, ver = 0;
|
||||
int ret;
|
||||
|
||||
if (!ifc_ctrl) {
|
||||
fsl_ifc_ctrl_init();
|
||||
@ -811,18 +814,18 @@ int board_nand_init(struct nand_chip *nand)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->ctrl = ifc_ctrl;
|
||||
priv->vbase = nand->IO_ADDR_R;
|
||||
priv->vbase = addr;
|
||||
|
||||
/* Find which chip select it is connected to.
|
||||
*/
|
||||
for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) {
|
||||
phys_addr_t base_addr = virt_to_phys(nand->IO_ADDR_R);
|
||||
phys_addr_t phys_addr = virt_to_phys(addr);
|
||||
|
||||
cspr = in_be32(&ifc_ctrl->regs->cspr_cs[priv->bank].cspr);
|
||||
csor = in_be32(&ifc_ctrl->regs->csor_cs[priv->bank].csor);
|
||||
|
||||
if ((cspr & CSPR_V) && (cspr & CSPR_MSEL) == CSPR_MSEL_NAND &&
|
||||
(cspr & CSPR_BA) == CSPR_PHYS_ADDR(base_addr)) {
|
||||
(cspr & CSPR_BA) == CSPR_PHYS_ADDR(phys_addr)) {
|
||||
ifc_ctrl->cs_nand = priv->bank << IFC_NAND_CSEL_SHIFT;
|
||||
break;
|
||||
}
|
||||
@ -835,6 +838,9 @@ int board_nand_init(struct nand_chip *nand)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
nand = &priv->chip;
|
||||
mtd->priv = nand;
|
||||
|
||||
ifc_ctrl->chips[priv->bank] = priv;
|
||||
|
||||
/* fill in nand_chip structure */
|
||||
@ -852,8 +858,8 @@ int board_nand_init(struct nand_chip *nand)
|
||||
nand->bbt_md = &bbt_mirror_descr;
|
||||
|
||||
/* set up nand options */
|
||||
nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR |
|
||||
NAND_USE_FLASH_BBT | NAND_NO_SUBPAGE_WRITE;
|
||||
nand->options = NAND_NO_SUBPAGE_WRITE;
|
||||
nand->bbt_options = NAND_BBT_USE_FLASH;
|
||||
|
||||
if (cspr & CSPR_PORT_SIZE_16) {
|
||||
nand->read_byte = fsl_ifc_read_byte16;
|
||||
@ -884,11 +890,13 @@ int board_nand_init(struct nand_chip *nand)
|
||||
bbt_mirror_descr.offs = 0;
|
||||
}
|
||||
|
||||
nand->ecc.strength = 4;
|
||||
priv->bufnum_mask = 15;
|
||||
break;
|
||||
|
||||
case CSOR_NAND_PGS_2K:
|
||||
layout = &oob_2048_ecc4;
|
||||
nand->ecc.strength = 4;
|
||||
priv->bufnum_mask = 3;
|
||||
break;
|
||||
|
||||
@ -896,8 +904,10 @@ int board_nand_init(struct nand_chip *nand)
|
||||
if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
|
||||
CSOR_NAND_ECC_MODE_4) {
|
||||
layout = &oob_4096_ecc4;
|
||||
nand->ecc.strength = 4;
|
||||
} else {
|
||||
layout = &oob_4096_ecc8;
|
||||
nand->ecc.strength = 8;
|
||||
nand->ecc.bytes = 16;
|
||||
}
|
||||
|
||||
@ -921,5 +931,31 @@ int board_nand_init(struct nand_chip *nand)
|
||||
if (ver == FSL_IFC_V1_1_0)
|
||||
fsl_ifc_sram_init();
|
||||
|
||||
ret = nand_scan_ident(mtd, 1, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nand_scan_tail(mtd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nand_register(devnum);
|
||||
if (ret)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SYS_NAND_BASE_LIST
|
||||
#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE }
|
||||
#endif
|
||||
|
||||
static unsigned long base_address[CONFIG_SYS_MAX_NAND_DEVICE] =
|
||||
CONFIG_SYS_NAND_BASE_LIST;
|
||||
|
||||
void board_nand_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
|
||||
fsl_ifc_chip_init(i, (u8 *)base_address[i]);
|
||||
}
|
||||
|
@ -341,6 +341,7 @@ void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||
* @mtd: mtd info structure
|
||||
* @chip: nand chip info structure
|
||||
* @buf: buffer to store read data
|
||||
* @oob_required: caller expects OOB data read to chip->oob_poi
|
||||
* @page: page number to read
|
||||
*
|
||||
* This routine is needed for fsmc verison 8 as reading from NAND chip has to be
|
||||
@ -350,7 +351,7 @@ void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||
* max of 8 bits)
|
||||
*/
|
||||
static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int page)
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
{
|
||||
struct fsmc_eccplace *fsmc_eccpl;
|
||||
int i, j, s, stat, eccsize = chip->ecc.size;
|
||||
@ -452,6 +453,7 @@ int fsmc_nand_init(struct nand_chip *nand)
|
||||
switch (fsmc_version) {
|
||||
case FSMC_VER8:
|
||||
nand->ecc.bytes = 13;
|
||||
nand->ecc.strength = 8;
|
||||
nand->ecc.correct = fsmc_bch8_correct_data;
|
||||
nand->ecc.read_page = fsmc_read_page_hwecc;
|
||||
if (mtd->writesize == 512)
|
||||
@ -466,6 +468,7 @@ int fsmc_nand_init(struct nand_chip *nand)
|
||||
break;
|
||||
default:
|
||||
nand->ecc.bytes = 3;
|
||||
nand->ecc.strength = 1;
|
||||
nand->ecc.layout = &fsmc_ecc1_layout;
|
||||
nand->ecc.correct = nand_correct_data;
|
||||
break;
|
||||
|
@ -253,6 +253,7 @@ int board_nand_init(struct nand_chip *nand)
|
||||
nand->ecc.mode = NAND_ECC_HW_OOB_FIRST;
|
||||
nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
|
||||
nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
|
||||
nand->ecc.strength = 4;
|
||||
nand->ecc.layout = &qi_lb60_ecclayout_2gb;
|
||||
nand->chip_delay = 50;
|
||||
nand->options = NAND_USE_FLASH_BBT;
|
||||
|
@ -621,7 +621,7 @@ int board_nand_init(struct nand_chip *chip)
|
||||
chip->write_buf = mpc5121_nfc_write_buf;
|
||||
chip->verify_buf = mpc5121_nfc_verify_buf;
|
||||
chip->select_chip = mpc5121_nfc_select_chip;
|
||||
chip->options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT;
|
||||
chip->bbt_options = NAND_BBT_USE_FLASH;
|
||||
chip->ecc.mode = NAND_ECC_SOFT;
|
||||
|
||||
/* Reset NAND Flash controller */
|
||||
|
@ -396,7 +396,7 @@ static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||
#if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2)
|
||||
static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
int page, int sndcmd)
|
||||
int page)
|
||||
{
|
||||
struct mxc_nand_host *host = chip->priv;
|
||||
uint8_t *buf = chip->oob_poi;
|
||||
@ -450,6 +450,7 @@ static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd,
|
||||
static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
uint8_t *buf,
|
||||
int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct mxc_nand_host *host = chip->priv;
|
||||
@ -494,6 +495,7 @@ static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd,
|
||||
static int mxc_nand_read_page_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
uint8_t *buf,
|
||||
int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct mxc_nand_host *host = chip->priv;
|
||||
@ -583,9 +585,10 @@ static int mxc_nand_write_oob_syndrome(struct mtd_info *mtd,
|
||||
return status & NAND_STATUS_FAIL ? -EIO : 0;
|
||||
}
|
||||
|
||||
static void mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd,
|
||||
static int mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
const uint8_t *buf)
|
||||
const uint8_t *buf,
|
||||
int oob_required)
|
||||
{
|
||||
struct mxc_nand_host *host = chip->priv;
|
||||
int eccsize = chip->ecc.size;
|
||||
@ -619,11 +622,13 @@ static void mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd,
|
||||
size = mtd->oobsize - (oob - chip->oob_poi);
|
||||
if (size)
|
||||
chip->write_buf(mtd, oob, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mxc_nand_write_page_syndrome(struct mtd_info *mtd,
|
||||
static int mxc_nand_write_page_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
const uint8_t *buf)
|
||||
const uint8_t *buf,
|
||||
int oob_required)
|
||||
{
|
||||
struct mxc_nand_host *host = chip->priv;
|
||||
int i, n, eccsize = chip->ecc.size;
|
||||
@ -662,6 +667,7 @@ static void mxc_nand_write_page_syndrome(struct mtd_info *mtd,
|
||||
i = mtd->oobsize - (oob - chip->oob_poi);
|
||||
if (i)
|
||||
chip->write_buf(mtd, oob, i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||
@ -1188,7 +1194,7 @@ int board_nand_init(struct nand_chip *this)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
|
||||
this->options |= NAND_USE_FLASH_BBT;
|
||||
this->bbt_options |= NAND_BBT_USE_FLASH;
|
||||
this->bbt_td = &bbt_main_descr;
|
||||
this->bbt_md = &bbt_mirror_descr;
|
||||
#endif
|
||||
@ -1236,6 +1242,13 @@ int board_nand_init(struct nand_chip *this)
|
||||
this->ecc.mode = NAND_ECC_HW;
|
||||
}
|
||||
|
||||
if (this->ecc.mode == NAND_ECC_HW) {
|
||||
if (is_mxc_nfc_1())
|
||||
this->ecc.strength = 1;
|
||||
else
|
||||
this->ecc.strength = 4;
|
||||
}
|
||||
|
||||
host->pagesize_2k = 0;
|
||||
|
||||
this->ecc.size = 512;
|
||||
|
@ -553,7 +553,8 @@ static uint8_t mxs_nand_read_byte(struct mtd_info *mtd)
|
||||
* Read a page from NAND.
|
||||
*/
|
||||
static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
|
||||
uint8_t *buf, int page)
|
||||
uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct mxs_nand_info *nand_info = nand->priv;
|
||||
struct mxs_dma_desc *d;
|
||||
@ -698,8 +699,9 @@ rtn:
|
||||
/*
|
||||
* Write a page to NAND.
|
||||
*/
|
||||
static void mxs_nand_ecc_write_page(struct mtd_info *mtd,
|
||||
struct nand_chip *nand, const uint8_t *buf)
|
||||
static int mxs_nand_ecc_write_page(struct mtd_info *mtd,
|
||||
struct nand_chip *nand, const uint8_t *buf,
|
||||
int oob_required)
|
||||
{
|
||||
struct mxs_nand_info *nand_info = nand->priv;
|
||||
struct mxs_dma_desc *d;
|
||||
@ -755,6 +757,7 @@ static void mxs_nand_ecc_write_page(struct mtd_info *mtd,
|
||||
|
||||
rtn:
|
||||
mxs_nand_return_dma_descs(nand_info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -770,7 +773,7 @@ static int mxs_nand_hook_read_oob(struct mtd_info *mtd, loff_t from,
|
||||
struct mxs_nand_info *nand_info = chip->priv;
|
||||
int ret;
|
||||
|
||||
if (ops->mode == MTD_OOB_RAW)
|
||||
if (ops->mode == MTD_OPS_RAW)
|
||||
nand_info->raw_oob_mode = 1;
|
||||
else
|
||||
nand_info->raw_oob_mode = 0;
|
||||
@ -795,7 +798,7 @@ static int mxs_nand_hook_write_oob(struct mtd_info *mtd, loff_t to,
|
||||
struct mxs_nand_info *nand_info = chip->priv;
|
||||
int ret;
|
||||
|
||||
if (ops->mode == MTD_OOB_RAW)
|
||||
if (ops->mode == MTD_OPS_RAW)
|
||||
nand_info->raw_oob_mode = 1;
|
||||
else
|
||||
nand_info->raw_oob_mode = 0;
|
||||
@ -873,7 +876,7 @@ static int mxs_nand_hook_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
* what to do.
|
||||
*/
|
||||
static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
|
||||
int page, int cmd)
|
||||
int page)
|
||||
{
|
||||
struct mxs_nand_info *nand_info = nand->priv;
|
||||
|
||||
@ -1006,19 +1009,19 @@ static int mxs_nand_scan_bbt(struct mtd_info *mtd)
|
||||
writel(BCH_CTRL_COMPLETE_IRQ_EN, &bch_regs->hw_bch_ctrl_set);
|
||||
|
||||
/* Hook some operations at the MTD level. */
|
||||
if (mtd->read_oob != mxs_nand_hook_read_oob) {
|
||||
nand_info->hooked_read_oob = mtd->read_oob;
|
||||
mtd->read_oob = mxs_nand_hook_read_oob;
|
||||
if (mtd->_read_oob != mxs_nand_hook_read_oob) {
|
||||
nand_info->hooked_read_oob = mtd->_read_oob;
|
||||
mtd->_read_oob = mxs_nand_hook_read_oob;
|
||||
}
|
||||
|
||||
if (mtd->write_oob != mxs_nand_hook_write_oob) {
|
||||
nand_info->hooked_write_oob = mtd->write_oob;
|
||||
mtd->write_oob = mxs_nand_hook_write_oob;
|
||||
if (mtd->_write_oob != mxs_nand_hook_write_oob) {
|
||||
nand_info->hooked_write_oob = mtd->_write_oob;
|
||||
mtd->_write_oob = mxs_nand_hook_write_oob;
|
||||
}
|
||||
|
||||
if (mtd->block_markbad != mxs_nand_hook_block_markbad) {
|
||||
nand_info->hooked_block_markbad = mtd->block_markbad;
|
||||
mtd->block_markbad = mxs_nand_hook_block_markbad;
|
||||
if (mtd->_block_markbad != mxs_nand_hook_block_markbad) {
|
||||
nand_info->hooked_block_markbad = mtd->_block_markbad;
|
||||
mtd->_block_markbad = mxs_nand_hook_block_markbad;
|
||||
}
|
||||
|
||||
/* We use the reference implementation for bad block management. */
|
||||
@ -1172,6 +1175,7 @@ int board_nand_init(struct nand_chip *nand)
|
||||
nand->ecc.mode = NAND_ECC_HW;
|
||||
nand->ecc.bytes = 9;
|
||||
nand->ecc.size = 512;
|
||||
nand->ecc.strength = 8;
|
||||
|
||||
return 0;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -71,7 +71,7 @@ const struct nand_flash_dev nand_flash_ids[] = {
|
||||
* These are the new chips with large page size. The pagesize and the
|
||||
* erasesize is determined from the extended id bytes
|
||||
*/
|
||||
#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR)
|
||||
#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS
|
||||
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
|
||||
|
||||
/* 512 Megabit */
|
||||
@ -79,6 +79,7 @@ const struct nand_flash_dev nand_flash_ids[] = {
|
||||
{"NAND 64MiB 1,8V 8-bit", 0xA0, 0, 64, 0, LP_OPTIONS},
|
||||
{"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS},
|
||||
{"NAND 64MiB 3,3V 8-bit", 0xD0, 0, 64, 0, LP_OPTIONS},
|
||||
{"NAND 64MiB 3,3V 8-bit", 0xF0, 0, 64, 0, LP_OPTIONS},
|
||||
{"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16},
|
||||
{"NAND 64MiB 1,8V 16-bit", 0xB0, 0, 64, 0, LP_OPTIONS16},
|
||||
{"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16},
|
||||
@ -157,9 +158,7 @@ const struct nand_flash_dev nand_flash_ids[] = {
|
||||
* writes possible, but not implemented now
|
||||
*/
|
||||
{"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000,
|
||||
NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY |
|
||||
BBT_AUTO_REFRESH
|
||||
},
|
||||
NAND_IS_AND | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
|
||||
|
||||
{NULL,}
|
||||
};
|
||||
@ -176,6 +175,9 @@ const struct nand_manufacturers nand_manuf_ids[] = {
|
||||
{NAND_MFR_STMICRO, "ST Micro"},
|
||||
{NAND_MFR_HYNIX, "Hynix"},
|
||||
{NAND_MFR_MICRON, "Micron"},
|
||||
{NAND_MFR_AMD, "AMD"},
|
||||
{NAND_MFR_AMD, "AMD/Spansion"},
|
||||
{NAND_MFR_MACRONIX, "Macronix"},
|
||||
{NAND_MFR_EON, "Eon"},
|
||||
{0x0, "Unknown"}
|
||||
};
|
||||
|
||||
|
@ -121,7 +121,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
|
||||
WATCHDOG_RESET();
|
||||
|
||||
if (!opts->scrub && bbtest) {
|
||||
int ret = meminfo->block_isbad(meminfo, erase.addr);
|
||||
int ret = mtd_block_isbad(meminfo, erase.addr);
|
||||
if (ret > 0) {
|
||||
if (!opts->quiet)
|
||||
printf("\rSkipping bad block at "
|
||||
@ -144,7 +144,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
|
||||
|
||||
erased_length++;
|
||||
|
||||
result = meminfo->erase(meminfo, &erase);
|
||||
result = mtd_erase(meminfo, &erase);
|
||||
if (result != 0) {
|
||||
printf("\n%s: MTD Erase failure: %d\n",
|
||||
mtd_device, result);
|
||||
@ -153,15 +153,16 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
|
||||
|
||||
/* format for JFFS2 ? */
|
||||
if (opts->jffs2 && chip->ecc.layout->oobavail >= 8) {
|
||||
chip->ops.ooblen = 8;
|
||||
chip->ops.datbuf = NULL;
|
||||
chip->ops.oobbuf = (uint8_t *)&cleanmarker;
|
||||
chip->ops.ooboffs = 0;
|
||||
chip->ops.mode = MTD_OOB_AUTO;
|
||||
struct mtd_oob_ops ops;
|
||||
ops.ooblen = 8;
|
||||
ops.datbuf = NULL;
|
||||
ops.oobbuf = (uint8_t *)&cleanmarker;
|
||||
ops.ooboffs = 0;
|
||||
ops.mode = MTD_OPS_AUTO_OOB;
|
||||
|
||||
result = meminfo->write_oob(meminfo,
|
||||
result = mtd_write_oob(meminfo,
|
||||
erase.addr,
|
||||
&chip->ops);
|
||||
&ops);
|
||||
if (result != 0) {
|
||||
printf("\n%s: MTD writeoob failure: %d\n",
|
||||
mtd_device, result);
|
||||
@ -458,7 +459,8 @@ static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length,
|
||||
static size_t drop_ffs(const nand_info_t *nand, const u_char *buf,
|
||||
const size_t *len)
|
||||
{
|
||||
size_t i, l = *len;
|
||||
size_t l = *len;
|
||||
ssize_t i;
|
||||
|
||||
for (i = l - 1; i >= 0; i--)
|
||||
if (buf[i] != 0xFF)
|
||||
@ -604,7 +606,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
|
||||
ops.len = pagesize;
|
||||
ops.ooblen = nand->oobsize;
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.mode = MTD_OPS_AUTO_OOB;
|
||||
ops.ooboffs = 0;
|
||||
|
||||
pages = write_size / pagesize_oob;
|
||||
@ -614,7 +616,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
ops.datbuf = p_buffer;
|
||||
ops.oobbuf = ops.datbuf + pagesize;
|
||||
|
||||
rval = nand->write_oob(nand, offset, &ops);
|
||||
rval = mtd_write_oob(nand, offset, &ops);
|
||||
if (rval != 0)
|
||||
break;
|
||||
|
||||
|
@ -216,6 +216,7 @@ int board_nand_init(struct nand_chip *nand)
|
||||
nand->ecc.mode = NAND_ECC_HW;
|
||||
nand->ecc.size = 256;
|
||||
nand->ecc.bytes = 3;
|
||||
nand->ecc.strength = 1;
|
||||
nand->select_chip = ndfc_select_chip;
|
||||
|
||||
#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT
|
||||
|
@ -212,6 +212,7 @@ int board_nand_init(struct nand_chip *chip)
|
||||
chip->ecc.mode = NAND_ECC_HW;
|
||||
chip->ecc.bytes = 3;
|
||||
chip->ecc.size = 512;
|
||||
chip->ecc.strength = 1;
|
||||
chip->ecc.layout = &nomadik_ecc_layout;
|
||||
chip->ecc.calculate = nomadik_ecc_calculate;
|
||||
chip->ecc.hwctl = nomadik_ecc_hwctl;
|
||||
|
@ -590,11 +590,12 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
|
||||
* @mtd: mtd info structure
|
||||
* @chip: nand chip info structure
|
||||
* @buf: buffer to store read data
|
||||
* @oob_required: caller expects OOB data read to chip->oob_poi
|
||||
* @page: page number to read
|
||||
*
|
||||
*/
|
||||
static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int page)
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
{
|
||||
int i, eccsize = chip->ecc.size;
|
||||
int eccbytes = chip->ecc.bytes;
|
||||
@ -804,6 +805,7 @@ void omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength)
|
||||
nand->ecc.hwctl = NULL;
|
||||
nand->ecc.correct = NULL;
|
||||
nand->ecc.calculate = NULL;
|
||||
nand->ecc.strength = eccstrength;
|
||||
|
||||
/* Setup the ecc configurations again */
|
||||
if (hardware) {
|
||||
@ -901,7 +903,7 @@ int board_nand_init(struct nand_chip *nand)
|
||||
nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
|
||||
|
||||
nand->cmd_ctrl = omap_nand_hwcontrol;
|
||||
nand->options = NAND_NO_PADDING | NAND_CACHEPRG | NAND_NO_AUTOINCR;
|
||||
nand->options = NAND_NO_PADDING | NAND_CACHEPRG;
|
||||
/* If we are 16 bit dev, our gpmc config tells us that */
|
||||
if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000)
|
||||
nand->options |= NAND_BUSWIDTH_16;
|
||||
|
@ -173,6 +173,7 @@ int board_nand_init(struct nand_chip *nand)
|
||||
nand->ecc.mode = NAND_ECC_HW;
|
||||
nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
|
||||
nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
|
||||
nand->ecc.strength = 1;
|
||||
#else
|
||||
nand->ecc.mode = NAND_ECC_SOFT;
|
||||
#endif
|
||||
|
@ -707,7 +707,7 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
* -EIO when command timeout
|
||||
*/
|
||||
static int nand_read_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, uint8_t *buf, int page)
|
||||
struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
|
||||
{
|
||||
return nand_rw_page(mtd, chip, buf, page, 1, 0);
|
||||
}
|
||||
@ -719,8 +719,8 @@ static int nand_read_page_hwecc(struct mtd_info *mtd,
|
||||
* @param chip nand chip info structure
|
||||
* @param buf data buffer
|
||||
*/
|
||||
static void nand_write_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf)
|
||||
static int nand_write_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf, int oob_required)
|
||||
{
|
||||
int page;
|
||||
struct nand_drv *info;
|
||||
@ -731,6 +731,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd,
|
||||
(readl(&info->reg->addr_reg2) << 16);
|
||||
|
||||
nand_rw_page(mtd, chip, (uint8_t *)buf, page, 1, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -746,7 +747,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd,
|
||||
* -EIO when command timeout
|
||||
*/
|
||||
static int nand_read_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, uint8_t *buf, int page)
|
||||
struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
|
||||
{
|
||||
return nand_rw_page(mtd, chip, buf, page, 0, 0);
|
||||
}
|
||||
@ -758,8 +759,8 @@ static int nand_read_page_raw(struct mtd_info *mtd,
|
||||
* @param chip nand chip info structure
|
||||
* @param buf data buffer
|
||||
*/
|
||||
static void nand_write_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf)
|
||||
static int nand_write_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf, int oob_required)
|
||||
{
|
||||
int page;
|
||||
struct nand_drv *info;
|
||||
@ -769,6 +770,7 @@ static void nand_write_page_raw(struct mtd_info *mtd,
|
||||
(readl(&info->reg->addr_reg2) << 16);
|
||||
|
||||
nand_rw_page(mtd, chip, (uint8_t *)buf, page, 0, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -873,19 +875,13 @@ static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
* @param mtd mtd info structure
|
||||
* @param chip nand chip info structure
|
||||
* @param page page number to read
|
||||
* @param sndcmd flag whether to issue read command or not
|
||||
* @return 1 - issue read command next time
|
||||
* 0 - not to issue
|
||||
*/
|
||||
static int nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page, int sndcmd)
|
||||
int page)
|
||||
{
|
||||
if (sndcmd) {
|
||||
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
|
||||
sndcmd = 0;
|
||||
}
|
||||
nand_rw_oob(mtd, chip, page, 0, 0);
|
||||
return sndcmd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1018,6 +1014,7 @@ int tegra_nand_init(struct nand_chip *nand, int devnum)
|
||||
nand->ecc.write_page_raw = nand_write_page_raw;
|
||||
nand->ecc.read_oob = nand_read_oob;
|
||||
nand->ecc.write_oob = nand_write_oob;
|
||||
nand->ecc.strength = 1;
|
||||
nand->select_chip = nand_select_chip;
|
||||
nand->dev_ready = nand_dev_ready;
|
||||
nand->priv = &nand_ctrl;
|
||||
|
@ -224,7 +224,7 @@ enum {
|
||||
#define BCH_DEC_STATUS_MAX_CORR_CNT_MASK (0x1f << 8)
|
||||
#define BCH_DEC_STATUS_PAGE_NUMBER_MASK 0xFF
|
||||
|
||||
#define LP_OPTIONS (NAND_NO_READRDY | NAND_NO_AUTOINCR)
|
||||
#define LP_OPTIONS 0
|
||||
|
||||
struct nand_ctlr {
|
||||
u32 command; /* offset 00h */
|
||||
|
@ -743,7 +743,7 @@ static void onenand_release_device(struct mtd_info *mtd)
|
||||
}
|
||||
|
||||
/**
|
||||
* onenand_transfer_auto_oob - [Internal] oob auto-placement transfer
|
||||
* onenand_transfer_auto_oob - [INTERN] oob auto-placement transfer
|
||||
* @param mtd MTD device structure
|
||||
* @param buf destination address
|
||||
* @param column oob offset to read from
|
||||
@ -807,7 +807,7 @@ static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status)
|
||||
return status;
|
||||
|
||||
/* check if we failed due to uncorrectable error */
|
||||
if (status != -EBADMSG && status != ONENAND_BBT_READ_ECC_ERROR)
|
||||
if (!mtd_is_eccerr(status) && status != ONENAND_BBT_READ_ECC_ERROR)
|
||||
return status;
|
||||
|
||||
/* check if address lies in MLC region */
|
||||
@ -847,7 +847,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
|
||||
|
||||
MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
|
||||
|
||||
if (ops->mode == MTD_OOB_AUTO)
|
||||
if (ops->mode == MTD_OPS_AUTO_OOB)
|
||||
oobsize = this->ecclayout->oobavail;
|
||||
else
|
||||
oobsize = mtd->oobsize;
|
||||
@ -914,7 +914,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
|
||||
thisooblen = oobsize - oobcolumn;
|
||||
thisooblen = min_t(int, thisooblen, ooblen - oobread);
|
||||
|
||||
if (ops->mode == MTD_OOB_AUTO)
|
||||
if (ops->mode == MTD_OPS_AUTO_OOB)
|
||||
onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
|
||||
else
|
||||
this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
|
||||
@ -929,7 +929,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
|
||||
if (unlikely(ret))
|
||||
ret = onenand_recover_lsb(mtd, from, ret);
|
||||
onenand_update_bufferram(mtd, from, !ret);
|
||||
if (ret == -EBADMSG)
|
||||
if (mtd_is_eccerr(ret))
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
@ -950,7 +950,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
|
||||
/* Now wait for load */
|
||||
ret = this->wait(mtd, FL_READING);
|
||||
onenand_update_bufferram(mtd, from, !ret);
|
||||
if (ret == -EBADMSG)
|
||||
if (mtd_is_eccerr(ret))
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
@ -987,7 +987,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
|
||||
struct mtd_ecc_stats stats;
|
||||
int read = 0, thislen, column, oobsize;
|
||||
size_t len = ops->ooblen;
|
||||
mtd_oob_mode_t mode = ops->mode;
|
||||
unsigned int mode = ops->mode;
|
||||
u_char *buf = ops->oobbuf;
|
||||
int ret = 0, readcmd;
|
||||
|
||||
@ -998,7 +998,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
|
||||
/* Initialize return length value */
|
||||
ops->oobretlen = 0;
|
||||
|
||||
if (mode == MTD_OOB_AUTO)
|
||||
if (mode == MTD_OPS_AUTO_OOB)
|
||||
oobsize = this->ecclayout->oobavail;
|
||||
else
|
||||
oobsize = mtd->oobsize;
|
||||
@ -1041,7 +1041,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
|
||||
break;
|
||||
}
|
||||
|
||||
if (mode == MTD_OOB_AUTO)
|
||||
if (mode == MTD_OPS_AUTO_OOB)
|
||||
onenand_transfer_auto_oob(mtd, buf, column, thislen);
|
||||
else
|
||||
this->read_bufferram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen);
|
||||
@ -1115,10 +1115,10 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from,
|
||||
int ret;
|
||||
|
||||
switch (ops->mode) {
|
||||
case MTD_OOB_PLACE:
|
||||
case MTD_OOB_AUTO:
|
||||
case MTD_OPS_PLACE_OOB:
|
||||
case MTD_OPS_AUTO_OOB:
|
||||
break;
|
||||
case MTD_OOB_RAW:
|
||||
case MTD_OPS_RAW:
|
||||
/* Not implemented yet */
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -1337,7 +1337,7 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,
|
||||
#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0)
|
||||
|
||||
/**
|
||||
* onenand_fill_auto_oob - [Internal] oob auto-placement transfer
|
||||
* onenand_fill_auto_oob - [INTERN] oob auto-placement transfer
|
||||
* @param mtd MTD device structure
|
||||
* @param oob_buf oob buffer
|
||||
* @param buf source address
|
||||
@ -1404,19 +1404,13 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
|
||||
ops->retlen = 0;
|
||||
ops->oobretlen = 0;
|
||||
|
||||
/* Do not allow writes past end of device */
|
||||
if (unlikely((to + len) > mtd->size)) {
|
||||
printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Reject writes, which are not page aligned */
|
||||
if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
|
||||
printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ops->mode == MTD_OOB_AUTO)
|
||||
if (ops->mode == MTD_OPS_AUTO_OOB)
|
||||
oobsize = this->ecclayout->oobavail;
|
||||
else
|
||||
oobsize = mtd->oobsize;
|
||||
@ -1450,7 +1444,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
|
||||
/* We send data to spare ram with oobsize
|
||||
* * to prevent byte access */
|
||||
memset(oobbuf, 0xff, mtd->oobsize);
|
||||
if (ops->mode == MTD_OOB_AUTO)
|
||||
if (ops->mode == MTD_OPS_AUTO_OOB)
|
||||
onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
|
||||
else
|
||||
memcpy(oobbuf + oobcolumn, oob, thisooblen);
|
||||
@ -1502,7 +1496,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
|
||||
}
|
||||
|
||||
/**
|
||||
* onenand_write_oob_nolock - [Internal] OneNAND write out-of-band
|
||||
* onenand_write_oob_nolock - [INTERN] OneNAND write out-of-band
|
||||
* @param mtd MTD device structure
|
||||
* @param to offset to write to
|
||||
* @param len number of bytes to write
|
||||
@ -1521,7 +1515,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
|
||||
u_char *oobbuf;
|
||||
size_t len = ops->ooblen;
|
||||
const u_char *buf = ops->oobbuf;
|
||||
mtd_oob_mode_t mode = ops->mode;
|
||||
unsigned int mode = ops->mode;
|
||||
|
||||
to += ops->ooboffs;
|
||||
|
||||
@ -1530,7 +1524,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
|
||||
/* Initialize retlen, in case of early exit */
|
||||
ops->oobretlen = 0;
|
||||
|
||||
if (mode == MTD_OOB_AUTO)
|
||||
if (mode == MTD_OPS_AUTO_OOB)
|
||||
oobsize = this->ecclayout->oobavail;
|
||||
else
|
||||
oobsize = mtd->oobsize;
|
||||
@ -1571,7 +1565,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
|
||||
/* We send data to spare ram with oobsize
|
||||
* to prevent byte access */
|
||||
memset(oobbuf, 0xff, mtd->oobsize);
|
||||
if (mode == MTD_OOB_AUTO)
|
||||
if (mode == MTD_OPS_AUTO_OOB)
|
||||
onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);
|
||||
else
|
||||
memcpy(oobbuf + column, buf, thislen);
|
||||
@ -1661,10 +1655,10 @@ int onenand_write_oob(struct mtd_info *mtd, loff_t to,
|
||||
int ret;
|
||||
|
||||
switch (ops->mode) {
|
||||
case MTD_OOB_PLACE:
|
||||
case MTD_OOB_AUTO:
|
||||
case MTD_OPS_PLACE_OOB:
|
||||
case MTD_OPS_AUTO_OOB:
|
||||
break;
|
||||
case MTD_OOB_RAW:
|
||||
case MTD_OPS_RAW:
|
||||
/* Not implemented yet */
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -1720,13 +1714,6 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n",
|
||||
(unsigned int) addr, len);
|
||||
|
||||
/* Do not allow erase past end of device */
|
||||
if (unlikely((len + addr) > mtd->size)) {
|
||||
MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:"
|
||||
"Erase past end of device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (FLEXONENAND(this)) {
|
||||
/* Find the eraseregion of this address */
|
||||
i = flexonenand_region(mtd, addr);
|
||||
@ -1762,8 +1749,6 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
instr->fail_addr = 0xffffffff;
|
||||
|
||||
/* Grab the lock and see if the device is available */
|
||||
onenand_get_device(mtd, FL_ERASING);
|
||||
|
||||
@ -1889,7 +1874,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
struct bbm_info *bbm = this->bbm;
|
||||
u_char buf[2] = {0, 0};
|
||||
struct mtd_oob_ops ops = {
|
||||
.mode = MTD_OOB_PLACE,
|
||||
.mode = MTD_OPS_PLACE_OOB,
|
||||
.ooblen = 2,
|
||||
.oobbuf = buf,
|
||||
.ooboffs = 0,
|
||||
@ -1915,7 +1900,6 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
*/
|
||||
int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
int ret;
|
||||
|
||||
ret = onenand_block_isbad(mtd, ofs);
|
||||
@ -1926,7 +1910,7 @@ int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = this->block_markbad(mtd, ofs);
|
||||
ret = mtd_block_markbad(mtd, ofs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2386,7 +2370,7 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd,
|
||||
int i, ret;
|
||||
int block;
|
||||
struct mtd_oob_ops ops = {
|
||||
.mode = MTD_OOB_PLACE,
|
||||
.mode = MTD_OPS_PLACE_OOB,
|
||||
.ooboffs = 0,
|
||||
.ooblen = mtd->oobsize,
|
||||
.datbuf = NULL,
|
||||
@ -2645,14 +2629,14 @@ int onenand_probe(struct mtd_info *mtd)
|
||||
mtd->size = this->chipsize;
|
||||
|
||||
mtd->flags = MTD_CAP_NANDFLASH;
|
||||
mtd->erase = onenand_erase;
|
||||
mtd->read = onenand_read;
|
||||
mtd->write = onenand_write;
|
||||
mtd->read_oob = onenand_read_oob;
|
||||
mtd->write_oob = onenand_write_oob;
|
||||
mtd->sync = onenand_sync;
|
||||
mtd->block_isbad = onenand_block_isbad;
|
||||
mtd->block_markbad = onenand_block_markbad;
|
||||
mtd->_erase = onenand_erase;
|
||||
mtd->_read = onenand_read;
|
||||
mtd->_write = onenand_write;
|
||||
mtd->_read_oob = onenand_read_oob;
|
||||
mtd->_write_oob = onenand_write_oob;
|
||||
mtd->_sync = onenand_sync;
|
||||
mtd->_block_isbad = onenand_block_isbad;
|
||||
mtd->_block_markbad = onenand_block_markbad;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf,
|
||||
startblock = 0;
|
||||
from = 0;
|
||||
|
||||
ops.mode = MTD_OOB_PLACE;
|
||||
ops.mode = MTD_OPS_PLACE_OOB;
|
||||
ops.ooblen = readlen;
|
||||
ops.oobbuf = buf;
|
||||
ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
|
||||
@ -200,10 +200,8 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||
len = this->chipsize >> (this->erase_shift + 2);
|
||||
/* Allocate memory (2bit per block) */
|
||||
bbm->bbt = malloc(len);
|
||||
if (!bbm->bbt) {
|
||||
printk(KERN_ERR "onenand_scan_bbt: Out of memory\n");
|
||||
if (!bbm->bbt)
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* Clear the memory bad block table */
|
||||
memset(bbm->bbt, 0x00, len);
|
||||
|
||||
|
@ -539,7 +539,7 @@ static int io_init(struct ubi_device *ubi)
|
||||
ubi->peb_count = mtd_div_by_eb(ubi->mtd->size, ubi->mtd);
|
||||
ubi->flash_size = ubi->mtd->size;
|
||||
|
||||
if (ubi->mtd->block_isbad && ubi->mtd->block_markbad)
|
||||
if (mtd_can_have_bb(ubi->mtd))
|
||||
ubi->bad_allowed = 1;
|
||||
|
||||
ubi->min_io_size = ubi->mtd->writesize;
|
||||
|
@ -460,7 +460,7 @@ retry:
|
||||
if (err == UBI_IO_BITFLIPS) {
|
||||
scrub = 1;
|
||||
err = 0;
|
||||
} else if (err == -EBADMSG) {
|
||||
} else if (mtd_is_eccerr(err)) {
|
||||
if (vol->vol_type == UBI_DYNAMIC_VOLUME)
|
||||
goto out_unlock;
|
||||
scrub = 1;
|
||||
|
@ -154,7 +154,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
|
||||
|
||||
addr = (loff_t)pnum * ubi->peb_size + offset;
|
||||
retry:
|
||||
err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
|
||||
err = mtd_read(ubi->mtd, addr, len, &read, buf);
|
||||
if (err) {
|
||||
if (err == -EUCLEAN) {
|
||||
/*
|
||||
@ -268,7 +268,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
|
||||
}
|
||||
|
||||
addr = (loff_t)pnum * ubi->peb_size + offset;
|
||||
err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf);
|
||||
err = mtd_write(ubi->mtd, addr, len, &written, buf);
|
||||
if (err) {
|
||||
ubi_err("error %d while writing %d bytes to PEB %d:%d, written"
|
||||
" %zd bytes", err, len, pnum, offset, written);
|
||||
@ -318,7 +318,7 @@ retry:
|
||||
ei.callback = erase_callback;
|
||||
ei.priv = (unsigned long)&wq;
|
||||
|
||||
err = ubi->mtd->erase(ubi->mtd, &ei);
|
||||
err = mtd_erase(ubi->mtd, &ei);
|
||||
if (err) {
|
||||
if (retries++ < UBI_IO_RETRIES) {
|
||||
dbg_io("error %d while erasing PEB %d, retry",
|
||||
@ -516,7 +516,7 @@ int ubi_io_is_bad(const struct ubi_device *ubi, int pnum)
|
||||
if (ubi->bad_allowed) {
|
||||
int ret;
|
||||
|
||||
ret = mtd->block_isbad(mtd, (loff_t)pnum * ubi->peb_size);
|
||||
ret = mtd_block_isbad(mtd, (loff_t)pnum * ubi->peb_size);
|
||||
if (ret < 0)
|
||||
ubi_err("error %d while checking if PEB %d is bad",
|
||||
ret, pnum);
|
||||
@ -551,7 +551,7 @@ int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum)
|
||||
if (!ubi->bad_allowed)
|
||||
return 0;
|
||||
|
||||
err = mtd->block_markbad(mtd, (loff_t)pnum * ubi->peb_size);
|
||||
err = mtd_block_markbad(mtd, (loff_t)pnum * ubi->peb_size);
|
||||
if (err)
|
||||
ubi_err("cannot mark PEB %d bad, error %d", pnum, err);
|
||||
return err;
|
||||
@ -1242,7 +1242,7 @@ static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
|
||||
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
|
||||
|
||||
mutex_lock(&ubi->dbg_buf_mutex);
|
||||
err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf);
|
||||
err = mtd_read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf);
|
||||
if (err && err != -EUCLEAN) {
|
||||
ubi_err("error %d while reading %d bytes from PEB %d:%d, "
|
||||
"read %zd bytes", err, len, pnum, offset, read);
|
||||
|
@ -349,7 +349,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
|
||||
return 0;
|
||||
|
||||
err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check);
|
||||
if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) {
|
||||
if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) {
|
||||
ubi_warn("mark volume %d as corrupted", vol_id);
|
||||
vol->corrupted = 1;
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
|
||||
|
||||
err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1);
|
||||
if (err) {
|
||||
if (err == -EBADMSG)
|
||||
if (mtd_is_eccerr(err))
|
||||
err = 1;
|
||||
break;
|
||||
}
|
||||
|
@ -388,7 +388,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
|
||||
|
||||
err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
|
||||
ubi->vtbl_size);
|
||||
if (err == UBI_IO_BITFLIPS || err == -EBADMSG)
|
||||
if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err))
|
||||
/*
|
||||
* Scrub the PEB later. Note, -EBADMSG indicates an
|
||||
* uncorrectable ECC error, but we have our own CRC and
|
||||
|
@ -70,22 +70,22 @@ int nandmtd_WriteChunkToNAND(struct yaffs_dev *dev, int chunkInNAND,
|
||||
u8 spareAsBytes[8]; /* OOB */
|
||||
|
||||
if (data && !spare)
|
||||
retval = mtd->write(mtd, addr, dev->data_bytes_per_chunk,
|
||||
retval = mtd_write(mtd, addr, dev->data_bytes_per_chunk,
|
||||
&dummy, data);
|
||||
else if (spare) {
|
||||
if (dev->param.use_nand_ecc) {
|
||||
translate_spare2oob(spare, spareAsBytes);
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.mode = MTD_OPS_AUTO_OOB;
|
||||
ops.ooblen = 8; /* temp hack */
|
||||
} else {
|
||||
ops.mode = MTD_OOB_RAW;
|
||||
ops.mode = MTD_OPS_RAW;
|
||||
ops.ooblen = YAFFS_BYTES_PER_SPARE;
|
||||
}
|
||||
ops.len = data ? dev->data_bytes_per_chunk : ops.ooblen;
|
||||
ops.datbuf = (u8 *)data;
|
||||
ops.ooboffs = 0;
|
||||
ops.oobbuf = spareAsBytes;
|
||||
retval = mtd->write_oob(mtd, addr, &ops);
|
||||
retval = mtd_write_oob(mtd, addr, &ops);
|
||||
}
|
||||
|
||||
if (retval == 0)
|
||||
@ -106,21 +106,21 @@ int nandmtd_ReadChunkFromNAND(struct yaffs_dev *dev, int chunkInNAND, u8 *data,
|
||||
u8 spareAsBytes[8]; /* OOB */
|
||||
|
||||
if (data && !spare)
|
||||
retval = mtd->read(mtd, addr, dev->data_bytes_per_chunk,
|
||||
retval = mtd_read(mtd, addr, dev->data_bytes_per_chunk,
|
||||
&dummy, data);
|
||||
else if (spare) {
|
||||
if (dev->param.use_nand_ecc) {
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.mode = MTD_OPS_AUTO_OOB;
|
||||
ops.ooblen = 8; /* temp hack */
|
||||
} else {
|
||||
ops.mode = MTD_OOB_RAW;
|
||||
ops.mode = MTD_OPS_RAW;
|
||||
ops.ooblen = YAFFS_BYTES_PER_SPARE;
|
||||
}
|
||||
ops.len = data ? dev->data_bytes_per_chunk : ops.ooblen;
|
||||
ops.datbuf = data;
|
||||
ops.ooboffs = 0;
|
||||
ops.oobbuf = spareAsBytes;
|
||||
retval = mtd->read_oob(mtd, addr, &ops);
|
||||
retval = mtd_read_oob(mtd, addr, &ops);
|
||||
if (dev->param.use_nand_ecc)
|
||||
translate_oob2spare(spare, spareAsBytes);
|
||||
}
|
||||
@ -151,7 +151,7 @@ int nandmtd_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber)
|
||||
/* Todo finish off the ei if required */
|
||||
|
||||
|
||||
retval = mtd->erase(mtd, &ei);
|
||||
retval = mtd_erase(mtd, &ei);
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
|
@ -77,13 +77,13 @@ int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
|
||||
yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
|
||||
}
|
||||
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.mode = MTD_OPS_AUTO_OOB;
|
||||
ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
|
||||
ops.len = dev->param.total_bytes_per_chunk;
|
||||
ops.ooboffs = 0;
|
||||
ops.datbuf = (u8 *) data;
|
||||
ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
|
||||
retval = mtd->write_oob(mtd, addr, &ops);
|
||||
retval = mtd_write_oob(mtd, addr, &ops);
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
@ -121,16 +121,16 @@ int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
|
||||
}
|
||||
|
||||
if (dev->param.inband_tags || (data && !tags))
|
||||
retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
|
||||
retval = mtd_read(mtd, addr, dev->param.total_bytes_per_chunk,
|
||||
&dummy, data);
|
||||
else if (tags) {
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.mode = MTD_OPS_AUTO_OOB;
|
||||
ops.ooblen = packed_tags_size;
|
||||
ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
|
||||
ops.ooboffs = 0;
|
||||
ops.datbuf = data;
|
||||
ops.oobbuf = local_spare;
|
||||
retval = mtd->read_oob(mtd, addr, &ops);
|
||||
retval = mtd_read_oob(mtd, addr, &ops);
|
||||
}
|
||||
|
||||
if (dev->param.inband_tags) {
|
||||
@ -179,7 +179,7 @@ int nandmtd2_MarkNANDBlockBad(struct yaffs_dev *dev, int blockNo)
|
||||
"nandmtd2_MarkNANDBlockBad %d", blockNo);
|
||||
|
||||
retval =
|
||||
mtd->block_markbad(mtd,
|
||||
mtd_block_markbad(mtd,
|
||||
blockNo * dev->param.chunks_per_block *
|
||||
dev->data_bytes_per_chunk);
|
||||
|
||||
@ -198,7 +198,7 @@ int nandmtd2_QueryNANDBlock(struct yaffs_dev *dev, int blockNo,
|
||||
|
||||
yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_QueryNANDBlock %d", blockNo);
|
||||
retval =
|
||||
mtd->block_isbad(mtd,
|
||||
mtd_block_isbad(mtd,
|
||||
blockNo * dev->param.chunks_per_block *
|
||||
dev->data_bytes_per_chunk);
|
||||
|
||||
|
@ -316,7 +316,6 @@
|
||||
#define CONFIG_SYS_HUSH_PARSER
|
||||
|
||||
/* Video */
|
||||
#define CONFIG_FSL_DIU_FB
|
||||
|
||||
#ifdef CONFIG_FSL_DIU_FB
|
||||
#define CONFIG_SYS_DIU_ADDR (CONFIG_SYS_CCSRBAR + 0x10000)
|
||||
@ -336,7 +335,6 @@
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_FSL_DIU_FB
|
||||
#define CONFIG_ATI
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ATI
|
||||
|
@ -81,32 +81,53 @@ struct nand_bbt_descr {
|
||||
#define NAND_BBT_LASTBLOCK 0x00000010
|
||||
/* The bbt is at the given page, else we must scan for the bbt */
|
||||
#define NAND_BBT_ABSPAGE 0x00000020
|
||||
/* The bbt is at the given page, else we must scan for the bbt */
|
||||
#define NAND_BBT_SEARCH 0x00000040
|
||||
/* bbt is stored per chip on multichip devices */
|
||||
#define NAND_BBT_PERCHIP 0x00000080
|
||||
/* bbt has a version counter at offset veroffs */
|
||||
#define NAND_BBT_VERSION 0x00000100
|
||||
/* Create a bbt if none exists */
|
||||
#define NAND_BBT_CREATE 0x00000200
|
||||
/*
|
||||
* Create an empty BBT with no vendor information. Vendor's information may be
|
||||
* unavailable, for example, if the NAND controller has a different data and OOB
|
||||
* layout or if this information is already purged. Must be used in conjunction
|
||||
* with NAND_BBT_CREATE.
|
||||
*/
|
||||
#define NAND_BBT_CREATE_EMPTY 0x00000400
|
||||
/* Search good / bad pattern through all pages of a block */
|
||||
#define NAND_BBT_SCANALLPAGES 0x00000400
|
||||
#define NAND_BBT_SCANALLPAGES 0x00000800
|
||||
/* Scan block empty during good / bad block scan */
|
||||
#define NAND_BBT_SCANEMPTY 0x00000800
|
||||
#define NAND_BBT_SCANEMPTY 0x00001000
|
||||
/* Write bbt if neccecary */
|
||||
#define NAND_BBT_WRITE 0x00001000
|
||||
#define NAND_BBT_WRITE 0x00002000
|
||||
/* Read and write back block contents when writing bbt */
|
||||
#define NAND_BBT_SAVECONTENT 0x00002000
|
||||
#define NAND_BBT_SAVECONTENT 0x00004000
|
||||
/* Search good / bad pattern on the first and the second page */
|
||||
#define NAND_BBT_SCAN2NDPAGE 0x00004000
|
||||
#define NAND_BBT_SCAN2NDPAGE 0x00008000
|
||||
/* Search good / bad pattern on the last page of the eraseblock */
|
||||
#define NAND_BBT_SCANLASTPAGE 0x00008000
|
||||
/* Chip stores bad block marker on BOTH 1st and 6th bytes of OOB */
|
||||
#define NAND_BBT_SCANBYTE1AND6 0x00100000
|
||||
/* The nand_bbt_descr was created dynamicaly and must be freed */
|
||||
#define NAND_BBT_DYNAMICSTRUCT 0x00200000
|
||||
/* The bad block table does not OOB for marker */
|
||||
#define NAND_BBT_NO_OOB 0x00400000
|
||||
#define NAND_BBT_SCANLASTPAGE 0x00010000
|
||||
/*
|
||||
* Use a flash based bad block table. By default, OOB identifier is saved in
|
||||
* OOB area. This option is passed to the default bad block table function.
|
||||
*/
|
||||
#define NAND_BBT_USE_FLASH 0x00020000
|
||||
/*
|
||||
* Do not store flash based bad block table marker in the OOB area; store it
|
||||
* in-band.
|
||||
*/
|
||||
#define NAND_BBT_NO_OOB 0x00040000
|
||||
/*
|
||||
* Do not write new bad block markers to OOB; useful, e.g., when ECC covers
|
||||
* entire spare area. Must be used with NAND_BBT_USE_FLASH.
|
||||
*/
|
||||
#define NAND_BBT_NO_OOB_BBM 0x00080000
|
||||
|
||||
/*
|
||||
* Flag set by nand_create_default_bbt_descr(), marking that the nand_bbt_descr
|
||||
* was allocated dynamicaly and must be freed in nand_release(). Has no meaning
|
||||
* in nand_chip.bbt_options.
|
||||
*/
|
||||
#define NAND_BBT_DYNAMICSTRUCT 0x80000000
|
||||
|
||||
/* The maximum number of blocks to scan for a bbt */
|
||||
#define NAND_BBT_SCAN_MAXBLOCKS 4
|
||||
|
@ -9,7 +9,8 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <div64.h>
|
||||
#include <linux/mtd/mtd-abi.h>
|
||||
#include <mtd/mtd-abi.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
#define MTD_CHAR_MAJOR 90
|
||||
#define MTD_BLOCK_MAJOR 31
|
||||
@ -65,22 +66,6 @@ struct mtd_erase_region_info {
|
||||
unsigned long *lockmap; /* If keeping bitmap of locks */
|
||||
};
|
||||
|
||||
/*
|
||||
* oob operation modes
|
||||
*
|
||||
* MTD_OOB_PLACE: oob data are placed at the given offset
|
||||
* MTD_OOB_AUTO: oob data are automatically placed at the free areas
|
||||
* which are defined by the ecclayout
|
||||
* MTD_OOB_RAW: mode to read raw data+oob in one chunk. The oob data
|
||||
* is inserted into the data. Thats a raw image of the
|
||||
* flash contents.
|
||||
*/
|
||||
typedef enum {
|
||||
MTD_OOB_PLACE,
|
||||
MTD_OOB_AUTO,
|
||||
MTD_OOB_RAW,
|
||||
} mtd_oob_mode_t;
|
||||
|
||||
/**
|
||||
* struct mtd_oob_ops - oob operation operands
|
||||
* @mode: operation mode
|
||||
@ -92,7 +77,7 @@ typedef enum {
|
||||
* @ooblen: number of oob bytes to write/read
|
||||
* @oobretlen: number of oob bytes written/read
|
||||
* @ooboffs: offset of oob data in the oob area (only relevant when
|
||||
* mode = MTD_OOB_PLACE)
|
||||
* mode = MTD_OPS_PLACE_OOB or MTD_OPS_RAW)
|
||||
* @datbuf: data buffer - if NULL only oob data are read/written
|
||||
* @oobbuf: oob data buffer
|
||||
*
|
||||
@ -101,7 +86,7 @@ typedef enum {
|
||||
* OOB area.
|
||||
*/
|
||||
struct mtd_oob_ops {
|
||||
mtd_oob_mode_t mode;
|
||||
unsigned int mode;
|
||||
size_t len;
|
||||
size_t retlen;
|
||||
size_t ooblen;
|
||||
@ -133,13 +118,25 @@ struct mtd_info {
|
||||
u_int32_t oobsize; /* Amount of OOB data per block (e.g. 16) */
|
||||
u_int32_t oobavail; /* Available OOB bytes per block */
|
||||
|
||||
/*
|
||||
* read ops return -EUCLEAN if max number of bitflips corrected on any
|
||||
* one region comprising an ecc step equals or exceeds this value.
|
||||
* Settable by driver, else defaults to ecc_strength. User can override
|
||||
* in sysfs. N.B. The meaning of the -EUCLEAN return code has changed;
|
||||
* see Documentation/ABI/testing/sysfs-class-mtd for more detail.
|
||||
*/
|
||||
unsigned int bitflip_threshold;
|
||||
|
||||
/* Kernel-only stuff starts here. */
|
||||
const char *name;
|
||||
int index;
|
||||
|
||||
/* ecc layout structure pointer - read only ! */
|
||||
/* ECC layout structure pointer - read only! */
|
||||
struct nand_ecclayout *ecclayout;
|
||||
|
||||
/* max number of correctible bit errors per ecc step */
|
||||
unsigned int ecc_strength;
|
||||
|
||||
/* Data for variable erase regions. If numeraseregions is zero,
|
||||
* it means that the whole device has erasesize as given above.
|
||||
*/
|
||||
@ -147,25 +144,17 @@ struct mtd_info {
|
||||
struct mtd_erase_region_info *eraseregions;
|
||||
|
||||
/*
|
||||
* Erase is an asynchronous operation. Device drivers are supposed
|
||||
* to call instr->callback() whenever the operation completes, even
|
||||
* if it completes with a failure.
|
||||
* Callers are supposed to pass a callback function and wait for it
|
||||
* to be called before writing to the block.
|
||||
* Do not call via these pointers, use corresponding mtd_*()
|
||||
* wrappers instead.
|
||||
*/
|
||||
int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
|
||||
|
||||
/* This stuff for eXecute-In-Place */
|
||||
/* phys is optional and may be set to NULL */
|
||||
int (*point) (struct mtd_info *mtd, loff_t from, size_t len,
|
||||
int (*_erase) (struct mtd_info *mtd, struct erase_info *instr);
|
||||
int (*_point) (struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, void **virt, phys_addr_t *phys);
|
||||
|
||||
/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
|
||||
void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
|
||||
|
||||
|
||||
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
|
||||
int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
|
||||
void (*_unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
|
||||
int (*_read) (struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf);
|
||||
int (*_write) (struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf);
|
||||
|
||||
/* In blackbox flight recorder like scenarios we want to make successful
|
||||
writes in interrupt context. panic_write() is only intended to be
|
||||
@ -174,24 +163,35 @@ struct mtd_info {
|
||||
longer, this function can break locks and delay to ensure the write
|
||||
succeeds (but not sleep). */
|
||||
|
||||
int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
|
||||
int (*_panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
|
||||
|
||||
int (*read_oob) (struct mtd_info *mtd, loff_t from,
|
||||
int (*_read_oob) (struct mtd_info *mtd, loff_t from,
|
||||
struct mtd_oob_ops *ops);
|
||||
int (*write_oob) (struct mtd_info *mtd, loff_t to,
|
||||
int (*_write_oob) (struct mtd_info *mtd, loff_t to,
|
||||
struct mtd_oob_ops *ops);
|
||||
|
||||
int (*_get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
|
||||
size_t len);
|
||||
int (*_read_fact_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||
size_t len, size_t *retlen, u_char *buf);
|
||||
int (*_get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
|
||||
size_t len);
|
||||
int (*_read_user_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||
size_t len, size_t *retlen, u_char *buf);
|
||||
int (*_write_user_prot_reg) (struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, u_char *buf);
|
||||
int (*_lock_user_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||
size_t len);
|
||||
void (*_sync) (struct mtd_info *mtd);
|
||||
int (*_lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int (*_unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
|
||||
int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
|
||||
/*
|
||||
* Methods to access the protection register area, present in some
|
||||
* flash devices. The user data is one time programmable but the
|
||||
* factory data is read only.
|
||||
* If the driver is something smart, like UBI, it may need to maintain
|
||||
* its own reference counting. The below functions are only for driver.
|
||||
*/
|
||||
int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
|
||||
int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
|
||||
int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
|
||||
int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
|
||||
int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
|
||||
int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);
|
||||
int (*_get_device) (struct mtd_info *mtd);
|
||||
void (*_put_device) (struct mtd_info *mtd);
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
@ -201,18 +201,6 @@ struct mtd_info {
|
||||
*/
|
||||
int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);
|
||||
#endif
|
||||
|
||||
/* Sync */
|
||||
void (*sync) (struct mtd_info *mtd);
|
||||
|
||||
/* Chip-supported device locking */
|
||||
int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
|
||||
/* Bad block management functions */
|
||||
int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
|
||||
int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
struct notifier_block reboot_notifier; /* default mode before reboot */
|
||||
@ -227,15 +215,59 @@ struct mtd_info {
|
||||
|
||||
struct module *owner;
|
||||
int usecount;
|
||||
|
||||
/* If the driver is something smart, like UBI, it may need to maintain
|
||||
* its own reference counting. The below functions are only for driver.
|
||||
* The driver may register its callbacks. These callbacks are not
|
||||
* supposed to be called by MTD users */
|
||||
int (*get_device) (struct mtd_info *mtd);
|
||||
void (*put_device) (struct mtd_info *mtd);
|
||||
};
|
||||
|
||||
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
|
||||
int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
||||
u_char *buf);
|
||||
int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||
const u_char *buf);
|
||||
int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||
const u_char *buf);
|
||||
|
||||
int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops);
|
||||
|
||||
static inline int mtd_write_oob(struct mtd_info *mtd, loff_t to,
|
||||
struct mtd_oob_ops *ops)
|
||||
{
|
||||
ops->retlen = ops->oobretlen = 0;
|
||||
if (!mtd->_write_oob)
|
||||
return -EOPNOTSUPP;
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
return mtd->_write_oob(mtd, to, ops);
|
||||
}
|
||||
|
||||
int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
||||
size_t len);
|
||||
int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf);
|
||||
int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
||||
size_t len);
|
||||
int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf);
|
||||
int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, u_char *buf);
|
||||
int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len);
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
int mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
|
||||
unsigned long count, loff_t to, size_t *retlen);
|
||||
#endif
|
||||
|
||||
static inline void mtd_sync(struct mtd_info *mtd)
|
||||
{
|
||||
if (mtd->_sync)
|
||||
mtd->_sync(mtd);
|
||||
}
|
||||
|
||||
int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs);
|
||||
int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs);
|
||||
|
||||
static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd)
|
||||
{
|
||||
do_div(sz, mtd->erasesize);
|
||||
@ -247,6 +279,16 @@ static inline uint32_t mtd_mod_by_eb(uint64_t sz, struct mtd_info *mtd)
|
||||
return do_div(sz, mtd->erasesize);
|
||||
}
|
||||
|
||||
static inline int mtd_has_oob(const struct mtd_info *mtd)
|
||||
{
|
||||
return mtd->_read_oob && mtd->_write_oob;
|
||||
}
|
||||
|
||||
static inline int mtd_can_have_bb(const struct mtd_info *mtd)
|
||||
{
|
||||
return !!mtd->_block_isbad;
|
||||
}
|
||||
|
||||
/* Kernel-side ioctl definitions */
|
||||
|
||||
extern int add_mtd_device(struct mtd_info *mtd);
|
||||
@ -269,12 +311,6 @@ struct mtd_notifier {
|
||||
|
||||
extern void register_mtd_user (struct mtd_notifier *new);
|
||||
extern int unregister_mtd_user (struct mtd_notifier *old);
|
||||
|
||||
int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
|
||||
unsigned long count, loff_t to, size_t *retlen);
|
||||
|
||||
int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,
|
||||
unsigned long count, loff_t from, size_t *retlen);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_PARTITIONS
|
||||
@ -296,17 +332,34 @@ static inline void mtd_erase_callback(struct erase_info *instr)
|
||||
#define MTD_DEBUG_LEVEL3 (3) /* Noisy */
|
||||
|
||||
#ifdef CONFIG_MTD_DEBUG
|
||||
#define pr_debug(args...) MTDDEBUG(MTD_DEBUG_LEVEL0, args)
|
||||
#define MTDDEBUG(n, args...) \
|
||||
do { \
|
||||
if (n <= CONFIG_MTD_DEBUG_VERBOSE) \
|
||||
printk(KERN_INFO args); \
|
||||
} while(0)
|
||||
#else /* CONFIG_MTD_DEBUG */
|
||||
#define pr_debug(args...)
|
||||
#define MTDDEBUG(n, args...) \
|
||||
do { \
|
||||
if (0) \
|
||||
printk(KERN_INFO args); \
|
||||
} while(0)
|
||||
#endif /* CONFIG_MTD_DEBUG */
|
||||
#define pr_info(args...) MTDDEBUG(MTD_DEBUG_LEVEL0, args)
|
||||
#define pr_warn(args...) MTDDEBUG(MTD_DEBUG_LEVEL0, args)
|
||||
#define pr_err(args...) MTDDEBUG(MTD_DEBUG_LEVEL0, args)
|
||||
|
||||
static inline int mtd_is_bitflip(int err) {
|
||||
return err == -EUCLEAN;
|
||||
}
|
||||
|
||||
static inline int mtd_is_eccerr(int err) {
|
||||
return err == -EBADMSG;
|
||||
}
|
||||
|
||||
static inline int mtd_is_bitflip_or_eccerr(int err) {
|
||||
return mtd_is_bitflip(err) || mtd_is_eccerr(err);
|
||||
}
|
||||
|
||||
#endif /* __MTD_MTD_H__ */
|
||||
|
@ -46,7 +46,7 @@ extern void nand_wait_ready(struct mtd_info *mtd);
|
||||
* is supported now. If you add a chip with bigger oobsize/page
|
||||
* adjust this accordingly.
|
||||
*/
|
||||
#define NAND_MAX_OOBSIZE 576
|
||||
#define NAND_MAX_OOBSIZE 640
|
||||
#define NAND_MAX_PAGESIZE 8192
|
||||
|
||||
/*
|
||||
@ -82,6 +82,8 @@ extern void nand_wait_ready(struct mtd_info *mtd);
|
||||
#define NAND_CMD_READID 0x90
|
||||
#define NAND_CMD_ERASE2 0xd0
|
||||
#define NAND_CMD_PARAM 0xec
|
||||
#define NAND_CMD_GET_FEATURES 0xee
|
||||
#define NAND_CMD_SET_FEATURES 0xef
|
||||
#define NAND_CMD_RESET 0xff
|
||||
|
||||
#define NAND_CMD_LOCK 0x2a
|
||||
@ -142,7 +144,7 @@ typedef enum {
|
||||
#define NAND_ECC_READ 0
|
||||
/* Reset Hardware ECC for write */
|
||||
#define NAND_ECC_WRITE 1
|
||||
/* Enable Hardware ECC before syndrom is read back from flash */
|
||||
/* Enable Hardware ECC before syndrome is read back from flash */
|
||||
#define NAND_ECC_READSYN 2
|
||||
|
||||
/* Bit mask for flags passed to do_nand_read_ecc */
|
||||
@ -153,9 +155,7 @@ typedef enum {
|
||||
* Option constants for bizarre disfunctionality and real
|
||||
* features.
|
||||
*/
|
||||
/* Chip can not auto increment pages */
|
||||
#define NAND_NO_AUTOINCR 0x00000001
|
||||
/* Buswitdh is 16 bit */
|
||||
/* Buswidth is 16 bit */
|
||||
#define NAND_BUSWIDTH_16 0x00000002
|
||||
/* Device supports partial programming without padding */
|
||||
#define NAND_NO_PADDING 0x00000004
|
||||
@ -179,12 +179,6 @@ typedef enum {
|
||||
* This happens with the Renesas AG-AND chips, possibly others.
|
||||
*/
|
||||
#define BBT_AUTO_REFRESH 0x00000080
|
||||
/*
|
||||
* Chip does not require ready check on read. true
|
||||
* for all large page devices, as they do not support
|
||||
* autoincrement.
|
||||
*/
|
||||
#define NAND_NO_READRDY 0x00000100
|
||||
/* Chip does not allow subpage writes */
|
||||
#define NAND_NO_SUBPAGE_WRITE 0x00000200
|
||||
|
||||
@ -202,34 +196,21 @@ typedef enum {
|
||||
(NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)
|
||||
|
||||
/* Macros to identify the above */
|
||||
#define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR))
|
||||
#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING))
|
||||
#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
|
||||
#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
|
||||
#define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ))
|
||||
|
||||
/* Non chip related options */
|
||||
/*
|
||||
* Use a flash based bad block table. OOB identifier is saved in OOB area.
|
||||
* This option is passed to the default bad block table function.
|
||||
*/
|
||||
#define NAND_USE_FLASH_BBT 0x00010000
|
||||
/* This option skips the bbt scan during initialization. */
|
||||
#define NAND_SKIP_BBTSCAN 0x00020000
|
||||
#define NAND_SKIP_BBTSCAN 0x00010000
|
||||
/*
|
||||
* This option is defined if the board driver allocates its own buffers
|
||||
* (e.g. because it needs them DMA-coherent).
|
||||
*/
|
||||
#define NAND_OWN_BUFFERS 0x00040000
|
||||
#define NAND_OWN_BUFFERS 0x00020000
|
||||
/* Chip may not exist, so silence any errors in scan */
|
||||
#define NAND_SCAN_SILENT_NODEV 0x00080000
|
||||
/*
|
||||
* If passed additionally to NAND_USE_FLASH_BBT then BBT code will not touch
|
||||
* the OOB area.
|
||||
*/
|
||||
#define NAND_USE_FLASH_BBT_NO_OOB 0x00800000
|
||||
/* Create an empty BBT with no vendor information if the BBT is available */
|
||||
#define NAND_CREATE_EMPTY_BBT 0x01000000
|
||||
#define NAND_SCAN_SILENT_NODEV 0x00040000
|
||||
|
||||
/* Options set by nand scan */
|
||||
/* bbt has already been read */
|
||||
@ -244,6 +225,21 @@ typedef enum {
|
||||
/* Keep gcc happy */
|
||||
struct nand_chip;
|
||||
|
||||
/* ONFI timing mode, used in both asynchronous and synchronous mode */
|
||||
#define ONFI_TIMING_MODE_0 (1 << 0)
|
||||
#define ONFI_TIMING_MODE_1 (1 << 1)
|
||||
#define ONFI_TIMING_MODE_2 (1 << 2)
|
||||
#define ONFI_TIMING_MODE_3 (1 << 3)
|
||||
#define ONFI_TIMING_MODE_4 (1 << 4)
|
||||
#define ONFI_TIMING_MODE_5 (1 << 5)
|
||||
#define ONFI_TIMING_MODE_UNKNOWN (1 << 6)
|
||||
|
||||
/* ONFI feature address */
|
||||
#define ONFI_FEATURE_ADDR_TIMING_MODE 0x1
|
||||
|
||||
/* ONFI subfeature parameters length */
|
||||
#define ONFI_SUBFEATURE_PARAM_LEN 4
|
||||
|
||||
struct nand_onfi_params {
|
||||
/* rev info and features block */
|
||||
/* 'O' 'N' 'F' 'I' */
|
||||
@ -326,27 +322,32 @@ struct nand_hw_control {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nand_ecc_ctrl - Control structure for ecc
|
||||
* @mode: ecc mode
|
||||
* @steps: number of ecc steps per page
|
||||
* @size: data bytes per ecc step
|
||||
* @bytes: ecc bytes per step
|
||||
* @total: total number of ecc bytes per page
|
||||
* @prepad: padding information for syndrome based ecc generators
|
||||
* @postpad: padding information for syndrome based ecc generators
|
||||
* struct nand_ecc_ctrl - Control structure for ECC
|
||||
* @mode: ECC mode
|
||||
* @steps: number of ECC steps per page
|
||||
* @size: data bytes per ECC step
|
||||
* @bytes: ECC bytes per step
|
||||
* @strength: max number of correctible bits per ECC step
|
||||
* @total: total number of ECC bytes per page
|
||||
* @prepad: padding information for syndrome based ECC generators
|
||||
* @postpad: padding information for syndrome based ECC generators
|
||||
* @layout: ECC layout control struct pointer
|
||||
* @priv: pointer to private ecc control data
|
||||
* @hwctl: function to control hardware ecc generator. Must only
|
||||
* @priv: pointer to private ECC control data
|
||||
* @hwctl: function to control hardware ECC generator. Must only
|
||||
* be provided if an hardware ECC is available
|
||||
* @calculate: function for ecc calculation or readback from ecc hardware
|
||||
* @correct: function for ecc correction, matching to ecc generator (sw/hw)
|
||||
* @calculate: function for ECC calculation or readback from ECC hardware
|
||||
* @correct: function for ECC correction, matching to ECC generator (sw/hw)
|
||||
* @read_page_raw: function to read a raw page without ECC
|
||||
* @write_page_raw: function to write a raw page without ECC
|
||||
* @read_page: function to read a page according to the ecc generator
|
||||
* requirements.
|
||||
* @read_subpage: function to read parts of the page covered by ECC.
|
||||
* @write_page: function to write a page according to the ecc generator
|
||||
* @read_page: function to read a page according to the ECC generator
|
||||
* requirements; returns maximum number of bitflips corrected in
|
||||
* any single ECC step, 0 if bitflips uncorrectable, -EIO hw error
|
||||
* @read_subpage: function to read parts of the page covered by ECC;
|
||||
* returns same as read_page()
|
||||
* @write_page: function to write a page according to the ECC generator
|
||||
* requirements.
|
||||
* @write_oob_raw: function to write chip OOB data without ECC
|
||||
* @read_oob_raw: function to read chip OOB data without ECC
|
||||
* @read_oob: function to read chip OOB data
|
||||
* @write_oob: function to write chip OOB data
|
||||
*/
|
||||
@ -356,6 +357,7 @@ struct nand_ecc_ctrl {
|
||||
int size;
|
||||
int bytes;
|
||||
int total;
|
||||
int strength;
|
||||
int prepad;
|
||||
int postpad;
|
||||
struct nand_ecclayout *layout;
|
||||
@ -366,25 +368,28 @@ struct nand_ecc_ctrl {
|
||||
int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc,
|
||||
uint8_t *calc_ecc);
|
||||
int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int page);
|
||||
void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf);
|
||||
uint8_t *buf, int oob_required, int page);
|
||||
int (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required);
|
||||
int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int page);
|
||||
uint8_t *buf, int oob_required, int page);
|
||||
int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint32_t offs, uint32_t len, uint8_t *buf);
|
||||
void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf);
|
||||
int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page,
|
||||
int sndcmd);
|
||||
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required);
|
||||
int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page);
|
||||
int (*read_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page);
|
||||
int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page);
|
||||
int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nand_buffers - buffer structure for read/write
|
||||
* @ecccalc: buffer for calculated ecc
|
||||
* @ecccode: buffer for ecc read from flash
|
||||
* @ecccalc: buffer for calculated ECC
|
||||
* @ecccode: buffer for ECC read from flash
|
||||
* @databuf: buffer for data - dynamically sized
|
||||
*
|
||||
* Do not change the order of buffers. databuf and oobrbuf must be in
|
||||
@ -418,7 +423,7 @@ struct nand_buffers {
|
||||
* mtd->oobsize, mtd->writesize and so on.
|
||||
* @id_data contains the 8 bytes values of NAND_CMD_READID.
|
||||
* Return with the bus width.
|
||||
* @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing
|
||||
* @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accessing
|
||||
* device ready/busy line. If set to NULL no access to
|
||||
* ready/busy is available and the ready/busy information
|
||||
* is read from the chip status register.
|
||||
@ -426,17 +431,17 @@ struct nand_buffers {
|
||||
* commands to the chip.
|
||||
* @waitfunc: [REPLACEABLE] hardwarespecific function for wait on
|
||||
* ready.
|
||||
* @ecc: [BOARDSPECIFIC] ecc control ctructure
|
||||
* @ecc: [BOARDSPECIFIC] ECC control structure
|
||||
* @buffers: buffer structure for read/write
|
||||
* @hwcontrol: platform-specific hardware control structure
|
||||
* @ops: oob operation operands
|
||||
* @erase_cmd: [INTERN] erase command write function, selectable due
|
||||
* to AND support.
|
||||
* @scan_bbt: [REPLACEABLE] function to scan bad block table
|
||||
* @chip_delay: [BOARDSPECIFIC] chip dependent delay for transferring
|
||||
* data from array to read regs (tR).
|
||||
* @state: [INTERN] the current state of the NAND device
|
||||
* @oob_poi: poison value buffer
|
||||
* @oob_poi: "poison value buffer," used for laying out OOB data
|
||||
* before writing
|
||||
* @page_shift: [INTERN] number of address bits in a page (column
|
||||
* address bits).
|
||||
* @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock
|
||||
@ -445,10 +450,14 @@ struct nand_buffers {
|
||||
* @options: [BOARDSPECIFIC] various chip options. They can partly
|
||||
* be set to inform nand_scan about special functionality.
|
||||
* See the defines for further explanation.
|
||||
* @bbt_options: [INTERN] bad block specific options. All options used
|
||||
* here must come from bbm.h. By default, these options
|
||||
* will be copied to the appropriate nand_bbt_descr's.
|
||||
* @badblockpos: [INTERN] position of the bad block marker in the oob
|
||||
* area.
|
||||
* @badblockbits: [INTERN] number of bits to left-shift the bad block
|
||||
* number
|
||||
* @badblockbits: [INTERN] minimum number of set bits in a good block's
|
||||
* bad block marker position; i.e., BBM == 11110111b is
|
||||
* not bad when badblockbits == 7
|
||||
* @cellinfo: [INTERN] MLC/multichip data from chip ident
|
||||
* @numchips: [INTERN] number of physical chips
|
||||
* @chipsize: [INTERN] the size of one chip for multichip arrays
|
||||
@ -460,7 +469,9 @@ struct nand_buffers {
|
||||
* non 0 if ONFI supported.
|
||||
* @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is
|
||||
* supported, 0 otherwise.
|
||||
* @ecclayout: [REPLACEABLE] the default ecc placement scheme
|
||||
* @onfi_set_features [REPLACEABLE] set the features for ONFI nand
|
||||
* @onfi_get_features [REPLACEABLE] get the features for ONFI nand
|
||||
* @ecclayout: [REPLACEABLE] the default ECC placement scheme
|
||||
* @bbt: [INTERN] bad block table pointer
|
||||
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash
|
||||
* lookup.
|
||||
@ -468,9 +479,9 @@ struct nand_buffers {
|
||||
* @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial
|
||||
* bad block scan.
|
||||
* @controller: [REPLACEABLE] a pointer to a hardware controller
|
||||
* structure which is shared among multiple independend
|
||||
* structure which is shared among multiple independent
|
||||
* devices.
|
||||
* @priv: [OPTIONAL] pointer to private chip date
|
||||
* @priv: [OPTIONAL] pointer to private chip data
|
||||
* @errstat: [OPTIONAL] hardware specific function to perform
|
||||
* additional error status checks (determine if errors are
|
||||
* correctable).
|
||||
@ -501,10 +512,16 @@ struct nand_chip {
|
||||
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
|
||||
int status, int page);
|
||||
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int page, int cached, int raw);
|
||||
const uint8_t *buf, int oob_required, int page,
|
||||
int cached, int raw);
|
||||
int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int feature_addr, uint8_t *subfeature_para);
|
||||
int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int feature_addr, uint8_t *subfeature_para);
|
||||
|
||||
int chip_delay;
|
||||
unsigned int options;
|
||||
unsigned int bbt_options;
|
||||
|
||||
int page_shift;
|
||||
int phys_erase_shift;
|
||||
@ -534,8 +551,6 @@ struct nand_chip {
|
||||
struct nand_buffers *buffers;
|
||||
struct nand_hw_control hwcontrol;
|
||||
|
||||
struct mtd_oob_ops ops;
|
||||
|
||||
uint8_t *bbt;
|
||||
struct nand_bbt_descr *bbt_td;
|
||||
struct nand_bbt_descr *bbt_md;
|
||||
@ -557,6 +572,8 @@ struct nand_chip {
|
||||
#define NAND_MFR_HYNIX 0xad
|
||||
#define NAND_MFR_MICRON 0x2c
|
||||
#define NAND_MFR_AMD 0x01
|
||||
#define NAND_MFR_MACRONIX 0xc2
|
||||
#define NAND_MFR_EON 0x92
|
||||
|
||||
/**
|
||||
* struct nand_flash_dev - NAND Flash Device ID Structure
|
||||
@ -615,9 +632,9 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
* @partitions: mtd partition list
|
||||
* @chip_delay: R/B delay value in us
|
||||
* @options: Option flags, e.g. 16bit buswidth
|
||||
* @ecclayout: ecc layout info structure
|
||||
* @bbt_options: BBT option flags, e.g. NAND_BBT_USE_FLASH
|
||||
* @ecclayout: ECC layout info structure
|
||||
* @part_probe_types: NULL-terminated array of probe types
|
||||
* @priv: hardware controller specific settings
|
||||
*/
|
||||
struct platform_nand_chip {
|
||||
int nr_chips;
|
||||
@ -627,8 +644,8 @@ struct platform_nand_chip {
|
||||
struct nand_ecclayout *ecclayout;
|
||||
int chip_delay;
|
||||
unsigned int options;
|
||||
unsigned int bbt_options;
|
||||
const char **part_probe_types;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/* Keep gcc happy */
|
||||
@ -650,6 +667,7 @@ struct platform_nand_ctrl {
|
||||
int (*dev_ready)(struct mtd_info *mtd);
|
||||
void (*select_chip)(struct mtd_info *mtd, int chip);
|
||||
void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
|
||||
unsigned char (*read_byte)(struct mtd_info *mtd);
|
||||
void *priv;
|
||||
};
|
||||
|
||||
@ -679,4 +697,23 @@ void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len);
|
||||
void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len);
|
||||
uint8_t nand_read_byte(struct mtd_info *mtd);
|
||||
|
||||
/* return the supported asynchronous timing mode. */
|
||||
|
||||
#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
|
||||
static inline int onfi_get_async_timing_mode(struct nand_chip *chip)
|
||||
{
|
||||
if (!chip->onfi_version)
|
||||
return ONFI_TIMING_MODE_UNKNOWN;
|
||||
return le16_to_cpu(chip->onfi_params.async_timing_mode);
|
||||
}
|
||||
|
||||
/* return the supported synchronous timing mode. */
|
||||
static inline int onfi_get_sync_timing_mode(struct nand_chip *chip)
|
||||
{
|
||||
if (!chip->onfi_version)
|
||||
return ONFI_TIMING_MODE_UNKNOWN;
|
||||
return le16_to_cpu(chip->onfi_params.src_sync_timing_mode);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LINUX_MTD_NAND_H */
|
||||
|
@ -85,6 +85,9 @@ extern int memcmp(const void *,const void *,__kernel_size_t);
|
||||
#ifndef __HAVE_ARCH_MEMCHR
|
||||
extern void * memchr(const void *,int,__kernel_size_t);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_MEMCHR_INV
|
||||
void *memchr_inv(const void *, int, size_t);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -24,6 +24,25 @@ struct mtd_oob_buf {
|
||||
unsigned char __user *ptr;
|
||||
};
|
||||
|
||||
/*
|
||||
* MTD operation modes
|
||||
*
|
||||
* @MTD_OPS_PLACE_OOB: OOB data are placed at the given offset (default)
|
||||
* @MTD_OPS_AUTO_OOB: OOB data are automatically placed at the free areas
|
||||
* which are defined by the internal ecclayout
|
||||
* @MTD_OPS_RAW: data are transferred as-is, with no error correction;
|
||||
* this mode implies %MTD_OPS_PLACE_OOB
|
||||
*
|
||||
* These modes can be passed to ioctl(MEMWRITE) and are also used internally.
|
||||
* See notes on "MTD file modes" for discussion on %MTD_OPS_RAW vs.
|
||||
* %MTD_FILE_MODE_RAW.
|
||||
*/
|
||||
enum {
|
||||
MTD_OPS_PLACE_OOB = 0,
|
||||
MTD_OPS_AUTO_OOB = 1,
|
||||
MTD_OPS_RAW = 2,
|
||||
};
|
||||
|
||||
#define MTD_ABSENT 0
|
||||
#define MTD_RAM 1
|
||||
#define MTD_ROM 2
|
||||
@ -82,24 +101,42 @@ struct otp_info {
|
||||
uint32_t locked;
|
||||
};
|
||||
|
||||
/* Get basic MTD characteristics info (better to use sysfs) */
|
||||
#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
|
||||
/* Erase segment of MTD */
|
||||
#define MEMERASE _IOW('M', 2, struct erase_info_user)
|
||||
/* Write out-of-band data from MTD */
|
||||
#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf)
|
||||
/* Read out-of-band data from MTD */
|
||||
#define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf)
|
||||
/* Lock a chip (for MTD that supports it) */
|
||||
#define MEMLOCK _IOW('M', 5, struct erase_info_user)
|
||||
/* Unlock a chip (for MTD that supports it) */
|
||||
#define MEMUNLOCK _IOW('M', 6, struct erase_info_user)
|
||||
/* Get the number of different erase regions */
|
||||
#define MEMGETREGIONCOUNT _IOR('M', 7, int)
|
||||
/* Get information about the erase region for a specific index */
|
||||
#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user)
|
||||
/* Get info about OOB modes (e.g., RAW, PLACE, AUTO) - legacy interface */
|
||||
#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo)
|
||||
#define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo)
|
||||
/* Check if an eraseblock is bad */
|
||||
#define MEMGETBADBLOCK _IOW('M', 11, loff_t)
|
||||
/* Mark an eraseblock as bad */
|
||||
#define MEMSETBADBLOCK _IOW('M', 12, loff_t)
|
||||
/* Set OTP (One-Time Programmable) mode (factory vs. user) */
|
||||
#define OTPSELECT _IOR('M', 13, int)
|
||||
/* Get number of OTP (One-Time Programmable) regions */
|
||||
#define OTPGETREGIONCOUNT _IOW('M', 14, int)
|
||||
/* Get all OTP (One-Time Programmable) info about MTD */
|
||||
#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info)
|
||||
/* Lock a given range of user data (must be in mode %MTD_FILE_MODE_OTP_USER) */
|
||||
#define OTPLOCK _IOR('M', 16, struct otp_info)
|
||||
/* Get ECC layout (deprecated) */
|
||||
#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout)
|
||||
/* Get statistics about corrected/uncorrected errors */
|
||||
#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
|
||||
/* Set MTD mode on a per-file-descriptor basis (see "MTD file modes") */
|
||||
#define MTDFILEMODE _IO('M', 19)
|
||||
|
||||
/*
|
||||
@ -146,7 +183,21 @@ struct mtd_ecc_stats {
|
||||
};
|
||||
|
||||
/*
|
||||
* Read/write file modes for access to MTD
|
||||
* MTD file modes - for read/write access to MTD
|
||||
*
|
||||
* @MTD_FILE_MODE_NORMAL: OTP disabled, ECC enabled
|
||||
* @MTD_FILE_MODE_OTP_FACTORY: OTP enabled in factory mode
|
||||
* @MTD_FILE_MODE_OTP_USER: OTP enabled in user mode
|
||||
* @MTD_FILE_MODE_RAW: OTP disabled, ECC disabled
|
||||
*
|
||||
* These modes can be set via ioctl(MTDFILEMODE). The mode mode will be retained
|
||||
* separately for each open file descriptor.
|
||||
*
|
||||
* Note: %MTD_FILE_MODE_RAW provides the same functionality as %MTD_OPS_RAW -
|
||||
* raw access to the flash, without error correction or autoplacement schemes.
|
||||
* Wherever possible, the MTD_OPS_* mode will override the MTD_FILE_MODE_* mode
|
||||
* (e.g., when using ioctl(MEMWRITE)), but in some cases, the MTD_FILE_MODE is
|
||||
* used out of necessity (e.g., `write()', ioctl(MEMWRITEOOB64)).
|
||||
*/
|
||||
enum mtd_file_modes {
|
||||
MTD_MODE_NORMAL = MTD_OTP_OFF,
|
@ -31,7 +31,8 @@
|
||||
* at the same time, so do it here. When all drivers are
|
||||
* converted, this will go away.
|
||||
*/
|
||||
#if defined(CONFIG_NAND_FSL_ELBC) || defined(CONFIG_NAND_ATMEL)
|
||||
#if defined(CONFIG_NAND_FSL_ELBC) || defined(CONFIG_NAND_ATMEL)\
|
||||
|| defined(CONFIG_NAND_FSL_IFC)
|
||||
#define CONFIG_SYS_NAND_SELF_INIT
|
||||
#endif
|
||||
|
||||
@ -55,17 +56,17 @@ extern nand_info_t nand_info[];
|
||||
|
||||
static inline int nand_read(nand_info_t *info, loff_t ofs, size_t *len, u_char *buf)
|
||||
{
|
||||
return info->read(info, ofs, *len, (size_t *)len, buf);
|
||||
return mtd_read(info, ofs, *len, (size_t *)len, buf);
|
||||
}
|
||||
|
||||
static inline int nand_write(nand_info_t *info, loff_t ofs, size_t *len, u_char *buf)
|
||||
{
|
||||
return info->write(info, ofs, *len, (size_t *)len, buf);
|
||||
return mtd_write(info, ofs, *len, (size_t *)len, buf);
|
||||
}
|
||||
|
||||
static inline int nand_block_isbad(nand_info_t *info, loff_t ofs)
|
||||
{
|
||||
return info->block_isbad(info, ofs);
|
||||
return mtd_block_isbad(info, ofs);
|
||||
}
|
||||
|
||||
static inline int nand_erase(nand_info_t *info, loff_t off, size_t size)
|
||||
@ -77,7 +78,7 @@ static inline int nand_erase(nand_info_t *info, loff_t off, size_t size)
|
||||
instr.len = size;
|
||||
instr.callback = 0;
|
||||
|
||||
return info->erase(info, &instr);
|
||||
return mtd_erase(info, &instr);
|
||||
}
|
||||
|
||||
|
||||
|
59
lib/string.c
59
lib/string.c
@ -617,3 +617,62 @@ void *memchr(const void *s, int c, size_t n)
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_MEMCHR_INV
|
||||
static void *check_bytes8(const u8 *start, u8 value, unsigned int bytes)
|
||||
{
|
||||
while (bytes) {
|
||||
if (*start != value)
|
||||
return (void *)start;
|
||||
start++;
|
||||
bytes--;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/**
|
||||
* memchr_inv - Find an unmatching character in an area of memory.
|
||||
* @start: The memory area
|
||||
* @c: Find a character other than c
|
||||
* @bytes: The size of the area.
|
||||
*
|
||||
* returns the address of the first character other than @c, or %NULL
|
||||
* if the whole buffer contains just @c.
|
||||
*/
|
||||
void *memchr_inv(const void *start, int c, size_t bytes)
|
||||
{
|
||||
u8 value = c;
|
||||
u64 value64;
|
||||
unsigned int words, prefix;
|
||||
|
||||
if (bytes <= 16)
|
||||
return check_bytes8(start, value, bytes);
|
||||
|
||||
value64 = value;
|
||||
value64 |= value64 << 8;
|
||||
value64 |= value64 << 16;
|
||||
value64 |= value64 << 32;
|
||||
|
||||
prefix = (unsigned long)start % 8;
|
||||
if (prefix) {
|
||||
u8 *r;
|
||||
|
||||
prefix = 8 - prefix;
|
||||
r = check_bytes8(start, value, prefix);
|
||||
if (r)
|
||||
return r;
|
||||
start += prefix;
|
||||
bytes -= prefix;
|
||||
}
|
||||
|
||||
words = bytes / 8;
|
||||
|
||||
while (words) {
|
||||
if (*(u64 *)start != value64)
|
||||
return check_bytes8(start, value, 8);
|
||||
start += 8;
|
||||
words--;
|
||||
}
|
||||
|
||||
return check_bytes8(start, value, bytes % 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user