1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * Common Flash Interface support:
4   *   Generic utility functions not dependent on command set
5   *
6   * Copyright (C) 2002 Red Hat
7   * Copyright (C) 2003 STMicroelectronics Limited
8   */
9  
10  #include <linux/module.h>
11  #include <linux/types.h>
12  #include <linux/kernel.h>
13  #include <asm/io.h>
14  #include <asm/byteorder.h>
15  
16  #include <linux/errno.h>
17  #include <linux/slab.h>
18  #include <linux/delay.h>
19  #include <linux/interrupt.h>
20  #include <linux/mtd/xip.h>
21  #include <linux/mtd/mtd.h>
22  #include <linux/mtd/map.h>
23  #include <linux/mtd/cfi.h>
24  
cfi_udelay(int us)25  void cfi_udelay(int us)
26  {
27  	if (us >= 1000) {
28  		msleep(DIV_ROUND_UP(us, 1000));
29  	} else {
30  		udelay(us);
31  		cond_resched();
32  	}
33  }
34  EXPORT_SYMBOL(cfi_udelay);
35  
36  /*
37   * Returns the command address according to the given geometry.
38   */
cfi_build_cmd_addr(uint32_t cmd_ofs,struct map_info * map,struct cfi_private * cfi)39  uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs,
40  				struct map_info *map, struct cfi_private *cfi)
41  {
42  	unsigned bankwidth = map_bankwidth(map);
43  	unsigned interleave = cfi_interleave(cfi);
44  	unsigned type = cfi->device_type;
45  	uint32_t addr;
46  
47  	addr = (cmd_ofs * type) * interleave;
48  
49  	/* Modify the unlock address if we are in compatibility mode.
50  	 * For 16bit devices on 8 bit busses
51  	 * and 32bit devices on 16 bit busses
52  	 * set the low bit of the alternating bit sequence of the address.
53  	 */
54  	if (((type * interleave) > bankwidth) && ((cmd_ofs & 0xff) == 0xaa))
55  		addr |= (type >> 1)*interleave;
56  
57  	return  addr;
58  }
59  EXPORT_SYMBOL(cfi_build_cmd_addr);
60  
61  /*
62   * Transforms the CFI command for the given geometry (bus width & interleave).
63   * It looks too long to be inline, but in the common case it should almost all
64   * get optimised away.
65   */
cfi_build_cmd(u_long cmd,struct map_info * map,struct cfi_private * cfi)66  map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi)
67  {
68  	map_word val = { {0} };
69  	int wordwidth, words_per_bus, chip_mode, chips_per_word;
70  	unsigned long onecmd;
71  	int i;
72  
73  	/* We do it this way to give the compiler a fighting chance
74  	   of optimising away all the crap for 'bankwidth' larger than
75  	   an unsigned long, in the common case where that support is
76  	   disabled */
77  	if (map_bankwidth_is_large(map)) {
78  		wordwidth = sizeof(unsigned long);
79  		words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1
80  	} else {
81  		wordwidth = map_bankwidth(map);
82  		words_per_bus = 1;
83  	}
84  
85  	chip_mode = map_bankwidth(map) / cfi_interleave(cfi);
86  	chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map);
87  
88  	/* First, determine what the bit-pattern should be for a single
89  	   device, according to chip mode and endianness... */
90  	switch (chip_mode) {
91  	default: BUG();
92  	case 1:
93  		onecmd = cmd;
94  		break;
95  	case 2:
96  		onecmd = cpu_to_cfi16(map, cmd);
97  		break;
98  	case 4:
99  		onecmd = cpu_to_cfi32(map, cmd);
100  		break;
101  	}
102  
103  	/* Now replicate it across the size of an unsigned long, or
104  	   just to the bus width as appropriate */
105  	switch (chips_per_word) {
106  	default: BUG();
107  #if BITS_PER_LONG >= 64
108  	case 8:
109  		onecmd |= (onecmd << (chip_mode * 32));
110  		fallthrough;
111  #endif
112  	case 4:
113  		onecmd |= (onecmd << (chip_mode * 16));
114  		fallthrough;
115  	case 2:
116  		onecmd |= (onecmd << (chip_mode * 8));
117  		fallthrough;
118  	case 1:
119  		;
120  	}
121  
122  	/* And finally, for the multi-word case, replicate it
123  	   in all words in the structure */
124  	for (i=0; i < words_per_bus; i++) {
125  		val.x[i] = onecmd;
126  	}
127  
128  	return val;
129  }
130  EXPORT_SYMBOL(cfi_build_cmd);
131  
cfi_merge_status(map_word val,struct map_info * map,struct cfi_private * cfi)132  unsigned long cfi_merge_status(map_word val, struct map_info *map,
133  					   struct cfi_private *cfi)
134  {
135  	int wordwidth, words_per_bus, chip_mode, chips_per_word;
136  	unsigned long onestat, res = 0;
137  	int i;
138  
139  	/* We do it this way to give the compiler a fighting chance
140  	   of optimising away all the crap for 'bankwidth' larger than
141  	   an unsigned long, in the common case where that support is
142  	   disabled */
143  	if (map_bankwidth_is_large(map)) {
144  		wordwidth = sizeof(unsigned long);
145  		words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1
146  	} else {
147  		wordwidth = map_bankwidth(map);
148  		words_per_bus = 1;
149  	}
150  
151  	chip_mode = map_bankwidth(map) / cfi_interleave(cfi);
152  	chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map);
153  
154  	onestat = val.x[0];
155  	/* Or all status words together */
156  	for (i=1; i < words_per_bus; i++) {
157  		onestat |= val.x[i];
158  	}
159  
160  	res = onestat;
161  	switch(chips_per_word) {
162  	default: BUG();
163  #if BITS_PER_LONG >= 64
164  	case 8:
165  		res |= (onestat >> (chip_mode * 32));
166  		fallthrough;
167  #endif
168  	case 4:
169  		res |= (onestat >> (chip_mode * 16));
170  		fallthrough;
171  	case 2:
172  		res |= (onestat >> (chip_mode * 8));
173  		fallthrough;
174  	case 1:
175  		;
176  	}
177  
178  	/* Last, determine what the bit-pattern should be for a single
179  	   device, according to chip mode and endianness... */
180  	switch (chip_mode) {
181  	case 1:
182  		break;
183  	case 2:
184  		res = cfi16_to_cpu(map, res);
185  		break;
186  	case 4:
187  		res = cfi32_to_cpu(map, res);
188  		break;
189  	default: BUG();
190  	}
191  	return res;
192  }
193  EXPORT_SYMBOL(cfi_merge_status);
194  
195  /*
196   * Sends a CFI command to a bank of flash for the given geometry.
197   *
198   * Returns the offset in flash where the command was written.
199   * If prev_val is non-null, it will be set to the value at the command address,
200   * before the command was written.
201   */
cfi_send_gen_cmd(u_char cmd,uint32_t cmd_addr,uint32_t base,struct map_info * map,struct cfi_private * cfi,int type,map_word * prev_val)202  uint32_t cfi_send_gen_cmd(u_char cmd, uint32_t cmd_addr, uint32_t base,
203  				struct map_info *map, struct cfi_private *cfi,
204  				int type, map_word *prev_val)
205  {
206  	map_word val;
207  	uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, map, cfi);
208  	val = cfi_build_cmd(cmd, map, cfi);
209  
210  	if (prev_val)
211  		*prev_val = map_read(map, addr);
212  
213  	map_write(map, val, addr);
214  
215  	return addr - base;
216  }
217  EXPORT_SYMBOL(cfi_send_gen_cmd);
218  
cfi_qry_present(struct map_info * map,__u32 base,struct cfi_private * cfi)219  int __xipram cfi_qry_present(struct map_info *map, __u32 base,
220  			     struct cfi_private *cfi)
221  {
222  	int osf = cfi->interleave * cfi->device_type;	/* scale factor */
223  	map_word val[3];
224  	map_word qry[3];
225  
226  	qry[0] = cfi_build_cmd('Q', map, cfi);
227  	qry[1] = cfi_build_cmd('R', map, cfi);
228  	qry[2] = cfi_build_cmd('Y', map, cfi);
229  
230  	val[0] = map_read(map, base + osf*0x10);
231  	val[1] = map_read(map, base + osf*0x11);
232  	val[2] = map_read(map, base + osf*0x12);
233  
234  	if (!map_word_equal(map, qry[0], val[0]))
235  		return 0;
236  
237  	if (!map_word_equal(map, qry[1], val[1]))
238  		return 0;
239  
240  	if (!map_word_equal(map, qry[2], val[2]))
241  		return 0;
242  
243  	return 1; 	/* "QRY" found */
244  }
245  EXPORT_SYMBOL_GPL(cfi_qry_present);
246  
cfi_qry_mode_on(uint32_t base,struct map_info * map,struct cfi_private * cfi)247  int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map,
248  			     struct cfi_private *cfi)
249  {
250  	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
251  	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
252  	if (cfi_qry_present(map, base, cfi))
253  		return 1;
254  	/* QRY not found probably we deal with some odd CFI chips */
255  	/* Some revisions of some old Intel chips? */
256  	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
257  	cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
258  	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
259  	if (cfi_qry_present(map, base, cfi))
260  		return 1;
261  	/* ST M29DW chips */
262  	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
263  	cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL);
264  	if (cfi_qry_present(map, base, cfi))
265  		return 1;
266  	/* some old SST chips, e.g. 39VF160x/39VF320x */
267  	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
268  	cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
269  	cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
270  	cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL);
271  	if (cfi_qry_present(map, base, cfi))
272  		return 1;
273  	/* SST 39VF640xB */
274  	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
275  	cfi_send_gen_cmd(0xAA, 0x555, base, map, cfi, cfi->device_type, NULL);
276  	cfi_send_gen_cmd(0x55, 0x2AA, base, map, cfi, cfi->device_type, NULL);
277  	cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL);
278  	if (cfi_qry_present(map, base, cfi))
279  		return 1;
280  	/* QRY not found */
281  	return 0;
282  }
283  EXPORT_SYMBOL_GPL(cfi_qry_mode_on);
284  
cfi_qry_mode_off(uint32_t base,struct map_info * map,struct cfi_private * cfi)285  void __xipram cfi_qry_mode_off(uint32_t base, struct map_info *map,
286  			       struct cfi_private *cfi)
287  {
288  	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
289  	cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
290  	/* M29W128G flashes require an additional reset command
291  	   when exit qry mode */
292  	if ((cfi->mfr == CFI_MFR_ST) && (cfi->id == 0x227E || cfi->id == 0x7E))
293  		cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
294  }
295  EXPORT_SYMBOL_GPL(cfi_qry_mode_off);
296  
297  struct cfi_extquery *
cfi_read_pri(struct map_info * map,__u16 adr,__u16 size,const char * name)298  __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
299  {
300  	struct cfi_private *cfi = map->fldrv_priv;
301  	__u32 base = 0; // cfi->chips[0].start;
302  	int ofs_factor = cfi->interleave * cfi->device_type;
303  	int i;
304  	struct cfi_extquery *extp = NULL;
305  
306  	if (!adr)
307  		goto out;
308  
309  	printk(KERN_INFO "%s Extended Query Table at 0x%4.4X\n", name, adr);
310  
311  	extp = kmalloc(size, GFP_KERNEL);
312  	if (!extp)
313  		goto out;
314  
315  #ifdef CONFIG_MTD_XIP
316  	local_irq_disable();
317  #endif
318  
319  	/* Switch it into Query Mode */
320  	cfi_qry_mode_on(base, map, cfi);
321  	/* Read in the Extended Query Table */
322  	for (i=0; i<size; i++) {
323  		((unsigned char *)extp)[i] =
324  			cfi_read_query(map, base+((adr+i)*ofs_factor));
325  	}
326  
327  	/* Make sure it returns to read mode */
328  	cfi_qry_mode_off(base, map, cfi);
329  
330  #ifdef CONFIG_MTD_XIP
331  	(void) map_read(map, base);
332  	xip_iprefetch();
333  	local_irq_enable();
334  #endif
335  
336   out:	return extp;
337  }
338  
339  EXPORT_SYMBOL(cfi_read_pri);
340  
cfi_fixup(struct mtd_info * mtd,struct cfi_fixup * fixups)341  void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup *fixups)
342  {
343  	struct map_info *map = mtd->priv;
344  	struct cfi_private *cfi = map->fldrv_priv;
345  	struct cfi_fixup *f;
346  
347  	for (f=fixups; f->fixup; f++) {
348  		if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) &&
349  		    ((f->id  == CFI_ID_ANY)  || (f->id  == cfi->id))) {
350  			f->fixup(mtd);
351  		}
352  	}
353  }
354  
355  EXPORT_SYMBOL(cfi_fixup);
356  
cfi_varsize_frob(struct mtd_info * mtd,varsize_frob_t frob,loff_t ofs,size_t len,void * thunk)357  int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
358  				     loff_t ofs, size_t len, void *thunk)
359  {
360  	struct map_info *map = mtd->priv;
361  	struct cfi_private *cfi = map->fldrv_priv;
362  	unsigned long adr;
363  	int chipnum, ret = 0;
364  	int i, first;
365  	struct mtd_erase_region_info *regions = mtd->eraseregions;
366  
367  	/* Check that both start and end of the requested erase are
368  	 * aligned with the erasesize at the appropriate addresses.
369  	 */
370  
371  	i = 0;
372  
373  	/* Skip all erase regions which are ended before the start of
374  	   the requested erase. Actually, to save on the calculations,
375  	   we skip to the first erase region which starts after the
376  	   start of the requested erase, and then go back one.
377  	*/
378  
379  	while (i < mtd->numeraseregions && ofs >= regions[i].offset)
380  	       i++;
381  	i--;
382  
383  	/* OK, now i is pointing at the erase region in which this
384  	   erase request starts. Check the start of the requested
385  	   erase range is aligned with the erase size which is in
386  	   effect here.
387  	*/
388  
389  	if (ofs & (regions[i].erasesize-1))
390  		return -EINVAL;
391  
392  	/* Remember the erase region we start on */
393  	first = i;
394  
395  	/* Next, check that the end of the requested erase is aligned
396  	 * with the erase region at that address.
397  	 */
398  
399  	while (i<mtd->numeraseregions && (ofs + len) >= regions[i].offset)
400  		i++;
401  
402  	/* As before, drop back one to point at the region in which
403  	   the address actually falls
404  	*/
405  	i--;
406  
407  	if ((ofs + len) & (regions[i].erasesize-1))
408  		return -EINVAL;
409  
410  	chipnum = ofs >> cfi->chipshift;
411  	adr = ofs - (chipnum << cfi->chipshift);
412  
413  	i=first;
414  
415  	while(len) {
416  		int size = regions[i].erasesize;
417  
418  		ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk);
419  
420  		if (ret)
421  			return ret;
422  
423  		adr += size;
424  		ofs += size;
425  		len -= size;
426  
427  		if (ofs == regions[i].offset + size * regions[i].numblocks)
428  			i++;
429  
430  		if (adr >> cfi->chipshift) {
431  			adr = 0;
432  			chipnum++;
433  
434  			if (chipnum >= cfi->numchips)
435  				break;
436  		}
437  	}
438  
439  	return 0;
440  }
441  
442  EXPORT_SYMBOL(cfi_varsize_frob);
443  
444  MODULE_DESCRIPTION("Common Flash Interface Generic utility functions");
445  MODULE_LICENSE("GPL");
446