source: rtems/c/src/lib/libbsp/powerpc/shared/flash/spansionFlash.c @ 2a444594

4.104.114.95
Last change on this file since 2a444594 was 2a444594, checked in by Till Straumann <strauman@…>, on Nov 27, 2007 at 8:36:22 PM

2007-11-29 Till Straumann <strauman@…>

  • Makefile.am, shared/flash, shared/flash/flash.c, shared/flash/flashPgm.h, shared/flash/flashPgmPvt.h, shared/flash/intelFlash.c, shared/flash/spansionFlash.c: Added flash programmer API, implementation and chip drivers for some intel + spansion flash chips (as found on mvme5500, mvme6100 and mvme3100 boards). A more appopriate place would probably be libchip but I don't know if the API is acceptable and if the implementation is generic enough (e.g., no CFI support) so I leave it here for now.
  • Property mode set to 100644
File size: 11.3 KB
Line 
1/* $Id$ */
2
3/*
4 * Trivial driver for spansion flash present on the
5 * MVME3100 board.
6 *
7 * For recognized devices, look for 'spansionDevs'.
8 *
9 * This driver has only been tested with stride=4
10 * and in 16-bit mode (width=2).
11 */
12
13/*
14 * Authorship
15 * ----------
16 * This software was created by
17 *     Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
18 *         Stanford Linear Accelerator Center, Stanford University.
19 *
20 * Acknowledgement of sponsorship
21 * ------------------------------
22 * The software was produced by
23 *     the Stanford Linear Accelerator Center, Stanford University,
24 *         under Contract DE-AC03-76SFO0515 with the Department of Energy.
25 *
26 * Government disclaimer of liability
27 * ----------------------------------
28 * Neither the United States nor the United States Department of Energy,
29 * nor any of their employees, makes any warranty, express or implied, or
30 * assumes any legal liability or responsibility for the accuracy,
31 * completeness, or usefulness of any data, apparatus, product, or process
32 * disclosed, or represents that its use would not infringe privately owned
33 * rights.
34 *
35 * Stanford disclaimer of liability
36 * --------------------------------
37 * Stanford University makes no representations or warranties, express or
38 * implied, nor assumes any liability for the use of this software.
39 *
40 * Stanford disclaimer of copyright
41 * --------------------------------
42 * Stanford University, owner of the copyright, hereby disclaims its
43 * copyright and all other rights in this software.  Hence, anyone may
44 * freely use it for any purpose without restriction. 
45 *
46 * Maintenance of notices
47 * ----------------------
48 * In the interest of clarity regarding the origin and status of this
49 * SLAC software, this and all the preceding Stanford University notices
50 * are to remain affixed to any copy or derivative of this software made
51 * or distributed by the recipient and are to be affixed to any copy of
52 * software made or distributed by the recipient that contains a copy or
53 * derivative of this software.
54 *
55 * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
56 */ 
57
58#include <rtems.h>
59#include <stdio.h>
60#include <inttypes.h>
61
62#include <bsp/flashPgmPvt.h>
63
64#define DEBUG                   5
65#undef  DEBUG
66
67#ifdef DEBUG
68#define STATIC
69#else
70#define STATIC          static
71#endif
72
73/* Manual says max erase time is 3.5 s */
74#define ERASE_TIMEOUT   4        /* seconds */
75#define WRITE_TIMEOUT   1000 /* us; manual says: 240us typ. */
76
77/* Assume flash-endianness == CPU endianness */
78
79#ifdef __PPC__
80#define IOSYNC(mem)     do { asm volatile("eieio":"=m"(mem):"m"(mem)); } while (0)
81#else
82#define IOSYNC(mem)     do { } while (0)
83#endif
84
85/********* Forward Declarations ****************/
86
87STATIC int
88flash_get_id_s160(struct bankdesc *, uint32_t , uint32_t *, uint32_t *);
89
90STATIC void
91flash_unlock_block_s160(struct bankdesc *, uint32_t);
92
93STATIC void
94flash_lock_block_s160(struct bankdesc *, uint32_t);
95
96STATIC int
97flash_erase_block_s160(struct bankdesc *, uint32_t);
98
99STATIC uint32_t
100flash_check_ready_s160(struct bankdesc *, uint32_t);
101
102STATIC void
103flash_print_stat_s160(struct bankdesc *, uint32_t, int);
104
105STATIC void
106flash_array_mode_s160(struct bankdesc *, uint32_t);
107
108STATIC uint32_t
109flash_write_line_s160(struct bankdesc *, uint32_t, char *, uint32_t);
110
111/********* Global Variables ********************/
112
113static struct flash_bank_ops spansionOps = {
114        get_id      : flash_get_id_s160,
115        unlock_block: flash_unlock_block_s160,
116        lock_block  : flash_lock_block_s160,
117        erase_block : flash_erase_block_s160,
118        check_ready : flash_check_ready_s160,
119        print_stat  : flash_print_stat_s160,
120        array_mode  : flash_array_mode_s160,
121        write_line  : flash_write_line_s160,
122};
123
124static struct devdesc spansionDevs[] = {
125        { 0x007e2101, "S29GL128N", 0x01000000, 32, 0x20000 }, /* 16MB */
126        { 0x007e2201, "S29GL256N", 0x02000000, 32, 0x20000 }, /* 32MB */
127        { 0x007e2301, "S29GL512N", 0x04000000, 32, 0x20000 }, /* 64MB */
128        { 0, 0, 0, 0}
129};
130
131struct vendesc BSP_flash_vendor_spansion[] = {
132        { 0x01, "Spansion/AMD", spansionDevs, &spansionOps },
133        { 0, 0}
134};
135
136/********* Register Definitions ****************/
137
138#define UNLK1_ADDR_16      0x555
139#define UNLK1_DATA         0xaa
140#define UNLK2_ADDR_16      0x2aa
141#define UNLK2_ADDR_8       0x555
142#define UNLK2_DATA         0x55
143#define ASEL_DATA          0x90
144#define VEND_ID_ADDR_16    0x000
145#define SPROT_ADDR_16      0x002
146#define DEV1_ID_ADDR_16    0x001
147#define DEV2_ID_ADDR_16    0x00e
148#define DEV3_ID_ADDR_16    0x00f
149#define ERASE_DATA         0x80
150#define SECT_ERASE_DATA    0x30
151#define DQ7_DATA           0x80
152#define RESET_DATA         0xf0
153#define WRBUF_DATA         0x25
154#define PGBUF_DATA         0x29
155
156#define DQ7_POLL_ALL       (-1)
157
158/********* Helper Types ************************/
159
160union bconv {
161        uint32_t        u;
162        uint16_t        s[2];
163        char            c[4];
164};
165
166/********* Register Access Primitives **********/
167
168/* All of these currently assume stride == 4, i.e.
169 * two 16-bit devices or 4 8-bit devices in parallel.
170 *
171 * FIXME:
172 *   8-bit mode and strides 1,2 untested.
173 */
174
175#define ADDR32(b, a, o)   ((a) + ((o)*FLASH_STRIDE(b)))
176
177static inline uint32_t
178fl_rd32(struct bankdesc *b, uint32_t a, uint32_t off)
179{
180volatile union bconv *p;
181uint32_t              rval;
182
183        if ( 1 == b->width )
184                off <<= 1;;
185
186        a = ADDR32(b, a, off);
187
188        p    = (volatile union bconv *)a;
189        if ( 4 == FLASH_STRIDE(b) ) {
190                rval = p->u;
191                IOSYNC(p->u);
192        } else if ( 2 == FLASH_STRIDE(b) ) {
193                rval = p->s[0];
194                IOSYNC(p->s[0]);
195        } else {
196                rval = p->c[0];
197                IOSYNC(p->c[0]);
198        }
199        return rval;
200}
201
202static inline void
203fl_wr32(struct bankdesc *b, uint32_t a, uint32_t v)
204{
205volatile union bconv *p = (volatile union bconv*)a;
206        if ( 4 == FLASH_STRIDE(b) ) {
207                p->u    = v;
208                IOSYNC(p->u);
209        } else if ( 2 == FLASH_STRIDE(b) ) {
210                p->s[0] = v;
211                IOSYNC(p->s[0]);
212        } else {
213                p->c[0] = v;
214                IOSYNC(p->c[0]);
215        }
216}
217
218static inline uint32_t
219fl_splat32(struct bankdesc *b, uint32_t x)
220{
221        if ( 4 == FLASH_STRIDE(b) ) {
222                if ( 1 == b->width ) {
223                        x = (x << 8) | x;
224                }
225                x = (x<<16) | x;
226        } else if ( 2 == FLASH_STRIDE(b) ) {
227                if ( 1 == b->width )
228                        x = (x << 8) | x;
229        }
230        return x;
231}
232
233static inline uint32_t
234fl_x32(struct bankdesc *b, union bconv *pv)
235{
236        if ( 4 == FLASH_STRIDE(b) )
237                return pv->u;
238        else if ( 2 == FLASH_STRIDE(b) )
239                return pv->s[0];
240        else
241                return pv->c[0];
242}
243
244static inline void
245fl_wr32_cmd(struct bankdesc *b, uint32_t a, uint32_t off, uint32_t cmd)
246{
247        if ( 1 == b->width ) {
248                if ( off == UNLK2_ADDR_16 )
249                        off = UNLK2_ADDR_8;
250                else
251                        /* all others are simply left shifted */
252                        off <<= 1;
253        }
254        cmd = fl_splat32(b, cmd);
255        a   = ADDR32(b, a, off);
256        fl_wr32(b, a, cmd);
257}
258
259/* Send unlock sequence */
260static inline void unlk(struct bankdesc *b, uint32_t a)
261{
262        a &= ~ ( ADDR32(b, 0,0x1000) - 1 );
263        fl_wr32_cmd(b, a, UNLK1_ADDR_16, UNLK1_DATA);
264        fl_wr32_cmd(b, a, UNLK2_ADDR_16, UNLK2_DATA);
265}
266
267/********* Helper Routines *********************/
268
269STATIC int
270sector_is_protected(struct bankdesc *b, uint32_t addr)
271{
272int rval;
273        unlk(b, addr);
274        fl_wr32_cmd(b, addr, UNLK1_ADDR_16, ASEL_DATA);
275        rval = fl_rd32(b, addr, SPROT_ADDR_16);
276        flash_array_mode_s160(b, addr);
277        return rval;
278}
279
280STATIC int fl_dq7_poll(struct bankdesc *b, uint32_t addr, uint32_t d7_val)
281{
282        d7_val &= fl_splat32(b, DQ7_DATA);
283        return ( (fl_rd32(b, addr, 0) & fl_splat32(b, DQ7_DATA)) == d7_val );
284}
285
286/* Do DQ7 polling until DQ7 reads the value passed in d7_val
287 * or timeout
288 */
289STATIC int
290flash_pend(struct bankdesc *b, uint32_t addr, uint32_t timeout_us, uint32_t d7_val)
291{
292uint32_t then = BSP_flashBspOps.read_us_timer();
293uint32_t now  = then;
294
295        do {
296                if ( fl_dq7_poll(b, addr, d7_val) ) {
297#if (DEBUG > 4)
298                        printf("Write buffer succeded after %"PRIi32"us\n", (now-then)*8/333);
299#endif
300                        return 0;
301                }
302                now = BSP_flashBspOps.read_us_timer();
303        } while ( now - then < timeout_us );
304
305        return -1;
306}
307
308
309/********* Access Methods **********************/
310
311STATIC void
312flash_array_mode_s160(struct bankdesc *b, uint32_t addr)
313{
314        fl_wr32_cmd(b, addr, 0, RESET_DATA);
315}
316
317STATIC int
318flash_get_id_s160(struct bankdesc *b, uint32_t addr, uint32_t *pVendorId, uint32_t *pDeviceId)
319{
320uint32_t dev_id[3], x, i;
321
322        if ( 4 != FLASH_STRIDE(b) )
323                fprintf(stderr,"Warning: strides other than 4 untested\n(%s at %d)\n",
324                        __FILE__,__LINE__);
325
326        if ( 2 != b->width )
327                fprintf(stderr,"Warning: device width other than 2 untested\n(%s at %d)\n",
328                        __FILE__,__LINE__);
329
330        addr &= ~ (ADDR32(b, 0, 0x1000) - 1);
331        unlk(b, addr);
332        fl_wr32_cmd(b, addr, UNLK1_ADDR_16, ASEL_DATA);
333        *pVendorId = fl_rd32(b, addr, VEND_ID_ADDR_16) & 0xff;
334        dev_id [0] = fl_rd32(b, addr, DEV1_ID_ADDR_16);
335        dev_id [1] = fl_rd32(b, addr, DEV2_ID_ADDR_16);
336        dev_id [2] = fl_rd32(b, addr, DEV3_ID_ADDR_16);
337
338#ifdef DEBUG
339        printf("Vendor Id 0x%08"PRIx32", Dev Ids: 0x%08"PRIx32", 0x%08"PRIx32", 0x%08"PRIx32"\n",
340                *pVendorId, dev_id[0], dev_id[1], dev_id[2]);
341#endif
342
343        flash_array_mode_s160(b, addr);
344
345        for ( x=0, i=0; i<3; i++ ) {
346                x = (x<<8) | (dev_id[i] & 0xff);
347        }
348
349        *pDeviceId = x;
350
351        return 0;
352}
353
354
355STATIC void
356flash_lock_block_s160(struct bankdesc *b, uint32_t addr)
357{
358}
359
360STATIC void
361flash_unlock_block_s160(struct bankdesc *b, uint32_t addr)
362{
363}
364
365STATIC uint32_t
366flash_check_ready_s160(struct bankdesc *b, uint32_t addr)
367{
368        flash_array_mode_s160(b, addr);
369        return 0;
370}
371
372/* Erase single block holding 'addr'ess
373 *
374 * RETURNS: zero on error, device status on failure.
375 *
376 *   NOTES: - device switched back to array mode on exit.
377 *          - 'addr' must be 32-bit aligned.
378 */
379STATIC int
380flash_erase_block_s160(struct bankdesc *b, uint32_t addr)
381{
382rtems_interval p,i;
383
384        addr &= ~ (b->fblksz-1);
385
386        if ( sector_is_protected(b, addr) ) {
387                fprintf(stderr,"Sector at 0x%08"PRIx32" is protected\n", addr);
388                return -10;
389        }
390
391        unlk(b, addr);
392        fl_wr32_cmd(b, addr, UNLK1_ADDR_16, ERASE_DATA);
393        unlk(b, addr);
394        fl_wr32_cmd(b, addr, 0, SECT_ERASE_DATA);
395
396        rtems_clock_get( RTEMS_CLOCK_GET_TICKS_PER_SECOND, &p );
397        p *= ERASE_TIMEOUT;
398
399        for ( i=p; i; i-- ) {
400                rtems_task_wake_after(1);
401                if ( fl_dq7_poll(b, addr, DQ7_POLL_ALL) ) {
402                        break;
403                }
404        }
405#ifdef DEBUG
406        printf("ERASE polled for %"PRIi32" ticks\n", p-i);
407#endif
408        flash_array_mode_s160(b, addr);
409
410        if ( i ) {
411                /* write successful; verify */
412                for ( i = 0; i < b->fblksz; i++ ) {
413                        if ( 0xff != ((char*)addr)[i] ) {
414                                fprintf(stderr,"ERROR: Erase verification failed at %p\n",
415                                        ((char*)addr) + i);
416                                return -1;
417                        }
418                }
419                return 0;
420        }
421        return -1;
422}
423       
424STATIC void
425flash_print_stat_s160(struct bankdesc *b, uint32_t sta, int verbose)
426{
427        fprintf(stderr,"Flash Spansion 160 error %"PRIi32"\n", sta);
428}
429       
430STATIC uint32_t
431flash_write_line_s160(struct bankdesc *b, uint32_t a, char *s, uint32_t N)
432{
433uint32_t        sta, nxt, j, v;
434union    bconv  buf; 
435
436        if ( 0 == N )
437                return -11;
438
439        if ( N & (FLASH_STRIDE(b) - 1) ) {
440                fprintf(stderr,"flash_write_line_s160: invalid byte count (not multiple of stride\n");
441                return -10;
442        }
443
444        unlk(b, a);
445
446        /* address block */
447        fl_wr32_cmd(b, a, 0, WRBUF_DATA);
448
449        /* (16-bit) word count per device */
450        N /= FLASH_STRIDE(b);
451
452        fl_wr32_cmd(b, a, 0, N-1);
453
454        /* silence compiler warning about uninitialized var (N > 0 at this point) */
455        v = 0;
456
457        /* fill buffer */
458        for (nxt = a; N>0; N--) {
459#if (DEBUG > 4)
460                printf("Writing DAT *0x%08"PRIx32" = 0x%08"PRIx32"\n", nxt, *(uint32_t*)s);
461#endif
462                /* deal with misaligned sources */
463                for ( j=0; j<FLASH_STRIDE(b); j++ ) {
464                        buf.c[j] = *s++;
465                }
466                v = fl_x32(b, &buf);
467                fl_wr32(b, nxt, v);
468                nxt += FLASH_STRIDE(b);
469        }
470
471        /* burn buffer */
472        fl_wr32_cmd(b, a, 0, PGBUF_DATA);
473
474        /* pend */
475
476        sta = flash_pend(b, nxt - FLASH_STRIDE(b), WRITE_TIMEOUT, v);
477
478        return sta;
479}
Note: See TracBrowser for help on using the repository browser.