diff options
author | Till Straumann <strauman@slac.stanford.edu> | 2007-11-27 20:36:22 +0000 |
---|---|---|
committer | Till Straumann <strauman@slac.stanford.edu> | 2007-11-27 20:36:22 +0000 |
commit | 2a444594b71822d62be0b32aefe9646a684c4cfc (patch) | |
tree | f034fe44a0a05b900a04d9da34300c121d09f4fd | |
parent | 2007-11-27 Glenn Humphrey <glenn.humphrey@OARcorp.com> (diff) | |
download | rtems-2a444594b71822d62be0b32aefe9646a684c4cfc.tar.bz2 |
2007-11-29 Till Straumann <strauman@slac.stanford.edu>
* 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.
-rw-r--r-- | c/src/lib/libbsp/powerpc/ChangeLog | 13 | ||||
-rw-r--r-- | c/src/lib/libbsp/powerpc/Makefile.am | 4 | ||||
-rw-r--r-- | c/src/lib/libbsp/powerpc/shared/flash/flash.c | 877 | ||||
-rw-r--r-- | c/src/lib/libbsp/powerpc/shared/flash/flashPgm.h | 185 | ||||
-rw-r--r-- | c/src/lib/libbsp/powerpc/shared/flash/flashPgmPvt.h | 275 | ||||
-rw-r--r-- | c/src/lib/libbsp/powerpc/shared/flash/intelFlash.c | 457 | ||||
-rw-r--r-- | c/src/lib/libbsp/powerpc/shared/flash/spansionFlash.c | 479 |
7 files changed, 2290 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/powerpc/ChangeLog b/c/src/lib/libbsp/powerpc/ChangeLog index 2bbc393aa5..0476ea5be1 100644 --- a/c/src/lib/libbsp/powerpc/ChangeLog +++ b/c/src/lib/libbsp/powerpc/ChangeLog @@ -1,3 +1,16 @@ +2007-11-29 Till Straumann <strauman@slac.stanford.edu> + + * 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. + 2007-11-26 Joel Sherrill <joel.sherrill@OARcorp.com> * shared/console/uart.c: Fix typo and spacing. diff --git a/c/src/lib/libbsp/powerpc/Makefile.am b/c/src/lib/libbsp/powerpc/Makefile.am index d7a122b4a8..ca916aa2de 100644 --- a/c/src/lib/libbsp/powerpc/Makefile.am +++ b/c/src/lib/libbsp/powerpc/Makefile.am @@ -31,6 +31,10 @@ EXTRA_DIST += shared/clock/p_clock.c EXTRA_DIST += shared/console/console.c shared/console/inch.c shared/console/polled_io.c \ shared/console/uart.c shared/console/reboot.c shared/console/console.inl +## shared/flash +EXTRA_DIST += shared/flash/flash.c shared/flash/flashPgm.h shared/flash/flashPgmPvt.h \ + shared/flash/intelFlash.c shared/flash/spansionFlash.c + ## shared/motorola EXTRA_DIST += shared/motorola/motorola.c diff --git a/c/src/lib/libbsp/powerpc/shared/flash/flash.c b/c/src/lib/libbsp/powerpc/shared/flash/flash.c new file mode 100644 index 0000000000..285e51a765 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/shared/flash/flash.c @@ -0,0 +1,877 @@ +/* $Id$ */ + +/* Trivial Flash Programmer */ + +/* Author: Till Straumann <strauman@slac.stanford.edu>, 2006 */ + +/* To keep things simple, this driver makes a few assumptions about the + * hardware: + * + * - no CFI + * - devices operate with 16-bit data width + * - two devices are used in parallel (stride 4) to + * provide 32-bit data. I.e., the devices are + * organized like this: + * unsigned short flash[FLASH_SIZE][2]; + * - no endianness issues (i.e., flash endianness == CPU endianness) + * - fixed block size + * - fixed buffer size + * - all devices in a bank are identical + * - NOT THREAD SAFE; no locking scheme is implemented. + * - cannot copy within same flash bank. + * - timeout uses polling/busy-wait. + * + * NOTE: some attempts have been made to remove the restrictions + * on stride and 16-bit width with the goal to support widths 1/2 (bytes) + * and strides 1/2/4 and all (legal) combinations thereof. + * However, the intel chip driver only implements stride 4 / width 2 + * and other combinations are untested. + */ + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The software was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ +#ifndef TESTING +#include <rtems.h> +#include <bsp/flashPgm.h> +#include <bsp/flashPgmPvt.h> +#else +#include "flashPgm.h" +#include "flashPgmPvt.h" +#endif + +#include <stdio.h> +#include <inttypes.h> +#include <ctype.h> +#include <fcntl.h> +#include <stdlib.h> + +#define DEBUG 0 +#undef DEBUG + +#ifdef DEBUG +#define STATIC +#else +#define STATIC static +#endif + +/* Forward decls. */ + +STATIC uint32_t +BSP_flashProbeSize(struct bankdesc *b); + +STATIC struct bankdesc * +bankValidate(int bank, int quiet); + +/* Type definitions */ + +union bconv { + uint32_t u; + uint16_t s[2]; + char c[4]; +}; + +/* Little helpers... */ + +/* Read parallel devices */ +static void +rd_par(struct bankdesc *b, union bconv *pv, uint32_t a) +{ + if ( 4 == FLASH_STRIDE(b) ) { + pv->u = *(_u32_a_t*)a; + } else if ( 2 == FLASH_STRIDE(b) ) { + pv->s[0] = *(_u16_a_t*)a; + } else { + pv->c[0] = *(_u8_a_t*)a; + } +} + +/* 'flush' input buffer and get an upper-case char from stdin */ +STATIC int +getUc() +{ + fseek(stdin, 0, SEEK_END); + return toupper(getchar()); +} + +/* Advance rotating progress indicator on stdout. + * The idea is that the caller updates a state variable + * using 'flip': + * + * unsigned f = 0; + * + * // advance indicator + * f = flip(f); + * + * ... + * + * // erase indicator + * wipe(f); + */ +static unsigned flip(unsigned x) +{ +static char bar[]= { '/', '-', '\\', '|' }; + putchar('\b'); + putchar(bar[ x & 3]); + fflush(stdout); + return x+1; +} + +/* If f!=0 then erase one char on stdout. + * ( If 'flip' was never called then f should still + * be zero and no action is taken). + */ +static void wipe(unsigned f) +{ + if ( f ) { + putchar('\b'); + putchar(' '); + putchar('\b'); + fflush(stdout); + } +} + +/* lookup vendor ID in table of known vendors using ops + * associated with the vendor. + */ +STATIC struct vendesc * +knownVendor(struct bankdesc *b, uint32_t addr, uint32_t *pd, unsigned quiet) +{ +uint32_t v; +struct vendesc *rval; + + for ( rval=b->knownVendors; rval->name; rval++ ) { + + if ( rval->ops->get_id(b, addr, &v, pd) ) { + if ( quiet < 2 ) + fprintf(stderr,"Unable to read vendor/device info at 0x%08"PRIx32"\n", addr); + return 0; + } + + if ( rval->id == v ) { + return rval; + } + } + if ( quiet < 2 ) + fprintf(stderr,"Unknown vendor id (0x%04"PRIx32") at 0x%08"PRIx32"\n",v, addr); + return 0; +} + +/* lookup device ID in table of known devices */ +STATIC struct devdesc * +knownDevice(struct vendesc *v, uint32_t d) +{ +struct devdesc *rval; + for ( rval=v->known_devs; rval->name; rval++ ) { + if ( rval->id == d ) { + return rval; + } + } + return 0; +} + +/* Write 'n_words' (32-bit) from 'src' to 'addr'ess on flash. + * (src is a char* to emphasize that no src-alignment is required) + * + * RETURNS: 0 on success, (destination) address of failure on error. + * + * NOTES: - device switched back to array mode on exit. + * - 'addr' must be 32-bit aligned. + */ + +STATIC uint32_t +BSP_flashWriteDataRaw(struct bankdesc *b, uint32_t addr, char *src, uint32_t n_words, int quiet) +{ +uint32_t sta; +uint32_t N; +uint32_t nxt, a, i, bufsz; +uint32_t then, now; +unsigned f; +char *s; + +#ifdef DEBUG + printf("\nflashWriteDataRaw(0x%08"PRIx32", %p, 0x%"PRIx32")\n", addr, src, n_words); +#endif + + if ( 0 == n_words ) { + return 0; + } + + if ( !b ) { + fprintf(stderr,"Missing bank descriptor argument\n"); + return -1; + } + if ( !b->dd ) { + fprintf(stderr,"Bank descriptor not initialized\n"); + return -1; + } + + if ( addr & (FLASH_STRIDE(b)-1) ) { + fprintf(stderr,"Misaligned address (not on word boundary) 0x%08"PRIx32"\n", addr); + return -1; + } + + if ( (sta = b->ops->check_ready(b, addr)) ) { + /* Error msgs have already been printed */ + return addr; + } + + bufsz = FLASH_NDEVS(b) * b->dd->bufsz; + + then = BSP_flashBspOps.read_us_timer(); + + for ( f = 0, a = addr, s=src, i = n_words; i ; s+=N ) { + /* start of next buffer */ + nxt = (a + bufsz) & ~(bufsz-1); + + /* number of bytes */ + N = (nxt - a); + + if ( N > i * FLASH_STRIDE(b) ) + N = i * FLASH_STRIDE(b); + + i -= N/FLASH_STRIDE(b); + + if ( (sta = b->ops->write_line(b, a, s, N)) ) + goto bail; + + if ( ! quiet && (now = BSP_flashBspOps.read_us_timer()) - then > 500000 ) { + f = flip(f); + then = now; + } + + a = nxt; + } + + sta = 0; + + /* verify */ + for ( i=0, a=addr; i < n_words * FLASH_STRIDE(b); i++, a++ ) { + if ( *(char*)a != src[i] ) { + sta = -2; + goto bail; + } + } + +bail: + if ( ! quiet ) { + wipe(f); + } + if ( sta ) { + switch ( sta ) { + default: + fprintf(stderr,"Error (flashWriteDataRaw): write error\n"); + b->ops->print_stat(b, sta,0); + break; + + case -1: + fprintf(stderr,"Error (flashWriteDataRaw): Timeout\n"); + break; + + case -2: + fprintf(stderr,"Error (flashWriteDataRaw): write verification failed at 0x%08"PRIx32"\n", a); + break; + } + b->ops->array_mode(b, a); + } else { + /* no errors */ + a = 0; + } + return a; +} + + +/* Query device for basic information verifying that we talk + * to a 'known'/'supported' device. + * + * This is not really clean since (until we implement CFI) + * we already need to know what kind of device it is to + * be able to read its ID... + * + * NOTES: - device switched back to array mode on exit. + * - 'addr' must be 32-bit aligned. + */ + +STATIC struct devdesc * +BSP_flashCheckId(struct bankdesc *b, uint32_t addr, unsigned quiet) +{ +uint8_t x; +uint32_t d; +struct vendesc *vd; +struct devdesc *dd; + + /* check if it's flash at all: */ + x = *(A8)addr; + *(A8)addr = ~x; + if ( x != *(A8)addr ) { + /* restore */ + *(A8)addr = x; + if ( quiet < 3 ) + fprintf(stderr,"Addr 0x%08"PRIx32" seems to be RAM!\n", addr); + return 0; + } + + if ( !(vd = knownVendor(b, addr, &d, quiet)) ) { + return 0; + } + + /* Use the vendor ops for this bank */ + b->ops = vd->ops; + + if ( !quiet ) + printf("Flash device, vendor: %s", vd->name); + + if ( !(dd = knownDevice(vd, d)) ) { + if ( !quiet ) + printf("\n"); + if ( quiet < 2 ) + fprintf(stderr,"Unknown device id (0x%04"PRIx32") at 0x%08"PRIx32"\n",d, addr); + return 0; + } + + /* logical sector size is device sector size + * multiplied by # of devices in parallel + */ + b->fblksz = dd->fblksz * FLASH_NDEVS(b); + + if ( !quiet ) + printf(", device: %s -- size 0x%08"PRIx32" bytes\n", dd->name, dd->size); + return dd; +} + +/* We don't have device info yet so just + * use 64k alignment + */ +#define SCAN_BACK_OFFSET 0x10000 + +/* Scan address range for flash devices and compute total size + * of bank. + * + * RETURNS: size in bytes. + */ +STATIC uint32_t +BSP_flashProbeSize(struct bankdesc *b) +{ +int max = b->max_size; +uint32_t rval; +struct devdesc *dd; +unsigned q; + if ( max > 0 ) { + for ( rval = 0, q=1; rval < max && (dd = BSP_flashCheckId(b, b->start + rval, q)); q=3 ) { + rval += dd->size * FLASH_NDEVS(b); + } + } else { + /* bank is populated from the top; scan backwards */ + max = -max; + for ( rval = 0, q=1; rval < max && (dd = BSP_flashCheckId(b, b->start + max - SCAN_BACK_OFFSET - rval, q)); q=3 ) { + rval += dd->size * FLASH_NDEVS(b); + } + } + return rval; +} + +#ifndef TESTING + +/* Obtain bank description making sure it is initialized and not write protected */ +STATIC struct bankdesc * +bankValidate(int bank, int quiet) +{ +struct bankdesc *b = BSP_flashBspOps.bankcheck(bank, quiet); + + /* If flash is write-protected then we can't even talk to it... */ + if ( BSP_flashBspOps.flash_wp(bank, -1) ) { + fprintf(stderr,"Flash bank #%i is write-protected; use 'BSP_flashWriteEnable(int bank)' and/or jumper\n", bank); + return 0; + } + + if ( !b->dd && !(b->dd = BSP_flashCheckId(b, b->start,1)) ) { + fprintf(stderr,"Error: unable to detect flash device in bank #%i\n", bank); + return 0; + } + return b; +} + +/* Validate arguments and write-protection status of 'bank'. + * + * 'bank': 0..max bank supported by board. + * 'offset': 0..bank size - 1 + * 'src': src .. src + size - 1 must not overlap bank; 'src' may be NULL + * (check is skipped in this case) + * + * RETURNS: pointer to bank description on success, NULL on error (invalid args; + * error message is printed to stderr). + * + * SIDE EFFECTS: probes for bank size and stores result in bank description table. + */ + +static struct bankdesc * +argcheck(uint32_t bank, uint32_t offset, char *src, uint32_t size) +{ +struct bankdesc *b; + + if ( !(b=bankValidate(bank, 0)) ) { + return 0; + } + + if ( !b->size && !(b->size = BSP_flashProbeSize(b)) ) { + fprintf(stderr,"Configuration Error - unable to determine flash size\n"); + return 0; + } + if ( offset + size > b->size ) { + fprintf(stderr,"Error: requested size exceeds available flash (0x%08"PRIx32" bytes)\n", b->size); + return 0; + } + + if ( src && ( src + size > (char*)b->start && src < (char*)(b->start + b->size) ) ) { + fprintf(stderr,"Error: cannot copy data within flash bank\n"); + return 0; + } + + + return b; +} + +/* Calculate region that needs to be erased from 'offset' and 'n_bytes' + * handling alignment and checking for blank areas that need not be + * erased. + * Ask for user confirmation and erase calculated region. + * + * RETURNS: 0 on success, -1 or destination address on error. + * + * NOTES: - device switched back to array mode on exit. + * - prints progress/messages. + */ +STATIC int +regionCheckAndErase(int bank, uint32_t offset, char *src, uint32_t n_bytes, int quiet) +{ +struct bankdesc *b; +uint32_t i; +char *p; +uint32_t a,e; + + if ( ! (b = argcheck(bank, offset, src, n_bytes)) ) + return -1; + + a = offset & ~(b->fblksz - 1); + e = (offset + n_bytes + b->fblksz - 1) & ~ (b->fblksz - 1); + + /* If 'offset' is not block-aligned then rest of the block must + * be free. + */ + if ( a != offset ) { + a += b->fblksz; + i = ( a > offset + n_bytes ) ? offset + n_bytes : a; + for ( p = (char*)(b->start + offset); p < (char*)(b->start + i); p++ ) { + if ( (char)0xff != *p ) { + if ( ! quiet ) { + fprintf(stderr,"Starting offset not block-aligned and destination area not empty.\n"); + fprintf(stderr,"I'll need to erase data below destination start\n"); + } + a -= b->fblksz; + break; + } + } + } + if ( e != offset + n_bytes ) { + e -= b->fblksz; + i = ( e < offset ) ? offset : e; + for ( p = (char*)(b->start + i); p < (char*)(b->start + offset + n_bytes); p++ ) { + if ( (char)0xff != *p ) { + if ( ! quiet ) { + fprintf(stderr,"Ending offset not block-aligned and destination area not empty.\n"); + fprintf(stderr,"I'll need to erase data beyond destination end\n"); + } + e += b->fblksz; + break; + } + } + } + if ( ! quiet ) { + if ( e > a ) + printf("ERASING 0x%08"PRIx32" .. 0x%08"PRIx32"\n", (b->start+a), (b->start + e - 1)); + printf("WRITING 0x%08"PRIx32" .. 0x%08"PRIx32"\n", (b->start+offset), (b->start + offset + n_bytes - 1)); + printf("OK to proceed y/[n]?"); fflush(stdout); + if ( 'Y' != getUc() ) { + printf("ABORTED\n"); + return -1; + } + } + if ( e > a ) { + if ( quiet < 2 ) { + printf("ERASING "); fflush(stdout); + } + + if ( (i = BSP_flashErase(bank, a, e-a, quiet ? quiet : 1)) ) + return i; + + if ( quiet < 2 ) { + printf("DONE\n"); + } + } + + return 0; +} + +/* Write to a flash region ('offset'..'offset'+'n_bytes'-1 on 'bank'). + * + * RETURNS: 0 on success, -1 or destination address on error. + * + * NOTES: - device switched back to array mode on exit. + * - no erase operation is performed. + * - written data is verified against source. + */ + +STATIC int +BSP_flashWriteRegion(int bank, uint32_t offset, char *src, uint32_t n_bytes, int quiet) +{ +struct bankdesc *b = BSP_flashBspOps.bankcheck(bank, 0); /* caller did bankValidate() */ +uint32_t ab = offset & ~(b->fblksz - 1); +uint32_t eb = (offset + n_bytes + b->fblksz - 1) & ~(b->fblksz - 1); +uint32_t o,i,a,e; +int err; +char *p; +union bconv buf; + + /* unlock */ + for ( i=ab; i<eb; i+=b->fblksz ) { + b->ops->unlock_block(b, b->start + i ); + } + + err = 0; + p = src; + + /* handle misaligned offset merging old contents */ + o = b->start + offset; + a = o & ~(FLASH_STRIDE(b)-1); + e = (o + n_bytes) & ~(FLASH_STRIDE(b)-1); + + if ( o > a ) { + i = o - a; + + rd_par(b, &buf, a); + + while ( i < FLASH_STRIDE(b) && p < src + n_bytes ) { + buf.c[i++] = *p++; + } + if ( (err = BSP_flashWriteDataRaw(b, a, buf.c, 1, quiet)) ) + goto bail; + a += FLASH_STRIDE(b); + } + + + /* caution if misaligned data covering only one or two words */ + + if ( e > a ) { + i = (e-a); + if ( (err = BSP_flashWriteDataRaw(b, a, p, i/FLASH_STRIDE(b), quiet)) ) + goto bail; + p += i; + } + + /* handle misaligned end */ + if ( o + n_bytes > e) { + rd_par(b, &buf, e); + for ( i=0; p < src + n_bytes; ) { + buf.c[i++] = *p++; + } + if ( (err = BSP_flashWriteDataRaw(b, e, buf.c, 1, quiet)) ) + goto bail; + } + +bail: + /* lock area */ + for ( i=ab; i<eb; i+=b->fblksz ) { + b->ops->lock_block(b, b->start + i ); + } + + /* final verification */ + if ( !err ) { + for ( i=0; i<n_bytes; i++ ) { + if ( ((char*)(b->start + offset))[i] != src[i] ) { + fprintf(stderr,"Final verification failed at offset 0x%08"PRIx32"\n", (offset + i)); + return b->start + offset + i; + } + } + } + + return err; +} + +int +BSP_flashErase(uint32_t bank, uint32_t offset, uint32_t size, int quiet) +{ +struct bankdesc *b; +uint32_t a,i; +int f; + + if ( ! (b = argcheck(bank, offset, 0, size)) ) + return -1; + + if ( offset & (b->fblksz - 1) ) { + fprintf(stderr,"Offset misaligned (needs to be multiple of 0x%08"PRIx32")\n", b->fblksz); + return -1; + } + if ( size & (b->fblksz - 1) ) { + fprintf(stderr,"Size misaligned (needs to be multiple of 0x%08"PRIx32")\n", b->fblksz); + return -1; + } + + a = b->start + offset; + + if ( !quiet ) { + printf("ERASING Flash (Bank #%"PRIu32")\n from 0x%08"PRIx32" .. 0x%08"PRIx32"\nproceed y/[n]?", + bank, a, (a+size-1)); + fflush(stdout); + if ( 'Y' != getUc() ) { + printf("ABORTED\n"); + return -1; + } + } + f = 0; + while ( size ) { + /* work to do ? */ + for ( i = 0; i<b->fblksz; i++ ) { + if ( (char)0xff != ((char*)a)[i] ) { + b->ops->unlock_block(b, a); + i = b->ops->erase_block(b, a); + b->ops->lock_block(b, a); + if (i) { + wipe(f); + return a; + } + break; + } + } + + if ( quiet < 2 ) { + f = flip(f); + } + + a += b->fblksz; + size -= b->fblksz; + } + b->ops->array_mode(b, a); + if ( quiet < 2 ) { + wipe(f); + } + return 0; +} + +int +BSP_flashWrite(int bank, uint32_t offset, char *src, uint32_t n_bytes, int quiet) +{ +int rval; + + if ( !src ) { + fprintf(stderr,"Error: Data source pointer is NULL\n"); + return -1; + } + + if ( (rval = regionCheckAndErase(bank, offset, src, n_bytes, quiet)) ) + return rval; + + if ( ! quiet ) { + printf("WRITING "); fflush(stdout); + } + + rval = BSP_flashWriteRegion(bank, offset, src, n_bytes, quiet); + + if ( !quiet && !rval ) { + printf("DONE"); + } + if ( !quiet ) + printf("\n"); + return rval; +} + +static int +bfill(int fd, char *buf, int size) +{ +int got, avail; + for (avail = size; (got = read(fd, buf, avail)) > 0; avail-=got ) { + buf += got; + } + return size - avail; +} + +int +BSP_flashWriteFile(int bank, uint32_t offset, char *fname, int quiet) +{ +int fd = -1; +struct stat sb; +uint32_t sz; +int rval = -1; +char *buf = 0; +uint32_t got; +struct bankdesc *b; +unsigned f = 0; + + if ( ! (b = BSP_flashBspOps.bankcheck(bank, 0)) ) + return -1; + + for ( sz = 0; -1 == fd ; ) { + if ( (fd = open(fname,O_RDONLY)) < 0 ) { + perror("Opening file"); + return -1; + } + + if ( sz ) + break; + + if ( fstat(fd, &sb) ) { + fprintf(stderr,"Warning: fstat doesn't work; need to slurp file to determine size; please be patient.\n"); + FILE *f; + close(fd); fd = -1; + f = fopen(fname,"r"); + if ( !f ) { + perror("fdopen"); + return -1; + } + while ( EOF != fgetc(f) ) + sz++; + fclose(f); + /* reopen */ + } else { + sz = sb.st_size; + } + if ( 0 == sz ) { + fprintf(stderr,"Error: zero file size (?)\n"); + goto bail; + } + } + + if ( !(buf = malloc(b->fblksz)) ) { + perror("buffer allocation"); + goto bail; + } + + /* See if we can erase the entire region */ + if ( (rval = regionCheckAndErase(bank, offset, buf, sz, quiet)) ) + goto bail; + + /* Proceed copying chunks */ + if ( quiet < 2 ) { + printf("WRITING "); fflush(stdout); + } + + while ( (got = bfill(fd, buf, b->fblksz)) > 0 && sz ) { + if ( (rval = BSP_flashWriteRegion(bank, offset, buf, got, 1)) ) { + wipe(f); + goto bail; + } + offset += got; + sz -= got; + if ( quiet < 2 ) { + f = flip(f); + } + } + if ( got < 0 ) { + perror("reading file"); + rval = offset; + goto bail; + } + + if ( quiet < 2 ) { + wipe(f); + printf("DONE"); + } +bail: + if ( quiet < 2 ) { + printf("\n"); + } + if ( fd > -1 ) + close(fd); + free(buf); + return rval; +} + +int +BSP_flashWriteEnable(int bank) +{ + return BSP_flashBspOps.flash_wp(bank,0); +} + +int +BSP_flashWriteDisable(int bank) +{ + return BSP_flashBspOps.flash_wp(bank,1); +} + +int +BSP_flashDumpInfo(FILE *f) +{ +struct bankdesc *b; +int bank; + + if ( !f ) + f = stdout; + + /* use 'bankValidate()' with 'quiet' flag to suppress error message when + * we reach the end of the table. + */ + for ( bank = 0; BSP_flashBspOps.bankcheck(bank,1); bank++ ) { + if ( (b=argcheck(bank,0,0,0)) ) { + fprintf(f,"Flash Bank #%i; 0x%08"PRIx32" .. 0x%08"PRIx32" (%"PRId32" bytes)\n", + bank, b->start, (b->start + b->size - 1), b->size); + fprintf(f,"%i * %i-bit devices in parallel; block size 0x%"PRIx32"\n", FLASH_NDEVS(b), FLASH_WIDTH(b)*8, b->fblksz); + BSP_flashCheckId(b, b->start, 0); + } + } + + return 0; +} + +#else + +int +main(int argc, char **argv) +{ +uint32_t fla[1000]; +uint32_t qqq[1000]; +int i; + for ( i=0; i<sizeof(qqq)/sizeof(qqq[0]); i++ ) + qqq[i] = 0xdada<<16 | i; + BSP_flashWriteDataRaw(0, (uint32_t)fla, (char*)qqq, 32, 0); +} +#endif diff --git a/c/src/lib/libbsp/powerpc/shared/flash/flashPgm.h b/c/src/lib/libbsp/powerpc/shared/flash/flashPgm.h new file mode 100644 index 0000000000..2d93cd094e --- /dev/null +++ b/c/src/lib/libbsp/powerpc/shared/flash/flashPgm.h @@ -0,0 +1,185 @@ +#ifndef BSP_FLASH_PGM_API_H +#define BSP_FLASH_PGM_API_H +/* $Id$ */ + +/* Trivial Flash Programmer */ + +/* Author: Till Straumann <strauman@slac.stanford.edu>, 2006 + * NOTE: copyright info at the bottom of this file + */ + +/* IMPORTANT NOTE + * + * The flash API is NOT THREAD SAFE. During the execution of any of the + * BSP_flashXXX() routines, flash (residing in the same device) + * MUST NOT be accessed by other threads in ANY way (NOT EVEN READ!). + * Read operations may return internal device register contents + * instead of memory array data when issued while a flash device + * is erased, written or queried by the library. + * + * The routines are intended for occasional maintenance use only + * (i.e., not for implementing a file system or similar). + * + * While polling for the completion of block erase operations the + * CPU is yielded to other threads. Busy waiting (interrupts and + * thread dispatching remain enabled) on write operations is employed. + */ + +#include <stdio.h> + +#ifdef __cplusplus + extern "C" { +#endif + +/* Disengage flash write protection. Write protection is implemented + * at the board or chipset level by disabling all write operations/bus cycles + * to the flash device(s). + * With write protection enabled, nothing but 'ordinary' (array) read operations + * are possible. + * Write protection must be disabled not only to erase and write contents + * but also in order to read ID, size, status etc. + * None of the operations (except for BSP_flashWriteEnable()) are possible + * on a write-protected device. + * + * 'bank': flash bank # (usually 0) + * RETURNS: 0 on success, nonzero on error (printing message to stderr). + * + * NOTES: - some boards (MVME5500) don't support 'bank' granularity but + * enable/disable write protection for all devices at once. + * - a jumper-based protection mechanism might be in place + * in addition to the software-based one. Consult the user's + * manual of your board for more information. + */ +int +BSP_flashWriteEnable(int bank); + +/* Engage flash write protection (see above) + */ +int +BSP_flashWriteDisable(int bank); + +/* Erase a region of flash memory. + * 'bank': flash bank # (usually 0). + * 'offset': destination address offset (from start of bank). + * 'size': number of bytes to erase. + * 'quiet': if non-zero, suppress confirmation message / prompt + * if > 1 also suppress the progress indicator. + * + * RETURNS: 0 on success, nonzero on error (printing messages to stderr). + * + * NOTES: - 'offset' and 'size' must be block-aligned. Common 16-bit devices + * have a block size of 0x20000 bytes. If two such devices are + * operated in parallel to form a 32-bit word then the 'effective' + * block size is 0x40000 bytes. + * + * - erase operation is verified. + */ +int +BSP_flashErase(uint32_t bank, uint32_t offset, uint32_t size, int quiet); + +/* Write data from a buffer to flash. The target area is erased if necessary. + * + * 'bank': flash bank # (usually 0). + * 'offset': destination address offset (from start of bank). + * 'src': data source block address (in memory). + *'n_bytes': number of bytes to copy. + * 'quiet': if non-zero, suppress confirmation message / prompt + * if > 1 also suppress the progress indicator. + * + * NOTES: - Erase operations are only performed where necessary. I.e., + * if one or both of the boundaries of the destination region is/are + * not block-aligned then adjacent data are preserved provided that + * the relevant chunks of the destination are blank (erased). + * + * | <neighbour> fffffff | + * ^--- destination ----- ^ + * | : block boundary + * f : blank/erased pieces + * + * (If the start of the destination region up to the next block boundary + * is blank then '<neighbour>'-data is preserved. The end of the + * destination is treated the same way.) + * + * - user confirmation is requested before changes are made + * + * - 'src' must not point into the destination bank (no copy + * within a flash bank). + * + * - erase and write operations are verified. + * + * RETURNS: 0 on success, nonzero on error (message printed to stderr). + */ +int +BSP_flashWrite(int bank, uint32_t offset, char *src, uint32_t n_bytes, int quiet); + +/* Copy contents of a file to flash. + * + * 'fname': Path of a file. + * 'quiet': if non-zero, suppress confirmation message / prompt + * if > 1 also suppress the progress indicator. + * + * NOTES: Convenience wrapper around BSP_flashWrite(); see above for + * args and return value. + */ +int +BSP_flashWriteFile(int bank, uint32_t offset, char *path, int quiet); + +/* Dump info about available flash to file + * (stdout is used if f==NULL). + * + * RETURNS: 0 + * NOTES: Write protection must be disengaged (see above); + */ +int +BSP_flashDumpInfo(FILE *f); + +#ifdef __cplusplus + } +#endif + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The software was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +#endif diff --git a/c/src/lib/libbsp/powerpc/shared/flash/flashPgmPvt.h b/c/src/lib/libbsp/powerpc/shared/flash/flashPgmPvt.h new file mode 100644 index 0000000000..55d0bf1333 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/shared/flash/flashPgmPvt.h @@ -0,0 +1,275 @@ +#ifndef FLASH_GLUE_INTERFACE_H +#define FLASH_GLUE_INTERFACE_H + +/* $Id$ */ + +/* Trivial flash programmer (for restrictions see below) */ + +/* Author: Till Straumann <strauman@slac.stanford.edu>, 2006 */ + +/* DO NOT INCLUDE THIS HEADER FROM APPLICATION CODE */ + +/* + * Glue interface -- to be used only internally by BSP + * and chip drivers: + * - BSP provides info about what chip drivers to use + * as well as 'wiring' info (how many devices are + * operated in parallel etc). + * - Chip drivers provide low-level 'methods' / 'ops' + * for performing basic operations which are used + * by the code in 'flash.c'. + */ + +/* To keep things simple, this API makes a few assumptions about the + * hardware: + * + * - devices operate with 16-bit data width + * - two devices are used in parallel (stride 4) to + * provide 32-bit data. I.e., the devices are + * organized like this: + * unsigned short flash[FLASH_SIZE][2]; + * - no endianness issues (i.e., flash endianness == CPU endianness) + * - fixed block size + * - fixed buffer size + * - all devices in a bank are identical + * - NOT THREAD SAFE; no locking scheme is implemented. + * - cannot copy within same flash bank. + * - write-timeout uses polling/busy-wait + * + * FIXME: code should be revised to remove assumptions on stride and 16-bit + * width to make it more generic. + */ + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The software was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +#include <stdint.h> + +#define NumberOf(arr) (sizeof(arr)/sizeof(arr[0])) + +#define FLASH_STRIDE(b) 4 /* bytes; currently fixed */ +#define FLASH_WIDTH(b) ((b)->width) +#define FLASH_NDEVS(b) (FLASH_STRIDE(b)/FLASH_WIDTH(b)) + +/* Type declarations */ + +/* Registers */ +typedef uint8_t _u8_a_t __attribute__((may_alias)); +typedef uint16_t _u16_a_t __attribute__((may_alias)); +typedef uint32_t _u32_a_t __attribute__((may_alias)); + +/* Register addresses */ +typedef volatile _u8_a_t *A8; +typedef volatile _u16_a_t *A16; +typedef volatile _u32_a_t *A32; + +struct flash_bank_ops; + +/* + * Description of a flash bank. Multiple + * devices that are used in parallel to + * make up words of FLASH_STRIDE bytes + * are a 'physical' bank. + * + * A bank can even be a 'logical' bank + * if it includes chip-select logic, i.e., + * int can contain multiple adjacent + * 'physical' banks + * + * The BSP must provide an array of 'bankdesc' + * structs and it must initialize the fields + * + * 'start' + * size of bank; may be set to zero to instruct + * the driver to scan a bank of 'max_size' for + * devices (i.e., bank may not be fully populated) + * 'max_size' + * size of fully populated bank (defines address range + * that is scanned for devices). + * If 'max_size' is negative then scanning starts from + * the top rather than from the bottom. + * 'width' + * width of a single device (in bytes). E.g., if + * 2 16-bit devices are used to form a (ATM fixed) + * stride of 4 then 'width = 2'. If four 8-bit + * devices are employed then 'width=1'. + * 'knownVendors' + * array of vendors descriptions to use for scanning + * the bank. + * + */ +struct bankdesc { + uint32_t start; /* start of bank (CPU address) */ + uint32_t size; /* in bytes (figured out automatically) */ + int max_size; /* in case multiple banks are adjacent; + * if max_size < 0 then the bank is scanned + * backwards (from top->bottom) for devices + */ + int width; /* FIXME there might be implicit assumptions still + * that width == 2 + */ + struct vendesc *knownVendors; + /* TODO: we assume identical devices within a bank... */ + + /* The next three variables cache information obtained + * from the applicable vendor and device descriptions. + * They are written by BSP_flashCheckId(). + */ + uint32_t fblksz; /* block size in bytes; includes counting + * parallel 16-bit devices, i.e., if a + * single device has a block-size of xxx + * then fblksz = xxx*ndevs. + */ + struct devdesc *dd; + struct flash_bank_ops *ops; +}; + +struct devdesc { + uint32_t id; /* numerical ID (matched against + * ID read from device). + */ + char *name; /* informational name */ + uint32_t size; /* bytes */ + uint32_t bufsz; /* size of write buffer (bytes) */ + uint32_t fblksz; /* sector/block size (bytes) */ +}; + +struct vendesc { + uint32_t id; /* numerical ID (matched against + * ID read from device). + */ + char *name; /* informational name */ + + /* array of supported devices; + * the 'ops' specified below + * are used to access these devices + */ + struct devdesc *known_devs; + /* access methods for talking to + * devices associated with this + * vendor description. + */ + struct flash_bank_ops *ops; +}; + +/* Device Access Methods ('ops'); these must be + * implemented by low-level chip drivers + */ + +struct flash_bank_ops { +/* Read vendor/device ID; Return 0 on success, nonzero if unable to read id */ + int (*get_id)(struct bankdesc *b, uint32_t addr, uint32_t *pVendorId, uint32_t *pDeviceId); +/* Unlock block holding 'addr'ess + * + * NOTES: - device switched back to array mode on exit. + * - 'addr' must be 32-bit aligned. + */ + + void (*unlock_block)(struct bankdesc *b, uint32_t addr); +/* Lock block holding 'addr'ess + * + * NOTES: - device switched back to array mode on exit. + * - 'addr' must be 32-bit aligned. + */ + + void (*lock_block)(struct bankdesc *b, uint32_t addr); +/* Erase single block holding 'addr'ess. The routine may + * assume that the address is block/sector aligned. + * + * RETURNS: zero on error, device status on failure. + * + * NOTES: - device switched back to array mode on exit. + * - 'addr' must be 32-bit aligned. + */ + int (*erase_block)(struct bankdesc *b, uint32_t addr); +/* Query the status of the device and assert it's readiness + * leave off in array-reading mode. + * + * RETURNS: 0 on success, error status (result of status query) on error. + * + * NOTES: - error message is printed to stderr. + * - device switched back to array mode on exit. + * - 'addr' must be 32-bit aligned. + */ + uint32_t (*check_ready)(struct bankdesc *b, uint32_t addr); +/* Dump status bits (F_CMD_RD_STA results); + * 'verbose' prints non-error bits, too + */ + void (*print_stat)(struct bankdesc *b, uint32_t sta, int verbose); +/* Switch to array mode; 'addr' can be assumed to be stride-aligned */ + void (*array_mode)(struct bankdesc *b, uint32_t addr); +/* Write N bytes from 'src' to flash: + * 'src[0] .. src[N-1]' -> addr[0]..addr[N-1]. + * N may be assumed to be a multiple of 'stride' + * RETURNS: failure status or zero on success. + */ + uint32_t (*write_line)(struct bankdesc *b, uint32_t addr, char *src, uint32_t N); +}; + +/* BSP ops (detect banks, handle write-protection on board); + * these must be implemented by the BSP. + */ + +struct flash_bsp_ops { +/* Return descriptor for bank # 'bank' or NULL (invalid arg) */ + struct bankdesc *(*bankcheck)(int bank, int quiet); +/* set (enbl:1), clear (enbl:0) or query (enbl:-1) + * on-board write protection. + * + * RETURNS 0 on success, nonzero on error. + */ + int (*flash_wp)(int bank, int enbl); +/* read a running us clock (for polling timeout) */ + uint32_t (*read_us_timer)(); +}; + +/* This must be provided by the BSP */ +extern struct flash_bsp_ops BSP_flashBspOps; + +/* Available low-level flash drivers, so far */ +extern struct vendesc BSP_flash_vendor_intel[]; +extern struct vendesc BSP_flash_vendor_spansion[]; + +#endif diff --git a/c/src/lib/libbsp/powerpc/shared/flash/intelFlash.c b/c/src/lib/libbsp/powerpc/shared/flash/intelFlash.c new file mode 100644 index 0000000000..c0685b32f0 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/shared/flash/intelFlash.c @@ -0,0 +1,457 @@ +/* $Id$ */ + +/* + * Trivial driver for 16-bit intel flash present on the + * MVME5500/MVME6100 boards. + * + * For recognized devices, look for 'intelDevs'. + * + * This driver currently only supports stride=4 and 16-bit + * mode (width=2). + */ + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The software was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ +#ifdef TESTING + +#define TIMEOUT_US 100000 +#define rtems_task_wake_after(args...) do {} while (0) + +#else + +#include <rtems.h> +#define TIMEOUT_US 1000 + +#endif + +#include <stdio.h> +#include <inttypes.h> +#include <stdlib.h> + +#include <bsp/flashPgmPvt.h> + +#define DEBUG 0 +#undef DEBUG + +#ifdef DEBUG +#define STATIC +#else +#define STATIC static +#endif + +#define NumberOf(arr) (sizeof(arr)/sizeof(arr[0])) + +/* This driver assumes two 16-bit devices in parallel */ + +/********* Register Definitions ****************/ + +/* command codes */ +#define F_CMD_RD_ARR 0xffffffff /* back to 'normal' read mode */ +#define F_CMD_RD_ID 0x90909090 /* read from ID space */ +#define F_CMD_RD_STA 0x70707070 /* read status register */ +#define F_CMD_WR_STA 0x50505050 /* clear status register */ +#define F_CMD_WR_BUF 0xe8e8e8e8 /* write to buffer */ +#define F_CMD_WR_WRD 0x40404040 /* write word */ +#define F_CMD_WR_ERA 0x20202020 /* block erase */ +#define F_CMD_WR_LCK 0x60606060 /* lock bit (1st cycle) */ +#define F_CMD_WR_CMD 0xd0d0d0d0 /* commit erase */ +#define F_CMD_WR_LCK_SET 0x01010101 /* lock block commit */ + +/* Status codes (F_CMD_RD_STA result) */ +#define STA_RDY (1<<7) /* ready */ +#define STA_ES (1<<6) /* erase suspend */ +#define STA_EE (1<<5) /* erase error */ +#define STA_PE (1<<4) /* program error */ +#define STA_VE (1<<3) /* VPEN < min */ +#define STA_PS (1<<2) /* program susp. */ +#define STA_LE (1<<1) /* block locked */ +#define STA_EFP (1<<0) /* buf. EFP stat.*/ + +/* Any error */ +#define STA_ERROR (STA_EE|STA_PE|STA_VE|STA_LE) + +/* TODO: Code using RDYRDY assumes flash is 16-bit wide :-( */ +#define STA_RDYRDY 0x00800080 /* ready status on both devices */ + +/********* Forward Declarations ****************/ + +STATIC int +flash_get_id_intel(struct bankdesc *, uint32_t, uint32_t *, uint32_t *); + +STATIC void +flash_unlock_block_intel(struct bankdesc *, uint32_t); + +STATIC void +flash_lock_block_intel(struct bankdesc *, uint32_t); + +STATIC int +flash_erase_block_intel(struct bankdesc *, uint32_t); + +STATIC uint32_t +flash_check_ready_intel(struct bankdesc *, uint32_t); + +STATIC void +flash_print_stat_intel(struct bankdesc *, uint32_t, int); + +STATIC void +flash_array_mode_intel(struct bankdesc *, uint32_t); + +STATIC uint32_t +flash_write_line_intel(struct bankdesc *, uint32_t, char *, uint32_t); + +/********* Global Variables ********************/ + +static struct flash_bank_ops intelOps = { + get_id : flash_get_id_intel, + unlock_block: flash_unlock_block_intel, + lock_block : flash_lock_block_intel, + erase_block : flash_erase_block_intel, + check_ready : flash_check_ready_intel, + print_stat : flash_print_stat_intel, + array_mode : flash_array_mode_intel, + write_line : flash_write_line_intel, +}; + +static struct devdesc intelDevs[] = { + { 0x8801, "K3 64Mb", 8*1024*1024, 0x40, 0x20000 }, + { 0x8802, "K3 128Mb", 16*1024*1024, 0x40, 0x20000 }, + { 0x8803, "K3 256Mb", 32*1024*1024, 0x40, 0x20000 }, + { 0x8805, "K18 64Mb", 8*1024*1024, 0x40, 0x20000 }, + { 0x8806, "K18 128Mb", 16*1024*1024, 0x40, 0x20000 }, + { 0x8807, "K18 256Mb", 32*1024*1024, 0x40, 0x20000 }, + { 0x0016, "J3 32Mb", 4*1024*1024, 0x20, 0x20000 }, + { 0x0017, "J3 64Mb", 8*1024*1024, 0x20, 0x20000 }, + { 0x0018, "J3 128Mb", 16*1024*1024, 0x20, 0x20000 }, + { 0x001d, "J3 256Mb", 32*1024*1024, 0x20, 0x20000 }, + { 0, 0, 0, 0} +}; + +struct vendesc BSP_flash_vendor_intel[] = +{ + { 0x89, "Intel", intelDevs, &intelOps }, + { 0, 0} +}; + +/********* Helper Subroutines ******************/ + +/* Basic low-level access routine for writing a command to the + * internal state machine. + * + * Flash is slow, so who cares if these access routines + * are not extremely efficient... + */ +STATIC uint32_t +BSP_flashReadRaw(uint32_t cmd, uint32_t addr) +{ +#if DEBUG > 4 + printf("Writing CMD *0x%08"PRIx32" = 0x%08"PRIx32"\n", addr, cmd); +#endif +#ifdef TESTING + return STA_RDYRDY; +#else + if ( cmd & 0xffff0000 ) { + /* 32-bit access */ + addr &= ~(sizeof(uint32_t)-1); + *(A32)addr = cmd; + return *(A32)addr; + } else if ( cmd & 0xffffff00 ) { + /* 16-bit access */ + addr &= ~(sizeof(uint16_t)-1); + *(A16)addr = cmd; + return *(A16)addr; + } else { + *(A8)addr = cmd; + return *(A8)addr; + } +#endif +} + +STATIC void +BSP_flashWriteRaw(uint32_t val, uint32_t addr) +{ +#ifdef TESTING + printf("Writing CNT *0x%08"PRIx32" = 0x%08"PRIx32"\n", addr, val); +#else +/* TODO implicitly assumes FLASH_WIDTH = 2, FLASH_NDEVS = 2 */ + /* 32-bit access */ + addr &= ~(sizeof(uint32_t)-1); + *(A32)addr = val; +#endif +} + +STATIC uint32_t +flash_pend(struct bankdesc *b, uint32_t a, uint32_t timeout_us) +{ +uint32_t then, now, sta; + + then = BSP_flashBspOps.read_us_timer(); + + do { + sta = BSP_flashReadRaw(F_CMD_RD_STA, a); + now = BSP_flashBspOps.read_us_timer(); + if ( now-then > timeout_us ) { + /* timeout */ + sta = -1; + break; + } + } while ( STA_RDYRDY != (STA_RDYRDY & sta) ); + + /* switch back to normal mode */ + flash_array_mode_intel(b, a); + + return STA_RDYRDY == sta ? 0 : sta; +} + + +/********* Access Methods **********************/ + +STATIC void +flash_array_mode_intel(struct bankdesc *b, uint32_t a) +{ + BSP_flashReadRaw(F_CMD_RD_ARR, a); +} + +/* Dump status bits (F_CMD_RD_STA results); 'verbose' prints non-error bits, too */ +STATIC void +flash_print_stat_intel(struct bankdesc *b, uint32_t sta, int verbose) +{ +int ch; + if ( sta & STA_ERROR ) { + ch = ':'; + fprintf(stderr,"Errors found"); + if ( STA_EE & sta ) { + fprintf(stderr,"%c ERASE",ch); + ch = ','; + } + if ( STA_PE & sta ) { + fprintf(stderr,"%c PROGRAM",ch); + ch = ','; + } + if ( STA_VE & sta ) { + fprintf(stderr,"%c VPEN TOO LOW",ch); + ch = ','; + } + if ( STA_LE & sta ) { + fprintf(stderr,"%c BLOCK LOCKED",ch); + ch = ','; + } + fprintf(stderr,"\n"); + } + if ( verbose ) { + fprintf(stderr,"%sREADY\n",STA_RDY & sta ? "" : "NOT "); + } +} + + +/* Query the status of the device and assert it's readiness + * leave off in array-reading mode. + * + * RETURNS: 0 on success, error status (result of status query) on error. + * + * NOTES: - error message is printed to stderr. + * - device switched back to array mode on exit. + * - 'addr' must be 32-bit aligned. + */ +STATIC uint32_t +flash_check_ready_intel(struct bankdesc *b, uint32_t addr) +{ +uint32_t sta; + + (void)BSP_flashReadRaw(F_CMD_WR_STA, addr); + if ( STA_RDYRDY != (STA_RDYRDY & (sta=BSP_flashReadRaw(F_CMD_RD_STA, addr))) ) { + fprintf(stderr,"Flash not ready (@0x%08"PRIx32")\n", addr); + flash_print_stat_intel(b, sta, 0); + } else { + sta = 0; + } + /* switch back to normal mode */ + flash_array_mode_intel(b, addr); + return sta; +} + +/* Erase single block holding 'addr'ess + * + * RETURNS: zero on error, device status on failure. + * + * NOTES: - device switched back to array mode on exit. + * - 'addr' must be 32-bit aligned. + */ +STATIC int +flash_erase_block_intel(struct bankdesc *b, uint32_t addr) +{ +uint32_t sta; +int i; + if ( (sta = flash_check_ready_intel(b, addr)) ) + return sta; + + (void)BSP_flashReadRaw(F_CMD_WR_ERA, addr); + (void)BSP_flashReadRaw(F_CMD_WR_CMD, addr); + i = 50; + while ( STA_RDYRDY != (STA_RDYRDY & (sta = BSP_flashReadRaw(F_CMD_RD_STA, addr))) && --i > 0 ) { + rtems_task_wake_after(1); + } + /* switch back to 'normal' mode */ + (void)flash_array_mode_intel(b, addr); + if ( 0 == i ) { + fprintf(stderr,"Flash erase block: timeout\n"); + return -1; + } + + /* Verify */ + for ( i = 0; i<b->fblksz; i++ ) { + if ( (char)0xff != ((char*)addr)[i] ) { + fprintf(stderr,"ERROR: Erase verification failed at %p\n", + ((char*)addr) + i); + return -1; + } + } + return STA_RDYRDY == sta ? 0 : sta; +} + +/* Unlock block holding 'addr'ess + * + * NOTES: - device switched back to array mode on exit. + * - 'addr' must be 32-bit aligned. + */ + +STATIC void +flash_unlock_block_intel(struct bankdesc *b, uint32_t addr) +{ +#ifdef DEBUG + printf("Unlocking block 0x%08"PRIx32"\n", addr); +#endif + (void)BSP_flashReadRaw(F_CMD_WR_LCK, addr); + (void)BSP_flashReadRaw(F_CMD_WR_CMD, addr); + flash_pend(b, addr, TIMEOUT_US); +} + +/* Lock block holding 'addr'ess + * + * NOTES: - device switched back to array mode on exit. + * - 'addr' must be 32-bit aligned. + */ + +STATIC void +flash_lock_block_intel(struct bankdesc *b, uint32_t addr) +{ +#ifdef DEBUG + printf("Locking block 0x%08"PRIx32"\n", addr); +#endif + (void)BSP_flashReadRaw(F_CMD_WR_LCK, addr); + (void)BSP_flashReadRaw(F_CMD_WR_LCK_SET, addr); + flash_pend(b, addr, TIMEOUT_US); +} + +STATIC uint32_t +flash_write_line_intel(struct bankdesc *b, uint32_t a, char *s, uint32_t N) +{ +uint32_t sta, Nspla, nxt, j; +union { + uint32_t u; + char c[sizeof(uint32_t)]; +} buf; + + /* address block */ + if ( STA_RDYRDY != (sta = BSP_flashReadRaw(F_CMD_WR_BUF, a)) ) { + return sta; + } + + /* count per device */ + N /= FLASH_STRIDE(b); + + /* splat out */ + Nspla = (N<<8) | N; + Nspla = (Nspla<<16) | Nspla; + BSP_flashWriteRaw(Nspla - 0x01010101, a); + + /* fill buffer */ + for (nxt = a; N>0; N--) { +#if defined(TESTING) || (DEBUG > 4) + printf("Writing DAT *0x%08"PRIx32" = 0x%08"PRIx32"\n", nxt, *(uint32_t*)s); +#endif + /* deal with misaligned sources */ + for ( j=0; j<sizeof(buf.u); j++ ) { + buf.c[j] = *s++; + } + *(A32)nxt = buf.u; + nxt += FLASH_STRIDE(b); + } + + BSP_flashReadRaw(F_CMD_WR_CMD, a); + + sta = flash_pend(b, a, TIMEOUT_US); + + return sta; +} + +/* Query device for basic information verifying that we talk + * to a 'known'/'supported' device. + * + * NOTES: - device switched back to array mode on exit. + * - 'addr' must be 32-bit aligned. + */ + +STATIC int +flash_get_id_intel(struct bankdesc *b, uint32_t addr, uint32_t *pVendorId, uint32_t *pDeviceId) +{ +uint16_t v,d; + + if ( 4 != FLASH_STRIDE(b) ) { + fprintf(stderr,"intel flash programmer: Strides other than 4 not implemented yet\n"); + return -1; + } + + /* Try to read ID */ + v = BSP_flashReadRaw(F_CMD_RD_ID, addr); + d = BSP_flashReadRaw(F_CMD_RD_ID, addr + FLASH_STRIDE(b)); + + /* switch to array mode */ + flash_array_mode_intel(b, addr); + + *pVendorId = v; + *pDeviceId = d; + + return 0; +} diff --git a/c/src/lib/libbsp/powerpc/shared/flash/spansionFlash.c b/c/src/lib/libbsp/powerpc/shared/flash/spansionFlash.c new file mode 100644 index 0000000000..b7f9d4f6a2 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/shared/flash/spansionFlash.c @@ -0,0 +1,479 @@ +/* $Id$ */ + +/* + * Trivial driver for spansion flash present on the + * MVME3100 board. + * + * For recognized devices, look for 'spansionDevs'. + * + * This driver has only been tested with stride=4 + * and in 16-bit mode (width=2). + */ + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The software was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +#include <rtems.h> +#include <stdio.h> +#include <inttypes.h> + +#include <bsp/flashPgmPvt.h> + +#define DEBUG 5 +#undef DEBUG + +#ifdef DEBUG +#define STATIC +#else +#define STATIC static +#endif + +/* Manual says max erase time is 3.5 s */ +#define ERASE_TIMEOUT 4 /* seconds */ +#define WRITE_TIMEOUT 1000 /* us; manual says: 240us typ. */ + +/* Assume flash-endianness == CPU endianness */ + +#ifdef __PPC__ +#define IOSYNC(mem) do { asm volatile("eieio":"=m"(mem):"m"(mem)); } while (0) +#else +#define IOSYNC(mem) do { } while (0) +#endif + +/********* Forward Declarations ****************/ + +STATIC int +flash_get_id_s160(struct bankdesc *, uint32_t , uint32_t *, uint32_t *); + +STATIC void +flash_unlock_block_s160(struct bankdesc *, uint32_t); + +STATIC void +flash_lock_block_s160(struct bankdesc *, uint32_t); + +STATIC int +flash_erase_block_s160(struct bankdesc *, uint32_t); + +STATIC uint32_t +flash_check_ready_s160(struct bankdesc *, uint32_t); + +STATIC void +flash_print_stat_s160(struct bankdesc *, uint32_t, int); + +STATIC void +flash_array_mode_s160(struct bankdesc *, uint32_t); + +STATIC uint32_t +flash_write_line_s160(struct bankdesc *, uint32_t, char *, uint32_t); + +/********* Global Variables ********************/ + +static struct flash_bank_ops spansionOps = { + get_id : flash_get_id_s160, + unlock_block: flash_unlock_block_s160, + lock_block : flash_lock_block_s160, + erase_block : flash_erase_block_s160, + check_ready : flash_check_ready_s160, + print_stat : flash_print_stat_s160, + array_mode : flash_array_mode_s160, + write_line : flash_write_line_s160, +}; + +static struct devdesc spansionDevs[] = { + { 0x007e2101, "S29GL128N", 0x01000000, 32, 0x20000 }, /* 16MB */ + { 0x007e2201, "S29GL256N", 0x02000000, 32, 0x20000 }, /* 32MB */ + { 0x007e2301, "S29GL512N", 0x04000000, 32, 0x20000 }, /* 64MB */ + { 0, 0, 0, 0} +}; + +struct vendesc BSP_flash_vendor_spansion[] = { + { 0x01, "Spansion/AMD", spansionDevs, &spansionOps }, + { 0, 0} +}; + +/********* Register Definitions ****************/ + +#define UNLK1_ADDR_16 0x555 +#define UNLK1_DATA 0xaa +#define UNLK2_ADDR_16 0x2aa +#define UNLK2_ADDR_8 0x555 +#define UNLK2_DATA 0x55 +#define ASEL_DATA 0x90 +#define VEND_ID_ADDR_16 0x000 +#define SPROT_ADDR_16 0x002 +#define DEV1_ID_ADDR_16 0x001 +#define DEV2_ID_ADDR_16 0x00e +#define DEV3_ID_ADDR_16 0x00f +#define ERASE_DATA 0x80 +#define SECT_ERASE_DATA 0x30 +#define DQ7_DATA 0x80 +#define RESET_DATA 0xf0 +#define WRBUF_DATA 0x25 +#define PGBUF_DATA 0x29 + +#define DQ7_POLL_ALL (-1) + +/********* Helper Types ************************/ + +union bconv { + uint32_t u; + uint16_t s[2]; + char c[4]; +}; + +/********* Register Access Primitives **********/ + +/* All of these currently assume stride == 4, i.e. + * two 16-bit devices or 4 8-bit devices in parallel. + * + * FIXME: + * 8-bit mode and strides 1,2 untested. + */ + +#define ADDR32(b, a, o) ((a) + ((o)*FLASH_STRIDE(b))) + +static inline uint32_t +fl_rd32(struct bankdesc *b, uint32_t a, uint32_t off) +{ +volatile union bconv *p; +uint32_t rval; + + if ( 1 == b->width ) + off <<= 1;; + + a = ADDR32(b, a, off); + + p = (volatile union bconv *)a; + if ( 4 == FLASH_STRIDE(b) ) { + rval = p->u; + IOSYNC(p->u); + } else if ( 2 == FLASH_STRIDE(b) ) { + rval = p->s[0]; + IOSYNC(p->s[0]); + } else { + rval = p->c[0]; + IOSYNC(p->c[0]); + } + return rval; +} + +static inline void +fl_wr32(struct bankdesc *b, uint32_t a, uint32_t v) +{ +volatile union bconv *p = (volatile union bconv*)a; + if ( 4 == FLASH_STRIDE(b) ) { + p->u = v; + IOSYNC(p->u); + } else if ( 2 == FLASH_STRIDE(b) ) { + p->s[0] = v; + IOSYNC(p->s[0]); + } else { + p->c[0] = v; + IOSYNC(p->c[0]); + } +} + +static inline uint32_t +fl_splat32(struct bankdesc *b, uint32_t x) +{ + if ( 4 == FLASH_STRIDE(b) ) { + if ( 1 == b->width ) { + x = (x << 8) | x; + } + x = (x<<16) | x; + } else if ( 2 == FLASH_STRIDE(b) ) { + if ( 1 == b->width ) + x = (x << 8) | x; + } + return x; +} + +static inline uint32_t +fl_x32(struct bankdesc *b, union bconv *pv) +{ + if ( 4 == FLASH_STRIDE(b) ) + return pv->u; + else if ( 2 == FLASH_STRIDE(b) ) + return pv->s[0]; + else + return pv->c[0]; +} + +static inline void +fl_wr32_cmd(struct bankdesc *b, uint32_t a, uint32_t off, uint32_t cmd) +{ + if ( 1 == b->width ) { + if ( off == UNLK2_ADDR_16 ) + off = UNLK2_ADDR_8; + else + /* all others are simply left shifted */ + off <<= 1; + } + cmd = fl_splat32(b, cmd); + a = ADDR32(b, a, off); + fl_wr32(b, a, cmd); +} + +/* Send unlock sequence */ +static inline void unlk(struct bankdesc *b, uint32_t a) +{ + a &= ~ ( ADDR32(b, 0,0x1000) - 1 ); + fl_wr32_cmd(b, a, UNLK1_ADDR_16, UNLK1_DATA); + fl_wr32_cmd(b, a, UNLK2_ADDR_16, UNLK2_DATA); +} + +/********* Helper Routines *********************/ + +STATIC int +sector_is_protected(struct bankdesc *b, uint32_t addr) +{ +int rval; + unlk(b, addr); + fl_wr32_cmd(b, addr, UNLK1_ADDR_16, ASEL_DATA); + rval = fl_rd32(b, addr, SPROT_ADDR_16); + flash_array_mode_s160(b, addr); + return rval; +} + +STATIC int fl_dq7_poll(struct bankdesc *b, uint32_t addr, uint32_t d7_val) +{ + d7_val &= fl_splat32(b, DQ7_DATA); + return ( (fl_rd32(b, addr, 0) & fl_splat32(b, DQ7_DATA)) == d7_val ); +} + +/* Do DQ7 polling until DQ7 reads the value passed in d7_val + * or timeout + */ +STATIC int +flash_pend(struct bankdesc *b, uint32_t addr, uint32_t timeout_us, uint32_t d7_val) +{ +uint32_t then = BSP_flashBspOps.read_us_timer(); +uint32_t now = then; + + do { + if ( fl_dq7_poll(b, addr, d7_val) ) { +#if (DEBUG > 4) + printf("Write buffer succeded after %"PRIi32"us\n", (now-then)*8/333); +#endif + return 0; + } + now = BSP_flashBspOps.read_us_timer(); + } while ( now - then < timeout_us ); + + return -1; +} + + +/********* Access Methods **********************/ + +STATIC void +flash_array_mode_s160(struct bankdesc *b, uint32_t addr) +{ + fl_wr32_cmd(b, addr, 0, RESET_DATA); +} + +STATIC int +flash_get_id_s160(struct bankdesc *b, uint32_t addr, uint32_t *pVendorId, uint32_t *pDeviceId) +{ +uint32_t dev_id[3], x, i; + + if ( 4 != FLASH_STRIDE(b) ) + fprintf(stderr,"Warning: strides other than 4 untested\n(%s at %d)\n", + __FILE__,__LINE__); + + if ( 2 != b->width ) + fprintf(stderr,"Warning: device width other than 2 untested\n(%s at %d)\n", + __FILE__,__LINE__); + + addr &= ~ (ADDR32(b, 0, 0x1000) - 1); + unlk(b, addr); + fl_wr32_cmd(b, addr, UNLK1_ADDR_16, ASEL_DATA); + *pVendorId = fl_rd32(b, addr, VEND_ID_ADDR_16) & 0xff; + dev_id [0] = fl_rd32(b, addr, DEV1_ID_ADDR_16); + dev_id [1] = fl_rd32(b, addr, DEV2_ID_ADDR_16); + dev_id [2] = fl_rd32(b, addr, DEV3_ID_ADDR_16); + +#ifdef DEBUG + printf("Vendor Id 0x%08"PRIx32", Dev Ids: 0x%08"PRIx32", 0x%08"PRIx32", 0x%08"PRIx32"\n", + *pVendorId, dev_id[0], dev_id[1], dev_id[2]); +#endif + + flash_array_mode_s160(b, addr); + + for ( x=0, i=0; i<3; i++ ) { + x = (x<<8) | (dev_id[i] & 0xff); + } + + *pDeviceId = x; + + return 0; +} + + +STATIC void +flash_lock_block_s160(struct bankdesc *b, uint32_t addr) +{ +} + +STATIC void +flash_unlock_block_s160(struct bankdesc *b, uint32_t addr) +{ +} + +STATIC uint32_t +flash_check_ready_s160(struct bankdesc *b, uint32_t addr) +{ + flash_array_mode_s160(b, addr); + return 0; +} + +/* Erase single block holding 'addr'ess + * + * RETURNS: zero on error, device status on failure. + * + * NOTES: - device switched back to array mode on exit. + * - 'addr' must be 32-bit aligned. + */ +STATIC int +flash_erase_block_s160(struct bankdesc *b, uint32_t addr) +{ +rtems_interval p,i; + + addr &= ~ (b->fblksz-1); + + if ( sector_is_protected(b, addr) ) { + fprintf(stderr,"Sector at 0x%08"PRIx32" is protected\n", addr); + return -10; + } + + unlk(b, addr); + fl_wr32_cmd(b, addr, UNLK1_ADDR_16, ERASE_DATA); + unlk(b, addr); + fl_wr32_cmd(b, addr, 0, SECT_ERASE_DATA); + + rtems_clock_get( RTEMS_CLOCK_GET_TICKS_PER_SECOND, &p ); + p *= ERASE_TIMEOUT; + + for ( i=p; i; i-- ) { + rtems_task_wake_after(1); + if ( fl_dq7_poll(b, addr, DQ7_POLL_ALL) ) { + break; + } + } +#ifdef DEBUG + printf("ERASE polled for %"PRIi32" ticks\n", p-i); +#endif + flash_array_mode_s160(b, addr); + + if ( i ) { + /* write successful; verify */ + for ( i = 0; i < b->fblksz; i++ ) { + if ( 0xff != ((char*)addr)[i] ) { + fprintf(stderr,"ERROR: Erase verification failed at %p\n", + ((char*)addr) + i); + return -1; + } + } + return 0; + } + return -1; +} + +STATIC void +flash_print_stat_s160(struct bankdesc *b, uint32_t sta, int verbose) +{ + fprintf(stderr,"Flash Spansion 160 error %"PRIi32"\n", sta); +} + +STATIC uint32_t +flash_write_line_s160(struct bankdesc *b, uint32_t a, char *s, uint32_t N) +{ +uint32_t sta, nxt, j, v; +union bconv buf; + + if ( 0 == N ) + return -11; + + if ( N & (FLASH_STRIDE(b) - 1) ) { + fprintf(stderr,"flash_write_line_s160: invalid byte count (not multiple of stride\n"); + return -10; + } + + unlk(b, a); + + /* address block */ + fl_wr32_cmd(b, a, 0, WRBUF_DATA); + + /* (16-bit) word count per device */ + N /= FLASH_STRIDE(b); + + fl_wr32_cmd(b, a, 0, N-1); + + /* silence compiler warning about uninitialized var (N > 0 at this point) */ + v = 0; + + /* fill buffer */ + for (nxt = a; N>0; N--) { +#if (DEBUG > 4) + printf("Writing DAT *0x%08"PRIx32" = 0x%08"PRIx32"\n", nxt, *(uint32_t*)s); +#endif + /* deal with misaligned sources */ + for ( j=0; j<FLASH_STRIDE(b); j++ ) { + buf.c[j] = *s++; + } + v = fl_x32(b, &buf); + fl_wr32(b, nxt, v); + nxt += FLASH_STRIDE(b); + } + + /* burn buffer */ + fl_wr32_cmd(b, a, 0, PGBUF_DATA); + + /* pend */ + + sta = flash_pend(b, nxt - FLASH_STRIDE(b), WRITE_TIMEOUT, v); + + return sta; +} |