Nor flash的探测
??? 首先说明一下,笔者使用的linux源码的版本是2.6.30。 ??? Map.h中定义了一个结构体: struct mtd_chip_driver { struct mtd_info *(*probe)(struct map_info *map);//探测函数 void (*destroy)(struct mtd_info *);//销毁 struct module *module; char *name;//芯片驱动的类型,如CFI,JEDEC,ROM,RAM等 struct list_head list;//将所有结构实体链接起来 }; mtd_chip_driver为所有芯片驱动程序提供了分类: (1)jedec_probe.c中定义了JEDEC标准的FLASH驱动; static struct mtd_chip_driver jedec_chipdrv = { .probe = jedec_probe,.name = "jedec_probe",.module = THIS_MODULE }; (2)cfi_probe.c中定义CFI标准的FLASH驱动; static struct mtd_chip_driver cfi_chipdrv = { .probe = cfi_probe,.name = "cfi_probe",.module = THIS_MODULE }; (3)Map_ram.c定义了以RAM作为MTD存储介质的驱动; static struct mtd_chip_driver mapram_chipdrv = { .probe = map_ram_probe,.name = "map_ram",.module = THIS_MODULE }; (4)Map_rom.c定义了以ROM作为MTD存储介质的驱动; static struct mtd_chip_driver maprom_chipdrv = { .probe = map_rom_probe,.name = "map_rom",.module = THIS_MODULE }; ?
它的代码在drivers/mtd/chips/Jedec_probe.c。从上面(1)中设置的jedec_chipdrv.probe函数开始执行: static struct mtd_info *jedec_probe(struct map_info *map) { /* * Just use the generic probe stuff to call our CFI-specific * chip_probe routine in all the possible permutations,etc. */ return mtd_do_chip_probe(map,&jedec_chip_probe); }
struct mtd_info *mtd_do_chip_probe(struct map_info *map,struct chip_probe *cp) { struct mtd_info *mtd = NULL; struct cfi_private *cfi; /* First probe the map to see if we have CFI stuff there. */ cfi = genprobe_ident_chips(map,cp); if (!cfi) return NULL; map->fldrv_priv = cfi; /* OK we liked it. Now find a driver for the command set it talks */ mtd = check_cmd_set(map,1); /* First the primary cmdset */ if (!mtd) mtd = check_cmd_set(map,0); /* Then the secondary */ if (mtd) { if (mtd->size > map->size) { printk(KERN_WARNING "Reducing visibility of %ldKiB chip to %ldKiBn",(unsigned long)mtd->size >> 10,(unsigned long)map->size >> 10); mtd->size = map->size; } return mtd; } printk(KERN_WARNING"gen_probe: No supported Vendor Command Set foundn"); kfree(cfi->cfiq); kfree(cfi); map->fldrv_priv = NULL; return NULL; } 先调用genprobe_ident_chips得到CFI结构,再判断是哪种指令集。FLASH的指令集有Intel、AMD、STAA指令,根据不同的指令,需要设置不同的操作。 1)cfi_cmdset_0001:Intel指令集,源文件drivers/mtd/chips/cfi_cmdset_0001.c 2)cfi_cmdset_0002:AMD指令集,源文件drivers/mtd/chips/cfi_cmdset_0002.c 3)cfi_cmdset_0020:STAA指令集,源文件drivers/mtd/chips/cfi_cmdset_0020.c 在这三个函数执行后,mtd_info实体被建立和初始化。 ? genprobe_ident_chips: static struct cfi_private *genprobe_ident_chips(struct map_info *map,struct chip_probe *cp) { struct cfi_private cfi; struct cfi_private *retcfi; unsigned long *chip_map; int i,j,mapsize; int max_chips; memset(&cfi,sizeof(cfi)); /* Call the probetype-specific code with all permutations of interleave and device type,etc. */ if (!genprobe_new_chip(map,cp,&cfi)) { /* The probe didn't like it */ pr_debug("%s: Found no %s device at location zeron",cp->name,map->name); return NULL; } #if 0 /* Let the CFI probe routine do this sanity check. The Intel and AMD probe routines won't ever return a broken CFI structure anyway,because they make them up themselves. */ if (cfi.cfiq->NumEraseRegions == 0) { printk(KERN_WARNING "Number of erase regions is zeron"); kfree(cfi.cfiq); return NULL; } #endif cfi.chipshift = cfi.cfiq->DevSize; if (cfi_interleave_is_1(&cfi)) { ; } else if (cfi_interleave_is_2(&cfi)) { cfi.chipshift++; } else if (cfi_interleave_is_4((&cfi))) { cfi.chipshift += 2; } else if (cfi_interleave_is_8(&cfi)) { cfi.chipshift += 3; } else { BUG(); } cfi.numchips = 1; /* * Allocate memory for bitmap of valid chips. * Align bitmap storage size to full byte. */ max_chips = map->size >> cfi.chipshift; if (!max_chips) { printk(KERN_WARNING "NOR chip too large to fit in mapping. Attempting to cope...n"); max_chips = 1; } mapsize = sizeof(long) * DIV_ROUND_UP(max_chips,BITS_PER_LONG); chip_map = kzalloc(mapsize,GFP_KERNEL); if (!chip_map) { printk(KERN_WARNING "%s: kmalloc failed for CFI chip mapn",map->name); kfree(cfi.cfiq); return NULL; } set_bit(0,chip_map); /* Mark first chip valid */ /* * Now probe for other chips,checking sensibly for aliases while * we're at it. The new_chip probe above should have let the first * chip in read mode. */ for (i = 1; i < max_chips; i++) { cp->probe_chip(map,i << cfi.chipshift,chip_map,&cfi); } ...代码略 return retcfi; } static int genprobe_new_chip(struct map_info *map,struct chip_probe *cp,struct cfi_private *cfi) { int min_chips = (map_bankwidth(map)/4?:1); /* At most 4-bytes wide. */ int max_chips = map_bankwidth(map); /* And minimum 1 */ int nr_chips,type; for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) { if (!cfi_interleave_supported(nr_chips)) continue; cfi->interleave = nr_chips; /* Minimum device size. Don't look for one 8-bit device in a 16-bit bus,etc. */ type = map_bankwidth(map) / nr_chips; for (; type <= CFI_DEVICETYPE_X32; type<<=1) { cfi->device_type = type; if (cp->probe_chip(map,NULL,cfi))//调用probe_chip,JEDEC和CFI调用各自的实现函数 return 1; } } return 0; } genprobe_ident_chips和genprobe_new_chip这两个函数的代码在Gen_probe.c中,这个文件的代码是JEDEC和CFI驱动共用的代码,为区分两者,使用了struct chip_probe作为参数传递。在Jedec_probe.c中定义的这个结构体是: static struct chip_probe jedec_chip_probe = { .name = "JEDEC",.probe_chip = jedec_probe_chip };
jedec_probe_chip函数的原型是 读者可能会奇怪,为何JEDEC flash的代码中会有个有关CFI的结构体struct cfi_private。这是因为代码的设计者把JEDEC模拟成了CFI设备,当cfi_private.cfi_mode==CFI_MODE_CFI时,它是一个真实的CFI设备,当cfi_private.cfi_mode==CFI_MODE_JEDEC时,它是JECEC模拟的CFI设备。 cfi_private结构: struct cfi_private { uint16_t cmdset; void *cmdset_priv; int interleave; int device_type; int cfi_mode; /* Are we a JEDEC device pretending to be CFI? */ int addr_unlock1; int addr_unlock2; struct mtd_info *(*cmdset_setup)(struct map_info *); struct cfi_ident *cfiq; /* For now only one. We insist that all devs must be of the same type. */ int mfr,id; int numchips; unsigned long chipshift; /* Because they're of the same type */ const char *im_name; /* inter_module name for cmdset_setup */ struct flchip chips[0]; /* per-chip data structure for each chip */ }; 系统可以有多个FLASH设备,numchips决定FLASH设备的个数。一个MTD设备也可以由多个FLASH设备组成,它用interleave表示,device_type表示它的位宽。例如一个位宽为32位的MTD设备由4个8位的FLASH设备组成,那么interleave=4。struct flchip chips用于描述每个FLASH设备的信息。 ? 再回到Jedec_probe.c中的jedec_probe_chip函数: jedec_probe_chip函数的主要作用是获取FLASH的信息并将它设置在cfi_private结构中。在此函数中,调用jedec_read_mfr和jedec_read_id获取生产厂商ID和设备ID,再调用jedec_match查找全局jedec_table表,找到相应的FLASH信息。最后调用cfi_jedec_setup完成cfi_private结构的设置。 ? struct amd_flash_info { const char *name;//设备名称 const uint16_t mfr_id;//厂商ID const uint16_t dev_id;//设备ID const uint8_t dev_size;//容量大小 const uint8_t nr_regions;//按擦除大小的分类,分类的个数 const uint16_t cmd_set;//指令集类型 const uint32_t regions[6];//区域 const uint8_t devtypes; /* Bitmask for x8,x16 etc. 指令类型*/ const uint8_t uaddr; /* unlock addrs for 8,16,32,64 */ }; 如果FLASH设备的信息不在此表表,需要自定义加入。例如: { .mfr_id = MANUFACTURER_SST,.dev_id = SST39LF040,.name = "SST 39LF040",.devtypes = CFI_DEVICETYPE_X8,.uaddr = MTD_UADDR_0x5555_0x2AAA,.dev_size = SIZE_512KiB,.cmd_set = P_ID_AMD_STD,.nr_regions = 1,.regions = { ERASEINFO(0x01000,128),}
CFI Flash的探测和JEDEC的探测有很多相似处,它们都调用了Gen_probe.c中的公共代码。CFI Flash的驱动代码在deivers/mtd/Cfi_probe.c中。 mtd_chip_driver的结构: static struct mtd_chip_driver cfi_chipdrv = { .probe = cfi_probe,.module = THIS_MODULE };
static struct chip_probe cfi_chip_probe = { .name = "CFI",.probe_chip = cfi_probe_chip }; struct mtd_info *cfi_probe(struct map_info *map) { /* * Just use the generic probe stuff to call our CFI-specific * chip_probe routine in all the possible permutations,&cfi_chip_probe); }
上面已经讲过mtd_do_chip_probe函数,它的内部调用genprobe_ident_chips,再调用genprobe_new_chip,并最终调用cp->probe_chip。这里它对应的是Cfi_probe.c中的cfi_probe_chip函数。和JEDEC不同,CFI直接通过命令读取FLASH的信息,drivers/mtd/chips/cfi_util.c提供了这些代码。
无论是哪种类型的FLASH的probe,都是为了将信息生成到mtd_info结构中。先通过FLASH驱动读ID或读CFI结构的方法填充一个cfi_private结构,然后将这个结构体赋给map_info中的fldrv_priv,最后将map_info结构的指针赋给mtd_info->priv。这样,所有的信息都被保存在mtd_info。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |