]>
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 | ||
443569a5 | 68 | if (mt76x02_ext_pa_enabled(&dev->mt76, 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 | ||
443569a5 | 79 | if (mt76x02_ext_pa_enabled(&dev->mt76, 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 | ||
443569a5 | 87 | if (mt76x02_ext_pa_enabled(&dev->mt76, 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 | ||
443569a5 | 101 | if (mt76x02_ext_pa_enabled(&dev->mt76, 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 | ||
443569a5 | 199 | if (mt76x02_ext_pa_enabled(&dev->mt76, 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 | ||
e40803f2 | 213 | void mt76x2_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl) |
5f0d10ce LB |
214 | { |
215 | int core_val, agc_val; | |
216 | ||
217 | switch (width) { | |
218 | case NL80211_CHAN_WIDTH_80: | |
219 | core_val = 3; | |
220 | agc_val = 7; | |
221 | break; | |
222 | case NL80211_CHAN_WIDTH_40: | |
223 | core_val = 2; | |
224 | agc_val = 3; | |
225 | break; | |
226 | default: | |
227 | core_val = 0; | |
228 | agc_val = 1; | |
229 | break; | |
230 | } | |
231 | ||
232 | mt76_rmw_field(dev, MT_BBP(CORE, 1), MT_BBP_CORE_R1_BW, core_val); | |
233 | mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_BW, agc_val); | |
234 | mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_CTRL_CHAN, ctrl); | |
235 | mt76_rmw_field(dev, MT_BBP(TXBE, 0), MT_BBP_TXBE_R0_CTRL_CHAN, ctrl); | |
236 | } | |
237 | EXPORT_SYMBOL_GPL(mt76x2_phy_set_bw); | |
238 | ||
e40803f2 | 239 | void mt76x2_phy_set_band(struct mt76x02_dev *dev, int band, bool primary_upper) |
5f0d10ce LB |
240 | { |
241 | switch (band) { | |
242 | case NL80211_BAND_2GHZ: | |
243 | mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G); | |
244 | mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G); | |
245 | break; | |
246 | case NL80211_BAND_5GHZ: | |
247 | mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G); | |
248 | mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G); | |
249 | break; | |
250 | } | |
251 | ||
252 | mt76_rmw_field(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_UPPER_40M, | |
253 | primary_upper); | |
254 | } | |
255 | EXPORT_SYMBOL_GPL(mt76x2_phy_set_band); | |
256 | ||
e40803f2 | 257 | void mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev, bool wait) |
8842d485 LB |
258 | { |
259 | struct ieee80211_channel *chan = dev->mt76.chandef.chan; | |
260 | struct mt76x2_tx_power_info txp; | |
261 | struct mt76x2_tssi_comp t = {}; | |
262 | ||
263 | if (!dev->cal.tssi_cal_done) | |
264 | return; | |
265 | ||
266 | if (!dev->cal.tssi_comp_pending) { | |
267 | /* TSSI trigger */ | |
268 | t.cal_mode = BIT(0); | |
269 | mt76x2_mcu_tssi_comp(dev, &t); | |
270 | dev->cal.tssi_comp_pending = true; | |
271 | } else { | |
272 | if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4)) | |
273 | return; | |
274 | ||
275 | dev->cal.tssi_comp_pending = false; | |
276 | mt76x2_get_power_info(dev, &txp, chan); | |
277 | ||
443569a5 | 278 | if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band)) |
8842d485 LB |
279 | t.pa_mode = 1; |
280 | ||
281 | t.cal_mode = BIT(1); | |
282 | t.slope0 = txp.chain[0].tssi_slope; | |
283 | t.offset0 = txp.chain[0].tssi_offset; | |
284 | t.slope1 = txp.chain[1].tssi_slope; | |
285 | t.offset1 = txp.chain[1].tssi_offset; | |
286 | mt76x2_mcu_tssi_comp(dev, &t); | |
287 | ||
288 | if (t.pa_mode || dev->cal.dpd_cal_done) | |
289 | return; | |
290 | ||
291 | usleep_range(10000, 20000); | |
499cd0aa | 292 | mt76x02_mcu_calibrate(dev, MCU_CAL_DPD, chan->hw_value, wait); |
8842d485 LB |
293 | dev->cal.dpd_cal_done = true; |
294 | } | |
295 | } | |
296 | EXPORT_SYMBOL_GPL(mt76x2_phy_tssi_compensate); |