175a6faf6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2843e1396SMark Starovoytov /* Atlantic Network Driver 3843e1396SMark Starovoytov * 4843e1396SMark Starovoytov * Copyright (C) 2014-2019 aQuantia Corporation 5843e1396SMark Starovoytov * Copyright (C) 2019-2020 Marvell International Ltd. 6a57d3929SIgor Russkikh */ 7a57d3929SIgor Russkikh 8a57d3929SIgor Russkikh /* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for 9a57d3929SIgor Russkikh * Atlantic hardware abstraction layer. 10a57d3929SIgor Russkikh */ 11a57d3929SIgor Russkikh 12a57d3929SIgor Russkikh #include "../aq_hw.h" 13a57d3929SIgor Russkikh #include "../aq_hw_utils.h" 14a57d3929SIgor Russkikh #include "../aq_pci_func.h" 15a57d3929SIgor Russkikh #include "../aq_ring.h" 16a57d3929SIgor Russkikh #include "../aq_vec.h" 170e1a0ddeSYana Esina #include "../aq_nic.h" 18a57d3929SIgor Russkikh #include "hw_atl_utils.h" 19a57d3929SIgor Russkikh #include "hw_atl_llh.h" 20a57d3929SIgor Russkikh 21d1287ce4SNikita Danilov #define HW_ATL_FW2X_MPI_LED_ADDR 0x31c 223ee5c887SYana Esina #define HW_ATL_FW2X_MPI_RPC_ADDR 0x334 23a57d3929SIgor Russkikh 246a7f2277SNikita Danilov #define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360 256a7f2277SNikita Danilov #define HW_ATL_FW2X_MPI_EFUSE_ADDR 0x364 26a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_CONTROL_ADDR 0x368 27a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_CONTROL2_ADDR 0x36C 28a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_STATE_ADDR 0x370 29a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374 30a57d3929SIgor Russkikh 31910479a9SEgor Pomozov #define HW_ATL_FW3X_EXT_CONTROL_ADDR 0x378 32910479a9SEgor Pomozov #define HW_ATL_FW3X_EXT_STATE_ADDR 0x37c 33910479a9SEgor Pomozov 34f08a464cSEgor Pomozov #define HW_ATL_FW3X_PTP_ADJ_LSW_ADDR 0x50a0 35f08a464cSEgor Pomozov #define HW_ATL_FW3X_PTP_ADJ_MSW_ADDR 0x50a4 36f08a464cSEgor Pomozov 3735e8e8b4SIgor Russkikh #define HW_ATL_FW2X_CAP_PAUSE BIT(CAPS_HI_PAUSE) 3835e8e8b4SIgor Russkikh #define HW_ATL_FW2X_CAP_ASYM_PAUSE BIT(CAPS_HI_ASYMMETRIC_PAUSE) 390e1a0ddeSYana Esina #define HW_ATL_FW2X_CAP_SLEEP_PROXY BIT(CAPS_HI_SLEEP_PROXY) 400e1a0ddeSYana Esina #define HW_ATL_FW2X_CAP_WOL BIT(CAPS_HI_WOL) 410e1a0ddeSYana Esina 42837c6378SNikita Danilov #define HW_ATL_FW2X_CTRL_WAKE_ON_LINK BIT(CTRL_WAKE_ON_LINK) 430e1a0ddeSYana Esina #define HW_ATL_FW2X_CTRL_SLEEP_PROXY BIT(CTRL_SLEEP_PROXY) 440e1a0ddeSYana Esina #define HW_ATL_FW2X_CTRL_WOL BIT(CTRL_WOL) 450e1a0ddeSYana Esina #define HW_ATL_FW2X_CTRL_LINK_DROP BIT(CTRL_LINK_DROP) 460e1a0ddeSYana Esina #define HW_ATL_FW2X_CTRL_PAUSE BIT(CTRL_PAUSE) 478f894011SYana Esina #define HW_ATL_FW2X_CTRL_TEMPERATURE BIT(CTRL_TEMPERATURE) 480e1a0ddeSYana Esina #define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE) 49ea4b4d7fSIgor Russkikh #define HW_ATL_FW2X_CTRL_INT_LOOPBACK BIT(CTRL_INT_LOOPBACK) 50ea4b4d7fSIgor Russkikh #define HW_ATL_FW2X_CTRL_EXT_LOOPBACK BIT(CTRL_EXT_LOOPBACK) 51ea4b4d7fSIgor Russkikh #define HW_ATL_FW2X_CTRL_DOWNSHIFT BIT(CTRL_DOWNSHIFT) 520e1a0ddeSYana Esina #define HW_ATL_FW2X_CTRL_FORCE_RECONNECT BIT(CTRL_FORCE_RECONNECT) 530e1a0ddeSYana Esina 5492ab6407SYana Esina #define HW_ATL_FW2X_CAP_EEE_1G_MASK BIT(CAPS_HI_1000BASET_FD_EEE) 5592ab6407SYana Esina #define HW_ATL_FW2X_CAP_EEE_2G5_MASK BIT(CAPS_HI_2P5GBASET_FD_EEE) 5692ab6407SYana Esina #define HW_ATL_FW2X_CAP_EEE_5G_MASK BIT(CAPS_HI_5GBASET_FD_EEE) 5792ab6407SYana Esina #define HW_ATL_FW2X_CAP_EEE_10G_MASK BIT(CAPS_HI_10GBASET_FD_EEE) 5892ab6407SYana Esina 5962c1c2e6SDmitry Bogdanov #define HW_ATL_FW2X_CAP_MACSEC BIT(CAPS_LO_MACSEC) 6062c1c2e6SDmitry Bogdanov 610e1a0ddeSYana Esina #define HAL_ATLANTIC_WOL_FILTERS_COUNT 8 620e1a0ddeSYana Esina #define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL 0x0E 630e1a0ddeSYana Esina 64d1287ce4SNikita Danilov #define HW_ATL_FW_VER_LED 0x03010026U 65ea4b4d7fSIgor Russkikh #define HW_ATL_FW_VER_MEDIA_CONTROL 0x0301005aU 66d1287ce4SNikita Danilov 670e1a0ddeSYana Esina struct __packed fw2x_msg_wol_pattern { 680e1a0ddeSYana Esina u8 mask[16]; 690e1a0ddeSYana Esina u32 crc; 700e1a0ddeSYana Esina }; 710e1a0ddeSYana Esina 720e1a0ddeSYana Esina struct __packed fw2x_msg_wol { 730e1a0ddeSYana Esina u32 msg_id; 740e1a0ddeSYana Esina u8 hw_addr[ETH_ALEN]; 750e1a0ddeSYana Esina u8 magic_packet_enabled; 760e1a0ddeSYana Esina u8 filter_count; 770e1a0ddeSYana Esina struct fw2x_msg_wol_pattern filter[HAL_ATLANTIC_WOL_FILTERS_COUNT]; 780e1a0ddeSYana Esina u8 link_up_enabled; 790e1a0ddeSYana Esina u8 link_down_enabled; 800e1a0ddeSYana Esina u16 reserved; 810e1a0ddeSYana Esina u32 link_up_timeout; 820e1a0ddeSYana Esina u32 link_down_timeout; 830e1a0ddeSYana Esina }; 840e1a0ddeSYana Esina 8544e00dd8SIgor Russkikh static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed); 8644e00dd8SIgor Russkikh static int aq_fw2x_set_state(struct aq_hw_s *self, 8744e00dd8SIgor Russkikh enum hal_atl_utils_fw_state_e state); 8844e00dd8SIgor Russkikh 896a7f2277SNikita Danilov static u32 aq_fw2x_mbox_get(struct aq_hw_s *self); 906a7f2277SNikita Danilov static u32 aq_fw2x_rpc_get(struct aq_hw_s *self); 91dc12f75aSNikita Danilov static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr); 9262c1c2e6SDmitry Bogdanov static u32 aq_fw2x_state_get(struct aq_hw_s *self); 936a7f2277SNikita Danilov static u32 aq_fw2x_state2_get(struct aq_hw_s *self); 946a7f2277SNikita Danilov 95a57d3929SIgor Russkikh static int aq_fw2x_init(struct aq_hw_s *self) 96a57d3929SIgor Russkikh { 97a57d3929SIgor Russkikh int err = 0; 98a57d3929SIgor Russkikh 99a57d3929SIgor Russkikh /* check 10 times by 1ms */ 1006a7f2277SNikita Danilov err = readx_poll_timeout_atomic(aq_fw2x_mbox_get, 1016a7f2277SNikita Danilov self, self->mbox_addr, 1026a7f2277SNikita Danilov self->mbox_addr != 0U, 1036a7f2277SNikita Danilov 1000U, 10000U); 1046a7f2277SNikita Danilov 1056a7f2277SNikita Danilov err = readx_poll_timeout_atomic(aq_fw2x_rpc_get, 1066a7f2277SNikita Danilov self, self->rpc_addr, 1076a7f2277SNikita Danilov self->rpc_addr != 0U, 1086a7f2277SNikita Danilov 1000U, 100000U); 1093ee5c887SYana Esina 110dc12f75aSNikita Danilov err = aq_fw2x_settings_get(self, &self->settings_addr); 111dc12f75aSNikita Danilov 112a57d3929SIgor Russkikh return err; 113a57d3929SIgor Russkikh } 114a57d3929SIgor Russkikh 11544e00dd8SIgor Russkikh static int aq_fw2x_deinit(struct aq_hw_s *self) 11644e00dd8SIgor Russkikh { 11744e00dd8SIgor Russkikh int err = aq_fw2x_set_link_speed(self, 0); 11844e00dd8SIgor Russkikh 11944e00dd8SIgor Russkikh if (!err) 12044e00dd8SIgor Russkikh err = aq_fw2x_set_state(self, MPI_DEINIT); 12144e00dd8SIgor Russkikh 12244e00dd8SIgor Russkikh return err; 12344e00dd8SIgor Russkikh } 12444e00dd8SIgor Russkikh 125a57d3929SIgor Russkikh static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed) 126a57d3929SIgor Russkikh { 127a57d3929SIgor Russkikh enum hw_atl_fw2x_rate rate = 0; 128a57d3929SIgor Russkikh 129a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_10G) 130a57d3929SIgor Russkikh rate |= FW2X_RATE_10G; 131a57d3929SIgor Russkikh 132a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_5G) 133a57d3929SIgor Russkikh rate |= FW2X_RATE_5G; 134a57d3929SIgor Russkikh 135a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_5GSR) 136a57d3929SIgor Russkikh rate |= FW2X_RATE_5G; 137a57d3929SIgor Russkikh 138843e1396SMark Starovoytov if (speed & AQ_NIC_RATE_2G5) 139a57d3929SIgor Russkikh rate |= FW2X_RATE_2G5; 140a57d3929SIgor Russkikh 141a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_1G) 142a57d3929SIgor Russkikh rate |= FW2X_RATE_1G; 143a57d3929SIgor Russkikh 144a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_100M) 145a57d3929SIgor Russkikh rate |= FW2X_RATE_100M; 146a57d3929SIgor Russkikh 147a57d3929SIgor Russkikh return rate; 148a57d3929SIgor Russkikh } 149a57d3929SIgor Russkikh 15092ab6407SYana Esina static u32 fw2x_to_eee_mask(u32 speed) 15192ab6407SYana Esina { 15292ab6407SYana Esina u32 rate = 0; 15392ab6407SYana Esina 15492ab6407SYana Esina if (speed & HW_ATL_FW2X_CAP_EEE_10G_MASK) 15592ab6407SYana Esina rate |= AQ_NIC_RATE_EEE_10G; 15692ab6407SYana Esina if (speed & HW_ATL_FW2X_CAP_EEE_5G_MASK) 15792ab6407SYana Esina rate |= AQ_NIC_RATE_EEE_5G; 15892ab6407SYana Esina if (speed & HW_ATL_FW2X_CAP_EEE_2G5_MASK) 159843e1396SMark Starovoytov rate |= AQ_NIC_RATE_EEE_2G5; 16092ab6407SYana Esina if (speed & HW_ATL_FW2X_CAP_EEE_1G_MASK) 16192ab6407SYana Esina rate |= AQ_NIC_RATE_EEE_1G; 16292ab6407SYana Esina 16392ab6407SYana Esina return rate; 16492ab6407SYana Esina } 16592ab6407SYana Esina 16692ab6407SYana Esina static u32 eee_mask_to_fw2x(u32 speed) 16792ab6407SYana Esina { 16892ab6407SYana Esina u32 rate = 0; 16992ab6407SYana Esina 17092ab6407SYana Esina if (speed & AQ_NIC_RATE_EEE_10G) 17192ab6407SYana Esina rate |= HW_ATL_FW2X_CAP_EEE_10G_MASK; 17292ab6407SYana Esina if (speed & AQ_NIC_RATE_EEE_5G) 17392ab6407SYana Esina rate |= HW_ATL_FW2X_CAP_EEE_5G_MASK; 174843e1396SMark Starovoytov if (speed & AQ_NIC_RATE_EEE_2G5) 17592ab6407SYana Esina rate |= HW_ATL_FW2X_CAP_EEE_2G5_MASK; 17692ab6407SYana Esina if (speed & AQ_NIC_RATE_EEE_1G) 17792ab6407SYana Esina rate |= HW_ATL_FW2X_CAP_EEE_1G_MASK; 17892ab6407SYana Esina 17992ab6407SYana Esina return rate; 18092ab6407SYana Esina } 18192ab6407SYana Esina 182a57d3929SIgor Russkikh static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed) 183a57d3929SIgor Russkikh { 184a57d3929SIgor Russkikh u32 val = link_speed_mask_2fw2x_ratemask(speed); 185a57d3929SIgor Russkikh 186a57d3929SIgor Russkikh aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, val); 187a57d3929SIgor Russkikh 188a57d3929SIgor Russkikh return 0; 189a57d3929SIgor Russkikh } 190a57d3929SIgor Russkikh 1918009bb19SNikita Danilov static void aq_fw2x_upd_flow_control_bits(struct aq_hw_s *self, 1928009bb19SNikita Danilov u32 *mpi_state, u32 fc) 193288551deSIgor Russkikh { 1948009bb19SNikita Danilov *mpi_state &= ~(HW_ATL_FW2X_CTRL_PAUSE | 1958009bb19SNikita Danilov HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE); 196288551deSIgor Russkikh 1978009bb19SNikita Danilov switch (fc) { 1988009bb19SNikita Danilov /* There is not explicit mode of RX only pause frames, 1998009bb19SNikita Danilov * thus, we join this mode with FC full. 2008009bb19SNikita Danilov * FC full is either Rx, either Tx, or both. 2018009bb19SNikita Danilov */ 2028009bb19SNikita Danilov case AQ_NIC_FC_FULL: 2038009bb19SNikita Danilov case AQ_NIC_FC_RX: 2048009bb19SNikita Danilov *mpi_state |= HW_ATL_FW2X_CTRL_PAUSE | 2058009bb19SNikita Danilov HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE; 2068009bb19SNikita Danilov break; 2078009bb19SNikita Danilov case AQ_NIC_FC_TX: 2088009bb19SNikita Danilov *mpi_state |= HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE; 2098009bb19SNikita Danilov break; 2108009bb19SNikita Danilov } 211288551deSIgor Russkikh } 212288551deSIgor Russkikh 21392ab6407SYana Esina static void aq_fw2x_upd_eee_rate_bits(struct aq_hw_s *self, u32 *mpi_opts, 21492ab6407SYana Esina u32 eee_speeds) 21592ab6407SYana Esina { 21692ab6407SYana Esina *mpi_opts &= ~(HW_ATL_FW2X_CAP_EEE_1G_MASK | 21792ab6407SYana Esina HW_ATL_FW2X_CAP_EEE_2G5_MASK | 21892ab6407SYana Esina HW_ATL_FW2X_CAP_EEE_5G_MASK | 21992ab6407SYana Esina HW_ATL_FW2X_CAP_EEE_10G_MASK); 22092ab6407SYana Esina 22192ab6407SYana Esina *mpi_opts |= eee_mask_to_fw2x(eee_speeds); 22292ab6407SYana Esina } 22392ab6407SYana Esina 224a57d3929SIgor Russkikh static int aq_fw2x_set_state(struct aq_hw_s *self, 225a57d3929SIgor Russkikh enum hal_atl_utils_fw_state_e state) 226a57d3929SIgor Russkikh { 22744e00dd8SIgor Russkikh u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 22892ab6407SYana Esina struct aq_nic_cfg_s *cfg = self->aq_nic_cfg; 22944e00dd8SIgor Russkikh 23044e00dd8SIgor Russkikh switch (state) { 23144e00dd8SIgor Russkikh case MPI_INIT: 23244e00dd8SIgor Russkikh mpi_state &= ~BIT(CAPS_HI_LINK_DROP); 23392ab6407SYana Esina aq_fw2x_upd_eee_rate_bits(self, &mpi_state, cfg->eee_speeds); 2348009bb19SNikita Danilov aq_fw2x_upd_flow_control_bits(self, &mpi_state, 2358009bb19SNikita Danilov self->aq_nic_cfg->fc.req); 23644e00dd8SIgor Russkikh break; 23744e00dd8SIgor Russkikh case MPI_DEINIT: 23844e00dd8SIgor Russkikh mpi_state |= BIT(CAPS_HI_LINK_DROP); 23944e00dd8SIgor Russkikh break; 24044e00dd8SIgor Russkikh case MPI_RESET: 24144e00dd8SIgor Russkikh case MPI_POWER: 24244e00dd8SIgor Russkikh /* No actions */ 24344e00dd8SIgor Russkikh break; 24444e00dd8SIgor Russkikh } 24544e00dd8SIgor Russkikh aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state); 2467b0c342fSNikita Danilov 247a57d3929SIgor Russkikh return 0; 248a57d3929SIgor Russkikh } 249a57d3929SIgor Russkikh 250a57d3929SIgor Russkikh static int aq_fw2x_update_link_status(struct aq_hw_s *self) 251a57d3929SIgor Russkikh { 252a57d3929SIgor Russkikh struct aq_hw_link_status_s *link_status = &self->aq_link_status; 2537b0c342fSNikita Danilov u32 mpi_state; 2547b0c342fSNikita Danilov u32 speed; 2557b0c342fSNikita Danilov 2567b0c342fSNikita Danilov mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR); 2577b0c342fSNikita Danilov speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G | 2587b0c342fSNikita Danilov FW2X_RATE_2G5 | FW2X_RATE_5G | 2597b0c342fSNikita Danilov FW2X_RATE_10G); 260a57d3929SIgor Russkikh 261a57d3929SIgor Russkikh if (speed) { 262a57d3929SIgor Russkikh if (speed & FW2X_RATE_10G) 263a57d3929SIgor Russkikh link_status->mbps = 10000; 264a57d3929SIgor Russkikh else if (speed & FW2X_RATE_5G) 265a57d3929SIgor Russkikh link_status->mbps = 5000; 266a57d3929SIgor Russkikh else if (speed & FW2X_RATE_2G5) 267a57d3929SIgor Russkikh link_status->mbps = 2500; 268a57d3929SIgor Russkikh else if (speed & FW2X_RATE_1G) 269a57d3929SIgor Russkikh link_status->mbps = 1000; 270a57d3929SIgor Russkikh else if (speed & FW2X_RATE_100M) 271a57d3929SIgor Russkikh link_status->mbps = 100; 272a57d3929SIgor Russkikh else 273a57d3929SIgor Russkikh link_status->mbps = 10000; 274a57d3929SIgor Russkikh } else { 275a57d3929SIgor Russkikh link_status->mbps = 0; 276a57d3929SIgor Russkikh } 277071a0204SIgor Russkikh link_status->full_duplex = true; 278a57d3929SIgor Russkikh 279a57d3929SIgor Russkikh return 0; 280a57d3929SIgor Russkikh } 281a57d3929SIgor Russkikh 28276a45194SColin Ian King static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac) 283a57d3929SIgor Russkikh { 2847b0c342fSNikita Danilov u32 efuse_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_EFUSE_ADDR); 2857b0c342fSNikita Danilov u32 mac_addr[2] = { 0 }; 286a57d3929SIgor Russkikh int err = 0; 287a57d3929SIgor Russkikh 288a57d3929SIgor Russkikh if (efuse_addr != 0) { 289a57d3929SIgor Russkikh err = hw_atl_utils_fw_downld_dwords(self, 290a57d3929SIgor Russkikh efuse_addr + (40U * 4U), 291a57d3929SIgor Russkikh mac_addr, 292a57d3929SIgor Russkikh ARRAY_SIZE(mac_addr)); 293a57d3929SIgor Russkikh if (err) 294a57d3929SIgor Russkikh return err; 295a57d3929SIgor Russkikh mac_addr[0] = __swab32(mac_addr[0]); 296a57d3929SIgor Russkikh mac_addr[1] = __swab32(mac_addr[1]); 297a57d3929SIgor Russkikh } 298a57d3929SIgor Russkikh 299a57d3929SIgor Russkikh ether_addr_copy(mac, (u8 *)mac_addr); 300a57d3929SIgor Russkikh 301a57d3929SIgor Russkikh return err; 302a57d3929SIgor Russkikh } 303a57d3929SIgor Russkikh 3040ba4ad32SYueHaibing static int aq_fw2x_update_stats(struct aq_hw_s *self) 305a57d3929SIgor Russkikh { 306a57d3929SIgor Russkikh u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 307a57d3929SIgor Russkikh u32 orig_stats_val = mpi_opts & BIT(CAPS_HI_STATISTICS); 3086a7f2277SNikita Danilov u32 stats_val; 3097b0c342fSNikita Danilov int err = 0; 310a57d3929SIgor Russkikh 311a57d3929SIgor Russkikh /* Toggle statistics bit for FW to update */ 312a57d3929SIgor Russkikh mpi_opts = mpi_opts ^ BIT(CAPS_HI_STATISTICS); 313a57d3929SIgor Russkikh aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); 314a57d3929SIgor Russkikh 315a57d3929SIgor Russkikh /* Wait FW to report back */ 3166a7f2277SNikita Danilov err = readx_poll_timeout_atomic(aq_fw2x_state2_get, 3176a7f2277SNikita Danilov self, stats_val, 3186a7f2277SNikita Danilov orig_stats_val != (stats_val & 319a57d3929SIgor Russkikh BIT(CAPS_HI_STATISTICS)), 320a57d3929SIgor Russkikh 1U, 10000U); 321a57d3929SIgor Russkikh if (err) 322a57d3929SIgor Russkikh return err; 323a57d3929SIgor Russkikh 324a57d3929SIgor Russkikh return hw_atl_utils_update_stats(self); 325a57d3929SIgor Russkikh } 326a57d3929SIgor Russkikh 3278f894011SYana Esina static int aq_fw2x_get_phy_temp(struct aq_hw_s *self, int *temp) 3288f894011SYana Esina { 3298f894011SYana Esina u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 3308f894011SYana Esina u32 temp_val = mpi_opts & HW_ATL_FW2X_CTRL_TEMPERATURE; 3318f894011SYana Esina u32 phy_temp_offset; 3328f894011SYana Esina u32 temp_res; 3338f894011SYana Esina int err = 0; 3348f894011SYana Esina u32 val; 3358f894011SYana Esina 3367b0c342fSNikita Danilov phy_temp_offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox, 3377b0c342fSNikita Danilov info.phy_temperature); 3387b0c342fSNikita Danilov 3398f894011SYana Esina /* Toggle statistics bit for FW to 0x36C.18 (CTRL_TEMPERATURE) */ 3408f894011SYana Esina mpi_opts = mpi_opts ^ HW_ATL_FW2X_CTRL_TEMPERATURE; 3418f894011SYana Esina aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); 3428f894011SYana Esina /* Wait FW to report back */ 3438f894011SYana Esina err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val, 3448f894011SYana Esina temp_val != 3458f894011SYana Esina (val & HW_ATL_FW2X_CTRL_TEMPERATURE), 3468f894011SYana Esina 1U, 10000U); 3478f894011SYana Esina err = hw_atl_utils_fw_downld_dwords(self, phy_temp_offset, 3488f894011SYana Esina &temp_res, 1); 3498f894011SYana Esina 3508f894011SYana Esina if (err) 3518f894011SYana Esina return err; 3528f894011SYana Esina 3538f894011SYana Esina /* Convert PHY temperature from 1/256 degree Celsius 3548f894011SYana Esina * to 1/1000 degree Celsius. 3558f894011SYana Esina */ 3568dcf2ad3SMark Starovoytov *temp = (int16_t)(temp_res & 0xFFFF) * 1000 / 256; 3578f894011SYana Esina 3588f894011SYana Esina return 0; 3598f894011SYana Esina } 3608f894011SYana Esina 361837c6378SNikita Danilov static int aq_fw2x_set_wol(struct aq_hw_s *self, u8 *mac) 362a0da96c0SYana Esina { 3638f60f762SNikita Danilov struct hw_atl_utils_fw_rpc *rpc = NULL; 364837c6378SNikita Danilov struct offload_info *info = NULL; 365837c6378SNikita Danilov u32 wol_bits = 0; 366837c6378SNikita Danilov u32 rpc_size; 367a0da96c0SYana Esina int err = 0; 3686a7f2277SNikita Danilov u32 val; 369a0da96c0SYana Esina 370837c6378SNikita Danilov if (self->aq_nic_cfg->wol & WAKE_PHY) { 371837c6378SNikita Danilov aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, 372837c6378SNikita Danilov HW_ATL_FW2X_CTRL_LINK_DROP); 373837c6378SNikita Danilov readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val, 374837c6378SNikita Danilov (val & 375837c6378SNikita Danilov HW_ATL_FW2X_CTRL_LINK_DROP) != 0, 376837c6378SNikita Danilov 1000, 100000); 377837c6378SNikita Danilov wol_bits |= HW_ATL_FW2X_CTRL_WAKE_ON_LINK; 378837c6378SNikita Danilov } 379837c6378SNikita Danilov 380837c6378SNikita Danilov if (self->aq_nic_cfg->wol & WAKE_MAGIC) { 381837c6378SNikita Danilov wol_bits |= HW_ATL_FW2X_CTRL_SLEEP_PROXY | 382837c6378SNikita Danilov HW_ATL_FW2X_CTRL_WOL; 383a0da96c0SYana Esina 384a0da96c0SYana Esina err = hw_atl_utils_fw_rpc_wait(self, &rpc); 385a0da96c0SYana Esina if (err < 0) 386a0da96c0SYana Esina goto err_exit; 387a0da96c0SYana Esina 388837c6378SNikita Danilov rpc_size = sizeof(*info) + 389837c6378SNikita Danilov offsetof(struct hw_atl_utils_fw_rpc, fw2x_offloads); 390a0da96c0SYana Esina memset(rpc, 0, rpc_size); 391837c6378SNikita Danilov info = &rpc->fw2x_offloads; 392837c6378SNikita Danilov memcpy(info->mac_addr, mac, ETH_ALEN); 393837c6378SNikita Danilov info->len = sizeof(*info); 394a0da96c0SYana Esina 395a0da96c0SYana Esina err = hw_atl_utils_fw_rpc_call(self, rpc_size); 396a0da96c0SYana Esina if (err < 0) 397a0da96c0SYana Esina goto err_exit; 398a0da96c0SYana Esina } 399a0da96c0SYana Esina 400837c6378SNikita Danilov aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, wol_bits); 401a0da96c0SYana Esina 402a0da96c0SYana Esina err_exit: 403a0da96c0SYana Esina return err; 404a0da96c0SYana Esina } 405a0da96c0SYana Esina 406a0da96c0SYana Esina static int aq_fw2x_set_power(struct aq_hw_s *self, unsigned int power_state, 407a0da96c0SYana Esina u8 *mac) 408a0da96c0SYana Esina { 409a0da96c0SYana Esina int err = 0; 410a0da96c0SYana Esina 411837c6378SNikita Danilov if (self->aq_nic_cfg->wol) 412837c6378SNikita Danilov err = aq_fw2x_set_wol(self, mac); 413a0da96c0SYana Esina 414a0da96c0SYana Esina return err; 415a0da96c0SYana Esina } 416a0da96c0SYana Esina 417910479a9SEgor Pomozov static int aq_fw2x_send_fw_request(struct aq_hw_s *self, 418910479a9SEgor Pomozov const struct hw_fw_request_iface *fw_req, 419910479a9SEgor Pomozov size_t size) 420910479a9SEgor Pomozov { 421910479a9SEgor Pomozov u32 ctrl2, orig_ctrl2; 422910479a9SEgor Pomozov u32 dword_cnt; 423910479a9SEgor Pomozov int err = 0; 424910479a9SEgor Pomozov u32 val; 425910479a9SEgor Pomozov 426910479a9SEgor Pomozov /* Write data to drvIface Mailbox */ 427910479a9SEgor Pomozov dword_cnt = size / sizeof(u32); 428910479a9SEgor Pomozov if (size % sizeof(u32)) 429910479a9SEgor Pomozov dword_cnt++; 430dc12f75aSNikita Danilov err = hw_atl_write_fwcfg_dwords(self, (void *)fw_req, dword_cnt); 431910479a9SEgor Pomozov if (err < 0) 432910479a9SEgor Pomozov goto err_exit; 433910479a9SEgor Pomozov 434910479a9SEgor Pomozov /* Toggle statistics bit for FW to update */ 435910479a9SEgor Pomozov ctrl2 = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 436910479a9SEgor Pomozov orig_ctrl2 = ctrl2 & BIT(CAPS_HI_FW_REQUEST); 437910479a9SEgor Pomozov ctrl2 = ctrl2 ^ BIT(CAPS_HI_FW_REQUEST); 438910479a9SEgor Pomozov aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, ctrl2); 439910479a9SEgor Pomozov 440910479a9SEgor Pomozov /* Wait FW to report back */ 441910479a9SEgor Pomozov err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val, 442910479a9SEgor Pomozov orig_ctrl2 != (val & 443910479a9SEgor Pomozov BIT(CAPS_HI_FW_REQUEST)), 444910479a9SEgor Pomozov 1U, 10000U); 445910479a9SEgor Pomozov 446910479a9SEgor Pomozov err_exit: 447910479a9SEgor Pomozov return err; 448910479a9SEgor Pomozov } 449910479a9SEgor Pomozov 450910479a9SEgor Pomozov static void aq_fw3x_enable_ptp(struct aq_hw_s *self, int enable) 451910479a9SEgor Pomozov { 452910479a9SEgor Pomozov u32 ptp_opts = aq_hw_read_reg(self, HW_ATL_FW3X_EXT_STATE_ADDR); 453910479a9SEgor Pomozov u32 all_ptp_features = BIT(CAPS_EX_PHY_PTP_EN) | 454910479a9SEgor Pomozov BIT(CAPS_EX_PTP_GPIO_EN); 455910479a9SEgor Pomozov 456910479a9SEgor Pomozov if (enable) 457910479a9SEgor Pomozov ptp_opts |= all_ptp_features; 458910479a9SEgor Pomozov else 459910479a9SEgor Pomozov ptp_opts &= ~all_ptp_features; 460910479a9SEgor Pomozov 461910479a9SEgor Pomozov aq_hw_write_reg(self, HW_ATL_FW3X_EXT_CONTROL_ADDR, ptp_opts); 462910479a9SEgor Pomozov } 463910479a9SEgor Pomozov 464f08a464cSEgor Pomozov static void aq_fw3x_adjust_ptp(struct aq_hw_s *self, uint64_t adj) 465f08a464cSEgor Pomozov { 466f08a464cSEgor Pomozov aq_hw_write_reg(self, HW_ATL_FW3X_PTP_ADJ_LSW_ADDR, 467f08a464cSEgor Pomozov (adj >> 0) & 0xffffffff); 468f08a464cSEgor Pomozov aq_hw_write_reg(self, HW_ATL_FW3X_PTP_ADJ_MSW_ADDR, 469f08a464cSEgor Pomozov (adj >> 32) & 0xffffffff); 470f08a464cSEgor Pomozov } 471f08a464cSEgor Pomozov 472d1287ce4SNikita Danilov static int aq_fw2x_led_control(struct aq_hw_s *self, u32 mode) 473d1287ce4SNikita Danilov { 474d1287ce4SNikita Danilov if (self->fw_ver_actual < HW_ATL_FW_VER_LED) 475d1287ce4SNikita Danilov return -EOPNOTSUPP; 476d1287ce4SNikita Danilov 477d1287ce4SNikita Danilov aq_hw_write_reg(self, HW_ATL_FW2X_MPI_LED_ADDR, mode); 478d1287ce4SNikita Danilov 479d1287ce4SNikita Danilov return 0; 480d1287ce4SNikita Danilov } 481d1287ce4SNikita Danilov 48292ab6407SYana Esina static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed) 48392ab6407SYana Esina { 48492ab6407SYana Esina u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 48592ab6407SYana Esina 48692ab6407SYana Esina aq_fw2x_upd_eee_rate_bits(self, &mpi_opts, speed); 48792ab6407SYana Esina 48892ab6407SYana Esina aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); 48992ab6407SYana Esina 49092ab6407SYana Esina return 0; 49192ab6407SYana Esina } 49292ab6407SYana Esina 49392ab6407SYana Esina static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate, 49492ab6407SYana Esina u32 *supported_rates) 49592ab6407SYana Esina { 49692ab6407SYana Esina u32 mpi_state; 49792ab6407SYana Esina u32 caps_hi; 49892ab6407SYana Esina int err = 0; 4997b0c342fSNikita Danilov u32 offset; 50092ab6407SYana Esina 5017b0c342fSNikita Danilov offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox, 5027b0c342fSNikita Danilov info.caps_hi); 5037b0c342fSNikita Danilov 5047b0c342fSNikita Danilov err = hw_atl_utils_fw_downld_dwords(self, offset, &caps_hi, 1); 50592ab6407SYana Esina 50692ab6407SYana Esina if (err) 50792ab6407SYana Esina return err; 50892ab6407SYana Esina 50992ab6407SYana Esina *supported_rates = fw2x_to_eee_mask(caps_hi); 51092ab6407SYana Esina 5110b926d46SNikita Danilov mpi_state = aq_fw2x_state2_get(self); 51292ab6407SYana Esina *rate = fw2x_to_eee_mask(mpi_state); 51392ab6407SYana Esina 51492ab6407SYana Esina return err; 51592ab6407SYana Esina } 51692ab6407SYana Esina 517b8d68b62SAnton Mikaev static int aq_fw2x_renegotiate(struct aq_hw_s *self) 518b8d68b62SAnton Mikaev { 519b8d68b62SAnton Mikaev u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 520b8d68b62SAnton Mikaev 521b8d68b62SAnton Mikaev mpi_opts |= BIT(CTRL_FORCE_RECONNECT); 522b8d68b62SAnton Mikaev 523b8d68b62SAnton Mikaev aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); 524b8d68b62SAnton Mikaev 525b8d68b62SAnton Mikaev return 0; 526b8d68b62SAnton Mikaev } 527b8d68b62SAnton Mikaev 528288551deSIgor Russkikh static int aq_fw2x_set_flow_control(struct aq_hw_s *self) 529288551deSIgor Russkikh { 530288551deSIgor Russkikh u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 531288551deSIgor Russkikh 5328009bb19SNikita Danilov aq_fw2x_upd_flow_control_bits(self, &mpi_state, 5338009bb19SNikita Danilov self->aq_nic_cfg->fc.req); 534288551deSIgor Russkikh 535288551deSIgor Russkikh aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state); 536288551deSIgor Russkikh 537288551deSIgor Russkikh return 0; 538288551deSIgor Russkikh } 539288551deSIgor Russkikh 54035e8e8b4SIgor Russkikh static u32 aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fcmode) 54135e8e8b4SIgor Russkikh { 5420b926d46SNikita Danilov u32 mpi_state = aq_fw2x_state2_get(self); 5438009bb19SNikita Danilov *fcmode = 0; 54435e8e8b4SIgor Russkikh 54535e8e8b4SIgor Russkikh if (mpi_state & HW_ATL_FW2X_CAP_PAUSE) 5468009bb19SNikita Danilov *fcmode |= AQ_NIC_FC_RX; 5478009bb19SNikita Danilov 54835e8e8b4SIgor Russkikh if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE) 5498009bb19SNikita Danilov *fcmode |= AQ_NIC_FC_TX; 55035e8e8b4SIgor Russkikh 55135e8e8b4SIgor Russkikh return 0; 55235e8e8b4SIgor Russkikh } 55335e8e8b4SIgor Russkikh 554ea4b4d7fSIgor Russkikh static int aq_fw2x_set_phyloopback(struct aq_hw_s *self, u32 mode, bool enable) 555ea4b4d7fSIgor Russkikh { 556ea4b4d7fSIgor Russkikh u32 mpi_opts; 557ea4b4d7fSIgor Russkikh 558ea4b4d7fSIgor Russkikh switch (mode) { 559ea4b4d7fSIgor Russkikh case AQ_HW_LOOPBACK_PHYINT_SYS: 560ea4b4d7fSIgor Russkikh mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 561ea4b4d7fSIgor Russkikh if (enable) 562ea4b4d7fSIgor Russkikh mpi_opts |= HW_ATL_FW2X_CTRL_INT_LOOPBACK; 563ea4b4d7fSIgor Russkikh else 564ea4b4d7fSIgor Russkikh mpi_opts &= ~HW_ATL_FW2X_CTRL_INT_LOOPBACK; 565ea4b4d7fSIgor Russkikh aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); 566ea4b4d7fSIgor Russkikh break; 567ea4b4d7fSIgor Russkikh case AQ_HW_LOOPBACK_PHYEXT_SYS: 568ea4b4d7fSIgor Russkikh mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 569ea4b4d7fSIgor Russkikh if (enable) 570ea4b4d7fSIgor Russkikh mpi_opts |= HW_ATL_FW2X_CTRL_EXT_LOOPBACK; 571ea4b4d7fSIgor Russkikh else 572ea4b4d7fSIgor Russkikh mpi_opts &= ~HW_ATL_FW2X_CTRL_EXT_LOOPBACK; 573ea4b4d7fSIgor Russkikh aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); 574ea4b4d7fSIgor Russkikh break; 575ea4b4d7fSIgor Russkikh default: 576ea4b4d7fSIgor Russkikh return -EINVAL; 577ea4b4d7fSIgor Russkikh } 5787b0c342fSNikita Danilov 579ea4b4d7fSIgor Russkikh return 0; 580ea4b4d7fSIgor Russkikh } 581ea4b4d7fSIgor Russkikh 5826a7f2277SNikita Danilov static u32 aq_fw2x_mbox_get(struct aq_hw_s *self) 5836a7f2277SNikita Danilov { 5846a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR); 5856a7f2277SNikita Danilov } 5866a7f2277SNikita Danilov 5876a7f2277SNikita Danilov static u32 aq_fw2x_rpc_get(struct aq_hw_s *self) 5886a7f2277SNikita Danilov { 5896a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR); 5906a7f2277SNikita Danilov } 5916a7f2277SNikita Danilov 592dc12f75aSNikita Danilov static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr) 593dc12f75aSNikita Danilov { 594dc12f75aSNikita Danilov int err = 0; 595dc12f75aSNikita Danilov u32 offset; 596dc12f75aSNikita Danilov 597dc12f75aSNikita Danilov offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox, 598dc12f75aSNikita Danilov info.setting_address); 599dc12f75aSNikita Danilov 600dc12f75aSNikita Danilov err = hw_atl_utils_fw_downld_dwords(self, offset, addr, 1); 601dc12f75aSNikita Danilov 602dc12f75aSNikita Danilov return err; 603dc12f75aSNikita Danilov } 604dc12f75aSNikita Danilov 60562c1c2e6SDmitry Bogdanov static u32 aq_fw2x_state_get(struct aq_hw_s *self) 60662c1c2e6SDmitry Bogdanov { 60762c1c2e6SDmitry Bogdanov return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR); 60862c1c2e6SDmitry Bogdanov } 60962c1c2e6SDmitry Bogdanov 6106a7f2277SNikita Danilov static u32 aq_fw2x_state2_get(struct aq_hw_s *self) 6116a7f2277SNikita Danilov { 6126a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR); 6136a7f2277SNikita Danilov } 6146a7f2277SNikita Danilov 61562c1c2e6SDmitry Bogdanov static u32 aq_fw2x_get_link_capabilities(struct aq_hw_s *self) 61662c1c2e6SDmitry Bogdanov { 61762c1c2e6SDmitry Bogdanov int err = 0; 61862c1c2e6SDmitry Bogdanov u32 offset; 61962c1c2e6SDmitry Bogdanov u32 val; 62062c1c2e6SDmitry Bogdanov 62162c1c2e6SDmitry Bogdanov offset = self->mbox_addr + 62262c1c2e6SDmitry Bogdanov offsetof(struct hw_atl_utils_mbox, info.caps_lo); 62362c1c2e6SDmitry Bogdanov 62462c1c2e6SDmitry Bogdanov err = hw_atl_utils_fw_downld_dwords(self, offset, &val, 1); 62562c1c2e6SDmitry Bogdanov 62662c1c2e6SDmitry Bogdanov if (err) 62762c1c2e6SDmitry Bogdanov return 0; 62862c1c2e6SDmitry Bogdanov 62962c1c2e6SDmitry Bogdanov return val; 63062c1c2e6SDmitry Bogdanov } 63162c1c2e6SDmitry Bogdanov 63262c1c2e6SDmitry Bogdanov static int aq_fw2x_send_macsec_req(struct aq_hw_s *hw, 63362c1c2e6SDmitry Bogdanov struct macsec_msg_fw_request *req, 63462c1c2e6SDmitry Bogdanov struct macsec_msg_fw_response *response) 63562c1c2e6SDmitry Bogdanov { 63662c1c2e6SDmitry Bogdanov u32 low_status, low_req = 0; 63762c1c2e6SDmitry Bogdanov u32 dword_cnt; 63862c1c2e6SDmitry Bogdanov u32 caps_lo; 63962c1c2e6SDmitry Bogdanov u32 offset; 64062c1c2e6SDmitry Bogdanov int err; 64162c1c2e6SDmitry Bogdanov 64262c1c2e6SDmitry Bogdanov if (!req || !response) 64362c1c2e6SDmitry Bogdanov return -EINVAL; 64462c1c2e6SDmitry Bogdanov 64562c1c2e6SDmitry Bogdanov caps_lo = aq_fw2x_get_link_capabilities(hw); 64662c1c2e6SDmitry Bogdanov if (!(caps_lo & BIT(CAPS_LO_MACSEC))) 64762c1c2e6SDmitry Bogdanov return -EOPNOTSUPP; 64862c1c2e6SDmitry Bogdanov 64962c1c2e6SDmitry Bogdanov /* Write macsec request to cfg memory */ 65062c1c2e6SDmitry Bogdanov dword_cnt = (sizeof(*req) + sizeof(u32) - 1) / sizeof(u32); 65162c1c2e6SDmitry Bogdanov err = hw_atl_write_fwcfg_dwords(hw, (void *)req, dword_cnt); 65262c1c2e6SDmitry Bogdanov if (err < 0) 65362c1c2e6SDmitry Bogdanov return err; 65462c1c2e6SDmitry Bogdanov 65562c1c2e6SDmitry Bogdanov /* Toggle 0x368.CAPS_LO_MACSEC bit */ 65662c1c2e6SDmitry Bogdanov low_req = aq_hw_read_reg(hw, HW_ATL_FW2X_MPI_CONTROL_ADDR); 65762c1c2e6SDmitry Bogdanov low_req ^= HW_ATL_FW2X_CAP_MACSEC; 65862c1c2e6SDmitry Bogdanov aq_hw_write_reg(hw, HW_ATL_FW2X_MPI_CONTROL_ADDR, low_req); 65962c1c2e6SDmitry Bogdanov 66062c1c2e6SDmitry Bogdanov /* Wait FW to report back */ 66162c1c2e6SDmitry Bogdanov err = readx_poll_timeout_atomic(aq_fw2x_state_get, hw, low_status, 66262c1c2e6SDmitry Bogdanov low_req != (low_status & BIT(CAPS_LO_MACSEC)), 1U, 10000U); 66362c1c2e6SDmitry Bogdanov if (err) 66462c1c2e6SDmitry Bogdanov return -EIO; 66562c1c2e6SDmitry Bogdanov 66662c1c2e6SDmitry Bogdanov /* Read status of write operation */ 66762c1c2e6SDmitry Bogdanov offset = hw->rpc_addr + sizeof(u32); 66862c1c2e6SDmitry Bogdanov err = hw_atl_utils_fw_downld_dwords(hw, offset, (u32 *)(void *)response, 66962c1c2e6SDmitry Bogdanov sizeof(*response) / sizeof(u32)); 67062c1c2e6SDmitry Bogdanov 67162c1c2e6SDmitry Bogdanov return err; 67262c1c2e6SDmitry Bogdanov } 67362c1c2e6SDmitry Bogdanov 674a57d3929SIgor Russkikh const struct aq_fw_ops aq_fw_2x_ops = { 675a57d3929SIgor Russkikh .init = aq_fw2x_init, 67644e00dd8SIgor Russkikh .deinit = aq_fw2x_deinit, 677a57d3929SIgor Russkikh .reset = NULL, 678b8d68b62SAnton Mikaev .renegotiate = aq_fw2x_renegotiate, 679a57d3929SIgor Russkikh .get_mac_permanent = aq_fw2x_get_mac_permanent, 680a57d3929SIgor Russkikh .set_link_speed = aq_fw2x_set_link_speed, 681a57d3929SIgor Russkikh .set_state = aq_fw2x_set_state, 682a57d3929SIgor Russkikh .update_link_status = aq_fw2x_update_link_status, 683a57d3929SIgor Russkikh .update_stats = aq_fw2x_update_stats, 6848dcf2ad3SMark Starovoytov .get_mac_temp = NULL, 6858f894011SYana Esina .get_phy_temp = aq_fw2x_get_phy_temp, 686a0da96c0SYana Esina .set_power = aq_fw2x_set_power, 68792ab6407SYana Esina .set_eee_rate = aq_fw2x_set_eee_rate, 68892ab6407SYana Esina .get_eee_rate = aq_fw2x_get_eee_rate, 689288551deSIgor Russkikh .set_flow_control = aq_fw2x_set_flow_control, 690910479a9SEgor Pomozov .get_flow_control = aq_fw2x_get_flow_control, 691910479a9SEgor Pomozov .send_fw_request = aq_fw2x_send_fw_request, 692910479a9SEgor Pomozov .enable_ptp = aq_fw3x_enable_ptp, 693d1287ce4SNikita Danilov .led_control = aq_fw2x_led_control, 694ea4b4d7fSIgor Russkikh .set_phyloopback = aq_fw2x_set_phyloopback, 695f08a464cSEgor Pomozov .adjust_ptp = aq_fw3x_adjust_ptp, 69662c1c2e6SDmitry Bogdanov .get_link_capabilities = aq_fw2x_get_link_capabilities, 69762c1c2e6SDmitry Bogdanov .send_macsec_req = aq_fw2x_send_macsec_req, 698a57d3929SIgor Russkikh }; 699