📄 fsl_elbc_nand.c
字号:
(FIR_OP_WB << FIR_OP4_SHIFT) | (FIR_OP_CW1 << FIR_OP5_SHIFT)); if (column >= mtd->writesize) { /* 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; } else { /* Second 256 bytes --> READ1 */ fcr |= NAND_CMD_READ1 << FCR_CMD0_SHIFT; } } out_be32(&lbc->fcr, fcr); 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 full_page; vdbg("fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " "writing %d bytes.\n", ctrl->index); /* if the write did not start at 0 or is not a full page * then set the exact length, otherwise use a full page * write so the HW generates the ECC. */ if (ctrl->oob || ctrl->column != 0 || ctrl->index != mtd->writesize + mtd->oobsize) { out_be32(&lbc->fbcr, ctrl->index); full_page = 0; } else { out_be32(&lbc->fbcr, 0); full_page = 1; } fsl_elbc_run_command(mtd); /* Read back the page in order to fill in the ECC for the * caller. Is this really needed? */ if (full_page && ctrl->oob_poi) { out_be32(&lbc->fbcr, 3); set_addr(mtd, 6, page_addr, 1); ctrl->read_bytes = mtd->writesize + 9; fsl_elbc_do_read(chip, 1); fsl_elbc_run_command(mtd); memcpy_fromio(ctrl->oob_poi + 6, &ctrl->addr[ctrl->index], 3); ctrl->index += 3; } ctrl->oob_poi = NULL; return; } /* CMD_STATUS must read the status byte while CEB is active */ /* 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)); out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT); out_be32(&lbc->fbcr, 1); set_addr(mtd, 0, 0, 0); ctrl->read_bytes = 1; fsl_elbc_run_command(mtd); /* The chip always seems to report that it is * write-protected, even when it is not. */ out_8(ctrl->addr, in_8(ctrl->addr) | NAND_STATUS_WP); return; /* RESET without waiting for the ready line */ case NAND_CMD_RESET: dbg("fsl_elbc_cmdfunc: NAND_CMD_RESET.\n"); out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT); out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT); fsl_elbc_run_command(mtd); return; default: printf("fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n", command); }}static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip){ /* The hardware does not seem to support multiple * chips per bank. */}/* * Write buf to the FCM Controller Data Buffer */static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len){ struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; struct fsl_elbc_ctrl *ctrl = priv->ctrl; unsigned int bufsize = mtd->writesize + mtd->oobsize; if (len <= 0) { printf("write_buf of %d bytes", len); ctrl->status = 0; return; } if ((unsigned int)len > bufsize - ctrl->index) { printf("write_buf beyond end of buffer " "(%d requested, %u available)\n", len, bufsize - ctrl->index); len = bufsize - ctrl->index; } 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 * write to make it through the localbus compared to a write to IMMR * is causing problems, and sync isn't helping for some reason." * Reading back the last byte helps though. */ in_8(&ctrl->addr[ctrl->index] + len - 1); ctrl->index += len;}/* * read a byte from either the FCM hardware buffer if it has any data left * otherwise issue a command to read a single byte. */static u8 fsl_elbc_read_byte(struct mtd_info *mtd){ struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; 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++]); printf("read_byte beyond end of buffer\n"); return ERR_BYTE;}/* * Read from the FCM Controller Data Buffer */static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len){ struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; struct fsl_elbc_ctrl *ctrl = priv->ctrl; int avail; if (len < 0) return; avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index); memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail); ctrl->index += avail; if (len > avail) printf("read_buf beyond end of buffer " "(%d requested, %d available)\n", len, avail);}/* * Verify buffer against the FCM Controller Data Buffer */static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len){ struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; struct fsl_elbc_ctrl *ctrl = priv->ctrl; int i; if (len < 0) { printf("write_buf of %d bytes", len); return -EINVAL; } if ((unsigned int)len > ctrl->read_bytes - ctrl->index) { printf("verify_buf beyond end of buffer " "(%d requested, %u available)\n", len, ctrl->read_bytes - ctrl->index); ctrl->index = ctrl->read_bytes; return -EINVAL; } 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;}/* This function is called after Program and Erase Operations to * check for success or failure. */static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip){ struct fsl_elbc_mtd *priv = chip->priv; struct fsl_elbc_ctrl *ctrl = priv->ctrl; fsl_lbus_t *lbc = ctrl->regs; if (ctrl->status != LTESR_CC) return NAND_STATUS_FAIL; /* 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)); out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT); out_be32(&lbc->fbcr, 1); set_addr(mtd, 0, 0, 0); ctrl->read_bytes = 1; fsl_elbc_run_command(mtd); if (ctrl->status != LTESR_CC) return NAND_STATUS_FAIL; /* The chip always seems to report that it is * write-protected, even when it is not. */ out_8(ctrl->addr, in_8(ctrl->addr) | NAND_STATUS_WP); return fsl_elbc_read_byte(mtd);}static int fsl_elbc_read_page(struct mtd_info *mtd, 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); if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL) mtd->ecc_stats.failed++; return 0;}/* ECC will be calculated automatically, and errors will be detected in * waitfunc. */static void fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf){ struct fsl_elbc_mtd *priv = chip->priv; struct fsl_elbc_ctrl *ctrl = priv->ctrl; fsl_elbc_write_buf(mtd, buf, mtd->writesize); fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); ctrl->oob_poi = chip->oob_poi;}static struct fsl_elbc_ctrl *elbc_ctrl;static void fsl_elbc_ctrl_init(void){ elbc_ctrl = kzalloc(sizeof(*elbc_ctrl), GFP_KERNEL); if (!elbc_ctrl) return;#ifdef CONFIG_MPC85xx elbc_ctrl->regs = (void *)CONFIG_SYS_MPC85xx_LBC_ADDR;#else elbc_ctrl->regs = &((immap_t *)CONFIG_SYS_IMMR)->lbus;#endif /* clear event registers */ out_be32(&elbc_ctrl->regs->ltesr, LTESR_NAND_MASK); out_be32(&elbc_ctrl->regs->lteatr, 0); /* Enable interrupts for any detected events */ out_be32(&elbc_ctrl->regs->lteir, LTESR_NAND_MASK); elbc_ctrl->read_bytes = 0; elbc_ctrl->index = 0; elbc_ctrl->addr = NULL;}int board_nand_init(struct nand_chip *nand){ struct fsl_elbc_mtd *priv; uint32_t br = 0, or = 0; if (!elbc_ctrl) { fsl_elbc_ctrl_init(); if (!elbc_ctrl) return -1; } priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; priv->ctrl = elbc_ctrl; priv->vbase = nand->IO_ADDR_R; /* Find which chip select it is connected to. It'd be nice * if we could pass more than one datum to the NAND driver... */ for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) { phys_addr_t base_addr = virt_to_phys(nand->IO_ADDR_R); br = in_be32(&elbc_ctrl->regs->bank[priv->bank].br); or = in_be32(&elbc_ctrl->regs->bank[priv->bank].or); if ((br & BR_V) && (br & BR_MSEL) == BR_MS_FCM && (br & or & BR_BA) == BR_PHYS_ADDR(base_addr)) break; } if (priv->bank >= MAX_BANKS) { printf("fsl_elbc_nand: address did not match any " "chip selects\n"); return -ENODEV; } elbc_ctrl->chips[priv->bank] = priv; /* fill in nand_chip structure */ /* set up function call table */ nand->read_byte = fsl_elbc_read_byte; nand->write_buf = fsl_elbc_write_buf; nand->read_buf = fsl_elbc_read_buf; nand->verify_buf = fsl_elbc_verify_buf; nand->select_chip = fsl_elbc_select_chip; nand->cmdfunc = fsl_elbc_cmdfunc; nand->waitfunc = fsl_elbc_wait; /* set up nand options */ 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.read_page = fsl_elbc_read_page; nand->ecc.write_page = fsl_elbc_write_page;#ifdef CONFIG_FSL_ELBC_FMR priv->fmr = CONFIG_FSL_ELBC_FMR;#else priv->fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT); /* * Hardware expects small page has ECCM0, large page has ECCM1 * when booting from NAND. Board config can override if not * booting from NAND. */ if (or & OR_FCM_PGS) priv->fmr |= FMR_ECCM;#endif /* If CS Base Register selects full hardware ECC then use it */ if ((br & BR_DECC) == BR_DECC_CHK_GEN) { nand->ecc.mode = NAND_ECC_HW; nand->ecc.layout = (priv->fmr & FMR_ECCM) ? &fsl_elbc_oob_sp_eccm1 : &fsl_elbc_oob_sp_eccm0; nand->ecc.size = 512; nand->ecc.bytes = 3; nand->ecc.steps = 1; } else { /* otherwise fall back to default software ECC */ nand->ecc.mode = NAND_ECC_SOFT; } /* 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; } } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -