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