[U-Boot] [PATCH 1/4] mtd/nand : Add function board_nand_init_tail() for some special NAND controllers

In some NAND controllers there is a size limitation of RAM buffer(2K bytes). To support large-page NAND chips with greater than 2K pagesize, we need a large buffer, but we don't know pagesize before calling nand_scan_ident(), for more flexible and to identify different cases of large-page greater than 2K bytes, we have a board_nand_init_tail() between nand_scan_ident() and nand_scan_tail().
Signed-off-by: Shengzhou Liu Shengzhou.Liu@freescale.com --- drivers/mtd/nand/nand.c | 14 +++++++++++++- 1 files changed, 13 insertions(+), 1 deletions(-)
diff --git a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c index d987f4c..2bafe47 100644 --- a/drivers/mtd/nand/nand.c +++ b/drivers/mtd/nand/nand.c @@ -39,6 +39,13 @@ static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIS static const char default_nand_name[] = "nand"; static __attribute__((unused)) char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8];
+int __board_nand_init_tail(struct mtd_info *mtd, struct nand_chip *nand) +{ + /* Allow for init at tail in controller-specific file for some reason */ +} +void board_nand_init_tail(struct mtd_info *mtd, struct nand_chip *nand) +__attribute__((weak, alias("__board_nand_init_tail"))); + static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand, ulong base_addr) { @@ -51,7 +58,12 @@ static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand,
nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr; if (board_nand_init(nand) == 0) { - if (nand_scan(mtd, maxchips) == 0) { + if (!nand_scan_ident(mtd, maxchips, NULL)) { + board_nand_init_tail(mtd, nand); + if (nand_scan_tail(mtd)) { + mtd->name = NULL; + return; + } if (!mtd->name) mtd->name = (char *)default_nand_name; #ifdef CONFIG_NEEDS_MANUAL_RELOC

There was a bug logically in the order of nand_flash_detect_onfi and checking nand_flash_ids. We should get NAND devices related informations first by ONFI method instead of querying nand_flash_ids table, if ONFI fails, then query nand_flash_ids table.
Signed-off-by: Shengzhou Liu Shengzhou.Liu@freescale.com --- drivers/mtd/nand/nand_base.c | 48 +++++++++++++++++++++-------------------- 1 files changed, 25 insertions(+), 23 deletions(-)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 6aac6a2..8d03f54 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2585,36 +2585,38 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, return ERR_PTR(-ENODEV); }
- if (!type) - type = nand_flash_ids; + ret = nand_flash_detect_onfi(mtd, chip, &busw); + if (!ret) { + if (!type) + type = nand_flash_ids;
- for (; type->name != NULL; type++) - if (*dev_id == type->id) - break; + for (; type->name != NULL; type++) + if (*dev_id == type->id) + break;
- if (!type->name) { - /* supress warning if there is no nand */ - if (*maf_id != 0x00 && *maf_id != 0xff && - *dev_id != 0x00 && *dev_id != 0xff) - printk(KERN_INFO "%s: unknown NAND device: " - "Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", - __func__, *maf_id, *dev_id); - return ERR_PTR(-ENODEV); - } + if (!type->name) { + /* supress warning if there is no nand */ + if (*maf_id != 0x00 && *maf_id != 0xff && + *dev_id != 0x00 && *dev_id != 0xff) { + printk(KERN_INFO "%s: unknown NAND device: " + "Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", + __func__, *maf_id, *dev_id); + } + return ERR_PTR(-ENODEV); + }
- if (!mtd->name) - mtd->name = type->name; + if (!mtd->name) + mtd->name = type->name;
- chip->chipsize = (uint64_t)type->chipsize << 20; - chip->onfi_version = 0; + chip->chipsize = (uint64_t)type->chipsize << 20; + chip->onfi_version = 0;
- ret = nand_flash_detect_onfi(mtd, chip, &busw); - if (!ret) nand_flash_detect_non_onfi(mtd, chip, type, &busw);
- /* Get chip options, preserve non chip based options */ - chip->options &= ~NAND_CHIPOPTIONS_MSK; - chip->options |= type->options & NAND_CHIPOPTIONS_MSK; + /* Get chip options, preserve non chip based options */ + chip->options &= ~NAND_CHIPOPTIONS_MSK; + chip->options |= type->options & NAND_CHIPOPTIONS_MSK; + }
/* * Set chip as a default. Board drivers can override it, if necessary

We should first try ONFI detection, if ONFI is not supported or fails, then try to check nand_flash_ids table.
Signed-off-by: Shengzhou Liu Shengzhou.Liu@freescale.com --- drivers/mtd/nand/nand_base.c | 9 --------- include/linux/mtd/nand.h | 2 -- 2 files changed, 0 insertions(+), 11 deletions(-)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 8d03f54..383da76 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2415,7 +2415,6 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) chip->controller = &chip->hwcontrol; }
-#ifdef CONFIG_SYS_NAND_ONFI_DETECTION static u16 onfi_crc16(u16 crc, u8 const *p, size_t len) { int i; @@ -2493,14 +2492,6 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd,
return 1; } -#else -static inline int nand_flash_detect_onfi(struct mtd_info *mtd, - struct nand_chip *chip, - int *busw) -{ - return 0; -} -#endif
static void nand_flash_detect_non_onfi(struct mtd_info *mtd, struct nand_chip *chip, diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 987a2ec..e61149e 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -472,9 +472,7 @@ struct nand_chip { uint8_t cellinfo; int badblockpos; int onfi_version; -#ifdef CONFIG_SYS_NAND_ONFI_DETECTION struct nand_onfi_params onfi_params; -#endif
int state;

- fix NAND_CMD_READID command for ONFI detect. - add NAND_CMD_PARAM command to read the ONFI parameter page.
Signed-off-by: Shengzhou Liu Shengzhou.Liu@freescale.com --- drivers/mtd/nand/fsl_elbc_nand.c | 16 +++++++++++++++- 1 files changed, 15 insertions(+), 1 deletions(-)
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 4d1e527..476fdd3 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -350,7 +350,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, out_be32(&lbc->fbcr, 5); ctrl->read_bytes = 5; ctrl->use_mdr = 1; - ctrl->mdr = 0; + ctrl->mdr = column;
set_addr(mtd, 0, 0, 0); fsl_elbc_run_command(mtd); @@ -480,6 +480,20 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, fsl_elbc_run_command(mtd); return;
+ case NAND_CMD_PARAM: + dbg("fsl_elbc_cmdfunc: NAND_CMD_PARAM.\n"); + out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) | + (FIR_OP_UA << FIR_OP1_SHIFT) | + (FIR_OP_RBW << FIR_OP2_SHIFT)); + out_be32(&lbc->fcr, NAND_CMD_PARAM << FCR_CMD0_SHIFT); + out_be32(&lbc->fbcr, 256); + ctrl->read_bytes = 256; + ctrl->use_mdr = 1; + ctrl->mdr = column; + set_addr(mtd, 0, 0, 0); + fsl_elbc_run_command(mtd); + return; + default: printf("fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n", command);

On 12/02/2011 03:17 AM, Shengzhou Liu wrote:
- fix NAND_CMD_READID command for ONFI detect.
- add NAND_CMD_PARAM command to read the ONFI parameter page.
Signed-off-by: Shengzhou Liu Shengzhou.Liu@freescale.com
drivers/mtd/nand/fsl_elbc_nand.c | 16 +++++++++++++++- 1 files changed, 15 insertions(+), 1 deletions(-)
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 4d1e527..476fdd3 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -350,7 +350,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, out_be32(&lbc->fbcr, 5); ctrl->read_bytes = 5; ctrl->use_mdr = 1;
ctrl->mdr = 0;
ctrl->mdr = column;
set_addr(mtd, 0, 0, 0); fsl_elbc_run_command(mtd);
@@ -480,6 +480,20 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, fsl_elbc_run_command(mtd); return;
- case NAND_CMD_PARAM:
dbg("fsl_elbc_cmdfunc: NAND_CMD_PARAM.\n");
out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) |
(FIR_OP_UA << FIR_OP1_SHIFT) |
(FIR_OP_RBW << FIR_OP2_SHIFT));
out_be32(&lbc->fcr, NAND_CMD_PARAM << FCR_CMD0_SHIFT);
out_be32(&lbc->fbcr, 256);
ctrl->read_bytes = 256;
ctrl->use_mdr = 1;
ctrl->mdr = column;
set_addr(mtd, 0, 0, 0);
fsl_elbc_run_command(mtd);
return;
This could share code with NAND_CMD_READID -- always read 256 bytes (we'll need to read more than 5 bytes for non-ONFI as well, when we pull in the newer Linux NAND code), and use "command << FCR_CMD0_SHIFT" for FCR.
BTW, has anyone tested the eLBC driver with 16-bit NAND? I think our read_byte() implementation is not going to do the right thing here -- it needs to read a 16-bit word when the chip is 16-bit, and discard the upper half.
-Scott

On 12/02/2011 03:17 AM, Shengzhou Liu wrote:
There was a bug logically in the order of nand_flash_detect_onfi and checking nand_flash_ids. We should get NAND devices related informations first by ONFI method instead of querying nand_flash_ids table, if ONFI fails, then query nand_flash_ids table.
ONFI issues should be taken care of with the patchset to sync NAND with Linux that was recently posted. It has some minor issues, which hopefully will be addressed by the next merge window.
I disagree that we should check ONFI first -- this is not what Linux does. U-Boot's problem is that it aborts before ever checking ONFI, if the device is not found in the table (and the Linux code suggests that ONFI devices won't be found in the table).
-Scott

Hi,
On 12/02/11 11:17, Shengzhou Liu wrote:
In some NAND controllers there is a size limitation of RAM buffer(2K bytes). To support large-page NAND chips with greater than 2K pagesize, we need a large buffer, but we don't know pagesize before calling nand_scan_ident(), for more flexible and to identify different cases of large-page greater than 2K bytes, we have a board_nand_init_tail() between nand_scan_ident() and nand_scan_tail().
Signed-off-by: Shengzhou Liu Shengzhou.Liu@freescale.com
drivers/mtd/nand/nand.c | 14 +++++++++++++- 1 files changed, 13 insertions(+), 1 deletions(-)
diff --git a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c index d987f4c..2bafe47 100644 --- a/drivers/mtd/nand/nand.c +++ b/drivers/mtd/nand/nand.c @@ -39,6 +39,13 @@ static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIS static const char default_nand_name[] = "nand"; static __attribute__((unused)) char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8];
+int __board_nand_init_tail(struct mtd_info *mtd, struct nand_chip *nand) +{
- /* Allow for init at tail in controller-specific file for some reason */
+} +void board_nand_init_tail(struct mtd_info *mtd, struct nand_chip *nand) +__attribute__((weak, alias("__board_nand_init_tail")));
Something is wrong here... You need to decide what should be the return type... Either make it void and change the return type of the default function, or make it an int and add a return statement.
static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand, ulong base_addr) { @@ -51,7 +58,12 @@ static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand,
nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr; if (board_nand_init(nand) == 0) {
if (nand_scan(mtd, maxchips) == 0) {
if (!nand_scan_ident(mtd, maxchips, NULL)) {
board_nand_init_tail(mtd, nand);
if (nand_scan_tail(mtd)) {
mtd->name = NULL;
return;
} if (!mtd->name) mtd->name = (char *)default_nand_name;
#ifdef CONFIG_NEEDS_MANUAL_RELOC
participants (3)
-
Igor Grinberg
-
Scott Wood
-
Shengzhou Liu