1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd.
5 #include "ngbe_phy_mvl.h"
7 #define MVL_PHY_RST_WAIT_PERIOD 5
9 s32 ngbe_read_phy_reg_mvl(struct ngbe_hw *hw,
10 u32 reg_addr, u32 device_type, u16 *phy_data)
15 reg.device_type = device_type;
18 if (hw->phy.media_type == ngbe_media_type_fiber)
19 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 1);
21 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 0);
23 ngbe_mdi_map_register(®, ®22);
25 ngbe_read_phy_reg_mdi(hw, reg22.addr, reg22.device_type, phy_data);
30 s32 ngbe_write_phy_reg_mvl(struct ngbe_hw *hw,
31 u32 reg_addr, u32 device_type, u16 phy_data)
36 reg.device_type = device_type;
39 if (hw->phy.media_type == ngbe_media_type_fiber)
40 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 1);
42 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 0);
44 ngbe_mdi_map_register(®, ®22);
46 ngbe_write_phy_reg_mdi(hw, reg22.addr, reg22.device_type, phy_data);
51 s32 ngbe_init_phy_mvl(struct ngbe_hw *hw)
57 DEBUGFUNC("ngbe_init_phy_mvl");
59 /* enable interrupts, only link status change and an done is allowed */
60 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 2);
61 ngbe_read_phy_reg_mdi(hw, MVL_RGM_CTL2, 0, &value);
62 value &= ~MVL_RGM_CTL2_TTC;
63 value |= MVL_RGM_CTL2_RTC;
64 ngbe_write_phy_reg_mdi(hw, MVL_RGM_CTL2, 0, value);
66 hw->phy.write_reg(hw, MVL_CTRL, 0, MVL_CTRL_RESET);
67 for (i = 0; i < 15; i++) {
68 ngbe_read_phy_reg_mdi(hw, MVL_CTRL, 0, &value);
69 if (value & MVL_CTRL_RESET)
76 DEBUGOUT("phy reset exceeds maximum waiting period.\n");
77 return NGBE_ERR_TIMEOUT;
80 ret_val = hw->phy.reset_hw(hw);
84 /* set LED2 to interrupt output and INTn active low */
85 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 3);
86 ngbe_read_phy_reg_mdi(hw, MVL_LEDTCR, 0, &value);
87 value |= MVL_LEDTCR_INTR_EN;
88 value &= ~(MVL_LEDTCR_INTR_POL);
89 ngbe_write_phy_reg_mdi(hw, MVL_LEDTCR, 0, value);
91 if (hw->phy.type == ngbe_phy_mvl_sfi) {
92 hw->phy.read_reg(hw, MVL_CTRL1, 0, &value);
93 value &= ~MVL_CTRL1_INTR_POL;
94 ngbe_write_phy_reg_mdi(hw, MVL_CTRL1, 0, value);
97 /* enable link status change and AN complete interrupts */
98 value = MVL_INTR_EN_ANC | MVL_INTR_EN_LSC;
99 hw->phy.write_reg(hw, MVL_INTR_EN, 0, value);
102 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 3);
103 ngbe_read_phy_reg_mdi(hw, MVL_LEDFCR, 0, &value);
104 value &= ~(MVL_LEDFCR_CTL0 | MVL_LEDFCR_CTL1);
105 value |= MVL_LEDFCR_CTL0_CONF | MVL_LEDFCR_CTL1_CONF;
106 ngbe_write_phy_reg_mdi(hw, MVL_LEDFCR, 0, value);
107 ngbe_read_phy_reg_mdi(hw, MVL_LEDPCR, 0, &value);
108 value &= ~(MVL_LEDPCR_CTL0 | MVL_LEDPCR_CTL1);
109 value |= MVL_LEDPCR_CTL0_CONF | MVL_LEDPCR_CTL1_CONF;
110 ngbe_write_phy_reg_mdi(hw, MVL_LEDPCR, 0, value);
115 s32 ngbe_setup_phy_link_mvl(struct ngbe_hw *hw, u32 speed,
116 bool autoneg_wait_to_complete)
122 DEBUGFUNC("ngbe_setup_phy_link_mvl");
123 UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
125 hw->phy.autoneg_advertised = 0;
127 if (hw->phy.type == ngbe_phy_mvl) {
128 if (speed & NGBE_LINK_SPEED_1GB_FULL) {
129 value_r9 |= MVL_PHY_1000BASET_FULL;
130 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
133 if (speed & NGBE_LINK_SPEED_100M_FULL) {
134 value_r4 |= MVL_PHY_100BASET_FULL;
135 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL;
138 if (speed & NGBE_LINK_SPEED_10M_FULL) {
139 value_r4 |= MVL_PHY_10BASET_FULL;
140 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL;
143 hw->phy.read_reg(hw, MVL_ANA, 0, &value);
144 value &= ~(MVL_PHY_100BASET_FULL |
145 MVL_PHY_100BASET_HALF |
146 MVL_PHY_10BASET_FULL |
147 MVL_PHY_10BASET_HALF);
149 hw->phy.write_reg(hw, MVL_ANA, 0, value_r4);
151 hw->phy.read_reg(hw, MVL_PHY_1000BASET, 0, &value);
152 value &= ~(MVL_PHY_1000BASET_FULL |
153 MVL_PHY_1000BASET_HALF);
155 hw->phy.write_reg(hw, MVL_PHY_1000BASET, 0, value_r9);
157 hw->phy.autoneg_advertised = 1;
159 hw->phy.read_reg(hw, MVL_ANA, 0, &value);
160 value &= ~(MVL_PHY_1000BASEX_HALF | MVL_PHY_1000BASEX_FULL);
161 value |= MVL_PHY_1000BASEX_FULL;
162 hw->phy.write_reg(hw, MVL_ANA, 0, value);
165 value = MVL_CTRL_RESTART_AN | MVL_CTRL_ANE;
166 ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
168 hw->phy.read_reg(hw, MVL_INTR, 0, &value);
173 s32 ngbe_reset_phy_mvl(struct ngbe_hw *hw)
179 DEBUGFUNC("ngbe_reset_phy_mvl");
181 if (hw->phy.type != ngbe_phy_mvl && hw->phy.type != ngbe_phy_mvl_sfi)
182 return NGBE_ERR_PHY_TYPE;
184 /* select page 18 reg 20 */
185 status = ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 18);
187 /* mode select to RGMII-to-copper or RGMII-to-sfi*/
188 if (hw->phy.type == ngbe_phy_mvl)
189 ctrl = MVL_GEN_CTL_MODE_COPPER;
191 ctrl = MVL_GEN_CTL_MODE_FIBER;
192 status = ngbe_write_phy_reg_mdi(hw, MVL_GEN_CTL, 0, ctrl);
194 ctrl |= MVL_GEN_CTL_RESET;
195 status = ngbe_write_phy_reg_mdi(hw, MVL_GEN_CTL, 0, ctrl);
197 for (i = 0; i < MVL_PHY_RST_WAIT_PERIOD; i++) {
198 status = ngbe_read_phy_reg_mdi(hw, MVL_GEN_CTL, 0, &ctrl);
199 if (!(ctrl & MVL_GEN_CTL_RESET))
204 if (i == MVL_PHY_RST_WAIT_PERIOD) {
205 DEBUGOUT("PHY reset polling failed to complete.\n");
206 return NGBE_ERR_RESET_FAILED;
212 s32 ngbe_check_phy_link_mvl(struct ngbe_hw *hw,
213 u32 *speed, bool *link_up)
221 DEBUGFUNC("ngbe_check_phy_link_mvl");
223 /* Initialize speed and link to default case */
225 *speed = NGBE_LINK_SPEED_UNKNOWN;
227 hw->phy.read_reg(hw, MVL_INTR, 0, &insr);
230 * Check current speed and link status of the PHY register.
231 * This is a vendor specific register and may have to
232 * be changed for other copper PHYs.
234 status = hw->phy.read_reg(hw, MVL_PHYSR, 0, &phy_data);
235 phy_link = phy_data & MVL_PHYSR_LINK;
236 phy_speed = phy_data & MVL_PHYSR_SPEED_MASK;
238 if (phy_link == MVL_PHYSR_LINK) {
241 if (phy_speed == MVL_PHYSR_SPEED_1000M)
242 *speed = NGBE_LINK_SPEED_1GB_FULL;
243 else if (phy_speed == MVL_PHYSR_SPEED_100M)
244 *speed = NGBE_LINK_SPEED_100M_FULL;
245 else if (phy_speed == MVL_PHYSR_SPEED_10M)
246 *speed = NGBE_LINK_SPEED_10M_FULL;