-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
net: pcs: xpcs: support to switch mode for Wangxun NICs
According to chapter 6 of DesignWare Cores Ethernet PCS (version 3.20a) and custom design manual, add a configuration flow for switching interface mode. If the interface changes, the following setting is required: 1. wait VR_XS_PCS_DIG_STS bit(4, 2) [PSEQ_STATE] = 100b (Power-Good) 2. write SR_XS_PCS_CTRL2 to select various PCS type 3. write SR_PMA_CTRL1 and/or SR_XS_PCS_CTRL1 for link speed 4. program PMA registers 5. write VR_XS_PCS_DIG_CTRL1 bit(15) [VR_RST] = 1b (Vendor-Specific Soft Reset) 6. wait for VR_XS_PCS_DIG_CTRL1 bit(15) [VR_RST] to get cleared Only 10GBASE-R/SGMII/1000BASE-X modes are planned for the current Wangxun devices. And there is a quirk for Wangxun devices to switch mode although the interface in phylink state has not changed, since PCS will change to default 10GBASE-R when the ethernet driver(txgbe) do LAN reset. Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
- Loading branch information
Jiawen Wu
authored and
David S. Miller
committed
Aug 25, 2023
1 parent
d55595f
commit f629acc
Showing
6 changed files
with
227 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
// 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_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) | ||
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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters