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