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

📄 cfi_cmdset_0001.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
	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,				   chip->erase_time_max);	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;}static 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);	}}static int __xipram do_getlockstatus_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);	return status;}#ifdef DEBUG_LOCK_BITSstatic int __xipram do_printlockstatus_oneblock(struct map_info *map,						struct flchip *chip,						unsigned long adr,						int len, void *thunk){	printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",	       adr, do_getlockstatus_oneblock(map, chip, adr, len, thunk));	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		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, udelay * 100);	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",	       __func__, ofs, len);	cfi_varsize_frob(mtd, do_printlockstatus_oneblock,		ofs, len, NULL);#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",	       __func__, ret);	cfi_varsize_frob(mtd, do_printlockstatus_oneblock,		ofs, len, NULL);#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",	       __func__, ofs, len);	cfi_varsize_frob(mtd, do_printlockstatus_oneblock,		ofs, len, NULL);#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",	       __func__, ret);	cfi_varsize_frob(mtd, do_printlockstatus_oneblock,		ofs, len, NULL);#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

⌨️ 快捷键说明

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