Import upstream u-boot 1.1.4
[u-boot.git] / board / altera / common / flash.c
1 /*
2  * (C) Copyright 2000-2004
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
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
25 #include <common.h>
26 #include <nios.h>
27
28 flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
29
30 /*--------------------------------------------------------------------*/
31 void flash_print_info (flash_info_t * info)
32 {
33         int i, k;
34         unsigned long size;
35         int erased;
36         volatile unsigned char *flash;
37
38         printf ("  Size: %ld KB in %d Sectors\n",
39                 info->size >> 10, info->sector_count);
40         printf ("  Sector Start Addresses:");
41         for (i = 0; i < info->sector_count; ++i) {
42
43                 /* Check if whole sector is erased */
44                 if (i != (info->sector_count - 1))
45                         size = info->start[i + 1] - info->start[i];
46                 else
47                         size = info->start[0] + info->size - info->start[i];
48                 erased = 1;
49                 flash = (volatile unsigned char *) info->start[i];
50                 for (k = 0; k < size; k++) {
51                         if (*flash++ != 0xff) {
52                                 erased = 0;
53                                 break;
54                         }
55                 }
56
57                 /* Print the info */
58                 if ((i % 5) == 0)
59                         printf ("\n   ");
60                 printf (" %08lX%s%s", info->start[i], erased ? " E" : "  ",
61                         info->protect[i] ? "RO " : "   ");
62         }
63         printf ("\n");
64 }
65
66 /*-------------------------------------------------------------------*/
67
68
69 int flash_erase (flash_info_t * info, int s_first, int s_last)
70 {
71         volatile CFG_FLASH_WORD_SIZE *addr = (CFG_FLASH_WORD_SIZE *) (info->start[0]);
72         volatile CFG_FLASH_WORD_SIZE *addr2;
73         int prot, sect;
74         unsigned oldpri;
75         ulong start;
76
77         /* Some sanity checking */
78         if ((s_first < 0) || (s_first > s_last)) {
79                 printf ("- no sectors to erase\n");
80                 return 1;
81         }
82
83         prot = 0;
84         for (sect = s_first; sect <= s_last; ++sect) {
85                 if (info->protect[sect]) {
86                         prot++;
87                 }
88         }
89         if (prot) {
90                 printf ("- Warning: %d protected sectors will not be erased!\n",
91                         prot);
92         } else {
93                 printf ("\n");
94         }
95
96 #ifdef DEBUG
97         for (sect = s_first; sect <= s_last; sect++) {
98                 printf("- Erase: Sect: %i @ 0x%08x\n", sect,  info->start[sect]);
99         }
100 #endif
101
102         /* NOTE: disabling interrupts on Nios can be very bad since it
103          * also disables the LO_LIMIT exception. It's better here to
104          * set the interrupt priority to 3 & restore it when we're done.
105          */
106         oldpri = ipri (3);
107
108         /* It's ok to erase multiple sectors provided we don't delay more
109          * than 50 usec between cmds ... at which point the erase time-out
110          * occurs. So don't go and put printf() calls in the loop ... it
111          * won't be very helpful ;-)
112          */
113         for (sect = s_first; sect <= s_last; sect++) {
114                 if (info->protect[sect] == 0) { /* not protected */
115                         addr2 = (CFG_FLASH_WORD_SIZE *) (info->start[sect]);
116                         *addr = 0xaa;
117                         *addr = 0x55;
118                         *addr = 0x80;
119                         *addr = 0xaa;
120                         *addr = 0x55;
121                         *addr2 = 0x30;
122                         /* Now just wait for 0xff & provide some user
123                          * feedback while we wait. Here we have to grant
124                          * timer interrupts. Otherwise get_timer() can't
125                          * work right. */
126                         ipri(oldpri);
127                         start = get_timer (0);
128                         while (*addr2 != 0xff) {
129                                 udelay (1000 * 1000);
130                                 putc ('.');
131                                 if (get_timer (start) > CFG_FLASH_ERASE_TOUT) {
132                                         printf ("timeout\n");
133                                         return 1;
134                                 }
135                         }
136                         oldpri = ipri (3); /* disallow non important irqs again */
137                 }
138         }
139
140         printf ("\n");
141
142         /* Restore interrupt priority */
143         ipri (oldpri);
144
145         return 0;
146 }
147
148 /*-----------------------------------------------------------------------
149  * Copy memory to flash, returns:
150  * 0 - OK
151  * 1 - write timeout
152  * 2 - Flash not erased
153  */
154
155 int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
156 {
157
158         vu_char *cmd = (vu_char *) info->start[0];
159         vu_char *dst = (vu_char *) addr;
160         unsigned char b;
161         unsigned oldpri;
162         ulong start;
163
164         while (cnt) {
165                 /* Check for sufficient erase */
166                 b = *src;
167                 if ((*dst & b) != b) {
168                         printf ("%02x : %02x\n", *dst, b);
169                         return (2);
170                 }
171
172                 /* Disable interrupts other than window underflow
173                  * (interrupt priority 2)
174                  */
175                 oldpri = ipri (3);
176                 *cmd = 0xaa;
177                 *cmd = 0x55;
178                 *cmd = 0xa0;
179                 *dst = b;
180
181                 /* Verify write */
182                 start = get_timer (0);
183                 while (*dst != b) {
184                         if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
185                                 ipri (oldpri);
186                                 return 1;
187                         }
188                 }
189                 dst++;
190                 src++;
191                 cnt--;
192                 ipri (oldpri);
193         }
194
195         return (0);
196 }