blob: e9eca35e0f7146ee82f21a06787087bfe72b1a90 [file] [log] [blame]
Wolfgang Denk7b9bc3a2005-09-14 23:53:32 +02001/*
2 * (C) Copyright 2002
3 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
4 * Alex Zuepke <azu@sysgo.de>
5 *
6 * (C) Copyright 2005
7 * 2N Telekomunikace, a.s. <www.2n.cz>
8 * Ladislav Michl <michl@2n.cz>
9 *
10 * See file CREDITS for list of people who contributed to this
11 * project.
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation; either version 2 of
16 * the License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26 * MA 02111-1307 USA
27 */
28
29#include <common.h>
30
31/*#if 0 */
32#if (PHYS_SDRAM_1_SIZE != SZ_32M)
33
34#include "crcek.h"
35
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020036#if (CONFIG_SYS_MAX_FLASH_BANKS > 1)
Wolfgang Denk7b9bc3a2005-09-14 23:53:32 +020037#error There is always only _one_ flash chip
38#endif
39
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020040flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
Wolfgang Denk7b9bc3a2005-09-14 23:53:32 +020041
42#define CMD_READ_ARRAY 0x000000f0
43#define CMD_UNLOCK1 0x000000aa
44#define CMD_UNLOCK2 0x00000055
45#define CMD_ERASE_SETUP 0x00000080
46#define CMD_ERASE_CONFIRM 0x00000030
47#define CMD_PROGRAM 0x000000a0
48#define CMD_UNLOCK_BYPASS 0x00000020
49
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020050#define MEM_FLASH_ADDR1 (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x00000555 << 1)))
51#define MEM_FLASH_ADDR2 (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x000002aa << 1)))
Wolfgang Denk7b9bc3a2005-09-14 23:53:32 +020052
53#define BIT_ERASE_DONE 0x00000080
54#define BIT_RDY_MASK 0x00000080
55#define BIT_PROGRAM_ERROR 0x00000020
56#define BIT_TIMEOUT 0x80000000 /* our flag */
57
58/*-----------------------------------------------------------------------
59 */
60
61ulong flash_init(void)
62{
63 int i;
64
65 flash_info[0].flash_id = (AMD_MANUFACT & FLASH_VENDMASK) |
66 (AMD_ID_LV800B & FLASH_TYPEMASK);
67 flash_info[0].size = PHYS_FLASH_1_SIZE;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020068 flash_info[0].sector_count = CONFIG_SYS_MAX_FLASH_SECT;
69 memset(flash_info[0].protect, 0, CONFIG_SYS_MAX_FLASH_SECT);
Wolfgang Denk7b9bc3a2005-09-14 23:53:32 +020070
71 for (i = 0; i < flash_info[0].sector_count; i++) {
72 switch (i) {
73 case 0: /* 16kB */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020074 flash_info[0].start[0] = CONFIG_SYS_FLASH_BASE;
Wolfgang Denk7b9bc3a2005-09-14 23:53:32 +020075 break;
76 case 1: /* 8kB */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020077 flash_info[0].start[1] = CONFIG_SYS_FLASH_BASE + 0x4000;
Wolfgang Denk7b9bc3a2005-09-14 23:53:32 +020078 break;
79 case 2: /* 8kB */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020080 flash_info[0].start[2] = CONFIG_SYS_FLASH_BASE + 0x4000 +
Wolfgang Denk7b9bc3a2005-09-14 23:53:32 +020081 0x2000;
82 break;
83 case 3: /* 32 KB */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020084 flash_info[0].start[3] = CONFIG_SYS_FLASH_BASE + 0x4000 +
Wolfgang Denk7b9bc3a2005-09-14 23:53:32 +020085 2 * 0x2000;
86 break;
87 case 4:
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020088 flash_info[0].start[4] = CONFIG_SYS_FLASH_BASE + 0x4000 +
Wolfgang Denk7b9bc3a2005-09-14 23:53:32 +020089 2 * 0x2000 + 0x8000;
90 break;
91 default: /* 64kB */
92 flash_info[0].start[i] = flash_info[0].start[i-1] +
93 0x10000;
94 break;
95 }
96 }
97
98 /* U-Boot */
99 flash_protect(FLAG_PROTECT_SET,
100 LOADER1_OFFSET,
101 LOADER1_OFFSET + LOADER_SIZE - 1, flash_info);
102 /* Protect crcek, env and r_env as well */
103 flash_protect(FLAG_PROTECT_SET, 0, 0x8000 - 1, flash_info);
104
105 return flash_info[0].size;
106}
107
108/*-----------------------------------------------------------------------
109 */
110void flash_print_info(flash_info_t *info)
111{
112 int i;
113
114 switch (info->flash_id & FLASH_VENDMASK) {
115 case (AMD_MANUFACT & FLASH_VENDMASK):
116 puts("AMD: ");
117 break;
118 default:
119 puts("Unknown vendor ");
120 break;
121 }
122
123 switch (info->flash_id & FLASH_TYPEMASK) {
124 case (AMD_ID_LV800B & FLASH_TYPEMASK):
125 puts("AM29LV800BB (8Mb)\n");
126 break;
127 default:
128 puts("Unknown chip type\n");
129 return;
130 }
131
132 printf(" Size: %ld MB in %d sectors\n",
133 info->size >> 20, info->sector_count);
134
135 puts(" Sector start addresses:");
136 for (i = 0; i < info->sector_count; i++) {
137 if ((i % 5) == 0)
138 puts("\n ");
139
140 printf(" %08lX%s", info->start[i],
141 info->protect[i] ? " (RO)" : " ");
142 }
143 puts("\n");
144}
145
146/*-----------------------------------------------------------------------
147 */
148
149int flash_erase(flash_info_t *info, int s_first, int s_last)
150{
151 ushort result;
152 int prot, sect;
153 int rc = ERR_OK;
154
155 /* first look for protection bits */
156
157 if (info->flash_id == FLASH_UNKNOWN)
158 return ERR_UNKNOWN_FLASH_TYPE;
159
160 if ((s_first < 0) || (s_first > s_last))
161 return ERR_INVAL;
162
163 if ((info->flash_id & FLASH_VENDMASK) !=
164 (AMD_MANUFACT & FLASH_VENDMASK))
165 return ERR_UNKNOWN_FLASH_VENDOR;
166
167 prot = 0;
168 for (sect = s_first; sect <= s_last; ++sect)
169 if (info->protect[sect])
170 prot++;
171
172 if (prot)
173 printf("- Warning: %d protected sectors will not be erased!\n",
174 prot);
175 else
176 putc('\n');
177
178 /* Start erase on unprotected sectors */
179 for (sect = s_first; sect <= s_last && !ctrlc (); sect++) {
180 if (info->protect[sect] == 0) { /* not protected */
181 vu_short *addr = (vu_short *) (info->start[sect]);
182
183 /* arm simple, non interrupt dependent timer */
184 reset_timer_masked();
185
186 MEM_FLASH_ADDR1 = CMD_UNLOCK1;
187 MEM_FLASH_ADDR2 = CMD_UNLOCK2;
188 MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
189
190 MEM_FLASH_ADDR1 = CMD_UNLOCK1;
191 MEM_FLASH_ADDR2 = CMD_UNLOCK2;
192 *addr = CMD_ERASE_CONFIRM;
193
194 /* wait until flash is ready */
195 while (1) {
196 result = *addr;
197
198 /* check timeout */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200199 if (get_timer_masked() > CONFIG_SYS_FLASH_ERASE_TOUT) {
Wolfgang Denk7b9bc3a2005-09-14 23:53:32 +0200200 MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
201 rc = ERR_TIMOUT;
202 break;
203 }
204
205 if ((result & 0xfff) & BIT_ERASE_DONE)
206 break;
207
208 if ((result & 0xffff) & BIT_PROGRAM_ERROR) {
209 rc = ERR_PROG_ERROR;
210 break;
211 }
212 }
213
214 MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
215
216 if (rc != ERR_OK)
217 goto out;
218
219 putc('.');
220 }
221 }
222out:
223 /* allow flash to settle - wait 10 ms */
224 udelay_masked(10000);
225
226 return rc;
227}
228
229/*-----------------------------------------------------------------------
230 * Copy memory to flash
231 */
232
Wolfgang Denk7fa6e902006-03-11 22:53:33 +0100233static int write_hword(flash_info_t *info, ulong dest, ushort data)
Wolfgang Denk7b9bc3a2005-09-14 23:53:32 +0200234{
235 vu_short *addr = (vu_short *) dest;
236 ushort result;
237 int rc = ERR_OK;
238
239 /* check if flash is (sufficiently) erased */
240 result = *addr;
241 if ((result & data) != data)
242 return ERR_NOT_ERASED;
243
244 MEM_FLASH_ADDR1 = CMD_UNLOCK1;
245 MEM_FLASH_ADDR2 = CMD_UNLOCK2;
246 MEM_FLASH_ADDR1 = CMD_PROGRAM;
247 *addr = data;
248
249 /* arm simple, non interrupt dependent timer */
250 reset_timer_masked();
251
252 /* wait until flash is ready */
253 while (1) {
254 result = *addr;
255
256 /* check timeout */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200257 if (get_timer_masked () > CONFIG_SYS_FLASH_ERASE_TOUT) {
Wolfgang Denk7b9bc3a2005-09-14 23:53:32 +0200258 rc = ERR_TIMOUT;
259 break;
260 }
261
262 if ((result & 0x80) == (data & 0x80))
263 break;
264
265 if ((result & 0xffff) & BIT_PROGRAM_ERROR) {
266 result = *addr;
267
268 if ((result & 0x80) != (data & 0x80))
269 rc = ERR_PROG_ERROR;
270 }
271 }
272
273 *addr = CMD_READ_ARRAY;
274
275 if (*addr != data)
276 rc = ERR_PROG_ERROR;
277
278 return rc;
279}
280
281/*-----------------------------------------------------------------------
282 * Copy memory to flash.
283 */
284
285int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
286{
287 ulong cp, wp;
288 int l;
289 int i, rc;
290 ushort data;
291
292 wp = (addr & ~1); /* get lower word aligned address */
293
294 /*
295 * handle unaligned start bytes
296 */
297 if ((l = addr - wp) != 0) {
298 data = 0;
299 for (i = 0, cp = wp; i < l; ++i, ++cp)
300 data = (data >> 8) | (*(uchar *) cp << 8);
301 for (; i < 2 && cnt > 0; ++i) {
302 data = (data >> 8) | (*src++ << 8);
303 --cnt;
304 ++cp;
305 }
306 for (; cnt == 0 && i < 2; ++i, ++cp)
307 data = (data >> 8) | (*(uchar *) cp << 8);
308
309 if ((rc = write_hword(info, wp, data)) != 0)
310 return (rc);
311 wp += 2;
312 }
313
314 /*
315 * handle word aligned part
316 */
317 while (cnt >= 2) {
318 data = *((vu_short *) src);
319 if ((rc = write_hword(info, wp, data)) != 0)
320 return (rc);
321 src += 2;
322 wp += 2;
323 cnt -= 2;
324 }
325
326 if (cnt == 0)
327 return ERR_OK;
328
329 /*
330 * handle unaligned tail bytes
331 */
332 data = 0;
333 for (i = 0, cp = wp; i < 2 && cnt > 0; ++i, ++cp) {
334 data = (data >> 8) | (*src++ << 8);
335 --cnt;
336 }
337 for (; i < 2; ++i, ++cp)
338 data = (data >> 8) | (*(uchar *) cp << 8);
339
340 return write_hword(info, wp, data);
341}
342
343#endif