162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/pcs/pcs-xpcs.h>
562306a36Sopenharmony_ci#include <linux/mdio.h>
662306a36Sopenharmony_ci#include "pcs-xpcs.h"
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/* VR_XS_PMA_MMD */
962306a36Sopenharmony_ci#define TXGBE_PMA_MMD			0x8020
1062306a36Sopenharmony_ci#define TXGBE_TX_GENCTL1		0x11
1162306a36Sopenharmony_ci#define TXGBE_TX_GENCTL1_VBOOST_LVL	GENMASK(10, 8)
1262306a36Sopenharmony_ci#define TXGBE_TX_GENCTL1_VBOOST_EN0	BIT(4)
1362306a36Sopenharmony_ci#define TXGBE_TX_GEN_CTL2		0x12
1462306a36Sopenharmony_ci#define TXGBE_TX_GEN_CTL2_TX0_WIDTH(v)	FIELD_PREP(GENMASK(9, 8), v)
1562306a36Sopenharmony_ci#define TXGBE_TX_RATE_CTL		0x14
1662306a36Sopenharmony_ci#define TXGBE_TX_RATE_CTL_TX0_RATE(v)	FIELD_PREP(GENMASK(2, 0), v)
1762306a36Sopenharmony_ci#define TXGBE_RX_GEN_CTL2		0x32
1862306a36Sopenharmony_ci#define TXGBE_RX_GEN_CTL2_RX0_WIDTH(v)	FIELD_PREP(GENMASK(9, 8), v)
1962306a36Sopenharmony_ci#define TXGBE_RX_GEN_CTL3		0x33
2062306a36Sopenharmony_ci#define TXGBE_RX_GEN_CTL3_LOS_TRSHLD0	GENMASK(2, 0)
2162306a36Sopenharmony_ci#define TXGBE_RX_RATE_CTL		0x34
2262306a36Sopenharmony_ci#define TXGBE_RX_RATE_CTL_RX0_RATE(v)	FIELD_PREP(GENMASK(1, 0), v)
2362306a36Sopenharmony_ci#define TXGBE_RX_EQ_ATTN_CTL		0x37
2462306a36Sopenharmony_ci#define TXGBE_RX_EQ_ATTN_LVL0		GENMASK(2, 0)
2562306a36Sopenharmony_ci#define TXGBE_RX_EQ_CTL0		0x38
2662306a36Sopenharmony_ci#define TXGBE_RX_EQ_CTL0_VGA1_GAIN(v)	FIELD_PREP(GENMASK(15, 12), v)
2762306a36Sopenharmony_ci#define TXGBE_RX_EQ_CTL0_VGA2_GAIN(v)	FIELD_PREP(GENMASK(11, 8), v)
2862306a36Sopenharmony_ci#define TXGBE_RX_EQ_CTL0_CTLE_POLE(v)	FIELD_PREP(GENMASK(7, 5), v)
2962306a36Sopenharmony_ci#define TXGBE_RX_EQ_CTL0_CTLE_BOOST(v)	FIELD_PREP(GENMASK(4, 0), v)
3062306a36Sopenharmony_ci#define TXGBE_RX_EQ_CTL4		0x3C
3162306a36Sopenharmony_ci#define TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0	BIT(4)
3262306a36Sopenharmony_ci#define TXGBE_RX_EQ_CTL4_CONT_ADAPT0	BIT(0)
3362306a36Sopenharmony_ci#define TXGBE_AFE_DFE_ENABLE		0x3D
3462306a36Sopenharmony_ci#define TXGBE_DFE_EN_0			BIT(4)
3562306a36Sopenharmony_ci#define TXGBE_AFE_EN_0			BIT(0)
3662306a36Sopenharmony_ci#define TXGBE_DFE_TAP_CTL0		0x3E
3762306a36Sopenharmony_ci#define TXGBE_MPLLA_CTL0		0x51
3862306a36Sopenharmony_ci#define TXGBE_MPLLA_CTL2		0x53
3962306a36Sopenharmony_ci#define TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN	BIT(10)
4062306a36Sopenharmony_ci#define TXGBE_MPLLA_CTL2_DIV10_CLK_EN	BIT(9)
4162306a36Sopenharmony_ci#define TXGBE_MPLLA_CTL3		0x57
4262306a36Sopenharmony_ci#define TXGBE_MISC_CTL0			0x70
4362306a36Sopenharmony_ci#define TXGBE_MISC_CTL0_PLL		BIT(15)
4462306a36Sopenharmony_ci#define TXGBE_MISC_CTL0_CR_PARA_SEL	BIT(14)
4562306a36Sopenharmony_ci#define TXGBE_MISC_CTL0_RX_VREF(v)	FIELD_PREP(GENMASK(12, 8), v)
4662306a36Sopenharmony_ci#define TXGBE_VCO_CAL_LD0		0x72
4762306a36Sopenharmony_ci#define TXGBE_VCO_CAL_REF0		0x76
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic int txgbe_read_pma(struct dw_xpcs *xpcs, int reg)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	return xpcs_read(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg);
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic int txgbe_write_pma(struct dw_xpcs *xpcs, int reg, u16 val)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	return xpcs_write(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg, val);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic void txgbe_pma_config_10gbaser(struct dw_xpcs *xpcs)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	int val;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x21);
6462306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0);
6562306a36Sopenharmony_ci	val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1);
6662306a36Sopenharmony_ci	val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL);
6762306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val);
6862306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL |
6962306a36Sopenharmony_ci			TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF));
7062306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x549);
7162306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x29);
7262306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, 0);
7362306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, 0);
7462306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(3));
7562306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(3));
7662306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN |
7762306a36Sopenharmony_ci			TXGBE_MPLLA_CTL2_DIV10_CLK_EN);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_CTLE_POLE(2) |
8062306a36Sopenharmony_ci			TXGBE_RX_EQ_CTL0_CTLE_BOOST(5));
8162306a36Sopenharmony_ci	val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL);
8262306a36Sopenharmony_ci	val &= ~TXGBE_RX_EQ_ATTN_LVL0;
8362306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
8462306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0xBE);
8562306a36Sopenharmony_ci	val = txgbe_read_pma(xpcs, TXGBE_AFE_DFE_ENABLE);
8662306a36Sopenharmony_ci	val &= ~(TXGBE_DFE_EN_0 | TXGBE_AFE_EN_0);
8762306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, val);
8862306a36Sopenharmony_ci	val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_CTL4);
8962306a36Sopenharmony_ci	val &= ~TXGBE_RX_EQ_CTL4_CONT_ADAPT0;
9062306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, val);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic void txgbe_pma_config_1g(struct dw_xpcs *xpcs)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	int val;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1);
9862306a36Sopenharmony_ci	val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL);
9962306a36Sopenharmony_ci	val &= ~TXGBE_TX_GENCTL1_VBOOST_EN0;
10062306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val);
10162306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL |
10262306a36Sopenharmony_ci			TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF));
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_VGA1_GAIN(7) |
10562306a36Sopenharmony_ci			TXGBE_RX_EQ_CTL0_VGA2_GAIN(7) | TXGBE_RX_EQ_CTL0_CTLE_BOOST(6));
10662306a36Sopenharmony_ci	val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL);
10762306a36Sopenharmony_ci	val &= ~TXGBE_RX_EQ_ATTN_LVL0;
10862306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
10962306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0);
11062306a36Sopenharmony_ci	val = txgbe_read_pma(xpcs, TXGBE_RX_GEN_CTL3);
11162306a36Sopenharmony_ci	val = u16_replace_bits(val, 0x4, TXGBE_RX_GEN_CTL3_LOS_TRSHLD0);
11262306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x20);
11562306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0x46);
11662306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x540);
11762306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x2A);
11862306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, 0);
11962306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0);
12062306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, TXGBE_TX_RATE_CTL_TX0_RATE(3));
12162306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, TXGBE_RX_RATE_CTL_RX0_RATE(3));
12262306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(1));
12362306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(1));
12462306a36Sopenharmony_ci	txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV10_CLK_EN);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic int txgbe_pcs_poll_power_up(struct dw_xpcs *xpcs)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	int val, ret;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	/* Wait xpcs power-up good */
13262306a36Sopenharmony_ci	ret = read_poll_timeout(xpcs_read_vpcs, val,
13362306a36Sopenharmony_ci				(val & DW_PSEQ_ST) == DW_PSEQ_ST_GOOD,
13462306a36Sopenharmony_ci				10000, 1000000, false,
13562306a36Sopenharmony_ci				xpcs, DW_VR_XS_PCS_DIG_STS);
13662306a36Sopenharmony_ci	if (ret < 0)
13762306a36Sopenharmony_ci		dev_err(&xpcs->mdiodev->dev, "xpcs power-up timeout\n");
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return ret;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic int txgbe_pma_init_done(struct dw_xpcs *xpcs)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	int val, ret;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_VR_RST | DW_EN_VSMMD1);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	/* wait pma initialization done */
14962306a36Sopenharmony_ci	ret = read_poll_timeout(xpcs_read_vpcs, val, !(val & DW_VR_RST),
15062306a36Sopenharmony_ci				100000, 10000000, false,
15162306a36Sopenharmony_ci				xpcs, DW_VR_XS_PCS_DIG_CTRL1);
15262306a36Sopenharmony_ci	if (ret < 0)
15362306a36Sopenharmony_ci		dev_err(&xpcs->mdiodev->dev, "xpcs pma initialization timeout\n");
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	return ret;
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic bool txgbe_xpcs_mode_quirk(struct dw_xpcs *xpcs)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	int ret;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	/* When txgbe do LAN reset, PCS will change to default 10GBASE-R mode */
16362306a36Sopenharmony_ci	ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_CTRL2);
16462306a36Sopenharmony_ci	ret &= MDIO_PCS_CTRL2_TYPE;
16562306a36Sopenharmony_ci	if ((ret == MDIO_PCS_CTRL2_10GBR &&
16662306a36Sopenharmony_ci	     xpcs->interface != PHY_INTERFACE_MODE_10GBASER) ||
16762306a36Sopenharmony_ci	    xpcs->interface == PHY_INTERFACE_MODE_SGMII)
16862306a36Sopenharmony_ci		return true;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	return false;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ciint txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	int val, ret;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	switch (interface) {
17862306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_10GBASER:
17962306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_SGMII:
18062306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_1000BASEX:
18162306a36Sopenharmony_ci		break;
18262306a36Sopenharmony_ci	default:
18362306a36Sopenharmony_ci		return 0;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (xpcs->interface == interface && !txgbe_xpcs_mode_quirk(xpcs))
18762306a36Sopenharmony_ci		return 0;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	xpcs->interface = interface;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	ret = txgbe_pcs_poll_power_up(xpcs);
19262306a36Sopenharmony_ci	if (ret < 0)
19362306a36Sopenharmony_ci		return ret;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	if (interface == PHY_INTERFACE_MODE_10GBASER) {
19662306a36Sopenharmony_ci		xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBR);
19762306a36Sopenharmony_ci		val = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1);
19862306a36Sopenharmony_ci		val |= MDIO_CTRL1_SPEED10G;
19962306a36Sopenharmony_ci		xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, val);
20062306a36Sopenharmony_ci		txgbe_pma_config_10gbaser(xpcs);
20162306a36Sopenharmony_ci	} else {
20262306a36Sopenharmony_ci		xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBX);
20362306a36Sopenharmony_ci		xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, 0);
20462306a36Sopenharmony_ci		xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL1, 0);
20562306a36Sopenharmony_ci		txgbe_pma_config_1g(xpcs);
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	return txgbe_pma_init_done(xpcs);
20962306a36Sopenharmony_ci}
210