Skip to contentSkip to conversation

mtd/nand : Add function board_nand_init_tail() for some special NAND controllers

PATCH New Shengzhou Liu 3 participants 9 messages Dec 2, 2011 – Dec 5, 2011 2 messages not in the archive

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

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().

---
 drivers/mtd/nand/nand.c |   14 +++++++++++++-
 1 files changed, 13 insertions(+), 1 deletions(-)
drivers/mtd/nand/nand.c +13 -1
index d987f4c..2bafe47 100644
@@ -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
Signature · 1 line
1.6.4
#1 lore raw

PATCH 2/4 mtd/nand: Fixup for support ONFI detect

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.

---
 drivers/mtd/nand/nand_base.c |   48 +++++++++++++++++++++--------------------
 1 files changed, 25 insertions(+), 23 deletions(-)
drivers/mtd/nand/nand_base.c +25 -23
index 6aac6a2..8d03f54 100644
@@ -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
Signature · 1 line
1.6.4
#2 lore raw

PATCH 3/4 mtd/nand: remove CONFIG_SYS_NAND_ONFI_DETECTION to enable ONFI detection

We should first try ONFI detection, if ONFI is not supported or fails, then try to check nand_flash_ids table.

---
 drivers/mtd/nand/nand_base.c |    9 ---------
 include/linux/mtd/nand.h     |    2 --
 2 files changed, 0 insertions(+), 11 deletions(-)
drivers/mtd/nand/nand_base.c +0 -9
index 8d03f54..383da76 100644
@@ -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,
include/linux/mtd/nand.h +0 -2
index 987a2ec..e61149e 100644
@@ -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;
 
Signature · 1 line
1.6.4
#3 lore raw

PATCH 4/4 mtd/nand: Add ONFI support for FSL NAND controller

- fix NAND_CMD_READID command for ONFI detect.
- add NAND_CMD_PARAM command to read the ONFI parameter page.

---
 drivers/mtd/nand/fsl_elbc_nand.c |   16 +++++++++++++++-
 1 files changed, 15 insertions(+), 1 deletions(-)
drivers/mtd/nand/fsl_elbc_nand.c +15 -1
index 4d1e527..476fdd3 100644
@@ -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);
Signature · 1 line
1.6.4
#4 lore raw

PATCH 4/4 mtd/nand: Add ONFI support for FSL NAND controller

Quoted 28 lines · Shengzhou Liu

- fix NAND_CMD_READID command for ONFI detect.
- add NAND_CMD_PARAM command to read the ONFI parameter page.

---
 drivers/mtd/nand/fsl_elbc_nand.c |   16 +++++++++++++++-
 1 files changed, 15 insertions(+), 1 deletions(-)
drivers/mtd/nand/fsl_elbc_nand.c +4 -1
index 4d1e527..476fdd3 100644
@@ -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) |

drivers/mtd/nand/fsl_elbc_nand.c static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, · line 495

Quoted 10 lines
drivers/mtd/nand/fsl_elbc_nand.c +10 -0
+				    (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

A message that is not in the archive (sent off-list or not yet received): 3F453DDFF675A64A89321A1F352810216B03B9@039-SN1MPN1-005.039d.mgd.msft.net

#6 lore raw

PATCH 4/4 mtd/nand: Add ONFI support for FSL NAND controller

Quoted 36 lines · On 12/03/2011 03:25 AM, Liu Shengzhou-B36685 wrote:
Quoted 36 lines

-----Original Message-----
From: Wood Scott-B07421
Sent: 2011?12?3? 2:45
To: Liu Shengzhou-B36685
Cc: u-boot at lists.denx.de; Gala Kumar-B11780
Subject: Re: [PATCH 4/4] mtd/nand: Add ONFI support for FSL NAND controller

drivers/mtd/nand/fsl_elbc_nand.c static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, · line 495

Quoted 13 lines · Shengzhou Liu
drivers/mtd/nand/fsl_elbc_nand.c +13 -0
+	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.

Quoted 4 lines
Quoted 1 line

-Scott

There was already NAND_CMD_PARAM command which is called in mtd/nand/nand_base.c, it's not new created. NAND_CMD_PARAM is defined in spec, we should not share it with NAND_CMD_READID, if so, we'll have to intrusive to nand_base.c.

Huh?

All I'm saying is that you could do this in fsl_elbc_nand.c:

	case NAND_CMD_READID:
	case NAND_CMD_PARAM:
		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, command << 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;

-Scott

#7 lore raw

PATCH 2/4 mtd/nand: Fixup for support ONFI detect

In reply to Shengzhou Liu
Quoted 4 lines · Shengzhou Liu

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

A message that is not in the archive (sent off-list or not yet received): 3F453DDFF675A64A89321A1F352810216B0393@039-SN1MPN1-005.039d.mgd.msft.net

#9 lore raw

PATCH 2/4 mtd/nand: Fixup for support ONFI detect

Quoted 18 lines · On 12/03/2011 03:11 AM, Liu Shengzhou-B36685 wrote:
Quoted 18 lines

-----Original Message-----
From: Wood Scott-B07421
Sent: 2011?12?3? 2:32
To: Liu Shengzhou-B36685
Cc: u-boot at lists.denx.de; Gala Kumar-B11780
Subject: Re: [PATCH 2/4] mtd/nand: Fixup for support ONFI detect

Quoted 3 lines · Shengzhou Liu

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,

Quoted 1 line

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.

Quoted 8 lines
Quoted 6 lines

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

Currently in Linux, ONFI is detected first, if ONFI fails, then detect nand_flash_ids table.

How do you get that impression from this code:?

        for (; type->name != NULL; type++)
                if (*dev_id == type->id)
                        break;

        chip->onfi_version = 0;
        if (!type->name || !type->pagesize) {
                /* Check is chip is ONFI compliant */
                ret = nand_flash_detect_onfi(mtd, chip, &busw);
                if (ret)
                        goto ident_done;
        }

nand_flash_detect_onfi() is called only if there is no match found in the ID table.

Quoted 1 line

But in u-boot, it first detects nand_flash_ids table, if not found in the table, it aborts, so ONFI never works.

Right, the problem is that it aborts, not that it checks the table first.

Quoted 4 lines

I think we should still check ONFI first to accord to what Linux does, because there many new NAND chips which not listed in the nand_flash_ids table before known, if check ONFI first, it can automatically find related info without manual intervention.

The assumption in the Linux code appears to be that ONFI chips will never be in the ID table (or possibly that if they are, we don't need the ONFI data).

-Scott

#10 lore raw

PATCH 1/4 mtd/nand : Add function board_nand_init_tail() for some special NAND controllers

In reply to Shengzhou Liu

Hi,

Quoted 16 lines · Shengzhou Liu

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().

---
 drivers/mtd/nand/nand.c |   14 +++++++++++++-
 1 files changed, 13 insertions(+), 1 deletions(-)
drivers/mtd/nand/nand.c +0 -0
index d987f4c..2bafe47 100644

drivers/mtd/nand/nand.c static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIS · line 48

Quoted 10 lines
drivers/mtd/nand/nand.c +7 -0
@@ -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.

Quoted 17 lines
drivers/mtd/nand/nand.c +6 -1
 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
Signature · 2 lines
Regards,
Igor.