@ -158,6 +158,293 @@ void serdes_init(u32 sd, u32 sd_addr, u32 rcwsr, u32 sd_prctl_mask,
serdes_prtcl_map [ NONE ] = 1 ;
}
__weak int get_serdes_volt ( void )
{
return - 1 ;
}
__weak int set_serdes_volt ( int svdd )
{
return - 1 ;
}
# define LNAGCR0_RT_RSTB 0x00600000
# define RSTCTL_RESET_MASK 0x000000E0
# define RSTCTL_RSTREQ 0x80000000
# define RSTCTL_RST_DONE 0x40000000
# define RSTCTL_RSTERR 0x20000000
# define RSTCTL_SDEN 0x00000020
# define RSTCTL_SDRST_B 0x00000040
# define RSTCTL_PLLRST_B 0x00000080
# define TCALCR_CALRST_B 0x08000000
struct serdes_prctl_info {
u32 id ;
u32 mask ;
u32 shift ;
} ;
struct serdes_prctl_info srds_prctl_info [ ] = {
# ifdef CONFIG_SYS_FSL_SRDS_1
{ . id = 1 ,
. mask = FSL_CHASSIS3_SRDS1_PRTCL_MASK ,
. shift = FSL_CHASSIS3_SRDS1_PRTCL_SHIFT
} ,
# endif
# ifdef CONFIG_SYS_FSL_SRDS_2
{ . id = 2 ,
. mask = FSL_CHASSIS3_SRDS2_PRTCL_MASK ,
. shift = FSL_CHASSIS3_SRDS2_PRTCL_SHIFT
} ,
# endif
{ } /* NULL ENTRY */
} ;
static int get_serdes_prctl_info_idx ( u32 serdes_id )
{
int pos = 0 ;
struct serdes_prctl_info * srds_info ;
/* loop until NULL ENTRY defined by .id=0 */
for ( srds_info = srds_prctl_info ; srds_info - > id ! = 0 ;
srds_info + + , pos + + ) {
if ( srds_info - > id = = serdes_id )
return pos ;
}
return - 1 ;
}
static void do_enabled_lanes_reset ( u32 serdes_id , u32 cfg ,
struct ccsr_serdes __iomem * serdes_base ,
bool cmplt )
{
int i , pos ;
u32 cfg_tmp ;
pos = get_serdes_prctl_info_idx ( serdes_id ) ;
if ( pos = = - 1 ) {
printf ( " invalid serdes_id %d \n " , serdes_id ) ;
return ;
}
cfg_tmp = cfg & srds_prctl_info [ pos ] . mask ;
cfg_tmp > > = srds_prctl_info [ pos ] . shift ;
for ( i = 0 ; i < 4 & & cfg_tmp & ( 0xf < < ( 3 - i ) ) ; i + + ) {
if ( cmplt )
setbits_le32 ( & serdes_base - > lane [ i ] . gcr0 ,
LNAGCR0_RT_RSTB ) ;
else
clrbits_le32 ( & serdes_base - > lane [ i ] . gcr0 ,
LNAGCR0_RT_RSTB ) ;
}
}
static void do_pll_reset ( u32 cfg ,
struct ccsr_serdes __iomem * serdes_base )
{
int i ;
for ( i = 0 ; i < 2 & & ! ( cfg & ( 0x1 < < ( 1 - i ) ) ) ; i + + ) {
clrbits_le32 ( & serdes_base - > bank [ i ] . rstctl ,
RSTCTL_RESET_MASK ) ;
udelay ( 1 ) ;
setbits_le32 ( & serdes_base - > bank [ i ] . rstctl ,
RSTCTL_RSTREQ ) ;
}
udelay ( 1 ) ;
}
static void do_rx_tx_cal_reset ( struct ccsr_serdes __iomem * serdes_base )
{
clrbits_le32 ( & serdes_base - > srdstcalcr , TCALCR_CALRST_B ) ;
clrbits_le32 ( & serdes_base - > srdstcalcr , TCALCR_CALRST_B ) ;
}
static void do_rx_tx_cal_reset_comp ( u32 cfg , int i ,
struct ccsr_serdes __iomem * serdes_base )
{
if ( ! ( cfg = = 0x3 & & i = = 1 ) ) {
udelay ( 1 ) ;
setbits_le32 ( & serdes_base - > srdstcalcr , TCALCR_CALRST_B ) ;
setbits_le32 ( & serdes_base - > srdstcalcr , TCALCR_CALRST_B ) ;
}
udelay ( 1 ) ;
}
static void do_pll_reset_done ( u32 cfg ,
struct ccsr_serdes __iomem * serdes_base )
{
int i ;
u32 reg = 0 ;
for ( i = 0 ; i < 2 ; i + + ) {
reg = in_le32 ( & serdes_base - > bank [ i ] . pllcr0 ) ;
if ( ! ( cfg & ( 0x1 < < ( 1 - i ) ) ) & & ( ( reg > > 23 ) & 0x1 ) ) {
setbits_le32 ( & serdes_base - > bank [ i ] . rstctl ,
RSTCTL_RST_DONE ) ;
}
}
}
static void do_serdes_enable ( u32 cfg ,
struct ccsr_serdes __iomem * serdes_base )
{
int i ;
for ( i = 0 ; i < 2 & & ! ( cfg & ( 0x1 < < ( 1 - i ) ) ) ; i + + ) {
setbits_le32 ( & serdes_base - > bank [ i ] . rstctl , RSTCTL_SDEN ) ;
udelay ( 1 ) ;
setbits_le32 ( & serdes_base - > bank [ i ] . rstctl , RSTCTL_PLLRST_B ) ;
udelay ( 1 ) ;
/* Take the Rx/Tx calibration out of reset */
do_rx_tx_cal_reset_comp ( cfg , i , serdes_base ) ;
}
}
static void do_pll_lock ( u32 cfg ,
struct ccsr_serdes __iomem * serdes_base )
{
int i ;
u32 reg = 0 ;
for ( i = 0 ; i < 2 & & ! ( cfg & ( 0x1 < < ( 1 - i ) ) ) ; i + + ) {
/* if the PLL is not locked, set RST_ERR */
reg = in_le32 ( & serdes_base - > bank [ i ] . pllcr0 ) ;
if ( ! ( ( reg > > 23 ) & 0x1 ) ) {
setbits_le32 ( & serdes_base - > bank [ i ] . rstctl ,
RSTCTL_RSTERR ) ;
} else {
udelay ( 1 ) ;
setbits_le32 ( & serdes_base - > bank [ i ] . rstctl ,
RSTCTL_SDRST_B ) ;
udelay ( 1 ) ;
}
}
}
int setup_serdes_volt ( u32 svdd )
{
struct ccsr_gur __iomem * gur = ( void * ) ( CONFIG_SYS_FSL_GUTS_ADDR ) ;
struct ccsr_serdes __iomem * serdes1_base =
( void * ) CONFIG_SYS_FSL_LSCH3_SERDES_ADDR ;
u32 cfg_rcwsrds1 = gur_in32 ( & gur - > rcwsr [ FSL_CHASSIS3_SRDS1_REGSR - 1 ] ) ;
# ifdef CONFIG_SYS_FSL_SRDS_2
struct ccsr_serdes __iomem * serdes2_base =
( void * ) ( CONFIG_SYS_FSL_LSCH3_SERDES_ADDR + 0x10000 ) ;
u32 cfg_rcwsrds2 = gur_in32 ( & gur - > rcwsr [ FSL_CHASSIS3_SRDS2_REGSR - 1 ] ) ;
# endif
u32 cfg_tmp ;
int svdd_cur , svdd_tar ;
int ret = 1 ;
/* Only support switch SVDD to 900mV */
if ( svdd ! = 900 )
return - EINVAL ;
/* Scale up to the LTC resolution is 1/4096V */
svdd = ( svdd * 4096 ) / 1000 ;
svdd_tar = svdd ;
svdd_cur = get_serdes_volt ( ) ;
if ( svdd_cur < 0 )
return - EINVAL ;
debug ( " %s: current SVDD: %x; target SVDD: %x \n " ,
__func__ , svdd_cur , svdd_tar ) ;
if ( svdd_cur = = svdd_tar )
return 0 ;
/* Put the all enabled lanes in reset */
# ifdef CONFIG_SYS_FSL_SRDS_1
do_enabled_lanes_reset ( 1 , cfg_rcwsrds1 , serdes1_base , false ) ;
# endif
# ifdef CONFIG_SYS_FSL_SRDS_2
do_enabled_lanes_reset ( 2 , cfg_rcwsrds2 , serdes2_base , false ) ;
# endif
/* Put the all enabled PLL in reset */
# ifdef CONFIG_SYS_FSL_SRDS_1
cfg_tmp = cfg_rcwsrds1 & 0x3 ;
do_pll_reset ( cfg_tmp , serdes1_base ) ;
# endif
# ifdef CONFIG_SYS_FSL_SRDS_2
cfg_tmp = cfg_rcwsrds1 & 0xC ;
cfg_tmp > > = 2 ;
do_pll_reset ( cfg_tmp , serdes2_base ) ;
# endif
/* Put the Rx/Tx calibration into reset */
# ifdef CONFIG_SYS_FSL_SRDS_1
do_rx_tx_cal_reset ( serdes1_base ) ;
# endif
# ifdef CONFIG_SYS_FSL_SRDS_2
do_rx_tx_cal_reset ( serdes2_base ) ;
# endif
ret = set_serdes_volt ( svdd ) ;
if ( ret < 0 ) {
printf ( " could not change SVDD \n " ) ;
ret = - 1 ;
}
/* For each PLL that’s not disabled via RCW enable the SERDES */
# ifdef CONFIG_SYS_FSL_SRDS_1
cfg_tmp = cfg_rcwsrds1 & 0x3 ;
do_serdes_enable ( cfg_tmp , serdes1_base ) ;
# endif
# ifdef CONFIG_SYS_FSL_SRDS_2
cfg_tmp = cfg_rcwsrds1 & 0xC ;
cfg_tmp > > = 2 ;
do_serdes_enable ( cfg_tmp , serdes2_base ) ;
# endif
/* Wait for at at least 625us, ensure the PLLs being reset are locked */
udelay ( 800 ) ;
# ifdef CONFIG_SYS_FSL_SRDS_1
cfg_tmp = cfg_rcwsrds1 & 0x3 ;
do_pll_lock ( cfg_tmp , serdes1_base ) ;
# endif
# ifdef CONFIG_SYS_FSL_SRDS_2
cfg_tmp = cfg_rcwsrds1 & 0xC ;
cfg_tmp > > = 2 ;
do_pll_lock ( cfg_tmp , serdes2_base ) ;
# endif
/* Take the all enabled lanes out of reset */
# ifdef CONFIG_SYS_FSL_SRDS_1
do_enabled_lanes_reset ( 1 , cfg_rcwsrds1 , serdes1_base , true ) ;
# endif
# ifdef CONFIG_SYS_FSL_SRDS_2
do_enabled_lanes_reset ( 2 , cfg_rcwsrds2 , serdes2_base , true ) ;
# endif
/* For each PLL being reset, and achieved PLL lock set RST_DONE */
# ifdef CONFIG_SYS_FSL_SRDS_1
cfg_tmp = cfg_rcwsrds1 & 0x3 ;
do_pll_reset_done ( cfg_tmp , serdes1_base ) ;
# endif
# ifdef CONFIG_SYS_FSL_SRDS_2
cfg_tmp = cfg_rcwsrds1 & 0xC ;
cfg_tmp > > = 2 ;
do_pll_reset_done ( cfg_tmp , serdes2_base ) ;
# endif
return ret ;
}
void fsl_serdes_init ( void )
{
# if defined(CONFIG_FSL_MC_ENET) && !defined(CONFIG_SPL_BUILD)