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