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