]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/siemens/SMN42/flash.c
rename CFG_ macros to CONFIG_SYS
[karo-tx-uboot.git] / board / siemens / SMN42 / flash.c
1 /*
2  * (C) Copyright 2006 Embedded Artists AB <www.embeddedartists.com>
3  *
4  * (C) Copyright 2007 Gary Jennejohn garyj@denx.de
5  * Modified to use the routines in cpu/arm720t/lpc2292/flash.c.
6  * Heavily modified to support the SMN42 board from Siemens
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 #include <common.h>
25 #include <asm/byteorder.h>
26 #include <asm/arch/hardware.h>
27
28 static unsigned long flash_addr_table[CONFIG_SYS_MAX_FLASH_BANKS] = CONFIG_SYS_FLASH_BANKS_LIST;
29 flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
30
31 extern int lpc2292_copy_buffer_to_flash(flash_info_t *, ulong);
32 extern int lpc2292_flash_erase(flash_info_t *, int, int);
33 extern int lpc2292_write_buff (flash_info_t *, uchar *, ulong, ulong);
34 static unsigned long ext_flash_init(void);
35 static int ext_flash_erase(flash_info_t *, int, int);
36 static int ext_write_buff(flash_info_t *, uchar *, ulong, ulong);
37
38 /*-----------------------------------------------------------------------
39  */
40
41 ulong flash_init (void)
42 {
43         int j, k;
44         ulong size = 0;
45         ulong flashbase = 0;
46
47         flash_info[0].flash_id = PHILIPS_LPC2292;
48         flash_info[0].size = 0x003E000; /* 256 - 8 KB */
49         flash_info[0].sector_count = 17;
50         memset (flash_info[0].protect, 0, 17);
51         flashbase = 0x00000000;
52         for (j = 0, k = 0; j < 8; j++, k++) {
53                 flash_info[0].start[k] = flashbase;
54                 flashbase += 0x00002000;
55         }
56         for (j = 0; j < 2; j++, k++) {
57                 flash_info[0].start[k] = flashbase;
58                 flashbase += 0x00010000;
59         }
60         for (j = 0; j < 7; j++, k++) {
61                 flash_info[0].start[k] = flashbase;
62                 flashbase += 0x00002000;
63         }
64         size += flash_info[0].size;
65
66         /* Protect monitor and environment sectors */
67         flash_protect (FLAG_PROTECT_SET,
68                  0x0,
69                  0x0 + monitor_flash_len - 1,
70                  &flash_info[0]);
71
72         flash_protect (FLAG_PROTECT_SET,
73                  CONFIG_ENV_ADDR,
74                  CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,
75                  &flash_info[0]);
76
77         size += ext_flash_init();
78
79         return size;
80 }
81
82 /*-----------------------------------------------------------------------
83  */
84 void flash_print_info (flash_info_t * info)
85 {
86         int i;
87         int erased = 0;
88         unsigned long j;
89         unsigned long count;
90         unsigned char *p;
91
92         switch (info->flash_id & FLASH_VENDMASK) {
93         case (PHILIPS_LPC2292 & FLASH_VENDMASK):
94                 printf("Philips: ");
95                 break;
96         case FLASH_MAN_AMD:
97                 printf("AMD: ");
98                 break;
99         default:
100                 printf ("Unknown Vendor ");
101                 break;
102         }
103
104         switch (info->flash_id & FLASH_TYPEMASK) {
105         case (PHILIPS_LPC2292 & FLASH_TYPEMASK):
106                 printf("LPC2292 internal flash\n");
107                 break;
108         case FLASH_S29GL128N:
109                 printf ("S29GL128N (128 Mbit, uniform sector size)\n");
110                 break;
111         default:
112                 printf("Unknown Chip Type\n");
113                 return;
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                 if ((i % 5) == 0) {
122                         printf ("\n   ");
123                 }
124                 if (i < (info->sector_count - 1)) {
125                         count = info->start[i+1] - info->start[i];
126                 }
127                 else {
128                         count = info->start[0] + info->size - info->start[i];
129                 }
130                 p = (unsigned char*)(info->start[i]);
131                 erased = 1;
132                 for (j = 0; j < count; j++) {
133                         if (*p != 0xFF) {
134                                 erased = 0;
135                                 break;
136                         }
137                         p++;
138                 }
139                 printf (" %08lX%s%s", info->start[i], info->protect[i] ? " RO" : "   ",
140                         erased ? " E" : "  ");
141         }
142         printf ("\n");
143 }
144
145 int flash_erase (flash_info_t * info, int s_first, int s_last)
146 {
147         switch (info->flash_id & FLASH_TYPEMASK) {
148                 case (PHILIPS_LPC2292 & FLASH_TYPEMASK):
149                         return lpc2292_flash_erase(info, s_first, s_last);
150                 case FLASH_S29GL128N:
151                         return ext_flash_erase(info, s_first, s_last);
152                 default:
153                         return ERR_PROTECTED;
154         }
155         return ERR_PROTECTED;
156 }
157
158 int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
159 {
160         switch (info->flash_id & FLASH_TYPEMASK) {
161                 case (PHILIPS_LPC2292 & FLASH_TYPEMASK):
162                         return lpc2292_write_buff(info, src, addr, cnt);
163                 case FLASH_S29GL128N:
164                         return ext_write_buff(info, src, addr, cnt);
165                 default:
166                         return ERR_PROG_ERROR;
167         }
168         return ERR_PROG_ERROR;
169 }
170
171 /*--------------------------------------------------------------------------
172  * From here on is code for the external S29GL128N taken from cam5200_flash.c
173  */
174
175 #define CONFIG_SYS_FLASH_WORD_SIZE unsigned short
176
177 static int wait_for_DQ7_32(flash_info_t * info, int sect)
178 {
179         ulong start, now, last;
180         volatile CONFIG_SYS_FLASH_WORD_SIZE *addr =
181                 (CONFIG_SYS_FLASH_WORD_SIZE *) (info->start[sect]);
182
183         start = get_timer(0);
184         last = start;
185         while ((addr[0] & (CONFIG_SYS_FLASH_WORD_SIZE) 0x00800080) !=
186                         (CONFIG_SYS_FLASH_WORD_SIZE) 0x00800080) {
187                 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
188                         printf("Timeout\n");
189                         return -1;
190                 }
191                 /* show that we're waiting */
192                 if ((now - last) > 1000) {      /* every second */
193                         putc('.');
194                         last = now;
195                 }
196         }
197         return 0;
198 }
199
200 int ext_flash_erase(flash_info_t * info, int s_first, int s_last)
201 {
202         volatile CONFIG_SYS_FLASH_WORD_SIZE *addr = (CONFIG_SYS_FLASH_WORD_SIZE *) (info->start[0]);
203         volatile CONFIG_SYS_FLASH_WORD_SIZE *addr2;
204         int flag, prot, sect, l_sect, ret;
205
206         ret = 0;
207         if ((s_first < 0) || (s_first > s_last)) {
208                 if (info->flash_id == FLASH_UNKNOWN)
209                         printf("- missing\n");
210                 else
211                         printf("- no sectors to erase\n");
212                 return 1;
213         }
214
215         if (info->flash_id == FLASH_UNKNOWN) {
216                 printf("Can't erase unknown flash type - aborted\n");
217                 return 1;
218         }
219
220         prot = 0;
221         for (sect = s_first; sect <= s_last; ++sect) {
222                 if (info->protect[sect])
223                         prot++;
224         }
225
226         if (prot)
227                 printf("- Warning: %d protected sectors will not be erased!", prot);
228
229         printf("\n");
230
231         l_sect = -1;
232
233         /* Disable interrupts which might cause a timeout here */
234         flag = disable_interrupts();
235
236         /* Start erase on unprotected sectors */
237         for (sect = s_first; sect <= s_last; sect++) {
238                 if (info->protect[sect] == 0) { /* not protected */
239                         addr2 = (CONFIG_SYS_FLASH_WORD_SIZE *) (info->start[sect]);
240
241                         addr[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00AA00AA;
242                         addr[CONFIG_SYS_FLASH_ADDR1] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00550055;
243                         addr[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00800080;
244                         addr[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00AA00AA;
245                         addr[CONFIG_SYS_FLASH_ADDR1] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00550055;
246                         addr2[0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00300030;     /* sector erase */
247
248                         l_sect = sect;
249                         /*
250                          * Wait for each sector to complete, it's more
251                          * reliable.  According to AMD Spec, you must
252                          * issue all erase commands within a specified
253                          * timeout.  This has been seen to fail, especially
254                          * if printf()s are included (for debug)!!
255                          */
256                         ret = wait_for_DQ7_32(info, sect);
257                         if (ret) {
258                                 ret = ERR_PROTECTED;
259                                 break;
260                         }
261                 }
262         }
263
264         /* re-enable interrupts if necessary */
265         if (flag)
266                 enable_interrupts();
267
268         /* wait at least 80us - let's wait 1 ms */
269         udelay(1000);
270
271         /* reset to read mode */
272         addr = (CONFIG_SYS_FLASH_WORD_SIZE *) info->start[0];
273         addr[0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00F000F0;      /* reset bank */
274
275         if (ret)
276                 printf(" error\n");
277         else
278                 printf(" done\n");
279         return ret;
280 }
281
282 static ulong flash_get_size(vu_long * addr, flash_info_t * info)
283 {
284         short i;
285         CONFIG_SYS_FLASH_WORD_SIZE value;
286         ulong base = (ulong) addr;
287         volatile CONFIG_SYS_FLASH_WORD_SIZE *addr2 = (CONFIG_SYS_FLASH_WORD_SIZE *) addr;
288
289         /* Write auto select command: read Manufacturer ID */
290         addr2[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00AA00AA;
291         addr2[CONFIG_SYS_FLASH_ADDR1] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00550055;
292         addr2[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00900090;
293         udelay(1000);
294
295         value = addr2[0];
296
297         switch (value) {
298                 case (CONFIG_SYS_FLASH_WORD_SIZE) AMD_MANUFACT:
299                         info->flash_id = FLASH_MAN_AMD;
300                         break;
301                 default:
302                         info->flash_id = FLASH_UNKNOWN;
303                         info->sector_count = 0;
304                         info->size = 0;
305                         return (0);     /* no or unknown flash  */
306         }
307
308         value = addr2[1];       /* device ID            */
309
310         switch (value) {
311                 case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_MIRROR:
312                         value = addr2[14];
313                         switch(value) {
314                                 case (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_GL128N_2:
315                                         value = addr2[15];
316                                         if (value != (CONFIG_SYS_FLASH_WORD_SIZE)AMD_ID_GL128N_3) {
317                                                 info->flash_id = FLASH_UNKNOWN;
318                                         } else {
319                                                 info->flash_id += FLASH_S29GL128N;
320                                                 info->sector_count = 128;
321                                                 info->size = 0x01000000;
322                                         }
323                                         break;
324                                 default:
325                                         info->flash_id = FLASH_UNKNOWN;
326                                         return(0);
327                         }
328                         break;
329
330                 default:
331                         info->flash_id = FLASH_UNKNOWN;
332                         return (0);     /* => no or unknown flash */
333         }
334
335         /* set up sector start address table */
336         for (i = 0; i < info->sector_count; i++)
337                 info->start[i] = base + (i * 0x00020000);
338
339         /* check for protected sectors */
340         for (i = 0; i < info->sector_count; i++) {
341                 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
342                 /* D0 = 1 if protected */
343                 addr2 = (volatile CONFIG_SYS_FLASH_WORD_SIZE *)(info->start[i]);
344
345                 info->protect[i] = addr2[2] & 1;
346         }
347
348         /* issue bank reset to return to read mode */
349         addr2[0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00F000F0;
350
351         return (info->size);
352 }
353
354 static unsigned long ext_flash_init(void)
355 {
356         unsigned long total_b = 0;
357         unsigned long size_b[CONFIG_SYS_MAX_FLASH_BANKS];
358         int i;
359
360         /* Init: no FLASHes known */
361         for (i = 1; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
362                 flash_info[i].flash_id = FLASH_UNKNOWN;
363                 flash_info[i].sector_count = -1;
364                 flash_info[i].size = 0;
365
366                 /* call flash_get_size() to initialize sector address */
367                 size_b[i] = flash_get_size((vu_long *) flash_addr_table[i],
368                                 &flash_info[i]);
369
370                 flash_info[i].size = size_b[i];
371
372                 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
373                         printf("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n",
374                                         i+1, size_b[i], size_b[i] << 20);
375                         flash_info[i].sector_count = -1;
376                         flash_info[i].size = 0;
377                 }
378
379                 total_b += flash_info[i].size;
380         }
381
382         return total_b;
383 }
384
385 static int write_word(flash_info_t * info, ulong dest, ushort data)
386 {
387         volatile CONFIG_SYS_FLASH_WORD_SIZE *addr2 = (CONFIG_SYS_FLASH_WORD_SIZE *) (info->start[0]);
388         volatile CONFIG_SYS_FLASH_WORD_SIZE *dest2 = (CONFIG_SYS_FLASH_WORD_SIZE *) dest;
389         volatile CONFIG_SYS_FLASH_WORD_SIZE *data2 = (CONFIG_SYS_FLASH_WORD_SIZE *) &data;
390         ulong start;
391         int flag;
392
393         /* Check if Flash is (sufficiently) erased */
394         if ((*dest2 & *data2) != *data2) {
395                 return (2);
396         }
397
398         /* Disable interrupts which might cause a timeout here */
399         flag = disable_interrupts();
400
401         addr2[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00AA00AA;
402         addr2[CONFIG_SYS_FLASH_ADDR1] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00550055;
403         addr2[CONFIG_SYS_FLASH_ADDR0] = (CONFIG_SYS_FLASH_WORD_SIZE) 0x00A000A0;
404         *dest2 = *data2;
405
406         /* re-enable interrupts if necessary */
407         if (flag)
408                 enable_interrupts();
409
410         /* data polling for D7 */
411         start = get_timer(0);
412         while ((*dest2 & (CONFIG_SYS_FLASH_WORD_SIZE) 0x00800080) !=
413                         (*data2 & (CONFIG_SYS_FLASH_WORD_SIZE) 0x00800080)) {
414
415                 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
416                         printf("WRITE_TOUT\n");
417                         return (1);
418                 }
419         }
420         return (0);
421 }
422
423 /*-----------------------------------------------------------------------
424  * This is taken from the original flash.c for the LPC2292 SODIMM board
425  * and modified to suit.
426  */
427
428 int ext_write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
429 {
430         ushort tmp;
431         ulong i;
432         uchar* src_org;
433         uchar* dst_org;
434         ulong cnt_org = cnt;
435         int ret = ERR_OK;
436
437         src_org = src;
438         dst_org = (uchar*)addr;
439
440         if (addr & 1) {         /* if odd address */
441                 tmp = *((uchar*)(addr - 1)); /* little endian */
442                 tmp |= (*src << 8);
443                 if (write_word(info, addr - 1, tmp))
444                         return ERR_PROG_ERROR;
445                 addr += 1;
446                 cnt -= 1;
447                 src++;
448         }
449         while (cnt > 1) {
450                 tmp = ((*(src+1)) << 8) + (*src); /* little endian */
451                 if (write_word(info, addr, tmp))
452                         return ERR_PROG_ERROR;
453                 addr += 2;
454                 src += 2;
455                 cnt -= 2;
456         }
457         if (cnt > 0) {
458                 tmp = (*((uchar*)(addr + 1))) << 8;
459                 tmp |= *src;
460                 if (write_word(info, addr, tmp))
461                         return ERR_PROG_ERROR;
462         }
463
464         for (i = 0; i < cnt_org; i++) {
465                 if (*dst_org != *src_org) {
466                         printf("Write failed. Byte %lX differs\n", i);
467                         ret = ERR_PROG_ERROR;
468                         break;
469                 }
470                 dst_org++;
471                 src_org++;
472         }
473
474         return ret;
475 }