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