[PATCH 1/3] mtd/nand : use elbc_fcm_ctrl-oob to set FPAR_MS bit of FPAR
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
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
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
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
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
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
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
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
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
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
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
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()
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
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; } +