blob: fd3b16ea50a6d7629f583d6ce6e1525ed28062d8 [file] [log] [blame]
wdenkc28149c2005-05-30 23:55:42 +00001/*
2 * (C) Copyright 2004
3 * Elmeg Communications Systems GmbH, Juergen Selent (j.selent@elmeg.de)
4 *
5 * Support for the Elmeg VoVPN Gateway Module
6 * ------------------------------------------
7 * This is a signle bank flashdriver for INTEL 28F320J3, 28F640J3
wdenk8d414a72005-06-10 10:00:19 +00008 * and 28F128J3A flashs working in 8 Bit mode.
wdenkc28149c2005-05-30 23:55:42 +00009 *
10 * Most of this code is taken from existing u-boot source code.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * MA 02111-1307 USA
26 */
27
28#include <common.h>
29
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020030flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
wdenkc28149c2005-05-30 23:55:42 +000031
32#define FLASH_CMD_READ_ID 0x90
33#define FLASH_CMD_READ_STATUS 0x70
34#define FLASH_CMD_RESET 0xff
35#define FLASH_CMD_BLOCK_ERASE 0x20
36#define FLASH_CMD_ERASE_CONFIRM 0xd0
37#define FLASH_CMD_CLEAR_STATUS 0x50
38#define FLASH_CMD_SUSPEND_ERASE 0xb0
39#define FLASH_CMD_WRITE 0x40
40#define FLASH_CMD_WRITE_BUFF 0xe8
41#define FLASH_CMD_PROG_RESUME 0xd0
42#define FLASH_CMD_PROTECT 0x60
43#define FLASH_CMD_PROTECT_SET 0x01
44#define FLASH_CMD_PROTECT_CLEAR 0xd0
45#define FLASH_STATUS_DONE 0x80
46
47#define FLASH_WRITE_BUFFER_SIZE 32
48
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020049#ifdef CONFIG_SYS_FLASH_16BIT
wdenkc28149c2005-05-30 23:55:42 +000050#define FLASH_WORD_SIZE unsigned short
51#define FLASH_ID_MASK 0xffff
52#define FLASH_CMD_ADDR_SHIFT 0
53#else
54#define FLASH_WORD_SIZE unsigned char
55#define FLASH_ID_MASK 0xff
56/* A0 is not used in either 8x or 16x for READ ID */
57#define FLASH_CMD_ADDR_SHIFT 1
58#endif
59
60
61static unsigned long
62flash_get(volatile FLASH_WORD_SIZE *addr, flash_info_t *info)
63{
64 volatile FLASH_WORD_SIZE *p;
65 FLASH_WORD_SIZE value;
66 int i;
67
68 addr[0] = FLASH_CMD_READ_ID;
69
70 /* manufactor */
71 value = addr[0 << FLASH_CMD_ADDR_SHIFT];
72 switch (value) {
73 case (INTEL_MANUFACT & FLASH_ID_MASK):
74 info->flash_id = FLASH_MAN_INTEL;
75 break;
76 default:
77 info->flash_id = FLASH_UNKNOWN;
78 info->sector_count = 0;
79 info->size = 0;
80 *addr = FLASH_CMD_RESET;
81 return (0);
82
83 }
84
85 /* device */
86 value = addr[1 << FLASH_CMD_ADDR_SHIFT];
87 switch (value) {
88 case (INTEL_ID_28F320J3A & FLASH_ID_MASK):
89 info->flash_id += FLASH_28F320J3A;
90 info->sector_count = 32;
91 info->size = 0x00400000;
92 break;
93 case (INTEL_ID_28F640J3A & FLASH_ID_MASK):
94 info->flash_id += FLASH_28F640J3A;
95 info->sector_count = 64;
96 info->size = 0x00800000;
97 break;
98 case (INTEL_ID_28F128J3A & FLASH_ID_MASK):
99 info->flash_id += FLASH_28F128J3A;
100 info->sector_count = 128;
101 info->size = 0x01000000;
102 break;
103 default:
104 info->flash_id = FLASH_UNKNOWN;
105 info->sector_count = 0;
106 info->size = 0;
107 *addr = FLASH_CMD_RESET;
108 return (0);
109 }
110
111 /* setup sectors */
112 for (i = 0; i < info->sector_count; i++) {
113 info->start[i] = (unsigned long)addr + (i * info->size/info->sector_count);
114 }
115
116 /* check protected sectors */
117 for (i = 0; i < info->sector_count; i++) {
118 p = (volatile FLASH_WORD_SIZE *)(info->start[i]);
119 info->protect[i] = p[2 << FLASH_CMD_ADDR_SHIFT] & 1;
120 }
121
122 /* reset bank */
123 *addr = FLASH_CMD_RESET;
124 return (info->size);
125}
126
127unsigned long
128flash_init(void)
129{
130 unsigned long size;
131 int i;
132
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200133 for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
wdenkc28149c2005-05-30 23:55:42 +0000134 flash_info[i].flash_id = FLASH_UNKNOWN;
135 }
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200136 size = flash_get((volatile FLASH_WORD_SIZE *)CONFIG_SYS_FLASH_BASE, &flash_info[0]);
wdenkc28149c2005-05-30 23:55:42 +0000137 if (flash_info[0].flash_id == FLASH_UNKNOWN) {
138 printf ("## Unknown FLASH Size=0x%08lx\n", size);
139 return (0);
140 }
141
142 /* always protect 1 sector containing the HRCW */
143 flash_protect(FLAG_PROTECT_SET,
144 flash_info[0].start[0],
145 flash_info[0].start[1] - 1,
146 &flash_info[0]);
147
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200148#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
wdenkc28149c2005-05-30 23:55:42 +0000149 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200150 CONFIG_SYS_MONITOR_FLASH,
151 CONFIG_SYS_MONITOR_FLASH+CONFIG_SYS_MONITOR_LEN-1,
wdenkc28149c2005-05-30 23:55:42 +0000152 &flash_info[0]);
153#endif
Jean-Christophe PLAGNIOL-VILLARD53db4cd2008-09-10 22:48:04 +0200154#ifdef CONFIG_ENV_IS_IN_FLASH
wdenkc28149c2005-05-30 23:55:42 +0000155 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200156 CONFIG_ENV_ADDR,
157 CONFIG_ENV_ADDR+CONFIG_ENV_SECT_SIZE-1,
wdenkc28149c2005-05-30 23:55:42 +0000158 &flash_info[0]);
159#endif
160 return (size);
161}
162
163void
164flash_print_info(flash_info_t *info)
165{
166 int i;
167
168 if (info->flash_id == FLASH_UNKNOWN) {
169 printf ("missing or unknown FLASH type\n");
170 return;
171 }
172
173 switch (info->flash_id & FLASH_VENDMASK) {
174 case FLASH_MAN_INTEL: printf ("INTEL "); break;
175 default: printf ("Unknown Vendor "); break;
176 }
177
178 switch (info->flash_id & FLASH_TYPEMASK) {
179 case FLASH_28F320J3A: printf ("28F320JA3 (32 Mbit)\n");
180 break;
181 case FLASH_28F640J3A: printf ("28F640JA3 (64 Mbit)\n");
182 break;
183 case FLASH_28F128J3A: printf ("28F128JA3 (128 Mbit)\n");
184 break;
185 default: printf ("Unknown Chip Type");
186 break;
187 }
188
189 printf (" Size: %ld MB in %d Sectors\n",
190 info->size >> 20, info->sector_count);
191
192 printf (" Sector Start Addresses:");
193 for (i=0; i<info->sector_count; ++i) {
194 if ((i % 5) == 0)
195 printf ("\n ");
196 printf (" %08lX%s",
197 info->start[i],
198 info->protect[i] ? " (RO)" : " "
199 );
200 }
201 printf ("\n");
202}
203
204int
205flash_erase(flash_info_t *info, int s_first, int s_last)
206{
207 unsigned long start, now, last;
208 int flag, prot, sect;
209 volatile FLASH_WORD_SIZE *addr;
210 FLASH_WORD_SIZE status;
211
212 if ((s_first < 0) || (s_first > s_last)) {
213 if (info->flash_id == FLASH_UNKNOWN) {
214 printf ("- missing\n");
215 } else {
216 printf ("- no sectors to erase\n");
217 }
218 return (1);
219 }
220
221 if (info->flash_id == FLASH_UNKNOWN) {
222 printf ("Cannot erase unknown flash - aborted\n");
223 return (1);
224 }
225
226 prot = 0;
227 for (sect=s_first; sect<=s_last; ++sect) {
228 if (info->protect[sect]) {
229 prot++;
230 }
231 }
232
233 if (prot) {
234 printf ("- Warning: %d protected sectors will not be erased!\n", prot);
235 } else {
236 printf ("\n");
237 }
238
239 start = get_timer (0);
240 last = start;
241
242 for (sect = s_first; sect<=s_last; sect++) {
243 if (info->protect[sect]) {
244 continue;
245 }
246
247 addr = (volatile FLASH_WORD_SIZE *)(info->start[sect]);
248 /* Disable interrupts which might cause a timeout here */
249 flag = disable_interrupts();
250
251#ifdef DEBUG
252 printf("Erase sector %d at start addr 0x%08X", sect, (unsigned int)info->start[sect]);
253#endif
254
255 *addr = FLASH_CMD_CLEAR_STATUS;
256 *addr = FLASH_CMD_BLOCK_ERASE;
257 *addr = FLASH_CMD_ERASE_CONFIRM;
258
259 /* re-enable interrupts if necessary */
260 if (flag) {
261 enable_interrupts();
262 }
263
264 /* wait at least 80us - let's wait 1 ms */
265 udelay (1000);
266
267 while (((status = *addr) & FLASH_STATUS_DONE) != FLASH_STATUS_DONE) {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200268 if ((now=get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
wdenkc28149c2005-05-30 23:55:42 +0000269 printf("Flash erase timeout at address %lx\n", info->start[sect]);
270 *addr = FLASH_CMD_SUSPEND_ERASE;
271 *addr = FLASH_CMD_RESET;
272 return (1);
273 }
274
275 /* show that we're waiting */
276 if ((now - last) > 1000) { /* every second */
277 putc ('.');
278 last = now;
279 }
280 }
281 *addr = FLASH_CMD_RESET;
282 }
283 printf (" done\n");
284 return (0);
285}
286
287static int
288write_buff2( volatile FLASH_WORD_SIZE *dst,
wdenk8d414a72005-06-10 10:00:19 +0000289 volatile FLASH_WORD_SIZE *src,
290 unsigned long cnt )
wdenkc28149c2005-05-30 23:55:42 +0000291{
292 unsigned long start;
293 FLASH_WORD_SIZE status;
294 int flag, i;
295
296 start = get_timer (0);
297 while (1) {
298 /* Disable interrupts which might cause a timeout here */
299 flag = disable_interrupts();
300 dst[0] = FLASH_CMD_WRITE_BUFF;
301 if ((status = *dst) & FLASH_STATUS_DONE) {
302 break;
303 }
304
305 /* re-enable interrupts if necessary */
306 if (flag) {
307 enable_interrupts();
308 }
309
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200310 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenkc28149c2005-05-30 23:55:42 +0000311 return (-1);
312 }
313 }
314 dst[0] = (FLASH_WORD_SIZE)(cnt - 1);
315 for (i=0; i<cnt; i++) {
316 dst[i] = src[i];
317 }
318 dst[0] = FLASH_CMD_PROG_RESUME;
319
320 if (flag) {
321 enable_interrupts();
322 }
323
324 return( 0 );
325}
326
327static int
328poll_status( volatile FLASH_WORD_SIZE *addr )
329{
330 unsigned long start;
331
332 start = get_timer (0);
333 /* wait for error or finish */
334 while (1) {
335 if (*addr == FLASH_STATUS_DONE) {
336 if (*addr == FLASH_STATUS_DONE) {
337 break;
338 }
339 }
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200340 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenkc28149c2005-05-30 23:55:42 +0000341 *addr = FLASH_CMD_RESET;
342 return (-1);
343 }
344 }
345 *addr = FLASH_CMD_RESET;
346 return (0);
347}
348
349/*
350 * write_buff return values:
351 * 0 - OK
352 * 1 - write timeout
353 * 2 - Flash not erased
354 * 4 - Flash not identified
355 */
356int
357write_buff(flash_info_t *info, uchar *src, ulong udst, ulong cnt)
358{
359 volatile FLASH_WORD_SIZE *addr, *dst;
360 unsigned long bcnt;
361 int flag, i;
362
363 if (info->flash_id == FLASH_UNKNOWN) {
364 return (4);
365 }
366
367 addr = (volatile FLASH_WORD_SIZE *)(info->start[0]);
368 dst = (volatile FLASH_WORD_SIZE *) udst;
369
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200370#ifdef CONFIG_SYS_FLASH_16BIT
wdenkc28149c2005-05-30 23:55:42 +0000371#error NYI
372#else
373 while (cnt > 0) {
374 /* Check if buffer write is possible */
375 if (cnt > 1 && (((unsigned long)dst & (FLASH_WRITE_BUFFER_SIZE - 1)) == 0)) {
376 bcnt = cnt > FLASH_WRITE_BUFFER_SIZE ? FLASH_WRITE_BUFFER_SIZE : cnt;
377 /* Check if Flash is (sufficiently) erased */
378 for (i=0; i<bcnt; i++) {
379 if ((dst[i] & src[i]) != src[i]) {
380 return (2);
381 }
382 }
383 if (write_buff2( dst,src,bcnt ) != 0) {
384 addr[0] = FLASH_CMD_READ_STATUS;
385 }
386 if (poll_status( dst ) != 0) {
387 return (1);
388 }
389 cnt -= bcnt;
390 dst += bcnt;
391 src += bcnt;
392 continue;
393 }
394
395 /* Check if Flash is (sufficiently) erased */
396 if ((*dst & *src) != *src) {
397 return (2);
398 }
399
400 /* Disable interrupts which might cause a timeout here */
401 flag = disable_interrupts();
402 addr[0] = FLASH_CMD_ERASE_CONFIRM;
403 addr[0] = FLASH_CMD_WRITE;
404 *dst++ = *src++;
405 /* re-enable interrupts if necessary */
406 if (flag) {
407 enable_interrupts();
408 }
409
410 if (poll_status( dst ) != 0) {
411 return (1);
412 }
413 cnt --;
414 }
415#endif
416 return (0);
417}
418
419int
420flash_real_protect(flash_info_t *info, long sector, int prot)
421{
422 volatile FLASH_WORD_SIZE *addr;
423 unsigned long start;
424
425 addr = (volatile FLASH_WORD_SIZE *)(info->start[sector]);
426 *addr = FLASH_CMD_CLEAR_STATUS;
427 *addr = FLASH_CMD_PROTECT;
428
429 if(prot) {
430 *addr = FLASH_CMD_PROTECT_SET;
431 } else {
432 *addr = FLASH_CMD_PROTECT_CLEAR;
433 }
434
435 /* wait for error or finish */
436 start = get_timer (0);
437 while(!(addr[0] & FLASH_STATUS_DONE)){
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200438 if (get_timer(start) > CONFIG_SYS_FLASH_ERASE_TOUT) {
wdenkc28149c2005-05-30 23:55:42 +0000439 printf("Flash protect timeout at address %lx\n", info->start[sector]);
440 addr[0] = FLASH_CMD_RESET;
441 return (1);
442 }
443 }
444
445 /* Set software protect flag */
446 info->protect[sector] = prot;
447 *addr = FLASH_CMD_RESET;
448 return (0);
449}