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

📄 cfi_cmdset_0002.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 4 页
字号:
	}}static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr){	struct cfi_private *cfi = map->fldrv_priv;	switch(chip->oldstate) {	case FL_ERASING:		chip->state = chip->oldstate;		cfi_write(map, CMD(0x30), adr);		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 & ~(CFIDEV_BUSWIDTH-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) {		cfi_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;	/* 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, cfi_word datum, int fast){	struct cfi_private *cfi = map->fldrv_priv;	unsigned long timeo = jiffies + HZ;	cfi_word oldstatus, status, prev_oldstatus, prev_status;	cfi_word dq6 = CMD(1<<6);	/*	 * 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;	int ta = 0;	DECLARE_RETRY_CMD_CNT();	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;	}	RETRY_CMD_LABEL;	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8x)\n",	       __func__, adr, datum );	/*	 * 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.	 */	status = cfi_read(map, adr);	if (status == datum) {		DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): NOP 0x%.8x == 0x%.8x\n",		       __func__, status, datum );		goto op_done;	}	ENABLE_VPP(map);	if (fast) { /* Unlock bypass */		cfi_send_gen_cmd(0xA0, 0, chip->start, map, cfi, cfi->device_type, NULL);	} else {		/*		 * 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);	}	cfi_write(map, datum, adr);	chip->state = FL_WRITING;	cfi_spin_unlock(chip->mutex);	cfi_udelay(chip->word_write_time);	cfi_spin_lock(chip->mutex);	/*	 * Polling toggle bits instead of reading back many times This ensures	 * that write operation is really completed, or tells us why it	 * failed.	 *	 * It may appear that the polling and decoding of error state might be	 * simplified.  Don't do it unless you really know what you are doing.	 *	 * You must remember that JESD21-C 3.5.3 states that the status must	 * be read back an _additional_ two times before a failure is	 * determined.  This is because these devices have internal state	 * machines that are asynchronous to the external data bus.  During an	 * erase or write the read-back status of the polling bits might be	 * transitioning internaly when the external read-back occurs.  This	 * means that the bits aren't in the final state and they might appear	 * to report an error as they are in a transient state: dq7 is	 * asynchronous with dq6 and other status bits.	 *	 * This asynchronous behaviour can cause infrequent errors that will	 * usually disappear the next time an erase or write happens (Try	 * tracking those errors down!).  To ensure that the bits are not in	 * transition, the location must be read-back two more times and	 * compared against what was written - BOTH reads MUST match what was	 * written.  Don't think this can be simplified to only the last read	 * matching the datum written: status bits *can* match the datum	 * written.	 *	 * If the final comparison fails, error state can *then* be decoded.	 *	 * - Thayne Harbaugh	 */	/* 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;		}		oldstatus = cfi_read(map, adr);		status = cfi_read(map, adr);		DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",		       __func__, oldstatus, status );		/*		 * This only checks if dq6 is still toggling and that our		 * timer hasn't expired.  We purposefully ignore the chip's		 * internal timer that will assert dq5 and leave dq6 toggling.		 * This is done for a variety of reasons:		 *		 * 1) Not all chips support dq5.		 *		 * 2) Dealing with asynchronous status bit and data updates		 * and reading a device two more times creates _messy_ logic		 * when trying to deal with interleaved devices - some may be		 * changing while others are still busy.		 *		 * 3) Checking dq5 only helps to optimize an error case that		 * should at worst be infrequent and at best non-existent.		 *		 * If our timeout occurs _then_ we will check dq5 to see if		 * the device also had an internal timeout.		 */		if ( (((status ^ oldstatus) & dq6) == 0)		     || ( ta = 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);	}	/*	 * Something kicked us out of the read-back loop.  We'll check success	 * befor checking failure.  Even though dq6 might be true data, it is	 * unkown if all of the other bits have changed to true data due to	 * the asynchronous nature of the internal state machine.  We will	 * read two more times and use this to either verify that the write	 * completed successfully or that something really went wrong.  BOTH	 * reads must match what was written - this certifies that bits aren't	 * still changing and that the status bits erroneously match the datum	 * that was written.	 */	prev_oldstatus = oldstatus;	prev_status = status;	oldstatus = cfi_read(map, adr);	status = cfi_read(map, adr);	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",	       __func__, oldstatus, status );	if ( oldstatus == datum && status == datum ) {		/* success - do nothing */		goto op_done;	}	if ( ta ) {		/* Only check dq5 on the chips that are still toggling. */		cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;		if ( status & dq5mask ) {			/* dq5 asserted - decode interleave chips */			printk( KERN_WARNING				"MTD %s(): FLASH internal timeout: 0x%.8x 0x%.8x 0x%8x\n",				__func__,				status & dq5mask, status, datum );		} else {			printk( KERN_WARNING				"MTD %s(): Software timed out during write.\n",				__func__ );		}		goto op_failed;	}	/*	 * If we get to here then it means that something	 * is wrong and it's not a timeout.  Something	 * is seriously wacky!  Dump some debug info.	 */	/*	 * Found a clue about the chips that reach this state.	 * Some flash chips (SST >cough<)	 * are horribly broken.  They do not ignore traffic that is	 * destined to other devices.  This happens because some solutions	 * are on shared busses, the erase and program sequences have	 * have multiple commands, and the sequence is interspersed with	 * commands destined to other devices.  A good flash chip will	 * examine the command and destination address and will ignore	 * commands that are for other devices.	 */	HANDLE_WACKY_STATE(); op_failed:	/* reset on all failures. */	cfi_write( map, CMD(0xF0), chip->start );	/* FIXME - should have reset delay before continuing */	CHECK_RETRIES();	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 & (CFIDEV_BUSWIDTH-1)) {		unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);		int i = ofs - bus_ofs;		int n = 0;		u_char tmp_buf[8];		cfi_word datum; 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;		}		map_copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);		cfi_spin_unlock(cfi->chips[chipnum].mutex);		while (len && i < CFIDEV_BUSWIDTH) {			tmp_buf[i++] = buf[n++];                        len--;                }		/* already know that buswidth > 1 */		if (cfi_buswidth_is_2()) {			datum = *(__u16*)tmp_buf;		} else if (cfi_buswidth_is_4()) {			datum = *(__u32*)tmp_buf;#ifdef CFI_WORD_64		} else if (cfi_buswidth_is_8()) {			datum = *(__u64*)tmp_buf;#endif		} else {			printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n",			       __func__, CFIDEV_BUSWIDTH);			return -EINVAL;		}		ret = do_write_oneword(map, &cfi->chips[chipnum], 				       bus_ofs, datum, 0);		if (ret) 			return ret;				ofs += n;		buf += n;		(*retlen) += n;		if (ofs >> cfi->chipshift) {			chipnum ++; 			ofs = 0;			if (chipnum == cfi->numchips)				return 0;		}	}		if (cfi->fast_prog) {		/* Go into unlock bypass mode */		cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);		cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);		cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);	}	/* We are now aligned, write as much as possible */	while(len >= CFIDEV_BUSWIDTH) {		cfi_word datum;		if (cfi_buswidth_is_1()) {			datum = *(__u8*)buf;		} else if (cfi_buswidth_is_2()) {			datum = *(__u16*)buf;		} else if (cfi_buswidth_is_4()) {			datum = *(__u32*)buf;#ifdef CFI_WORD_64		} else if (cfi_buswidth_is_8()) {			datum = *(__u64*)buf;#endif		} else {			printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n",			       __func__, CFIDEV_BUSWIDTH);			return -EINVAL;		}		ret = do_write_oneword(map, &cfi->chips[chipnum],				       ofs, datum, cfi->fast_prog);		if (ret) {			if (cfi->fast_prog){				/* Get out of unlock bypass mode */				cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);				cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);			}			return ret;		}		ofs += CFIDEV_BUSWIDTH;		buf += CFIDEV_BUSWIDTH;		(*retlen) += CFIDEV_BUSWIDTH;		len -= CFIDEV_BUSWIDTH;

⌨️ 快捷键说明

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