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

📄 cfi_cmdset_0001.c

📁 飞思卡尔芯片imx27下的MTD模块的驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		BUG();	/*	 * If Instant Individual Block Locking supported then no need	 * to delay.	 */	udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0;	ret = WAIT_TIMEOUT(map, chip, adr, udelay);	if (ret) {		map_write(map, CMD(0x70), adr);		chip->state = FL_STATUS;		xip_enable(map, chip, adr);		printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name);		goto out;	}	xip_enable(map, chip, adr);out:	put_chip(map, chip, adr);	spin_unlock(chip->mutex);	return ret;}static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len){	int ret;#ifdef DEBUG_LOCK_BITS	printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",	       __FUNCTION__, ofs, len);	cfi_varsize_frob(mtd, do_printlockstatus_oneblock,		ofs, len, 0);#endif	ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,		ofs, len, DO_XXLOCK_ONEBLOCK_LOCK);#ifdef DEBUG_LOCK_BITS	printk(KERN_DEBUG "%s: lock status after, ret=%d\n",	       __FUNCTION__, ret);	cfi_varsize_frob(mtd, do_printlockstatus_oneblock,		ofs, len, 0);#endif	return ret;}static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len){	int ret;#ifdef DEBUG_LOCK_BITS	printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",	       __FUNCTION__, ofs, len);	cfi_varsize_frob(mtd, do_printlockstatus_oneblock,		ofs, len, 0);#endif	ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,					ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK);#ifdef DEBUG_LOCK_BITS	printk(KERN_DEBUG "%s: lock status after, ret=%d\n",	       __FUNCTION__, ret);	cfi_varsize_frob(mtd, do_printlockstatus_oneblock,		ofs, len, 0);#endif	return ret;}#ifdef CONFIG_MTD_OTPtypedef int (*otp_op_t)(struct map_info *map, struct flchip *chip,			u_long data_offset, u_char *buf, u_int size,			u_long prot_offset, u_int groupno, u_int groupsize);static int __xipramdo_otp_read(struct map_info *map, struct flchip *chip, u_long offset,	    u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz){	struct cfi_private *cfi = map->fldrv_priv;	int ret;	spin_lock(chip->mutex);	ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);	if (ret) {		spin_unlock(chip->mutex);		return ret;	}	/* let's ensure we're not reading back cached data from array mode */	INVALIDATE_CACHED_RANGE(map, chip->start + offset, size);	xip_disable(map, chip, chip->start);	if (chip->state != FL_JEDEC_QUERY) {		map_write(map, CMD(0x90), chip->start);		chip->state = FL_JEDEC_QUERY;	}	map_copy_from(map, buf, chip->start + offset, size);	xip_enable(map, chip, chip->start);	/* then ensure we don't keep OTP data in the cache */	INVALIDATE_CACHED_RANGE(map, chip->start + offset, size);	put_chip(map, chip, chip->start);	spin_unlock(chip->mutex);	return 0;}static intdo_otp_write(struct map_info *map, struct flchip *chip, u_long offset,	     u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz){	int ret;	while (size) {		unsigned long bus_ofs = offset & ~(map_bankwidth(map)-1);		int gap = offset - bus_ofs;		int n = min_t(int, size, map_bankwidth(map)-gap);		map_word datum = map_word_ff(map);		datum = map_word_load_partial(map, datum, buf, gap, n);		ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE);		if (ret)			return ret;		offset += n;		buf += n;		size -= n;	}	return 0;}static intdo_otp_lock(struct map_info *map, struct flchip *chip, u_long offset,	    u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz){	struct cfi_private *cfi = map->fldrv_priv;	map_word datum;	/* make sure area matches group boundaries */	if (size != grpsz)		return -EXDEV;	datum = map_word_ff(map);	datum = map_word_clr(map, datum, CMD(1 << grpno));	return do_write_oneword(map, chip, prot, datum, FL_OTP_WRITE);}static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,				 size_t *retlen, u_char *buf,				 otp_op_t action, int user_regs){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	struct cfi_pri_intelext *extp = cfi->cmdset_priv;	struct flchip *chip;	struct cfi_intelext_otpinfo *otp;	u_long devsize, reg_prot_offset, data_offset;	u_int chip_num, chip_step, field, reg_fact_size, reg_user_size;	u_int groups, groupno, groupsize, reg_fact_groups, reg_user_groups;	int ret;	*retlen = 0;	/* Check that we actually have some OTP registers */	if (!extp || !(extp->FeatureSupport & 64) || !extp->NumProtectionFields)		return -ENODATA;	/* we need real chips here not virtual ones */	devsize = (1 << cfi->cfiq->DevSize) * cfi->interleave;	chip_step = devsize >> cfi->chipshift;	chip_num = 0;	/* Some chips have OTP located in the _top_ partition only.	   For example: Intel 28F256L18T (T means top-parameter device) */	if (cfi->mfr == MANUFACTURER_INTEL) {		switch (cfi->id) {		case 0x880b:		case 0x880c:		case 0x880d:			chip_num = chip_step - 1;		}	}	for ( ; chip_num < cfi->numchips; chip_num += chip_step) {		chip = &cfi->chips[chip_num];		otp = (struct cfi_intelext_otpinfo *)&extp->extra[0];		/* first OTP region */		field = 0;		reg_prot_offset = extp->ProtRegAddr;		reg_fact_groups = 1;		reg_fact_size = 1 << extp->FactProtRegSize;		reg_user_groups = 1;		reg_user_size = 1 << extp->UserProtRegSize;		while (len > 0) {			/* flash geometry fixup */			data_offset = reg_prot_offset + 1;			data_offset *= cfi->interleave * cfi->device_type;			reg_prot_offset *= cfi->interleave * cfi->device_type;			reg_fact_size *= cfi->interleave;			reg_user_size *= cfi->interleave;			if (user_regs) {				groups = reg_user_groups;				groupsize = reg_user_size;				/* skip over factory reg area */				groupno = reg_fact_groups;				data_offset += reg_fact_groups * reg_fact_size;			} else {				groups = reg_fact_groups;				groupsize = reg_fact_size;				groupno = 0;			}			while (len > 0 && groups > 0) {				if (!action) {					/*					 * Special case: if action is NULL					 * we fill buf with otp_info records.					 */					struct otp_info *otpinfo;					map_word lockword;					len -= sizeof(struct otp_info);					if (len <= 0)						return -ENOSPC;					ret = do_otp_read(map, chip,							  reg_prot_offset,							  (u_char *)&lockword,							  map_bankwidth(map),							  0, 0,  0);					if (ret)						return ret;					otpinfo = (struct otp_info *)buf;					otpinfo->start = from;					otpinfo->length = groupsize;					otpinfo->locked =					   !map_word_bitsset(map, lockword,							     CMD(1 << groupno));					from += groupsize;					buf += sizeof(*otpinfo);					*retlen += sizeof(*otpinfo);				} else if (from >= groupsize) {					from -= groupsize;					data_offset += groupsize;				} else {					int size = groupsize;					data_offset += from;					size -= from;					from = 0;					if (size > len)						size = len;					ret = action(map, chip, data_offset,						     buf, size, reg_prot_offset,						     groupno, groupsize);					if (ret < 0)						return ret;					buf += size;					len -= size;					*retlen += size;					data_offset += size;				}				groupno++;				groups--;			}			/* next OTP region */			if (++field == extp->NumProtectionFields)				break;			reg_prot_offset = otp->ProtRegAddr;			reg_fact_groups = otp->FactGroups;			reg_fact_size = 1 << otp->FactProtRegSize;			reg_user_groups = otp->UserGroups;			reg_user_size = 1 << otp->UserProtRegSize;			otp++;		}	}	return 0;}static int cfi_intelext_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,					   size_t len, size_t *retlen,					    u_char *buf){	return cfi_intelext_otp_walk(mtd, from, len, retlen,				     buf, do_otp_read, 0);}static int cfi_intelext_read_user_prot_reg(struct mtd_info *mtd, loff_t from,					   size_t len, size_t *retlen,					    u_char *buf){	return cfi_intelext_otp_walk(mtd, from, len, retlen,				     buf, do_otp_read, 1);}static int cfi_intelext_write_user_prot_reg(struct mtd_info *mtd, loff_t from,					    size_t len, size_t *retlen,					     u_char *buf){	return cfi_intelext_otp_walk(mtd, from, len, retlen,				     buf, do_otp_write, 1);}static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd,					   loff_t from, size_t len){	size_t retlen;	return cfi_intelext_otp_walk(mtd, from, len, &retlen,				     NULL, do_otp_lock, 1);}static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd,					   struct otp_info *buf, size_t len){	size_t retlen;	int ret;	ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0);	return ret ? : retlen;}static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd,					   struct otp_info *buf, size_t len){	size_t retlen;	int ret;	ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1);	return ret ? : retlen;}#endifstatic int cfi_intelext_suspend(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);		switch (chip->state) {		case FL_READY:		case FL_STATUS:		case FL_CFI_QUERY:		case FL_JEDEC_QUERY:			if (chip->oldstate == FL_READY) {				chip->oldstate = chip->state;				chip->state = FL_PM_SUSPENDED;				/* No need to wake_up() on this state change -				 * as the whole point is that nobody can do anything				 * with the chip now anyway.				 */			} else {				/* There seems to be an operation pending. We must wait for it. */				printk(KERN_NOTICE "Flash device refused suspend due to pending operation (oldstate %d)\n", chip->oldstate);				ret = -EAGAIN;			}			break;		default:			/* Should we actually wait? Once upon a time these routines weren't			   allowed to. Or should we return -EAGAIN, because the upper layers			   ought to have already shut down anything which was using the device			   anyway? The latter for now. */			printk(KERN_NOTICE "Flash device refused suspend due to active operation (state %d)\n", chip->oldstate);			ret = -EAGAIN;		case FL_PM_SUSPENDED:			break;		}		spin_unlock(chip->mutex);	}	/* Unlock the chips again */	if (ret) {		for (i--; i >=0; i--) {			chip = &cfi->chips[i];			spin_lock(chip->mutex);			if (chip->state == FL_PM_SUSPENDED) {				/* No need to force it into a known state here,				   because we're returning failure, and it didn't				   get power cycled */				chip->state = chip->oldstate;				chip->oldstate = FL_READY;				wake_up(&chip->wq);			}			spin_unlock(chip->mutex);		}	}	return ret;}static void cfi_intelext_resume(struct mtd_info *mtd){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	int i;	struct flchip *chip;	for (i=0; i<cfi->numchips; i++) {		chip = &cfi->chips[i];		spin_lock(chip->mutex);		/* Go to known state. Chip may have been power cycled */		if (chip->state == FL_PM_SUSPENDED) {			map_write(map, CMD(0xFF), cfi->chips[i].start);			chip->oldstate = chip->state = FL_READY;			wake_up(&chip->wq);		}		spin_unlock(chip->mutex);	}}static int cfi_intelext_reset(struct mtd_info *mtd){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	int i, ret;	for (i=0; i < cfi->numchips; i++) {		struct flchip *chip = &cfi->chips[i];		/* force the completion of any ongoing operation		   and switch to array mode so any bootloader in		   flash is accessible for soft reboot. */		spin_lock(chip->mutex);		ret = get_chip(map, chip, chip->start, FL_SYNCING);		if (!ret) {			map_write(map, CMD(0xff), chip->start);			chip->state = FL_READY;		}		spin_unlock(chip->mutex);	}	return 0;}static int cfi_intelext_reboot(struct notifier_block *nb, unsigned long val,			       void *v){	struct mtd_info *mtd;	mtd = container_of(nb, struct mtd_info, reboot_notifier);	cfi_intelext_reset(mtd);	return NOTIFY_DONE;}static void cfi_intelext_destroy(struct mtd_info *mtd){

⌨️ 快捷键说明

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