xref: /linux/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c (revision e87b5039511a7780f3483a7202b4e67a8493c181)
1*e87b5039SStanislaw Gruszka /*
2*e87b5039SStanislaw Gruszka  * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
3*e87b5039SStanislaw Gruszka  * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
4*e87b5039SStanislaw Gruszka  * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
5*e87b5039SStanislaw Gruszka  *
6*e87b5039SStanislaw Gruszka  * This program is free software; you can redistribute it and/or modify
7*e87b5039SStanislaw Gruszka  * it under the terms of the GNU General Public License version 2
8*e87b5039SStanislaw Gruszka  * as published by the Free Software Foundation
9*e87b5039SStanislaw Gruszka  *
10*e87b5039SStanislaw Gruszka  * This program is distributed in the hope that it will be useful,
11*e87b5039SStanislaw Gruszka  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*e87b5039SStanislaw Gruszka  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*e87b5039SStanislaw Gruszka  * GNU General Public License for more details.
14*e87b5039SStanislaw Gruszka  */
15*e87b5039SStanislaw Gruszka 
16*e87b5039SStanislaw Gruszka #include <linux/of.h>
17*e87b5039SStanislaw Gruszka #include <linux/mtd/mtd.h>
18*e87b5039SStanislaw Gruszka #include <linux/mtd/partitions.h>
19*e87b5039SStanislaw Gruszka #include <linux/etherdevice.h>
20*e87b5039SStanislaw Gruszka #include <asm/unaligned.h>
21*e87b5039SStanislaw Gruszka #include "mt76x0.h"
22*e87b5039SStanislaw Gruszka #include "eeprom.h"
23*e87b5039SStanislaw Gruszka 
24*e87b5039SStanislaw Gruszka static bool
25*e87b5039SStanislaw Gruszka field_valid(u8 val)
26*e87b5039SStanislaw Gruszka {
27*e87b5039SStanislaw Gruszka 	return val != 0xff;
28*e87b5039SStanislaw Gruszka }
29*e87b5039SStanislaw Gruszka 
30*e87b5039SStanislaw Gruszka static s8
31*e87b5039SStanislaw Gruszka field_validate(u8 val)
32*e87b5039SStanislaw Gruszka {
33*e87b5039SStanislaw Gruszka 	if (!field_valid(val))
34*e87b5039SStanislaw Gruszka 		return 0;
35*e87b5039SStanislaw Gruszka 
36*e87b5039SStanislaw Gruszka 	return val;
37*e87b5039SStanislaw Gruszka }
38*e87b5039SStanislaw Gruszka 
39*e87b5039SStanislaw Gruszka static inline int
40*e87b5039SStanislaw Gruszka sign_extend(u32 val, unsigned int size)
41*e87b5039SStanislaw Gruszka {
42*e87b5039SStanislaw Gruszka 	bool sign = val & BIT(size - 1);
43*e87b5039SStanislaw Gruszka 
44*e87b5039SStanislaw Gruszka 	val &= BIT(size - 1) - 1;
45*e87b5039SStanislaw Gruszka 
46*e87b5039SStanislaw Gruszka 	return sign ? val : -val;
47*e87b5039SStanislaw Gruszka }
48*e87b5039SStanislaw Gruszka 
49*e87b5039SStanislaw Gruszka static int
50*e87b5039SStanislaw Gruszka mt76x0_efuse_read(struct mt76x0_dev *dev, u16 addr, u8 *data,
51*e87b5039SStanislaw Gruszka 		   enum mt76x0_eeprom_access_modes mode)
52*e87b5039SStanislaw Gruszka {
53*e87b5039SStanislaw Gruszka 	u32 val;
54*e87b5039SStanislaw Gruszka 	int i;
55*e87b5039SStanislaw Gruszka 
56*e87b5039SStanislaw Gruszka 	val = mt76_rr(dev, MT_EFUSE_CTRL);
57*e87b5039SStanislaw Gruszka 	val &= ~(MT_EFUSE_CTRL_AIN |
58*e87b5039SStanislaw Gruszka 		 MT_EFUSE_CTRL_MODE);
59*e87b5039SStanislaw Gruszka 	val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf) |
60*e87b5039SStanislaw Gruszka 	       FIELD_PREP(MT_EFUSE_CTRL_MODE, mode) |
61*e87b5039SStanislaw Gruszka 	       MT_EFUSE_CTRL_KICK;
62*e87b5039SStanislaw Gruszka 	mt76_wr(dev, MT_EFUSE_CTRL, val);
63*e87b5039SStanislaw Gruszka 
64*e87b5039SStanislaw Gruszka 	if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
65*e87b5039SStanislaw Gruszka 		return -ETIMEDOUT;
66*e87b5039SStanislaw Gruszka 
67*e87b5039SStanislaw Gruszka 	val = mt76_rr(dev, MT_EFUSE_CTRL);
68*e87b5039SStanislaw Gruszka 	if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) {
69*e87b5039SStanislaw Gruszka 		/* Parts of eeprom not in the usage map (0x80-0xc0,0xf0)
70*e87b5039SStanislaw Gruszka 		 * will not return valid data but it's ok.
71*e87b5039SStanislaw Gruszka 		 */
72*e87b5039SStanislaw Gruszka 		memset(data, 0xff, 16);
73*e87b5039SStanislaw Gruszka 		return 0;
74*e87b5039SStanislaw Gruszka 	}
75*e87b5039SStanislaw Gruszka 
76*e87b5039SStanislaw Gruszka 	for (i = 0; i < 4; i++) {
77*e87b5039SStanislaw Gruszka 		val = mt76_rr(dev, MT_EFUSE_DATA(i));
78*e87b5039SStanislaw Gruszka 		put_unaligned_le32(val, data + 4 * i);
79*e87b5039SStanislaw Gruszka 	}
80*e87b5039SStanislaw Gruszka 
81*e87b5039SStanislaw Gruszka 	return 0;
82*e87b5039SStanislaw Gruszka }
83*e87b5039SStanislaw Gruszka 
84*e87b5039SStanislaw Gruszka static int
85*e87b5039SStanislaw Gruszka mt76x0_efuse_physical_size_check(struct mt76x0_dev *dev)
86*e87b5039SStanislaw Gruszka {
87*e87b5039SStanislaw Gruszka 	const int map_reads = DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16);
88*e87b5039SStanislaw Gruszka 	u8 data[map_reads * 16];
89*e87b5039SStanislaw Gruszka 	int ret, i;
90*e87b5039SStanislaw Gruszka 	u32 start = 0, end = 0, cnt_free;
91*e87b5039SStanislaw Gruszka 
92*e87b5039SStanislaw Gruszka 	for (i = 0; i < map_reads; i++) {
93*e87b5039SStanislaw Gruszka 		ret = mt76x0_efuse_read(dev, MT_EE_USAGE_MAP_START + i * 16,
94*e87b5039SStanislaw Gruszka 					 data + i * 16, MT_EE_PHYSICAL_READ);
95*e87b5039SStanislaw Gruszka 		if (ret)
96*e87b5039SStanislaw Gruszka 			return ret;
97*e87b5039SStanislaw Gruszka 	}
98*e87b5039SStanislaw Gruszka 
99*e87b5039SStanislaw Gruszka 	for (i = 0; i < MT_EFUSE_USAGE_MAP_SIZE; i++)
100*e87b5039SStanislaw Gruszka 		if (!data[i]) {
101*e87b5039SStanislaw Gruszka 			if (!start)
102*e87b5039SStanislaw Gruszka 				start = MT_EE_USAGE_MAP_START + i;
103*e87b5039SStanislaw Gruszka 			end = MT_EE_USAGE_MAP_START + i;
104*e87b5039SStanislaw Gruszka 		}
105*e87b5039SStanislaw Gruszka 	cnt_free = end - start + 1;
106*e87b5039SStanislaw Gruszka 
107*e87b5039SStanislaw Gruszka 	if (MT_EFUSE_USAGE_MAP_SIZE - cnt_free < 5) {
108*e87b5039SStanislaw Gruszka 		dev_err(dev->mt76.dev, "Error: your device needs default EEPROM file and this driver doesn't support it!\n");
109*e87b5039SStanislaw Gruszka 		return -EINVAL;
110*e87b5039SStanislaw Gruszka 	}
111*e87b5039SStanislaw Gruszka 
112*e87b5039SStanislaw Gruszka 	return 0;
113*e87b5039SStanislaw Gruszka }
114*e87b5039SStanislaw Gruszka 
115*e87b5039SStanislaw Gruszka static void
116*e87b5039SStanislaw Gruszka mt76x0_set_chip_cap(struct mt76x0_dev *dev, u8 *eeprom)
117*e87b5039SStanislaw Gruszka {
118*e87b5039SStanislaw Gruszka 	enum mt76x2_board_type { BOARD_TYPE_2GHZ = 1, BOARD_TYPE_5GHZ = 2 };
119*e87b5039SStanislaw Gruszka 	u16 nic_conf0 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_0);
120*e87b5039SStanislaw Gruszka 	u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1);
121*e87b5039SStanislaw Gruszka 
122*e87b5039SStanislaw Gruszka 	dev_dbg(dev->mt76.dev, "NIC_CONF0: %04x NIC_CONF1: %04x\n", nic_conf0, nic_conf1);
123*e87b5039SStanislaw Gruszka 
124*e87b5039SStanislaw Gruszka 	switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, nic_conf0)) {
125*e87b5039SStanislaw Gruszka 	case BOARD_TYPE_5GHZ:
126*e87b5039SStanislaw Gruszka 		dev->ee->has_5ghz = true;
127*e87b5039SStanislaw Gruszka 		break;
128*e87b5039SStanislaw Gruszka 	case BOARD_TYPE_2GHZ:
129*e87b5039SStanislaw Gruszka 		dev->ee->has_2ghz = true;
130*e87b5039SStanislaw Gruszka 		break;
131*e87b5039SStanislaw Gruszka 	default:
132*e87b5039SStanislaw Gruszka 		dev->ee->has_2ghz = true;
133*e87b5039SStanislaw Gruszka 		dev->ee->has_5ghz = true;
134*e87b5039SStanislaw Gruszka 		break;
135*e87b5039SStanislaw Gruszka 	}
136*e87b5039SStanislaw Gruszka 
137*e87b5039SStanislaw Gruszka 	dev_dbg(dev->mt76.dev, "Has 2GHZ %d 5GHZ %d\n", dev->ee->has_2ghz, dev->ee->has_5ghz);
138*e87b5039SStanislaw Gruszka 
139*e87b5039SStanislaw Gruszka 	if (!field_valid(nic_conf1 & 0xff))
140*e87b5039SStanislaw Gruszka 		nic_conf1 &= 0xff00;
141*e87b5039SStanislaw Gruszka 
142*e87b5039SStanislaw Gruszka 	if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL)
143*e87b5039SStanislaw Gruszka 		dev_err(dev->mt76.dev,
144*e87b5039SStanislaw Gruszka 			"Error: this driver does not support HW RF ctrl\n");
145*e87b5039SStanislaw Gruszka 
146*e87b5039SStanislaw Gruszka 	if (!field_valid(nic_conf0 >> 8))
147*e87b5039SStanislaw Gruszka 		return;
148*e87b5039SStanislaw Gruszka 
149*e87b5039SStanislaw Gruszka 	if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 ||
150*e87b5039SStanislaw Gruszka 	    FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1)
151*e87b5039SStanislaw Gruszka 		dev_err(dev->mt76.dev,
152*e87b5039SStanislaw Gruszka 			"Error: device has more than 1 RX/TX stream!\n");
153*e87b5039SStanislaw Gruszka 
154*e87b5039SStanislaw Gruszka 	dev->ee->pa_type = FIELD_GET(MT_EE_NIC_CONF_0_PA_TYPE, nic_conf0);
155*e87b5039SStanislaw Gruszka 	dev_dbg(dev->mt76.dev, "PA Type %d\n", dev->ee->pa_type);
156*e87b5039SStanislaw Gruszka }
157*e87b5039SStanislaw Gruszka 
158*e87b5039SStanislaw Gruszka static int
159*e87b5039SStanislaw Gruszka mt76x0_set_macaddr(struct mt76x0_dev *dev, const u8 *eeprom)
160*e87b5039SStanislaw Gruszka {
161*e87b5039SStanislaw Gruszka 	const void *src = eeprom + MT_EE_MAC_ADDR;
162*e87b5039SStanislaw Gruszka 
163*e87b5039SStanislaw Gruszka 	ether_addr_copy(dev->macaddr, src);
164*e87b5039SStanislaw Gruszka 
165*e87b5039SStanislaw Gruszka 	if (!is_valid_ether_addr(dev->macaddr)) {
166*e87b5039SStanislaw Gruszka 		eth_random_addr(dev->macaddr);
167*e87b5039SStanislaw Gruszka 		dev_info(dev->mt76.dev,
168*e87b5039SStanislaw Gruszka 			 "Invalid MAC address, using random address %pM\n",
169*e87b5039SStanislaw Gruszka 			 dev->macaddr);
170*e87b5039SStanislaw Gruszka 	}
171*e87b5039SStanislaw Gruszka 
172*e87b5039SStanislaw Gruszka 	mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr));
173*e87b5039SStanislaw Gruszka 	mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) |
174*e87b5039SStanislaw Gruszka 		FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
175*e87b5039SStanislaw Gruszka 
176*e87b5039SStanislaw Gruszka 	return 0;
177*e87b5039SStanislaw Gruszka }
178*e87b5039SStanislaw Gruszka 
179*e87b5039SStanislaw Gruszka static void
180*e87b5039SStanislaw Gruszka mt76x0_set_temp_offset(struct mt76x0_dev *dev, u8 *eeprom)
181*e87b5039SStanislaw Gruszka {
182*e87b5039SStanislaw Gruszka 	u8 temp = eeprom[MT_EE_TEMP_OFFSET];
183*e87b5039SStanislaw Gruszka 
184*e87b5039SStanislaw Gruszka 	if (field_valid(temp))
185*e87b5039SStanislaw Gruszka 		dev->ee->temp_off = sign_extend(temp, 8);
186*e87b5039SStanislaw Gruszka 	else
187*e87b5039SStanislaw Gruszka 		dev->ee->temp_off = -10;
188*e87b5039SStanislaw Gruszka }
189*e87b5039SStanislaw Gruszka 
190*e87b5039SStanislaw Gruszka static void
191*e87b5039SStanislaw Gruszka mt76x0_set_country_reg(struct mt76x0_dev *dev, u8 *eeprom)
192*e87b5039SStanislaw Gruszka {
193*e87b5039SStanislaw Gruszka 	/* Note: - region 31 is not valid for mt76x0 (see rtmp_init.c)
194*e87b5039SStanislaw Gruszka 	 *	 - comments in rtmp_def.h are incorrect (see rt_channel.c)
195*e87b5039SStanislaw Gruszka 	 */
196*e87b5039SStanislaw Gruszka 	static const struct reg_channel_bounds chan_bounds[] = {
197*e87b5039SStanislaw Gruszka 		/* EEPROM country regions 0 - 7 */
198*e87b5039SStanislaw Gruszka 		{  1, 11 },	{  1, 13 },	{ 10,  2 },	{ 10,  4 },
199*e87b5039SStanislaw Gruszka 		{ 14,  1 },	{  1, 14 },	{  3,  7 },	{  5,  9 },
200*e87b5039SStanislaw Gruszka 		/* EEPROM country regions 32 - 33 */
201*e87b5039SStanislaw Gruszka 		{  1, 11 },	{  1, 14 }
202*e87b5039SStanislaw Gruszka 	};
203*e87b5039SStanislaw Gruszka 	u8 val = eeprom[MT_EE_COUNTRY_REGION_2GHZ];
204*e87b5039SStanislaw Gruszka 	int idx = -1;
205*e87b5039SStanislaw Gruszka 
206*e87b5039SStanislaw Gruszka 	dev_dbg(dev->mt76.dev, "REG 2GHZ %u REG 5GHZ %u\n", val, eeprom[MT_EE_COUNTRY_REGION_5GHZ]);
207*e87b5039SStanislaw Gruszka 	if (val < 8)
208*e87b5039SStanislaw Gruszka 		idx = val;
209*e87b5039SStanislaw Gruszka 	if (val > 31 && val < 33)
210*e87b5039SStanislaw Gruszka 		idx = val - 32 + 8;
211*e87b5039SStanislaw Gruszka 
212*e87b5039SStanislaw Gruszka 	if (idx != -1)
213*e87b5039SStanislaw Gruszka 		dev_info(dev->mt76.dev,
214*e87b5039SStanislaw Gruszka 			 "EEPROM country region %02hhx (channels %hhd-%hhd)\n",
215*e87b5039SStanislaw Gruszka 			 val, chan_bounds[idx].start,
216*e87b5039SStanislaw Gruszka 			 chan_bounds[idx].start + chan_bounds[idx].num - 1);
217*e87b5039SStanislaw Gruszka 	else
218*e87b5039SStanislaw Gruszka 		idx = 5; /* channels 1 - 14 */
219*e87b5039SStanislaw Gruszka 
220*e87b5039SStanislaw Gruszka 	dev->ee->reg = chan_bounds[idx];
221*e87b5039SStanislaw Gruszka 
222*e87b5039SStanislaw Gruszka 	/* TODO: country region 33 is special - phy should be set to B-mode
223*e87b5039SStanislaw Gruszka 	 *	 before entering channel 14 (see sta/connect.c)
224*e87b5039SStanislaw Gruszka 	 */
225*e87b5039SStanislaw Gruszka }
226*e87b5039SStanislaw Gruszka 
227*e87b5039SStanislaw Gruszka static void
228*e87b5039SStanislaw Gruszka mt76x0_set_rf_freq_off(struct mt76x0_dev *dev, u8 *eeprom)
229*e87b5039SStanislaw Gruszka {
230*e87b5039SStanislaw Gruszka 	u8 comp;
231*e87b5039SStanislaw Gruszka 
232*e87b5039SStanislaw Gruszka 	dev->ee->rf_freq_off = field_validate(eeprom[MT_EE_FREQ_OFFSET]);
233*e87b5039SStanislaw Gruszka 	comp = field_validate(eeprom[MT_EE_FREQ_OFFSET_COMPENSATION]);
234*e87b5039SStanislaw Gruszka 
235*e87b5039SStanislaw Gruszka 	if (comp & BIT(7))
236*e87b5039SStanislaw Gruszka 		dev->ee->rf_freq_off -= comp & 0x7f;
237*e87b5039SStanislaw Gruszka 	else
238*e87b5039SStanislaw Gruszka 		dev->ee->rf_freq_off += comp;
239*e87b5039SStanislaw Gruszka }
240*e87b5039SStanislaw Gruszka 
241*e87b5039SStanislaw Gruszka static void
242*e87b5039SStanislaw Gruszka mt76x0_set_lna_gain(struct mt76x0_dev *dev, u8 *eeprom)
243*e87b5039SStanislaw Gruszka {
244*e87b5039SStanislaw Gruszka 	s8 gain;
245*e87b5039SStanislaw Gruszka 
246*e87b5039SStanislaw Gruszka 	dev->ee->lna_gain_2ghz = eeprom[MT_EE_LNA_GAIN_2GHZ];
247*e87b5039SStanislaw Gruszka 	dev->ee->lna_gain_5ghz[0] = eeprom[MT_EE_LNA_GAIN_5GHZ_0];
248*e87b5039SStanislaw Gruszka 
249*e87b5039SStanislaw Gruszka 	gain = eeprom[MT_EE_LNA_GAIN_5GHZ_1];
250*e87b5039SStanislaw Gruszka 	if (gain == 0xff || gain == 0)
251*e87b5039SStanislaw Gruszka 		dev->ee->lna_gain_5ghz[1] = dev->ee->lna_gain_5ghz[0];
252*e87b5039SStanislaw Gruszka 	else
253*e87b5039SStanislaw Gruszka 		dev->ee->lna_gain_5ghz[1] = gain;
254*e87b5039SStanislaw Gruszka 
255*e87b5039SStanislaw Gruszka 	gain = eeprom[MT_EE_LNA_GAIN_5GHZ_2];
256*e87b5039SStanislaw Gruszka 	if (gain == 0xff || gain == 0)
257*e87b5039SStanislaw Gruszka 		dev->ee->lna_gain_5ghz[2] = dev->ee->lna_gain_5ghz[0];
258*e87b5039SStanislaw Gruszka 	else
259*e87b5039SStanislaw Gruszka 		dev->ee->lna_gain_5ghz[2] = gain;
260*e87b5039SStanislaw Gruszka }
261*e87b5039SStanislaw Gruszka 
262*e87b5039SStanislaw Gruszka static void
263*e87b5039SStanislaw Gruszka mt76x0_set_rssi_offset(struct mt76x0_dev *dev, u8 *eeprom)
264*e87b5039SStanislaw Gruszka {
265*e87b5039SStanislaw Gruszka 	int i;
266*e87b5039SStanislaw Gruszka 	s8 *rssi_offset = dev->ee->rssi_offset_2ghz;
267*e87b5039SStanislaw Gruszka 
268*e87b5039SStanislaw Gruszka 	for (i = 0; i < 2; i++) {
269*e87b5039SStanislaw Gruszka 		rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET + i];
270*e87b5039SStanislaw Gruszka 
271*e87b5039SStanislaw Gruszka 		if (rssi_offset[i] < -10 || rssi_offset[i] > 10) {
272*e87b5039SStanislaw Gruszka 			dev_warn(dev->mt76.dev,
273*e87b5039SStanislaw Gruszka 				 "Warning: EEPROM RSSI is invalid %02hhx\n",
274*e87b5039SStanislaw Gruszka 				 rssi_offset[i]);
275*e87b5039SStanislaw Gruszka 			rssi_offset[i] = 0;
276*e87b5039SStanislaw Gruszka 		}
277*e87b5039SStanislaw Gruszka 	}
278*e87b5039SStanislaw Gruszka 
279*e87b5039SStanislaw Gruszka 	rssi_offset = dev->ee->rssi_offset_5ghz;
280*e87b5039SStanislaw Gruszka 
281*e87b5039SStanislaw Gruszka 	for (i = 0; i < 3; i++) {
282*e87b5039SStanislaw Gruszka 		rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET_5GHZ + i];
283*e87b5039SStanislaw Gruszka 
284*e87b5039SStanislaw Gruszka 		if (rssi_offset[i] < -10 || rssi_offset[i] > 10) {
285*e87b5039SStanislaw Gruszka 			dev_warn(dev->mt76.dev,
286*e87b5039SStanislaw Gruszka 				 "Warning: EEPROM RSSI is invalid %02hhx\n",
287*e87b5039SStanislaw Gruszka 				 rssi_offset[i]);
288*e87b5039SStanislaw Gruszka 			rssi_offset[i] = 0;
289*e87b5039SStanislaw Gruszka 		}
290*e87b5039SStanislaw Gruszka 	}
291*e87b5039SStanislaw Gruszka }
292*e87b5039SStanislaw Gruszka 
293*e87b5039SStanislaw Gruszka static u32
294*e87b5039SStanislaw Gruszka calc_bw40_power_rate(u32 value, int delta)
295*e87b5039SStanislaw Gruszka {
296*e87b5039SStanislaw Gruszka 	u32 ret = 0;
297*e87b5039SStanislaw Gruszka 	int i, tmp;
298*e87b5039SStanislaw Gruszka 
299*e87b5039SStanislaw Gruszka 	for (i = 0; i < 4; i++) {
300*e87b5039SStanislaw Gruszka 		tmp = s6_to_int((value >> i*8) & 0xff) + delta;
301*e87b5039SStanislaw Gruszka 		ret |= (u32)(int_to_s6(tmp)) << i*8;
302*e87b5039SStanislaw Gruszka 	}
303*e87b5039SStanislaw Gruszka 
304*e87b5039SStanislaw Gruszka 	return ret;
305*e87b5039SStanislaw Gruszka }
306*e87b5039SStanislaw Gruszka 
307*e87b5039SStanislaw Gruszka static s8
308*e87b5039SStanislaw Gruszka get_delta(u8 val)
309*e87b5039SStanislaw Gruszka {
310*e87b5039SStanislaw Gruszka 	s8 ret;
311*e87b5039SStanislaw Gruszka 
312*e87b5039SStanislaw Gruszka 	if (!field_valid(val) || !(val & BIT(7)))
313*e87b5039SStanislaw Gruszka 		return 0;
314*e87b5039SStanislaw Gruszka 
315*e87b5039SStanislaw Gruszka 	ret = val & 0x1f;
316*e87b5039SStanislaw Gruszka 	if (ret > 8)
317*e87b5039SStanislaw Gruszka 		ret = 8;
318*e87b5039SStanislaw Gruszka 	if (val & BIT(6))
319*e87b5039SStanislaw Gruszka 		ret = -ret;
320*e87b5039SStanislaw Gruszka 
321*e87b5039SStanislaw Gruszka 	return ret;
322*e87b5039SStanislaw Gruszka }
323*e87b5039SStanislaw Gruszka 
324*e87b5039SStanislaw Gruszka static void
325*e87b5039SStanislaw Gruszka mt76x0_set_tx_power_per_rate(struct mt76x0_dev *dev, u8 *eeprom)
326*e87b5039SStanislaw Gruszka {
327*e87b5039SStanislaw Gruszka 	s8 bw40_delta_2g, bw40_delta_5g;
328*e87b5039SStanislaw Gruszka 	u32 val;
329*e87b5039SStanislaw Gruszka 	int i;
330*e87b5039SStanislaw Gruszka 
331*e87b5039SStanislaw Gruszka 	bw40_delta_2g = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40]);
332*e87b5039SStanislaw Gruszka 	bw40_delta_5g = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40 + 1]);
333*e87b5039SStanislaw Gruszka 
334*e87b5039SStanislaw Gruszka 	for (i = 0; i < 5; i++) {
335*e87b5039SStanislaw Gruszka 		val = get_unaligned_le32(eeprom + MT_EE_TX_POWER_BYRATE(i));
336*e87b5039SStanislaw Gruszka 
337*e87b5039SStanislaw Gruszka 		/* Skip last 16 bits. */
338*e87b5039SStanislaw Gruszka 		if (i == 4)
339*e87b5039SStanislaw Gruszka 			val &= 0x0000ffff;
340*e87b5039SStanislaw Gruszka 
341*e87b5039SStanislaw Gruszka 		dev->ee->tx_pwr_cfg_2g[i][0] = val;
342*e87b5039SStanislaw Gruszka 		dev->ee->tx_pwr_cfg_2g[i][1] = calc_bw40_power_rate(val, bw40_delta_2g);
343*e87b5039SStanislaw Gruszka 	}
344*e87b5039SStanislaw Gruszka 
345*e87b5039SStanislaw Gruszka 	/* Reading per rate tx power for 5 GHz band is a bit more complex. Note
346*e87b5039SStanislaw Gruszka 	 * we mix 16 bit and 32 bit reads and sometimes do shifts.
347*e87b5039SStanislaw Gruszka 	 */
348*e87b5039SStanislaw Gruszka 	val = get_unaligned_le16(eeprom + 0x120);
349*e87b5039SStanislaw Gruszka 	val <<= 16;
350*e87b5039SStanislaw Gruszka 	dev->ee->tx_pwr_cfg_5g[0][0] = val;
351*e87b5039SStanislaw Gruszka 	dev->ee->tx_pwr_cfg_5g[0][1] = calc_bw40_power_rate(val, bw40_delta_5g);
352*e87b5039SStanislaw Gruszka 
353*e87b5039SStanislaw Gruszka 	val = get_unaligned_le32(eeprom + 0x122);
354*e87b5039SStanislaw Gruszka 	dev->ee->tx_pwr_cfg_5g[1][0] = val;
355*e87b5039SStanislaw Gruszka 	dev->ee->tx_pwr_cfg_5g[1][1] = calc_bw40_power_rate(val, bw40_delta_5g);
356*e87b5039SStanislaw Gruszka 
357*e87b5039SStanislaw Gruszka 	val = get_unaligned_le16(eeprom + 0x126);
358*e87b5039SStanislaw Gruszka 	dev->ee->tx_pwr_cfg_5g[2][0] = val;
359*e87b5039SStanislaw Gruszka 	dev->ee->tx_pwr_cfg_5g[2][1] = calc_bw40_power_rate(val, bw40_delta_5g);
360*e87b5039SStanislaw Gruszka 
361*e87b5039SStanislaw Gruszka 	val = get_unaligned_le16(eeprom + 0xec);
362*e87b5039SStanislaw Gruszka 	val <<= 16;
363*e87b5039SStanislaw Gruszka 	dev->ee->tx_pwr_cfg_5g[3][0] = val;
364*e87b5039SStanislaw Gruszka 	dev->ee->tx_pwr_cfg_5g[3][1] = calc_bw40_power_rate(val, bw40_delta_5g);
365*e87b5039SStanislaw Gruszka 
366*e87b5039SStanislaw Gruszka 	val = get_unaligned_le16(eeprom + 0xee);
367*e87b5039SStanislaw Gruszka 	dev->ee->tx_pwr_cfg_5g[4][0] = val;
368*e87b5039SStanislaw Gruszka 	dev->ee->tx_pwr_cfg_5g[4][1] = calc_bw40_power_rate(val, bw40_delta_5g);
369*e87b5039SStanislaw Gruszka }
370*e87b5039SStanislaw Gruszka 
371*e87b5039SStanislaw Gruszka static void
372*e87b5039SStanislaw Gruszka mt76x0_set_tx_power_per_chan(struct mt76x0_dev *dev, u8 *eeprom)
373*e87b5039SStanislaw Gruszka {
374*e87b5039SStanislaw Gruszka 	int i;
375*e87b5039SStanislaw Gruszka 	u8 tx_pwr;
376*e87b5039SStanislaw Gruszka 
377*e87b5039SStanislaw Gruszka 	for (i = 0; i < 14; i++) {
378*e87b5039SStanislaw Gruszka 		tx_pwr = eeprom[MT_EE_TX_POWER_OFFSET_2GHZ + i];
379*e87b5039SStanislaw Gruszka 		if (tx_pwr <= 0x3f && tx_pwr > 0)
380*e87b5039SStanislaw Gruszka 			dev->ee->tx_pwr_per_chan[i] = tx_pwr;
381*e87b5039SStanislaw Gruszka 		else
382*e87b5039SStanislaw Gruszka 			dev->ee->tx_pwr_per_chan[i] = 5;
383*e87b5039SStanislaw Gruszka 	}
384*e87b5039SStanislaw Gruszka 
385*e87b5039SStanislaw Gruszka 	for (i = 0; i < 40; i++) {
386*e87b5039SStanislaw Gruszka 		tx_pwr = eeprom[MT_EE_TX_POWER_OFFSET_5GHZ + i];
387*e87b5039SStanislaw Gruszka 		if (tx_pwr <= 0x3f && tx_pwr > 0)
388*e87b5039SStanislaw Gruszka 			dev->ee->tx_pwr_per_chan[14 + i] = tx_pwr;
389*e87b5039SStanislaw Gruszka 		else
390*e87b5039SStanislaw Gruszka 			dev->ee->tx_pwr_per_chan[14 + i] = 5;
391*e87b5039SStanislaw Gruszka 	}
392*e87b5039SStanislaw Gruszka 
393*e87b5039SStanislaw Gruszka 	dev->ee->tx_pwr_per_chan[54] = dev->ee->tx_pwr_per_chan[22];
394*e87b5039SStanislaw Gruszka 	dev->ee->tx_pwr_per_chan[55] = dev->ee->tx_pwr_per_chan[28];
395*e87b5039SStanislaw Gruszka 	dev->ee->tx_pwr_per_chan[56] = dev->ee->tx_pwr_per_chan[34];
396*e87b5039SStanislaw Gruszka 	dev->ee->tx_pwr_per_chan[57] = dev->ee->tx_pwr_per_chan[44];
397*e87b5039SStanislaw Gruszka }
398*e87b5039SStanislaw Gruszka 
399*e87b5039SStanislaw Gruszka int
400*e87b5039SStanislaw Gruszka mt76x0_eeprom_init(struct mt76x0_dev *dev)
401*e87b5039SStanislaw Gruszka {
402*e87b5039SStanislaw Gruszka 	u8 *eeprom;
403*e87b5039SStanislaw Gruszka 	int i, ret;
404*e87b5039SStanislaw Gruszka 
405*e87b5039SStanislaw Gruszka 	ret = mt76x0_efuse_physical_size_check(dev);
406*e87b5039SStanislaw Gruszka 	if (ret)
407*e87b5039SStanislaw Gruszka 		return ret;
408*e87b5039SStanislaw Gruszka 
409*e87b5039SStanislaw Gruszka 	dev->ee = devm_kzalloc(dev->mt76.dev, sizeof(*dev->ee), GFP_KERNEL);
410*e87b5039SStanislaw Gruszka 	if (!dev->ee)
411*e87b5039SStanislaw Gruszka 		return -ENOMEM;
412*e87b5039SStanislaw Gruszka 
413*e87b5039SStanislaw Gruszka 	eeprom = kmalloc(MT76X0_EEPROM_SIZE, GFP_KERNEL);
414*e87b5039SStanislaw Gruszka 	if (!eeprom)
415*e87b5039SStanislaw Gruszka 		return -ENOMEM;
416*e87b5039SStanislaw Gruszka 
417*e87b5039SStanislaw Gruszka 	for (i = 0; i + 16 <= MT76X0_EEPROM_SIZE; i += 16) {
418*e87b5039SStanislaw Gruszka 		ret = mt76x0_efuse_read(dev, i, eeprom + i, MT_EE_READ);
419*e87b5039SStanislaw Gruszka 		if (ret)
420*e87b5039SStanislaw Gruszka 			goto out;
421*e87b5039SStanislaw Gruszka 	}
422*e87b5039SStanislaw Gruszka 
423*e87b5039SStanislaw Gruszka 	if (eeprom[MT_EE_VERSION_EE] > MT76X0U_EE_MAX_VER)
424*e87b5039SStanislaw Gruszka 		dev_warn(dev->mt76.dev,
425*e87b5039SStanislaw Gruszka 			 "Warning: unsupported EEPROM version %02hhx\n",
426*e87b5039SStanislaw Gruszka 			 eeprom[MT_EE_VERSION_EE]);
427*e87b5039SStanislaw Gruszka 	dev_info(dev->mt76.dev, "EEPROM ver:%02hhx fae:%02hhx\n",
428*e87b5039SStanislaw Gruszka 		 eeprom[MT_EE_VERSION_EE], eeprom[MT_EE_VERSION_FAE]);
429*e87b5039SStanislaw Gruszka 
430*e87b5039SStanislaw Gruszka 	mt76x0_set_macaddr(dev, eeprom);
431*e87b5039SStanislaw Gruszka 	mt76x0_set_chip_cap(dev, eeprom);
432*e87b5039SStanislaw Gruszka 	mt76x0_set_country_reg(dev, eeprom);
433*e87b5039SStanislaw Gruszka 	mt76x0_set_rf_freq_off(dev, eeprom);
434*e87b5039SStanislaw Gruszka 	mt76x0_set_temp_offset(dev, eeprom);
435*e87b5039SStanislaw Gruszka 	mt76x0_set_lna_gain(dev, eeprom);
436*e87b5039SStanislaw Gruszka 	mt76x0_set_rssi_offset(dev, eeprom);
437*e87b5039SStanislaw Gruszka 	dev->chainmask = 0x0101;
438*e87b5039SStanislaw Gruszka 
439*e87b5039SStanislaw Gruszka 	mt76x0_set_tx_power_per_rate(dev, eeprom);
440*e87b5039SStanislaw Gruszka 	mt76x0_set_tx_power_per_chan(dev, eeprom);
441*e87b5039SStanislaw Gruszka 
442*e87b5039SStanislaw Gruszka out:
443*e87b5039SStanislaw Gruszka 	kfree(eeprom);
444*e87b5039SStanislaw Gruszka 	return ret;
445*e87b5039SStanislaw Gruszka }
446