[PATCH 1/3] mtd/nand : use elbc_fcm_ctrl-oob to set FPAR_MS bit of FPAR

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

On both of large-page chip and small-page chip, we always should use
'elbc_fcm_ctrl-oob' to set the FPAR_LP_MS/FPAR_SP_MS bit of FPAR, don't
use a overflowed 'column' to set it.

Signed-off-by: Liu Shuo b35...@freescale.com
Signed-off-by: Li Yang le...@freescale.com
---
 drivers/mtd/nand/fsl_elbc_nand.c |   18 +++---
 1 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index cc08a11..6fce7da 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -414,9 +414,17 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
unsigned int command,
 page_addr, column);
 
elbc_fcm_ctrl-column = column;
-   elbc_fcm_ctrl-oob = 0;
elbc_fcm_ctrl-use_mdr = 1;
 
+   if (column = mtd-writesize) {
+   /* OOB area */
+   column -= mtd-writesize;
+   elbc_fcm_ctrl-oob = 1;
+   } else {
+   WARN_ON(column != 0);
+   elbc_fcm_ctrl-oob = 0;
+   }
+
fcr = (NAND_CMD_STATUSFCR_CMD1_SHIFT) |
  (NAND_CMD_SEQIN FCR_CMD2_SHIFT) |
  (NAND_CMD_PAGEPROG  FCR_CMD3_SHIFT);
@@ -441,16 +449,12 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
unsigned int command,
 (FIR_OP_CW1  FIR_OP6_SHIFT) |
 (FIR_OP_RS   FIR_OP7_SHIFT));
 
-   if (column = mtd-writesize) {
+   if (elbc_fcm_ctrl-oob)
/* OOB area -- READOOB */
-   column -= mtd-writesize;
fcr |= NAND_CMD_READOOB  FCR_CMD0_SHIFT;
-   elbc_fcm_ctrl-oob = 1;
-   } else {
-   WARN_ON(column != 0);
+   else
/* First 256 bytes -- READ0 */
fcr |= NAND_CMD_READ0  FCR_CMD0_SHIFT;
-   }
}
 
out_be32(lbc-fcr, fcr);
-- 
1.7.1


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


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

2011-11-23 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 b35...@freescale.com
Signed-off-by: Li Yang le...@freescale.com
---
 drivers/mtd/nand/fsl_elbc_nand.c |  211 +++---
 1 files changed, 194 insertions(+), 17 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index d634c5f..c96e714 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, the mutiple of 2048.
+* (0=512, 1=2048, 2=4096, 4=8192)
+*/
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,6 +380,26 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
unsigned int command,
 
fsl_elbc_do_read(chip, 0);
fsl_elbc_run_command(mtd);
+
+   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 timing,
+* 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. */
@@ -347,13 +408,36 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
unsigned int command,
 fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:
  

[PATCH 2/3] mtd/nand : set correct length to FBCR for a non-full-page write

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

When we do a non-full-page write, the length be set to FBCR should
not be 'elbc_fcm_ctrl-index', it should be 'elbc_fcm_ctrl-index -
elbc_fcm_ctrl-column'.

Signed-off-by: Liu Shuo b35...@freescale.com
Signed-off-by: Li Yang le...@freescale.com
---
 drivers/mtd/nand/fsl_elbc_nand.c |3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 6fce7da..d634c5f 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -474,7 +474,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned 
int command,
 */
if (elbc_fcm_ctrl-oob || elbc_fcm_ctrl-column != 0 ||
elbc_fcm_ctrl-index != mtd-writesize + mtd-oobsize)
-   out_be32(lbc-fbcr, elbc_fcm_ctrl-index);
+   out_be32(lbc-fbcr,
+   elbc_fcm_ctrl-index - elbc_fcm_ctrl-column);
else
out_be32(lbc-fbcr, 0);
 
-- 
1.7.1


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


[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: 

[PATCH 2/3] mtd/nand : set Nand flash page address to FBAR and FPAR correctly

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

If we use the Nand flash chip whose number of pages in a block is greater
than 64(for large page), we must treat the low bit of FBAR as being the
high bit of the page address due to the limitation of FCM, it simply uses
the low 6-bits (for large page) of the combined block/page address as the
FPAR component, rather than considering the actual block size.

Signed-off-by: Liu Shuo b35...@freescale.com
Signed-off-by: Jerry Huang chang-ming.hu...@freescale.com
Signed-off-by: Tang Yuantian b29...@freescale.com
Signed-off-by: Li Yang le...@freescale.com
---
 drivers/mtd/nand/fsl_elbc_nand.c |   13 ++---
 1 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 1bfcdef..c2c231b 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -166,15 +166,22 @@ static void set_addr(struct mtd_info *mtd, int column, 
int page_addr, int oob)
 
elbc_fcm_ctrl-page = page_addr;
 
-   out_be32(lbc-fbar,
-page_addr  (chip-phys_erase_shift - chip-page_shift));
-
if (priv-page_size) {
+   /*
+* large page size chip : FPAR[PI] save the lowest 6 bits,
+*FBAR[BLK] save the other bits.
+*/
+   out_be32(lbc-fbar, page_addr  6);
out_be32(lbc-fpar,
 ((page_addr  FPAR_LP_PI_SHIFT)  FPAR_LP_PI) |
 (oob ? FPAR_LP_MS : 0) | column);
buf_num = (page_addr  1)  2;
} else {
+   /*
+* small page size chip : FPAR[PI] save the lowest 5 bits,
+*FBAR[BLK] save the other bits.
+*/
+   out_be32(lbc-fbar, page_addr  5);
out_be32(lbc-fpar,
 ((page_addr  FPAR_SP_PI_SHIFT)  FPAR_SP_PI) |
 (oob ? FPAR_SP_MS : 0) | column);
-- 
1.7.1


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


[PATCH 1/3] mtd/nand: fix coding style issue in drivers/mtd/nand/fsl_elbc.c

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

fix whitespaces,tabs coding style issue and use #include linux/io.h instead 
of asm/io.h
in drivers/mtd/nand/fsl_elbc.c.

Signed-off-by: Liu Shuo b35...@freescale.com
Signed-off-by: Li Yang le...@freescale.com
---
 drivers/mtd/nand/fsl_elbc_nand.c |  194 +++---
 1 files changed, 97 insertions(+), 97 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index eedd8ee..1bfcdef 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -38,7 +38,7 @@
 #include linux/mtd/nand_ecc.h
 #include linux/mtd/partitions.h
 
-#include asm/io.h
+#include linux/io.h
 #include asm/fsl_lbc.h
 
 #define MAX_BANKS 8
@@ -167,17 +167,17 @@ static void set_addr(struct mtd_info *mtd, int column, 
int page_addr, int oob)
elbc_fcm_ctrl-page = page_addr;
 
out_be32(lbc-fbar,
-page_addr  (chip-phys_erase_shift - chip-page_shift));
+page_addr  (chip-phys_erase_shift - chip-page_shift));
 
if (priv-page_size) {
out_be32(lbc-fpar,
-((page_addr  FPAR_LP_PI_SHIFT)  FPAR_LP_PI) |
-(oob ? FPAR_LP_MS : 0) | column);
+((page_addr  FPAR_LP_PI_SHIFT)  FPAR_LP_PI) |
+(oob ? FPAR_LP_MS : 0) | column);
buf_num = (page_addr  1)  2;
} else {
out_be32(lbc-fpar,
-((page_addr  FPAR_SP_PI_SHIFT)  FPAR_SP_PI) |
-(oob ? FPAR_SP_MS : 0) | column);
+((page_addr  FPAR_SP_PI_SHIFT)  FPAR_SP_PI) |
+(oob ? FPAR_SP_MS : 0) | column);
buf_num = page_addr  7;
}
 
@@ -190,10 +190,10 @@ static void set_addr(struct mtd_info *mtd, int column, 
int page_addr, int oob)
 
dev_vdbg(priv-dev, set_addr: bank=%d, 
elbc_fcm_ctrl-addr=0x%p (0x%p), 
-   index %x, pes %d ps %d\n,
+   index %x, pes %d ps %d\n,
 buf_num, elbc_fcm_ctrl-addr, priv-vbase,
 elbc_fcm_ctrl-index,
-chip-phys_erase_shift, chip-page_shift);
+chip-phys_erase_shift, chip-page_shift);
 }
 
 /*
@@ -213,13 +213,13 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
out_be32(lbc-mdr, elbc_fcm_ctrl-mdr);
 
dev_vdbg(priv-dev,
-fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n,
-in_be32(lbc-fmr), in_be32(lbc-fir), in_be32(lbc-fcr));
+fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n,
+in_be32(lbc-fmr), in_be32(lbc-fir), in_be32(lbc-fcr));
dev_vdbg(priv-dev,
-fsl_elbc_run_command: fbar=%08x fpar=%08x 
-fbcr=%08x bank=%d\n,
-in_be32(lbc-fbar), in_be32(lbc-fpar),
-in_be32(lbc-fbcr), priv-bank);
+fsl_elbc_run_command: fbar=%08x fpar=%08x 
+fbcr=%08x bank=%d\n,
+in_be32(lbc-fbar), in_be32(lbc-fpar),
+in_be32(lbc-fbcr), priv-bank);
 
ctrl-irq_status = 0;
/* execute special operation */
@@ -227,7 +227,7 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
 
/* wait for FCM complete flag or timeout */
wait_event_timeout(ctrl-irq_wait, ctrl-irq_status,
-  FCM_TIMEOUT_MSECS * HZ/1000);
+  FCM_TIMEOUT_MSECS * HZ/1000);
elbc_fcm_ctrl-status = ctrl-irq_status;
/* store mdr value in case it was needed */
if (elbc_fcm_ctrl-use_mdr)
@@ -237,8 +237,8 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
 
if (elbc_fcm_ctrl-status != LTESR_CC) {
dev_info(priv-dev,
-command failed: fir %x fcr %x status %x mdr %x\n,
-in_be32(lbc-fir), in_be32(lbc-fcr),
+command failed: fir %x fcr %x status %x mdr %x\n,
+in_be32(lbc-fir), in_be32(lbc-fcr),
 elbc_fcm_ctrl-status, elbc_fcm_ctrl-mdr);
return -EIO;
}
@@ -273,20 +273,20 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int 
oob)
 
if (priv-page_size) {
out_be32(lbc-fir,
-(FIR_OP_CM0  FIR_OP0_SHIFT) |
-(FIR_OP_CA   FIR_OP1_SHIFT) |
-(FIR_OP_PA   FIR_OP2_SHIFT) |
-(FIR_OP_CM1  FIR_OP3_SHIFT) |
-(FIR_OP_RBW  FIR_OP4_SHIFT));
+(FIR_OP_CM0  FIR_OP0_SHIFT) |
+(FIR_OP_CA   FIR_OP1_SHIFT) |
+(FIR_OP_PA   FIR_OP2_SHIFT) |
+(FIR_OP_CM1  FIR_OP3_SHIFT) |
+(FIR_OP_RBW  FIR_OP4_SHIFT));
 
out_be32(lbc-fcr, 

[PATCH] mtd/nand : set Nand flash page address to FBAR and FPAR correctly

2011-10-31 Thread b35362
From: Liu Shuo b35...@freescale.com

If we use the Nand flash chip whose number of pages in a block is greater
than 64(for large page), we must treat the low bit of FBAR as being the
high bit of the page address due to the limitation of FCM, it simply uses
the low 6-bits (for large page) of the combined block/page address as the
FPAR component, rather than considering the actual block size.

Signed-off-by: Liu Shuo b35...@freescale.com
Signed-off-by: Jerry Huang chang-ming.hu...@freescale.com
Signed-off-by: Tang Yuantian b29...@freescale.com
Signed-off-by: Li Yang le...@freescale.com
---
 drivers/mtd/nand/fsl_elbc_nand.c |   13 ++---
 1 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 33d8aad..681d8c5 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -167,15 +167,22 @@ static void set_addr(struct mtd_info *mtd, int column, 
int page_addr, int oob)
 
elbc_fcm_ctrl-page = page_addr;
 
-   out_be32(lbc-fbar,
-page_addr  (chip-phys_erase_shift - chip-page_shift));
-
if (priv-page_size) {
+   /*
+* large page size chip : FPAR[PI] save the lowest 6 bits,
+*FBAR[BLK] save the other bits.
+*/
+   out_be32(lbc-fbar, page_addr  6);
out_be32(lbc-fpar,
 ((page_addr  FPAR_LP_PI_SHIFT)  FPAR_LP_PI) |
 (oob ? FPAR_LP_MS : 0) | column);
buf_num = (page_addr  1)  2;
} else {
+   /*
+* small page size chip : FPAR[PI] save the lowest 5 bits,
+*FBAR[BLK] save the other bits.
+*/
+   out_be32(lbc-fbar, page_addr  5);
out_be32(lbc-fpar,
 ((page_addr  FPAR_SP_PI_SHIFT)  FPAR_SP_PI) |
 (oob ? FPAR_SP_MS : 0) | column);
-- 
1.7.1


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


[PATCH v2] Integrated Flash Controller support

2011-10-31 Thread b35362
From: Liu Shuo b35...@freescale.com

Integrated Flash Controller supports various flashes like NOR, NAND
and other devices using NOR, NAND and GPCM Machine available on it.
IFC supports four chip selects.

Signed-off-by: Dipen Dudhat dipen.dud...@freescale.com
Signed-off-by: Scott Wood scottw...@freescale.com
Signed-off-by: Li Yang le...@freescale.com
Signed-off-by: Liu Shuo b35...@freescale.com
---
 arch/powerpc/Kconfig   |4 +
 arch/powerpc/include/asm/fsl_ifc.h |  834 
 arch/powerpc/sysdev/Makefile   |1 +
 arch/powerpc/sysdev/fsl_ifc.c  |  322 ++
 4 files changed, 1161 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/include/asm/fsl_ifc.h
 create mode 100644 arch/powerpc/sysdev/fsl_ifc.c

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index f8e578b..3cd1e64 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -688,6 +688,10 @@ config FSL_LBC
  controller.  Also contains some common code used by
  drivers for specific local bus peripherals.
 
+config FSL_IFC
+   bool
+depends on FSL_SOC
+
 config FSL_GTM
bool
depends on PPC_83xx || QUICC_ENGINE || CPM2
diff --git a/arch/powerpc/include/asm/fsl_ifc.h 
b/arch/powerpc/include/asm/fsl_ifc.h
new file mode 100644
index 000..b955012
--- /dev/null
+++ b/arch/powerpc/include/asm/fsl_ifc.h
@@ -0,0 +1,834 @@
+/* Freescale Integrated Flash Controller
+ *
+ * Copyright 2011 Freescale Semiconductor, Inc
+ *
+ * Author: Dipen Dudhat dipen.dud...@freescale.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_FSL_IFC_H
+#define __ASM_FSL_IFC_H
+
+#include linux/compiler.h
+#include linux/types.h
+#include linux/io.h
+
+#include linux/of_platform.h
+#include linux/interrupt.h
+
+#define FSL_IFC_BANK_COUNT 4
+
+/*
+ * CSPR - Chip Select Property Register
+ */
+#define CSPR_BA0x
+#define CSPR_BA_SHIFT  16
+#define CSPR_PORT_SIZE 0x0180
+#define CSPR_PORT_SIZE_SHIFT   7
+/* Port Size 8 bit */
+#define CSPR_PORT_SIZE_8   0x0080
+/* Port Size 16 bit */
+#define CSPR_PORT_SIZE_16  0x0100
+/* Port Size 32 bit */
+#define CSPR_PORT_SIZE_32  0x0180
+/* Write Protect */
+#define CSPR_WP0x0040
+#define CSPR_WP_SHIFT  6
+/* Machine Select */
+#define CSPR_MSEL  0x0006
+#define CSPR_MSEL_SHIFT1
+/* NOR */
+#define CSPR_MSEL_NOR  0x
+/* NAND */
+#define CSPR_MSEL_NAND 0x0002
+/* GPCM */
+#define CSPR_MSEL_GPCM 0x0004
+/* Bank Valid */
+#define CSPR_V 0x0001
+#define CSPR_V_SHIFT   0
+
+/*
+ * Address Mask Register
+ */
+#define IFC_AMASK_MASK 0x
+#define IFC_AMASK_SHIFT16
+#define IFC_AMASK(n)   (IFC_AMASK_MASK  \
+   (__ilog2(n) - IFC_AMASK_SHIFT))
+
+/*
+ * Chip Select Option Register IFC_NAND Machine
+ */
+/* Enable ECC Encoder */
+#define CSOR_NAND_ECC_ENC_EN   0x8000
+#define CSOR_NAND_ECC_MODE_MASK0x3000
+/* 4 bit correction per 520 Byte sector */
+#define CSOR_NAND_ECC_MODE_4   0x
+/* 8 bit correction per 528 Byte sector */
+#define CSOR_NAND_ECC_MODE_8   0x1000
+/* Enable ECC Decoder */
+#define CSOR_NAND_ECC_DEC_EN   0x0400
+/* Row Address Length */
+#define CSOR_NAND_RAL_MASK 0x0180
+#define CSOR_NAND_RAL_SHIFT20
+#define CSOR_NAND_RAL_10x
+#define CSOR_NAND_RAL_20x0080
+#define CSOR_NAND_RAL_30x0100
+#define CSOR_NAND_RAL_40x0180
+/* Page Size 512b, 2k, 4k */
+#define CSOR_NAND_PGS_MASK 0x0018
+#define CSOR_NAND_PGS_SHIFT16
+#define CSOR_NAND_PGS_512  0x
+#define CSOR_NAND_PGS_2K   0x0008
+#define CSOR_NAND_PGS_4K   0x0010
+/* Spare region Size */
+#define CSOR_NAND_SPRZ_MASK0xE000
+#define 

[PATCH 2/2] NAND Machine support for Integrated Flash Controller

2011-10-31 Thread b35362
From: Liu Shuo b35...@freescale.com

Integrated Flash Controller(IFC) can be used to hook NAND Flash
chips using NAND Flash Machine available on it.

Signed-off-by: Scott Wood scottw...@freescale.com
Signed-off-by: Li Yang le...@freescale.com
Signed-off-by: Liu Shuo b35...@freescale.com
---
 drivers/mtd/nand/Kconfig|   10 +
 drivers/mtd/nand/Makefile   |1 +
 drivers/mtd/nand/fsl_ifc_nand.c | 1076 +++
 3 files changed, 1087 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mtd/nand/fsl_ifc_nand.c

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 4c34252..126d9cc 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -456,6 +456,16 @@ config MTD_NAND_FSL_ELBC
  Enabling this option will enable you to use this to control
  external NAND devices.
 
+config MTD_NAND_FSL_IFC
+   tristate NAND support for Freescale IFC controller
+   depends on MTD_NAND  FSL_SOC
+   select FSL_IFC
+   help
+ Various Freescale chips e.g P1010, include a NAND Flash machine
+ with built-in hardware ECC capabilities.
+ Enabling this option will enable you to use this to control
+ external NAND devices.
+
 config MTD_NAND_FSL_UPM
tristate Support for NAND on Freescale UPM
depends on PPC_83xx || PPC_85xx
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 5745d83..3094131 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_MTD_ALAUDA)  += alauda.o
 obj-$(CONFIG_MTD_NAND_PASEMI)  += pasemi_nand.o
 obj-$(CONFIG_MTD_NAND_ORION)   += orion_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_ELBC)+= fsl_elbc_nand.o
+obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
 obj-$(CONFIG_MTD_NAND_SH_FLCTL)+= sh_flctl.o
 obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
new file mode 100644
index 000..2c9116c
--- /dev/null
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -0,0 +1,1076 @@
+/*
+ * Freescale Integrated Flash Controller NAND driver
+ *
+ * Copyright 2011 Freescale Semiconductor, Inc
+ *
+ * Author: Dipen Dudhat dipen.dud...@freescale.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include linux/module.h
+#include linux/types.h
+#include linux/init.h
+#include linux/kernel.h
+#include linux/slab.h
+#include linux/mtd/mtd.h
+#include linux/mtd/nand.h
+#include linux/mtd/partitions.h
+#include linux/mtd/nand_ecc.h
+#include asm/fsl_ifc.h
+
+#define ERR_BYTE   0xFF /* Value returned for read
+   bytes when read failed  */
+#define IFC_TIMEOUT_MSECS  500  /* Maximum number of mSecs to wait
+   for IFC NAND Machine*/
+
+struct fsl_ifc_ctrl;
+
+/* mtd information per set */
+struct fsl_ifc_mtd {
+   struct mtd_info mtd;
+   struct nand_chip chip;
+   struct fsl_ifc_ctrl *ctrl;
+
+   struct device *dev;
+   int bank;   /* Chip select bank number  */
+   unsigned int bufnum_mask; /* bufnum = page  bufnum_mask */
+   u8 __iomem *vbase;  /* Chip select base virtual address */
+};
+
+/* overview of the fsl ifc controller */
+struct fsl_ifc_nand_ctrl {
+   struct nand_hw_control controller;
+   struct fsl_ifc_mtd *chips[FSL_IFC_BANK_COUNT];
+
+   u8 __iomem *addr;   /* Address of assigned IFC buffer   */
+   unsigned int page;  /* Last page written to / read from */
+   unsigned int read_bytes;/* Number of bytes read during command  */
+   unsigned int column;/* Saved column from SEQIN  */
+   unsigned int index; /* Pointer to next byte to 'read'   */
+   unsigned int oob;   /* Non zero if operating on OOB data*/
+   unsigned int eccread;   /* Non zero for a full-page ECC read*/
+   unsigned int counter;   /* counter for the initializations  */
+};
+
+static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl;
+
+/* 512-byte page with 4-bit ECC, 8-bit */
+static struct nand_ecclayout oob_512_8bit_ecc4 = {
+   

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

2011-08-17 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 divide a page into multi-2K pages for MTD layer driver. In that case,
we force to set the page size to 2K bytes. We convert the page address of
MTD layer driver to a real page address in flash chips and a column index
in fsl_elbc driver. We can issue any column address by UA instruction of
elbc controller.

NOTE: Due to there is a limitation of 'Number of Partial Program Cycles in
the Same Page (NOP)', the flash chip which is supported by this workaround 
have to meet below conditions.
1. page size is not greater than 4KB 
2.  1) if main area and spare area have independent NOPs:
  main  area NOP:=3
  spare area NOP:=2
2) if main area and spare area have a common NOP: 
  NOP   :=4

Signed-off-by: Liu Shuo b35...@freescale.com
Signed-off-by: Li Yang le...@freescale.com
---
 drivers/mtd/nand/fsl_elbc_nand.c |   66 ++---
 1 files changed, 53 insertions(+), 13 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index a212116..884a9f1 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -76,6 +76,13 @@ struct fsl_elbc_fcm_ctrl {
unsigned int oob;/* Non zero if operating on OOB data */
unsigned int counter;/* counter for the initializations   */
char *oob_poi;   /* Place to write ECC after read back*/
+
+   /*
+* If writesize  2048, these two members are used to calculate
+* the real page address and real column address.
+*/
+   int subpage_shift;
+   int subpage_mask;
 };
 
 /* These map to the positions used by the FCM hardware ECC generator */
@@ -164,18 +171,27 @@ static void set_addr(struct mtd_info *mtd, int column, 
int page_addr, int oob)
struct fsl_lbc_regs __iomem *lbc = ctrl-regs;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl-nand;
int buf_num;
+   u32 real_ca = column;
 
-   elbc_fcm_ctrl-page = page_addr;
+   if (priv-page_size  elbc_fcm_ctrl-subpage_shift) {
+   real_ca = (page_addr  elbc_fcm_ctrl-subpage_mask) * 2112;
+   page_addr = elbc_fcm_ctrl-subpage_shift;
+   }
 
-   out_be32(lbc-fbar,
-page_addr  (chip-phys_erase_shift - chip-page_shift));
+   elbc_fcm_ctrl-page = page_addr;
 
if (priv-page_size) {
+   real_ca += (oob ? 2048 : 0);
+   elbc_fcm_ctrl-use_mdr = 1;
+   elbc_fcm_ctrl-mdr = real_ca;
+
+   out_be32(lbc-fbar, page_addr  6);
out_be32(lbc-fpar,
 ((page_addr  FPAR_LP_PI_SHIFT)  FPAR_LP_PI) |
 (oob ? FPAR_LP_MS : 0) | column);
buf_num = (page_addr  1)  2;
} else {
+   out_be32(lbc-fbar, page_addr  5);
out_be32(lbc-fpar,
 ((page_addr  FPAR_SP_PI_SHIFT)  FPAR_SP_PI) |
 (oob ? FPAR_SP_MS : 0) | column);
@@ -256,10 +272,11 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int 
oob)
if (priv-page_size) {
out_be32(lbc-fir,
 (FIR_OP_CM0  FIR_OP0_SHIFT) |
-(FIR_OP_CA   FIR_OP1_SHIFT) |
-(FIR_OP_PA   FIR_OP2_SHIFT) |
-(FIR_OP_CM1  FIR_OP3_SHIFT) |
-(FIR_OP_RBW  FIR_OP4_SHIFT));
+(FIR_OP_UA   FIR_OP1_SHIFT) |
+(FIR_OP_UA   FIR_OP2_SHIFT) |
+(FIR_OP_PA   FIR_OP3_SHIFT) |
+(FIR_OP_CM1  FIR_OP4_SHIFT) |
+(FIR_OP_RBW  FIR_OP5_SHIFT));
 
out_be32(lbc-fcr, (NAND_CMD_READ0  FCR_CMD0_SHIFT) |
(NAND_CMD_READSTART  FCR_CMD1_SHIFT));
@@ -399,12 +416,13 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
unsigned int command,
if (priv-page_size) {
out_be32(lbc-fir,
 (FIR_OP_CM2  FIR_OP0_SHIFT) |
-(FIR_OP_CA   FIR_OP1_SHIFT) |
-(FIR_OP_PA   FIR_OP2_SHIFT) |
-(FIR_OP_WB   FIR_OP3_SHIFT) |
-(FIR_OP_CM3  FIR_OP4_SHIFT) |
-(FIR_OP_CW1  FIR_OP5_SHIFT) |
-(FIR_OP_RS   FIR_OP6_SHIFT));
+(FIR_OP_UA   FIR_OP1_SHIFT) |
+(FIR_OP_UA   FIR_OP2_SHIFT) |
+(FIR_OP_PA   FIR_OP3_SHIFT) |
+(FIR_OP_WB  

[PATCH] mtd-utils: fix corrupt cleanmarker with flash_erase -j command

2011-08-03 Thread b35362
From: Liu Shuo b35...@freescale.com

Flash_erase -j should fill discrete freeoob areas with required bytes
of JFFS2 cleanmarker in jffs2_check_nand_cleanmarker(). Not just fill
the first freeoob area.

Signed-off-by: Liu Shuo b35...@freescale.com
Signed-off-by: Li Yang le...@freescale.com
---
 flash_erase.c |   41 +++--
 1 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/flash_erase.c b/flash_erase.c
index fe2eaca..e6747fc 100644
--- a/flash_erase.c
+++ b/flash_erase.c
@@ -98,6 +98,7 @@ int main(int argc, char *argv[])
int isNAND;
int error = 0;
uint64_t offset = 0;
+   void *oob_data = NULL;
 
/*
 * Process user arguments
@@ -197,15 +198,40 @@ int main(int argc, char *argv[])
if (ioctl(fd, MEMGETOOBSEL, oobinfo) != 0)
return sys_errmsg(%s: unable to get NAND 
oobinfo, mtd_device);
 
+   cleanmarker.totlen = cpu_to_je32(8);
/* Check for autoplacement */
if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
+   struct nand_ecclayout_user ecclayout;
/* Get the position of the free bytes */
-   if (!oobinfo.oobfree[0][1])
+   if (ioctl(fd, ECCGETLAYOUT, ecclayout) != 0)
+   return sys_errmsg(%s: unable to get 
NAND ecclayout, mtd_device);
+
+   if (!ecclayout.oobavail)
return errmsg( Eeep. Autoplacement 
selected and no empty space in oob);
clmpos = oobinfo.oobfree[0][0];
-   clmlen = oobinfo.oobfree[0][1];
-   if (clmlen  8)
-   clmlen = 8;
+   clmlen = MIN(ecclayout.oobavail, 8);
+
+   if (oobinfo.oobfree[0][1]  8  
ecclayout.oobavail = 8) {
+   int i, left, n, last = 0;
+   void *cm;
+
+   oob_data = malloc(mtd.oob_size);
+   if (!oob_data)
+   return -ENOMEM;
+
+   memset(oob_data, 0xff, mtd.oob_size);
+   cm = cleanmarker;
+   for (i = 0, left = clmlen; left ; i++) {
+   n = MIN(left, 
oobinfo.oobfree[i][1]);
+   memcpy(oob_data + 
oobinfo.oobfree[i][0],
+   cm, n);
+   left -= n;
+   cm   += n;
+   last = oobinfo.oobfree[i][0] + 
n;
+   }
+
+   clmlen = last - clmpos;
+   }
} else {
/* Legacy mode */
switch (mtd.oob_size) {
@@ -223,7 +249,6 @@ int main(int argc, char *argv[])
break;
}
}
-   cleanmarker.totlen = cpu_to_je32(8);
}
cleanmarker.hdr_crc = cpu_to_je32(mtd_crc32(0, cleanmarker, 
sizeof(cleanmarker) - 4));
}
@@ -272,7 +297,8 @@ int main(int argc, char *argv[])
 
/* write cleanmarker */
if (isNAND) {
-   if (mtd_write_oob(mtd_desc, mtd, fd, offset + clmpos, 
clmlen, cleanmarker) != 0) {
+   void *data = oob_data ? oob_data + clmpos : 
cleanmarker;
+   if (mtd_write_oob(mtd_desc, mtd, fd, offset + clmpos, 
clmlen, data) != 0) {
sys_errmsg(%s: MTD writeoob failure, 
mtd_device);
continue;
}
@@ -291,5 +317,8 @@ int main(int argc, char *argv[])
show_progress(mtd, offset, eb, eb_start, eb_cnt);
bareverbose(!quiet, \n);
 
+   if (oob_data)
+   free(oob_data);
+
return 0;
 }
-- 
1.7.1


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


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

2011-07-11 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 divide a page into multi-2K pages for MTD layer driver. In that case,
we force to set the page size to 2K bytes. We convert the page address of
MTD layer driver to a real page address in flash chips and a column index
in fsl_elbc driver. We can issue any column address by UA instruction of
elbc controller.

Signed-off-by: Liu Shuo b35...@freescale.com
Signed-off-by: Li Yang le...@freescale.com
---
 drivers/mtd/nand/fsl_elbc_nand.c |   66 ++---
 1 files changed, 53 insertions(+), 13 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index a212116..884a9f1 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -76,6 +76,13 @@ struct fsl_elbc_fcm_ctrl {
unsigned int oob;/* Non zero if operating on OOB data */
unsigned int counter;/* counter for the initializations   */
char *oob_poi;   /* Place to write ECC after read back*/
+
+   /*
+* If writesize  2048, these two members are used to calculate
+* the real page address and real column address.
+*/
+   int subpage_shift;
+   int subpage_mask;
 };
 
 /* These map to the positions used by the FCM hardware ECC generator */
@@ -164,18 +171,27 @@ static void set_addr(struct mtd_info *mtd, int column, 
int page_addr, int oob)
struct fsl_lbc_regs __iomem *lbc = ctrl-regs;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl-nand;
int buf_num;
+   u32 real_ca = column;
 
-   elbc_fcm_ctrl-page = page_addr;
+   if (priv-page_size  elbc_fcm_ctrl-subpage_shift) {
+   real_ca = (page_addr  elbc_fcm_ctrl-subpage_mask) * 2112;
+   page_addr = elbc_fcm_ctrl-subpage_shift;
+   }
 
-   out_be32(lbc-fbar,
-page_addr  (chip-phys_erase_shift - chip-page_shift));
+   elbc_fcm_ctrl-page = page_addr;
 
if (priv-page_size) {
+   real_ca += (oob ? 2048 : 0);
+   elbc_fcm_ctrl-use_mdr = 1;
+   elbc_fcm_ctrl-mdr = real_ca;
+
+   out_be32(lbc-fbar, page_addr  6);
out_be32(lbc-fpar,
 ((page_addr  FPAR_LP_PI_SHIFT)  FPAR_LP_PI) |
 (oob ? FPAR_LP_MS : 0) | column);
buf_num = (page_addr  1)  2;
} else {
+   out_be32(lbc-fbar, page_addr  5);
out_be32(lbc-fpar,
 ((page_addr  FPAR_SP_PI_SHIFT)  FPAR_SP_PI) |
 (oob ? FPAR_SP_MS : 0) | column);
@@ -256,10 +272,11 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int 
oob)
if (priv-page_size) {
out_be32(lbc-fir,
 (FIR_OP_CM0  FIR_OP0_SHIFT) |
-(FIR_OP_CA   FIR_OP1_SHIFT) |
-(FIR_OP_PA   FIR_OP2_SHIFT) |
-(FIR_OP_CM1  FIR_OP3_SHIFT) |
-(FIR_OP_RBW  FIR_OP4_SHIFT));
+(FIR_OP_UA   FIR_OP1_SHIFT) |
+(FIR_OP_UA   FIR_OP2_SHIFT) |
+(FIR_OP_PA   FIR_OP3_SHIFT) |
+(FIR_OP_CM1  FIR_OP4_SHIFT) |
+(FIR_OP_RBW  FIR_OP5_SHIFT));
 
out_be32(lbc-fcr, (NAND_CMD_READ0  FCR_CMD0_SHIFT) |
(NAND_CMD_READSTART  FCR_CMD1_SHIFT));
@@ -399,12 +416,13 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
unsigned int command,
if (priv-page_size) {
out_be32(lbc-fir,
 (FIR_OP_CM2  FIR_OP0_SHIFT) |
-(FIR_OP_CA   FIR_OP1_SHIFT) |
-(FIR_OP_PA   FIR_OP2_SHIFT) |
-(FIR_OP_WB   FIR_OP3_SHIFT) |
-(FIR_OP_CM3  FIR_OP4_SHIFT) |
-(FIR_OP_CW1  FIR_OP5_SHIFT) |
-(FIR_OP_RS   FIR_OP6_SHIFT));
+(FIR_OP_UA   FIR_OP1_SHIFT) |
+(FIR_OP_UA   FIR_OP2_SHIFT) |
+(FIR_OP_PA   FIR_OP3_SHIFT) |
+(FIR_OP_WB   FIR_OP4_SHIFT) |
+(FIR_OP_CM3  FIR_OP5_SHIFT) |
+(FIR_OP_CW1  FIR_OP6_SHIFT) |
+(FIR_OP_RS   FIR_OP7_SHIFT));
} else {
out_be32(lbc-fir,
 (FIR_OP_CM0  FIR_OP0_SHIFT) |
@@ -453,6 +471,9 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned 
int command,
full_page = 1;
}
 
+   if 

[PATCH 1/2] mtd/nand : don't free the global data fsl_lbc_ctrl_dev-nand in fsl_elbc_chip_remove()

2011-06-27 Thread b35362
From: Liu Shuo b35...@freescale.com

The global data fsl_lbc_ctrl_dev-nand don't have to be freed in
fsl_elbc_chip_remove(). The right place to do that is in fsl_elbc_nand_remove()
if elbc_fcm_ctrl-counter is zero.

Signed-off-by: Liu Shuo b35...@freescale.com
---
 drivers/mtd/nand/fsl_elbc_nand.c |1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 0bb254c..a212116 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -829,7 +829,6 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
 
elbc_fcm_ctrl-chips[priv-bank] = NULL;
kfree(priv);
-   kfree(elbc_fcm_ctrl);
return 0;
 }
 
-- 
1.7.1


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


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

2011-06-27 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 divide a page into multi-2K pages for MTD layer driver. In that case,
we force to set the page size to 2K bytes. We convert the page address of
MTD layer driver to a real page address in flash chips and a column index
in fsl_elbc driver. We can issue any column address by UA instruction of
elbc controller.

Signed-off-by: Liu Shuo b35...@freescale.com
Signed-off-by: Li Yang le...@freescale.com
---
 drivers/mtd/nand/fsl_elbc_nand.c |   61 +
 1 files changed, 48 insertions(+), 13 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index a212116..eea7a22 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -76,6 +76,10 @@ struct fsl_elbc_fcm_ctrl {
unsigned int oob;/* Non zero if operating on OOB data */
unsigned int counter;/* counter for the initializations   */
char *oob_poi;   /* Place to write ECC after read back*/
+
+   int subpage_shift;   /* If writesize  2048, these two members*/
+   int subpage_mask;/* are used to calculate the real page   */
+/* address and real column address   */
 };
 
 /* These map to the positions used by the FCM hardware ECC generator */
@@ -164,18 +168,27 @@ static void set_addr(struct mtd_info *mtd, int column, 
int page_addr, int oob)
struct fsl_lbc_regs __iomem *lbc = ctrl-regs;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl-nand;
int buf_num;
+   u32 real_ca = column;
 
-   elbc_fcm_ctrl-page = page_addr;
+   if (priv-page_size  elbc_fcm_ctrl-subpage_shift) {
+   real_ca = (page_addr  elbc_fcm_ctrl-subpage_mask) * 2112;
+   page_addr = elbc_fcm_ctrl-subpage_shift;
+   }
 
-   out_be32(lbc-fbar,
-page_addr  (chip-phys_erase_shift - chip-page_shift));
+   elbc_fcm_ctrl-page = page_addr;
 
if (priv-page_size) {
+   real_ca += (oob ? 2048 : 0);
+   elbc_fcm_ctrl-use_mdr = 1;
+   elbc_fcm_ctrl-mdr = real_ca;
+
+   out_be32(lbc-fbar, page_addr  6);
out_be32(lbc-fpar,
 ((page_addr  FPAR_LP_PI_SHIFT)  FPAR_LP_PI) |
 (oob ? FPAR_LP_MS : 0) | column);
buf_num = (page_addr  1)  2;
} else {
+   out_be32(lbc-fbar, page_addr  5);
out_be32(lbc-fpar,
 ((page_addr  FPAR_SP_PI_SHIFT)  FPAR_SP_PI) |
 (oob ? FPAR_SP_MS : 0) | column);
@@ -256,10 +269,11 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int 
oob)
if (priv-page_size) {
out_be32(lbc-fir,
 (FIR_OP_CM0  FIR_OP0_SHIFT) |
-(FIR_OP_CA   FIR_OP1_SHIFT) |
-(FIR_OP_PA   FIR_OP2_SHIFT) |
-(FIR_OP_CM1  FIR_OP3_SHIFT) |
-(FIR_OP_RBW  FIR_OP4_SHIFT));
+(FIR_OP_UA   FIR_OP1_SHIFT) |
+(FIR_OP_UA   FIR_OP2_SHIFT) |
+(FIR_OP_PA   FIR_OP3_SHIFT) |
+(FIR_OP_CM1  FIR_OP4_SHIFT) |
+(FIR_OP_RBW  FIR_OP5_SHIFT));
 
out_be32(lbc-fcr, (NAND_CMD_READ0  FCR_CMD0_SHIFT) |
(NAND_CMD_READSTART  FCR_CMD1_SHIFT));
@@ -399,12 +413,13 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, 
unsigned int command,
if (priv-page_size) {
out_be32(lbc-fir,
 (FIR_OP_CM2  FIR_OP0_SHIFT) |
-(FIR_OP_CA   FIR_OP1_SHIFT) |
-(FIR_OP_PA   FIR_OP2_SHIFT) |
-(FIR_OP_WB   FIR_OP3_SHIFT) |
-(FIR_OP_CM3  FIR_OP4_SHIFT) |
-(FIR_OP_CW1  FIR_OP5_SHIFT) |
-(FIR_OP_RS   FIR_OP6_SHIFT));
+(FIR_OP_UA   FIR_OP1_SHIFT) |
+(FIR_OP_UA   FIR_OP2_SHIFT) |
+(FIR_OP_PA   FIR_OP3_SHIFT) |
+(FIR_OP_WB   FIR_OP4_SHIFT) |
+(FIR_OP_CM3  FIR_OP5_SHIFT) |
+(FIR_OP_CW1  FIR_OP6_SHIFT) |
+(FIR_OP_RS   FIR_OP7_SHIFT));
} else {
out_be32(lbc-fir,
 (FIR_OP_CM0  FIR_OP0_SHIFT) |
@@ -453,6 +468,9 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned 
int command,
full_page = 1;
}
 
+