1 /******************************************************************************
3 * Copyright(c) 2007 - 2017 Realtek Corporation.
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.
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
14 *****************************************************************************/
17 #include <drv_types.h>
20 u8 center_ch_2g[CENTER_CH_2G_NUM] = {
29 u8 center_ch_2g_40m[CENTER_CH_2G_40M_NUM] = {
41 u8 op_chs_of_cch_2g_40m[CENTER_CH_2G_40M_NUM][2] = {
53 u8 center_ch_5g_all[CENTER_CH_5G_ALL_NUM] = {
61 /* G04 */100, 102, 104,
63 /* G05 */108, 110, 112,
65 /* G06 */116, 118, 120,
67 /* G07 */124, 126, 128,
68 /* G08 */132, 134, 136,
70 /* G09 */140, 142, 144,
71 /* G10 */149, 151, 153,
73 /* G11 */157, 159, 161,
75 /* G12 */165, 167, 169,
77 /* G13 */173, 175, 177
80 u8 center_ch_5g_20m[CENTER_CH_5G_20M_NUM] = {
97 u8 center_ch_5g_40m[CENTER_CH_5G_40M_NUM] = {
114 u8 center_ch_5g_20m_40m[CENTER_CH_5G_20M_NUM + CENTER_CH_5G_40M_NUM] = {
119 /* G04 */100, 102, 104,
120 /* G05 */108, 110, 112,
121 /* G06 */116, 118, 120,
122 /* G07 */124, 126, 128,
123 /* G08 */132, 134, 136,
124 /* G09 */140, 142, 144,
125 /* G10 */149, 151, 153,
126 /* G11 */157, 159, 161,
127 /* G12 */165, 167, 169,
128 /* G13 */173, 175, 177
131 u8 op_chs_of_cch_5g_40m[CENTER_CH_5G_40M_NUM][2] = {
136 {100, 104}, /* 102 */
137 {108, 112}, /* 110 */
138 {116, 120}, /* 118 */
139 {124, 128}, /* 126 */
140 {132, 136}, /* 134 */
141 {140, 144}, /* 142 */
142 {149, 153}, /* 151 */
143 {157, 161}, /* 159 */
144 {165, 169}, /* 167 */
145 {173, 177}, /* 175 */
148 u8 center_ch_5g_80m[CENTER_CH_5G_80M_NUM] = {
158 u8 op_chs_of_cch_5g_80m[CENTER_CH_5G_80M_NUM][4] = {
159 {36, 40, 44, 48}, /* 42 */
160 {52, 56, 60, 64}, /* 58 */
161 {100, 104, 108, 112}, /* 106 */
162 {116, 120, 124, 128}, /* 122 */
163 {132, 136, 140, 144}, /* 138 */
164 {149, 153, 157, 161}, /* 155 */
165 {165, 169, 173, 177}, /* 171 */
168 u8 center_ch_5g_160m[CENTER_CH_5G_160M_NUM] = {
174 u8 op_chs_of_cch_5g_160m[CENTER_CH_5G_160M_NUM][8] = {
175 {36, 40, 44, 48, 52, 56, 60, 64}, /* 50 */
176 {100, 104, 108, 112, 116, 120, 124, 128}, /* 114 */
177 {149, 153, 157, 161, 165, 169, 173, 177}, /* 163 */
180 struct center_chs_ent_t {
185 struct center_chs_ent_t center_chs_2g_by_bw[] = {
186 {CENTER_CH_2G_NUM, center_ch_2g},
187 {CENTER_CH_2G_40M_NUM, center_ch_2g_40m},
190 struct center_chs_ent_t center_chs_5g_by_bw[] = {
191 {CENTER_CH_5G_20M_NUM, center_ch_5g_20m},
192 {CENTER_CH_5G_40M_NUM, center_ch_5g_40m},
193 {CENTER_CH_5G_80M_NUM, center_ch_5g_80m},
194 {CENTER_CH_5G_160M_NUM, center_ch_5g_160m},
198 * Get center channel of smaller bandwidth by @param cch, @param bw, @param offset
199 * @cch: the given center channel
200 * @bw: the given bandwidth
201 * @offset: the given primary SC offset of the given bandwidth
203 * return center channel of smaller bandiwdth if valid, or 0
205 u8 rtw_get_scch_by_cch_offset(u8 cch, u8 bw, u8 offset)
209 if (bw == CHANNEL_WIDTH_20) {
214 if (offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) {
220 if (cch >= 3 && cch <= 11 && bw == CHANNEL_WIDTH_40) {
221 t_cch = (offset == HAL_PRIME_CHNL_OFFSET_UPPER) ? cch + 2 : cch - 2;
226 if (cch >= 50 && cch <= 163 && bw == CHANNEL_WIDTH_160) {
227 t_cch = (offset == HAL_PRIME_CHNL_OFFSET_UPPER) ? cch + 8 : cch - 8;
231 } else if (cch >= 42 && cch <= 171 && bw == CHANNEL_WIDTH_80) {
232 t_cch = (offset == HAL_PRIME_CHNL_OFFSET_UPPER) ? cch + 4 : cch - 4;
236 } else if (cch >= 38 && cch <= 175 && bw == CHANNEL_WIDTH_40) {
237 t_cch = (offset == HAL_PRIME_CHNL_OFFSET_UPPER) ? cch + 2 : cch - 2;
249 struct op_chs_ent_t {
254 struct op_chs_ent_t op_chs_of_cch_2g_by_bw[] = {
256 {2, (u8 *)op_chs_of_cch_2g_40m},
259 struct op_chs_ent_t op_chs_of_cch_5g_by_bw[] = {
260 {1, center_ch_5g_20m},
261 {2, (u8 *)op_chs_of_cch_5g_40m},
262 {4, (u8 *)op_chs_of_cch_5g_80m},
263 {8, (u8 *)op_chs_of_cch_5g_160m},
266 inline u8 center_chs_2g_num(u8 bw)
268 if (bw > CHANNEL_WIDTH_40)
271 return center_chs_2g_by_bw[bw].ch_num;
274 inline u8 center_chs_2g(u8 bw, u8 id)
276 if (bw > CHANNEL_WIDTH_40)
279 if (id >= center_chs_2g_num(bw))
282 return center_chs_2g_by_bw[bw].chs[id];
285 inline u8 center_chs_5g_num(u8 bw)
287 if (bw > CHANNEL_WIDTH_80)
290 return center_chs_5g_by_bw[bw].ch_num;
293 inline u8 center_chs_5g(u8 bw, u8 id)
295 if (bw > CHANNEL_WIDTH_80)
298 if (id >= center_chs_5g_num(bw))
301 return center_chs_5g_by_bw[bw].chs[id];
305 * Get available op channels by @param cch, @param bw
306 * @cch: the given center channel
307 * @bw: the given bandwidth
308 * @op_chs: the pointer to return pointer of op channel array
309 * @op_ch_num: the pointer to return pointer of op channel number
311 * return valid (1) or not (0)
313 u8 rtw_get_op_chs_by_cch_bw(u8 cch, u8 bw, u8 **op_chs, u8 *op_ch_num)
316 struct center_chs_ent_t *c_chs_ent = NULL;
317 struct op_chs_ent_t *op_chs_ent = NULL;
321 && bw >= CHANNEL_WIDTH_20 && bw <= CHANNEL_WIDTH_40
323 c_chs_ent = ¢er_chs_2g_by_bw[bw];
324 op_chs_ent = &op_chs_of_cch_2g_by_bw[bw];
325 } else if (cch >= 36 && cch <= 177
326 && bw >= CHANNEL_WIDTH_20 && bw <= CHANNEL_WIDTH_160
328 c_chs_ent = ¢er_chs_5g_by_bw[bw];
329 op_chs_ent = &op_chs_of_cch_5g_by_bw[bw];
335 for (i = 0; i < c_chs_ent->ch_num; i++)
336 if (cch == *(c_chs_ent->chs + i))
339 if (i == c_chs_ent->ch_num) {
344 *op_chs = op_chs_ent->chs + op_chs_ent->ch_num * i;
345 *op_ch_num = op_chs_ent->ch_num;
351 u8 rtw_get_ch_group(u8 ch, u8 *group, u8 *cck_group)
353 BAND_TYPE band = BAND_MAX;
354 s8 gp = -1, cck_gp = -1;
359 if (1 <= ch && ch <= 2)
361 else if (3 <= ch && ch <= 5)
363 else if (6 <= ch && ch <= 8)
365 else if (9 <= ch && ch <= 11)
367 else if (12 <= ch && ch <= 14)
379 if (36 <= ch && ch <= 42)
381 else if (44 <= ch && ch <= 48)
383 else if (50 <= ch && ch <= 58)
385 else if (60 <= ch && ch <= 64)
387 else if (100 <= ch && ch <= 106)
389 else if (108 <= ch && ch <= 114)
391 else if (116 <= ch && ch <= 122)
393 else if (124 <= ch && ch <= 130)
395 else if (132 <= ch && ch <= 138)
397 else if (140 <= ch && ch <= 144)
399 else if (149 <= ch && ch <= 155)
401 else if (157 <= ch && ch <= 161)
403 else if (165 <= ch && ch <= 171)
405 else if (173 <= ch && ch <= 177)
412 || (band == BAND_ON_2_4G && cck_gp == -1)
415 RTW_WARN("%s invalid channel:%u", __func__, ch);
422 if (cck_group && band == BAND_ON_2_4G)
429 int rtw_ch2freq(int chan)
431 /* see 802.11 17.3.8.3.2 and Annex J
432 * there are overlapping channel numbers in 5GHz and 2GHz bands */
435 * RTK: don't consider the overlapping channel numbers: 5G channel <= 14,
436 * because we don't support it. simply judge from channel number
439 if (chan >= 1 && chan <= 14) {
443 return 2407 + chan * 5;
444 } else if (chan >= 36 && chan <= 177)
445 return 5000 + chan * 5;
447 return 0; /* not supported */
450 int rtw_freq2ch(int freq)
452 /* see 802.11 17.3.8.3.2 and Annex J */
455 else if (freq < 2484)
456 return (freq - 2407) / 5;
457 else if (freq >= 4910 && freq <= 4980)
458 return (freq - 4000) / 5;
459 else if (freq <= 45000) /* DMG band lower limit */
460 return (freq - 5000) / 5;
461 else if (freq >= 58320 && freq <= 64800)
462 return (freq - 56160) / 2160;
467 bool rtw_chbw_to_freq_range(u8 ch, u8 bw, u8 offset, u32 *hi, u32 *lo)
471 u32 hi_ret = 0, lo_ret = 0;
479 c_ch = rtw_get_center_ch(ch, bw, offset);
480 freq = rtw_ch2freq(c_ch);
487 if (bw == CHANNEL_WIDTH_80) {
490 } else if (bw == CHANNEL_WIDTH_40) {
493 } else if (bw == CHANNEL_WIDTH_20) {
510 const char *const _ch_width_str[CHANNEL_WIDTH_MAX] = {
520 const u8 _ch_width_to_bw_cap[CHANNEL_WIDTH_MAX] = {
530 const char *const _band_str[] = {
537 const u8 _band_to_band_cap[] = {
544 const u8 _rf_type_to_rf_tx_cnt[] = {
556 const u8 _rf_type_to_rf_rx_cnt[] = {
568 const char *const _regd_str[] = {
580 #ifdef CONFIG_TXPWR_LIMIT
581 void _dump_regd_exc_list(void *sel, struct rf_ctl_t *rfctl)
583 struct regd_exc_ent *ent;
586 RTW_PRINT_SEL(sel, "regd_exc_num:%u\n", rfctl->regd_exc_num);
588 if (!rfctl->regd_exc_num)
591 RTW_PRINT_SEL(sel, "%-7s %-6s %-9s\n", "country", "domain", "regd_name");
593 head = &rfctl->reg_exc_list;
594 cur = get_next(head);
596 while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
599 ent = LIST_CONTAINOR(cur, struct regd_exc_ent, list);
601 has_country = (ent->country[0] == '\0' && ent->country[1] == '\0') ? 0 : 1;
603 RTW_PRINT_SEL(sel, " %c%c 0x%02x %s\n"
604 , has_country ? ent->country[0] : '0'
605 , has_country ? ent->country[1] : '0'
615 inline void dump_regd_exc_list(void *sel, struct rf_ctl_t *rfctl)
619 _enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
620 _dump_regd_exc_list(sel, rfctl);
621 _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
624 void rtw_regd_exc_add_with_nlen(struct rf_ctl_t *rfctl, const char *country, u8 domain, const char *regd_name, u32 nlen)
626 struct regd_exc_ent *ent;
629 if (!regd_name || !nlen) {
634 ent = (struct regd_exc_ent *)rtw_zmalloc(sizeof(struct regd_exc_ent) + nlen + 1);
638 _rtw_init_listhead(&ent->list);
640 _rtw_memcpy(ent->country, country, 2);
641 ent->domain = domain;
642 _rtw_memcpy(ent->regd_name, regd_name, nlen);
644 _enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
646 rtw_list_insert_tail(&ent->list, &rfctl->reg_exc_list);
647 rfctl->regd_exc_num++;
649 _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
655 inline void rtw_regd_exc_add(struct rf_ctl_t *rfctl, const char *country, u8 domain, const char *regd_name)
657 rtw_regd_exc_add_with_nlen(rfctl, country, domain, regd_name, strlen(regd_name));
660 struct regd_exc_ent *_rtw_regd_exc_search(struct rf_ctl_t *rfctl, const char *country, u8 domain)
662 struct regd_exc_ent *ent;
666 head = &rfctl->reg_exc_list;
667 cur = get_next(head);
669 while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
672 ent = LIST_CONTAINOR(cur, struct regd_exc_ent, list);
674 has_country = (ent->country[0] == '\0' && ent->country[1] == '\0') ? 0 : 1;
676 /* entry has country condition to match */
680 if (ent->country[0] != country[0]
681 || ent->country[1] != country[1])
685 /* entry has domain condition to match */
686 if (ent->domain != 0xFF) {
689 if (ent->domain != domain)
703 inline struct regd_exc_ent *rtw_regd_exc_search(struct rf_ctl_t *rfctl, const char *country, u8 domain)
705 struct regd_exc_ent *ent;
708 _enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
709 ent = _rtw_regd_exc_search(rfctl, country, domain);
710 _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
715 void rtw_regd_exc_list_free(struct rf_ctl_t *rfctl)
717 struct regd_exc_ent *ent;
721 _enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
723 head = &rfctl->reg_exc_list;
724 cur = get_next(head);
726 while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
727 ent = LIST_CONTAINOR(cur, struct regd_exc_ent, list);
729 rtw_list_delete(&ent->list);
730 rtw_mfree((u8 *)ent, sizeof(struct regd_exc_ent) + strlen(ent->regd_name) + 1);
732 rfctl->regd_exc_num = 0;
734 _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
737 void dump_txpwr_lmt(void *sel, _adapter *adapter)
739 #define TMP_STR_LEN 16
740 struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
741 struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter);
744 char tmp_str[TMP_STR_LEN];
746 int bw, band, ch_num, tlrs, ntx_idx, rs, i, path;
747 u8 ch, n, rfpath_num;
749 _enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
751 _dump_regd_exc_list(sel, rfctl);
752 RTW_PRINT_SEL(sel, "\n");
754 if (!rfctl->txpwr_regd_num)
757 lmt_idx = rtw_malloc(sizeof(s8) * RF_PATH_MAX * rfctl->txpwr_regd_num);
759 RTW_ERR("%s alloc fail\n", __func__);
763 RTW_PRINT_SEL(sel, "txpwr_lmt_2g_cck_ofdm_state:0x%02x\n", rfctl->txpwr_lmt_2g_cck_ofdm_state);
764 #ifdef CONFIG_IEEE80211_BAND_5GHZ
765 if (IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(adapter))
766 RTW_PRINT_SEL(sel, "txpwr_lmt_5g_cck_ofdm_state:0x%02x\n", rfctl->txpwr_lmt_5g_cck_ofdm_state);
767 RTW_PRINT_SEL(sel, "txpwr_lmt_5g_20_40_ref:0x%02x\n", rfctl->txpwr_lmt_5g_20_40_ref);
769 RTW_PRINT_SEL(sel, "\n");
771 for (band = BAND_ON_2_4G; band <= BAND_ON_5G; band++) {
772 if (!hal_is_band_support(adapter, band))
775 rfpath_num = (band == BAND_ON_2_4G ? hal_spec->rfpath_num_2g : hal_spec->rfpath_num_5g);
777 for (bw = 0; bw < MAX_5G_BANDWIDTH_NUM; bw++) {
779 if (bw >= CHANNEL_WIDTH_160)
781 if (band == BAND_ON_2_4G && bw >= CHANNEL_WIDTH_80)
784 if (band == BAND_ON_2_4G)
785 ch_num = CENTER_CH_2G_NUM;
787 ch_num = center_chs_5g_num(bw);
794 for (tlrs = TXPWR_LMT_RS_CCK; tlrs < TXPWR_LMT_RS_NUM; tlrs++) {
796 if (band == BAND_ON_2_4G && tlrs == TXPWR_LMT_RS_VHT)
798 if (band == BAND_ON_5G && tlrs == TXPWR_LMT_RS_CCK)
800 if (bw > CHANNEL_WIDTH_20 && (tlrs == TXPWR_LMT_RS_CCK || tlrs == TXPWR_LMT_RS_OFDM))
802 if (bw > CHANNEL_WIDTH_40 && tlrs == TXPWR_LMT_RS_HT)
804 if (tlrs == TXPWR_LMT_RS_VHT && !IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(adapter))
807 for (ntx_idx = RF_1TX; ntx_idx < MAX_TX_COUNT; ntx_idx++) {
808 struct txpwr_lmt_ent *ent;
811 if (ntx_idx >= hal_spec->tx_nss_num)
814 /* bypass CCK multi-TX is not defined */
815 if (tlrs == TXPWR_LMT_RS_CCK && ntx_idx > RF_1TX) {
816 if (band == BAND_ON_2_4G
817 && !(rfctl->txpwr_lmt_2g_cck_ofdm_state & (TXPWR_LMT_HAS_CCK_1T << ntx_idx)))
821 /* bypass OFDM multi-TX is not defined */
822 if (tlrs == TXPWR_LMT_RS_OFDM && ntx_idx > RF_1TX) {
823 if (band == BAND_ON_2_4G
824 && !(rfctl->txpwr_lmt_2g_cck_ofdm_state & (TXPWR_LMT_HAS_OFDM_1T << ntx_idx)))
826 #ifdef CONFIG_IEEE80211_BAND_5GHZ
827 if (band == BAND_ON_5G
828 && !(rfctl->txpwr_lmt_5g_cck_ofdm_state & (TXPWR_LMT_HAS_OFDM_1T << ntx_idx)))
833 /* bypass 5G 20M, 40M pure reference */
834 #ifdef CONFIG_IEEE80211_BAND_5GHZ
835 if (band == BAND_ON_5G && (bw == CHANNEL_WIDTH_20 || bw == CHANNEL_WIDTH_40)) {
836 if (rfctl->txpwr_lmt_5g_20_40_ref == TXPWR_LMT_REF_HT_FROM_VHT) {
837 if (tlrs == TXPWR_LMT_RS_HT)
839 } else if (rfctl->txpwr_lmt_5g_20_40_ref == TXPWR_LMT_REF_VHT_FROM_HT) {
840 if (tlrs == TXPWR_LMT_RS_VHT && bw <= CHANNEL_WIDTH_40)
846 /* choose n-SS mapping rate section to get lmt diff value */
847 if (tlrs == TXPWR_LMT_RS_CCK)
849 else if (tlrs == TXPWR_LMT_RS_OFDM)
851 else if (tlrs == TXPWR_LMT_RS_HT)
852 rs = HT_1SS + ntx_idx;
853 else if (tlrs == TXPWR_LMT_RS_VHT)
854 rs = VHT_1SS + ntx_idx;
856 RTW_ERR("%s invalid tlrs %u\n", __func__, tlrs);
860 RTW_PRINT_SEL(sel, "[%s][%s][%s][%uT]\n"
863 , txpwr_lmt_rs_str(tlrs)
867 /* header for limit in db */
868 RTW_PRINT_SEL(sel, "%3s ", "ch");
870 head = &rfctl->txpwr_lmt_list;
871 cur = get_next(head);
872 while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
873 ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
876 sprintf(fmt, "%%%zus%%s ", strlen(ent->regd_name) >= 6 ? 1 : 6 - strlen(ent->regd_name));
877 snprintf(tmp_str, TMP_STR_LEN, fmt
878 , strcmp(ent->regd_name, rfctl->regd_name) == 0 ? "*" : ""
880 _RTW_PRINT_SEL(sel, "%s", tmp_str);
882 sprintf(fmt, "%%%zus%%s ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? 1 : 6 - strlen(regd_str(TXPWR_LMT_WW)));
883 snprintf(tmp_str, TMP_STR_LEN, fmt
884 , strcmp(rfctl->regd_name, regd_str(TXPWR_LMT_WW)) == 0 ? "*" : ""
885 , regd_str(TXPWR_LMT_WW));
886 _RTW_PRINT_SEL(sel, "%s", tmp_str);
888 /* header for limit offset */
889 for (path = 0; path < RF_PATH_MAX; path++) {
890 if (path >= rfpath_num)
892 _RTW_PRINT_SEL(sel, "|");
893 head = &rfctl->txpwr_lmt_list;
894 cur = get_next(head);
895 while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
896 ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
898 _RTW_PRINT_SEL(sel, "%3c "
899 , strcmp(ent->regd_name, rfctl->regd_name) == 0 ? rf_path_char(path) : ' ');
901 _RTW_PRINT_SEL(sel, "%3c "
902 , strcmp(rfctl->regd_name, regd_str(TXPWR_LMT_WW)) == 0 ? rf_path_char(path) : ' ');
904 _RTW_PRINT_SEL(sel, "\n");
906 for (n = 0; n < ch_num; n++) {
911 if (band == BAND_ON_2_4G)
914 ch = center_chs_5g(bw, n);
921 /* dump limit in db */
922 RTW_PRINT_SEL(sel, "%3u ", ch);
923 head = &rfctl->txpwr_lmt_list;
924 cur = get_next(head);
925 while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
926 ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
928 lmt = phy_get_txpwr_lmt_abs(adapter, ent->regd_name, band, bw, tlrs, ntx_idx, ch, 0);
929 if (lmt == hal_spec->txgi_max) {
930 sprintf(fmt, "%%%zus ", strlen(ent->regd_name) >= 6 ? strlen(ent->regd_name) + 1 : 6);
931 snprintf(tmp_str, TMP_STR_LEN, fmt, "NA");
932 _RTW_PRINT_SEL(sel, "%s", tmp_str);
933 } else if (lmt > -hal_spec->txgi_pdbm && lmt < 0) { /* -0.xx */
934 sprintf(fmt, "%%%zus-0.%%d ", strlen(ent->regd_name) >= 6 ? strlen(ent->regd_name) - 4 : 1);
935 snprintf(tmp_str, TMP_STR_LEN, fmt, "", (rtw_abs(lmt) % hal_spec->txgi_pdbm) * 100 / hal_spec->txgi_pdbm);
936 _RTW_PRINT_SEL(sel, "%s", tmp_str);
937 } else if (lmt % hal_spec->txgi_pdbm) { /* d.xx */
938 sprintf(fmt, "%%%zud.%%d ", strlen(ent->regd_name) >= 6 ? strlen(ent->regd_name) - 2 : 3);
939 snprintf(tmp_str, TMP_STR_LEN, fmt, lmt / hal_spec->txgi_pdbm, (rtw_abs(lmt) % hal_spec->txgi_pdbm) * 100 / hal_spec->txgi_pdbm);
940 _RTW_PRINT_SEL(sel, "%s", tmp_str);
942 sprintf(fmt, "%%%zud ", strlen(ent->regd_name) >= 6 ? strlen(ent->regd_name) + 1 : 6);
943 snprintf(tmp_str, TMP_STR_LEN, fmt, lmt / hal_spec->txgi_pdbm);
944 _RTW_PRINT_SEL(sel, "%s", tmp_str);
947 lmt = phy_get_txpwr_lmt_abs(adapter, regd_str(TXPWR_LMT_WW), band, bw, tlrs, ntx_idx, ch, 0);
948 if (lmt == hal_spec->txgi_max) {
949 sprintf(fmt, "%%%zus ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? strlen(regd_str(TXPWR_LMT_WW)) + 1 : 6);
950 snprintf(tmp_str, TMP_STR_LEN, fmt, "NA");
951 _RTW_PRINT_SEL(sel, "%s", tmp_str);
952 } else if (lmt > -hal_spec->txgi_pdbm && lmt < 0) { /* -0.xx */
953 sprintf(fmt, "%%%zus-0.%%d ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? strlen(regd_str(TXPWR_LMT_WW)) - 4 : 1);
954 snprintf(tmp_str, TMP_STR_LEN, fmt, "", (rtw_abs(lmt) % hal_spec->txgi_pdbm) * 100 / hal_spec->txgi_pdbm);
955 _RTW_PRINT_SEL(sel, "%s", tmp_str);
956 } else if (lmt % hal_spec->txgi_pdbm) { /* d.xx */
957 sprintf(fmt, "%%%zud.%%d ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? strlen(regd_str(TXPWR_LMT_WW)) - 2 : 3);
958 snprintf(tmp_str, TMP_STR_LEN, fmt, lmt / hal_spec->txgi_pdbm, (rtw_abs(lmt) % hal_spec->txgi_pdbm) * 100 / hal_spec->txgi_pdbm);
959 _RTW_PRINT_SEL(sel, "%s", tmp_str);
961 sprintf(fmt, "%%%zud ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? strlen(regd_str(TXPWR_LMT_WW)) + 1 : 6);
962 snprintf(tmp_str, TMP_STR_LEN, fmt, lmt / hal_spec->txgi_pdbm);
963 _RTW_PRINT_SEL(sel, "%s", tmp_str);
966 /* dump limit offset of each path */
967 for (path = RF_PATH_A; path < RF_PATH_MAX; path++) {
968 if (path >= rfpath_num)
971 base = PHY_GetTxPowerByRateBase(adapter, band, path, rs);
973 _RTW_PRINT_SEL(sel, "|");
974 head = &rfctl->txpwr_lmt_list;
975 cur = get_next(head);
977 while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
978 ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
980 lmt_offset = phy_get_txpwr_lmt(adapter, ent->regd_name, band, bw, path, rs, ntx_idx, ch, 0);
981 if (lmt_offset == hal_spec->txgi_max) {
982 *(lmt_idx + i * RF_PATH_MAX + path) = hal_spec->txgi_max;
983 _RTW_PRINT_SEL(sel, "%3s ", "NA");
985 *(lmt_idx + i * RF_PATH_MAX + path) = lmt_offset + base;
986 _RTW_PRINT_SEL(sel, "%3d ", lmt_offset);
990 lmt_offset = phy_get_txpwr_lmt(adapter, regd_str(TXPWR_LMT_WW), band, bw, path, rs, ntx_idx, ch, 0);
991 if (lmt_offset == hal_spec->txgi_max)
992 _RTW_PRINT_SEL(sel, "%3s ", "NA");
994 _RTW_PRINT_SEL(sel, "%3d ", lmt_offset);
998 /* compare limit_idx of each path, print 'x' when mismatch */
999 if (rfpath_num > 1) {
1000 for (i = 0; i < rfctl->txpwr_regd_num; i++) {
1001 for (path = 0; path < RF_PATH_MAX; path++) {
1002 if (path >= rfpath_num)
1004 if (*(lmt_idx + i * RF_PATH_MAX + path) != *(lmt_idx + i * RF_PATH_MAX + ((path + 1) % rfpath_num)))
1007 if (path >= rfpath_num)
1008 _RTW_PRINT_SEL(sel, " ");
1010 _RTW_PRINT_SEL(sel, "x");
1013 _RTW_PRINT_SEL(sel, "\n");
1016 RTW_PRINT_SEL(sel, "\n");
1018 } /* loop for rate sections */
1019 } /* loop for bandwidths */
1020 } /* loop for bands */
1023 rtw_mfree(lmt_idx, sizeof(s8) * RF_PATH_MAX * rfctl->txpwr_regd_num);
1026 _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1029 /* search matcing first, if not found, alloc one */
1030 void rtw_txpwr_lmt_add_with_nlen(struct rf_ctl_t *rfctl, const char *regd_name, u32 nlen
1031 , u8 band, u8 bw, u8 tlrs, u8 ntx_idx, u8 ch_idx, s8 lmt)
1033 struct hal_spec_t *hal_spec = GET_HAL_SPEC(dvobj_get_primary_adapter(rfctl_to_dvobj(rfctl)));
1034 struct txpwr_lmt_ent *ent;
1039 if (!regd_name || !nlen) {
1044 _enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1046 /* search for existed entry */
1047 head = &rfctl->txpwr_lmt_list;
1048 cur = get_next(head);
1049 while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
1050 ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
1051 cur = get_next(cur);
1053 if (strlen(ent->regd_name) == nlen
1054 && _rtw_memcmp(ent->regd_name, regd_name, nlen) == _TRUE)
1059 ent = (struct txpwr_lmt_ent *)rtw_zvmalloc(sizeof(struct txpwr_lmt_ent) + nlen + 1);
1063 _rtw_init_listhead(&ent->list);
1064 _rtw_memcpy(ent->regd_name, regd_name, nlen);
1068 for (j = 0; j < MAX_2_4G_BANDWIDTH_NUM; ++j)
1069 for (k = 0; k < TXPWR_LMT_RS_NUM_2G; ++k)
1070 for (m = 0; m < CENTER_CH_2G_NUM; ++m)
1071 for (l = 0; l < MAX_TX_COUNT; ++l)
1072 ent->lmt_2g[j][k][m][l] = hal_spec->txgi_max;
1073 #ifdef CONFIG_IEEE80211_BAND_5GHZ
1074 for (j = 0; j < MAX_5G_BANDWIDTH_NUM; ++j)
1075 for (k = 0; k < TXPWR_LMT_RS_NUM_5G; ++k)
1076 for (m = 0; m < CENTER_CH_5G_ALL_NUM; ++m)
1077 for (l = 0; l < MAX_TX_COUNT; ++l)
1078 ent->lmt_5g[j][k][m][l] = hal_spec->txgi_max;
1082 rtw_list_insert_tail(&ent->list, &rfctl->txpwr_lmt_list);
1083 rfctl->txpwr_regd_num++;
1086 if (band == BAND_ON_2_4G)
1087 pre_lmt = ent->lmt_2g[bw][tlrs][ch_idx][ntx_idx];
1088 #ifdef CONFIG_IEEE80211_BAND_5GHZ
1089 else if (band == BAND_ON_5G)
1090 pre_lmt = ent->lmt_5g[bw][tlrs - 1][ch_idx][ntx_idx];
1095 if (pre_lmt != hal_spec->txgi_max)
1096 RTW_PRINT("duplicate txpwr_lmt for [%s][%s][%s][%s][%uT][%d]\n"
1097 , regd_name, band_str(band), ch_width_str(bw), txpwr_lmt_rs_str(tlrs), ntx_idx + 1
1098 , band == BAND_ON_2_4G ? ch_idx + 1 : center_ch_5g_all[ch_idx]);
1100 lmt = rtw_min(pre_lmt, lmt);
1101 if (band == BAND_ON_2_4G)
1102 ent->lmt_2g[bw][tlrs][ch_idx][ntx_idx] = lmt;
1103 #ifdef CONFIG_IEEE80211_BAND_5GHZ
1104 else if (band == BAND_ON_5G)
1105 ent->lmt_5g[bw][tlrs - 1][ch_idx][ntx_idx] = lmt;
1109 RTW_PRINT("%s, %4s, %6s, %7s, %uT, ch%3d = %d\n"
1110 , regd_name, band_str(band), ch_width_str(bw), txpwr_lmt_rs_str(tlrs), ntx_idx + 1
1111 , band == BAND_ON_2_4G ? ch_idx + 1 : center_ch_5g_all[ch_idx]
1115 _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1121 inline void rtw_txpwr_lmt_add(struct rf_ctl_t *rfctl, const char *regd_name
1122 , u8 band, u8 bw, u8 tlrs, u8 ntx_idx, u8 ch_idx, s8 lmt)
1124 rtw_txpwr_lmt_add_with_nlen(rfctl, regd_name, strlen(regd_name)
1125 , band, bw, tlrs, ntx_idx, ch_idx, lmt);
1128 struct txpwr_lmt_ent *_rtw_txpwr_lmt_get_by_name(struct rf_ctl_t *rfctl, const char *regd_name)
1130 struct txpwr_lmt_ent *ent;
1134 head = &rfctl->txpwr_lmt_list;
1135 cur = get_next(head);
1137 while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
1138 ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
1139 cur = get_next(cur);
1141 if (strcmp(ent->regd_name, regd_name) == 0) {
1152 inline struct txpwr_lmt_ent *rtw_txpwr_lmt_get_by_name(struct rf_ctl_t *rfctl, const char *regd_name)
1154 struct txpwr_lmt_ent *ent;
1157 _enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1158 ent = _rtw_txpwr_lmt_get_by_name(rfctl, regd_name);
1159 _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1164 void rtw_txpwr_lmt_list_free(struct rf_ctl_t *rfctl)
1166 struct txpwr_lmt_ent *ent;
1170 _enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1172 head = &rfctl->txpwr_lmt_list;
1173 cur = get_next(head);
1175 while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
1176 ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);
1177 cur = get_next(cur);
1178 if (ent->regd_name == rfctl->regd_name)
1179 rfctl->regd_name = regd_str(TXPWR_LMT_NONE);
1180 rtw_list_delete(&ent->list);
1181 rtw_vmfree((u8 *)ent, sizeof(struct txpwr_lmt_ent) + strlen(ent->regd_name) + 1);
1183 rfctl->txpwr_regd_num = 0;
1185 _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
1187 #endif /* CONFIG_TXPWR_LIMIT */
1189 int rtw_ch_to_bb_gain_sel(int ch)
1193 if (ch >= 1 && ch <= 14)
1195 #ifdef CONFIG_IEEE80211_BAND_5GHZ
1196 else if (ch >= 36 && ch < 48)
1197 sel = BB_GAIN_5GLB1;
1198 else if (ch >= 52 && ch <= 64)
1199 sel = BB_GAIN_5GLB2;
1200 else if (ch >= 100 && ch <= 120)
1201 sel = BB_GAIN_5GMB1;
1202 else if (ch >= 124 && ch <= 144)
1203 sel = BB_GAIN_5GMB2;
1204 else if (ch >= 149 && ch <= 177)
1211 s8 rtw_rf_get_kfree_tx_gain_offset(_adapter *padapter, u8 path, u8 ch)
1213 s8 kfree_offset = 0;
1215 #ifdef CONFIG_RF_POWER_TRIM
1216 struct kfree_data_t *kfree_data = GET_KFREE_DATA(padapter);
1217 s8 bb_gain_sel = rtw_ch_to_bb_gain_sel(ch);
1219 if (bb_gain_sel < BB_GAIN_2G || bb_gain_sel >= BB_GAIN_NUM) {
1224 if (kfree_data->flag & KFREE_FLAG_ON) {
1225 kfree_offset = kfree_data->bb_gain[bb_gain_sel][path];
1226 if (IS_HARDWARE_TYPE_8723D(padapter))
1227 RTW_INFO("%s path:%s, ch:%u, bb_gain_sel:%d, kfree_offset:%d\n"
1228 , __func__, (path == 0)?"S1":"S0",
1229 ch, bb_gain_sel, kfree_offset);
1231 RTW_INFO("%s path:%u, ch:%u, bb_gain_sel:%d, kfree_offset:%d\n"
1232 , __func__, path, ch, bb_gain_sel, kfree_offset);
1235 #endif /* CONFIG_RF_POWER_TRIM */
1236 return kfree_offset;
1239 void rtw_rf_set_tx_gain_offset(_adapter *adapter, u8 path, s8 offset)
1241 #if !defined(CONFIG_RTL8814A) && !defined(CONFIG_RTL8822B) && !defined(CONFIG_RTL8821C)
1247 if (IS_HARDWARE_TYPE_8723D(adapter)) {
1248 target_path = RF_PATH_A; /*in 8723D case path means S0/S1*/
1249 if (path == PPG_8723D_S1)
1250 RTW_INFO("kfree gain_offset 0x55:0x%x ",
1251 rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff));
1252 else if (path == PPG_8723D_S0)
1253 RTW_INFO("kfree gain_offset 0x65:0x%x ",
1254 rtw_hal_read_rfreg(adapter, target_path, 0x65, 0xffffffff));
1257 RTW_INFO("kfree gain_offset 0x55:0x%x ", rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff));
1260 switch (rtw_get_chip_type(adapter)) {
1261 #ifdef CONFIG_RTL8723D
1263 write_value = RF_TX_GAIN_OFFSET_8723D(offset);
1264 if (path == PPG_8723D_S1)
1265 rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0f8000, write_value);
1266 else if (path == PPG_8723D_S0)
1267 rtw_hal_write_rfreg(adapter, target_path, 0x65, 0x0f8000, write_value);
1269 #endif /* CONFIG_RTL8723D */
1270 #ifdef CONFIG_RTL8703B
1272 write_value = RF_TX_GAIN_OFFSET_8703B(offset);
1273 rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0fc000, write_value);
1275 #endif /* CONFIG_RTL8703B */
1276 #ifdef CONFIG_RTL8188F
1278 write_value = RF_TX_GAIN_OFFSET_8188F(offset);
1279 rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0fc000, write_value);
1281 #endif /* CONFIG_RTL8188F */
1282 #ifdef CONFIG_RTL8188GTV
1284 write_value = RF_TX_GAIN_OFFSET_8188GTV(offset);
1285 rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0fc000, write_value);
1287 #endif /* CONFIG_RTL8188GTV */
1288 #ifdef CONFIG_RTL8192E
1290 write_value = RF_TX_GAIN_OFFSET_8192E(offset);
1291 rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0f8000, write_value);
1293 #endif /* CONFIG_RTL8188F */
1295 #ifdef CONFIG_RTL8821A
1297 write_value = RF_TX_GAIN_OFFSET_8821A(offset);
1298 rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0f8000, write_value);
1300 #endif /* CONFIG_RTL8821A */
1301 #if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) || defined(CONFIG_RTL8192F)
1306 RTW_INFO("\nkfree by PhyDM on the sw CH. path %d\n", path);
1308 #endif /* CONFIG_RTL8814A || CONFIG_RTL8822B || CONFIG_RTL8821C */
1315 if (IS_HARDWARE_TYPE_8723D(adapter)) {
1316 if (path == PPG_8723D_S1)
1317 val32 = rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff);
1318 else if (path == PPG_8723D_S0)
1319 val32 = rtw_hal_read_rfreg(adapter, target_path, 0x65, 0xffffffff);
1321 val32 = rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff);
1323 RTW_INFO(" after :0x%x\n", val32);
1326 void rtw_rf_apply_tx_gain_offset(_adapter *adapter, u8 ch)
1328 HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
1329 s8 kfree_offset = 0;
1330 s8 tx_pwr_track_offset = 0; /* TODO: 8814A should consider tx pwr track when setting tx gain offset */
1334 if (IS_HARDWARE_TYPE_8723D(adapter))
1335 total = 2; /* S1 and S0 */
1337 total = hal_data->NumTotalRFPath;
1339 for (i = 0; i < total; i++) {
1340 kfree_offset = rtw_rf_get_kfree_tx_gain_offset(adapter, i, ch);
1341 total_offset = kfree_offset + tx_pwr_track_offset;
1342 rtw_rf_set_tx_gain_offset(adapter, i, total_offset);
1346 inline u8 rtw_is_dfs_range(u32 hi, u32 lo)
1348 return rtw_is_range_overlap(hi, lo, 5720 + 10, 5260 - 10);
1351 u8 rtw_is_dfs_ch(u8 ch)
1355 if (!rtw_chbw_to_freq_range(ch, CHANNEL_WIDTH_20, HAL_PRIME_CHNL_OFFSET_DONT_CARE, &hi, &lo))
1358 return rtw_is_dfs_range(hi, lo);
1361 u8 rtw_is_dfs_chbw(u8 ch, u8 bw, u8 offset)
1365 if (!rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo))
1368 return rtw_is_dfs_range(hi, lo);
1371 bool rtw_is_long_cac_range(u32 hi, u32 lo, u8 dfs_region)
1373 return (dfs_region == PHYDM_DFS_DOMAIN_ETSI && rtw_is_range_overlap(hi, lo, 5650, 5600)) ? _TRUE : _FALSE;
1376 bool rtw_is_long_cac_ch(u8 ch, u8 bw, u8 offset, u8 dfs_region)
1380 if (rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo) == _FALSE)
1383 return rtw_is_long_cac_range(hi, lo, dfs_region) ? _TRUE : _FALSE;