175a6faf6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2843e1396SMark Starovoytov /* Atlantic Network Driver
3843e1396SMark Starovoytov  *
4843e1396SMark Starovoytov  * Copyright (C) 2014-2019 aQuantia Corporation
5843e1396SMark Starovoytov  * Copyright (C) 2019-2020 Marvell International Ltd.
698c4c201SDavid VomLehn  */
798c4c201SDavid VomLehn 
898c4c201SDavid VomLehn /* File hw_atl_utils.c: Definition of common functions for Atlantic hardware
998c4c201SDavid VomLehn  * abstraction layer.
1098c4c201SDavid VomLehn  */
1198c4c201SDavid VomLehn 
121a713f87SIgor Russkikh #include "../aq_nic.h"
1398c4c201SDavid VomLehn #include "../aq_hw_utils.h"
1498c4c201SDavid VomLehn #include "hw_atl_utils.h"
1598c4c201SDavid VomLehn #include "hw_atl_llh.h"
160c58c35fSIgor Russkikh #include "hw_atl_llh_internal.h"
1798c4c201SDavid VomLehn 
1898c4c201SDavid VomLehn #include <linux/random.h>
1998c4c201SDavid VomLehn 
2098c4c201SDavid VomLehn #define HW_ATL_UCP_0X370_REG    0x0370U
2198c4c201SDavid VomLehn 
2247203b34SIgor Russkikh #define HW_ATL_MIF_CMD          0x0200U
2347203b34SIgor Russkikh #define HW_ATL_MIF_ADDR         0x0208U
2447203b34SIgor Russkikh #define HW_ATL_MIF_VAL          0x020CU
2547203b34SIgor Russkikh 
26e7b5f97eSIgor Russkikh #define HW_ATL_MPI_RPC_ADDR     0x0334U
276a7f2277SNikita Danilov #define HW_ATL_RPC_CONTROL_ADR  0x0338U
286a7f2277SNikita Danilov #define HW_ATL_RPC_STATE_ADR    0x033CU
296a7f2277SNikita Danilov 
300c58c35fSIgor Russkikh #define HW_ATL_MPI_FW_VERSION	0x18
3198c4c201SDavid VomLehn #define HW_ATL_MPI_CONTROL_ADR  0x0368U
3298c4c201SDavid VomLehn #define HW_ATL_MPI_STATE_ADR    0x036CU
3398c4c201SDavid VomLehn 
3498c4c201SDavid VomLehn #define HW_ATL_MPI_STATE_MSK      0x00FFU
3598c4c201SDavid VomLehn #define HW_ATL_MPI_STATE_SHIFT    0U
3644e00dd8SIgor Russkikh #define HW_ATL_MPI_SPEED_MSK      0x00FF0000U
3798c4c201SDavid VomLehn #define HW_ATL_MPI_SPEED_SHIFT    16U
3844e00dd8SIgor Russkikh #define HW_ATL_MPI_DIRTY_WAKE_MSK 0x02000000U
3998c4c201SDavid VomLehn 
40c8c82eb3SIgor Russkikh #define HW_ATL_MPI_DAISY_CHAIN_STATUS	0x704
41c8c82eb3SIgor Russkikh #define HW_ATL_MPI_BOOT_EXIT_CODE	0x388
42c8c82eb3SIgor Russkikh 
43c8c82eb3SIgor Russkikh #define HW_ATL_MAC_PHY_CONTROL	0x4000
44c8c82eb3SIgor Russkikh #define HW_ATL_MAC_PHY_MPI_RESET_BIT 0x1D
45c8c82eb3SIgor Russkikh 
460c58c35fSIgor Russkikh #define HW_ATL_FW_VER_1X 0x01050006U
47a57d3929SIgor Russkikh #define HW_ATL_FW_VER_2X 0x02000000U
48a57d3929SIgor Russkikh #define HW_ATL_FW_VER_3X 0x03000000U
490c58c35fSIgor Russkikh 
50c8c82eb3SIgor Russkikh #define FORCE_FLASHLESS 0
51c8c82eb3SIgor Russkikh 
52dc12f75aSNikita Danilov enum mcp_area {
53dc12f75aSNikita Danilov 	MCP_AREA_CONFIG = 0x80000000,
54dc12f75aSNikita Danilov 	MCP_AREA_SETTINGS = 0x20000000,
55dc12f75aSNikita Danilov };
56dc12f75aSNikita Danilov 
57cce96d18SIgor Russkikh static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
58cce96d18SIgor Russkikh 				      enum hal_atl_utils_fw_state_e state);
596a7f2277SNikita Danilov static u32 hw_atl_utils_get_mpi_mbox_tid(struct aq_hw_s *self);
606a7f2277SNikita Danilov static u32 hw_atl_utils_mpi_get_state(struct aq_hw_s *self);
616a7f2277SNikita Danilov static u32 hw_atl_utils_mif_cmd_get(struct aq_hw_s *self);
626a7f2277SNikita Danilov static u32 hw_atl_utils_mif_addr_get(struct aq_hw_s *self);
636a7f2277SNikita Danilov static u32 hw_atl_utils_rpc_state_get(struct aq_hw_s *self);
64e7b5f97eSIgor Russkikh static u32 aq_fw1x_rpc_get(struct aq_hw_s *self);
656a7f2277SNikita Danilov 
660c58c35fSIgor Russkikh int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
670c58c35fSIgor Russkikh {
680c58c35fSIgor Russkikh 	int err = 0;
690c58c35fSIgor Russkikh 
700c58c35fSIgor Russkikh 	hw_atl_utils_hw_chip_features_init(self,
710c58c35fSIgor Russkikh 					   &self->chip_features);
720c58c35fSIgor Russkikh 
7336e90a52SNikita Danilov 	self->fw_ver_actual = hw_atl_utils_get_fw_version(self);
740c58c35fSIgor Russkikh 
75b567edbfSMark Starovoytov 	if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, self->fw_ver_actual)) {
760c58c35fSIgor Russkikh 		*fw_ops = &aq_fw_1x_ops;
77b567edbfSMark Starovoytov 	} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X, self->fw_ver_actual)) {
78a57d3929SIgor Russkikh 		*fw_ops = &aq_fw_2x_ops;
79b567edbfSMark Starovoytov 	} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X, self->fw_ver_actual)) {
80a57d3929SIgor Russkikh 		*fw_ops = &aq_fw_2x_ops;
81c8c82eb3SIgor Russkikh 	} else {
820c58c35fSIgor Russkikh 		aq_pr_err("Bad FW version detected: %x\n",
830c58c35fSIgor Russkikh 			  self->fw_ver_actual);
840c58c35fSIgor Russkikh 		return -EOPNOTSUPP;
850c58c35fSIgor Russkikh 	}
860c58c35fSIgor Russkikh 	self->aq_fw_ops = *fw_ops;
870c58c35fSIgor Russkikh 	err = self->aq_fw_ops->init(self);
887b0c342fSNikita Danilov 
890c58c35fSIgor Russkikh 	return err;
900c58c35fSIgor Russkikh }
910c58c35fSIgor Russkikh 
92c8c82eb3SIgor Russkikh static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self)
93c8c82eb3SIgor Russkikh {
941bf9a752SIgor Russkikh 	u32 gsr, val;
95c8c82eb3SIgor Russkikh 	int k = 0;
96c8c82eb3SIgor Russkikh 
97c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x40e1);
98c8c82eb3SIgor Russkikh 	AQ_HW_SLEEP(50);
99c8c82eb3SIgor Russkikh 
100c8c82eb3SIgor Russkikh 	/* Cleanup SPI */
1011bf9a752SIgor Russkikh 	val = aq_hw_read_reg(self, 0x53C);
1021bf9a752SIgor Russkikh 	aq_hw_write_reg(self, 0x53C, val | 0x10);
103c8c82eb3SIgor Russkikh 
104c8c82eb3SIgor Russkikh 	gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
105c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000);
106c8c82eb3SIgor Russkikh 
107c8c82eb3SIgor Russkikh 	/* Kickstart MAC */
108c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x80e0);
109c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x32a8, 0x0);
110c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x520, 0x1);
1111bf9a752SIgor Russkikh 
1121bf9a752SIgor Russkikh 	/* Reset SPI again because of possible interrupted SPI burst */
1131bf9a752SIgor Russkikh 	val = aq_hw_read_reg(self, 0x53C);
1141bf9a752SIgor Russkikh 	aq_hw_write_reg(self, 0x53C, val | 0x10);
115c8c82eb3SIgor Russkikh 	AQ_HW_SLEEP(10);
1161bf9a752SIgor Russkikh 	/* Clear SPI reset state */
1171bf9a752SIgor Russkikh 	aq_hw_write_reg(self, 0x53C, val & ~0x10);
1181bf9a752SIgor Russkikh 
119c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x180e0);
120c8c82eb3SIgor Russkikh 
121c8c82eb3SIgor Russkikh 	for (k = 0; k < 1000; k++) {
122c8c82eb3SIgor Russkikh 		u32 flb_status = aq_hw_read_reg(self,
123c8c82eb3SIgor Russkikh 						HW_ATL_MPI_DAISY_CHAIN_STATUS);
124c8c82eb3SIgor Russkikh 
125c8c82eb3SIgor Russkikh 		flb_status = flb_status & 0x10;
126c8c82eb3SIgor Russkikh 		if (flb_status)
127c8c82eb3SIgor Russkikh 			break;
128c8c82eb3SIgor Russkikh 		AQ_HW_SLEEP(10);
129c8c82eb3SIgor Russkikh 	}
130c8c82eb3SIgor Russkikh 	if (k == 1000) {
131c8c82eb3SIgor Russkikh 		aq_pr_err("MAC kickstart failed\n");
132c8c82eb3SIgor Russkikh 		return -EIO;
133c8c82eb3SIgor Russkikh 	}
134c8c82eb3SIgor Russkikh 
135c8c82eb3SIgor Russkikh 	/* FW reset */
136c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x80e0);
137c8c82eb3SIgor Russkikh 	AQ_HW_SLEEP(50);
138c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x3a0, 0x1);
139c8c82eb3SIgor Russkikh 
140c8c82eb3SIgor Russkikh 	/* Kickstart PHY - skipped */
141c8c82eb3SIgor Russkikh 
142c8c82eb3SIgor Russkikh 	/* Global software reset*/
143c8c82eb3SIgor Russkikh 	hw_atl_rx_rx_reg_res_dis_set(self, 0U);
144c8c82eb3SIgor Russkikh 	hw_atl_tx_tx_reg_res_dis_set(self, 0U);
145c8c82eb3SIgor Russkikh 	aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL,
146c8c82eb3SIgor Russkikh 			    BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT),
147c8c82eb3SIgor Russkikh 			    HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0);
148c8c82eb3SIgor Russkikh 	gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
149c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000);
150c8c82eb3SIgor Russkikh 
151c8c82eb3SIgor Russkikh 	for (k = 0; k < 1000; k++) {
152c8c82eb3SIgor Russkikh 		u32 fw_state = aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION);
153c8c82eb3SIgor Russkikh 
154c8c82eb3SIgor Russkikh 		if (fw_state)
155c8c82eb3SIgor Russkikh 			break;
156c8c82eb3SIgor Russkikh 		AQ_HW_SLEEP(10);
157c8c82eb3SIgor Russkikh 	}
158c8c82eb3SIgor Russkikh 	if (k == 1000) {
159c8c82eb3SIgor Russkikh 		aq_pr_err("FW kickstart failed\n");
160c8c82eb3SIgor Russkikh 		return -EIO;
161c8c82eb3SIgor Russkikh 	}
162d0f0fb25SIgor Russkikh 	/* Old FW requires fixed delay after init */
163d0f0fb25SIgor Russkikh 	AQ_HW_SLEEP(15);
164c8c82eb3SIgor Russkikh 
165c8c82eb3SIgor Russkikh 	return 0;
166c8c82eb3SIgor Russkikh }
167c8c82eb3SIgor Russkikh 
168c8c82eb3SIgor Russkikh static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self)
169c8c82eb3SIgor Russkikh {
1701bf9a752SIgor Russkikh 	u32 gsr, val, rbl_status;
171c8c82eb3SIgor Russkikh 	int k;
172c8c82eb3SIgor Russkikh 
173c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x40e1);
174c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x3a0, 0x1);
175c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x32a8, 0x0);
176c8c82eb3SIgor Russkikh 
177c8c82eb3SIgor Russkikh 	/* Alter RBL status */
178c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x388, 0xDEAD);
179c8c82eb3SIgor Russkikh 
1801bf9a752SIgor Russkikh 	/* Cleanup SPI */
1811bf9a752SIgor Russkikh 	val = aq_hw_read_reg(self, 0x53C);
1821bf9a752SIgor Russkikh 	aq_hw_write_reg(self, 0x53C, val | 0x10);
1831bf9a752SIgor Russkikh 
184c8c82eb3SIgor Russkikh 	/* Global software reset*/
185c8c82eb3SIgor Russkikh 	hw_atl_rx_rx_reg_res_dis_set(self, 0U);
186c8c82eb3SIgor Russkikh 	hw_atl_tx_tx_reg_res_dis_set(self, 0U);
187c8c82eb3SIgor Russkikh 	aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL,
188c8c82eb3SIgor Russkikh 			    BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT),
189c8c82eb3SIgor Russkikh 			    HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0);
190c8c82eb3SIgor Russkikh 	gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
191c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR,
192c8c82eb3SIgor Russkikh 			(gsr & 0xFFFFBFFF) | 0x8000);
193c8c82eb3SIgor Russkikh 
194c8c82eb3SIgor Russkikh 	if (FORCE_FLASHLESS)
195c8c82eb3SIgor Russkikh 		aq_hw_write_reg(self, 0x534, 0x0);
196c8c82eb3SIgor Russkikh 
197c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x40e0);
198c8c82eb3SIgor Russkikh 
199c8c82eb3SIgor Russkikh 	/* Wait for RBL boot */
200c8c82eb3SIgor Russkikh 	for (k = 0; k < 1000; k++) {
201c8c82eb3SIgor Russkikh 		rbl_status = aq_hw_read_reg(self, 0x388) & 0xFFFF;
202c8c82eb3SIgor Russkikh 		if (rbl_status && rbl_status != 0xDEAD)
203c8c82eb3SIgor Russkikh 			break;
204c8c82eb3SIgor Russkikh 		AQ_HW_SLEEP(10);
205c8c82eb3SIgor Russkikh 	}
206c8c82eb3SIgor Russkikh 	if (!rbl_status || rbl_status == 0xDEAD) {
207c8c82eb3SIgor Russkikh 		aq_pr_err("RBL Restart failed");
208c8c82eb3SIgor Russkikh 		return -EIO;
209c8c82eb3SIgor Russkikh 	}
210c8c82eb3SIgor Russkikh 
211c8c82eb3SIgor Russkikh 	/* Restore NVR */
212c8c82eb3SIgor Russkikh 	if (FORCE_FLASHLESS)
213c8c82eb3SIgor Russkikh 		aq_hw_write_reg(self, 0x534, 0xA0);
214c8c82eb3SIgor Russkikh 
215c8c82eb3SIgor Russkikh 	if (rbl_status == 0xF1A7) {
216c8c82eb3SIgor Russkikh 		aq_pr_err("No FW detected. Dynamic FW load not implemented\n");
217e35df218SMark Starovoytov 		return -EOPNOTSUPP;
218c8c82eb3SIgor Russkikh 	}
219c8c82eb3SIgor Russkikh 
220c8c82eb3SIgor Russkikh 	for (k = 0; k < 1000; k++) {
221c8c82eb3SIgor Russkikh 		u32 fw_state = aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION);
222c8c82eb3SIgor Russkikh 
223c8c82eb3SIgor Russkikh 		if (fw_state)
224c8c82eb3SIgor Russkikh 			break;
225c8c82eb3SIgor Russkikh 		AQ_HW_SLEEP(10);
226c8c82eb3SIgor Russkikh 	}
227c8c82eb3SIgor Russkikh 	if (k == 1000) {
228c8c82eb3SIgor Russkikh 		aq_pr_err("FW kickstart failed\n");
229c8c82eb3SIgor Russkikh 		return -EIO;
230c8c82eb3SIgor Russkikh 	}
231d0f0fb25SIgor Russkikh 	/* Old FW requires fixed delay after init */
232d0f0fb25SIgor Russkikh 	AQ_HW_SLEEP(15);
233c8c82eb3SIgor Russkikh 
234c8c82eb3SIgor Russkikh 	return 0;
235c8c82eb3SIgor Russkikh }
236c8c82eb3SIgor Russkikh 
237c8c82eb3SIgor Russkikh int hw_atl_utils_soft_reset(struct aq_hw_s *self)
238c8c82eb3SIgor Russkikh {
239c8c82eb3SIgor Russkikh 	u32 boot_exit_code = 0;
2406a7f2277SNikita Danilov 	u32 val;
2417b0c342fSNikita Danilov 	int k;
242c8c82eb3SIgor Russkikh 
243c8c82eb3SIgor Russkikh 	for (k = 0; k < 1000; ++k) {
244c8c82eb3SIgor Russkikh 		u32 flb_status = aq_hw_read_reg(self,
245c8c82eb3SIgor Russkikh 						HW_ATL_MPI_DAISY_CHAIN_STATUS);
246c8c82eb3SIgor Russkikh 		boot_exit_code = aq_hw_read_reg(self,
247c8c82eb3SIgor Russkikh 						HW_ATL_MPI_BOOT_EXIT_CODE);
248c8c82eb3SIgor Russkikh 		if (flb_status != 0x06000000 || boot_exit_code != 0)
249c8c82eb3SIgor Russkikh 			break;
250c8c82eb3SIgor Russkikh 	}
251c8c82eb3SIgor Russkikh 
252c8c82eb3SIgor Russkikh 	if (k == 1000) {
253c8c82eb3SIgor Russkikh 		aq_pr_err("Neither RBL nor FLB firmware started\n");
254c8c82eb3SIgor Russkikh 		return -EOPNOTSUPP;
255c8c82eb3SIgor Russkikh 	}
256c8c82eb3SIgor Russkikh 
257c8c82eb3SIgor Russkikh 	self->rbl_enabled = (boot_exit_code != 0);
258c8c82eb3SIgor Russkikh 
259cce96d18SIgor Russkikh 	/* FW 1.x may bootup in an invalid POWER state (WOL feature).
260cce96d18SIgor Russkikh 	 * We should work around this by forcing its state back to DEINIT
261cce96d18SIgor Russkikh 	 */
262b567edbfSMark Starovoytov 	if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X,
263cce96d18SIgor Russkikh 				   aq_hw_read_reg(self,
264cce96d18SIgor Russkikh 						  HW_ATL_MPI_FW_VERSION))) {
265cce96d18SIgor Russkikh 		int err = 0;
266cce96d18SIgor Russkikh 
267cce96d18SIgor Russkikh 		hw_atl_utils_mpi_set_state(self, MPI_DEINIT);
2686a7f2277SNikita Danilov 		err = readx_poll_timeout_atomic(hw_atl_utils_mpi_get_state,
2696a7f2277SNikita Danilov 						self, val,
2706a7f2277SNikita Danilov 						(val & HW_ATL_MPI_STATE_MSK) ==
2716a7f2277SNikita Danilov 						 MPI_DEINIT,
2726a7f2277SNikita Danilov 						10, 10000U);
2734e3c7c00SYueHaibing 		if (err)
2744e3c7c00SYueHaibing 			return err;
275cce96d18SIgor Russkikh 	}
276cce96d18SIgor Russkikh 
277c8c82eb3SIgor Russkikh 	if (self->rbl_enabled)
278c8c82eb3SIgor Russkikh 		return hw_atl_utils_soft_reset_rbl(self);
279c8c82eb3SIgor Russkikh 	else
280c8c82eb3SIgor Russkikh 		return hw_atl_utils_soft_reset_flb(self);
281c8c82eb3SIgor Russkikh }
282c8c82eb3SIgor Russkikh 
283a57d3929SIgor Russkikh int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
28498c4c201SDavid VomLehn 				  u32 *p, u32 cnt)
28598c4c201SDavid VomLehn {
28698c4c201SDavid VomLehn 	int err = 0;
2876a7f2277SNikita Danilov 	u32 val;
28898c4c201SDavid VomLehn 
2896a7f2277SNikita Danilov 	err = readx_poll_timeout_atomic(hw_atl_sem_ram_get,
2906a7f2277SNikita Danilov 					self, val, val == 1U,
29198c4c201SDavid VomLehn 					1U, 10000U);
29298c4c201SDavid VomLehn 
29398c4c201SDavid VomLehn 	if (err < 0) {
29498c4c201SDavid VomLehn 		bool is_locked;
29598c4c201SDavid VomLehn 
2968e1c072fSIgor Russkikh 		hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
2970b926d46SNikita Danilov 		is_locked = hw_atl_sem_ram_get(self);
29898c4c201SDavid VomLehn 		if (!is_locked) {
29998c4c201SDavid VomLehn 			err = -ETIME;
30098c4c201SDavid VomLehn 			goto err_exit;
30198c4c201SDavid VomLehn 		}
30298c4c201SDavid VomLehn 	}
30398c4c201SDavid VomLehn 
30447203b34SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_MIF_ADDR, a);
30598c4c201SDavid VomLehn 
30647203b34SIgor Russkikh 	for (++cnt; --cnt && !err;) {
30747203b34SIgor Russkikh 		aq_hw_write_reg(self, HW_ATL_MIF_CMD, 0x00008000U);
30898c4c201SDavid VomLehn 
309d1ad88feSMark Starovoytov 		if (ATL_HW_IS_CHIP_FEATURE(self, REVISION_B1))
3106a7f2277SNikita Danilov 			err = readx_poll_timeout_atomic(hw_atl_utils_mif_addr_get,
3116a7f2277SNikita Danilov 							self, val, val != a,
3126a7f2277SNikita Danilov 							1U, 1000U);
31347203b34SIgor Russkikh 		else
3146a7f2277SNikita Danilov 			err = readx_poll_timeout_atomic(hw_atl_utils_mif_cmd_get,
3156a7f2277SNikita Danilov 							self, val,
3166a7f2277SNikita Danilov 							!(val & 0x100),
3176a7f2277SNikita Danilov 							1U, 1000U);
31898c4c201SDavid VomLehn 
31947203b34SIgor Russkikh 		*(p++) = aq_hw_read_reg(self, HW_ATL_MIF_VAL);
32047203b34SIgor Russkikh 		a += 4;
32198c4c201SDavid VomLehn 	}
32298c4c201SDavid VomLehn 
3238e1c072fSIgor Russkikh 	hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
32498c4c201SDavid VomLehn 
32598c4c201SDavid VomLehn err_exit:
32698c4c201SDavid VomLehn 	return err;
32798c4c201SDavid VomLehn }
32898c4c201SDavid VomLehn 
329dc12f75aSNikita Danilov static int hw_atl_utils_write_b1_mbox(struct aq_hw_s *self, u32 addr,
330dc12f75aSNikita Danilov 				      u32 *p, u32 cnt, enum mcp_area area)
33198c4c201SDavid VomLehn {
332dc12f75aSNikita Danilov 	u32 data_offset = 0;
333dc12f75aSNikita Danilov 	u32 offset = addr;
33498c4c201SDavid VomLehn 	int err = 0;
335dc12f75aSNikita Danilov 	u32 val;
33698c4c201SDavid VomLehn 
337dc12f75aSNikita Danilov 	switch (area) {
338dc12f75aSNikita Danilov 	case MCP_AREA_CONFIG:
339dc12f75aSNikita Danilov 		offset -= self->rpc_addr;
340dc12f75aSNikita Danilov 		break;
341930b9a05SNikita Danilov 
342dc12f75aSNikita Danilov 	case MCP_AREA_SETTINGS:
343dc12f75aSNikita Danilov 		offset -= self->settings_addr;
344dc12f75aSNikita Danilov 		break;
345dc12f75aSNikita Danilov 	}
34698c4c201SDavid VomLehn 
347dc12f75aSNikita Danilov 	offset = offset / sizeof(u32);
348dc12f75aSNikita Danilov 
349dc12f75aSNikita Danilov 	for (; data_offset < cnt; ++data_offset, ++offset) {
350dc12f75aSNikita Danilov 		aq_hw_write_reg(self, 0x328, p[data_offset]);
3513ee5c887SYana Esina 		aq_hw_write_reg(self, 0x32C,
352dc12f75aSNikita Danilov 				(area | (0xFFFF & (offset * 4))));
3533ee5c887SYana Esina 		hw_atl_mcp_up_force_intr_set(self, 1);
3543ee5c887SYana Esina 		/* 1000 times by 10us = 10ms */
3556a7f2277SNikita Danilov 		err = readx_poll_timeout_atomic(hw_atl_scrpad12_get,
3566a7f2277SNikita Danilov 						self, val,
357930b9a05SNikita Danilov 						(val & 0xF0000000) !=
358dc12f75aSNikita Danilov 						area,
3596a7f2277SNikita Danilov 						10U, 10000U);
36098c4c201SDavid VomLehn 
361dc12f75aSNikita Danilov 		if (err < 0)
362dc12f75aSNikita Danilov 			break;
363dc12f75aSNikita Danilov 	}
364dc12f75aSNikita Danilov 
365dc12f75aSNikita Danilov 	return err;
366dc12f75aSNikita Danilov }
367dc12f75aSNikita Danilov 
368dc12f75aSNikita Danilov static int hw_atl_utils_write_b0_mbox(struct aq_hw_s *self, u32 addr,
369dc12f75aSNikita Danilov 				      u32 *p, u32 cnt)
370dc12f75aSNikita Danilov {
371dc12f75aSNikita Danilov 	u32 offset = 0;
372dc12f75aSNikita Danilov 	int err = 0;
373dc12f75aSNikita Danilov 	u32 val;
374dc12f75aSNikita Danilov 
375dc12f75aSNikita Danilov 	aq_hw_write_reg(self, 0x208, addr);
37698c4c201SDavid VomLehn 
3773ee5c887SYana Esina 	for (; offset < cnt; ++offset) {
3783ee5c887SYana Esina 		aq_hw_write_reg(self, 0x20C, p[offset]);
3793ee5c887SYana Esina 		aq_hw_write_reg(self, 0x200, 0xC000);
38098c4c201SDavid VomLehn 
3816a7f2277SNikita Danilov 		err = readx_poll_timeout_atomic(hw_atl_utils_mif_cmd_get,
3826a7f2277SNikita Danilov 						self, val,
383dc12f75aSNikita Danilov 						(val & 0x100) == 0U,
384dc12f75aSNikita Danilov 						10U, 10000U);
385dc12f75aSNikita Danilov 
386dc12f75aSNikita Danilov 		if (err < 0)
387dc12f75aSNikita Danilov 			break;
38898c4c201SDavid VomLehn 	}
389dc12f75aSNikita Danilov 
390dc12f75aSNikita Danilov 	return err;
39198c4c201SDavid VomLehn }
39298c4c201SDavid VomLehn 
393dc12f75aSNikita Danilov static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 addr, u32 *p,
394dc12f75aSNikita Danilov 					 u32 cnt, enum mcp_area area)
395dc12f75aSNikita Danilov {
396dc12f75aSNikita Danilov 	int err = 0;
397dc12f75aSNikita Danilov 	u32 val;
398dc12f75aSNikita Danilov 
399dc12f75aSNikita Danilov 	err = readx_poll_timeout_atomic(hw_atl_sem_ram_get, self,
400dc12f75aSNikita Danilov 					val, val == 1U,
401dc12f75aSNikita Danilov 					10U, 100000U);
402dc12f75aSNikita Danilov 	if (err < 0)
403dc12f75aSNikita Danilov 		goto err_exit;
404dc12f75aSNikita Danilov 
405d1ad88feSMark Starovoytov 	if (ATL_HW_IS_CHIP_FEATURE(self, REVISION_B1))
406dc12f75aSNikita Danilov 		err = hw_atl_utils_write_b1_mbox(self, addr, p, cnt, area);
407dc12f75aSNikita Danilov 	else
408dc12f75aSNikita Danilov 		err = hw_atl_utils_write_b0_mbox(self, addr, p, cnt);
409dc12f75aSNikita Danilov 
4108e1c072fSIgor Russkikh 	hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
41198c4c201SDavid VomLehn 
412dc12f75aSNikita Danilov 	if (err < 0)
413dc12f75aSNikita Danilov 		goto err_exit;
414dc12f75aSNikita Danilov 
415dc12f75aSNikita Danilov 	err = aq_hw_err_from_flags(self);
416dc12f75aSNikita Danilov 
41798c4c201SDavid VomLehn err_exit:
41898c4c201SDavid VomLehn 	return err;
41998c4c201SDavid VomLehn }
42098c4c201SDavid VomLehn 
421dc12f75aSNikita Danilov int hw_atl_write_fwcfg_dwords(struct aq_hw_s *self, u32 *p, u32 cnt)
422dc12f75aSNikita Danilov {
423dc12f75aSNikita Danilov 	return hw_atl_utils_fw_upload_dwords(self, self->rpc_addr, p,
424dc12f75aSNikita Danilov 					     cnt, MCP_AREA_CONFIG);
425dc12f75aSNikita Danilov }
426dc12f75aSNikita Danilov 
427dc12f75aSNikita Danilov int hw_atl_write_fwsettings_dwords(struct aq_hw_s *self, u32 offset, u32 *p,
428dc12f75aSNikita Danilov 				   u32 cnt)
429dc12f75aSNikita Danilov {
430dc12f75aSNikita Danilov 	return hw_atl_utils_fw_upload_dwords(self, self->settings_addr + offset,
431dc12f75aSNikita Danilov 					     p, cnt, MCP_AREA_SETTINGS);
432dc12f75aSNikita Danilov }
433dc12f75aSNikita Danilov 
434b567edbfSMark Starovoytov bool hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual)
43598c4c201SDavid VomLehn {
43698c4c201SDavid VomLehn 	const u32 dw_major_mask = 0xff000000U;
43798c4c201SDavid VomLehn 	const u32 dw_minor_mask = 0x00ffffffU;
438b567edbfSMark Starovoytov 	bool ver_match;
43998c4c201SDavid VomLehn 
440b567edbfSMark Starovoytov 	ver_match = (dw_major_mask & (ver_expected ^ ver_actual)) ? false : true;
441b567edbfSMark Starovoytov 	if (!ver_match)
44298c4c201SDavid VomLehn 		goto err_exit;
443b567edbfSMark Starovoytov 	ver_match = ((dw_minor_mask & ver_expected) > (dw_minor_mask & ver_actual)) ?
444b567edbfSMark Starovoytov 		false : true;
4457b0c342fSNikita Danilov 
44698c4c201SDavid VomLehn err_exit:
447b567edbfSMark Starovoytov 	return ver_match;
44898c4c201SDavid VomLehn }
44998c4c201SDavid VomLehn 
45098c4c201SDavid VomLehn static int hw_atl_utils_init_ucp(struct aq_hw_s *self,
4514cbc9f92SIgor Russkikh 				 const struct aq_hw_caps_s *aq_hw_caps)
45298c4c201SDavid VomLehn {
45398c4c201SDavid VomLehn 	int err = 0;
45498c4c201SDavid VomLehn 
45598c4c201SDavid VomLehn 	if (!aq_hw_read_reg(self, 0x370U)) {
45698c4c201SDavid VomLehn 		unsigned int rnd = 0U;
45798c4c201SDavid VomLehn 		unsigned int ucp_0x370 = 0U;
45898c4c201SDavid VomLehn 
45998c4c201SDavid VomLehn 		get_random_bytes(&rnd, sizeof(unsigned int));
46098c4c201SDavid VomLehn 
46198c4c201SDavid VomLehn 		ucp_0x370 = 0x02020202U | (0xFEFEFEFEU & rnd);
46298c4c201SDavid VomLehn 		aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
46398c4c201SDavid VomLehn 	}
46498c4c201SDavid VomLehn 
4658e1c072fSIgor Russkikh 	hw_atl_reg_glb_cpu_scratch_scp_set(self, 0x00000000U, 25U);
46698c4c201SDavid VomLehn 
46798c4c201SDavid VomLehn 	/* check 10 times by 1ms */
4686a7f2277SNikita Danilov 	err = readx_poll_timeout_atomic(hw_atl_scrpad25_get,
4696a7f2277SNikita Danilov 					self, self->mbox_addr,
4706a7f2277SNikita Danilov 					self->mbox_addr != 0U,
4716a7f2277SNikita Danilov 					1000U, 10000U);
472e7b5f97eSIgor Russkikh 	err = readx_poll_timeout_atomic(aq_fw1x_rpc_get, self,
473e7b5f97eSIgor Russkikh 					self->rpc_addr,
474e7b5f97eSIgor Russkikh 					self->rpc_addr != 0U,
475e7b5f97eSIgor Russkikh 					1000U, 100000U);
47698c4c201SDavid VomLehn 
47798c4c201SDavid VomLehn 	return err;
47898c4c201SDavid VomLehn }
47998c4c201SDavid VomLehn 
48098c4c201SDavid VomLehn struct aq_hw_atl_utils_fw_rpc_tid_s {
48198c4c201SDavid VomLehn 	union {
48298c4c201SDavid VomLehn 		u32 val;
48398c4c201SDavid VomLehn 		struct {
48498c4c201SDavid VomLehn 			u16 tid;
48598c4c201SDavid VomLehn 			u16 len;
48698c4c201SDavid VomLehn 		};
48798c4c201SDavid VomLehn 	};
48898c4c201SDavid VomLehn };
48998c4c201SDavid VomLehn 
49098c4c201SDavid VomLehn #define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL)
49198c4c201SDavid VomLehn 
4923ee5c887SYana Esina int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size)
49398c4c201SDavid VomLehn {
49498c4c201SDavid VomLehn 	struct aq_hw_atl_utils_fw_rpc_tid_s sw;
4957b0c342fSNikita Danilov 	int err = 0;
49698c4c201SDavid VomLehn 
497d1ad88feSMark Starovoytov 	if (!ATL_HW_IS_CHIP_FEATURE(self, MIPS)) {
49898c4c201SDavid VomLehn 		err = -1;
49998c4c201SDavid VomLehn 		goto err_exit;
50098c4c201SDavid VomLehn 	}
501dc12f75aSNikita Danilov 	err = hw_atl_write_fwcfg_dwords(self, (u32 *)(void *)&self->rpc,
50298c4c201SDavid VomLehn 					(rpc_size + sizeof(u32) -
50398c4c201SDavid VomLehn 					 sizeof(u8)) / sizeof(u32));
50498c4c201SDavid VomLehn 	if (err < 0)
50598c4c201SDavid VomLehn 		goto err_exit;
50698c4c201SDavid VomLehn 
5071a713f87SIgor Russkikh 	sw.tid = 0xFFFFU & (++self->rpc_tid);
50898c4c201SDavid VomLehn 	sw.len = (u16)rpc_size;
50998c4c201SDavid VomLehn 	aq_hw_write_reg(self, HW_ATL_RPC_CONTROL_ADR, sw.val);
51098c4c201SDavid VomLehn 
51198c4c201SDavid VomLehn err_exit:
51298c4c201SDavid VomLehn 	return err;
51398c4c201SDavid VomLehn }
51498c4c201SDavid VomLehn 
5153ee5c887SYana Esina int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
5168f60f762SNikita Danilov 			     struct hw_atl_utils_fw_rpc **rpc)
51798c4c201SDavid VomLehn {
51898c4c201SDavid VomLehn 	struct aq_hw_atl_utils_fw_rpc_tid_s sw;
51998c4c201SDavid VomLehn 	struct aq_hw_atl_utils_fw_rpc_tid_s fw;
5207b0c342fSNikita Danilov 	int err = 0;
52198c4c201SDavid VomLehn 
52298c4c201SDavid VomLehn 	do {
52398c4c201SDavid VomLehn 		sw.val = aq_hw_read_reg(self, HW_ATL_RPC_CONTROL_ADR);
52498c4c201SDavid VomLehn 
5251a713f87SIgor Russkikh 		self->rpc_tid = sw.tid;
52698c4c201SDavid VomLehn 
5276a7f2277SNikita Danilov 		err = readx_poll_timeout_atomic(hw_atl_utils_rpc_state_get,
5286a7f2277SNikita Danilov 						self, fw.val,
5296a7f2277SNikita Danilov 						sw.tid == fw.tid,
5306a7f2277SNikita Danilov 						1000U, 100000U);
531e7b5f97eSIgor Russkikh 		if (err < 0)
532e7b5f97eSIgor Russkikh 			goto err_exit;
533e7b5f97eSIgor Russkikh 
534e7b5f97eSIgor Russkikh 		err = aq_hw_err_from_flags(self);
535e7b5f97eSIgor Russkikh 		if (err < 0)
536e7b5f97eSIgor Russkikh 			goto err_exit;
53798c4c201SDavid VomLehn 
53898c4c201SDavid VomLehn 		if (fw.len == 0xFFFFU) {
53998c4c201SDavid VomLehn 			err = hw_atl_utils_fw_rpc_call(self, sw.len);
54098c4c201SDavid VomLehn 			if (err < 0)
54198c4c201SDavid VomLehn 				goto err_exit;
54298c4c201SDavid VomLehn 		}
54398c4c201SDavid VomLehn 	} while (sw.tid != fw.tid || 0xFFFFU == fw.len);
54498c4c201SDavid VomLehn 
54598c4c201SDavid VomLehn 	if (rpc) {
54698c4c201SDavid VomLehn 		if (fw.len) {
54798c4c201SDavid VomLehn 			err =
54898c4c201SDavid VomLehn 			hw_atl_utils_fw_downld_dwords(self,
5491a713f87SIgor Russkikh 						      self->rpc_addr,
55098c4c201SDavid VomLehn 						      (u32 *)(void *)
5511a713f87SIgor Russkikh 						      &self->rpc,
55298c4c201SDavid VomLehn 						      (fw.len + sizeof(u32) -
55398c4c201SDavid VomLehn 						       sizeof(u8)) /
55498c4c201SDavid VomLehn 						      sizeof(u32));
55598c4c201SDavid VomLehn 			if (err < 0)
55698c4c201SDavid VomLehn 				goto err_exit;
55798c4c201SDavid VomLehn 		}
55898c4c201SDavid VomLehn 
5591a713f87SIgor Russkikh 		*rpc = &self->rpc;
56098c4c201SDavid VomLehn 	}
56198c4c201SDavid VomLehn 
56298c4c201SDavid VomLehn err_exit:
56398c4c201SDavid VomLehn 	return err;
56498c4c201SDavid VomLehn }
56598c4c201SDavid VomLehn 
5661a713f87SIgor Russkikh static int hw_atl_utils_mpi_create(struct aq_hw_s *self)
56798c4c201SDavid VomLehn {
56898c4c201SDavid VomLehn 	int err = 0;
56998c4c201SDavid VomLehn 
5701a713f87SIgor Russkikh 	err = hw_atl_utils_init_ucp(self, self->aq_nic_cfg->aq_hw_caps);
57198c4c201SDavid VomLehn 	if (err < 0)
57298c4c201SDavid VomLehn 		goto err_exit;
57398c4c201SDavid VomLehn 
57498c4c201SDavid VomLehn 	err = hw_atl_utils_fw_rpc_init(self);
57598c4c201SDavid VomLehn 	if (err < 0)
57698c4c201SDavid VomLehn 		goto err_exit;
57798c4c201SDavid VomLehn 
57898c4c201SDavid VomLehn err_exit:
57998c4c201SDavid VomLehn 	return err;
58098c4c201SDavid VomLehn }
58198c4c201SDavid VomLehn 
58265e665e6SIgor Russkikh int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self,
5838f60f762SNikita Danilov 			       struct hw_atl_utils_mbox_header *pmbox)
58465e665e6SIgor Russkikh {
58565e665e6SIgor Russkikh 	return hw_atl_utils_fw_downld_dwords(self,
5861a713f87SIgor Russkikh 					     self->mbox_addr,
58765e665e6SIgor Russkikh 					     (u32 *)(void *)pmbox,
58865e665e6SIgor Russkikh 					     sizeof(*pmbox) / sizeof(u32));
58965e665e6SIgor Russkikh }
59065e665e6SIgor Russkikh 
59198c4c201SDavid VomLehn void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
5928f60f762SNikita Danilov 				 struct hw_atl_utils_mbox *pmbox)
59398c4c201SDavid VomLehn {
59498c4c201SDavid VomLehn 	int err = 0;
59598c4c201SDavid VomLehn 
59698c4c201SDavid VomLehn 	err = hw_atl_utils_fw_downld_dwords(self,
5971a713f87SIgor Russkikh 					    self->mbox_addr,
59898c4c201SDavid VomLehn 					    (u32 *)(void *)pmbox,
59998c4c201SDavid VomLehn 					    sizeof(*pmbox) / sizeof(u32));
60098c4c201SDavid VomLehn 	if (err < 0)
60198c4c201SDavid VomLehn 		goto err_exit;
60298c4c201SDavid VomLehn 
603d1ad88feSMark Starovoytov 	if (ATL_HW_IS_CHIP_FEATURE(self, REVISION_A0)) {
60498c4c201SDavid VomLehn 		unsigned int mtu = self->aq_nic_cfg ?
60598c4c201SDavid VomLehn 					self->aq_nic_cfg->mtu : 1514U;
60698c4c201SDavid VomLehn 		pmbox->stats.ubrc = pmbox->stats.uprc * mtu;
60798c4c201SDavid VomLehn 		pmbox->stats.ubtc = pmbox->stats.uptc * mtu;
6081a713f87SIgor Russkikh 		pmbox->stats.dpc = atomic_read(&self->dpc);
60998c4c201SDavid VomLehn 	} else {
610ce4cdbe4SDmitry Bogdanov 		pmbox->stats.dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self);
61198c4c201SDavid VomLehn 	}
61298c4c201SDavid VomLehn 
61398c4c201SDavid VomLehn err_exit:;
61498c4c201SDavid VomLehn }
61598c4c201SDavid VomLehn 
616dfbd0749SWei Yongjun static int hw_atl_utils_mpi_set_speed(struct aq_hw_s *self, u32 speed)
61798c4c201SDavid VomLehn {
6180c58c35fSIgor Russkikh 	u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR);
61998c4c201SDavid VomLehn 
62044e00dd8SIgor Russkikh 	val = val & ~HW_ATL_MPI_SPEED_MSK;
62144e00dd8SIgor Russkikh 	val |= speed << HW_ATL_MPI_SPEED_SHIFT;
6220c58c35fSIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val);
62398c4c201SDavid VomLehn 
62498c4c201SDavid VomLehn 	return 0;
62598c4c201SDavid VomLehn }
62698c4c201SDavid VomLehn 
627dfbd0749SWei Yongjun static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
62844e00dd8SIgor Russkikh 				      enum hal_atl_utils_fw_state_e state)
62998c4c201SDavid VomLehn {
63044e00dd8SIgor Russkikh 	u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR);
6317b0c342fSNikita Danilov 	struct hw_atl_utils_mbox_header mbox;
6327b0c342fSNikita Danilov 	u32 transaction_id = 0;
6337b0c342fSNikita Danilov 	int err = 0;
63498c4c201SDavid VomLehn 
63598c4c201SDavid VomLehn 	if (state == MPI_RESET) {
63665e665e6SIgor Russkikh 		hw_atl_utils_mpi_read_mbox(self, &mbox);
63798c4c201SDavid VomLehn 
63865e665e6SIgor Russkikh 		transaction_id = mbox.transaction_id;
63998c4c201SDavid VomLehn 
6406a7f2277SNikita Danilov 		err = readx_poll_timeout_atomic(hw_atl_utils_get_mpi_mbox_tid,
6416a7f2277SNikita Danilov 						self, mbox.transaction_id,
6426a7f2277SNikita Danilov 						transaction_id !=
6436a7f2277SNikita Danilov 						mbox.transaction_id,
6446a7f2277SNikita Danilov 						1000U, 100000U);
64598c4c201SDavid VomLehn 		if (err < 0)
64698c4c201SDavid VomLehn 			goto err_exit;
64798c4c201SDavid VomLehn 	}
64844e00dd8SIgor Russkikh 	/* On interface DEINIT we disable DW (raise bit)
64944e00dd8SIgor Russkikh 	 * Otherwise enable DW (clear bit)
65044e00dd8SIgor Russkikh 	 */
65144e00dd8SIgor Russkikh 	if (state == MPI_DEINIT || state == MPI_POWER)
65244e00dd8SIgor Russkikh 		val |= HW_ATL_MPI_DIRTY_WAKE_MSK;
65344e00dd8SIgor Russkikh 	else
65444e00dd8SIgor Russkikh 		val &= ~HW_ATL_MPI_DIRTY_WAKE_MSK;
65598c4c201SDavid VomLehn 
65644e00dd8SIgor Russkikh 	/* Set new state bits */
65744e00dd8SIgor Russkikh 	val = val & ~HW_ATL_MPI_STATE_MSK;
65844e00dd8SIgor Russkikh 	val |= state & HW_ATL_MPI_STATE_MSK;
65998c4c201SDavid VomLehn 
6600c58c35fSIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val);
6617b0c342fSNikita Danilov 
66244e00dd8SIgor Russkikh err_exit:
66344e00dd8SIgor Russkikh 	return err;
6640c58c35fSIgor Russkikh }
6650c58c35fSIgor Russkikh 
666bd8ed441SPavel Belous int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self)
66798c4c201SDavid VomLehn {
668bd8ed441SPavel Belous 	struct aq_hw_link_status_s *link_status = &self->aq_link_status;
6697b0c342fSNikita Danilov 	u32 mpi_state;
6707b0c342fSNikita Danilov 	u32 speed;
67198c4c201SDavid VomLehn 
6727b0c342fSNikita Danilov 	mpi_state = hw_atl_utils_mpi_get_state(self);
673ac70957eSIgor Russkikh 	speed = mpi_state >> HW_ATL_MPI_SPEED_SHIFT;
6747b0c342fSNikita Danilov 
6757b0c342fSNikita Danilov 	if (!speed) {
67698c4c201SDavid VomLehn 		link_status->mbps = 0U;
67798c4c201SDavid VomLehn 	} else {
6787b0c342fSNikita Danilov 		switch (speed) {
67998c4c201SDavid VomLehn 		case HAL_ATLANTIC_RATE_10G:
68098c4c201SDavid VomLehn 			link_status->mbps = 10000U;
68198c4c201SDavid VomLehn 			break;
68298c4c201SDavid VomLehn 
68398c4c201SDavid VomLehn 		case HAL_ATLANTIC_RATE_5G:
68498c4c201SDavid VomLehn 		case HAL_ATLANTIC_RATE_5GSR:
68598c4c201SDavid VomLehn 			link_status->mbps = 5000U;
68698c4c201SDavid VomLehn 			break;
68798c4c201SDavid VomLehn 
688843e1396SMark Starovoytov 		case HAL_ATLANTIC_RATE_2G5:
68998c4c201SDavid VomLehn 			link_status->mbps = 2500U;
69098c4c201SDavid VomLehn 			break;
69198c4c201SDavid VomLehn 
69298c4c201SDavid VomLehn 		case HAL_ATLANTIC_RATE_1G:
69398c4c201SDavid VomLehn 			link_status->mbps = 1000U;
69498c4c201SDavid VomLehn 			break;
69598c4c201SDavid VomLehn 
69698c4c201SDavid VomLehn 		case HAL_ATLANTIC_RATE_100M:
69798c4c201SDavid VomLehn 			link_status->mbps = 100U;
69898c4c201SDavid VomLehn 			break;
69998c4c201SDavid VomLehn 
70098c4c201SDavid VomLehn 		default:
701a7bb1beaSIgor Russkikh 			return -EBUSY;
70298c4c201SDavid VomLehn 		}
70398c4c201SDavid VomLehn 	}
704071a0204SIgor Russkikh 	link_status->full_duplex = true;
70598c4c201SDavid VomLehn 
70698c4c201SDavid VomLehn 	return 0;
70798c4c201SDavid VomLehn }
70898c4c201SDavid VomLehn 
70998c4c201SDavid VomLehn int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self,
71098c4c201SDavid VomLehn 				   u8 *mac)
71198c4c201SDavid VomLehn {
7127b0c342fSNikita Danilov 	u32 mac_addr[2];
7137b0c342fSNikita Danilov 	u32 efuse_addr;
71498c4c201SDavid VomLehn 	int err = 0;
71598c4c201SDavid VomLehn 	u32 h = 0U;
71698c4c201SDavid VomLehn 	u32 l = 0U;
71798c4c201SDavid VomLehn 
71898c4c201SDavid VomLehn 	if (!aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) {
71998c4c201SDavid VomLehn 		unsigned int ucp_0x370 = 0;
7207b0c342fSNikita Danilov 		unsigned int rnd = 0;
72198c4c201SDavid VomLehn 
72298c4c201SDavid VomLehn 		get_random_bytes(&rnd, sizeof(unsigned int));
72398c4c201SDavid VomLehn 
72498c4c201SDavid VomLehn 		ucp_0x370 = 0x02020202 | (0xFEFEFEFE & rnd);
72598c4c201SDavid VomLehn 		aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
72698c4c201SDavid VomLehn 	}
72798c4c201SDavid VomLehn 
7287b0c342fSNikita Danilov 	efuse_addr = aq_hw_read_reg(self, 0x00000374U);
7297b0c342fSNikita Danilov 
7307b0c342fSNikita Danilov 	err = hw_atl_utils_fw_downld_dwords(self, efuse_addr + (40U * 4U),
7317b0c342fSNikita Danilov 					    mac_addr, ARRAY_SIZE(mac_addr));
73298c4c201SDavid VomLehn 	if (err < 0) {
73398c4c201SDavid VomLehn 		mac_addr[0] = 0U;
73498c4c201SDavid VomLehn 		mac_addr[1] = 0U;
73598c4c201SDavid VomLehn 		err = 0;
73698c4c201SDavid VomLehn 	} else {
73798c4c201SDavid VomLehn 		mac_addr[0] = __swab32(mac_addr[0]);
73898c4c201SDavid VomLehn 		mac_addr[1] = __swab32(mac_addr[1]);
73998c4c201SDavid VomLehn 	}
74098c4c201SDavid VomLehn 
74198c4c201SDavid VomLehn 	ether_addr_copy(mac, (u8 *)mac_addr);
74298c4c201SDavid VomLehn 
74398c4c201SDavid VomLehn 	if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) {
74498c4c201SDavid VomLehn 		/* chip revision */
745e9157848SNikita Danilov 		l = 0xE3000000U |
746e9157848SNikita Danilov 		    (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) |
747e9157848SNikita Danilov 		    (0x00 << 16);
74898c4c201SDavid VomLehn 		h = 0x8001300EU;
74998c4c201SDavid VomLehn 
75098c4c201SDavid VomLehn 		mac[5] = (u8)(0xFFU & l);
75198c4c201SDavid VomLehn 		l >>= 8;
75298c4c201SDavid VomLehn 		mac[4] = (u8)(0xFFU & l);
75398c4c201SDavid VomLehn 		l >>= 8;
75498c4c201SDavid VomLehn 		mac[3] = (u8)(0xFFU & l);
75598c4c201SDavid VomLehn 		l >>= 8;
75698c4c201SDavid VomLehn 		mac[2] = (u8)(0xFFU & l);
75798c4c201SDavid VomLehn 		mac[1] = (u8)(0xFFU & h);
75898c4c201SDavid VomLehn 		h >>= 8;
75998c4c201SDavid VomLehn 		mac[0] = (u8)(0xFFU & h);
76098c4c201SDavid VomLehn 	}
76198c4c201SDavid VomLehn 
76298c4c201SDavid VomLehn 	return err;
76398c4c201SDavid VomLehn }
76498c4c201SDavid VomLehn 
76598c4c201SDavid VomLehn unsigned int hw_atl_utils_mbps_2_speed_index(unsigned int mbps)
76698c4c201SDavid VomLehn {
76798c4c201SDavid VomLehn 	unsigned int ret = 0U;
76898c4c201SDavid VomLehn 
76998c4c201SDavid VomLehn 	switch (mbps) {
77098c4c201SDavid VomLehn 	case 100U:
77198c4c201SDavid VomLehn 		ret = 5U;
77298c4c201SDavid VomLehn 		break;
77398c4c201SDavid VomLehn 
77498c4c201SDavid VomLehn 	case 1000U:
77598c4c201SDavid VomLehn 		ret = 4U;
77698c4c201SDavid VomLehn 		break;
77798c4c201SDavid VomLehn 
77898c4c201SDavid VomLehn 	case 2500U:
77998c4c201SDavid VomLehn 		ret = 3U;
78098c4c201SDavid VomLehn 		break;
78198c4c201SDavid VomLehn 
78298c4c201SDavid VomLehn 	case 5000U:
78398c4c201SDavid VomLehn 		ret = 1U;
78498c4c201SDavid VomLehn 		break;
78598c4c201SDavid VomLehn 
78698c4c201SDavid VomLehn 	case 10000U:
78798c4c201SDavid VomLehn 		ret = 0U;
78898c4c201SDavid VomLehn 		break;
78998c4c201SDavid VomLehn 
79098c4c201SDavid VomLehn 	default:
79198c4c201SDavid VomLehn 		break;
79298c4c201SDavid VomLehn 	}
7937b0c342fSNikita Danilov 
79498c4c201SDavid VomLehn 	return ret;
79598c4c201SDavid VomLehn }
79698c4c201SDavid VomLehn 
79798c4c201SDavid VomLehn void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p)
79898c4c201SDavid VomLehn {
7998e1c072fSIgor Russkikh 	u32 val = hw_atl_reg_glb_mif_id_get(self);
80098c4c201SDavid VomLehn 	u32 mif_rev = val & 0xFFU;
8017b0c342fSNikita Danilov 	u32 chip_features = 0U;
80298c4c201SDavid VomLehn 
803d1ad88feSMark Starovoytov 	chip_features |= ATL_HW_CHIP_ATLANTIC;
804d1ad88feSMark Starovoytov 
80547203b34SIgor Russkikh 	if ((0xFU & mif_rev) == 1U) {
806d1ad88feSMark Starovoytov 		chip_features |= ATL_HW_CHIP_REVISION_A0 |
807d1ad88feSMark Starovoytov 			ATL_HW_CHIP_MPI_AQ |
808d1ad88feSMark Starovoytov 			ATL_HW_CHIP_MIPS;
80947203b34SIgor Russkikh 	} else if ((0xFU & mif_rev) == 2U) {
810d1ad88feSMark Starovoytov 		chip_features |= ATL_HW_CHIP_REVISION_B0 |
811d1ad88feSMark Starovoytov 			ATL_HW_CHIP_MPI_AQ |
812d1ad88feSMark Starovoytov 			ATL_HW_CHIP_MIPS |
813d1ad88feSMark Starovoytov 			ATL_HW_CHIP_TPO2 |
814d1ad88feSMark Starovoytov 			ATL_HW_CHIP_RPF2;
81547203b34SIgor Russkikh 	} else if ((0xFU & mif_rev) == 0xAU) {
816d1ad88feSMark Starovoytov 		chip_features |= ATL_HW_CHIP_REVISION_B1 |
817d1ad88feSMark Starovoytov 			ATL_HW_CHIP_MPI_AQ |
818d1ad88feSMark Starovoytov 			ATL_HW_CHIP_MIPS |
819d1ad88feSMark Starovoytov 			ATL_HW_CHIP_TPO2 |
820d1ad88feSMark Starovoytov 			ATL_HW_CHIP_RPF2;
82198c4c201SDavid VomLehn 	}
82298c4c201SDavid VomLehn 
82398c4c201SDavid VomLehn 	*p = chip_features;
82498c4c201SDavid VomLehn }
82598c4c201SDavid VomLehn 
82644e00dd8SIgor Russkikh static int hw_atl_fw1x_deinit(struct aq_hw_s *self)
82798c4c201SDavid VomLehn {
82844e00dd8SIgor Russkikh 	hw_atl_utils_mpi_set_speed(self, 0);
82944e00dd8SIgor Russkikh 	hw_atl_utils_mpi_set_state(self, MPI_DEINIT);
8307b0c342fSNikita Danilov 
83198c4c201SDavid VomLehn 	return 0;
83298c4c201SDavid VomLehn }
83398c4c201SDavid VomLehn 
83465e665e6SIgor Russkikh int hw_atl_utils_update_stats(struct aq_hw_s *self)
83565e665e6SIgor Russkikh {
836ce4cdbe4SDmitry Bogdanov 	struct aq_stats_s *cs = &self->curr_stats;
8377b0c342fSNikita Danilov 	struct hw_atl_utils_mbox mbox;
83865e665e6SIgor Russkikh 
83965e665e6SIgor Russkikh 	hw_atl_utils_mpi_read_stats(self, &mbox);
84065e665e6SIgor Russkikh 
8411a713f87SIgor Russkikh #define AQ_SDELTA(_N_) (self->curr_stats._N_ += \
8421a713f87SIgor Russkikh 			mbox.stats._N_ - self->last_stats._N_)
8431a713f87SIgor Russkikh 
844be08d839SIgor Russkikh 	if (self->aq_link_status.mbps) {
84565e665e6SIgor Russkikh 		AQ_SDELTA(uprc);
84665e665e6SIgor Russkikh 		AQ_SDELTA(mprc);
84765e665e6SIgor Russkikh 		AQ_SDELTA(bprc);
84865e665e6SIgor Russkikh 		AQ_SDELTA(erpt);
84965e665e6SIgor Russkikh 
85065e665e6SIgor Russkikh 		AQ_SDELTA(uptc);
85165e665e6SIgor Russkikh 		AQ_SDELTA(mptc);
85265e665e6SIgor Russkikh 		AQ_SDELTA(bptc);
85365e665e6SIgor Russkikh 		AQ_SDELTA(erpr);
85465e665e6SIgor Russkikh 
85565e665e6SIgor Russkikh 		AQ_SDELTA(ubrc);
85665e665e6SIgor Russkikh 		AQ_SDELTA(ubtc);
85765e665e6SIgor Russkikh 		AQ_SDELTA(mbrc);
85865e665e6SIgor Russkikh 		AQ_SDELTA(mbtc);
85965e665e6SIgor Russkikh 		AQ_SDELTA(bbrc);
86065e665e6SIgor Russkikh 		AQ_SDELTA(bbtc);
86165e665e6SIgor Russkikh 		AQ_SDELTA(dpc);
862be08d839SIgor Russkikh 	}
86365e665e6SIgor Russkikh #undef AQ_SDELTA
864ce4cdbe4SDmitry Bogdanov 
865ce4cdbe4SDmitry Bogdanov 	cs->dma_pkt_rc = hw_atl_stats_rx_dma_good_pkt_counter_get(self);
866ce4cdbe4SDmitry Bogdanov 	cs->dma_pkt_tc = hw_atl_stats_tx_dma_good_pkt_counter_get(self);
867ce4cdbe4SDmitry Bogdanov 	cs->dma_oct_rc = hw_atl_stats_rx_dma_good_octet_counter_get(self);
868ce4cdbe4SDmitry Bogdanov 	cs->dma_oct_tc = hw_atl_stats_tx_dma_good_octet_counter_get(self);
86965e665e6SIgor Russkikh 
8701a713f87SIgor Russkikh 	memcpy(&self->last_stats, &mbox.stats, sizeof(mbox.stats));
87165e665e6SIgor Russkikh 
87265e665e6SIgor Russkikh 	return 0;
87365e665e6SIgor Russkikh }
87465e665e6SIgor Russkikh 
875be08d839SIgor Russkikh struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self)
87698c4c201SDavid VomLehn {
8771a713f87SIgor Russkikh 	return &self->curr_stats;
87898c4c201SDavid VomLehn }
87998c4c201SDavid VomLehn 
88098c4c201SDavid VomLehn static const u32 hw_atl_utils_hw_mac_regs[] = {
88198c4c201SDavid VomLehn 	0x00005580U, 0x00005590U, 0x000055B0U, 0x000055B4U,
88298c4c201SDavid VomLehn 	0x000055C0U, 0x00005B00U, 0x00005B04U, 0x00005B08U,
88398c4c201SDavid VomLehn 	0x00005B0CU, 0x00005B10U, 0x00005B14U, 0x00005B18U,
88498c4c201SDavid VomLehn 	0x00005B1CU, 0x00005B20U, 0x00005B24U, 0x00005B28U,
88598c4c201SDavid VomLehn 	0x00005B2CU, 0x00005B30U, 0x00005B34U, 0x00005B38U,
88698c4c201SDavid VomLehn 	0x00005B3CU, 0x00005B40U, 0x00005B44U, 0x00005B48U,
88798c4c201SDavid VomLehn 	0x00005B4CU, 0x00005B50U, 0x00005B54U, 0x00005B58U,
88898c4c201SDavid VomLehn 	0x00005B5CU, 0x00005B60U, 0x00005B64U, 0x00005B68U,
88998c4c201SDavid VomLehn 	0x00005B6CU, 0x00005B70U, 0x00005B74U, 0x00005B78U,
89098c4c201SDavid VomLehn 	0x00005B7CU, 0x00007C00U, 0x00007C04U, 0x00007C08U,
89198c4c201SDavid VomLehn 	0x00007C0CU, 0x00007C10U, 0x00007C14U, 0x00007C18U,
89298c4c201SDavid VomLehn 	0x00007C1CU, 0x00007C20U, 0x00007C40U, 0x00007C44U,
89398c4c201SDavid VomLehn 	0x00007C48U, 0x00007C4CU, 0x00007C50U, 0x00007C54U,
89498c4c201SDavid VomLehn 	0x00007C58U, 0x00007C5CU, 0x00007C60U, 0x00007C80U,
89598c4c201SDavid VomLehn 	0x00007C84U, 0x00007C88U, 0x00007C8CU, 0x00007C90U,
89698c4c201SDavid VomLehn 	0x00007C94U, 0x00007C98U, 0x00007C9CU, 0x00007CA0U,
89798c4c201SDavid VomLehn 	0x00007CC0U, 0x00007CC4U, 0x00007CC8U, 0x00007CCCU,
89898c4c201SDavid VomLehn 	0x00007CD0U, 0x00007CD4U, 0x00007CD8U, 0x00007CDCU,
89998c4c201SDavid VomLehn 	0x00007CE0U, 0x00000300U, 0x00000304U, 0x00000308U,
90098c4c201SDavid VomLehn 	0x0000030cU, 0x00000310U, 0x00000314U, 0x00000318U,
90198c4c201SDavid VomLehn 	0x0000031cU, 0x00000360U, 0x00000364U, 0x00000368U,
90298c4c201SDavid VomLehn 	0x0000036cU, 0x00000370U, 0x00000374U, 0x00006900U,
90398c4c201SDavid VomLehn };
90498c4c201SDavid VomLehn 
90598c4c201SDavid VomLehn int hw_atl_utils_hw_get_regs(struct aq_hw_s *self,
9064cbc9f92SIgor Russkikh 			     const struct aq_hw_caps_s *aq_hw_caps,
90798c4c201SDavid VomLehn 			     u32 *regs_buff)
90898c4c201SDavid VomLehn {
90998c4c201SDavid VomLehn 	unsigned int i = 0U;
91098c4c201SDavid VomLehn 
91198c4c201SDavid VomLehn 	for (i = 0; i < aq_hw_caps->mac_regs_count; i++)
91298c4c201SDavid VomLehn 		regs_buff[i] = aq_hw_read_reg(self,
91398c4c201SDavid VomLehn 					      hw_atl_utils_hw_mac_regs[i]);
9147b0c342fSNikita Danilov 
91598c4c201SDavid VomLehn 	return 0;
91698c4c201SDavid VomLehn }
91798c4c201SDavid VomLehn 
91836e90a52SNikita Danilov u32 hw_atl_utils_get_fw_version(struct aq_hw_s *self)
91998c4c201SDavid VomLehn {
92036e90a52SNikita Danilov 	return aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION);
92198c4c201SDavid VomLehn }
9220c58c35fSIgor Russkikh 
923837c6378SNikita Danilov static int aq_fw1x_set_wake_magic(struct aq_hw_s *self, bool wol_enabled,
924837c6378SNikita Danilov 				  u8 *mac)
925a0da96c0SYana Esina {
9268f60f762SNikita Danilov 	struct hw_atl_utils_fw_rpc *prpc = NULL;
927a0da96c0SYana Esina 	unsigned int rpc_size = 0U;
928a0da96c0SYana Esina 	int err = 0;
929a0da96c0SYana Esina 
930a0da96c0SYana Esina 	err = hw_atl_utils_fw_rpc_wait(self, &prpc);
931a0da96c0SYana Esina 	if (err < 0)
932a0da96c0SYana Esina 		goto err_exit;
933a0da96c0SYana Esina 
934a0da96c0SYana Esina 	memset(prpc, 0, sizeof(*prpc));
935a0da96c0SYana Esina 
936a0da96c0SYana Esina 	if (wol_enabled) {
937d993e14bSNikita Danilov 		rpc_size = offsetof(struct hw_atl_utils_fw_rpc, msg_wol_add) +
938d993e14bSNikita Danilov 			   sizeof(prpc->msg_wol_add);
939d993e14bSNikita Danilov 
940a0da96c0SYana Esina 
941a0da96c0SYana Esina 		prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD;
942d993e14bSNikita Danilov 		prpc->msg_wol_add.priority =
943a0da96c0SYana Esina 				HAL_ATLANTIC_UTILS_FW_MSG_WOL_PRIOR;
944d993e14bSNikita Danilov 		prpc->msg_wol_add.pattern_id =
945a0da96c0SYana Esina 				HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN;
946d993e14bSNikita Danilov 		prpc->msg_wol_add.packet_type =
947a0da96c0SYana Esina 				HAL_ATLANTIC_UTILS_FW_MSG_WOL_MAG_PKT;
948a0da96c0SYana Esina 
949d993e14bSNikita Danilov 		ether_addr_copy((u8 *)&prpc->msg_wol_add.magic_packet_pattern,
950d993e14bSNikita Danilov 				mac);
951a0da96c0SYana Esina 	} else {
952d993e14bSNikita Danilov 		rpc_size = sizeof(prpc->msg_wol_remove) +
953d993e14bSNikita Danilov 			   offsetof(struct hw_atl_utils_fw_rpc, msg_wol_remove);
954a0da96c0SYana Esina 
955a0da96c0SYana Esina 		prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL;
956d993e14bSNikita Danilov 		prpc->msg_wol_add.pattern_id =
957a0da96c0SYana Esina 				HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN;
958a0da96c0SYana Esina 	}
959a0da96c0SYana Esina 
960a0da96c0SYana Esina 	err = hw_atl_utils_fw_rpc_call(self, rpc_size);
961a0da96c0SYana Esina 
962a0da96c0SYana Esina err_exit:
963a0da96c0SYana Esina 	return err;
964a0da96c0SYana Esina }
965a0da96c0SYana Esina 
9663d5537f9SWei Yongjun static int aq_fw1x_set_power(struct aq_hw_s *self, unsigned int power_state,
967a0da96c0SYana Esina 			     u8 *mac)
968a0da96c0SYana Esina {
9698f60f762SNikita Danilov 	struct hw_atl_utils_fw_rpc *prpc = NULL;
970a0da96c0SYana Esina 	unsigned int rpc_size = 0U;
971a0da96c0SYana Esina 	int err = 0;
972a0da96c0SYana Esina 
973837c6378SNikita Danilov 	if (self->aq_nic_cfg->wol & WAKE_MAGIC) {
974837c6378SNikita Danilov 		err = aq_fw1x_set_wake_magic(self, 1, mac);
975a0da96c0SYana Esina 
976a0da96c0SYana Esina 		if (err < 0)
977a0da96c0SYana Esina 			goto err_exit;
978a0da96c0SYana Esina 
979a0da96c0SYana Esina 		rpc_size = sizeof(prpc->msg_id) +
980a0da96c0SYana Esina 			   sizeof(prpc->msg_enable_wakeup);
981a0da96c0SYana Esina 
982a0da96c0SYana Esina 		err = hw_atl_utils_fw_rpc_wait(self, &prpc);
983a0da96c0SYana Esina 
984a0da96c0SYana Esina 		if (err < 0)
985a0da96c0SYana Esina 			goto err_exit;
986a0da96c0SYana Esina 
987a0da96c0SYana Esina 		memset(prpc, 0, rpc_size);
988a0da96c0SYana Esina 
989a0da96c0SYana Esina 		prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP;
990a0da96c0SYana Esina 		prpc->msg_enable_wakeup.pattern_mask = 0x00000002;
991a0da96c0SYana Esina 
992a0da96c0SYana Esina 		err = hw_atl_utils_fw_rpc_call(self, rpc_size);
993a0da96c0SYana Esina 		if (err < 0)
994a0da96c0SYana Esina 			goto err_exit;
995a0da96c0SYana Esina 	}
996a0da96c0SYana Esina 	hw_atl_utils_mpi_set_speed(self, 0);
997a0da96c0SYana Esina 	hw_atl_utils_mpi_set_state(self, MPI_POWER);
998a0da96c0SYana Esina 
999a0da96c0SYana Esina err_exit:
1000a0da96c0SYana Esina 	return err;
1001a0da96c0SYana Esina }
1002a0da96c0SYana Esina 
10036a7f2277SNikita Danilov static u32 hw_atl_utils_get_mpi_mbox_tid(struct aq_hw_s *self)
10046a7f2277SNikita Danilov {
10056a7f2277SNikita Danilov 	struct hw_atl_utils_mbox_header mbox;
10066a7f2277SNikita Danilov 
10076a7f2277SNikita Danilov 	hw_atl_utils_mpi_read_mbox(self, &mbox);
10086a7f2277SNikita Danilov 
10096a7f2277SNikita Danilov 	return mbox.transaction_id;
10106a7f2277SNikita Danilov }
10116a7f2277SNikita Danilov 
10126a7f2277SNikita Danilov static u32 hw_atl_utils_mpi_get_state(struct aq_hw_s *self)
10136a7f2277SNikita Danilov {
10146a7f2277SNikita Danilov 	return aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR);
10156a7f2277SNikita Danilov }
10166a7f2277SNikita Danilov 
10176a7f2277SNikita Danilov static u32 hw_atl_utils_mif_cmd_get(struct aq_hw_s *self)
10186a7f2277SNikita Danilov {
10196a7f2277SNikita Danilov 	return aq_hw_read_reg(self, HW_ATL_MIF_CMD);
10206a7f2277SNikita Danilov }
10216a7f2277SNikita Danilov 
10226a7f2277SNikita Danilov static u32 hw_atl_utils_mif_addr_get(struct aq_hw_s *self)
10236a7f2277SNikita Danilov {
10246a7f2277SNikita Danilov 	return aq_hw_read_reg(self, HW_ATL_MIF_ADDR);
10256a7f2277SNikita Danilov }
10266a7f2277SNikita Danilov 
10276a7f2277SNikita Danilov static u32 hw_atl_utils_rpc_state_get(struct aq_hw_s *self)
10286a7f2277SNikita Danilov {
10296a7f2277SNikita Danilov 	return aq_hw_read_reg(self, HW_ATL_RPC_STATE_ADR);
10306a7f2277SNikita Danilov }
10316a7f2277SNikita Danilov 
1032e7b5f97eSIgor Russkikh static u32 aq_fw1x_rpc_get(struct aq_hw_s *self)
1033e7b5f97eSIgor Russkikh {
1034e7b5f97eSIgor Russkikh 	return aq_hw_read_reg(self, HW_ATL_MPI_RPC_ADDR);
1035e7b5f97eSIgor Russkikh }
1036e7b5f97eSIgor Russkikh 
10370c58c35fSIgor Russkikh const struct aq_fw_ops aq_fw_1x_ops = {
10380c58c35fSIgor Russkikh 	.init = hw_atl_utils_mpi_create,
103944e00dd8SIgor Russkikh 	.deinit = hw_atl_fw1x_deinit,
10400c58c35fSIgor Russkikh 	.reset = NULL,
10410c58c35fSIgor Russkikh 	.get_mac_permanent = hw_atl_utils_get_mac_permanent,
10420c58c35fSIgor Russkikh 	.set_link_speed = hw_atl_utils_mpi_set_speed,
10430c58c35fSIgor Russkikh 	.set_state = hw_atl_utils_mpi_set_state,
10440c58c35fSIgor Russkikh 	.update_link_status = hw_atl_utils_mpi_get_link_status,
10450c58c35fSIgor Russkikh 	.update_stats = hw_atl_utils_update_stats,
10468f894011SYana Esina 	.get_phy_temp = NULL,
1047a0da96c0SYana Esina 	.set_power = aq_fw1x_set_power,
104892ab6407SYana Esina 	.set_eee_rate = NULL,
104992ab6407SYana Esina 	.get_eee_rate = NULL,
1050288551deSIgor Russkikh 	.set_flow_control = NULL,
1051910479a9SEgor Pomozov 	.send_fw_request = NULL,
1052910479a9SEgor Pomozov 	.enable_ptp = NULL,
1053d1287ce4SNikita Danilov 	.led_control = NULL,
10540c58c35fSIgor Russkikh };
1055