Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:58

0001 /*
0002  * Trivial driver for spansion flash present on the
0003  * MVME3100 board.
0004  *
0005  * For recognized devices, look for 'spansionDevs'.
0006  *
0007  * This driver has only been tested with stride=4
0008  * and in 16-bit mode (width=2).
0009  */
0010 
0011 /*
0012  * Authorship
0013  * ----------
0014  * This software was created by
0015  *     Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
0016  *     Stanford Linear Accelerator Center, Stanford University.
0017  *
0018  * Acknowledgement of sponsorship
0019  * ------------------------------
0020  * The software was produced by
0021  *     the Stanford Linear Accelerator Center, Stanford University,
0022  *     under Contract DE-AC03-76SFO0515 with the Department of Energy.
0023  *
0024  * Government disclaimer of liability
0025  * ----------------------------------
0026  * Neither the United States nor the United States Department of Energy,
0027  * nor any of their employees, makes any warranty, express or implied, or
0028  * assumes any legal liability or responsibility for the accuracy,
0029  * completeness, or usefulness of any data, apparatus, product, or process
0030  * disclosed, or represents that its use would not infringe privately owned
0031  * rights.
0032  *
0033  * Stanford disclaimer of liability
0034  * --------------------------------
0035  * Stanford University makes no representations or warranties, express or
0036  * implied, nor assumes any liability for the use of this software.
0037  *
0038  * Stanford disclaimer of copyright
0039  * --------------------------------
0040  * Stanford University, owner of the copyright, hereby disclaims its
0041  * copyright and all other rights in this software.  Hence, anyone may
0042  * freely use it for any purpose without restriction.
0043  *
0044  * Maintenance of notices
0045  * ----------------------
0046  * In the interest of clarity regarding the origin and status of this
0047  * SLAC software, this and all the preceding Stanford University notices
0048  * are to remain affixed to any copy or derivative of this software made
0049  * or distributed by the recipient and are to be affixed to any copy of
0050  * software made or distributed by the recipient that contains a copy or
0051  * derivative of this software.
0052  *
0053  * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
0054  */
0055 
0056 #include <rtems.h>
0057 #include <stdio.h>
0058 #include <inttypes.h>
0059 
0060 #include <bsp/flashPgmPvt.h>
0061 
0062 #define DEBUG           5
0063 #undef  DEBUG
0064 
0065 #ifdef DEBUG
0066 #define STATIC
0067 #else
0068 #define STATIC          static
0069 #endif
0070 
0071 /* Manual says max erase time is 3.5 s */
0072 #define ERASE_TIMEOUT   4    /* seconds */
0073 #define WRITE_TIMEOUT   1000 /* us; manual says: 240us typ. */
0074 
0075 /* Assume flash-endianness == CPU endianness */
0076 
0077 #ifdef __PPC__
0078 #define IOSYNC(mem) do { __asm__ volatile("eieio"); } while (0)
0079 #else
0080 #define IOSYNC(mem) do { } while (0)
0081 #endif
0082 
0083 /********* Forward Declarations ****************/
0084 
0085 STATIC int
0086 flash_get_id_s160(struct bankdesc *, uint32_t , uint32_t *, uint32_t *);
0087 
0088 STATIC void
0089 flash_unlock_block_s160(struct bankdesc *, uint32_t);
0090 
0091 STATIC void
0092 flash_lock_block_s160(struct bankdesc *, uint32_t);
0093 
0094 STATIC int
0095 flash_erase_block_s160(struct bankdesc *, uint32_t);
0096 
0097 STATIC uint32_t
0098 flash_check_ready_s160(struct bankdesc *, uint32_t);
0099 
0100 STATIC void
0101 flash_print_stat_s160(struct bankdesc *, uint32_t, int);
0102 
0103 STATIC void
0104 flash_array_mode_s160(struct bankdesc *, uint32_t);
0105 
0106 STATIC uint32_t
0107 flash_write_line_s160(struct bankdesc *, uint32_t, const char *, uint32_t);
0108 
0109 /********* Global Variables ********************/
0110 
0111 static struct flash_bank_ops spansionOps = {
0112     get_id      : flash_get_id_s160,
0113     unlock_block: flash_unlock_block_s160,
0114     lock_block  : flash_lock_block_s160,
0115     erase_block : flash_erase_block_s160,
0116     check_ready : flash_check_ready_s160,
0117     print_stat  : flash_print_stat_s160,
0118     array_mode  : flash_array_mode_s160,
0119     write_line  : flash_write_line_s160,
0120 };
0121 
0122 static struct devdesc spansionDevs[] = {
0123     { 0x007e2101, "S29GL128N", 0x01000000, 32, 0x20000 }, /* 16MB */
0124     { 0x007e2201, "S29GL256N", 0x02000000, 32, 0x20000 }, /* 32MB */
0125     { 0x007e2301, "S29GL512N", 0x04000000, 32, 0x20000 }, /* 64MB */
0126     { 0, 0, 0, 0}
0127 };
0128 
0129 struct vendesc BSP_flash_vendor_spansion[] = {
0130     { 0x01, "Spansion/AMD", spansionDevs, &spansionOps },
0131     { 0, 0}
0132 };
0133 
0134 /********* Register Definitions ****************/
0135 
0136 #define UNLK1_ADDR_16      0x555
0137 #define UNLK1_DATA         0xaa
0138 #define UNLK2_ADDR_16      0x2aa
0139 #define UNLK2_ADDR_8       0x555
0140 #define UNLK2_DATA         0x55
0141 #define ASEL_DATA          0x90
0142 #define VEND_ID_ADDR_16    0x000
0143 #define SPROT_ADDR_16      0x002
0144 #define DEV1_ID_ADDR_16    0x001
0145 #define DEV2_ID_ADDR_16    0x00e
0146 #define DEV3_ID_ADDR_16    0x00f
0147 #define ERASE_DATA         0x80
0148 #define SECT_ERASE_DATA    0x30
0149 #define DQ7_DATA           0x80
0150 #define RESET_DATA         0xf0
0151 #define WRBUF_DATA         0x25
0152 #define PGBUF_DATA         0x29
0153 
0154 #define DQ7_POLL_ALL       (-1)
0155 
0156 /********* Helper Types ************************/
0157 
0158 union bconv {
0159     uint32_t    u;
0160     uint16_t    s[2];
0161     char        c[4];
0162 };
0163 
0164 /********* Register Access Primitives **********/
0165 
0166 /* All of these currently assume stride == 4, i.e.
0167  * two 16-bit devices or 4 8-bit devices in parallel.
0168  *
0169  * FIXME:
0170  *   8-bit mode and strides 1,2 untested.
0171  */
0172 
0173 #define ADDR32(b, a, o)   ((a) + ((o)*FLASH_STRIDE(b)))
0174 
0175 static inline uint32_t
0176 fl_rd32(struct bankdesc *b, uint32_t a, uint32_t off)
0177 {
0178 volatile union bconv *p;
0179 uint32_t              rval;
0180 
0181     if ( 1 == b->width )
0182         off <<= 1;
0183 
0184     a = ADDR32(b, a, off);
0185 
0186     p    = (volatile union bconv *)a;
0187     if ( 4 == FLASH_STRIDE(b) ) {
0188         rval = p->u;
0189         IOSYNC(p->u);
0190     } else if ( 2 == FLASH_STRIDE(b) ) {
0191         rval = p->s[0];
0192         IOSYNC(p->s[0]);
0193     } else {
0194         rval = p->c[0];
0195         IOSYNC(p->c[0]);
0196     }
0197     return rval;
0198 }
0199 
0200 static inline void
0201 fl_wr32(struct bankdesc *b, uint32_t a, uint32_t v)
0202 {
0203 volatile union bconv *p = (volatile union bconv*)a;
0204     if ( 4 == FLASH_STRIDE(b) ) {
0205         p->u    = v;
0206         IOSYNC(p->u);
0207     } else if ( 2 == FLASH_STRIDE(b) ) {
0208         p->s[0] = v;
0209         IOSYNC(p->s[0]);
0210     } else {
0211         p->c[0] = v;
0212         IOSYNC(p->c[0]);
0213     }
0214 }
0215 
0216 static inline uint32_t
0217 fl_splat32(struct bankdesc *b, uint32_t x)
0218 {
0219     if ( 4 == FLASH_STRIDE(b) ) {
0220         if ( 1 == b->width ) {
0221             x = (x << 8) | x;
0222         }
0223         x = (x<<16) | x;
0224     } else if ( 2 == FLASH_STRIDE(b) ) {
0225         if ( 1 == b->width )
0226             x = (x << 8) | x;
0227     }
0228     return x;
0229 }
0230 
0231 static inline uint32_t
0232 fl_x32(struct bankdesc *b, union bconv *pv)
0233 {
0234     if ( 4 == FLASH_STRIDE(b) )
0235         return pv->u;
0236     else if ( 2 == FLASH_STRIDE(b) )
0237         return pv->s[0];
0238     else
0239         return pv->c[0];
0240 }
0241 
0242 static inline void
0243 fl_wr32_cmd(struct bankdesc *b, uint32_t a, uint32_t off, uint32_t cmd)
0244 {
0245     if ( 1 == b->width ) {
0246         if ( off == UNLK2_ADDR_16 )
0247             off = UNLK2_ADDR_8;
0248         else
0249             /* all others are simply left shifted */
0250             off <<= 1;
0251     }
0252     cmd = fl_splat32(b, cmd);
0253     a   = ADDR32(b, a, off);
0254     fl_wr32(b, a, cmd);
0255 }
0256 
0257 /* Send unlock sequence */
0258 static inline void unlk(struct bankdesc *b, uint32_t a)
0259 {
0260     a &= ~ ( ADDR32(b, 0,0x1000) - 1 );
0261     fl_wr32_cmd(b, a, UNLK1_ADDR_16, UNLK1_DATA);
0262     fl_wr32_cmd(b, a, UNLK2_ADDR_16, UNLK2_DATA);
0263 }
0264 
0265 /********* Helper Routines *********************/
0266 
0267 STATIC int
0268 sector_is_protected(struct bankdesc *b, uint32_t addr)
0269 {
0270 int rval;
0271     unlk(b, addr);
0272     fl_wr32_cmd(b, addr, UNLK1_ADDR_16, ASEL_DATA);
0273     rval = fl_rd32(b, addr, SPROT_ADDR_16);
0274     flash_array_mode_s160(b, addr);
0275     return rval;
0276 }
0277 
0278 STATIC int fl_dq7_poll(struct bankdesc *b, uint32_t addr, uint32_t d7_val)
0279 {
0280     d7_val &= fl_splat32(b, DQ7_DATA);
0281     return ( (fl_rd32(b, addr, 0) & fl_splat32(b, DQ7_DATA)) == d7_val );
0282 }
0283 
0284 /* Do DQ7 polling until DQ7 reads the value passed in d7_val
0285  * or timeout
0286  */
0287 STATIC int
0288 flash_pend(struct bankdesc *b, uint32_t addr, uint32_t timeout_us, uint32_t d7_val)
0289 {
0290 uint32_t then = BSP_flashBspOps.read_us_timer();
0291 uint32_t now  = then;
0292 
0293     do {
0294         if ( fl_dq7_poll(b, addr, d7_val) ) {
0295 #if (DEBUG > 4)
0296             printf("Write buffer succeded after %"PRIi32"us\n", (now-then)*8/333);
0297 #endif
0298             return 0;
0299         }
0300         now = BSP_flashBspOps.read_us_timer();
0301     } while ( now - then < timeout_us );
0302 
0303     return -1;
0304 }
0305 
0306 
0307 /********* Access Methods **********************/
0308 
0309 STATIC void
0310 flash_array_mode_s160(struct bankdesc *b, uint32_t addr)
0311 {
0312     fl_wr32_cmd(b, addr, 0, RESET_DATA);
0313 }
0314 
0315 STATIC int
0316 flash_get_id_s160(struct bankdesc *b, uint32_t addr, uint32_t *pVendorId, uint32_t *pDeviceId)
0317 {
0318 uint32_t dev_id[3], x, i;
0319 
0320     if ( 4 != FLASH_STRIDE(b) )
0321         fprintf(stderr,"Warning: strides other than 4 untested\n(%s at %d)\n",
0322             __FILE__,__LINE__);
0323 
0324     if ( 2 != b->width )
0325         fprintf(stderr,"Warning: device width other than 2 untested\n(%s at %d)\n",
0326             __FILE__,__LINE__);
0327 
0328     addr &= ~ (ADDR32(b, 0, 0x1000) - 1);
0329     unlk(b, addr);
0330     fl_wr32_cmd(b, addr, UNLK1_ADDR_16, ASEL_DATA);
0331     *pVendorId = fl_rd32(b, addr, VEND_ID_ADDR_16) & 0xff;
0332     dev_id [0] = fl_rd32(b, addr, DEV1_ID_ADDR_16);
0333     dev_id [1] = fl_rd32(b, addr, DEV2_ID_ADDR_16);
0334     dev_id [2] = fl_rd32(b, addr, DEV3_ID_ADDR_16);
0335 
0336 #ifdef DEBUG
0337     printf("Vendor Id 0x%08"PRIx32", Dev Ids: 0x%08"PRIx32", 0x%08"PRIx32", 0x%08"PRIx32"\n",
0338         *pVendorId, dev_id[0], dev_id[1], dev_id[2]);
0339 #endif
0340 
0341     flash_array_mode_s160(b, addr);
0342 
0343     for ( x=0, i=0; i<3; i++ ) {
0344         x = (x<<8) | (dev_id[i] & 0xff);
0345     }
0346 
0347     *pDeviceId = x;
0348 
0349     return 0;
0350 }
0351 
0352 
0353 STATIC void
0354 flash_lock_block_s160(struct bankdesc *b, uint32_t addr)
0355 {
0356 }
0357 
0358 STATIC void
0359 flash_unlock_block_s160(struct bankdesc *b, uint32_t addr)
0360 {
0361 }
0362 
0363 STATIC uint32_t
0364 flash_check_ready_s160(struct bankdesc *b, uint32_t addr)
0365 {
0366     flash_array_mode_s160(b, addr);
0367     return 0;
0368 }
0369 
0370 /* Erase single block holding 'addr'ess
0371  *
0372  * RETURNS: zero on error, device status on failure.
0373  *
0374  *   NOTES: - device switched back to array mode on exit.
0375  *          - 'addr' must be 32-bit aligned.
0376  */
0377 STATIC int
0378 flash_erase_block_s160(struct bankdesc *b, uint32_t addr)
0379 {
0380 rtems_interval p,i;
0381 
0382     addr &= ~ (b->fblksz-1);
0383 
0384     if ( sector_is_protected(b, addr) ) {
0385         fprintf(stderr,"Sector at 0x%08"PRIx32" is protected\n", addr);
0386         return -10;
0387     }
0388 
0389     unlk(b, addr);
0390     fl_wr32_cmd(b, addr, UNLK1_ADDR_16, ERASE_DATA);
0391     unlk(b, addr);
0392     fl_wr32_cmd(b, addr, 0, SECT_ERASE_DATA);
0393 
0394     p = rtems_clock_get_ticks_per_second();
0395     p *= ERASE_TIMEOUT;
0396 
0397     for ( i=p; i; i-- ) {
0398         rtems_task_wake_after(1);
0399         if ( fl_dq7_poll(b, addr, DQ7_POLL_ALL) ) {
0400             break;
0401         }
0402     }
0403 #ifdef DEBUG
0404     printf("ERASE polled for %"PRIi32" ticks\n", p-i);
0405 #endif
0406     flash_array_mode_s160(b, addr);
0407 
0408     if ( i ) {
0409         /* write successful; verify */
0410         for ( i = 0; i < b->fblksz; i++ ) {
0411             if ( 0xff != ((char*)addr)[i] ) {
0412                 fprintf(stderr,"ERROR: Erase verification failed at %p\n",
0413                     ((char*)addr) + i);
0414                 return -1;
0415             }
0416         }
0417         return 0;
0418     }
0419     return -1;
0420 }
0421 
0422 STATIC void
0423 flash_print_stat_s160(struct bankdesc *b, uint32_t sta, int verbose)
0424 {
0425     fprintf(stderr,"Flash Spansion 160 error %"PRIi32"\n", sta);
0426 }
0427 
0428 STATIC uint32_t
0429 flash_write_line_s160(struct bankdesc *b, uint32_t a, const char *s, uint32_t N)
0430 {
0431 uint32_t        sta, nxt, j, v;
0432 union    bconv  buf;
0433 
0434     if ( 0 == N )
0435         return -11;
0436 
0437     if ( N & (FLASH_STRIDE(b) - 1) ) {
0438         fprintf(stderr,"flash_write_line_s160: invalid byte count (not multiple of stride\n");
0439         return -10;
0440     }
0441 
0442     unlk(b, a);
0443 
0444     /* address block */
0445     fl_wr32_cmd(b, a, 0, WRBUF_DATA);
0446 
0447     /* (16-bit) word count per device */
0448     N /= FLASH_STRIDE(b);
0449 
0450     fl_wr32_cmd(b, a, 0, N-1);
0451 
0452     /* silence compiler warning about uninitialized var (N > 0 at this point) */
0453     v = 0;
0454 
0455     /* fill buffer */
0456     for (nxt = a; N>0; N--) {
0457 #if (DEBUG > 4)
0458         printf("Writing DAT *0x%08"PRIx32" = 0x%08"PRIx32"\n", nxt, *(uint32_t*)s);
0459 #endif
0460         /* deal with misaligned sources */
0461         for ( j=0; j<FLASH_STRIDE(b); j++ ) {
0462             buf.c[j] = *s++;
0463         }
0464         v = fl_x32(b, &buf);
0465         fl_wr32(b, nxt, v);
0466         nxt += FLASH_STRIDE(b);
0467     }
0468 
0469     /* burn buffer */
0470     fl_wr32_cmd(b, a, 0, PGBUF_DATA);
0471 
0472     /* pend */
0473 
0474     sta = flash_pend(b, nxt - FLASH_STRIDE(b), WRITE_TIMEOUT, v);
0475 
0476     return sta;
0477 }