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

📄 cfi_cmdset_0002.c

📁 ARMer9 s3c2410开发系统 mtd文件系统的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		ofs = 0;		chipnum++;	}	return ret;}static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf){	DECLARE_WAITQUEUE(wait, current);	unsigned long timeo = jiffies + HZ;	struct cfi_private *cfi = map->fldrv_priv; retry:	cfi_spin_lock(chip->mutex);	if (chip->state != FL_READY){#if 0		printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state);#endif		set_current_state(TASK_UNINTERRUPTIBLE);		add_wait_queue(&chip->wq, &wait);				cfi_spin_unlock(chip->mutex);		schedule();		remove_wait_queue(&chip->wq, &wait);#if 0		if(signal_pending(current))			return -EINTR;#endif		timeo = jiffies + HZ;		goto retry;	}		adr += chip->start;	chip->state = FL_READY;	/* should these be CFI_DEVICETYPE_X8 instead of cfi->device_type? */	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);	cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);		map_copy_from(map, buf, adr, len);	/* should these be CFI_DEVICETYPE_X8 instead of cfi->device_type? */	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);	cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);		wake_up(&chip->wq);	cfi_spin_unlock(chip->mutex);	return 0;}static int cfi_amdstd_secsi_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 */	/* 8 secsi bytes per chip */	chipnum=from>>3;	ofs=from & 7;	*retlen = 0;	while (len) {		unsigned long thislen;		if (chipnum >= cfi->numchips)			break;		if ((len + ofs -1) >> 3)			thislen = (1<<3) - ofs;		else			thislen = len;		ret = do_read_secsi_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);		if (ret)			break;		*retlen += thislen;		len -= thislen;		buf += thislen;		ofs = 0;		chipnum++;	}	return ret;}static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum){	struct cfi_private *cfi = map->fldrv_priv;	unsigned long timeo = jiffies + HZ;	/*	 * We use a 1ms + 1 jiffies generic timeout for writes (most devices	 * have a max write time of a few hundreds usec). However, we should	 * use the maximum timeout value given by the chip at probe time	 * instead.  Unfortunately, struct flchip does have a field for	 * maximum timeout, only for typical which can be far too short	 * depending of the conditions.	 The ' + 1' is to avoid having a	 * timeout of 0 jiffies if HZ is smaller than 1000.	 */	unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;	int ret = 0;	map_word oldd, curd;	int retry_cnt = 0;	adr += chip->start;	cfi_spin_lock(chip->mutex);	ret = get_chip(map, chip, adr, FL_WRITING);	if (ret) {		cfi_spin_unlock(chip->mutex);		return ret;	}	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",	       __func__, adr, datum.x[0] );	/*	 * Check for a NOP for the case when the datum to write is already	 * present - it saves time and works around buggy chips that corrupt	 * data at other locations when 0xff is written to a location that	 * already contains 0xff.	 */	oldd = map_read(map, adr);	if (map_word_equal(map, oldd, datum)) {		DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): NOP\n",		       __func__);		goto op_done;	}	ENABLE_VPP(map); retry:	/*	 * The CFI_DEVICETYPE_X8 argument is needed even when	 * cfi->device_type != CFI_DEVICETYPE_X8.  The addresses for	 * command sequences don't scale even when the device is	 * wider.  This is the case for many of the cfi_send_gen_cmd()	 * below.  I'm not sure, however, why some use	 * cfi->device_type.	 */	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	map_write(map, datum, adr);	chip->state = FL_WRITING;	cfi_spin_unlock(chip->mutex);	cfi_udelay(chip->word_write_time);	cfi_spin_lock(chip->mutex);	/* See comment above for timeout value. */	timeo = jiffies + uWriteTimeout; 	for (;;) {		if (chip->state != FL_WRITING) {			/* Someone's suspended the write. Sleep */			DECLARE_WAITQUEUE(wait, current);			set_current_state(TASK_UNINTERRUPTIBLE);			add_wait_queue(&chip->wq, &wait);			cfi_spin_unlock(chip->mutex);			schedule();			remove_wait_queue(&chip->wq, &wait);			timeo = jiffies + (HZ / 2); /* FIXME */			cfi_spin_lock(chip->mutex);			continue;		}		/* Test to see if toggling has stopped. */		oldd = map_read(map, adr);		curd = map_read(map, adr);		if (map_word_equal(map, curd, oldd)) {			/* Do we have the correct value? */			if (map_word_equal(map, curd, datum)) {				goto op_done;			}			/* Nope something has gone wrong. */			break;		}		if (time_after(jiffies, timeo)) {			printk(KERN_WARNING "MTD %s(): software timeout\n",				__func__ );			break;		}		/* Latency issues. Drop the lock, wait a while and retry */		cfi_spin_unlock(chip->mutex);		cfi_udelay(1);		cfi_spin_lock(chip->mutex);	}	/* reset on all failures. */	map_write( map, CMD(0xF0), chip->start );	/* FIXME - should have reset delay before continuing */	if (++retry_cnt <= MAX_WORD_RETRIES) 		goto retry;	ret = -EIO; op_done:	chip->state = FL_READY;	put_chip(map, chip, adr);	cfi_spin_unlock(chip->mutex);	return ret;}static int cfi_amdstd_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, chipstart;	DECLARE_WAITQUEUE(wait, current);	*retlen = 0;	if (!len)		return 0;	chipnum = to >> cfi->chipshift;	ofs = to  - (chipnum << cfi->chipshift);	chipstart = cfi->chips[chipnum].start;	/* 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 i = ofs - bus_ofs;		int n = 0;		map_word tmp_buf; retry:		cfi_spin_lock(cfi->chips[chipnum].mutex);		if (cfi->chips[chipnum].state != FL_READY) {#if 0			printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state);#endif			set_current_state(TASK_UNINTERRUPTIBLE);			add_wait_queue(&cfi->chips[chipnum].wq, &wait);			cfi_spin_unlock(cfi->chips[chipnum].mutex);			schedule();			remove_wait_queue(&cfi->chips[chipnum].wq, &wait);#if 0			if(signal_pending(current))				return -EINTR;#endif			goto retry;		}		/* Load 'tmp_buf' with old contents of flash */		tmp_buf = map_read(map, bus_ofs+chipstart);		cfi_spin_unlock(cfi->chips[chipnum].mutex);		/* Number of bytes to copy from buffer */		n = min_t(int, len, map_bankwidth(map)-i);				tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n);		ret = do_write_oneword(map, &cfi->chips[chipnum], 				       bus_ofs, tmp_buf);		if (ret) 			return ret;				ofs += n;		buf += n;		(*retlen) += n;		len -= n;		if (ofs >> cfi->chipshift) {			chipnum ++; 			ofs = 0;			if (chipnum == cfi->numchips)				return 0;		}	}		/* We are now aligned, write as much as possible */	while(len >= map_bankwidth(map)) {		map_word datum;		datum = map_word_load(map, buf);		ret = do_write_oneword(map, &cfi->chips[chipnum],				       ofs, datum);		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;			chipstart = cfi->chips[chipnum].start;		}	}	/* Write the trailing bytes if any */	if (len & (map_bankwidth(map)-1)) {		map_word tmp_buf; retry1:		cfi_spin_lock(cfi->chips[chipnum].mutex);		if (cfi->chips[chipnum].state != FL_READY) {#if 0			printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state);#endif			set_current_state(TASK_UNINTERRUPTIBLE);			add_wait_queue(&cfi->chips[chipnum].wq, &wait);			cfi_spin_unlock(cfi->chips[chipnum].mutex);			schedule();			remove_wait_queue(&cfi->chips[chipnum].wq, &wait);#if 0			if(signal_pending(current))				return -EINTR;#endif			goto retry1;		}		tmp_buf = map_read(map, ofs + chipstart);		cfi_spin_unlock(cfi->chips[chipnum].mutex);		tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);			ret = do_write_oneword(map, &cfi->chips[chipnum], 				ofs, tmp_buf);		if (ret) 			return ret;				(*retlen) += len;	}	return 0;}/* * FIXME: interleaved mode not tested, and probably not supported! */static inline int do_write_buffer(struct map_info *map, struct flchip *chip, 				  unsigned long adr, const u_char *buf, int len){	struct cfi_private *cfi = map->fldrv_priv;	unsigned long timeo = jiffies + HZ;	/* see comments in do_write_oneword() regarding uWriteTimeo. */	static unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;	int ret = -EIO;	unsigned long cmd_adr;	int z, words;	map_word datum;	adr += chip->start;	cmd_adr = adr;	cfi_spin_lock(chip->mutex);	ret = get_chip(map, chip, adr, FL_WRITING);	if (ret) {		cfi_spin_unlock(chip->mutex);		return ret;	}	datum = map_word_load(map, buf);	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",	       __func__, adr, datum.x[0] );	ENABLE_VPP(map);	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	//cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	/* Write Buffer Load */	map_write(map, CMD(0x25), cmd_adr);	chip->state = FL_WRITING_TO_BUFFER;	/* Write length of data to come */	words = len / map_bankwidth(map);	map_write(map, CMD(words - 1), cmd_adr);	/* Write data */	z = 0;	while(z < words * map_bankwidth(map)) {		datum = map_word_load(map, buf);		map_write(map, datum, adr + z);		z += map_bankwidth(map);		buf += map_bankwidth(map);	}	z -= map_bankwidth(map);	adr += z;	/* Write Buffer Program Confirm: GO GO GO */	map_write(map, CMD(0x29), cmd_adr);	chip->state = FL_WRITING;	cfi_spin_unlock(chip->mutex);	cfi_udelay(chip->buffer_write_time);	cfi_spin_lock(chip->mutex);	timeo = jiffies + uWriteTimeout; 			for (;;) {		if (chip->state != FL_WRITING) {			/* Someone's suspended the write. Sleep */			DECLARE_WAITQUEUE(wait, current);			set_current_state(TASK_UNINTERRUPTIBLE);			add_wait_queue(&chip->wq, &wait);			cfi_spin_unlock(chip->mutex);			schedule();			remove_wait_queue(&chip->wq, &wait);			timeo = jiffies + (HZ / 2); /* FIXME */			cfi_spin_lock(chip->mutex);			continue;		}		if (chip_ready(map, adr))			goto op_done;		    		if( time_after(jiffies, timeo))			break;		/* Latency issues. Drop the lock, wait a while and retry */		cfi_spin_unlock(chip->mutex);		cfi_udelay(1);		cfi_spin_lock(chip->mutex);	}	printk(KERN_WARNING "MTD %s(): software timeout\n",	       __func__ );	/* reset on all failures. */	map_write( map, CMD(0xF0), chip->start );	/* FIXME - should have reset delay before continuing */	ret = -EIO; op_done:	chip->state = FL_READY;	put_chip(map, chip, adr);	cfi_spin_unlock(chip->mutex);	return ret;}static int cfi_amdstd_write_buffers(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 wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;	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 word write */	if (ofs & (map_bankwidth(map)-1)) {		size_t local_len = (-ofs)&(map_bankwidth(map)-1);		if (local_len > len)			local_len = len;		ret = cfi_amdstd_write_words(mtd, to, local_len,					       retlen, buf);		if (ret)			return ret;		ofs += local_len;		buf += local_len;		len -= local_len;		if (ofs >> cfi->chipshift) {			chipnum ++;			ofs = 0;			if (chipnum == cfi->numchips)				return 0;		}	}	/* Write buffer is worth it only if more than one word to write... */	while (len >= map_bankwidth(map) * 2) {		/* We must not cross write block boundaries */		int size = wbufsize - (ofs & (wbufsize-1));		if (size > len)			size = len;		if (size % map_bankwidth(map))			size -= size % map_bankwidth(map);		ret = do_write_buffer(map, &cfi->chips[chipnum], 				      ofs, buf, size);		if (ret)			return ret;		ofs += size;		buf += size;		(*retlen) += size;		len -= size;		if (ofs >> cfi->chipshift) {			chipnum ++; 			ofs = 0;			if (chipnum == cfi->numchips)				return 0;		}	}	if (len) {		size_t retlen_dregs = 0;		ret = cfi_amdstd_write_words(mtd, to, len, &retlen_dregs, buf);		*retlen += retlen_dregs;		return ret;	}	return 0;}/* * Handle devices with one erase region, that only implement * the chip erase command. */static inline int do_erase_chip(struct map_info *map, struct flchip *chip){	struct cfi_private *cfi = map->fldrv_priv;	unsigned long timeo = jiffies + HZ;	unsigned long int adr;	DECLARE_WAITQUEUE(wait, current);	int ret = 0;	adr = cfi->addr_unlock1;	cfi_spin_lock(chip->mutex);	ret = get_chip(map, chip, adr, FL_WRITING);	if (ret) {		cfi_spin_unlock(chip->mutex);		return ret;	}	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",	       __func__, chip->start );	ENABLE_VPP(map);	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);

⌨️ 快捷键说明

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