blob: 9850445465c1783f57004abaae67169bcae9e957 [file] [log] [blame]
Stefan Roese5e4b3362005-08-22 17:51:53 +02001/*
2 * (C) Copyright 2003
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24#include <common.h>
25
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020026flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
Stefan Roese5e4b3362005-08-22 17:51:53 +020027
28typedef unsigned short FLASH_PORT_WIDTH;
29typedef volatile unsigned short FLASH_PORT_WIDTHV;
30
31#define FLASH_ID_MASK 0x00FF
32
33#define FPW FLASH_PORT_WIDTH
34#define FPWV FLASH_PORT_WIDTHV
35
36#define FLASH_CYCLE1 0x0555
37#define FLASH_CYCLE2 0x0aaa
38#define FLASH_ID1 0x00
39#define FLASH_ID2 0x01
40#define FLASH_ID3 0x0E
41#define FLASH_ID4 0x0F
42
43/*-----------------------------------------------------------------------
44 * Functions
45 */
46static ulong flash_get_size(FPWV * addr, flash_info_t * info);
47static void flash_reset(flash_info_t * info);
48static int write_word_amd(flash_info_t * info, FPWV * dest, FPW data);
49static flash_info_t *flash_get_info(ulong base);
50
51/*-----------------------------------------------------------------------
52 * flash_init()
53 *
54 * sets up flash_info and returns size of FLASH (bytes)
55 */
56unsigned long flash_init(void)
57{
58 unsigned long size = 0;
59 int i = 0;
60 extern void flash_preinit(void);
61 extern void flash_afterinit(uint, ulong, ulong);
62
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020063 ulong flashbase = CONFIG_SYS_FLASH_BASE;
Stefan Roese5e4b3362005-08-22 17:51:53 +020064
65 flash_preinit();
66
67 /* There is only ONE FLASH device */
68 memset(&flash_info[i], 0, sizeof(flash_info_t));
69 flash_info[i].size = flash_get_size((FPW *) flashbase, &flash_info[i]);
70 size += flash_info[i].size;
71
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020072#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
Stefan Roese5e4b3362005-08-22 17:51:53 +020073 /* monitor protection ON by default */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020074 flash_protect(FLAG_PROTECT_SET, CONFIG_SYS_MONITOR_BASE,
75 CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
76 flash_get_info(CONFIG_SYS_MONITOR_BASE));
Stefan Roese5e4b3362005-08-22 17:51:53 +020077#endif
78
Jean-Christophe PLAGNIOL-VILLARD5a1aceb2008-09-10 22:48:04 +020079#ifdef CONFIG_ENV_IS_IN_FLASH
Stefan Roese5e4b3362005-08-22 17:51:53 +020080 /* ENV protection ON by default */
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020081 flash_protect(FLAG_PROTECT_SET, CONFIG_ENV_ADDR,
82 CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,
83 flash_get_info(CONFIG_ENV_ADDR));
Stefan Roese5e4b3362005-08-22 17:51:53 +020084#endif
85
86 flash_afterinit(i, flash_info[i].start[0], flash_info[i].size);
87 return size ? size : 1;
88}
89
90/*-----------------------------------------------------------------------
91 */
92static void flash_reset(flash_info_t * info) {
93 FPWV *base = (FPWV *) (info->start[0]);
94
95 /* Put FLASH back in read mode */
96 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
97 *base = (FPW) 0x00FF00FF; /* Intel Read Mode */
98 } else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD) {
99 *base = (FPW) 0x00F000F0; /* AMD Read Mode */
100 }
101}
102
103/*-----------------------------------------------------------------------
104 */
105
106static flash_info_t *flash_get_info(ulong base) {
107 int i;
108 flash_info_t *info;
109
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200110 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
Stefan Roese5e4b3362005-08-22 17:51:53 +0200111 info = &flash_info[i];
112 if ((info->size) && (info->start[0] <= base)
113 && (base <= info->start[0] + info->size - 1)) {
114 break;
115 }
116 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200117 return (i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info);
Stefan Roese5e4b3362005-08-22 17:51:53 +0200118}
119
120/*-----------------------------------------------------------------------
121 */
122
123void flash_print_info(flash_info_t * info) {
124 int i;
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200125 char *fmt;
Stefan Roese5e4b3362005-08-22 17:51:53 +0200126
127 if (info->flash_id == FLASH_UNKNOWN) {
128 printf("missing or unknown FLASH type\n");
129 return;
130 }
131
132 switch (info->flash_id & FLASH_VENDMASK) {
133 case FLASH_MAN_AMD:
134 printf("AMD ");
135 break;
136 default:
137 printf("Unknown Vendor ");
138 break;
139 }
140
141 switch (info->flash_id & FLASH_TYPEMASK) {
142 case FLASH_AMLV256U:
143 fmt = "29LV256M (256 Mbit)\n";
144 break;
145 default:
146 fmt = "Unknown Chip Type\n";
147 break;
148 }
149
150 printf(fmt);
151 printf(" Size: %ld MB in %d Sectors\n", info->size >> 20,
152 info->sector_count);
153 printf(" Sector Start Addresses:");
154
155 for (i = 0; i < info->sector_count; ++i) {
156 ulong size;
157 int erased;
158 ulong *flash = (unsigned long *)info->start[i];
159
160 if ((i % 5) == 0) {
161 printf("\n ");
162 }
163
164 /*
165 * Check if whole sector is erased
166 */
167 size =
168 (i !=
169 (info->sector_count - 1)) ? (info->start[i + 1] -
170 info->start[i]) >> 2 : (info->
171 start
172 [0] +
173 info->
174 size -
175 info->
176 start
177 [i])
178 >> 2;
179
180 for (flash = (unsigned long *)info->start[i], erased = 1;
181 (flash != (unsigned long *)info->start[i] + size)
182 && erased; flash++) {
183 erased = *flash == ~0x0UL;
184 }
185 printf(" %08lX %s %s", info->start[i], erased ? "E" : " ",
186 info->protect[i] ? "(RO)" : " ");
187 }
188
189 printf("\n");
190}
191
192/*-----------------------------------------------------------------------
193 */
194
195/*
196 * The following code cannot be run from FLASH!
197 */
198
199ulong flash_get_size(FPWV * addr, flash_info_t * info) {
200 int i;
201
202 /* Write auto select command: read Manufacturer ID */
203 /* Write auto select command sequence and test FLASH answer */
204 addr[FLASH_CYCLE1] = (FPW) 0x00AA00AA; /* for AMD, Intel ignores this */
205 addr[FLASH_CYCLE2] = (FPW) 0x00550055; /* for AMD, Intel ignores this */
206 addr[FLASH_CYCLE1] = (FPW) 0x00900090; /* selects Intel or AMD */
207
208 /* The manufacturer codes are only 1 byte, so just use 1 byte. */
209 /* This works for any bus width and any FLASH device width. */
210 udelay(100);
211 switch (addr[FLASH_ID1] & 0x00ff) {
212 case (uchar) AMD_MANUFACT:
213 info->flash_id = FLASH_MAN_AMD;
214 break;
215 default:
216 printf("unknown vendor=%x ", addr[FLASH_ID1] & 0xff);
217 info->flash_id = FLASH_UNKNOWN;
218 info->sector_count = 0;
219 info->size = 0;
220 break;
221 }
222
223 /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */
224 if (info->flash_id != FLASH_UNKNOWN) {
225 switch ((FPW) addr[FLASH_ID2]) {
226 case (FPW) AMD_ID_MIRROR:
227 /* MIRROR BIT FLASH, read more ID bytes */
228 if ((FPW) addr[FLASH_ID3] == (FPW) AMD_ID_LV256U_2
229 && (FPW) addr[FLASH_ID4] == (FPW) AMD_ID_LV256U_3) {
230 /* attention: only the first 16 MB will be used in u-boot */
231 info->flash_id += FLASH_AMLV256U;
232 info->sector_count = 512;
233 info->size = 0x02000000;
234 for (i = 0; i < info->sector_count; i++) {
235 info->start[i] =
236 (ulong) addr + 0x10000 * i;
237 }
238 break;
239 }
240 /* fall thru to here ! */
241 default:
242 printf("unknown AMD device=%x %x %x",
243 (FPW) addr[FLASH_ID2], (FPW) addr[FLASH_ID3],
244 (FPW) addr[FLASH_ID4]);
245 info->flash_id = FLASH_UNKNOWN;
246 info->sector_count = 0;
247 info->size = 0x800000;
248 break;
249 }
250
251 /* Put FLASH back in read mode */
252 flash_reset(info);
253 }
254 return (info->size);
255}
256
257/*-----------------------------------------------------------------------
258 */
259
260int flash_erase(flash_info_t * info, int s_first, int s_last) {
261 FPWV *addr;
262 int flag, prot, sect;
263 int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
264 ulong start, now, last;
265 int rcode = 0;
266
267 if ((s_first < 0) || (s_first > s_last)) {
268 if (info->flash_id == FLASH_UNKNOWN) {
269 printf("- missing\n");
270 } else {
271 printf("- no sectors to erase\n");
272 }
273 return 1;
274 }
275
276 switch (info->flash_id & FLASH_TYPEMASK) {
277 case FLASH_AMLV256U:
278 break;
279 case FLASH_UNKNOWN:
280 default:
281 printf("Can't erase unknown flash type %08lx - aborted\n",
282 info->flash_id);
283 return 1;
284 }
285
286 prot = 0;
287 for (sect = s_first; sect <= s_last; ++sect) {
288 if (info->protect[sect]) {
289 prot++;
290 }
291 }
292
293 if (prot) {
294 printf("- Warning: %d protected sectors will not be erased!\n",
295 prot);
296 } else {
297 printf("\n");
298 }
299
300 last = get_timer(0);
301
302 /* Start erase on unprotected sectors */
303 for (sect = s_first; sect <= s_last && rcode == 0; sect++) {
304 if (info->protect[sect] != 0) { /* protected, skip it */
305 continue;
306 }
307 /* Disable interrupts which might cause a timeout here */
308 flag = disable_interrupts();
309
310 addr = (FPWV *) (info->start[sect]);
311 if (intel) {
312 *addr = (FPW) 0x00500050; /* clear status register */
313 *addr = (FPW) 0x00200020; /* erase setup */
314 *addr = (FPW) 0x00D000D0; /* erase confirm */
315 } else {
316 /* must be AMD style if not Intel */
317 FPWV *base; /* first address in bank */
318
319 base = (FPWV *) (info->start[0]);
320 base[FLASH_CYCLE1] = (FPW) 0x00AA00AA; /* unlock */
321 base[FLASH_CYCLE2] = (FPW) 0x00550055; /* unlock */
322 base[FLASH_CYCLE1] = (FPW) 0x00800080; /* erase mode */
323 base[FLASH_CYCLE1] = (FPW) 0x00AA00AA; /* unlock */
324 base[FLASH_CYCLE2] = (FPW) 0x00550055; /* unlock */
325 *addr = (FPW) 0x00300030; /* erase sector */
326 }
327
328 /* re-enable interrupts if necessary */
329 if (flag) {
330 enable_interrupts();
331 }
332 start = get_timer(0);
333
334 /* wait at least 50us for AMD, 80us for Intel. */
335 /* Let's wait 1 ms. */
336 udelay(1000);
337
338 while ((*addr & (FPW) 0x00800080) != (FPW) 0x00800080) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200339 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
Stefan Roese5e4b3362005-08-22 17:51:53 +0200340 printf("Timeout\n");
341 if (intel) {
342 /* suspend erase */
343 *addr = (FPW) 0x00B000B0;
344 }
345 flash_reset(info); /* reset to read mode */
346 rcode = 1; /* failed */
347 break;
348 }
349 /* show that we're waiting */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200350 if ((get_timer(last)) > CONFIG_SYS_HZ) {
Stefan Roese5e4b3362005-08-22 17:51:53 +0200351 /* every second */
352 putc('.');
353 last = get_timer(0);
354 }
355 }
356 /* show that we're waiting */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200357 if ((get_timer(last)) > CONFIG_SYS_HZ) {
Stefan Roese5e4b3362005-08-22 17:51:53 +0200358 /* every second */
359 putc('.');
360 last = get_timer(0);
361 }
362 flash_reset(info); /* reset to read mode */
363 }
364 printf(" done\n");
365 return (rcode);
366}
367
368/*-----------------------------------------------------------------------
369 * Copy memory to flash, returns:
370 * 0 - OK
371 * 1 - write timeout
372 * 2 - Flash not erased
373 */
374int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
375{
376 FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */
377 int bytes; /* number of bytes to program in current word */
378 int left; /* number of bytes left to program */
379 int i, res;
380
381 for (left = cnt, res = 0;
382 left > 0 && res == 0;
383 addr += sizeof(data), left -= sizeof(data) - bytes) {
384
385 bytes = addr & (sizeof(data) - 1);
386 addr &= ~(sizeof(data) - 1);
387
388 /* combine source and destination data so can program
389 * an entire word of 16 or 32 bits
390 */
391 for (i = 0; i < sizeof(data); i++) {
392 data <<= 8;
393 if (i < bytes || i - bytes >= left)
394 data += *((uchar *) addr + i);
395 else
396 data += *src++;
397 }
398
399 /* write one word to the flash */
400 switch (info->flash_id & FLASH_VENDMASK) {
401 case FLASH_MAN_AMD:
402 res = write_word_amd(info, (FPWV *) addr, data);
403 break;
404 default:
405 /* unknown flash type, error! */
406 printf("missing or unknown FLASH type\n");
407 res = 1; /* not really a timeout, but gives error */
408 break;
409 }
410 }
411 return (res);
412}
413
414/*-----------------------------------------------------------------------
415 * Write a word to Flash for AMD FLASH
416 * A word is 16 or 32 bits, whichever the bus width of the flash bank
417 * (not an individual chip) is.
418 *
419 * returns:
420 * 0 - OK
421 * 1 - write timeout
422 * 2 - Flash not erased
423 */
424static int write_word_amd(flash_info_t * info, FPWV * dest, FPW data) {
425 ulong start;
426 int flag;
427 int res = 0; /* result, assume success */
428 FPWV *base; /* first address in flash bank */
429
430 /* Check if Flash is (sufficiently) erased */
431 if ((*dest & data) != data) {
432 return (2);
433 }
434
435 base = (FPWV *) (info->start[0]);
436
437 /* Disable interrupts which might cause a timeout here */
438 flag = disable_interrupts();
439
440 base[FLASH_CYCLE1] = (FPW) 0x00AA00AA; /* unlock */
441 base[FLASH_CYCLE2] = (FPW) 0x00550055; /* unlock */
442 base[FLASH_CYCLE1] = (FPW) 0x00A000A0; /* selects program mode */
443
444 *dest = data; /* start programming the data */
445
446 /* re-enable interrupts if necessary */
447 if (flag) {
448 enable_interrupts();
449 }
450 start = get_timer(0);
451
452 /* data polling for D7 */
453 while (res == 0
454 && (*dest & (FPW) 0x00800080) != (data & (FPW) 0x00800080)) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200455 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
Stefan Roese5e4b3362005-08-22 17:51:53 +0200456 *dest = (FPW) 0x00F000F0; /* reset bank */
457 res = 1;
458 }
459 }
460 return (res);
461}