mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-06 07:33:17 +00:00
Add "(void) param;" annotation to address unused parameter warnings. Found with GCC's warning -Wunused-parameter.
912 lines
21 KiB
C
912 lines
21 KiB
C
/* 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 <unistd.h>
|
|
#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);
|
|
|
|
static struct bankdesc *
|
|
argcheck(int bank, uint32_t offset, const char *src, uint32_t size);
|
|
|
|
/* 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)
|
|
{
|
|
(void) b;
|
|
|
|
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(void)
|
|
{
|
|
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, const 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;
|
|
const 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);
|
|
}
|
|
b->start += max - rval;
|
|
}
|
|
return rval;
|
|
}
|
|
|
|
uint32_t
|
|
BSP_flashStart(int bank)
|
|
{
|
|
struct bankdesc *b;
|
|
if ( ! ( b = argcheck(bank, 0, 0, 0) ) )
|
|
return -1;
|
|
return b->start;
|
|
}
|
|
|
|
uint32_t
|
|
BSP_flashSize(int bank)
|
|
{
|
|
struct bankdesc *b;
|
|
if ( ! ( b = argcheck(bank, 0, 0, 0) ) )
|
|
return -1;
|
|
return b->size;
|
|
}
|
|
|
|
uint32_t
|
|
BSP_flashBlockSize(int bank)
|
|
{
|
|
struct bankdesc *b;
|
|
if ( ! ( b = argcheck(bank, 0, 0, 0) ) )
|
|
return -1;
|
|
return b->fblksz;
|
|
}
|
|
|
|
|
|
#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->size && !(b->size = BSP_flashProbeSize(b)) ) {
|
|
fprintf(stderr,"Configuration Error - unable to determine flash size\n");
|
|
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(int bank, uint32_t offset, const char *src, uint32_t size)
|
|
{
|
|
struct bankdesc *b;
|
|
|
|
if ( !(b=bankValidate(bank, 0)) ) {
|
|
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, const 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, const 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;
|
|
const 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(int 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 #%i)\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, const 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, const 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 = bankValidate(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
|