1
0
Files
irix-657m-src/stand/x86/ffsc/cdi/flash.c
2022-09-29 17:59:04 +03:00

974 lines
19 KiB
C

/*
** =======================================================================
** DERIVED FROM...
**
** Header Name : if00sxa.cpp
**
** Class Leniage : Storage
**
** Class Name : IntelFlashFileStorage
**
** Description : Methods for the IntelFlashFileStorage class
**
** Author : Kenneth J. Smith
**
** Creation Date : June 8, 1996
**
** Compiler Env. : Borland C++
**
** (c) Copyright Lines Unlimited
** 1996 All Rights Reserved
**
** BY JEFF BECKER, SGI
** =======================================================================
*/
#include <vxworks.h>
#include <iolib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysLib.h>
#include <timers.h>
#include "ffsc.h"
#include "flash.h"
/* struct timespec shortDelay = { 0, 10000 };*/
struct timespec shortDelay = { 0, 100000 };
/*struct timespec longDelay = { 0, 1600000 }; */
struct timespec longDelay = { 1, 0 };
/* struct timespec longDelay = { 1, 600000000 }; */
int socketArray[] = { 0x80,0x88,0x90,0x98,0xa0,0xa8,0xb0,0xb8,
0x01,0x09,0x11,0x19,0x21,0x29,0x31,0x39 };
int flashArray[] = { 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04 };
void initFlash(struct flashStruct *flash)
{
flash->flashVPP = FLASH_ENABLE_DEFAULT;
flash->deviceOpen = 0;
flash->numDevices = NUMDEVICES;
flash->position = 0;
flash->blockSize = BLOCK_SIZE_32K;
flash->deviceSocket = 1;
flash->pageSelectPort = PAGE_SELECT;
flash->VGAOn = RAM_VGA_ENABLE;
flash->VGAOff = RAM_VGA_DISABLE;
flash->windowSegment = 0x0a0000;
flash->deviceSize = 2048;
flash->SGISocket = socketArray;
flash->SGIFlash = flashArray;
}
/*char *
SGIRAMMap::OpenWindow( unsigned block, int access_mode ) */
/*
* Open the FLASH RAM window
*/
char *openFlashWindow( struct flashStruct *flash,
unsigned block, int access_mode )
{
unsigned long offset;
unsigned page, pageRegValue, segment;
char *retPtr;
/*
** Calculate the absolute offset from the block number and size
*/
offset = (long)block * flash->blockSize;
/*
** Range check the block requested
*/
if( offset > ( flash->deviceSize * 1024L ))
{
/*
** The requested block excedes the
** device size. Return NULL
*/
retPtr = NULL;
}
else
{
/*
** Now calculate which 128K page this offset falls into.
*/
page = offset / SIZE_128K;
/*
** Calculate a segment that starts where the requested
** block begins. Because the only valid block sizes
** are multiples of 16 they will always line up on
** a segment boundary.
*/
offset %= SIZE_128K;
/* segment = (unsigned)(flash->windowSegment + (offset >> 4 ));*/
segment = (unsigned)(flash->windowSegment + offset);
/*
** The return value is a pointer to where the requested
** block begins within the page.
*/
/* retPtr = (char *)MK_FP( segment, 0000 ); */
retPtr = (char *) (segment);
/*
** Disable VGA, thus enabeling access to the RAM/ROM sockets
*/
sysOutByte( flash->VGAOff, 0x0ff );
/*
** Set up the page register based on the device type
** specified
*/
pageRegValue = flash->SGISocket[page];
if ( access_mode == CMD_WRITE )
pageRegValue |= flash->SGIFlash[page];
sysOutByte( flash->pageSelectPort, pageRegValue );
}
/* delay( 10 ); */
nanosleep(&shortDelay, NULL);
return( retPtr );
}
/*
* Close the RAM/ROM window
*/
void
closeFlashWindow(struct flashStruct *flash)
{
unsigned pageRegValue;
/*
** Set Vppl on the first flash device
*/
pageRegValue = flash->SGISocket[0];
sysOutByte( flash->pageSelectPort, pageRegValue );
/*
** Set Vppl on the second flash device
*/
pageRegValue = flash->SGISocket[8];
sysOutByte( flash->pageSelectPort, pageRegValue );
/*
** Enable VGA, thus disabeling access to the RAM/ROM sockets
*/
sysOutByte( flash->VGAOn, 0x0ff );
/* delay( 10 ); */
nanosleep(&shortDelay, NULL);
}
/*
* Clear a block of Flash RAM
*/
int clearFlashBlock( struct flashStruct *flash,
int deviceBlock,
int FeedbackFD )
{
int i, j;
volatile unsigned char *flashPtr;
unsigned char statreg = 0;
/* Reiterate until the retry count is exceeded or we succeed */
for (i = 0; i < ffscTune[TUNE_CLEAR_FLASH_RETRY]; ++i) {
flashPtr = openFlashWindow( flash, deviceBlock, CMD_WRITE );
*flashPtr = CMD_CLR_STATUS;
nanosleep(&longDelay, NULL);
if (FeedbackFD >= 0) {
fdprintf(FeedbackFD, ".");
}
ffscMsgN(".");
*flashPtr = CMD_ERASE_SET;
nanosleep(&longDelay, NULL);
if (FeedbackFD >= 0) {
fdprintf(FeedbackFD, ".");
}
ffscMsgN(".");
*flashPtr = CMD_ERASE_CONF;
nanosleep(&longDelay, NULL);
if (FeedbackFD >= 0) {
fdprintf(FeedbackFD, ".");
}
ffscMsgN(".");
/*
** Loop until status is READY
*/
j = ffscTune[TUNE_CLEAR_FLASH_LOOPS];
flashPtr = openFlashWindow( flash, deviceBlock, CMD_READ );
while ( j-- ) {
statreg = *flashPtr;
if ( statreg & 0x80 ) {
break;
}
}
/*
** Timeout - status register never reset to READY
*/
if ( !j ) {
ffscMsg("Timed out waiting for deviceBlock %d",
deviceBlock);
return STATUS_REGISTER_ERROR;
}
/*
** Make sure the current Intel block was erased
*/
if ( ! (statreg & 0x20) ) {
/* The block was successfully erased - we are done */
if (FeedbackFD >= 0) {
fdprintf(FeedbackFD, ",");
}
ffscMsgN(",");
return STATUS_OK;
}
/* The block erase failed - try again */
ffscMsg("Got erase error for deviceBlock %d, %d loops",
deviceBlock,
ffscTune[TUNE_CLEAR_FLASH_LOOPS] - j);
if (FeedbackFD >= 0) {
fdprintf(FeedbackFD, "E");
}
}
return STATUS_ERASE_ERROR;
}
/*
* Set up for action. Make sure that there's an i28F00xsa device out there.
*/
int openFlash( struct flashStruct *flash, int mode, int FeedbackFD ) {
char *flashPtr1, *flashPtr2;
unsigned char lowStatus, highStatus;
int k,
flash2,
retVal,
deviceBlock;
/*
** Initialize
*/
flash2 = 1; /* Assume flash 2 is present until proven otherwise */
flash->deviceOpen = 1;
retVal = STATUS_OK; /* 0 */
/*
** Device starts with position 0
*/
flash->position = 0;
/*
** Attempt to detect each device by toggling the flash voltage and
** monitoring the voltage
**
** First attempt to get the status register with VPP disabled.
**
**
*/
/*
** Calculate current block
*/
deviceBlock = 0;
/*
** Open the current block for READ (FLASH DEVICE #1)
*/
flashPtr1 = openFlashWindow( flash, deviceBlock, CMD_READ );
/*
** Get the intelligent identifier bytes ( 0x89 and 0xa2 )
*/
*flashPtr1 = CMD_IDENT;
lowStatus = *flashPtr1;
highStatus = *(flashPtr1 + 1);
/*
** Reset the device for READ
*/
*flashPtr1 = CMD_READ;
/*
** Make sure the correct identifier was read
*/
if ( lowStatus != 0x89 || highStatus != 0xa2 )
{
retVal = STATUS_IDENTIFIER_ERROR;
goto done;
}
/*
** Open the current block for READ (FLASH DEVICE #2)
*/
flashPtr2 = openFlashWindow( flash, deviceBlock+32, CMD_READ );
*flashPtr2 = CMD_IDENT;
lowStatus = *flashPtr2;
highStatus = *(flashPtr2 + 1);
*flashPtr2 = CMD_READ;
if ( lowStatus != 0x89 || highStatus != 0xa2 )
flash2 = 0; /* Flash 2 isn't on-board */
/*
** The first flash device was found, we may proceed.
** The second device may or may not have been found.
*/
/*
** If open for WRITE mode, clear all data form device(s)
*/
if ( mode == WRITE_MODE ) {
/*
** Say what we are about to do if desired
*/
ffscMsg("Clearing flash storage");
if (FeedbackFD >= 0) {
fdprintf(FeedbackFD,
"\r\n"
"Clearing non-volatile storage\r\n"
"This will take approximately 100 seconds\r\n");
}
/*
** The flash is divided into blocks ( 64K x 16 )
*/
for ( k = 0; k < INTEL_BLOCKS; k++ ) {
/*
** The CDI blocks are 32K so only write to every
** other block which will clear Intel 64K blocks
*/
deviceBlock = ( k * 2 );
retVal = clearFlashBlock(flash, deviceBlock, FeedbackFD);
if (retVal != STATUS_OK) {
ffscMsg("Unable to clear block %d/1", k);
goto done;
}
if (flash2) {
retVal = clearFlashBlock(flash,
deviceBlock+32,
FeedbackFD);
if (retVal != STATUS_OK) {
ffscMsg("Unable to clear block %d/2", k);
goto done;
}
}
}
}
done:
closeFlashWindow(flash);
return ( retVal );
}
/*
*close flash device
*/
int
closeFlash(struct flashStruct *flash)
{
/*
** Make sure the device is closed
*/
closeFlashWindow(flash);
flash->deviceOpen = 0;
return STATUS_OK;
}
int
readFlash( struct flashStruct *flash, char *data, unsigned length )
{
unsigned blockSize = flash->blockSize;
unsigned block, remain, offset;
char *devicePtr, *dataPtr = data;
int status;
/*
** First, it's very possible that our current position
** is not on a block boundary.
**
** We will determine what block we are in and how far
** from the boundary we are. If the requested data length
** fits within the rest of the block then everything's OK.
** Otherwise we will need to start a block reading loop
*/
status = STATUS_OK;
block = flash->position / blockSize;
offset = flash->position % blockSize;
remain = blockSize - offset;
/*
** Open the RAM/ROM window
*/
if ((devicePtr = openFlashWindow( flash, block, CMD_READ )))
{
/*
** move our pointer to the byte
** we want
*/
devicePtr += offset;
if( length <= remain )
{
/*
** We can get the data in one chunk!
**
** Move the device data to the buffer
*/
bcopy( devicePtr, dataPtr, length );
/*
** Update the position
*/
flash->position += length;
status = STATUS_OK;
}
else
{
/*
** The data is bigger than the block so
** we need to bring it in block by block.
**
** Move the rest of this block to the buffer
*/
bcopy( devicePtr, dataPtr, remain );
/*
** Update the position
*/
flash->position += remain;
/*
** reduce our remaining length
*/
length -= remain;
/*
** Update data pointer
*/
dataPtr += remain;
/*
** We are now lined up on a block boundary
** so as long as the remaining length is
** at least as long as a block we can just
** eat blocks.
*/
while( length >= blockSize )
{
block = flash->position / blockSize;
devicePtr = openFlashWindow( flash, block, CMD_READ );
/*
** Read in the whole block
*/
bcopy( devicePtr, dataPtr, blockSize );
/*
** Update the position
*/
flash->position += blockSize;
/*
** reduce our remaining length
*/
length -= blockSize;
/*
** Update data pointer
*/
dataPtr += blockSize;
}
/*
** Our last bit of data did not fill a whole
** block (if any data is left at all)
** We are still on a block boundary so
** just read in the rest of it
*/
if( length )
{
block = flash->position / blockSize;
devicePtr = openFlashWindow( flash, block, CMD_READ );
/*
** Read in the whole block
*/
bcopy( devicePtr, dataPtr, length );
/*
** Update the position
*/
flash->position += length;
/*
** Update data pointer
*/
dataPtr += length;
}
}
}
else
{
/*
** Couldn't open the map window
*/
status = STATUS_OPEN_WINDOW_ERROR;
}
/*
** Close the window down
*/
closeFlashWindow(flash);
return( status );
}
int
writeFlashBytes( char *writePtr, char *dataPtr, unsigned lng)
{
int i,j,k,
retry,
retVal;
unsigned char status;
char *statReg;
/*
** Initialize
*/
retVal = WRITE_OK; /* 0 */
retry = RETRY_LIMIT; /* 100 */
statReg = writePtr;
/*
** Copy each byte of the data string to the Flash ROM
*/
for ( i = 0, k=0; i < lng;)
{
/*
** Clear the Status Register
*/
*statReg = CMD_CLR_STATUS;
/*
** Loop until the Write State Machine Status is READY (0x80)
*/
j = LOOP_DOWN; /* 10000 */
while ( j-- )
{
*statReg = CMD_CLR_STATUS;
*statReg = CMD_READ_STATUS;
status = *statReg;
if ( status & 0x80 )
break;
}
/*
** The unable to clear the status register
*/
if ( !j )
{
retVal = CLEAR_STATUS_ERROR;
goto done;
}
/*
** Clear the Status Register
*/
*statReg = CMD_CLR_STATUS;
/*
** Byte write setup plus byte write
*/
*writePtr = CMD_WRITE;
*writePtr = *dataPtr;
/*
** Loop until the Write State Machine Status is READY (0x80)
*/
j = LOOP_DOWN;
while ( j-- )
{
*statReg = CMD_CLR_STATUS;
*statReg = CMD_READ_STATUS;
status = *statReg;
if ( status & 0x80 )
break;
}
/*
** Unable to get a Write state machine status of READY (0x80)
*/
if ( !j )
{
retVal = WRITE_STATUS_READY_ERROR;
goto done;
}
/*
** Byte Write status error
*/
if ( status & 0x10 )
retVal = WRITE_ERROR;
/*
** Byte Write status ok
*/
else
{
/*
** Make sure the data byte was stored properly
*/
*statReg = CMD_READ;
if ( *writePtr != *dataPtr )
{
retVal = DATA_NOT_EQUAL_ERROR;
if ( !(--retry) )
goto done;
}
/*
** Byte written successfully, increment pointers & counters
*/
else
{
retry = LOOP_DOWN; /* 10000 */
i++; k++;
writePtr++; dataPtr++;
}
}
/*
** End FOR loop
*/
}
done:
return ( retVal );
}
int
writeFlash( struct flashStruct *flash, char *data, unsigned length )
{
unsigned blockSize = flash->blockSize;
unsigned block, remain, offset;
char *devicePtr, *dataPtr = data, status;
/*
** First, it's very possible that our current position
** is not on a block boundary.
**
** We will determine what block we are in and how far
** from the boundary we are. If the requested data length
** fits within the rest of the block then everything's OK.
** Otherwise we will need to start a block reading loop
*/
status = STATUS_OK;
block = flash->position / blockSize;
offset = flash->position % blockSize;
remain = blockSize - offset;
/*
** Open the RAM/ROM window
*/
if ((devicePtr = openFlashWindow( flash, block, CMD_WRITE )))
{
/*
** move our pointer to the byte
** we want
*/
devicePtr += offset;
if( length <= remain )
{
/*
** We can get the data in one chunck!
**
** Move the device data to the buffer
*/
if ( (status = writeFlashBytes( devicePtr, dataPtr, length )) )
{
goto done;
}
/*
** Update the position
*/
flash->position += length;
}
else
{
/*
** The data is bigger than the block so
** we need to bring it in block by block.
**
** Move the rest of this block to the buffer
*/
if ( (status = writeFlashBytes( devicePtr, dataPtr, length ) ) )
{
goto done;
}
/*
** Update the position
*/
flash->position += remain;
/*
** reduce our remaining length
*/
length -= remain;
/*
** Update data pointer
*/
dataPtr += remain;
/*
** We are now lined up on a block boundary
** so as long as the remaining length is
** at least as long as a block we can just
** eat blocks.
*/
while( length >= blockSize )
{
block = flash->position / blockSize;
devicePtr = openFlashWindow( flash, block, CMD_WRITE );
/*
** Read in the whole block
*/
if ( (status = writeFlashBytes( devicePtr, dataPtr, length )) )
{
goto done;
}
/*
** Update the position
*/
flash->position += blockSize;
/*
** reduce our remaining length
*/
length -= blockSize;
/*
** Update data pointer
*/
dataPtr += blockSize;
}
/*
** Our last bit of data did not fill a whole
** block (if any data is left at all)
** We are still on a block boundary so
** just read in the rest of it
*/
if( length )
{
block = flash->position / blockSize;
devicePtr = openFlashWindow( flash, block, CMD_WRITE );
/*
** Read in the whole block
*/
if ( (status = writeFlashBytes( devicePtr, dataPtr, length )) )
{
goto done;
}
/*
** Update the position
*/
flash->position += length;
/*
** Update data pointer
*/
dataPtr += length;
}
}
}
else
{
/*
** Couldn't open the map window
*/
status = STATUS_OPEN_WINDOW_ERROR;
}
done:
/*
** Close the window down
*/
closeFlashWindow(flash);
return( status );
}
/* flashtest: a simple command to see if flash is doing writes properly -
numK <= 64 should work */
void flashtest(int numK)
{
int bufsize, i, result;
int offset;
struct flashStruct slashTheFlash;
unsigned char *stuff;
bufsize = 1024 * numK;
ffscMsg("numK is %d, bufsize is %d", numK, bufsize);
stuff = malloc(bufsize);
for (i=0; i<bufsize; i++)
stuff[i] = i%201;
initFlash(&slashTheFlash);
result = openFlash(&slashTheFlash, WRITE_MODE, -1);
ffscMsg("openFlash returned %d", result);
if (result >= 0 ) {
for (offset = 0; offset < bufsize; offset += 128) {
result = writeFlash(&slashTheFlash, stuff+offset, 128);
ffscMsg("Offset=%d Position=%ld Result=%d",
offset, slashTheFlash.position, result);
if (result < 0) {
return;
}
}
}
if (result >= 0 ) {
slashTheFlash.position = 0;
for (offset = 0; offset < bufsize && result >= 0; offset+=128) {
result = readFlash(&slashTheFlash, stuff+offset, 128);
ffscMsg("Offset=%d Position=%ld Result=%d",
offset, slashTheFlash.position, result);
}
if (result >= 0) {
for (i=0; i<bufsize; i++) {
if (stuff[i] != i%201) {
ffscMsg("Bad read at i=%d", i);
return;
}
}
ffscMsg("Buffer reads as written!");
}
}
}