// SPDX-License-Identifier: GPL-2.0-only
/* Atlantic Network Driver
*
* Copyright (C) 2014-2019 aQuantia Corporation
* Copyright (C) 2019-2020 Marvell International Ltd.
*/
/* File hw_atl_utils.c: Definition of common functions for Atlantic hardware
* abstraction layer.
*/
#include "../aq_nic.h"
#include "../aq_hw_utils.h"
#include "hw_atl_utils.h"
#include "hw_atl_llh.h"
#include "hw_atl_llh_internal.h"
#include <linux/random.h>
#define HW_ATL_UCP_0X370_REG 0x0370U
#define HW_ATL_MIF_CMD 0x0200U
#define HW_ATL_MIF_ADDR 0x0208U
#define HW_ATL_MIF_VAL 0x020CU
#define HW_ATL_MPI_RPC_ADDR 0x0334U
#define HW_ATL_RPC_CONTROL_ADR 0x0338U
#define HW_ATL_RPC_STATE_ADR 0x033CU
#define HW_ATL_MPI_FW_VERSION 0x18
#define HW_ATL_MPI_CONTROL_ADR 0x0368U
#define HW_ATL_MPI_STATE_ADR 0x036CU
#define HW_ATL_MPI_STATE_MSK 0x00FFU
#define HW_ATL_MPI_STATE_SHIFT 0U
#define HW_ATL_MPI_SPEED_MSK 0x00FF0000U
#define HW_ATL_MPI_SPEED_SHIFT 16U
#define HW_ATL_MPI_DIRTY_WAKE_MSK 0x02000000U
#define HW_ATL_MPI_DAISY_CHAIN_STATUS 0x704
#define HW_ATL_MPI_BOOT_EXIT_CODE 0x388
#define HW_ATL_MAC_PHY_CONTROL 0x4000
#define HW_ATL_MAC_PHY_MPI_RESET_BIT 0x1D
#define HW_ATL_FW_VER_1X 0x01050006U
#define HW_ATL_FW_VER_2X 0x02000000U
#define HW_ATL_FW_VER_3X 0x03000000U
#define HW_ATL_FW_VER_4X 0x04000000U
#define FORCE_FLASHLESS 0
enum mcp_area {
MCP_AREA_CONFIG = 0x80000000,
MCP_AREA_SETTINGS = 0x20000000,
};
static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state);
static u32 hw_atl_utils_get_mpi_mbox_tid(struct aq_hw_s *self);
static u32 hw_atl_utils_mpi_get_state(struct aq_hw_s *self);
static u32 hw_atl_utils_mif_cmd_get(struct aq_hw_s *self);
static u32 hw_atl_utils_mif_addr_get(struct aq_hw_s *self);
static u32 hw_atl_utils_rpc_state_get(struct aq_hw_s *self);
static u32 aq_fw1x_rpc_get(struct aq_hw_s *self);
int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
{
int err = 0;
hw_atl_utils_hw_chip_features_init(self,
&self->chip_features);
self->fw_ver_actual = hw_atl_utils_get_fw_version(self);
if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, self->fw_ver_actual)) {
*fw_ops = &aq_fw_1x_ops;
} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X, self->fw_ver_actual)) {
*fw_ops = &aq_fw_2x_ops;
} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X, self->fw_ver_actual)) {
*fw_ops = &aq_fw_2x_ops;
} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_4X, self->fw_ver_actual)) {
*fw_ops = &aq_fw_2x_ops;
} else {
aq_pr_err("Bad FW version detected: %x\n",
self->fw_ver_actual);
return -EOPNOTSUPP;
}
self->aq_fw_ops = *fw_ops;
err = self->aq_fw_ops->init(self);
return err;
}
static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self)
{
u32 gsr, val;
int k = 0;
aq_hw_write_reg(self, 0x404, 0x40e1);
AQ_HW_SLEEP(50);
/* Cleanup SPI */
val = aq_hw_read_reg(self, 0x53C);
aq_hw_write_reg(self, 0x53C, val | 0x10);
gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000);
/* Kickstart MAC */
aq_hw_write_reg(self, 0x404, 0x80e0);
aq_hw_write_reg(self, 0x32a8, 0x0);
aq_hw_write_reg(self, 0x520, 0x1);
/* Reset SPI again because of possible interrupted SPI burst */
val = aq_hw_read_reg(self, 0x53C);
aq_hw_write_reg(self, 0x53C, val | 0x10);
AQ_HW_SLEEP(10);
/* Clear SPI reset state */
aq_hw_write_reg(self, 0x53C, val & ~0x10);
aq_hw_write_reg(self, 0x404, 0x180e0);
for (k = 0; k < 1000; k++) {
u32 flb_status = aq_hw_read_reg(self,
HW_ATL_MPI_DAISY_CHAIN_STATUS);
flb_status = flb_status & 0x10;
if (flb_status)
break;
AQ_HW_SLEEP(10);
}
if (k == 1000) <