]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/hermes/flash.c
arm: vf610: improve evaluation of reset source
[karo-tx-uboot.git] / board / hermes / flash.c
1 /*
2  * (C) Copyright 2000
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9 #include <mpc8xx.h>
10
11 flash_info_t    flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
12
13 /*-----------------------------------------------------------------------
14  * Functions
15  */
16 static ulong flash_get_size (vu_long *addr, flash_info_t *info);
17 static int write_byte (flash_info_t *info, ulong dest, uchar data);
18 static void flash_get_offsets (ulong base, flash_info_t *info);
19
20 /*-----------------------------------------------------------------------
21  */
22
23 unsigned long flash_init (void)
24 {
25         volatile immap_t     *immap  = (immap_t *)CONFIG_SYS_IMMR;
26         volatile memctl8xx_t *memctl = &immap->im_memctl;
27         unsigned long size;
28         int i;
29
30         /* Init: no FLASHes known */
31         for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
32                 flash_info[i].flash_id = FLASH_UNKNOWN;
33         }
34
35         /* Static FLASH Bank configuration here - FIXME XXX */
36
37         size = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
38
39         if (flash_info[0].flash_id == FLASH_UNKNOWN) {
40                 printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
41                         size, size<<20);
42         }
43
44         /* Remap FLASH according to real size */
45         memctl->memc_or0 = CONFIG_SYS_OR_TIMING_FLASH | (-size & 0xFFFF8000);
46         memctl->memc_br0 = (CONFIG_SYS_FLASH_BASE & BR_BA_MSK) |
47                                 (memctl->memc_br0 & ~(BR_BA_MSK));
48
49         /* Re-do sizing to get full correct info */
50         size = flash_get_size((vu_long *)CONFIG_SYS_FLASH_BASE, &flash_info[0]);
51
52         flash_get_offsets (CONFIG_SYS_FLASH_BASE, &flash_info[0]);
53
54 #if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
55         /* monitor protection ON by default */
56         flash_protect(FLAG_PROTECT_SET,
57                       CONFIG_SYS_MONITOR_BASE,
58                       CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
59                       &flash_info[0]);
60 #endif
61
62         flash_info[0].size = size;
63
64         return (size);
65 }
66
67 /*-----------------------------------------------------------------------
68  */
69 static void flash_get_offsets (ulong base, flash_info_t *info)
70 {
71         int i;
72
73         /* set up sector start address table */
74         if (info->flash_id & FLASH_BTYPE) {
75                 /* set sector offsets for bottom boot block type        */
76                 info->start[0] = base + 0x00000000;
77                 info->start[1] = base + 0x00004000;
78                 info->start[2] = base + 0x00006000;
79                 info->start[3] = base + 0x00008000;
80                 for (i = 4; i < info->sector_count; i++) {
81                         info->start[i] = base + (i * 0x00010000) - 0x00030000;
82                 }
83         } else {
84                 /* set sector offsets for top boot block type           */
85                 i = info->sector_count - 1;
86                 info->start[i--] = base + info->size - 0x00004000;
87                 info->start[i--] = base + info->size - 0x00006000;
88                 info->start[i--] = base + info->size - 0x00008000;
89                 for (; i >= 0; i--) {
90                         info->start[i] = base + i * 0x00010000;
91                 }
92         }
93
94 }
95
96 /*-----------------------------------------------------------------------
97  */
98 void flash_print_info  (flash_info_t *info)
99 {
100         int i;
101
102         if (info->flash_id == FLASH_UNKNOWN) {
103                 printf ("missing or unknown FLASH type\n");
104                 return;
105         }
106
107         switch (info->flash_id & FLASH_VENDMASK) {
108         case FLASH_MAN_AMD:     printf ("AMD ");                break;
109         case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
110         default:                printf ("Unknown Vendor ");     break;
111         }
112
113         switch (info->flash_id & FLASH_TYPEMASK) {
114         case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
115                                 break;
116         case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
117                                 break;
118         case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
119                                 break;
120         case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
121                                 break;
122         case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
123                                 break;
124         case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
125                                 break;
126         case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
127                                 break;
128         case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
129                                 break;
130         default:                printf ("Unknown Chip Type\n");
131                                 break;
132         }
133
134         printf ("  Size: %ld MB in %d Sectors\n",
135                 info->size >> 20, info->sector_count);
136
137         printf ("  Sector Start Addresses:");
138         for (i=0; i<info->sector_count; ++i) {
139                 if ((i % 5) == 0)
140                         printf ("\n   ");
141                 printf (" %08lX%s",
142                         info->start[i],
143                         info->protect[i] ? " (RO)" : "     "
144                 );
145         }
146         printf ("\n");
147         return;
148 }
149
150 /*-----------------------------------------------------------------------
151  */
152
153
154 /*-----------------------------------------------------------------------
155  */
156
157 /*
158  * The following code cannot be run from FLASH!
159  */
160
161 static ulong flash_get_size (vu_long *addr, flash_info_t *info)
162 {
163         short i;
164         uchar value;
165         vu_char *caddr = (vu_char *)addr;
166         ulong base = (ulong)addr;
167
168
169         /* Write auto select command: read Manufacturer ID */
170         caddr[0x0AAA] = 0xAA;
171         caddr[0x0555] = 0x55;
172         caddr[0x0AAA] = 0x90;
173
174         value = caddr[0];
175         switch (value) {
176         case (AMD_MANUFACT & 0xFF):
177                 info->flash_id = FLASH_MAN_AMD;
178                 break;
179         case (FUJ_MANUFACT & 0xFF):
180                 info->flash_id = FLASH_MAN_FUJ;
181                 break;
182         default:
183                 info->flash_id = FLASH_UNKNOWN;
184                 info->sector_count = 0;
185                 info->size = 0;
186                 return (0);                     /* no or unknown flash  */
187         }
188
189         value = caddr[2];                       /* device ID            */
190
191         switch (value) {
192         case (AMD_ID_LV400T & 0xFF):
193                 info->flash_id += FLASH_AM400T;
194                 info->sector_count = 11;
195                 info->size = 0x00080000;
196                 break;                          /* => 512 kB            */
197
198         case (AMD_ID_LV400B & 0xFF):
199                 info->flash_id += FLASH_AM400B;
200                 info->sector_count = 11;
201                 info->size = 0x00080000;
202                 break;                          /* => 512 kB            */
203
204         case (AMD_ID_LV800T & 0xFF):
205                 info->flash_id += FLASH_AM800T;
206                 info->sector_count = 19;
207                 info->size = 0x00100000;
208                 break;                          /* => 1 MB              */
209
210         case (AMD_ID_LV800B & 0xFF):
211                 info->flash_id += FLASH_AM800B;
212                 info->sector_count = 19;
213                 info->size = 0x00100000;
214                 break;                          /* => 1 MB              */
215
216         case (AMD_ID_LV160T & 0xFF):
217                 info->flash_id += FLASH_AM160T;
218                 info->sector_count = 35;
219                 info->size = 0x00200000;
220                 break;                          /* => 2 MB              */
221
222         case (AMD_ID_LV160B & 0xFF):
223                 info->flash_id += FLASH_AM160B;
224                 info->sector_count = 35;
225                 info->size = 0x00200000;
226                 break;                          /* => 2 MB              */
227 #if 0   /* enable when device IDs are available */
228         case (AMD_ID_LV320T & 0xFF):
229                 info->flash_id += FLASH_AM320T;
230                 info->sector_count = 67;
231                 info->size = 0x00400000;
232                 break;                          /* => 4 MB              */
233
234         case (AMD_ID_LV320B & 0xFF):
235                 info->flash_id += FLASH_AM320B;
236                 info->sector_count = 67;
237                 info->size = 0x00400000;
238                 break;                          /* => 4 MB              */
239 #endif
240         default:
241                 info->flash_id = FLASH_UNKNOWN;
242                 return (0);                     /* => no or unknown flash */
243
244         }
245
246         /* set up sector start address table */
247         if (info->flash_id & FLASH_BTYPE) {
248                 /* set sector offsets for bottom boot block type        */
249                 info->start[0] = base + 0x00000000;
250                 info->start[1] = base + 0x00004000;
251                 info->start[2] = base + 0x00006000;
252                 info->start[3] = base + 0x00008000;
253                 for (i = 4; i < info->sector_count; i++) {
254                         info->start[i] = base + (i * 0x00010000) - 0x00030000;
255                 }
256         } else {
257                 /* set sector offsets for top boot block type           */
258                 i = info->sector_count - 1;
259                 info->start[i--] = base + info->size - 0x00004000;
260                 info->start[i--] = base + info->size - 0x00006000;
261                 info->start[i--] = base + info->size - 0x00008000;
262                 for (; i >= 0; i--) {
263                         info->start[i] = base + i * 0x00010000;
264                 }
265         }
266
267         /* check for protected sectors */
268         for (i = 0; i < info->sector_count; i++) {
269                 /* read sector protection: D0 = 1 if protected */
270                 caddr = (volatile unsigned char *)(info->start[i]);
271                 info->protect[i] = caddr[4] & 1;
272         }
273
274         /*
275          * Prevent writes to uninitialized FLASH.
276          */
277         if (info->flash_id != FLASH_UNKNOWN) {
278                 caddr = (vu_char *)info->start[0];
279
280                 *caddr = 0xF0;  /* reset bank */
281         }
282
283         return (info->size);
284 }
285
286
287 /*-----------------------------------------------------------------------
288  */
289
290 int     flash_erase (flash_info_t *info, int s_first, int s_last)
291 {
292         vu_char *addr = (vu_char*)(info->start[0]);
293         int flag, prot, sect, l_sect;
294         ulong start, now, last;
295
296         if ((s_first < 0) || (s_first > s_last)) {
297                 if (info->flash_id == FLASH_UNKNOWN) {
298                         printf ("- missing\n");
299                 } else {
300                         printf ("- no sectors to erase\n");
301                 }
302                 return 1;
303         }
304
305         if ((info->flash_id == FLASH_UNKNOWN) ||
306             (info->flash_id > FLASH_AMD_COMP)) {
307                 printf ("Can't erase unknown flash type %08lx - aborted\n",
308                         info->flash_id);
309                 return 1;
310         }
311
312         prot = 0;
313         for (sect=s_first; sect<=s_last; ++sect) {
314                 if (info->protect[sect]) {
315                         prot++;
316                 }
317         }
318
319         if (prot) {
320                 printf ("- Warning: %d protected sectors will not be erased!\n",
321                         prot);
322         } else {
323                 printf ("\n");
324         }
325
326         l_sect = -1;
327
328         /* Disable interrupts which might cause a timeout here */
329         flag = disable_interrupts();
330
331         addr[0x0AAA] = 0xAA;
332         addr[0x0555] = 0x55;
333         addr[0x0AAA] = 0x80;
334         addr[0x0AAA] = 0xAA;
335         addr[0x0555] = 0x55;
336
337         /* Start erase on unprotected sectors */
338         for (sect = s_first; sect<=s_last; sect++) {
339                 if (info->protect[sect] == 0) { /* not protected */
340                         addr = (vu_char*)(info->start[sect]);
341                         addr[0] = 0x30;
342                         l_sect = sect;
343                 }
344         }
345
346         /* re-enable interrupts if necessary */
347         if (flag)
348                 enable_interrupts();
349
350         /* wait at least 80us - let's wait 1 ms */
351         udelay (1000);
352
353         /*
354          * We wait for the last triggered sector
355          */
356         if (l_sect < 0)
357                 goto DONE;
358
359         start = get_timer (0);
360         last  = start;
361         addr = (vu_char*)(info->start[l_sect]);
362         while ((addr[0] & 0x80) != 0x80) {
363                 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
364                         printf ("Timeout\n");
365                         return 1;
366                 }
367                 /* show that we're waiting */
368                 if ((now - last) > 1000) {      /* every second */
369                         putc ('.');
370                         last = now;
371                 }
372         }
373
374 DONE:
375         /* reset to read mode */
376         addr = (vu_char *)info->start[0];
377         addr[0] = 0xF0; /* reset bank */
378
379         printf (" done\n");
380         return 0;
381 }
382
383 /*-----------------------------------------------------------------------
384  * Copy memory to flash, returns:
385  * 0 - OK
386  * 1 - write timeout
387  * 2 - Flash not erased
388  */
389
390 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
391 {
392         int rc;
393
394         while (cnt > 0) {
395                 if ((rc = write_byte(info, addr++, *src++)) != 0) {
396                         return (rc);
397                 }
398                 --cnt;
399         }
400
401         return (0);
402 }
403
404 /*-----------------------------------------------------------------------
405  * Write a word to Flash, returns:
406  * 0 - OK
407  * 1 - write timeout
408  * 2 - Flash not erased
409  */
410 static int write_byte (flash_info_t *info, ulong dest, uchar data)
411 {
412         vu_char *addr = (vu_char*)(info->start[0]);
413         ulong start;
414         int flag;
415
416         /* Check if Flash is (sufficiently) erased */
417         if ((*((vu_char *)dest) & data) != data) {
418                 return (2);
419         }
420         /* Disable interrupts which might cause a timeout here */
421         flag = disable_interrupts();
422
423         addr[0x0AAA] = 0xAA;
424         addr[0x0555] = 0x55;
425         addr[0x0AAA] = 0xA0;
426
427         *((vu_char *)dest) = data;
428
429         /* re-enable interrupts if necessary */
430         if (flag)
431                 enable_interrupts();
432
433         /* data polling for D7 */
434         start = get_timer (0);
435         while ((*((vu_char *)dest) & 0x80) != (data & 0x80)) {
436                 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
437                         return (1);
438                 }
439         }
440         return (0);
441 }
442
443 /*-----------------------------------------------------------------------
444  */