Commit | Line | Data |
---|---|---|
f629acc6 JW |
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 | ||
49 | static 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 | ||
54 | static 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 | ||
59 | static 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 | ||
93 | static 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 | ||
127 | static 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 | ||
142 | static 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 | ||
158 | static 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; | |
2a22b7ae JW |
165 | if ((ret == MDIO_PCS_CTRL2_10GBR && |
166 | xpcs->interface != PHY_INTERFACE_MODE_10GBASER) || | |
167 | xpcs->interface == PHY_INTERFACE_MODE_SGMII) | |
f629acc6 JW |
168 | return true; |
169 | ||
170 | return false; | |
171 | } | |
172 | ||
173 | int 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 | } |