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

4.115
Last change on this file since a7775cb was 721fe34, checked in by Joel Sherrill <joel.sherrill@…>, on 05/31/12 at 20:34:36

Fix C files which had two semi-colons at EOL

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