1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
// 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);
}
|