xref: /dpdk/drivers/net/atlantic/hw_atl/hw_atl_utils.c (revision f665790a5dbad7b645ff46f31d65e977324e7bfc)
186d36773SIgor Russkikh // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
286d36773SIgor Russkikh /* Copyright (C) 2014-2017 aQuantia Corporation. */
386d36773SIgor Russkikh 
486d36773SIgor Russkikh /* File hw_atl_utils.c: Definition of common functions for Atlantic hardware
586d36773SIgor Russkikh  * abstraction layer.
686d36773SIgor Russkikh  */
786d36773SIgor Russkikh 
886d36773SIgor Russkikh #include <stdio.h>
986d36773SIgor Russkikh #include <errno.h>
1086d36773SIgor Russkikh #include <stdint.h>
1186d36773SIgor Russkikh #include <string.h>
1286d36773SIgor Russkikh #include <unistd.h>
1386d36773SIgor Russkikh #include <stdarg.h>
1486d36773SIgor Russkikh #include <inttypes.h>
1586d36773SIgor Russkikh #include <rte_ether.h>
1686d36773SIgor Russkikh #include "../atl_hw_regs.h"
1786d36773SIgor Russkikh 
1886d36773SIgor Russkikh #include "hw_atl_llh.h"
1986d36773SIgor Russkikh #include "hw_atl_llh_internal.h"
2086d36773SIgor Russkikh #include "../atl_logs.h"
2186d36773SIgor Russkikh 
2286d36773SIgor Russkikh #define HW_ATL_UCP_0X370_REG    0x0370U
2386d36773SIgor Russkikh 
2486d36773SIgor Russkikh #define HW_ATL_MIF_CMD          0x0200U
2586d36773SIgor Russkikh #define HW_ATL_MIF_ADDR         0x0208U
2686d36773SIgor Russkikh #define HW_ATL_MIF_VAL          0x020CU
2786d36773SIgor Russkikh 
2886d36773SIgor Russkikh #define HW_ATL_FW_SM_RAM        0x2U
2986d36773SIgor Russkikh #define HW_ATL_MPI_FW_VERSION	0x18
3086d36773SIgor Russkikh #define HW_ATL_MPI_CONTROL_ADR  0x0368U
3186d36773SIgor Russkikh #define HW_ATL_MPI_STATE_ADR    0x036CU
3286d36773SIgor Russkikh 
3386d36773SIgor Russkikh #define HW_ATL_MPI_STATE_MSK      0x00FFU
3486d36773SIgor Russkikh #define HW_ATL_MPI_STATE_SHIFT    0U
3586d36773SIgor Russkikh #define HW_ATL_MPI_SPEED_MSK      0x00FF0000U
3686d36773SIgor Russkikh #define HW_ATL_MPI_SPEED_SHIFT    16U
3786d36773SIgor Russkikh #define HW_ATL_MPI_DIRTY_WAKE_MSK 0x02000000U
3886d36773SIgor Russkikh 
3986d36773SIgor Russkikh #define HW_ATL_MPI_DAISY_CHAIN_STATUS	0x704
4086d36773SIgor Russkikh #define HW_ATL_MPI_BOOT_EXIT_CODE	0x388
4186d36773SIgor Russkikh 
4286d36773SIgor Russkikh #define HW_ATL_MAC_PHY_CONTROL	0x4000
4386d36773SIgor Russkikh #define HW_ATL_MAC_PHY_MPI_RESET_BIT 0x1D
4486d36773SIgor Russkikh 
4586d36773SIgor Russkikh #define HW_ATL_FW_VER_1X 0x01050006U
4686d36773SIgor Russkikh #define HW_ATL_FW_VER_2X 0x02000000U
4786d36773SIgor Russkikh #define HW_ATL_FW_VER_3X 0x03000000U
4886d36773SIgor Russkikh 
4986d36773SIgor Russkikh #define FORCE_FLASHLESS 0
5086d36773SIgor Russkikh 
5186d36773SIgor Russkikh static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual);
5286d36773SIgor Russkikh static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
5386d36773SIgor Russkikh 				enum hal_atl_utils_fw_state_e state);
5486d36773SIgor Russkikh 
5586d36773SIgor Russkikh 
5686d36773SIgor Russkikh int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
5786d36773SIgor Russkikh {
5886d36773SIgor Russkikh 	int err = 0;
5986d36773SIgor Russkikh 
6086d36773SIgor Russkikh 	err = hw_atl_utils_soft_reset(self);
6186d36773SIgor Russkikh 	if (err)
6286d36773SIgor Russkikh 		return err;
6386d36773SIgor Russkikh 
6486d36773SIgor Russkikh 	hw_atl_utils_hw_chip_features_init(self,
6586d36773SIgor Russkikh 					   &self->chip_features);
6686d36773SIgor Russkikh 
6786d36773SIgor Russkikh 	hw_atl_utils_get_fw_version(self, &self->fw_ver_actual);
6886d36773SIgor Russkikh 
6986d36773SIgor Russkikh 	if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X,
7086d36773SIgor Russkikh 				   self->fw_ver_actual) == 0) {
7186d36773SIgor Russkikh 		*fw_ops = &aq_fw_1x_ops;
7286d36773SIgor Russkikh 	} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X,
7386d36773SIgor Russkikh 					self->fw_ver_actual) == 0) {
7486d36773SIgor Russkikh 		*fw_ops = &aq_fw_2x_ops;
7586d36773SIgor Russkikh 	} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X,
7686d36773SIgor Russkikh 					self->fw_ver_actual) == 0) {
7786d36773SIgor Russkikh 		*fw_ops = &aq_fw_2x_ops;
7886d36773SIgor Russkikh 	} else {
79*f665790aSDavid Marchand 		PMD_DRV_LOG(ERR, "Bad FW version detected: %x",
8086d36773SIgor Russkikh 			  self->fw_ver_actual);
8186d36773SIgor Russkikh 		return -EOPNOTSUPP;
8286d36773SIgor Russkikh 	}
8386d36773SIgor Russkikh 	self->aq_fw_ops = *fw_ops;
8486d36773SIgor Russkikh 	err = self->aq_fw_ops->init(self);
8586d36773SIgor Russkikh 	return err;
8686d36773SIgor Russkikh }
8786d36773SIgor Russkikh 
8886d36773SIgor Russkikh static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self)
8986d36773SIgor Russkikh {
9086d36773SIgor Russkikh 	u32 gsr, val;
9186d36773SIgor Russkikh 	int k = 0;
9286d36773SIgor Russkikh 
9386d36773SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x40e1);
9486d36773SIgor Russkikh 	AQ_HW_SLEEP(50);
9586d36773SIgor Russkikh 
9686d36773SIgor Russkikh 	/* Cleanup SPI */
9786d36773SIgor Russkikh 	val = aq_hw_read_reg(self, 0x53C);
9886d36773SIgor Russkikh 	aq_hw_write_reg(self, 0x53C, val | 0x10);
9986d36773SIgor Russkikh 
10086d36773SIgor Russkikh 	gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
10186d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000);
10286d36773SIgor Russkikh 
10386d36773SIgor Russkikh 	/* Kickstart MAC */
10486d36773SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x80e0);
10586d36773SIgor Russkikh 	aq_hw_write_reg(self, 0x32a8, 0x0);
10686d36773SIgor Russkikh 	aq_hw_write_reg(self, 0x520, 0x1);
10786d36773SIgor Russkikh 
10886d36773SIgor Russkikh 	/* Reset SPI again because of possible interrupted SPI burst */
10986d36773SIgor Russkikh 	val = aq_hw_read_reg(self, 0x53C);
11086d36773SIgor Russkikh 	aq_hw_write_reg(self, 0x53C, val | 0x10);
11186d36773SIgor Russkikh 	AQ_HW_SLEEP(10);
11286d36773SIgor Russkikh 	/* Clear SPI reset state */
11386d36773SIgor Russkikh 	aq_hw_write_reg(self, 0x53C, val & ~0x10);
11486d36773SIgor Russkikh 
11586d36773SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x180e0);
11686d36773SIgor Russkikh 
11786d36773SIgor Russkikh 	for (k = 0; k < 1000; k++) {
11886d36773SIgor Russkikh 		u32 flb_status = aq_hw_read_reg(self,
11986d36773SIgor Russkikh 						HW_ATL_MPI_DAISY_CHAIN_STATUS);
12086d36773SIgor Russkikh 
12186d36773SIgor Russkikh 		flb_status = flb_status & 0x10;
12286d36773SIgor Russkikh 		if (flb_status)
12386d36773SIgor Russkikh 			break;
12486d36773SIgor Russkikh 		AQ_HW_SLEEP(10);
12586d36773SIgor Russkikh 	}
12686d36773SIgor Russkikh 	if (k == 1000) {
127*f665790aSDavid Marchand 		PMD_DRV_LOG(ERR, "MAC kickstart failed");
12886d36773SIgor Russkikh 		return -EIO;
12986d36773SIgor Russkikh 	}
13086d36773SIgor Russkikh 
13186d36773SIgor Russkikh 	/* FW reset */
13286d36773SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x80e0);
13386d36773SIgor Russkikh 	AQ_HW_SLEEP(50);
13486d36773SIgor Russkikh 	aq_hw_write_reg(self, 0x3a0, 0x1);
13586d36773SIgor Russkikh 
13686d36773SIgor Russkikh 	/* Kickstart PHY - skipped */
13786d36773SIgor Russkikh 
13886d36773SIgor Russkikh 	/* Global software reset*/
13986d36773SIgor Russkikh 	hw_atl_rx_rx_reg_res_dis_set(self, 0U);
14086d36773SIgor Russkikh 	hw_atl_tx_tx_reg_res_dis_set(self, 0U);
14186d36773SIgor Russkikh 	aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL,
14286d36773SIgor Russkikh 			    BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT),
14386d36773SIgor Russkikh 			    HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0);
14486d36773SIgor Russkikh 	gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
14586d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000);
14686d36773SIgor Russkikh 
14786d36773SIgor Russkikh 	for (k = 0; k < 1000; k++) {
14886d36773SIgor Russkikh 		u32 fw_state = aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION);
14986d36773SIgor Russkikh 
15086d36773SIgor Russkikh 		if (fw_state)
15186d36773SIgor Russkikh 			break;
15286d36773SIgor Russkikh 		AQ_HW_SLEEP(10);
15386d36773SIgor Russkikh 	}
15486d36773SIgor Russkikh 	if (k == 1000) {
155*f665790aSDavid Marchand 		PMD_DRV_LOG(ERR, "FW kickstart failed");
15686d36773SIgor Russkikh 		return -EIO;
15786d36773SIgor Russkikh 	}
15886d36773SIgor Russkikh 	/* Old FW requires fixed delay after init */
15986d36773SIgor Russkikh 	AQ_HW_SLEEP(15);
16086d36773SIgor Russkikh 
16186d36773SIgor Russkikh 	return 0;
16286d36773SIgor Russkikh }
16386d36773SIgor Russkikh 
16486d36773SIgor Russkikh static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self)
16586d36773SIgor Russkikh {
16686d36773SIgor Russkikh 	u32 gsr, val, rbl_status;
16786d36773SIgor Russkikh 	int k;
16886d36773SIgor Russkikh 
16986d36773SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x40e1);
17086d36773SIgor Russkikh 	aq_hw_write_reg(self, 0x3a0, 0x1);
17186d36773SIgor Russkikh 	aq_hw_write_reg(self, 0x32a8, 0x0);
17286d36773SIgor Russkikh 
17386d36773SIgor Russkikh 	/* Alter RBL status */
17486d36773SIgor Russkikh 	aq_hw_write_reg(self, 0x388, 0xDEAD);
17586d36773SIgor Russkikh 
17686d36773SIgor Russkikh 	/* Cleanup SPI */
17786d36773SIgor Russkikh 	val = aq_hw_read_reg(self, 0x53C);
17886d36773SIgor Russkikh 	aq_hw_write_reg(self, 0x53C, val | 0x10);
17986d36773SIgor Russkikh 
18086d36773SIgor Russkikh 	/* Global software reset*/
18186d36773SIgor Russkikh 	hw_atl_rx_rx_reg_res_dis_set(self, 0U);
18286d36773SIgor Russkikh 	hw_atl_tx_tx_reg_res_dis_set(self, 0U);
18386d36773SIgor Russkikh 	aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL,
18486d36773SIgor Russkikh 			    BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT),
18586d36773SIgor Russkikh 			    HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0);
18686d36773SIgor Russkikh 	gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
18786d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR,
18886d36773SIgor Russkikh 			(gsr & 0xFFFFBFFF) | 0x8000);
18986d36773SIgor Russkikh 
19086d36773SIgor Russkikh 	if (FORCE_FLASHLESS)
19186d36773SIgor Russkikh 		aq_hw_write_reg(self, 0x534, 0x0);
19286d36773SIgor Russkikh 
19386d36773SIgor Russkikh 	aq_hw_write_reg(self, 0x404, 0x40e0);
19486d36773SIgor Russkikh 
19586d36773SIgor Russkikh 	/* Wait for RBL boot */
19686d36773SIgor Russkikh 	for (k = 0; k < 1000; k++) {
19786d36773SIgor Russkikh 		rbl_status = aq_hw_read_reg(self, 0x388) & 0xFFFF;
19886d36773SIgor Russkikh 		if (rbl_status && rbl_status != 0xDEAD)
19986d36773SIgor Russkikh 			break;
20086d36773SIgor Russkikh 		AQ_HW_SLEEP(10);
20186d36773SIgor Russkikh 	}
20286d36773SIgor Russkikh 	if (!rbl_status || rbl_status == 0xDEAD) {
20386d36773SIgor Russkikh 		PMD_DRV_LOG(ERR, "RBL Restart failed");
20486d36773SIgor Russkikh 		return -EIO;
20586d36773SIgor Russkikh 	}
20686d36773SIgor Russkikh 
20786d36773SIgor Russkikh 	/* Restore NVR */
20886d36773SIgor Russkikh 	if (FORCE_FLASHLESS)
20986d36773SIgor Russkikh 		aq_hw_write_reg(self, 0x534, 0xA0);
21086d36773SIgor Russkikh 
21186d36773SIgor Russkikh 	if (rbl_status == 0xF1A7) {
212*f665790aSDavid Marchand 		PMD_DRV_LOG(ERR, "No FW detected. Dynamic FW load not implemented");
21386d36773SIgor Russkikh 		return -EOPNOTSUPP;
21486d36773SIgor Russkikh 	}
21586d36773SIgor Russkikh 
21686d36773SIgor Russkikh 	for (k = 0; k < 1000; k++) {
21786d36773SIgor Russkikh 		u32 fw_state = aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION);
21886d36773SIgor Russkikh 
21986d36773SIgor Russkikh 		if (fw_state)
22086d36773SIgor Russkikh 			break;
22186d36773SIgor Russkikh 		AQ_HW_SLEEP(10);
22286d36773SIgor Russkikh 	}
22386d36773SIgor Russkikh 	if (k == 1000) {
224*f665790aSDavid Marchand 		PMD_DRV_LOG(ERR, "FW kickstart failed");
22586d36773SIgor Russkikh 		return -EIO;
22686d36773SIgor Russkikh 	}
22786d36773SIgor Russkikh 	/* Old FW requires fixed delay after init */
22886d36773SIgor Russkikh 	AQ_HW_SLEEP(15);
22986d36773SIgor Russkikh 
23086d36773SIgor Russkikh 	return 0;
23186d36773SIgor Russkikh }
23286d36773SIgor Russkikh 
23386d36773SIgor Russkikh int hw_atl_utils_soft_reset(struct aq_hw_s *self)
23486d36773SIgor Russkikh {
23586d36773SIgor Russkikh 	int err = 0;
23686d36773SIgor Russkikh 	int k;
23786d36773SIgor Russkikh 	u32 boot_exit_code = 0;
23886d36773SIgor Russkikh 
23986d36773SIgor Russkikh 	for (k = 0; k < 1000; ++k) {
24086d36773SIgor Russkikh 		u32 flb_status = aq_hw_read_reg(self,
24186d36773SIgor Russkikh 						HW_ATL_MPI_DAISY_CHAIN_STATUS);
24286d36773SIgor Russkikh 		boot_exit_code = aq_hw_read_reg(self,
24386d36773SIgor Russkikh 						HW_ATL_MPI_BOOT_EXIT_CODE);
24486d36773SIgor Russkikh 		if (flb_status != 0x06000000 || boot_exit_code != 0)
24586d36773SIgor Russkikh 			break;
24686d36773SIgor Russkikh 	}
24786d36773SIgor Russkikh 
24886d36773SIgor Russkikh 	if (k == 1000) {
249*f665790aSDavid Marchand 		PMD_DRV_LOG(ERR, "Neither RBL nor FLB firmware started");
25086d36773SIgor Russkikh 		return -EOPNOTSUPP;
25186d36773SIgor Russkikh 	}
25286d36773SIgor Russkikh 
25386d36773SIgor Russkikh 	self->rbl_enabled = (boot_exit_code != 0);
25486d36773SIgor Russkikh 
25586d36773SIgor Russkikh 	/* FW 1.x may bootup in an invalid POWER state (WOL feature).
25686d36773SIgor Russkikh 	 * We should work around this by forcing its state back to DEINIT
25786d36773SIgor Russkikh 	 */
25886d36773SIgor Russkikh 	if (!hw_atl_utils_ver_match(HW_ATL_FW_VER_1X,
25986d36773SIgor Russkikh 				    aq_hw_read_reg(self,
26086d36773SIgor Russkikh 						   HW_ATL_MPI_FW_VERSION))) {
26186d36773SIgor Russkikh 		hw_atl_utils_mpi_set_state(self, MPI_DEINIT);
26286d36773SIgor Russkikh 		AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR) &
26386d36773SIgor Russkikh 			       HW_ATL_MPI_STATE_MSK) == MPI_DEINIT,
26486d36773SIgor Russkikh 			       10, 1000U);
26586d36773SIgor Russkikh 	}
26686d36773SIgor Russkikh 
26786d36773SIgor Russkikh 	if (self->rbl_enabled)
26886d36773SIgor Russkikh 		err = hw_atl_utils_soft_reset_rbl(self);
26986d36773SIgor Russkikh 	else
27086d36773SIgor Russkikh 		err = hw_atl_utils_soft_reset_flb(self);
27186d36773SIgor Russkikh 
27286d36773SIgor Russkikh 	return err;
27386d36773SIgor Russkikh }
27486d36773SIgor Russkikh 
27586d36773SIgor Russkikh int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
27686d36773SIgor Russkikh 				  u32 *p, u32 cnt)
27786d36773SIgor Russkikh {
27886d36773SIgor Russkikh 	int err = 0;
27986d36773SIgor Russkikh 
28086d36773SIgor Russkikh 	AQ_HW_WAIT_FOR(hw_atl_reg_glb_cpu_sem_get(self,
28186d36773SIgor Russkikh 						  HW_ATL_FW_SM_RAM) == 1U,
28286d36773SIgor Russkikh 						  1U, 10000U);
28386d36773SIgor Russkikh 
28486d36773SIgor Russkikh 	if (err < 0) {
28586d36773SIgor Russkikh 		bool is_locked;
28686d36773SIgor Russkikh 
28786d36773SIgor Russkikh 		hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
28886d36773SIgor Russkikh 		is_locked = hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM);
28986d36773SIgor Russkikh 		if (!is_locked) {
29086d36773SIgor Russkikh 			err = -ETIMEDOUT;
29186d36773SIgor Russkikh 			goto err_exit;
29286d36773SIgor Russkikh 		}
29386d36773SIgor Russkikh 	}
29486d36773SIgor Russkikh 
29586d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_MIF_ADDR, a);
29686d36773SIgor Russkikh 
29786d36773SIgor Russkikh 	for (++cnt; --cnt && !err;) {
29886d36773SIgor Russkikh 		aq_hw_write_reg(self, HW_ATL_MIF_CMD, 0x00008000U);
29986d36773SIgor Russkikh 
30086d36773SIgor Russkikh 		if (IS_CHIP_FEATURE(REVISION_B1))
30186d36773SIgor Russkikh 			AQ_HW_WAIT_FOR(a != aq_hw_read_reg(self,
30286d36773SIgor Russkikh 							   HW_ATL_MIF_ADDR),
30386d36773SIgor Russkikh 				       1, 1000U);
30486d36773SIgor Russkikh 		else
30586d36773SIgor Russkikh 			AQ_HW_WAIT_FOR(!(0x100 & aq_hw_read_reg(self,
30686d36773SIgor Russkikh 							   HW_ATL_MIF_CMD)),
30786d36773SIgor Russkikh 				       1, 1000U);
308f73061d5SPavel Belous 		if (err) {
309f73061d5SPavel Belous 			err = -ETIMEDOUT;
310f73061d5SPavel Belous 			goto err_exit;
311f73061d5SPavel Belous 		}
31286d36773SIgor Russkikh 
31386d36773SIgor Russkikh 		*(p++) = aq_hw_read_reg(self, HW_ATL_MIF_VAL);
31486d36773SIgor Russkikh 		a += 4;
31586d36773SIgor Russkikh 	}
31686d36773SIgor Russkikh 
31786d36773SIgor Russkikh 	hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
31886d36773SIgor Russkikh 
31986d36773SIgor Russkikh err_exit:
32086d36773SIgor Russkikh 	return err;
32186d36773SIgor Russkikh }
32286d36773SIgor Russkikh 
32386d36773SIgor Russkikh int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p,
32486d36773SIgor Russkikh 					 u32 cnt)
32586d36773SIgor Russkikh {
32686d36773SIgor Russkikh 	int err = 0;
32786d36773SIgor Russkikh 	bool is_locked;
32886d36773SIgor Russkikh 
32986d36773SIgor Russkikh 	is_locked = hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM);
33086d36773SIgor Russkikh 	if (!is_locked) {
33186d36773SIgor Russkikh 		err = -ETIMEDOUT;
33286d36773SIgor Russkikh 		goto err_exit;
33386d36773SIgor Russkikh 	}
33486d36773SIgor Russkikh 	if (IS_CHIP_FEATURE(REVISION_B1)) {
3358fd8aa74SPavel Belous 		u32 mbox_offset = (a - self->rpc_addr) / sizeof(u32);
3368fd8aa74SPavel Belous 		u32 data_offset = 0;
33786d36773SIgor Russkikh 
3388fd8aa74SPavel Belous 		for (; data_offset < cnt; ++mbox_offset, ++data_offset) {
3398fd8aa74SPavel Belous 			aq_hw_write_reg(self, 0x328, p[data_offset]);
34086d36773SIgor Russkikh 			aq_hw_write_reg(self, 0x32C,
3418fd8aa74SPavel Belous 				(0x80000000 | (0xFFFF & (mbox_offset * 4))));
34286d36773SIgor Russkikh 			hw_atl_mcp_up_force_intr_set(self, 1);
34386d36773SIgor Russkikh 			/* 1000 times by 10us = 10ms */
34486d36773SIgor Russkikh 			AQ_HW_WAIT_FOR((aq_hw_read_reg(self,
34586d36773SIgor Russkikh 					0x32C) & 0xF0000000) != 0x80000000,
34686d36773SIgor Russkikh 					10, 1000);
34786d36773SIgor Russkikh 		}
34886d36773SIgor Russkikh 	} else {
34986d36773SIgor Russkikh 		u32 offset = 0;
35086d36773SIgor Russkikh 
35186d36773SIgor Russkikh 		aq_hw_write_reg(self, 0x208, a);
35286d36773SIgor Russkikh 
35386d36773SIgor Russkikh 		for (; offset < cnt; ++offset) {
35486d36773SIgor Russkikh 			aq_hw_write_reg(self, 0x20C, p[offset]);
35586d36773SIgor Russkikh 			aq_hw_write_reg(self, 0x200, 0xC000);
35686d36773SIgor Russkikh 
35786d36773SIgor Russkikh 			AQ_HW_WAIT_FOR((aq_hw_read_reg(self, 0x200U)
35886d36773SIgor Russkikh 					& 0x100) == 0, 10, 1000);
35986d36773SIgor Russkikh 		}
36086d36773SIgor Russkikh 	}
36186d36773SIgor Russkikh 
36286d36773SIgor Russkikh 	hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
36386d36773SIgor Russkikh 
36486d36773SIgor Russkikh err_exit:
36586d36773SIgor Russkikh 	return err;
36686d36773SIgor Russkikh }
36786d36773SIgor Russkikh 
36886d36773SIgor Russkikh static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual)
36986d36773SIgor Russkikh {
37086d36773SIgor Russkikh 	int err = 0;
37186d36773SIgor Russkikh 	const u32 dw_major_mask = 0xff000000U;
37286d36773SIgor Russkikh 	const u32 dw_minor_mask = 0x00ffffffU;
37386d36773SIgor Russkikh 
37486d36773SIgor Russkikh 	err = (dw_major_mask & (ver_expected ^ ver_actual)) ? -EOPNOTSUPP : 0;
37586d36773SIgor Russkikh 	if (err < 0)
37686d36773SIgor Russkikh 		goto err_exit;
37786d36773SIgor Russkikh 	err = ((dw_minor_mask & ver_expected) > (dw_minor_mask & ver_actual)) ?
37886d36773SIgor Russkikh 		-EOPNOTSUPP : 0;
37986d36773SIgor Russkikh err_exit:
38086d36773SIgor Russkikh 	return err;
38186d36773SIgor Russkikh }
38286d36773SIgor Russkikh 
38386d36773SIgor Russkikh static int hw_atl_utils_init_ucp(struct aq_hw_s *self)
38486d36773SIgor Russkikh {
38586d36773SIgor Russkikh 	int err = 0;
38686d36773SIgor Russkikh 
38786d36773SIgor Russkikh 	if (!aq_hw_read_reg(self, 0x370U)) {
38886d36773SIgor Russkikh 		unsigned int rnd = (uint32_t)rte_rand();
38986d36773SIgor Russkikh 		unsigned int ucp_0x370 = 0U;
39086d36773SIgor Russkikh 
39186d36773SIgor Russkikh 		ucp_0x370 = 0x02020202U | (0xFEFEFEFEU & rnd);
39286d36773SIgor Russkikh 		aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
39386d36773SIgor Russkikh 	}
39486d36773SIgor Russkikh 
39586d36773SIgor Russkikh 	hw_atl_reg_glb_cpu_scratch_scp_set(self, 0x00000000U, 25U);
39686d36773SIgor Russkikh 
39786d36773SIgor Russkikh 	/* check 10 times by 1ms */
39886d36773SIgor Russkikh 	AQ_HW_WAIT_FOR(0U != (self->mbox_addr =
39986d36773SIgor Russkikh 		       aq_hw_read_reg(self, 0x360U)), 1000U, 10U);
40086d36773SIgor Russkikh 	AQ_HW_WAIT_FOR(0U != (self->rpc_addr =
40186d36773SIgor Russkikh 		       aq_hw_read_reg(self, 0x334U)), 1000U, 100U);
40286d36773SIgor Russkikh 
40386d36773SIgor Russkikh 	return err;
40486d36773SIgor Russkikh }
40586d36773SIgor Russkikh 
40686d36773SIgor Russkikh #define HW_ATL_RPC_CONTROL_ADR 0x0338U
40786d36773SIgor Russkikh #define HW_ATL_RPC_STATE_ADR   0x033CU
40886d36773SIgor Russkikh 
40986d36773SIgor Russkikh struct aq_hw_atl_utils_fw_rpc_tid_s {
41086d36773SIgor Russkikh 	union {
41186d36773SIgor Russkikh 		u32 val;
41286d36773SIgor Russkikh 		struct {
41386d36773SIgor Russkikh 			u16 tid;
41486d36773SIgor Russkikh 			u16 len;
41586d36773SIgor Russkikh 		};
41686d36773SIgor Russkikh 	};
41786d36773SIgor Russkikh };
41886d36773SIgor Russkikh 
41986d36773SIgor Russkikh #define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL)
42086d36773SIgor Russkikh 
42186d36773SIgor Russkikh int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size)
42286d36773SIgor Russkikh {
42386d36773SIgor Russkikh 	int err = 0;
42486d36773SIgor Russkikh 	struct aq_hw_atl_utils_fw_rpc_tid_s sw;
42586d36773SIgor Russkikh 
42686d36773SIgor Russkikh 	if (!IS_CHIP_FEATURE(MIPS)) {
42786d36773SIgor Russkikh 		err = -1;
42886d36773SIgor Russkikh 		goto err_exit;
42986d36773SIgor Russkikh 	}
43086d36773SIgor Russkikh 	err = hw_atl_utils_fw_upload_dwords(self, self->rpc_addr,
43186d36773SIgor Russkikh 					    (u32 *)(void *)&self->rpc,
43286d36773SIgor Russkikh 					    (rpc_size + sizeof(u32) -
43386d36773SIgor Russkikh 					    sizeof(u8)) / sizeof(u32));
43486d36773SIgor Russkikh 	if (err < 0)
43586d36773SIgor Russkikh 		goto err_exit;
43686d36773SIgor Russkikh 
43786d36773SIgor Russkikh 	sw.tid = 0xFFFFU & (++self->rpc_tid);
43886d36773SIgor Russkikh 	sw.len = (u16)rpc_size;
43986d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_RPC_CONTROL_ADR, sw.val);
44086d36773SIgor Russkikh 
44186d36773SIgor Russkikh err_exit:
44286d36773SIgor Russkikh 	return err;
44386d36773SIgor Russkikh }
44486d36773SIgor Russkikh 
44586d36773SIgor Russkikh int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
44686d36773SIgor Russkikh 				    struct hw_aq_atl_utils_fw_rpc **rpc)
44786d36773SIgor Russkikh {
44886d36773SIgor Russkikh 	int err = 0;
44986d36773SIgor Russkikh 	struct aq_hw_atl_utils_fw_rpc_tid_s sw;
45086d36773SIgor Russkikh 	struct aq_hw_atl_utils_fw_rpc_tid_s fw;
45186d36773SIgor Russkikh 
45286d36773SIgor Russkikh 	do {
45386d36773SIgor Russkikh 		sw.val = aq_hw_read_reg(self, HW_ATL_RPC_CONTROL_ADR);
45486d36773SIgor Russkikh 
45586d36773SIgor Russkikh 		self->rpc_tid = sw.tid;
45686d36773SIgor Russkikh 
45786d36773SIgor Russkikh 		AQ_HW_WAIT_FOR(sw.tid ==
45886d36773SIgor Russkikh 				(fw.val =
45986d36773SIgor Russkikh 				aq_hw_read_reg(self, HW_ATL_RPC_STATE_ADR),
46086d36773SIgor Russkikh 				fw.tid), 1000U, 100U);
46186d36773SIgor Russkikh 		if (err < 0)
46286d36773SIgor Russkikh 			goto err_exit;
46386d36773SIgor Russkikh 
46486d36773SIgor Russkikh 		if (fw.len == 0xFFFFU) {
46586d36773SIgor Russkikh 			err = hw_atl_utils_fw_rpc_call(self, sw.len);
46686d36773SIgor Russkikh 			if (err < 0)
46786d36773SIgor Russkikh 				goto err_exit;
46886d36773SIgor Russkikh 		}
46986d36773SIgor Russkikh 	} while (sw.tid != fw.tid || 0xFFFFU == fw.len);
47086d36773SIgor Russkikh 
47186d36773SIgor Russkikh 	if (rpc) {
47286d36773SIgor Russkikh 		if (fw.len) {
47386d36773SIgor Russkikh 			err =
47486d36773SIgor Russkikh 			hw_atl_utils_fw_downld_dwords(self,
47586d36773SIgor Russkikh 						      self->rpc_addr,
47686d36773SIgor Russkikh 						      (u32 *)(void *)
47786d36773SIgor Russkikh 						      &self->rpc,
47886d36773SIgor Russkikh 						      (fw.len + sizeof(u32) -
47986d36773SIgor Russkikh 						      sizeof(u8)) /
48086d36773SIgor Russkikh 						      sizeof(u32));
48186d36773SIgor Russkikh 			if (err < 0)
48286d36773SIgor Russkikh 				goto err_exit;
48386d36773SIgor Russkikh 		}
48486d36773SIgor Russkikh 
48586d36773SIgor Russkikh 		*rpc = &self->rpc;
48686d36773SIgor Russkikh 	}
48786d36773SIgor Russkikh 
48886d36773SIgor Russkikh err_exit:
48986d36773SIgor Russkikh 	return err;
49086d36773SIgor Russkikh }
49186d36773SIgor Russkikh 
49286d36773SIgor Russkikh static int hw_atl_utils_mpi_create(struct aq_hw_s *self)
49386d36773SIgor Russkikh {
49486d36773SIgor Russkikh 	int err = 0;
49586d36773SIgor Russkikh 
49686d36773SIgor Russkikh 	err = hw_atl_utils_init_ucp(self);
49786d36773SIgor Russkikh 	if (err < 0)
49886d36773SIgor Russkikh 		goto err_exit;
49986d36773SIgor Russkikh 
50086d36773SIgor Russkikh 	err = hw_atl_utils_fw_rpc_init(self);
50186d36773SIgor Russkikh 	if (err < 0)
50286d36773SIgor Russkikh 		goto err_exit;
50386d36773SIgor Russkikh 
50486d36773SIgor Russkikh err_exit:
50586d36773SIgor Russkikh 	return err;
50686d36773SIgor Russkikh }
50786d36773SIgor Russkikh 
50886d36773SIgor Russkikh int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self,
50986d36773SIgor Russkikh 			       struct hw_aq_atl_utils_mbox_header *pmbox)
51086d36773SIgor Russkikh {
51186d36773SIgor Russkikh 	return hw_atl_utils_fw_downld_dwords(self,
51286d36773SIgor Russkikh 				      self->mbox_addr,
51386d36773SIgor Russkikh 				      (u32 *)(void *)pmbox,
51486d36773SIgor Russkikh 				      sizeof(*pmbox) / sizeof(u32));
51586d36773SIgor Russkikh }
51686d36773SIgor Russkikh 
51786d36773SIgor Russkikh void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
51886d36773SIgor Russkikh 				 struct hw_aq_atl_utils_mbox *pmbox)
51986d36773SIgor Russkikh {
52086d36773SIgor Russkikh 	int err = 0;
52186d36773SIgor Russkikh 
52286d36773SIgor Russkikh 	err = hw_atl_utils_fw_downld_dwords(self,
52386d36773SIgor Russkikh 					    self->mbox_addr,
52486d36773SIgor Russkikh 					    (u32 *)(void *)pmbox,
52586d36773SIgor Russkikh 					    sizeof(*pmbox) / sizeof(u32));
52686d36773SIgor Russkikh 	if (err < 0)
52786d36773SIgor Russkikh 		goto err_exit;
52886d36773SIgor Russkikh 
52986d36773SIgor Russkikh 	if (IS_CHIP_FEATURE(REVISION_A0)) {
53086d36773SIgor Russkikh 		unsigned int mtu = 1514;
53186d36773SIgor Russkikh 		pmbox->stats.ubrc = pmbox->stats.uprc * mtu;
53286d36773SIgor Russkikh 		pmbox->stats.ubtc = pmbox->stats.uptc * mtu;
53386d36773SIgor Russkikh 	} else {
53486d36773SIgor Russkikh 		pmbox->stats.dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self);
53586d36773SIgor Russkikh 	}
53686d36773SIgor Russkikh 
53786d36773SIgor Russkikh err_exit:;
53886d36773SIgor Russkikh }
53986d36773SIgor Russkikh 
54086d36773SIgor Russkikh static
54186d36773SIgor Russkikh int hw_atl_utils_mpi_set_speed(struct aq_hw_s *self, u32 speed)
54286d36773SIgor Russkikh {
54386d36773SIgor Russkikh 	u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR);
54486d36773SIgor Russkikh 
54586d36773SIgor Russkikh 	val = val & ~HW_ATL_MPI_SPEED_MSK;
54686d36773SIgor Russkikh 	val |= speed << HW_ATL_MPI_SPEED_SHIFT;
54786d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val);
54886d36773SIgor Russkikh 
54986d36773SIgor Russkikh 	return 0;
55086d36773SIgor Russkikh }
55186d36773SIgor Russkikh 
55286d36773SIgor Russkikh int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
55386d36773SIgor Russkikh 				enum hal_atl_utils_fw_state_e state)
55486d36773SIgor Russkikh {
55586d36773SIgor Russkikh 	int err = 0;
55686d36773SIgor Russkikh 	u32 transaction_id = 0;
55786d36773SIgor Russkikh 	struct hw_aq_atl_utils_mbox_header mbox;
55886d36773SIgor Russkikh 	u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR);
55986d36773SIgor Russkikh 
56086d36773SIgor Russkikh 	if (state == MPI_RESET) {
56186d36773SIgor Russkikh 		hw_atl_utils_mpi_read_mbox(self, &mbox);
56286d36773SIgor Russkikh 
56386d36773SIgor Russkikh 		transaction_id = mbox.transaction_id;
56486d36773SIgor Russkikh 
56586d36773SIgor Russkikh 		AQ_HW_WAIT_FOR(transaction_id !=
56686d36773SIgor Russkikh 				(hw_atl_utils_mpi_read_mbox(self, &mbox),
56786d36773SIgor Russkikh 				 mbox.transaction_id),
56886d36773SIgor Russkikh 			       1000U, 100U);
56986d36773SIgor Russkikh 		if (err < 0)
57086d36773SIgor Russkikh 			goto err_exit;
57186d36773SIgor Russkikh 	}
57286d36773SIgor Russkikh 	/* On interface DEINIT we disable DW (raise bit)
57386d36773SIgor Russkikh 	 * Otherwise enable DW (clear bit)
57486d36773SIgor Russkikh 	 */
57586d36773SIgor Russkikh 	if (state == MPI_DEINIT || state == MPI_POWER)
57686d36773SIgor Russkikh 		val |= HW_ATL_MPI_DIRTY_WAKE_MSK;
57786d36773SIgor Russkikh 	else
57886d36773SIgor Russkikh 		val &= ~HW_ATL_MPI_DIRTY_WAKE_MSK;
57986d36773SIgor Russkikh 
58086d36773SIgor Russkikh 	/* Set new state bits */
58186d36773SIgor Russkikh 	val = val & ~HW_ATL_MPI_STATE_MSK;
58286d36773SIgor Russkikh 	val |= state & HW_ATL_MPI_STATE_MSK;
58386d36773SIgor Russkikh 
58486d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val);
58586d36773SIgor Russkikh err_exit:
58686d36773SIgor Russkikh 	return err;
58786d36773SIgor Russkikh }
58886d36773SIgor Russkikh 
58986d36773SIgor Russkikh int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self)
59086d36773SIgor Russkikh {
59186d36773SIgor Russkikh 	u32 cp0x036C = aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR);
59286d36773SIgor Russkikh 	u32 link_speed_mask = cp0x036C >> HW_ATL_MPI_SPEED_SHIFT;
59386d36773SIgor Russkikh 	struct aq_hw_link_status_s *link_status = &self->aq_link_status;
59486d36773SIgor Russkikh 
59586d36773SIgor Russkikh 	if (!link_speed_mask) {
59686d36773SIgor Russkikh 		link_status->mbps = 0U;
59786d36773SIgor Russkikh 	} else {
59886d36773SIgor Russkikh 		switch (link_speed_mask) {
59986d36773SIgor Russkikh 		case HAL_ATLANTIC_RATE_10G:
60086d36773SIgor Russkikh 			link_status->mbps = 10000U;
60186d36773SIgor Russkikh 			break;
60286d36773SIgor Russkikh 
60386d36773SIgor Russkikh 		case HAL_ATLANTIC_RATE_5G:
60486d36773SIgor Russkikh 		case HAL_ATLANTIC_RATE_5GSR:
60586d36773SIgor Russkikh 			link_status->mbps = 5000U;
60686d36773SIgor Russkikh 			break;
60786d36773SIgor Russkikh 
60886d36773SIgor Russkikh 		case HAL_ATLANTIC_RATE_2GS:
60986d36773SIgor Russkikh 			link_status->mbps = 2500U;
61086d36773SIgor Russkikh 			break;
61186d36773SIgor Russkikh 
61286d36773SIgor Russkikh 		case HAL_ATLANTIC_RATE_1G:
61386d36773SIgor Russkikh 			link_status->mbps = 1000U;
61486d36773SIgor Russkikh 			break;
61586d36773SIgor Russkikh 
61686d36773SIgor Russkikh 		case HAL_ATLANTIC_RATE_100M:
61786d36773SIgor Russkikh 			link_status->mbps = 100U;
61886d36773SIgor Russkikh 			break;
61986d36773SIgor Russkikh 
62086d36773SIgor Russkikh 		default:
62186d36773SIgor Russkikh 			return -EBUSY;
62286d36773SIgor Russkikh 		}
62386d36773SIgor Russkikh 	}
62486d36773SIgor Russkikh 
62586d36773SIgor Russkikh 	return 0;
62686d36773SIgor Russkikh }
62786d36773SIgor Russkikh 
62886d36773SIgor Russkikh static int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self,
62986d36773SIgor Russkikh 				   u8 *mac)
63086d36773SIgor Russkikh {
63186d36773SIgor Russkikh 	int err = 0;
63286d36773SIgor Russkikh 	u32 h = 0U;
63386d36773SIgor Russkikh 	u32 l = 0U;
63486d36773SIgor Russkikh 	u32 mac_addr[2];
63586d36773SIgor Russkikh 
63686d36773SIgor Russkikh 	if (!aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) {
63786d36773SIgor Russkikh 		unsigned int rnd = (uint32_t)rte_rand();
63886d36773SIgor Russkikh 		unsigned int ucp_0x370 = 0;
63986d36773SIgor Russkikh 
64086d36773SIgor Russkikh 		//get_random_bytes(&rnd, sizeof(unsigned int));
64186d36773SIgor Russkikh 
64286d36773SIgor Russkikh 		ucp_0x370 = 0x02020202 | (0xFEFEFEFE & rnd);
64386d36773SIgor Russkikh 		aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
64486d36773SIgor Russkikh 	}
64586d36773SIgor Russkikh 
64686d36773SIgor Russkikh 	err = hw_atl_utils_fw_downld_dwords(self,
64786d36773SIgor Russkikh 					    aq_hw_read_reg(self, 0x00000374U) +
64886d36773SIgor Russkikh 					    (40U * 4U),
64986d36773SIgor Russkikh 					    mac_addr,
65086d36773SIgor Russkikh 					    ARRAY_SIZE(mac_addr));
65186d36773SIgor Russkikh 	if (err < 0) {
65286d36773SIgor Russkikh 		mac_addr[0] = 0U;
65386d36773SIgor Russkikh 		mac_addr[1] = 0U;
65486d36773SIgor Russkikh 		err = 0;
65586d36773SIgor Russkikh 	} else {
65686d36773SIgor Russkikh 		mac_addr[0] = rte_constant_bswap32(mac_addr[0]);
65786d36773SIgor Russkikh 		mac_addr[1] = rte_constant_bswap32(mac_addr[1]);
65886d36773SIgor Russkikh 	}
65986d36773SIgor Russkikh 
660538da7a1SOlivier Matz 	rte_ether_addr_copy((struct rte_ether_addr *)mac_addr,
6616d13ea8eSOlivier Matz 			(struct rte_ether_addr *)mac);
66286d36773SIgor Russkikh 
66386d36773SIgor Russkikh 	if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) {
66486d36773SIgor Russkikh 		/* chip revision */
66586d36773SIgor Russkikh 		l = 0xE3000000U
66686d36773SIgor Russkikh 			| (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG))
66786d36773SIgor Russkikh 			| (0x00 << 16);
66886d36773SIgor Russkikh 		h = 0x8001300EU;
66986d36773SIgor Russkikh 
67086d36773SIgor Russkikh 		mac[5] = (u8)(0xFFU & l);
67186d36773SIgor Russkikh 		l >>= 8;
67286d36773SIgor Russkikh 		mac[4] = (u8)(0xFFU & l);
67386d36773SIgor Russkikh 		l >>= 8;
67486d36773SIgor Russkikh 		mac[3] = (u8)(0xFFU & l);
67586d36773SIgor Russkikh 		l >>= 8;
67686d36773SIgor Russkikh 		mac[2] = (u8)(0xFFU & l);
67786d36773SIgor Russkikh 		mac[1] = (u8)(0xFFU & h);
67886d36773SIgor Russkikh 		h >>= 8;
67986d36773SIgor Russkikh 		mac[0] = (u8)(0xFFU & h);
68086d36773SIgor Russkikh 	}
68186d36773SIgor Russkikh 
68286d36773SIgor Russkikh 	return err;
68386d36773SIgor Russkikh }
68486d36773SIgor Russkikh 
68586d36773SIgor Russkikh unsigned int hw_atl_utils_mbps_2_speed_index(unsigned int mbps)
68686d36773SIgor Russkikh {
68786d36773SIgor Russkikh 	unsigned int ret = 0U;
68886d36773SIgor Russkikh 
68986d36773SIgor Russkikh 	switch (mbps) {
69086d36773SIgor Russkikh 	case 100U:
69186d36773SIgor Russkikh 		ret = 5U;
69286d36773SIgor Russkikh 		break;
69386d36773SIgor Russkikh 
69486d36773SIgor Russkikh 	case 1000U:
69586d36773SIgor Russkikh 		ret = 4U;
69686d36773SIgor Russkikh 		break;
69786d36773SIgor Russkikh 
69886d36773SIgor Russkikh 	case 2500U:
69986d36773SIgor Russkikh 		ret = 3U;
70086d36773SIgor Russkikh 		break;
70186d36773SIgor Russkikh 
70286d36773SIgor Russkikh 	case 5000U:
70386d36773SIgor Russkikh 		ret = 1U;
70486d36773SIgor Russkikh 		break;
70586d36773SIgor Russkikh 
70686d36773SIgor Russkikh 	case 10000U:
70786d36773SIgor Russkikh 		ret = 0U;
70886d36773SIgor Russkikh 		break;
70986d36773SIgor Russkikh 
71086d36773SIgor Russkikh 	default:
71186d36773SIgor Russkikh 		break;
71286d36773SIgor Russkikh 	}
71386d36773SIgor Russkikh 	return ret;
71486d36773SIgor Russkikh }
71586d36773SIgor Russkikh 
71686d36773SIgor Russkikh void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p)
71786d36773SIgor Russkikh {
71886d36773SIgor Russkikh 	u32 chip_features = 0U;
71986d36773SIgor Russkikh 	u32 val = hw_atl_reg_glb_mif_id_get(self);
72086d36773SIgor Russkikh 	u32 mif_rev = val & 0xFFU;
72186d36773SIgor Russkikh 
72286d36773SIgor Russkikh 	if ((0xFU & mif_rev) == 1U) {
72386d36773SIgor Russkikh 		chip_features |= HAL_ATLANTIC_UTILS_CHIP_REVISION_A0 |
72486d36773SIgor Russkikh 			HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
72586d36773SIgor Russkikh 			HAL_ATLANTIC_UTILS_CHIP_MIPS;
72686d36773SIgor Russkikh 	} else if ((0xFU & mif_rev) == 2U) {
72786d36773SIgor Russkikh 		chip_features |= HAL_ATLANTIC_UTILS_CHIP_REVISION_B0 |
72886d36773SIgor Russkikh 			HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
72986d36773SIgor Russkikh 			HAL_ATLANTIC_UTILS_CHIP_MIPS |
73086d36773SIgor Russkikh 			HAL_ATLANTIC_UTILS_CHIP_TPO2 |
73186d36773SIgor Russkikh 			HAL_ATLANTIC_UTILS_CHIP_RPF2;
73286d36773SIgor Russkikh 	} else if ((0xFU & mif_rev) == 0xAU) {
73386d36773SIgor Russkikh 		chip_features |= HAL_ATLANTIC_UTILS_CHIP_REVISION_B1 |
73486d36773SIgor Russkikh 			HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
73586d36773SIgor Russkikh 			HAL_ATLANTIC_UTILS_CHIP_MIPS |
73686d36773SIgor Russkikh 			HAL_ATLANTIC_UTILS_CHIP_TPO2 |
73786d36773SIgor Russkikh 			HAL_ATLANTIC_UTILS_CHIP_RPF2;
73886d36773SIgor Russkikh 	}
73986d36773SIgor Russkikh 
74086d36773SIgor Russkikh 	*p = chip_features;
74186d36773SIgor Russkikh }
74286d36773SIgor Russkikh 
74386d36773SIgor Russkikh static int hw_atl_fw1x_deinit(struct aq_hw_s *self)
74486d36773SIgor Russkikh {
74586d36773SIgor Russkikh 	hw_atl_utils_mpi_set_speed(self, 0);
74686d36773SIgor Russkikh 	hw_atl_utils_mpi_set_state(self, MPI_DEINIT);
74786d36773SIgor Russkikh 	return 0;
74886d36773SIgor Russkikh }
74986d36773SIgor Russkikh 
75086d36773SIgor Russkikh int hw_atl_utils_update_stats(struct aq_hw_s *self)
75186d36773SIgor Russkikh {
75286d36773SIgor Russkikh 	struct hw_aq_atl_utils_mbox mbox;
75386d36773SIgor Russkikh 
75486d36773SIgor Russkikh 	hw_atl_utils_mpi_read_stats(self, &mbox);
75586d36773SIgor Russkikh 
75686d36773SIgor Russkikh #define AQ_SDELTA(_N_) (self->curr_stats._N_ += \
75786d36773SIgor Russkikh 			mbox.stats._N_ - self->last_stats._N_)
75886d36773SIgor Russkikh 
75986d36773SIgor Russkikh 	if (1) {//self->aq_link_status.mbps) {
76086d36773SIgor Russkikh 		AQ_SDELTA(uprc);
76186d36773SIgor Russkikh 		AQ_SDELTA(mprc);
76286d36773SIgor Russkikh 		AQ_SDELTA(bprc);
76386d36773SIgor Russkikh 		AQ_SDELTA(erpt);
76486d36773SIgor Russkikh 
76586d36773SIgor Russkikh 		AQ_SDELTA(uptc);
76686d36773SIgor Russkikh 		AQ_SDELTA(mptc);
76786d36773SIgor Russkikh 		AQ_SDELTA(bptc);
76886d36773SIgor Russkikh 		AQ_SDELTA(erpr);
76986d36773SIgor Russkikh 		AQ_SDELTA(ubrc);
77086d36773SIgor Russkikh 		AQ_SDELTA(ubtc);
77186d36773SIgor Russkikh 		AQ_SDELTA(mbrc);
77286d36773SIgor Russkikh 		AQ_SDELTA(mbtc);
77386d36773SIgor Russkikh 		AQ_SDELTA(bbrc);
77486d36773SIgor Russkikh 		AQ_SDELTA(bbtc);
77586d36773SIgor Russkikh 		AQ_SDELTA(dpc);
77686d36773SIgor Russkikh 	}
77786d36773SIgor Russkikh #undef AQ_SDELTA
77886d36773SIgor Russkikh 	self->curr_stats.dma_pkt_rc =
77986d36773SIgor Russkikh 	   hw_atl_stats_rx_dma_good_pkt_counterlsw_get(self) +
78086d36773SIgor Russkikh 	   ((u64)hw_atl_stats_rx_dma_good_pkt_countermsw_get(self) << 32);
78186d36773SIgor Russkikh 	self->curr_stats.dma_pkt_tc =
78286d36773SIgor Russkikh 	   hw_atl_stats_tx_dma_good_pkt_counterlsw_get(self) +
78386d36773SIgor Russkikh 	   ((u64)hw_atl_stats_tx_dma_good_pkt_countermsw_get(self) << 32);
78486d36773SIgor Russkikh 	self->curr_stats.dma_oct_rc =
78586d36773SIgor Russkikh 	   hw_atl_stats_rx_dma_good_octet_counterlsw_get(self) +
78686d36773SIgor Russkikh 	   ((u64)hw_atl_stats_rx_dma_good_octet_countermsw_get(self) << 32);
78786d36773SIgor Russkikh 	self->curr_stats.dma_oct_tc =
78886d36773SIgor Russkikh 	   hw_atl_stats_tx_dma_good_octet_counterlsw_get(self) +
78986d36773SIgor Russkikh 	   ((u64)hw_atl_stats_tx_dma_good_octet_countermsw_get(self) << 32);
79086d36773SIgor Russkikh 
79186d36773SIgor Russkikh 	self->curr_stats.dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self);
79286d36773SIgor Russkikh 
79386d36773SIgor Russkikh 	memcpy(&self->last_stats, &mbox.stats, sizeof(mbox.stats));
79486d36773SIgor Russkikh 
79586d36773SIgor Russkikh 	return 0;
79686d36773SIgor Russkikh }
79786d36773SIgor Russkikh 
79886d36773SIgor Russkikh struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self)
79986d36773SIgor Russkikh {
80086d36773SIgor Russkikh 	return &self->curr_stats;
80186d36773SIgor Russkikh }
80286d36773SIgor Russkikh 
80386d36773SIgor Russkikh static const u32 hw_atl_utils_hw_mac_regs[] = {
80486d36773SIgor Russkikh 	0x00005580U, 0x00005590U, 0x000055B0U, 0x000055B4U,
80586d36773SIgor Russkikh 	0x000055C0U, 0x00005B00U, 0x00005B04U, 0x00005B08U,
80686d36773SIgor Russkikh 	0x00005B0CU, 0x00005B10U, 0x00005B14U, 0x00005B18U,
80786d36773SIgor Russkikh 	0x00005B1CU, 0x00005B20U, 0x00005B24U, 0x00005B28U,
80886d36773SIgor Russkikh 	0x00005B2CU, 0x00005B30U, 0x00005B34U, 0x00005B38U,
80986d36773SIgor Russkikh 	0x00005B3CU, 0x00005B40U, 0x00005B44U, 0x00005B48U,
81086d36773SIgor Russkikh 	0x00005B4CU, 0x00005B50U, 0x00005B54U, 0x00005B58U,
81186d36773SIgor Russkikh 	0x00005B5CU, 0x00005B60U, 0x00005B64U, 0x00005B68U,
81286d36773SIgor Russkikh 	0x00005B6CU, 0x00005B70U, 0x00005B74U, 0x00005B78U,
81386d36773SIgor Russkikh 	0x00005B7CU, 0x00007C00U, 0x00007C04U, 0x00007C08U,
81486d36773SIgor Russkikh 	0x00007C0CU, 0x00007C10U, 0x00007C14U, 0x00007C18U,
81586d36773SIgor Russkikh 	0x00007C1CU, 0x00007C20U, 0x00007C40U, 0x00007C44U,
81686d36773SIgor Russkikh 	0x00007C48U, 0x00007C4CU, 0x00007C50U, 0x00007C54U,
81786d36773SIgor Russkikh 	0x00007C58U, 0x00007C5CU, 0x00007C60U, 0x00007C80U,
81886d36773SIgor Russkikh 	0x00007C84U, 0x00007C88U, 0x00007C8CU, 0x00007C90U,
81986d36773SIgor Russkikh 	0x00007C94U, 0x00007C98U, 0x00007C9CU, 0x00007CA0U,
82086d36773SIgor Russkikh 	0x00007CC0U, 0x00007CC4U, 0x00007CC8U, 0x00007CCCU,
82186d36773SIgor Russkikh 	0x00007CD0U, 0x00007CD4U, 0x00007CD8U, 0x00007CDCU,
82286d36773SIgor Russkikh 	0x00007CE0U, 0x00000300U, 0x00000304U, 0x00000308U,
82386d36773SIgor Russkikh 	0x0000030cU, 0x00000310U, 0x00000314U, 0x00000318U,
82486d36773SIgor Russkikh 	0x0000031cU, 0x00000360U, 0x00000364U, 0x00000368U,
82586d36773SIgor Russkikh 	0x0000036cU, 0x00000370U, 0x00000374U, 0x00006900U,
82686d36773SIgor Russkikh };
82786d36773SIgor Russkikh 
82886d36773SIgor Russkikh unsigned int hw_atl_utils_hw_get_reg_length(void)
82986d36773SIgor Russkikh {
83086d36773SIgor Russkikh 	return ARRAY_SIZE(hw_atl_utils_hw_mac_regs);
83186d36773SIgor Russkikh }
83286d36773SIgor Russkikh 
83386d36773SIgor Russkikh int hw_atl_utils_hw_get_regs(struct aq_hw_s *self,
83486d36773SIgor Russkikh 			     u32 *regs_buff)
83586d36773SIgor Russkikh {
83686d36773SIgor Russkikh 	unsigned int i = 0U;
83786d36773SIgor Russkikh 	unsigned int mac_regs_count = hw_atl_utils_hw_get_reg_length();
83886d36773SIgor Russkikh 
83986d36773SIgor Russkikh 	for (i = 0; i < mac_regs_count; i++)
84086d36773SIgor Russkikh 		regs_buff[i] = aq_hw_read_reg(self,
84186d36773SIgor Russkikh 					      hw_atl_utils_hw_mac_regs[i]);
84286d36773SIgor Russkikh 	return 0;
84386d36773SIgor Russkikh }
84486d36773SIgor Russkikh 
84586d36773SIgor Russkikh int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version)
84686d36773SIgor Russkikh {
84786d36773SIgor Russkikh 	*fw_version = aq_hw_read_reg(self, 0x18U);
84886d36773SIgor Russkikh 	return 0;
84986d36773SIgor Russkikh }
85086d36773SIgor Russkikh 
85186d36773SIgor Russkikh static int aq_fw1x_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac)
85286d36773SIgor Russkikh {
85386d36773SIgor Russkikh 	struct hw_aq_atl_utils_fw_rpc *prpc = NULL;
85486d36773SIgor Russkikh 	unsigned int rpc_size = 0U;
85586d36773SIgor Russkikh 	int err = 0;
85686d36773SIgor Russkikh 
85786d36773SIgor Russkikh 	err = hw_atl_utils_fw_rpc_wait(self, &prpc);
85886d36773SIgor Russkikh 	if (err < 0)
85986d36773SIgor Russkikh 		goto err_exit;
86086d36773SIgor Russkikh 
86186d36773SIgor Russkikh 	memset(prpc, 0, sizeof(*prpc));
86286d36773SIgor Russkikh 
86386d36773SIgor Russkikh 	if (wol_enabled) {
86486d36773SIgor Russkikh 		rpc_size = sizeof(prpc->msg_id) + sizeof(prpc->msg_wol);
86586d36773SIgor Russkikh 
86686d36773SIgor Russkikh 		prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD;
86786d36773SIgor Russkikh 		prpc->msg_wol.priority = 0x10000000; /* normal priority */
86886d36773SIgor Russkikh 		prpc->msg_wol.pattern_id = 1U;
86986d36773SIgor Russkikh 		prpc->msg_wol.wol_packet_type = 2U; /* Magic Packet */
87086d36773SIgor Russkikh 
871538da7a1SOlivier Matz 		rte_ether_addr_copy((struct rte_ether_addr *)mac,
8726d13ea8eSOlivier Matz 			(struct rte_ether_addr *)&prpc->msg_wol.wol_pattern);
87386d36773SIgor Russkikh 	} else {
87486d36773SIgor Russkikh 		rpc_size = sizeof(prpc->msg_id) + sizeof(prpc->msg_del_id);
87586d36773SIgor Russkikh 
87686d36773SIgor Russkikh 		prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL;
87786d36773SIgor Russkikh 		prpc->msg_wol.pattern_id = 1U;
87886d36773SIgor Russkikh 	}
87986d36773SIgor Russkikh 
88086d36773SIgor Russkikh 	err = hw_atl_utils_fw_rpc_call(self, rpc_size);
8810b504bcfSIgor Russkikh 
88286d36773SIgor Russkikh err_exit:
88386d36773SIgor Russkikh 	return err;
88486d36773SIgor Russkikh }
88586d36773SIgor Russkikh 
88686d36773SIgor Russkikh static
88786d36773SIgor Russkikh int aq_fw1x_set_power(struct aq_hw_s *self,
88886d36773SIgor Russkikh 		      unsigned int power_state __rte_unused,
88986d36773SIgor Russkikh 		      u8 *mac)
89086d36773SIgor Russkikh {
89186d36773SIgor Russkikh 	struct hw_aq_atl_utils_fw_rpc *prpc = NULL;
89286d36773SIgor Russkikh 	unsigned int rpc_size = 0U;
89386d36773SIgor Russkikh 	int err = 0;
89486d36773SIgor Russkikh 	if (self->aq_nic_cfg->wol & AQ_NIC_WOL_ENABLED) {
89586d36773SIgor Russkikh 		err = aq_fw1x_set_wol(self, 1, mac);
89686d36773SIgor Russkikh 
89786d36773SIgor Russkikh 		if (err < 0)
89886d36773SIgor Russkikh 			goto err_exit;
89986d36773SIgor Russkikh 
90086d36773SIgor Russkikh 		rpc_size = sizeof(prpc->msg_id) +
90186d36773SIgor Russkikh 				sizeof(prpc->msg_enable_wakeup);
90286d36773SIgor Russkikh 
90386d36773SIgor Russkikh 		err = hw_atl_utils_fw_rpc_wait(self, &prpc);
90486d36773SIgor Russkikh 
90586d36773SIgor Russkikh 		if (err < 0)
90686d36773SIgor Russkikh 			goto err_exit;
90786d36773SIgor Russkikh 
90886d36773SIgor Russkikh 		memset(prpc, 0, rpc_size);
90986d36773SIgor Russkikh 
91086d36773SIgor Russkikh 		prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP;
91186d36773SIgor Russkikh 		prpc->msg_enable_wakeup.pattern_mask = 0x00000002;
91286d36773SIgor Russkikh 
91386d36773SIgor Russkikh 		err = hw_atl_utils_fw_rpc_call(self, rpc_size);
91486d36773SIgor Russkikh 		if (err < 0)
91586d36773SIgor Russkikh 			goto err_exit;
91686d36773SIgor Russkikh 	}
91786d36773SIgor Russkikh 
91886d36773SIgor Russkikh 	hw_atl_utils_mpi_set_speed(self, 0);
91986d36773SIgor Russkikh 	hw_atl_utils_mpi_set_state(self, MPI_POWER);
92086d36773SIgor Russkikh err_exit:
92186d36773SIgor Russkikh 	return err;
92286d36773SIgor Russkikh }
92386d36773SIgor Russkikh 
92486d36773SIgor Russkikh 
92586d36773SIgor Russkikh 
92686d36773SIgor Russkikh const struct aq_fw_ops aq_fw_1x_ops = {
92786d36773SIgor Russkikh 	.init = hw_atl_utils_mpi_create,
92886d36773SIgor Russkikh 	.deinit = hw_atl_fw1x_deinit,
92986d36773SIgor Russkikh 	.reset = NULL,
93086d36773SIgor Russkikh 	.get_mac_permanent = hw_atl_utils_get_mac_permanent,
93186d36773SIgor Russkikh 	.set_link_speed = hw_atl_utils_mpi_set_speed,
93286d36773SIgor Russkikh 	.set_state = hw_atl_utils_mpi_set_state,
93386d36773SIgor Russkikh 	.update_link_status = hw_atl_utils_mpi_get_link_status,
93486d36773SIgor Russkikh 	.update_stats = hw_atl_utils_update_stats,
93586d36773SIgor Russkikh 	.set_power = aq_fw1x_set_power,
93686d36773SIgor Russkikh 	.get_temp = NULL,
93786d36773SIgor Russkikh 	.get_cable_len = NULL,
93886d36773SIgor Russkikh 	.set_eee_rate = NULL,
93986d36773SIgor Russkikh 	.get_eee_rate = NULL,
94086d36773SIgor Russkikh 	.set_flow_control = NULL,
94186d36773SIgor Russkikh 	.led_control = NULL,
94286d36773SIgor Russkikh 	.get_eeprom = NULL,
94386d36773SIgor Russkikh 	.set_eeprom = NULL,
94486d36773SIgor Russkikh };
945