diff options
Diffstat (limited to 'drivers/spi/spirom.c')
-rw-r--r-- | drivers/spi/spirom.c | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/drivers/spi/spirom.c b/drivers/spi/spirom.c new file mode 100644 index 00000000000..87c93668ed3 --- /dev/null +++ b/drivers/spi/spirom.c @@ -0,0 +1,212 @@ +/* + * Copyright 2007 b7 Spectrum Digital Incorporated. + * All rights reserved. Property of Spectrum Digital Incorporated. + */ + +/* + * SPI ROM interface + * + */ + +#include "spirom.h" + +static Uint8 spirombuf[SPIROM_PAGESIZE + 5]; +static Uint8 statusbuf[8]; +static Uint32 spidat1; + +/* ------------------------------------------------------------------------ * + * * + * _wait( delay ) * + * Wait in a software loop for 'x' delay * + * * + * ------------------------------------------------------------------------ */ +void DAVINCIHD_wait( Uint32 delay ) +{ + volatile Uint32 i; + for ( i = 0 ; i < delay ; i++ ){ }; +} + + +/* ------------------------------------------------------------------------ * + * spirom_init( ) * + * ------------------------------------------------------------------------ */ +void spirom_init( ) +{ + /* Reset SPI */ + SPI_SPIGCR0 = 0; + _wait( 1000 ); + + /* Release SPI */ + SPI_SPIGCR0 = 1; + + /* SPI 4-Pin Mode setup */ + SPI_SPIGCR1 = 0 + | ( 0 << 24 ) + | ( 0 << 16 ) + | ( 1 << 1 ) + | ( 1 << 0 ); + + SPI_SPIPC0 = 0 + | ( 1 << 11 ) // DI + | ( 1 << 10 ) // DO + | ( 1 << 9 ) // CLK + | ( 1 << 1 ) // EN1 + | ( 1 << 0 ); // EN0 + + SPI_SPIFMT0 = 0 + | ( 0 << 20 ) // SHIFTDIR + | ( 0 << 17 ) // Polarity + | ( 1 << 16 ) // Phase + | ( 50 << 8 ) // Prescale + | ( 8 << 0 ); // Char Len + + spidat1 = 0 + | ( 1 << 28 ) // CSHOLD + | ( 0 << 24 ) // Format [0] + | ( 2 << 16 ) // CSNR [only CS0 enbled] + | ( 0 << 0 ); // + + SPI_SPIDAT1 = spidat1; + + SPI_SPIDELAY = 0 + | ( 8 << 24 ) // C2TDELAY + | ( 8 << 16 ); // T2CDELAY + + SPI_SPIDEF = 0 + | ( 1 << 1 ) // EN1 inactive high + | ( 1 << 0 ); // EN0 inactive high + + SPI_SPIINT = 0 + | ( 0 << 16 ) // + | ( 0 << 8 ) // + | ( 0 << 6 ) // + | ( 1 << 4 ); // + + SPI_SPILVL = 0 + | ( 0 << 8 ) // EN0 + | ( 0 << 6 ) // EN0 + | ( 0 << 4 ); // EN0 + + + /* Enable SPI */ + SPI_SPIGCR1 |= ( 1 << 24 ); +} + +/* ------------------------------------------------------------------------ * + * spirom_cycle( buf, len ) * + * * + * Execute a SPI spirom data transfer cycle. Each byte in buf is shifted * + * out and replaced with data coming back from the spirom. * + * ------------------------------------------------------------------------ */ +void spirom_cycle( Uint8 *buf, Uint16 len ) +{ + Uint16 i; + + /* Clear any old data */ + SPI_SPIBUF; + + /* SPIROM access cycle */ + for ( i = 0 ; i <= len ; i++ ) + { + /* Wait for transmit ready */ + while ( SPI_SPIBUF & 0x10000000 ); + + if ( i == len ) + SPI_SPIDAT1 = ( spidat1 & 0x0ffcffff ) | buf[i]; + else + SPI_SPIDAT1 = spidat1 | buf[i]; + + /* Wait for receive data ready */ + while ( SPI_SPIBUF & 0x80000000 ); + + /* Read 1 byte */ + buf[i] = SPI_SPIBUF; + } +} + +/* ------------------------------------------------------------------------ * + * spirom_status( ) * + * ------------------------------------------------------------------------ */ +Uint8 spirom_status( ) +{ + /* Issue read status command */ + statusbuf[0] = SPIROM_CMD_RDSR; + statusbuf[1] = 0; + + spirom_cycle( statusbuf, 2 ); + + return statusbuf[1]; +} + +/* ------------------------------------------------------------------------ * + * spirom_read( src, dst, length ) * + * ------------------------------------------------------------------------ */ +void spirom_read( Uint16 src, Uint32 dst, Uint32 length ) +{ + Int32 i; + Uint8 *psrc, *pdst; + + // Setup command + spirombuf[0] = SPIROM_CMD_READ; + spirombuf[1] = ( src >> 8 ); + spirombuf[2] = ( src >> 0 ); + + // Execute spirom read cycle + spirom_cycle( spirombuf, length + 3 ); + + // Copy returned data + pdst = ( Uint8 * )dst; + psrc = spirombuf + 3; + for ( i = 0 ; i < length ; i++ ) + *pdst++ = *psrc++; +} + +/* ------------------------------------------------------------------------ * + * spirom_write( src, dst, length ) * + * ------------------------------------------------------------------------ */ +void spirom_write( Uint32 src, Uint16 dst, Uint32 length ) +{ + Int32 i; + Int32 bytes_left; + Int32 bytes_to_program; + Uint8 *psrc; + + /* Establish source */ + psrc = ( Uint8 * )src; + bytes_left = length; + + while ( bytes_left > 0 ) + { + bytes_to_program = bytes_left; + + /* Most to program is SPIROM_CMD_BLOCKSIZE */ + if ( bytes_to_program > SPIROM_PAGESIZE ) + bytes_to_program = SPIROM_PAGESIZE; + + /* Make sure you don't run off the end of a block */ + if ( ( dst & SPIROM_PAGEMASK ) != ( ( dst + bytes_to_program ) & SPIROM_PAGEMASK ) ) + bytes_to_program -= ( dst + bytes_to_program ) - ( ( dst + bytes_to_program ) & SPIROM_PAGEMASK ); + + /* Issue WPEN */ + spirombuf[0] = SPIROM_CMD_WREN; + spirom_cycle( spirombuf, 0 ); + + /* Create command block for program operation */ + spirombuf[0] = SPIROM_CMD_WRITE; + spirombuf[1] = ( Uint8 )( dst >> 8 ); + spirombuf[2] = ( Uint8 )( dst ); + + for ( i = 0 ; i < bytes_to_program ; i++ ) + spirombuf[3+i] = *psrc++; + + /* Execute write command */ + spirom_cycle( spirombuf, bytes_to_program + 2 ); + + /* Wait while busy */ + while( ( spirom_status( ) & 0x01 ) ); + + /* Get ready for next iteration */ + bytes_left -= bytes_to_program; + dst += bytes_to_program; + } +} |