186d36773SIgor Russkikh // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) 286d36773SIgor Russkikh /* Copyright (C) 2014-2017 aQuantia Corporation. */ 386d36773SIgor Russkikh 486d36773SIgor Russkikh /* File hw_atl_utils.c: Definition of common functions for Atlantic hardware 586d36773SIgor Russkikh * abstraction layer. 686d36773SIgor Russkikh */ 786d36773SIgor Russkikh 886d36773SIgor Russkikh #include <stdio.h> 986d36773SIgor Russkikh #include <errno.h> 1086d36773SIgor Russkikh #include <stdint.h> 1186d36773SIgor Russkikh #include <string.h> 1286d36773SIgor Russkikh #include <unistd.h> 1386d36773SIgor Russkikh #include <stdarg.h> 1486d36773SIgor Russkikh #include <inttypes.h> 1586d36773SIgor Russkikh #include <rte_ether.h> 1686d36773SIgor Russkikh #include "../atl_hw_regs.h" 1786d36773SIgor Russkikh 1886d36773SIgor Russkikh #include "hw_atl_llh.h" 1986d36773SIgor Russkikh #include "hw_atl_llh_internal.h" 2086d36773SIgor Russkikh #include "../atl_logs.h" 2186d36773SIgor Russkikh 2286d36773SIgor Russkikh #define HW_ATL_UCP_0X370_REG 0x0370U 2386d36773SIgor Russkikh 2486d36773SIgor Russkikh #define HW_ATL_MIF_CMD 0x0200U 2586d36773SIgor Russkikh #define HW_ATL_MIF_ADDR 0x0208U 2686d36773SIgor Russkikh #define HW_ATL_MIF_VAL 0x020CU 2786d36773SIgor Russkikh 2886d36773SIgor Russkikh #define HW_ATL_FW_SM_RAM 0x2U 2986d36773SIgor Russkikh #define HW_ATL_MPI_FW_VERSION 0x18 3086d36773SIgor Russkikh #define HW_ATL_MPI_CONTROL_ADR 0x0368U 3186d36773SIgor Russkikh #define HW_ATL_MPI_STATE_ADR 0x036CU 3286d36773SIgor Russkikh 3386d36773SIgor Russkikh #define HW_ATL_MPI_STATE_MSK 0x00FFU 3486d36773SIgor Russkikh #define HW_ATL_MPI_STATE_SHIFT 0U 3586d36773SIgor Russkikh #define HW_ATL_MPI_SPEED_MSK 0x00FF0000U 3686d36773SIgor Russkikh #define HW_ATL_MPI_SPEED_SHIFT 16U 3786d36773SIgor Russkikh #define HW_ATL_MPI_DIRTY_WAKE_MSK 0x02000000U 3886d36773SIgor Russkikh 3986d36773SIgor Russkikh #define HW_ATL_MPI_DAISY_CHAIN_STATUS 0x704 4086d36773SIgor Russkikh #define HW_ATL_MPI_BOOT_EXIT_CODE 0x388 4186d36773SIgor Russkikh 4286d36773SIgor Russkikh #define HW_ATL_MAC_PHY_CONTROL 0x4000 4386d36773SIgor Russkikh #define HW_ATL_MAC_PHY_MPI_RESET_BIT 0x1D 4486d36773SIgor Russkikh 4586d36773SIgor Russkikh #define HW_ATL_FW_VER_1X 0x01050006U 4686d36773SIgor Russkikh #define HW_ATL_FW_VER_2X 0x02000000U 4786d36773SIgor Russkikh #define HW_ATL_FW_VER_3X 0x03000000U 4886d36773SIgor Russkikh 4986d36773SIgor Russkikh #define FORCE_FLASHLESS 0 5086d36773SIgor Russkikh 5186d36773SIgor Russkikh static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual); 5286d36773SIgor Russkikh static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self, 5386d36773SIgor Russkikh enum hal_atl_utils_fw_state_e state); 5486d36773SIgor Russkikh 5586d36773SIgor Russkikh 5686d36773SIgor Russkikh int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops) 5786d36773SIgor Russkikh { 5886d36773SIgor Russkikh int err = 0; 5986d36773SIgor Russkikh 6086d36773SIgor Russkikh err = hw_atl_utils_soft_reset(self); 6186d36773SIgor Russkikh if (err) 6286d36773SIgor Russkikh return err; 6386d36773SIgor Russkikh 6486d36773SIgor Russkikh hw_atl_utils_hw_chip_features_init(self, 6586d36773SIgor Russkikh &self->chip_features); 6686d36773SIgor Russkikh 6786d36773SIgor Russkikh hw_atl_utils_get_fw_version(self, &self->fw_ver_actual); 6886d36773SIgor Russkikh 6986d36773SIgor Russkikh if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, 7086d36773SIgor Russkikh self->fw_ver_actual) == 0) { 7186d36773SIgor Russkikh *fw_ops = &aq_fw_1x_ops; 7286d36773SIgor Russkikh } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X, 7386d36773SIgor Russkikh self->fw_ver_actual) == 0) { 7486d36773SIgor Russkikh *fw_ops = &aq_fw_2x_ops; 7586d36773SIgor Russkikh } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X, 7686d36773SIgor Russkikh self->fw_ver_actual) == 0) { 7786d36773SIgor Russkikh *fw_ops = &aq_fw_2x_ops; 7886d36773SIgor Russkikh } else { 79*f665790aSDavid Marchand PMD_DRV_LOG(ERR, "Bad FW version detected: %x", 8086d36773SIgor Russkikh self->fw_ver_actual); 8186d36773SIgor Russkikh return -EOPNOTSUPP; 8286d36773SIgor Russkikh } 8386d36773SIgor Russkikh self->aq_fw_ops = *fw_ops; 8486d36773SIgor Russkikh err = self->aq_fw_ops->init(self); 8586d36773SIgor Russkikh return err; 8686d36773SIgor Russkikh } 8786d36773SIgor Russkikh 8886d36773SIgor Russkikh static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self) 8986d36773SIgor Russkikh { 9086d36773SIgor Russkikh u32 gsr, val; 9186d36773SIgor Russkikh int k = 0; 9286d36773SIgor Russkikh 9386d36773SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x40e1); 9486d36773SIgor Russkikh AQ_HW_SLEEP(50); 9586d36773SIgor Russkikh 9686d36773SIgor Russkikh /* Cleanup SPI */ 9786d36773SIgor Russkikh val = aq_hw_read_reg(self, 0x53C); 9886d36773SIgor Russkikh aq_hw_write_reg(self, 0x53C, val | 0x10); 9986d36773SIgor Russkikh 10086d36773SIgor Russkikh gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR); 10186d36773SIgor Russkikh aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000); 10286d36773SIgor Russkikh 10386d36773SIgor Russkikh /* Kickstart MAC */ 10486d36773SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x80e0); 10586d36773SIgor Russkikh aq_hw_write_reg(self, 0x32a8, 0x0); 10686d36773SIgor Russkikh aq_hw_write_reg(self, 0x520, 0x1); 10786d36773SIgor Russkikh 10886d36773SIgor Russkikh /* Reset SPI again because of possible interrupted SPI burst */ 10986d36773SIgor Russkikh val = aq_hw_read_reg(self, 0x53C); 11086d36773SIgor Russkikh aq_hw_write_reg(self, 0x53C, val | 0x10); 11186d36773SIgor Russkikh AQ_HW_SLEEP(10); 11286d36773SIgor Russkikh /* Clear SPI reset state */ 11386d36773SIgor Russkikh aq_hw_write_reg(self, 0x53C, val & ~0x10); 11486d36773SIgor Russkikh 11586d36773SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x180e0); 11686d36773SIgor Russkikh 11786d36773SIgor Russkikh for (k = 0; k < 1000; k++) { 11886d36773SIgor Russkikh u32 flb_status = aq_hw_read_reg(self, 11986d36773SIgor Russkikh HW_ATL_MPI_DAISY_CHAIN_STATUS); 12086d36773SIgor Russkikh 12186d36773SIgor Russkikh flb_status = flb_status & 0x10; 12286d36773SIgor Russkikh if (flb_status) 12386d36773SIgor Russkikh break; 12486d36773SIgor Russkikh AQ_HW_SLEEP(10); 12586d36773SIgor Russkikh } 12686d36773SIgor Russkikh if (k == 1000) { 127*f665790aSDavid Marchand PMD_DRV_LOG(ERR, "MAC kickstart failed"); 12886d36773SIgor Russkikh return -EIO; 12986d36773SIgor Russkikh } 13086d36773SIgor Russkikh 13186d36773SIgor Russkikh /* FW reset */ 13286d36773SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x80e0); 13386d36773SIgor Russkikh AQ_HW_SLEEP(50); 13486d36773SIgor Russkikh aq_hw_write_reg(self, 0x3a0, 0x1); 13586d36773SIgor Russkikh 13686d36773SIgor Russkikh /* Kickstart PHY - skipped */ 13786d36773SIgor Russkikh 13886d36773SIgor Russkikh /* Global software reset*/ 13986d36773SIgor Russkikh hw_atl_rx_rx_reg_res_dis_set(self, 0U); 14086d36773SIgor Russkikh hw_atl_tx_tx_reg_res_dis_set(self, 0U); 14186d36773SIgor Russkikh aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL, 14286d36773SIgor Russkikh BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT), 14386d36773SIgor Russkikh HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0); 14486d36773SIgor Russkikh gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR); 14586d36773SIgor Russkikh aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000); 14686d36773SIgor Russkikh 14786d36773SIgor Russkikh for (k = 0; k < 1000; k++) { 14886d36773SIgor Russkikh u32 fw_state = aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION); 14986d36773SIgor Russkikh 15086d36773SIgor Russkikh if (fw_state) 15186d36773SIgor Russkikh break; 15286d36773SIgor Russkikh AQ_HW_SLEEP(10); 15386d36773SIgor Russkikh } 15486d36773SIgor Russkikh if (k == 1000) { 155*f665790aSDavid Marchand PMD_DRV_LOG(ERR, "FW kickstart failed"); 15686d36773SIgor Russkikh return -EIO; 15786d36773SIgor Russkikh } 15886d36773SIgor Russkikh /* Old FW requires fixed delay after init */ 15986d36773SIgor Russkikh AQ_HW_SLEEP(15); 16086d36773SIgor Russkikh 16186d36773SIgor Russkikh return 0; 16286d36773SIgor Russkikh } 16386d36773SIgor Russkikh 16486d36773SIgor Russkikh static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self) 16586d36773SIgor Russkikh { 16686d36773SIgor Russkikh u32 gsr, val, rbl_status; 16786d36773SIgor Russkikh int k; 16886d36773SIgor Russkikh 16986d36773SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x40e1); 17086d36773SIgor Russkikh aq_hw_write_reg(self, 0x3a0, 0x1); 17186d36773SIgor Russkikh aq_hw_write_reg(self, 0x32a8, 0x0); 17286d36773SIgor Russkikh 17386d36773SIgor Russkikh /* Alter RBL status */ 17486d36773SIgor Russkikh aq_hw_write_reg(self, 0x388, 0xDEAD); 17586d36773SIgor Russkikh 17686d36773SIgor Russkikh /* Cleanup SPI */ 17786d36773SIgor Russkikh val = aq_hw_read_reg(self, 0x53C); 17886d36773SIgor Russkikh aq_hw_write_reg(self, 0x53C, val | 0x10); 17986d36773SIgor Russkikh 18086d36773SIgor Russkikh /* Global software reset*/ 18186d36773SIgor Russkikh hw_atl_rx_rx_reg_res_dis_set(self, 0U); 18286d36773SIgor Russkikh hw_atl_tx_tx_reg_res_dis_set(self, 0U); 18386d36773SIgor Russkikh aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL, 18486d36773SIgor Russkikh BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT), 18586d36773SIgor Russkikh HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0); 18686d36773SIgor Russkikh gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR); 18786d36773SIgor Russkikh aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, 18886d36773SIgor Russkikh (gsr & 0xFFFFBFFF) | 0x8000); 18986d36773SIgor Russkikh 19086d36773SIgor Russkikh if (FORCE_FLASHLESS) 19186d36773SIgor Russkikh aq_hw_write_reg(self, 0x534, 0x0); 19286d36773SIgor Russkikh 19386d36773SIgor Russkikh aq_hw_write_reg(self, 0x404, 0x40e0); 19486d36773SIgor Russkikh 19586d36773SIgor Russkikh /* Wait for RBL boot */ 19686d36773SIgor Russkikh for (k = 0; k < 1000; k++) { 19786d36773SIgor Russkikh rbl_status = aq_hw_read_reg(self, 0x388) & 0xFFFF; 19886d36773SIgor Russkikh if (rbl_status && rbl_status != 0xDEAD) 19986d36773SIgor Russkikh break; 20086d36773SIgor Russkikh AQ_HW_SLEEP(10); 20186d36773SIgor Russkikh } 20286d36773SIgor Russkikh if (!rbl_status || rbl_status == 0xDEAD) { 20386d36773SIgor Russkikh PMD_DRV_LOG(ERR, "RBL Restart failed"); 20486d36773SIgor Russkikh return -EIO; 20586d36773SIgor Russkikh } 20686d36773SIgor Russkikh 20786d36773SIgor Russkikh /* Restore NVR */ 20886d36773SIgor Russkikh if (FORCE_FLASHLESS) 20986d36773SIgor Russkikh aq_hw_write_reg(self, 0x534, 0xA0); 21086d36773SIgor Russkikh 21186d36773SIgor Russkikh if (rbl_status == 0xF1A7) { 212*f665790aSDavid Marchand PMD_DRV_LOG(ERR, "No FW detected. Dynamic FW load not implemented"); 21386d36773SIgor Russkikh return -EOPNOTSUPP; 21486d36773SIgor Russkikh } 21586d36773SIgor Russkikh 21686d36773SIgor Russkikh for (k = 0; k < 1000; k++) { 21786d36773SIgor Russkikh u32 fw_state = aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION); 21886d36773SIgor Russkikh 21986d36773SIgor Russkikh if (fw_state) 22086d36773SIgor Russkikh break; 22186d36773SIgor Russkikh AQ_HW_SLEEP(10); 22286d36773SIgor Russkikh } 22386d36773SIgor Russkikh if (k == 1000) { 224*f665790aSDavid Marchand PMD_DRV_LOG(ERR, "FW kickstart failed"); 22586d36773SIgor Russkikh return -EIO; 22686d36773SIgor Russkikh } 22786d36773SIgor Russkikh /* Old FW requires fixed delay after init */ 22886d36773SIgor Russkikh AQ_HW_SLEEP(15); 22986d36773SIgor Russkikh 23086d36773SIgor Russkikh return 0; 23186d36773SIgor Russkikh } 23286d36773SIgor Russkikh 23386d36773SIgor Russkikh int hw_atl_utils_soft_reset(struct aq_hw_s *self) 23486d36773SIgor Russkikh { 23586d36773SIgor Russkikh int err = 0; 23686d36773SIgor Russkikh int k; 23786d36773SIgor Russkikh u32 boot_exit_code = 0; 23886d36773SIgor Russkikh 23986d36773SIgor Russkikh for (k = 0; k < 1000; ++k) { 24086d36773SIgor Russkikh u32 flb_status = aq_hw_read_reg(self, 24186d36773SIgor Russkikh HW_ATL_MPI_DAISY_CHAIN_STATUS); 24286d36773SIgor Russkikh boot_exit_code = aq_hw_read_reg(self, 24386d36773SIgor Russkikh HW_ATL_MPI_BOOT_EXIT_CODE); 24486d36773SIgor Russkikh if (flb_status != 0x06000000 || boot_exit_code != 0) 24586d36773SIgor Russkikh break; 24686d36773SIgor Russkikh } 24786d36773SIgor Russkikh 24886d36773SIgor Russkikh if (k == 1000) { 249*f665790aSDavid Marchand PMD_DRV_LOG(ERR, "Neither RBL nor FLB firmware started"); 25086d36773SIgor Russkikh return -EOPNOTSUPP; 25186d36773SIgor Russkikh } 25286d36773SIgor Russkikh 25386d36773SIgor Russkikh self->rbl_enabled = (boot_exit_code != 0); 25486d36773SIgor Russkikh 25586d36773SIgor Russkikh /* FW 1.x may bootup in an invalid POWER state (WOL feature). 25686d36773SIgor Russkikh * We should work around this by forcing its state back to DEINIT 25786d36773SIgor Russkikh */ 25886d36773SIgor Russkikh if (!hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, 25986d36773SIgor Russkikh aq_hw_read_reg(self, 26086d36773SIgor Russkikh HW_ATL_MPI_FW_VERSION))) { 26186d36773SIgor Russkikh hw_atl_utils_mpi_set_state(self, MPI_DEINIT); 26286d36773SIgor Russkikh AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR) & 26386d36773SIgor Russkikh HW_ATL_MPI_STATE_MSK) == MPI_DEINIT, 26486d36773SIgor Russkikh 10, 1000U); 26586d36773SIgor Russkikh } 26686d36773SIgor Russkikh 26786d36773SIgor Russkikh if (self->rbl_enabled) 26886d36773SIgor Russkikh err = hw_atl_utils_soft_reset_rbl(self); 26986d36773SIgor Russkikh else 27086d36773SIgor Russkikh err = hw_atl_utils_soft_reset_flb(self); 27186d36773SIgor Russkikh 27286d36773SIgor Russkikh return err; 27386d36773SIgor Russkikh } 27486d36773SIgor Russkikh 27586d36773SIgor Russkikh int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a, 27686d36773SIgor Russkikh u32 *p, u32 cnt) 27786d36773SIgor Russkikh { 27886d36773SIgor Russkikh int err = 0; 27986d36773SIgor Russkikh 28086d36773SIgor Russkikh AQ_HW_WAIT_FOR(hw_atl_reg_glb_cpu_sem_get(self, 28186d36773SIgor Russkikh HW_ATL_FW_SM_RAM) == 1U, 28286d36773SIgor Russkikh 1U, 10000U); 28386d36773SIgor Russkikh 28486d36773SIgor Russkikh if (err < 0) { 28586d36773SIgor Russkikh bool is_locked; 28686d36773SIgor Russkikh 28786d36773SIgor Russkikh hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM); 28886d36773SIgor Russkikh is_locked = hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM); 28986d36773SIgor Russkikh if (!is_locked) { 29086d36773SIgor Russkikh err = -ETIMEDOUT; 29186d36773SIgor Russkikh goto err_exit; 29286d36773SIgor Russkikh } 29386d36773SIgor Russkikh } 29486d36773SIgor Russkikh 29586d36773SIgor Russkikh aq_hw_write_reg(self, HW_ATL_MIF_ADDR, a); 29686d36773SIgor Russkikh 29786d36773SIgor Russkikh for (++cnt; --cnt && !err;) { 29886d36773SIgor Russkikh aq_hw_write_reg(self, HW_ATL_MIF_CMD, 0x00008000U); 29986d36773SIgor Russkikh 30086d36773SIgor Russkikh if (IS_CHIP_FEATURE(REVISION_B1)) 30186d36773SIgor Russkikh AQ_HW_WAIT_FOR(a != aq_hw_read_reg(self, 30286d36773SIgor Russkikh HW_ATL_MIF_ADDR), 30386d36773SIgor Russkikh 1, 1000U); 30486d36773SIgor Russkikh else 30586d36773SIgor Russkikh AQ_HW_WAIT_FOR(!(0x100 & aq_hw_read_reg(self, 30686d36773SIgor Russkikh HW_ATL_MIF_CMD)), 30786d36773SIgor Russkikh 1, 1000U); 308f73061d5SPavel Belous if (err) { 309f73061d5SPavel Belous err = -ETIMEDOUT; 310f73061d5SPavel Belous goto err_exit; 311f73061d5SPavel Belous } 31286d36773SIgor Russkikh 31386d36773SIgor Russkikh *(p++) = aq_hw_read_reg(self, HW_ATL_MIF_VAL); 31486d36773SIgor Russkikh a += 4; 31586d36773SIgor Russkikh } 31686d36773SIgor Russkikh 31786d36773SIgor Russkikh hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM); 31886d36773SIgor Russkikh 31986d36773SIgor Russkikh err_exit: 32086d36773SIgor Russkikh return err; 32186d36773SIgor Russkikh } 32286d36773SIgor Russkikh 32386d36773SIgor Russkikh int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p, 32486d36773SIgor Russkikh u32 cnt) 32586d36773SIgor Russkikh { 32686d36773SIgor Russkikh int err = 0; 32786d36773SIgor Russkikh bool is_locked; 32886d36773SIgor Russkikh 32986d36773SIgor Russkikh is_locked = hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM); 33086d36773SIgor Russkikh if (!is_locked) { 33186d36773SIgor Russkikh err = -ETIMEDOUT; 33286d36773SIgor Russkikh goto err_exit; 33386d36773SIgor Russkikh } 33486d36773SIgor Russkikh if (IS_CHIP_FEATURE(REVISION_B1)) { 3358fd8aa74SPavel Belous u32 mbox_offset = (a - self->rpc_addr) / sizeof(u32); 3368fd8aa74SPavel Belous u32 data_offset = 0; 33786d36773SIgor Russkikh 3388fd8aa74SPavel Belous for (; data_offset < cnt; ++mbox_offset, ++data_offset) { 3398fd8aa74SPavel Belous aq_hw_write_reg(self, 0x328, p[data_offset]); 34086d36773SIgor Russkikh aq_hw_write_reg(self, 0x32C, 3418fd8aa74SPavel Belous (0x80000000 | (0xFFFF & (mbox_offset * 4)))); 34286d36773SIgor Russkikh hw_atl_mcp_up_force_intr_set(self, 1); 34386d36773SIgor Russkikh /* 1000 times by 10us = 10ms */ 34486d36773SIgor Russkikh AQ_HW_WAIT_FOR((aq_hw_read_reg(self, 34586d36773SIgor Russkikh 0x32C) & 0xF0000000) != 0x80000000, 34686d36773SIgor Russkikh 10, 1000); 34786d36773SIgor Russkikh } 34886d36773SIgor Russkikh } else { 34986d36773SIgor Russkikh u32 offset = 0; 35086d36773SIgor Russkikh 35186d36773SIgor Russkikh aq_hw_write_reg(self, 0x208, a); 35286d36773SIgor Russkikh 35386d36773SIgor Russkikh for (; offset < cnt; ++offset) { 35486d36773SIgor Russkikh aq_hw_write_reg(self, 0x20C, p[offset]); 35586d36773SIgor Russkikh aq_hw_write_reg(self, 0x200, 0xC000); 35686d36773SIgor Russkikh 35786d36773SIgor Russkikh AQ_HW_WAIT_FOR((aq_hw_read_reg(self, 0x200U) 35886d36773SIgor Russkikh & 0x100) == 0, 10, 1000); 35986d36773SIgor Russkikh } 36086d36773SIgor Russkikh } 36186d36773SIgor Russkikh 36286d36773SIgor Russkikh hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM); 36386d36773SIgor Russkikh 36486d36773SIgor Russkikh err_exit: 36586d36773SIgor Russkikh return err; 36686d36773SIgor Russkikh } 36786d36773SIgor Russkikh 36886d36773SIgor Russkikh static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual) 36986d36773SIgor Russkikh { 37086d36773SIgor Russkikh int err = 0; 37186d36773SIgor Russkikh const u32 dw_major_mask = 0xff000000U; 37286d36773SIgor Russkikh const u32 dw_minor_mask = 0x00ffffffU; 37386d36773SIgor Russkikh 37486d36773SIgor Russkikh err = (dw_major_mask & (ver_expected ^ ver_actual)) ? -EOPNOTSUPP : 0; 37586d36773SIgor Russkikh if (err < 0) 37686d36773SIgor Russkikh goto err_exit; 37786d36773SIgor Russkikh err = ((dw_minor_mask & ver_expected) > (dw_minor_mask & ver_actual)) ? 37886d36773SIgor Russkikh -EOPNOTSUPP : 0; 37986d36773SIgor Russkikh err_exit: 38086d36773SIgor Russkikh return err; 38186d36773SIgor Russkikh } 38286d36773SIgor Russkikh 38386d36773SIgor Russkikh static int hw_atl_utils_init_ucp(struct aq_hw_s *self) 38486d36773SIgor Russkikh { 38586d36773SIgor Russkikh int err = 0; 38686d36773SIgor Russkikh 38786d36773SIgor Russkikh if (!aq_hw_read_reg(self, 0x370U)) { 38886d36773SIgor Russkikh unsigned int rnd = (uint32_t)rte_rand(); 38986d36773SIgor Russkikh unsigned int ucp_0x370 = 0U; 39086d36773SIgor Russkikh 39186d36773SIgor Russkikh ucp_0x370 = 0x02020202U | (0xFEFEFEFEU & rnd); 39286d36773SIgor Russkikh aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370); 39386d36773SIgor Russkikh } 39486d36773SIgor Russkikh 39586d36773SIgor Russkikh hw_atl_reg_glb_cpu_scratch_scp_set(self, 0x00000000U, 25U); 39686d36773SIgor Russkikh 39786d36773SIgor Russkikh /* check 10 times by 1ms */ 39886d36773SIgor Russkikh AQ_HW_WAIT_FOR(0U != (self->mbox_addr = 39986d36773SIgor Russkikh aq_hw_read_reg(self, 0x360U)), 1000U, 10U); 40086d36773SIgor Russkikh AQ_HW_WAIT_FOR(0U != (self->rpc_addr = 40186d36773SIgor Russkikh aq_hw_read_reg(self, 0x334U)), 1000U, 100U); 40286d36773SIgor Russkikh 40386d36773SIgor Russkikh return err; 40486d36773SIgor Russkikh } 40586d36773SIgor Russkikh 40686d36773SIgor Russkikh #define HW_ATL_RPC_CONTROL_ADR 0x0338U 40786d36773SIgor Russkikh #define HW_ATL_RPC_STATE_ADR 0x033CU 40886d36773SIgor Russkikh 40986d36773SIgor Russkikh struct aq_hw_atl_utils_fw_rpc_tid_s { 41086d36773SIgor Russkikh union { 41186d36773SIgor Russkikh u32 val; 41286d36773SIgor Russkikh struct { 41386d36773SIgor Russkikh u16 tid; 41486d36773SIgor Russkikh u16 len; 41586d36773SIgor Russkikh }; 41686d36773SIgor Russkikh }; 41786d36773SIgor Russkikh }; 41886d36773SIgor Russkikh 41986d36773SIgor Russkikh #define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL) 42086d36773SIgor Russkikh 42186d36773SIgor Russkikh int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size) 42286d36773SIgor Russkikh { 42386d36773SIgor Russkikh int err = 0; 42486d36773SIgor Russkikh struct aq_hw_atl_utils_fw_rpc_tid_s sw; 42586d36773SIgor Russkikh 42686d36773SIgor Russkikh if (!IS_CHIP_FEATURE(MIPS)) { 42786d36773SIgor Russkikh err = -1; 42886d36773SIgor Russkikh goto err_exit; 42986d36773SIgor Russkikh } 43086d36773SIgor Russkikh err = hw_atl_utils_fw_upload_dwords(self, self->rpc_addr, 43186d36773SIgor Russkikh (u32 *)(void *)&self->rpc, 43286d36773SIgor Russkikh (rpc_size + sizeof(u32) - 43386d36773SIgor Russkikh sizeof(u8)) / sizeof(u32)); 43486d36773SIgor Russkikh if (err < 0) 43586d36773SIgor Russkikh goto err_exit; 43686d36773SIgor Russkikh 43786d36773SIgor Russkikh sw.tid = 0xFFFFU & (++self->rpc_tid); 43886d36773SIgor Russkikh sw.len = (u16)rpc_size; 43986d36773SIgor Russkikh aq_hw_write_reg(self, HW_ATL_RPC_CONTROL_ADR, sw.val); 44086d36773SIgor Russkikh 44186d36773SIgor Russkikh err_exit: 44286d36773SIgor Russkikh return err; 44386d36773SIgor Russkikh } 44486d36773SIgor Russkikh 44586d36773SIgor Russkikh int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self, 44686d36773SIgor Russkikh struct hw_aq_atl_utils_fw_rpc **rpc) 44786d36773SIgor Russkikh { 44886d36773SIgor Russkikh int err = 0; 44986d36773SIgor Russkikh struct aq_hw_atl_utils_fw_rpc_tid_s sw; 45086d36773SIgor Russkikh struct aq_hw_atl_utils_fw_rpc_tid_s fw; 45186d36773SIgor Russkikh 45286d36773SIgor Russkikh do { 45386d36773SIgor Russkikh sw.val = aq_hw_read_reg(self, HW_ATL_RPC_CONTROL_ADR); 45486d36773SIgor Russkikh 45586d36773SIgor Russkikh self->rpc_tid = sw.tid; 45686d36773SIgor Russkikh 45786d36773SIgor Russkikh AQ_HW_WAIT_FOR(sw.tid == 45886d36773SIgor Russkikh (fw.val = 45986d36773SIgor Russkikh aq_hw_read_reg(self, HW_ATL_RPC_STATE_ADR), 46086d36773SIgor Russkikh fw.tid), 1000U, 100U); 46186d36773SIgor Russkikh if (err < 0) 46286d36773SIgor Russkikh goto err_exit; 46386d36773SIgor Russkikh 46486d36773SIgor Russkikh if (fw.len == 0xFFFFU) { 46586d36773SIgor Russkikh err = hw_atl_utils_fw_rpc_call(self, sw.len); 46686d36773SIgor Russkikh if (err < 0) 46786d36773SIgor Russkikh goto err_exit; 46886d36773SIgor Russkikh } 46986d36773SIgor Russkikh } while (sw.tid != fw.tid || 0xFFFFU == fw.len); 47086d36773SIgor Russkikh 47186d36773SIgor Russkikh if (rpc) { 47286d36773SIgor Russkikh if (fw.len) { 47386d36773SIgor Russkikh err = 47486d36773SIgor Russkikh hw_atl_utils_fw_downld_dwords(self, 47586d36773SIgor Russkikh self->rpc_addr, 47686d36773SIgor Russkikh (u32 *)(void *) 47786d36773SIgor Russkikh &self->rpc, 47886d36773SIgor Russkikh (fw.len + sizeof(u32) - 47986d36773SIgor Russkikh sizeof(u8)) / 48086d36773SIgor Russkikh sizeof(u32)); 48186d36773SIgor Russkikh if (err < 0) 48286d36773SIgor Russkikh goto err_exit; 48386d36773SIgor Russkikh } 48486d36773SIgor Russkikh 48586d36773SIgor Russkikh *rpc = &self->rpc; 48686d36773SIgor Russkikh } 48786d36773SIgor Russkikh 48886d36773SIgor Russkikh err_exit: 48986d36773SIgor Russkikh return err; 49086d36773SIgor Russkikh } 49186d36773SIgor Russkikh 49286d36773SIgor Russkikh static int hw_atl_utils_mpi_create(struct aq_hw_s *self) 49386d36773SIgor Russkikh { 49486d36773SIgor Russkikh int err = 0; 49586d36773SIgor Russkikh 49686d36773SIgor Russkikh err = hw_atl_utils_init_ucp(self); 49786d36773SIgor Russkikh if (err < 0) 49886d36773SIgor Russkikh goto err_exit; 49986d36773SIgor Russkikh 50086d36773SIgor Russkikh err = hw_atl_utils_fw_rpc_init(self); 50186d36773SIgor Russkikh if (err < 0) 50286d36773SIgor Russkikh goto err_exit; 50386d36773SIgor Russkikh 50486d36773SIgor Russkikh err_exit: 50586d36773SIgor Russkikh return err; 50686d36773SIgor Russkikh } 50786d36773SIgor Russkikh 50886d36773SIgor Russkikh int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self, 50986d36773SIgor Russkikh struct hw_aq_atl_utils_mbox_header *pmbox) 51086d36773SIgor Russkikh { 51186d36773SIgor Russkikh return hw_atl_utils_fw_downld_dwords(self, 51286d36773SIgor Russkikh self->mbox_addr, 51386d36773SIgor Russkikh (u32 *)(void *)pmbox, 51486d36773SIgor Russkikh sizeof(*pmbox) / sizeof(u32)); 51586d36773SIgor Russkikh } 51686d36773SIgor Russkikh 51786d36773SIgor Russkikh void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self, 51886d36773SIgor Russkikh struct hw_aq_atl_utils_mbox *pmbox) 51986d36773SIgor Russkikh { 52086d36773SIgor Russkikh int err = 0; 52186d36773SIgor Russkikh 52286d36773SIgor Russkikh err = hw_atl_utils_fw_downld_dwords(self, 52386d36773SIgor Russkikh self->mbox_addr, 52486d36773SIgor Russkikh (u32 *)(void *)pmbox, 52586d36773SIgor Russkikh sizeof(*pmbox) / sizeof(u32)); 52686d36773SIgor Russkikh if (err < 0) 52786d36773SIgor Russkikh goto err_exit; 52886d36773SIgor Russkikh 52986d36773SIgor Russkikh if (IS_CHIP_FEATURE(REVISION_A0)) { 53086d36773SIgor Russkikh unsigned int mtu = 1514; 53186d36773SIgor Russkikh pmbox->stats.ubrc = pmbox->stats.uprc * mtu; 53286d36773SIgor Russkikh pmbox->stats.ubtc = pmbox->stats.uptc * mtu; 53386d36773SIgor Russkikh } else { 53486d36773SIgor Russkikh pmbox->stats.dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self); 53586d36773SIgor Russkikh } 53686d36773SIgor Russkikh 53786d36773SIgor Russkikh err_exit:; 53886d36773SIgor Russkikh } 53986d36773SIgor Russkikh 54086d36773SIgor Russkikh static 54186d36773SIgor Russkikh int hw_atl_utils_mpi_set_speed(struct aq_hw_s *self, u32 speed) 54286d36773SIgor Russkikh { 54386d36773SIgor Russkikh u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR); 54486d36773SIgor Russkikh 54586d36773SIgor Russkikh val = val & ~HW_ATL_MPI_SPEED_MSK; 54686d36773SIgor Russkikh val |= speed << HW_ATL_MPI_SPEED_SHIFT; 54786d36773SIgor Russkikh aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val); 54886d36773SIgor Russkikh 54986d36773SIgor Russkikh return 0; 55086d36773SIgor Russkikh } 55186d36773SIgor Russkikh 55286d36773SIgor Russkikh int hw_atl_utils_mpi_set_state(struct aq_hw_s *self, 55386d36773SIgor Russkikh enum hal_atl_utils_fw_state_e state) 55486d36773SIgor Russkikh { 55586d36773SIgor Russkikh int err = 0; 55686d36773SIgor Russkikh u32 transaction_id = 0; 55786d36773SIgor Russkikh struct hw_aq_atl_utils_mbox_header mbox; 55886d36773SIgor Russkikh u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR); 55986d36773SIgor Russkikh 56086d36773SIgor Russkikh if (state == MPI_RESET) { 56186d36773SIgor Russkikh hw_atl_utils_mpi_read_mbox(self, &mbox); 56286d36773SIgor Russkikh 56386d36773SIgor Russkikh transaction_id = mbox.transaction_id; 56486d36773SIgor Russkikh 56586d36773SIgor Russkikh AQ_HW_WAIT_FOR(transaction_id != 56686d36773SIgor Russkikh (hw_atl_utils_mpi_read_mbox(self, &mbox), 56786d36773SIgor Russkikh mbox.transaction_id), 56886d36773SIgor Russkikh 1000U, 100U); 56986d36773SIgor Russkikh if (err < 0) 57086d36773SIgor Russkikh goto err_exit; 57186d36773SIgor Russkikh } 57286d36773SIgor Russkikh /* On interface DEINIT we disable DW (raise bit) 57386d36773SIgor Russkikh * Otherwise enable DW (clear bit) 57486d36773SIgor Russkikh */ 57586d36773SIgor Russkikh if (state == MPI_DEINIT || state == MPI_POWER) 57686d36773SIgor Russkikh val |= HW_ATL_MPI_DIRTY_WAKE_MSK; 57786d36773SIgor Russkikh else 57886d36773SIgor Russkikh val &= ~HW_ATL_MPI_DIRTY_WAKE_MSK; 57986d36773SIgor Russkikh 58086d36773SIgor Russkikh /* Set new state bits */ 58186d36773SIgor Russkikh val = val & ~HW_ATL_MPI_STATE_MSK; 58286d36773SIgor Russkikh val |= state & HW_ATL_MPI_STATE_MSK; 58386d36773SIgor Russkikh 58486d36773SIgor Russkikh aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val); 58586d36773SIgor Russkikh err_exit: 58686d36773SIgor Russkikh return err; 58786d36773SIgor Russkikh } 58886d36773SIgor Russkikh 58986d36773SIgor Russkikh int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self) 59086d36773SIgor Russkikh { 59186d36773SIgor Russkikh u32 cp0x036C = aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR); 59286d36773SIgor Russkikh u32 link_speed_mask = cp0x036C >> HW_ATL_MPI_SPEED_SHIFT; 59386d36773SIgor Russkikh struct aq_hw_link_status_s *link_status = &self->aq_link_status; 59486d36773SIgor Russkikh 59586d36773SIgor Russkikh if (!link_speed_mask) { 59686d36773SIgor Russkikh link_status->mbps = 0U; 59786d36773SIgor Russkikh } else { 59886d36773SIgor Russkikh switch (link_speed_mask) { 59986d36773SIgor Russkikh case HAL_ATLANTIC_RATE_10G: 60086d36773SIgor Russkikh link_status->mbps = 10000U; 60186d36773SIgor Russkikh break; 60286d36773SIgor Russkikh 60386d36773SIgor Russkikh case HAL_ATLANTIC_RATE_5G: 60486d36773SIgor Russkikh case HAL_ATLANTIC_RATE_5GSR: 60586d36773SIgor Russkikh link_status->mbps = 5000U; 60686d36773SIgor Russkikh break; 60786d36773SIgor Russkikh 60886d36773SIgor Russkikh case HAL_ATLANTIC_RATE_2GS: 60986d36773SIgor Russkikh link_status->mbps = 2500U; 61086d36773SIgor Russkikh break; 61186d36773SIgor Russkikh 61286d36773SIgor Russkikh case HAL_ATLANTIC_RATE_1G: 61386d36773SIgor Russkikh link_status->mbps = 1000U; 61486d36773SIgor Russkikh break; 61586d36773SIgor Russkikh 61686d36773SIgor Russkikh case HAL_ATLANTIC_RATE_100M: 61786d36773SIgor Russkikh link_status->mbps = 100U; 61886d36773SIgor Russkikh break; 61986d36773SIgor Russkikh 62086d36773SIgor Russkikh default: 62186d36773SIgor Russkikh return -EBUSY; 62286d36773SIgor Russkikh } 62386d36773SIgor Russkikh } 62486d36773SIgor Russkikh 62586d36773SIgor Russkikh return 0; 62686d36773SIgor Russkikh } 62786d36773SIgor Russkikh 62886d36773SIgor Russkikh static int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self, 62986d36773SIgor Russkikh u8 *mac) 63086d36773SIgor Russkikh { 63186d36773SIgor Russkikh int err = 0; 63286d36773SIgor Russkikh u32 h = 0U; 63386d36773SIgor Russkikh u32 l = 0U; 63486d36773SIgor Russkikh u32 mac_addr[2]; 63586d36773SIgor Russkikh 63686d36773SIgor Russkikh if (!aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) { 63786d36773SIgor Russkikh unsigned int rnd = (uint32_t)rte_rand(); 63886d36773SIgor Russkikh unsigned int ucp_0x370 = 0; 63986d36773SIgor Russkikh 64086d36773SIgor Russkikh //get_random_bytes(&rnd, sizeof(unsigned int)); 64186d36773SIgor Russkikh 64286d36773SIgor Russkikh ucp_0x370 = 0x02020202 | (0xFEFEFEFE & rnd); 64386d36773SIgor Russkikh aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370); 64486d36773SIgor Russkikh } 64586d36773SIgor Russkikh 64686d36773SIgor Russkikh err = hw_atl_utils_fw_downld_dwords(self, 64786d36773SIgor Russkikh aq_hw_read_reg(self, 0x00000374U) + 64886d36773SIgor Russkikh (40U * 4U), 64986d36773SIgor Russkikh mac_addr, 65086d36773SIgor Russkikh ARRAY_SIZE(mac_addr)); 65186d36773SIgor Russkikh if (err < 0) { 65286d36773SIgor Russkikh mac_addr[0] = 0U; 65386d36773SIgor Russkikh mac_addr[1] = 0U; 65486d36773SIgor Russkikh err = 0; 65586d36773SIgor Russkikh } else { 65686d36773SIgor Russkikh mac_addr[0] = rte_constant_bswap32(mac_addr[0]); 65786d36773SIgor Russkikh mac_addr[1] = rte_constant_bswap32(mac_addr[1]); 65886d36773SIgor Russkikh } 65986d36773SIgor Russkikh 660538da7a1SOlivier Matz rte_ether_addr_copy((struct rte_ether_addr *)mac_addr, 6616d13ea8eSOlivier Matz (struct rte_ether_addr *)mac); 66286d36773SIgor Russkikh 66386d36773SIgor Russkikh if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) { 66486d36773SIgor Russkikh /* chip revision */ 66586d36773SIgor Russkikh l = 0xE3000000U 66686d36773SIgor Russkikh | (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) 66786d36773SIgor Russkikh | (0x00 << 16); 66886d36773SIgor Russkikh h = 0x8001300EU; 66986d36773SIgor Russkikh 67086d36773SIgor Russkikh mac[5] = (u8)(0xFFU & l); 67186d36773SIgor Russkikh l >>= 8; 67286d36773SIgor Russkikh mac[4] = (u8)(0xFFU & l); 67386d36773SIgor Russkikh l >>= 8; 67486d36773SIgor Russkikh mac[3] = (u8)(0xFFU & l); 67586d36773SIgor Russkikh l >>= 8; 67686d36773SIgor Russkikh mac[2] = (u8)(0xFFU & l); 67786d36773SIgor Russkikh mac[1] = (u8)(0xFFU & h); 67886d36773SIgor Russkikh h >>= 8; 67986d36773SIgor Russkikh mac[0] = (u8)(0xFFU & h); 68086d36773SIgor Russkikh } 68186d36773SIgor Russkikh 68286d36773SIgor Russkikh return err; 68386d36773SIgor Russkikh } 68486d36773SIgor Russkikh 68586d36773SIgor Russkikh unsigned int hw_atl_utils_mbps_2_speed_index(unsigned int mbps) 68686d36773SIgor Russkikh { 68786d36773SIgor Russkikh unsigned int ret = 0U; 68886d36773SIgor Russkikh 68986d36773SIgor Russkikh switch (mbps) { 69086d36773SIgor Russkikh case 100U: 69186d36773SIgor Russkikh ret = 5U; 69286d36773SIgor Russkikh break; 69386d36773SIgor Russkikh 69486d36773SIgor Russkikh case 1000U: 69586d36773SIgor Russkikh ret = 4U; 69686d36773SIgor Russkikh break; 69786d36773SIgor Russkikh 69886d36773SIgor Russkikh case 2500U: 69986d36773SIgor Russkikh ret = 3U; 70086d36773SIgor Russkikh break; 70186d36773SIgor Russkikh 70286d36773SIgor Russkikh case 5000U: 70386d36773SIgor Russkikh ret = 1U; 70486d36773SIgor Russkikh break; 70586d36773SIgor Russkikh 70686d36773SIgor Russkikh case 10000U: 70786d36773SIgor Russkikh ret = 0U; 70886d36773SIgor Russkikh break; 70986d36773SIgor Russkikh 71086d36773SIgor Russkikh default: 71186d36773SIgor Russkikh break; 71286d36773SIgor Russkikh } 71386d36773SIgor Russkikh return ret; 71486d36773SIgor Russkikh } 71586d36773SIgor Russkikh 71686d36773SIgor Russkikh void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p) 71786d36773SIgor Russkikh { 71886d36773SIgor Russkikh u32 chip_features = 0U; 71986d36773SIgor Russkikh u32 val = hw_atl_reg_glb_mif_id_get(self); 72086d36773SIgor Russkikh u32 mif_rev = val & 0xFFU; 72186d36773SIgor Russkikh 72286d36773SIgor Russkikh if ((0xFU & mif_rev) == 1U) { 72386d36773SIgor Russkikh chip_features |= HAL_ATLANTIC_UTILS_CHIP_REVISION_A0 | 72486d36773SIgor Russkikh HAL_ATLANTIC_UTILS_CHIP_MPI_AQ | 72586d36773SIgor Russkikh HAL_ATLANTIC_UTILS_CHIP_MIPS; 72686d36773SIgor Russkikh } else if ((0xFU & mif_rev) == 2U) { 72786d36773SIgor Russkikh chip_features |= HAL_ATLANTIC_UTILS_CHIP_REVISION_B0 | 72886d36773SIgor Russkikh HAL_ATLANTIC_UTILS_CHIP_MPI_AQ | 72986d36773SIgor Russkikh HAL_ATLANTIC_UTILS_CHIP_MIPS | 73086d36773SIgor Russkikh HAL_ATLANTIC_UTILS_CHIP_TPO2 | 73186d36773SIgor Russkikh HAL_ATLANTIC_UTILS_CHIP_RPF2; 73286d36773SIgor Russkikh } else if ((0xFU & mif_rev) == 0xAU) { 73386d36773SIgor Russkikh chip_features |= HAL_ATLANTIC_UTILS_CHIP_REVISION_B1 | 73486d36773SIgor Russkikh HAL_ATLANTIC_UTILS_CHIP_MPI_AQ | 73586d36773SIgor Russkikh HAL_ATLANTIC_UTILS_CHIP_MIPS | 73686d36773SIgor Russkikh HAL_ATLANTIC_UTILS_CHIP_TPO2 | 73786d36773SIgor Russkikh HAL_ATLANTIC_UTILS_CHIP_RPF2; 73886d36773SIgor Russkikh } 73986d36773SIgor Russkikh 74086d36773SIgor Russkikh *p = chip_features; 74186d36773SIgor Russkikh } 74286d36773SIgor Russkikh 74386d36773SIgor Russkikh static int hw_atl_fw1x_deinit(struct aq_hw_s *self) 74486d36773SIgor Russkikh { 74586d36773SIgor Russkikh hw_atl_utils_mpi_set_speed(self, 0); 74686d36773SIgor Russkikh hw_atl_utils_mpi_set_state(self, MPI_DEINIT); 74786d36773SIgor Russkikh return 0; 74886d36773SIgor Russkikh } 74986d36773SIgor Russkikh 75086d36773SIgor Russkikh int hw_atl_utils_update_stats(struct aq_hw_s *self) 75186d36773SIgor Russkikh { 75286d36773SIgor Russkikh struct hw_aq_atl_utils_mbox mbox; 75386d36773SIgor Russkikh 75486d36773SIgor Russkikh hw_atl_utils_mpi_read_stats(self, &mbox); 75586d36773SIgor Russkikh 75686d36773SIgor Russkikh #define AQ_SDELTA(_N_) (self->curr_stats._N_ += \ 75786d36773SIgor Russkikh mbox.stats._N_ - self->last_stats._N_) 75886d36773SIgor Russkikh 75986d36773SIgor Russkikh if (1) {//self->aq_link_status.mbps) { 76086d36773SIgor Russkikh AQ_SDELTA(uprc); 76186d36773SIgor Russkikh AQ_SDELTA(mprc); 76286d36773SIgor Russkikh AQ_SDELTA(bprc); 76386d36773SIgor Russkikh AQ_SDELTA(erpt); 76486d36773SIgor Russkikh 76586d36773SIgor Russkikh AQ_SDELTA(uptc); 76686d36773SIgor Russkikh AQ_SDELTA(mptc); 76786d36773SIgor Russkikh AQ_SDELTA(bptc); 76886d36773SIgor Russkikh AQ_SDELTA(erpr); 76986d36773SIgor Russkikh AQ_SDELTA(ubrc); 77086d36773SIgor Russkikh AQ_SDELTA(ubtc); 77186d36773SIgor Russkikh AQ_SDELTA(mbrc); 77286d36773SIgor Russkikh AQ_SDELTA(mbtc); 77386d36773SIgor Russkikh AQ_SDELTA(bbrc); 77486d36773SIgor Russkikh AQ_SDELTA(bbtc); 77586d36773SIgor Russkikh AQ_SDELTA(dpc); 77686d36773SIgor Russkikh } 77786d36773SIgor Russkikh #undef AQ_SDELTA 77886d36773SIgor Russkikh self->curr_stats.dma_pkt_rc = 77986d36773SIgor Russkikh hw_atl_stats_rx_dma_good_pkt_counterlsw_get(self) + 78086d36773SIgor Russkikh ((u64)hw_atl_stats_rx_dma_good_pkt_countermsw_get(self) << 32); 78186d36773SIgor Russkikh self->curr_stats.dma_pkt_tc = 78286d36773SIgor Russkikh hw_atl_stats_tx_dma_good_pkt_counterlsw_get(self) + 78386d36773SIgor Russkikh ((u64)hw_atl_stats_tx_dma_good_pkt_countermsw_get(self) << 32); 78486d36773SIgor Russkikh self->curr_stats.dma_oct_rc = 78586d36773SIgor Russkikh hw_atl_stats_rx_dma_good_octet_counterlsw_get(self) + 78686d36773SIgor Russkikh ((u64)hw_atl_stats_rx_dma_good_octet_countermsw_get(self) << 32); 78786d36773SIgor Russkikh self->curr_stats.dma_oct_tc = 78886d36773SIgor Russkikh hw_atl_stats_tx_dma_good_octet_counterlsw_get(self) + 78986d36773SIgor Russkikh ((u64)hw_atl_stats_tx_dma_good_octet_countermsw_get(self) << 32); 79086d36773SIgor Russkikh 79186d36773SIgor Russkikh self->curr_stats.dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self); 79286d36773SIgor Russkikh 79386d36773SIgor Russkikh memcpy(&self->last_stats, &mbox.stats, sizeof(mbox.stats)); 79486d36773SIgor Russkikh 79586d36773SIgor Russkikh return 0; 79686d36773SIgor Russkikh } 79786d36773SIgor Russkikh 79886d36773SIgor Russkikh struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self) 79986d36773SIgor Russkikh { 80086d36773SIgor Russkikh return &self->curr_stats; 80186d36773SIgor Russkikh } 80286d36773SIgor Russkikh 80386d36773SIgor Russkikh static const u32 hw_atl_utils_hw_mac_regs[] = { 80486d36773SIgor Russkikh 0x00005580U, 0x00005590U, 0x000055B0U, 0x000055B4U, 80586d36773SIgor Russkikh 0x000055C0U, 0x00005B00U, 0x00005B04U, 0x00005B08U, 80686d36773SIgor Russkikh 0x00005B0CU, 0x00005B10U, 0x00005B14U, 0x00005B18U, 80786d36773SIgor Russkikh 0x00005B1CU, 0x00005B20U, 0x00005B24U, 0x00005B28U, 80886d36773SIgor Russkikh 0x00005B2CU, 0x00005B30U, 0x00005B34U, 0x00005B38U, 80986d36773SIgor Russkikh 0x00005B3CU, 0x00005B40U, 0x00005B44U, 0x00005B48U, 81086d36773SIgor Russkikh 0x00005B4CU, 0x00005B50U, 0x00005B54U, 0x00005B58U, 81186d36773SIgor Russkikh 0x00005B5CU, 0x00005B60U, 0x00005B64U, 0x00005B68U, 81286d36773SIgor Russkikh 0x00005B6CU, 0x00005B70U, 0x00005B74U, 0x00005B78U, 81386d36773SIgor Russkikh 0x00005B7CU, 0x00007C00U, 0x00007C04U, 0x00007C08U, 81486d36773SIgor Russkikh 0x00007C0CU, 0x00007C10U, 0x00007C14U, 0x00007C18U, 81586d36773SIgor Russkikh 0x00007C1CU, 0x00007C20U, 0x00007C40U, 0x00007C44U, 81686d36773SIgor Russkikh 0x00007C48U, 0x00007C4CU, 0x00007C50U, 0x00007C54U, 81786d36773SIgor Russkikh 0x00007C58U, 0x00007C5CU, 0x00007C60U, 0x00007C80U, 81886d36773SIgor Russkikh 0x00007C84U, 0x00007C88U, 0x00007C8CU, 0x00007C90U, 81986d36773SIgor Russkikh 0x00007C94U, 0x00007C98U, 0x00007C9CU, 0x00007CA0U, 82086d36773SIgor Russkikh 0x00007CC0U, 0x00007CC4U, 0x00007CC8U, 0x00007CCCU, 82186d36773SIgor Russkikh 0x00007CD0U, 0x00007CD4U, 0x00007CD8U, 0x00007CDCU, 82286d36773SIgor Russkikh 0x00007CE0U, 0x00000300U, 0x00000304U, 0x00000308U, 82386d36773SIgor Russkikh 0x0000030cU, 0x00000310U, 0x00000314U, 0x00000318U, 82486d36773SIgor Russkikh 0x0000031cU, 0x00000360U, 0x00000364U, 0x00000368U, 82586d36773SIgor Russkikh 0x0000036cU, 0x00000370U, 0x00000374U, 0x00006900U, 82686d36773SIgor Russkikh }; 82786d36773SIgor Russkikh 82886d36773SIgor Russkikh unsigned int hw_atl_utils_hw_get_reg_length(void) 82986d36773SIgor Russkikh { 83086d36773SIgor Russkikh return ARRAY_SIZE(hw_atl_utils_hw_mac_regs); 83186d36773SIgor Russkikh } 83286d36773SIgor Russkikh 83386d36773SIgor Russkikh int hw_atl_utils_hw_get_regs(struct aq_hw_s *self, 83486d36773SIgor Russkikh u32 *regs_buff) 83586d36773SIgor Russkikh { 83686d36773SIgor Russkikh unsigned int i = 0U; 83786d36773SIgor Russkikh unsigned int mac_regs_count = hw_atl_utils_hw_get_reg_length(); 83886d36773SIgor Russkikh 83986d36773SIgor Russkikh for (i = 0; i < mac_regs_count; i++) 84086d36773SIgor Russkikh regs_buff[i] = aq_hw_read_reg(self, 84186d36773SIgor Russkikh hw_atl_utils_hw_mac_regs[i]); 84286d36773SIgor Russkikh return 0; 84386d36773SIgor Russkikh } 84486d36773SIgor Russkikh 84586d36773SIgor Russkikh int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version) 84686d36773SIgor Russkikh { 84786d36773SIgor Russkikh *fw_version = aq_hw_read_reg(self, 0x18U); 84886d36773SIgor Russkikh return 0; 84986d36773SIgor Russkikh } 85086d36773SIgor Russkikh 85186d36773SIgor Russkikh static int aq_fw1x_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac) 85286d36773SIgor Russkikh { 85386d36773SIgor Russkikh struct hw_aq_atl_utils_fw_rpc *prpc = NULL; 85486d36773SIgor Russkikh unsigned int rpc_size = 0U; 85586d36773SIgor Russkikh int err = 0; 85686d36773SIgor Russkikh 85786d36773SIgor Russkikh err = hw_atl_utils_fw_rpc_wait(self, &prpc); 85886d36773SIgor Russkikh if (err < 0) 85986d36773SIgor Russkikh goto err_exit; 86086d36773SIgor Russkikh 86186d36773SIgor Russkikh memset(prpc, 0, sizeof(*prpc)); 86286d36773SIgor Russkikh 86386d36773SIgor Russkikh if (wol_enabled) { 86486d36773SIgor Russkikh rpc_size = sizeof(prpc->msg_id) + sizeof(prpc->msg_wol); 86586d36773SIgor Russkikh 86686d36773SIgor Russkikh prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD; 86786d36773SIgor Russkikh prpc->msg_wol.priority = 0x10000000; /* normal priority */ 86886d36773SIgor Russkikh prpc->msg_wol.pattern_id = 1U; 86986d36773SIgor Russkikh prpc->msg_wol.wol_packet_type = 2U; /* Magic Packet */ 87086d36773SIgor Russkikh 871538da7a1SOlivier Matz rte_ether_addr_copy((struct rte_ether_addr *)mac, 8726d13ea8eSOlivier Matz (struct rte_ether_addr *)&prpc->msg_wol.wol_pattern); 87386d36773SIgor Russkikh } else { 87486d36773SIgor Russkikh rpc_size = sizeof(prpc->msg_id) + sizeof(prpc->msg_del_id); 87586d36773SIgor Russkikh 87686d36773SIgor Russkikh prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL; 87786d36773SIgor Russkikh prpc->msg_wol.pattern_id = 1U; 87886d36773SIgor Russkikh } 87986d36773SIgor Russkikh 88086d36773SIgor Russkikh err = hw_atl_utils_fw_rpc_call(self, rpc_size); 8810b504bcfSIgor Russkikh 88286d36773SIgor Russkikh err_exit: 88386d36773SIgor Russkikh return err; 88486d36773SIgor Russkikh } 88586d36773SIgor Russkikh 88686d36773SIgor Russkikh static 88786d36773SIgor Russkikh int aq_fw1x_set_power(struct aq_hw_s *self, 88886d36773SIgor Russkikh unsigned int power_state __rte_unused, 88986d36773SIgor Russkikh u8 *mac) 89086d36773SIgor Russkikh { 89186d36773SIgor Russkikh struct hw_aq_atl_utils_fw_rpc *prpc = NULL; 89286d36773SIgor Russkikh unsigned int rpc_size = 0U; 89386d36773SIgor Russkikh int err = 0; 89486d36773SIgor Russkikh if (self->aq_nic_cfg->wol & AQ_NIC_WOL_ENABLED) { 89586d36773SIgor Russkikh err = aq_fw1x_set_wol(self, 1, mac); 89686d36773SIgor Russkikh 89786d36773SIgor Russkikh if (err < 0) 89886d36773SIgor Russkikh goto err_exit; 89986d36773SIgor Russkikh 90086d36773SIgor Russkikh rpc_size = sizeof(prpc->msg_id) + 90186d36773SIgor Russkikh sizeof(prpc->msg_enable_wakeup); 90286d36773SIgor Russkikh 90386d36773SIgor Russkikh err = hw_atl_utils_fw_rpc_wait(self, &prpc); 90486d36773SIgor Russkikh 90586d36773SIgor Russkikh if (err < 0) 90686d36773SIgor Russkikh goto err_exit; 90786d36773SIgor Russkikh 90886d36773SIgor Russkikh memset(prpc, 0, rpc_size); 90986d36773SIgor Russkikh 91086d36773SIgor Russkikh prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP; 91186d36773SIgor Russkikh prpc->msg_enable_wakeup.pattern_mask = 0x00000002; 91286d36773SIgor Russkikh 91386d36773SIgor Russkikh err = hw_atl_utils_fw_rpc_call(self, rpc_size); 91486d36773SIgor Russkikh if (err < 0) 91586d36773SIgor Russkikh goto err_exit; 91686d36773SIgor Russkikh } 91786d36773SIgor Russkikh 91886d36773SIgor Russkikh hw_atl_utils_mpi_set_speed(self, 0); 91986d36773SIgor Russkikh hw_atl_utils_mpi_set_state(self, MPI_POWER); 92086d36773SIgor Russkikh err_exit: 92186d36773SIgor Russkikh return err; 92286d36773SIgor Russkikh } 92386d36773SIgor Russkikh 92486d36773SIgor Russkikh 92586d36773SIgor Russkikh 92686d36773SIgor Russkikh const struct aq_fw_ops aq_fw_1x_ops = { 92786d36773SIgor Russkikh .init = hw_atl_utils_mpi_create, 92886d36773SIgor Russkikh .deinit = hw_atl_fw1x_deinit, 92986d36773SIgor Russkikh .reset = NULL, 93086d36773SIgor Russkikh .get_mac_permanent = hw_atl_utils_get_mac_permanent, 93186d36773SIgor Russkikh .set_link_speed = hw_atl_utils_mpi_set_speed, 93286d36773SIgor Russkikh .set_state = hw_atl_utils_mpi_set_state, 93386d36773SIgor Russkikh .update_link_status = hw_atl_utils_mpi_get_link_status, 93486d36773SIgor Russkikh .update_stats = hw_atl_utils_update_stats, 93586d36773SIgor Russkikh .set_power = aq_fw1x_set_power, 93686d36773SIgor Russkikh .get_temp = NULL, 93786d36773SIgor Russkikh .get_cable_len = NULL, 93886d36773SIgor Russkikh .set_eee_rate = NULL, 93986d36773SIgor Russkikh .get_eee_rate = NULL, 94086d36773SIgor Russkikh .set_flow_control = NULL, 94186d36773SIgor Russkikh .led_control = NULL, 94286d36773SIgor Russkikh .get_eeprom = NULL, 94386d36773SIgor Russkikh .set_eeprom = NULL, 94486d36773SIgor Russkikh }; 945