Example #1
0
void __xipram cfi_qry_mode_off(uint32_t base, struct map_info *map,
			       struct cfi_private *cfi)
{
	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
	/* M29W128G flashes require an additional reset command
	   when exit qry mode */
	if ((cfi->mfr == CFI_MFR_ST) && (cfi->id == 0x227E || cfi->id == 0x7E))
		cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
}
struct cfi_extquery *
cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
{
	struct cfi_private *cfi = map->fldrv_priv;
	__u32 base = 0; // cfi->chips[0].start;
	int ofs_factor = cfi->interleave * cfi->device_type;
	int i;
	struct cfi_extquery *extp = NULL;

	printk(" %s Extended Query Table at 0x%4.4X\n", name, adr);
	if (!adr)
		goto out;

	/* Switch it into Query Mode */
	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);

	extp = kmalloc(size, GFP_KERNEL);
	if (!extp) {
		printk(KERN_ERR "Failed to allocate memory\n");
		goto out;
	}
		
	/* Read in the Extended Query Table */
	for (i=0; i<size; i++) {
		((unsigned char *)extp)[i] = 
			cfi_read_query(map, base+((adr+i)*ofs_factor));
	}

#ifndef CONFIG_BCM96348
	/* XXX: Some AMD flashes do not report the correct version (they 
	 * return zero instead).*/
	
	if (extp->MajorVersion != '1' || 
	    (extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
		printk(KERN_WARNING "  Unknown %s Extended Query "
		       "version %c.%c.\n",  name, extp->MajorVersion,
		       extp->MinorVersion);
		kfree(extp);
		extp = NULL;
		goto out;
	}
#endif

out:
	/* Make sure it's in read mode */
	cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0xff, 0, base, map, cfi, cfi->device_type, NULL);

	return extp;
}
Example #3
0
static inline int cfi_isSST(struct map_info *map,struct cfi_private *cfi, __u32 base)
{
        int man_id;

	cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x90, 0x5555, base, map, cfi, cfi->device_type, NULL);
        man_id = cfi_read_query(map, base);

	/* SST manufacture id = 0xBF */
        if(man_id==0xBF){
                return 1;
        }else{
                return 0;
        }

}
Example #4
0
static int cfi_chip_setup(struct map_info *map, 
		   struct cfi_private *cfi)
{
	int ofs_factor = cfi->interleave*cfi->device_type;
	__u32 base = 0;
	int num_erase_regions = cfi_read_query(map, base + (0x10 + 28)*ofs_factor);
	int i;

#ifdef DEBUG_CFI
	printk("Number of erase regions: %d\n", num_erase_regions);
#endif
	if (!num_erase_regions)
		return 0;

	cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL);
	if (!cfi->cfiq) {
		printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name);
		return 0;
	}
	
	memset(cfi->cfiq,0,sizeof(struct cfi_ident));	
	
	cfi->cfi_mode = CFI_MODE_CFI;
	cfi->fast_prog=1;		/* CFI supports fast programming */
	
	/* Read the CFI info structure */
	for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) {
		((unsigned char *)cfi->cfiq)[i] = cfi_read_query(map,base + (0x10 + i)*ofs_factor);
	}
	
	/* Do any necessary byteswapping */
	cfi->cfiq->P_ID = le16_to_cpu(cfi->cfiq->P_ID);
	
	cfi->cfiq->P_ADR = le16_to_cpu(cfi->cfiq->P_ADR);
	cfi->cfiq->A_ID = le16_to_cpu(cfi->cfiq->A_ID);
	cfi->cfiq->A_ADR = le16_to_cpu(cfi->cfiq->A_ADR);
	cfi->cfiq->InterfaceDesc = le16_to_cpu(cfi->cfiq->InterfaceDesc);
	cfi->cfiq->MaxBufWriteSize = le16_to_cpu(cfi->cfiq->MaxBufWriteSize);

#ifdef DEBUG_CFI
	/* Dump the information therein */
	print_cfi_ident(cfi->cfiq);
#endif

	for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
		cfi->cfiq->EraseRegionInfo[i] = le32_to_cpu(cfi->cfiq->EraseRegionInfo[i]);
		
#ifdef DEBUG_CFI		
		printk("  Erase Region #%d: BlockSize 0x%4.4X bytes, %d blocks\n",
		       i, (cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff, 
		       (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1);
#endif
	}
	/* Put it back into Read Mode */
	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);

	return 1;
}
Example #5
0
/*
 *	Set the Intel flash back to read mode since some old boot
 *	loaders don't.
 */
static int nettel_reboot_notifier(struct notifier_block *nb, unsigned long val, void *v)
{
	struct cfi_private *cfi = nettel_intel_map.fldrv_priv;
	unsigned long b;

	/* Make sure all FLASH chips are put back into read mode */
	for (b = 0; (b < nettel_intel_partitions[3].size); b += 0x100000) {
		cfi_send_gen_cmd(0xff, 0x55, b, &nettel_intel_map, cfi,
			cfi->device_type, NULL);
	}
	return(NOTIFY_OK);
}
Example #6
0
static int nettel_reboot_notifier(
    struct notifier_block *nb,
    unsigned long val,
    void *v)
{
    struct cfi_private *cfi = nettel_flash_map.fldrv_priv;
    int i;
 
    for (i = 0; cfi && i < cfi->numchips; i++)
        cfi_send_gen_cmd(0xff, 0x55, cfi->chips[i].start, &nettel_flash_map,
                cfi, cfi->device_type, NULL);
    
    return(NOTIFY_OK);
}
Example #7
0
static int cfi_probe_chip(struct map_info *map, __u32 base,
			  struct flchip *chips, struct cfi_private *cfi)
{
	int i;
	
	if ((base + 0) >= map->size) {
		printk(KERN_NOTICE
			"Probe at base[0x00](0x%08lx) past the end of the map(0x%08lx)\n",
			(unsigned long)base, map->size -1);
		return 0;
	}
	if ((base + 0xff) >= map->size) {
		printk(KERN_NOTICE
			"Probe at base[0x55](0x%08lx) past the end of the map(0x%08lx)\n",
			(unsigned long)base + 0x55, map->size -1);
		return 0;
	}
	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);

	/* SST Flash on board ? */
	isSST=cfi_isSST(map,cfi,base);

	if(isSST)
	{
		cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
		cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
		cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL);
	}
	else
	{
		cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
	}
	
	if (!qry_present(map,base,cfi))
		return 0;

	if (!cfi->numchips) {
		/* This is the first time we're called. Set up the CFI 
		   stuff accordingly and return */
		return cfi_chip_setup(map, cfi);
	}

	/* Check each previous chip to see if it's an alias */
	for (i=0; i<cfi->numchips; i++) {
		/* This chip should be in read mode if it's one
		   we've already touched. */
		if (qry_present(map,chips[i].start,cfi)) {
			/* Eep. This chip also had the QRY marker. 
			 * Is it an alias for the new one? */
			cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL);

			/* If the QRY marker goes away, it's an alias */
			if (!qry_present(map, chips[i].start, cfi)) {
				printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
				       map->name, base, chips[i].start);
				return 0;
			}
			/* Yes, it's actually got QRY for data. Most 
			 * unfortunate. Stick the new chip in read mode
			 * too and if it's the same, assume it's an alias. */
			/* FIXME: Use other modes to do a proper check */
			cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
			
			if (qry_present(map, base, cfi)) {
				printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
				       map->name, base, chips[i].start);
				return 0;
			}
		}
	}
	
	/* 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(KERN_WARNING"%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;
	}
	chips[cfi->numchips].start = base;
	chips[cfi->numchips].state = FL_READY;
	cfi->numchips++;
	
	/* Put it back into Read Mode */
	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);

	printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n",
	       map->name, cfi->interleave, cfi->device_type*8, base,
	       map->buswidth*8);
	
	return 1;
}
Example #8
0
static int cfi_chip_setup(struct map_info *map,
                          struct cfi_private *cfi)
{
    int ofs_factor = cfi->interleave*cfi->device_type;
    __u32 base = 0;
    int num_erase_regions = cfi_read_query(map, base + (0x10 + 28)*ofs_factor);
    int i;

#ifdef DEBUG_CFI
    printk("Number of erase regions: %d\n", num_erase_regions);
#endif
    if (!num_erase_regions)
        return 0;

    cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL);
    if (!cfi->cfiq) {
        printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name);
        return 0;
    }

    memset(cfi->cfiq,0,sizeof(struct cfi_ident));

    cfi->cfi_mode = CFI_MODE_CFI;
    cfi->fast_prog=1;		/* CFI supports fast programming */

    /* Read the CFI info structure */
    for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) {
        ((unsigned char *)cfi->cfiq)[i] = cfi_read_query(map,base + (0x10 + i)*ofs_factor);
    }

    /* Do any necessary byteswapping */
    cfi->cfiq->P_ID = le16_to_cpu(cfi->cfiq->P_ID);

    cfi->cfiq->P_ADR = le16_to_cpu(cfi->cfiq->P_ADR);
    cfi->cfiq->A_ID = le16_to_cpu(cfi->cfiq->A_ID);
    cfi->cfiq->A_ADR = le16_to_cpu(cfi->cfiq->A_ADR);
    cfi->cfiq->InterfaceDesc = le16_to_cpu(cfi->cfiq->InterfaceDesc);
    cfi->cfiq->MaxBufWriteSize = le16_to_cpu(cfi->cfiq->MaxBufWriteSize);

    /*
     * ST screwed up the CFI interface for buffer writes on their parts,
     * so this needs to be fixed up by hand here.
         *
         * A possible enhancment is that instead of just reverting back
         * to word write (as this does), we could use the ST specific double
         * word write instead.
     */

    if (cfi_read_query(map,base) == 0x20) {
        cfi->cfiq->BufWriteTimeoutTyp = 0;
        cfi->cfiq->BufWriteTimeoutMax = 0;
    }

#ifdef DEBUG_CFI
    /* Dump the information therein */
    print_cfi_ident(cfi->cfiq);
#endif

    for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
        cfi->cfiq->EraseRegionInfo[i] = le32_to_cpu(cfi->cfiq->EraseRegionInfo[i]);

#ifdef DEBUG_CFI
        printk("  Erase Region #%d: BlockSize 0x%4.4X bytes, %d blocks\n",
               i, (cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff,
               (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1);
#endif
    }
    /* Put it back into Read Mode */
    cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);

    /* some devices don't respond to 0xF0, so send 0xFF to be sure */
    cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);

    return 1;
}
struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
{
	struct cfi_private *cfi = map->fldrv_priv;
	unsigned char bootloc;
	int ofs_factor = cfi->interleave * cfi->device_type;
	int i;
	__u8 major, minor;
	__u32 base = cfi->chips[0].start;

	if (cfi->cfi_mode==CFI_MODE_CFI){
		__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;

		cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
		
		major = cfi_read_query(map, base + (adr+3)*ofs_factor);
		minor = cfi_read_query(map, base + (adr+4)*ofs_factor);
		
		printk(KERN_NOTICE " Amd/Fujitsu Extended Query Table v%c.%c at 0x%4.4X\n",
		       major, minor, adr);
				cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL);
		
		cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
		cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
		cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
		cfi->mfr = cfi_read_query(map, base);
		cfi->id = cfi_read_query(map, base + ofs_factor);    

		/* Wheee. Bring me the head of someone at AMD. */
#ifdef AMD_BOOTLOC_BUG
		if (((major << 8) | minor) < 0x3131) {
			/* CFI version 1.0 => don't trust bootloc */
			if (cfi->id & 0x80) {
				printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id);
				bootloc = 3;	/* top boot */
			} else {
				bootloc = 2;	/* bottom boot */
			}
		} else
#endif
			{
				cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
				bootloc = cfi_read_query(map, base + (adr+15)*ofs_factor);
			}
		if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) {
			printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name);
			
			for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) {
				int j = (cfi->cfiq->NumEraseRegions-1)-i;
				__u32 swap;
				
				swap = cfi->cfiq->EraseRegionInfo[i];
				cfi->cfiq->EraseRegionInfo[i] = cfi->cfiq->EraseRegionInfo[j];
				cfi->cfiq->EraseRegionInfo[j] = swap;
			}
		}
		switch (cfi->device_type) {
		case CFI_DEVICETYPE_X8:
			cfi->addr_unlock1 = 0x555; 
			cfi->addr_unlock2 = 0x2aa; 
			break;
		case CFI_DEVICETYPE_X16:
			cfi->addr_unlock1 = 0xaaa;
			if (map->buswidth == cfi->interleave) {
				/* X16 chip(s) in X8 mode */
				cfi->addr_unlock2 = 0x555;
			} else {
				cfi->addr_unlock2 = 0x554;
			}
			break;
		case CFI_DEVICETYPE_X32:
			cfi->addr_unlock2 = 0xaaa; 
			if (map->buswidth == cfi->interleave) {
                        	cfi->addr_unlock1 = 0x1555;
			} else {
				cfi->addr_unlock1 = 0x1554;
			}
			break;
		default:
			printk(KERN_NOTICE "Eep. Unknown cfi_cmdset_0002 device type %d\n", cfi->device_type);
			return NULL;
		}
	} /* CFI mode */

	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;
	}		
	
	map->fldrv = &cfi_amdstd_chipdrv;

	cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL);
	return cfi_amdstd_setup(map);
}
Example #10
0
int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map,
			     struct cfi_private *cfi)
{
	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
	if (cfi_qry_present(map, base, cfi))
		return 1;
	/* QRY not found probably we deal with some odd CFI chips */
	/* Some revisions of some old Intel chips? */
	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
	if (cfi_qry_present(map, base, cfi))
		return 1;
	/* ST M29DW chips */
	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL);
	if (cfi_qry_present(map, base, cfi))
		return 1;
	/* some old SST chips, e.g. 39VF160x/39VF320x */
	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL);
	if (cfi_qry_present(map, base, cfi))
		return 1;
	/* SST 39VF640xB */
	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0xAA, 0x555, base, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0x55, 0x2AA, base, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL);
	if (cfi_qry_present(map, base, cfi))
		return 1;
	/* QRY not found */
	return 0;
}
Example #11
0
struct mtd_info *cfi_cmdset_0701(struct map_info *map, int primary)
{
	struct cfi_private *cfi = map->fldrv_priv;
	int ofs_factor = cfi->interleave * cfi->device_type;
	int i;
	__u8 major, minor;
	__u32 base = cfi->chips[0].start;

	if (cfi->cfi_mode==1){
		__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;

		cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
		cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
		cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL);
		
		major = cfi_read_query(map, base + (adr+3)*ofs_factor);
		minor = cfi_read_query(map, base + (adr+4)*ofs_factor);
		
		printk(" SST Query Table v%c.%c at 0x%4.4X\n",
		       major, minor, adr);
		cfi_send_gen_cmd(0xf0, 0x5555, base, map, cfi, cfi->device_type, NULL);
		
		cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
		cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
		cfi_send_gen_cmd(0x90, 0x5555, base, map, cfi, cfi->device_type, NULL);
		cfi->mfr = cfi_read_query(map, base);
		cfi->id = cfi_read_query(map, base + ofs_factor);

		cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
		cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
		cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL);
		
		switch (cfi->device_type) {
		case CFI_DEVICETYPE_X16:
			cfi->addr_unlock1 = 0x5555;
			cfi->addr_unlock2 = 0x2AAA;
			break;
		default:
			printk(KERN_NOTICE "Eep. Unknown cfi_cmdset_0701 device type %d\n", cfi->device_type);
			return NULL;
		}
	} /* CFI mode */

	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;
	}		
	
	map->fldrv = &cfi_sststd_chipdrv;
	MOD_INC_USE_COUNT;

	cfi_send_gen_cmd(0xf0, 0x5555, base, map, cfi, cfi->device_type, NULL);
	return cfi_sststd_setup(map);
}