phydm_noisemonitor.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /******************************************************************************
  2. *
  3. * Copyright(c) 2007 - 2017 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. * include files
  27. ************************************************************/
  28. #include "mp_precomp.h"
  29. #include "phydm_precomp.h"
  30. /**************************************************
  31. * This function is for inband noise test utility only
  32. * To obtain the inband noise level(dbm), do the following.
  33. * 1. disable DIG and Power Saving
  34. * 2. Set initial gain = 0x1a
  35. * 3. Stop updating idle time pwer report (for driver read)
  36. * - 0x80c[25]
  37. *
  38. *************************************************/
  39. void phydm_set_noise_data_sum(struct noise_level *noise_data, u8 max_rf_path)
  40. {
  41. u8 i = 0;
  42. for (i = RF_PATH_A; i < max_rf_path; i++) {
  43. if (noise_data->valid_cnt[i])
  44. noise_data->sum[i] /= noise_data->valid_cnt[i];
  45. else
  46. noise_data->sum[i] = 0;
  47. }
  48. }
  49. #if (ODM_IC_11N_SERIES_SUPPORT)
  50. s16 odm_inband_noise_monitor_n(struct dm_struct *dm, u8 is_pause_dig, u8 igi,
  51. u32 max_time)
  52. {
  53. u32 tmp4b;
  54. u8 max_rf_path = 0, i = 0;
  55. u8 reg_c50, reg_c58, valid_done = 0;
  56. struct noise_level noise_data;
  57. u64 start = 0, func_start = 0, func_end = 0;
  58. s8 val_s8 = 0;
  59. func_start = odm_get_current_time(dm);
  60. dm->noise_level.noise_all = 0;
  61. if (dm->rf_type == RF_1T2R || dm->rf_type == RF_2T2R)
  62. max_rf_path = 2;
  63. else
  64. max_rf_path = 1;
  65. PHYDM_DBG(dm, DBG_ENV_MNTR,
  66. "odm_DebugControlInbandNoise_Nseries() ==>\n");
  67. odm_memory_set(dm, &noise_data, 0, sizeof(struct noise_level));
  68. /* step 1. Disable DIG && Set initial gain. */
  69. if (is_pause_dig)
  70. odm_pause_dig(dm, PHYDM_PAUSE, PHYDM_PAUSE_LEVEL_1, igi);
  71. /* step 3. Get noise power level */
  72. start = odm_get_current_time(dm);
  73. while (1) {
  74. /* Stop updating idle time pwer report (for driver read) */
  75. odm_set_bb_reg(dm, REG_FPGA0_TX_GAIN_STAGE, BIT(25), 1);
  76. /* Read Noise Floor Report */
  77. tmp4b = odm_get_bb_reg(dm, R_0x8f8, MASKDWORD);
  78. /* update idle time pwer report per 5us */
  79. odm_set_bb_reg(dm, REG_FPGA0_TX_GAIN_STAGE, BIT(25), 0);
  80. ODM_delay_us(5);
  81. noise_data.value[RF_PATH_A] = (u8)(tmp4b & 0xff);
  82. noise_data.value[RF_PATH_B] = (u8)((tmp4b & 0xff00) >> 8);
  83. for (i = RF_PATH_A; i < max_rf_path; i++) {
  84. noise_data.sval[i] = (s8)noise_data.value[i];
  85. noise_data.sval[i] /= 2;
  86. }
  87. for (i = RF_PATH_A; i < max_rf_path; i++) {
  88. if (noise_data.valid_cnt[i] >= VALID_CNT)
  89. continue;
  90. noise_data.valid_cnt[i]++;
  91. noise_data.sum[i] += noise_data.sval[i];
  92. PHYDM_DBG(dm, DBG_ENV_MNTR,
  93. "rf_path:%d Valid sval=%d\n", i,
  94. noise_data.sval[i]);
  95. PHYDM_DBG(dm, DBG_ENV_MNTR, "Sum of sval = %d,\n",
  96. noise_data.sum[i]);
  97. if (noise_data.valid_cnt[i] == VALID_CNT)
  98. valid_done++;
  99. }
  100. if (valid_done == max_rf_path ||
  101. (odm_get_progressing_time(dm, start) > max_time)) {
  102. phydm_set_noise_data_sum(&noise_data, max_rf_path);
  103. break;
  104. }
  105. }
  106. reg_c50 = (u8)odm_get_bb_reg(dm, REG_OFDM_0_XA_AGC_CORE1, MASKBYTE0);
  107. reg_c50 &= ~BIT(7);
  108. val_s8 = (s8)(-110 + reg_c50 + noise_data.sum[RF_PATH_A]);
  109. dm->noise_level.noise[RF_PATH_A] = val_s8;
  110. dm->noise_level.noise_all += dm->noise_level.noise[RF_PATH_A];
  111. if (max_rf_path == 2) {
  112. reg_c58 = (u8)odm_get_bb_reg(dm, R_0xc58, MASKBYTE0);
  113. reg_c58 &= ~BIT(7);
  114. val_s8 = (s8)(-110 + reg_c58 + noise_data.sum[RF_PATH_B]);
  115. dm->noise_level.noise[RF_PATH_B] = val_s8;
  116. dm->noise_level.noise_all += dm->noise_level.noise[RF_PATH_B];
  117. }
  118. dm->noise_level.noise_all /= max_rf_path;
  119. PHYDM_DBG(dm, DBG_ENV_MNTR,
  120. "noise_a = %d, noise_b = %d, noise_all = %d\n",
  121. dm->noise_level.noise[RF_PATH_A],
  122. dm->noise_level.noise[RF_PATH_B], dm->noise_level.noise_all);
  123. /* step 4. Recover the Dig */
  124. if (is_pause_dig)
  125. odm_pause_dig(dm, PHYDM_RESUME, PHYDM_PAUSE_LEVEL_1, igi);
  126. func_end = odm_get_progressing_time(dm, func_start);
  127. PHYDM_DBG(dm, DBG_ENV_MNTR, "end\n");
  128. return dm->noise_level.noise_all;
  129. }
  130. #endif
  131. #if (ODM_IC_11AC_SERIES_SUPPORT)
  132. s16 phydm_idle_noise_measure_ac(struct dm_struct *dm, u8 pause_dig,
  133. u8 igi, u32 max_time)
  134. {
  135. u32 tmp4b;
  136. u8 max_rf_path = 0, i = 0;
  137. u8 reg_c50, reg_e50, valid_done = 0;
  138. u64 start = 0, func_start = 0, func_end = 0;
  139. struct noise_level noise_data;
  140. s8 val_s8 = 0;
  141. func_start = odm_get_current_time(dm);
  142. dm->noise_level.noise_all = 0;
  143. if (dm->rf_type == RF_1T2R || dm->rf_type == RF_2T2R)
  144. max_rf_path = 2;
  145. else
  146. max_rf_path = 1;
  147. PHYDM_DBG(dm, DBG_ENV_MNTR, "%s==>\n", __func__);
  148. odm_memory_set(dm, &noise_data, 0, sizeof(struct noise_level));
  149. /*Step 1. Disable DIG && Set initial gain.*/
  150. if (pause_dig)
  151. odm_pause_dig(dm, PHYDM_PAUSE, PHYDM_PAUSE_LEVEL_1, igi);
  152. /*Step 2. Get noise power level*/
  153. start = odm_get_current_time(dm);
  154. while (1) {
  155. /*Stop updating idle time pwer report (for driver read)*/
  156. odm_set_bb_reg(dm, R_0x9e4, BIT(30), 0x1);
  157. /*Read Noise Floor Report*/
  158. tmp4b = odm_get_bb_reg(dm, R_0xff0, MASKDWORD);
  159. /*update idle time pwer report per 5us*/
  160. odm_set_bb_reg(dm, R_0x9e4, BIT(30), 0x0);
  161. ODM_delay_us(5);
  162. noise_data.value[RF_PATH_A] = (u8)(tmp4b & 0xff);
  163. noise_data.value[RF_PATH_B] = (u8)((tmp4b & 0xff00) >> 8);
  164. for (i = RF_PATH_A; i < max_rf_path; i++) {
  165. noise_data.sval[i] = (s8)noise_data.value[i];
  166. noise_data.sval[i] = noise_data.sval[i] >> 1;
  167. }
  168. for (i = RF_PATH_A; i < max_rf_path; i++) {
  169. if (noise_data.valid_cnt[i] >= VALID_CNT)
  170. continue;
  171. noise_data.valid_cnt[i]++;
  172. noise_data.sum[i] += noise_data.sval[i];
  173. PHYDM_DBG(dm, DBG_ENV_MNTR, "Path:%d Valid sval = %d\n",
  174. i, noise_data.sval[i]);
  175. PHYDM_DBG(dm, DBG_ENV_MNTR, "Sum of sval = %d\n",
  176. noise_data.sum[i]);
  177. if (noise_data.valid_cnt[i] == VALID_CNT)
  178. valid_done++;
  179. }
  180. if (valid_done == max_rf_path ||
  181. (odm_get_progressing_time(dm, start) > max_time)) {
  182. phydm_set_noise_data_sum(&noise_data, max_rf_path);
  183. break;
  184. }
  185. }
  186. reg_c50 = (u8)odm_get_bb_reg(dm, R_0xc50, MASKBYTE0);
  187. reg_c50 &= ~BIT(7);
  188. val_s8 = (s8)(-110 + reg_c50 + noise_data.sum[RF_PATH_A]);
  189. dm->noise_level.noise[RF_PATH_A] = val_s8;
  190. dm->noise_level.noise_all += dm->noise_level.noise[RF_PATH_A];
  191. if (max_rf_path == 2) {
  192. reg_e50 = (u8)odm_get_bb_reg(dm, R_0xe50, MASKBYTE0);
  193. reg_e50 &= ~BIT(7);
  194. val_s8 = (s8)(-110 + reg_e50 + noise_data.sum[RF_PATH_B]);
  195. dm->noise_level.noise[RF_PATH_B] = val_s8;
  196. dm->noise_level.noise_all += dm->noise_level.noise[RF_PATH_B];
  197. }
  198. dm->noise_level.noise_all /= max_rf_path;
  199. PHYDM_DBG(dm, DBG_ENV_MNTR,
  200. "noise_a = %d, noise_b = %d, noise_all = %d\n",
  201. dm->noise_level.noise[RF_PATH_A],
  202. dm->noise_level.noise[RF_PATH_B], dm->noise_level.noise_all);
  203. /*Step 3. Recover the Dig*/
  204. if (pause_dig)
  205. odm_pause_dig(dm, PHYDM_RESUME, PHYDM_PAUSE_LEVEL_1, igi);
  206. func_end = odm_get_progressing_time(dm, func_start);
  207. PHYDM_DBG(dm, DBG_ENV_MNTR, "end\n");
  208. return dm->noise_level.noise_all;
  209. }
  210. s16 odm_inband_noise_monitor_ac(struct dm_struct *dm, u8 pause_dig, u8 igi,
  211. u32 max_time)
  212. {
  213. s32 rxi_buf_anta, rxq_buf_anta; /*rxi_buf_antb, rxq_buf_antb;*/
  214. s32 value32, pwdb_A = 0, sval, noise, sum = 0;
  215. boolean pd_flag;
  216. u8 valid_cnt = 0;
  217. u64 start = 0, func_start = 0, func_end = 0;
  218. s32 val_s32 = 0;
  219. s16 rpt = 0;
  220. u8 val_u8 = 0;
  221. if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C)) {
  222. rpt = phydm_idle_noise_measure_ac(dm, pause_dig, igi, max_time);
  223. return rpt;
  224. }
  225. if (!(dm->support_ic_type & (ODM_RTL8812 | ODM_RTL8821 | ODM_RTL8814A)))
  226. return 0;
  227. func_start = odm_get_current_time(dm);
  228. dm->noise_level.noise_all = 0;
  229. PHYDM_DBG(dm, DBG_ENV_MNTR, "%s ==>\n", __func__);
  230. /* step 1. Disable DIG && Set initial gain. */
  231. if (pause_dig)
  232. odm_pause_dig(dm, PHYDM_PAUSE, PHYDM_PAUSE_LEVEL_1, igi);
  233. /* step 3. Get noise power level */
  234. start = odm_get_current_time(dm);
  235. /* step 3. Get noise power level */
  236. while (1) {
  237. /*Set IGI=0x1C */
  238. odm_write_dig(dm, 0x1C);
  239. /*stop CK320&CK88 */
  240. odm_set_bb_reg(dm, R_0x8b4, BIT(6), 1);
  241. /*Read path-A */
  242. /*set debug port*/
  243. odm_set_bb_reg(dm, R_0x8fc, MASKDWORD, 0x200);
  244. /*read debug port*/
  245. value32 = odm_get_bb_reg(dm, R_0xfa0, MASKDWORD);
  246. /*rxi_buf_anta=RegFA0[19:10]*/
  247. rxi_buf_anta = (value32 & 0xFFC00) >> 10;
  248. rxq_buf_anta = value32 & 0x3FF; /*rxq_buf_anta=RegFA0[19:10]*/
  249. pd_flag = (boolean)((value32 & BIT(31)) >> 31);
  250. /*Not in packet detection period or Tx state */
  251. if (!pd_flag || rxi_buf_anta != 0x200) {
  252. /*sign conversion*/
  253. rxi_buf_anta = odm_sign_conversion(rxi_buf_anta, 10);
  254. rxq_buf_anta = odm_sign_conversion(rxq_buf_anta, 10);
  255. val_s32 = rxi_buf_anta * rxi_buf_anta +
  256. rxq_buf_anta * rxq_buf_anta;
  257. /*S(10,9)*S(10,9)=S(20,18)*/
  258. pwdb_A = odm_pwdb_conversion(val_s32, 20, 18);
  259. PHYDM_DBG(dm, DBG_ENV_MNTR,
  260. "pwdb_A= %d dB, rxi_buf_anta= 0x%x, rxq_buf_anta= 0x%x\n",
  261. pwdb_A, rxi_buf_anta & 0x3FF,
  262. rxq_buf_anta & 0x3FF);
  263. }
  264. /*Start CK320&CK88*/
  265. odm_set_bb_reg(dm, R_0x8b4, BIT(6), 0);
  266. /*@BB Reset*/
  267. val_u8 = odm_read_1byte(dm, 0x02) & (~BIT(0));
  268. odm_write_1byte(dm, 0x02, val_u8);
  269. val_u8 = odm_read_1byte(dm, 0x02) | BIT(0);
  270. odm_write_1byte(dm, 0x02, val_u8);
  271. /*PMAC Reset*/
  272. val_u8 = odm_read_1byte(dm, 0xB03) & (~BIT(0));
  273. odm_write_1byte(dm, 0xB03, val_u8);
  274. val_u8 = odm_read_1byte(dm, 0xB03) | BIT(0);
  275. odm_write_1byte(dm, 0xB03, val_u8);
  276. /*@CCK Reset*/
  277. if (odm_read_1byte(dm, 0x80B) & BIT(4)) {
  278. val_u8 = odm_read_1byte(dm, 0x80B) & (~BIT(4));
  279. odm_write_1byte(dm, 0x80B, val_u8);
  280. val_u8 = odm_read_1byte(dm, 0x80B) | BIT(4);
  281. odm_write_1byte(dm, 0x80B, val_u8);
  282. }
  283. sval = pwdb_A;
  284. if ((sval < 0 && sval >= -27) && valid_cnt < VALID_CNT) {
  285. valid_cnt++;
  286. sum += sval;
  287. PHYDM_DBG(dm, DBG_ENV_MNTR, "Valid sval = %d\n", sval);
  288. PHYDM_DBG(dm, DBG_ENV_MNTR, "Sum of sval = %d,\n", sum);
  289. if (valid_cnt >= VALID_CNT ||
  290. (odm_get_progressing_time(dm, start) > max_time)) {
  291. sum /= VALID_CNT;
  292. PHYDM_DBG(dm, DBG_ENV_MNTR,
  293. "After divided, sum = %d\n", sum);
  294. break;
  295. }
  296. }
  297. }
  298. /*@ADC backoff is 12dB,*/
  299. /*Ptarget=0x1C-110=-82dBm*/
  300. noise = sum + 12 + 0x1C - 110;
  301. /*Offset*/
  302. noise = noise - 3;
  303. PHYDM_DBG(dm, DBG_ENV_MNTR, "noise = %d\n", noise);
  304. dm->noise_level.noise_all = (s16)noise;
  305. /* step 4. Recover the Dig*/
  306. if (pause_dig)
  307. odm_pause_dig(dm, PHYDM_RESUME, PHYDM_PAUSE_LEVEL_1, igi);
  308. func_end = odm_get_progressing_time(dm, func_start);
  309. PHYDM_DBG(dm, DBG_ENV_MNTR, "%s <==\n", __func__);
  310. return dm->noise_level.noise_all;
  311. }
  312. #endif
  313. s16 odm_inband_noise_monitor(void *dm_void, u8 pause_dig, u8 igi,
  314. u32 max_time)
  315. {
  316. struct dm_struct *dm = (struct dm_struct *)dm_void;
  317. s16 val = 0;
  318. igi = 0x32;
  319. /* since HW ability is about +15~-35,
  320. * we fix IGI = -60 for maximum coverage
  321. */
  322. #if (ODM_IC_11AC_SERIES_SUPPORT)
  323. if (dm->support_ic_type & ODM_IC_11AC_SERIES)
  324. val = odm_inband_noise_monitor_ac(dm, pause_dig, igi, max_time);
  325. #endif
  326. #if (ODM_IC_11N_SERIES_SUPPORT)
  327. if (dm->support_ic_type & ODM_IC_11N_SERIES)
  328. val = odm_inband_noise_monitor_n(dm, pause_dig, igi, max_time);
  329. #endif
  330. return val;
  331. }
  332. void phydm_noisy_detection(void *dm_void)
  333. {
  334. struct dm_struct *dm = (struct dm_struct *)dm_void;
  335. u32 total_fa_cnt, total_cca_cnt;
  336. u32 score = 0, i, score_smooth;
  337. total_cca_cnt = dm->false_alm_cnt.cnt_cca_all;
  338. total_fa_cnt = dm->false_alm_cnt.cnt_all;
  339. #if 0
  340. if (total_fa_cnt * 16 >= total_cca_cnt * 14) /* @87.5 */
  341. ;
  342. else if (total_fa_cnt * 16 >= total_cca_cnt * 12) /* @75 */
  343. ;
  344. else if (total_fa_cnt * 16 >= total_cca_cnt * 10) /* @56.25 */
  345. ;
  346. else if (total_fa_cnt * 16 >= total_cca_cnt * 8) /* @50 */
  347. ;
  348. else if (total_fa_cnt * 16 >= total_cca_cnt * 7) /* @43.75 */
  349. ;
  350. else if (total_fa_cnt * 16 >= total_cca_cnt * 6) /* @37.5 */
  351. ;
  352. else if (total_fa_cnt * 16 >= total_cca_cnt * 5) /* @31.25% */
  353. ;
  354. else if (total_fa_cnt * 16 >= total_cca_cnt * 4) /* @25% */
  355. ;
  356. else if (total_fa_cnt * 16 >= total_cca_cnt * 3) /* @18.75% */
  357. ;
  358. else if (total_fa_cnt * 16 >= total_cca_cnt * 2) /* @12.5% */
  359. ;
  360. else if (total_fa_cnt * 16 >= total_cca_cnt * 1) /* @6.25% */
  361. ;
  362. #endif
  363. for (i = 0; i <= 16; i++) {
  364. if (total_fa_cnt * 16 >= total_cca_cnt * (16 - i)) {
  365. score = 16 - i;
  366. break;
  367. }
  368. }
  369. /* noisy_decision_smooth = noisy_decision_smooth>>1 + (score<<3)>>1; */
  370. dm->noisy_decision_smooth = (dm->noisy_decision_smooth >> 1) +
  371. (score << 2);
  372. /* Round the noisy_decision_smooth: +"3" comes from (2^3)/2-1 */
  373. if (total_cca_cnt >= 300)
  374. score_smooth = (dm->noisy_decision_smooth + 3) >> 3;
  375. else
  376. score_smooth = 0;
  377. dm->noisy_decision = (score_smooth >= 3) ? 1 : 0;
  378. PHYDM_DBG(dm, DBG_ENV_MNTR,
  379. "[NoisyDetection] CCA_cnt=%d,FA_cnt=%d, noisy_dec_smooth=%d, score=%d, score_smooth=%d, noisy_dec=%d\n",
  380. total_cca_cnt, total_fa_cnt, dm->noisy_decision_smooth, score,
  381. score_smooth, dm->noisy_decision);
  382. }