• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Atlantic Network Driver
3  *
4  * Copyright (C) 2014-2019 aQuantia Corporation
5  * Copyright (C) 2019-2020 Marvell International Ltd.
6  */
7 
8 /* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for
9  * Atlantic hardware abstraction layer.
10  */
11 
12 #include "../aq_hw.h"
13 #include "../aq_hw_utils.h"
14 #include "../aq_pci_func.h"
15 #include "../aq_ring.h"
16 #include "../aq_vec.h"
17 #include "../aq_nic.h"
18 #include "hw_atl_utils.h"
19 #include "hw_atl_llh.h"
20 
21 #define HW_ATL_FW2X_MPI_LED_ADDR         0x31c
22 #define HW_ATL_FW2X_MPI_RPC_ADDR         0x334
23 
24 #define HW_ATL_FW2X_MPI_MBOX_ADDR        0x360
25 #define HW_ATL_FW2X_MPI_EFUSE_ADDR       0x364
26 #define HW_ATL_FW2X_MPI_CONTROL_ADDR     0x368
27 #define HW_ATL_FW2X_MPI_CONTROL2_ADDR    0x36C
28 #define HW_ATL_FW2X_MPI_STATE_ADDR       0x370
29 #define HW_ATL_FW2X_MPI_STATE2_ADDR      0x374
30 
31 #define HW_ATL_FW3X_EXT_CONTROL_ADDR     0x378
32 #define HW_ATL_FW3X_EXT_STATE_ADDR       0x37c
33 
34 #define HW_ATL_FW3X_PTP_ADJ_LSW_ADDR	 0x50a0
35 #define HW_ATL_FW3X_PTP_ADJ_MSW_ADDR	 0x50a4
36 
37 #define HW_ATL_FW2X_CAP_PAUSE            BIT(CAPS_HI_PAUSE)
38 #define HW_ATL_FW2X_CAP_ASYM_PAUSE       BIT(CAPS_HI_ASYMMETRIC_PAUSE)
39 #define HW_ATL_FW2X_CAP_SLEEP_PROXY      BIT(CAPS_HI_SLEEP_PROXY)
40 #define HW_ATL_FW2X_CAP_WOL              BIT(CAPS_HI_WOL)
41 
42 #define HW_ATL_FW2X_CTRL_WAKE_ON_LINK     BIT(CTRL_WAKE_ON_LINK)
43 #define HW_ATL_FW2X_CTRL_SLEEP_PROXY      BIT(CTRL_SLEEP_PROXY)
44 #define HW_ATL_FW2X_CTRL_WOL              BIT(CTRL_WOL)
45 #define HW_ATL_FW2X_CTRL_LINK_DROP        BIT(CTRL_LINK_DROP)
46 #define HW_ATL_FW2X_CTRL_PAUSE            BIT(CTRL_PAUSE)
47 #define HW_ATL_FW2X_CTRL_TEMPERATURE      BIT(CTRL_TEMPERATURE)
48 #define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE)
49 #define HW_ATL_FW2X_CTRL_INT_LOOPBACK     BIT(CTRL_INT_LOOPBACK)
50 #define HW_ATL_FW2X_CTRL_EXT_LOOPBACK     BIT(CTRL_EXT_LOOPBACK)
51 #define HW_ATL_FW2X_CTRL_DOWNSHIFT        BIT(CTRL_DOWNSHIFT)
52 #define HW_ATL_FW2X_CTRL_FORCE_RECONNECT  BIT(CTRL_FORCE_RECONNECT)
53 
54 #define HW_ATL_FW2X_CAP_EEE_1G_MASK      BIT(CAPS_HI_1000BASET_FD_EEE)
55 #define HW_ATL_FW2X_CAP_EEE_2G5_MASK     BIT(CAPS_HI_2P5GBASET_FD_EEE)
56 #define HW_ATL_FW2X_CAP_EEE_5G_MASK      BIT(CAPS_HI_5GBASET_FD_EEE)
57 #define HW_ATL_FW2X_CAP_EEE_10G_MASK     BIT(CAPS_HI_10GBASET_FD_EEE)
58 
59 #define HW_ATL_FW2X_CAP_MACSEC           BIT(CAPS_LO_MACSEC)
60 
61 #define HAL_ATLANTIC_WOL_FILTERS_COUNT   8
62 #define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL  0x0E
63 
64 #define HW_ATL_FW_VER_LED                0x03010026U
65 #define HW_ATL_FW_VER_MEDIA_CONTROL      0x0301005aU
66 
67 struct __packed fw2x_msg_wol_pattern {
68 	u8 mask[16];
69 	u32 crc;
70 };
71 
72 struct __packed fw2x_msg_wol {
73 	u32 msg_id;
74 	u8 hw_addr[ETH_ALEN];
75 	u8 magic_packet_enabled;
76 	u8 filter_count;
77 	struct fw2x_msg_wol_pattern filter[HAL_ATLANTIC_WOL_FILTERS_COUNT];
78 	u8 link_up_enabled;
79 	u8 link_down_enabled;
80 	u16 reserved;
81 	u32 link_up_timeout;
82 	u32 link_down_timeout;
83 };
84 
85 static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed);
86 static int aq_fw2x_set_state(struct aq_hw_s *self,
87 			     enum hal_atl_utils_fw_state_e state);
88 
89 static u32 aq_fw2x_mbox_get(struct aq_hw_s *self);
90 static u32 aq_fw2x_rpc_get(struct aq_hw_s *self);
91 static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr);
92 static u32 aq_fw2x_state_get(struct aq_hw_s *self);
93 static u32 aq_fw2x_state2_get(struct aq_hw_s *self);
94 
aq_fw2x_init(struct aq_hw_s * self)95 static int aq_fw2x_init(struct aq_hw_s *self)
96 {
97 	int err = 0;
98 
99 	/* check 10 times by 1ms */
100 	err = readx_poll_timeout_atomic(aq_fw2x_mbox_get,
101 					self, self->mbox_addr,
102 					self->mbox_addr != 0U,
103 					1000U, 10000U);
104 
105 	err = readx_poll_timeout_atomic(aq_fw2x_rpc_get,
106 					self, self->rpc_addr,
107 					self->rpc_addr != 0U,
108 					1000U, 100000U);
109 
110 	err = aq_fw2x_settings_get(self, &self->settings_addr);
111 
112 	return err;
113 }
114 
aq_fw2x_deinit(struct aq_hw_s * self)115 static int aq_fw2x_deinit(struct aq_hw_s *self)
116 {
117 	int err = aq_fw2x_set_link_speed(self, 0);
118 
119 	if (!err)
120 		err = aq_fw2x_set_state(self, MPI_DEINIT);
121 
122 	return err;
123 }
124 
link_speed_mask_2fw2x_ratemask(u32 speed)125 static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed)
126 {
127 	enum hw_atl_fw2x_rate rate = 0;
128 
129 	if (speed & AQ_NIC_RATE_10G)
130 		rate |= FW2X_RATE_10G;
131 
132 	if (speed & AQ_NIC_RATE_5G)
133 		rate |= FW2X_RATE_5G;
134 
135 	if (speed & AQ_NIC_RATE_2G5)
136 		rate |= FW2X_RATE_2G5;
137 
138 	if (speed & AQ_NIC_RATE_1G)
139 		rate |= FW2X_RATE_1G;
140 
141 	if (speed & AQ_NIC_RATE_100M)
142 		rate |= FW2X_RATE_100M;
143 
144 	return rate;
145 }
146 
fw2x_to_eee_mask(u32 speed)147 static u32 fw2x_to_eee_mask(u32 speed)
148 {
149 	u32 rate = 0;
150 
151 	if (speed & HW_ATL_FW2X_CAP_EEE_10G_MASK)
152 		rate |= AQ_NIC_RATE_EEE_10G;
153 	if (speed & HW_ATL_FW2X_CAP_EEE_5G_MASK)
154 		rate |= AQ_NIC_RATE_EEE_5G;
155 	if (speed & HW_ATL_FW2X_CAP_EEE_2G5_MASK)
156 		rate |= AQ_NIC_RATE_EEE_2G5;
157 	if (speed & HW_ATL_FW2X_CAP_EEE_1G_MASK)
158 		rate |= AQ_NIC_RATE_EEE_1G;
159 
160 	return rate;
161 }
162 
eee_mask_to_fw2x(u32 speed)163 static u32 eee_mask_to_fw2x(u32 speed)
164 {
165 	u32 rate = 0;
166 
167 	if (speed & AQ_NIC_RATE_EEE_10G)
168 		rate |= HW_ATL_FW2X_CAP_EEE_10G_MASK;
169 	if (speed & AQ_NIC_RATE_EEE_5G)
170 		rate |= HW_ATL_FW2X_CAP_EEE_5G_MASK;
171 	if (speed & AQ_NIC_RATE_EEE_2G5)
172 		rate |= HW_ATL_FW2X_CAP_EEE_2G5_MASK;
173 	if (speed & AQ_NIC_RATE_EEE_1G)
174 		rate |= HW_ATL_FW2X_CAP_EEE_1G_MASK;
175 
176 	return rate;
177 }
178 
aq_fw2x_set_link_speed(struct aq_hw_s * self,u32 speed)179 static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed)
180 {
181 	u32 val = link_speed_mask_2fw2x_ratemask(speed);
182 
183 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, val);
184 
185 	return 0;
186 }
187 
aq_fw2x_upd_flow_control_bits(struct aq_hw_s * self,u32 * mpi_state,u32 fc)188 static void aq_fw2x_upd_flow_control_bits(struct aq_hw_s *self,
189 					  u32 *mpi_state, u32 fc)
190 {
191 	*mpi_state &= ~(HW_ATL_FW2X_CTRL_PAUSE |
192 			HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE);
193 
194 	switch (fc) {
195 	/* There is not explicit mode of RX only pause frames,
196 	 * thus, we join this mode with FC full.
197 	 * FC full is either Rx, either Tx, or both.
198 	 */
199 	case AQ_NIC_FC_FULL:
200 	case AQ_NIC_FC_RX:
201 		*mpi_state |= HW_ATL_FW2X_CTRL_PAUSE |
202 			      HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE;
203 		break;
204 	case AQ_NIC_FC_TX:
205 		*mpi_state |= HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE;
206 		break;
207 	}
208 }
209 
aq_fw2x_upd_eee_rate_bits(struct aq_hw_s * self,u32 * mpi_opts,u32 eee_speeds)210 static void aq_fw2x_upd_eee_rate_bits(struct aq_hw_s *self, u32 *mpi_opts,
211 				      u32 eee_speeds)
212 {
213 	*mpi_opts &= ~(HW_ATL_FW2X_CAP_EEE_1G_MASK |
214 		       HW_ATL_FW2X_CAP_EEE_2G5_MASK |
215 		       HW_ATL_FW2X_CAP_EEE_5G_MASK |
216 		       HW_ATL_FW2X_CAP_EEE_10G_MASK);
217 
218 	*mpi_opts |= eee_mask_to_fw2x(eee_speeds);
219 }
220 
aq_fw2x_set_state(struct aq_hw_s * self,enum hal_atl_utils_fw_state_e state)221 static int aq_fw2x_set_state(struct aq_hw_s *self,
222 			     enum hal_atl_utils_fw_state_e state)
223 {
224 	u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
225 	struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
226 
227 	switch (state) {
228 	case MPI_INIT:
229 		mpi_state &= ~BIT(CAPS_HI_LINK_DROP);
230 		aq_fw2x_upd_eee_rate_bits(self, &mpi_state, cfg->eee_speeds);
231 		aq_fw2x_upd_flow_control_bits(self, &mpi_state,
232 					      self->aq_nic_cfg->fc.req);
233 		break;
234 	case MPI_DEINIT:
235 		mpi_state |= BIT(CAPS_HI_LINK_DROP);
236 		break;
237 	case MPI_RESET:
238 	case MPI_POWER:
239 		/* No actions */
240 		break;
241 	}
242 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
243 
244 	return 0;
245 }
246 
aq_fw2x_update_link_status(struct aq_hw_s * self)247 static int aq_fw2x_update_link_status(struct aq_hw_s *self)
248 {
249 	struct aq_hw_link_status_s *link_status = &self->aq_link_status;
250 	u32 mpi_state;
251 	u32 speed;
252 
253 	mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR);
254 	speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G |
255 			     FW2X_RATE_2G5 | FW2X_RATE_5G |
256 			     FW2X_RATE_10G);
257 
258 	if (speed) {
259 		if (speed & FW2X_RATE_10G)
260 			link_status->mbps = 10000;
261 		else if (speed & FW2X_RATE_5G)
262 			link_status->mbps = 5000;
263 		else if (speed & FW2X_RATE_2G5)
264 			link_status->mbps = 2500;
265 		else if (speed & FW2X_RATE_1G)
266 			link_status->mbps = 1000;
267 		else if (speed & FW2X_RATE_100M)
268 			link_status->mbps = 100;
269 		else
270 			link_status->mbps = 10000;
271 	} else {
272 		link_status->mbps = 0;
273 	}
274 	link_status->full_duplex = true;
275 
276 	return 0;
277 }
278 
aq_fw2x_get_mac_permanent(struct aq_hw_s * self,u8 * mac)279 static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
280 {
281 	u32 efuse_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_EFUSE_ADDR);
282 	u32 mac_addr[2] = { 0 };
283 	int err = 0;
284 
285 	if (efuse_addr != 0) {
286 		err = hw_atl_utils_fw_downld_dwords(self,
287 						    efuse_addr + (40U * 4U),
288 						    mac_addr,
289 						    ARRAY_SIZE(mac_addr));
290 		if (err)
291 			return err;
292 		mac_addr[0] = __swab32(mac_addr[0]);
293 		mac_addr[1] = __swab32(mac_addr[1]);
294 	}
295 
296 	ether_addr_copy(mac, (u8 *)mac_addr);
297 
298 	return err;
299 }
300 
aq_fw2x_update_stats(struct aq_hw_s * self)301 static int aq_fw2x_update_stats(struct aq_hw_s *self)
302 {
303 	u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
304 	u32 orig_stats_val = mpi_opts & BIT(CAPS_HI_STATISTICS);
305 	u32 stats_val;
306 	int err = 0;
307 
308 	/* Toggle statistics bit for FW to update */
309 	mpi_opts = mpi_opts ^ BIT(CAPS_HI_STATISTICS);
310 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
311 
312 	/* Wait FW to report back */
313 	err = readx_poll_timeout_atomic(aq_fw2x_state2_get,
314 					self, stats_val,
315 					orig_stats_val != (stats_val &
316 					BIT(CAPS_HI_STATISTICS)),
317 					1U, 10000U);
318 	if (err)
319 		return err;
320 
321 	return hw_atl_utils_update_stats(self);
322 }
323 
aq_fw2x_get_phy_temp(struct aq_hw_s * self,int * temp)324 static int aq_fw2x_get_phy_temp(struct aq_hw_s *self, int *temp)
325 {
326 	u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
327 	u32 temp_val = mpi_opts & HW_ATL_FW2X_CTRL_TEMPERATURE;
328 	u32 phy_temp_offset;
329 	u32 temp_res;
330 	int err = 0;
331 	u32 val;
332 
333 	phy_temp_offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
334 						     info.phy_temperature);
335 
336 	/* Toggle statistics bit for FW to 0x36C.18 (CTRL_TEMPERATURE) */
337 	mpi_opts = mpi_opts ^ HW_ATL_FW2X_CTRL_TEMPERATURE;
338 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
339 	/* Wait FW to report back */
340 	err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
341 					temp_val !=
342 					(val & HW_ATL_FW2X_CTRL_TEMPERATURE),
343 					1U, 10000U);
344 	err = hw_atl_utils_fw_downld_dwords(self, phy_temp_offset,
345 					    &temp_res, 1);
346 
347 	if (err)
348 		return err;
349 
350 	/* Convert PHY temperature from 1/256 degree Celsius
351 	 * to 1/1000 degree Celsius.
352 	 */
353 	*temp = (int16_t)(temp_res & 0xFFFF) * 1000 / 256;
354 
355 	return 0;
356 }
357 
aq_fw2x_set_wol(struct aq_hw_s * self,u8 * mac)358 static int aq_fw2x_set_wol(struct aq_hw_s *self, u8 *mac)
359 {
360 	struct hw_atl_utils_fw_rpc *rpc = NULL;
361 	struct offload_info *info = NULL;
362 	u32 wol_bits = 0;
363 	u32 rpc_size;
364 	int err = 0;
365 	u32 val;
366 
367 	if (self->aq_nic_cfg->wol & WAKE_PHY) {
368 		aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR,
369 				HW_ATL_FW2X_CTRL_LINK_DROP);
370 		readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
371 					  (val &
372 					   HW_ATL_FW2X_CTRL_LINK_DROP) != 0,
373 					  1000, 100000);
374 		wol_bits |= HW_ATL_FW2X_CTRL_WAKE_ON_LINK;
375 	}
376 
377 	if (self->aq_nic_cfg->wol & WAKE_MAGIC) {
378 		wol_bits |= HW_ATL_FW2X_CTRL_SLEEP_PROXY |
379 			    HW_ATL_FW2X_CTRL_WOL;
380 
381 		err = hw_atl_utils_fw_rpc_wait(self, &rpc);
382 		if (err < 0)
383 			goto err_exit;
384 
385 		rpc_size = sizeof(*info) +
386 			   offsetof(struct hw_atl_utils_fw_rpc, fw2x_offloads);
387 		memset(rpc, 0, rpc_size);
388 		info = &rpc->fw2x_offloads;
389 		memcpy(info->mac_addr, mac, ETH_ALEN);
390 		info->len = sizeof(*info);
391 
392 		err = hw_atl_utils_fw_rpc_call(self, rpc_size);
393 		if (err < 0)
394 			goto err_exit;
395 	}
396 
397 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, wol_bits);
398 
399 err_exit:
400 	return err;
401 }
402 
aq_fw2x_set_power(struct aq_hw_s * self,unsigned int power_state,u8 * mac)403 static int aq_fw2x_set_power(struct aq_hw_s *self, unsigned int power_state,
404 			     u8 *mac)
405 {
406 	int err = 0;
407 
408 	if (self->aq_nic_cfg->wol)
409 		err = aq_fw2x_set_wol(self, mac);
410 
411 	return err;
412 }
413 
aq_fw2x_send_fw_request(struct aq_hw_s * self,const struct hw_fw_request_iface * fw_req,size_t size)414 static int aq_fw2x_send_fw_request(struct aq_hw_s *self,
415 				   const struct hw_fw_request_iface *fw_req,
416 				   size_t size)
417 {
418 	u32 ctrl2, orig_ctrl2;
419 	u32 dword_cnt;
420 	int err = 0;
421 	u32 val;
422 
423 	/* Write data to drvIface Mailbox */
424 	dword_cnt = size / sizeof(u32);
425 	if (size % sizeof(u32))
426 		dword_cnt++;
427 	err = hw_atl_write_fwcfg_dwords(self, (void *)fw_req, dword_cnt);
428 	if (err < 0)
429 		goto err_exit;
430 
431 	/* Toggle statistics bit for FW to update */
432 	ctrl2 = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
433 	orig_ctrl2 = ctrl2 & BIT(CAPS_HI_FW_REQUEST);
434 	ctrl2 = ctrl2 ^ BIT(CAPS_HI_FW_REQUEST);
435 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, ctrl2);
436 
437 	/* Wait FW to report back */
438 	err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
439 					orig_ctrl2 != (val &
440 						       BIT(CAPS_HI_FW_REQUEST)),
441 					1U, 10000U);
442 
443 err_exit:
444 	return err;
445 }
446 
aq_fw3x_enable_ptp(struct aq_hw_s * self,int enable)447 static void aq_fw3x_enable_ptp(struct aq_hw_s *self, int enable)
448 {
449 	u32 ptp_opts = aq_hw_read_reg(self, HW_ATL_FW3X_EXT_STATE_ADDR);
450 	u32 all_ptp_features = BIT(CAPS_EX_PHY_PTP_EN) |
451 						   BIT(CAPS_EX_PTP_GPIO_EN);
452 
453 	if (enable)
454 		ptp_opts |= all_ptp_features;
455 	else
456 		ptp_opts &= ~all_ptp_features;
457 
458 	aq_hw_write_reg(self, HW_ATL_FW3X_EXT_CONTROL_ADDR, ptp_opts);
459 }
460 
aq_fw3x_adjust_ptp(struct aq_hw_s * self,uint64_t adj)461 static void aq_fw3x_adjust_ptp(struct aq_hw_s *self, uint64_t adj)
462 {
463 	aq_hw_write_reg(self, HW_ATL_FW3X_PTP_ADJ_LSW_ADDR,
464 			(adj >>  0) & 0xffffffff);
465 	aq_hw_write_reg(self, HW_ATL_FW3X_PTP_ADJ_MSW_ADDR,
466 			(adj >> 32) & 0xffffffff);
467 }
468 
aq_fw2x_led_control(struct aq_hw_s * self,u32 mode)469 static int aq_fw2x_led_control(struct aq_hw_s *self, u32 mode)
470 {
471 	if (self->fw_ver_actual < HW_ATL_FW_VER_LED)
472 		return -EOPNOTSUPP;
473 
474 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_LED_ADDR, mode);
475 
476 	return 0;
477 }
478 
aq_fw2x_set_eee_rate(struct aq_hw_s * self,u32 speed)479 static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed)
480 {
481 	u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
482 
483 	aq_fw2x_upd_eee_rate_bits(self, &mpi_opts, speed);
484 
485 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
486 
487 	return 0;
488 }
489 
aq_fw2x_get_eee_rate(struct aq_hw_s * self,u32 * rate,u32 * supported_rates)490 static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate,
491 				u32 *supported_rates)
492 {
493 	u32 mpi_state;
494 	u32 caps_hi;
495 	int err = 0;
496 	u32 offset;
497 
498 	offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
499 					    info.caps_hi);
500 
501 	err = hw_atl_utils_fw_downld_dwords(self, offset, &caps_hi, 1);
502 
503 	if (err)
504 		return err;
505 
506 	*supported_rates = fw2x_to_eee_mask(caps_hi);
507 
508 	mpi_state = aq_fw2x_state2_get(self);
509 	*rate = fw2x_to_eee_mask(mpi_state);
510 
511 	return err;
512 }
513 
aq_fw2x_renegotiate(struct aq_hw_s * self)514 static int aq_fw2x_renegotiate(struct aq_hw_s *self)
515 {
516 	u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
517 
518 	mpi_opts |= BIT(CTRL_FORCE_RECONNECT);
519 
520 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
521 
522 	return 0;
523 }
524 
aq_fw2x_set_flow_control(struct aq_hw_s * self)525 static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
526 {
527 	u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
528 
529 	aq_fw2x_upd_flow_control_bits(self, &mpi_state,
530 				      self->aq_nic_cfg->fc.req);
531 
532 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
533 
534 	return 0;
535 }
536 
aq_fw2x_get_flow_control(struct aq_hw_s * self,u32 * fcmode)537 static u32 aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fcmode)
538 {
539 	u32 mpi_state = aq_fw2x_state2_get(self);
540 	*fcmode = 0;
541 
542 	if (mpi_state & HW_ATL_FW2X_CAP_PAUSE)
543 		*fcmode |= AQ_NIC_FC_RX;
544 
545 	if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE)
546 		*fcmode |= AQ_NIC_FC_TX;
547 
548 	return 0;
549 }
550 
aq_fw2x_set_phyloopback(struct aq_hw_s * self,u32 mode,bool enable)551 static int aq_fw2x_set_phyloopback(struct aq_hw_s *self, u32 mode, bool enable)
552 {
553 	u32 mpi_opts;
554 
555 	switch (mode) {
556 	case AQ_HW_LOOPBACK_PHYINT_SYS:
557 		mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
558 		if (enable)
559 			mpi_opts |= HW_ATL_FW2X_CTRL_INT_LOOPBACK;
560 		else
561 			mpi_opts &= ~HW_ATL_FW2X_CTRL_INT_LOOPBACK;
562 		aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
563 		break;
564 	case AQ_HW_LOOPBACK_PHYEXT_SYS:
565 		mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
566 		if (enable)
567 			mpi_opts |= HW_ATL_FW2X_CTRL_EXT_LOOPBACK;
568 		else
569 			mpi_opts &= ~HW_ATL_FW2X_CTRL_EXT_LOOPBACK;
570 		aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
571 		break;
572 	default:
573 		return -EINVAL;
574 	}
575 
576 	return 0;
577 }
578 
aq_fw2x_mbox_get(struct aq_hw_s * self)579 static u32 aq_fw2x_mbox_get(struct aq_hw_s *self)
580 {
581 	return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR);
582 }
583 
aq_fw2x_rpc_get(struct aq_hw_s * self)584 static u32 aq_fw2x_rpc_get(struct aq_hw_s *self)
585 {
586 	return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR);
587 }
588 
aq_fw2x_settings_get(struct aq_hw_s * self,u32 * addr)589 static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr)
590 {
591 	int err = 0;
592 	u32 offset;
593 
594 	offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
595 					    info.setting_address);
596 
597 	err = hw_atl_utils_fw_downld_dwords(self, offset, addr, 1);
598 
599 	return err;
600 }
601 
aq_fw2x_state_get(struct aq_hw_s * self)602 static u32 aq_fw2x_state_get(struct aq_hw_s *self)
603 {
604 	return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR);
605 }
606 
aq_fw2x_state2_get(struct aq_hw_s * self)607 static u32 aq_fw2x_state2_get(struct aq_hw_s *self)
608 {
609 	return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR);
610 }
611 
aq_fw2x_set_downshift(struct aq_hw_s * self,u32 counter)612 static int aq_fw2x_set_downshift(struct aq_hw_s *self, u32 counter)
613 {
614 	int err = 0;
615 	u32 mpi_opts;
616 	u32 offset;
617 
618 	offset = offsetof(struct hw_atl_utils_settings, downshift_retry_count);
619 	err = hw_atl_write_fwsettings_dwords(self, offset, &counter, 1);
620 	if (err)
621 		return err;
622 
623 	mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
624 	if (counter)
625 		mpi_opts |= HW_ATL_FW2X_CTRL_DOWNSHIFT;
626 	else
627 		mpi_opts &= ~HW_ATL_FW2X_CTRL_DOWNSHIFT;
628 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
629 
630 	return err;
631 }
632 
aq_fw2x_set_media_detect(struct aq_hw_s * self,bool on)633 static int aq_fw2x_set_media_detect(struct aq_hw_s *self, bool on)
634 {
635 	u32 enable;
636 	u32 offset;
637 
638 	if (self->fw_ver_actual < HW_ATL_FW_VER_MEDIA_CONTROL)
639 		return -EOPNOTSUPP;
640 
641 	offset = offsetof(struct hw_atl_utils_settings, media_detect);
642 	enable = on;
643 
644 	return hw_atl_write_fwsettings_dwords(self, offset, &enable, 1);
645 }
646 
aq_fw2x_get_link_capabilities(struct aq_hw_s * self)647 static u32 aq_fw2x_get_link_capabilities(struct aq_hw_s *self)
648 {
649 	int err = 0;
650 	u32 offset;
651 	u32 val;
652 
653 	offset = self->mbox_addr +
654 		 offsetof(struct hw_atl_utils_mbox, info.caps_lo);
655 
656 	err = hw_atl_utils_fw_downld_dwords(self, offset, &val, 1);
657 
658 	if (err)
659 		return 0;
660 
661 	return val;
662 }
663 
aq_fw2x_send_macsec_req(struct aq_hw_s * hw,struct macsec_msg_fw_request * req,struct macsec_msg_fw_response * response)664 static int aq_fw2x_send_macsec_req(struct aq_hw_s *hw,
665 				   struct macsec_msg_fw_request *req,
666 				   struct macsec_msg_fw_response *response)
667 {
668 	u32 low_status, low_req = 0;
669 	u32 dword_cnt;
670 	u32 caps_lo;
671 	u32 offset;
672 	int err;
673 
674 	if (!req || !response)
675 		return -EINVAL;
676 
677 	caps_lo = aq_fw2x_get_link_capabilities(hw);
678 	if (!(caps_lo & BIT(CAPS_LO_MACSEC)))
679 		return -EOPNOTSUPP;
680 
681 	/* Write macsec request to cfg memory */
682 	dword_cnt = (sizeof(*req) + sizeof(u32) - 1) / sizeof(u32);
683 	err = hw_atl_write_fwcfg_dwords(hw, (void *)req, dword_cnt);
684 	if (err < 0)
685 		return err;
686 
687 	/* Toggle 0x368.CAPS_LO_MACSEC bit */
688 	low_req = aq_hw_read_reg(hw, HW_ATL_FW2X_MPI_CONTROL_ADDR);
689 	low_req ^= HW_ATL_FW2X_CAP_MACSEC;
690 	aq_hw_write_reg(hw, HW_ATL_FW2X_MPI_CONTROL_ADDR, low_req);
691 
692 	/* Wait FW to report back */
693 	err = readx_poll_timeout_atomic(aq_fw2x_state_get, hw, low_status,
694 		low_req != (low_status & BIT(CAPS_LO_MACSEC)), 1U, 10000U);
695 	if (err)
696 		return -EIO;
697 
698 	/* Read status of write operation */
699 	offset = hw->rpc_addr + sizeof(u32);
700 	err = hw_atl_utils_fw_downld_dwords(hw, offset, (u32 *)(void *)response,
701 					    sizeof(*response) / sizeof(u32));
702 
703 	return err;
704 }
705 
706 const struct aq_fw_ops aq_fw_2x_ops = {
707 	.init               = aq_fw2x_init,
708 	.deinit             = aq_fw2x_deinit,
709 	.reset              = NULL,
710 	.renegotiate        = aq_fw2x_renegotiate,
711 	.get_mac_permanent  = aq_fw2x_get_mac_permanent,
712 	.set_link_speed     = aq_fw2x_set_link_speed,
713 	.set_state          = aq_fw2x_set_state,
714 	.update_link_status = aq_fw2x_update_link_status,
715 	.update_stats       = aq_fw2x_update_stats,
716 	.get_mac_temp       = NULL,
717 	.get_phy_temp       = aq_fw2x_get_phy_temp,
718 	.set_power          = aq_fw2x_set_power,
719 	.set_eee_rate       = aq_fw2x_set_eee_rate,
720 	.get_eee_rate       = aq_fw2x_get_eee_rate,
721 	.set_flow_control   = aq_fw2x_set_flow_control,
722 	.get_flow_control   = aq_fw2x_get_flow_control,
723 	.send_fw_request    = aq_fw2x_send_fw_request,
724 	.enable_ptp         = aq_fw3x_enable_ptp,
725 	.led_control        = aq_fw2x_led_control,
726 	.set_phyloopback    = aq_fw2x_set_phyloopback,
727 	.set_downshift      = aq_fw2x_set_downshift,
728 	.set_media_detect   = aq_fw2x_set_media_detect,
729 	.adjust_ptp         = aq_fw3x_adjust_ptp,
730 	.get_link_capabilities = aq_fw2x_get_link_capabilities,
731 	.send_macsec_req    = aq_fw2x_send_macsec_req,
732 };
733