1*f629acc6SJiawen Wu // SPDX-License-Identifier: GPL-2.0 2*f629acc6SJiawen Wu /* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */ 3*f629acc6SJiawen Wu 4*f629acc6SJiawen Wu #include <linux/pcs/pcs-xpcs.h> 5*f629acc6SJiawen Wu #include <linux/mdio.h> 6*f629acc6SJiawen Wu #include "pcs-xpcs.h" 7*f629acc6SJiawen Wu 8*f629acc6SJiawen Wu /* VR_XS_PMA_MMD */ 9*f629acc6SJiawen Wu #define TXGBE_PMA_MMD 0x8020 10*f629acc6SJiawen Wu #define TXGBE_TX_GENCTL1 0x11 11*f629acc6SJiawen Wu #define TXGBE_TX_GENCTL1_VBOOST_LVL GENMASK(10, 8) 12*f629acc6SJiawen Wu #define TXGBE_TX_GENCTL1_VBOOST_EN0 BIT(4) 13*f629acc6SJiawen Wu #define TXGBE_TX_GEN_CTL2 0x12 14*f629acc6SJiawen Wu #define TXGBE_TX_GEN_CTL2_TX0_WIDTH(v) FIELD_PREP(GENMASK(9, 8), v) 15*f629acc6SJiawen Wu #define TXGBE_TX_RATE_CTL 0x14 16*f629acc6SJiawen Wu #define TXGBE_TX_RATE_CTL_TX0_RATE(v) FIELD_PREP(GENMASK(2, 0), v) 17*f629acc6SJiawen Wu #define TXGBE_RX_GEN_CTL2 0x32 18*f629acc6SJiawen Wu #define TXGBE_RX_GEN_CTL2_RX0_WIDTH(v) FIELD_PREP(GENMASK(9, 8), v) 19*f629acc6SJiawen Wu #define TXGBE_RX_GEN_CTL3 0x33 20*f629acc6SJiawen Wu #define TXGBE_RX_GEN_CTL3_LOS_TRSHLD0 GENMASK(2, 0) 21*f629acc6SJiawen Wu #define TXGBE_RX_RATE_CTL 0x34 22*f629acc6SJiawen Wu #define TXGBE_RX_RATE_CTL_RX0_RATE(v) FIELD_PREP(GENMASK(1, 0), v) 23*f629acc6SJiawen Wu #define TXGBE_RX_EQ_ATTN_CTL 0x37 24*f629acc6SJiawen Wu #define TXGBE_RX_EQ_ATTN_LVL0 GENMASK(2, 0) 25*f629acc6SJiawen Wu #define TXGBE_RX_EQ_CTL0 0x38 26*f629acc6SJiawen Wu #define TXGBE_RX_EQ_CTL0_VGA1_GAIN(v) FIELD_PREP(GENMASK(15, 12), v) 27*f629acc6SJiawen Wu #define TXGBE_RX_EQ_CTL0_VGA2_GAIN(v) FIELD_PREP(GENMASK(11, 8), v) 28*f629acc6SJiawen Wu #define TXGBE_RX_EQ_CTL0_CTLE_POLE(v) FIELD_PREP(GENMASK(7, 5), v) 29*f629acc6SJiawen Wu #define TXGBE_RX_EQ_CTL0_CTLE_BOOST(v) FIELD_PREP(GENMASK(4, 0), v) 30*f629acc6SJiawen Wu #define TXGBE_RX_EQ_CTL4 0x3C 31*f629acc6SJiawen Wu #define TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0 BIT(4) 32*f629acc6SJiawen Wu #define TXGBE_RX_EQ_CTL4_CONT_ADAPT0 BIT(0) 33*f629acc6SJiawen Wu #define TXGBE_AFE_DFE_ENABLE 0x3D 34*f629acc6SJiawen Wu #define TXGBE_DFE_EN_0 BIT(4) 35*f629acc6SJiawen Wu #define TXGBE_AFE_EN_0 BIT(0) 36*f629acc6SJiawen Wu #define TXGBE_DFE_TAP_CTL0 0x3E 37*f629acc6SJiawen Wu #define TXGBE_MPLLA_CTL0 0x51 38*f629acc6SJiawen Wu #define TXGBE_MPLLA_CTL2 0x53 39*f629acc6SJiawen Wu #define TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN BIT(10) 40*f629acc6SJiawen Wu #define TXGBE_MPLLA_CTL2_DIV10_CLK_EN BIT(9) 41*f629acc6SJiawen Wu #define TXGBE_MPLLA_CTL3 0x57 42*f629acc6SJiawen Wu #define TXGBE_MISC_CTL0 0x70 43*f629acc6SJiawen Wu #define TXGBE_MISC_CTL0_PLL BIT(15) 44*f629acc6SJiawen Wu #define TXGBE_MISC_CTL0_CR_PARA_SEL BIT(14) 45*f629acc6SJiawen Wu #define TXGBE_MISC_CTL0_RX_VREF(v) FIELD_PREP(GENMASK(12, 8), v) 46*f629acc6SJiawen Wu #define TXGBE_VCO_CAL_LD0 0x72 47*f629acc6SJiawen Wu #define TXGBE_VCO_CAL_REF0 0x76 48*f629acc6SJiawen Wu 49*f629acc6SJiawen Wu static int txgbe_read_pma(struct dw_xpcs *xpcs, int reg) 50*f629acc6SJiawen Wu { 51*f629acc6SJiawen Wu return xpcs_read(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg); 52*f629acc6SJiawen Wu } 53*f629acc6SJiawen Wu 54*f629acc6SJiawen Wu static int txgbe_write_pma(struct dw_xpcs *xpcs, int reg, u16 val) 55*f629acc6SJiawen Wu { 56*f629acc6SJiawen Wu return xpcs_write(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg, val); 57*f629acc6SJiawen Wu } 58*f629acc6SJiawen Wu 59*f629acc6SJiawen Wu static void txgbe_pma_config_10gbaser(struct dw_xpcs *xpcs) 60*f629acc6SJiawen Wu { 61*f629acc6SJiawen Wu int val; 62*f629acc6SJiawen Wu 63*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x21); 64*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0); 65*f629acc6SJiawen Wu val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1); 66*f629acc6SJiawen Wu val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL); 67*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val); 68*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL | 69*f629acc6SJiawen Wu TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF)); 70*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x549); 71*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x29); 72*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, 0); 73*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, 0); 74*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(3)); 75*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(3)); 76*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN | 77*f629acc6SJiawen Wu TXGBE_MPLLA_CTL2_DIV10_CLK_EN); 78*f629acc6SJiawen Wu 79*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_CTLE_POLE(2) | 80*f629acc6SJiawen Wu TXGBE_RX_EQ_CTL0_CTLE_BOOST(5)); 81*f629acc6SJiawen Wu val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL); 82*f629acc6SJiawen Wu val &= ~TXGBE_RX_EQ_ATTN_LVL0; 83*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val); 84*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0xBE); 85*f629acc6SJiawen Wu val = txgbe_read_pma(xpcs, TXGBE_AFE_DFE_ENABLE); 86*f629acc6SJiawen Wu val &= ~(TXGBE_DFE_EN_0 | TXGBE_AFE_EN_0); 87*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, val); 88*f629acc6SJiawen Wu val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_CTL4); 89*f629acc6SJiawen Wu val &= ~TXGBE_RX_EQ_CTL4_CONT_ADAPT0; 90*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, val); 91*f629acc6SJiawen Wu } 92*f629acc6SJiawen Wu 93*f629acc6SJiawen Wu static void txgbe_pma_config_1g(struct dw_xpcs *xpcs) 94*f629acc6SJiawen Wu { 95*f629acc6SJiawen Wu int val; 96*f629acc6SJiawen Wu 97*f629acc6SJiawen Wu val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1); 98*f629acc6SJiawen Wu val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL); 99*f629acc6SJiawen Wu val &= ~TXGBE_TX_GENCTL1_VBOOST_EN0; 100*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val); 101*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL | 102*f629acc6SJiawen Wu TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF)); 103*f629acc6SJiawen Wu 104*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_VGA1_GAIN(7) | 105*f629acc6SJiawen Wu TXGBE_RX_EQ_CTL0_VGA2_GAIN(7) | TXGBE_RX_EQ_CTL0_CTLE_BOOST(6)); 106*f629acc6SJiawen Wu val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL); 107*f629acc6SJiawen Wu val &= ~TXGBE_RX_EQ_ATTN_LVL0; 108*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val); 109*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0); 110*f629acc6SJiawen Wu val = txgbe_read_pma(xpcs, TXGBE_RX_GEN_CTL3); 111*f629acc6SJiawen Wu val = u16_replace_bits(val, 0x4, TXGBE_RX_GEN_CTL3_LOS_TRSHLD0); 112*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val); 113*f629acc6SJiawen Wu 114*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x20); 115*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0x46); 116*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x540); 117*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x2A); 118*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, 0); 119*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0); 120*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, TXGBE_TX_RATE_CTL_TX0_RATE(3)); 121*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, TXGBE_RX_RATE_CTL_RX0_RATE(3)); 122*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(1)); 123*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(1)); 124*f629acc6SJiawen Wu txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV10_CLK_EN); 125*f629acc6SJiawen Wu } 126*f629acc6SJiawen Wu 127*f629acc6SJiawen Wu static int txgbe_pcs_poll_power_up(struct dw_xpcs *xpcs) 128*f629acc6SJiawen Wu { 129*f629acc6SJiawen Wu int val, ret; 130*f629acc6SJiawen Wu 131*f629acc6SJiawen Wu /* Wait xpcs power-up good */ 132*f629acc6SJiawen Wu ret = read_poll_timeout(xpcs_read_vpcs, val, 133*f629acc6SJiawen Wu (val & DW_PSEQ_ST) == DW_PSEQ_ST_GOOD, 134*f629acc6SJiawen Wu 10000, 1000000, false, 135*f629acc6SJiawen Wu xpcs, DW_VR_XS_PCS_DIG_STS); 136*f629acc6SJiawen Wu if (ret < 0) 137*f629acc6SJiawen Wu dev_err(&xpcs->mdiodev->dev, "xpcs power-up timeout\n"); 138*f629acc6SJiawen Wu 139*f629acc6SJiawen Wu return ret; 140*f629acc6SJiawen Wu } 141*f629acc6SJiawen Wu 142*f629acc6SJiawen Wu static int txgbe_pma_init_done(struct dw_xpcs *xpcs) 143*f629acc6SJiawen Wu { 144*f629acc6SJiawen Wu int val, ret; 145*f629acc6SJiawen Wu 146*f629acc6SJiawen Wu xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_VR_RST | DW_EN_VSMMD1); 147*f629acc6SJiawen Wu 148*f629acc6SJiawen Wu /* wait pma initialization done */ 149*f629acc6SJiawen Wu ret = read_poll_timeout(xpcs_read_vpcs, val, !(val & DW_VR_RST), 150*f629acc6SJiawen Wu 100000, 10000000, false, 151*f629acc6SJiawen Wu xpcs, DW_VR_XS_PCS_DIG_CTRL1); 152*f629acc6SJiawen Wu if (ret < 0) 153*f629acc6SJiawen Wu dev_err(&xpcs->mdiodev->dev, "xpcs pma initialization timeout\n"); 154*f629acc6SJiawen Wu 155*f629acc6SJiawen Wu return ret; 156*f629acc6SJiawen Wu } 157*f629acc6SJiawen Wu 158*f629acc6SJiawen Wu static bool txgbe_xpcs_mode_quirk(struct dw_xpcs *xpcs) 159*f629acc6SJiawen Wu { 160*f629acc6SJiawen Wu int ret; 161*f629acc6SJiawen Wu 162*f629acc6SJiawen Wu /* When txgbe do LAN reset, PCS will change to default 10GBASE-R mode */ 163*f629acc6SJiawen Wu ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_CTRL2); 164*f629acc6SJiawen Wu ret &= MDIO_PCS_CTRL2_TYPE; 165*f629acc6SJiawen Wu if (ret == MDIO_PCS_CTRL2_10GBR && 166*f629acc6SJiawen Wu xpcs->interface != PHY_INTERFACE_MODE_10GBASER) 167*f629acc6SJiawen Wu return true; 168*f629acc6SJiawen Wu 169*f629acc6SJiawen Wu return false; 170*f629acc6SJiawen Wu } 171*f629acc6SJiawen Wu 172*f629acc6SJiawen Wu int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface) 173*f629acc6SJiawen Wu { 174*f629acc6SJiawen Wu int val, ret; 175*f629acc6SJiawen Wu 176*f629acc6SJiawen Wu switch (interface) { 177*f629acc6SJiawen Wu case PHY_INTERFACE_MODE_10GBASER: 178*f629acc6SJiawen Wu case PHY_INTERFACE_MODE_SGMII: 179*f629acc6SJiawen Wu case PHY_INTERFACE_MODE_1000BASEX: 180*f629acc6SJiawen Wu break; 181*f629acc6SJiawen Wu default: 182*f629acc6SJiawen Wu return 0; 183*f629acc6SJiawen Wu } 184*f629acc6SJiawen Wu 185*f629acc6SJiawen Wu if (xpcs->interface == interface && !txgbe_xpcs_mode_quirk(xpcs)) 186*f629acc6SJiawen Wu return 0; 187*f629acc6SJiawen Wu 188*f629acc6SJiawen Wu xpcs->interface = interface; 189*f629acc6SJiawen Wu 190*f629acc6SJiawen Wu ret = txgbe_pcs_poll_power_up(xpcs); 191*f629acc6SJiawen Wu if (ret < 0) 192*f629acc6SJiawen Wu return ret; 193*f629acc6SJiawen Wu 194*f629acc6SJiawen Wu if (interface == PHY_INTERFACE_MODE_10GBASER) { 195*f629acc6SJiawen Wu xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBR); 196*f629acc6SJiawen Wu val = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1); 197*f629acc6SJiawen Wu val |= MDIO_CTRL1_SPEED10G; 198*f629acc6SJiawen Wu xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, val); 199*f629acc6SJiawen Wu txgbe_pma_config_10gbaser(xpcs); 200*f629acc6SJiawen Wu } else { 201*f629acc6SJiawen Wu xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBX); 202*f629acc6SJiawen Wu xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, 0); 203*f629acc6SJiawen Wu xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL1, 0); 204*f629acc6SJiawen Wu txgbe_pma_config_1g(xpcs); 205*f629acc6SJiawen Wu } 206*f629acc6SJiawen Wu 207*f629acc6SJiawen Wu return txgbe_pma_init_done(xpcs); 208*f629acc6SJiawen Wu } 209