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

📄 cfi_cmdset_0001.c

📁 飞思卡尔芯片imx27下的MTD模块的驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
			 * another operation suspended (imagine what happens			 * when one chip was already done with the current			 * operation while another chip suspended it, then			 * we resume the whole thing at once).  Yes, it			 * can happen!			 */			usec -= done;			map_write(map, CMD(0xb0), adr);			map_write(map, CMD(0x70), adr);			suspended = xip_currtime();			do {				if (xip_elapsed_since(suspended) > 100000) {					/*					 * The chip doesn't want to suspend					 * after waiting for 100 msecs.					 * This is a critical error but there					 * is not much we can do here.					 */					return -EIO;				}				status = map_read(map, adr);			} while (!map_word_andequal(map, status, OK, OK));			/* Suspend succeeded */			oldstate = chip->state;			if (oldstate == FL_ERASING) {				if (!map_word_bitsset(map, status, CMD(0x40)))					break;				newstate = FL_XIP_WHILE_ERASING;				chip->erase_suspended = 1;			} else {				if (!map_word_bitsset(map, status, CMD(0x04)))					break;				newstate = FL_XIP_WHILE_WRITING;				chip->write_suspended = 1;			}			chip->state = newstate;			map_write(map, CMD(0xff), adr);			(void) map_read(map, adr);			asm volatile (".rep 8; nop; .endr");			local_irq_enable();			spin_unlock(chip->mutex);			asm volatile (".rep 8; nop; .endr");			cond_resched();			/*			 * We're back.  However someone else might have			 * decided to go write to the chip if we are in			 * a suspended erase state.  If so let's wait			 * until it's done.			 */			spin_lock(chip->mutex);			while (chip->state != newstate) {				DECLARE_WAITQUEUE(wait, current);				set_current_state(TASK_UNINTERRUPTIBLE);				add_wait_queue(&chip->wq, &wait);				spin_unlock(chip->mutex);				schedule();				remove_wait_queue(&chip->wq, &wait);				spin_lock(chip->mutex);			}			/* Disallow XIP again */			local_irq_disable();			/* Resume the write or erase operation */			map_write(map, CMD(0xd0), adr);			map_write(map, CMD(0x70), adr);			chip->state = oldstate;			start = xip_currtime();		} else if (usec >= 1000000/HZ) {			/*			 * Try to save on CPU power when waiting delay			 * is at least a system timer tick period.			 * No need to be extremely accurate here.			 */			xip_cpu_idle();		}		status = map_read(map, adr);		done = xip_elapsed_since(start);	} while (!map_word_andequal(map, status, OK, OK)		 && done < usec);	return (done >= usec) ? -ETIME : 0;}/* * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while * the flash is actively programming or erasing since we have to poll for * the operation to complete anyway.  We can't do that in a generic way with * a XIP setup so do it before the actual flash operation in this case * and stub it out from INVAL_CACHE_AND_WAIT. */#define XIP_INVAL_CACHED_RANGE(map, from, size)  \	INVALIDATE_CACHED_RANGE(map, from, size)#define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, usec) \	xip_wait_for_operation(map, chip, cmd_adr, usec)#else#define xip_disable(map, chip, adr)#define xip_enable(map, chip, adr)#define XIP_INVAL_CACHED_RANGE(x...)#define INVAL_CACHE_AND_WAIT inval_cache_and_wait_for_operationstatic int inval_cache_and_wait_for_operation(		struct map_info *map, struct flchip *chip,		unsigned long cmd_adr, unsigned long inval_adr, int inval_len,		unsigned int chip_op_time){	struct cfi_private *cfi = map->fldrv_priv;	map_word status, status_OK = CMD(0x80);	int chip_state = chip->state;	unsigned int timeo, sleep_time;	spin_unlock(chip->mutex);	if (inval_len)		INVALIDATE_CACHED_RANGE(map, inval_adr, inval_len);	spin_lock(chip->mutex);	/* set our timeout to 8 times the expected delay */	timeo = chip_op_time * 8;	if (!timeo)		timeo = 500000;	sleep_time = chip_op_time / 2;	for (;;) {		status = map_read(map, cmd_adr);		if (map_word_andequal(map, status, status_OK, status_OK))			break;		if (!timeo) {			map_write(map, CMD(0x70), cmd_adr);			chip->state = FL_STATUS;			return -ETIME;		}		/* OK Still waiting. Drop the lock, wait a while and retry. */		spin_unlock(chip->mutex);		if (sleep_time >= 1000000/HZ) {			/*			 * Half of the normal delay still remaining			 * can be performed with a sleeping delay instead			 * of busy waiting.			 */			msleep(sleep_time/1000);			timeo -= sleep_time;			sleep_time = 1000000/HZ;		} else {			udelay(1);			cond_resched();			timeo--;		}		spin_lock(chip->mutex);		while (chip->state != chip_state) {			/* Someone's suspended the operation: sleep */			DECLARE_WAITQUEUE(wait, current);			set_current_state(TASK_UNINTERRUPTIBLE);			add_wait_queue(&chip->wq, &wait);			spin_unlock(chip->mutex);			schedule();			remove_wait_queue(&chip->wq, &wait);			spin_lock(chip->mutex);		}	}	/* Done and happy. */ 	chip->state = FL_STATUS;	return 0;}#endif#define WAIT_TIMEOUT(map, chip, adr, udelay) \	INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, udelay);static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len){	unsigned long cmd_addr;	struct cfi_private *cfi = map->fldrv_priv;	int ret = 0;	adr += chip->start;	/* Ensure cmd read/writes are aligned. */	cmd_addr = adr & ~(map_bankwidth(map)-1);	spin_lock(chip->mutex);	ret = get_chip(map, chip, cmd_addr, FL_POINT);	if (!ret) {		if (chip->state != FL_POINT && chip->state != FL_READY)			map_write(map, CMD(0xff), cmd_addr);		chip->state = FL_POINT;		chip->ref_point_counter++;	}	spin_unlock(chip->mutex);	return ret;}static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	unsigned long ofs;	int chipnum;	int ret = 0;	if (!map->virt || (from + len > mtd->size))		return -EINVAL;	*mtdbuf = (void *)map->virt + from;	*retlen = 0;	/* Now lock the chip(s) to POINT state */	/* ofs: offset within the first chip that the first read should start */	chipnum = (from >> cfi->chipshift);	ofs = from - (chipnum << cfi->chipshift);	while (len) {		unsigned long thislen;		if (chipnum >= cfi->numchips)			break;		if ((len + ofs -1) >> cfi->chipshift)			thislen = (1<<cfi->chipshift) - ofs;		else			thislen = len;		ret = do_point_onechip(map, &cfi->chips[chipnum], ofs, thislen);		if (ret)			break;		*retlen += thislen;		len -= thislen;		ofs = 0;		chipnum++;	}	return 0;}static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	unsigned long ofs;	int chipnum;	/* Now unlock the chip(s) POINT state */	/* ofs: offset within the first chip that the first read should start */	chipnum = (from >> cfi->chipshift);	ofs = from - (chipnum <<  cfi->chipshift);	while (len) {		unsigned long thislen;		struct flchip *chip;		chip = &cfi->chips[chipnum];		if (chipnum >= cfi->numchips)			break;		if ((len + ofs -1) >> cfi->chipshift)			thislen = (1<<cfi->chipshift) - ofs;		else			thislen = len;		spin_lock(chip->mutex);		if (chip->state == FL_POINT) {			chip->ref_point_counter--;			if(chip->ref_point_counter == 0)				chip->state = FL_READY;		} else			printk(KERN_ERR "%s: Warning: unpoint called on non pointed region\n", map->name); /* Should this give an error? */		put_chip(map, chip, chip->start);		spin_unlock(chip->mutex);		len -= thislen;		ofs = 0;		chipnum++;	}}static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf){	unsigned long cmd_addr;	struct cfi_private *cfi = map->fldrv_priv;	int ret;	adr += chip->start;	/* Ensure cmd read/writes are aligned. */	cmd_addr = adr & ~(map_bankwidth(map)-1);	spin_lock(chip->mutex);	ret = get_chip(map, chip, cmd_addr, FL_READY);	if (ret) {		spin_unlock(chip->mutex);		return ret;	}	if (chip->state != FL_POINT && chip->state != FL_READY) {		map_write(map, CMD(0xff), cmd_addr);		chip->state = FL_READY;	}	map_copy_from(map, buf, adr, len);	put_chip(map, chip, cmd_addr);	spin_unlock(chip->mutex);	return 0;}static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	unsigned long ofs;	int chipnum;	int ret = 0;	/* ofs: offset within the first chip that the first read should start */	chipnum = (from >> cfi->chipshift);	ofs = from - (chipnum <<  cfi->chipshift);	*retlen = 0;	while (len) {		unsigned long thislen;		if (chipnum >= cfi->numchips)			break;		if ((len + ofs -1) >> cfi->chipshift)			thislen = (1<<cfi->chipshift) - ofs;		else			thislen = len;		ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);		if (ret)			break;		*retlen += thislen;		len -= thislen;		buf += thislen;		ofs = 0;		chipnum++;	}	return ret;}static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,				     unsigned long adr, map_word datum, int mode){	struct cfi_private *cfi = map->fldrv_priv;	map_word status, write_cmd;	int ret=0;	adr += chip->start;	switch (mode) {	case FL_WRITING:		write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41);		break;	case FL_OTP_WRITE:		write_cmd = CMD(0xc0);		break;	default:		return -EINVAL;	}	spin_lock(chip->mutex);	ret = get_chip(map, chip, adr, mode);	if (ret) {		spin_unlock(chip->mutex);		return ret;	}	XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));	ENABLE_VPP(map);	xip_disable(map, chip, adr);	map_write(map, write_cmd, adr);	map_write(map, datum, adr);	chip->state = mode;	ret = INVAL_CACHE_AND_WAIT(map, chip, adr,				   adr, map_bankwidth(map),				   chip->word_write_time);	if (ret) {		xip_enable(map, chip, adr);		printk(KERN_ERR "%s: word write error (status timeout)\n", map->name);		goto out;	}	/* check for errors */	status = map_read(map, adr);	if (map_word_bitsset(map, status, CMD(0x1a))) {		unsigned long chipstatus = MERGESTATUS(status);		/* reset status */		map_write(map, CMD(0x50), adr);		map_write(map, CMD(0x70), adr);		xip_enable(map, chip, adr);		if (chipstatus & 0x02) {			ret = -EROFS;		} else if (chipstatus & 0x08) {			printk(KERN_ERR "%s: word write error (bad VPP)\n", map->name);			ret = -EIO;		} else {			printk(KERN_ERR "%s: word write error (status 0x%lx)\n", map->name, chipstatus);			ret = -EINVAL;		}		goto out;	}	xip_enable(map, chip, adr); out:	put_chip(map, chip, adr);	spin_unlock(chip->mutex);	return ret;}static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	int ret = 0;	int chipnum;	unsigned long ofs;	*retlen = 0;	if (!len)		return 0;	chipnum = to >> cfi->chipshift;	ofs = to  - (chipnum << cfi->chipshift);	/* If it's not bus-aligned, do the first byte write */	if (ofs & (map_bankwidth(map)-1)) {		unsigned long bus_ofs = ofs & ~(map_bankwidth(map)-1);		int gap = ofs - bus_ofs;		int n;		map_word datum;		n = min_t(int, len, map_bankwidth(map)-gap);		datum = map_word_ff(map);		datum = map_word_load_partial(map, datum, buf, gap, n);		ret = do_write_oneword(map, &cfi->chips[chipnum],					       bus_ofs, datum, FL_WRITING);		if (ret)			return ret;

⌨️ 快捷键说明

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