1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd.
5 #include "ngbe_phy_rtl.h"
7 s32 ngbe_read_phy_reg_rtl(struct ngbe_hw *hw,
8 u32 reg_addr, u32 device_type, u16 *phy_data)
13 reg.device_type = device_type;
15 ngbe_mdi_map_register(®, ®22);
17 wr32(hw, NGBE_PHY_CONFIG(RTL_PAGE_SELECT), reg22.page);
18 *phy_data = 0xFFFF & rd32(hw, NGBE_PHY_CONFIG(reg22.addr));
23 s32 ngbe_write_phy_reg_rtl(struct ngbe_hw *hw,
24 u32 reg_addr, u32 device_type, u16 phy_data)
29 reg.device_type = device_type;
31 ngbe_mdi_map_register(®, ®22);
33 wr32(hw, NGBE_PHY_CONFIG(RTL_PAGE_SELECT), reg22.page);
34 wr32(hw, NGBE_PHY_CONFIG(reg22.addr), phy_data);
39 static void ngbe_phy_led_ctrl_rtl(struct ngbe_hw *hw)
43 if (hw->led_conf != 0xFFFF)
44 value = hw->led_conf & 0xFFFF;
48 hw->phy.write_reg(hw, RTL_LCR, 0xd04, value);
49 hw->phy.write_reg(hw, RTL_EEELCR, 0xd04, 0);
51 hw->phy.read_reg(hw, RTL_LPCR, 0xd04, &value);
52 if (hw->led_conf != 0xFFFF) {
54 value |= hw->led_conf >> 16;
57 /*act led blinking mode set to 60ms*/
60 hw->phy.write_reg(hw, RTL_LPCR, 0xd04, value);
63 s32 ngbe_init_phy_rtl(struct ngbe_hw *hw)
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);
72 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
74 for (i = 0; i < 15; i++) {
75 if (!rd32m(hw, NGBE_STAT,
76 NGBE_STAT_GPHY_IN_RST(hw->bus.lan_id)))
82 DEBUGOUT("GPhy reset exceeds maximum times.\n");
83 return NGBE_ERR_PHY_TIMEOUT;
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.\n");
90 return NGBE_ERR_PHY_TIMEOUT;
93 for (i = 0; i < 1000; i++) {
94 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
95 if (value & RTL_INSR_ACCESS)
100 DEBUGOUT("PHY wait mdio 1 access timeout.\n");
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.\n");
107 return NGBE_ERR_PHY_TIMEOUT;
110 for (i = 0; i < 1000; i++) {
111 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
112 if (value & RTL_INSR_ACCESS)
117 DEBUGOUT("PHY wait mdio 2 access timeout.\n");
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)
126 return NGBE_ERR_PHY_TIMEOUT;
132 * ngbe_setup_phy_link_rtl - Set and restart auto-neg
133 * @hw: pointer to hardware structure
135 * Restart auto-negotiation and PHY and waits for completion.
137 s32 ngbe_setup_phy_link_rtl(struct ngbe_hw *hw,
138 u32 speed, bool autoneg_wait_to_complete)
140 u16 autoneg_reg = NGBE_MII_AUTONEG_REG;
143 DEBUGFUNC("ngbe_setup_phy_link_rtl");
145 UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
147 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &autoneg_reg);
149 if (!hw->mac.autoneg) {
150 hw->phy.reset_hw(hw);
153 case NGBE_LINK_SPEED_1GB_FULL:
154 value = RTL_BMCR_SPEED_SELECT1;
156 case NGBE_LINK_SPEED_100M_FULL:
157 value = RTL_BMCR_SPEED_SELECT0;
159 case NGBE_LINK_SPEED_10M_FULL:
163 value = RTL_BMCR_SPEED_SELECT1 | RTL_BMCR_SPEED_SELECT0;
164 DEBUGOUT("unknown speed = 0x%x.\n", speed);
168 value |= RTL_BMCR_DUPLEX;
169 hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value);
175 * Clear autoneg_advertised and set new values based on input link
179 hw->phy.autoneg_advertised = 0;
181 if (speed & NGBE_LINK_SPEED_1GB_FULL)
182 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
184 if (speed & NGBE_LINK_SPEED_100M_FULL)
185 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL;
187 if (speed & NGBE_LINK_SPEED_10M_FULL)
188 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL;
191 /* disable 10/100M Half Duplex */
192 hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &autoneg_reg);
193 autoneg_reg &= 0xFF5F;
194 hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, autoneg_reg);
196 /* set advertise enable according to input speed */
197 if (!(speed & NGBE_LINK_SPEED_1GB_FULL)) {
198 hw->phy.read_reg(hw, RTL_GBCR,
199 RTL_DEV_ZERO, &autoneg_reg);
200 autoneg_reg &= ~RTL_GBCR_1000F;
201 hw->phy.write_reg(hw, RTL_GBCR,
202 RTL_DEV_ZERO, autoneg_reg);
204 hw->phy.read_reg(hw, RTL_GBCR,
205 RTL_DEV_ZERO, &autoneg_reg);
206 autoneg_reg |= RTL_GBCR_1000F;
207 hw->phy.write_reg(hw, RTL_GBCR,
208 RTL_DEV_ZERO, autoneg_reg);
211 if (!(speed & NGBE_LINK_SPEED_100M_FULL)) {
212 hw->phy.read_reg(hw, RTL_ANAR,
213 RTL_DEV_ZERO, &autoneg_reg);
214 autoneg_reg &= ~RTL_ANAR_100F;
215 autoneg_reg &= ~RTL_ANAR_100H;
216 hw->phy.write_reg(hw, RTL_ANAR,
217 RTL_DEV_ZERO, autoneg_reg);
219 hw->phy.read_reg(hw, RTL_ANAR,
220 RTL_DEV_ZERO, &autoneg_reg);
221 autoneg_reg |= RTL_ANAR_100F;
222 hw->phy.write_reg(hw, RTL_ANAR,
223 RTL_DEV_ZERO, autoneg_reg);
226 if (!(speed & NGBE_LINK_SPEED_10M_FULL)) {
227 hw->phy.read_reg(hw, RTL_ANAR,
228 RTL_DEV_ZERO, &autoneg_reg);
229 autoneg_reg &= ~RTL_ANAR_10F;
230 autoneg_reg &= ~RTL_ANAR_10H;
231 hw->phy.write_reg(hw, RTL_ANAR,
232 RTL_DEV_ZERO, autoneg_reg);
234 hw->phy.read_reg(hw, RTL_ANAR,
235 RTL_DEV_ZERO, &autoneg_reg);
236 autoneg_reg |= RTL_ANAR_10F;
237 hw->phy.write_reg(hw, RTL_ANAR,
238 RTL_DEV_ZERO, autoneg_reg);
241 /* restart AN and wait AN done interrupt */
242 autoneg_reg = RTL_BMCR_RESTART_AN | RTL_BMCR_ANE;
243 hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, autoneg_reg);
246 ngbe_phy_led_ctrl_rtl(hw);
251 s32 ngbe_reset_phy_rtl(struct ngbe_hw *hw)
256 DEBUGFUNC("ngbe_reset_phy_rtl");
258 value |= RTL_BMCR_RESET;
259 status = hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value);
266 s32 ngbe_get_phy_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit)
271 status = hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &value);
272 value &= RTL_ANAR_APAUSE | RTL_ANAR_PAUSE;
273 *pause_bit = (u8)(value >> 10);
277 s32 ngbe_get_phy_lp_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit)
282 status = hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
284 status = hw->phy.read_reg(hw, RTL_BMSR, RTL_DEV_ZERO, &value);
285 value = value & RTL_BMSR_ANC;
287 /* if AN complete then check lp adv pause */
288 status = hw->phy.read_reg(hw, RTL_ANLPAR, RTL_DEV_ZERO, &value);
289 value &= RTL_ANLPAR_LP;
290 *pause_bit = (u8)(value >> 10);
294 s32 ngbe_set_phy_pause_adv_rtl(struct ngbe_hw *hw, u16 pause_bit)
299 status = hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &value);
300 value &= ~(RTL_ANAR_APAUSE | RTL_ANAR_PAUSE);
303 status = hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, value);
308 s32 ngbe_check_phy_link_rtl(struct ngbe_hw *hw, u32 *speed, bool *link_up)
316 DEBUGFUNC("ngbe_check_phy_link_rtl");
318 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &insr);
320 /* Initialize speed and link to default case */
322 *speed = NGBE_LINK_SPEED_UNKNOWN;
325 * Check current speed and link status of the PHY register.
326 * This is a vendor specific register and may have to
327 * be changed for other copper PHYs.
329 status = hw->phy.read_reg(hw, RTL_PHYSR, 0xa43, &phy_data);
330 phy_link = phy_data & RTL_PHYSR_RTLS;
331 phy_speed = phy_data & (RTL_PHYSR_SPEED_MASK | RTL_PHYSR_DP);
332 if (phy_link == RTL_PHYSR_RTLS) {
335 if (phy_speed == (RTL_PHYSR_SPEED_1000M | RTL_PHYSR_DP))
336 *speed = NGBE_LINK_SPEED_1GB_FULL;
337 else if (phy_speed == (RTL_PHYSR_SPEED_100M | RTL_PHYSR_DP))
338 *speed = NGBE_LINK_SPEED_100M_FULL;
339 else if (phy_speed == (RTL_PHYSR_SPEED_10M | RTL_PHYSR_DP))
340 *speed = NGBE_LINK_SPEED_10M_FULL;