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

📄 cfi_cmdset_0002_v4.c

📁 1.under bootloader 1)cd your_dir/mrua_EM8620L_2.5.115.RC8_dev.arm.bootirq/MRUA_src/loader 2)将f
💻 C
📖 第 1 页 / 共 3 页
字号:
	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. */        	dq6 = CMD(1<<6);	dq5 = CMD(1<<5);	timeo = jiffies + HZ; /* setting timeout to 1s for safety */			oldstatus = cfi_read(map, adr);	status = cfi_read(map, adr);	/*	 * some toshiba flash acts weird with the toggle bits, so	 * we check the datum as well	 */	while( (status != datum ||	           ((status & dq6) != (oldstatus & dq6) && 	           (status & dq5) != dq5)) &&	       !time_after(jiffies, timeo) ) {		if (need_resched()) {			cfi_spin_unlock(chip->mutex);			yield();			cfi_spin_lock(chip->mutex);		} else 			udelay(1);		oldstatus = cfi_read( map, adr );		status = cfi_read( map, adr );	}		if( (status & dq6) != (oldstatus & dq6) ) {		/* The erasing didn't stop?? */		if( (status & dq5) == dq5 ) {			/* When DQ5 raises, we must check once again			   if DQ6 is toggling.  If not, the erase has been			   completed OK.  If not, reset chip. */			oldstatus = cfi_read(map, adr);			status = cfi_read(map, adr);		    			if ( (oldstatus & 0x00FF) == (status & 0x00FF) ) {				printk(KERN_WARNING "Warning: DQ5 raised while program operation was in progress, however operation completed OK\n" );			} else { 				/* DQ5 is active so we can do a reset and stop the erase */				cfi_write(map, CMD(0xF0), chip->start);				printk(KERN_WARNING "Internal flash device timeout occurred or write operation was performed while flash was programming.\n" );			}		} else {			printk(KERN_WARNING "Waiting for write to complete timed out in do_write_oneword.");        						chip->state = FL_READY;			wake_up(&chip->wq);			cfi_spin_unlock(chip->mutex);			DISABLE_VPP(map);			ret = -EIO;		}	}	DISABLE_VPP(map);	chip->state = FL_READY;	wake_up(&chip->wq);	cfi_spin_unlock(chip->mutex);	return ret;}static inline int do_write_buffer(struct map_info *map, struct flchip *chip, 				  unsigned long adr, const u_char *buf, int len){	unsigned long timeo = jiffies + HZ;	unsigned int status;	unsigned int dq7, dq5, dq1;		struct cfi_private *cfi = map->fldrv_priv;	DECLARE_WAITQUEUE(wait, current);	int ret = 0;	int z;	__u32 datum = 0;		 retry:	cfi_spin_lock(chip->mutex);	if (chip->state != FL_READY) {		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;		goto retry;	}			adr += chip->start;	ENABLE_VPP(map);	/* write buffers algorithm taken from Am29LV641MH/L manual */	cfi_send_gen_cmd(0xAA, 0xaaa, chip->start, map, cfi, 1, NULL);	cfi_send_gen_cmd(0x55, 0x555, chip->start, map, cfi, 1, NULL);	cfi_write(map, CMD(0x25), adr);		chip->state = FL_WRITING_TO_BUFFER;		cfi_write(map, CMD(len/CFIDEV_BUSWIDTH-1), adr); /* word count */	/* Write data */	for (z = 0; z < len; z += CFIDEV_BUSWIDTH) {	 /*   	if (cfi_buswidth_is_2())			map->write16 (map, datum = *((__u16*)buf)++, adr+z);		else if (cfi_buswidth_is_4())		    	map->write32 (map, datum = *((__u32*)buf)++, adr+z);	*/		cfi_write(map,datum=*((unsigned char*)buf)++, adr+z);		}	/* start program */	cfi_write(map, CMD(0x29), adr);		chip->state = FL_WRITING;	cfi_spin_unlock(chip->mutex);	cfi_udelay(chip->buffer_write_time);	cfi_spin_lock(chip->mutex);	/* use data polling algorithm */	dq1 = CMD(1<<1);	dq5 = CMD(1<<5);	dq7 = CMD(1<<7);	timeo = jiffies + HZ; /* setting timeout to 1s for safety */	z -= CFIDEV_BUSWIDTH;	/* go to last written address */	do {	    	status = cfi_read(map, adr+z);	    	if( (dq7 & status) == (dq7 & datum) )			break;/*	    	if( ((dq5 & status) == dq5) ||		    ((dq1 & status) == dq1) ) {			status = cfi_read( map, adr+z );			if( (dq7 & status) != (dq7 & datum) )			{		    		ret = -EIO;				break;			} else break;	    	}*/		if ((dq5 & status) == dq5) {			status = cfi_read( map, adr+z );			if( (dq7 & status) != (dq7 & datum) )			{		    		ret = -EIO;				break;			} else 				break;	    	}else if((dq1 & status) == dq1){	    		status = cfi_read( map, adr+z );			if( (dq7 & status) != (dq7 & datum) )			{		    		ret = -EIO;				break;			} else 				break;		    	}		if (need_resched()) {		    cfi_spin_unlock(chip->mutex);		    	yield();			cfi_spin_lock(chip->mutex);		} else 		    	udelay(1);	} while( !time_after(jiffies, timeo) );	if( !ret && time_after( jiffies, timeo ) )	{	    	printk(KERN_WARNING "Waiting for write to complete timed out in do_write_buffer.");        	    	ret = -EIO;	}	if( ret == -EIO ) {	    	if( (dq1 & status) == dq1 ) {		    	printk( "Flash write to Buffer aborted @ 0x%lx = 0x%x\n", adr, status );			cfi_send_gen_cmd(0xAA, 0xaaa, chip->start, map, cfi, 1, NULL);			cfi_send_gen_cmd(0x55, 0x555, chip->start, map, cfi, 1, NULL);			cfi_send_gen_cmd(0xF0, 0xaaa, chip->start, map, cfi, 1, NULL);		} else {		    	printk( "Flash write to buffer faileed @ 0x%lx = 0x%x\n", adr, status );			cfi_write(map, CMD(0xF0), chip->start);		}	}	DISABLE_VPP(map);	chip->state = FL_READY;	wake_up(&chip->wq);	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;	*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[4];		__u32 datum;								map->copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);		while (len && i < CFIDEV_BUSWIDTH)			tmp_buf[i++] = buf[n++], len--;		if (cfi_buswidth_is_2()) {			datum = *(__u16*)tmp_buf;		} else if (cfi_buswidth_is_4()) {			datum = *(__u32*)tmp_buf;		} else {			return -EINVAL;  /* should never happen, but be safe */		}		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) {		__u32 datum;						if (cfi_buswidth_is_1()) {			datum = *(__u8*)buf;		} else if (cfi_buswidth_is_2()) {			datum = get_unaligned((__u16*)buf);		} else if (cfi_buswidth_is_4()) {			datum = get_unaligned((__u32*)buf);		} else {			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;		if (ofs >> cfi->chipshift) {			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);			}			chipnum ++; 			ofs = 0;			if (chipnum == cfi->numchips)				return 0;			chipstart = cfi->chips[chipnum].start;			if (cfi->fast_prog){				/* Go into unlock bypass mode for next set of chips */				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);			}		}	}	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);	}	/* Write the trailing bytes if any */	if (len & (CFIDEV_BUSWIDTH-1)) {		int i = 0, n = 0;		u_char tmp_buf[4];		__u32 datum;		map->copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);		while (len--)			tmp_buf[i++] = buf[n++];		if (cfi_buswidth_is_2()) {			datum = *(__u16*)tmp_buf;		} else if (cfi_buswidth_is_4()) {			datum = *(__u32*)tmp_buf;		} else {			return -EINVAL;  /* should never happen, but be safe */		}		ret = do_write_oneword(map, &cfi->chips[chipnum], 				ofs, datum, 0);		if (ret) 			return ret;				(*retlen) += n;	}	return 0;}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 = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;	int ret = 0;	int chipnum;	unsigned long ofs;		int count=0;	int retlen2=0;		/* code derived from cfi_cmdset_0001.c:cfi_intelext_write_words */	*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 & (CFIDEV_BUSWIDTH-1)) {		size_t local_len = (-ofs)&(CFIDEV_BUSWIDTH-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 > CFIDEV_BUSWIDTH) {		/* We must not cross write block boundaries */		int size = wbufsize - (ofs & (wbufsize-1));				if (size > len)			size = len & ~(CFIDEV_BUSWIDTH-1);		ret = do_write_buffer(map, &cfi->chips[chipnum], ofs, buf, size);				if(ret)			return ret;/*		while(ret&&(count<1000))		{			ret = do_write_buffer(map, &cfi->chips[chipnum], ofs, buf, size);			printk("count=%d\n",count);			count++;		}*//*		if(ret){			ret = cfi_amdstd_write_words(mtd, ofs, size, &retlen2, buf);			if(ret)				printk("error in write words\n");			ofs += size;			buf += size;			(*retlen) += retlen2;			len -= size;		}else{*/			ofs += size;			buf += size;			(*retlen) += size;			len -= size;//		}				if (ofs >> cfi->chipshift) {			chipnum ++; 			ofs = 0;			if (chipnum == cfi->numchips)				return 0;		}	}	/* ... and write the remaining bytes */	if (len > 0) {		size_t local_retlen;		ret = cfi_amdstd_write_words(mtd, ofs + (chipnum << cfi->chipshift),					     len, &local_retlen, buf);		if (ret)			return ret;		(*retlen) += local_retlen;	}	return 0;}static inline int do_erase_chip(struct map_info *map, struct flchip *chip){	unsigned int oldstatus, status;	unsigned int dq6, dq5;	unsigned long timeo = jiffies + HZ;	unsigned int adr;	struct cfi_private *cfi = map->fldrv_priv;	DECLARE_WAITQUEUE(wait, current); retry:	cfi_spin_lock(chip->mutex);	if (chip->state != FL_READY){		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;	}		chip->state = FL_ERASING;		/* Handle devices with one erase region, that only implement	 * the chip erase command.	 */	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);	timeo = jiffies + (HZ*20);	adr = cfi->addr_unlock1;#ifdef CONFIG_ARCH_EM86XX	/* We need extra delay here since reading bit5/bit6 operation may	   froze the chip for some times */	cfi_spin_unlock(chip->mutex);	schedule_timeout(((1<<cfi->cfiq->ChipEraseTimeoutTyp) * HZ) / 1000);	cfi_spin_lock(chip->mutex);#endif	/* Wait for the end of programing/erasure by using the toggle method.	 * As long as there is a programming procedure going on, bit 6 of the last	 * written byte is toggling it's state with each consectuve read.	 * The toggling stops as soon as the procedure is completed.	 *	 * If the process has gone on for too long on the chip bit 5 gets.	 * After bit5 is set you can kill the operation by sending a reset	 * command to the chip.	 */	dq6 = CMD(1<<6);	dq5 = CMD(1<<5);	oldstatus = cfi_read(map, adr);	status = cfi_read(map, adr);	while( ((status & dq6) != (oldstatus & dq6)) && 		((status & dq5) != dq5) &&		!time_after(jiffies, timeo)) {		int wait_reps;		/* an initial short sleep */		cfi_spin_unlock(chip->mutex);		schedule_timeout(HZ/100);		cfi_spin_lock(chip->mutex);				if (chip->state != FL_ERASING) {			/* Someone's suspended the erase. Sleep */			set_current_state(TASK_UNINTERRUPTIBLE);			add_wait_queue(&chip->wq, &wait);						cfi_spin_unlock(chip->mutex);			printk("erase suspended. Sleeping\n");						schedule();

⌨️ 快捷键说明

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