.oobavail = 48,
};
+/*
+ * fsl_elbc_oob_lp_eccm* specify that LP NAND's OOB free area starts at offset
+ * 1, so we have to adjust bad block pattern. This pattern should be used for
+ * x8 chips only. So far hardware does not support x16 chips anyway.
+ */
+static u8 scan_ff_pattern[] = { 0xff, };
+
+static struct nand_bbt_descr largepage_memorybased = {
+ .options = 0,
+ .offs = 0,
+ .len = 1,
+ .pattern = scan_ff_pattern,
+};
+
+/*
+ * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt,
+ * interfere with ECC positions, that's why we implement our own descriptors.
+ * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0.
+ */
+static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+ NAND_BBT_2BIT | NAND_BBT_VERSION,
+ .offs = 11,
+ .len = 4,
+ .veroffs = 15,
+ .maxblocks = 4,
+ .pattern = bbt_pattern,
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+ NAND_BBT_2BIT | NAND_BBT_VERSION,
+ .offs = 11,
+ .len = 4,
+ .veroffs = 15,
+ .maxblocks = 4,
+ .pattern = mirror_pattern,
+};
+
/*=================================*/
/*
ctrl->page = page_addr;
- out_be32(&lbc->fbar,
- page_addr >> (chip->phys_erase_shift - chip->page_shift));
-
if (priv->page_size) {
+ 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);
+ ((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);
+ ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
+ (oob ? FPAR_SP_MS : 0) | column);
buf_num = page_addr & 7;
}
if (priv->page_size) {
out_be32(&lbc->fir,
- (FIR_OP_CW0 << FIR_OP0_SHIFT) |
- (FIR_OP_CA << FIR_OP1_SHIFT) |
- (FIR_OP_PA << FIR_OP2_SHIFT) |
- (FIR_OP_CW1 << FIR_OP3_SHIFT) |
- (FIR_OP_RBW << FIR_OP4_SHIFT));
+ (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_CA << FIR_OP1_SHIFT) |
+ (FIR_OP_PA << FIR_OP2_SHIFT) |
+ (FIR_OP_CW1 << FIR_OP3_SHIFT) |
+ (FIR_OP_RBW << FIR_OP4_SHIFT));
out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
- (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
+ (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
} else {
out_be32(&lbc->fir,
- (FIR_OP_CW0 << FIR_OP0_SHIFT) |
- (FIR_OP_CA << FIR_OP1_SHIFT) |
- (FIR_OP_PA << FIR_OP2_SHIFT) |
- (FIR_OP_RBW << FIR_OP3_SHIFT));
+ (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_CA << FIR_OP1_SHIFT) |
+ (FIR_OP_PA << FIR_OP2_SHIFT) |
+ (FIR_OP_RBW << FIR_OP3_SHIFT));
if (oob)
out_be32(&lbc->fcr,
- NAND_CMD_READOOB << FCR_CMD0_SHIFT);
+ NAND_CMD_READOOB << FCR_CMD0_SHIFT);
else
out_be32(&lbc->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT);
}
/* cmdfunc send commands to the FCM */
static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
- int column, int page_addr)
+ int column, int page_addr)
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
vdbg("fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) |
- (FIR_OP_UA << FIR_OP1_SHIFT) |
- (FIR_OP_RBW << FIR_OP2_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);
vdbg("fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
out_be32(&lbc->fir,
- (FIR_OP_CW0 << FIR_OP0_SHIFT) |
- (FIR_OP_PA << FIR_OP1_SHIFT) |
- (FIR_OP_CM1 << FIR_OP2_SHIFT));
+ (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_PA << FIR_OP1_SHIFT) |
+ (FIR_OP_CM1 << FIR_OP2_SHIFT));
out_be32(&lbc->fcr,
- (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
- (NAND_CMD_ERASE2 << FCR_CMD1_SHIFT));
+ (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
+ (NAND_CMD_ERASE2 << FCR_CMD1_SHIFT));
out_be32(&lbc->fbcr, 0);
ctrl->read_bytes = 0;
(NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT);
out_be32(&lbc->fir,
- (FIR_OP_CW0 << FIR_OP0_SHIFT) |
- (FIR_OP_CA << FIR_OP1_SHIFT) |
- (FIR_OP_PA << FIR_OP2_SHIFT) |
- (FIR_OP_WB << FIR_OP3_SHIFT) |
- (FIR_OP_CW1 << FIR_OP4_SHIFT));
+ (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_CA << FIR_OP1_SHIFT) |
+ (FIR_OP_PA << FIR_OP2_SHIFT) |
+ (FIR_OP_WB << FIR_OP3_SHIFT) |
+ (FIR_OP_CW1 << FIR_OP4_SHIFT));
} else {
fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) |
(NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
out_be32(&lbc->fir,
- (FIR_OP_CW0 << FIR_OP0_SHIFT) |
- (FIR_OP_CM2 << FIR_OP1_SHIFT) |
- (FIR_OP_CA << FIR_OP2_SHIFT) |
- (FIR_OP_PA << FIR_OP3_SHIFT) |
- (FIR_OP_WB << FIR_OP4_SHIFT) |
- (FIR_OP_CW1 << FIR_OP5_SHIFT));
+ (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_CM2 << FIR_OP1_SHIFT) |
+ (FIR_OP_CA << FIR_OP2_SHIFT) |
+ (FIR_OP_PA << FIR_OP3_SHIFT) |
+ (FIR_OP_WB << FIR_OP4_SHIFT) |
+ (FIR_OP_CW1 << FIR_OP5_SHIFT));
if (column >= mtd->writesize) {
/* OOB area --> READOOB */
fsl_elbc_run_command(mtd);
memcpy_fromio(ctrl->oob_poi + 6,
- &ctrl->addr[ctrl->index], 3);
+ &ctrl->addr[ctrl->index], 3);
ctrl->index += 3;
}
/* Note - it does not wait for the ready line */
case NAND_CMD_STATUS:
out_be32(&lbc->fir,
- (FIR_OP_CM0 << FIR_OP0_SHIFT) |
- (FIR_OP_RBW << FIR_OP1_SHIFT));
+ (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+ (FIR_OP_RBW << FIR_OP1_SHIFT));
out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
out_be32(&lbc->fbcr, 1);
set_addr(mtd, 0, 0, 0);
default:
printf("fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
- command);
+ command);
}
}
* Verify buffer against the FCM Controller Data Buffer
*/
static int fsl_elbc_verify_buf(struct mtd_info *mtd,
- const u_char *buf, int len)
+ const u_char *buf, int len)
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
/* Use READ_STATUS command, but wait for the device to be ready */
ctrl->use_mdr = 0;
out_be32(&lbc->fir,
- (FIR_OP_CW0 << FIR_OP0_SHIFT) |
- (FIR_OP_RBW << FIR_OP1_SHIFT));
+ (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_RBW << FIR_OP1_SHIFT));
out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
out_be32(&lbc->fbcr, 1);
set_addr(mtd, 0, 0, 0);
}
static int fsl_elbc_read_page(struct mtd_info *mtd,
- struct nand_chip *chip,
- uint8_t *buf)
+ struct nand_chip *chip,
+ uint8_t *buf)
{
fsl_elbc_read_buf(mtd, buf, mtd->writesize);
fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
* waitfunc.
*/
static void fsl_elbc_write_page(struct mtd_info *mtd,
- struct nand_chip *chip,
- const uint8_t *buf)
+ struct nand_chip *chip,
+ const uint8_t *buf)
{
struct fsl_elbc_mtd *priv = chip->priv;
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
nand->waitfunc = fsl_elbc_wait;
/* set up nand options */
- nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR;
+ nand->bbt_td = &bbt_main_descr;
+ nand->bbt_md = &bbt_mirror_descr;
+
+ /* set up nand options */
+ nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR |
+ NAND_USE_FLASH_BBT;
nand->controller = &elbc_ctrl->controller;
nand->priv = priv;
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.layout = (priv->fmr & FMR_ECCM) ?
- &fsl_elbc_oob_sp_eccm1 :
- &fsl_elbc_oob_sp_eccm0;
+ &fsl_elbc_oob_sp_eccm1 :
+ &fsl_elbc_oob_sp_eccm0;
nand->ecc.size = 512;
nand->ecc.bytes = 3;
priv->fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT);
- /* adjust Option Register and ECC to match Flash page size */
+ /* Large-page-specific setup */
if (or & OR_FCM_PGS) {
priv->page_size = 1;
+ nand->badblock_pattern = &largepage_memorybased;
/* adjust ecc setup if needed */
if ((br & BR_DECC) == BR_DECC_CHK_GEN) {
nand->ecc.steps = 4;
nand->ecc.layout = (priv->fmr & FMR_ECCM) ?
- &fsl_elbc_oob_lp_eccm1 :
- &fsl_elbc_oob_lp_eccm0;
+ &fsl_elbc_oob_lp_eccm1 :
+ &fsl_elbc_oob_lp_eccm0;
}
}