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

📄 cfi_cmdset_0002.c

📁 linux 下的coldfire cpu的 nor flash 驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	switch(chip->oldstate) {	case FL_ERASING:		chip->state = chip->oldstate;		map_write(map, CMD(0x30), chip->in_progress_block_addr);		chip->oldstate = FL_READY;		chip->state = FL_ERASING;		break;	case FL_READY:	case FL_STATUS:		/* We should really make set_vpp() count, rather than doing this */		DISABLE_VPP(map);		break;	default:		printk(KERN_ERR "MTD: put_chip() called with oldstate %d!!\n", chip->oldstate);	}	wake_up(&chip->wq);}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); 	cfi_spin_lock(chip->mutex);	ret = get_chip(map, chip, cmd_addr, FL_READY);	if (ret) {		cfi_spin_unlock(chip->mutex);		return ret;	}	if (chip->state != FL_POINT && chip->state != FL_READY) {		map_write(map, CMD(0xf0), cmd_addr);		chip->state = FL_READY;	}	map_copy_from(map, buf, adr, len);	put_chip(map, chip, cmd_addr);	cfi_spin_unlock(chip->mutex);	return 0;}static int cfi_amdstd_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 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;	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);	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;	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:	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(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, 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;		}		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 */	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. */	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->device_type, NULL);	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);	//cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, 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);

⌨️ 快捷键说明

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