Merge branch 'master' into hpc2
[platform/kernel/u-boot.git] / board / lpc2292sodimm / flash.c
1 /*
2  * (C) Copyright 2006 Embedded Artists AB <www.embeddedartists.com>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
17  * MA 02111-1307 USA
18  */
19
20 #include <common.h>
21 #include <asm/arch/hardware.h>
22
23 /* IAP commands use 32 bytes at the top of CPU internal sram, we
24    use 512 bytes below that */
25 #define COPY_BUFFER_LOCATION 0x40003de0
26
27 #define IAP_LOCATION 0x7ffffff1
28 #define IAP_CMD_PREPARE 50
29 #define IAP_CMD_COPY 51
30 #define IAP_CMD_ERASE 52
31 #define IAP_CMD_CHECK 53
32 #define IAP_CMD_ID 54
33 #define IAP_CMD_VERSION 55
34 #define IAP_CMD_COMPARE 56
35
36 #define IAP_RET_CMD_SUCCESS 0
37
38 #define SST_BASEADDR 0x80000000
39 #define SST_ADDR1 ((volatile ushort*)(SST_BASEADDR + (0x5555 << 1)))
40 #define SST_ADDR2 ((volatile ushort*)(SST_BASEADDR + (0x2AAA << 1)))
41
42
43 static unsigned long command[5];
44 static unsigned long result[2];
45
46 flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
47
48 extern void iap_entry(unsigned long * command, unsigned long * result);
49
50 /*-----------------------------------------------------------------------
51  *
52  */
53 int get_flash_sector(flash_info_t * info, ulong flash_addr)
54 {
55         int i;
56
57         for(i=1; i < (info->sector_count); i++) {
58                 if (flash_addr < (info->start[i]))
59                         break;
60         }
61
62         return (i-1);
63 }
64
65 /*-----------------------------------------------------------------------
66  * This function assumes that flash_addr is aligned on 512 bytes boundary
67  * in flash. This function also assumes that prepare have been called
68  * for the sector in question.
69  */
70 int copy_buffer_to_flash(flash_info_t * info, ulong flash_addr)
71 {
72         int first_sector;
73         int last_sector;
74
75         first_sector = get_flash_sector(info, flash_addr);
76         last_sector = get_flash_sector(info, flash_addr + 512 - 1);
77
78         /* prepare sectors for write */
79         command[0] = IAP_CMD_PREPARE;
80         command[1] = first_sector;
81         command[2] = last_sector;
82         iap_entry(command, result);
83         if (result[0] != IAP_RET_CMD_SUCCESS) {
84                 printf("IAP prepare failed\n");
85                 return ERR_PROG_ERROR;
86         }
87
88         command[0] = IAP_CMD_COPY;
89         command[1] = flash_addr;
90         command[2] = COPY_BUFFER_LOCATION;
91         command[3] = 512;
92         command[4] = CFG_SYS_CLK_FREQ >> 10;
93         iap_entry(command, result);
94         if (result[0] != IAP_RET_CMD_SUCCESS) {
95                 printf("IAP copy failed\n");
96                 return 1;
97         }
98
99         return 0;
100 }
101
102 /*-----------------------------------------------------------------------
103  *
104  */
105 void write_word_sst(ulong addr, ushort data)
106 {
107         ushort tmp;
108
109         *SST_ADDR1 = 0x00AA;
110         *SST_ADDR2 = 0x0055;
111         *SST_ADDR1 = 0x00A0;
112         *((volatile ushort*)addr) = data;
113         /* do data polling */
114         do {
115                 tmp = *((volatile ushort*)addr);
116         } while (tmp != data);
117 }
118
119 /*-----------------------------------------------------------------------
120  */
121
122 ulong flash_init (void)
123 {
124         int j, k;
125         ulong size = 0;
126         ulong flashbase = 0;
127
128         flash_info[0].flash_id = (PHILIPS_LPC2292 & FLASH_VENDMASK);
129         flash_info[0].size = 0x003E000; /* 256 - 8 KB */
130         flash_info[0].sector_count = 17;
131         memset (flash_info[0].protect, 0, 17);
132         flashbase = 0x00000000;
133         for (j = 0, k = 0; j < 8; j++, k++) {
134                 flash_info[0].start[k] = flashbase;
135                 flashbase += 0x00002000;
136         }
137         for (j = 0; j < 2; j++, k++) {
138                 flash_info[0].start[k] = flashbase;
139                 flashbase += 0x00010000;
140         }
141         for (j = 0; j < 7; j++, k++) {
142                 flash_info[0].start[k] = flashbase;
143                 flashbase += 0x00002000;
144         }
145         size += flash_info[0].size;
146
147         flash_info[1].flash_id = (SST_MANUFACT & FLASH_VENDMASK);
148         flash_info[1].size = 0x00200000; /* 2 MB */
149         flash_info[1].sector_count = 512;
150         memset (flash_info[1].protect, 0, 512);
151         flashbase = SST_BASEADDR;
152         for (j=0; j<512; j++) {
153                 flash_info[1].start[j] = flashbase;
154                 flashbase += 0x1000;    /* 4 KB sectors */
155         }
156         size += flash_info[1].size;
157
158         /* Protect monitor and environment sectors */
159         flash_protect (FLAG_PROTECT_SET,
160                  0x0,
161                  0x0 + monitor_flash_len - 1,
162                  &flash_info[0]);
163
164         flash_protect (FLAG_PROTECT_SET,
165                  CFG_ENV_ADDR,
166                  CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
167                  &flash_info[0]);
168
169         return size;
170 }
171
172 /*-----------------------------------------------------------------------
173  */
174 void flash_print_info (flash_info_t * info)
175 {
176         int i;
177         int erased = 0;
178         unsigned long j;
179         unsigned long count;
180         unsigned char *p;
181
182         switch (info->flash_id & FLASH_VENDMASK) {
183         case (SST_MANUFACT & FLASH_VENDMASK):
184                 printf("SST: ");
185                 break;
186         case (PHILIPS_LPC2292 & FLASH_VENDMASK):
187                 printf("Philips: ");
188                 break;
189         default:
190                 printf ("Unknown Vendor ");
191                 break;
192         }
193
194         printf ("  Size: %ld KB in %d Sectors\n",
195           info->size >> 10, info->sector_count);
196
197         printf ("  Sector Start Addresses:");
198         for (i = 0; i < info->sector_count; i++) {
199                 if ((i % 5) == 0) {
200                         printf ("\n   ");
201                 }
202                 if (i < (info->sector_count - 1)) {
203                         count = info->start[i+1] - info->start[i];
204                 }
205                 else {
206                         count = info->start[0] + info->size - info->start[i];
207                 }
208                 p = (unsigned char*)(info->start[i]);
209                 erased = 1;
210                 for (j = 0; j < count; j++) {
211                         if (*p != 0xFF) {
212                                 erased = 0;
213                                 break;
214                         }
215                         p++;
216                 }
217                 printf (" %08lX%s%s", info->start[i], info->protect[i] ? " RO" : "   ",
218                         erased ? " E" : "  ");
219         }
220         printf ("\n");
221 }
222
223 /*-----------------------------------------------------------------------
224  */
225
226 int flash_erase_philips (flash_info_t * info, int s_first, int s_last)
227 {
228         int flag;
229         int prot;
230         int sect;
231
232         prot = 0;
233         for (sect = s_first; sect <= s_last; ++sect) {
234                 if (info->protect[sect]) {
235                         prot++;
236                 }
237         }
238         if (prot)
239                 return ERR_PROTECTED;
240
241
242         flag = disable_interrupts();
243
244         printf ("Erasing %d sectors starting at sector %2d.\n"
245         "This make take some time ... ",
246         s_last - s_first + 1, s_first);
247
248         command[0] = IAP_CMD_PREPARE;
249         command[1] = s_first;
250         command[2] = s_last;
251         iap_entry(command, result);
252         if (result[0] != IAP_RET_CMD_SUCCESS) {
253                 printf("IAP prepare failed\n");
254                 return ERR_PROTECTED;
255         }
256
257         command[0] = IAP_CMD_ERASE;
258         command[1] = s_first;
259         command[2] = s_last;
260         command[3] = CFG_SYS_CLK_FREQ >> 10;
261         iap_entry(command, result);
262         if (result[0] != IAP_RET_CMD_SUCCESS) {
263                 printf("IAP erase failed\n");
264                 return ERR_PROTECTED;
265         }
266
267         if (flag)
268                 enable_interrupts();
269
270         return ERR_OK;
271 }
272
273 int flash_erase_sst (flash_info_t * info, int s_first, int s_last)
274 {
275         int i;
276
277         for (i = s_first; i <= s_last; i++) {
278                 *SST_ADDR1 = 0x00AA;
279                 *SST_ADDR2 = 0x0055;
280                 *SST_ADDR1 = 0x0080;
281                 *SST_ADDR1 = 0x00AA;
282                 *SST_ADDR2 = 0x0055;
283                 *((volatile ushort*)(info->start[i])) = 0x0030;
284                 /* wait for erase to finish */
285                 udelay(25000);
286         }
287
288         return ERR_OK;
289 }
290
291 int flash_erase (flash_info_t * info, int s_first, int s_last)
292 {
293         switch (info->flash_id & FLASH_VENDMASK) {
294                 case (SST_MANUFACT & FLASH_VENDMASK):
295                         return flash_erase_sst(info, s_first, s_last);
296                 case (PHILIPS_LPC2292 & FLASH_VENDMASK):
297                         return flash_erase_philips(info, s_first, s_last);
298                 default:
299                         return ERR_PROTECTED;
300         }
301         return ERR_PROTECTED;
302 }
303
304 /*-----------------------------------------------------------------------
305  * Copy memory to flash.
306  *
307  * cnt is in bytes
308  */
309
310 int write_buff_sst (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
311 {
312         ushort tmp;
313         ulong i;
314         uchar* src_org;
315         uchar* dst_org;
316         ulong cnt_org = cnt;
317         int ret = ERR_OK;
318
319         src_org = src;
320         dst_org = (uchar*)addr;
321
322         if (addr & 1) {         /* if odd address */
323                 tmp = *((uchar*)(addr - 1)); /* little endian */
324                 tmp |= (*src << 8);
325                 write_word_sst(addr - 1, tmp);
326                 addr += 1;
327                 cnt -= 1;
328                 src++;
329         }
330         while (cnt > 1) {
331                 tmp = ((*(src+1)) << 8) + (*src); /* little endian */
332                 write_word_sst(addr, tmp);
333                 addr += 2;
334                 src += 2;
335                 cnt -= 2;
336         }
337         if (cnt > 0) {
338                 tmp = (*((uchar*)(addr + 1))) << 8;
339                 tmp |= *src;
340                 write_word_sst(addr, tmp);
341         }
342
343         for (i = 0; i < cnt_org; i++) {
344                 if (*dst_org != *src_org) {
345                         printf("Write failed. Byte %lX differs\n", i);
346                         ret = ERR_PROG_ERROR;
347                         break;
348                 }
349                 dst_org++;
350                 src_org++;
351         }
352
353         return ret;
354 }
355
356 int write_buff_philips (flash_info_t * info,
357                         uchar * src,
358                         ulong addr,
359                         ulong cnt)
360 {
361         int first_copy_size;
362         int last_copy_size;
363         int first_block;
364         int last_block;
365         int nbr_mid_blocks;
366         uchar memmap_value;
367         ulong i;
368         uchar* src_org;
369         uchar* dst_org;
370         int ret = ERR_OK;
371
372         src_org = src;
373         dst_org = (uchar*)addr;
374
375         first_block = addr / 512;
376         last_block = (addr + cnt) / 512;
377         nbr_mid_blocks = last_block - first_block - 1;
378
379         first_copy_size = 512 - (addr % 512);
380         last_copy_size = (addr + cnt) % 512;
381
382 #if 0
383         printf("\ncopy first block: (1) %lX -> %lX 0x200 bytes, "
384                 "(2) %lX -> %lX 0x%X bytes, (3) %lX -> %lX 0x200 bytes\n",
385         (ulong)(first_block * 512),
386         (ulong)COPY_BUFFER_LOCATION,
387         (ulong)src,
388         (ulong)(COPY_BUFFER_LOCATION + 512 - first_copy_size),
389         first_copy_size,
390         (ulong)COPY_BUFFER_LOCATION,
391         (ulong)(first_block * 512));
392 #endif
393
394         /* copy first block */
395         memcpy((void*)COPY_BUFFER_LOCATION,
396                 (void*)(first_block * 512), 512);
397         memcpy((void*)(COPY_BUFFER_LOCATION + 512 - first_copy_size),
398                 src, first_copy_size);
399         copy_buffer_to_flash(info, first_block * 512);
400         src += first_copy_size;
401         addr += first_copy_size;
402
403         /* copy middle blocks */
404         for (i = 0; i < nbr_mid_blocks; i++) {
405 #if 0
406                 printf("copy middle block: %lX -> %lX 512 bytes, "
407                 "%lX -> %lX 512 bytes\n",
408                 (ulong)src,
409                 (ulong)COPY_BUFFER_LOCATION,
410                 (ulong)COPY_BUFFER_LOCATION,
411                 (ulong)addr);
412 #endif
413                 memcpy((void*)COPY_BUFFER_LOCATION, src, 512);
414                 copy_buffer_to_flash(info, addr);
415                 src += 512;
416                 addr += 512;
417         }
418
419
420         if (last_copy_size > 0) {
421 #if 0
422                 printf("copy last block: (1) %lX -> %lX 0x200 bytes, "
423                 "(2) %lX -> %lX 0x%X bytes, (3) %lX -> %lX x200 bytes\n",
424                 (ulong)(last_block * 512),
425                 (ulong)COPY_BUFFER_LOCATION,
426                 (ulong)src,
427                 (ulong)(COPY_BUFFER_LOCATION),
428                 last_copy_size,
429                 (ulong)COPY_BUFFER_LOCATION,
430                 (ulong)addr);
431 #endif
432                 /* copy last block */
433                 memcpy((void*)COPY_BUFFER_LOCATION,
434                         (void*)(last_block * 512), 512);
435                 memcpy((void*)COPY_BUFFER_LOCATION,
436                         src, last_copy_size);
437                 copy_buffer_to_flash(info, addr);
438         }
439
440         /* verify write */
441         memmap_value = GET8(MEMMAP);
442
443         disable_interrupts();
444
445         PUT8(MEMMAP, 01);               /* we must make sure that initial 64
446                                                            bytes are taken from flash when we
447                                                            do the compare */
448
449         for (i = 0; i < cnt; i++) {
450                 if (*dst_org != *src_org){
451                         printf("Write failed. Byte %lX differs\n", i);
452                         ret = ERR_PROG_ERROR;
453                         break;
454                 }
455                 dst_org++;
456                 src_org++;
457         }
458
459         PUT8(MEMMAP, memmap_value);
460         enable_interrupts();
461
462         return ret;
463 }
464
465 int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
466 {
467         switch (info->flash_id & FLASH_VENDMASK) {
468                 case (SST_MANUFACT & FLASH_VENDMASK):
469                         return write_buff_sst(info, src, addr, cnt);
470                 case (PHILIPS_LPC2292 & FLASH_VENDMASK):
471                         return write_buff_philips(info, src, addr, cnt);
472                 default:
473                         return ERR_PROG_ERROR;
474         }
475         return ERR_PROG_ERROR;
476 }