blob: 0c4a9439f8d77f436cc79a6b0ddf4c38193d767c [file] [log] [blame]
wdenkafd7f3d2002-11-03 01:41:26 +00001/*
2 * (C) Copyright 2000
3 * Marius Groeger <mgroeger@sysgo.de>
4 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
5 *
6 * (C) Copyright 2000, 2001
7 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
8 *
9 * (C) Copyright 2001
10 * Advent Networks, Inc. <http://www.adventnetworks.com>
11 * Oliver Brown <oliverb@alumni.utexas.net>
12 *
Wolfgang Denk1a459662013-07-08 09:37:19 +020013 * SPDX-License-Identifier: GPL-2.0+
wdenkafd7f3d2002-11-03 01:41:26 +000014 */
15
16/*********************************************************************/
17/* DESCRIPTION:
18 * This file contains the flash routines for the GW8260 board.
19 *
20 *
21 *
22 * MODULE DEPENDENCY:
23 * None
24 *
25 *
26 * RESTRICTIONS/LIMITATIONS:
27 *
28 * Only supports the following flash devices:
29 * AMD 29F080B
30 * AMD 29F016D
31 *
32 * Copyright (c) 2001, Advent Networks, Inc.
33 *
34 */
35/*********************************************************************/
36
37#include <common.h>
38#include <mpc8260.h>
39
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020040flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
wdenkafd7f3d2002-11-03 01:41:26 +000041
42static ulong flash_get_size (vu_long *addr, flash_info_t *info);
43static int write_word (flash_info_t *info, ulong dest, ulong data);
44
45/*********************************************************************/
46/* functions */
47/*********************************************************************/
48
Wolfgang Denk6cfdd302011-11-05 05:13:07 +000049/*
50 * NAME: flash_init() - initializes flash banks
51 *
52 * DESCRIPTION:
53 * This function initializes the flash bank(s).
54 *
55 * RETURNS:
56 * The size in bytes of the flash
57 *
58 * RESTRICTIONS/LIMITATIONS:
59 *
60 *
61 */
62unsigned long flash_init(void)
wdenkafd7f3d2002-11-03 01:41:26 +000063{
Wolfgang Denk6cfdd302011-11-05 05:13:07 +000064 int i;
wdenkafd7f3d2002-11-03 01:41:26 +000065
Wolfgang Denk6cfdd302011-11-05 05:13:07 +000066 /* Init: no FLASHes known */
67 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i)
68 flash_info[i].flash_id = FLASH_UNKNOWN;
wdenkafd7f3d2002-11-03 01:41:26 +000069
Wolfgang Denk6cfdd302011-11-05 05:13:07 +000070 /* for now, only support the 4 MB Flash SIMM */
Wolfgang Denk5a5f34a2011-11-05 05:13:08 +000071 (void)flash_get_size((vu_long *) CONFIG_SYS_FLASH0_BASE,
Wolfgang Denk6cfdd302011-11-05 05:13:07 +000072 &flash_info[0]);
73 /*
74 * protect monitor and environment sectors
75 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020076#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH0_BASE
Wolfgang Denk6cfdd302011-11-05 05:13:07 +000077 flash_protect(FLAG_PROTECT_SET,
78 CONFIG_SYS_MONITOR_BASE,
79 CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
80 &flash_info[0]);
wdenkafd7f3d2002-11-03 01:41:26 +000081#endif
82
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020083#if defined(CONFIG_ENV_IS_IN_FLASH) && defined(CONFIG_ENV_ADDR)
Wolfgang Denk6cfdd302011-11-05 05:13:07 +000084#ifndef CONFIG_ENV_SIZE
85#define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE
86#endif
87 flash_protect(FLAG_PROTECT_SET,
88 CONFIG_ENV_ADDR,
89 CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]);
wdenkafd7f3d2002-11-03 01:41:26 +000090#endif
91
Wolfgang Denk6cfdd302011-11-05 05:13:07 +000092 return CONFIG_SYS_FLASH0_SIZE * 1024 * 1024; /*size */
wdenkafd7f3d2002-11-03 01:41:26 +000093}
94
95/*********************************************************************/
96/* NAME: flash_print_info() - prints flash imformation */
97/* */
98/* DESCRIPTION: */
99/* This function prints the flash information. */
100/* */
101/* INPUTS: */
102/* flash_info_t *info - flash information structure */
103/* */
104/* OUTPUTS: */
105/* Displays flash information to console */
106/* */
107/* RETURNS: */
108/* None */
109/* */
110/* RESTRICTIONS/LIMITATIONS: */
111/* */
112/* */
113/*********************************************************************/
114void flash_print_info (flash_info_t *info)
115{
116 int i;
117
118 if (info->flash_id == FLASH_UNKNOWN) {
119 printf ("missing or unknown FLASH type\n");
120 return;
121 }
122
123 switch ((info->flash_id >> 16) & 0xff) {
124 case 0x1:
125 printf ("AMD ");
126 break;
127 default:
128 printf ("Unknown Vendor ");
129 break;
130 }
131
132 switch (info->flash_id & FLASH_TYPEMASK) {
133 case AMD_ID_F040B:
134 printf ("AM29F040B (4 Mbit)\n");
135 break;
136 case AMD_ID_F080B:
137 printf ("AM29F080B (8 Mbit)\n");
138 break;
139 case AMD_ID_F016D:
140 printf ("AM29F016D (16 Mbit)\n");
141 break;
142 default:
143 printf ("Unknown Chip Type\n");
144 break;
145 }
146
147 printf (" Size: %ld MB in %d Sectors\n",
148 info->size >> 20, info->sector_count);
149
150 printf (" Sector Start Addresses:");
151 for (i=0; i<info->sector_count; ++i) {
152 if ((i % 5) == 0)
153 printf ("\n ");
154 printf (" %08lX%s",
155 info->start[i],
156 info->protect[i] ? " (RO)" : " "
157 );
158 }
159 printf ("\n");
160 return;
161}
162
163/*********************************************************************/
164/* The following code cannot be run from FLASH! */
165/*********************************************************************/
166
167/*********************************************************************/
168/* NAME: flash_get_size() - detects the flash size */
169/* */
170/* DESCRIPTION: */
171/* 1) Reads vendor ID and devices ID from the flash devices. */
172/* 2) Initializes flash info struct. */
173/* 3) Return the flash size */
174/* */
175/* INPUTS: */
176/* vu_long *addr - pointer to start of flash */
177/* flash_info_t *info - flash information structure */
178/* */
179/* OUTPUTS: */
180/* None */
181/* */
182/* RETURNS: */
183/* Size of the flash in bytes, or 0 if device id is unknown. */
184/* */
185/* RESTRICTIONS/LIMITATIONS: */
186/* Only supports the following devices: */
187/* AM29F080D */
188/* AM29F016D */
189/* */
190/*********************************************************************/
191static ulong flash_get_size (vu_long *addr, flash_info_t *info)
192{
193 short i;
194 vu_long vendor, devid;
195 ulong base = (ulong)addr;
196
197 /*printf("addr = %08lx\n", (unsigned long)addr); */
198
199 /* Reset and Write auto select command: read Manufacturer ID */
200 addr[0x0000] = 0xf0f0f0f0;
201 addr[0x0555] = 0xAAAAAAAA;
202 addr[0x02AA] = 0x55555555;
203 addr[0x0555] = 0x90909090;
204 udelay (1000);
205
206 vendor = addr[0];
207 /*printf("vendor = %08lx\n", vendor); */
208 if (vendor != 0x01010101) {
209 info->size = 0;
210 goto out;
211 }
212
213 devid = addr[1];
214 /*printf("devid = %08lx\n", devid); */
215
216 if ((devid & 0xff) == AMD_ID_F080B) {
217 info->flash_id = (vendor & 0xff) << 16 | AMD_ID_F080B;
218 /* we have 16 sectors with 64KB each x 4 */
219 info->sector_count = 16;
220 info->size = 4 * info->sector_count * 64*1024;
221 } else if ((devid & 0xff) == AMD_ID_F016D){
222 info->flash_id = (vendor & 0xff) << 16 | AMD_ID_F016D;
223 /* we have 32 sectors with 64KB each x 4 */
224 info->sector_count = 32;
225 info->size = 4 * info->sector_count * 64*1024;
226 } else {
227 info->size = 0;
228 goto out;
229 }
230 /*printf("sector count = %08x\n", info->sector_count); */
231 /* check for protected sectors */
232 for (i = 0; i < info->sector_count; i++) {
233 /* sector base address */
234 info->start[i] = base + i * (info->size / info->sector_count);
235 /* read sector protection at sector address, (A7 .. A0) = 0x02 */
236 /* D0 = 1 if protected */
237 addr = (volatile unsigned long *)(info->start[i]);
238 info->protect[i] = addr[2] & 1;
239 }
240
241 /* reset command */
242 addr = (vu_long *)info->start[0];
243
244 out:
245 addr[0] = 0xf0f0f0f0;
246
247 /*printf("size = %08x\n", info->size); */
248 return info->size;
249}
250
251/*********************************************************************/
252/* NAME: flash_erase() - erases flash by sector */
253/* */
254/* DESCRIPTION: */
255/* This function erases flash sectors starting for s_first to */
256/* s_last. */
257/* */
258/* INPUTS: */
259/* flash_info_t *info - flash information structure */
260/* int s_first - first sector to erase */
261/* int s_last - last sector to erase */
262/* */
263/* OUTPUTS: */
264/* None */
265/* */
266/* RETURNS: */
267/* Returns 0 for success, 1 for failure. */
268/* */
269/* RESTRICTIONS/LIMITATIONS: */
270/* */
271/*********************************************************************/
272int flash_erase (flash_info_t *info, int s_first, int s_last)
273{
274 vu_long *addr = (vu_long*)(info->start[0]);
275 int flag, prot, sect, l_sect;
276 ulong start, now, last;
277
278 if ((s_first < 0) || (s_first > s_last)) {
279 if (info->flash_id == FLASH_UNKNOWN) {
280 printf ("- missing\n");
281 } else {
282 printf ("- no sectors to erase\n");
283 }
284 return 1;
285 }
286
287 prot = 0;
288 for (sect = s_first; sect <= s_last; sect++) {
289 if (info->protect[sect]) {
290 prot++;
291 }
292 }
293
294 if (prot) {
295 printf ("- Warning: %d protected sectors will not be erased!\n",
296 prot);
297 } else {
298 printf ("\n");
299 }
300
301 l_sect = -1;
302
303 /* Disable interrupts which might cause a timeout here */
304 flag = disable_interrupts();
305
306 addr[0x0555] = 0xAAAAAAAA;
307 addr[0x02AA] = 0x55555555;
308 addr[0x0555] = 0x80808080;
309 addr[0x0555] = 0xAAAAAAAA;
310 addr[0x02AA] = 0x55555555;
311 udelay (100);
312
313 /* Start erase on unprotected sectors */
314 for (sect = s_first; sect <= s_last; sect++) {
315 if (info->protect[sect] == 0) { /* not protected */
316 addr = (vu_long*)(info->start[sect]);
317 addr[0] = 0x30303030;
318 l_sect = sect;
319 }
320 }
321
322 /* re-enable interrupts if necessary */
323 if (flag)
324 enable_interrupts();
325
326 /* wait at least 80us - let's wait 1 ms */
327 udelay (1000);
328
329 /*
330 * We wait for the last triggered sector
331 */
332 if (l_sect < 0)
333 goto DONE;
334
335 start = get_timer (0);
336 last = start;
337 addr = (vu_long*)(info->start[l_sect]);
338 while ((addr[0] & 0x80808080) != 0x80808080) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200339 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
wdenkafd7f3d2002-11-03 01:41:26 +0000340 printf ("Timeout\n");
341 return 1;
342 }
343 /* show that we're waiting */
344 if ((now - last) > 1000) { /* every second */
345 serial_putc ('.');
346 last = now;
347 }
348 }
349
350 DONE:
351 /* reset to read mode */
352 addr = (volatile unsigned long *)info->start[0];
353 addr[0] = 0xF0F0F0F0; /* reset bank */
354
355 printf (" done\n");
356 return 0;
357}
358
359/*********************************************************************/
360/* NAME: write_buff() - writes a buffer to flash */
361/* */
362/* DESCRIPTION: */
363/* This function copies a buffer, *src, to flash. */
364/* */
365/* INPUTS: */
366/* flash_info_t *info - flash information structure */
367/* uchar *src - pointer to buffer to write to flash */
368/* ulong addr - address to start write at */
369/* ulong cnt - number of bytes to write to flash */
370/* */
371/* OUTPUTS: */
372/* None */
373/* */
374/* RETURNS: */
375/* 0 - OK */
376/* 1 - write timeout */
377/* 2 - Flash not erased */
378/* */
379/* RESTRICTIONS/LIMITATIONS: */
380/* */
381/*********************************************************************/
382int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
383{
384 ulong cp, wp, data;
385 int i, l, rc;
386
387 wp = (addr & ~3); /* get lower word aligned address */
388
389 /*
390 * handle unaligned start bytes
391 */
392 if ((l = addr - wp) != 0) {
393 data = 0;
394 for (i = 0, cp = wp; i < l; ++i, ++cp) {
395 data = (data << 8) | (*(uchar *)cp);
396 }
397 for (; (i < 4) && (cnt > 0); ++i) {
398 data = (data << 8) | *src++;
399 --cnt;
400 ++cp;
401 }
402 for (; (cnt == 0) && (i < 4); ++i, ++cp) {
403 data = (data << 8) | (*(uchar *)cp);
404 }
405
406 if ((rc = write_word(info, wp, data)) != 0) {
407 return (rc);
408 }
409 wp += 4;
410 }
411
412 /*
413 * handle word aligned part
414 */
415 while (cnt >= 4) {
416 data = 0;
417 for (i = 0; i < 4; ++i) {
418 data = (data << 8) | *src++;
419 }
420 if ((rc = write_word(info, wp, data)) != 0) {
421 return (rc);
422 }
423 wp += 4;
424 cnt -= 4;
425 }
426
427 if (cnt == 0) {
428 return (0);
429 }
430
431 /*
432 * handle unaligned tail bytes
433 */
434 data = 0;
435 for (i = 0, cp = wp; (i < 4) && (cnt > 0); ++i, ++cp) {
436 data = (data << 8) | *src++;
437 --cnt;
438 }
439 for (; (i < 4); ++i, ++cp) {
440 data = (data << 8) | (*(uchar *)cp);
441 }
442
443 return (write_word(info, wp, data));
444}
445
446/*********************************************************************/
447/* NAME: write_word() - writes a word to flash */
448/* */
449/* DESCRIPTION: */
450/* This writes a single word to flash. */
451/* */
452/* INPUTS: */
453/* flash_info_t *info - flash information structure */
454/* ulong dest - address to write */
455/* ulong data - data to write */
456/* */
457/* OUTPUTS: */
458/* None */
459/* */
460/* RETURNS: */
461/* 0 - OK */
462/* 1 - write timeout */
463/* 2 - Flash not erased */
464/* */
465/* RESTRICTIONS/LIMITATIONS: */
466/* */
467/*********************************************************************/
468static int write_word (flash_info_t *info, ulong dest, ulong data)
469{
470 vu_long *addr = (vu_long*)(info->start[0]);
471 ulong start;
472 int flag;
473
474 /* Check if Flash is (sufficiently) erased */
475 if ((*((vu_long *)dest) & data) != data) {
476 return (2);
477 }
478 /* Disable interrupts which might cause a timeout here */
479 flag = disable_interrupts();
480
481 addr[0x0555] = 0xAAAAAAAA;
482 addr[0x02AA] = 0x55555555;
483 addr[0x0555] = 0xA0A0A0A0;
484
485 *((vu_long *)dest) = data;
486
487 /* re-enable interrupts if necessary */
488 if (flag)
489 enable_interrupts();
490
491 /* data polling for D7 */
492 start = get_timer (0);
493 while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080)) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200494 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenkafd7f3d2002-11-03 01:41:26 +0000495 return (1);
496 }
497 }
498 return (0);
499}
500/*********************************************************************/
501/* End of flash.c */
502/*********************************************************************/