blob: 8252c42fd8c684b087633f26cf375a365ef7c62a [file] [log] [blame]
Aubrey Li26bf7de2007-03-19 01:24:52 +08001/*
2 * U-boot - flash.c Flash driver for PSD4256GV
3 *
Aubrey Li155fd762007-04-05 18:31:18 +08004 * Copyright (c) 2005-2007 Analog Devices Inc.
Aubrey Li26bf7de2007-03-19 01:24:52 +08005 * This file is based on BF533EzFlash.c originally written by Analog Devices, Inc.
6 *
7 * (C) Copyright 2000-2004
8 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
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
Aubrey Li155fd762007-04-05 18:31:18 +080025 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
26 * MA 02110-1301 USA
Aubrey Li26bf7de2007-03-19 01:24:52 +080027 */
28
29#include <malloc.h>
30#include <config.h>
31#include <asm/io.h>
32#include "flash-defines.h"
33
34void flash_reset(void)
35{
36 reset_flash();
37}
38
39unsigned long flash_get_size(ulong baseaddr, flash_info_t * info, int bank_flag)
40{
41 int id = 0, i = 0;
42 static int FlagDev = 1;
43
44 id = get_codes();
45 if (FlagDev) {
46 FlagDev = 0;
47 }
48 info->flash_id = id;
49 switch (bank_flag) {
50 case 0:
51 for (i = PriFlashABegin; i < SecFlashABegin; i++)
52 info->start[i] = (baseaddr + (i * AFP_SectorSize1));
53 for (i = SecFlashABegin; i < NUM_SECTORS; i++)
54 info->start[i] =
55 (baseaddr + SecFlashAOff +
56 ((i - SecFlashABegin) * AFP_SectorSize2));
57 info->size = 0x400000;
58 info->sector_count = NUM_SECTORS;
59 break;
60 case 1:
61 info->start[0] = baseaddr + SecFlashASec1Off;
62 info->start[1] = baseaddr + SecFlashASec2Off;
63 info->start[2] = baseaddr + SecFlashASec3Off;
64 info->start[3] = baseaddr + SecFlashASec4Off;
65 info->size = 0x10000;
66 info->sector_count = 4;
67 break;
68 case 2:
69 info->start[0] = baseaddr + SecFlashBSec1Off;
70 info->start[1] = baseaddr + SecFlashBSec2Off;
71 info->start[2] = baseaddr + SecFlashBSec3Off;
72 info->start[3] = baseaddr + SecFlashBSec4Off;
73 info->size = 0x10000;
74 info->sector_count = 4;
75 break;
76 }
77 return (info->size);
78}
79
80unsigned long flash_init(void)
81{
82 unsigned long size_b;
83 int i;
84
85 size_b = 0;
86 for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
87 flash_info[i].flash_id = FLASH_UNKNOWN;
88 }
89
90 size_b = flash_get_size(CFG_FLASH_BASE, &flash_info[0], 0);
91
92 if (flash_info[0].flash_id == FLASH_UNKNOWN || size_b == 0) {
93 printf("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
94 size_b, size_b >> 20);
95 }
96
97 /* flash_protect (int flag, ulong from, ulong to, flash_info_t *info) */
98 (void)flash_protect(FLAG_PROTECT_SET, CFG_FLASH_BASE,
99 (flash_info[0].start[2] - 1), &flash_info[0]);
100#if (BFIN_BOOT_MODE == BF537_BYPASS_BOOT)
101 (void)flash_protect(FLAG_PROTECT_SET, 0x203F0000, 0x203FFFFF,
102 &flash_info[0]);
103#endif
104
105 return (size_b);
106}
107
108void flash_print_info(flash_info_t * info)
109{
110 int i;
111
112 if (info->flash_id == FLASH_UNKNOWN) {
113 printf("missing or unknown FLASH type\n");
114 return;
115 }
116
117 switch (info->flash_id) {
118 case (STM_ID_29W320EB & 0xFFFF):
119 case (STM_ID_29W320DB & 0xFFFF):
120 printf("ST Microelectronics ");
121 break;
122 default:
123 printf("Unknown Vendor: (0x%08X) ", info->flash_id);
124 break;
125 }
126 for (i = 0; i < info->sector_count; ++i) {
127 if ((i % 5) == 0)
128 printf("\n ");
129 printf(" %08lX%s",
130 info->start[i], info->protect[i] ? " (RO)" : " ");
131 }
132 printf("\n");
133 return;
134}
135
136int flash_erase(flash_info_t * info, int s_first, int s_last)
137{
138 int cnt = 0, i;
139 int prot, sect;
140
141 prot = 0;
142 for (sect = s_first; sect <= s_last; ++sect) {
143 if (info->protect[sect])
144 prot++;
145 }
146 if (prot)
147 printf("- Warning: %d protected sectors will not be erased!\n",
148 prot);
149 else
150 printf("\n");
151
152 cnt = s_last - s_first + 1;
153
154#if (BFIN_BOOT_MODE == BF537_BYPASS_BOOT)
155 printf("Erasing Flash locations, Please Wait\n");
156 for (i = s_first; i <= s_last; i++) {
157 if (info->protect[i] == 0) { /* not protected */
158 if (erase_block_flash(i) < 0) {
159 printf("Error Sector erasing \n");
160 return FLASH_FAIL;
161 }
162 }
163 }
164#elif (BFIN_BOOT_MODE == BF537_SPI_MASTER_BOOT)
165 if (cnt == FLASH_TOT_SECT) {
166 printf("Erasing flash, Please Wait \n");
167 if (erase_flash() < 0) {
168 printf("Erasing flash failed \n");
169 return FLASH_FAIL;
170 }
171 } else {
172 printf("Erasing Flash locations, Please Wait\n");
173 for (i = s_first; i <= s_last; i++) {
174 if (info->protect[i] == 0) { /* not protected */
175 if (erase_block_flash(i) < 0) {
176 printf("Error Sector erasing \n");
177 return FLASH_FAIL;
178 }
179 }
180 }
181 }
182#endif
183 printf("\n");
184 return FLASH_SUCCESS;
185}
186
187int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
188{
189 int d;
190 if (addr % 2) {
191 read_flash(addr - 1 - CFG_FLASH_BASE, &d);
192 d = (int)((d & 0x00FF) | (*src++ << 8));
193 write_data(addr - 1, 2, (uchar *) & d);
194 write_data(addr + 1, cnt - 1, src);
195 } else
196 write_data(addr, cnt, src);
197 return FLASH_SUCCESS;
198}
199
200int write_data(long lStart, long lCount, uchar * pnData)
201{
202 long i = 0;
203 unsigned long ulOffset = lStart - CFG_FLASH_BASE;
204 int d;
205 int nSector = 0;
206 int flag = 0;
207
208 if (lCount % 2) {
209 flag = 1;
210 lCount = lCount - 1;
211 }
212
213 for (i = 0; i < lCount - 1; i += 2, ulOffset += 2) {
214 get_sector_number(ulOffset, &nSector);
215 read_flash(ulOffset, &d);
216 if (d != 0xffff) {
217 printf
218 ("Flash not erased at offset 0x%x Please erase to reprogram \n",
219 ulOffset);
220 return FLASH_FAIL;
221 }
222 unlock_flash(ulOffset);
223 d = (int)(pnData[i] | pnData[i + 1] << 8);
224 write_flash(ulOffset, d);
225 if (poll_toggle_bit(ulOffset) < 0) {
226 printf("Error programming the flash \n");
227 return FLASH_FAIL;
228 }
229 if ((i > 0) && (!(i % AFP_SectorSize2)))
230 printf(".");
231 }
232 if (flag) {
233 get_sector_number(ulOffset, &nSector);
234 read_flash(ulOffset, &d);
235 if (d != 0xffff) {
236 printf
237 ("Flash not erased at offset 0x%x Please erase to reprogram \n",
238 ulOffset);
239 return FLASH_FAIL;
240 }
241 unlock_flash(ulOffset);
242 d = (int)(pnData[i] | (d & 0xFF00));
243 write_flash(ulOffset, d);
244 if (poll_toggle_bit(ulOffset) < 0) {
245 printf("Error programming the flash \n");
246 return FLASH_FAIL;
247 }
248 }
249 return FLASH_SUCCESS;
250}
251
252int write_flash(long nOffset, int nValue)
253{
254 long addr;
255
256 addr = (CFG_FLASH_BASE + nOffset);
257 *(unsigned volatile short *)addr = nValue;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500258 SSYNC();
Aubrey Li26bf7de2007-03-19 01:24:52 +0800259#if (BFIN_BOOT_MODE == BF537_SPI_MASTER_BOOT)
260 if (icache_status())
261 udelay(CONFIG_CCLK_HZ / 1000000);
262#endif
263 return FLASH_SUCCESS;
264}
265
266int read_flash(long nOffset, int *pnValue)
267{
268 unsigned short *pFlashAddr =
269 (unsigned short *)(CFG_FLASH_BASE + nOffset);
270
271 *pnValue = *pFlashAddr;
272
273 return TRUE;
274}
275
276int poll_toggle_bit(long lOffset)
277{
278 unsigned int u1, u2;
279 volatile unsigned long *FB =
280 (volatile unsigned long *)(CFG_FLASH_BASE + lOffset);
281 while (1) {
282 u1 = *(volatile unsigned short *)FB;
283 u2 = *(volatile unsigned short *)FB;
284 u1 ^= u2;
285 if (!(u1 & 0x0040))
286 break;
287 if (!(u2 & 0x0020))
288 continue;
289 else {
290 u1 = *(volatile unsigned short *)FB;
291 u2 = *(volatile unsigned short *)FB;
292 u1 ^= u2;
293 if (!(u1 & 0x0040))
294 break;
295 else {
296 reset_flash();
297 return FLASH_FAIL;
298 }
299 }
300 }
301 return FLASH_SUCCESS;
302}
303
304void reset_flash(void)
305{
306 write_flash(WRITESEQ1, RESET_VAL);
307 /* Wait for 10 micro seconds */
308 udelay(10);
309}
310
311int erase_flash(void)
312{
313 write_flash(WRITESEQ1, WRITEDATA1);
314 write_flash(WRITESEQ2, WRITEDATA2);
315 write_flash(WRITESEQ3, WRITEDATA3);
316 write_flash(WRITESEQ4, WRITEDATA4);
317 write_flash(WRITESEQ5, WRITEDATA5);
318 write_flash(WRITESEQ6, WRITEDATA6);
319
320 if (poll_toggle_bit(0x0000) < 0)
321 return FLASH_FAIL;
322
323 return FLASH_SUCCESS;
324}
325
326int erase_block_flash(int nBlock)
327{
328 long ulSectorOff = 0x0;
329
330 if ((nBlock < 0) || (nBlock > AFP_NumSectors))
331 return FALSE;
332
Aubrey Lia6154fd2007-03-19 22:55:58 +0800333 /* figure out the offset of the block in flash */
Aubrey Li26bf7de2007-03-19 01:24:52 +0800334 if ((nBlock >= 0) && (nBlock < SecFlashABegin))
335 ulSectorOff = nBlock * AFP_SectorSize1;
336
337 else if ((nBlock >= SecFlashABegin) && (nBlock < NUM_SECTORS))
338 ulSectorOff =
339 SecFlashAOff + (nBlock - SecFlashABegin) * AFP_SectorSize2;
Aubrey Lia6154fd2007-03-19 22:55:58 +0800340 /* no such sector */
Aubrey Li26bf7de2007-03-19 01:24:52 +0800341 else
342 return FLASH_FAIL;
343
344 write_flash((WRITESEQ1 | ulSectorOff), WRITEDATA1);
345 write_flash((WRITESEQ2 | ulSectorOff), WRITEDATA2);
346 write_flash((WRITESEQ3 | ulSectorOff), WRITEDATA3);
347 write_flash((WRITESEQ4 | ulSectorOff), WRITEDATA4);
348 write_flash((WRITESEQ5 | ulSectorOff), WRITEDATA5);
349
350 write_flash(ulSectorOff, BlockEraseVal);
351
352 if (poll_toggle_bit(ulSectorOff) < 0)
353 return FLASH_FAIL;
354 printf(".");
355
356 return FLASH_SUCCESS;
357}
358
359void unlock_flash(long ulOffset)
360{
361 unsigned long ulOffsetAddr = ulOffset;
362 ulOffsetAddr &= 0xFFFF0000;
363
364 write_flash((WRITESEQ1 | ulOffsetAddr), UNLOCKDATA1);
365 write_flash((WRITESEQ2 | ulOffsetAddr), UNLOCKDATA2);
366 write_flash((WRITESEQ3 | ulOffsetAddr), UNLOCKDATA3);
367}
368
369int get_codes()
370{
371 int dev_id = 0;
372
373 write_flash(WRITESEQ1, GETCODEDATA1);
374 write_flash(WRITESEQ2, GETCODEDATA2);
375 write_flash(WRITESEQ3, GETCODEDATA3);
376
377 read_flash(0x0402, &dev_id);
378 dev_id &= 0x0000FFFF;
379
380 reset_flash();
381
382 return dev_id;
383}
384
385void get_sector_number(long ulOffset, int *pnSector)
386{
387 int nSector = 0;
388 long lMainEnd = 0x400000;
389 long lBootEnd = 0x10000;
390
Aubrey Lia6154fd2007-03-19 22:55:58 +0800391 /* sector numbers for the FLASH A boot sectors */
Aubrey Li26bf7de2007-03-19 01:24:52 +0800392 if (ulOffset < lBootEnd) {
393 nSector = (int)ulOffset / AFP_SectorSize1;
394 }
Aubrey Lia6154fd2007-03-19 22:55:58 +0800395 /* sector numbers for the FLASH B boot sectors */
Aubrey Li26bf7de2007-03-19 01:24:52 +0800396 else if ((ulOffset >= lBootEnd) && (ulOffset < lMainEnd)) {
397 nSector = ((ulOffset / (AFP_SectorSize2)) + 7);
398 }
Aubrey Lia6154fd2007-03-19 22:55:58 +0800399 /* if it is a valid sector, set it */
Aubrey Li26bf7de2007-03-19 01:24:52 +0800400 if ((nSector >= 0) && (nSector < AFP_NumSectors))
401 *pnSector = nSector;
402
403}