LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Software > Linux - Kernel
User Name
Password
Linux - Kernel This forum is for all discussion relating to the Linux kernel.

Notices


Reply
  Search this Thread
Old 07-20-2010, 08:46 AM   #1
yuvarajragupathi
LQ Newbie
 
Registered: Jul 2010
Posts: 2

Rep: Reputation: 0
Thumbs up MTD flash lock and unlock


Hi all,

I am trying to lock my flash . My flash is spansion GL128p90ffiR2.

I added command set to lock and unlock in driver/mtd/chips/cfi_cmdset_0002.c.But lock and unlock not working . attached here my cfi_cmdset_0002.c file.

Code:

	if (!mtd) {
		printk(KERN_WARNING "Failed to allocate memory for MTD device\n");
		return NULL;
	}
	mtd->priv = map;
	mtd->type = MTD_NORFLASH;

	/* Fill in the default mtd operations */
	mtd->erase   = cfi_amdstd_erase_varsize;
	mtd->write   = cfi_amdstd_write_words;
	mtd->read    = cfi_amdstd_read;
	mtd->sync    = cfi_amdstd_sync;
        mtd->lock    = cfi_amdstd_lock; // yuvaraj defined
        mtd->unlock  = cfi_amdstd_unlock; // yuvaraj defined
	mtd->suspend = cfi_amdstd_suspend;
	mtd->resume  = cfi_amdstd_resume;
	mtd->flags   = MTD_CAP_NORFLASH;
	mtd->name    = map->name;
	mtd->writesize = 1;

	if (cfi->cfi_mode==CFI_MODE_CFI){
		unsigned char bootloc;
		/*
		 * 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_amdstd *extp;

		extp = (struct cfi_pri_amdstd*)cfi_read_pri(map, adr, sizeof(*extp), "Amd/Fujitsu");
		if (!extp) {
			kfree(mtd);
			return NULL;
		}

		if (extp->MajorVersion != '1' ||
		    (extp->MinorVersion < '0' || extp->MinorVersion > '4')) {
			printk(KERN_ERR "  Unknown Amd/Fujitsu Extended Query "
			       "version %c.%c.\n",  extp->MajorVersion,
			       extp->MinorVersion);
			kfree(extp);
			kfree(mtd);
			return NULL;
		}

		/* Install our own private info structure */
		cfi->cmdset_priv = extp;

		/* Apply cfi device specific fixups */
		cfi_fixup(mtd, cfi_fixup_table);

#ifdef DEBUG_CFI_FEATURES
		/* Tell the user about it in lots of lovely detail */
		cfi_tell_features(extp);
#endif

		bootloc = extp->TopBottom;
		if ((bootloc != 2) && (bootloc != 3)) {
			printk(KERN_WARNING "%s: CFI does not contain boot "
			       "bank location. Assuming top.\n", map->name);
			bootloc = 2;
		}

		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;
			}
		}
		/* Set the default CFI lock/unlock addresses */
		cfi->addr_unlock1 = 0x555;
		cfi->addr_unlock2 = 0x2aa;
		/* Modify the unlock address if we are in compatibility mode */
		if (	/* x16 in x8 mode */
			((cfi->device_type == CFI_DEVICETYPE_X8) &&
				(cfi->cfiq->InterfaceDesc == 2)) ||
			/* x32 in x16 mode */
			((cfi->device_type == CFI_DEVICETYPE_X16) &&
				(cfi->cfiq->InterfaceDesc == 4)))
		{
			cfi->addr_unlock1 = 0xaaa;
			cfi->addr_unlock2 = 0x555;
		}

	} /* CFI mode */
	else if (cfi->cfi_mode == CFI_MODE_JEDEC) {
		/* Apply jedec specific fixups */
		cfi_fixup(mtd, jedec_fixup_table);
	}
	/* Apply generic fixups */
	cfi_fixup(mtd, fixup_table);

	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;
		init_waitqueue_head(&(cfi->chips[i].wq));
	}

	map->fldrv = &cfi_amdstd_chipdrv;

	return cfi_amdstd_setup(mtd);
}
EXPORT_SYMBOL_GPL(cfi_cmdset_0002);

static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
{
	struct map_info *map = mtd->priv;
	struct cfi_private *cfi = map->fldrv_priv;
	unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
	unsigned long offset = 0;
	int i,j;

	printk(KERN_NOTICE "number of %s chips: %d\n",
	       (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips);
	/* Select the correct geometry setup */
	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_WARNING "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;
	}
#if 0
	// debug
	for (i=0; i<mtd->numeraseregions;i++){
		printk("%d: offset=0x%x,size=0x%x,blocks=%d\n",
		       i,mtd->eraseregions[i].offset,
		       mtd->eraseregions[i].erasesize,
		       mtd->eraseregions[i].numblocks);
	}
#endif

	/* FIXME: erase-suspend-program is broken.  See
	   http://lists.infradead.org/pipermail/linux-mtd/2003-December/009001.html */
	printk(KERN_NOTICE "cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.\n");

	__module_get(THIS_MODULE);
	return mtd;

 setup_err:
	if(mtd) {
		kfree(mtd->eraseregions);
		kfree(mtd);
	}
	kfree(cfi->cmdset_priv);
	kfree(cfi->cfiq);
	return NULL;
}



static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
				unsigned long adr)
{
	struct cfi_private *cfi = map->fldrv_priv;

	if (chip->state != FL_POINT && chip->state != FL_READY) {
		map_write(map, CMD(0xf0), adr);
		chip->state = FL_READY;
	}
	(void) map_read(map, adr);
	xip_iprefetch();
	local_irq_enable();
}

/*
 * When a delay is required for the flash operation to complete, the
 * xip_udelay() function is polling for both the given timeout and pending
 * (but still masked) hardware interrupts.  Whenever there is an interrupt
 * pending then the flash erase operation is suspended, array mode restored
 * and interrupts unmasked.  Task scheduling might also happen at that
 * point.  The CPU eventually returns from the interrupt or the call to
 * schedule() and the suspended flash operation is resumed for the remaining
 * of the delay period.
 *
 * Warning: this function _will_ fool interrupt latency tracing tools.
 */

static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
				unsigned long adr, int usec)
{
	struct cfi_private *cfi = map->fldrv_priv;
	struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
	map_word status, OK = CMD(0x80);
	unsigned long suspended, start = xip_currtime();
	flstate_t oldstate;

	do {
		cpu_relax();
		if (xip_irqpending() && extp &&
		    ((chip->state == FL_ERASING && (extp->EraseSuspend & 2))) &&
		    (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) {
			/*
			 * Let's suspend the erase operation when supported.
			 * Note that we currently don't try to suspend
			 * interleaved chips if there is already another
			 * operation suspended (imagine what happens
			 * when one chip was already done with the current
			 * operation while another chip suspended it, then
			 * we resume the whole thing at once).  Yes, it
			 * can happen!
			 */
			map_write(map, CMD(0xb0), adr);
			usec -= xip_elapsed_since(start);
			suspended = xip_currtime();
			do {
				if (xip_elapsed_since(suspended) > 100000) {
					/*
					 * The chip doesn't want to suspend
					 * after waiting for 100 msecs.
					 * This is a critical error but there
					 * is not much we can do here.
					 */
					return;
				}
				status = map_read(map, adr);
			} while (!map_word_andequal(map, status, OK, OK));

			/* Suspend succeeded */
			oldstate = chip->state;
			if (!map_word_bitsset(map, status, CMD(0x40)))
				break;
			chip->state = FL_XIP_WHILE_ERASING;
			chip->erase_suspended = 1;
			map_write(map, CMD(0xf0), adr);
			(void) map_read(map, adr);
			asm volatile (".rep 8; nop; .endr");
			local_irq_enable();
			spin_unlock(chip->mutex);
			asm volatile (".rep 8; nop; .endr");
			cond_resched();

			/*
			 * We're back.  However someone else might have
			 * decided to go write to the chip if we are in
			 * a suspended erase state.  If so let's wait
			 * until it's done.
			 */
			spin_lock(chip->mutex);
			while (chip->state != FL_XIP_WHILE_ERASING) {
				DECLARE_WAITQUEUE(wait, current);
				set_current_state(TASK_UNINTERRUPTIBLE);
				add_wait_queue(&chip->wq, &wait);
				spin_unlock(chip->mutex);
				schedule();
				remove_wait_queue(&chip->wq, &wait);
				spin_lock(chip->mutex);
			}
			/* Disallow XIP again */
			local_irq_disable();

			/* Resume the write or erase operation */
			map_write(map, CMD(0x30), adr);
			chip->state = oldstate;
			start = xip_currtime();
		} else if (usec >= 1000000/HZ) {
			/*
			 * Try to save on CPU power when waiting delay
			 * is at least a system timer tick period.
			 * No need to be extremely accurate here.
			 */
			xip_cpu_idle();
		}
		status = map_read(map, adr);
	} while (!map_word_andequal(map, status, OK, OK)
		 && xip_elapsed_since(start) < usec);
}

#define UDELAY(map, chip, adr, usec)  xip_udelay(map, chip, adr, usec)

/*
 * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
 * the flash is actively programming or erasing since we have to poll for
 * the operation to complete anyway.  We can't do that in a generic way with
 * a XIP setup so do it before the actual flash operation in this case
 * and stub it out from INVALIDATE_CACHE_UDELAY.
 */
#define XIP_INVAL_CACHED_RANGE(map, from, size)  \
	INVALIDATE_CACHED_RANGE(map, from, size)

#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec)  \
	UDELAY(map, chip, adr, usec)

/*
 * Extra notes:
 *
 * Activating this XIP support changes the way the code works a bit.  For
 * example the code to suspend the current process when concurrent access
 * happens is never executed because xip_udelay() will always return with the
 * same chip state as it was entered with.  This is why there is no care for
 * the presence of add_wait_queue() or schedule() calls from within a couple
 * xip_disable()'d  areas of code, like in do_erase_oneblock for example.
 * The queueing and scheduling are always happening within xip_udelay().
 *
 * Similarly, get_chip() and put_chip() just happen to always be executed
 * with chip->state set to FL_READY (or FL_XIP_WHILE_*) where flash state
 * is in array mode, therefore never executing many cases therein and not
 * causing any problem with XIP.
 */

#else

#define xip_disable(map, chip, adr)
#define xip_enable(map, chip, adr)
#define XIP_INVAL_CACHED_RANGE(x...)

#define UDELAY(map, chip, adr, usec)  \
do {  \
	spin_unlock(chip->mutex);  \
	cfi_udelay(usec);  \
	spin_lock(chip->mutex);  \
} while (0)

#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec)  \
do {  \
	spin_unlock(chip->mutex);  \
	INVALIDATE_CACHED_RANGE(map, adr, len);  \
	cfi_udelay(usec);  \
	spin_lock(chip->mutex);  \
} while (0)

#endif

static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
{
	unsigned long cmd_addr;
	struct cfi_private *cfi = map->fldrv_priv;
	int ret;

	adr += chip->start;

	/* Ensure cmd read/writes are aligned. */
	cmd_addr = adr & ~(map_bankwidth(map)-1);

	spin_lock(chip->mutex);
	ret = get_chip(map, chip, cmd_addr, FL_READY);
	if (ret) {
		spin_unlock(chip->mutex);
		return ret;
	}

	if (chip->state != FL_POINT && chip->state != FL_READY) {
		map_write(map, CMD(0xf0), cmd_addr);
		chip->state = FL_READY;
	}

	map_copy_from(map, buf, adr, len);

	put_chip(map, chip, cmd_addr);

	spin_unlock(chip->mutex);
	return 0;
}


static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
{
	struct map_info *map = mtd->priv;
	struct cfi_private *cfi = map->fldrv_priv;
	unsigned long ofs;
	int chipnum;
	int ret = 0;
  //printk(KERN_ERR "Yuvaraj # cfi_0002 read function \n");
	/* ofs: offset within the first chip that the first read should start */

	chipnum = (from >> cfi->chipshift);
	ofs = from - (chipnum <<  cfi->chipshift);


	*retlen = 0;

	while (len) {
		unsigned long thislen;

		if (chipnum >= cfi->numchips)
			break;

		if ((len + ofs -1) >> cfi->chipshift)
			thislen = (1<<cfi->chipshift) - ofs;
		else
			thislen = len;

		ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
		if (ret)
			break;

		*retlen += thislen;
		len -= thislen;
		buf += thislen;

		ofs = 0;
		chipnum++;
	}
	return ret;
}
//******************************************************************************
// Yuvaraj added
static int cfi_mta_lock(struct map_info *map,struct flchip *chip,unsigned long address,int length, void *thunk)
{
    int iReturn;
    struct cfi_private *cfi = map->fldrv_priv;
    address = address+chip->start;
    spin_lock(chip->mutex);
   //chip->state = FL_LOCKING;
    iReturn = get_chip(map,chip,address,FL_LOCKING);
    if(iReturn != 0)
    {
        spin_unlock(chip->mutex);
        printk(KERN_ERR "lock failed @ cfi 0002\n");
        return iReturn;
    }
      ENABLE_VPP(map);
      xip_disable(map,chip,address);
      printk(KERN_ERR "+++++++++++++++++ Flash address details ++++++++++++++++++++\n\n");

      printk(KERN_ERR "Address : 0x%x\n",cfi->addr_unlock1);
      printk(KERN_ERR "Address : 0x%x\n",cfi->addr_unlock2);
      printk(KERN_ERR "System starting address: 0x%x\n",chip->start);
      printk(KERN_ERR "Address(from user) : 0x%x\n",address);

      printk(KERN_ERR "++++++++++++++++++++++++++end+++++++++++++++++++++++++++++++\n\n");

  #if 1
       //enter into password protection mode
    cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x60, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        // set password
    cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x0001,0x00, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x0002, 0x01, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x0003, 0x02, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x0004, 0x03, chip->start, map, cfi, cfi->device_type, NULL);
       // Exit from the mode
    cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
  #endif
#if 0
    //enter into DYB protection mode
 cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
 cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
 cfi_send_gen_cmd(0xE0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
     // Program
 cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
 cfi_send_gen_cmd(0x01,address, chip->start, map, cfi, cfi->device_type, NULL);

    // Exit from the mode
 cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
 cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
#endif
    // enter into lock register
    cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x40, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
    //configure lock register for password protection mode
    cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x011, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
    // exit from lock register
    cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x00, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
   chip->state = FL_READY;
    put_chip(map,chip,address);
    spin_unlock(chip->mutex);
    printk(KERN_ERR "Yuvaraj # do_cfi_lock function \n");
    return 0;

}
//******************************************************************************
static int cfi_mta_unlock(struct map_info *map,struct flchip *chip,unsigned long address,int length, void *thunk)
{
    int iReturn;
    struct cfi_private *cfi = map->fldrv_priv;
    address = address+chip->start;
    spin_lock(chip->mutex);
//chip->state = FL_UNLOCKING;
    iReturn = get_chip(map,chip,address,FL_UNLOCKING);
    if(iReturn != 0)
    {
         spin_unlock(chip->mutex);
        printk(KERN_ERR "unlock failed @ cfi 0002\n");
        return iReturn;
    }
    ENABLE_VPP(map);
    xip_disable(map,chip,address);
#if 1
    //enter into password protection mode
    cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x60, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
      // remove password
    cfi_send_gen_cmd(0x25, 0x00, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x03, 0x00, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x0001,0x00, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x0002, 0x01, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x0003, 0x02, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x0004, 0x03, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x29, 0x00, chip->start, map, cfi, cfi->device_type, NULL);
     // Exit from the mode
    cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
    cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
#endif
#if 0
    //enter into DYB protection mode
 cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
 cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
 cfi_send_gen_cmd(0xE0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
     // Program
 cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
 cfi_send_gen_cmd(0x00,address, chip->start, map, cfi, cfi->device_type, NULL);

    // Exit from the mode
 cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
 cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
#endif
    chip->state = FL_READY;
put_chip(map,chip,address);
spin_unlock(chip->mutex);
printk(KERN_ERR "Yuvaraj # do_cfi_unlock function \n");
return 0;

}

//*******************************************************************************
static int cfi_amdstd_lock (struct mtd_info *mtd,loff_t ofs,size_t len)
{
   // printk(KERN_ERR "cfi # cfi_0002 mtd lock\n");
    return cfi_varsize_frob(mtd, cfi_mta_lock, ofs, len, (void *)0);
}
//********************************************************************************
static int cfi_amdstd_unlock (struct mtd_info *mtd,loff_t ofs,size_t len)
{
   // printk(KERN_ERR "cfi # cfi_0002 mtd unlock \n");
    return cfi_varsize_frob(mtd, cfi_mta_unlock, ofs, len, (void*)0);

}

//**********************************************************************************
static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
{
	DECLARE_WAITQUEUE(wait, current);
	unsigned long timeo = jiffies + HZ;
	struct cfi_private *cfi = map->fldrv_priv;

 retry:
	spin_lock(chip->mutex);

	if (chip->state != FL_READY){
#if 0
		printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state);
#endif
		set_current_state(TASK_UNINTERRUPTIBLE);
		add_wait_queue(&chip->wq, &wait);
		spin_unlock(chip->mutex);
		schedule();
		remove_wait_queue(&chip->wq, &wait);
#if 0
		if(signal_pending(current))
			return -EINTR;
#endif
		timeo = jiffies + HZ;

		goto retry;
	}

	adr += chip->start;

	chip->state = FL_READY;

	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);

	map_copy_from(map, buf, adr, len);

	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);

	wake_up(&chip->wq);
	spin_unlock(chip->mutex);

	return 0;
}

static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
{
	struct map_info *map = mtd->priv;
	struct cfi_private *cfi = map->fldrv_priv;
	unsigned long ofs;
	int chipnum;
	int ret = 0;


	/* ofs: offset within the first chip that the first read should start */

	/* 8 secsi bytes per chip */
	chipnum=from>>3;
	ofs=from & 7;


	*retlen = 0;

	while (len) {
		unsigned long thislen;

		if (chipnum >= cfi->numchips)
			break;

		if ((len + ofs -1) >> 3)
			thislen = (1<<3) - ofs;
		else
			thislen = len;

		ret = do_read_secsi_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
		if (ret)
			break;

		*retlen += thislen;
		len -= thislen;
		buf += thislen;

		ofs = 0;
		chipnum++;
	}
	return ret;
}


static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
{
	struct cfi_private *cfi = map->fldrv_priv;
	unsigned long timeo = jiffies + HZ;
	/*
	 * We use a 1ms + 1 jiffies generic timeout for writes (most devices
	 * have a max write time of a few hundreds usec). However, we should
	 * use the maximum timeout value given by the chip at probe time
	 * instead.  Unfortunately, struct flchip does have a field for
	 * maximum timeout, only for typical which can be far too short
	 * depending of the conditions.	 The ' + 1' is to avoid having a
	 * timeout of 0 jiffies if HZ is smaller than 1000.
	 */
	unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
	int ret = 0;
	map_word oldd;
	int retry_cnt = 0;
//printk(KERN_ERR "yuvaraj do_write_one word \n");
	adr += chip->start;

	spin_lock(chip->mutex);
	ret = get_chip(map, chip, adr, FL_WRITING);
	if (ret) {
		spin_unlock(chip->mutex);
		return ret;
	}

	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
	       __func__, adr, datum.x[0] );

	/*
	 * Check for a NOP for the case when the datum to write is already
	 * present - it saves time and works around buggy chips that corrupt
	 * data at other locations when 0xff is written to a location that
	 * already contains 0xff.
	 */
	oldd = map_read(map, adr);
	if (map_word_equal(map, oldd, datum)) {
		DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): NOP\n",
		       __func__);
		goto op_done;
	}

	XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
	ENABLE_VPP(map);
	xip_disable(map, chip, adr);
 retry:
	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
	cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
	map_write(map, datum, adr);
	chip->state = FL_WRITING;

	INVALIDATE_CACHE_UDELAY(map, chip,
				adr, map_bankwidth(map),
				chip->word_write_time);

	/* See comment above for timeout value. */
	timeo = jiffies + uWriteTimeout;
	for (;;) {
		if (chip->state != FL_WRITING) {
			/* Someone's suspended the write. Sleep */
			DECLARE_WAITQUEUE(wait, current);

			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 / 2); /* FIXME */
			spin_lock(chip->mutex);
			continue;
		}

		if (time_after(jiffies, timeo) && !chip_ready(map, adr)){
			xip_enable(map, chip, adr);
			printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
			xip_disable(map, chip, adr);
			break;
		}

		if (chip_ready(map, adr))
			break;

		/* Latency issues. Drop the lock, wait a while and retry */
		UDELAY(map, chip, adr, 1);
	}
	/* Did we succeed? */
	if (!chip_good(map, adr, datum)) {
		/* reset on all failures. */
		map_write( map, CMD(0xF0), chip->start );
		/* FIXME - should have reset delay before continuing */

		if (++retry_cnt <= MAX_WORD_RETRIES)
			goto retry;

		ret = -EIO;
	}
	xip_enable(map, chip, adr);
 op_done:
	chip->state = FL_READY;
	put_chip(map, chip, adr);
	spin_unlock(chip->mutex);

	return ret;
}
Please help me

Thanks

Yuvi
 
Old 12-18-2011, 04:44 PM   #2
AustinMarton
Member
 
Registered: May 2007
Location: New Zealand
Distribution: Ubuntu
Posts: 88

Rep: Reputation: 16
Might not be relevant anymore but I added lock/unlock support for the M25P64 flash and had to set "write enable" before I could modify the status register that contained the protection bits.
 
Old 11-15-2012, 11:26 PM   #3
rinky05
LQ Newbie
 
Registered: Aug 2012
Posts: 10

Rep: Reputation: Disabled
Please provide me with the solution for the above problem because I am also doing the sane thing with a difference that I am using persistent protection mode . Can somebody tell me the necessary changes to be done .

Urgent...please help !!
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
user lock/unlock by bad tries LinuxLover Solaris / OpenSolaris 2 10-26-2010 03:45 PM
flash base and flash size in MTD driver ashok449 Linux - Kernel 1 05-21-2010 06:58 PM
Special flash memory partition - MTD theChacalIsDead Linux - Embedded & Single-board computer 1 05-24-2009 04:48 AM
lock and unlock munna_dude Programming 1 05-18-2007 06:03 AM
About Lock And Unlock George2 Programming 8 08-23-2005 11:30 PM

LinuxQuestions.org > Forums > Linux Forums > Linux - Software > Linux - Kernel

All times are GMT -5. The time now is 07:52 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration