11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Common Flash Interface support: 325985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Generic utility functions not dependent on command set 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2002 Red Hat 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 STMicroelectronics Limited 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This code is covered by the GPL. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/xip.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/mtd.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/map.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/cfi.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26c314dfdc358847eef0fc07ec8682e1acc8cadd00David Woodhouseint __xipram cfi_qry_present(struct map_info *map, __u32 base, 27c314dfdc358847eef0fc07ec8682e1acc8cadd00David Woodhouse struct cfi_private *cfi) 282e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev{ 292e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev int osf = cfi->interleave * cfi->device_type; /* scale factor */ 302e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev map_word val[3]; 312e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev map_word qry[3]; 322e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev 332e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev qry[0] = cfi_build_cmd('Q', map, cfi); 342e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev qry[1] = cfi_build_cmd('R', map, cfi); 352e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev qry[2] = cfi_build_cmd('Y', map, cfi); 362e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev 372e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev val[0] = map_read(map, base + osf*0x10); 382e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev val[1] = map_read(map, base + osf*0x11); 392e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev val[2] = map_read(map, base + osf*0x12); 402e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev 412e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev if (!map_word_equal(map, qry[0], val[0])) 422e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev return 0; 432e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev 442e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev if (!map_word_equal(map, qry[1], val[1])) 452e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev return 0; 462e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev 472e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev if (!map_word_equal(map, qry[2], val[2])) 482e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev return 0; 492e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev 502e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev return 1; /* "QRY" found */ 512e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev} 52c314dfdc358847eef0fc07ec8682e1acc8cadd00David WoodhouseEXPORT_SYMBOL_GPL(cfi_qry_present); 532e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev 54c314dfdc358847eef0fc07ec8682e1acc8cadd00David Woodhouseint __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map, 55c314dfdc358847eef0fc07ec8682e1acc8cadd00David Woodhouse struct cfi_private *cfi) 562e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev{ 572e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); 582e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); 59c314dfdc358847eef0fc07ec8682e1acc8cadd00David Woodhouse if (cfi_qry_present(map, base, cfi)) 602e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev return 1; 612e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev /* QRY not found probably we deal with some odd CFI chips */ 622e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev /* Some revisions of some old Intel chips? */ 632e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); 642e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); 652e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); 66c314dfdc358847eef0fc07ec8682e1acc8cadd00David Woodhouse if (cfi_qry_present(map, base, cfi)) 672e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev return 1; 682e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev /* ST M29DW chips */ 692e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); 702e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL); 714a58948669702639db7acecfa2105c3172d85c93Guillaume LECERF if (cfi_qry_present(map, base, cfi)) 724a58948669702639db7acecfa2105c3172d85c93Guillaume LECERF return 1; 734a58948669702639db7acecfa2105c3172d85c93Guillaume LECERF /* some old SST chips, e.g. 39VF160x/39VF320x */ 744a58948669702639db7acecfa2105c3172d85c93Guillaume LECERF cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); 754a58948669702639db7acecfa2105c3172d85c93Guillaume LECERF cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL); 764a58948669702639db7acecfa2105c3172d85c93Guillaume LECERF cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL); 774a58948669702639db7acecfa2105c3172d85c93Guillaume LECERF cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL); 78fc61015f72808f2fd83657909d02f4d29404b8c6Guillaume LECERF if (cfi_qry_present(map, base, cfi)) 79fc61015f72808f2fd83657909d02f4d29404b8c6Guillaume LECERF return 1; 80fc61015f72808f2fd83657909d02f4d29404b8c6Guillaume LECERF /* SST 39VF640xB */ 81fc61015f72808f2fd83657909d02f4d29404b8c6Guillaume LECERF cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); 82fc61015f72808f2fd83657909d02f4d29404b8c6Guillaume LECERF cfi_send_gen_cmd(0xAA, 0x555, base, map, cfi, cfi->device_type, NULL); 83fc61015f72808f2fd83657909d02f4d29404b8c6Guillaume LECERF cfi_send_gen_cmd(0x55, 0x2AA, base, map, cfi, cfi->device_type, NULL); 84fc61015f72808f2fd83657909d02f4d29404b8c6Guillaume LECERF cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL); 85c314dfdc358847eef0fc07ec8682e1acc8cadd00David Woodhouse if (cfi_qry_present(map, base, cfi)) 862e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev return 1; 872e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev /* QRY not found */ 882e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev return 0; 892e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev} 90c314dfdc358847eef0fc07ec8682e1acc8cadd00David WoodhouseEXPORT_SYMBOL_GPL(cfi_qry_mode_on); 91c314dfdc358847eef0fc07ec8682e1acc8cadd00David Woodhouse 92c314dfdc358847eef0fc07ec8682e1acc8cadd00David Woodhousevoid __xipram cfi_qry_mode_off(uint32_t base, struct map_info *map, 93c314dfdc358847eef0fc07ec8682e1acc8cadd00David Woodhouse struct cfi_private *cfi) 942e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev{ 952e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); 962e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); 9723af51ecfb04ff65bae51bd8e2270f4449abc789Massimo Cirillo /* M29W128G flashes require an additional reset command 9823af51ecfb04ff65bae51bd8e2270f4449abc789Massimo Cirillo when exit qry mode */ 9923af51ecfb04ff65bae51bd8e2270f4449abc789Massimo Cirillo if ((cfi->mfr == CFI_MFR_ST) && (cfi->id == 0x227E || cfi->id == 0x7E)) 10023af51ecfb04ff65bae51bd8e2270f4449abc789Massimo Cirillo cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); 1012e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev} 102c314dfdc358847eef0fc07ec8682e1acc8cadd00David WoodhouseEXPORT_SYMBOL_GPL(cfi_qry_mode_off); 1032e489e077a6ad118c4f247faedf330117b107cceAlexey Korolev 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct cfi_extquery * 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name) 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u32 base = 0; // cfi->chips[0].start; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ofs_factor = cfi->interleave * cfi->device_type; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cfi_extquery *extp = NULL; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!adr) 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 116087444da61ed972b3c2bfbf7dcf317cb4475f143Guillaume LECERF printk(KERN_INFO "%s Extended Query Table at 0x%4.4X\n", name, adr); 117087444da61ed972b3c2bfbf7dcf317cb4475f143Guillaume LECERF 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extp = kmalloc(size, GFP_KERNEL); 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!extp) { 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "Failed to allocate memory\n"); 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_MTD_XIP 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_disable(); 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Switch it into Query Mode */ 129c314dfdc358847eef0fc07ec8682e1acc8cadd00David Woodhouse cfi_qry_mode_on(base, map, cfi); 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Read in the Extended Query Table */ 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; i<size; i++) { 1321f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner ((unsigned char *)extp)[i] = 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfi_read_query(map, base+((adr+i)*ofs_factor)); 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Make sure it returns to read mode */ 137c314dfdc358847eef0fc07ec8682e1acc8cadd00David Woodhouse cfi_qry_mode_off(base, map, cfi); 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_MTD_XIP 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) map_read(map, base); 141ca5c23c3b8882d61bf19b7685f2244501902869fPaulius Zaleckas xip_iprefetch(); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_enable(); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: return extp; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(cfi_read_pri); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid cfi_fixup(struct mtd_info *mtd, struct cfi_fixup *fixups) 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct map_info *map = mtd->priv; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cfi_fixup *f; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (f=fixups; f->fixup; f++) { 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) && 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((f->id == CFI_ID_ANY) || (f->id == cfi->id))) { 159cc31822250236ec173bb2aa149ebe2ba35405db2Guillaume LECERF f->fixup(mtd); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(cfi_fixup); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loff_t ofs, size_t len, void *thunk) 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct map_info *map = mtd->priv; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long adr; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int chipnum, ret = 0; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, first; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mtd_erase_region_info *regions = mtd->eraseregions; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check that both start and end of the requested erase are 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * aligned with the erasesize at the appropriate addresses. 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = 0; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner /* Skip all erase regions which are ended before the start of 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the requested erase. Actually, to save on the calculations, 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds we skip to the first erase region which starts after the 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start of the requested erase, and then go back one. 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1871f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (i < mtd->numeraseregions && ofs >= regions[i].offset) 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i++; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i--; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1921f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner /* OK, now i is pointing at the erase region in which this 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds erase request starts. Check the start of the requested 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds erase range is aligned with the erase size which is in 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds effect here. 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ofs & (regions[i].erasesize-1)) 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Remember the erase region we start on */ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds first = i; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Next, check that the end of the requested erase is aligned 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with the erase region at that address. 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (i<mtd->numeraseregions && (ofs + len) >= regions[i].offset) 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i++; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* As before, drop back one to point at the region in which 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the address actually falls 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i--; 2151f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ofs + len) & (regions[i].erasesize-1)) 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chipnum = ofs >> cfi->chipshift; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adr = ofs - (chipnum << cfi->chipshift); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i=first; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while(len) { 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int size = regions[i].erasesize; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk); 2281f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adr += size; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ofs += size; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= size; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ofs == regions[i].offset + size * regions[i].numblocks) 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i++; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (adr >> cfi->chipshift) { 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adr = 0; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chipnum++; 2421f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (chipnum >= cfi->numchips) 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(cfi_varsize_frob); 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 254