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

📄 cfi_cmdset_0001.c

📁 飞思卡尔芯片imx27下的MTD模块的驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		len -= n;		ofs += n;		buf += n;		(*retlen) += n;		if (ofs >> cfi->chipshift) {			chipnum ++;			ofs = 0;			if (chipnum == cfi->numchips)				return 0;		}	}	while(len >= map_bankwidth(map)) {		map_word datum = map_word_load(map, buf);		ret = do_write_oneword(map, &cfi->chips[chipnum],				       ofs, datum, FL_WRITING);		if (ret)			return ret;		ofs += map_bankwidth(map);		buf += map_bankwidth(map);		(*retlen) += map_bankwidth(map);		len -= map_bankwidth(map);		if (ofs >> cfi->chipshift) {			chipnum ++;			ofs = 0;			if (chipnum == cfi->numchips)				return 0;		}	}	if (len & (map_bankwidth(map)-1)) {		map_word datum;		datum = map_word_ff(map);		datum = map_word_load_partial(map, datum, buf, 0, len);		ret = do_write_oneword(map, &cfi->chips[chipnum],				       ofs, datum, FL_WRITING);		if (ret)			return ret;		(*retlen) += len;	}	return 0;}static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,				    unsigned long adr, const struct kvec **pvec,				    unsigned long *pvec_seek, int len){	struct cfi_private *cfi = map->fldrv_priv;	map_word status, write_cmd, datum;	unsigned long cmd_adr;	int ret, wbufsize, word_gap, words;	const struct kvec *vec;	unsigned long vec_seek;	wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;	adr += chip->start;	cmd_adr = adr & ~(wbufsize-1);	/* Let's determine this according to the interleave only once */	write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9);	spin_lock(chip->mutex);	ret = get_chip(map, chip, cmd_adr, FL_WRITING);	if (ret) {		spin_unlock(chip->mutex);		return ret;	}	XIP_INVAL_CACHED_RANGE(map, adr, len);	ENABLE_VPP(map);	xip_disable(map, chip, cmd_adr);	/* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set	   [...], the device will not accept any more Write to Buffer commands".	   So we must check here and reset those bits if they're set. Otherwise	   we're just pissing in the wind */	if (chip->state != FL_STATUS) {		map_write(map, CMD(0x70), cmd_adr);		chip->state = FL_STATUS;	}	status = map_read(map, cmd_adr);	if (map_word_bitsset(map, status, CMD(0x30))) {		xip_enable(map, chip, cmd_adr);		printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %lx). Clearing.\n", status.x[0]);		xip_disable(map, chip, cmd_adr);		map_write(map, CMD(0x50), cmd_adr);		map_write(map, CMD(0x70), cmd_adr);	}	chip->state = FL_WRITING_TO_BUFFER;	map_write(map, write_cmd, cmd_adr);	ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0);	if (ret) {		/* Argh. Not ready for write to buffer */		map_word Xstatus = map_read(map, cmd_adr);		map_write(map, CMD(0x70), cmd_adr);		chip->state = FL_STATUS;		status = map_read(map, cmd_adr);		map_write(map, CMD(0x50), cmd_adr);		map_write(map, CMD(0x70), cmd_adr);		xip_enable(map, chip, cmd_adr);		printk(KERN_ERR "%s: Chip not ready for buffer write. Xstatus = %lx, status = %lx\n",				map->name, Xstatus.x[0], status.x[0]);		goto out;	}	/* Figure out the number of words to write */	word_gap = (-adr & (map_bankwidth(map)-1));	words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map);	if (!word_gap) {		words--;	} else {		word_gap = map_bankwidth(map) - word_gap;		adr -= word_gap;		datum = map_word_ff(map);	}	/* Write length of data to come */	map_write(map, CMD(words), cmd_adr );	/* Write data */	vec = *pvec;	vec_seek = *pvec_seek;	do {		int n = map_bankwidth(map) - word_gap;		if (n > vec->iov_len - vec_seek)			n = vec->iov_len - vec_seek;		if (n > len)			n = len;		if (!word_gap && len < map_bankwidth(map))			datum = map_word_ff(map);		datum = map_word_load_partial(map, datum,					      vec->iov_base + vec_seek,					      word_gap, n);		len -= n;		word_gap += n;		if (!len || word_gap == map_bankwidth(map)) {			map_write(map, datum, adr);			adr += map_bankwidth(map);			word_gap = 0;		}		vec_seek += n;		if (vec_seek == vec->iov_len) {			vec++;			vec_seek = 0;		}	} while (len);	*pvec = vec;	*pvec_seek = vec_seek;	/* GO GO GO */	map_write(map, CMD(0xd0), cmd_adr);	chip->state = FL_WRITING;	ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr,				   adr, len,				   chip->buffer_write_time);	if (ret) {		map_write(map, CMD(0x70), cmd_adr);		chip->state = FL_STATUS;		xip_enable(map, chip, cmd_adr);		printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name);		goto out;	}	/* check for errors */	status = map_read(map, cmd_adr);	if (map_word_bitsset(map, status, CMD(0x1a))) {		unsigned long chipstatus = MERGESTATUS(status);		/* reset status */		map_write(map, CMD(0x50), cmd_adr);		map_write(map, CMD(0x70), cmd_adr);		xip_enable(map, chip, cmd_adr);		if (chipstatus & 0x02) {			ret = -EROFS;		} else if (chipstatus & 0x08) {			printk(KERN_ERR "%s: buffer write error (bad VPP)\n", map->name);			ret = -EIO;		} else {			printk(KERN_ERR "%s: buffer write error (status 0x%lx)\n", map->name, chipstatus);			ret = -EINVAL;		}		goto out;	}	xip_enable(map, chip, cmd_adr); out:	put_chip(map, chip, cmd_adr);	spin_unlock(chip->mutex);	return ret;}static int cfi_intelext_writev (struct mtd_info *mtd, const struct kvec *vecs,				unsigned long count, loff_t to, size_t *retlen){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;	int ret = 0;	int chipnum;	unsigned long ofs, vec_seek, i;	size_t len = 0;	for (i = 0; i < count; i++)		len += vecs[i].iov_len;	*retlen = 0;	if (!len)		return 0;	chipnum = to >> cfi->chipshift;	ofs = to - (chipnum << cfi->chipshift);	vec_seek = 0;	do {		/* We must not cross write block boundaries */		int size = wbufsize - (ofs & (wbufsize-1));		if (size > len)			size = len;		ret = do_write_buffer(map, &cfi->chips[chipnum],				      ofs, &vecs, &vec_seek, size);		if (ret)			return ret;		ofs += size;		(*retlen) += size;		len -= size;		if (ofs >> cfi->chipshift) {			chipnum ++;			ofs = 0;			if (chipnum == cfi->numchips)				return 0;		}		/* Be nice and reschedule with the chip in a usable state for other		   processes. */		cond_resched();	} while (len);	return 0;}static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to,				       size_t len, size_t *retlen, const u_char *buf){	struct kvec vec;	vec.iov_base = (void *) buf;	vec.iov_len = len;	return cfi_intelext_writev(mtd, &vec, 1, to, retlen);}static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,				      unsigned long adr, int len, void *thunk){	struct cfi_private *cfi = map->fldrv_priv;	map_word status;	int retries = 3;	int ret;	adr += chip->start; retry:	spin_lock(chip->mutex);	ret = get_chip(map, chip, adr, FL_ERASING);	if (ret) {		spin_unlock(chip->mutex);		return ret;	}	XIP_INVAL_CACHED_RANGE(map, adr, len);	ENABLE_VPP(map);	xip_disable(map, chip, adr);	/* Clear the status register first */	map_write(map, CMD(0x50), adr);	/* Now erase */	map_write(map, CMD(0x20), adr);	map_write(map, CMD(0xD0), adr);	chip->state = FL_ERASING;	chip->erase_suspended = 0;	ret = INVAL_CACHE_AND_WAIT(map, chip, adr,				   adr, len,				   chip->erase_time);	if (ret) {		map_write(map, CMD(0x70), adr);		chip->state = FL_STATUS;		xip_enable(map, chip, adr);		printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name);		goto out;	}	/* We've broken this before. It doesn't hurt to be safe */	map_write(map, CMD(0x70), adr);	chip->state = FL_STATUS;	status = map_read(map, adr);	/* check for errors */	if (map_word_bitsset(map, status, CMD(0x3a))) {		unsigned long chipstatus = MERGESTATUS(status);		/* Reset the error bits */		map_write(map, CMD(0x50), adr);		map_write(map, CMD(0x70), adr);		xip_enable(map, chip, adr);		if ((chipstatus & 0x30) == 0x30) {			printk(KERN_ERR "%s: block erase error: (bad command sequence, status 0x%lx)\n", map->name, chipstatus);			ret = -EINVAL;		} else if (chipstatus & 0x02) {			/* Protection bit set */			ret = -EROFS;		} else if (chipstatus & 0x8) {			/* Voltage */			printk(KERN_ERR "%s: block erase error: (bad VPP)\n", map->name);			ret = -EIO;		} else if (chipstatus & 0x20 && retries--) {			printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus);			put_chip(map, chip, adr);			spin_unlock(chip->mutex);			goto retry;		} else {			printk(KERN_ERR "%s: block erase failed at 0x%08lx (status 0x%lx)\n", map->name, adr, chipstatus);			ret = -EIO;		}		goto out;	}	xip_enable(map, chip, adr); out:	put_chip(map, chip, adr);	spin_unlock(chip->mutex);	return ret;}int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr){	unsigned long ofs, len;	int ret;	ofs = instr->addr;	len = instr->len;	ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL);	if (ret)		return ret;	instr->state = MTD_ERASE_DONE;	mtd_erase_callback(instr);	return 0;}static void cfi_intelext_sync (struct mtd_info *mtd){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	int i;	struct flchip *chip;	int ret = 0;	for (i=0; !ret && i<cfi->numchips; i++) {		chip = &cfi->chips[i];		spin_lock(chip->mutex);		ret = get_chip(map, chip, chip->start, FL_SYNCING);		if (!ret) {			chip->oldstate = chip->state;			chip->state = FL_SYNCING;			/* No need to wake_up() on this state change -			 * as the whole point is that nobody can do anything			 * with the chip now anyway.			 */		}		spin_unlock(chip->mutex);	}	/* Unlock the chips again */	for (i--; i >=0; i--) {		chip = &cfi->chips[i];		spin_lock(chip->mutex);		if (chip->state == FL_SYNCING) {			chip->state = chip->oldstate;			chip->oldstate = FL_READY;			wake_up(&chip->wq);		}		spin_unlock(chip->mutex);	}}#ifdef DEBUG_LOCK_BITSstatic int __xipram do_printlockstatus_oneblock(struct map_info *map,						struct flchip *chip,						unsigned long adr,						int len, void *thunk){	struct cfi_private *cfi = map->fldrv_priv;	int status, ofs_factor = cfi->interleave * cfi->device_type;	adr += chip->start;	xip_disable(map, chip, adr+(2*ofs_factor));	map_write(map, CMD(0x90), adr+(2*ofs_factor));	chip->state = FL_JEDEC_QUERY;	status = cfi_read_query(map, adr+(2*ofs_factor));	xip_enable(map, chip, 0);	printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",	       adr, status);	return 0;}#endif#define DO_XXLOCK_ONEBLOCK_LOCK		((void *) 1)#define DO_XXLOCK_ONEBLOCK_UNLOCK	((void *) 2)static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip,				       unsigned long adr, int len, void *thunk){	struct cfi_private *cfi = map->fldrv_priv;	struct cfi_pri_intelext *extp = cfi->cmdset_priv;	int udelay;	int ret;	adr += chip->start;	spin_lock(chip->mutex);	ret = get_chip(map, chip, adr, FL_LOCKING);	if (ret) {		spin_unlock(chip->mutex);		return ret;	}	ENABLE_VPP(map);	xip_disable(map, chip, adr);	map_write(map, CMD(0x60), adr);	if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) {		map_write(map, CMD(0x01), adr);		chip->state = FL_LOCKING;	} else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) {		map_write(map, CMD(0xD0), adr);		chip->state = FL_UNLOCKING;	} else

⌨️ 快捷键说明

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