1c1be0bf0SDmitry Bogdanov // SPDX-License-Identifier: GPL-2.0-only
2c1be0bf0SDmitry Bogdanov /* Atlantic Network Driver
3c1be0bf0SDmitry Bogdanov * Copyright (C) 2020 Marvell International Ltd.
4c1be0bf0SDmitry Bogdanov */
5c1be0bf0SDmitry Bogdanov
6c1be0bf0SDmitry Bogdanov #include <linux/iopoll.h>
7c1be0bf0SDmitry Bogdanov
8c1be0bf0SDmitry Bogdanov #include "aq_hw_utils.h"
9c1be0bf0SDmitry Bogdanov #include "hw_atl/hw_atl_utils.h"
10c1be0bf0SDmitry Bogdanov #include "hw_atl2_utils.h"
11c1be0bf0SDmitry Bogdanov #include "hw_atl2_llh.h"
12c1be0bf0SDmitry Bogdanov #include "hw_atl2_llh_internal.h"
13c1be0bf0SDmitry Bogdanov
14c1be0bf0SDmitry Bogdanov #define HW_ATL2_FW_VER_1X 0x01000000U
15c1be0bf0SDmitry Bogdanov
16c1be0bf0SDmitry Bogdanov #define AQ_A2_BOOT_STARTED BIT(0x18)
17c1be0bf0SDmitry Bogdanov #define AQ_A2_CRASH_INIT BIT(0x1B)
18c1be0bf0SDmitry Bogdanov #define AQ_A2_BOOT_CODE_FAILED BIT(0x1C)
19c1be0bf0SDmitry Bogdanov #define AQ_A2_FW_INIT_FAILED BIT(0x1D)
20c1be0bf0SDmitry Bogdanov #define AQ_A2_FW_INIT_COMP_SUCCESS BIT(0x1F)
21c1be0bf0SDmitry Bogdanov
22c1be0bf0SDmitry Bogdanov #define AQ_A2_FW_BOOT_FAILED_MASK (AQ_A2_CRASH_INIT | \
23c1be0bf0SDmitry Bogdanov AQ_A2_BOOT_CODE_FAILED | \
24c1be0bf0SDmitry Bogdanov AQ_A2_FW_INIT_FAILED)
25c1be0bf0SDmitry Bogdanov #define AQ_A2_FW_BOOT_COMPLETE_MASK (AQ_A2_FW_BOOT_FAILED_MASK | \
26c1be0bf0SDmitry Bogdanov AQ_A2_FW_INIT_COMP_SUCCESS)
27c1be0bf0SDmitry Bogdanov
28c1be0bf0SDmitry Bogdanov #define AQ_A2_FW_BOOT_REQ_REBOOT BIT(0x0)
29c1be0bf0SDmitry Bogdanov #define AQ_A2_FW_BOOT_REQ_HOST_BOOT BIT(0x8)
30c1be0bf0SDmitry Bogdanov #define AQ_A2_FW_BOOT_REQ_MAC_FAST_BOOT BIT(0xA)
31c1be0bf0SDmitry Bogdanov #define AQ_A2_FW_BOOT_REQ_PHY_FAST_BOOT BIT(0xB)
32c1be0bf0SDmitry Bogdanov
hw_atl2_utils_initfw(struct aq_hw_s * self,const struct aq_fw_ops ** fw_ops)33c1be0bf0SDmitry Bogdanov int hw_atl2_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
34c1be0bf0SDmitry Bogdanov {
35c1be0bf0SDmitry Bogdanov int err;
36c1be0bf0SDmitry Bogdanov
37c1be0bf0SDmitry Bogdanov self->fw_ver_actual = hw_atl2_utils_get_fw_version(self);
38c1be0bf0SDmitry Bogdanov
39b567edbfSMark Starovoytov if (hw_atl_utils_ver_match(HW_ATL2_FW_VER_1X, self->fw_ver_actual)) {
40c1be0bf0SDmitry Bogdanov *fw_ops = &aq_a2_fw_ops;
41c1be0bf0SDmitry Bogdanov } else {
42c1be0bf0SDmitry Bogdanov aq_pr_err("Bad FW version detected: %x, but continue\n",
43c1be0bf0SDmitry Bogdanov self->fw_ver_actual);
44c1be0bf0SDmitry Bogdanov *fw_ops = &aq_a2_fw_ops;
45c1be0bf0SDmitry Bogdanov }
46c1be0bf0SDmitry Bogdanov aq_pr_trace("Detect ATL2FW %x\n", self->fw_ver_actual);
47c1be0bf0SDmitry Bogdanov self->aq_fw_ops = *fw_ops;
48c1be0bf0SDmitry Bogdanov err = self->aq_fw_ops->init(self);
49c1be0bf0SDmitry Bogdanov
50c1be0bf0SDmitry Bogdanov self->chip_features |= ATL_HW_CHIP_ANTIGUA;
51c1be0bf0SDmitry Bogdanov
52c1be0bf0SDmitry Bogdanov return err;
53c1be0bf0SDmitry Bogdanov }
54c1be0bf0SDmitry Bogdanov
hw_atl2_mcp_boot_complete(struct aq_hw_s * self)55c1be0bf0SDmitry Bogdanov static bool hw_atl2_mcp_boot_complete(struct aq_hw_s *self)
56c1be0bf0SDmitry Bogdanov {
57c1be0bf0SDmitry Bogdanov u32 rbl_status;
58c1be0bf0SDmitry Bogdanov
59c1be0bf0SDmitry Bogdanov rbl_status = hw_atl2_mif_mcp_boot_reg_get(self);
60c1be0bf0SDmitry Bogdanov if (rbl_status & AQ_A2_FW_BOOT_COMPLETE_MASK)
61c1be0bf0SDmitry Bogdanov return true;
62c1be0bf0SDmitry Bogdanov
63c1be0bf0SDmitry Bogdanov /* Host boot requested */
64c1be0bf0SDmitry Bogdanov if (hw_atl2_mif_host_req_int_get(self) & HW_ATL2_MCP_HOST_REQ_INT_READY)
65c1be0bf0SDmitry Bogdanov return true;
66c1be0bf0SDmitry Bogdanov
67c1be0bf0SDmitry Bogdanov return false;
68c1be0bf0SDmitry Bogdanov }
69c1be0bf0SDmitry Bogdanov
hw_atl2_utils_soft_reset(struct aq_hw_s * self)70c1be0bf0SDmitry Bogdanov int hw_atl2_utils_soft_reset(struct aq_hw_s *self)
71c1be0bf0SDmitry Bogdanov {
72c1be0bf0SDmitry Bogdanov bool rbl_complete = false;
73c1be0bf0SDmitry Bogdanov u32 rbl_status = 0;
74c1be0bf0SDmitry Bogdanov u32 rbl_request;
75c1be0bf0SDmitry Bogdanov int err;
76c1be0bf0SDmitry Bogdanov
77c1be0bf0SDmitry Bogdanov hw_atl2_mif_host_req_int_clr(self, 0x01);
78c1be0bf0SDmitry Bogdanov rbl_request = AQ_A2_FW_BOOT_REQ_REBOOT;
79c1be0bf0SDmitry Bogdanov #ifdef AQ_CFG_FAST_START
80c1be0bf0SDmitry Bogdanov rbl_request |= AQ_A2_FW_BOOT_REQ_MAC_FAST_BOOT;
81c1be0bf0SDmitry Bogdanov #endif
82c1be0bf0SDmitry Bogdanov hw_atl2_mif_mcp_boot_reg_set(self, rbl_request);
83c1be0bf0SDmitry Bogdanov
84c1be0bf0SDmitry Bogdanov /* Wait for RBL boot */
85c1be0bf0SDmitry Bogdanov err = readx_poll_timeout_atomic(hw_atl2_mif_mcp_boot_reg_get, self,
86c1be0bf0SDmitry Bogdanov rbl_status,
87c1be0bf0SDmitry Bogdanov ((rbl_status & AQ_A2_BOOT_STARTED) &&
88c1be0bf0SDmitry Bogdanov (rbl_status != 0xFFFFFFFFu)),
89c1be0bf0SDmitry Bogdanov 10, 200000);
90c1be0bf0SDmitry Bogdanov if (err) {
91c1be0bf0SDmitry Bogdanov aq_pr_err("Boot code hanged");
92c1be0bf0SDmitry Bogdanov goto err_exit;
93c1be0bf0SDmitry Bogdanov }
94c1be0bf0SDmitry Bogdanov
95c1be0bf0SDmitry Bogdanov err = readx_poll_timeout_atomic(hw_atl2_mcp_boot_complete, self,
96c1be0bf0SDmitry Bogdanov rbl_complete,
97c1be0bf0SDmitry Bogdanov rbl_complete,
98c1be0bf0SDmitry Bogdanov 10, 2000000);
99c1be0bf0SDmitry Bogdanov
100c1be0bf0SDmitry Bogdanov if (err) {
101c1be0bf0SDmitry Bogdanov aq_pr_err("FW Restart timed out");
102c1be0bf0SDmitry Bogdanov goto err_exit;
103c1be0bf0SDmitry Bogdanov }
104c1be0bf0SDmitry Bogdanov
105c1be0bf0SDmitry Bogdanov rbl_status = hw_atl2_mif_mcp_boot_reg_get(self);
106c1be0bf0SDmitry Bogdanov
107c1be0bf0SDmitry Bogdanov if (rbl_status & AQ_A2_FW_BOOT_FAILED_MASK) {
108c1be0bf0SDmitry Bogdanov err = -EIO;
109c1be0bf0SDmitry Bogdanov aq_pr_err("FW Restart failed");
110c1be0bf0SDmitry Bogdanov goto err_exit;
111c1be0bf0SDmitry Bogdanov }
112c1be0bf0SDmitry Bogdanov
113c1be0bf0SDmitry Bogdanov if (hw_atl2_mif_host_req_int_get(self) &
114c1be0bf0SDmitry Bogdanov HW_ATL2_MCP_HOST_REQ_INT_READY) {
115c1be0bf0SDmitry Bogdanov err = -EIO;
116c1be0bf0SDmitry Bogdanov aq_pr_err("No FW detected. Dynamic FW load not implemented");
117c1be0bf0SDmitry Bogdanov goto err_exit;
118c1be0bf0SDmitry Bogdanov }
119c1be0bf0SDmitry Bogdanov
120c1be0bf0SDmitry Bogdanov if (self->aq_fw_ops) {
121c1be0bf0SDmitry Bogdanov err = self->aq_fw_ops->init(self);
122c1be0bf0SDmitry Bogdanov if (err) {
123c1be0bf0SDmitry Bogdanov aq_pr_err("FW Init failed");
124c1be0bf0SDmitry Bogdanov goto err_exit;
125c1be0bf0SDmitry Bogdanov }
126c1be0bf0SDmitry Bogdanov }
127c1be0bf0SDmitry Bogdanov
128c1be0bf0SDmitry Bogdanov err_exit:
129c1be0bf0SDmitry Bogdanov return err;
130c1be0bf0SDmitry Bogdanov }
131