Initial revision
[platform/kernel/u-boot.git] / board / rsdproto / flash.c
1 /*
2  * (C) Copyright 2000
3  * Marius Groeger <mgroeger@sysgo.de>
4  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
5  *
6  * (C) Copyright 2000
7  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
8  *
9  * Flash Routines for AM290[48]0B devices
10  *
11  *--------------------------------------------------------------------
12  * See file CREDITS for list of people who contributed to this
13  * project.
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License as
17  * published by the Free Software Foundation; either version 2 of
18  * the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
28  * MA 02111-1307 USA
29  */
30
31 #include <common.h>
32 #include <mpc8xx.h>
33
34 /* flash hardware ids */
35 #define VENDOR_AMD     0x0001
36 #define AMD_29DL323C_B 0x2253
37
38 /* Define this to include autoselect sequence in flash_init(). Does NOT
39  * work when executing from flash itself, so this should be turned
40  * on only when debugging the RAM version.
41  */
42 #undef WITH_AUTOSELECT
43
44 flash_info_t    flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
45
46 #if 1
47 #define D(x)
48 #else
49 #define D(x) printf x
50 #endif
51
52 /*-----------------------------------------------------------------------
53  * Functions
54  */
55
56 static unsigned char write_ull(flash_info_t *info,
57                                unsigned long address,
58                                volatile unsigned long long data);
59
60 /* from flash_asm.S */
61 extern void ull_write(unsigned long long volatile *address,
62                       unsigned long long volatile *data);
63 extern void ull_read(unsigned long long volatile *address,
64                      unsigned long long volatile *data);
65
66 /*-----------------------------------------------------------------------
67  */
68
69 unsigned long flash_init (void)
70 {
71     int i;
72     ulong addr;
73
74 #ifdef WITH_AUTOSELECT
75         {
76                 unsigned long long *f_addr = (unsigned long long *)PHYS_FLASH;
77                 unsigned long long f_command, vendor, device;
78                 /* Perform Autoselect */
79                 f_command       = 0x00AA00AA00AA00AAULL;
80                 ull_write(&f_addr[0x555], &f_command);
81                 f_command       = 0x0055005500550055ULL;
82                 ull_write(&f_addr[0x2AA], &f_command);
83                 f_command       = 0x0090009000900090ULL;
84                 ull_write(&f_addr[0x555], &f_command);
85                 ull_read(&f_addr[0], &vendor);
86                 vendor &= 0xffff;
87                 ull_read(&f_addr[1], &device);
88                 device &= 0xffff;
89                 f_command       = 0x00F000F000F000F0ULL;
90                 ull_write(&f_addr[0x555], &f_command);
91                 if (vendor != VENDOR_AMD || device != AMD_29DL323C_B)
92                   return 0;
93         }
94 #endif
95
96     /* Init: no FLASHes known */
97     for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
98                 flash_info[i].flash_id = FLASH_UNKNOWN;
99     }
100
101         /* 1st bank: 8 x 32 KB sectors */
102         flash_info[0].flash_id = VENDOR_AMD << 16 | AMD_29DL323C_B;
103         flash_info[0].sector_count = 8;
104         flash_info[0].size = flash_info[0].sector_count * 32 * 1024;
105         addr = PHYS_FLASH;
106     for(i = 0; i < flash_info[0].sector_count; i++) {
107                 flash_info[0].start[i] = addr;
108                 addr += flash_info[0].size / flash_info[0].sector_count;
109         }
110         /* 1st bank: 63 x 256 KB sectors */
111         flash_info[1].flash_id = VENDOR_AMD << 16 | AMD_29DL323C_B;
112         flash_info[1].sector_count = 63;
113         flash_info[1].size = flash_info[1].sector_count * 256 * 1024;
114     for(i = 0; i < flash_info[1].sector_count; i++) {
115                 flash_info[1].start[i] = addr;
116                 addr += flash_info[1].size / flash_info[1].sector_count;
117         }
118
119         /*
120          * protect monitor and environment sectors
121          */
122
123 #if CFG_MONITOR_BASE >= PHYS_FLASH
124         flash_protect(FLAG_PROTECT_SET,
125                       CFG_MONITOR_BASE,
126                       CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
127                       &flash_info[0]);
128         flash_protect(FLAG_PROTECT_SET,
129                       CFG_MONITOR_BASE,
130                       CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
131                       &flash_info[1]);
132 #endif
133
134 #if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
135 # ifndef  CFG_ENV_SIZE
136 #  define CFG_ENV_SIZE  CFG_ENV_SECT_SIZE
137 # endif
138         flash_protect(FLAG_PROTECT_SET,
139                       CFG_ENV_ADDR,
140                       CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
141                       &flash_info[0]);
142         flash_protect(FLAG_PROTECT_SET,
143                       CFG_ENV_ADDR,
144                       CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
145                       &flash_info[1]);
146 #endif
147
148     return flash_info[0].size + flash_info[1].size;
149 }
150
151 /*-----------------------------------------------------------------------
152  */
153 void flash_print_info  (flash_info_t *info)
154 {
155     int i;
156
157     if (info->flash_id == FLASH_UNKNOWN) {
158                 printf ("missing or unknown FLASH type\n");
159                 return;
160     }
161
162     switch (info->flash_id >> 16) {
163     case VENDOR_AMD:
164                 printf ("AMD ");
165                 break;
166     default:
167                 printf ("Unknown Vendor ");
168                 break;
169     }
170
171     switch (info->flash_id & FLASH_TYPEMASK) {
172     case AMD_29DL323C_B:
173                 printf ("AM29DL323CB (32 Mbit)\n");
174                 break;
175     default:
176                 printf ("Unknown Chip Type\n");
177                 break;
178     }
179
180     printf ("  Size: %ld MB in %d Sectors\n",
181                         info->size >> 20, info->sector_count);
182
183     printf ("  Sector Start Addresses:");
184     for (i=0; i<info->sector_count; ++i) {
185                 if ((i % 5) == 0)
186                   printf ("\n   ");
187                 printf (" %08lX%s",
188                                 info->start[i],
189                                 info->protect[i] ? " (RO)" : "     "
190                                 );
191     }
192     printf ("\n");
193     return;
194 }
195
196 /*-----------------------------------------------------------------------
197  */
198
199 int     flash_erase (flash_info_t *info, int s_first, int s_last)
200 {
201     int flag, prot, sect, l_sect;
202     ulong start;
203         unsigned long long volatile *f_addr;
204         unsigned long long volatile f_command;
205
206     if ((s_first < 0) || (s_first > s_last)) {
207                 if (info->flash_id == FLASH_UNKNOWN) {
208                         printf ("- missing\n");
209                 } else {
210                         printf ("- no sectors to erase\n");
211                 }
212                 return 1;
213     }
214
215     prot = 0;
216     for (sect = s_first; sect <= s_last; sect++) {
217                 if (info->protect[sect]) {
218                         prot++;
219                 }
220     }
221     if (prot) {
222                 printf ("- Warning: %d protected sectors will not be erased!\n",
223                                 prot);
224     } else {
225                 printf ("\n");
226     }
227
228         f_addr  = (unsigned long long *)info->start[0];
229         f_command       = 0x00AA00AA00AA00AAULL;
230         ull_write(&f_addr[0x555], &f_command);
231         f_command       = 0x0055005500550055ULL;
232         ull_write(&f_addr[0x2AA], &f_command);
233         f_command       = 0x0080008000800080ULL;
234         ull_write(&f_addr[0x555], &f_command);
235         f_command       = 0x00AA00AA00AA00AAULL;
236         ull_write(&f_addr[0x555], &f_command);
237         f_command       = 0x0055005500550055ULL;
238         ull_write(&f_addr[0x2AA], &f_command);
239
240     /* Disable interrupts which might cause a timeout here */
241     flag = disable_interrupts();
242
243     /* Start erase on unprotected sectors */
244     for (l_sect = -1, sect = s_first; sect<=s_last; sect++) {
245                 if (info->protect[sect] == 0) { /* not protected */
246
247                         f_addr  =
248                           (unsigned long long *)(info->start[sect]);
249                         f_command       = 0x0030003000300030ULL;
250                         ull_write(f_addr, &f_command);
251                         l_sect = sect;
252                 }
253     }
254
255     /* re-enable interrupts if necessary */
256     if (flag)
257       enable_interrupts();
258
259         start = get_timer (0);
260         do
261         {
262                 if (get_timer(start) > CFG_FLASH_ERASE_TOUT)
263                 {       /* write reset command, command address is unimportant */
264                         /* this command turns the flash back to read mode     */
265                         f_addr =
266                           (unsigned long long *)(info->start[l_sect]);
267                         f_command       = 0x00F000F000F000F0ULL;
268                         ull_write(f_addr, &f_command);
269                         printf (" timeout\n");
270                         return 1;
271         }
272         } while(*f_addr != 0xFFFFFFFFFFFFFFFFULL);
273
274     printf (" done\n");
275     return 0;
276 }
277
278 /*-----------------------------------------------------------------------
279  * Copy memory to flash, returns:
280  * 0 - OK
281  * 1 - write timeout
282  * 2 - Flash not erased
283  */
284
285 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
286 {
287     unsigned long cp, wp;
288         unsigned long long data;
289     int i, l, rc;
290
291     wp = (addr & ~7);   /* get lower long long aligned address */
292
293     /*
294      * handle unaligned start bytes
295      */
296     if ((l = addr - wp) != 0) {
297                 data = 0;
298                 for (i=0, cp=wp; i<l; ++i, ++cp) {
299                         data = (data << 8) | (*(uchar *)cp);
300                 }
301                 for (; i<8 && cnt>0; ++i) {
302                         data = (data << 8) | *src++;
303                         --cnt;
304                         ++cp;
305                 }
306                 for (; cnt==0 && i<8; ++i, ++cp) {
307                         data = (data << 8) | (*(uchar *)cp);
308                 }
309
310                 if ((rc = write_ull(info, wp, data)) != 0) {
311                         return rc;
312                 }
313                 wp += 4;
314     }
315
316     /*
317      * handle long long aligned part
318      */
319     while (cnt >= 8) {
320                 data = 0;
321                 for (i=0; i<8; ++i) {
322                         data = (data << 8) | *src++;
323                 }
324                 if ((rc = write_ull(info, wp, data)) != 0) {
325                         return rc;
326                 }
327                 wp  += 8;
328                 cnt -= 8;
329     }
330
331     if (cnt == 0) {
332                 return ERR_OK;
333     }
334
335     /*
336      * handle unaligned tail bytes
337      */
338     data = 0;
339     for (i=0, cp=wp; i<8 && cnt>0; ++i, ++cp) {
340                 data = (data << 8) | *src++;
341                 --cnt;
342     }
343     for (; i<8; ++i, ++cp) {
344                 data = (data << 8) | (*(uchar *)cp);
345     }
346
347     return write_ull(info, wp, data);
348 }
349
350 /*---------------------------------------------------------------------------
351 *
352 * FUNCTION NAME:  write_ull
353 *
354 * DESCRIPTION:   writes 8 bytes to flash
355 *
356 * EXTERNAL EFFECT: nothing
357 *
358 * PARAMETERS:   32 bit long pointer to address, 64 bit long pointer to data
359 *
360 * RETURNS:      0 if OK, 1 if timeout, 4 if parameter error
361 *--------------------------------------------------------------------------*/
362
363 static unsigned char write_ull(flash_info_t *info,
364                                                            unsigned long address,
365                                                            volatile unsigned long long data)
366 {
367         static unsigned long long f_command;
368         static unsigned long long *f_addr;
369         ulong start;
370
371         /* address muss be 8-aligned! */
372         if (address & 0x7)
373           return ERR_ALIGN;
374
375         f_addr  = (unsigned long long *)info->start[0];
376         f_command       = 0x00AA00AA00AA00AAULL;
377         ull_write(&f_addr[0x555], &f_command);
378         f_command       = 0x0055005500550055ULL;
379         ull_write(&f_addr[0x2AA], &f_command);
380         f_command       = 0x00A000A000A000A0ULL;
381         ull_write(&f_addr[0x555], &f_command);
382
383         f_addr  = (unsigned long long *)address;
384         f_command       = data;
385         ull_write(f_addr, &f_command);
386
387         start = get_timer (0);
388         do
389         {
390                 if (get_timer(start) > CFG_FLASH_WRITE_TOUT)
391                 {
392                         /* write reset command, command address is unimportant */
393                         /* this command turns the flash back to read mode     */
394                         f_addr  = (unsigned long long *)info->start[0];
395                         f_command       = 0x00F000F000F000F0ULL;
396                         ull_write(f_addr, &f_command);
397                         return ERR_TIMOUT;
398                 }
399         } while(*((unsigned long long *)address) != data);
400
401         return 0;
402 }