]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/sandburst/common/flash.c
Coding Style cleanup: remove trailing white space
[karo-tx-uboot.git] / board / sandburst / common / flash.c
1 /*
2  * (C) Copyright 2002-2005
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * (C) Copyright 2002 Jun Gu <jung@artesyncp.com>
6  * Add support for Am29F016D and dynamic switch setting.
7  *
8  * SPDX-License-Identifier:     GPL-2.0+
9  */
10 /*
11  * Ported from Ebony flash support
12  * Travis B. Sawyer
13  * Sandburst Corporation
14  */
15 #include <common.h>
16 #include <asm/ppc4xx.h>
17 #include <asm/processor.h>
18
19
20 #undef DEBUG
21 #ifdef DEBUG
22 #define DEBUGF(x...) printf(x)
23 #else
24 #define DEBUGF(x...)
25 #endif /* DEBUG */
26
27
28 flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips    */
29
30 static unsigned long flash_addr_table[8][CONFIG_SYS_MAX_FLASH_BANKS] = {
31         {0xfff80000}    /* Boot Flash */
32 };
33
34 /*-----------------------------------------------------------------------
35  * Functions
36  */
37 static ulong flash_get_size (vu_long *addr, flash_info_t *info);
38 static int write_word (flash_info_t *info, ulong dest, ulong data);
39
40
41 #define ADDR0           0x5555
42 #define ADDR1           0x2aaa
43 #define FLASH_WORD_SIZE unsigned char
44
45
46 /*-----------------------------------------------------------------------
47  */
48
49 unsigned long flash_init (void)
50 {
51         unsigned long total_b = 0;
52         unsigned long size_b[CONFIG_SYS_MAX_FLASH_BANKS];
53         unsigned short index = 0;
54         int i;
55
56
57         DEBUGF("\n");
58         DEBUGF("FLASH: Index: %d\n", index);
59
60         /* Init: no FLASHes known */
61         for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
62                 flash_info[i].flash_id = FLASH_UNKNOWN;
63                 flash_info[i].sector_count = -1;
64                 flash_info[i].size = 0;
65
66                 /* check whether the address is 0 */
67                 if (flash_addr_table[index][i] == 0) {
68                         continue;
69                 }
70
71                 /* call flash_get_size() to initialize sector address */
72                 size_b[i] = flash_get_size(
73                         (vu_long *)flash_addr_table[index][i], &flash_info[i]);
74                 flash_info[i].size = size_b[i];
75                 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
76                         printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n",
77                                 i, size_b[i], size_b[i]<<20);
78                         flash_info[i].sector_count = -1;
79                         flash_info[i].size = 0;
80                 }
81
82                 total_b += flash_info[i].size;
83         }
84
85         return total_b;
86 }
87
88
89 /*-----------------------------------------------------------------------
90  */
91 void flash_print_info  (flash_info_t *info)
92 {
93         int i;
94         int k;
95         int size;
96         int erased;
97         volatile unsigned long *flash;
98
99         if (info->flash_id == FLASH_UNKNOWN) {
100                 printf ("missing or unknown FLASH type\n");
101                 return;
102         }
103
104         switch (info->flash_id & FLASH_VENDMASK) {
105         case FLASH_MAN_AMD:     printf ("AMD ");                break;
106         default:                printf ("Unknown Vendor ");     break;
107         }
108
109         switch (info->flash_id & FLASH_TYPEMASK) {
110         case FLASH_AM040:       printf ("AM29F040 (512 Kbit, uniform sector size)\n");
111                 break;
112         default:                printf ("Unknown Chip Type\n");
113                 break;
114         }
115
116         printf ("  Size: %ld KB in %d Sectors\n",
117                 info->size >> 10, info->sector_count);
118
119         printf ("  Sector Start Addresses:");
120         for (i=0; i<info->sector_count; ++i) {
121                 /*
122                  * Check if whole sector is erased
123                  */
124                 if (i != (info->sector_count-1))
125                         size = info->start[i+1] - info->start[i];
126                 else
127                         size = info->start[0] + info->size - info->start[i];
128                 erased = 1;
129                 flash = (volatile unsigned long *)info->start[i];
130                 size = size >> 2;        /* divide by 4 for longword access */
131                 for (k=0; k<size; k++)
132                 {
133                         if (*flash++ != 0xffffffff)
134                         {
135                                 erased = 0;
136                                 break;
137                         }
138                 }
139
140                 if ((i % 5) == 0)
141                         printf ("\n   ");
142                         printf (" %08lX%s%s",
143                                 info->start[i],
144                                 erased ? " E" : "  ",
145                                 info->protect[i] ? "RO " : "   "
146                                 );
147                         }
148                 printf ("\n");
149                 return;
150         }
151
152 /*-----------------------------------------------------------------------
153  */
154
155
156 /*-----------------------------------------------------------------------
157  */
158
159 /*
160  * The following code cannot be run from FLASH!
161  */
162 static ulong flash_get_size (vu_long *addr, flash_info_t *info)
163 {
164         short i;
165         FLASH_WORD_SIZE value;
166         ulong base = (ulong)addr;
167         volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)addr;
168
169         DEBUGF("FLASH ADDR: %08x\n", (unsigned)addr );
170
171         /* Write auto select command: read Manufacturer ID */
172         udelay(10000);
173         addr2[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
174         udelay(1000);
175         addr2[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
176         udelay(1000);
177         addr2[ADDR0] = (FLASH_WORD_SIZE)0x00900090;
178         udelay(1000);
179
180         value = addr2[0];
181
182         DEBUGF("FLASH MANUFACT: %x\n", value);
183
184         switch (value) {
185         case (FLASH_WORD_SIZE)AMD_MANUFACT:
186                 info->flash_id = FLASH_MAN_AMD;
187                 break;
188         default:
189                 info->flash_id = FLASH_UNKNOWN;
190                 info->sector_count = 0;
191                 info->size = 0;
192                 return (0);                     /* no or unknown flash  */
193         }
194
195         value = addr2[1];                       /* device ID            */
196
197         DEBUGF("\nFLASH DEVICEID: %x\n", value);
198
199         switch (value) {
200         case (FLASH_WORD_SIZE)AMD_ID_LV040B:
201                 info->flash_id += FLASH_AM040;
202                 info->sector_count = 8;
203                 info->size = 0x00080000; /* => 512 kb */
204                 break;
205
206         default:
207                 info->flash_id = FLASH_UNKNOWN;
208                 return (0);                     /* => no or unknown flash */
209
210         }
211
212         /* set up sector start address table */
213         if (info->flash_id  == FLASH_AM040) {
214                 for (i = 0; i < info->sector_count; i++)
215                         info->start[i] = base + (i * 0x00010000);
216         } else {
217                 if (info->flash_id & FLASH_BTYPE) {
218                         /* set sector offsets for bottom boot block type        */
219                         info->start[0] = base + 0x00000000;
220                         info->start[1] = base + 0x00004000;
221                         info->start[2] = base + 0x00006000;
222                         info->start[3] = base + 0x00008000;
223                         for (i = 4; i < info->sector_count; i++) {
224                                 info->start[i] = base + (i * 0x00010000) - 0x00030000;
225                         }
226                 } else {
227                         /* set sector offsets for top boot block type           */
228                         i = info->sector_count - 1;
229                         info->start[i--] = base + info->size - 0x00004000;
230                         info->start[i--] = base + info->size - 0x00006000;
231                         info->start[i--] = base + info->size - 0x00008000;
232                         for (; i >= 0; i--) {
233                                 info->start[i] = base + i * 0x00010000;
234                         }
235                 }
236         }
237
238         /* check for protected sectors */
239         for (i = 0; i < info->sector_count; i++) {
240                 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
241                 /* D0 = 1 if protected */
242                 addr2 = (volatile FLASH_WORD_SIZE *)(info->start[i]);
243                 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST)
244                         info->protect[i] = 0;
245                 else
246                         info->protect[i] = addr2[2] & 1;
247         }
248
249         /* reset to return to reading data */
250         addr2[0] = (FLASH_WORD_SIZE) 0x00F000F0;        /* reset bank */
251
252         /*
253          * Prevent writes to uninitialized FLASH.
254          */
255         if (info->flash_id != FLASH_UNKNOWN) {
256                 addr2 = (FLASH_WORD_SIZE *)info->start[0];
257                 *addr2 = (FLASH_WORD_SIZE)0x00F000F0;   /* reset bank */
258         }
259
260         return (info->size);
261 }
262
263 int wait_for_DQ7(flash_info_t *info, int sect)
264 {
265         ulong start, now, last;
266         volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[sect]);
267
268         start = get_timer (0);
269         last  = start;
270         while ((addr[0] & (FLASH_WORD_SIZE)0x00800080) != (FLASH_WORD_SIZE)0x00800080) {
271                 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
272                         printf ("Timeout\n");
273                         return -1;
274                 }
275                 /* show that we're waiting */
276                 if ((now - last) > 1000) {  /* every second */
277                         putc ('.');
278                         last = now;
279                 }
280         }
281         return 0;
282 }
283
284 /*-----------------------------------------------------------------------
285  */
286
287 int flash_erase (flash_info_t *info, int s_first, int s_last)
288 {
289         volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[0]);
290         volatile FLASH_WORD_SIZE *addr2;
291         int flag, prot, sect;
292         int i;
293
294         if ((s_first < 0) || (s_first > s_last)) {
295                 if (info->flash_id == FLASH_UNKNOWN) {
296                         printf ("- missing\n");
297                 } else {
298                         printf ("- no sectors to erase\n");
299                 }
300                 return 1;
301         }
302
303         if (info->flash_id == FLASH_UNKNOWN) {
304                 printf ("Can't erase unknown flash type - aborted\n");
305                 return 1;
306         }
307
308         prot = 0;
309         for (sect=s_first; sect<=s_last; ++sect) {
310                 if (info->protect[sect]) {
311                         prot++;
312                 }
313         }
314
315         if (prot) {
316                 printf ("- Warning: %d protected sectors will not be erased!\n",
317                         prot);
318         } else {
319                 printf ("\n");
320         }
321
322         /* Disable interrupts which might cause a timeout here */
323         flag = disable_interrupts();
324
325         /* Start erase on unprotected sectors */
326         for (sect = s_first; sect<=s_last; sect++) {
327                 if (info->protect[sect] == 0) { /* not protected */
328                         addr2 = (FLASH_WORD_SIZE *)(info->start[sect]);
329                         DEBUGF("Erasing sector %p\n", addr2);
330
331                         if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
332                                 addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
333                                 addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
334                                 addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080;
335                                 addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
336                                 addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
337                                 addr2[0] = (FLASH_WORD_SIZE)0x00500050;  /* block erase */
338                                 for (i=0; i<50; i++)
339                                         udelay(1000);  /* wait 1 ms */
340                         } else {
341                                 addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
342                                 addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
343                                 addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080;
344                                 addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
345                                 addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
346                                 addr2[0] = (FLASH_WORD_SIZE)0x00300030;  /* sector erase */
347                         }
348                         /*
349                          * Wait for each sector to complete, it's more
350                          * reliable.  According to AMD Spec, you must
351                          * issue all erase commands within a specified
352                          * timeout.  This has been seen to fail, especially
353                          * if printf()s are included (for debug)!!
354                          */
355                         wait_for_DQ7(info, sect);
356                 }
357         }
358
359         /* re-enable interrupts if necessary */
360         if (flag)
361                 enable_interrupts();
362
363         /* wait at least 80us - let's wait 1 ms */
364         udelay (1000);
365
366         /* reset to read mode */
367         addr = (FLASH_WORD_SIZE *)info->start[0];
368         addr[0] = (FLASH_WORD_SIZE)0x00F000F0;  /* reset bank */
369
370         printf (" done\n");
371         return 0;
372 }
373
374 /*-----------------------------------------------------------------------
375  * Copy memory to flash, returns:
376  * 0 - OK
377  * 1 - write timeout
378  * 2 - Flash not erased
379  */
380
381 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
382 {
383         ulong cp, wp, data;
384         int i, l, rc;
385
386         wp = (addr & ~3);       /* get lower word aligned address */
387
388         /*
389          * handle unaligned start bytes
390          */
391         if ((l = addr - wp) != 0) {
392                 data = 0;
393                 for (i=0, cp=wp; i<l; ++i, ++cp) {
394                         data = (data << 8) | (*(uchar *)cp);
395                 }
396                 for (; i<4 && cnt>0; ++i) {
397                         data = (data << 8) | *src++;
398                         --cnt;
399                         ++cp;
400                 }
401                 for (; cnt==0 && i<4; ++i, ++cp) {
402                         data = (data << 8) | (*(uchar *)cp);
403                 }
404
405                 if ((rc = write_word(info, wp, data)) != 0) {
406                         return (rc);
407                 }
408                 wp += 4;
409         }
410
411         /*
412          * handle word aligned part
413          */
414         while (cnt >= 4) {
415                 data = 0;
416                 for (i=0; i<4; ++i) {
417                         data = (data << 8) | *src++;
418                 }
419                 if ((rc = write_word(info, wp, data)) != 0) {
420                         return (rc);
421                 }
422                 wp  += 4;
423                 cnt -= 4;
424         }
425
426         if (cnt == 0) {
427                 return (0);
428         }
429
430         /*
431          * handle unaligned tail bytes
432          */
433         data = 0;
434         for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
435                 data = (data << 8) | *src++;
436                 --cnt;
437         }
438         for (; i<4; ++i, ++cp) {
439                 data = (data << 8) | (*(uchar *)cp);
440         }
441
442         return (write_word(info, wp, data));
443 }
444
445 /*-----------------------------------------------------------------------
446  * Write a word to Flash, returns:
447  * 0 - OK
448  * 1 - write timeout
449  * 2 - Flash not erased
450  */
451 static int write_word (flash_info_t * info, ulong dest, ulong data)
452 {
453         volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *) (info->start[0]);
454         volatile FLASH_WORD_SIZE *dest2 = (FLASH_WORD_SIZE *) dest;
455         volatile FLASH_WORD_SIZE *data2 = (FLASH_WORD_SIZE *) & data;
456         ulong start;
457         int i;
458
459         /* Check if Flash is (sufficiently) erased */
460         if ((*((volatile FLASH_WORD_SIZE *) dest) &
461              (FLASH_WORD_SIZE) data) != (FLASH_WORD_SIZE) data) {
462                 return (2);
463         }
464
465         for (i = 0; i < 4 / sizeof (FLASH_WORD_SIZE); i++) {
466                 int flag;
467
468                 /* Disable interrupts which might cause a timeout here */
469                 flag = disable_interrupts ();
470
471                 addr2[ADDR0] = (FLASH_WORD_SIZE) 0x00AA00AA;
472                 addr2[ADDR1] = (FLASH_WORD_SIZE) 0x00550055;
473                 addr2[ADDR0] = (FLASH_WORD_SIZE) 0x00A000A0;
474
475                 dest2[i] = data2[i];
476
477                 /* re-enable interrupts if necessary */
478                 if (flag)
479                         enable_interrupts ();
480
481                 /* data polling for D7 */
482                 start = get_timer (0);
483                 while ((dest2[i] & (FLASH_WORD_SIZE) 0x00800080) !=
484                        (data2[i] & (FLASH_WORD_SIZE) 0x00800080)) {
485
486                         if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
487                                 return (1);
488                         }
489                 }
490         }
491
492         return (0);
493 }