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_check_phy_mode_mvl(struct ngbe_hw *hw)
55 /* select page 18 reg 20 */
56 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 18);
57 ngbe_read_phy_reg_mdi(hw, MVL_GEN_CTL, 0, &value);
58 if (MVL_GEN_CTL_MODE(value) == MVL_GEN_CTL_MODE_COPPER) {
59 /* mode select to RGMII-to-copper */
60 hw->phy.type = ngbe_phy_mvl;
61 hw->phy.media_type = ngbe_media_type_copper;
62 hw->mac.link_type = ngbe_link_copper;
63 } else if (MVL_GEN_CTL_MODE(value) == MVL_GEN_CTL_MODE_FIBER) {
64 /* mode select to RGMII-to-sfi */
65 hw->phy.type = ngbe_phy_mvl_sfi;
66 hw->phy.media_type = ngbe_media_type_fiber;
67 hw->mac.link_type = ngbe_link_fiber;
69 DEBUGOUT("marvell 88E1512 mode %x is not supported.\n", value);
70 return NGBE_ERR_DEVICE_NOT_SUPPORTED;
76 s32 ngbe_init_phy_mvl(struct ngbe_hw *hw)
82 DEBUGFUNC("ngbe_init_phy_mvl");
84 /* enable interrupts, only link status change and an done is allowed */
85 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 2);
86 ngbe_read_phy_reg_mdi(hw, MVL_RGM_CTL2, 0, &value);
87 value &= ~MVL_RGM_CTL2_TTC;
88 value |= MVL_RGM_CTL2_RTC;
89 ngbe_write_phy_reg_mdi(hw, MVL_RGM_CTL2, 0, value);
91 hw->phy.write_reg(hw, MVL_CTRL, 0, MVL_CTRL_RESET);
92 for (i = 0; i < 15; i++) {
93 ngbe_read_phy_reg_mdi(hw, MVL_CTRL, 0, &value);
94 if (value & MVL_CTRL_RESET)
101 DEBUGOUT("phy reset exceeds maximum waiting period.\n");
102 return NGBE_ERR_TIMEOUT;
105 ret_val = hw->phy.reset_hw(hw);
109 /* set LED2 to interrupt output and INTn active low */
110 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 3);
111 ngbe_read_phy_reg_mdi(hw, MVL_LEDTCR, 0, &value);
112 value |= MVL_LEDTCR_INTR_EN;
113 value &= ~(MVL_LEDTCR_INTR_POL);
114 ngbe_write_phy_reg_mdi(hw, MVL_LEDTCR, 0, value);
116 if (hw->phy.type == ngbe_phy_mvl_sfi) {
117 hw->phy.read_reg(hw, MVL_CTRL1, 0, &value);
118 value &= ~MVL_CTRL1_INTR_POL;
119 ngbe_write_phy_reg_mdi(hw, MVL_CTRL1, 0, value);
122 /* enable link status change and AN complete interrupts */
123 value = MVL_INTR_EN_ANC | MVL_INTR_EN_LSC;
124 hw->phy.write_reg(hw, MVL_INTR_EN, 0, value);
126 ngbe_read_phy_reg_mdi(hw, MVL_CTRL, 0, &value);
127 value |= MVL_CTRL_PWDN;
128 ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
133 s32 ngbe_setup_phy_link_mvl(struct ngbe_hw *hw, u32 speed,
134 bool autoneg_wait_to_complete)
140 DEBUGFUNC("ngbe_setup_phy_link_mvl");
141 UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
143 if (hw->led_conf == 0xFFFF) {
145 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 3);
146 ngbe_read_phy_reg_mdi(hw, MVL_LEDFCR, 0, &value);
147 value &= ~(MVL_LEDFCR_CTL0 | MVL_LEDFCR_CTL1);
148 value |= MVL_LEDFCR_CTL0_CONF | MVL_LEDFCR_CTL1_CONF;
149 ngbe_write_phy_reg_mdi(hw, MVL_LEDFCR, 0, value);
150 ngbe_read_phy_reg_mdi(hw, MVL_LEDPCR, 0, &value);
151 value &= ~(MVL_LEDPCR_CTL0 | MVL_LEDPCR_CTL1);
152 value |= MVL_LEDPCR_CTL0_CONF | MVL_LEDPCR_CTL1_CONF;
153 ngbe_write_phy_reg_mdi(hw, MVL_LEDPCR, 0, value);
156 hw->phy.autoneg_advertised = 0;
158 if (hw->phy.type == ngbe_phy_mvl) {
159 if (!hw->mac.autoneg) {
161 case NGBE_LINK_SPEED_1GB_FULL:
162 value = MVL_CTRL_SPEED_SELECT1;
164 case NGBE_LINK_SPEED_100M_FULL:
165 value = MVL_CTRL_SPEED_SELECT0;
167 case NGBE_LINK_SPEED_10M_FULL:
171 value = MVL_CTRL_SPEED_SELECT0 |
172 MVL_CTRL_SPEED_SELECT1;
173 DEBUGOUT("unknown speed = 0x%x.\n", speed);
177 value |= MVL_CTRL_DUPLEX | MVL_CTRL_RESET;
178 ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
182 if (speed & NGBE_LINK_SPEED_1GB_FULL) {
183 value_r9 |= MVL_PHY_1000BASET_FULL;
184 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
187 if (speed & NGBE_LINK_SPEED_100M_FULL) {
188 value_r4 |= MVL_PHY_100BASET_FULL;
189 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL;
192 if (speed & NGBE_LINK_SPEED_10M_FULL) {
193 value_r4 |= MVL_PHY_10BASET_FULL;
194 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL;
197 hw->phy.read_reg(hw, MVL_ANA, 0, &value);
198 value &= ~(MVL_PHY_100BASET_FULL |
199 MVL_PHY_100BASET_HALF |
200 MVL_PHY_10BASET_FULL |
201 MVL_PHY_10BASET_HALF);
203 hw->phy.write_reg(hw, MVL_ANA, 0, value_r4);
205 hw->phy.read_reg(hw, MVL_PHY_1000BASET, 0, &value);
206 value &= ~(MVL_PHY_1000BASET_FULL |
207 MVL_PHY_1000BASET_HALF);
209 hw->phy.write_reg(hw, MVL_PHY_1000BASET, 0, value_r9);
211 hw->phy.autoneg_advertised = 1;
213 hw->phy.read_reg(hw, MVL_ANA, 0, &value);
214 value &= ~(MVL_PHY_1000BASEX_HALF | MVL_PHY_1000BASEX_FULL);
215 value |= MVL_PHY_1000BASEX_FULL;
216 hw->phy.write_reg(hw, MVL_ANA, 0, value);
219 value = MVL_CTRL_RESTART_AN | MVL_CTRL_ANE | MVL_CTRL_RESET;
220 ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
223 ngbe_read_phy_reg_mdi(hw, MVL_CTRL, 0, &value);
224 value |= MVL_CTRL_PWDN;
225 ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
227 hw->phy.read_reg(hw, MVL_INTR, 0, &value);
232 s32 ngbe_reset_phy_mvl(struct ngbe_hw *hw)
238 DEBUGFUNC("ngbe_reset_phy_mvl");
240 if (hw->phy.type != ngbe_phy_mvl && hw->phy.type != ngbe_phy_mvl_sfi)
241 return NGBE_ERR_PHY_TYPE;
243 /* select page 18 reg 20 */
244 status = ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 18);
246 /* mode select to RGMII-to-copper or RGMII-to-sfi*/
247 if (hw->phy.type == ngbe_phy_mvl)
248 ctrl = MVL_GEN_CTL_MODE_COPPER;
250 ctrl = MVL_GEN_CTL_MODE_FIBER;
251 status = ngbe_write_phy_reg_mdi(hw, MVL_GEN_CTL, 0, ctrl);
253 ctrl |= MVL_GEN_CTL_RESET;
254 status = ngbe_write_phy_reg_mdi(hw, MVL_GEN_CTL, 0, ctrl);
256 for (i = 0; i < MVL_PHY_RST_WAIT_PERIOD; i++) {
257 status = ngbe_read_phy_reg_mdi(hw, MVL_GEN_CTL, 0, &ctrl);
258 if (!(ctrl & MVL_GEN_CTL_RESET))
263 if (i == MVL_PHY_RST_WAIT_PERIOD) {
264 DEBUGOUT("PHY reset polling failed to complete.\n");
265 return NGBE_ERR_RESET_FAILED;
271 s32 ngbe_get_phy_advertised_pause_mvl(struct ngbe_hw *hw, u8 *pause_bit)
276 if (hw->phy.type == ngbe_phy_mvl) {
277 status = hw->phy.read_reg(hw, MVL_ANA, 0, &value);
278 value &= MVL_CANA_ASM_PAUSE | MVL_CANA_PAUSE;
279 *pause_bit = (u8)(value >> 10);
281 status = hw->phy.read_reg(hw, MVL_ANA, 0, &value);
282 value &= MVL_FANA_PAUSE_MASK;
283 *pause_bit = (u8)(value >> 7);
289 s32 ngbe_get_phy_lp_advertised_pause_mvl(struct ngbe_hw *hw, u8 *pause_bit)
294 if (hw->phy.type == ngbe_phy_mvl) {
295 status = hw->phy.read_reg(hw, MVL_LPAR, 0, &value);
296 value &= MVL_CLPAR_ASM_PAUSE | MVL_CLPAR_PAUSE;
297 *pause_bit = (u8)(value >> 10);
299 status = hw->phy.read_reg(hw, MVL_LPAR, 0, &value);
300 value &= MVL_FLPAR_PAUSE_MASK;
301 *pause_bit = (u8)(value >> 7);
307 s32 ngbe_set_phy_pause_adv_mvl(struct ngbe_hw *hw, u16 pause_bit)
312 DEBUGFUNC("ngbe_set_phy_pause_adv_mvl");
314 if (hw->phy.type == ngbe_phy_mvl) {
315 status = hw->phy.read_reg(hw, MVL_ANA, 0, &value);
316 value &= ~(MVL_CANA_ASM_PAUSE | MVL_CANA_PAUSE);
318 status = hw->phy.read_reg(hw, MVL_ANA, 0, &value);
319 value &= ~MVL_FANA_PAUSE_MASK;
323 status = hw->phy.write_reg(hw, MVL_ANA, 0, value);
328 s32 ngbe_check_phy_link_mvl(struct ngbe_hw *hw,
329 u32 *speed, bool *link_up)
337 DEBUGFUNC("ngbe_check_phy_link_mvl");
339 /* Initialize speed and link to default case */
341 *speed = NGBE_LINK_SPEED_UNKNOWN;
343 hw->phy.read_reg(hw, MVL_INTR, 0, &insr);
346 * Check current speed and link status of the PHY register.
347 * This is a vendor specific register and may have to
348 * be changed for other copper PHYs.
350 status = hw->phy.read_reg(hw, MVL_PHYSR, 0, &phy_data);
351 phy_link = phy_data & MVL_PHYSR_LINK;
352 phy_speed = phy_data & MVL_PHYSR_SPEED_MASK;
354 if (phy_link == MVL_PHYSR_LINK) {
357 if (phy_speed == MVL_PHYSR_SPEED_1000M)
358 *speed = NGBE_LINK_SPEED_1GB_FULL;
359 else if (phy_speed == MVL_PHYSR_SPEED_100M)
360 *speed = NGBE_LINK_SPEED_100M_FULL;
361 else if (phy_speed == MVL_PHYSR_SPEED_10M)
362 *speed = NGBE_LINK_SPEED_10M_FULL;