blob: f07d96052aa5c66f32c5adfd678b678eb6053a4c [file] [log] [blame]
wdenk5b1d7132002-11-03 00:07:02 +00001/*
2 * (C) Copyright 2001
3 * Stäubli Faverges - <www.staubli.com>
4 * Pierre AUBERT p.aubert@staubli.com
5 * U-Boot port on RPXClassic LF (CLLF_BW31) board
6 *
7 * RPXClassic uses Am29DL323B flash memory with 2 banks
8 *
9 *
10 * (C) Copyright 2000
11 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
12 *
13 * See file CREDITS for list of people who contributed to this
14 * project.
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License as
18 * published by the Free Software Foundation; either version 2 of
19 * the License, or (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
29 * MA 02111-1307 USA
30 */
31
32
33#include <common.h>
34#include <mpc8xx.h>
35
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020036flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
wdenk5b1d7132002-11-03 00:07:02 +000037
38/*-----------------------------------------------------------------------
39 * Functions
40 */
41static ulong flash_get_size (vu_long *addr, flash_info_t *info);
42static int write_word (flash_info_t *info, ulong dest, ulong data);
43static void flash_get_offsets (ulong base, flash_info_t *info);
44
45/*-----------------------------------------------------------------------
46 */
47
48unsigned long flash_init (void)
49{
50 unsigned long size_b0 ;
51 int i;
52
53 /* Init: no FLASHes known */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020054 for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
wdenk5b1d7132002-11-03 00:07:02 +000055 flash_info[i].flash_id = FLASH_UNKNOWN;
56 }
57
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020058 size_b0 = flash_get_size((vu_long *)CONFIG_SYS_FLASH_BASE, &flash_info[0]);
wdenk5b1d7132002-11-03 00:07:02 +000059
60
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020061 flash_get_offsets (CONFIG_SYS_FLASH_BASE, &flash_info[0]);
wdenk5b1d7132002-11-03 00:07:02 +000062
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020063#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
wdenk5b1d7132002-11-03 00:07:02 +000064 /* monitor protection ON by default */
65 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020066 CONFIG_SYS_MONITOR_BASE,
67 CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
wdenk5b1d7132002-11-03 00:07:02 +000068 &flash_info[0]);
69#endif
70
71 flash_info[0].size = size_b0;
72
73 return (size_b0);
74}
75
76/*-----------------------------------------------------------------------
77 */
78static void flash_get_offsets (ulong base, flash_info_t *info)
79{
80 int i;
81
82 if (info->flash_id & FLASH_BTYPE) {
83 /* set sector offsets for bottom boot block type */
84 info->start[0] = base + 0x00000000;
85 info->start[1] = base + 0x00008000;
86 info->start[2] = base + 0x00010000;
87 info->start[3] = base + 0x00018000;
88 info->start[4] = base + 0x00020000;
89 info->start[5] = base + 0x00028000;
90 info->start[6] = base + 0x00030000;
91 info->start[7] = base + 0x00038000;
92 for (i = 8; i < info->sector_count; i++) {
93 info->start[i] = base + ((i-7) * 0x00040000) ;
94 }
95 }
96}
97
98/*-----------------------------------------------------------------------
99 */
100void flash_print_info (flash_info_t *info)
101{
102 int i;
103
104 if (info->flash_id == FLASH_UNKNOWN) {
105 printf ("missing or unknown FLASH type\n");
106 return;
107 }
108
109 switch (info->flash_id & FLASH_VENDMASK) {
110 case FLASH_MAN_AMD: printf ("AMD "); break;
111 default: printf ("Unknown Vendor "); break;
112 }
113
114 switch (info->flash_id & FLASH_TYPEMASK) {
wdenk8bde7f72003-06-27 21:31:46 +0000115 case FLASH_AMDL323B:
116 printf ("AMDL323DB (16 Mbytes, bottom boot sect)\n");
117 break;
wdenk5b1d7132002-11-03 00:07:02 +0000118 default:
wdenk8bde7f72003-06-27 21:31:46 +0000119 printf ("Unknown Chip Type\n");
120 break;
wdenk5b1d7132002-11-03 00:07:02 +0000121 }
122
123 printf (" Size: %ld MB in %d Sectors\n",
124 info->size >> 20, info->sector_count);
125
126 printf (" Sector Start Addresses:");
127 for (i=0; i<info->sector_count; ++i) {
128 if ((i % 5) == 0)
129 printf ("\n ");
130 printf (" %08lX%s",
131 info->start[i],
132 info->protect[i] ? " (RO)" : " "
133 );
134 }
135 printf ("\n");
136}
137
138/*-----------------------------------------------------------------------
139 */
140
141
142/*-----------------------------------------------------------------------
143 */
144
145/*
146 * The following code cannot be run from FLASH!
147 */
148
149static ulong flash_get_size (vu_long *addr, flash_info_t *info)
150{
151 short i;
152 ulong value;
153 ulong base = (ulong)addr;
154
wdenk8bde7f72003-06-27 21:31:46 +0000155 /* Reset flash componeny */
156 addr [0] = 0xf0f0f0f0;
wdenk5b1d7132002-11-03 00:07:02 +0000157
wdenk8bde7f72003-06-27 21:31:46 +0000158 /* Write auto select command: read Manufacturer ID */
159 addr[0xAAA] = 0xAAAAAAAA ;
wdenk5b1d7132002-11-03 00:07:02 +0000160 addr[0x555] = 0x55555555 ;
161 addr[0xAAA] = 0x90909090 ;
162
163 value = addr[0] ;
164
165 switch (value & 0x00FF00FF) {
166 case AMD_MANUFACT:
167 info->flash_id = FLASH_MAN_AMD;
168 break;
169 default:
170 info->flash_id = FLASH_UNKNOWN;
171 info->sector_count = 0;
172 info->size = 0;
173 return (0); /* no or unknown flash */
174 }
175
176 value = addr[2] ; /* device ID */
177
178 switch (value & 0x00FF00FF) {
wdenk8bde7f72003-06-27 21:31:46 +0000179 case (AMD_ID_DL323B & 0x00FF00FF):
180 info->flash_id += FLASH_AMDL323B;
181 info->sector_count = 71;
182 info->size = 0x01000000; /* 16 Mb */
wdenk5b1d7132002-11-03 00:07:02 +0000183
wdenk8bde7f72003-06-27 21:31:46 +0000184 break;
wdenk5b1d7132002-11-03 00:07:02 +0000185 default:
186 info->flash_id = FLASH_UNKNOWN;
187 return (0); /* => no or unknown flash */
188
189 }
190 /* set up sector start address table */
wdenk8bde7f72003-06-27 21:31:46 +0000191 /* set sector offsets for bottom boot block type */
192 info->start[0] = base + 0x00000000;
193 info->start[1] = base + 0x00008000;
194 info->start[2] = base + 0x00010000;
195 info->start[3] = base + 0x00018000;
196 info->start[4] = base + 0x00020000;
197 info->start[5] = base + 0x00028000;
198 info->start[6] = base + 0x00030000;
199 info->start[7] = base + 0x00038000;
200 for (i = 8; i < info->sector_count; i++) {
201 info->start[i] = base + ((i-7) * 0x00040000) ;
202 }
wdenk5b1d7132002-11-03 00:07:02 +0000203
204 /* check for protected sectors */
wdenk8bde7f72003-06-27 21:31:46 +0000205 for (i = 0; i < 23; i++) {
206 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
207 /* D0 = 1 if protected */
208 addr = (volatile unsigned long *)(info->start[i]);
209 info->protect[i] = addr[4] & 1 ;
wdenk5b1d7132002-11-03 00:07:02 +0000210 }
wdenk8bde7f72003-06-27 21:31:46 +0000211 /* Check for protected sectors in the 2nd bank */
212 addr[0x100AAA] = 0xAAAAAAAA ;
213 addr[0x100555] = 0x55555555 ;
214 addr[0x100AAA] = 0x90909090 ;
wdenk5b1d7132002-11-03 00:07:02 +0000215
wdenk8bde7f72003-06-27 21:31:46 +0000216 for (i = 23; i < info->sector_count; i++) {
217 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
218 /* D0 = 1 if protected */
219 addr = (volatile unsigned long *)(info->start[i]);
220 info->protect[i] = addr[4] & 1 ;
wdenk5b1d7132002-11-03 00:07:02 +0000221 }
222
223 /*
224 * Prevent writes to uninitialized FLASH.
225 */
226 if (info->flash_id != FLASH_UNKNOWN) {
227 addr = (volatile unsigned long *)info->start[0];
228
229 *addr = 0xF0F0F0F0; /* reset bank 1 */
230 addr = (volatile unsigned long *)info->start[23];
231
232 *addr = 0xF0F0F0F0; /* reset bank 2 */
233
234 }
235
236 return (info->size);
237}
238
239
240/*-----------------------------------------------------------------------
241 */
242
243int flash_erase (flash_info_t *info, int s_first, int s_last)
244{
245 vu_long *addr = (vu_long*)(info->start[0]);
246 int flag, prot, sect, l_sect;
247 ulong start, now, last;
248
249 if ((s_first < 0) || (s_first > s_last)) {
250 if (info->flash_id == FLASH_UNKNOWN) {
251 printf ("- missing\n");
252 } else {
253 printf ("- no sectors to erase\n");
254 }
255 return 1;
256 }
257
258 if ((info->flash_id == FLASH_UNKNOWN) ||
259 (info->flash_id > FLASH_AMD_COMP)) {
260 printf ("Can't erase unknown flash type %08lx - aborted\n",
261 info->flash_id);
262 return 1;
263 }
264
265 prot = 0;
266 for (sect=s_first; sect<=s_last; ++sect) {
267 if (info->protect[sect]) {
268 prot++;
269 }
270 }
271
272 if (prot) {
273 printf ("- Warning: %d protected sectors will not be erased!\n",
274 prot);
275 } else {
276 printf ("\n");
277 }
278
279 l_sect = -1;
280
281 /* Disable interrupts which might cause a timeout here */
282 flag = disable_interrupts();
283
284 addr[0xAAA] = 0xAAAAAAAA;
285 addr[0x555] = 0x55555555;
286 addr[0xAAA] = 0x80808080;
287 addr[0xAAA] = 0xAAAAAAAA;
288 addr[0x555] = 0x55555555;
289
290 /* Start erase on unprotected sectors */
291 for (sect = s_first; sect<=s_last; sect++) {
292 if (info->protect[sect] == 0) { /* not protected */
293 addr = (vu_long *)(info->start[sect]) ;
294 addr[0] = 0x30303030 ;
295 l_sect = sect;
296 }
297 }
298
299 /* re-enable interrupts if necessary */
300 if (flag)
301 enable_interrupts();
302
303 /* wait at least 80us - let's wait 1 ms */
304 udelay (1000);
305
306 /*
307 * We wait for the last triggered sector
308 */
309 if (l_sect < 0)
310 goto DONE;
311
312 start = get_timer (0);
313 last = start;
314 addr = (vu_long *)(info->start[l_sect]);
315 while ((addr[0] & 0x80808080) != 0x80808080) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200316 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
wdenk5b1d7132002-11-03 00:07:02 +0000317 printf ("Timeout\n");
318 return 1;
319 }
320 /* show that we're waiting */
321 if ((now - last) > 1000) { /* every second */
322 putc ('.');
323 last = now;
324 }
325 }
326
327DONE:
328 /* reset to read mode */
329 addr = (vu_long *)info->start[0];
330 addr[0] = 0xF0F0F0F0; /* reset bank */
331
332 printf (" done\n");
wdenk8bde7f72003-06-27 21:31:46 +0000333 return 0;
wdenk5b1d7132002-11-03 00:07:02 +0000334}
335
336/*-----------------------------------------------------------------------
337 * Copy memory to flash, returns:
338 * 0 - OK
339 * 1 - write timeout
340 * 2 - Flash not erased
341 */
342
343int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
344{
345 ulong cp, wp, data;
346 int i, l, rc;
347
348 wp = (addr & ~3); /* get lower word aligned address */
349
350 /*
351 * handle unaligned start bytes
352 */
353 if ((l = addr - wp) != 0) {
354 data = 0;
355 for (i=0, cp=wp; i<l; ++i, ++cp) {
356 data = (data << 8) | (*(uchar *)cp);
357 }
358 for (; i<4 && cnt>0; ++i) {
359 data = (data << 8) | *src++;
360 --cnt;
361 ++cp;
362 }
363 for (; cnt==0 && i<4; ++i, ++cp) {
364 data = (data << 8) | (*(uchar *)cp);
365 }
366
367 if ((rc = write_word(info, wp, data)) != 0) {
368 return (rc);
369 }
370 wp += 4;
371 }
372
373 /*
374 * handle word aligned part
375 */
376 while (cnt >= 4) {
377 data = 0;
378 for (i=0; i<4; ++i) {
379 data = (data << 8) | *src++;
380 }
381 if ((rc = write_word(info, wp, data)) != 0) {
382 return (rc);
383 }
384 wp += 4;
385 cnt -= 4;
386 }
387
388 if (cnt == 0) {
389 return (0);
390 }
391
392 /*
393 * handle unaligned tail bytes
394 */
395 data = 0;
396 for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
397 data = (data << 8) | *src++;
398 --cnt;
399 }
400 for (; i<4; ++i, ++cp) {
401 data = (data << 8) | (*(uchar *)cp);
402 }
403
404 return (write_word(info, wp, data));
405}
406
407/*-----------------------------------------------------------------------
408 * Write a word to Flash, returns:
409 * 0 - OK
410 * 1 - write timeout
411 * 2 - Flash not erased
412 */
413static int write_word (flash_info_t *info, ulong dest, ulong data)
414{
415 vu_long *addr = (vu_long *)(info->start[0]);
416 ulong start;
417 int flag;
418
419 /* Check if Flash is (sufficiently) erased */
420 if ((*((vu_long *)dest) & data) != data) {
421 return (2);
422 }
423 /* Disable interrupts which might cause a timeout here */
424 flag = disable_interrupts();
425
426 addr[0xAAA] = 0xAAAAAAAA;
427 addr[0x555] = 0x55555555;
428 addr[0xAAA] = 0xA0A0A0A0;
429
430 *((vu_long *)dest) = data;
431
432 /* re-enable interrupts if necessary */
433 if (flag)
434 enable_interrupts();
435
436 /* data polling for D7 */
437 start = get_timer (0);
438 while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080)) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200439 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenk5b1d7132002-11-03 00:07:02 +0000440 return (1);
441 }
442 }
443 return (0);
444}
445
446/*-----------------------------------------------------------------------
447 */