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

📄 cfi_cmdset_0001.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Common Flash Interface support: *   Intel Extended Vendor Command Set (ID 0x0001) * * (C) 2000 Red Hat. GPL'd * * $Id: cfi_cmdset_0001.c,v 1.114 2003/03/18 12:28:40 dwmw2 Exp $ * *  * 10/10/2000	Nicolas Pitre <nico@cam.org> * 	- completely revamped method functions so they are aware and * 	  independent of the flash geometry (buswidth, interleave, etc.) * 	- scalability vs code size is completely set at compile-time * 	  (see include/linux/mtd/cfi.h for selection) *	- optimized write buffer method * 02/05/2002	Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com> *	- reworked lock/unlock/erase support for var size flash */#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <asm/io.h>#include <asm/byteorder.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/mtd/map.h>#include <linux/mtd/cfi.h>#include <linux/mtd/compatmac.h>// debugging, turns off buffer write mode #define FORCE_WORD_WRITEstatic int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);static void cfi_intelext_sync (struct mtd_info *);static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len);static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);static int cfi_intelext_suspend (struct mtd_info *);static void cfi_intelext_resume (struct mtd_info *);static void cfi_intelext_destroy(struct mtd_info *);struct mtd_info *cfi_cmdset_0001(struct map_info *, int);static struct mtd_info *cfi_intelext_setup (struct map_info *);static int do_point (struct mtd_info *mtd, loff_t from, size_t len,		     size_t *retlen, u_char **mtdbuf);static void do_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,			size_t len);static struct mtd_chip_driver cfi_intelext_chipdrv = {	probe: NULL, /* Not usable directly */	destroy: cfi_intelext_destroy,	name: "cfi_cmdset_0001",	module: THIS_MODULE};/* #define DEBUG_LOCK_BITS *//* #define DEBUG_CFI_FEATURES */#ifdef DEBUG_CFI_FEATURESstatic void cfi_tell_features(struct cfi_pri_intelext *extp){	int i;	printk("  Feature/Command Support: %4.4X\n", extp->FeatureSupport);	printk("     - Chip Erase:         %s\n", extp->FeatureSupport&1?"supported":"unsupported");	printk("     - Suspend Erase:      %s\n", extp->FeatureSupport&2?"supported":"unsupported");	printk("     - Suspend Program:    %s\n", extp->FeatureSupport&4?"supported":"unsupported");	printk("     - Legacy Lock/Unlock: %s\n", extp->FeatureSupport&8?"supported":"unsupported");	printk("     - Queued Erase:       %s\n", extp->FeatureSupport&16?"supported":"unsupported");	printk("     - Instant block lock: %s\n", extp->FeatureSupport&32?"supported":"unsupported");	printk("     - Protection Bits:    %s\n", extp->FeatureSupport&64?"supported":"unsupported");	printk("     - Page-mode read:     %s\n", extp->FeatureSupport&128?"supported":"unsupported");	printk("     - Synchronous read:   %s\n", extp->FeatureSupport&256?"supported":"unsupported");	for (i=9; i<32; i++) {		if (extp->FeatureSupport & (1<<i)) 			printk("     - Unknown Bit %X:      supported\n", i);	}		printk("  Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport);	printk("     - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported");	for (i=1; i<8; i++) {		if (extp->SuspendCmdSupport & (1<<i))			printk("     - Unknown Bit %X:               supported\n", i);	}		printk("  Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask);	printk("     - Lock Bit Active:      %s\n", extp->BlkStatusRegMask&1?"yes":"no");	printk("     - Valid Bit Active:     %s\n", extp->BlkStatusRegMask&2?"yes":"no");	for (i=2; i<16; i++) {		if (extp->BlkStatusRegMask & (1<<i))			printk("     - Unknown Bit %X Active: yes\n",i);	}		printk("  Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", 	       extp->VccOptimal >> 8, extp->VccOptimal & 0xf);	if (extp->VppOptimal)		printk("  Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", 		       extp->VppOptimal >> 8, extp->VppOptimal & 0xf);}#endif/* This routine is made available to other mtd code via * inter_module_register.  It must only be accessed through * inter_module_get which will bump the use count of this module.  The * addresses passed back in cfi are valid as long as the use count of * this module is non-zero, i.e. between inter_module_get and * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000. */struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary){	struct cfi_private *cfi = map->fldrv_priv;	int i;	__u32 base = cfi->chips[0].start;	if (cfi->cfi_mode == CFI_MODE_CFI) {		/* 		 * It's a real CFI chip, not one for which the probe		 * routine faked a CFI structure. So we read the feature		 * table from it.		 */		__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;		struct cfi_pri_intelext *extp;		int ofs_factor = cfi->interleave * cfi->device_type;		//printk(" Intel/Sharp Extended Query Table at 0x%4.4X\n", adr);		if (!adr)			return NULL;		/* Switch it into Query Mode */		cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);		extp = kmalloc(sizeof(*extp), GFP_KERNEL);		if (!extp) {			printk(KERN_ERR "Failed to allocate memory\n");			return NULL;		}				/* Read in the Extended Query Table */		for (i=0; i<sizeof(*extp); i++) {			((unsigned char *)extp)[i] = 				cfi_read_query(map, (base+((adr+i)*ofs_factor)));		}				if (extp->MajorVersion != '1' || 		    (extp->MinorVersion < '0' || extp->MinorVersion > '3')) {			printk(KERN_WARNING "  Unknown IntelExt Extended Query "			       "version %c.%c.\n",  extp->MajorVersion,			       extp->MinorVersion);			kfree(extp);			return NULL;		}				/* Do some byteswapping if necessary */		extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);		extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);		extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);			#ifdef DEBUG_CFI_FEATURES		/* Tell the user about it in lots of lovely detail */		cfi_tell_features(extp);#endif			if(extp->SuspendCmdSupport & 1) {//#define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ 			printk(KERN_WARNING "cfi_cmdset_0001: Suspend "			       "erase on write disabled.\n");			extp->SuspendCmdSupport &= ~1;#else			printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n");#endif		}		/* Install our own private info structure */		cfi->cmdset_priv = extp;		}	for (i=0; i< cfi->numchips; i++) {		cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;		cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;		cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;		cfi->chips[i].ref_point_counter = 0;	}			map->fldrv = &cfi_intelext_chipdrv;		/* Make sure it's in read mode */	cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);	return cfi_intelext_setup(map);}static struct mtd_info *cfi_intelext_setup(struct map_info *map){	struct cfi_private *cfi = map->fldrv_priv;	struct mtd_info *mtd;	unsigned long offset = 0;	int i,j;	unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);	//printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips);	if (!mtd) {		printk(KERN_ERR "Failed to allocate memory for MTD device\n");		goto setup_err;	}	memset(mtd, 0, sizeof(*mtd));	mtd->priv = map;	mtd->type = MTD_NORFLASH;	mtd->size = devsize * cfi->numchips;	mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;	mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) 			* mtd->numeraseregions, GFP_KERNEL);	if (!mtd->eraseregions) { 		printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");		goto setup_err;	}		for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {		unsigned long ernum, ersize;		ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;		ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;		if (mtd->erasesize < ersize) {			mtd->erasesize = ersize;		}		for (j=0; j<cfi->numchips; j++) {			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;		}		offset += (ersize * ernum);	}	if (offset != devsize) {		/* Argh */		printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);		goto setup_err;	}	for (i=0; i<mtd->numeraseregions;i++){		printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n",		       i,mtd->eraseregions[i].offset,		       mtd->eraseregions[i].erasesize,		       mtd->eraseregions[i].numblocks);	}	/* Also select the correct geometry setup too */ 	mtd->erase = cfi_intelext_erase_varsize;	mtd->read = cfi_intelext_read;	if(map->point && map->unpoint){		mtd->point = do_point;		mtd->unpoint = do_unpoint;	}#ifndef FORCE_WORD_WRITE	if ( cfi->cfiq->BufWriteTimeoutTyp ) {		printk("Using buffer write method\n" );		mtd->write = cfi_intelext_write_buffers;	} else {#else	{#endif		printk("Using word write method\n" );		mtd->write = cfi_intelext_write_words;	}	mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;	mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;	mtd->sync = cfi_intelext_sync;	mtd->lock = cfi_intelext_lock;	mtd->unlock = cfi_intelext_unlock;	mtd->suspend = cfi_intelext_suspend;	mtd->resume = cfi_intelext_resume;	mtd->flags = MTD_CAP_NORFLASH;	map->fldrv = &cfi_intelext_chipdrv;	MOD_INC_USE_COUNT;	mtd->name = map->name;	return mtd; setup_err:	if(mtd) {		if(mtd->eraseregions)			kfree(mtd->eraseregions);		kfree(mtd);	}	kfree(cfi->cmdset_priv);	kfree(cfi->cfiq);	return NULL;}static int do_point_onechip (struct map_info *map,  struct flchip *chip, loff_t adr, size_t len){	cfi_word status, status_OK;	unsigned long timeo;	DECLARE_WAITQUEUE(wait, current);	unsigned long cmd_addr;	struct cfi_private *cfi = map->fldrv_priv;	adr += chip->start;	/* Ensure cmd read/writes are aligned. */ 	cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); 	/* Let's determine this according to the interleave only once */	status_OK = CMD(0x80);	timeo = jiffies + HZ; retry:	spin_lock(chip->mutex);	/* Check that the chip's ready to talk to us.	 * If it's in FL_ERASING state, suspend it and make it talk now.	 */	switch (chip->state) {	case FL_READY:	case FL_POINT:		break;	case FL_CFI_QUERY:	case FL_JEDEC_QUERY:		cfi_write(map, CMD(0x70), cmd_addr);		chip->state = FL_STATUS;	case FL_STATUS:		status = cfi_read(map, cmd_addr);		if ((status & status_OK) == status_OK) {			cfi_write(map, CMD(0xff), cmd_addr);			chip->state = FL_READY;			break;		}				/* Urgh. Chip not yet ready to talk to us. */		if (time_after(jiffies, timeo)) {			spin_unlock(chip->mutex);			printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %llx\n", (__u64)status);			return -EIO;		}		/* Latency issues. Drop the lock, wait a while and retry */		spin_unlock(chip->mutex);		cfi_udelay(1);		goto retry;	default:		/* Stick ourselves on a wait queue to be woken when		   someone changes the status */		set_current_state(TASK_UNINTERRUPTIBLE);		add_wait_queue(&chip->wq, &wait);		spin_unlock(chip->mutex);		schedule();		remove_wait_queue(&chip->wq, &wait);		timeo = jiffies + HZ;		goto retry;	}	chip->state = FL_POINT;	chip->ref_point_counter++;	spin_unlock(chip->mutex);	return 0;}static int do_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	unsigned long ofs;	int chipnum;	int ret = 0;	if (from + len > mtd->size)		return -EINVAL;		*mtdbuf = map->point(map, from, len);	if(*mtdbuf == NULL)

⌨️ 快捷键说明

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