// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */ #include #include #include "pcs-xpcs.h" /* VR_XS_PMA_MMD */ #define TXGBE_PMA_MMD 0x8020 #define TXGBE_TX_GENCTL1 0x11 #define TXGBE_TX_GENCTL1_VBOOST_LVL GENMASK(10, 8) #define TXGBE_TX_GENCTL1_VBOOST_EN0 BIT(4) #define TXGBE_TX_GEN_CTL2 0x12 #define TXGBE_TX_GEN_CTL2_TX0_WIDTH(v) FIELD_PREP(GENMASK(9, 8), v) #define TXGBE_TX_RATE_CTL 0x14 #define TXGBE_TX_RATE_CTL_TX0_RATE(v) FIELD_PREP(GENMASK(2, 0), v) #define TXGBE_RX_GEN_CTL2 0x32 #define TXGBE_RX_GEN_CTL2_RX0_WIDTH(v) FIELD_PREP(GENMASK(9, 8), v) #define TXGBE_RX_GEN_CTL3 0x33 #define TXGBE_RX_GEN_CTL3_LOS_TRSHLD0 GENMASK(2, 0) #define TXGBE_RX_RATE_CTL 0x34 #define TXGBE_RX_RATE_CTL_RX0_RATE(v) FIELD_PREP(GENMASK(1, 0), v) #define TXGBE_RX_EQ_ATTN_CTL 0x37 #define TXGBE_RX_EQ_ATTN_LVL0 GENMASK(2, 0) #define TXGBE_RX_EQ_CTL0 0x38 #define TXGBE_RX_EQ_CTL0_VGA1_GAIN(v) FIELD_PREP(GENMASK(15, 12), v) #define TXGBE_RX_EQ_CTL0_VGA2_GAIN(v) FIELD_PREP(GENMASK(11, 8), v) #define TXGBE_RX_EQ_CTL0_CTLE_POLE(v) FIELD_PREP(GENMASK(7, 5), v) #define TXGBE_RX_EQ_CTL0_CTLE_BOOST(v) FIELD_PREP(GENMASK(4, 0), v) #define TXGBE_RX_EQ_CTL4 0x3C #define TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0 BIT(4) #define TXGBE_RX_EQ_CTL4_CONT_ADAPT0 BIT(0) #define TXGBE_AFE_DFE_ENABLE 0x3D #define TXGBE_DFE_EN_0 BIT(4) #define TXGBE_AFE_EN_0 BIT(0) #define TXGBE_DFE_TAP_CTL0 0x3E #define TXGBE_MPLLA_CTL0 0x51 #define TXGBE_MPLLA_CTL2 0x53 #define TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN BIT(10) #define TXGBE_MPLLA_CTL2_DIV10_CLK_EN BIT(9) #define TXGBE_MPLLA_CTL3 0x57 #define TXGBE_MISC_CTL0 0x70 #define TXGBE_MISC_CTL0_PLL BIT(15) #define TXGBE_MISC_CTL0_CR_PARA_SEL BIT(14) #define TXGBE_MISC_CTL0_RX_VREF(v) FIELD_PREP(GENMASK(12, 8), v) #define TXGBE_VCO_CAL_LD0 0x72 #define TXGBE_VCO_CAL_REF0 0x76 static int txgbe_read_pma(struct dw_xpcs *xpcs, int reg) { return xpcs_read(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg); } static int txgbe_write_pma(struct dw_xpcs *xpcs, int reg, u16 val) { return xpcs_write(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg, val); } static void txgbe_pma_config_10gbaser(struct dw_xpcs *xpcs) { int val; txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x21); txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0); val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1); val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL); txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val); txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL | TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF)); txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x549); txgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x29); txgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, 0); txgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, 0); txgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(3)); txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(3)); txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN | TXGBE_MPLLA_CTL2_DIV10_CLK_EN); txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_CTLE_POLE(2) | TXGBE_RX_EQ_CTL0_CTLE_BOOST(5)); val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL); val &= ~TXGBE_RX_EQ_ATTN_LVL0; txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val); txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0xBE); val = txgbe_read_pma(xpcs, TXGBE_AFE_DFE_ENABLE); val &= ~(TXGBE_DFE_EN_0 | TXGBE_AFE_EN_0); txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, val); val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_CTL4); val &= ~TXGBE_RX_EQ_CTL4_CONT_ADAPT0; txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, val); } static void txgbe_pma_config_1g(struct dw_xpcs *xpcs) { int val; val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1); val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL); val &= ~TXGBE_TX_GENCTL1_VBOOST_EN0; txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val); txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL | TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF)); txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_VGA1_GAIN(7) | TXGBE_RX_EQ_CTL0_VGA2_GAIN(7) | TXGBE_RX_EQ_CTL0_CTLE_BOOST(6)); val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL); val &= ~TXGBE_RX_EQ_ATTN_LVL0; txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val); txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0); val = txgbe_read_pma(xpcs, TXGBE_RX_GEN_CTL3); val = u16_replace_bits(val, 0x4, TXGBE_RX_GEN_CTL3_LOS_TRSHLD0); txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val); txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x20); txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0x46); txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x540); txgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x2A); txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, 0); txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0); txgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, TXGBE_TX_RATE_CTL_TX0_RATE(3)); txgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, TXGBE_RX_RATE_CTL_RX0_RATE(3)); txgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(1)); txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(1)); txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV10_CLK_EN); } static int txgbe_pcs_poll_power_up(struct dw_xpcs *xpcs) { int val, ret; /* Wait xpcs power-up good */ ret = read_poll_timeout(xpcs_read_vpcs, val, (val & DW_PSEQ_ST) == DW_PSEQ_ST_GOOD, 10000, 1000000, false, xpcs, DW_VR_XS_PCS_DIG_STS); if (ret < 0) dev_err(&xpcs->mdiodev->dev, "xpcs power-up timeout\n"); return ret; } static int txgbe_pma_init_done(struct dw_xpcs *xpcs) { int val, ret; xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_VR_RST | DW_EN_VSMMD1); /* wait pma initialization done */ ret = read_poll_timeout(xpcs_read_vpcs, val, !(val & DW_VR_RST), 100000, 10000000, false, xpcs, DW_VR_XS_PCS_DIG_CTRL1); if (ret < 0) dev_err(&xpcs->mdiodev->dev, "xpcs pma initialization timeout\n"); return ret; } static bool txgbe_xpcs_mode_quirk(struct dw_xpcs *xpcs) { int ret; /* When txgbe do LAN reset, PCS will change to default 10GBASE-R mode */ ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_CTRL2); ret &= MDIO_PCS_CTRL2_TYPE; if ((ret == MDIO_PCS_CTRL2_10GBR && xpcs->interface != PHY_INTERFACE_MODE_10GBASER) || xpcs->interface == PHY_INTERFACE_MODE_SGMII) return true; return false; } int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface) { int val, ret; switch (interface) { case PHY_INTERFACE_MODE_10GBASER: case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_1000BASEX: break; default: return 0; } if (xpcs->interface == interface && !txgbe_xpcs_mode_quirk(xpcs)) return 0; xpcs->interface = interface; ret = txgbe_pcs_poll_power_up(xpcs); if (ret < 0) return ret; if (interface == PHY_INTERFACE_MODE_10GBASER) { xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBR); val = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1); val |= MDIO_CTRL1_SPEED10G; xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, val); txgbe_pma_config_10gbaser(xpcs); } else { xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBX); xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, 0); xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL1, 0); txgbe_pma_config_1g(xpcs); } return txgbe_pma_init_done(xpcs); }