mtd: vf610_nfc: allow bitflips in an empty page
[oweals/u-boot.git] / drivers / mtd / jedec_flash.c
1 /*
2  * (C) Copyright 2007
3  * Michael Schwingen, <michael@schwingen.org>
4  *
5  * based in great part on jedec_probe.c from linux kernel:
6  * (C) 2000 Red Hat. GPL'd.
7  * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
8  *
9  * SPDX-License-Identifier:     GPL-2.0+
10  */
11
12 /* The DEBUG define must be before common to enable debugging */
13 /*#define DEBUG*/
14
15 #include <common.h>
16 #include <asm/processor.h>
17 #include <asm/io.h>
18 #include <asm/byteorder.h>
19 #include <environment.h>
20
21 #define P_ID_AMD_STD CFI_CMDSET_AMD_LEGACY
22
23 /* AMD */
24 #define AM29DL800BB     0x22CB
25 #define AM29DL800BT     0x224A
26
27 #define AM29F400BB      0x22AB
28 #define AM29F800BB      0x2258
29 #define AM29F800BT      0x22D6
30 #define AM29LV400BB     0x22BA
31 #define AM29LV400BT     0x22B9
32 #define AM29LV800BB     0x225B
33 #define AM29LV800BT     0x22DA
34 #define AM29LV160DT     0x22C4
35 #define AM29LV160DB     0x2249
36 #define AM29F017D       0x003D
37 #define AM29F016D       0x00AD
38 #define AM29F080        0x00D5
39 #define AM29F040        0x00A4
40 #define AM29LV040B      0x004F
41 #define AM29F032B       0x0041
42 #define AM29F002T       0x00B0
43
44 /* SST */
45 #define SST39LF800      0x2781
46 #define SST39LF160      0x2782
47 #define SST39VF1601     0x234b
48 #define SST39LF512      0x00D4
49 #define SST39LF010      0x00D5
50 #define SST39LF020      0x00D6
51 #define SST39LF040      0x00D7
52 #define SST39SF010A     0x00B5
53 #define SST39SF020A     0x00B6
54
55 /* STM */
56 #define STM29F400BB     0x00D6
57
58 /* MXIC */
59 #define MX29LV040       0x004F
60
61 /* WINBOND */
62 #define W39L040A        0x00D6
63
64 /* AMIC */
65 #define A29L040         0x0092
66
67 /* EON */
68 #define EN29LV040A      0x004F
69
70 /*
71  * Unlock address sets for AMD command sets.
72  * Intel command sets use the MTD_UADDR_UNNECESSARY.
73  * Each identifier, except MTD_UADDR_UNNECESSARY, and
74  * MTD_UADDR_NO_SUPPORT must be defined below in unlock_addrs[].
75  * MTD_UADDR_NOT_SUPPORTED must be 0 so that structure
76  * initialization need not require initializing all of the
77  * unlock addresses for all bit widths.
78  */
79 enum uaddr {
80         MTD_UADDR_NOT_SUPPORTED = 0,    /* data width not supported */
81         MTD_UADDR_0x0555_0x02AA,
82         MTD_UADDR_0x0555_0x0AAA,
83         MTD_UADDR_0x5555_0x2AAA,
84         MTD_UADDR_0x0AAA_0x0555,
85         MTD_UADDR_DONT_CARE,            /* Requires an arbitrary address */
86         MTD_UADDR_UNNECESSARY,          /* Does not require any address */
87 };
88
89
90 struct unlock_addr {
91         u32 addr1;
92         u32 addr2;
93 };
94
95
96 /*
97  * I don't like the fact that the first entry in unlock_addrs[]
98  * exists, but is for MTD_UADDR_NOT_SUPPORTED - and, therefore,
99  * should not be used.  The  problem is that structures with
100  * initializers have extra fields initialized to 0.  It is _very_
101  * desireable to have the unlock address entries for unsupported
102  * data widths automatically initialized - that means that
103  * MTD_UADDR_NOT_SUPPORTED must be 0 and the first entry here
104  * must go unused.
105  */
106 static const struct unlock_addr  unlock_addrs[] = {
107         [MTD_UADDR_NOT_SUPPORTED] = {
108                 .addr1 = 0xffff,
109                 .addr2 = 0xffff
110         },
111
112         [MTD_UADDR_0x0555_0x02AA] = {
113                 .addr1 = 0x0555,
114                 .addr2 = 0x02aa
115         },
116
117         [MTD_UADDR_0x0555_0x0AAA] = {
118                 .addr1 = 0x0555,
119                 .addr2 = 0x0aaa
120         },
121
122         [MTD_UADDR_0x5555_0x2AAA] = {
123                 .addr1 = 0x5555,
124                 .addr2 = 0x2aaa
125         },
126
127         [MTD_UADDR_0x0AAA_0x0555] = {
128                 .addr1 = 0x0AAA,
129                 .addr2 = 0x0555
130         },
131
132         [MTD_UADDR_DONT_CARE] = {
133                 .addr1 = 0x0000,      /* Doesn't matter which address */
134                 .addr2 = 0x0000       /* is used - must be last entry */
135         },
136
137         [MTD_UADDR_UNNECESSARY] = {
138                 .addr1 = 0x0000,
139                 .addr2 = 0x0000
140         }
141 };
142
143
144 struct amd_flash_info {
145         const __u16 mfr_id;
146         const __u16 dev_id;
147         const char *name;
148         const int DevSize;
149         const int NumEraseRegions;
150         const int CmdSet;
151         const __u8 uaddr[4];            /* unlock addrs for 8, 16, 32, 64 */
152         const ulong regions[6];
153 };
154
155 #define ERASEINFO(size,blocks) (size<<8)|(blocks-1)
156
157 #define SIZE_64KiB  16
158 #define SIZE_128KiB 17
159 #define SIZE_256KiB 18
160 #define SIZE_512KiB 19
161 #define SIZE_1MiB   20
162 #define SIZE_2MiB   21
163 #define SIZE_4MiB   22
164 #define SIZE_8MiB   23
165
166 static const struct amd_flash_info jedec_table[] = {
167 #ifdef CONFIG_SYS_FLASH_LEGACY_256Kx8
168         {
169                 .mfr_id         = (u16)SST_MANUFACT,
170                 .dev_id         = SST39LF020,
171                 .name           = "SST 39LF020",
172                 .uaddr          = {
173                         [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
174                 },
175                 .DevSize        = SIZE_256KiB,
176                 .CmdSet         = P_ID_AMD_STD,
177                 .NumEraseRegions= 1,
178                 .regions        = {
179                         ERASEINFO(0x01000,64),
180                 }
181         },
182 #endif
183 #ifdef CONFIG_SYS_FLASH_LEGACY_512Kx8
184         {
185                 .mfr_id         = (u16)AMD_MANUFACT,
186                 .dev_id         = AM29LV040B,
187                 .name           = "AMD AM29LV040B",
188                 .uaddr          = {
189                         [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
190                 },
191                 .DevSize        = SIZE_512KiB,
192                 .CmdSet         = P_ID_AMD_STD,
193                 .NumEraseRegions= 1,
194                 .regions        = {
195                         ERASEINFO(0x10000,8),
196                 }
197         },
198         {
199                 .mfr_id         = (u16)SST_MANUFACT,
200                 .dev_id         = SST39LF040,
201                 .name           = "SST 39LF040",
202                 .uaddr          = {
203                         [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
204                 },
205                 .DevSize        = SIZE_512KiB,
206                 .CmdSet         = P_ID_AMD_STD,
207                 .NumEraseRegions= 1,
208                 .regions        = {
209                         ERASEINFO(0x01000,128),
210                 }
211         },
212         {
213                 .mfr_id         = (u16)STM_MANUFACT,
214                 .dev_id         = STM_ID_M29W040B,
215                 .name           = "ST Micro M29W040B",
216                 .uaddr          = {
217                         [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
218                 },
219                 .DevSize        = SIZE_512KiB,
220                 .CmdSet         = P_ID_AMD_STD,
221                 .NumEraseRegions= 1,
222                 .regions        = {
223                         ERASEINFO(0x10000,8),
224                 }
225         },
226         {
227                 .mfr_id         = (u16)MX_MANUFACT,
228                 .dev_id         = MX29LV040,
229                 .name           = "MXIC MX29LV040",
230                 .uaddr          = {
231                         [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
232                 },
233                 .DevSize        = SIZE_512KiB,
234                 .CmdSet         = P_ID_AMD_STD,
235                 .NumEraseRegions= 1,
236                 .regions        = {
237                         ERASEINFO(0x10000, 8),
238                 }
239         },
240         {
241                 .mfr_id         = (u16)WINB_MANUFACT,
242                 .dev_id         = W39L040A,
243                 .name           = "WINBOND W39L040A",
244                 .uaddr          = {
245                         [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
246                 },
247                 .DevSize        = SIZE_512KiB,
248                 .CmdSet         = P_ID_AMD_STD,
249                 .NumEraseRegions= 1,
250                 .regions        = {
251                         ERASEINFO(0x10000, 8),
252                 }
253         },
254         {
255                 .mfr_id         = (u16)AMIC_MANUFACT,
256                 .dev_id         = A29L040,
257                 .name           = "AMIC A29L040",
258                 .uaddr          = {
259                         [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
260                 },
261                 .DevSize        = SIZE_512KiB,
262                 .CmdSet         = P_ID_AMD_STD,
263                 .NumEraseRegions= 1,
264                 .regions        = {
265                         ERASEINFO(0x10000, 8),
266                 }
267         },
268         {
269                 .mfr_id         = (u16)EON_MANUFACT,
270                 .dev_id         = EN29LV040A,
271                 .name           = "EON EN29LV040A",
272                 .uaddr          = {
273                         [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
274                 },
275                 .DevSize        = SIZE_512KiB,
276                 .CmdSet         = P_ID_AMD_STD,
277                 .NumEraseRegions= 1,
278                 .regions        = {
279                         ERASEINFO(0x10000, 8),
280                 }
281         },
282 #endif
283 #ifdef CONFIG_SYS_FLASH_LEGACY_512Kx16
284         {
285                 .mfr_id         = (u16)AMD_MANUFACT,
286                 .dev_id         = AM29F400BB,
287                 .name           = "AMD AM29F400BB",
288                 .uaddr          = {
289                         [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
290                 },
291                 .DevSize        = SIZE_512KiB,
292                 .CmdSet         = CFI_CMDSET_AMD_LEGACY,
293                 .NumEraseRegions= 4,
294                 .regions        = {
295                         ERASEINFO(0x04000, 1),
296                         ERASEINFO(0x02000, 2),
297                         ERASEINFO(0x08000, 1),
298                         ERASEINFO(0x10000, 7),
299                 }
300         },
301         {
302                 .mfr_id         = (u16)AMD_MANUFACT,
303                 .dev_id         = AM29LV400BB,
304                 .name           = "AMD AM29LV400BB",
305                 .uaddr          = {
306                         [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
307                 },
308                 .DevSize        = SIZE_512KiB,
309                 .CmdSet         = CFI_CMDSET_AMD_LEGACY,
310                 .NumEraseRegions= 4,
311                 .regions        = {
312                         ERASEINFO(0x04000,1),
313                         ERASEINFO(0x02000,2),
314                         ERASEINFO(0x08000,1),
315                         ERASEINFO(0x10000,7),
316                 }
317         },
318         {
319                 .mfr_id         = (u16)AMD_MANUFACT,
320                 .dev_id         = AM29LV800BB,
321                 .name           = "AMD AM29LV800BB",
322                 .uaddr          = {
323                         [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
324                 },
325                 .DevSize        = SIZE_1MiB,
326                 .CmdSet         = CFI_CMDSET_AMD_LEGACY,
327                 .NumEraseRegions= 4,
328                 .regions        = {
329                         ERASEINFO(0x04000, 1),
330                         ERASEINFO(0x02000, 2),
331                         ERASEINFO(0x08000, 1),
332                         ERASEINFO(0x10000, 15),
333                 }
334         },
335         {
336                 .mfr_id         = (u16)AMD_MANUFACT,
337                 .dev_id         = AM29LV800BT,
338                 .name           = "AMD AM29LV800BT",
339                 .uaddr          = {
340                         [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
341                 },
342                 .DevSize        = SIZE_1MiB,
343                 .CmdSet         = CFI_CMDSET_AMD_LEGACY,
344                 .NumEraseRegions= 4,
345                 .regions        = {
346                         ERASEINFO(0x10000, 15),
347                         ERASEINFO(0x08000, 1),
348                         ERASEINFO(0x02000, 2),
349                         ERASEINFO(0x04000, 1),
350                 }
351         },
352         {
353                 .mfr_id         = (u16)MX_MANUFACT,
354                 .dev_id         = AM29LV800BT,
355                 .name           = "MXIC MX29LV800BT",
356                 .uaddr          = {
357                         [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
358                 },
359                 .DevSize        = SIZE_1MiB,
360                 .CmdSet         = CFI_CMDSET_AMD_LEGACY,
361                 .NumEraseRegions= 4,
362                 .regions        = {
363                         ERASEINFO(0x10000, 15),
364                         ERASEINFO(0x08000, 1),
365                         ERASEINFO(0x02000, 2),
366                         ERASEINFO(0x04000, 1),
367                 }
368         },
369         {
370                 .mfr_id         = (u16)EON_ALT_MANU,
371                 .dev_id         = AM29LV800BT,
372                 .name           = "EON EN29LV800BT",
373                 .uaddr          = {
374                         [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
375                 },
376                 .DevSize        = SIZE_1MiB,
377                 .CmdSet         = CFI_CMDSET_AMD_LEGACY,
378                 .NumEraseRegions= 4,
379                 .regions        = {
380                         ERASEINFO(0x10000, 15),
381                         ERASEINFO(0x08000, 1),
382                         ERASEINFO(0x02000, 2),
383                         ERASEINFO(0x04000, 1),
384                 }
385         },
386         {
387                 .mfr_id         = (u16)STM_MANUFACT,
388                 .dev_id         = STM29F400BB,
389                 .name           = "ST Micro M29F400BB",
390                 .uaddr          = {
391                         [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
392                 },
393                 .DevSize                = SIZE_512KiB,
394                 .CmdSet                 = CFI_CMDSET_AMD_LEGACY,
395                 .NumEraseRegions        = 4,
396                 .regions                = {
397                         ERASEINFO(0x04000, 1),
398                         ERASEINFO(0x02000, 2),
399                         ERASEINFO(0x08000, 1),
400                         ERASEINFO(0x10000, 7),
401                 }
402         },
403 #endif
404 };
405
406 static inline void fill_info(flash_info_t *info, const struct amd_flash_info *jedec_entry, ulong base)
407 {
408         int i,j;
409         int sect_cnt;
410         int size_ratio;
411         int total_size;
412         enum uaddr uaddr_idx;
413
414         size_ratio = info->portwidth / info->chipwidth;
415
416         debug("Found JEDEC Flash: %s\n", jedec_entry->name);
417         info->vendor = jedec_entry->CmdSet;
418         /* Todo: do we need device-specific timeouts? */
419         info->erase_blk_tout = 30000;
420         info->buffer_write_tout = 1000;
421         info->write_tout = 100;
422         info->name = jedec_entry->name;
423
424         /* copy unlock addresses from device table to CFI info struct. This
425            is just here because the addresses are in the table anyway - if
426            the flash is not detected due to wrong unlock addresses,
427            flash_detect_legacy would have to try all of them before we even
428            get here. */
429         switch(info->chipwidth) {
430         case FLASH_CFI_8BIT:
431                 uaddr_idx = jedec_entry->uaddr[0];
432                 break;
433         case FLASH_CFI_16BIT:
434                 uaddr_idx = jedec_entry->uaddr[1];
435                 break;
436         case FLASH_CFI_32BIT:
437                 uaddr_idx = jedec_entry->uaddr[2];
438                 break;
439         default:
440                 uaddr_idx = MTD_UADDR_NOT_SUPPORTED;
441                 break;
442         }
443
444         debug("unlock address index %d\n", uaddr_idx);
445         info->addr_unlock1 = unlock_addrs[uaddr_idx].addr1;
446         info->addr_unlock2 = unlock_addrs[uaddr_idx].addr2;
447         debug("unlock addresses are 0x%lx/0x%lx\n",
448                 info->addr_unlock1, info->addr_unlock2);
449
450         sect_cnt = 0;
451         total_size = 0;
452         for (i = 0; i < jedec_entry->NumEraseRegions; i++) {
453                 ulong erase_region_size = jedec_entry->regions[i] >> 8;
454                 ulong erase_region_count = (jedec_entry->regions[i] & 0xff) + 1;
455
456                 total_size += erase_region_size * erase_region_count;
457                 debug("erase_region_count = %ld erase_region_size = %ld\n",
458                        erase_region_count, erase_region_size);
459                 for (j = 0; j < erase_region_count; j++) {
460                         if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {
461                                 printf("ERROR: too many flash sectors\n");
462                                 break;
463                         }
464                         info->start[sect_cnt] = base;
465                         base += (erase_region_size * size_ratio);
466                         sect_cnt++;
467                 }
468         }
469         info->sector_count = sect_cnt;
470         info->size = total_size * size_ratio;
471 }
472
473 /*-----------------------------------------------------------------------
474  * match jedec ids against table. If a match is found, fill flash_info entry
475  */
476 int jedec_flash_match(flash_info_t *info, ulong base)
477 {
478         int ret = 0;
479         int i;
480         ulong mask = 0xFFFF;
481         if (info->chipwidth == 1)
482                 mask = 0xFF;
483
484         for (i = 0; i < ARRAY_SIZE(jedec_table); i++) {
485                 if ((jedec_table[i].mfr_id & mask) == (info->manufacturer_id & mask) &&
486                     (jedec_table[i].dev_id & mask) == (info->device_id & mask)) {
487                         fill_info(info, &jedec_table[i], base);
488                         ret = 1;
489                         break;
490                 }
491         }
492         return ret;
493 }