]> git.baikalelectronics.ru Git - kernel.git/commitdiff
net: atlantic: common functions needed for basic A2 init/deinit hw_ops
authorDmitry Bogdanov <dbogdanov@marvell.com>
Thu, 30 Apr 2020 08:04:43 +0000 (11:04 +0300)
committerDavid S. Miller <davem@davemloft.net>
Fri, 1 May 2020 22:37:58 +0000 (15:37 -0700)
This patch adds common functions (mostly FW-related), which are
needed for basic A2 HW initialization / deinitialization.

Signed-off-by: Dmitry Bogdanov <dbogdanov@marvell.com>
Co-developed-by: Igor Russkikh <irusskikh@marvell.com>
Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/aquantia/atlantic/Makefile
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.c [new file with mode: 0644]
drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.h
drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c

index 23f0e5b5fcdbb7ce2ffaa1eced4a0f0c0494f53a..130a105d03f3b1fbe721fef1da751c80dee7b649 100644 (file)
@@ -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
index 20655a2170cc0b93e4e43b2bab4e094eeb60ca3d..1100d40a0302687c5911cbc2537e636b8968ca47 100644 (file)
@@ -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;
index 5db57ea9a5bdd4aa69b2a95061c69bad0e345799..99c1b6644ec3cb5ee5f0b8dabaa742d70ed24931 100644 (file)
@@ -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;
 
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.c
new file mode 100644 (file)
index 0000000..85ccc9a
--- /dev/null
@@ -0,0 +1,139 @@
+// 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;
+}
index 5421fbed3db5b60b29995314fec39664419dfcf1..2317dd8459d0f28b1b56ac5d85135bc5aab60617 100644 (file)
@@ -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);
 
index c3e0e5575810d6c065c327f66b83ac276f3c4d23..f5fb4b11f51a2bdb7c397034d17b02e2b5a8f4d3 100644 (file)
@@ -301,6 +301,18 @@ static int aq_a2_fw_renegotiate(struct aq_hw_s *self)
        return err;
 }
 
+u32 hw_atl2_utils_get_fw_version(struct aq_hw_s *self)
+{
+       struct version_s version;
+
+       hw_atl2_shared_buffer_read_safe(self, version, &version);
+
+       /* A2 FW version is stored in reverse order */
+       return version.mac.major << 24 |
+              version.mac.minor << 16 |
+              version.mac.build;
+}
+
 int hw_atl2_utils_get_action_resolve_table_caps(struct aq_hw_s *self,
                                                u8 *base_index, u8 *count)
 {