Re: [PATCH v3 3/3] mtd/nand : workaround for Freescale FCM to support large-page Nand chip

2011-11-28 Thread Scott Wood
On 11/23/2011 06:14 AM, LiuShuo wrote:
 于 2011年11月23日 07:55, Scott Wood 写道:
 On 11/15/2011 03:29 AM, b35...@freescale.com wrote:
 From: Liu Shuob35...@freescale.com

 -if (elbc_fcm_ctrl-oob || elbc_fcm_ctrl-column != 0 ||
 +if (elbc_fcm_ctrl-column= mtd-writesize) {
 +/* write oob */
 +if (priv-page_size  1) {
 +/* when pagesize of chip is greater than 2048,
 + * we have to write full page to write spare
 + * region, so we fill '0xff' to main region
 + * and some bytes of spare region which we
 + * don't want to rewrite.
 + * (write '1' won't change the original value)
 + */
 +memset(elbc_fcm_ctrl-buffer, 0xff,
 +elbc_fcm_ctrl-column);
 I don't like relying on this -- can we use RNDIN instead to do a
 discontiguous write?

 I have no better way to implement it now.
 Some chips have 'NOP' limitation, so I don't use the FIR_OP_UA to do a
 oob write.

I don't think each RNDIN counts separately against NOP (someone correct
me if I'm wrong).  You're writing discontiguous regions of the page in
one operation.

-Scott

___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Re: [PATCH v3 3/3] mtd/nand : workaround for Freescale FCM to support large-page Nand chip

2011-11-23 Thread LiuShuo

于 2011年11月23日 07:55, Scott Wood 写道:

On 11/15/2011 03:29 AM, b35...@freescale.com wrote:

From: Liu Shuob35...@freescale.com

Freescale FCM controller has a 2K size limitation of buffer RAM. In order
to support the Nand flash chip whose page size is larger than 2K bytes,
we read/write 2k data repeatedly by issuing FIR_OP_RB/FIR_OP_WB and save
them to a large buffer.

Signed-off-by: Liu Shuoshuo@freescale.com
Signed-off-by: Shengzhou Liushengzhou@freescale.com
Signed-off-by: Li Yangle...@freescale.com
---
  drivers/mtd/nand/fsl_elbc_nand.c |  216 +++---
  1 files changed, 199 insertions(+), 17 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index c2c231b..415f87e 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -55,7 +55,9 @@ struct fsl_elbc_mtd {
struct device *dev;
int bank;   /* Chip select bank number   */
u8 __iomem *vbase;  /* Chip select base virtual address  */
-   int page_size;  /* NAND page size (0=512, 1=2048)*/
+   int page_size;  /* NAND page size (0=512, 1=2048, 2=4096...),
+* the mutiple of 2048.
+*/

That ... isn't very descriptive.  What happens with 8192-byte pages?
Is it 3 or 4?

Please just get rid of this and use mtd-writesize.


+   for (i = 1; i  priv-page_size; i++) {
+   /*
+* Maybe there are some reasons of FCM hardware timming,
+* we must insert a FIR_OP_NOP(0x00) before FIR_OP_RB.
+*/

s/timming/timing/


/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
case NAND_CMD_PAGEPROG: {
+   int len;
dev_vdbg(priv-dev,
 fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG 
 writing %d bytes.\n, elbc_fcm_ctrl-index);
-
/* if the write did not start at 0 or is not a full page
 * then set the exact length, otherwise use a full page
 * write so the HW generates the ECC.
 */
-   if (elbc_fcm_ctrl-oob || elbc_fcm_ctrl-column != 0 ||
+   if (elbc_fcm_ctrl-column= mtd-writesize) {
+   /* write oob */
+   if (priv-page_size  1) {
+   /* when pagesize of chip is greater than 2048,
+* we have to write full page to write spare
+* region, so we fill '0xff' to main region
+* and some bytes of spare region which we
+* don't want to rewrite.
+* (write '1' won't change the original value)
+*/
+   memset(elbc_fcm_ctrl-buffer, 0xff,
+   elbc_fcm_ctrl-column);

I don't like relying on this -- can we use RNDIN instead to do a
discontiguous write?


I have no better way to implement it now.
Some chips have 'NOP' limitation, so I don't use the FIR_OP_UA to do a 
oob write.

+   len = 2112;

len = min(elbc_fcm_ctrl-index, 2112);
when do a oob write (writesize  2048), elbc_fcm_ctrl-index is greater 
writesize

(is 4096 at least).

+   } else
+   len = mtd-writesize + mtd-oobsize -
+   elbc_fcm_ctrl-column;
+   out_be32(lbc-fbcr, len);

len = elbc_fcm_ctrl-index - elbc_fcm_ctrl-column;

Use braces on both sides of the if/else if it's needed on one side.

+   } else if (elbc_fcm_ctrl-column != 0 ||
elbc_fcm_ctrl-index != mtd-writesize + mtd-oobsize)
out_be32(lbc-fbcr, elbc_fcm_ctrl-index);

This should have set fbcr to index - column as well (after adjusting --
though really it's not a supported use case.  We should only be seeing
column != 0 for oob.


I have make a independent to fix this issue.
(In fact,documentation says FCM will stop automatically after
reading the last byte of spare region)

@@ -625,10 +776,16 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, 
const u_char *buf, int len)
return -EINVAL;
}

-   for (i = 0; i  len; i++)
-   if (in_8(elbc_fcm_ctrl-addr[elbc_fcm_ctrl-index + i])
-   != buf[i])
-   break;
+   if (mtd-writesize  2048)
+   for (i = 0; i  len; i++)
+   if (elbc_fcm_ctrl-buffer[elbc_fcm_ctrl-index + i]
+   != buf[i])
+   break;
+   else
+   for (i = 0; i  len; i++)
+   if 

Re: [PATCH v3 3/3] mtd/nand : workaround for Freescale FCM to support large-page Nand chip

2011-11-22 Thread Artem Bityutskiy
On Tue, 2011-11-15 at 17:29 +0800, b35...@freescale.com wrote:
 +   /*
 +* Freescale FCM controller has a 2K size limitation of buffer
 +* RAM, so elbc_fcm_ctrl-buffer have to be used if writesize
 +* of chip is greater than 2048.
 +* We malloc a large enough buffer at this point, because we
 +* don't know writesize before calling nand_scan(). We will
 +* re-malloc later if needed.
 +*/
 +   elbc_fcm_ctrl-buffer = kmalloc(4096 * 6, GFP_KERNEL);
 +   if (!elbc_fcm_ctrl-buffer)
 +   return -ENOMEM; 

Why 4096*6? Judging from the comment it should be 4096.

Artem.

___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH v3 3/3] mtd/nand : workaround for Freescale FCM to support large-page Nand chip

2011-11-22 Thread Scott Wood
On 11/15/2011 03:29 AM, b35...@freescale.com wrote:
 From: Liu Shuo b35...@freescale.com
 
 Freescale FCM controller has a 2K size limitation of buffer RAM. In order
 to support the Nand flash chip whose page size is larger than 2K bytes,
 we read/write 2k data repeatedly by issuing FIR_OP_RB/FIR_OP_WB and save
 them to a large buffer.
 
 Signed-off-by: Liu Shuo shuo@freescale.com
 Signed-off-by: Shengzhou Liu shengzhou@freescale.com
 Signed-off-by: Li Yang le...@freescale.com
 ---
  drivers/mtd/nand/fsl_elbc_nand.c |  216 
 +++---
  1 files changed, 199 insertions(+), 17 deletions(-)
 
 diff --git a/drivers/mtd/nand/fsl_elbc_nand.c 
 b/drivers/mtd/nand/fsl_elbc_nand.c
 index c2c231b..415f87e 100644
 --- a/drivers/mtd/nand/fsl_elbc_nand.c
 +++ b/drivers/mtd/nand/fsl_elbc_nand.c
 @@ -55,7 +55,9 @@ struct fsl_elbc_mtd {
   struct device *dev;
   int bank;   /* Chip select bank number   */
   u8 __iomem *vbase;  /* Chip select base virtual address  */
 - int page_size;  /* NAND page size (0=512, 1=2048)*/
 + int page_size;  /* NAND page size (0=512, 1=2048, 2=4096...),
 +  * the mutiple of 2048.
 +  */

That ... isn't very descriptive.  What happens with 8192-byte pages?
Is it 3 or 4?

Please just get rid of this and use mtd-writesize.

 + for (i = 1; i  priv-page_size; i++) {
 + /*
 +  * Maybe there are some reasons of FCM hardware timming,
 +  * we must insert a FIR_OP_NOP(0x00) before FIR_OP_RB.
 +  */

s/timming/timing/

   /* PAGEPROG reuses all of the setup from SEQIN and adds the length */
   case NAND_CMD_PAGEPROG: {
 + int len;
   dev_vdbg(priv-dev,
fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG 
writing %d bytes.\n, elbc_fcm_ctrl-index);
 -
   /* if the write did not start at 0 or is not a full page
* then set the exact length, otherwise use a full page
* write so the HW generates the ECC.
*/
 - if (elbc_fcm_ctrl-oob || elbc_fcm_ctrl-column != 0 ||
 + if (elbc_fcm_ctrl-column = mtd-writesize) {
 + /* write oob */
 + if (priv-page_size  1) {
 + /* when pagesize of chip is greater than 2048,
 +  * we have to write full page to write spare
 +  * region, so we fill '0xff' to main region
 +  * and some bytes of spare region which we
 +  * don't want to rewrite.
 +  * (write '1' won't change the original value)
 +  */
 + memset(elbc_fcm_ctrl-buffer, 0xff,
 + elbc_fcm_ctrl-column);

I don't like relying on this -- can we use RNDIN instead to do a
discontiguous write?

 + len = 2112;

len = min(elbc_fcm_ctrl-index, 2112);

 + } else
 + len = mtd-writesize + mtd-oobsize -
 + elbc_fcm_ctrl-column;
 + out_be32(lbc-fbcr, len);

len = elbc_fcm_ctrl-index - elbc_fcm_ctrl-column;

Use braces on both sides of the if/else if it's needed on one side.

 + } else if (elbc_fcm_ctrl-column != 0 ||
   elbc_fcm_ctrl-index != mtd-writesize + mtd-oobsize)
   out_be32(lbc-fbcr, elbc_fcm_ctrl-index);

This should have set fbcr to index - column as well (after adjusting --
though really it's not a supported use case.  We should only be seeing
column != 0 for oob.

 @@ -625,10 +776,16 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, 
 const u_char *buf, int len)
   return -EINVAL;
   }
  
 - for (i = 0; i  len; i++)
 - if (in_8(elbc_fcm_ctrl-addr[elbc_fcm_ctrl-index + i])
 - != buf[i])
 - break;
 + if (mtd-writesize  2048)
 + for (i = 0; i  len; i++)
 + if (elbc_fcm_ctrl-buffer[elbc_fcm_ctrl-index + i]
 + != buf[i])
 + break;
 + else
 + for (i = 0; i  len; i++)
 + if (in_8(elbc_fcm_ctrl-addr[elbc_fcm_ctrl-index + i])
 + != buf[i])
 + break;

Please use braces around multiline if/for bodies, even if they're
technically a single statement -- especially when you've got a dangling
else.

   elbc_fcm_ctrl-index += len;
   return i == len  elbc_fcm_ctrl-status == LTESR_CC ? 0 : -EIO;
 @@ -657,6 +814,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
   

Re: [PATCH v3 3/3] mtd/nand : workaround for Freescale FCM to support large-page Nand chip

2011-11-22 Thread LiuShuo

于 2011年11月23日 07:55, Scott Wood 写道:

On 11/15/2011 03:29 AM, b35...@freescale.com wrote:

From: Liu Shuob35...@freescale.com

Freescale FCM controller has a 2K size limitation of buffer RAM. In order
to support the Nand flash chip whose page size is larger than 2K bytes,
we read/write 2k data repeatedly by issuing FIR_OP_RB/FIR_OP_WB and save
them to a large buffer.

Signed-off-by: Liu Shuoshuo@freescale.com
Signed-off-by: Shengzhou Liushengzhou@freescale.com
Signed-off-by: Li Yangle...@freescale.com
---
  drivers/mtd/nand/fsl_elbc_nand.c |  216 +++---
  1 files changed, 199 insertions(+), 17 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index c2c231b..415f87e 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -55,7 +55,9 @@ struct fsl_elbc_mtd {
struct device *dev;
int bank;   /* Chip select bank number   */
u8 __iomem *vbase;  /* Chip select base virtual address  */
-   int page_size;  /* NAND page size (0=512, 1=2048)*/
+   int page_size;  /* NAND page size (0=512, 1=2048, 2=4096...),
+* the mutiple of 2048.
+*/

That ... isn't very descriptive.  What happens with 8192-byte pages?
Is it 3 or 4?

Please just get rid of this and use mtd-writesize.


+   for (i = 1; i  priv-page_size; i++) {
+   /*
+* Maybe there are some reasons of FCM hardware timming,
+* we must insert a FIR_OP_NOP(0x00) before FIR_OP_RB.
+*/

s/timming/timing/


/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
case NAND_CMD_PAGEPROG: {
+   int len;
dev_vdbg(priv-dev,
 fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG 
 writing %d bytes.\n, elbc_fcm_ctrl-index);
-
/* if the write did not start at 0 or is not a full page
 * then set the exact length, otherwise use a full page
 * write so the HW generates the ECC.
 */
-   if (elbc_fcm_ctrl-oob || elbc_fcm_ctrl-column != 0 ||
+   if (elbc_fcm_ctrl-column= mtd-writesize) {
+   /* write oob */
+   if (priv-page_size  1) {
+   /* when pagesize of chip is greater than 2048,
+* we have to write full page to write spare
+* region, so we fill '0xff' to main region
+* and some bytes of spare region which we
+* don't want to rewrite.
+* (write '1' won't change the original value)
+*/
+   memset(elbc_fcm_ctrl-buffer, 0xff,
+   elbc_fcm_ctrl-column);

I don't like relying on this -- can we use RNDIN instead to do a
discontiguous write?


+   len = 2112;

len = min(elbc_fcm_ctrl-index, 2112);


+   } else
+   len = mtd-writesize + mtd-oobsize -
+   elbc_fcm_ctrl-column;
+   out_be32(lbc-fbcr, len);

len = elbc_fcm_ctrl-index - elbc_fcm_ctrl-column;

Use braces on both sides of the if/else if it's needed on one side.


+   } else if (elbc_fcm_ctrl-column != 0 ||
elbc_fcm_ctrl-index != mtd-writesize + mtd-oobsize)
out_be32(lbc-fbcr, elbc_fcm_ctrl-index);

This should have set fbcr to index - column as well (after adjusting --
though really it's not a supported use case.  We should only be seeing
column != 0 for oob.


@@ -625,10 +776,16 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, 
const u_char *buf, int len)
return -EINVAL;
}

-   for (i = 0; i  len; i++)
-   if (in_8(elbc_fcm_ctrl-addr[elbc_fcm_ctrl-index + i])
-   != buf[i])
-   break;
+   if (mtd-writesize  2048)
+   for (i = 0; i  len; i++)
+   if (elbc_fcm_ctrl-buffer[elbc_fcm_ctrl-index + i]
+   != buf[i])
+   break;
+   else
+   for (i = 0; i  len; i++)
+   if (in_8(elbc_fcm_ctrl-addr[elbc_fcm_ctrl-index + i])
+   != buf[i])
+   break;

Please use braces around multiline if/for bodies, even if they're
technically a single statement -- especially when you've got a dangling
else.


elbc_fcm_ctrl-index += len;
return i == len  elbc_fcm_ctrl-status == LTESR_CC ? 0 : -EIO;
@@ -657,6 

[PATCH v3 3/3] mtd/nand : workaround for Freescale FCM to support large-page Nand chip

2011-11-15 Thread b35362
From: Liu Shuo b35...@freescale.com

Freescale FCM controller has a 2K size limitation of buffer RAM. In order
to support the Nand flash chip whose page size is larger than 2K bytes,
we read/write 2k data repeatedly by issuing FIR_OP_RB/FIR_OP_WB and save
them to a large buffer.

Signed-off-by: Liu Shuo shuo@freescale.com
Signed-off-by: Shengzhou Liu shengzhou@freescale.com
Signed-off-by: Li Yang le...@freescale.com
---
 drivers/mtd/nand/fsl_elbc_nand.c |  216 +++---
 1 files changed, 199 insertions(+), 17 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index c2c231b..415f87e 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -55,7 +55,9 @@ struct fsl_elbc_mtd {
struct device *dev;
int bank;   /* Chip select bank number   */
u8 __iomem *vbase;  /* Chip select base virtual address  */
-   int page_size;  /* NAND page size (0=512, 1=2048)*/
+   int page_size;  /* NAND page size (0=512, 1=2048, 2=4096...),
+* the mutiple of 2048.
+*/
unsigned int fmr;   /* FCM Flash Mode Register value */
 };
 
@@ -75,6 +77,8 @@ struct fsl_elbc_fcm_ctrl {
unsigned int use_mdr;/* Non zero if the MDR is to be set  */
unsigned int oob;/* Non zero if operating on OOB data */
unsigned int counter;/* counter for the initializations   */
+
+   char *buffer;/* just be used when pagesize  2048 */
 };
 
 /* These map to the positions used by the FCM hardware ECC generator */
@@ -150,6 +154,42 @@ static struct nand_bbt_descr bbt_mirror_descr = {
 };
 
 /*=*/
+static void io_to_buffer(struct mtd_info *mtd, int subpage, int oob)
+{
+   struct nand_chip *chip = mtd-priv;
+   struct fsl_elbc_mtd *priv = chip-priv;
+   struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv-ctrl-nand;
+   void *src, *dst;
+   int len = (oob ? 64 : 2048);
+
+   if (oob)
+   dst = elbc_fcm_ctrl-buffer + mtd-writesize + subpage * 64;
+   else
+   dst = elbc_fcm_ctrl-buffer + subpage * 2048;
+
+   src = elbc_fcm_ctrl-addr + (oob ? 2048 : 0);
+   memcpy_fromio(dst, src, len);
+}
+
+static void buffer_to_io(struct mtd_info *mtd, int subpage, int oob)
+{
+   struct nand_chip *chip = mtd-priv;
+   struct fsl_elbc_mtd *priv = chip-priv;
+   struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv-ctrl-nand;
+   void *src, *dst;
+   int len = (oob ? 64 : 2048);
+
+   if (oob)
+   src = elbc_fcm_ctrl-buffer + mtd-writesize + subpage * 64;
+   else
+   src = elbc_fcm_ctrl-buffer + subpage * 2048;
+
+   dst = elbc_fcm_ctrl-addr + (oob ? 2048 : 0);
+   memcpy_toio(dst, src, len);
+
+   /* See the in_8() in fsl_elbc_write_buf() */
+   in_8(elbc_fcm_ctrl-addr);
+}
 
 /*
  * Set up the FCM hardware block and page address fields, and the fcm
@@ -193,7 +233,7 @@ static void set_addr(struct mtd_info *mtd, int column, int 
page_addr, int oob)
 
/* for OOB data point to the second half of the buffer */
if (oob)
-   elbc_fcm_ctrl-index += priv-page_size ? 2048 : 512;
+   elbc_fcm_ctrl-index += mtd-writesize;
 
dev_vdbg(priv-dev, set_addr: bank=%d, 
elbc_fcm_ctrl-addr=0x%p (0x%p), 
@@ -311,6 +351,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned 
int command,
struct fsl_lbc_ctrl *ctrl = priv-ctrl;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl-nand;
struct fsl_lbc_regs __iomem *lbc = ctrl-regs;
+   int i;
 
elbc_fcm_ctrl-use_mdr = 0;
 
@@ -339,21 +380,63 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
unsigned int command,
 
fsl_elbc_do_read(chip, 0);
fsl_elbc_run_command(mtd);
-   return;
 
+   if (priv-page_size = 1)
+   return;
+
+   /* Continue to read the rest bytes if writesize  2048 */
+   io_to_buffer(mtd, 0, 0);
+   io_to_buffer(mtd, 0, 1);
+
+   out_be32(lbc-fir, FIR_OP_RB  FIR_OP1_SHIFT);
+
+   for (i = 1; i  priv-page_size; i++) {
+   /*
+* Maybe there are some reasons of FCM hardware timming,
+* we must insert a FIR_OP_NOP(0x00) before FIR_OP_RB.
+*/
+   fsl_elbc_run_command(mtd);
+   io_to_buffer(mtd, i, 0);
+   io_to_buffer(mtd, i, 1);
+   }
+
+   return;
/* READOOB reads only the OOB because no ECC is performed. */
case NAND_CMD_READOOB:
dev_vdbg(priv-dev,
 fsl_elbc_cmdfunc: