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