⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fsl_elbc_nand.c

📁 uboot200903最新版本的通用uboot
💻 C
📖 第 1 页 / 共 2 页
字号:
				 (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 + -