blob: d209a6f9ac4359bca0a13cd191335fa1096f00c7 [file] [log] [blame]
Wolfgang Denk32cb2c72006-07-21 11:31:42 +02001/*
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#define FLASH_BANK_SIZE PHYS_FLASH_SIZE
30#define MAIN_SECT_SIZE 0x10000 /* 64 KB */
31
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020032flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
Wolfgang Denk32cb2c72006-07-21 11:31:42 +020033
34#define CMD_READ_ARRAY 0x000000F0
35#define CMD_UNLOCK1 0x000000AA
36#define CMD_UNLOCK2 0x00000055
37#define CMD_ERASE_SETUP 0x00000080
38#define CMD_ERASE_CONFIRM 0x00000030
39#define CMD_PROGRAM 0x000000A0
40#define CMD_UNLOCK_BYPASS 0x00000020
41
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020042#define MEM_FLASH_ADDR1 (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x00000555 << 1)))
43#define MEM_FLASH_ADDR2 (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x000002AA << 1)))
Wolfgang Denk32cb2c72006-07-21 11:31:42 +020044
45#define BIT_ERASE_DONE 0x00000080
46#define BIT_RDY_MASK 0x00000080
47#define BIT_PROGRAM_ERROR 0x00000020
48#define BIT_TIMEOUT 0x80000000 /* our flag */
49
50#define READY 1
51#define ERR 2
52#define TMO 4
53
54/*-----------------------------------------------------------------------
55 */
56
57ulong flash_init (void)
58{
59 int i, j;
60 ulong size = 0;
61
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020062 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
Wolfgang Denk32cb2c72006-07-21 11:31:42 +020063 ulong flashbase = 0;
64
65 flash_info[i].flash_id =
66#if defined(CONFIG_AMD_LV400)
67 (AMD_MANUFACT & FLASH_VENDMASK) |
68 (AMD_ID_LV400B & FLASH_TYPEMASK);
69#elif defined(CONFIG_AMD_LV800)
70 (AMD_MANUFACT & FLASH_VENDMASK) |
71 (AMD_ID_LV800B & FLASH_TYPEMASK);
72#else
73#error "Unknown flash configured"
74#endif
75 flash_info[i].size = FLASH_BANK_SIZE;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020076 flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT;
77 memset (flash_info[i].protect, 0, CONFIG_SYS_MAX_FLASH_SECT);
Wolfgang Denk32cb2c72006-07-21 11:31:42 +020078 if (i == 0)
79 flashbase = PHYS_FLASH_1;
80 else
81 panic ("configured too many flash banks!\n");
82 for (j = 0; j < flash_info[i].sector_count; j++) {
83 if (j <= 3) {
84 /* 1st one is 16 KB */
85 if (j == 0) {
86 flash_info[i].start[j] =
87 flashbase + 0;
88 }
89
90 /* 2nd and 3rd are both 8 KB */
91 if ((j == 1) || (j == 2)) {
92 flash_info[i].start[j] =
93 flashbase + 0x4000 + (j -
94 1) *
95 0x2000;
96 }
97
98 /* 4th 32 KB */
99 if (j == 3) {
100 flash_info[i].start[j] =
101 flashbase + 0x8000;
102 }
103 } else {
104 flash_info[i].start[j] =
105 flashbase + (j - 3) * MAIN_SECT_SIZE;
106 }
107 }
108 size += flash_info[i].size;
109 }
110
111 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200112 CONFIG_SYS_FLASH_BASE,
113 CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1,
Wolfgang Denk32cb2c72006-07-21 11:31:42 +0200114 &flash_info[0]);
115
116 flash_protect (FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200117 CONFIG_ENV_ADDR,
118 CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]);
Wolfgang Denk32cb2c72006-07-21 11:31:42 +0200119
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 case (AMD_MANUFACT & FLASH_VENDMASK):
131 printf ("AMD: ");
132 break;
133 default:
134 printf ("Unknown Vendor ");
135 break;
136 }
137
138 switch (info->flash_id & FLASH_TYPEMASK) {
139 case (AMD_ID_LV400B & FLASH_TYPEMASK):
140 printf ("1x Amd29LV400BB (4Mbit)\n");
141 break;
142 case (AMD_ID_LV800B & FLASH_TYPEMASK):
143 printf ("1x Amd29LV800BB (8Mbit)\n");
144 break;
145 default:
146 printf ("Unknown Chip Type\n");
147 goto Done;
148 break;
149 }
150
151 printf (" Size: %ld MB in %d Sectors\n",
152 info->size >> 20, info->sector_count);
153
154 printf (" Sector Start Addresses:");
155 for (i = 0; i < info->sector_count; i++) {
156 if ((i % 5) == 0) {
157 printf ("\n ");
158 }
159 printf (" %08lX%s", info->start[i],
160 info->protect[i] ? " (RO)" : " ");
161 }
162 printf ("\n");
163
164 Done:;
165}
166
167/*-----------------------------------------------------------------------
168 */
169
170int flash_erase (flash_info_t * info, int s_first, int s_last)
171{
172 ushort result;
173 int iflag, cflag, prot, sect;
174 int rc = ERR_OK;
175 int chip;
Graeme Russa60d1e52011-07-15 23:31:37 +0000176 ulong start;
Wolfgang Denk32cb2c72006-07-21 11:31:42 +0200177
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 cflag = icache_status ();
209 icache_disable ();
210 iflag = disable_interrupts ();
211
212 /* Start erase on unprotected sectors */
213 for (sect = s_first; sect <= s_last && !ctrlc (); sect++) {
214 printf ("Erasing sector %2d ... ", sect);
215
216 /* arm simple, non interrupt dependent timer */
Graeme Russa60d1e52011-07-15 23:31:37 +0000217 start = get_timer(0);
Wolfgang Denk32cb2c72006-07-21 11:31:42 +0200218
219 if (info->protect[sect] == 0) { /* not protected */
220 vu_short *addr = (vu_short *) (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 chip = 0;
232
233 do {
234 result = *addr;
235
236 /* check timeout */
Graeme Russa60d1e52011-07-15 23:31:37 +0000237 if (get_timer(start) >
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200238 CONFIG_SYS_FLASH_ERASE_TOUT) {
Wolfgang Denk32cb2c72006-07-21 11:31:42 +0200239 MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
240 chip = TMO;
241 break;
242 }
243
244 if (!chip
245 && (result & 0xFFFF) & BIT_ERASE_DONE)
246 chip = READY;
247
248 if (!chip
249 && (result & 0xFFFF) & BIT_PROGRAM_ERROR)
250 chip = ERR;
251
252 } while (!chip);
253
254 MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
255
256 if (chip == ERR) {
257 rc = ERR_PROG_ERROR;
258 goto outahere;
259 }
260 if (chip == TMO) {
261 rc = ERR_TIMOUT;
262 goto outahere;
263 }
264
265 printf ("ok.\n");
266 } else { /* it was protected */
267
268 printf ("protected!\n");
269 }
270 }
271
272 if (ctrlc ())
273 printf ("User Interrupt!\n");
274
275 outahere:
276 /* allow flash to settle - wait 10 ms */
277 udelay_masked (10000);
278
279 if (iflag)
280 enable_interrupts ();
281
282 if (cflag)
283 icache_enable ();
284
285 return rc;
286}
287
288/*-----------------------------------------------------------------------
289 * Copy memory to flash
290 */
291
Wolfgang Denk8412d812007-11-18 17:11:09 +0100292static int write_hword (flash_info_t * info, ulong dest, ushort data)
Wolfgang Denk32cb2c72006-07-21 11:31:42 +0200293{
294 vu_short *addr = (vu_short *) dest;
295 ushort result;
296 int rc = ERR_OK;
297 int cflag, iflag;
298 int chip;
Graeme Russa60d1e52011-07-15 23:31:37 +0000299 ulong start;
Wolfgang Denk32cb2c72006-07-21 11:31:42 +0200300
301 /*
302 * Check if Flash is (sufficiently) erased
303 */
304 result = *addr;
305 if ((result & data) != data)
306 return ERR_NOT_ERASED;
307
308
309 /*
310 * Disable interrupts which might cause a timeout
311 * here. Remember that our exception vectors are
312 * at address 0 in the flash, and we don't want a
313 * (ticker) exception to happen while the flash
314 * chip is in programming mode.
315 */
316 cflag = icache_status ();
317 icache_disable ();
318 iflag = disable_interrupts ();
319
320 MEM_FLASH_ADDR1 = CMD_UNLOCK1;
321 MEM_FLASH_ADDR2 = CMD_UNLOCK2;
322 MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS;
323 *addr = CMD_PROGRAM;
324 *addr = data;
325
326 /* arm simple, non interrupt dependent timer */
Graeme Russa60d1e52011-07-15 23:31:37 +0000327 get_timer(start);
Wolfgang Denk32cb2c72006-07-21 11:31:42 +0200328
329 /* wait until flash is ready */
330 chip = 0;
331 do {
332 result = *addr;
333
334 /* check timeout */
Graeme Russa60d1e52011-07-15 23:31:37 +0000335 if (get_timer(start) > CONFIG_SYS_FLASH_ERASE_TOUT) {
Wolfgang Denk32cb2c72006-07-21 11:31:42 +0200336 chip = ERR | TMO;
337 break;
338 }
339 if (!chip && ((result & 0x80) == (data & 0x80)))
340 chip = READY;
341
342 if (!chip && ((result & 0xFFFF) & BIT_PROGRAM_ERROR)) {
343 result = *addr;
344
345 if ((result & 0x80) == (data & 0x80))
346 chip = READY;
347 else
348 chip = ERR;
349 }
350
351 } while (!chip);
352
353 *addr = CMD_READ_ARRAY;
354
355 if (chip == ERR || *addr != data)
356 rc = ERR_PROG_ERROR;
357
358 if (iflag)
359 enable_interrupts ();
360
361 if (cflag)
362 icache_enable ();
363
364 return rc;
365}
366
367/*-----------------------------------------------------------------------
368 * Copy memory to flash.
369 */
370
371int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
372{
373 ulong cp, wp;
374 int l;
375 int i, rc;
376 ushort data;
377
378 wp = (addr & ~1); /* get lower word aligned address */
379
380 /*
381 * handle unaligned start bytes
382 */
383 if ((l = addr - wp) != 0) {
384 data = 0;
385 for (i = 0, cp = wp; i < l; ++i, ++cp) {
386 data = (data >> 8) | (*(uchar *) cp << 8);
387 }
388 for (; i < 2 && cnt > 0; ++i) {
389 data = (data >> 8) | (*src++ << 8);
390 --cnt;
391 ++cp;
392 }
393 for (; cnt == 0 && i < 2; ++i, ++cp) {
394 data = (data >> 8) | (*(uchar *) cp << 8);
395 }
396
397 if ((rc = write_hword (info, wp, data)) != 0) {
398 return (rc);
399 }
400 wp += 2;
401 }
402
403 /*
404 * handle word aligned part
405 */
406 while (cnt >= 2) {
407 data = *((vu_short *) src);
408 if ((rc = write_hword (info, wp, data)) != 0) {
409 return (rc);
410 }
411 src += 2;
412 wp += 2;
413 cnt -= 2;
414 }
415
416 if (cnt == 0) {
417 return ERR_OK;
418 }
419
420 /*
421 * handle unaligned tail bytes
422 */
423 data = 0;
424 for (i = 0, cp = wp; i < 2 && cnt > 0; ++i, ++cp) {
425 data = (data >> 8) | (*src++ << 8);
426 --cnt;
427 }
428 for (; i < 2; ++i, ++cp) {
429 data = (data >> 8) | (*(uchar *) cp << 8);
430 }
431
432 return write_hword (info, wp, data);
433}