[U-Boot-Users] [PATCH 4/5] OneNAND support

[PATCH] OneNAND support
Signed-off-by: Kyungmin Park kyungmin.park@samsung.com --- diff --git a/drivers/onenand/onenand_bbt.c b/drivers/onenand/onenand_bbt.c new file mode 100644 index 0000000..6a0eb57 --- /dev/null +++ b/drivers/onenand/onenand_bbt.c @@ -0,0 +1,260 @@ +/* + * linux/drivers/mtd/onenand/onenand_bbt.c + * + * Bad Block Table support for the OneNAND driver + * + * Copyright(c) 2005-2007 Samsung Electronics + * Kyungmin Park kyungmin.park@samsung.com + * + * TODO: + * Split BBT core and chip specific BBT. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <common.h> + +#ifdef CONFIG_CMD_ONENAND + +#include <linux/mtd/onenand.h> +#include <malloc.h> + +/** + * check_short_pattern - [GENERIC] check if a pattern is in the buffer + * @param buf the buffer to search + * @param len the length of buffer to search + * @param paglen the pagelength + * @param td search pattern descriptor + * + * Check for a pattern at the given place. Used to search bad block + * tables and good / bad block identifiers. Same as check_pattern, but + * no optional empty check and the pattern is expected to start + * at offset 0. + */ +static int check_short_pattern(uint8_t * buf, int len, int paglen, + struct nand_bbt_descr *td) +{ + int i; + uint8_t *p = buf; + + /* Compare the pattern */ + for (i = 0; i < td->len; i++) { + if (p[i] != td->pattern[i]) + return -1; + } + return 0; +} + +/** + * create_bbt - [GENERIC] Create a bad block table by scanning the device + * @param mtd MTD device structure + * @param buf temporary buffer + * @param bd descriptor for the good/bad block search pattern + * @param chip create the table for a specific chip, -1 read all chips. + * Applies only if NAND_BBT_PERCHIP option is set + * + * Create a bad block table by scanning the device + * for the given good/bad block identify pattern + */ +static int create_bbt(struct mtd_info *mtd, uint8_t * buf, + struct nand_bbt_descr *bd, int chip) +{ + struct onenand_chip *this = mtd->priv; + struct bbm_info *bbm = this->bbm; + int i, j, numblocks, len, scanlen; + int startblock; + loff_t from; + size_t readlen, ooblen; + + printk(KERN_INFO "Scanning device for bad blocks\n"); + + len = 1; + + /* We need only read few bytes from the OOB area */ + scanlen = ooblen = 0; + readlen = bd->len; + + /* chip == -1 case only */ + /* Note that numblocks is 2 * (real numblocks) here; + * see i += 2 below as it makses shifting and masking less painful + */ + numblocks = mtd->size >> (bbm->bbt_erase_shift - 1); + startblock = 0; + from = 0; + + for (i = startblock; i < numblocks;) { + int ret; + + for (j = 0; j < len; j++) { + size_t retlen; + + /* No need to read pages fully, + * just read required OOB bytes */ + ret = + onenand_read_oob(mtd, + from + j * mtd->oobblock + + bd->offs, readlen, &retlen, + &buf[0]); + + if (ret) + return ret; + + if (check_short_pattern + (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { + bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); + printk(KERN_WARNING + "Bad eraseblock %d at 0x%08x\n", i >> 1, + (unsigned int)from); + break; + } + } + i += 2; + from += (1 << bbm->bbt_erase_shift); + } + + return 0; +} + +/** + * onenand_memory_bbt - [GENERIC] create a memory based bad block table + * @param mtd MTD device structure + * @param bd descriptor for the good/bad block search pattern + * + * The function creates a memory based bbt by scanning the device + * for manufacturer / software marked good / bad blocks + */ +static inline int onenand_memory_bbt(struct mtd_info *mtd, + struct nand_bbt_descr *bd) +{ + unsigned char data_buf[MAX_ONENAND_PAGESIZE]; + + bd->options &= ~NAND_BBT_SCANEMPTY; + return create_bbt(mtd, data_buf, bd, -1); +} + +/** + * onenand_isbad_bbt - [OneNAND Interface] Check if a block is bad + * @param mtd MTD device structure + * @param offs offset in the device + * @param allowbbt allow access to bad block table region + */ +static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) +{ + struct onenand_chip *this = mtd->priv; + struct bbm_info *bbm = this->bbm; + int block; + uint8_t res; + + /* Get block number * 2 */ + block = (int)(offs >> (bbm->bbt_erase_shift - 1)); + res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03; + + DEBUG(MTD_DEBUG_LEVEL2, + "onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", + (unsigned int)offs, block >> 1, res); + + switch ((int)res) { + case 0x00: + return 0; + case 0x01: + return 1; + case 0x02: + return allowbbt ? 0 : 1; + } + + return 1; +} + +/** + * onenand_scan_bbt - [OneNAND Interface] scan, find, read and maybe create bad block table(s) + * @param mtd MTD device structure + * @param bd descriptor for the good/bad block search pattern + * + * The function checks, if a bad block table(s) is/are already + * available. If not it scans the device for manufacturer + * marked good / bad blocks and writes the bad block table(s) to + * the selected place. + * + * The bad block table memory is allocated here. It must be freed + * by calling the onenand_free_bbt function. + * + */ +int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) +{ + struct onenand_chip *this = mtd->priv; + struct bbm_info *bbm = this->bbm; + int len, ret = 0; + + len = mtd->size >> (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"); + return -ENOMEM; + } + /* Clear the memory bad block table */ + memset(bbm->bbt, 0x00, len); + + /* Set the bad block position */ + bbm->badblockpos = ONENAND_BADBLOCK_POS; + + /* Set erase shift */ + bbm->bbt_erase_shift = this->erase_shift; + + if (!bbm->isbad_bbt) + bbm->isbad_bbt = onenand_isbad_bbt; + + /* Scan the device to build a memory based bad block table */ + if ((ret = onenand_memory_bbt(mtd, bd))) { + printk(KERN_ERR + "onenand_scan_bbt: Can't scan flash and build the RAM-based BBT\n"); + free(bbm->bbt); + bbm->bbt = NULL; + } + + return ret; +} + +/* + * Define some generic bad / good block scan pattern which are used + * while scanning a device for factory marked good / bad blocks. + */ +static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; + +static struct nand_bbt_descr largepage_memorybased = { + .options = 0, + .offs = 0, + .len = 2, + .pattern = scan_ff_pattern, +}; + +/** + * onenand_default_bbt - [OneNAND Interface] Select a default bad block table for the device + * @param mtd MTD device structure + * + * This function selects the default bad block table + * support for the device and calls the onenand_scan_bbt function + */ +int onenand_default_bbt(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + struct bbm_info *bbm; + + this->bbm = malloc(sizeof(struct bbm_info)); + if (!this->bbm) + return -ENOMEM; + + bbm = this->bbm; + + memset(bbm, 0, sizeof(struct bbm_info)); + + /* 1KB page has same configuration as 2KB page */ + if (!bbm->badblock_pattern) + bbm->badblock_pattern = &largepage_memorybased; + + return onenand_scan_bbt(mtd, bbm->badblock_pattern); +} + +#endif /* CFG_CMD_ONENAND */

Hello,
in message 20070907010102.GA19979@party you wrote:
[PATCH] OneNAND support
Signed-off-by: Kyungmin Park kyungmin.park@samsung.com
diff --git a/drivers/onenand/onenand_bbt.c b/drivers/onenand/onenand_bbt.c new file mode 100644 index 0000000..6a0eb57 --- /dev/null +++ b/drivers/onenand/onenand_bbt.c
...
- check_short_pattern - [GENERIC] check if a pattern is in the buffer
- @param buf the buffer to search
- @param len the length of buffer to search
- @param paglen the pagelength
- @param td search pattern descriptor
- Check for a pattern at the given place. Used to search bad block
- tables and good / bad block identifiers. Same as check_pattern, but
- no optional empty check and the pattern is expected to start
- at offset 0.
- */
+static int check_short_pattern(uint8_t * buf, int len, int paglen,
struct nand_bbt_descr *td)
+{
- int i;
- uint8_t *p = buf;
- /* Compare the pattern */
- for (i = 0; i < td->len; i++) {
if (p[i] != td->pattern[i])
return -1;
- }
- return 0;
+}
This should probably be replaced by a call to memmem() ?
+/**
- onenand_memory_bbt - [GENERIC] create a memory based bad block table
- @param mtd MTD device structure
- @param bd descriptor for the good/bad block search pattern
- The function creates a memory based bbt by scanning the device
- for manufacturer / software marked good / bad blocks
- */
+static inline int onenand_memory_bbt(struct mtd_info *mtd,
struct nand_bbt_descr *bd)
+{
- unsigned char data_buf[MAX_ONENAND_PAGESIZE];
- bd->options &= ~NAND_BBT_SCANEMPTY;
- return create_bbt(mtd, data_buf, bd, -1);
+}
This scares me. What is data_buf[] being used for? You are aware that it goes out of scope when that function returns?
Best regards,
Wolfgang Denk

- */
+static int check_short_pattern(uint8_t * buf, int len, int paglen,
struct nand_bbt_descr *td)
+{
- int i;
- uint8_t *p = buf;
- /* Compare the pattern */
- for (i = 0; i < td->len; i++) {
if (p[i] != td->pattern[i])
return -1;
- }
- return 0;
+}
This should probably be replaced by a call to memmem() ?
+/**
- onenand_memory_bbt - [GENERIC] create a memory based bad block table
- @param mtd MTD device structure
- @param bd descriptor for the good/bad block search pattern
- The function creates a memory based bbt by scanning the device
- for manufacturer / software marked good / bad blocks
- */
+static inline int onenand_memory_bbt(struct mtd_info *mtd,
struct nand_bbt_descr *bd)
+{
- unsigned char data_buf[MAX_ONENAND_PAGESIZE];
- bd->options &= ~NAND_BBT_SCANEMPTY;
- return create_bbt(mtd, data_buf, bd, -1);
+}
This scares me. What is data_buf[] being used for? You are aware that it goes out of scope when that function returns?
This BBT code is not yet implemented. It's only scan the full blocks at boot time and display the bad blocks.
It's also next time work.
It will be changed at following using page_buf allocated at onenand_init code. static inline int onenand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) { struct onenand_chip *this = mtd->priv;
bd->options &= ~NAND_BBT_SCANEMPTY; return create_bbt(mtd, this->page_buf, bd, -1); }
Thank you, Kyungmin Park

In message 002601c7f348$ae36a480$e1ac580a@swcenter.sec.samsung.co.kr you wrote:
+static int check_short_pattern(uint8_t * buf, int len, int paglen,
...
- /* Compare the pattern */
- for (i = 0; i < td->len; i++) {
if (p[i] != td->pattern[i])
return -1;
- }
...
This should probably be replaced by a call to memmem() ?
...
+static inline int onenand_memory_bbt(struct mtd_info *mtd,
...
This BBT code is not yet implemented. It's only scan the full blocks at boot time and display the bad blocks.
It's also next time work.
I see. OK.
What about using memmem() above?
Best regards,
Wolfgang Denk

-----Original Message----- From: wd@denx.de [mailto:wd@denx.de] Sent: Monday, September 10, 2007 4:09 PM To: kmpark@infradead.org Cc: u-boot-users@lists.sourceforge.net Subject: Re: [U-Boot-Users] [PATCH 4/5] OneNAND support
In message 002601c7f348$ae36a480$e1ac580a@swcenter.sec.samsung.co.kr you wrote:
+static int check_short_pattern(uint8_t * buf, int len, int paglen,
...
- /* Compare the pattern */
- for (i = 0; i < td->len; i++) {
if (p[i] != td->pattern[i])
return -1;
- }
...
This should probably be replaced by a call to memmem() ?
...
+static inline int onenand_memory_bbt(struct mtd_info *mtd,
...
This BBT code is not yet implemented. It's only scan the full blocks at boot time and display the bad blocks.
It's also next time work.
I see. OK.
What about using memmem() above?
It's also written in drivers/nand/nand_bbt.c. Is there any reason to use it? Maybe people are familiar with this code.
Thank you, Kyungmin Park
-- static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) { int i, end; uint8_t *p = buf;
...snip...
/* Compare the pattern */ for (i = 0; i < td->len; i++) { if (p[i] != td->pattern[i]) return -1; }
...snip... }

In message 002f01c7f37c$240db1c0$e1ac580a@swcenter.sec.samsung.co.kr you wrote:
What about using memmem() above?
It's also written in drivers/nand/nand_bbt.c. Is there any reason to use it? Maybe people are familiar with this code.
Maybe we should dump it there, too...
But OK, let's keep this for the next round...
Best regards,
Wolfgang Denk
participants (2)
-
Kyungmin Park
-
Wolfgang Denk