| // SPDX-License-Identifier: GPL-2.0 |
| /****************************************************************************** |
| * |
| * Copyright(c) 2007 - 2016 Realtek Corporation. |
| * |
| * Contact Information: |
| * wlanfae <wlanfae@realtek.com> |
| * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, |
| * Hsinchu 300, Taiwan. |
| * |
| * Larry Finger <Larry.Finger@lwfinger.net> |
| * |
| *****************************************************************************/ |
| |
| #include "../mp_precomp.h" |
| #include "../phydm_precomp.h" |
| |
| static void phydm_dynamic_switch_htstf_mumimo_8822b(struct phy_dm_struct *dm) |
| { |
| /*if rssi > 40dBm, enable HT-STF gain controller, |
| *otherwise, if rssi < 40dBm, disable the controller |
| */ |
| /*add by Chun-Hung Ho 20160711 */ |
| if (dm->rssi_min >= 40) |
| odm_set_bb_reg(dm, 0x8d8, BIT(17), 0x1); |
| else if (dm->rssi_min < 35) |
| odm_set_bb_reg(dm, 0x8d8, BIT(17), 0x0); |
| |
| ODM_RT_TRACE(dm, ODM_COMP_COMMON, "%s, rssi_min = %d\n", __func__, |
| dm->rssi_min); |
| } |
| |
| static void _set_tx_a_cali_value(struct phy_dm_struct *dm, u8 rf_path, |
| u8 offset, u8 tx_a_bias_offset) |
| { |
| u32 modi_tx_a_value = 0; |
| u8 tmp1_byte = 0; |
| bool is_minus = false; |
| u8 comp_value = 0; |
| |
| switch (offset) { |
| case 0x0: |
| odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X10124); |
| break; |
| case 0x1: |
| odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X10524); |
| break; |
| case 0x2: |
| odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X10924); |
| break; |
| case 0x3: |
| odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X10D24); |
| break; |
| case 0x4: |
| odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X30164); |
| break; |
| case 0x5: |
| odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X30564); |
| break; |
| case 0x6: |
| odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X30964); |
| break; |
| case 0x7: |
| odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X30D64); |
| break; |
| case 0x8: |
| odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X50195); |
| break; |
| case 0x9: |
| odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X50595); |
| break; |
| case 0xa: |
| odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X50995); |
| break; |
| case 0xb: |
| odm_set_rf_reg(dm, rf_path, 0x18, 0xFFFFF, 0X50D95); |
| break; |
| default: |
| ODM_RT_TRACE(dm, ODM_COMP_COMMON, |
| "Invalid TxA band offset...\n"); |
| return; |
| } |
| |
| /* Get TxA value */ |
| modi_tx_a_value = odm_get_rf_reg(dm, rf_path, 0x61, 0xFFFFF); |
| tmp1_byte = (u8)modi_tx_a_value & (BIT(3) | BIT(2) | BIT(1) | BIT(0)); |
| |
| /* check how much need to calibration */ |
| switch (tx_a_bias_offset) { |
| case 0xF6: |
| is_minus = true; |
| comp_value = 3; |
| break; |
| |
| case 0xF4: |
| is_minus = true; |
| comp_value = 2; |
| break; |
| |
| case 0xF2: |
| is_minus = true; |
| comp_value = 1; |
| break; |
| |
| case 0xF3: |
| is_minus = false; |
| comp_value = 1; |
| break; |
| |
| case 0xF5: |
| is_minus = false; |
| comp_value = 2; |
| break; |
| |
| case 0xF7: |
| is_minus = false; |
| comp_value = 3; |
| break; |
| |
| case 0xF9: |
| is_minus = false; |
| comp_value = 4; |
| break; |
| |
| /* do nothing case */ |
| case 0xF0: |
| default: |
| ODM_RT_TRACE(dm, ODM_COMP_COMMON, |
| "No need to do TxA bias current calibration\n"); |
| return; |
| } |
| |
| /* calc correct value to calibrate */ |
| if (is_minus) { |
| if (tmp1_byte >= comp_value) { |
| tmp1_byte -= comp_value; |
| /*modi_tx_a_value += tmp1_byte;*/ |
| } else { |
| tmp1_byte = 0; |
| } |
| } else { |
| tmp1_byte += comp_value; |
| if (tmp1_byte >= 7) |
| tmp1_byte = 7; |
| } |
| |
| /* Write back to RF reg */ |
| odm_set_rf_reg(dm, rf_path, 0x30, 0xFFFF, |
| (offset << 12 | (modi_tx_a_value & 0xFF0) | tmp1_byte)); |
| } |
| |
| static void _txa_bias_cali_4_each_path(struct phy_dm_struct *dm, u8 rf_path, |
| u8 efuse_value) |
| { |
| /* switch on set TxA bias */ |
| odm_set_rf_reg(dm, rf_path, 0xEF, 0xFFFFF, 0x200); |
| |
| /* Set 12 sets of TxA value */ |
| _set_tx_a_cali_value(dm, rf_path, 0x0, efuse_value); |
| _set_tx_a_cali_value(dm, rf_path, 0x1, efuse_value); |
| _set_tx_a_cali_value(dm, rf_path, 0x2, efuse_value); |
| _set_tx_a_cali_value(dm, rf_path, 0x3, efuse_value); |
| _set_tx_a_cali_value(dm, rf_path, 0x4, efuse_value); |
| _set_tx_a_cali_value(dm, rf_path, 0x5, efuse_value); |
| _set_tx_a_cali_value(dm, rf_path, 0x6, efuse_value); |
| _set_tx_a_cali_value(dm, rf_path, 0x7, efuse_value); |
| _set_tx_a_cali_value(dm, rf_path, 0x8, efuse_value); |
| _set_tx_a_cali_value(dm, rf_path, 0x9, efuse_value); |
| _set_tx_a_cali_value(dm, rf_path, 0xa, efuse_value); |
| _set_tx_a_cali_value(dm, rf_path, 0xb, efuse_value); |
| |
| /* switch off set TxA bias */ |
| odm_set_rf_reg(dm, rf_path, 0xEF, 0xFFFFF, 0x0); |
| } |
| |
| /* |
| * for 8822B PCIE D-cut patch only |
| * Normal driver and MP driver need this patch |
| */ |
| |
| void phydm_txcurrentcalibration(struct phy_dm_struct *dm) |
| { |
| u8 efuse0x3D8, efuse0x3D7; |
| u32 orig_rf0x18_path_a = 0, orig_rf0x18_path_b = 0; |
| |
| /* save original 0x18 value */ |
| orig_rf0x18_path_a = odm_get_rf_reg(dm, ODM_RF_PATH_A, 0x18, 0xFFFFF); |
| orig_rf0x18_path_b = odm_get_rf_reg(dm, ODM_RF_PATH_B, 0x18, 0xFFFFF); |
| |
| /* define efuse content */ |
| efuse0x3D8 = dm->efuse0x3d8; |
| efuse0x3D7 = dm->efuse0x3d7; |
| |
| /* check efuse content to judge whether need to calibration or not */ |
| if (efuse0x3D7 == 0xFF) { |
| ODM_RT_TRACE( |
| dm, ODM_COMP_COMMON, |
| "efuse content 0x3D7 == 0xFF, No need to do TxA cali\n"); |
| return; |
| } |
| |
| /* write RF register for calibration */ |
| _txa_bias_cali_4_each_path(dm, ODM_RF_PATH_A, efuse0x3D7); |
| _txa_bias_cali_4_each_path(dm, ODM_RF_PATH_B, efuse0x3D8); |
| |
| /* restore original 0x18 value */ |
| odm_set_rf_reg(dm, ODM_RF_PATH_A, 0x18, 0xFFFFF, orig_rf0x18_path_a); |
| odm_set_rf_reg(dm, ODM_RF_PATH_B, 0x18, 0xFFFFF, orig_rf0x18_path_b); |
| } |
| |
| void phydm_hwsetting_8822b(struct phy_dm_struct *dm) |
| { |
| phydm_dynamic_switch_htstf_mumimo_8822b(dm); |
| } |