175a6faf6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 298c4c201SDavid VomLehn /* 398c4c201SDavid VomLehn * aQuantia Corporation Network Driver 4593f7b43SDmitry Bezrukov * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved 598c4c201SDavid VomLehn */ 698c4c201SDavid VomLehn 798c4c201SDavid VomLehn /* File hw_atl_utils.c: Definition of common functions for Atlantic hardware 898c4c201SDavid VomLehn * abstraction layer. 998c4c201SDavid VomLehn */ 1098c4c201SDavid VomLehn 111a713f87SIgor Russkikh #include "../aq_nic.h" 1298c4c201SDavid VomLehn #include "../aq_hw_utils.h" 1398c4c201SDavid VomLehn #include "hw_atl_utils.h" 1498c4c201SDavid VomLehn #include "hw_atl_llh.h" 150c58c35fSIgor Russkikh #include "hw_atl_llh_internal.h" 1698c4c201SDavid VomLehn 1798c4c201SDavid VomLehn #include <linux/random.h> 1898c4c201SDavid VomLehn 1998c4c201SDavid VomLehn #define HW_ATL_UCP_0X370_REG 0x0370U 2098c4c201SDavid VomLehn 2147203b34SIgor Russkikh #define HW_ATL_MIF_CMD 0x0200U 2247203b34SIgor Russkikh #define HW_ATL_MIF_ADDR 0x0208U 2347203b34SIgor Russkikh #define HW_ATL_MIF_VAL 0x020CU 2447203b34SIgor Russkikh 25e7b5f97eSIgor Russkikh #define HW_ATL_MPI_RPC_ADDR 0x0334U 266a7f2277SNikita Danilov #define HW_ATL_RPC_CONTROL_ADR 0x0338U 276a7f2277SNikita Danilov #define HW_ATL_RPC_STATE_ADR 0x033CU 286a7f2277SNikita Danilov 290c58c35fSIgor Russkikh #define HW_ATL_MPI_FW_VERSION 0x18 3098c4c201SDavid VomLehn #define HW_ATL_MPI_CONTROL_ADR 0x0368U 3198c4c201SDavid VomLehn #define HW_ATL_MPI_STATE_ADR 0x036CU 3298c4c201SDavid VomLehn 3398c4c201SDavid VomLehn #define HW_ATL_MPI_STATE_MSK 0x00FFU 3498c4c201SDavid VomLehn #define HW_ATL_MPI_STATE_SHIFT 0U 3544e00dd8SIgor Russkikh #define HW_ATL_MPI_SPEED_MSK 0x00FF0000U 3698c4c201SDavid VomLehn #define HW_ATL_MPI_SPEED_SHIFT 16U 3744e00dd8SIgor Russkikh #define HW_ATL_MPI_DIRTY_WAKE_MSK 0x02000000U 3898c4c201SDavid VomLehn 39c8c82eb3SIgor Russkikh #define HW_ATL_MPI_DAISY_CHAIN_STATUS 0x704 40c8c82eb3SIgor Russkikh #define HW_ATL_MPI_BOOT_EXIT_CODE 0x388 41c8c82eb3SIgor Russkikh 42c8c82eb3SIgor Russkikh #define HW_ATL_MAC_PHY_CONTROL 0x4000 43c8c82eb3SIgor Russkikh #define HW_ATL_MAC_PHY_MPI_RESET_BIT 0x1D 44c8c82eb3SIgor Russkikh 450c58c35fSIgor Russkikh #define HW_ATL_FW_VER_1X 0x01050006U 46a57d3929SIgor Russkikh #define HW_ATL_FW_VER_2X 0x02000000U 47a57d3929SIgor Russkikh #define HW_ATL_FW_VER_3X 0x03000000U 480c58c35fSIgor Russkikh 49c8c82eb3SIgor Russkikh #define FORCE_FLASHLESS 0 50c8c82eb3SIgor Russkikh 51dc12f75aSNikita Danilov enum mcp_area { 52dc12f75aSNikita Danilov MCP_AREA_CONFIG = 0x80000000, 53dc12f75aSNikita Danilov MCP_AREA_SETTINGS = 0x20000000, 54dc12f75aSNikita Danilov }; 55dc12f75aSNikita Danilov 560c58c35fSIgor Russkikh static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual); 57cce96d18SIgor Russkikh static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self, 58cce96d18SIgor Russkikh enum hal_atl_utils_fw_state_e state); 596a7f2277SNikita Danilov static u32 hw_atl_utils_get_mpi_mbox_tid(struct aq_hw_s *self); 606a7f2277SNikita Danilov static u32 hw_atl_utils_mpi_get_state(struct aq_hw_s *self); 616a7f2277SNikita Danilov static u32 hw_atl_utils_mif_cmd_get(struct aq_hw_s *self); 626a7f2277SNikita Danilov static u32 hw_atl_utils_mif_addr_get(struct aq_hw_s *self); 636a7f2277SNikita Danilov static u32 hw_atl_utils_rpc_state_get(struct aq_hw_s *self); 64e7b5f97eSIgor Russkikh static u32 aq_fw1x_rpc_get(struct aq_hw_s *self); 656a7f2277SNikita Danilov 660c58c35fSIgor Russkikh int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops) 670c58c35fSIgor Russkikh { 680c58c35fSIgor Russkikh int err = 0; 690c58c35fSIgor Russkikh 700c58c35fSIgor Russkikh hw_atl_utils_hw_chip_features_init(self, 710c58c35fSIgor Russkikh &self->chip_features); 720c58c35fSIgor Russkikh 7336e90a52SNikita Danilov self->fw_ver_actual = hw_atl_utils_get_fw_version(self); 740c58c35fSIgor Russkikh 75c8c82eb3SIgor Russkikh if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, 76c8c82eb3SIgor Russkikh self->fw_ver_actual) == 0) { 770c58c35fSIgor Russkikh *fw_ops = &aq_fw_1x_ops; 78c8c82eb3SIgor Russkikh } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X, 79c8c82eb3SIgor Russkikh self->fw_ver_actual) == 0) { 80a57d3929SIgor Russkikh *fw_ops = &aq_fw_2x_ops; 81c8c82eb3SIgor Russkikh } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X, 82c8c82eb3SIgor Russkikh self->fw_ver_actual) == 0) { 83a57d3929SIgor Russkikh *fw_ops = &aq_fw_2x_ops; 84c8c82eb3SIgor Russkikh } else { 850c58c35fSIgor Russkikh aq_pr_err("Bad FW version detected: %x\n", 860c58c35fSIgor Russkikh self->fw_ver_actual); 870c58c35fSIgor Russkikh return -EOPNOTSUPP; 880c58c35fSIgor Russkikh } 890c58c35fSIgor Russkikh self->aq_fw_ops = *fw_ops; 900c58c35fSIgor Russkikh err = self->aq_fw_ops->init(self); 917b0c342fSNikita Danilov 920c58c35fSIgor Russkikh return err; 930c58c35fSIgor Russkikh } 940c58c35fSIgor Russkikh 95c8c82eb3SIgor Russkikh static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self) 96c8c82eb3SIgor Russkikh { 971bf9a752SIgor Russkikh u32 gsr, val; 98c8c82eb3SIgor Russkikh int k = 0; 99c8c82eb3SIgor Russkikh 100c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x40e1); 101c8c82eb3SIgor Russkikh AQ_HW_SLEEP(50); 102c8c82eb3SIgor Russkikh 103c8c82eb3SIgor Russkikh /* Cleanup SPI */ 1041bf9a752SIgor Russkikh val = aq_hw_read_reg(self, 0x53C); 1051bf9a752SIgor Russkikh aq_hw_write_reg(self, 0x53C, val | 0x10); 106c8c82eb3SIgor Russkikh 107c8c82eb3SIgor Russkikh gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR); 108c8c82eb3SIgor Russkikh aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000); 109c8c82eb3SIgor Russkikh 110c8c82eb3SIgor Russkikh /* Kickstart MAC */ 111c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x80e0); 112c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x32a8, 0x0); 113c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x520, 0x1); 1141bf9a752SIgor Russkikh 1151bf9a752SIgor Russkikh /* Reset SPI again because of possible interrupted SPI burst */ 1161bf9a752SIgor Russkikh val = aq_hw_read_reg(self, 0x53C); 1171bf9a752SIgor Russkikh aq_hw_write_reg(self, 0x53C, val | 0x10); 118c8c82eb3SIgor Russkikh AQ_HW_SLEEP(10); 1191bf9a752SIgor Russkikh /* Clear SPI reset state */ 1201bf9a752SIgor Russkikh aq_hw_write_reg(self, 0x53C, val & ~0x10); 1211bf9a752SIgor Russkikh 122c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x180e0); 123c8c82eb3SIgor Russkikh 124c8c82eb3SIgor Russkikh for (k = 0; k < 1000; k++) { 125c8c82eb3SIgor Russkikh u32 flb_status = aq_hw_read_reg(self, 126c8c82eb3SIgor Russkikh HW_ATL_MPI_DAISY_CHAIN_STATUS); 127c8c82eb3SIgor Russkikh 128c8c82eb3SIgor Russkikh flb_status = flb_status & 0x10; 129c8c82eb3SIgor Russkikh if (flb_status) 130c8c82eb3SIgor Russkikh break; 131c8c82eb3SIgor Russkikh AQ_HW_SLEEP(10); 132c8c82eb3SIgor Russkikh } 133c8c82eb3SIgor Russkikh if (k == 1000) { 134c8c82eb3SIgor Russkikh aq_pr_err("MAC kickstart failed\n"); 135c8c82eb3SIgor Russkikh return -EIO; 136c8c82eb3SIgor Russkikh } 137c8c82eb3SIgor Russkikh 138c8c82eb3SIgor Russkikh /* FW reset */ 139c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x80e0); 140c8c82eb3SIgor Russkikh AQ_HW_SLEEP(50); 141c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x3a0, 0x1); 142c8c82eb3SIgor Russkikh 143c8c82eb3SIgor Russkikh /* Kickstart PHY - skipped */ 144c8c82eb3SIgor Russkikh 145c8c82eb3SIgor Russkikh /* Global software reset*/ 146c8c82eb3SIgor Russkikh hw_atl_rx_rx_reg_res_dis_set(self, 0U); 147c8c82eb3SIgor Russkikh hw_atl_tx_tx_reg_res_dis_set(self, 0U); 148c8c82eb3SIgor Russkikh aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL, 149c8c82eb3SIgor Russkikh BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT), 150c8c82eb3SIgor Russkikh HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0); 151c8c82eb3SIgor Russkikh gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR); 152c8c82eb3SIgor Russkikh aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000); 153c8c82eb3SIgor Russkikh 154c8c82eb3SIgor Russkikh for (k = 0; k < 1000; k++) { 155c8c82eb3SIgor Russkikh u32 fw_state = aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION); 156c8c82eb3SIgor Russkikh 157c8c82eb3SIgor Russkikh if (fw_state) 158c8c82eb3SIgor Russkikh break; 159c8c82eb3SIgor Russkikh AQ_HW_SLEEP(10); 160c8c82eb3SIgor Russkikh } 161c8c82eb3SIgor Russkikh if (k == 1000) { 162c8c82eb3SIgor Russkikh aq_pr_err("FW kickstart failed\n"); 163c8c82eb3SIgor Russkikh return -EIO; 164c8c82eb3SIgor Russkikh } 165d0f0fb25SIgor Russkikh /* Old FW requires fixed delay after init */ 166d0f0fb25SIgor Russkikh AQ_HW_SLEEP(15); 167c8c82eb3SIgor Russkikh 168c8c82eb3SIgor Russkikh return 0; 169c8c82eb3SIgor Russkikh } 170c8c82eb3SIgor Russkikh 171c8c82eb3SIgor Russkikh static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self) 172c8c82eb3SIgor Russkikh { 1731bf9a752SIgor Russkikh u32 gsr, val, rbl_status; 174c8c82eb3SIgor Russkikh int k; 175c8c82eb3SIgor Russkikh 176c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x40e1); 177c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x3a0, 0x1); 178c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x32a8, 0x0); 179c8c82eb3SIgor Russkikh 180c8c82eb3SIgor Russkikh /* Alter RBL status */ 181c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x388, 0xDEAD); 182c8c82eb3SIgor Russkikh 1831bf9a752SIgor Russkikh /* Cleanup SPI */ 1841bf9a752SIgor Russkikh val = aq_hw_read_reg(self, 0x53C); 1851bf9a752SIgor Russkikh aq_hw_write_reg(self, 0x53C, val | 0x10); 1861bf9a752SIgor Russkikh 187c8c82eb3SIgor Russkikh /* Global software reset*/ 188c8c82eb3SIgor Russkikh hw_atl_rx_rx_reg_res_dis_set(self, 0U); 189c8c82eb3SIgor Russkikh hw_atl_tx_tx_reg_res_dis_set(self, 0U); 190c8c82eb3SIgor Russkikh aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL, 191c8c82eb3SIgor Russkikh BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT), 192c8c82eb3SIgor Russkikh HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0); 193c8c82eb3SIgor Russkikh gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR); 194c8c82eb3SIgor Russkikh aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, 195c8c82eb3SIgor Russkikh (gsr & 0xFFFFBFFF) | 0x8000); 196c8c82eb3SIgor Russkikh 197c8c82eb3SIgor Russkikh if (FORCE_FLASHLESS) 198c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x534, 0x0); 199c8c82eb3SIgor Russkikh 200c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x40e0); 201c8c82eb3SIgor Russkikh 202c8c82eb3SIgor Russkikh /* Wait for RBL boot */ 203c8c82eb3SIgor Russkikh for (k = 0; k < 1000; k++) { 204c8c82eb3SIgor Russkikh rbl_status = aq_hw_read_reg(self, 0x388) & 0xFFFF; 205c8c82eb3SIgor Russkikh if (rbl_status && rbl_status != 0xDEAD) 206c8c82eb3SIgor Russkikh break; 207c8c82eb3SIgor Russkikh AQ_HW_SLEEP(10); 208c8c82eb3SIgor Russkikh } 209c8c82eb3SIgor Russkikh if (!rbl_status || rbl_status == 0xDEAD) { 210c8c82eb3SIgor Russkikh aq_pr_err("RBL Restart failed"); 211c8c82eb3SIgor Russkikh return -EIO; 212c8c82eb3SIgor Russkikh } 213c8c82eb3SIgor Russkikh 214c8c82eb3SIgor Russkikh /* Restore NVR */ 215c8c82eb3SIgor Russkikh if (FORCE_FLASHLESS) 216c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x534, 0xA0); 217c8c82eb3SIgor Russkikh 218c8c82eb3SIgor Russkikh if (rbl_status == 0xF1A7) { 219c8c82eb3SIgor Russkikh aq_pr_err("No FW detected. Dynamic FW load not implemented\n"); 220c8c82eb3SIgor Russkikh return -ENOTSUPP; 221c8c82eb3SIgor Russkikh } 222c8c82eb3SIgor Russkikh 223c8c82eb3SIgor Russkikh for (k = 0; k < 1000; k++) { 224c8c82eb3SIgor Russkikh u32 fw_state = aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION); 225c8c82eb3SIgor Russkikh 226c8c82eb3SIgor Russkikh if (fw_state) 227c8c82eb3SIgor Russkikh break; 228c8c82eb3SIgor Russkikh AQ_HW_SLEEP(10); 229c8c82eb3SIgor Russkikh } 230c8c82eb3SIgor Russkikh if (k == 1000) { 231c8c82eb3SIgor Russkikh aq_pr_err("FW kickstart failed\n"); 232c8c82eb3SIgor Russkikh return -EIO; 233c8c82eb3SIgor Russkikh } 234d0f0fb25SIgor Russkikh /* Old FW requires fixed delay after init */ 235d0f0fb25SIgor Russkikh AQ_HW_SLEEP(15); 236c8c82eb3SIgor Russkikh 237c8c82eb3SIgor Russkikh return 0; 238c8c82eb3SIgor Russkikh } 239c8c82eb3SIgor Russkikh 240c8c82eb3SIgor Russkikh int hw_atl_utils_soft_reset(struct aq_hw_s *self) 241c8c82eb3SIgor Russkikh { 242c8c82eb3SIgor Russkikh u32 boot_exit_code = 0; 2436a7f2277SNikita Danilov u32 val; 2447b0c342fSNikita Danilov int k; 245c8c82eb3SIgor Russkikh 246c8c82eb3SIgor Russkikh for (k = 0; k < 1000; ++k) { 247c8c82eb3SIgor Russkikh u32 flb_status = aq_hw_read_reg(self, 248c8c82eb3SIgor Russkikh HW_ATL_MPI_DAISY_CHAIN_STATUS); 249c8c82eb3SIgor Russkikh boot_exit_code = aq_hw_read_reg(self, 250c8c82eb3SIgor Russkikh HW_ATL_MPI_BOOT_EXIT_CODE); 251c8c82eb3SIgor Russkikh if (flb_status != 0x06000000 || boot_exit_code != 0) 252c8c82eb3SIgor Russkikh break; 253c8c82eb3SIgor Russkikh } 254c8c82eb3SIgor Russkikh 255c8c82eb3SIgor Russkikh if (k == 1000) { 256c8c82eb3SIgor Russkikh aq_pr_err("Neither RBL nor FLB firmware started\n"); 257c8c82eb3SIgor Russkikh return -EOPNOTSUPP; 258c8c82eb3SIgor Russkikh } 259c8c82eb3SIgor Russkikh 260c8c82eb3SIgor Russkikh self->rbl_enabled = (boot_exit_code != 0); 261c8c82eb3SIgor Russkikh 262cce96d18SIgor Russkikh /* FW 1.x may bootup in an invalid POWER state (WOL feature). 263cce96d18SIgor Russkikh * We should work around this by forcing its state back to DEINIT 264cce96d18SIgor Russkikh */ 265cce96d18SIgor Russkikh if (!hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, 266cce96d18SIgor Russkikh aq_hw_read_reg(self, 267cce96d18SIgor Russkikh HW_ATL_MPI_FW_VERSION))) { 268cce96d18SIgor Russkikh int err = 0; 269cce96d18SIgor Russkikh 270cce96d18SIgor Russkikh hw_atl_utils_mpi_set_state(self, MPI_DEINIT); 2716a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_mpi_get_state, 2726a7f2277SNikita Danilov self, val, 2736a7f2277SNikita Danilov (val & HW_ATL_MPI_STATE_MSK) == 2746a7f2277SNikita Danilov MPI_DEINIT, 2756a7f2277SNikita Danilov 10, 10000U); 2764e3c7c00SYueHaibing if (err) 2774e3c7c00SYueHaibing return err; 278cce96d18SIgor Russkikh } 279cce96d18SIgor Russkikh 280c8c82eb3SIgor Russkikh if (self->rbl_enabled) 281c8c82eb3SIgor Russkikh return hw_atl_utils_soft_reset_rbl(self); 282c8c82eb3SIgor Russkikh else 283c8c82eb3SIgor Russkikh return hw_atl_utils_soft_reset_flb(self); 284c8c82eb3SIgor Russkikh } 285c8c82eb3SIgor Russkikh 286a57d3929SIgor Russkikh int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a, 28798c4c201SDavid VomLehn u32 *p, u32 cnt) 28898c4c201SDavid VomLehn { 28998c4c201SDavid VomLehn int err = 0; 2906a7f2277SNikita Danilov u32 val; 29198c4c201SDavid VomLehn 2926a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_sem_ram_get, 2936a7f2277SNikita Danilov self, val, val == 1U, 29498c4c201SDavid VomLehn 1U, 10000U); 29598c4c201SDavid VomLehn 29698c4c201SDavid VomLehn if (err < 0) { 29798c4c201SDavid VomLehn bool is_locked; 29898c4c201SDavid VomLehn 2998e1c072fSIgor Russkikh hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM); 3000b926d46SNikita Danilov is_locked = hw_atl_sem_ram_get(self); 30198c4c201SDavid VomLehn if (!is_locked) { 30298c4c201SDavid VomLehn err = -ETIME; 30398c4c201SDavid VomLehn goto err_exit; 30498c4c201SDavid VomLehn } 30598c4c201SDavid VomLehn } 30698c4c201SDavid VomLehn 30747203b34SIgor Russkikh aq_hw_write_reg(self, HW_ATL_MIF_ADDR, a); 30898c4c201SDavid VomLehn 30947203b34SIgor Russkikh for (++cnt; --cnt && !err;) { 31047203b34SIgor Russkikh aq_hw_write_reg(self, HW_ATL_MIF_CMD, 0x00008000U); 31198c4c201SDavid VomLehn 312d1ad88feSMark Starovoytov if (ATL_HW_IS_CHIP_FEATURE(self, REVISION_B1)) 3136a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_mif_addr_get, 3146a7f2277SNikita Danilov self, val, val != a, 3156a7f2277SNikita Danilov 1U, 1000U); 31647203b34SIgor Russkikh else 3176a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_mif_cmd_get, 3186a7f2277SNikita Danilov self, val, 3196a7f2277SNikita Danilov !(val & 0x100), 3206a7f2277SNikita Danilov 1U, 1000U); 32198c4c201SDavid VomLehn 32247203b34SIgor Russkikh *(p++) = aq_hw_read_reg(self, HW_ATL_MIF_VAL); 32347203b34SIgor Russkikh a += 4; 32498c4c201SDavid VomLehn } 32598c4c201SDavid VomLehn 3268e1c072fSIgor Russkikh hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM); 32798c4c201SDavid VomLehn 32898c4c201SDavid VomLehn err_exit: 32998c4c201SDavid VomLehn return err; 33098c4c201SDavid VomLehn } 33198c4c201SDavid VomLehn 332dc12f75aSNikita Danilov static int hw_atl_utils_write_b1_mbox(struct aq_hw_s *self, u32 addr, 333dc12f75aSNikita Danilov u32 *p, u32 cnt, enum mcp_area area) 33498c4c201SDavid VomLehn { 335dc12f75aSNikita Danilov u32 data_offset = 0; 336dc12f75aSNikita Danilov u32 offset = addr; 33798c4c201SDavid VomLehn int err = 0; 338dc12f75aSNikita Danilov u32 val; 33998c4c201SDavid VomLehn 340dc12f75aSNikita Danilov switch (area) { 341dc12f75aSNikita Danilov case MCP_AREA_CONFIG: 342dc12f75aSNikita Danilov offset -= self->rpc_addr; 343dc12f75aSNikita Danilov break; 344930b9a05SNikita Danilov 345dc12f75aSNikita Danilov case MCP_AREA_SETTINGS: 346dc12f75aSNikita Danilov offset -= self->settings_addr; 347dc12f75aSNikita Danilov break; 348dc12f75aSNikita Danilov } 34998c4c201SDavid VomLehn 350dc12f75aSNikita Danilov offset = offset / sizeof(u32); 351dc12f75aSNikita Danilov 352dc12f75aSNikita Danilov for (; data_offset < cnt; ++data_offset, ++offset) { 353dc12f75aSNikita Danilov aq_hw_write_reg(self, 0x328, p[data_offset]); 3543ee5c887SYana Esina aq_hw_write_reg(self, 0x32C, 355dc12f75aSNikita Danilov (area | (0xFFFF & (offset * 4)))); 3563ee5c887SYana Esina hw_atl_mcp_up_force_intr_set(self, 1); 3573ee5c887SYana Esina /* 1000 times by 10us = 10ms */ 3586a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_scrpad12_get, 3596a7f2277SNikita Danilov self, val, 360930b9a05SNikita Danilov (val & 0xF0000000) != 361dc12f75aSNikita Danilov area, 3626a7f2277SNikita Danilov 10U, 10000U); 36398c4c201SDavid VomLehn 364dc12f75aSNikita Danilov if (err < 0) 365dc12f75aSNikita Danilov break; 366dc12f75aSNikita Danilov } 367dc12f75aSNikita Danilov 368dc12f75aSNikita Danilov return err; 369dc12f75aSNikita Danilov } 370dc12f75aSNikita Danilov 371dc12f75aSNikita Danilov static int hw_atl_utils_write_b0_mbox(struct aq_hw_s *self, u32 addr, 372dc12f75aSNikita Danilov u32 *p, u32 cnt) 373dc12f75aSNikita Danilov { 374dc12f75aSNikita Danilov u32 offset = 0; 375dc12f75aSNikita Danilov int err = 0; 376dc12f75aSNikita Danilov u32 val; 377dc12f75aSNikita Danilov 378dc12f75aSNikita Danilov aq_hw_write_reg(self, 0x208, addr); 37998c4c201SDavid VomLehn 3803ee5c887SYana Esina for (; offset < cnt; ++offset) { 3813ee5c887SYana Esina aq_hw_write_reg(self, 0x20C, p[offset]); 3823ee5c887SYana Esina aq_hw_write_reg(self, 0x200, 0xC000); 38398c4c201SDavid VomLehn 3846a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_mif_cmd_get, 3856a7f2277SNikita Danilov self, val, 386dc12f75aSNikita Danilov (val & 0x100) == 0U, 387dc12f75aSNikita Danilov 10U, 10000U); 388dc12f75aSNikita Danilov 389dc12f75aSNikita Danilov if (err < 0) 390dc12f75aSNikita Danilov break; 39198c4c201SDavid VomLehn } 392dc12f75aSNikita Danilov 393dc12f75aSNikita Danilov return err; 39498c4c201SDavid VomLehn } 39598c4c201SDavid VomLehn 396dc12f75aSNikita Danilov static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 addr, u32 *p, 397dc12f75aSNikita Danilov u32 cnt, enum mcp_area area) 398dc12f75aSNikita Danilov { 399dc12f75aSNikita Danilov int err = 0; 400dc12f75aSNikita Danilov u32 val; 401dc12f75aSNikita Danilov 402dc12f75aSNikita Danilov err = readx_poll_timeout_atomic(hw_atl_sem_ram_get, self, 403dc12f75aSNikita Danilov val, val == 1U, 404dc12f75aSNikita Danilov 10U, 100000U); 405dc12f75aSNikita Danilov if (err < 0) 406dc12f75aSNikita Danilov goto err_exit; 407dc12f75aSNikita Danilov 408d1ad88feSMark Starovoytov if (ATL_HW_IS_CHIP_FEATURE(self, REVISION_B1)) 409dc12f75aSNikita Danilov err = hw_atl_utils_write_b1_mbox(self, addr, p, cnt, area); 410dc12f75aSNikita Danilov else 411dc12f75aSNikita Danilov err = hw_atl_utils_write_b0_mbox(self, addr, p, cnt); 412dc12f75aSNikita Danilov 4138e1c072fSIgor Russkikh hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM); 41498c4c201SDavid VomLehn 415dc12f75aSNikita Danilov if (err < 0) 416dc12f75aSNikita Danilov goto err_exit; 417dc12f75aSNikita Danilov 418dc12f75aSNikita Danilov err = aq_hw_err_from_flags(self); 419dc12f75aSNikita Danilov 42098c4c201SDavid VomLehn err_exit: 42198c4c201SDavid VomLehn return err; 42298c4c201SDavid VomLehn } 42398c4c201SDavid VomLehn 424dc12f75aSNikita Danilov int hw_atl_write_fwcfg_dwords(struct aq_hw_s *self, u32 *p, u32 cnt) 425dc12f75aSNikita Danilov { 426dc12f75aSNikita Danilov return hw_atl_utils_fw_upload_dwords(self, self->rpc_addr, p, 427dc12f75aSNikita Danilov cnt, MCP_AREA_CONFIG); 428dc12f75aSNikita Danilov } 429dc12f75aSNikita Danilov 430dc12f75aSNikita Danilov int hw_atl_write_fwsettings_dwords(struct aq_hw_s *self, u32 offset, u32 *p, 431dc12f75aSNikita Danilov u32 cnt) 432dc12f75aSNikita Danilov { 433dc12f75aSNikita Danilov return hw_atl_utils_fw_upload_dwords(self, self->settings_addr + offset, 434dc12f75aSNikita Danilov p, cnt, MCP_AREA_SETTINGS); 435dc12f75aSNikita Danilov } 436dc12f75aSNikita Danilov 43798c4c201SDavid VomLehn static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual) 43898c4c201SDavid VomLehn { 43998c4c201SDavid VomLehn const u32 dw_major_mask = 0xff000000U; 44098c4c201SDavid VomLehn const u32 dw_minor_mask = 0x00ffffffU; 4417b0c342fSNikita Danilov int err = 0; 44298c4c201SDavid VomLehn 44398c4c201SDavid VomLehn err = (dw_major_mask & (ver_expected ^ ver_actual)) ? -EOPNOTSUPP : 0; 44498c4c201SDavid VomLehn if (err < 0) 44598c4c201SDavid VomLehn goto err_exit; 44698c4c201SDavid VomLehn err = ((dw_minor_mask & ver_expected) > (dw_minor_mask & ver_actual)) ? 44798c4c201SDavid VomLehn -EOPNOTSUPP : 0; 4487b0c342fSNikita Danilov 44998c4c201SDavid VomLehn err_exit: 45098c4c201SDavid VomLehn return err; 45198c4c201SDavid VomLehn } 45298c4c201SDavid VomLehn 45398c4c201SDavid VomLehn static int hw_atl_utils_init_ucp(struct aq_hw_s *self, 4544cbc9f92SIgor Russkikh const struct aq_hw_caps_s *aq_hw_caps) 45598c4c201SDavid VomLehn { 45698c4c201SDavid VomLehn int err = 0; 45798c4c201SDavid VomLehn 45898c4c201SDavid VomLehn if (!aq_hw_read_reg(self, 0x370U)) { 45998c4c201SDavid VomLehn unsigned int rnd = 0U; 46098c4c201SDavid VomLehn unsigned int ucp_0x370 = 0U; 46198c4c201SDavid VomLehn 46298c4c201SDavid VomLehn get_random_bytes(&rnd, sizeof(unsigned int)); 46398c4c201SDavid VomLehn 46498c4c201SDavid VomLehn ucp_0x370 = 0x02020202U | (0xFEFEFEFEU & rnd); 46598c4c201SDavid VomLehn aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370); 46698c4c201SDavid VomLehn } 46798c4c201SDavid VomLehn 4688e1c072fSIgor Russkikh hw_atl_reg_glb_cpu_scratch_scp_set(self, 0x00000000U, 25U); 46998c4c201SDavid VomLehn 47098c4c201SDavid VomLehn /* check 10 times by 1ms */ 4716a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_scrpad25_get, 4726a7f2277SNikita Danilov self, self->mbox_addr, 4736a7f2277SNikita Danilov self->mbox_addr != 0U, 4746a7f2277SNikita Danilov 1000U, 10000U); 475e7b5f97eSIgor Russkikh err = readx_poll_timeout_atomic(aq_fw1x_rpc_get, self, 476e7b5f97eSIgor Russkikh self->rpc_addr, 477e7b5f97eSIgor Russkikh self->rpc_addr != 0U, 478e7b5f97eSIgor Russkikh 1000U, 100000U); 47998c4c201SDavid VomLehn 48098c4c201SDavid VomLehn return err; 48198c4c201SDavid VomLehn } 48298c4c201SDavid VomLehn 48398c4c201SDavid VomLehn struct aq_hw_atl_utils_fw_rpc_tid_s { 48498c4c201SDavid VomLehn union { 48598c4c201SDavid VomLehn u32 val; 48698c4c201SDavid VomLehn struct { 48798c4c201SDavid VomLehn u16 tid; 48898c4c201SDavid VomLehn u16 len; 48998c4c201SDavid VomLehn }; 49098c4c201SDavid VomLehn }; 49198c4c201SDavid VomLehn }; 49298c4c201SDavid VomLehn 49398c4c201SDavid VomLehn #define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL) 49498c4c201SDavid VomLehn 4953ee5c887SYana Esina int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size) 49698c4c201SDavid VomLehn { 49798c4c201SDavid VomLehn struct aq_hw_atl_utils_fw_rpc_tid_s sw; 4987b0c342fSNikita Danilov int err = 0; 49998c4c201SDavid VomLehn 500d1ad88feSMark Starovoytov if (!ATL_HW_IS_CHIP_FEATURE(self, MIPS)) { 50198c4c201SDavid VomLehn err = -1; 50298c4c201SDavid VomLehn goto err_exit; 50398c4c201SDavid VomLehn } 504dc12f75aSNikita Danilov err = hw_atl_write_fwcfg_dwords(self, (u32 *)(void *)&self->rpc, 50598c4c201SDavid VomLehn (rpc_size + sizeof(u32) - 50698c4c201SDavid VomLehn sizeof(u8)) / sizeof(u32)); 50798c4c201SDavid VomLehn if (err < 0) 50898c4c201SDavid VomLehn goto err_exit; 50998c4c201SDavid VomLehn 5101a713f87SIgor Russkikh sw.tid = 0xFFFFU & (++self->rpc_tid); 51198c4c201SDavid VomLehn sw.len = (u16)rpc_size; 51298c4c201SDavid VomLehn aq_hw_write_reg(self, HW_ATL_RPC_CONTROL_ADR, sw.val); 51398c4c201SDavid VomLehn 51498c4c201SDavid VomLehn err_exit: 51598c4c201SDavid VomLehn return err; 51698c4c201SDavid VomLehn } 51798c4c201SDavid VomLehn 5183ee5c887SYana Esina int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self, 5198f60f762SNikita Danilov struct hw_atl_utils_fw_rpc **rpc) 52098c4c201SDavid VomLehn { 52198c4c201SDavid VomLehn struct aq_hw_atl_utils_fw_rpc_tid_s sw; 52298c4c201SDavid VomLehn struct aq_hw_atl_utils_fw_rpc_tid_s fw; 5237b0c342fSNikita Danilov int err = 0; 52498c4c201SDavid VomLehn 52598c4c201SDavid VomLehn do { 52698c4c201SDavid VomLehn sw.val = aq_hw_read_reg(self, HW_ATL_RPC_CONTROL_ADR); 52798c4c201SDavid VomLehn 5281a713f87SIgor Russkikh self->rpc_tid = sw.tid; 52998c4c201SDavid VomLehn 5306a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_rpc_state_get, 5316a7f2277SNikita Danilov self, fw.val, 5326a7f2277SNikita Danilov sw.tid == fw.tid, 5336a7f2277SNikita Danilov 1000U, 100000U); 534e7b5f97eSIgor Russkikh if (err < 0) 535e7b5f97eSIgor Russkikh goto err_exit; 536e7b5f97eSIgor Russkikh 537e7b5f97eSIgor Russkikh err = aq_hw_err_from_flags(self); 538e7b5f97eSIgor Russkikh if (err < 0) 539e7b5f97eSIgor Russkikh goto err_exit; 54098c4c201SDavid VomLehn 54198c4c201SDavid VomLehn if (fw.len == 0xFFFFU) { 54298c4c201SDavid VomLehn err = hw_atl_utils_fw_rpc_call(self, sw.len); 54398c4c201SDavid VomLehn if (err < 0) 54498c4c201SDavid VomLehn goto err_exit; 54598c4c201SDavid VomLehn } 54698c4c201SDavid VomLehn } while (sw.tid != fw.tid || 0xFFFFU == fw.len); 54798c4c201SDavid VomLehn 54898c4c201SDavid VomLehn if (rpc) { 54998c4c201SDavid VomLehn if (fw.len) { 55098c4c201SDavid VomLehn err = 55198c4c201SDavid VomLehn hw_atl_utils_fw_downld_dwords(self, 5521a713f87SIgor Russkikh self->rpc_addr, 55398c4c201SDavid VomLehn (u32 *)(void *) 5541a713f87SIgor Russkikh &self->rpc, 55598c4c201SDavid VomLehn (fw.len + sizeof(u32) - 55698c4c201SDavid VomLehn sizeof(u8)) / 55798c4c201SDavid VomLehn sizeof(u32)); 55898c4c201SDavid VomLehn if (err < 0) 55998c4c201SDavid VomLehn goto err_exit; 56098c4c201SDavid VomLehn } 56198c4c201SDavid VomLehn 5621a713f87SIgor Russkikh *rpc = &self->rpc; 56398c4c201SDavid VomLehn } 56498c4c201SDavid VomLehn 56598c4c201SDavid VomLehn err_exit: 56698c4c201SDavid VomLehn return err; 56798c4c201SDavid VomLehn } 56898c4c201SDavid VomLehn 5691a713f87SIgor Russkikh static int hw_atl_utils_mpi_create(struct aq_hw_s *self) 57098c4c201SDavid VomLehn { 57198c4c201SDavid VomLehn int err = 0; 57298c4c201SDavid VomLehn 5731a713f87SIgor Russkikh err = hw_atl_utils_init_ucp(self, self->aq_nic_cfg->aq_hw_caps); 57498c4c201SDavid VomLehn if (err < 0) 57598c4c201SDavid VomLehn goto err_exit; 57698c4c201SDavid VomLehn 57798c4c201SDavid VomLehn err = hw_atl_utils_fw_rpc_init(self); 57898c4c201SDavid VomLehn if (err < 0) 57998c4c201SDavid VomLehn goto err_exit; 58098c4c201SDavid VomLehn 58198c4c201SDavid VomLehn err_exit: 58298c4c201SDavid VomLehn return err; 58398c4c201SDavid VomLehn } 58498c4c201SDavid VomLehn 58565e665e6SIgor Russkikh int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self, 5868f60f762SNikita Danilov struct hw_atl_utils_mbox_header *pmbox) 58765e665e6SIgor Russkikh { 58865e665e6SIgor Russkikh return hw_atl_utils_fw_downld_dwords(self, 5891a713f87SIgor Russkikh self->mbox_addr, 59065e665e6SIgor Russkikh (u32 *)(void *)pmbox, 59165e665e6SIgor Russkikh sizeof(*pmbox) / sizeof(u32)); 59265e665e6SIgor Russkikh } 59365e665e6SIgor Russkikh 59498c4c201SDavid VomLehn void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self, 5958f60f762SNikita Danilov struct hw_atl_utils_mbox *pmbox) 59698c4c201SDavid VomLehn { 59798c4c201SDavid VomLehn int err = 0; 59898c4c201SDavid VomLehn 59998c4c201SDavid VomLehn err = hw_atl_utils_fw_downld_dwords(self, 6001a713f87SIgor Russkikh self->mbox_addr, 60198c4c201SDavid VomLehn (u32 *)(void *)pmbox, 60298c4c201SDavid VomLehn sizeof(*pmbox) / sizeof(u32)); 60398c4c201SDavid VomLehn if (err < 0) 60498c4c201SDavid VomLehn goto err_exit; 60598c4c201SDavid VomLehn 606d1ad88feSMark Starovoytov if (ATL_HW_IS_CHIP_FEATURE(self, REVISION_A0)) { 60798c4c201SDavid VomLehn unsigned int mtu = self->aq_nic_cfg ? 60898c4c201SDavid VomLehn self->aq_nic_cfg->mtu : 1514U; 60998c4c201SDavid VomLehn pmbox->stats.ubrc = pmbox->stats.uprc * mtu; 61098c4c201SDavid VomLehn pmbox->stats.ubtc = pmbox->stats.uptc * mtu; 6111a713f87SIgor Russkikh pmbox->stats.dpc = atomic_read(&self->dpc); 61298c4c201SDavid VomLehn } else { 613ce4cdbe4SDmitry Bogdanov pmbox->stats.dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self); 61498c4c201SDavid VomLehn } 61598c4c201SDavid VomLehn 61698c4c201SDavid VomLehn err_exit:; 61798c4c201SDavid VomLehn } 61898c4c201SDavid VomLehn 619dfbd0749SWei Yongjun static int hw_atl_utils_mpi_set_speed(struct aq_hw_s *self, u32 speed) 62098c4c201SDavid VomLehn { 6210c58c35fSIgor Russkikh u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR); 62298c4c201SDavid VomLehn 62344e00dd8SIgor Russkikh val = val & ~HW_ATL_MPI_SPEED_MSK; 62444e00dd8SIgor Russkikh val |= speed << HW_ATL_MPI_SPEED_SHIFT; 6250c58c35fSIgor Russkikh aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val); 62698c4c201SDavid VomLehn 62798c4c201SDavid VomLehn return 0; 62898c4c201SDavid VomLehn } 62998c4c201SDavid VomLehn 630dfbd0749SWei Yongjun static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self, 63144e00dd8SIgor Russkikh enum hal_atl_utils_fw_state_e state) 63298c4c201SDavid VomLehn { 63344e00dd8SIgor Russkikh u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR); 6347b0c342fSNikita Danilov struct hw_atl_utils_mbox_header mbox; 6357b0c342fSNikita Danilov u32 transaction_id = 0; 6367b0c342fSNikita Danilov int err = 0; 63798c4c201SDavid VomLehn 63898c4c201SDavid VomLehn if (state == MPI_RESET) { 63965e665e6SIgor Russkikh hw_atl_utils_mpi_read_mbox(self, &mbox); 64098c4c201SDavid VomLehn 64165e665e6SIgor Russkikh transaction_id = mbox.transaction_id; 64298c4c201SDavid VomLehn 6436a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_get_mpi_mbox_tid, 6446a7f2277SNikita Danilov self, mbox.transaction_id, 6456a7f2277SNikita Danilov transaction_id != 6466a7f2277SNikita Danilov mbox.transaction_id, 6476a7f2277SNikita Danilov 1000U, 100000U); 64898c4c201SDavid VomLehn if (err < 0) 64998c4c201SDavid VomLehn goto err_exit; 65098c4c201SDavid VomLehn } 65144e00dd8SIgor Russkikh /* On interface DEINIT we disable DW (raise bit) 65244e00dd8SIgor Russkikh * Otherwise enable DW (clear bit) 65344e00dd8SIgor Russkikh */ 65444e00dd8SIgor Russkikh if (state == MPI_DEINIT || state == MPI_POWER) 65544e00dd8SIgor Russkikh val |= HW_ATL_MPI_DIRTY_WAKE_MSK; 65644e00dd8SIgor Russkikh else 65744e00dd8SIgor Russkikh val &= ~HW_ATL_MPI_DIRTY_WAKE_MSK; 65898c4c201SDavid VomLehn 65944e00dd8SIgor Russkikh /* Set new state bits */ 66044e00dd8SIgor Russkikh val = val & ~HW_ATL_MPI_STATE_MSK; 66144e00dd8SIgor Russkikh val |= state & HW_ATL_MPI_STATE_MSK; 66298c4c201SDavid VomLehn 6630c58c35fSIgor Russkikh aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val); 6647b0c342fSNikita Danilov 66544e00dd8SIgor Russkikh err_exit: 66644e00dd8SIgor Russkikh return err; 6670c58c35fSIgor Russkikh } 6680c58c35fSIgor Russkikh 669bd8ed441SPavel Belous int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self) 67098c4c201SDavid VomLehn { 671bd8ed441SPavel Belous struct aq_hw_link_status_s *link_status = &self->aq_link_status; 6727b0c342fSNikita Danilov u32 mpi_state; 6737b0c342fSNikita Danilov u32 speed; 67498c4c201SDavid VomLehn 6757b0c342fSNikita Danilov mpi_state = hw_atl_utils_mpi_get_state(self); 676ac70957eSIgor Russkikh speed = mpi_state >> HW_ATL_MPI_SPEED_SHIFT; 6777b0c342fSNikita Danilov 6787b0c342fSNikita Danilov if (!speed) { 67998c4c201SDavid VomLehn link_status->mbps = 0U; 68098c4c201SDavid VomLehn } else { 6817b0c342fSNikita Danilov switch (speed) { 68298c4c201SDavid VomLehn case HAL_ATLANTIC_RATE_10G: 68398c4c201SDavid VomLehn link_status->mbps = 10000U; 68498c4c201SDavid VomLehn break; 68598c4c201SDavid VomLehn 68698c4c201SDavid VomLehn case HAL_ATLANTIC_RATE_5G: 68798c4c201SDavid VomLehn case HAL_ATLANTIC_RATE_5GSR: 68898c4c201SDavid VomLehn link_status->mbps = 5000U; 68998c4c201SDavid VomLehn break; 69098c4c201SDavid VomLehn 69198c4c201SDavid VomLehn case HAL_ATLANTIC_RATE_2GS: 69298c4c201SDavid VomLehn link_status->mbps = 2500U; 69398c4c201SDavid VomLehn break; 69498c4c201SDavid VomLehn 69598c4c201SDavid VomLehn case HAL_ATLANTIC_RATE_1G: 69698c4c201SDavid VomLehn link_status->mbps = 1000U; 69798c4c201SDavid VomLehn break; 69898c4c201SDavid VomLehn 69998c4c201SDavid VomLehn case HAL_ATLANTIC_RATE_100M: 70098c4c201SDavid VomLehn link_status->mbps = 100U; 70198c4c201SDavid VomLehn break; 70298c4c201SDavid VomLehn 70398c4c201SDavid VomLehn default: 704a7bb1beaSIgor Russkikh return -EBUSY; 70598c4c201SDavid VomLehn } 70698c4c201SDavid VomLehn } 70798c4c201SDavid VomLehn 70898c4c201SDavid VomLehn return 0; 70998c4c201SDavid VomLehn } 71098c4c201SDavid VomLehn 71198c4c201SDavid VomLehn int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self, 71298c4c201SDavid VomLehn u8 *mac) 71398c4c201SDavid VomLehn { 7147b0c342fSNikita Danilov u32 mac_addr[2]; 7157b0c342fSNikita Danilov u32 efuse_addr; 71698c4c201SDavid VomLehn int err = 0; 71798c4c201SDavid VomLehn u32 h = 0U; 71898c4c201SDavid VomLehn u32 l = 0U; 71998c4c201SDavid VomLehn 72098c4c201SDavid VomLehn if (!aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) { 72198c4c201SDavid VomLehn unsigned int ucp_0x370 = 0; 7227b0c342fSNikita Danilov unsigned int rnd = 0; 72398c4c201SDavid VomLehn 72498c4c201SDavid VomLehn get_random_bytes(&rnd, sizeof(unsigned int)); 72598c4c201SDavid VomLehn 72698c4c201SDavid VomLehn ucp_0x370 = 0x02020202 | (0xFEFEFEFE & rnd); 72798c4c201SDavid VomLehn aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370); 72898c4c201SDavid VomLehn } 72998c4c201SDavid VomLehn 7307b0c342fSNikita Danilov efuse_addr = aq_hw_read_reg(self, 0x00000374U); 7317b0c342fSNikita Danilov 7327b0c342fSNikita Danilov err = hw_atl_utils_fw_downld_dwords(self, efuse_addr + (40U * 4U), 7337b0c342fSNikita Danilov mac_addr, ARRAY_SIZE(mac_addr)); 73498c4c201SDavid VomLehn if (err < 0) { 73598c4c201SDavid VomLehn mac_addr[0] = 0U; 73698c4c201SDavid VomLehn mac_addr[1] = 0U; 73798c4c201SDavid VomLehn err = 0; 73898c4c201SDavid VomLehn } else { 73998c4c201SDavid VomLehn mac_addr[0] = __swab32(mac_addr[0]); 74098c4c201SDavid VomLehn mac_addr[1] = __swab32(mac_addr[1]); 74198c4c201SDavid VomLehn } 74298c4c201SDavid VomLehn 74398c4c201SDavid VomLehn ether_addr_copy(mac, (u8 *)mac_addr); 74498c4c201SDavid VomLehn 74598c4c201SDavid VomLehn if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) { 74698c4c201SDavid VomLehn /* chip revision */ 747e9157848SNikita Danilov l = 0xE3000000U | 748e9157848SNikita Danilov (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) | 749e9157848SNikita Danilov (0x00 << 16); 75098c4c201SDavid VomLehn h = 0x8001300EU; 75198c4c201SDavid VomLehn 75298c4c201SDavid VomLehn mac[5] = (u8)(0xFFU & l); 75398c4c201SDavid VomLehn l >>= 8; 75498c4c201SDavid VomLehn mac[4] = (u8)(0xFFU & l); 75598c4c201SDavid VomLehn l >>= 8; 75698c4c201SDavid VomLehn mac[3] = (u8)(0xFFU & l); 75798c4c201SDavid VomLehn l >>= 8; 75898c4c201SDavid VomLehn mac[2] = (u8)(0xFFU & l); 75998c4c201SDavid VomLehn mac[1] = (u8)(0xFFU & h); 76098c4c201SDavid VomLehn h >>= 8; 76198c4c201SDavid VomLehn mac[0] = (u8)(0xFFU & h); 76298c4c201SDavid VomLehn } 76398c4c201SDavid VomLehn 76498c4c201SDavid VomLehn return err; 76598c4c201SDavid VomLehn } 76698c4c201SDavid VomLehn 76798c4c201SDavid VomLehn unsigned int hw_atl_utils_mbps_2_speed_index(unsigned int mbps) 76898c4c201SDavid VomLehn { 76998c4c201SDavid VomLehn unsigned int ret = 0U; 77098c4c201SDavid VomLehn 77198c4c201SDavid VomLehn switch (mbps) { 77298c4c201SDavid VomLehn case 100U: 77398c4c201SDavid VomLehn ret = 5U; 77498c4c201SDavid VomLehn break; 77598c4c201SDavid VomLehn 77698c4c201SDavid VomLehn case 1000U: 77798c4c201SDavid VomLehn ret = 4U; 77898c4c201SDavid VomLehn break; 77998c4c201SDavid VomLehn 78098c4c201SDavid VomLehn case 2500U: 78198c4c201SDavid VomLehn ret = 3U; 78298c4c201SDavid VomLehn break; 78398c4c201SDavid VomLehn 78498c4c201SDavid VomLehn case 5000U: 78598c4c201SDavid VomLehn ret = 1U; 78698c4c201SDavid VomLehn break; 78798c4c201SDavid VomLehn 78898c4c201SDavid VomLehn case 10000U: 78998c4c201SDavid VomLehn ret = 0U; 79098c4c201SDavid VomLehn break; 79198c4c201SDavid VomLehn 79298c4c201SDavid VomLehn default: 79398c4c201SDavid VomLehn break; 79498c4c201SDavid VomLehn } 7957b0c342fSNikita Danilov 79698c4c201SDavid VomLehn return ret; 79798c4c201SDavid VomLehn } 79898c4c201SDavid VomLehn 79998c4c201SDavid VomLehn void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p) 80098c4c201SDavid VomLehn { 8018e1c072fSIgor Russkikh u32 val = hw_atl_reg_glb_mif_id_get(self); 80298c4c201SDavid VomLehn u32 mif_rev = val & 0xFFU; 8037b0c342fSNikita Danilov u32 chip_features = 0U; 80498c4c201SDavid VomLehn 805d1ad88feSMark Starovoytov chip_features |= ATL_HW_CHIP_ATLANTIC; 806d1ad88feSMark Starovoytov 80747203b34SIgor Russkikh if ((0xFU & mif_rev) == 1U) { 808d1ad88feSMark Starovoytov chip_features |= ATL_HW_CHIP_REVISION_A0 | 809d1ad88feSMark Starovoytov ATL_HW_CHIP_MPI_AQ | 810d1ad88feSMark Starovoytov ATL_HW_CHIP_MIPS; 81147203b34SIgor Russkikh } else if ((0xFU & mif_rev) == 2U) { 812d1ad88feSMark Starovoytov chip_features |= ATL_HW_CHIP_REVISION_B0 | 813d1ad88feSMark Starovoytov ATL_HW_CHIP_MPI_AQ | 814d1ad88feSMark Starovoytov ATL_HW_CHIP_MIPS | 815d1ad88feSMark Starovoytov ATL_HW_CHIP_TPO2 | 816d1ad88feSMark Starovoytov ATL_HW_CHIP_RPF2; 81747203b34SIgor Russkikh } else if ((0xFU & mif_rev) == 0xAU) { 818d1ad88feSMark Starovoytov chip_features |= ATL_HW_CHIP_REVISION_B1 | 819d1ad88feSMark Starovoytov ATL_HW_CHIP_MPI_AQ | 820d1ad88feSMark Starovoytov ATL_HW_CHIP_MIPS | 821d1ad88feSMark Starovoytov ATL_HW_CHIP_TPO2 | 822d1ad88feSMark Starovoytov ATL_HW_CHIP_RPF2; 82398c4c201SDavid VomLehn } 82498c4c201SDavid VomLehn 82598c4c201SDavid VomLehn *p = chip_features; 82698c4c201SDavid VomLehn } 82798c4c201SDavid VomLehn 82844e00dd8SIgor Russkikh static int hw_atl_fw1x_deinit(struct aq_hw_s *self) 82998c4c201SDavid VomLehn { 83044e00dd8SIgor Russkikh hw_atl_utils_mpi_set_speed(self, 0); 83144e00dd8SIgor Russkikh hw_atl_utils_mpi_set_state(self, MPI_DEINIT); 8327b0c342fSNikita Danilov 83398c4c201SDavid VomLehn return 0; 83498c4c201SDavid VomLehn } 83598c4c201SDavid VomLehn 83665e665e6SIgor Russkikh int hw_atl_utils_update_stats(struct aq_hw_s *self) 83765e665e6SIgor Russkikh { 838ce4cdbe4SDmitry Bogdanov struct aq_stats_s *cs = &self->curr_stats; 8397b0c342fSNikita Danilov struct hw_atl_utils_mbox mbox; 84065e665e6SIgor Russkikh 84165e665e6SIgor Russkikh hw_atl_utils_mpi_read_stats(self, &mbox); 84265e665e6SIgor Russkikh 8431a713f87SIgor Russkikh #define AQ_SDELTA(_N_) (self->curr_stats._N_ += \ 8441a713f87SIgor Russkikh mbox.stats._N_ - self->last_stats._N_) 8451a713f87SIgor Russkikh 846be08d839SIgor Russkikh if (self->aq_link_status.mbps) { 84765e665e6SIgor Russkikh AQ_SDELTA(uprc); 84865e665e6SIgor Russkikh AQ_SDELTA(mprc); 84965e665e6SIgor Russkikh AQ_SDELTA(bprc); 85065e665e6SIgor Russkikh AQ_SDELTA(erpt); 85165e665e6SIgor Russkikh 85265e665e6SIgor Russkikh AQ_SDELTA(uptc); 85365e665e6SIgor Russkikh AQ_SDELTA(mptc); 85465e665e6SIgor Russkikh AQ_SDELTA(bptc); 85565e665e6SIgor Russkikh AQ_SDELTA(erpr); 85665e665e6SIgor Russkikh 85765e665e6SIgor Russkikh AQ_SDELTA(ubrc); 85865e665e6SIgor Russkikh AQ_SDELTA(ubtc); 85965e665e6SIgor Russkikh AQ_SDELTA(mbrc); 86065e665e6SIgor Russkikh AQ_SDELTA(mbtc); 86165e665e6SIgor Russkikh AQ_SDELTA(bbrc); 86265e665e6SIgor Russkikh AQ_SDELTA(bbtc); 86365e665e6SIgor Russkikh AQ_SDELTA(dpc); 864be08d839SIgor Russkikh } 86565e665e6SIgor Russkikh #undef AQ_SDELTA 866ce4cdbe4SDmitry Bogdanov 867ce4cdbe4SDmitry Bogdanov cs->dma_pkt_rc = hw_atl_stats_rx_dma_good_pkt_counter_get(self); 868ce4cdbe4SDmitry Bogdanov cs->dma_pkt_tc = hw_atl_stats_tx_dma_good_pkt_counter_get(self); 869ce4cdbe4SDmitry Bogdanov cs->dma_oct_rc = hw_atl_stats_rx_dma_good_octet_counter_get(self); 870ce4cdbe4SDmitry Bogdanov cs->dma_oct_tc = hw_atl_stats_tx_dma_good_octet_counter_get(self); 87165e665e6SIgor Russkikh 8721a713f87SIgor Russkikh memcpy(&self->last_stats, &mbox.stats, sizeof(mbox.stats)); 87365e665e6SIgor Russkikh 87465e665e6SIgor Russkikh return 0; 87565e665e6SIgor Russkikh } 87665e665e6SIgor Russkikh 877be08d839SIgor Russkikh struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self) 87898c4c201SDavid VomLehn { 8791a713f87SIgor Russkikh return &self->curr_stats; 88098c4c201SDavid VomLehn } 88198c4c201SDavid VomLehn 88298c4c201SDavid VomLehn static const u32 hw_atl_utils_hw_mac_regs[] = { 88398c4c201SDavid VomLehn 0x00005580U, 0x00005590U, 0x000055B0U, 0x000055B4U, 88498c4c201SDavid VomLehn 0x000055C0U, 0x00005B00U, 0x00005B04U, 0x00005B08U, 88598c4c201SDavid VomLehn 0x00005B0CU, 0x00005B10U, 0x00005B14U, 0x00005B18U, 88698c4c201SDavid VomLehn 0x00005B1CU, 0x00005B20U, 0x00005B24U, 0x00005B28U, 88798c4c201SDavid VomLehn 0x00005B2CU, 0x00005B30U, 0x00005B34U, 0x00005B38U, 88898c4c201SDavid VomLehn 0x00005B3CU, 0x00005B40U, 0x00005B44U, 0x00005B48U, 88998c4c201SDavid VomLehn 0x00005B4CU, 0x00005B50U, 0x00005B54U, 0x00005B58U, 89098c4c201SDavid VomLehn 0x00005B5CU, 0x00005B60U, 0x00005B64U, 0x00005B68U, 89198c4c201SDavid VomLehn 0x00005B6CU, 0x00005B70U, 0x00005B74U, 0x00005B78U, 89298c4c201SDavid VomLehn 0x00005B7CU, 0x00007C00U, 0x00007C04U, 0x00007C08U, 89398c4c201SDavid VomLehn 0x00007C0CU, 0x00007C10U, 0x00007C14U, 0x00007C18U, 89498c4c201SDavid VomLehn 0x00007C1CU, 0x00007C20U, 0x00007C40U, 0x00007C44U, 89598c4c201SDavid VomLehn 0x00007C48U, 0x00007C4CU, 0x00007C50U, 0x00007C54U, 89698c4c201SDavid VomLehn 0x00007C58U, 0x00007C5CU, 0x00007C60U, 0x00007C80U, 89798c4c201SDavid VomLehn 0x00007C84U, 0x00007C88U, 0x00007C8CU, 0x00007C90U, 89898c4c201SDavid VomLehn 0x00007C94U, 0x00007C98U, 0x00007C9CU, 0x00007CA0U, 89998c4c201SDavid VomLehn 0x00007CC0U, 0x00007CC4U, 0x00007CC8U, 0x00007CCCU, 90098c4c201SDavid VomLehn 0x00007CD0U, 0x00007CD4U, 0x00007CD8U, 0x00007CDCU, 90198c4c201SDavid VomLehn 0x00007CE0U, 0x00000300U, 0x00000304U, 0x00000308U, 90298c4c201SDavid VomLehn 0x0000030cU, 0x00000310U, 0x00000314U, 0x00000318U, 90398c4c201SDavid VomLehn 0x0000031cU, 0x00000360U, 0x00000364U, 0x00000368U, 90498c4c201SDavid VomLehn 0x0000036cU, 0x00000370U, 0x00000374U, 0x00006900U, 90598c4c201SDavid VomLehn }; 90698c4c201SDavid VomLehn 90798c4c201SDavid VomLehn int hw_atl_utils_hw_get_regs(struct aq_hw_s *self, 9084cbc9f92SIgor Russkikh const struct aq_hw_caps_s *aq_hw_caps, 90998c4c201SDavid VomLehn u32 *regs_buff) 91098c4c201SDavid VomLehn { 91198c4c201SDavid VomLehn unsigned int i = 0U; 91298c4c201SDavid VomLehn 91398c4c201SDavid VomLehn for (i = 0; i < aq_hw_caps->mac_regs_count; i++) 91498c4c201SDavid VomLehn regs_buff[i] = aq_hw_read_reg(self, 91598c4c201SDavid VomLehn hw_atl_utils_hw_mac_regs[i]); 9167b0c342fSNikita Danilov 91798c4c201SDavid VomLehn return 0; 91898c4c201SDavid VomLehn } 91998c4c201SDavid VomLehn 92036e90a52SNikita Danilov u32 hw_atl_utils_get_fw_version(struct aq_hw_s *self) 92198c4c201SDavid VomLehn { 92236e90a52SNikita Danilov return aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION); 92398c4c201SDavid VomLehn } 9240c58c35fSIgor Russkikh 925837c6378SNikita Danilov static int aq_fw1x_set_wake_magic(struct aq_hw_s *self, bool wol_enabled, 926837c6378SNikita Danilov u8 *mac) 927a0da96c0SYana Esina { 9288f60f762SNikita Danilov struct hw_atl_utils_fw_rpc *prpc = NULL; 929a0da96c0SYana Esina unsigned int rpc_size = 0U; 930a0da96c0SYana Esina int err = 0; 931a0da96c0SYana Esina 932a0da96c0SYana Esina err = hw_atl_utils_fw_rpc_wait(self, &prpc); 933a0da96c0SYana Esina if (err < 0) 934a0da96c0SYana Esina goto err_exit; 935a0da96c0SYana Esina 936a0da96c0SYana Esina memset(prpc, 0, sizeof(*prpc)); 937a0da96c0SYana Esina 938a0da96c0SYana Esina if (wol_enabled) { 939d993e14bSNikita Danilov rpc_size = offsetof(struct hw_atl_utils_fw_rpc, msg_wol_add) + 940d993e14bSNikita Danilov sizeof(prpc->msg_wol_add); 941d993e14bSNikita Danilov 942a0da96c0SYana Esina 943a0da96c0SYana Esina prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD; 944d993e14bSNikita Danilov prpc->msg_wol_add.priority = 945a0da96c0SYana Esina HAL_ATLANTIC_UTILS_FW_MSG_WOL_PRIOR; 946d993e14bSNikita Danilov prpc->msg_wol_add.pattern_id = 947a0da96c0SYana Esina HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN; 948d993e14bSNikita Danilov prpc->msg_wol_add.packet_type = 949a0da96c0SYana Esina HAL_ATLANTIC_UTILS_FW_MSG_WOL_MAG_PKT; 950a0da96c0SYana Esina 951d993e14bSNikita Danilov ether_addr_copy((u8 *)&prpc->msg_wol_add.magic_packet_pattern, 952d993e14bSNikita Danilov mac); 953a0da96c0SYana Esina } else { 954d993e14bSNikita Danilov rpc_size = sizeof(prpc->msg_wol_remove) + 955d993e14bSNikita Danilov offsetof(struct hw_atl_utils_fw_rpc, msg_wol_remove); 956a0da96c0SYana Esina 957a0da96c0SYana Esina prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL; 958d993e14bSNikita Danilov prpc->msg_wol_add.pattern_id = 959a0da96c0SYana Esina HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN; 960a0da96c0SYana Esina } 961a0da96c0SYana Esina 962a0da96c0SYana Esina err = hw_atl_utils_fw_rpc_call(self, rpc_size); 963a0da96c0SYana Esina 964a0da96c0SYana Esina err_exit: 965a0da96c0SYana Esina return err; 966a0da96c0SYana Esina } 967a0da96c0SYana Esina 9683d5537f9SWei Yongjun static int aq_fw1x_set_power(struct aq_hw_s *self, unsigned int power_state, 969a0da96c0SYana Esina u8 *mac) 970a0da96c0SYana Esina { 9718f60f762SNikita Danilov struct hw_atl_utils_fw_rpc *prpc = NULL; 972a0da96c0SYana Esina unsigned int rpc_size = 0U; 973a0da96c0SYana Esina int err = 0; 974a0da96c0SYana Esina 975837c6378SNikita Danilov if (self->aq_nic_cfg->wol & WAKE_MAGIC) { 976837c6378SNikita Danilov err = aq_fw1x_set_wake_magic(self, 1, mac); 977a0da96c0SYana Esina 978a0da96c0SYana Esina if (err < 0) 979a0da96c0SYana Esina goto err_exit; 980a0da96c0SYana Esina 981a0da96c0SYana Esina rpc_size = sizeof(prpc->msg_id) + 982a0da96c0SYana Esina sizeof(prpc->msg_enable_wakeup); 983a0da96c0SYana Esina 984a0da96c0SYana Esina err = hw_atl_utils_fw_rpc_wait(self, &prpc); 985a0da96c0SYana Esina 986a0da96c0SYana Esina if (err < 0) 987a0da96c0SYana Esina goto err_exit; 988a0da96c0SYana Esina 989a0da96c0SYana Esina memset(prpc, 0, rpc_size); 990a0da96c0SYana Esina 991a0da96c0SYana Esina prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP; 992a0da96c0SYana Esina prpc->msg_enable_wakeup.pattern_mask = 0x00000002; 993a0da96c0SYana Esina 994a0da96c0SYana Esina err = hw_atl_utils_fw_rpc_call(self, rpc_size); 995a0da96c0SYana Esina if (err < 0) 996a0da96c0SYana Esina goto err_exit; 997a0da96c0SYana Esina } 998a0da96c0SYana Esina hw_atl_utils_mpi_set_speed(self, 0); 999a0da96c0SYana Esina hw_atl_utils_mpi_set_state(self, MPI_POWER); 1000a0da96c0SYana Esina 1001a0da96c0SYana Esina err_exit: 1002a0da96c0SYana Esina return err; 1003a0da96c0SYana Esina } 1004a0da96c0SYana Esina 10056a7f2277SNikita Danilov static u32 hw_atl_utils_get_mpi_mbox_tid(struct aq_hw_s *self) 10066a7f2277SNikita Danilov { 10076a7f2277SNikita Danilov struct hw_atl_utils_mbox_header mbox; 10086a7f2277SNikita Danilov 10096a7f2277SNikita Danilov hw_atl_utils_mpi_read_mbox(self, &mbox); 10106a7f2277SNikita Danilov 10116a7f2277SNikita Danilov return mbox.transaction_id; 10126a7f2277SNikita Danilov } 10136a7f2277SNikita Danilov 10146a7f2277SNikita Danilov static u32 hw_atl_utils_mpi_get_state(struct aq_hw_s *self) 10156a7f2277SNikita Danilov { 10166a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR); 10176a7f2277SNikita Danilov } 10186a7f2277SNikita Danilov 10196a7f2277SNikita Danilov static u32 hw_atl_utils_mif_cmd_get(struct aq_hw_s *self) 10206a7f2277SNikita Danilov { 10216a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_MIF_CMD); 10226a7f2277SNikita Danilov } 10236a7f2277SNikita Danilov 10246a7f2277SNikita Danilov static u32 hw_atl_utils_mif_addr_get(struct aq_hw_s *self) 10256a7f2277SNikita Danilov { 10266a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_MIF_ADDR); 10276a7f2277SNikita Danilov } 10286a7f2277SNikita Danilov 10296a7f2277SNikita Danilov static u32 hw_atl_utils_rpc_state_get(struct aq_hw_s *self) 10306a7f2277SNikita Danilov { 10316a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_RPC_STATE_ADR); 10326a7f2277SNikita Danilov } 10336a7f2277SNikita Danilov 1034e7b5f97eSIgor Russkikh static u32 aq_fw1x_rpc_get(struct aq_hw_s *self) 1035e7b5f97eSIgor Russkikh { 1036e7b5f97eSIgor Russkikh return aq_hw_read_reg(self, HW_ATL_MPI_RPC_ADDR); 1037e7b5f97eSIgor Russkikh } 1038e7b5f97eSIgor Russkikh 10390c58c35fSIgor Russkikh const struct aq_fw_ops aq_fw_1x_ops = { 10400c58c35fSIgor Russkikh .init = hw_atl_utils_mpi_create, 104144e00dd8SIgor Russkikh .deinit = hw_atl_fw1x_deinit, 10420c58c35fSIgor Russkikh .reset = NULL, 10430c58c35fSIgor Russkikh .get_mac_permanent = hw_atl_utils_get_mac_permanent, 10440c58c35fSIgor Russkikh .set_link_speed = hw_atl_utils_mpi_set_speed, 10450c58c35fSIgor Russkikh .set_state = hw_atl_utils_mpi_set_state, 10460c58c35fSIgor Russkikh .update_link_status = hw_atl_utils_mpi_get_link_status, 10470c58c35fSIgor Russkikh .update_stats = hw_atl_utils_update_stats, 10488f894011SYana Esina .get_phy_temp = NULL, 1049a0da96c0SYana Esina .set_power = aq_fw1x_set_power, 105092ab6407SYana Esina .set_eee_rate = NULL, 105192ab6407SYana Esina .get_eee_rate = NULL, 1052288551deSIgor Russkikh .set_flow_control = NULL, 1053910479a9SEgor Pomozov .send_fw_request = NULL, 1054910479a9SEgor Pomozov .enable_ptp = NULL, 1055d1287ce4SNikita Danilov .led_control = NULL, 10560c58c35fSIgor Russkikh }; 1057