blob: 81b7767a665aa053ebffd4c716da847d40edc01a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Common Flash Interface support:
3 * Intel Extended Vendor Command Set (ID 0x0001)
4 *
5 * (C) 2000 Red Hat. GPL'd
6 *
Nicolas Pitre8bc3b382005-11-23 22:07:56 +00007 * $Id: cfi_cmdset_0001.c,v 1.186 2005/11/23 22:07:52 nico Exp $
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
Thomas Gleixner1f948b42005-11-07 11:15:37 +00009 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 * 10/10/2000 Nicolas Pitre <nico@cam.org>
11 * - completely revamped method functions so they are aware and
12 * independent of the flash geometry (buswidth, interleave, etc.)
13 * - scalability vs code size is completely set at compile-time
14 * (see include/linux/mtd/cfi.h for selection)
15 * - optimized write buffer method
16 * 02/05/2002 Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com>
17 * - reworked lock/unlock/erase support for var size flash
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -080018 * 21/03/2007 Rodolfo Giometti <giometti@linux.it>
19 * - auto unlock sectors on resume for auto locking flash on power up
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 */
21
22#include <linux/module.h>
23#include <linux/types.h>
24#include <linux/kernel.h>
25#include <linux/sched.h>
26#include <linux/init.h>
27#include <asm/io.h>
28#include <asm/byteorder.h>
29
30#include <linux/errno.h>
31#include <linux/slab.h>
32#include <linux/delay.h>
33#include <linux/interrupt.h>
Nicolas Pitre963a6fb2005-04-01 02:59:56 +010034#include <linux/reboot.h>
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -080035#include <linux/bitmap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/mtd/xip.h>
37#include <linux/mtd/map.h>
38#include <linux/mtd/mtd.h>
39#include <linux/mtd/compatmac.h>
40#include <linux/mtd/cfi.h>
41
42/* #define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE */
43/* #define CMDSET0001_DISABLE_WRITE_SUSPEND */
44
45// debugging, turns off buffer write mode if set to 1
46#define FORCE_WORD_WRITE 0
47
48#define MANUFACTURER_INTEL 0x0089
49#define I82802AB 0x00ad
50#define I82802AC 0x00ac
51#define MANUFACTURER_ST 0x0020
52#define M50LPW080 0x002F
Hans-Christian Egtvedtd10a39d2007-10-30 16:33:07 +010053#define AT49BV640D 0x02de
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
57static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
Nicolas Pitree102d542005-08-06 05:46:59 +010058static int cfi_intelext_writev(struct mtd_info *, const struct kvec *, unsigned long, loff_t, size_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
60static void cfi_intelext_sync (struct mtd_info *);
61static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
62static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
Todd Poynor8048d2f2005-03-31 00:57:33 +010063#ifdef CONFIG_MTD_OTP
Nicolas Pitref77814d2005-02-08 17:11:19 +000064static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
65static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
66static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
67static int cfi_intelext_lock_user_prot_reg (struct mtd_info *, loff_t, size_t);
68static int cfi_intelext_get_fact_prot_info (struct mtd_info *,
69 struct otp_info *, size_t);
70static int cfi_intelext_get_user_prot_info (struct mtd_info *,
71 struct otp_info *, size_t);
Todd Poynor8048d2f2005-03-31 00:57:33 +010072#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070073static int cfi_intelext_suspend (struct mtd_info *);
74static void cfi_intelext_resume (struct mtd_info *);
Nicolas Pitre963a6fb2005-04-01 02:59:56 +010075static int cfi_intelext_reboot (struct notifier_block *, unsigned long, void *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
77static void cfi_intelext_destroy(struct mtd_info *);
78
79struct mtd_info *cfi_cmdset_0001(struct map_info *, int);
80
81static struct mtd_info *cfi_intelext_setup (struct mtd_info *);
82static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **);
83
84static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
85 size_t *retlen, u_char **mtdbuf);
86static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
87 size_t len);
88
Alexey Korolev5a37cf12007-10-22 17:55:20 +010089static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
91static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr);
92#include "fwh_lock.h"
93
94
95
96/*
97 * *********** SETUP AND PROBE BITS ***********
98 */
99
100static struct mtd_chip_driver cfi_intelext_chipdrv = {
101 .probe = NULL, /* Not usable directly */
102 .destroy = cfi_intelext_destroy,
103 .name = "cfi_cmdset_0001",
104 .module = THIS_MODULE
105};
106
107/* #define DEBUG_LOCK_BITS */
108/* #define DEBUG_CFI_FEATURES */
109
110#ifdef DEBUG_CFI_FEATURES
111static void cfi_tell_features(struct cfi_pri_intelext *extp)
112{
113 int i;
Nicolas Pitre638d9832005-08-06 05:40:46 +0100114 printk(" Extended Query version %c.%c\n", extp->MajorVersion, extp->MinorVersion);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport);
116 printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported");
117 printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported");
118 printk(" - Suspend Program: %s\n", extp->FeatureSupport&4?"supported":"unsupported");
119 printk(" - Legacy Lock/Unlock: %s\n", extp->FeatureSupport&8?"supported":"unsupported");
120 printk(" - Queued Erase: %s\n", extp->FeatureSupport&16?"supported":"unsupported");
121 printk(" - Instant block lock: %s\n", extp->FeatureSupport&32?"supported":"unsupported");
122 printk(" - Protection Bits: %s\n", extp->FeatureSupport&64?"supported":"unsupported");
123 printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported");
124 printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported");
125 printk(" - Simultaneous operations: %s\n", extp->FeatureSupport&512?"supported":"unsupported");
Nicolas Pitre638d9832005-08-06 05:40:46 +0100126 printk(" - Extended Flash Array: %s\n", extp->FeatureSupport&1024?"supported":"unsupported");
127 for (i=11; i<32; i++) {
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000128 if (extp->FeatureSupport & (1<<i))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 printk(" - Unknown Bit %X: supported\n", i);
130 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 printk(" Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport);
133 printk(" - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported");
134 for (i=1; i<8; i++) {
135 if (extp->SuspendCmdSupport & (1<<i))
136 printk(" - Unknown Bit %X: supported\n", i);
137 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000138
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 printk(" Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask);
140 printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no");
Nicolas Pitre638d9832005-08-06 05:40:46 +0100141 printk(" - Lock-Down Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no");
142 for (i=2; i<3; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 if (extp->BlkStatusRegMask & (1<<i))
144 printk(" - Unknown Bit %X Active: yes\n",i);
145 }
Nicolas Pitre638d9832005-08-06 05:40:46 +0100146 printk(" - EFA Lock Bit: %s\n", extp->BlkStatusRegMask&16?"yes":"no");
147 printk(" - EFA Lock-Down Bit: %s\n", extp->BlkStatusRegMask&32?"yes":"no");
148 for (i=6; i<16; i++) {
149 if (extp->BlkStatusRegMask & (1<<i))
150 printk(" - Unknown Bit %X Active: yes\n",i);
151 }
152
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000153 printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 extp->VccOptimal >> 4, extp->VccOptimal & 0xf);
155 if (extp->VppOptimal)
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000156 printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 extp->VppOptimal >> 4, extp->VppOptimal & 0xf);
158}
159#endif
160
Hans-Christian Egtvedtd10a39d2007-10-30 16:33:07 +0100161/* Atmel chips don't use the same PRI format as Intel chips */
162static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
163{
164 struct map_info *map = mtd->priv;
165 struct cfi_private *cfi = map->fldrv_priv;
166 struct cfi_pri_intelext *extp = cfi->cmdset_priv;
167 struct cfi_pri_atmel atmel_pri;
168 uint32_t features = 0;
169
170 /* Reverse byteswapping */
171 extp->FeatureSupport = cpu_to_le32(extp->FeatureSupport);
172 extp->BlkStatusRegMask = cpu_to_le16(extp->BlkStatusRegMask);
173 extp->ProtRegAddr = cpu_to_le16(extp->ProtRegAddr);
174
175 memcpy(&atmel_pri, extp, sizeof(atmel_pri));
176 memset((char *)extp + 5, 0, sizeof(*extp) - 5);
177
178 printk(KERN_ERR "atmel Features: %02x\n", atmel_pri.Features);
179
180 if (atmel_pri.Features & 0x01) /* chip erase supported */
181 features |= (1<<0);
182 if (atmel_pri.Features & 0x02) /* erase suspend supported */
183 features |= (1<<1);
184 if (atmel_pri.Features & 0x04) /* program suspend supported */
185 features |= (1<<2);
186 if (atmel_pri.Features & 0x08) /* simultaneous operations supported */
187 features |= (1<<9);
188 if (atmel_pri.Features & 0x20) /* page mode read supported */
189 features |= (1<<7);
190 if (atmel_pri.Features & 0x40) /* queued erase supported */
191 features |= (1<<4);
192 if (atmel_pri.Features & 0x80) /* Protection bits supported */
193 features |= (1<<6);
194
195 extp->FeatureSupport = features;
196
197 /* burst write mode not supported */
198 cfi->cfiq->BufWriteTimeoutTyp = 0;
199 cfi->cfiq->BufWriteTimeoutMax = 0;
200}
201
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000203/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)
205{
206 struct map_info *map = mtd->priv;
207 struct cfi_private *cfi = map->fldrv_priv;
208 struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
209
210 printk(KERN_WARNING "cfi_cmdset_0001: Suspend "
211 "erase on write disabled.\n");
212 extp->SuspendCmdSupport &= ~1;
213}
214#endif
215
216#ifdef CMDSET0001_DISABLE_WRITE_SUSPEND
217static void fixup_no_write_suspend(struct mtd_info *mtd, void* param)
218{
219 struct map_info *map = mtd->priv;
220 struct cfi_private *cfi = map->fldrv_priv;
221 struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
222
223 if (cfip && (cfip->FeatureSupport&4)) {
224 cfip->FeatureSupport &= ~4;
225 printk(KERN_WARNING "cfi_cmdset_0001: write suspend disabled\n");
226 }
227}
228#endif
229
230static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param)
231{
232 struct map_info *map = mtd->priv;
233 struct cfi_private *cfi = map->fldrv_priv;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000234
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 cfi->cfiq->BufWriteTimeoutTyp = 0; /* Not supported */
236 cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */
237}
238
239static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param)
240{
241 struct map_info *map = mtd->priv;
242 struct cfi_private *cfi = map->fldrv_priv;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000243
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 /* Note this is done after the region info is endian swapped */
245 cfi->cfiq->EraseRegionInfo[1] =
246 (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e;
247};
248
249static void fixup_use_point(struct mtd_info *mtd, void *param)
250{
251 struct map_info *map = mtd->priv;
252 if (!mtd->point && map_is_linear(map)) {
253 mtd->point = cfi_intelext_point;
254 mtd->unpoint = cfi_intelext_unpoint;
255 }
256}
257
258static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
259{
260 struct map_info *map = mtd->priv;
261 struct cfi_private *cfi = map->fldrv_priv;
262 if (cfi->cfiq->BufWriteTimeoutTyp) {
263 printk(KERN_INFO "Using buffer write method\n" );
264 mtd->write = cfi_intelext_write_buffers;
Nicolas Pitree102d542005-08-06 05:46:59 +0100265 mtd->writev = cfi_intelext_writev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 }
267}
268
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -0800269/*
270 * Some chips power-up with all sectors locked by default.
271 */
Justin Treone619a752008-01-30 10:25:49 -0800272static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param)
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -0800273{
Justin Treone619a752008-01-30 10:25:49 -0800274 struct map_info *map = mtd->priv;
275 struct cfi_private *cfi = map->fldrv_priv;
276 struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
277
278 if (cfip->FeatureSupport&32) {
279 printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
280 mtd->flags |= MTD_POWERUP_LOCK;
281 }
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -0800282}
283
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284static struct cfi_fixup cfi_fixup_table[] = {
Hans-Christian Egtvedtd10a39d2007-10-30 16:33:07 +0100285 { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000287 { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288#endif
289#ifdef CMDSET0001_DISABLE_WRITE_SUSPEND
290 { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend, NULL },
291#endif
292#if !FORCE_WORD_WRITE
293 { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL },
294#endif
295 { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
296 { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
Justin Treone619a752008-01-30 10:25:49 -0800297 { MANUFACTURER_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock, NULL, },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 { 0, 0, NULL, NULL }
299};
300
301static struct cfi_fixup jedec_fixup_table[] = {
302 { MANUFACTURER_INTEL, I82802AB, fixup_use_fwh_lock, NULL, },
303 { MANUFACTURER_INTEL, I82802AC, fixup_use_fwh_lock, NULL, },
304 { MANUFACTURER_ST, M50LPW080, fixup_use_fwh_lock, NULL, },
305 { 0, 0, NULL, NULL }
306};
307static struct cfi_fixup fixup_table[] = {
308 /* The CFI vendor ids and the JEDEC vendor IDs appear
309 * to be common. It is like the devices id's are as
310 * well. This table is to pick all cases where
311 * we know that is the case.
312 */
313 { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point, NULL },
314 { 0, 0, NULL, NULL }
315};
316
317static inline struct cfi_pri_intelext *
318read_pri_intelext(struct map_info *map, __u16 adr)
319{
320 struct cfi_pri_intelext *extp;
321 unsigned int extp_size = sizeof(*extp);
322
323 again:
324 extp = (struct cfi_pri_intelext *)cfi_read_pri(map, adr, extp_size, "Intel/Sharp");
325 if (!extp)
326 return NULL;
327
Todd Poynord88f9772005-07-20 22:01:17 +0100328 if (extp->MajorVersion != '1' ||
Alexey Korolevb1c9c9b2007-11-23 09:31:56 +0000329 (extp->MinorVersion < '0' || extp->MinorVersion > '5')) {
Todd Poynord88f9772005-07-20 22:01:17 +0100330 printk(KERN_ERR " Unknown Intel/Sharp Extended Query "
331 "version %c.%c.\n", extp->MajorVersion,
332 extp->MinorVersion);
333 kfree(extp);
334 return NULL;
335 }
336
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 /* Do some byteswapping if necessary */
338 extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
339 extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
340 extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
341
Nicolas Pitre638d9832005-08-06 05:40:46 +0100342 if (extp->MajorVersion == '1' && extp->MinorVersion >= '3') {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 unsigned int extra_size = 0;
344 int nb_parts, i;
345
346 /* Protection Register info */
Nicolas Pitre72b56a22005-02-05 02:06:19 +0000347 extra_size += (extp->NumProtectionFields - 1) *
348 sizeof(struct cfi_intelext_otpinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
350 /* Burst Read info */
Nicolas Pitre6f6ed052005-10-25 21:28:43 +0100351 extra_size += 2;
352 if (extp_size < sizeof(*extp) + extra_size)
353 goto need_more;
354 extra_size += extp->extra[extra_size-1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
356 /* Number of hardware-partitions */
357 extra_size += 1;
358 if (extp_size < sizeof(*extp) + extra_size)
359 goto need_more;
360 nb_parts = extp->extra[extra_size - 1];
361
Nicolas Pitre638d9832005-08-06 05:40:46 +0100362 /* skip the sizeof(partregion) field in CFI 1.4 */
363 if (extp->MinorVersion >= '4')
364 extra_size += 2;
365
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 for (i = 0; i < nb_parts; i++) {
367 struct cfi_intelext_regioninfo *rinfo;
368 rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[extra_size];
369 extra_size += sizeof(*rinfo);
370 if (extp_size < sizeof(*extp) + extra_size)
371 goto need_more;
372 rinfo->NumIdentPartitions=le16_to_cpu(rinfo->NumIdentPartitions);
373 extra_size += (rinfo->NumBlockTypes - 1)
374 * sizeof(struct cfi_intelext_blockinfo);
375 }
376
Nicolas Pitre638d9832005-08-06 05:40:46 +0100377 if (extp->MinorVersion >= '4')
378 extra_size += sizeof(struct cfi_intelext_programming_regioninfo);
379
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 if (extp_size < sizeof(*extp) + extra_size) {
381 need_more:
382 extp_size = sizeof(*extp) + extra_size;
383 kfree(extp);
384 if (extp_size > 4096) {
385 printk(KERN_ERR
386 "%s: cfi_pri_intelext is too fat\n",
Harvey Harrisoncb53b3b2008-04-18 13:44:19 -0700387 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 return NULL;
389 }
390 goto again;
391 }
392 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000393
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 return extp;
395}
396
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
398{
399 struct cfi_private *cfi = map->fldrv_priv;
400 struct mtd_info *mtd;
401 int i;
402
Burman Yan95b93a02006-11-15 21:10:29 +0200403 mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 if (!mtd) {
405 printk(KERN_ERR "Failed to allocate memory for MTD device\n");
406 return NULL;
407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 mtd->priv = map;
409 mtd->type = MTD_NORFLASH;
410
411 /* Fill in the default mtd operations */
412 mtd->erase = cfi_intelext_erase_varsize;
413 mtd->read = cfi_intelext_read;
414 mtd->write = cfi_intelext_write_words;
415 mtd->sync = cfi_intelext_sync;
416 mtd->lock = cfi_intelext_lock;
417 mtd->unlock = cfi_intelext_unlock;
418 mtd->suspend = cfi_intelext_suspend;
419 mtd->resume = cfi_intelext_resume;
420 mtd->flags = MTD_CAP_NORFLASH;
421 mtd->name = map->name;
Artem B. Bityutskiy17ffc7b2006-06-22 18:15:48 +0400422 mtd->writesize = 1;
Nicolas Pitre963a6fb2005-04-01 02:59:56 +0100423
424 mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;
425
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 if (cfi->cfi_mode == CFI_MODE_CFI) {
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000427 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 * It's a real CFI chip, not one for which the probe
429 * routine faked a CFI structure. So we read the feature
430 * table from it.
431 */
432 __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
433 struct cfi_pri_intelext *extp;
434
435 extp = read_pri_intelext(map, adr);
436 if (!extp) {
437 kfree(mtd);
438 return NULL;
439 }
440
441 /* Install our own private info structure */
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000442 cfi->cmdset_priv = extp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
444 cfi_fixup(mtd, cfi_fixup_table);
445
446#ifdef DEBUG_CFI_FEATURES
447 /* Tell the user about it in lots of lovely detail */
448 cfi_tell_features(extp);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000449#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451 if(extp->SuspendCmdSupport & 1) {
452 printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n");
453 }
454 }
455 else if (cfi->cfi_mode == CFI_MODE_JEDEC) {
456 /* Apply jedec specific fixups */
457 cfi_fixup(mtd, jedec_fixup_table);
458 }
459 /* Apply generic fixups */
460 cfi_fixup(mtd, fixup_table);
461
462 for (i=0; i< cfi->numchips; i++) {
David Woodhouse2a5bd592007-02-09 14:39:10 +0000463 if (cfi->cfiq->WordWriteTimeoutTyp)
464 cfi->chips[i].word_write_time =
465 1<<cfi->cfiq->WordWriteTimeoutTyp;
466 else
467 cfi->chips[i].word_write_time = 50000;
468
469 if (cfi->cfiq->BufWriteTimeoutTyp)
470 cfi->chips[i].buffer_write_time =
471 1<<cfi->cfiq->BufWriteTimeoutTyp;
472 /* No default; if it isn't specified, we won't use it */
473
474 if (cfi->cfiq->BlockEraseTimeoutTyp)
475 cfi->chips[i].erase_time =
476 1000<<cfi->cfiq->BlockEraseTimeoutTyp;
477 else
478 cfi->chips[i].erase_time = 2000000;
479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 cfi->chips[i].ref_point_counter = 0;
Simon Voglc314b6f2006-02-24 13:04:09 -0800481 init_waitqueue_head(&(cfi->chips[i].wq));
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000482 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
484 map->fldrv = &cfi_intelext_chipdrv;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 return cfi_intelext_setup(mtd);
487}
David Woodhousea15bdee2006-05-08 22:35:05 +0100488struct mtd_info *cfi_cmdset_0003(struct map_info *map, int primary) __attribute__((alias("cfi_cmdset_0001")));
489struct mtd_info *cfi_cmdset_0200(struct map_info *map, int primary) __attribute__((alias("cfi_cmdset_0001")));
490EXPORT_SYMBOL_GPL(cfi_cmdset_0001);
491EXPORT_SYMBOL_GPL(cfi_cmdset_0003);
492EXPORT_SYMBOL_GPL(cfi_cmdset_0200);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493
494static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
495{
496 struct map_info *map = mtd->priv;
497 struct cfi_private *cfi = map->fldrv_priv;
498 unsigned long offset = 0;
499 int i,j;
500 unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
501
502 //printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips);
503
504 mtd->size = devsize * cfi->numchips;
505
506 mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000507 mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 * mtd->numeraseregions, GFP_KERNEL);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000509 if (!mtd->eraseregions) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");
511 goto setup_err;
512 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000513
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
515 unsigned long ernum, ersize;
516 ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
517 ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
518
519 if (mtd->erasesize < ersize) {
520 mtd->erasesize = ersize;
521 }
522 for (j=0; j<cfi->numchips; j++) {
523 mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
524 mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
525 mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -0800526 mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].lockmap = kmalloc(ernum / 8 + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 }
528 offset += (ersize * ernum);
529 }
530
531 if (offset != devsize) {
532 /* Argh */
533 printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
534 goto setup_err;
535 }
536
537 for (i=0; i<mtd->numeraseregions;i++){
Nicolas Pitre48436532005-08-06 05:16:52 +0100538 printk(KERN_DEBUG "erase region %d: offset=0x%x,size=0x%x,blocks=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 i,mtd->eraseregions[i].offset,
540 mtd->eraseregions[i].erasesize,
541 mtd->eraseregions[i].numblocks);
542 }
543
Nicolas Pitref77814d2005-02-08 17:11:19 +0000544#ifdef CONFIG_MTD_OTP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
Nicolas Pitref77814d2005-02-08 17:11:19 +0000546 mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
547 mtd->write_user_prot_reg = cfi_intelext_write_user_prot_reg;
548 mtd->lock_user_prot_reg = cfi_intelext_lock_user_prot_reg;
549 mtd->get_fact_prot_info = cfi_intelext_get_fact_prot_info;
550 mtd->get_user_prot_info = cfi_intelext_get_user_prot_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551#endif
552
553 /* This function has the potential to distort the reality
554 a bit and therefore should be called last. */
555 if (cfi_intelext_partition_fixup(mtd, &cfi) != 0)
556 goto setup_err;
557
558 __module_get(THIS_MODULE);
Nicolas Pitre963a6fb2005-04-01 02:59:56 +0100559 register_reboot_notifier(&mtd->reboot_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 return mtd;
561
562 setup_err:
563 if(mtd) {
Jesper Juhlfa671642005-11-07 01:01:27 -0800564 kfree(mtd->eraseregions);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 kfree(mtd);
566 }
567 kfree(cfi->cmdset_priv);
568 return NULL;
569}
570
571static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
572 struct cfi_private **pcfi)
573{
574 struct map_info *map = mtd->priv;
575 struct cfi_private *cfi = *pcfi;
576 struct cfi_pri_intelext *extp = cfi->cmdset_priv;
577
578 /*
Jesper Juhl8f1a8662007-07-05 02:18:34 +0200579 * Probing of multi-partition flash chips.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 *
581 * To support multiple partitions when available, we simply arrange
582 * for each of them to have their own flchip structure even if they
583 * are on the same physical chip. This means completely recreating
584 * a new cfi_private structure right here which is a blatent code
585 * layering violation, but this is still the least intrusive
586 * arrangement at this point. This can be rearranged in the future
587 * if someone feels motivated enough. --nico
588 */
Nicolas Pitre638d9832005-08-06 05:40:46 +0100589 if (extp && extp->MajorVersion == '1' && extp->MinorVersion >= '3'
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 && extp->FeatureSupport & (1 << 9)) {
591 struct cfi_private *newcfi;
592 struct flchip *chip;
593 struct flchip_shared *shared;
594 int offs, numregions, numparts, partshift, numvirtchips, i, j;
595
596 /* Protection Register info */
Nicolas Pitre72b56a22005-02-05 02:06:19 +0000597 offs = (extp->NumProtectionFields - 1) *
598 sizeof(struct cfi_intelext_otpinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
600 /* Burst Read info */
Nicolas Pitre6f6ed052005-10-25 21:28:43 +0100601 offs += extp->extra[offs+1]+2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
603 /* Number of partition regions */
604 numregions = extp->extra[offs];
605 offs += 1;
606
Nicolas Pitre638d9832005-08-06 05:40:46 +0100607 /* skip the sizeof(partregion) field in CFI 1.4 */
608 if (extp->MinorVersion >= '4')
609 offs += 2;
610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 /* Number of hardware partitions */
612 numparts = 0;
613 for (i = 0; i < numregions; i++) {
614 struct cfi_intelext_regioninfo *rinfo;
615 rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[offs];
616 numparts += rinfo->NumIdentPartitions;
617 offs += sizeof(*rinfo)
618 + (rinfo->NumBlockTypes - 1) *
619 sizeof(struct cfi_intelext_blockinfo);
620 }
621
Nicolas Pitre638d9832005-08-06 05:40:46 +0100622 /* Programming Region info */
623 if (extp->MinorVersion >= '4') {
624 struct cfi_intelext_programming_regioninfo *prinfo;
625 prinfo = (struct cfi_intelext_programming_regioninfo *)&extp->extra[offs];
Joern Engel28318772006-05-22 23:18:05 +0200626 mtd->writesize = cfi->interleave << prinfo->ProgRegShift;
Joern Engel5fa43392006-05-22 23:18:29 +0200627 mtd->flags &= ~MTD_BIT_WRITEABLE;
Nicolas Pitre638d9832005-08-06 05:40:46 +0100628 printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n",
Joern Engel28318772006-05-22 23:18:05 +0200629 map->name, mtd->writesize,
Artem Bityutskiyd4160852007-01-30 10:45:55 +0200630 cfi->interleave * prinfo->ControlValid,
631 cfi->interleave * prinfo->ControlInvalid);
Nicolas Pitre638d9832005-08-06 05:40:46 +0100632 }
633
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 /*
635 * All functions below currently rely on all chips having
636 * the same geometry so we'll just assume that all hardware
637 * partitions are of the same size too.
638 */
639 partshift = cfi->chipshift - __ffs(numparts);
640
641 if ((1 << partshift) < mtd->erasesize) {
642 printk( KERN_ERR
643 "%s: bad number of hw partitions (%d)\n",
Harvey Harrisoncb53b3b2008-04-18 13:44:19 -0700644 __func__, numparts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 return -EINVAL;
646 }
647
648 numvirtchips = cfi->numchips * numparts;
649 newcfi = kmalloc(sizeof(struct cfi_private) + numvirtchips * sizeof(struct flchip), GFP_KERNEL);
650 if (!newcfi)
651 return -ENOMEM;
652 shared = kmalloc(sizeof(struct flchip_shared) * cfi->numchips, GFP_KERNEL);
653 if (!shared) {
654 kfree(newcfi);
655 return -ENOMEM;
656 }
657 memcpy(newcfi, cfi, sizeof(struct cfi_private));
658 newcfi->numchips = numvirtchips;
659 newcfi->chipshift = partshift;
660
661 chip = &newcfi->chips[0];
662 for (i = 0; i < cfi->numchips; i++) {
663 shared[i].writing = shared[i].erasing = NULL;
664 spin_lock_init(&shared[i].lock);
665 for (j = 0; j < numparts; j++) {
666 *chip = cfi->chips[i];
667 chip->start += j << partshift;
668 chip->priv = &shared[i];
669 /* those should be reset too since
670 they create memory references. */
671 init_waitqueue_head(&chip->wq);
672 spin_lock_init(&chip->_spinlock);
673 chip->mutex = &chip->_spinlock;
674 chip++;
675 }
676 }
677
678 printk(KERN_DEBUG "%s: %d set(s) of %d interleaved chips "
679 "--> %d partitions of %d KiB\n",
680 map->name, cfi->numchips, cfi->interleave,
681 newcfi->numchips, 1<<(newcfi->chipshift-10));
682
683 map->fldrv_priv = newcfi;
684 *pcfi = newcfi;
685 kfree(cfi);
686 }
687
688 return 0;
689}
690
691/*
692 * *********** CHIP ACCESS FUNCTIONS ***********
693 */
Alexey Korolev5a37cf12007-10-22 17:55:20 +0100694static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695{
696 DECLARE_WAITQUEUE(wait, current);
697 struct cfi_private *cfi = map->fldrv_priv;
698 map_word status, status_OK = CMD(0x80), status_PWS = CMD(0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
Alexey Korolev5a37cf12007-10-22 17:55:20 +0100700 unsigned long timeo = jiffies + HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702 switch (chip->state) {
703
704 case FL_STATUS:
705 for (;;) {
706 status = map_read(map, adr);
707 if (map_word_andequal(map, status, status_OK, status_OK))
708 break;
709
710 /* At this point we're fine with write operations
711 in other partitions as they don't conflict. */
712 if (chip->priv && map_word_andequal(map, status, status_PWS, status_PWS))
713 break;
714
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 spin_unlock(chip->mutex);
716 cfi_udelay(1);
717 spin_lock(chip->mutex);
718 /* Someone else might have been playing with it. */
Alexey Korolev5a37cf12007-10-22 17:55:20 +0100719 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 }
Alexey Korolevfb6d0802008-04-04 14:30:01 -0700721 /* Fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 case FL_READY:
723 case FL_CFI_QUERY:
724 case FL_JEDEC_QUERY:
725 return 0;
726
727 case FL_ERASING:
728 if (!cfip ||
729 !(cfip->FeatureSupport & 2) ||
730 !(mode == FL_READY || mode == FL_POINT ||
731 (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1))))
732 goto sleep;
733
734
735 /* Erase suspend */
736 map_write(map, CMD(0xB0), adr);
737
738 /* If the flash has finished erasing, then 'erase suspend'
739 * appears to make some (28F320) flash devices switch to
740 * 'read' mode. Make sure that we switch to 'read status'
741 * mode so we get the right data. --rmk
742 */
743 map_write(map, CMD(0x70), adr);
744 chip->oldstate = FL_ERASING;
745 chip->state = FL_ERASE_SUSPENDING;
746 chip->erase_suspended = 1;
747 for (;;) {
748 status = map_read(map, adr);
749 if (map_word_andequal(map, status, status_OK, status_OK))
750 break;
751
752 if (time_after(jiffies, timeo)) {
753 /* Urgh. Resume and pretend we weren't here. */
754 map_write(map, CMD(0xd0), adr);
755 /* Make sure we're in 'read status' mode if it had finished */
756 map_write(map, CMD(0x70), adr);
757 chip->state = FL_ERASING;
758 chip->oldstate = FL_READY;
Nicolas Pitre48436532005-08-06 05:16:52 +0100759 printk(KERN_ERR "%s: Chip not ready after erase "
760 "suspended: status = 0x%lx\n", map->name, status.x[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 return -EIO;
762 }
763
764 spin_unlock(chip->mutex);
765 cfi_udelay(1);
766 spin_lock(chip->mutex);
767 /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
768 So we can just loop here. */
769 }
770 chip->state = FL_STATUS;
771 return 0;
772
773 case FL_XIP_WHILE_ERASING:
774 if (mode != FL_READY && mode != FL_POINT &&
775 (mode != FL_WRITING || !cfip || !(cfip->SuspendCmdSupport&1)))
776 goto sleep;
777 chip->oldstate = chip->state;
778 chip->state = FL_READY;
779 return 0;
780
Alexey Korolevfb6d0802008-04-04 14:30:01 -0700781 case FL_SHUTDOWN:
782 /* The machine is rebooting now,so no one can get chip anymore */
783 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 case FL_POINT:
785 /* Only if there's no operation suspended... */
786 if (mode == FL_READY && chip->oldstate == FL_READY)
787 return 0;
Alexey Korolevfb6d0802008-04-04 14:30:01 -0700788 /* Fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 default:
790 sleep:
791 set_current_state(TASK_UNINTERRUPTIBLE);
792 add_wait_queue(&chip->wq, &wait);
793 spin_unlock(chip->mutex);
794 schedule();
795 remove_wait_queue(&chip->wq, &wait);
796 spin_lock(chip->mutex);
Alexey Korolev5a37cf12007-10-22 17:55:20 +0100797 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 }
799}
800
Alexey Korolev5a37cf12007-10-22 17:55:20 +0100801static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
802{
803 int ret;
Alexander Belyakov6c24e412007-11-07 11:58:07 +0300804 DECLARE_WAITQUEUE(wait, current);
Alexey Korolev5a37cf12007-10-22 17:55:20 +0100805
806 retry:
807 if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING
808 || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) {
809 /*
810 * OK. We have possibility for contention on the write/erase
811 * operations which are global to the real chip and not per
812 * partition. So let's fight it over in the partition which
813 * currently has authority on the operation.
814 *
815 * The rules are as follows:
816 *
817 * - any write operation must own shared->writing.
818 *
819 * - any erase operation must own _both_ shared->writing and
820 * shared->erasing.
821 *
822 * - contention arbitration is handled in the owner's context.
823 *
824 * The 'shared' struct can be read and/or written only when
825 * its lock is taken.
826 */
827 struct flchip_shared *shared = chip->priv;
828 struct flchip *contender;
829 spin_lock(&shared->lock);
830 contender = shared->writing;
831 if (contender && contender != chip) {
832 /*
833 * The engine to perform desired operation on this
834 * partition is already in use by someone else.
835 * Let's fight over it in the context of the chip
836 * currently using it. If it is possible to suspend,
837 * that other partition will do just that, otherwise
838 * it'll happily send us to sleep. In any case, when
839 * get_chip returns success we're clear to go ahead.
840 */
841 ret = spin_trylock(contender->mutex);
842 spin_unlock(&shared->lock);
843 if (!ret)
844 goto retry;
845 spin_unlock(chip->mutex);
846 ret = chip_ready(map, contender, contender->start, mode);
847 spin_lock(chip->mutex);
848
849 if (ret == -EAGAIN) {
850 spin_unlock(contender->mutex);
851 goto retry;
852 }
853 if (ret) {
854 spin_unlock(contender->mutex);
855 return ret;
856 }
857 spin_lock(&shared->lock);
858 spin_unlock(contender->mutex);
859 }
860
Alexander Belyakov6c24e412007-11-07 11:58:07 +0300861 /* Check if we already have suspended erase
862 * on this chip. Sleep. */
863 if (mode == FL_ERASING && shared->erasing
864 && shared->erasing->oldstate == FL_ERASING) {
865 spin_unlock(&shared->lock);
866 set_current_state(TASK_UNINTERRUPTIBLE);
867 add_wait_queue(&chip->wq, &wait);
868 spin_unlock(chip->mutex);
869 schedule();
870 remove_wait_queue(&chip->wq, &wait);
871 spin_lock(chip->mutex);
872 goto retry;
873 }
874
Alexey Korolev5a37cf12007-10-22 17:55:20 +0100875 /* We now own it */
876 shared->writing = chip;
877 if (mode == FL_ERASING)
878 shared->erasing = chip;
879 spin_unlock(&shared->lock);
880 }
881 ret = chip_ready(map, chip, adr, mode);
882 if (ret == -EAGAIN)
883 goto retry;
884
885 return ret;
886}
887
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr)
889{
890 struct cfi_private *cfi = map->fldrv_priv;
891
892 if (chip->priv) {
893 struct flchip_shared *shared = chip->priv;
894 spin_lock(&shared->lock);
895 if (shared->writing == chip && chip->oldstate == FL_READY) {
896 /* We own the ability to write, but we're done */
897 shared->writing = shared->erasing;
898 if (shared->writing && shared->writing != chip) {
899 /* give back ownership to who we loaned it from */
900 struct flchip *loaner = shared->writing;
901 spin_lock(loaner->mutex);
902 spin_unlock(&shared->lock);
903 spin_unlock(chip->mutex);
904 put_chip(map, loaner, loaner->start);
905 spin_lock(chip->mutex);
906 spin_unlock(loaner->mutex);
907 wake_up(&chip->wq);
908 return;
909 }
910 shared->erasing = NULL;
911 shared->writing = NULL;
912 } else if (shared->erasing == chip && shared->writing != chip) {
913 /*
914 * We own the ability to erase without the ability
915 * to write, which means the erase was suspended
916 * and some other partition is currently writing.
917 * Don't let the switch below mess things up since
918 * we don't have ownership to resume anything.
919 */
920 spin_unlock(&shared->lock);
921 wake_up(&chip->wq);
922 return;
923 }
924 spin_unlock(&shared->lock);
925 }
926
927 switch(chip->oldstate) {
928 case FL_ERASING:
929 chip->state = chip->oldstate;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000930 /* What if one interleaved chip has finished and the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 other hasn't? The old code would leave the finished
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000932 one in READY mode. That's bad, and caused -EROFS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 errors to be returned from do_erase_oneblock because
934 that's the only bit it checked for at the time.
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000935 As the state machine appears to explicitly allow
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 sending the 0x70 (Read Status) command to an erasing
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000937 chip and expecting it to be ignored, that's what we
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 do. */
939 map_write(map, CMD(0xd0), adr);
940 map_write(map, CMD(0x70), adr);
941 chip->oldstate = FL_READY;
942 chip->state = FL_ERASING;
943 break;
944
945 case FL_XIP_WHILE_ERASING:
946 chip->state = chip->oldstate;
947 chip->oldstate = FL_READY;
948 break;
949
950 case FL_READY:
951 case FL_STATUS:
952 case FL_JEDEC_QUERY:
953 /* We should really make set_vpp() count, rather than doing this */
954 DISABLE_VPP(map);
955 break;
956 default:
Nicolas Pitre48436532005-08-06 05:16:52 +0100957 printk(KERN_ERR "%s: put_chip() called with oldstate %d!!\n", map->name, chip->oldstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 }
959 wake_up(&chip->wq);
960}
961
962#ifdef CONFIG_MTD_XIP
963
964/*
965 * No interrupt what so ever can be serviced while the flash isn't in array
966 * mode. This is ensured by the xip_disable() and xip_enable() functions
967 * enclosing any code path where the flash is known not to be in array mode.
968 * And within a XIP disabled code path, only functions marked with __xipram
969 * may be called and nothing else (it's a good thing to inspect generated
970 * assembly to make sure inline functions were actually inlined and that gcc
971 * didn't emit calls to its own support functions). Also configuring MTD CFI
972 * support to a single buswidth and a single interleave is also recommended.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 */
974
975static void xip_disable(struct map_info *map, struct flchip *chip,
976 unsigned long adr)
977{
978 /* TODO: chips with no XIP use should ignore and return */
979 (void) map_read(map, adr); /* ensure mmu mapping is up to date */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 local_irq_disable();
981}
982
983static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
984 unsigned long adr)
985{
986 struct cfi_private *cfi = map->fldrv_priv;
987 if (chip->state != FL_POINT && chip->state != FL_READY) {
988 map_write(map, CMD(0xff), adr);
989 chip->state = FL_READY;
990 }
991 (void) map_read(map, adr);
Thomas Gleixner97f927a2005-07-07 16:50:16 +0200992 xip_iprefetch();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 local_irq_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994}
995
996/*
997 * When a delay is required for the flash operation to complete, the
Nicolas Pitrec1724712006-03-30 15:52:41 +0100998 * xip_wait_for_operation() function is polling for both the given timeout
999 * and pending (but still masked) hardware interrupts. Whenever there is an
1000 * interrupt pending then the flash erase or write operation is suspended,
1001 * array mode restored and interrupts unmasked. Task scheduling might also
1002 * happen at that point. The CPU eventually returns from the interrupt or
1003 * the call to schedule() and the suspended flash operation is resumed for
1004 * the remaining of the delay period.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 *
1006 * Warning: this function _will_ fool interrupt latency tracing tools.
1007 */
1008
Nicolas Pitrec1724712006-03-30 15:52:41 +01001009static int __xipram xip_wait_for_operation(
1010 struct map_info *map, struct flchip *chip,
Alexey Korolev46a16522006-06-28 19:22:07 +01001011 unsigned long adr, unsigned int chip_op_time )
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012{
1013 struct cfi_private *cfi = map->fldrv_priv;
1014 struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
1015 map_word status, OK = CMD(0x80);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001016 unsigned long usec, suspended, start, done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 flstate_t oldstate, newstate;
1018
Nicolas Pitrec1724712006-03-30 15:52:41 +01001019 start = xip_currtime();
Alexey Korolev46a16522006-06-28 19:22:07 +01001020 usec = chip_op_time * 8;
Nicolas Pitrec1724712006-03-30 15:52:41 +01001021 if (usec == 0)
1022 usec = 500000;
1023 done = 0;
1024
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 do {
1026 cpu_relax();
1027 if (xip_irqpending() && cfip &&
1028 ((chip->state == FL_ERASING && (cfip->FeatureSupport&2)) ||
1029 (chip->state == FL_WRITING && (cfip->FeatureSupport&4))) &&
1030 (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) {
1031 /*
1032 * Let's suspend the erase or write operation when
1033 * supported. Note that we currently don't try to
1034 * suspend interleaved chips if there is already
1035 * another operation suspended (imagine what happens
1036 * when one chip was already done with the current
1037 * operation while another chip suspended it, then
1038 * we resume the whole thing at once). Yes, it
1039 * can happen!
1040 */
Nicolas Pitrec1724712006-03-30 15:52:41 +01001041 usec -= done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 map_write(map, CMD(0xb0), adr);
1043 map_write(map, CMD(0x70), adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 suspended = xip_currtime();
1045 do {
1046 if (xip_elapsed_since(suspended) > 100000) {
1047 /*
1048 * The chip doesn't want to suspend
1049 * after waiting for 100 msecs.
1050 * This is a critical error but there
1051 * is not much we can do here.
1052 */
Nicolas Pitrec1724712006-03-30 15:52:41 +01001053 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 }
1055 status = map_read(map, adr);
1056 } while (!map_word_andequal(map, status, OK, OK));
1057
1058 /* Suspend succeeded */
1059 oldstate = chip->state;
1060 if (oldstate == FL_ERASING) {
1061 if (!map_word_bitsset(map, status, CMD(0x40)))
1062 break;
1063 newstate = FL_XIP_WHILE_ERASING;
1064 chip->erase_suspended = 1;
1065 } else {
1066 if (!map_word_bitsset(map, status, CMD(0x04)))
1067 break;
1068 newstate = FL_XIP_WHILE_WRITING;
1069 chip->write_suspended = 1;
1070 }
1071 chip->state = newstate;
1072 map_write(map, CMD(0xff), adr);
1073 (void) map_read(map, adr);
1074 asm volatile (".rep 8; nop; .endr");
1075 local_irq_enable();
Nicolas Pitre6da70122005-05-19 18:05:47 +01001076 spin_unlock(chip->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 asm volatile (".rep 8; nop; .endr");
1078 cond_resched();
1079
1080 /*
1081 * We're back. However someone else might have
1082 * decided to go write to the chip if we are in
1083 * a suspended erase state. If so let's wait
1084 * until it's done.
1085 */
Nicolas Pitre6da70122005-05-19 18:05:47 +01001086 spin_lock(chip->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 while (chip->state != newstate) {
1088 DECLARE_WAITQUEUE(wait, current);
1089 set_current_state(TASK_UNINTERRUPTIBLE);
1090 add_wait_queue(&chip->wq, &wait);
Nicolas Pitre6da70122005-05-19 18:05:47 +01001091 spin_unlock(chip->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 schedule();
1093 remove_wait_queue(&chip->wq, &wait);
Nicolas Pitre6da70122005-05-19 18:05:47 +01001094 spin_lock(chip->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 }
1096 /* Disallow XIP again */
1097 local_irq_disable();
1098
1099 /* Resume the write or erase operation */
1100 map_write(map, CMD(0xd0), adr);
1101 map_write(map, CMD(0x70), adr);
1102 chip->state = oldstate;
1103 start = xip_currtime();
1104 } else if (usec >= 1000000/HZ) {
1105 /*
1106 * Try to save on CPU power when waiting delay
1107 * is at least a system timer tick period.
1108 * No need to be extremely accurate here.
1109 */
1110 xip_cpu_idle();
1111 }
1112 status = map_read(map, adr);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001113 done = xip_elapsed_since(start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 } while (!map_word_andequal(map, status, OK, OK)
Nicolas Pitrec1724712006-03-30 15:52:41 +01001115 && done < usec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
Nicolas Pitrec1724712006-03-30 15:52:41 +01001117 return (done >= usec) ? -ETIME : 0;
1118}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
1120/*
1121 * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
1122 * the flash is actively programming or erasing since we have to poll for
1123 * the operation to complete anyway. We can't do that in a generic way with
Nicolas Pitre6da70122005-05-19 18:05:47 +01001124 * a XIP setup so do it before the actual flash operation in this case
Nicolas Pitrec1724712006-03-30 15:52:41 +01001125 * and stub it out from INVAL_CACHE_AND_WAIT.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 */
Nicolas Pitre6da70122005-05-19 18:05:47 +01001127#define XIP_INVAL_CACHED_RANGE(map, from, size) \
1128 INVALIDATE_CACHED_RANGE(map, from, size)
1129
Alexey Korolev46a16522006-06-28 19:22:07 +01001130#define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, usec) \
1131 xip_wait_for_operation(map, chip, cmd_adr, usec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
1133#else
1134
1135#define xip_disable(map, chip, adr)
1136#define xip_enable(map, chip, adr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137#define XIP_INVAL_CACHED_RANGE(x...)
Nicolas Pitrec1724712006-03-30 15:52:41 +01001138#define INVAL_CACHE_AND_WAIT inval_cache_and_wait_for_operation
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
Nicolas Pitrec1724712006-03-30 15:52:41 +01001140static int inval_cache_and_wait_for_operation(
1141 struct map_info *map, struct flchip *chip,
1142 unsigned long cmd_adr, unsigned long inval_adr, int inval_len,
Alexey Korolev46a16522006-06-28 19:22:07 +01001143 unsigned int chip_op_time)
Nicolas Pitrec1724712006-03-30 15:52:41 +01001144{
1145 struct cfi_private *cfi = map->fldrv_priv;
1146 map_word status, status_OK = CMD(0x80);
Alexey Korolev46a16522006-06-28 19:22:07 +01001147 int chip_state = chip->state;
1148 unsigned int timeo, sleep_time;
Nicolas Pitre6da70122005-05-19 18:05:47 +01001149
Nicolas Pitrec1724712006-03-30 15:52:41 +01001150 spin_unlock(chip->mutex);
1151 if (inval_len)
1152 INVALIDATE_CACHED_RANGE(map, inval_adr, inval_len);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001153 spin_lock(chip->mutex);
1154
Alexey Korolev46a16522006-06-28 19:22:07 +01001155 /* set our timeout to 8 times the expected delay */
1156 timeo = chip_op_time * 8;
1157 if (!timeo)
1158 timeo = 500000;
1159 sleep_time = chip_op_time / 2;
Nicolas Pitrec1724712006-03-30 15:52:41 +01001160
Nicolas Pitrec1724712006-03-30 15:52:41 +01001161 for (;;) {
Nicolas Pitrec1724712006-03-30 15:52:41 +01001162 status = map_read(map, cmd_adr);
1163 if (map_word_andequal(map, status, status_OK, status_OK))
1164 break;
1165
Alexey Korolev46a16522006-06-28 19:22:07 +01001166 if (!timeo) {
Nicolas Pitrec1724712006-03-30 15:52:41 +01001167 map_write(map, CMD(0x70), cmd_adr);
1168 chip->state = FL_STATUS;
1169 return -ETIME;
1170 }
1171
Alexey Korolev46a16522006-06-28 19:22:07 +01001172 /* OK Still waiting. Drop the lock, wait a while and retry. */
Nicolas Pitrec1724712006-03-30 15:52:41 +01001173 spin_unlock(chip->mutex);
Alexey Korolev46a16522006-06-28 19:22:07 +01001174 if (sleep_time >= 1000000/HZ) {
1175 /*
1176 * Half of the normal delay still remaining
1177 * can be performed with a sleeping delay instead
1178 * of busy waiting.
1179 */
1180 msleep(sleep_time/1000);
1181 timeo -= sleep_time;
1182 sleep_time = 1000000/HZ;
1183 } else {
1184 udelay(1);
1185 cond_resched();
1186 timeo--;
1187 }
Nicolas Pitrec1724712006-03-30 15:52:41 +01001188 spin_lock(chip->mutex);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001189
Joakim Tjernlund967bf622006-11-28 23:11:52 +00001190 while (chip->state != chip_state) {
Alexey Korolev46a16522006-06-28 19:22:07 +01001191 /* Someone's suspended the operation: sleep */
1192 DECLARE_WAITQUEUE(wait, current);
1193 set_current_state(TASK_UNINTERRUPTIBLE);
1194 add_wait_queue(&chip->wq, &wait);
1195 spin_unlock(chip->mutex);
1196 schedule();
1197 remove_wait_queue(&chip->wq, &wait);
1198 spin_lock(chip->mutex);
1199 }
1200 }
Nicolas Pitrec1724712006-03-30 15:52:41 +01001201
1202 /* Done and happy. */
1203 chip->state = FL_STATUS;
1204 return 0;
1205}
Nicolas Pitre6da70122005-05-19 18:05:47 +01001206
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207#endif
1208
Nicolas Pitrec1724712006-03-30 15:52:41 +01001209#define WAIT_TIMEOUT(map, chip, adr, udelay) \
Alexey Korolev46a16522006-06-28 19:22:07 +01001210 INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, udelay);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001211
1212
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
1214{
1215 unsigned long cmd_addr;
1216 struct cfi_private *cfi = map->fldrv_priv;
1217 int ret = 0;
1218
1219 adr += chip->start;
1220
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001221 /* Ensure cmd read/writes are aligned. */
1222 cmd_addr = adr & ~(map_bankwidth(map)-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
1224 spin_lock(chip->mutex);
1225
1226 ret = get_chip(map, chip, cmd_addr, FL_POINT);
1227
1228 if (!ret) {
1229 if (chip->state != FL_POINT && chip->state != FL_READY)
1230 map_write(map, CMD(0xff), cmd_addr);
1231
1232 chip->state = FL_POINT;
1233 chip->ref_point_counter++;
1234 }
1235 spin_unlock(chip->mutex);
1236
1237 return ret;
1238}
1239
1240static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
1241{
1242 struct map_info *map = mtd->priv;
1243 struct cfi_private *cfi = map->fldrv_priv;
Andy Lowe097f2572007-01-12 18:05:10 -05001244 unsigned long ofs, last_end = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 int chipnum;
1246 int ret = 0;
1247
1248 if (!map->virt || (from + len > mtd->size))
1249 return -EINVAL;
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001250
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 /* Now lock the chip(s) to POINT state */
1252
1253 /* ofs: offset within the first chip that the first read should start */
1254 chipnum = (from >> cfi->chipshift);
1255 ofs = from - (chipnum << cfi->chipshift);
1256
Andy Lowe097f2572007-01-12 18:05:10 -05001257 *mtdbuf = (void *)map->virt + cfi->chips[chipnum].start + ofs;
1258 *retlen = 0;
1259
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 while (len) {
1261 unsigned long thislen;
1262
1263 if (chipnum >= cfi->numchips)
1264 break;
1265
Andy Lowe097f2572007-01-12 18:05:10 -05001266 /* We cannot point across chips that are virtually disjoint */
1267 if (!last_end)
1268 last_end = cfi->chips[chipnum].start;
1269 else if (cfi->chips[chipnum].start != last_end)
1270 break;
1271
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 if ((len + ofs -1) >> cfi->chipshift)
1273 thislen = (1<<cfi->chipshift) - ofs;
1274 else
1275 thislen = len;
1276
1277 ret = do_point_onechip(map, &cfi->chips[chipnum], ofs, thislen);
1278 if (ret)
1279 break;
1280
1281 *retlen += thislen;
1282 len -= thislen;
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001283
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 ofs = 0;
Andy Lowe097f2572007-01-12 18:05:10 -05001285 last_end += 1 << cfi->chipshift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 chipnum++;
1287 }
1288 return 0;
1289}
1290
1291static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
1292{
1293 struct map_info *map = mtd->priv;
1294 struct cfi_private *cfi = map->fldrv_priv;
1295 unsigned long ofs;
1296 int chipnum;
1297
1298 /* Now unlock the chip(s) POINT state */
1299
1300 /* ofs: offset within the first chip that the first read should start */
1301 chipnum = (from >> cfi->chipshift);
1302 ofs = from - (chipnum << cfi->chipshift);
1303
1304 while (len) {
1305 unsigned long thislen;
1306 struct flchip *chip;
1307
1308 chip = &cfi->chips[chipnum];
1309 if (chipnum >= cfi->numchips)
1310 break;
1311
1312 if ((len + ofs -1) >> cfi->chipshift)
1313 thislen = (1<<cfi->chipshift) - ofs;
1314 else
1315 thislen = len;
1316
1317 spin_lock(chip->mutex);
1318 if (chip->state == FL_POINT) {
1319 chip->ref_point_counter--;
1320 if(chip->ref_point_counter == 0)
1321 chip->state = FL_READY;
1322 } else
Nicolas Pitre48436532005-08-06 05:16:52 +01001323 printk(KERN_ERR "%s: Warning: unpoint called on non pointed region\n", map->name); /* Should this give an error? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
1325 put_chip(map, chip, chip->start);
1326 spin_unlock(chip->mutex);
1327
1328 len -= thislen;
1329 ofs = 0;
1330 chipnum++;
1331 }
1332}
1333
1334static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
1335{
1336 unsigned long cmd_addr;
1337 struct cfi_private *cfi = map->fldrv_priv;
1338 int ret;
1339
1340 adr += chip->start;
1341
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001342 /* Ensure cmd read/writes are aligned. */
1343 cmd_addr = adr & ~(map_bankwidth(map)-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344
1345 spin_lock(chip->mutex);
1346 ret = get_chip(map, chip, cmd_addr, FL_READY);
1347 if (ret) {
1348 spin_unlock(chip->mutex);
1349 return ret;
1350 }
1351
1352 if (chip->state != FL_POINT && chip->state != FL_READY) {
1353 map_write(map, CMD(0xff), cmd_addr);
1354
1355 chip->state = FL_READY;
1356 }
1357
1358 map_copy_from(map, buf, adr, len);
1359
1360 put_chip(map, chip, cmd_addr);
1361
1362 spin_unlock(chip->mutex);
1363 return 0;
1364}
1365
1366static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
1367{
1368 struct map_info *map = mtd->priv;
1369 struct cfi_private *cfi = map->fldrv_priv;
1370 unsigned long ofs;
1371 int chipnum;
1372 int ret = 0;
1373
1374 /* ofs: offset within the first chip that the first read should start */
1375 chipnum = (from >> cfi->chipshift);
1376 ofs = from - (chipnum << cfi->chipshift);
1377
1378 *retlen = 0;
1379
1380 while (len) {
1381 unsigned long thislen;
1382
1383 if (chipnum >= cfi->numchips)
1384 break;
1385
1386 if ((len + ofs -1) >> cfi->chipshift)
1387 thislen = (1<<cfi->chipshift) - ofs;
1388 else
1389 thislen = len;
1390
1391 ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
1392 if (ret)
1393 break;
1394
1395 *retlen += thislen;
1396 len -= thislen;
1397 buf += thislen;
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001398
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 ofs = 0;
1400 chipnum++;
1401 }
1402 return ret;
1403}
1404
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
Nicolas Pitref77814d2005-02-08 17:11:19 +00001406 unsigned long adr, map_word datum, int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407{
1408 struct cfi_private *cfi = map->fldrv_priv;
Nicolas Pitrec1724712006-03-30 15:52:41 +01001409 map_word status, write_cmd;
1410 int ret=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
1412 adr += chip->start;
1413
Nicolas Pitref77814d2005-02-08 17:11:19 +00001414 switch (mode) {
Nicolas Pitre638d9832005-08-06 05:40:46 +01001415 case FL_WRITING:
1416 write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41);
1417 break;
1418 case FL_OTP_WRITE:
1419 write_cmd = CMD(0xc0);
1420 break;
1421 default:
1422 return -EINVAL;
Nicolas Pitref77814d2005-02-08 17:11:19 +00001423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424
1425 spin_lock(chip->mutex);
Nicolas Pitref77814d2005-02-08 17:11:19 +00001426 ret = get_chip(map, chip, adr, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 if (ret) {
1428 spin_unlock(chip->mutex);
1429 return ret;
1430 }
1431
1432 XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
1433 ENABLE_VPP(map);
1434 xip_disable(map, chip, adr);
Nicolas Pitref77814d2005-02-08 17:11:19 +00001435 map_write(map, write_cmd, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 map_write(map, datum, adr);
Nicolas Pitref77814d2005-02-08 17:11:19 +00001437 chip->state = mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438
Nicolas Pitrec1724712006-03-30 15:52:41 +01001439 ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
1440 adr, map_bankwidth(map),
Alexey Korolev46a16522006-06-28 19:22:07 +01001441 chip->word_write_time);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001442 if (ret) {
1443 xip_enable(map, chip, adr);
1444 printk(KERN_ERR "%s: word write error (status timeout)\n", map->name);
1445 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447
Nicolas Pitre48436532005-08-06 05:16:52 +01001448 /* check for errors */
Nicolas Pitrec1724712006-03-30 15:52:41 +01001449 status = map_read(map, adr);
Nicolas Pitre48436532005-08-06 05:16:52 +01001450 if (map_word_bitsset(map, status, CMD(0x1a))) {
1451 unsigned long chipstatus = MERGESTATUS(status);
1452
1453 /* reset status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 map_write(map, CMD(0x50), adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 map_write(map, CMD(0x70), adr);
Nicolas Pitre48436532005-08-06 05:16:52 +01001456 xip_enable(map, chip, adr);
1457
1458 if (chipstatus & 0x02) {
1459 ret = -EROFS;
1460 } else if (chipstatus & 0x08) {
1461 printk(KERN_ERR "%s: word write error (bad VPP)\n", map->name);
1462 ret = -EIO;
1463 } else {
1464 printk(KERN_ERR "%s: word write error (status 0x%lx)\n", map->name, chipstatus);
1465 ret = -EINVAL;
1466 }
1467
1468 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 }
1470
1471 xip_enable(map, chip, adr);
1472 out: put_chip(map, chip, adr);
1473 spin_unlock(chip->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 return ret;
1475}
1476
1477
1478static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf)
1479{
1480 struct map_info *map = mtd->priv;
1481 struct cfi_private *cfi = map->fldrv_priv;
1482 int ret = 0;
1483 int chipnum;
1484 unsigned long ofs;
1485
1486 *retlen = 0;
1487 if (!len)
1488 return 0;
1489
1490 chipnum = to >> cfi->chipshift;
1491 ofs = to - (chipnum << cfi->chipshift);
1492
1493 /* If it's not bus-aligned, do the first byte write */
1494 if (ofs & (map_bankwidth(map)-1)) {
1495 unsigned long bus_ofs = ofs & ~(map_bankwidth(map)-1);
1496 int gap = ofs - bus_ofs;
1497 int n;
1498 map_word datum;
1499
1500 n = min_t(int, len, map_bankwidth(map)-gap);
1501 datum = map_word_ff(map);
1502 datum = map_word_load_partial(map, datum, buf, gap, n);
1503
1504 ret = do_write_oneword(map, &cfi->chips[chipnum],
Nicolas Pitref77814d2005-02-08 17:11:19 +00001505 bus_ofs, datum, FL_WRITING);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001506 if (ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 return ret;
1508
1509 len -= n;
1510 ofs += n;
1511 buf += n;
1512 (*retlen) += n;
1513
1514 if (ofs >> cfi->chipshift) {
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001515 chipnum ++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 ofs = 0;
1517 if (chipnum == cfi->numchips)
1518 return 0;
1519 }
1520 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001521
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 while(len >= map_bankwidth(map)) {
1523 map_word datum = map_word_load(map, buf);
1524
1525 ret = do_write_oneword(map, &cfi->chips[chipnum],
Nicolas Pitref77814d2005-02-08 17:11:19 +00001526 ofs, datum, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 if (ret)
1528 return ret;
1529
1530 ofs += map_bankwidth(map);
1531 buf += map_bankwidth(map);
1532 (*retlen) += map_bankwidth(map);
1533 len -= map_bankwidth(map);
1534
1535 if (ofs >> cfi->chipshift) {
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001536 chipnum ++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 ofs = 0;
1538 if (chipnum == cfi->numchips)
1539 return 0;
1540 }
1541 }
1542
1543 if (len & (map_bankwidth(map)-1)) {
1544 map_word datum;
1545
1546 datum = map_word_ff(map);
1547 datum = map_word_load_partial(map, datum, buf, 0, len);
1548
1549 ret = do_write_oneword(map, &cfi->chips[chipnum],
Nicolas Pitref77814d2005-02-08 17:11:19 +00001550 ofs, datum, FL_WRITING);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001551 if (ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 return ret;
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001553
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 (*retlen) += len;
1555 }
1556
1557 return 0;
1558}
1559
1560
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001561static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
Nicolas Pitree102d542005-08-06 05:46:59 +01001562 unsigned long adr, const struct kvec **pvec,
1563 unsigned long *pvec_seek, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564{
1565 struct cfi_private *cfi = map->fldrv_priv;
Nicolas Pitrec1724712006-03-30 15:52:41 +01001566 map_word status, write_cmd, datum;
1567 unsigned long cmd_adr;
1568 int ret, wbufsize, word_gap, words;
Nicolas Pitree102d542005-08-06 05:46:59 +01001569 const struct kvec *vec;
1570 unsigned long vec_seek;
Massimo Cirillo646fd122008-01-11 10:24:11 +00001571 unsigned long initial_adr;
1572 int initial_len = len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573
1574 wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
1575 adr += chip->start;
Massimo Cirillo646fd122008-01-11 10:24:11 +00001576 initial_adr = adr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 cmd_adr = adr & ~(wbufsize-1);
Nicolas Pitre638d9832005-08-06 05:40:46 +01001578
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 /* Let's determine this according to the interleave only once */
Nicolas Pitre638d9832005-08-06 05:40:46 +01001580 write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
1582 spin_lock(chip->mutex);
1583 ret = get_chip(map, chip, cmd_adr, FL_WRITING);
1584 if (ret) {
1585 spin_unlock(chip->mutex);
1586 return ret;
1587 }
1588
Massimo Cirillo646fd122008-01-11 10:24:11 +00001589 XIP_INVAL_CACHED_RANGE(map, initial_adr, initial_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 ENABLE_VPP(map);
1591 xip_disable(map, chip, cmd_adr);
1592
David Woodhouse151e7652006-05-14 01:51:54 +01001593 /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001594 [...], the device will not accept any more Write to Buffer commands".
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 So we must check here and reset those bits if they're set. Otherwise
1596 we're just pissing in the wind */
Nicolas Pitre6e7a6802006-03-29 23:31:42 +01001597 if (chip->state != FL_STATUS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 map_write(map, CMD(0x70), cmd_adr);
Nicolas Pitre6e7a6802006-03-29 23:31:42 +01001599 chip->state = FL_STATUS;
1600 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 status = map_read(map, cmd_adr);
1602 if (map_word_bitsset(map, status, CMD(0x30))) {
1603 xip_enable(map, chip, cmd_adr);
1604 printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %lx). Clearing.\n", status.x[0]);
1605 xip_disable(map, chip, cmd_adr);
1606 map_write(map, CMD(0x50), cmd_adr);
1607 map_write(map, CMD(0x70), cmd_adr);
1608 }
1609
1610 chip->state = FL_WRITING_TO_BUFFER;
Nicolas Pitrec1724712006-03-30 15:52:41 +01001611 map_write(map, write_cmd, cmd_adr);
1612 ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0);
1613 if (ret) {
1614 /* Argh. Not ready for write to buffer */
1615 map_word Xstatus = map_read(map, cmd_adr);
1616 map_write(map, CMD(0x70), cmd_adr);
1617 chip->state = FL_STATUS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 status = map_read(map, cmd_adr);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001619 map_write(map, CMD(0x50), cmd_adr);
1620 map_write(map, CMD(0x70), cmd_adr);
1621 xip_enable(map, chip, cmd_adr);
1622 printk(KERN_ERR "%s: Chip not ready for buffer write. Xstatus = %lx, status = %lx\n",
1623 map->name, Xstatus.x[0], status.x[0]);
1624 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 }
1626
Nicolas Pitree102d542005-08-06 05:46:59 +01001627 /* Figure out the number of words to write */
1628 word_gap = (-adr & (map_bankwidth(map)-1));
1629 words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map);
1630 if (!word_gap) {
1631 words--;
1632 } else {
1633 word_gap = map_bankwidth(map) - word_gap;
1634 adr -= word_gap;
1635 datum = map_word_ff(map);
1636 }
1637
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 /* Write length of data to come */
Nicolas Pitree102d542005-08-06 05:46:59 +01001639 map_write(map, CMD(words), cmd_adr );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
1641 /* Write data */
Nicolas Pitree102d542005-08-06 05:46:59 +01001642 vec = *pvec;
1643 vec_seek = *pvec_seek;
1644 do {
1645 int n = map_bankwidth(map) - word_gap;
1646 if (n > vec->iov_len - vec_seek)
1647 n = vec->iov_len - vec_seek;
1648 if (n > len)
1649 n = len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650
Nicolas Pitree102d542005-08-06 05:46:59 +01001651 if (!word_gap && len < map_bankwidth(map))
1652 datum = map_word_ff(map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
Nicolas Pitree102d542005-08-06 05:46:59 +01001654 datum = map_word_load_partial(map, datum,
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001655 vec->iov_base + vec_seek,
Nicolas Pitree102d542005-08-06 05:46:59 +01001656 word_gap, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657
Nicolas Pitree102d542005-08-06 05:46:59 +01001658 len -= n;
1659 word_gap += n;
1660 if (!len || word_gap == map_bankwidth(map)) {
1661 map_write(map, datum, adr);
1662 adr += map_bankwidth(map);
1663 word_gap = 0;
1664 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665
Nicolas Pitree102d542005-08-06 05:46:59 +01001666 vec_seek += n;
1667 if (vec_seek == vec->iov_len) {
1668 vec++;
1669 vec_seek = 0;
1670 }
1671 } while (len);
1672 *pvec = vec;
1673 *pvec_seek = vec_seek;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
1675 /* GO GO GO */
1676 map_write(map, CMD(0xd0), cmd_adr);
1677 chip->state = FL_WRITING;
1678
Nicolas Pitrec1724712006-03-30 15:52:41 +01001679 ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr,
Massimo Cirillo646fd122008-01-11 10:24:11 +00001680 initial_adr, initial_len,
Alexey Korolev46a16522006-06-28 19:22:07 +01001681 chip->buffer_write_time);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001682 if (ret) {
1683 map_write(map, CMD(0x70), cmd_adr);
1684 chip->state = FL_STATUS;
1685 xip_enable(map, chip, cmd_adr);
1686 printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name);
1687 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
Nicolas Pitre48436532005-08-06 05:16:52 +01001690 /* check for errors */
Nicolas Pitrec1724712006-03-30 15:52:41 +01001691 status = map_read(map, cmd_adr);
Nicolas Pitre48436532005-08-06 05:16:52 +01001692 if (map_word_bitsset(map, status, CMD(0x1a))) {
1693 unsigned long chipstatus = MERGESTATUS(status);
1694
1695 /* reset status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 map_write(map, CMD(0x50), cmd_adr);
Nicolas Pitre48436532005-08-06 05:16:52 +01001697 map_write(map, CMD(0x70), cmd_adr);
1698 xip_enable(map, chip, cmd_adr);
1699
1700 if (chipstatus & 0x02) {
1701 ret = -EROFS;
1702 } else if (chipstatus & 0x08) {
1703 printk(KERN_ERR "%s: buffer write error (bad VPP)\n", map->name);
1704 ret = -EIO;
1705 } else {
1706 printk(KERN_ERR "%s: buffer write error (status 0x%lx)\n", map->name, chipstatus);
1707 ret = -EINVAL;
1708 }
1709
1710 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 }
1712
1713 xip_enable(map, chip, cmd_adr);
1714 out: put_chip(map, chip, cmd_adr);
1715 spin_unlock(chip->mutex);
1716 return ret;
1717}
1718
Nicolas Pitree102d542005-08-06 05:46:59 +01001719static int cfi_intelext_writev (struct mtd_info *mtd, const struct kvec *vecs,
1720 unsigned long count, loff_t to, size_t *retlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721{
1722 struct map_info *map = mtd->priv;
1723 struct cfi_private *cfi = map->fldrv_priv;
1724 int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
1725 int ret = 0;
1726 int chipnum;
Nicolas Pitree102d542005-08-06 05:46:59 +01001727 unsigned long ofs, vec_seek, i;
1728 size_t len = 0;
1729
1730 for (i = 0; i < count; i++)
1731 len += vecs[i].iov_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732
1733 *retlen = 0;
1734 if (!len)
1735 return 0;
1736
1737 chipnum = to >> cfi->chipshift;
Nicolas Pitree102d542005-08-06 05:46:59 +01001738 ofs = to - (chipnum << cfi->chipshift);
1739 vec_seek = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740
Nicolas Pitree102d542005-08-06 05:46:59 +01001741 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 /* We must not cross write block boundaries */
1743 int size = wbufsize - (ofs & (wbufsize-1));
1744
1745 if (size > len)
1746 size = len;
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001747 ret = do_write_buffer(map, &cfi->chips[chipnum],
Nicolas Pitree102d542005-08-06 05:46:59 +01001748 ofs, &vecs, &vec_seek, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 if (ret)
1750 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751
1752 ofs += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 (*retlen) += size;
1754 len -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
1756 if (ofs >> cfi->chipshift) {
1757 chipnum ++;
1758 ofs = 0;
1759 if (chipnum == cfi->numchips)
1760 return 0;
1761 }
Josh Boyerdf54b52c2005-12-06 17:28:19 +00001762
1763 /* Be nice and reschedule with the chip in a usable state for other
1764 processes. */
1765 cond_resched();
1766
Nicolas Pitree102d542005-08-06 05:46:59 +01001767 } while (len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 return 0;
1770}
1771
Nicolas Pitree102d542005-08-06 05:46:59 +01001772static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to,
1773 size_t len, size_t *retlen, const u_char *buf)
1774{
1775 struct kvec vec;
1776
1777 vec.iov_base = (void *) buf;
1778 vec.iov_len = len;
1779
1780 return cfi_intelext_writev(mtd, &vec, 1, to, retlen);
1781}
1782
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
1784 unsigned long adr, int len, void *thunk)
1785{
1786 struct cfi_private *cfi = map->fldrv_priv;
Nicolas Pitrec1724712006-03-30 15:52:41 +01001787 map_word status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 int retries = 3;
Nicolas Pitrec1724712006-03-30 15:52:41 +01001789 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790
1791 adr += chip->start;
1792
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 retry:
1794 spin_lock(chip->mutex);
1795 ret = get_chip(map, chip, adr, FL_ERASING);
1796 if (ret) {
1797 spin_unlock(chip->mutex);
1798 return ret;
1799 }
1800
1801 XIP_INVAL_CACHED_RANGE(map, adr, len);
1802 ENABLE_VPP(map);
1803 xip_disable(map, chip, adr);
1804
1805 /* Clear the status register first */
1806 map_write(map, CMD(0x50), adr);
1807
1808 /* Now erase */
1809 map_write(map, CMD(0x20), adr);
1810 map_write(map, CMD(0xD0), adr);
1811 chip->state = FL_ERASING;
1812 chip->erase_suspended = 0;
1813
Nicolas Pitrec1724712006-03-30 15:52:41 +01001814 ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
1815 adr, len,
Alexey Korolev46a16522006-06-28 19:22:07 +01001816 chip->erase_time);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001817 if (ret) {
1818 map_write(map, CMD(0x70), adr);
1819 chip->state = FL_STATUS;
1820 xip_enable(map, chip, adr);
1821 printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name);
1822 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 }
1824
1825 /* We've broken this before. It doesn't hurt to be safe */
1826 map_write(map, CMD(0x70), adr);
1827 chip->state = FL_STATUS;
1828 status = map_read(map, adr);
1829
Nicolas Pitre48436532005-08-06 05:16:52 +01001830 /* check for errors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 if (map_word_bitsset(map, status, CMD(0x3a))) {
Nicolas Pitre48436532005-08-06 05:16:52 +01001832 unsigned long chipstatus = MERGESTATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833
1834 /* Reset the error bits */
1835 map_write(map, CMD(0x50), adr);
1836 map_write(map, CMD(0x70), adr);
1837 xip_enable(map, chip, adr);
1838
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 if ((chipstatus & 0x30) == 0x30) {
Nicolas Pitre48436532005-08-06 05:16:52 +01001840 printk(KERN_ERR "%s: block erase error: (bad command sequence, status 0x%lx)\n", map->name, chipstatus);
1841 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 } else if (chipstatus & 0x02) {
1843 /* Protection bit set */
1844 ret = -EROFS;
1845 } else if (chipstatus & 0x8) {
1846 /* Voltage */
Nicolas Pitre48436532005-08-06 05:16:52 +01001847 printk(KERN_ERR "%s: block erase error: (bad VPP)\n", map->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 ret = -EIO;
Nicolas Pitre48436532005-08-06 05:16:52 +01001849 } else if (chipstatus & 0x20 && retries--) {
1850 printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus);
Nicolas Pitre48436532005-08-06 05:16:52 +01001851 put_chip(map, chip, adr);
1852 spin_unlock(chip->mutex);
1853 goto retry;
1854 } else {
1855 printk(KERN_ERR "%s: block erase failed at 0x%08lx (status 0x%lx)\n", map->name, adr, chipstatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 ret = -EIO;
1857 }
Nicolas Pitre48436532005-08-06 05:16:52 +01001858
1859 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 }
1861
Nicolas Pitre48436532005-08-06 05:16:52 +01001862 xip_enable(map, chip, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 out: put_chip(map, chip, adr);
1864 spin_unlock(chip->mutex);
1865 return ret;
1866}
1867
Ben Dooks029a9eb2007-05-28 20:11:37 +01001868static int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869{
1870 unsigned long ofs, len;
1871 int ret;
1872
1873 ofs = instr->addr;
1874 len = instr->len;
1875
1876 ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL);
1877 if (ret)
1878 return ret;
1879
1880 instr->state = MTD_ERASE_DONE;
1881 mtd_erase_callback(instr);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001882
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 return 0;
1884}
1885
1886static void cfi_intelext_sync (struct mtd_info *mtd)
1887{
1888 struct map_info *map = mtd->priv;
1889 struct cfi_private *cfi = map->fldrv_priv;
1890 int i;
1891 struct flchip *chip;
1892 int ret = 0;
1893
1894 for (i=0; !ret && i<cfi->numchips; i++) {
1895 chip = &cfi->chips[i];
1896
1897 spin_lock(chip->mutex);
1898 ret = get_chip(map, chip, chip->start, FL_SYNCING);
1899
1900 if (!ret) {
1901 chip->oldstate = chip->state;
1902 chip->state = FL_SYNCING;
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001903 /* No need to wake_up() on this state change -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 * as the whole point is that nobody can do anything
1905 * with the chip now anyway.
1906 */
1907 }
1908 spin_unlock(chip->mutex);
1909 }
1910
1911 /* Unlock the chips again */
1912
1913 for (i--; i >=0; i--) {
1914 chip = &cfi->chips[i];
1915
1916 spin_lock(chip->mutex);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001917
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 if (chip->state == FL_SYNCING) {
1919 chip->state = chip->oldstate;
Nicolas Pitre09c79332005-03-16 22:41:09 +00001920 chip->oldstate = FL_READY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 wake_up(&chip->wq);
1922 }
1923 spin_unlock(chip->mutex);
1924 }
1925}
1926
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08001927static int __xipram do_getlockstatus_oneblock(struct map_info *map,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 struct flchip *chip,
1929 unsigned long adr,
1930 int len, void *thunk)
1931{
1932 struct cfi_private *cfi = map->fldrv_priv;
1933 int status, ofs_factor = cfi->interleave * cfi->device_type;
1934
Todd Poynorc25bb1f2005-04-27 21:01:52 +01001935 adr += chip->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 xip_disable(map, chip, adr+(2*ofs_factor));
Todd Poynorc25bb1f2005-04-27 21:01:52 +01001937 map_write(map, CMD(0x90), adr+(2*ofs_factor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 chip->state = FL_JEDEC_QUERY;
1939 status = cfi_read_query(map, adr+(2*ofs_factor));
1940 xip_enable(map, chip, 0);
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08001941 return status;
1942}
1943
1944#ifdef DEBUG_LOCK_BITS
1945static int __xipram do_printlockstatus_oneblock(struct map_info *map,
1946 struct flchip *chip,
1947 unsigned long adr,
1948 int len, void *thunk)
1949{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08001951 adr, do_getlockstatus_oneblock(map, chip, adr, len, thunk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 return 0;
1953}
1954#endif
1955
1956#define DO_XXLOCK_ONEBLOCK_LOCK ((void *) 1)
1957#define DO_XXLOCK_ONEBLOCK_UNLOCK ((void *) 2)
1958
1959static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip,
1960 unsigned long adr, int len, void *thunk)
1961{
1962 struct cfi_private *cfi = map->fldrv_priv;
Todd Poynor9a6e73e2005-03-29 23:06:40 +01001963 struct cfi_pri_intelext *extp = cfi->cmdset_priv;
Nicolas Pitrec1724712006-03-30 15:52:41 +01001964 int udelay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 int ret;
1966
1967 adr += chip->start;
1968
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 spin_lock(chip->mutex);
1970 ret = get_chip(map, chip, adr, FL_LOCKING);
1971 if (ret) {
1972 spin_unlock(chip->mutex);
1973 return ret;
1974 }
1975
1976 ENABLE_VPP(map);
1977 xip_disable(map, chip, adr);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001978
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 map_write(map, CMD(0x60), adr);
1980 if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) {
1981 map_write(map, CMD(0x01), adr);
1982 chip->state = FL_LOCKING;
1983 } else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) {
1984 map_write(map, CMD(0xD0), adr);
1985 chip->state = FL_UNLOCKING;
1986 } else
1987 BUG();
1988
Todd Poynor9a6e73e2005-03-29 23:06:40 +01001989 /*
1990 * If Instant Individual Block Locking supported then no need
1991 * to delay.
1992 */
Nicolas Pitrec1724712006-03-30 15:52:41 +01001993 udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0;
Todd Poynor9a6e73e2005-03-29 23:06:40 +01001994
Nicolas Pitrec1724712006-03-30 15:52:41 +01001995 ret = WAIT_TIMEOUT(map, chip, adr, udelay);
1996 if (ret) {
1997 map_write(map, CMD(0x70), adr);
1998 chip->state = FL_STATUS;
1999 xip_enable(map, chip, adr);
2000 printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name);
2001 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002003
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 xip_enable(map, chip, adr);
Nicolas Pitrec1724712006-03-30 15:52:41 +01002005out: put_chip(map, chip, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 spin_unlock(chip->mutex);
Nicolas Pitrec1724712006-03-30 15:52:41 +01002007 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008}
2009
2010static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
2011{
2012 int ret;
2013
2014#ifdef DEBUG_LOCK_BITS
2015 printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
Harvey Harrisoncb53b3b2008-04-18 13:44:19 -07002016 __func__, ofs, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
Randy Dunlap1da1caf2007-06-28 23:00:09 +01002018 ofs, len, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019#endif
2020
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002021 ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 ofs, len, DO_XXLOCK_ONEBLOCK_LOCK);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002023
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024#ifdef DEBUG_LOCK_BITS
2025 printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
Harvey Harrisoncb53b3b2008-04-18 13:44:19 -07002026 __func__, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
Randy Dunlap1da1caf2007-06-28 23:00:09 +01002028 ofs, len, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029#endif
2030
2031 return ret;
2032}
2033
2034static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
2035{
2036 int ret;
2037
2038#ifdef DEBUG_LOCK_BITS
2039 printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
Harvey Harrisoncb53b3b2008-04-18 13:44:19 -07002040 __func__, ofs, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
Randy Dunlap1da1caf2007-06-28 23:00:09 +01002042 ofs, len, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043#endif
2044
2045 ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
2046 ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002047
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048#ifdef DEBUG_LOCK_BITS
2049 printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
Harvey Harrisoncb53b3b2008-04-18 13:44:19 -07002050 __func__, ret);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002051 cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
Randy Dunlap1da1caf2007-06-28 23:00:09 +01002052 ofs, len, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053#endif
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002054
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 return ret;
2056}
2057
Nicolas Pitref77814d2005-02-08 17:11:19 +00002058#ifdef CONFIG_MTD_OTP
2059
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002060typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip,
Nicolas Pitref77814d2005-02-08 17:11:19 +00002061 u_long data_offset, u_char *buf, u_int size,
2062 u_long prot_offset, u_int groupno, u_int groupsize);
2063
2064static int __xipram
2065do_otp_read(struct map_info *map, struct flchip *chip, u_long offset,
2066 u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
2067{
2068 struct cfi_private *cfi = map->fldrv_priv;
2069 int ret;
2070
2071 spin_lock(chip->mutex);
2072 ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
2073 if (ret) {
2074 spin_unlock(chip->mutex);
2075 return ret;
2076 }
2077
2078 /* let's ensure we're not reading back cached data from array mode */
Nicolas Pitre6da70122005-05-19 18:05:47 +01002079 INVALIDATE_CACHED_RANGE(map, chip->start + offset, size);
Nicolas Pitref77814d2005-02-08 17:11:19 +00002080
2081 xip_disable(map, chip, chip->start);
2082 if (chip->state != FL_JEDEC_QUERY) {
2083 map_write(map, CMD(0x90), chip->start);
2084 chip->state = FL_JEDEC_QUERY;
2085 }
2086 map_copy_from(map, buf, chip->start + offset, size);
2087 xip_enable(map, chip, chip->start);
2088
2089 /* then ensure we don't keep OTP data in the cache */
Nicolas Pitre6da70122005-05-19 18:05:47 +01002090 INVALIDATE_CACHED_RANGE(map, chip->start + offset, size);
Nicolas Pitref77814d2005-02-08 17:11:19 +00002091
2092 put_chip(map, chip, chip->start);
2093 spin_unlock(chip->mutex);
2094 return 0;
2095}
2096
2097static int
2098do_otp_write(struct map_info *map, struct flchip *chip, u_long offset,
2099 u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
2100{
2101 int ret;
2102
2103 while (size) {
2104 unsigned long bus_ofs = offset & ~(map_bankwidth(map)-1);
2105 int gap = offset - bus_ofs;
2106 int n = min_t(int, size, map_bankwidth(map)-gap);
2107 map_word datum = map_word_ff(map);
2108
2109 datum = map_word_load_partial(map, datum, buf, gap, n);
2110 ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002111 if (ret)
Nicolas Pitref77814d2005-02-08 17:11:19 +00002112 return ret;
2113
2114 offset += n;
2115 buf += n;
2116 size -= n;
2117 }
2118
2119 return 0;
2120}
2121
2122static int
2123do_otp_lock(struct map_info *map, struct flchip *chip, u_long offset,
2124 u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
2125{
2126 struct cfi_private *cfi = map->fldrv_priv;
2127 map_word datum;
2128
2129 /* make sure area matches group boundaries */
Nicolas Pitre332d71f2005-02-17 20:35:04 +00002130 if (size != grpsz)
Nicolas Pitref77814d2005-02-08 17:11:19 +00002131 return -EXDEV;
2132
2133 datum = map_word_ff(map);
2134 datum = map_word_clr(map, datum, CMD(1 << grpno));
2135 return do_write_oneword(map, chip, prot, datum, FL_OTP_WRITE);
2136}
2137
2138static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
2139 size_t *retlen, u_char *buf,
2140 otp_op_t action, int user_regs)
2141{
2142 struct map_info *map = mtd->priv;
2143 struct cfi_private *cfi = map->fldrv_priv;
2144 struct cfi_pri_intelext *extp = cfi->cmdset_priv;
2145 struct flchip *chip;
2146 struct cfi_intelext_otpinfo *otp;
2147 u_long devsize, reg_prot_offset, data_offset;
2148 u_int chip_num, chip_step, field, reg_fact_size, reg_user_size;
2149 u_int groups, groupno, groupsize, reg_fact_groups, reg_user_groups;
2150 int ret;
2151
2152 *retlen = 0;
2153
2154 /* Check that we actually have some OTP registers */
2155 if (!extp || !(extp->FeatureSupport & 64) || !extp->NumProtectionFields)
2156 return -ENODATA;
2157
2158 /* we need real chips here not virtual ones */
2159 devsize = (1 << cfi->cfiq->DevSize) * cfi->interleave;
2160 chip_step = devsize >> cfi->chipshift;
Nicolas Pitredce2b4d2005-04-01 17:36:29 +01002161 chip_num = 0;
Nicolas Pitref77814d2005-02-08 17:11:19 +00002162
Nicolas Pitredce2b4d2005-04-01 17:36:29 +01002163 /* Some chips have OTP located in the _top_ partition only.
2164 For example: Intel 28F256L18T (T means top-parameter device) */
2165 if (cfi->mfr == MANUFACTURER_INTEL) {
2166 switch (cfi->id) {
2167 case 0x880b:
2168 case 0x880c:
2169 case 0x880d:
2170 chip_num = chip_step - 1;
2171 }
2172 }
2173
2174 for ( ; chip_num < cfi->numchips; chip_num += chip_step) {
Nicolas Pitref77814d2005-02-08 17:11:19 +00002175 chip = &cfi->chips[chip_num];
2176 otp = (struct cfi_intelext_otpinfo *)&extp->extra[0];
2177
2178 /* first OTP region */
2179 field = 0;
2180 reg_prot_offset = extp->ProtRegAddr;
2181 reg_fact_groups = 1;
2182 reg_fact_size = 1 << extp->FactProtRegSize;
2183 reg_user_groups = 1;
2184 reg_user_size = 1 << extp->UserProtRegSize;
2185
2186 while (len > 0) {
2187 /* flash geometry fixup */
2188 data_offset = reg_prot_offset + 1;
2189 data_offset *= cfi->interleave * cfi->device_type;
2190 reg_prot_offset *= cfi->interleave * cfi->device_type;
2191 reg_fact_size *= cfi->interleave;
2192 reg_user_size *= cfi->interleave;
2193
2194 if (user_regs) {
2195 groups = reg_user_groups;
2196 groupsize = reg_user_size;
2197 /* skip over factory reg area */
2198 groupno = reg_fact_groups;
2199 data_offset += reg_fact_groups * reg_fact_size;
2200 } else {
2201 groups = reg_fact_groups;
2202 groupsize = reg_fact_size;
2203 groupno = 0;
2204 }
2205
Nicolas Pitre332d71f2005-02-17 20:35:04 +00002206 while (len > 0 && groups > 0) {
Nicolas Pitref77814d2005-02-08 17:11:19 +00002207 if (!action) {
2208 /*
2209 * Special case: if action is NULL
2210 * we fill buf with otp_info records.
2211 */
2212 struct otp_info *otpinfo;
2213 map_word lockword;
2214 len -= sizeof(struct otp_info);
2215 if (len <= 0)
2216 return -ENOSPC;
2217 ret = do_otp_read(map, chip,
2218 reg_prot_offset,
2219 (u_char *)&lockword,
2220 map_bankwidth(map),
2221 0, 0, 0);
2222 if (ret)
2223 return ret;
2224 otpinfo = (struct otp_info *)buf;
2225 otpinfo->start = from;
2226 otpinfo->length = groupsize;
2227 otpinfo->locked =
2228 !map_word_bitsset(map, lockword,
2229 CMD(1 << groupno));
2230 from += groupsize;
2231 buf += sizeof(*otpinfo);
2232 *retlen += sizeof(*otpinfo);
2233 } else if (from >= groupsize) {
2234 from -= groupsize;
Nicolas Pitre332d71f2005-02-17 20:35:04 +00002235 data_offset += groupsize;
Nicolas Pitref77814d2005-02-08 17:11:19 +00002236 } else {
2237 int size = groupsize;
2238 data_offset += from;
2239 size -= from;
2240 from = 0;
2241 if (size > len)
2242 size = len;
2243 ret = action(map, chip, data_offset,
2244 buf, size, reg_prot_offset,
2245 groupno, groupsize);
2246 if (ret < 0)
2247 return ret;
2248 buf += size;
2249 len -= size;
2250 *retlen += size;
Nicolas Pitre332d71f2005-02-17 20:35:04 +00002251 data_offset += size;
Nicolas Pitref77814d2005-02-08 17:11:19 +00002252 }
2253 groupno++;
2254 groups--;
2255 }
2256
2257 /* next OTP region */
2258 if (++field == extp->NumProtectionFields)
2259 break;
2260 reg_prot_offset = otp->ProtRegAddr;
2261 reg_fact_groups = otp->FactGroups;
2262 reg_fact_size = 1 << otp->FactProtRegSize;
2263 reg_user_groups = otp->UserGroups;
2264 reg_user_size = 1 << otp->UserProtRegSize;
2265 otp++;
2266 }
2267 }
2268
2269 return 0;
2270}
2271
2272static int cfi_intelext_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
2273 size_t len, size_t *retlen,
2274 u_char *buf)
2275{
2276 return cfi_intelext_otp_walk(mtd, from, len, retlen,
2277 buf, do_otp_read, 0);
2278}
2279
2280static int cfi_intelext_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
2281 size_t len, size_t *retlen,
2282 u_char *buf)
2283{
2284 return cfi_intelext_otp_walk(mtd, from, len, retlen,
2285 buf, do_otp_read, 1);
2286}
2287
2288static int cfi_intelext_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
2289 size_t len, size_t *retlen,
2290 u_char *buf)
2291{
2292 return cfi_intelext_otp_walk(mtd, from, len, retlen,
2293 buf, do_otp_write, 1);
2294}
2295
2296static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd,
2297 loff_t from, size_t len)
2298{
2299 size_t retlen;
2300 return cfi_intelext_otp_walk(mtd, from, len, &retlen,
2301 NULL, do_otp_lock, 1);
2302}
2303
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002304static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd,
Nicolas Pitref77814d2005-02-08 17:11:19 +00002305 struct otp_info *buf, size_t len)
2306{
2307 size_t retlen;
2308 int ret;
2309
2310 ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0);
2311 return ret ? : retlen;
2312}
2313
2314static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd,
2315 struct otp_info *buf, size_t len)
2316{
2317 size_t retlen;
2318 int ret;
2319
2320 ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1);
2321 return ret ? : retlen;
2322}
2323
2324#endif
2325
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002326static void cfi_intelext_save_locks(struct mtd_info *mtd)
2327{
2328 struct mtd_erase_region_info *region;
2329 int block, status, i;
2330 unsigned long adr;
2331 size_t len;
2332
2333 for (i = 0; i < mtd->numeraseregions; i++) {
2334 region = &mtd->eraseregions[i];
2335 if (!region->lockmap)
2336 continue;
2337
2338 for (block = 0; block < region->numblocks; block++){
2339 len = region->erasesize;
2340 adr = region->offset + block * len;
2341
2342 status = cfi_varsize_frob(mtd,
Ben Dooks029a9eb2007-05-28 20:11:37 +01002343 do_getlockstatus_oneblock, adr, len, NULL);
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002344 if (status)
2345 set_bit(block, region->lockmap);
2346 else
2347 clear_bit(block, region->lockmap);
2348 }
2349 }
2350}
2351
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352static int cfi_intelext_suspend(struct mtd_info *mtd)
2353{
2354 struct map_info *map = mtd->priv;
2355 struct cfi_private *cfi = map->fldrv_priv;
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002356 struct cfi_pri_intelext *extp = cfi->cmdset_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 int i;
2358 struct flchip *chip;
2359 int ret = 0;
2360
Justin Treone619a752008-01-30 10:25:49 -08002361 if ((mtd->flags & MTD_POWERUP_LOCK)
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002362 && extp && (extp->FeatureSupport & (1 << 5)))
2363 cfi_intelext_save_locks(mtd);
2364
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 for (i=0; !ret && i<cfi->numchips; i++) {
2366 chip = &cfi->chips[i];
2367
2368 spin_lock(chip->mutex);
2369
2370 switch (chip->state) {
2371 case FL_READY:
2372 case FL_STATUS:
2373 case FL_CFI_QUERY:
2374 case FL_JEDEC_QUERY:
2375 if (chip->oldstate == FL_READY) {
David Andersa86aaa62006-10-19 19:33:19 +03002376 /* place the chip in a known state before suspend */
2377 map_write(map, CMD(0xFF), cfi->chips[i].start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 chip->oldstate = chip->state;
2379 chip->state = FL_PM_SUSPENDED;
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002380 /* No need to wake_up() on this state change -
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 * as the whole point is that nobody can do anything
2382 * with the chip now anyway.
2383 */
2384 } else {
2385 /* There seems to be an operation pending. We must wait for it. */
2386 printk(KERN_NOTICE "Flash device refused suspend due to pending operation (oldstate %d)\n", chip->oldstate);
2387 ret = -EAGAIN;
2388 }
2389 break;
2390 default:
2391 /* Should we actually wait? Once upon a time these routines weren't
2392 allowed to. Or should we return -EAGAIN, because the upper layers
2393 ought to have already shut down anything which was using the device
2394 anyway? The latter for now. */
2395 printk(KERN_NOTICE "Flash device refused suspend due to active operation (state %d)\n", chip->oldstate);
2396 ret = -EAGAIN;
2397 case FL_PM_SUSPENDED:
2398 break;
2399 }
2400 spin_unlock(chip->mutex);
2401 }
2402
2403 /* Unlock the chips again */
2404
2405 if (ret) {
2406 for (i--; i >=0; i--) {
2407 chip = &cfi->chips[i];
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002408
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 spin_lock(chip->mutex);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002410
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 if (chip->state == FL_PM_SUSPENDED) {
2412 /* No need to force it into a known state here,
2413 because we're returning failure, and it didn't
2414 get power cycled */
2415 chip->state = chip->oldstate;
2416 chip->oldstate = FL_READY;
2417 wake_up(&chip->wq);
2418 }
2419 spin_unlock(chip->mutex);
2420 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002421 }
2422
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 return ret;
2424}
2425
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002426static void cfi_intelext_restore_locks(struct mtd_info *mtd)
2427{
2428 struct mtd_erase_region_info *region;
2429 int block, i;
2430 unsigned long adr;
2431 size_t len;
2432
2433 for (i = 0; i < mtd->numeraseregions; i++) {
2434 region = &mtd->eraseregions[i];
2435 if (!region->lockmap)
2436 continue;
2437
2438 for (block = 0; block < region->numblocks; block++) {
2439 len = region->erasesize;
2440 adr = region->offset + block * len;
2441
2442 if (!test_bit(block, region->lockmap))
2443 cfi_intelext_unlock(mtd, adr, len);
2444 }
2445 }
2446}
2447
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448static void cfi_intelext_resume(struct mtd_info *mtd)
2449{
2450 struct map_info *map = mtd->priv;
2451 struct cfi_private *cfi = map->fldrv_priv;
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002452 struct cfi_pri_intelext *extp = cfi->cmdset_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 int i;
2454 struct flchip *chip;
2455
2456 for (i=0; i<cfi->numchips; i++) {
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002457
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 chip = &cfi->chips[i];
2459
2460 spin_lock(chip->mutex);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002461
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 /* Go to known state. Chip may have been power cycled */
2463 if (chip->state == FL_PM_SUSPENDED) {
2464 map_write(map, CMD(0xFF), cfi->chips[i].start);
2465 chip->oldstate = chip->state = FL_READY;
2466 wake_up(&chip->wq);
2467 }
2468
2469 spin_unlock(chip->mutex);
2470 }
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002471
Justin Treone619a752008-01-30 10:25:49 -08002472 if ((mtd->flags & MTD_POWERUP_LOCK)
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002473 && extp && (extp->FeatureSupport & (1 << 5)))
2474 cfi_intelext_restore_locks(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475}
2476
Nicolas Pitre963a6fb2005-04-01 02:59:56 +01002477static int cfi_intelext_reset(struct mtd_info *mtd)
2478{
2479 struct map_info *map = mtd->priv;
2480 struct cfi_private *cfi = map->fldrv_priv;
2481 int i, ret;
2482
2483 for (i=0; i < cfi->numchips; i++) {
2484 struct flchip *chip = &cfi->chips[i];
2485
2486 /* force the completion of any ongoing operation
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002487 and switch to array mode so any bootloader in
Nicolas Pitre963a6fb2005-04-01 02:59:56 +01002488 flash is accessible for soft reboot. */
2489 spin_lock(chip->mutex);
Kevin Haoc4a9f882007-10-02 13:56:04 -07002490 ret = get_chip(map, chip, chip->start, FL_SHUTDOWN);
Nicolas Pitre963a6fb2005-04-01 02:59:56 +01002491 if (!ret) {
2492 map_write(map, CMD(0xff), chip->start);
Kevin Haoc4a9f882007-10-02 13:56:04 -07002493 chip->state = FL_SHUTDOWN;
Nicolas Pitre963a6fb2005-04-01 02:59:56 +01002494 }
2495 spin_unlock(chip->mutex);
2496 }
2497
2498 return 0;
2499}
2500
2501static int cfi_intelext_reboot(struct notifier_block *nb, unsigned long val,
2502 void *v)
2503{
2504 struct mtd_info *mtd;
2505
2506 mtd = container_of(nb, struct mtd_info, reboot_notifier);
2507 cfi_intelext_reset(mtd);
2508 return NOTIFY_DONE;
2509}
2510
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511static void cfi_intelext_destroy(struct mtd_info *mtd)
2512{
2513 struct map_info *map = mtd->priv;
2514 struct cfi_private *cfi = map->fldrv_priv;
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002515 struct mtd_erase_region_info *region;
2516 int i;
Nicolas Pitre963a6fb2005-04-01 02:59:56 +01002517 cfi_intelext_reset(mtd);
2518 unregister_reboot_notifier(&mtd->reboot_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 kfree(cfi->cmdset_priv);
2520 kfree(cfi->cfiq);
2521 kfree(cfi->chips[0].priv);
2522 kfree(cfi);
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002523 for (i = 0; i < mtd->numeraseregions; i++) {
2524 region = &mtd->eraseregions[i];
2525 if (region->lockmap)
2526 kfree(region->lockmap);
2527 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 kfree(mtd->eraseregions);
2529}
2530
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531MODULE_LICENSE("GPL");
2532MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");
2533MODULE_DESCRIPTION("MTD chip driver for Intel/Sharp flash chips");
David Woodhousea15bdee2006-05-08 22:35:05 +01002534MODULE_ALIAS("cfi_cmdset_0003");
2535MODULE_ALIAS("cfi_cmdset_0200");