2019-05-23 11:14:55 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2015-05-20 17:18:40 -07:00
/*
* Broadcom SATA3 AHCI Controller PHY Driver
*
2016-03-28 10:18:26 +05:30
* Copyright ( C ) 2016 Broadcom
2015-05-20 17:18:40 -07:00
*/
2016-03-28 10:18:27 +05:30
# include <linux/delay.h>
2015-05-20 17:18:40 -07:00
# include <linux/device.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/phy/phy.h>
# include <linux/platform_device.h>
2016-03-28 10:18:27 +05:30
# define SATA_PCB_BANK_OFFSET 0x23c
# define SATA_PCB_REG_OFFSET(ofs) ((ofs) * 4)
2015-05-20 17:18:40 -07:00
# define MAX_PORTS 2
/* Register offset between PHYs in PCB space */
2016-03-28 10:18:27 +05:30
# define SATA_PCB_REG_28NM_SPACE_SIZE 0x1000
2015-11-26 11:56:34 +09:00
2015-11-26 11:56:35 +09:00
/* The older SATA PHY registers duplicated per port registers within the map,
* rather than having a separate map per port .
*/
2016-03-28 10:18:27 +05:30
# define SATA_PCB_REG_40NM_SPACE_SIZE 0x10
/* Register offset between PHYs in PHY control space */
# define SATA_PHY_CTRL_REG_28NM_SPACE_SIZE 0x8
2015-11-26 11:56:35 +09:00
2015-11-26 11:56:34 +09:00
enum brcm_sata_phy_version {
2019-12-10 12:08:52 -08:00
BRCM_SATA_PHY_STB_16NM ,
2016-03-28 10:18:27 +05:30
BRCM_SATA_PHY_STB_28NM ,
BRCM_SATA_PHY_STB_40NM ,
BRCM_SATA_PHY_IPROC_NS2 ,
2016-06-16 09:53:34 -04:00
BRCM_SATA_PHY_IPROC_NSP ,
2017-06-08 17:01:39 +05:30
BRCM_SATA_PHY_IPROC_SR ,
2018-09-20 12:16:38 -07:00
BRCM_SATA_PHY_DSL_28NM ,
2015-11-26 11:56:34 +09:00
} ;
2015-05-20 17:18:40 -07:00
2017-10-11 17:53:12 -07:00
enum brcm_sata_phy_rxaeq_mode {
RXAEQ_MODE_OFF = 0 ,
RXAEQ_MODE_AUTO ,
RXAEQ_MODE_MANUAL ,
} ;
static enum brcm_sata_phy_rxaeq_mode rxaeq_to_val ( const char * m )
{
if ( ! strcmp ( m , " auto " ) )
return RXAEQ_MODE_AUTO ;
else if ( ! strcmp ( m , " manual " ) )
return RXAEQ_MODE_MANUAL ;
else
return RXAEQ_MODE_OFF ;
}
2015-05-20 17:18:40 -07:00
struct brcm_sata_port {
int portnum ;
struct phy * phy ;
struct brcm_sata_phy * phy_priv ;
bool ssc_en ;
2017-10-11 17:53:12 -07:00
enum brcm_sata_phy_rxaeq_mode rxaeq_mode ;
u32 rxaeq_val ;
2020-10-22 13:50:56 -07:00
u32 tx_amplitude_val ;
2015-05-20 17:18:40 -07:00
} ;
struct brcm_sata_phy {
struct device * dev ;
void __iomem * phy_base ;
2016-03-28 10:18:27 +05:30
void __iomem * ctrl_base ;
2015-11-26 11:56:34 +09:00
enum brcm_sata_phy_version version ;
2015-05-20 17:18:40 -07:00
struct brcm_sata_port phys [ MAX_PORTS ] ;
} ;
2016-03-28 10:18:27 +05:30
enum sata_phy_regs {
BLOCK0_REG_BANK = 0x000 ,
BLOCK0_XGXSSTATUS = 0x81 ,
BLOCK0_XGXSSTATUS_PLL_LOCK = BIT ( 12 ) ,
BLOCK0_SPARE = 0x8d ,
BLOCK0_SPARE_OOB_CLK_SEL_MASK = 0x3 ,
BLOCK0_SPARE_OOB_CLK_SEL_REFBY2 = 0x1 ,
2020-10-22 13:50:56 -07:00
BLOCK1_REG_BANK = 0x10 ,
BLOCK1_TEST_TX = 0x83 ,
BLOCK1_TEST_TX_AMP_SHIFT = 12 ,
2016-03-28 10:18:27 +05:30
PLL_REG_BANK_0 = 0x050 ,
2015-05-20 17:18:40 -07:00
PLL_REG_BANK_0_PLLCONTROL_0 = 0x81 ,
2016-06-16 09:53:34 -04:00
PLLCONTROL_0_FREQ_DET_RESTART = BIT ( 13 ) ,
PLLCONTROL_0_FREQ_MONITOR = BIT ( 12 ) ,
PLLCONTROL_0_SEQ_START = BIT ( 15 ) ,
2018-09-20 12:16:38 -07:00
PLL_CAP_CHARGE_TIME = 0x83 ,
PLL_VCO_CAL_THRESH = 0x84 ,
2016-06-16 09:53:34 -04:00
PLL_CAP_CONTROL = 0x85 ,
2018-09-20 12:16:38 -07:00
PLL_FREQ_DET_TIME = 0x86 ,
2016-06-16 09:53:34 -04:00
PLL_ACTRL2 = 0x8b ,
PLL_ACTRL2_SELDIV_MASK = 0x1f ,
PLL_ACTRL2_SELDIV_SHIFT = 9 ,
2017-06-08 17:01:39 +05:30
PLL_ACTRL6 = 0x86 ,
2015-05-20 17:18:40 -07:00
2016-03-28 10:18:27 +05:30
PLL1_REG_BANK = 0x060 ,
PLL1_ACTRL2 = 0x82 ,
PLL1_ACTRL3 = 0x83 ,
PLL1_ACTRL4 = 0x84 ,
2018-09-20 12:16:38 -07:00
PLL1_ACTRL5 = 0x85 ,
PLL1_ACTRL6 = 0x86 ,
PLL1_ACTRL7 = 0x87 ,
2019-12-10 12:08:52 -08:00
PLL1_ACTRL8 = 0x88 ,
2016-03-28 10:18:27 +05:30
2017-06-08 17:01:39 +05:30
TX_REG_BANK = 0x070 ,
TX_ACTRL0 = 0x80 ,
TX_ACTRL0_TXPOL_FLIP = BIT ( 6 ) ,
2019-12-10 12:08:52 -08:00
TX_ACTRL5 = 0x85 ,
TX_ACTRL5_SSC_EN = BIT ( 11 ) ,
2017-06-08 17:01:39 +05:30
2017-10-11 17:53:12 -07:00
AEQRX_REG_BANK_0 = 0xd0 ,
AEQ_CONTROL1 = 0x81 ,
AEQ_CONTROL1_ENABLE = BIT ( 2 ) ,
AEQ_CONTROL1_FREEZE = BIT ( 3 ) ,
AEQ_FRC_EQ = 0x83 ,
AEQ_FRC_EQ_FORCE = BIT ( 0 ) ,
AEQ_FRC_EQ_FORCE_VAL = BIT ( 1 ) ,
2019-12-10 12:08:52 -08:00
AEQ_RFZ_FRC_VAL = BIT ( 8 ) ,
2017-10-11 17:53:12 -07:00
AEQRX_REG_BANK_1 = 0xe0 ,
2018-09-20 12:16:38 -07:00
AEQRX_SLCAL0_CTRL0 = 0x82 ,
AEQRX_SLCAL1_CTRL0 = 0x86 ,
2017-10-11 17:53:12 -07:00
2016-03-28 10:18:27 +05:30
OOB_REG_BANK = 0x150 ,
2016-06-16 09:53:34 -04:00
OOB1_REG_BANK = 0x160 ,
2016-03-28 10:18:27 +05:30
OOB_CTRL1 = 0x80 ,
OOB_CTRL1_BURST_MAX_MASK = 0xf ,
OOB_CTRL1_BURST_MAX_SHIFT = 12 ,
OOB_CTRL1_BURST_MIN_MASK = 0xf ,
OOB_CTRL1_BURST_MIN_SHIFT = 8 ,
OOB_CTRL1_WAKE_IDLE_MAX_MASK = 0xf ,
OOB_CTRL1_WAKE_IDLE_MAX_SHIFT = 4 ,
OOB_CTRL1_WAKE_IDLE_MIN_MASK = 0xf ,
OOB_CTRL1_WAKE_IDLE_MIN_SHIFT = 0 ,
OOB_CTRL2 = 0x81 ,
OOB_CTRL2_SEL_ENA_SHIFT = 15 ,
OOB_CTRL2_SEL_ENA_RC_SHIFT = 14 ,
OOB_CTRL2_RESET_IDLE_MAX_MASK = 0x3f ,
OOB_CTRL2_RESET_IDLE_MAX_SHIFT = 8 ,
OOB_CTRL2_BURST_CNT_MASK = 0x3 ,
OOB_CTRL2_BURST_CNT_SHIFT = 6 ,
OOB_CTRL2_RESET_IDLE_MIN_MASK = 0x3f ,
OOB_CTRL2_RESET_IDLE_MIN_SHIFT = 0 ,
2015-05-20 17:18:40 -07:00
TXPMD_REG_BANK = 0x1a0 ,
TXPMD_CONTROL1 = 0x81 ,
TXPMD_CONTROL1_TX_SSC_EN_FRC = BIT ( 0 ) ,
TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL = BIT ( 1 ) ,
TXPMD_TX_FREQ_CTRL_CONTROL1 = 0x82 ,
TXPMD_TX_FREQ_CTRL_CONTROL2 = 0x83 ,
TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK = 0x3ff ,
TXPMD_TX_FREQ_CTRL_CONTROL3 = 0x84 ,
TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff ,
2018-01-11 17:31:07 -08:00
RXPMD_REG_BANK = 0x1c0 ,
2019-12-10 12:08:52 -08:00
RXPMD_RX_CDR_CONTROL1 = 0x81 ,
RXPMD_RX_PPM_VAL_MASK = 0x1ff ,
RXPMD_RXPMD_EN_FRC = BIT ( 12 ) ,
RXPMD_RXPMD_EN_FRC_VAL = BIT ( 13 ) ,
RXPMD_RX_CDR_CDR_PROP_BW = 0x82 ,
RXPMD_G_CDR_PROP_BW_MASK = 0x7 ,
RXPMD_G1_CDR_PROP_BW_SHIFT = 0 ,
RXPMD_G2_CDR_PROP_BW_SHIFT = 3 ,
RXPMD_G3_CDR_PROB_BW_SHIFT = 6 ,
RXPMD_RX_CDR_CDR_ACQ_INTEG_BW = 0x83 ,
RXPMD_G_CDR_ACQ_INT_BW_MASK = 0x7 ,
RXPMD_G1_CDR_ACQ_INT_BW_SHIFT = 0 ,
RXPMD_G2_CDR_ACQ_INT_BW_SHIFT = 3 ,
RXPMD_G3_CDR_ACQ_INT_BW_SHIFT = 6 ,
RXPMD_RX_CDR_CDR_LOCK_INTEG_BW = 0x84 ,
RXPMD_G_CDR_LOCK_INT_BW_MASK = 0x7 ,
RXPMD_G1_CDR_LOCK_INT_BW_SHIFT = 0 ,
RXPMD_G2_CDR_LOCK_INT_BW_SHIFT = 3 ,
RXPMD_G3_CDR_LOCK_INT_BW_SHIFT = 6 ,
2018-01-11 17:31:07 -08:00
RXPMD_RX_FREQ_MON_CONTROL1 = 0x87 ,
2019-12-10 12:08:52 -08:00
RXPMD_MON_CORRECT_EN = BIT ( 8 ) ,
RXPMD_MON_MARGIN_VAL_MASK = 0xff ,
2015-05-20 17:18:40 -07:00
} ;
2016-03-28 10:18:27 +05:30
enum sata_phy_ctrl_regs {
PHY_CTRL_1 = 0x0 ,
PHY_CTRL_1_RESET = BIT ( 0 ) ,
} ;
static inline void __iomem * brcm_sata_ctrl_base ( struct brcm_sata_port * port )
{
struct brcm_sata_phy * priv = port - > phy_priv ;
u32 size = 0 ;
switch ( priv - > version ) {
case BRCM_SATA_PHY_IPROC_NS2 :
size = SATA_PHY_CTRL_REG_28NM_SPACE_SIZE ;
break ;
default :
2015-11-26 11:56:35 +09:00
dev_err ( priv - > dev , " invalid phy version \n " ) ;
2016-03-28 10:18:27 +05:30
break ;
2016-10-20 12:23:38 +05:30
}
2015-11-26 11:56:34 +09:00
2016-03-28 10:18:27 +05:30
return priv - > ctrl_base + ( port - > portnum * size ) ;
2015-05-20 17:18:40 -07:00
}
2020-02-20 20:14:23 -08:00
static void brcm_sata_phy_wr ( struct brcm_sata_port * port , u32 bank ,
2016-03-28 10:18:27 +05:30
u32 ofs , u32 msk , u32 value )
2015-05-20 17:18:40 -07:00
{
2020-02-20 20:14:23 -08:00
struct brcm_sata_phy * priv = port - > phy_priv ;
void __iomem * pcb_base = priv - > phy_base ;
2015-05-20 17:18:40 -07:00
u32 tmp ;
2020-02-20 20:14:23 -08:00
if ( priv - > version = = BRCM_SATA_PHY_STB_40NM )
bank + = ( port - > portnum * SATA_PCB_REG_40NM_SPACE_SIZE ) ;
else
pcb_base + = ( port - > portnum * SATA_PCB_REG_28NM_SPACE_SIZE ) ;
2016-03-28 10:18:27 +05:30
writel ( bank , pcb_base + SATA_PCB_BANK_OFFSET ) ;
tmp = readl ( pcb_base + SATA_PCB_REG_OFFSET ( ofs ) ) ;
2015-05-20 17:18:40 -07:00
tmp = ( tmp & msk ) | value ;
2016-03-28 10:18:27 +05:30
writel ( tmp , pcb_base + SATA_PCB_REG_OFFSET ( ofs ) ) ;
}
2020-02-20 20:14:23 -08:00
static u32 brcm_sata_phy_rd ( struct brcm_sata_port * port , u32 bank , u32 ofs )
2016-03-28 10:18:27 +05:30
{
2020-02-20 20:14:23 -08:00
struct brcm_sata_phy * priv = port - > phy_priv ;
void __iomem * pcb_base = priv - > phy_base ;
if ( priv - > version = = BRCM_SATA_PHY_STB_40NM )
bank + = ( port - > portnum * SATA_PCB_REG_40NM_SPACE_SIZE ) ;
else
pcb_base + = ( port - > portnum * SATA_PCB_REG_28NM_SPACE_SIZE ) ;
2016-03-28 10:18:27 +05:30
writel ( bank , pcb_base + SATA_PCB_BANK_OFFSET ) ;
return readl ( pcb_base + SATA_PCB_REG_OFFSET ( ofs ) ) ;
2015-05-20 17:18:40 -07:00
}
/* These defaults were characterized by H/W group */
2016-03-28 10:18:27 +05:30
# define STB_FMIN_VAL_DEFAULT 0x3df
# define STB_FMAX_VAL_DEFAULT 0x3df
# define STB_FMAX_VAL_SSC 0x83
2015-05-20 17:18:40 -07:00
2017-10-11 17:53:11 -07:00
static void brcm_stb_sata_ssc_init ( struct brcm_sata_port * port )
2015-05-20 17:18:40 -07:00
{
struct brcm_sata_phy * priv = port - > phy_priv ;
u32 tmp ;
/* override the TX spread spectrum setting */
tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , TXPMD_REG_BANK , TXPMD_CONTROL1 , ~ tmp , tmp ) ;
2015-05-20 17:18:40 -07:00
/* set fixed min freq */
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , TXPMD_REG_BANK , TXPMD_TX_FREQ_CTRL_CONTROL2 ,
2016-03-28 10:18:27 +05:30
~ TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK ,
STB_FMIN_VAL_DEFAULT ) ;
2015-05-20 17:18:40 -07:00
/* set fixed max freq depending on SSC config */
if ( port - > ssc_en ) {
2016-03-28 10:18:27 +05:30
dev_info ( priv - > dev , " enabling SSC on port%d \n " , port - > portnum ) ;
tmp = STB_FMAX_VAL_SSC ;
2015-05-20 17:18:40 -07:00
} else {
2016-03-28 10:18:27 +05:30
tmp = STB_FMAX_VAL_DEFAULT ;
2015-05-20 17:18:40 -07:00
}
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , TXPMD_REG_BANK , TXPMD_TX_FREQ_CTRL_CONTROL3 ,
2015-05-20 17:18:40 -07:00
~ TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK , tmp ) ;
2017-10-11 17:53:11 -07:00
}
2017-10-11 17:53:12 -07:00
# define AEQ_FRC_EQ_VAL_SHIFT 2
# define AEQ_FRC_EQ_VAL_MASK 0x3f
static int brcm_stb_sata_rxaeq_init ( struct brcm_sata_port * port )
{
u32 tmp = 0 , reg = 0 ;
switch ( port - > rxaeq_mode ) {
case RXAEQ_MODE_OFF :
return 0 ;
case RXAEQ_MODE_AUTO :
reg = AEQ_CONTROL1 ;
tmp = AEQ_CONTROL1_ENABLE | AEQ_CONTROL1_FREEZE ;
break ;
case RXAEQ_MODE_MANUAL :
reg = AEQ_FRC_EQ ;
tmp = AEQ_FRC_EQ_FORCE | AEQ_FRC_EQ_FORCE_VAL ;
if ( port - > rxaeq_val > AEQ_FRC_EQ_VAL_MASK )
return - EINVAL ;
tmp | = port - > rxaeq_val < < AEQ_FRC_EQ_VAL_SHIFT ;
break ;
}
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , AEQRX_REG_BANK_0 , reg , ~ tmp , tmp ) ;
brcm_sata_phy_wr ( port , AEQRX_REG_BANK_1 , reg , ~ tmp , tmp ) ;
2017-10-11 17:53:12 -07:00
return 0 ;
}
2017-10-11 17:53:11 -07:00
static int brcm_stb_sata_init ( struct brcm_sata_port * port )
{
brcm_stb_sata_ssc_init ( port ) ;
2016-03-28 10:18:27 +05:30
2017-10-11 17:53:12 -07:00
return brcm_stb_sata_rxaeq_init ( port ) ;
2016-03-28 10:18:27 +05:30
}
2019-12-10 12:08:52 -08:00
static int brcm_stb_sata_16nm_ssc_init ( struct brcm_sata_port * port )
{
u32 tmp , value ;
/* Reduce CP tail current to 1/16th of its default value */
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL1_REG_BANK , PLL1_ACTRL6 , 0 , 0x141 ) ;
2019-12-10 12:08:52 -08:00
/* Turn off CP tail current boost */
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL1_REG_BANK , PLL1_ACTRL8 , 0 , 0xc006 ) ;
2019-12-10 12:08:52 -08:00
/* Set a specific AEQ equalizer value */
tmp = AEQ_FRC_EQ_FORCE_VAL | AEQ_FRC_EQ_FORCE ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , AEQRX_REG_BANK_0 , AEQ_FRC_EQ ,
2019-12-10 12:08:52 -08:00
~ ( tmp | AEQ_RFZ_FRC_VAL |
AEQ_FRC_EQ_VAL_MASK < < AEQ_FRC_EQ_VAL_SHIFT ) ,
tmp | 32 < < AEQ_FRC_EQ_VAL_SHIFT ) ;
/* Set RX PPM val center frequency */
if ( port - > ssc_en )
value = 0x52 ;
else
value = 0 ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , RXPMD_REG_BANK , RXPMD_RX_CDR_CONTROL1 ,
2019-12-10 12:08:52 -08:00
~ RXPMD_RX_PPM_VAL_MASK , value ) ;
/* Set proportional loop bandwith Gen1/2/3 */
tmp = RXPMD_G_CDR_PROP_BW_MASK < < RXPMD_G1_CDR_PROP_BW_SHIFT |
RXPMD_G_CDR_PROP_BW_MASK < < RXPMD_G2_CDR_PROP_BW_SHIFT |
RXPMD_G_CDR_PROP_BW_MASK < < RXPMD_G3_CDR_PROB_BW_SHIFT ;
if ( port - > ssc_en )
value = 2 < < RXPMD_G1_CDR_PROP_BW_SHIFT |
2 < < RXPMD_G2_CDR_PROP_BW_SHIFT |
2 < < RXPMD_G3_CDR_PROB_BW_SHIFT ;
else
value = 1 < < RXPMD_G1_CDR_PROP_BW_SHIFT |
1 < < RXPMD_G2_CDR_PROP_BW_SHIFT |
1 < < RXPMD_G3_CDR_PROB_BW_SHIFT ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , RXPMD_REG_BANK , RXPMD_RX_CDR_CDR_PROP_BW , ~ tmp ,
2019-12-10 12:08:52 -08:00
value ) ;
/* Set CDR integral loop acquisition bandwidth for Gen1/2/3 */
tmp = RXPMD_G_CDR_ACQ_INT_BW_MASK < < RXPMD_G1_CDR_ACQ_INT_BW_SHIFT |
RXPMD_G_CDR_ACQ_INT_BW_MASK < < RXPMD_G2_CDR_ACQ_INT_BW_SHIFT |
RXPMD_G_CDR_ACQ_INT_BW_MASK < < RXPMD_G3_CDR_ACQ_INT_BW_SHIFT ;
if ( port - > ssc_en )
value = 1 < < RXPMD_G1_CDR_ACQ_INT_BW_SHIFT |
1 < < RXPMD_G2_CDR_ACQ_INT_BW_SHIFT |
1 < < RXPMD_G3_CDR_ACQ_INT_BW_SHIFT ;
else
value = 0 ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , RXPMD_REG_BANK , RXPMD_RX_CDR_CDR_ACQ_INTEG_BW ,
2019-12-10 12:08:52 -08:00
~ tmp , value ) ;
/* Set CDR integral loop locking bandwidth to 1 for Gen 1/2/3 */
tmp = RXPMD_G_CDR_LOCK_INT_BW_MASK < < RXPMD_G1_CDR_LOCK_INT_BW_SHIFT |
RXPMD_G_CDR_LOCK_INT_BW_MASK < < RXPMD_G2_CDR_LOCK_INT_BW_SHIFT |
RXPMD_G_CDR_LOCK_INT_BW_MASK < < RXPMD_G3_CDR_LOCK_INT_BW_SHIFT ;
if ( port - > ssc_en )
value = 1 < < RXPMD_G1_CDR_LOCK_INT_BW_SHIFT |
1 < < RXPMD_G2_CDR_LOCK_INT_BW_SHIFT |
1 < < RXPMD_G3_CDR_LOCK_INT_BW_SHIFT ;
else
value = 0 ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , RXPMD_REG_BANK , RXPMD_RX_CDR_CDR_LOCK_INTEG_BW ,
2019-12-10 12:08:52 -08:00
~ tmp , value ) ;
/* Set no guard band and clamp CDR */
tmp = RXPMD_MON_CORRECT_EN | RXPMD_MON_MARGIN_VAL_MASK ;
if ( port - > ssc_en )
value = 0x51 ;
else
value = 0 ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , RXPMD_REG_BANK , RXPMD_RX_FREQ_MON_CONTROL1 ,
2019-12-10 12:08:52 -08:00
~ tmp , RXPMD_MON_CORRECT_EN | value ) ;
2020-10-22 13:50:56 -07:00
tmp = GENMASK ( 15 , 12 ) ;
switch ( port - > tx_amplitude_val ) {
case 400 :
value = BIT ( 12 ) | BIT ( 13 ) ;
break ;
case 500 :
value = BIT ( 13 ) ;
break ;
case 600 :
value = BIT ( 12 ) ;
break ;
case 800 :
value = 0 ;
break ;
default :
value = tmp ;
break ;
}
if ( value ! = tmp )
brcm_sata_phy_wr ( port , BLOCK1_REG_BANK , BLOCK1_TEST_TX , ~ tmp ,
value ) ;
2019-12-10 12:08:52 -08:00
/* Turn on/off SSC */
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , TX_REG_BANK , TX_ACTRL5 , ~ TX_ACTRL5_SSC_EN ,
2019-12-10 12:08:52 -08:00
port - > ssc_en ? TX_ACTRL5_SSC_EN : 0 ) ;
return 0 ;
}
static int brcm_stb_sata_16nm_init ( struct brcm_sata_port * port )
{
return brcm_stb_sata_16nm_ssc_init ( port ) ;
}
2016-03-28 10:18:27 +05:30
/* NS2 SATA PLL1 defaults were characterized by H/W group */
# define NS2_PLL1_ACTRL2_MAGIC 0x1df8
# define NS2_PLL1_ACTRL3_MAGIC 0x2b00
# define NS2_PLL1_ACTRL4_MAGIC 0x8824
static int brcm_ns2_sata_init ( struct brcm_sata_port * port )
{
int try ;
unsigned int val ;
void __iomem * ctrl_base = brcm_sata_ctrl_base ( port ) ;
struct device * dev = port - > phy_priv - > dev ;
/* Configure OOB control */
val = 0x0 ;
val | = ( 0xc < < OOB_CTRL1_BURST_MAX_SHIFT ) ;
val | = ( 0x4 < < OOB_CTRL1_BURST_MIN_SHIFT ) ;
val | = ( 0x9 < < OOB_CTRL1_WAKE_IDLE_MAX_SHIFT ) ;
val | = ( 0x3 < < OOB_CTRL1_WAKE_IDLE_MIN_SHIFT ) ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , OOB_REG_BANK , OOB_CTRL1 , 0x0 , val ) ;
2016-03-28 10:18:27 +05:30
val = 0x0 ;
val | = ( 0x1b < < OOB_CTRL2_RESET_IDLE_MAX_SHIFT ) ;
val | = ( 0x2 < < OOB_CTRL2_BURST_CNT_SHIFT ) ;
val | = ( 0x9 < < OOB_CTRL2_RESET_IDLE_MIN_SHIFT ) ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , OOB_REG_BANK , OOB_CTRL2 , 0x0 , val ) ;
2016-03-28 10:18:27 +05:30
/* Configure PHY PLL register bank 1 */
val = NS2_PLL1_ACTRL2_MAGIC ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL1_REG_BANK , PLL1_ACTRL2 , 0x0 , val ) ;
2016-03-28 10:18:27 +05:30
val = NS2_PLL1_ACTRL3_MAGIC ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL1_REG_BANK , PLL1_ACTRL3 , 0x0 , val ) ;
2016-03-28 10:18:27 +05:30
val = NS2_PLL1_ACTRL4_MAGIC ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL1_REG_BANK , PLL1_ACTRL4 , 0x0 , val ) ;
2016-03-28 10:18:27 +05:30
/* Configure PHY BLOCK0 register bank */
/* Set oob_clk_sel to refclk/2 */
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , BLOCK0_REG_BANK , BLOCK0_SPARE ,
2016-03-28 10:18:27 +05:30
~ BLOCK0_SPARE_OOB_CLK_SEL_MASK ,
BLOCK0_SPARE_OOB_CLK_SEL_REFBY2 ) ;
/* Strobe PHY reset using PHY control register */
writel ( PHY_CTRL_1_RESET , ctrl_base + PHY_CTRL_1 ) ;
mdelay ( 1 ) ;
writel ( 0x0 , ctrl_base + PHY_CTRL_1 ) ;
mdelay ( 1 ) ;
/* Wait for PHY PLL lock by polling pll_lock bit */
try = 50 ;
while ( try ) {
2020-02-20 20:14:23 -08:00
val = brcm_sata_phy_rd ( port , BLOCK0_REG_BANK ,
2016-03-28 10:18:27 +05:30
BLOCK0_XGXSSTATUS ) ;
if ( val & BLOCK0_XGXSSTATUS_PLL_LOCK )
break ;
msleep ( 20 ) ;
try - - ;
}
if ( ! try ) {
/* PLL did not lock; give up */
dev_err ( dev , " port%d PLL did not lock \n " , port - > portnum ) ;
return - ETIMEDOUT ;
}
dev_dbg ( dev , " port%d initialized \n " , port - > portnum ) ;
return 0 ;
2015-05-20 17:18:40 -07:00
}
2016-06-16 09:53:34 -04:00
static int brcm_nsp_sata_init ( struct brcm_sata_port * port )
{
struct device * dev = port - > phy_priv - > dev ;
unsigned int oob_bank ;
unsigned int val , try ;
/* Configure OOB control */
if ( port - > portnum = = 0 )
oob_bank = OOB_REG_BANK ;
else if ( port - > portnum = = 1 )
oob_bank = OOB1_REG_BANK ;
else
return - EINVAL ;
val = 0x0 ;
val | = ( 0x0f < < OOB_CTRL1_BURST_MAX_SHIFT ) ;
val | = ( 0x06 < < OOB_CTRL1_BURST_MIN_SHIFT ) ;
val | = ( 0x0f < < OOB_CTRL1_WAKE_IDLE_MAX_SHIFT ) ;
val | = ( 0x06 < < OOB_CTRL1_WAKE_IDLE_MIN_SHIFT ) ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , oob_bank , OOB_CTRL1 , 0x0 , val ) ;
2016-06-16 09:53:34 -04:00
val = 0x0 ;
val | = ( 0x2e < < OOB_CTRL2_RESET_IDLE_MAX_SHIFT ) ;
val | = ( 0x02 < < OOB_CTRL2_BURST_CNT_SHIFT ) ;
val | = ( 0x16 < < OOB_CTRL2_RESET_IDLE_MIN_SHIFT ) ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , oob_bank , OOB_CTRL2 , 0x0 , val ) ;
2016-06-16 09:53:34 -04:00
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL_REG_BANK_0 , PLL_ACTRL2 ,
2016-06-16 09:53:34 -04:00
~ ( PLL_ACTRL2_SELDIV_MASK < < PLL_ACTRL2_SELDIV_SHIFT ) ,
0x0c < < PLL_ACTRL2_SELDIV_SHIFT ) ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL_REG_BANK_0 , PLL_CAP_CONTROL ,
2016-06-16 09:53:34 -04:00
0xff0 , 0x4f0 ) ;
val = PLLCONTROL_0_FREQ_DET_RESTART | PLLCONTROL_0_FREQ_MONITOR ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL_REG_BANK_0 , PLL_REG_BANK_0_PLLCONTROL_0 ,
2016-06-16 09:53:34 -04:00
~ val , val ) ;
val = PLLCONTROL_0_SEQ_START ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL_REG_BANK_0 , PLL_REG_BANK_0_PLLCONTROL_0 ,
2016-06-16 09:53:34 -04:00
~ val , 0 ) ;
mdelay ( 10 ) ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL_REG_BANK_0 , PLL_REG_BANK_0_PLLCONTROL_0 ,
2016-06-16 09:53:34 -04:00
~ val , val ) ;
/* Wait for pll_seq_done bit */
try = 50 ;
2017-06-19 13:56:05 +03:00
while ( - - try ) {
2020-02-20 20:14:23 -08:00
val = brcm_sata_phy_rd ( port , BLOCK0_REG_BANK ,
2016-06-16 09:53:34 -04:00
BLOCK0_XGXSSTATUS ) ;
if ( val & BLOCK0_XGXSSTATUS_PLL_LOCK )
break ;
msleep ( 20 ) ;
}
if ( ! try ) {
/* PLL did not lock; give up */
dev_err ( dev , " port%d PLL did not lock \n " , port - > portnum ) ;
return - ETIMEDOUT ;
}
dev_dbg ( dev , " port%d initialized \n " , port - > portnum ) ;
return 0 ;
}
2017-06-08 17:01:39 +05:30
/* SR PHY PLL0 registers */
# define SR_PLL0_ACTRL6_MAGIC 0xa
/* SR PHY PLL1 registers */
# define SR_PLL1_ACTRL2_MAGIC 0x32
# define SR_PLL1_ACTRL3_MAGIC 0x2
# define SR_PLL1_ACTRL4_MAGIC 0x3e8
static int brcm_sr_sata_init ( struct brcm_sata_port * port )
{
struct device * dev = port - > phy_priv - > dev ;
unsigned int val , try ;
/* Configure PHY PLL register bank 1 */
val = SR_PLL1_ACTRL2_MAGIC ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL1_REG_BANK , PLL1_ACTRL2 , 0x0 , val ) ;
2017-06-08 17:01:39 +05:30
val = SR_PLL1_ACTRL3_MAGIC ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL1_REG_BANK , PLL1_ACTRL3 , 0x0 , val ) ;
2017-06-08 17:01:39 +05:30
val = SR_PLL1_ACTRL4_MAGIC ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL1_REG_BANK , PLL1_ACTRL4 , 0x0 , val ) ;
2017-06-08 17:01:39 +05:30
/* Configure PHY PLL register bank 0 */
val = SR_PLL0_ACTRL6_MAGIC ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL_REG_BANK_0 , PLL_ACTRL6 , 0x0 , val ) ;
2017-06-08 17:01:39 +05:30
/* Wait for PHY PLL lock by polling pll_lock bit */
try = 50 ;
do {
2020-02-20 20:14:23 -08:00
val = brcm_sata_phy_rd ( port , BLOCK0_REG_BANK ,
2017-06-08 17:01:39 +05:30
BLOCK0_XGXSSTATUS ) ;
if ( val & BLOCK0_XGXSSTATUS_PLL_LOCK )
break ;
msleep ( 20 ) ;
try - - ;
} while ( try ) ;
if ( ( val & BLOCK0_XGXSSTATUS_PLL_LOCK ) = = 0 ) {
/* PLL did not lock; give up */
dev_err ( dev , " port%d PLL did not lock \n " , port - > portnum ) ;
return - ETIMEDOUT ;
}
/* Invert Tx polarity */
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , TX_REG_BANK , TX_ACTRL0 ,
2017-06-08 17:01:39 +05:30
~ TX_ACTRL0_TXPOL_FLIP , TX_ACTRL0_TXPOL_FLIP ) ;
/* Configure OOB control to handle 100MHz reference clock */
val = ( ( 0xc < < OOB_CTRL1_BURST_MAX_SHIFT ) |
( 0x4 < < OOB_CTRL1_BURST_MIN_SHIFT ) |
( 0x8 < < OOB_CTRL1_WAKE_IDLE_MAX_SHIFT ) |
( 0x3 < < OOB_CTRL1_WAKE_IDLE_MIN_SHIFT ) ) ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , OOB_REG_BANK , OOB_CTRL1 , 0x0 , val ) ;
2017-06-08 17:01:39 +05:30
val = ( ( 0x1b < < OOB_CTRL2_RESET_IDLE_MAX_SHIFT ) |
( 0x2 < < OOB_CTRL2_BURST_CNT_SHIFT ) |
( 0x9 < < OOB_CTRL2_RESET_IDLE_MIN_SHIFT ) ) ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , OOB_REG_BANK , OOB_CTRL2 , 0x0 , val ) ;
2017-06-08 17:01:39 +05:30
return 0 ;
}
2018-09-20 12:16:38 -07:00
static int brcm_dsl_sata_init ( struct brcm_sata_port * port )
{
struct device * dev = port - > phy_priv - > dev ;
unsigned int try ;
u32 tmp ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL1_REG_BANK , PLL1_ACTRL7 , 0 , 0x873 ) ;
2018-09-20 12:16:38 -07:00
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL1_REG_BANK , PLL1_ACTRL6 , 0 , 0xc000 ) ;
2018-09-20 12:16:38 -07:00
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL_REG_BANK_0 , PLL_REG_BANK_0_PLLCONTROL_0 ,
2018-09-20 12:16:38 -07:00
0 , 0x3089 ) ;
usleep_range ( 1000 , 2000 ) ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL_REG_BANK_0 , PLL_REG_BANK_0_PLLCONTROL_0 ,
2018-09-20 12:16:38 -07:00
0 , 0x3088 ) ;
usleep_range ( 1000 , 2000 ) ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , AEQRX_REG_BANK_1 , AEQRX_SLCAL0_CTRL0 ,
2018-09-20 12:16:38 -07:00
0 , 0x3000 ) ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , AEQRX_REG_BANK_1 , AEQRX_SLCAL1_CTRL0 ,
2018-09-20 12:16:38 -07:00
0 , 0x3000 ) ;
usleep_range ( 1000 , 2000 ) ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL_REG_BANK_0 , PLL_CAP_CHARGE_TIME , 0 , 0x32 ) ;
2018-09-20 12:16:38 -07:00
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL_REG_BANK_0 , PLL_VCO_CAL_THRESH , 0 , 0xa ) ;
2018-09-20 12:16:38 -07:00
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , PLL_REG_BANK_0 , PLL_FREQ_DET_TIME , 0 , 0x64 ) ;
2018-09-20 12:16:38 -07:00
usleep_range ( 1000 , 2000 ) ;
/* Acquire PLL lock */
try = 50 ;
while ( try ) {
2020-02-20 20:14:23 -08:00
tmp = brcm_sata_phy_rd ( port , BLOCK0_REG_BANK ,
2018-09-20 12:16:38 -07:00
BLOCK0_XGXSSTATUS ) ;
if ( tmp & BLOCK0_XGXSSTATUS_PLL_LOCK )
break ;
msleep ( 20 ) ;
try - - ;
2021-02-03 10:58:07 +08:00
}
2018-09-20 12:16:38 -07:00
if ( ! try ) {
/* PLL did not lock; give up */
dev_err ( dev , " port%d PLL did not lock \n " , port - > portnum ) ;
return - ETIMEDOUT ;
}
dev_dbg ( dev , " port%d initialized \n " , port - > portnum ) ;
return 0 ;
}
2015-05-20 17:18:40 -07:00
static int brcm_sata_phy_init ( struct phy * phy )
{
2016-03-28 10:18:27 +05:30
int rc ;
2015-05-20 17:18:40 -07:00
struct brcm_sata_port * port = phy_get_drvdata ( phy ) ;
2016-03-28 10:18:27 +05:30
switch ( port - > phy_priv - > version ) {
2019-12-10 12:08:52 -08:00
case BRCM_SATA_PHY_STB_16NM :
rc = brcm_stb_sata_16nm_init ( port ) ;
break ;
2016-03-28 10:18:27 +05:30
case BRCM_SATA_PHY_STB_28NM :
case BRCM_SATA_PHY_STB_40NM :
rc = brcm_stb_sata_init ( port ) ;
break ;
case BRCM_SATA_PHY_IPROC_NS2 :
rc = brcm_ns2_sata_init ( port ) ;
break ;
2016-06-16 09:53:34 -04:00
case BRCM_SATA_PHY_IPROC_NSP :
rc = brcm_nsp_sata_init ( port ) ;
break ;
2017-06-08 17:01:39 +05:30
case BRCM_SATA_PHY_IPROC_SR :
rc = brcm_sr_sata_init ( port ) ;
break ;
2018-09-20 12:16:38 -07:00
case BRCM_SATA_PHY_DSL_28NM :
rc = brcm_dsl_sata_init ( port ) ;
break ;
2016-03-28 10:18:27 +05:30
default :
rc = - ENODEV ;
2016-10-20 12:23:38 +05:30
}
2015-05-20 17:18:40 -07:00
2016-08-10 18:04:44 +08:00
return rc ;
2015-05-20 17:18:40 -07:00
}
2018-01-11 17:31:07 -08:00
static void brcm_stb_sata_calibrate ( struct brcm_sata_port * port )
{
u32 tmp = BIT ( 8 ) ;
2020-02-20 20:14:23 -08:00
brcm_sata_phy_wr ( port , RXPMD_REG_BANK , RXPMD_RX_FREQ_MON_CONTROL1 ,
2018-01-11 17:31:07 -08:00
~ tmp , tmp ) ;
}
static int brcm_sata_phy_calibrate ( struct phy * phy )
{
struct brcm_sata_port * port = phy_get_drvdata ( phy ) ;
int rc = - EOPNOTSUPP ;
switch ( port - > phy_priv - > version ) {
case BRCM_SATA_PHY_STB_28NM :
case BRCM_SATA_PHY_STB_40NM :
brcm_stb_sata_calibrate ( port ) ;
rc = 0 ;
break ;
default :
break ;
2018-01-18 01:51:18 +08:00
}
2018-01-11 17:31:07 -08:00
return rc ;
}
2015-11-26 11:56:35 +09:00
static const struct phy_ops phy_ops = {
2015-05-20 17:18:40 -07:00
. init = brcm_sata_phy_init ,
2018-01-11 17:31:07 -08:00
. calibrate = brcm_sata_phy_calibrate ,
2015-05-20 17:18:40 -07:00
. owner = THIS_MODULE ,
} ;
static const struct of_device_id brcm_sata_phy_of_match [ ] = {
2019-12-10 12:08:52 -08:00
{ . compatible = " brcm,bcm7216-sata-phy " ,
. data = ( void * ) BRCM_SATA_PHY_STB_16NM } ,
2015-11-26 11:56:34 +09:00
{ . compatible = " brcm,bcm7445-sata-phy " ,
2016-03-28 10:18:27 +05:30
. data = ( void * ) BRCM_SATA_PHY_STB_28NM } ,
2015-11-26 11:56:35 +09:00
{ . compatible = " brcm,bcm7425-sata-phy " ,
2016-03-28 10:18:27 +05:30
. data = ( void * ) BRCM_SATA_PHY_STB_40NM } ,
{ . compatible = " brcm,iproc-ns2-sata-phy " ,
. data = ( void * ) BRCM_SATA_PHY_IPROC_NS2 } ,
2016-06-16 09:53:34 -04:00
{ . compatible = " brcm,iproc-nsp-sata-phy " ,
. data = ( void * ) BRCM_SATA_PHY_IPROC_NSP } ,
2017-06-08 17:01:39 +05:30
{ . compatible = " brcm,iproc-sr-sata-phy " ,
. data = ( void * ) BRCM_SATA_PHY_IPROC_SR } ,
2018-09-20 12:16:38 -07:00
{ . compatible = " brcm,bcm63138-sata-phy " ,
. data = ( void * ) BRCM_SATA_PHY_DSL_28NM } ,
2015-05-20 17:18:40 -07:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , brcm_sata_phy_of_match ) ;
static int brcm_sata_phy_probe ( struct platform_device * pdev )
{
2017-10-11 17:53:12 -07:00
const char * rxaeq_mode ;
2015-05-20 17:18:40 -07:00
struct device * dev = & pdev - > dev ;
struct device_node * dn = dev - > of_node , * child ;
2015-11-26 11:56:34 +09:00
const struct of_device_id * of_id ;
2015-05-20 17:18:40 -07:00
struct brcm_sata_phy * priv ;
struct phy_provider * provider ;
2015-11-16 12:33:14 +01:00
int ret , count = 0 ;
2015-05-20 17:18:40 -07:00
if ( of_get_child_count ( dn ) = = 0 )
return - ENODEV ;
priv = devm_kzalloc ( dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
dev_set_drvdata ( dev , priv ) ;
priv - > dev = dev ;
2020-11-06 14:08:36 +08:00
priv - > phy_base = devm_platform_ioremap_resource_byname ( pdev , " phy " ) ;
2015-05-20 17:18:40 -07:00
if ( IS_ERR ( priv - > phy_base ) )
return PTR_ERR ( priv - > phy_base ) ;
2015-11-26 11:56:34 +09:00
of_id = of_match_node ( brcm_sata_phy_of_match , dn ) ;
if ( of_id )
priv - > version = ( enum brcm_sata_phy_version ) of_id - > data ;
else
2016-03-28 10:18:27 +05:30
priv - > version = BRCM_SATA_PHY_STB_28NM ;
if ( priv - > version = = BRCM_SATA_PHY_IPROC_NS2 ) {
2020-11-06 14:08:36 +08:00
priv - > ctrl_base = devm_platform_ioremap_resource_byname ( pdev , " phy-ctrl " ) ;
2016-03-28 10:18:27 +05:30
if ( IS_ERR ( priv - > ctrl_base ) )
return PTR_ERR ( priv - > ctrl_base ) ;
}
2015-11-26 11:56:34 +09:00
2015-05-20 17:18:40 -07:00
for_each_available_child_of_node ( dn , child ) {
unsigned int id ;
struct brcm_sata_port * port ;
if ( of_property_read_u32 ( child , " reg " , & id ) ) {
2018-08-27 20:52:40 -05:00
dev_err ( dev , " missing reg property in node %pOFn \n " ,
child ) ;
2015-11-16 12:33:14 +01:00
ret = - EINVAL ;
goto put_child ;
2015-05-20 17:18:40 -07:00
}
if ( id > = MAX_PORTS ) {
dev_err ( dev , " invalid reg: %u \n " , id ) ;
2015-11-16 12:33:14 +01:00
ret = - EINVAL ;
goto put_child ;
2015-05-20 17:18:40 -07:00
}
if ( priv - > phys [ id ] . phy ) {
dev_err ( dev , " already registered port %u \n " , id ) ;
2015-11-16 12:33:14 +01:00
ret = - EINVAL ;
goto put_child ;
2015-05-20 17:18:40 -07:00
}
port = & priv - > phys [ id ] ;
port - > portnum = id ;
port - > phy_priv = priv ;
2015-11-26 11:56:35 +09:00
port - > phy = devm_phy_create ( dev , child , & phy_ops ) ;
2017-10-11 17:53:12 -07:00
port - > rxaeq_mode = RXAEQ_MODE_OFF ;
if ( ! of_property_read_string ( child , " brcm,rxaeq-mode " ,
& rxaeq_mode ) )
port - > rxaeq_mode = rxaeq_to_val ( rxaeq_mode ) ;
if ( port - > rxaeq_mode = = RXAEQ_MODE_MANUAL )
of_property_read_u32 ( child , " brcm,rxaeq-value " ,
& port - > rxaeq_val ) ;
2020-10-22 13:50:56 -07:00
of_property_read_u32 ( child , " brcm,tx-amplitude-millivolt " ,
& port - > tx_amplitude_val ) ;
2015-05-20 17:18:40 -07:00
port - > ssc_en = of_property_read_bool ( child , " brcm,enable-ssc " ) ;
if ( IS_ERR ( port - > phy ) ) {
dev_err ( dev , " failed to create PHY \n " ) ;
2015-11-16 12:33:14 +01:00
ret = PTR_ERR ( port - > phy ) ;
goto put_child ;
2015-05-20 17:18:40 -07:00
}
phy_set_drvdata ( port - > phy , port ) ;
count + + ;
}
provider = devm_of_phy_provider_register ( dev , of_phy_simple_xlate ) ;
if ( IS_ERR ( provider ) ) {
dev_err ( dev , " could not register PHY provider \n " ) ;
return PTR_ERR ( provider ) ;
}
dev_info ( dev , " registered %d port(s) \n " , count ) ;
return 0 ;
2015-11-16 12:33:14 +01:00
put_child :
of_node_put ( child ) ;
return ret ;
2015-05-20 17:18:40 -07:00
}
static struct platform_driver brcm_sata_phy_driver = {
. probe = brcm_sata_phy_probe ,
. driver = {
. of_match_table = brcm_sata_phy_of_match ,
2016-03-28 10:18:26 +05:30
. name = " brcm-sata-phy " ,
2015-05-20 17:18:40 -07:00
}
} ;
module_platform_driver ( brcm_sata_phy_driver ) ;
2016-03-28 10:18:26 +05:30
MODULE_DESCRIPTION ( " Broadcom SATA PHY driver " ) ;
2015-05-20 17:18:40 -07:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Marc Carino " ) ;
MODULE_AUTHOR ( " Brian Norris " ) ;
2016-03-28 10:18:26 +05:30
MODULE_ALIAS ( " platform:phy-brcm-sata " ) ;