~ubuntu-branches/ubuntu/maverick/u-boot-omap3/maverick

« back to all changes in this revision

Viewing changes to board/lubbock/flash.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2010-03-22 15:06:23 UTC
  • Revision ID: james.westby@ubuntu.com-20100322150623-i21g8rgiyl5dohag
Tags: upstream-2010.3git20100315
ImportĀ upstreamĀ versionĀ 2010.3git20100315

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * (C) Copyright 2001
 
3
 * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
 
4
 *
 
5
 * (C) Copyright 2001
 
6
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 
7
 *
 
8
 * See file CREDITS for list of people who contributed to this
 
9
 * project.
 
10
 *
 
11
 * This program is free software; you can redistribute it and/or
 
12
 * modify it under the terms of the GNU General Public License as
 
13
 * published by the Free Software Foundation; either version 2 of
 
14
 * the License, or (at your option) any later version.
 
15
 *
 
16
 * This program is distributed in the hope that it will be useful,
 
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
 * GNU General Public License for more details.
 
20
 *
 
21
 * You should have received a copy of the GNU General Public License
 
22
 * along with this program; if not, write to the Free Software
 
23
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 
24
 * MA 02111-1307 USA
 
25
 */
 
26
 
 
27
#include <common.h>
 
28
#include <linux/byteorder/swab.h>
 
29
 
 
30
 
 
31
flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];    /* info for FLASH chips    */
 
32
 
 
33
/* Board support for 1 or 2 flash devices */
 
34
#define FLASH_PORT_WIDTH32
 
35
#undef FLASH_PORT_WIDTH16
 
36
 
 
37
#ifdef FLASH_PORT_WIDTH16
 
38
#define FLASH_PORT_WIDTH                ushort
 
39
#define FLASH_PORT_WIDTHV               vu_short
 
40
#define SWAP(x)               __swab16(x)
 
41
#else
 
42
#define FLASH_PORT_WIDTH                ulong
 
43
#define FLASH_PORT_WIDTHV               vu_long
 
44
#define SWAP(x)               __swab32(x)
 
45
#endif
 
46
 
 
47
#define FPW        FLASH_PORT_WIDTH
 
48
#define FPWV   FLASH_PORT_WIDTHV
 
49
 
 
50
#define mb() __asm__ __volatile__ ("" : : : "memory")
 
51
 
 
52
/*-----------------------------------------------------------------------
 
53
 * Functions
 
54
 */
 
55
static ulong flash_get_size (FPW *addr, flash_info_t *info);
 
56
static int write_data (flash_info_t *info, ulong dest, FPW data);
 
57
static void flash_get_offsets (ulong base, flash_info_t *info);
 
58
void inline spin_wheel (void);
 
59
 
 
60
/*-----------------------------------------------------------------------
 
61
 */
 
62
 
 
63
unsigned long flash_init (void)
 
64
{
 
65
        int i;
 
66
        ulong size = 0;
 
67
 
 
68
        for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
 
69
                switch (i) {
 
70
                case 0:
 
71
                        flash_get_size ((FPW *) PHYS_FLASH_1, &flash_info[i]);
 
72
                        flash_get_offsets (PHYS_FLASH_1, &flash_info[i]);
 
73
                        break;
 
74
                case 1:
 
75
                        flash_get_size ((FPW *) PHYS_FLASH_2, &flash_info[i]);
 
76
                        flash_get_offsets (PHYS_FLASH_2, &flash_info[i]);
 
77
                        break;
 
78
                default:
 
79
                        panic ("configured too many flash banks!\n");
 
80
                        break;
 
81
                }
 
82
                size += flash_info[i].size;
 
83
        }
 
84
 
 
85
        /* Protect monitor and environment sectors
 
86
         */
 
87
        flash_protect ( FLAG_PROTECT_SET,
 
88
                        CONFIG_SYS_FLASH_BASE,
 
89
                        CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1,
 
90
                        &flash_info[0] );
 
91
 
 
92
        flash_protect ( FLAG_PROTECT_SET,
 
93
                        CONFIG_ENV_ADDR,
 
94
                        CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0] );
 
95
 
 
96
        return size;
 
97
}
 
98
 
 
99
/*-----------------------------------------------------------------------
 
100
 */
 
101
static void flash_get_offsets (ulong base, flash_info_t *info)
 
102
{
 
103
        int i;
 
104
 
 
105
        if (info->flash_id == FLASH_UNKNOWN) {
 
106
                return;
 
107
        }
 
108
 
 
109
        if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
 
110
                for (i = 0; i < info->sector_count; i++) {
 
111
                        info->start[i] = base + (i * PHYS_FLASH_SECT_SIZE);
 
112
                        info->protect[i] = 0;
 
113
                }
 
114
        }
 
115
}
 
116
 
 
117
/*-----------------------------------------------------------------------
 
118
 */
 
119
void flash_print_info (flash_info_t *info)
 
120
{
 
121
        int i;
 
122
 
 
123
        if (info->flash_id == FLASH_UNKNOWN) {
 
124
                printf ("missing or unknown FLASH type\n");
 
125
                return;
 
126
        }
 
127
 
 
128
        switch (info->flash_id & FLASH_VENDMASK) {
 
129
        case FLASH_MAN_INTEL:
 
130
                printf ("INTEL ");
 
131
                break;
 
132
        default:
 
133
                printf ("Unknown Vendor ");
 
134
                break;
 
135
        }
 
136
 
 
137
        switch (info->flash_id & FLASH_TYPEMASK) {
 
138
        case FLASH_28F128J3A:
 
139
                printf ("28F128J3A\n");
 
140
                break;
 
141
        default:
 
142
                printf ("Unknown Chip Type\n");
 
143
                break;
 
144
        }
 
145
 
 
146
        printf ("  Size: %ld MB in %d Sectors\n",
 
147
                        info->size >> 20, info->sector_count);
 
148
 
 
149
        printf ("  Sector Start Addresses:");
 
150
        for (i = 0; i < info->sector_count; ++i) {
 
151
                if ((i % 5) == 0)
 
152
                        printf ("\n   ");
 
153
                printf (" %08lX%s",
 
154
                        info->start[i],
 
155
                        info->protect[i] ? " (RO)" : "     ");
 
156
        }
 
157
        printf ("\n");
 
158
        return;
 
159
}
 
160
 
 
161
/*
 
162
 * The following code cannot be run from FLASH!
 
163
 */
 
164
static ulong flash_get_size (FPW *addr, flash_info_t *info)
 
165
{
 
166
        volatile FPW value;
 
167
 
 
168
        /* Write auto select command: read Manufacturer ID */
 
169
        addr[0x5555] = (FPW) 0x00AA00AA;
 
170
        addr[0x2AAA] = (FPW) 0x00550055;
 
171
        addr[0x5555] = (FPW) 0x00900090;
 
172
 
 
173
        mb ();
 
174
        value = addr[0];
 
175
 
 
176
        switch (value) {
 
177
 
 
178
        case (FPW) INTEL_MANUFACT:
 
179
                info->flash_id = FLASH_MAN_INTEL;
 
180
                break;
 
181
 
 
182
        default:
 
183
                info->flash_id = FLASH_UNKNOWN;
 
184
                info->sector_count = 0;
 
185
                info->size = 0;
 
186
                addr[0] = (FPW) 0x00FF00FF;     /* restore read mode */
 
187
                return (0);                     /* no or unknown flash  */
 
188
        }
 
189
 
 
190
        mb ();
 
191
        value = addr[1];                        /* device ID        */
 
192
 
 
193
        switch (value) {
 
194
 
 
195
        case (FPW) INTEL_ID_28F128J3A:
 
196
                info->flash_id += FLASH_28F128J3A;
 
197
                info->sector_count = 128;
 
198
                info->size = 0x02000000;
 
199
                break;                          /* => 16 MB     */
 
200
 
 
201
        default:
 
202
                info->flash_id = FLASH_UNKNOWN;
 
203
                break;
 
204
        }
 
205
 
 
206
        if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) {
 
207
                printf ("** ERROR: sector count %d > max (%d) **\n",
 
208
                        info->sector_count, CONFIG_SYS_MAX_FLASH_SECT);
 
209
                info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
 
210
        }
 
211
 
 
212
        addr[0] = (FPW) 0x00FF00FF;             /* restore read mode */
 
213
 
 
214
        return (info->size);
 
215
}
 
216
 
 
217
 
 
218
/*-----------------------------------------------------------------------
 
219
 */
 
220
 
 
221
int flash_erase (flash_info_t *info, int s_first, int s_last)
 
222
{
 
223
        int flag, prot, sect;
 
224
        ulong type, start, last;
 
225
        int rcode = 0;
 
226
 
 
227
        if ((s_first < 0) || (s_first > s_last)) {
 
228
                if (info->flash_id == FLASH_UNKNOWN) {
 
229
                        printf ("- missing\n");
 
230
                } else {
 
231
                        printf ("- no sectors to erase\n");
 
232
                }
 
233
                return 1;
 
234
        }
 
235
 
 
236
        type = (info->flash_id & FLASH_VENDMASK);
 
237
        if ((type != FLASH_MAN_INTEL)) {
 
238
                printf ("Can't erase unknown flash type %08lx - aborted\n",
 
239
                        info->flash_id);
 
240
                return 1;
 
241
        }
 
242
 
 
243
        prot = 0;
 
244
        for (sect = s_first; sect <= s_last; ++sect) {
 
245
                if (info->protect[sect]) {
 
246
                        prot++;
 
247
                }
 
248
        }
 
249
 
 
250
        if (prot) {
 
251
                printf ("- Warning: %d protected sectors will not be erased!\n",
 
252
                        prot);
 
253
        } else {
 
254
                printf ("\n");
 
255
        }
 
256
 
 
257
        start = get_timer (0);
 
258
        last = start;
 
259
 
 
260
        /* Disable interrupts which might cause a timeout here */
 
261
        flag = disable_interrupts ();
 
262
 
 
263
        /* Start erase on unprotected sectors */
 
264
        for (sect = s_first; sect <= s_last; sect++) {
 
265
                if (info->protect[sect] == 0) { /* not protected */
 
266
                        FPWV *addr = (FPWV *) (info->start[sect]);
 
267
                        FPW status;
 
268
 
 
269
                        printf ("Erasing sector %2d ... ", sect);
 
270
 
 
271
                        /* arm simple, non interrupt dependent timer */
 
272
                        reset_timer_masked ();
 
273
 
 
274
                        *addr = (FPW) 0x00500050;       /* clear status register */
 
275
                        *addr = (FPW) 0x00200020;       /* erase setup */
 
276
                        *addr = (FPW) 0x00D000D0;       /* erase confirm */
 
277
 
 
278
                        while (((status = *addr) & (FPW) 0x00800080) != (FPW) 0x00800080) {
 
279
                                if (get_timer_masked () > CONFIG_SYS_FLASH_ERASE_TOUT) {
 
280
                                        printf ("Timeout\n");
 
281
                                        *addr = (FPW) 0x00B000B0;       /* suspend erase     */
 
282
                                        *addr = (FPW) 0x00FF00FF;       /* reset to read mode */
 
283
                                        rcode = 1;
 
284
                                        break;
 
285
                                }
 
286
                        }
 
287
 
 
288
                        *addr = 0x00500050;     /* clear status register cmd.   */
 
289
                        *addr = 0x00FF00FF;     /* resest to read mode          */
 
290
 
 
291
                        printf (" done\n");
 
292
                }
 
293
        }
 
294
        return rcode;
 
295
}
 
296
 
 
297
/*-----------------------------------------------------------------------
 
298
 * Copy memory to flash, returns:
 
299
 * 0 - OK
 
300
 * 1 - write timeout
 
301
 * 2 - Flash not erased
 
302
 * 4 - Flash not identified
 
303
 */
 
304
 
 
305
int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
 
306
{
 
307
        ulong cp, wp;
 
308
        FPW data;
 
309
        int count, i, l, rc, port_width;
 
310
 
 
311
        if (info->flash_id == FLASH_UNKNOWN) {
 
312
                return 4;
 
313
        }
 
314
/* get lower word aligned address */
 
315
#ifdef FLASH_PORT_WIDTH16
 
316
        wp = (addr & ~1);
 
317
        port_width = 2;
 
318
#else
 
319
        wp = (addr & ~3);
 
320
        port_width = 4;
 
321
#endif
 
322
 
 
323
        /*
 
324
         * handle unaligned start bytes
 
325
         */
 
326
        if ((l = addr - wp) != 0) {
 
327
                data = 0;
 
328
                for (i = 0, cp = wp; i < l; ++i, ++cp) {
 
329
                        data = (data << 8) | (*(uchar *) cp);
 
330
                }
 
331
                for (; i < port_width && cnt > 0; ++i) {
 
332
                        data = (data << 8) | *src++;
 
333
                        --cnt;
 
334
                        ++cp;
 
335
                }
 
336
                for (; cnt == 0 && i < port_width; ++i, ++cp) {
 
337
                        data = (data << 8) | (*(uchar *) cp);
 
338
                }
 
339
 
 
340
                if ((rc = write_data (info, wp, SWAP (data))) != 0) {
 
341
                        return (rc);
 
342
                }
 
343
                wp += port_width;
 
344
        }
 
345
 
 
346
        /*
 
347
         * handle word aligned part
 
348
         */
 
349
        count = 0;
 
350
        while (cnt >= port_width) {
 
351
                data = 0;
 
352
                for (i = 0; i < port_width; ++i) {
 
353
                        data = (data << 8) | *src++;
 
354
                }
 
355
                if ((rc = write_data (info, wp, SWAP (data))) != 0) {
 
356
                        return (rc);
 
357
                }
 
358
                wp += port_width;
 
359
                cnt -= port_width;
 
360
                if (count++ > 0x800) {
 
361
                        spin_wheel ();
 
362
                        count = 0;
 
363
                }
 
364
        }
 
365
 
 
366
        if (cnt == 0) {
 
367
                return (0);
 
368
        }
 
369
 
 
370
        /*
 
371
         * handle unaligned tail bytes
 
372
         */
 
373
        data = 0;
 
374
        for (i = 0, cp = wp; i < port_width && cnt > 0; ++i, ++cp) {
 
375
                data = (data << 8) | *src++;
 
376
                --cnt;
 
377
        }
 
378
        for (; i < port_width; ++i, ++cp) {
 
379
                data = (data << 8) | (*(uchar *) cp);
 
380
        }
 
381
 
 
382
        return (write_data (info, wp, SWAP (data)));
 
383
}
 
384
 
 
385
/*-----------------------------------------------------------------------
 
386
 * Write a word or halfword to Flash, returns:
 
387
 * 0 - OK
 
388
 * 1 - write timeout
 
389
 * 2 - Flash not erased
 
390
 */
 
391
static int write_data (flash_info_t *info, ulong dest, FPW data)
 
392
{
 
393
        FPWV *addr = (FPWV *) dest;
 
394
        ulong status;
 
395
        int flag;
 
396
 
 
397
        /* Check if Flash is (sufficiently) erased */
 
398
        if ((*addr & data) != data) {
 
399
                printf ("not erased at %08lx (%lx)\n", (ulong) addr, *addr);
 
400
                return (2);
 
401
        }
 
402
        /* Disable interrupts which might cause a timeout here */
 
403
        flag = disable_interrupts ();
 
404
 
 
405
        *addr = (FPW) 0x00400040;       /* write setup */
 
406
        *addr = data;
 
407
 
 
408
        /* arm simple, non interrupt dependent timer */
 
409
        reset_timer_masked ();
 
410
 
 
411
        /* wait while polling the status register */
 
412
        while (((status = *addr) & (FPW) 0x00800080) != (FPW) 0x00800080) {
 
413
                if (get_timer_masked () > CONFIG_SYS_FLASH_WRITE_TOUT) {
 
414
                        *addr = (FPW) 0x00FF00FF;       /* restore read mode */
 
415
                        return (1);
 
416
                }
 
417
        }
 
418
 
 
419
        *addr = (FPW) 0x00FF00FF;       /* restore read mode */
 
420
 
 
421
        return (0);
 
422
}
 
423
 
 
424
void inline spin_wheel (void)
 
425
{
 
426
        static int p = 0;
 
427
        static char w[] = "\\/-";
 
428
 
 
429
        printf ("\010%c", w[p]);
 
430
        (++p == 3) ? (p = 0) : 0;
 
431
}