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 4585a82e28STokunori Ikegami #define MAX_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 524844ef80SVignesh Raghavendra /* 534844ef80SVignesh Raghavendra * Status Register bit description. Used by flash devices that don't 544844ef80SVignesh Raghavendra * support DQ polling (e.g. HyperFlash) 554844ef80SVignesh Raghavendra */ 564844ef80SVignesh Raghavendra #define CFI_SR_DRB BIT(7) 574844ef80SVignesh Raghavendra #define CFI_SR_ESB BIT(5) 584844ef80SVignesh Raghavendra #define CFI_SR_PSB BIT(4) 594844ef80SVignesh Raghavendra #define CFI_SR_WBASB BIT(3) 604844ef80SVignesh Raghavendra #define CFI_SR_SLSB BIT(1) 614844ef80SVignesh Raghavendra 621da177e4SLinus Torvalds static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); 631da177e4SLinus Torvalds static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); 64557c7590STokunori Ikegami #if !FORCE_WORD_WRITE 651da177e4SLinus Torvalds static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); 66557c7590STokunori Ikegami #endif 671da177e4SLinus Torvalds static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *); 681da177e4SLinus Torvalds static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *); 691da177e4SLinus Torvalds static void cfi_amdstd_sync (struct mtd_info *); 701da177e4SLinus Torvalds static int cfi_amdstd_suspend (struct mtd_info *); 711da177e4SLinus Torvalds static void cfi_amdstd_resume (struct mtd_info *); 72eafe1311SKevin Cernekee static int cfi_amdstd_reboot(struct notifier_block *, unsigned long, void *); 73dc7e9ecdSChristian Riesch static int cfi_amdstd_get_fact_prot_info(struct mtd_info *, size_t, 74dc7e9ecdSChristian Riesch size_t *, struct otp_info *); 75dc7e9ecdSChristian Riesch static int cfi_amdstd_get_user_prot_info(struct mtd_info *, size_t, 76dc7e9ecdSChristian Riesch size_t *, struct otp_info *); 771da177e4SLinus Torvalds static int cfi_amdstd_secsi_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); 78dc7e9ecdSChristian Riesch static int cfi_amdstd_read_fact_prot_reg(struct mtd_info *, loff_t, size_t, 79dc7e9ecdSChristian Riesch size_t *, u_char *); 80dc7e9ecdSChristian Riesch static int cfi_amdstd_read_user_prot_reg(struct mtd_info *, loff_t, size_t, 81dc7e9ecdSChristian Riesch size_t *, u_char *); 82af744750SChristian Riesch static int cfi_amdstd_write_user_prot_reg(struct mtd_info *, loff_t, size_t, 83af744750SChristian Riesch size_t *, u_char *); 844f5cb243SChristian Riesch static int cfi_amdstd_lock_user_prot_reg(struct mtd_info *, loff_t, size_t); 851da177e4SLinus Torvalds 8630ec5a2cSIra W. Snyder static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, 8730ec5a2cSIra W. Snyder size_t *retlen, const u_char *buf); 8830ec5a2cSIra W. Snyder 891da177e4SLinus Torvalds static void cfi_amdstd_destroy(struct mtd_info *); 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds struct mtd_info *cfi_cmdset_0002(struct map_info *, int); 921da177e4SLinus Torvalds static struct mtd_info *cfi_amdstd_setup (struct mtd_info *); 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode); 951da177e4SLinus Torvalds static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr); 961da177e4SLinus Torvalds #include "fwh_lock.h" 971da177e4SLinus Torvalds 9869423d99SAdrian Hunter static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); 9969423d99SAdrian Hunter static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); 1000165508cSHaavard Skinnemoen 1011648eaaaSStefan Roese static int cfi_ppb_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); 1021648eaaaSStefan Roese static int cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); 1031648eaaaSStefan Roese static int cfi_ppb_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len); 1041648eaaaSStefan Roese 1051da177e4SLinus Torvalds static struct mtd_chip_driver cfi_amdstd_chipdrv = { 1061da177e4SLinus Torvalds .probe = NULL, /* Not usable directly */ 1071da177e4SLinus Torvalds .destroy = cfi_amdstd_destroy, 1081da177e4SLinus Torvalds .name = "cfi_cmdset_0002", 1091da177e4SLinus Torvalds .module = THIS_MODULE 1101da177e4SLinus Torvalds }; 1111da177e4SLinus Torvalds 1124844ef80SVignesh Raghavendra /* 1134844ef80SVignesh Raghavendra * Use status register to poll for Erase/write completion when DQ is not 1144844ef80SVignesh Raghavendra * supported. This is indicated by Bit[1:0] of SoftwareFeatures field in 1154844ef80SVignesh Raghavendra * CFI Primary Vendor-Specific Extended Query table 1.5 1164844ef80SVignesh Raghavendra */ 1174844ef80SVignesh Raghavendra static int cfi_use_status_reg(struct cfi_private *cfi) 1184844ef80SVignesh Raghavendra { 1194844ef80SVignesh Raghavendra struct cfi_pri_amdstd *extp = cfi->cmdset_priv; 1204844ef80SVignesh Raghavendra u8 poll_mask = CFI_POLL_STATUS_REG | CFI_POLL_DQ; 1214844ef80SVignesh Raghavendra 1224844ef80SVignesh Raghavendra return extp->MinorVersion >= '5' && 1234844ef80SVignesh Raghavendra (extp->SoftwareFeatures & poll_mask) == CFI_POLL_STATUS_REG; 1244844ef80SVignesh Raghavendra } 1254844ef80SVignesh Raghavendra 126c1599569SSergei Shtylyov static int cfi_check_err_status(struct map_info *map, struct flchip *chip, 1274844ef80SVignesh Raghavendra unsigned long adr) 1284844ef80SVignesh Raghavendra { 1294844ef80SVignesh Raghavendra struct cfi_private *cfi = map->fldrv_priv; 1304844ef80SVignesh Raghavendra map_word status; 1314844ef80SVignesh Raghavendra 1324844ef80SVignesh Raghavendra if (!cfi_use_status_reg(cfi)) 133c1599569SSergei Shtylyov return 0; 1344844ef80SVignesh Raghavendra 1354844ef80SVignesh Raghavendra cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi, 1364844ef80SVignesh Raghavendra cfi->device_type, NULL); 1374844ef80SVignesh Raghavendra status = map_read(map, adr); 1384844ef80SVignesh Raghavendra 13972914a8cSSergei Shtylyov /* The error bits are invalid while the chip's busy */ 14072914a8cSSergei Shtylyov if (!map_word_bitsset(map, status, CMD(CFI_SR_DRB))) 141c1599569SSergei Shtylyov return 0; 14272914a8cSSergei Shtylyov 1434844ef80SVignesh Raghavendra if (map_word_bitsset(map, status, CMD(0x3a))) { 1444844ef80SVignesh Raghavendra unsigned long chipstatus = MERGESTATUS(status); 1454844ef80SVignesh Raghavendra 1464844ef80SVignesh Raghavendra if (chipstatus & CFI_SR_ESB) 1474844ef80SVignesh Raghavendra pr_err("%s erase operation failed, status %lx\n", 1484844ef80SVignesh Raghavendra map->name, chipstatus); 1494844ef80SVignesh Raghavendra if (chipstatus & CFI_SR_PSB) 1504844ef80SVignesh Raghavendra pr_err("%s program operation failed, status %lx\n", 1514844ef80SVignesh Raghavendra map->name, chipstatus); 1524844ef80SVignesh Raghavendra if (chipstatus & CFI_SR_WBASB) 1534844ef80SVignesh Raghavendra pr_err("%s buffer program command aborted, status %lx\n", 1544844ef80SVignesh Raghavendra map->name, chipstatus); 1554844ef80SVignesh Raghavendra if (chipstatus & CFI_SR_SLSB) 1564844ef80SVignesh Raghavendra pr_err("%s sector write protected, status %lx\n", 1574844ef80SVignesh Raghavendra map->name, chipstatus); 158c1599569SSergei Shtylyov 159c1599569SSergei Shtylyov /* Erase/Program status bits are set on the operation failure */ 160c1599569SSergei Shtylyov if (chipstatus & (CFI_SR_ESB | CFI_SR_PSB)) 161c1599569SSergei Shtylyov return 1; 1624844ef80SVignesh Raghavendra } 163c1599569SSergei Shtylyov return 0; 1644844ef80SVignesh Raghavendra } 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds /* #define DEBUG_CFI_FEATURES */ 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds #ifdef DEBUG_CFI_FEATURES 1701da177e4SLinus Torvalds static void cfi_tell_features(struct cfi_pri_amdstd *extp) 1711da177e4SLinus Torvalds { 1721da177e4SLinus Torvalds const char* erase_suspend[3] = { 1731da177e4SLinus Torvalds "Not supported", "Read only", "Read/write" 1741da177e4SLinus Torvalds }; 1751da177e4SLinus Torvalds const char* top_bottom[6] = { 1761da177e4SLinus Torvalds "No WP", "8x8KiB sectors at top & bottom, no WP", 1771da177e4SLinus Torvalds "Bottom boot", "Top boot", 1781da177e4SLinus Torvalds "Uniform, Bottom WP", "Uniform, Top WP" 1791da177e4SLinus Torvalds }; 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds printk(" Silicon revision: %d\n", extp->SiliconRevision >> 1); 1821da177e4SLinus Torvalds printk(" Address sensitive unlock: %s\n", 1831da177e4SLinus Torvalds (extp->SiliconRevision & 1) ? "Not required" : "Required"); 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend)) 1861da177e4SLinus Torvalds printk(" Erase Suspend: %s\n", erase_suspend[extp->EraseSuspend]); 1871da177e4SLinus Torvalds else 1881da177e4SLinus Torvalds printk(" Erase Suspend: Unknown value %d\n", extp->EraseSuspend); 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds if (extp->BlkProt == 0) 1911da177e4SLinus Torvalds printk(" Block protection: Not supported\n"); 1921da177e4SLinus Torvalds else 1931da177e4SLinus Torvalds printk(" Block protection: %d sectors per group\n", extp->BlkProt); 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds printk(" Temporary block unprotect: %s\n", 1971da177e4SLinus Torvalds extp->TmpBlkUnprotect ? "Supported" : "Not supported"); 1981da177e4SLinus Torvalds printk(" Block protect/unprotect scheme: %d\n", extp->BlkProtUnprot); 1991da177e4SLinus Torvalds printk(" Number of simultaneous operations: %d\n", extp->SimultaneousOps); 2001da177e4SLinus Torvalds printk(" Burst mode: %s\n", 2011da177e4SLinus Torvalds extp->BurstMode ? "Supported" : "Not supported"); 2021da177e4SLinus Torvalds if (extp->PageMode == 0) 2031da177e4SLinus Torvalds printk(" Page mode: Not supported\n"); 2041da177e4SLinus Torvalds else 2051da177e4SLinus Torvalds printk(" Page mode: %d word page\n", extp->PageMode << 2); 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds printk(" Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n", 2081da177e4SLinus Torvalds extp->VppMin >> 4, extp->VppMin & 0xf); 2091da177e4SLinus Torvalds printk(" Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n", 2101da177e4SLinus Torvalds extp->VppMax >> 4, extp->VppMax & 0xf); 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds if (extp->TopBottom < ARRAY_SIZE(top_bottom)) 2131da177e4SLinus Torvalds printk(" Top/Bottom Boot Block: %s\n", top_bottom[extp->TopBottom]); 2141da177e4SLinus Torvalds else 2151da177e4SLinus Torvalds printk(" Top/Bottom Boot Block: Unknown value %d\n", extp->TopBottom); 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds #endif 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds #ifdef AMD_BOOTLOC_BUG 2201da177e4SLinus Torvalds /* Wheee. Bring me the head of someone at AMD. */ 221cc318222SGuillaume LECERF static void fixup_amd_bootblock(struct mtd_info *mtd) 2221da177e4SLinus Torvalds { 2231da177e4SLinus Torvalds struct map_info *map = mtd->priv; 2241da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 2251da177e4SLinus Torvalds struct cfi_pri_amdstd *extp = cfi->cmdset_priv; 2261da177e4SLinus Torvalds __u8 major = extp->MajorVersion; 2271da177e4SLinus Torvalds __u8 minor = extp->MinorVersion; 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds if (((major << 8) | minor) < 0x3131) { 2301da177e4SLinus Torvalds /* CFI version 1.0 => don't trust bootloc */ 23187e92c06SChristopher Moore 232289c0522SBrian Norris pr_debug("%s: JEDEC Vendor ID is 0x%02X Device ID is 0x%02X\n", 23387e92c06SChristopher Moore map->name, cfi->mfr, cfi->id); 23487e92c06SChristopher Moore 23587e92c06SChristopher Moore /* AFAICS all 29LV400 with a bottom boot block have a device ID 23687e92c06SChristopher Moore * of 0x22BA in 16-bit mode and 0xBA in 8-bit mode. 23787e92c06SChristopher Moore * These were badly detected as they have the 0x80 bit set 23887e92c06SChristopher Moore * so treat them as a special case. 23987e92c06SChristopher Moore */ 24087e92c06SChristopher Moore if (((cfi->id == 0xBA) || (cfi->id == 0x22BA)) && 24187e92c06SChristopher Moore 24287e92c06SChristopher Moore /* Macronix added CFI to their 2nd generation 24387e92c06SChristopher Moore * MX29LV400C B/T but AFAICS no other 29LV400 (AMD, 24487e92c06SChristopher Moore * Fujitsu, Spansion, EON, ESI and older Macronix) 24587e92c06SChristopher Moore * has CFI. 24687e92c06SChristopher Moore * 24787e92c06SChristopher Moore * Therefore also check the manufacturer. 24887e92c06SChristopher Moore * This reduces the risk of false detection due to 24987e92c06SChristopher Moore * the 8-bit device ID. 25087e92c06SChristopher Moore */ 251f3e69c65SGuillaume LECERF (cfi->mfr == CFI_MFR_MACRONIX)) { 252289c0522SBrian Norris pr_debug("%s: Macronix MX29LV400C with bottom boot block" 25387e92c06SChristopher Moore " detected\n", map->name); 25487e92c06SChristopher Moore extp->TopBottom = 2; /* bottom boot */ 25587e92c06SChristopher Moore } else 2561da177e4SLinus Torvalds if (cfi->id & 0x80) { 2571da177e4SLinus Torvalds printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id); 2581da177e4SLinus Torvalds extp->TopBottom = 3; /* top boot */ 2591da177e4SLinus Torvalds } else { 2601da177e4SLinus Torvalds extp->TopBottom = 2; /* bottom boot */ 2611da177e4SLinus Torvalds } 26287e92c06SChristopher Moore 263289c0522SBrian Norris pr_debug("%s: AMD CFI PRI V%c.%c has no boot block field;" 26487e92c06SChristopher Moore " deduced %s from Device ID\n", map->name, major, minor, 26587e92c06SChristopher Moore extp->TopBottom == 2 ? "bottom" : "top"); 2661da177e4SLinus Torvalds } 2671da177e4SLinus Torvalds } 2681da177e4SLinus Torvalds #endif 2691da177e4SLinus Torvalds 270557c7590STokunori Ikegami #if !FORCE_WORD_WRITE 271cc318222SGuillaume LECERF static void fixup_use_write_buffers(struct mtd_info *mtd) 2721da177e4SLinus Torvalds { 2731da177e4SLinus Torvalds struct map_info *map = mtd->priv; 2741da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 2751da177e4SLinus Torvalds if (cfi->cfiq->BufWriteTimeoutTyp) { 276289c0522SBrian Norris pr_debug("Using buffer write method\n"); 2773c3c10bbSArtem Bityutskiy mtd->_write = cfi_amdstd_write_buffers; 2781da177e4SLinus Torvalds } 2791da177e4SLinus Torvalds } 280557c7590STokunori Ikegami #endif /* !FORCE_WORD_WRITE */ 2811da177e4SLinus Torvalds 2825b0c5c2cSHaavard Skinnemoen /* Atmel chips don't use the same PRI format as AMD chips */ 283cc318222SGuillaume LECERF static void fixup_convert_atmel_pri(struct mtd_info *mtd) 2845b0c5c2cSHaavard Skinnemoen { 2855b0c5c2cSHaavard Skinnemoen struct map_info *map = mtd->priv; 2865b0c5c2cSHaavard Skinnemoen struct cfi_private *cfi = map->fldrv_priv; 2875b0c5c2cSHaavard Skinnemoen struct cfi_pri_amdstd *extp = cfi->cmdset_priv; 2885b0c5c2cSHaavard Skinnemoen struct cfi_pri_atmel atmel_pri; 2895b0c5c2cSHaavard Skinnemoen 2905b0c5c2cSHaavard Skinnemoen memcpy(&atmel_pri, extp, sizeof(atmel_pri)); 291de591dacSHåvard Skinnemoen memset((char *)extp + 5, 0, sizeof(*extp) - 5); 2925b0c5c2cSHaavard Skinnemoen 2935b0c5c2cSHaavard Skinnemoen if (atmel_pri.Features & 0x02) 2945b0c5c2cSHaavard Skinnemoen extp->EraseSuspend = 2; 2955b0c5c2cSHaavard Skinnemoen 296be8f78b8SHaavard Skinnemoen /* Some chips got it backwards... */ 297be8f78b8SHaavard Skinnemoen if (cfi->id == AT49BV6416) { 298be8f78b8SHaavard Skinnemoen if (atmel_pri.BottomBoot) 299be8f78b8SHaavard Skinnemoen extp->TopBottom = 3; 300be8f78b8SHaavard Skinnemoen else 301be8f78b8SHaavard Skinnemoen extp->TopBottom = 2; 302be8f78b8SHaavard Skinnemoen } else { 3035b0c5c2cSHaavard Skinnemoen if (atmel_pri.BottomBoot) 3045b0c5c2cSHaavard Skinnemoen extp->TopBottom = 2; 3055b0c5c2cSHaavard Skinnemoen else 3065b0c5c2cSHaavard Skinnemoen extp->TopBottom = 3; 307be8f78b8SHaavard Skinnemoen } 308d10a39d1SHans-Christian Egtvedt 309d10a39d1SHans-Christian Egtvedt /* burst write mode not supported */ 310d10a39d1SHans-Christian Egtvedt cfi->cfiq->BufWriteTimeoutTyp = 0; 311d10a39d1SHans-Christian Egtvedt cfi->cfiq->BufWriteTimeoutMax = 0; 3125b0c5c2cSHaavard Skinnemoen } 3135b0c5c2cSHaavard Skinnemoen 314cc318222SGuillaume LECERF static void fixup_use_secsi(struct mtd_info *mtd) 3151da177e4SLinus Torvalds { 3161da177e4SLinus Torvalds /* Setup for chips with a secsi area */ 3173c3c10bbSArtem Bityutskiy mtd->_read_user_prot_reg = cfi_amdstd_secsi_read; 3183c3c10bbSArtem Bityutskiy mtd->_read_fact_prot_reg = cfi_amdstd_secsi_read; 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 321cc318222SGuillaume LECERF static void fixup_use_erase_chip(struct mtd_info *mtd) 3221da177e4SLinus Torvalds { 3231da177e4SLinus Torvalds struct map_info *map = mtd->priv; 3241da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 3251da177e4SLinus Torvalds if ((cfi->cfiq->NumEraseRegions == 1) && 3261da177e4SLinus Torvalds ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) { 3273c3c10bbSArtem Bityutskiy mtd->_erase = cfi_amdstd_erase_chip; 3281da177e4SLinus Torvalds } 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds } 3311da177e4SLinus Torvalds 3320165508cSHaavard Skinnemoen /* 3330165508cSHaavard Skinnemoen * Some Atmel chips (e.g. the AT49BV6416) power-up with all sectors 3340165508cSHaavard Skinnemoen * locked by default. 3350165508cSHaavard Skinnemoen */ 336cc318222SGuillaume LECERF static void fixup_use_atmel_lock(struct mtd_info *mtd) 3370165508cSHaavard Skinnemoen { 3383c3c10bbSArtem Bityutskiy mtd->_lock = cfi_atmel_lock; 3393c3c10bbSArtem Bityutskiy mtd->_unlock = cfi_atmel_unlock; 340e619a75fSJustin Treon mtd->flags |= MTD_POWERUP_LOCK; 3410165508cSHaavard Skinnemoen } 3420165508cSHaavard Skinnemoen 34383dcd3bbSGuillaume LECERF static void fixup_old_sst_eraseregion(struct mtd_info *mtd) 34483dcd3bbSGuillaume LECERF { 34583dcd3bbSGuillaume LECERF struct map_info *map = mtd->priv; 34683dcd3bbSGuillaume LECERF struct cfi_private *cfi = map->fldrv_priv; 34783dcd3bbSGuillaume LECERF 34883dcd3bbSGuillaume LECERF /* 34925985edcSLucas De Marchi * These flashes report two separate eraseblock regions based on the 35083dcd3bbSGuillaume LECERF * sector_erase-size and block_erase-size, although they both operate on the 35183dcd3bbSGuillaume LECERF * same memory. This is not allowed according to CFI, so we just pick the 35283dcd3bbSGuillaume LECERF * sector_erase-size. 35383dcd3bbSGuillaume LECERF */ 35483dcd3bbSGuillaume LECERF cfi->cfiq->NumEraseRegions = 1; 35583dcd3bbSGuillaume LECERF } 35683dcd3bbSGuillaume LECERF 357cc318222SGuillaume LECERF static void fixup_sst39vf(struct mtd_info *mtd) 35883dcd3bbSGuillaume LECERF { 35983dcd3bbSGuillaume LECERF struct map_info *map = mtd->priv; 36083dcd3bbSGuillaume LECERF struct cfi_private *cfi = map->fldrv_priv; 36183dcd3bbSGuillaume LECERF 36283dcd3bbSGuillaume LECERF fixup_old_sst_eraseregion(mtd); 36383dcd3bbSGuillaume LECERF 36483dcd3bbSGuillaume LECERF cfi->addr_unlock1 = 0x5555; 36583dcd3bbSGuillaume LECERF cfi->addr_unlock2 = 0x2AAA; 36683dcd3bbSGuillaume LECERF } 36783dcd3bbSGuillaume LECERF 368cc318222SGuillaume LECERF static void fixup_sst39vf_rev_b(struct mtd_info *mtd) 3695a0563f0SGuillaume LECERF { 3705a0563f0SGuillaume LECERF struct map_info *map = mtd->priv; 3715a0563f0SGuillaume LECERF struct cfi_private *cfi = map->fldrv_priv; 3725a0563f0SGuillaume LECERF 3735a0563f0SGuillaume LECERF fixup_old_sst_eraseregion(mtd); 3745a0563f0SGuillaume LECERF 3755a0563f0SGuillaume LECERF cfi->addr_unlock1 = 0x555; 3765a0563f0SGuillaume LECERF cfi->addr_unlock2 = 0x2AA; 37708968041SGuillaume LECERF 37808968041SGuillaume LECERF cfi->sector_erase_cmd = CMD(0x50); 3795a0563f0SGuillaume LECERF } 3805a0563f0SGuillaume LECERF 381cc318222SGuillaume LECERF static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd) 3829fc05fcaSGuillaume LECERF { 3839fc05fcaSGuillaume LECERF struct map_info *map = mtd->priv; 3849fc05fcaSGuillaume LECERF struct cfi_private *cfi = map->fldrv_priv; 3859fc05fcaSGuillaume LECERF 386cc318222SGuillaume LECERF fixup_sst39vf_rev_b(mtd); 3879fc05fcaSGuillaume LECERF 3889fc05fcaSGuillaume LECERF /* 3899fc05fcaSGuillaume LECERF * CFI reports 1024 sectors (0x03ff+1) of 64KBytes (0x0100*256) where 3909fc05fcaSGuillaume LECERF * it should report a size of 8KBytes (0x0020*256). 3919fc05fcaSGuillaume LECERF */ 3929fc05fcaSGuillaume LECERF cfi->cfiq->EraseRegionInfo[0] = 0x002003ff; 393e8348dc5SJoe Perches pr_warn("%s: Bad 38VF640x CFI data; adjusting sector size from 64 to 8KiB\n", 394e8348dc5SJoe Perches mtd->name); 3959fc05fcaSGuillaume LECERF } 3969fc05fcaSGuillaume LECERF 397cc318222SGuillaume LECERF static void fixup_s29gl064n_sectors(struct mtd_info *mtd) 39870b07255STrent Piepho { 39970b07255STrent Piepho struct map_info *map = mtd->priv; 40070b07255STrent Piepho struct cfi_private *cfi = map->fldrv_priv; 40170b07255STrent Piepho 40270b07255STrent Piepho if ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0x003f) { 40370b07255STrent Piepho cfi->cfiq->EraseRegionInfo[0] |= 0x0040; 404e8348dc5SJoe Perches pr_warn("%s: Bad S29GL064N CFI data; adjust from 64 to 128 sectors\n", 405e8348dc5SJoe Perches mtd->name); 40670b07255STrent Piepho } 40770b07255STrent Piepho } 40870b07255STrent Piepho 409cc318222SGuillaume LECERF static void fixup_s29gl032n_sectors(struct mtd_info *mtd) 41070b07255STrent Piepho { 41170b07255STrent Piepho struct map_info *map = mtd->priv; 41270b07255STrent Piepho struct cfi_private *cfi = map->fldrv_priv; 41370b07255STrent Piepho 41470b07255STrent Piepho if ((cfi->cfiq->EraseRegionInfo[1] & 0xffff) == 0x007e) { 41570b07255STrent Piepho cfi->cfiq->EraseRegionInfo[1] &= ~0x0040; 416e8348dc5SJoe Perches pr_warn("%s: Bad S29GL032N CFI data; adjust from 127 to 63 sectors\n", 417e8348dc5SJoe Perches mtd->name); 41870b07255STrent Piepho } 41970b07255STrent Piepho } 42070b07255STrent Piepho 42143dc03c7SJavier Martin static void fixup_s29ns512p_sectors(struct mtd_info *mtd) 42243dc03c7SJavier Martin { 42343dc03c7SJavier Martin struct map_info *map = mtd->priv; 42443dc03c7SJavier Martin struct cfi_private *cfi = map->fldrv_priv; 42543dc03c7SJavier Martin 42643dc03c7SJavier Martin /* 42743dc03c7SJavier Martin * S29NS512P flash uses more than 8bits to report number of sectors, 42843dc03c7SJavier Martin * which is not permitted by CFI. 42943dc03c7SJavier Martin */ 43043dc03c7SJavier Martin cfi->cfiq->EraseRegionInfo[0] = 0x020001ff; 431e8348dc5SJoe Perches pr_warn("%s: Bad S29NS512P CFI data; adjust to 512 sectors\n", 432e8348dc5SJoe Perches mtd->name); 43343dc03c7SJavier Martin } 43443dc03c7SJavier Martin 43583dcd3bbSGuillaume LECERF /* Used to fix CFI-Tables of chips without Extended Query Tables */ 43683dcd3bbSGuillaume LECERF static struct cfi_fixup cfi_nopri_fixup_table[] = { 437cc318222SGuillaume LECERF { CFI_MFR_SST, 0x234a, fixup_sst39vf }, /* SST39VF1602 */ 438cc318222SGuillaume LECERF { CFI_MFR_SST, 0x234b, fixup_sst39vf }, /* SST39VF1601 */ 439cc318222SGuillaume LECERF { CFI_MFR_SST, 0x235a, fixup_sst39vf }, /* SST39VF3202 */ 440cc318222SGuillaume LECERF { CFI_MFR_SST, 0x235b, fixup_sst39vf }, /* SST39VF3201 */ 441cc318222SGuillaume LECERF { CFI_MFR_SST, 0x235c, fixup_sst39vf_rev_b }, /* SST39VF3202B */ 442cc318222SGuillaume LECERF { CFI_MFR_SST, 0x235d, fixup_sst39vf_rev_b }, /* SST39VF3201B */ 443cc318222SGuillaume LECERF { CFI_MFR_SST, 0x236c, fixup_sst39vf_rev_b }, /* SST39VF6402B */ 444cc318222SGuillaume LECERF { CFI_MFR_SST, 0x236d, fixup_sst39vf_rev_b }, /* SST39VF6401B */ 445cc318222SGuillaume LECERF { 0, 0, NULL } 44683dcd3bbSGuillaume LECERF }; 44783dcd3bbSGuillaume LECERF 4481da177e4SLinus Torvalds static struct cfi_fixup cfi_fixup_table[] = { 449cc318222SGuillaume LECERF { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri }, 4501da177e4SLinus Torvalds #ifdef AMD_BOOTLOC_BUG 451cc318222SGuillaume LECERF { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock }, 4521065cda8SSteffen Sledz { CFI_MFR_AMIC, CFI_ID_ANY, fixup_amd_bootblock }, 453cc318222SGuillaume LECERF { CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock }, 4541da177e4SLinus Torvalds #endif 455cc318222SGuillaume LECERF { CFI_MFR_AMD, 0x0050, fixup_use_secsi }, 456cc318222SGuillaume LECERF { CFI_MFR_AMD, 0x0053, fixup_use_secsi }, 457cc318222SGuillaume LECERF { CFI_MFR_AMD, 0x0055, fixup_use_secsi }, 458cc318222SGuillaume LECERF { CFI_MFR_AMD, 0x0056, fixup_use_secsi }, 459cc318222SGuillaume LECERF { CFI_MFR_AMD, 0x005C, fixup_use_secsi }, 460cc318222SGuillaume LECERF { CFI_MFR_AMD, 0x005F, fixup_use_secsi }, 461cc318222SGuillaume LECERF { CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors }, 462cc318222SGuillaume LECERF { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors }, 463cc318222SGuillaume LECERF { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors }, 464cc318222SGuillaume LECERF { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors }, 46543dc03c7SJavier Martin { CFI_MFR_AMD, 0x3f00, fixup_s29ns512p_sectors }, 466cc318222SGuillaume LECERF { CFI_MFR_SST, 0x536a, fixup_sst38vf640x_sectorsize }, /* SST38VF6402 */ 467cc318222SGuillaume LECERF { CFI_MFR_SST, 0x536b, fixup_sst38vf640x_sectorsize }, /* SST38VF6401 */ 468cc318222SGuillaume LECERF { CFI_MFR_SST, 0x536c, fixup_sst38vf640x_sectorsize }, /* SST38VF6404 */ 469cc318222SGuillaume LECERF { CFI_MFR_SST, 0x536d, fixup_sst38vf640x_sectorsize }, /* SST38VF6403 */ 4701da177e4SLinus Torvalds #if !FORCE_WORD_WRITE 471cc318222SGuillaume LECERF { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers }, 4721da177e4SLinus Torvalds #endif 473cc318222SGuillaume LECERF { 0, 0, NULL } 4741da177e4SLinus Torvalds }; 4751da177e4SLinus Torvalds static struct cfi_fixup jedec_fixup_table[] = { 476cc318222SGuillaume LECERF { CFI_MFR_SST, SST49LF004B, fixup_use_fwh_lock }, 477cc318222SGuillaume LECERF { CFI_MFR_SST, SST49LF040B, fixup_use_fwh_lock }, 478cc318222SGuillaume LECERF { CFI_MFR_SST, SST49LF008A, fixup_use_fwh_lock }, 479cc318222SGuillaume LECERF { 0, 0, NULL } 4801da177e4SLinus Torvalds }; 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds static struct cfi_fixup fixup_table[] = { 4831da177e4SLinus Torvalds /* The CFI vendor ids and the JEDEC vendor IDs appear 4841da177e4SLinus Torvalds * to be common. It is like the devices id's are as 4851da177e4SLinus Torvalds * well. This table is to pick all cases where 4861da177e4SLinus Torvalds * we know that is the case. 4871da177e4SLinus Torvalds */ 488cc318222SGuillaume LECERF { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip }, 489cc318222SGuillaume LECERF { CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock }, 490cc318222SGuillaume LECERF { 0, 0, NULL } 4911da177e4SLinus Torvalds }; 4921da177e4SLinus Torvalds 4931da177e4SLinus Torvalds 494fefae48bSWolfgang Grandegger static void cfi_fixup_major_minor(struct cfi_private *cfi, 495fefae48bSWolfgang Grandegger struct cfi_pri_amdstd *extp) 496fefae48bSWolfgang Grandegger { 497e6372763SGuillaume LECERF if (cfi->mfr == CFI_MFR_SAMSUNG) { 498e8953b73SGuillaume LECERF if ((extp->MajorVersion == '0' && extp->MinorVersion == '0') || 499e8953b73SGuillaume LECERF (extp->MajorVersion == '3' && extp->MinorVersion == '3')) { 500e6372763SGuillaume LECERF /* 501e6372763SGuillaume LECERF * Samsung K8P2815UQB and K8D6x16UxM chips 502e6372763SGuillaume LECERF * report major=0 / minor=0. 503e8953b73SGuillaume LECERF * K8D3x16UxC chips report major=3 / minor=3. 504e6372763SGuillaume LECERF */ 505e6372763SGuillaume LECERF printk(KERN_NOTICE " Fixing Samsung's Amd/Fujitsu" 506e6372763SGuillaume LECERF " Extended Query version to 1.%c\n", 507e6372763SGuillaume LECERF extp->MinorVersion); 508fefae48bSWolfgang Grandegger extp->MajorVersion = '1'; 509e6372763SGuillaume LECERF } 510e6372763SGuillaume LECERF } 511e6372763SGuillaume LECERF 5129fc05fcaSGuillaume LECERF /* 5139fc05fcaSGuillaume LECERF * SST 38VF640x chips report major=0xFF / minor=0xFF. 5149fc05fcaSGuillaume LECERF */ 5159fc05fcaSGuillaume LECERF if (cfi->mfr == CFI_MFR_SST && (cfi->id >> 4) == 0x0536) { 5169fc05fcaSGuillaume LECERF extp->MajorVersion = '1'; 5179fc05fcaSGuillaume LECERF extp->MinorVersion = '0'; 5189fc05fcaSGuillaume LECERF } 519fefae48bSWolfgang Grandegger } 520fefae48bSWolfgang Grandegger 52142096288SGerlando Falauto static int is_m29ew(struct cfi_private *cfi) 52242096288SGerlando Falauto { 52342096288SGerlando Falauto if (cfi->mfr == CFI_MFR_INTEL && 52442096288SGerlando Falauto ((cfi->device_type == CFI_DEVICETYPE_X8 && (cfi->id & 0xff) == 0x7e) || 52542096288SGerlando Falauto (cfi->device_type == CFI_DEVICETYPE_X16 && cfi->id == 0x227e))) 52642096288SGerlando Falauto return 1; 52742096288SGerlando Falauto return 0; 52842096288SGerlando Falauto } 52942096288SGerlando Falauto 53042096288SGerlando Falauto /* 53142096288SGerlando Falauto * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 20: 53242096288SGerlando Falauto * Some revisions of the M29EW suffer from erase suspend hang ups. In 53342096288SGerlando Falauto * particular, it can occur when the sequence 53442096288SGerlando Falauto * Erase Confirm -> Suspend -> Program -> Resume 53542096288SGerlando Falauto * causes a lockup due to internal timing issues. The consequence is that the 53642096288SGerlando Falauto * erase cannot be resumed without inserting a dummy command after programming 53742096288SGerlando Falauto * and prior to resuming. [...] The work-around is to issue a dummy write cycle 53842096288SGerlando Falauto * that writes an F0 command code before the RESUME command. 53942096288SGerlando Falauto */ 54042096288SGerlando Falauto static void cfi_fixup_m29ew_erase_suspend(struct map_info *map, 54142096288SGerlando Falauto unsigned long adr) 54242096288SGerlando Falauto { 54342096288SGerlando Falauto struct cfi_private *cfi = map->fldrv_priv; 54442096288SGerlando Falauto /* before resume, insert a dummy 0xF0 cycle for Micron M29EW devices */ 54542096288SGerlando Falauto if (is_m29ew(cfi)) 54642096288SGerlando Falauto map_write(map, CMD(0xF0), adr); 54742096288SGerlando Falauto } 54842096288SGerlando Falauto 54942096288SGerlando Falauto /* 55042096288SGerlando Falauto * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 22: 55142096288SGerlando Falauto * 55242096288SGerlando Falauto * Some revisions of the M29EW (for example, A1 and A2 step revisions) 55342096288SGerlando Falauto * are affected by a problem that could cause a hang up when an ERASE SUSPEND 55442096288SGerlando Falauto * command is issued after an ERASE RESUME operation without waiting for a 55542096288SGerlando Falauto * minimum delay. The result is that once the ERASE seems to be completed 55642096288SGerlando Falauto * (no bits are toggling), the contents of the Flash memory block on which 55742096288SGerlando Falauto * the erase was ongoing could be inconsistent with the expected values 55842096288SGerlando Falauto * (typically, the array value is stuck to the 0xC0, 0xC4, 0x80, or 0x84 55942096288SGerlando Falauto * values), causing a consequent failure of the ERASE operation. 56042096288SGerlando Falauto * The occurrence of this issue could be high, especially when file system 56142096288SGerlando Falauto * operations on the Flash are intensive. As a result, it is recommended 56242096288SGerlando Falauto * that a patch be applied. Intensive file system operations can cause many 56342096288SGerlando Falauto * calls to the garbage routine to free Flash space (also by erasing physical 56442096288SGerlando Falauto * Flash blocks) and as a result, many consecutive SUSPEND and RESUME 56542096288SGerlando Falauto * commands can occur. The problem disappears when a delay is inserted after 56642096288SGerlando Falauto * the RESUME command by using the udelay() function available in Linux. 56742096288SGerlando Falauto * The DELAY value must be tuned based on the customer's platform. 56842096288SGerlando Falauto * The maximum value that fixes the problem in all cases is 500us. 56942096288SGerlando Falauto * But, in our experience, a delay of 30 µs to 50 µs is sufficient 57042096288SGerlando Falauto * in most cases. 57142096288SGerlando Falauto * We have chosen 500µs because this latency is acceptable. 57242096288SGerlando Falauto */ 57342096288SGerlando Falauto static void cfi_fixup_m29ew_delay_after_resume(struct cfi_private *cfi) 57442096288SGerlando Falauto { 57542096288SGerlando Falauto /* 57642096288SGerlando Falauto * Resolving the Delay After Resume Issue see Micron TN-13-07 57742096288SGerlando Falauto * Worst case delay must be 500µs but 30-50µs should be ok as well 57842096288SGerlando Falauto */ 57942096288SGerlando Falauto if (is_m29ew(cfi)) 58042096288SGerlando Falauto cfi_udelay(500); 58142096288SGerlando Falauto } 58242096288SGerlando Falauto 5831da177e4SLinus Torvalds struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) 5841da177e4SLinus Torvalds { 5851da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 5861648eaaaSStefan Roese struct device_node __maybe_unused *np = map->device_node; 5871da177e4SLinus Torvalds struct mtd_info *mtd; 5881da177e4SLinus Torvalds int i; 5891da177e4SLinus Torvalds 59095b93a0cSBurman Yan mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); 5915c8b1fbbSJingoo Han if (!mtd) 5921da177e4SLinus Torvalds return NULL; 5931da177e4SLinus Torvalds mtd->priv = map; 5941da177e4SLinus Torvalds mtd->type = MTD_NORFLASH; 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds /* Fill in the default mtd operations */ 5973c3c10bbSArtem Bityutskiy mtd->_erase = cfi_amdstd_erase_varsize; 5983c3c10bbSArtem Bityutskiy mtd->_write = cfi_amdstd_write_words; 5993c3c10bbSArtem Bityutskiy mtd->_read = cfi_amdstd_read; 6003c3c10bbSArtem Bityutskiy mtd->_sync = cfi_amdstd_sync; 6013c3c10bbSArtem Bityutskiy mtd->_suspend = cfi_amdstd_suspend; 6023c3c10bbSArtem Bityutskiy mtd->_resume = cfi_amdstd_resume; 603dc7e9ecdSChristian Riesch mtd->_read_user_prot_reg = cfi_amdstd_read_user_prot_reg; 604dc7e9ecdSChristian Riesch mtd->_read_fact_prot_reg = cfi_amdstd_read_fact_prot_reg; 605dc7e9ecdSChristian Riesch mtd->_get_fact_prot_info = cfi_amdstd_get_fact_prot_info; 606dc7e9ecdSChristian Riesch mtd->_get_user_prot_info = cfi_amdstd_get_user_prot_info; 607af744750SChristian Riesch mtd->_write_user_prot_reg = cfi_amdstd_write_user_prot_reg; 6084f5cb243SChristian Riesch mtd->_lock_user_prot_reg = cfi_amdstd_lock_user_prot_reg; 6091da177e4SLinus Torvalds mtd->flags = MTD_CAP_NORFLASH; 6101da177e4SLinus Torvalds mtd->name = map->name; 611783ed81fSArtem B. Bityutskiy mtd->writesize = 1; 61213ce77f4SAnatolij Gustschin mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; 613d261c72aSAnatolij Gustschin 6140a32a102SBrian Norris pr_debug("MTD %s(): write buffer size %d\n", __func__, 6150a32a102SBrian Norris mtd->writebufsize); 6161da177e4SLinus Torvalds 6173c3c10bbSArtem Bityutskiy mtd->_panic_write = cfi_amdstd_panic_write; 618eafe1311SKevin Cernekee mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot; 619eafe1311SKevin Cernekee 6201da177e4SLinus Torvalds if (cfi->cfi_mode==CFI_MODE_CFI){ 6211da177e4SLinus Torvalds unsigned char bootloc; 6221da177e4SLinus Torvalds __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; 6231da177e4SLinus Torvalds struct cfi_pri_amdstd *extp; 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds extp = (struct cfi_pri_amdstd*)cfi_read_pri(map, adr, sizeof(*extp), "Amd/Fujitsu"); 626564b8497SGuillaume LECERF if (extp) { 627564b8497SGuillaume LECERF /* 628564b8497SGuillaume LECERF * It's a real CFI chip, not one for which the probe 629564b8497SGuillaume LECERF * routine faked a CFI structure. 630564b8497SGuillaume LECERF */ 631fefae48bSWolfgang Grandegger cfi_fixup_major_minor(cfi, extp); 632fefae48bSWolfgang Grandegger 633e17f47a1SGuillaume LECERF /* 634c9ddab25SGernot Hoyler * Valid primary extension versions are: 1.0, 1.1, 1.2, 1.3, 1.4, 1.5 635631dd1a8SJustin P. Mattock * see: http://cs.ozerki.net/zap/pub/axim-x5/docs/cfi_r20.pdf, page 19 636631dd1a8SJustin P. Mattock * http://www.spansion.com/Support/AppNotes/cfi_100_20011201.pdf 6375da19532SGuillaume LECERF * http://www.spansion.com/Support/Datasheets/s29ws-p_00_a12_e.pdf 638c9ddab25SGernot Hoyler * http://www.spansion.com/Support/Datasheets/S29GL_128S_01GS_00_02_e.pdf 639e17f47a1SGuillaume LECERF */ 640d88f977bSTodd Poynor if (extp->MajorVersion != '1' || 641c9ddab25SGernot Hoyler (extp->MajorVersion == '1' && (extp->MinorVersion < '0' || extp->MinorVersion > '5'))) { 642d88f977bSTodd Poynor printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query " 643e17f47a1SGuillaume LECERF "version %c.%c (%#02x/%#02x).\n", 644e17f47a1SGuillaume LECERF extp->MajorVersion, extp->MinorVersion, 645e17f47a1SGuillaume LECERF extp->MajorVersion, extp->MinorVersion); 646d88f977bSTodd Poynor kfree(extp); 647d88f977bSTodd Poynor kfree(mtd); 648d88f977bSTodd Poynor return NULL; 649d88f977bSTodd Poynor } 650d88f977bSTodd Poynor 651e17f47a1SGuillaume LECERF printk(KERN_INFO " Amd/Fujitsu Extended Query version %c.%c.\n", 652e17f47a1SGuillaume LECERF extp->MajorVersion, extp->MinorVersion); 653e17f47a1SGuillaume LECERF 6541da177e4SLinus Torvalds /* Install our own private info structure */ 6551da177e4SLinus Torvalds cfi->cmdset_priv = extp; 6561da177e4SLinus Torvalds 6571da177e4SLinus Torvalds /* Apply cfi device specific fixups */ 6581da177e4SLinus Torvalds cfi_fixup(mtd, cfi_fixup_table); 6591da177e4SLinus Torvalds 6601da177e4SLinus Torvalds #ifdef DEBUG_CFI_FEATURES 6611da177e4SLinus Torvalds /* Tell the user about it in lots of lovely detail */ 6621da177e4SLinus Torvalds cfi_tell_features(extp); 6631da177e4SLinus Torvalds #endif 6641da177e4SLinus Torvalds 6651648eaaaSStefan Roese #ifdef CONFIG_OF 6661648eaaaSStefan Roese if (np && of_property_read_bool( 6671648eaaaSStefan Roese np, "use-advanced-sector-protection") 6681648eaaaSStefan Roese && extp->BlkProtUnprot == 8) { 6691648eaaaSStefan Roese printk(KERN_INFO " Advanced Sector Protection (PPB Locking) supported\n"); 6701648eaaaSStefan Roese mtd->_lock = cfi_ppb_lock; 6711648eaaaSStefan Roese mtd->_unlock = cfi_ppb_unlock; 6721648eaaaSStefan Roese mtd->_is_locked = cfi_ppb_is_locked; 6731648eaaaSStefan Roese } 6741648eaaaSStefan Roese #endif 6751648eaaaSStefan Roese 6761da177e4SLinus Torvalds bootloc = extp->TopBottom; 677412da2f6SDavid Woodhouse if ((bootloc < 2) || (bootloc > 5)) { 678412da2f6SDavid Woodhouse printk(KERN_WARNING "%s: CFI contains unrecognised boot " 679412da2f6SDavid Woodhouse "bank location (%d). Assuming bottom.\n", 680abab7ebfSDavid Woodhouse map->name, bootloc); 6811da177e4SLinus Torvalds bootloc = 2; 6821da177e4SLinus Torvalds } 6831da177e4SLinus Torvalds 6841da177e4SLinus Torvalds if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) { 685412da2f6SDavid Woodhouse printk(KERN_WARNING "%s: Swapping erase regions for top-boot CFI table.\n", map->name); 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) { 6881da177e4SLinus Torvalds int j = (cfi->cfiq->NumEraseRegions-1)-i; 6891da177e4SLinus Torvalds 690fdd9d27cSFabian Frederick swap(cfi->cfiq->EraseRegionInfo[i], 691fdd9d27cSFabian Frederick cfi->cfiq->EraseRegionInfo[j]); 6921da177e4SLinus Torvalds } 6931da177e4SLinus Torvalds } 6941da177e4SLinus Torvalds /* Set the default CFI lock/unlock addresses */ 6951da177e4SLinus Torvalds cfi->addr_unlock1 = 0x555; 6961da177e4SLinus Torvalds cfi->addr_unlock2 = 0x2aa; 697564b8497SGuillaume LECERF } 69883dcd3bbSGuillaume LECERF cfi_fixup(mtd, cfi_nopri_fixup_table); 699564b8497SGuillaume LECERF 700564b8497SGuillaume LECERF if (!cfi->addr_unlock1 || !cfi->addr_unlock2) { 701564b8497SGuillaume LECERF kfree(mtd); 702564b8497SGuillaume LECERF return NULL; 703564b8497SGuillaume LECERF } 7041da177e4SLinus Torvalds 7051da177e4SLinus Torvalds } /* CFI mode */ 7061da177e4SLinus Torvalds else if (cfi->cfi_mode == CFI_MODE_JEDEC) { 7071da177e4SLinus Torvalds /* Apply jedec specific fixups */ 7081da177e4SLinus Torvalds cfi_fixup(mtd, jedec_fixup_table); 7091da177e4SLinus Torvalds } 7101da177e4SLinus Torvalds /* Apply generic fixups */ 7111da177e4SLinus Torvalds cfi_fixup(mtd, fixup_table); 7121da177e4SLinus Torvalds 7131da177e4SLinus Torvalds for (i=0; i< cfi->numchips; i++) { 7141da177e4SLinus Torvalds cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp; 7151da177e4SLinus Torvalds cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; 7161da177e4SLinus Torvalds cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; 7176534e680SBean Huo /* 7186534e680SBean Huo * First calculate the timeout max according to timeout field 7196534e680SBean Huo * of struct cfi_ident that probed from chip's CFI aera, if 7206534e680SBean Huo * available. Specify a minimum of 2000us, in case the CFI data 7216534e680SBean Huo * is wrong. 7226534e680SBean Huo */ 7236534e680SBean Huo if (cfi->cfiq->BufWriteTimeoutTyp && 7246534e680SBean Huo cfi->cfiq->BufWriteTimeoutMax) 7256534e680SBean Huo cfi->chips[i].buffer_write_time_max = 7266534e680SBean Huo 1 << (cfi->cfiq->BufWriteTimeoutTyp + 7276534e680SBean Huo cfi->cfiq->BufWriteTimeoutMax); 7286534e680SBean Huo else 7296534e680SBean Huo cfi->chips[i].buffer_write_time_max = 0; 7306534e680SBean Huo 7316534e680SBean Huo cfi->chips[i].buffer_write_time_max = 7326534e680SBean Huo max(cfi->chips[i].buffer_write_time_max, 2000); 7336534e680SBean Huo 73483d48091SVijay Sampath cfi->chips[i].ref_point_counter = 0; 73583d48091SVijay Sampath init_waitqueue_head(&(cfi->chips[i].wq)); 7361da177e4SLinus Torvalds } 7371da177e4SLinus Torvalds 7381da177e4SLinus Torvalds map->fldrv = &cfi_amdstd_chipdrv; 7391da177e4SLinus Torvalds 7401da177e4SLinus Torvalds return cfi_amdstd_setup(mtd); 7411da177e4SLinus Torvalds } 74280461128SGuillaume LECERF struct mtd_info *cfi_cmdset_0006(struct map_info *map, int primary) __attribute__((alias("cfi_cmdset_0002"))); 7431e804cecSDavid Woodhouse struct mtd_info *cfi_cmdset_0701(struct map_info *map, int primary) __attribute__((alias("cfi_cmdset_0002"))); 74483ea4ef2SDavid Woodhouse EXPORT_SYMBOL_GPL(cfi_cmdset_0002); 74580461128SGuillaume LECERF EXPORT_SYMBOL_GPL(cfi_cmdset_0006); 7461e804cecSDavid Woodhouse EXPORT_SYMBOL_GPL(cfi_cmdset_0701); 7471da177e4SLinus Torvalds 7481da177e4SLinus Torvalds static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) 7491da177e4SLinus Torvalds { 7501da177e4SLinus Torvalds struct map_info *map = mtd->priv; 7511da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 7521da177e4SLinus Torvalds unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave; 7531da177e4SLinus Torvalds unsigned long offset = 0; 7541da177e4SLinus Torvalds int i,j; 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds printk(KERN_NOTICE "number of %s chips: %d\n", 7571da177e4SLinus Torvalds (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips); 7581da177e4SLinus Torvalds /* Select the correct geometry setup */ 7591da177e4SLinus Torvalds mtd->size = devsize * cfi->numchips; 7601da177e4SLinus Torvalds 7611da177e4SLinus Torvalds mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; 7626da2ec56SKees Cook mtd->eraseregions = kmalloc_array(mtd->numeraseregions, 7636da2ec56SKees Cook sizeof(struct mtd_erase_region_info), 7646da2ec56SKees Cook GFP_KERNEL); 7655c8b1fbbSJingoo Han if (!mtd->eraseregions) 7661da177e4SLinus Torvalds goto setup_err; 7671da177e4SLinus Torvalds 7681da177e4SLinus Torvalds for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { 7691da177e4SLinus Torvalds unsigned long ernum, ersize; 7701da177e4SLinus Torvalds ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; 7711da177e4SLinus Torvalds ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1; 7721da177e4SLinus Torvalds 7731da177e4SLinus Torvalds if (mtd->erasesize < ersize) { 7741da177e4SLinus Torvalds mtd->erasesize = ersize; 7751da177e4SLinus Torvalds } 7761da177e4SLinus Torvalds for (j=0; j<cfi->numchips; j++) { 7771da177e4SLinus Torvalds mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset; 7781da177e4SLinus Torvalds mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize; 7791da177e4SLinus Torvalds mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum; 7801da177e4SLinus Torvalds } 7811da177e4SLinus Torvalds offset += (ersize * ernum); 7821da177e4SLinus Torvalds } 7831da177e4SLinus Torvalds if (offset != devsize) { 7841da177e4SLinus Torvalds /* Argh */ 7851da177e4SLinus Torvalds printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); 7861da177e4SLinus Torvalds goto setup_err; 7871da177e4SLinus Torvalds } 7881da177e4SLinus Torvalds 7891da177e4SLinus Torvalds __module_get(THIS_MODULE); 790eafe1311SKevin Cernekee register_reboot_notifier(&mtd->reboot_notifier); 7911da177e4SLinus Torvalds return mtd; 7921da177e4SLinus Torvalds 7931da177e4SLinus Torvalds setup_err: 7941da177e4SLinus Torvalds kfree(mtd->eraseregions); 7951da177e4SLinus Torvalds kfree(mtd); 7961da177e4SLinus Torvalds kfree(cfi->cmdset_priv); 7971da177e4SLinus Torvalds return NULL; 7981da177e4SLinus Torvalds } 7991da177e4SLinus Torvalds 8001da177e4SLinus Torvalds /* 8011da177e4SLinus Torvalds * Return true if the chip is ready. 8021da177e4SLinus Torvalds * 8031da177e4SLinus Torvalds * Ready is one of: read mode, query mode, erase-suspend-read mode (in any 8041da177e4SLinus Torvalds * non-suspended sector) and is indicated by no toggle bits toggling. 8051da177e4SLinus Torvalds * 8061da177e4SLinus Torvalds * Note that anything more complicated than checking if no bits are toggling 8071da177e4SLinus Torvalds * (including checking DQ5 for an error status) is tricky to get working 80825985edcSLucas De Marchi * correctly and is therefore not done (particularly with interleaved chips 80925985edcSLucas De Marchi * as each chip must be checked independently of the others). 8101da177e4SLinus Torvalds */ 8114844ef80SVignesh Raghavendra static int __xipram chip_ready(struct map_info *map, struct flchip *chip, 8124844ef80SVignesh Raghavendra unsigned long addr) 8131da177e4SLinus Torvalds { 8144844ef80SVignesh Raghavendra struct cfi_private *cfi = map->fldrv_priv; 8151da177e4SLinus Torvalds map_word d, t; 8161da177e4SLinus Torvalds 8174844ef80SVignesh Raghavendra if (cfi_use_status_reg(cfi)) { 8184844ef80SVignesh Raghavendra map_word ready = CMD(CFI_SR_DRB); 8194844ef80SVignesh Raghavendra /* 8204844ef80SVignesh Raghavendra * For chips that support status register, check device 8214844ef80SVignesh Raghavendra * ready bit 8224844ef80SVignesh Raghavendra */ 8234844ef80SVignesh Raghavendra cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi, 8244844ef80SVignesh Raghavendra cfi->device_type, NULL); 8254844ef80SVignesh Raghavendra d = map_read(map, addr); 8264844ef80SVignesh Raghavendra 8274844ef80SVignesh Raghavendra return map_word_andequal(map, d, ready, ready); 8284844ef80SVignesh Raghavendra } 8294844ef80SVignesh Raghavendra 8301da177e4SLinus Torvalds d = map_read(map, addr); 8311da177e4SLinus Torvalds t = map_read(map, addr); 8321da177e4SLinus Torvalds 8331da177e4SLinus Torvalds return map_word_equal(map, d, t); 8341da177e4SLinus Torvalds } 8351da177e4SLinus Torvalds 836fb4a90bfSEric W. Biedermann /* 837fb4a90bfSEric W. Biedermann * Return true if the chip is ready and has the correct value. 838fb4a90bfSEric W. Biedermann * 839fb4a90bfSEric W. Biedermann * Ready is one of: read mode, query mode, erase-suspend-read mode (in any 840fb4a90bfSEric W. Biedermann * non-suspended sector) and it is indicated by no bits toggling. 841fb4a90bfSEric W. Biedermann * 842fb4a90bfSEric W. Biedermann * Error are indicated by toggling bits or bits held with the wrong value, 843fb4a90bfSEric W. Biedermann * or with bits toggling. 844fb4a90bfSEric W. Biedermann * 845fb4a90bfSEric W. Biedermann * Note that anything more complicated than checking if no bits are toggling 846fb4a90bfSEric W. Biedermann * (including checking DQ5 for an error status) is tricky to get working 84725985edcSLucas De Marchi * correctly and is therefore not done (particularly with interleaved chips 84825985edcSLucas De Marchi * as each chip must be checked independently of the others). 849fb4a90bfSEric W. Biedermann * 850fb4a90bfSEric W. Biedermann */ 8514844ef80SVignesh Raghavendra static int __xipram chip_good(struct map_info *map, struct flchip *chip, 8524844ef80SVignesh Raghavendra unsigned long addr, map_word expected) 853fb4a90bfSEric W. Biedermann { 8544844ef80SVignesh Raghavendra struct cfi_private *cfi = map->fldrv_priv; 855fb4a90bfSEric W. Biedermann map_word oldd, curd; 856fb4a90bfSEric W. Biedermann 8574844ef80SVignesh Raghavendra if (cfi_use_status_reg(cfi)) { 8584844ef80SVignesh Raghavendra map_word ready = CMD(CFI_SR_DRB); 859c1599569SSergei Shtylyov 8604844ef80SVignesh Raghavendra /* 8614844ef80SVignesh Raghavendra * For chips that support status register, check device 862c1599569SSergei Shtylyov * ready bit 8634844ef80SVignesh Raghavendra */ 8644844ef80SVignesh Raghavendra cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi, 8654844ef80SVignesh Raghavendra cfi->device_type, NULL); 8664844ef80SVignesh Raghavendra curd = map_read(map, addr); 8674844ef80SVignesh Raghavendra 868c1599569SSergei Shtylyov return map_word_andequal(map, curd, ready, ready); 8694844ef80SVignesh Raghavendra } 8704844ef80SVignesh Raghavendra 871fb4a90bfSEric W. Biedermann oldd = map_read(map, addr); 872fb4a90bfSEric W. Biedermann curd = map_read(map, addr); 873fb4a90bfSEric W. Biedermann 874fb4a90bfSEric W. Biedermann return map_word_equal(map, oldd, curd) && 875fb4a90bfSEric W. Biedermann map_word_equal(map, curd, expected); 876fb4a90bfSEric W. Biedermann } 877fb4a90bfSEric W. Biedermann 8781da177e4SLinus Torvalds static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) 8791da177e4SLinus Torvalds { 8801da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current); 8811da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 8821da177e4SLinus Torvalds unsigned long timeo; 8831da177e4SLinus Torvalds struct cfi_pri_amdstd *cfip = (struct cfi_pri_amdstd *)cfi->cmdset_priv; 8841da177e4SLinus Torvalds 8851da177e4SLinus Torvalds resettime: 8861da177e4SLinus Torvalds timeo = jiffies + HZ; 8871da177e4SLinus Torvalds retry: 8881da177e4SLinus Torvalds switch (chip->state) { 8891da177e4SLinus Torvalds 8901da177e4SLinus Torvalds case FL_STATUS: 8911da177e4SLinus Torvalds for (;;) { 8924844ef80SVignesh Raghavendra if (chip_ready(map, chip, adr)) 8931da177e4SLinus Torvalds break; 8941da177e4SLinus Torvalds 8951da177e4SLinus Torvalds if (time_after(jiffies, timeo)) { 8961da177e4SLinus Torvalds printk(KERN_ERR "Waiting for chip to be ready timed out.\n"); 8971da177e4SLinus Torvalds return -EIO; 8981da177e4SLinus Torvalds } 899c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 9001da177e4SLinus Torvalds cfi_udelay(1); 901c4e77376SStefani Seibold mutex_lock(&chip->mutex); 9021da177e4SLinus Torvalds /* Someone else might have been playing with it. */ 9031da177e4SLinus Torvalds goto retry; 9041da177e4SLinus Torvalds } 905*c6f51f1fSGustavo A. R. Silva return 0; 9061da177e4SLinus Torvalds 9071da177e4SLinus Torvalds case FL_READY: 9081da177e4SLinus Torvalds case FL_CFI_QUERY: 9091da177e4SLinus Torvalds case FL_JEDEC_QUERY: 9101da177e4SLinus Torvalds return 0; 9111da177e4SLinus Torvalds 9121da177e4SLinus Torvalds case FL_ERASING: 9132695eab9SJoakim Tjernlund if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) || 9142695eab9SJoakim Tjernlund !(mode == FL_READY || mode == FL_POINT || 9152695eab9SJoakim Tjernlund (mode == FL_WRITING && (cfip->EraseSuspend & 0x2)))) 9161da177e4SLinus Torvalds goto sleep; 9171da177e4SLinus Torvalds 9187b70eb14SJoakim Tjernlund /* Do not allow suspend iff read/write to EB address */ 9197b70eb14SJoakim Tjernlund if ((adr & chip->in_progress_block_mask) == 9207b70eb14SJoakim Tjernlund chip->in_progress_block_addr) 9217b70eb14SJoakim Tjernlund goto sleep; 9221da177e4SLinus Torvalds 9231da177e4SLinus Torvalds /* Erase suspend */ 9241da177e4SLinus Torvalds /* It's harmless to issue the Erase-Suspend and Erase-Resume 9251da177e4SLinus Torvalds * commands when the erase algorithm isn't in progress. */ 9261da177e4SLinus Torvalds map_write(map, CMD(0xB0), chip->in_progress_block_addr); 9271da177e4SLinus Torvalds chip->oldstate = FL_ERASING; 9281da177e4SLinus Torvalds chip->state = FL_ERASE_SUSPENDING; 9291da177e4SLinus Torvalds chip->erase_suspended = 1; 9301da177e4SLinus Torvalds for (;;) { 9314844ef80SVignesh Raghavendra if (chip_ready(map, chip, adr)) 9321da177e4SLinus Torvalds break; 9331da177e4SLinus Torvalds 9341da177e4SLinus Torvalds if (time_after(jiffies, timeo)) { 9351da177e4SLinus Torvalds /* Should have suspended the erase by now. 9361da177e4SLinus Torvalds * Send an Erase-Resume command as either 9371da177e4SLinus Torvalds * there was an error (so leave the erase 9381da177e4SLinus Torvalds * routine to recover from it) or we trying to 9391da177e4SLinus Torvalds * use the erase-in-progress sector. */ 940100f2341STadashi Abe put_chip(map, chip, adr); 9411da177e4SLinus Torvalds printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__); 9421da177e4SLinus Torvalds return -EIO; 9431da177e4SLinus Torvalds } 9441da177e4SLinus Torvalds 945c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 9461da177e4SLinus Torvalds cfi_udelay(1); 947c4e77376SStefani Seibold mutex_lock(&chip->mutex); 9481da177e4SLinus Torvalds /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING. 9491da177e4SLinus Torvalds So we can just loop here. */ 9501da177e4SLinus Torvalds } 9511da177e4SLinus Torvalds chip->state = FL_READY; 9521da177e4SLinus Torvalds return 0; 9531da177e4SLinus Torvalds 95402b15e34STodd Poynor case FL_XIP_WHILE_ERASING: 95502b15e34STodd Poynor if (mode != FL_READY && mode != FL_POINT && 95602b15e34STodd Poynor (!cfip || !(cfip->EraseSuspend&2))) 95702b15e34STodd Poynor goto sleep; 95802b15e34STodd Poynor chip->oldstate = chip->state; 95902b15e34STodd Poynor chip->state = FL_READY; 96002b15e34STodd Poynor return 0; 96102b15e34STodd Poynor 962eafe1311SKevin Cernekee case FL_SHUTDOWN: 963eafe1311SKevin Cernekee /* The machine is rebooting */ 964eafe1311SKevin Cernekee return -EIO; 965eafe1311SKevin Cernekee 9661da177e4SLinus Torvalds case FL_POINT: 9671da177e4SLinus Torvalds /* Only if there's no operation suspended... */ 9681da177e4SLinus Torvalds if (mode == FL_READY && chip->oldstate == FL_READY) 9691da177e4SLinus Torvalds return 0; 970025a06c1SMiquel Raynal fallthrough; 9711da177e4SLinus Torvalds default: 9721da177e4SLinus Torvalds sleep: 9731da177e4SLinus Torvalds set_current_state(TASK_UNINTERRUPTIBLE); 9741da177e4SLinus Torvalds add_wait_queue(&chip->wq, &wait); 975c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 9761da177e4SLinus Torvalds schedule(); 9771da177e4SLinus Torvalds remove_wait_queue(&chip->wq, &wait); 978c4e77376SStefani Seibold mutex_lock(&chip->mutex); 9791da177e4SLinus Torvalds goto resettime; 9801da177e4SLinus Torvalds } 9811da177e4SLinus Torvalds } 9821da177e4SLinus Torvalds 9831da177e4SLinus Torvalds 9841da177e4SLinus Torvalds static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr) 9851da177e4SLinus Torvalds { 9861da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 9871da177e4SLinus Torvalds 9881da177e4SLinus Torvalds switch(chip->oldstate) { 9891da177e4SLinus Torvalds case FL_ERASING: 99042096288SGerlando Falauto cfi_fixup_m29ew_erase_suspend(map, 99142096288SGerlando Falauto chip->in_progress_block_addr); 99208968041SGuillaume LECERF map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr); 99342096288SGerlando Falauto cfi_fixup_m29ew_delay_after_resume(cfi); 9941da177e4SLinus Torvalds chip->oldstate = FL_READY; 9951da177e4SLinus Torvalds chip->state = FL_ERASING; 9961da177e4SLinus Torvalds break; 9971da177e4SLinus Torvalds 99802b15e34STodd Poynor case FL_XIP_WHILE_ERASING: 99902b15e34STodd Poynor chip->state = chip->oldstate; 100002b15e34STodd Poynor chip->oldstate = FL_READY; 100102b15e34STodd Poynor break; 100202b15e34STodd Poynor 10031da177e4SLinus Torvalds case FL_READY: 10041da177e4SLinus Torvalds case FL_STATUS: 10051da177e4SLinus Torvalds break; 10061da177e4SLinus Torvalds default: 10071da177e4SLinus Torvalds printk(KERN_ERR "MTD: put_chip() called with oldstate %d!!\n", chip->oldstate); 10081da177e4SLinus Torvalds } 10091da177e4SLinus Torvalds wake_up(&chip->wq); 10101da177e4SLinus Torvalds } 10111da177e4SLinus Torvalds 101202b15e34STodd Poynor #ifdef CONFIG_MTD_XIP 101302b15e34STodd Poynor 101402b15e34STodd Poynor /* 101502b15e34STodd Poynor * No interrupt what so ever can be serviced while the flash isn't in array 101602b15e34STodd Poynor * mode. This is ensured by the xip_disable() and xip_enable() functions 101702b15e34STodd Poynor * enclosing any code path where the flash is known not to be in array mode. 101802b15e34STodd Poynor * And within a XIP disabled code path, only functions marked with __xipram 101902b15e34STodd Poynor * may be called and nothing else (it's a good thing to inspect generated 102002b15e34STodd Poynor * assembly to make sure inline functions were actually inlined and that gcc 102102b15e34STodd Poynor * didn't emit calls to its own support functions). Also configuring MTD CFI 102202b15e34STodd Poynor * support to a single buswidth and a single interleave is also recommended. 102302b15e34STodd Poynor */ 1024f8eb321bSThomas Gleixner 102502b15e34STodd Poynor static void xip_disable(struct map_info *map, struct flchip *chip, 102602b15e34STodd Poynor unsigned long adr) 102702b15e34STodd Poynor { 102802b15e34STodd Poynor /* TODO: chips with no XIP use should ignore and return */ 102902b15e34STodd Poynor (void) map_read(map, adr); /* ensure mmu mapping is up to date */ 103002b15e34STodd Poynor local_irq_disable(); 103102b15e34STodd Poynor } 103202b15e34STodd Poynor 103302b15e34STodd Poynor static void __xipram xip_enable(struct map_info *map, struct flchip *chip, 103402b15e34STodd Poynor unsigned long adr) 103502b15e34STodd Poynor { 103602b15e34STodd Poynor struct cfi_private *cfi = map->fldrv_priv; 103702b15e34STodd Poynor 103802b15e34STodd Poynor if (chip->state != FL_POINT && chip->state != FL_READY) { 103902b15e34STodd Poynor map_write(map, CMD(0xf0), adr); 104002b15e34STodd Poynor chip->state = FL_READY; 104102b15e34STodd Poynor } 104202b15e34STodd Poynor (void) map_read(map, adr); 104397f927a4SThomas Gleixner xip_iprefetch(); 104402b15e34STodd Poynor local_irq_enable(); 104502b15e34STodd Poynor } 104602b15e34STodd Poynor 104702b15e34STodd Poynor /* 104802b15e34STodd Poynor * When a delay is required for the flash operation to complete, the 104902b15e34STodd Poynor * xip_udelay() function is polling for both the given timeout and pending 105002b15e34STodd Poynor * (but still masked) hardware interrupts. Whenever there is an interrupt 105102b15e34STodd Poynor * pending then the flash erase operation is suspended, array mode restored 105202b15e34STodd Poynor * and interrupts unmasked. Task scheduling might also happen at that 105302b15e34STodd Poynor * point. The CPU eventually returns from the interrupt or the call to 105402b15e34STodd Poynor * schedule() and the suspended flash operation is resumed for the remaining 105502b15e34STodd Poynor * of the delay period. 105602b15e34STodd Poynor * 105702b15e34STodd Poynor * Warning: this function _will_ fool interrupt latency tracing tools. 105802b15e34STodd Poynor */ 105902b15e34STodd Poynor 106002b15e34STodd Poynor static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, 106102b15e34STodd Poynor unsigned long adr, int usec) 106202b15e34STodd Poynor { 106302b15e34STodd Poynor struct cfi_private *cfi = map->fldrv_priv; 106402b15e34STodd Poynor struct cfi_pri_amdstd *extp = cfi->cmdset_priv; 106502b15e34STodd Poynor map_word status, OK = CMD(0x80); 106602b15e34STodd Poynor unsigned long suspended, start = xip_currtime(); 106702b15e34STodd Poynor flstate_t oldstate; 106802b15e34STodd Poynor 106902b15e34STodd Poynor do { 107002b15e34STodd Poynor cpu_relax(); 107102b15e34STodd Poynor if (xip_irqpending() && extp && 107202b15e34STodd Poynor ((chip->state == FL_ERASING && (extp->EraseSuspend & 2))) && 107302b15e34STodd Poynor (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) { 107402b15e34STodd Poynor /* 107502b15e34STodd Poynor * Let's suspend the erase operation when supported. 107602b15e34STodd Poynor * Note that we currently don't try to suspend 107702b15e34STodd Poynor * interleaved chips if there is already another 107802b15e34STodd Poynor * operation suspended (imagine what happens 107902b15e34STodd Poynor * when one chip was already done with the current 108002b15e34STodd Poynor * operation while another chip suspended it, then 108102b15e34STodd Poynor * we resume the whole thing at once). Yes, it 108202b15e34STodd Poynor * can happen! 108302b15e34STodd Poynor */ 108402b15e34STodd Poynor map_write(map, CMD(0xb0), adr); 108502b15e34STodd Poynor usec -= xip_elapsed_since(start); 108602b15e34STodd Poynor suspended = xip_currtime(); 108702b15e34STodd Poynor do { 108802b15e34STodd Poynor if (xip_elapsed_since(suspended) > 100000) { 108902b15e34STodd Poynor /* 109002b15e34STodd Poynor * The chip doesn't want to suspend 109102b15e34STodd Poynor * after waiting for 100 msecs. 109202b15e34STodd Poynor * This is a critical error but there 109302b15e34STodd Poynor * is not much we can do here. 109402b15e34STodd Poynor */ 109502b15e34STodd Poynor return; 109602b15e34STodd Poynor } 109702b15e34STodd Poynor status = map_read(map, adr); 109802b15e34STodd Poynor } while (!map_word_andequal(map, status, OK, OK)); 109902b15e34STodd Poynor 110002b15e34STodd Poynor /* Suspend succeeded */ 110102b15e34STodd Poynor oldstate = chip->state; 110202b15e34STodd Poynor if (!map_word_bitsset(map, status, CMD(0x40))) 110302b15e34STodd Poynor break; 110402b15e34STodd Poynor chip->state = FL_XIP_WHILE_ERASING; 110502b15e34STodd Poynor chip->erase_suspended = 1; 110602b15e34STodd Poynor map_write(map, CMD(0xf0), adr); 110702b15e34STodd Poynor (void) map_read(map, adr); 1108ca5c23c3SPaulius Zaleckas xip_iprefetch(); 110902b15e34STodd Poynor local_irq_enable(); 1110c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 1111ca5c23c3SPaulius Zaleckas xip_iprefetch(); 111202b15e34STodd Poynor cond_resched(); 111302b15e34STodd Poynor 111402b15e34STodd Poynor /* 111502b15e34STodd Poynor * We're back. However someone else might have 111602b15e34STodd Poynor * decided to go write to the chip if we are in 111702b15e34STodd Poynor * a suspended erase state. If so let's wait 111802b15e34STodd Poynor * until it's done. 111902b15e34STodd Poynor */ 1120c4e77376SStefani Seibold mutex_lock(&chip->mutex); 112102b15e34STodd Poynor while (chip->state != FL_XIP_WHILE_ERASING) { 112202b15e34STodd Poynor DECLARE_WAITQUEUE(wait, current); 112302b15e34STodd Poynor set_current_state(TASK_UNINTERRUPTIBLE); 112402b15e34STodd Poynor add_wait_queue(&chip->wq, &wait); 1125c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 112602b15e34STodd Poynor schedule(); 112702b15e34STodd Poynor remove_wait_queue(&chip->wq, &wait); 1128c4e77376SStefani Seibold mutex_lock(&chip->mutex); 112902b15e34STodd Poynor } 113002b15e34STodd Poynor /* Disallow XIP again */ 113102b15e34STodd Poynor local_irq_disable(); 113202b15e34STodd Poynor 113342096288SGerlando Falauto /* Correct Erase Suspend Hangups for M29EW */ 113442096288SGerlando Falauto cfi_fixup_m29ew_erase_suspend(map, adr); 113502b15e34STodd Poynor /* Resume the write or erase operation */ 113608968041SGuillaume LECERF map_write(map, cfi->sector_erase_cmd, adr); 113702b15e34STodd Poynor chip->state = oldstate; 113802b15e34STodd Poynor start = xip_currtime(); 113902b15e34STodd Poynor } else if (usec >= 1000000/HZ) { 114002b15e34STodd Poynor /* 114102b15e34STodd Poynor * Try to save on CPU power when waiting delay 114202b15e34STodd Poynor * is at least a system timer tick period. 114302b15e34STodd Poynor * No need to be extremely accurate here. 114402b15e34STodd Poynor */ 114502b15e34STodd Poynor xip_cpu_idle(); 114602b15e34STodd Poynor } 114702b15e34STodd Poynor status = map_read(map, adr); 114802b15e34STodd Poynor } while (!map_word_andequal(map, status, OK, OK) 114902b15e34STodd Poynor && xip_elapsed_since(start) < usec); 115002b15e34STodd Poynor } 115102b15e34STodd Poynor 115202b15e34STodd Poynor #define UDELAY(map, chip, adr, usec) xip_udelay(map, chip, adr, usec) 115302b15e34STodd Poynor 115402b15e34STodd Poynor /* 115502b15e34STodd Poynor * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while 115602b15e34STodd Poynor * the flash is actively programming or erasing since we have to poll for 115702b15e34STodd Poynor * the operation to complete anyway. We can't do that in a generic way with 115802b15e34STodd Poynor * a XIP setup so do it before the actual flash operation in this case 115902b15e34STodd Poynor * and stub it out from INVALIDATE_CACHE_UDELAY. 116002b15e34STodd Poynor */ 116102b15e34STodd Poynor #define XIP_INVAL_CACHED_RANGE(map, from, size) \ 116202b15e34STodd Poynor INVALIDATE_CACHED_RANGE(map, from, size) 116302b15e34STodd Poynor 116402b15e34STodd Poynor #define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \ 116502b15e34STodd Poynor UDELAY(map, chip, adr, usec) 116602b15e34STodd Poynor 116702b15e34STodd Poynor /* 116802b15e34STodd Poynor * Extra notes: 116902b15e34STodd Poynor * 117002b15e34STodd Poynor * Activating this XIP support changes the way the code works a bit. For 117102b15e34STodd Poynor * example the code to suspend the current process when concurrent access 117202b15e34STodd Poynor * happens is never executed because xip_udelay() will always return with the 117302b15e34STodd Poynor * same chip state as it was entered with. This is why there is no care for 117402b15e34STodd Poynor * the presence of add_wait_queue() or schedule() calls from within a couple 117502b15e34STodd Poynor * xip_disable()'d areas of code, like in do_erase_oneblock for example. 117602b15e34STodd Poynor * The queueing and scheduling are always happening within xip_udelay(). 117702b15e34STodd Poynor * 117802b15e34STodd Poynor * Similarly, get_chip() and put_chip() just happen to always be executed 117902b15e34STodd Poynor * with chip->state set to FL_READY (or FL_XIP_WHILE_*) where flash state 118002b15e34STodd Poynor * is in array mode, therefore never executing many cases therein and not 118102b15e34STodd Poynor * causing any problem with XIP. 118202b15e34STodd Poynor */ 118302b15e34STodd Poynor 118402b15e34STodd Poynor #else 118502b15e34STodd Poynor 118602b15e34STodd Poynor #define xip_disable(map, chip, adr) 118702b15e34STodd Poynor #define xip_enable(map, chip, adr) 118802b15e34STodd Poynor #define XIP_INVAL_CACHED_RANGE(x...) 118902b15e34STodd Poynor 119002b15e34STodd Poynor #define UDELAY(map, chip, adr, usec) \ 119102b15e34STodd Poynor do { \ 1192c4e77376SStefani Seibold mutex_unlock(&chip->mutex); \ 119302b15e34STodd Poynor cfi_udelay(usec); \ 1194c4e77376SStefani Seibold mutex_lock(&chip->mutex); \ 119502b15e34STodd Poynor } while (0) 119602b15e34STodd Poynor 119702b15e34STodd Poynor #define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \ 119802b15e34STodd Poynor do { \ 1199c4e77376SStefani Seibold mutex_unlock(&chip->mutex); \ 120002b15e34STodd Poynor INVALIDATE_CACHED_RANGE(map, adr, len); \ 120102b15e34STodd Poynor cfi_udelay(usec); \ 1202c4e77376SStefani Seibold mutex_lock(&chip->mutex); \ 120302b15e34STodd Poynor } while (0) 120402b15e34STodd Poynor 120502b15e34STodd Poynor #endif 12061da177e4SLinus Torvalds 12071da177e4SLinus Torvalds static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) 12081da177e4SLinus Torvalds { 12091da177e4SLinus Torvalds unsigned long cmd_addr; 12101da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 12111da177e4SLinus Torvalds int ret; 12121da177e4SLinus Torvalds 12131da177e4SLinus Torvalds adr += chip->start; 12141da177e4SLinus Torvalds 12151da177e4SLinus Torvalds /* Ensure cmd read/writes are aligned. */ 12161da177e4SLinus Torvalds cmd_addr = adr & ~(map_bankwidth(map)-1); 12171da177e4SLinus Torvalds 1218c4e77376SStefani Seibold mutex_lock(&chip->mutex); 12191da177e4SLinus Torvalds ret = get_chip(map, chip, cmd_addr, FL_READY); 12201da177e4SLinus Torvalds if (ret) { 1221c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 12221da177e4SLinus Torvalds return ret; 12231da177e4SLinus Torvalds } 12241da177e4SLinus Torvalds 12251da177e4SLinus Torvalds if (chip->state != FL_POINT && chip->state != FL_READY) { 12261da177e4SLinus Torvalds map_write(map, CMD(0xf0), cmd_addr); 12271da177e4SLinus Torvalds chip->state = FL_READY; 12281da177e4SLinus Torvalds } 12291da177e4SLinus Torvalds 12301da177e4SLinus Torvalds map_copy_from(map, buf, adr, len); 12311da177e4SLinus Torvalds 12321da177e4SLinus Torvalds put_chip(map, chip, cmd_addr); 12331da177e4SLinus Torvalds 1234c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 12351da177e4SLinus Torvalds return 0; 12361da177e4SLinus Torvalds } 12371da177e4SLinus Torvalds 12381da177e4SLinus Torvalds 12391da177e4SLinus Torvalds static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) 12401da177e4SLinus Torvalds { 12411da177e4SLinus Torvalds struct map_info *map = mtd->priv; 12421da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 12431da177e4SLinus Torvalds unsigned long ofs; 12441da177e4SLinus Torvalds int chipnum; 12451da177e4SLinus Torvalds int ret = 0; 12461da177e4SLinus Torvalds 12471da177e4SLinus Torvalds /* ofs: offset within the first chip that the first read should start */ 12481da177e4SLinus Torvalds chipnum = (from >> cfi->chipshift); 12491da177e4SLinus Torvalds ofs = from - (chipnum << cfi->chipshift); 12501da177e4SLinus Torvalds 12511da177e4SLinus Torvalds while (len) { 12521da177e4SLinus Torvalds unsigned long thislen; 12531da177e4SLinus Torvalds 12541da177e4SLinus Torvalds if (chipnum >= cfi->numchips) 12551da177e4SLinus Torvalds break; 12561da177e4SLinus Torvalds 12571da177e4SLinus Torvalds if ((len + ofs -1) >> cfi->chipshift) 12581da177e4SLinus Torvalds thislen = (1<<cfi->chipshift) - ofs; 12591da177e4SLinus Torvalds else 12601da177e4SLinus Torvalds thislen = len; 12611da177e4SLinus Torvalds 12621da177e4SLinus Torvalds ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf); 12631da177e4SLinus Torvalds if (ret) 12641da177e4SLinus Torvalds break; 12651da177e4SLinus Torvalds 12661da177e4SLinus Torvalds *retlen += thislen; 12671da177e4SLinus Torvalds len -= thislen; 12681da177e4SLinus Torvalds buf += thislen; 12691da177e4SLinus Torvalds 12701da177e4SLinus Torvalds ofs = 0; 12711da177e4SLinus Torvalds chipnum++; 12721da177e4SLinus Torvalds } 12731da177e4SLinus Torvalds return ret; 12741da177e4SLinus Torvalds } 12751da177e4SLinus Torvalds 1276dc7e9ecdSChristian Riesch typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, 12774f5cb243SChristian Riesch loff_t adr, size_t len, u_char *buf, size_t grouplen); 12781da177e4SLinus Torvalds 1279feb86779SChristian Riesch static inline void otp_enter(struct map_info *map, struct flchip *chip, 1280feb86779SChristian Riesch loff_t adr, size_t len) 1281feb86779SChristian Riesch { 1282feb86779SChristian Riesch struct cfi_private *cfi = map->fldrv_priv; 1283feb86779SChristian Riesch 1284feb86779SChristian Riesch cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, 1285feb86779SChristian Riesch cfi->device_type, NULL); 1286feb86779SChristian Riesch cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, 1287feb86779SChristian Riesch cfi->device_type, NULL); 1288feb86779SChristian Riesch cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, 1289feb86779SChristian Riesch cfi->device_type, NULL); 1290feb86779SChristian Riesch 1291feb86779SChristian Riesch INVALIDATE_CACHED_RANGE(map, chip->start + adr, len); 1292feb86779SChristian Riesch } 1293feb86779SChristian Riesch 1294feb86779SChristian Riesch static inline void otp_exit(struct map_info *map, struct flchip *chip, 1295feb86779SChristian Riesch loff_t adr, size_t len) 1296feb86779SChristian Riesch { 1297feb86779SChristian Riesch struct cfi_private *cfi = map->fldrv_priv; 1298feb86779SChristian Riesch 1299feb86779SChristian Riesch cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, 1300feb86779SChristian Riesch cfi->device_type, NULL); 1301feb86779SChristian Riesch cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, 1302feb86779SChristian Riesch cfi->device_type, NULL); 1303feb86779SChristian Riesch cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, 1304feb86779SChristian Riesch cfi->device_type, NULL); 1305feb86779SChristian Riesch cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, 1306feb86779SChristian Riesch cfi->device_type, NULL); 1307feb86779SChristian Riesch 1308feb86779SChristian Riesch INVALIDATE_CACHED_RANGE(map, chip->start + adr, len); 1309feb86779SChristian Riesch } 1310feb86779SChristian Riesch 13114f5cb243SChristian Riesch static inline int do_read_secsi_onechip(struct map_info *map, 13124f5cb243SChristian Riesch struct flchip *chip, loff_t adr, 13134f5cb243SChristian Riesch size_t len, u_char *buf, 13144f5cb243SChristian Riesch size_t grouplen) 13151da177e4SLinus Torvalds { 13161da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current); 13171da177e4SLinus Torvalds 13181da177e4SLinus Torvalds retry: 1319c4e77376SStefani Seibold mutex_lock(&chip->mutex); 13201da177e4SLinus Torvalds 13211da177e4SLinus Torvalds if (chip->state != FL_READY){ 13221da177e4SLinus Torvalds set_current_state(TASK_UNINTERRUPTIBLE); 13231da177e4SLinus Torvalds add_wait_queue(&chip->wq, &wait); 13241da177e4SLinus Torvalds 1325c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 13261da177e4SLinus Torvalds 13271da177e4SLinus Torvalds schedule(); 13281da177e4SLinus Torvalds remove_wait_queue(&chip->wq, &wait); 13291da177e4SLinus Torvalds 13301da177e4SLinus Torvalds goto retry; 13311da177e4SLinus Torvalds } 13321da177e4SLinus Torvalds 13331da177e4SLinus Torvalds adr += chip->start; 13341da177e4SLinus Torvalds 13351da177e4SLinus Torvalds chip->state = FL_READY; 13361da177e4SLinus Torvalds 1337feb86779SChristian Riesch otp_enter(map, chip, adr, len); 13381da177e4SLinus Torvalds map_copy_from(map, buf, adr, len); 1339feb86779SChristian Riesch otp_exit(map, chip, adr, len); 13401da177e4SLinus Torvalds 13411da177e4SLinus Torvalds wake_up(&chip->wq); 1342c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 13431da177e4SLinus Torvalds 13441da177e4SLinus Torvalds return 0; 13451da177e4SLinus Torvalds } 13461da177e4SLinus Torvalds 13471da177e4SLinus Torvalds static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) 13481da177e4SLinus Torvalds { 13491da177e4SLinus Torvalds struct map_info *map = mtd->priv; 13501da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 13511da177e4SLinus Torvalds unsigned long ofs; 13521da177e4SLinus Torvalds int chipnum; 13531da177e4SLinus Torvalds int ret = 0; 13541da177e4SLinus Torvalds 13551da177e4SLinus Torvalds /* ofs: offset within the first chip that the first read should start */ 13561da177e4SLinus Torvalds /* 8 secsi bytes per chip */ 13571da177e4SLinus Torvalds chipnum=from>>3; 13581da177e4SLinus Torvalds ofs=from & 7; 13591da177e4SLinus Torvalds 13601da177e4SLinus Torvalds while (len) { 13611da177e4SLinus Torvalds unsigned long thislen; 13621da177e4SLinus Torvalds 13631da177e4SLinus Torvalds if (chipnum >= cfi->numchips) 13641da177e4SLinus Torvalds break; 13651da177e4SLinus Torvalds 13661da177e4SLinus Torvalds if ((len + ofs -1) >> 3) 13671da177e4SLinus Torvalds thislen = (1<<3) - ofs; 13681da177e4SLinus Torvalds else 13691da177e4SLinus Torvalds thislen = len; 13701da177e4SLinus Torvalds 13714f5cb243SChristian Riesch ret = do_read_secsi_onechip(map, &cfi->chips[chipnum], ofs, 13724f5cb243SChristian Riesch thislen, buf, 0); 13731da177e4SLinus Torvalds if (ret) 13741da177e4SLinus Torvalds break; 13751da177e4SLinus Torvalds 13761da177e4SLinus Torvalds *retlen += thislen; 13771da177e4SLinus Torvalds len -= thislen; 13781da177e4SLinus Torvalds buf += thislen; 13791da177e4SLinus Torvalds 13801da177e4SLinus Torvalds ofs = 0; 13811da177e4SLinus Torvalds chipnum++; 13821da177e4SLinus Torvalds } 13831da177e4SLinus Torvalds return ret; 13841da177e4SLinus Torvalds } 13851da177e4SLinus Torvalds 1386af744750SChristian Riesch static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, 1387af744750SChristian Riesch unsigned long adr, map_word datum, 1388af744750SChristian Riesch int mode); 1389af744750SChristian Riesch 1390af744750SChristian Riesch static int do_otp_write(struct map_info *map, struct flchip *chip, loff_t adr, 13914f5cb243SChristian Riesch size_t len, u_char *buf, size_t grouplen) 1392af744750SChristian Riesch { 1393af744750SChristian Riesch int ret; 1394af744750SChristian Riesch while (len) { 1395af744750SChristian Riesch unsigned long bus_ofs = adr & ~(map_bankwidth(map)-1); 1396af744750SChristian Riesch int gap = adr - bus_ofs; 1397af744750SChristian Riesch int n = min_t(int, len, map_bankwidth(map) - gap); 1398636fdbf8SChristian Riesch map_word datum = map_word_ff(map); 1399af744750SChristian Riesch 1400af744750SChristian Riesch if (n != map_bankwidth(map)) { 1401af744750SChristian Riesch /* partial write of a word, load old contents */ 1402af744750SChristian Riesch otp_enter(map, chip, bus_ofs, map_bankwidth(map)); 1403af744750SChristian Riesch datum = map_read(map, bus_ofs); 1404af744750SChristian Riesch otp_exit(map, chip, bus_ofs, map_bankwidth(map)); 1405af744750SChristian Riesch } 1406af744750SChristian Riesch 1407af744750SChristian Riesch datum = map_word_load_partial(map, datum, buf, gap, n); 1408af744750SChristian Riesch ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE); 1409af744750SChristian Riesch if (ret) 1410af744750SChristian Riesch return ret; 1411af744750SChristian Riesch 1412af744750SChristian Riesch adr += n; 1413af744750SChristian Riesch buf += n; 1414af744750SChristian Riesch len -= n; 1415af744750SChristian Riesch } 1416af744750SChristian Riesch 1417af744750SChristian Riesch return 0; 1418af744750SChristian Riesch } 1419af744750SChristian Riesch 14204f5cb243SChristian Riesch static int do_otp_lock(struct map_info *map, struct flchip *chip, loff_t adr, 14214f5cb243SChristian Riesch size_t len, u_char *buf, size_t grouplen) 14224f5cb243SChristian Riesch { 14234f5cb243SChristian Riesch struct cfi_private *cfi = map->fldrv_priv; 14244f5cb243SChristian Riesch uint8_t lockreg; 14254f5cb243SChristian Riesch unsigned long timeo; 14264f5cb243SChristian Riesch int ret; 14274f5cb243SChristian Riesch 14284f5cb243SChristian Riesch /* make sure area matches group boundaries */ 14294f5cb243SChristian Riesch if ((adr != 0) || (len != grouplen)) 14304f5cb243SChristian Riesch return -EINVAL; 14314f5cb243SChristian Riesch 14324f5cb243SChristian Riesch mutex_lock(&chip->mutex); 14334f5cb243SChristian Riesch ret = get_chip(map, chip, chip->start, FL_LOCKING); 14344f5cb243SChristian Riesch if (ret) { 14354f5cb243SChristian Riesch mutex_unlock(&chip->mutex); 14364f5cb243SChristian Riesch return ret; 14374f5cb243SChristian Riesch } 14384f5cb243SChristian Riesch chip->state = FL_LOCKING; 14394f5cb243SChristian Riesch 14404f5cb243SChristian Riesch /* Enter lock register command */ 14414f5cb243SChristian Riesch cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, 14424f5cb243SChristian Riesch cfi->device_type, NULL); 14434f5cb243SChristian Riesch cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, 14444f5cb243SChristian Riesch cfi->device_type, NULL); 14454f5cb243SChristian Riesch cfi_send_gen_cmd(0x40, cfi->addr_unlock1, chip->start, map, cfi, 14464f5cb243SChristian Riesch cfi->device_type, NULL); 14474f5cb243SChristian Riesch 14484f5cb243SChristian Riesch /* read lock register */ 14494f5cb243SChristian Riesch lockreg = cfi_read_query(map, 0); 14504f5cb243SChristian Riesch 14514f5cb243SChristian Riesch /* set bit 0 to protect extended memory block */ 14524f5cb243SChristian Riesch lockreg &= ~0x01; 14534f5cb243SChristian Riesch 14544f5cb243SChristian Riesch /* set bit 0 to protect extended memory block */ 14554f5cb243SChristian Riesch /* write lock register */ 14564f5cb243SChristian Riesch map_write(map, CMD(0xA0), chip->start); 14574f5cb243SChristian Riesch map_write(map, CMD(lockreg), chip->start); 14584f5cb243SChristian Riesch 14594f5cb243SChristian Riesch /* wait for chip to become ready */ 14604f5cb243SChristian Riesch timeo = jiffies + msecs_to_jiffies(2); 14614f5cb243SChristian Riesch for (;;) { 14624844ef80SVignesh Raghavendra if (chip_ready(map, chip, adr)) 14634f5cb243SChristian Riesch break; 14644f5cb243SChristian Riesch 14654f5cb243SChristian Riesch if (time_after(jiffies, timeo)) { 14664f5cb243SChristian Riesch pr_err("Waiting for chip to be ready timed out.\n"); 14674f5cb243SChristian Riesch ret = -EIO; 14684f5cb243SChristian Riesch break; 14694f5cb243SChristian Riesch } 14704f5cb243SChristian Riesch UDELAY(map, chip, 0, 1); 14714f5cb243SChristian Riesch } 14724f5cb243SChristian Riesch 14734f5cb243SChristian Riesch /* exit protection commands */ 14744f5cb243SChristian Riesch map_write(map, CMD(0x90), chip->start); 14754f5cb243SChristian Riesch map_write(map, CMD(0x00), chip->start); 14764f5cb243SChristian Riesch 14774f5cb243SChristian Riesch chip->state = FL_READY; 14784f5cb243SChristian Riesch put_chip(map, chip, chip->start); 14794f5cb243SChristian Riesch mutex_unlock(&chip->mutex); 14804f5cb243SChristian Riesch 14814f5cb243SChristian Riesch return ret; 14824f5cb243SChristian Riesch } 14834f5cb243SChristian Riesch 1484dc7e9ecdSChristian Riesch static int cfi_amdstd_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, 1485dc7e9ecdSChristian Riesch size_t *retlen, u_char *buf, 1486dc7e9ecdSChristian Riesch otp_op_t action, int user_regs) 1487dc7e9ecdSChristian Riesch { 1488dc7e9ecdSChristian Riesch struct map_info *map = mtd->priv; 1489dc7e9ecdSChristian Riesch struct cfi_private *cfi = map->fldrv_priv; 1490dc7e9ecdSChristian Riesch int ofs_factor = cfi->interleave * cfi->device_type; 1491dc7e9ecdSChristian Riesch unsigned long base; 1492dc7e9ecdSChristian Riesch int chipnum; 1493dc7e9ecdSChristian Riesch struct flchip *chip; 1494dc7e9ecdSChristian Riesch uint8_t otp, lockreg; 1495dc7e9ecdSChristian Riesch int ret; 1496dc7e9ecdSChristian Riesch 1497dc7e9ecdSChristian Riesch size_t user_size, factory_size, otpsize; 1498dc7e9ecdSChristian Riesch loff_t user_offset, factory_offset, otpoffset; 1499dc7e9ecdSChristian Riesch int user_locked = 0, otplocked; 1500dc7e9ecdSChristian Riesch 1501dc7e9ecdSChristian Riesch *retlen = 0; 1502dc7e9ecdSChristian Riesch 1503dc7e9ecdSChristian Riesch for (chipnum = 0; chipnum < cfi->numchips; chipnum++) { 1504dc7e9ecdSChristian Riesch chip = &cfi->chips[chipnum]; 1505dc7e9ecdSChristian Riesch factory_size = 0; 1506dc7e9ecdSChristian Riesch user_size = 0; 1507dc7e9ecdSChristian Riesch 1508dc7e9ecdSChristian Riesch /* Micron M29EW family */ 1509dc7e9ecdSChristian Riesch if (is_m29ew(cfi)) { 1510dc7e9ecdSChristian Riesch base = chip->start; 1511dc7e9ecdSChristian Riesch 1512dc7e9ecdSChristian Riesch /* check whether secsi area is factory locked 1513dc7e9ecdSChristian Riesch or user lockable */ 1514dc7e9ecdSChristian Riesch mutex_lock(&chip->mutex); 1515dc7e9ecdSChristian Riesch ret = get_chip(map, chip, base, FL_CFI_QUERY); 1516dc7e9ecdSChristian Riesch if (ret) { 1517dc7e9ecdSChristian Riesch mutex_unlock(&chip->mutex); 1518dc7e9ecdSChristian Riesch return ret; 1519dc7e9ecdSChristian Riesch } 1520dc7e9ecdSChristian Riesch cfi_qry_mode_on(base, map, cfi); 1521dc7e9ecdSChristian Riesch otp = cfi_read_query(map, base + 0x3 * ofs_factor); 1522dc7e9ecdSChristian Riesch cfi_qry_mode_off(base, map, cfi); 1523dc7e9ecdSChristian Riesch put_chip(map, chip, base); 1524dc7e9ecdSChristian Riesch mutex_unlock(&chip->mutex); 1525dc7e9ecdSChristian Riesch 1526dc7e9ecdSChristian Riesch if (otp & 0x80) { 1527dc7e9ecdSChristian Riesch /* factory locked */ 1528dc7e9ecdSChristian Riesch factory_offset = 0; 1529dc7e9ecdSChristian Riesch factory_size = 0x100; 1530dc7e9ecdSChristian Riesch } else { 1531dc7e9ecdSChristian Riesch /* customer lockable */ 1532dc7e9ecdSChristian Riesch user_offset = 0; 1533dc7e9ecdSChristian Riesch user_size = 0x100; 1534dc7e9ecdSChristian Riesch 1535dc7e9ecdSChristian Riesch mutex_lock(&chip->mutex); 1536dc7e9ecdSChristian Riesch ret = get_chip(map, chip, base, FL_LOCKING); 15375d20bad1SBrian Norris if (ret) { 15385d20bad1SBrian Norris mutex_unlock(&chip->mutex); 15395d20bad1SBrian Norris return ret; 15405d20bad1SBrian Norris } 1541dc7e9ecdSChristian Riesch 1542dc7e9ecdSChristian Riesch /* Enter lock register command */ 1543dc7e9ecdSChristian Riesch cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, 1544dc7e9ecdSChristian Riesch chip->start, map, cfi, 1545dc7e9ecdSChristian Riesch cfi->device_type, NULL); 1546dc7e9ecdSChristian Riesch cfi_send_gen_cmd(0x55, cfi->addr_unlock2, 1547dc7e9ecdSChristian Riesch chip->start, map, cfi, 1548dc7e9ecdSChristian Riesch cfi->device_type, NULL); 1549dc7e9ecdSChristian Riesch cfi_send_gen_cmd(0x40, cfi->addr_unlock1, 1550dc7e9ecdSChristian Riesch chip->start, map, cfi, 1551dc7e9ecdSChristian Riesch cfi->device_type, NULL); 1552dc7e9ecdSChristian Riesch /* read lock register */ 1553dc7e9ecdSChristian Riesch lockreg = cfi_read_query(map, 0); 1554dc7e9ecdSChristian Riesch /* exit protection commands */ 1555dc7e9ecdSChristian Riesch map_write(map, CMD(0x90), chip->start); 1556dc7e9ecdSChristian Riesch map_write(map, CMD(0x00), chip->start); 1557dc7e9ecdSChristian Riesch put_chip(map, chip, chip->start); 1558dc7e9ecdSChristian Riesch mutex_unlock(&chip->mutex); 1559dc7e9ecdSChristian Riesch 1560dc7e9ecdSChristian Riesch user_locked = ((lockreg & 0x01) == 0x00); 1561dc7e9ecdSChristian Riesch } 1562dc7e9ecdSChristian Riesch } 1563dc7e9ecdSChristian Riesch 1564dc7e9ecdSChristian Riesch otpsize = user_regs ? user_size : factory_size; 1565dc7e9ecdSChristian Riesch if (!otpsize) 1566dc7e9ecdSChristian Riesch continue; 1567dc7e9ecdSChristian Riesch otpoffset = user_regs ? user_offset : factory_offset; 1568dc7e9ecdSChristian Riesch otplocked = user_regs ? user_locked : 1; 1569dc7e9ecdSChristian Riesch 1570dc7e9ecdSChristian Riesch if (!action) { 1571dc7e9ecdSChristian Riesch /* return otpinfo */ 1572dc7e9ecdSChristian Riesch struct otp_info *otpinfo; 1573dc7e9ecdSChristian Riesch len -= sizeof(*otpinfo); 1574dc7e9ecdSChristian Riesch if (len <= 0) 1575dc7e9ecdSChristian Riesch return -ENOSPC; 1576dc7e9ecdSChristian Riesch otpinfo = (struct otp_info *)buf; 1577dc7e9ecdSChristian Riesch otpinfo->start = from; 1578dc7e9ecdSChristian Riesch otpinfo->length = otpsize; 1579dc7e9ecdSChristian Riesch otpinfo->locked = otplocked; 1580dc7e9ecdSChristian Riesch buf += sizeof(*otpinfo); 1581dc7e9ecdSChristian Riesch *retlen += sizeof(*otpinfo); 1582dc7e9ecdSChristian Riesch from += otpsize; 1583dc7e9ecdSChristian Riesch } else if ((from < otpsize) && (len > 0)) { 1584dc7e9ecdSChristian Riesch size_t size; 1585dc7e9ecdSChristian Riesch size = (len < otpsize - from) ? len : otpsize - from; 15864f5cb243SChristian Riesch ret = action(map, chip, otpoffset + from, size, buf, 15874f5cb243SChristian Riesch otpsize); 1588dc7e9ecdSChristian Riesch if (ret < 0) 1589dc7e9ecdSChristian Riesch return ret; 1590dc7e9ecdSChristian Riesch 1591dc7e9ecdSChristian Riesch buf += size; 1592dc7e9ecdSChristian Riesch len -= size; 1593dc7e9ecdSChristian Riesch *retlen += size; 1594dc7e9ecdSChristian Riesch from = 0; 1595dc7e9ecdSChristian Riesch } else { 1596dc7e9ecdSChristian Riesch from -= otpsize; 1597dc7e9ecdSChristian Riesch } 1598dc7e9ecdSChristian Riesch } 1599dc7e9ecdSChristian Riesch return 0; 1600dc7e9ecdSChristian Riesch } 1601dc7e9ecdSChristian Riesch 1602dc7e9ecdSChristian Riesch static int cfi_amdstd_get_fact_prot_info(struct mtd_info *mtd, size_t len, 1603dc7e9ecdSChristian Riesch size_t *retlen, struct otp_info *buf) 1604dc7e9ecdSChristian Riesch { 1605dc7e9ecdSChristian Riesch return cfi_amdstd_otp_walk(mtd, 0, len, retlen, (u_char *)buf, 1606dc7e9ecdSChristian Riesch NULL, 0); 1607dc7e9ecdSChristian Riesch } 1608dc7e9ecdSChristian Riesch 1609dc7e9ecdSChristian Riesch static int cfi_amdstd_get_user_prot_info(struct mtd_info *mtd, size_t len, 1610dc7e9ecdSChristian Riesch size_t *retlen, struct otp_info *buf) 1611dc7e9ecdSChristian Riesch { 1612dc7e9ecdSChristian Riesch return cfi_amdstd_otp_walk(mtd, 0, len, retlen, (u_char *)buf, 1613dc7e9ecdSChristian Riesch NULL, 1); 1614dc7e9ecdSChristian Riesch } 1615dc7e9ecdSChristian Riesch 1616dc7e9ecdSChristian Riesch static int cfi_amdstd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, 1617dc7e9ecdSChristian Riesch size_t len, size_t *retlen, 1618dc7e9ecdSChristian Riesch u_char *buf) 1619dc7e9ecdSChristian Riesch { 1620dc7e9ecdSChristian Riesch return cfi_amdstd_otp_walk(mtd, from, len, retlen, 1621dc7e9ecdSChristian Riesch buf, do_read_secsi_onechip, 0); 1622dc7e9ecdSChristian Riesch } 1623dc7e9ecdSChristian Riesch 1624dc7e9ecdSChristian Riesch static int cfi_amdstd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, 1625dc7e9ecdSChristian Riesch size_t len, size_t *retlen, 1626dc7e9ecdSChristian Riesch u_char *buf) 1627dc7e9ecdSChristian Riesch { 1628dc7e9ecdSChristian Riesch return cfi_amdstd_otp_walk(mtd, from, len, retlen, 1629dc7e9ecdSChristian Riesch buf, do_read_secsi_onechip, 1); 1630dc7e9ecdSChristian Riesch } 16311da177e4SLinus Torvalds 1632af744750SChristian Riesch static int cfi_amdstd_write_user_prot_reg(struct mtd_info *mtd, loff_t from, 1633af744750SChristian Riesch size_t len, size_t *retlen, 1634af744750SChristian Riesch u_char *buf) 1635af744750SChristian Riesch { 1636af744750SChristian Riesch return cfi_amdstd_otp_walk(mtd, from, len, retlen, buf, 1637af744750SChristian Riesch do_otp_write, 1); 1638af744750SChristian Riesch } 1639af744750SChristian Riesch 16404f5cb243SChristian Riesch static int cfi_amdstd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, 16414f5cb243SChristian Riesch size_t len) 16424f5cb243SChristian Riesch { 16434f5cb243SChristian Riesch size_t retlen; 16444f5cb243SChristian Riesch return cfi_amdstd_otp_walk(mtd, from, len, &retlen, NULL, 16454f5cb243SChristian Riesch do_otp_lock, 1); 16464f5cb243SChristian Riesch } 16474f5cb243SChristian Riesch 1648a371ba57STokunori Ikegami static int __xipram do_write_oneword_once(struct map_info *map, 1649a371ba57STokunori Ikegami struct flchip *chip, 1650af744750SChristian Riesch unsigned long adr, map_word datum, 1651a371ba57STokunori Ikegami int mode, struct cfi_private *cfi) 16521da177e4SLinus Torvalds { 16531da177e4SLinus Torvalds unsigned long timeo = jiffies + HZ; 16541da177e4SLinus Torvalds /* 16551da177e4SLinus Torvalds * We use a 1ms + 1 jiffies generic timeout for writes (most devices 16561da177e4SLinus Torvalds * have a max write time of a few hundreds usec). However, we should 16571da177e4SLinus Torvalds * use the maximum timeout value given by the chip at probe time 16581da177e4SLinus Torvalds * instead. Unfortunately, struct flchip does have a field for 16591da177e4SLinus Torvalds * maximum timeout, only for typical which can be far too short 16601da177e4SLinus Torvalds * depending of the conditions. The ' + 1' is to avoid having a 16611da177e4SLinus Torvalds * timeout of 0 jiffies if HZ is smaller than 1000. 16621da177e4SLinus Torvalds */ 16631da177e4SLinus Torvalds unsigned long uWriteTimeout = (HZ / 1000) + 1; 16641da177e4SLinus Torvalds int ret = 0; 16651da177e4SLinus Torvalds 16661da177e4SLinus Torvalds cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); 16671da177e4SLinus Torvalds cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); 16681da177e4SLinus Torvalds cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); 16691da177e4SLinus Torvalds map_write(map, datum, adr); 1670af744750SChristian Riesch chip->state = mode; 16711da177e4SLinus Torvalds 167202b15e34STodd Poynor INVALIDATE_CACHE_UDELAY(map, chip, 167302b15e34STodd Poynor adr, map_bankwidth(map), 167402b15e34STodd Poynor chip->word_write_time); 16751da177e4SLinus Torvalds 16761da177e4SLinus Torvalds /* See comment above for timeout value. */ 16771da177e4SLinus Torvalds timeo = jiffies + uWriteTimeout; 16781da177e4SLinus Torvalds for (;;) { 1679af744750SChristian Riesch if (chip->state != mode) { 16801da177e4SLinus Torvalds /* Someone's suspended the write. Sleep */ 16811da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current); 16821da177e4SLinus Torvalds 16831da177e4SLinus Torvalds set_current_state(TASK_UNINTERRUPTIBLE); 16841da177e4SLinus Torvalds add_wait_queue(&chip->wq, &wait); 1685c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 16861da177e4SLinus Torvalds schedule(); 16871da177e4SLinus Torvalds remove_wait_queue(&chip->wq, &wait); 16881da177e4SLinus Torvalds timeo = jiffies + (HZ / 2); /* FIXME */ 1689c4e77376SStefani Seibold mutex_lock(&chip->mutex); 16901da177e4SLinus Torvalds continue; 16911da177e4SLinus Torvalds } 16921da177e4SLinus Torvalds 169337c673adSTokunori Ikegami /* 169437c673adSTokunori Ikegami * We check "time_after" and "!chip_good" before checking 169537c673adSTokunori Ikegami * "chip_good" to avoid the failure due to scheduling. 169637c673adSTokunori Ikegami */ 16974844ef80SVignesh Raghavendra if (time_after(jiffies, timeo) && 169837c673adSTokunori Ikegami !chip_good(map, chip, adr, datum)) { 169902b15e34STodd Poynor xip_enable(map, chip, adr); 1700fb4a90bfSEric W. Biedermann printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); 170102b15e34STodd Poynor xip_disable(map, chip, adr); 170237c673adSTokunori Ikegami ret = -EIO; 1703fb4a90bfSEric W. Biedermann break; 1704fb4a90bfSEric W. Biedermann } 1705fb4a90bfSEric W. Biedermann 1706c1599569SSergei Shtylyov if (chip_good(map, chip, adr, datum)) { 1707c1599569SSergei Shtylyov if (cfi_check_err_status(map, chip, adr)) 1708c1599569SSergei Shtylyov ret = -EIO; 1709b95f9609SKonstantin Baidarov break; 1710c1599569SSergei Shtylyov } 1711b95f9609SKonstantin Baidarov 17121da177e4SLinus Torvalds /* Latency issues. Drop the lock, wait a while and retry */ 171302b15e34STodd Poynor UDELAY(map, chip, adr, 1); 17141da177e4SLinus Torvalds } 171537c673adSTokunori Ikegami 1716a371ba57STokunori Ikegami return ret; 1717a371ba57STokunori Ikegami } 1718a371ba57STokunori Ikegami 1719228c05c2STokunori Ikegami static int __xipram do_write_oneword_start(struct map_info *map, 1720228c05c2STokunori Ikegami struct flchip *chip, 1721228c05c2STokunori Ikegami unsigned long adr, int mode) 1722228c05c2STokunori Ikegami { 1723ea4f5135SSergei Shtylyov int ret; 1724228c05c2STokunori Ikegami 1725228c05c2STokunori Ikegami mutex_lock(&chip->mutex); 1726228c05c2STokunori Ikegami 1727228c05c2STokunori Ikegami ret = get_chip(map, chip, adr, mode); 1728228c05c2STokunori Ikegami if (ret) { 1729228c05c2STokunori Ikegami mutex_unlock(&chip->mutex); 1730228c05c2STokunori Ikegami return ret; 1731228c05c2STokunori Ikegami } 1732228c05c2STokunori Ikegami 1733228c05c2STokunori Ikegami if (mode == FL_OTP_WRITE) 1734228c05c2STokunori Ikegami otp_enter(map, chip, adr, map_bankwidth(map)); 1735228c05c2STokunori Ikegami 1736228c05c2STokunori Ikegami return ret; 1737228c05c2STokunori Ikegami } 1738228c05c2STokunori Ikegami 1739228c05c2STokunori Ikegami static void __xipram do_write_oneword_done(struct map_info *map, 1740228c05c2STokunori Ikegami struct flchip *chip, 1741228c05c2STokunori Ikegami unsigned long adr, int mode) 1742228c05c2STokunori Ikegami { 1743228c05c2STokunori Ikegami if (mode == FL_OTP_WRITE) 1744228c05c2STokunori Ikegami otp_exit(map, chip, adr, map_bankwidth(map)); 1745228c05c2STokunori Ikegami 1746228c05c2STokunori Ikegami chip->state = FL_READY; 1747228c05c2STokunori Ikegami DISABLE_VPP(map); 1748228c05c2STokunori Ikegami put_chip(map, chip, adr); 1749228c05c2STokunori Ikegami 1750228c05c2STokunori Ikegami mutex_unlock(&chip->mutex); 1751228c05c2STokunori Ikegami } 1752228c05c2STokunori Ikegami 17530bcf880bSTokunori Ikegami static int __xipram do_write_oneword_retry(struct map_info *map, 17540bcf880bSTokunori Ikegami struct flchip *chip, 1755a371ba57STokunori Ikegami unsigned long adr, map_word datum, 1756a371ba57STokunori Ikegami int mode) 1757a371ba57STokunori Ikegami { 1758a371ba57STokunori Ikegami struct cfi_private *cfi = map->fldrv_priv; 1759a371ba57STokunori Ikegami int ret = 0; 1760a371ba57STokunori Ikegami map_word oldd; 1761a371ba57STokunori Ikegami int retry_cnt = 0; 1762a371ba57STokunori Ikegami 1763a371ba57STokunori Ikegami /* 1764a371ba57STokunori Ikegami * Check for a NOP for the case when the datum to write is already 1765a371ba57STokunori Ikegami * present - it saves time and works around buggy chips that corrupt 1766a371ba57STokunori Ikegami * data at other locations when 0xff is written to a location that 1767a371ba57STokunori Ikegami * already contains 0xff. 1768a371ba57STokunori Ikegami */ 1769a371ba57STokunori Ikegami oldd = map_read(map, adr); 1770a371ba57STokunori Ikegami if (map_word_equal(map, oldd, datum)) { 1771228c05c2STokunori Ikegami pr_debug("MTD %s(): NOP\n", __func__); 1772228c05c2STokunori Ikegami return ret; 1773a371ba57STokunori Ikegami } 1774a371ba57STokunori Ikegami 1775a371ba57STokunori Ikegami XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map)); 1776a371ba57STokunori Ikegami ENABLE_VPP(map); 1777a371ba57STokunori Ikegami xip_disable(map, chip, adr); 1778a371ba57STokunori Ikegami 1779a371ba57STokunori Ikegami retry: 1780a371ba57STokunori Ikegami ret = do_write_oneword_once(map, chip, adr, datum, mode, cfi); 178137c673adSTokunori Ikegami if (ret) { 17821da177e4SLinus Torvalds /* reset on all failures. */ 17831da177e4SLinus Torvalds map_write(map, CMD(0xF0), chip->start); 17841da177e4SLinus Torvalds /* FIXME - should have reset delay before continuing */ 1785fb4a90bfSEric W. Biedermann 178637c673adSTokunori Ikegami if (++retry_cnt <= MAX_RETRIES) { 178737c673adSTokunori Ikegami ret = 0; 17881da177e4SLinus Torvalds goto retry; 178937c673adSTokunori Ikegami } 1790fb4a90bfSEric W. Biedermann } 179102b15e34STodd Poynor xip_enable(map, chip, adr); 1792228c05c2STokunori Ikegami 17930bcf880bSTokunori Ikegami return ret; 17940bcf880bSTokunori Ikegami } 17950bcf880bSTokunori Ikegami 17960bcf880bSTokunori Ikegami static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, 17970bcf880bSTokunori Ikegami unsigned long adr, map_word datum, 17980bcf880bSTokunori Ikegami int mode) 17990bcf880bSTokunori Ikegami { 1800ea4f5135SSergei Shtylyov int ret; 18010bcf880bSTokunori Ikegami 18020bcf880bSTokunori Ikegami adr += chip->start; 18030bcf880bSTokunori Ikegami 18040bcf880bSTokunori Ikegami pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", __func__, adr, 18050bcf880bSTokunori Ikegami datum.x[0]); 18060bcf880bSTokunori Ikegami 18070bcf880bSTokunori Ikegami ret = do_write_oneword_start(map, chip, adr, mode); 18080bcf880bSTokunori Ikegami if (ret) 18090bcf880bSTokunori Ikegami return ret; 18100bcf880bSTokunori Ikegami 18110bcf880bSTokunori Ikegami ret = do_write_oneword_retry(map, chip, adr, datum, mode); 18120bcf880bSTokunori Ikegami 1813228c05c2STokunori Ikegami do_write_oneword_done(map, chip, adr, mode); 18141da177e4SLinus Torvalds 18151da177e4SLinus Torvalds return ret; 18161da177e4SLinus Torvalds } 18171da177e4SLinus Torvalds 18181da177e4SLinus Torvalds 18191da177e4SLinus Torvalds static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, 18201da177e4SLinus Torvalds size_t *retlen, const u_char *buf) 18211da177e4SLinus Torvalds { 18221da177e4SLinus Torvalds struct map_info *map = mtd->priv; 18231da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 1824ea4f5135SSergei Shtylyov int ret; 18251da177e4SLinus Torvalds int chipnum; 18261da177e4SLinus Torvalds unsigned long ofs, chipstart; 18271da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current); 18281da177e4SLinus Torvalds 18291da177e4SLinus Torvalds chipnum = to >> cfi->chipshift; 18301da177e4SLinus Torvalds ofs = to - (chipnum << cfi->chipshift); 18311da177e4SLinus Torvalds chipstart = cfi->chips[chipnum].start; 18321da177e4SLinus Torvalds 18331da177e4SLinus Torvalds /* If it's not bus-aligned, do the first byte write */ 18341da177e4SLinus Torvalds if (ofs & (map_bankwidth(map)-1)) { 18351da177e4SLinus Torvalds unsigned long bus_ofs = ofs & ~(map_bankwidth(map)-1); 18361da177e4SLinus Torvalds int i = ofs - bus_ofs; 18371da177e4SLinus Torvalds int n = 0; 18381da177e4SLinus Torvalds map_word tmp_buf; 18391da177e4SLinus Torvalds 18401da177e4SLinus Torvalds retry: 1841c4e77376SStefani Seibold mutex_lock(&cfi->chips[chipnum].mutex); 18421da177e4SLinus Torvalds 18431da177e4SLinus Torvalds if (cfi->chips[chipnum].state != FL_READY) { 18441da177e4SLinus Torvalds set_current_state(TASK_UNINTERRUPTIBLE); 18451da177e4SLinus Torvalds add_wait_queue(&cfi->chips[chipnum].wq, &wait); 18461da177e4SLinus Torvalds 1847c4e77376SStefani Seibold mutex_unlock(&cfi->chips[chipnum].mutex); 18481da177e4SLinus Torvalds 18491da177e4SLinus Torvalds schedule(); 18501da177e4SLinus Torvalds remove_wait_queue(&cfi->chips[chipnum].wq, &wait); 18511da177e4SLinus Torvalds goto retry; 18521da177e4SLinus Torvalds } 18531da177e4SLinus Torvalds 18541da177e4SLinus Torvalds /* Load 'tmp_buf' with old contents of flash */ 18551da177e4SLinus Torvalds tmp_buf = map_read(map, bus_ofs+chipstart); 18561da177e4SLinus Torvalds 1857c4e77376SStefani Seibold mutex_unlock(&cfi->chips[chipnum].mutex); 18581da177e4SLinus Torvalds 18591da177e4SLinus Torvalds /* Number of bytes to copy from buffer */ 18601da177e4SLinus Torvalds n = min_t(int, len, map_bankwidth(map)-i); 18611da177e4SLinus Torvalds 18621da177e4SLinus Torvalds tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n); 18631da177e4SLinus Torvalds 18641da177e4SLinus Torvalds ret = do_write_oneword(map, &cfi->chips[chipnum], 1865af744750SChristian Riesch bus_ofs, tmp_buf, FL_WRITING); 18661da177e4SLinus Torvalds if (ret) 18671da177e4SLinus Torvalds return ret; 18681da177e4SLinus Torvalds 18691da177e4SLinus Torvalds ofs += n; 18701da177e4SLinus Torvalds buf += n; 18711da177e4SLinus Torvalds (*retlen) += n; 18721da177e4SLinus Torvalds len -= n; 18731da177e4SLinus Torvalds 18741da177e4SLinus Torvalds if (ofs >> cfi->chipshift) { 18751da177e4SLinus Torvalds chipnum ++; 18761da177e4SLinus Torvalds ofs = 0; 18771da177e4SLinus Torvalds if (chipnum == cfi->numchips) 18781da177e4SLinus Torvalds return 0; 18791da177e4SLinus Torvalds } 18801da177e4SLinus Torvalds } 18811da177e4SLinus Torvalds 18821da177e4SLinus Torvalds /* We are now aligned, write as much as possible */ 18831da177e4SLinus Torvalds while(len >= map_bankwidth(map)) { 18841da177e4SLinus Torvalds map_word datum; 18851da177e4SLinus Torvalds 18861da177e4SLinus Torvalds datum = map_word_load(map, buf); 18871da177e4SLinus Torvalds 18881da177e4SLinus Torvalds ret = do_write_oneword(map, &cfi->chips[chipnum], 1889af744750SChristian Riesch ofs, datum, FL_WRITING); 18901da177e4SLinus Torvalds if (ret) 18911da177e4SLinus Torvalds return ret; 18921da177e4SLinus Torvalds 18931da177e4SLinus Torvalds ofs += map_bankwidth(map); 18941da177e4SLinus Torvalds buf += map_bankwidth(map); 18951da177e4SLinus Torvalds (*retlen) += map_bankwidth(map); 18961da177e4SLinus Torvalds len -= map_bankwidth(map); 18971da177e4SLinus Torvalds 18981da177e4SLinus Torvalds if (ofs >> cfi->chipshift) { 18991da177e4SLinus Torvalds chipnum ++; 19001da177e4SLinus Torvalds ofs = 0; 19011da177e4SLinus Torvalds if (chipnum == cfi->numchips) 19021da177e4SLinus Torvalds return 0; 19031da177e4SLinus Torvalds chipstart = cfi->chips[chipnum].start; 19041da177e4SLinus Torvalds } 19051da177e4SLinus Torvalds } 19061da177e4SLinus Torvalds 19071da177e4SLinus Torvalds /* Write the trailing bytes if any */ 19081da177e4SLinus Torvalds if (len & (map_bankwidth(map)-1)) { 19091da177e4SLinus Torvalds map_word tmp_buf; 19101da177e4SLinus Torvalds 19111da177e4SLinus Torvalds retry1: 1912c4e77376SStefani Seibold mutex_lock(&cfi->chips[chipnum].mutex); 19131da177e4SLinus Torvalds 19141da177e4SLinus Torvalds if (cfi->chips[chipnum].state != FL_READY) { 19151da177e4SLinus Torvalds set_current_state(TASK_UNINTERRUPTIBLE); 19161da177e4SLinus Torvalds add_wait_queue(&cfi->chips[chipnum].wq, &wait); 19171da177e4SLinus Torvalds 1918c4e77376SStefani Seibold mutex_unlock(&cfi->chips[chipnum].mutex); 19191da177e4SLinus Torvalds 19201da177e4SLinus Torvalds schedule(); 19211da177e4SLinus Torvalds remove_wait_queue(&cfi->chips[chipnum].wq, &wait); 19221da177e4SLinus Torvalds goto retry1; 19231da177e4SLinus Torvalds } 19241da177e4SLinus Torvalds 19251da177e4SLinus Torvalds tmp_buf = map_read(map, ofs + chipstart); 19261da177e4SLinus Torvalds 1927c4e77376SStefani Seibold mutex_unlock(&cfi->chips[chipnum].mutex); 19281da177e4SLinus Torvalds 19291da177e4SLinus Torvalds tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len); 19301da177e4SLinus Torvalds 19311da177e4SLinus Torvalds ret = do_write_oneword(map, &cfi->chips[chipnum], 1932af744750SChristian Riesch ofs, tmp_buf, FL_WRITING); 19331da177e4SLinus Torvalds if (ret) 19341da177e4SLinus Torvalds return ret; 19351da177e4SLinus Torvalds 19361da177e4SLinus Torvalds (*retlen) += len; 19371da177e4SLinus Torvalds } 19381da177e4SLinus Torvalds 19391da177e4SLinus Torvalds return 0; 19401da177e4SLinus Torvalds } 19411da177e4SLinus Torvalds 1942557c7590STokunori Ikegami #if !FORCE_WORD_WRITE 19436beb3ea7STokunori Ikegami static int __xipram do_write_buffer_wait(struct map_info *map, 19446beb3ea7STokunori Ikegami struct flchip *chip, unsigned long adr, 19456beb3ea7STokunori Ikegami map_word datum) 19466beb3ea7STokunori Ikegami { 19476beb3ea7STokunori Ikegami unsigned long timeo; 19486beb3ea7STokunori Ikegami unsigned long u_write_timeout; 19496beb3ea7STokunori Ikegami int ret = 0; 19506beb3ea7STokunori Ikegami 19516beb3ea7STokunori Ikegami /* 19526beb3ea7STokunori Ikegami * Timeout is calculated according to CFI data, if available. 19536beb3ea7STokunori Ikegami * See more comments in cfi_cmdset_0002(). 19546beb3ea7STokunori Ikegami */ 19556beb3ea7STokunori Ikegami u_write_timeout = usecs_to_jiffies(chip->buffer_write_time_max); 19566beb3ea7STokunori Ikegami timeo = jiffies + u_write_timeout; 19576beb3ea7STokunori Ikegami 19586beb3ea7STokunori Ikegami for (;;) { 19596beb3ea7STokunori Ikegami if (chip->state != FL_WRITING) { 19606beb3ea7STokunori Ikegami /* Someone's suspended the write. Sleep */ 19616beb3ea7STokunori Ikegami DECLARE_WAITQUEUE(wait, current); 19626beb3ea7STokunori Ikegami 19636beb3ea7STokunori Ikegami set_current_state(TASK_UNINTERRUPTIBLE); 19646beb3ea7STokunori Ikegami add_wait_queue(&chip->wq, &wait); 19656beb3ea7STokunori Ikegami mutex_unlock(&chip->mutex); 19666beb3ea7STokunori Ikegami schedule(); 19676beb3ea7STokunori Ikegami remove_wait_queue(&chip->wq, &wait); 19686beb3ea7STokunori Ikegami timeo = jiffies + (HZ / 2); /* FIXME */ 19696beb3ea7STokunori Ikegami mutex_lock(&chip->mutex); 19706beb3ea7STokunori Ikegami continue; 19716beb3ea7STokunori Ikegami } 19726beb3ea7STokunori Ikegami 19736beb3ea7STokunori Ikegami /* 19746beb3ea7STokunori Ikegami * We check "time_after" and "!chip_good" before checking 19756beb3ea7STokunori Ikegami * "chip_good" to avoid the failure due to scheduling. 19766beb3ea7STokunori Ikegami */ 19776beb3ea7STokunori Ikegami if (time_after(jiffies, timeo) && 19786beb3ea7STokunori Ikegami !chip_good(map, chip, adr, datum)) { 1979c1599569SSergei Shtylyov pr_err("MTD %s(): software timeout, address:0x%.8lx.\n", 1980c1599569SSergei Shtylyov __func__, adr); 19816beb3ea7STokunori Ikegami ret = -EIO; 19826beb3ea7STokunori Ikegami break; 19836beb3ea7STokunori Ikegami } 19846beb3ea7STokunori Ikegami 1985c1599569SSergei Shtylyov if (chip_good(map, chip, adr, datum)) { 1986c1599569SSergei Shtylyov if (cfi_check_err_status(map, chip, adr)) 1987c1599569SSergei Shtylyov ret = -EIO; 19886beb3ea7STokunori Ikegami break; 1989c1599569SSergei Shtylyov } 19906beb3ea7STokunori Ikegami 19916beb3ea7STokunori Ikegami /* Latency issues. Drop the lock, wait a while and retry */ 19926beb3ea7STokunori Ikegami UDELAY(map, chip, adr, 1); 19936beb3ea7STokunori Ikegami } 19946beb3ea7STokunori Ikegami 19956beb3ea7STokunori Ikegami return ret; 19966beb3ea7STokunori Ikegami } 19976beb3ea7STokunori Ikegami 1998816a6d14STokunori Ikegami static void __xipram do_write_buffer_reset(struct map_info *map, 1999816a6d14STokunori Ikegami struct flchip *chip, 2000816a6d14STokunori Ikegami struct cfi_private *cfi) 2001816a6d14STokunori Ikegami { 2002816a6d14STokunori Ikegami /* 2003816a6d14STokunori Ikegami * Recovery from write-buffer programming failures requires 2004816a6d14STokunori Ikegami * the write-to-buffer-reset sequence. Since the last part 2005816a6d14STokunori Ikegami * of the sequence also works as a normal reset, we can run 2006816a6d14STokunori Ikegami * the same commands regardless of why we are here. 2007816a6d14STokunori Ikegami * See e.g. 2008816a6d14STokunori Ikegami * http://www.spansion.com/Support/Application%20Notes/MirrorBit_Write_Buffer_Prog_Page_Buffer_Read_AN.pdf 2009816a6d14STokunori Ikegami */ 2010816a6d14STokunori Ikegami cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, 2011816a6d14STokunori Ikegami cfi->device_type, NULL); 2012816a6d14STokunori Ikegami cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, 2013816a6d14STokunori Ikegami cfi->device_type, NULL); 2014816a6d14STokunori Ikegami cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, chip->start, map, cfi, 2015816a6d14STokunori Ikegami cfi->device_type, NULL); 2016816a6d14STokunori Ikegami 2017816a6d14STokunori Ikegami /* FIXME - should have reset delay before continuing */ 2018816a6d14STokunori Ikegami } 20191da177e4SLinus Torvalds 20201da177e4SLinus Torvalds /* 20211da177e4SLinus Torvalds * FIXME: interleaved mode not tested, and probably not supported! 20221da177e4SLinus Torvalds */ 202302b15e34STodd Poynor static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, 202402b15e34STodd Poynor unsigned long adr, const u_char *buf, 202502b15e34STodd Poynor int len) 20261da177e4SLinus Torvalds { 20271da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 2028ea4f5135SSergei Shtylyov int ret; 20291da177e4SLinus Torvalds unsigned long cmd_adr; 20301da177e4SLinus Torvalds int z, words; 20311da177e4SLinus Torvalds map_word datum; 20321da177e4SLinus Torvalds 20331da177e4SLinus Torvalds adr += chip->start; 20341da177e4SLinus Torvalds cmd_adr = adr; 20351da177e4SLinus Torvalds 2036c4e77376SStefani Seibold mutex_lock(&chip->mutex); 20371da177e4SLinus Torvalds ret = get_chip(map, chip, adr, FL_WRITING); 20381da177e4SLinus Torvalds if (ret) { 2039c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 20401da177e4SLinus Torvalds return ret; 20411da177e4SLinus Torvalds } 20421da177e4SLinus Torvalds 20431da177e4SLinus Torvalds datum = map_word_load(map, buf); 20441da177e4SLinus Torvalds 2045289c0522SBrian Norris pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", 20461da177e4SLinus Torvalds __func__, adr, datum.x[0]); 20471da177e4SLinus Torvalds 204802b15e34STodd Poynor XIP_INVAL_CACHED_RANGE(map, adr, len); 20491da177e4SLinus Torvalds ENABLE_VPP(map); 205002b15e34STodd Poynor xip_disable(map, chip, cmd_adr); 205102b15e34STodd Poynor 20521da177e4SLinus Torvalds cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); 20531da177e4SLinus Torvalds cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); 20541da177e4SLinus Torvalds 20551da177e4SLinus Torvalds /* Write Buffer Load */ 20561da177e4SLinus Torvalds map_write(map, CMD(0x25), cmd_adr); 20571da177e4SLinus Torvalds 20581da177e4SLinus Torvalds chip->state = FL_WRITING_TO_BUFFER; 20591da177e4SLinus Torvalds 20601da177e4SLinus Torvalds /* Write length of data to come */ 20611da177e4SLinus Torvalds words = len / map_bankwidth(map); 20621da177e4SLinus Torvalds map_write(map, CMD(words - 1), cmd_adr); 20631da177e4SLinus Torvalds /* Write data */ 20641da177e4SLinus Torvalds z = 0; 20651da177e4SLinus Torvalds while(z < words * map_bankwidth(map)) { 20661da177e4SLinus Torvalds datum = map_word_load(map, buf); 20671da177e4SLinus Torvalds map_write(map, datum, adr + z); 20681da177e4SLinus Torvalds 20691da177e4SLinus Torvalds z += map_bankwidth(map); 20701da177e4SLinus Torvalds buf += map_bankwidth(map); 20711da177e4SLinus Torvalds } 20721da177e4SLinus Torvalds z -= map_bankwidth(map); 20731da177e4SLinus Torvalds 20741da177e4SLinus Torvalds adr += z; 20751da177e4SLinus Torvalds 20761da177e4SLinus Torvalds /* Write Buffer Program Confirm: GO GO GO */ 20771da177e4SLinus Torvalds map_write(map, CMD(0x29), cmd_adr); 20781da177e4SLinus Torvalds chip->state = FL_WRITING; 20791da177e4SLinus Torvalds 208002b15e34STodd Poynor INVALIDATE_CACHE_UDELAY(map, chip, 208102b15e34STodd Poynor adr, map_bankwidth(map), 208202b15e34STodd Poynor chip->word_write_time); 20831da177e4SLinus Torvalds 20846beb3ea7STokunori Ikegami ret = do_write_buffer_wait(map, chip, adr, datum); 2085c1599569SSergei Shtylyov if (ret) 2086816a6d14STokunori Ikegami do_write_buffer_reset(map, chip, cfi); 208702b15e34STodd Poynor 20885981dfceSTokunori Ikegami xip_enable(map, chip, adr); 20895981dfceSTokunori Ikegami 20901da177e4SLinus Torvalds chip->state = FL_READY; 2091e7d9377eSPaul Parsons DISABLE_VPP(map); 20921da177e4SLinus Torvalds put_chip(map, chip, adr); 2093c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 20941da177e4SLinus Torvalds 20951da177e4SLinus Torvalds return ret; 20961da177e4SLinus Torvalds } 20971da177e4SLinus Torvalds 20981da177e4SLinus Torvalds 20991da177e4SLinus Torvalds static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, 21001da177e4SLinus Torvalds size_t *retlen, const u_char *buf) 21011da177e4SLinus Torvalds { 21021da177e4SLinus Torvalds struct map_info *map = mtd->priv; 21031da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 21041da177e4SLinus Torvalds int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; 2105ea4f5135SSergei Shtylyov int ret; 21061da177e4SLinus Torvalds int chipnum; 21071da177e4SLinus Torvalds unsigned long ofs; 21081da177e4SLinus Torvalds 21091da177e4SLinus Torvalds chipnum = to >> cfi->chipshift; 21101da177e4SLinus Torvalds ofs = to - (chipnum << cfi->chipshift); 21111da177e4SLinus Torvalds 21121da177e4SLinus Torvalds /* If it's not bus-aligned, do the first word write */ 21131da177e4SLinus Torvalds if (ofs & (map_bankwidth(map)-1)) { 21141da177e4SLinus Torvalds size_t local_len = (-ofs)&(map_bankwidth(map)-1); 21151da177e4SLinus Torvalds if (local_len > len) 21161da177e4SLinus Torvalds local_len = len; 21171da177e4SLinus Torvalds ret = cfi_amdstd_write_words(mtd, ofs + (chipnum<<cfi->chipshift), 21181da177e4SLinus Torvalds local_len, retlen, buf); 21191da177e4SLinus Torvalds if (ret) 21201da177e4SLinus Torvalds return ret; 21211da177e4SLinus Torvalds ofs += local_len; 21221da177e4SLinus Torvalds buf += local_len; 21231da177e4SLinus Torvalds len -= local_len; 21241da177e4SLinus Torvalds 21251da177e4SLinus Torvalds if (ofs >> cfi->chipshift) { 21261da177e4SLinus Torvalds chipnum ++; 21271da177e4SLinus Torvalds ofs = 0; 21281da177e4SLinus Torvalds if (chipnum == cfi->numchips) 21291da177e4SLinus Torvalds return 0; 21301da177e4SLinus Torvalds } 21311da177e4SLinus Torvalds } 21321da177e4SLinus Torvalds 21331da177e4SLinus Torvalds /* Write buffer is worth it only if more than one word to write... */ 21341da177e4SLinus Torvalds while (len >= map_bankwidth(map) * 2) { 21351da177e4SLinus Torvalds /* We must not cross write block boundaries */ 21361da177e4SLinus Torvalds int size = wbufsize - (ofs & (wbufsize-1)); 21371da177e4SLinus Torvalds 21381da177e4SLinus Torvalds if (size > len) 21391da177e4SLinus Torvalds size = len; 21401da177e4SLinus Torvalds if (size % map_bankwidth(map)) 21411da177e4SLinus Torvalds size -= size % map_bankwidth(map); 21421da177e4SLinus Torvalds 21431da177e4SLinus Torvalds ret = do_write_buffer(map, &cfi->chips[chipnum], 21441da177e4SLinus Torvalds ofs, buf, size); 21451da177e4SLinus Torvalds if (ret) 21461da177e4SLinus Torvalds return ret; 21471da177e4SLinus Torvalds 21481da177e4SLinus Torvalds ofs += size; 21491da177e4SLinus Torvalds buf += size; 21501da177e4SLinus Torvalds (*retlen) += size; 21511da177e4SLinus Torvalds len -= size; 21521da177e4SLinus Torvalds 21531da177e4SLinus Torvalds if (ofs >> cfi->chipshift) { 21541da177e4SLinus Torvalds chipnum ++; 21551da177e4SLinus Torvalds ofs = 0; 21561da177e4SLinus Torvalds if (chipnum == cfi->numchips) 21571da177e4SLinus Torvalds return 0; 21581da177e4SLinus Torvalds } 21591da177e4SLinus Torvalds } 21601da177e4SLinus Torvalds 21611da177e4SLinus Torvalds if (len) { 21621da177e4SLinus Torvalds size_t retlen_dregs = 0; 21631da177e4SLinus Torvalds 21641da177e4SLinus Torvalds ret = cfi_amdstd_write_words(mtd, ofs + (chipnum<<cfi->chipshift), 21651da177e4SLinus Torvalds len, &retlen_dregs, buf); 21661da177e4SLinus Torvalds 21671da177e4SLinus Torvalds *retlen += retlen_dregs; 21681da177e4SLinus Torvalds return ret; 21691da177e4SLinus Torvalds } 21701da177e4SLinus Torvalds 21711da177e4SLinus Torvalds return 0; 21721da177e4SLinus Torvalds } 2173557c7590STokunori Ikegami #endif /* !FORCE_WORD_WRITE */ 21741da177e4SLinus Torvalds 217530ec5a2cSIra W. Snyder /* 217630ec5a2cSIra W. Snyder * Wait for the flash chip to become ready to write data 217730ec5a2cSIra W. Snyder * 217830ec5a2cSIra W. Snyder * This is only called during the panic_write() path. When panic_write() 217930ec5a2cSIra W. Snyder * is called, the kernel is in the process of a panic, and will soon be 218030ec5a2cSIra W. Snyder * dead. Therefore we don't take any locks, and attempt to get access 218130ec5a2cSIra W. Snyder * to the chip as soon as possible. 218230ec5a2cSIra W. Snyder */ 218330ec5a2cSIra W. Snyder static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip, 218430ec5a2cSIra W. Snyder unsigned long adr) 218530ec5a2cSIra W. Snyder { 218630ec5a2cSIra W. Snyder struct cfi_private *cfi = map->fldrv_priv; 218730ec5a2cSIra W. Snyder int retries = 10; 218830ec5a2cSIra W. Snyder int i; 218930ec5a2cSIra W. Snyder 219030ec5a2cSIra W. Snyder /* 219130ec5a2cSIra W. Snyder * If the driver thinks the chip is idle, and no toggle bits 219230ec5a2cSIra W. Snyder * are changing, then the chip is actually idle for sure. 219330ec5a2cSIra W. Snyder */ 21944844ef80SVignesh Raghavendra if (chip->state == FL_READY && chip_ready(map, chip, adr)) 219530ec5a2cSIra W. Snyder return 0; 219630ec5a2cSIra W. Snyder 219730ec5a2cSIra W. Snyder /* 219830ec5a2cSIra W. Snyder * Try several times to reset the chip and then wait for it 219930ec5a2cSIra W. Snyder * to become idle. The upper limit of a few milliseconds of 220030ec5a2cSIra W. Snyder * delay isn't a big problem: the kernel is dying anyway. It 220130ec5a2cSIra W. Snyder * is more important to save the messages. 220230ec5a2cSIra W. Snyder */ 220330ec5a2cSIra W. Snyder while (retries > 0) { 220430ec5a2cSIra W. Snyder const unsigned long timeo = (HZ / 1000) + 1; 220530ec5a2cSIra W. Snyder 220630ec5a2cSIra W. Snyder /* send the reset command */ 220730ec5a2cSIra W. Snyder map_write(map, CMD(0xF0), chip->start); 220830ec5a2cSIra W. Snyder 220930ec5a2cSIra W. Snyder /* wait for the chip to become ready */ 221030ec5a2cSIra W. Snyder for (i = 0; i < jiffies_to_usecs(timeo); i++) { 22114844ef80SVignesh Raghavendra if (chip_ready(map, chip, adr)) 221230ec5a2cSIra W. Snyder return 0; 221330ec5a2cSIra W. Snyder 221430ec5a2cSIra W. Snyder udelay(1); 221530ec5a2cSIra W. Snyder } 221636c6a7acSBrian Norris 221736c6a7acSBrian Norris retries--; 221830ec5a2cSIra W. Snyder } 221930ec5a2cSIra W. Snyder 222030ec5a2cSIra W. Snyder /* the chip never became ready */ 222130ec5a2cSIra W. Snyder return -EBUSY; 222230ec5a2cSIra W. Snyder } 222330ec5a2cSIra W. Snyder 222430ec5a2cSIra W. Snyder /* 222530ec5a2cSIra W. Snyder * Write out one word of data to a single flash chip during a kernel panic 222630ec5a2cSIra W. Snyder * 222730ec5a2cSIra W. Snyder * This is only called during the panic_write() path. When panic_write() 222830ec5a2cSIra W. Snyder * is called, the kernel is in the process of a panic, and will soon be 222930ec5a2cSIra W. Snyder * dead. Therefore we don't take any locks, and attempt to get access 223030ec5a2cSIra W. Snyder * to the chip as soon as possible. 223130ec5a2cSIra W. Snyder * 223230ec5a2cSIra W. Snyder * The implementation of this routine is intentionally similar to 223330ec5a2cSIra W. Snyder * do_write_oneword(), in order to ease code maintenance. 223430ec5a2cSIra W. Snyder */ 223530ec5a2cSIra W. Snyder static int do_panic_write_oneword(struct map_info *map, struct flchip *chip, 223630ec5a2cSIra W. Snyder unsigned long adr, map_word datum) 223730ec5a2cSIra W. Snyder { 223830ec5a2cSIra W. Snyder const unsigned long uWriteTimeout = (HZ / 1000) + 1; 223930ec5a2cSIra W. Snyder struct cfi_private *cfi = map->fldrv_priv; 224030ec5a2cSIra W. Snyder int retry_cnt = 0; 224130ec5a2cSIra W. Snyder map_word oldd; 2242ea4f5135SSergei Shtylyov int ret; 224330ec5a2cSIra W. Snyder int i; 224430ec5a2cSIra W. Snyder 224530ec5a2cSIra W. Snyder adr += chip->start; 224630ec5a2cSIra W. Snyder 224730ec5a2cSIra W. Snyder ret = cfi_amdstd_panic_wait(map, chip, adr); 224830ec5a2cSIra W. Snyder if (ret) 224930ec5a2cSIra W. Snyder return ret; 225030ec5a2cSIra W. Snyder 225130ec5a2cSIra W. Snyder pr_debug("MTD %s(): PANIC WRITE 0x%.8lx(0x%.8lx)\n", 225230ec5a2cSIra W. Snyder __func__, adr, datum.x[0]); 225330ec5a2cSIra W. Snyder 225430ec5a2cSIra W. Snyder /* 225530ec5a2cSIra W. Snyder * Check for a NOP for the case when the datum to write is already 225630ec5a2cSIra W. Snyder * present - it saves time and works around buggy chips that corrupt 225730ec5a2cSIra W. Snyder * data at other locations when 0xff is written to a location that 225830ec5a2cSIra W. Snyder * already contains 0xff. 225930ec5a2cSIra W. Snyder */ 226030ec5a2cSIra W. Snyder oldd = map_read(map, adr); 226130ec5a2cSIra W. Snyder if (map_word_equal(map, oldd, datum)) { 226230ec5a2cSIra W. Snyder pr_debug("MTD %s(): NOP\n", __func__); 226330ec5a2cSIra W. Snyder goto op_done; 226430ec5a2cSIra W. Snyder } 226530ec5a2cSIra W. Snyder 226630ec5a2cSIra W. Snyder ENABLE_VPP(map); 226730ec5a2cSIra W. Snyder 226830ec5a2cSIra W. Snyder retry: 226930ec5a2cSIra W. Snyder cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); 227030ec5a2cSIra W. Snyder cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); 227130ec5a2cSIra W. Snyder cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); 227230ec5a2cSIra W. Snyder map_write(map, datum, adr); 227330ec5a2cSIra W. Snyder 227430ec5a2cSIra W. Snyder for (i = 0; i < jiffies_to_usecs(uWriteTimeout); i++) { 22754844ef80SVignesh Raghavendra if (chip_ready(map, chip, adr)) 227630ec5a2cSIra W. Snyder break; 227730ec5a2cSIra W. Snyder 227830ec5a2cSIra W. Snyder udelay(1); 227930ec5a2cSIra W. Snyder } 228030ec5a2cSIra W. Snyder 2281c1599569SSergei Shtylyov if (!chip_good(map, chip, adr, datum) || 2282c1599569SSergei Shtylyov cfi_check_err_status(map, chip, adr)) { 228330ec5a2cSIra W. Snyder /* reset on all failures. */ 228430ec5a2cSIra W. Snyder map_write(map, CMD(0xF0), chip->start); 228530ec5a2cSIra W. Snyder /* FIXME - should have reset delay before continuing */ 228630ec5a2cSIra W. Snyder 228785a82e28STokunori Ikegami if (++retry_cnt <= MAX_RETRIES) 228830ec5a2cSIra W. Snyder goto retry; 228930ec5a2cSIra W. Snyder 229030ec5a2cSIra W. Snyder ret = -EIO; 229130ec5a2cSIra W. Snyder } 229230ec5a2cSIra W. Snyder 229330ec5a2cSIra W. Snyder op_done: 229430ec5a2cSIra W. Snyder DISABLE_VPP(map); 229530ec5a2cSIra W. Snyder return ret; 229630ec5a2cSIra W. Snyder } 229730ec5a2cSIra W. Snyder 229830ec5a2cSIra W. Snyder /* 229930ec5a2cSIra W. Snyder * Write out some data during a kernel panic 230030ec5a2cSIra W. Snyder * 230130ec5a2cSIra W. Snyder * This is used by the mtdoops driver to save the dying messages from a 230230ec5a2cSIra W. Snyder * kernel which has panic'd. 230330ec5a2cSIra W. Snyder * 230430ec5a2cSIra W. Snyder * This routine ignores all of the locking used throughout the rest of the 230530ec5a2cSIra W. Snyder * driver, in order to ensure that the data gets written out no matter what 230630ec5a2cSIra W. Snyder * state this driver (and the flash chip itself) was in when the kernel crashed. 230730ec5a2cSIra W. Snyder * 230830ec5a2cSIra W. Snyder * The implementation of this routine is intentionally similar to 230930ec5a2cSIra W. Snyder * cfi_amdstd_write_words(), in order to ease code maintenance. 231030ec5a2cSIra W. Snyder */ 231130ec5a2cSIra W. Snyder static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, 231230ec5a2cSIra W. Snyder size_t *retlen, const u_char *buf) 231330ec5a2cSIra W. Snyder { 231430ec5a2cSIra W. Snyder struct map_info *map = mtd->priv; 231530ec5a2cSIra W. Snyder struct cfi_private *cfi = map->fldrv_priv; 231630ec5a2cSIra W. Snyder unsigned long ofs, chipstart; 2317ea4f5135SSergei Shtylyov int ret; 231830ec5a2cSIra W. Snyder int chipnum; 231930ec5a2cSIra W. Snyder 232030ec5a2cSIra W. Snyder chipnum = to >> cfi->chipshift; 232130ec5a2cSIra W. Snyder ofs = to - (chipnum << cfi->chipshift); 232230ec5a2cSIra W. Snyder chipstart = cfi->chips[chipnum].start; 232330ec5a2cSIra W. Snyder 232430ec5a2cSIra W. Snyder /* If it's not bus aligned, do the first byte write */ 232530ec5a2cSIra W. Snyder if (ofs & (map_bankwidth(map) - 1)) { 232630ec5a2cSIra W. Snyder unsigned long bus_ofs = ofs & ~(map_bankwidth(map) - 1); 232730ec5a2cSIra W. Snyder int i = ofs - bus_ofs; 232830ec5a2cSIra W. Snyder int n = 0; 232930ec5a2cSIra W. Snyder map_word tmp_buf; 233030ec5a2cSIra W. Snyder 233130ec5a2cSIra W. Snyder ret = cfi_amdstd_panic_wait(map, &cfi->chips[chipnum], bus_ofs); 233230ec5a2cSIra W. Snyder if (ret) 233330ec5a2cSIra W. Snyder return ret; 233430ec5a2cSIra W. Snyder 233530ec5a2cSIra W. Snyder /* Load 'tmp_buf' with old contents of flash */ 233630ec5a2cSIra W. Snyder tmp_buf = map_read(map, bus_ofs + chipstart); 233730ec5a2cSIra W. Snyder 233830ec5a2cSIra W. Snyder /* Number of bytes to copy from buffer */ 233930ec5a2cSIra W. Snyder n = min_t(int, len, map_bankwidth(map) - i); 234030ec5a2cSIra W. Snyder 234130ec5a2cSIra W. Snyder tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n); 234230ec5a2cSIra W. Snyder 234330ec5a2cSIra W. Snyder ret = do_panic_write_oneword(map, &cfi->chips[chipnum], 234430ec5a2cSIra W. Snyder bus_ofs, tmp_buf); 234530ec5a2cSIra W. Snyder if (ret) 234630ec5a2cSIra W. Snyder return ret; 234730ec5a2cSIra W. Snyder 234830ec5a2cSIra W. Snyder ofs += n; 234930ec5a2cSIra W. Snyder buf += n; 235030ec5a2cSIra W. Snyder (*retlen) += n; 235130ec5a2cSIra W. Snyder len -= n; 235230ec5a2cSIra W. Snyder 235330ec5a2cSIra W. Snyder if (ofs >> cfi->chipshift) { 235430ec5a2cSIra W. Snyder chipnum++; 235530ec5a2cSIra W. Snyder ofs = 0; 235630ec5a2cSIra W. Snyder if (chipnum == cfi->numchips) 235730ec5a2cSIra W. Snyder return 0; 235830ec5a2cSIra W. Snyder } 235930ec5a2cSIra W. Snyder } 236030ec5a2cSIra W. Snyder 236130ec5a2cSIra W. Snyder /* We are now aligned, write as much as possible */ 236230ec5a2cSIra W. Snyder while (len >= map_bankwidth(map)) { 236330ec5a2cSIra W. Snyder map_word datum; 236430ec5a2cSIra W. Snyder 236530ec5a2cSIra W. Snyder datum = map_word_load(map, buf); 236630ec5a2cSIra W. Snyder 236730ec5a2cSIra W. Snyder ret = do_panic_write_oneword(map, &cfi->chips[chipnum], 236830ec5a2cSIra W. Snyder ofs, datum); 236930ec5a2cSIra W. Snyder if (ret) 237030ec5a2cSIra W. Snyder return ret; 237130ec5a2cSIra W. Snyder 237230ec5a2cSIra W. Snyder ofs += map_bankwidth(map); 237330ec5a2cSIra W. Snyder buf += map_bankwidth(map); 237430ec5a2cSIra W. Snyder (*retlen) += map_bankwidth(map); 237530ec5a2cSIra W. Snyder len -= map_bankwidth(map); 237630ec5a2cSIra W. Snyder 237730ec5a2cSIra W. Snyder if (ofs >> cfi->chipshift) { 237830ec5a2cSIra W. Snyder chipnum++; 237930ec5a2cSIra W. Snyder ofs = 0; 238030ec5a2cSIra W. Snyder if (chipnum == cfi->numchips) 238130ec5a2cSIra W. Snyder return 0; 238230ec5a2cSIra W. Snyder 238330ec5a2cSIra W. Snyder chipstart = cfi->chips[chipnum].start; 238430ec5a2cSIra W. Snyder } 238530ec5a2cSIra W. Snyder } 238630ec5a2cSIra W. Snyder 238730ec5a2cSIra W. Snyder /* Write the trailing bytes if any */ 238830ec5a2cSIra W. Snyder if (len & (map_bankwidth(map) - 1)) { 238930ec5a2cSIra W. Snyder map_word tmp_buf; 239030ec5a2cSIra W. Snyder 239130ec5a2cSIra W. Snyder ret = cfi_amdstd_panic_wait(map, &cfi->chips[chipnum], ofs); 239230ec5a2cSIra W. Snyder if (ret) 239330ec5a2cSIra W. Snyder return ret; 239430ec5a2cSIra W. Snyder 239530ec5a2cSIra W. Snyder tmp_buf = map_read(map, ofs + chipstart); 239630ec5a2cSIra W. Snyder 239730ec5a2cSIra W. Snyder tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len); 239830ec5a2cSIra W. Snyder 239930ec5a2cSIra W. Snyder ret = do_panic_write_oneword(map, &cfi->chips[chipnum], 240030ec5a2cSIra W. Snyder ofs, tmp_buf); 240130ec5a2cSIra W. Snyder if (ret) 240230ec5a2cSIra W. Snyder return ret; 240330ec5a2cSIra W. Snyder 240430ec5a2cSIra W. Snyder (*retlen) += len; 240530ec5a2cSIra W. Snyder } 240630ec5a2cSIra W. Snyder 240730ec5a2cSIra W. Snyder return 0; 240830ec5a2cSIra W. Snyder } 240930ec5a2cSIra W. Snyder 24101da177e4SLinus Torvalds 24111da177e4SLinus Torvalds /* 24121da177e4SLinus Torvalds * Handle devices with one erase region, that only implement 24131da177e4SLinus Torvalds * the chip erase command. 24141da177e4SLinus Torvalds */ 241502b15e34STodd Poynor static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) 24161da177e4SLinus Torvalds { 24171da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 24181da177e4SLinus Torvalds unsigned long timeo = jiffies + HZ; 24191da177e4SLinus Torvalds unsigned long int adr; 24201da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current); 2421ea4f5135SSergei Shtylyov int ret; 242245f75b8aSTokunori Ikegami int retry_cnt = 0; 24231da177e4SLinus Torvalds 24241da177e4SLinus Torvalds adr = cfi->addr_unlock1; 24251da177e4SLinus Torvalds 2426c4e77376SStefani Seibold mutex_lock(&chip->mutex); 24278a9485ffSTokunori Ikegami ret = get_chip(map, chip, adr, FL_ERASING); 24281da177e4SLinus Torvalds if (ret) { 2429c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 24301da177e4SLinus Torvalds return ret; 24311da177e4SLinus Torvalds } 24321da177e4SLinus Torvalds 2433289c0522SBrian Norris pr_debug("MTD %s(): ERASE 0x%.8lx\n", 24341da177e4SLinus Torvalds __func__, chip->start); 24351da177e4SLinus Torvalds 243602b15e34STodd Poynor XIP_INVAL_CACHED_RANGE(map, adr, map->size); 24371da177e4SLinus Torvalds ENABLE_VPP(map); 243802b15e34STodd Poynor xip_disable(map, chip, adr); 243902b15e34STodd Poynor 244045f75b8aSTokunori Ikegami retry: 24411da177e4SLinus Torvalds cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); 24421da177e4SLinus Torvalds cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); 24431da177e4SLinus Torvalds cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); 24441da177e4SLinus Torvalds cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); 24451da177e4SLinus Torvalds cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); 24461da177e4SLinus Torvalds cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); 24471da177e4SLinus Torvalds 24481da177e4SLinus Torvalds chip->state = FL_ERASING; 24491da177e4SLinus Torvalds chip->erase_suspended = 0; 24501da177e4SLinus Torvalds chip->in_progress_block_addr = adr; 24517b70eb14SJoakim Tjernlund chip->in_progress_block_mask = ~(map->size - 1); 24521da177e4SLinus Torvalds 245302b15e34STodd Poynor INVALIDATE_CACHE_UDELAY(map, chip, 245402b15e34STodd Poynor adr, map->size, 245502b15e34STodd Poynor chip->erase_time*500); 24561da177e4SLinus Torvalds 24571da177e4SLinus Torvalds timeo = jiffies + (HZ*20); 24581da177e4SLinus Torvalds 24591da177e4SLinus Torvalds for (;;) { 24601da177e4SLinus Torvalds if (chip->state != FL_ERASING) { 24611da177e4SLinus Torvalds /* Someone's suspended the erase. Sleep */ 24621da177e4SLinus Torvalds set_current_state(TASK_UNINTERRUPTIBLE); 24631da177e4SLinus Torvalds add_wait_queue(&chip->wq, &wait); 2464c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 24651da177e4SLinus Torvalds schedule(); 24661da177e4SLinus Torvalds remove_wait_queue(&chip->wq, &wait); 2467c4e77376SStefani Seibold mutex_lock(&chip->mutex); 24681da177e4SLinus Torvalds continue; 24691da177e4SLinus Torvalds } 24701da177e4SLinus Torvalds if (chip->erase_suspended) { 24711da177e4SLinus Torvalds /* This erase was suspended and resumed. 24721da177e4SLinus Torvalds Adjust the timeout */ 24731da177e4SLinus Torvalds timeo = jiffies + (HZ*20); /* FIXME */ 24741da177e4SLinus Torvalds chip->erase_suspended = 0; 24751da177e4SLinus Torvalds } 24761da177e4SLinus Torvalds 2477c1599569SSergei Shtylyov if (chip_good(map, chip, adr, map_word_ff(map))) { 2478c1599569SSergei Shtylyov if (cfi_check_err_status(map, chip, adr)) 2479c1599569SSergei Shtylyov ret = -EIO; 24801da177e4SLinus Torvalds break; 2481c1599569SSergei Shtylyov } 24821da177e4SLinus Torvalds 2483fb4a90bfSEric W. Biedermann if (time_after(jiffies, timeo)) { 2484fb4a90bfSEric W. Biedermann printk(KERN_WARNING "MTD %s(): software timeout\n", 2485fb4a90bfSEric W. Biedermann __func__); 248679ca484bSTokunori Ikegami ret = -EIO; 2487fb4a90bfSEric W. Biedermann break; 2488fb4a90bfSEric W. Biedermann } 2489fb4a90bfSEric W. Biedermann 24901da177e4SLinus Torvalds /* Latency issues. Drop the lock, wait a while and retry */ 249102b15e34STodd Poynor UDELAY(map, chip, adr, 1000000/HZ); 24921da177e4SLinus Torvalds } 2493fb4a90bfSEric W. Biedermann /* Did we succeed? */ 249479ca484bSTokunori Ikegami if (ret) { 24951da177e4SLinus Torvalds /* reset on all failures. */ 24961da177e4SLinus Torvalds map_write(map, CMD(0xF0), chip->start); 24971da177e4SLinus Torvalds /* FIXME - should have reset delay before continuing */ 24981da177e4SLinus Torvalds 249979ca484bSTokunori Ikegami if (++retry_cnt <= MAX_RETRIES) { 250079ca484bSTokunori Ikegami ret = 0; 250145f75b8aSTokunori Ikegami goto retry; 250279ca484bSTokunori Ikegami } 2503fb4a90bfSEric W. Biedermann } 2504fb4a90bfSEric W. Biedermann 25051da177e4SLinus Torvalds chip->state = FL_READY; 250602b15e34STodd Poynor xip_enable(map, chip, adr); 2507e7d9377eSPaul Parsons DISABLE_VPP(map); 25081da177e4SLinus Torvalds put_chip(map, chip, adr); 2509c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 25101da177e4SLinus Torvalds 25111da177e4SLinus Torvalds return ret; 25121da177e4SLinus Torvalds } 25131da177e4SLinus Torvalds 25141da177e4SLinus Torvalds 251502b15e34STodd Poynor static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk) 25161da177e4SLinus Torvalds { 25171da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 25181da177e4SLinus Torvalds unsigned long timeo = jiffies + HZ; 25191da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current); 2520ea4f5135SSergei Shtylyov int ret; 252145f75b8aSTokunori Ikegami int retry_cnt = 0; 25221da177e4SLinus Torvalds 25231da177e4SLinus Torvalds adr += chip->start; 25241da177e4SLinus Torvalds 2525c4e77376SStefani Seibold mutex_lock(&chip->mutex); 25261da177e4SLinus Torvalds ret = get_chip(map, chip, adr, FL_ERASING); 25271da177e4SLinus Torvalds if (ret) { 2528c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 25291da177e4SLinus Torvalds return ret; 25301da177e4SLinus Torvalds } 25311da177e4SLinus Torvalds 2532289c0522SBrian Norris pr_debug("MTD %s(): ERASE 0x%.8lx\n", 25331da177e4SLinus Torvalds __func__, adr); 25341da177e4SLinus Torvalds 253502b15e34STodd Poynor XIP_INVAL_CACHED_RANGE(map, adr, len); 25361da177e4SLinus Torvalds ENABLE_VPP(map); 253702b15e34STodd Poynor xip_disable(map, chip, adr); 253802b15e34STodd Poynor 253945f75b8aSTokunori Ikegami retry: 25401da177e4SLinus Torvalds cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); 25411da177e4SLinus Torvalds cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); 25421da177e4SLinus Torvalds cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); 25431da177e4SLinus Torvalds cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); 25441da177e4SLinus Torvalds cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); 254508968041SGuillaume LECERF map_write(map, cfi->sector_erase_cmd, adr); 25461da177e4SLinus Torvalds 25471da177e4SLinus Torvalds chip->state = FL_ERASING; 25481da177e4SLinus Torvalds chip->erase_suspended = 0; 25491da177e4SLinus Torvalds chip->in_progress_block_addr = adr; 25507b70eb14SJoakim Tjernlund chip->in_progress_block_mask = ~(len - 1); 25511da177e4SLinus Torvalds 255202b15e34STodd Poynor INVALIDATE_CACHE_UDELAY(map, chip, 255302b15e34STodd Poynor adr, len, 255402b15e34STodd Poynor chip->erase_time*500); 25551da177e4SLinus Torvalds 25561da177e4SLinus Torvalds timeo = jiffies + (HZ*20); 25571da177e4SLinus Torvalds 25581da177e4SLinus Torvalds for (;;) { 25591da177e4SLinus Torvalds if (chip->state != FL_ERASING) { 25601da177e4SLinus Torvalds /* Someone's suspended the erase. Sleep */ 25611da177e4SLinus Torvalds set_current_state(TASK_UNINTERRUPTIBLE); 25621da177e4SLinus Torvalds add_wait_queue(&chip->wq, &wait); 2563c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 25641da177e4SLinus Torvalds schedule(); 25651da177e4SLinus Torvalds remove_wait_queue(&chip->wq, &wait); 2566c4e77376SStefani Seibold mutex_lock(&chip->mutex); 25671da177e4SLinus Torvalds continue; 25681da177e4SLinus Torvalds } 25691da177e4SLinus Torvalds if (chip->erase_suspended) { 25701da177e4SLinus Torvalds /* This erase was suspended and resumed. 25711da177e4SLinus Torvalds Adjust the timeout */ 25721da177e4SLinus Torvalds timeo = jiffies + (HZ*20); /* FIXME */ 25731da177e4SLinus Torvalds chip->erase_suspended = 0; 25741da177e4SLinus Torvalds } 25751da177e4SLinus Torvalds 2576c1599569SSergei Shtylyov if (chip_good(map, chip, adr, map_word_ff(map))) { 2577c1599569SSergei Shtylyov if (cfi_check_err_status(map, chip, adr)) 2578c1599569SSergei Shtylyov ret = -EIO; 25791da177e4SLinus Torvalds break; 2580c1599569SSergei Shtylyov } 25811da177e4SLinus Torvalds 2582fb4a90bfSEric W. Biedermann if (time_after(jiffies, timeo)) { 2583fb4a90bfSEric W. Biedermann printk(KERN_WARNING "MTD %s(): software timeout\n", 2584fb4a90bfSEric W. Biedermann __func__); 258579ca484bSTokunori Ikegami ret = -EIO; 2586fb4a90bfSEric W. Biedermann break; 2587fb4a90bfSEric W. Biedermann } 2588fb4a90bfSEric W. Biedermann 25891da177e4SLinus Torvalds /* Latency issues. Drop the lock, wait a while and retry */ 259002b15e34STodd Poynor UDELAY(map, chip, adr, 1000000/HZ); 25911da177e4SLinus Torvalds } 2592fb4a90bfSEric W. Biedermann /* Did we succeed? */ 259379ca484bSTokunori Ikegami if (ret) { 25941da177e4SLinus Torvalds /* reset on all failures. */ 25951da177e4SLinus Torvalds map_write(map, CMD(0xF0), chip->start); 25961da177e4SLinus Torvalds /* FIXME - should have reset delay before continuing */ 25971da177e4SLinus Torvalds 259879ca484bSTokunori Ikegami if (++retry_cnt <= MAX_RETRIES) { 259979ca484bSTokunori Ikegami ret = 0; 260045f75b8aSTokunori Ikegami goto retry; 260179ca484bSTokunori Ikegami } 2602fb4a90bfSEric W. Biedermann } 2603fb4a90bfSEric W. Biedermann 26041da177e4SLinus Torvalds chip->state = FL_READY; 2605c64d4419STokunori Ikegami xip_enable(map, chip, adr); 2606e7d9377eSPaul Parsons DISABLE_VPP(map); 26071da177e4SLinus Torvalds put_chip(map, chip, adr); 2608c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 26091da177e4SLinus Torvalds return ret; 26101da177e4SLinus Torvalds } 26111da177e4SLinus Torvalds 26121da177e4SLinus Torvalds 2613ce0f33adSBen Dooks static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) 26141da177e4SLinus Torvalds { 2615e7bfb3fdSBoris Brezillon return cfi_varsize_frob(mtd, do_erase_oneblock, instr->addr, 2616e7bfb3fdSBoris Brezillon instr->len, NULL); 26171da177e4SLinus Torvalds } 26181da177e4SLinus Torvalds 26191da177e4SLinus Torvalds 26201da177e4SLinus Torvalds static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr) 26211da177e4SLinus Torvalds { 26221da177e4SLinus Torvalds struct map_info *map = mtd->priv; 26231da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 26241da177e4SLinus Torvalds 26251da177e4SLinus Torvalds if (instr->addr != 0) 26261da177e4SLinus Torvalds return -EINVAL; 26271da177e4SLinus Torvalds 26281da177e4SLinus Torvalds if (instr->len != mtd->size) 26291da177e4SLinus Torvalds return -EINVAL; 26301da177e4SLinus Torvalds 2631e7bfb3fdSBoris Brezillon return do_erase_chip(map, &cfi->chips[0]); 26321da177e4SLinus Torvalds } 26331da177e4SLinus Torvalds 26340165508cSHaavard Skinnemoen static int do_atmel_lock(struct map_info *map, struct flchip *chip, 26350165508cSHaavard Skinnemoen unsigned long adr, int len, void *thunk) 26360165508cSHaavard Skinnemoen { 26370165508cSHaavard Skinnemoen struct cfi_private *cfi = map->fldrv_priv; 26380165508cSHaavard Skinnemoen int ret; 26390165508cSHaavard Skinnemoen 2640c4e77376SStefani Seibold mutex_lock(&chip->mutex); 26410165508cSHaavard Skinnemoen ret = get_chip(map, chip, adr + chip->start, FL_LOCKING); 26420165508cSHaavard Skinnemoen if (ret) 26430165508cSHaavard Skinnemoen goto out_unlock; 26440165508cSHaavard Skinnemoen chip->state = FL_LOCKING; 26450165508cSHaavard Skinnemoen 26460a32a102SBrian Norris pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", __func__, adr, len); 26470165508cSHaavard Skinnemoen 26480165508cSHaavard Skinnemoen cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, 26490165508cSHaavard Skinnemoen cfi->device_type, NULL); 26500165508cSHaavard Skinnemoen cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, 26510165508cSHaavard Skinnemoen cfi->device_type, NULL); 26520165508cSHaavard Skinnemoen cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, 26530165508cSHaavard Skinnemoen cfi->device_type, NULL); 26540165508cSHaavard Skinnemoen cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, 26550165508cSHaavard Skinnemoen cfi->device_type, NULL); 26560165508cSHaavard Skinnemoen cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, 26570165508cSHaavard Skinnemoen cfi->device_type, NULL); 26580165508cSHaavard Skinnemoen map_write(map, CMD(0x40), chip->start + adr); 26590165508cSHaavard Skinnemoen 26600165508cSHaavard Skinnemoen chip->state = FL_READY; 26610165508cSHaavard Skinnemoen put_chip(map, chip, adr + chip->start); 26620165508cSHaavard Skinnemoen ret = 0; 26630165508cSHaavard Skinnemoen 26640165508cSHaavard Skinnemoen out_unlock: 2665c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 26660165508cSHaavard Skinnemoen return ret; 26670165508cSHaavard Skinnemoen } 26680165508cSHaavard Skinnemoen 26690165508cSHaavard Skinnemoen static int do_atmel_unlock(struct map_info *map, struct flchip *chip, 26700165508cSHaavard Skinnemoen unsigned long adr, int len, void *thunk) 26710165508cSHaavard Skinnemoen { 26720165508cSHaavard Skinnemoen struct cfi_private *cfi = map->fldrv_priv; 26730165508cSHaavard Skinnemoen int ret; 26740165508cSHaavard Skinnemoen 2675c4e77376SStefani Seibold mutex_lock(&chip->mutex); 26760165508cSHaavard Skinnemoen ret = get_chip(map, chip, adr + chip->start, FL_UNLOCKING); 26770165508cSHaavard Skinnemoen if (ret) 26780165508cSHaavard Skinnemoen goto out_unlock; 26790165508cSHaavard Skinnemoen chip->state = FL_UNLOCKING; 26800165508cSHaavard Skinnemoen 26810a32a102SBrian Norris pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", __func__, adr, len); 26820165508cSHaavard Skinnemoen 26830165508cSHaavard Skinnemoen cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, 26840165508cSHaavard Skinnemoen cfi->device_type, NULL); 26850165508cSHaavard Skinnemoen map_write(map, CMD(0x70), adr); 26860165508cSHaavard Skinnemoen 26870165508cSHaavard Skinnemoen chip->state = FL_READY; 26880165508cSHaavard Skinnemoen put_chip(map, chip, adr + chip->start); 26890165508cSHaavard Skinnemoen ret = 0; 26900165508cSHaavard Skinnemoen 26910165508cSHaavard Skinnemoen out_unlock: 2692c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 26930165508cSHaavard Skinnemoen return ret; 26940165508cSHaavard Skinnemoen } 26950165508cSHaavard Skinnemoen 269669423d99SAdrian Hunter static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) 26970165508cSHaavard Skinnemoen { 26980165508cSHaavard Skinnemoen return cfi_varsize_frob(mtd, do_atmel_lock, ofs, len, NULL); 26990165508cSHaavard Skinnemoen } 27000165508cSHaavard Skinnemoen 270169423d99SAdrian Hunter static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) 27020165508cSHaavard Skinnemoen { 27030165508cSHaavard Skinnemoen return cfi_varsize_frob(mtd, do_atmel_unlock, ofs, len, NULL); 27040165508cSHaavard Skinnemoen } 27050165508cSHaavard Skinnemoen 27061648eaaaSStefan Roese /* 27071648eaaaSStefan Roese * Advanced Sector Protection - PPB (Persistent Protection Bit) locking 27081648eaaaSStefan Roese */ 27091648eaaaSStefan Roese 27101648eaaaSStefan Roese struct ppb_lock { 27111648eaaaSStefan Roese struct flchip *chip; 27125fdfc3dbSJoakim Tjernlund unsigned long adr; 27131648eaaaSStefan Roese int locked; 27141648eaaaSStefan Roese }; 27151648eaaaSStefan Roese 27161648eaaaSStefan Roese #define DO_XXLOCK_ONEBLOCK_LOCK ((void *)1) 27171648eaaaSStefan Roese #define DO_XXLOCK_ONEBLOCK_UNLOCK ((void *)2) 27181648eaaaSStefan Roese #define DO_XXLOCK_ONEBLOCK_GETLOCK ((void *)3) 27191648eaaaSStefan Roese 27201648eaaaSStefan Roese static int __maybe_unused do_ppb_xxlock(struct map_info *map, 27211648eaaaSStefan Roese struct flchip *chip, 27221648eaaaSStefan Roese unsigned long adr, int len, void *thunk) 27231648eaaaSStefan Roese { 27241648eaaaSStefan Roese struct cfi_private *cfi = map->fldrv_priv; 27251648eaaaSStefan Roese unsigned long timeo; 27261648eaaaSStefan Roese int ret; 27271648eaaaSStefan Roese 2728f93aa8c4SJoakim Tjernlund adr += chip->start; 27291648eaaaSStefan Roese mutex_lock(&chip->mutex); 2730f93aa8c4SJoakim Tjernlund ret = get_chip(map, chip, adr, FL_LOCKING); 27311648eaaaSStefan Roese if (ret) { 27321648eaaaSStefan Roese mutex_unlock(&chip->mutex); 27331648eaaaSStefan Roese return ret; 27341648eaaaSStefan Roese } 27351648eaaaSStefan Roese 27361648eaaaSStefan Roese pr_debug("MTD %s(): XXLOCK 0x%08lx len %d\n", __func__, adr, len); 27371648eaaaSStefan Roese 27381648eaaaSStefan Roese cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, 27391648eaaaSStefan Roese cfi->device_type, NULL); 27401648eaaaSStefan Roese cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, 27411648eaaaSStefan Roese cfi->device_type, NULL); 27421648eaaaSStefan Roese /* PPB entry command */ 27431648eaaaSStefan Roese cfi_send_gen_cmd(0xC0, cfi->addr_unlock1, chip->start, map, cfi, 27441648eaaaSStefan Roese cfi->device_type, NULL); 27451648eaaaSStefan Roese 27461648eaaaSStefan Roese if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) { 27471648eaaaSStefan Roese chip->state = FL_LOCKING; 2748f93aa8c4SJoakim Tjernlund map_write(map, CMD(0xA0), adr); 2749f93aa8c4SJoakim Tjernlund map_write(map, CMD(0x00), adr); 27501648eaaaSStefan Roese } else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) { 27511648eaaaSStefan Roese /* 27521648eaaaSStefan Roese * Unlocking of one specific sector is not supported, so we 27531648eaaaSStefan Roese * have to unlock all sectors of this device instead 27541648eaaaSStefan Roese */ 27551648eaaaSStefan Roese chip->state = FL_UNLOCKING; 27561648eaaaSStefan Roese map_write(map, CMD(0x80), chip->start); 27571648eaaaSStefan Roese map_write(map, CMD(0x30), chip->start); 27581648eaaaSStefan Roese } else if (thunk == DO_XXLOCK_ONEBLOCK_GETLOCK) { 27591648eaaaSStefan Roese chip->state = FL_JEDEC_QUERY; 27601648eaaaSStefan Roese /* Return locked status: 0->locked, 1->unlocked */ 27611648eaaaSStefan Roese ret = !cfi_read_query(map, adr); 27621648eaaaSStefan Roese } else 27631648eaaaSStefan Roese BUG(); 27641648eaaaSStefan Roese 27651648eaaaSStefan Roese /* 27661648eaaaSStefan Roese * Wait for some time as unlocking of all sectors takes quite long 27671648eaaaSStefan Roese */ 27681648eaaaSStefan Roese timeo = jiffies + msecs_to_jiffies(2000); /* 2s max (un)locking */ 27691648eaaaSStefan Roese for (;;) { 27704844ef80SVignesh Raghavendra if (chip_ready(map, chip, adr)) 27711648eaaaSStefan Roese break; 27721648eaaaSStefan Roese 27731648eaaaSStefan Roese if (time_after(jiffies, timeo)) { 27741648eaaaSStefan Roese printk(KERN_ERR "Waiting for chip to be ready timed out.\n"); 27751648eaaaSStefan Roese ret = -EIO; 27761648eaaaSStefan Roese break; 27771648eaaaSStefan Roese } 27781648eaaaSStefan Roese 27791648eaaaSStefan Roese UDELAY(map, chip, adr, 1); 27801648eaaaSStefan Roese } 27811648eaaaSStefan Roese 27821648eaaaSStefan Roese /* Exit BC commands */ 27831648eaaaSStefan Roese map_write(map, CMD(0x90), chip->start); 27841648eaaaSStefan Roese map_write(map, CMD(0x00), chip->start); 27851648eaaaSStefan Roese 27861648eaaaSStefan Roese chip->state = FL_READY; 2787f93aa8c4SJoakim Tjernlund put_chip(map, chip, adr); 27881648eaaaSStefan Roese mutex_unlock(&chip->mutex); 27891648eaaaSStefan Roese 27901648eaaaSStefan Roese return ret; 27911648eaaaSStefan Roese } 27921648eaaaSStefan Roese 27931648eaaaSStefan Roese static int __maybe_unused cfi_ppb_lock(struct mtd_info *mtd, loff_t ofs, 27941648eaaaSStefan Roese uint64_t len) 27951648eaaaSStefan Roese { 27961648eaaaSStefan Roese return cfi_varsize_frob(mtd, do_ppb_xxlock, ofs, len, 27971648eaaaSStefan Roese DO_XXLOCK_ONEBLOCK_LOCK); 27981648eaaaSStefan Roese } 27991648eaaaSStefan Roese 28001648eaaaSStefan Roese static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, 28011648eaaaSStefan Roese uint64_t len) 28021648eaaaSStefan Roese { 28031648eaaaSStefan Roese struct mtd_erase_region_info *regions = mtd->eraseregions; 28041648eaaaSStefan Roese struct map_info *map = mtd->priv; 28051648eaaaSStefan Roese struct cfi_private *cfi = map->fldrv_priv; 28061648eaaaSStefan Roese struct ppb_lock *sect; 28071648eaaaSStefan Roese unsigned long adr; 28081648eaaaSStefan Roese loff_t offset; 28091648eaaaSStefan Roese uint64_t length; 28101648eaaaSStefan Roese int chipnum; 28111648eaaaSStefan Roese int i; 28121648eaaaSStefan Roese int sectors; 28131648eaaaSStefan Roese int ret; 281499a125f8SChris Packham int max_sectors; 28151648eaaaSStefan Roese 28161648eaaaSStefan Roese /* 28171648eaaaSStefan Roese * PPB unlocking always unlocks all sectors of the flash chip. 28181648eaaaSStefan Roese * We need to re-lock all previously locked sectors. So lets 28191648eaaaSStefan Roese * first check the locking status of all sectors and save 28201648eaaaSStefan Roese * it for future use. 28211648eaaaSStefan Roese */ 282299a125f8SChris Packham max_sectors = 0; 282399a125f8SChris Packham for (i = 0; i < mtd->numeraseregions; i++) 282499a125f8SChris Packham max_sectors += regions[i].numblocks; 282599a125f8SChris Packham 282699a125f8SChris Packham sect = kcalloc(max_sectors, sizeof(struct ppb_lock), GFP_KERNEL); 28271648eaaaSStefan Roese if (!sect) 28281648eaaaSStefan Roese return -ENOMEM; 28291648eaaaSStefan Roese 28301648eaaaSStefan Roese /* 28311648eaaaSStefan Roese * This code to walk all sectors is a slightly modified version 28321648eaaaSStefan Roese * of the cfi_varsize_frob() code. 28331648eaaaSStefan Roese */ 28341648eaaaSStefan Roese i = 0; 28351648eaaaSStefan Roese chipnum = 0; 28361648eaaaSStefan Roese adr = 0; 28371648eaaaSStefan Roese sectors = 0; 28381648eaaaSStefan Roese offset = 0; 28391648eaaaSStefan Roese length = mtd->size; 28401648eaaaSStefan Roese 28411648eaaaSStefan Roese while (length) { 28421648eaaaSStefan Roese int size = regions[i].erasesize; 28431648eaaaSStefan Roese 28441648eaaaSStefan Roese /* 28451648eaaaSStefan Roese * Only test sectors that shall not be unlocked. The other 28461648eaaaSStefan Roese * sectors shall be unlocked, so lets keep their locking 28471648eaaaSStefan Roese * status at "unlocked" (locked=0) for the final re-locking. 28481648eaaaSStefan Roese */ 28490cd8116fSJoakim Tjernlund if ((offset < ofs) || (offset >= (ofs + len))) { 28501648eaaaSStefan Roese sect[sectors].chip = &cfi->chips[chipnum]; 28515fdfc3dbSJoakim Tjernlund sect[sectors].adr = adr; 28521648eaaaSStefan Roese sect[sectors].locked = do_ppb_xxlock( 28531648eaaaSStefan Roese map, &cfi->chips[chipnum], adr, 0, 28541648eaaaSStefan Roese DO_XXLOCK_ONEBLOCK_GETLOCK); 28551648eaaaSStefan Roese } 28561648eaaaSStefan Roese 28571648eaaaSStefan Roese adr += size; 28581648eaaaSStefan Roese offset += size; 28591648eaaaSStefan Roese length -= size; 28601648eaaaSStefan Roese 28611648eaaaSStefan Roese if (offset == regions[i].offset + size * regions[i].numblocks) 28621648eaaaSStefan Roese i++; 28631648eaaaSStefan Roese 28641648eaaaSStefan Roese if (adr >> cfi->chipshift) { 2865f1ce87f6SJoakim Tjernlund if (offset >= (ofs + len)) 2866f1ce87f6SJoakim Tjernlund break; 28671648eaaaSStefan Roese adr = 0; 28681648eaaaSStefan Roese chipnum++; 28691648eaaaSStefan Roese 28701648eaaaSStefan Roese if (chipnum >= cfi->numchips) 28711648eaaaSStefan Roese break; 28721648eaaaSStefan Roese } 28731648eaaaSStefan Roese 28741648eaaaSStefan Roese sectors++; 287599a125f8SChris Packham if (sectors >= max_sectors) { 28761648eaaaSStefan Roese printk(KERN_ERR "Only %d sectors for PPB locking supported!\n", 287799a125f8SChris Packham max_sectors); 28781648eaaaSStefan Roese kfree(sect); 28791648eaaaSStefan Roese return -EINVAL; 28801648eaaaSStefan Roese } 28811648eaaaSStefan Roese } 28821648eaaaSStefan Roese 28831648eaaaSStefan Roese /* Now unlock the whole chip */ 28841648eaaaSStefan Roese ret = cfi_varsize_frob(mtd, do_ppb_xxlock, ofs, len, 28851648eaaaSStefan Roese DO_XXLOCK_ONEBLOCK_UNLOCK); 28861648eaaaSStefan Roese if (ret) { 28871648eaaaSStefan Roese kfree(sect); 28881648eaaaSStefan Roese return ret; 28891648eaaaSStefan Roese } 28901648eaaaSStefan Roese 28911648eaaaSStefan Roese /* 28921648eaaaSStefan Roese * PPB unlocking always unlocks all sectors of the flash chip. 28931648eaaaSStefan Roese * We need to re-lock all previously locked sectors. 28941648eaaaSStefan Roese */ 28951648eaaaSStefan Roese for (i = 0; i < sectors; i++) { 28961648eaaaSStefan Roese if (sect[i].locked) 28975fdfc3dbSJoakim Tjernlund do_ppb_xxlock(map, sect[i].chip, sect[i].adr, 0, 28981648eaaaSStefan Roese DO_XXLOCK_ONEBLOCK_LOCK); 28991648eaaaSStefan Roese } 29001648eaaaSStefan Roese 29011648eaaaSStefan Roese kfree(sect); 29021648eaaaSStefan Roese return ret; 29031648eaaaSStefan Roese } 29041648eaaaSStefan Roese 29051648eaaaSStefan Roese static int __maybe_unused cfi_ppb_is_locked(struct mtd_info *mtd, loff_t ofs, 29061648eaaaSStefan Roese uint64_t len) 29071648eaaaSStefan Roese { 29081648eaaaSStefan Roese return cfi_varsize_frob(mtd, do_ppb_xxlock, ofs, len, 29091648eaaaSStefan Roese DO_XXLOCK_ONEBLOCK_GETLOCK) ? 1 : 0; 29101648eaaaSStefan Roese } 29111da177e4SLinus Torvalds 29121da177e4SLinus Torvalds static void cfi_amdstd_sync (struct mtd_info *mtd) 29131da177e4SLinus Torvalds { 29141da177e4SLinus Torvalds struct map_info *map = mtd->priv; 29151da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 29161da177e4SLinus Torvalds int i; 29171da177e4SLinus Torvalds struct flchip *chip; 29181da177e4SLinus Torvalds int ret = 0; 29191da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current); 29201da177e4SLinus Torvalds 29211da177e4SLinus Torvalds for (i=0; !ret && i<cfi->numchips; i++) { 29221da177e4SLinus Torvalds chip = &cfi->chips[i]; 29231da177e4SLinus Torvalds 29241da177e4SLinus Torvalds retry: 2925c4e77376SStefani Seibold mutex_lock(&chip->mutex); 29261da177e4SLinus Torvalds 29271da177e4SLinus Torvalds switch(chip->state) { 29281da177e4SLinus Torvalds case FL_READY: 29291da177e4SLinus Torvalds case FL_STATUS: 29301da177e4SLinus Torvalds case FL_CFI_QUERY: 29311da177e4SLinus Torvalds case FL_JEDEC_QUERY: 29321da177e4SLinus Torvalds chip->oldstate = chip->state; 29331da177e4SLinus Torvalds chip->state = FL_SYNCING; 29341da177e4SLinus Torvalds /* No need to wake_up() on this state change - 29351da177e4SLinus Torvalds * as the whole point is that nobody can do anything 29361da177e4SLinus Torvalds * with the chip now anyway. 29371da177e4SLinus Torvalds */ 2938025a06c1SMiquel Raynal fallthrough; 29391da177e4SLinus Torvalds case FL_SYNCING: 2940c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 29411da177e4SLinus Torvalds break; 29421da177e4SLinus Torvalds 29431da177e4SLinus Torvalds default: 29441da177e4SLinus Torvalds /* Not an idle state */ 2945f8e30e44SDmitry Adamushko set_current_state(TASK_UNINTERRUPTIBLE); 29461da177e4SLinus Torvalds add_wait_queue(&chip->wq, &wait); 29471da177e4SLinus Torvalds 2948c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 29491da177e4SLinus Torvalds 29501da177e4SLinus Torvalds schedule(); 29511da177e4SLinus Torvalds 29521da177e4SLinus Torvalds remove_wait_queue(&chip->wq, &wait); 29531da177e4SLinus Torvalds 29541da177e4SLinus Torvalds goto retry; 29551da177e4SLinus Torvalds } 29561da177e4SLinus Torvalds } 29571da177e4SLinus Torvalds 29581da177e4SLinus Torvalds /* Unlock the chips again */ 29591da177e4SLinus Torvalds 29601da177e4SLinus Torvalds for (i--; i >=0; i--) { 29611da177e4SLinus Torvalds chip = &cfi->chips[i]; 29621da177e4SLinus Torvalds 2963c4e77376SStefani Seibold mutex_lock(&chip->mutex); 29641da177e4SLinus Torvalds 29651da177e4SLinus Torvalds if (chip->state == FL_SYNCING) { 29661da177e4SLinus Torvalds chip->state = chip->oldstate; 29671da177e4SLinus Torvalds wake_up(&chip->wq); 29681da177e4SLinus Torvalds } 2969c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 29701da177e4SLinus Torvalds } 29711da177e4SLinus Torvalds } 29721da177e4SLinus Torvalds 29731da177e4SLinus Torvalds 29741da177e4SLinus Torvalds static int cfi_amdstd_suspend(struct mtd_info *mtd) 29751da177e4SLinus Torvalds { 29761da177e4SLinus Torvalds struct map_info *map = mtd->priv; 29771da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 29781da177e4SLinus Torvalds int i; 29791da177e4SLinus Torvalds struct flchip *chip; 29801da177e4SLinus Torvalds int ret = 0; 29811da177e4SLinus Torvalds 29821da177e4SLinus Torvalds for (i=0; !ret && i<cfi->numchips; i++) { 29831da177e4SLinus Torvalds chip = &cfi->chips[i]; 29841da177e4SLinus Torvalds 2985c4e77376SStefani Seibold mutex_lock(&chip->mutex); 29861da177e4SLinus Torvalds 29871da177e4SLinus Torvalds switch(chip->state) { 29881da177e4SLinus Torvalds case FL_READY: 29891da177e4SLinus Torvalds case FL_STATUS: 29901da177e4SLinus Torvalds case FL_CFI_QUERY: 29911da177e4SLinus Torvalds case FL_JEDEC_QUERY: 29921da177e4SLinus Torvalds chip->oldstate = chip->state; 29931da177e4SLinus Torvalds chip->state = FL_PM_SUSPENDED; 29941da177e4SLinus Torvalds /* No need to wake_up() on this state change - 29951da177e4SLinus Torvalds * as the whole point is that nobody can do anything 29961da177e4SLinus Torvalds * with the chip now anyway. 29971da177e4SLinus Torvalds */ 2998*c6f51f1fSGustavo A. R. Silva break; 29991da177e4SLinus Torvalds case FL_PM_SUSPENDED: 30001da177e4SLinus Torvalds break; 30011da177e4SLinus Torvalds 30021da177e4SLinus Torvalds default: 30031da177e4SLinus Torvalds ret = -EAGAIN; 30041da177e4SLinus Torvalds break; 30051da177e4SLinus Torvalds } 3006c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 30071da177e4SLinus Torvalds } 30081da177e4SLinus Torvalds 30091da177e4SLinus Torvalds /* Unlock the chips again */ 30101da177e4SLinus Torvalds 30111da177e4SLinus Torvalds if (ret) { 30121da177e4SLinus Torvalds for (i--; i >=0; i--) { 30131da177e4SLinus Torvalds chip = &cfi->chips[i]; 30141da177e4SLinus Torvalds 3015c4e77376SStefani Seibold mutex_lock(&chip->mutex); 30161da177e4SLinus Torvalds 30171da177e4SLinus Torvalds if (chip->state == FL_PM_SUSPENDED) { 30181da177e4SLinus Torvalds chip->state = chip->oldstate; 30191da177e4SLinus Torvalds wake_up(&chip->wq); 30201da177e4SLinus Torvalds } 3021c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 30221da177e4SLinus Torvalds } 30231da177e4SLinus Torvalds } 30241da177e4SLinus Torvalds 30251da177e4SLinus Torvalds return ret; 30261da177e4SLinus Torvalds } 30271da177e4SLinus Torvalds 30281da177e4SLinus Torvalds 30291da177e4SLinus Torvalds static void cfi_amdstd_resume(struct mtd_info *mtd) 30301da177e4SLinus Torvalds { 30311da177e4SLinus Torvalds struct map_info *map = mtd->priv; 30321da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 30331da177e4SLinus Torvalds int i; 30341da177e4SLinus Torvalds struct flchip *chip; 30351da177e4SLinus Torvalds 30361da177e4SLinus Torvalds for (i=0; i<cfi->numchips; i++) { 30371da177e4SLinus Torvalds 30381da177e4SLinus Torvalds chip = &cfi->chips[i]; 30391da177e4SLinus Torvalds 3040c4e77376SStefani Seibold mutex_lock(&chip->mutex); 30411da177e4SLinus Torvalds 30421da177e4SLinus Torvalds if (chip->state == FL_PM_SUSPENDED) { 30431da177e4SLinus Torvalds chip->state = FL_READY; 30441da177e4SLinus Torvalds map_write(map, CMD(0xF0), chip->start); 30451da177e4SLinus Torvalds wake_up(&chip->wq); 30461da177e4SLinus Torvalds } 30471da177e4SLinus Torvalds else 30481da177e4SLinus Torvalds printk(KERN_ERR "Argh. Chip not in PM_SUSPENDED state upon resume()\n"); 30491da177e4SLinus Torvalds 3050c4e77376SStefani Seibold mutex_unlock(&chip->mutex); 30511da177e4SLinus Torvalds } 30521da177e4SLinus Torvalds } 30531da177e4SLinus Torvalds 3054eafe1311SKevin Cernekee 3055eafe1311SKevin Cernekee /* 3056eafe1311SKevin Cernekee * Ensure that the flash device is put back into read array mode before 3057eafe1311SKevin Cernekee * unloading the driver or rebooting. On some systems, rebooting while 3058eafe1311SKevin Cernekee * the flash is in query/program/erase mode will prevent the CPU from 3059eafe1311SKevin Cernekee * fetching the bootloader code, requiring a hard reset or power cycle. 3060eafe1311SKevin Cernekee */ 3061eafe1311SKevin Cernekee static int cfi_amdstd_reset(struct mtd_info *mtd) 3062eafe1311SKevin Cernekee { 3063eafe1311SKevin Cernekee struct map_info *map = mtd->priv; 3064eafe1311SKevin Cernekee struct cfi_private *cfi = map->fldrv_priv; 3065eafe1311SKevin Cernekee int i, ret; 3066eafe1311SKevin Cernekee struct flchip *chip; 3067eafe1311SKevin Cernekee 3068eafe1311SKevin Cernekee for (i = 0; i < cfi->numchips; i++) { 3069eafe1311SKevin Cernekee 3070eafe1311SKevin Cernekee chip = &cfi->chips[i]; 3071eafe1311SKevin Cernekee 3072eafe1311SKevin Cernekee mutex_lock(&chip->mutex); 3073eafe1311SKevin Cernekee 3074eafe1311SKevin Cernekee ret = get_chip(map, chip, chip->start, FL_SHUTDOWN); 3075eafe1311SKevin Cernekee if (!ret) { 3076eafe1311SKevin Cernekee map_write(map, CMD(0xF0), chip->start); 3077eafe1311SKevin Cernekee chip->state = FL_SHUTDOWN; 3078eafe1311SKevin Cernekee put_chip(map, chip, chip->start); 3079eafe1311SKevin Cernekee } 3080eafe1311SKevin Cernekee 3081eafe1311SKevin Cernekee mutex_unlock(&chip->mutex); 3082eafe1311SKevin Cernekee } 3083eafe1311SKevin Cernekee 3084eafe1311SKevin Cernekee return 0; 3085eafe1311SKevin Cernekee } 3086eafe1311SKevin Cernekee 3087eafe1311SKevin Cernekee 3088eafe1311SKevin Cernekee static int cfi_amdstd_reboot(struct notifier_block *nb, unsigned long val, 3089eafe1311SKevin Cernekee void *v) 3090eafe1311SKevin Cernekee { 3091eafe1311SKevin Cernekee struct mtd_info *mtd; 3092eafe1311SKevin Cernekee 3093eafe1311SKevin Cernekee mtd = container_of(nb, struct mtd_info, reboot_notifier); 3094eafe1311SKevin Cernekee cfi_amdstd_reset(mtd); 3095eafe1311SKevin Cernekee return NOTIFY_DONE; 3096eafe1311SKevin Cernekee } 3097eafe1311SKevin Cernekee 3098eafe1311SKevin Cernekee 30991da177e4SLinus Torvalds static void cfi_amdstd_destroy(struct mtd_info *mtd) 31001da177e4SLinus Torvalds { 31011da177e4SLinus Torvalds struct map_info *map = mtd->priv; 31021da177e4SLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 3103fa671646SJesper Juhl 3104eafe1311SKevin Cernekee cfi_amdstd_reset(mtd); 3105eafe1311SKevin Cernekee unregister_reboot_notifier(&mtd->reboot_notifier); 31061da177e4SLinus Torvalds kfree(cfi->cmdset_priv); 31071da177e4SLinus Torvalds kfree(cfi->cfiq); 31081da177e4SLinus Torvalds kfree(cfi); 31091da177e4SLinus Torvalds kfree(mtd->eraseregions); 31101da177e4SLinus Torvalds } 31111da177e4SLinus Torvalds 31121da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 31131da177e4SLinus Torvalds MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al."); 31141da177e4SLinus Torvalds MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips"); 311580461128SGuillaume LECERF MODULE_ALIAS("cfi_cmdset_0006"); 31161e804cecSDavid Woodhouse MODULE_ALIAS("cfi_cmdset_0701"); 3117