xref: /openbmc/linux/drivers/net/pcs/pcs-xpcs-wx.c (revision f629acc6)
1*f629acc6SJiawen Wu // SPDX-License-Identifier: GPL-2.0
2*f629acc6SJiawen Wu /* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */
3*f629acc6SJiawen Wu 
4*f629acc6SJiawen Wu #include <linux/pcs/pcs-xpcs.h>
5*f629acc6SJiawen Wu #include <linux/mdio.h>
6*f629acc6SJiawen Wu #include "pcs-xpcs.h"
7*f629acc6SJiawen Wu 
8*f629acc6SJiawen Wu /* VR_XS_PMA_MMD */
9*f629acc6SJiawen Wu #define TXGBE_PMA_MMD			0x8020
10*f629acc6SJiawen Wu #define TXGBE_TX_GENCTL1		0x11
11*f629acc6SJiawen Wu #define TXGBE_TX_GENCTL1_VBOOST_LVL	GENMASK(10, 8)
12*f629acc6SJiawen Wu #define TXGBE_TX_GENCTL1_VBOOST_EN0	BIT(4)
13*f629acc6SJiawen Wu #define TXGBE_TX_GEN_CTL2		0x12
14*f629acc6SJiawen Wu #define TXGBE_TX_GEN_CTL2_TX0_WIDTH(v)	FIELD_PREP(GENMASK(9, 8), v)
15*f629acc6SJiawen Wu #define TXGBE_TX_RATE_CTL		0x14
16*f629acc6SJiawen Wu #define TXGBE_TX_RATE_CTL_TX0_RATE(v)	FIELD_PREP(GENMASK(2, 0), v)
17*f629acc6SJiawen Wu #define TXGBE_RX_GEN_CTL2		0x32
18*f629acc6SJiawen Wu #define TXGBE_RX_GEN_CTL2_RX0_WIDTH(v)	FIELD_PREP(GENMASK(9, 8), v)
19*f629acc6SJiawen Wu #define TXGBE_RX_GEN_CTL3		0x33
20*f629acc6SJiawen Wu #define TXGBE_RX_GEN_CTL3_LOS_TRSHLD0	GENMASK(2, 0)
21*f629acc6SJiawen Wu #define TXGBE_RX_RATE_CTL		0x34
22*f629acc6SJiawen Wu #define TXGBE_RX_RATE_CTL_RX0_RATE(v)	FIELD_PREP(GENMASK(1, 0), v)
23*f629acc6SJiawen Wu #define TXGBE_RX_EQ_ATTN_CTL		0x37
24*f629acc6SJiawen Wu #define TXGBE_RX_EQ_ATTN_LVL0		GENMASK(2, 0)
25*f629acc6SJiawen Wu #define TXGBE_RX_EQ_CTL0		0x38
26*f629acc6SJiawen Wu #define TXGBE_RX_EQ_CTL0_VGA1_GAIN(v)	FIELD_PREP(GENMASK(15, 12), v)
27*f629acc6SJiawen Wu #define TXGBE_RX_EQ_CTL0_VGA2_GAIN(v)	FIELD_PREP(GENMASK(11, 8), v)
28*f629acc6SJiawen Wu #define TXGBE_RX_EQ_CTL0_CTLE_POLE(v)	FIELD_PREP(GENMASK(7, 5), v)
29*f629acc6SJiawen Wu #define TXGBE_RX_EQ_CTL0_CTLE_BOOST(v)	FIELD_PREP(GENMASK(4, 0), v)
30*f629acc6SJiawen Wu #define TXGBE_RX_EQ_CTL4		0x3C
31*f629acc6SJiawen Wu #define TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0	BIT(4)
32*f629acc6SJiawen Wu #define TXGBE_RX_EQ_CTL4_CONT_ADAPT0	BIT(0)
33*f629acc6SJiawen Wu #define TXGBE_AFE_DFE_ENABLE		0x3D
34*f629acc6SJiawen Wu #define TXGBE_DFE_EN_0			BIT(4)
35*f629acc6SJiawen Wu #define TXGBE_AFE_EN_0			BIT(0)
36*f629acc6SJiawen Wu #define TXGBE_DFE_TAP_CTL0		0x3E
37*f629acc6SJiawen Wu #define TXGBE_MPLLA_CTL0		0x51
38*f629acc6SJiawen Wu #define TXGBE_MPLLA_CTL2		0x53
39*f629acc6SJiawen Wu #define TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN	BIT(10)
40*f629acc6SJiawen Wu #define TXGBE_MPLLA_CTL2_DIV10_CLK_EN	BIT(9)
41*f629acc6SJiawen Wu #define TXGBE_MPLLA_CTL3		0x57
42*f629acc6SJiawen Wu #define TXGBE_MISC_CTL0			0x70
43*f629acc6SJiawen Wu #define TXGBE_MISC_CTL0_PLL		BIT(15)
44*f629acc6SJiawen Wu #define TXGBE_MISC_CTL0_CR_PARA_SEL	BIT(14)
45*f629acc6SJiawen Wu #define TXGBE_MISC_CTL0_RX_VREF(v)	FIELD_PREP(GENMASK(12, 8), v)
46*f629acc6SJiawen Wu #define TXGBE_VCO_CAL_LD0		0x72
47*f629acc6SJiawen Wu #define TXGBE_VCO_CAL_REF0		0x76
48*f629acc6SJiawen Wu 
49*f629acc6SJiawen Wu static int txgbe_read_pma(struct dw_xpcs *xpcs, int reg)
50*f629acc6SJiawen Wu {
51*f629acc6SJiawen Wu 	return xpcs_read(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg);
52*f629acc6SJiawen Wu }
53*f629acc6SJiawen Wu 
54*f629acc6SJiawen Wu static int txgbe_write_pma(struct dw_xpcs *xpcs, int reg, u16 val)
55*f629acc6SJiawen Wu {
56*f629acc6SJiawen Wu 	return xpcs_write(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg, val);
57*f629acc6SJiawen Wu }
58*f629acc6SJiawen Wu 
59*f629acc6SJiawen Wu static void txgbe_pma_config_10gbaser(struct dw_xpcs *xpcs)
60*f629acc6SJiawen Wu {
61*f629acc6SJiawen Wu 	int val;
62*f629acc6SJiawen Wu 
63*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x21);
64*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0);
65*f629acc6SJiawen Wu 	val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1);
66*f629acc6SJiawen Wu 	val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL);
67*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val);
68*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL |
69*f629acc6SJiawen Wu 			TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF));
70*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x549);
71*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x29);
72*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, 0);
73*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, 0);
74*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(3));
75*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(3));
76*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN |
77*f629acc6SJiawen Wu 			TXGBE_MPLLA_CTL2_DIV10_CLK_EN);
78*f629acc6SJiawen Wu 
79*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_CTLE_POLE(2) |
80*f629acc6SJiawen Wu 			TXGBE_RX_EQ_CTL0_CTLE_BOOST(5));
81*f629acc6SJiawen Wu 	val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL);
82*f629acc6SJiawen Wu 	val &= ~TXGBE_RX_EQ_ATTN_LVL0;
83*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
84*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0xBE);
85*f629acc6SJiawen Wu 	val = txgbe_read_pma(xpcs, TXGBE_AFE_DFE_ENABLE);
86*f629acc6SJiawen Wu 	val &= ~(TXGBE_DFE_EN_0 | TXGBE_AFE_EN_0);
87*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, val);
88*f629acc6SJiawen Wu 	val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_CTL4);
89*f629acc6SJiawen Wu 	val &= ~TXGBE_RX_EQ_CTL4_CONT_ADAPT0;
90*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, val);
91*f629acc6SJiawen Wu }
92*f629acc6SJiawen Wu 
93*f629acc6SJiawen Wu static void txgbe_pma_config_1g(struct dw_xpcs *xpcs)
94*f629acc6SJiawen Wu {
95*f629acc6SJiawen Wu 	int val;
96*f629acc6SJiawen Wu 
97*f629acc6SJiawen Wu 	val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1);
98*f629acc6SJiawen Wu 	val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL);
99*f629acc6SJiawen Wu 	val &= ~TXGBE_TX_GENCTL1_VBOOST_EN0;
100*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val);
101*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL |
102*f629acc6SJiawen Wu 			TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF));
103*f629acc6SJiawen Wu 
104*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_VGA1_GAIN(7) |
105*f629acc6SJiawen Wu 			TXGBE_RX_EQ_CTL0_VGA2_GAIN(7) | TXGBE_RX_EQ_CTL0_CTLE_BOOST(6));
106*f629acc6SJiawen Wu 	val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL);
107*f629acc6SJiawen Wu 	val &= ~TXGBE_RX_EQ_ATTN_LVL0;
108*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
109*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0);
110*f629acc6SJiawen Wu 	val = txgbe_read_pma(xpcs, TXGBE_RX_GEN_CTL3);
111*f629acc6SJiawen Wu 	val = u16_replace_bits(val, 0x4, TXGBE_RX_GEN_CTL3_LOS_TRSHLD0);
112*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
113*f629acc6SJiawen Wu 
114*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x20);
115*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0x46);
116*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x540);
117*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x2A);
118*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, 0);
119*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0);
120*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, TXGBE_TX_RATE_CTL_TX0_RATE(3));
121*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, TXGBE_RX_RATE_CTL_RX0_RATE(3));
122*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(1));
123*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(1));
124*f629acc6SJiawen Wu 	txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV10_CLK_EN);
125*f629acc6SJiawen Wu }
126*f629acc6SJiawen Wu 
127*f629acc6SJiawen Wu static int txgbe_pcs_poll_power_up(struct dw_xpcs *xpcs)
128*f629acc6SJiawen Wu {
129*f629acc6SJiawen Wu 	int val, ret;
130*f629acc6SJiawen Wu 
131*f629acc6SJiawen Wu 	/* Wait xpcs power-up good */
132*f629acc6SJiawen Wu 	ret = read_poll_timeout(xpcs_read_vpcs, val,
133*f629acc6SJiawen Wu 				(val & DW_PSEQ_ST) == DW_PSEQ_ST_GOOD,
134*f629acc6SJiawen Wu 				10000, 1000000, false,
135*f629acc6SJiawen Wu 				xpcs, DW_VR_XS_PCS_DIG_STS);
136*f629acc6SJiawen Wu 	if (ret < 0)
137*f629acc6SJiawen Wu 		dev_err(&xpcs->mdiodev->dev, "xpcs power-up timeout\n");
138*f629acc6SJiawen Wu 
139*f629acc6SJiawen Wu 	return ret;
140*f629acc6SJiawen Wu }
141*f629acc6SJiawen Wu 
142*f629acc6SJiawen Wu static int txgbe_pma_init_done(struct dw_xpcs *xpcs)
143*f629acc6SJiawen Wu {
144*f629acc6SJiawen Wu 	int val, ret;
145*f629acc6SJiawen Wu 
146*f629acc6SJiawen Wu 	xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_VR_RST | DW_EN_VSMMD1);
147*f629acc6SJiawen Wu 
148*f629acc6SJiawen Wu 	/* wait pma initialization done */
149*f629acc6SJiawen Wu 	ret = read_poll_timeout(xpcs_read_vpcs, val, !(val & DW_VR_RST),
150*f629acc6SJiawen Wu 				100000, 10000000, false,
151*f629acc6SJiawen Wu 				xpcs, DW_VR_XS_PCS_DIG_CTRL1);
152*f629acc6SJiawen Wu 	if (ret < 0)
153*f629acc6SJiawen Wu 		dev_err(&xpcs->mdiodev->dev, "xpcs pma initialization timeout\n");
154*f629acc6SJiawen Wu 
155*f629acc6SJiawen Wu 	return ret;
156*f629acc6SJiawen Wu }
157*f629acc6SJiawen Wu 
158*f629acc6SJiawen Wu static bool txgbe_xpcs_mode_quirk(struct dw_xpcs *xpcs)
159*f629acc6SJiawen Wu {
160*f629acc6SJiawen Wu 	int ret;
161*f629acc6SJiawen Wu 
162*f629acc6SJiawen Wu 	/* When txgbe do LAN reset, PCS will change to default 10GBASE-R mode */
163*f629acc6SJiawen Wu 	ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_CTRL2);
164*f629acc6SJiawen Wu 	ret &= MDIO_PCS_CTRL2_TYPE;
165*f629acc6SJiawen Wu 	if (ret == MDIO_PCS_CTRL2_10GBR &&
166*f629acc6SJiawen Wu 	    xpcs->interface != PHY_INTERFACE_MODE_10GBASER)
167*f629acc6SJiawen Wu 		return true;
168*f629acc6SJiawen Wu 
169*f629acc6SJiawen Wu 	return false;
170*f629acc6SJiawen Wu }
171*f629acc6SJiawen Wu 
172*f629acc6SJiawen Wu int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface)
173*f629acc6SJiawen Wu {
174*f629acc6SJiawen Wu 	int val, ret;
175*f629acc6SJiawen Wu 
176*f629acc6SJiawen Wu 	switch (interface) {
177*f629acc6SJiawen Wu 	case PHY_INTERFACE_MODE_10GBASER:
178*f629acc6SJiawen Wu 	case PHY_INTERFACE_MODE_SGMII:
179*f629acc6SJiawen Wu 	case PHY_INTERFACE_MODE_1000BASEX:
180*f629acc6SJiawen Wu 		break;
181*f629acc6SJiawen Wu 	default:
182*f629acc6SJiawen Wu 		return 0;
183*f629acc6SJiawen Wu 	}
184*f629acc6SJiawen Wu 
185*f629acc6SJiawen Wu 	if (xpcs->interface == interface && !txgbe_xpcs_mode_quirk(xpcs))
186*f629acc6SJiawen Wu 		return 0;
187*f629acc6SJiawen Wu 
188*f629acc6SJiawen Wu 	xpcs->interface = interface;
189*f629acc6SJiawen Wu 
190*f629acc6SJiawen Wu 	ret = txgbe_pcs_poll_power_up(xpcs);
191*f629acc6SJiawen Wu 	if (ret < 0)
192*f629acc6SJiawen Wu 		return ret;
193*f629acc6SJiawen Wu 
194*f629acc6SJiawen Wu 	if (interface == PHY_INTERFACE_MODE_10GBASER) {
195*f629acc6SJiawen Wu 		xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBR);
196*f629acc6SJiawen Wu 		val = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1);
197*f629acc6SJiawen Wu 		val |= MDIO_CTRL1_SPEED10G;
198*f629acc6SJiawen Wu 		xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, val);
199*f629acc6SJiawen Wu 		txgbe_pma_config_10gbaser(xpcs);
200*f629acc6SJiawen Wu 	} else {
201*f629acc6SJiawen Wu 		xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBX);
202*f629acc6SJiawen Wu 		xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, 0);
203*f629acc6SJiawen Wu 		xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL1, 0);
204*f629acc6SJiawen Wu 		txgbe_pma_config_1g(xpcs);
205*f629acc6SJiawen Wu 	}
206*f629acc6SJiawen Wu 
207*f629acc6SJiawen Wu 	return txgbe_pma_init_done(xpcs);
208*f629acc6SJiawen Wu }
209