@ -19,6 +19,7 @@
# include <malloc.h>
# include <spi.h>
# include <asm/io.h>
# include <wait_bit.h>
/*
* [ 0 ] : http : //www.xilinx.com/support/documentation
@ -77,6 +78,8 @@
# define CONFIG_XILINX_SPI_IDLE_VAL GENMASK(7, 0)
# endif
# define XILINX_SPISR_TIMEOUT 10000 /* in milliseconds */
/* xilinx spi register set */
struct xilinx_spi_regs {
u32 __space0__ [ 7 ] ;
@ -101,6 +104,7 @@ struct xilinx_spi_priv {
struct xilinx_spi_regs * regs ;
unsigned int freq ;
unsigned int mode ;
unsigned int fifo_depth ;
} ;
static int xilinx_spi_probe ( struct udevice * bus )
@ -110,6 +114,9 @@ static int xilinx_spi_probe(struct udevice *bus)
priv - > regs = ( struct xilinx_spi_regs * ) devfdt_get_addr ( bus ) ;
priv - > fifo_depth = fdtdec_get_int ( gd - > fdt_blob , dev_of_offset ( bus ) ,
" fifo-size " , 0 ) ;
writel ( SPISSR_RESET_VALUE , & regs - > srr ) ;
return 0 ;
@ -157,6 +164,47 @@ static int xilinx_spi_release_bus(struct udevice *dev)
return 0 ;
}
static u32 xilinx_spi_fill_txfifo ( struct udevice * bus , const u8 * txp ,
u32 txbytes )
{
struct xilinx_spi_priv * priv = dev_get_priv ( bus ) ;
struct xilinx_spi_regs * regs = priv - > regs ;
unsigned char d ;
u32 i = 0 ;
while ( txbytes & & ! ( readl ( & regs - > spisr ) & SPISR_TX_FULL ) & &
i < priv - > fifo_depth ) {
d = txp ? * txp + + : CONFIG_XILINX_SPI_IDLE_VAL ;
debug ( " spi_xfer: tx:%x " , d ) ;
/* write out and wait for processing (receive data) */
writel ( d & SPIDTR_8BIT_MASK , & regs - > spidtr ) ;
txbytes - - ;
i + + ;
}
return i ;
}
static u32 xilinx_spi_read_rxfifo ( struct udevice * bus , u8 * rxp , u32 rxbytes )
{
struct xilinx_spi_priv * priv = dev_get_priv ( bus ) ;
struct xilinx_spi_regs * regs = priv - > regs ;
unsigned char d ;
unsigned int i = 0 ;
while ( rxbytes & & ! ( readl ( & regs - > spisr ) & SPISR_RX_EMPTY ) ) {
d = readl ( & regs - > spidrr ) & SPIDRR_8BIT_MASK ;
if ( rxp )
* rxp + + = d ;
debug ( " spi_xfer: rx:%x \n " , d ) ;
rxbytes - - ;
i + + ;
}
debug ( " Rx_done \n " ) ;
return i ;
}
static int xilinx_spi_xfer ( struct udevice * dev , unsigned int bitlen ,
const void * dout , void * din , unsigned long flags )
{
@ -168,8 +216,10 @@ static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen,
unsigned int bytes = bitlen / XILSPI_MAX_XFER_BITS ;
const unsigned char * txp = dout ;
unsigned char * rxp = din ;
unsigned rxecount = 17 ; /* max. 16 elements in FIFO, leftover 1 */
unsigned global_timeout ;
u32 txbytes = bytes ;
u32 rxbytes = bytes ;
u32 reg , count , timeout ;
int ret ;
debug ( " spi_xfer: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx \n " ,
bus - > seq , slave_plat - > cs , bitlen , bytes , flags ) ;
@ -184,48 +234,31 @@ static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen,
goto done ;
}
/* empty read buffer */
while ( rxecount & & ! ( readl ( & regs - > spisr ) & SPISR_RX_EMPTY ) ) {
readl ( & regs - > spidrr ) ;
rxecount - - ;
}
if ( ! rxecount ) {
printf ( " XILSPI error: Rx buffer not empty \n " ) ;
return - 1 ;
}
if ( flags & SPI_XFER_BEGIN )
spi_cs_activate ( dev , slave_plat - > cs ) ;
/* at least 1usec or greater, leftover 1 */
global_timeout = priv - > freq > XILSPI_MAX_XFER_BITS * 1000000 ? 2 :
( XILSPI_MAX_XFER_BITS * 1000000 / priv - > freq ) + 1 ;
while ( bytes - - ) {
unsigned timeout = global_timeout ;
/* get Tx element from data out buffer and count up */
unsigned char d = txp ? * txp + + : CONFIG_XILINX_SPI_IDLE_VAL ;
debug ( " spi_xfer: tx:%x " , d ) ;
while ( txbytes & & rxbytes ) {
count = xilinx_spi_fill_txfifo ( bus , txp , txbytes ) ;
reg = readl ( & regs - > spicr ) & ~ SPICR_MASTER_INHIBIT ;
writel ( reg , & regs - > spicr ) ;
txbytes - = count ;
if ( txp )
txp + = count ;
/* write out and wait for processing (receive data) */
writel ( d & SPIDTR_8BIT_MASK , & regs - > spidtr ) ;
while ( timeout & & readl ( & regs - > spisr )
& SPISR_RX_EMPTY ) {
timeout - - ;
udelay ( 1 ) ;
}
if ( ! timeout ) {
ret = wait_for_bit_le32 ( & regs - > spisr , SPISR_TX_EMPTY , true ,
XILINX_SPISR_TIMEOUT , false ) ;
if ( ret < 0 ) {
printf ( " XILSPI error: Xfer timeout \n " ) ;
return - 1 ;
return ret ;
}
/* read Rx element and push into data in buffer */
d = readl ( & regs - > spidrr ) & SPIDRR_8BIT_MASK ;
debug ( " txbytes:0x%x,txp:0x%p \n " , txbytes , txp ) ;
count = xilinx_spi_read_rxfifo ( bus , rxp , rxbytes ) ;
rxbytes - = count ;
if ( rxp )
* rxp + + = d ;
debug ( " spi_xfer: rx:%x \n " , d ) ;
rxp + = count ;
debug ( " rxbytes:0x%x rxp:0x%p \n " , rxbytes , rxp ) ;
}
done :