blob: a044e8f24a9f016bb8bdde16cef6545d60035cf9 [file] [log] [blame]
wdenk945af8d2003-07-16 21:53:01 +00001/*
2 * (C) Copyright 2003
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
wdenk945af8d2003-07-16 21:53:01 +00006 */
7
8#include <common.h>
9
Jean-Christophe PLAGNIOL-VILLARD00b18832008-08-13 01:40:42 +020010#ifndef CONFIG_FLASH_CFI_DRIVER
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020011flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
wdenk945af8d2003-07-16 21:53:01 +000012
13/* NOTE - CONFIG_FLASH_16BIT means the CPU interface is 16-bit, it
14 * has nothing to do with the flash chip being 8-bit or 16-bit.
15 */
16#ifdef CONFIG_FLASH_16BIT
17typedef unsigned short FLASH_PORT_WIDTH;
18typedef volatile unsigned short FLASH_PORT_WIDTHV;
19#define FLASH_ID_MASK 0xFFFF
20#else
21typedef unsigned char FLASH_PORT_WIDTH;
22typedef volatile unsigned char FLASH_PORT_WIDTHV;
23#define FLASH_ID_MASK 0xFF
24#endif
25
26#define FPW FLASH_PORT_WIDTH
27#define FPWV FLASH_PORT_WIDTHV
28
29#define ORMASK(size) ((-size) & OR_AM_MSK)
30
31#define FLASH_CYCLE1 0x0555
32#define FLASH_CYCLE2 0x02aa
33
34/*-----------------------------------------------------------------------
35 * Functions
36 */
37static ulong flash_get_size(FPWV *addr, flash_info_t *info);
38static void flash_reset(flash_info_t *info);
39static int write_word_amd(flash_info_t *info, FPWV *dest, FPW data);
40static flash_info_t *flash_get_info(ulong base);
41
42/*-----------------------------------------------------------------------
43 * flash_init()
44 *
45 * sets up flash_info and returns size of FLASH (bytes)
46 */
47unsigned long flash_init (void)
48{
49 unsigned long size = 0;
50 int i;
51 extern void flash_preinit(void);
wdenk7152b1d2003-09-05 23:19:14 +000052 extern void flash_afterinit(ulong);
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020053 ulong flashbase = CONFIG_SYS_FLASH_BASE;
wdenk945af8d2003-07-16 21:53:01 +000054
55 flash_preinit();
56
57 /* Init: no FLASHes known */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020058 for (i=0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
wdenk945af8d2003-07-16 21:53:01 +000059 memset(&flash_info[i], 0, sizeof(flash_info_t));
60
61 flash_info[i].size =
62 flash_get_size((FPW *)flashbase, &flash_info[i]);
63
wdenk945af8d2003-07-16 21:53:01 +000064 size += flash_info[i].size;
wdenk7152b1d2003-09-05 23:19:14 +000065 flashbase += 0x800000;
wdenk945af8d2003-07-16 21:53:01 +000066 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020067#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
wdenk945af8d2003-07-16 21:53:01 +000068 /* monitor protection ON by default */
69 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020070 CONFIG_SYS_MONITOR_BASE,
71 CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
72 flash_get_info(CONFIG_SYS_MONITOR_BASE));
wdenk945af8d2003-07-16 21:53:01 +000073#endif
74
Jean-Christophe PLAGNIOL-VILLARD5a1aceb2008-09-10 22:48:04 +020075#ifdef CONFIG_ENV_IS_IN_FLASH
wdenk945af8d2003-07-16 21:53:01 +000076 /* ENV protection ON by default */
77 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020078 CONFIG_ENV_ADDR,
79 CONFIG_ENV_ADDR+CONFIG_ENV_SIZE-1,
80 flash_get_info(CONFIG_ENV_ADDR));
wdenk945af8d2003-07-16 21:53:01 +000081#endif
82
83
wdenk7152b1d2003-09-05 23:19:14 +000084 flash_afterinit(size);
wdenk945af8d2003-07-16 21:53:01 +000085 return size ? size : 1;
86}
87
88/*-----------------------------------------------------------------------
89 */
90static void flash_reset(flash_info_t *info)
91{
92 FPWV *base = (FPWV *)(info->start[0]);
93
94 /* Put FLASH back in read mode */
95 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
96 *base = (FPW)0x00FF00FF; /* Intel Read Mode */
97 else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD)
98 *base = (FPW)0x00F000F0; /* AMD Read Mode */
99}
100
101/*-----------------------------------------------------------------------
102 */
103
104static flash_info_t *flash_get_info(ulong base)
105{
106 int i;
107 flash_info_t * info;
108
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200109 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i ++) {
wdenk945af8d2003-07-16 21:53:01 +0000110 info = & flash_info[i];
wdenk42d1f032003-10-15 23:53:47 +0000111 if (info->size &&
wdenk7152b1d2003-09-05 23:19:14 +0000112 info->start[0] <= base && base <= info->start[0] + info->size - 1)
wdenk945af8d2003-07-16 21:53:01 +0000113 break;
114 }
115
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200116 return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info;
wdenk945af8d2003-07-16 21:53:01 +0000117}
118
119/*-----------------------------------------------------------------------
120 */
121
122void flash_print_info (flash_info_t *info)
123{
124 int i;
125 uchar *boottype;
126 uchar *bootletter;
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200127 char *fmt;
wdenk945af8d2003-07-16 21:53:01 +0000128 uchar botbootletter[] = "B";
129 uchar topbootletter[] = "T";
130 uchar botboottype[] = "bottom boot sector";
131 uchar topboottype[] = "top boot sector";
132
133 if (info->flash_id == FLASH_UNKNOWN) {
134 printf ("missing or unknown FLASH type\n");
135 return;
136 }
137
138 switch (info->flash_id & FLASH_VENDMASK) {
139 case FLASH_MAN_AMD: printf ("AMD "); break;
140 case FLASH_MAN_BM: printf ("BRIGHT MICRO "); break;
141 case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
142 case FLASH_MAN_SST: printf ("SST "); break;
143 case FLASH_MAN_STM: printf ("STM "); break;
144 case FLASH_MAN_INTEL: printf ("INTEL "); break;
145 default: printf ("Unknown Vendor "); break;
146 }
147
148 /* check for top or bottom boot, if it applies */
149 if (info->flash_id & FLASH_BTYPE) {
150 boottype = botboottype;
151 bootletter = botbootletter;
152 }
153 else {
154 boottype = topboottype;
155 bootletter = topbootletter;
156 }
157
158 switch (info->flash_id & FLASH_TYPEMASK) {
159 case FLASH_AMDLV065D:
160 fmt = "29LV065 (64 Mbit, uniform sectors)\n";
161 break;
162 default:
163 fmt = "Unknown Chip Type\n";
164 break;
165 }
166
167 printf (fmt, bootletter, boottype);
168
169 printf (" Size: %ld MB in %d Sectors\n",
170 info->size >> 20,
171 info->sector_count);
172
173 printf (" Sector Start Addresses:");
174
175 for (i=0; i<info->sector_count; ++i) {
176 if ((i % 5) == 0) {
177 printf ("\n ");
178 }
179
180 printf (" %08lX%s", info->start[i],
181 info->protect[i] ? " (RO)" : " ");
182 }
183
184 printf ("\n");
185}
186
187/*-----------------------------------------------------------------------
188 */
189
190/*
191 * The following code cannot be run from FLASH!
192 */
193
194ulong flash_get_size (FPWV *addr, flash_info_t *info)
195{
196 int i;
wdenk7152b1d2003-09-05 23:19:14 +0000197 FPWV* addr2;
198
wdenk945af8d2003-07-16 21:53:01 +0000199 /* Write auto select command: read Manufacturer ID */
200 /* Write auto select command sequence and test FLASH answer */
201 addr[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* for AMD, Intel ignores this */
202 addr[FLASH_CYCLE2] = (FPW)0x00550055; /* for AMD, Intel ignores this */
203 addr[FLASH_CYCLE1] = (FPW)0x00900090; /* selects Intel or AMD */
204
205 /* The manufacturer codes are only 1 byte, so just use 1 byte.
206 * This works for any bus width and any FLASH device width.
207 */
208 udelay(100);
209 switch (addr[0] & 0xff) {
210
211 case (uchar)AMD_MANUFACT:
212 info->flash_id = FLASH_MAN_AMD;
213 break;
214
215 case (uchar)INTEL_MANUFACT:
216 info->flash_id = FLASH_MAN_INTEL;
217 break;
218
219 default:
220 info->flash_id = FLASH_UNKNOWN;
221 info->sector_count = 0;
222 info->size = 0;
223 break;
224 }
225
226 /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */
227 if (info->flash_id != FLASH_UNKNOWN) switch ((FPW)addr[1]) {
228
229 case (FPW)AMD_ID_LV065D:
230 info->flash_id += FLASH_AMDLV065D;
231 info->sector_count = 128;
232 info->size = 0x00800000;
233 for( i = 0; i < info->sector_count; i++ )
234 info->start[i] = (ulong)addr + (i * 0x10000);
235 break; /* => 8 or 16 MB */
236
237 default:
238 info->flash_id = FLASH_UNKNOWN;
239 info->sector_count = 0;
240 info->size = 0;
241 return (0); /* => no or unknown flash */
242 }
243
wdenk7152b1d2003-09-05 23:19:14 +0000244 /* test for real flash at bank 1 */
245 addr2 = (FPW *)((ulong)addr | 0x800000);
246 if (addr2 != addr &&
247 ((addr2[0] & 0xff) == (addr[0] & 0xff)) && ((FPW)addr2[1] == (FPW)addr[1])) {
wdenk42d1f032003-10-15 23:53:47 +0000248 /* Seems 2 banks are the same space (8Mb chip is installed,
wdenk7152b1d2003-09-05 23:19:14 +0000249 * J24 in default position (CS0)). Disable this (first) bank.
250 */
251 info->flash_id = FLASH_UNKNOWN;
252 info->sector_count = 0;
253 info->size = 0;
254 }
wdenk945af8d2003-07-16 21:53:01 +0000255 /* Put FLASH back in read mode */
256 flash_reset(info);
257
258 return (info->size);
259}
260
261/*-----------------------------------------------------------------------
262 */
263
264int flash_erase (flash_info_t *info, int s_first, int s_last)
265{
266 FPWV *addr;
267 int flag, prot, sect;
268 int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
269 ulong start, now, last;
270 int rcode = 0;
271
272 if ((s_first < 0) || (s_first > s_last)) {
273 if (info->flash_id == FLASH_UNKNOWN) {
274 printf ("- missing\n");
275 } else {
276 printf ("- no sectors to erase\n");
277 }
278 return 1;
279 }
280
281 switch (info->flash_id & FLASH_TYPEMASK) {
282 case FLASH_AMDLV065D:
283 break;
284 case FLASH_UNKNOWN:
285 default:
286 printf ("Can't erase unknown flash type %08lx - aborted\n",
287 info->flash_id);
288 return 1;
289 }
290
291 prot = 0;
292 for (sect=s_first; sect<=s_last; ++sect) {
293 if (info->protect[sect]) {
294 prot++;
295 }
296 }
297
298 if (prot) {
299 printf ("- Warning: %d protected sectors will not be erased!\n",
300 prot);
301 } else {
302 printf ("\n");
303 }
304
305 last = get_timer(0);
306
307 /* Start erase on unprotected sectors */
308 for (sect = s_first; sect<=s_last && rcode == 0; sect++) {
309
310 if (info->protect[sect] != 0) /* protected, skip it */
311 continue;
312
313 /* Disable interrupts which might cause a timeout here */
314 flag = disable_interrupts();
315
316 addr = (FPWV *)(info->start[sect]);
317 if (intel) {
318 *addr = (FPW)0x00500050; /* clear status register */
319 *addr = (FPW)0x00200020; /* erase setup */
320 *addr = (FPW)0x00D000D0; /* erase confirm */
321 }
322 else {
323 /* must be AMD style if not Intel */
324 FPWV *base; /* first address in bank */
325
326 base = (FPWV *)(info->start[0]);
327 base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */
328 base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */
329 base[FLASH_CYCLE1] = (FPW)0x00800080; /* erase mode */
330 base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */
331 base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */
332 *addr = (FPW)0x00300030; /* erase sector */
333 }
334
335 /* re-enable interrupts if necessary */
336 if (flag)
337 enable_interrupts();
338
339 start = get_timer(0);
340
341 /* wait at least 50us for AMD, 80us for Intel.
342 * Let's wait 1 ms.
343 */
344 udelay (1000);
345
346 while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200347 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
wdenk945af8d2003-07-16 21:53:01 +0000348 printf ("Timeout\n");
349
350 if (intel) {
351 /* suspend erase */
352 *addr = (FPW)0x00B000B0;
353 }
354
355 flash_reset(info); /* reset to read mode */
356 rcode = 1; /* failed */
357 break;
358 }
359
360 /* show that we're waiting */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200361 if ((get_timer(last)) > CONFIG_SYS_HZ) {/* every second */
wdenk945af8d2003-07-16 21:53:01 +0000362 putc ('.');
363 last = get_timer(0);
364 }
365 }
366
367 /* show that we're waiting */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200368 if ((get_timer(last)) > CONFIG_SYS_HZ) { /* every second */
wdenk945af8d2003-07-16 21:53:01 +0000369 putc ('.');
370 last = get_timer(0);
371 }
372
373 flash_reset(info); /* reset to read mode */
374 }
375
376 printf (" done\n");
377 return rcode;
378}
379
380/*-----------------------------------------------------------------------
381 * Copy memory to flash, returns:
382 * 0 - OK
383 * 1 - write timeout
384 * 2 - Flash not erased
385 */
386int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
387{
388 FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */
389 int bytes; /* number of bytes to program in current word */
390 int left; /* number of bytes left to program */
391 int i, res;
392
393 for (left = cnt, res = 0;
394 left > 0 && res == 0;
395 addr += sizeof(data), left -= sizeof(data) - bytes) {
396
397 bytes = addr & (sizeof(data) - 1);
398 addr &= ~(sizeof(data) - 1);
399
400 /* combine source and destination data so can program
401 * an entire word of 16 or 32 bits
402 */
403 for (i = 0; i < sizeof(data); i++) {
404 data <<= 8;
405 if (i < bytes || i - bytes >= left )
406 data += *((uchar *)addr + i);
407 else
408 data += *src++;
409 }
410
411 /* write one word to the flash */
412 switch (info->flash_id & FLASH_VENDMASK) {
413 case FLASH_MAN_AMD:
414 res = write_word_amd(info, (FPWV *)addr, data);
415 break;
416 default:
417 /* unknown flash type, error! */
418 printf ("missing or unknown FLASH type\n");
419 res = 1; /* not really a timeout, but gives error */
420 break;
421 }
422 }
423
424 return (res);
425}
426
427/*-----------------------------------------------------------------------
428 * Write a word to Flash for AMD FLASH
429 * A word is 16 or 32 bits, whichever the bus width of the flash bank
430 * (not an individual chip) is.
431 *
432 * returns:
433 * 0 - OK
434 * 1 - write timeout
435 * 2 - Flash not erased
436 */
437static int write_word_amd (flash_info_t *info, FPWV *dest, FPW data)
438{
439 ulong start;
440 int flag;
441 int res = 0; /* result, assume success */
442 FPWV *base; /* first address in flash bank */
443
444 /* Check if Flash is (sufficiently) erased */
445 if ((*dest & data) != data) {
446 return (2);
447 }
448
449
450 base = (FPWV *)(info->start[0]);
451
452 /* Disable interrupts which might cause a timeout here */
453 flag = disable_interrupts();
454
455 base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */
456 base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */
457 base[FLASH_CYCLE1] = (FPW)0x00A000A0; /* selects program mode */
458
459 *dest = data; /* start programming the data */
460
461 /* re-enable interrupts if necessary */
462 if (flag)
463 enable_interrupts();
464
465 start = get_timer (0);
466
467 /* data polling for D7 */
468 while (res == 0 && (*dest & (FPW)0x00800080) != (data & (FPW)0x00800080)) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200469 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenk945af8d2003-07-16 21:53:01 +0000470 *dest = (FPW)0x00F000F0; /* reset bank */
471 res = 1;
472 }
473 }
474
475 return (res);
476}
Jean-Christophe PLAGNIOL-VILLARD00b18832008-08-13 01:40:42 +0200477#endif /*CONFIG_FLASH_CFI_DRIVER*/