mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-05 23:23:13 +00:00
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.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
877
c/src/lib/libbsp/powerpc/shared/flash/flash.c
Normal file
877
c/src/lib/libbsp/powerpc/shared/flash/flash.c
Normal file
@@ -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
|
||||
185
c/src/lib/libbsp/powerpc/shared/flash/flashPgm.h
Normal file
185
c/src/lib/libbsp/powerpc/shared/flash/flashPgm.h
Normal file
@@ -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
|
||||
275
c/src/lib/libbsp/powerpc/shared/flash/flashPgmPvt.h
Normal file
275
c/src/lib/libbsp/powerpc/shared/flash/flashPgmPvt.h
Normal file
@@ -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
|
||||
457
c/src/lib/libbsp/powerpc/shared/flash/intelFlash.c
Normal file
457
c/src/lib/libbsp/powerpc/shared/flash/intelFlash.c
Normal file
@@ -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;
|
||||
}
|
||||
479
c/src/lib/libbsp/powerpc/shared/flash/spansionFlash.c
Normal file
479
c/src/lib/libbsp/powerpc/shared/flash/spansionFlash.c
Normal file
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user