1/*
2   Common Flash Interface probe code.
3   (C) 2000 Red Hat. GPL'd.
4   $Id: jedec_probe.c,v 1.1.1.1 2008/10/15 03:26:35 james26_jang Exp $
5*/
6
7#include <linux/config.h>
8#include <linux/module.h>
9#include <linux/types.h>
10#include <linux/kernel.h>
11#include <asm/io.h>
12#include <asm/byteorder.h>
13#include <linux/errno.h>
14#include <linux/slab.h>
15#include <linux/interrupt.h>
16
17#include <linux/mtd/map.h>
18#include <linux/mtd/cfi.h>
19#include <linux/mtd/gen_probe.h>
20
21
22/* Manufacturers */
23#define MANUFACTURER_AMD	0x0001
24#define MANUFACTURER_FUJITSU	0x0004
25#define MANUFACTURER_ATMEL	0x001f
26#define MANUFACTURER_ST		0x0020
27#define MANUFACTURER_SST	0x00BF
28#define MANUFACTURER_TOSHIBA	0x0098
29
30/* AMD */
31#define AM29F800BB	0x2258
32#define AM29F800BT	0x22D6
33#define AM29LV800BB	0x225B
34#define AM29LV800BT	0x22DA
35#define AM29LV160DT	0x22C4
36#define AM29LV160DB	0x2249
37
38/* Atmel */
39#define AT49BV16X4	0x00c0
40#define AT49BV16X4T	0x00c2
41
42/* Fujitsu */
43#define MBM29LV160TE	0x22C4
44#define MBM29LV160BE	0x2249
45
46/* ST - www.st.com */
47#define M29W800T	0x00D7
48#define M29W160DT	0x22C4
49#define M29W160DB	0x2249
50
51/* SST */
52#define SST39LF800	0x2781
53#define SST39LF160	0x2782
54
55/* Toshiba */
56#define TC58FVT160	0x00C2
57#define TC58FVB160	0x0043
58
59
60struct amd_flash_info {
61	const __u16 mfr_id;
62	const __u16 dev_id;
63	const char *name;
64	const int DevSize;
65	const int InterfaceDesc;
66	const int NumEraseRegions;
67	const ulong regions[4];
68};
69
70#define ERASEINFO(size,blocks) (size<<8)|(blocks-1)
71
72#define SIZE_1MiB 20
73#define SIZE_2MiB 21
74#define SIZE_4MiB 22
75
76static const struct amd_flash_info jedec_table[] = {
77	{
78		mfr_id: MANUFACTURER_AMD,
79		dev_id: AM29LV160DT,
80		name: "AMD AM29LV160DT",
81		DevSize: SIZE_2MiB,
82		NumEraseRegions: 4,
83		regions: {ERASEINFO(0x10000,31),
84			  ERASEINFO(0x08000,1),
85			  ERASEINFO(0x02000,2),
86			  ERASEINFO(0x04000,1)
87		}
88	}, {
89		mfr_id: MANUFACTURER_AMD,
90		dev_id: AM29LV160DB,
91		name: "AMD AM29LV160DB",
92		DevSize: SIZE_2MiB,
93		NumEraseRegions: 4,
94		regions: {ERASEINFO(0x04000,1),
95			  ERASEINFO(0x02000,2),
96			  ERASEINFO(0x08000,1),
97			  ERASEINFO(0x10000,31)
98		}
99	}, {
100		mfr_id: MANUFACTURER_TOSHIBA,
101		dev_id: TC58FVT160,
102		name: "Toshiba TC58FVT160",
103		DevSize: SIZE_2MiB,
104		NumEraseRegions: 4,
105		regions: {ERASEINFO(0x10000,31),
106			  ERASEINFO(0x08000,1),
107			  ERASEINFO(0x02000,2),
108			  ERASEINFO(0x04000,1)
109		}
110	}, {
111		mfr_id: MANUFACTURER_FUJITSU,
112		dev_id: MBM29LV160TE,
113		name: "Fujitsu MBM29LV160TE",
114		DevSize: SIZE_2MiB,
115		NumEraseRegions: 4,
116		regions: {ERASEINFO(0x10000,31),
117			  ERASEINFO(0x08000,1),
118			  ERASEINFO(0x02000,2),
119			  ERASEINFO(0x04000,1)
120		}
121	}, {
122		mfr_id: MANUFACTURER_TOSHIBA,
123		dev_id: TC58FVB160,
124		name: "Toshiba TC58FVB160",
125		DevSize: SIZE_2MiB,
126		NumEraseRegions: 4,
127		regions: {ERASEINFO(0x04000,1),
128			  ERASEINFO(0x02000,2),
129			  ERASEINFO(0x08000,1),
130			  ERASEINFO(0x10000,31)
131		}
132	}, {
133		mfr_id: MANUFACTURER_FUJITSU,
134		dev_id: MBM29LV160BE,
135		name: "Fujitsu MBM29LV160BE",
136		DevSize: SIZE_2MiB,
137		NumEraseRegions: 4,
138		regions: {ERASEINFO(0x04000,1),
139			  ERASEINFO(0x02000,2),
140			  ERASEINFO(0x08000,1),
141			  ERASEINFO(0x10000,31)
142		}
143	}, {
144		mfr_id: MANUFACTURER_AMD,
145		dev_id: AM29LV800BB,
146		name: "AMD AM29LV800BB",
147		DevSize: SIZE_1MiB,
148		NumEraseRegions: 4,
149		regions: {ERASEINFO(0x04000,1),
150			  ERASEINFO(0x02000,2),
151			  ERASEINFO(0x08000,1),
152			  ERASEINFO(0x10000,15),
153		}
154	}, {
155		mfr_id: MANUFACTURER_AMD,
156		dev_id: AM29F800BB,
157		name: "AMD AM29F800BB",
158		DevSize: SIZE_1MiB,
159		NumEraseRegions: 4,
160		regions: {ERASEINFO(0x04000,1),
161			  ERASEINFO(0x02000,2),
162			  ERASEINFO(0x08000,1),
163			  ERASEINFO(0x10000,15),
164		}
165	}, {
166		mfr_id: MANUFACTURER_AMD,
167		dev_id: AM29LV800BT,
168		name: "AMD AM29LV800BT",
169		DevSize: SIZE_1MiB,
170		NumEraseRegions: 4,
171		regions: {ERASEINFO(0x10000,15),
172			  ERASEINFO(0x08000,1),
173			  ERASEINFO(0x02000,2),
174			  ERASEINFO(0x04000,1)
175		}
176	}, {
177		mfr_id: MANUFACTURER_AMD,
178		dev_id: AM29F800BT,
179		name: "AMD AM29F800BT",
180		DevSize: SIZE_1MiB,
181		NumEraseRegions: 4,
182		regions: {ERASEINFO(0x10000,15),
183			  ERASEINFO(0x08000,1),
184			  ERASEINFO(0x02000,2),
185			  ERASEINFO(0x04000,1)
186		}
187	}, {
188		mfr_id: MANUFACTURER_AMD,
189		dev_id: AM29LV800BB,
190		name: "AMD AM29LV800BB",
191		DevSize: SIZE_1MiB,
192		NumEraseRegions: 4,
193		regions: {ERASEINFO(0x10000,15),
194			  ERASEINFO(0x08000,1),
195			  ERASEINFO(0x02000,2),
196			  ERASEINFO(0x04000,1)
197		}
198	}, {
199		mfr_id: MANUFACTURER_ST,
200		dev_id: M29W800T,
201		name: "ST M29W800T",
202		DevSize: SIZE_1MiB,
203		NumEraseRegions: 4,
204		regions: {ERASEINFO(0x10000,15),
205			  ERASEINFO(0x08000,1),
206			  ERASEINFO(0x02000,2),
207			  ERASEINFO(0x04000,1)
208		}
209	}, {
210		mfr_id: MANUFACTURER_ST,
211		dev_id: M29W160DT,
212		name: "ST M29W160DT",
213		DevSize: SIZE_2MiB,
214		NumEraseRegions: 4,
215		regions: {ERASEINFO(0x10000,31),
216			  ERASEINFO(0x08000,1),
217			  ERASEINFO(0x02000,2),
218			  ERASEINFO(0x04000,1)
219		}
220	}, {
221		mfr_id: MANUFACTURER_ST,
222		dev_id: M29W160DB,
223		name: "ST M29W160DB",
224		DevSize: SIZE_2MiB,
225		NumEraseRegions: 4,
226		regions: {ERASEINFO(0x04000,1),
227			  ERASEINFO(0x02000,2),
228			  ERASEINFO(0x08000,1),
229			  ERASEINFO(0x10000,31)
230		}
231	}, {
232		mfr_id: MANUFACTURER_ATMEL,
233		dev_id: AT49BV16X4,
234		name: "Atmel AT49BV16X4",
235		DevSize: SIZE_2MiB,
236		NumEraseRegions: 3,
237		regions: {ERASEINFO(0x02000,8),
238			  ERASEINFO(0x08000,2),
239			  ERASEINFO(0x10000,30)
240		}
241	}, {
242                mfr_id: MANUFACTURER_ATMEL,
243                dev_id: AT49BV16X4T,
244                name: "Atmel AT49BV16X4T",
245                DevSize: SIZE_2MiB,
246                NumEraseRegions: 3,
247                regions: {ERASEINFO(0x10000,30),
248                          ERASEINFO(0x08000,2),
249			  ERASEINFO(0x02000,8)
250                }
251	}
252};
253
254
255static int cfi_jedec_setup(struct cfi_private *p_cfi, int index);
256
257static int jedec_probe_chip(struct map_info *map, __u32 base,
258			    struct flchip *chips, struct cfi_private *cfi);
259
260struct mtd_info *jedec_probe(struct map_info *map);
261#define jedec_read_mfr(map, base, osf) cfi_read(map, base)
262#define jedec_read_id(map, base, osf) cfi_read(map, (base)+(osf))
263
264static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
265{
266	int i,num_erase_regions;
267
268	printk("Found: %s\n",jedec_table[index].name);
269
270	num_erase_regions = jedec_table[index].NumEraseRegions;
271
272	p_cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL);
273	if (!p_cfi->cfiq) {
274		//xx printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name);
275		return 0;
276	}
277
278	memset(p_cfi->cfiq,0,sizeof(struct cfi_ident));
279
280	p_cfi->cfiq->P_ID = P_ID_AMD_STD;
281	p_cfi->cfiq->NumEraseRegions = jedec_table[index].NumEraseRegions;
282	p_cfi->cfiq->DevSize = jedec_table[index].DevSize;
283
284	for (i=0; i<num_erase_regions; i++){
285		p_cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i];
286	}
287	return 1; 	/* ok */
288}
289
290static int jedec_probe_chip(struct map_info *map, __u32 base,
291			      struct flchip *chips, struct cfi_private *cfi)
292{
293	int i;
294	int osf = cfi->interleave * cfi->device_type;
295	int retried = 0;
296
297	if (!cfi->numchips) {
298		switch (cfi->device_type) {
299		case CFI_DEVICETYPE_X8:
300			cfi->addr_unlock1 = 0x555;
301			cfi->addr_unlock2 = 0x2aa;
302			break;
303		case CFI_DEVICETYPE_X16:
304			cfi->addr_unlock1 = 0xaaa;
305			if (map->buswidth == cfi->interleave) {
306				/* X16 chip(s) in X8 mode */
307				cfi->addr_unlock2 = 0x555;
308			} else {
309				cfi->addr_unlock2 = 0x554;
310			}
311			break;
312		case CFI_DEVICETYPE_X32:
313			cfi->addr_unlock1 = 0x1555;
314			cfi->addr_unlock2 = 0xaaa;
315			break;
316		default:
317			printk(KERN_NOTICE "Eep. Unknown jedec_probe device type %d\n", cfi->device_type);
318		return 0;
319		}
320	}
321
322 retry:
323	/* Reset */
324	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
325
326	/* Autoselect Mode */
327	cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
328	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
329	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
330
331	if (!cfi->numchips) {
332		/* This is the first time we're called. Set up the CFI
333		   stuff accordingly and return */
334
335		cfi->mfr = jedec_read_mfr(map, base, osf);
336		cfi->id = jedec_read_id(map, base, osf);
337
338		for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) {
339			if (cfi->mfr == jedec_table[i].mfr_id &&
340			    cfi->id == jedec_table[i].dev_id)
341				return cfi_jedec_setup(cfi, i);
342		}
343		if (!retried++) {
344			/* Deal with whichever strange chips these were */
345			cfi->addr_unlock1 |= cfi->addr_unlock1 << 8;
346			cfi->addr_unlock2 |= cfi->addr_unlock2 << 8;
347			goto retry;
348		}
349		return 0;
350	}
351
352	/* Check each previous chip to see if it's an alias */
353	for (i=0; i<cfi->numchips; i++) {
354		/* This chip should be in read mode if it's one
355		   we've already touched. */
356		if (jedec_read_mfr(map, base, osf) == cfi->mfr &&
357		    jedec_read_id(map, base, osf) == cfi->id) {
358			/* Eep. This chip also looks like it's in autoselect mode.
359			   Is it an alias for the new one? */
360
361			cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL);
362			/* If the device IDs go away, it's an alias */
363			if (jedec_read_mfr(map, base, osf) != cfi->mfr ||
364			    jedec_read_id(map, base, osf) != cfi->id) {
365				printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
366				       map->name, base, chips[i].start);
367				return 0;
368			}
369
370			/* Yes, it's actually got the device IDs as data. Most
371			 * unfortunate. Stick the new chip in read mode
372			 * too and if it's the same, assume it's an alias. */
373			cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
374			if (jedec_read_mfr(map, base, osf) == cfi->mfr &&
375			    jedec_read_id(map, base, osf) == cfi->id) {
376				printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
377				       map->name, base, chips[i].start);
378				return 0;
379			}
380		}
381	}
382
383	/* OK, if we got to here, then none of the previous chips appear to
384	   be aliases for the current one. */
385	if (cfi->numchips == MAX_CFI_CHIPS) {
386		printk(KERN_WARNING"%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS);
387		/* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */
388		return -1;
389	}
390	chips[cfi->numchips].start = base;
391	chips[cfi->numchips].state = FL_READY;
392	cfi->numchips++;
393
394	/* Put it back into Read Mode */
395	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
396
397	printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n",
398	       map->name, cfi->interleave, cfi->device_type*8, base,
399	       map->buswidth*8);
400
401	return 1;
402}
403
404static struct chip_probe jedec_chip_probe = {
405	name: "JEDEC",
406	probe_chip: jedec_probe_chip
407};
408
409struct mtd_info *jedec_probe(struct map_info *map)
410{
411	/*
412	 * Just use the generic probe stuff to call our CFI-specific
413	 * chip_probe routine in all the possible permutations, etc.
414	 */
415	return mtd_do_chip_probe(map, &jedec_chip_probe);
416}
417
418static struct mtd_chip_driver jedec_chipdrv = {
419	probe: jedec_probe,
420	name: "jedec_probe",
421	module: THIS_MODULE
422};
423
424int __init jedec_probe_init(void)
425{
426	register_mtd_chip_driver(&jedec_chipdrv);
427	return 0;
428}
429
430static void __exit jedec_probe_exit(void)
431{
432	unregister_mtd_chip_driver(&jedec_chipdrv);
433}
434
435module_init(jedec_probe_init);
436module_exit(jedec_probe_exit);
437
438MODULE_LICENSE("GPL");
439MODULE_AUTHOR("Erwin Authried <eauth@softsys.co.at> et al.");
440MODULE_DESCRIPTION("Probe code for JEDEC-compliant flash chips");
441