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 <asm/io.h>
281da177e4SLinus Torvalds #include <asm/byteorder.h>
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds #include <linux/errno.h>
311da177e4SLinus Torvalds #include <linux/slab.h>
321da177e4SLinus Torvalds #include <linux/delay.h>
331da177e4SLinus Torvalds #include <linux/interrupt.h>
34eafe1311SKevin Cernekee #include <linux/reboot.h>
351648eaaaSStefan Roese #include <linux/of.h>
361648eaaaSStefan Roese #include <linux/of_platform.h>
371da177e4SLinus Torvalds #include <linux/mtd/map.h>
381da177e4SLinus Torvalds #include <linux/mtd/mtd.h>
391da177e4SLinus Torvalds #include <linux/mtd/cfi.h>
4002b15e34STodd Poynor #include <linux/mtd/xip.h>
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds #define AMD_BOOTLOC_BUG
431da177e4SLinus Torvalds #define FORCE_WORD_WRITE 0
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds #define MAX_WORD_RETRIES 3
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds #define SST49LF004B	        0x0060
4889072ef9SRyan Jackson #define SST49LF040B	        0x0050
49fb4a90bfSEric W. Biedermann #define SST49LF008A		0x005a
500165508cSHaavard Skinnemoen #define AT49BV6416		0x00d6
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
531da177e4SLinus Torvalds static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
541da177e4SLinus Torvalds static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
551da177e4SLinus Torvalds static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *);
561da177e4SLinus Torvalds static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *);
571da177e4SLinus Torvalds static void cfi_amdstd_sync (struct mtd_info *);
581da177e4SLinus Torvalds static int cfi_amdstd_suspend (struct mtd_info *);
591da177e4SLinus Torvalds static void cfi_amdstd_resume (struct mtd_info *);
60eafe1311SKevin Cernekee static int cfi_amdstd_reboot(struct notifier_block *, unsigned long, void *);
61dc7e9ecdSChristian Riesch static int cfi_amdstd_get_fact_prot_info(struct mtd_info *, size_t,
62dc7e9ecdSChristian Riesch 					 size_t *, struct otp_info *);
63dc7e9ecdSChristian Riesch static int cfi_amdstd_get_user_prot_info(struct mtd_info *, size_t,
64dc7e9ecdSChristian Riesch 					 size_t *, struct otp_info *);
651da177e4SLinus Torvalds static int cfi_amdstd_secsi_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
66dc7e9ecdSChristian Riesch static int cfi_amdstd_read_fact_prot_reg(struct mtd_info *, loff_t, size_t,
67dc7e9ecdSChristian Riesch 					 size_t *, u_char *);
68dc7e9ecdSChristian Riesch static int cfi_amdstd_read_user_prot_reg(struct mtd_info *, loff_t, size_t,
69dc7e9ecdSChristian Riesch 					 size_t *, u_char *);
70af744750SChristian Riesch static int cfi_amdstd_write_user_prot_reg(struct mtd_info *, loff_t, size_t,
71af744750SChristian Riesch 					  size_t *, u_char *);
724f5cb243SChristian Riesch static int cfi_amdstd_lock_user_prot_reg(struct mtd_info *, loff_t, size_t);
731da177e4SLinus Torvalds 
7430ec5a2cSIra W. Snyder static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
7530ec5a2cSIra W. Snyder 				  size_t *retlen, const u_char *buf);
7630ec5a2cSIra W. Snyder 
771da177e4SLinus Torvalds static void cfi_amdstd_destroy(struct mtd_info *);
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds struct mtd_info *cfi_cmdset_0002(struct map_info *, int);
801da177e4SLinus Torvalds static struct mtd_info *cfi_amdstd_setup (struct mtd_info *);
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
831da177e4SLinus Torvalds static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr);
841da177e4SLinus Torvalds #include "fwh_lock.h"
851da177e4SLinus Torvalds 
8669423d99SAdrian Hunter static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
8769423d99SAdrian Hunter static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
880165508cSHaavard Skinnemoen 
891648eaaaSStefan Roese static int cfi_ppb_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
901648eaaaSStefan Roese static int cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
911648eaaaSStefan Roese static int cfi_ppb_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len);
921648eaaaSStefan Roese 
931da177e4SLinus Torvalds static struct mtd_chip_driver cfi_amdstd_chipdrv = {
941da177e4SLinus Torvalds 	.probe		= NULL, /* Not usable directly */
951da177e4SLinus Torvalds 	.destroy	= cfi_amdstd_destroy,
961da177e4SLinus Torvalds 	.name		= "cfi_cmdset_0002",
971da177e4SLinus Torvalds 	.module		= THIS_MODULE
981da177e4SLinus Torvalds };
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds /* #define DEBUG_CFI_FEATURES */
1021da177e4SLinus Torvalds 
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds #ifdef DEBUG_CFI_FEATURES
1051da177e4SLinus Torvalds static void cfi_tell_features(struct cfi_pri_amdstd *extp)
1061da177e4SLinus Torvalds {
1071da177e4SLinus Torvalds 	const char* erase_suspend[3] = {
1081da177e4SLinus Torvalds 		"Not supported", "Read only", "Read/write"
1091da177e4SLinus Torvalds 	};
1101da177e4SLinus Torvalds 	const char* top_bottom[6] = {
1111da177e4SLinus Torvalds 		"No WP", "8x8KiB sectors at top & bottom, no WP",
1121da177e4SLinus Torvalds 		"Bottom boot", "Top boot",
1131da177e4SLinus Torvalds 		"Uniform, Bottom WP", "Uniform, Top WP"
1141da177e4SLinus Torvalds 	};
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds 	printk("  Silicon revision: %d\n", extp->SiliconRevision >> 1);
1171da177e4SLinus Torvalds 	printk("  Address sensitive unlock: %s\n",
1181da177e4SLinus Torvalds 	       (extp->SiliconRevision & 1) ? "Not required" : "Required");
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds 	if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend))
1211da177e4SLinus Torvalds 		printk("  Erase Suspend: %s\n", erase_suspend[extp->EraseSuspend]);
1221da177e4SLinus Torvalds 	else
1231da177e4SLinus Torvalds 		printk("  Erase Suspend: Unknown value %d\n", extp->EraseSuspend);
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds 	if (extp->BlkProt == 0)
1261da177e4SLinus Torvalds 		printk("  Block protection: Not supported\n");
1271da177e4SLinus Torvalds 	else
1281da177e4SLinus Torvalds 		printk("  Block protection: %d sectors per group\n", extp->BlkProt);
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds 	printk("  Temporary block unprotect: %s\n",
1321da177e4SLinus Torvalds 	       extp->TmpBlkUnprotect ? "Supported" : "Not supported");
1331da177e4SLinus Torvalds 	printk("  Block protect/unprotect scheme: %d\n", extp->BlkProtUnprot);
1341da177e4SLinus Torvalds 	printk("  Number of simultaneous operations: %d\n", extp->SimultaneousOps);
1351da177e4SLinus Torvalds 	printk("  Burst mode: %s\n",
1361da177e4SLinus Torvalds 	       extp->BurstMode ? "Supported" : "Not supported");
1371da177e4SLinus Torvalds 	if (extp->PageMode == 0)
1381da177e4SLinus Torvalds 		printk("  Page mode: Not supported\n");
1391da177e4SLinus Torvalds 	else
1401da177e4SLinus Torvalds 		printk("  Page mode: %d word page\n", extp->PageMode << 2);
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds 	printk("  Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n",
1431da177e4SLinus Torvalds 	       extp->VppMin >> 4, extp->VppMin & 0xf);
1441da177e4SLinus Torvalds 	printk("  Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n",
1451da177e4SLinus Torvalds 	       extp->VppMax >> 4, extp->VppMax & 0xf);
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds 	if (extp->TopBottom < ARRAY_SIZE(top_bottom))
1481da177e4SLinus Torvalds 		printk("  Top/Bottom Boot Block: %s\n", top_bottom[extp->TopBottom]);
1491da177e4SLinus Torvalds 	else
1501da177e4SLinus Torvalds 		printk("  Top/Bottom Boot Block: Unknown value %d\n", extp->TopBottom);
1511da177e4SLinus Torvalds }
1521da177e4SLinus Torvalds #endif
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds #ifdef AMD_BOOTLOC_BUG
1551da177e4SLinus Torvalds /* Wheee. Bring me the head of someone at AMD. */
156cc318222SGuillaume LECERF static void fixup_amd_bootblock(struct mtd_info *mtd)
1571da177e4SLinus Torvalds {
1581da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
1591da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
1601da177e4SLinus Torvalds 	struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
1611da177e4SLinus Torvalds 	__u8 major = extp->MajorVersion;
1621da177e4SLinus Torvalds 	__u8 minor = extp->MinorVersion;
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds 	if (((major << 8) | minor) < 0x3131) {
1651da177e4SLinus Torvalds 		/* CFI version 1.0 => don't trust bootloc */
16687e92c06SChristopher Moore 
167289c0522SBrian Norris 		pr_debug("%s: JEDEC Vendor ID is 0x%02X Device ID is 0x%02X\n",
16887e92c06SChristopher Moore 			map->name, cfi->mfr, cfi->id);
16987e92c06SChristopher Moore 
17087e92c06SChristopher Moore 		/* AFAICS all 29LV400 with a bottom boot block have a device ID
17187e92c06SChristopher Moore 		 * of 0x22BA in 16-bit mode and 0xBA in 8-bit mode.
17287e92c06SChristopher Moore 		 * These were badly detected as they have the 0x80 bit set
17387e92c06SChristopher Moore 		 * so treat them as a special case.
17487e92c06SChristopher Moore 		 */
17587e92c06SChristopher Moore 		if (((cfi->id == 0xBA) || (cfi->id == 0x22BA)) &&
17687e92c06SChristopher Moore 
17787e92c06SChristopher Moore 			/* Macronix added CFI to their 2nd generation
17887e92c06SChristopher Moore 			 * MX29LV400C B/T but AFAICS no other 29LV400 (AMD,
17987e92c06SChristopher Moore 			 * Fujitsu, Spansion, EON, ESI and older Macronix)
18087e92c06SChristopher Moore 			 * has CFI.
18187e92c06SChristopher Moore 			 *
18287e92c06SChristopher Moore 			 * Therefore also check the manufacturer.
18387e92c06SChristopher Moore 			 * This reduces the risk of false detection due to
18487e92c06SChristopher Moore 			 * the 8-bit device ID.
18587e92c06SChristopher Moore 			 */
186f3e69c65SGuillaume LECERF 			(cfi->mfr == CFI_MFR_MACRONIX)) {
187289c0522SBrian Norris 			pr_debug("%s: Macronix MX29LV400C with bottom boot block"
18887e92c06SChristopher Moore 				" detected\n", map->name);
18987e92c06SChristopher Moore 			extp->TopBottom = 2;	/* bottom boot */
19087e92c06SChristopher Moore 		} else
1911da177e4SLinus Torvalds 		if (cfi->id & 0x80) {
1921da177e4SLinus Torvalds 			printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id);
1931da177e4SLinus Torvalds 			extp->TopBottom = 3;	/* top boot */
1941da177e4SLinus Torvalds 		} else {
1951da177e4SLinus Torvalds 			extp->TopBottom = 2;	/* bottom boot */
1961da177e4SLinus Torvalds 		}
19787e92c06SChristopher Moore 
198289c0522SBrian Norris 		pr_debug("%s: AMD CFI PRI V%c.%c has no boot block field;"
19987e92c06SChristopher Moore 			" deduced %s from Device ID\n", map->name, major, minor,
20087e92c06SChristopher Moore 			extp->TopBottom == 2 ? "bottom" : "top");
2011da177e4SLinus Torvalds 	}
2021da177e4SLinus Torvalds }
2031da177e4SLinus Torvalds #endif
2041da177e4SLinus Torvalds 
205cc318222SGuillaume LECERF static void fixup_use_write_buffers(struct mtd_info *mtd)
2061da177e4SLinus Torvalds {
2071da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
2081da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
2091da177e4SLinus Torvalds 	if (cfi->cfiq->BufWriteTimeoutTyp) {
210289c0522SBrian Norris 		pr_debug("Using buffer write method\n" );
2113c3c10bbSArtem Bityutskiy 		mtd->_write = cfi_amdstd_write_buffers;
2121da177e4SLinus Torvalds 	}
2131da177e4SLinus Torvalds }
2141da177e4SLinus Torvalds 
2155b0c5c2cSHaavard Skinnemoen /* Atmel chips don't use the same PRI format as AMD chips */
216cc318222SGuillaume LECERF static void fixup_convert_atmel_pri(struct mtd_info *mtd)
2175b0c5c2cSHaavard Skinnemoen {
2185b0c5c2cSHaavard Skinnemoen 	struct map_info *map = mtd->priv;
2195b0c5c2cSHaavard Skinnemoen 	struct cfi_private *cfi = map->fldrv_priv;
2205b0c5c2cSHaavard Skinnemoen 	struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
2215b0c5c2cSHaavard Skinnemoen 	struct cfi_pri_atmel atmel_pri;
2225b0c5c2cSHaavard Skinnemoen 
2235b0c5c2cSHaavard Skinnemoen 	memcpy(&atmel_pri, extp, sizeof(atmel_pri));
224de591dacSHåvard Skinnemoen 	memset((char *)extp + 5, 0, sizeof(*extp) - 5);
2255b0c5c2cSHaavard Skinnemoen 
2265b0c5c2cSHaavard Skinnemoen 	if (atmel_pri.Features & 0x02)
2275b0c5c2cSHaavard Skinnemoen 		extp->EraseSuspend = 2;
2285b0c5c2cSHaavard Skinnemoen 
229be8f78b8SHaavard Skinnemoen 	/* Some chips got it backwards... */
230be8f78b8SHaavard Skinnemoen 	if (cfi->id == AT49BV6416) {
231be8f78b8SHaavard Skinnemoen 		if (atmel_pri.BottomBoot)
232be8f78b8SHaavard Skinnemoen 			extp->TopBottom = 3;
233be8f78b8SHaavard Skinnemoen 		else
234be8f78b8SHaavard Skinnemoen 			extp->TopBottom = 2;
235be8f78b8SHaavard Skinnemoen 	} else {
2365b0c5c2cSHaavard Skinnemoen 		if (atmel_pri.BottomBoot)
2375b0c5c2cSHaavard Skinnemoen 			extp->TopBottom = 2;
2385b0c5c2cSHaavard Skinnemoen 		else
2395b0c5c2cSHaavard Skinnemoen 			extp->TopBottom = 3;
240be8f78b8SHaavard Skinnemoen 	}
241d10a39d1SHans-Christian Egtvedt 
242d10a39d1SHans-Christian Egtvedt 	/* burst write mode not supported */
243d10a39d1SHans-Christian Egtvedt 	cfi->cfiq->BufWriteTimeoutTyp = 0;
244d10a39d1SHans-Christian Egtvedt 	cfi->cfiq->BufWriteTimeoutMax = 0;
2455b0c5c2cSHaavard Skinnemoen }
2465b0c5c2cSHaavard Skinnemoen 
247cc318222SGuillaume LECERF static void fixup_use_secsi(struct mtd_info *mtd)
2481da177e4SLinus Torvalds {
2491da177e4SLinus Torvalds 	/* Setup for chips with a secsi area */
2503c3c10bbSArtem Bityutskiy 	mtd->_read_user_prot_reg = cfi_amdstd_secsi_read;
2513c3c10bbSArtem Bityutskiy 	mtd->_read_fact_prot_reg = cfi_amdstd_secsi_read;
2521da177e4SLinus Torvalds }
2531da177e4SLinus Torvalds 
254cc318222SGuillaume LECERF static void fixup_use_erase_chip(struct mtd_info *mtd)
2551da177e4SLinus Torvalds {
2561da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
2571da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
2581da177e4SLinus Torvalds 	if ((cfi->cfiq->NumEraseRegions == 1) &&
2591da177e4SLinus Torvalds 		((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) {
2603c3c10bbSArtem Bityutskiy 		mtd->_erase = cfi_amdstd_erase_chip;
2611da177e4SLinus Torvalds 	}
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds }
2641da177e4SLinus Torvalds 
2650165508cSHaavard Skinnemoen /*
2660165508cSHaavard Skinnemoen  * Some Atmel chips (e.g. the AT49BV6416) power-up with all sectors
2670165508cSHaavard Skinnemoen  * locked by default.
2680165508cSHaavard Skinnemoen  */
269cc318222SGuillaume LECERF static void fixup_use_atmel_lock(struct mtd_info *mtd)
2700165508cSHaavard Skinnemoen {
2713c3c10bbSArtem Bityutskiy 	mtd->_lock = cfi_atmel_lock;
2723c3c10bbSArtem Bityutskiy 	mtd->_unlock = cfi_atmel_unlock;
273e619a75fSJustin Treon 	mtd->flags |= MTD_POWERUP_LOCK;
2740165508cSHaavard Skinnemoen }
2750165508cSHaavard Skinnemoen 
27683dcd3bbSGuillaume LECERF static void fixup_old_sst_eraseregion(struct mtd_info *mtd)
27783dcd3bbSGuillaume LECERF {
27883dcd3bbSGuillaume LECERF 	struct map_info *map = mtd->priv;
27983dcd3bbSGuillaume LECERF 	struct cfi_private *cfi = map->fldrv_priv;
28083dcd3bbSGuillaume LECERF 
28183dcd3bbSGuillaume LECERF 	/*
28225985edcSLucas De Marchi 	 * These flashes report two separate eraseblock regions based on the
28383dcd3bbSGuillaume LECERF 	 * sector_erase-size and block_erase-size, although they both operate on the
28483dcd3bbSGuillaume LECERF 	 * same memory. This is not allowed according to CFI, so we just pick the
28583dcd3bbSGuillaume LECERF 	 * sector_erase-size.
28683dcd3bbSGuillaume LECERF 	 */
28783dcd3bbSGuillaume LECERF 	cfi->cfiq->NumEraseRegions = 1;
28883dcd3bbSGuillaume LECERF }
28983dcd3bbSGuillaume LECERF 
290cc318222SGuillaume LECERF static void fixup_sst39vf(struct mtd_info *mtd)
29183dcd3bbSGuillaume LECERF {
29283dcd3bbSGuillaume LECERF 	struct map_info *map = mtd->priv;
29383dcd3bbSGuillaume LECERF 	struct cfi_private *cfi = map->fldrv_priv;
29483dcd3bbSGuillaume LECERF 
29583dcd3bbSGuillaume LECERF 	fixup_old_sst_eraseregion(mtd);
29683dcd3bbSGuillaume LECERF 
29783dcd3bbSGuillaume LECERF 	cfi->addr_unlock1 = 0x5555;
29883dcd3bbSGuillaume LECERF 	cfi->addr_unlock2 = 0x2AAA;
29983dcd3bbSGuillaume LECERF }
30083dcd3bbSGuillaume LECERF 
301cc318222SGuillaume LECERF static void fixup_sst39vf_rev_b(struct mtd_info *mtd)
3025a0563f0SGuillaume LECERF {
3035a0563f0SGuillaume LECERF 	struct map_info *map = mtd->priv;
3045a0563f0SGuillaume LECERF 	struct cfi_private *cfi = map->fldrv_priv;
3055a0563f0SGuillaume LECERF 
3065a0563f0SGuillaume LECERF 	fixup_old_sst_eraseregion(mtd);
3075a0563f0SGuillaume LECERF 
3085a0563f0SGuillaume LECERF 	cfi->addr_unlock1 = 0x555;
3095a0563f0SGuillaume LECERF 	cfi->addr_unlock2 = 0x2AA;
31008968041SGuillaume LECERF 
31108968041SGuillaume LECERF 	cfi->sector_erase_cmd = CMD(0x50);
3125a0563f0SGuillaume LECERF }
3135a0563f0SGuillaume LECERF 
314cc318222SGuillaume LECERF static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd)
3159fc05fcaSGuillaume LECERF {
3169fc05fcaSGuillaume LECERF 	struct map_info *map = mtd->priv;
3179fc05fcaSGuillaume LECERF 	struct cfi_private *cfi = map->fldrv_priv;
3189fc05fcaSGuillaume LECERF 
319cc318222SGuillaume LECERF 	fixup_sst39vf_rev_b(mtd);
3209fc05fcaSGuillaume LECERF 
3219fc05fcaSGuillaume LECERF 	/*
3229fc05fcaSGuillaume LECERF 	 * CFI reports 1024 sectors (0x03ff+1) of 64KBytes (0x0100*256) where
3239fc05fcaSGuillaume LECERF 	 * it should report a size of 8KBytes (0x0020*256).
3249fc05fcaSGuillaume LECERF 	 */
3259fc05fcaSGuillaume LECERF 	cfi->cfiq->EraseRegionInfo[0] = 0x002003ff;
326e8348dc5SJoe Perches 	pr_warn("%s: Bad 38VF640x CFI data; adjusting sector size from 64 to 8KiB\n",
327e8348dc5SJoe Perches 		mtd->name);
3289fc05fcaSGuillaume LECERF }
3299fc05fcaSGuillaume LECERF 
330cc318222SGuillaume LECERF static void fixup_s29gl064n_sectors(struct mtd_info *mtd)
33170b07255STrent Piepho {
33270b07255STrent Piepho 	struct map_info *map = mtd->priv;
33370b07255STrent Piepho 	struct cfi_private *cfi = map->fldrv_priv;
33470b07255STrent Piepho 
33570b07255STrent Piepho 	if ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0x003f) {
33670b07255STrent Piepho 		cfi->cfiq->EraseRegionInfo[0] |= 0x0040;
337e8348dc5SJoe Perches 		pr_warn("%s: Bad S29GL064N CFI data; adjust from 64 to 128 sectors\n",
338e8348dc5SJoe Perches 			mtd->name);
33970b07255STrent Piepho 	}
34070b07255STrent Piepho }
34170b07255STrent Piepho 
342cc318222SGuillaume LECERF static void fixup_s29gl032n_sectors(struct mtd_info *mtd)
34370b07255STrent Piepho {
34470b07255STrent Piepho 	struct map_info *map = mtd->priv;
34570b07255STrent Piepho 	struct cfi_private *cfi = map->fldrv_priv;
34670b07255STrent Piepho 
34770b07255STrent Piepho 	if ((cfi->cfiq->EraseRegionInfo[1] & 0xffff) == 0x007e) {
34870b07255STrent Piepho 		cfi->cfiq->EraseRegionInfo[1] &= ~0x0040;
349e8348dc5SJoe Perches 		pr_warn("%s: Bad S29GL032N CFI data; adjust from 127 to 63 sectors\n",
350e8348dc5SJoe Perches 			mtd->name);
35170b07255STrent Piepho 	}
35270b07255STrent Piepho }
35370b07255STrent Piepho 
35443dc03c7SJavier Martin static void fixup_s29ns512p_sectors(struct mtd_info *mtd)
35543dc03c7SJavier Martin {
35643dc03c7SJavier Martin 	struct map_info *map = mtd->priv;
35743dc03c7SJavier Martin 	struct cfi_private *cfi = map->fldrv_priv;
35843dc03c7SJavier Martin 
35943dc03c7SJavier Martin 	/*
36043dc03c7SJavier Martin 	 *  S29NS512P flash uses more than 8bits to report number of sectors,
36143dc03c7SJavier Martin 	 * which is not permitted by CFI.
36243dc03c7SJavier Martin 	 */
36343dc03c7SJavier Martin 	cfi->cfiq->EraseRegionInfo[0] = 0x020001ff;
364e8348dc5SJoe Perches 	pr_warn("%s: Bad S29NS512P CFI data; adjust to 512 sectors\n",
365e8348dc5SJoe Perches 		mtd->name);
36643dc03c7SJavier Martin }
36743dc03c7SJavier Martin 
36883dcd3bbSGuillaume LECERF /* Used to fix CFI-Tables of chips without Extended Query Tables */
36983dcd3bbSGuillaume LECERF static struct cfi_fixup cfi_nopri_fixup_table[] = {
370cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x234a, fixup_sst39vf }, /* SST39VF1602 */
371cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x234b, fixup_sst39vf }, /* SST39VF1601 */
372cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x235a, fixup_sst39vf }, /* SST39VF3202 */
373cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x235b, fixup_sst39vf }, /* SST39VF3201 */
374cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x235c, fixup_sst39vf_rev_b }, /* SST39VF3202B */
375cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x235d, fixup_sst39vf_rev_b }, /* SST39VF3201B */
376cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x236c, fixup_sst39vf_rev_b }, /* SST39VF6402B */
377cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x236d, fixup_sst39vf_rev_b }, /* SST39VF6401B */
378cc318222SGuillaume LECERF 	{ 0, 0, NULL }
37983dcd3bbSGuillaume LECERF };
38083dcd3bbSGuillaume LECERF 
3811da177e4SLinus Torvalds static struct cfi_fixup cfi_fixup_table[] = {
382cc318222SGuillaume LECERF 	{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri },
3831da177e4SLinus Torvalds #ifdef AMD_BOOTLOC_BUG
384cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock },
3851065cda8SSteffen Sledz 	{ CFI_MFR_AMIC, CFI_ID_ANY, fixup_amd_bootblock },
386cc318222SGuillaume LECERF 	{ CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock },
3871da177e4SLinus Torvalds #endif
388cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x0050, fixup_use_secsi },
389cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x0053, fixup_use_secsi },
390cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x0055, fixup_use_secsi },
391cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x0056, fixup_use_secsi },
392cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x005C, fixup_use_secsi },
393cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x005F, fixup_use_secsi },
394cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors },
395cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors },
396cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors },
397cc318222SGuillaume LECERF 	{ CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors },
39843dc03c7SJavier Martin 	{ CFI_MFR_AMD, 0x3f00, fixup_s29ns512p_sectors },
399cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x536a, fixup_sst38vf640x_sectorsize }, /* SST38VF6402 */
400cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x536b, fixup_sst38vf640x_sectorsize }, /* SST38VF6401 */
401cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x536c, fixup_sst38vf640x_sectorsize }, /* SST38VF6404 */
402cc318222SGuillaume LECERF 	{ CFI_MFR_SST, 0x536d, fixup_sst38vf640x_sectorsize }, /* SST38VF6403 */
4031da177e4SLinus Torvalds #if !FORCE_WORD_WRITE
404cc318222SGuillaume LECERF 	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers },
4051da177e4SLinus Torvalds #endif
406cc318222SGuillaume LECERF 	{ 0, 0, NULL }
4071da177e4SLinus Torvalds };
4081da177e4SLinus Torvalds static struct cfi_fixup jedec_fixup_table[] = {
409cc318222SGuillaume LECERF 	{ CFI_MFR_SST, SST49LF004B, fixup_use_fwh_lock },
410cc318222SGuillaume LECERF 	{ CFI_MFR_SST, SST49LF040B, fixup_use_fwh_lock },
411cc318222SGuillaume LECERF 	{ CFI_MFR_SST, SST49LF008A, fixup_use_fwh_lock },
412cc318222SGuillaume LECERF 	{ 0, 0, NULL }
4131da177e4SLinus Torvalds };
4141da177e4SLinus Torvalds 
4151da177e4SLinus Torvalds static struct cfi_fixup fixup_table[] = {
4161da177e4SLinus Torvalds 	/* The CFI vendor ids and the JEDEC vendor IDs appear
4171da177e4SLinus Torvalds 	 * to be common.  It is like the devices id's are as
4181da177e4SLinus Torvalds 	 * well.  This table is to pick all cases where
4191da177e4SLinus Torvalds 	 * we know that is the case.
4201da177e4SLinus Torvalds 	 */
421cc318222SGuillaume LECERF 	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip },
422cc318222SGuillaume LECERF 	{ CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock },
423cc318222SGuillaume LECERF 	{ 0, 0, NULL }
4241da177e4SLinus Torvalds };
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds 
427fefae48bSWolfgang Grandegger static void cfi_fixup_major_minor(struct cfi_private *cfi,
428fefae48bSWolfgang Grandegger 				  struct cfi_pri_amdstd *extp)
429fefae48bSWolfgang Grandegger {
430e6372763SGuillaume LECERF 	if (cfi->mfr == CFI_MFR_SAMSUNG) {
431e8953b73SGuillaume LECERF 		if ((extp->MajorVersion == '0' && extp->MinorVersion == '0') ||
432e8953b73SGuillaume LECERF 		    (extp->MajorVersion == '3' && extp->MinorVersion == '3')) {
433e6372763SGuillaume LECERF 			/*
434e6372763SGuillaume LECERF 			 * Samsung K8P2815UQB and K8D6x16UxM chips
435e6372763SGuillaume LECERF 			 * report major=0 / minor=0.
436e8953b73SGuillaume LECERF 			 * K8D3x16UxC chips report major=3 / minor=3.
437e6372763SGuillaume LECERF 			 */
438e6372763SGuillaume LECERF 			printk(KERN_NOTICE "  Fixing Samsung's Amd/Fujitsu"
439e6372763SGuillaume LECERF 			       " Extended Query version to 1.%c\n",
440e6372763SGuillaume LECERF 			       extp->MinorVersion);
441fefae48bSWolfgang Grandegger 			extp->MajorVersion = '1';
442e6372763SGuillaume LECERF 		}
443e6372763SGuillaume LECERF 	}
444e6372763SGuillaume LECERF 
4459fc05fcaSGuillaume LECERF 	/*
4469fc05fcaSGuillaume LECERF 	 * SST 38VF640x chips report major=0xFF / minor=0xFF.
4479fc05fcaSGuillaume LECERF 	 */
4489fc05fcaSGuillaume LECERF 	if (cfi->mfr == CFI_MFR_SST && (cfi->id >> 4) == 0x0536) {
4499fc05fcaSGuillaume LECERF 		extp->MajorVersion = '1';
4509fc05fcaSGuillaume LECERF 		extp->MinorVersion = '0';
4519fc05fcaSGuillaume LECERF 	}
452fefae48bSWolfgang Grandegger }
453fefae48bSWolfgang Grandegger 
45442096288SGerlando Falauto static int is_m29ew(struct cfi_private *cfi)
45542096288SGerlando Falauto {
45642096288SGerlando Falauto 	if (cfi->mfr == CFI_MFR_INTEL &&
45742096288SGerlando Falauto 	    ((cfi->device_type == CFI_DEVICETYPE_X8 && (cfi->id & 0xff) == 0x7e) ||
45842096288SGerlando Falauto 	     (cfi->device_type == CFI_DEVICETYPE_X16 && cfi->id == 0x227e)))
45942096288SGerlando Falauto 		return 1;
46042096288SGerlando Falauto 	return 0;
46142096288SGerlando Falauto }
46242096288SGerlando Falauto 
46342096288SGerlando Falauto /*
46442096288SGerlando Falauto  * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 20:
46542096288SGerlando Falauto  * Some revisions of the M29EW suffer from erase suspend hang ups. In
46642096288SGerlando Falauto  * particular, it can occur when the sequence
46742096288SGerlando Falauto  * Erase Confirm -> Suspend -> Program -> Resume
46842096288SGerlando Falauto  * causes a lockup due to internal timing issues. The consequence is that the
46942096288SGerlando Falauto  * erase cannot be resumed without inserting a dummy command after programming
47042096288SGerlando Falauto  * and prior to resuming. [...] The work-around is to issue a dummy write cycle
47142096288SGerlando Falauto  * that writes an F0 command code before the RESUME command.
47242096288SGerlando Falauto  */
47342096288SGerlando Falauto static void cfi_fixup_m29ew_erase_suspend(struct map_info *map,
47442096288SGerlando Falauto 					  unsigned long adr)
47542096288SGerlando Falauto {
47642096288SGerlando Falauto 	struct cfi_private *cfi = map->fldrv_priv;
47742096288SGerlando Falauto 	/* before resume, insert a dummy 0xF0 cycle for Micron M29EW devices */
47842096288SGerlando Falauto 	if (is_m29ew(cfi))
47942096288SGerlando Falauto 		map_write(map, CMD(0xF0), adr);
48042096288SGerlando Falauto }
48142096288SGerlando Falauto 
48242096288SGerlando Falauto /*
48342096288SGerlando Falauto  * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 22:
48442096288SGerlando Falauto  *
48542096288SGerlando Falauto  * Some revisions of the M29EW (for example, A1 and A2 step revisions)
48642096288SGerlando Falauto  * are affected by a problem that could cause a hang up when an ERASE SUSPEND
48742096288SGerlando Falauto  * command is issued after an ERASE RESUME operation without waiting for a
48842096288SGerlando Falauto  * minimum delay.  The result is that once the ERASE seems to be completed
48942096288SGerlando Falauto  * (no bits are toggling), the contents of the Flash memory block on which
49042096288SGerlando Falauto  * the erase was ongoing could be inconsistent with the expected values
49142096288SGerlando Falauto  * (typically, the array value is stuck to the 0xC0, 0xC4, 0x80, or 0x84
49242096288SGerlando Falauto  * values), causing a consequent failure of the ERASE operation.
49342096288SGerlando Falauto  * The occurrence of this issue could be high, especially when file system
49442096288SGerlando Falauto  * operations on the Flash are intensive.  As a result, it is recommended
49542096288SGerlando Falauto  * that a patch be applied.  Intensive file system operations can cause many
49642096288SGerlando Falauto  * calls to the garbage routine to free Flash space (also by erasing physical
49742096288SGerlando Falauto  * Flash blocks) and as a result, many consecutive SUSPEND and RESUME
49842096288SGerlando Falauto  * commands can occur.  The problem disappears when a delay is inserted after
49942096288SGerlando Falauto  * the RESUME command by using the udelay() function available in Linux.
50042096288SGerlando Falauto  * The DELAY value must be tuned based on the customer's platform.
50142096288SGerlando Falauto  * The maximum value that fixes the problem in all cases is 500us.
50242096288SGerlando Falauto  * But, in our experience, a delay of 30 µs to 50 µs is sufficient
50342096288SGerlando Falauto  * in most cases.
50442096288SGerlando Falauto  * We have chosen 500µs because this latency is acceptable.
50542096288SGerlando Falauto  */
50642096288SGerlando Falauto static void cfi_fixup_m29ew_delay_after_resume(struct cfi_private *cfi)
50742096288SGerlando Falauto {
50842096288SGerlando Falauto 	/*
50942096288SGerlando Falauto 	 * Resolving the Delay After Resume Issue see Micron TN-13-07
51042096288SGerlando Falauto 	 * Worst case delay must be 500µs but 30-50µs should be ok as well
51142096288SGerlando Falauto 	 */
51242096288SGerlando Falauto 	if (is_m29ew(cfi))
51342096288SGerlando Falauto 		cfi_udelay(500);
51442096288SGerlando Falauto }
51542096288SGerlando Falauto 
5161da177e4SLinus Torvalds struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
5171da177e4SLinus Torvalds {
5181da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
5191648eaaaSStefan Roese 	struct device_node __maybe_unused *np = map->device_node;
5201da177e4SLinus Torvalds 	struct mtd_info *mtd;
5211da177e4SLinus Torvalds 	int i;
5221da177e4SLinus Torvalds 
52395b93a0cSBurman Yan 	mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
5245c8b1fbbSJingoo Han 	if (!mtd)
5251da177e4SLinus Torvalds 		return NULL;
5261da177e4SLinus Torvalds 	mtd->priv = map;
5271da177e4SLinus Torvalds 	mtd->type = MTD_NORFLASH;
5281da177e4SLinus Torvalds 
5291da177e4SLinus Torvalds 	/* Fill in the default mtd operations */
5303c3c10bbSArtem Bityutskiy 	mtd->_erase   = cfi_amdstd_erase_varsize;
5313c3c10bbSArtem Bityutskiy 	mtd->_write   = cfi_amdstd_write_words;
5323c3c10bbSArtem Bityutskiy 	mtd->_read    = cfi_amdstd_read;
5333c3c10bbSArtem Bityutskiy 	mtd->_sync    = cfi_amdstd_sync;
5343c3c10bbSArtem Bityutskiy 	mtd->_suspend = cfi_amdstd_suspend;
5353c3c10bbSArtem Bityutskiy 	mtd->_resume  = cfi_amdstd_resume;
536dc7e9ecdSChristian Riesch 	mtd->_read_user_prot_reg = cfi_amdstd_read_user_prot_reg;
537dc7e9ecdSChristian Riesch 	mtd->_read_fact_prot_reg = cfi_amdstd_read_fact_prot_reg;
538dc7e9ecdSChristian Riesch 	mtd->_get_fact_prot_info = cfi_amdstd_get_fact_prot_info;
539dc7e9ecdSChristian Riesch 	mtd->_get_user_prot_info = cfi_amdstd_get_user_prot_info;
540af744750SChristian Riesch 	mtd->_write_user_prot_reg = cfi_amdstd_write_user_prot_reg;
5414f5cb243SChristian Riesch 	mtd->_lock_user_prot_reg = cfi_amdstd_lock_user_prot_reg;
5421da177e4SLinus Torvalds 	mtd->flags   = MTD_CAP_NORFLASH;
5431da177e4SLinus Torvalds 	mtd->name    = map->name;
544783ed81fSArtem B. Bityutskiy 	mtd->writesize = 1;
54513ce77f4SAnatolij Gustschin 	mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
546d261c72aSAnatolij Gustschin 
5470a32a102SBrian Norris 	pr_debug("MTD %s(): write buffer size %d\n", __func__,
5480a32a102SBrian Norris 			mtd->writebufsize);
5491da177e4SLinus Torvalds 
5503c3c10bbSArtem Bityutskiy 	mtd->_panic_write = cfi_amdstd_panic_write;
551eafe1311SKevin Cernekee 	mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot;
552eafe1311SKevin Cernekee 
5531da177e4SLinus Torvalds 	if (cfi->cfi_mode==CFI_MODE_CFI){
5541da177e4SLinus Torvalds 		unsigned char bootloc;
5551da177e4SLinus Torvalds 		__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
5561da177e4SLinus Torvalds 		struct cfi_pri_amdstd *extp;
5571da177e4SLinus Torvalds 
5581da177e4SLinus Torvalds 		extp = (struct cfi_pri_amdstd*)cfi_read_pri(map, adr, sizeof(*extp), "Amd/Fujitsu");
559564b8497SGuillaume LECERF 		if (extp) {
560564b8497SGuillaume LECERF 			/*
561564b8497SGuillaume LECERF 			 * It's a real CFI chip, not one for which the probe
562564b8497SGuillaume LECERF 			 * routine faked a CFI structure.
563564b8497SGuillaume LECERF 			 */
564fefae48bSWolfgang Grandegger 			cfi_fixup_major_minor(cfi, extp);
565fefae48bSWolfgang Grandegger 
566e17f47a1SGuillaume LECERF 			/*
567c9ddab25SGernot Hoyler 			 * Valid primary extension versions are: 1.0, 1.1, 1.2, 1.3, 1.4, 1.5
568631dd1a8SJustin P. Mattock 			 * see: http://cs.ozerki.net/zap/pub/axim-x5/docs/cfi_r20.pdf, page 19
569631dd1a8SJustin P. Mattock 			 *      http://www.spansion.com/Support/AppNotes/cfi_100_20011201.pdf
5705da19532SGuillaume LECERF 			 *      http://www.spansion.com/Support/Datasheets/s29ws-p_00_a12_e.pdf
571c9ddab25SGernot Hoyler 			 *      http://www.spansion.com/Support/Datasheets/S29GL_128S_01GS_00_02_e.pdf
572e17f47a1SGuillaume LECERF 			 */
573d88f977bSTodd Poynor 			if (extp->MajorVersion != '1' ||
574c9ddab25SGernot Hoyler 			    (extp->MajorVersion == '1' && (extp->MinorVersion < '0' || extp->MinorVersion > '5'))) {
575d88f977bSTodd Poynor 				printk(KERN_ERR "  Unknown Amd/Fujitsu Extended Query "
576e17f47a1SGuillaume LECERF 				       "version %c.%c (%#02x/%#02x).\n",
577e17f47a1SGuillaume LECERF 				       extp->MajorVersion, extp->MinorVersion,
578e17f47a1SGuillaume LECERF 				       extp->MajorVersion, extp->MinorVersion);
579d88f977bSTodd Poynor 				kfree(extp);
580d88f977bSTodd Poynor 				kfree(mtd);
581d88f977bSTodd Poynor 				return NULL;
582d88f977bSTodd Poynor 			}
583d88f977bSTodd Poynor 
584e17f47a1SGuillaume LECERF 			printk(KERN_INFO "  Amd/Fujitsu Extended Query version %c.%c.\n",
585e17f47a1SGuillaume LECERF 			       extp->MajorVersion, extp->MinorVersion);
586e17f47a1SGuillaume LECERF 
5871da177e4SLinus Torvalds 			/* Install our own private info structure */
5881da177e4SLinus Torvalds 			cfi->cmdset_priv = extp;
5891da177e4SLinus Torvalds 
5901da177e4SLinus Torvalds 			/* Apply cfi device specific fixups */
5911da177e4SLinus Torvalds 			cfi_fixup(mtd, cfi_fixup_table);
5921da177e4SLinus Torvalds 
5931da177e4SLinus Torvalds #ifdef DEBUG_CFI_FEATURES
5941da177e4SLinus Torvalds 			/* Tell the user about it in lots of lovely detail */
5951da177e4SLinus Torvalds 			cfi_tell_features(extp);
5961da177e4SLinus Torvalds #endif
5971da177e4SLinus Torvalds 
5981648eaaaSStefan Roese #ifdef CONFIG_OF
5991648eaaaSStefan Roese 			if (np && of_property_read_bool(
6001648eaaaSStefan Roese 				    np, "use-advanced-sector-protection")
6011648eaaaSStefan Roese 			    && extp->BlkProtUnprot == 8) {
6021648eaaaSStefan Roese 				printk(KERN_INFO "  Advanced Sector Protection (PPB Locking) supported\n");
6031648eaaaSStefan Roese 				mtd->_lock = cfi_ppb_lock;
6041648eaaaSStefan Roese 				mtd->_unlock = cfi_ppb_unlock;
6051648eaaaSStefan Roese 				mtd->_is_locked = cfi_ppb_is_locked;
6061648eaaaSStefan Roese 			}
6071648eaaaSStefan Roese #endif
6081648eaaaSStefan Roese 
6091da177e4SLinus Torvalds 			bootloc = extp->TopBottom;
610412da2f6SDavid Woodhouse 			if ((bootloc < 2) || (bootloc > 5)) {
611412da2f6SDavid Woodhouse 				printk(KERN_WARNING "%s: CFI contains unrecognised boot "
612412da2f6SDavid Woodhouse 				       "bank location (%d). Assuming bottom.\n",
613abab7ebfSDavid Woodhouse 				       map->name, bootloc);
6141da177e4SLinus Torvalds 				bootloc = 2;
6151da177e4SLinus Torvalds 			}
6161da177e4SLinus Torvalds 
6171da177e4SLinus Torvalds 			if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) {
618412da2f6SDavid Woodhouse 				printk(KERN_WARNING "%s: Swapping erase regions for top-boot CFI table.\n", map->name);
6191da177e4SLinus Torvalds 
6201da177e4SLinus Torvalds 				for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) {
6211da177e4SLinus Torvalds 					int j = (cfi->cfiq->NumEraseRegions-1)-i;
6221da177e4SLinus Torvalds 
623fdd9d27cSFabian Frederick 					swap(cfi->cfiq->EraseRegionInfo[i],
624fdd9d27cSFabian Frederick 					     cfi->cfiq->EraseRegionInfo[j]);
6251da177e4SLinus Torvalds 				}
6261da177e4SLinus Torvalds 			}
6271da177e4SLinus Torvalds 			/* Set the default CFI lock/unlock addresses */
6281da177e4SLinus Torvalds 			cfi->addr_unlock1 = 0x555;
6291da177e4SLinus Torvalds 			cfi->addr_unlock2 = 0x2aa;
630564b8497SGuillaume LECERF 		}
63183dcd3bbSGuillaume LECERF 		cfi_fixup(mtd, cfi_nopri_fixup_table);
632564b8497SGuillaume LECERF 
633564b8497SGuillaume LECERF 		if (!cfi->addr_unlock1 || !cfi->addr_unlock2) {
634564b8497SGuillaume LECERF 			kfree(mtd);
635564b8497SGuillaume LECERF 			return NULL;
636564b8497SGuillaume LECERF 		}
6371da177e4SLinus Torvalds 
6381da177e4SLinus Torvalds 	} /* CFI mode */
6391da177e4SLinus Torvalds 	else if (cfi->cfi_mode == CFI_MODE_JEDEC) {
6401da177e4SLinus Torvalds 		/* Apply jedec specific fixups */
6411da177e4SLinus Torvalds 		cfi_fixup(mtd, jedec_fixup_table);
6421da177e4SLinus Torvalds 	}
6431da177e4SLinus Torvalds 	/* Apply generic fixups */
6441da177e4SLinus Torvalds 	cfi_fixup(mtd, fixup_table);
6451da177e4SLinus Torvalds 
6461da177e4SLinus Torvalds 	for (i=0; i< cfi->numchips; i++) {
6471da177e4SLinus Torvalds 		cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
6481da177e4SLinus Torvalds 		cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
6491da177e4SLinus Torvalds 		cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
6506534e680SBean Huo 		/*
6516534e680SBean Huo 		 * First calculate the timeout max according to timeout field
6526534e680SBean Huo 		 * of struct cfi_ident that probed from chip's CFI aera, if
6536534e680SBean Huo 		 * available. Specify a minimum of 2000us, in case the CFI data
6546534e680SBean Huo 		 * is wrong.
6556534e680SBean Huo 		 */
6566534e680SBean Huo 		if (cfi->cfiq->BufWriteTimeoutTyp &&
6576534e680SBean Huo 		    cfi->cfiq->BufWriteTimeoutMax)
6586534e680SBean Huo 			cfi->chips[i].buffer_write_time_max =
6596534e680SBean Huo 				1 << (cfi->cfiq->BufWriteTimeoutTyp +
6606534e680SBean Huo 				      cfi->cfiq->BufWriteTimeoutMax);
6616534e680SBean Huo 		else
6626534e680SBean Huo 			cfi->chips[i].buffer_write_time_max = 0;
6636534e680SBean Huo 
6646534e680SBean Huo 		cfi->chips[i].buffer_write_time_max =
6656534e680SBean Huo 			max(cfi->chips[i].buffer_write_time_max, 2000);
6666534e680SBean Huo 
66783d48091SVijay Sampath 		cfi->chips[i].ref_point_counter = 0;
66883d48091SVijay Sampath 		init_waitqueue_head(&(cfi->chips[i].wq));
6691da177e4SLinus Torvalds 	}
6701da177e4SLinus Torvalds 
6711da177e4SLinus Torvalds 	map->fldrv = &cfi_amdstd_chipdrv;
6721da177e4SLinus Torvalds 
6731da177e4SLinus Torvalds 	return cfi_amdstd_setup(mtd);
6741da177e4SLinus Torvalds }
67580461128SGuillaume LECERF struct mtd_info *cfi_cmdset_0006(struct map_info *map, int primary) __attribute__((alias("cfi_cmdset_0002")));
6761e804cecSDavid Woodhouse struct mtd_info *cfi_cmdset_0701(struct map_info *map, int primary) __attribute__((alias("cfi_cmdset_0002")));
67783ea4ef2SDavid Woodhouse EXPORT_SYMBOL_GPL(cfi_cmdset_0002);
67880461128SGuillaume LECERF EXPORT_SYMBOL_GPL(cfi_cmdset_0006);
6791e804cecSDavid Woodhouse EXPORT_SYMBOL_GPL(cfi_cmdset_0701);
6801da177e4SLinus Torvalds 
6811da177e4SLinus Torvalds static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
6821da177e4SLinus Torvalds {
6831da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
6841da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
6851da177e4SLinus Torvalds 	unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
6861da177e4SLinus Torvalds 	unsigned long offset = 0;
6871da177e4SLinus Torvalds 	int i,j;
6881da177e4SLinus Torvalds 
6891da177e4SLinus Torvalds 	printk(KERN_NOTICE "number of %s chips: %d\n",
6901da177e4SLinus Torvalds 	       (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips);
6911da177e4SLinus Torvalds 	/* Select the correct geometry setup */
6921da177e4SLinus Torvalds 	mtd->size = devsize * cfi->numchips;
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds 	mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
6951da177e4SLinus Torvalds 	mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
6961da177e4SLinus Torvalds 				    * mtd->numeraseregions, GFP_KERNEL);
6975c8b1fbbSJingoo Han 	if (!mtd->eraseregions)
6981da177e4SLinus Torvalds 		goto setup_err;
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds 	for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
7011da177e4SLinus Torvalds 		unsigned long ernum, ersize;
7021da177e4SLinus Torvalds 		ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
7031da177e4SLinus Torvalds 		ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
7041da177e4SLinus Torvalds 
7051da177e4SLinus Torvalds 		if (mtd->erasesize < ersize) {
7061da177e4SLinus Torvalds 			mtd->erasesize = ersize;
7071da177e4SLinus Torvalds 		}
7081da177e4SLinus Torvalds 		for (j=0; j<cfi->numchips; j++) {
7091da177e4SLinus Torvalds 			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
7101da177e4SLinus Torvalds 			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
7111da177e4SLinus Torvalds 			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
7121da177e4SLinus Torvalds 		}
7131da177e4SLinus Torvalds 		offset += (ersize * ernum);
7141da177e4SLinus Torvalds 	}
7151da177e4SLinus Torvalds 	if (offset != devsize) {
7161da177e4SLinus Torvalds 		/* Argh */
7171da177e4SLinus Torvalds 		printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
7181da177e4SLinus Torvalds 		goto setup_err;
7191da177e4SLinus Torvalds 	}
7201da177e4SLinus Torvalds 
7211da177e4SLinus Torvalds 	__module_get(THIS_MODULE);
722eafe1311SKevin Cernekee 	register_reboot_notifier(&mtd->reboot_notifier);
7231da177e4SLinus Torvalds 	return mtd;
7241da177e4SLinus Torvalds 
7251da177e4SLinus Torvalds  setup_err:
7261da177e4SLinus Torvalds 	kfree(mtd->eraseregions);
7271da177e4SLinus Torvalds 	kfree(mtd);
7281da177e4SLinus Torvalds 	kfree(cfi->cmdset_priv);
7291da177e4SLinus Torvalds 	kfree(cfi->cfiq);
7301da177e4SLinus Torvalds 	return NULL;
7311da177e4SLinus Torvalds }
7321da177e4SLinus Torvalds 
7331da177e4SLinus Torvalds /*
7341da177e4SLinus Torvalds  * Return true if the chip is ready.
7351da177e4SLinus Torvalds  *
7361da177e4SLinus Torvalds  * Ready is one of: read mode, query mode, erase-suspend-read mode (in any
7371da177e4SLinus Torvalds  * non-suspended sector) and is indicated by no toggle bits toggling.
7381da177e4SLinus Torvalds  *
7391da177e4SLinus Torvalds  * Note that anything more complicated than checking if no bits are toggling
7401da177e4SLinus Torvalds  * (including checking DQ5 for an error status) is tricky to get working
74125985edcSLucas De Marchi  * correctly and is therefore not done	(particularly with interleaved chips
74225985edcSLucas De Marchi  * as each chip must be checked independently of the others).
7431da177e4SLinus Torvalds  */
74402b15e34STodd Poynor static int __xipram chip_ready(struct map_info *map, unsigned long addr)
7451da177e4SLinus Torvalds {
7461da177e4SLinus Torvalds 	map_word d, t;
7471da177e4SLinus Torvalds 
7481da177e4SLinus Torvalds 	d = map_read(map, addr);
7491da177e4SLinus Torvalds 	t = map_read(map, addr);
7501da177e4SLinus Torvalds 
7511da177e4SLinus Torvalds 	return map_word_equal(map, d, t);
7521da177e4SLinus Torvalds }
7531da177e4SLinus Torvalds 
754fb4a90bfSEric W. Biedermann /*
755fb4a90bfSEric W. Biedermann  * Return true if the chip is ready and has the correct value.
756fb4a90bfSEric W. Biedermann  *
757fb4a90bfSEric W. Biedermann  * Ready is one of: read mode, query mode, erase-suspend-read mode (in any
758fb4a90bfSEric W. Biedermann  * non-suspended sector) and it is indicated by no bits toggling.
759fb4a90bfSEric W. Biedermann  *
760fb4a90bfSEric W. Biedermann  * Error are indicated by toggling bits or bits held with the wrong value,
761fb4a90bfSEric W. Biedermann  * or with bits toggling.
762fb4a90bfSEric W. Biedermann  *
763fb4a90bfSEric W. Biedermann  * Note that anything more complicated than checking if no bits are toggling
764fb4a90bfSEric W. Biedermann  * (including checking DQ5 for an error status) is tricky to get working
76525985edcSLucas De Marchi  * correctly and is therefore not done	(particularly with interleaved chips
76625985edcSLucas De Marchi  * as each chip must be checked independently of the others).
767fb4a90bfSEric W. Biedermann  *
768fb4a90bfSEric W. Biedermann  */
76902b15e34STodd Poynor static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word expected)
770fb4a90bfSEric W. Biedermann {
771fb4a90bfSEric W. Biedermann 	map_word oldd, curd;
772fb4a90bfSEric W. Biedermann 
773fb4a90bfSEric W. Biedermann 	oldd = map_read(map, addr);
774fb4a90bfSEric W. Biedermann 	curd = map_read(map, addr);
775fb4a90bfSEric W. Biedermann 
776fb4a90bfSEric W. Biedermann 	return	map_word_equal(map, oldd, curd) &&
777fb4a90bfSEric W. Biedermann 		map_word_equal(map, curd, expected);
778fb4a90bfSEric W. Biedermann }
779fb4a90bfSEric W. Biedermann 
7801da177e4SLinus Torvalds static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
7811da177e4SLinus Torvalds {
7821da177e4SLinus Torvalds 	DECLARE_WAITQUEUE(wait, current);
7831da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
7841da177e4SLinus Torvalds 	unsigned long timeo;
7851da177e4SLinus Torvalds 	struct cfi_pri_amdstd *cfip = (struct cfi_pri_amdstd *)cfi->cmdset_priv;
7861da177e4SLinus Torvalds 
7871da177e4SLinus Torvalds  resettime:
7881da177e4SLinus Torvalds 	timeo = jiffies + HZ;
7891da177e4SLinus Torvalds  retry:
7901da177e4SLinus Torvalds 	switch (chip->state) {
7911da177e4SLinus Torvalds 
7921da177e4SLinus Torvalds 	case FL_STATUS:
7931da177e4SLinus Torvalds 		for (;;) {
7941da177e4SLinus Torvalds 			if (chip_ready(map, adr))
7951da177e4SLinus Torvalds 				break;
7961da177e4SLinus Torvalds 
7971da177e4SLinus Torvalds 			if (time_after(jiffies, timeo)) {
7981da177e4SLinus Torvalds 				printk(KERN_ERR "Waiting for chip to be ready timed out.\n");
7991da177e4SLinus Torvalds 				return -EIO;
8001da177e4SLinus Torvalds 			}
801c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
8021da177e4SLinus Torvalds 			cfi_udelay(1);
803c4e77376SStefani Seibold 			mutex_lock(&chip->mutex);
8041da177e4SLinus Torvalds 			/* Someone else might have been playing with it. */
8051da177e4SLinus Torvalds 			goto retry;
8061da177e4SLinus Torvalds 		}
8071da177e4SLinus Torvalds 
8081da177e4SLinus Torvalds 	case FL_READY:
8091da177e4SLinus Torvalds 	case FL_CFI_QUERY:
8101da177e4SLinus Torvalds 	case FL_JEDEC_QUERY:
8111da177e4SLinus Torvalds 		return 0;
8121da177e4SLinus Torvalds 
8131da177e4SLinus Torvalds 	case FL_ERASING:
8142695eab9SJoakim Tjernlund 		if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
8152695eab9SJoakim Tjernlund 		    !(mode == FL_READY || mode == FL_POINT ||
8162695eab9SJoakim Tjernlund 		    (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
8171da177e4SLinus Torvalds 			goto sleep;
8181da177e4SLinus Torvalds 
8197b70eb14SJoakim Tjernlund 		/* Do not allow suspend iff read/write to EB address */
8207b70eb14SJoakim Tjernlund 		if ((adr & chip->in_progress_block_mask) ==
8217b70eb14SJoakim Tjernlund 		    chip->in_progress_block_addr)
8227b70eb14SJoakim Tjernlund 			goto sleep;
8231da177e4SLinus Torvalds 
8241da177e4SLinus Torvalds 		/* Erase suspend */
8251da177e4SLinus Torvalds 		/* It's harmless to issue the Erase-Suspend and Erase-Resume
8261da177e4SLinus Torvalds 		 * commands when the erase algorithm isn't in progress. */
8271da177e4SLinus Torvalds 		map_write(map, CMD(0xB0), chip->in_progress_block_addr);
8281da177e4SLinus Torvalds 		chip->oldstate = FL_ERASING;
8291da177e4SLinus Torvalds 		chip->state = FL_ERASE_SUSPENDING;
8301da177e4SLinus Torvalds 		chip->erase_suspended = 1;
8311da177e4SLinus Torvalds 		for (;;) {
8321da177e4SLinus Torvalds 			if (chip_ready(map, adr))
8331da177e4SLinus Torvalds 				break;
8341da177e4SLinus Torvalds 
8351da177e4SLinus Torvalds 			if (time_after(jiffies, timeo)) {
8361da177e4SLinus Torvalds 				/* Should have suspended the erase by now.
8371da177e4SLinus Torvalds 				 * Send an Erase-Resume command as either
8381da177e4SLinus Torvalds 				 * there was an error (so leave the erase
8391da177e4SLinus Torvalds 				 * routine to recover from it) or we trying to
8401da177e4SLinus Torvalds 				 * use the erase-in-progress sector. */
841100f2341STadashi Abe 				put_chip(map, chip, adr);
8421da177e4SLinus Torvalds 				printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__);
8431da177e4SLinus Torvalds 				return -EIO;
8441da177e4SLinus Torvalds 			}
8451da177e4SLinus Torvalds 
846c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
8471da177e4SLinus Torvalds 			cfi_udelay(1);
848c4e77376SStefani Seibold 			mutex_lock(&chip->mutex);
8491da177e4SLinus Torvalds 			/* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
8501da177e4SLinus Torvalds 			   So we can just loop here. */
8511da177e4SLinus Torvalds 		}
8521da177e4SLinus Torvalds 		chip->state = FL_READY;
8531da177e4SLinus Torvalds 		return 0;
8541da177e4SLinus Torvalds 
85502b15e34STodd Poynor 	case FL_XIP_WHILE_ERASING:
85602b15e34STodd Poynor 		if (mode != FL_READY && mode != FL_POINT &&
85702b15e34STodd Poynor 		    (!cfip || !(cfip->EraseSuspend&2)))
85802b15e34STodd Poynor 			goto sleep;
85902b15e34STodd Poynor 		chip->oldstate = chip->state;
86002b15e34STodd Poynor 		chip->state = FL_READY;
86102b15e34STodd Poynor 		return 0;
86202b15e34STodd Poynor 
863eafe1311SKevin Cernekee 	case FL_SHUTDOWN:
864eafe1311SKevin Cernekee 		/* The machine is rebooting */
865eafe1311SKevin Cernekee 		return -EIO;
866eafe1311SKevin Cernekee 
8671da177e4SLinus Torvalds 	case FL_POINT:
8681da177e4SLinus Torvalds 		/* Only if there's no operation suspended... */
8691da177e4SLinus Torvalds 		if (mode == FL_READY && chip->oldstate == FL_READY)
8701da177e4SLinus Torvalds 			return 0;
8711da177e4SLinus Torvalds 
8721da177e4SLinus Torvalds 	default:
8731da177e4SLinus Torvalds 	sleep:
8741da177e4SLinus Torvalds 		set_current_state(TASK_UNINTERRUPTIBLE);
8751da177e4SLinus Torvalds 		add_wait_queue(&chip->wq, &wait);
876c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
8771da177e4SLinus Torvalds 		schedule();
8781da177e4SLinus Torvalds 		remove_wait_queue(&chip->wq, &wait);
879c4e77376SStefani Seibold 		mutex_lock(&chip->mutex);
8801da177e4SLinus Torvalds 		goto resettime;
8811da177e4SLinus Torvalds 	}
8821da177e4SLinus Torvalds }
8831da177e4SLinus Torvalds 
8841da177e4SLinus Torvalds 
8851da177e4SLinus Torvalds static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr)
8861da177e4SLinus Torvalds {
8871da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
8881da177e4SLinus Torvalds 
8891da177e4SLinus Torvalds 	switch(chip->oldstate) {
8901da177e4SLinus Torvalds 	case FL_ERASING:
89142096288SGerlando Falauto 		cfi_fixup_m29ew_erase_suspend(map,
89242096288SGerlando Falauto 			chip->in_progress_block_addr);
89308968041SGuillaume LECERF 		map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr);
89442096288SGerlando Falauto 		cfi_fixup_m29ew_delay_after_resume(cfi);
8951da177e4SLinus Torvalds 		chip->oldstate = FL_READY;
8961da177e4SLinus Torvalds 		chip->state = FL_ERASING;
8971da177e4SLinus Torvalds 		break;
8981da177e4SLinus Torvalds 
89902b15e34STodd Poynor 	case FL_XIP_WHILE_ERASING:
90002b15e34STodd Poynor 		chip->state = chip->oldstate;
90102b15e34STodd Poynor 		chip->oldstate = FL_READY;
90202b15e34STodd Poynor 		break;
90302b15e34STodd Poynor 
9041da177e4SLinus Torvalds 	case FL_READY:
9051da177e4SLinus Torvalds 	case FL_STATUS:
9061da177e4SLinus Torvalds 		break;
9071da177e4SLinus Torvalds 	default:
9081da177e4SLinus Torvalds 		printk(KERN_ERR "MTD: put_chip() called with oldstate %d!!\n", chip->oldstate);
9091da177e4SLinus Torvalds 	}
9101da177e4SLinus Torvalds 	wake_up(&chip->wq);
9111da177e4SLinus Torvalds }
9121da177e4SLinus Torvalds 
91302b15e34STodd Poynor #ifdef CONFIG_MTD_XIP
91402b15e34STodd Poynor 
91502b15e34STodd Poynor /*
91602b15e34STodd Poynor  * No interrupt what so ever can be serviced while the flash isn't in array
91702b15e34STodd Poynor  * mode.  This is ensured by the xip_disable() and xip_enable() functions
91802b15e34STodd Poynor  * enclosing any code path where the flash is known not to be in array mode.
91902b15e34STodd Poynor  * And within a XIP disabled code path, only functions marked with __xipram
92002b15e34STodd Poynor  * may be called and nothing else (it's a good thing to inspect generated
92102b15e34STodd Poynor  * assembly to make sure inline functions were actually inlined and that gcc
92202b15e34STodd Poynor  * didn't emit calls to its own support functions). Also configuring MTD CFI
92302b15e34STodd Poynor  * support to a single buswidth and a single interleave is also recommended.
92402b15e34STodd Poynor  */
925f8eb321bSThomas Gleixner 
92602b15e34STodd Poynor static void xip_disable(struct map_info *map, struct flchip *chip,
92702b15e34STodd Poynor 			unsigned long adr)
92802b15e34STodd Poynor {
92902b15e34STodd Poynor 	/* TODO: chips with no XIP use should ignore and return */
93002b15e34STodd Poynor 	(void) map_read(map, adr); /* ensure mmu mapping is up to date */
93102b15e34STodd Poynor 	local_irq_disable();
93202b15e34STodd Poynor }
93302b15e34STodd Poynor 
93402b15e34STodd Poynor static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
93502b15e34STodd Poynor 				unsigned long adr)
93602b15e34STodd Poynor {
93702b15e34STodd Poynor 	struct cfi_private *cfi = map->fldrv_priv;
93802b15e34STodd Poynor 
93902b15e34STodd Poynor 	if (chip->state != FL_POINT && chip->state != FL_READY) {
94002b15e34STodd Poynor 		map_write(map, CMD(0xf0), adr);
94102b15e34STodd Poynor 		chip->state = FL_READY;
94202b15e34STodd Poynor 	}
94302b15e34STodd Poynor 	(void) map_read(map, adr);
94497f927a4SThomas Gleixner 	xip_iprefetch();
94502b15e34STodd Poynor 	local_irq_enable();
94602b15e34STodd Poynor }
94702b15e34STodd Poynor 
94802b15e34STodd Poynor /*
94902b15e34STodd Poynor  * When a delay is required for the flash operation to complete, the
95002b15e34STodd Poynor  * xip_udelay() function is polling for both the given timeout and pending
95102b15e34STodd Poynor  * (but still masked) hardware interrupts.  Whenever there is an interrupt
95202b15e34STodd Poynor  * pending then the flash erase operation is suspended, array mode restored
95302b15e34STodd Poynor  * and interrupts unmasked.  Task scheduling might also happen at that
95402b15e34STodd Poynor  * point.  The CPU eventually returns from the interrupt or the call to
95502b15e34STodd Poynor  * schedule() and the suspended flash operation is resumed for the remaining
95602b15e34STodd Poynor  * of the delay period.
95702b15e34STodd Poynor  *
95802b15e34STodd Poynor  * Warning: this function _will_ fool interrupt latency tracing tools.
95902b15e34STodd Poynor  */
96002b15e34STodd Poynor 
96102b15e34STodd Poynor static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
96202b15e34STodd Poynor 				unsigned long adr, int usec)
96302b15e34STodd Poynor {
96402b15e34STodd Poynor 	struct cfi_private *cfi = map->fldrv_priv;
96502b15e34STodd Poynor 	struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
96602b15e34STodd Poynor 	map_word status, OK = CMD(0x80);
96702b15e34STodd Poynor 	unsigned long suspended, start = xip_currtime();
96802b15e34STodd Poynor 	flstate_t oldstate;
96902b15e34STodd Poynor 
97002b15e34STodd Poynor 	do {
97102b15e34STodd Poynor 		cpu_relax();
97202b15e34STodd Poynor 		if (xip_irqpending() && extp &&
97302b15e34STodd Poynor 		    ((chip->state == FL_ERASING && (extp->EraseSuspend & 2))) &&
97402b15e34STodd Poynor 		    (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) {
97502b15e34STodd Poynor 			/*
97602b15e34STodd Poynor 			 * Let's suspend the erase operation when supported.
97702b15e34STodd Poynor 			 * Note that we currently don't try to suspend
97802b15e34STodd Poynor 			 * interleaved chips if there is already another
97902b15e34STodd Poynor 			 * operation suspended (imagine what happens
98002b15e34STodd Poynor 			 * when one chip was already done with the current
98102b15e34STodd Poynor 			 * operation while another chip suspended it, then
98202b15e34STodd Poynor 			 * we resume the whole thing at once).  Yes, it
98302b15e34STodd Poynor 			 * can happen!
98402b15e34STodd Poynor 			 */
98502b15e34STodd Poynor 			map_write(map, CMD(0xb0), adr);
98602b15e34STodd Poynor 			usec -= xip_elapsed_since(start);
98702b15e34STodd Poynor 			suspended = xip_currtime();
98802b15e34STodd Poynor 			do {
98902b15e34STodd Poynor 				if (xip_elapsed_since(suspended) > 100000) {
99002b15e34STodd Poynor 					/*
99102b15e34STodd Poynor 					 * The chip doesn't want to suspend
99202b15e34STodd Poynor 					 * after waiting for 100 msecs.
99302b15e34STodd Poynor 					 * This is a critical error but there
99402b15e34STodd Poynor 					 * is not much we can do here.
99502b15e34STodd Poynor 					 */
99602b15e34STodd Poynor 					return;
99702b15e34STodd Poynor 				}
99802b15e34STodd Poynor 				status = map_read(map, adr);
99902b15e34STodd Poynor 			} while (!map_word_andequal(map, status, OK, OK));
100002b15e34STodd Poynor 
100102b15e34STodd Poynor 			/* Suspend succeeded */
100202b15e34STodd Poynor 			oldstate = chip->state;
100302b15e34STodd Poynor 			if (!map_word_bitsset(map, status, CMD(0x40)))
100402b15e34STodd Poynor 				break;
100502b15e34STodd Poynor 			chip->state = FL_XIP_WHILE_ERASING;
100602b15e34STodd Poynor 			chip->erase_suspended = 1;
100702b15e34STodd Poynor 			map_write(map, CMD(0xf0), adr);
100802b15e34STodd Poynor 			(void) map_read(map, adr);
1009ca5c23c3SPaulius Zaleckas 			xip_iprefetch();
101002b15e34STodd Poynor 			local_irq_enable();
1011c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
1012ca5c23c3SPaulius Zaleckas 			xip_iprefetch();
101302b15e34STodd Poynor 			cond_resched();
101402b15e34STodd Poynor 
101502b15e34STodd Poynor 			/*
101602b15e34STodd Poynor 			 * We're back.  However someone else might have
101702b15e34STodd Poynor 			 * decided to go write to the chip if we are in
101802b15e34STodd Poynor 			 * a suspended erase state.  If so let's wait
101902b15e34STodd Poynor 			 * until it's done.
102002b15e34STodd Poynor 			 */
1021c4e77376SStefani Seibold 			mutex_lock(&chip->mutex);
102202b15e34STodd Poynor 			while (chip->state != FL_XIP_WHILE_ERASING) {
102302b15e34STodd Poynor 				DECLARE_WAITQUEUE(wait, current);
102402b15e34STodd Poynor 				set_current_state(TASK_UNINTERRUPTIBLE);
102502b15e34STodd Poynor 				add_wait_queue(&chip->wq, &wait);
1026c4e77376SStefani Seibold 				mutex_unlock(&chip->mutex);
102702b15e34STodd Poynor 				schedule();
102802b15e34STodd Poynor 				remove_wait_queue(&chip->wq, &wait);
1029c4e77376SStefani Seibold 				mutex_lock(&chip->mutex);
103002b15e34STodd Poynor 			}
103102b15e34STodd Poynor 			/* Disallow XIP again */
103202b15e34STodd Poynor 			local_irq_disable();
103302b15e34STodd Poynor 
103442096288SGerlando Falauto 			/* Correct Erase Suspend Hangups for M29EW */
103542096288SGerlando Falauto 			cfi_fixup_m29ew_erase_suspend(map, adr);
103602b15e34STodd Poynor 			/* Resume the write or erase operation */
103708968041SGuillaume LECERF 			map_write(map, cfi->sector_erase_cmd, adr);
103802b15e34STodd Poynor 			chip->state = oldstate;
103902b15e34STodd Poynor 			start = xip_currtime();
104002b15e34STodd Poynor 		} else if (usec >= 1000000/HZ) {
104102b15e34STodd Poynor 			/*
104202b15e34STodd Poynor 			 * Try to save on CPU power when waiting delay
104302b15e34STodd Poynor 			 * is at least a system timer tick period.
104402b15e34STodd Poynor 			 * No need to be extremely accurate here.
104502b15e34STodd Poynor 			 */
104602b15e34STodd Poynor 			xip_cpu_idle();
104702b15e34STodd Poynor 		}
104802b15e34STodd Poynor 		status = map_read(map, adr);
104902b15e34STodd Poynor 	} while (!map_word_andequal(map, status, OK, OK)
105002b15e34STodd Poynor 		 && xip_elapsed_since(start) < usec);
105102b15e34STodd Poynor }
105202b15e34STodd Poynor 
105302b15e34STodd Poynor #define UDELAY(map, chip, adr, usec)  xip_udelay(map, chip, adr, usec)
105402b15e34STodd Poynor 
105502b15e34STodd Poynor /*
105602b15e34STodd Poynor  * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
105702b15e34STodd Poynor  * the flash is actively programming or erasing since we have to poll for
105802b15e34STodd Poynor  * the operation to complete anyway.  We can't do that in a generic way with
105902b15e34STodd Poynor  * a XIP setup so do it before the actual flash operation in this case
106002b15e34STodd Poynor  * and stub it out from INVALIDATE_CACHE_UDELAY.
106102b15e34STodd Poynor  */
106202b15e34STodd Poynor #define XIP_INVAL_CACHED_RANGE(map, from, size)  \
106302b15e34STodd Poynor 	INVALIDATE_CACHED_RANGE(map, from, size)
106402b15e34STodd Poynor 
106502b15e34STodd Poynor #define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec)  \
106602b15e34STodd Poynor 	UDELAY(map, chip, adr, usec)
106702b15e34STodd Poynor 
106802b15e34STodd Poynor /*
106902b15e34STodd Poynor  * Extra notes:
107002b15e34STodd Poynor  *
107102b15e34STodd Poynor  * Activating this XIP support changes the way the code works a bit.  For
107202b15e34STodd Poynor  * example the code to suspend the current process when concurrent access
107302b15e34STodd Poynor  * happens is never executed because xip_udelay() will always return with the
107402b15e34STodd Poynor  * same chip state as it was entered with.  This is why there is no care for
107502b15e34STodd Poynor  * the presence of add_wait_queue() or schedule() calls from within a couple
107602b15e34STodd Poynor  * xip_disable()'d  areas of code, like in do_erase_oneblock for example.
107702b15e34STodd Poynor  * The queueing and scheduling are always happening within xip_udelay().
107802b15e34STodd Poynor  *
107902b15e34STodd Poynor  * Similarly, get_chip() and put_chip() just happen to always be executed
108002b15e34STodd Poynor  * with chip->state set to FL_READY (or FL_XIP_WHILE_*) where flash state
108102b15e34STodd Poynor  * is in array mode, therefore never executing many cases therein and not
108202b15e34STodd Poynor  * causing any problem with XIP.
108302b15e34STodd Poynor  */
108402b15e34STodd Poynor 
108502b15e34STodd Poynor #else
108602b15e34STodd Poynor 
108702b15e34STodd Poynor #define xip_disable(map, chip, adr)
108802b15e34STodd Poynor #define xip_enable(map, chip, adr)
108902b15e34STodd Poynor #define XIP_INVAL_CACHED_RANGE(x...)
109002b15e34STodd Poynor 
109102b15e34STodd Poynor #define UDELAY(map, chip, adr, usec)  \
109202b15e34STodd Poynor do {  \
1093c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);  \
109402b15e34STodd Poynor 	cfi_udelay(usec);  \
1095c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);  \
109602b15e34STodd Poynor } while (0)
109702b15e34STodd Poynor 
109802b15e34STodd Poynor #define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec)  \
109902b15e34STodd Poynor do {  \
1100c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);  \
110102b15e34STodd Poynor 	INVALIDATE_CACHED_RANGE(map, adr, len);  \
110202b15e34STodd Poynor 	cfi_udelay(usec);  \
1103c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);  \
110402b15e34STodd Poynor } while (0)
110502b15e34STodd Poynor 
110602b15e34STodd Poynor #endif
11071da177e4SLinus Torvalds 
11081da177e4SLinus Torvalds static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
11091da177e4SLinus Torvalds {
11101da177e4SLinus Torvalds 	unsigned long cmd_addr;
11111da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
11121da177e4SLinus Torvalds 	int ret;
11131da177e4SLinus Torvalds 
11141da177e4SLinus Torvalds 	adr += chip->start;
11151da177e4SLinus Torvalds 
11161da177e4SLinus Torvalds 	/* Ensure cmd read/writes are aligned. */
11171da177e4SLinus Torvalds 	cmd_addr = adr & ~(map_bankwidth(map)-1);
11181da177e4SLinus Torvalds 
1119c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);
11201da177e4SLinus Torvalds 	ret = get_chip(map, chip, cmd_addr, FL_READY);
11211da177e4SLinus Torvalds 	if (ret) {
1122c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
11231da177e4SLinus Torvalds 		return ret;
11241da177e4SLinus Torvalds 	}
11251da177e4SLinus Torvalds 
11261da177e4SLinus Torvalds 	if (chip->state != FL_POINT && chip->state != FL_READY) {
11271da177e4SLinus Torvalds 		map_write(map, CMD(0xf0), cmd_addr);
11281da177e4SLinus Torvalds 		chip->state = FL_READY;
11291da177e4SLinus Torvalds 	}
11301da177e4SLinus Torvalds 
11311da177e4SLinus Torvalds 	map_copy_from(map, buf, adr, len);
11321da177e4SLinus Torvalds 
11331da177e4SLinus Torvalds 	put_chip(map, chip, cmd_addr);
11341da177e4SLinus Torvalds 
1135c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);
11361da177e4SLinus Torvalds 	return 0;
11371da177e4SLinus Torvalds }
11381da177e4SLinus Torvalds 
11391da177e4SLinus Torvalds 
11401da177e4SLinus Torvalds static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
11411da177e4SLinus Torvalds {
11421da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
11431da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
11441da177e4SLinus Torvalds 	unsigned long ofs;
11451da177e4SLinus Torvalds 	int chipnum;
11461da177e4SLinus Torvalds 	int ret = 0;
11471da177e4SLinus Torvalds 
11481da177e4SLinus Torvalds 	/* ofs: offset within the first chip that the first read should start */
11491da177e4SLinus Torvalds 	chipnum = (from >> cfi->chipshift);
11501da177e4SLinus Torvalds 	ofs = from - (chipnum <<  cfi->chipshift);
11511da177e4SLinus Torvalds 
11521da177e4SLinus Torvalds 	while (len) {
11531da177e4SLinus Torvalds 		unsigned long thislen;
11541da177e4SLinus Torvalds 
11551da177e4SLinus Torvalds 		if (chipnum >= cfi->numchips)
11561da177e4SLinus Torvalds 			break;
11571da177e4SLinus Torvalds 
11581da177e4SLinus Torvalds 		if ((len + ofs -1) >> cfi->chipshift)
11591da177e4SLinus Torvalds 			thislen = (1<<cfi->chipshift) - ofs;
11601da177e4SLinus Torvalds 		else
11611da177e4SLinus Torvalds 			thislen = len;
11621da177e4SLinus Torvalds 
11631da177e4SLinus Torvalds 		ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
11641da177e4SLinus Torvalds 		if (ret)
11651da177e4SLinus Torvalds 			break;
11661da177e4SLinus Torvalds 
11671da177e4SLinus Torvalds 		*retlen += thislen;
11681da177e4SLinus Torvalds 		len -= thislen;
11691da177e4SLinus Torvalds 		buf += thislen;
11701da177e4SLinus Torvalds 
11711da177e4SLinus Torvalds 		ofs = 0;
11721da177e4SLinus Torvalds 		chipnum++;
11731da177e4SLinus Torvalds 	}
11741da177e4SLinus Torvalds 	return ret;
11751da177e4SLinus Torvalds }
11761da177e4SLinus Torvalds 
1177dc7e9ecdSChristian Riesch typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip,
11784f5cb243SChristian Riesch 			loff_t adr, size_t len, u_char *buf, size_t grouplen);
11791da177e4SLinus Torvalds 
1180feb86779SChristian Riesch static inline void otp_enter(struct map_info *map, struct flchip *chip,
1181feb86779SChristian Riesch 			     loff_t adr, size_t len)
1182feb86779SChristian Riesch {
1183feb86779SChristian Riesch 	struct cfi_private *cfi = map->fldrv_priv;
1184feb86779SChristian Riesch 
1185feb86779SChristian Riesch 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
1186feb86779SChristian Riesch 			 cfi->device_type, NULL);
1187feb86779SChristian Riesch 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
1188feb86779SChristian Riesch 			 cfi->device_type, NULL);
1189feb86779SChristian Riesch 	cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi,
1190feb86779SChristian Riesch 			 cfi->device_type, NULL);
1191feb86779SChristian Riesch 
1192feb86779SChristian Riesch 	INVALIDATE_CACHED_RANGE(map, chip->start + adr, len);
1193feb86779SChristian Riesch }
1194feb86779SChristian Riesch 
1195feb86779SChristian Riesch static inline void otp_exit(struct map_info *map, struct flchip *chip,
1196feb86779SChristian Riesch 			    loff_t adr, size_t len)
1197feb86779SChristian Riesch {
1198feb86779SChristian Riesch 	struct cfi_private *cfi = map->fldrv_priv;
1199feb86779SChristian Riesch 
1200feb86779SChristian Riesch 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
1201feb86779SChristian Riesch 			 cfi->device_type, NULL);
1202feb86779SChristian Riesch 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
1203feb86779SChristian Riesch 			 cfi->device_type, NULL);
1204feb86779SChristian Riesch 	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi,
1205feb86779SChristian Riesch 			 cfi->device_type, NULL);
1206feb86779SChristian Riesch 	cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi,
1207feb86779SChristian Riesch 			 cfi->device_type, NULL);
1208feb86779SChristian Riesch 
1209feb86779SChristian Riesch 	INVALIDATE_CACHED_RANGE(map, chip->start + adr, len);
1210feb86779SChristian Riesch }
1211feb86779SChristian Riesch 
12124f5cb243SChristian Riesch static inline int do_read_secsi_onechip(struct map_info *map,
12134f5cb243SChristian Riesch 					struct flchip *chip, loff_t adr,
12144f5cb243SChristian Riesch 					size_t len, u_char *buf,
12154f5cb243SChristian Riesch 					size_t grouplen)
12161da177e4SLinus Torvalds {
12171da177e4SLinus Torvalds 	DECLARE_WAITQUEUE(wait, current);
12181da177e4SLinus Torvalds 	unsigned long timeo = jiffies + HZ;
12191da177e4SLinus Torvalds 
12201da177e4SLinus Torvalds  retry:
1221c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);
12221da177e4SLinus Torvalds 
12231da177e4SLinus Torvalds 	if (chip->state != FL_READY){
12241da177e4SLinus Torvalds 		set_current_state(TASK_UNINTERRUPTIBLE);
12251da177e4SLinus Torvalds 		add_wait_queue(&chip->wq, &wait);
12261da177e4SLinus Torvalds 
1227c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
12281da177e4SLinus Torvalds 
12291da177e4SLinus Torvalds 		schedule();
12301da177e4SLinus Torvalds 		remove_wait_queue(&chip->wq, &wait);
12311da177e4SLinus Torvalds 		timeo = jiffies + HZ;
12321da177e4SLinus Torvalds 
12331da177e4SLinus Torvalds 		goto retry;
12341da177e4SLinus Torvalds 	}
12351da177e4SLinus Torvalds 
12361da177e4SLinus Torvalds 	adr += chip->start;
12371da177e4SLinus Torvalds 
12381da177e4SLinus Torvalds 	chip->state = FL_READY;
12391da177e4SLinus Torvalds 
1240feb86779SChristian Riesch 	otp_enter(map, chip, adr, len);
12411da177e4SLinus Torvalds 	map_copy_from(map, buf, adr, len);
1242feb86779SChristian Riesch 	otp_exit(map, chip, adr, len);
12431da177e4SLinus Torvalds 
12441da177e4SLinus Torvalds 	wake_up(&chip->wq);
1245c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);
12461da177e4SLinus Torvalds 
12471da177e4SLinus Torvalds 	return 0;
12481da177e4SLinus Torvalds }
12491da177e4SLinus Torvalds 
12501da177e4SLinus Torvalds static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
12511da177e4SLinus Torvalds {
12521da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
12531da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
12541da177e4SLinus Torvalds 	unsigned long ofs;
12551da177e4SLinus Torvalds 	int chipnum;
12561da177e4SLinus Torvalds 	int ret = 0;
12571da177e4SLinus Torvalds 
12581da177e4SLinus Torvalds 	/* ofs: offset within the first chip that the first read should start */
12591da177e4SLinus Torvalds 	/* 8 secsi bytes per chip */
12601da177e4SLinus Torvalds 	chipnum=from>>3;
12611da177e4SLinus Torvalds 	ofs=from & 7;
12621da177e4SLinus Torvalds 
12631da177e4SLinus Torvalds 	while (len) {
12641da177e4SLinus Torvalds 		unsigned long thislen;
12651da177e4SLinus Torvalds 
12661da177e4SLinus Torvalds 		if (chipnum >= cfi->numchips)
12671da177e4SLinus Torvalds 			break;
12681da177e4SLinus Torvalds 
12691da177e4SLinus Torvalds 		if ((len + ofs -1) >> 3)
12701da177e4SLinus Torvalds 			thislen = (1<<3) - ofs;
12711da177e4SLinus Torvalds 		else
12721da177e4SLinus Torvalds 			thislen = len;
12731da177e4SLinus Torvalds 
12744f5cb243SChristian Riesch 		ret = do_read_secsi_onechip(map, &cfi->chips[chipnum], ofs,
12754f5cb243SChristian Riesch 					    thislen, buf, 0);
12761da177e4SLinus Torvalds 		if (ret)
12771da177e4SLinus Torvalds 			break;
12781da177e4SLinus Torvalds 
12791da177e4SLinus Torvalds 		*retlen += thislen;
12801da177e4SLinus Torvalds 		len -= thislen;
12811da177e4SLinus Torvalds 		buf += thislen;
12821da177e4SLinus Torvalds 
12831da177e4SLinus Torvalds 		ofs = 0;
12841da177e4SLinus Torvalds 		chipnum++;
12851da177e4SLinus Torvalds 	}
12861da177e4SLinus Torvalds 	return ret;
12871da177e4SLinus Torvalds }
12881da177e4SLinus Torvalds 
1289af744750SChristian Riesch static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
1290af744750SChristian Riesch 				     unsigned long adr, map_word datum,
1291af744750SChristian Riesch 				     int mode);
1292af744750SChristian Riesch 
1293af744750SChristian Riesch static int do_otp_write(struct map_info *map, struct flchip *chip, loff_t adr,
12944f5cb243SChristian Riesch 			size_t len, u_char *buf, size_t grouplen)
1295af744750SChristian Riesch {
1296af744750SChristian Riesch 	int ret;
1297af744750SChristian Riesch 	while (len) {
1298af744750SChristian Riesch 		unsigned long bus_ofs = adr & ~(map_bankwidth(map)-1);
1299af744750SChristian Riesch 		int gap = adr - bus_ofs;
1300af744750SChristian Riesch 		int n = min_t(int, len, map_bankwidth(map) - gap);
1301636fdbf8SChristian Riesch 		map_word datum = map_word_ff(map);
1302af744750SChristian Riesch 
1303af744750SChristian Riesch 		if (n != map_bankwidth(map)) {
1304af744750SChristian Riesch 			/* partial write of a word, load old contents */
1305af744750SChristian Riesch 			otp_enter(map, chip, bus_ofs, map_bankwidth(map));
1306af744750SChristian Riesch 			datum = map_read(map, bus_ofs);
1307af744750SChristian Riesch 			otp_exit(map, chip, bus_ofs, map_bankwidth(map));
1308af744750SChristian Riesch 		}
1309af744750SChristian Riesch 
1310af744750SChristian Riesch 		datum = map_word_load_partial(map, datum, buf, gap, n);
1311af744750SChristian Riesch 		ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE);
1312af744750SChristian Riesch 		if (ret)
1313af744750SChristian Riesch 			return ret;
1314af744750SChristian Riesch 
1315af744750SChristian Riesch 		adr += n;
1316af744750SChristian Riesch 		buf += n;
1317af744750SChristian Riesch 		len -= n;
1318af744750SChristian Riesch 	}
1319af744750SChristian Riesch 
1320af744750SChristian Riesch 	return 0;
1321af744750SChristian Riesch }
1322af744750SChristian Riesch 
13234f5cb243SChristian Riesch static int do_otp_lock(struct map_info *map, struct flchip *chip, loff_t adr,
13244f5cb243SChristian Riesch 		       size_t len, u_char *buf, size_t grouplen)
13254f5cb243SChristian Riesch {
13264f5cb243SChristian Riesch 	struct cfi_private *cfi = map->fldrv_priv;
13274f5cb243SChristian Riesch 	uint8_t lockreg;
13284f5cb243SChristian Riesch 	unsigned long timeo;
13294f5cb243SChristian Riesch 	int ret;
13304f5cb243SChristian Riesch 
13314f5cb243SChristian Riesch 	/* make sure area matches group boundaries */
13324f5cb243SChristian Riesch 	if ((adr != 0) || (len != grouplen))
13334f5cb243SChristian Riesch 		return -EINVAL;
13344f5cb243SChristian Riesch 
13354f5cb243SChristian Riesch 	mutex_lock(&chip->mutex);
13364f5cb243SChristian Riesch 	ret = get_chip(map, chip, chip->start, FL_LOCKING);
13374f5cb243SChristian Riesch 	if (ret) {
13384f5cb243SChristian Riesch 		mutex_unlock(&chip->mutex);
13394f5cb243SChristian Riesch 		return ret;
13404f5cb243SChristian Riesch 	}
13414f5cb243SChristian Riesch 	chip->state = FL_LOCKING;
13424f5cb243SChristian Riesch 
13434f5cb243SChristian Riesch 	/* Enter lock register command */
13444f5cb243SChristian Riesch 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
13454f5cb243SChristian Riesch 			 cfi->device_type, NULL);
13464f5cb243SChristian Riesch 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
13474f5cb243SChristian Riesch 			 cfi->device_type, NULL);
13484f5cb243SChristian Riesch 	cfi_send_gen_cmd(0x40, cfi->addr_unlock1, chip->start, map, cfi,
13494f5cb243SChristian Riesch 			 cfi->device_type, NULL);
13504f5cb243SChristian Riesch 
13514f5cb243SChristian Riesch 	/* read lock register */
13524f5cb243SChristian Riesch 	lockreg = cfi_read_query(map, 0);
13534f5cb243SChristian Riesch 
13544f5cb243SChristian Riesch 	/* set bit 0 to protect extended memory block */
13554f5cb243SChristian Riesch 	lockreg &= ~0x01;
13564f5cb243SChristian Riesch 
13574f5cb243SChristian Riesch 	/* set bit 0 to protect extended memory block */
13584f5cb243SChristian Riesch 	/* write lock register */
13594f5cb243SChristian Riesch 	map_write(map, CMD(0xA0), chip->start);
13604f5cb243SChristian Riesch 	map_write(map, CMD(lockreg), chip->start);
13614f5cb243SChristian Riesch 
13624f5cb243SChristian Riesch 	/* wait for chip to become ready */
13634f5cb243SChristian Riesch 	timeo = jiffies + msecs_to_jiffies(2);
13644f5cb243SChristian Riesch 	for (;;) {
13654f5cb243SChristian Riesch 		if (chip_ready(map, adr))
13664f5cb243SChristian Riesch 			break;
13674f5cb243SChristian Riesch 
13684f5cb243SChristian Riesch 		if (time_after(jiffies, timeo)) {
13694f5cb243SChristian Riesch 			pr_err("Waiting for chip to be ready timed out.\n");
13704f5cb243SChristian Riesch 			ret = -EIO;
13714f5cb243SChristian Riesch 			break;
13724f5cb243SChristian Riesch 		}
13734f5cb243SChristian Riesch 		UDELAY(map, chip, 0, 1);
13744f5cb243SChristian Riesch 	}
13754f5cb243SChristian Riesch 
13764f5cb243SChristian Riesch 	/* exit protection commands */
13774f5cb243SChristian Riesch 	map_write(map, CMD(0x90), chip->start);
13784f5cb243SChristian Riesch 	map_write(map, CMD(0x00), chip->start);
13794f5cb243SChristian Riesch 
13804f5cb243SChristian Riesch 	chip->state = FL_READY;
13814f5cb243SChristian Riesch 	put_chip(map, chip, chip->start);
13824f5cb243SChristian Riesch 	mutex_unlock(&chip->mutex);
13834f5cb243SChristian Riesch 
13844f5cb243SChristian Riesch 	return ret;
13854f5cb243SChristian Riesch }
13864f5cb243SChristian Riesch 
1387dc7e9ecdSChristian Riesch static int cfi_amdstd_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
1388dc7e9ecdSChristian Riesch 			       size_t *retlen, u_char *buf,
1389dc7e9ecdSChristian Riesch 			       otp_op_t action, int user_regs)
1390dc7e9ecdSChristian Riesch {
1391dc7e9ecdSChristian Riesch 	struct map_info *map = mtd->priv;
1392dc7e9ecdSChristian Riesch 	struct cfi_private *cfi = map->fldrv_priv;
1393dc7e9ecdSChristian Riesch 	int ofs_factor = cfi->interleave * cfi->device_type;
1394dc7e9ecdSChristian Riesch 	unsigned long base;
1395dc7e9ecdSChristian Riesch 	int chipnum;
1396dc7e9ecdSChristian Riesch 	struct flchip *chip;
1397dc7e9ecdSChristian Riesch 	uint8_t otp, lockreg;
1398dc7e9ecdSChristian Riesch 	int ret;
1399dc7e9ecdSChristian Riesch 
1400dc7e9ecdSChristian Riesch 	size_t user_size, factory_size, otpsize;
1401dc7e9ecdSChristian Riesch 	loff_t user_offset, factory_offset, otpoffset;
1402dc7e9ecdSChristian Riesch 	int user_locked = 0, otplocked;
1403dc7e9ecdSChristian Riesch 
1404dc7e9ecdSChristian Riesch 	*retlen = 0;
1405dc7e9ecdSChristian Riesch 
1406dc7e9ecdSChristian Riesch 	for (chipnum = 0; chipnum < cfi->numchips; chipnum++) {
1407dc7e9ecdSChristian Riesch 		chip = &cfi->chips[chipnum];
1408dc7e9ecdSChristian Riesch 		factory_size = 0;
1409dc7e9ecdSChristian Riesch 		user_size = 0;
1410dc7e9ecdSChristian Riesch 
1411dc7e9ecdSChristian Riesch 		/* Micron M29EW family */
1412dc7e9ecdSChristian Riesch 		if (is_m29ew(cfi)) {
1413dc7e9ecdSChristian Riesch 			base = chip->start;
1414dc7e9ecdSChristian Riesch 
1415dc7e9ecdSChristian Riesch 			/* check whether secsi area is factory locked
1416dc7e9ecdSChristian Riesch 			   or user lockable */
1417dc7e9ecdSChristian Riesch 			mutex_lock(&chip->mutex);
1418dc7e9ecdSChristian Riesch 			ret = get_chip(map, chip, base, FL_CFI_QUERY);
1419dc7e9ecdSChristian Riesch 			if (ret) {
1420dc7e9ecdSChristian Riesch 				mutex_unlock(&chip->mutex);
1421dc7e9ecdSChristian Riesch 				return ret;
1422dc7e9ecdSChristian Riesch 			}
1423dc7e9ecdSChristian Riesch 			cfi_qry_mode_on(base, map, cfi);
1424dc7e9ecdSChristian Riesch 			otp = cfi_read_query(map, base + 0x3 * ofs_factor);
1425dc7e9ecdSChristian Riesch 			cfi_qry_mode_off(base, map, cfi);
1426dc7e9ecdSChristian Riesch 			put_chip(map, chip, base);
1427dc7e9ecdSChristian Riesch 			mutex_unlock(&chip->mutex);
1428dc7e9ecdSChristian Riesch 
1429dc7e9ecdSChristian Riesch 			if (otp & 0x80) {
1430dc7e9ecdSChristian Riesch 				/* factory locked */
1431dc7e9ecdSChristian Riesch 				factory_offset = 0;
1432dc7e9ecdSChristian Riesch 				factory_size = 0x100;
1433dc7e9ecdSChristian Riesch 			} else {
1434dc7e9ecdSChristian Riesch 				/* customer lockable */
1435dc7e9ecdSChristian Riesch 				user_offset = 0;
1436dc7e9ecdSChristian Riesch 				user_size = 0x100;
1437dc7e9ecdSChristian Riesch 
1438dc7e9ecdSChristian Riesch 				mutex_lock(&chip->mutex);
1439dc7e9ecdSChristian Riesch 				ret = get_chip(map, chip, base, FL_LOCKING);
14405d20bad1SBrian Norris 				if (ret) {
14415d20bad1SBrian Norris 					mutex_unlock(&chip->mutex);
14425d20bad1SBrian Norris 					return ret;
14435d20bad1SBrian Norris 				}
1444dc7e9ecdSChristian Riesch 
1445dc7e9ecdSChristian Riesch 				/* Enter lock register command */
1446dc7e9ecdSChristian Riesch 				cfi_send_gen_cmd(0xAA, cfi->addr_unlock1,
1447dc7e9ecdSChristian Riesch 						 chip->start, map, cfi,
1448dc7e9ecdSChristian Riesch 						 cfi->device_type, NULL);
1449dc7e9ecdSChristian Riesch 				cfi_send_gen_cmd(0x55, cfi->addr_unlock2,
1450dc7e9ecdSChristian Riesch 						 chip->start, map, cfi,
1451dc7e9ecdSChristian Riesch 						 cfi->device_type, NULL);
1452dc7e9ecdSChristian Riesch 				cfi_send_gen_cmd(0x40, cfi->addr_unlock1,
1453dc7e9ecdSChristian Riesch 						 chip->start, map, cfi,
1454dc7e9ecdSChristian Riesch 						 cfi->device_type, NULL);
1455dc7e9ecdSChristian Riesch 				/* read lock register */
1456dc7e9ecdSChristian Riesch 				lockreg = cfi_read_query(map, 0);
1457dc7e9ecdSChristian Riesch 				/* exit protection commands */
1458dc7e9ecdSChristian Riesch 				map_write(map, CMD(0x90), chip->start);
1459dc7e9ecdSChristian Riesch 				map_write(map, CMD(0x00), chip->start);
1460dc7e9ecdSChristian Riesch 				put_chip(map, chip, chip->start);
1461dc7e9ecdSChristian Riesch 				mutex_unlock(&chip->mutex);
1462dc7e9ecdSChristian Riesch 
1463dc7e9ecdSChristian Riesch 				user_locked = ((lockreg & 0x01) == 0x00);
1464dc7e9ecdSChristian Riesch 			}
1465dc7e9ecdSChristian Riesch 		}
1466dc7e9ecdSChristian Riesch 
1467dc7e9ecdSChristian Riesch 		otpsize = user_regs ? user_size : factory_size;
1468dc7e9ecdSChristian Riesch 		if (!otpsize)
1469dc7e9ecdSChristian Riesch 			continue;
1470dc7e9ecdSChristian Riesch 		otpoffset = user_regs ? user_offset : factory_offset;
1471dc7e9ecdSChristian Riesch 		otplocked = user_regs ? user_locked : 1;
1472dc7e9ecdSChristian Riesch 
1473dc7e9ecdSChristian Riesch 		if (!action) {
1474dc7e9ecdSChristian Riesch 			/* return otpinfo */
1475dc7e9ecdSChristian Riesch 			struct otp_info *otpinfo;
1476dc7e9ecdSChristian Riesch 			len -= sizeof(*otpinfo);
1477dc7e9ecdSChristian Riesch 			if (len <= 0)
1478dc7e9ecdSChristian Riesch 				return -ENOSPC;
1479dc7e9ecdSChristian Riesch 			otpinfo = (struct otp_info *)buf;
1480dc7e9ecdSChristian Riesch 			otpinfo->start = from;
1481dc7e9ecdSChristian Riesch 			otpinfo->length = otpsize;
1482dc7e9ecdSChristian Riesch 			otpinfo->locked = otplocked;
1483dc7e9ecdSChristian Riesch 			buf += sizeof(*otpinfo);
1484dc7e9ecdSChristian Riesch 			*retlen += sizeof(*otpinfo);
1485dc7e9ecdSChristian Riesch 			from += otpsize;
1486dc7e9ecdSChristian Riesch 		} else if ((from < otpsize) && (len > 0)) {
1487dc7e9ecdSChristian Riesch 			size_t size;
1488dc7e9ecdSChristian Riesch 			size = (len < otpsize - from) ? len : otpsize - from;
14894f5cb243SChristian Riesch 			ret = action(map, chip, otpoffset + from, size, buf,
14904f5cb243SChristian Riesch 				     otpsize);
1491dc7e9ecdSChristian Riesch 			if (ret < 0)
1492dc7e9ecdSChristian Riesch 				return ret;
1493dc7e9ecdSChristian Riesch 
1494dc7e9ecdSChristian Riesch 			buf += size;
1495dc7e9ecdSChristian Riesch 			len -= size;
1496dc7e9ecdSChristian Riesch 			*retlen += size;
1497dc7e9ecdSChristian Riesch 			from = 0;
1498dc7e9ecdSChristian Riesch 		} else {
1499dc7e9ecdSChristian Riesch 			from -= otpsize;
1500dc7e9ecdSChristian Riesch 		}
1501dc7e9ecdSChristian Riesch 	}
1502dc7e9ecdSChristian Riesch 	return 0;
1503dc7e9ecdSChristian Riesch }
1504dc7e9ecdSChristian Riesch 
1505dc7e9ecdSChristian Riesch static int cfi_amdstd_get_fact_prot_info(struct mtd_info *mtd, size_t len,
1506dc7e9ecdSChristian Riesch 					 size_t *retlen, struct otp_info *buf)
1507dc7e9ecdSChristian Riesch {
1508dc7e9ecdSChristian Riesch 	return cfi_amdstd_otp_walk(mtd, 0, len, retlen, (u_char *)buf,
1509dc7e9ecdSChristian Riesch 				   NULL, 0);
1510dc7e9ecdSChristian Riesch }
1511dc7e9ecdSChristian Riesch 
1512dc7e9ecdSChristian Riesch static int cfi_amdstd_get_user_prot_info(struct mtd_info *mtd, size_t len,
1513dc7e9ecdSChristian Riesch 					 size_t *retlen, struct otp_info *buf)
1514dc7e9ecdSChristian Riesch {
1515dc7e9ecdSChristian Riesch 	return cfi_amdstd_otp_walk(mtd, 0, len, retlen, (u_char *)buf,
1516dc7e9ecdSChristian Riesch 				   NULL, 1);
1517dc7e9ecdSChristian Riesch }
1518dc7e9ecdSChristian Riesch 
1519dc7e9ecdSChristian Riesch static int cfi_amdstd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
1520dc7e9ecdSChristian Riesch 					 size_t len, size_t *retlen,
1521dc7e9ecdSChristian Riesch 					 u_char *buf)
1522dc7e9ecdSChristian Riesch {
1523dc7e9ecdSChristian Riesch 	return cfi_amdstd_otp_walk(mtd, from, len, retlen,
1524dc7e9ecdSChristian Riesch 				   buf, do_read_secsi_onechip, 0);
1525dc7e9ecdSChristian Riesch }
1526dc7e9ecdSChristian Riesch 
1527dc7e9ecdSChristian Riesch static int cfi_amdstd_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
1528dc7e9ecdSChristian Riesch 					 size_t len, size_t *retlen,
1529dc7e9ecdSChristian Riesch 					 u_char *buf)
1530dc7e9ecdSChristian Riesch {
1531dc7e9ecdSChristian Riesch 	return cfi_amdstd_otp_walk(mtd, from, len, retlen,
1532dc7e9ecdSChristian Riesch 				   buf, do_read_secsi_onechip, 1);
1533dc7e9ecdSChristian Riesch }
15341da177e4SLinus Torvalds 
1535af744750SChristian Riesch static int cfi_amdstd_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
1536af744750SChristian Riesch 					  size_t len, size_t *retlen,
1537af744750SChristian Riesch 					  u_char *buf)
1538af744750SChristian Riesch {
1539af744750SChristian Riesch 	return cfi_amdstd_otp_walk(mtd, from, len, retlen, buf,
1540af744750SChristian Riesch 				   do_otp_write, 1);
1541af744750SChristian Riesch }
1542af744750SChristian Riesch 
15434f5cb243SChristian Riesch static int cfi_amdstd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
15444f5cb243SChristian Riesch 					 size_t len)
15454f5cb243SChristian Riesch {
15464f5cb243SChristian Riesch 	size_t retlen;
15474f5cb243SChristian Riesch 	return cfi_amdstd_otp_walk(mtd, from, len, &retlen, NULL,
15484f5cb243SChristian Riesch 				   do_otp_lock, 1);
15494f5cb243SChristian Riesch }
15504f5cb243SChristian Riesch 
1551af744750SChristian Riesch static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
1552af744750SChristian Riesch 				     unsigned long adr, map_word datum,
1553af744750SChristian Riesch 				     int mode)
15541da177e4SLinus Torvalds {
15551da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
15561da177e4SLinus Torvalds 	unsigned long timeo = jiffies + HZ;
15571da177e4SLinus Torvalds 	/*
15581da177e4SLinus Torvalds 	 * We use a 1ms + 1 jiffies generic timeout for writes (most devices
15591da177e4SLinus Torvalds 	 * have a max write time of a few hundreds usec). However, we should
15601da177e4SLinus Torvalds 	 * use the maximum timeout value given by the chip at probe time
15611da177e4SLinus Torvalds 	 * instead.  Unfortunately, struct flchip does have a field for
15621da177e4SLinus Torvalds 	 * maximum timeout, only for typical which can be far too short
15631da177e4SLinus Torvalds 	 * depending of the conditions.	 The ' + 1' is to avoid having a
15641da177e4SLinus Torvalds 	 * timeout of 0 jiffies if HZ is smaller than 1000.
15651da177e4SLinus Torvalds 	 */
15661da177e4SLinus Torvalds 	unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
15671da177e4SLinus Torvalds 	int ret = 0;
15681da177e4SLinus Torvalds 	map_word oldd;
15691da177e4SLinus Torvalds 	int retry_cnt = 0;
15701da177e4SLinus Torvalds 
15711da177e4SLinus Torvalds 	adr += chip->start;
15721da177e4SLinus Torvalds 
1573c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);
1574af744750SChristian Riesch 	ret = get_chip(map, chip, adr, mode);
15751da177e4SLinus Torvalds 	if (ret) {
1576c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
15771da177e4SLinus Torvalds 		return ret;
15781da177e4SLinus Torvalds 	}
15791da177e4SLinus Torvalds 
1580289c0522SBrian Norris 	pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
15811da177e4SLinus Torvalds 	       __func__, adr, datum.x[0] );
15821da177e4SLinus Torvalds 
1583af744750SChristian Riesch 	if (mode == FL_OTP_WRITE)
1584af744750SChristian Riesch 		otp_enter(map, chip, adr, map_bankwidth(map));
1585af744750SChristian Riesch 
15861da177e4SLinus Torvalds 	/*
15871da177e4SLinus Torvalds 	 * Check for a NOP for the case when the datum to write is already
15881da177e4SLinus Torvalds 	 * present - it saves time and works around buggy chips that corrupt
15891da177e4SLinus Torvalds 	 * data at other locations when 0xff is written to a location that
15901da177e4SLinus Torvalds 	 * already contains 0xff.
15911da177e4SLinus Torvalds 	 */
15921da177e4SLinus Torvalds 	oldd = map_read(map, adr);
15931da177e4SLinus Torvalds 	if (map_word_equal(map, oldd, datum)) {
1594289c0522SBrian Norris 		pr_debug("MTD %s(): NOP\n",
15951da177e4SLinus Torvalds 		       __func__);
15961da177e4SLinus Torvalds 		goto op_done;
15971da177e4SLinus Torvalds 	}
15981da177e4SLinus Torvalds 
159902b15e34STodd Poynor 	XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
16001da177e4SLinus Torvalds 	ENABLE_VPP(map);
160102b15e34STodd Poynor 	xip_disable(map, chip, adr);
1602af744750SChristian Riesch 
16031da177e4SLinus Torvalds  retry:
16041da177e4SLinus Torvalds 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
16051da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
16061da177e4SLinus Torvalds 	cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
16071da177e4SLinus Torvalds 	map_write(map, datum, adr);
1608af744750SChristian Riesch 	chip->state = mode;
16091da177e4SLinus Torvalds 
161002b15e34STodd Poynor 	INVALIDATE_CACHE_UDELAY(map, chip,
161102b15e34STodd Poynor 				adr, map_bankwidth(map),
161202b15e34STodd Poynor 				chip->word_write_time);
16131da177e4SLinus Torvalds 
16141da177e4SLinus Torvalds 	/* See comment above for timeout value. */
16151da177e4SLinus Torvalds 	timeo = jiffies + uWriteTimeout;
16161da177e4SLinus Torvalds 	for (;;) {
1617af744750SChristian Riesch 		if (chip->state != mode) {
16181da177e4SLinus Torvalds 			/* Someone's suspended the write. Sleep */
16191da177e4SLinus Torvalds 			DECLARE_WAITQUEUE(wait, current);
16201da177e4SLinus Torvalds 
16211da177e4SLinus Torvalds 			set_current_state(TASK_UNINTERRUPTIBLE);
16221da177e4SLinus Torvalds 			add_wait_queue(&chip->wq, &wait);
1623c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
16241da177e4SLinus Torvalds 			schedule();
16251da177e4SLinus Torvalds 			remove_wait_queue(&chip->wq, &wait);
16261da177e4SLinus Torvalds 			timeo = jiffies + (HZ / 2); /* FIXME */
1627c4e77376SStefani Seibold 			mutex_lock(&chip->mutex);
16281da177e4SLinus Torvalds 			continue;
16291da177e4SLinus Torvalds 		}
16301da177e4SLinus Torvalds 
1631b95f9609SKonstantin Baidarov 		if (time_after(jiffies, timeo) && !chip_ready(map, adr)){
163202b15e34STodd Poynor 			xip_enable(map, chip, adr);
1633fb4a90bfSEric W. Biedermann 			printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
163402b15e34STodd Poynor 			xip_disable(map, chip, adr);
1635fb4a90bfSEric W. Biedermann 			break;
1636fb4a90bfSEric W. Biedermann 		}
1637fb4a90bfSEric W. Biedermann 
1638b95f9609SKonstantin Baidarov 		if (chip_ready(map, adr))
1639b95f9609SKonstantin Baidarov 			break;
1640b95f9609SKonstantin Baidarov 
16411da177e4SLinus Torvalds 		/* Latency issues. Drop the lock, wait a while and retry */
164202b15e34STodd Poynor 		UDELAY(map, chip, adr, 1);
16431da177e4SLinus Torvalds 	}
1644fb4a90bfSEric W. Biedermann 	/* Did we succeed? */
1645fb4a90bfSEric W. Biedermann 	if (!chip_good(map, adr, datum)) {
16461da177e4SLinus Torvalds 		/* reset on all failures. */
16471da177e4SLinus Torvalds 		map_write( map, CMD(0xF0), chip->start );
16481da177e4SLinus Torvalds 		/* FIXME - should have reset delay before continuing */
1649fb4a90bfSEric W. Biedermann 
16501da177e4SLinus Torvalds 		if (++retry_cnt <= MAX_WORD_RETRIES)
16511da177e4SLinus Torvalds 			goto retry;
16521da177e4SLinus Torvalds 
16531da177e4SLinus Torvalds 		ret = -EIO;
1654fb4a90bfSEric W. Biedermann 	}
165502b15e34STodd Poynor 	xip_enable(map, chip, adr);
16561da177e4SLinus Torvalds  op_done:
1657af744750SChristian Riesch 	if (mode == FL_OTP_WRITE)
1658af744750SChristian Riesch 		otp_exit(map, chip, adr, map_bankwidth(map));
16591da177e4SLinus Torvalds 	chip->state = FL_READY;
1660e7d9377eSPaul Parsons 	DISABLE_VPP(map);
16611da177e4SLinus Torvalds 	put_chip(map, chip, adr);
1662c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);
16631da177e4SLinus Torvalds 
16641da177e4SLinus Torvalds 	return ret;
16651da177e4SLinus Torvalds }
16661da177e4SLinus Torvalds 
16671da177e4SLinus Torvalds 
16681da177e4SLinus Torvalds static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
16691da177e4SLinus Torvalds 				  size_t *retlen, const u_char *buf)
16701da177e4SLinus Torvalds {
16711da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
16721da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
16731da177e4SLinus Torvalds 	int ret = 0;
16741da177e4SLinus Torvalds 	int chipnum;
16751da177e4SLinus Torvalds 	unsigned long ofs, chipstart;
16761da177e4SLinus Torvalds 	DECLARE_WAITQUEUE(wait, current);
16771da177e4SLinus Torvalds 
16781da177e4SLinus Torvalds 	chipnum = to >> cfi->chipshift;
16791da177e4SLinus Torvalds 	ofs = to  - (chipnum << cfi->chipshift);
16801da177e4SLinus Torvalds 	chipstart = cfi->chips[chipnum].start;
16811da177e4SLinus Torvalds 
16821da177e4SLinus Torvalds 	/* If it's not bus-aligned, do the first byte write */
16831da177e4SLinus Torvalds 	if (ofs & (map_bankwidth(map)-1)) {
16841da177e4SLinus Torvalds 		unsigned long bus_ofs = ofs & ~(map_bankwidth(map)-1);
16851da177e4SLinus Torvalds 		int i = ofs - bus_ofs;
16861da177e4SLinus Torvalds 		int n = 0;
16871da177e4SLinus Torvalds 		map_word tmp_buf;
16881da177e4SLinus Torvalds 
16891da177e4SLinus Torvalds  retry:
1690c4e77376SStefani Seibold 		mutex_lock(&cfi->chips[chipnum].mutex);
16911da177e4SLinus Torvalds 
16921da177e4SLinus Torvalds 		if (cfi->chips[chipnum].state != FL_READY) {
16931da177e4SLinus Torvalds 			set_current_state(TASK_UNINTERRUPTIBLE);
16941da177e4SLinus Torvalds 			add_wait_queue(&cfi->chips[chipnum].wq, &wait);
16951da177e4SLinus Torvalds 
1696c4e77376SStefani Seibold 			mutex_unlock(&cfi->chips[chipnum].mutex);
16971da177e4SLinus Torvalds 
16981da177e4SLinus Torvalds 			schedule();
16991da177e4SLinus Torvalds 			remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
17001da177e4SLinus Torvalds 			goto retry;
17011da177e4SLinus Torvalds 		}
17021da177e4SLinus Torvalds 
17031da177e4SLinus Torvalds 		/* Load 'tmp_buf' with old contents of flash */
17041da177e4SLinus Torvalds 		tmp_buf = map_read(map, bus_ofs+chipstart);
17051da177e4SLinus Torvalds 
1706c4e77376SStefani Seibold 		mutex_unlock(&cfi->chips[chipnum].mutex);
17071da177e4SLinus Torvalds 
17081da177e4SLinus Torvalds 		/* Number of bytes to copy from buffer */
17091da177e4SLinus Torvalds 		n = min_t(int, len, map_bankwidth(map)-i);
17101da177e4SLinus Torvalds 
17111da177e4SLinus Torvalds 		tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n);
17121da177e4SLinus Torvalds 
17131da177e4SLinus Torvalds 		ret = do_write_oneword(map, &cfi->chips[chipnum],
1714af744750SChristian Riesch 				       bus_ofs, tmp_buf, FL_WRITING);
17151da177e4SLinus Torvalds 		if (ret)
17161da177e4SLinus Torvalds 			return ret;
17171da177e4SLinus Torvalds 
17181da177e4SLinus Torvalds 		ofs += n;
17191da177e4SLinus Torvalds 		buf += n;
17201da177e4SLinus Torvalds 		(*retlen) += n;
17211da177e4SLinus Torvalds 		len -= n;
17221da177e4SLinus Torvalds 
17231da177e4SLinus Torvalds 		if (ofs >> cfi->chipshift) {
17241da177e4SLinus Torvalds 			chipnum ++;
17251da177e4SLinus Torvalds 			ofs = 0;
17261da177e4SLinus Torvalds 			if (chipnum == cfi->numchips)
17271da177e4SLinus Torvalds 				return 0;
17281da177e4SLinus Torvalds 		}
17291da177e4SLinus Torvalds 	}
17301da177e4SLinus Torvalds 
17311da177e4SLinus Torvalds 	/* We are now aligned, write as much as possible */
17321da177e4SLinus Torvalds 	while(len >= map_bankwidth(map)) {
17331da177e4SLinus Torvalds 		map_word datum;
17341da177e4SLinus Torvalds 
17351da177e4SLinus Torvalds 		datum = map_word_load(map, buf);
17361da177e4SLinus Torvalds 
17371da177e4SLinus Torvalds 		ret = do_write_oneword(map, &cfi->chips[chipnum],
1738af744750SChristian Riesch 				       ofs, datum, FL_WRITING);
17391da177e4SLinus Torvalds 		if (ret)
17401da177e4SLinus Torvalds 			return ret;
17411da177e4SLinus Torvalds 
17421da177e4SLinus Torvalds 		ofs += map_bankwidth(map);
17431da177e4SLinus Torvalds 		buf += map_bankwidth(map);
17441da177e4SLinus Torvalds 		(*retlen) += map_bankwidth(map);
17451da177e4SLinus Torvalds 		len -= map_bankwidth(map);
17461da177e4SLinus Torvalds 
17471da177e4SLinus Torvalds 		if (ofs >> cfi->chipshift) {
17481da177e4SLinus Torvalds 			chipnum ++;
17491da177e4SLinus Torvalds 			ofs = 0;
17501da177e4SLinus Torvalds 			if (chipnum == cfi->numchips)
17511da177e4SLinus Torvalds 				return 0;
17521da177e4SLinus Torvalds 			chipstart = cfi->chips[chipnum].start;
17531da177e4SLinus Torvalds 		}
17541da177e4SLinus Torvalds 	}
17551da177e4SLinus Torvalds 
17561da177e4SLinus Torvalds 	/* Write the trailing bytes if any */
17571da177e4SLinus Torvalds 	if (len & (map_bankwidth(map)-1)) {
17581da177e4SLinus Torvalds 		map_word tmp_buf;
17591da177e4SLinus Torvalds 
17601da177e4SLinus Torvalds  retry1:
1761c4e77376SStefani Seibold 		mutex_lock(&cfi->chips[chipnum].mutex);
17621da177e4SLinus Torvalds 
17631da177e4SLinus Torvalds 		if (cfi->chips[chipnum].state != FL_READY) {
17641da177e4SLinus Torvalds 			set_current_state(TASK_UNINTERRUPTIBLE);
17651da177e4SLinus Torvalds 			add_wait_queue(&cfi->chips[chipnum].wq, &wait);
17661da177e4SLinus Torvalds 
1767c4e77376SStefani Seibold 			mutex_unlock(&cfi->chips[chipnum].mutex);
17681da177e4SLinus Torvalds 
17691da177e4SLinus Torvalds 			schedule();
17701da177e4SLinus Torvalds 			remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
17711da177e4SLinus Torvalds 			goto retry1;
17721da177e4SLinus Torvalds 		}
17731da177e4SLinus Torvalds 
17741da177e4SLinus Torvalds 		tmp_buf = map_read(map, ofs + chipstart);
17751da177e4SLinus Torvalds 
1776c4e77376SStefani Seibold 		mutex_unlock(&cfi->chips[chipnum].mutex);
17771da177e4SLinus Torvalds 
17781da177e4SLinus Torvalds 		tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);
17791da177e4SLinus Torvalds 
17801da177e4SLinus Torvalds 		ret = do_write_oneword(map, &cfi->chips[chipnum],
1781af744750SChristian Riesch 				       ofs, tmp_buf, FL_WRITING);
17821da177e4SLinus Torvalds 		if (ret)
17831da177e4SLinus Torvalds 			return ret;
17841da177e4SLinus Torvalds 
17851da177e4SLinus Torvalds 		(*retlen) += len;
17861da177e4SLinus Torvalds 	}
17871da177e4SLinus Torvalds 
17881da177e4SLinus Torvalds 	return 0;
17891da177e4SLinus Torvalds }
17901da177e4SLinus Torvalds 
17911da177e4SLinus Torvalds 
17921da177e4SLinus Torvalds /*
17931da177e4SLinus Torvalds  * FIXME: interleaved mode not tested, and probably not supported!
17941da177e4SLinus Torvalds  */
179502b15e34STodd Poynor static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
179602b15e34STodd Poynor 				    unsigned long adr, const u_char *buf,
179702b15e34STodd Poynor 				    int len)
17981da177e4SLinus Torvalds {
17991da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
18001da177e4SLinus Torvalds 	unsigned long timeo = jiffies + HZ;
18016534e680SBean Huo 	/*
18026534e680SBean Huo 	 * Timeout is calculated according to CFI data, if available.
18036534e680SBean Huo 	 * See more comments in cfi_cmdset_0002().
18046534e680SBean Huo 	 */
18056534e680SBean Huo 	unsigned long uWriteTimeout =
18066534e680SBean Huo 				usecs_to_jiffies(chip->buffer_write_time_max);
18071da177e4SLinus Torvalds 	int ret = -EIO;
18081da177e4SLinus Torvalds 	unsigned long cmd_adr;
18091da177e4SLinus Torvalds 	int z, words;
18101da177e4SLinus Torvalds 	map_word datum;
18111da177e4SLinus Torvalds 
18121da177e4SLinus Torvalds 	adr += chip->start;
18131da177e4SLinus Torvalds 	cmd_adr = adr;
18141da177e4SLinus Torvalds 
1815c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);
18161da177e4SLinus Torvalds 	ret = get_chip(map, chip, adr, FL_WRITING);
18171da177e4SLinus Torvalds 	if (ret) {
1818c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
18191da177e4SLinus Torvalds 		return ret;
18201da177e4SLinus Torvalds 	}
18211da177e4SLinus Torvalds 
18221da177e4SLinus Torvalds 	datum = map_word_load(map, buf);
18231da177e4SLinus Torvalds 
1824289c0522SBrian Norris 	pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
18251da177e4SLinus Torvalds 	       __func__, adr, datum.x[0] );
18261da177e4SLinus Torvalds 
182702b15e34STodd Poynor 	XIP_INVAL_CACHED_RANGE(map, adr, len);
18281da177e4SLinus Torvalds 	ENABLE_VPP(map);
182902b15e34STodd Poynor 	xip_disable(map, chip, cmd_adr);
183002b15e34STodd Poynor 
18311da177e4SLinus Torvalds 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
18321da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
18331da177e4SLinus Torvalds 
18341da177e4SLinus Torvalds 	/* Write Buffer Load */
18351da177e4SLinus Torvalds 	map_write(map, CMD(0x25), cmd_adr);
18361da177e4SLinus Torvalds 
18371da177e4SLinus Torvalds 	chip->state = FL_WRITING_TO_BUFFER;
18381da177e4SLinus Torvalds 
18391da177e4SLinus Torvalds 	/* Write length of data to come */
18401da177e4SLinus Torvalds 	words = len / map_bankwidth(map);
18411da177e4SLinus Torvalds 	map_write(map, CMD(words - 1), cmd_adr);
18421da177e4SLinus Torvalds 	/* Write data */
18431da177e4SLinus Torvalds 	z = 0;
18441da177e4SLinus Torvalds 	while(z < words * map_bankwidth(map)) {
18451da177e4SLinus Torvalds 		datum = map_word_load(map, buf);
18461da177e4SLinus Torvalds 		map_write(map, datum, adr + z);
18471da177e4SLinus Torvalds 
18481da177e4SLinus Torvalds 		z += map_bankwidth(map);
18491da177e4SLinus Torvalds 		buf += map_bankwidth(map);
18501da177e4SLinus Torvalds 	}
18511da177e4SLinus Torvalds 	z -= map_bankwidth(map);
18521da177e4SLinus Torvalds 
18531da177e4SLinus Torvalds 	adr += z;
18541da177e4SLinus Torvalds 
18551da177e4SLinus Torvalds 	/* Write Buffer Program Confirm: GO GO GO */
18561da177e4SLinus Torvalds 	map_write(map, CMD(0x29), cmd_adr);
18571da177e4SLinus Torvalds 	chip->state = FL_WRITING;
18581da177e4SLinus Torvalds 
185902b15e34STodd Poynor 	INVALIDATE_CACHE_UDELAY(map, chip,
186002b15e34STodd Poynor 				adr, map_bankwidth(map),
186102b15e34STodd Poynor 				chip->word_write_time);
18621da177e4SLinus Torvalds 
18631da177e4SLinus Torvalds 	timeo = jiffies + uWriteTimeout;
18641da177e4SLinus Torvalds 
18651da177e4SLinus Torvalds 	for (;;) {
18661da177e4SLinus Torvalds 		if (chip->state != FL_WRITING) {
18671da177e4SLinus Torvalds 			/* Someone's suspended the write. Sleep */
18681da177e4SLinus Torvalds 			DECLARE_WAITQUEUE(wait, current);
18691da177e4SLinus Torvalds 
18701da177e4SLinus Torvalds 			set_current_state(TASK_UNINTERRUPTIBLE);
18711da177e4SLinus Torvalds 			add_wait_queue(&chip->wq, &wait);
1872c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
18731da177e4SLinus Torvalds 			schedule();
18741da177e4SLinus Torvalds 			remove_wait_queue(&chip->wq, &wait);
18751da177e4SLinus Torvalds 			timeo = jiffies + (HZ / 2); /* FIXME */
1876c4e77376SStefani Seibold 			mutex_lock(&chip->mutex);
18771da177e4SLinus Torvalds 			continue;
18781da177e4SLinus Torvalds 		}
18791da177e4SLinus Torvalds 
1880b95f9609SKonstantin Baidarov 		if (time_after(jiffies, timeo) && !chip_ready(map, adr))
1881b95f9609SKonstantin Baidarov 			break;
1882b95f9609SKonstantin Baidarov 
188302b15e34STodd Poynor 		if (chip_ready(map, adr)) {
188402b15e34STodd Poynor 			xip_enable(map, chip, adr);
18851da177e4SLinus Torvalds 			goto op_done;
188602b15e34STodd Poynor 		}
18871da177e4SLinus Torvalds 
18881da177e4SLinus Torvalds 		/* Latency issues. Drop the lock, wait a while and retry */
188902b15e34STodd Poynor 		UDELAY(map, chip, adr, 1);
18901da177e4SLinus Torvalds 	}
18911da177e4SLinus Torvalds 
1892070c3222SHarald Nordgard-Hansen 	/*
1893070c3222SHarald Nordgard-Hansen 	 * Recovery from write-buffer programming failures requires
1894070c3222SHarald Nordgard-Hansen 	 * the write-to-buffer-reset sequence.  Since the last part
1895070c3222SHarald Nordgard-Hansen 	 * of the sequence also works as a normal reset, we can run
1896070c3222SHarald Nordgard-Hansen 	 * the same commands regardless of why we are here.
1897070c3222SHarald Nordgard-Hansen 	 * See e.g.
1898070c3222SHarald Nordgard-Hansen 	 * http://www.spansion.com/Support/Application%20Notes/MirrorBit_Write_Buffer_Prog_Page_Buffer_Read_AN.pdf
1899070c3222SHarald Nordgard-Hansen 	 */
1900070c3222SHarald Nordgard-Hansen 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
1901070c3222SHarald Nordgard-Hansen 			 cfi->device_type, NULL);
1902070c3222SHarald Nordgard-Hansen 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
1903070c3222SHarald Nordgard-Hansen 			 cfi->device_type, NULL);
1904070c3222SHarald Nordgard-Hansen 	cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, chip->start, map, cfi,
1905070c3222SHarald Nordgard-Hansen 			 cfi->device_type, NULL);
190602b15e34STodd Poynor 	xip_enable(map, chip, adr);
19071da177e4SLinus Torvalds 	/* FIXME - should have reset delay before continuing */
19081da177e4SLinus Torvalds 
190925983b18SHuang Shijie 	printk(KERN_WARNING "MTD %s(): software timeout, address:0x%.8lx.\n",
191025983b18SHuang Shijie 	       __func__, adr);
191102b15e34STodd Poynor 
19121da177e4SLinus Torvalds 	ret = -EIO;
19131da177e4SLinus Torvalds  op_done:
19141da177e4SLinus Torvalds 	chip->state = FL_READY;
1915e7d9377eSPaul Parsons 	DISABLE_VPP(map);
19161da177e4SLinus Torvalds 	put_chip(map, chip, adr);
1917c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);
19181da177e4SLinus Torvalds 
19191da177e4SLinus Torvalds 	return ret;
19201da177e4SLinus Torvalds }
19211da177e4SLinus Torvalds 
19221da177e4SLinus Torvalds 
19231da177e4SLinus Torvalds static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
19241da177e4SLinus Torvalds 				    size_t *retlen, const u_char *buf)
19251da177e4SLinus Torvalds {
19261da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
19271da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
19281da177e4SLinus Torvalds 	int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
19291da177e4SLinus Torvalds 	int ret = 0;
19301da177e4SLinus Torvalds 	int chipnum;
19311da177e4SLinus Torvalds 	unsigned long ofs;
19321da177e4SLinus Torvalds 
19331da177e4SLinus Torvalds 	chipnum = to >> cfi->chipshift;
19341da177e4SLinus Torvalds 	ofs = to  - (chipnum << cfi->chipshift);
19351da177e4SLinus Torvalds 
19361da177e4SLinus Torvalds 	/* If it's not bus-aligned, do the first word write */
19371da177e4SLinus Torvalds 	if (ofs & (map_bankwidth(map)-1)) {
19381da177e4SLinus Torvalds 		size_t local_len = (-ofs)&(map_bankwidth(map)-1);
19391da177e4SLinus Torvalds 		if (local_len > len)
19401da177e4SLinus Torvalds 			local_len = len;
19411da177e4SLinus Torvalds 		ret = cfi_amdstd_write_words(mtd, ofs + (chipnum<<cfi->chipshift),
19421da177e4SLinus Torvalds 					     local_len, retlen, buf);
19431da177e4SLinus Torvalds 		if (ret)
19441da177e4SLinus Torvalds 			return ret;
19451da177e4SLinus Torvalds 		ofs += local_len;
19461da177e4SLinus Torvalds 		buf += local_len;
19471da177e4SLinus Torvalds 		len -= local_len;
19481da177e4SLinus Torvalds 
19491da177e4SLinus Torvalds 		if (ofs >> cfi->chipshift) {
19501da177e4SLinus Torvalds 			chipnum ++;
19511da177e4SLinus Torvalds 			ofs = 0;
19521da177e4SLinus Torvalds 			if (chipnum == cfi->numchips)
19531da177e4SLinus Torvalds 				return 0;
19541da177e4SLinus Torvalds 		}
19551da177e4SLinus Torvalds 	}
19561da177e4SLinus Torvalds 
19571da177e4SLinus Torvalds 	/* Write buffer is worth it only if more than one word to write... */
19581da177e4SLinus Torvalds 	while (len >= map_bankwidth(map) * 2) {
19591da177e4SLinus Torvalds 		/* We must not cross write block boundaries */
19601da177e4SLinus Torvalds 		int size = wbufsize - (ofs & (wbufsize-1));
19611da177e4SLinus Torvalds 
19621da177e4SLinus Torvalds 		if (size > len)
19631da177e4SLinus Torvalds 			size = len;
19641da177e4SLinus Torvalds 		if (size % map_bankwidth(map))
19651da177e4SLinus Torvalds 			size -= size % map_bankwidth(map);
19661da177e4SLinus Torvalds 
19671da177e4SLinus Torvalds 		ret = do_write_buffer(map, &cfi->chips[chipnum],
19681da177e4SLinus Torvalds 				      ofs, buf, size);
19691da177e4SLinus Torvalds 		if (ret)
19701da177e4SLinus Torvalds 			return ret;
19711da177e4SLinus Torvalds 
19721da177e4SLinus Torvalds 		ofs += size;
19731da177e4SLinus Torvalds 		buf += size;
19741da177e4SLinus Torvalds 		(*retlen) += size;
19751da177e4SLinus Torvalds 		len -= size;
19761da177e4SLinus Torvalds 
19771da177e4SLinus Torvalds 		if (ofs >> cfi->chipshift) {
19781da177e4SLinus Torvalds 			chipnum ++;
19791da177e4SLinus Torvalds 			ofs = 0;
19801da177e4SLinus Torvalds 			if (chipnum == cfi->numchips)
19811da177e4SLinus Torvalds 				return 0;
19821da177e4SLinus Torvalds 		}
19831da177e4SLinus Torvalds 	}
19841da177e4SLinus Torvalds 
19851da177e4SLinus Torvalds 	if (len) {
19861da177e4SLinus Torvalds 		size_t retlen_dregs = 0;
19871da177e4SLinus Torvalds 
19881da177e4SLinus Torvalds 		ret = cfi_amdstd_write_words(mtd, ofs + (chipnum<<cfi->chipshift),
19891da177e4SLinus Torvalds 					     len, &retlen_dregs, buf);
19901da177e4SLinus Torvalds 
19911da177e4SLinus Torvalds 		*retlen += retlen_dregs;
19921da177e4SLinus Torvalds 		return ret;
19931da177e4SLinus Torvalds 	}
19941da177e4SLinus Torvalds 
19951da177e4SLinus Torvalds 	return 0;
19961da177e4SLinus Torvalds }
19971da177e4SLinus Torvalds 
199830ec5a2cSIra W. Snyder /*
199930ec5a2cSIra W. Snyder  * Wait for the flash chip to become ready to write data
200030ec5a2cSIra W. Snyder  *
200130ec5a2cSIra W. Snyder  * This is only called during the panic_write() path. When panic_write()
200230ec5a2cSIra W. Snyder  * is called, the kernel is in the process of a panic, and will soon be
200330ec5a2cSIra W. Snyder  * dead. Therefore we don't take any locks, and attempt to get access
200430ec5a2cSIra W. Snyder  * to the chip as soon as possible.
200530ec5a2cSIra W. Snyder  */
200630ec5a2cSIra W. Snyder static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip,
200730ec5a2cSIra W. Snyder 				 unsigned long adr)
200830ec5a2cSIra W. Snyder {
200930ec5a2cSIra W. Snyder 	struct cfi_private *cfi = map->fldrv_priv;
201030ec5a2cSIra W. Snyder 	int retries = 10;
201130ec5a2cSIra W. Snyder 	int i;
201230ec5a2cSIra W. Snyder 
201330ec5a2cSIra W. Snyder 	/*
201430ec5a2cSIra W. Snyder 	 * If the driver thinks the chip is idle, and no toggle bits
201530ec5a2cSIra W. Snyder 	 * are changing, then the chip is actually idle for sure.
201630ec5a2cSIra W. Snyder 	 */
201730ec5a2cSIra W. Snyder 	if (chip->state == FL_READY && chip_ready(map, adr))
201830ec5a2cSIra W. Snyder 		return 0;
201930ec5a2cSIra W. Snyder 
202030ec5a2cSIra W. Snyder 	/*
202130ec5a2cSIra W. Snyder 	 * Try several times to reset the chip and then wait for it
202230ec5a2cSIra W. Snyder 	 * to become idle. The upper limit of a few milliseconds of
202330ec5a2cSIra W. Snyder 	 * delay isn't a big problem: the kernel is dying anyway. It
202430ec5a2cSIra W. Snyder 	 * is more important to save the messages.
202530ec5a2cSIra W. Snyder 	 */
202630ec5a2cSIra W. Snyder 	while (retries > 0) {
202730ec5a2cSIra W. Snyder 		const unsigned long timeo = (HZ / 1000) + 1;
202830ec5a2cSIra W. Snyder 
202930ec5a2cSIra W. Snyder 		/* send the reset command */
203030ec5a2cSIra W. Snyder 		map_write(map, CMD(0xF0), chip->start);
203130ec5a2cSIra W. Snyder 
203230ec5a2cSIra W. Snyder 		/* wait for the chip to become ready */
203330ec5a2cSIra W. Snyder 		for (i = 0; i < jiffies_to_usecs(timeo); i++) {
203430ec5a2cSIra W. Snyder 			if (chip_ready(map, adr))
203530ec5a2cSIra W. Snyder 				return 0;
203630ec5a2cSIra W. Snyder 
203730ec5a2cSIra W. Snyder 			udelay(1);
203830ec5a2cSIra W. Snyder 		}
203936c6a7acSBrian Norris 
204036c6a7acSBrian Norris 		retries--;
204130ec5a2cSIra W. Snyder 	}
204230ec5a2cSIra W. Snyder 
204330ec5a2cSIra W. Snyder 	/* the chip never became ready */
204430ec5a2cSIra W. Snyder 	return -EBUSY;
204530ec5a2cSIra W. Snyder }
204630ec5a2cSIra W. Snyder 
204730ec5a2cSIra W. Snyder /*
204830ec5a2cSIra W. Snyder  * Write out one word of data to a single flash chip during a kernel panic
204930ec5a2cSIra W. Snyder  *
205030ec5a2cSIra W. Snyder  * This is only called during the panic_write() path. When panic_write()
205130ec5a2cSIra W. Snyder  * is called, the kernel is in the process of a panic, and will soon be
205230ec5a2cSIra W. Snyder  * dead. Therefore we don't take any locks, and attempt to get access
205330ec5a2cSIra W. Snyder  * to the chip as soon as possible.
205430ec5a2cSIra W. Snyder  *
205530ec5a2cSIra W. Snyder  * The implementation of this routine is intentionally similar to
205630ec5a2cSIra W. Snyder  * do_write_oneword(), in order to ease code maintenance.
205730ec5a2cSIra W. Snyder  */
205830ec5a2cSIra W. Snyder static int do_panic_write_oneword(struct map_info *map, struct flchip *chip,
205930ec5a2cSIra W. Snyder 				  unsigned long adr, map_word datum)
206030ec5a2cSIra W. Snyder {
206130ec5a2cSIra W. Snyder 	const unsigned long uWriteTimeout = (HZ / 1000) + 1;
206230ec5a2cSIra W. Snyder 	struct cfi_private *cfi = map->fldrv_priv;
206330ec5a2cSIra W. Snyder 	int retry_cnt = 0;
206430ec5a2cSIra W. Snyder 	map_word oldd;
206530ec5a2cSIra W. Snyder 	int ret = 0;
206630ec5a2cSIra W. Snyder 	int i;
206730ec5a2cSIra W. Snyder 
206830ec5a2cSIra W. Snyder 	adr += chip->start;
206930ec5a2cSIra W. Snyder 
207030ec5a2cSIra W. Snyder 	ret = cfi_amdstd_panic_wait(map, chip, adr);
207130ec5a2cSIra W. Snyder 	if (ret)
207230ec5a2cSIra W. Snyder 		return ret;
207330ec5a2cSIra W. Snyder 
207430ec5a2cSIra W. Snyder 	pr_debug("MTD %s(): PANIC WRITE 0x%.8lx(0x%.8lx)\n",
207530ec5a2cSIra W. Snyder 			__func__, adr, datum.x[0]);
207630ec5a2cSIra W. Snyder 
207730ec5a2cSIra W. Snyder 	/*
207830ec5a2cSIra W. Snyder 	 * Check for a NOP for the case when the datum to write is already
207930ec5a2cSIra W. Snyder 	 * present - it saves time and works around buggy chips that corrupt
208030ec5a2cSIra W. Snyder 	 * data at other locations when 0xff is written to a location that
208130ec5a2cSIra W. Snyder 	 * already contains 0xff.
208230ec5a2cSIra W. Snyder 	 */
208330ec5a2cSIra W. Snyder 	oldd = map_read(map, adr);
208430ec5a2cSIra W. Snyder 	if (map_word_equal(map, oldd, datum)) {
208530ec5a2cSIra W. Snyder 		pr_debug("MTD %s(): NOP\n", __func__);
208630ec5a2cSIra W. Snyder 		goto op_done;
208730ec5a2cSIra W. Snyder 	}
208830ec5a2cSIra W. Snyder 
208930ec5a2cSIra W. Snyder 	ENABLE_VPP(map);
209030ec5a2cSIra W. Snyder 
209130ec5a2cSIra W. Snyder retry:
209230ec5a2cSIra W. Snyder 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
209330ec5a2cSIra W. Snyder 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
209430ec5a2cSIra W. Snyder 	cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
209530ec5a2cSIra W. Snyder 	map_write(map, datum, adr);
209630ec5a2cSIra W. Snyder 
209730ec5a2cSIra W. Snyder 	for (i = 0; i < jiffies_to_usecs(uWriteTimeout); i++) {
209830ec5a2cSIra W. Snyder 		if (chip_ready(map, adr))
209930ec5a2cSIra W. Snyder 			break;
210030ec5a2cSIra W. Snyder 
210130ec5a2cSIra W. Snyder 		udelay(1);
210230ec5a2cSIra W. Snyder 	}
210330ec5a2cSIra W. Snyder 
210430ec5a2cSIra W. Snyder 	if (!chip_good(map, adr, datum)) {
210530ec5a2cSIra W. Snyder 		/* reset on all failures. */
210630ec5a2cSIra W. Snyder 		map_write(map, CMD(0xF0), chip->start);
210730ec5a2cSIra W. Snyder 		/* FIXME - should have reset delay before continuing */
210830ec5a2cSIra W. Snyder 
210930ec5a2cSIra W. Snyder 		if (++retry_cnt <= MAX_WORD_RETRIES)
211030ec5a2cSIra W. Snyder 			goto retry;
211130ec5a2cSIra W. Snyder 
211230ec5a2cSIra W. Snyder 		ret = -EIO;
211330ec5a2cSIra W. Snyder 	}
211430ec5a2cSIra W. Snyder 
211530ec5a2cSIra W. Snyder op_done:
211630ec5a2cSIra W. Snyder 	DISABLE_VPP(map);
211730ec5a2cSIra W. Snyder 	return ret;
211830ec5a2cSIra W. Snyder }
211930ec5a2cSIra W. Snyder 
212030ec5a2cSIra W. Snyder /*
212130ec5a2cSIra W. Snyder  * Write out some data during a kernel panic
212230ec5a2cSIra W. Snyder  *
212330ec5a2cSIra W. Snyder  * This is used by the mtdoops driver to save the dying messages from a
212430ec5a2cSIra W. Snyder  * kernel which has panic'd.
212530ec5a2cSIra W. Snyder  *
212630ec5a2cSIra W. Snyder  * This routine ignores all of the locking used throughout the rest of the
212730ec5a2cSIra W. Snyder  * driver, in order to ensure that the data gets written out no matter what
212830ec5a2cSIra W. Snyder  * state this driver (and the flash chip itself) was in when the kernel crashed.
212930ec5a2cSIra W. Snyder  *
213030ec5a2cSIra W. Snyder  * The implementation of this routine is intentionally similar to
213130ec5a2cSIra W. Snyder  * cfi_amdstd_write_words(), in order to ease code maintenance.
213230ec5a2cSIra W. Snyder  */
213330ec5a2cSIra W. Snyder static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
213430ec5a2cSIra W. Snyder 				  size_t *retlen, const u_char *buf)
213530ec5a2cSIra W. Snyder {
213630ec5a2cSIra W. Snyder 	struct map_info *map = mtd->priv;
213730ec5a2cSIra W. Snyder 	struct cfi_private *cfi = map->fldrv_priv;
213830ec5a2cSIra W. Snyder 	unsigned long ofs, chipstart;
213930ec5a2cSIra W. Snyder 	int ret = 0;
214030ec5a2cSIra W. Snyder 	int chipnum;
214130ec5a2cSIra W. Snyder 
214230ec5a2cSIra W. Snyder 	chipnum = to >> cfi->chipshift;
214330ec5a2cSIra W. Snyder 	ofs = to - (chipnum << cfi->chipshift);
214430ec5a2cSIra W. Snyder 	chipstart = cfi->chips[chipnum].start;
214530ec5a2cSIra W. Snyder 
214630ec5a2cSIra W. Snyder 	/* If it's not bus aligned, do the first byte write */
214730ec5a2cSIra W. Snyder 	if (ofs & (map_bankwidth(map) - 1)) {
214830ec5a2cSIra W. Snyder 		unsigned long bus_ofs = ofs & ~(map_bankwidth(map) - 1);
214930ec5a2cSIra W. Snyder 		int i = ofs - bus_ofs;
215030ec5a2cSIra W. Snyder 		int n = 0;
215130ec5a2cSIra W. Snyder 		map_word tmp_buf;
215230ec5a2cSIra W. Snyder 
215330ec5a2cSIra W. Snyder 		ret = cfi_amdstd_panic_wait(map, &cfi->chips[chipnum], bus_ofs);
215430ec5a2cSIra W. Snyder 		if (ret)
215530ec5a2cSIra W. Snyder 			return ret;
215630ec5a2cSIra W. Snyder 
215730ec5a2cSIra W. Snyder 		/* Load 'tmp_buf' with old contents of flash */
215830ec5a2cSIra W. Snyder 		tmp_buf = map_read(map, bus_ofs + chipstart);
215930ec5a2cSIra W. Snyder 
216030ec5a2cSIra W. Snyder 		/* Number of bytes to copy from buffer */
216130ec5a2cSIra W. Snyder 		n = min_t(int, len, map_bankwidth(map) - i);
216230ec5a2cSIra W. Snyder 
216330ec5a2cSIra W. Snyder 		tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n);
216430ec5a2cSIra W. Snyder 
216530ec5a2cSIra W. Snyder 		ret = do_panic_write_oneword(map, &cfi->chips[chipnum],
216630ec5a2cSIra W. Snyder 					     bus_ofs, tmp_buf);
216730ec5a2cSIra W. Snyder 		if (ret)
216830ec5a2cSIra W. Snyder 			return ret;
216930ec5a2cSIra W. Snyder 
217030ec5a2cSIra W. Snyder 		ofs += n;
217130ec5a2cSIra W. Snyder 		buf += n;
217230ec5a2cSIra W. Snyder 		(*retlen) += n;
217330ec5a2cSIra W. Snyder 		len -= n;
217430ec5a2cSIra W. Snyder 
217530ec5a2cSIra W. Snyder 		if (ofs >> cfi->chipshift) {
217630ec5a2cSIra W. Snyder 			chipnum++;
217730ec5a2cSIra W. Snyder 			ofs = 0;
217830ec5a2cSIra W. Snyder 			if (chipnum == cfi->numchips)
217930ec5a2cSIra W. Snyder 				return 0;
218030ec5a2cSIra W. Snyder 		}
218130ec5a2cSIra W. Snyder 	}
218230ec5a2cSIra W. Snyder 
218330ec5a2cSIra W. Snyder 	/* We are now aligned, write as much as possible */
218430ec5a2cSIra W. Snyder 	while (len >= map_bankwidth(map)) {
218530ec5a2cSIra W. Snyder 		map_word datum;
218630ec5a2cSIra W. Snyder 
218730ec5a2cSIra W. Snyder 		datum = map_word_load(map, buf);
218830ec5a2cSIra W. Snyder 
218930ec5a2cSIra W. Snyder 		ret = do_panic_write_oneword(map, &cfi->chips[chipnum],
219030ec5a2cSIra W. Snyder 					     ofs, datum);
219130ec5a2cSIra W. Snyder 		if (ret)
219230ec5a2cSIra W. Snyder 			return ret;
219330ec5a2cSIra W. Snyder 
219430ec5a2cSIra W. Snyder 		ofs += map_bankwidth(map);
219530ec5a2cSIra W. Snyder 		buf += map_bankwidth(map);
219630ec5a2cSIra W. Snyder 		(*retlen) += map_bankwidth(map);
219730ec5a2cSIra W. Snyder 		len -= map_bankwidth(map);
219830ec5a2cSIra W. Snyder 
219930ec5a2cSIra W. Snyder 		if (ofs >> cfi->chipshift) {
220030ec5a2cSIra W. Snyder 			chipnum++;
220130ec5a2cSIra W. Snyder 			ofs = 0;
220230ec5a2cSIra W. Snyder 			if (chipnum == cfi->numchips)
220330ec5a2cSIra W. Snyder 				return 0;
220430ec5a2cSIra W. Snyder 
220530ec5a2cSIra W. Snyder 			chipstart = cfi->chips[chipnum].start;
220630ec5a2cSIra W. Snyder 		}
220730ec5a2cSIra W. Snyder 	}
220830ec5a2cSIra W. Snyder 
220930ec5a2cSIra W. Snyder 	/* Write the trailing bytes if any */
221030ec5a2cSIra W. Snyder 	if (len & (map_bankwidth(map) - 1)) {
221130ec5a2cSIra W. Snyder 		map_word tmp_buf;
221230ec5a2cSIra W. Snyder 
221330ec5a2cSIra W. Snyder 		ret = cfi_amdstd_panic_wait(map, &cfi->chips[chipnum], ofs);
221430ec5a2cSIra W. Snyder 		if (ret)
221530ec5a2cSIra W. Snyder 			return ret;
221630ec5a2cSIra W. Snyder 
221730ec5a2cSIra W. Snyder 		tmp_buf = map_read(map, ofs + chipstart);
221830ec5a2cSIra W. Snyder 
221930ec5a2cSIra W. Snyder 		tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);
222030ec5a2cSIra W. Snyder 
222130ec5a2cSIra W. Snyder 		ret = do_panic_write_oneword(map, &cfi->chips[chipnum],
222230ec5a2cSIra W. Snyder 					     ofs, tmp_buf);
222330ec5a2cSIra W. Snyder 		if (ret)
222430ec5a2cSIra W. Snyder 			return ret;
222530ec5a2cSIra W. Snyder 
222630ec5a2cSIra W. Snyder 		(*retlen) += len;
222730ec5a2cSIra W. Snyder 	}
222830ec5a2cSIra W. Snyder 
222930ec5a2cSIra W. Snyder 	return 0;
223030ec5a2cSIra W. Snyder }
223130ec5a2cSIra W. Snyder 
22321da177e4SLinus Torvalds 
22331da177e4SLinus Torvalds /*
22341da177e4SLinus Torvalds  * Handle devices with one erase region, that only implement
22351da177e4SLinus Torvalds  * the chip erase command.
22361da177e4SLinus Torvalds  */
223702b15e34STodd Poynor static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
22381da177e4SLinus Torvalds {
22391da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
22401da177e4SLinus Torvalds 	unsigned long timeo = jiffies + HZ;
22411da177e4SLinus Torvalds 	unsigned long int adr;
22421da177e4SLinus Torvalds 	DECLARE_WAITQUEUE(wait, current);
22431da177e4SLinus Torvalds 	int ret = 0;
22441da177e4SLinus Torvalds 
22451da177e4SLinus Torvalds 	adr = cfi->addr_unlock1;
22461da177e4SLinus Torvalds 
2247c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);
22481da177e4SLinus Torvalds 	ret = get_chip(map, chip, adr, FL_WRITING);
22491da177e4SLinus Torvalds 	if (ret) {
2250c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
22511da177e4SLinus Torvalds 		return ret;
22521da177e4SLinus Torvalds 	}
22531da177e4SLinus Torvalds 
2254289c0522SBrian Norris 	pr_debug("MTD %s(): ERASE 0x%.8lx\n",
22551da177e4SLinus Torvalds 	       __func__, chip->start );
22561da177e4SLinus Torvalds 
225702b15e34STodd Poynor 	XIP_INVAL_CACHED_RANGE(map, adr, map->size);
22581da177e4SLinus Torvalds 	ENABLE_VPP(map);
225902b15e34STodd Poynor 	xip_disable(map, chip, adr);
226002b15e34STodd Poynor 
22611da177e4SLinus Torvalds 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
22621da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
22631da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
22641da177e4SLinus Torvalds 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
22651da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
22661da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
22671da177e4SLinus Torvalds 
22681da177e4SLinus Torvalds 	chip->state = FL_ERASING;
22691da177e4SLinus Torvalds 	chip->erase_suspended = 0;
22701da177e4SLinus Torvalds 	chip->in_progress_block_addr = adr;
22717b70eb14SJoakim Tjernlund 	chip->in_progress_block_mask = ~(map->size - 1);
22721da177e4SLinus Torvalds 
227302b15e34STodd Poynor 	INVALIDATE_CACHE_UDELAY(map, chip,
227402b15e34STodd Poynor 				adr, map->size,
227502b15e34STodd Poynor 				chip->erase_time*500);
22761da177e4SLinus Torvalds 
22771da177e4SLinus Torvalds 	timeo = jiffies + (HZ*20);
22781da177e4SLinus Torvalds 
22791da177e4SLinus Torvalds 	for (;;) {
22801da177e4SLinus Torvalds 		if (chip->state != FL_ERASING) {
22811da177e4SLinus Torvalds 			/* Someone's suspended the erase. Sleep */
22821da177e4SLinus Torvalds 			set_current_state(TASK_UNINTERRUPTIBLE);
22831da177e4SLinus Torvalds 			add_wait_queue(&chip->wq, &wait);
2284c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
22851da177e4SLinus Torvalds 			schedule();
22861da177e4SLinus Torvalds 			remove_wait_queue(&chip->wq, &wait);
2287c4e77376SStefani Seibold 			mutex_lock(&chip->mutex);
22881da177e4SLinus Torvalds 			continue;
22891da177e4SLinus Torvalds 		}
22901da177e4SLinus Torvalds 		if (chip->erase_suspended) {
22911da177e4SLinus Torvalds 			/* This erase was suspended and resumed.
22921da177e4SLinus Torvalds 			   Adjust the timeout */
22931da177e4SLinus Torvalds 			timeo = jiffies + (HZ*20); /* FIXME */
22941da177e4SLinus Torvalds 			chip->erase_suspended = 0;
22951da177e4SLinus Torvalds 		}
22961da177e4SLinus Torvalds 
22971da177e4SLinus Torvalds 		if (chip_ready(map, adr))
22981da177e4SLinus Torvalds 			break;
22991da177e4SLinus Torvalds 
2300fb4a90bfSEric W. Biedermann 		if (time_after(jiffies, timeo)) {
2301fb4a90bfSEric W. Biedermann 			printk(KERN_WARNING "MTD %s(): software timeout\n",
2302fb4a90bfSEric W. Biedermann 				__func__ );
2303fb4a90bfSEric W. Biedermann 			break;
2304fb4a90bfSEric W. Biedermann 		}
2305fb4a90bfSEric W. Biedermann 
23061da177e4SLinus Torvalds 		/* Latency issues. Drop the lock, wait a while and retry */
230702b15e34STodd Poynor 		UDELAY(map, chip, adr, 1000000/HZ);
23081da177e4SLinus Torvalds 	}
2309fb4a90bfSEric W. Biedermann 	/* Did we succeed? */
2310fb4a90bfSEric W. Biedermann 	if (!chip_good(map, adr, map_word_ff(map))) {
23111da177e4SLinus Torvalds 		/* reset on all failures. */
23121da177e4SLinus Torvalds 		map_write( map, CMD(0xF0), chip->start );
23131da177e4SLinus Torvalds 		/* FIXME - should have reset delay before continuing */
23141da177e4SLinus Torvalds 
23151da177e4SLinus Torvalds 		ret = -EIO;
2316fb4a90bfSEric W. Biedermann 	}
2317fb4a90bfSEric W. Biedermann 
23181da177e4SLinus Torvalds 	chip->state = FL_READY;
231902b15e34STodd Poynor 	xip_enable(map, chip, adr);
2320e7d9377eSPaul Parsons 	DISABLE_VPP(map);
23211da177e4SLinus Torvalds 	put_chip(map, chip, adr);
2322c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);
23231da177e4SLinus Torvalds 
23241da177e4SLinus Torvalds 	return ret;
23251da177e4SLinus Torvalds }
23261da177e4SLinus Torvalds 
23271da177e4SLinus Torvalds 
232802b15e34STodd Poynor static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk)
23291da177e4SLinus Torvalds {
23301da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
23311da177e4SLinus Torvalds 	unsigned long timeo = jiffies + HZ;
23321da177e4SLinus Torvalds 	DECLARE_WAITQUEUE(wait, current);
23331da177e4SLinus Torvalds 	int ret = 0;
23341da177e4SLinus Torvalds 
23351da177e4SLinus Torvalds 	adr += chip->start;
23361da177e4SLinus Torvalds 
2337c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);
23381da177e4SLinus Torvalds 	ret = get_chip(map, chip, adr, FL_ERASING);
23391da177e4SLinus Torvalds 	if (ret) {
2340c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
23411da177e4SLinus Torvalds 		return ret;
23421da177e4SLinus Torvalds 	}
23431da177e4SLinus Torvalds 
2344289c0522SBrian Norris 	pr_debug("MTD %s(): ERASE 0x%.8lx\n",
23451da177e4SLinus Torvalds 	       __func__, adr );
23461da177e4SLinus Torvalds 
234702b15e34STodd Poynor 	XIP_INVAL_CACHED_RANGE(map, adr, len);
23481da177e4SLinus Torvalds 	ENABLE_VPP(map);
234902b15e34STodd Poynor 	xip_disable(map, chip, adr);
235002b15e34STodd Poynor 
23511da177e4SLinus Torvalds 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
23521da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
23531da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
23541da177e4SLinus Torvalds 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
23551da177e4SLinus Torvalds 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
235608968041SGuillaume LECERF 	map_write(map, cfi->sector_erase_cmd, adr);
23571da177e4SLinus Torvalds 
23581da177e4SLinus Torvalds 	chip->state = FL_ERASING;
23591da177e4SLinus Torvalds 	chip->erase_suspended = 0;
23601da177e4SLinus Torvalds 	chip->in_progress_block_addr = adr;
23617b70eb14SJoakim Tjernlund 	chip->in_progress_block_mask = ~(len - 1);
23621da177e4SLinus Torvalds 
236302b15e34STodd Poynor 	INVALIDATE_CACHE_UDELAY(map, chip,
236402b15e34STodd Poynor 				adr, len,
236502b15e34STodd Poynor 				chip->erase_time*500);
23661da177e4SLinus Torvalds 
23671da177e4SLinus Torvalds 	timeo = jiffies + (HZ*20);
23681da177e4SLinus Torvalds 
23691da177e4SLinus Torvalds 	for (;;) {
23701da177e4SLinus Torvalds 		if (chip->state != FL_ERASING) {
23711da177e4SLinus Torvalds 			/* Someone's suspended the erase. Sleep */
23721da177e4SLinus Torvalds 			set_current_state(TASK_UNINTERRUPTIBLE);
23731da177e4SLinus Torvalds 			add_wait_queue(&chip->wq, &wait);
2374c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
23751da177e4SLinus Torvalds 			schedule();
23761da177e4SLinus Torvalds 			remove_wait_queue(&chip->wq, &wait);
2377c4e77376SStefani Seibold 			mutex_lock(&chip->mutex);
23781da177e4SLinus Torvalds 			continue;
23791da177e4SLinus Torvalds 		}
23801da177e4SLinus Torvalds 		if (chip->erase_suspended) {
23811da177e4SLinus Torvalds 			/* This erase was suspended and resumed.
23821da177e4SLinus Torvalds 			   Adjust the timeout */
23831da177e4SLinus Torvalds 			timeo = jiffies + (HZ*20); /* FIXME */
23841da177e4SLinus Torvalds 			chip->erase_suspended = 0;
23851da177e4SLinus Torvalds 		}
23861da177e4SLinus Torvalds 
238702b15e34STodd Poynor 		if (chip_ready(map, adr)) {
238802b15e34STodd Poynor 			xip_enable(map, chip, adr);
23891da177e4SLinus Torvalds 			break;
239002b15e34STodd Poynor 		}
23911da177e4SLinus Torvalds 
2392fb4a90bfSEric W. Biedermann 		if (time_after(jiffies, timeo)) {
239302b15e34STodd Poynor 			xip_enable(map, chip, adr);
2394fb4a90bfSEric W. Biedermann 			printk(KERN_WARNING "MTD %s(): software timeout\n",
2395fb4a90bfSEric W. Biedermann 				__func__ );
2396fb4a90bfSEric W. Biedermann 			break;
2397fb4a90bfSEric W. Biedermann 		}
2398fb4a90bfSEric W. Biedermann 
23991da177e4SLinus Torvalds 		/* Latency issues. Drop the lock, wait a while and retry */
240002b15e34STodd Poynor 		UDELAY(map, chip, adr, 1000000/HZ);
24011da177e4SLinus Torvalds 	}
2402fb4a90bfSEric W. Biedermann 	/* Did we succeed? */
240322fd9a87SThomas Gleixner 	if (!chip_good(map, adr, map_word_ff(map))) {
24041da177e4SLinus Torvalds 		/* reset on all failures. */
24051da177e4SLinus Torvalds 		map_write( map, CMD(0xF0), chip->start );
24061da177e4SLinus Torvalds 		/* FIXME - should have reset delay before continuing */
24071da177e4SLinus Torvalds 
24081da177e4SLinus Torvalds 		ret = -EIO;
2409fb4a90bfSEric W. Biedermann 	}
2410fb4a90bfSEric W. Biedermann 
24111da177e4SLinus Torvalds 	chip->state = FL_READY;
2412e7d9377eSPaul Parsons 	DISABLE_VPP(map);
24131da177e4SLinus Torvalds 	put_chip(map, chip, adr);
2414c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);
24151da177e4SLinus Torvalds 	return ret;
24161da177e4SLinus Torvalds }
24171da177e4SLinus Torvalds 
24181da177e4SLinus Torvalds 
2419ce0f33adSBen Dooks static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
24201da177e4SLinus Torvalds {
2421e7bfb3fdSBoris Brezillon 	return cfi_varsize_frob(mtd, do_erase_oneblock, instr->addr,
2422e7bfb3fdSBoris Brezillon 				instr->len, NULL);
24231da177e4SLinus Torvalds }
24241da177e4SLinus Torvalds 
24251da177e4SLinus Torvalds 
24261da177e4SLinus Torvalds static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr)
24271da177e4SLinus Torvalds {
24281da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
24291da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
24301da177e4SLinus Torvalds 
24311da177e4SLinus Torvalds 	if (instr->addr != 0)
24321da177e4SLinus Torvalds 		return -EINVAL;
24331da177e4SLinus Torvalds 
24341da177e4SLinus Torvalds 	if (instr->len != mtd->size)
24351da177e4SLinus Torvalds 		return -EINVAL;
24361da177e4SLinus Torvalds 
2437e7bfb3fdSBoris Brezillon 	return do_erase_chip(map, &cfi->chips[0]);
24381da177e4SLinus Torvalds }
24391da177e4SLinus Torvalds 
24400165508cSHaavard Skinnemoen static int do_atmel_lock(struct map_info *map, struct flchip *chip,
24410165508cSHaavard Skinnemoen 			 unsigned long adr, int len, void *thunk)
24420165508cSHaavard Skinnemoen {
24430165508cSHaavard Skinnemoen 	struct cfi_private *cfi = map->fldrv_priv;
24440165508cSHaavard Skinnemoen 	int ret;
24450165508cSHaavard Skinnemoen 
2446c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);
24470165508cSHaavard Skinnemoen 	ret = get_chip(map, chip, adr + chip->start, FL_LOCKING);
24480165508cSHaavard Skinnemoen 	if (ret)
24490165508cSHaavard Skinnemoen 		goto out_unlock;
24500165508cSHaavard Skinnemoen 	chip->state = FL_LOCKING;
24510165508cSHaavard Skinnemoen 
24520a32a102SBrian Norris 	pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", __func__, adr, len);
24530165508cSHaavard Skinnemoen 
24540165508cSHaavard Skinnemoen 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
24550165508cSHaavard Skinnemoen 			 cfi->device_type, NULL);
24560165508cSHaavard Skinnemoen 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
24570165508cSHaavard Skinnemoen 			 cfi->device_type, NULL);
24580165508cSHaavard Skinnemoen 	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi,
24590165508cSHaavard Skinnemoen 			 cfi->device_type, NULL);
24600165508cSHaavard Skinnemoen 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
24610165508cSHaavard Skinnemoen 			 cfi->device_type, NULL);
24620165508cSHaavard Skinnemoen 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
24630165508cSHaavard Skinnemoen 			 cfi->device_type, NULL);
24640165508cSHaavard Skinnemoen 	map_write(map, CMD(0x40), chip->start + adr);
24650165508cSHaavard Skinnemoen 
24660165508cSHaavard Skinnemoen 	chip->state = FL_READY;
24670165508cSHaavard Skinnemoen 	put_chip(map, chip, adr + chip->start);
24680165508cSHaavard Skinnemoen 	ret = 0;
24690165508cSHaavard Skinnemoen 
24700165508cSHaavard Skinnemoen out_unlock:
2471c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);
24720165508cSHaavard Skinnemoen 	return ret;
24730165508cSHaavard Skinnemoen }
24740165508cSHaavard Skinnemoen 
24750165508cSHaavard Skinnemoen static int do_atmel_unlock(struct map_info *map, struct flchip *chip,
24760165508cSHaavard Skinnemoen 			   unsigned long adr, int len, void *thunk)
24770165508cSHaavard Skinnemoen {
24780165508cSHaavard Skinnemoen 	struct cfi_private *cfi = map->fldrv_priv;
24790165508cSHaavard Skinnemoen 	int ret;
24800165508cSHaavard Skinnemoen 
2481c4e77376SStefani Seibold 	mutex_lock(&chip->mutex);
24820165508cSHaavard Skinnemoen 	ret = get_chip(map, chip, adr + chip->start, FL_UNLOCKING);
24830165508cSHaavard Skinnemoen 	if (ret)
24840165508cSHaavard Skinnemoen 		goto out_unlock;
24850165508cSHaavard Skinnemoen 	chip->state = FL_UNLOCKING;
24860165508cSHaavard Skinnemoen 
24870a32a102SBrian Norris 	pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", __func__, adr, len);
24880165508cSHaavard Skinnemoen 
24890165508cSHaavard Skinnemoen 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
24900165508cSHaavard Skinnemoen 			 cfi->device_type, NULL);
24910165508cSHaavard Skinnemoen 	map_write(map, CMD(0x70), adr);
24920165508cSHaavard Skinnemoen 
24930165508cSHaavard Skinnemoen 	chip->state = FL_READY;
24940165508cSHaavard Skinnemoen 	put_chip(map, chip, adr + chip->start);
24950165508cSHaavard Skinnemoen 	ret = 0;
24960165508cSHaavard Skinnemoen 
24970165508cSHaavard Skinnemoen out_unlock:
2498c4e77376SStefani Seibold 	mutex_unlock(&chip->mutex);
24990165508cSHaavard Skinnemoen 	return ret;
25000165508cSHaavard Skinnemoen }
25010165508cSHaavard Skinnemoen 
250269423d99SAdrian Hunter static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
25030165508cSHaavard Skinnemoen {
25040165508cSHaavard Skinnemoen 	return cfi_varsize_frob(mtd, do_atmel_lock, ofs, len, NULL);
25050165508cSHaavard Skinnemoen }
25060165508cSHaavard Skinnemoen 
250769423d99SAdrian Hunter static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
25080165508cSHaavard Skinnemoen {
25090165508cSHaavard Skinnemoen 	return cfi_varsize_frob(mtd, do_atmel_unlock, ofs, len, NULL);
25100165508cSHaavard Skinnemoen }
25110165508cSHaavard Skinnemoen 
25121648eaaaSStefan Roese /*
25131648eaaaSStefan Roese  * Advanced Sector Protection - PPB (Persistent Protection Bit) locking
25141648eaaaSStefan Roese  */
25151648eaaaSStefan Roese 
25161648eaaaSStefan Roese struct ppb_lock {
25171648eaaaSStefan Roese 	struct flchip *chip;
25181648eaaaSStefan Roese 	loff_t offset;
25191648eaaaSStefan Roese 	int locked;
25201648eaaaSStefan Roese };
25211648eaaaSStefan Roese 
25221648eaaaSStefan Roese #define MAX_SECTORS			512
25231648eaaaSStefan Roese 
25241648eaaaSStefan Roese #define DO_XXLOCK_ONEBLOCK_LOCK		((void *)1)
25251648eaaaSStefan Roese #define DO_XXLOCK_ONEBLOCK_UNLOCK	((void *)2)
25261648eaaaSStefan Roese #define DO_XXLOCK_ONEBLOCK_GETLOCK	((void *)3)
25271648eaaaSStefan Roese 
25281648eaaaSStefan Roese static int __maybe_unused do_ppb_xxlock(struct map_info *map,
25291648eaaaSStefan Roese 					struct flchip *chip,
25301648eaaaSStefan Roese 					unsigned long adr, int len, void *thunk)
25311648eaaaSStefan Roese {
25321648eaaaSStefan Roese 	struct cfi_private *cfi = map->fldrv_priv;
25331648eaaaSStefan Roese 	unsigned long timeo;
25341648eaaaSStefan Roese 	int ret;
25351648eaaaSStefan Roese 
25361648eaaaSStefan Roese 	mutex_lock(&chip->mutex);
25371648eaaaSStefan Roese 	ret = get_chip(map, chip, adr + chip->start, FL_LOCKING);
25381648eaaaSStefan Roese 	if (ret) {
25391648eaaaSStefan Roese 		mutex_unlock(&chip->mutex);
25401648eaaaSStefan Roese 		return ret;
25411648eaaaSStefan Roese 	}
25421648eaaaSStefan Roese 
25431648eaaaSStefan Roese 	pr_debug("MTD %s(): XXLOCK 0x%08lx len %d\n", __func__, adr, len);
25441648eaaaSStefan Roese 
25451648eaaaSStefan Roese 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
25461648eaaaSStefan Roese 			 cfi->device_type, NULL);
25471648eaaaSStefan Roese 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
25481648eaaaSStefan Roese 			 cfi->device_type, NULL);
25491648eaaaSStefan Roese 	/* PPB entry command */
25501648eaaaSStefan Roese 	cfi_send_gen_cmd(0xC0, cfi->addr_unlock1, chip->start, map, cfi,
25511648eaaaSStefan Roese 			 cfi->device_type, NULL);
25521648eaaaSStefan Roese 
25531648eaaaSStefan Roese 	if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) {
25541648eaaaSStefan Roese 		chip->state = FL_LOCKING;
25551648eaaaSStefan Roese 		map_write(map, CMD(0xA0), chip->start + adr);
25561648eaaaSStefan Roese 		map_write(map, CMD(0x00), chip->start + adr);
25571648eaaaSStefan Roese 	} else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) {
25581648eaaaSStefan Roese 		/*
25591648eaaaSStefan Roese 		 * Unlocking of one specific sector is not supported, so we
25601648eaaaSStefan Roese 		 * have to unlock all sectors of this device instead
25611648eaaaSStefan Roese 		 */
25621648eaaaSStefan Roese 		chip->state = FL_UNLOCKING;
25631648eaaaSStefan Roese 		map_write(map, CMD(0x80), chip->start);
25641648eaaaSStefan Roese 		map_write(map, CMD(0x30), chip->start);
25651648eaaaSStefan Roese 	} else if (thunk == DO_XXLOCK_ONEBLOCK_GETLOCK) {
25661648eaaaSStefan Roese 		chip->state = FL_JEDEC_QUERY;
25671648eaaaSStefan Roese 		/* Return locked status: 0->locked, 1->unlocked */
25681648eaaaSStefan Roese 		ret = !cfi_read_query(map, adr);
25691648eaaaSStefan Roese 	} else
25701648eaaaSStefan Roese 		BUG();
25711648eaaaSStefan Roese 
25721648eaaaSStefan Roese 	/*
25731648eaaaSStefan Roese 	 * Wait for some time as unlocking of all sectors takes quite long
25741648eaaaSStefan Roese 	 */
25751648eaaaSStefan Roese 	timeo = jiffies + msecs_to_jiffies(2000);	/* 2s max (un)locking */
25761648eaaaSStefan Roese 	for (;;) {
25771648eaaaSStefan Roese 		if (chip_ready(map, adr))
25781648eaaaSStefan Roese 			break;
25791648eaaaSStefan Roese 
25801648eaaaSStefan Roese 		if (time_after(jiffies, timeo)) {
25811648eaaaSStefan Roese 			printk(KERN_ERR "Waiting for chip to be ready timed out.\n");
25821648eaaaSStefan Roese 			ret = -EIO;
25831648eaaaSStefan Roese 			break;
25841648eaaaSStefan Roese 		}
25851648eaaaSStefan Roese 
25861648eaaaSStefan Roese 		UDELAY(map, chip, adr, 1);
25871648eaaaSStefan Roese 	}
25881648eaaaSStefan Roese 
25891648eaaaSStefan Roese 	/* Exit BC commands */
25901648eaaaSStefan Roese 	map_write(map, CMD(0x90), chip->start);
25911648eaaaSStefan Roese 	map_write(map, CMD(0x00), chip->start);
25921648eaaaSStefan Roese 
25931648eaaaSStefan Roese 	chip->state = FL_READY;
25941648eaaaSStefan Roese 	put_chip(map, chip, adr + chip->start);
25951648eaaaSStefan Roese 	mutex_unlock(&chip->mutex);
25961648eaaaSStefan Roese 
25971648eaaaSStefan Roese 	return ret;
25981648eaaaSStefan Roese }
25991648eaaaSStefan Roese 
26001648eaaaSStefan Roese static int __maybe_unused cfi_ppb_lock(struct mtd_info *mtd, loff_t ofs,
26011648eaaaSStefan Roese 				       uint64_t len)
26021648eaaaSStefan Roese {
26031648eaaaSStefan Roese 	return cfi_varsize_frob(mtd, do_ppb_xxlock, ofs, len,
26041648eaaaSStefan Roese 				DO_XXLOCK_ONEBLOCK_LOCK);
26051648eaaaSStefan Roese }
26061648eaaaSStefan Roese 
26071648eaaaSStefan Roese static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs,
26081648eaaaSStefan Roese 					 uint64_t len)
26091648eaaaSStefan Roese {
26101648eaaaSStefan Roese 	struct mtd_erase_region_info *regions = mtd->eraseregions;
26111648eaaaSStefan Roese 	struct map_info *map = mtd->priv;
26121648eaaaSStefan Roese 	struct cfi_private *cfi = map->fldrv_priv;
26131648eaaaSStefan Roese 	struct ppb_lock *sect;
26141648eaaaSStefan Roese 	unsigned long adr;
26151648eaaaSStefan Roese 	loff_t offset;
26161648eaaaSStefan Roese 	uint64_t length;
26171648eaaaSStefan Roese 	int chipnum;
26181648eaaaSStefan Roese 	int i;
26191648eaaaSStefan Roese 	int sectors;
26201648eaaaSStefan Roese 	int ret;
26211648eaaaSStefan Roese 
26221648eaaaSStefan Roese 	/*
26231648eaaaSStefan Roese 	 * PPB unlocking always unlocks all sectors of the flash chip.
26241648eaaaSStefan Roese 	 * We need to re-lock all previously locked sectors. So lets
26251648eaaaSStefan Roese 	 * first check the locking status of all sectors and save
26261648eaaaSStefan Roese 	 * it for future use.
26271648eaaaSStefan Roese 	 */
26281648eaaaSStefan Roese 	sect = kzalloc(MAX_SECTORS * sizeof(struct ppb_lock), GFP_KERNEL);
26291648eaaaSStefan Roese 	if (!sect)
26301648eaaaSStefan Roese 		return -ENOMEM;
26311648eaaaSStefan Roese 
26321648eaaaSStefan Roese 	/*
26331648eaaaSStefan Roese 	 * This code to walk all sectors is a slightly modified version
26341648eaaaSStefan Roese 	 * of the cfi_varsize_frob() code.
26351648eaaaSStefan Roese 	 */
26361648eaaaSStefan Roese 	i = 0;
26371648eaaaSStefan Roese 	chipnum = 0;
26381648eaaaSStefan Roese 	adr = 0;
26391648eaaaSStefan Roese 	sectors = 0;
26401648eaaaSStefan Roese 	offset = 0;
26411648eaaaSStefan Roese 	length = mtd->size;
26421648eaaaSStefan Roese 
26431648eaaaSStefan Roese 	while (length) {
26441648eaaaSStefan Roese 		int size = regions[i].erasesize;
26451648eaaaSStefan Roese 
26461648eaaaSStefan Roese 		/*
26471648eaaaSStefan Roese 		 * Only test sectors that shall not be unlocked. The other
26481648eaaaSStefan Roese 		 * sectors shall be unlocked, so lets keep their locking
26491648eaaaSStefan Roese 		 * status at "unlocked" (locked=0) for the final re-locking.
26501648eaaaSStefan Roese 		 */
26511648eaaaSStefan Roese 		if ((adr < ofs) || (adr >= (ofs + len))) {
26521648eaaaSStefan Roese 			sect[sectors].chip = &cfi->chips[chipnum];
26531648eaaaSStefan Roese 			sect[sectors].offset = offset;
26541648eaaaSStefan Roese 			sect[sectors].locked = do_ppb_xxlock(
26551648eaaaSStefan Roese 				map, &cfi->chips[chipnum], adr, 0,
26561648eaaaSStefan Roese 				DO_XXLOCK_ONEBLOCK_GETLOCK);
26571648eaaaSStefan Roese 		}
26581648eaaaSStefan Roese 
26591648eaaaSStefan Roese 		adr += size;
26601648eaaaSStefan Roese 		offset += size;
26611648eaaaSStefan Roese 		length -= size;
26621648eaaaSStefan Roese 
26631648eaaaSStefan Roese 		if (offset == regions[i].offset + size * regions[i].numblocks)
26641648eaaaSStefan Roese 			i++;
26651648eaaaSStefan Roese 
26661648eaaaSStefan Roese 		if (adr >> cfi->chipshift) {
26671648eaaaSStefan Roese 			adr = 0;
26681648eaaaSStefan Roese 			chipnum++;
26691648eaaaSStefan Roese 
26701648eaaaSStefan Roese 			if (chipnum >= cfi->numchips)
26711648eaaaSStefan Roese 				break;
26721648eaaaSStefan Roese 		}
26731648eaaaSStefan Roese 
26741648eaaaSStefan Roese 		sectors++;
26751648eaaaSStefan Roese 		if (sectors >= MAX_SECTORS) {
26761648eaaaSStefan Roese 			printk(KERN_ERR "Only %d sectors for PPB locking supported!\n",
26771648eaaaSStefan Roese 			       MAX_SECTORS);
26781648eaaaSStefan Roese 			kfree(sect);
26791648eaaaSStefan Roese 			return -EINVAL;
26801648eaaaSStefan Roese 		}
26811648eaaaSStefan Roese 	}
26821648eaaaSStefan Roese 
26831648eaaaSStefan Roese 	/* Now unlock the whole chip */
26841648eaaaSStefan Roese 	ret = cfi_varsize_frob(mtd, do_ppb_xxlock, ofs, len,
26851648eaaaSStefan Roese 			       DO_XXLOCK_ONEBLOCK_UNLOCK);
26861648eaaaSStefan Roese 	if (ret) {
26871648eaaaSStefan Roese 		kfree(sect);
26881648eaaaSStefan Roese 		return ret;
26891648eaaaSStefan Roese 	}
26901648eaaaSStefan Roese 
26911648eaaaSStefan Roese 	/*
26921648eaaaSStefan Roese 	 * PPB unlocking always unlocks all sectors of the flash chip.
26931648eaaaSStefan Roese 	 * We need to re-lock all previously locked sectors.
26941648eaaaSStefan Roese 	 */
26951648eaaaSStefan Roese 	for (i = 0; i < sectors; i++) {
26961648eaaaSStefan Roese 		if (sect[i].locked)
26971648eaaaSStefan Roese 			do_ppb_xxlock(map, sect[i].chip, sect[i].offset, 0,
26981648eaaaSStefan Roese 				      DO_XXLOCK_ONEBLOCK_LOCK);
26991648eaaaSStefan Roese 	}
27001648eaaaSStefan Roese 
27011648eaaaSStefan Roese 	kfree(sect);
27021648eaaaSStefan Roese 	return ret;
27031648eaaaSStefan Roese }
27041648eaaaSStefan Roese 
27051648eaaaSStefan Roese static int __maybe_unused cfi_ppb_is_locked(struct mtd_info *mtd, loff_t ofs,
27061648eaaaSStefan Roese 					    uint64_t len)
27071648eaaaSStefan Roese {
27081648eaaaSStefan Roese 	return cfi_varsize_frob(mtd, do_ppb_xxlock, ofs, len,
27091648eaaaSStefan Roese 				DO_XXLOCK_ONEBLOCK_GETLOCK) ? 1 : 0;
27101648eaaaSStefan Roese }
27111da177e4SLinus Torvalds 
27121da177e4SLinus Torvalds static void cfi_amdstd_sync (struct mtd_info *mtd)
27131da177e4SLinus Torvalds {
27141da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
27151da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
27161da177e4SLinus Torvalds 	int i;
27171da177e4SLinus Torvalds 	struct flchip *chip;
27181da177e4SLinus Torvalds 	int ret = 0;
27191da177e4SLinus Torvalds 	DECLARE_WAITQUEUE(wait, current);
27201da177e4SLinus Torvalds 
27211da177e4SLinus Torvalds 	for (i=0; !ret && i<cfi->numchips; i++) {
27221da177e4SLinus Torvalds 		chip = &cfi->chips[i];
27231da177e4SLinus Torvalds 
27241da177e4SLinus Torvalds 	retry:
2725c4e77376SStefani Seibold 		mutex_lock(&chip->mutex);
27261da177e4SLinus Torvalds 
27271da177e4SLinus Torvalds 		switch(chip->state) {
27281da177e4SLinus Torvalds 		case FL_READY:
27291da177e4SLinus Torvalds 		case FL_STATUS:
27301da177e4SLinus Torvalds 		case FL_CFI_QUERY:
27311da177e4SLinus Torvalds 		case FL_JEDEC_QUERY:
27321da177e4SLinus Torvalds 			chip->oldstate = chip->state;
27331da177e4SLinus Torvalds 			chip->state = FL_SYNCING;
27341da177e4SLinus Torvalds 			/* No need to wake_up() on this state change -
27351da177e4SLinus Torvalds 			 * as the whole point is that nobody can do anything
27361da177e4SLinus Torvalds 			 * with the chip now anyway.
27371da177e4SLinus Torvalds 			 */
27381da177e4SLinus Torvalds 		case FL_SYNCING:
2739c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
27401da177e4SLinus Torvalds 			break;
27411da177e4SLinus Torvalds 
27421da177e4SLinus Torvalds 		default:
27431da177e4SLinus Torvalds 			/* Not an idle state */
2744f8e30e44SDmitry Adamushko 			set_current_state(TASK_UNINTERRUPTIBLE);
27451da177e4SLinus Torvalds 			add_wait_queue(&chip->wq, &wait);
27461da177e4SLinus Torvalds 
2747c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
27481da177e4SLinus Torvalds 
27491da177e4SLinus Torvalds 			schedule();
27501da177e4SLinus Torvalds 
27511da177e4SLinus Torvalds 			remove_wait_queue(&chip->wq, &wait);
27521da177e4SLinus Torvalds 
27531da177e4SLinus Torvalds 			goto retry;
27541da177e4SLinus Torvalds 		}
27551da177e4SLinus Torvalds 	}
27561da177e4SLinus Torvalds 
27571da177e4SLinus Torvalds 	/* Unlock the chips again */
27581da177e4SLinus Torvalds 
27591da177e4SLinus Torvalds 	for (i--; i >=0; i--) {
27601da177e4SLinus Torvalds 		chip = &cfi->chips[i];
27611da177e4SLinus Torvalds 
2762c4e77376SStefani Seibold 		mutex_lock(&chip->mutex);
27631da177e4SLinus Torvalds 
27641da177e4SLinus Torvalds 		if (chip->state == FL_SYNCING) {
27651da177e4SLinus Torvalds 			chip->state = chip->oldstate;
27661da177e4SLinus Torvalds 			wake_up(&chip->wq);
27671da177e4SLinus Torvalds 		}
2768c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
27691da177e4SLinus Torvalds 	}
27701da177e4SLinus Torvalds }
27711da177e4SLinus Torvalds 
27721da177e4SLinus Torvalds 
27731da177e4SLinus Torvalds static int cfi_amdstd_suspend(struct mtd_info *mtd)
27741da177e4SLinus Torvalds {
27751da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
27761da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
27771da177e4SLinus Torvalds 	int i;
27781da177e4SLinus Torvalds 	struct flchip *chip;
27791da177e4SLinus Torvalds 	int ret = 0;
27801da177e4SLinus Torvalds 
27811da177e4SLinus Torvalds 	for (i=0; !ret && i<cfi->numchips; i++) {
27821da177e4SLinus Torvalds 		chip = &cfi->chips[i];
27831da177e4SLinus Torvalds 
2784c4e77376SStefani Seibold 		mutex_lock(&chip->mutex);
27851da177e4SLinus Torvalds 
27861da177e4SLinus Torvalds 		switch(chip->state) {
27871da177e4SLinus Torvalds 		case FL_READY:
27881da177e4SLinus Torvalds 		case FL_STATUS:
27891da177e4SLinus Torvalds 		case FL_CFI_QUERY:
27901da177e4SLinus Torvalds 		case FL_JEDEC_QUERY:
27911da177e4SLinus Torvalds 			chip->oldstate = chip->state;
27921da177e4SLinus Torvalds 			chip->state = FL_PM_SUSPENDED;
27931da177e4SLinus Torvalds 			/* No need to wake_up() on this state change -
27941da177e4SLinus Torvalds 			 * as the whole point is that nobody can do anything
27951da177e4SLinus Torvalds 			 * with the chip now anyway.
27961da177e4SLinus Torvalds 			 */
27971da177e4SLinus Torvalds 		case FL_PM_SUSPENDED:
27981da177e4SLinus Torvalds 			break;
27991da177e4SLinus Torvalds 
28001da177e4SLinus Torvalds 		default:
28011da177e4SLinus Torvalds 			ret = -EAGAIN;
28021da177e4SLinus Torvalds 			break;
28031da177e4SLinus Torvalds 		}
2804c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
28051da177e4SLinus Torvalds 	}
28061da177e4SLinus Torvalds 
28071da177e4SLinus Torvalds 	/* Unlock the chips again */
28081da177e4SLinus Torvalds 
28091da177e4SLinus Torvalds 	if (ret) {
28101da177e4SLinus Torvalds 		for (i--; i >=0; i--) {
28111da177e4SLinus Torvalds 			chip = &cfi->chips[i];
28121da177e4SLinus Torvalds 
2813c4e77376SStefani Seibold 			mutex_lock(&chip->mutex);
28141da177e4SLinus Torvalds 
28151da177e4SLinus Torvalds 			if (chip->state == FL_PM_SUSPENDED) {
28161da177e4SLinus Torvalds 				chip->state = chip->oldstate;
28171da177e4SLinus Torvalds 				wake_up(&chip->wq);
28181da177e4SLinus Torvalds 			}
2819c4e77376SStefani Seibold 			mutex_unlock(&chip->mutex);
28201da177e4SLinus Torvalds 		}
28211da177e4SLinus Torvalds 	}
28221da177e4SLinus Torvalds 
28231da177e4SLinus Torvalds 	return ret;
28241da177e4SLinus Torvalds }
28251da177e4SLinus Torvalds 
28261da177e4SLinus Torvalds 
28271da177e4SLinus Torvalds static void cfi_amdstd_resume(struct mtd_info *mtd)
28281da177e4SLinus Torvalds {
28291da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
28301da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
28311da177e4SLinus Torvalds 	int i;
28321da177e4SLinus Torvalds 	struct flchip *chip;
28331da177e4SLinus Torvalds 
28341da177e4SLinus Torvalds 	for (i=0; i<cfi->numchips; i++) {
28351da177e4SLinus Torvalds 
28361da177e4SLinus Torvalds 		chip = &cfi->chips[i];
28371da177e4SLinus Torvalds 
2838c4e77376SStefani Seibold 		mutex_lock(&chip->mutex);
28391da177e4SLinus Torvalds 
28401da177e4SLinus Torvalds 		if (chip->state == FL_PM_SUSPENDED) {
28411da177e4SLinus Torvalds 			chip->state = FL_READY;
28421da177e4SLinus Torvalds 			map_write(map, CMD(0xF0), chip->start);
28431da177e4SLinus Torvalds 			wake_up(&chip->wq);
28441da177e4SLinus Torvalds 		}
28451da177e4SLinus Torvalds 		else
28461da177e4SLinus Torvalds 			printk(KERN_ERR "Argh. Chip not in PM_SUSPENDED state upon resume()\n");
28471da177e4SLinus Torvalds 
2848c4e77376SStefani Seibold 		mutex_unlock(&chip->mutex);
28491da177e4SLinus Torvalds 	}
28501da177e4SLinus Torvalds }
28511da177e4SLinus Torvalds 
2852eafe1311SKevin Cernekee 
2853eafe1311SKevin Cernekee /*
2854eafe1311SKevin Cernekee  * Ensure that the flash device is put back into read array mode before
2855eafe1311SKevin Cernekee  * unloading the driver or rebooting.  On some systems, rebooting while
2856eafe1311SKevin Cernekee  * the flash is in query/program/erase mode will prevent the CPU from
2857eafe1311SKevin Cernekee  * fetching the bootloader code, requiring a hard reset or power cycle.
2858eafe1311SKevin Cernekee  */
2859eafe1311SKevin Cernekee static int cfi_amdstd_reset(struct mtd_info *mtd)
2860eafe1311SKevin Cernekee {
2861eafe1311SKevin Cernekee 	struct map_info *map = mtd->priv;
2862eafe1311SKevin Cernekee 	struct cfi_private *cfi = map->fldrv_priv;
2863eafe1311SKevin Cernekee 	int i, ret;
2864eafe1311SKevin Cernekee 	struct flchip *chip;
2865eafe1311SKevin Cernekee 
2866eafe1311SKevin Cernekee 	for (i = 0; i < cfi->numchips; i++) {
2867eafe1311SKevin Cernekee 
2868eafe1311SKevin Cernekee 		chip = &cfi->chips[i];
2869eafe1311SKevin Cernekee 
2870eafe1311SKevin Cernekee 		mutex_lock(&chip->mutex);
2871eafe1311SKevin Cernekee 
2872eafe1311SKevin Cernekee 		ret = get_chip(map, chip, chip->start, FL_SHUTDOWN);
2873eafe1311SKevin Cernekee 		if (!ret) {
2874eafe1311SKevin Cernekee 			map_write(map, CMD(0xF0), chip->start);
2875eafe1311SKevin Cernekee 			chip->state = FL_SHUTDOWN;
2876eafe1311SKevin Cernekee 			put_chip(map, chip, chip->start);
2877eafe1311SKevin Cernekee 		}
2878eafe1311SKevin Cernekee 
2879eafe1311SKevin Cernekee 		mutex_unlock(&chip->mutex);
2880eafe1311SKevin Cernekee 	}
2881eafe1311SKevin Cernekee 
2882eafe1311SKevin Cernekee 	return 0;
2883eafe1311SKevin Cernekee }
2884eafe1311SKevin Cernekee 
2885eafe1311SKevin Cernekee 
2886eafe1311SKevin Cernekee static int cfi_amdstd_reboot(struct notifier_block *nb, unsigned long val,
2887eafe1311SKevin Cernekee 			       void *v)
2888eafe1311SKevin Cernekee {
2889eafe1311SKevin Cernekee 	struct mtd_info *mtd;
2890eafe1311SKevin Cernekee 
2891eafe1311SKevin Cernekee 	mtd = container_of(nb, struct mtd_info, reboot_notifier);
2892eafe1311SKevin Cernekee 	cfi_amdstd_reset(mtd);
2893eafe1311SKevin Cernekee 	return NOTIFY_DONE;
2894eafe1311SKevin Cernekee }
2895eafe1311SKevin Cernekee 
2896eafe1311SKevin Cernekee 
28971da177e4SLinus Torvalds static void cfi_amdstd_destroy(struct mtd_info *mtd)
28981da177e4SLinus Torvalds {
28991da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
29001da177e4SLinus Torvalds 	struct cfi_private *cfi = map->fldrv_priv;
2901fa671646SJesper Juhl 
2902eafe1311SKevin Cernekee 	cfi_amdstd_reset(mtd);
2903eafe1311SKevin Cernekee 	unregister_reboot_notifier(&mtd->reboot_notifier);
29041da177e4SLinus Torvalds 	kfree(cfi->cmdset_priv);
29051da177e4SLinus Torvalds 	kfree(cfi->cfiq);
29061da177e4SLinus Torvalds 	kfree(cfi);
29071da177e4SLinus Torvalds 	kfree(mtd->eraseregions);
29081da177e4SLinus Torvalds }
29091da177e4SLinus Torvalds 
29101da177e4SLinus Torvalds MODULE_LICENSE("GPL");
29111da177e4SLinus Torvalds MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al.");
29121da177e4SLinus Torvalds MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips");
291380461128SGuillaume LECERF MODULE_ALIAS("cfi_cmdset_0006");
29141e804cecSDavid Woodhouse MODULE_ALIAS("cfi_cmdset_0701");
2915