GNU Linux-libre 4.14.266-gnu1
[releases.git] / drivers / staging / rtlwifi / phydm / phydm_psd.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2016  Realtek Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * The full GNU General Public License is included in this distribution in the
15  * file called LICENSE.
16  *
17  * Contact Information:
18  * wlanfae <wlanfae@realtek.com>
19  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20  * Hsinchu 300, Taiwan.
21  *
22  * Larry Finger <Larry.Finger@lwfinger.net>
23  *
24  *****************************************************************************/
25
26 /*============================================================
27  * include files
28  *============================================================
29  */
30 #include "mp_precomp.h"
31 #include "phydm_precomp.h"
32
33 u32 phydm_get_psd_data(void *dm_void, u32 psd_tone_idx, u32 igi)
34 {
35         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
36         struct psd_info *dm_psd_table = &dm->dm_psd_table;
37         u32 psd_report = 0;
38
39         odm_set_bb_reg(dm, dm_psd_table->psd_reg, 0x3ff, psd_tone_idx);
40
41         odm_set_bb_reg(dm, dm_psd_table->psd_reg, BIT(22),
42                        1); /*PSD trigger start*/
43         ODM_delay_us(10);
44         odm_set_bb_reg(dm, dm_psd_table->psd_reg, BIT(22),
45                        0); /*PSD trigger stop*/
46
47         psd_report = odm_get_bb_reg(dm, dm_psd_table->psd_report_reg, 0xffff);
48         psd_report = odm_convert_to_db(psd_report) + igi;
49
50         return psd_report;
51 }
52
53 static u8 phydm_psd_stop_trx(void *dm_void)
54 {
55         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
56         u32 i;
57         u8 trx_idle_success = false;
58         u32 dbg_port_value = 0;
59
60         /*[Stop TRX]----------------------------------------------------------*/
61         if (!phydm_set_bb_dbg_port(dm, BB_DBGPORT_PRIORITY_3,
62                                    0x0)) /*set debug port to 0x0*/
63                 return STOP_TRX_FAIL;
64
65         for (i = 0; i < 10000; i++) {
66                 dbg_port_value = phydm_get_bb_dbg_port_value(dm);
67                 if ((dbg_port_value & (BIT(17) | BIT(3))) ==
68                     0) /* PHYTXON && CCA_all */ {
69                         ODM_RT_TRACE(dm, ODM_COMP_API,
70                                      "PSD wait for ((%d)) times\n", i);
71
72                         trx_idle_success = true;
73                         break;
74                 }
75         }
76
77         if (trx_idle_success) {
78                 /*pause all TX queue*/
79                 odm_set_bb_reg(dm, 0x520, 0xff0000, 0xff);
80
81                 if (dm->support_ic_type & ODM_IC_11AC_SERIES) {
82                         /*disable CCK block*/
83                         odm_set_bb_reg(dm, 0x808, BIT(28), 0);
84                         /*disable OFDM RX CCA*/
85                         odm_set_bb_reg(dm, 0x838, BIT(1), 1);
86                 } else {
87                         /*TBD*/
88                         /* disable whole CCK block */
89                         odm_set_bb_reg(dm, 0x800, BIT(24), 0);
90                         /*[ Set IQK Matrix = 0 ] equivalent to [ Turn off CCA]*/
91                         odm_set_bb_reg(dm, 0xC14, MASKDWORD, 0x0);
92                 }
93
94         } else {
95                 return STOP_TRX_FAIL;
96         }
97
98         phydm_release_bb_dbg_port(dm);
99
100         return STOP_TRX_SUCCESS;
101 }
102
103 static u8 psd_result_cali_tone_8821[7] = {21, 28, 33, 93, 98, 105, 127};
104 static u8 psd_result_cali_val_8821[7] = {67, 69, 71, 72, 71, 69, 67};
105
106 void phydm_psd(void *dm_void, u32 igi, u16 start_point, u16 stop_point)
107 {
108         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
109         struct psd_info *dm_psd_table = &dm->dm_psd_table;
110         u32 i = 0, mod_tone_idx;
111         u32 t = 0;
112         u16 fft_max_half_bw;
113         u32 psd_igi_a_reg;
114         u32 psd_igi_b_reg;
115         u16 psd_fc_channel = dm_psd_table->psd_fc_channel;
116         u8 ag_rf_mode_reg = 0;
117         u8 rf_reg18_9_8 = 0;
118         u32 psd_result_tmp = 0;
119         u8 psd_result = 0;
120         u8 psd_result_cali_tone[7] = {0};
121         u8 psd_result_cali_val[7] = {0};
122         u8 noise_table_idx = 0;
123
124         if (dm->support_ic_type == ODM_RTL8821) {
125                 odm_move_memory(dm, psd_result_cali_tone,
126                                 psd_result_cali_tone_8821, 7);
127                 odm_move_memory(dm, psd_result_cali_val,
128                                 psd_result_cali_val_8821, 7);
129         }
130
131         dm_psd_table->psd_in_progress = 1;
132
133         /*[Stop DIG]*/
134         dm->support_ability &= ~(ODM_BB_DIG);
135         dm->support_ability &= ~(ODM_BB_FA_CNT);
136
137         ODM_RT_TRACE(dm, ODM_COMP_API, "PSD Start =>\n");
138
139         if (dm->support_ic_type & ODM_IC_11AC_SERIES) {
140                 psd_igi_a_reg = 0xc50;
141                 psd_igi_b_reg = 0xe50;
142         } else {
143                 psd_igi_a_reg = 0xc50;
144                 psd_igi_b_reg = 0xc58;
145         }
146
147         /*[back up IGI]*/
148         dm_psd_table->initial_gain_backup =
149                 odm_get_bb_reg(dm, psd_igi_a_reg, 0xff);
150         odm_set_bb_reg(dm, psd_igi_a_reg, 0xff,
151                        0x6e); /*IGI target at 0dBm & make it can't CCA*/
152         odm_set_bb_reg(dm, psd_igi_b_reg, 0xff,
153                        0x6e); /*IGI target at 0dBm & make it can't CCA*/
154         ODM_delay_us(10);
155
156         if (phydm_psd_stop_trx(dm) == STOP_TRX_FAIL) {
157                 ODM_RT_TRACE(dm, ODM_COMP_API, "STOP_TRX_FAIL\n");
158                 return;
159         }
160
161         /*[Set IGI]*/
162         odm_set_bb_reg(dm, psd_igi_a_reg, 0xff, igi);
163         odm_set_bb_reg(dm, psd_igi_b_reg, 0xff, igi);
164
165         /*[Backup RF Reg]*/
166         dm_psd_table->rf_0x18_bkp =
167                 odm_get_rf_reg(dm, ODM_RF_PATH_A, 0x18, RFREGOFFSETMASK);
168
169         if (psd_fc_channel > 14) {
170                 rf_reg18_9_8 = 1;
171
172                 if (psd_fc_channel >= 36 && psd_fc_channel <= 64)
173                         ag_rf_mode_reg = 0x1;
174                 else if (psd_fc_channel >= 100 && psd_fc_channel <= 140)
175                         ag_rf_mode_reg = 0x3;
176                 else if (psd_fc_channel > 140)
177                         ag_rf_mode_reg = 0x5;
178         }
179
180         /* Set RF fc*/
181         odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x18, 0xff, psd_fc_channel);
182         odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x18, 0x300, rf_reg18_9_8);
183         /*2b'11: 20MHz, 2b'10: 40MHz, 2b'01: 80MHz */
184         odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x18, 0xc00,
185                        dm_psd_table->psd_bw_rf_reg);
186         /* Set RF ag fc mode*/
187         odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x18, 0xf0000, ag_rf_mode_reg);
188
189         ODM_RT_TRACE(dm, ODM_COMP_API, "0xc50=((0x%x))\n",
190                      odm_get_bb_reg(dm, 0xc50, MASKDWORD));
191         ODM_RT_TRACE(dm, ODM_COMP_API, "RF0x18=((0x%x))\n",
192                      odm_get_rf_reg(dm, ODM_RF_PATH_A, 0x18, RFREGOFFSETMASK));
193
194         /*[Stop 3-wires]*/
195         if (dm->support_ic_type & ODM_IC_11AC_SERIES) {
196                 odm_set_bb_reg(dm, 0xc00, 0xf, 0x4); /* hardware 3-wire off */
197                 odm_set_bb_reg(dm, 0xe00, 0xf, 0x4); /* hardware 3-wire off */
198         } else {
199                 odm_set_bb_reg(dm, 0x88c, 0xf00000,
200                                0xf); /* 3 wire Disable    88c[23:20]=0xf */
201         }
202         ODM_delay_us(10);
203
204         if (stop_point > (dm_psd_table->fft_smp_point - 1))
205                 stop_point = (dm_psd_table->fft_smp_point - 1);
206
207         if (start_point > (dm_psd_table->fft_smp_point - 1))
208                 start_point = (dm_psd_table->fft_smp_point - 1);
209
210         if (start_point > stop_point)
211                 stop_point = start_point;
212
213         if (stop_point > 127) /* limit of psd_result[128] */
214                 stop_point = 127;
215
216         for (i = start_point; i <= stop_point; i++) {
217                 fft_max_half_bw = (dm_psd_table->fft_smp_point) >> 1;
218
219                 if (i < fft_max_half_bw)
220                         mod_tone_idx = i + fft_max_half_bw;
221                 else
222                         mod_tone_idx = i - fft_max_half_bw;
223
224                 psd_result_tmp = 0;
225                 for (t = 0; t < dm_psd_table->sw_avg_time; t++)
226                         psd_result_tmp +=
227                                 phydm_get_psd_data(dm, mod_tone_idx, igi);
228                 psd_result =
229                         (u8)((psd_result_tmp / dm_psd_table->sw_avg_time)) -
230                         dm_psd_table->psd_pwr_common_offset;
231
232                 if (dm_psd_table->fft_smp_point == 128 &&
233                     (dm_psd_table->noise_k_en)) {
234                         if (i > psd_result_cali_tone[noise_table_idx])
235                                 noise_table_idx++;
236
237                         if (noise_table_idx > 6)
238                                 noise_table_idx = 6;
239
240                         if (psd_result >= psd_result_cali_val[noise_table_idx])
241                                 psd_result =
242                                         psd_result -
243                                         psd_result_cali_val[noise_table_idx];
244                         else
245                                 psd_result = 0;
246
247                         dm_psd_table->psd_result[i] = psd_result;
248                 }
249
250                 ODM_RT_TRACE(dm, ODM_COMP_API, "[%d] N_cali = %d, PSD = %d\n",
251                              mod_tone_idx, psd_result_cali_val[noise_table_idx],
252                              psd_result);
253         }
254
255         /*[Start 3-wires]*/
256         if (dm->support_ic_type & ODM_IC_11AC_SERIES) {
257                 odm_set_bb_reg(dm, 0xc00, 0xf, 0x7); /* hardware 3-wire on */
258                 odm_set_bb_reg(dm, 0xe00, 0xf, 0x7); /* hardware 3-wire on */
259         } else {
260                 odm_set_bb_reg(dm, 0x88c, 0xf00000,
261                                0x0); /* 3 wire enable    88c[23:20]=0x0 */
262         }
263         ODM_delay_us(10);
264
265         /*[Revert Reg]*/
266         odm_set_bb_reg(dm, 0x520, 0xff0000, 0x0); /*start all TX queue*/
267         odm_set_bb_reg(dm, 0x808, BIT(28), 1); /*enable CCK block*/
268         odm_set_bb_reg(dm, 0x838, BIT(1), 0); /*enable OFDM RX CCA*/
269
270         odm_set_bb_reg(dm, psd_igi_a_reg, 0xff,
271                        dm_psd_table->initial_gain_backup);
272         odm_set_bb_reg(dm, psd_igi_b_reg, 0xff,
273                        dm_psd_table->initial_gain_backup);
274
275         odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x18, RFREGOFFSETMASK,
276                        dm_psd_table->rf_0x18_bkp);
277
278         ODM_RT_TRACE(dm, ODM_COMP_API, "PSD finished\n\n");
279
280         dm->support_ability |= ODM_BB_DIG;
281         dm->support_ability |= ODM_BB_FA_CNT;
282         dm_psd_table->psd_in_progress = 0;
283 }
284
285 void phydm_psd_para_setting(void *dm_void, u8 sw_avg_time, u8 hw_avg_time,
286                             u8 i_q_setting, u16 fft_smp_point, u8 ant_sel,
287                             u8 psd_input, u8 channel, u8 noise_k_en)
288 {
289         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
290         struct psd_info *dm_psd_table = &dm->dm_psd_table;
291         u8 fft_smp_point_idx = 0;
292
293         dm_psd_table->fft_smp_point = fft_smp_point;
294
295         if (sw_avg_time == 0)
296                 sw_avg_time = 1;
297
298         dm_psd_table->sw_avg_time = sw_avg_time;
299         dm_psd_table->psd_fc_channel = channel;
300         dm_psd_table->noise_k_en = noise_k_en;
301
302         if (fft_smp_point == 128)
303                 fft_smp_point_idx = 0;
304         else if (fft_smp_point == 256)
305                 fft_smp_point_idx = 1;
306         else if (fft_smp_point == 512)
307                 fft_smp_point_idx = 2;
308         else if (fft_smp_point == 1024)
309                 fft_smp_point_idx = 3;
310
311         if (dm->support_ic_type & ODM_IC_11AC_SERIES) {
312                 odm_set_bb_reg(dm, 0x910, BIT(11) | BIT(10), i_q_setting);
313                 odm_set_bb_reg(dm, 0x910, BIT(13) | BIT(12), hw_avg_time);
314                 odm_set_bb_reg(dm, 0x910, BIT(15) | BIT(14), fft_smp_point_idx);
315                 odm_set_bb_reg(dm, 0x910, BIT(17) | BIT(16), ant_sel);
316                 odm_set_bb_reg(dm, 0x910, BIT(23), psd_input);
317         }
318
319         /*bw = (*dm->band_width); //ODM_BW20M */
320         /*channel = *(dm->channel);*/
321 }
322
323 void phydm_psd_init(void *dm_void)
324 {
325         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
326         struct psd_info *dm_psd_table = &dm->dm_psd_table;
327
328         ODM_RT_TRACE(dm, ODM_COMP_API, "PSD para init\n");
329
330         dm_psd_table->psd_in_progress = false;
331
332         if (dm->support_ic_type & ODM_IC_11AC_SERIES) {
333                 dm_psd_table->psd_reg = 0x910;
334                 dm_psd_table->psd_report_reg = 0xF44;
335
336                 if (ODM_IC_11AC_2_SERIES)
337                         dm_psd_table->psd_bw_rf_reg =
338                                 1; /*2b'11: 20MHz, 2b'10: 40MHz, 2b'01: 80MHz */
339                 else
340                         dm_psd_table->psd_bw_rf_reg =
341                                 2; /*2b'11: 20MHz, 2b'10: 40MHz, 2b'01: 80MHz */
342
343         } else {
344                 dm_psd_table->psd_reg = 0x808;
345                 dm_psd_table->psd_report_reg = 0x8B4;
346                 dm_psd_table->psd_bw_rf_reg =
347                         2; /*2b'11: 20MHz, 2b'10: 40MHz, 2b'01: 80MHz */
348         }
349
350         if (dm->support_ic_type == ODM_RTL8812)
351                 dm_psd_table->psd_pwr_common_offset = 0;
352         else if (dm->support_ic_type == ODM_RTL8821)
353                 dm_psd_table->psd_pwr_common_offset = 0;
354         else
355                 dm_psd_table->psd_pwr_common_offset = 0;
356
357         phydm_psd_para_setting(dm, 1, 2, 3, 128, 0, 0, 7, 0);
358         /*phydm_psd(dm, 0x3c, 0, 127);*/ /* target at -50dBm */
359 }
360
361 void phydm_psd_debug(void *dm_void, char input[][16], u32 *_used, char *output,
362                      u32 *_out_len, u32 input_num)
363 {
364         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
365         char help[] = "-h";
366         u32 var1[10] = {0};
367         u32 used = *_used;
368         u32 out_len = *_out_len;
369         u8 i;
370
371         if ((strcmp(input[1], help) == 0)) {
372                 PHYDM_SNPRINTF(
373                         output + used, out_len - used,
374                         "{0} {sw_avg} {hw_avg 0:3} {1:I,2:Q,3:IQ} {fft_point: 128*(1:4)} {path_sel 0~3} {0:ADC, 1:RXIQC} {CH} {noise_k}\n");
375                 PHYDM_SNPRINTF(output + used, out_len - used,
376                                "{1} {IGI(hex)} {start_point} {stop_point}\n");
377                 return;
378         }
379
380         PHYDM_SSCANF(input[1], DCMD_DECIMAL, &var1[0]);
381
382         if (var1[0] == 0) {
383                 for (i = 1; i < 10; i++) {
384                         if (input[i + 1])
385                                 PHYDM_SSCANF(input[i + 1], DCMD_DECIMAL,
386                                              &var1[i]);
387                 }
388
389                 PHYDM_SNPRINTF(
390                         output + used, out_len - used,
391                         "sw_avg_time=((%d)), hw_avg_time=((%d)), IQ=((%d)), fft=((%d)), path=((%d)), input =((%d)) ch=((%d)), noise_k=((%d))\n",
392                         var1[1], var1[2], var1[3], var1[4], var1[5], var1[6],
393                         (u8)var1[7], (u8)var1[8]);
394                 phydm_psd_para_setting(dm, (u8)var1[1], (u8)var1[2],
395                                        (u8)var1[3], (u16)var1[4], (u8)var1[5],
396                                        (u8)var1[6], (u8)var1[7], (u8)var1[8]);
397
398         } else if (var1[0] == 1) {
399                 PHYDM_SSCANF(input[2], DCMD_HEX, &var1[1]);
400                 PHYDM_SSCANF(input[3], DCMD_DECIMAL, &var1[2]);
401                 PHYDM_SSCANF(input[4], DCMD_DECIMAL, &var1[3]);
402                 PHYDM_SNPRINTF(
403                         output + used, out_len - used,
404                         "IGI=((0x%x)), start_point=((%d)), stop_point=((%d))\n",
405                         var1[1], var1[2], var1[3]);
406                 dm->debug_components |= ODM_COMP_API;
407                 phydm_psd(dm, var1[1], (u16)var1[2], (u16)var1[3]);
408                 dm->debug_components &= (~ODM_COMP_API);
409         }
410 }
411
412 u8 phydm_get_psd_result_table(void *dm_void, int index)
413 {
414         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
415         struct psd_info *dm_psd_table = &dm->dm_psd_table;
416         u8 temp_result = 0;
417
418         if (index < 128)
419                 temp_result = dm_psd_table->psd_result[index];
420
421         return temp_result;
422 }