|
/////////////////////////////////////////////////////////////// // // TS101EzFlash.c // // Analog Devices, Inc. - 2002 // // Rev - 1.00.0 // // Fixes in this Release // // // Change Log // // 1.00.0 // - initial release // // VisualDSP++ "Flash Programmer" flash driver for use with the // ADSP-TS101S EZ-KIT Lite containing the STMicroelectronics DSM2150 // flash device. // // NOTE: In order to use inline assembly the compiler otion // -flags-compiler --allow_asm must be added in project options. // Also, there are warnings for each line ofinline assembly, which // is supposed to be addressed in VisualDSP 3.0 for TigerSHARC. // The warnings should not affect the functionality of our driver. // ///////////////////////////////////////////////////////////////
#include <signal.h> #include <defts101.h>
// #defines #define TRUE 0x1 #define FALSE 0x0 #define NULL 0x0 #define BUFFER_SIZE 0x2000
// Flash Programmer commands #define NO_COMMAND 0 #define GET_CODES 1 #define RESET 2 #define WRITE 3 #define FILL 4 #define ERASE_ALL 5 #define ERASE_SECT 6 #define READ 7 #define GET_SECTNUM 8
// function prototypes bool SetupForFlash(); bool GetCodes(); bool PollToggleBit(long lOffset, int nValue); bool ResetFlash(); bool EraseFlash(); bool EraseBlock( int nBlock ); bool UnlockFlash(long lOffset); bool WriteData( long lStart, long lCount, long lStride, int *pnData ); bool FillData( long lStart, long lCount, long lStride, int *pnData ); bool ReadData( long lStart, long lCount, long lStride, int *pnData ); bool ReadFlash( long lOffset, int *pnValue ); bool WriteFlash( long lOffset, int nValue ); bool GetSectorNumber( long lOffset, int *pnSector );
// used for debugging purposes bool ReadToInternal(long lOffset, long lCount, long lStride);
// DMA interrupt handler void dma_int_0( int nothing );
// sets up DMA registers void do_dma();
// global data for use with the VisualDSP++ plug-in char AFP_Title[] = "ADSP-TS101 MP SYSTEM"; char AFP_Description[] = "HY. 29LV160"; int AFP_Command = NO_COMMAND; int AFP_ManCode = -1; // 0x20 = STMicroelectronics int AFP_DevCode = -1; // 0xE8 = DSM2150V long AFP_Offset = 0x0; int *AFP_Buffer; long AFP_Size = BUFFER_SIZE; long AFP_Count = -1; long AFP_Stride = -1; int AFP_NumSectors = 34; long AFP_SectorSize1 = 0x10000; int AFP_Sector = -1;
// this is a temporary storage variable section ("data1") int temp_stor;
// exit flag bool bExit = FALSE;
main() { // by making AFP_Buffer as big as possible the plug-in can send and // receive more data at a time making the data transfer quicker // // by allocating it on the heap the compiler does not create an // initialized array therefore making the driver image smaller // and faster to load // // we have modified the linker description file (LDF) so that the heap // is large enough to store BUFFER_SIZE elements at this point
AFP_Buffer = (int *)malloc(BUFFER_SIZE);
// AFP_Buffer will be NULL if we could not allocate storage for the // buffer
// setup the flash so the DSP can access it SetupForFlash();
// command processing loop while ( !bExit ) { // the plug-in will set a breakpoint at "AFP_BreakReady" so it knows // when we are ready for a new command because the DSP will halt // // the jump is used so that the label will be part of the debug // information in the driver image otherwise it may be left out // since the label is not referenced anywhere asm("AFP_BreakReady:"); if ( FALSE ) asm("jump AFP_BreakReady;;");
// switch on the command switch ( AFP_Command ) { // get manufacturer and device codes case GET_CODES: GetCodes(); break;
// reset case RESET: ResetFlash(); break;
// write case WRITE: WriteData( AFP_Offset, AFP_Count, AFP_Stride, AFP_Buffer ); ReadToInternal(AFP_Offset, AFP_Count, AFP_Stride); break;
// fill case FILL: FillData( AFP_Offset, AFP_Count, AFP_Stride, AFP_Buffer ); ReadToInternal(AFP_Offset, AFP_Count, AFP_Stride); break;
// erase all case ERASE_ALL: EraseFlash(); break;
// erase sector case ERASE_SECT: EraseBlock( AFP_Sector ); break;
// read case READ: ReadData( AFP_Offset, AFP_Count, AFP_Stride, AFP_Buffer ); break;
// get sector number based on address case GET_SECTNUM: GetSectorNumber( AFP_Offset, &AFP_Sector );
// no command or unknown command do nothing case NO_COMMAND: default: break; }
// clear the command AFP_Command = NO_COMMAND; }
// free the buffer if we were able to allocate one if ( AFP_Buffer ) free( AFP_Buffer );
// all done return 0; }
////////////////////////////////////////////////////////////// // bool SetupForFlash() // // Perform necessary setup for the processor to talk to the // flash such as external memory interface registers, etc. // //////////////////////////////////////////////////////////////
bool SetupForFlash() { asm("#include <defines.h>");
asm("xr0 = IMASKL;;"); // read current value asm("xr0 = bset r0 by INTDMA0;;"); // set DMA0 interrupt mask asm("IMASKL = xr0;;"); // set new value in IMASKL asm("xr0 = IMASKH;;"); // read current value asm("xr0 = bset r0 by INTGLOBAL;;"); // set global interrupts asm("IMASKH = xr0;;"); // set new value in IMASKH
interrupt( SIGDMA0, dma_int_0 ); // set DMA interrupt vector
return TRUE; }
////////////////////////////////////////////////////////////// // bool WriteData() // // Write a buffer to flash. // // Inputs: long lStart - offset in flash to start the writes at // long lCount - number of elements to write, in this case bytes // long lStride - number of locations to skip between writes // int *pnData - pointer to data buffer // //////////////////////////////////////////////////////////////
bool WriteData( long lStart, long lCount, long lStride, int *pnData ) { long i = 0; // loop counter long lOffset = lStart; // current offset to write
long temp = 0;
// write the buffer up to BUFFER_SIZE items for (i = 0; (i < lCount) && (i < BUFFER_SIZE); i++, lOffset += lStride) { // unlock the flash, do the write, and wait for completion UnlockFlash( lOffset ); WriteFlash( lOffset, pnData[i] ); PollToggleBit( lOffset, pnData[i] ); }
// ok return TRUE; }
////////////////////////////////////////////////////////////// // bool FillData() // // Fill flash with a value. // // Inputs: long lStart - offset in flash to start the writes at // long lCount - number of elements to write, in this case bytes // long lStride - number of locations to skip between writes // int *pnData - pointer to data buffer // //////////////////////////////////////////////////////////////
bool FillData( long lStart, long lCount, long lStride, int *pnData ) { long i = 0; // loop counter long lOffset = lStart; // current offset to write
// fill the value for (i = 0; i < lCount; i++, lOffset += lStride) { // unlock the flash, do the write, and wait for completion UnlockFlash( lOffset ); WriteFlash( lOffset, pnData[0] ); PollToggleBit( lOffset, pnData[0] ); }
// ok return TRUE; }
////////////////////////////////////////////////////////////// // bool ReadData() // // Read a buffer from flash. // // Inputs: long lStart - offset in flash to start the reads at // long lCount - number of elements to read, in this case bytes // long lStride - number of locations to skip between reads // int *pnData - pointer to data buffer to fill // //////////////////////////////////////////////////////////////
bool ReadData( long lStart, long lCount, long lStride, int *pnData ) { long i = 0; // loop counter long lOffset = lStart; // current offset to write
// read the buffer up to BUFFER_SIZE items for (i = 0; (i < lCount) && (i < BUFFER_SIZE); i++, lOffset += lStride) { // do the read ReadFlash( lOffset, &pnData[i] ); }
// ok return TRUE; }
////////////////////////////////////////////////////////////// // bool WriteFlash() // // Write a value to an offset in flash. // // Inputs: long lOffset - offset to write to // int nValue - value to write // //////////////////////////////////////////////////////////////
bool WriteFlash( long lOffset, int nValue ) {
asm("[j31 + _temp_stor] = j5;;"); // put the data into _temp_stor
asm("xr0 = _temp_stor;;"); // xr0 = source index asm("xr1 = 0x00010001;;"); // count = 1, modify = 1 asm("xr2 = 0x0;;"); // not used asm("xr3 = 0x43000000;;"); // int mem,prio=norm,2D=no,word=norm,int=yes,RQ=dsbl,chain=no asm("xr4 = j4;;"); // xr4 = destination index asm("xr5 = 0x00010001;;"); // count = 1, modify = 1 asm("xr6 = 0x0;;"); // not used asm("xr7 = 0xc3000000;;"); // boot rom,prio=norm,2D=no,word=norm,int=yes,RQ=dsbl,chain=no
do_dma(); // do dma transfer
// ok return TRUE; }
////////////////////////////////////////////////////////////// // bool ReadFlash() // // Read a value from an offset in flash. // // Inputs: long lOffset - offset to read from // int pnValue - pointer to store value read from flash // //////////////////////////////////////////////////////////////
bool ReadFlash( long lOffset, int *pnValue ) { // temp holder int nValue = 0x0;
asm("xr0 = j4;;"); // xr0 = source index, j4 = nOffset asm("xr1 = 0x00010001;;"); // count = 1, modify = 1 asm("xr2 = 0x0;;"); // not used asm("xr3 = 0xc3000000;;"); // boot rom,prio=norm,2D=no,word=norm,int=yes,RQ=dsbl,chain=no asm("xr4 = _temp_stor;;"); // xr4 = destination index asm("xr5 = 0x00010001;;"); // count = 1, modify = 1 asm("xr6 = 0x0;;"); // not used asm("xr7 = 0x43000000;;"); // int mem,prio=norm,2D=no,word=norm,int=yes,RQ=dsbl,chain=no
do_dma();
// put the value at the location passed in *pnValue = temp_stor;
// ok return TRUE; }
////////////////////////////////////////////////////////////// // bool PollToggleBit() // // Polls to see if the value read equals the value written // // Inputs: int nOffset - offset to read from // int nValue - value of data written // //////////////////////////////////////////////////////////////
bool PollToggleBit(long lOffset, int nValue ) { bool bError = FALSE; // flag to indicate error
// read valid address in the range written to asm ("POLL_TOGGLE_BIT:"); asm("xr0 = j4;;"); // xr0 = source index, j4 = lOffset asm("xr1 = 0x00010001;;"); // count = 1, modify = 1 asm("xr2 = 0x0;;"); // not used asm("xr3 = 0xc3000000;;"); // boot rom,prio=norm,2D=no,word=norm,int=yes,RQ=dsbl,chain=no asm("xr4 = _temp_stor;;"); // xr4 = destination index asm("xr5 = 0x00010001;;"); // count = 1, modify = 1 asm("xr6 = 0x0;;"); // not used asm("xr7 = 0x43000000;;"); // int mem,prio=norm,2D=no,word=norm,int=yes,RQ=dsbl,chain=no
do_dma(); // read the value
asm("j0 = [j31 + _temp_stor];;"); // get data that was read
asm("xr0 = j0;;"); // need to be in compute block regs asm("xr1 = j5;;"); // put data being set into xr1
asm("r1 = r0 xor r1;;"); // find out what bits toggled
// see if the data is toggling asm ("BITEST r1 by 7;;"); asm("if xSEQ, jump DONE_TOGGLE_BIT; nop; nop; nop;;");
// see if there was an error asm ("BITEST r0 by 5;;"); asm("if xSEQ, jump POLL_TOGGLE_BIT; nop; nop; nop;;");
// do another read asm("xr0 = j4;;"); // xr0 = source index, j4 = lOffset asm("xr1 = 0x00010001;;"); // count = 1, modify = 1 asm("xr2 = 0x0;;"); // not used asm("xr3 = 0xc3000000;;"); // boot rom,prio=norm,2D=no,word=norm,int=yes,RQ=dsbl,chain=no asm("xr4 = _temp_stor;;"); // xr4 = destination index asm("xr5 = 0x00010001;;"); // count = 1, modify = 1 asm("xr6 = 0x0;;"); // not used asm("xr7 = 0x43000000;;"); // int mem,prio=norm,2D=no,word=norm,int=yes,RQ=dsbl,chain=no
do_dma(); // read the value
asm("j0 = [j31 + _temp_stor];;"); // get data read
asm("xr0 = j0;;"); // need to be in compute block regs asm("xr1 = j5;;"); // put data being set into xr1
asm("r1 = r0 xor r1;;"); // find out what bits toggled
// see if data is still toggling asm ("BITEST r1 by 7;;"); asm("if xSEQ, jump DONE_TOGGLE_BIT; nop; nop; nop;;");
// else we have failed, restore page, set error flag, and reset bError = TRUE; ResetFlash();
asm ("DONE_TOGGLE_BIT:");
// we can return return !bError; }
////////////////////////////////////////////////////////////// // bool ResetFlash() // // Sends a "reset" command to the flash. // //////////////////////////////////////////////////////////////
bool ResetFlash() { // send the reset command to the flash WriteFlash( 0x0AAA, 0xf0 );
// reset should be complete return TRUE; }
////////////////////////////////////////////////////////////// // bool EraseFlash() // // Sends an "erase all" command to the flash. // //////////////////////////////////////////////////////////////
bool EraseFlash() { // erase contents in Main Flash Array WriteFlash( 0x0aaa, 0xaa ); WriteFlash( 0x0555, 0x55 ); WriteFlash( 0x0aaa, 0x80 ); WriteFlash( 0x0aaa, 0xaa ); WriteFlash( 0x0555, 0x55 ); WriteFlash( 0x0aaa, 0x10 );
// poll until the command has completed PollToggleBit(0x0000, 0x80);
// erase should be complete return TRUE; }
////////////////////////////////////////////////////////////// // bool EraseBlock() // // Sends an "erase block" command to the flash. // // Inputs: int nBlock - block to erase // //////////////////////////////////////////////////////////////
bool EraseBlock( int nBlock ) { long lSectorOff = 0x0;
// if the block is invalid just return if ( (nBlock < 0) || (nBlock > AFP_NumSectors) ) return FALSE;
// block is in valid Flash Array if ( (nBlock >= 0) && (nBlock < 34) ) { // send the erase block command to the flash WriteFlash( 0x0aaa, 0xaa ); WriteFlash( 0x0555, 0x55 ); WriteFlash( 0x0aaa, 0x80 ); WriteFlash( 0x0aaa, 0xaa ); WriteFlash( 0x0555, 0x55 );
// the last write has to be at an address in the block // we want to erase lSectorOff = (nBlock * AFP_SectorSize1); WriteFlash( lSectorOff, 0x30 );
// poll until the command has completed PollToggleBit(lSectorOff, 0x80); } // block is in Boot Flash Array else { }
// block erase should be complete return TRUE; }
////////////////////////////////////////////////////////////// // bool UnlockFlash() // // Sends an "unlock" command to the flash to allow the flash // to be programmed. // // Inputs: long lOffset - offset to unlock // //////////////////////////////////////////////////////////////
bool UnlockFlash(long lOffset) { long lOffsetAddr = lOffset; lOffsetAddr &= 0x000F0000;
// send the unlock command to the flash // ORed with lOffsetAddr so we know what block we are in WriteFlash( (0x0aaa | lOffsetAddr), 0xaa ); WriteFlash( (0x0555 | lOffsetAddr), 0x55 ); WriteFlash( (0x0aaa | lOffsetAddr), 0xa0 );
// ok return TRUE; }
////////////////////////////////////////////////////////////// // bool GetCodes() // // Sends an "auto select" command to the flash which will allow // us to get the manufacturer and device codes. // //////////////////////////////////////////////////////////////
bool GetCodes() { int tmp; // send the auto select command to the flash WriteFlash( 0x0aaa, 0xaa ); WriteFlash( 0x0555, 0x55 ); WriteFlash( 0x0aaa, 0x90 ); // now we can read the codes ReadFlash( 0x0000, &AFP_DevCode ); tmp = AFP_DevCode; AFP_DevCode = (tmp>>16) & 0x00FF;
// there is no ManCode that can be read so make it 0x20 AFP_ManCode = tmp & 0x00FF;
// we need to issue another command to get the part out // of auto select mode so issue a reset which just puts // the device back in read mode ResetFlash();
// ok return TRUE; }
////////////////////////////////////////////////////////////// // bool GetSectorNumber() // // Gets a sector number based on the offset. // // Inputs: long lOffset - offset in the sector // int *pnSector - sector number // //////////////////////////////////////////////////////////////
bool GetSectorNumber( long lOffset, int *pnSector ) { int nSector = 0;
// determine the sector nSector = lOffset & 0xffff0000; nSector = lOffset >> 16; nSector = nSector & 0x00007;
// if it is a valid sector, set it if ( (nSector >= 0) && (nSector < AFP_NumSectors) ) *pnSector = nSector;
// else it is an invalid sector else return FALSE;
// ok return TRUE; }
////////////////////////////////////////////////////////////// // void dma_int_0( int nothing ) // // DMA interrupt handler, we come in here after the data block // is done being DMAed // ////////////////////////////////////////////////////////////// void dma_int_0( int nothing ) { return; }
////////////////////////////////////////////////////////////// // void do_dma() // // sets up our DMA registers and does the DMA // ////////////////////////////////////////////////////////////// void do_dma() { asm("DCS0 = xr3:0;;"); // setup DMA sourse asm("DCD0 = xr7:4;;"); // setup DMA destination asm("idle;;"); // wait for dma to finish }
////////////////////////////////////////////////////////////// // bool ReadToInternal() // // Used to DMA flash memory to internal memory so that the // contents of flash can be viewed because the flash is not // memory mapped // // Inputs: long lOffset - offset in flash to start the reads at // long lCount - number of elements to read, in this case bytes // long lStride - number of locations to skip between writes // ////////////////////////////////////////////////////////////// bool ReadToInternal(long lOffset, long lCount, long lStride) { // we only allocate 0x8FFF locations for debugging so // check count to make sure we don't overwrite memory if( lCount > 0x1FFF ) asm("j5 = 0x1FFF;;"); asm("xr1 = j5;;"); // j5 is the count asm("xr1 = ashift r1 by 16;;"); // shift the count to upper 16 asm("xr2 = j6;;"); // j6 is the stride asm("xr1 = r1 OR r2;;"); // OR in stride asm("xr5 = xr1;;"); // set destination register the same
asm("xr0 = j4;;"); // xr0 = source index, j4 = nOffset asm("xr2 = 0x0;;"); // not used asm("xr3 = 0xc3000000;;"); // boot rom,prio=norm,2D=no,word=norm,int=yes,RQ=dsbl,chain=no asm("xr4 = 0x83000;;"); // xr4 = destination index / needs to change if debug section moves asm("xr6 = 0x0;;"); // not used asm("xr7 = 0x43000000;;"); // int mem,prio=norm,2D=no,word=norm,int=yes,RQ=dsbl,chain=no
do_dma(); // set up dma registers
// ok return TRUE; }
|