175a6faf6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
298c4c201SDavid VomLehn /*
398c4c201SDavid VomLehn  * aQuantia Corporation Network Driver
4593f7b43SDmitry Bezrukov  * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
598c4c201SDavid VomLehn  */
698c4c201SDavid VomLehn 
798c4c201SDavid VomLehn /* File hw_atl_utils.c: Definition of common functions for Atlantic hardware
898c4c201SDavid VomLehn  * abstraction layer.
998c4c201SDavid VomLehn  */
1098c4c201SDavid VomLehn 
111a713f87SIgor Russkikh #include "../aq_nic.h"
1298c4c201SDavid VomLehn #include "../aq_hw_utils.h"
1398c4c201SDavid VomLehn #include "hw_atl_utils.h"
1498c4c201SDavid VomLehn #include "hw_atl_llh.h"
150c58c35fSIgor Russkikh #include "hw_atl_llh_internal.h"
1698c4c201SDavid VomLehn 
1798c4c201SDavid VomLehn #include <linux/random.h>
1898c4c201SDavid VomLehn 
1998c4c201SDavid VomLehn #define HW_ATL_UCP_0X370_REG    0x0370U
2098c4c201SDavid VomLehn 
2147203b34SIgor Russkikh #define HW_ATL_MIF_CMD          0x0200U
2247203b34SIgor Russkikh #define HW_ATL_MIF_ADDR         0x0208U
2347203b34SIgor Russkikh #define HW_ATL_MIF_VAL          0x020CU
2447203b34SIgor Russkikh 
25e7b5f97eSIgor Russkikh #define HW_ATL_MPI_RPC_ADDR     0x0334U
266a7f2277SNikita Danilov #define HW_ATL_RPC_CONTROL_ADR  0x0338U
276a7f2277SNikita Danilov #define HW_ATL_RPC_STATE_ADR    0x033CU
286a7f2277SNikita Danilov 
290c58c35fSIgor Russkikh #define HW_ATL_MPI_FW_VERSION	0x18
3098c4c201SDavid VomLehn #define HW_ATL_MPI_CONTROL_ADR  0x0368U
3198c4c201SDavid VomLehn #define HW_ATL_MPI_STATE_ADR    0x036CU
3298c4c201SDavid VomLehn 
3398c4c201SDavid VomLehn #define HW_ATL_MPI_STATE_MSK      0x00FFU
3498c4c201SDavid VomLehn #define HW_ATL_MPI_STATE_SHIFT    0U
3544e00dd8SIgor Russkikh #define HW_ATL_MPI_SPEED_MSK      0x00FF0000U
3698c4c201SDavid VomLehn #define HW_ATL_MPI_SPEED_SHIFT    16U
3744e00dd8SIgor Russkikh #define HW_ATL_MPI_DIRTY_WAKE_MSK 0x02000000U
3898c4c201SDavid VomLehn 
39c8c82eb3SIgor Russkikh #define HW_ATL_MPI_DAISY_CHAIN_STATUS	0x704
40c8c82eb3SIgor Russkikh #define HW_ATL_MPI_BOOT_EXIT_CODE	0x388
41c8c82eb3SIgor Russkikh 
42c8c82eb3SIgor Russkikh #define HW_ATL_MAC_PHY_CONTROL	0x4000
43c8c82eb3SIgor Russkikh #define HW_ATL_MAC_PHY_MPI_RESET_BIT 0x1D
44c8c82eb3SIgor Russkikh 
450c58c35fSIgor Russkikh #define HW_ATL_FW_VER_1X 0x01050006U
46a57d3929SIgor Russkikh #define HW_ATL_FW_VER_2X 0x02000000U
47a57d3929SIgor Russkikh #define HW_ATL_FW_VER_3X 0x03000000U
480c58c35fSIgor Russkikh 
49c8c82eb3SIgor Russkikh #define FORCE_FLASHLESS 0
50c8c82eb3SIgor Russkikh 
51dc12f75aSNikita Danilov enum mcp_area {
52dc12f75aSNikita Danilov 	MCP_AREA_CONFIG = 0x80000000,
53dc12f75aSNikita Danilov 	MCP_AREA_SETTINGS = 0x20000000,
54dc12f75aSNikita Danilov };
55dc12f75aSNikita Danilov 
560c58c35fSIgor Russkikh static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual);
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 
75c8c82eb3SIgor Russkikh 	if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X,
76c8c82eb3SIgor Russkikh 				   self->fw_ver_actual) == 0) {
770c58c35fSIgor Russkikh 		*fw_ops = &aq_fw_1x_ops;
78c8c82eb3SIgor Russkikh 	} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X,
79c8c82eb3SIgor Russkikh 					  self->fw_ver_actual) == 0) {
80a57d3929SIgor Russkikh 		*fw_ops = &aq_fw_2x_ops;
81c8c82eb3SIgor Russkikh 	} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X,
82c8c82eb3SIgor Russkikh 					  self->fw_ver_actual) == 0) {
83a57d3929SIgor Russkikh 		*fw_ops = &aq_fw_2x_ops;
84c8c82eb3SIgor Russkikh 	} else {
850c58c35fSIgor Russkikh 		aq_pr_err("Bad FW version detected: %x\n",
860c58c35fSIgor Russkikh 			  self->fw_ver_actual);
870c58c35fSIgor Russkikh 		return -EOPNOTSUPP;
880c58c35fSIgor Russkikh 	}
890c58c35fSIgor Russkikh 	self->aq_fw_ops = *fw_ops;
900c58c35fSIgor Russkikh 	err = self->aq_fw_ops->init(self);
917b0c342fSNikita Danilov 
920c58c35fSIgor Russkikh 	return err;
930c58c35fSIgor Russkikh }
940c58c35fSIgor Russkikh 
95c8c82eb3SIgor Russkikh static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self)
96c8c82eb3SIgor Russkikh {
971bf9a752SIgor Russkikh 	u32 gsr, val;
98c8c82eb3SIgor Russkikh 	int k = 0;
99c8c82eb3SIgor Russkikh 
100c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x40e1);
101c8c82eb3SIgor Russkikh 	AQ_HW_SLEEP(50);
102c8c82eb3SIgor Russkikh 
103c8c82eb3SIgor Russkikh 	/* Cleanup SPI */
1041bf9a752SIgor Russkikh 	val = aq_hw_read_reg(self, 0x53C);
1051bf9a752SIgor Russkikh 	aq_hw_write_reg(self, 0x53C, val | 0x10);
106c8c82eb3SIgor Russkikh 
107c8c82eb3SIgor Russkikh 	gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
108c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000);
109c8c82eb3SIgor Russkikh 
110c8c82eb3SIgor Russkikh 	/* Kickstart MAC */
111c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x80e0);
112c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x32a8, 0x0);
113c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x520, 0x1);
1141bf9a752SIgor Russkikh 
1151bf9a752SIgor Russkikh 	/* Reset SPI again because of possible interrupted SPI burst */
1161bf9a752SIgor Russkikh 	val = aq_hw_read_reg(self, 0x53C);
1171bf9a752SIgor Russkikh 	aq_hw_write_reg(self, 0x53C, val | 0x10);
118c8c82eb3SIgor Russkikh 	AQ_HW_SLEEP(10);
1191bf9a752SIgor Russkikh 	/* Clear SPI reset state */
1201bf9a752SIgor Russkikh 	aq_hw_write_reg(self, 0x53C, val & ~0x10);
1211bf9a752SIgor Russkikh 
122c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x180e0);
123c8c82eb3SIgor Russkikh 
124c8c82eb3SIgor Russkikh 	for (k = 0; k < 1000; k++) {
125c8c82eb3SIgor Russkikh 		u32 flb_status = aq_hw_read_reg(self,
126c8c82eb3SIgor Russkikh 						HW_ATL_MPI_DAISY_CHAIN_STATUS);
127c8c82eb3SIgor Russkikh 
128c8c82eb3SIgor Russkikh 		flb_status = flb_status & 0x10;
129c8c82eb3SIgor Russkikh 		if (flb_status)
130c8c82eb3SIgor Russkikh 			break;
131c8c82eb3SIgor Russkikh 		AQ_HW_SLEEP(10);
132c8c82eb3SIgor Russkikh 	}
133c8c82eb3SIgor Russkikh 	if (k == 1000) {
134c8c82eb3SIgor Russkikh 		aq_pr_err("MAC kickstart failed\n");
135c8c82eb3SIgor Russkikh 		return -EIO;
136c8c82eb3SIgor Russkikh 	}
137c8c82eb3SIgor Russkikh 
138c8c82eb3SIgor Russkikh 	/* FW reset */
139c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x80e0);
140c8c82eb3SIgor Russkikh 	AQ_HW_SLEEP(50);
141c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x3a0, 0x1);
142c8c82eb3SIgor Russkikh 
143c8c82eb3SIgor Russkikh 	/* Kickstart PHY - skipped */
144c8c82eb3SIgor Russkikh 
145c8c82eb3SIgor Russkikh 	/* Global software reset*/
146c8c82eb3SIgor Russkikh 	hw_atl_rx_rx_reg_res_dis_set(self, 0U);
147c8c82eb3SIgor Russkikh 	hw_atl_tx_tx_reg_res_dis_set(self, 0U);
148c8c82eb3SIgor Russkikh 	aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL,
149c8c82eb3SIgor Russkikh 			    BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT),
150c8c82eb3SIgor Russkikh 			    HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0);
151c8c82eb3SIgor Russkikh 	gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
152c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000);
153c8c82eb3SIgor Russkikh 
154c8c82eb3SIgor Russkikh 	for (k = 0; k < 1000; k++) {
155c8c82eb3SIgor Russkikh 		u32 fw_state = aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION);
156c8c82eb3SIgor Russkikh 
157c8c82eb3SIgor Russkikh 		if (fw_state)
158c8c82eb3SIgor Russkikh 			break;
159c8c82eb3SIgor Russkikh 		AQ_HW_SLEEP(10);
160c8c82eb3SIgor Russkikh 	}
161c8c82eb3SIgor Russkikh 	if (k == 1000) {
162c8c82eb3SIgor Russkikh 		aq_pr_err("FW kickstart failed\n");
163c8c82eb3SIgor Russkikh 		return -EIO;
164c8c82eb3SIgor Russkikh 	}
165d0f0fb25SIgor Russkikh 	/* Old FW requires fixed delay after init */
166d0f0fb25SIgor Russkikh 	AQ_HW_SLEEP(15);
167c8c82eb3SIgor Russkikh 
168c8c82eb3SIgor Russkikh 	return 0;
169c8c82eb3SIgor Russkikh }
170c8c82eb3SIgor Russkikh 
171c8c82eb3SIgor Russkikh static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self)
172c8c82eb3SIgor Russkikh {
1731bf9a752SIgor Russkikh 	u32 gsr, val, rbl_status;
174c8c82eb3SIgor Russkikh 	int k;
175c8c82eb3SIgor Russkikh 
176c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x40e1);
177c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x3a0, 0x1);
178c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x32a8, 0x0);
179c8c82eb3SIgor Russkikh 
180c8c82eb3SIgor Russkikh 	/* Alter RBL status */
181c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x388, 0xDEAD);
182c8c82eb3SIgor Russkikh 
1831bf9a752SIgor Russkikh 	/* Cleanup SPI */
1841bf9a752SIgor Russkikh 	val = aq_hw_read_reg(self, 0x53C);
1851bf9a752SIgor Russkikh 	aq_hw_write_reg(self, 0x53C, val | 0x10);
1861bf9a752SIgor Russkikh 
187c8c82eb3SIgor Russkikh 	/* Global software reset*/
188c8c82eb3SIgor Russkikh 	hw_atl_rx_rx_reg_res_dis_set(self, 0U);
189c8c82eb3SIgor Russkikh 	hw_atl_tx_tx_reg_res_dis_set(self, 0U);
190c8c82eb3SIgor Russkikh 	aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL,
191c8c82eb3SIgor Russkikh 			    BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT),
192c8c82eb3SIgor Russkikh 			    HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0);
193c8c82eb3SIgor Russkikh 	gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
194c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR,
195c8c82eb3SIgor Russkikh 			(gsr & 0xFFFFBFFF) | 0x8000);
196c8c82eb3SIgor Russkikh 
197c8c82eb3SIgor Russkikh 	if (FORCE_FLASHLESS)
198c8c82eb3SIgor Russkikh 		aq_hw_write_reg(self, 0x534, 0x0);
199c8c82eb3SIgor Russkikh 
200c8c82eb3SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x40e0);
201c8c82eb3SIgor Russkikh 
202c8c82eb3SIgor Russkikh 	/* Wait for RBL boot */
203c8c82eb3SIgor Russkikh 	for (k = 0; k < 1000; k++) {
204c8c82eb3SIgor Russkikh 		rbl_status = aq_hw_read_reg(self, 0x388) & 0xFFFF;
205c8c82eb3SIgor Russkikh 		if (rbl_status && rbl_status != 0xDEAD)
206c8c82eb3SIgor Russkikh 			break;
207c8c82eb3SIgor Russkikh 		AQ_HW_SLEEP(10);
208c8c82eb3SIgor Russkikh 	}
209c8c82eb3SIgor Russkikh 	if (!rbl_status || rbl_status == 0xDEAD) {
210c8c82eb3SIgor Russkikh 		aq_pr_err("RBL Restart failed");
211c8c82eb3SIgor Russkikh 		return -EIO;
212c8c82eb3SIgor Russkikh 	}
213c8c82eb3SIgor Russkikh 
214c8c82eb3SIgor Russkikh 	/* Restore NVR */
215c8c82eb3SIgor Russkikh 	if (FORCE_FLASHLESS)
216c8c82eb3SIgor Russkikh 		aq_hw_write_reg(self, 0x534, 0xA0);
217c8c82eb3SIgor Russkikh 
218c8c82eb3SIgor Russkikh 	if (rbl_status == 0xF1A7) {
219c8c82eb3SIgor Russkikh 		aq_pr_err("No FW detected. Dynamic FW load not implemented\n");
220c8c82eb3SIgor Russkikh 		return -ENOTSUPP;
221c8c82eb3SIgor Russkikh 	}
222c8c82eb3SIgor Russkikh 
223c8c82eb3SIgor Russkikh 	for (k = 0; k < 1000; k++) {
224c8c82eb3SIgor Russkikh 		u32 fw_state = aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION);
225c8c82eb3SIgor Russkikh 
226c8c82eb3SIgor Russkikh 		if (fw_state)
227c8c82eb3SIgor Russkikh 			break;
228c8c82eb3SIgor Russkikh 		AQ_HW_SLEEP(10);
229c8c82eb3SIgor Russkikh 	}
230c8c82eb3SIgor Russkikh 	if (k == 1000) {
231c8c82eb3SIgor Russkikh 		aq_pr_err("FW kickstart failed\n");
232c8c82eb3SIgor Russkikh 		return -EIO;
233c8c82eb3SIgor Russkikh 	}
234d0f0fb25SIgor Russkikh 	/* Old FW requires fixed delay after init */
235d0f0fb25SIgor Russkikh 	AQ_HW_SLEEP(15);
236c8c82eb3SIgor Russkikh 
237c8c82eb3SIgor Russkikh 	return 0;
238c8c82eb3SIgor Russkikh }
239c8c82eb3SIgor Russkikh 
240c8c82eb3SIgor Russkikh int hw_atl_utils_soft_reset(struct aq_hw_s *self)
241c8c82eb3SIgor Russkikh {
242c8c82eb3SIgor Russkikh 	u32 boot_exit_code = 0;
2436a7f2277SNikita Danilov 	u32 val;
2447b0c342fSNikita Danilov 	int k;
245c8c82eb3SIgor Russkikh 
246c8c82eb3SIgor Russkikh 	for (k = 0; k < 1000; ++k) {
247c8c82eb3SIgor Russkikh 		u32 flb_status = aq_hw_read_reg(self,
248c8c82eb3SIgor Russkikh 						HW_ATL_MPI_DAISY_CHAIN_STATUS);
249c8c82eb3SIgor Russkikh 		boot_exit_code = aq_hw_read_reg(self,
250c8c82eb3SIgor Russkikh 						HW_ATL_MPI_BOOT_EXIT_CODE);
251c8c82eb3SIgor Russkikh 		if (flb_status != 0x06000000 || boot_exit_code != 0)
252c8c82eb3SIgor Russkikh 			break;
253c8c82eb3SIgor Russkikh 	}
254c8c82eb3SIgor Russkikh 
255c8c82eb3SIgor Russkikh 	if (k == 1000) {
256c8c82eb3SIgor Russkikh 		aq_pr_err("Neither RBL nor FLB firmware started\n");
257c8c82eb3SIgor Russkikh 		return -EOPNOTSUPP;
258c8c82eb3SIgor Russkikh 	}
259c8c82eb3SIgor Russkikh 
260c8c82eb3SIgor Russkikh 	self->rbl_enabled = (boot_exit_code != 0);
261c8c82eb3SIgor Russkikh 
262cce96d18SIgor Russkikh 	/* FW 1.x may bootup in an invalid POWER state (WOL feature).
263cce96d18SIgor Russkikh 	 * We should work around this by forcing its state back to DEINIT
264cce96d18SIgor Russkikh 	 */
265cce96d18SIgor Russkikh 	if (!hw_atl_utils_ver_match(HW_ATL_FW_VER_1X,
266cce96d18SIgor Russkikh 				    aq_hw_read_reg(self,
267cce96d18SIgor Russkikh 						   HW_ATL_MPI_FW_VERSION))) {
268cce96d18SIgor Russkikh 		int err = 0;
269cce96d18SIgor Russkikh 
270cce96d18SIgor Russkikh 		hw_atl_utils_mpi_set_state(self, MPI_DEINIT);
2716a7f2277SNikita Danilov 		err = readx_poll_timeout_atomic(hw_atl_utils_mpi_get_state,
2726a7f2277SNikita Danilov 						self, val,
2736a7f2277SNikita Danilov 						(val & HW_ATL_MPI_STATE_MSK) ==
2746a7f2277SNikita Danilov 						 MPI_DEINIT,
2756a7f2277SNikita Danilov 						10, 10000U);
2764e3c7c00SYueHaibing 		if (err)
2774e3c7c00SYueHaibing 			return err;
278cce96d18SIgor Russkikh 	}
279cce96d18SIgor Russkikh 
280c8c82eb3SIgor Russkikh 	if (self->rbl_enabled)
281c8c82eb3SIgor Russkikh 		return hw_atl_utils_soft_reset_rbl(self);
282c8c82eb3SIgor Russkikh 	else
283c8c82eb3SIgor Russkikh 		return hw_atl_utils_soft_reset_flb(self);
284c8c82eb3SIgor Russkikh }
285c8c82eb3SIgor Russkikh 
286a57d3929SIgor Russkikh int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
28798c4c201SDavid VomLehn 				  u32 *p, u32 cnt)
28898c4c201SDavid VomLehn {
28998c4c201SDavid VomLehn 	int err = 0;
2906a7f2277SNikita Danilov 	u32 val;
29198c4c201SDavid VomLehn 
2926a7f2277SNikita Danilov 	err = readx_poll_timeout_atomic(hw_atl_sem_ram_get,
2936a7f2277SNikita Danilov 					self, val, val == 1U,
29498c4c201SDavid VomLehn 					1U, 10000U);
29598c4c201SDavid VomLehn 
29698c4c201SDavid VomLehn 	if (err < 0) {
29798c4c201SDavid VomLehn 		bool is_locked;
29898c4c201SDavid VomLehn 
2998e1c072fSIgor Russkikh 		hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
3000b926d46SNikita Danilov 		is_locked = hw_atl_sem_ram_get(self);
30198c4c201SDavid VomLehn 		if (!is_locked) {
30298c4c201SDavid VomLehn 			err = -ETIME;
30398c4c201SDavid VomLehn 			goto err_exit;
30498c4c201SDavid VomLehn 		}
30598c4c201SDavid VomLehn 	}
30698c4c201SDavid VomLehn 
30747203b34SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_MIF_ADDR, a);
30898c4c201SDavid VomLehn 
30947203b34SIgor Russkikh 	for (++cnt; --cnt && !err;) {
31047203b34SIgor Russkikh 		aq_hw_write_reg(self, HW_ATL_MIF_CMD, 0x00008000U);
31198c4c201SDavid VomLehn 
312d1ad88feSMark Starovoytov 		if (ATL_HW_IS_CHIP_FEATURE(self, REVISION_B1))
3136a7f2277SNikita Danilov 			err = readx_poll_timeout_atomic(hw_atl_utils_mif_addr_get,
3146a7f2277SNikita Danilov 							self, val, val != a,
3156a7f2277SNikita Danilov 							1U, 1000U);
31647203b34SIgor Russkikh 		else
3176a7f2277SNikita Danilov 			err = readx_poll_timeout_atomic(hw_atl_utils_mif_cmd_get,
3186a7f2277SNikita Danilov 							self, val,
3196a7f2277SNikita Danilov 							!(val & 0x100),
3206a7f2277SNikita Danilov 							1U, 1000U);
32198c4c201SDavid VomLehn 
32247203b34SIgor Russkikh 		*(p++) = aq_hw_read_reg(self, HW_ATL_MIF_VAL);
32347203b34SIgor Russkikh 		a += 4;
32498c4c201SDavid VomLehn 	}
32598c4c201SDavid VomLehn 
3268e1c072fSIgor Russkikh 	hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
32798c4c201SDavid VomLehn 
32898c4c201SDavid VomLehn err_exit:
32998c4c201SDavid VomLehn 	return err;
33098c4c201SDavid VomLehn }
33198c4c201SDavid VomLehn 
332dc12f75aSNikita Danilov static int hw_atl_utils_write_b1_mbox(struct aq_hw_s *self, u32 addr,
333dc12f75aSNikita Danilov 				      u32 *p, u32 cnt, enum mcp_area area)
33498c4c201SDavid VomLehn {
335dc12f75aSNikita Danilov 	u32 data_offset = 0;
336dc12f75aSNikita Danilov 	u32 offset = addr;
33798c4c201SDavid VomLehn 	int err = 0;
338dc12f75aSNikita Danilov 	u32 val;
33998c4c201SDavid VomLehn 
340dc12f75aSNikita Danilov 	switch (area) {
341dc12f75aSNikita Danilov 	case MCP_AREA_CONFIG:
342dc12f75aSNikita Danilov 		offset -= self->rpc_addr;
343dc12f75aSNikita Danilov 		break;
344930b9a05SNikita Danilov 
345dc12f75aSNikita Danilov 	case MCP_AREA_SETTINGS:
346dc12f75aSNikita Danilov 		offset -= self->settings_addr;
347dc12f75aSNikita Danilov 		break;
348dc12f75aSNikita Danilov 	}
34998c4c201SDavid VomLehn 
350dc12f75aSNikita Danilov 	offset = offset / sizeof(u32);
351dc12f75aSNikita Danilov 
352dc12f75aSNikita Danilov 	for (; data_offset < cnt; ++data_offset, ++offset) {
353dc12f75aSNikita Danilov 		aq_hw_write_reg(self, 0x328, p[data_offset]);
3543ee5c887SYana Esina 		aq_hw_write_reg(self, 0x32C,
355dc12f75aSNikita Danilov 				(area | (0xFFFF & (offset * 4))));
3563ee5c887SYana Esina 		hw_atl_mcp_up_force_intr_set(self, 1);
3573ee5c887SYana Esina 		/* 1000 times by 10us = 10ms */
3586a7f2277SNikita Danilov 		err = readx_poll_timeout_atomic(hw_atl_scrpad12_get,
3596a7f2277SNikita Danilov 						self, val,
360930b9a05SNikita Danilov 						(val & 0xF0000000) !=
361dc12f75aSNikita Danilov 						area,
3626a7f2277SNikita Danilov 						10U, 10000U);
36398c4c201SDavid VomLehn 
364dc12f75aSNikita Danilov 		if (err < 0)
365dc12f75aSNikita Danilov 			break;
366dc12f75aSNikita Danilov 	}
367dc12f75aSNikita Danilov 
368dc12f75aSNikita Danilov 	return err;
369dc12f75aSNikita Danilov }
370dc12f75aSNikita Danilov 
371dc12f75aSNikita Danilov static int hw_atl_utils_write_b0_mbox(struct aq_hw_s *self, u32 addr,
372dc12f75aSNikita Danilov 				      u32 *p, u32 cnt)
373dc12f75aSNikita Danilov {
374dc12f75aSNikita Danilov 	u32 offset = 0;
375dc12f75aSNikita Danilov 	int err = 0;
376dc12f75aSNikita Danilov 	u32 val;
377dc12f75aSNikita Danilov 
378dc12f75aSNikita Danilov 	aq_hw_write_reg(self, 0x208, addr);
37998c4c201SDavid VomLehn 
3803ee5c887SYana Esina 	for (; offset < cnt; ++offset) {
3813ee5c887SYana Esina 		aq_hw_write_reg(self, 0x20C, p[offset]);
3823ee5c887SYana Esina 		aq_hw_write_reg(self, 0x200, 0xC000);
38398c4c201SDavid VomLehn 
3846a7f2277SNikita Danilov 		err = readx_poll_timeout_atomic(hw_atl_utils_mif_cmd_get,
3856a7f2277SNikita Danilov 						self, val,
386dc12f75aSNikita Danilov 						(val & 0x100) == 0U,
387dc12f75aSNikita Danilov 						10U, 10000U);
388dc12f75aSNikita Danilov 
389dc12f75aSNikita Danilov 		if (err < 0)
390dc12f75aSNikita Danilov 			break;
39198c4c201SDavid VomLehn 	}
392dc12f75aSNikita Danilov 
393dc12f75aSNikita Danilov 	return err;
39498c4c201SDavid VomLehn }
39598c4c201SDavid VomLehn 
396dc12f75aSNikita Danilov static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 addr, u32 *p,
397dc12f75aSNikita Danilov 					 u32 cnt, enum mcp_area area)
398dc12f75aSNikita Danilov {
399dc12f75aSNikita Danilov 	int err = 0;
400dc12f75aSNikita Danilov 	u32 val;
401dc12f75aSNikita Danilov 
402dc12f75aSNikita Danilov 	err = readx_poll_timeout_atomic(hw_atl_sem_ram_get, self,
403dc12f75aSNikita Danilov 					val, val == 1U,
404dc12f75aSNikita Danilov 					10U, 100000U);
405dc12f75aSNikita Danilov 	if (err < 0)
406dc12f75aSNikita Danilov 		goto err_exit;
407dc12f75aSNikita Danilov 
408d1ad88feSMark Starovoytov 	if (ATL_HW_IS_CHIP_FEATURE(self, REVISION_B1))
409dc12f75aSNikita Danilov 		err = hw_atl_utils_write_b1_mbox(self, addr, p, cnt, area);
410dc12f75aSNikita Danilov 	else
411dc12f75aSNikita Danilov 		err = hw_atl_utils_write_b0_mbox(self, addr, p, cnt);
412dc12f75aSNikita Danilov 
4138e1c072fSIgor Russkikh 	hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
41498c4c201SDavid VomLehn 
415dc12f75aSNikita Danilov 	if (err < 0)
416dc12f75aSNikita Danilov 		goto err_exit;
417dc12f75aSNikita Danilov 
418dc12f75aSNikita Danilov 	err = aq_hw_err_from_flags(self);
419dc12f75aSNikita Danilov 
42098c4c201SDavid VomLehn err_exit:
42198c4c201SDavid VomLehn 	return err;
42298c4c201SDavid VomLehn }
42398c4c201SDavid VomLehn 
424dc12f75aSNikita Danilov int hw_atl_write_fwcfg_dwords(struct aq_hw_s *self, u32 *p, u32 cnt)
425dc12f75aSNikita Danilov {
426dc12f75aSNikita Danilov 	return hw_atl_utils_fw_upload_dwords(self, self->rpc_addr, p,
427dc12f75aSNikita Danilov 					     cnt, MCP_AREA_CONFIG);
428dc12f75aSNikita Danilov }
429dc12f75aSNikita Danilov 
430dc12f75aSNikita Danilov int hw_atl_write_fwsettings_dwords(struct aq_hw_s *self, u32 offset, u32 *p,
431dc12f75aSNikita Danilov 				   u32 cnt)
432dc12f75aSNikita Danilov {
433dc12f75aSNikita Danilov 	return hw_atl_utils_fw_upload_dwords(self, self->settings_addr + offset,
434dc12f75aSNikita Danilov 					     p, cnt, MCP_AREA_SETTINGS);
435dc12f75aSNikita Danilov }
436dc12f75aSNikita Danilov 
43798c4c201SDavid VomLehn static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual)
43898c4c201SDavid VomLehn {
43998c4c201SDavid VomLehn 	const u32 dw_major_mask = 0xff000000U;
44098c4c201SDavid VomLehn 	const u32 dw_minor_mask = 0x00ffffffU;
4417b0c342fSNikita Danilov 	int err = 0;
44298c4c201SDavid VomLehn 
44398c4c201SDavid VomLehn 	err = (dw_major_mask & (ver_expected ^ ver_actual)) ? -EOPNOTSUPP : 0;
44498c4c201SDavid VomLehn 	if (err < 0)
44598c4c201SDavid VomLehn 		goto err_exit;
44698c4c201SDavid VomLehn 	err = ((dw_minor_mask & ver_expected) > (dw_minor_mask & ver_actual)) ?
44798c4c201SDavid VomLehn 		-EOPNOTSUPP : 0;
4487b0c342fSNikita Danilov 
44998c4c201SDavid VomLehn err_exit:
45098c4c201SDavid VomLehn 	return err;
45198c4c201SDavid VomLehn }
45298c4c201SDavid VomLehn 
45398c4c201SDavid VomLehn static int hw_atl_utils_init_ucp(struct aq_hw_s *self,
4544cbc9f92SIgor Russkikh 				 const struct aq_hw_caps_s *aq_hw_caps)
45598c4c201SDavid VomLehn {
45698c4c201SDavid VomLehn 	int err = 0;
45798c4c201SDavid VomLehn 
45898c4c201SDavid VomLehn 	if (!aq_hw_read_reg(self, 0x370U)) {
45998c4c201SDavid VomLehn 		unsigned int rnd = 0U;
46098c4c201SDavid VomLehn 		unsigned int ucp_0x370 = 0U;
46198c4c201SDavid VomLehn 
46298c4c201SDavid VomLehn 		get_random_bytes(&rnd, sizeof(unsigned int));
46398c4c201SDavid VomLehn 
46498c4c201SDavid VomLehn 		ucp_0x370 = 0x02020202U | (0xFEFEFEFEU & rnd);
46598c4c201SDavid VomLehn 		aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
46698c4c201SDavid VomLehn 	}
46798c4c201SDavid VomLehn 
4688e1c072fSIgor Russkikh 	hw_atl_reg_glb_cpu_scratch_scp_set(self, 0x00000000U, 25U);
46998c4c201SDavid VomLehn 
47098c4c201SDavid VomLehn 	/* check 10 times by 1ms */
4716a7f2277SNikita Danilov 	err = readx_poll_timeout_atomic(hw_atl_scrpad25_get,
4726a7f2277SNikita Danilov 					self, self->mbox_addr,
4736a7f2277SNikita Danilov 					self->mbox_addr != 0U,
4746a7f2277SNikita Danilov 					1000U, 10000U);
475e7b5f97eSIgor Russkikh 	err = readx_poll_timeout_atomic(aq_fw1x_rpc_get, self,
476e7b5f97eSIgor Russkikh 					self->rpc_addr,
477e7b5f97eSIgor Russkikh 					self->rpc_addr != 0U,
478e7b5f97eSIgor Russkikh 					1000U, 100000U);
47998c4c201SDavid VomLehn 
48098c4c201SDavid VomLehn 	return err;
48198c4c201SDavid VomLehn }
48298c4c201SDavid VomLehn 
48398c4c201SDavid VomLehn struct aq_hw_atl_utils_fw_rpc_tid_s {
48498c4c201SDavid VomLehn 	union {
48598c4c201SDavid VomLehn 		u32 val;
48698c4c201SDavid VomLehn 		struct {
48798c4c201SDavid VomLehn 			u16 tid;
48898c4c201SDavid VomLehn 			u16 len;
48998c4c201SDavid VomLehn 		};
49098c4c201SDavid VomLehn 	};
49198c4c201SDavid VomLehn };
49298c4c201SDavid VomLehn 
49398c4c201SDavid VomLehn #define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL)
49498c4c201SDavid VomLehn 
4953ee5c887SYana Esina int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size)
49698c4c201SDavid VomLehn {
49798c4c201SDavid VomLehn 	struct aq_hw_atl_utils_fw_rpc_tid_s sw;
4987b0c342fSNikita Danilov 	int err = 0;
49998c4c201SDavid VomLehn 
500d1ad88feSMark Starovoytov 	if (!ATL_HW_IS_CHIP_FEATURE(self, MIPS)) {
50198c4c201SDavid VomLehn 		err = -1;
50298c4c201SDavid VomLehn 		goto err_exit;
50398c4c201SDavid VomLehn 	}
504dc12f75aSNikita Danilov 	err = hw_atl_write_fwcfg_dwords(self, (u32 *)(void *)&self->rpc,
50598c4c201SDavid VomLehn 					(rpc_size + sizeof(u32) -
50698c4c201SDavid VomLehn 					 sizeof(u8)) / sizeof(u32));
50798c4c201SDavid VomLehn 	if (err < 0)
50898c4c201SDavid VomLehn 		goto err_exit;
50998c4c201SDavid VomLehn 
5101a713f87SIgor Russkikh 	sw.tid = 0xFFFFU & (++self->rpc_tid);
51198c4c201SDavid VomLehn 	sw.len = (u16)rpc_size;
51298c4c201SDavid VomLehn 	aq_hw_write_reg(self, HW_ATL_RPC_CONTROL_ADR, sw.val);
51398c4c201SDavid VomLehn 
51498c4c201SDavid VomLehn err_exit:
51598c4c201SDavid VomLehn 	return err;
51698c4c201SDavid VomLehn }
51798c4c201SDavid VomLehn 
5183ee5c887SYana Esina int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
5198f60f762SNikita Danilov 			     struct hw_atl_utils_fw_rpc **rpc)
52098c4c201SDavid VomLehn {
52198c4c201SDavid VomLehn 	struct aq_hw_atl_utils_fw_rpc_tid_s sw;
52298c4c201SDavid VomLehn 	struct aq_hw_atl_utils_fw_rpc_tid_s fw;
5237b0c342fSNikita Danilov 	int err = 0;
52498c4c201SDavid VomLehn 
52598c4c201SDavid VomLehn 	do {
52698c4c201SDavid VomLehn 		sw.val = aq_hw_read_reg(self, HW_ATL_RPC_CONTROL_ADR);
52798c4c201SDavid VomLehn 
5281a713f87SIgor Russkikh 		self->rpc_tid = sw.tid;
52998c4c201SDavid VomLehn 
5306a7f2277SNikita Danilov 		err = readx_poll_timeout_atomic(hw_atl_utils_rpc_state_get,
5316a7f2277SNikita Danilov 						self, fw.val,
5326a7f2277SNikita Danilov 						sw.tid == fw.tid,
5336a7f2277SNikita Danilov 						1000U, 100000U);
534e7b5f97eSIgor Russkikh 		if (err < 0)
535e7b5f97eSIgor Russkikh 			goto err_exit;
536e7b5f97eSIgor Russkikh 
537e7b5f97eSIgor Russkikh 		err = aq_hw_err_from_flags(self);
538e7b5f97eSIgor Russkikh 		if (err < 0)
539e7b5f97eSIgor Russkikh 			goto err_exit;
54098c4c201SDavid VomLehn 
54198c4c201SDavid VomLehn 		if (fw.len == 0xFFFFU) {
54298c4c201SDavid VomLehn 			err = hw_atl_utils_fw_rpc_call(self, sw.len);
54398c4c201SDavid VomLehn 			if (err < 0)
54498c4c201SDavid VomLehn 				goto err_exit;
54598c4c201SDavid VomLehn 		}
54698c4c201SDavid VomLehn 	} while (sw.tid != fw.tid || 0xFFFFU == fw.len);
54798c4c201SDavid VomLehn 
54898c4c201SDavid VomLehn 	if (rpc) {
54998c4c201SDavid VomLehn 		if (fw.len) {
55098c4c201SDavid VomLehn 			err =
55198c4c201SDavid VomLehn 			hw_atl_utils_fw_downld_dwords(self,
5521a713f87SIgor Russkikh 						      self->rpc_addr,
55398c4c201SDavid VomLehn 						      (u32 *)(void *)
5541a713f87SIgor Russkikh 						      &self->rpc,
55598c4c201SDavid VomLehn 						      (fw.len + sizeof(u32) -
55698c4c201SDavid VomLehn 						       sizeof(u8)) /
55798c4c201SDavid VomLehn 						      sizeof(u32));
55898c4c201SDavid VomLehn 			if (err < 0)
55998c4c201SDavid VomLehn 				goto err_exit;
56098c4c201SDavid VomLehn 		}
56198c4c201SDavid VomLehn 
5621a713f87SIgor Russkikh 		*rpc = &self->rpc;
56398c4c201SDavid VomLehn 	}
56498c4c201SDavid VomLehn 
56598c4c201SDavid VomLehn err_exit:
56698c4c201SDavid VomLehn 	return err;
56798c4c201SDavid VomLehn }
56898c4c201SDavid VomLehn 
5691a713f87SIgor Russkikh static int hw_atl_utils_mpi_create(struct aq_hw_s *self)
57098c4c201SDavid VomLehn {
57198c4c201SDavid VomLehn 	int err = 0;
57298c4c201SDavid VomLehn 
5731a713f87SIgor Russkikh 	err = hw_atl_utils_init_ucp(self, self->aq_nic_cfg->aq_hw_caps);
57498c4c201SDavid VomLehn 	if (err < 0)
57598c4c201SDavid VomLehn 		goto err_exit;
57698c4c201SDavid VomLehn 
57798c4c201SDavid VomLehn 	err = hw_atl_utils_fw_rpc_init(self);
57898c4c201SDavid VomLehn 	if (err < 0)
57998c4c201SDavid VomLehn 		goto err_exit;
58098c4c201SDavid VomLehn 
58198c4c201SDavid VomLehn err_exit:
58298c4c201SDavid VomLehn 	return err;
58398c4c201SDavid VomLehn }
58498c4c201SDavid VomLehn 
58565e665e6SIgor Russkikh int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self,
5868f60f762SNikita Danilov 			       struct hw_atl_utils_mbox_header *pmbox)
58765e665e6SIgor Russkikh {
58865e665e6SIgor Russkikh 	return hw_atl_utils_fw_downld_dwords(self,
5891a713f87SIgor Russkikh 					     self->mbox_addr,
59065e665e6SIgor Russkikh 					     (u32 *)(void *)pmbox,
59165e665e6SIgor Russkikh 					     sizeof(*pmbox) / sizeof(u32));
59265e665e6SIgor Russkikh }
59365e665e6SIgor Russkikh 
59498c4c201SDavid VomLehn void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
5958f60f762SNikita Danilov 				 struct hw_atl_utils_mbox *pmbox)
59698c4c201SDavid VomLehn {
59798c4c201SDavid VomLehn 	int err = 0;
59898c4c201SDavid VomLehn 
59998c4c201SDavid VomLehn 	err = hw_atl_utils_fw_downld_dwords(self,
6001a713f87SIgor Russkikh 					    self->mbox_addr,
60198c4c201SDavid VomLehn 					    (u32 *)(void *)pmbox,
60298c4c201SDavid VomLehn 					    sizeof(*pmbox) / sizeof(u32));
60398c4c201SDavid VomLehn 	if (err < 0)
60498c4c201SDavid VomLehn 		goto err_exit;
60598c4c201SDavid VomLehn 
606d1ad88feSMark Starovoytov 	if (ATL_HW_IS_CHIP_FEATURE(self, REVISION_A0)) {
60798c4c201SDavid VomLehn 		unsigned int mtu = self->aq_nic_cfg ?
60898c4c201SDavid VomLehn 					self->aq_nic_cfg->mtu : 1514U;
60998c4c201SDavid VomLehn 		pmbox->stats.ubrc = pmbox->stats.uprc * mtu;
61098c4c201SDavid VomLehn 		pmbox->stats.ubtc = pmbox->stats.uptc * mtu;
6111a713f87SIgor Russkikh 		pmbox->stats.dpc = atomic_read(&self->dpc);
61298c4c201SDavid VomLehn 	} else {
613ce4cdbe4SDmitry Bogdanov 		pmbox->stats.dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self);
61498c4c201SDavid VomLehn 	}
61598c4c201SDavid VomLehn 
61698c4c201SDavid VomLehn err_exit:;
61798c4c201SDavid VomLehn }
61898c4c201SDavid VomLehn 
619dfbd0749SWei Yongjun static int hw_atl_utils_mpi_set_speed(struct aq_hw_s *self, u32 speed)
62098c4c201SDavid VomLehn {
6210c58c35fSIgor Russkikh 	u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR);
62298c4c201SDavid VomLehn 
62344e00dd8SIgor Russkikh 	val = val & ~HW_ATL_MPI_SPEED_MSK;
62444e00dd8SIgor Russkikh 	val |= speed << HW_ATL_MPI_SPEED_SHIFT;
6250c58c35fSIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val);
62698c4c201SDavid VomLehn 
62798c4c201SDavid VomLehn 	return 0;
62898c4c201SDavid VomLehn }
62998c4c201SDavid VomLehn 
630dfbd0749SWei Yongjun static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
63144e00dd8SIgor Russkikh 				      enum hal_atl_utils_fw_state_e state)
63298c4c201SDavid VomLehn {
63344e00dd8SIgor Russkikh 	u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR);
6347b0c342fSNikita Danilov 	struct hw_atl_utils_mbox_header mbox;
6357b0c342fSNikita Danilov 	u32 transaction_id = 0;
6367b0c342fSNikita Danilov 	int err = 0;
63798c4c201SDavid VomLehn 
63898c4c201SDavid VomLehn 	if (state == MPI_RESET) {
63965e665e6SIgor Russkikh 		hw_atl_utils_mpi_read_mbox(self, &mbox);
64098c4c201SDavid VomLehn 
64165e665e6SIgor Russkikh 		transaction_id = mbox.transaction_id;
64298c4c201SDavid VomLehn 
6436a7f2277SNikita Danilov 		err = readx_poll_timeout_atomic(hw_atl_utils_get_mpi_mbox_tid,
6446a7f2277SNikita Danilov 						self, mbox.transaction_id,
6456a7f2277SNikita Danilov 						transaction_id !=
6466a7f2277SNikita Danilov 						mbox.transaction_id,
6476a7f2277SNikita Danilov 						1000U, 100000U);
64898c4c201SDavid VomLehn 		if (err < 0)
64998c4c201SDavid VomLehn 			goto err_exit;
65098c4c201SDavid VomLehn 	}
65144e00dd8SIgor Russkikh 	/* On interface DEINIT we disable DW (raise bit)
65244e00dd8SIgor Russkikh 	 * Otherwise enable DW (clear bit)
65344e00dd8SIgor Russkikh 	 */
65444e00dd8SIgor Russkikh 	if (state == MPI_DEINIT || state == MPI_POWER)
65544e00dd8SIgor Russkikh 		val |= HW_ATL_MPI_DIRTY_WAKE_MSK;
65644e00dd8SIgor Russkikh 	else
65744e00dd8SIgor Russkikh 		val &= ~HW_ATL_MPI_DIRTY_WAKE_MSK;
65898c4c201SDavid VomLehn 
65944e00dd8SIgor Russkikh 	/* Set new state bits */
66044e00dd8SIgor Russkikh 	val = val & ~HW_ATL_MPI_STATE_MSK;
66144e00dd8SIgor Russkikh 	val |= state & HW_ATL_MPI_STATE_MSK;
66298c4c201SDavid VomLehn 
6630c58c35fSIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val);
6647b0c342fSNikita Danilov 
66544e00dd8SIgor Russkikh err_exit:
66644e00dd8SIgor Russkikh 	return err;
6670c58c35fSIgor Russkikh }
6680c58c35fSIgor Russkikh 
669bd8ed441SPavel Belous int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self)
67098c4c201SDavid VomLehn {
671bd8ed441SPavel Belous 	struct aq_hw_link_status_s *link_status = &self->aq_link_status;
6727b0c342fSNikita Danilov 	u32 mpi_state;
6737b0c342fSNikita Danilov 	u32 speed;
67498c4c201SDavid VomLehn 
6757b0c342fSNikita Danilov 	mpi_state = hw_atl_utils_mpi_get_state(self);
676ac70957eSIgor Russkikh 	speed = mpi_state >> HW_ATL_MPI_SPEED_SHIFT;
6777b0c342fSNikita Danilov 
6787b0c342fSNikita Danilov 	if (!speed) {
67998c4c201SDavid VomLehn 		link_status->mbps = 0U;
68098c4c201SDavid VomLehn 	} else {
6817b0c342fSNikita Danilov 		switch (speed) {
68298c4c201SDavid VomLehn 		case HAL_ATLANTIC_RATE_10G:
68398c4c201SDavid VomLehn 			link_status->mbps = 10000U;
68498c4c201SDavid VomLehn 			break;
68598c4c201SDavid VomLehn 
68698c4c201SDavid VomLehn 		case HAL_ATLANTIC_RATE_5G:
68798c4c201SDavid VomLehn 		case HAL_ATLANTIC_RATE_5GSR:
68898c4c201SDavid VomLehn 			link_status->mbps = 5000U;
68998c4c201SDavid VomLehn 			break;
69098c4c201SDavid VomLehn 
69198c4c201SDavid VomLehn 		case HAL_ATLANTIC_RATE_2GS:
69298c4c201SDavid VomLehn 			link_status->mbps = 2500U;
69398c4c201SDavid VomLehn 			break;
69498c4c201SDavid VomLehn 
69598c4c201SDavid VomLehn 		case HAL_ATLANTIC_RATE_1G:
69698c4c201SDavid VomLehn 			link_status->mbps = 1000U;
69798c4c201SDavid VomLehn 			break;
69898c4c201SDavid VomLehn 
69998c4c201SDavid VomLehn 		case HAL_ATLANTIC_RATE_100M:
70098c4c201SDavid VomLehn 			link_status->mbps = 100U;
70198c4c201SDavid VomLehn 			break;
70298c4c201SDavid VomLehn 
70398c4c201SDavid VomLehn 		default:
704a7bb1beaSIgor Russkikh 			return -EBUSY;
70598c4c201SDavid VomLehn 		}
70698c4c201SDavid VomLehn 	}
70798c4c201SDavid VomLehn 
70898c4c201SDavid VomLehn 	return 0;
70998c4c201SDavid VomLehn }
71098c4c201SDavid VomLehn 
71198c4c201SDavid VomLehn int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self,
71298c4c201SDavid VomLehn 				   u8 *mac)
71398c4c201SDavid VomLehn {
7147b0c342fSNikita Danilov 	u32 mac_addr[2];
7157b0c342fSNikita Danilov 	u32 efuse_addr;
71698c4c201SDavid VomLehn 	int err = 0;
71798c4c201SDavid VomLehn 	u32 h = 0U;
71898c4c201SDavid VomLehn 	u32 l = 0U;
71998c4c201SDavid VomLehn 
72098c4c201SDavid VomLehn 	if (!aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) {
72198c4c201SDavid VomLehn 		unsigned int ucp_0x370 = 0;
7227b0c342fSNikita Danilov 		unsigned int rnd = 0;
72398c4c201SDavid VomLehn 
72498c4c201SDavid VomLehn 		get_random_bytes(&rnd, sizeof(unsigned int));
72598c4c201SDavid VomLehn 
72698c4c201SDavid VomLehn 		ucp_0x370 = 0x02020202 | (0xFEFEFEFE & rnd);
72798c4c201SDavid VomLehn 		aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
72898c4c201SDavid VomLehn 	}
72998c4c201SDavid VomLehn 
7307b0c342fSNikita Danilov 	efuse_addr = aq_hw_read_reg(self, 0x00000374U);
7317b0c342fSNikita Danilov 
7327b0c342fSNikita Danilov 	err = hw_atl_utils_fw_downld_dwords(self, efuse_addr + (40U * 4U),
7337b0c342fSNikita Danilov 					    mac_addr, ARRAY_SIZE(mac_addr));
73498c4c201SDavid VomLehn 	if (err < 0) {
73598c4c201SDavid VomLehn 		mac_addr[0] = 0U;
73698c4c201SDavid VomLehn 		mac_addr[1] = 0U;
73798c4c201SDavid VomLehn 		err = 0;
73898c4c201SDavid VomLehn 	} else {
73998c4c201SDavid VomLehn 		mac_addr[0] = __swab32(mac_addr[0]);
74098c4c201SDavid VomLehn 		mac_addr[1] = __swab32(mac_addr[1]);
74198c4c201SDavid VomLehn 	}
74298c4c201SDavid VomLehn 
74398c4c201SDavid VomLehn 	ether_addr_copy(mac, (u8 *)mac_addr);
74498c4c201SDavid VomLehn 
74598c4c201SDavid VomLehn 	if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) {
74698c4c201SDavid VomLehn 		/* chip revision */
747e9157848SNikita Danilov 		l = 0xE3000000U |
748e9157848SNikita Danilov 		    (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) |
749e9157848SNikita Danilov 		    (0x00 << 16);
75098c4c201SDavid VomLehn 		h = 0x8001300EU;
75198c4c201SDavid VomLehn 
75298c4c201SDavid VomLehn 		mac[5] = (u8)(0xFFU & l);
75398c4c201SDavid VomLehn 		l >>= 8;
75498c4c201SDavid VomLehn 		mac[4] = (u8)(0xFFU & l);
75598c4c201SDavid VomLehn 		l >>= 8;
75698c4c201SDavid VomLehn 		mac[3] = (u8)(0xFFU & l);
75798c4c201SDavid VomLehn 		l >>= 8;
75898c4c201SDavid VomLehn 		mac[2] = (u8)(0xFFU & l);
75998c4c201SDavid VomLehn 		mac[1] = (u8)(0xFFU & h);
76098c4c201SDavid VomLehn 		h >>= 8;
76198c4c201SDavid VomLehn 		mac[0] = (u8)(0xFFU & h);
76298c4c201SDavid VomLehn 	}
76398c4c201SDavid VomLehn 
76498c4c201SDavid VomLehn 	return err;
76598c4c201SDavid VomLehn }
76698c4c201SDavid VomLehn 
76798c4c201SDavid VomLehn unsigned int hw_atl_utils_mbps_2_speed_index(unsigned int mbps)
76898c4c201SDavid VomLehn {
76998c4c201SDavid VomLehn 	unsigned int ret = 0U;
77098c4c201SDavid VomLehn 
77198c4c201SDavid VomLehn 	switch (mbps) {
77298c4c201SDavid VomLehn 	case 100U:
77398c4c201SDavid VomLehn 		ret = 5U;
77498c4c201SDavid VomLehn 		break;
77598c4c201SDavid VomLehn 
77698c4c201SDavid VomLehn 	case 1000U:
77798c4c201SDavid VomLehn 		ret = 4U;
77898c4c201SDavid VomLehn 		break;
77998c4c201SDavid VomLehn 
78098c4c201SDavid VomLehn 	case 2500U:
78198c4c201SDavid VomLehn 		ret = 3U;
78298c4c201SDavid VomLehn 		break;
78398c4c201SDavid VomLehn 
78498c4c201SDavid VomLehn 	case 5000U:
78598c4c201SDavid VomLehn 		ret = 1U;
78698c4c201SDavid VomLehn 		break;
78798c4c201SDavid VomLehn 
78898c4c201SDavid VomLehn 	case 10000U:
78998c4c201SDavid VomLehn 		ret = 0U;
79098c4c201SDavid VomLehn 		break;
79198c4c201SDavid VomLehn 
79298c4c201SDavid VomLehn 	default:
79398c4c201SDavid VomLehn 		break;
79498c4c201SDavid VomLehn 	}
7957b0c342fSNikita Danilov 
79698c4c201SDavid VomLehn 	return ret;
79798c4c201SDavid VomLehn }
79898c4c201SDavid VomLehn 
79998c4c201SDavid VomLehn void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p)
80098c4c201SDavid VomLehn {
8018e1c072fSIgor Russkikh 	u32 val = hw_atl_reg_glb_mif_id_get(self);
80298c4c201SDavid VomLehn 	u32 mif_rev = val & 0xFFU;
8037b0c342fSNikita Danilov 	u32 chip_features = 0U;
80498c4c201SDavid VomLehn 
805d1ad88feSMark Starovoytov 	chip_features |= ATL_HW_CHIP_ATLANTIC;
806d1ad88feSMark Starovoytov 
80747203b34SIgor Russkikh 	if ((0xFU & mif_rev) == 1U) {
808d1ad88feSMark Starovoytov 		chip_features |= ATL_HW_CHIP_REVISION_A0 |
809d1ad88feSMark Starovoytov 			ATL_HW_CHIP_MPI_AQ |
810d1ad88feSMark Starovoytov 			ATL_HW_CHIP_MIPS;
81147203b34SIgor Russkikh 	} else if ((0xFU & mif_rev) == 2U) {
812d1ad88feSMark Starovoytov 		chip_features |= ATL_HW_CHIP_REVISION_B0 |
813d1ad88feSMark Starovoytov 			ATL_HW_CHIP_MPI_AQ |
814d1ad88feSMark Starovoytov 			ATL_HW_CHIP_MIPS |
815d1ad88feSMark Starovoytov 			ATL_HW_CHIP_TPO2 |
816d1ad88feSMark Starovoytov 			ATL_HW_CHIP_RPF2;
81747203b34SIgor Russkikh 	} else if ((0xFU & mif_rev) == 0xAU) {
818d1ad88feSMark Starovoytov 		chip_features |= ATL_HW_CHIP_REVISION_B1 |
819d1ad88feSMark Starovoytov 			ATL_HW_CHIP_MPI_AQ |
820d1ad88feSMark Starovoytov 			ATL_HW_CHIP_MIPS |
821d1ad88feSMark Starovoytov 			ATL_HW_CHIP_TPO2 |
822d1ad88feSMark Starovoytov 			ATL_HW_CHIP_RPF2;
82398c4c201SDavid VomLehn 	}
82498c4c201SDavid VomLehn 
82598c4c201SDavid VomLehn 	*p = chip_features;
82698c4c201SDavid VomLehn }
82798c4c201SDavid VomLehn 
82844e00dd8SIgor Russkikh static int hw_atl_fw1x_deinit(struct aq_hw_s *self)
82998c4c201SDavid VomLehn {
83044e00dd8SIgor Russkikh 	hw_atl_utils_mpi_set_speed(self, 0);
83144e00dd8SIgor Russkikh 	hw_atl_utils_mpi_set_state(self, MPI_DEINIT);
8327b0c342fSNikita Danilov 
83398c4c201SDavid VomLehn 	return 0;
83498c4c201SDavid VomLehn }
83598c4c201SDavid VomLehn 
83665e665e6SIgor Russkikh int hw_atl_utils_update_stats(struct aq_hw_s *self)
83765e665e6SIgor Russkikh {
838ce4cdbe4SDmitry Bogdanov 	struct aq_stats_s *cs = &self->curr_stats;
8397b0c342fSNikita Danilov 	struct hw_atl_utils_mbox mbox;
84065e665e6SIgor Russkikh 
84165e665e6SIgor Russkikh 	hw_atl_utils_mpi_read_stats(self, &mbox);
84265e665e6SIgor Russkikh 
8431a713f87SIgor Russkikh #define AQ_SDELTA(_N_) (self->curr_stats._N_ += \
8441a713f87SIgor Russkikh 			mbox.stats._N_ - self->last_stats._N_)
8451a713f87SIgor Russkikh 
846be08d839SIgor Russkikh 	if (self->aq_link_status.mbps) {
84765e665e6SIgor Russkikh 		AQ_SDELTA(uprc);
84865e665e6SIgor Russkikh 		AQ_SDELTA(mprc);
84965e665e6SIgor Russkikh 		AQ_SDELTA(bprc);
85065e665e6SIgor Russkikh 		AQ_SDELTA(erpt);
85165e665e6SIgor Russkikh 
85265e665e6SIgor Russkikh 		AQ_SDELTA(uptc);
85365e665e6SIgor Russkikh 		AQ_SDELTA(mptc);
85465e665e6SIgor Russkikh 		AQ_SDELTA(bptc);
85565e665e6SIgor Russkikh 		AQ_SDELTA(erpr);
85665e665e6SIgor Russkikh 
85765e665e6SIgor Russkikh 		AQ_SDELTA(ubrc);
85865e665e6SIgor Russkikh 		AQ_SDELTA(ubtc);
85965e665e6SIgor Russkikh 		AQ_SDELTA(mbrc);
86065e665e6SIgor Russkikh 		AQ_SDELTA(mbtc);
86165e665e6SIgor Russkikh 		AQ_SDELTA(bbrc);
86265e665e6SIgor Russkikh 		AQ_SDELTA(bbtc);
86365e665e6SIgor Russkikh 		AQ_SDELTA(dpc);
864be08d839SIgor Russkikh 	}
86565e665e6SIgor Russkikh #undef AQ_SDELTA
866ce4cdbe4SDmitry Bogdanov 
867ce4cdbe4SDmitry Bogdanov 	cs->dma_pkt_rc = hw_atl_stats_rx_dma_good_pkt_counter_get(self);
868ce4cdbe4SDmitry Bogdanov 	cs->dma_pkt_tc = hw_atl_stats_tx_dma_good_pkt_counter_get(self);
869ce4cdbe4SDmitry Bogdanov 	cs->dma_oct_rc = hw_atl_stats_rx_dma_good_octet_counter_get(self);
870ce4cdbe4SDmitry Bogdanov 	cs->dma_oct_tc = hw_atl_stats_tx_dma_good_octet_counter_get(self);
87165e665e6SIgor Russkikh 
8721a713f87SIgor Russkikh 	memcpy(&self->last_stats, &mbox.stats, sizeof(mbox.stats));
87365e665e6SIgor Russkikh 
87465e665e6SIgor Russkikh 	return 0;
87565e665e6SIgor Russkikh }
87665e665e6SIgor Russkikh 
877be08d839SIgor Russkikh struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self)
87898c4c201SDavid VomLehn {
8791a713f87SIgor Russkikh 	return &self->curr_stats;
88098c4c201SDavid VomLehn }
88198c4c201SDavid VomLehn 
88298c4c201SDavid VomLehn static const u32 hw_atl_utils_hw_mac_regs[] = {
88398c4c201SDavid VomLehn 	0x00005580U, 0x00005590U, 0x000055B0U, 0x000055B4U,
88498c4c201SDavid VomLehn 	0x000055C0U, 0x00005B00U, 0x00005B04U, 0x00005B08U,
88598c4c201SDavid VomLehn 	0x00005B0CU, 0x00005B10U, 0x00005B14U, 0x00005B18U,
88698c4c201SDavid VomLehn 	0x00005B1CU, 0x00005B20U, 0x00005B24U, 0x00005B28U,
88798c4c201SDavid VomLehn 	0x00005B2CU, 0x00005B30U, 0x00005B34U, 0x00005B38U,
88898c4c201SDavid VomLehn 	0x00005B3CU, 0x00005B40U, 0x00005B44U, 0x00005B48U,
88998c4c201SDavid VomLehn 	0x00005B4CU, 0x00005B50U, 0x00005B54U, 0x00005B58U,
89098c4c201SDavid VomLehn 	0x00005B5CU, 0x00005B60U, 0x00005B64U, 0x00005B68U,
89198c4c201SDavid VomLehn 	0x00005B6CU, 0x00005B70U, 0x00005B74U, 0x00005B78U,
89298c4c201SDavid VomLehn 	0x00005B7CU, 0x00007C00U, 0x00007C04U, 0x00007C08U,
89398c4c201SDavid VomLehn 	0x00007C0CU, 0x00007C10U, 0x00007C14U, 0x00007C18U,
89498c4c201SDavid VomLehn 	0x00007C1CU, 0x00007C20U, 0x00007C40U, 0x00007C44U,
89598c4c201SDavid VomLehn 	0x00007C48U, 0x00007C4CU, 0x00007C50U, 0x00007C54U,
89698c4c201SDavid VomLehn 	0x00007C58U, 0x00007C5CU, 0x00007C60U, 0x00007C80U,
89798c4c201SDavid VomLehn 	0x00007C84U, 0x00007C88U, 0x00007C8CU, 0x00007C90U,
89898c4c201SDavid VomLehn 	0x00007C94U, 0x00007C98U, 0x00007C9CU, 0x00007CA0U,
89998c4c201SDavid VomLehn 	0x00007CC0U, 0x00007CC4U, 0x00007CC8U, 0x00007CCCU,
90098c4c201SDavid VomLehn 	0x00007CD0U, 0x00007CD4U, 0x00007CD8U, 0x00007CDCU,
90198c4c201SDavid VomLehn 	0x00007CE0U, 0x00000300U, 0x00000304U, 0x00000308U,
90298c4c201SDavid VomLehn 	0x0000030cU, 0x00000310U, 0x00000314U, 0x00000318U,
90398c4c201SDavid VomLehn 	0x0000031cU, 0x00000360U, 0x00000364U, 0x00000368U,
90498c4c201SDavid VomLehn 	0x0000036cU, 0x00000370U, 0x00000374U, 0x00006900U,
90598c4c201SDavid VomLehn };
90698c4c201SDavid VomLehn 
90798c4c201SDavid VomLehn int hw_atl_utils_hw_get_regs(struct aq_hw_s *self,
9084cbc9f92SIgor Russkikh 			     const struct aq_hw_caps_s *aq_hw_caps,
90998c4c201SDavid VomLehn 			     u32 *regs_buff)
91098c4c201SDavid VomLehn {
91198c4c201SDavid VomLehn 	unsigned int i = 0U;
91298c4c201SDavid VomLehn 
91398c4c201SDavid VomLehn 	for (i = 0; i < aq_hw_caps->mac_regs_count; i++)
91498c4c201SDavid VomLehn 		regs_buff[i] = aq_hw_read_reg(self,
91598c4c201SDavid VomLehn 					      hw_atl_utils_hw_mac_regs[i]);
9167b0c342fSNikita Danilov 
91798c4c201SDavid VomLehn 	return 0;
91898c4c201SDavid VomLehn }
91998c4c201SDavid VomLehn 
92036e90a52SNikita Danilov u32 hw_atl_utils_get_fw_version(struct aq_hw_s *self)
92198c4c201SDavid VomLehn {
92236e90a52SNikita Danilov 	return aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION);
92398c4c201SDavid VomLehn }
9240c58c35fSIgor Russkikh 
925837c6378SNikita Danilov static int aq_fw1x_set_wake_magic(struct aq_hw_s *self, bool wol_enabled,
926837c6378SNikita Danilov 				  u8 *mac)
927a0da96c0SYana Esina {
9288f60f762SNikita Danilov 	struct hw_atl_utils_fw_rpc *prpc = NULL;
929a0da96c0SYana Esina 	unsigned int rpc_size = 0U;
930a0da96c0SYana Esina 	int err = 0;
931a0da96c0SYana Esina 
932a0da96c0SYana Esina 	err = hw_atl_utils_fw_rpc_wait(self, &prpc);
933a0da96c0SYana Esina 	if (err < 0)
934a0da96c0SYana Esina 		goto err_exit;
935a0da96c0SYana Esina 
936a0da96c0SYana Esina 	memset(prpc, 0, sizeof(*prpc));
937a0da96c0SYana Esina 
938a0da96c0SYana Esina 	if (wol_enabled) {
939d993e14bSNikita Danilov 		rpc_size = offsetof(struct hw_atl_utils_fw_rpc, msg_wol_add) +
940d993e14bSNikita Danilov 			   sizeof(prpc->msg_wol_add);
941d993e14bSNikita Danilov 
942a0da96c0SYana Esina 
943a0da96c0SYana Esina 		prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD;
944d993e14bSNikita Danilov 		prpc->msg_wol_add.priority =
945a0da96c0SYana Esina 				HAL_ATLANTIC_UTILS_FW_MSG_WOL_PRIOR;
946d993e14bSNikita Danilov 		prpc->msg_wol_add.pattern_id =
947a0da96c0SYana Esina 				HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN;
948d993e14bSNikita Danilov 		prpc->msg_wol_add.packet_type =
949a0da96c0SYana Esina 				HAL_ATLANTIC_UTILS_FW_MSG_WOL_MAG_PKT;
950a0da96c0SYana Esina 
951d993e14bSNikita Danilov 		ether_addr_copy((u8 *)&prpc->msg_wol_add.magic_packet_pattern,
952d993e14bSNikita Danilov 				mac);
953a0da96c0SYana Esina 	} else {
954d993e14bSNikita Danilov 		rpc_size = sizeof(prpc->msg_wol_remove) +
955d993e14bSNikita Danilov 			   offsetof(struct hw_atl_utils_fw_rpc, msg_wol_remove);
956a0da96c0SYana Esina 
957a0da96c0SYana Esina 		prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL;
958d993e14bSNikita Danilov 		prpc->msg_wol_add.pattern_id =
959a0da96c0SYana Esina 				HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN;
960a0da96c0SYana Esina 	}
961a0da96c0SYana Esina 
962a0da96c0SYana Esina 	err = hw_atl_utils_fw_rpc_call(self, rpc_size);
963a0da96c0SYana Esina 
964a0da96c0SYana Esina err_exit:
965a0da96c0SYana Esina 	return err;
966a0da96c0SYana Esina }
967a0da96c0SYana Esina 
9683d5537f9SWei Yongjun static int aq_fw1x_set_power(struct aq_hw_s *self, unsigned int power_state,
969a0da96c0SYana Esina 			     u8 *mac)
970a0da96c0SYana Esina {
9718f60f762SNikita Danilov 	struct hw_atl_utils_fw_rpc *prpc = NULL;
972a0da96c0SYana Esina 	unsigned int rpc_size = 0U;
973a0da96c0SYana Esina 	int err = 0;
974a0da96c0SYana Esina 
975837c6378SNikita Danilov 	if (self->aq_nic_cfg->wol & WAKE_MAGIC) {
976837c6378SNikita Danilov 		err = aq_fw1x_set_wake_magic(self, 1, mac);
977a0da96c0SYana Esina 
978a0da96c0SYana Esina 		if (err < 0)
979a0da96c0SYana Esina 			goto err_exit;
980a0da96c0SYana Esina 
981a0da96c0SYana Esina 		rpc_size = sizeof(prpc->msg_id) +
982a0da96c0SYana Esina 			   sizeof(prpc->msg_enable_wakeup);
983a0da96c0SYana Esina 
984a0da96c0SYana Esina 		err = hw_atl_utils_fw_rpc_wait(self, &prpc);
985a0da96c0SYana Esina 
986a0da96c0SYana Esina 		if (err < 0)
987a0da96c0SYana Esina 			goto err_exit;
988a0da96c0SYana Esina 
989a0da96c0SYana Esina 		memset(prpc, 0, rpc_size);
990a0da96c0SYana Esina 
991a0da96c0SYana Esina 		prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP;
992a0da96c0SYana Esina 		prpc->msg_enable_wakeup.pattern_mask = 0x00000002;
993a0da96c0SYana Esina 
994a0da96c0SYana Esina 		err = hw_atl_utils_fw_rpc_call(self, rpc_size);
995a0da96c0SYana Esina 		if (err < 0)
996a0da96c0SYana Esina 			goto err_exit;
997a0da96c0SYana Esina 	}
998a0da96c0SYana Esina 	hw_atl_utils_mpi_set_speed(self, 0);
999a0da96c0SYana Esina 	hw_atl_utils_mpi_set_state(self, MPI_POWER);
1000a0da96c0SYana Esina 
1001a0da96c0SYana Esina err_exit:
1002a0da96c0SYana Esina 	return err;
1003a0da96c0SYana Esina }
1004a0da96c0SYana Esina 
10056a7f2277SNikita Danilov static u32 hw_atl_utils_get_mpi_mbox_tid(struct aq_hw_s *self)
10066a7f2277SNikita Danilov {
10076a7f2277SNikita Danilov 	struct hw_atl_utils_mbox_header mbox;
10086a7f2277SNikita Danilov 
10096a7f2277SNikita Danilov 	hw_atl_utils_mpi_read_mbox(self, &mbox);
10106a7f2277SNikita Danilov 
10116a7f2277SNikita Danilov 	return mbox.transaction_id;
10126a7f2277SNikita Danilov }
10136a7f2277SNikita Danilov 
10146a7f2277SNikita Danilov static u32 hw_atl_utils_mpi_get_state(struct aq_hw_s *self)
10156a7f2277SNikita Danilov {
10166a7f2277SNikita Danilov 	return aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR);
10176a7f2277SNikita Danilov }
10186a7f2277SNikita Danilov 
10196a7f2277SNikita Danilov static u32 hw_atl_utils_mif_cmd_get(struct aq_hw_s *self)
10206a7f2277SNikita Danilov {
10216a7f2277SNikita Danilov 	return aq_hw_read_reg(self, HW_ATL_MIF_CMD);
10226a7f2277SNikita Danilov }
10236a7f2277SNikita Danilov 
10246a7f2277SNikita Danilov static u32 hw_atl_utils_mif_addr_get(struct aq_hw_s *self)
10256a7f2277SNikita Danilov {
10266a7f2277SNikita Danilov 	return aq_hw_read_reg(self, HW_ATL_MIF_ADDR);
10276a7f2277SNikita Danilov }
10286a7f2277SNikita Danilov 
10296a7f2277SNikita Danilov static u32 hw_atl_utils_rpc_state_get(struct aq_hw_s *self)
10306a7f2277SNikita Danilov {
10316a7f2277SNikita Danilov 	return aq_hw_read_reg(self, HW_ATL_RPC_STATE_ADR);
10326a7f2277SNikita Danilov }
10336a7f2277SNikita Danilov 
1034e7b5f97eSIgor Russkikh static u32 aq_fw1x_rpc_get(struct aq_hw_s *self)
1035e7b5f97eSIgor Russkikh {
1036e7b5f97eSIgor Russkikh 	return aq_hw_read_reg(self, HW_ATL_MPI_RPC_ADDR);
1037e7b5f97eSIgor Russkikh }
1038e7b5f97eSIgor Russkikh 
10390c58c35fSIgor Russkikh const struct aq_fw_ops aq_fw_1x_ops = {
10400c58c35fSIgor Russkikh 	.init = hw_atl_utils_mpi_create,
104144e00dd8SIgor Russkikh 	.deinit = hw_atl_fw1x_deinit,
10420c58c35fSIgor Russkikh 	.reset = NULL,
10430c58c35fSIgor Russkikh 	.get_mac_permanent = hw_atl_utils_get_mac_permanent,
10440c58c35fSIgor Russkikh 	.set_link_speed = hw_atl_utils_mpi_set_speed,
10450c58c35fSIgor Russkikh 	.set_state = hw_atl_utils_mpi_set_state,
10460c58c35fSIgor Russkikh 	.update_link_status = hw_atl_utils_mpi_get_link_status,
10470c58c35fSIgor Russkikh 	.update_stats = hw_atl_utils_update_stats,
10488f894011SYana Esina 	.get_phy_temp = NULL,
1049a0da96c0SYana Esina 	.set_power = aq_fw1x_set_power,
105092ab6407SYana Esina 	.set_eee_rate = NULL,
105192ab6407SYana Esina 	.get_eee_rate = NULL,
1052288551deSIgor Russkikh 	.set_flow_control = NULL,
1053910479a9SEgor Pomozov 	.send_fw_request = NULL,
1054910479a9SEgor Pomozov 	.enable_ptp = NULL,
1055d1287ce4SNikita Danilov 	.led_control = NULL,
10560c58c35fSIgor Russkikh };
1057