a45b0f0a555c621ecb0f5191e05ceb383c5f097a
[dpdk.git] / drivers / net / ngbe / base / ngbe_phy_rtl.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd.
3  */
4
5 #include "ngbe_phy_rtl.h"
6
7 #define RTL_PHY_RST_WAIT_PERIOD               5
8
9 s32 ngbe_read_phy_reg_rtl(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         ngbe_mdi_map_register(&reg, &reg22);
18
19         wr32(hw, NGBE_PHY_CONFIG(RTL_PAGE_SELECT), reg22.page);
20         *phy_data = 0xFFFF & rd32(hw, NGBE_PHY_CONFIG(reg22.addr));
21
22         return 0;
23 }
24
25 s32 ngbe_write_phy_reg_rtl(struct ngbe_hw *hw,
26                 u32 reg_addr, u32 device_type, u16 phy_data)
27 {
28         mdi_reg_t reg;
29         mdi_reg_22_t reg22;
30
31         reg.device_type = device_type;
32         reg.addr = reg_addr;
33         ngbe_mdi_map_register(&reg, &reg22);
34
35         wr32(hw, NGBE_PHY_CONFIG(RTL_PAGE_SELECT), reg22.page);
36         wr32(hw, NGBE_PHY_CONFIG(reg22.addr), phy_data);
37
38         return 0;
39 }
40
41 /**
42  *  ngbe_setup_phy_link_rtl - Set and restart auto-neg
43  *  @hw: pointer to hardware structure
44  *
45  *  Restart auto-negotiation and PHY and waits for completion.
46  **/
47 s32 ngbe_setup_phy_link_rtl(struct ngbe_hw *hw,
48                 u32 speed, bool autoneg_wait_to_complete)
49 {
50         u16 autoneg_reg = NGBE_MII_AUTONEG_REG;
51         u16 value = 0;
52
53         DEBUGFUNC("ngbe_setup_phy_link_rtl");
54
55         UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
56
57         hw->phy.read_reg(hw, RTL_INSR, 0xa43, &autoneg_reg);
58
59         if (!hw->mac.autoneg) {
60                 hw->phy.reset_hw(hw);
61
62                 switch (speed) {
63                 case NGBE_LINK_SPEED_1GB_FULL:
64                         value = RTL_BMCR_SPEED_SELECT1;
65                         break;
66                 case NGBE_LINK_SPEED_100M_FULL:
67                         value = RTL_BMCR_SPEED_SELECT0;
68                         break;
69                 case NGBE_LINK_SPEED_10M_FULL:
70                         value = 0;
71                         break;
72                 default:
73                         value = RTL_BMCR_SPEED_SELECT1 | RTL_BMCR_SPEED_SELECT0;
74                         DEBUGOUT("unknown speed = 0x%x.\n", speed);
75                         break;
76                 }
77                 /* duplex full */
78                 value |= RTL_BMCR_DUPLEX;
79                 hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value);
80
81                 goto skip_an;
82         }
83
84         /*
85          * Clear autoneg_advertised and set new values based on input link
86          * speed.
87          */
88         if (speed) {
89                 hw->phy.autoneg_advertised = 0;
90
91                 if (speed & NGBE_LINK_SPEED_1GB_FULL)
92                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
93
94                 if (speed & NGBE_LINK_SPEED_100M_FULL)
95                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL;
96
97                 if (speed & NGBE_LINK_SPEED_10M_FULL)
98                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL;
99         }
100
101         /* disable 10/100M Half Duplex */
102         hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &autoneg_reg);
103         autoneg_reg &= 0xFF5F;
104         hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, autoneg_reg);
105
106         /* set advertise enable according to input speed */
107         if (!(speed & NGBE_LINK_SPEED_1GB_FULL)) {
108                 hw->phy.read_reg(hw, RTL_GBCR,
109                         RTL_DEV_ZERO, &autoneg_reg);
110                 autoneg_reg &= ~RTL_GBCR_1000F;
111                 hw->phy.write_reg(hw, RTL_GBCR,
112                         RTL_DEV_ZERO, autoneg_reg);
113         } else {
114                 hw->phy.read_reg(hw, RTL_GBCR,
115                         RTL_DEV_ZERO, &autoneg_reg);
116                 autoneg_reg |= RTL_GBCR_1000F;
117                 hw->phy.write_reg(hw, RTL_GBCR,
118                         RTL_DEV_ZERO, autoneg_reg);
119         }
120
121         if (!(speed & NGBE_LINK_SPEED_100M_FULL)) {
122                 hw->phy.read_reg(hw, RTL_ANAR,
123                         RTL_DEV_ZERO, &autoneg_reg);
124                 autoneg_reg &= ~RTL_ANAR_100F;
125                 autoneg_reg &= ~RTL_ANAR_100H;
126                 hw->phy.write_reg(hw, RTL_ANAR,
127                         RTL_DEV_ZERO, autoneg_reg);
128         } else {
129                 hw->phy.read_reg(hw, RTL_ANAR,
130                         RTL_DEV_ZERO, &autoneg_reg);
131                 autoneg_reg |= RTL_ANAR_100F;
132                 hw->phy.write_reg(hw, RTL_ANAR,
133                         RTL_DEV_ZERO, autoneg_reg);
134         }
135
136         if (!(speed & NGBE_LINK_SPEED_10M_FULL)) {
137                 hw->phy.read_reg(hw, RTL_ANAR,
138                         RTL_DEV_ZERO, &autoneg_reg);
139                 autoneg_reg &= ~RTL_ANAR_10F;
140                 autoneg_reg &= ~RTL_ANAR_10H;
141                 hw->phy.write_reg(hw, RTL_ANAR,
142                         RTL_DEV_ZERO, autoneg_reg);
143         } else {
144                 hw->phy.read_reg(hw, RTL_ANAR,
145                         RTL_DEV_ZERO, &autoneg_reg);
146                 autoneg_reg |= RTL_ANAR_10F;
147                 hw->phy.write_reg(hw, RTL_ANAR,
148                         RTL_DEV_ZERO, autoneg_reg);
149         }
150
151         /* restart AN and wait AN done interrupt */
152         autoneg_reg = RTL_BMCR_RESTART_AN | RTL_BMCR_ANE;
153         hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, autoneg_reg);
154
155 skip_an:
156         autoneg_reg = 0x205B;
157         hw->phy.write_reg(hw, RTL_LCR, 0xd04, autoneg_reg);
158         hw->phy.write_reg(hw, RTL_EEELCR, 0xd04, 0);
159
160         hw->phy.read_reg(hw, RTL_LPCR, 0xd04, &autoneg_reg);
161         autoneg_reg = autoneg_reg & 0xFFFC;
162         /* act led blinking mode set to 60ms */
163         autoneg_reg |= 0x2;
164         hw->phy.write_reg(hw, RTL_LPCR, 0xd04, autoneg_reg);
165
166         return 0;
167 }
168
169 s32 ngbe_reset_phy_rtl(struct ngbe_hw *hw)
170 {
171         u16 value = 0, i;
172         s32 status = 0;
173
174         DEBUGFUNC("ngbe_reset_phy_rtl");
175
176         value |= RTL_BMCR_RESET;
177         status = hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value);
178
179         for (i = 0; i < RTL_PHY_RST_WAIT_PERIOD; i++) {
180                 status = hw->phy.read_reg(hw, RTL_BMCR, RTL_DEV_ZERO, &value);
181                 if (!(value & RTL_BMCR_RESET))
182                         break;
183                 msleep(1);
184         }
185
186         if (i == RTL_PHY_RST_WAIT_PERIOD) {
187                 DEBUGOUT("PHY reset polling failed to complete.\n");
188                 return NGBE_ERR_RESET_FAILED;
189         }
190
191         return status;
192 }
193
194 s32 ngbe_check_phy_link_rtl(struct ngbe_hw *hw, u32 *speed, bool *link_up)
195 {
196         s32 status = 0;
197         u16 phy_link = 0;
198         u16 phy_speed = 0;
199         u16 phy_data = 0;
200         u16 insr = 0;
201
202         DEBUGFUNC("ngbe_check_phy_link_rtl");
203
204         hw->phy.read_reg(hw, RTL_INSR, 0xa43, &insr);
205
206         /* Initialize speed and link to default case */
207         *link_up = false;
208         *speed = NGBE_LINK_SPEED_UNKNOWN;
209
210         /*
211          * Check current speed and link status of the PHY register.
212          * This is a vendor specific register and may have to
213          * be changed for other copper PHYs.
214          */
215         status = hw->phy.read_reg(hw, RTL_PHYSR, 0xa43, &phy_data);
216         phy_link = phy_data & RTL_PHYSR_RTLS;
217         phy_speed = phy_data & (RTL_PHYSR_SPEED_MASK | RTL_PHYSR_DP);
218         if (phy_link == RTL_PHYSR_RTLS) {
219                 *link_up = true;
220
221                 if (phy_speed == (RTL_PHYSR_SPEED_1000M | RTL_PHYSR_DP))
222                         *speed = NGBE_LINK_SPEED_1GB_FULL;
223                 else if (phy_speed == (RTL_PHYSR_SPEED_100M | RTL_PHYSR_DP))
224                         *speed = NGBE_LINK_SPEED_100M_FULL;
225                 else if (phy_speed == (RTL_PHYSR_SPEED_10M | RTL_PHYSR_DP))
226                         *speed = NGBE_LINK_SPEED_10M_FULL;
227         }
228
229         return status;
230 }
231