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
490044b1e1SDmitry Bogdanov #define HW_ATL_FW_VER_4X 0x04000000U
500c58c35fSIgor Russkikh
51c8c82eb3SIgor Russkikh #define FORCE_FLASHLESS 0
52c8c82eb3SIgor Russkikh
53dc12f75aSNikita Danilov enum mcp_area {
54dc12f75aSNikita Danilov MCP_AREA_CONFIG = 0x80000000,
55dc12f75aSNikita Danilov MCP_AREA_SETTINGS = 0x20000000,
56dc12f75aSNikita Danilov };
57dc12f75aSNikita Danilov
58cce96d18SIgor Russkikh static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
59cce96d18SIgor Russkikh enum hal_atl_utils_fw_state_e state);
606a7f2277SNikita Danilov static u32 hw_atl_utils_get_mpi_mbox_tid(struct aq_hw_s *self);
616a7f2277SNikita Danilov static u32 hw_atl_utils_mpi_get_state(struct aq_hw_s *self);
626a7f2277SNikita Danilov static u32 hw_atl_utils_mif_cmd_get(struct aq_hw_s *self);
636a7f2277SNikita Danilov static u32 hw_atl_utils_mif_addr_get(struct aq_hw_s *self);
646a7f2277SNikita Danilov static u32 hw_atl_utils_rpc_state_get(struct aq_hw_s *self);
65e7b5f97eSIgor Russkikh static u32 aq_fw1x_rpc_get(struct aq_hw_s *self);
666a7f2277SNikita Danilov
hw_atl_utils_initfw(struct aq_hw_s * self,const struct aq_fw_ops ** fw_ops)670c58c35fSIgor Russkikh int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
680c58c35fSIgor Russkikh {
690c58c35fSIgor Russkikh int err = 0;
700c58c35fSIgor Russkikh
710c58c35fSIgor Russkikh hw_atl_utils_hw_chip_features_init(self,
720c58c35fSIgor Russkikh &self->chip_features);
730c58c35fSIgor Russkikh
7436e90a52SNikita Danilov self->fw_ver_actual = hw_atl_utils_get_fw_version(self);
750c58c35fSIgor Russkikh
76b567edbfSMark Starovoytov if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, self->fw_ver_actual)) {
770c58c35fSIgor Russkikh *fw_ops = &aq_fw_1x_ops;
78b567edbfSMark Starovoytov } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X, self->fw_ver_actual)) {
79a57d3929SIgor Russkikh *fw_ops = &aq_fw_2x_ops;
80b567edbfSMark Starovoytov } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X, self->fw_ver_actual)) {
81a57d3929SIgor Russkikh *fw_ops = &aq_fw_2x_ops;
820044b1e1SDmitry Bogdanov } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_4X, self->fw_ver_actual)) {
830044b1e1SDmitry Bogdanov *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
hw_atl_utils_soft_reset_flb(struct aq_hw_s * self)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
hw_atl_utils_soft_reset_rbl(struct aq_hw_s * self)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");
220e35df218SMark Starovoytov return -EOPNOTSUPP;
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
hw_atl_utils_soft_reset(struct aq_hw_s * self)240c8c82eb3SIgor Russkikh int hw_atl_utils_soft_reset(struct aq_hw_s *self)
241c8c82eb3SIgor Russkikh {
2420044b1e1SDmitry Bogdanov int ver = hw_atl_utils_get_fw_version(self);
243c8c82eb3SIgor Russkikh u32 boot_exit_code = 0;
2446a7f2277SNikita Danilov u32 val;
2457b0c342fSNikita Danilov int k;
246c8c82eb3SIgor Russkikh
247c8c82eb3SIgor Russkikh for (k = 0; k < 1000; ++k) {
248c8c82eb3SIgor Russkikh u32 flb_status = aq_hw_read_reg(self,
249c8c82eb3SIgor Russkikh HW_ATL_MPI_DAISY_CHAIN_STATUS);
250c8c82eb3SIgor Russkikh boot_exit_code = aq_hw_read_reg(self,
251c8c82eb3SIgor Russkikh HW_ATL_MPI_BOOT_EXIT_CODE);
252c8c82eb3SIgor Russkikh if (flb_status != 0x06000000 || boot_exit_code != 0)
253c8c82eb3SIgor Russkikh break;
254c8c82eb3SIgor Russkikh }
255c8c82eb3SIgor Russkikh
256c8c82eb3SIgor Russkikh if (k == 1000) {
257c8c82eb3SIgor Russkikh aq_pr_err("Neither RBL nor FLB firmware started\n");
258c8c82eb3SIgor Russkikh return -EOPNOTSUPP;
259c8c82eb3SIgor Russkikh }
260c8c82eb3SIgor Russkikh
261c8c82eb3SIgor Russkikh self->rbl_enabled = (boot_exit_code != 0);
262c8c82eb3SIgor Russkikh
2630044b1e1SDmitry Bogdanov if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, ver)) {
2640044b1e1SDmitry Bogdanov int err = 0;
2650044b1e1SDmitry Bogdanov
266cce96d18SIgor Russkikh /* FW 1.x may bootup in an invalid POWER state (WOL feature).
267cce96d18SIgor Russkikh * We should work around this by forcing its state back to DEINIT
268cce96d18SIgor Russkikh */
269cce96d18SIgor Russkikh hw_atl_utils_mpi_set_state(self, MPI_DEINIT);
2706a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_mpi_get_state,
2716a7f2277SNikita Danilov self, val,
2726a7f2277SNikita Danilov (val & HW_ATL_MPI_STATE_MSK) ==
2736a7f2277SNikita Danilov MPI_DEINIT,
2746a7f2277SNikita Danilov 10, 10000U);
2754e3c7c00SYueHaibing if (err)
2764e3c7c00SYueHaibing return err;
2770044b1e1SDmitry Bogdanov } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_4X, ver)) {
2780044b1e1SDmitry Bogdanov u64 sem_timeout = aq_hw_read_reg(self, HW_ATL_MIF_RESET_TIMEOUT_ADR);
2790044b1e1SDmitry Bogdanov
2800044b1e1SDmitry Bogdanov /* Acquire 2 semaphores before issuing reset for FW 4.x */
2810044b1e1SDmitry Bogdanov if (sem_timeout > 3000)
2820044b1e1SDmitry Bogdanov sem_timeout = 3000;
2830044b1e1SDmitry Bogdanov sem_timeout = sem_timeout * 1000;
2840044b1e1SDmitry Bogdanov
2850044b1e1SDmitry Bogdanov if (sem_timeout != 0) {
2860044b1e1SDmitry Bogdanov int err;
2870044b1e1SDmitry Bogdanov
2880044b1e1SDmitry Bogdanov err = readx_poll_timeout_atomic(hw_atl_sem_reset1_get, self, val,
2890044b1e1SDmitry Bogdanov val == 1U, 1U, sem_timeout);
2900044b1e1SDmitry Bogdanov if (err)
2910044b1e1SDmitry Bogdanov aq_pr_err("reset sema1 timeout");
2920044b1e1SDmitry Bogdanov
2930044b1e1SDmitry Bogdanov err = readx_poll_timeout_atomic(hw_atl_sem_reset2_get, self, val,
2940044b1e1SDmitry Bogdanov val == 1U, 1U, sem_timeout);
2950044b1e1SDmitry Bogdanov if (err)
2960044b1e1SDmitry Bogdanov aq_pr_err("reset sema2 timeout");
2970044b1e1SDmitry Bogdanov }
298cce96d18SIgor Russkikh }
299cce96d18SIgor Russkikh
300c8c82eb3SIgor Russkikh if (self->rbl_enabled)
301c8c82eb3SIgor Russkikh return hw_atl_utils_soft_reset_rbl(self);
302c8c82eb3SIgor Russkikh else
303c8c82eb3SIgor Russkikh return hw_atl_utils_soft_reset_flb(self);
304c8c82eb3SIgor Russkikh }
305c8c82eb3SIgor Russkikh
hw_atl_utils_fw_downld_dwords(struct aq_hw_s * self,u32 a,u32 * p,u32 cnt)306a57d3929SIgor Russkikh int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
30798c4c201SDavid VomLehn u32 *p, u32 cnt)
30898c4c201SDavid VomLehn {
30998c4c201SDavid VomLehn int err = 0;
3106a7f2277SNikita Danilov u32 val;
31198c4c201SDavid VomLehn
3126a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_sem_ram_get,
3136a7f2277SNikita Danilov self, val, val == 1U,
31498c4c201SDavid VomLehn 1U, 10000U);
31598c4c201SDavid VomLehn
31698c4c201SDavid VomLehn if (err < 0) {
31798c4c201SDavid VomLehn bool is_locked;
31898c4c201SDavid VomLehn
3198e1c072fSIgor Russkikh hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
3200b926d46SNikita Danilov is_locked = hw_atl_sem_ram_get(self);
32198c4c201SDavid VomLehn if (!is_locked) {
32298c4c201SDavid VomLehn err = -ETIME;
32398c4c201SDavid VomLehn goto err_exit;
32498c4c201SDavid VomLehn }
32598c4c201SDavid VomLehn }
32698c4c201SDavid VomLehn
32747203b34SIgor Russkikh aq_hw_write_reg(self, HW_ATL_MIF_ADDR, a);
32898c4c201SDavid VomLehn
32947203b34SIgor Russkikh for (++cnt; --cnt && !err;) {
33047203b34SIgor Russkikh aq_hw_write_reg(self, HW_ATL_MIF_CMD, 0x00008000U);
33198c4c201SDavid VomLehn
332d1ad88feSMark Starovoytov if (ATL_HW_IS_CHIP_FEATURE(self, REVISION_B1))
3336a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_mif_addr_get,
3346a7f2277SNikita Danilov self, val, val != a,
3356a7f2277SNikita Danilov 1U, 1000U);
33647203b34SIgor Russkikh else
3376a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_mif_cmd_get,
3386a7f2277SNikita Danilov self, val,
3396a7f2277SNikita Danilov !(val & 0x100),
3406a7f2277SNikita Danilov 1U, 1000U);
34198c4c201SDavid VomLehn
34247203b34SIgor Russkikh *(p++) = aq_hw_read_reg(self, HW_ATL_MIF_VAL);
34347203b34SIgor Russkikh a += 4;
34498c4c201SDavid VomLehn }
34598c4c201SDavid VomLehn
3468e1c072fSIgor Russkikh hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
34798c4c201SDavid VomLehn
34898c4c201SDavid VomLehn err_exit:
34998c4c201SDavid VomLehn return err;
35098c4c201SDavid VomLehn }
35198c4c201SDavid VomLehn
hw_atl_utils_write_b1_mbox(struct aq_hw_s * self,u32 addr,u32 * p,u32 cnt,enum mcp_area area)352dc12f75aSNikita Danilov static int hw_atl_utils_write_b1_mbox(struct aq_hw_s *self, u32 addr,
353dc12f75aSNikita Danilov u32 *p, u32 cnt, enum mcp_area area)
35498c4c201SDavid VomLehn {
355dc12f75aSNikita Danilov u32 data_offset = 0;
356dc12f75aSNikita Danilov u32 offset = addr;
35798c4c201SDavid VomLehn int err = 0;
358dc12f75aSNikita Danilov u32 val;
35998c4c201SDavid VomLehn
360dc12f75aSNikita Danilov switch (area) {
361dc12f75aSNikita Danilov case MCP_AREA_CONFIG:
362dc12f75aSNikita Danilov offset -= self->rpc_addr;
363dc12f75aSNikita Danilov break;
364930b9a05SNikita Danilov
365dc12f75aSNikita Danilov case MCP_AREA_SETTINGS:
366dc12f75aSNikita Danilov offset -= self->settings_addr;
367dc12f75aSNikita Danilov break;
368dc12f75aSNikita Danilov }
36998c4c201SDavid VomLehn
370dc12f75aSNikita Danilov offset = offset / sizeof(u32);
371dc12f75aSNikita Danilov
372dc12f75aSNikita Danilov for (; data_offset < cnt; ++data_offset, ++offset) {
373dc12f75aSNikita Danilov aq_hw_write_reg(self, 0x328, p[data_offset]);
3743ee5c887SYana Esina aq_hw_write_reg(self, 0x32C,
375dc12f75aSNikita Danilov (area | (0xFFFF & (offset * 4))));
3763ee5c887SYana Esina hw_atl_mcp_up_force_intr_set(self, 1);
3773ee5c887SYana Esina /* 1000 times by 10us = 10ms */
3786a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_scrpad12_get,
3796a7f2277SNikita Danilov self, val,
380930b9a05SNikita Danilov (val & 0xF0000000) !=
381dc12f75aSNikita Danilov area,
3826a7f2277SNikita Danilov 10U, 10000U);
38398c4c201SDavid VomLehn
384dc12f75aSNikita Danilov if (err < 0)
385dc12f75aSNikita Danilov break;
386dc12f75aSNikita Danilov }
387dc12f75aSNikita Danilov
388dc12f75aSNikita Danilov return err;
389dc12f75aSNikita Danilov }
390dc12f75aSNikita Danilov
hw_atl_utils_write_b0_mbox(struct aq_hw_s * self,u32 addr,u32 * p,u32 cnt)391dc12f75aSNikita Danilov static int hw_atl_utils_write_b0_mbox(struct aq_hw_s *self, u32 addr,
392dc12f75aSNikita Danilov u32 *p, u32 cnt)
393dc12f75aSNikita Danilov {
394dc12f75aSNikita Danilov u32 offset = 0;
395dc12f75aSNikita Danilov int err = 0;
396dc12f75aSNikita Danilov u32 val;
397dc12f75aSNikita Danilov
398dc12f75aSNikita Danilov aq_hw_write_reg(self, 0x208, addr);
39998c4c201SDavid VomLehn
4003ee5c887SYana Esina for (; offset < cnt; ++offset) {
4013ee5c887SYana Esina aq_hw_write_reg(self, 0x20C, p[offset]);
4023ee5c887SYana Esina aq_hw_write_reg(self, 0x200, 0xC000);
40398c4c201SDavid VomLehn
4046a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_mif_cmd_get,
4056a7f2277SNikita Danilov self, val,
406dc12f75aSNikita Danilov (val & 0x100) == 0U,
407dc12f75aSNikita Danilov 10U, 10000U);
408dc12f75aSNikita Danilov
409dc12f75aSNikita Danilov if (err < 0)
410dc12f75aSNikita Danilov break;
41198c4c201SDavid VomLehn }
412dc12f75aSNikita Danilov
413dc12f75aSNikita Danilov return err;
41498c4c201SDavid VomLehn }
41598c4c201SDavid VomLehn
hw_atl_utils_fw_upload_dwords(struct aq_hw_s * self,u32 addr,u32 * p,u32 cnt,enum mcp_area area)416dc12f75aSNikita Danilov static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 addr, u32 *p,
417dc12f75aSNikita Danilov u32 cnt, enum mcp_area area)
418dc12f75aSNikita Danilov {
419dc12f75aSNikita Danilov int err = 0;
420dc12f75aSNikita Danilov u32 val;
421dc12f75aSNikita Danilov
422dc12f75aSNikita Danilov err = readx_poll_timeout_atomic(hw_atl_sem_ram_get, self,
423dc12f75aSNikita Danilov val, val == 1U,
424dc12f75aSNikita Danilov 10U, 100000U);
425dc12f75aSNikita Danilov if (err < 0)
426dc12f75aSNikita Danilov goto err_exit;
427dc12f75aSNikita Danilov
428d1ad88feSMark Starovoytov if (ATL_HW_IS_CHIP_FEATURE(self, REVISION_B1))
429dc12f75aSNikita Danilov err = hw_atl_utils_write_b1_mbox(self, addr, p, cnt, area);
430dc12f75aSNikita Danilov else
431dc12f75aSNikita Danilov err = hw_atl_utils_write_b0_mbox(self, addr, p, cnt);
432dc12f75aSNikita Danilov
4338e1c072fSIgor Russkikh hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
43498c4c201SDavid VomLehn
435dc12f75aSNikita Danilov if (err < 0)
436dc12f75aSNikita Danilov goto err_exit;
437dc12f75aSNikita Danilov
438dc12f75aSNikita Danilov err = aq_hw_err_from_flags(self);
439dc12f75aSNikita Danilov
44098c4c201SDavid VomLehn err_exit:
44198c4c201SDavid VomLehn return err;
44298c4c201SDavid VomLehn }
44398c4c201SDavid VomLehn
hw_atl_write_fwcfg_dwords(struct aq_hw_s * self,u32 * p,u32 cnt)444dc12f75aSNikita Danilov int hw_atl_write_fwcfg_dwords(struct aq_hw_s *self, u32 *p, u32 cnt)
445dc12f75aSNikita Danilov {
446dc12f75aSNikita Danilov return hw_atl_utils_fw_upload_dwords(self, self->rpc_addr, p,
447dc12f75aSNikita Danilov cnt, MCP_AREA_CONFIG);
448dc12f75aSNikita Danilov }
449dc12f75aSNikita Danilov
hw_atl_write_fwsettings_dwords(struct aq_hw_s * self,u32 offset,u32 * p,u32 cnt)450dc12f75aSNikita Danilov int hw_atl_write_fwsettings_dwords(struct aq_hw_s *self, u32 offset, u32 *p,
451dc12f75aSNikita Danilov u32 cnt)
452dc12f75aSNikita Danilov {
453dc12f75aSNikita Danilov return hw_atl_utils_fw_upload_dwords(self, self->settings_addr + offset,
454dc12f75aSNikita Danilov p, cnt, MCP_AREA_SETTINGS);
455dc12f75aSNikita Danilov }
456dc12f75aSNikita Danilov
hw_atl_utils_ver_match(u32 ver_expected,u32 ver_actual)457b567edbfSMark Starovoytov bool hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual)
45898c4c201SDavid VomLehn {
45998c4c201SDavid VomLehn const u32 dw_major_mask = 0xff000000U;
46098c4c201SDavid VomLehn const u32 dw_minor_mask = 0x00ffffffU;
461b567edbfSMark Starovoytov bool ver_match;
46298c4c201SDavid VomLehn
463b567edbfSMark Starovoytov ver_match = (dw_major_mask & (ver_expected ^ ver_actual)) ? false : true;
464b567edbfSMark Starovoytov if (!ver_match)
46598c4c201SDavid VomLehn goto err_exit;
466b567edbfSMark Starovoytov ver_match = ((dw_minor_mask & ver_expected) > (dw_minor_mask & ver_actual)) ?
467b567edbfSMark Starovoytov false : true;
4687b0c342fSNikita Danilov
46998c4c201SDavid VomLehn err_exit:
470b567edbfSMark Starovoytov return ver_match;
47198c4c201SDavid VomLehn }
47298c4c201SDavid VomLehn
hw_atl_utils_init_ucp(struct aq_hw_s * self,const struct aq_hw_caps_s * aq_hw_caps)47398c4c201SDavid VomLehn static int hw_atl_utils_init_ucp(struct aq_hw_s *self,
4744cbc9f92SIgor Russkikh const struct aq_hw_caps_s *aq_hw_caps)
47598c4c201SDavid VomLehn {
47698c4c201SDavid VomLehn int err = 0;
47798c4c201SDavid VomLehn
47898c4c201SDavid VomLehn if (!aq_hw_read_reg(self, 0x370U)) {
47998c4c201SDavid VomLehn unsigned int rnd = 0U;
48098c4c201SDavid VomLehn unsigned int ucp_0x370 = 0U;
48198c4c201SDavid VomLehn
48298c4c201SDavid VomLehn get_random_bytes(&rnd, sizeof(unsigned int));
48398c4c201SDavid VomLehn
48498c4c201SDavid VomLehn ucp_0x370 = 0x02020202U | (0xFEFEFEFEU & rnd);
48598c4c201SDavid VomLehn aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
48698c4c201SDavid VomLehn }
48798c4c201SDavid VomLehn
4888e1c072fSIgor Russkikh hw_atl_reg_glb_cpu_scratch_scp_set(self, 0x00000000U, 25U);
48998c4c201SDavid VomLehn
49098c4c201SDavid VomLehn /* check 10 times by 1ms */
4916a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_scrpad25_get,
4926a7f2277SNikita Danilov self, self->mbox_addr,
4936a7f2277SNikita Danilov self->mbox_addr != 0U,
4946a7f2277SNikita Danilov 1000U, 10000U);
495e7b5f97eSIgor Russkikh err = readx_poll_timeout_atomic(aq_fw1x_rpc_get, self,
496e7b5f97eSIgor Russkikh self->rpc_addr,
497e7b5f97eSIgor Russkikh self->rpc_addr != 0U,
498e7b5f97eSIgor Russkikh 1000U, 100000U);
49998c4c201SDavid VomLehn
50098c4c201SDavid VomLehn return err;
50198c4c201SDavid VomLehn }
50298c4c201SDavid VomLehn
50398c4c201SDavid VomLehn struct aq_hw_atl_utils_fw_rpc_tid_s {
50498c4c201SDavid VomLehn union {
50598c4c201SDavid VomLehn u32 val;
50698c4c201SDavid VomLehn struct {
50798c4c201SDavid VomLehn u16 tid;
50898c4c201SDavid VomLehn u16 len;
50998c4c201SDavid VomLehn };
51098c4c201SDavid VomLehn };
51198c4c201SDavid VomLehn };
51298c4c201SDavid VomLehn
51398c4c201SDavid VomLehn #define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL)
51498c4c201SDavid VomLehn
hw_atl_utils_fw_rpc_call(struct aq_hw_s * self,unsigned int rpc_size)5153ee5c887SYana Esina int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size)
51698c4c201SDavid VomLehn {
51798c4c201SDavid VomLehn struct aq_hw_atl_utils_fw_rpc_tid_s sw;
5187b0c342fSNikita Danilov int err = 0;
51998c4c201SDavid VomLehn
520d1ad88feSMark Starovoytov if (!ATL_HW_IS_CHIP_FEATURE(self, MIPS)) {
52198c4c201SDavid VomLehn err = -1;
52298c4c201SDavid VomLehn goto err_exit;
52398c4c201SDavid VomLehn }
524dc12f75aSNikita Danilov err = hw_atl_write_fwcfg_dwords(self, (u32 *)(void *)&self->rpc,
52598c4c201SDavid VomLehn (rpc_size + sizeof(u32) -
52698c4c201SDavid VomLehn sizeof(u8)) / sizeof(u32));
52798c4c201SDavid VomLehn if (err < 0)
52898c4c201SDavid VomLehn goto err_exit;
52998c4c201SDavid VomLehn
5301a713f87SIgor Russkikh sw.tid = 0xFFFFU & (++self->rpc_tid);
53198c4c201SDavid VomLehn sw.len = (u16)rpc_size;
53298c4c201SDavid VomLehn aq_hw_write_reg(self, HW_ATL_RPC_CONTROL_ADR, sw.val);
53398c4c201SDavid VomLehn
53498c4c201SDavid VomLehn err_exit:
53598c4c201SDavid VomLehn return err;
53698c4c201SDavid VomLehn }
53798c4c201SDavid VomLehn
hw_atl_utils_fw_rpc_wait(struct aq_hw_s * self,struct hw_atl_utils_fw_rpc ** rpc)5383ee5c887SYana Esina int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
5398f60f762SNikita Danilov struct hw_atl_utils_fw_rpc **rpc)
54098c4c201SDavid VomLehn {
54198c4c201SDavid VomLehn struct aq_hw_atl_utils_fw_rpc_tid_s sw;
54298c4c201SDavid VomLehn struct aq_hw_atl_utils_fw_rpc_tid_s fw;
5437b0c342fSNikita Danilov int err = 0;
54498c4c201SDavid VomLehn
54598c4c201SDavid VomLehn do {
54698c4c201SDavid VomLehn sw.val = aq_hw_read_reg(self, HW_ATL_RPC_CONTROL_ADR);
54798c4c201SDavid VomLehn
5481a713f87SIgor Russkikh self->rpc_tid = sw.tid;
54998c4c201SDavid VomLehn
5506a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_rpc_state_get,
5516a7f2277SNikita Danilov self, fw.val,
5526a7f2277SNikita Danilov sw.tid == fw.tid,
5536a7f2277SNikita Danilov 1000U, 100000U);
554e7b5f97eSIgor Russkikh if (err < 0)
555e7b5f97eSIgor Russkikh goto err_exit;
556e7b5f97eSIgor Russkikh
557e7b5f97eSIgor Russkikh err = aq_hw_err_from_flags(self);
558e7b5f97eSIgor Russkikh if (err < 0)
559e7b5f97eSIgor Russkikh goto err_exit;
56098c4c201SDavid VomLehn
56198c4c201SDavid VomLehn if (fw.len == 0xFFFFU) {
562b922f622SZekun Shen if (sw.len > sizeof(self->rpc)) {
563b922f622SZekun Shen printk(KERN_INFO "Invalid sw len: %x\n", sw.len);
564b922f622SZekun Shen err = -EINVAL;
565b922f622SZekun Shen goto err_exit;
566b922f622SZekun Shen }
56798c4c201SDavid VomLehn err = hw_atl_utils_fw_rpc_call(self, sw.len);
56898c4c201SDavid VomLehn if (err < 0)
56998c4c201SDavid VomLehn goto err_exit;
57098c4c201SDavid VomLehn }
57198c4c201SDavid VomLehn } while (sw.tid != fw.tid || 0xFFFFU == fw.len);
57298c4c201SDavid VomLehn
57398c4c201SDavid VomLehn if (rpc) {
57498c4c201SDavid VomLehn if (fw.len) {
575b922f622SZekun Shen if (fw.len > sizeof(self->rpc)) {
576b922f622SZekun Shen printk(KERN_INFO "Invalid fw len: %x\n", fw.len);
577b922f622SZekun Shen err = -EINVAL;
578b922f622SZekun Shen goto err_exit;
579b922f622SZekun Shen }
58098c4c201SDavid VomLehn err =
58198c4c201SDavid VomLehn hw_atl_utils_fw_downld_dwords(self,
5821a713f87SIgor Russkikh self->rpc_addr,
58398c4c201SDavid VomLehn (u32 *)(void *)
5841a713f87SIgor Russkikh &self->rpc,
58598c4c201SDavid VomLehn (fw.len + sizeof(u32) -
58698c4c201SDavid VomLehn sizeof(u8)) /
58798c4c201SDavid VomLehn sizeof(u32));
58898c4c201SDavid VomLehn if (err < 0)
58998c4c201SDavid VomLehn goto err_exit;
59098c4c201SDavid VomLehn }
59198c4c201SDavid VomLehn
5921a713f87SIgor Russkikh *rpc = &self->rpc;
59398c4c201SDavid VomLehn }
59498c4c201SDavid VomLehn
59598c4c201SDavid VomLehn err_exit:
59698c4c201SDavid VomLehn return err;
59798c4c201SDavid VomLehn }
59898c4c201SDavid VomLehn
hw_atl_utils_mpi_create(struct aq_hw_s * self)5991a713f87SIgor Russkikh static int hw_atl_utils_mpi_create(struct aq_hw_s *self)
60098c4c201SDavid VomLehn {
60198c4c201SDavid VomLehn int err = 0;
60298c4c201SDavid VomLehn
6031a713f87SIgor Russkikh err = hw_atl_utils_init_ucp(self, self->aq_nic_cfg->aq_hw_caps);
60498c4c201SDavid VomLehn if (err < 0)
60598c4c201SDavid VomLehn goto err_exit;
60698c4c201SDavid VomLehn
60798c4c201SDavid VomLehn err = hw_atl_utils_fw_rpc_init(self);
60898c4c201SDavid VomLehn if (err < 0)
60998c4c201SDavid VomLehn goto err_exit;
61098c4c201SDavid VomLehn
61198c4c201SDavid VomLehn err_exit:
61298c4c201SDavid VomLehn return err;
61398c4c201SDavid VomLehn }
61498c4c201SDavid VomLehn
hw_atl_utils_mpi_read_mbox(struct aq_hw_s * self,struct hw_atl_utils_mbox_header * pmbox)61565e665e6SIgor Russkikh int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self,
6168f60f762SNikita Danilov struct hw_atl_utils_mbox_header *pmbox)
61765e665e6SIgor Russkikh {
61865e665e6SIgor Russkikh return hw_atl_utils_fw_downld_dwords(self,
6191a713f87SIgor Russkikh self->mbox_addr,
62065e665e6SIgor Russkikh (u32 *)(void *)pmbox,
62165e665e6SIgor Russkikh sizeof(*pmbox) / sizeof(u32));
62265e665e6SIgor Russkikh }
62365e665e6SIgor Russkikh
hw_atl_utils_mpi_read_stats(struct aq_hw_s * self,struct hw_atl_utils_mbox * pmbox)62498c4c201SDavid VomLehn void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
6258f60f762SNikita Danilov struct hw_atl_utils_mbox *pmbox)
62698c4c201SDavid VomLehn {
62798c4c201SDavid VomLehn int err = 0;
62898c4c201SDavid VomLehn
62998c4c201SDavid VomLehn err = hw_atl_utils_fw_downld_dwords(self,
6301a713f87SIgor Russkikh self->mbox_addr,
63198c4c201SDavid VomLehn (u32 *)(void *)pmbox,
63298c4c201SDavid VomLehn sizeof(*pmbox) / sizeof(u32));
63398c4c201SDavid VomLehn if (err < 0)
63498c4c201SDavid VomLehn goto err_exit;
63598c4c201SDavid VomLehn
636d1ad88feSMark Starovoytov if (ATL_HW_IS_CHIP_FEATURE(self, REVISION_A0)) {
63798c4c201SDavid VomLehn unsigned int mtu = self->aq_nic_cfg ?
63898c4c201SDavid VomLehn self->aq_nic_cfg->mtu : 1514U;
63998c4c201SDavid VomLehn pmbox->stats.ubrc = pmbox->stats.uprc * mtu;
64098c4c201SDavid VomLehn pmbox->stats.ubtc = pmbox->stats.uptc * mtu;
6411a713f87SIgor Russkikh pmbox->stats.dpc = atomic_read(&self->dpc);
64298c4c201SDavid VomLehn } else {
643ce4cdbe4SDmitry Bogdanov pmbox->stats.dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self);
64498c4c201SDavid VomLehn }
64598c4c201SDavid VomLehn
64698c4c201SDavid VomLehn err_exit:;
64798c4c201SDavid VomLehn }
64898c4c201SDavid VomLehn
hw_atl_utils_mpi_set_speed(struct aq_hw_s * self,u32 speed)649dfbd0749SWei Yongjun static int hw_atl_utils_mpi_set_speed(struct aq_hw_s *self, u32 speed)
65098c4c201SDavid VomLehn {
6510c58c35fSIgor Russkikh u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR);
65298c4c201SDavid VomLehn
65344e00dd8SIgor Russkikh val = val & ~HW_ATL_MPI_SPEED_MSK;
65444e00dd8SIgor Russkikh val |= speed << HW_ATL_MPI_SPEED_SHIFT;
6550c58c35fSIgor Russkikh aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val);
65698c4c201SDavid VomLehn
65798c4c201SDavid VomLehn return 0;
65898c4c201SDavid VomLehn }
65998c4c201SDavid VomLehn
hw_atl_utils_mpi_set_state(struct aq_hw_s * self,enum hal_atl_utils_fw_state_e state)660dfbd0749SWei Yongjun static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
66144e00dd8SIgor Russkikh enum hal_atl_utils_fw_state_e state)
66298c4c201SDavid VomLehn {
66344e00dd8SIgor Russkikh u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR);
6647b0c342fSNikita Danilov struct hw_atl_utils_mbox_header mbox;
6657b0c342fSNikita Danilov u32 transaction_id = 0;
6667b0c342fSNikita Danilov int err = 0;
66798c4c201SDavid VomLehn
66898c4c201SDavid VomLehn if (state == MPI_RESET) {
66965e665e6SIgor Russkikh hw_atl_utils_mpi_read_mbox(self, &mbox);
67098c4c201SDavid VomLehn
67165e665e6SIgor Russkikh transaction_id = mbox.transaction_id;
67298c4c201SDavid VomLehn
6736a7f2277SNikita Danilov err = readx_poll_timeout_atomic(hw_atl_utils_get_mpi_mbox_tid,
6746a7f2277SNikita Danilov self, mbox.transaction_id,
6756a7f2277SNikita Danilov transaction_id !=
6766a7f2277SNikita Danilov mbox.transaction_id,
6776a7f2277SNikita Danilov 1000U, 100000U);
67898c4c201SDavid VomLehn if (err < 0)
67998c4c201SDavid VomLehn goto err_exit;
68098c4c201SDavid VomLehn }
68144e00dd8SIgor Russkikh /* On interface DEINIT we disable DW (raise bit)
68244e00dd8SIgor Russkikh * Otherwise enable DW (clear bit)
68344e00dd8SIgor Russkikh */
68444e00dd8SIgor Russkikh if (state == MPI_DEINIT || state == MPI_POWER)
68544e00dd8SIgor Russkikh val |= HW_ATL_MPI_DIRTY_WAKE_MSK;
68644e00dd8SIgor Russkikh else
68744e00dd8SIgor Russkikh val &= ~HW_ATL_MPI_DIRTY_WAKE_MSK;
68898c4c201SDavid VomLehn
68944e00dd8SIgor Russkikh /* Set new state bits */
69044e00dd8SIgor Russkikh val = val & ~HW_ATL_MPI_STATE_MSK;
69144e00dd8SIgor Russkikh val |= state & HW_ATL_MPI_STATE_MSK;
69298c4c201SDavid VomLehn
6930c58c35fSIgor Russkikh aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val);
6947b0c342fSNikita Danilov
69544e00dd8SIgor Russkikh err_exit:
69644e00dd8SIgor Russkikh return err;
6970c58c35fSIgor Russkikh }
6980c58c35fSIgor Russkikh
hw_atl_utils_mpi_get_link_status(struct aq_hw_s * self)699bd8ed441SPavel Belous int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self)
70098c4c201SDavid VomLehn {
701bd8ed441SPavel Belous struct aq_hw_link_status_s *link_status = &self->aq_link_status;
7027b0c342fSNikita Danilov u32 mpi_state;
7037b0c342fSNikita Danilov u32 speed;
70498c4c201SDavid VomLehn
7057b0c342fSNikita Danilov mpi_state = hw_atl_utils_mpi_get_state(self);
706ac70957eSIgor Russkikh speed = mpi_state >> HW_ATL_MPI_SPEED_SHIFT;
7077b0c342fSNikita Danilov
7087b0c342fSNikita Danilov if (!speed) {
70998c4c201SDavid VomLehn link_status->mbps = 0U;
71098c4c201SDavid VomLehn } else {
7117b0c342fSNikita Danilov switch (speed) {
71298c4c201SDavid VomLehn case HAL_ATLANTIC_RATE_10G:
71398c4c201SDavid VomLehn link_status->mbps = 10000U;
71498c4c201SDavid VomLehn break;
71598c4c201SDavid VomLehn
71698c4c201SDavid VomLehn case HAL_ATLANTIC_RATE_5G:
71798c4c201SDavid VomLehn case HAL_ATLANTIC_RATE_5GSR:
71898c4c201SDavid VomLehn link_status->mbps = 5000U;
71998c4c201SDavid VomLehn break;
72098c4c201SDavid VomLehn
721843e1396SMark Starovoytov case HAL_ATLANTIC_RATE_2G5:
72298c4c201SDavid VomLehn link_status->mbps = 2500U;
72398c4c201SDavid VomLehn break;
72498c4c201SDavid VomLehn
72598c4c201SDavid VomLehn case HAL_ATLANTIC_RATE_1G:
72698c4c201SDavid VomLehn link_status->mbps = 1000U;
72798c4c201SDavid VomLehn break;
72898c4c201SDavid VomLehn
72998c4c201SDavid VomLehn case HAL_ATLANTIC_RATE_100M:
73098c4c201SDavid VomLehn link_status->mbps = 100U;
73198c4c201SDavid VomLehn break;
73298c4c201SDavid VomLehn
73398c4c201SDavid VomLehn default:
734a7bb1beaSIgor Russkikh return -EBUSY;
73598c4c201SDavid VomLehn }
73698c4c201SDavid VomLehn }
737071a0204SIgor Russkikh link_status->full_duplex = true;
73898c4c201SDavid VomLehn
73998c4c201SDavid VomLehn return 0;
74098c4c201SDavid VomLehn }
74198c4c201SDavid VomLehn
hw_atl_utils_get_mac_permanent(struct aq_hw_s * self,u8 * mac)74298c4c201SDavid VomLehn int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self,
74398c4c201SDavid VomLehn u8 *mac)
74498c4c201SDavid VomLehn {
7457b0c342fSNikita Danilov u32 mac_addr[2];
7467b0c342fSNikita Danilov u32 efuse_addr;
74798c4c201SDavid VomLehn int err = 0;
74898c4c201SDavid VomLehn u32 h = 0U;
74998c4c201SDavid VomLehn u32 l = 0U;
75098c4c201SDavid VomLehn
75198c4c201SDavid VomLehn if (!aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) {
75298c4c201SDavid VomLehn unsigned int ucp_0x370 = 0;
7537b0c342fSNikita Danilov unsigned int rnd = 0;
75498c4c201SDavid VomLehn
75598c4c201SDavid VomLehn get_random_bytes(&rnd, sizeof(unsigned int));
75698c4c201SDavid VomLehn
75798c4c201SDavid VomLehn ucp_0x370 = 0x02020202 | (0xFEFEFEFE & rnd);
75898c4c201SDavid VomLehn aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
75998c4c201SDavid VomLehn }
76098c4c201SDavid VomLehn
7617b0c342fSNikita Danilov efuse_addr = aq_hw_read_reg(self, 0x00000374U);
7627b0c342fSNikita Danilov
7637b0c342fSNikita Danilov err = hw_atl_utils_fw_downld_dwords(self, efuse_addr + (40U * 4U),
7647b0c342fSNikita Danilov mac_addr, ARRAY_SIZE(mac_addr));
76598c4c201SDavid VomLehn if (err < 0) {
76698c4c201SDavid VomLehn mac_addr[0] = 0U;
76798c4c201SDavid VomLehn mac_addr[1] = 0U;
76898c4c201SDavid VomLehn err = 0;
76998c4c201SDavid VomLehn } else {
77098c4c201SDavid VomLehn mac_addr[0] = __swab32(mac_addr[0]);
77198c4c201SDavid VomLehn mac_addr[1] = __swab32(mac_addr[1]);
77298c4c201SDavid VomLehn }
77398c4c201SDavid VomLehn
77498c4c201SDavid VomLehn ether_addr_copy(mac, (u8 *)mac_addr);
77598c4c201SDavid VomLehn
77698c4c201SDavid VomLehn if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) {
77798c4c201SDavid VomLehn /* chip revision */
778e9157848SNikita Danilov l = 0xE3000000U |
779e9157848SNikita Danilov (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) |
780e9157848SNikita Danilov (0x00 << 16);
78198c4c201SDavid VomLehn h = 0x8001300EU;
78298c4c201SDavid VomLehn
78398c4c201SDavid VomLehn mac[5] = (u8)(0xFFU & l);
78498c4c201SDavid VomLehn l >>= 8;
78598c4c201SDavid VomLehn mac[4] = (u8)(0xFFU & l);
78698c4c201SDavid VomLehn l >>= 8;
78798c4c201SDavid VomLehn mac[3] = (u8)(0xFFU & l);
78898c4c201SDavid VomLehn l >>= 8;
78998c4c201SDavid VomLehn mac[2] = (u8)(0xFFU & l);
79098c4c201SDavid VomLehn mac[1] = (u8)(0xFFU & h);
79198c4c201SDavid VomLehn h >>= 8;
79298c4c201SDavid VomLehn mac[0] = (u8)(0xFFU & h);
79398c4c201SDavid VomLehn }
79498c4c201SDavid VomLehn
79598c4c201SDavid VomLehn return err;
79698c4c201SDavid VomLehn }
79798c4c201SDavid VomLehn
hw_atl_utils_mbps_2_speed_index(unsigned int mbps)79898c4c201SDavid VomLehn unsigned int hw_atl_utils_mbps_2_speed_index(unsigned int mbps)
79998c4c201SDavid VomLehn {
80098c4c201SDavid VomLehn unsigned int ret = 0U;
80198c4c201SDavid VomLehn
80298c4c201SDavid VomLehn switch (mbps) {
80398c4c201SDavid VomLehn case 100U:
80498c4c201SDavid VomLehn ret = 5U;
80598c4c201SDavid VomLehn break;
80698c4c201SDavid VomLehn
80798c4c201SDavid VomLehn case 1000U:
80898c4c201SDavid VomLehn ret = 4U;
80998c4c201SDavid VomLehn break;
81098c4c201SDavid VomLehn
81198c4c201SDavid VomLehn case 2500U:
81298c4c201SDavid VomLehn ret = 3U;
81398c4c201SDavid VomLehn break;
81498c4c201SDavid VomLehn
81598c4c201SDavid VomLehn case 5000U:
81698c4c201SDavid VomLehn ret = 1U;
81798c4c201SDavid VomLehn break;
81898c4c201SDavid VomLehn
81998c4c201SDavid VomLehn case 10000U:
82098c4c201SDavid VomLehn ret = 0U;
82198c4c201SDavid VomLehn break;
82298c4c201SDavid VomLehn
82398c4c201SDavid VomLehn default:
82498c4c201SDavid VomLehn break;
82598c4c201SDavid VomLehn }
8267b0c342fSNikita Danilov
82798c4c201SDavid VomLehn return ret;
82898c4c201SDavid VomLehn }
82998c4c201SDavid VomLehn
hw_atl_utils_hw_chip_features_init(struct aq_hw_s * self,u32 * p)83098c4c201SDavid VomLehn void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p)
83198c4c201SDavid VomLehn {
8328e1c072fSIgor Russkikh u32 val = hw_atl_reg_glb_mif_id_get(self);
83398c4c201SDavid VomLehn u32 mif_rev = val & 0xFFU;
8347b0c342fSNikita Danilov u32 chip_features = 0U;
83598c4c201SDavid VomLehn
836d1ad88feSMark Starovoytov chip_features |= ATL_HW_CHIP_ATLANTIC;
837d1ad88feSMark Starovoytov
83847203b34SIgor Russkikh if ((0xFU & mif_rev) == 1U) {
839d1ad88feSMark Starovoytov chip_features |= ATL_HW_CHIP_REVISION_A0 |
840d1ad88feSMark Starovoytov ATL_HW_CHIP_MPI_AQ |
841d1ad88feSMark Starovoytov ATL_HW_CHIP_MIPS;
84247203b34SIgor Russkikh } else if ((0xFU & mif_rev) == 2U) {
843d1ad88feSMark Starovoytov chip_features |= ATL_HW_CHIP_REVISION_B0 |
844d1ad88feSMark Starovoytov ATL_HW_CHIP_MPI_AQ |
845d1ad88feSMark Starovoytov ATL_HW_CHIP_MIPS |
846d1ad88feSMark Starovoytov ATL_HW_CHIP_TPO2 |
847d1ad88feSMark Starovoytov ATL_HW_CHIP_RPF2;
84847203b34SIgor Russkikh } else if ((0xFU & mif_rev) == 0xAU) {
849d1ad88feSMark Starovoytov chip_features |= ATL_HW_CHIP_REVISION_B1 |
850d1ad88feSMark Starovoytov ATL_HW_CHIP_MPI_AQ |
851d1ad88feSMark Starovoytov ATL_HW_CHIP_MIPS |
852d1ad88feSMark Starovoytov ATL_HW_CHIP_TPO2 |
853d1ad88feSMark Starovoytov ATL_HW_CHIP_RPF2;
85498c4c201SDavid VomLehn }
85598c4c201SDavid VomLehn
85698c4c201SDavid VomLehn *p = chip_features;
85798c4c201SDavid VomLehn }
85898c4c201SDavid VomLehn
hw_atl_fw1x_deinit(struct aq_hw_s * self)85944e00dd8SIgor Russkikh static int hw_atl_fw1x_deinit(struct aq_hw_s *self)
86098c4c201SDavid VomLehn {
86144e00dd8SIgor Russkikh hw_atl_utils_mpi_set_speed(self, 0);
86244e00dd8SIgor Russkikh hw_atl_utils_mpi_set_state(self, MPI_DEINIT);
8637b0c342fSNikita Danilov
86498c4c201SDavid VomLehn return 0;
86598c4c201SDavid VomLehn }
86698c4c201SDavid VomLehn
hw_atl_utils_update_stats(struct aq_hw_s * self)86765e665e6SIgor Russkikh int hw_atl_utils_update_stats(struct aq_hw_s *self)
86865e665e6SIgor Russkikh {
869ce4cdbe4SDmitry Bogdanov struct aq_stats_s *cs = &self->curr_stats;
870*2087ced0SDmitry Bogdanov struct aq_stats_s curr_stats = *cs;
8717b0c342fSNikita Danilov struct hw_atl_utils_mbox mbox;
872*2087ced0SDmitry Bogdanov bool corrupted_stats = false;
87365e665e6SIgor Russkikh
87465e665e6SIgor Russkikh hw_atl_utils_mpi_read_stats(self, &mbox);
87565e665e6SIgor Russkikh
876*2087ced0SDmitry Bogdanov #define AQ_SDELTA(_N_) \
877*2087ced0SDmitry Bogdanov do { \
878*2087ced0SDmitry Bogdanov if (!corrupted_stats && \
879*2087ced0SDmitry Bogdanov ((s64)(mbox.stats._N_ - self->last_stats._N_)) >= 0) \
880*2087ced0SDmitry Bogdanov curr_stats._N_ += mbox.stats._N_ - self->last_stats._N_; \
881*2087ced0SDmitry Bogdanov else \
882*2087ced0SDmitry Bogdanov corrupted_stats = true; \
883*2087ced0SDmitry Bogdanov } while (0)
8841a713f87SIgor Russkikh
885be08d839SIgor Russkikh if (self->aq_link_status.mbps) {
88665e665e6SIgor Russkikh AQ_SDELTA(uprc);
88765e665e6SIgor Russkikh AQ_SDELTA(mprc);
88865e665e6SIgor Russkikh AQ_SDELTA(bprc);
88965e665e6SIgor Russkikh AQ_SDELTA(erpt);
89065e665e6SIgor Russkikh
89165e665e6SIgor Russkikh AQ_SDELTA(uptc);
89265e665e6SIgor Russkikh AQ_SDELTA(mptc);
89365e665e6SIgor Russkikh AQ_SDELTA(bptc);
89465e665e6SIgor Russkikh AQ_SDELTA(erpr);
89565e665e6SIgor Russkikh
89665e665e6SIgor Russkikh AQ_SDELTA(ubrc);
89765e665e6SIgor Russkikh AQ_SDELTA(ubtc);
89865e665e6SIgor Russkikh AQ_SDELTA(mbrc);
89965e665e6SIgor Russkikh AQ_SDELTA(mbtc);
90065e665e6SIgor Russkikh AQ_SDELTA(bbrc);
90165e665e6SIgor Russkikh AQ_SDELTA(bbtc);
90265e665e6SIgor Russkikh AQ_SDELTA(dpc);
903*2087ced0SDmitry Bogdanov
904*2087ced0SDmitry Bogdanov if (!corrupted_stats)
905*2087ced0SDmitry Bogdanov *cs = curr_stats;
906be08d839SIgor Russkikh }
90765e665e6SIgor Russkikh #undef AQ_SDELTA
908ce4cdbe4SDmitry Bogdanov
909ce4cdbe4SDmitry Bogdanov cs->dma_pkt_rc = hw_atl_stats_rx_dma_good_pkt_counter_get(self);
910ce4cdbe4SDmitry Bogdanov cs->dma_pkt_tc = hw_atl_stats_tx_dma_good_pkt_counter_get(self);
911ce4cdbe4SDmitry Bogdanov cs->dma_oct_rc = hw_atl_stats_rx_dma_good_octet_counter_get(self);
912ce4cdbe4SDmitry Bogdanov cs->dma_oct_tc = hw_atl_stats_tx_dma_good_octet_counter_get(self);
91365e665e6SIgor Russkikh
9141a713f87SIgor Russkikh memcpy(&self->last_stats, &mbox.stats, sizeof(mbox.stats));
91565e665e6SIgor Russkikh
91665e665e6SIgor Russkikh return 0;
91765e665e6SIgor Russkikh }
91865e665e6SIgor Russkikh
hw_atl_utils_get_hw_stats(struct aq_hw_s * self)919be08d839SIgor Russkikh struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self)
92098c4c201SDavid VomLehn {
9211a713f87SIgor Russkikh return &self->curr_stats;
92298c4c201SDavid VomLehn }
92398c4c201SDavid VomLehn
92498c4c201SDavid VomLehn static const u32 hw_atl_utils_hw_mac_regs[] = {
92598c4c201SDavid VomLehn 0x00005580U, 0x00005590U, 0x000055B0U, 0x000055B4U,
92698c4c201SDavid VomLehn 0x000055C0U, 0x00005B00U, 0x00005B04U, 0x00005B08U,
92798c4c201SDavid VomLehn 0x00005B0CU, 0x00005B10U, 0x00005B14U, 0x00005B18U,
92898c4c201SDavid VomLehn 0x00005B1CU, 0x00005B20U, 0x00005B24U, 0x00005B28U,
92998c4c201SDavid VomLehn 0x00005B2CU, 0x00005B30U, 0x00005B34U, 0x00005B38U,
93098c4c201SDavid VomLehn 0x00005B3CU, 0x00005B40U, 0x00005B44U, 0x00005B48U,
93198c4c201SDavid VomLehn 0x00005B4CU, 0x00005B50U, 0x00005B54U, 0x00005B58U,
93298c4c201SDavid VomLehn 0x00005B5CU, 0x00005B60U, 0x00005B64U, 0x00005B68U,
93398c4c201SDavid VomLehn 0x00005B6CU, 0x00005B70U, 0x00005B74U, 0x00005B78U,
93498c4c201SDavid VomLehn 0x00005B7CU, 0x00007C00U, 0x00007C04U, 0x00007C08U,
93598c4c201SDavid VomLehn 0x00007C0CU, 0x00007C10U, 0x00007C14U, 0x00007C18U,
93698c4c201SDavid VomLehn 0x00007C1CU, 0x00007C20U, 0x00007C40U, 0x00007C44U,
93798c4c201SDavid VomLehn 0x00007C48U, 0x00007C4CU, 0x00007C50U, 0x00007C54U,
93898c4c201SDavid VomLehn 0x00007C58U, 0x00007C5CU, 0x00007C60U, 0x00007C80U,
93998c4c201SDavid VomLehn 0x00007C84U, 0x00007C88U, 0x00007C8CU, 0x00007C90U,
94098c4c201SDavid VomLehn 0x00007C94U, 0x00007C98U, 0x00007C9CU, 0x00007CA0U,
94198c4c201SDavid VomLehn 0x00007CC0U, 0x00007CC4U, 0x00007CC8U, 0x00007CCCU,
94298c4c201SDavid VomLehn 0x00007CD0U, 0x00007CD4U, 0x00007CD8U, 0x00007CDCU,
94398c4c201SDavid VomLehn 0x00007CE0U, 0x00000300U, 0x00000304U, 0x00000308U,
94498c4c201SDavid VomLehn 0x0000030cU, 0x00000310U, 0x00000314U, 0x00000318U,
94598c4c201SDavid VomLehn 0x0000031cU, 0x00000360U, 0x00000364U, 0x00000368U,
94698c4c201SDavid VomLehn 0x0000036cU, 0x00000370U, 0x00000374U, 0x00006900U,
94798c4c201SDavid VomLehn };
94898c4c201SDavid VomLehn
hw_atl_utils_hw_get_regs(struct aq_hw_s * self,const struct aq_hw_caps_s * aq_hw_caps,u32 * regs_buff)94998c4c201SDavid VomLehn int hw_atl_utils_hw_get_regs(struct aq_hw_s *self,
9504cbc9f92SIgor Russkikh const struct aq_hw_caps_s *aq_hw_caps,
95198c4c201SDavid VomLehn u32 *regs_buff)
95298c4c201SDavid VomLehn {
95398c4c201SDavid VomLehn unsigned int i = 0U;
95498c4c201SDavid VomLehn
95598c4c201SDavid VomLehn for (i = 0; i < aq_hw_caps->mac_regs_count; i++)
95698c4c201SDavid VomLehn regs_buff[i] = aq_hw_read_reg(self,
95798c4c201SDavid VomLehn hw_atl_utils_hw_mac_regs[i]);
9587b0c342fSNikita Danilov
95998c4c201SDavid VomLehn return 0;
96098c4c201SDavid VomLehn }
96198c4c201SDavid VomLehn
hw_atl_utils_get_fw_version(struct aq_hw_s * self)96236e90a52SNikita Danilov u32 hw_atl_utils_get_fw_version(struct aq_hw_s *self)
96398c4c201SDavid VomLehn {
96436e90a52SNikita Danilov return aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION);
96598c4c201SDavid VomLehn }
9660c58c35fSIgor Russkikh
aq_fw1x_set_wake_magic(struct aq_hw_s * self,bool wol_enabled,const u8 * mac)967837c6378SNikita Danilov static int aq_fw1x_set_wake_magic(struct aq_hw_s *self, bool wol_enabled,
96876660757SJakub Kicinski const u8 *mac)
969a0da96c0SYana Esina {
9708f60f762SNikita Danilov struct hw_atl_utils_fw_rpc *prpc = NULL;
971a0da96c0SYana Esina unsigned int rpc_size = 0U;
972a0da96c0SYana Esina int err = 0;
973a0da96c0SYana Esina
974a0da96c0SYana Esina err = hw_atl_utils_fw_rpc_wait(self, &prpc);
975a0da96c0SYana Esina if (err < 0)
976a0da96c0SYana Esina goto err_exit;
977a0da96c0SYana Esina
978a0da96c0SYana Esina memset(prpc, 0, sizeof(*prpc));
979a0da96c0SYana Esina
980a0da96c0SYana Esina if (wol_enabled) {
981d993e14bSNikita Danilov rpc_size = offsetof(struct hw_atl_utils_fw_rpc, msg_wol_add) +
982d993e14bSNikita Danilov sizeof(prpc->msg_wol_add);
983d993e14bSNikita Danilov
984a0da96c0SYana Esina
985a0da96c0SYana Esina prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD;
986d993e14bSNikita Danilov prpc->msg_wol_add.priority =
987a0da96c0SYana Esina HAL_ATLANTIC_UTILS_FW_MSG_WOL_PRIOR;
988d993e14bSNikita Danilov prpc->msg_wol_add.pattern_id =
989a0da96c0SYana Esina HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN;
990d993e14bSNikita Danilov prpc->msg_wol_add.packet_type =
991a0da96c0SYana Esina HAL_ATLANTIC_UTILS_FW_MSG_WOL_MAG_PKT;
992a0da96c0SYana Esina
993d993e14bSNikita Danilov ether_addr_copy((u8 *)&prpc->msg_wol_add.magic_packet_pattern,
994d993e14bSNikita Danilov mac);
995a0da96c0SYana Esina } else {
996d993e14bSNikita Danilov rpc_size = sizeof(prpc->msg_wol_remove) +
997d993e14bSNikita Danilov offsetof(struct hw_atl_utils_fw_rpc, msg_wol_remove);
998a0da96c0SYana Esina
999a0da96c0SYana Esina prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL;
1000d993e14bSNikita Danilov prpc->msg_wol_add.pattern_id =
1001a0da96c0SYana Esina HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN;
1002a0da96c0SYana Esina }
1003a0da96c0SYana Esina
1004a0da96c0SYana Esina err = hw_atl_utils_fw_rpc_call(self, rpc_size);
1005a0da96c0SYana Esina
1006a0da96c0SYana Esina err_exit:
1007a0da96c0SYana Esina return err;
1008a0da96c0SYana Esina }
1009a0da96c0SYana Esina
aq_fw1x_set_power(struct aq_hw_s * self,unsigned int power_state,const u8 * mac)10103d5537f9SWei Yongjun static int aq_fw1x_set_power(struct aq_hw_s *self, unsigned int power_state,
101176660757SJakub Kicinski const u8 *mac)
1012a0da96c0SYana Esina {
10138f60f762SNikita Danilov struct hw_atl_utils_fw_rpc *prpc = NULL;
1014a0da96c0SYana Esina unsigned int rpc_size = 0U;
1015a0da96c0SYana Esina int err = 0;
1016a0da96c0SYana Esina
1017837c6378SNikita Danilov if (self->aq_nic_cfg->wol & WAKE_MAGIC) {
1018837c6378SNikita Danilov err = aq_fw1x_set_wake_magic(self, 1, mac);
1019a0da96c0SYana Esina
1020a0da96c0SYana Esina if (err < 0)
1021a0da96c0SYana Esina goto err_exit;
1022a0da96c0SYana Esina
1023a0da96c0SYana Esina rpc_size = sizeof(prpc->msg_id) +
1024a0da96c0SYana Esina sizeof(prpc->msg_enable_wakeup);
1025a0da96c0SYana Esina
1026a0da96c0SYana Esina err = hw_atl_utils_fw_rpc_wait(self, &prpc);
1027a0da96c0SYana Esina
1028a0da96c0SYana Esina if (err < 0)
1029a0da96c0SYana Esina goto err_exit;
1030a0da96c0SYana Esina
1031a0da96c0SYana Esina memset(prpc, 0, rpc_size);
1032a0da96c0SYana Esina
1033a0da96c0SYana Esina prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP;
1034a0da96c0SYana Esina prpc->msg_enable_wakeup.pattern_mask = 0x00000002;
1035a0da96c0SYana Esina
1036a0da96c0SYana Esina err = hw_atl_utils_fw_rpc_call(self, rpc_size);
1037a0da96c0SYana Esina if (err < 0)
1038a0da96c0SYana Esina goto err_exit;
1039a0da96c0SYana Esina }
1040a0da96c0SYana Esina hw_atl_utils_mpi_set_speed(self, 0);
1041a0da96c0SYana Esina hw_atl_utils_mpi_set_state(self, MPI_POWER);
1042a0da96c0SYana Esina
1043a0da96c0SYana Esina err_exit:
1044a0da96c0SYana Esina return err;
1045a0da96c0SYana Esina }
1046a0da96c0SYana Esina
hw_atl_utils_get_mpi_mbox_tid(struct aq_hw_s * self)10476a7f2277SNikita Danilov static u32 hw_atl_utils_get_mpi_mbox_tid(struct aq_hw_s *self)
10486a7f2277SNikita Danilov {
10496a7f2277SNikita Danilov struct hw_atl_utils_mbox_header mbox;
10506a7f2277SNikita Danilov
10516a7f2277SNikita Danilov hw_atl_utils_mpi_read_mbox(self, &mbox);
10526a7f2277SNikita Danilov
10536a7f2277SNikita Danilov return mbox.transaction_id;
10546a7f2277SNikita Danilov }
10556a7f2277SNikita Danilov
hw_atl_utils_mpi_get_state(struct aq_hw_s * self)10566a7f2277SNikita Danilov static u32 hw_atl_utils_mpi_get_state(struct aq_hw_s *self)
10576a7f2277SNikita Danilov {
10586a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR);
10596a7f2277SNikita Danilov }
10606a7f2277SNikita Danilov
hw_atl_utils_mif_cmd_get(struct aq_hw_s * self)10616a7f2277SNikita Danilov static u32 hw_atl_utils_mif_cmd_get(struct aq_hw_s *self)
10626a7f2277SNikita Danilov {
10636a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_MIF_CMD);
10646a7f2277SNikita Danilov }
10656a7f2277SNikita Danilov
hw_atl_utils_mif_addr_get(struct aq_hw_s * self)10666a7f2277SNikita Danilov static u32 hw_atl_utils_mif_addr_get(struct aq_hw_s *self)
10676a7f2277SNikita Danilov {
10686a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_MIF_ADDR);
10696a7f2277SNikita Danilov }
10706a7f2277SNikita Danilov
hw_atl_utils_rpc_state_get(struct aq_hw_s * self)10716a7f2277SNikita Danilov static u32 hw_atl_utils_rpc_state_get(struct aq_hw_s *self)
10726a7f2277SNikita Danilov {
10736a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_RPC_STATE_ADR);
10746a7f2277SNikita Danilov }
10756a7f2277SNikita Danilov
aq_fw1x_rpc_get(struct aq_hw_s * self)1076e7b5f97eSIgor Russkikh static u32 aq_fw1x_rpc_get(struct aq_hw_s *self)
1077e7b5f97eSIgor Russkikh {
1078e7b5f97eSIgor Russkikh return aq_hw_read_reg(self, HW_ATL_MPI_RPC_ADDR);
1079e7b5f97eSIgor Russkikh }
1080e7b5f97eSIgor Russkikh
10810c58c35fSIgor Russkikh const struct aq_fw_ops aq_fw_1x_ops = {
10820c58c35fSIgor Russkikh .init = hw_atl_utils_mpi_create,
108344e00dd8SIgor Russkikh .deinit = hw_atl_fw1x_deinit,
10840c58c35fSIgor Russkikh .reset = NULL,
10850c58c35fSIgor Russkikh .get_mac_permanent = hw_atl_utils_get_mac_permanent,
10860c58c35fSIgor Russkikh .set_link_speed = hw_atl_utils_mpi_set_speed,
10870c58c35fSIgor Russkikh .set_state = hw_atl_utils_mpi_set_state,
10880c58c35fSIgor Russkikh .update_link_status = hw_atl_utils_mpi_get_link_status,
10890c58c35fSIgor Russkikh .update_stats = hw_atl_utils_update_stats,
10908dcf2ad3SMark Starovoytov .get_mac_temp = NULL,
10918f894011SYana Esina .get_phy_temp = NULL,
1092a0da96c0SYana Esina .set_power = aq_fw1x_set_power,
109392ab6407SYana Esina .set_eee_rate = NULL,
109492ab6407SYana Esina .get_eee_rate = NULL,
1095288551deSIgor Russkikh .set_flow_control = NULL,
1096910479a9SEgor Pomozov .send_fw_request = NULL,
1097910479a9SEgor Pomozov .enable_ptp = NULL,
1098d1287ce4SNikita Danilov .led_control = NULL,
10990c58c35fSIgor Russkikh };
1100