Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtw88: set power trim according to efuse PG values

8822C devices have power trim, thermal and PA bias values
programmed in efuse. Driver should configure the RF components
according to the values.

If the power trim is not configured, then the devices might have
distortion on the output tx power.

Signed-off-by: Tzu-En Huang <tehuang@realtek.com>
Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20200420105207.31899-1-yhchuang@realtek.com

authored by

Tzu-En Huang and committed by
Kalle Valo
5ad4d895 ab0a031e

+166
+22
drivers/net/wireless/realtek/rtw88/efuse.c
··· 2 2 /* Copyright(c) 2018-2019 Realtek Corporation 3 3 */ 4 4 5 + #include <linux/iopoll.h> 6 + 5 7 #include "main.h" 6 8 #include "efuse.h" 7 9 #include "reg.h" ··· 118 116 } 119 117 120 118 rtw_chip_efuse_grant_off(rtwdev); 119 + 120 + return 0; 121 + } 122 + 123 + int rtw_read8_physical_efuse(struct rtw_dev *rtwdev, u16 addr, u8 *data) 124 + { 125 + u32 efuse_ctl; 126 + int ret; 127 + 128 + rtw_write32_mask(rtwdev, REG_EFUSE_CTRL, 0x3ff00, addr); 129 + rtw_write32_clr(rtwdev, REG_EFUSE_CTRL, BIT_EF_FLAG); 130 + 131 + ret = read_poll_timeout(rtw_read32, efuse_ctl, efuse_ctl & BIT_EF_FLAG, 132 + 1000, 100000, false, rtwdev, REG_EFUSE_CTRL); 133 + if (ret) { 134 + *data = EFUSE_READ_FAIL; 135 + return ret; 136 + } 137 + 138 + *data = rtw_read8(rtwdev, REG_EFUSE_CTRL); 121 139 122 140 return 0; 123 141 }
+3
drivers/net/wireless/realtek/rtw88/efuse.h
··· 10 10 #define EFUSE_HW_CAP_SUPP_BW80 7 11 11 #define EFUSE_HW_CAP_SUPP_BW40 6 12 12 13 + #define EFUSE_READ_FAIL 0xff 14 + 13 15 #define GET_EFUSE_HW_CAP_HCI(hw_cap) \ 14 16 le32_get_bits(*((__le32 *)(hw_cap) + 0x01), GENMASK(3, 0)) 15 17 #define GET_EFUSE_HW_CAP_BW(hw_cap) \ ··· 24 22 le32_get_bits(*((__le32 *)(hw_cap) + 0x01), GENMASK(27, 26)) 25 23 26 24 int rtw_parse_efuse_map(struct rtw_dev *rtwdev); 25 + int rtw_read8_physical_efuse(struct rtw_dev *rtwdev, u16 addr, u8 *data); 27 26 28 27 #endif
+113
drivers/net/wireless/realtek/rtw88/rtw8822c.c
··· 15 15 #include "debug.h" 16 16 #include "util.h" 17 17 #include "bf.h" 18 + #include "efuse.h" 18 19 19 20 static void rtw8822c_config_trx_mode(struct rtw_dev *rtwdev, u8 tx_path, 20 21 u8 rx_path, bool is_tx2_path); ··· 1001 1000 } 1002 1001 } 1003 1002 1003 + static void rtw8822c_set_power_trim(struct rtw_dev *rtwdev, s8 bb_gain[2][8]) 1004 + { 1005 + #define RF_SET_POWER_TRIM(_path, _seq, _idx) \ 1006 + do { \ 1007 + rtw_write_rf(rtwdev, _path, 0x33, RFREG_MASK, _seq); \ 1008 + rtw_write_rf(rtwdev, _path, 0x3f, RFREG_MASK, \ 1009 + bb_gain[_path][_idx]); \ 1010 + } while (0) 1011 + u8 path; 1012 + 1013 + for (path = 0; path < rtwdev->hal.rf_path_num; path++) { 1014 + rtw_write_rf(rtwdev, path, 0xee, BIT(19), 1); 1015 + RF_SET_POWER_TRIM(path, 0x0, 0); 1016 + RF_SET_POWER_TRIM(path, 0x1, 1); 1017 + RF_SET_POWER_TRIM(path, 0x2, 2); 1018 + RF_SET_POWER_TRIM(path, 0x3, 2); 1019 + RF_SET_POWER_TRIM(path, 0x4, 3); 1020 + RF_SET_POWER_TRIM(path, 0x5, 4); 1021 + RF_SET_POWER_TRIM(path, 0x6, 5); 1022 + RF_SET_POWER_TRIM(path, 0x7, 6); 1023 + RF_SET_POWER_TRIM(path, 0x8, 7); 1024 + RF_SET_POWER_TRIM(path, 0x9, 3); 1025 + RF_SET_POWER_TRIM(path, 0xa, 4); 1026 + RF_SET_POWER_TRIM(path, 0xb, 5); 1027 + RF_SET_POWER_TRIM(path, 0xc, 6); 1028 + RF_SET_POWER_TRIM(path, 0xd, 7); 1029 + RF_SET_POWER_TRIM(path, 0xe, 7); 1030 + rtw_write_rf(rtwdev, path, 0xee, BIT(19), 0); 1031 + } 1032 + #undef RF_SET_POWER_TRIM 1033 + } 1034 + 1035 + static void rtw8822c_power_trim(struct rtw_dev *rtwdev) 1036 + { 1037 + u8 pg_pwr = 0xff, i, path, idx; 1038 + s8 bb_gain[2][8] = {0}; 1039 + u16 rf_efuse_2g[3] = {PPG_2GL_TXAB, PPG_2GM_TXAB, PPG_2GH_TXAB}; 1040 + u16 rf_efuse_5g[2][5] = {{PPG_5GL1_TXA, PPG_5GL2_TXA, PPG_5GM1_TXA, 1041 + PPG_5GM2_TXA, PPG_5GH1_TXA}, 1042 + {PPG_5GL1_TXB, PPG_5GL2_TXB, PPG_5GM1_TXB, 1043 + PPG_5GM2_TXB, PPG_5GH1_TXB} }; 1044 + bool set = false; 1045 + 1046 + for (i = 0; i < ARRAY_SIZE(rf_efuse_2g); i++) { 1047 + rtw_read8_physical_efuse(rtwdev, rf_efuse_2g[i], &pg_pwr); 1048 + if (pg_pwr == EFUSE_READ_FAIL) 1049 + continue; 1050 + set = true; 1051 + bb_gain[RF_PATH_A][i] = FIELD_GET(PPG_2G_A_MASK, pg_pwr); 1052 + bb_gain[RF_PATH_B][i] = FIELD_GET(PPG_2G_B_MASK, pg_pwr); 1053 + } 1054 + 1055 + for (i = 0; i < ARRAY_SIZE(rf_efuse_5g[0]); i++) { 1056 + for (path = 0; path < rtwdev->hal.rf_path_num; path++) { 1057 + rtw_read8_physical_efuse(rtwdev, rf_efuse_5g[path][i], 1058 + &pg_pwr); 1059 + if (pg_pwr == EFUSE_READ_FAIL) 1060 + continue; 1061 + set = true; 1062 + idx = i + ARRAY_SIZE(rf_efuse_2g); 1063 + bb_gain[path][idx] = FIELD_GET(PPG_5G_MASK, pg_pwr); 1064 + } 1065 + } 1066 + if (set) 1067 + rtw8822c_set_power_trim(rtwdev, bb_gain); 1068 + 1069 + rtw_write32_mask(rtwdev, REG_DIS_DPD, DIS_DPD_MASK, DIS_DPD_RATEALL); 1070 + } 1071 + 1072 + static void rtw8822c_thermal_trim(struct rtw_dev *rtwdev) 1073 + { 1074 + u16 rf_efuse[2] = {PPG_THERMAL_A, PPG_THERMAL_B}; 1075 + u8 pg_therm = 0xff, thermal[2] = {0}, path; 1076 + 1077 + for (path = 0; path < rtwdev->hal.rf_path_num; path++) { 1078 + rtw_read8_physical_efuse(rtwdev, rf_efuse[path], &pg_therm); 1079 + if (pg_therm == EFUSE_READ_FAIL) 1080 + return; 1081 + /* Efuse value of BIT(0) shall be move to BIT(3), and the value 1082 + * of BIT(1) to BIT(3) should be right shifted 1 bit. 1083 + */ 1084 + thermal[path] = FIELD_GET(GENMASK(3, 1), pg_therm); 1085 + thermal[path] |= FIELD_PREP(BIT(3), pg_therm & BIT(0)); 1086 + rtw_write_rf(rtwdev, path, 0x43, RF_THEMAL_MASK, thermal[path]); 1087 + } 1088 + } 1089 + 1090 + static void rtw8822c_pa_bias(struct rtw_dev *rtwdev) 1091 + { 1092 + u16 rf_efuse_2g[2] = {PPG_PABIAS_2GA, PPG_PABIAS_2GB}; 1093 + u16 rf_efuse_5g[2] = {PPG_PABIAS_5GA, PPG_PABIAS_5GB}; 1094 + u8 pg_pa_bias = 0xff, path; 1095 + 1096 + for (path = 0; path < rtwdev->hal.rf_path_num; path++) { 1097 + rtw_read8_physical_efuse(rtwdev, rf_efuse_2g[path], 1098 + &pg_pa_bias); 1099 + if (pg_pa_bias == EFUSE_READ_FAIL) 1100 + return; 1101 + pg_pa_bias = FIELD_GET(PPG_PABIAS_MASK, pg_pa_bias); 1102 + rtw_write_rf(rtwdev, path, 0x60, RF_PABIAS_2G_MASK, pg_pa_bias); 1103 + } 1104 + for (path = 0; path < rtwdev->hal.rf_path_num; path++) { 1105 + rtw_read8_physical_efuse(rtwdev, rf_efuse_5g[path], 1106 + &pg_pa_bias); 1107 + pg_pa_bias = FIELD_GET(PPG_PABIAS_MASK, pg_pa_bias); 1108 + rtw_write_rf(rtwdev, path, 0x60, RF_PABIAS_5G_MASK, pg_pa_bias); 1109 + } 1110 + } 1111 + 1004 1112 static void rtw8822c_rf_init(struct rtw_dev *rtwdev) 1005 1113 { 1006 1114 rtw8822c_rf_dac_cal(rtwdev); 1007 1115 rtw8822c_rf_x2_check(rtwdev); 1116 + rtw8822c_thermal_trim(rtwdev); 1117 + rtw8822c_power_trim(rtwdev); 1118 + rtw8822c_pa_bias(rtwdev); 1008 1119 } 1009 1120 1010 1121 static void rtw8822c_pwrtrack_init(struct rtw_dev *rtwdev)
+28
drivers/net/wireless/realtek/rtw88/rtw8822c.h
··· 309 309 #define BIT_GS_PWSF GENMASK(27, 0) 310 310 #define BIT_RPT_DGAIN GENMASK(27, 16) 311 311 #define BIT_TX_CFIR GENMASK(31, 30) 312 + 313 + #define PPG_THERMAL_A 0x1ef 314 + #define PPG_THERMAL_B 0x1b0 315 + #define RF_THEMAL_MASK GENMASK(19, 16) 316 + #define PPG_2GL_TXAB 0x1d4 317 + #define PPG_2GM_TXAB 0x1ee 318 + #define PPG_2GH_TXAB 0x1d2 319 + #define PPG_2G_A_MASK GENMASK(3, 0) 320 + #define PPG_2G_B_MASK GENMASK(7, 4) 321 + #define PPG_5GL1_TXA 0x1ec 322 + #define PPG_5GL2_TXA 0x1e8 323 + #define PPG_5GM1_TXA 0x1e4 324 + #define PPG_5GM2_TXA 0x1e0 325 + #define PPG_5GH1_TXA 0x1dc 326 + #define PPG_5GL1_TXB 0x1eb 327 + #define PPG_5GL2_TXB 0x1e7 328 + #define PPG_5GM1_TXB 0x1e3 329 + #define PPG_5GM2_TXB 0x1df 330 + #define PPG_5GH1_TXB 0x1db 331 + #define PPG_5G_MASK GENMASK(4, 0) 332 + #define PPG_PABIAS_2GA 0x1d6 333 + #define PPG_PABIAS_2GB 0x1d5 334 + #define PPG_PABIAS_5GA 0x1d8 335 + #define PPG_PABIAS_5GB 0x1d7 336 + #define PPG_PABIAS_MASK GENMASK(3, 0) 337 + #define RF_PABIAS_2G_MASK GENMASK(15, 12) 338 + #define RF_PABIAS_5G_MASK GENMASK(19, 16) 339 + 312 340 #endif