📄 cfi_probe.c
字号:
/* Common Flash Interface probe code. (C) 2000 Red Hat. GPL'd. $Id: cfi_probe.c,v 1.12 2000/07/03 13:29:16 dwmw2 Exp $*/#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <asm/io.h>#include <asm/byteorder.h>#include <linux/errno.h>#include <linux/malloc.h>#include <linux/mtd/map.h>#include <linux/mtd/cfi.h>struct mtd_info *cfi_probe(struct map_info *);static void print_cfi_ident(struct cfi_ident *);static void check_cmd_set(struct map_info *, int, unsigned long);static struct cfi_private *cfi_cfi_probe(struct map_info *);static const char im_name[] = "cfi_probe";/* 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 mtd 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_probe(struct map_info *map){ struct mtd_info *mtd = NULL; struct cfi_private *cfi; /* First probe the map to see if we have CFI stuff there. */ cfi = cfi_cfi_probe(map); if (!cfi) return NULL; map->fldrv_priv = cfi; map->im_name = im_name; /* OK we liked it. Now find a driver for the command set it talks */ check_cmd_set(map, 1, cfi->chips[0].start); /* First the primary cmdset */ check_cmd_set(map, 0, cfi->chips[0].start); /* Then the secondary */ /* check_cmd_set() will have used inter_module_get to increase the use count of the module which provides the command set driver. If we're quitting, we have to decrease it again. */ if(cfi->cmdset_setup) { mtd = cfi->cmdset_setup(map); if (mtd) return mtd; inter_module_put(cfi->im_name); } printk("No supported Vendor Command Set found\n"); kfree(cfi); map->fldrv_priv = NULL; return NULL;}static int cfi_probe_new_chip(struct map_info *map, unsigned long base, struct flchip *chips, struct cfi_private *cfi){ switch (map->buswidth) { case 1: { unsigned char tmp = map->read8(map, base + 0x55); /* If there's a device there, put it in Query Mode */ map->write8(map, 0x98, base+0x55); if (map->read8(map,base+0x10) == 'Q' && map->read8(map,base+0x11) == 'R' && map->read8(map,base+0x12) == 'Y') { printk("%s: Found a CFI device at 0x%lx in 8 bit mode\n", map->name, base); if (chips) { /* Check previous chips for aliases */ printk("FIXME: Do alias check at line %d of cfi_probe.c\n", __LINE__); /* Put it back into Read Mode */ map->write8(map, 0x98, base+0x55); } return 1; } else { if (map->read8(map, base + 0x55) == 0x98) { /* It looks like RAM. Put back the stuff we overwrote */ map->write8(map, tmp, base+0x55); } return 0; } } case 2: { __u16 tmp = map->read16(map, base + 0xaa); /* If there's a device there, put it into Query Mode */ map->write16(map, 0x9898, base+0xAA); if (map->read16(map, base+0x20) == cpu_to_le16(0x0051) && map->read16(map, base+0x22) == cpu_to_le16(0x0052) && map->read16(map, base+0x24) == cpu_to_le16(0x0059)) { printk("%s: Found a CFI device at 0x%lx in 16 bit mode\n", map->name, base); if (chips) { /* Check previous chips for aliases */ int i; for (i=0; i < cfi->numchips; i++) { /* This chip should be in read mode if it's one we've already touched. */ if (map->read16(map, chips[i].start+0x20) == cpu_to_le16(0x0051) && map->read16(map, chips[i].start+0x22) == cpu_to_le16(0x0052) && map->read16(map, chips[i].start+0x24) == cpu_to_le16(0x0059)){ /* Either the old chip has got 'Q''R''Y' in a most unfortunate place, or it's an alias of the new chip. Double-check that it's in read mode, and check. */ map->write16(map, 0xffff, chips[i].start+0x20); if (map->read16(map, chips[i].start+0x20) == cpu_to_le16(0x0051) && map->read16(map, chips[i].start+0x22) == cpu_to_le16(0x0052) && map->read16(map, chips[i].start+0x24) == cpu_to_le16(0x0059)) { /* Yes it's got QRY for data. Most unfortunate. Stick the old one in read mode too. */ map->write16(map, 0xffff, base); if (map->read16(map, base+0x20) == cpu_to_le16(0x0051) && map->read16(map, base+0x22) == cpu_to_le16(0x0052) && map->read16(map, base+0x24) == cpu_to_le16(0x0059)) { /* OK, so has the new one. Assume it's an alias */ printk("T'was probably an alias for the chip at 0x%lx\n", chips[i].start); return 1; } /* else no, they're different, fall through. */ } else { /* No the old one hasn't got QRY for data. Therefore, it's an alias of the new one. */ map->write16(map, 0xffff, base+0xaa); /* Just to be paranoid. */ map->write16(map, 0xffff, chips[i].start+0xaa); printk("T'was an alias for the chip at 0x%lx\n", chips[i].start); return 1; } } /* No, the old one didn't look like it's in query mode. Next. */ } /* OK, if we got to here, then none of the previous chips appear to be aliases for the current one. */ if (cfi->numchips == MAX_CFI_CHIPS) { printk("%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS); /* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */ return 1; } printk("Not an alias. Adding\n"); chips[cfi->numchips].start = base; chips[cfi->numchips].state = FL_READY; chips[cfi->numchips].mutex = &chips[cfi->numchips]._spinlock; cfi->numchips++; /* Put it back into Read Mode */ map->write16(map, 0xffff, base+0xaa); } return 1; } else if (map->read16(map, base+0x20) == 0x5151 && map->read16(map, base+0x22) == 0x5252 && map->read16(map, base+0x24) == 0x5959) { printk("%s: Found a coupled pair of CFI devices at %lx in 8 bit mode\n", map->name, base); if (chips) { /* Check previous chips for aliases */ printk("FIXME: Do alias check at line %d of cfi_probe.c\n", __LINE__); /* Put it back into Read Mode */ map->write16(map, 0xffff, base+0xaa); } return 2; } else { if (map->read16(map, base+0xaa) == 0x9898) { /* It looks like RAM. Put back the stuff we overwrote */ map->write16(map, tmp, base+0xaa); } return 0; } } case 4: { __u32 tmp = map->read32(map, base+0x154); /* If there's a device there, put it into Query Mode */ map->write32(map, 0x98989898, base+0x154); if (map->read32(map, base+0x40) == cpu_to_le32(0x00000051) && map->read32(map, base+0x44) == cpu_to_le32(0x00000052) && map->read32(map, base+0x48) == cpu_to_le32(0x00000059)) { /* This isn't actually in the CFI spec - only x8 and x16 are. */ printk("%s: Found a CFI device at %lx in 32 bit mode\n", map->name, base); if (chips) { /* Check previous chips for aliases */ printk("FIXME: Do alias check at line %d of cfi_probe.c\n", __LINE__); /* Put it back into read mode */ map->write32(map, 0xffffffff, base+0x154); } return 1; } else if (map->read32(map, base+0x40) == cpu_to_le32(0x00510051) && map->read32(map, base+0x44) == cpu_to_le32(0x00520052) && map->read32(map, base+0x48) == cpu_to_le32(0x00590059)) { printk("%s: Found a coupled pair of CFI devices at location %lx in 16 bit mode\n", map->name, base); if (chips) { /* Check previous chips for aliases */ printk("FIXME: Do alias check at line %d of cfi_probe.c\n", __LINE__); /* Put it back into read mode */ map->write32(map, 0xffffffff, base+0x154); } return 2; } else if (map->read32(map, base+0x40) == 0x51515151 && map->read32(map, base+0x44) == 0x52525252 && map->read32(map, base+0x48) == 0x59595959) { printk("%s: Found four side-by-side CFI devices at location %lx in 8 bit mode\n", map->name, base); if (chips) { /* Check previous chips for aliases */ printk("FIXME: Do alias check at line %d of cfi_probe.c\n", __LINE__); /* Put it back into read mode */ map->write32(map, 0xffffffff, base+0x154); } return 4; } else { if (map->read32(map, base+0x154) == 0x98989898) { /* It looks like RAM. Put back the stuff we overwrote */ map->write32(map, tmp, base+0x154); } return 0; } } default: printk(KERN_WARNING "cfi_probe called with strange buswidth %d\n", map->buswidth); return 0; }}static struct cfi_private *cfi_cfi_probe(struct map_info *map){ unsigned long base=0; struct cfi_private cfi;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -