xref: /openbmc/linux/drivers/mtd/chips/cfi_util.c (revision 87194aba)
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_LICENSE("GPL");
445