1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd.
3 */
4
5 #include "ngbe_phy_rtl.h"
6
ngbe_read_phy_reg_rtl(struct ngbe_hw * hw,u32 reg_addr,u32 device_type,u16 * phy_data)7 s32 ngbe_read_phy_reg_rtl(struct ngbe_hw *hw,
8 u32 reg_addr, u32 device_type, u16 *phy_data)
9 {
10 mdi_reg_t reg;
11 mdi_reg_22_t reg22;
12
13 reg.device_type = device_type;
14 reg.addr = reg_addr;
15 ngbe_mdi_map_register(®, ®22);
16
17 wr32(hw, NGBE_PHY_CONFIG(RTL_PAGE_SELECT), reg22.page);
18 *phy_data = 0xFFFF & rd32(hw, NGBE_PHY_CONFIG(reg22.addr));
19
20 return 0;
21 }
22
ngbe_write_phy_reg_rtl(struct ngbe_hw * hw,u32 reg_addr,u32 device_type,u16 phy_data)23 s32 ngbe_write_phy_reg_rtl(struct ngbe_hw *hw,
24 u32 reg_addr, u32 device_type, u16 phy_data)
25 {
26 mdi_reg_t reg;
27 mdi_reg_22_t reg22;
28
29 reg.device_type = device_type;
30 reg.addr = reg_addr;
31 ngbe_mdi_map_register(®, ®22);
32
33 wr32(hw, NGBE_PHY_CONFIG(RTL_PAGE_SELECT), reg22.page);
34 wr32(hw, NGBE_PHY_CONFIG(reg22.addr), phy_data);
35
36 return 0;
37 }
38
ngbe_phy_led_ctrl_rtl(struct ngbe_hw * hw)39 static void ngbe_phy_led_ctrl_rtl(struct ngbe_hw *hw)
40 {
41 u16 value = 0;
42
43 if (hw->led_conf != 0xFFFF)
44 value = hw->led_conf & 0xFFFF;
45 else
46 value = 0x205B;
47
48 hw->phy.write_reg(hw, RTL_LCR, 0xd04, value);
49 hw->phy.write_reg(hw, RTL_EEELCR, 0xd04, 0);
50
51 hw->phy.read_reg(hw, RTL_LPCR, 0xd04, &value);
52 if (hw->led_conf != 0xFFFF) {
53 value &= ~0x73;
54 value |= hw->led_conf >> 16;
55 } else {
56 value &= 0xFFFC;
57 /*act led blinking mode set to 60ms*/
58 value |= 0x2;
59 }
60 hw->phy.write_reg(hw, RTL_LPCR, 0xd04, value);
61 }
62
ngbe_init_phy_rtl(struct ngbe_hw * hw)63 s32 ngbe_init_phy_rtl(struct ngbe_hw *hw)
64 {
65 int i;
66 u16 value = 0;
67
68 /* enable interrupts, only link status change and an done is allowed */
69 value = RTL_INER_LSC | RTL_INER_ANC;
70 hw->phy.write_reg(hw, RTL_INER, 0xa42, value);
71
72 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
73
74 for (i = 0; i < 15; i++) {
75 if (!rd32m(hw, NGBE_STAT,
76 NGBE_STAT_GPHY_IN_RST(hw->bus.lan_id)))
77 break;
78
79 msec_delay(10);
80 }
81 if (i == 15) {
82 DEBUGOUT("GPhy reset exceeds maximum times.");
83 return NGBE_ERR_PHY_TIMEOUT;
84 }
85
86 hw->phy.write_reg(hw, RTL_SCR, 0xa46, RTL_SCR_EFUSE);
87 hw->phy.read_reg(hw, RTL_SCR, 0xa46, &value);
88 if (!(value & RTL_SCR_EFUSE)) {
89 DEBUGOUT("Write EFUSE failed.");
90 return NGBE_ERR_PHY_TIMEOUT;
91 }
92
93 for (i = 0; i < 1000; i++) {
94 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
95 if (value & RTL_INSR_ACCESS)
96 break;
97 msec_delay(1);
98 }
99 if (i == 1000)
100 DEBUGOUT("PHY wait mdio 1 access timeout.");
101
102
103 hw->phy.write_reg(hw, RTL_SCR, 0xa46, RTL_SCR_EXTINI);
104 hw->phy.read_reg(hw, RTL_SCR, 0xa46, &value);
105 if (!(value & RTL_SCR_EXTINI)) {
106 DEBUGOUT("Write EXIINI failed.");
107 return NGBE_ERR_PHY_TIMEOUT;
108 }
109
110 for (i = 0; i < 1000; i++) {
111 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
112 if (value & RTL_INSR_ACCESS)
113 break;
114 msec_delay(1);
115 }
116 if (i == 1000)
117 DEBUGOUT("PHY wait mdio 2 access timeout.");
118
119 for (i = 0; i < 1000; i++) {
120 hw->phy.read_reg(hw, RTL_GSR, 0xa42, &value);
121 if ((value & RTL_GSR_ST) == RTL_GSR_ST_LANON)
122 break;
123 msec_delay(1);
124 }
125 if (i == 1000)
126 return NGBE_ERR_PHY_TIMEOUT;
127
128 return 0;
129 }
130
131 /**
132 * ngbe_setup_phy_link_rtl - Set and restart auto-neg
133 * @hw: pointer to hardware structure
134 *
135 * Restart auto-negotiation and PHY and waits for completion.
136 **/
ngbe_setup_phy_link_rtl(struct ngbe_hw * hw,u32 speed,bool autoneg_wait_to_complete)137 s32 ngbe_setup_phy_link_rtl(struct ngbe_hw *hw,
138 u32 speed, bool autoneg_wait_to_complete)
139 {
140 u16 autoneg_reg = NGBE_MII_AUTONEG_REG;
141 u16 value = 0;
142
143 UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
144
145 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &autoneg_reg);
146
147 if (!hw->mac.autoneg) {
148 hw->phy.reset_hw(hw);
149
150 switch (speed) {
151 case NGBE_LINK_SPEED_1GB_FULL:
152 value = RTL_BMCR_SPEED_SELECT1;
153 break;
154 case NGBE_LINK_SPEED_100M_FULL:
155 value = RTL_BMCR_SPEED_SELECT0;
156 break;
157 case NGBE_LINK_SPEED_10M_FULL:
158 value = 0;
159 break;
160 default:
161 value = RTL_BMCR_SPEED_SELECT1 | RTL_BMCR_SPEED_SELECT0;
162 DEBUGOUT("unknown speed = 0x%x.", speed);
163 break;
164 }
165 /* duplex full */
166 value |= RTL_BMCR_DUPLEX;
167 hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value);
168
169 goto skip_an;
170 }
171
172 /*
173 * Clear autoneg_advertised and set new values based on input link
174 * speed.
175 */
176 if (speed) {
177 hw->phy.autoneg_advertised = 0;
178
179 if (speed & NGBE_LINK_SPEED_1GB_FULL)
180 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
181
182 if (speed & NGBE_LINK_SPEED_100M_FULL)
183 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL;
184
185 if (speed & NGBE_LINK_SPEED_10M_FULL)
186 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL;
187 }
188
189 /* disable 10/100M Half Duplex */
190 hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &autoneg_reg);
191 autoneg_reg &= 0xFF5F;
192 hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, autoneg_reg);
193
194 /* set advertise enable according to input speed */
195 if (!(speed & NGBE_LINK_SPEED_1GB_FULL)) {
196 hw->phy.read_reg(hw, RTL_GBCR,
197 RTL_DEV_ZERO, &autoneg_reg);
198 autoneg_reg &= ~RTL_GBCR_1000F;
199 hw->phy.write_reg(hw, RTL_GBCR,
200 RTL_DEV_ZERO, autoneg_reg);
201 } else {
202 hw->phy.read_reg(hw, RTL_GBCR,
203 RTL_DEV_ZERO, &autoneg_reg);
204 autoneg_reg |= RTL_GBCR_1000F;
205 hw->phy.write_reg(hw, RTL_GBCR,
206 RTL_DEV_ZERO, autoneg_reg);
207 }
208
209 if (!(speed & NGBE_LINK_SPEED_100M_FULL)) {
210 hw->phy.read_reg(hw, RTL_ANAR,
211 RTL_DEV_ZERO, &autoneg_reg);
212 autoneg_reg &= ~RTL_ANAR_100F;
213 autoneg_reg &= ~RTL_ANAR_100H;
214 hw->phy.write_reg(hw, RTL_ANAR,
215 RTL_DEV_ZERO, autoneg_reg);
216 } else {
217 hw->phy.read_reg(hw, RTL_ANAR,
218 RTL_DEV_ZERO, &autoneg_reg);
219 autoneg_reg |= RTL_ANAR_100F;
220 hw->phy.write_reg(hw, RTL_ANAR,
221 RTL_DEV_ZERO, autoneg_reg);
222 }
223
224 if (!(speed & NGBE_LINK_SPEED_10M_FULL)) {
225 hw->phy.read_reg(hw, RTL_ANAR,
226 RTL_DEV_ZERO, &autoneg_reg);
227 autoneg_reg &= ~RTL_ANAR_10F;
228 autoneg_reg &= ~RTL_ANAR_10H;
229 hw->phy.write_reg(hw, RTL_ANAR,
230 RTL_DEV_ZERO, autoneg_reg);
231 } else {
232 hw->phy.read_reg(hw, RTL_ANAR,
233 RTL_DEV_ZERO, &autoneg_reg);
234 autoneg_reg |= RTL_ANAR_10F;
235 hw->phy.write_reg(hw, RTL_ANAR,
236 RTL_DEV_ZERO, autoneg_reg);
237 }
238
239 /* restart AN and wait AN done interrupt */
240 autoneg_reg = RTL_BMCR_RESTART_AN | RTL_BMCR_ANE;
241 hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, autoneg_reg);
242
243 skip_an:
244 ngbe_phy_led_ctrl_rtl(hw);
245
246 return 0;
247 }
248
ngbe_reset_phy_rtl(struct ngbe_hw * hw)249 s32 ngbe_reset_phy_rtl(struct ngbe_hw *hw)
250 {
251 u16 value = 0;
252 s32 status = 0;
253
254 value |= RTL_BMCR_RESET;
255 status = hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value);
256
257 msec_delay(5);
258
259 return status;
260 }
261
ngbe_get_phy_advertised_pause_rtl(struct ngbe_hw * hw,u8 * pause_bit)262 s32 ngbe_get_phy_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit)
263 {
264 u16 value;
265 s32 status = 0;
266
267 status = hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &value);
268 value &= RTL_ANAR_APAUSE | RTL_ANAR_PAUSE;
269 *pause_bit = (u8)(value >> 10);
270 return status;
271 }
272
ngbe_get_phy_lp_advertised_pause_rtl(struct ngbe_hw * hw,u8 * pause_bit)273 s32 ngbe_get_phy_lp_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit)
274 {
275 u16 value;
276 s32 status = 0;
277
278 status = hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
279
280 status = hw->phy.read_reg(hw, RTL_BMSR, RTL_DEV_ZERO, &value);
281 value = value & RTL_BMSR_ANC;
282
283 /* if AN complete then check lp adv pause */
284 status = hw->phy.read_reg(hw, RTL_ANLPAR, RTL_DEV_ZERO, &value);
285 value &= RTL_ANLPAR_LP;
286 *pause_bit = (u8)(value >> 10);
287 return status;
288 }
289
ngbe_set_phy_pause_adv_rtl(struct ngbe_hw * hw,u16 pause_bit)290 s32 ngbe_set_phy_pause_adv_rtl(struct ngbe_hw *hw, u16 pause_bit)
291 {
292 u16 value;
293 s32 status = 0;
294
295 status = hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &value);
296 value &= ~(RTL_ANAR_APAUSE | RTL_ANAR_PAUSE);
297 value |= pause_bit;
298
299 status = hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, value);
300
301 return status;
302 }
303
ngbe_check_phy_link_rtl(struct ngbe_hw * hw,u32 * speed,bool * link_up)304 s32 ngbe_check_phy_link_rtl(struct ngbe_hw *hw, u32 *speed, bool *link_up)
305 {
306 s32 status = 0;
307 u16 phy_link = 0;
308 u16 phy_speed = 0;
309 u16 phy_data = 0;
310 u16 insr = 0;
311
312 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &insr);
313
314 /* Initialize speed and link to default case */
315 *link_up = false;
316 *speed = NGBE_LINK_SPEED_UNKNOWN;
317
318 /*
319 * Check current speed and link status of the PHY register.
320 * This is a vendor specific register and may have to
321 * be changed for other copper PHYs.
322 */
323 status = hw->phy.read_reg(hw, RTL_PHYSR, 0xa43, &phy_data);
324 phy_link = phy_data & RTL_PHYSR_RTLS;
325 phy_speed = phy_data & (RTL_PHYSR_SPEED_MASK | RTL_PHYSR_DP);
326 if (phy_link == RTL_PHYSR_RTLS) {
327 *link_up = true;
328
329 if (phy_speed == (RTL_PHYSR_SPEED_1000M | RTL_PHYSR_DP))
330 *speed = NGBE_LINK_SPEED_1GB_FULL;
331 else if (phy_speed == (RTL_PHYSR_SPEED_100M | RTL_PHYSR_DP))
332 *speed = NGBE_LINK_SPEED_100M_FULL;
333 else if (phy_speed == (RTL_PHYSR_SPEED_10M | RTL_PHYSR_DP))
334 *speed = NGBE_LINK_SPEED_10M_FULL;
335 }
336
337 return status;
338 }
339
340