1a57d3929SIgor Russkikh /*
2a57d3929SIgor Russkikh  * aQuantia Corporation Network Driver
3a57d3929SIgor Russkikh  * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
4a57d3929SIgor Russkikh  *
5a57d3929SIgor Russkikh  * This program is free software; you can redistribute it and/or modify it
6a57d3929SIgor Russkikh  * under the terms and conditions of the GNU General Public License,
7a57d3929SIgor Russkikh  * version 2, as published by the Free Software Foundation.
8a57d3929SIgor Russkikh  */
9a57d3929SIgor Russkikh 
10a57d3929SIgor Russkikh /* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for
11a57d3929SIgor Russkikh  * Atlantic hardware abstraction layer.
12a57d3929SIgor Russkikh  */
13a57d3929SIgor Russkikh 
14a57d3929SIgor Russkikh #include "../aq_hw.h"
15a57d3929SIgor Russkikh #include "../aq_hw_utils.h"
16a57d3929SIgor Russkikh #include "../aq_pci_func.h"
17a57d3929SIgor Russkikh #include "../aq_ring.h"
18a57d3929SIgor Russkikh #include "../aq_vec.h"
19a57d3929SIgor Russkikh #include "hw_atl_utils.h"
20a57d3929SIgor Russkikh #include "hw_atl_llh.h"
21a57d3929SIgor Russkikh 
22a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_EFUSE_ADDR	0x364
23a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_MBOX_ADDR	0x360
243ee5c887SYana Esina #define HW_ATL_FW2X_MPI_RPC_ADDR        0x334
25a57d3929SIgor Russkikh 
26a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_CONTROL_ADDR	0x368
27a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_CONTROL2_ADDR	0x36C
28a57d3929SIgor Russkikh 
29a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_STATE_ADDR	0x370
30a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_STATE2_ADDR	0x374
31a57d3929SIgor Russkikh 
3244e00dd8SIgor Russkikh static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed);
3344e00dd8SIgor Russkikh static int aq_fw2x_set_state(struct aq_hw_s *self,
3444e00dd8SIgor Russkikh 			     enum hal_atl_utils_fw_state_e state);
3544e00dd8SIgor Russkikh 
36a57d3929SIgor Russkikh static int aq_fw2x_init(struct aq_hw_s *self)
37a57d3929SIgor Russkikh {
38a57d3929SIgor Russkikh 	int err = 0;
39a57d3929SIgor Russkikh 
40a57d3929SIgor Russkikh 	/* check 10 times by 1ms */
41a57d3929SIgor Russkikh 	AQ_HW_WAIT_FOR(0U != (self->mbox_addr =
42a57d3929SIgor Russkikh 			aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR)),
43a57d3929SIgor Russkikh 		       1000U, 10U);
443ee5c887SYana Esina 	AQ_HW_WAIT_FOR(0U != (self->rpc_addr =
453ee5c887SYana Esina 		       aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR)),
463ee5c887SYana Esina 		       1000U, 100U);
473ee5c887SYana Esina 
48a57d3929SIgor Russkikh 	return err;
49a57d3929SIgor Russkikh }
50a57d3929SIgor Russkikh 
5144e00dd8SIgor Russkikh static int aq_fw2x_deinit(struct aq_hw_s *self)
5244e00dd8SIgor Russkikh {
5344e00dd8SIgor Russkikh 	int err = aq_fw2x_set_link_speed(self, 0);
5444e00dd8SIgor Russkikh 
5544e00dd8SIgor Russkikh 	if (!err)
5644e00dd8SIgor Russkikh 		err = aq_fw2x_set_state(self, MPI_DEINIT);
5744e00dd8SIgor Russkikh 
5844e00dd8SIgor Russkikh 	return err;
5944e00dd8SIgor Russkikh }
6044e00dd8SIgor Russkikh 
61a57d3929SIgor Russkikh static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed)
62a57d3929SIgor Russkikh {
63a57d3929SIgor Russkikh 	enum hw_atl_fw2x_rate rate = 0;
64a57d3929SIgor Russkikh 
65a57d3929SIgor Russkikh 	if (speed & AQ_NIC_RATE_10G)
66a57d3929SIgor Russkikh 		rate |= FW2X_RATE_10G;
67a57d3929SIgor Russkikh 
68a57d3929SIgor Russkikh 	if (speed & AQ_NIC_RATE_5G)
69a57d3929SIgor Russkikh 		rate |= FW2X_RATE_5G;
70a57d3929SIgor Russkikh 
71a57d3929SIgor Russkikh 	if (speed & AQ_NIC_RATE_5GSR)
72a57d3929SIgor Russkikh 		rate |= FW2X_RATE_5G;
73a57d3929SIgor Russkikh 
74a57d3929SIgor Russkikh 	if (speed & AQ_NIC_RATE_2GS)
75a57d3929SIgor Russkikh 		rate |= FW2X_RATE_2G5;
76a57d3929SIgor Russkikh 
77a57d3929SIgor Russkikh 	if (speed & AQ_NIC_RATE_1G)
78a57d3929SIgor Russkikh 		rate |= FW2X_RATE_1G;
79a57d3929SIgor Russkikh 
80a57d3929SIgor Russkikh 	if (speed & AQ_NIC_RATE_100M)
81a57d3929SIgor Russkikh 		rate |= FW2X_RATE_100M;
82a57d3929SIgor Russkikh 
83a57d3929SIgor Russkikh 	return rate;
84a57d3929SIgor Russkikh }
85a57d3929SIgor Russkikh 
86a57d3929SIgor Russkikh static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed)
87a57d3929SIgor Russkikh {
88a57d3929SIgor Russkikh 	u32 val = link_speed_mask_2fw2x_ratemask(speed);
89a57d3929SIgor Russkikh 
90a57d3929SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, val);
91a57d3929SIgor Russkikh 
92a57d3929SIgor Russkikh 	return 0;
93a57d3929SIgor Russkikh }
94a57d3929SIgor Russkikh 
95288551deSIgor Russkikh static void aq_fw2x_set_mpi_flow_control(struct aq_hw_s *self, u32 *mpi_state)
96288551deSIgor Russkikh {
97288551deSIgor Russkikh 	if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_RX)
98288551deSIgor Russkikh 		*mpi_state |= BIT(CAPS_HI_PAUSE);
99288551deSIgor Russkikh 	else
100288551deSIgor Russkikh 		*mpi_state &= ~BIT(CAPS_HI_PAUSE);
101288551deSIgor Russkikh 
102288551deSIgor Russkikh 	if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_TX)
103288551deSIgor Russkikh 		*mpi_state |= BIT(CAPS_HI_ASYMMETRIC_PAUSE);
104288551deSIgor Russkikh 	else
105288551deSIgor Russkikh 		*mpi_state &= ~BIT(CAPS_HI_ASYMMETRIC_PAUSE);
106288551deSIgor Russkikh }
107288551deSIgor Russkikh 
108a57d3929SIgor Russkikh static int aq_fw2x_set_state(struct aq_hw_s *self,
109a57d3929SIgor Russkikh 			     enum hal_atl_utils_fw_state_e state)
110a57d3929SIgor Russkikh {
11144e00dd8SIgor Russkikh 	u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
11244e00dd8SIgor Russkikh 
11344e00dd8SIgor Russkikh 	switch (state) {
11444e00dd8SIgor Russkikh 	case MPI_INIT:
11544e00dd8SIgor Russkikh 		mpi_state &= ~BIT(CAPS_HI_LINK_DROP);
116288551deSIgor Russkikh 		aq_fw2x_set_mpi_flow_control(self, &mpi_state);
11744e00dd8SIgor Russkikh 		break;
11844e00dd8SIgor Russkikh 	case MPI_DEINIT:
11944e00dd8SIgor Russkikh 		mpi_state |= BIT(CAPS_HI_LINK_DROP);
12044e00dd8SIgor Russkikh 		break;
12144e00dd8SIgor Russkikh 	case MPI_RESET:
12244e00dd8SIgor Russkikh 	case MPI_POWER:
12344e00dd8SIgor Russkikh 		/* No actions */
12444e00dd8SIgor Russkikh 		break;
12544e00dd8SIgor Russkikh 	}
12644e00dd8SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
127a57d3929SIgor Russkikh 	return 0;
128a57d3929SIgor Russkikh }
129a57d3929SIgor Russkikh 
130a57d3929SIgor Russkikh static int aq_fw2x_update_link_status(struct aq_hw_s *self)
131a57d3929SIgor Russkikh {
132a57d3929SIgor Russkikh 	u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR);
133a57d3929SIgor Russkikh 	u32 speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G |
134a57d3929SIgor Russkikh 				FW2X_RATE_2G5 | FW2X_RATE_5G | FW2X_RATE_10G);
135a57d3929SIgor Russkikh 	struct aq_hw_link_status_s *link_status = &self->aq_link_status;
136a57d3929SIgor Russkikh 
137a57d3929SIgor Russkikh 	if (speed) {
138a57d3929SIgor Russkikh 		if (speed & FW2X_RATE_10G)
139a57d3929SIgor Russkikh 			link_status->mbps = 10000;
140a57d3929SIgor Russkikh 		else if (speed & FW2X_RATE_5G)
141a57d3929SIgor Russkikh 			link_status->mbps = 5000;
142a57d3929SIgor Russkikh 		else if (speed & FW2X_RATE_2G5)
143a57d3929SIgor Russkikh 			link_status->mbps = 2500;
144a57d3929SIgor Russkikh 		else if (speed & FW2X_RATE_1G)
145a57d3929SIgor Russkikh 			link_status->mbps = 1000;
146a57d3929SIgor Russkikh 		else if (speed & FW2X_RATE_100M)
147a57d3929SIgor Russkikh 			link_status->mbps = 100;
148a57d3929SIgor Russkikh 		else
149a57d3929SIgor Russkikh 			link_status->mbps = 10000;
150a57d3929SIgor Russkikh 	} else {
151a57d3929SIgor Russkikh 		link_status->mbps = 0;
152a57d3929SIgor Russkikh 	}
153a57d3929SIgor Russkikh 
154a57d3929SIgor Russkikh 	return 0;
155a57d3929SIgor Russkikh }
156a57d3929SIgor Russkikh 
15776a45194SColin Ian King static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
158a57d3929SIgor Russkikh {
159a57d3929SIgor Russkikh 	int err = 0;
160a57d3929SIgor Russkikh 	u32 h = 0U;
161a57d3929SIgor Russkikh 	u32 l = 0U;
162a57d3929SIgor Russkikh 	u32 mac_addr[2] = { 0 };
163a57d3929SIgor Russkikh 	u32 efuse_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_EFUSE_ADDR);
164a57d3929SIgor Russkikh 
165a57d3929SIgor Russkikh 	if (efuse_addr != 0) {
166a57d3929SIgor Russkikh 		err = hw_atl_utils_fw_downld_dwords(self,
167a57d3929SIgor Russkikh 						    efuse_addr + (40U * 4U),
168a57d3929SIgor Russkikh 						    mac_addr,
169a57d3929SIgor Russkikh 						    ARRAY_SIZE(mac_addr));
170a57d3929SIgor Russkikh 		if (err)
171a57d3929SIgor Russkikh 			return err;
172a57d3929SIgor Russkikh 		mac_addr[0] = __swab32(mac_addr[0]);
173a57d3929SIgor Russkikh 		mac_addr[1] = __swab32(mac_addr[1]);
174a57d3929SIgor Russkikh 	}
175a57d3929SIgor Russkikh 
176a57d3929SIgor Russkikh 	ether_addr_copy(mac, (u8 *)mac_addr);
177a57d3929SIgor Russkikh 
178a57d3929SIgor Russkikh 	if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) {
179a57d3929SIgor Russkikh 		unsigned int rnd = 0;
180a57d3929SIgor Russkikh 
181a57d3929SIgor Russkikh 		get_random_bytes(&rnd, sizeof(unsigned int));
182a57d3929SIgor Russkikh 
183a57d3929SIgor Russkikh 		l = 0xE3000000U
184a57d3929SIgor Russkikh 			| (0xFFFFU & rnd)
185a57d3929SIgor Russkikh 			| (0x00 << 16);
186a57d3929SIgor Russkikh 		h = 0x8001300EU;
187a57d3929SIgor Russkikh 
188a57d3929SIgor Russkikh 		mac[5] = (u8)(0xFFU & l);
189a57d3929SIgor Russkikh 		l >>= 8;
190a57d3929SIgor Russkikh 		mac[4] = (u8)(0xFFU & l);
191a57d3929SIgor Russkikh 		l >>= 8;
192a57d3929SIgor Russkikh 		mac[3] = (u8)(0xFFU & l);
193a57d3929SIgor Russkikh 		l >>= 8;
194a57d3929SIgor Russkikh 		mac[2] = (u8)(0xFFU & l);
195a57d3929SIgor Russkikh 		mac[1] = (u8)(0xFFU & h);
196a57d3929SIgor Russkikh 		h >>= 8;
197a57d3929SIgor Russkikh 		mac[0] = (u8)(0xFFU & h);
198a57d3929SIgor Russkikh 	}
199a57d3929SIgor Russkikh 	return err;
200a57d3929SIgor Russkikh }
201a57d3929SIgor Russkikh 
202a57d3929SIgor Russkikh static int aq_fw2x_update_stats(struct aq_hw_s *self)
203a57d3929SIgor Russkikh {
204a57d3929SIgor Russkikh 	int err = 0;
205a57d3929SIgor Russkikh 	u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
206a57d3929SIgor Russkikh 	u32 orig_stats_val = mpi_opts & BIT(CAPS_HI_STATISTICS);
207a57d3929SIgor Russkikh 
208a57d3929SIgor Russkikh 	/* Toggle statistics bit for FW to update */
209a57d3929SIgor Russkikh 	mpi_opts = mpi_opts ^ BIT(CAPS_HI_STATISTICS);
210a57d3929SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
211a57d3929SIgor Russkikh 
212a57d3929SIgor Russkikh 	/* Wait FW to report back */
213a57d3929SIgor Russkikh 	AQ_HW_WAIT_FOR(orig_stats_val !=
214a57d3929SIgor Russkikh 		       (aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) &
215a57d3929SIgor Russkikh 				       BIT(CAPS_HI_STATISTICS)),
216a57d3929SIgor Russkikh 		       1U, 10000U);
217a57d3929SIgor Russkikh 	if (err)
218a57d3929SIgor Russkikh 		return err;
219a57d3929SIgor Russkikh 
220a57d3929SIgor Russkikh 	return hw_atl_utils_update_stats(self);
221a57d3929SIgor Russkikh }
222a57d3929SIgor Russkikh 
223b8d68b62SAnton Mikaev static int aq_fw2x_renegotiate(struct aq_hw_s *self)
224b8d68b62SAnton Mikaev {
225b8d68b62SAnton Mikaev 	u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
226b8d68b62SAnton Mikaev 
227b8d68b62SAnton Mikaev 	mpi_opts |= BIT(CTRL_FORCE_RECONNECT);
228b8d68b62SAnton Mikaev 
229b8d68b62SAnton Mikaev 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
230b8d68b62SAnton Mikaev 
231b8d68b62SAnton Mikaev 	return 0;
232b8d68b62SAnton Mikaev }
233b8d68b62SAnton Mikaev 
234288551deSIgor Russkikh static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
235288551deSIgor Russkikh {
236288551deSIgor Russkikh 	u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
237288551deSIgor Russkikh 
238288551deSIgor Russkikh 	aq_fw2x_set_mpi_flow_control(self, &mpi_state);
239288551deSIgor Russkikh 
240288551deSIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
241288551deSIgor Russkikh 
242288551deSIgor Russkikh 	return 0;
243288551deSIgor Russkikh }
244288551deSIgor Russkikh 
245a57d3929SIgor Russkikh const struct aq_fw_ops aq_fw_2x_ops = {
246a57d3929SIgor Russkikh 	.init = aq_fw2x_init,
24744e00dd8SIgor Russkikh 	.deinit = aq_fw2x_deinit,
248a57d3929SIgor Russkikh 	.reset = NULL,
249b8d68b62SAnton Mikaev 	.renegotiate = aq_fw2x_renegotiate,
250a57d3929SIgor Russkikh 	.get_mac_permanent = aq_fw2x_get_mac_permanent,
251a57d3929SIgor Russkikh 	.set_link_speed = aq_fw2x_set_link_speed,
252a57d3929SIgor Russkikh 	.set_state = aq_fw2x_set_state,
253a57d3929SIgor Russkikh 	.update_link_status = aq_fw2x_update_link_status,
254a57d3929SIgor Russkikh 	.update_stats = aq_fw2x_update_stats,
255288551deSIgor Russkikh 	.set_flow_control   = aq_fw2x_set_flow_control,
256a57d3929SIgor Russkikh };
257