blob: e43451286f83ac9009170fbfdf7b0b32364dc8ff [file] [log] [blame]
wdenk2262cfe2002-11-18 00:14:45 +00001/*
2 * (C) Copyright 2002
3 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
4 * Alex Zuepke <azu@sysgo.de>
5 *
6 * See file CREDITS for list of people who contributed to this
7 * project.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22 * MA 02111-1307 USA
23 */
24
25#include <common.h>
26
27ulong myflush(void);
28
29
30#define FLASH_BANK_SIZE 0x400000 /* 4 MB */
31#define MAIN_SECT_SIZE 0x20000 /* 128 KB */
32
33flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
34
35
36#define CMD_READ_ARRAY 0x00F000F0
37#define CMD_UNLOCK1 0x00AA00AA
38#define CMD_UNLOCK2 0x00550055
39#define CMD_ERASE_SETUP 0x00800080
40#define CMD_ERASE_CONFIRM 0x00300030
41#define CMD_PROGRAM 0x00A000A0
42#define CMD_UNLOCK_BYPASS 0x00200020
43
44#define MEM_FLASH_ADDR1 (*(volatile u32 *)(CFG_FLASH_BASE + (0x00000555 << 2)))
45#define MEM_FLASH_ADDR2 (*(volatile u32 *)(CFG_FLASH_BASE + (0x000002AA << 2)))
46
47#define BIT_ERASE_DONE 0x00800080
48#define BIT_RDY_MASK 0x00800080
49#define BIT_PROGRAM_ERROR 0x00200020
50#define BIT_TIMEOUT 0x80000000 /* our flag */
51
52#define READY 1
53#define ERR 2
54#define TMO 4
55
56/*-----------------------------------------------------------------------
57 */
58
59ulong flash_init(void)
60{
61 int i, j;
62 ulong size = 0;
63
64 for (i = 0; i < CFG_MAX_FLASH_BANKS; i++)
65 {
66 ulong flashbase = 0;
67 flash_info[i].flash_id =
68 (AMD_MANUFACT & FLASH_VENDMASK) |
69 (AMD_ID_LV160B & FLASH_TYPEMASK);
70 flash_info[i].size = FLASH_BANK_SIZE;
71 flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
72 memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
73 if (i == 0)
74 flashbase = PHYS_FLASH_1;
75 else
76 panic("configured to many flash banks!\n");
77 for (j = 0; j < flash_info[i].sector_count; j++)
78 {
79
80 if (j <= 3)
81 {
82 /* 1st one is 32 KB */
83 if (j == 0)
84 {
85 flash_info[i].start[j] = flashbase + 0;
86 }
87
88 /* 2nd and 3rd are both 16 KB */
89 if ((j == 1) || (j == 2))
90 {
91 flash_info[i].start[j] = flashbase + 0x8000 + (j-1)*0x4000;
92 }
93
94 /* 4th 64 KB */
95 if (j == 3)
96 {
97 flash_info[i].start[j] = flashbase + 0x10000;
98 }
99 }
100 else
101 {
102 flash_info[i].start[j] = flashbase + (j - 3)*MAIN_SECT_SIZE;
103 }
104 }
105 size += flash_info[i].size;
106 }
107
108 /*
109 * Protect monitor and environment sectors
110 */
111 flash_protect(FLAG_PROTECT_SET,
112 i386boot_start-CFG_FLASH_BASE,
113 i386boot_end-CFG_FLASH_BASE,
114 &flash_info[0]);
115
116 flash_protect(FLAG_PROTECT_SET,
117 CFG_ENV_ADDR,
118 CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
119 &flash_info[0]);
120 return size;
121}
122
123/*-----------------------------------------------------------------------
124 */
125void flash_print_info (flash_info_t *info)
126{
127 int i;
128
129 switch (info->flash_id & FLASH_VENDMASK)
130 {
131 case (AMD_MANUFACT & FLASH_VENDMASK):
132 printf("AMD: ");
133 break;
134 default:
135 printf("Unknown Vendor ");
136 break;
137 }
138
139 switch (info->flash_id & FLASH_TYPEMASK)
140 {
141 case (AMD_ID_LV160B & FLASH_TYPEMASK):
142 printf("2x Amd29F160BB (16Mbit)\n");
143 break;
144 default:
145 printf("Unknown Chip Type\n");
146 goto Done;
147 break;
148 }
149
150 printf(" Size: %ld MB in %d Sectors\n",
151 info->size >> 20, info->sector_count);
152
153 printf(" Sector Start Addresses:");
154 for (i = 0; i < info->sector_count; i++)
155 {
156 if ((i % 5) == 0)
157 {
158 printf ("\n ");
159 }
160 printf (" %08lX%s", info->start[i],
161 info->protect[i] ? " (RO)" : " ");
162 }
163 printf ("\n");
164
165Done:
166}
167
168/*-----------------------------------------------------------------------
169 */
170
171int flash_erase (flash_info_t *info, int s_first, int s_last)
172{
173 ulong result;
174 int iflag, cflag, prot, sect;
175 int rc = ERR_OK;
176 int chip1, chip2;
177
178 /* first look for protection bits */
179
180 if (info->flash_id == FLASH_UNKNOWN)
181 return ERR_UNKNOWN_FLASH_TYPE;
182
183 if ((s_first < 0) || (s_first > s_last)) {
184 return ERR_INVAL;
185 }
186
187 if ((info->flash_id & FLASH_VENDMASK) !=
188 (AMD_MANUFACT & FLASH_VENDMASK)) {
189 return ERR_UNKNOWN_FLASH_VENDOR;
190 }
191
192 prot = 0;
193 for (sect=s_first; sect<=s_last; ++sect) {
194 if (info->protect[sect]) {
195 prot++;
196 }
197 }
198 if (prot)
199 return ERR_PROTECTED;
200
201 /*
202 * Disable interrupts which might cause a timeout
203 * here. Remember that our exception vectors are
204 * at address 0 in the flash, and we don't want a
205 * (ticker) exception to happen while the flash
206 * chip is in programming mode.
207 */
208 iflag = disable_interrupts();
209
210 /* Start erase on unprotected sectors */
211 for (sect = s_first; sect<=s_last && !ctrlc(); sect++)
212 {
213 printf("Erasing sector %2d ... ", sect);
214
215 /* arm simple, non interrupt dependent timer */
216 reset_timer();
217
218 if (info->protect[sect] == 0)
219 { /* not protected */
220 vu_long *addr = (vu_long *)(info->start[sect]);
221
222 MEM_FLASH_ADDR1 = CMD_UNLOCK1;
223 MEM_FLASH_ADDR2 = CMD_UNLOCK2;
224 MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
225
226 MEM_FLASH_ADDR1 = CMD_UNLOCK1;
227 MEM_FLASH_ADDR2 = CMD_UNLOCK2;
228 *addr = CMD_ERASE_CONFIRM;
229
230 /* wait until flash is ready */
231 chip1 = chip2 = 0;
232
233 do
234 {
235 result = *addr;
236
237 /* check timeout */
238 if (get_timer(0) > CFG_FLASH_ERASE_TOUT)
239 {
240 MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
241 chip1 = TMO;
242 break;
243 }
244
245 if (!chip1 && (result & 0xFFFF) & BIT_ERASE_DONE)
246 chip1 = READY;
247
248 if (!chip1 && (result & 0xFFFF) & BIT_PROGRAM_ERROR)
249 chip1 = ERR;
250
251 if (!chip2 && (result >> 16) & BIT_ERASE_DONE)
252 chip2 = READY;
253
254 if (!chip2 && (result >> 16) & BIT_PROGRAM_ERROR)
255 chip2 = ERR;
256
257 } while (!chip1 || !chip2);
258
259 MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
260
261 if (chip1 == ERR || chip2 == ERR)
262 {
263 rc = ERR_PROG_ERROR;
264 goto outahere;
265 }
266 if (chip1 == TMO)
267 {
268 rc = ERR_TIMOUT;
269 goto outahere;
270 }
271
272 printf("ok.\n");
273 }
274 else /* it was protected */
275 {
276 printf("protected!\n");
277 }
278 }
279
280 if (ctrlc())
281 printf("User Interrupt!\n");
282
283outahere:
284 /* allow flash to settle - wait 10 ms */
285 udelay(10000);
286
287 if (iflag)
288 enable_interrupts();
289
290
291 return rc;
292}
293
294/*-----------------------------------------------------------------------
295 * Copy memory to flash
296 */
297
298volatile static int write_word (flash_info_t *info, ulong dest, ulong data)
299{
300 vu_long *addr = (vu_long *)dest;
301 ulong result;
302 int rc = ERR_OK;
303 int iflag;
304 int chip1, chip2;
305
306 /*
307 * Check if Flash is (sufficiently) erased
308 */
309 result = *addr;
310 if ((result & data) != data)
311 return ERR_NOT_ERASED;
312
313
314 /*
315 * Disable interrupts which might cause a timeout
316 * here. Remember that our exception vectors are
317 * at address 0 in the flash, and we don't want a
318 * (ticker) exception to happen while the flash
319 * chip is in programming mode.
320 */
321 iflag = disable_interrupts();
322
323 MEM_FLASH_ADDR1 = CMD_UNLOCK1;
324 MEM_FLASH_ADDR2 = CMD_UNLOCK2;
325 MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS;
326 *addr = CMD_PROGRAM;
327 *addr = data;
328
329 /* arm simple, non interrupt dependent timer */
330 reset_timer();
331
332 /* wait until flash is ready */
333 chip1 = chip2 = 0;
334 do
335 {
336 result = *addr;
337
338 /* check timeout */
339 if (get_timer(0) > CFG_FLASH_ERASE_TOUT)
340 {
341 chip1 = ERR | TMO;
342 break;
343 }
344 if (!chip1 && ((result & 0x80) == (data & 0x80)))
345 chip1 = READY;
346
347 if (!chip1 && ((result & 0xFFFF) & BIT_PROGRAM_ERROR))
348 {
349 result = *addr;
350
351 if ((result & 0x80) == (data & 0x80))
352 chip1 = READY;
353 else
354 chip1 = ERR;
355 }
356
357 if (!chip2 && ((result & (0x80 << 16)) == (data & (0x80 << 16))))
358 chip2 = READY;
359
360 if (!chip2 && ((result >> 16) & BIT_PROGRAM_ERROR))
361 {
362 result = *addr;
363
364 if ((result & (0x80 << 16)) == (data & (0x80 << 16)))
365 chip2 = READY;
366 else
367 chip2 = ERR;
368 }
369
370 } while (!chip1 || !chip2);
371
372 *addr = CMD_READ_ARRAY;
373
374 if (chip1 == ERR || chip2 == ERR || *addr != data)
375 rc = ERR_PROG_ERROR;
376
377 if (iflag)
378 enable_interrupts();
379
380
381 return rc;
382}
383
384/*-----------------------------------------------------------------------
385 * Copy memory to flash.
386 */
387
388int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
389{
390 ulong cp, wp, data;
391 int l;
392 int i, rc;
393
394 wp = (addr & ~3); /* get lower word aligned address */
395
396 /*
397 * handle unaligned start bytes
398 */
399 if ((l = addr - wp) != 0) {
400 data = 0;
401 for (i=0, cp=wp; i<l; ++i, ++cp) {
402 data = (data >> 8) | (*(uchar *)cp << 24);
403 }
404 for (; i<4 && cnt>0; ++i) {
405 data = (data >> 8) | (*src++ << 24);
406 --cnt;
407 ++cp;
408 }
409 for (; cnt==0 && i<4; ++i, ++cp) {
410 data = (data >> 8) | (*(uchar *)cp << 24);
411 }
412
413 if ((rc = write_word(info, wp, data)) != 0) {
414 return (rc);
415 }
416 wp += 4;
417 }
418
419 /*
420 * handle word aligned part
421 */
422 while (cnt >= 4) {
423 data = *((vu_long*)src);
424 if ((rc = write_word(info, wp, data)) != 0) {
425 return (rc);
426 }
427 src += 4;
428 wp += 4;
429 cnt -= 4;
430 }
431
432 if (cnt == 0) {
433 return ERR_OK;
434 }
435
436 /*
437 * handle unaligned tail bytes
438 */
439 data = 0;
440 for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
441 data = (data >> 8) | (*src++ << 24);
442 --cnt;
443 }
444 for (; i<4; ++i, ++cp) {
445 data = (data >> 8) | (*(uchar *)cp << 24);
446 }
447
448 return write_word(info, wp, data);
449}