11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Common Flash Interface support:
31da177e4SLinus Torvalds  *   AMD & Fujitsu Standard Vendor Command Set (ID 0x0002)
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp>
61da177e4SLinus Torvalds  * Copyright (C) 2004 Arcom Control Systems Ltd <linux@arcom.com>
702b15e34STodd Poynor  * Copyright (C) 2005 MontaVista Software Inc. <source@mvista.com>
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  * 2_by_8 routines added by Simon Munton
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * 4_by_16 work by Carolyn J. Smith
121da177e4SLinus Torvalds  *
1302b15e34STodd Poynor  * XIP support hooks by Vitaly Wool (based on code for Intel flash
1402b15e34STodd Poynor  * by Nicolas Pitre)
1502b15e34STodd Poynor  *
1687e92c06SChristopher Moore  * 25/09/2008 Christopher Moore: TopBottom fixup for many Macronix with CFI V1.0
1787e92c06SChristopher Moore  *
181da177e4SLinus Torvalds  * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
191da177e4SLinus Torvalds  *
201da177e4SLinus Torvalds  * This code is GPL
211da177e4SLinus Torvalds  */
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds #include <linux/module.h>
241da177e4SLinus Torvalds #include <linux/types.h>
251da177e4SLinus Torvalds #include <linux/kernel.h>
261da177e4SLinus Torvalds #include <linux/sched.h>
271da177e4SLinus Torvalds #include <linux/init.h>
281da177e4SLinus Torvalds #include <asm/io.h>
291da177e4SLinus Torvalds #include <asm/byteorder.h>
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds #include <linux/errno.h>
321da177e4SLinus Torvalds #include <linux/slab.h>
331da177e4SLinus Torvalds #include <linux/delay.h>
341da177e4SLinus Torvalds #include <linux/interrupt.h>
35eafe1311SKevin Cernekee #include <linux/reboot.h>
361da177e4SLinus Torvalds #include <linux/mtd/map.h>
371da177e4SLinus Torvalds #include <linux/mtd/mtd.h>
381da177e4SLinus Torvalds #include <linux/mtd/cfi.h>
3902b15e34STodd Poynor #include <linux/mtd/xip.h>
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds #define AMD_BOOTLOC_BUG
421da177e4SLinus Torvalds #define FORCE_WORD_WRITE 0
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds #define MAX_WORD_RETRIES 3
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds #define SST49LF004B	        0x0060
4789072ef9SRyan Jackson #define SST49LF040B	        0x0050
48fb4a90bfSEric W. Biedermann #define SST49LF008A		0x005a
490165508cSHaavard Skinnemoen #define AT49BV6416		0x00d6
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
521da177e4SLinus Torvalds static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
531da177e4SLinus Torvalds static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
541da177e4SLinus Torvalds static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *);
551da177e4SLinus Torvalds static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *);
561da177e4SLinus Torvalds static void cfi_amdstd_sync (struct mtd_info *);
571da177e4SLinus Torvalds static int cfi_amdstd_suspend (struct mtd_info *);
581da177e4SLinus Torvalds static void cfi_amdstd_resume (struct mtd_info *);
59eafe1311SKevin Cernekee static int cfi_amdstd_reboot(struct notifier_block *, unsigned long, void *);
601da177e4SLinus Torvalds static int cfi_amdstd_secsi_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
611da177e4SLinus Torvalds 
6230ec5a2cSIra W. Snyder static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
6330ec5a2cSIra W. Snyder 				  size_t *retlen, const u_char *buf);
6430ec5a2cSIra W. Snyder 
651da177e4SLinus Torvalds static void cfi_amdstd_destroy(struct mtd_info *);
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds struct mtd_info *cfi_cmdset_0002(struct map_info *, int);
681da177e4SLinus Torvalds static struct mtd_info *cfi_amdstd_setup (struct mtd_info *);
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
711da177e4SLinus Torvalds static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr);
721da177e4SLinus Torvalds #include "fwh_lock.h"
731da177e4SLinus Torvalds 
7469423d99SAdrian Hunter static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
7569423d99SAdrian Hunter static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
760165508cSHaavard Skinnemoen 
771da177e4SLinus Torvalds static struct mtd_chip_driver cfi_amdstd_chipdrv = {
781da177e4SLinus Torvalds 	.probe		= NULL, /* Not usable directly */
791da177e4SLinus Torvalds 	.destroy	= cfi_amdstd_destroy,
801da177e4SLinus Torvalds 	.name		= "cfi_cmdset_0002",
811da177e4SLinus Torvalds 	.module		= THIS_MODULE
821da177e4SLinus Torvalds };
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds /* #define DEBUG_CFI_FEATURES */
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds 
881da177e4SLinus Torvalds #ifdef DEBUG_CFI_FEATURES
891da177e4SLinus Torvalds static void cfi_tell_features(struct cfi_pri_amdstd *extp)
901da177e4SLinus Torvalds {
911da177e4SLinus Torvalds 	const char* erase_suspend[3] = {
921da177e4SLinus Torvalds 		"Not supported", "Read only", "Read/write"
931da177e4SLinus Torvalds 	};
941da177e4SLinus Torvalds 	const char* top_bottom[6] = {
951da177e4SLinus Torvalds 		"No WP", "8x8KiB sectors at top & bottom, no WP",
961da177e4SLinus Torvalds 		"Bottom boot", "Top boot",
971da177e4SLinus Torvalds 		"Uniform, Bottom WP", "Uniform, Top WP"
981da177e4SLinus Torvalds 	};
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds 	printk("  Silicon revision: %d\n", extp->SiliconRevision >> 1);
1011da177e4SLinus Torvalds 	printk("  Address sensitive unlock: %s\n",
1021da177e4SLinus Torvalds 	       (extp->SiliconRevision & 1) ? "Not required" : "Required");
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds 	if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend))
1051da177e4SLinus Torvalds 		printk("  Erase Suspend: %s\n", erase_suspend[extp->EraseSuspend]);
1061da177e4SLinus Torvalds 	else
1071da177e4SLinus Torvalds 		printk("  Erase Suspend: Unknown value %d\n", extp->EraseSuspend);
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds 	if (extp->BlkProt == 0)
1101da177e4SLinus Torvalds 		printk("  Block protection: Not supported\n");
1111da177e4SLinus Torvalds 	else
1121da177e4SLinus Torvalds 		printk("  Block protection: %d sectors per group\n", extp->BlkProt);
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds 	printk("  Temporary block unprotect: %s\n",
1161da177e4SLinus Torvalds 	       extp->TmpBlkUnprotect ? "Supported" : "Not supported");
1171da177e4SLinus Torvalds 	printk("  Block protect/unprotect scheme: %d\n", extp->BlkProtUnprot);
1181da177e4SLinus Torvalds 	printk("  Number of simultaneous operations: %d\n", extp->SimultaneousOps);
1191da177e4SLinus Torvalds 	printk("  Burst mode: %s\n",
1201da177e4SLinus Torvalds 	       extp->BurstMode ? "Supported" : "Not supported");
1211da177e4SLinus Torvalds 	if (extp->PageMode == 0)
1221da177e4SLinus Torvalds 		printk("  Page mode: Not supported\n");
1231da177e4SLinus Torvalds 	else
1241da177e4SLinus Torvalds 		printk("  Page mode: %d word page\n", extp->PageMode << 2);
1251da177e4SLinus Torvalds 
1261da177e4SLinus Torvalds 	printk("  Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n",
1271da177e4SLinus Torvalds 	       extp->VppMin >> 4, extp->VppMin & 0xf);
1281da177e4SLinus Torvalds 	printk("  Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n",
1291da177e4SLinus Torvalds 	       extp->VppMax >> 4, extp->VppMax & 0xf);
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds 	if (extp->TopBottom < ARRAY_SIZE(top_bottom))
1321da177e4SLinus Torvalds 		printk("  Top/Bottom Boot Block: %s\n", top_bottom[extp->TopBottom]);
1331da177e4SLinus Torvalds 	else
1341da177e4SLinus Torvalds 		printk("  Top/Bottom Boot Block: Unknown value %d\n", extp->TopBottom);
1351da177e4SLinus Torvalds }
1361da177e4SLinus Torvalds #endif
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds #ifdef AMD_BOOTLOC_BUG
1391da177e4SLinus Torvalds /* Wheee. Bring me the head of someone at AMD. */
140cc318222SGuillaume LECERF static void fixup_amd_bootblock(struct mtd_info *mtd)
1411da177e4SLinus Torvalds {
1421da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
1431da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
1441da177e4SLinus Torvalds 	struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
1451da177e4SLinus Torvalds 	__u8 major = extp->MajorVersion;
1461da177e4SLinus Torvalds 	__u8 minor = extp->MinorVersion;
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds 	if (((major << 8) | minor) < 0x3131) {
1491da177e4SLinus Torvalds 		/* CFI version 1.0 => don't trust bootloc */
15087e92c06SChristopher Moore 
151289c0522SBrian Norris 		pr_debug("%s: JEDEC Vendor ID is 0x%02X Device ID is 0x%02X\n",
15287e92c06SChristopher Moore 			map->name, cfi->mfr, cfi->id);
15387e92c06SChristopher Moore 
15487e92c06SChristopher Moore 		/* AFAICS all 29LV400 with a bottom boot block have a device ID
15587e92c06SChristopher Moore 		 * of 0x22BA in 16-bit mode and 0xBA in 8-bit mode.
15687e92c06SChristopher Moore 		 * These were badly detected as they have the 0x80 bit set
15787e92c06SChristopher Moore 		 * so treat them as a special case.
15887e92c06SChristopher Moore 		 */
15987e92c06SChristopher Moore 		if (((cfi->id == 0xBA) || (cfi->id == 0x22BA)) &&
16087e92c06SChristopher Moore 
16187e92c06SChristopher Moore 			/* Macronix added CFI to their 2nd generation
16287e92c06SChristopher Moore 			 * MX29LV400C B/T but AFAICS no other 29LV400 (AMD,
16387e92c06SChristopher Moore 			 * Fujitsu, Spansion, EON, ESI and older Macronix)
16487e92c06SChristopher Moore 			 * has CFI.
16587e92c06SChristopher Moore 			 *
16687e92c06SChristopher Moore 			 * Therefore also check the manufacturer.
16787e92c06SChristopher Moore 			 * This reduces the risk of false detection due to
16887e92c06SChristopher Moore 			 * the 8-bit device ID.
16987e92c06SChristopher Moore 			 */
170f3e69c65SGuillaume LECERF 			(cfi->mfr == CFI_MFR_MACRONIX)) {
171289c0522SBrian Norris 			pr_debug("%s: Macronix MX29LV400C with bottom boot block"
17287e92c06SChristopher Moore 				" detected\n", map->name);
17387e92c06SChristopher Moore 			extp->TopBottom = 2;	/* bottom boot */
17487e92c06SChristopher Moore 		} else
1751da177e4SLinus Torvalds 		if (cfi->id & 0x80) {
1761da177e4SLinus Torvalds 			printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id);
1771da177e4SLinus Torvalds 			extp->TopBottom = 3;	/* top boot */
1781da177e4SLinus Torvalds 		} else {
1791da177e4SLinus Torvalds 			extp->TopBottom = 2;	/* bottom boot */
1801da177e4SLinus Torvalds 		}
18187e92c06SChristopher Moore 
182289c0522SBrian Norris 		pr_debug("%s: AMD CFI PRI V%c.%c has no boot block field;"
18387e92c06SChristopher Moore 			" deduced %s from Device ID\n", map->name, major, minor,
18487e92c06SChristopher Moore 			extp->TopBottom == 2 ? "bottom" : "top");
1851da177e4SLinus Torvalds 	}
1861da177e4SLinus Torvalds }
1871da177e4SLinus Torvalds #endif
1881da177e4SLinus Torvalds 
189cc318222SGuillaume LECERF static void fixup_use_write_buffers(struct mtd_info *mtd)
1901da177e4SLinus Torvalds {
1911da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
1921da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
1931da177e4SLinus Torvalds 	if (cfi->cfiq->BufWriteTimeoutTyp) {
194289c0522SBrian Norris 		pr_debug("Using buffer write method\n" );
1951da177e4SLinus Torvalds 		mtd->write = cfi_amdstd_write_buffers;
1961da177e4SLinus Torvalds 	}
1971da177e4SLinus Torvalds }
1981da177e4SLinus Torvalds 
1995b0c5c2cSHaavard Skinnemoen /* Atmel chips don't use the same PRI format as AMD chips */
200cc318222SGuillaume LECERF static void fixup_convert_atmel_pri(struct mtd_info *mtd)
2015b0c5c2cSHaavard Skinnemoen {
2025b0c5c2cSHaavard Skinnemoen 	struct map_info *map = mtd->priv;
2035b0c5c2cSHaavard Skinnemoen 	struct cfi_private *cfi = map->fldrv_priv;
2045b0c5c2cSHaavard Skinnemoen 	struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
2055b0c5c2cSHaavard Skinnemoen 	struct cfi_pri_atmel atmel_pri;
2065b0c5c2cSHaavard Skinnemoen 
2075b0c5c2cSHaavard Skinnemoen 	memcpy(&atmel_pri, extp, sizeof(atmel_pri));
208de591dacSHåvard Skinnemoen 	memset((char *)extp + 5, 0, sizeof(*extp) - 5);
2095b0c5c2cSHaavard Skinnemoen 
2105b0c5c2cSHaavard Skinnemoen 	if (atmel_pri.Features & 0x02)
2115b0c5c2cSHaavard Skinnemoen 		extp->EraseSuspend = 2;
2125b0c5c2cSHaavard Skinnemoen 
213be8f78b8SHaavard Skinnemoen 	/* Some chips got it backwards... */
214be8f78b8SHaavard Skinnemoen 	if (cfi->id == AT49BV6416) {
215be8f78b8SHaavard Skinnemoen 		if (atmel_pri.BottomBoot)
216be8f78b8SHaavard Skinnemoen 			extp->TopBottom = 3;
217be8f78b8SHaavard Skinnemoen 		else
218be8f78b8SHaavard Skinnemoen 			extp->TopBottom = 2;
219be8f78b8SHaavard Skinnemoen 	} else {
2205b0c5c2cSHaavard Skinnemoen 		if (atmel_pri.BottomBoot)
2215b0c5c2cSHaavard Skinnemoen 			extp->TopBottom = 2;
2225b0c5c2cSHaavard Skinnemoen 		else
2235b0c5c2cSHaavard Skinnemoen 			extp->TopBottom = 3;
224be8f78b8SHaavard Skinnemoen 	}
225d10a39d1SHans-Christian Egtvedt 
226d10a39d1SHans-Christian Egtvedt 	/* burst write mode not supported */
227d10a39d1SHans-Christian Egtvedt 	cfi->cfiq->BufWriteTimeoutTyp = 0;
228d10a39d1SHans-Christian Egtvedt 	cfi->cfiq->BufWriteTimeoutMax = 0;
2295b0c5c2cSHaavard Skinnemoen }
2305b0c5c2cSHaavard Skinnemoen 
231cc318222SGuillaume LECERF static void fixup_use_secsi(struct mtd_info *mtd)
2321da177e4SLinus Torvalds {
2331da177e4SLinus Torvalds 	/* Setup for chips with a secsi area */
2341da177e4SLinus Torvalds 	mtd->read_user_prot_reg = cfi_amdstd_secsi_read;
2351da177e4SLinus Torvalds 	mtd->read_fact_prot_reg = cfi_amdstd_secsi_read;
2361da177e4SLinus Torvalds }
2371da177e4SLinus Torvalds 
238cc318222SGuillaume LECERF static void fixup_use_erase_chip(struct mtd_info *mtd)
2391da177e4SLinus Torvalds {
2401da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
2411da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
2421da177e4SLinus Torvalds 	if ((cfi->cfiq->NumEraseRegions == 1) &&
2431da177e4SLinus Torvalds 		((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) {
2441da177e4SLinus Torvalds 		mtd->erase = cfi_amdstd_erase_chip;
2451da177e4SLinus Torvalds 	}
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds }
2481da177e4SLinus Torvalds 
2490165508cSHaavard Skinnemoen /*
2500165508cSHaavard Skinnemoen  * Some Atmel chips (e.g. the AT49BV6416) power-up with all sectors
2510165508cSHaavard Skinnemoen  * locked by default.
2520165508cSHaavard Skinnemoen  */
253cc318222SGuillaume LECERF static void fixup_use_atmel_lock(struct mtd_info *mtd)
2540165508cSHaavard Skinnemoen {
2550165508cSHaavard Skinnemoen 	mtd->lock = cfi_atmel_lock;
2560165508cSHaavard Skinnemoen 	mtd->unlock = cfi_atmel_unlock;
257e619a75fSJustin Treon 	mtd->flags |= MTD_POWERUP_LOCK;
2580165508cSHaavard Skinnemoen }
2590165508cSHaavard Skinnemoen 
26083dcd3bbSGuillaume LECERF static void fixup_old_sst_eraseregion(struct mtd_info *mtd)
26183dcd3bbSGuillaume LECERF {
26283dcd3bbSGuillaume LECERF 	struct map_info *map = mtd->priv;
26383dcd3bbSGuillaume LECERF 	struct cfi_private *cfi = map->fldrv_priv;
26483dcd3bbSGuillaume LECERF 
26583dcd3bbSGuillaume LECERF 	/*
26625985edcSLucas De Marchi 	 * These flashes report two separate eraseblock regions based on the
26783dcd3bbSGuillaume LECERF 	 * sector_erase-size and block_erase-size, although they both operate on the
26883dcd3bbSGuillaume LECERF 	 * same memory. This is not allowed according to CFI, so we just pick the
26983dcd3bbSGuillaume LECERF 	 * sector_erase-size.
27083dcd3bbSGuillaume LECERF 	 */
27183dcd3bbSGuillaume LECERF 	cfi->cfiq->NumEraseRegions = 1;
27283dcd3bbSGuillaume LECERF }
27383dcd3bbSGuillaume LECERF 
274cc318222SGuillaume LECERF static void fixup_sst39vf(struct mtd_info *mtd)
27583dcd3bbSGuillaume LECERF {
27683dcd3bbSGuillaume LECERF 	struct map_info *map = mtd->priv;
27783dcd3bbSGuillaume LECERF 	struct cfi_private *cfi = map->fldrv_priv;
27883dcd3bbSGuillaume LECERF 
27983dcd3bbSGuillaume LECERF 	fixup_old_sst_eraseregion(mtd);
28083dcd3bbSGuillaume LECERF 
28183dcd3bbSGuillaume LECERF 	cfi->addr_unlock1 = 0x5555;
28283dcd3bbSGuillaume LECERF 	cfi->addr_unlock2 = 0x2AAA;
28383dcd3bbSGuillaume LECERF }
28483dcd3bbSGuillaume LECERF 
285cc318222SGuillaume LECERF static void fixup_sst39vf_rev_b(struct mtd_info *mtd)
2865a0563f0SGuillaume LECERF {
2875a0563f0SGuillaume LECERF 	struct map_info *map = mtd->priv;
2885a0563f0SGuillaume LECERF 	struct cfi_private *cfi = map->fldrv_priv;
2895a0563f0SGuillaume LECERF 
2905a0563f0SGuillaume LECERF 	fixup_old_sst_eraseregion(mtd);
2915a0563f0SGuillaume LECERF 
2925a0563f0SGuillaume LECERF 	cfi->addr_unlock1 = 0x555;
2935a0563f0SGuillaume LECERF 	cfi->addr_unlock2 = 0x2AA;
29408968041SGuillaume LECERF 
29508968041SGuillaume LECERF 	cfi->sector_erase_cmd = CMD(0x50);
2965a0563f0SGuillaume LECERF }
2975a0563f0SGuillaume LECERF 
298cc318222SGuillaume LECERF static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd)
2999fc05fcaSGuillaume LECERF {
3009fc05fcaSGuillaume LECERF 	struct map_info *map = mtd->priv;
3019fc05fcaSGuillaume LECERF 	struct cfi_private *cfi = map->fldrv_priv;
3029fc05fcaSGuillaume LECERF 
303cc318222SGuillaume LECERF 	fixup_sst39vf_rev_b(mtd);
3049fc05fcaSGuillaume LECERF 
3059fc05fcaSGuillaume LECERF 	/*
3069fc05fcaSGuillaume LECERF 	 * CFI reports 1024 sectors (0x03ff+1) of 64KBytes (0x0100*256) where
3079fc05fcaSGuillaume LECERF 	 * it should report a size of 8KBytes (0x0020*256).
3089fc05fcaSGuillaume LECERF 	 */
3099fc05fcaSGuillaume LECERF 	cfi->cfiq->EraseRegionInfo[0] = 0x002003ff;
3109fc05fcaSGuillaume LECERF 	pr_warning("%s: Bad 38VF640x CFI data; adjusting sector size from 64 to 8KiB\n", mtd->name);
3119fc05fcaSGuillaume LECERF }
3129fc05fcaSGuillaume LECERF 
313cc318222SGuillaume LECERF static void fixup_s29gl064n_sectors(struct mtd_info *mtd)
31470b07255STrent Piepho {
31570b07255STrent Piepho 	struct map_info *map = mtd->priv;
31670b07255STrent Piepho 	struct cfi_private *cfi = map->fldrv_priv;
31770b07255STrent Piepho 
31870b07255STrent Piepho 	if ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0x003f) {
31970b07255STrent Piepho 		cfi->cfiq->EraseRegionInfo[0] |= 0x0040;
32070b07255STrent Piepho 		pr_warning("%s: Bad S29GL064N CFI data, adjust from 64 to 128 sectors\n", mtd->name);
32170b07255STrent Piepho 	}
32270b07255STrent Piepho }
32370b07255STrent Piepho 
324cc318222SGuillaume LECERF static void fixup_s29gl032n_sectors(struct mtd_info *mtd)
32570b07255STrent Piepho {
32670b07255STrent Piepho 	struct map_info *map = mtd->priv;
32770b07255STrent Piepho 	struct cfi_private *cfi = map->fldrv_priv;
32870b07255STrent Piepho 
32970b07255STrent Piepho 	if ((cfi->cfiq->EraseRegionInfo[1] & 0xffff) == 0x007e) {
33070b07255STrent Piepho 		cfi->cfiq->EraseRegionInfo[1] &= ~0x0040;
33170b07255STrent Piepho 		pr_warning("%s: Bad S29GL032N CFI data, adjust from 127 to 63 sectors\n", mtd->name);
33270b07255STrent Piepho 	}
33370b07255STrent Piepho }
33470b07255STrent Piepho 
33583dcd3bbSGuillaume LECERF /* Used to fix CFI-Tables of chips without Extended Query Tables */
33683dcd3bbSGuillaume LECERF static struct cfi_fixup cfi_nopri_fixup_table[] = {
337cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x234a, fixup_sst39vf }, /* SST39VF1602 */
338cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x234b, fixup_sst39vf }, /* SST39VF1601 */
339cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x235a, fixup_sst39vf }, /* SST39VF3202 */
340cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x235b, fixup_sst39vf }, /* SST39VF3201 */
341cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x235c, fixup_sst39vf_rev_b }, /* SST39VF3202B */
342cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x235d, fixup_sst39vf_rev_b }, /* SST39VF3201B */
343cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x236c, fixup_sst39vf_rev_b }, /* SST39VF6402B */
344cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x236d, fixup_sst39vf_rev_b }, /* SST39VF6401B */
345cc318222SGuillaume LECERF 	{ 0, 0, NULL }
34683dcd3bbSGuillaume LECERF };
34783dcd3bbSGuillaume LECERF 
3481da177e4SLinus Torvalds static struct cfi_fixup cfi_fixup_table[] = {
349cc318222SGuillaume LECERF 	{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri },
3501da177e4SLinus Torvalds #ifdef AMD_BOOTLOC_BUG
351cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock },
3521065cda8SSteffen Sledz 	{ CFI_MFR_AMIC, CFI_ID_ANY, fixup_amd_bootblock },
353cc318222SGuillaume LECERF 	{ CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock },
3541da177e4SLinus Torvalds #endif
355cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x0050, fixup_use_secsi },
356cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x0053, fixup_use_secsi },
357cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x0055, fixup_use_secsi },
358cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x0056, fixup_use_secsi },
359cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x005C, fixup_use_secsi },
360cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x005F, fixup_use_secsi },
361cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors },
362cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors },
363cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors },
364cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors },
365cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x536a, fixup_sst38vf640x_sectorsize }, /* SST38VF6402 */
366cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x536b, fixup_sst38vf640x_sectorsize }, /* SST38VF6401 */
367cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x536c, fixup_sst38vf640x_sectorsize }, /* SST38VF6404 */
368cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x536d, fixup_sst38vf640x_sectorsize }, /* SST38VF6403 */
3691da177e4SLinus Torvalds #if !FORCE_WORD_WRITE
370cc318222SGuillaume LECERF 	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers },
3711da177e4SLinus Torvalds #endif
372cc318222SGuillaume LECERF 	{ 0, 0, NULL }
3731da177e4SLinus Torvalds };
3741da177e4SLinus Torvalds static struct cfi_fixup jedec_fixup_table[] = {
375cc318222SGuillaume LECERF 	{ CFI_MFR_SST, SST49LF004B, fixup_use_fwh_lock },
376cc318222SGuillaume LECERF 	{ CFI_MFR_SST, SST49LF040B, fixup_use_fwh_lock },
377cc318222SGuillaume LECERF 	{ CFI_MFR_SST, SST49LF008A, fixup_use_fwh_lock },
378cc318222SGuillaume LECERF 	{ 0, 0, NULL }
3791da177e4SLinus Torvalds };
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds static struct cfi_fixup fixup_table[] = {
3821da177e4SLinus Torvalds 	/* The CFI vendor ids and the JEDEC vendor IDs appear
3831da177e4SLinus Torvalds 	 * to be common.  It is like the devices id's are as
3841da177e4SLinus Torvalds 	 * well.  This table is to pick all cases where
3851da177e4SLinus Torvalds 	 * we know that is the case.
3861da177e4SLinus Torvalds 	 */
387cc318222SGuillaume LECERF 	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip },
388cc318222SGuillaume LECERF 	{ CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock },
389cc318222SGuillaume LECERF 	{ 0, 0, NULL }
3901da177e4SLinus Torvalds };
3911da177e4SLinus Torvalds 
3921da177e4SLinus Torvalds 
393fefae48bSWolfgang Grandegger static void cfi_fixup_major_minor(struct cfi_private *cfi,
394fefae48bSWolfgang Grandegger 				  struct cfi_pri_amdstd *extp)
395fefae48bSWolfgang Grandegger {
396e6372763SGuillaume LECERF 	if (cfi->mfr == CFI_MFR_SAMSUNG) {
397e8953b73SGuillaume LECERF 		if ((extp->MajorVersion == '0' && extp->MinorVersion == '0') ||
398e8953b73SGuillaume LECERF 		    (extp->MajorVersion == '3' && extp->MinorVersion == '3')) {
399e6372763SGuillaume LECERF 			/*
400e6372763SGuillaume LECERF 			 * Samsung K8P2815UQB and K8D6x16UxM chips
401e6372763SGuillaume LECERF 			 * report major=0 / minor=0.
402e8953b73SGuillaume LECERF 			 * K8D3x16UxC chips report major=3 / minor=3.
403e6372763SGuillaume LECERF 			 */
404e6372763SGuillaume LECERF 			printk(KERN_NOTICE "  Fixing Samsung's Amd/Fujitsu"
405e6372763SGuillaume LECERF 			       " Extended Query version to 1.%c\n",
406e6372763SGuillaume LECERF 			       extp->MinorVersion);
407fefae48bSWolfgang Grandegger 			extp->MajorVersion = '1';
408e6372763SGuillaume LECERF 		}
409e6372763SGuillaume LECERF 	}
410e6372763SGuillaume LECERF 
4119fc05fcaSGuillaume LECERF 	/*
4129fc05fcaSGuillaume LECERF 	 * SST 38VF640x chips report major=0xFF / minor=0xFF.
4139fc05fcaSGuillaume LECERF 	 */
4149fc05fcaSGuillaume LECERF 	if (cfi->mfr == CFI_MFR_SST && (cfi->id >> 4) == 0x0536) {
4159fc05fcaSGuillaume LECERF 		extp->MajorVersion = '1';
4169fc05fcaSGuillaume LECERF 		extp->MinorVersion = '0';
4179fc05fcaSGuillaume LECERF 	}
418fefae48bSWolfgang Grandegger }
419fefae48bSWolfgang Grandegger 
4201da177e4SLinus Torvalds struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
4211da177e4SLinus Torvalds {
4221da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
4231da177e4SLinus Torvalds 	struct mtd_info *mtd;
4241da177e4SLinus Torvalds 	int i;
4251da177e4SLinus Torvalds 
42695b93a0cSBurman Yan 	mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
4271da177e4SLinus Torvalds 	if (!mtd) {
4281da177e4SLinus Torvalds 		printk(KERN_WARNING "Failed to allocate memory for MTD device\n");
4291da177e4SLinus Torvalds 		return NULL;
4301da177e4SLinus Torvalds 	}
4311da177e4SLinus Torvalds 	mtd->priv = map;
4321da177e4SLinus Torvalds 	mtd->type = MTD_NORFLASH;
4331da177e4SLinus Torvalds 
4341da177e4SLinus Torvalds 	/* Fill in the default mtd operations */
4351da177e4SLinus Torvalds 	mtd->erase   = cfi_amdstd_erase_varsize;
4361da177e4SLinus Torvalds 	mtd->write   = cfi_amdstd_write_words;
4371da177e4SLinus Torvalds 	mtd->read    = cfi_amdstd_read;
4381da177e4SLinus Torvalds 	mtd->sync    = cfi_amdstd_sync;
4391da177e4SLinus Torvalds 	mtd->suspend = cfi_amdstd_suspend;
4401da177e4SLinus Torvalds 	mtd->resume  = cfi_amdstd_resume;
4411da177e4SLinus Torvalds 	mtd->flags   = MTD_CAP_NORFLASH;
4421da177e4SLinus Torvalds 	mtd->name    = map->name;
443783ed81fSArtem B. Bityutskiy 	mtd->writesize = 1;
44413ce77f4SAnatolij Gustschin 	mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
445d261c72aSAnatolij Gustschin 
4460a32a102SBrian Norris 	pr_debug("MTD %s(): write buffer size %d\n", __func__,
4470a32a102SBrian Norris 			mtd->writebufsize);
4481da177e4SLinus Torvalds 
44930ec5a2cSIra W. Snyder 	mtd->panic_write = cfi_amdstd_panic_write;
450eafe1311SKevin Cernekee 	mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot;
451eafe1311SKevin Cernekee 
4521da177e4SLinus Torvalds 	if (cfi->cfi_mode==CFI_MODE_CFI){
4531da177e4SLinus Torvalds 		unsigned char bootloc;
4541da177e4SLinus Torvalds 		__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
4551da177e4SLinus Torvalds 		struct cfi_pri_amdstd *extp;
4561da177e4SLinus Torvalds 
4571da177e4SLinus Torvalds 		extp = (struct cfi_pri_amdstd*)cfi_read_pri(map, adr, sizeof(*extp), "Amd/Fujitsu");
458564b8497SGuillaume LECERF 		if (extp) {
459564b8497SGuillaume LECERF 			/*
460564b8497SGuillaume LECERF 			 * It's a real CFI chip, not one for which the probe
461564b8497SGuillaume LECERF 			 * routine faked a CFI structure.
462564b8497SGuillaume LECERF 			 */
463fefae48bSWolfgang Grandegger 			cfi_fixup_major_minor(cfi, extp);
464fefae48bSWolfgang Grandegger 
465e17f47a1SGuillaume LECERF 			/*
466c9ddab25SGernot Hoyler 			 * Valid primary extension versions are: 1.0, 1.1, 1.2, 1.3, 1.4, 1.5
467631dd1a8SJustin P. Mattock 			 * see: http://cs.ozerki.net/zap/pub/axim-x5/docs/cfi_r20.pdf, page 19
468631dd1a8SJustin P. Mattock 			 *      http://www.spansion.com/Support/AppNotes/cfi_100_20011201.pdf
4695da19532SGuillaume LECERF 			 *      http://www.spansion.com/Support/Datasheets/s29ws-p_00_a12_e.pdf
470c9ddab25SGernot Hoyler 			 *      http://www.spansion.com/Support/Datasheets/S29GL_128S_01GS_00_02_e.pdf
471e17f47a1SGuillaume LECERF 			 */
472d88f977bSTodd Poynor 			if (extp->MajorVersion != '1' ||
473c9ddab25SGernot Hoyler 			    (extp->MajorVersion == '1' && (extp->MinorVersion < '0' || extp->MinorVersion > '5'))) {
474d88f977bSTodd Poynor 				printk(KERN_ERR "  Unknown Amd/Fujitsu Extended Query "
475e17f47a1SGuillaume LECERF 				       "version %c.%c (%#02x/%#02x).\n",
476e17f47a1SGuillaume LECERF 				       extp->MajorVersion, extp->MinorVersion,
477e17f47a1SGuillaume LECERF 				       extp->MajorVersion, extp->MinorVersion);
478d88f977bSTodd Poynor 				kfree(extp);
479d88f977bSTodd Poynor 				kfree(mtd);
480d88f977bSTodd Poynor 				return NULL;
481d88f977bSTodd Poynor 			}
482d88f977bSTodd Poynor 
483e17f47a1SGuillaume LECERF 			printk(KERN_INFO "  Amd/Fujitsu Extended Query version %c.%c.\n",
484e17f47a1SGuillaume LECERF 			       extp->MajorVersion, extp->MinorVersion);
485e17f47a1SGuillaume LECERF 
4861da177e4SLinus Torvalds 			/* Install our own private info structure */
4871da177e4SLinus Torvalds 			cfi->cmdset_priv = extp;
4881da177e4SLinus Torvalds 
4891da177e4SLinus Torvalds 			/* Apply cfi device specific fixups */
4901da177e4SLinus Torvalds 			cfi_fixup(mtd, cfi_fixup_table);
4911da177e4SLinus Torvalds 
4921da177e4SLinus Torvalds #ifdef DEBUG_CFI_FEATURES
4931da177e4SLinus Torvalds 			/* Tell the user about it in lots of lovely detail */
4941da177e4SLinus Torvalds 			cfi_tell_features(extp);
4951da177e4SLinus Torvalds #endif
4961da177e4SLinus Torvalds 
4971da177e4SLinus Torvalds 			bootloc = extp->TopBottom;
498412da2f6SDavid Woodhouse 			if ((bootloc < 2) || (bootloc > 5)) {
499412da2f6SDavid Woodhouse 				printk(KERN_WARNING "%s: CFI contains unrecognised boot "
500412da2f6SDavid Woodhouse 				       "bank location (%d). Assuming bottom.\n",
501abab7ebfSDavid Woodhouse 				       map->name, bootloc);
5021da177e4SLinus Torvalds 				bootloc = 2;
5031da177e4SLinus Torvalds 			}
5041da177e4SLinus Torvalds 
5051da177e4SLinus Torvalds 			if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) {
506412da2f6SDavid Woodhouse 				printk(KERN_WARNING "%s: Swapping erase regions for top-boot CFI table.\n", map->name);
5071da177e4SLinus Torvalds 
5081da177e4SLinus Torvalds 				for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) {
5091da177e4SLinus Torvalds 					int j = (cfi->cfiq->NumEraseRegions-1)-i;
5101da177e4SLinus Torvalds 					__u32 swap;
5111da177e4SLinus Torvalds 
5121da177e4SLinus Torvalds 					swap = cfi->cfiq->EraseRegionInfo[i];
5131da177e4SLinus Torvalds 					cfi->cfiq->EraseRegionInfo[i] = cfi->cfiq->EraseRegionInfo[j];
5141da177e4SLinus Torvalds 					cfi->cfiq->EraseRegionInfo[j] = swap;
5151da177e4SLinus Torvalds 				}
5161da177e4SLinus Torvalds 			}
5171da177e4SLinus Torvalds 			/* Set the default CFI lock/unlock addresses */
5181da177e4SLinus Torvalds 			cfi->addr_unlock1 = 0x555;
5191da177e4SLinus Torvalds 			cfi->addr_unlock2 = 0x2aa;
520564b8497SGuillaume LECERF 		}
52183dcd3bbSGuillaume LECERF 		cfi_fixup(mtd, cfi_nopri_fixup_table);
522564b8497SGuillaume LECERF 
523564b8497SGuillaume LECERF 		if (!cfi->addr_unlock1 || !cfi->addr_unlock2) {
524564b8497SGuillaume LECERF 			kfree(mtd);
525564b8497SGuillaume LECERF 			return NULL;
526564b8497SGuillaume LECERF 		}
5271da177e4SLinus Torvalds 
5281da177e4SLinus Torvalds 	} /* CFI mode */
5291da177e4SLinus Torvalds 	else if (cfi->cfi_mode == CFI_MODE_JEDEC) {
5301da177e4SLinus Torvalds 		/* Apply jedec specific fixups */
5311da177e4SLinus Torvalds 		cfi_fixup(mtd, jedec_fixup_table);
5321da177e4SLinus Torvalds 	}
5331da177e4SLinus Torvalds 	/* Apply generic fixups */
5341da177e4SLinus Torvalds 	cfi_fixup(mtd, fixup_table);
5351da177e4SLinus Torvalds 
5361da177e4SLinus Torvalds 	for (i=0; i< cfi->numchips; i++) {
5371da177e4SLinus Torvalds 		cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
5381da177e4SLinus Torvalds 		cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
5391da177e4SLinus Torvalds 		cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
54083d48091SVijay Sampath 		cfi->chips[i].ref_point_counter = 0;
54183d48091SVijay Sampath 		init_waitqueue_head(&(cfi->chips[i].wq));
5421da177e4SLinus Torvalds 	}
5431da177e4SLinus Torvalds 
5441da177e4SLinus Torvalds 	map->fldrv = &cfi_amdstd_chipdrv;
5451da177e4SLinus Torvalds 
5461da177e4SLinus Torvalds 	return cfi_amdstd_setup(mtd);
5471da177e4SLinus Torvalds }
54880461128SGuillaume LECERF struct mtd_info *cfi_cmdset_0006(struct map_info *map, int primary) __attribute__((alias("cfi_cmdset_0002")));
5491e804cecSDavid Woodhouse struct mtd_info *cfi_cmdset_0701(struct map_info *map, int primary) __attribute__((alias("cfi_cmdset_0002")));
55083ea4ef2SDavid Woodhouse EXPORT_SYMBOL_GPL(cfi_cmdset_0002);
55180461128SGuillaume LECERF EXPORT_SYMBOL_GPL(cfi_cmdset_0006);
5521e804cecSDavid Woodhouse EXPORT_SYMBOL_GPL(cfi_cmdset_0701);
5531da177e4SLinus Torvalds 
5541da177e4SLinus Torvalds static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
5551da177e4SLinus Torvalds {
5561da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
5571da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
5581da177e4SLinus Torvalds 	unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
5591da177e4SLinus Torvalds 	unsigned long offset = 0;
5601da177e4SLinus Torvalds 	int i,j;
5611da177e4SLinus Torvalds 
5621da177e4SLinus Torvalds 	printk(KERN_NOTICE "number of %s chips: %d\n",
5631da177e4SLinus Torvalds 	       (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips);
5641da177e4SLinus Torvalds 	/* Select the correct geometry setup */
5651da177e4SLinus Torvalds 	mtd->size = devsize * cfi->numchips;
5661da177e4SLinus Torvalds 
5671da177e4SLinus Torvalds 	mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
5681da177e4SLinus Torvalds 	mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
5691da177e4SLinus Torvalds 				    * mtd->numeraseregions, GFP_KERNEL);
5701da177e4SLinus Torvalds 	if (!mtd->eraseregions) {
5711da177e4SLinus Torvalds 		printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n");
5721da177e4SLinus Torvalds 		goto setup_err;
5731da177e4SLinus Torvalds 	}
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds 	for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
5761da177e4SLinus Torvalds 		unsigned long ernum, ersize;
5771da177e4SLinus Torvalds 		ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
5781da177e4SLinus Torvalds 		ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
5791da177e4SLinus Torvalds 
5801da177e4SLinus Torvalds 		if (mtd->erasesize < ersize) {
5811da177e4SLinus Torvalds 			mtd->erasesize = ersize;
5821da177e4SLinus Torvalds 		}
5831da177e4SLinus Torvalds 		for (j=0; j<cfi->numchips; j++) {
5841da177e4SLinus Torvalds 			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
5851da177e4SLinus Torvalds 			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
5861da177e4SLinus Torvalds 			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
5871da177e4SLinus Torvalds 		}
5881da177e4SLinus Torvalds 		offset += (ersize * ernum);
5891da177e4SLinus Torvalds 	}
5901da177e4SLinus Torvalds 	if (offset != devsize) {
5911da177e4SLinus Torvalds 		/* Argh */
5921da177e4SLinus Torvalds 		printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
5931da177e4SLinus Torvalds 		goto setup_err;
5941da177e4SLinus Torvalds 	}
5951da177e4SLinus Torvalds 
5961da177e4SLinus Torvalds 	__module_get(THIS_MODULE);
597eafe1311SKevin Cernekee 	register_reboot_notifier(&mtd->reboot_notifier);
5981da177e4SLinus Torvalds 	return mtd;
5991da177e4SLinus Torvalds 
6001da177e4SLinus Torvalds  setup_err:
6011da177e4SLinus Torvalds 	kfree(mtd->eraseregions);
6021da177e4SLinus Torvalds 	kfree(mtd);
6031da177e4SLinus Torvalds 	kfree(cfi->cmdset_priv);
6041da177e4SLinus Torvalds 	kfree(cfi->cfiq);
6051da177e4SLinus Torvalds 	return NULL;
6061da177e4SLinus Torvalds }
6071da177e4SLinus Torvalds 
6081da177e4SLinus Torvalds /*
6091da177e4SLinus Torvalds  * Return true if the chip is ready.
6101da177e4SLinus Torvalds  *
6111da177e4SLinus Torvalds  * Ready is one of: read mode, query mode, erase-suspend-read mode (in any
6121da177e4SLinus Torvalds  * non-suspended sector) and is indicated by no toggle bits toggling.
6131da177e4SLinus Torvalds  *
6141da177e4SLinus Torvalds  * Note that anything more complicated than checking if no bits are toggling
6151da177e4SLinus Torvalds  * (including checking DQ5 for an error status) is tricky to get working
61625985edcSLucas De Marchi  * correctly and is therefore not done	(particularly with interleaved chips
61725985edcSLucas De Marchi  * as each chip must be checked independently of the others).
6181da177e4SLinus Torvalds  */
61902b15e34STodd Poynor static int __xipram chip_ready(struct map_info *map, unsigned long addr)
6201da177e4SLinus Torvalds {
6211da177e4SLinus Torvalds 	map_word d, t;
6221da177e4SLinus Torvalds 
6231da177e4SLinus Torvalds 	d = map_read(map, addr);
6241da177e4SLinus Torvalds 	t = map_read(map, addr);
6251da177e4SLinus Torvalds 
6261da177e4SLinus Torvalds 	return map_word_equal(map, d, t);
6271da177e4SLinus Torvalds }
6281da177e4SLinus Torvalds 
629fb4a90bfSEric W. Biedermann /*
630fb4a90bfSEric W. Biedermann  * Return true if the chip is ready and has the correct value.
631fb4a90bfSEric W. Biedermann  *
632fb4a90bfSEric W. Biedermann  * Ready is one of: read mode, query mode, erase-suspend-read mode (in any
633fb4a90bfSEric W. Biedermann  * non-suspended sector) and it is indicated by no bits toggling.
634fb4a90bfSEric W. Biedermann  *
635fb4a90bfSEric W. Biedermann  * Error are indicated by toggling bits or bits held with the wrong value,
636fb4a90bfSEric W. Biedermann  * or with bits toggling.
637fb4a90bfSEric W. Biedermann  *
638fb4a90bfSEric W. Biedermann  * Note that anything more complicated than checking if no bits are toggling
639fb4a90bfSEric W. Biedermann  * (including checking DQ5 for an error status) is tricky to get working
64025985edcSLucas De Marchi  * correctly and is therefore not done	(particularly with interleaved chips
64125985edcSLucas De Marchi  * as each chip must be checked independently of the others).
642fb4a90bfSEric W. Biedermann  *
643fb4a90bfSEric W. Biedermann  */
64402b15e34STodd Poynor static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word expected)
645fb4a90bfSEric W. Biedermann {
646fb4a90bfSEric W. Biedermann 	map_word oldd, curd;
647fb4a90bfSEric W. Biedermann 
648fb4a90bfSEric W. Biedermann 	oldd = map_read(map, addr);
649fb4a90bfSEric W. Biedermann 	curd = map_read(map, addr);
650fb4a90bfSEric W. Biedermann 
651fb4a90bfSEric W. Biedermann 	return	map_word_equal(map, oldd, curd) &&
652fb4a90bfSEric W. Biedermann 		map_word_equal(map, curd, expected);
653fb4a90bfSEric W. Biedermann }
654fb4a90bfSEric W. Biedermann 
6551da177e4SLinus Torvalds static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
6561da177e4SLinus Torvalds {
6571da177e4SLinus Torvalds 	DECLARE_WAITQUEUE(wait, current);
6581da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
6591da177e4SLinus Torvalds 	unsigned long timeo;
6601da177e4SLinus Torvalds 	struct cfi_pri_amdstd *cfip = (struct cfi_pri_amdstd *)cfi->cmdset_priv;
6611da177e4SLinus Torvalds 
6621da177e4SLinus Torvalds  resettime:
6631da177e4SLinus Torvalds 	timeo = jiffies + HZ;
6641da177e4SLinus Torvalds  retry:
6651da177e4SLinus Torvalds 	switch (chip->state) {
6661da177e4SLinus Torvalds 
6671da177e4SLinus Torvalds 	case FL_STATUS:
6681da177e4SLinus Torvalds 		for (;;) {
6691da177e4SLinus Torvalds 			if (chip_ready(map, adr))
6701da177e4SLinus Torvalds 				break;
6711da177e4SLinus Torvalds 
6721da177e4SLinus Torvalds 			if (time_after(jiffies, timeo)) {
6731da177e4SLinus Torvalds 				printk(KERN_ERR "Waiting for chip to be ready timed out.\n");
6741da177e4SLinus Torvalds 				return -EIO;
6751da177e4SLinus Torvalds 			}
676c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
6771da177e4SLinus Torvalds 			cfi_udelay(1);
678c4e77376SStefani Seibold 			mutex_lock(&chip->mutex);
6791da177e4SLinus Torvalds 			/* Someone else might have been playing with it. */
6801da177e4SLinus Torvalds 			goto retry;
6811da177e4SLinus Torvalds 		}
6821da177e4SLinus Torvalds 
6831da177e4SLinus Torvalds 	case FL_READY:
6841da177e4SLinus Torvalds 	case FL_CFI_QUERY:
6851da177e4SLinus Torvalds 	case FL_JEDEC_QUERY:
6861da177e4SLinus Torvalds 		return 0;
6871da177e4SLinus Torvalds 
6881da177e4SLinus Torvalds 	case FL_ERASING:
6892695eab9SJoakim Tjernlund 		if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
6902695eab9SJoakim Tjernlund 		    !(mode == FL_READY || mode == FL_POINT ||
6912695eab9SJoakim Tjernlund 		    (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
6921da177e4SLinus Torvalds 			goto sleep;
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds 		/* We could check to see if we're trying to access the sector
6951da177e4SLinus Torvalds 		 * that is currently being erased. However, no user will try
6961da177e4SLinus Torvalds 		 * anything like that so we just wait for the timeout. */
6971da177e4SLinus Torvalds 
6981da177e4SLinus Torvalds 		/* Erase suspend */
6991da177e4SLinus Torvalds 		/* It's harmless to issue the Erase-Suspend and Erase-Resume
7001da177e4SLinus Torvalds 		 * commands when the erase algorithm isn't in progress. */
7011da177e4SLinus Torvalds 		map_write(map, CMD(0xB0), chip->in_progress_block_addr);
7021da177e4SLinus Torvalds 		chip->oldstate = FL_ERASING;
7031da177e4SLinus Torvalds 		chip->state = FL_ERASE_SUSPENDING;
7041da177e4SLinus Torvalds 		chip->erase_suspended = 1;
7051da177e4SLinus Torvalds 		for (;;) {
7061da177e4SLinus Torvalds 			if (chip_ready(map, adr))
7071da177e4SLinus Torvalds 				break;
7081da177e4SLinus Torvalds 
7091da177e4SLinus Torvalds 			if (time_after(jiffies, timeo)) {
7101da177e4SLinus Torvalds 				/* Should have suspended the erase by now.
7111da177e4SLinus Torvalds 				 * Send an Erase-Resume command as either
7121da177e4SLinus Torvalds 				 * there was an error (so leave the erase
7131da177e4SLinus Torvalds 				 * routine to recover from it) or we trying to
7141da177e4SLinus Torvalds 				 * use the erase-in-progress sector. */
715100f2341STadashi Abe 				put_chip(map, chip, adr);
7161da177e4SLinus Torvalds 				printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__);
7171da177e4SLinus Torvalds 				return -EIO;
7181da177e4SLinus Torvalds 			}
7191da177e4SLinus Torvalds 
720c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
7211da177e4SLinus Torvalds 			cfi_udelay(1);
722c4e77376SStefani Seibold 			mutex_lock(&chip->mutex);
7231da177e4SLinus Torvalds 			/* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
7241da177e4SLinus Torvalds 			   So we can just loop here. */
7251da177e4SLinus Torvalds 		}
7261da177e4SLinus Torvalds 		chip->state = FL_READY;
7271da177e4SLinus Torvalds 		return 0;
7281da177e4SLinus Torvalds 
72902b15e34STodd Poynor 	case FL_XIP_WHILE_ERASING:
73002b15e34STodd Poynor 		if (mode != FL_READY && mode != FL_POINT &&
73102b15e34STodd Poynor 		    (!cfip || !(cfip->EraseSuspend&2)))
73202b15e34STodd Poynor 			goto sleep;
73302b15e34STodd Poynor 		chip->oldstate = chip->state;
73402b15e34STodd Poynor 		chip->state = FL_READY;
73502b15e34STodd Poynor 		return 0;
73602b15e34STodd Poynor 
737eafe1311SKevin Cernekee 	case FL_SHUTDOWN:
738eafe1311SKevin Cernekee 		/* The machine is rebooting */
739eafe1311SKevin Cernekee 		return -EIO;
740eafe1311SKevin Cernekee 
7411da177e4SLinus Torvalds 	case FL_POINT:
7421da177e4SLinus Torvalds 		/* Only if there's no operation suspended... */
7431da177e4SLinus Torvalds 		if (mode == FL_READY && chip->oldstate == FL_READY)
7441da177e4SLinus Torvalds 			return 0;
7451da177e4SLinus Torvalds 
7461da177e4SLinus Torvalds 	default:
7471da177e4SLinus Torvalds 	sleep:
7481da177e4SLinus Torvalds 		set_current_state(TASK_UNINTERRUPTIBLE);
7491da177e4SLinus Torvalds 		add_wait_queue(&chip->wq, &wait);
750c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
7511da177e4SLinus Torvalds 		schedule();
7521da177e4SLinus Torvalds 		remove_wait_queue(&chip->wq, &wait);
753c4e77376SStefani Seibold 		mutex_lock(&chip->mutex);
7541da177e4SLinus Torvalds 		goto resettime;
7551da177e4SLinus Torvalds 	}
7561da177e4SLinus Torvalds }
7571da177e4SLinus Torvalds 
7581da177e4SLinus Torvalds 
7591da177e4SLinus Torvalds static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr)
7601da177e4SLinus Torvalds {
7611da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
7621da177e4SLinus Torvalds 
7631da177e4SLinus Torvalds 	switch(chip->oldstate) {
7641da177e4SLinus Torvalds 	case FL_ERASING:
76508968041SGuillaume LECERF 		map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr);
7661da177e4SLinus Torvalds 		chip->oldstate = FL_READY;
7671da177e4SLinus Torvalds 		chip->state = FL_ERASING;
7681da177e4SLinus Torvalds 		break;
7691da177e4SLinus Torvalds 
77002b15e34STodd Poynor 	case FL_XIP_WHILE_ERASING:
77102b15e34STodd Poynor 		chip->state = chip->oldstate;
77202b15e34STodd Poynor 		chip->oldstate = FL_READY;
77302b15e34STodd Poynor 		break;
77402b15e34STodd Poynor 
7751da177e4SLinus Torvalds 	case FL_READY:
7761da177e4SLinus Torvalds 	case FL_STATUS:
7771da177e4SLinus Torvalds 		/* We should really make set_vpp() count, rather than doing this */
7781da177e4SLinus Torvalds 		DISABLE_VPP(map);
7791da177e4SLinus Torvalds 		break;
7801da177e4SLinus Torvalds 	default:
7811da177e4SLinus Torvalds 		printk(KERN_ERR "MTD: put_chip() called with oldstate %d!!\n", chip->oldstate);
7821da177e4SLinus Torvalds 	}
7831da177e4SLinus Torvalds 	wake_up(&chip->wq);
7841da177e4SLinus Torvalds }
7851da177e4SLinus Torvalds 
78602b15e34STodd Poynor #ifdef CONFIG_MTD_XIP
78702b15e34STodd Poynor 
78802b15e34STodd Poynor /*
78902b15e34STodd Poynor  * No interrupt what so ever can be serviced while the flash isn't in array
79002b15e34STodd Poynor  * mode.  This is ensured by the xip_disable() and xip_enable() functions
79102b15e34STodd Poynor  * enclosing any code path where the flash is known not to be in array mode.
79202b15e34STodd Poynor  * And within a XIP disabled code path, only functions marked with __xipram
79302b15e34STodd Poynor  * may be called and nothing else (it's a good thing to inspect generated
79402b15e34STodd Poynor  * assembly to make sure inline functions were actually inlined and that gcc
79502b15e34STodd Poynor  * didn't emit calls to its own support functions). Also configuring MTD CFI
79602b15e34STodd Poynor  * support to a single buswidth and a single interleave is also recommended.
79702b15e34STodd Poynor  */
798f8eb321bSThomas Gleixner 
79902b15e34STodd Poynor static void xip_disable(struct map_info *map, struct flchip *chip,
80002b15e34STodd Poynor 			unsigned long adr)
80102b15e34STodd Poynor {
80202b15e34STodd Poynor 	/* TODO: chips with no XIP use should ignore and return */
80302b15e34STodd Poynor 	(void) map_read(map, adr); /* ensure mmu mapping is up to date */
80402b15e34STodd Poynor 	local_irq_disable();
80502b15e34STodd Poynor }
80602b15e34STodd Poynor 
80702b15e34STodd Poynor static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
80802b15e34STodd Poynor 				unsigned long adr)
80902b15e34STodd Poynor {
81002b15e34STodd Poynor 	struct cfi_private *cfi = map->fldrv_priv;
81102b15e34STodd Poynor 
81202b15e34STodd Poynor 	if (chip->state != FL_POINT && chip->state != FL_READY) {
81302b15e34STodd Poynor 		map_write(map, CMD(0xf0), adr);
81402b15e34STodd Poynor 		chip->state = FL_READY;
81502b15e34STodd Poynor 	}
81602b15e34STodd Poynor 	(void) map_read(map, adr);
81797f927a4SThomas Gleixner 	xip_iprefetch();
81802b15e34STodd Poynor 	local_irq_enable();
81902b15e34STodd Poynor }
82002b15e34STodd Poynor 
82102b15e34STodd Poynor /*
82202b15e34STodd Poynor  * When a delay is required for the flash operation to complete, the
82302b15e34STodd Poynor  * xip_udelay() function is polling for both the given timeout and pending
82402b15e34STodd Poynor  * (but still masked) hardware interrupts.  Whenever there is an interrupt
82502b15e34STodd Poynor  * pending then the flash erase operation is suspended, array mode restored
82602b15e34STodd Poynor  * and interrupts unmasked.  Task scheduling might also happen at that
82702b15e34STodd Poynor  * point.  The CPU eventually returns from the interrupt or the call to
82802b15e34STodd Poynor  * schedule() and the suspended flash operation is resumed for the remaining
82902b15e34STodd Poynor  * of the delay period.
83002b15e34STodd Poynor  *
83102b15e34STodd Poynor  * Warning: this function _will_ fool interrupt latency tracing tools.
83202b15e34STodd Poynor  */
83302b15e34STodd Poynor 
83402b15e34STodd Poynor static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
83502b15e34STodd Poynor 				unsigned long adr, int usec)
83602b15e34STodd Poynor {
83702b15e34STodd Poynor 	struct cfi_private *cfi = map->fldrv_priv;
83802b15e34STodd Poynor 	struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
83902b15e34STodd Poynor 	map_word status, OK = CMD(0x80);
84002b15e34STodd Poynor 	unsigned long suspended, start = xip_currtime();
84102b15e34STodd Poynor 	flstate_t oldstate;
84202b15e34STodd Poynor 
84302b15e34STodd Poynor 	do {
84402b15e34STodd Poynor 		cpu_relax();
84502b15e34STodd Poynor 		if (xip_irqpending() && extp &&
84602b15e34STodd Poynor 		    ((chip->state == FL_ERASING && (extp->EraseSuspend & 2))) &&
84702b15e34STodd Poynor 		    (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) {
84802b15e34STodd Poynor 			/*
84902b15e34STodd Poynor 			 * Let's suspend the erase operation when supported.
85002b15e34STodd Poynor 			 * Note that we currently don't try to suspend
85102b15e34STodd Poynor 			 * interleaved chips if there is already another
85202b15e34STodd Poynor 			 * operation suspended (imagine what happens
85302b15e34STodd Poynor 			 * when one chip was already done with the current
85402b15e34STodd Poynor 			 * operation while another chip suspended it, then
85502b15e34STodd Poynor 			 * we resume the whole thing at once).  Yes, it
85602b15e34STodd Poynor 			 * can happen!
85702b15e34STodd Poynor 			 */
85802b15e34STodd Poynor 			map_write(map, CMD(0xb0), adr);
85902b15e34STodd Poynor 			usec -= xip_elapsed_since(start);
86002b15e34STodd Poynor 			suspended = xip_currtime();
86102b15e34STodd Poynor 			do {
86202b15e34STodd Poynor 				if (xip_elapsed_since(suspended) > 100000) {
86302b15e34STodd Poynor 					/*
86402b15e34STodd Poynor 					 * The chip doesn't want to suspend
86502b15e34STodd Poynor 					 * after waiting for 100 msecs.
86602b15e34STodd Poynor 					 * This is a critical error but there
86702b15e34STodd Poynor 					 * is not much we can do here.
86802b15e34STodd Poynor 					 */
86902b15e34STodd Poynor 					return;
87002b15e34STodd Poynor 				}
87102b15e34STodd Poynor 				status = map_read(map, adr);
87202b15e34STodd Poynor 			} while (!map_word_andequal(map, status, OK, OK));
87302b15e34STodd Poynor 
87402b15e34STodd Poynor 			/* Suspend succeeded */
87502b15e34STodd Poynor 			oldstate = chip->state;
87602b15e34STodd Poynor 			if (!map_word_bitsset(map, status, CMD(0x40)))
87702b15e34STodd Poynor 				break;
87802b15e34STodd Poynor 			chip->state = FL_XIP_WHILE_ERASING;
87902b15e34STodd Poynor 			chip->erase_suspended = 1;
88002b15e34STodd Poynor 			map_write(map, CMD(0xf0), adr);
88102b15e34STodd Poynor 			(void) map_read(map, adr);
882ca5c23c3SPaulius Zaleckas 			xip_iprefetch();
88302b15e34STodd Poynor 			local_irq_enable();
884c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
885ca5c23c3SPaulius Zaleckas 			xip_iprefetch();
88602b15e34STodd Poynor 			cond_resched();
88702b15e34STodd Poynor 
88802b15e34STodd Poynor 			/*
88902b15e34STodd Poynor 			 * We're back.  However someone else might have
89002b15e34STodd Poynor 			 * decided to go write to the chip if we are in
89102b15e34STodd Poynor 			 * a suspended erase state.  If so let's wait
89202b15e34STodd Poynor 			 * until it's done.
89302b15e34STodd Poynor 			 */
894c4e77376SStefani Seibold 			mutex_lock(&chip->mutex);
89502b15e34STodd Poynor 			while (chip->state != FL_XIP_WHILE_ERASING) {
89602b15e34STodd Poynor 				DECLARE_WAITQUEUE(wait, current);
89702b15e34STodd Poynor 				set_current_state(TASK_UNINTERRUPTIBLE);
89802b15e34STodd Poynor 				add_wait_queue(&chip->wq, &wait);
899c4e77376SStefani Seibold 				mutex_unlock(&chip->mutex);
90002b15e34STodd Poynor 				schedule();
90102b15e34STodd Poynor 				remove_wait_queue(&chip->wq, &wait);
902c4e77376SStefani Seibold 				mutex_lock(&chip->mutex);
90302b15e34STodd Poynor 			}
90402b15e34STodd Poynor 			/* Disallow XIP again */
90502b15e34STodd Poynor 			local_irq_disable();
90602b15e34STodd Poynor 
90702b15e34STodd Poynor 			/* Resume the write or erase operation */
90808968041SGuillaume LECERF 			map_write(map, cfi->sector_erase_cmd, adr);
90902b15e34STodd Poynor 			chip->state = oldstate;
91002b15e34STodd Poynor 			start = xip_currtime();
91102b15e34STodd Poynor 		} else if (usec >= 1000000/HZ) {
91202b15e34STodd Poynor 			/*
91302b15e34STodd Poynor 			 * Try to save on CPU power when waiting delay
91402b15e34STodd Poynor 			 * is at least a system timer tick period.
91502b15e34STodd Poynor 			 * No need to be extremely accurate here.
91602b15e34STodd Poynor 			 */
91702b15e34STodd Poynor 			xip_cpu_idle();
91802b15e34STodd Poynor 		}
91902b15e34STodd Poynor 		status = map_read(map, adr);
92002b15e34STodd Poynor 	} while (!map_word_andequal(map, status, OK, OK)
92102b15e34STodd Poynor 		 && xip_elapsed_since(start) < usec);
92202b15e34STodd Poynor }
92302b15e34STodd Poynor 
92402b15e34STodd Poynor #define UDELAY(map, chip, adr, usec)  xip_udelay(map, chip, adr, usec)
92502b15e34STodd Poynor 
92602b15e34STodd Poynor /*
92702b15e34STodd Poynor  * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
92802b15e34STodd Poynor  * the flash is actively programming or erasing since we have to poll for
92902b15e34STodd Poynor  * the operation to complete anyway.  We can't do that in a generic way with
93002b15e34STodd Poynor  * a XIP setup so do it before the actual flash operation in this case
93102b15e34STodd Poynor  * and stub it out from INVALIDATE_CACHE_UDELAY.
93202b15e34STodd Poynor  */
93302b15e34STodd Poynor #define XIP_INVAL_CACHED_RANGE(map, from, size)  \
93402b15e34STodd Poynor 	INVALIDATE_CACHED_RANGE(map, from, size)
93502b15e34STodd Poynor 
93602b15e34STodd Poynor #define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec)  \
93702b15e34STodd Poynor 	UDELAY(map, chip, adr, usec)
93802b15e34STodd Poynor 
93902b15e34STodd Poynor /*
94002b15e34STodd Poynor  * Extra notes:
94102b15e34STodd Poynor  *
94202b15e34STodd Poynor  * Activating this XIP support changes the way the code works a bit.  For
94302b15e34STodd Poynor  * example the code to suspend the current process when concurrent access
94402b15e34STodd Poynor  * happens is never executed because xip_udelay() will always return with the
94502b15e34STodd Poynor  * same chip state as it was entered with.  This is why there is no care for
94602b15e34STodd Poynor  * the presence of add_wait_queue() or schedule() calls from within a couple
94702b15e34STodd Poynor  * xip_disable()'d  areas of code, like in do_erase_oneblock for example.
94802b15e34STodd Poynor  * The queueing and scheduling are always happening within xip_udelay().
94902b15e34STodd Poynor  *
95002b15e34STodd Poynor  * Similarly, get_chip() and put_chip() just happen to always be executed
95102b15e34STodd Poynor  * with chip->state set to FL_READY (or FL_XIP_WHILE_*) where flash state
95202b15e34STodd Poynor  * is in array mode, therefore never executing many cases therein and not
95302b15e34STodd Poynor  * causing any problem with XIP.
95402b15e34STodd Poynor  */
95502b15e34STodd Poynor 
95602b15e34STodd Poynor #else
95702b15e34STodd Poynor 
95802b15e34STodd Poynor #define xip_disable(map, chip, adr)
95902b15e34STodd Poynor #define xip_enable(map, chip, adr)
96002b15e34STodd Poynor #define XIP_INVAL_CACHED_RANGE(x...)
96102b15e34STodd Poynor 
96202b15e34STodd Poynor #define UDELAY(map, chip, adr, usec)  \
96302b15e34STodd Poynor do {  \
964c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);  \
96502b15e34STodd Poynor 	cfi_udelay(usec);  \
966c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);  \
96702b15e34STodd Poynor } while (0)
96802b15e34STodd Poynor 
96902b15e34STodd Poynor #define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec)  \
97002b15e34STodd Poynor do {  \
971c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);  \
97202b15e34STodd Poynor 	INVALIDATE_CACHED_RANGE(map, adr, len);  \
97302b15e34STodd Poynor 	cfi_udelay(usec);  \
974c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);  \
97502b15e34STodd Poynor } while (0)
97602b15e34STodd Poynor 
97702b15e34STodd Poynor #endif
9781da177e4SLinus Torvalds 
9791da177e4SLinus Torvalds static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
9801da177e4SLinus Torvalds {
9811da177e4SLinus Torvalds 	unsigned long cmd_addr;
9821da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
9831da177e4SLinus Torvalds 	int ret;
9841da177e4SLinus Torvalds 
9851da177e4SLinus Torvalds 	adr += chip->start;
9861da177e4SLinus Torvalds 
9871da177e4SLinus Torvalds 	/* Ensure cmd read/writes are aligned. */
9881da177e4SLinus Torvalds 	cmd_addr = adr & ~(map_bankwidth(map)-1);
9891da177e4SLinus Torvalds 
990c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);
9911da177e4SLinus Torvalds 	ret = get_chip(map, chip, cmd_addr, FL_READY);
9921da177e4SLinus Torvalds 	if (ret) {
993c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
9941da177e4SLinus Torvalds 		return ret;
9951da177e4SLinus Torvalds 	}
9961da177e4SLinus Torvalds 
9971da177e4SLinus Torvalds 	if (chip->state != FL_POINT && chip->state != FL_READY) {
9981da177e4SLinus Torvalds 		map_write(map, CMD(0xf0), cmd_addr);
9991da177e4SLinus Torvalds 		chip->state = FL_READY;
10001da177e4SLinus Torvalds 	}
10011da177e4SLinus Torvalds 
10021da177e4SLinus Torvalds 	map_copy_from(map, buf, adr, len);
10031da177e4SLinus Torvalds 
10041da177e4SLinus Torvalds 	put_chip(map, chip, cmd_addr);
10051da177e4SLinus Torvalds 
1006c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);
10071da177e4SLinus Torvalds 	return 0;
10081da177e4SLinus Torvalds }
10091da177e4SLinus Torvalds 
10101da177e4SLinus Torvalds 
10111da177e4SLinus Torvalds static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
10121da177e4SLinus Torvalds {
10131da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
10141da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
10151da177e4SLinus Torvalds 	unsigned long ofs;
10161da177e4SLinus Torvalds 	int chipnum;
10171da177e4SLinus Torvalds 	int ret = 0;
10181da177e4SLinus Torvalds 
10191da177e4SLinus Torvalds 	/* ofs: offset within the first chip that the first read should start */
10201da177e4SLinus Torvalds 
10211da177e4SLinus Torvalds 	chipnum = (from >> cfi->chipshift);
10221da177e4SLinus Torvalds 	ofs = from - (chipnum <<  cfi->chipshift);
10231da177e4SLinus Torvalds 
10241da177e4SLinus Torvalds 
10251da177e4SLinus Torvalds 	*retlen = 0;
10261da177e4SLinus Torvalds 
10271da177e4SLinus Torvalds 	while (len) {
10281da177e4SLinus Torvalds 		unsigned long thislen;
10291da177e4SLinus Torvalds 
10301da177e4SLinus Torvalds 		if (chipnum >= cfi->numchips)
10311da177e4SLinus Torvalds 			break;
10321da177e4SLinus Torvalds 
10331da177e4SLinus Torvalds 		if ((len + ofs -1) >> cfi->chipshift)
10341da177e4SLinus Torvalds 			thislen = (1<<cfi->chipshift) - ofs;
10351da177e4SLinus Torvalds 		else
10361da177e4SLinus Torvalds 			thislen = len;
10371da177e4SLinus Torvalds 
10381da177e4SLinus Torvalds 		ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
10391da177e4SLinus Torvalds 		if (ret)
10401da177e4SLinus Torvalds 			break;
10411da177e4SLinus Torvalds 
10421da177e4SLinus Torvalds 		*retlen += thislen;
10431da177e4SLinus Torvalds 		len -= thislen;
10441da177e4SLinus Torvalds 		buf += thislen;
10451da177e4SLinus Torvalds 
10461da177e4SLinus Torvalds 		ofs = 0;
10471da177e4SLinus Torvalds 		chipnum++;
10481da177e4SLinus Torvalds 	}
10491da177e4SLinus Torvalds 	return ret;
10501da177e4SLinus Torvalds }
10511da177e4SLinus Torvalds 
10521da177e4SLinus Torvalds 
10531da177e4SLinus Torvalds static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
10541da177e4SLinus Torvalds {
10551da177e4SLinus Torvalds 	DECLARE_WAITQUEUE(wait, current);
10561da177e4SLinus Torvalds 	unsigned long timeo = jiffies + HZ;
10571da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
10581da177e4SLinus Torvalds 
10591da177e4SLinus Torvalds  retry:
1060c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);
10611da177e4SLinus Torvalds 
10621da177e4SLinus Torvalds 	if (chip->state != FL_READY){
10631da177e4SLinus Torvalds 		set_current_state(TASK_UNINTERRUPTIBLE);
10641da177e4SLinus Torvalds 		add_wait_queue(&chip->wq, &wait);
10651da177e4SLinus Torvalds 
1066c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
10671da177e4SLinus Torvalds 
10681da177e4SLinus Torvalds 		schedule();
10691da177e4SLinus Torvalds 		remove_wait_queue(&chip->wq, &wait);
10701da177e4SLinus Torvalds 		timeo = jiffies + HZ;
10711da177e4SLinus Torvalds 
10721da177e4SLinus Torvalds 		goto retry;
10731da177e4SLinus Torvalds 	}
10741da177e4SLinus Torvalds 
10751da177e4SLinus Torvalds 	adr += chip->start;
10761da177e4SLinus Torvalds 
10771da177e4SLinus Torvalds 	chip->state = FL_READY;
10781da177e4SLinus Torvalds 
10791da177e4SLinus Torvalds 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
10801da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
10811da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
10821da177e4SLinus Torvalds 
10831da177e4SLinus Torvalds 	map_copy_from(map, buf, adr, len);
10841da177e4SLinus Torvalds 
10851da177e4SLinus Torvalds 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
10861da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
10871da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
10881da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
10891da177e4SLinus Torvalds 
10901da177e4SLinus Torvalds 	wake_up(&chip->wq);
1091c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);
10921da177e4SLinus Torvalds 
10931da177e4SLinus Torvalds 	return 0;
10941da177e4SLinus Torvalds }
10951da177e4SLinus Torvalds 
10961da177e4SLinus Torvalds static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
10971da177e4SLinus Torvalds {
10981da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
10991da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
11001da177e4SLinus Torvalds 	unsigned long ofs;
11011da177e4SLinus Torvalds 	int chipnum;
11021da177e4SLinus Torvalds 	int ret = 0;
11031da177e4SLinus Torvalds 
11041da177e4SLinus Torvalds 
11051da177e4SLinus Torvalds 	/* ofs: offset within the first chip that the first read should start */
11061da177e4SLinus Torvalds 
11071da177e4SLinus Torvalds 	/* 8 secsi bytes per chip */
11081da177e4SLinus Torvalds 	chipnum=from>>3;
11091da177e4SLinus Torvalds 	ofs=from & 7;
11101da177e4SLinus Torvalds 
11111da177e4SLinus Torvalds 
11121da177e4SLinus Torvalds 	*retlen = 0;
11131da177e4SLinus Torvalds 
11141da177e4SLinus Torvalds 	while (len) {
11151da177e4SLinus Torvalds 		unsigned long thislen;
11161da177e4SLinus Torvalds 
11171da177e4SLinus Torvalds 		if (chipnum >= cfi->numchips)
11181da177e4SLinus Torvalds 			break;
11191da177e4SLinus Torvalds 
11201da177e4SLinus Torvalds 		if ((len + ofs -1) >> 3)
11211da177e4SLinus Torvalds 			thislen = (1<<3) - ofs;
11221da177e4SLinus Torvalds 		else
11231da177e4SLinus Torvalds 			thislen = len;
11241da177e4SLinus Torvalds 
11251da177e4SLinus Torvalds 		ret = do_read_secsi_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
11261da177e4SLinus Torvalds 		if (ret)
11271da177e4SLinus Torvalds 			break;
11281da177e4SLinus Torvalds 
11291da177e4SLinus Torvalds 		*retlen += thislen;
11301da177e4SLinus Torvalds 		len -= thislen;
11311da177e4SLinus Torvalds 		buf += thislen;
11321da177e4SLinus Torvalds 
11331da177e4SLinus Torvalds 		ofs = 0;
11341da177e4SLinus Torvalds 		chipnum++;
11351da177e4SLinus Torvalds 	}
11361da177e4SLinus Torvalds 	return ret;
11371da177e4SLinus Torvalds }
11381da177e4SLinus Torvalds 
11391da177e4SLinus Torvalds 
114002b15e34STodd Poynor static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
11411da177e4SLinus Torvalds {
11421da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
11431da177e4SLinus Torvalds 	unsigned long timeo = jiffies + HZ;
11441da177e4SLinus Torvalds 	/*
11451da177e4SLinus Torvalds 	 * We use a 1ms + 1 jiffies generic timeout for writes (most devices
11461da177e4SLinus Torvalds 	 * have a max write time of a few hundreds usec). However, we should
11471da177e4SLinus Torvalds 	 * use the maximum timeout value given by the chip at probe time
11481da177e4SLinus Torvalds 	 * instead.  Unfortunately, struct flchip does have a field for
11491da177e4SLinus Torvalds 	 * maximum timeout, only for typical which can be far too short
11501da177e4SLinus Torvalds 	 * depending of the conditions.	 The ' + 1' is to avoid having a
11511da177e4SLinus Torvalds 	 * timeout of 0 jiffies if HZ is smaller than 1000.
11521da177e4SLinus Torvalds 	 */
11531da177e4SLinus Torvalds 	unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
11541da177e4SLinus Torvalds 	int ret = 0;
11551da177e4SLinus Torvalds 	map_word oldd;
11561da177e4SLinus Torvalds 	int retry_cnt = 0;
11571da177e4SLinus Torvalds 
11581da177e4SLinus Torvalds 	adr += chip->start;
11591da177e4SLinus Torvalds 
1160c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);
11611da177e4SLinus Torvalds 	ret = get_chip(map, chip, adr, FL_WRITING);
11621da177e4SLinus Torvalds 	if (ret) {
1163c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
11641da177e4SLinus Torvalds 		return ret;
11651da177e4SLinus Torvalds 	}
11661da177e4SLinus Torvalds 
1167289c0522SBrian Norris 	pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
11681da177e4SLinus Torvalds 	       __func__, adr, datum.x[0] );
11691da177e4SLinus Torvalds 
11701da177e4SLinus Torvalds 	/*
11711da177e4SLinus Torvalds 	 * Check for a NOP for the case when the datum to write is already
11721da177e4SLinus Torvalds 	 * present - it saves time and works around buggy chips that corrupt
11731da177e4SLinus Torvalds 	 * data at other locations when 0xff is written to a location that
11741da177e4SLinus Torvalds 	 * already contains 0xff.
11751da177e4SLinus Torvalds 	 */
11761da177e4SLinus Torvalds 	oldd = map_read(map, adr);
11771da177e4SLinus Torvalds 	if (map_word_equal(map, oldd, datum)) {
1178289c0522SBrian Norris 		pr_debug("MTD %s(): NOP\n",
11791da177e4SLinus Torvalds 		       __func__);
11801da177e4SLinus Torvalds 		goto op_done;
11811da177e4SLinus Torvalds 	}
11821da177e4SLinus Torvalds 
118302b15e34STodd Poynor 	XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
11841da177e4SLinus Torvalds 	ENABLE_VPP(map);
118502b15e34STodd Poynor 	xip_disable(map, chip, adr);
11861da177e4SLinus Torvalds  retry:
11871da177e4SLinus Torvalds 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
11881da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
11891da177e4SLinus Torvalds 	cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
11901da177e4SLinus Torvalds 	map_write(map, datum, adr);
11911da177e4SLinus Torvalds 	chip->state = FL_WRITING;
11921da177e4SLinus Torvalds 
119302b15e34STodd Poynor 	INVALIDATE_CACHE_UDELAY(map, chip,
119402b15e34STodd Poynor 				adr, map_bankwidth(map),
119502b15e34STodd Poynor 				chip->word_write_time);
11961da177e4SLinus Torvalds 
11971da177e4SLinus Torvalds 	/* See comment above for timeout value. */
11981da177e4SLinus Torvalds 	timeo = jiffies + uWriteTimeout;
11991da177e4SLinus Torvalds 	for (;;) {
12001da177e4SLinus Torvalds 		if (chip->state != FL_WRITING) {
12011da177e4SLinus Torvalds 			/* Someone's suspended the write. Sleep */
12021da177e4SLinus Torvalds 			DECLARE_WAITQUEUE(wait, current);
12031da177e4SLinus Torvalds 
12041da177e4SLinus Torvalds 			set_current_state(TASK_UNINTERRUPTIBLE);
12051da177e4SLinus Torvalds 			add_wait_queue(&chip->wq, &wait);
1206c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
12071da177e4SLinus Torvalds 			schedule();
12081da177e4SLinus Torvalds 			remove_wait_queue(&chip->wq, &wait);
12091da177e4SLinus Torvalds 			timeo = jiffies + (HZ / 2); /* FIXME */
1210c4e77376SStefani Seibold 			mutex_lock(&chip->mutex);
12111da177e4SLinus Torvalds 			continue;
12121da177e4SLinus Torvalds 		}
12131da177e4SLinus Torvalds 
1214b95f9609SKonstantin Baidarov 		if (time_after(jiffies, timeo) && !chip_ready(map, adr)){
121502b15e34STodd Poynor 			xip_enable(map, chip, adr);
1216fb4a90bfSEric W. Biedermann 			printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
121702b15e34STodd Poynor 			xip_disable(map, chip, adr);
1218fb4a90bfSEric W. Biedermann 			break;
1219fb4a90bfSEric W. Biedermann 		}
1220fb4a90bfSEric W. Biedermann 
1221b95f9609SKonstantin Baidarov 		if (chip_ready(map, adr))
1222b95f9609SKonstantin Baidarov 			break;
1223b95f9609SKonstantin Baidarov 
12241da177e4SLinus Torvalds 		/* Latency issues. Drop the lock, wait a while and retry */
122502b15e34STodd Poynor 		UDELAY(map, chip, adr, 1);
12261da177e4SLinus Torvalds 	}
1227fb4a90bfSEric W. Biedermann 	/* Did we succeed? */
1228fb4a90bfSEric W. Biedermann 	if (!chip_good(map, adr, datum)) {
12291da177e4SLinus Torvalds 		/* reset on all failures. */
12301da177e4SLinus Torvalds 		map_write( map, CMD(0xF0), chip->start );
12311da177e4SLinus Torvalds 		/* FIXME - should have reset delay before continuing */
1232fb4a90bfSEric W. Biedermann 
12331da177e4SLinus Torvalds 		if (++retry_cnt <= MAX_WORD_RETRIES)
12341da177e4SLinus Torvalds 			goto retry;
12351da177e4SLinus Torvalds 
12361da177e4SLinus Torvalds 		ret = -EIO;
1237fb4a90bfSEric W. Biedermann 	}
123802b15e34STodd Poynor 	xip_enable(map, chip, adr);
12391da177e4SLinus Torvalds  op_done:
12401da177e4SLinus Torvalds 	chip->state = FL_READY;
12411da177e4SLinus Torvalds 	put_chip(map, chip, adr);
1242c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);
12431da177e4SLinus Torvalds 
12441da177e4SLinus Torvalds 	return ret;
12451da177e4SLinus Torvalds }
12461da177e4SLinus Torvalds 
12471da177e4SLinus Torvalds 
12481da177e4SLinus Torvalds static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
12491da177e4SLinus Torvalds 				  size_t *retlen, const u_char *buf)
12501da177e4SLinus Torvalds {
12511da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
12521da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
12531da177e4SLinus Torvalds 	int ret = 0;
12541da177e4SLinus Torvalds 	int chipnum;
12551da177e4SLinus Torvalds 	unsigned long ofs, chipstart;
12561da177e4SLinus Torvalds 	DECLARE_WAITQUEUE(wait, current);
12571da177e4SLinus Torvalds 
12581da177e4SLinus Torvalds 	*retlen = 0;
12591da177e4SLinus Torvalds 	if (!len)
12601da177e4SLinus Torvalds 		return 0;
12611da177e4SLinus Torvalds 
12621da177e4SLinus Torvalds 	chipnum = to >> cfi->chipshift;
12631da177e4SLinus Torvalds 	ofs = to  - (chipnum << cfi->chipshift);
12641da177e4SLinus Torvalds 	chipstart = cfi->chips[chipnum].start;
12651da177e4SLinus Torvalds 
12661da177e4SLinus Torvalds 	/* If it's not bus-aligned, do the first byte write */
12671da177e4SLinus Torvalds 	if (ofs & (map_bankwidth(map)-1)) {
12681da177e4SLinus Torvalds 		unsigned long bus_ofs = ofs & ~(map_bankwidth(map)-1);
12691da177e4SLinus Torvalds 		int i = ofs - bus_ofs;
12701da177e4SLinus Torvalds 		int n = 0;
12711da177e4SLinus Torvalds 		map_word tmp_buf;
12721da177e4SLinus Torvalds 
12731da177e4SLinus Torvalds  retry:
1274c4e77376SStefani Seibold 		mutex_lock(&cfi->chips[chipnum].mutex);
12751da177e4SLinus Torvalds 
12761da177e4SLinus Torvalds 		if (cfi->chips[chipnum].state != FL_READY) {
12771da177e4SLinus Torvalds 			set_current_state(TASK_UNINTERRUPTIBLE);
12781da177e4SLinus Torvalds 			add_wait_queue(&cfi->chips[chipnum].wq, &wait);
12791da177e4SLinus Torvalds 
1280c4e77376SStefani Seibold 			mutex_unlock(&cfi->chips[chipnum].mutex);
12811da177e4SLinus Torvalds 
12821da177e4SLinus Torvalds 			schedule();
12831da177e4SLinus Torvalds 			remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
12841da177e4SLinus Torvalds 			goto retry;
12851da177e4SLinus Torvalds 		}
12861da177e4SLinus Torvalds 
12871da177e4SLinus Torvalds 		/* Load 'tmp_buf' with old contents of flash */
12881da177e4SLinus Torvalds 		tmp_buf = map_read(map, bus_ofs+chipstart);
12891da177e4SLinus Torvalds 
1290c4e77376SStefani Seibold 		mutex_unlock(&cfi->chips[chipnum].mutex);
12911da177e4SLinus Torvalds 
12921da177e4SLinus Torvalds 		/* Number of bytes to copy from buffer */
12931da177e4SLinus Torvalds 		n = min_t(int, len, map_bankwidth(map)-i);
12941da177e4SLinus Torvalds 
12951da177e4SLinus Torvalds 		tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n);
12961da177e4SLinus Torvalds 
12971da177e4SLinus Torvalds 		ret = do_write_oneword(map, &cfi->chips[chipnum],
12981da177e4SLinus Torvalds 				       bus_ofs, tmp_buf);
12991da177e4SLinus Torvalds 		if (ret)
13001da177e4SLinus Torvalds 			return ret;
13011da177e4SLinus Torvalds 
13021da177e4SLinus Torvalds 		ofs += n;
13031da177e4SLinus Torvalds 		buf += n;
13041da177e4SLinus Torvalds 		(*retlen) += n;
13051da177e4SLinus Torvalds 		len -= n;
13061da177e4SLinus Torvalds 
13071da177e4SLinus Torvalds 		if (ofs >> cfi->chipshift) {
13081da177e4SLinus Torvalds 			chipnum ++;
13091da177e4SLinus Torvalds 			ofs = 0;
13101da177e4SLinus Torvalds 			if (chipnum == cfi->numchips)
13111da177e4SLinus Torvalds 				return 0;
13121da177e4SLinus Torvalds 		}
13131da177e4SLinus Torvalds 	}
13141da177e4SLinus Torvalds 
13151da177e4SLinus Torvalds 	/* We are now aligned, write as much as possible */
13161da177e4SLinus Torvalds 	while(len >= map_bankwidth(map)) {
13171da177e4SLinus Torvalds 		map_word datum;
13181da177e4SLinus Torvalds 
13191da177e4SLinus Torvalds 		datum = map_word_load(map, buf);
13201da177e4SLinus Torvalds 
13211da177e4SLinus Torvalds 		ret = do_write_oneword(map, &cfi->chips[chipnum],
13221da177e4SLinus Torvalds 				       ofs, datum);
13231da177e4SLinus Torvalds 		if (ret)
13241da177e4SLinus Torvalds 			return ret;
13251da177e4SLinus Torvalds 
13261da177e4SLinus Torvalds 		ofs += map_bankwidth(map);
13271da177e4SLinus Torvalds 		buf += map_bankwidth(map);
13281da177e4SLinus Torvalds 		(*retlen) += map_bankwidth(map);
13291da177e4SLinus Torvalds 		len -= map_bankwidth(map);
13301da177e4SLinus Torvalds 
13311da177e4SLinus Torvalds 		if (ofs >> cfi->chipshift) {
13321da177e4SLinus Torvalds 			chipnum ++;
13331da177e4SLinus Torvalds 			ofs = 0;
13341da177e4SLinus Torvalds 			if (chipnum == cfi->numchips)
13351da177e4SLinus Torvalds 				return 0;
13361da177e4SLinus Torvalds 			chipstart = cfi->chips[chipnum].start;
13371da177e4SLinus Torvalds 		}
13381da177e4SLinus Torvalds 	}
13391da177e4SLinus Torvalds 
13401da177e4SLinus Torvalds 	/* Write the trailing bytes if any */
13411da177e4SLinus Torvalds 	if (len & (map_bankwidth(map)-1)) {
13421da177e4SLinus Torvalds 		map_word tmp_buf;
13431da177e4SLinus Torvalds 
13441da177e4SLinus Torvalds  retry1:
1345c4e77376SStefani Seibold 		mutex_lock(&cfi->chips[chipnum].mutex);
13461da177e4SLinus Torvalds 
13471da177e4SLinus Torvalds 		if (cfi->chips[chipnum].state != FL_READY) {
13481da177e4SLinus Torvalds 			set_current_state(TASK_UNINTERRUPTIBLE);
13491da177e4SLinus Torvalds 			add_wait_queue(&cfi->chips[chipnum].wq, &wait);
13501da177e4SLinus Torvalds 
1351c4e77376SStefani Seibold 			mutex_unlock(&cfi->chips[chipnum].mutex);
13521da177e4SLinus Torvalds 
13531da177e4SLinus Torvalds 			schedule();
13541da177e4SLinus Torvalds 			remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
13551da177e4SLinus Torvalds 			goto retry1;
13561da177e4SLinus Torvalds 		}
13571da177e4SLinus Torvalds 
13581da177e4SLinus Torvalds 		tmp_buf = map_read(map, ofs + chipstart);
13591da177e4SLinus Torvalds 
1360c4e77376SStefani Seibold 		mutex_unlock(&cfi->chips[chipnum].mutex);
13611da177e4SLinus Torvalds 
13621da177e4SLinus Torvalds 		tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);
13631da177e4SLinus Torvalds 
13641da177e4SLinus Torvalds 		ret = do_write_oneword(map, &cfi->chips[chipnum],
13651da177e4SLinus Torvalds 				ofs, tmp_buf);
13661da177e4SLinus Torvalds 		if (ret)
13671da177e4SLinus Torvalds 			return ret;
13681da177e4SLinus Torvalds 
13691da177e4SLinus Torvalds 		(*retlen) += len;
13701da177e4SLinus Torvalds 	}
13711da177e4SLinus Torvalds 
13721da177e4SLinus Torvalds 	return 0;
13731da177e4SLinus Torvalds }
13741da177e4SLinus Torvalds 
13751da177e4SLinus Torvalds 
13761da177e4SLinus Torvalds /*
13771da177e4SLinus Torvalds  * FIXME: interleaved mode not tested, and probably not supported!
13781da177e4SLinus Torvalds  */
137902b15e34STodd Poynor static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
138002b15e34STodd Poynor 				    unsigned long adr, const u_char *buf,
138102b15e34STodd Poynor 				    int len)
13821da177e4SLinus Torvalds {
13831da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
13841da177e4SLinus Torvalds 	unsigned long timeo = jiffies + HZ;
13851da177e4SLinus Torvalds 	/* see comments in do_write_oneword() regarding uWriteTimeo. */
13861da177e4SLinus Torvalds 	unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
13871da177e4SLinus Torvalds 	int ret = -EIO;
13881da177e4SLinus Torvalds 	unsigned long cmd_adr;
13891da177e4SLinus Torvalds 	int z, words;
13901da177e4SLinus Torvalds 	map_word datum;
13911da177e4SLinus Torvalds 
13921da177e4SLinus Torvalds 	adr += chip->start;
13931da177e4SLinus Torvalds 	cmd_adr = adr;
13941da177e4SLinus Torvalds 
1395c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);
13961da177e4SLinus Torvalds 	ret = get_chip(map, chip, adr, FL_WRITING);
13971da177e4SLinus Torvalds 	if (ret) {
1398c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
13991da177e4SLinus Torvalds 		return ret;
14001da177e4SLinus Torvalds 	}
14011da177e4SLinus Torvalds 
14021da177e4SLinus Torvalds 	datum = map_word_load(map, buf);
14031da177e4SLinus Torvalds 
1404289c0522SBrian Norris 	pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
14051da177e4SLinus Torvalds 	       __func__, adr, datum.x[0] );
14061da177e4SLinus Torvalds 
140702b15e34STodd Poynor 	XIP_INVAL_CACHED_RANGE(map, adr, len);
14081da177e4SLinus Torvalds 	ENABLE_VPP(map);
140902b15e34STodd Poynor 	xip_disable(map, chip, cmd_adr);
141002b15e34STodd Poynor 
14111da177e4SLinus Torvalds 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
14121da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
14131da177e4SLinus Torvalds 
14141da177e4SLinus Torvalds 	/* Write Buffer Load */
14151da177e4SLinus Torvalds 	map_write(map, CMD(0x25), cmd_adr);
14161da177e4SLinus Torvalds 
14171da177e4SLinus Torvalds 	chip->state = FL_WRITING_TO_BUFFER;
14181da177e4SLinus Torvalds 
14191da177e4SLinus Torvalds 	/* Write length of data to come */
14201da177e4SLinus Torvalds 	words = len / map_bankwidth(map);
14211da177e4SLinus Torvalds 	map_write(map, CMD(words - 1), cmd_adr);
14221da177e4SLinus Torvalds 	/* Write data */
14231da177e4SLinus Torvalds 	z = 0;
14241da177e4SLinus Torvalds 	while(z < words * map_bankwidth(map)) {
14251da177e4SLinus Torvalds 		datum = map_word_load(map, buf);
14261da177e4SLinus Torvalds 		map_write(map, datum, adr + z);
14271da177e4SLinus Torvalds 
14281da177e4SLinus Torvalds 		z += map_bankwidth(map);
14291da177e4SLinus Torvalds 		buf += map_bankwidth(map);
14301da177e4SLinus Torvalds 	}
14311da177e4SLinus Torvalds 	z -= map_bankwidth(map);
14321da177e4SLinus Torvalds 
14331da177e4SLinus Torvalds 	adr += z;
14341da177e4SLinus Torvalds 
14351da177e4SLinus Torvalds 	/* Write Buffer Program Confirm: GO GO GO */
14361da177e4SLinus Torvalds 	map_write(map, CMD(0x29), cmd_adr);
14371da177e4SLinus Torvalds 	chip->state = FL_WRITING;
14381da177e4SLinus Torvalds 
143902b15e34STodd Poynor 	INVALIDATE_CACHE_UDELAY(map, chip,
144002b15e34STodd Poynor 				adr, map_bankwidth(map),
144102b15e34STodd Poynor 				chip->word_write_time);
14421da177e4SLinus Torvalds 
14431da177e4SLinus Torvalds 	timeo = jiffies + uWriteTimeout;
14441da177e4SLinus Torvalds 
14451da177e4SLinus Torvalds 	for (;;) {
14461da177e4SLinus Torvalds 		if (chip->state != FL_WRITING) {
14471da177e4SLinus Torvalds 			/* Someone's suspended the write. Sleep */
14481da177e4SLinus Torvalds 			DECLARE_WAITQUEUE(wait, current);
14491da177e4SLinus Torvalds 
14501da177e4SLinus Torvalds 			set_current_state(TASK_UNINTERRUPTIBLE);
14511da177e4SLinus Torvalds 			add_wait_queue(&chip->wq, &wait);
1452c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
14531da177e4SLinus Torvalds 			schedule();
14541da177e4SLinus Torvalds 			remove_wait_queue(&chip->wq, &wait);
14551da177e4SLinus Torvalds 			timeo = jiffies + (HZ / 2); /* FIXME */
1456c4e77376SStefani Seibold 			mutex_lock(&chip->mutex);
14571da177e4SLinus Torvalds 			continue;
14581da177e4SLinus Torvalds 		}
14591da177e4SLinus Torvalds 
1460b95f9609SKonstantin Baidarov 		if (time_after(jiffies, timeo) && !chip_ready(map, adr))
1461b95f9609SKonstantin Baidarov 			break;
1462b95f9609SKonstantin Baidarov 
146302b15e34STodd Poynor 		if (chip_ready(map, adr)) {
146402b15e34STodd Poynor 			xip_enable(map, chip, adr);
14651da177e4SLinus Torvalds 			goto op_done;
146602b15e34STodd Poynor 		}
14671da177e4SLinus Torvalds 
14681da177e4SLinus Torvalds 		/* Latency issues. Drop the lock, wait a while and retry */
146902b15e34STodd Poynor 		UDELAY(map, chip, adr, 1);
14701da177e4SLinus Torvalds 	}
14711da177e4SLinus Torvalds 
14721da177e4SLinus Torvalds 	/* reset on all failures. */
14731da177e4SLinus Torvalds 	map_write( map, CMD(0xF0), chip->start );
147402b15e34STodd Poynor 	xip_enable(map, chip, adr);
14751da177e4SLinus Torvalds 	/* FIXME - should have reset delay before continuing */
14761da177e4SLinus Torvalds 
147702b15e34STodd Poynor 	printk(KERN_WARNING "MTD %s(): software timeout\n",
147802b15e34STodd Poynor 	       __func__ );
147902b15e34STodd Poynor 
14801da177e4SLinus Torvalds 	ret = -EIO;
14811da177e4SLinus Torvalds  op_done:
14821da177e4SLinus Torvalds 	chip->state = FL_READY;
14831da177e4SLinus Torvalds 	put_chip(map, chip, adr);
1484c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);
14851da177e4SLinus Torvalds 
14861da177e4SLinus Torvalds 	return ret;
14871da177e4SLinus Torvalds }
14881da177e4SLinus Torvalds 
14891da177e4SLinus Torvalds 
14901da177e4SLinus Torvalds static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
14911da177e4SLinus Torvalds 				    size_t *retlen, const u_char *buf)
14921da177e4SLinus Torvalds {
14931da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
14941da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
14951da177e4SLinus Torvalds 	int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
14961da177e4SLinus Torvalds 	int ret = 0;
14971da177e4SLinus Torvalds 	int chipnum;
14981da177e4SLinus Torvalds 	unsigned long ofs;
14991da177e4SLinus Torvalds 
15001da177e4SLinus Torvalds 	*retlen = 0;
15011da177e4SLinus Torvalds 	if (!len)
15021da177e4SLinus Torvalds 		return 0;
15031da177e4SLinus Torvalds 
15041da177e4SLinus Torvalds 	chipnum = to >> cfi->chipshift;
15051da177e4SLinus Torvalds 	ofs = to  - (chipnum << cfi->chipshift);
15061da177e4SLinus Torvalds 
15071da177e4SLinus Torvalds 	/* If it's not bus-aligned, do the first word write */
15081da177e4SLinus Torvalds 	if (ofs & (map_bankwidth(map)-1)) {
15091da177e4SLinus Torvalds 		size_t local_len = (-ofs)&(map_bankwidth(map)-1);
15101da177e4SLinus Torvalds 		if (local_len > len)
15111da177e4SLinus Torvalds 			local_len = len;
15121da177e4SLinus Torvalds 		ret = cfi_amdstd_write_words(mtd, ofs + (chipnum<<cfi->chipshift),
15131da177e4SLinus Torvalds 					     local_len, retlen, buf);
15141da177e4SLinus Torvalds 		if (ret)
15151da177e4SLinus Torvalds 			return ret;
15161da177e4SLinus Torvalds 		ofs += local_len;
15171da177e4SLinus Torvalds 		buf += local_len;
15181da177e4SLinus Torvalds 		len -= local_len;
15191da177e4SLinus Torvalds 
15201da177e4SLinus Torvalds 		if (ofs >> cfi->chipshift) {
15211da177e4SLinus Torvalds 			chipnum ++;
15221da177e4SLinus Torvalds 			ofs = 0;
15231da177e4SLinus Torvalds 			if (chipnum == cfi->numchips)
15241da177e4SLinus Torvalds 				return 0;
15251da177e4SLinus Torvalds 		}
15261da177e4SLinus Torvalds 	}
15271da177e4SLinus Torvalds 
15281da177e4SLinus Torvalds 	/* Write buffer is worth it only if more than one word to write... */
15291da177e4SLinus Torvalds 	while (len >= map_bankwidth(map) * 2) {
15301da177e4SLinus Torvalds 		/* We must not cross write block boundaries */
15311da177e4SLinus Torvalds 		int size = wbufsize - (ofs & (wbufsize-1));
15321da177e4SLinus Torvalds 
15331da177e4SLinus Torvalds 		if (size > len)
15341da177e4SLinus Torvalds 			size = len;
15351da177e4SLinus Torvalds 		if (size % map_bankwidth(map))
15361da177e4SLinus Torvalds 			size -= size % map_bankwidth(map);
15371da177e4SLinus Torvalds 
15381da177e4SLinus Torvalds 		ret = do_write_buffer(map, &cfi->chips[chipnum],
15391da177e4SLinus Torvalds 				      ofs, buf, size);
15401da177e4SLinus Torvalds 		if (ret)
15411da177e4SLinus Torvalds 			return ret;
15421da177e4SLinus Torvalds 
15431da177e4SLinus Torvalds 		ofs += size;
15441da177e4SLinus Torvalds 		buf += size;
15451da177e4SLinus Torvalds 		(*retlen) += size;
15461da177e4SLinus Torvalds 		len -= size;
15471da177e4SLinus Torvalds 
15481da177e4SLinus Torvalds 		if (ofs >> cfi->chipshift) {
15491da177e4SLinus Torvalds 			chipnum ++;
15501da177e4SLinus Torvalds 			ofs = 0;
15511da177e4SLinus Torvalds 			if (chipnum == cfi->numchips)
15521da177e4SLinus Torvalds 				return 0;
15531da177e4SLinus Torvalds 		}
15541da177e4SLinus Torvalds 	}
15551da177e4SLinus Torvalds 
15561da177e4SLinus Torvalds 	if (len) {
15571da177e4SLinus Torvalds 		size_t retlen_dregs = 0;
15581da177e4SLinus Torvalds 
15591da177e4SLinus Torvalds 		ret = cfi_amdstd_write_words(mtd, ofs + (chipnum<<cfi->chipshift),
15601da177e4SLinus Torvalds 					     len, &retlen_dregs, buf);
15611da177e4SLinus Torvalds 
15621da177e4SLinus Torvalds 		*retlen += retlen_dregs;
15631da177e4SLinus Torvalds 		return ret;
15641da177e4SLinus Torvalds 	}
15651da177e4SLinus Torvalds 
15661da177e4SLinus Torvalds 	return 0;
15671da177e4SLinus Torvalds }
15681da177e4SLinus Torvalds 
156930ec5a2cSIra W. Snyder /*
157030ec5a2cSIra W. Snyder  * Wait for the flash chip to become ready to write data
157130ec5a2cSIra W. Snyder  *
157230ec5a2cSIra W. Snyder  * This is only called during the panic_write() path. When panic_write()
157330ec5a2cSIra W. Snyder  * is called, the kernel is in the process of a panic, and will soon be
157430ec5a2cSIra W. Snyder  * dead. Therefore we don't take any locks, and attempt to get access
157530ec5a2cSIra W. Snyder  * to the chip as soon as possible.
157630ec5a2cSIra W. Snyder  */
157730ec5a2cSIra W. Snyder static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip,
157830ec5a2cSIra W. Snyder 				 unsigned long adr)
157930ec5a2cSIra W. Snyder {
158030ec5a2cSIra W. Snyder 	struct cfi_private *cfi = map->fldrv_priv;
158130ec5a2cSIra W. Snyder 	int retries = 10;
158230ec5a2cSIra W. Snyder 	int i;
158330ec5a2cSIra W. Snyder 
158430ec5a2cSIra W. Snyder 	/*
158530ec5a2cSIra W. Snyder 	 * If the driver thinks the chip is idle, and no toggle bits
158630ec5a2cSIra W. Snyder 	 * are changing, then the chip is actually idle for sure.
158730ec5a2cSIra W. Snyder 	 */
158830ec5a2cSIra W. Snyder 	if (chip->state == FL_READY && chip_ready(map, adr))
158930ec5a2cSIra W. Snyder 		return 0;
159030ec5a2cSIra W. Snyder 
159130ec5a2cSIra W. Snyder 	/*
159230ec5a2cSIra W. Snyder 	 * Try several times to reset the chip and then wait for it
159330ec5a2cSIra W. Snyder 	 * to become idle. The upper limit of a few milliseconds of
159430ec5a2cSIra W. Snyder 	 * delay isn't a big problem: the kernel is dying anyway. It
159530ec5a2cSIra W. Snyder 	 * is more important to save the messages.
159630ec5a2cSIra W. Snyder 	 */
159730ec5a2cSIra W. Snyder 	while (retries > 0) {
159830ec5a2cSIra W. Snyder 		const unsigned long timeo = (HZ / 1000) + 1;
159930ec5a2cSIra W. Snyder 
160030ec5a2cSIra W. Snyder 		/* send the reset command */
160130ec5a2cSIra W. Snyder 		map_write(map, CMD(0xF0), chip->start);
160230ec5a2cSIra W. Snyder 
160330ec5a2cSIra W. Snyder 		/* wait for the chip to become ready */
160430ec5a2cSIra W. Snyder 		for (i = 0; i < jiffies_to_usecs(timeo); i++) {
160530ec5a2cSIra W. Snyder 			if (chip_ready(map, adr))
160630ec5a2cSIra W. Snyder 				return 0;
160730ec5a2cSIra W. Snyder 
160830ec5a2cSIra W. Snyder 			udelay(1);
160930ec5a2cSIra W. Snyder 		}
161030ec5a2cSIra W. Snyder 	}
161130ec5a2cSIra W. Snyder 
161230ec5a2cSIra W. Snyder 	/* the chip never became ready */
161330ec5a2cSIra W. Snyder 	return -EBUSY;
161430ec5a2cSIra W. Snyder }
161530ec5a2cSIra W. Snyder 
161630ec5a2cSIra W. Snyder /*
161730ec5a2cSIra W. Snyder  * Write out one word of data to a single flash chip during a kernel panic
161830ec5a2cSIra W. Snyder  *
161930ec5a2cSIra W. Snyder  * This is only called during the panic_write() path. When panic_write()
162030ec5a2cSIra W. Snyder  * is called, the kernel is in the process of a panic, and will soon be
162130ec5a2cSIra W. Snyder  * dead. Therefore we don't take any locks, and attempt to get access
162230ec5a2cSIra W. Snyder  * to the chip as soon as possible.
162330ec5a2cSIra W. Snyder  *
162430ec5a2cSIra W. Snyder  * The implementation of this routine is intentionally similar to
162530ec5a2cSIra W. Snyder  * do_write_oneword(), in order to ease code maintenance.
162630ec5a2cSIra W. Snyder  */
162730ec5a2cSIra W. Snyder static int do_panic_write_oneword(struct map_info *map, struct flchip *chip,
162830ec5a2cSIra W. Snyder 				  unsigned long adr, map_word datum)
162930ec5a2cSIra W. Snyder {
163030ec5a2cSIra W. Snyder 	const unsigned long uWriteTimeout = (HZ / 1000) + 1;
163130ec5a2cSIra W. Snyder 	struct cfi_private *cfi = map->fldrv_priv;
163230ec5a2cSIra W. Snyder 	int retry_cnt = 0;
163330ec5a2cSIra W. Snyder 	map_word oldd;
163430ec5a2cSIra W. Snyder 	int ret = 0;
163530ec5a2cSIra W. Snyder 	int i;
163630ec5a2cSIra W. Snyder 
163730ec5a2cSIra W. Snyder 	adr += chip->start;
163830ec5a2cSIra W. Snyder 
163930ec5a2cSIra W. Snyder 	ret = cfi_amdstd_panic_wait(map, chip, adr);
164030ec5a2cSIra W. Snyder 	if (ret)
164130ec5a2cSIra W. Snyder 		return ret;
164230ec5a2cSIra W. Snyder 
164330ec5a2cSIra W. Snyder 	pr_debug("MTD %s(): PANIC WRITE 0x%.8lx(0x%.8lx)\n",
164430ec5a2cSIra W. Snyder 			__func__, adr, datum.x[0]);
164530ec5a2cSIra W. Snyder 
164630ec5a2cSIra W. Snyder 	/*
164730ec5a2cSIra W. Snyder 	 * Check for a NOP for the case when the datum to write is already
164830ec5a2cSIra W. Snyder 	 * present - it saves time and works around buggy chips that corrupt
164930ec5a2cSIra W. Snyder 	 * data at other locations when 0xff is written to a location that
165030ec5a2cSIra W. Snyder 	 * already contains 0xff.
165130ec5a2cSIra W. Snyder 	 */
165230ec5a2cSIra W. Snyder 	oldd = map_read(map, adr);
165330ec5a2cSIra W. Snyder 	if (map_word_equal(map, oldd, datum)) {
165430ec5a2cSIra W. Snyder 		pr_debug("MTD %s(): NOP\n", __func__);
165530ec5a2cSIra W. Snyder 		goto op_done;
165630ec5a2cSIra W. Snyder 	}
165730ec5a2cSIra W. Snyder 
165830ec5a2cSIra W. Snyder 	ENABLE_VPP(map);
165930ec5a2cSIra W. Snyder 
166030ec5a2cSIra W. Snyder retry:
166130ec5a2cSIra W. Snyder 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
166230ec5a2cSIra W. Snyder 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
166330ec5a2cSIra W. Snyder 	cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
166430ec5a2cSIra W. Snyder 	map_write(map, datum, adr);
166530ec5a2cSIra W. Snyder 
166630ec5a2cSIra W. Snyder 	for (i = 0; i < jiffies_to_usecs(uWriteTimeout); i++) {
166730ec5a2cSIra W. Snyder 		if (chip_ready(map, adr))
166830ec5a2cSIra W. Snyder 			break;
166930ec5a2cSIra W. Snyder 
167030ec5a2cSIra W. Snyder 		udelay(1);
167130ec5a2cSIra W. Snyder 	}
167230ec5a2cSIra W. Snyder 
167330ec5a2cSIra W. Snyder 	if (!chip_good(map, adr, datum)) {
167430ec5a2cSIra W. Snyder 		/* reset on all failures. */
167530ec5a2cSIra W. Snyder 		map_write(map, CMD(0xF0), chip->start);
167630ec5a2cSIra W. Snyder 		/* FIXME - should have reset delay before continuing */
167730ec5a2cSIra W. Snyder 
167830ec5a2cSIra W. Snyder 		if (++retry_cnt <= MAX_WORD_RETRIES)
167930ec5a2cSIra W. Snyder 			goto retry;
168030ec5a2cSIra W. Snyder 
168130ec5a2cSIra W. Snyder 		ret = -EIO;
168230ec5a2cSIra W. Snyder 	}
168330ec5a2cSIra W. Snyder 
168430ec5a2cSIra W. Snyder op_done:
168530ec5a2cSIra W. Snyder 	DISABLE_VPP(map);
168630ec5a2cSIra W. Snyder 	return ret;
168730ec5a2cSIra W. Snyder }
168830ec5a2cSIra W. Snyder 
168930ec5a2cSIra W. Snyder /*
169030ec5a2cSIra W. Snyder  * Write out some data during a kernel panic
169130ec5a2cSIra W. Snyder  *
169230ec5a2cSIra W. Snyder  * This is used by the mtdoops driver to save the dying messages from a
169330ec5a2cSIra W. Snyder  * kernel which has panic'd.
169430ec5a2cSIra W. Snyder  *
169530ec5a2cSIra W. Snyder  * This routine ignores all of the locking used throughout the rest of the
169630ec5a2cSIra W. Snyder  * driver, in order to ensure that the data gets written out no matter what
169730ec5a2cSIra W. Snyder  * state this driver (and the flash chip itself) was in when the kernel crashed.
169830ec5a2cSIra W. Snyder  *
169930ec5a2cSIra W. Snyder  * The implementation of this routine is intentionally similar to
170030ec5a2cSIra W. Snyder  * cfi_amdstd_write_words(), in order to ease code maintenance.
170130ec5a2cSIra W. Snyder  */
170230ec5a2cSIra W. Snyder static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
170330ec5a2cSIra W. Snyder 				  size_t *retlen, const u_char *buf)
170430ec5a2cSIra W. Snyder {
170530ec5a2cSIra W. Snyder 	struct map_info *map = mtd->priv;
170630ec5a2cSIra W. Snyder 	struct cfi_private *cfi = map->fldrv_priv;
170730ec5a2cSIra W. Snyder 	unsigned long ofs, chipstart;
170830ec5a2cSIra W. Snyder 	int ret = 0;
170930ec5a2cSIra W. Snyder 	int chipnum;
171030ec5a2cSIra W. Snyder 
171130ec5a2cSIra W. Snyder 	*retlen = 0;
171230ec5a2cSIra W. Snyder 	if (!len)
171330ec5a2cSIra W. Snyder 		return 0;
171430ec5a2cSIra W. Snyder 
171530ec5a2cSIra W. Snyder 	chipnum = to >> cfi->chipshift;
171630ec5a2cSIra W. Snyder 	ofs = to - (chipnum << cfi->chipshift);
171730ec5a2cSIra W. Snyder 	chipstart = cfi->chips[chipnum].start;
171830ec5a2cSIra W. Snyder 
171930ec5a2cSIra W. Snyder 	/* If it's not bus aligned, do the first byte write */
172030ec5a2cSIra W. Snyder 	if (ofs & (map_bankwidth(map) - 1)) {
172130ec5a2cSIra W. Snyder 		unsigned long bus_ofs = ofs & ~(map_bankwidth(map) - 1);
172230ec5a2cSIra W. Snyder 		int i = ofs - bus_ofs;
172330ec5a2cSIra W. Snyder 		int n = 0;
172430ec5a2cSIra W. Snyder 		map_word tmp_buf;
172530ec5a2cSIra W. Snyder 
172630ec5a2cSIra W. Snyder 		ret = cfi_amdstd_panic_wait(map, &cfi->chips[chipnum], bus_ofs);
172730ec5a2cSIra W. Snyder 		if (ret)
172830ec5a2cSIra W. Snyder 			return ret;
172930ec5a2cSIra W. Snyder 
173030ec5a2cSIra W. Snyder 		/* Load 'tmp_buf' with old contents of flash */
173130ec5a2cSIra W. Snyder 		tmp_buf = map_read(map, bus_ofs + chipstart);
173230ec5a2cSIra W. Snyder 
173330ec5a2cSIra W. Snyder 		/* Number of bytes to copy from buffer */
173430ec5a2cSIra W. Snyder 		n = min_t(int, len, map_bankwidth(map) - i);
173530ec5a2cSIra W. Snyder 
173630ec5a2cSIra W. Snyder 		tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n);
173730ec5a2cSIra W. Snyder 
173830ec5a2cSIra W. Snyder 		ret = do_panic_write_oneword(map, &cfi->chips[chipnum],
173930ec5a2cSIra W. Snyder 					     bus_ofs, tmp_buf);
174030ec5a2cSIra W. Snyder 		if (ret)
174130ec5a2cSIra W. Snyder 			return ret;
174230ec5a2cSIra W. Snyder 
174330ec5a2cSIra W. Snyder 		ofs += n;
174430ec5a2cSIra W. Snyder 		buf += n;
174530ec5a2cSIra W. Snyder 		(*retlen) += n;
174630ec5a2cSIra W. Snyder 		len -= n;
174730ec5a2cSIra W. Snyder 
174830ec5a2cSIra W. Snyder 		if (ofs >> cfi->chipshift) {
174930ec5a2cSIra W. Snyder 			chipnum++;
175030ec5a2cSIra W. Snyder 			ofs = 0;
175130ec5a2cSIra W. Snyder 			if (chipnum == cfi->numchips)
175230ec5a2cSIra W. Snyder 				return 0;
175330ec5a2cSIra W. Snyder 		}
175430ec5a2cSIra W. Snyder 	}
175530ec5a2cSIra W. Snyder 
175630ec5a2cSIra W. Snyder 	/* We are now aligned, write as much as possible */
175730ec5a2cSIra W. Snyder 	while (len >= map_bankwidth(map)) {
175830ec5a2cSIra W. Snyder 		map_word datum;
175930ec5a2cSIra W. Snyder 
176030ec5a2cSIra W. Snyder 		datum = map_word_load(map, buf);
176130ec5a2cSIra W. Snyder 
176230ec5a2cSIra W. Snyder 		ret = do_panic_write_oneword(map, &cfi->chips[chipnum],
176330ec5a2cSIra W. Snyder 					     ofs, datum);
176430ec5a2cSIra W. Snyder 		if (ret)
176530ec5a2cSIra W. Snyder 			return ret;
176630ec5a2cSIra W. Snyder 
176730ec5a2cSIra W. Snyder 		ofs += map_bankwidth(map);
176830ec5a2cSIra W. Snyder 		buf += map_bankwidth(map);
176930ec5a2cSIra W. Snyder 		(*retlen) += map_bankwidth(map);
177030ec5a2cSIra W. Snyder 		len -= map_bankwidth(map);
177130ec5a2cSIra W. Snyder 
177230ec5a2cSIra W. Snyder 		if (ofs >> cfi->chipshift) {
177330ec5a2cSIra W. Snyder 			chipnum++;
177430ec5a2cSIra W. Snyder 			ofs = 0;
177530ec5a2cSIra W. Snyder 			if (chipnum == cfi->numchips)
177630ec5a2cSIra W. Snyder 				return 0;
177730ec5a2cSIra W. Snyder 
177830ec5a2cSIra W. Snyder 			chipstart = cfi->chips[chipnum].start;
177930ec5a2cSIra W. Snyder 		}
178030ec5a2cSIra W. Snyder 	}
178130ec5a2cSIra W. Snyder 
178230ec5a2cSIra W. Snyder 	/* Write the trailing bytes if any */
178330ec5a2cSIra W. Snyder 	if (len & (map_bankwidth(map) - 1)) {
178430ec5a2cSIra W. Snyder 		map_word tmp_buf;
178530ec5a2cSIra W. Snyder 
178630ec5a2cSIra W. Snyder 		ret = cfi_amdstd_panic_wait(map, &cfi->chips[chipnum], ofs);
178730ec5a2cSIra W. Snyder 		if (ret)
178830ec5a2cSIra W. Snyder 			return ret;
178930ec5a2cSIra W. Snyder 
179030ec5a2cSIra W. Snyder 		tmp_buf = map_read(map, ofs + chipstart);
179130ec5a2cSIra W. Snyder 
179230ec5a2cSIra W. Snyder 		tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);
179330ec5a2cSIra W. Snyder 
179430ec5a2cSIra W. Snyder 		ret = do_panic_write_oneword(map, &cfi->chips[chipnum],
179530ec5a2cSIra W. Snyder 					     ofs, tmp_buf);
179630ec5a2cSIra W. Snyder 		if (ret)
179730ec5a2cSIra W. Snyder 			return ret;
179830ec5a2cSIra W. Snyder 
179930ec5a2cSIra W. Snyder 		(*retlen) += len;
180030ec5a2cSIra W. Snyder 	}
180130ec5a2cSIra W. Snyder 
180230ec5a2cSIra W. Snyder 	return 0;
180330ec5a2cSIra W. Snyder }
180430ec5a2cSIra W. Snyder 
18051da177e4SLinus Torvalds 
18061da177e4SLinus Torvalds /*
18071da177e4SLinus Torvalds  * Handle devices with one erase region, that only implement
18081da177e4SLinus Torvalds  * the chip erase command.
18091da177e4SLinus Torvalds  */
181002b15e34STodd Poynor static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
18111da177e4SLinus Torvalds {
18121da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
18131da177e4SLinus Torvalds 	unsigned long timeo = jiffies + HZ;
18141da177e4SLinus Torvalds 	unsigned long int adr;
18151da177e4SLinus Torvalds 	DECLARE_WAITQUEUE(wait, current);
18161da177e4SLinus Torvalds 	int ret = 0;
18171da177e4SLinus Torvalds 
18181da177e4SLinus Torvalds 	adr = cfi->addr_unlock1;
18191da177e4SLinus Torvalds 
1820c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);
18211da177e4SLinus Torvalds 	ret = get_chip(map, chip, adr, FL_WRITING);
18221da177e4SLinus Torvalds 	if (ret) {
1823c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
18241da177e4SLinus Torvalds 		return ret;
18251da177e4SLinus Torvalds 	}
18261da177e4SLinus Torvalds 
1827289c0522SBrian Norris 	pr_debug("MTD %s(): ERASE 0x%.8lx\n",
18281da177e4SLinus Torvalds 	       __func__, chip->start );
18291da177e4SLinus Torvalds 
183002b15e34STodd Poynor 	XIP_INVAL_CACHED_RANGE(map, adr, map->size);
18311da177e4SLinus Torvalds 	ENABLE_VPP(map);
183202b15e34STodd Poynor 	xip_disable(map, chip, adr);
183302b15e34STodd Poynor 
18341da177e4SLinus Torvalds 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
18351da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
18361da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
18371da177e4SLinus Torvalds 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
18381da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
18391da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
18401da177e4SLinus Torvalds 
18411da177e4SLinus Torvalds 	chip->state = FL_ERASING;
18421da177e4SLinus Torvalds 	chip->erase_suspended = 0;
18431da177e4SLinus Torvalds 	chip->in_progress_block_addr = adr;
18441da177e4SLinus Torvalds 
184502b15e34STodd Poynor 	INVALIDATE_CACHE_UDELAY(map, chip,
184602b15e34STodd Poynor 				adr, map->size,
184702b15e34STodd Poynor 				chip->erase_time*500);
18481da177e4SLinus Torvalds 
18491da177e4SLinus Torvalds 	timeo = jiffies + (HZ*20);
18501da177e4SLinus Torvalds 
18511da177e4SLinus Torvalds 	for (;;) {
18521da177e4SLinus Torvalds 		if (chip->state != FL_ERASING) {
18531da177e4SLinus Torvalds 			/* Someone's suspended the erase. Sleep */
18541da177e4SLinus Torvalds 			set_current_state(TASK_UNINTERRUPTIBLE);
18551da177e4SLinus Torvalds 			add_wait_queue(&chip->wq, &wait);
1856c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
18571da177e4SLinus Torvalds 			schedule();
18581da177e4SLinus Torvalds 			remove_wait_queue(&chip->wq, &wait);
1859c4e77376SStefani Seibold 			mutex_lock(&chip->mutex);
18601da177e4SLinus Torvalds 			continue;
18611da177e4SLinus Torvalds 		}
18621da177e4SLinus Torvalds 		if (chip->erase_suspended) {
18631da177e4SLinus Torvalds 			/* This erase was suspended and resumed.
18641da177e4SLinus Torvalds 			   Adjust the timeout */
18651da177e4SLinus Torvalds 			timeo = jiffies + (HZ*20); /* FIXME */
18661da177e4SLinus Torvalds 			chip->erase_suspended = 0;
18671da177e4SLinus Torvalds 		}
18681da177e4SLinus Torvalds 
18691da177e4SLinus Torvalds 		if (chip_ready(map, adr))
18701da177e4SLinus Torvalds 			break;
18711da177e4SLinus Torvalds 
1872fb4a90bfSEric W. Biedermann 		if (time_after(jiffies, timeo)) {
1873fb4a90bfSEric W. Biedermann 			printk(KERN_WARNING "MTD %s(): software timeout\n",
1874fb4a90bfSEric W. Biedermann 				__func__ );
1875fb4a90bfSEric W. Biedermann 			break;
1876fb4a90bfSEric W. Biedermann 		}
1877fb4a90bfSEric W. Biedermann 
18781da177e4SLinus Torvalds 		/* Latency issues. Drop the lock, wait a while and retry */
187902b15e34STodd Poynor 		UDELAY(map, chip, adr, 1000000/HZ);
18801da177e4SLinus Torvalds 	}
1881fb4a90bfSEric W. Biedermann 	/* Did we succeed? */
1882fb4a90bfSEric W. Biedermann 	if (!chip_good(map, adr, map_word_ff(map))) {
18831da177e4SLinus Torvalds 		/* reset on all failures. */
18841da177e4SLinus Torvalds 		map_write( map, CMD(0xF0), chip->start );
18851da177e4SLinus Torvalds 		/* FIXME - should have reset delay before continuing */
18861da177e4SLinus Torvalds 
18871da177e4SLinus Torvalds 		ret = -EIO;
1888fb4a90bfSEric W. Biedermann 	}
1889fb4a90bfSEric W. Biedermann 
18901da177e4SLinus Torvalds 	chip->state = FL_READY;
189102b15e34STodd Poynor 	xip_enable(map, chip, adr);
18921da177e4SLinus Torvalds 	put_chip(map, chip, adr);
1893c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);
18941da177e4SLinus Torvalds 
18951da177e4SLinus Torvalds 	return ret;
18961da177e4SLinus Torvalds }
18971da177e4SLinus Torvalds 
18981da177e4SLinus Torvalds 
189902b15e34STodd Poynor static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk)
19001da177e4SLinus Torvalds {
19011da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
19021da177e4SLinus Torvalds 	unsigned long timeo = jiffies + HZ;
19031da177e4SLinus Torvalds 	DECLARE_WAITQUEUE(wait, current);
19041da177e4SLinus Torvalds 	int ret = 0;
19051da177e4SLinus Torvalds 
19061da177e4SLinus Torvalds 	adr += chip->start;
19071da177e4SLinus Torvalds 
1908c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);
19091da177e4SLinus Torvalds 	ret = get_chip(map, chip, adr, FL_ERASING);
19101da177e4SLinus Torvalds 	if (ret) {
1911c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
19121da177e4SLinus Torvalds 		return ret;
19131da177e4SLinus Torvalds 	}
19141da177e4SLinus Torvalds 
1915289c0522SBrian Norris 	pr_debug("MTD %s(): ERASE 0x%.8lx\n",
19161da177e4SLinus Torvalds 	       __func__, adr );
19171da177e4SLinus Torvalds 
191802b15e34STodd Poynor 	XIP_INVAL_CACHED_RANGE(map, adr, len);
19191da177e4SLinus Torvalds 	ENABLE_VPP(map);
192002b15e34STodd Poynor 	xip_disable(map, chip, adr);
192102b15e34STodd Poynor 
19221da177e4SLinus Torvalds 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
19231da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
19241da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
19251da177e4SLinus Torvalds 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
19261da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
192708968041SGuillaume LECERF 	map_write(map, cfi->sector_erase_cmd, adr);
19281da177e4SLinus Torvalds 
19291da177e4SLinus Torvalds 	chip->state = FL_ERASING;
19301da177e4SLinus Torvalds 	chip->erase_suspended = 0;
19311da177e4SLinus Torvalds 	chip->in_progress_block_addr = adr;
19321da177e4SLinus Torvalds 
193302b15e34STodd Poynor 	INVALIDATE_CACHE_UDELAY(map, chip,
193402b15e34STodd Poynor 				adr, len,
193502b15e34STodd Poynor 				chip->erase_time*500);
19361da177e4SLinus Torvalds 
19371da177e4SLinus Torvalds 	timeo = jiffies + (HZ*20);
19381da177e4SLinus Torvalds 
19391da177e4SLinus Torvalds 	for (;;) {
19401da177e4SLinus Torvalds 		if (chip->state != FL_ERASING) {
19411da177e4SLinus Torvalds 			/* Someone's suspended the erase. Sleep */
19421da177e4SLinus Torvalds 			set_current_state(TASK_UNINTERRUPTIBLE);
19431da177e4SLinus Torvalds 			add_wait_queue(&chip->wq, &wait);
1944c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
19451da177e4SLinus Torvalds 			schedule();
19461da177e4SLinus Torvalds 			remove_wait_queue(&chip->wq, &wait);
1947c4e77376SStefani Seibold 			mutex_lock(&chip->mutex);
19481da177e4SLinus Torvalds 			continue;
19491da177e4SLinus Torvalds 		}
19501da177e4SLinus Torvalds 		if (chip->erase_suspended) {
19511da177e4SLinus Torvalds 			/* This erase was suspended and resumed.
19521da177e4SLinus Torvalds 			   Adjust the timeout */
19531da177e4SLinus Torvalds 			timeo = jiffies + (HZ*20); /* FIXME */
19541da177e4SLinus Torvalds 			chip->erase_suspended = 0;
19551da177e4SLinus Torvalds 		}
19561da177e4SLinus Torvalds 
195702b15e34STodd Poynor 		if (chip_ready(map, adr)) {
195802b15e34STodd Poynor 			xip_enable(map, chip, adr);
19591da177e4SLinus Torvalds 			break;
196002b15e34STodd Poynor 		}
19611da177e4SLinus Torvalds 
1962fb4a90bfSEric W. Biedermann 		if (time_after(jiffies, timeo)) {
196302b15e34STodd Poynor 			xip_enable(map, chip, adr);
1964fb4a90bfSEric W. Biedermann 			printk(KERN_WARNING "MTD %s(): software timeout\n",
1965fb4a90bfSEric W. Biedermann 				__func__ );
1966fb4a90bfSEric W. Biedermann 			break;
1967fb4a90bfSEric W. Biedermann 		}
1968fb4a90bfSEric W. Biedermann 
19691da177e4SLinus Torvalds 		/* Latency issues. Drop the lock, wait a while and retry */
197002b15e34STodd Poynor 		UDELAY(map, chip, adr, 1000000/HZ);
19711da177e4SLinus Torvalds 	}
1972fb4a90bfSEric W. Biedermann 	/* Did we succeed? */
197322fd9a87SThomas Gleixner 	if (!chip_good(map, adr, map_word_ff(map))) {
19741da177e4SLinus Torvalds 		/* reset on all failures. */
19751da177e4SLinus Torvalds 		map_write( map, CMD(0xF0), chip->start );
19761da177e4SLinus Torvalds 		/* FIXME - should have reset delay before continuing */
19771da177e4SLinus Torvalds 
19781da177e4SLinus Torvalds 		ret = -EIO;
1979fb4a90bfSEric W. Biedermann 	}
1980fb4a90bfSEric W. Biedermann 
19811da177e4SLinus Torvalds 	chip->state = FL_READY;
19821da177e4SLinus Torvalds 	put_chip(map, chip, adr);
1983c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);
19841da177e4SLinus Torvalds 	return ret;
19851da177e4SLinus Torvalds }
19861da177e4SLinus Torvalds 
19871da177e4SLinus Torvalds 
1988ce0f33adSBen Dooks static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
19891da177e4SLinus Torvalds {
19901da177e4SLinus Torvalds 	unsigned long ofs, len;
19911da177e4SLinus Torvalds 	int ret;
19921da177e4SLinus Torvalds 
19931da177e4SLinus Torvalds 	ofs = instr->addr;
19941da177e4SLinus Torvalds 	len = instr->len;
19951da177e4SLinus Torvalds 
19961da177e4SLinus Torvalds 	ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL);
19971da177e4SLinus Torvalds 	if (ret)
19981da177e4SLinus Torvalds 		return ret;
19991da177e4SLinus Torvalds 
20001da177e4SLinus Torvalds 	instr->state = MTD_ERASE_DONE;
20011da177e4SLinus Torvalds 	mtd_erase_callback(instr);
20021da177e4SLinus Torvalds 
20031da177e4SLinus Torvalds 	return 0;
20041da177e4SLinus Torvalds }
20051da177e4SLinus Torvalds 
20061da177e4SLinus Torvalds 
20071da177e4SLinus Torvalds static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr)
20081da177e4SLinus Torvalds {
20091da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
20101da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
20111da177e4SLinus Torvalds 	int ret = 0;
20121da177e4SLinus Torvalds 
20131da177e4SLinus Torvalds 	if (instr->addr != 0)
20141da177e4SLinus Torvalds 		return -EINVAL;
20151da177e4SLinus Torvalds 
20161da177e4SLinus Torvalds 	if (instr->len != mtd->size)
20171da177e4SLinus Torvalds 		return -EINVAL;
20181da177e4SLinus Torvalds 
20191da177e4SLinus Torvalds 	ret = do_erase_chip(map, &cfi->chips[0]);
20201da177e4SLinus Torvalds 	if (ret)
20211da177e4SLinus Torvalds 		return ret;
20221da177e4SLinus Torvalds 
20231da177e4SLinus Torvalds 	instr->state = MTD_ERASE_DONE;
20241da177e4SLinus Torvalds 	mtd_erase_callback(instr);
20251da177e4SLinus Torvalds 
20261da177e4SLinus Torvalds 	return 0;
20271da177e4SLinus Torvalds }
20281da177e4SLinus Torvalds 
20290165508cSHaavard Skinnemoen static int do_atmel_lock(struct map_info *map, struct flchip *chip,
20300165508cSHaavard Skinnemoen 			 unsigned long adr, int len, void *thunk)
20310165508cSHaavard Skinnemoen {
20320165508cSHaavard Skinnemoen 	struct cfi_private *cfi = map->fldrv_priv;
20330165508cSHaavard Skinnemoen 	int ret;
20340165508cSHaavard Skinnemoen 
2035c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);
20360165508cSHaavard Skinnemoen 	ret = get_chip(map, chip, adr + chip->start, FL_LOCKING);
20370165508cSHaavard Skinnemoen 	if (ret)
20380165508cSHaavard Skinnemoen 		goto out_unlock;
20390165508cSHaavard Skinnemoen 	chip->state = FL_LOCKING;
20400165508cSHaavard Skinnemoen 
20410a32a102SBrian Norris 	pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", __func__, adr, len);
20420165508cSHaavard Skinnemoen 
20430165508cSHaavard Skinnemoen 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
20440165508cSHaavard Skinnemoen 			 cfi->device_type, NULL);
20450165508cSHaavard Skinnemoen 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
20460165508cSHaavard Skinnemoen 			 cfi->device_type, NULL);
20470165508cSHaavard Skinnemoen 	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi,
20480165508cSHaavard Skinnemoen 			 cfi->device_type, NULL);
20490165508cSHaavard Skinnemoen 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
20500165508cSHaavard Skinnemoen 			 cfi->device_type, NULL);
20510165508cSHaavard Skinnemoen 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
20520165508cSHaavard Skinnemoen 			 cfi->device_type, NULL);
20530165508cSHaavard Skinnemoen 	map_write(map, CMD(0x40), chip->start + adr);
20540165508cSHaavard Skinnemoen 
20550165508cSHaavard Skinnemoen 	chip->state = FL_READY;
20560165508cSHaavard Skinnemoen 	put_chip(map, chip, adr + chip->start);
20570165508cSHaavard Skinnemoen 	ret = 0;
20580165508cSHaavard Skinnemoen 
20590165508cSHaavard Skinnemoen out_unlock:
2060c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);
20610165508cSHaavard Skinnemoen 	return ret;
20620165508cSHaavard Skinnemoen }
20630165508cSHaavard Skinnemoen 
20640165508cSHaavard Skinnemoen static int do_atmel_unlock(struct map_info *map, struct flchip *chip,
20650165508cSHaavard Skinnemoen 			   unsigned long adr, int len, void *thunk)
20660165508cSHaavard Skinnemoen {
20670165508cSHaavard Skinnemoen 	struct cfi_private *cfi = map->fldrv_priv;
20680165508cSHaavard Skinnemoen 	int ret;
20690165508cSHaavard Skinnemoen 
2070c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);
20710165508cSHaavard Skinnemoen 	ret = get_chip(map, chip, adr + chip->start, FL_UNLOCKING);
20720165508cSHaavard Skinnemoen 	if (ret)
20730165508cSHaavard Skinnemoen 		goto out_unlock;
20740165508cSHaavard Skinnemoen 	chip->state = FL_UNLOCKING;
20750165508cSHaavard Skinnemoen 
20760a32a102SBrian Norris 	pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", __func__, adr, len);
20770165508cSHaavard Skinnemoen 
20780165508cSHaavard Skinnemoen 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
20790165508cSHaavard Skinnemoen 			 cfi->device_type, NULL);
20800165508cSHaavard Skinnemoen 	map_write(map, CMD(0x70), adr);
20810165508cSHaavard Skinnemoen 
20820165508cSHaavard Skinnemoen 	chip->state = FL_READY;
20830165508cSHaavard Skinnemoen 	put_chip(map, chip, adr + chip->start);
20840165508cSHaavard Skinnemoen 	ret = 0;
20850165508cSHaavard Skinnemoen 
20860165508cSHaavard Skinnemoen out_unlock:
2087c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);
20880165508cSHaavard Skinnemoen 	return ret;
20890165508cSHaavard Skinnemoen }
20900165508cSHaavard Skinnemoen 
209169423d99SAdrian Hunter static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
20920165508cSHaavard Skinnemoen {
20930165508cSHaavard Skinnemoen 	return cfi_varsize_frob(mtd, do_atmel_lock, ofs, len, NULL);
20940165508cSHaavard Skinnemoen }
20950165508cSHaavard Skinnemoen 
209669423d99SAdrian Hunter static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
20970165508cSHaavard Skinnemoen {
20980165508cSHaavard Skinnemoen 	return cfi_varsize_frob(mtd, do_atmel_unlock, ofs, len, NULL);
20990165508cSHaavard Skinnemoen }
21000165508cSHaavard Skinnemoen 
21011da177e4SLinus Torvalds 
21021da177e4SLinus Torvalds static void cfi_amdstd_sync (struct mtd_info *mtd)
21031da177e4SLinus Torvalds {
21041da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
21051da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
21061da177e4SLinus Torvalds 	int i;
21071da177e4SLinus Torvalds 	struct flchip *chip;
21081da177e4SLinus Torvalds 	int ret = 0;
21091da177e4SLinus Torvalds 	DECLARE_WAITQUEUE(wait, current);
21101da177e4SLinus Torvalds 
21111da177e4SLinus Torvalds 	for (i=0; !ret && i<cfi->numchips; i++) {
21121da177e4SLinus Torvalds 		chip = &cfi->chips[i];
21131da177e4SLinus Torvalds 
21141da177e4SLinus Torvalds 	retry:
2115c4e77376SStefani Seibold 		mutex_lock(&chip->mutex);
21161da177e4SLinus Torvalds 
21171da177e4SLinus Torvalds 		switch(chip->state) {
21181da177e4SLinus Torvalds 		case FL_READY:
21191da177e4SLinus Torvalds 		case FL_STATUS:
21201da177e4SLinus Torvalds 		case FL_CFI_QUERY:
21211da177e4SLinus Torvalds 		case FL_JEDEC_QUERY:
21221da177e4SLinus Torvalds 			chip->oldstate = chip->state;
21231da177e4SLinus Torvalds 			chip->state = FL_SYNCING;
21241da177e4SLinus Torvalds 			/* No need to wake_up() on this state change -
21251da177e4SLinus Torvalds 			 * as the whole point is that nobody can do anything
21261da177e4SLinus Torvalds 			 * with the chip now anyway.
21271da177e4SLinus Torvalds 			 */
21281da177e4SLinus Torvalds 		case FL_SYNCING:
2129c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
21301da177e4SLinus Torvalds 			break;
21311da177e4SLinus Torvalds 
21321da177e4SLinus Torvalds 		default:
21331da177e4SLinus Torvalds 			/* Not an idle state */
2134f8e30e44SDmitry Adamushko 			set_current_state(TASK_UNINTERRUPTIBLE);
21351da177e4SLinus Torvalds 			add_wait_queue(&chip->wq, &wait);
21361da177e4SLinus Torvalds 
2137c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
21381da177e4SLinus Torvalds 
21391da177e4SLinus Torvalds 			schedule();
21401da177e4SLinus Torvalds 
21411da177e4SLinus Torvalds 			remove_wait_queue(&chip->wq, &wait);
21421da177e4SLinus Torvalds 
21431da177e4SLinus Torvalds 			goto retry;
21441da177e4SLinus Torvalds 		}
21451da177e4SLinus Torvalds 	}
21461da177e4SLinus Torvalds 
21471da177e4SLinus Torvalds 	/* Unlock the chips again */
21481da177e4SLinus Torvalds 
21491da177e4SLinus Torvalds 	for (i--; i >=0; i--) {
21501da177e4SLinus Torvalds 		chip = &cfi->chips[i];
21511da177e4SLinus Torvalds 
2152c4e77376SStefani Seibold 		mutex_lock(&chip->mutex);
21531da177e4SLinus Torvalds 
21541da177e4SLinus Torvalds 		if (chip->state == FL_SYNCING) {
21551da177e4SLinus Torvalds 			chip->state = chip->oldstate;
21561da177e4SLinus Torvalds 			wake_up(&chip->wq);
21571da177e4SLinus Torvalds 		}
2158c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
21591da177e4SLinus Torvalds 	}
21601da177e4SLinus Torvalds }
21611da177e4SLinus Torvalds 
21621da177e4SLinus Torvalds 
21631da177e4SLinus Torvalds static int cfi_amdstd_suspend(struct mtd_info *mtd)
21641da177e4SLinus Torvalds {
21651da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
21661da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
21671da177e4SLinus Torvalds 	int i;
21681da177e4SLinus Torvalds 	struct flchip *chip;
21691da177e4SLinus Torvalds 	int ret = 0;
21701da177e4SLinus Torvalds 
21711da177e4SLinus Torvalds 	for (i=0; !ret && i<cfi->numchips; i++) {
21721da177e4SLinus Torvalds 		chip = &cfi->chips[i];
21731da177e4SLinus Torvalds 
2174c4e77376SStefani Seibold 		mutex_lock(&chip->mutex);
21751da177e4SLinus Torvalds 
21761da177e4SLinus Torvalds 		switch(chip->state) {
21771da177e4SLinus Torvalds 		case FL_READY:
21781da177e4SLinus Torvalds 		case FL_STATUS:
21791da177e4SLinus Torvalds 		case FL_CFI_QUERY:
21801da177e4SLinus Torvalds 		case FL_JEDEC_QUERY:
21811da177e4SLinus Torvalds 			chip->oldstate = chip->state;
21821da177e4SLinus Torvalds 			chip->state = FL_PM_SUSPENDED;
21831da177e4SLinus Torvalds 			/* No need to wake_up() on this state change -
21841da177e4SLinus Torvalds 			 * as the whole point is that nobody can do anything
21851da177e4SLinus Torvalds 			 * with the chip now anyway.
21861da177e4SLinus Torvalds 			 */
21871da177e4SLinus Torvalds 		case FL_PM_SUSPENDED:
21881da177e4SLinus Torvalds 			break;
21891da177e4SLinus Torvalds 
21901da177e4SLinus Torvalds 		default:
21911da177e4SLinus Torvalds 			ret = -EAGAIN;
21921da177e4SLinus Torvalds 			break;
21931da177e4SLinus Torvalds 		}
2194c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
21951da177e4SLinus Torvalds 	}
21961da177e4SLinus Torvalds 
21971da177e4SLinus Torvalds 	/* Unlock the chips again */
21981da177e4SLinus Torvalds 
21991da177e4SLinus Torvalds 	if (ret) {
22001da177e4SLinus Torvalds 		for (i--; i >=0; i--) {
22011da177e4SLinus Torvalds 			chip = &cfi->chips[i];
22021da177e4SLinus Torvalds 
2203c4e77376SStefani Seibold 			mutex_lock(&chip->mutex);
22041da177e4SLinus Torvalds 
22051da177e4SLinus Torvalds 			if (chip->state == FL_PM_SUSPENDED) {
22061da177e4SLinus Torvalds 				chip->state = chip->oldstate;
22071da177e4SLinus Torvalds 				wake_up(&chip->wq);
22081da177e4SLinus Torvalds 			}
2209c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
22101da177e4SLinus Torvalds 		}
22111da177e4SLinus Torvalds 	}
22121da177e4SLinus Torvalds 
22131da177e4SLinus Torvalds 	return ret;
22141da177e4SLinus Torvalds }
22151da177e4SLinus Torvalds 
22161da177e4SLinus Torvalds 
22171da177e4SLinus Torvalds static void cfi_amdstd_resume(struct mtd_info *mtd)
22181da177e4SLinus Torvalds {
22191da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
22201da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
22211da177e4SLinus Torvalds 	int i;
22221da177e4SLinus Torvalds 	struct flchip *chip;
22231da177e4SLinus Torvalds 
22241da177e4SLinus Torvalds 	for (i=0; i<cfi->numchips; i++) {
22251da177e4SLinus Torvalds 
22261da177e4SLinus Torvalds 		chip = &cfi->chips[i];
22271da177e4SLinus Torvalds 
2228c4e77376SStefani Seibold 		mutex_lock(&chip->mutex);
22291da177e4SLinus Torvalds 
22301da177e4SLinus Torvalds 		if (chip->state == FL_PM_SUSPENDED) {
22311da177e4SLinus Torvalds 			chip->state = FL_READY;
22321da177e4SLinus Torvalds 			map_write(map, CMD(0xF0), chip->start);
22331da177e4SLinus Torvalds 			wake_up(&chip->wq);
22341da177e4SLinus Torvalds 		}
22351da177e4SLinus Torvalds 		else
22361da177e4SLinus Torvalds 			printk(KERN_ERR "Argh. Chip not in PM_SUSPENDED state upon resume()\n");
22371da177e4SLinus Torvalds 
2238c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
22391da177e4SLinus Torvalds 	}
22401da177e4SLinus Torvalds }
22411da177e4SLinus Torvalds 
2242eafe1311SKevin Cernekee 
2243eafe1311SKevin Cernekee /*
2244eafe1311SKevin Cernekee  * Ensure that the flash device is put back into read array mode before
2245eafe1311SKevin Cernekee  * unloading the driver or rebooting.  On some systems, rebooting while
2246eafe1311SKevin Cernekee  * the flash is in query/program/erase mode will prevent the CPU from
2247eafe1311SKevin Cernekee  * fetching the bootloader code, requiring a hard reset or power cycle.
2248eafe1311SKevin Cernekee  */
2249eafe1311SKevin Cernekee static int cfi_amdstd_reset(struct mtd_info *mtd)
2250eafe1311SKevin Cernekee {
2251eafe1311SKevin Cernekee 	struct map_info *map = mtd->priv;
2252eafe1311SKevin Cernekee 	struct cfi_private *cfi = map->fldrv_priv;
2253eafe1311SKevin Cernekee 	int i, ret;
2254eafe1311SKevin Cernekee 	struct flchip *chip;
2255eafe1311SKevin Cernekee 
2256eafe1311SKevin Cernekee 	for (i = 0; i < cfi->numchips; i++) {
2257eafe1311SKevin Cernekee 
2258eafe1311SKevin Cernekee 		chip = &cfi->chips[i];
2259eafe1311SKevin Cernekee 
2260eafe1311SKevin Cernekee 		mutex_lock(&chip->mutex);
2261eafe1311SKevin Cernekee 
2262eafe1311SKevin Cernekee 		ret = get_chip(map, chip, chip->start, FL_SHUTDOWN);
2263eafe1311SKevin Cernekee 		if (!ret) {
2264eafe1311SKevin Cernekee 			map_write(map, CMD(0xF0), chip->start);
2265eafe1311SKevin Cernekee 			chip->state = FL_SHUTDOWN;
2266eafe1311SKevin Cernekee 			put_chip(map, chip, chip->start);
2267eafe1311SKevin Cernekee 		}
2268eafe1311SKevin Cernekee 
2269eafe1311SKevin Cernekee 		mutex_unlock(&chip->mutex);
2270eafe1311SKevin Cernekee 	}
2271eafe1311SKevin Cernekee 
2272eafe1311SKevin Cernekee 	return 0;
2273eafe1311SKevin Cernekee }
2274eafe1311SKevin Cernekee 
2275eafe1311SKevin Cernekee 
2276eafe1311SKevin Cernekee static int cfi_amdstd_reboot(struct notifier_block *nb, unsigned long val,
2277eafe1311SKevin Cernekee 			       void *v)
2278eafe1311SKevin Cernekee {
2279eafe1311SKevin Cernekee 	struct mtd_info *mtd;
2280eafe1311SKevin Cernekee 
2281eafe1311SKevin Cernekee 	mtd = container_of(nb, struct mtd_info, reboot_notifier);
2282eafe1311SKevin Cernekee 	cfi_amdstd_reset(mtd);
2283eafe1311SKevin Cernekee 	return NOTIFY_DONE;
2284eafe1311SKevin Cernekee }
2285eafe1311SKevin Cernekee 
2286eafe1311SKevin Cernekee 
22871da177e4SLinus Torvalds static void cfi_amdstd_destroy(struct mtd_info *mtd)
22881da177e4SLinus Torvalds {
22891da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
22901da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
2291fa671646SJesper Juhl 
2292eafe1311SKevin Cernekee 	cfi_amdstd_reset(mtd);
2293eafe1311SKevin Cernekee 	unregister_reboot_notifier(&mtd->reboot_notifier);
22941da177e4SLinus Torvalds 	kfree(cfi->cmdset_priv);
22951da177e4SLinus Torvalds 	kfree(cfi->cfiq);
22961da177e4SLinus Torvalds 	kfree(cfi);
22971da177e4SLinus Torvalds 	kfree(mtd->eraseregions);
22981da177e4SLinus Torvalds }
22991da177e4SLinus Torvalds 
23001da177e4SLinus Torvalds MODULE_LICENSE("GPL");
23011da177e4SLinus Torvalds MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al.");
23021da177e4SLinus Torvalds MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips");
230380461128SGuillaume LECERF MODULE_ALIAS("cfi_cmdset_0006");
23041e804cecSDavid Woodhouse MODULE_ALIAS("cfi_cmdset_0701");
2305