]>
Commit | Line | Data |
---|---|---|
0332990b WD |
1 | /* |
2 | * (C) Copyright 2001 | |
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 | ||
25 | #include <common.h> | |
26 | #include <mpc824x.h> | |
27 | ||
5a1aceb0 | 28 | #if defined(CONFIG_ENV_IS_IN_FLASH) |
0e8d1586 | 29 | # ifndef CONFIG_ENV_ADDR |
6d0f6bcf | 30 | # define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET) |
0332990b | 31 | # endif |
0e8d1586 JCPV |
32 | # ifndef CONFIG_ENV_SIZE |
33 | # define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE | |
0332990b | 34 | # endif |
0e8d1586 JCPV |
35 | # ifndef CONFIG_ENV_SECT_SIZE |
36 | # define CONFIG_ENV_SECT_SIZE CONFIG_ENV_SIZE | |
0332990b WD |
37 | # endif |
38 | #endif | |
39 | ||
40 | ||
41 | /*---------------------------------------------------------------------*/ | |
42 | #define DEBUG_FLASH | |
43 | ||
44 | #ifdef DEBUG_FLASH | |
45 | #define DEBUGF(fmt,args...) printf(fmt ,##args) | |
46 | #else | |
47 | #define DEBUGF(fmt,args...) | |
48 | #endif | |
49 | /*---------------------------------------------------------------------*/ | |
50 | ||
6d0f6bcf | 51 | flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */ |
0332990b WD |
52 | |
53 | /*----------------------------------------------------------------------- | |
54 | * Functions | |
55 | */ | |
56 | static ulong flash_get_size (vu_char *addr, flash_info_t *info); | |
57 | static int write_data (flash_info_t *info, uchar *dest, uchar data); | |
58 | static void flash_get_offsets (ulong base, flash_info_t *info); | |
59 | ||
60 | #define BS(b) (b) | |
61 | #define BYTEME(x) ((x) & 0xFF) | |
62 | ||
63 | /*----------------------------------------------------------------------- | |
64 | */ | |
65 | ||
66 | unsigned long flash_init (void) | |
67 | { | |
6d0f6bcf JCPV |
68 | unsigned long flash_banks[CONFIG_SYS_MAX_FLASH_BANKS] = CONFIG_SYS_FLASH_BANKS; |
69 | unsigned long size, size_b[CONFIG_SYS_MAX_FLASH_BANKS]; | |
0332990b WD |
70 | |
71 | int i; | |
72 | ||
73 | /* Init: no FLASHes known */ | |
6d0f6bcf | 74 | for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) |
0332990b WD |
75 | { |
76 | flash_info[i].flash_id = FLASH_UNKNOWN; | |
77 | ||
78 | DEBUGF("Get flash bank %d @ 0x%08lx\n", i, flash_banks[i]); | |
79 | /* | |
80 | size_b[i] = flash_get_size((vu_char *)flash_banks[i], &flash_info[i]); | |
81 | */ | |
82 | size_b[i] = flash_get_size((vu_char *) 0xff800000 , &flash_info[i]); | |
83 | ||
8bde7f77 | 84 | if (flash_info[i].flash_id == FLASH_UNKNOWN) |
0332990b WD |
85 | { |
86 | printf ("## Unknown FLASH on Bank %d: " | |
87 | "ID 0x%lx, Size = 0x%08lx = %ld MB\n", | |
88 | i, flash_info[i].flash_id, | |
89 | size_b[i], size_b[i]<<20); | |
90 | } | |
91 | else | |
92 | { | |
93 | DEBUGF("## Flash bank %d at 0x%08lx sizes: 0x%08lx \n", | |
94 | i, flash_banks[i], size_b[i]); | |
95 | ||
96 | flash_get_offsets (flash_banks[i], &flash_info[i]); | |
97 | flash_info[i].size = size_b[i]; | |
98 | } | |
99 | } | |
100 | ||
101 | ||
6d0f6bcf JCPV |
102 | #if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE |
103 | DEBUGF("protect monitor %x @ %x\n", CONFIG_SYS_MONITOR_BASE, CONFIG_SYS_MONITOR_LEN); | |
0332990b WD |
104 | /* monitor protection ON by default */ |
105 | flash_protect(FLAG_PROTECT_SET, | |
6d0f6bcf JCPV |
106 | CONFIG_SYS_MONITOR_BASE, |
107 | CONFIG_SYS_MONITOR_BASE+CONFIG_SYS_MONITOR_LEN-1, | |
0332990b WD |
108 | &flash_info[0]); |
109 | #endif | |
110 | ||
5a1aceb0 | 111 | #ifdef CONFIG_ENV_IS_IN_FLASH |
0332990b | 112 | /* ENV protection ON by default */ |
0e8d1586 | 113 | DEBUGF("protect environtment %x @ %x\n", CONFIG_ENV_ADDR, CONFIG_ENV_SECT_SIZE); |
0332990b | 114 | flash_protect(FLAG_PROTECT_SET, |
0e8d1586 JCPV |
115 | CONFIG_ENV_ADDR, |
116 | CONFIG_ENV_ADDR+CONFIG_ENV_SECT_SIZE-1, | |
0332990b WD |
117 | &flash_info[0]); |
118 | #endif | |
119 | ||
120 | size = 0; | |
121 | DEBUGF("## Final Flash bank sizes: "); | |
6d0f6bcf | 122 | for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) |
0332990b WD |
123 | { |
124 | DEBUGF("%08lx ", size_b[i]); | |
125 | size += size_b[i]; | |
126 | } | |
127 | DEBUGF("\n"); | |
128 | return (size); | |
129 | } | |
130 | ||
131 | /*----------------------------------------------------------------------- | |
132 | */ | |
133 | static void flash_get_offsets (ulong base, flash_info_t *info) | |
134 | { | |
135 | int i; | |
136 | ||
137 | if (info->flash_id == FLASH_UNKNOWN) { | |
138 | return; | |
139 | } | |
140 | ||
141 | switch (info->flash_id & FLASH_VENDMASK) { | |
142 | case FLASH_MAN_INTEL: | |
143 | for (i = 0; i < info->sector_count; i++) { | |
144 | info->start[i] = base; | |
145 | base += 0x00020000; /* 128k per bank */ | |
146 | } | |
147 | return; | |
148 | ||
149 | default: | |
150 | printf ("Don't know sector ofsets for flash type 0x%lx\n", info->flash_id); | |
151 | return; | |
152 | } | |
153 | } | |
154 | ||
155 | /*----------------------------------------------------------------------- | |
156 | */ | |
157 | void flash_print_info (flash_info_t *info) | |
158 | { | |
159 | int i; | |
160 | ||
161 | if (info->flash_id == FLASH_UNKNOWN) { | |
162 | printf ("missing or unknown FLASH type\n"); | |
163 | return; | |
164 | } | |
165 | ||
166 | switch (info->flash_id & FLASH_VENDMASK) { | |
167 | case FLASH_MAN_AMD: printf ("AMD "); break; | |
168 | case FLASH_MAN_FUJ: printf ("Fujitsu "); break; | |
169 | case FLASH_MAN_SST: printf ("SST "); break; | |
170 | case FLASH_MAN_STM: printf ("STM "); break; | |
171 | case FLASH_MAN_INTEL: printf ("Intel "); break; | |
172 | case FLASH_MAN_MT: printf ("MT "); break; | |
173 | default: printf ("Unknown Vendor "); break; | |
174 | } | |
175 | ||
176 | switch (info->flash_id & FLASH_TYPEMASK) { | |
8bde7f77 | 177 | case FLASH_28F320J3A: |
0332990b WD |
178 | printf ("28F320J3A (32Mbit = 128K x 32)\n"); |
179 | break; | |
8bde7f77 | 180 | case FLASH_28F640J3A: |
0332990b WD |
181 | printf ("28F640J3A (64Mbit = 128K x 64)\n"); |
182 | break; | |
8bde7f77 | 183 | case FLASH_28F128J3A: |
0332990b WD |
184 | printf ("28F128J3A (128Mbit = 128K x 128)\n"); |
185 | break; | |
8bde7f77 | 186 | default: |
0332990b WD |
187 | printf ("Unknown Chip Type\n"); |
188 | break; | |
189 | } | |
190 | ||
191 | #if 1 | |
192 | if (info->size >= (1 << 20)) { | |
193 | i = 20; | |
194 | } else { | |
195 | i = 10; | |
196 | } | |
197 | printf (" Size: %ld %cB in %d Sectors\n", | |
198 | info->size >> i, | |
199 | (i == 20) ? 'M' : 'k', | |
200 | info->sector_count); | |
201 | ||
202 | printf (" Sector Start Addresses:"); | |
203 | for (i=0; i<info->sector_count; ++i) { | |
204 | if ((i % 5) == 0) | |
205 | printf ("\n "); | |
206 | printf (" %08lX%s", | |
207 | info->start[i], | |
208 | info->protect[i] ? " (RO)" : " " | |
209 | ); | |
210 | } | |
211 | printf ("\n"); | |
212 | #endif | |
213 | return; | |
214 | } | |
215 | ||
216 | /*----------------------------------------------------------------------- | |
217 | */ | |
218 | ||
219 | ||
220 | /*----------------------------------------------------------------------- | |
221 | */ | |
222 | ||
223 | /* | |
224 | * The following code cannot be run from FLASH! | |
225 | */ | |
226 | static ulong flash_get_size (vu_char *addr, flash_info_t *info) | |
227 | { | |
228 | vu_char manuf, device; | |
229 | ||
230 | addr[0] = BS(0x90); | |
231 | manuf = BS(addr[0]); | |
232 | DEBUGF("Manuf. ID @ 0x%08lx: 0x%08x\n", (ulong)addr, manuf); | |
233 | ||
234 | switch (manuf) { | |
235 | case BYTEME(AMD_MANUFACT): | |
236 | info->flash_id = FLASH_MAN_AMD; | |
237 | break; | |
238 | case BYTEME(FUJ_MANUFACT): | |
239 | info->flash_id = FLASH_MAN_FUJ; | |
240 | break; | |
241 | case BYTEME(SST_MANUFACT): | |
242 | info->flash_id = FLASH_MAN_SST; | |
243 | break; | |
244 | case BYTEME(STM_MANUFACT): | |
245 | info->flash_id = FLASH_MAN_STM; | |
246 | break; | |
247 | case BYTEME(INTEL_MANUFACT): | |
248 | info->flash_id = FLASH_MAN_INTEL; | |
249 | break; | |
250 | default: | |
251 | info->flash_id = FLASH_UNKNOWN; | |
252 | info->sector_count = 0; | |
253 | info->size = 0; | |
254 | addr[0] = BS(0xFF); /* restore read mode, (yes, BS is a NOP) */ | |
255 | return 0; /* no or unknown flash */ | |
256 | } | |
257 | ||
258 | device = BS(addr[2]); /* device ID */ | |
259 | ||
260 | DEBUGF("Device ID @ 0x%08lx: 0x%08x\n", (ulong)(&addr[1]), device); | |
261 | ||
262 | switch (device) { | |
263 | case BYTEME(INTEL_ID_28F320J3A): | |
264 | info->flash_id += FLASH_28F320J3A; | |
265 | info->sector_count = 32; | |
266 | info->size = 0x00400000; | |
267 | break; /* => 4 MB */ | |
268 | ||
269 | case BYTEME(INTEL_ID_28F640J3A): | |
270 | info->flash_id += FLASH_28F640J3A; | |
271 | info->sector_count = 64; | |
272 | info->size = 0x00800000; | |
273 | break; /* => 8 MB */ | |
274 | ||
275 | case BYTEME(INTEL_ID_28F128J3A): | |
276 | info->flash_id += FLASH_28F128J3A; | |
277 | info->sector_count = 128; | |
278 | info->size = 0x01000000; | |
279 | break; /* => 16 MB */ | |
280 | ||
281 | default: | |
282 | info->flash_id = FLASH_UNKNOWN; | |
283 | addr[0] = BS(0xFF); /* restore read mode (yes, a NOP) */ | |
284 | return 0; /* => no or unknown flash */ | |
285 | ||
286 | } | |
287 | ||
6d0f6bcf | 288 | if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) { |
0332990b | 289 | printf ("** ERROR: sector count %d > max (%d) **\n", |
6d0f6bcf JCPV |
290 | info->sector_count, CONFIG_SYS_MAX_FLASH_SECT); |
291 | info->sector_count = CONFIG_SYS_MAX_FLASH_SECT; | |
0332990b WD |
292 | } |
293 | ||
294 | addr[0] = BS(0xFF); /* restore read mode */ | |
295 | ||
296 | return (info->size); | |
297 | } | |
298 | ||
299 | ||
300 | /*----------------------------------------------------------------------- | |
301 | */ | |
302 | ||
303 | int flash_erase (flash_info_t *info, int s_first, int s_last) | |
304 | { | |
305 | int flag, prot, sect; | |
306 | ulong start, now, last; | |
307 | ||
308 | if ((s_first < 0) || (s_first > s_last)) { | |
309 | if (info->flash_id == FLASH_UNKNOWN) { | |
310 | printf ("- missing\n"); | |
311 | } else { | |
312 | printf ("- no sectors to erase\n"); | |
313 | } | |
314 | return 1; | |
315 | } | |
316 | ||
317 | if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL) { | |
318 | printf ("Can erase only Intel flash types - aborted\n"); | |
319 | return 1; | |
320 | } | |
321 | ||
322 | prot = 0; | |
323 | for (sect=s_first; sect<=s_last; ++sect) { | |
324 | if (info->protect[sect]) { | |
325 | prot++; | |
326 | } | |
327 | } | |
328 | ||
329 | if (prot) { | |
330 | printf ("- Warning: %d protected sectors will not be erased!\n", prot); | |
331 | } else { | |
332 | printf ("\n"); | |
333 | } | |
334 | ||
335 | start = get_timer (0); | |
336 | last = start; | |
337 | /* Start erase on unprotected sectors */ | |
338 | for (sect = s_first; sect<=s_last; sect++) { | |
339 | if (info->protect[sect] == 0) { /* not protected */ | |
340 | vu_char *addr = (vu_char *)(info->start[sect]); | |
341 | unsigned long status; | |
342 | ||
343 | /* Disable interrupts which might cause a timeout here */ | |
344 | flag = disable_interrupts(); | |
345 | ||
346 | *addr = BS(0x50); /* clear status register */ | |
347 | *addr = BS(0x20); /* erase setup */ | |
348 | *addr = BS(0xD0); /* erase confirm */ | |
349 | ||
350 | /* re-enable interrupts if necessary */ | |
351 | if (flag) { | |
352 | enable_interrupts(); | |
353 | } | |
354 | ||
355 | /* wait at least 80us - let's wait 1 ms */ | |
356 | udelay (1000); | |
357 | ||
358 | while (((status = BS(*addr)) & BYTEME(0x00800080)) != BYTEME(0x00800080)) { | |
6d0f6bcf | 359 | if ((now=get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) { |
0332990b WD |
360 | printf ("Timeout\n"); |
361 | *addr = BS(0xB0); /* suspend erase */ | |
362 | *addr = BS(0xFF); /* reset to read mode */ | |
363 | return 1; | |
364 | } | |
365 | ||
366 | /* show that we're waiting */ | |
367 | if ((now - last) > 1000) { /* every second */ | |
368 | putc ('.'); | |
369 | last = now; | |
370 | } | |
371 | } | |
372 | ||
373 | *addr = BS(0xFF); /* reset to read mode */ | |
374 | } | |
375 | } | |
376 | printf (" done\n"); | |
377 | return 0; | |
378 | } | |
379 | ||
380 | /*----------------------------------------------------------------------- | |
381 | * Copy memory to flash, returns: | |
382 | * 0 - OK | |
383 | * 1 - write timeout | |
384 | * 2 - Flash not erased | |
385 | * 4 - Flash not identified | |
386 | */ | |
387 | ||
388 | #define FLASH_WIDTH 1 /* flash bus width in bytes */ | |
389 | ||
390 | int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) | |
391 | { | |
392 | uchar *wp = (uchar *)addr; | |
393 | int rc; | |
394 | ||
395 | if (info->flash_id == FLASH_UNKNOWN) { | |
396 | return 4; | |
397 | } | |
398 | ||
399 | while (cnt > 0) { | |
400 | if ((rc = write_data(info, wp, *src)) != 0) { | |
401 | return rc; | |
402 | } | |
403 | wp++; | |
404 | src++; | |
405 | cnt--; | |
406 | } | |
407 | ||
408 | return cnt; | |
409 | } | |
410 | ||
411 | /*----------------------------------------------------------------------- | |
412 | * Write a word to Flash, returns: | |
413 | * 0 - OK | |
414 | * 1 - write timeout | |
415 | * 2 - Flash not erased | |
416 | */ | |
417 | static int write_data (flash_info_t *info, uchar *dest, uchar data) | |
418 | { | |
419 | vu_char *addr = (vu_char *)dest; | |
420 | ulong status; | |
421 | ulong start; | |
422 | int flag; | |
423 | ||
424 | /* Check if Flash is (sufficiently) erased */ | |
425 | if ((BS(*addr) & data) != data) { | |
426 | return 2; | |
427 | } | |
428 | /* Disable interrupts which might cause a timeout here */ | |
429 | flag = disable_interrupts(); | |
430 | ||
431 | *addr = BS(0x40); /* write setup */ | |
432 | *addr = data; | |
433 | ||
434 | /* re-enable interrupts if necessary */ | |
435 | if (flag) { | |
436 | enable_interrupts(); | |
437 | } | |
438 | ||
439 | start = get_timer (0); | |
440 | ||
441 | while (((status = BS(*addr)) & BYTEME(0x00800080)) != BYTEME(0x00800080)) { | |
6d0f6bcf | 442 | if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) { |
0332990b WD |
443 | *addr = BS(0xFF); /* restore read mode */ |
444 | return 1; | |
445 | } | |
446 | } | |
447 | ||
448 | *addr = BS(0xFF); /* restore read mode */ | |
449 | ||
450 | return 0; | |
451 | } | |
452 | ||
453 | /*----------------------------------------------------------------------- | |
454 | */ |