2018-08-09 11:30:30 +01:00
// SPDX-License-Identifier: GPL-2.0-only
/*
2020-02-06 07:10:52 +01:00
* Cadence Torrent SD0801 PHY driver .
2018-08-09 11:30:30 +01:00
*
* Copyright 2018 Cadence Design Systems , Inc .
*
*/
2020-02-06 07:10:56 +01:00
# include <linux/clk.h>
2018-08-09 11:30:30 +01:00
# include <linux/delay.h>
# include <linux/err.h>
# include <linux/io.h>
# include <linux/iopoll.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_device.h>
# include <linux/phy/phy.h>
# include <linux/platform_device.h>
2020-02-06 07:10:56 +01:00
# define REF_CLK_19_2MHz 19200000
# define REF_CLK_25MHz 25000000
# define DEFAULT_NUM_LANES 4
2018-08-09 11:30:30 +01:00
# define MAX_NUM_LANES 4
# define DEFAULT_MAX_BIT_RATE 8100 /* in Mbps */
2020-02-06 07:10:55 +01:00
# define POLL_TIMEOUT_US 5000
2018-08-09 11:30:30 +01:00
# define LANE_MASK 0x7
/*
* register offsets from DPTX PHY register block base ( i . e MHDP
* register base + 0x30a00 )
*/
# define PHY_AUX_CONFIG 0x00
# define PHY_AUX_CTRL 0x04
# define PHY_RESET 0x20
2020-02-06 07:10:57 +01:00
# define PMA_TX_ELEC_IDLE_MASK 0xF0U
# define PMA_TX_ELEC_IDLE_SHIFT 4
# define PHY_L00_RESET_N_MASK 0x01U
2018-08-09 11:30:30 +01:00
# define PHY_PMA_XCVR_PLLCLK_EN 0x24
# define PHY_PMA_XCVR_PLLCLK_EN_ACK 0x28
# define PHY_PMA_XCVR_POWER_STATE_REQ 0x2c
# define PHY_POWER_STATE_LN_0 0x0000
# define PHY_POWER_STATE_LN_1 0x0008
# define PHY_POWER_STATE_LN_2 0x0010
# define PHY_POWER_STATE_LN_3 0x0018
2020-02-06 07:10:55 +01:00
# define PMA_XCVR_POWER_STATE_REQ_LN_MASK 0x3FU
2018-08-09 11:30:30 +01:00
# define PHY_PMA_XCVR_POWER_STATE_ACK 0x30
# define PHY_PMA_CMN_READY 0x34
# define PHY_PMA_XCVR_TX_VMARGIN 0x38
# define PHY_PMA_XCVR_TX_DEEMPH 0x3c
/*
* register offsets from SD0801 PHY register block base ( i . e MHDP
* register base + 0x500000 )
*/
# define CMN_SSM_BANDGAP_TMR 0x00084
# define CMN_SSM_BIAS_TMR 0x00088
# define CMN_PLLSM0_PLLPRE_TMR 0x000a8
# define CMN_PLLSM0_PLLLOCK_TMR 0x000b0
# define CMN_PLLSM1_PLLPRE_TMR 0x000c8
# define CMN_PLLSM1_PLLLOCK_TMR 0x000d0
# define CMN_BGCAL_INIT_TMR 0x00190
# define CMN_BGCAL_ITER_TMR 0x00194
# define CMN_IBCAL_INIT_TMR 0x001d0
2020-02-06 07:10:56 +01:00
# define CMN_PLL0_VCOCAL_TCTRL 0x00208
2018-08-09 11:30:30 +01:00
# define CMN_PLL0_VCOCAL_INIT_TMR 0x00210
# define CMN_PLL0_VCOCAL_ITER_TMR 0x00214
# define CMN_PLL0_VCOCAL_REFTIM_START 0x00218
# define CMN_PLL0_VCOCAL_PLLCNT_START 0x00220
# define CMN_PLL0_INTDIV_M0 0x00240
# define CMN_PLL0_FRACDIVL_M0 0x00244
# define CMN_PLL0_FRACDIVH_M0 0x00248
# define CMN_PLL0_HIGH_THR_M0 0x0024c
# define CMN_PLL0_DSM_DIAG_M0 0x00250
2020-02-06 07:10:56 +01:00
# define CMN_PLL0_SS_CTRL1_M0 0x00260
# define CMN_PLL0_SS_CTRL2_M0 0x00264
# define CMN_PLL0_SS_CTRL3_M0 0x00268
# define CMN_PLL0_SS_CTRL4_M0 0x0026C
# define CMN_PLL0_LOCK_REFCNT_START 0x00270
2018-08-09 11:30:30 +01:00
# define CMN_PLL0_LOCK_PLLCNT_START 0x00278
2020-02-06 07:10:56 +01:00
# define CMN_PLL0_LOCK_PLLCNT_THR 0x0027C
# define CMN_PLL1_VCOCAL_TCTRL 0x00308
2018-08-09 11:30:30 +01:00
# define CMN_PLL1_VCOCAL_INIT_TMR 0x00310
# define CMN_PLL1_VCOCAL_ITER_TMR 0x00314
2020-02-06 07:10:56 +01:00
# define CMN_PLL1_VCOCAL_REFTIM_START 0x00318
# define CMN_PLL1_VCOCAL_PLLCNT_START 0x00320
# define CMN_PLL1_INTDIV_M0 0x00340
# define CMN_PLL1_FRACDIVL_M0 0x00344
# define CMN_PLL1_FRACDIVH_M0 0x00348
# define CMN_PLL1_HIGH_THR_M0 0x0034c
2018-08-09 11:30:30 +01:00
# define CMN_PLL1_DSM_DIAG_M0 0x00350
2020-02-06 07:10:56 +01:00
# define CMN_PLL1_SS_CTRL1_M0 0x00360
# define CMN_PLL1_SS_CTRL2_M0 0x00364
# define CMN_PLL1_SS_CTRL3_M0 0x00368
# define CMN_PLL1_SS_CTRL4_M0 0x0036C
# define CMN_PLL1_LOCK_REFCNT_START 0x00370
# define CMN_PLL1_LOCK_PLLCNT_START 0x00378
# define CMN_PLL1_LOCK_PLLCNT_THR 0x0037C
2018-08-09 11:30:30 +01:00
# define CMN_TXPUCAL_INIT_TMR 0x00410
# define CMN_TXPUCAL_ITER_TMR 0x00414
# define CMN_TXPDCAL_INIT_TMR 0x00430
# define CMN_TXPDCAL_ITER_TMR 0x00434
# define CMN_RXCAL_INIT_TMR 0x00450
# define CMN_RXCAL_ITER_TMR 0x00454
# define CMN_SD_CAL_INIT_TMR 0x00490
# define CMN_SD_CAL_ITER_TMR 0x00494
# define CMN_SD_CAL_REFTIM_START 0x00498
# define CMN_SD_CAL_PLLCNT_START 0x004a0
# define CMN_PDIAG_PLL0_CTRL_M0 0x00680
# define CMN_PDIAG_PLL0_CLK_SEL_M0 0x00684
# define CMN_PDIAG_PLL0_CP_PADJ_M0 0x00690
# define CMN_PDIAG_PLL0_CP_IADJ_M0 0x00694
# define CMN_PDIAG_PLL0_FILT_PADJ_M0 0x00698
# define CMN_PDIAG_PLL0_CP_PADJ_M1 0x006d0
# define CMN_PDIAG_PLL0_CP_IADJ_M1 0x006d4
2020-02-06 07:10:56 +01:00
# define CMN_PDIAG_PLL1_CTRL_M0 0x00700
2018-08-09 11:30:30 +01:00
# define CMN_PDIAG_PLL1_CLK_SEL_M0 0x00704
2020-02-06 07:10:56 +01:00
# define CMN_PDIAG_PLL1_CP_PADJ_M0 0x00710
# define CMN_PDIAG_PLL1_CP_IADJ_M0 0x00714
# define CMN_PDIAG_PLL1_FILT_PADJ_M0 0x00718
2020-02-06 07:10:57 +01:00
# define TX_TXCC_CTRL 0x10100
# define TX_TXCC_CPOST_MULT_00 0x10130
# define TX_TXCC_MGNFS_MULT_000 0x10140
# define DRV_DIAG_TX_DRV 0x10318
2018-08-09 11:30:30 +01:00
# define XCVR_DIAG_PLLDRC_CTRL 0x10394
# define XCVR_DIAG_HSCLK_SEL 0x10398
# define XCVR_DIAG_HSCLK_DIV 0x1039c
2020-02-06 07:10:56 +01:00
# define XCVR_DIAG_BIDI_CTRL 0x103a8
2018-08-09 11:30:30 +01:00
# define TX_PSC_A0 0x10400
# define TX_PSC_A1 0x10404
# define TX_PSC_A2 0x10408
# define TX_PSC_A3 0x1040c
2020-02-06 07:10:56 +01:00
# define TX_RCVDET_ST_TMR 0x1048c
2020-02-06 07:10:57 +01:00
# define TX_DIAG_ACYA 0x1079c
# define TX_DIAG_ACYA_HBDC_MASK 0x0001U
2018-08-09 11:30:30 +01:00
# define RX_PSC_A0 0x20000
# define RX_PSC_A1 0x20004
# define RX_PSC_A2 0x20008
# define RX_PSC_A3 0x2000c
2020-02-06 07:10:56 +01:00
# define RX_PSC_CAL 0x20018
# define RX_REE_GCSM1_CTRL 0x20420
# define RX_REE_GCSM2_CTRL 0x20440
# define RX_REE_PERGCSM_CTRL 0x20460
2018-08-09 11:30:30 +01:00
# define PHY_PLL_CFG 0x30038
2020-02-06 07:10:57 +01:00
# define PHY_PMA_CMN_CTRL2 0x38004
# define PHY_PMA_PLL_RAW_CTRL 0x3800c
2020-02-06 07:10:52 +01:00
struct cdns_torrent_phy {
2018-08-09 11:30:30 +01:00
void __iomem * base ; /* DPTX registers base */
void __iomem * sd_base ; /* SD0801 registers base */
u32 num_lanes ; /* Number of lanes to use */
u32 max_bit_rate ; /* Maximum link bit rate to use (in Mbps) */
struct device * dev ;
2020-02-06 07:10:56 +01:00
struct clk * clk ;
unsigned long ref_clk_rate ;
2018-08-09 11:30:30 +01:00
} ;
2020-02-06 07:10:55 +01:00
enum phy_powerstate {
POWERSTATE_A0 = 0 ,
/* Powerstate A1 is unused */
POWERSTATE_A2 = 2 ,
POWERSTATE_A3 = 3 ,
} ;
2020-02-06 07:10:52 +01:00
static int cdns_torrent_dp_init ( struct phy * phy ) ;
2020-02-06 07:10:56 +01:00
static int cdns_torrent_dp_exit ( struct phy * phy ) ;
2020-02-06 07:10:57 +01:00
static int cdns_torrent_dp_run ( struct cdns_torrent_phy * cdns_phy ,
u32 num_lanes ) ;
2020-02-06 07:10:52 +01:00
static
2020-02-06 07:10:55 +01:00
int cdns_torrent_dp_wait_pma_cmn_ready ( struct cdns_torrent_phy * cdns_phy ) ;
2020-02-06 07:10:52 +01:00
static void cdns_torrent_dp_pma_cfg ( struct cdns_torrent_phy * cdns_phy ) ;
static
2020-02-06 07:10:56 +01:00
void cdns_torrent_dp_pma_cmn_cfg_19_2mhz ( struct cdns_torrent_phy * cdns_phy ) ;
static
void cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz ( struct cdns_torrent_phy * cdns_phy ,
u32 rate , bool ssc ) ;
static
2020-02-06 07:10:52 +01:00
void cdns_torrent_dp_pma_cmn_cfg_25mhz ( struct cdns_torrent_phy * cdns_phy ) ;
2020-02-06 07:10:56 +01:00
static
void cdns_torrent_dp_pma_cmn_vco_cfg_25mhz ( struct cdns_torrent_phy * cdns_phy ,
u32 rate , bool ssc ) ;
2020-02-06 07:10:52 +01:00
static void cdns_torrent_dp_pma_lane_cfg ( struct cdns_torrent_phy * cdns_phy ,
2018-08-09 11:30:30 +01:00
unsigned int lane ) ;
2020-02-06 07:10:56 +01:00
static void cdns_torrent_dp_pma_cmn_rate ( struct cdns_torrent_phy * cdns_phy ,
u32 rate , u32 num_lanes ) ;
2020-02-06 07:10:52 +01:00
static void cdns_dp_phy_write_field ( struct cdns_torrent_phy * cdns_phy ,
unsigned int offset ,
unsigned char start_bit ,
unsigned char num_bits ,
unsigned int val ) ;
2020-02-06 07:10:57 +01:00
static int cdns_torrent_dp_configure ( struct phy * phy ,
union phy_configure_opts * opts ) ;
static int cdns_torrent_dp_set_power_state ( struct cdns_torrent_phy * cdns_phy ,
u32 num_lanes ,
enum phy_powerstate powerstate ) ;
2020-02-06 07:10:52 +01:00
static const struct phy_ops cdns_torrent_phy_ops = {
. init = cdns_torrent_dp_init ,
2020-02-06 07:10:56 +01:00
. exit = cdns_torrent_dp_exit ,
2020-02-06 07:10:57 +01:00
. configure = cdns_torrent_dp_configure ,
2018-08-09 11:30:30 +01:00
. owner = THIS_MODULE ,
} ;
2020-02-06 07:10:53 +01:00
/* PHY mmr access functions */
static void cdns_torrent_phy_write ( struct cdns_torrent_phy * cdns_phy ,
u32 offset , u32 val )
{
writel ( val , cdns_phy - > sd_base + offset ) ;
}
2020-02-06 07:10:57 +01:00
static u32 cdns_torrent_phy_read ( struct cdns_torrent_phy * cdns_phy , u32 offset )
{
return readl ( cdns_phy - > sd_base + offset ) ;
}
# define cdns_torrent_phy_read_poll_timeout(cdns_phy, offset, val, cond, \
delay_us , timeout_us ) \
readl_poll_timeout ( ( cdns_phy ) - > sd_base + ( offset ) , \
val , cond , delay_us , timeout_us )
2020-02-06 07:10:54 +01:00
/* DPTX mmr access functions */
static void cdns_torrent_dp_write ( struct cdns_torrent_phy * cdns_phy ,
u32 offset , u32 val )
{
writel ( val , cdns_phy - > base + offset ) ;
}
static u32 cdns_torrent_dp_read ( struct cdns_torrent_phy * cdns_phy , u32 offset )
{
return readl ( cdns_phy - > base + offset ) ;
}
# define cdns_torrent_dp_read_poll_timeout(cdns_phy, offset, val, cond, \
delay_us , timeout_us ) \
readl_poll_timeout ( ( cdns_phy ) - > base + ( offset ) , \
val , cond , delay_us , timeout_us )
2020-02-06 07:10:57 +01:00
/*
* Structure used to store values of PHY registers for voltage - related
* coefficients , for particular voltage swing and pre - emphasis level . Values
* are shared across all physical lanes .
*/
struct coefficients {
/* Value of DRV_DIAG_TX_DRV register to use */
u16 diag_tx_drv ;
/* Value of TX_TXCC_MGNFS_MULT_000 register to use */
u16 mgnfs_mult ;
/* Value of TX_TXCC_CPOST_MULT_00 register to use */
u16 cpost_mult ;
} ;
/*
* Array consists of values of voltage - related registers for sd0801 PHY . A value
* of 0xFFFF is a placeholder for invalid combination , and will never be used .
*/
static const struct coefficients vltg_coeff [ 4 ] [ 4 ] = {
/* voltage swing 0, pre-emphasis 0->3 */
{ { . diag_tx_drv = 0x0003 , . mgnfs_mult = 0x002A ,
. cpost_mult = 0x0000 } ,
{ . diag_tx_drv = 0x0003 , . mgnfs_mult = 0x001F ,
. cpost_mult = 0x0014 } ,
{ . diag_tx_drv = 0x0003 , . mgnfs_mult = 0x0012 ,
. cpost_mult = 0x0020 } ,
{ . diag_tx_drv = 0x0003 , . mgnfs_mult = 0x0000 ,
. cpost_mult = 0x002A }
} ,
/* voltage swing 1, pre-emphasis 0->3 */
{ { . diag_tx_drv = 0x0003 , . mgnfs_mult = 0x001F ,
. cpost_mult = 0x0000 } ,
{ . diag_tx_drv = 0x0003 , . mgnfs_mult = 0x0013 ,
. cpost_mult = 0x0012 } ,
{ . diag_tx_drv = 0x0003 , . mgnfs_mult = 0x0000 ,
. cpost_mult = 0x001F } ,
{ . diag_tx_drv = 0xFFFF , . mgnfs_mult = 0xFFFF ,
. cpost_mult = 0xFFFF }
} ,
/* voltage swing 2, pre-emphasis 0->3 */
{ { . diag_tx_drv = 0x0003 , . mgnfs_mult = 0x0013 ,
. cpost_mult = 0x0000 } ,
{ . diag_tx_drv = 0x0003 , . mgnfs_mult = 0x0000 ,
. cpost_mult = 0x0013 } ,
{ . diag_tx_drv = 0xFFFF , . mgnfs_mult = 0xFFFF ,
. cpost_mult = 0xFFFF } ,
{ . diag_tx_drv = 0xFFFF , . mgnfs_mult = 0xFFFF ,
. cpost_mult = 0xFFFF }
} ,
/* voltage swing 3, pre-emphasis 0->3 */
{ { . diag_tx_drv = 0x0003 , . mgnfs_mult = 0x0000 ,
. cpost_mult = 0x0000 } ,
{ . diag_tx_drv = 0xFFFF , . mgnfs_mult = 0xFFFF ,
. cpost_mult = 0xFFFF } ,
{ . diag_tx_drv = 0xFFFF , . mgnfs_mult = 0xFFFF ,
. cpost_mult = 0xFFFF } ,
{ . diag_tx_drv = 0xFFFF , . mgnfs_mult = 0xFFFF ,
. cpost_mult = 0xFFFF }
}
} ;
/*
* Enable or disable PLL for selected lanes .
*/
static int cdns_torrent_dp_set_pll_en ( struct cdns_torrent_phy * cdns_phy ,
struct phy_configure_opts_dp * dp ,
bool enable )
{
u32 rd_val ;
u32 ret ;
/*
* Used to determine , which bits to check for or enable in
* PHY_PMA_XCVR_PLLCLK_EN register .
*/
u32 pll_bits ;
/* Used to enable or disable lanes. */
u32 pll_val ;
/* Select values of registers and mask, depending on enabled lane
* count .
*/
switch ( dp - > lanes ) {
/* lane 0 */
case ( 1 ) :
pll_bits = 0x00000001 ;
break ;
/* lanes 0-1 */
case ( 2 ) :
pll_bits = 0x00000003 ;
break ;
/* lanes 0-3, all */
default :
pll_bits = 0x0000000F ;
break ;
}
if ( enable )
pll_val = pll_bits ;
else
pll_val = 0x00000000 ;
cdns_torrent_dp_write ( cdns_phy , PHY_PMA_XCVR_PLLCLK_EN , pll_val ) ;
/* Wait for acknowledgment from PHY. */
ret = cdns_torrent_dp_read_poll_timeout ( cdns_phy ,
PHY_PMA_XCVR_PLLCLK_EN_ACK ,
rd_val ,
( rd_val & pll_bits ) = = pll_val ,
0 , POLL_TIMEOUT_US ) ;
ndelay ( 100 ) ;
return ret ;
}
/*
* Perform register operations related to setting link rate , once powerstate is
* set and PLL disable request was processed .
*/
static int cdns_torrent_dp_configure_rate ( struct cdns_torrent_phy * cdns_phy ,
struct phy_configure_opts_dp * dp )
{
u32 ret ;
u32 read_val ;
/* Disable the cmn_pll0_en before re-programming the new data rate. */
cdns_torrent_phy_write ( cdns_phy , PHY_PMA_PLL_RAW_CTRL , 0 ) ;
/*
* Wait for PLL ready de - assertion .
* For PLL0 - PHY_PMA_CMN_CTRL2 [ 2 ] = = 1
*/
ret = cdns_torrent_phy_read_poll_timeout ( cdns_phy , PHY_PMA_CMN_CTRL2 ,
read_val ,
( ( read_val > > 2 ) & 0x01 ) ! = 0 ,
0 , POLL_TIMEOUT_US ) ;
if ( ret )
return ret ;
ndelay ( 200 ) ;
/* DP Rate Change - VCO Output settings. */
if ( cdns_phy - > ref_clk_rate = = REF_CLK_19_2MHz ) {
/* PMA common configuration 19.2MHz */
cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz ( cdns_phy , dp - > link_rate ,
dp - > ssc ) ;
cdns_torrent_dp_pma_cmn_cfg_19_2mhz ( cdns_phy ) ;
} else if ( cdns_phy - > ref_clk_rate = = REF_CLK_25MHz ) {
/* PMA common configuration 25MHz */
cdns_torrent_dp_pma_cmn_vco_cfg_25mhz ( cdns_phy , dp - > link_rate ,
dp - > ssc ) ;
cdns_torrent_dp_pma_cmn_cfg_25mhz ( cdns_phy ) ;
}
cdns_torrent_dp_pma_cmn_rate ( cdns_phy , dp - > link_rate , dp - > lanes ) ;
/* Enable the cmn_pll0_en. */
cdns_torrent_phy_write ( cdns_phy , PHY_PMA_PLL_RAW_CTRL , 0x3 ) ;
/*
* Wait for PLL ready assertion .
* For PLL0 - PHY_PMA_CMN_CTRL2 [ 0 ] = = 1
*/
ret = cdns_torrent_phy_read_poll_timeout ( cdns_phy , PHY_PMA_CMN_CTRL2 ,
read_val ,
( read_val & 0x01 ) ! = 0 ,
0 , POLL_TIMEOUT_US ) ;
return ret ;
}
/*
* Verify , that parameters to configure PHY with are correct .
*/
static int cdns_torrent_dp_verify_config ( struct cdns_torrent_phy * cdns_phy ,
struct phy_configure_opts_dp * dp )
{
u8 i ;
/* If changing link rate was required, verify it's supported. */
if ( dp - > set_rate ) {
switch ( dp - > link_rate ) {
case 1620 :
case 2160 :
case 2430 :
case 2700 :
case 3240 :
case 4320 :
case 5400 :
case 8100 :
/* valid bit rate */
break ;
default :
return - EINVAL ;
}
}
/* Verify lane count. */
switch ( dp - > lanes ) {
case 1 :
case 2 :
case 4 :
/* valid lane count. */
break ;
default :
return - EINVAL ;
}
/* Check against actual number of PHY's lanes. */
if ( dp - > lanes > cdns_phy - > num_lanes )
return - EINVAL ;
/*
* If changing voltages is required , check swing and pre - emphasis
* levels , per - lane .
*/
if ( dp - > set_voltages ) {
/* Lane count verified previously. */
for ( i = 0 ; i < dp - > lanes ; i + + ) {
if ( dp - > voltage [ i ] > 3 | | dp - > pre [ i ] > 3 )
return - EINVAL ;
/* Sum of voltage swing and pre-emphasis levels cannot
* exceed 3.
*/
if ( dp - > voltage [ i ] + dp - > pre [ i ] > 3 )
return - EINVAL ;
}
}
return 0 ;
}
2020-02-06 07:10:55 +01:00
/* Set power state A0 and PLL clock enable to 0 on enabled lanes. */
static void cdns_torrent_dp_set_a0_pll ( struct cdns_torrent_phy * cdns_phy ,
u32 num_lanes )
{
u32 pwr_state = cdns_torrent_dp_read ( cdns_phy ,
PHY_PMA_XCVR_POWER_STATE_REQ ) ;
u32 pll_clk_en = cdns_torrent_dp_read ( cdns_phy ,
PHY_PMA_XCVR_PLLCLK_EN ) ;
/* Lane 0 is always enabled. */
pwr_state & = ~ ( PMA_XCVR_POWER_STATE_REQ_LN_MASK < <
PHY_POWER_STATE_LN_0 ) ;
pll_clk_en & = ~ 0x01U ;
if ( num_lanes > 1 ) {
/* lane 1 */
pwr_state & = ~ ( PMA_XCVR_POWER_STATE_REQ_LN_MASK < <
PHY_POWER_STATE_LN_1 ) ;
pll_clk_en & = ~ ( 0x01U < < 1 ) ;
}
if ( num_lanes > 2 ) {
/* lanes 2 and 3 */
pwr_state & = ~ ( PMA_XCVR_POWER_STATE_REQ_LN_MASK < <
PHY_POWER_STATE_LN_2 ) ;
pwr_state & = ~ ( PMA_XCVR_POWER_STATE_REQ_LN_MASK < <
PHY_POWER_STATE_LN_3 ) ;
pll_clk_en & = ~ ( 0x01U < < 2 ) ;
pll_clk_en & = ~ ( 0x01U < < 3 ) ;
}
cdns_torrent_dp_write ( cdns_phy ,
PHY_PMA_XCVR_POWER_STATE_REQ , pwr_state ) ;
cdns_torrent_dp_write ( cdns_phy , PHY_PMA_XCVR_PLLCLK_EN , pll_clk_en ) ;
}
2020-02-06 07:10:57 +01:00
/* Configure lane count as required. */
static int cdns_torrent_dp_set_lanes ( struct cdns_torrent_phy * cdns_phy ,
struct phy_configure_opts_dp * dp )
{
u32 value ;
u32 ret ;
u8 lane_mask = ( 1 < < dp - > lanes ) - 1 ;
value = cdns_torrent_dp_read ( cdns_phy , PHY_RESET ) ;
/* clear pma_tx_elec_idle_ln_* bits. */
value & = ~ PMA_TX_ELEC_IDLE_MASK ;
/* Assert pma_tx_elec_idle_ln_* for disabled lanes. */
value | = ( ( ~ lane_mask ) < < PMA_TX_ELEC_IDLE_SHIFT ) &
PMA_TX_ELEC_IDLE_MASK ;
cdns_torrent_dp_write ( cdns_phy , PHY_RESET , value ) ;
/* reset the link by asserting phy_l00_reset_n low */
cdns_torrent_dp_write ( cdns_phy , PHY_RESET ,
value & ( ~ PHY_L00_RESET_N_MASK ) ) ;
/*
* Assert lane reset on unused lanes and lane 0 so they remain in reset
* and powered down when re - enabling the link
*/
value = ( value & 0x0000FFF0 ) | ( 0x0000000E & lane_mask ) ;
cdns_torrent_dp_write ( cdns_phy , PHY_RESET , value ) ;
cdns_torrent_dp_set_a0_pll ( cdns_phy , dp - > lanes ) ;
/* release phy_l0*_reset_n based on used laneCount */
value = ( value & 0x0000FFF0 ) | ( 0x0000000F & lane_mask ) ;
cdns_torrent_dp_write ( cdns_phy , PHY_RESET , value ) ;
/* Wait, until PHY gets ready after releasing PHY reset signal. */
ret = cdns_torrent_dp_wait_pma_cmn_ready ( cdns_phy ) ;
if ( ret )
return ret ;
ndelay ( 100 ) ;
/* release pma_xcvr_pllclk_en_ln_*, only for the master lane */
cdns_torrent_dp_write ( cdns_phy , PHY_PMA_XCVR_PLLCLK_EN , 0x0001 ) ;
ret = cdns_torrent_dp_run ( cdns_phy , dp - > lanes ) ;
return ret ;
}
/* Configure link rate as required. */
static int cdns_torrent_dp_set_rate ( struct cdns_torrent_phy * cdns_phy ,
struct phy_configure_opts_dp * dp )
{
u32 ret ;
ret = cdns_torrent_dp_set_power_state ( cdns_phy , dp - > lanes ,
POWERSTATE_A3 ) ;
if ( ret )
return ret ;
ret = cdns_torrent_dp_set_pll_en ( cdns_phy , dp , false ) ;
if ( ret )
return ret ;
ndelay ( 200 ) ;
ret = cdns_torrent_dp_configure_rate ( cdns_phy , dp ) ;
if ( ret )
return ret ;
ndelay ( 200 ) ;
ret = cdns_torrent_dp_set_pll_en ( cdns_phy , dp , true ) ;
if ( ret )
return ret ;
ret = cdns_torrent_dp_set_power_state ( cdns_phy , dp - > lanes ,
POWERSTATE_A2 ) ;
if ( ret )
return ret ;
ret = cdns_torrent_dp_set_power_state ( cdns_phy , dp - > lanes ,
POWERSTATE_A0 ) ;
if ( ret )
return ret ;
ndelay ( 900 ) ;
return ret ;
}
/* Configure voltage swing and pre-emphasis for all enabled lanes. */
static void cdns_torrent_dp_set_voltages ( struct cdns_torrent_phy * cdns_phy ,
struct phy_configure_opts_dp * dp )
{
u8 lane ;
u16 val ;
unsigned int lane_bits ;
for ( lane = 0 ; lane < dp - > lanes ; lane + + ) {
lane_bits = ( lane & LANE_MASK ) < < 11 ;
val = cdns_torrent_phy_read ( cdns_phy ,
( TX_DIAG_ACYA | lane_bits ) ) ;
/*
* Write 1 to register bit TX_DIAG_ACYA [ 0 ] to freeze the
* current state of the analog TX driver .
*/
val | = TX_DIAG_ACYA_HBDC_MASK ;
cdns_torrent_phy_write ( cdns_phy ,
( TX_DIAG_ACYA | lane_bits ) , val ) ;
cdns_torrent_phy_write ( cdns_phy ,
( TX_TXCC_CTRL | lane_bits ) , 0x08A4 ) ;
val = vltg_coeff [ dp - > voltage [ lane ] ] [ dp - > pre [ lane ] ] . diag_tx_drv ;
cdns_torrent_phy_write ( cdns_phy ,
( DRV_DIAG_TX_DRV | lane_bits ) , val ) ;
val = vltg_coeff [ dp - > voltage [ lane ] ] [ dp - > pre [ lane ] ] . mgnfs_mult ;
cdns_torrent_phy_write ( cdns_phy ,
( TX_TXCC_MGNFS_MULT_000 | lane_bits ) ,
val ) ;
val = vltg_coeff [ dp - > voltage [ lane ] ] [ dp - > pre [ lane ] ] . cpost_mult ;
cdns_torrent_phy_write ( cdns_phy ,
( TX_TXCC_CPOST_MULT_00 | lane_bits ) ,
val ) ;
val = cdns_torrent_phy_read ( cdns_phy ,
( TX_DIAG_ACYA | lane_bits ) ) ;
/*
* Write 0 to register bit TX_DIAG_ACYA [ 0 ] to allow the state of
* analog TX driver to reflect the new programmed one .
*/
val & = ~ TX_DIAG_ACYA_HBDC_MASK ;
cdns_torrent_phy_write ( cdns_phy ,
( TX_DIAG_ACYA | lane_bits ) , val ) ;
}
} ;
static int cdns_torrent_dp_configure ( struct phy * phy ,
union phy_configure_opts * opts )
{
struct cdns_torrent_phy * cdns_phy = phy_get_drvdata ( phy ) ;
int ret ;
ret = cdns_torrent_dp_verify_config ( cdns_phy , & opts - > dp ) ;
if ( ret ) {
dev_err ( & phy - > dev , " invalid params for phy configure \n " ) ;
return ret ;
}
if ( opts - > dp . set_lanes ) {
ret = cdns_torrent_dp_set_lanes ( cdns_phy , & opts - > dp ) ;
if ( ret ) {
dev_err ( & phy - > dev , " cdns_torrent_dp_set_lanes failed \n " ) ;
return ret ;
}
}
if ( opts - > dp . set_rate ) {
ret = cdns_torrent_dp_set_rate ( cdns_phy , & opts - > dp ) ;
if ( ret ) {
dev_err ( & phy - > dev , " cdns_torrent_dp_set_rate failed \n " ) ;
return ret ;
}
}
if ( opts - > dp . set_voltages )
cdns_torrent_dp_set_voltages ( cdns_phy , & opts - > dp ) ;
return ret ;
}
2020-02-06 07:10:52 +01:00
static int cdns_torrent_dp_init ( struct phy * phy )
2018-08-09 11:30:30 +01:00
{
unsigned char lane_bits ;
2020-02-06 07:10:55 +01:00
int ret ;
2018-08-09 11:30:30 +01:00
2020-02-06 07:10:52 +01:00
struct cdns_torrent_phy * cdns_phy = phy_get_drvdata ( phy ) ;
2018-08-09 11:30:30 +01:00
2020-02-06 07:10:56 +01:00
ret = clk_prepare_enable ( cdns_phy - > clk ) ;
if ( ret ) {
dev_err ( cdns_phy - > dev , " Failed to prepare ref clock \n " ) ;
return ret ;
}
cdns_phy - > ref_clk_rate = clk_get_rate ( cdns_phy - > clk ) ;
if ( ! ( cdns_phy - > ref_clk_rate ) ) {
dev_err ( cdns_phy - > dev , " Failed to get ref clock rate \n " ) ;
clk_disable_unprepare ( cdns_phy - > clk ) ;
return - EINVAL ;
}
switch ( cdns_phy - > ref_clk_rate ) {
case REF_CLK_19_2MHz :
case REF_CLK_25MHz :
/* Valid Ref Clock Rate */
break ;
default :
dev_err ( cdns_phy - > dev , " Unsupported Ref Clock Rate \n " ) ;
return - EINVAL ;
}
2020-02-06 07:10:54 +01:00
cdns_torrent_dp_write ( cdns_phy , PHY_AUX_CTRL , 0x0003 ) ; /* enable AUX */
2018-08-09 11:30:30 +01:00
/* PHY PMA registers configuration function */
2020-02-06 07:10:52 +01:00
cdns_torrent_dp_pma_cfg ( cdns_phy ) ;
2018-08-09 11:30:30 +01:00
/*
* Set lines power state to A0
* Set lines pll clk enable to 0
*/
2020-02-06 07:10:55 +01:00
cdns_torrent_dp_set_a0_pll ( cdns_phy , cdns_phy - > num_lanes ) ;
2018-08-09 11:30:30 +01:00
/*
* release phy_l0 * _reset_n and pma_tx_elec_idle_ln_ * based on
* used lanes
*/
lane_bits = ( 1 < < cdns_phy - > num_lanes ) - 1 ;
2020-02-06 07:10:54 +01:00
cdns_torrent_dp_write ( cdns_phy , PHY_RESET ,
( ( 0xF & ~ lane_bits ) < < 4 ) | ( 0xF & lane_bits ) ) ;
2018-08-09 11:30:30 +01:00
/* release pma_xcvr_pllclk_en_ln_*, only for the master lane */
2020-02-06 07:10:54 +01:00
cdns_torrent_dp_write ( cdns_phy , PHY_PMA_XCVR_PLLCLK_EN , 0x0001 ) ;
2018-08-09 11:30:30 +01:00
/* PHY PMA registers configuration functions */
2020-02-06 07:10:56 +01:00
/* Initialize PHY with max supported link rate, without SSC. */
if ( cdns_phy - > ref_clk_rate = = REF_CLK_19_2MHz )
cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz ( cdns_phy ,
cdns_phy - > max_bit_rate ,
false ) ;
else if ( cdns_phy - > ref_clk_rate = = REF_CLK_25MHz )
cdns_torrent_dp_pma_cmn_vco_cfg_25mhz ( cdns_phy ,
cdns_phy - > max_bit_rate ,
false ) ;
cdns_torrent_dp_pma_cmn_rate ( cdns_phy , cdns_phy - > max_bit_rate ,
cdns_phy - > num_lanes ) ;
2018-08-09 11:30:30 +01:00
/* take out of reset */
cdns_dp_phy_write_field ( cdns_phy , PHY_RESET , 8 , 1 , 1 ) ;
2020-02-06 07:10:55 +01:00
ret = cdns_torrent_dp_wait_pma_cmn_ready ( cdns_phy ) ;
if ( ret )
return ret ;
2018-08-09 11:30:30 +01:00
2020-02-06 07:10:57 +01:00
ret = cdns_torrent_dp_run ( cdns_phy , cdns_phy - > num_lanes ) ;
2020-02-06 07:10:55 +01:00
return ret ;
2018-08-09 11:30:30 +01:00
}
2020-02-06 07:10:56 +01:00
static int cdns_torrent_dp_exit ( struct phy * phy )
{
struct cdns_torrent_phy * cdns_phy = phy_get_drvdata ( phy ) ;
clk_disable_unprepare ( cdns_phy - > clk ) ;
return 0 ;
}
2020-02-06 07:10:52 +01:00
static
2020-02-06 07:10:55 +01:00
int cdns_torrent_dp_wait_pma_cmn_ready ( struct cdns_torrent_phy * cdns_phy )
2018-08-09 11:30:30 +01:00
{
unsigned int reg ;
int ret ;
2020-02-06 07:10:54 +01:00
ret = cdns_torrent_dp_read_poll_timeout ( cdns_phy , PHY_PMA_CMN_READY ,
2020-02-06 07:10:55 +01:00
reg , reg & 1 , 0 ,
POLL_TIMEOUT_US ) ;
if ( ret = = - ETIMEDOUT ) {
2018-08-09 11:30:30 +01:00
dev_err ( cdns_phy - > dev ,
" timeout waiting for PMA common ready \n " ) ;
2020-02-06 07:10:55 +01:00
return - ETIMEDOUT ;
}
return 0 ;
2018-08-09 11:30:30 +01:00
}
2020-02-06 07:10:52 +01:00
static void cdns_torrent_dp_pma_cfg ( struct cdns_torrent_phy * cdns_phy )
2018-08-09 11:30:30 +01:00
{
unsigned int i ;
2020-02-06 07:10:56 +01:00
if ( cdns_phy - > ref_clk_rate = = REF_CLK_19_2MHz )
/* PMA common configuration 19.2MHz */
cdns_torrent_dp_pma_cmn_cfg_19_2mhz ( cdns_phy ) ;
else if ( cdns_phy - > ref_clk_rate = = REF_CLK_25MHz )
/* PMA common configuration 25MHz */
cdns_torrent_dp_pma_cmn_cfg_25mhz ( cdns_phy ) ;
2018-08-09 11:30:30 +01:00
/* PMA lane configuration to deal with multi-link operation */
for ( i = 0 ; i < cdns_phy - > num_lanes ; i + + )
2020-02-06 07:10:52 +01:00
cdns_torrent_dp_pma_lane_cfg ( cdns_phy , i ) ;
2018-08-09 11:30:30 +01:00
}
2020-02-06 07:10:56 +01:00
static
void cdns_torrent_dp_pma_cmn_cfg_19_2mhz ( struct cdns_torrent_phy * cdns_phy )
{
/* refclock registers - assumes 19.2 MHz refclock */
cdns_torrent_phy_write ( cdns_phy , CMN_SSM_BIAS_TMR , 0x0014 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLLSM0_PLLPRE_TMR , 0x0027 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLLSM0_PLLLOCK_TMR , 0x00A1 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLLSM1_PLLPRE_TMR , 0x0027 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLLSM1_PLLLOCK_TMR , 0x00A1 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_BGCAL_INIT_TMR , 0x0060 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_BGCAL_ITER_TMR , 0x0060 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_IBCAL_INIT_TMR , 0x0014 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_TXPUCAL_INIT_TMR , 0x0018 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_TXPUCAL_ITER_TMR , 0x0005 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_TXPDCAL_INIT_TMR , 0x0018 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_TXPDCAL_ITER_TMR , 0x0005 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_RXCAL_INIT_TMR , 0x0240 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_RXCAL_ITER_TMR , 0x0005 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_SD_CAL_INIT_TMR , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_SD_CAL_ITER_TMR , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_SD_CAL_REFTIM_START , 0x000B ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_SD_CAL_PLLCNT_START , 0x0137 ) ;
/* PLL registers */
cdns_torrent_phy_write ( cdns_phy , CMN_PDIAG_PLL0_CP_PADJ_M0 , 0x0509 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PDIAG_PLL0_CP_IADJ_M0 , 0x0F00 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PDIAG_PLL0_FILT_PADJ_M0 , 0x0F08 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_DSM_DIAG_M0 , 0x0004 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PDIAG_PLL1_CP_PADJ_M0 , 0x0509 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PDIAG_PLL1_CP_IADJ_M0 , 0x0F00 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PDIAG_PLL1_FILT_PADJ_M0 , 0x0F08 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_DSM_DIAG_M0 , 0x0004 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_VCOCAL_INIT_TMR , 0x00C0 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_VCOCAL_ITER_TMR , 0x0004 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_VCOCAL_INIT_TMR , 0x00C0 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_VCOCAL_ITER_TMR , 0x0004 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_VCOCAL_REFTIM_START , 0x0260 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_VCOCAL_TCTRL , 0x0003 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_VCOCAL_REFTIM_START , 0x0260 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_VCOCAL_TCTRL , 0x0003 ) ;
}
/*
* Set registers responsible for enabling and configuring SSC , with second and
* third register values provided by parameters .
*/
static
void cdns_torrent_dp_enable_ssc_19_2mhz ( struct cdns_torrent_phy * cdns_phy ,
u32 ctrl2_val , u32 ctrl3_val )
{
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_SS_CTRL1_M0 , 0x0001 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_SS_CTRL1_M0 , ctrl2_val ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_SS_CTRL1_M0 , ctrl3_val ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_SS_CTRL4_M0 , 0x0003 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_SS_CTRL1_M0 , 0x0001 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_SS_CTRL1_M0 , ctrl2_val ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_SS_CTRL1_M0 , ctrl3_val ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_SS_CTRL4_M0 , 0x0003 ) ;
}
static
void cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz ( struct cdns_torrent_phy * cdns_phy ,
u32 rate , bool ssc )
{
/* Assumes 19.2 MHz refclock */
switch ( rate ) {
/* Setting VCO for 10.8GHz */
case 2700 :
case 5400 :
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_INTDIV_M0 , 0x0119 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_FRACDIVL_M0 , 0x4000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_FRACDIVH_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_HIGH_THR_M0 , 0x00BC ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PDIAG_PLL0_CTRL_M0 , 0x0012 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_INTDIV_M0 , 0x0119 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_FRACDIVL_M0 , 0x4000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_FRACDIVH_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_HIGH_THR_M0 , 0x00BC ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PDIAG_PLL1_CTRL_M0 , 0x0012 ) ;
if ( ssc )
cdns_torrent_dp_enable_ssc_19_2mhz ( cdns_phy , 0x033A ,
0x006A ) ;
break ;
/* Setting VCO for 9.72GHz */
case 1620 :
case 2430 :
case 3240 :
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_INTDIV_M0 , 0x01FA ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_FRACDIVL_M0 , 0x4000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_FRACDIVH_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_HIGH_THR_M0 , 0x0152 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PDIAG_PLL0_CTRL_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_INTDIV_M0 , 0x01FA ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_FRACDIVL_M0 , 0x4000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_FRACDIVH_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_HIGH_THR_M0 , 0x0152 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PDIAG_PLL1_CTRL_M0 , 0x0002 ) ;
if ( ssc )
cdns_torrent_dp_enable_ssc_19_2mhz ( cdns_phy , 0x05DD ,
0x0069 ) ;
break ;
/* Setting VCO for 8.64GHz */
case 2160 :
case 4320 :
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_INTDIV_M0 , 0x01C2 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_FRACDIVL_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_FRACDIVH_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_HIGH_THR_M0 , 0x012C ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PDIAG_PLL0_CTRL_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_INTDIV_M0 , 0x01C2 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_FRACDIVL_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_FRACDIVH_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_HIGH_THR_M0 , 0x012C ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PDIAG_PLL1_CTRL_M0 , 0x0002 ) ;
if ( ssc )
cdns_torrent_dp_enable_ssc_19_2mhz ( cdns_phy , 0x0536 ,
0x0069 ) ;
break ;
/* Setting VCO for 8.1GHz */
case 8100 :
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_INTDIV_M0 , 0x01A5 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_FRACDIVL_M0 , 0xE000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_FRACDIVH_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_HIGH_THR_M0 , 0x011A ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PDIAG_PLL0_CTRL_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_INTDIV_M0 , 0x01A5 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_FRACDIVL_M0 , 0xE000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_FRACDIVH_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_HIGH_THR_M0 , 0x011A ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PDIAG_PLL1_CTRL_M0 , 0x0002 ) ;
if ( ssc )
cdns_torrent_dp_enable_ssc_19_2mhz ( cdns_phy , 0x04D7 ,
0x006A ) ;
break ;
}
if ( ssc ) {
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_VCOCAL_PLLCNT_START , 0x025E ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_LOCK_PLLCNT_THR , 0x0005 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_VCOCAL_PLLCNT_START , 0x025E ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_LOCK_PLLCNT_THR , 0x0005 ) ;
} else {
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_VCOCAL_PLLCNT_START , 0x0260 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_VCOCAL_PLLCNT_START , 0x0260 ) ;
/* Set reset register values to disable SSC */
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_SS_CTRL1_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_SS_CTRL2_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_SS_CTRL3_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_SS_CTRL4_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_LOCK_PLLCNT_THR , 0x0003 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_SS_CTRL1_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_SS_CTRL2_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_SS_CTRL3_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_SS_CTRL4_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_LOCK_PLLCNT_THR , 0x0003 ) ;
}
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_LOCK_REFCNT_START , 0x0099 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_LOCK_PLLCNT_START , 0x0099 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_LOCK_REFCNT_START , 0x0099 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_LOCK_PLLCNT_START , 0x0099 ) ;
}
2020-02-06 07:10:52 +01:00
static
void cdns_torrent_dp_pma_cmn_cfg_25mhz ( struct cdns_torrent_phy * cdns_phy )
2018-08-09 11:30:30 +01:00
{
/* refclock registers - assumes 25 MHz refclock */
2020-02-06 07:10:53 +01:00
cdns_torrent_phy_write ( cdns_phy , CMN_SSM_BIAS_TMR , 0x0019 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLLSM0_PLLPRE_TMR , 0x0032 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLLSM0_PLLLOCK_TMR , 0x00D1 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLLSM1_PLLPRE_TMR , 0x0032 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLLSM1_PLLLOCK_TMR , 0x00D1 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_BGCAL_INIT_TMR , 0x007D ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_BGCAL_ITER_TMR , 0x007D ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_IBCAL_INIT_TMR , 0x0019 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_TXPUCAL_INIT_TMR , 0x001E ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_TXPUCAL_ITER_TMR , 0x0006 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_TXPDCAL_INIT_TMR , 0x001E ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_TXPDCAL_ITER_TMR , 0x0006 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_RXCAL_INIT_TMR , 0x02EE ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_RXCAL_ITER_TMR , 0x0006 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_SD_CAL_INIT_TMR , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_SD_CAL_ITER_TMR , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_SD_CAL_REFTIM_START , 0x000E ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_SD_CAL_PLLCNT_START , 0x012B ) ;
2018-08-09 11:30:30 +01:00
/* PLL registers */
2020-02-06 07:10:56 +01:00
cdns_torrent_phy_write ( cdns_phy , CMN_PDIAG_PLL0_CP_PADJ_M0 , 0x0509 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PDIAG_PLL0_CP_IADJ_M0 , 0x0F00 ) ;
2020-02-06 07:10:53 +01:00
cdns_torrent_phy_write ( cdns_phy , CMN_PDIAG_PLL0_FILT_PADJ_M0 , 0x0F08 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_DSM_DIAG_M0 , 0x0004 ) ;
2020-02-06 07:10:56 +01:00
cdns_torrent_phy_write ( cdns_phy , CMN_PDIAG_PLL1_CP_PADJ_M0 , 0x0509 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PDIAG_PLL1_CP_IADJ_M0 , 0x0F00 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PDIAG_PLL1_FILT_PADJ_M0 , 0x0F08 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_DSM_DIAG_M0 , 0x0004 ) ;
2020-02-06 07:10:53 +01:00
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_VCOCAL_INIT_TMR , 0x00FA ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_VCOCAL_ITER_TMR , 0x0004 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_VCOCAL_INIT_TMR , 0x00FA ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_VCOCAL_ITER_TMR , 0x0004 ) ;
2020-02-06 07:10:56 +01:00
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_VCOCAL_REFTIM_START , 0x0317 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_VCOCAL_TCTRL , 0x0003 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_VCOCAL_REFTIM_START , 0x0317 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_VCOCAL_TCTRL , 0x0003 ) ;
}
/*
* Set registers responsible for enabling and configuring SSC , with second
* register value provided by a parameter .
*/
static void cdns_torrent_dp_enable_ssc_25mhz ( struct cdns_torrent_phy * cdns_phy ,
u32 ctrl2_val )
{
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_SS_CTRL1_M0 , 0x0001 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_SS_CTRL1_M0 , ctrl2_val ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_SS_CTRL1_M0 , 0x007F ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_SS_CTRL4_M0 , 0x0003 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_SS_CTRL1_M0 , 0x0001 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_SS_CTRL1_M0 , ctrl2_val ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_SS_CTRL1_M0 , 0x007F ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_SS_CTRL4_M0 , 0x0003 ) ;
2018-08-09 11:30:30 +01:00
}
2020-02-06 07:10:52 +01:00
static
2020-02-06 07:10:56 +01:00
void cdns_torrent_dp_pma_cmn_vco_cfg_25mhz ( struct cdns_torrent_phy * cdns_phy ,
u32 rate , bool ssc )
2018-08-09 11:30:30 +01:00
{
/* Assumes 25 MHz refclock */
2020-02-06 07:10:56 +01:00
switch ( rate ) {
2020-02-06 07:10:53 +01:00
/* Setting VCO for 10.8GHz */
2018-08-09 11:30:30 +01:00
case 2700 :
case 5400 :
2020-02-06 07:10:53 +01:00
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_INTDIV_M0 , 0x01B0 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_FRACDIVL_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_FRACDIVH_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_HIGH_THR_M0 , 0x0120 ) ;
2020-02-06 07:10:56 +01:00
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_INTDIV_M0 , 0x01B0 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_FRACDIVL_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_FRACDIVH_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_HIGH_THR_M0 , 0x0120 ) ;
if ( ssc )
cdns_torrent_dp_enable_ssc_25mhz ( cdns_phy , 0x0423 ) ;
2018-08-09 11:30:30 +01:00
break ;
2020-02-06 07:10:53 +01:00
/* Setting VCO for 9.72GHz */
2020-02-06 07:10:56 +01:00
case 1620 :
2018-08-09 11:30:30 +01:00
case 2430 :
case 3240 :
2020-02-06 07:10:53 +01:00
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_INTDIV_M0 , 0x0184 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_FRACDIVL_M0 , 0xCCCD ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_FRACDIVH_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_HIGH_THR_M0 , 0x0104 ) ;
2020-02-06 07:10:56 +01:00
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_INTDIV_M0 , 0x0184 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_FRACDIVL_M0 , 0xCCCD ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_FRACDIVH_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_HIGH_THR_M0 , 0x0104 ) ;
if ( ssc )
cdns_torrent_dp_enable_ssc_25mhz ( cdns_phy , 0x03B9 ) ;
2018-08-09 11:30:30 +01:00
break ;
2020-02-06 07:10:53 +01:00
/* Setting VCO for 8.64GHz */
2018-08-09 11:30:30 +01:00
case 2160 :
case 4320 :
2020-02-06 07:10:53 +01:00
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_INTDIV_M0 , 0x0159 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_FRACDIVL_M0 , 0x999A ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_FRACDIVH_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_HIGH_THR_M0 , 0x00E7 ) ;
2020-02-06 07:10:56 +01:00
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_INTDIV_M0 , 0x0159 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_FRACDIVL_M0 , 0x999A ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_FRACDIVH_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_HIGH_THR_M0 , 0x00E7 ) ;
if ( ssc )
cdns_torrent_dp_enable_ssc_25mhz ( cdns_phy , 0x034F ) ;
2018-08-09 11:30:30 +01:00
break ;
2020-02-06 07:10:53 +01:00
/* Setting VCO for 8.1GHz */
2018-08-09 11:30:30 +01:00
case 8100 :
2020-02-06 07:10:53 +01:00
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_INTDIV_M0 , 0x0144 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_FRACDIVL_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_FRACDIVH_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_HIGH_THR_M0 , 0x00D8 ) ;
2020-02-06 07:10:56 +01:00
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_INTDIV_M0 , 0x0144 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_FRACDIVL_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_FRACDIVH_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_HIGH_THR_M0 , 0x00D8 ) ;
if ( ssc )
cdns_torrent_dp_enable_ssc_25mhz ( cdns_phy , 0x031A ) ;
2018-08-09 11:30:30 +01:00
break ;
}
2020-02-06 07:10:53 +01:00
cdns_torrent_phy_write ( cdns_phy , CMN_PDIAG_PLL0_CTRL_M0 , 0x0002 ) ;
2020-02-06 07:10:56 +01:00
cdns_torrent_phy_write ( cdns_phy , CMN_PDIAG_PLL1_CTRL_M0 , 0x0002 ) ;
if ( ssc ) {
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_VCOCAL_PLLCNT_START , 0x0315 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_LOCK_PLLCNT_THR , 0x0005 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_VCOCAL_PLLCNT_START , 0x0315 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_LOCK_PLLCNT_THR , 0x0005 ) ;
} else {
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_VCOCAL_PLLCNT_START , 0x0317 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_VCOCAL_PLLCNT_START , 0x0317 ) ;
/* Set reset register values to disable SSC */
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_SS_CTRL1_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_SS_CTRL2_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_SS_CTRL3_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_SS_CTRL4_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL0_LOCK_PLLCNT_THR , 0x0003 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_SS_CTRL1_M0 , 0x0002 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_SS_CTRL2_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_SS_CTRL3_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_SS_CTRL4_M0 , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
CMN_PLL1_LOCK_PLLCNT_THR , 0x0003 ) ;
}
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_LOCK_REFCNT_START , 0x00C7 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL0_LOCK_PLLCNT_START , 0x00C7 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_LOCK_REFCNT_START , 0x00C7 ) ;
cdns_torrent_phy_write ( cdns_phy , CMN_PLL1_LOCK_PLLCNT_START , 0x00C7 ) ;
2018-08-09 11:30:30 +01:00
}
2020-02-06 07:10:56 +01:00
static void cdns_torrent_dp_pma_cmn_rate ( struct cdns_torrent_phy * cdns_phy ,
u32 rate , u32 num_lanes )
2018-08-09 11:30:30 +01:00
{
unsigned int clk_sel_val = 0 ;
unsigned int hsclk_div_val = 0 ;
unsigned int i ;
/* 16'h0000 for single DP link configuration */
2020-02-06 07:10:53 +01:00
cdns_torrent_phy_write ( cdns_phy , PHY_PLL_CFG , 0x0000 ) ;
2018-08-09 11:30:30 +01:00
2020-02-06 07:10:56 +01:00
switch ( rate ) {
2018-08-09 11:30:30 +01:00
case 1620 :
clk_sel_val = 0x0f01 ;
hsclk_div_val = 2 ;
break ;
case 2160 :
case 2430 :
case 2700 :
clk_sel_val = 0x0701 ;
2020-02-06 07:10:53 +01:00
hsclk_div_val = 1 ;
2018-08-09 11:30:30 +01:00
break ;
case 3240 :
clk_sel_val = 0x0b00 ;
hsclk_div_val = 2 ;
break ;
case 4320 :
case 5400 :
clk_sel_val = 0x0301 ;
hsclk_div_val = 0 ;
break ;
case 8100 :
clk_sel_val = 0x0200 ;
hsclk_div_val = 0 ;
break ;
}
2020-02-06 07:10:53 +01:00
cdns_torrent_phy_write ( cdns_phy ,
CMN_PDIAG_PLL0_CLK_SEL_M0 , clk_sel_val ) ;
2020-02-06 07:10:56 +01:00
cdns_torrent_phy_write ( cdns_phy ,
CMN_PDIAG_PLL1_CLK_SEL_M0 , clk_sel_val ) ;
2018-08-09 11:30:30 +01:00
/* PMA lane configuration to deal with multi-link operation */
2020-02-06 07:10:56 +01:00
for ( i = 0 ; i < num_lanes ; i + + )
2020-02-06 07:10:53 +01:00
cdns_torrent_phy_write ( cdns_phy ,
( XCVR_DIAG_HSCLK_DIV | ( i < < 11 ) ) ,
hsclk_div_val ) ;
2018-08-09 11:30:30 +01:00
}
2020-02-06 07:10:52 +01:00
static void cdns_torrent_dp_pma_lane_cfg ( struct cdns_torrent_phy * cdns_phy ,
unsigned int lane )
2018-08-09 11:30:30 +01:00
{
unsigned int lane_bits = ( lane & LANE_MASK ) < < 11 ;
2020-02-06 07:10:56 +01:00
/* Per lane, refclock-dependent receiver detection setting */
if ( cdns_phy - > ref_clk_rate = = REF_CLK_19_2MHz )
cdns_torrent_phy_write ( cdns_phy ,
( TX_RCVDET_ST_TMR | lane_bits ) , 0x0780 ) ;
else if ( cdns_phy - > ref_clk_rate = = REF_CLK_25MHz )
cdns_torrent_phy_write ( cdns_phy ,
( TX_RCVDET_ST_TMR | lane_bits ) , 0x09C4 ) ;
2018-08-09 11:30:30 +01:00
/* Writing Tx/Rx Power State Controllers registers */
2020-02-06 07:10:53 +01:00
cdns_torrent_phy_write ( cdns_phy , ( TX_PSC_A0 | lane_bits ) , 0x00FB ) ;
cdns_torrent_phy_write ( cdns_phy , ( TX_PSC_A2 | lane_bits ) , 0x04AA ) ;
cdns_torrent_phy_write ( cdns_phy , ( TX_PSC_A3 | lane_bits ) , 0x04AA ) ;
cdns_torrent_phy_write ( cdns_phy , ( RX_PSC_A0 | lane_bits ) , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy , ( RX_PSC_A2 | lane_bits ) , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy , ( RX_PSC_A3 | lane_bits ) , 0x0000 ) ;
2020-02-06 07:10:56 +01:00
cdns_torrent_phy_write ( cdns_phy , ( RX_PSC_CAL | lane_bits ) , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
( RX_REE_GCSM1_CTRL | lane_bits ) , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
( RX_REE_GCSM2_CTRL | lane_bits ) , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
( RX_REE_PERGCSM_CTRL | lane_bits ) , 0x0000 ) ;
cdns_torrent_phy_write ( cdns_phy ,
( XCVR_DIAG_BIDI_CTRL | lane_bits ) , 0x000F ) ;
2020-02-06 07:10:53 +01:00
cdns_torrent_phy_write ( cdns_phy ,
( XCVR_DIAG_PLLDRC_CTRL | lane_bits ) , 0x0001 ) ;
cdns_torrent_phy_write ( cdns_phy ,
( XCVR_DIAG_HSCLK_SEL | lane_bits ) , 0x0000 ) ;
2018-08-09 11:30:30 +01:00
}
2020-02-06 07:10:55 +01:00
static int cdns_torrent_dp_set_power_state ( struct cdns_torrent_phy * cdns_phy ,
u32 num_lanes ,
enum phy_powerstate powerstate )
{
/* Register value for power state for a single byte. */
u32 value_part ;
u32 value ;
u32 mask ;
u32 read_val ;
u32 ret ;
switch ( powerstate ) {
case ( POWERSTATE_A0 ) :
value_part = 0x01U ;
break ;
case ( POWERSTATE_A2 ) :
value_part = 0x04U ;
break ;
default :
/* Powerstate A3 */
value_part = 0x08U ;
break ;
}
/* Select values of registers and mask, depending on enabled
* lane count .
*/
switch ( num_lanes ) {
/* lane 0 */
case ( 1 ) :
value = value_part ;
mask = 0x0000003FU ;
break ;
/* lanes 0-1 */
case ( 2 ) :
value = ( value_part
| ( value_part < < 8 ) ) ;
mask = 0x00003F3FU ;
break ;
/* lanes 0-3, all */
default :
value = ( value_part
| ( value_part < < 8 )
| ( value_part < < 16 )
| ( value_part < < 24 ) ) ;
mask = 0x3F3F3F3FU ;
break ;
}
/* Set power state A<n>. */
cdns_torrent_dp_write ( cdns_phy , PHY_PMA_XCVR_POWER_STATE_REQ , value ) ;
/* Wait, until PHY acknowledges power state completion. */
ret = cdns_torrent_dp_read_poll_timeout ( cdns_phy ,
PHY_PMA_XCVR_POWER_STATE_ACK ,
read_val ,
( read_val & mask ) = = value , 0 ,
POLL_TIMEOUT_US ) ;
cdns_torrent_dp_write ( cdns_phy ,
PHY_PMA_XCVR_POWER_STATE_REQ , 0x00000000 ) ;
ndelay ( 100 ) ;
return ret ;
}
2020-02-06 07:10:57 +01:00
static int cdns_torrent_dp_run ( struct cdns_torrent_phy * cdns_phy , u32 num_lanes )
2018-08-09 11:30:30 +01:00
{
unsigned int read_val ;
int ret ;
/*
* waiting for ACK of pma_xcvr_pllclk_en_ln_ * , only for the
* master lane
*/
2020-02-06 07:10:54 +01:00
ret = cdns_torrent_dp_read_poll_timeout ( cdns_phy ,
PHY_PMA_XCVR_PLLCLK_EN_ACK ,
read_val , read_val & 1 , 0 ,
POLL_TIMEOUT_US ) ;
2020-02-06 07:10:55 +01:00
if ( ret = = - ETIMEDOUT ) {
2018-08-09 11:30:30 +01:00
dev_err ( cdns_phy - > dev ,
" timeout waiting for link PLL clock enable ack \n " ) ;
2020-02-06 07:10:55 +01:00
return ret ;
2018-08-09 11:30:30 +01:00
}
ndelay ( 100 ) ;
2020-02-06 07:10:57 +01:00
ret = cdns_torrent_dp_set_power_state ( cdns_phy , num_lanes ,
2020-02-06 07:10:55 +01:00
POWERSTATE_A2 ) ;
if ( ret )
return ret ;
2018-08-09 11:30:30 +01:00
2020-02-06 07:10:57 +01:00
ret = cdns_torrent_dp_set_power_state ( cdns_phy , num_lanes ,
2020-02-06 07:10:55 +01:00
POWERSTATE_A0 ) ;
2018-08-09 11:30:30 +01:00
2020-02-06 07:10:55 +01:00
return ret ;
2018-08-09 11:30:30 +01:00
}
2020-02-06 07:10:52 +01:00
static void cdns_dp_phy_write_field ( struct cdns_torrent_phy * cdns_phy ,
2018-08-09 11:30:30 +01:00
unsigned int offset ,
unsigned char start_bit ,
unsigned char num_bits ,
unsigned int val )
{
unsigned int read_val ;
2020-02-06 07:10:54 +01:00
read_val = cdns_torrent_dp_read ( cdns_phy , offset ) ;
cdns_torrent_dp_write ( cdns_phy , offset ,
( ( val < < start_bit ) |
( read_val & ~ ( ( ( 1 < < num_bits ) - 1 ) < <
start_bit ) ) ) ) ;
2018-08-09 11:30:30 +01:00
}
2020-02-06 07:10:52 +01:00
static int cdns_torrent_phy_probe ( struct platform_device * pdev )
2018-08-09 11:30:30 +01:00
{
struct resource * regs ;
2020-02-06 07:10:52 +01:00
struct cdns_torrent_phy * cdns_phy ;
2018-08-09 11:30:30 +01:00
struct device * dev = & pdev - > dev ;
struct phy_provider * phy_provider ;
struct phy * phy ;
int err ;
cdns_phy = devm_kzalloc ( dev , sizeof ( * cdns_phy ) , GFP_KERNEL ) ;
if ( ! cdns_phy )
return - ENOMEM ;
cdns_phy - > dev = & pdev - > dev ;
2020-02-06 07:10:52 +01:00
phy = devm_phy_create ( dev , NULL , & cdns_torrent_phy_ops ) ;
2018-08-09 11:30:30 +01:00
if ( IS_ERR ( phy ) ) {
2020-02-06 07:10:52 +01:00
dev_err ( dev , " failed to create Torrent PHY \n " ) ;
2018-08-09 11:30:30 +01:00
return PTR_ERR ( phy ) ;
}
regs = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
cdns_phy - > base = devm_ioremap_resource ( & pdev - > dev , regs ) ;
if ( IS_ERR ( cdns_phy - > base ) )
return PTR_ERR ( cdns_phy - > base ) ;
regs = platform_get_resource ( pdev , IORESOURCE_MEM , 1 ) ;
cdns_phy - > sd_base = devm_ioremap_resource ( & pdev - > dev , regs ) ;
if ( IS_ERR ( cdns_phy - > sd_base ) )
return PTR_ERR ( cdns_phy - > sd_base ) ;
err = device_property_read_u32 ( dev , " num_lanes " ,
2020-02-06 07:10:52 +01:00
& cdns_phy - > num_lanes ) ;
2018-08-09 11:30:30 +01:00
if ( err )
cdns_phy - > num_lanes = DEFAULT_NUM_LANES ;
switch ( cdns_phy - > num_lanes ) {
case 1 :
case 2 :
case 4 :
/* valid number of lanes */
break ;
default :
dev_err ( dev , " unsupported number of lanes: %d \n " ,
cdns_phy - > num_lanes ) ;
return - EINVAL ;
}
err = device_property_read_u32 ( dev , " max_bit_rate " ,
2020-02-06 07:10:52 +01:00
& cdns_phy - > max_bit_rate ) ;
2018-08-09 11:30:30 +01:00
if ( err )
cdns_phy - > max_bit_rate = DEFAULT_MAX_BIT_RATE ;
switch ( cdns_phy - > max_bit_rate ) {
2020-02-06 07:10:56 +01:00
case 1620 :
2018-08-09 11:30:30 +01:00
case 2160 :
case 2430 :
case 2700 :
case 3240 :
case 4320 :
case 5400 :
case 8100 :
/* valid bit rate */
break ;
default :
dev_err ( dev , " unsupported max bit rate: %dMbps \n " ,
cdns_phy - > max_bit_rate ) ;
return - EINVAL ;
}
2020-02-06 07:10:56 +01:00
cdns_phy - > clk = devm_clk_get ( dev , " refclk " ) ;
if ( IS_ERR ( cdns_phy - > clk ) ) {
dev_err ( dev , " phy ref clock not found \n " ) ;
return PTR_ERR ( cdns_phy - > clk ) ;
}
2018-08-09 11:30:30 +01:00
phy_set_drvdata ( phy , cdns_phy ) ;
phy_provider = devm_of_phy_provider_register ( dev , of_phy_simple_xlate ) ;
dev_info ( dev , " %d lanes, max bit rate %d.%03d Gbps \n " ,
cdns_phy - > num_lanes ,
cdns_phy - > max_bit_rate / 1000 ,
cdns_phy - > max_bit_rate % 1000 ) ;
return PTR_ERR_OR_ZERO ( phy_provider ) ;
}
2020-02-06 07:10:52 +01:00
static const struct of_device_id cdns_torrent_phy_of_match [ ] = {
2018-08-09 11:30:30 +01:00
{
2020-02-06 07:10:51 +01:00
. compatible = " cdns,torrent-phy "
2018-08-09 11:30:30 +01:00
} ,
{ }
} ;
2020-02-06 07:10:52 +01:00
MODULE_DEVICE_TABLE ( of , cdns_torrent_phy_of_match ) ;
2018-08-09 11:30:30 +01:00
2020-02-06 07:10:52 +01:00
static struct platform_driver cdns_torrent_phy_driver = {
. probe = cdns_torrent_phy_probe ,
2018-08-09 11:30:30 +01:00
. driver = {
2020-02-06 07:10:52 +01:00
. name = " cdns-torrent-phy " ,
. of_match_table = cdns_torrent_phy_of_match ,
2018-08-09 11:30:30 +01:00
}
} ;
2020-02-06 07:10:52 +01:00
module_platform_driver ( cdns_torrent_phy_driver ) ;
2018-08-09 11:30:30 +01:00
MODULE_AUTHOR ( " Cadence Design Systems, Inc. " ) ;
2020-02-06 07:10:52 +01:00
MODULE_DESCRIPTION ( " Cadence Torrent PHY driver " ) ;
2018-08-09 11:30:30 +01:00
MODULE_LICENSE ( " GPL v2 " ) ;