@ -1,5 +1,6 @@
/*
* ( C ) Copyright 2013 Inc .
* ( C ) Copyright 2015 Jagan Teki < jteki @ openedev . com >
*
* Xilinx Zynq PS SPI controller driver ( master mode only )
*
@ -8,6 +9,8 @@
# include <config.h>
# include <common.h>
# include <dm.h>
# include <errno.h>
# include <malloc.h>
# include <spi.h>
# include <asm/io.h>
@ -44,180 +47,141 @@ struct zynq_spi_regs {
u32 rxdr ; /* 0x20 */
} ;
/* zynq spi slave */
struct zynq_spi_slave {
struct spi_slave slave ;
struct zynq_spi_regs * base ;
u8 mode ;
u8 fifo_depth ;
/* zynq spi platform data */
struct zynq_spi_platdata {
struct zynq_spi_regs * regs ;
u32 frequency ; /* input frequency */
u32 speed_hz ;
u32 input_hz ;
u32 req_hz ;
} ;
static inline struct zynq_spi_slave * to_zynq_spi_slave ( struct spi_slave * slave )
{
return container_of ( slave , struct zynq_spi_slave , slave ) ;
}
/* zynq spi priv */
struct zynq_spi_priv {
struct zynq_spi_regs * regs ;
u8 mode ;
u8 fifo_depth ;
u32 freq ; /* required frequency */
} ;
static inline struct zynq_spi_regs * get_zynq_spi_base ( int dev )
static inline struct zynq_spi_regs * get_zynq_spi_regs ( struct udevice * bus )
{
if ( dev )
if ( bus - > seq )
return ( struct zynq_spi_regs * ) ZYNQ_SPI_BASEADDR1 ;
else
return ( struct zynq_spi_regs * ) ZYNQ_SPI_BASEADDR0 ;
}
static void zynq_spi_init_hw ( struct zynq_spi_slave * zslave )
static int zynq_spi_ofdata_to_platdata ( struct udevice * bus )
{
struct zynq_spi_platdata * plat = bus - > platdata ;
plat - > regs = get_zynq_spi_regs ( bus ) ;
plat - > frequency = 166666700 ;
plat - > speed_hz = plat - > frequency / 2 ;
return 0 ;
}
static void zynq_spi_init_hw ( struct zynq_spi_priv * priv )
{
struct zynq_spi_regs * regs = priv - > regs ;
u32 confr ;
/* Disable SPI */
writel ( ~ ZYNQ_SPI_ENR_SPI_EN_MASK , & zslave - > base - > enr ) ;
writel ( ~ ZYNQ_SPI_ENR_SPI_EN_MASK , & regs - > enr ) ;
/* Disable Interrupts */
writel ( ZYNQ_SPI_IXR_ALL_MASK , & zslave - > base - > idr ) ;
writel ( ZYNQ_SPI_IXR_ALL_MASK , & regs - > idr ) ;
/* Clear RX FIFO */
while ( readl ( & zslave - > base - > isr ) &
while ( readl ( & regs - > isr ) &
ZYNQ_SPI_IXR_RXNEMPTY_MASK )
readl ( & zslave - > base - > rxdr ) ;
readl ( & regs - > rxdr ) ;
/* Clear Interrupts */
writel ( ZYNQ_SPI_IXR_ALL_MASK , & zslave - > base - > isr ) ;
writel ( ZYNQ_SPI_IXR_ALL_MASK , & regs - > isr ) ;
/* Manual slave select and Auto start */
confr = ZYNQ_SPI_CR_MCS_MASK | ZYNQ_SPI_CR_CS_MASK |
ZYNQ_SPI_CR_MSTREN_MASK ;
confr & = ~ ZYNQ_SPI_CR_MSA_MASK ;
writel ( confr , & zslave - > base - > cr ) ;
writel ( confr , & regs - > cr ) ;
/* Enable SPI */
writel ( ZYNQ_SPI_ENR_SPI_EN_MASK , & zslave - > base - > enr ) ;
writel ( ZYNQ_SPI_ENR_SPI_EN_MASK , & regs - > enr ) ;
}
int spi_cs_is_valid ( unsigned int bus , unsigned int c s)
static int zynq_spi_probe ( struct udevice * bu s)
{
/* 2 bus with 3 chipselect */
return bus < 2 & & cs < 3 ;
struct zynq_spi_platdata * plat = dev_get_platdata ( bus ) ;
struct zynq_spi_priv * priv = dev_get_priv ( bus ) ;
priv - > regs = plat - > regs ;
priv - > fifo_depth = ZYNQ_SPI_FIFO_DEPTH ;
/* init the zynq spi hw */
zynq_spi_init_hw ( priv ) ;
return 0 ;
}
void spi_cs_activate ( struct spi_slave * slave )
static void spi_cs_activate ( struct udevice * dev , uint cs )
{
struct zynq_spi_slave * zslave = to_zynq_spi_slave ( slave ) ;
struct udevice * bus = dev - > parent ;
struct zynq_spi_priv * priv = dev_get_priv ( bus ) ;
struct zynq_spi_regs * regs = priv - > regs ;
u32 cr ;
debug ( " spi_cs_activate: 0x%08x \n " , ( u32 ) slave ) ;
clrbits_le32 ( & zslave - > base - > cr , ZYNQ_SPI_CR_CS_MASK ) ;
cr = readl ( & zslave - > base - > cr ) ;
clrbits_le32 ( & regs - > cr , ZYNQ_SPI_CR_CS_MASK ) ;
cr = readl ( & regs - > cr ) ;
/*
* CS cal logic : CS [ 13 : 10 ]
* xxx0 - cs0
* xx01 - cs1
* x011 - cs2
*/
cr | = ( ~ ( 0x1 < < slave - > cs ) < < 10 ) & ZYNQ_SPI_CR_CS_MASK ;
writel ( cr , & zslave - > base - > cr ) ;
cr | = ( ~ ( 0x1 < < cs ) < < 10 ) & ZYNQ_SPI_CR_CS_MASK ;
writel ( cr , & regs - > cr ) ;
}
void spi_cs_deactivate ( struct spi_slave * slave )
static void spi_cs_deactivate ( struct udevice * dev )
{
struct zynq_spi_slave * zslave = to_zynq_spi_slave ( slave ) ;
debug ( " spi_cs_deactivate: 0x%08x \n " , ( u32 ) slave ) ;
struct udevice * bus = dev - > parent ;
struct zynq_spi_priv * priv = dev_get_priv ( bus ) ;
struct zynq_spi_regs * regs = priv - > regs ;
setbits_le32 ( & zslave - > base - > cr , ZYNQ_SPI_CR_CS_MASK ) ;
setbits_le32 ( & regs - > cr , ZYNQ_SPI_CR_CS_MASK ) ;
}
void spi_init ( )
static int zynq_spi_claim_bus ( struct udevice * dev )
{
/* nothing to do */
}
struct udevice * bus = dev - > parent ;
struct zynq_spi_priv * priv = dev_get_priv ( bus ) ;
struct zynq_spi_regs * regs = priv - > regs ;
struct spi_slave * spi_setup_slave ( unsigned int bus , unsigned int cs ,
unsigned int max_hz , unsigned int mode )
{
struct zynq_spi_slave * zslave ;
writel ( ZYNQ_SPI_ENR_SPI_EN_MASK , & regs - > enr ) ;
if ( ! spi_cs_is_valid ( bus , cs ) )
return NULL ;
zslave = spi_alloc_slave ( struct zynq_spi_slave , bus , cs ) ;
if ( ! zslave ) {
printf ( " SPI_error: Fail to allocate zynq_spi_slave \n " ) ;
return NULL ;
}
zslave - > base = get_zynq_spi_base ( bus ) ;
zslave - > mode = mode ;
zslave - > fifo_depth = ZYNQ_SPI_FIFO_DEPTH ;
zslave - > input_hz = 166666700 ;
zslave - > speed_hz = zslave - > input_hz / 2 ;
zslave - > req_hz = max_hz ;
/* init the zynq spi hw */
zynq_spi_init_hw ( zslave ) ;
return & zslave - > slave ;
}
void spi_free_slave ( struct spi_slave * slave )
{
struct zynq_spi_slave * zslave = to_zynq_spi_slave ( slave ) ;
debug ( " spi_free_slave: 0x%08x \n " , ( u32 ) slave ) ;
free ( zslave ) ;
return 0 ;
}
int spi_claim_bus ( struct spi_slave * slave )
static int zynq_spi_release_bus ( struct udevice * dev )
{
struct zynq_spi_slave * zslave = to_zynq_spi_slave ( slave ) ;
u32 confr = 0 ;
u8 baud_rate_val = 0 ;
writel ( ~ ZYNQ_SPI_ENR_SPI_EN_MASK , & zslave - > base - > enr ) ;
struct udevice * bus = dev - > parent ;
struct zynq_spi_priv * priv = dev_get_priv ( bus ) ;
struct zynq_spi_regs * regs = priv - > regs ;
/* Set the SPI Clock phase and polarities */
confr = readl ( & zslave - > base - > cr ) ;
confr & = ~ ( ZYNQ_SPI_CR_CPHA_MASK | ZYNQ_SPI_CR_CPOL_MASK ) ;
if ( zslave - > mode & SPI_CPHA )
confr | = ZYNQ_SPI_CR_CPHA_MASK ;
if ( zslave - > mode & SPI_CPOL )
confr | = ZYNQ_SPI_CR_CPOL_MASK ;
/* Set the clock frequency */
if ( zslave - > req_hz = = 0 ) {
/* Set baudrate x8, if the req_hz is 0 */
baud_rate_val = 0x2 ;
} else if ( zslave - > speed_hz ! = zslave - > req_hz ) {
while ( ( baud_rate_val < 8 ) & &
( ( zslave - > input_hz /
( 2 < < baud_rate_val ) ) > zslave - > req_hz ) )
baud_rate_val + + ;
zslave - > speed_hz = zslave - > req_hz / ( 2 < < baud_rate_val ) ;
}
confr & = ~ ZYNQ_SPI_CR_BRD_MASK ;
confr | = ( baud_rate_val < < 3 ) ;
writel ( confr , & zslave - > base - > cr ) ;
writel ( ZYNQ_SPI_ENR_SPI_EN_MASK , & zslave - > base - > enr ) ;
writel ( ~ ZYNQ_SPI_ENR_SPI_EN_MASK , & regs - > enr ) ;
return 0 ;
}
void spi_release_bus ( struct spi_slave * slave )
static int zynq_spi_xfer ( struct udevice * dev , unsigned int bitlen ,
const void * dout , void * din , unsigned long flags )
{
struct zynq_spi_slave * zslave = to_zynq_spi_slave ( slave ) ;
debug ( " spi_release_bus: 0x%08x \n " , ( u32 ) slave ) ;
writel ( ~ ZYNQ_SPI_ENR_SPI_EN_MASK , & zslave - > base - > enr ) ;
}
int spi_xfer ( struct spi_slave * slave , unsigned int bitlen , const void * dout ,
void * din , unsigned long flags )
{
struct zynq_spi_slave * zslave = to_zynq_spi_slave ( slave ) ;
struct udevice * bus = dev - > parent ;
struct zynq_spi_priv * priv = dev_get_priv ( bus ) ;
struct zynq_spi_regs * regs = priv - > regs ;
struct dm_spi_slave_platdata * slave_plat = dev_get_parent_platdata ( dev ) ;
u32 len = bitlen / 8 ;
u32 tx_len = len , rx_len = len , tx_tvl ;
const u8 * tx_buf = dout ;
@ -225,7 +189,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
u32 ts , status ;
debug ( " spi_xfer: bus:%i cs:%i bitlen:%i len:%i flags:%lx \n " ,
slave - > bu s, slave - > cs , bitlen , len , flags ) ;
bu s- > seq , slave_plat - > cs , bitlen , len , flags ) ;
if ( bitlen % 8 ) {
debug ( " spi_xfer: Non byte aligned SPI transfer \n " ) ;
@ -233,45 +197,126 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
}
if ( flags & SPI_XFER_BEGIN )
spi_cs_activate ( slave ) ;
spi_cs_activate ( dev , slave_plat - > cs ) ;
while ( rx_len > 0 ) {
/* Write the data into TX FIFO - tx threshold is fifo_depth */
tx_tvl = 0 ;
while ( ( tx_tvl < zslave - > fifo_depth ) & & tx_len ) {
while ( ( tx_tvl < priv - > fifo_depth ) & & tx_len ) {
if ( tx_buf )
buf = * tx_buf + + ;
else
buf = 0 ;
writel ( buf , & zslave - > base - > txdr ) ;
writel ( buf , & regs - > txdr ) ;
tx_len - - ;
tx_tvl + + ;
}
/* Check TX FIFO completion */
ts = get_timer ( 0 ) ;
status = readl ( & zslave - > base - > isr ) ;
status = readl ( & regs - > isr ) ;
while ( ! ( status & ZYNQ_SPI_IXR_TXOW_MASK ) ) {
if ( get_timer ( ts ) > CONFIG_SYS_ZYNQ_SPI_WAIT ) {
printf ( " spi_xfer: Timeout! TX FIFO not full \n " ) ;
return - 1 ;
}
status = readl ( & zslave - > base - > isr ) ;
status = readl ( & regs - > isr ) ;
}
/* Read the data from RX FIFO */
status = readl ( & zslave - > base - > isr ) ;
status = readl ( & regs - > isr ) ;
while ( status & ZYNQ_SPI_IXR_RXNEMPTY_MASK ) {
buf = readl ( & zslave - > base - > rxdr ) ;
buf = readl ( & regs - > rxdr ) ;
if ( rx_buf )
* rx_buf + + = buf ;
status = readl ( & zslave - > base - > isr ) ;
status = readl ( & regs - > isr ) ;
rx_len - - ;
}
}
if ( flags & SPI_XFER_END )
spi_cs_deactivate ( slave ) ;
spi_cs_deactivate ( dev ) ;
return 0 ;
}
static int zynq_spi_set_speed ( struct udevice * bus , uint speed )
{
struct zynq_spi_platdata * plat = bus - > platdata ;
struct zynq_spi_priv * priv = dev_get_priv ( bus ) ;
struct zynq_spi_regs * regs = priv - > regs ;
uint32_t confr ;
u8 baud_rate_val = 0 ;
if ( speed > plat - > frequency )
speed = plat - > frequency ;
/* Set the clock frequency */
confr = readl ( & regs - > cr ) ;
if ( speed = = 0 ) {
/* Set baudrate x8, if the freq is 0 */
baud_rate_val = 0x2 ;
} else if ( plat - > speed_hz ! = speed ) {
while ( ( baud_rate_val < 8 ) & &
( ( plat - > frequency /
( 2 < < baud_rate_val ) ) > speed ) )
baud_rate_val + + ;
plat - > speed_hz = speed / ( 2 < < baud_rate_val ) ;
}
confr & = ~ ZYNQ_SPI_CR_BRD_MASK ;
confr | = ( baud_rate_val < < 3 ) ;
writel ( confr , & regs - > cr ) ;
priv - > freq = speed ;
debug ( " zynq_spi_set_speed: regs=%p, mode=%d \n " , priv - > regs , priv - > freq ) ;
return 0 ;
}
static int zynq_spi_set_mode ( struct udevice * bus , uint mode )
{
struct zynq_spi_priv * priv = dev_get_priv ( bus ) ;
struct zynq_spi_regs * regs = priv - > regs ;
uint32_t confr ;
/* Set the SPI Clock phase and polarities */
confr = readl ( & regs - > cr ) ;
confr & = ~ ( ZYNQ_SPI_CR_CPHA_MASK | ZYNQ_SPI_CR_CPOL_MASK ) ;
if ( priv - > mode & SPI_CPHA )
confr | = ZYNQ_SPI_CR_CPHA_MASK ;
if ( priv - > mode & SPI_CPOL )
confr | = ZYNQ_SPI_CR_CPOL_MASK ;
writel ( confr , & regs - > cr ) ;
priv - > mode = mode ;
debug ( " zynq_spi_set_mode: regs=%p, mode=%d \n " , priv - > regs , priv - > mode ) ;
return 0 ;
}
static const struct dm_spi_ops zynq_spi_ops = {
. claim_bus = zynq_spi_claim_bus ,
. release_bus = zynq_spi_release_bus ,
. xfer = zynq_spi_xfer ,
. set_speed = zynq_spi_set_speed ,
. set_mode = zynq_spi_set_mode ,
} ;
static const struct udevice_id zynq_spi_ids [ ] = {
{ . compatible = " xlnx,zynq-spi " } ,
{ }
} ;
U_BOOT_DRIVER ( zynq_spi ) = {
. name = " zynq_spi " ,
. id = UCLASS_SPI ,
. of_match = zynq_spi_ids ,
. ops = & zynq_spi_ops ,
. ofdata_to_platdata = zynq_spi_ofdata_to_platdata ,
. platdata_auto_alloc_size = sizeof ( struct zynq_spi_platdata ) ,
. priv_auto_alloc_size = sizeof ( struct zynq_spi_priv ) ,
. probe = zynq_spi_probe ,
} ;