blob: 14e57b2bf8424ccc287a184bdd9e08a26f7925c4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001
2/* JEDEC Flash Interface.
Thomas Gleixner1f948b42005-11-07 11:15:37 +00003 * This is an older type of interface for self programming flash. It is
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * commonly use in older AMD chips and is obsolete compared with CFI.
5 * It is called JEDEC because the JEDEC association distributes the ID codes
6 * for the chips.
7 *
8 * See the AMD flash databook for information on how to operate the interface.
9 *
10 * This code does not support anything wider than 8 bit flash chips, I am
11 * not going to guess how to send commands to them, plus I expect they will
12 * all speak CFI..
13 *
14 * $Id: jedec.c,v 1.22 2005/01/05 18:05:11 dwmw2 Exp $
15 */
16
17#include <linux/init.h>
18#include <linux/module.h>
19#include <linux/kernel.h>
Tim Schmielau4e57b682005-10-30 15:03:48 -080020#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/mtd/jedec.h>
22#include <linux/mtd/map.h>
23#include <linux/mtd/mtd.h>
24#include <linux/mtd/compatmac.h>
25
26static struct mtd_info *jedec_probe(struct map_info *);
27static int jedec_probe8(struct map_info *map,unsigned long base,
28 struct jedec_private *priv);
29static int jedec_probe16(struct map_info *map,unsigned long base,
30 struct jedec_private *priv);
31static int jedec_probe32(struct map_info *map,unsigned long base,
32 struct jedec_private *priv);
33static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
34 unsigned long len);
35static int flash_erase(struct mtd_info *mtd, struct erase_info *instr);
36static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
37 size_t *retlen, const u_char *buf);
38
39static unsigned long my_bank_size;
40
41/* Listing of parts and sizes. We need this table to learn the sector
42 size of the chip and the total length */
43static const struct JEDECTable JEDEC_table[] = {
44 {
45 .jedec = 0x013D,
46 .name = "AMD Am29F017D",
47 .size = 2*1024*1024,
48 .sectorsize = 64*1024,
49 .capabilities = MTD_CAP_NORFLASH
50 },
51 {
52 .jedec = 0x01AD,
53 .name = "AMD Am29F016",
54 .size = 2*1024*1024,
55 .sectorsize = 64*1024,
56 .capabilities = MTD_CAP_NORFLASH
57 },
58 {
59 .jedec = 0x01D5,
60 .name = "AMD Am29F080",
61 .size = 1*1024*1024,
62 .sectorsize = 64*1024,
63 .capabilities = MTD_CAP_NORFLASH
64 },
65 {
66 .jedec = 0x01A4,
67 .name = "AMD Am29F040",
68 .size = 512*1024,
69 .sectorsize = 64*1024,
70 .capabilities = MTD_CAP_NORFLASH
71 },
72 {
73 .jedec = 0x20E3,
74 .name = "AMD Am29W040B",
75 .size = 512*1024,
76 .sectorsize = 64*1024,
77 .capabilities = MTD_CAP_NORFLASH
78 },
79 {
80 .jedec = 0xC2AD,
81 .name = "Macronix MX29F016",
82 .size = 2*1024*1024,
83 .sectorsize = 64*1024,
84 .capabilities = MTD_CAP_NORFLASH
85 },
86 { .jedec = 0x0 }
87};
88
89static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id);
90static void jedec_sync(struct mtd_info *mtd) {};
Thomas Gleixner1f948b42005-11-07 11:15:37 +000091static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 size_t *retlen, u_char *buf);
Thomas Gleixner1f948b42005-11-07 11:15:37 +000093static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 size_t *retlen, u_char *buf);
95
96static struct mtd_info *jedec_probe(struct map_info *map);
97
98
99
100static struct mtd_chip_driver jedec_chipdrv = {
101 .probe = jedec_probe,
102 .name = "jedec",
103 .module = THIS_MODULE
104};
105
106/* Probe entry point */
107
108static struct mtd_info *jedec_probe(struct map_info *map)
109{
110 struct mtd_info *MTD;
111 struct jedec_private *priv;
112 unsigned long Base;
113 unsigned long SectorSize;
114 unsigned count;
115 unsigned I,Uniq;
116 char Part[200];
117 memset(&priv,0,sizeof(priv));
118
Burman Yan95b93a02006-11-15 21:10:29 +0200119 MTD = kzalloc(sizeof(struct mtd_info) + sizeof(struct jedec_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 if (!MTD)
121 return NULL;
122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 priv = (struct jedec_private *)&MTD[1];
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 my_bank_size = map->size;
126
127 if (map->size/my_bank_size > MAX_JEDEC_CHIPS)
128 {
129 printk("mtd: Increase MAX_JEDEC_CHIPS, too many banks.\n");
130 kfree(MTD);
131 return NULL;
132 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000133
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 for (Base = 0; Base < map->size; Base += my_bank_size)
135 {
136 // Perhaps zero could designate all tests?
137 if (map->buswidth == 0)
138 map->buswidth = 1;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000139
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 if (map->buswidth == 1){
141 if (jedec_probe8(map,Base,priv) == 0) {
142 printk("did recognize jedec chip\n");
143 kfree(MTD);
144 return NULL;
145 }
146 }
147 if (map->buswidth == 2)
148 jedec_probe16(map,Base,priv);
149 if (map->buswidth == 4)
150 jedec_probe32(map,Base,priv);
151 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000152
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 // Get the biggest sector size
154 SectorSize = 0;
155 for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
156 {
157 // printk("priv->chips[%d].jedec is %x\n",I,priv->chips[I].jedec);
158 // printk("priv->chips[%d].sectorsize is %lx\n",I,priv->chips[I].sectorsize);
159 if (priv->chips[I].sectorsize > SectorSize)
160 SectorSize = priv->chips[I].sectorsize;
161 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000162
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 // Quickly ensure that the other sector sizes are factors of the largest
164 for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
165 {
166 if ((SectorSize/priv->chips[I].sectorsize)*priv->chips[I].sectorsize != SectorSize)
167 {
168 printk("mtd: Failed. Device has incompatible mixed sector sizes\n");
169 kfree(MTD);
170 return NULL;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000173
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 /* Generate a part name that includes the number of different chips and
175 other configuration information */
176 count = 1;
177 strlcpy(Part,map->name,sizeof(Part)-10);
178 strcat(Part," ");
179 Uniq = 0;
180 for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
181 {
182 const struct JEDECTable *JEDEC;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000183
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 if (priv->chips[I+1].jedec == priv->chips[I].jedec)
185 {
186 count++;
187 continue;
188 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 // Locate the chip in the jedec table
191 JEDEC = jedec_idtoinf(priv->chips[I].jedec >> 8,priv->chips[I].jedec);
192 if (JEDEC == 0)
193 {
194 printk("mtd: Internal Error, JEDEC not set\n");
195 kfree(MTD);
196 return NULL;
197 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000198
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 if (Uniq != 0)
200 strcat(Part,",");
201 Uniq++;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000202
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 if (count != 1)
204 sprintf(Part+strlen(Part),"%x*[%s]",count,JEDEC->name);
205 else
206 sprintf(Part+strlen(Part),"%s",JEDEC->name);
207 if (strlen(Part) > sizeof(Part)*2/3)
208 break;
209 count = 1;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000210 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
212 /* Determine if the chips are organized in a linear fashion, or if there
213 are empty banks. Note, the last bank does not count here, only the
214 first banks are important. Holes on non-bank boundaries can not exist
215 due to the way the detection algorithm works. */
216 if (priv->size < my_bank_size)
217 my_bank_size = priv->size;
218 priv->is_banked = 0;
219 //printk("priv->size is %x, my_bank_size is %x\n",priv->size,my_bank_size);
220 //printk("priv->bank_fill[0] is %x\n",priv->bank_fill[0]);
221 if (!priv->size) {
222 printk("priv->size is zero\n");
223 kfree(MTD);
224 return NULL;
225 }
226 if (priv->size/my_bank_size) {
227 if (priv->size/my_bank_size == 1) {
228 priv->size = my_bank_size;
229 }
230 else {
231 for (I = 0; I != priv->size/my_bank_size - 1; I++)
232 {
233 if (priv->bank_fill[I] != my_bank_size)
234 priv->is_banked = 1;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000235
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 /* This even could be eliminated, but new de-optimized read/write
237 functions have to be written */
238 printk("priv->bank_fill[%d] is %lx, priv->bank_fill[0] is %lx\n",I,priv->bank_fill[I],priv->bank_fill[0]);
239 if (priv->bank_fill[I] != priv->bank_fill[0])
240 {
241 printk("mtd: Failed. Cannot handle unsymmetric banking\n");
242 kfree(MTD);
243 return NULL;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 }
246 }
247 }
248 if (priv->is_banked == 1)
249 strcat(Part,", banked");
250
251 // printk("Part: '%s'\n",Part);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 memset(MTD,0,sizeof(*MTD));
254 // strlcpy(MTD->name,Part,sizeof(MTD->name));
255 MTD->name = map->name;
256 MTD->type = MTD_NORFLASH;
257 MTD->flags = MTD_CAP_NORFLASH;
Artem B. Bityutskiy17ffc7b2006-06-22 18:15:48 +0400258 MTD->writesize = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 MTD->erasesize = SectorSize*(map->buswidth);
260 // printk("MTD->erasesize is %x\n",(unsigned int)MTD->erasesize);
261 MTD->size = priv->size;
262 // printk("MTD->size is %x\n",(unsigned int)MTD->size);
263 //MTD->module = THIS_MODULE; // ? Maybe this should be the low level module?
264 MTD->erase = flash_erase;
265 if (priv->is_banked == 1)
266 MTD->read = jedec_read_banked;
267 else
268 MTD->read = jedec_read;
269 MTD->write = flash_write;
270 MTD->sync = jedec_sync;
271 MTD->priv = map;
272 map->fldrv_priv = priv;
273 map->fldrv = &jedec_chipdrv;
274 __module_get(THIS_MODULE);
275 return MTD;
276}
277
278/* Helper for the JEDEC function, JEDEC numbers all have odd parity */
279static int checkparity(u_char C)
280{
281 u_char parity = 0;
282 while (C != 0)
283 {
284 parity ^= C & 1;
285 C >>= 1;
286 }
287
288 return parity == 1;
289}
290
291
292/* Take an array of JEDEC numbers that represent interleved flash chips
293 and process them. Check to make sure they are good JEDEC numbers, look
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000294 them up and then add them to the chip list */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count,
296 unsigned long base,struct jedec_private *priv)
297{
298 unsigned I,J;
299 unsigned long Size;
300 unsigned long SectorSize;
301 const struct JEDECTable *JEDEC;
302
303 // Test #2 JEDEC numbers exhibit odd parity
304 for (I = 0; I != Count; I++)
305 {
306 if (checkparity(Mfg[I]) == 0 || checkparity(Id[I]) == 0)
307 return 0;
308 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000309
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 // Finally, just make sure all the chip sizes are the same
311 JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 if (JEDEC == 0)
314 {
315 printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
316 return 0;
317 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000318
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 Size = JEDEC->size;
320 SectorSize = JEDEC->sectorsize;
321 for (I = 0; I != Count; I++)
322 {
323 JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
324 if (JEDEC == 0)
325 {
326 printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
327 return 0;
328 }
329
330 if (Size != JEDEC->size || SectorSize != JEDEC->sectorsize)
331 {
332 printk("mtd: Failed. Interleved flash does not have matching characteristics\n");
333 return 0;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 }
336
337 // Load the Chips
338 for (I = 0; I != MAX_JEDEC_CHIPS; I++)
339 {
340 if (priv->chips[I].jedec == 0)
341 break;
342 }
343
344 if (I + Count > MAX_JEDEC_CHIPS)
345 {
346 printk("mtd: Device has too many chips. Increase MAX_JEDEC_CHIPS\n");
347 return 0;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000348 }
349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 // Add them to the table
351 for (J = 0; J != Count; J++)
352 {
353 unsigned long Bank;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000354
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 JEDEC = jedec_idtoinf(Mfg[J],Id[J]);
356 priv->chips[I].jedec = (Mfg[J] << 8) | Id[J];
357 priv->chips[I].size = JEDEC->size;
358 priv->chips[I].sectorsize = JEDEC->sectorsize;
359 priv->chips[I].base = base + J;
360 priv->chips[I].datashift = J*8;
361 priv->chips[I].capabilities = JEDEC->capabilities;
362 priv->chips[I].offset = priv->size + J;
363
364 // log2 n :|
365 priv->chips[I].addrshift = 0;
366 for (Bank = Count; Bank != 1; Bank >>= 1, priv->chips[I].addrshift++);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000367
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 // Determine how filled this bank is.
369 Bank = base & (~(my_bank_size-1));
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000370 if (priv->bank_fill[Bank/my_bank_size] < base +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 (JEDEC->size << priv->chips[I].addrshift) - Bank)
372 priv->bank_fill[Bank/my_bank_size] = base + (JEDEC->size << priv->chips[I].addrshift) - Bank;
373 I++;
374 }
375
376 priv->size += priv->chips[I-1].size*Count;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000377
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 return priv->chips[I-1].size;
379}
380
381/* Lookup the chip information from the JEDEC ID table. */
382static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id)
383{
384 __u16 Id = (mfr << 8) | id;
385 unsigned long I = 0;
386 for (I = 0; JEDEC_table[I].jedec != 0; I++)
387 if (JEDEC_table[I].jedec == Id)
388 return JEDEC_table + I;
389 return NULL;
390}
391
392// Look for flash using an 8 bit bus interface
393static int jedec_probe8(struct map_info *map,unsigned long base,
394 struct jedec_private *priv)
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000395{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 #define flread(x) map_read8(map,base+x)
397 #define flwrite(v,x) map_write8(map,v,base+x)
398
399 const unsigned long AutoSel1 = 0xAA;
400 const unsigned long AutoSel2 = 0x55;
401 const unsigned long AutoSel3 = 0x90;
402 const unsigned long Reset = 0xF0;
403 __u32 OldVal;
404 __u8 Mfg[1];
405 __u8 Id[1];
406 unsigned I;
407 unsigned long Size;
408
409 // Wait for any write/erase operation to settle
410 OldVal = flread(base);
411 for (I = 0; OldVal != flread(base) && I < 10000; I++)
412 OldVal = flread(base);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000413
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 // Reset the chip
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000415 flwrite(Reset,0x555);
416
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 // Send the sequence
418 flwrite(AutoSel1,0x555);
419 flwrite(AutoSel2,0x2AA);
420 flwrite(AutoSel3,0x555);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000421
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 // Get the JEDEC numbers
423 Mfg[0] = flread(0);
424 Id[0] = flread(1);
425 // printk("Mfg is %x, Id is %x\n",Mfg[0],Id[0]);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000426
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 Size = handle_jedecs(map,Mfg,Id,1,base,priv);
428 // printk("handle_jedecs Size is %x\n",(unsigned int)Size);
429 if (Size == 0)
430 {
431 flwrite(Reset,0x555);
432 return 0;
433 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000434
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436 // Reset.
437 flwrite(Reset,0x555);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 return 1;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000440
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 #undef flread
442 #undef flwrite
443}
444
445// Look for flash using a 16 bit bus interface (ie 2 8-bit chips)
446static int jedec_probe16(struct map_info *map,unsigned long base,
447 struct jedec_private *priv)
448{
449 return 0;
450}
451
452// Look for flash using a 32 bit bus interface (ie 4 8-bit chips)
453static int jedec_probe32(struct map_info *map,unsigned long base,
454 struct jedec_private *priv)
455{
456 #define flread(x) map_read32(map,base+((x)<<2))
457 #define flwrite(v,x) map_write32(map,v,base+((x)<<2))
458
459 const unsigned long AutoSel1 = 0xAAAAAAAA;
460 const unsigned long AutoSel2 = 0x55555555;
461 const unsigned long AutoSel3 = 0x90909090;
462 const unsigned long Reset = 0xF0F0F0F0;
463 __u32 OldVal;
464 __u8 Mfg[4];
465 __u8 Id[4];
466 unsigned I;
467 unsigned long Size;
468
469 // Wait for any write/erase operation to settle
470 OldVal = flread(base);
471 for (I = 0; OldVal != flread(base) && I < 10000; I++)
472 OldVal = flread(base);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000473
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 // Reset the chip
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000475 flwrite(Reset,0x555);
476
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 // Send the sequence
478 flwrite(AutoSel1,0x555);
479 flwrite(AutoSel2,0x2AA);
480 flwrite(AutoSel3,0x555);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000481
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 // Test #1, JEDEC numbers are readable from 0x??00/0x??01
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000483 if (flread(0) != flread(0x100) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 flread(1) != flread(0x101))
485 {
486 flwrite(Reset,0x555);
487 return 0;
488 }
489
490 // Split up the JEDEC numbers
491 OldVal = flread(0);
492 for (I = 0; I != 4; I++)
493 Mfg[I] = (OldVal >> (I*8));
494 OldVal = flread(1);
495 for (I = 0; I != 4; I++)
496 Id[I] = (OldVal >> (I*8));
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000497
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 Size = handle_jedecs(map,Mfg,Id,4,base,priv);
499 if (Size == 0)
500 {
501 flwrite(Reset,0x555);
502 return 0;
503 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000504
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 /* Check if there is address wrap around within a single bank, if this
506 returns JEDEC numbers then we assume that it is wrap around. Notice
507 we call this routine with the JEDEC return still enabled, if two or
508 more flashes have a truncated address space the probe test will still
509 work */
510 if (base + (Size<<2)+0x555 < map->size &&
511 base + (Size<<2)+0x555 < (base & (~(my_bank_size-1))) + my_bank_size)
512 {
513 if (flread(base+Size) != flread(base+Size + 0x100) ||
514 flread(base+Size + 1) != flread(base+Size + 0x101))
515 {
516 jedec_probe32(map,base+Size,priv);
517 }
518 }
519
520 // Reset.
521 flwrite(0xF0F0F0F0,0x555);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000522
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 return 1;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000524
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 #undef flread
526 #undef flwrite
527}
528
529/* Linear read. */
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000530static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 size_t *retlen, u_char *buf)
532{
533 struct map_info *map = mtd->priv;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 map_copy_from(map, buf, from, len);
536 *retlen = len;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000537 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538}
539
540/* Banked read. Take special care to jump past the holes in the bank
541 mapping. This version assumes symetry in the holes.. */
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000542static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 size_t *retlen, u_char *buf)
544{
545 struct map_info *map = mtd->priv;
546 struct jedec_private *priv = map->fldrv_priv;
547
548 *retlen = 0;
549 while (len > 0)
550 {
551 // Determine what bank and offset into that bank the first byte is
552 unsigned long bank = from & (~(priv->bank_fill[0]-1));
553 unsigned long offset = from & (priv->bank_fill[0]-1);
554 unsigned long get = len;
555 if (priv->bank_fill[0] - offset < len)
556 get = priv->bank_fill[0] - offset;
557
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000558 bank /= priv->bank_fill[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000560
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 len -= get;
562 *retlen += get;
563 from += get;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000564 }
565 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566}
567
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000568/* Pass the flags value that the flash return before it re-entered read
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 mode. */
570static void jedec_flash_failed(unsigned char code)
571{
572 /* Bit 5 being high indicates that there was an internal device
573 failure, erasure time limits exceeded or something */
574 if ((code & (1 << 5)) != 0)
575 {
576 printk("mtd: Internal Flash failure\n");
577 return;
578 }
579 printk("mtd: Programming didn't take\n");
580}
581
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000582/* This uses the erasure function described in the AMD Flash Handbook,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 it will work for flashes with a fixed sector size only. Flashes with
584 a selection of sector sizes (ie the AMD Am29F800B) will need a different
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000585 routine. This routine tries to parallize erasing multiple chips/sectors
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 where possible */
587static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
588{
589 // Does IO to the currently selected chip
590 #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift))
591 #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift))
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000592
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 unsigned long Time = 0;
594 unsigned long NoTime = 0;
595 unsigned long start = instr->addr, len = instr->len;
596 unsigned int I;
597 struct map_info *map = mtd->priv;
598 struct jedec_private *priv = map->fldrv_priv;
599
600 // Verify the arguments..
601 if (start + len > mtd->size ||
602 (start % mtd->erasesize) != 0 ||
603 (len % mtd->erasesize) != 0 ||
604 (len/mtd->erasesize) == 0)
605 return -EINVAL;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 jedec_flash_chip_scan(priv,start,len);
608
609 // Start the erase sequence on each chip
610 for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
611 {
612 unsigned long off;
613 struct jedec_flash_chip *chip = priv->chips + I;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000614
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 if (chip->length == 0)
616 continue;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000617
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 if (chip->start + chip->length > chip->size)
619 {
620 printk("DIE\n");
621 return -EIO;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000622 }
623
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 flwrite(0xF0,chip->start + 0x555);
625 flwrite(0xAA,chip->start + 0x555);
626 flwrite(0x55,chip->start + 0x2AA);
627 flwrite(0x80,chip->start + 0x555);
628 flwrite(0xAA,chip->start + 0x555);
629 flwrite(0x55,chip->start + 0x2AA);
630
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000631 /* Once we start selecting the erase sectors the delay between each
632 command must not exceed 50us or it will immediately start erasing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 and ignore the other sectors */
634 for (off = 0; off < len; off += chip->sectorsize)
635 {
636 // Check to make sure we didn't timeout
637 flwrite(0x30,chip->start + off);
638 if (off == 0)
639 continue;
640 if ((flread(chip->start + off) & (1 << 3)) != 0)
641 {
642 printk("mtd: Ack! We timed out the erase timer!\n");
643 return -EIO;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000646 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
648 /* We could split this into a timer routine and return early, performing
649 background erasure.. Maybe later if the need warrents */
650
651 /* Poll the flash for erasure completion, specs say this can take as long
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000652 as 480 seconds to do all the sectors (for a 2 meg flash).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 Erasure time is dependent on chip age, temp and wear.. */
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000654
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 /* This being a generic routine assumes a 32 bit bus. It does read32s
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000656 and bundles interleved chips into the same grouping. This will work
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 for all bus widths */
658 Time = 0;
659 NoTime = 0;
660 for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
661 {
662 struct jedec_flash_chip *chip = priv->chips + I;
663 unsigned long off = 0;
664 unsigned todo[4] = {0,0,0,0};
665 unsigned todo_left = 0;
666 unsigned J;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 if (chip->length == 0)
669 continue;
670
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000671 /* Find all chips in this data line, realistically this is all
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 or nothing up to the interleve count */
673 for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
674 {
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000675 if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 (chip->base & (~((1<<chip->addrshift)-1))))
677 {
678 todo_left++;
679 todo[priv->chips[J].base & ((1<<chip->addrshift)-1)] = 1;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 }
682
683 /* printk("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1],
684 (short)todo[2],(short)todo[3]);
685 */
686 while (1)
687 {
688 __u32 Last[4];
689 unsigned long Count = 0;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000690
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 /* During erase bit 7 is held low and bit 6 toggles, we watch this,
692 should it stop toggling or go high then the erase is completed,
693 or this is not really flash ;> */
694 switch (map->buswidth) {
695 case 1:
696 Last[0] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
697 Last[1] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
698 Last[2] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
699 break;
700 case 2:
701 Last[0] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
702 Last[1] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
703 Last[2] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
704 break;
705 case 3:
706 Last[0] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
707 Last[1] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
708 Last[2] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
709 break;
710 }
711 Count = 3;
712 while (todo_left != 0)
713 {
714 for (J = 0; J != 4; J++)
715 {
716 __u8 Byte1 = (Last[(Count-1)%4] >> (J*8)) & 0xFF;
717 __u8 Byte2 = (Last[(Count-2)%4] >> (J*8)) & 0xFF;
718 __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF;
719 if (todo[J] == 0)
720 continue;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2)
723 {
724// printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2);
725 continue;
726 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000727
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 if (Byte1 == Byte2)
729 {
730 jedec_flash_failed(Byte3);
731 return -EIO;
732 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000733
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 todo[J] = 0;
735 todo_left--;
736 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000737
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738/* if (NoTime == 0)
739 Time += HZ/10 - schedule_timeout(HZ/10);*/
740 NoTime = 0;
741
742 switch (map->buswidth) {
743 case 1:
744 Last[Count % 4] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
745 break;
746 case 2:
747 Last[Count % 4] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
748 break;
749 case 4:
750 Last[Count % 4] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
751 break;
752 }
753 Count++;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000754
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755/* // Count time, max of 15s per sector (according to AMD)
756 if (Time > 15*len/mtd->erasesize*HZ)
757 {
758 printk("mtd: Flash Erase Timed out\n");
759 return -EIO;
760 } */
761 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000762
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 // Skip to the next chip if we used chip erase
764 if (chip->length == chip->size)
765 off = chip->size;
766 else
767 off += chip->sectorsize;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000768
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 if (off >= chip->length)
770 break;
771 NoTime = 1;
772 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000773
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
775 {
776 if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
777 (chip->base & (~((1<<chip->addrshift)-1))))
778 priv->chips[J].length = 0;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000779 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 //printk("done\n");
783 instr->state = MTD_ERASE_DONE;
784 mtd_erase_callback(instr);
785 return 0;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 #undef flread
788 #undef flwrite
789}
790
791/* This is the simple flash writing function. It writes to every byte, in
792 sequence. It takes care of how to properly address the flash if
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000793 the flash is interleved. It can only be used if all the chips in the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 array are identical!*/
795static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
796 size_t *retlen, const u_char *buf)
797{
798 /* Does IO to the currently selected chip. It takes the bank addressing
799 base (which is divisible by the chip size) adds the necessary lower bits
800 of addrshift (interleave index) and then adds the control register index. */
801 #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
802 #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000803
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 struct map_info *map = mtd->priv;
805 struct jedec_private *priv = map->fldrv_priv;
806 unsigned long base;
807 unsigned long off;
808 size_t save_len = len;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000809
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 if (start + len > mtd->size)
811 return -EIO;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 //printk("Here");
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 //printk("flash_write: start is %x, len is %x\n",start,(unsigned long)len);
816 while (len != 0)
817 {
818 struct jedec_flash_chip *chip = priv->chips;
819 unsigned long bank;
820 unsigned long boffset;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000821
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 // Compute the base of the flash.
823 off = ((unsigned long)start) % (chip->size << chip->addrshift);
824 base = start - off;
825
826 // Perform banked addressing translation.
827 bank = base & (~(priv->bank_fill[0]-1));
828 boffset = base & (priv->bank_fill[0]-1);
829 bank = (bank/priv->bank_fill[0])*my_bank_size;
830 base = bank + boffset;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000831
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 // printk("Flasing %X %X %X\n",base,chip->size,len);
833 // printk("off is %x, compare with %x\n",off,chip->size << chip->addrshift);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000834
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 // Loop over this page
836 for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++)
837 {
838 unsigned char oldbyte = map_read8(map,base+off);
839 unsigned char Last[4];
840 unsigned long Count = 0;
841
842 if (oldbyte == *buf) {
843 // printk("oldbyte and *buf is %x,len is %x\n",oldbyte,len);
844 continue;
845 }
846 if (((~oldbyte) & *buf) != 0)
847 printk("mtd: warn: Trying to set a 0 to a 1\n");
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000848
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 // Write
850 flwrite(0xAA,0x555);
851 flwrite(0x55,0x2AA);
852 flwrite(0xA0,0x555);
853 map_write8(map,*buf,base + off);
854 Last[0] = map_read8(map,base + off);
855 Last[1] = map_read8(map,base + off);
856 Last[2] = map_read8(map,base + off);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 /* Wait for the flash to finish the operation. We store the last 4
859 status bytes that have been retrieved so we can determine why
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000860 it failed. The toggle bits keep toggling when there is a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 failure */
862 for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] &&
863 Count < 10000; Count++)
864 Last[Count % 4] = map_read8(map,base + off);
865 if (Last[(Count - 1) % 4] != *buf)
866 {
867 jedec_flash_failed(Last[(Count - 3) % 4]);
868 return -EIO;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 }
871 }
872 *retlen = save_len;
873 return 0;
874}
875
876/* This is used to enhance the speed of the erase routine,
877 when things are being done to multiple chips it is possible to
878 parallize the operations, particularly full memory erases of multi
879 chip memories benifit */
880static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
881 unsigned long len)
882{
883 unsigned int I;
884
885 // Zero the records
886 for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
887 priv->chips[I].start = priv->chips[I].length = 0;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 // Intersect the region with each chip
890 for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
891 {
892 struct jedec_flash_chip *chip = priv->chips + I;
893 unsigned long ByteStart;
894 unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000895
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 // End is before this chip or the start is after it
897 if (start+len < chip->offset ||
898 ChipEndByte - (1 << chip->addrshift) < start)
899 continue;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000900
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 if (start < chip->offset)
902 {
903 ByteStart = chip->offset;
904 chip->start = 0;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000905 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 else
907 {
908 chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift;
909 ByteStart = start;
910 }
911
912 if (start + len >= ChipEndByte)
913 chip->length = (ChipEndByte - ByteStart) >> chip->addrshift;
914 else
915 chip->length = (start + len - ByteStart + (1 << chip->addrshift)-1) >> chip->addrshift;
916 }
917}
918
919int __init jedec_init(void)
920{
921 register_mtd_chip_driver(&jedec_chipdrv);
922 return 0;
923}
924
925static void __exit jedec_exit(void)
926{
927 unregister_mtd_chip_driver(&jedec_chipdrv);
928}
929
930module_init(jedec_init);
931module_exit(jedec_exit);
932
933MODULE_LICENSE("GPL");
934MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com> et al.");
935MODULE_DESCRIPTION("Old MTD chip driver for JEDEC-compliant flash chips");