net/ngbe: support SR-IOV
[dpdk.git] / drivers / net / ngbe / base / ngbe_phy_mvl.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd.
3  */
4
5 #include "ngbe_phy_mvl.h"
6
7 #define MVL_PHY_RST_WAIT_PERIOD  5
8
9 s32 ngbe_read_phy_reg_mvl(struct ngbe_hw *hw,
10                 u32 reg_addr, u32 device_type, u16 *phy_data)
11 {
12         mdi_reg_t reg;
13         mdi_reg_22_t reg22;
14
15         reg.device_type = device_type;
16         reg.addr = reg_addr;
17
18         if (hw->phy.media_type == ngbe_media_type_fiber)
19                 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 1);
20         else
21                 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 0);
22
23         ngbe_mdi_map_register(&reg, &reg22);
24
25         ngbe_read_phy_reg_mdi(hw, reg22.addr, reg22.device_type, phy_data);
26
27         return 0;
28 }
29
30 s32 ngbe_write_phy_reg_mvl(struct ngbe_hw *hw,
31                 u32 reg_addr, u32 device_type, u16 phy_data)
32 {
33         mdi_reg_t reg;
34         mdi_reg_22_t reg22;
35
36         reg.device_type = device_type;
37         reg.addr = reg_addr;
38
39         if (hw->phy.media_type == ngbe_media_type_fiber)
40                 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 1);
41         else
42                 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 0);
43
44         ngbe_mdi_map_register(&reg, &reg22);
45
46         ngbe_write_phy_reg_mdi(hw, reg22.addr, reg22.device_type, phy_data);
47
48         return 0;
49 }
50
51 s32 ngbe_init_phy_mvl(struct ngbe_hw *hw)
52 {
53         s32 ret_val = 0;
54         u16 value = 0;
55         int i;
56
57         DEBUGFUNC("ngbe_init_phy_mvl");
58
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);
65
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)
70                         msleep(1);
71                 else
72                         break;
73         }
74
75         if (i == 15) {
76                 DEBUGOUT("phy reset exceeds maximum waiting period.\n");
77                 return NGBE_ERR_TIMEOUT;
78         }
79
80         ret_val = hw->phy.reset_hw(hw);
81         if (ret_val)
82                 return ret_val;
83
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);
90
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);
95         }
96
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);
100
101         /* LED control */
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);
111
112         return ret_val;
113 }
114
115 s32 ngbe_setup_phy_link_mvl(struct ngbe_hw *hw, u32 speed,
116                                 bool autoneg_wait_to_complete)
117 {
118         u16 value_r4 = 0;
119         u16 value_r9 = 0;
120         u16 value;
121
122         DEBUGFUNC("ngbe_setup_phy_link_mvl");
123         UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
124
125         hw->phy.autoneg_advertised = 0;
126
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;
131                 }
132
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;
136                 }
137
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;
141                 }
142
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);
148                 value_r4 |= value;
149                 hw->phy.write_reg(hw, MVL_ANA, 0, value_r4);
150
151                 hw->phy.read_reg(hw, MVL_PHY_1000BASET, 0, &value);
152                 value &= ~(MVL_PHY_1000BASET_FULL |
153                            MVL_PHY_1000BASET_HALF);
154                 value_r9 |= value;
155                 hw->phy.write_reg(hw, MVL_PHY_1000BASET, 0, value_r9);
156         } else {
157                 hw->phy.autoneg_advertised = 1;
158
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);
163         }
164
165         value = MVL_CTRL_RESTART_AN | MVL_CTRL_ANE;
166         ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
167
168         hw->phy.read_reg(hw, MVL_INTR, 0, &value);
169
170         return 0;
171 }
172
173 s32 ngbe_reset_phy_mvl(struct ngbe_hw *hw)
174 {
175         u32 i;
176         u16 ctrl = 0;
177         s32 status = 0;
178
179         DEBUGFUNC("ngbe_reset_phy_mvl");
180
181         if (hw->phy.type != ngbe_phy_mvl && hw->phy.type != ngbe_phy_mvl_sfi)
182                 return NGBE_ERR_PHY_TYPE;
183
184         /* select page 18 reg 20 */
185         status = ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 18);
186
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;
190         else
191                 ctrl = MVL_GEN_CTL_MODE_FIBER;
192         status = ngbe_write_phy_reg_mdi(hw, MVL_GEN_CTL, 0, ctrl);
193         /* mode reset */
194         ctrl |= MVL_GEN_CTL_RESET;
195         status = ngbe_write_phy_reg_mdi(hw, MVL_GEN_CTL, 0, ctrl);
196
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))
200                         break;
201                 msleep(1);
202         }
203
204         if (i == MVL_PHY_RST_WAIT_PERIOD) {
205                 DEBUGOUT("PHY reset polling failed to complete.\n");
206                 return NGBE_ERR_RESET_FAILED;
207         }
208
209         return status;
210 }
211
212 s32 ngbe_check_phy_link_mvl(struct ngbe_hw *hw,
213                 u32 *speed, bool *link_up)
214 {
215         s32 status = 0;
216         u16 phy_link = 0;
217         u16 phy_speed = 0;
218         u16 phy_data = 0;
219         u16 insr = 0;
220
221         DEBUGFUNC("ngbe_check_phy_link_mvl");
222
223         /* Initialize speed and link to default case */
224         *link_up = false;
225         *speed = NGBE_LINK_SPEED_UNKNOWN;
226
227         hw->phy.read_reg(hw, MVL_INTR, 0, &insr);
228
229         /*
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.
233          */
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;
237
238         if (phy_link == MVL_PHYSR_LINK) {
239                 *link_up = true;
240
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;
247         }
248
249         return status;
250 }
251