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. 698c4c201SDavid VomLehn */ 798c4c201SDavid VomLehn 898c4c201SDavid VomLehn /* File hw_atl_utils.c: Definition of common functions for Atlantic hardware 998c4c201SDavid VomLehn * abstraction layer. 1098c4c201SDavid VomLehn */ 1198c4c201SDavid VomLehn 121a713f87SIgor Russkikh #include "../aq_nic.h" 1398c4c201SDavid VomLehn #include "../aq_hw_utils.h" 1498c4c201SDavid VomLehn #include "hw_atl_utils.h" 1598c4c201SDavid VomLehn #include "hw_atl_llh.h" 160c58c35fSIgor Russkikh #include "hw_atl_llh_internal.h" 1798c4c201SDavid VomLehn 1898c4c201SDavid VomLehn #include <linux/random.h> 1998c4c201SDavid VomLehn 2098c4c201SDavid VomLehn #define HW_ATL_UCP_0X370_REG 0x0370U 2198c4c201SDavid VomLehn 2247203b34SIgor Russkikh #define HW_ATL_MIF_CMD 0x0200U 2347203b34SIgor Russkikh #define HW_ATL_MIF_ADDR 0x0208U 2447203b34SIgor Russkikh #define HW_ATL_MIF_VAL 0x020CU 2547203b34SIgor Russkikh 26e7b5f97eSIgor Russkikh #define HW_ATL_MPI_RPC_ADDR 0x0334U 276a7f2277SNikita Danilov #define HW_ATL_RPC_CONTROL_ADR 0x0338U 286a7f2277SNikita Danilov #define HW_ATL_RPC_STATE_ADR 0x033CU 296a7f2277SNikita Danilov 300c58c35fSIgor Russkikh #define HW_ATL_MPI_FW_VERSION 0x18 3198c4c201SDavid VomLehn #define HW_ATL_MPI_CONTROL_ADR 0x0368U 3298c4c201SDavid VomLehn #define HW_ATL_MPI_STATE_ADR 0x036CU 3398c4c201SDavid VomLehn 3498c4c201SDavid VomLehn #define HW_ATL_MPI_STATE_MSK 0x00FFU 3598c4c201SDavid VomLehn #define HW_ATL_MPI_STATE_SHIFT 0U 3644e00dd8SIgor Russkikh #define HW_ATL_MPI_SPEED_MSK 0x00FF0000U 3798c4c201SDavid VomLehn #define HW_ATL_MPI_SPEED_SHIFT 16U 3844e00dd8SIgor Russkikh #define HW_ATL_MPI_DIRTY_WAKE_MSK 0x02000000U 3998c4c201SDavid VomLehn 40c8c82eb3SIgor Russkikh #define HW_ATL_MPI_DAISY_CHAIN_STATUS 0x704 41c8c82eb3SIgor Russkikh #define HW_ATL_MPI_BOOT_EXIT_CODE 0x388 42c8c82eb3SIgor Russkikh 43c8c82eb3SIgor Russkikh #define HW_ATL_MAC_PHY_CONTROL 0x4000 44c8c82eb3SIgor Russkikh #define HW_ATL_MAC_PHY_MPI_RESET_BIT 0x1D 45c8c82eb3SIgor Russkikh 460c58c35fSIgor Russkikh #define HW_ATL_FW_VER_1X 0x01050006U 47a57d3929SIgor Russkikh #define HW_ATL_FW_VER_2X 0x02000000U 48a57d3929SIgor Russkikh #define HW_ATL_FW_VER_3X 0x03000000U 490c58c35fSIgor Russkikh 50c8c82eb3SIgor Russkikh #define FORCE_FLASHLESS 0 51c8c82eb3SIgor Russkikh 52dc12f75aSNikita Danilov enum mcp_area { 53dc12f75aSNikita Danilov MCP_AREA_CONFIG = 0x80000000, 54dc12f75aSNikita Danilov MCP_AREA_SETTINGS = 0x20000000, 55dc12f75aSNikita Danilov }; 56dc12f75aSNikita Danilov 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 75b567edbfSMark Starovoytov if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, self->fw_ver_actual)) { 760c58c35fSIgor Russkikh *fw_ops = &aq_fw_1x_ops; 77b567edbfSMark Starovoytov } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X, self->fw_ver_actual)) { 78a57d3929SIgor Russkikh *fw_ops = &aq_fw_2x_ops; 79b567edbfSMark Starovoytov } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X, self->fw_ver_actual)) { 80a57d3929SIgor Russkikh *fw_ops = &aq_fw_2x_ops; 81c8c82eb3SIgor Russkikh } else { 820c58c35fSIgor Russkikh aq_pr_err("Bad FW version detected: %x\n", 830c58c35fSIgor Russkikh self->fw_ver_actual); 840c58c35fSIgor Russkikh return -EOPNOTSUPP; 850c58c35fSIgor Russkikh } 860c58c35fSIgor Russkikh self->aq_fw_ops = *fw_ops; 870c58c35fSIgor Russkikh err = self->aq_fw_ops->init(self); 887b0c342fSNikita Danilov 890c58c35fSIgor Russkikh return err; 900c58c35fSIgor Russkikh } 910c58c35fSIgor Russkikh 92c8c82eb3SIgor Russkikh static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self) 93c8c82eb3SIgor Russkikh { 941bf9a752SIgor Russkikh u32 gsr, val; 95c8c82eb3SIgor Russkikh int k = 0; 96c8c82eb3SIgor Russkikh 97c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x40e1); 98c8c82eb3SIgor Russkikh AQ_HW_SLEEP(50); 99c8c82eb3SIgor Russkikh 100c8c82eb3SIgor Russkikh /* Cleanup SPI */ 1011bf9a752SIgor Russkikh val = aq_hw_read_reg(self, 0x53C); 1021bf9a752SIgor Russkikh aq_hw_write_reg(self, 0x53C, val | 0x10); 103c8c82eb3SIgor Russkikh 104c8c82eb3SIgor Russkikh gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR); 105c8c82eb3SIgor Russkikh aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000); 106c8c82eb3SIgor Russkikh 107c8c82eb3SIgor Russkikh /* Kickstart MAC */ 108c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x80e0); 109c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x32a8, 0x0); 110c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x520, 0x1); 1111bf9a752SIgor Russkikh 1121bf9a752SIgor Russkikh /* Reset SPI again because of possible interrupted SPI burst */ 1131bf9a752SIgor Russkikh val = aq_hw_read_reg(self, 0x53C); 1141bf9a752SIgor Russkikh aq_hw_write_reg(self, 0x53C, val | 0x10); 115c8c82eb3SIgor Russkikh AQ_HW_SLEEP(10); 1161bf9a752SIgor Russkikh /* Clear SPI reset state */ 1171bf9a752SIgor Russkikh aq_hw_write_reg(self, 0x53C, val & ~0x10); 1181bf9a752SIgor Russkikh 119c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x180e0); 120c8c82eb3SIgor Russkikh 121c8c82eb3SIgor Russkikh for (k = 0; k < 1000; k++) { 122c8c82eb3SIgor Russkikh u32 flb_status = aq_hw_read_reg(self, 123c8c82eb3SIgor Russkikh HW_ATL_MPI_DAISY_CHAIN_STATUS); 124c8c82eb3SIgor Russkikh 125c8c82eb3SIgor Russkikh flb_status = flb_status & 0x10; 126c8c82eb3SIgor Russkikh if (flb_status) 127c8c82eb3SIgor Russkikh break; 128c8c82eb3SIgor Russkikh AQ_HW_SLEEP(10); 129c8c82eb3SIgor Russkikh } 130c8c82eb3SIgor Russkikh if (k == 1000) { 131c8c82eb3SIgor Russkikh aq_pr_err("MAC kickstart failed\n"); 132c8c82eb3SIgor Russkikh return -EIO; 133c8c82eb3SIgor Russkikh } 134c8c82eb3SIgor Russkikh 135c8c82eb3SIgor Russkikh /* FW reset */ 136c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x80e0); 137c8c82eb3SIgor Russkikh AQ_HW_SLEEP(50); 138c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x3a0, 0x1); 139c8c82eb3SIgor Russkikh 140c8c82eb3SIgor Russkikh /* Kickstart PHY - skipped */ 141c8c82eb3SIgor Russkikh 142c8c82eb3SIgor Russkikh /* Global software reset*/ 143c8c82eb3SIgor Russkikh hw_atl_rx_rx_reg_res_dis_set(self, 0U); 144c8c82eb3SIgor Russkikh hw_atl_tx_tx_reg_res_dis_set(self, 0U); 145c8c82eb3SIgor Russkikh aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL, 146c8c82eb3SIgor Russkikh BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT), 147c8c82eb3SIgor Russkikh HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0); 148c8c82eb3SIgor Russkikh gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR); 149c8c82eb3SIgor Russkikh aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000); 150c8c82eb3SIgor Russkikh 151c8c82eb3SIgor Russkikh for (k = 0; k < 1000; k++) { 152c8c82eb3SIgor Russkikh u32 fw_state = aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION); 153c8c82eb3SIgor Russkikh 154c8c82eb3SIgor Russkikh if (fw_state) 155c8c82eb3SIgor Russkikh break; 156c8c82eb3SIgor Russkikh AQ_HW_SLEEP(10); 157c8c82eb3SIgor Russkikh } 158c8c82eb3SIgor Russkikh if (k == 1000) { 159c8c82eb3SIgor Russkikh aq_pr_err("FW kickstart failed\n"); 160c8c82eb3SIgor Russkikh return -EIO; 161c8c82eb3SIgor Russkikh } 162d0f0fb25SIgor Russkikh /* Old FW requires fixed delay after init */ 163d0f0fb25SIgor Russkikh AQ_HW_SLEEP(15); 164c8c82eb3SIgor Russkikh 165c8c82eb3SIgor Russkikh return 0; 166c8c82eb3SIgor Russkikh } 167c8c82eb3SIgor Russkikh 168c8c82eb3SIgor Russkikh static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self) 169c8c82eb3SIgor Russkikh { 1701bf9a752SIgor Russkikh u32 gsr, val, rbl_status; 171c8c82eb3SIgor Russkikh int k; 172c8c82eb3SIgor Russkikh 173c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x40e1); 174c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x3a0, 0x1); 175c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x32a8, 0x0); 176c8c82eb3SIgor Russkikh 177c8c82eb3SIgor Russkikh /* Alter RBL status */ 178c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x388, 0xDEAD); 179c8c82eb3SIgor Russkikh 1801bf9a752SIgor Russkikh /* Cleanup SPI */ 1811bf9a752SIgor Russkikh val = aq_hw_read_reg(self, 0x53C); 1821bf9a752SIgor Russkikh aq_hw_write_reg(self, 0x53C, val | 0x10); 1831bf9a752SIgor Russkikh 184c8c82eb3SIgor Russkikh /* Global software reset*/ 185c8c82eb3SIgor Russkikh hw_atl_rx_rx_reg_res_dis_set(self, 0U); 186c8c82eb3SIgor Russkikh hw_atl_tx_tx_reg_res_dis_set(self, 0U); 187c8c82eb3SIgor Russkikh aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL, 188c8c82eb3SIgor Russkikh BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT), 189c8c82eb3SIgor Russkikh HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0); 190c8c82eb3SIgor Russkikh gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR); 191c8c82eb3SIgor Russkikh aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, 192c8c82eb3SIgor Russkikh (gsr & 0xFFFFBFFF) | 0x8000); 193c8c82eb3SIgor Russkikh 194c8c82eb3SIgor Russkikh if (FORCE_FLASHLESS) 195c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x534, 0x0); 196c8c82eb3SIgor Russkikh 197c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x40e0); 198c8c82eb3SIgor Russkikh 199c8c82eb3SIgor Russkikh /* Wait for RBL boot */ 200c8c82eb3SIgor Russkikh for (k = 0; k < 1000; k++) { 201c8c82eb3SIgor Russkikh rbl_status = aq_hw_read_reg(self, 0x388) & 0xFFFF; 202c8c82eb3SIgor Russkikh if (rbl_status && rbl_status != 0xDEAD) 203c8c82eb3SIgor Russkikh break; 204c8c82eb3SIgor Russkikh AQ_HW_SLEEP(10); 205c8c82eb3SIgor Russkikh } 206c8c82eb3SIgor Russkikh if (!rbl_status || rbl_status == 0xDEAD) { 207c8c82eb3SIgor Russkikh aq_pr_err("RBL Restart failed"); 208c8c82eb3SIgor Russkikh return -EIO; 209c8c82eb3SIgor Russkikh } 210c8c82eb3SIgor Russkikh 211c8c82eb3SIgor Russkikh /* Restore NVR */ 212c8c82eb3SIgor Russkikh if (FORCE_FLASHLESS) 213c8c82eb3SIgor Russkikh aq_hw_write_reg(self, 0x534, 0xA0); 214c8c82eb3SIgor Russkikh 215c8c82eb3SIgor Russkikh if (rbl_status == 0xF1A7) { 216c8c82eb3SIgor Russkikh aq_pr_err("No FW detected. Dynamic FW load not implemented\n"); 217e35df218SMark Starovoytov return -EOPNOTSUPP; 218c8c82eb3SIgor Russkikh } 219c8c82eb3SIgor Russkikh 220c8c82eb3SIgor Russkikh for (k = 0; k < 1000; k++) { 221c8c82eb3SIgor Russkikh u32 fw_state = aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION); 222c8c82eb3SIgor Russkikh 223c8c82eb3SIgor Russkikh if (fw_state) 224c8c82eb3SIgor Russkikh break; 225c8c82eb3SIgor Russkikh AQ_HW_SLEEP(10); 226c8c82eb3SIgor Russkikh } 227c8c82eb3SIgor Russkikh if (k == 1000) { 228c8c82eb3SIgor Russkikh aq_pr_err("FW kickstart failed\n"); 229c8c82eb3SIgor Russkikh return -EIO; 230c8c82eb3SIgor Russkikh } 231d0f0fb25SIgor Russkikh /* Old FW requires fixed delay after init */ 232d0f0fb25SIgor Russkikh AQ_HW_SLEEP(15); 233c8c82eb3SIgor Russkikh 234c8c82eb3SIgor Russkikh return 0; 235c8c82eb3SIgor Russkikh } 236c8c82eb3SIgor Russkikh 237c8c82eb3SIgor Russkikh int hw_atl_utils_soft_reset(struct aq_hw_s *self) 238c8c82eb3SIgor Russkikh { 239c8c82eb3SIgor Russkikh u32 boot_exit_code = 0; 2406a7f2277SNikita Danilov u32 val; 2417b0c342fSNikita Danilov int k; 242c8c82eb3SIgor Russkikh 243c8c82eb3SIgor Russkikh for (k = 0; k < 1000; ++k) { 244c8c82eb3SIgor Russkikh u32 flb_status = aq_hw_read_reg(self, 245c8c82eb3SIgor Russkikh HW_ATL_MPI_DAISY_CHAIN_STATUS); 246c8c82eb3SIgor Russkikh boot_exit_code = aq_hw_read_reg(self, 247c8c82eb3SIgor Russkikh HW_ATL_MPI_BOOT_EXIT_CODE); 248c8c82eb3SIgor Russkikh if (flb_status != 0x06000000 || boot_exit_code != 0) 249c8c82eb3SIgor Russkikh break; 250c8c82eb3SIgor Russkikh } 251c8c82eb3SIgor Russkikh 252c8c82eb3SIgor Russkikh if (k == 1000) { 253c8c82eb3SIgor Russkikh aq_pr_err("Neither RBL nor FLB firmware started\n"); 254c8c82eb3SIgor Russkikh return -EOPNOTSUPP; 255c8c82eb3SIgor Russkikh } 256c8c82eb3SIgor Russkikh 257c8c82eb3SIgor Russkikh self->rbl_enabled = (boot_exit_code != 0); 258c8c82eb3SIgor Russkikh 259cce96d18SIgor Russkikh /* FW 1.x may bootup in an invalid POWER state (WOL feature). 260cce96d18SIgor Russkikh * We should work around this by forcing its state back to DEINIT 261cce96d18SIgor Russkikh */ 262b567edbfSMark Starovoytov if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, 263cce96d18SIgor Russkikh aq_hw_read_reg(self, 264cce96d18SIgor Russkikh HW_ATL_MPI_FW_VERSION))) { 265cce96d18SIgor Russkikh int err = 0; 266cce96d18SIgor Russkikh 267cce96d18SIgor Russkikh hw_atl_utils_mpi_set_state(self, MPI_DEINIT); 2686a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_mpi_get_state, 2696a7f2277SNikita Danilov self, val, 2706a7f2277SNikita Danilov (val & HW_ATL_MPI_STATE_MSK) == 2716a7f2277SNikita Danilov MPI_DEINIT, 2726a7f2277SNikita Danilov 10, 10000U); 2734e3c7c00SYueHaibing if (err) 2744e3c7c00SYueHaibing return err; 275cce96d18SIgor Russkikh } 276cce96d18SIgor Russkikh 277c8c82eb3SIgor Russkikh if (self->rbl_enabled) 278c8c82eb3SIgor Russkikh return hw_atl_utils_soft_reset_rbl(self); 279c8c82eb3SIgor Russkikh else 280c8c82eb3SIgor Russkikh return hw_atl_utils_soft_reset_flb(self); 281c8c82eb3SIgor Russkikh } 282c8c82eb3SIgor Russkikh 283a57d3929SIgor Russkikh int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a, 28498c4c201SDavid VomLehn u32 *p, u32 cnt) 28598c4c201SDavid VomLehn { 28698c4c201SDavid VomLehn int err = 0; 2876a7f2277SNikita Danilov u32 val; 28898c4c201SDavid VomLehn 2896a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_sem_ram_get, 2906a7f2277SNikita Danilov self, val, val == 1U, 29198c4c201SDavid VomLehn 1U, 10000U); 29298c4c201SDavid VomLehn 29398c4c201SDavid VomLehn if (err < 0) { 29498c4c201SDavid VomLehn bool is_locked; 29598c4c201SDavid VomLehn 2968e1c072fSIgor Russkikh hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM); 2970b926d46SNikita Danilov is_locked = hw_atl_sem_ram_get(self); 29898c4c201SDavid VomLehn if (!is_locked) { 29998c4c201SDavid VomLehn err = -ETIME; 30098c4c201SDavid VomLehn goto err_exit; 30198c4c201SDavid VomLehn } 30298c4c201SDavid VomLehn } 30398c4c201SDavid VomLehn 30447203b34SIgor Russkikh aq_hw_write_reg(self, HW_ATL_MIF_ADDR, a); 30598c4c201SDavid VomLehn 30647203b34SIgor Russkikh for (++cnt; --cnt && !err;) { 30747203b34SIgor Russkikh aq_hw_write_reg(self, HW_ATL_MIF_CMD, 0x00008000U); 30898c4c201SDavid VomLehn 309d1ad88feSMark Starovoytov if (ATL_HW_IS_CHIP_FEATURE(self, REVISION_B1)) 3106a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_mif_addr_get, 3116a7f2277SNikita Danilov self, val, val != a, 3126a7f2277SNikita Danilov 1U, 1000U); 31347203b34SIgor Russkikh else 3146a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_mif_cmd_get, 3156a7f2277SNikita Danilov self, val, 3166a7f2277SNikita Danilov !(val & 0x100), 3176a7f2277SNikita Danilov 1U, 1000U); 31898c4c201SDavid VomLehn 31947203b34SIgor Russkikh *(p++) = aq_hw_read_reg(self, HW_ATL_MIF_VAL); 32047203b34SIgor Russkikh a += 4; 32198c4c201SDavid VomLehn } 32298c4c201SDavid VomLehn 3238e1c072fSIgor Russkikh hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM); 32498c4c201SDavid VomLehn 32598c4c201SDavid VomLehn err_exit: 32698c4c201SDavid VomLehn return err; 32798c4c201SDavid VomLehn } 32898c4c201SDavid VomLehn 329dc12f75aSNikita Danilov static int hw_atl_utils_write_b1_mbox(struct aq_hw_s *self, u32 addr, 330dc12f75aSNikita Danilov u32 *p, u32 cnt, enum mcp_area area) 33198c4c201SDavid VomLehn { 332dc12f75aSNikita Danilov u32 data_offset = 0; 333dc12f75aSNikita Danilov u32 offset = addr; 33498c4c201SDavid VomLehn int err = 0; 335dc12f75aSNikita Danilov u32 val; 33698c4c201SDavid VomLehn 337dc12f75aSNikita Danilov switch (area) { 338dc12f75aSNikita Danilov case MCP_AREA_CONFIG: 339dc12f75aSNikita Danilov offset -= self->rpc_addr; 340dc12f75aSNikita Danilov break; 341930b9a05SNikita Danilov 342dc12f75aSNikita Danilov case MCP_AREA_SETTINGS: 343dc12f75aSNikita Danilov offset -= self->settings_addr; 344dc12f75aSNikita Danilov break; 345dc12f75aSNikita Danilov } 34698c4c201SDavid VomLehn 347dc12f75aSNikita Danilov offset = offset / sizeof(u32); 348dc12f75aSNikita Danilov 349dc12f75aSNikita Danilov for (; data_offset < cnt; ++data_offset, ++offset) { 350dc12f75aSNikita Danilov aq_hw_write_reg(self, 0x328, p[data_offset]); 3513ee5c887SYana Esina aq_hw_write_reg(self, 0x32C, 352dc12f75aSNikita Danilov (area | (0xFFFF & (offset * 4)))); 3533ee5c887SYana Esina hw_atl_mcp_up_force_intr_set(self, 1); 3543ee5c887SYana Esina /* 1000 times by 10us = 10ms */ 3556a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_scrpad12_get, 3566a7f2277SNikita Danilov self, val, 357930b9a05SNikita Danilov (val & 0xF0000000) != 358dc12f75aSNikita Danilov area, 3596a7f2277SNikita Danilov 10U, 10000U); 36098c4c201SDavid VomLehn 361dc12f75aSNikita Danilov if (err < 0) 362dc12f75aSNikita Danilov break; 363dc12f75aSNikita Danilov } 364dc12f75aSNikita Danilov 365dc12f75aSNikita Danilov return err; 366dc12f75aSNikita Danilov } 367dc12f75aSNikita Danilov 368dc12f75aSNikita Danilov static int hw_atl_utils_write_b0_mbox(struct aq_hw_s *self, u32 addr, 369dc12f75aSNikita Danilov u32 *p, u32 cnt) 370dc12f75aSNikita Danilov { 371dc12f75aSNikita Danilov u32 offset = 0; 372dc12f75aSNikita Danilov int err = 0; 373dc12f75aSNikita Danilov u32 val; 374dc12f75aSNikita Danilov 375dc12f75aSNikita Danilov aq_hw_write_reg(self, 0x208, addr); 37698c4c201SDavid VomLehn 3773ee5c887SYana Esina for (; offset < cnt; ++offset) { 3783ee5c887SYana Esina aq_hw_write_reg(self, 0x20C, p[offset]); 3793ee5c887SYana Esina aq_hw_write_reg(self, 0x200, 0xC000); 38098c4c201SDavid VomLehn 3816a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_mif_cmd_get, 3826a7f2277SNikita Danilov self, val, 383dc12f75aSNikita Danilov (val & 0x100) == 0U, 384dc12f75aSNikita Danilov 10U, 10000U); 385dc12f75aSNikita Danilov 386dc12f75aSNikita Danilov if (err < 0) 387dc12f75aSNikita Danilov break; 38898c4c201SDavid VomLehn } 389dc12f75aSNikita Danilov 390dc12f75aSNikita Danilov return err; 39198c4c201SDavid VomLehn } 39298c4c201SDavid VomLehn 393dc12f75aSNikita Danilov static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 addr, u32 *p, 394dc12f75aSNikita Danilov u32 cnt, enum mcp_area area) 395dc12f75aSNikita Danilov { 396dc12f75aSNikita Danilov int err = 0; 397dc12f75aSNikita Danilov u32 val; 398dc12f75aSNikita Danilov 399dc12f75aSNikita Danilov err = readx_poll_timeout_atomic(hw_atl_sem_ram_get, self, 400dc12f75aSNikita Danilov val, val == 1U, 401dc12f75aSNikita Danilov 10U, 100000U); 402dc12f75aSNikita Danilov if (err < 0) 403dc12f75aSNikita Danilov goto err_exit; 404dc12f75aSNikita Danilov 405d1ad88feSMark Starovoytov if (ATL_HW_IS_CHIP_FEATURE(self, REVISION_B1)) 406dc12f75aSNikita Danilov err = hw_atl_utils_write_b1_mbox(self, addr, p, cnt, area); 407dc12f75aSNikita Danilov else 408dc12f75aSNikita Danilov err = hw_atl_utils_write_b0_mbox(self, addr, p, cnt); 409dc12f75aSNikita Danilov 4108e1c072fSIgor Russkikh hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM); 41198c4c201SDavid VomLehn 412dc12f75aSNikita Danilov if (err < 0) 413dc12f75aSNikita Danilov goto err_exit; 414dc12f75aSNikita Danilov 415dc12f75aSNikita Danilov err = aq_hw_err_from_flags(self); 416dc12f75aSNikita Danilov 41798c4c201SDavid VomLehn err_exit: 41898c4c201SDavid VomLehn return err; 41998c4c201SDavid VomLehn } 42098c4c201SDavid VomLehn 421dc12f75aSNikita Danilov int hw_atl_write_fwcfg_dwords(struct aq_hw_s *self, u32 *p, u32 cnt) 422dc12f75aSNikita Danilov { 423dc12f75aSNikita Danilov return hw_atl_utils_fw_upload_dwords(self, self->rpc_addr, p, 424dc12f75aSNikita Danilov cnt, MCP_AREA_CONFIG); 425dc12f75aSNikita Danilov } 426dc12f75aSNikita Danilov 427dc12f75aSNikita Danilov int hw_atl_write_fwsettings_dwords(struct aq_hw_s *self, u32 offset, u32 *p, 428dc12f75aSNikita Danilov u32 cnt) 429dc12f75aSNikita Danilov { 430dc12f75aSNikita Danilov return hw_atl_utils_fw_upload_dwords(self, self->settings_addr + offset, 431dc12f75aSNikita Danilov p, cnt, MCP_AREA_SETTINGS); 432dc12f75aSNikita Danilov } 433dc12f75aSNikita Danilov 434b567edbfSMark Starovoytov bool hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual) 43598c4c201SDavid VomLehn { 43698c4c201SDavid VomLehn const u32 dw_major_mask = 0xff000000U; 43798c4c201SDavid VomLehn const u32 dw_minor_mask = 0x00ffffffU; 438b567edbfSMark Starovoytov bool ver_match; 43998c4c201SDavid VomLehn 440b567edbfSMark Starovoytov ver_match = (dw_major_mask & (ver_expected ^ ver_actual)) ? false : true; 441b567edbfSMark Starovoytov if (!ver_match) 44298c4c201SDavid VomLehn goto err_exit; 443b567edbfSMark Starovoytov ver_match = ((dw_minor_mask & ver_expected) > (dw_minor_mask & ver_actual)) ? 444b567edbfSMark Starovoytov false : true; 4457b0c342fSNikita Danilov 44698c4c201SDavid VomLehn err_exit: 447b567edbfSMark Starovoytov return ver_match; 44898c4c201SDavid VomLehn } 44998c4c201SDavid VomLehn 45098c4c201SDavid VomLehn static int hw_atl_utils_init_ucp(struct aq_hw_s *self, 4514cbc9f92SIgor Russkikh const struct aq_hw_caps_s *aq_hw_caps) 45298c4c201SDavid VomLehn { 45398c4c201SDavid VomLehn int err = 0; 45498c4c201SDavid VomLehn 45598c4c201SDavid VomLehn if (!aq_hw_read_reg(self, 0x370U)) { 45698c4c201SDavid VomLehn unsigned int rnd = 0U; 45798c4c201SDavid VomLehn unsigned int ucp_0x370 = 0U; 45898c4c201SDavid VomLehn 45998c4c201SDavid VomLehn get_random_bytes(&rnd, sizeof(unsigned int)); 46098c4c201SDavid VomLehn 46198c4c201SDavid VomLehn ucp_0x370 = 0x02020202U | (0xFEFEFEFEU & rnd); 46298c4c201SDavid VomLehn aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370); 46398c4c201SDavid VomLehn } 46498c4c201SDavid VomLehn 4658e1c072fSIgor Russkikh hw_atl_reg_glb_cpu_scratch_scp_set(self, 0x00000000U, 25U); 46698c4c201SDavid VomLehn 46798c4c201SDavid VomLehn /* check 10 times by 1ms */ 4686a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_scrpad25_get, 4696a7f2277SNikita Danilov self, self->mbox_addr, 4706a7f2277SNikita Danilov self->mbox_addr != 0U, 4716a7f2277SNikita Danilov 1000U, 10000U); 472e7b5f97eSIgor Russkikh err = readx_poll_timeout_atomic(aq_fw1x_rpc_get, self, 473e7b5f97eSIgor Russkikh self->rpc_addr, 474e7b5f97eSIgor Russkikh self->rpc_addr != 0U, 475e7b5f97eSIgor Russkikh 1000U, 100000U); 47698c4c201SDavid VomLehn 47798c4c201SDavid VomLehn return err; 47898c4c201SDavid VomLehn } 47998c4c201SDavid VomLehn 48098c4c201SDavid VomLehn struct aq_hw_atl_utils_fw_rpc_tid_s { 48198c4c201SDavid VomLehn union { 48298c4c201SDavid VomLehn u32 val; 48398c4c201SDavid VomLehn struct { 48498c4c201SDavid VomLehn u16 tid; 48598c4c201SDavid VomLehn u16 len; 48698c4c201SDavid VomLehn }; 48798c4c201SDavid VomLehn }; 48898c4c201SDavid VomLehn }; 48998c4c201SDavid VomLehn 49098c4c201SDavid VomLehn #define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL) 49198c4c201SDavid VomLehn 4923ee5c887SYana Esina int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size) 49398c4c201SDavid VomLehn { 49498c4c201SDavid VomLehn struct aq_hw_atl_utils_fw_rpc_tid_s sw; 4957b0c342fSNikita Danilov int err = 0; 49698c4c201SDavid VomLehn 497d1ad88feSMark Starovoytov if (!ATL_HW_IS_CHIP_FEATURE(self, MIPS)) { 49898c4c201SDavid VomLehn err = -1; 49998c4c201SDavid VomLehn goto err_exit; 50098c4c201SDavid VomLehn } 501dc12f75aSNikita Danilov err = hw_atl_write_fwcfg_dwords(self, (u32 *)(void *)&self->rpc, 50298c4c201SDavid VomLehn (rpc_size + sizeof(u32) - 50398c4c201SDavid VomLehn sizeof(u8)) / sizeof(u32)); 50498c4c201SDavid VomLehn if (err < 0) 50598c4c201SDavid VomLehn goto err_exit; 50698c4c201SDavid VomLehn 5071a713f87SIgor Russkikh sw.tid = 0xFFFFU & (++self->rpc_tid); 50898c4c201SDavid VomLehn sw.len = (u16)rpc_size; 50998c4c201SDavid VomLehn aq_hw_write_reg(self, HW_ATL_RPC_CONTROL_ADR, sw.val); 51098c4c201SDavid VomLehn 51198c4c201SDavid VomLehn err_exit: 51298c4c201SDavid VomLehn return err; 51398c4c201SDavid VomLehn } 51498c4c201SDavid VomLehn 5153ee5c887SYana Esina int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self, 5168f60f762SNikita Danilov struct hw_atl_utils_fw_rpc **rpc) 51798c4c201SDavid VomLehn { 51898c4c201SDavid VomLehn struct aq_hw_atl_utils_fw_rpc_tid_s sw; 51998c4c201SDavid VomLehn struct aq_hw_atl_utils_fw_rpc_tid_s fw; 5207b0c342fSNikita Danilov int err = 0; 52198c4c201SDavid VomLehn 52298c4c201SDavid VomLehn do { 52398c4c201SDavid VomLehn sw.val = aq_hw_read_reg(self, HW_ATL_RPC_CONTROL_ADR); 52498c4c201SDavid VomLehn 5251a713f87SIgor Russkikh self->rpc_tid = sw.tid; 52698c4c201SDavid VomLehn 5276a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_rpc_state_get, 5286a7f2277SNikita Danilov self, fw.val, 5296a7f2277SNikita Danilov sw.tid == fw.tid, 5306a7f2277SNikita Danilov 1000U, 100000U); 531e7b5f97eSIgor Russkikh if (err < 0) 532e7b5f97eSIgor Russkikh goto err_exit; 533e7b5f97eSIgor Russkikh 534e7b5f97eSIgor Russkikh err = aq_hw_err_from_flags(self); 535e7b5f97eSIgor Russkikh if (err < 0) 536e7b5f97eSIgor Russkikh goto err_exit; 53798c4c201SDavid VomLehn 53898c4c201SDavid VomLehn if (fw.len == 0xFFFFU) { 53998c4c201SDavid VomLehn err = hw_atl_utils_fw_rpc_call(self, sw.len); 54098c4c201SDavid VomLehn if (err < 0) 54198c4c201SDavid VomLehn goto err_exit; 54298c4c201SDavid VomLehn } 54398c4c201SDavid VomLehn } while (sw.tid != fw.tid || 0xFFFFU == fw.len); 54498c4c201SDavid VomLehn 54598c4c201SDavid VomLehn if (rpc) { 54698c4c201SDavid VomLehn if (fw.len) { 54798c4c201SDavid VomLehn err = 54898c4c201SDavid VomLehn hw_atl_utils_fw_downld_dwords(self, 5491a713f87SIgor Russkikh self->rpc_addr, 55098c4c201SDavid VomLehn (u32 *)(void *) 5511a713f87SIgor Russkikh &self->rpc, 55298c4c201SDavid VomLehn (fw.len + sizeof(u32) - 55398c4c201SDavid VomLehn sizeof(u8)) / 55498c4c201SDavid VomLehn sizeof(u32)); 55598c4c201SDavid VomLehn if (err < 0) 55698c4c201SDavid VomLehn goto err_exit; 55798c4c201SDavid VomLehn } 55898c4c201SDavid VomLehn 5591a713f87SIgor Russkikh *rpc = &self->rpc; 56098c4c201SDavid VomLehn } 56198c4c201SDavid VomLehn 56298c4c201SDavid VomLehn err_exit: 56398c4c201SDavid VomLehn return err; 56498c4c201SDavid VomLehn } 56598c4c201SDavid VomLehn 5661a713f87SIgor Russkikh static int hw_atl_utils_mpi_create(struct aq_hw_s *self) 56798c4c201SDavid VomLehn { 56898c4c201SDavid VomLehn int err = 0; 56998c4c201SDavid VomLehn 5701a713f87SIgor Russkikh err = hw_atl_utils_init_ucp(self, self->aq_nic_cfg->aq_hw_caps); 57198c4c201SDavid VomLehn if (err < 0) 57298c4c201SDavid VomLehn goto err_exit; 57398c4c201SDavid VomLehn 57498c4c201SDavid VomLehn err = hw_atl_utils_fw_rpc_init(self); 57598c4c201SDavid VomLehn if (err < 0) 57698c4c201SDavid VomLehn goto err_exit; 57798c4c201SDavid VomLehn 57898c4c201SDavid VomLehn err_exit: 57998c4c201SDavid VomLehn return err; 58098c4c201SDavid VomLehn } 58198c4c201SDavid VomLehn 58265e665e6SIgor Russkikh int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self, 5838f60f762SNikita Danilov struct hw_atl_utils_mbox_header *pmbox) 58465e665e6SIgor Russkikh { 58565e665e6SIgor Russkikh return hw_atl_utils_fw_downld_dwords(self, 5861a713f87SIgor Russkikh self->mbox_addr, 58765e665e6SIgor Russkikh (u32 *)(void *)pmbox, 58865e665e6SIgor Russkikh sizeof(*pmbox) / sizeof(u32)); 58965e665e6SIgor Russkikh } 59065e665e6SIgor Russkikh 59198c4c201SDavid VomLehn void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self, 5928f60f762SNikita Danilov struct hw_atl_utils_mbox *pmbox) 59398c4c201SDavid VomLehn { 59498c4c201SDavid VomLehn int err = 0; 59598c4c201SDavid VomLehn 59698c4c201SDavid VomLehn err = hw_atl_utils_fw_downld_dwords(self, 5971a713f87SIgor Russkikh self->mbox_addr, 59898c4c201SDavid VomLehn (u32 *)(void *)pmbox, 59998c4c201SDavid VomLehn sizeof(*pmbox) / sizeof(u32)); 60098c4c201SDavid VomLehn if (err < 0) 60198c4c201SDavid VomLehn goto err_exit; 60298c4c201SDavid VomLehn 603d1ad88feSMark Starovoytov if (ATL_HW_IS_CHIP_FEATURE(self, REVISION_A0)) { 60498c4c201SDavid VomLehn unsigned int mtu = self->aq_nic_cfg ? 60598c4c201SDavid VomLehn self->aq_nic_cfg->mtu : 1514U; 60698c4c201SDavid VomLehn pmbox->stats.ubrc = pmbox->stats.uprc * mtu; 60798c4c201SDavid VomLehn pmbox->stats.ubtc = pmbox->stats.uptc * mtu; 6081a713f87SIgor Russkikh pmbox->stats.dpc = atomic_read(&self->dpc); 60998c4c201SDavid VomLehn } else { 610ce4cdbe4SDmitry Bogdanov pmbox->stats.dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self); 61198c4c201SDavid VomLehn } 61298c4c201SDavid VomLehn 61398c4c201SDavid VomLehn err_exit:; 61498c4c201SDavid VomLehn } 61598c4c201SDavid VomLehn 616dfbd0749SWei Yongjun static int hw_atl_utils_mpi_set_speed(struct aq_hw_s *self, u32 speed) 61798c4c201SDavid VomLehn { 6180c58c35fSIgor Russkikh u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR); 61998c4c201SDavid VomLehn 62044e00dd8SIgor Russkikh val = val & ~HW_ATL_MPI_SPEED_MSK; 62144e00dd8SIgor Russkikh val |= speed << HW_ATL_MPI_SPEED_SHIFT; 6220c58c35fSIgor Russkikh aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val); 62398c4c201SDavid VomLehn 62498c4c201SDavid VomLehn return 0; 62598c4c201SDavid VomLehn } 62698c4c201SDavid VomLehn 627dfbd0749SWei Yongjun static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self, 62844e00dd8SIgor Russkikh enum hal_atl_utils_fw_state_e state) 62998c4c201SDavid VomLehn { 63044e00dd8SIgor Russkikh u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR); 6317b0c342fSNikita Danilov struct hw_atl_utils_mbox_header mbox; 6327b0c342fSNikita Danilov u32 transaction_id = 0; 6337b0c342fSNikita Danilov int err = 0; 63498c4c201SDavid VomLehn 63598c4c201SDavid VomLehn if (state == MPI_RESET) { 63665e665e6SIgor Russkikh hw_atl_utils_mpi_read_mbox(self, &mbox); 63798c4c201SDavid VomLehn 63865e665e6SIgor Russkikh transaction_id = mbox.transaction_id; 63998c4c201SDavid VomLehn 6406a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_get_mpi_mbox_tid, 6416a7f2277SNikita Danilov self, mbox.transaction_id, 6426a7f2277SNikita Danilov transaction_id != 6436a7f2277SNikita Danilov mbox.transaction_id, 6446a7f2277SNikita Danilov 1000U, 100000U); 64598c4c201SDavid VomLehn if (err < 0) 64698c4c201SDavid VomLehn goto err_exit; 64798c4c201SDavid VomLehn } 64844e00dd8SIgor Russkikh /* On interface DEINIT we disable DW (raise bit) 64944e00dd8SIgor Russkikh * Otherwise enable DW (clear bit) 65044e00dd8SIgor Russkikh */ 65144e00dd8SIgor Russkikh if (state == MPI_DEINIT || state == MPI_POWER) 65244e00dd8SIgor Russkikh val |= HW_ATL_MPI_DIRTY_WAKE_MSK; 65344e00dd8SIgor Russkikh else 65444e00dd8SIgor Russkikh val &= ~HW_ATL_MPI_DIRTY_WAKE_MSK; 65598c4c201SDavid VomLehn 65644e00dd8SIgor Russkikh /* Set new state bits */ 65744e00dd8SIgor Russkikh val = val & ~HW_ATL_MPI_STATE_MSK; 65844e00dd8SIgor Russkikh val |= state & HW_ATL_MPI_STATE_MSK; 65998c4c201SDavid VomLehn 6600c58c35fSIgor Russkikh aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val); 6617b0c342fSNikita Danilov 66244e00dd8SIgor Russkikh err_exit: 66344e00dd8SIgor Russkikh return err; 6640c58c35fSIgor Russkikh } 6650c58c35fSIgor Russkikh 666bd8ed441SPavel Belous int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self) 66798c4c201SDavid VomLehn { 668bd8ed441SPavel Belous struct aq_hw_link_status_s *link_status = &self->aq_link_status; 6697b0c342fSNikita Danilov u32 mpi_state; 6707b0c342fSNikita Danilov u32 speed; 67198c4c201SDavid VomLehn 6727b0c342fSNikita Danilov mpi_state = hw_atl_utils_mpi_get_state(self); 673ac70957eSIgor Russkikh speed = mpi_state >> HW_ATL_MPI_SPEED_SHIFT; 6747b0c342fSNikita Danilov 6757b0c342fSNikita Danilov if (!speed) { 67698c4c201SDavid VomLehn link_status->mbps = 0U; 67798c4c201SDavid VomLehn } else { 6787b0c342fSNikita Danilov switch (speed) { 67998c4c201SDavid VomLehn case HAL_ATLANTIC_RATE_10G: 68098c4c201SDavid VomLehn link_status->mbps = 10000U; 68198c4c201SDavid VomLehn break; 68298c4c201SDavid VomLehn 68398c4c201SDavid VomLehn case HAL_ATLANTIC_RATE_5G: 68498c4c201SDavid VomLehn case HAL_ATLANTIC_RATE_5GSR: 68598c4c201SDavid VomLehn link_status->mbps = 5000U; 68698c4c201SDavid VomLehn break; 68798c4c201SDavid VomLehn 688843e1396SMark Starovoytov case HAL_ATLANTIC_RATE_2G5: 68998c4c201SDavid VomLehn link_status->mbps = 2500U; 69098c4c201SDavid VomLehn break; 69198c4c201SDavid VomLehn 69298c4c201SDavid VomLehn case HAL_ATLANTIC_RATE_1G: 69398c4c201SDavid VomLehn link_status->mbps = 1000U; 69498c4c201SDavid VomLehn break; 69598c4c201SDavid VomLehn 69698c4c201SDavid VomLehn case HAL_ATLANTIC_RATE_100M: 69798c4c201SDavid VomLehn link_status->mbps = 100U; 69898c4c201SDavid VomLehn break; 69998c4c201SDavid VomLehn 70098c4c201SDavid VomLehn default: 701a7bb1beaSIgor Russkikh return -EBUSY; 70298c4c201SDavid VomLehn } 70398c4c201SDavid VomLehn } 704071a0204SIgor Russkikh link_status->full_duplex = true; 70598c4c201SDavid VomLehn 70698c4c201SDavid VomLehn return 0; 70798c4c201SDavid VomLehn } 70898c4c201SDavid VomLehn 70998c4c201SDavid VomLehn int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self, 71098c4c201SDavid VomLehn u8 *mac) 71198c4c201SDavid VomLehn { 7127b0c342fSNikita Danilov u32 mac_addr[2]; 7137b0c342fSNikita Danilov u32 efuse_addr; 71498c4c201SDavid VomLehn int err = 0; 71598c4c201SDavid VomLehn u32 h = 0U; 71698c4c201SDavid VomLehn u32 l = 0U; 71798c4c201SDavid VomLehn 71898c4c201SDavid VomLehn if (!aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) { 71998c4c201SDavid VomLehn unsigned int ucp_0x370 = 0; 7207b0c342fSNikita Danilov unsigned int rnd = 0; 72198c4c201SDavid VomLehn 72298c4c201SDavid VomLehn get_random_bytes(&rnd, sizeof(unsigned int)); 72398c4c201SDavid VomLehn 72498c4c201SDavid VomLehn ucp_0x370 = 0x02020202 | (0xFEFEFEFE & rnd); 72598c4c201SDavid VomLehn aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370); 72698c4c201SDavid VomLehn } 72798c4c201SDavid VomLehn 7287b0c342fSNikita Danilov efuse_addr = aq_hw_read_reg(self, 0x00000374U); 7297b0c342fSNikita Danilov 7307b0c342fSNikita Danilov err = hw_atl_utils_fw_downld_dwords(self, efuse_addr + (40U * 4U), 7317b0c342fSNikita Danilov mac_addr, ARRAY_SIZE(mac_addr)); 73298c4c201SDavid VomLehn if (err < 0) { 73398c4c201SDavid VomLehn mac_addr[0] = 0U; 73498c4c201SDavid VomLehn mac_addr[1] = 0U; 73598c4c201SDavid VomLehn err = 0; 73698c4c201SDavid VomLehn } else { 73798c4c201SDavid VomLehn mac_addr[0] = __swab32(mac_addr[0]); 73898c4c201SDavid VomLehn mac_addr[1] = __swab32(mac_addr[1]); 73998c4c201SDavid VomLehn } 74098c4c201SDavid VomLehn 74198c4c201SDavid VomLehn ether_addr_copy(mac, (u8 *)mac_addr); 74298c4c201SDavid VomLehn 74398c4c201SDavid VomLehn if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) { 74498c4c201SDavid VomLehn /* chip revision */ 745e9157848SNikita Danilov l = 0xE3000000U | 746e9157848SNikita Danilov (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) | 747e9157848SNikita Danilov (0x00 << 16); 74898c4c201SDavid VomLehn h = 0x8001300EU; 74998c4c201SDavid VomLehn 75098c4c201SDavid VomLehn mac[5] = (u8)(0xFFU & l); 75198c4c201SDavid VomLehn l >>= 8; 75298c4c201SDavid VomLehn mac[4] = (u8)(0xFFU & l); 75398c4c201SDavid VomLehn l >>= 8; 75498c4c201SDavid VomLehn mac[3] = (u8)(0xFFU & l); 75598c4c201SDavid VomLehn l >>= 8; 75698c4c201SDavid VomLehn mac[2] = (u8)(0xFFU & l); 75798c4c201SDavid VomLehn mac[1] = (u8)(0xFFU & h); 75898c4c201SDavid VomLehn h >>= 8; 75998c4c201SDavid VomLehn mac[0] = (u8)(0xFFU & h); 76098c4c201SDavid VomLehn } 76198c4c201SDavid VomLehn 76298c4c201SDavid VomLehn return err; 76398c4c201SDavid VomLehn } 76498c4c201SDavid VomLehn 76598c4c201SDavid VomLehn unsigned int hw_atl_utils_mbps_2_speed_index(unsigned int mbps) 76698c4c201SDavid VomLehn { 76798c4c201SDavid VomLehn unsigned int ret = 0U; 76898c4c201SDavid VomLehn 76998c4c201SDavid VomLehn switch (mbps) { 77098c4c201SDavid VomLehn case 100U: 77198c4c201SDavid VomLehn ret = 5U; 77298c4c201SDavid VomLehn break; 77398c4c201SDavid VomLehn 77498c4c201SDavid VomLehn case 1000U: 77598c4c201SDavid VomLehn ret = 4U; 77698c4c201SDavid VomLehn break; 77798c4c201SDavid VomLehn 77898c4c201SDavid VomLehn case 2500U: 77998c4c201SDavid VomLehn ret = 3U; 78098c4c201SDavid VomLehn break; 78198c4c201SDavid VomLehn 78298c4c201SDavid VomLehn case 5000U: 78398c4c201SDavid VomLehn ret = 1U; 78498c4c201SDavid VomLehn break; 78598c4c201SDavid VomLehn 78698c4c201SDavid VomLehn case 10000U: 78798c4c201SDavid VomLehn ret = 0U; 78898c4c201SDavid VomLehn break; 78998c4c201SDavid VomLehn 79098c4c201SDavid VomLehn default: 79198c4c201SDavid VomLehn break; 79298c4c201SDavid VomLehn } 7937b0c342fSNikita Danilov 79498c4c201SDavid VomLehn return ret; 79598c4c201SDavid VomLehn } 79698c4c201SDavid VomLehn 79798c4c201SDavid VomLehn void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p) 79898c4c201SDavid VomLehn { 7998e1c072fSIgor Russkikh u32 val = hw_atl_reg_glb_mif_id_get(self); 80098c4c201SDavid VomLehn u32 mif_rev = val & 0xFFU; 8017b0c342fSNikita Danilov u32 chip_features = 0U; 80298c4c201SDavid VomLehn 803d1ad88feSMark Starovoytov chip_features |= ATL_HW_CHIP_ATLANTIC; 804d1ad88feSMark Starovoytov 80547203b34SIgor Russkikh if ((0xFU & mif_rev) == 1U) { 806d1ad88feSMark Starovoytov chip_features |= ATL_HW_CHIP_REVISION_A0 | 807d1ad88feSMark Starovoytov ATL_HW_CHIP_MPI_AQ | 808d1ad88feSMark Starovoytov ATL_HW_CHIP_MIPS; 80947203b34SIgor Russkikh } else if ((0xFU & mif_rev) == 2U) { 810d1ad88feSMark Starovoytov chip_features |= ATL_HW_CHIP_REVISION_B0 | 811d1ad88feSMark Starovoytov ATL_HW_CHIP_MPI_AQ | 812d1ad88feSMark Starovoytov ATL_HW_CHIP_MIPS | 813d1ad88feSMark Starovoytov ATL_HW_CHIP_TPO2 | 814d1ad88feSMark Starovoytov ATL_HW_CHIP_RPF2; 81547203b34SIgor Russkikh } else if ((0xFU & mif_rev) == 0xAU) { 816d1ad88feSMark Starovoytov chip_features |= ATL_HW_CHIP_REVISION_B1 | 817d1ad88feSMark Starovoytov ATL_HW_CHIP_MPI_AQ | 818d1ad88feSMark Starovoytov ATL_HW_CHIP_MIPS | 819d1ad88feSMark Starovoytov ATL_HW_CHIP_TPO2 | 820d1ad88feSMark Starovoytov ATL_HW_CHIP_RPF2; 82198c4c201SDavid VomLehn } 82298c4c201SDavid VomLehn 82398c4c201SDavid VomLehn *p = chip_features; 82498c4c201SDavid VomLehn } 82598c4c201SDavid VomLehn 82644e00dd8SIgor Russkikh static int hw_atl_fw1x_deinit(struct aq_hw_s *self) 82798c4c201SDavid VomLehn { 82844e00dd8SIgor Russkikh hw_atl_utils_mpi_set_speed(self, 0); 82944e00dd8SIgor Russkikh hw_atl_utils_mpi_set_state(self, MPI_DEINIT); 8307b0c342fSNikita Danilov 83198c4c201SDavid VomLehn return 0; 83298c4c201SDavid VomLehn } 83398c4c201SDavid VomLehn 83465e665e6SIgor Russkikh int hw_atl_utils_update_stats(struct aq_hw_s *self) 83565e665e6SIgor Russkikh { 836ce4cdbe4SDmitry Bogdanov struct aq_stats_s *cs = &self->curr_stats; 8377b0c342fSNikita Danilov struct hw_atl_utils_mbox mbox; 83865e665e6SIgor Russkikh 83965e665e6SIgor Russkikh hw_atl_utils_mpi_read_stats(self, &mbox); 84065e665e6SIgor Russkikh 8411a713f87SIgor Russkikh #define AQ_SDELTA(_N_) (self->curr_stats._N_ += \ 8421a713f87SIgor Russkikh mbox.stats._N_ - self->last_stats._N_) 8431a713f87SIgor Russkikh 844be08d839SIgor Russkikh if (self->aq_link_status.mbps) { 84565e665e6SIgor Russkikh AQ_SDELTA(uprc); 84665e665e6SIgor Russkikh AQ_SDELTA(mprc); 84765e665e6SIgor Russkikh AQ_SDELTA(bprc); 84865e665e6SIgor Russkikh AQ_SDELTA(erpt); 84965e665e6SIgor Russkikh 85065e665e6SIgor Russkikh AQ_SDELTA(uptc); 85165e665e6SIgor Russkikh AQ_SDELTA(mptc); 85265e665e6SIgor Russkikh AQ_SDELTA(bptc); 85365e665e6SIgor Russkikh AQ_SDELTA(erpr); 85465e665e6SIgor Russkikh 85565e665e6SIgor Russkikh AQ_SDELTA(ubrc); 85665e665e6SIgor Russkikh AQ_SDELTA(ubtc); 85765e665e6SIgor Russkikh AQ_SDELTA(mbrc); 85865e665e6SIgor Russkikh AQ_SDELTA(mbtc); 85965e665e6SIgor Russkikh AQ_SDELTA(bbrc); 86065e665e6SIgor Russkikh AQ_SDELTA(bbtc); 86165e665e6SIgor Russkikh AQ_SDELTA(dpc); 862be08d839SIgor Russkikh } 86365e665e6SIgor Russkikh #undef AQ_SDELTA 864ce4cdbe4SDmitry Bogdanov 865ce4cdbe4SDmitry Bogdanov cs->dma_pkt_rc = hw_atl_stats_rx_dma_good_pkt_counter_get(self); 866ce4cdbe4SDmitry Bogdanov cs->dma_pkt_tc = hw_atl_stats_tx_dma_good_pkt_counter_get(self); 867ce4cdbe4SDmitry Bogdanov cs->dma_oct_rc = hw_atl_stats_rx_dma_good_octet_counter_get(self); 868ce4cdbe4SDmitry Bogdanov cs->dma_oct_tc = hw_atl_stats_tx_dma_good_octet_counter_get(self); 86965e665e6SIgor Russkikh 8701a713f87SIgor Russkikh memcpy(&self->last_stats, &mbox.stats, sizeof(mbox.stats)); 87165e665e6SIgor Russkikh 87265e665e6SIgor Russkikh return 0; 87365e665e6SIgor Russkikh } 87465e665e6SIgor Russkikh 875be08d839SIgor Russkikh struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self) 87698c4c201SDavid VomLehn { 8771a713f87SIgor Russkikh return &self->curr_stats; 87898c4c201SDavid VomLehn } 87998c4c201SDavid VomLehn 88098c4c201SDavid VomLehn static const u32 hw_atl_utils_hw_mac_regs[] = { 88198c4c201SDavid VomLehn 0x00005580U, 0x00005590U, 0x000055B0U, 0x000055B4U, 88298c4c201SDavid VomLehn 0x000055C0U, 0x00005B00U, 0x00005B04U, 0x00005B08U, 88398c4c201SDavid VomLehn 0x00005B0CU, 0x00005B10U, 0x00005B14U, 0x00005B18U, 88498c4c201SDavid VomLehn 0x00005B1CU, 0x00005B20U, 0x00005B24U, 0x00005B28U, 88598c4c201SDavid VomLehn 0x00005B2CU, 0x00005B30U, 0x00005B34U, 0x00005B38U, 88698c4c201SDavid VomLehn 0x00005B3CU, 0x00005B40U, 0x00005B44U, 0x00005B48U, 88798c4c201SDavid VomLehn 0x00005B4CU, 0x00005B50U, 0x00005B54U, 0x00005B58U, 88898c4c201SDavid VomLehn 0x00005B5CU, 0x00005B60U, 0x00005B64U, 0x00005B68U, 88998c4c201SDavid VomLehn 0x00005B6CU, 0x00005B70U, 0x00005B74U, 0x00005B78U, 89098c4c201SDavid VomLehn 0x00005B7CU, 0x00007C00U, 0x00007C04U, 0x00007C08U, 89198c4c201SDavid VomLehn 0x00007C0CU, 0x00007C10U, 0x00007C14U, 0x00007C18U, 89298c4c201SDavid VomLehn 0x00007C1CU, 0x00007C20U, 0x00007C40U, 0x00007C44U, 89398c4c201SDavid VomLehn 0x00007C48U, 0x00007C4CU, 0x00007C50U, 0x00007C54U, 89498c4c201SDavid VomLehn 0x00007C58U, 0x00007C5CU, 0x00007C60U, 0x00007C80U, 89598c4c201SDavid VomLehn 0x00007C84U, 0x00007C88U, 0x00007C8CU, 0x00007C90U, 89698c4c201SDavid VomLehn 0x00007C94U, 0x00007C98U, 0x00007C9CU, 0x00007CA0U, 89798c4c201SDavid VomLehn 0x00007CC0U, 0x00007CC4U, 0x00007CC8U, 0x00007CCCU, 89898c4c201SDavid VomLehn 0x00007CD0U, 0x00007CD4U, 0x00007CD8U, 0x00007CDCU, 89998c4c201SDavid VomLehn 0x00007CE0U, 0x00000300U, 0x00000304U, 0x00000308U, 90098c4c201SDavid VomLehn 0x0000030cU, 0x00000310U, 0x00000314U, 0x00000318U, 90198c4c201SDavid VomLehn 0x0000031cU, 0x00000360U, 0x00000364U, 0x00000368U, 90298c4c201SDavid VomLehn 0x0000036cU, 0x00000370U, 0x00000374U, 0x00006900U, 90398c4c201SDavid VomLehn }; 90498c4c201SDavid VomLehn 90598c4c201SDavid VomLehn int hw_atl_utils_hw_get_regs(struct aq_hw_s *self, 9064cbc9f92SIgor Russkikh const struct aq_hw_caps_s *aq_hw_caps, 90798c4c201SDavid VomLehn u32 *regs_buff) 90898c4c201SDavid VomLehn { 90998c4c201SDavid VomLehn unsigned int i = 0U; 91098c4c201SDavid VomLehn 91198c4c201SDavid VomLehn for (i = 0; i < aq_hw_caps->mac_regs_count; i++) 91298c4c201SDavid VomLehn regs_buff[i] = aq_hw_read_reg(self, 91398c4c201SDavid VomLehn hw_atl_utils_hw_mac_regs[i]); 9147b0c342fSNikita Danilov 91598c4c201SDavid VomLehn return 0; 91698c4c201SDavid VomLehn } 91798c4c201SDavid VomLehn 91836e90a52SNikita Danilov u32 hw_atl_utils_get_fw_version(struct aq_hw_s *self) 91998c4c201SDavid VomLehn { 92036e90a52SNikita Danilov return aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION); 92198c4c201SDavid VomLehn } 9220c58c35fSIgor Russkikh 923837c6378SNikita Danilov static int aq_fw1x_set_wake_magic(struct aq_hw_s *self, bool wol_enabled, 924837c6378SNikita Danilov u8 *mac) 925a0da96c0SYana Esina { 9268f60f762SNikita Danilov struct hw_atl_utils_fw_rpc *prpc = NULL; 927a0da96c0SYana Esina unsigned int rpc_size = 0U; 928a0da96c0SYana Esina int err = 0; 929a0da96c0SYana Esina 930a0da96c0SYana Esina err = hw_atl_utils_fw_rpc_wait(self, &prpc); 931a0da96c0SYana Esina if (err < 0) 932a0da96c0SYana Esina goto err_exit; 933a0da96c0SYana Esina 934a0da96c0SYana Esina memset(prpc, 0, sizeof(*prpc)); 935a0da96c0SYana Esina 936a0da96c0SYana Esina if (wol_enabled) { 937d993e14bSNikita Danilov rpc_size = offsetof(struct hw_atl_utils_fw_rpc, msg_wol_add) + 938d993e14bSNikita Danilov sizeof(prpc->msg_wol_add); 939d993e14bSNikita Danilov 940a0da96c0SYana Esina 941a0da96c0SYana Esina prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD; 942d993e14bSNikita Danilov prpc->msg_wol_add.priority = 943a0da96c0SYana Esina HAL_ATLANTIC_UTILS_FW_MSG_WOL_PRIOR; 944d993e14bSNikita Danilov prpc->msg_wol_add.pattern_id = 945a0da96c0SYana Esina HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN; 946d993e14bSNikita Danilov prpc->msg_wol_add.packet_type = 947a0da96c0SYana Esina HAL_ATLANTIC_UTILS_FW_MSG_WOL_MAG_PKT; 948a0da96c0SYana Esina 949d993e14bSNikita Danilov ether_addr_copy((u8 *)&prpc->msg_wol_add.magic_packet_pattern, 950d993e14bSNikita Danilov mac); 951a0da96c0SYana Esina } else { 952d993e14bSNikita Danilov rpc_size = sizeof(prpc->msg_wol_remove) + 953d993e14bSNikita Danilov offsetof(struct hw_atl_utils_fw_rpc, msg_wol_remove); 954a0da96c0SYana Esina 955a0da96c0SYana Esina prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL; 956d993e14bSNikita Danilov prpc->msg_wol_add.pattern_id = 957a0da96c0SYana Esina HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN; 958a0da96c0SYana Esina } 959a0da96c0SYana Esina 960a0da96c0SYana Esina err = hw_atl_utils_fw_rpc_call(self, rpc_size); 961a0da96c0SYana Esina 962a0da96c0SYana Esina err_exit: 963a0da96c0SYana Esina return err; 964a0da96c0SYana Esina } 965a0da96c0SYana Esina 9663d5537f9SWei Yongjun static int aq_fw1x_set_power(struct aq_hw_s *self, unsigned int power_state, 967a0da96c0SYana Esina u8 *mac) 968a0da96c0SYana Esina { 9698f60f762SNikita Danilov struct hw_atl_utils_fw_rpc *prpc = NULL; 970a0da96c0SYana Esina unsigned int rpc_size = 0U; 971a0da96c0SYana Esina int err = 0; 972a0da96c0SYana Esina 973837c6378SNikita Danilov if (self->aq_nic_cfg->wol & WAKE_MAGIC) { 974837c6378SNikita Danilov err = aq_fw1x_set_wake_magic(self, 1, mac); 975a0da96c0SYana Esina 976a0da96c0SYana Esina if (err < 0) 977a0da96c0SYana Esina goto err_exit; 978a0da96c0SYana Esina 979a0da96c0SYana Esina rpc_size = sizeof(prpc->msg_id) + 980a0da96c0SYana Esina sizeof(prpc->msg_enable_wakeup); 981a0da96c0SYana Esina 982a0da96c0SYana Esina err = hw_atl_utils_fw_rpc_wait(self, &prpc); 983a0da96c0SYana Esina 984a0da96c0SYana Esina if (err < 0) 985a0da96c0SYana Esina goto err_exit; 986a0da96c0SYana Esina 987a0da96c0SYana Esina memset(prpc, 0, rpc_size); 988a0da96c0SYana Esina 989a0da96c0SYana Esina prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP; 990a0da96c0SYana Esina prpc->msg_enable_wakeup.pattern_mask = 0x00000002; 991a0da96c0SYana Esina 992a0da96c0SYana Esina err = hw_atl_utils_fw_rpc_call(self, rpc_size); 993a0da96c0SYana Esina if (err < 0) 994a0da96c0SYana Esina goto err_exit; 995a0da96c0SYana Esina } 996a0da96c0SYana Esina hw_atl_utils_mpi_set_speed(self, 0); 997a0da96c0SYana Esina hw_atl_utils_mpi_set_state(self, MPI_POWER); 998a0da96c0SYana Esina 999a0da96c0SYana Esina err_exit: 1000a0da96c0SYana Esina return err; 1001a0da96c0SYana Esina } 1002a0da96c0SYana Esina 10036a7f2277SNikita Danilov static u32 hw_atl_utils_get_mpi_mbox_tid(struct aq_hw_s *self) 10046a7f2277SNikita Danilov { 10056a7f2277SNikita Danilov struct hw_atl_utils_mbox_header mbox; 10066a7f2277SNikita Danilov 10076a7f2277SNikita Danilov hw_atl_utils_mpi_read_mbox(self, &mbox); 10086a7f2277SNikita Danilov 10096a7f2277SNikita Danilov return mbox.transaction_id; 10106a7f2277SNikita Danilov } 10116a7f2277SNikita Danilov 10126a7f2277SNikita Danilov static u32 hw_atl_utils_mpi_get_state(struct aq_hw_s *self) 10136a7f2277SNikita Danilov { 10146a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR); 10156a7f2277SNikita Danilov } 10166a7f2277SNikita Danilov 10176a7f2277SNikita Danilov static u32 hw_atl_utils_mif_cmd_get(struct aq_hw_s *self) 10186a7f2277SNikita Danilov { 10196a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_MIF_CMD); 10206a7f2277SNikita Danilov } 10216a7f2277SNikita Danilov 10226a7f2277SNikita Danilov static u32 hw_atl_utils_mif_addr_get(struct aq_hw_s *self) 10236a7f2277SNikita Danilov { 10246a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_MIF_ADDR); 10256a7f2277SNikita Danilov } 10266a7f2277SNikita Danilov 10276a7f2277SNikita Danilov static u32 hw_atl_utils_rpc_state_get(struct aq_hw_s *self) 10286a7f2277SNikita Danilov { 10296a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_RPC_STATE_ADR); 10306a7f2277SNikita Danilov } 10316a7f2277SNikita Danilov 1032e7b5f97eSIgor Russkikh static u32 aq_fw1x_rpc_get(struct aq_hw_s *self) 1033e7b5f97eSIgor Russkikh { 1034e7b5f97eSIgor Russkikh return aq_hw_read_reg(self, HW_ATL_MPI_RPC_ADDR); 1035e7b5f97eSIgor Russkikh } 1036e7b5f97eSIgor Russkikh 10370c58c35fSIgor Russkikh const struct aq_fw_ops aq_fw_1x_ops = { 10380c58c35fSIgor Russkikh .init = hw_atl_utils_mpi_create, 103944e00dd8SIgor Russkikh .deinit = hw_atl_fw1x_deinit, 10400c58c35fSIgor Russkikh .reset = NULL, 10410c58c35fSIgor Russkikh .get_mac_permanent = hw_atl_utils_get_mac_permanent, 10420c58c35fSIgor Russkikh .set_link_speed = hw_atl_utils_mpi_set_speed, 10430c58c35fSIgor Russkikh .set_state = hw_atl_utils_mpi_set_state, 10440c58c35fSIgor Russkikh .update_link_status = hw_atl_utils_mpi_get_link_status, 10450c58c35fSIgor Russkikh .update_stats = hw_atl_utils_update_stats, 10468f894011SYana Esina .get_phy_temp = NULL, 1047a0da96c0SYana Esina .set_power = aq_fw1x_set_power, 104892ab6407SYana Esina .set_eee_rate = NULL, 104992ab6407SYana Esina .get_eee_rate = NULL, 1050288551deSIgor Russkikh .set_flow_control = NULL, 1051910479a9SEgor Pomozov .send_fw_request = NULL, 1052910479a9SEgor Pomozov .enable_ptp = NULL, 1053d1287ce4SNikita Danilov .led_control = NULL, 10540c58c35fSIgor Russkikh }; 1055