mtd/nand: Add function board_nand_init_tail() for some special NAND controllers
Subsystems (2)
PATCH v2 1/5 mtd/nand: Add function board_nand_init_tail() for some special NAND controllers
In some NAND controllers there is a size limitation of RAM buffer(2K bytes). To support large-page NAND chips with greater than 2K pagesize, we need a large buffer, but we don't know pagesize before calling nand_scan_ident(), for more flexible and to identify different cases of large-page greater than 2K bytes, we have a board_nand_init_tail() between nand_scan_ident() and nand_scan_tail().
--- drivers/mtd/nand/nand.c | 19 ++++++++++++++++++- 1 files changed, 18 insertions(+), 1 deletions(-)
drivers/mtd/nand/nand.c +18 -1
@@ -39,6 +39,14 @@ static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LISstatic const char default_nand_name[] ="nand" ;static __attribute__((unused))char dev_name[CONFIG_SYS_MAX_NAND_DEVICE ][8 ]; +int __board_nand_init_tail (struct mtd_info *mtd) +{ +/* Allow for init at tail in controller-specific file for some reason */ +return 0 ; +} +int board_nand_init_tail (struct mtd_info *mtd) +__attribute__((weak,alias ("__board_nand_init_tail" ))); +static void nand_init_chip (struct mtd_info *mtd,struct nand_chip *nand,ulong base_addr) {
@@ -51,7 +59,16 @@ static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand, nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr;if (board_nand_init (nand) ==0 ) { -if (nand_scan (mtd, maxchips) ==0 ) { +if (!nand_scan_ident (mtd, maxchips,NULL )) { +if (board_nand_init_tail (mtd)) { + mtd->name =NULL ; +return ; + } + +if (nand_scan_tail (mtd)) { + mtd->name =NULL ; +return ; + }if (!mtd->name) mtd->name = (char *)default_nand_name;#ifdef CONFIG_NEEDS_MANUAL_RELOC
Signature · 1 line
1.6.4
PATCH v2 2/5 mtd/nand: Fixup for support ONFI detect
In the past the ONFI never worked dut to u-boot aborted when nand device id not found in ids table. Now if not found in ids table, u-boot still continues to detect by ONFI way.
--- drivers/mtd/nand/nand_base.c | 26 ++++++++++++++++---------- 1 files changed, 16 insertions(+), 10 deletions(-)
drivers/mtd/nand/nand_base.c +16 -10
@@ -2592,10 +2592,17 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,if (*dev_id == type->id)break ; +if (!type->name || !type->pagesize) { +/* Check if chip is ONFI compliant */ + ret =nand_flash_detect_onfi (mtd, chip, &busw); +if (ret) + goto ident_done; + } +if (!type->name) {/* supress warning if there is no nand */ if (*maf_id !=0x00 && *maf_id !=0xff && - *dev_id !=0x00 && *dev_id !=0xff ) + *dev_id !=0x00 && *dev_id !=0xff )printk (KERN_INFO "%s: unknown NAND device: " "Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n" , __func__, *maf_id, *dev_id);
@@ -2608,14 +2615,19 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->chipsize = (uint64_t )type->chipsize <<20 ; chip->onfi_version =0 ; - ret =nand_flash_detect_onfi (mtd, chip, &busw); -if (!ret) -nand_flash_detect_non_onfi (mtd, chip, type, &busw); +nand_flash_detect_non_onfi (mtd, chip, type, &busw);/* Get chip options, preserve non chip based options */ chip->options &= ~NAND_CHIPOPTIONS_MSK ; chip->options |= type->options &NAND_CHIPOPTIONS_MSK ; +/* Check if chip is a not a samsung device. Do not clear the +* options for chips which are not having an extended id. +*/ +if (*maf_id !=NAND_MFR_SAMSUNG && !type->pagesize) + chip->options &= ~NAND_SAMSUNG_LP_OPTIONS ; + +ident_done:/* * Set chip as a default. Board drivers can override it, if necessary */
@@ -2657,12 +2669,6 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->badblockpos = mtd->writesize >512 ?NAND_LARGE_BADBLOCK_POS :NAND_SMALL_BADBLOCK_POS ; -/* Check if chip is a not a samsung device. Do not clear the -* options for chips which are not having an extended id. -*/ -if (*maf_id !=NAND_MFR_SAMSUNG && !type->pagesize) - chip->options &= ~NAND_SAMSUNG_LP_OPTIONS ; -/* Check for AND chips with 4 page planes */ if (chip->options &NAND_4PAGE_ARRAY ) chip->erase_cmd = multi_erase_cmd;
Signature · 1 line
1.6.4
PATCH v2 3/5 mtd/nand: remove CONFIG_SYS_NAND_ONFI_DETECTION to enable ONFI detection
remove CONFIG_SYS_NAND_ONFI_DETECTION to enable ONFI detection.
--- drivers/mtd/nand/nand_base.c | 9 --------- include/linux/mtd/nand.h | 2 -- 2 files changed, 0 insertions(+), 11 deletions(-)
drivers/mtd/nand/nand_base.c +0 -9
@@ -2415,7 +2415,6 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) chip->controller = &chip->hwcontrol; } -#ifdef CONFIG_SYS_NAND_ONFI_DETECTION static u16 onfi_crc16 (u16 crc,u8 const *p,size_t len) {int i;
@@ -2493,14 +2492,6 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd,return 1 ; } -#else -static inline int nand_flash_detect_onfi (struct mtd_info *mtd, -struct nand_chip *chip, -int *busw) -{ -return 0 ; -} -#endif static void nand_flash_detect_non_onfi(struct mtd_info *mtd, struct nand_chip *chip,
include/linux/mtd/nand.h +0 -2
@@ -472,9 +472,7 @@ struct nand_chip {uint8_t cellinfo;int badblockpos;int onfi_version; -#ifdef CONFIG_SYS_NAND_ONFI_DETECTION struct nand_onfi_params onfi_params; -#endif int state;
Signature · 1 line
1.6.4
PATCH v2 4/5 mtd/nand: Add ONFI support for FSL NAND controller
- fix NAND_CMD_READID command for ONFI detect.
- add NAND_CMD_PARAM command to read the ONFI parameter page.
--- drivers/mtd/nand/fsl_elbc_nand.c | 17 ++++++++++------- 1 files changed, 10 insertions(+), 7 deletions(-)
drivers/mtd/nand/fsl_elbc_nand.c +10 -7
@@ -340,18 +340,21 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,/* READID must read all 5 possible bytes while CEB is active */ case NAND_CMD_READID : -vdbg ("fsl_elbc_cmdfunc: NAND_CMD_READID.\n" ); +case NAND_CMD_PARAM : +vdbg ("fsl_elbc_cmdfunc: NAND_CMD 0x%x.\n" , command);out_be32 (&lbc->fir, (FIR_OP_CW0 <<FIR_OP0_SHIFT ) | (FIR_OP_UA <<FIR_OP1_SHIFT ) | (FIR_OP_RBW <<FIR_OP2_SHIFT )); -out_be32 (&lbc->fcr,NAND_CMD_READID <<FCR_CMD0_SHIFT ); -/* 5 bytes for manuf, device and exts */ -out_be32 (&lbc->fbcr,5 ); - ctrl->read_bytes =5 ; +out_be32 (&lbc->fcr, command <<FCR_CMD0_SHIFT ); +/* +* although currently it's 8 bytes for READID, we always read +* the maximum 256 bytes(for PARAM) +*/ +out_be32 (&lbc->fbcr,256 ); + ctrl->read_bytes =256 ; ctrl->use_mdr =1 ; - ctrl->mdr =0 ; - + ctrl->mdr = column;set_addr (mtd,0 ,0 ,0 );fsl_elbc_run_command (mtd);return ;
Signature · 1 line
1.6.4
PATCH v2 5/5 mtd/nand: workaround for Freescale FCM to support 4k pagesize Nand chip
Freescale FCM controller has a 2K size limitation of buffer RAM. In order to support the Nand flash chip with pagesize 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.
--- drivers/mtd/nand/fsl_elbc_nand.c | 283 +++++++++++++++++++++++++++++++++---- 1 files changed, 252 insertions(+), 31 deletions(-)
drivers/mtd/nand/fsl_elbc_nand.c +252 -31
@@ -64,7 +64,6 @@ 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) */ unsigned int fmr;/* FCM Flash Mode Register value */ };
@@ -85,6 +84,8 @@ struct fsl_elbc_ctrl {unsigned int mdr;/* UPM/FCM Data Register value */ unsigned int use_mdr;/* Non zero if the MDR is to be set */ unsigned int oob;/* Non zero if operating on OOB data */ +char *buffer;/* Just used when pagesize is greater */ +/* than FCM RAM 2K limitation */ };/* These map to the positions used by the FCM hardware ECC generator */
@@ -159,6 +160,35 @@ static struct nand_bbt_descr bbt_mirror_descr = { .pattern = mirror_pattern, }; +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_ctrl *ctrl = priv->ctrl; +void *src, *dst; +int len = oob ?64 :2048 ; + +/* for emulating 4096+ bytes NAND using 2048-byte FCM RAM */ + dst = ctrl->buffer + (oob ? mtd->writesize :0 ) + subpage * len; + src = 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_ctrl *ctrl = priv->ctrl; +void *src, *dst; +int len = oob ?64 :2048 ; + + src = ctrl->buffer + (oob ? mtd->writesize :0 ) + subpage * len; + dst = ctrl->addr + (oob ?2048 :0 ); +memcpy_toio (dst, src, len); +/* See the in_8() in fsl_elbc_write_buf() */ +in_8 (ctrl->addr); +} +/*=================================*/ /*
@@ -175,7 +205,7 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) ctrl->page = page_addr; -if (priv->page_size) { +if (mtd->writesize >=2048 ) {out_be32 (&lbc->fbar, page_addr >>6 ); out_be32(&lbc->fpar, ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
@@ -194,7 +224,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) - ctrl->index += priv->page_size ?2048 :512 ; + ctrl->index += mtd->writesize; vdbg("set_addr: bank=%d, ctrl->addr=0x%p (0x%p), " "index %x, pes %d ps %d\n",
@@ -256,13 +286,14 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)return ctrl->status ==LTESR_CC ?0 : -EIO ; } -static void fsl_elbc_do_read (struct nand_chip *chip,int oob) +static void fsl_elbc_do_read (struct mtd_info *mtd,int oob) { +struct nand_chip *chip = mtd->priv;struct fsl_elbc_mtd *priv = chip->priv;struct fsl_elbc_ctrl *ctrl = priv->ctrl;fsl_lbc_t *lbc = ctrl->regs; -if (priv->page_size) { +if (mtd->writesize >=2048 ) { out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) | (FIR_OP_CA << FIR_OP1_SHIFT) |
@@ -295,6 +326,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,struct fsl_elbc_mtd *priv = chip->priv;struct fsl_elbc_ctrl *ctrl = priv->ctrl;fsl_lbc_t *lbc = ctrl->regs; +int i, nps = mtd->writesize /2048 ; ctrl->use_mdr =0 ;
@@ -319,8 +351,28 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, ctrl->read_bytes = mtd->writesize + mtd->oobsize; ctrl->index += column; -fsl_elbc_do_read (chip,0 ); +fsl_elbc_do_read (mtd,0 );fsl_elbc_run_command (mtd); + +if (mtd->writesize <=2048 ) +return ; + +/* Continue to read the rest bytes if writesize > 2048 */ +io_to_buffer (mtd,0 ,0 ); +io_to_buffer (mtd,0 ,1 ); +/* +* Maybe there are some reasons of FCM hardware timing, +* we must insert a FIR_OP_NOP(0x00) before FIR_OP_RB. +*/ +out_be32 (&lbc->fir,FIR_OP_NOP <<FIR_OP0_SHIFT | +FIR_OP_RB <<FIR_OP1_SHIFT ); + +for (i =1 ; i < nps; i++) { +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. */
@@ -328,14 +380,35 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,vdbg ("fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:" " 0x%x, column: 0x%x.\n" , page_addr, column); -out_be32 (&lbc->fbcr, mtd->oobsize - column); -set_addr (mtd, column, page_addr,1 ); +if (mtd->writesize <=2048 ) { +out_be32 (&lbc->fbcr, mtd->oobsize - column); +set_addr (mtd, column, page_addr,1 ); + }else { +out_be32 (&lbc->fbcr,64 ); +set_addr (mtd,0 , page_addr,1 ); + ctrl->index += column; + } ctrl->read_bytes = mtd->writesize + mtd->oobsize; - -fsl_elbc_do_read (chip,1 ); +fsl_elbc_do_read (mtd,1 );fsl_elbc_run_command (mtd); +if (mtd->writesize <=2048 ) +return ; + +if (column <64 ) +io_to_buffer (mtd,0 ,1 ); + +out_be32 (&lbc->fpar,in_be32 (&lbc->fpar) & ~FPAR_LP_MS ); +out_be32 (&lbc->fir,FIR_OP_RB <<FIR_OP1_SHIFT ); +out_be32 (&lbc->fbcr,2112 ); + +for (i =1 ; i < nps; i++) { +fsl_elbc_run_command (mtd); +if (column < (64 * (i +1 ))) +io_to_buffer (mtd, i,1 ); + } +return ;/* READID must read all 5 possible bytes while CEB is active */
@@ -357,6 +430,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, ctrl->mdr = column;set_addr (mtd,0 ,0 ,0 );fsl_elbc_run_command (mtd); +if (mtd->writesize >2048 ) +memcpy_fromio (ctrl->buffer, ctrl->addr,256 );return ;/* ERASE1 stores the block and page address */
@@ -393,9 +468,28 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, page_addr, column); ctrl->column = column; - ctrl->oob =0 ; +if (column >= mtd->writesize) { +/* OOB area */ + column -= mtd->writesize; + ctrl->oob =1 ; + }else { + ctrl->oob =0 ; + } + +if (mtd->writesize >2048 ) { +/* writesize > 2048 */ + fcr = (NAND_CMD_STATUS <<FCR_CMD1_SHIFT ) | + (NAND_CMD_SEQIN <<FCR_CMD2_SHIFT ) | + (NAND_CMD_PAGEPROG <<FCR_CMD3_SHIFT ); +if (ctrl->oob) + fcr |=NAND_CMD_RNDIN <<FCR_CMD0_SHIFT ; -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 )); + }else if (mtd->writesize ==2048 ) { fcr = (NAND_CMD_SEQIN <<FCR_CMD0_SHIFT ) | (NAND_CMD_PAGEPROG <<FCR_CMD1_SHIFT );
@@ -417,11 +511,9 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, (FIR_OP_WB <<FIR_OP4_SHIFT ) | (FIR_OP_CW1 << FIR_OP5_SHIFT)); -if (column >= mtd->writesize) { +if (ctrl->oob) {/* OOB area --> READOOB */ - column -= mtd->writesize; fcr |=NAND_CMD_READOOB <<FCR_CMD0_SHIFT ; - ctrl->oob =1 ; }else if (column <256 ) {/* First 256 bytes --> READ0 */ fcr |=NAND_CMD_READ0 <<FCR_CMD0_SHIFT ;
@@ -432,12 +524,19 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, }out_be32 (&lbc->fcr, fcr); -set_addr (mtd, column, page_addr, ctrl->oob); +if (column >= mtd->writesize && mtd->writesize >2048 ) { +/* for write oob && writesize > 2048 */ +set_addr (mtd,0 , page_addr,0 ); + ctrl->index = column; + }else { +set_addr (mtd, column, page_addr, ctrl->oob); + }return ; }/* PAGEPROG reuses all of the setup from SEQIN and adds the length */ case NAND_CMD_PAGEPROG : { +int pos;vdbg ("fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " "writing %d bytes.\n" , ctrl->index);
@@ -445,14 +544,71 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,* then set the exact length, otherwise use a full page * write so the HW generates the ECC. */ +if (ctrl->oob || ctrl->column !=0 || - ctrl->index != mtd->writesize + mtd->oobsize) -out_be32 (&lbc->fbcr, ctrl->index); -else + ctrl->index != mtd->writesize + mtd->oobsize) { +if (ctrl->oob && mtd->writesize >2048 ) { +out_be32 (&lbc->fbcr,64 ); + }else { +out_be32 (&lbc->fbcr, ctrl->index - + ctrl->column); + } + }else {out_be32 (&lbc->fbcr,0 ); + } + +if (mtd->writesize >2048 ) { +if (!ctrl->oob) +buffer_to_io (mtd,0 ,0 ); +buffer_to_io (mtd,0 ,1 ); + }fsl_elbc_run_command (mtd); +if (mtd->writesize <=2048 ) +return ; + +if (ctrl->oob) { + pos =2048 ; +out_be32 (&lbc->fir, + (FIR_OP_CM0 <<FIR_OP0_SHIFT ) | + (FIR_OP_UA <<FIR_OP1_SHIFT ) | + (FIR_OP_UA <<FIR_OP2_SHIFT ) | + (FIR_OP_WB <<FIR_OP3_SHIFT )); + +for (i =1 ; i < nps; i++) { + pos +=2112 ; + ctrl->mdr = pos; + ctrl->use_mdr =1 ; +if (i == nps -1 ) { +out_be32 (&lbc->fir, + (FIR_OP_CM0 <<FIR_OP1_SHIFT ) | + (FIR_OP_UA <<FIR_OP2_SHIFT ) | + (FIR_OP_UA <<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 )); + } +buffer_to_io (mtd, i,1 ); +fsl_elbc_run_command (mtd); + } + }else { +out_be32 (&lbc->fir,FIR_OP_WB <<FIR_OP1_SHIFT ); +for (i =1 ; i < nps; i++) { +if (i == nps -1 ) { + ctrl->use_mdr =1 ; +out_be32 (&lbc->fir, + (FIR_OP_WB <<FIR_OP1_SHIFT ) | + (FIR_OP_CM3 <<FIR_OP2_SHIFT ) | + (FIR_OP_CW1 <<FIR_OP3_SHIFT ) | + (FIR_OP_RS <<FIR_OP4_SHIFT )); + } +buffer_to_io (mtd, i,0 ); +buffer_to_io (mtd, i,1 ); +fsl_elbc_run_command (mtd); + } + }return ; }
@@ -473,6 +629,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,* write-protected, even when it is not. */ out_8 (ctrl->addr,in_8 (ctrl->addr) |NAND_STATUS_WP ); +if (mtd->writesize >2048 ) + ctrl->buffer[0 ] =in_8 (ctrl->addr);return ;/* RESET without waiting for the ready line */
@@ -519,7 +677,11 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) len = bufsize - ctrl->index; } -memcpy_toio (&ctrl->addr[ctrl->index], buf, len); +if (mtd->writesize >2048 ) +memcpy (&ctrl->buffer[ctrl->index], buf, len); +else +memcpy_toio (&ctrl->addr[ctrl->index], buf, len); +/* * This is workaround for the weird elbc hangs during nand write, * Scott Wood says: "...perhaps difference in how long it takes a
@@ -543,8 +705,13 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd)struct fsl_elbc_ctrl *ctrl = priv->ctrl;/* If there are still bytes in the FCM, then use the next byte. */ -if (ctrl->index < ctrl->read_bytes) -return in_8 (&ctrl->addr[ctrl->index++]); +if (ctrl->index < ctrl->read_bytes) { +int index = ctrl->index++; +if (mtd->writesize >2048 ) +return ctrl->buffer[index]; +else +return in_8 (&ctrl->addr[index]); + }printf ("read_byte beyond end of buffer\n" );return ERR_BYTE ;
@@ -564,7 +731,10 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)return ; avail =min ((unsigned int )len, ctrl->read_bytes - ctrl->index); -memcpy_fromio (buf, &ctrl->addr[ctrl->index], avail); +if (mtd->writesize >2048 ) +memcpy (buf, &ctrl->buffer[ctrl->index], avail); +else +memcpy_fromio (buf, &ctrl->addr[ctrl->index], avail); ctrl->index += avail;if (len > avail)
@@ -598,9 +768,17 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd,return -EINVAL ; } -for (i =0 ; i < len; i++) -if (in_8 (&ctrl->addr[ctrl->index + i]) != buf[i]) -break ; +if (mtd->writesize >2048 ) { +for (i =0 ; i < len; i++) { +if (ctrl->buffer[ctrl->index + i] != buf[i]) +break ; + } + }else { +for (i =0 ; i < len; i++) { +if (in_8 (&ctrl->addr[ctrl->index + i]) != buf[i]) +break ; + } + } ctrl->index += len;return i == len && ctrl->status ==LTESR_CC ?0 : -EIO ;
@@ -637,6 +815,8 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)* write-protected, even when it is not. */ out_8 (ctrl->addr,in_8 (ctrl->addr) |NAND_STATUS_WP ); +if (mtd->writesize >2048 ) + ctrl->buffer[0 ] =in_8 (ctrl->addr);return fsl_elbc_read_byte (mtd); }
@@ -666,11 +846,11 @@ static void fsl_elbc_write_page(struct mtd_info *mtd,static struct fsl_elbc_ctrl *elbc_ctrl; -static void fsl_elbc_ctrl_init (void ) +static int fsl_elbc_ctrl_init (void ) { elbc_ctrl =kzalloc (sizeof (*elbc_ctrl),GFP_KERNEL );if (!elbc_ctrl) -return ; +return -ENOMEM ; elbc_ctrl->regs =LBC_BASE_ADDR ;
@@ -684,6 +864,21 @@ static void fsl_elbc_ctrl_init(void) elbc_ctrl->read_bytes =0 ; elbc_ctrl->index =0 ; elbc_ctrl->addr =NULL ; + +/* +* Freescale FCM controller has a 2KB size limitation of buffer RAM, +* so elbc_ctrl->buffer have to be used if pagesize of NAND devices +* chip greater than 2048. We malloc a large enough buffer(just max +* 8K pagesize for now) at this point, because we don't know pagesize +* before calling nand_scan_ident(). +*/ + elbc_ctrl->buffer =kmalloc (1024 *8 +1024 ,GFP_KERNEL ); +if (!elbc_ctrl->buffer) { +printf ("failed to allocate memory for elbc_ctrl->buffer\n" ); +return -ENOMEM ; + } + +return 0 ; }int board_nand_init (struct nand_chip *nand)
@@ -692,8 +887,7 @@ int board_nand_init(struct nand_chip *nand)uint32_t br =0 , or =0 ;if (!elbc_ctrl) { -fsl_elbc_ctrl_init (); -if (!elbc_ctrl) +if (fsl_elbc_ctrl_init ())return -1 ; }
@@ -782,7 +976,6 @@ int board_nand_init(struct nand_chip *nand)/* Large-page-specific setup */ if (or &OR_FCM_PGS ) { - priv->page_size =1 ; nand->badblock_pattern = &largepage_memorybased;/* adjust ecc setup if needed */
@@ -796,3 +989,31 @@ int board_nand_init(struct nand_chip *nand)return 0 ; } + +int board_nand_init_tail (struct mtd_info *mtd) +{ +struct nand_chip *nand = mtd->priv; +struct fsl_elbc_mtd *priv = nand->priv; +struct fsl_elbc_ctrl *ctrl = priv->ctrl; + +/* adjust Option Register and ECC to match Flash page size */ +if (mtd->writesize ==512 ) { +clrbits_be32 (&ctrl->regs->bank[priv->bank].or,OR_FCM_PGS ); + }else if (mtd->writesize >=2048 && mtd->writesize <=8192 ) { +setbits_be32 (&ctrl->regs->bank[priv->bank].or,OR_FCM_PGS ); +/* adjust ecc setup if needed */ +if ((in_be32 (&ctrl->regs->bank[priv->bank].br) &BR_DECC ) == +BR_DECC_CHK_GEN ) { + nand->ecc.size =512 ; + nand->ecc.layout = (priv->fmr &FMR_ECCM ) ? + &fsl_elbc_oob_lp_eccm1 : &fsl_elbc_oob_lp_eccm0; + nand->badblock_pattern = &largepage_memorybased; + } + }else { +printf ("%s: page size %d is not supported\n" , __func__, + mtd->writesize); +return -1 ; + } + +return 0 ; +}
Signature · 1 line
1.6.4
PATCH v2 5/5 mtd/nand: workaround for Freescale FCM to support 4k pagesize Nand chip
Quoted 10 lines · Shengzhou Liu
Freescale FCM controller has a 2K size limitation of buffer RAM. In order to support the Nand flash chip with pagesize 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 Shengzhou Liu <[email protected]>Signed-off-by Liu Shuo <[email protected]>--- drivers/mtd/nand/fsl_elbc_nand.c | 283 +++++++++++++++++++++++++++++++++---- 1 files changed, 252 insertions(+), 31 deletions(-)
I've asked you several times what you're planning on doing for bad block marker migration. I am not going to let you ignore this. NACK until you have a migration tool, and a scheme for marking the flash as having been migrated.
Also please mention below the --- what has changed since v1.
Quoted 12 lines
drivers/mtd/nand/fsl_elbc_nand.c +7
-1@@ -393,9 +468,28 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, page_addr, column); ctrl->column = column; - ctrl->oob =0 ; +if (column >= mtd->writesize) { +/* OOB area */ + column -= mtd->writesize; + ctrl->oob =1 ; + }else { + ctrl->oob =0 ; + }
[snip]
drivers/mtd/nand/fsl_elbc_nand.c static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, · line 527
Quoted 6 lines
drivers/mtd/nand/fsl_elbc_nand.c +1
-1@@ -432,12 +524,19 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, }out_be32 (&lbc->fcr, fcr); -set_addr (mtd, column, page_addr, ctrl->oob); +if (column >= mtd->writesize && mtd->writesize >2048 ) {
How can column >= mtd->writesize be true at this point? You've already subtracted it out.
Quoted 4 lines
drivers/mtd/nand/fsl_elbc_nand.c +0
-3if (ctrl->oob || ctrl->column != 0 || - ctrl->index != mtd->writesize + mtd->oobsize) -out_be32 (&lbc->fbcr, ctrl->index); -else
drivers/mtd/nand/fsl_elbc_nand.c static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, · line 558
Quoted 10 lines
drivers/mtd/nand/fsl_elbc_nand.c +9
-0+ ctrl->index != mtd->writesize + mtd->oobsize) { + if (ctrl->oob && mtd->writesize > 2048) { + out_be32(&lbc->fbcr, 64); + } else { + out_be32(&lbc->fbcr, ctrl->index - + ctrl->column); + } + } else {out_be32 (&lbc->fbcr,0 ); + }
Again, if we're going to make an API assumption that we get either a full page access or a full OOB access, then make the assumption fully. Don't half-implement partial accessses.
Quoted 5 lines
drivers/mtd/nand/fsl_elbc_nand.c +5
-0+int board_nand_init_tail (struct mtd_info *mtd) +{ +struct nand_chip *nand = mtd->priv; +struct fsl_elbc_mtd *priv = nand->priv; +struct fsl_elbc_ctrl *ctrl = priv->ctrl;
drivers/mtd/nand/fsl_elbc_nand.c int board_nand_init(struct nand_chip *nand) · line 1007
Quoted 10 lines
drivers/mtd/nand/fsl_elbc_nand.c +10
-0+ +/* adjust Option Register and ECC to match Flash page size */ +if (mtd->writesize ==512 ) { +clrbits_be32 (&ctrl->regs->bank[priv->bank].or,OR_FCM_PGS ); + }else if (mtd->writesize >=2048 && mtd->writesize <=8192 ) { +setbits_be32 (&ctrl->regs->bank[priv->bank].or,OR_FCM_PGS ); +/* adjust ecc setup if needed */ +if ((in_be32 (&ctrl->regs->bank[priv->bank].br) &BR_DECC ) == +BR_DECC_CHK_GEN ) { + nand->ecc.size =512 ;
Please find some way to indent the continuation line so it doesn't line up with the if-body.
drivers/mtd/nand/fsl_elbc_nand.c int board_nand_init(struct nand_chip *nand) · line 1010
Quoted 3 lines
drivers/mtd/nand/fsl_elbc_nand.c +3
-0+ nand->ecc.layout = (priv->fmr &FMR_ECCM ) ? + &fsl_elbc_oob_lp_eccm1 : &fsl_elbc_oob_lp_eccm0; + nand->badblock_pattern = &largepage_memorybased;
Those oob layouts won't be quite right for larger page sizes.
-Scott
A message that is not in the archive (sent off-list or not yet received): 3F453DDFF675A64A89321A1F352810216BEF66@039-SN1MPN1-005.039d.mgd.msft.net
PATCH v2 5/5 mtd/nand: workaround for Freescale FCM to support 4k pagesize Nand chip
Quoted 16 lines · On 12/14/2011 01:30 AM, Liu Shengzhou-B36685 wrote:
Quoted 10 lines
-----Original Message-----
From: Wood Scott-B07421
Sent: Tuesday, December 13, 2011 4:14 AM
To: Liu Shengzhou-B36685
Cc: u-boot at lists.denx.de; Gala Kumar-B11780; Liu Shuo-B35362
Subject: Re: [PATCH 5/5 v2] mtd/nand: workaround for Freescale FCM to support 4k pagesize Nand chipQuoted 5 lines
I've asked you several times what you're planning on doing for bad block marker migration. I am not going to let you ignore this. NACK until you have a migration tool, and a scheme for marking the flash as having been migrated.
Quoted 5 lines
[Shengzhou]
This is the first time that you asked me about bad block marker migration. You asked LiuShuo several times in Linux mail list, as I am not in that thread And not known about it until Liushuo told me.
As LiuShuo will do it, so I am not planning on it.
Ah, sorry about that.
Still, I'd like to see it done, whoever does it, before this gets merged. I don't want people to be able to accidentally start using it without doing migration.
Quoted 8 lines
Quoted 7 lines
drivers/mtd/nand/fsl_elbc_nand.c int board_nand_init(struct nand_chip *nand) · line 1010
Quoted 3 lines
drivers/mtd/nand/fsl_elbc_nand.c +3
-0+ nand->ecc.layout = (priv->fmr &FMR_ECCM ) ? + &fsl_elbc_oob_lp_eccm1 : &fsl_elbc_oob_lp_eccm0; + nand->badblock_pattern = &largepage_memorybased;Those oob layouts won't be quite right for larger page sizes.
-Scott
[Shengzhou] It's the same with what Linux does. What's the right?
I think we need to explicitly define 4096 and 8192 variants, with the extra eccpos/oobfree. Or generate them programatically.
-Scott
A message that is not in the archive (sent off-list or not yet received): 3F453DDFF675A64A89321A1F352810216C4934@039-SN1MPN1-005.039d.mgd.msft.net
PATCH v2 5/5 mtd/nand: workaround for Freescale FCM to support 4k pagesize Nand chip
Quoted 24 lines · On 12/15/2011 04:53 AM, Liu Shengzhou-B36685 wrote:
Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
-----Original Message-----
From: Wood Scott-B07421
Sent: Tuesday, December 13, 2011 4:14 AM
To: Liu Shengzhou-B36685
Cc: u-boot at lists.denx.de; Gala Kumar-B11780; Liu Shuo-B35362
Subject: Re: [PATCH 5/5 v2] mtd/nand: workaround for Freescale FCM to support 4k pagesize Nand chipdrivers/mtd/nand/fsl_elbc_nand.c int board_nand_init(struct nand_chip *nand) · line 1010
Quoted 3 lines
drivers/mtd/nand/fsl_elbc_nand.c +3
-0+ nand->ecc.layout = (priv->fmr &FMR_ECCM ) ? + &fsl_elbc_oob_lp_eccm1 : &fsl_elbc_oob_lp_eccm0; + nand->badblock_pattern = &largepage_memorybased;Those oob layouts won't be quite right for larger page sizes.
Quoted 7 lines
Quoted 2 lines
Quoted 1 line
-Scott
[Shengzhou] It's the same with what Linux does. What's the right?
I think we need to explicitly define 4096 and 8192 variants, with the extra eccpos/oobfree. Or generate them programatically.
-Scott
[Shengzhou]
You mean we should define something like below?
Quoted 7 lines
static struct nand_ecclayout fsl_elbc_oob_lp_4k_eccm0 = { .eccbytes = 24, .eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56, 70, 71, 72, 86, 87, 88, 102, 103, 104, 118, 119, 120}, .oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7},...... }, };static struct
nand_ecclayoutfsl_elbc_oob_lp_8k_eccm0= {........};
Yes.
Quoted 5 lines
eLBC RM says:
ECC is checked/calculated over 512-Byte blocks. A 24-bit ECC is assigned to spare region bytes at offsets
(N ? 16) + 6 through (N ? 16) + 8 for spare region N, N = 0?3. (for ECCM=0 case)Here RM just says N is 0?3, but it should be 0-7 for 4096 case,
Well, yes, this is a hack to do things that the hardware doesn't officially support.
Quoted 1 line
hardware ECC doesn't generate ECC in position of N=4,5,6,7.
It will. It just thinks that N=0,1,2,3.
Quoted 1 line
fsl_elbc_oob_lp_eccm0andfsl_elbc_oob_lp_eccm1are controller-associated, not device-associated,
Then why do we have separate small and large page versions?
Quoted 3 lines
I think we don't need define 4096 and 8192 variants, it's emulating 4096/8192 case by the existing 2K layout of
fsl_elbc_oob_lp_eccm0andfsl_elbc_oob_lp_eccm1. Please correct me if any wrong understanding.
It's supporting 4096/8192 by repeating the 2048 layout multiple times. This repetition is not captured by the existing nand_ecclayout.
-Scott
PATCH v2 4/5 mtd/nand: Add ONFI support for FSL NAND controller
In reply to Shengzhou LiuQuoted 7 lines · Shengzhou Liu
- fix
NAND_CMD_READIDcommand for ONFI detect.
- addNAND_CMD_PARAMcommand to read the ONFI parameter page.Signed-off-by Shengzhou Liu <[email protected]>--- drivers/mtd/nand/fsl_elbc_nand.c | 17 ++++++++++------- 1 files changed, 10 insertions(+), 7 deletions(-)
Applied to u-boot-nand-flash
-Scott
PATCH v2 3/5 mtd/nand: remove CONFIG_SYS_NAND_ONFI_DETECTION to enable ONFI detection
In reply to Shengzhou LiuQuoted 3 lines · Shengzhou Liu
remove
CONFIG_SYS_NAND_ONFI_DETECTIONto enable ONFI detection.Signed-off-by Shengzhou Liu <[email protected]>
Why?
-Scott
A message that is not in the archive (sent off-list or not yet received): 3F453DDFF675A64A89321A1F352810216BECF4@039-SN1MPN1-005.039d.mgd.msft.net
PATCH v2 3/5 mtd/nand: remove CONFIG_SYS_NAND_ONFI_DETECTION to enable ONFI detection
Quoted 14 lines · On 12/13/2011 08:37 PM, Liu Shengzhou-B36685 wrote:
Quoted 14 lines
-----Original Message-----
From: Wood Scott-B07421
Sent: Tuesday, December 13, 2011 2:42 AM
To: Liu Shengzhou-B36685
Cc: u-boot at lists.denx.de; Gala Kumar-B11780
Subject: Re: [PATCH 3/5 v2] mtd/nand: removeCONFIG_SYS_NAND_ONFI_DETECTIONto enable ONFI detectionQuoted 3 lines · Shengzhou Liu
remove
CONFIG_SYS_NAND_ONFI_DETECTIONto enable ONFI detection.Signed-off-by Shengzhou Liu <[email protected]>
Quoted 7 lines
Quoted 3 lines
Why?
-Scott
[Shengzhou]
There is not necessity toCONFIG_SYS_NAND_ONFI_DETECTIONnow. We should always enable ONFI detection as what Linux does.
Linux has fewer concerns about code size than U-Boot does.
-Scott