From 628bee6593107c466e28462f58c5fd5cd4163c7c Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Fri, 12 May 2006 17:02:24 +0300 Subject: OneNAND: Add touch_softlock_watchdog() Signed-off-by: Kyungmin Park --- drivers/mtd/onenand/onenand_base.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mtd/onenand/onenand_base.c') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index a53a73fc2a5..d6c13f7ae5a 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -301,6 +301,7 @@ static int onenand_wait(struct mtd_info *mtd, int state) if (state != FL_READING) cond_resched(); + touch_softlockup_watchdog(); } /* To get correct interrupt status in timeout case */ interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); -- cgit v1.2.2 From 9c01f87db183403a4f603fe5180c57b82b54b4a1 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Fri, 12 May 2006 17:02:31 +0300 Subject: OneNAND: handle byte access on BufferRAM Signed-off-by: Kyungmin Park --- drivers/mtd/onenand/onenand_base.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'drivers/mtd/onenand/onenand_base.c') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index d6c13f7ae5a..1439c9fa1d2 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -373,6 +373,17 @@ static int onenand_read_bufferram(struct mtd_info *mtd, int area, bufferram += onenand_bufferram_offset(mtd, area); + if (ONENAND_CHECK_BYTE_ACCESS(count)) { + unsigned short word; + + /* Align with word(16-bit) size */ + count--; + + /* Read word and save byte */ + word = this->read_word(bufferram + offset + count); + buffer[count] = (word & 0xff); + } + memcpy(buffer, bufferram + offset, count); return 0; @@ -400,6 +411,17 @@ static int onenand_sync_read_bufferram(struct mtd_info *mtd, int area, this->mmcontrol(mtd, ONENAND_SYS_CFG1_SYNC_READ); + if (ONENAND_CHECK_BYTE_ACCESS(count)) { + unsigned short word; + + /* Align with word(16-bit) size */ + count--; + + /* Read word and save byte */ + word = this->read_word(bufferram + offset + count); + buffer[count] = (word & 0xff); + } + memcpy(buffer, bufferram + offset, count); this->mmcontrol(mtd, 0); @@ -427,6 +449,22 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area, bufferram += onenand_bufferram_offset(mtd, area); + if (ONENAND_CHECK_BYTE_ACCESS(count)) { + unsigned short word; + int byte_offset; + + /* Align with word(16-bit) size */ + count--; + + /* Calculate byte access offset */ + byte_offset = offset + count; + + /* Read word and save byte */ + word = this->read_word(bufferram + byte_offset); + word = (word & ~0xff) | buffer[count]; + this->write_word(word, bufferram + byte_offset); + } + memcpy(bufferram + offset, buffer, count); return 0; -- cgit v1.2.2 From d9777f1c42bffff0d21cd029a2415776aa874e96 Mon Sep 17 00:00:00 2001 From: Jarkko Lavinen Date: Fri, 12 May 2006 17:02:35 +0300 Subject: OneNand: Fix free byte positions. Some free byte positions at onenand_oob_64 were wrong. This was also reported by Christian Lehne. 3 byte slots are at 2+16*i and 2 byte slots at 14+16*i. Signed-off-by: Jarkko Lavinen --- drivers/mtd/onenand/onenand_base.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mtd/onenand/onenand_base.c') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 1439c9fa1d2..b6a73b72f60 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -34,7 +34,8 @@ static struct nand_oobinfo onenand_oob_64 = { }, .oobfree = { {2, 3}, {14, 2}, {18, 3}, {30, 2}, - {24, 3}, {46, 2}, {40, 3}, {62, 2} } + {34, 3}, {46, 2}, {50, 3}, {62, 2} + } }; /** -- cgit v1.2.2 From 8e6ec69059ba0eecbb2226d3d9e45c6efe6fb82b Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Fri, 12 May 2006 17:02:41 +0300 Subject: OneNAND: Add write_oob verify function Signed-off-by: Jarkko Lavinen --- drivers/mtd/onenand/onenand_base.c | 47 ++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) (limited to 'drivers/mtd/onenand/onenand_base.c') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index b6a73b72f60..e342ba04118 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -758,6 +758,36 @@ out: } #ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE +/** + * onenand_verify_oob - [GENERIC] verify the oob contents after a write + * @param mtd MTD device structure + * @param buf the databuffer to verify + * @param to offset to read from + * @param len number of bytes to read and compare + * + */ +static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to, int len) +{ + struct onenand_chip *this = mtd->priv; + char *readp = this->page_buf; + int column = to & (mtd->oobsize - 1); + int status, i; + + this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); + onenand_update_bufferram(mtd, to, 0); + status = this->wait(mtd, FL_READING); + if (status) + return status; + + this->read_bufferram(mtd, ONENAND_SPARERAM, readp, column, len); + + for(i = 0; i < len; i++) + if (buf[i] != 0xFF && buf[i] != readp[i]) + return -EBADMSG; + + return 0; +} + /** * onenand_verify_page - [GENERIC] verify the chip contents after a write * @param mtd MTD device structure @@ -790,6 +820,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) } #else #define onenand_verify_page(...) (0) +#define onenand_verify_oob(...) (0) #endif #define NOTALIGNED(x) ((x & (mtd->oobblock - 1)) != 0) @@ -909,7 +940,7 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { struct onenand_chip *this = mtd->priv; - int column, status; + int column, ret = 0; int written = 0; DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); @@ -941,9 +972,17 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, onenand_update_bufferram(mtd, to, 0); - status = this->wait(mtd, FL_WRITING); - if (status) + ret = this->wait(mtd, FL_WRITING); + if (ret) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: write filaed %d\n", ret); + goto out; + } + + ret = onenand_verify_oob(mtd, buf, to, thislen); + if (ret) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: verify failed %d\n", ret); goto out; + } written += thislen; @@ -960,7 +999,7 @@ out: *retlen = written; - return 0; + return ret; } /** -- cgit v1.2.2 From 34c1060959b61a5bb2e97a88411446028cebfa7c Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Fri, 12 May 2006 17:02:46 +0300 Subject: OneNAND: Write oob area with aligned size, mtd->oobsize There's some problem with write oob in serveral platform. So we write oob with oobsize aligned (16bytes) instead of 3 bytes (from {2, 3}) Signed-off-by: Kyungmin Park --- drivers/mtd/onenand/onenand_base.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/mtd/onenand/onenand_base.c') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index e342ba04118..6b950ab8ea8 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -965,8 +965,11 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize); - this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); - this->write_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); + /* We send data to spare ram with oobsize + * to prevent byte access */ + memset(this->page_buf, 0xff, mtd->oobsize); + memcpy(this->page_buf + column, buf, thislen); + this->write_bufferram(mtd, ONENAND_SPARERAM, this->page_buf, 0, mtd->oobsize); this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); -- cgit v1.2.2 From 3cecf69ecde22199699c4f0e609dfed2a487b674 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Fri, 12 May 2006 17:02:51 +0300 Subject: OneNAND: Handle erase correctly in Double Density Package (DDP) There's erase bug in DDP. We need to add DDP select in erase Signed-off-by: Kyungmin Park --- drivers/mtd/onenand/onenand_base.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/mtd/onenand/onenand_base.c') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 6b950ab8ea8..7c7dc0ae5a1 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -234,6 +234,12 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le /* Write 'DFS, FBA' of Flash */ value = onenand_block_address(this, block); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); + + if (cmd == ONENAND_CMD_ERASE) { + /* Select DataRAM for DDP */ + value = onenand_bufferram_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); + } } if (page != -1) { -- cgit v1.2.2 From 493c646077ef0b8668ed71b8057f81cb7454af87 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Fri, 12 May 2006 17:03:07 +0300 Subject: OneNAND: One-Time Programmable (OTP) support One Block of the NAND Flash Array memory is reserved as a One-Time Programmable Block memory area. Also, 1st Block of NAND Flash Array can be used as OTP. The OTP block can be read, programmed and locked using the same operations as any other NAND Flash Array memory block. OTP block cannot be erased. OTP block is fully-guaranteed to be a valid block. Signed-off-by: Kyungmin Park --- drivers/mtd/onenand/onenand_base.c | 313 ++++++++++++++++++++++++++++++++++++- 1 file changed, 310 insertions(+), 3 deletions(-) (limited to 'drivers/mtd/onenand/onenand_base.c') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 7c7dc0ae5a1..163c8113544 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -191,7 +191,7 @@ static int onenand_buffer_address(int dataram1, int sectors, int count) static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len) { struct onenand_chip *this = mtd->priv; - int value, readcmd = 0; + int value, readcmd = 0, block_cmd = 0; int block, page; /* Now we use page size operation */ int sectors = 4, count = 4; @@ -207,6 +207,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le case ONENAND_CMD_ERASE: case ONENAND_CMD_BUFFERRAM: + case ONENAND_CMD_OTP_ACCESS: + block_cmd = 1; block = (int) (addr >> this->erase_shift); page = -1; break; @@ -235,7 +237,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le value = onenand_block_address(this, block); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); - if (cmd == ONENAND_CMD_ERASE) { + if (cmd == block_cmd) { /* Select DataRAM for DDP */ value = onenand_bufferram_address(this, block); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); @@ -1412,6 +1414,304 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) return 0; } +#ifdef CONFIG_MTD_ONENAND_OTP + +/* Interal OTP operation */ +typedef int (*otp_op_t)(struct mtd_info *mtd, loff_t form, size_t len, + size_t *retlen, u_char *buf); + +/** + * do_otp_read - [DEFAULT] Read OTP block area + * @param mtd MTD device structure + * @param from The offset to read + * @param len number of bytes to read + * @param retlen pointer to variable to store the number of readbytes + * @param buf the databuffer to put/get data + * + * Read OTP block area. + */ +static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct onenand_chip *this = mtd->priv; + int ret; + + /* Enter OTP access mode */ + this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); + this->wait(mtd, FL_OTPING); + + ret = mtd->read(mtd, from, len, retlen, buf); + + /* Exit OTP access mode */ + this->command(mtd, ONENAND_CMD_RESET, 0, 0); + this->wait(mtd, FL_RESETING); + + return ret; +} + +/** + * do_otp_write - [DEFAULT] Write OTP block area + * @param mtd MTD device structure + * @param from The offset to write + * @param len number of bytes to write + * @param retlen pointer to variable to store the number of write bytes + * @param buf the databuffer to put/get data + * + * Write OTP block area. + */ +static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct onenand_chip *this = mtd->priv; + unsigned char *pbuf = buf; + int ret; + + /* Force buffer page aligned */ + if (len < mtd->oobblock) { + memcpy(this->page_buf, buf, len); + memset(this->page_buf + len, 0xff, mtd->oobblock - len); + pbuf = this->page_buf; + len = mtd->oobblock; + } + + /* Enter OTP access mode */ + this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); + this->wait(mtd, FL_OTPING); + + ret = mtd->write(mtd, from, len, retlen, pbuf); + + /* Exit OTP access mode */ + this->command(mtd, ONENAND_CMD_RESET, 0, 0); + this->wait(mtd, FL_RESETING); + + return ret; +} + +/** + * do_otp_lock - [DEFAULT] Lock OTP block area + * @param mtd MTD device structure + * @param from The offset to lock + * @param len number of bytes to lock + * @param retlen pointer to variable to store the number of lock bytes + * @param buf the databuffer to put/get data + * + * Lock OTP block area. + */ +static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct onenand_chip *this = mtd->priv; + int ret; + + /* Enter OTP access mode */ + this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); + this->wait(mtd, FL_OTPING); + + ret = mtd->write_oob(mtd, from, len, retlen, buf); + + /* Exit OTP access mode */ + this->command(mtd, ONENAND_CMD_RESET, 0, 0); + this->wait(mtd, FL_RESETING); + + return ret; +} + +/** + * onenand_otp_walk - [DEFAULT] Handle OTP operation + * @param mtd MTD device structure + * @param from The offset to read/write + * @param len number of bytes to read/write + * @param retlen pointer to variable to store the number of read bytes + * @param buf the databuffer to put/get data + * @param action do given action + * @param mode specify user and factory + * + * Handle OTP operation. + */ +static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf, + otp_op_t action, int mode) +{ + struct onenand_chip *this = mtd->priv; + int otp_pages; + int density; + int ret = 0; + + *retlen = 0; + + density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT; + if (density < ONENAND_DEVICE_DENSITY_512Mb) + otp_pages = 20; + else + otp_pages = 10; + + if (mode == MTD_OTP_FACTORY) { + from += mtd->oobblock * otp_pages; + otp_pages = 64 - otp_pages; + } + + /* Check User/Factory boundary */ + if (((mtd->oobblock * otp_pages) - (from + len)) < 0) + return 0; + + while (len > 0 && otp_pages > 0) { + if (!action) { /* OTP Info functions */ + struct otp_info *otpinfo; + + len -= sizeof(struct otp_info); + if (len <= 0) + return -ENOSPC; + + otpinfo = (struct otp_info *) buf; + otpinfo->start = from; + otpinfo->length = mtd->oobblock; + otpinfo->locked = 0; + + from += mtd->oobblock; + buf += sizeof(struct otp_info); + *retlen += sizeof(struct otp_info); + } else { + size_t tmp_retlen; + int size = len; + + ret = action(mtd, from, len, &tmp_retlen, buf); + + buf += size; + len -= size; + *retlen += size; + + if (ret < 0) + return ret; + } + otp_pages--; + } + + return 0; +} + +/** + * onenand_get_fact_prot_info - [MTD Interface] Read factory OTP info + * @param mtd MTD device structure + * @param buf the databuffer to put/get data + * @param len number of bytes to read + * + * Read factory OTP info. + */ +static int onenand_get_fact_prot_info(struct mtd_info *mtd, + struct otp_info *buf, size_t len) +{ + size_t retlen; + int ret; + + ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_FACTORY); + + return ret ? : retlen; +} + +/** + * onenand_read_fact_prot_reg - [MTD Interface] Read factory OTP area + * @param mtd MTD device structure + * @param from The offset to read + * @param len number of bytes to read + * @param retlen pointer to variable to store the number of read bytes + * @param buf the databuffer to put/get data + * + * Read factory OTP area. + */ +static int onenand_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, u_char *buf) +{ + return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_FACTORY); +} + +/** + * onenand_get_user_prot_info - [MTD Interface] Read user OTP info + * @param mtd MTD device structure + * @param buf the databuffer to put/get data + * @param len number of bytes to read + * + * Read user OTP info. + */ +static int onenand_get_user_prot_info(struct mtd_info *mtd, + struct otp_info *buf, size_t len) +{ + size_t retlen; + int ret; + + ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_USER); + + return ret ? : retlen; +} + +/** + * onenand_read_user_prot_reg - [MTD Interface] Read user OTP area + * @param mtd MTD device structure + * @param from The offset to read + * @param len number of bytes to read + * @param retlen pointer to variable to store the number of read bytes + * @param buf the databuffer to put/get data + * + * Read user OTP area. + */ +static int onenand_read_user_prot_reg(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, u_char *buf) +{ + return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_USER); +} + +/** + * onenand_write_user_prot_reg - [MTD Interface] Write user OTP area + * @param mtd MTD device structure + * @param from The offset to write + * @param len number of bytes to write + * @param retlen pointer to variable to store the number of write bytes + * @param buf the databuffer to put/get data + * + * Write user OTP area. + */ +static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, u_char *buf) +{ + return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_write, MTD_OTP_USER); +} + +/** + * onenand_lock_user_prot_reg - [MTD Interface] Lock user OTP area + * @param mtd MTD device structure + * @param from The offset to lock + * @param len number of bytes to unlock + * + * Write lock mark on spare area in page 0 in OTP block + */ +static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, + size_t len) +{ + unsigned char oob_buf[64]; + size_t retlen; + int ret; + + memset(oob_buf, 0xff, mtd->oobsize); + /* + * Note: OTP lock operation + * OTP block : 0xXXFC + * 1st block : 0xXXF3 (If chip support) + * Both : 0xXXF0 (If chip support) + */ + oob_buf[ONENAND_OTP_LOCK_OFFSET] = 0xFC; + + /* + * Write lock mark to 8th word of sector0 of page0 of the spare0. + * We write 16 bytes spare area instead of 2 bytes. + */ + from = 0; + len = 16; + + ret = onenand_otp_walk(mtd, from, len, &retlen, oob_buf, do_otp_lock, MTD_OTP_USER); + + return ret ? : retlen; +} +#endif /* CONFIG_MTD_ONENAND_OTP */ + /** * onenand_print_device_info - Print device ID * @param device device ID @@ -1563,7 +1863,6 @@ static void onenand_resume(struct mtd_info *mtd) "in suspended state\n"); } - /** * onenand_scan - [OneNAND Interface] Scan for the OneNAND device * @param mtd MTD device structure @@ -1655,6 +1954,14 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) mtd->write_ecc = onenand_write_ecc; mtd->read_oob = onenand_read_oob; mtd->write_oob = onenand_write_oob; +#ifdef CONFIG_MTD_ONENAND_OTP + mtd->get_fact_prot_info = onenand_get_fact_prot_info; + mtd->read_fact_prot_reg = onenand_read_fact_prot_reg; + mtd->get_user_prot_info = onenand_get_user_prot_info; + mtd->read_user_prot_reg = onenand_read_user_prot_reg; + mtd->write_user_prot_reg = onenand_write_user_prot_reg; + mtd->lock_user_prot_reg = onenand_lock_user_prot_reg; +#endif mtd->readv = NULL; mtd->readv_ecc = NULL; mtd->writev = onenand_writev; -- cgit v1.2.2 From 752870707f2818b5f0d94ca05e46cb0ffee6cbf9 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Fri, 12 May 2006 17:03:23 +0300 Subject: OneNAND: fix block command typo We need to check block cmd only instead with comparing with cmd Signed-off-by: Kyungmin Park --- drivers/mtd/onenand/onenand_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/onenand/onenand_base.c') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 163c8113544..fe5b4899727 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -237,7 +237,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le value = onenand_block_address(this, block); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); - if (cmd == block_cmd) { + if (block_cmd) { /* Select DataRAM for DDP */ value = onenand_bufferram_address(this, block); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); -- cgit v1.2.2 From 28318776a80bc3261f9af91ef79e6e38bb9f5bec Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Mon, 22 May 2006 23:18:05 +0200 Subject: [MTD] Introduce writesize At least two flashes exists that have the concept of a minimum write unit, similar to NAND pages, but no other NAND characteristics. Therefore, rename the minimum write unit to "writesize" for all flashes, including NAND. Signed-off-by: Joern Engel --- drivers/mtd/onenand/onenand_base.c | 72 +++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 36 deletions(-) (limited to 'drivers/mtd/onenand/onenand_base.c') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index fe5b4899727..198bb8562d9 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -354,7 +354,7 @@ static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area) if (ONENAND_CURRENT_BUFFERRAM(this)) { if (area == ONENAND_DATARAM) - return mtd->oobblock; + return mtd->writesize; if (area == ONENAND_SPARERAM) return mtd->oobsize; } @@ -632,14 +632,14 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, /* TODO handling oob */ while (read < len) { - thislen = min_t(int, mtd->oobblock, len - read); + thislen = min_t(int, mtd->writesize, len - read); - column = from & (mtd->oobblock - 1); - if (column + thislen > mtd->oobblock) - thislen = mtd->oobblock - column; + column = from & (mtd->writesize - 1); + if (column + thislen > mtd->writesize) + thislen = mtd->writesize - column; if (!onenand_check_bufferram(mtd, from)) { - this->command(mtd, ONENAND_CMD_READ, from, mtd->oobblock); + this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); ret = this->wait(mtd, FL_READING); /* First copy data and check return value for ECC handling */ @@ -752,7 +752,7 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, /* Read more? */ if (read < len) { /* Page size */ - from += mtd->oobblock; + from += mtd->writesize; column = 0; } } @@ -809,7 +809,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) void __iomem *dataram0, *dataram1; int ret = 0; - this->command(mtd, ONENAND_CMD_READ, addr, mtd->oobblock); + this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize); ret = this->wait(mtd, FL_READING); if (ret) @@ -819,9 +819,9 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) /* Check, if the two dataram areas are same */ dataram0 = this->base + ONENAND_DATARAM; - dataram1 = dataram0 + mtd->oobblock; + dataram1 = dataram0 + mtd->writesize; - if (memcmp(dataram0, dataram1, mtd->oobblock)) + if (memcmp(dataram0, dataram1, mtd->writesize)) return -EBADMSG; return 0; @@ -831,7 +831,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) #define onenand_verify_oob(...) (0) #endif -#define NOTALIGNED(x) ((x & (mtd->oobblock - 1)) != 0) +#define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0) /** * onenand_write_ecc - [MTD Interface] OneNAND write with ECC @@ -875,14 +875,14 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, /* Loop until all data write */ while (written < len) { - int thislen = min_t(int, mtd->oobblock, len - written); + int thislen = min_t(int, mtd->writesize, len - written); - this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock); + this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize); this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen); this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); - this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock); + this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); onenand_update_bufferram(mtd, to, 1); @@ -1070,10 +1070,10 @@ static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, * If the given tuple is >= pagesize then * write it out from the iov */ - if ((vecs->iov_len - len) >= mtd->oobblock) { + if ((vecs->iov_len - len) >= mtd->writesize) { pbuf = vecs->iov_base + len; - len += mtd->oobblock; + len += mtd->writesize; /* Check, if we have to switch to the next tuple */ if (len >= (int) vecs->iov_len) { @@ -1083,8 +1083,8 @@ static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, } } else { int cnt = 0, thislen; - while (cnt < mtd->oobblock) { - thislen = min_t(int, mtd->oobblock - cnt, vecs->iov_len - len); + while (cnt < mtd->writesize) { + thislen = min_t(int, mtd->writesize - cnt, vecs->iov_len - len); memcpy(this->page_buf + cnt, vecs->iov_base + len, thislen); cnt += thislen; len += thislen; @@ -1098,12 +1098,12 @@ static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, } } - this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock); + this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize); - this->write_bufferram(mtd, ONENAND_DATARAM, pbuf, 0, mtd->oobblock); + this->write_bufferram(mtd, ONENAND_DATARAM, pbuf, 0, mtd->writesize); this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); - this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock); + this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); onenand_update_bufferram(mtd, to, 1); @@ -1121,9 +1121,9 @@ static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, goto out; } - written += mtd->oobblock; + written += mtd->writesize; - to += mtd->oobblock; + to += mtd->writesize; } out: @@ -1467,11 +1467,11 @@ static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len, int ret; /* Force buffer page aligned */ - if (len < mtd->oobblock) { + if (len < mtd->writesize) { memcpy(this->page_buf, buf, len); - memset(this->page_buf + len, 0xff, mtd->oobblock - len); + memset(this->page_buf + len, 0xff, mtd->writesize - len); pbuf = this->page_buf; - len = mtd->oobblock; + len = mtd->writesize; } /* Enter OTP access mode */ @@ -1546,12 +1546,12 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, otp_pages = 10; if (mode == MTD_OTP_FACTORY) { - from += mtd->oobblock * otp_pages; + from += mtd->writesize * otp_pages; otp_pages = 64 - otp_pages; } /* Check User/Factory boundary */ - if (((mtd->oobblock * otp_pages) - (from + len)) < 0) + if (((mtd->writesize * otp_pages) - (from + len)) < 0) return 0; while (len > 0 && otp_pages > 0) { @@ -1564,10 +1564,10 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, otpinfo = (struct otp_info *) buf; otpinfo->start = from; - otpinfo->length = mtd->oobblock; + otpinfo->length = mtd->writesize; otpinfo->locked = 0; - from += mtd->oobblock; + from += mtd->writesize; buf += sizeof(struct otp_info); *retlen += sizeof(struct otp_info); } else { @@ -1811,15 +1811,15 @@ static int onenand_probe(struct mtd_info *mtd) /* OneNAND page size & block size */ /* The data buffer size is equal to page size */ - mtd->oobblock = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); - mtd->oobsize = mtd->oobblock >> 5; + mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); + mtd->oobsize = mtd->writesize >> 5; /* Pagers per block is always 64 in OneNAND */ - mtd->erasesize = mtd->oobblock << 6; + mtd->erasesize = mtd->writesize << 6; this->erase_shift = ffs(mtd->erasesize) - 1; - this->page_shift = ffs(mtd->oobblock) - 1; + this->page_shift = ffs(mtd->writesize) - 1; this->ppb_shift = (this->erase_shift - this->page_shift); - this->page_mask = (mtd->erasesize / mtd->oobblock) - 1; + this->page_mask = (mtd->erasesize / mtd->writesize) - 1; /* REVIST: Multichip handling */ @@ -1909,7 +1909,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) /* Allocate buffers, if necessary */ if (!this->page_buf) { size_t len; - len = mtd->oobblock + mtd->oobsize; + len = mtd->writesize + mtd->oobsize; this->page_buf = kmalloc(len, GFP_KERNEL); if (!this->page_buf) { printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n"); -- cgit v1.2.2 From 5fa433942ba4e399f7e28764c9db4ade89e91d40 Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Mon, 22 May 2006 23:18:29 +0200 Subject: [MTD] Introduce MTD_BIT_WRITEABLE o Add a flag MTD_BIT_WRITEABLE for devices that allow single bits to be cleared. o Replace MTD_PROGRAM_REGIONS with a cleared MTD_BIT_WRITEABLE flag for STMicro and Intel Sibley flashes with internal ECC. Those flashes disallow clearing of single bits, unlike regular NOR flashes, so the new flag models their behaviour better. o Remove MTD_ECC. After the STMicro/Sibley merge, this flag is only set and never checked. Signed-off-by: Joern Engel --- drivers/mtd/onenand/onenand_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/onenand/onenand_base.c') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 198bb8562d9..4c2c61d54b3 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1943,7 +1943,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) /* Fill in remaining MTD driver data */ mtd->type = MTD_NANDFLASH; - mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC; + mtd->flags = MTD_CAP_NANDFLASH; mtd->ecctype = MTD_ECC_SW; mtd->erase = onenand_erase; mtd->point = NULL; -- cgit v1.2.2 From 9d8522df37f91621a70c5c0dbbf5bf2220b16798 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 May 2006 16:06:03 +0200 Subject: [MTD] Remove nand writev support NAND writev(_ecc) support is not longer necessary. Remove it. Signed-off-by: Thomas Gleixner --- drivers/mtd/onenand/onenand_base.c | 140 ------------------------------------- 1 file changed, 140 deletions(-) (limited to 'drivers/mtd/onenand/onenand_base.c') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 4c2c61d54b3..8e875fa140a 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1013,144 +1013,6 @@ out: return ret; } -/** - * onenand_writev_ecc - [MTD Interface] write with iovec with ecc - * @param mtd MTD device structure - * @param vecs the iovectors to write - * @param count number of vectors - * @param to offset to write to - * @param retlen pointer to variable to store the number of written bytes - * @param eccbuf filesystem supplied oob data buffer - * @param oobsel oob selection structure - * - * OneNAND write with iovec with ecc - */ -static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t *retlen, - u_char *eccbuf, struct nand_oobinfo *oobsel) -{ - struct onenand_chip *this = mtd->priv; - unsigned char *pbuf; - size_t total_len, len; - int i, written = 0; - int ret = 0; - - /* Preset written len for early exit */ - *retlen = 0; - - /* Calculate total length of data */ - total_len = 0; - for (i = 0; i < count; i++) - total_len += vecs[i].iov_len; - - DEBUG(MTD_DEBUG_LEVEL3, "onenand_writev_ecc: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count); - - /* Do not allow write past end of the device */ - if (unlikely((to + total_len) > mtd->size)) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempted write past end of device\n"); - return -EINVAL; - } - - /* Reject writes, which are not page aligned */ - if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(total_len))) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempt to write not page aligned data\n"); - return -EINVAL; - } - - /* Grab the lock and see if the device is available */ - onenand_get_device(mtd, FL_WRITING); - - /* TODO handling oob */ - - /* Loop until all keve's data has been written */ - len = 0; - while (count) { - pbuf = this->page_buf; - /* - * If the given tuple is >= pagesize then - * write it out from the iov - */ - if ((vecs->iov_len - len) >= mtd->writesize) { - pbuf = vecs->iov_base + len; - - len += mtd->writesize; - - /* Check, if we have to switch to the next tuple */ - if (len >= (int) vecs->iov_len) { - vecs++; - len = 0; - count--; - } - } else { - int cnt = 0, thislen; - while (cnt < mtd->writesize) { - thislen = min_t(int, mtd->writesize - cnt, vecs->iov_len - len); - memcpy(this->page_buf + cnt, vecs->iov_base + len, thislen); - cnt += thislen; - len += thislen; - - /* Check, if we have to switch to the next tuple */ - if (len >= (int) vecs->iov_len) { - vecs++; - len = 0; - count--; - } - } - } - - this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize); - - this->write_bufferram(mtd, ONENAND_DATARAM, pbuf, 0, mtd->writesize); - this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); - - this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); - - onenand_update_bufferram(mtd, to, 1); - - ret = this->wait(mtd, FL_WRITING); - if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: write failed %d\n", ret); - goto out; - } - - - /* Only check verify write turn on */ - ret = onenand_verify_page(mtd, (u_char *) pbuf, to); - if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: verify failed %d\n", ret); - goto out; - } - - written += mtd->writesize; - - to += mtd->writesize; - } - -out: - /* Deselect and wakt up anyone waiting on the device */ - onenand_release_device(mtd); - - *retlen = written; - - return 0; -} - -/** - * onenand_writev - [MTD Interface] compabilty function for onenand_writev_ecc - * @param mtd MTD device structure - * @param vecs the iovectors to write - * @param count number of vectors - * @param to offset to write to - * @param retlen pointer to variable to store the number of written bytes - * - * OneNAND write with kvec. This just calls the ecc function - */ -static int onenand_writev(struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t *retlen) -{ - return onenand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL); -} - /** * onenand_block_checkbad - [GENERIC] Check if a block is marked bad * @param mtd MTD device structure @@ -1964,8 +1826,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) #endif mtd->readv = NULL; mtd->readv_ecc = NULL; - mtd->writev = onenand_writev; - mtd->writev_ecc = onenand_writev_ecc; mtd->sync = onenand_sync; mtd->lock = NULL; mtd->unlock = onenand_unlock; -- cgit v1.2.2 From 2528e8cdf376d7da24647c442ec1e88c360d76ca Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 May 2006 16:10:00 +0200 Subject: [MTD] Remove readv/readv_ecc These functions were never implemented and added only bloat to partition and concat code. Signed-off-by: Thomas Gleixner --- drivers/mtd/onenand/onenand_base.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/mtd/onenand/onenand_base.c') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 8e875fa140a..3a3fe1d8fcd 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1824,8 +1824,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) mtd->write_user_prot_reg = onenand_write_user_prot_reg; mtd->lock_user_prot_reg = onenand_lock_user_prot_reg; #endif - mtd->readv = NULL; - mtd->readv_ecc = NULL; mtd->sync = onenand_sync; mtd->lock = NULL; mtd->unlock = onenand_unlock; -- cgit v1.2.2 From 9223a456da8ed357bf7e0b128c853e2c8bd54614 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 May 2006 17:21:03 +0200 Subject: [MTD] Remove read/write _ecc variants MTD clients are agnostic of FLASH which needs ECC suppport. Remove the functions and fixup the callers. Signed-off-by: Thomas Gleixner --- drivers/mtd/onenand/onenand_base.c | 75 +++++++++----------------------------- 1 file changed, 17 insertions(+), 58 deletions(-) (limited to 'drivers/mtd/onenand/onenand_base.c') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 3a3fe1d8fcd..7a2419186ff 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -597,31 +597,28 @@ static void onenand_release_device(struct mtd_info *mtd) } /** - * onenand_read_ecc - [MTD Interface] Read data with ECC + * onenand_read - [MTD Interface] Read data from flash * @param mtd MTD device structure * @param from offset to read from * @param len number of bytes to read * @param retlen pointer to variable to store the number of read bytes * @param buf the databuffer to put data - * @param oob_buf filesystem supplied oob data buffer - * @param oobsel oob selection structure * - * OneNAND read with ECC - */ -static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf, - u_char *oob_buf, struct nand_oobinfo *oobsel) + * Read with ecc +*/ +static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) { struct onenand_chip *this = mtd->priv; int read = 0, column; int thislen; int ret = 0; - DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); + DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: Attempt read beyond end of device\n"); + DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: Attempt read beyond end of device\n"); *retlen = 0; return -EINVAL; } @@ -654,7 +651,7 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, break; if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: read failed = %d\n", ret); + DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: read failed = %d\n", ret); goto out; } @@ -675,22 +672,6 @@ out: return ret; } -/** - * onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc - * @param mtd MTD device structure - * @param from offset to read from - * @param len number of bytes to read - * @param retlen pointer to variable to store the number of read bytes - * @param buf the databuffer to put data - * - * This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL -*/ -static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) -{ - return onenand_read_ecc(mtd, from, len, retlen, buf, NULL, NULL); -} - /** * onenand_read_oob - [MTD Interface] OneNAND read out-of-band * @param mtd MTD device structure @@ -834,39 +815,36 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) #define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0) /** - * onenand_write_ecc - [MTD Interface] OneNAND write with ECC + * onenand_write - [MTD Interface] write buffer to FLASH * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write * @param retlen pointer to variable to store the number of written bytes * @param buf the data to write - * @param eccbuf filesystem supplied oob data buffer - * @param oobsel oob selection structure * - * OneNAND write with ECC + * Write with ECC */ -static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf, - u_char *eccbuf, struct nand_oobinfo *oobsel) +static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) { struct onenand_chip *this = mtd->priv; int written = 0; int ret = 0; - DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); + DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Initialize retlen, in case of early exit */ *retlen = 0; /* Do not allow writes past end of device */ if (unlikely((to + len) > mtd->size)) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt write to past end of device\n"); + DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt write to past end of device\n"); return -EINVAL; } /* Reject writes, which are not page aligned */ if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt to write not page aligned data\n"); + DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt to write not page aligned data\n"); return -EINVAL; } @@ -888,7 +866,7 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, ret = this->wait(mtd, FL_WRITING); if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: write filaed %d\n", ret); + DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret); goto out; } @@ -897,7 +875,7 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, /* Only check verify write turn on */ ret = onenand_verify_page(mtd, (u_char *) buf, to); if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: verify failed %d\n", ret); + DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret); goto out; } @@ -917,23 +895,6 @@ out: return ret; } -/** - * onenand_write - [MTD Interface] compability function for onenand_write_ecc - * @param mtd MTD device structure - * @param to offset to write to - * @param len number of bytes to write - * @param retlen pointer to variable to store the number of written bytes - * @param buf the data to write - * - * This function simply calls onenand_write_ecc - * with oob buffer and oobsel = NULL - */ -static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) -{ - return onenand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL); -} - /** * onenand_write_oob - [MTD Interface] OneNAND write out-of-band * @param mtd MTD device structure @@ -1812,8 +1773,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) mtd->unpoint = NULL; mtd->read = onenand_read; mtd->write = onenand_write; - mtd->read_ecc = onenand_read_ecc; - mtd->write_ecc = onenand_write_ecc; mtd->read_oob = onenand_read_oob; mtd->write_oob = onenand_write_oob; #ifdef CONFIG_MTD_ONENAND_OTP -- cgit v1.2.2 From ff268fb8791cf18df536113355d7184007c269d9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 27 May 2006 20:36:12 +0200 Subject: [MTD] NAND Consolidate oobinfo handling The info structure for out of band data was copied into the mtd structure. Make it a pointer and remove the ability to set it from userspace. The position of ecc bytes is defined by the hardware and should not be changed by software. Signed-off-by: Thomas Gleixner --- drivers/mtd/onenand/onenand_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/onenand/onenand_base.c') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 7a2419186ff..b24bfa6e202 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1762,7 +1762,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) break; } - memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); + mtd->oobinfo = this->autooob; /* Fill in remaining MTD driver data */ mtd->type = MTD_NANDFLASH; -- cgit v1.2.2 From 5bd34c091a044d130601370c370f84b1c59f1627 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 27 May 2006 22:16:10 +0200 Subject: [MTD] NAND Replace oobinfo by ecclayout The nand_oobinfo structure is not fitting the newer error correction demands anymore. Replace it by struct nand_ecclayout and fixup the users all over the place. Keep the nand_oobinfo based ioctl for user space compability reasons. Signed-off-by: Thomas Gleixner --- drivers/mtd/onenand/onenand_base.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/mtd/onenand/onenand_base.c') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index b24bfa6e202..a0d3f011c0f 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -23,8 +23,7 @@ /** * onenand_oob_64 - oob info for large (2KB) page */ -static struct nand_oobinfo onenand_oob_64 = { - .useecc = MTD_NANDECC_AUTOPLACE, +static struct nand_ecclayout onenand_oob_64 = { .eccbytes = 20, .eccpos = { 8, 9, 10, 11, 12, @@ -41,8 +40,7 @@ static struct nand_oobinfo onenand_oob_64 = { /** * onenand_oob_32 - oob info for middle (1KB) page */ -static struct nand_oobinfo onenand_oob_32 = { - .useecc = MTD_NANDECC_AUTOPLACE, +static struct nand_ecclayout onenand_oob_32 = { .eccbytes = 10, .eccpos = { 8, 9, 10, 11, 12, @@ -1747,22 +1745,22 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) switch (mtd->oobsize) { case 64: - this->autooob = &onenand_oob_64; + this->ecclayout = &onenand_oob_64; break; case 32: - this->autooob = &onenand_oob_32; + this->ecclayout = &onenand_oob_32; break; default: printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n", mtd->oobsize); /* To prevent kernel oops */ - this->autooob = &onenand_oob_32; + this->ecclayout = &onenand_oob_32; break; } - mtd->oobinfo = this->autooob; + mtd->ecclayout = this->ecclayout; /* Fill in remaining MTD driver data */ mtd->type = MTD_NANDFLASH; -- cgit v1.2.2 From 8593fbc68b0df1168995de76d1af38eb62fd6b62 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 29 May 2006 03:26:58 +0200 Subject: [MTD] Rework the out of band handling completely Hopefully the last iteration on this! The handling of out of band data on NAND was accompanied by tons of fruitless discussions and halfarsed patches to make it work for a particular problem. Sufficiently annoyed by I all those "I know it better" mails and the resonable amount of discarded "it solves my problem" patches, I finally decided to go for the big rework. After removing the _ecc variants of mtd read/write functions the solution to satisfy the various requirements was to refactor the read/write _oob functions in mtd. The major change is that read/write_oob now takes a pointer to an operation descriptor structure "struct mtd_oob_ops".instead of having a function with at least seven arguments. read/write_oob which should probably renamed to a more descriptive name, can do the following tasks: - read/write out of band data - read/write data content and out of band data - read/write raw data content and out of band data (ecc disabled) struct mtd_oob_ops has a mode field, which determines the oob handling mode. Aside of the MTD_OOB_RAW mode, which is intended to be especially for diagnostic purposes and some internal functions e.g. bad block table creation, the other two modes are for mtd clients: MTD_OOB_PLACE puts/gets the given oob data exactly to/from the place which is described by the ooboffs and ooblen fields of the mtd_oob_ops strcuture. It's up to the caller to make sure that the byte positions are not used by the ECC placement algorithms. MTD_OOB_AUTO puts/gets the given oob data automaticaly to/from the places in the out of band area which are described by the oobfree tuples in the ecclayout data structre which is associated to the devicee. The decision whether data plus oob or oob only handling is done depends on the setting of the datbuf member of the data structure. When datbuf == NULL then the internal read/write_oob functions are selected, otherwise the read/write data routines are invoked. Tested on a few platforms with all variants. Please be aware of possible regressions for your particular device / application scenario Disclaimer: Any whining will be ignored from those who just contributed "hot air blurb" and never sat down to tackle the underlying problem of the mess in the NAND driver grown over time and the big chunk of work to fix up the existing users. The problem was not the holiness of the existing MTD interfaces. The problems was the lack of time to go for the big overhaul. It's easy to add more mess to the existing one, but it takes alot of effort to go for a real solution. Improvements and bugfixes are welcome! Signed-off-by: Thomas Gleixner --- drivers/mtd/onenand/onenand_base.c | 46 +++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 8 deletions(-) (limited to 'drivers/mtd/onenand/onenand_base.c') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index a0d3f011c0f..84ec40d2543 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -671,7 +671,7 @@ out: } /** - * onenand_read_oob - [MTD Interface] OneNAND read out-of-band + * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band * @param mtd MTD device structure * @param from offset to read from * @param len number of bytes to read @@ -680,8 +680,8 @@ out: * * OneNAND read out-of-band data from the spare area */ -static int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) +int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) { struct onenand_chip *this = mtd->priv; int read = 0, thislen, column; @@ -744,6 +744,21 @@ out: return ret; } +/** + * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operation description structure + */ +static int onenand_read_oob(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + BUG_ON(ops->mode != MTD_OOB_PLACE); + + return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->len, + &ops->retlen, ops->oobbuf); +} + #ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE /** * onenand_verify_oob - [GENERIC] verify the oob contents after a write @@ -894,7 +909,7 @@ out: } /** - * onenand_write_oob - [MTD Interface] OneNAND write out-of-band + * onenand_do_write_oob - [Internal] OneNAND write out-of-band * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write @@ -903,8 +918,8 @@ out: * * OneNAND write out-of-band */ -static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) +static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) { struct onenand_chip *this = mtd->priv; int column, ret = 0; @@ -972,6 +987,21 @@ out: return ret; } +/** + * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operation description structure + */ +static int onenand_write_oob(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) +{ + BUG_ON(ops->mode != MTD_OOB_PLACE); + + return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->len, + &ops->retlen, ops->oobbuf); +} + /** * onenand_block_checkbad - [GENERIC] Check if a block is marked bad * @param mtd MTD device structure @@ -1138,7 +1168,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) /* We write two bytes, so we dont have to mess with 16 bit access */ ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); - return mtd->write_oob(mtd, ofs , 2, &retlen, buf); + return onenand_do_write_oob(mtd, ofs , 2, &retlen, buf); } /** @@ -1328,7 +1358,7 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len, this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); this->wait(mtd, FL_OTPING); - ret = mtd->write_oob(mtd, from, len, retlen, buf); + ret = onenand_do_write_oob(mtd, from, len, retlen, buf); /* Exit OTP access mode */ this->command(mtd, ONENAND_CMD_RESET, 0, 0); -- cgit v1.2.2