hw_atl_utils_fw2x.c (19197B)
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 67struct __packed fw2x_msg_wol_pattern { 68 u8 mask[16]; 69 u32 crc; 70}; 71 72struct __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 85static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed); 86static int aq_fw2x_set_state(struct aq_hw_s *self, 87 enum hal_atl_utils_fw_state_e state); 88 89static u32 aq_fw2x_mbox_get(struct aq_hw_s *self); 90static u32 aq_fw2x_rpc_get(struct aq_hw_s *self); 91static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr); 92static u32 aq_fw2x_state_get(struct aq_hw_s *self); 93static u32 aq_fw2x_state2_get(struct aq_hw_s *self); 94 95static 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 115static 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 125static 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 147static 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 163static 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 179static 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 188static 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 210static 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 221static 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 247static 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 279static 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 301static 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 324static 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 358static int aq_fw2x_set_wol(struct aq_hw_s *self, const 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 399err_exit: 400 return err; 401} 402 403static int aq_fw2x_set_power(struct aq_hw_s *self, unsigned int power_state, 404 const 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 414static 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 443err_exit: 444 return err; 445} 446 447static 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 461static 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 469static 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 479static 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 490static 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 514static 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 525static 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 537static 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 551static 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 579static 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 584static 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 589static 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 602static 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 607static 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 612static 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 633static 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 647static 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 664static 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 706const 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};