]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[mirror_ubuntu-jammy-kernel.git] / drivers / net / ethernet / aquantia / atlantic / hw_atl / hw_atl_utils.c
CommitLineData
75a6faf6 1// SPDX-License-Identifier: GPL-2.0-only
98c4c201
DV
2/*
3 * aQuantia Corporation Network Driver
593f7b43 4 * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
98c4c201
DV
5 */
6
7/* File hw_atl_utils.c: Definition of common functions for Atlantic hardware
8 * abstraction layer.
9 */
10
1a713f87 11#include "../aq_nic.h"
98c4c201 12#include "../aq_hw_utils.h"
98c4c201
DV
13#include "hw_atl_utils.h"
14#include "hw_atl_llh.h"
0c58c35f 15#include "hw_atl_llh_internal.h"
98c4c201
DV
16
17#include <linux/random.h>
18
19#define HW_ATL_UCP_0X370_REG 0x0370U
20
47203b34
IR
21#define HW_ATL_MIF_CMD 0x0200U
22#define HW_ATL_MIF_ADDR 0x0208U
23#define HW_ATL_MIF_VAL 0x020CU
24
6a7f2277
ND
25#define HW_ATL_RPC_CONTROL_ADR 0x0338U
26#define HW_ATL_RPC_STATE_ADR 0x033CU
27
0c58c35f 28#define HW_ATL_MPI_FW_VERSION 0x18
98c4c201
DV
29#define HW_ATL_MPI_CONTROL_ADR 0x0368U
30#define HW_ATL_MPI_STATE_ADR 0x036CU
31
44e00dd8
IR
32#define HW_ATL_MPI_STATE_MSK 0x00FFU
33#define HW_ATL_MPI_STATE_SHIFT 0U
34#define HW_ATL_MPI_SPEED_MSK 0x00FF0000U
35#define HW_ATL_MPI_SPEED_SHIFT 16U
36#define HW_ATL_MPI_DIRTY_WAKE_MSK 0x02000000U
98c4c201 37
c8c82eb3
IR
38#define HW_ATL_MPI_DAISY_CHAIN_STATUS 0x704
39#define HW_ATL_MPI_BOOT_EXIT_CODE 0x388
40
41#define HW_ATL_MAC_PHY_CONTROL 0x4000
42#define HW_ATL_MAC_PHY_MPI_RESET_BIT 0x1D
43
0c58c35f 44#define HW_ATL_FW_VER_1X 0x01050006U
a57d3929
IR
45#define HW_ATL_FW_VER_2X 0x02000000U
46#define HW_ATL_FW_VER_3X 0x03000000U
0c58c35f 47
c8c82eb3
IR
48#define FORCE_FLASHLESS 0
49
dc12f75a
ND
50enum mcp_area {
51 MCP_AREA_CONFIG = 0x80000000,
52 MCP_AREA_SETTINGS = 0x20000000,
53};
54
0c58c35f 55static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual);
e9157848 56
cce96d18
IR
57static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
58 enum hal_atl_utils_fw_state_e state);
0c58c35f 59
6a7f2277
ND
60static u32 hw_atl_utils_get_mpi_mbox_tid(struct aq_hw_s *self);
61static u32 hw_atl_utils_mpi_get_state(struct aq_hw_s *self);
62static u32 hw_atl_utils_mif_cmd_get(struct aq_hw_s *self);
63static u32 hw_atl_utils_mif_addr_get(struct aq_hw_s *self);
64static u32 hw_atl_utils_rpc_state_get(struct aq_hw_s *self);
65
0c58c35f
IR
66int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
67{
68 int err = 0;
69
c8c82eb3
IR
70 err = hw_atl_utils_soft_reset(self);
71 if (err)
72 return err;
73
0c58c35f
IR
74 hw_atl_utils_hw_chip_features_init(self,
75 &self->chip_features);
76
77 hw_atl_utils_get_fw_version(self, &self->fw_ver_actual);
78
c8c82eb3
IR
79 if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X,
80 self->fw_ver_actual) == 0) {
0c58c35f 81 *fw_ops = &aq_fw_1x_ops;
c8c82eb3 82 } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X,
e9157848 83 self->fw_ver_actual) == 0) {
a57d3929 84 *fw_ops = &aq_fw_2x_ops;
c8c82eb3 85 } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X,
e9157848 86 self->fw_ver_actual) == 0) {
a57d3929 87 *fw_ops = &aq_fw_2x_ops;
c8c82eb3 88 } else {
0c58c35f 89 aq_pr_err("Bad FW version detected: %x\n",
c8c82eb3 90 self->fw_ver_actual);
0c58c35f
IR
91 return -EOPNOTSUPP;
92 }
93 self->aq_fw_ops = *fw_ops;
94 err = self->aq_fw_ops->init(self);
7b0c342f 95
0c58c35f
IR
96 return err;
97}
98
c8c82eb3
IR
99static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self)
100{
1bf9a752 101 u32 gsr, val;
c8c82eb3 102 int k = 0;
c8c82eb3
IR
103
104 aq_hw_write_reg(self, 0x404, 0x40e1);
105 AQ_HW_SLEEP(50);
106
107 /* Cleanup SPI */
1bf9a752
IR
108 val = aq_hw_read_reg(self, 0x53C);
109 aq_hw_write_reg(self, 0x53C, val | 0x10);
c8c82eb3
IR
110
111 gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
112 aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000);
113
114 /* Kickstart MAC */
115 aq_hw_write_reg(self, 0x404, 0x80e0);
116 aq_hw_write_reg(self, 0x32a8, 0x0);
117 aq_hw_write_reg(self, 0x520, 0x1);
1bf9a752
IR
118
119 /* Reset SPI again because of possible interrupted SPI burst */
120 val = aq_hw_read_reg(self, 0x53C);
121 aq_hw_write_reg(self, 0x53C, val | 0x10);
c8c82eb3 122 AQ_HW_SLEEP(10);
1bf9a752
IR
123 /* Clear SPI reset state */
124 aq_hw_write_reg(self, 0x53C, val & ~0x10);
125
c8c82eb3
IR
126 aq_hw_write_reg(self, 0x404, 0x180e0);
127
128 for (k = 0; k < 1000; k++) {
129 u32 flb_status = aq_hw_read_reg(self,
130 HW_ATL_MPI_DAISY_CHAIN_STATUS);
131
132 flb_status = flb_status & 0x10;
133 if (flb_status)
134 break;
135 AQ_HW_SLEEP(10);
136 }
137 if (k == 1000) {
138 aq_pr_err("MAC kickstart failed\n");
139 return -EIO;
140 }
141
142 /* FW reset */
143 aq_hw_write_reg(self, 0x404, 0x80e0);
144 AQ_HW_SLEEP(50);
145 aq_hw_write_reg(self, 0x3a0, 0x1);
146
147 /* Kickstart PHY - skipped */
148
149 /* Global software reset*/
150 hw_atl_rx_rx_reg_res_dis_set(self, 0U);
151 hw_atl_tx_tx_reg_res_dis_set(self, 0U);
152 aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL,
153 BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT),
154 HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0);
155 gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
156 aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000);
157
158 for (k = 0; k < 1000; k++) {
159 u32 fw_state = aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION);
160
161 if (fw_state)
162 break;
163 AQ_HW_SLEEP(10);
164 }
165 if (k == 1000) {
166 aq_pr_err("FW kickstart failed\n");
167 return -EIO;
168 }
d0f0fb25
IR
169 /* Old FW requires fixed delay after init */
170 AQ_HW_SLEEP(15);
c8c82eb3
IR
171
172 return 0;
173}
174
175static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self)
176{
1bf9a752 177 u32 gsr, val, rbl_status;
c8c82eb3
IR
178 int k;
179
180 aq_hw_write_reg(self, 0x404, 0x40e1);
181 aq_hw_write_reg(self, 0x3a0, 0x1);
182 aq_hw_write_reg(self, 0x32a8, 0x0);
183
184 /* Alter RBL status */
185 aq_hw_write_reg(self, 0x388, 0xDEAD);
186
1bf9a752
IR
187 /* Cleanup SPI */
188 val = aq_hw_read_reg(self, 0x53C);
189 aq_hw_write_reg(self, 0x53C, val | 0x10);
190
c8c82eb3
IR
191 /* Global software reset*/
192 hw_atl_rx_rx_reg_res_dis_set(self, 0U);
193 hw_atl_tx_tx_reg_res_dis_set(self, 0U);
194 aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL,
195 BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT),
196 HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0);
197 gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
198 aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR,
199 (gsr & 0xFFFFBFFF) | 0x8000);
200
201 if (FORCE_FLASHLESS)
202 aq_hw_write_reg(self, 0x534, 0x0);
203
204 aq_hw_write_reg(self, 0x404, 0x40e0);
205
206 /* Wait for RBL boot */
207 for (k = 0; k < 1000; k++) {
208 rbl_status = aq_hw_read_reg(self, 0x388) & 0xFFFF;
209 if (rbl_status && rbl_status != 0xDEAD)
210 break;
211 AQ_HW_SLEEP(10);
212 }
213 if (!rbl_status || rbl_status == 0xDEAD) {
214 aq_pr_err("RBL Restart failed");
215 return -EIO;
216 }
217
218 /* Restore NVR */
219 if (FORCE_FLASHLESS)
220 aq_hw_write_reg(self, 0x534, 0xA0);
221
222 if (rbl_status == 0xF1A7) {
223 aq_pr_err("No FW detected. Dynamic FW load not implemented\n");
224 return -ENOTSUPP;
225 }
226
227 for (k = 0; k < 1000; k++) {
228 u32 fw_state = aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION);
229
230 if (fw_state)
231 break;
232 AQ_HW_SLEEP(10);
233 }
234 if (k == 1000) {
235 aq_pr_err("FW kickstart failed\n");
236 return -EIO;
237 }
d0f0fb25
IR
238 /* Old FW requires fixed delay after init */
239 AQ_HW_SLEEP(15);
c8c82eb3
IR
240
241 return 0;
242}
243
244int hw_atl_utils_soft_reset(struct aq_hw_s *self)
245{
c8c82eb3 246 u32 boot_exit_code = 0;
6a7f2277 247 u32 val;
7b0c342f 248 int k;
c8c82eb3
IR
249
250 for (k = 0; k < 1000; ++k) {
251 u32 flb_status = aq_hw_read_reg(self,
252 HW_ATL_MPI_DAISY_CHAIN_STATUS);
253 boot_exit_code = aq_hw_read_reg(self,
254 HW_ATL_MPI_BOOT_EXIT_CODE);
255 if (flb_status != 0x06000000 || boot_exit_code != 0)
256 break;
257 }
258
259 if (k == 1000) {
260 aq_pr_err("Neither RBL nor FLB firmware started\n");
261 return -EOPNOTSUPP;
262 }
263
264 self->rbl_enabled = (boot_exit_code != 0);
265
cce96d18
IR
266 /* FW 1.x may bootup in an invalid POWER state (WOL feature).
267 * We should work around this by forcing its state back to DEINIT
268 */
269 if (!hw_atl_utils_ver_match(HW_ATL_FW_VER_1X,
270 aq_hw_read_reg(self,
271 HW_ATL_MPI_FW_VERSION))) {
272 int err = 0;
273
274 hw_atl_utils_mpi_set_state(self, MPI_DEINIT);
6a7f2277
ND
275 err = readx_poll_timeout_atomic(hw_atl_utils_mpi_get_state,
276 self, val,
277 (val & HW_ATL_MPI_STATE_MSK) ==
278 MPI_DEINIT,
279 10, 10000U);
4e3c7c00
Y
280 if (err)
281 return err;
cce96d18
IR
282 }
283
c8c82eb3
IR
284 if (self->rbl_enabled)
285 return hw_atl_utils_soft_reset_rbl(self);
286 else
287 return hw_atl_utils_soft_reset_flb(self);
288}
289
a57d3929
IR
290int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
291 u32 *p, u32 cnt)
98c4c201
DV
292{
293 int err = 0;
6a7f2277 294 u32 val;
98c4c201 295
6a7f2277
ND
296 err = readx_poll_timeout_atomic(hw_atl_sem_ram_get,
297 self, val, val == 1U,
298 1U, 10000U);
98c4c201
DV
299
300 if (err < 0) {
301 bool is_locked;
302
8e1c072f 303 hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
0b926d46 304 is_locked = hw_atl_sem_ram_get(self);
98c4c201
DV
305 if (!is_locked) {
306 err = -ETIME;
307 goto err_exit;
308 }
309 }
310
47203b34 311 aq_hw_write_reg(self, HW_ATL_MIF_ADDR, a);
98c4c201 312
47203b34
IR
313 for (++cnt; --cnt && !err;) {
314 aq_hw_write_reg(self, HW_ATL_MIF_CMD, 0x00008000U);
98c4c201 315
47203b34 316 if (IS_CHIP_FEATURE(REVISION_B1))
6a7f2277
ND
317 err = readx_poll_timeout_atomic(hw_atl_utils_mif_addr_get,
318 self, val, val != a,
319 1U, 1000U);
47203b34 320 else
6a7f2277
ND
321 err = readx_poll_timeout_atomic(hw_atl_utils_mif_cmd_get,
322 self, val,
323 !(val & 0x100),
324 1U, 1000U);
98c4c201 325
47203b34
IR
326 *(p++) = aq_hw_read_reg(self, HW_ATL_MIF_VAL);
327 a += 4;
98c4c201
DV
328 }
329
8e1c072f 330 hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
98c4c201
DV
331
332err_exit:
333 return err;
334}
335
dc12f75a
ND
336static int hw_atl_utils_write_b1_mbox(struct aq_hw_s *self, u32 addr,
337 u32 *p, u32 cnt, enum mcp_area area)
338{
339 u32 data_offset = 0;
340 u32 offset = addr;
341 int err = 0;
342 u32 val;
343
344 switch (area) {
345 case MCP_AREA_CONFIG:
346 offset -= self->rpc_addr;
347 break;
348
349 case MCP_AREA_SETTINGS:
350 offset -= self->settings_addr;
351 break;
352 }
353
354 offset = offset / sizeof(u32);
355
356 for (; data_offset < cnt; ++data_offset, ++offset) {
357 aq_hw_write_reg(self, 0x328, p[data_offset]);
358 aq_hw_write_reg(self, 0x32C,
359 (area | (0xFFFF & (offset * 4))));
360 hw_atl_mcp_up_force_intr_set(self, 1);
361 /* 1000 times by 10us = 10ms */
362 err = readx_poll_timeout_atomic(hw_atl_scrpad12_get,
363 self, val,
364 (val & 0xF0000000) !=
365 area,
366 10U, 10000U);
367
368 if (err < 0)
369 break;
370 }
371
372 return err;
373}
374
375static int hw_atl_utils_write_b0_mbox(struct aq_hw_s *self, u32 addr,
376 u32 *p, u32 cnt)
98c4c201 377{
dc12f75a
ND
378 u32 offset = 0;
379 int err = 0;
6a7f2277 380 u32 val;
dc12f75a
ND
381
382 aq_hw_write_reg(self, 0x208, addr);
383
384 for (; offset < cnt; ++offset) {
385 aq_hw_write_reg(self, 0x20C, p[offset]);
386 aq_hw_write_reg(self, 0x200, 0xC000);
387
388 err = readx_poll_timeout_atomic(hw_atl_utils_mif_cmd_get,
389 self, val,
390 (val & 0x100) == 0U,
391 10U, 10000U);
392
393 if (err < 0)
394 break;
395 }
396
397 return err;
398}
399
400static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 addr, u32 *p,
401 u32 cnt, enum mcp_area area)
402{
98c4c201 403 int err = 0;
dc12f75a 404 u32 val;
98c4c201 405
930b9a05
ND
406 err = readx_poll_timeout_atomic(hw_atl_sem_ram_get, self,
407 val, val == 1U,
408 10U, 100000U);
409 if (err < 0)
98c4c201 410 goto err_exit;
930b9a05 411
dc12f75a
ND
412 if (IS_CHIP_FEATURE(REVISION_B1))
413 err = hw_atl_utils_write_b1_mbox(self, addr, p, cnt, area);
414 else
415 err = hw_atl_utils_write_b0_mbox(self, addr, p, cnt);
98c4c201 416
dc12f75a 417 hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
98c4c201 418
dc12f75a
ND
419 if (err < 0)
420 goto err_exit;
98c4c201 421
dc12f75a 422 err = aq_hw_err_from_flags(self);
98c4c201
DV
423
424err_exit:
425 return err;
426}
427
dc12f75a
ND
428int hw_atl_write_fwcfg_dwords(struct aq_hw_s *self, u32 *p, u32 cnt)
429{
430 return hw_atl_utils_fw_upload_dwords(self, self->rpc_addr, p,
431 cnt, MCP_AREA_CONFIG);
432}
433
434int hw_atl_write_fwsettings_dwords(struct aq_hw_s *self, u32 offset, u32 *p,
435 u32 cnt)
436{
437 return hw_atl_utils_fw_upload_dwords(self, self->settings_addr + offset,
438 p, cnt, MCP_AREA_SETTINGS);
439}
440
98c4c201
DV
441static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual)
442{
98c4c201
DV
443 const u32 dw_major_mask = 0xff000000U;
444 const u32 dw_minor_mask = 0x00ffffffU;
7b0c342f 445 int err = 0;
98c4c201
DV
446
447 err = (dw_major_mask & (ver_expected ^ ver_actual)) ? -EOPNOTSUPP : 0;
448 if (err < 0)
449 goto err_exit;
450 err = ((dw_minor_mask & ver_expected) > (dw_minor_mask & ver_actual)) ?
451 -EOPNOTSUPP : 0;
7b0c342f 452
98c4c201
DV
453err_exit:
454 return err;
455}
456
457static int hw_atl_utils_init_ucp(struct aq_hw_s *self,
4cbc9f92 458 const struct aq_hw_caps_s *aq_hw_caps)
98c4c201
DV
459{
460 int err = 0;
461
462 if (!aq_hw_read_reg(self, 0x370U)) {
463 unsigned int rnd = 0U;
464 unsigned int ucp_0x370 = 0U;
465
466 get_random_bytes(&rnd, sizeof(unsigned int));
467
468 ucp_0x370 = 0x02020202U | (0xFEFEFEFEU & rnd);
469 aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
470 }
471
8e1c072f 472 hw_atl_reg_glb_cpu_scratch_scp_set(self, 0x00000000U, 25U);
98c4c201
DV
473
474 /* check 10 times by 1ms */
6a7f2277
ND
475 err = readx_poll_timeout_atomic(hw_atl_scrpad25_get,
476 self, self->mbox_addr,
477 self->mbox_addr != 0U,
478 1000U, 10000U);
98c4c201 479
98c4c201
DV
480 return err;
481}
482
98c4c201
DV
483struct aq_hw_atl_utils_fw_rpc_tid_s {
484 union {
485 u32 val;
486 struct {
487 u16 tid;
488 u16 len;
489 };
490 };
491};
492
493#define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL)
494
3ee5c887 495int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size)
98c4c201 496{
98c4c201 497 struct aq_hw_atl_utils_fw_rpc_tid_s sw;
7b0c342f 498 int err = 0;
98c4c201
DV
499
500 if (!IS_CHIP_FEATURE(MIPS)) {
501 err = -1;
502 goto err_exit;
503 }
dc12f75a
ND
504 err = hw_atl_write_fwcfg_dwords(self, (u32 *)(void *)&self->rpc,
505 (rpc_size + sizeof(u32) -
506 sizeof(u8)) / sizeof(u32));
98c4c201
DV
507 if (err < 0)
508 goto err_exit;
509
1a713f87 510 sw.tid = 0xFFFFU & (++self->rpc_tid);
98c4c201
DV
511 sw.len = (u16)rpc_size;
512 aq_hw_write_reg(self, HW_ATL_RPC_CONTROL_ADR, sw.val);
513
514err_exit:
515 return err;
516}
517
3ee5c887 518int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
8f60f762 519 struct hw_atl_utils_fw_rpc **rpc)
98c4c201 520{
98c4c201
DV
521 struct aq_hw_atl_utils_fw_rpc_tid_s sw;
522 struct aq_hw_atl_utils_fw_rpc_tid_s fw;
7b0c342f 523 int err = 0;
98c4c201
DV
524
525 do {
526 sw.val = aq_hw_read_reg(self, HW_ATL_RPC_CONTROL_ADR);
527
1a713f87 528 self->rpc_tid = sw.tid;
98c4c201 529
6a7f2277
ND
530 err = readx_poll_timeout_atomic(hw_atl_utils_rpc_state_get,
531 self, fw.val,
532 sw.tid == fw.tid,
533 1000U, 100000U);
98c4c201
DV
534
535 if (fw.len == 0xFFFFU) {
536 err = hw_atl_utils_fw_rpc_call(self, sw.len);
537 if (err < 0)
538 goto err_exit;
539 }
540 } while (sw.tid != fw.tid || 0xFFFFU == fw.len);
98c4c201
DV
541
542 if (rpc) {
543 if (fw.len) {
544 err =
545 hw_atl_utils_fw_downld_dwords(self,
1a713f87 546 self->rpc_addr,
98c4c201 547 (u32 *)(void *)
1a713f87 548 &self->rpc,
98c4c201 549 (fw.len + sizeof(u32) -
e9157848 550 sizeof(u8)) /
98c4c201
DV
551 sizeof(u32));
552 if (err < 0)
553 goto err_exit;
554 }
555
1a713f87 556 *rpc = &self->rpc;
98c4c201
DV
557 }
558
559err_exit:
560 return err;
561}
562
1a713f87 563static int hw_atl_utils_mpi_create(struct aq_hw_s *self)
98c4c201
DV
564{
565 int err = 0;
566
1a713f87 567 err = hw_atl_utils_init_ucp(self, self->aq_nic_cfg->aq_hw_caps);
98c4c201
DV
568 if (err < 0)
569 goto err_exit;
570
571 err = hw_atl_utils_fw_rpc_init(self);
572 if (err < 0)
573 goto err_exit;
574
575err_exit:
576 return err;
577}
578
65e665e6 579int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self,
8f60f762 580 struct hw_atl_utils_mbox_header *pmbox)
65e665e6
IR
581{
582 return hw_atl_utils_fw_downld_dwords(self,
e9157848
ND
583 self->mbox_addr,
584 (u32 *)(void *)pmbox,
585 sizeof(*pmbox) / sizeof(u32));
65e665e6
IR
586}
587
98c4c201 588void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
8f60f762 589 struct hw_atl_utils_mbox *pmbox)
98c4c201
DV
590{
591 int err = 0;
592
593 err = hw_atl_utils_fw_downld_dwords(self,
1a713f87 594 self->mbox_addr,
98c4c201
DV
595 (u32 *)(void *)pmbox,
596 sizeof(*pmbox) / sizeof(u32));
597 if (err < 0)
598 goto err_exit;
599
98c4c201
DV
600 if (IS_CHIP_FEATURE(REVISION_A0)) {
601 unsigned int mtu = self->aq_nic_cfg ?
602 self->aq_nic_cfg->mtu : 1514U;
603 pmbox->stats.ubrc = pmbox->stats.uprc * mtu;
604 pmbox->stats.ubtc = pmbox->stats.uptc * mtu;
1a713f87 605 pmbox->stats.dpc = atomic_read(&self->dpc);
98c4c201 606 } else {
ce4cdbe4 607 pmbox->stats.dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self);
98c4c201
DV
608 }
609
610err_exit:;
611}
612
dfbd0749 613static int hw_atl_utils_mpi_set_speed(struct aq_hw_s *self, u32 speed)
98c4c201 614{
0c58c35f 615 u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR);
98c4c201 616
44e00dd8
IR
617 val = val & ~HW_ATL_MPI_SPEED_MSK;
618 val |= speed << HW_ATL_MPI_SPEED_SHIFT;
0c58c35f 619 aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val);
98c4c201
DV
620
621 return 0;
622}
623
dfbd0749
WY
624static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
625 enum hal_atl_utils_fw_state_e state)
98c4c201 626{
44e00dd8 627 u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR);
7b0c342f
ND
628 struct hw_atl_utils_mbox_header mbox;
629 u32 transaction_id = 0;
630 int err = 0;
98c4c201
DV
631
632 if (state == MPI_RESET) {
65e665e6 633 hw_atl_utils_mpi_read_mbox(self, &mbox);
98c4c201 634
65e665e6 635 transaction_id = mbox.transaction_id;
98c4c201 636
6a7f2277
ND
637 err = readx_poll_timeout_atomic(hw_atl_utils_get_mpi_mbox_tid,
638 self, mbox.transaction_id,
639 transaction_id !=
640 mbox.transaction_id,
641 1000U, 100000U);
98c4c201
DV
642 if (err < 0)
643 goto err_exit;
644 }
44e00dd8
IR
645 /* On interface DEINIT we disable DW (raise bit)
646 * Otherwise enable DW (clear bit)
647 */
648 if (state == MPI_DEINIT || state == MPI_POWER)
649 val |= HW_ATL_MPI_DIRTY_WAKE_MSK;
650 else
651 val &= ~HW_ATL_MPI_DIRTY_WAKE_MSK;
98c4c201 652
44e00dd8
IR
653 /* Set new state bits */
654 val = val & ~HW_ATL_MPI_STATE_MSK;
655 val |= state & HW_ATL_MPI_STATE_MSK;
98c4c201 656
0c58c35f 657 aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val);
7b0c342f 658
44e00dd8
IR
659err_exit:
660 return err;
0c58c35f
IR
661}
662
bd8ed441 663int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self)
98c4c201 664{
bd8ed441 665 struct aq_hw_link_status_s *link_status = &self->aq_link_status;
7b0c342f
ND
666 u32 mpi_state;
667 u32 speed;
668
669 mpi_state = hw_atl_utils_mpi_get_state(self);
670 speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G |
671 FW2X_RATE_2G5 | FW2X_RATE_5G |
672 FW2X_RATE_10G);
98c4c201 673
7b0c342f 674 if (!speed) {
98c4c201
DV
675 link_status->mbps = 0U;
676 } else {
7b0c342f 677 switch (speed) {
98c4c201
DV
678 case HAL_ATLANTIC_RATE_10G:
679 link_status->mbps = 10000U;
680 break;
681
682 case HAL_ATLANTIC_RATE_5G:
683 case HAL_ATLANTIC_RATE_5GSR:
684 link_status->mbps = 5000U;
685 break;
686
687 case HAL_ATLANTIC_RATE_2GS:
688 link_status->mbps = 2500U;
689 break;
690
691 case HAL_ATLANTIC_RATE_1G:
692 link_status->mbps = 1000U;
693 break;
694
695 case HAL_ATLANTIC_RATE_100M:
696 link_status->mbps = 100U;
697 break;
698
699 default:
a7bb1bea 700 return -EBUSY;
98c4c201
DV
701 }
702 }
703
704 return 0;
705}
706
707int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self,
98c4c201
DV
708 u8 *mac)
709{
7b0c342f
ND
710 u32 mac_addr[2];
711 u32 efuse_addr;
98c4c201
DV
712 int err = 0;
713 u32 h = 0U;
714 u32 l = 0U;
98c4c201 715
98c4c201 716 if (!aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) {
98c4c201 717 unsigned int ucp_0x370 = 0;
7b0c342f 718 unsigned int rnd = 0;
98c4c201
DV
719
720 get_random_bytes(&rnd, sizeof(unsigned int));
721
722 ucp_0x370 = 0x02020202 | (0xFEFEFEFE & rnd);
723 aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
724 }
725
7b0c342f
ND
726 efuse_addr = aq_hw_read_reg(self, 0x00000374U);
727
728 err = hw_atl_utils_fw_downld_dwords(self, efuse_addr + (40U * 4U),
729 mac_addr, ARRAY_SIZE(mac_addr));
98c4c201
DV
730 if (err < 0) {
731 mac_addr[0] = 0U;
732 mac_addr[1] = 0U;
733 err = 0;
734 } else {
735 mac_addr[0] = __swab32(mac_addr[0]);
736 mac_addr[1] = __swab32(mac_addr[1]);
737 }
738
739 ether_addr_copy(mac, (u8 *)mac_addr);
740
741 if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) {
742 /* chip revision */
e9157848
ND
743 l = 0xE3000000U |
744 (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) |
745 (0x00 << 16);
98c4c201
DV
746 h = 0x8001300EU;
747
748 mac[5] = (u8)(0xFFU & l);
749 l >>= 8;
750 mac[4] = (u8)(0xFFU & l);
751 l >>= 8;
752 mac[3] = (u8)(0xFFU & l);
753 l >>= 8;
754 mac[2] = (u8)(0xFFU & l);
755 mac[1] = (u8)(0xFFU & h);
756 h >>= 8;
757 mac[0] = (u8)(0xFFU & h);
758 }
759
98c4c201
DV
760 return err;
761}
762
763unsigned int hw_atl_utils_mbps_2_speed_index(unsigned int mbps)
764{
765 unsigned int ret = 0U;
766
767 switch (mbps) {
768 case 100U:
769 ret = 5U;
770 break;
771
772 case 1000U:
773 ret = 4U;
774 break;
775
776 case 2500U:
777 ret = 3U;
778 break;
779
780 case 5000U:
781 ret = 1U;
782 break;
783
784 case 10000U:
785 ret = 0U;
786 break;
787
788 default:
789 break;
790 }
7b0c342f 791
98c4c201
DV
792 return ret;
793}
794
795void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p)
796{
8e1c072f 797 u32 val = hw_atl_reg_glb_mif_id_get(self);
98c4c201 798 u32 mif_rev = val & 0xFFU;
7b0c342f 799 u32 chip_features = 0U;
98c4c201 800
47203b34
IR
801 if ((0xFU & mif_rev) == 1U) {
802 chip_features |= HAL_ATLANTIC_UTILS_CHIP_REVISION_A0 |
98c4c201
DV
803 HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
804 HAL_ATLANTIC_UTILS_CHIP_MIPS;
47203b34
IR
805 } else if ((0xFU & mif_rev) == 2U) {
806 chip_features |= HAL_ATLANTIC_UTILS_CHIP_REVISION_B0 |
807 HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
808 HAL_ATLANTIC_UTILS_CHIP_MIPS |
809 HAL_ATLANTIC_UTILS_CHIP_TPO2 |
810 HAL_ATLANTIC_UTILS_CHIP_RPF2;
811 } else if ((0xFU & mif_rev) == 0xAU) {
812 chip_features |= HAL_ATLANTIC_UTILS_CHIP_REVISION_B1 |
98c4c201
DV
813 HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
814 HAL_ATLANTIC_UTILS_CHIP_MIPS |
815 HAL_ATLANTIC_UTILS_CHIP_TPO2 |
816 HAL_ATLANTIC_UTILS_CHIP_RPF2;
817 }
818
819 *p = chip_features;
820}
821
44e00dd8 822static int hw_atl_fw1x_deinit(struct aq_hw_s *self)
98c4c201 823{
44e00dd8
IR
824 hw_atl_utils_mpi_set_speed(self, 0);
825 hw_atl_utils_mpi_set_state(self, MPI_DEINIT);
7b0c342f 826
98c4c201
DV
827 return 0;
828}
829
65e665e6
IR
830int hw_atl_utils_update_stats(struct aq_hw_s *self)
831{
ce4cdbe4 832 struct aq_stats_s *cs = &self->curr_stats;
7b0c342f 833 struct hw_atl_utils_mbox mbox;
65e665e6 834
65e665e6
IR
835 hw_atl_utils_mpi_read_stats(self, &mbox);
836
1a713f87
IR
837#define AQ_SDELTA(_N_) (self->curr_stats._N_ += \
838 mbox.stats._N_ - self->last_stats._N_)
839
be08d839
IR
840 if (self->aq_link_status.mbps) {
841 AQ_SDELTA(uprc);
842 AQ_SDELTA(mprc);
843 AQ_SDELTA(bprc);
844 AQ_SDELTA(erpt);
845
846 AQ_SDELTA(uptc);
847 AQ_SDELTA(mptc);
848 AQ_SDELTA(bptc);
849 AQ_SDELTA(erpr);
850
851 AQ_SDELTA(ubrc);
852 AQ_SDELTA(ubtc);
853 AQ_SDELTA(mbrc);
854 AQ_SDELTA(mbtc);
855 AQ_SDELTA(bbrc);
856 AQ_SDELTA(bbtc);
857 AQ_SDELTA(dpc);
858 }
65e665e6 859#undef AQ_SDELTA
ce4cdbe4
DB
860
861 cs->dma_pkt_rc = hw_atl_stats_rx_dma_good_pkt_counter_get(self);
862 cs->dma_pkt_tc = hw_atl_stats_tx_dma_good_pkt_counter_get(self);
863 cs->dma_oct_rc = hw_atl_stats_rx_dma_good_octet_counter_get(self);
864 cs->dma_oct_tc = hw_atl_stats_tx_dma_good_octet_counter_get(self);
65e665e6 865
1a713f87 866 memcpy(&self->last_stats, &mbox.stats, sizeof(mbox.stats));
65e665e6
IR
867
868 return 0;
869}
870
be08d839 871struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self)
98c4c201 872{
1a713f87 873 return &self->curr_stats;
98c4c201
DV
874}
875
876static const u32 hw_atl_utils_hw_mac_regs[] = {
877 0x00005580U, 0x00005590U, 0x000055B0U, 0x000055B4U,
878 0x000055C0U, 0x00005B00U, 0x00005B04U, 0x00005B08U,
879 0x00005B0CU, 0x00005B10U, 0x00005B14U, 0x00005B18U,
880 0x00005B1CU, 0x00005B20U, 0x00005B24U, 0x00005B28U,
881 0x00005B2CU, 0x00005B30U, 0x00005B34U, 0x00005B38U,
882 0x00005B3CU, 0x00005B40U, 0x00005B44U, 0x00005B48U,
883 0x00005B4CU, 0x00005B50U, 0x00005B54U, 0x00005B58U,
884 0x00005B5CU, 0x00005B60U, 0x00005B64U, 0x00005B68U,
885 0x00005B6CU, 0x00005B70U, 0x00005B74U, 0x00005B78U,
886 0x00005B7CU, 0x00007C00U, 0x00007C04U, 0x00007C08U,
887 0x00007C0CU, 0x00007C10U, 0x00007C14U, 0x00007C18U,
888 0x00007C1CU, 0x00007C20U, 0x00007C40U, 0x00007C44U,
889 0x00007C48U, 0x00007C4CU, 0x00007C50U, 0x00007C54U,
890 0x00007C58U, 0x00007C5CU, 0x00007C60U, 0x00007C80U,
891 0x00007C84U, 0x00007C88U, 0x00007C8CU, 0x00007C90U,
892 0x00007C94U, 0x00007C98U, 0x00007C9CU, 0x00007CA0U,
893 0x00007CC0U, 0x00007CC4U, 0x00007CC8U, 0x00007CCCU,
894 0x00007CD0U, 0x00007CD4U, 0x00007CD8U, 0x00007CDCU,
895 0x00007CE0U, 0x00000300U, 0x00000304U, 0x00000308U,
896 0x0000030cU, 0x00000310U, 0x00000314U, 0x00000318U,
897 0x0000031cU, 0x00000360U, 0x00000364U, 0x00000368U,
898 0x0000036cU, 0x00000370U, 0x00000374U, 0x00006900U,
899};
900
901int hw_atl_utils_hw_get_regs(struct aq_hw_s *self,
4cbc9f92 902 const struct aq_hw_caps_s *aq_hw_caps,
98c4c201
DV
903 u32 *regs_buff)
904{
905 unsigned int i = 0U;
906
907 for (i = 0; i < aq_hw_caps->mac_regs_count; i++)
908 regs_buff[i] = aq_hw_read_reg(self,
c8c82eb3 909 hw_atl_utils_hw_mac_regs[i]);
7b0c342f 910
98c4c201
DV
911 return 0;
912}
913
914int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version)
915{
916 *fw_version = aq_hw_read_reg(self, 0x18U);
7b0c342f 917
98c4c201
DV
918 return 0;
919}
0c58c35f 920
837c6378
ND
921static int aq_fw1x_set_wake_magic(struct aq_hw_s *self, bool wol_enabled,
922 u8 *mac)
a0da96c0 923{
8f60f762 924 struct hw_atl_utils_fw_rpc *prpc = NULL;
a0da96c0
YE
925 unsigned int rpc_size = 0U;
926 int err = 0;
927
928 err = hw_atl_utils_fw_rpc_wait(self, &prpc);
929 if (err < 0)
930 goto err_exit;
931
932 memset(prpc, 0, sizeof(*prpc));
933
934 if (wol_enabled) {
d993e14b
ND
935 rpc_size = offsetof(struct hw_atl_utils_fw_rpc, msg_wol_add) +
936 sizeof(prpc->msg_wol_add);
937
a0da96c0
YE
938
939 prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD;
d993e14b 940 prpc->msg_wol_add.priority =
a0da96c0 941 HAL_ATLANTIC_UTILS_FW_MSG_WOL_PRIOR;
d993e14b 942 prpc->msg_wol_add.pattern_id =
a0da96c0 943 HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN;
d993e14b 944 prpc->msg_wol_add.packet_type =
a0da96c0
YE
945 HAL_ATLANTIC_UTILS_FW_MSG_WOL_MAG_PKT;
946
d993e14b
ND
947 ether_addr_copy((u8 *)&prpc->msg_wol_add.magic_packet_pattern,
948 mac);
a0da96c0 949 } else {
d993e14b
ND
950 rpc_size = sizeof(prpc->msg_wol_remove) +
951 offsetof(struct hw_atl_utils_fw_rpc, msg_wol_remove);
a0da96c0
YE
952
953 prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL;
d993e14b 954 prpc->msg_wol_add.pattern_id =
a0da96c0
YE
955 HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN;
956 }
957
958 err = hw_atl_utils_fw_rpc_call(self, rpc_size);
959
960err_exit:
961 return err;
962}
963
3d5537f9
WY
964static int aq_fw1x_set_power(struct aq_hw_s *self, unsigned int power_state,
965 u8 *mac)
a0da96c0 966{
8f60f762 967 struct hw_atl_utils_fw_rpc *prpc = NULL;
a0da96c0
YE
968 unsigned int rpc_size = 0U;
969 int err = 0;
970
837c6378
ND
971 if (self->aq_nic_cfg->wol & WAKE_MAGIC) {
972 err = aq_fw1x_set_wake_magic(self, 1, mac);
a0da96c0
YE
973
974 if (err < 0)
975 goto err_exit;
976
977 rpc_size = sizeof(prpc->msg_id) +
978 sizeof(prpc->msg_enable_wakeup);
979
980 err = hw_atl_utils_fw_rpc_wait(self, &prpc);
981
982 if (err < 0)
983 goto err_exit;
984
985 memset(prpc, 0, rpc_size);
986
987 prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP;
988 prpc->msg_enable_wakeup.pattern_mask = 0x00000002;
989
990 err = hw_atl_utils_fw_rpc_call(self, rpc_size);
991 if (err < 0)
992 goto err_exit;
993 }
994 hw_atl_utils_mpi_set_speed(self, 0);
995 hw_atl_utils_mpi_set_state(self, MPI_POWER);
996
997err_exit:
998 return err;
999}
1000
6a7f2277
ND
1001static u32 hw_atl_utils_get_mpi_mbox_tid(struct aq_hw_s *self)
1002{
1003 struct hw_atl_utils_mbox_header mbox;
1004
1005 hw_atl_utils_mpi_read_mbox(self, &mbox);
1006
1007 return mbox.transaction_id;
1008}
1009
1010static u32 hw_atl_utils_mpi_get_state(struct aq_hw_s *self)
1011{
1012 return aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR);
1013}
1014
1015static u32 hw_atl_utils_mif_cmd_get(struct aq_hw_s *self)
1016{
1017 return aq_hw_read_reg(self, HW_ATL_MIF_CMD);
1018}
1019
1020static u32 hw_atl_utils_mif_addr_get(struct aq_hw_s *self)
1021{
1022 return aq_hw_read_reg(self, HW_ATL_MIF_ADDR);
1023}
1024
1025static u32 hw_atl_utils_rpc_state_get(struct aq_hw_s *self)
1026{
1027 return aq_hw_read_reg(self, HW_ATL_RPC_STATE_ADR);
1028}
1029
0c58c35f
IR
1030const struct aq_fw_ops aq_fw_1x_ops = {
1031 .init = hw_atl_utils_mpi_create,
44e00dd8 1032 .deinit = hw_atl_fw1x_deinit,
0c58c35f
IR
1033 .reset = NULL,
1034 .get_mac_permanent = hw_atl_utils_get_mac_permanent,
1035 .set_link_speed = hw_atl_utils_mpi_set_speed,
1036 .set_state = hw_atl_utils_mpi_set_state,
1037 .update_link_status = hw_atl_utils_mpi_get_link_status,
1038 .update_stats = hw_atl_utils_update_stats,
8f894011 1039 .get_phy_temp = NULL,
a0da96c0 1040 .set_power = aq_fw1x_set_power,
92ab6407
YE
1041 .set_eee_rate = NULL,
1042 .get_eee_rate = NULL,
288551de 1043 .set_flow_control = NULL,
910479a9
EP
1044 .send_fw_request = NULL,
1045 .enable_ptp = NULL,
d1287ce4 1046 .led_control = NULL,
0c58c35f 1047};