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