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