| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- // SPDX-License-Identifier: GPL-2.0
- /* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */
- #include <linux/pcs/pcs-xpcs.h>
- #include <linux/mdio.h>
- #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_GEN_CTL3, 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);
- }
|