New Intel chip with CFIext version 1.3 not working.

Jarkko Lavinen jlavi at
Wed Nov 14 04:53:35 EST 2001

Is anybody using Intel chips with extended CFI query version 1.3?

Current version of the cfi_cmdset_0001.c rejects the chip and accepts
only the extended CFI versions 1.0, 1.1, and 1.2. The chip I am trying
to get working is Intel's 28F640W18 and its datasheet is available
from The
extended query is specified at the page 71 of the datasheet.

I tried to modify the driver by allowing also the extemded CFI version
1.3. After that the chip was accepted but sectors were locked and
writes failed The unlock function unlocked only the first sector, not 
the whole region requested.

I modified the function cfi_intelext_unlock() to unlock the whole
region requested. After that it was possible to unlock the chip and 
also erase it with erase_all. Mounting JFFS2, however, fails.

JFFS2 mount seems to fail because the chip has 4mbit partitions and
each of them has their own status. When the mount scans flash chip
contents and proceeds past the partition boundary, the status is not
anymore the same as in the previous boundary.

What happens is that cfi_cmdset_0001.c keeps the chip at state
FL_STATUS and when the mount proceeds to address 0x80000 it fails
because the chip is at read array mode and returns flash contents, not
the partition status.

I have attached the changes I made in cfi_cmdset_0001.c to get to this

Could anyone help me on solving this problem? Suggestions, please?

Jarkko Lavinen

Changes in function cfi_cmdset_0001():

                if (extp->MajorVersion != '1' ||
+#if 0
                    (extp->MinorVersion < '0' || extp->MinorVersion > '2')) {
+                   (extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
                        printk(KERN_WARNING "  Unknown IntelExt Extended Query "
                               "version %c.%c.\n",  extp->MajorVersion,

The function cfi_intelext_unlock() after my changes:

static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
	struct map_info *map = mtd->priv;
	struct cfi_private *cfi = map->fldrv_priv;
	int eraseoffset, erasesize, eraseblocks;
	unsigned long adr;
	int chipnum, ernum, ret = 0;
	int ofs_factor = cfi->interleave * cfi->device_type;
	unsigned long temp_adr = adr;
	unsigned long temp_len = len;

	/* Pass the whole chip through sector by sector and check for each
	   sector if the sector and the given interval overlap */
	for(ernum = 0; ernum < mtd->numeraseregions; ernum++) {
		struct mtd_erase_region_info *erp = &mtd->eraseregions[ernum];

		eraseoffset = erp->offset;
		erasesize = erp->erasesize;
		eraseblocks = erp->numblocks;

		printk("Erase offset %08x size %06x blocks %d\n",
		       eraseoffset, erasesize, eraseblocks);

		if (ofs > eraseoffset + erasesize)

		while (eraseblocks > 0) {
			if (ofs < eraseoffset + erasesize &&
			    ofs + len > eraseoffset) {

				chipnum = eraseoffset >> cfi->chipshift;
				adr = eraseoffset -
					(chipnum << cfi->chipshift);

				temp_adr = adr;
				temp_len = len;

				cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi,
						 cfi->device_type, NULL);
				while (temp_len) {
					printk("before unlock %x: block "
					       "status register is %x\n",
					       temp_adr, cfi_read_query(map, temp_adr+(2*ofs_factor)));
					temp_adr += mtd->erasesize;
					temp_len -= mtd->erasesize;

				cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi,
						 cfi->device_type, NULL);

				ret = do_unlock_oneblock(map,

				cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi,
						 cfi->device_type, NULL);
				printk("after unlock: block status register "
				       "is %x\n",
				       cfi_read_query(map, adr+(2*ofs_factor)));
				cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi,
						 cfi->device_type, NULL);
			eraseoffset += erasesize;
			eraseblocks --;

	return ret;

More information about the linux-mtd mailing list