mt76x0: unify lna_gain parsing
[sfrench/cifs-2.6.git] / drivers / net / wireless / mediatek / mt76 / mt76x0 / eeprom.c
1 /*
2  * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
3  * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
4  * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2
8  * as published by the Free Software Foundation
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
15
16 #include <linux/of.h>
17 #include <linux/mtd/mtd.h>
18 #include <linux/mtd/partitions.h>
19 #include <linux/etherdevice.h>
20 #include <asm/unaligned.h>
21 #include "mt76x0.h"
22 #include "eeprom.h"
23
24 #define MT_MAP_READS    DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16)
25 static int
26 mt76x0_efuse_physical_size_check(struct mt76x0_dev *dev)
27 {
28         u8 data[MT_MAP_READS * 16];
29         int ret, i;
30         u32 start = 0, end = 0, cnt_free;
31
32         ret = mt76x02_get_efuse_data(&dev->mt76, MT_EE_USAGE_MAP_START,
33                                      data, sizeof(data), MT_EE_PHYSICAL_READ);
34         if (ret)
35                 return ret;
36
37         for (i = 0; i < MT_EFUSE_USAGE_MAP_SIZE; i++)
38                 if (!data[i]) {
39                         if (!start)
40                                 start = MT_EE_USAGE_MAP_START + i;
41                         end = MT_EE_USAGE_MAP_START + i;
42                 }
43         cnt_free = end - start + 1;
44
45         if (MT_EFUSE_USAGE_MAP_SIZE - cnt_free < 5) {
46                 dev_err(dev->mt76.dev,
47                         "driver does not support default EEPROM\n");
48                 return -EINVAL;
49         }
50
51         return 0;
52 }
53
54 static void
55 mt76x0_set_chip_cap(struct mt76x0_dev *dev, u8 *eeprom)
56 {
57         enum mt76x2_board_type { BOARD_TYPE_2GHZ = 1, BOARD_TYPE_5GHZ = 2 };
58         u16 nic_conf0 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_0);
59         u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1);
60
61         dev_dbg(dev->mt76.dev, "NIC_CONF0: %04x NIC_CONF1: %04x\n", nic_conf0, nic_conf1);
62
63         switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, nic_conf0)) {
64         case BOARD_TYPE_5GHZ:
65                 dev->mt76.cap.has_5ghz = true;
66                 break;
67         case BOARD_TYPE_2GHZ:
68                 dev->mt76.cap.has_2ghz = true;
69                 break;
70         default:
71                 dev->mt76.cap.has_2ghz = true;
72                 dev->mt76.cap.has_5ghz = true;
73                 break;
74         }
75
76         dev_dbg(dev->mt76.dev, "Has 2GHZ %d 5GHZ %d\n",
77                 dev->mt76.cap.has_2ghz, dev->mt76.cap.has_5ghz);
78
79         if (!mt76x02_field_valid(nic_conf1 & 0xff))
80                 nic_conf1 &= 0xff00;
81
82         if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL)
83                 dev_err(dev->mt76.dev,
84                         "Error: this driver does not support HW RF ctrl\n");
85
86         if (!mt76x02_field_valid(nic_conf0 >> 8))
87                 return;
88
89         if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 ||
90             FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1)
91                 dev_err(dev->mt76.dev,
92                         "Error: device has more than 1 RX/TX stream!\n");
93 }
94
95 static void
96 mt76x0_set_temp_offset(struct mt76x0_dev *dev, u8 *eeprom)
97 {
98         u8 temp = eeprom[MT_EE_TEMP_OFFSET];
99
100         if (mt76x02_field_valid(temp))
101                 dev->ee->temp_off = mt76x02_sign_extend(temp, 8);
102         else
103                 dev->ee->temp_off = -10;
104 }
105
106 static void
107 mt76x0_set_rf_freq_off(struct mt76x0_dev *dev, u8 *eeprom)
108 {
109         u8 comp;
110
111         comp = eeprom[MT_EE_FREQ_OFFSET_COMPENSATION];
112         if (!mt76x02_field_valid(comp))
113                 comp = 0;
114
115         dev->ee->rf_freq_off = eeprom[MT_EE_FREQ_OFFSET];
116         if (!mt76x02_field_valid(dev->ee->rf_freq_off))
117                 dev->ee->rf_freq_off = 0;
118
119         if (comp & BIT(7))
120                 dev->ee->rf_freq_off -= comp & 0x7f;
121         else
122                 dev->ee->rf_freq_off += comp;
123 }
124
125 void mt76x0_read_rx_gain(struct mt76x0_dev *dev)
126 {
127         struct ieee80211_channel *chan = dev->mt76.chandef.chan;
128         struct mt76x0_caldata *caldata = &dev->caldata;
129         s8 lna_5g[3], lna_2g;
130         u16 rssi_offset;
131
132         mt76x02_get_rx_gain(&dev->mt76, chan->band, &rssi_offset,
133                             &lna_2g, lna_5g);
134         caldata->lna_gain = mt76x02_get_lna_gain(&dev->mt76, &lna_2g,
135                                                  lna_5g, chan);
136
137 }
138
139 static void
140 mt76x0_set_rssi_offset(struct mt76x0_dev *dev, u8 *eeprom)
141 {
142         int i;
143         s8 *rssi_offset = dev->ee->rssi_offset_2ghz;
144
145         for (i = 0; i < 2; i++) {
146                 rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET_2G_0 + i];
147
148                 if (rssi_offset[i] < -10 || rssi_offset[i] > 10) {
149                         dev_warn(dev->mt76.dev,
150                                  "Warning: EEPROM RSSI is invalid %02hhx\n",
151                                  rssi_offset[i]);
152                         rssi_offset[i] = 0;
153                 }
154         }
155
156         rssi_offset = dev->ee->rssi_offset_5ghz;
157
158         for (i = 0; i < 3; i++) {
159                 rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET_5G_0 + i];
160
161                 if (rssi_offset[i] < -10 || rssi_offset[i] > 10) {
162                         dev_warn(dev->mt76.dev,
163                                  "Warning: EEPROM RSSI is invalid %02hhx\n",
164                                  rssi_offset[i]);
165                         rssi_offset[i] = 0;
166                 }
167         }
168 }
169
170 static u32
171 calc_bw40_power_rate(u32 value, int delta)
172 {
173         u32 ret = 0;
174         int i, tmp;
175
176         for (i = 0; i < 4; i++) {
177                 tmp = s6_to_int((value >> i*8) & 0xff) + delta;
178                 ret |= (u32)(int_to_s6(tmp)) << i*8;
179         }
180
181         return ret;
182 }
183
184 static s8
185 get_delta(u8 val)
186 {
187         s8 ret;
188
189         if (!mt76x02_field_valid(val) || !(val & BIT(7)))
190                 return 0;
191
192         ret = val & 0x1f;
193         if (ret > 8)
194                 ret = 8;
195         if (val & BIT(6))
196                 ret = -ret;
197
198         return ret;
199 }
200
201 static void
202 mt76x0_set_tx_power_per_rate(struct mt76x0_dev *dev, u8 *eeprom)
203 {
204         s8 bw40_delta_2g, bw40_delta_5g;
205         u32 val;
206         int i;
207
208         bw40_delta_2g = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40]);
209         bw40_delta_5g = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40 + 1]);
210
211         for (i = 0; i < 5; i++) {
212                 val = get_unaligned_le32(eeprom + MT_EE_TX_POWER_BYRATE(i));
213
214                 /* Skip last 16 bits. */
215                 if (i == 4)
216                         val &= 0x0000ffff;
217
218                 dev->ee->tx_pwr_cfg_2g[i][0] = val;
219                 dev->ee->tx_pwr_cfg_2g[i][1] = calc_bw40_power_rate(val, bw40_delta_2g);
220         }
221
222         /* Reading per rate tx power for 5 GHz band is a bit more complex. Note
223          * we mix 16 bit and 32 bit reads and sometimes do shifts.
224          */
225         val = get_unaligned_le16(eeprom + 0x120);
226         val <<= 16;
227         dev->ee->tx_pwr_cfg_5g[0][0] = val;
228         dev->ee->tx_pwr_cfg_5g[0][1] = calc_bw40_power_rate(val, bw40_delta_5g);
229
230         val = get_unaligned_le32(eeprom + 0x122);
231         dev->ee->tx_pwr_cfg_5g[1][0] = val;
232         dev->ee->tx_pwr_cfg_5g[1][1] = calc_bw40_power_rate(val, bw40_delta_5g);
233
234         val = get_unaligned_le16(eeprom + 0x126);
235         dev->ee->tx_pwr_cfg_5g[2][0] = val;
236         dev->ee->tx_pwr_cfg_5g[2][1] = calc_bw40_power_rate(val, bw40_delta_5g);
237
238         val = get_unaligned_le16(eeprom + 0xec);
239         val <<= 16;
240         dev->ee->tx_pwr_cfg_5g[3][0] = val;
241         dev->ee->tx_pwr_cfg_5g[3][1] = calc_bw40_power_rate(val, bw40_delta_5g);
242
243         val = get_unaligned_le16(eeprom + 0xee);
244         dev->ee->tx_pwr_cfg_5g[4][0] = val;
245         dev->ee->tx_pwr_cfg_5g[4][1] = calc_bw40_power_rate(val, bw40_delta_5g);
246 }
247
248 static void
249 mt76x0_set_tx_power_per_chan(struct mt76x0_dev *dev, u8 *eeprom)
250 {
251         int i;
252         u8 tx_pwr;
253
254         for (i = 0; i < 14; i++) {
255                 tx_pwr = eeprom[MT_EE_TX_POWER_DELTA_BW80 + i];
256                 if (tx_pwr <= 0x3f && tx_pwr > 0)
257                         dev->ee->tx_pwr_per_chan[i] = tx_pwr;
258                 else
259                         dev->ee->tx_pwr_per_chan[i] = 5;
260         }
261
262         for (i = 0; i < 40; i++) {
263                 tx_pwr = eeprom[MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE + 2 + i];
264                 if (tx_pwr <= 0x3f && tx_pwr > 0)
265                         dev->ee->tx_pwr_per_chan[14 + i] = tx_pwr;
266                 else
267                         dev->ee->tx_pwr_per_chan[14 + i] = 5;
268         }
269
270         dev->ee->tx_pwr_per_chan[54] = dev->ee->tx_pwr_per_chan[22];
271         dev->ee->tx_pwr_per_chan[55] = dev->ee->tx_pwr_per_chan[28];
272         dev->ee->tx_pwr_per_chan[56] = dev->ee->tx_pwr_per_chan[34];
273         dev->ee->tx_pwr_per_chan[57] = dev->ee->tx_pwr_per_chan[44];
274 }
275
276 int
277 mt76x0_eeprom_init(struct mt76x0_dev *dev)
278 {
279         u8 *eeprom;
280         int ret;
281
282         ret = mt76x0_efuse_physical_size_check(dev);
283         if (ret)
284                 return ret;
285
286         ret = mt76_eeprom_init(&dev->mt76, MT76X0_EEPROM_SIZE);
287         if (ret < 0)
288                 return ret;
289
290         dev->ee = devm_kzalloc(dev->mt76.dev, sizeof(*dev->ee), GFP_KERNEL);
291         if (!dev->ee)
292                 return -ENOMEM;
293
294         eeprom = kmalloc(MT76X0_EEPROM_SIZE, GFP_KERNEL);
295         if (!eeprom)
296                 return -ENOMEM;
297
298         ret = mt76x02_get_efuse_data(&dev->mt76, 0, eeprom,
299                                      MT76X0_EEPROM_SIZE, MT_EE_READ);
300         if (ret)
301                 goto out;
302
303         if (eeprom[MT_EE_VERSION + 1] > MT76X0U_EE_MAX_VER)
304                 dev_warn(dev->mt76.dev,
305                          "Warning: unsupported EEPROM version %02hhx\n",
306                          eeprom[MT_EE_VERSION + 1]);
307         dev_info(dev->mt76.dev, "EEPROM ver:%02hhx fae:%02hhx\n",
308                  eeprom[MT_EE_VERSION + 1], eeprom[MT_EE_VERSION]);
309
310         mt76x02_mac_setaddr(&dev->mt76, eeprom + MT_EE_MAC_ADDR);
311         mt76x0_set_chip_cap(dev, eeprom);
312         mt76x0_set_rf_freq_off(dev, eeprom);
313         mt76x0_set_temp_offset(dev, eeprom);
314         mt76x0_set_rssi_offset(dev, eeprom);
315         dev->chainmask = 0x0101;
316
317         mt76x0_set_tx_power_per_rate(dev, eeprom);
318         mt76x0_set_tx_power_per_chan(dev, eeprom);
319
320 out:
321         kfree(eeprom);
322         return ret;
323 }
324
325 MODULE_LICENSE("Dual BSD/GPL");