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

📄 nand_base.c

📁 uboot200903最新版本的通用uboot
💻 C
📖 第 1 页 / 共 5 页
字号:
	reset_timer();	/* wait until command is processed or timeout occures */	while (get_timer(0) < timeo) {		if (chip->dev_ready)			if (chip->dev_ready(mtd))				break;	}}#endif/** * nand_command - [DEFAULT] Send command to NAND device * @mtd:	MTD device structure * @command:	the command to be sent * @column:	the column address for this command, -1 if none * @page_addr:	the page address for this command, -1 if none * * Send command to NAND device. This function is used for small page * devices (256/512 Bytes per page) */static void nand_command(struct mtd_info *mtd, unsigned int command,			 int column, int page_addr){	register struct nand_chip *chip = mtd->priv;	int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;	uint32_t rst_sts_cnt = CONFIG_SYS_NAND_RESET_CNT;	/*	 * Write out the command to the device.	 */	if (command == NAND_CMD_SEQIN) {		int readcmd;		if (column >= mtd->writesize) {			/* OOB area */			column -= mtd->writesize;			readcmd = NAND_CMD_READOOB;		} else if (column < 256) {			/* First 256 bytes --> READ0 */			readcmd = NAND_CMD_READ0;		} else {			column -= 256;			readcmd = NAND_CMD_READ1;		}		chip->cmd_ctrl(mtd, readcmd, ctrl);		ctrl &= ~NAND_CTRL_CHANGE;	}	chip->cmd_ctrl(mtd, command, ctrl);	/*	 * Address cycle, when necessary	 */	ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;	/* Serially input address */	if (column != -1) {		/* Adjust columns for 16 bit buswidth */		if (chip->options & NAND_BUSWIDTH_16)			column >>= 1;		chip->cmd_ctrl(mtd, column, ctrl);		ctrl &= ~NAND_CTRL_CHANGE;	}	if (page_addr != -1) {		chip->cmd_ctrl(mtd, page_addr, ctrl);		ctrl &= ~NAND_CTRL_CHANGE;		chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);		/* One more address cycle for devices > 32MiB */		if (chip->chipsize > (32 << 20))			chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);	}	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);	/*	 * program and erase have their own busy handlers	 * status and sequential in needs no delay	 */	switch (command) {	case NAND_CMD_PAGEPROG:	case NAND_CMD_ERASE1:	case NAND_CMD_ERASE2:	case NAND_CMD_SEQIN:	case NAND_CMD_STATUS:		return;	case NAND_CMD_RESET:		if (chip->dev_ready)			break;		udelay(chip->chip_delay);		chip->cmd_ctrl(mtd, NAND_CMD_STATUS,			       NAND_CTRL_CLE | NAND_CTRL_CHANGE);		chip->cmd_ctrl(mtd,			       NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);		while (!(chip->read_byte(mtd) & NAND_STATUS_READY) &&			(rst_sts_cnt--));		return;		/* This applies to read commands */	default:		/*		 * If we don't have access to the busy pin, we apply the given		 * command delay		 */		if (!chip->dev_ready) {			udelay(chip->chip_delay);			return;		}	}	/* Apply this short delay always to ensure that we do wait tWB in	 * any case on any machine. */	ndelay(100);	nand_wait_ready(mtd);}/** * nand_command_lp - [DEFAULT] Send command to NAND large page device * @mtd:	MTD device structure * @command:	the command to be sent * @column:	the column address for this command, -1 if none * @page_addr:	the page address for this command, -1 if none * * Send command to NAND device. This is the version for the new large page * devices We dont have the separate regions as we have in the small page * devices.  We must emulate NAND_CMD_READOOB to keep the code compatible. */static void nand_command_lp(struct mtd_info *mtd, unsigned int command,			    int column, int page_addr){	register struct nand_chip *chip = mtd->priv;	uint32_t rst_sts_cnt = CONFIG_SYS_NAND_RESET_CNT;	/* Emulate NAND_CMD_READOOB */	if (command == NAND_CMD_READOOB) {		column += mtd->writesize;		command = NAND_CMD_READ0;	}	/* Command latch cycle */	chip->cmd_ctrl(mtd, command & 0xff,		       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);	if (column != -1 || page_addr != -1) {		int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;		/* Serially input address */		if (column != -1) {			/* Adjust columns for 16 bit buswidth */			if (chip->options & NAND_BUSWIDTH_16)				column >>= 1;			chip->cmd_ctrl(mtd, column, ctrl);			ctrl &= ~NAND_CTRL_CHANGE;			chip->cmd_ctrl(mtd, column >> 8, ctrl);		}		if (page_addr != -1) {			chip->cmd_ctrl(mtd, page_addr, ctrl);			chip->cmd_ctrl(mtd, page_addr >> 8,				       NAND_NCE | NAND_ALE);			/* One more address cycle for devices > 128MiB */			if (chip->chipsize > (128 << 20))				chip->cmd_ctrl(mtd, page_addr >> 16,					       NAND_NCE | NAND_ALE);		}	}	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);	/*	 * program and erase have their own busy handlers	 * status, sequential in, and deplete1 need no delay	 */	switch (command) {	case NAND_CMD_CACHEDPROG:	case NAND_CMD_PAGEPROG:	case NAND_CMD_ERASE1:	case NAND_CMD_ERASE2:	case NAND_CMD_SEQIN:	case NAND_CMD_RNDIN:	case NAND_CMD_STATUS:	case NAND_CMD_DEPLETE1:		return;		/*		 * read error status commands require only a short delay		 */	case NAND_CMD_STATUS_ERROR:	case NAND_CMD_STATUS_ERROR0:	case NAND_CMD_STATUS_ERROR1:	case NAND_CMD_STATUS_ERROR2:	case NAND_CMD_STATUS_ERROR3:		udelay(chip->chip_delay);		return;	case NAND_CMD_RESET:		if (chip->dev_ready)			break;		udelay(chip->chip_delay);		chip->cmd_ctrl(mtd, NAND_CMD_STATUS,			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);		chip->cmd_ctrl(mtd, NAND_CMD_NONE,			       NAND_NCE | NAND_CTRL_CHANGE);		while (!(chip->read_byte(mtd) & NAND_STATUS_READY) &&			(rst_sts_cnt--));		return;	case NAND_CMD_RNDOUT:		/* No ready / busy check necessary */		chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);		chip->cmd_ctrl(mtd, NAND_CMD_NONE,			       NAND_NCE | NAND_CTRL_CHANGE);		return;	case NAND_CMD_READ0:		chip->cmd_ctrl(mtd, NAND_CMD_READSTART,			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);		chip->cmd_ctrl(mtd, NAND_CMD_NONE,			       NAND_NCE | NAND_CTRL_CHANGE);		/* This applies to read commands */	default:		/*		 * If we don't have access to the busy pin, we apply the given		 * command delay		 */		if (!chip->dev_ready) {			udelay(chip->chip_delay);			return;		}	}	/* Apply this short delay always to ensure that we do wait tWB in	 * any case on any machine. */	ndelay(100);	nand_wait_ready(mtd);}/** * nand_get_device - [GENERIC] Get chip for selected access * @chip:	the nand chip descriptor * @mtd:	MTD device structure * @new_state:	the state which is requested * * Get the device and lock it for exclusive access *//* XXX U-BOOT XXX */#if 0static intnand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state){	spinlock_t *lock = &chip->controller->lock;	wait_queue_head_t *wq = &chip->controller->wq;	DECLARE_WAITQUEUE(wait, current); retry:	spin_lock(lock);	/* Hardware controller shared among independend devices */	/* Hardware controller shared among independend devices */	if (!chip->controller->active)		chip->controller->active = chip;	if (chip->controller->active == chip && chip->state == FL_READY) {		chip->state = new_state;		spin_unlock(lock);		return 0;	}	if (new_state == FL_PM_SUSPENDED) {		spin_unlock(lock);		return (chip->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;	}	set_current_state(TASK_UNINTERRUPTIBLE);	add_wait_queue(wq, &wait);	spin_unlock(lock);	schedule();	remove_wait_queue(wq, &wait);	goto retry;}#elsestatic int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state){	this->state = new_state;	return 0;}#endif/** * nand_wait - [DEFAULT]  wait until the command is done * @mtd:	MTD device structure * @chip:	NAND chip structure * * Wait for command done. This applies to erase and program only * Erase can take up to 400ms and program up to 20ms according to * general NAND and SmartMedia specs *//* XXX U-BOOT XXX */#if 0static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip){	unsigned long timeo = jiffies;	int status, state = chip->state;	if (state == FL_ERASING)		timeo += (HZ * 400) / 1000;	else		timeo += (HZ * 20) / 1000;	led_trigger_event(nand_led_trigger, LED_FULL);	/* Apply this short delay always to ensure that we do wait tWB in	 * any case on any machine. */	ndelay(100);	if ((state == FL_ERASING) && (chip->options & NAND_IS_AND))		chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);	else		chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);	while (time_before(jiffies, timeo)) {		if (chip->dev_ready) {			if (chip->dev_ready(mtd))				break;		} else {			if (chip->read_byte(mtd) & NAND_STATUS_READY)				break;		}		cond_resched();	}	led_trigger_event(nand_led_trigger, LED_OFF);	status = (int)chip->read_byte(mtd);	return status;}#elsestatic int nand_wait(struct mtd_info *mtd, struct nand_chip *this){	unsigned long	timeo;	int state = this->state;	if (state == FL_ERASING)		timeo = (CONFIG_SYS_HZ * 400) / 1000;	else		timeo = (CONFIG_SYS_HZ * 20) / 1000;	if ((state == FL_ERASING) && (this->options & NAND_IS_AND))		this->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);	else		this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);	reset_timer();	while (1) {		if (get_timer(0) > timeo) {			printf("Timeout!");			return 0x01;		}		if (this->dev_ready) {			if (this->dev_ready(mtd))				break;		} else {			if (this->read_byte(mtd) & NAND_STATUS_READY)				break;		}	}#ifdef PPCHAMELON_NAND_TIMER_HACK	reset_timer();	while (get_timer(0) < 10);#endif /*  PPCHAMELON_NAND_TIMER_HACK */	return this->read_byte(mtd);}#endif/** * nand_read_page_raw - [Intern] read raw page data without ecc * @mtd:	mtd info structure * @chip:	nand chip info structure * @buf:	buffer to store read data */static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,			      uint8_t *buf){	chip->read_buf(mtd, buf, mtd->writesize);	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);	return 0;}/** * nand_read_page_swecc - [REPLACABLE] software ecc based page read function * @mtd:	mtd info structure * @chip:	nand chip info structure * @buf:	buffer to store read data */static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,				uint8_t *buf){	int i, eccsize = chip->ecc.size;	int eccbytes = chip->ecc.bytes;	int eccsteps = chip->ecc.steps;	uint8_t *p = buf;	uint8_t *ecc_calc = chip->buffers->ecccalc;	uint8_t *ecc_code = chip->buffers->ecccode;	uint32_t *eccpos = chip->ecc.layout->eccpos;	chip->ecc.read_page_raw(mtd, chip, buf);	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)		chip->ecc.calculate(mtd, p, &ecc_calc[i]);	for (i = 0; i < chip->ecc.total; i++)		ecc_code[i] = chip->oob_poi[eccpos[i]];	eccsteps = chip->ecc.steps;	p = buf;	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {		int stat;		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);		if (stat < 0)			mtd->ecc_stats.failed++;		else			mtd->ecc_stats.corrected += stat;	}	return 0;}/** * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function * @mtd:	mtd info structure * @chip:	nand chip info structure * @dataofs	offset of requested data within the page * @readlen	data length * @buf:	buffer to store read data */static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi){	int start_step, end_step, num_steps;	uint32_t *eccpos = chip->ecc.layout->eccpos;	uint8_t *p;	int data_col_addr, i, gaps = 0;	int datafrag_len, eccfrag_len, aligned_len, aligned_pos;	int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;	/* Column address wihin the page aligned to ECC size (256bytes). */	start_step = data_offs / chip->ecc.size;	end_step = (data_offs + readlen - 1) / chip->ecc.size;	num_steps = end_step - start_step + 1;	/* Data size aligned to ECC ecc.size*/	datafrag_len = num_steps * chip->ecc.size;	eccfrag_len = num_steps * chip->ecc.bytes;	data_col_addr = start_step * chip->ecc.size;	/* If we read not a page aligned data */	if (data_col_addr != 0)		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);	p = bufpoi + data_col_addr;	chip->read_buf(mtd, p, datafrag_len);	/* Calculate  ECC */	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)		chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]);	/* The performance is faster if to position offsets	   according to ecc.pos. Let make sure here that	   there are no gaps in ecc positions */	for (i = 0; i < eccfrag_len - 1; i++) {		if (eccpos[i + start_step * chip->ecc.bytes] + 1 !=			eccpos[i + start_step * chip->ecc.bytes + 1]) {			gaps = 1;			break;		}	}	if (gaps) {		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);	} else {		/* send the command to read the particular ecc bytes */		/* take care about buswidth alignment in read_buf */		aligned_pos = eccpos[start_step * chip->ecc.bytes] & ~(busw - 1);		aligned_len = eccfrag_len;		if (eccpos[start_step * chip->ecc.bytes] & (busw - 1))			aligned_len++;		if (eccpos[(start_step + num_steps) * chip->ecc.bytes] & (busw - 1))			aligned_len++;		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize + aligned_pos, -1);		chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);	}	for (i = 0; i < eccfrag_len; i++)		chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + start_step * chip->ecc.bytes]];	p = bufpoi + data_col_addr;	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {		int stat;		stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);		if (stat < 0)			mtd->ecc_stats.failed++;		else			mtd->ecc_stats.corrected += stat;	}	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -