xref: /openbmc/u-boot/drivers/mtd/jedec_flash.c (revision 7ca6f363)
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)STM_MANUFACT,
337 		.dev_id		= STM29F400BB,
338 		.name		= "ST Micro M29F400BB",
339 		.uaddr		= {
340 			[1] = MTD_UADDR_0x0555_0x02AA /* x16 */
341 		},
342 		.DevSize		= SIZE_512KiB,
343 		.CmdSet			= CFI_CMDSET_AMD_LEGACY,
344 		.NumEraseRegions	= 4,
345 		.regions		= {
346 			ERASEINFO(0x04000, 1),
347 			ERASEINFO(0x02000, 2),
348 			ERASEINFO(0x08000, 1),
349 			ERASEINFO(0x10000, 7),
350 		}
351 	},
352 #endif
353 };
354 
355 static inline void fill_info(flash_info_t *info, const struct amd_flash_info *jedec_entry, ulong base)
356 {
357 	int i,j;
358 	int sect_cnt;
359 	int size_ratio;
360 	int total_size;
361 	enum uaddr uaddr_idx;
362 
363 	size_ratio = info->portwidth / info->chipwidth;
364 
365 	debug("Found JEDEC Flash: %s\n", jedec_entry->name);
366 	info->vendor = jedec_entry->CmdSet;
367 	/* Todo: do we need device-specific timeouts? */
368 	info->erase_blk_tout = 30000;
369 	info->buffer_write_tout = 1000;
370 	info->write_tout = 100;
371 	info->name = jedec_entry->name;
372 
373 	/* copy unlock addresses from device table to CFI info struct. This
374 	   is just here because the addresses are in the table anyway - if
375 	   the flash is not detected due to wrong unlock addresses,
376 	   flash_detect_legacy would have to try all of them before we even
377 	   get here. */
378 	switch(info->chipwidth) {
379 	case FLASH_CFI_8BIT:
380 		uaddr_idx = jedec_entry->uaddr[0];
381 		break;
382 	case FLASH_CFI_16BIT:
383 		uaddr_idx = jedec_entry->uaddr[1];
384 		break;
385 	case FLASH_CFI_32BIT:
386 		uaddr_idx = jedec_entry->uaddr[2];
387 		break;
388 	default:
389 		uaddr_idx = MTD_UADDR_NOT_SUPPORTED;
390 		break;
391 	}
392 
393 	debug("unlock address index %d\n", uaddr_idx);
394 	info->addr_unlock1 = unlock_addrs[uaddr_idx].addr1;
395 	info->addr_unlock2 = unlock_addrs[uaddr_idx].addr2;
396 	debug("unlock addresses are 0x%lx/0x%lx\n",
397 		info->addr_unlock1, info->addr_unlock2);
398 
399 	sect_cnt = 0;
400 	total_size = 0;
401 	for (i = 0; i < jedec_entry->NumEraseRegions; i++) {
402 		ulong erase_region_size = jedec_entry->regions[i] >> 8;
403 		ulong erase_region_count = (jedec_entry->regions[i] & 0xff) + 1;
404 
405 		total_size += erase_region_size * erase_region_count;
406 		debug("erase_region_count = %ld erase_region_size = %ld\n",
407 		       erase_region_count, erase_region_size);
408 		for (j = 0; j < erase_region_count; j++) {
409 			if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {
410 				printf("ERROR: too many flash sectors\n");
411 				break;
412 			}
413 			info->start[sect_cnt] = base;
414 			base += (erase_region_size * size_ratio);
415 			sect_cnt++;
416 		}
417 	}
418 	info->sector_count = sect_cnt;
419 	info->size = total_size * size_ratio;
420 }
421 
422 /*-----------------------------------------------------------------------
423  * match jedec ids against table. If a match is found, fill flash_info entry
424  */
425 int jedec_flash_match(flash_info_t *info, ulong base)
426 {
427 	int ret = 0;
428 	int i;
429 	ulong mask = 0xFFFF;
430 	if (info->chipwidth == 1)
431 		mask = 0xFF;
432 
433 	for (i = 0; i < ARRAY_SIZE(jedec_table); i++) {
434 		if ((jedec_table[i].mfr_id & mask) == (info->manufacturer_id & mask) &&
435 		    (jedec_table[i].dev_id & mask) == (info->device_id & mask)) {
436 			fill_info(info, &jedec_table[i], base);
437 			ret = 1;
438 			break;
439 		}
440 	}
441 	return ret;
442 }
443