Commit c1be0bf0 authored by Dmitry Bogdanov's avatar Dmitry Bogdanov Committed by David S. Miller
Browse files

net: atlantic: common functions needed for basic A2 init/deinit hw_ops



This patch adds common functions (mostly FW-related), which are
needed for basic A2 HW initialization / deinitialization.

Signed-off-by: default avatarDmitry Bogdanov <dbogdanov@marvell.com>
Co-developed-by: default avatarIgor Russkikh <irusskikh@marvell.com>
Signed-off-by: default avatarIgor Russkikh <irusskikh@marvell.com>
Signed-off-by: default avatarMark Starovoytov <mstarovoitov@marvell.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ec7629e0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ atlantic-objs := aq_main.o \
	hw_atl/hw_atl_utils_fw2x.o \
	hw_atl/hw_atl_llh.o \
	hw_atl2/hw_atl2.o \
	hw_atl2/hw_atl2_utils.o \
	hw_atl2/hw_atl2_utils_fw.o \
	hw_atl2/hw_atl2_llh.o \
	macsec/macsec_api.o
+1 −2
Original line number Diff line number Diff line
@@ -53,7 +53,6 @@ enum mcp_area {
	MCP_AREA_SETTINGS = 0x20000000,
};

static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual);
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);
@@ -434,7 +433,7 @@ int hw_atl_write_fwsettings_dwords(struct aq_hw_s *self, u32 offset, u32 *p,
					     p, cnt, MCP_AREA_SETTINGS);
}

static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual)
int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual)
{
	const u32 dw_major_mask = 0xff000000U;
	const u32 dw_minor_mask = 0x00ffffffU;
+2 −0
Original line number Diff line number Diff line
@@ -634,6 +634,8 @@ int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size);
int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
			     struct hw_atl_utils_fw_rpc **rpc);

int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual);

extern const struct aq_fw_ops aq_fw_1x_ops;
extern const struct aq_fw_ops aq_fw_2x_ops;

+139 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Atlantic Network Driver
 * Copyright (C) 2020 Marvell International Ltd.
 */

#include <linux/iopoll.h>

#include "aq_hw_utils.h"
#include "hw_atl/hw_atl_utils.h"
#include "hw_atl2_utils.h"
#include "hw_atl2_llh.h"
#include "hw_atl2_llh_internal.h"

#define HW_ATL2_FW_VER_1X          0x01000000U

#define AQ_A2_BOOT_STARTED         BIT(0x18)
#define AQ_A2_CRASH_INIT           BIT(0x1B)
#define AQ_A2_BOOT_CODE_FAILED     BIT(0x1C)
#define AQ_A2_FW_INIT_FAILED       BIT(0x1D)
#define AQ_A2_FW_INIT_COMP_SUCCESS BIT(0x1F)

#define AQ_A2_FW_BOOT_FAILED_MASK (AQ_A2_CRASH_INIT | \
				   AQ_A2_BOOT_CODE_FAILED | \
				   AQ_A2_FW_INIT_FAILED)
#define AQ_A2_FW_BOOT_COMPLETE_MASK (AQ_A2_FW_BOOT_FAILED_MASK | \
				     AQ_A2_FW_INIT_COMP_SUCCESS)

#define AQ_A2_FW_BOOT_REQ_REBOOT        BIT(0x0)
#define AQ_A2_FW_BOOT_REQ_HOST_BOOT     BIT(0x8)
#define AQ_A2_FW_BOOT_REQ_MAC_FAST_BOOT BIT(0xA)
#define AQ_A2_FW_BOOT_REQ_PHY_FAST_BOOT BIT(0xB)

int hw_atl2_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
{
	int err;

	self->fw_ver_actual = hw_atl2_utils_get_fw_version(self);

	if (hw_atl_utils_ver_match(HW_ATL2_FW_VER_1X,
				   self->fw_ver_actual) == 0) {
		*fw_ops = &aq_a2_fw_ops;
	} else {
		aq_pr_err("Bad FW version detected: %x, but continue\n",
			  self->fw_ver_actual);
		*fw_ops = &aq_a2_fw_ops;
	}
	aq_pr_trace("Detect ATL2FW %x\n", self->fw_ver_actual);
	self->aq_fw_ops = *fw_ops;
	err = self->aq_fw_ops->init(self);

	self->chip_features |= ATL_HW_CHIP_ANTIGUA;

	return err;
}

static bool hw_atl2_mcp_boot_complete(struct aq_hw_s *self)
{
	u32 rbl_status;

	rbl_status = hw_atl2_mif_mcp_boot_reg_get(self);
	if (rbl_status & AQ_A2_FW_BOOT_COMPLETE_MASK)
		return true;

	/* Host boot requested */
	if (hw_atl2_mif_host_req_int_get(self) & HW_ATL2_MCP_HOST_REQ_INT_READY)
		return true;

	return false;
}

int hw_atl2_utils_soft_reset(struct aq_hw_s *self)
{
	bool rbl_complete = false;
	u32 rbl_status = 0;
	u32 rbl_request;
	int err;

	err = readx_poll_timeout_atomic(hw_atl2_mif_mcp_boot_reg_get, self,
				rbl_status,
				((rbl_status & AQ_A2_BOOT_STARTED) &&
				 (rbl_status != 0xFFFFFFFFu)),
				10, 500000);
	if (err)
		aq_pr_trace("Boot code probably hanged, reboot anyway");

	hw_atl2_mif_host_req_int_clr(self, 0x01);
	rbl_request = AQ_A2_FW_BOOT_REQ_REBOOT;
#ifdef AQ_CFG_FAST_START
	rbl_request |= AQ_A2_FW_BOOT_REQ_MAC_FAST_BOOT;
#endif
	hw_atl2_mif_mcp_boot_reg_set(self, rbl_request);

	/* Wait for RBL boot */
	err = readx_poll_timeout_atomic(hw_atl2_mif_mcp_boot_reg_get, self,
				rbl_status,
				((rbl_status & AQ_A2_BOOT_STARTED) &&
				 (rbl_status != 0xFFFFFFFFu)),
				10, 200000);
	if (err) {
		aq_pr_err("Boot code hanged");
		goto err_exit;
	}

	err = readx_poll_timeout_atomic(hw_atl2_mcp_boot_complete, self,
					rbl_complete,
					rbl_complete,
					10, 2000000);

	if (err) {
		aq_pr_err("FW Restart timed out");
		goto err_exit;
	}

	rbl_status = hw_atl2_mif_mcp_boot_reg_get(self);

	if (rbl_status & AQ_A2_FW_BOOT_FAILED_MASK) {
		err = -EIO;
		aq_pr_err("FW Restart failed");
		goto err_exit;
	}

	if (hw_atl2_mif_host_req_int_get(self) &
	    HW_ATL2_MCP_HOST_REQ_INT_READY) {
		err = -EIO;
		aq_pr_err("No FW detected. Dynamic FW load not implemented");
		goto err_exit;
	}

	if (self->aq_fw_ops) {
		err = self->aq_fw_ops->init(self);
		if (err) {
			aq_pr_err("FW Init failed");
			goto err_exit;
		}
	}

err_exit:
	return err;
}
+8 −0
Original line number Diff line number Diff line
@@ -6,6 +6,8 @@
#ifndef HW_ATL2_UTILS_H
#define HW_ATL2_UTILS_H

#include "aq_hw.h"

/* F W    A P I */

struct link_options_s {
@@ -590,6 +592,12 @@ struct fw_interface_out {
#define  AQ_HOST_MODE_LOW_POWER    3U
#define  AQ_HOST_MODE_SHUTDOWN     4U

int hw_atl2_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops);

int hw_atl2_utils_soft_reset(struct aq_hw_s *self);

u32 hw_atl2_utils_get_fw_version(struct aq_hw_s *self);

int hw_atl2_utils_get_action_resolve_table_caps(struct aq_hw_s *self,
						u8 *base_index, u8 *count);

Loading