1 /*
2  * (C) Copyright 2000-2003
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
6  * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
7  *
8  * See file CREDITS for list of people who contributed to this
9  * project.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation; either version 2 of
14  * the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24  * MA 02111-1307 USA
25  */
26 
27 #include <common.h>
28 
29 #include <asm/immap.h>
30 
31 #ifndef CONFIG_SYS_FLASH_CFI
32 typedef unsigned short FLASH_PORT_WIDTH;
33 typedef volatile unsigned short FLASH_PORT_WIDTHV;
34 
35 #define FPW             FLASH_PORT_WIDTH
36 #define FPWV            FLASH_PORT_WIDTHV
37 
38 #define FLASH_CYCLE1    0x5555
39 #define FLASH_CYCLE2    0x2aaa
40 
41 #define SYNC			__asm__("nop")
42 
43 /*-----------------------------------------------------------------------
44  * Functions
45  */
46 
47 ulong flash_get_size(FPWV * addr, flash_info_t * info);
48 int flash_get_offsets(ulong base, flash_info_t * info);
49 int write_word(flash_info_t * info, FPWV * dest, u16 data);
50 void inline spin_wheel(void);
51 
52 flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
53 
54 ulong flash_init(void)
55 {
56 	ulong size = 0;
57 	ulong fbase = 0;
58 
59 	fbase = (ulong) CONFIG_SYS_FLASH_BASE;
60 	flash_get_size((FPWV *) fbase, &flash_info[0]);
61 	flash_get_offsets((ulong) fbase, &flash_info[0]);
62 	fbase += flash_info[0].size;
63 	size += flash_info[0].size;
64 
65 	/* Protect monitor and environment sectors */
66 	flash_protect(FLAG_PROTECT_SET,
67 		      CONFIG_SYS_MONITOR_BASE,
68 		      CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, &flash_info[0]);
69 
70 	return size;
71 }
72 
73 int flash_get_offsets(ulong base, flash_info_t * info)
74 {
75 	int j, k;
76 
77 	if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
78 
79 		info->start[0] = base;
80 		for (k = 0, j = 0; j < CONFIG_SYS_SST_SECT; j++, k++) {
81 			info->start[k + 1] = info->start[k] + CONFIG_SYS_SST_SECTSZ;
82 			info->protect[k] = 0;
83 		}
84 	}
85 
86 	return ERR_OK;
87 }
88 
89 void flash_print_info(flash_info_t * info)
90 {
91 	int i;
92 
93 	switch (info->flash_id & FLASH_VENDMASK) {
94 	case FLASH_MAN_SST:
95 		printf("SST ");
96 		break;
97 	default:
98 		printf("Unknown Vendor ");
99 		break;
100 	}
101 
102 	switch (info->flash_id & FLASH_TYPEMASK) {
103 	case FLASH_SST6401B:
104 		printf("SST39VF6401B\n");
105 		break;
106 	default:
107 		printf("Unknown Chip Type\n");
108 		return;
109 	}
110 
111 	if (info->size > 0x100000) {
112 		int remainder;
113 
114 		printf("  Size: %ld", info->size >> 20);
115 
116 		remainder = (info->size % 0x100000);
117 		if (remainder) {
118 			remainder >>= 10;
119 			remainder = (int)((float)
120 					  (((float)remainder / (float)1024) *
121 					   10000));
122 			printf(".%d ", remainder);
123 		}
124 
125 		printf("MB in %d Sectors\n", info->sector_count);
126 	} else
127 		printf("  Size: %ld KB in %d Sectors\n",
128 		       info->size >> 10, info->sector_count);
129 
130 	printf("  Sector Start Addresses:");
131 	for (i = 0; i < info->sector_count; ++i) {
132 		if ((i % 5) == 0)
133 			printf("\n   ");
134 		printf(" %08lX%s",
135 		       info->start[i], info->protect[i] ? " (RO)" : "     ");
136 	}
137 	printf("\n");
138 }
139 
140 /*
141  * The following code cannot be run from FLASH!
142  */
143 ulong flash_get_size(FPWV * addr, flash_info_t * info)
144 {
145 	u16 value;
146 
147 	addr[FLASH_CYCLE1] = (FPWV) 0x00AA00AA;	/* for Atmel, Intel ignores this */
148 	addr[FLASH_CYCLE2] = (FPWV) 0x00550055;	/* for Atmel, Intel ignores this */
149 	addr[FLASH_CYCLE1] = (FPWV) 0x00900090;	/* selects Intel or Atmel */
150 
151 	switch (addr[0] & 0xffff) {
152 	case (u8) SST_MANUFACT:
153 		info->flash_id = FLASH_MAN_SST;
154 		value = addr[1];
155 		break;
156 	default:
157 		printf("Unknown Flash\n");
158 		info->flash_id = FLASH_UNKNOWN;
159 		info->sector_count = 0;
160 		info->size = 0;
161 
162 		*addr = (FPW) 0x00F000F0;
163 		return (0);	/* no or unknown flash  */
164 	}
165 
166 	switch (value) {
167 	case (u16) SST_ID_xF6401B:
168 		info->flash_id += FLASH_SST6401B;
169 		break;
170 	default:
171 		info->flash_id = FLASH_UNKNOWN;
172 		break;
173 	}
174 
175 	info->sector_count = 0;
176 	info->size = 0;
177 	info->sector_count = CONFIG_SYS_SST_SECT;
178 	info->size = CONFIG_SYS_SST_SECT * CONFIG_SYS_SST_SECTSZ;
179 
180 	/* reset ID mode */
181 	*addr = (FPWV) 0x00F000F0;
182 
183 	if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) {
184 		printf("** ERROR: sector count %d > max (%d) **\n",
185 		       info->sector_count, CONFIG_SYS_MAX_FLASH_SECT);
186 		info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
187 	}
188 
189 	return (info->size);
190 }
191 
192 int flash_erase(flash_info_t * info, int s_first, int s_last)
193 {
194 	FPWV *addr;
195 	int flag, prot, sect, count;
196 	ulong type, start, last;
197 	int rcode = 0, flashtype = 0;
198 
199 	if ((s_first < 0) || (s_first > s_last)) {
200 		if (info->flash_id == FLASH_UNKNOWN)
201 			printf("- missing\n");
202 		else
203 			printf("- no sectors to erase\n");
204 		return 1;
205 	}
206 
207 	type = (info->flash_id & FLASH_VENDMASK);
208 
209 	switch (type) {
210 	case FLASH_MAN_SST:
211 		flashtype = 1;
212 		break;
213 	default:
214 		type = (info->flash_id & FLASH_VENDMASK);
215 		printf("Can't erase unknown flash type %08lx - aborted\n",
216 		       info->flash_id);
217 		return 1;
218 	}
219 
220 	prot = 0;
221 	for (sect = s_first; sect <= s_last; ++sect) {
222 		if (info->protect[sect]) {
223 			prot++;
224 		}
225 	}
226 
227 	if (prot)
228 		printf("- Warning: %d protected sectors will not be erased!\n",
229 		       prot);
230 	else
231 		printf("\n");
232 
233 	flag = disable_interrupts();
234 
235 	start = get_timer(0);
236 	last = start;
237 
238 	if ((s_last - s_first) == (CONFIG_SYS_SST_SECT - 1)) {
239 		if (prot == 0) {
240 			addr = (FPWV *) info->start[0];
241 
242 			addr[FLASH_CYCLE1] = 0x00AA;	/* unlock */
243 			addr[FLASH_CYCLE2] = 0x0055;	/* unlock */
244 			addr[FLASH_CYCLE1] = 0x0080;	/* erase mode */
245 			addr[FLASH_CYCLE1] = 0x00AA;	/* unlock */
246 			addr[FLASH_CYCLE2] = 0x0055;	/* unlock */
247 			*addr = 0x0030;	/* erase chip */
248 
249 			count = 0;
250 			start = get_timer(0);
251 
252 			while ((*addr & 0x0080) != 0x0080) {
253 				if (count++ > 0x10000) {
254 					spin_wheel();
255 					count = 0;
256 				}
257 
258 				if (get_timer(start) > CONFIG_SYS_FLASH_ERASE_TOUT) {
259 					printf("Timeout\n");
260 					*addr = 0x00F0;	/* reset to read mode */
261 
262 					return 1;
263 				}
264 			}
265 
266 			*addr = 0x00F0;	/* reset to read mode */
267 
268 			printf("\b. done\n");
269 
270 			if (flag)
271 				enable_interrupts();
272 
273 			return 0;
274 		} else if (prot == CONFIG_SYS_SST_SECT) {
275 			return 1;
276 		}
277 	}
278 
279 	/* Start erase on unprotected sectors */
280 	for (sect = s_first; sect <= s_last; sect++) {
281 		if (info->protect[sect] == 0) {	/* not protected */
282 
283 			addr = (FPWV *) (info->start[sect]);
284 
285 			printf(".");
286 
287 			/* arm simple, non interrupt dependent timer */
288 			start = get_timer(0);
289 
290 			switch (flashtype) {
291 			case 1:
292 				{
293 					FPWV *base;	/* first address in bank */
294 
295 					flag = disable_interrupts();
296 
297 					base = (FPWV *) (CONFIG_SYS_FLASH_BASE);	/* First sector */
298 
299 					base[FLASH_CYCLE1] = 0x00AA;	/* unlock */
300 					base[FLASH_CYCLE2] = 0x0055;	/* unlock */
301 					base[FLASH_CYCLE1] = 0x0080;	/* erase mode */
302 					base[FLASH_CYCLE1] = 0x00AA;	/* unlock */
303 					base[FLASH_CYCLE2] = 0x0055;	/* unlock */
304 					*addr = 0x0050;	/* erase sector */
305 
306 					if (flag)
307 						enable_interrupts();
308 
309 					while ((*addr & 0x0080) != 0x0080) {
310 						if (get_timer(start) >
311 						    CONFIG_SYS_FLASH_ERASE_TOUT) {
312 							printf("Timeout\n");
313 							*addr = 0x00F0;	/* reset to read mode */
314 
315 							rcode = 1;
316 							break;
317 						}
318 					}
319 
320 					*addr = 0x00F0;	/* reset to read mode */
321 					break;
322 				}
323 			}	/* switch (flashtype) */
324 		}
325 	}
326 	printf(" done\n");
327 
328 	if (flag)
329 		enable_interrupts();
330 
331 	return rcode;
332 }
333 
334 int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
335 {
336 	ulong wp, count;
337 	u16 data;
338 	int rc, port_width;
339 
340 	if (info->flash_id == FLASH_UNKNOWN)
341 		return 4;
342 
343 	/* get lower word aligned address */
344 	wp = addr;
345 	port_width = sizeof(FPW);
346 
347 	/* handle unaligned start bytes */
348 	if (wp & 1) {
349 		data = *((FPWV *) wp);
350 		data = (data << 8) | *src;
351 
352 		if ((rc = write_word(info, (FPWV *) wp, data)) != 0)
353 			return (rc);
354 
355 		wp++;
356 		cnt -= 1;
357 		src++;
358 	}
359 
360 	while (cnt >= 2) {
361 		/*
362 		 * handle word aligned part
363 		 */
364 		count = 0;
365 		data = *((FPWV *) src);
366 
367 		if ((rc = write_word(info, (FPWV *) wp, data)) != 0)
368 			return (rc);
369 
370 		wp += 2;
371 		src += 2;
372 		cnt -= 2;
373 
374 		if (count++ > 0x800) {
375 			spin_wheel();
376 			count = 0;
377 		}
378 	}
379 	/* handle word aligned part */
380 	if (cnt) {
381 		/* handle word aligned part */
382 		count = 0;
383 		data = *((FPWV *) wp);
384 
385 		data = (data & 0x00FF) | (*src << 8);
386 
387 		if ((rc = write_word(info, (FPWV *) wp, data)) != 0)
388 			return (rc);
389 
390 		wp++;
391 		src++;
392 		cnt -= 1;
393 		if (count++ > 0x800) {
394 			spin_wheel();
395 			count = 0;
396 		}
397 	}
398 
399 	if (cnt == 0)
400 		return ERR_OK;
401 
402 	return ERR_OK;
403 }
404 
405 /*-----------------------------------------------------------------------
406  * Write a word to Flash
407  * A word is 16 bits, whichever the bus width of the flash bank
408  * (not an individual chip) is.
409  *
410  * returns:
411  * 0 - OK
412  * 1 - write timeout
413  * 2 - Flash not erased
414  */
415 int write_word(flash_info_t * info, FPWV * dest, u16 data)
416 {
417 	ulong start;
418 	int flag;
419 	int res = 0;		/* result, assume success */
420 	FPWV *base;		/* first address in flash bank */
421 
422 	/* Check if Flash is (sufficiently) erased */
423 	if ((*dest & (u8) data) != (u8) data) {
424 		return (2);
425 	}
426 
427 	base = (FPWV *) (CONFIG_SYS_FLASH_BASE);
428 
429 	/* Disable interrupts which might cause a timeout here */
430 	flag = disable_interrupts();
431 
432 	base[FLASH_CYCLE1] = (u8) 0x00AA00AA;	/* unlock */
433 	base[FLASH_CYCLE2] = (u8) 0x00550055;	/* unlock */
434 	base[FLASH_CYCLE1] = (u8) 0x00A000A0;	/* selects program mode */
435 
436 	*dest = data;		/* start programming the data */
437 
438 	/* re-enable interrupts if necessary */
439 	if (flag)
440 		enable_interrupts();
441 
442 	start = get_timer(0);
443 
444 	/* data polling for D7 */
445 	while (res == 0
446 	       && (*dest & (u8) 0x00800080) != (data & (u8) 0x00800080)) {
447 		if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
448 			*dest = (u8) 0x00F000F0;	/* reset bank */
449 			res = 1;
450 		}
451 	}
452 
453 	*dest++ = (u8) 0x00F000F0;	/* reset bank */
454 
455 	return (res);
456 }
457 
458 void inline spin_wheel(void)
459 {
460 	static int p = 0;
461 	static char w[] = "\\/-";
462 
463 	printf("\010%c", w[p]);
464 	(++p == 3) ? (p = 0) : 0;
465 }
466 
467 #endif
468