blob: e812df607a5c9aef596e96c4800881cb2df15967 [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
Thomas Kunzefe224662008-04-23 01:40:52 +0200622 if (!numparts)
623 numparts = 1;
624
Nicolas Pitre638d9832005-08-06 05:40:46 +0100625 /* Programming Region info */
626 if (extp->MinorVersion >= '4') {
627 struct cfi_intelext_programming_regioninfo *prinfo;
628 prinfo = (struct cfi_intelext_programming_regioninfo *)&extp->extra[offs];
Joern Engel28318772006-05-22 23:18:05 +0200629 mtd->writesize = cfi->interleave << prinfo->ProgRegShift;
Joern Engel5fa43392006-05-22 23:18:29 +0200630 mtd->flags &= ~MTD_BIT_WRITEABLE;
Nicolas Pitre638d9832005-08-06 05:40:46 +0100631 printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n",
Joern Engel28318772006-05-22 23:18:05 +0200632 map->name, mtd->writesize,
Artem Bityutskiyd4160852007-01-30 10:45:55 +0200633 cfi->interleave * prinfo->ControlValid,
634 cfi->interleave * prinfo->ControlInvalid);
Nicolas Pitre638d9832005-08-06 05:40:46 +0100635 }
636
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 /*
638 * All functions below currently rely on all chips having
639 * the same geometry so we'll just assume that all hardware
640 * partitions are of the same size too.
641 */
642 partshift = cfi->chipshift - __ffs(numparts);
643
644 if ((1 << partshift) < mtd->erasesize) {
645 printk( KERN_ERR
646 "%s: bad number of hw partitions (%d)\n",
Harvey Harrisoncb53b3b2008-04-18 13:44:19 -0700647 __func__, numparts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 return -EINVAL;
649 }
650
651 numvirtchips = cfi->numchips * numparts;
652 newcfi = kmalloc(sizeof(struct cfi_private) + numvirtchips * sizeof(struct flchip), GFP_KERNEL);
653 if (!newcfi)
654 return -ENOMEM;
655 shared = kmalloc(sizeof(struct flchip_shared) * cfi->numchips, GFP_KERNEL);
656 if (!shared) {
657 kfree(newcfi);
658 return -ENOMEM;
659 }
660 memcpy(newcfi, cfi, sizeof(struct cfi_private));
661 newcfi->numchips = numvirtchips;
662 newcfi->chipshift = partshift;
663
664 chip = &newcfi->chips[0];
665 for (i = 0; i < cfi->numchips; i++) {
666 shared[i].writing = shared[i].erasing = NULL;
667 spin_lock_init(&shared[i].lock);
668 for (j = 0; j < numparts; j++) {
669 *chip = cfi->chips[i];
670 chip->start += j << partshift;
671 chip->priv = &shared[i];
672 /* those should be reset too since
673 they create memory references. */
674 init_waitqueue_head(&chip->wq);
675 spin_lock_init(&chip->_spinlock);
676 chip->mutex = &chip->_spinlock;
677 chip++;
678 }
679 }
680
681 printk(KERN_DEBUG "%s: %d set(s) of %d interleaved chips "
682 "--> %d partitions of %d KiB\n",
683 map->name, cfi->numchips, cfi->interleave,
684 newcfi->numchips, 1<<(newcfi->chipshift-10));
685
686 map->fldrv_priv = newcfi;
687 *pcfi = newcfi;
688 kfree(cfi);
689 }
690
691 return 0;
692}
693
694/*
695 * *********** CHIP ACCESS FUNCTIONS ***********
696 */
Alexey Korolev5a37cf12007-10-22 17:55:20 +0100697static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698{
699 DECLARE_WAITQUEUE(wait, current);
700 struct cfi_private *cfi = map->fldrv_priv;
701 map_word status, status_OK = CMD(0x80), status_PWS = CMD(0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
Alexey Korolev5a37cf12007-10-22 17:55:20 +0100703 unsigned long timeo = jiffies + HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
705 switch (chip->state) {
706
707 case FL_STATUS:
708 for (;;) {
709 status = map_read(map, adr);
710 if (map_word_andequal(map, status, status_OK, status_OK))
711 break;
712
713 /* At this point we're fine with write operations
714 in other partitions as they don't conflict. */
715 if (chip->priv && map_word_andequal(map, status, status_PWS, status_PWS))
716 break;
717
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 spin_unlock(chip->mutex);
719 cfi_udelay(1);
720 spin_lock(chip->mutex);
721 /* Someone else might have been playing with it. */
Alexey Korolev5a37cf12007-10-22 17:55:20 +0100722 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 }
Alexey Korolevfb6d0802008-04-04 14:30:01 -0700724 /* Fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 case FL_READY:
726 case FL_CFI_QUERY:
727 case FL_JEDEC_QUERY:
728 return 0;
729
730 case FL_ERASING:
731 if (!cfip ||
732 !(cfip->FeatureSupport & 2) ||
733 !(mode == FL_READY || mode == FL_POINT ||
734 (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1))))
735 goto sleep;
736
737
738 /* Erase suspend */
739 map_write(map, CMD(0xB0), adr);
740
741 /* If the flash has finished erasing, then 'erase suspend'
742 * appears to make some (28F320) flash devices switch to
743 * 'read' mode. Make sure that we switch to 'read status'
744 * mode so we get the right data. --rmk
745 */
746 map_write(map, CMD(0x70), adr);
747 chip->oldstate = FL_ERASING;
748 chip->state = FL_ERASE_SUSPENDING;
749 chip->erase_suspended = 1;
750 for (;;) {
751 status = map_read(map, adr);
752 if (map_word_andequal(map, status, status_OK, status_OK))
753 break;
754
755 if (time_after(jiffies, timeo)) {
756 /* Urgh. Resume and pretend we weren't here. */
757 map_write(map, CMD(0xd0), adr);
758 /* Make sure we're in 'read status' mode if it had finished */
759 map_write(map, CMD(0x70), adr);
760 chip->state = FL_ERASING;
761 chip->oldstate = FL_READY;
Nicolas Pitre48436532005-08-06 05:16:52 +0100762 printk(KERN_ERR "%s: Chip not ready after erase "
763 "suspended: status = 0x%lx\n", map->name, status.x[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 return -EIO;
765 }
766
767 spin_unlock(chip->mutex);
768 cfi_udelay(1);
769 spin_lock(chip->mutex);
770 /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
771 So we can just loop here. */
772 }
773 chip->state = FL_STATUS;
774 return 0;
775
776 case FL_XIP_WHILE_ERASING:
777 if (mode != FL_READY && mode != FL_POINT &&
778 (mode != FL_WRITING || !cfip || !(cfip->SuspendCmdSupport&1)))
779 goto sleep;
780 chip->oldstate = chip->state;
781 chip->state = FL_READY;
782 return 0;
783
Alexey Korolevfb6d0802008-04-04 14:30:01 -0700784 case FL_SHUTDOWN:
785 /* The machine is rebooting now,so no one can get chip anymore */
786 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 case FL_POINT:
788 /* Only if there's no operation suspended... */
789 if (mode == FL_READY && chip->oldstate == FL_READY)
790 return 0;
Alexey Korolevfb6d0802008-04-04 14:30:01 -0700791 /* Fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 default:
793 sleep:
794 set_current_state(TASK_UNINTERRUPTIBLE);
795 add_wait_queue(&chip->wq, &wait);
796 spin_unlock(chip->mutex);
797 schedule();
798 remove_wait_queue(&chip->wq, &wait);
799 spin_lock(chip->mutex);
Alexey Korolev5a37cf12007-10-22 17:55:20 +0100800 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 }
802}
803
Alexey Korolev5a37cf12007-10-22 17:55:20 +0100804static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
805{
806 int ret;
Alexander Belyakov6c24e412007-11-07 11:58:07 +0300807 DECLARE_WAITQUEUE(wait, current);
Alexey Korolev5a37cf12007-10-22 17:55:20 +0100808
809 retry:
810 if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING
811 || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) {
812 /*
813 * OK. We have possibility for contention on the write/erase
814 * operations which are global to the real chip and not per
815 * partition. So let's fight it over in the partition which
816 * currently has authority on the operation.
817 *
818 * The rules are as follows:
819 *
820 * - any write operation must own shared->writing.
821 *
822 * - any erase operation must own _both_ shared->writing and
823 * shared->erasing.
824 *
825 * - contention arbitration is handled in the owner's context.
826 *
827 * The 'shared' struct can be read and/or written only when
828 * its lock is taken.
829 */
830 struct flchip_shared *shared = chip->priv;
831 struct flchip *contender;
832 spin_lock(&shared->lock);
833 contender = shared->writing;
834 if (contender && contender != chip) {
835 /*
836 * The engine to perform desired operation on this
837 * partition is already in use by someone else.
838 * Let's fight over it in the context of the chip
839 * currently using it. If it is possible to suspend,
840 * that other partition will do just that, otherwise
841 * it'll happily send us to sleep. In any case, when
842 * get_chip returns success we're clear to go ahead.
843 */
844 ret = spin_trylock(contender->mutex);
845 spin_unlock(&shared->lock);
846 if (!ret)
847 goto retry;
848 spin_unlock(chip->mutex);
849 ret = chip_ready(map, contender, contender->start, mode);
850 spin_lock(chip->mutex);
851
852 if (ret == -EAGAIN) {
853 spin_unlock(contender->mutex);
854 goto retry;
855 }
856 if (ret) {
857 spin_unlock(contender->mutex);
858 return ret;
859 }
860 spin_lock(&shared->lock);
861 spin_unlock(contender->mutex);
862 }
863
Alexander Belyakov6c24e412007-11-07 11:58:07 +0300864 /* Check if we already have suspended erase
865 * on this chip. Sleep. */
866 if (mode == FL_ERASING && shared->erasing
867 && shared->erasing->oldstate == FL_ERASING) {
868 spin_unlock(&shared->lock);
869 set_current_state(TASK_UNINTERRUPTIBLE);
870 add_wait_queue(&chip->wq, &wait);
871 spin_unlock(chip->mutex);
872 schedule();
873 remove_wait_queue(&chip->wq, &wait);
874 spin_lock(chip->mutex);
875 goto retry;
876 }
877
Alexey Korolev5a37cf12007-10-22 17:55:20 +0100878 /* We now own it */
879 shared->writing = chip;
880 if (mode == FL_ERASING)
881 shared->erasing = chip;
882 spin_unlock(&shared->lock);
883 }
884 ret = chip_ready(map, chip, adr, mode);
885 if (ret == -EAGAIN)
886 goto retry;
887
888 return ret;
889}
890
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr)
892{
893 struct cfi_private *cfi = map->fldrv_priv;
894
895 if (chip->priv) {
896 struct flchip_shared *shared = chip->priv;
897 spin_lock(&shared->lock);
898 if (shared->writing == chip && chip->oldstate == FL_READY) {
899 /* We own the ability to write, but we're done */
900 shared->writing = shared->erasing;
901 if (shared->writing && shared->writing != chip) {
902 /* give back ownership to who we loaned it from */
903 struct flchip *loaner = shared->writing;
904 spin_lock(loaner->mutex);
905 spin_unlock(&shared->lock);
906 spin_unlock(chip->mutex);
907 put_chip(map, loaner, loaner->start);
908 spin_lock(chip->mutex);
909 spin_unlock(loaner->mutex);
910 wake_up(&chip->wq);
911 return;
912 }
913 shared->erasing = NULL;
914 shared->writing = NULL;
915 } else if (shared->erasing == chip && shared->writing != chip) {
916 /*
917 * We own the ability to erase without the ability
918 * to write, which means the erase was suspended
919 * and some other partition is currently writing.
920 * Don't let the switch below mess things up since
921 * we don't have ownership to resume anything.
922 */
923 spin_unlock(&shared->lock);
924 wake_up(&chip->wq);
925 return;
926 }
927 spin_unlock(&shared->lock);
928 }
929
930 switch(chip->oldstate) {
931 case FL_ERASING:
932 chip->state = chip->oldstate;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000933 /* What if one interleaved chip has finished and the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 other hasn't? The old code would leave the finished
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000935 one in READY mode. That's bad, and caused -EROFS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 errors to be returned from do_erase_oneblock because
937 that's the only bit it checked for at the time.
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000938 As the state machine appears to explicitly allow
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 sending the 0x70 (Read Status) command to an erasing
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000940 chip and expecting it to be ignored, that's what we
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 do. */
942 map_write(map, CMD(0xd0), adr);
943 map_write(map, CMD(0x70), adr);
944 chip->oldstate = FL_READY;
945 chip->state = FL_ERASING;
946 break;
947
948 case FL_XIP_WHILE_ERASING:
949 chip->state = chip->oldstate;
950 chip->oldstate = FL_READY;
951 break;
952
953 case FL_READY:
954 case FL_STATUS:
955 case FL_JEDEC_QUERY:
956 /* We should really make set_vpp() count, rather than doing this */
957 DISABLE_VPP(map);
958 break;
959 default:
Nicolas Pitre48436532005-08-06 05:16:52 +0100960 printk(KERN_ERR "%s: put_chip() called with oldstate %d!!\n", map->name, chip->oldstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 }
962 wake_up(&chip->wq);
963}
964
965#ifdef CONFIG_MTD_XIP
966
967/*
968 * No interrupt what so ever can be serviced while the flash isn't in array
969 * mode. This is ensured by the xip_disable() and xip_enable() functions
970 * enclosing any code path where the flash is known not to be in array mode.
971 * And within a XIP disabled code path, only functions marked with __xipram
972 * may be called and nothing else (it's a good thing to inspect generated
973 * assembly to make sure inline functions were actually inlined and that gcc
974 * didn't emit calls to its own support functions). Also configuring MTD CFI
975 * support to a single buswidth and a single interleave is also recommended.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 */
977
978static void xip_disable(struct map_info *map, struct flchip *chip,
979 unsigned long adr)
980{
981 /* TODO: chips with no XIP use should ignore and return */
982 (void) map_read(map, adr); /* ensure mmu mapping is up to date */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 local_irq_disable();
984}
985
986static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
987 unsigned long adr)
988{
989 struct cfi_private *cfi = map->fldrv_priv;
990 if (chip->state != FL_POINT && chip->state != FL_READY) {
991 map_write(map, CMD(0xff), adr);
992 chip->state = FL_READY;
993 }
994 (void) map_read(map, adr);
Thomas Gleixner97f927a2005-07-07 16:50:16 +0200995 xip_iprefetch();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 local_irq_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997}
998
999/*
1000 * When a delay is required for the flash operation to complete, the
Nicolas Pitrec1724712006-03-30 15:52:41 +01001001 * xip_wait_for_operation() function is polling for both the given timeout
1002 * and pending (but still masked) hardware interrupts. Whenever there is an
1003 * interrupt pending then the flash erase or write operation is suspended,
1004 * array mode restored and interrupts unmasked. Task scheduling might also
1005 * happen at that point. The CPU eventually returns from the interrupt or
1006 * the call to schedule() and the suspended flash operation is resumed for
1007 * the remaining of the delay period.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 *
1009 * Warning: this function _will_ fool interrupt latency tracing tools.
1010 */
1011
Nicolas Pitrec1724712006-03-30 15:52:41 +01001012static int __xipram xip_wait_for_operation(
1013 struct map_info *map, struct flchip *chip,
Alexey Korolev46a16522006-06-28 19:22:07 +01001014 unsigned long adr, unsigned int chip_op_time )
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015{
1016 struct cfi_private *cfi = map->fldrv_priv;
1017 struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
1018 map_word status, OK = CMD(0x80);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001019 unsigned long usec, suspended, start, done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 flstate_t oldstate, newstate;
1021
Nicolas Pitrec1724712006-03-30 15:52:41 +01001022 start = xip_currtime();
Alexey Korolev46a16522006-06-28 19:22:07 +01001023 usec = chip_op_time * 8;
Nicolas Pitrec1724712006-03-30 15:52:41 +01001024 if (usec == 0)
1025 usec = 500000;
1026 done = 0;
1027
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 do {
1029 cpu_relax();
1030 if (xip_irqpending() && cfip &&
1031 ((chip->state == FL_ERASING && (cfip->FeatureSupport&2)) ||
1032 (chip->state == FL_WRITING && (cfip->FeatureSupport&4))) &&
1033 (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) {
1034 /*
1035 * Let's suspend the erase or write operation when
1036 * supported. Note that we currently don't try to
1037 * suspend interleaved chips if there is already
1038 * another operation suspended (imagine what happens
1039 * when one chip was already done with the current
1040 * operation while another chip suspended it, then
1041 * we resume the whole thing at once). Yes, it
1042 * can happen!
1043 */
Nicolas Pitrec1724712006-03-30 15:52:41 +01001044 usec -= done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 map_write(map, CMD(0xb0), adr);
1046 map_write(map, CMD(0x70), adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 suspended = xip_currtime();
1048 do {
1049 if (xip_elapsed_since(suspended) > 100000) {
1050 /*
1051 * The chip doesn't want to suspend
1052 * after waiting for 100 msecs.
1053 * This is a critical error but there
1054 * is not much we can do here.
1055 */
Nicolas Pitrec1724712006-03-30 15:52:41 +01001056 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 }
1058 status = map_read(map, adr);
1059 } while (!map_word_andequal(map, status, OK, OK));
1060
1061 /* Suspend succeeded */
1062 oldstate = chip->state;
1063 if (oldstate == FL_ERASING) {
1064 if (!map_word_bitsset(map, status, CMD(0x40)))
1065 break;
1066 newstate = FL_XIP_WHILE_ERASING;
1067 chip->erase_suspended = 1;
1068 } else {
1069 if (!map_word_bitsset(map, status, CMD(0x04)))
1070 break;
1071 newstate = FL_XIP_WHILE_WRITING;
1072 chip->write_suspended = 1;
1073 }
1074 chip->state = newstate;
1075 map_write(map, CMD(0xff), adr);
1076 (void) map_read(map, adr);
Paulius Zaleckasca5c23c2008-02-27 01:42:39 +02001077 xip_iprefetch();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 local_irq_enable();
Nicolas Pitre6da70122005-05-19 18:05:47 +01001079 spin_unlock(chip->mutex);
Paulius Zaleckasca5c23c2008-02-27 01:42:39 +02001080 xip_iprefetch();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 cond_resched();
1082
1083 /*
1084 * We're back. However someone else might have
1085 * decided to go write to the chip if we are in
1086 * a suspended erase state. If so let's wait
1087 * until it's done.
1088 */
Nicolas Pitre6da70122005-05-19 18:05:47 +01001089 spin_lock(chip->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 while (chip->state != newstate) {
1091 DECLARE_WAITQUEUE(wait, current);
1092 set_current_state(TASK_UNINTERRUPTIBLE);
1093 add_wait_queue(&chip->wq, &wait);
Nicolas Pitre6da70122005-05-19 18:05:47 +01001094 spin_unlock(chip->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 schedule();
1096 remove_wait_queue(&chip->wq, &wait);
Nicolas Pitre6da70122005-05-19 18:05:47 +01001097 spin_lock(chip->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 }
1099 /* Disallow XIP again */
1100 local_irq_disable();
1101
1102 /* Resume the write or erase operation */
1103 map_write(map, CMD(0xd0), adr);
1104 map_write(map, CMD(0x70), adr);
1105 chip->state = oldstate;
1106 start = xip_currtime();
1107 } else if (usec >= 1000000/HZ) {
1108 /*
1109 * Try to save on CPU power when waiting delay
1110 * is at least a system timer tick period.
1111 * No need to be extremely accurate here.
1112 */
1113 xip_cpu_idle();
1114 }
1115 status = map_read(map, adr);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001116 done = xip_elapsed_since(start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 } while (!map_word_andequal(map, status, OK, OK)
Nicolas Pitrec1724712006-03-30 15:52:41 +01001118 && done < usec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
Nicolas Pitrec1724712006-03-30 15:52:41 +01001120 return (done >= usec) ? -ETIME : 0;
1121}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122
1123/*
1124 * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
1125 * the flash is actively programming or erasing since we have to poll for
1126 * the operation to complete anyway. We can't do that in a generic way with
Nicolas Pitre6da70122005-05-19 18:05:47 +01001127 * a XIP setup so do it before the actual flash operation in this case
Nicolas Pitrec1724712006-03-30 15:52:41 +01001128 * and stub it out from INVAL_CACHE_AND_WAIT.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 */
Nicolas Pitre6da70122005-05-19 18:05:47 +01001130#define XIP_INVAL_CACHED_RANGE(map, from, size) \
1131 INVALIDATE_CACHED_RANGE(map, from, size)
1132
Alexey Korolev46a16522006-06-28 19:22:07 +01001133#define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, usec) \
1134 xip_wait_for_operation(map, chip, cmd_adr, usec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
1136#else
1137
1138#define xip_disable(map, chip, adr)
1139#define xip_enable(map, chip, adr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140#define XIP_INVAL_CACHED_RANGE(x...)
Nicolas Pitrec1724712006-03-30 15:52:41 +01001141#define INVAL_CACHE_AND_WAIT inval_cache_and_wait_for_operation
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
Nicolas Pitrec1724712006-03-30 15:52:41 +01001143static int inval_cache_and_wait_for_operation(
1144 struct map_info *map, struct flchip *chip,
1145 unsigned long cmd_adr, unsigned long inval_adr, int inval_len,
Alexey Korolev46a16522006-06-28 19:22:07 +01001146 unsigned int chip_op_time)
Nicolas Pitrec1724712006-03-30 15:52:41 +01001147{
1148 struct cfi_private *cfi = map->fldrv_priv;
1149 map_word status, status_OK = CMD(0x80);
Alexey Korolev46a16522006-06-28 19:22:07 +01001150 int chip_state = chip->state;
1151 unsigned int timeo, sleep_time;
Nicolas Pitre6da70122005-05-19 18:05:47 +01001152
Nicolas Pitrec1724712006-03-30 15:52:41 +01001153 spin_unlock(chip->mutex);
1154 if (inval_len)
1155 INVALIDATE_CACHED_RANGE(map, inval_adr, inval_len);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001156 spin_lock(chip->mutex);
1157
Alexey Korolev46a16522006-06-28 19:22:07 +01001158 /* set our timeout to 8 times the expected delay */
1159 timeo = chip_op_time * 8;
1160 if (!timeo)
1161 timeo = 500000;
1162 sleep_time = chip_op_time / 2;
Nicolas Pitrec1724712006-03-30 15:52:41 +01001163
Nicolas Pitrec1724712006-03-30 15:52:41 +01001164 for (;;) {
Nicolas Pitrec1724712006-03-30 15:52:41 +01001165 status = map_read(map, cmd_adr);
1166 if (map_word_andequal(map, status, status_OK, status_OK))
1167 break;
1168
Alexey Korolev46a16522006-06-28 19:22:07 +01001169 if (!timeo) {
Nicolas Pitrec1724712006-03-30 15:52:41 +01001170 map_write(map, CMD(0x70), cmd_adr);
1171 chip->state = FL_STATUS;
1172 return -ETIME;
1173 }
1174
Alexey Korolev46a16522006-06-28 19:22:07 +01001175 /* OK Still waiting. Drop the lock, wait a while and retry. */
Nicolas Pitrec1724712006-03-30 15:52:41 +01001176 spin_unlock(chip->mutex);
Alexey Korolev46a16522006-06-28 19:22:07 +01001177 if (sleep_time >= 1000000/HZ) {
1178 /*
1179 * Half of the normal delay still remaining
1180 * can be performed with a sleeping delay instead
1181 * of busy waiting.
1182 */
1183 msleep(sleep_time/1000);
1184 timeo -= sleep_time;
1185 sleep_time = 1000000/HZ;
1186 } else {
1187 udelay(1);
1188 cond_resched();
1189 timeo--;
1190 }
Nicolas Pitrec1724712006-03-30 15:52:41 +01001191 spin_lock(chip->mutex);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001192
Joakim Tjernlund967bf622006-11-28 23:11:52 +00001193 while (chip->state != chip_state) {
Alexey Korolev46a16522006-06-28 19:22:07 +01001194 /* Someone's suspended the operation: sleep */
1195 DECLARE_WAITQUEUE(wait, current);
1196 set_current_state(TASK_UNINTERRUPTIBLE);
1197 add_wait_queue(&chip->wq, &wait);
1198 spin_unlock(chip->mutex);
1199 schedule();
1200 remove_wait_queue(&chip->wq, &wait);
1201 spin_lock(chip->mutex);
1202 }
1203 }
Nicolas Pitrec1724712006-03-30 15:52:41 +01001204
1205 /* Done and happy. */
1206 chip->state = FL_STATUS;
1207 return 0;
1208}
Nicolas Pitre6da70122005-05-19 18:05:47 +01001209
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210#endif
1211
Nicolas Pitrec1724712006-03-30 15:52:41 +01001212#define WAIT_TIMEOUT(map, chip, adr, udelay) \
Alexey Korolev46a16522006-06-28 19:22:07 +01001213 INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, udelay);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001214
1215
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
1217{
1218 unsigned long cmd_addr;
1219 struct cfi_private *cfi = map->fldrv_priv;
1220 int ret = 0;
1221
1222 adr += chip->start;
1223
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001224 /* Ensure cmd read/writes are aligned. */
1225 cmd_addr = adr & ~(map_bankwidth(map)-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
1227 spin_lock(chip->mutex);
1228
1229 ret = get_chip(map, chip, cmd_addr, FL_POINT);
1230
1231 if (!ret) {
1232 if (chip->state != FL_POINT && chip->state != FL_READY)
1233 map_write(map, CMD(0xff), cmd_addr);
1234
1235 chip->state = FL_POINT;
1236 chip->ref_point_counter++;
1237 }
1238 spin_unlock(chip->mutex);
1239
1240 return ret;
1241}
1242
1243static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
1244{
1245 struct map_info *map = mtd->priv;
1246 struct cfi_private *cfi = map->fldrv_priv;
Andy Lowe097f2572007-01-12 18:05:10 -05001247 unsigned long ofs, last_end = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 int chipnum;
1249 int ret = 0;
1250
1251 if (!map->virt || (from + len > mtd->size))
1252 return -EINVAL;
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001253
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 /* Now lock the chip(s) to POINT state */
1255
1256 /* ofs: offset within the first chip that the first read should start */
1257 chipnum = (from >> cfi->chipshift);
1258 ofs = from - (chipnum << cfi->chipshift);
1259
Andy Lowe097f2572007-01-12 18:05:10 -05001260 *mtdbuf = (void *)map->virt + cfi->chips[chipnum].start + ofs;
1261 *retlen = 0;
1262
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 while (len) {
1264 unsigned long thislen;
1265
1266 if (chipnum >= cfi->numchips)
1267 break;
1268
Andy Lowe097f2572007-01-12 18:05:10 -05001269 /* We cannot point across chips that are virtually disjoint */
1270 if (!last_end)
1271 last_end = cfi->chips[chipnum].start;
1272 else if (cfi->chips[chipnum].start != last_end)
1273 break;
1274
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 if ((len + ofs -1) >> cfi->chipshift)
1276 thislen = (1<<cfi->chipshift) - ofs;
1277 else
1278 thislen = len;
1279
1280 ret = do_point_onechip(map, &cfi->chips[chipnum], ofs, thislen);
1281 if (ret)
1282 break;
1283
1284 *retlen += thislen;
1285 len -= thislen;
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001286
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 ofs = 0;
Andy Lowe097f2572007-01-12 18:05:10 -05001288 last_end += 1 << cfi->chipshift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 chipnum++;
1290 }
1291 return 0;
1292}
1293
1294static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
1295{
1296 struct map_info *map = mtd->priv;
1297 struct cfi_private *cfi = map->fldrv_priv;
1298 unsigned long ofs;
1299 int chipnum;
1300
1301 /* Now unlock the chip(s) POINT state */
1302
1303 /* ofs: offset within the first chip that the first read should start */
1304 chipnum = (from >> cfi->chipshift);
1305 ofs = from - (chipnum << cfi->chipshift);
1306
1307 while (len) {
1308 unsigned long thislen;
1309 struct flchip *chip;
1310
1311 chip = &cfi->chips[chipnum];
1312 if (chipnum >= cfi->numchips)
1313 break;
1314
1315 if ((len + ofs -1) >> cfi->chipshift)
1316 thislen = (1<<cfi->chipshift) - ofs;
1317 else
1318 thislen = len;
1319
1320 spin_lock(chip->mutex);
1321 if (chip->state == FL_POINT) {
1322 chip->ref_point_counter--;
1323 if(chip->ref_point_counter == 0)
1324 chip->state = FL_READY;
1325 } else
Nicolas Pitre48436532005-08-06 05:16:52 +01001326 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 -07001327
1328 put_chip(map, chip, chip->start);
1329 spin_unlock(chip->mutex);
1330
1331 len -= thislen;
1332 ofs = 0;
1333 chipnum++;
1334 }
1335}
1336
1337static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
1338{
1339 unsigned long cmd_addr;
1340 struct cfi_private *cfi = map->fldrv_priv;
1341 int ret;
1342
1343 adr += chip->start;
1344
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001345 /* Ensure cmd read/writes are aligned. */
1346 cmd_addr = adr & ~(map_bankwidth(map)-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
1348 spin_lock(chip->mutex);
1349 ret = get_chip(map, chip, cmd_addr, FL_READY);
1350 if (ret) {
1351 spin_unlock(chip->mutex);
1352 return ret;
1353 }
1354
1355 if (chip->state != FL_POINT && chip->state != FL_READY) {
1356 map_write(map, CMD(0xff), cmd_addr);
1357
1358 chip->state = FL_READY;
1359 }
1360
1361 map_copy_from(map, buf, adr, len);
1362
1363 put_chip(map, chip, cmd_addr);
1364
1365 spin_unlock(chip->mutex);
1366 return 0;
1367}
1368
1369static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
1370{
1371 struct map_info *map = mtd->priv;
1372 struct cfi_private *cfi = map->fldrv_priv;
1373 unsigned long ofs;
1374 int chipnum;
1375 int ret = 0;
1376
1377 /* ofs: offset within the first chip that the first read should start */
1378 chipnum = (from >> cfi->chipshift);
1379 ofs = from - (chipnum << cfi->chipshift);
1380
1381 *retlen = 0;
1382
1383 while (len) {
1384 unsigned long thislen;
1385
1386 if (chipnum >= cfi->numchips)
1387 break;
1388
1389 if ((len + ofs -1) >> cfi->chipshift)
1390 thislen = (1<<cfi->chipshift) - ofs;
1391 else
1392 thislen = len;
1393
1394 ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
1395 if (ret)
1396 break;
1397
1398 *retlen += thislen;
1399 len -= thislen;
1400 buf += thislen;
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001401
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 ofs = 0;
1403 chipnum++;
1404 }
1405 return ret;
1406}
1407
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
Nicolas Pitref77814d2005-02-08 17:11:19 +00001409 unsigned long adr, map_word datum, int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410{
1411 struct cfi_private *cfi = map->fldrv_priv;
Nicolas Pitrec1724712006-03-30 15:52:41 +01001412 map_word status, write_cmd;
1413 int ret=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414
1415 adr += chip->start;
1416
Nicolas Pitref77814d2005-02-08 17:11:19 +00001417 switch (mode) {
Nicolas Pitre638d9832005-08-06 05:40:46 +01001418 case FL_WRITING:
1419 write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41);
1420 break;
1421 case FL_OTP_WRITE:
1422 write_cmd = CMD(0xc0);
1423 break;
1424 default:
1425 return -EINVAL;
Nicolas Pitref77814d2005-02-08 17:11:19 +00001426 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
1428 spin_lock(chip->mutex);
Nicolas Pitref77814d2005-02-08 17:11:19 +00001429 ret = get_chip(map, chip, adr, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 if (ret) {
1431 spin_unlock(chip->mutex);
1432 return ret;
1433 }
1434
1435 XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
1436 ENABLE_VPP(map);
1437 xip_disable(map, chip, adr);
Nicolas Pitref77814d2005-02-08 17:11:19 +00001438 map_write(map, write_cmd, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 map_write(map, datum, adr);
Nicolas Pitref77814d2005-02-08 17:11:19 +00001440 chip->state = mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441
Nicolas Pitrec1724712006-03-30 15:52:41 +01001442 ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
1443 adr, map_bankwidth(map),
Alexey Korolev46a16522006-06-28 19:22:07 +01001444 chip->word_write_time);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001445 if (ret) {
1446 xip_enable(map, chip, adr);
1447 printk(KERN_ERR "%s: word write error (status timeout)\n", map->name);
1448 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450
Nicolas Pitre48436532005-08-06 05:16:52 +01001451 /* check for errors */
Nicolas Pitrec1724712006-03-30 15:52:41 +01001452 status = map_read(map, adr);
Nicolas Pitre48436532005-08-06 05:16:52 +01001453 if (map_word_bitsset(map, status, CMD(0x1a))) {
1454 unsigned long chipstatus = MERGESTATUS(status);
1455
1456 /* reset status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 map_write(map, CMD(0x50), adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 map_write(map, CMD(0x70), adr);
Nicolas Pitre48436532005-08-06 05:16:52 +01001459 xip_enable(map, chip, adr);
1460
1461 if (chipstatus & 0x02) {
1462 ret = -EROFS;
1463 } else if (chipstatus & 0x08) {
1464 printk(KERN_ERR "%s: word write error (bad VPP)\n", map->name);
1465 ret = -EIO;
1466 } else {
1467 printk(KERN_ERR "%s: word write error (status 0x%lx)\n", map->name, chipstatus);
1468 ret = -EINVAL;
1469 }
1470
1471 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 }
1473
1474 xip_enable(map, chip, adr);
1475 out: put_chip(map, chip, adr);
1476 spin_unlock(chip->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 return ret;
1478}
1479
1480
1481static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf)
1482{
1483 struct map_info *map = mtd->priv;
1484 struct cfi_private *cfi = map->fldrv_priv;
1485 int ret = 0;
1486 int chipnum;
1487 unsigned long ofs;
1488
1489 *retlen = 0;
1490 if (!len)
1491 return 0;
1492
1493 chipnum = to >> cfi->chipshift;
1494 ofs = to - (chipnum << cfi->chipshift);
1495
1496 /* If it's not bus-aligned, do the first byte write */
1497 if (ofs & (map_bankwidth(map)-1)) {
1498 unsigned long bus_ofs = ofs & ~(map_bankwidth(map)-1);
1499 int gap = ofs - bus_ofs;
1500 int n;
1501 map_word datum;
1502
1503 n = min_t(int, len, map_bankwidth(map)-gap);
1504 datum = map_word_ff(map);
1505 datum = map_word_load_partial(map, datum, buf, gap, n);
1506
1507 ret = do_write_oneword(map, &cfi->chips[chipnum],
Nicolas Pitref77814d2005-02-08 17:11:19 +00001508 bus_ofs, datum, FL_WRITING);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001509 if (ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 return ret;
1511
1512 len -= n;
1513 ofs += n;
1514 buf += n;
1515 (*retlen) += n;
1516
1517 if (ofs >> cfi->chipshift) {
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001518 chipnum ++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 ofs = 0;
1520 if (chipnum == cfi->numchips)
1521 return 0;
1522 }
1523 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001524
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 while(len >= map_bankwidth(map)) {
1526 map_word datum = map_word_load(map, buf);
1527
1528 ret = do_write_oneword(map, &cfi->chips[chipnum],
Nicolas Pitref77814d2005-02-08 17:11:19 +00001529 ofs, datum, FL_WRITING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 if (ret)
1531 return ret;
1532
1533 ofs += map_bankwidth(map);
1534 buf += map_bankwidth(map);
1535 (*retlen) += map_bankwidth(map);
1536 len -= map_bankwidth(map);
1537
1538 if (ofs >> cfi->chipshift) {
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001539 chipnum ++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 ofs = 0;
1541 if (chipnum == cfi->numchips)
1542 return 0;
1543 }
1544 }
1545
1546 if (len & (map_bankwidth(map)-1)) {
1547 map_word datum;
1548
1549 datum = map_word_ff(map);
1550 datum = map_word_load_partial(map, datum, buf, 0, len);
1551
1552 ret = do_write_oneword(map, &cfi->chips[chipnum],
Nicolas Pitref77814d2005-02-08 17:11:19 +00001553 ofs, datum, FL_WRITING);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001554 if (ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 return ret;
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001556
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 (*retlen) += len;
1558 }
1559
1560 return 0;
1561}
1562
1563
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001564static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
Nicolas Pitree102d542005-08-06 05:46:59 +01001565 unsigned long adr, const struct kvec **pvec,
1566 unsigned long *pvec_seek, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567{
1568 struct cfi_private *cfi = map->fldrv_priv;
Nicolas Pitrec1724712006-03-30 15:52:41 +01001569 map_word status, write_cmd, datum;
1570 unsigned long cmd_adr;
1571 int ret, wbufsize, word_gap, words;
Nicolas Pitree102d542005-08-06 05:46:59 +01001572 const struct kvec *vec;
1573 unsigned long vec_seek;
Massimo Cirillo646fd122008-01-11 10:24:11 +00001574 unsigned long initial_adr;
1575 int initial_len = len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576
1577 wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
1578 adr += chip->start;
Massimo Cirillo646fd122008-01-11 10:24:11 +00001579 initial_adr = adr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 cmd_adr = adr & ~(wbufsize-1);
Nicolas Pitre638d9832005-08-06 05:40:46 +01001581
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 /* Let's determine this according to the interleave only once */
Nicolas Pitre638d9832005-08-06 05:40:46 +01001583 write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
1585 spin_lock(chip->mutex);
1586 ret = get_chip(map, chip, cmd_adr, FL_WRITING);
1587 if (ret) {
1588 spin_unlock(chip->mutex);
1589 return ret;
1590 }
1591
Massimo Cirillo646fd122008-01-11 10:24:11 +00001592 XIP_INVAL_CACHED_RANGE(map, initial_adr, initial_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 ENABLE_VPP(map);
1594 xip_disable(map, chip, cmd_adr);
1595
David Woodhouse151e7652006-05-14 01:51:54 +01001596 /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001597 [...], the device will not accept any more Write to Buffer commands".
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 So we must check here and reset those bits if they're set. Otherwise
1599 we're just pissing in the wind */
Nicolas Pitre6e7a6802006-03-29 23:31:42 +01001600 if (chip->state != FL_STATUS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 map_write(map, CMD(0x70), cmd_adr);
Nicolas Pitre6e7a6802006-03-29 23:31:42 +01001602 chip->state = FL_STATUS;
1603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 status = map_read(map, cmd_adr);
1605 if (map_word_bitsset(map, status, CMD(0x30))) {
1606 xip_enable(map, chip, cmd_adr);
1607 printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %lx). Clearing.\n", status.x[0]);
1608 xip_disable(map, chip, cmd_adr);
1609 map_write(map, CMD(0x50), cmd_adr);
1610 map_write(map, CMD(0x70), cmd_adr);
1611 }
1612
1613 chip->state = FL_WRITING_TO_BUFFER;
Nicolas Pitrec1724712006-03-30 15:52:41 +01001614 map_write(map, write_cmd, cmd_adr);
1615 ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0);
1616 if (ret) {
1617 /* Argh. Not ready for write to buffer */
1618 map_word Xstatus = map_read(map, cmd_adr);
1619 map_write(map, CMD(0x70), cmd_adr);
1620 chip->state = FL_STATUS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 status = map_read(map, cmd_adr);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001622 map_write(map, CMD(0x50), cmd_adr);
1623 map_write(map, CMD(0x70), cmd_adr);
1624 xip_enable(map, chip, cmd_adr);
1625 printk(KERN_ERR "%s: Chip not ready for buffer write. Xstatus = %lx, status = %lx\n",
1626 map->name, Xstatus.x[0], status.x[0]);
1627 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 }
1629
Nicolas Pitree102d542005-08-06 05:46:59 +01001630 /* Figure out the number of words to write */
1631 word_gap = (-adr & (map_bankwidth(map)-1));
1632 words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map);
1633 if (!word_gap) {
1634 words--;
1635 } else {
1636 word_gap = map_bankwidth(map) - word_gap;
1637 adr -= word_gap;
1638 datum = map_word_ff(map);
1639 }
1640
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 /* Write length of data to come */
Nicolas Pitree102d542005-08-06 05:46:59 +01001642 map_write(map, CMD(words), cmd_adr );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
1644 /* Write data */
Nicolas Pitree102d542005-08-06 05:46:59 +01001645 vec = *pvec;
1646 vec_seek = *pvec_seek;
1647 do {
1648 int n = map_bankwidth(map) - word_gap;
1649 if (n > vec->iov_len - vec_seek)
1650 n = vec->iov_len - vec_seek;
1651 if (n > len)
1652 n = len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
Nicolas Pitree102d542005-08-06 05:46:59 +01001654 if (!word_gap && len < map_bankwidth(map))
1655 datum = map_word_ff(map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656
Nicolas Pitree102d542005-08-06 05:46:59 +01001657 datum = map_word_load_partial(map, datum,
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001658 vec->iov_base + vec_seek,
Nicolas Pitree102d542005-08-06 05:46:59 +01001659 word_gap, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
Nicolas Pitree102d542005-08-06 05:46:59 +01001661 len -= n;
1662 word_gap += n;
1663 if (!len || word_gap == map_bankwidth(map)) {
1664 map_write(map, datum, adr);
1665 adr += map_bankwidth(map);
1666 word_gap = 0;
1667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668
Nicolas Pitree102d542005-08-06 05:46:59 +01001669 vec_seek += n;
1670 if (vec_seek == vec->iov_len) {
1671 vec++;
1672 vec_seek = 0;
1673 }
1674 } while (len);
1675 *pvec = vec;
1676 *pvec_seek = vec_seek;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
1678 /* GO GO GO */
1679 map_write(map, CMD(0xd0), cmd_adr);
1680 chip->state = FL_WRITING;
1681
Nicolas Pitrec1724712006-03-30 15:52:41 +01001682 ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr,
Massimo Cirillo646fd122008-01-11 10:24:11 +00001683 initial_adr, initial_len,
Alexey Korolev46a16522006-06-28 19:22:07 +01001684 chip->buffer_write_time);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001685 if (ret) {
1686 map_write(map, CMD(0x70), cmd_adr);
1687 chip->state = FL_STATUS;
1688 xip_enable(map, chip, cmd_adr);
1689 printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name);
1690 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
Nicolas Pitre48436532005-08-06 05:16:52 +01001693 /* check for errors */
Nicolas Pitrec1724712006-03-30 15:52:41 +01001694 status = map_read(map, cmd_adr);
Nicolas Pitre48436532005-08-06 05:16:52 +01001695 if (map_word_bitsset(map, status, CMD(0x1a))) {
1696 unsigned long chipstatus = MERGESTATUS(status);
1697
1698 /* reset status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 map_write(map, CMD(0x50), cmd_adr);
Nicolas Pitre48436532005-08-06 05:16:52 +01001700 map_write(map, CMD(0x70), cmd_adr);
1701 xip_enable(map, chip, cmd_adr);
1702
1703 if (chipstatus & 0x02) {
1704 ret = -EROFS;
1705 } else if (chipstatus & 0x08) {
1706 printk(KERN_ERR "%s: buffer write error (bad VPP)\n", map->name);
1707 ret = -EIO;
1708 } else {
1709 printk(KERN_ERR "%s: buffer write error (status 0x%lx)\n", map->name, chipstatus);
1710 ret = -EINVAL;
1711 }
1712
1713 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 }
1715
1716 xip_enable(map, chip, cmd_adr);
1717 out: put_chip(map, chip, cmd_adr);
1718 spin_unlock(chip->mutex);
1719 return ret;
1720}
1721
Nicolas Pitree102d542005-08-06 05:46:59 +01001722static int cfi_intelext_writev (struct mtd_info *mtd, const struct kvec *vecs,
1723 unsigned long count, loff_t to, size_t *retlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724{
1725 struct map_info *map = mtd->priv;
1726 struct cfi_private *cfi = map->fldrv_priv;
1727 int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
1728 int ret = 0;
1729 int chipnum;
Nicolas Pitree102d542005-08-06 05:46:59 +01001730 unsigned long ofs, vec_seek, i;
1731 size_t len = 0;
1732
1733 for (i = 0; i < count; i++)
1734 len += vecs[i].iov_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735
1736 *retlen = 0;
1737 if (!len)
1738 return 0;
1739
1740 chipnum = to >> cfi->chipshift;
Nicolas Pitree102d542005-08-06 05:46:59 +01001741 ofs = to - (chipnum << cfi->chipshift);
1742 vec_seek = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743
Nicolas Pitree102d542005-08-06 05:46:59 +01001744 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 /* We must not cross write block boundaries */
1746 int size = wbufsize - (ofs & (wbufsize-1));
1747
1748 if (size > len)
1749 size = len;
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001750 ret = do_write_buffer(map, &cfi->chips[chipnum],
Nicolas Pitree102d542005-08-06 05:46:59 +01001751 ofs, &vecs, &vec_seek, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 if (ret)
1753 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754
1755 ofs += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 (*retlen) += size;
1757 len -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758
1759 if (ofs >> cfi->chipshift) {
1760 chipnum ++;
1761 ofs = 0;
1762 if (chipnum == cfi->numchips)
1763 return 0;
1764 }
Josh Boyerdf54b52c2005-12-06 17:28:19 +00001765
1766 /* Be nice and reschedule with the chip in a usable state for other
1767 processes. */
1768 cond_resched();
1769
Nicolas Pitree102d542005-08-06 05:46:59 +01001770 } while (len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 return 0;
1773}
1774
Nicolas Pitree102d542005-08-06 05:46:59 +01001775static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to,
1776 size_t len, size_t *retlen, const u_char *buf)
1777{
1778 struct kvec vec;
1779
1780 vec.iov_base = (void *) buf;
1781 vec.iov_len = len;
1782
1783 return cfi_intelext_writev(mtd, &vec, 1, to, retlen);
1784}
1785
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
1787 unsigned long adr, int len, void *thunk)
1788{
1789 struct cfi_private *cfi = map->fldrv_priv;
Nicolas Pitrec1724712006-03-30 15:52:41 +01001790 map_word status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 int retries = 3;
Nicolas Pitrec1724712006-03-30 15:52:41 +01001792 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793
1794 adr += chip->start;
1795
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 retry:
1797 spin_lock(chip->mutex);
1798 ret = get_chip(map, chip, adr, FL_ERASING);
1799 if (ret) {
1800 spin_unlock(chip->mutex);
1801 return ret;
1802 }
1803
1804 XIP_INVAL_CACHED_RANGE(map, adr, len);
1805 ENABLE_VPP(map);
1806 xip_disable(map, chip, adr);
1807
1808 /* Clear the status register first */
1809 map_write(map, CMD(0x50), adr);
1810
1811 /* Now erase */
1812 map_write(map, CMD(0x20), adr);
1813 map_write(map, CMD(0xD0), adr);
1814 chip->state = FL_ERASING;
1815 chip->erase_suspended = 0;
1816
Nicolas Pitrec1724712006-03-30 15:52:41 +01001817 ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
1818 adr, len,
Alexey Korolev46a16522006-06-28 19:22:07 +01001819 chip->erase_time);
Nicolas Pitrec1724712006-03-30 15:52:41 +01001820 if (ret) {
1821 map_write(map, CMD(0x70), adr);
1822 chip->state = FL_STATUS;
1823 xip_enable(map, chip, adr);
1824 printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name);
1825 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 }
1827
1828 /* We've broken this before. It doesn't hurt to be safe */
1829 map_write(map, CMD(0x70), adr);
1830 chip->state = FL_STATUS;
1831 status = map_read(map, adr);
1832
Nicolas Pitre48436532005-08-06 05:16:52 +01001833 /* check for errors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 if (map_word_bitsset(map, status, CMD(0x3a))) {
Nicolas Pitre48436532005-08-06 05:16:52 +01001835 unsigned long chipstatus = MERGESTATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836
1837 /* Reset the error bits */
1838 map_write(map, CMD(0x50), adr);
1839 map_write(map, CMD(0x70), adr);
1840 xip_enable(map, chip, adr);
1841
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 if ((chipstatus & 0x30) == 0x30) {
Nicolas Pitre48436532005-08-06 05:16:52 +01001843 printk(KERN_ERR "%s: block erase error: (bad command sequence, status 0x%lx)\n", map->name, chipstatus);
1844 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 } else if (chipstatus & 0x02) {
1846 /* Protection bit set */
1847 ret = -EROFS;
1848 } else if (chipstatus & 0x8) {
1849 /* Voltage */
Nicolas Pitre48436532005-08-06 05:16:52 +01001850 printk(KERN_ERR "%s: block erase error: (bad VPP)\n", map->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 ret = -EIO;
Nicolas Pitre48436532005-08-06 05:16:52 +01001852 } else if (chipstatus & 0x20 && retries--) {
1853 printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus);
Nicolas Pitre48436532005-08-06 05:16:52 +01001854 put_chip(map, chip, adr);
1855 spin_unlock(chip->mutex);
1856 goto retry;
1857 } else {
1858 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 -07001859 ret = -EIO;
1860 }
Nicolas Pitre48436532005-08-06 05:16:52 +01001861
1862 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 }
1864
Nicolas Pitre48436532005-08-06 05:16:52 +01001865 xip_enable(map, chip, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 out: put_chip(map, chip, adr);
1867 spin_unlock(chip->mutex);
1868 return ret;
1869}
1870
Ben Dooks029a9eb2007-05-28 20:11:37 +01001871static int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872{
1873 unsigned long ofs, len;
1874 int ret;
1875
1876 ofs = instr->addr;
1877 len = instr->len;
1878
1879 ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL);
1880 if (ret)
1881 return ret;
1882
1883 instr->state = MTD_ERASE_DONE;
1884 mtd_erase_callback(instr);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001885
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 return 0;
1887}
1888
1889static void cfi_intelext_sync (struct mtd_info *mtd)
1890{
1891 struct map_info *map = mtd->priv;
1892 struct cfi_private *cfi = map->fldrv_priv;
1893 int i;
1894 struct flchip *chip;
1895 int ret = 0;
1896
1897 for (i=0; !ret && i<cfi->numchips; i++) {
1898 chip = &cfi->chips[i];
1899
1900 spin_lock(chip->mutex);
1901 ret = get_chip(map, chip, chip->start, FL_SYNCING);
1902
1903 if (!ret) {
1904 chip->oldstate = chip->state;
1905 chip->state = FL_SYNCING;
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001906 /* No need to wake_up() on this state change -
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 * as the whole point is that nobody can do anything
1908 * with the chip now anyway.
1909 */
1910 }
1911 spin_unlock(chip->mutex);
1912 }
1913
1914 /* Unlock the chips again */
1915
1916 for (i--; i >=0; i--) {
1917 chip = &cfi->chips[i];
1918
1919 spin_lock(chip->mutex);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001920
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 if (chip->state == FL_SYNCING) {
1922 chip->state = chip->oldstate;
Nicolas Pitre09c79332005-03-16 22:41:09 +00001923 chip->oldstate = FL_READY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 wake_up(&chip->wq);
1925 }
1926 spin_unlock(chip->mutex);
1927 }
1928}
1929
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08001930static int __xipram do_getlockstatus_oneblock(struct map_info *map,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 struct flchip *chip,
1932 unsigned long adr,
1933 int len, void *thunk)
1934{
1935 struct cfi_private *cfi = map->fldrv_priv;
1936 int status, ofs_factor = cfi->interleave * cfi->device_type;
1937
Todd Poynorc25bb1f2005-04-27 21:01:52 +01001938 adr += chip->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 xip_disable(map, chip, adr+(2*ofs_factor));
Todd Poynorc25bb1f2005-04-27 21:01:52 +01001940 map_write(map, CMD(0x90), adr+(2*ofs_factor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 chip->state = FL_JEDEC_QUERY;
1942 status = cfi_read_query(map, adr+(2*ofs_factor));
1943 xip_enable(map, chip, 0);
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08001944 return status;
1945}
1946
1947#ifdef DEBUG_LOCK_BITS
1948static int __xipram do_printlockstatus_oneblock(struct map_info *map,
1949 struct flchip *chip,
1950 unsigned long adr,
1951 int len, void *thunk)
1952{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08001954 adr, do_getlockstatus_oneblock(map, chip, adr, len, thunk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 return 0;
1956}
1957#endif
1958
1959#define DO_XXLOCK_ONEBLOCK_LOCK ((void *) 1)
1960#define DO_XXLOCK_ONEBLOCK_UNLOCK ((void *) 2)
1961
1962static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip,
1963 unsigned long adr, int len, void *thunk)
1964{
1965 struct cfi_private *cfi = map->fldrv_priv;
Todd Poynor9a6e73e2005-03-29 23:06:40 +01001966 struct cfi_pri_intelext *extp = cfi->cmdset_priv;
Nicolas Pitrec1724712006-03-30 15:52:41 +01001967 int udelay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 int ret;
1969
1970 adr += chip->start;
1971
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 spin_lock(chip->mutex);
1973 ret = get_chip(map, chip, adr, FL_LOCKING);
1974 if (ret) {
1975 spin_unlock(chip->mutex);
1976 return ret;
1977 }
1978
1979 ENABLE_VPP(map);
1980 xip_disable(map, chip, adr);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00001981
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 map_write(map, CMD(0x60), adr);
1983 if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) {
1984 map_write(map, CMD(0x01), adr);
1985 chip->state = FL_LOCKING;
1986 } else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) {
1987 map_write(map, CMD(0xD0), adr);
1988 chip->state = FL_UNLOCKING;
1989 } else
1990 BUG();
1991
Todd Poynor9a6e73e2005-03-29 23:06:40 +01001992 /*
1993 * If Instant Individual Block Locking supported then no need
1994 * to delay.
1995 */
Nicolas Pitrec1724712006-03-30 15:52:41 +01001996 udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0;
Todd Poynor9a6e73e2005-03-29 23:06:40 +01001997
Nicolas Pitrec1724712006-03-30 15:52:41 +01001998 ret = WAIT_TIMEOUT(map, chip, adr, udelay);
1999 if (ret) {
2000 map_write(map, CMD(0x70), adr);
2001 chip->state = FL_STATUS;
2002 xip_enable(map, chip, adr);
2003 printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name);
2004 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002006
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 xip_enable(map, chip, adr);
Nicolas Pitrec1724712006-03-30 15:52:41 +01002008out: put_chip(map, chip, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 spin_unlock(chip->mutex);
Nicolas Pitrec1724712006-03-30 15:52:41 +01002010 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011}
2012
2013static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
2014{
2015 int ret;
2016
2017#ifdef DEBUG_LOCK_BITS
2018 printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
Harvey Harrisoncb53b3b2008-04-18 13:44:19 -07002019 __func__, ofs, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
Randy Dunlap1da1caf2007-06-28 23:00:09 +01002021 ofs, len, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022#endif
2023
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002024 ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 ofs, len, DO_XXLOCK_ONEBLOCK_LOCK);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002026
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027#ifdef DEBUG_LOCK_BITS
2028 printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
Harvey Harrisoncb53b3b2008-04-18 13:44:19 -07002029 __func__, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
Randy Dunlap1da1caf2007-06-28 23:00:09 +01002031 ofs, len, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032#endif
2033
2034 return ret;
2035}
2036
2037static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
2038{
2039 int ret;
2040
2041#ifdef DEBUG_LOCK_BITS
2042 printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
Harvey Harrisoncb53b3b2008-04-18 13:44:19 -07002043 __func__, ofs, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
Randy Dunlap1da1caf2007-06-28 23:00:09 +01002045 ofs, len, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046#endif
2047
2048 ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
2049 ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002050
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051#ifdef DEBUG_LOCK_BITS
2052 printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
Harvey Harrisoncb53b3b2008-04-18 13:44:19 -07002053 __func__, ret);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002054 cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
Randy Dunlap1da1caf2007-06-28 23:00:09 +01002055 ofs, len, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056#endif
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002057
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 return ret;
2059}
2060
Nicolas Pitref77814d2005-02-08 17:11:19 +00002061#ifdef CONFIG_MTD_OTP
2062
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002063typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip,
Nicolas Pitref77814d2005-02-08 17:11:19 +00002064 u_long data_offset, u_char *buf, u_int size,
2065 u_long prot_offset, u_int groupno, u_int groupsize);
2066
2067static int __xipram
2068do_otp_read(struct map_info *map, struct flchip *chip, u_long offset,
2069 u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
2070{
2071 struct cfi_private *cfi = map->fldrv_priv;
2072 int ret;
2073
2074 spin_lock(chip->mutex);
2075 ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
2076 if (ret) {
2077 spin_unlock(chip->mutex);
2078 return ret;
2079 }
2080
2081 /* let's ensure we're not reading back cached data from array mode */
Nicolas Pitre6da70122005-05-19 18:05:47 +01002082 INVALIDATE_CACHED_RANGE(map, chip->start + offset, size);
Nicolas Pitref77814d2005-02-08 17:11:19 +00002083
2084 xip_disable(map, chip, chip->start);
2085 if (chip->state != FL_JEDEC_QUERY) {
2086 map_write(map, CMD(0x90), chip->start);
2087 chip->state = FL_JEDEC_QUERY;
2088 }
2089 map_copy_from(map, buf, chip->start + offset, size);
2090 xip_enable(map, chip, chip->start);
2091
2092 /* then ensure we don't keep OTP data in the cache */
Nicolas Pitre6da70122005-05-19 18:05:47 +01002093 INVALIDATE_CACHED_RANGE(map, chip->start + offset, size);
Nicolas Pitref77814d2005-02-08 17:11:19 +00002094
2095 put_chip(map, chip, chip->start);
2096 spin_unlock(chip->mutex);
2097 return 0;
2098}
2099
2100static int
2101do_otp_write(struct map_info *map, struct flchip *chip, u_long offset,
2102 u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
2103{
2104 int ret;
2105
2106 while (size) {
2107 unsigned long bus_ofs = offset & ~(map_bankwidth(map)-1);
2108 int gap = offset - bus_ofs;
2109 int n = min_t(int, size, map_bankwidth(map)-gap);
2110 map_word datum = map_word_ff(map);
2111
2112 datum = map_word_load_partial(map, datum, buf, gap, n);
2113 ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002114 if (ret)
Nicolas Pitref77814d2005-02-08 17:11:19 +00002115 return ret;
2116
2117 offset += n;
2118 buf += n;
2119 size -= n;
2120 }
2121
2122 return 0;
2123}
2124
2125static int
2126do_otp_lock(struct map_info *map, struct flchip *chip, u_long offset,
2127 u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
2128{
2129 struct cfi_private *cfi = map->fldrv_priv;
2130 map_word datum;
2131
2132 /* make sure area matches group boundaries */
Nicolas Pitre332d71f2005-02-17 20:35:04 +00002133 if (size != grpsz)
Nicolas Pitref77814d2005-02-08 17:11:19 +00002134 return -EXDEV;
2135
2136 datum = map_word_ff(map);
2137 datum = map_word_clr(map, datum, CMD(1 << grpno));
2138 return do_write_oneword(map, chip, prot, datum, FL_OTP_WRITE);
2139}
2140
2141static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
2142 size_t *retlen, u_char *buf,
2143 otp_op_t action, int user_regs)
2144{
2145 struct map_info *map = mtd->priv;
2146 struct cfi_private *cfi = map->fldrv_priv;
2147 struct cfi_pri_intelext *extp = cfi->cmdset_priv;
2148 struct flchip *chip;
2149 struct cfi_intelext_otpinfo *otp;
2150 u_long devsize, reg_prot_offset, data_offset;
2151 u_int chip_num, chip_step, field, reg_fact_size, reg_user_size;
2152 u_int groups, groupno, groupsize, reg_fact_groups, reg_user_groups;
2153 int ret;
2154
2155 *retlen = 0;
2156
2157 /* Check that we actually have some OTP registers */
2158 if (!extp || !(extp->FeatureSupport & 64) || !extp->NumProtectionFields)
2159 return -ENODATA;
2160
2161 /* we need real chips here not virtual ones */
2162 devsize = (1 << cfi->cfiq->DevSize) * cfi->interleave;
2163 chip_step = devsize >> cfi->chipshift;
Nicolas Pitredce2b4d2005-04-01 17:36:29 +01002164 chip_num = 0;
Nicolas Pitref77814d2005-02-08 17:11:19 +00002165
Nicolas Pitredce2b4d2005-04-01 17:36:29 +01002166 /* Some chips have OTP located in the _top_ partition only.
2167 For example: Intel 28F256L18T (T means top-parameter device) */
2168 if (cfi->mfr == MANUFACTURER_INTEL) {
2169 switch (cfi->id) {
2170 case 0x880b:
2171 case 0x880c:
2172 case 0x880d:
2173 chip_num = chip_step - 1;
2174 }
2175 }
2176
2177 for ( ; chip_num < cfi->numchips; chip_num += chip_step) {
Nicolas Pitref77814d2005-02-08 17:11:19 +00002178 chip = &cfi->chips[chip_num];
2179 otp = (struct cfi_intelext_otpinfo *)&extp->extra[0];
2180
2181 /* first OTP region */
2182 field = 0;
2183 reg_prot_offset = extp->ProtRegAddr;
2184 reg_fact_groups = 1;
2185 reg_fact_size = 1 << extp->FactProtRegSize;
2186 reg_user_groups = 1;
2187 reg_user_size = 1 << extp->UserProtRegSize;
2188
2189 while (len > 0) {
2190 /* flash geometry fixup */
2191 data_offset = reg_prot_offset + 1;
2192 data_offset *= cfi->interleave * cfi->device_type;
2193 reg_prot_offset *= cfi->interleave * cfi->device_type;
2194 reg_fact_size *= cfi->interleave;
2195 reg_user_size *= cfi->interleave;
2196
2197 if (user_regs) {
2198 groups = reg_user_groups;
2199 groupsize = reg_user_size;
2200 /* skip over factory reg area */
2201 groupno = reg_fact_groups;
2202 data_offset += reg_fact_groups * reg_fact_size;
2203 } else {
2204 groups = reg_fact_groups;
2205 groupsize = reg_fact_size;
2206 groupno = 0;
2207 }
2208
Nicolas Pitre332d71f2005-02-17 20:35:04 +00002209 while (len > 0 && groups > 0) {
Nicolas Pitref77814d2005-02-08 17:11:19 +00002210 if (!action) {
2211 /*
2212 * Special case: if action is NULL
2213 * we fill buf with otp_info records.
2214 */
2215 struct otp_info *otpinfo;
2216 map_word lockword;
2217 len -= sizeof(struct otp_info);
2218 if (len <= 0)
2219 return -ENOSPC;
2220 ret = do_otp_read(map, chip,
2221 reg_prot_offset,
2222 (u_char *)&lockword,
2223 map_bankwidth(map),
2224 0, 0, 0);
2225 if (ret)
2226 return ret;
2227 otpinfo = (struct otp_info *)buf;
2228 otpinfo->start = from;
2229 otpinfo->length = groupsize;
2230 otpinfo->locked =
2231 !map_word_bitsset(map, lockword,
2232 CMD(1 << groupno));
2233 from += groupsize;
2234 buf += sizeof(*otpinfo);
2235 *retlen += sizeof(*otpinfo);
2236 } else if (from >= groupsize) {
2237 from -= groupsize;
Nicolas Pitre332d71f2005-02-17 20:35:04 +00002238 data_offset += groupsize;
Nicolas Pitref77814d2005-02-08 17:11:19 +00002239 } else {
2240 int size = groupsize;
2241 data_offset += from;
2242 size -= from;
2243 from = 0;
2244 if (size > len)
2245 size = len;
2246 ret = action(map, chip, data_offset,
2247 buf, size, reg_prot_offset,
2248 groupno, groupsize);
2249 if (ret < 0)
2250 return ret;
2251 buf += size;
2252 len -= size;
2253 *retlen += size;
Nicolas Pitre332d71f2005-02-17 20:35:04 +00002254 data_offset += size;
Nicolas Pitref77814d2005-02-08 17:11:19 +00002255 }
2256 groupno++;
2257 groups--;
2258 }
2259
2260 /* next OTP region */
2261 if (++field == extp->NumProtectionFields)
2262 break;
2263 reg_prot_offset = otp->ProtRegAddr;
2264 reg_fact_groups = otp->FactGroups;
2265 reg_fact_size = 1 << otp->FactProtRegSize;
2266 reg_user_groups = otp->UserGroups;
2267 reg_user_size = 1 << otp->UserProtRegSize;
2268 otp++;
2269 }
2270 }
2271
2272 return 0;
2273}
2274
2275static int cfi_intelext_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
2276 size_t len, size_t *retlen,
2277 u_char *buf)
2278{
2279 return cfi_intelext_otp_walk(mtd, from, len, retlen,
2280 buf, do_otp_read, 0);
2281}
2282
2283static int cfi_intelext_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
2284 size_t len, size_t *retlen,
2285 u_char *buf)
2286{
2287 return cfi_intelext_otp_walk(mtd, from, len, retlen,
2288 buf, do_otp_read, 1);
2289}
2290
2291static int cfi_intelext_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
2292 size_t len, size_t *retlen,
2293 u_char *buf)
2294{
2295 return cfi_intelext_otp_walk(mtd, from, len, retlen,
2296 buf, do_otp_write, 1);
2297}
2298
2299static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd,
2300 loff_t from, size_t len)
2301{
2302 size_t retlen;
2303 return cfi_intelext_otp_walk(mtd, from, len, &retlen,
2304 NULL, do_otp_lock, 1);
2305}
2306
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002307static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd,
Nicolas Pitref77814d2005-02-08 17:11:19 +00002308 struct otp_info *buf, size_t len)
2309{
2310 size_t retlen;
2311 int ret;
2312
2313 ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0);
2314 return ret ? : retlen;
2315}
2316
2317static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd,
2318 struct otp_info *buf, size_t len)
2319{
2320 size_t retlen;
2321 int ret;
2322
2323 ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1);
2324 return ret ? : retlen;
2325}
2326
2327#endif
2328
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002329static void cfi_intelext_save_locks(struct mtd_info *mtd)
2330{
2331 struct mtd_erase_region_info *region;
2332 int block, status, i;
2333 unsigned long adr;
2334 size_t len;
2335
2336 for (i = 0; i < mtd->numeraseregions; i++) {
2337 region = &mtd->eraseregions[i];
2338 if (!region->lockmap)
2339 continue;
2340
2341 for (block = 0; block < region->numblocks; block++){
2342 len = region->erasesize;
2343 adr = region->offset + block * len;
2344
2345 status = cfi_varsize_frob(mtd,
Ben Dooks029a9eb2007-05-28 20:11:37 +01002346 do_getlockstatus_oneblock, adr, len, NULL);
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002347 if (status)
2348 set_bit(block, region->lockmap);
2349 else
2350 clear_bit(block, region->lockmap);
2351 }
2352 }
2353}
2354
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355static int cfi_intelext_suspend(struct mtd_info *mtd)
2356{
2357 struct map_info *map = mtd->priv;
2358 struct cfi_private *cfi = map->fldrv_priv;
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002359 struct cfi_pri_intelext *extp = cfi->cmdset_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 int i;
2361 struct flchip *chip;
2362 int ret = 0;
2363
Justin Treone619a752008-01-30 10:25:49 -08002364 if ((mtd->flags & MTD_POWERUP_LOCK)
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002365 && extp && (extp->FeatureSupport & (1 << 5)))
2366 cfi_intelext_save_locks(mtd);
2367
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 for (i=0; !ret && i<cfi->numchips; i++) {
2369 chip = &cfi->chips[i];
2370
2371 spin_lock(chip->mutex);
2372
2373 switch (chip->state) {
2374 case FL_READY:
2375 case FL_STATUS:
2376 case FL_CFI_QUERY:
2377 case FL_JEDEC_QUERY:
2378 if (chip->oldstate == FL_READY) {
David Andersa86aaa62006-10-19 19:33:19 +03002379 /* place the chip in a known state before suspend */
2380 map_write(map, CMD(0xFF), cfi->chips[i].start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 chip->oldstate = chip->state;
2382 chip->state = FL_PM_SUSPENDED;
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002383 /* No need to wake_up() on this state change -
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 * as the whole point is that nobody can do anything
2385 * with the chip now anyway.
2386 */
2387 } else {
2388 /* There seems to be an operation pending. We must wait for it. */
2389 printk(KERN_NOTICE "Flash device refused suspend due to pending operation (oldstate %d)\n", chip->oldstate);
2390 ret = -EAGAIN;
2391 }
2392 break;
2393 default:
2394 /* Should we actually wait? Once upon a time these routines weren't
2395 allowed to. Or should we return -EAGAIN, because the upper layers
2396 ought to have already shut down anything which was using the device
2397 anyway? The latter for now. */
2398 printk(KERN_NOTICE "Flash device refused suspend due to active operation (state %d)\n", chip->oldstate);
2399 ret = -EAGAIN;
2400 case FL_PM_SUSPENDED:
2401 break;
2402 }
2403 spin_unlock(chip->mutex);
2404 }
2405
2406 /* Unlock the chips again */
2407
2408 if (ret) {
2409 for (i--; i >=0; i--) {
2410 chip = &cfi->chips[i];
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002411
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 spin_lock(chip->mutex);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002413
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 if (chip->state == FL_PM_SUSPENDED) {
2415 /* No need to force it into a known state here,
2416 because we're returning failure, and it didn't
2417 get power cycled */
2418 chip->state = chip->oldstate;
2419 chip->oldstate = FL_READY;
2420 wake_up(&chip->wq);
2421 }
2422 spin_unlock(chip->mutex);
2423 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002424 }
2425
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 return ret;
2427}
2428
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002429static void cfi_intelext_restore_locks(struct mtd_info *mtd)
2430{
2431 struct mtd_erase_region_info *region;
2432 int block, i;
2433 unsigned long adr;
2434 size_t len;
2435
2436 for (i = 0; i < mtd->numeraseregions; i++) {
2437 region = &mtd->eraseregions[i];
2438 if (!region->lockmap)
2439 continue;
2440
2441 for (block = 0; block < region->numblocks; block++) {
2442 len = region->erasesize;
2443 adr = region->offset + block * len;
2444
2445 if (!test_bit(block, region->lockmap))
2446 cfi_intelext_unlock(mtd, adr, len);
2447 }
2448 }
2449}
2450
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451static void cfi_intelext_resume(struct mtd_info *mtd)
2452{
2453 struct map_info *map = mtd->priv;
2454 struct cfi_private *cfi = map->fldrv_priv;
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002455 struct cfi_pri_intelext *extp = cfi->cmdset_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 int i;
2457 struct flchip *chip;
2458
2459 for (i=0; i<cfi->numchips; i++) {
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002460
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 chip = &cfi->chips[i];
2462
2463 spin_lock(chip->mutex);
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002464
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 /* Go to known state. Chip may have been power cycled */
2466 if (chip->state == FL_PM_SUSPENDED) {
2467 map_write(map, CMD(0xFF), cfi->chips[i].start);
2468 chip->oldstate = chip->state = FL_READY;
2469 wake_up(&chip->wq);
2470 }
2471
2472 spin_unlock(chip->mutex);
2473 }
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002474
Justin Treone619a752008-01-30 10:25:49 -08002475 if ((mtd->flags & MTD_POWERUP_LOCK)
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002476 && extp && (extp->FeatureSupport & (1 << 5)))
2477 cfi_intelext_restore_locks(mtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478}
2479
Nicolas Pitre963a6fb2005-04-01 02:59:56 +01002480static int cfi_intelext_reset(struct mtd_info *mtd)
2481{
2482 struct map_info *map = mtd->priv;
2483 struct cfi_private *cfi = map->fldrv_priv;
2484 int i, ret;
2485
2486 for (i=0; i < cfi->numchips; i++) {
2487 struct flchip *chip = &cfi->chips[i];
2488
2489 /* force the completion of any ongoing operation
Thomas Gleixner1f948b42005-11-07 11:15:37 +00002490 and switch to array mode so any bootloader in
Nicolas Pitre963a6fb2005-04-01 02:59:56 +01002491 flash is accessible for soft reboot. */
2492 spin_lock(chip->mutex);
Kevin Haoc4a9f882007-10-02 13:56:04 -07002493 ret = get_chip(map, chip, chip->start, FL_SHUTDOWN);
Nicolas Pitre963a6fb2005-04-01 02:59:56 +01002494 if (!ret) {
2495 map_write(map, CMD(0xff), chip->start);
Kevin Haoc4a9f882007-10-02 13:56:04 -07002496 chip->state = FL_SHUTDOWN;
Nicolas Pitre963a6fb2005-04-01 02:59:56 +01002497 }
2498 spin_unlock(chip->mutex);
2499 }
2500
2501 return 0;
2502}
2503
2504static int cfi_intelext_reboot(struct notifier_block *nb, unsigned long val,
2505 void *v)
2506{
2507 struct mtd_info *mtd;
2508
2509 mtd = container_of(nb, struct mtd_info, reboot_notifier);
2510 cfi_intelext_reset(mtd);
2511 return NOTIFY_DONE;
2512}
2513
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514static void cfi_intelext_destroy(struct mtd_info *mtd)
2515{
2516 struct map_info *map = mtd->priv;
2517 struct cfi_private *cfi = map->fldrv_priv;
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002518 struct mtd_erase_region_info *region;
2519 int i;
Nicolas Pitre963a6fb2005-04-01 02:59:56 +01002520 cfi_intelext_reset(mtd);
2521 unregister_reboot_notifier(&mtd->reboot_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 kfree(cfi->cmdset_priv);
2523 kfree(cfi->cfiq);
2524 kfree(cfi->chips[0].priv);
2525 kfree(cfi);
Rodolfo Giometti0ecbc812007-03-26 21:45:43 -08002526 for (i = 0; i < mtd->numeraseregions; i++) {
2527 region = &mtd->eraseregions[i];
2528 if (region->lockmap)
2529 kfree(region->lockmap);
2530 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 kfree(mtd->eraseregions);
2532}
2533
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534MODULE_LICENSE("GPL");
2535MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");
2536MODULE_DESCRIPTION("MTD chip driver for Intel/Sharp flash chips");
David Woodhousea15bdee2006-05-08 22:35:05 +01002537MODULE_ALIAS("cfi_cmdset_0003");
2538MODULE_ALIAS("cfi_cmdset_0200");