net/ngbe: setup PHY link
[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_setup_phy_link_mvl(struct ngbe_hw *hw, u32 speed,
52                                 bool autoneg_wait_to_complete)
53 {
54         u16 value_r4 = 0;
55         u16 value_r9 = 0;
56         u16 value;
57
58         DEBUGFUNC("ngbe_setup_phy_link_mvl");
59         UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
60
61         hw->phy.autoneg_advertised = 0;
62
63         if (hw->phy.type == ngbe_phy_mvl) {
64                 if (speed & NGBE_LINK_SPEED_1GB_FULL) {
65                         value_r9 |= MVL_PHY_1000BASET_FULL;
66                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
67                 }
68
69                 if (speed & NGBE_LINK_SPEED_100M_FULL) {
70                         value_r4 |= MVL_PHY_100BASET_FULL;
71                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL;
72                 }
73
74                 if (speed & NGBE_LINK_SPEED_10M_FULL) {
75                         value_r4 |= MVL_PHY_10BASET_FULL;
76                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL;
77                 }
78
79                 hw->phy.read_reg(hw, MVL_ANA, 0, &value);
80                 value &= ~(MVL_PHY_100BASET_FULL |
81                            MVL_PHY_100BASET_HALF |
82                            MVL_PHY_10BASET_FULL |
83                            MVL_PHY_10BASET_HALF);
84                 value_r4 |= value;
85                 hw->phy.write_reg(hw, MVL_ANA, 0, value_r4);
86
87                 hw->phy.read_reg(hw, MVL_PHY_1000BASET, 0, &value);
88                 value &= ~(MVL_PHY_1000BASET_FULL |
89                            MVL_PHY_1000BASET_HALF);
90                 value_r9 |= value;
91                 hw->phy.write_reg(hw, MVL_PHY_1000BASET, 0, value_r9);
92         } else {
93                 hw->phy.autoneg_advertised = 1;
94
95                 hw->phy.read_reg(hw, MVL_ANA, 0, &value);
96                 value &= ~(MVL_PHY_1000BASEX_HALF | MVL_PHY_1000BASEX_FULL);
97                 value |= MVL_PHY_1000BASEX_FULL;
98                 hw->phy.write_reg(hw, MVL_ANA, 0, value);
99         }
100
101         value = MVL_CTRL_RESTART_AN | MVL_CTRL_ANE;
102         ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
103
104         hw->phy.read_reg(hw, MVL_INTR, 0, &value);
105
106         return 0;
107 }
108
109 s32 ngbe_reset_phy_mvl(struct ngbe_hw *hw)
110 {
111         u32 i;
112         u16 ctrl = 0;
113         s32 status = 0;
114
115         DEBUGFUNC("ngbe_reset_phy_mvl");
116
117         if (hw->phy.type != ngbe_phy_mvl && hw->phy.type != ngbe_phy_mvl_sfi)
118                 return NGBE_ERR_PHY_TYPE;
119
120         /* select page 18 reg 20 */
121         status = ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 18);
122
123         /* mode select to RGMII-to-copper or RGMII-to-sfi*/
124         if (hw->phy.type == ngbe_phy_mvl)
125                 ctrl = MVL_GEN_CTL_MODE_COPPER;
126         else
127                 ctrl = MVL_GEN_CTL_MODE_FIBER;
128         status = ngbe_write_phy_reg_mdi(hw, MVL_GEN_CTL, 0, ctrl);
129         /* mode reset */
130         ctrl |= MVL_GEN_CTL_RESET;
131         status = ngbe_write_phy_reg_mdi(hw, MVL_GEN_CTL, 0, ctrl);
132
133         for (i = 0; i < MVL_PHY_RST_WAIT_PERIOD; i++) {
134                 status = ngbe_read_phy_reg_mdi(hw, MVL_GEN_CTL, 0, &ctrl);
135                 if (!(ctrl & MVL_GEN_CTL_RESET))
136                         break;
137                 msleep(1);
138         }
139
140         if (i == MVL_PHY_RST_WAIT_PERIOD) {
141                 DEBUGOUT("PHY reset polling failed to complete.\n");
142                 return NGBE_ERR_RESET_FAILED;
143         }
144
145         return status;
146 }
147
148 s32 ngbe_check_phy_link_mvl(struct ngbe_hw *hw,
149                 u32 *speed, bool *link_up)
150 {
151         s32 status = 0;
152         u16 phy_link = 0;
153         u16 phy_speed = 0;
154         u16 phy_data = 0;
155         u16 insr = 0;
156
157         DEBUGFUNC("ngbe_check_phy_link_mvl");
158
159         /* Initialize speed and link to default case */
160         *link_up = false;
161         *speed = NGBE_LINK_SPEED_UNKNOWN;
162
163         hw->phy.read_reg(hw, MVL_INTR, 0, &insr);
164
165         /*
166          * Check current speed and link status of the PHY register.
167          * This is a vendor specific register and may have to
168          * be changed for other copper PHYs.
169          */
170         status = hw->phy.read_reg(hw, MVL_PHYSR, 0, &phy_data);
171         phy_link = phy_data & MVL_PHYSR_LINK;
172         phy_speed = phy_data & MVL_PHYSR_SPEED_MASK;
173
174         if (phy_link == MVL_PHYSR_LINK) {
175                 *link_up = true;
176
177                 if (phy_speed == MVL_PHYSR_SPEED_1000M)
178                         *speed = NGBE_LINK_SPEED_1GB_FULL;
179                 else if (phy_speed == MVL_PHYSR_SPEED_100M)
180                         *speed = NGBE_LINK_SPEED_100M_FULL;
181                 else if (phy_speed == MVL_PHYSR_SPEED_10M)
182                         *speed = NGBE_LINK_SPEED_10M_FULL;
183         }
184
185         return status;
186 }
187