brintos

brintos / linux-shallow public Read only

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