]>
Commit | Line | Data |
---|---|---|
5f0d10ce LB |
1 | /* |
2 | * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> | |
3 | * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> | |
4 | * | |
5 | * Permission to use, copy, modify, and/or distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
18 | #include "mt76x2.h" | |
1613c621 LB |
19 | #include "eeprom.h" |
20 | #include "mcu.h" | |
21 | #include "../mt76x02_phy.h" | |
5f0d10ce LB |
22 | |
23 | static void | |
e40803f2 | 24 | mt76x2_adjust_high_lna_gain(struct mt76x02_dev *dev, int reg, s8 offset) |
5f0d10ce LB |
25 | { |
26 | s8 gain; | |
27 | ||
28 | gain = FIELD_GET(MT_BBP_AGC_LNA_HIGH_GAIN, mt76_rr(dev, MT_BBP(AGC, reg))); | |
29 | gain -= offset / 2; | |
30 | mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_LNA_HIGH_GAIN, gain); | |
31 | } | |
32 | ||
33 | static void | |
e40803f2 | 34 | mt76x2_adjust_agc_gain(struct mt76x02_dev *dev, int reg, s8 offset) |
5f0d10ce LB |
35 | { |
36 | s8 gain; | |
37 | ||
38 | gain = FIELD_GET(MT_BBP_AGC_GAIN, mt76_rr(dev, MT_BBP(AGC, reg))); | |
39 | gain += offset; | |
40 | mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_GAIN, gain); | |
41 | } | |
42 | ||
e40803f2 | 43 | void mt76x2_apply_gain_adj(struct mt76x02_dev *dev) |
5f0d10ce LB |
44 | { |
45 | s8 *gain_adj = dev->cal.rx.high_gain; | |
46 | ||
47 | mt76x2_adjust_high_lna_gain(dev, 4, gain_adj[0]); | |
48 | mt76x2_adjust_high_lna_gain(dev, 5, gain_adj[1]); | |
49 | ||
50 | mt76x2_adjust_agc_gain(dev, 8, gain_adj[0]); | |
51 | mt76x2_adjust_agc_gain(dev, 9, gain_adj[1]); | |
52 | } | |
53 | EXPORT_SYMBOL_GPL(mt76x2_apply_gain_adj); | |
54 | ||
e40803f2 | 55 | void mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev, |
5f0d10ce LB |
56 | enum nl80211_band band) |
57 | { | |
58 | u32 pa_mode[2]; | |
59 | u32 pa_mode_adj; | |
60 | ||
61 | if (band == NL80211_BAND_2GHZ) { | |
62 | pa_mode[0] = 0x010055ff; | |
63 | pa_mode[1] = 0x00550055; | |
64 | ||
65 | mt76_wr(dev, MT_TX_ALC_CFG_2, 0x35160a00); | |
66 | mt76_wr(dev, MT_TX_ALC_CFG_3, 0x35160a06); | |
67 | ||
26a9daa6 | 68 | if (mt76x02_ext_pa_enabled(dev, band)) { |
5f0d10ce LB |
69 | mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0x0000ec00); |
70 | mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0x0000ec00); | |
71 | } else { | |
72 | mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0xf4000200); | |
73 | mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0xfa000200); | |
74 | } | |
75 | } else { | |
76 | pa_mode[0] = 0x0000ffff; | |
77 | pa_mode[1] = 0x00ff00ff; | |
78 | ||
26a9daa6 | 79 | if (mt76x02_ext_pa_enabled(dev, band)) { |
5f0d10ce LB |
80 | mt76_wr(dev, MT_TX_ALC_CFG_2, 0x2f0f0400); |
81 | mt76_wr(dev, MT_TX_ALC_CFG_3, 0x2f0f0476); | |
82 | } else { | |
83 | mt76_wr(dev, MT_TX_ALC_CFG_2, 0x1b0f0400); | |
84 | mt76_wr(dev, MT_TX_ALC_CFG_3, 0x1b0f0476); | |
85 | } | |
86 | ||
26a9daa6 | 87 | if (mt76x02_ext_pa_enabled(dev, band)) |
5f0d10ce LB |
88 | pa_mode_adj = 0x04000000; |
89 | else | |
90 | pa_mode_adj = 0; | |
91 | ||
92 | mt76_wr(dev, MT_RF_PA_MODE_ADJ0, pa_mode_adj); | |
93 | mt76_wr(dev, MT_RF_PA_MODE_ADJ1, pa_mode_adj); | |
94 | } | |
95 | ||
96 | mt76_wr(dev, MT_BB_PA_MODE_CFG0, pa_mode[0]); | |
97 | mt76_wr(dev, MT_BB_PA_MODE_CFG1, pa_mode[1]); | |
98 | mt76_wr(dev, MT_RF_PA_MODE_CFG0, pa_mode[0]); | |
99 | mt76_wr(dev, MT_RF_PA_MODE_CFG1, pa_mode[1]); | |
100 | ||
26a9daa6 | 101 | if (mt76x02_ext_pa_enabled(dev, band)) { |
5f0d10ce LB |
102 | u32 val; |
103 | ||
104 | if (band == NL80211_BAND_2GHZ) | |
105 | val = 0x3c3c023c; | |
106 | else | |
107 | val = 0x363c023c; | |
108 | ||
109 | mt76_wr(dev, MT_TX0_RF_GAIN_CORR, val); | |
110 | mt76_wr(dev, MT_TX1_RF_GAIN_CORR, val); | |
111 | mt76_wr(dev, MT_TX_ALC_CFG_4, 0x00001818); | |
112 | } else { | |
113 | if (band == NL80211_BAND_2GHZ) { | |
114 | u32 val = 0x0f3c3c3c; | |
115 | ||
116 | mt76_wr(dev, MT_TX0_RF_GAIN_CORR, val); | |
117 | mt76_wr(dev, MT_TX1_RF_GAIN_CORR, val); | |
118 | mt76_wr(dev, MT_TX_ALC_CFG_4, 0x00000606); | |
119 | } else { | |
120 | mt76_wr(dev, MT_TX0_RF_GAIN_CORR, 0x383c023c); | |
121 | mt76_wr(dev, MT_TX1_RF_GAIN_CORR, 0x24282e28); | |
122 | mt76_wr(dev, MT_TX_ALC_CFG_4, 0); | |
123 | } | |
124 | } | |
125 | } | |
126 | EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower_regs); | |
127 | ||
5f0d10ce LB |
128 | static int |
129 | mt76x2_get_min_rate_power(struct mt76_rate_power *r) | |
130 | { | |
131 | int i; | |
132 | s8 ret = 0; | |
133 | ||
134 | for (i = 0; i < sizeof(r->all); i++) { | |
135 | if (!r->all[i]) | |
136 | continue; | |
137 | ||
138 | if (ret) | |
139 | ret = min(ret, r->all[i]); | |
140 | else | |
141 | ret = r->all[i]; | |
142 | } | |
143 | ||
144 | return ret; | |
145 | } | |
146 | ||
e40803f2 | 147 | void mt76x2_phy_set_txpower(struct mt76x02_dev *dev) |
5f0d10ce LB |
148 | { |
149 | enum nl80211_chan_width width = dev->mt76.chandef.width; | |
150 | struct ieee80211_channel *chan = dev->mt76.chandef.chan; | |
151 | struct mt76x2_tx_power_info txp; | |
152 | int txp_0, txp_1, delta = 0; | |
153 | struct mt76_rate_power t = {}; | |
154 | int base_power, gain; | |
155 | ||
156 | mt76x2_get_power_info(dev, &txp, chan); | |
157 | ||
158 | if (width == NL80211_CHAN_WIDTH_40) | |
159 | delta = txp.delta_bw40; | |
160 | else if (width == NL80211_CHAN_WIDTH_80) | |
161 | delta = txp.delta_bw80; | |
162 | ||
163 | mt76x2_get_rate_power(dev, &t, chan); | |
b9f192b8 LB |
164 | mt76x02_add_rate_power_offset(&t, txp.chain[0].target_power); |
165 | mt76x02_limit_rate_power(&t, dev->mt76.txpower_conf); | |
166 | dev->mt76.txpower_cur = mt76x02_get_max_rate_power(&t); | |
5f0d10ce LB |
167 | |
168 | base_power = mt76x2_get_min_rate_power(&t); | |
169 | delta += base_power - txp.chain[0].target_power; | |
170 | txp_0 = txp.chain[0].target_power + txp.chain[0].delta + delta; | |
171 | txp_1 = txp.chain[1].target_power + txp.chain[1].delta + delta; | |
172 | ||
173 | gain = min(txp_0, txp_1); | |
174 | if (gain < 0) { | |
175 | base_power -= gain; | |
176 | txp_0 -= gain; | |
177 | txp_1 -= gain; | |
178 | } else if (gain > 0x2f) { | |
179 | base_power -= gain - 0x2f; | |
180 | txp_0 = 0x2f; | |
181 | txp_1 = 0x2f; | |
182 | } | |
183 | ||
b9f192b8 | 184 | mt76x02_add_rate_power_offset(&t, -base_power); |
5f0d10ce LB |
185 | dev->target_power = txp.chain[0].target_power; |
186 | dev->target_power_delta[0] = txp_0 - txp.chain[0].target_power; | |
187 | dev->target_power_delta[1] = txp_1 - txp.chain[0].target_power; | |
b6862eff | 188 | dev->mt76.rate_power = t; |
5f0d10ce | 189 | |
bfdff5d0 | 190 | mt76x02_phy_set_txpower(dev, txp_0, txp_1); |
5f0d10ce LB |
191 | } |
192 | EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower); | |
193 | ||
e40803f2 | 194 | void mt76x2_configure_tx_delay(struct mt76x02_dev *dev, |
5f0d10ce LB |
195 | enum nl80211_band band, u8 bw) |
196 | { | |
197 | u32 cfg0, cfg1; | |
198 | ||
26a9daa6 | 199 | if (mt76x02_ext_pa_enabled(dev, band)) { |
5f0d10ce LB |
200 | cfg0 = bw ? 0x000b0c01 : 0x00101101; |
201 | cfg1 = 0x00011414; | |
202 | } else { | |
203 | cfg0 = bw ? 0x000b0b01 : 0x00101001; | |
204 | cfg1 = 0x00021414; | |
205 | } | |
206 | mt76_wr(dev, MT_TX_SW_CFG0, cfg0); | |
207 | mt76_wr(dev, MT_TX_SW_CFG1, cfg1); | |
208 | ||
209 | mt76_rmw_field(dev, MT_XIFS_TIME_CFG, MT_XIFS_TIME_CFG_OFDM_SIFS, 15); | |
210 | } | |
211 | EXPORT_SYMBOL_GPL(mt76x2_configure_tx_delay); | |
212 | ||
4ece1e0a | 213 | void mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev) |
8842d485 LB |
214 | { |
215 | struct ieee80211_channel *chan = dev->mt76.chandef.chan; | |
216 | struct mt76x2_tx_power_info txp; | |
217 | struct mt76x2_tssi_comp t = {}; | |
218 | ||
219 | if (!dev->cal.tssi_cal_done) | |
220 | return; | |
221 | ||
222 | if (!dev->cal.tssi_comp_pending) { | |
223 | /* TSSI trigger */ | |
224 | t.cal_mode = BIT(0); | |
225 | mt76x2_mcu_tssi_comp(dev, &t); | |
226 | dev->cal.tssi_comp_pending = true; | |
227 | } else { | |
228 | if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4)) | |
229 | return; | |
230 | ||
231 | dev->cal.tssi_comp_pending = false; | |
232 | mt76x2_get_power_info(dev, &txp, chan); | |
233 | ||
26a9daa6 | 234 | if (mt76x02_ext_pa_enabled(dev, chan->band)) |
8842d485 LB |
235 | t.pa_mode = 1; |
236 | ||
237 | t.cal_mode = BIT(1); | |
238 | t.slope0 = txp.chain[0].tssi_slope; | |
239 | t.offset0 = txp.chain[0].tssi_offset; | |
240 | t.slope1 = txp.chain[1].tssi_slope; | |
241 | t.offset1 = txp.chain[1].tssi_offset; | |
242 | mt76x2_mcu_tssi_comp(dev, &t); | |
243 | ||
1564fa92 | 244 | if (t.pa_mode || dev->cal.dpd_cal_done || dev->ed_tx_blocked) |
8842d485 LB |
245 | return; |
246 | ||
247 | usleep_range(10000, 20000); | |
4ece1e0a | 248 | mt76x02_mcu_calibrate(dev, MCU_CAL_DPD, chan->hw_value); |
8842d485 LB |
249 | dev->cal.dpd_cal_done = true; |
250 | } | |
251 | } | |
252 | EXPORT_SYMBOL_GPL(mt76x2_phy_tssi_compensate); | |
989582e5 | 253 | |
989582e5 LB |
254 | static void |
255 | mt76x2_phy_set_gain_val(struct mt76x02_dev *dev) | |
256 | { | |
257 | u32 val; | |
258 | u8 gain_val[2]; | |
259 | ||
260 | gain_val[0] = dev->cal.agc_gain_cur[0] - dev->cal.agc_gain_adjust; | |
261 | gain_val[1] = dev->cal.agc_gain_cur[1] - dev->cal.agc_gain_adjust; | |
262 | ||
45a042e3 FF |
263 | val = 0x1836 << 16; |
264 | if (!mt76x2_has_ext_lna(dev) && | |
265 | dev->mt76.chandef.width >= NL80211_CHAN_WIDTH_40) | |
989582e5 | 266 | val = 0x1e42 << 16; |
45a042e3 FF |
267 | |
268 | if (mt76x2_has_ext_lna(dev) && | |
269 | dev->mt76.chandef.chan->band == NL80211_BAND_2GHZ && | |
270 | dev->mt76.chandef.width < NL80211_CHAN_WIDTH_40) | |
271 | val = 0x0f36 << 16; | |
989582e5 LB |
272 | |
273 | val |= 0xf8; | |
274 | ||
275 | mt76_wr(dev, MT_BBP(AGC, 8), | |
276 | val | FIELD_PREP(MT_BBP_AGC_GAIN, gain_val[0])); | |
277 | mt76_wr(dev, MT_BBP(AGC, 9), | |
278 | val | FIELD_PREP(MT_BBP_AGC_GAIN, gain_val[1])); | |
279 | ||
280 | if (dev->mt76.chandef.chan->flags & IEEE80211_CHAN_RADAR) | |
801ccc8a | 281 | mt76x02_phy_dfs_adjust_agc(dev); |
989582e5 LB |
282 | } |
283 | ||
284 | void mt76x2_phy_update_channel_gain(struct mt76x02_dev *dev) | |
285 | { | |
286 | u8 *gain = dev->cal.agc_gain_init; | |
287 | u8 low_gain_delta, gain_delta; | |
b8cfd87a | 288 | u32 agc_35, agc_37; |
989582e5 LB |
289 | bool gain_change; |
290 | int low_gain; | |
291 | u32 val; | |
292 | ||
ef13edc0 FF |
293 | dev->cal.avg_rssi_all = mt76_get_min_avg_rssi(&dev->mt76); |
294 | if (!dev->cal.avg_rssi_all) | |
295 | dev->cal.avg_rssi_all = -75; | |
989582e5 LB |
296 | |
297 | low_gain = (dev->cal.avg_rssi_all > mt76x02_get_rssi_gain_thresh(dev)) + | |
298 | (dev->cal.avg_rssi_all > mt76x02_get_low_rssi_gain_thresh(dev)); | |
299 | ||
4784a3cc SG |
300 | gain_change = dev->cal.low_gain < 0 || |
301 | (dev->cal.low_gain & 2) ^ (low_gain & 2); | |
989582e5 LB |
302 | dev->cal.low_gain = low_gain; |
303 | ||
304 | if (!gain_change) { | |
305 | if (mt76x02_phy_adjust_vga_gain(dev)) | |
306 | mt76x2_phy_set_gain_val(dev); | |
307 | return; | |
308 | } | |
309 | ||
310 | if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80) { | |
311 | mt76_wr(dev, MT_BBP(RXO, 14), 0x00560211); | |
312 | val = mt76_rr(dev, MT_BBP(AGC, 26)) & ~0xf; | |
313 | if (low_gain == 2) | |
314 | val |= 0x3; | |
315 | else | |
316 | val |= 0x5; | |
317 | mt76_wr(dev, MT_BBP(AGC, 26), val); | |
318 | } else { | |
319 | mt76_wr(dev, MT_BBP(RXO, 14), 0x00560423); | |
320 | } | |
321 | ||
322 | if (mt76x2_has_ext_lna(dev)) | |
323 | low_gain_delta = 10; | |
324 | else | |
325 | low_gain_delta = 14; | |
326 | ||
b8cfd87a FF |
327 | agc_37 = 0x2121262c; |
328 | if (dev->mt76.chandef.chan->band == NL80211_BAND_2GHZ) | |
329 | agc_35 = 0x11111516; | |
330 | else if (low_gain == 2) | |
331 | agc_35 = agc_37 = 0x08080808; | |
332 | else if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80) | |
333 | agc_35 = 0x10101014; | |
334 | else | |
335 | agc_35 = 0x11111116; | |
336 | ||
989582e5 LB |
337 | if (low_gain == 2) { |
338 | mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a990); | |
339 | mt76_wr(dev, MT_BBP(AGC, 35), 0x08080808); | |
340 | mt76_wr(dev, MT_BBP(AGC, 37), 0x08080808); | |
341 | gain_delta = low_gain_delta; | |
342 | dev->cal.agc_gain_adjust = 0; | |
343 | } else { | |
344 | mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a991); | |
989582e5 LB |
345 | gain_delta = 0; |
346 | dev->cal.agc_gain_adjust = low_gain_delta; | |
347 | } | |
348 | ||
b8cfd87a FF |
349 | mt76_wr(dev, MT_BBP(AGC, 35), agc_35); |
350 | mt76_wr(dev, MT_BBP(AGC, 37), agc_37); | |
351 | ||
989582e5 LB |
352 | dev->cal.agc_gain_cur[0] = gain[0] - gain_delta; |
353 | dev->cal.agc_gain_cur[1] = gain[1] - gain_delta; | |
354 | mt76x2_phy_set_gain_val(dev); | |
355 | ||
356 | /* clear false CCA counters */ | |
357 | mt76_rr(dev, MT_RX_STAT_1); | |
358 | } | |
359 | EXPORT_SYMBOL_GPL(mt76x2_phy_update_channel_gain); |