/****************************************************************************** * * Copyright(c) 2007 - 2017 Realtek Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * * Contact Information: * wlanfae * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, * Hsinchu 300, Taiwan. * * Larry Finger * *****************************************************************************/ /*@************************************************************ * include files ************************************************************/ #include "mp_precomp.h" #include "phydm_precomp.h" #ifdef PHYDM_SUPPORT_CCKPD #ifdef PHYDM_COMPILE_CCKPD_TYPE1 void phydm_write_cck_pd_type1(void *dm_void, u8 cca_th) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; PHYDM_DBG(dm, DBG_CCKPD, "[%s] cck_cca_th=((0x%x))\n", __func__, cca_th); odm_write_1byte(dm, R_0xa0a, cca_th); cckpd_t->cur_cck_cca_thres = cca_th; } void phydm_set_cckpd_lv_type1(void *dm_void, enum cckpd_lv lv) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; u8 pd_th = 0; PHYDM_DBG(dm, DBG_CCKPD, "%s ======>\n", __func__); PHYDM_DBG(dm, DBG_CCKPD, "lv: (%d) -> (%d)\n", cckpd_t->cck_pd_lv, lv); if (cckpd_t->cck_pd_lv == lv) { PHYDM_DBG(dm, DBG_CCKPD, "stay in lv=%d\n", lv); return; } cckpd_t->cck_pd_lv = lv; cckpd_t->cck_fa_ma = CCK_FA_MA_RESET; if (lv == CCK_PD_LV_4) pd_th = 0xed; else if (lv == CCK_PD_LV_3) pd_th = 0xdd; else if (lv == CCK_PD_LV_2) pd_th = 0xcd; else if (lv == CCK_PD_LV_1) pd_th = 0x83; else if (lv == CCK_PD_LV_0) pd_th = 0x40; phydm_write_cck_pd_type1(dm, pd_th); } void phydm_cckpd_type1(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_dig_struct *dig_t = &dm->dm_dig_table; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; enum cckpd_lv lv = CCK_PD_LV_INIT; boolean is_update = true; if (dm->is_linked) { #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) if (dm->rssi_min > 60) { lv = CCK_PD_LV_3; } else if (dm->rssi_min > 35) { lv = CCK_PD_LV_2; } else if (dm->rssi_min > 20) { if (cckpd_t->cck_fa_ma > 500) lv = CCK_PD_LV_2; else if (cckpd_t->cck_fa_ma < 250) lv = CCK_PD_LV_1; else is_update = false; } else { /*RSSI < 20*/ lv = CCK_PD_LV_1; } #else /*ODM_AP*/ if (dig_t->cur_ig_value > 0x32) lv = CCK_PD_LV_4; else if (dig_t->cur_ig_value > 0x2a) lv = CCK_PD_LV_3; else if (dig_t->cur_ig_value > 0x24) lv = CCK_PD_LV_2; else lv = CCK_PD_LV_1; #endif } else { if (cckpd_t->cck_fa_ma > 1000) lv = CCK_PD_LV_1; else if (cckpd_t->cck_fa_ma < 500) lv = CCK_PD_LV_0; else is_update = false; } /*[Abnormal case] =================================================*/ #if (DM_ODM_SUPPORT_TYPE & ODM_WIN) /*@HP 22B LPS power consumption issue & [PCIE-1596]*/ if (dm->hp_hw_id && dm->traffic_load == TRAFFIC_ULTRA_LOW) { lv = CCK_PD_LV_0; PHYDM_DBG(dm, DBG_CCKPD, "CCKPD Abnormal case1\n"); } else if ((dm->p_advance_ota & PHYDM_ASUS_OTA_SETTING) && cckpd_t->cck_fa_ma > 200 && dm->rssi_min <= 20) { lv = CCK_PD_LV_1; cckpd_t->cck_pd_lv = lv; phydm_write_cck_pd_type1(dm, 0xc3); /*@for ASUS OTA test*/ is_update = false; PHYDM_DBG(dm, DBG_CCKPD, "CCKPD Abnormal case2\n"); } #elif (DM_ODM_SUPPORT_TYPE & (ODM_AP)) #ifdef MCR_WIRELESS_EXTEND lv = CCK_PD_LV_2; cckpd_t->cck_pd_lv = lv; phydm_write_cck_pd_type1(dm, 0x43); is_update = false; PHYDM_DBG(dm, DBG_CCKPD, "CCKPD Abnormal case3\n"); #endif #endif /*=================================================================*/ if (is_update) phydm_set_cckpd_lv_type1(dm, lv); PHYDM_DBG(dm, DBG_CCKPD, "is_linked=%d, lv=%d, pd_th=0x%x\n\n", dm->is_linked, cckpd_t->cck_pd_lv, cckpd_t->cur_cck_cca_thres); } #endif /*#ifdef PHYDM_COMPILE_CCKPD_TYPE1*/ #ifdef PHYDM_COMPILE_CCKPD_TYPE2 void phydm_write_cck_pd_type2(void *dm_void, u8 cca_th, u8 cca_th_aaa) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; PHYDM_DBG(dm, DBG_CCKPD, "[%s] pd_th=0x%x, cs_ratio=0x%x\n", __func__, cca_th, cca_th_aaa); odm_set_bb_reg(dm, R_0xa08, 0x3f0000, cca_th); odm_set_bb_reg(dm, R_0xaa8, 0x1f0000, cca_th_aaa); cckpd_t->cur_cck_cca_thres = cca_th; cckpd_t->cck_cca_th_aaa = cca_th_aaa; } void phydm_set_cckpd_lv_type2(void *dm_void, enum cckpd_lv lv) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; u8 pd_th = 0, cs_ratio = 0, cs_2r_offset = 0; u8 cck_n_rx = 1; PHYDM_DBG(dm, DBG_CCKPD, "%s ======>\n", __func__); PHYDM_DBG(dm, DBG_CCKPD, "lv: (%d) -> (%d)\n", cckpd_t->cck_pd_lv, lv); /*@r_mrx & r_cca_mrc*/ cck_n_rx = (odm_get_bb_reg(dm, R_0xa2c, BIT(18)) && odm_get_bb_reg(dm, R_0xa2c, BIT(22))) ? 2 : 1; if (cckpd_t->cck_pd_lv == lv && cckpd_t->cck_n_rx == cck_n_rx) { PHYDM_DBG(dm, DBG_CCKPD, "stay in lv=%d\n", lv); return; } cckpd_t->cck_n_rx = cck_n_rx; cckpd_t->cck_pd_lv = lv; cckpd_t->cck_fa_ma = CCK_FA_MA_RESET; if (lv == CCK_PD_LV_4) { cs_ratio = cckpd_t->aaa_default + 8; cs_2r_offset = 5; pd_th = 0xd; } else if (lv == CCK_PD_LV_3) { cs_ratio = cckpd_t->aaa_default + 6; cs_2r_offset = 4; pd_th = 0xd; } else if (lv == CCK_PD_LV_2) { cs_ratio = cckpd_t->aaa_default + 4; cs_2r_offset = 3; pd_th = 0xd; } else if (lv == CCK_PD_LV_1) { cs_ratio = cckpd_t->aaa_default + 2; cs_2r_offset = 1; pd_th = 0x7; } else if (lv == CCK_PD_LV_0) { cs_ratio = cckpd_t->aaa_default; cs_2r_offset = 0; pd_th = 0x3; } if (cckpd_t->cck_n_rx == 2) { if (cs_ratio >= cs_2r_offset) cs_ratio = cs_ratio - cs_2r_offset; else cs_ratio = 0; } phydm_write_cck_pd_type2(dm, pd_th, cs_ratio); } void phydm_cckpd_type2(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_dig_struct *dig_t = &dm->dm_dig_table; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; enum cckpd_lv lv = CCK_PD_LV_INIT; u8 igi = dig_t->cur_ig_value; u8 rssi_min = dm->rssi_min; boolean is_update = true; PHYDM_DBG(dm, DBG_CCKPD, "%s ======>\n", __func__); if (dm->is_linked) { if (igi > 0x38 && rssi_min > 32) { lv = CCK_PD_LV_4; } else if (igi > 0x2a && rssi_min > 32) { lv = CCK_PD_LV_3; } else if (igi > 0x24 || (rssi_min > 24 && rssi_min <= 30)) { lv = CCK_PD_LV_2; } else if (igi <= 0x24 || rssi_min < 22) { if (cckpd_t->cck_fa_ma > 1000) { lv = CCK_PD_LV_1; } else if (cckpd_t->cck_fa_ma < 500) { lv = CCK_PD_LV_0; } else { is_update = false; } } else { is_update = false; } } else { if (cckpd_t->cck_fa_ma > 1000) { lv = CCK_PD_LV_1; } else if (cckpd_t->cck_fa_ma < 500) { lv = CCK_PD_LV_0; } else { is_update = false; } } /*[Abnormal case] =================================================*/ #if (DM_ODM_SUPPORT_TYPE & ODM_WIN) /*@21C Miracast lag issue & [PCIE-3298]*/ if (dm->support_ic_type & ODM_RTL8821C && rssi_min > 60) { lv = CCK_PD_LV_4; cckpd_t->cck_pd_lv = lv; phydm_write_cck_pd_type2(dm, 0x1d, (cckpd_t->aaa_default + 8)); is_update = false; PHYDM_DBG(dm, DBG_CCKPD, "CCKPD Abnormal case1\n"); } #endif /*=================================================================*/ if (is_update) { phydm_set_cckpd_lv_type2(dm, lv); } PHYDM_DBG(dm, DBG_CCKPD, "is_linked=%d, lv=%d, n_rx=%d, cs_ratio=0x%x, pd_th=0x%x\n\n", dm->is_linked, cckpd_t->cck_pd_lv, cckpd_t->cck_n_rx, cckpd_t->cck_cca_th_aaa, cckpd_t->cur_cck_cca_thres); } #endif /*#ifdef PHYDM_COMPILE_CCKPD_TYPE2*/ #ifdef PHYDM_COMPILE_CCKPD_TYPE3 void phydm_write_cck_pd_type3(void *dm_void, u8 pd_th, u8 cs_ratio, enum cckpd_mode mode) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; PHYDM_DBG(dm, DBG_CCKPD, "[%s] mode=%d, pd_th=0x%x, cs_ratio=0x%x\n", __func__, mode, pd_th, cs_ratio); switch (mode) { case CCK_BW20_1R: /*RFBW20_1R*/ { cckpd_t->cur_cck_pd_20m_1r = pd_th; cckpd_t->cur_cck_cs_ratio_20m_1r = cs_ratio; odm_set_bb_reg(dm, R_0xac8, 0xff, pd_th); odm_set_bb_reg(dm, R_0xad0, 0x1f, cs_ratio); } break; case CCK_BW20_2R: /*RFBW20_2R*/ { cckpd_t->cur_cck_pd_20m_2r = pd_th; cckpd_t->cur_cck_cs_ratio_20m_2r = cs_ratio; odm_set_bb_reg(dm, R_0xac8, 0xff00, pd_th); odm_set_bb_reg(dm, R_0xad0, 0x3e0, cs_ratio); } break; case CCK_BW40_1R: /*RFBW40_1R*/ { cckpd_t->cur_cck_pd_40m_1r = pd_th; cckpd_t->cur_cck_cs_ratio_40m_1r = cs_ratio; odm_set_bb_reg(dm, R_0xacc, 0xff, pd_th); odm_set_bb_reg(dm, R_0xad0, 0x1f00000, cs_ratio); } break; case CCK_BW40_2R: /*RFBW40_2R*/ { cckpd_t->cur_cck_pd_40m_2r = pd_th; cckpd_t->cur_cck_cs_ratio_40m_2r = cs_ratio; odm_set_bb_reg(dm, R_0xacc, 0xff00, pd_th); odm_set_bb_reg(dm, R_0xad0, 0x3e000000, cs_ratio); } break; default: /*@pr_debug("[%s] warning!\n", __func__);*/ break; } } void phydm_set_cckpd_lv_type3(void *dm_void, enum cckpd_lv lv) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; enum cckpd_mode cck_mode = CCK_BW20_2R; enum channel_width cck_bw = CHANNEL_WIDTH_20; u8 cck_n_rx = 1; u8 pd_th; u8 cs_ratio; PHYDM_DBG(dm, DBG_CCKPD, "%s ======>\n", __func__); PHYDM_DBG(dm, DBG_CCKPD, "lv: (%d) -> (%d)\n", cckpd_t->cck_pd_lv, lv); /*[Check Nrx]*/ cck_n_rx = (odm_get_bb_reg(dm, R_0xa2c, BIT(17))) ? 2 : 1; /*[Check BW]*/ if (odm_get_bb_reg(dm, R_0x800, BIT(0))) cck_bw = CHANNEL_WIDTH_40; else cck_bw = CHANNEL_WIDTH_20; /*[Check LV]*/ if (cckpd_t->cck_pd_lv == lv && cckpd_t->cck_n_rx == cck_n_rx && cckpd_t->cck_bw == cck_bw) { PHYDM_DBG(dm, DBG_CCKPD, "stay in lv=%d\n", lv); return; } cckpd_t->cck_bw = cck_bw; cckpd_t->cck_n_rx = cck_n_rx; cckpd_t->cck_pd_lv = lv; cckpd_t->cck_fa_ma = CCK_FA_MA_RESET; if (cck_n_rx == 2) { if (cck_bw == CHANNEL_WIDTH_20) { pd_th = cckpd_t->cck_pd_20m_2r; cs_ratio = cckpd_t->cck_cs_ratio_20m_2r; cck_mode = CCK_BW20_2R; } else { pd_th = cckpd_t->cck_pd_40m_2r; cs_ratio = cckpd_t->cck_cs_ratio_40m_2r; cck_mode = CCK_BW40_2R; } } else { if (cck_bw == CHANNEL_WIDTH_20) { pd_th = cckpd_t->cck_pd_20m_1r; cs_ratio = cckpd_t->cck_cs_ratio_20m_1r; cck_mode = CCK_BW20_1R; } else { pd_th = cckpd_t->cck_pd_40m_1r; cs_ratio = cckpd_t->cck_cs_ratio_40m_1r; cck_mode = CCK_BW40_1R; } } if (lv == CCK_PD_LV_4) { if (cck_n_rx == 2) { pd_th += 4; cs_ratio += 2; } else { pd_th += 4; cs_ratio += 3; } } else if (lv == CCK_PD_LV_3) { if (cck_n_rx == 2) { pd_th += 3; cs_ratio += 1; } else { pd_th += 3; cs_ratio += 2; } } else if (lv == CCK_PD_LV_2) { pd_th += 2; cs_ratio += 1; } else if (lv == CCK_PD_LV_1) { pd_th += 1; cs_ratio += 1; } #if 0 else if (lv == CCK_PD_LV_0) { pd_th += 0; cs_ratio += 0; } #endif phydm_write_cck_pd_type3(dm, pd_th, cs_ratio, cck_mode); } void phydm_cckpd_type3(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; enum cckpd_lv lv = CCK_PD_LV_INIT; u8 igi = dm->dm_dig_table.cur_ig_value; boolean is_update = true; u8 pd_th = 0; u8 cs_ratio = 0; PHYDM_DBG(dm, DBG_CCKPD, "%s ======>\n", __func__); if (dm->is_linked) { if (igi > 0x38 && dm->rssi_min > 32) { lv = CCK_PD_LV_4; } else if ((igi > 0x2a) && (dm->rssi_min > 32)) { lv = CCK_PD_LV_3; } else if ((igi > 0x24) || (dm->rssi_min > 24 && dm->rssi_min <= 30)) { lv = CCK_PD_LV_2; } else if ((igi <= 0x24) || (dm->rssi_min < 22)) { if (cckpd_t->cck_fa_ma > 1000) lv = CCK_PD_LV_1; else if (cckpd_t->cck_fa_ma < 500) lv = CCK_PD_LV_0; else is_update = false; } } else { if (cckpd_t->cck_fa_ma > 1000) lv = CCK_PD_LV_1; else if (cckpd_t->cck_fa_ma < 500) lv = CCK_PD_LV_0; else is_update = false; } if (is_update) phydm_set_cckpd_lv_type3(dm, lv); if (cckpd_t->cck_n_rx == 2) { if (cckpd_t->cck_bw == CHANNEL_WIDTH_20) { pd_th = cckpd_t->cur_cck_pd_20m_2r; cs_ratio = cckpd_t->cur_cck_cs_ratio_20m_2r; } else { pd_th = cckpd_t->cur_cck_pd_40m_2r; cs_ratio = cckpd_t->cur_cck_cs_ratio_40m_2r; } } else { if (cckpd_t->cck_bw == CHANNEL_WIDTH_20) { pd_th = cckpd_t->cur_cck_pd_20m_1r; cs_ratio = cckpd_t->cur_cck_cs_ratio_20m_1r; } else { pd_th = cckpd_t->cur_cck_pd_40m_1r; cs_ratio = cckpd_t->cur_cck_cs_ratio_40m_1r; } } PHYDM_DBG(dm, DBG_CCKPD, "[%dR][%dM] is_linked=%d, lv=%d, cs_ratio=0x%x, pd_th=0x%x\n\n", cckpd_t->cck_n_rx, 20 << cckpd_t->cck_bw, dm->is_linked, cckpd_t->cck_pd_lv, cs_ratio, pd_th); } void phydm_cck_pd_init_type3(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; u32 reg_tmp = 0; /*Get Default value*/ cckpd_t->cck_pd_20m_1r = (u8)odm_get_bb_reg(dm, R_0xac8, 0xff); cckpd_t->cck_pd_20m_2r = (u8)odm_get_bb_reg(dm, R_0xac8, 0xff00); cckpd_t->cck_pd_40m_1r = (u8)odm_get_bb_reg(dm, R_0xacc, 0xff); cckpd_t->cck_pd_40m_2r = (u8)odm_get_bb_reg(dm, R_0xacc, 0xff00); reg_tmp = odm_get_bb_reg(dm, R_0xad0, MASKDWORD); cckpd_t->cck_cs_ratio_20m_1r = (u8)(reg_tmp & 0x1f); cckpd_t->cck_cs_ratio_20m_2r = (u8)((reg_tmp & 0x3e0) >> 5); cckpd_t->cck_cs_ratio_40m_1r = (u8)((reg_tmp & 0x1f00000) >> 20); cckpd_t->cck_cs_ratio_40m_2r = (u8)((reg_tmp & 0x3e000000) >> 25); } #endif /*#ifdef PHYDM_COMPILE_CCKPD_TYPE3*/ #ifdef PHYDM_COMPILE_CCKPD_TYPE4 void phydm_write_cck_pd_type4(void *dm_void, enum cckpd_lv lv, enum cckpd_mode mode) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; u32 val = 0; PHYDM_DBG(dm, DBG_CCKPD, "write CCK CCA parameters(CS_ratio & PD)\n"); switch (mode) { case CCK_BW20_1R: /*RFBW20_1R*/ { val = cckpd_t->cck_pd_table_jgr3[0][0][0][lv]; odm_set_bb_reg(dm, R_0x1ac8, 0xff, val); val = cckpd_t->cck_pd_table_jgr3[0][0][1][lv]; odm_set_bb_reg(dm, R_0x1ad0, 0x1f, val); } break; case CCK_BW40_1R: /*RFBW40_1R*/ { val = cckpd_t->cck_pd_table_jgr3[1][0][0][lv]; odm_set_bb_reg(dm, R_0x1acc, 0xff, val); val = cckpd_t->cck_pd_table_jgr3[1][0][1][lv]; odm_set_bb_reg(dm, R_0x1ad0, 0x01F00000, val); } break; #if (defined(PHYDM_COMPILE_ABOVE_2SS)) case CCK_BW20_2R: /*RFBW20_2R*/ { val = cckpd_t->cck_pd_table_jgr3[0][1][0][lv]; odm_set_bb_reg(dm, R_0x1ac8, 0xff00, val); val = cckpd_t->cck_pd_table_jgr3[0][1][1][lv]; odm_set_bb_reg(dm, R_0x1ad0, 0x3e0, val); } break; case CCK_BW40_2R: /*RFBW40_2R*/ { val = cckpd_t->cck_pd_table_jgr3[1][1][0][lv]; odm_set_bb_reg(dm, R_0x1acc, 0xff00, val); val = cckpd_t->cck_pd_table_jgr3[1][1][1][lv]; odm_set_bb_reg(dm, R_0x1ad0, 0x3E000000, val); } break; #endif #if (defined(PHYDM_COMPILE_ABOVE_3SS)) case CCK_BW20_3R: /*RFBW20_3R*/ { val = cckpd_t->cck_pd_table_jgr3[0][2][0][lv]; odm_set_bb_reg(dm, R_0x1ac8, 0xff0000, val); val = cckpd_t->cck_pd_table_jgr3[0][2][1][lv]; odm_set_bb_reg(dm, R_0x1ad0, 0x7c00, val); } break; case CCK_BW40_3R: /*RFBW40_3R*/ { val = cckpd_t->cck_pd_table_jgr3[1][2][0][lv]; odm_set_bb_reg(dm, R_0x1acc, 0xff0000, val); val = cckpd_t->cck_pd_table_jgr3[1][2][1][lv] & 0x3; odm_set_bb_reg(dm, R_0x1ad0, 0xC0000000, val); val = (cckpd_t->cck_pd_table_jgr3[1][2][1][lv] & 0x1c) >> 2; odm_set_bb_reg(dm, R_0x1ad4, 0x7, val); } break; #endif #if (defined(PHYDM_COMPILE_ABOVE_4SS)) case CCK_BW20_4R: /*RFBW20_4R*/ { val = cckpd_t->cck_pd_table_jgr3[0][3][0][lv]; odm_set_bb_reg(dm, R_0x1ac8, 0xff000000, val); val = cckpd_t->cck_pd_table_jgr3[0][3][1][lv]; odm_set_bb_reg(dm, R_0x1ad0, 0xF8000, val); } break; case CCK_BW40_4R: /*RFBW40_4R*/ { val = cckpd_t->cck_pd_table_jgr3[1][3][0][lv]; odm_set_bb_reg(dm, R_0x1acc, 0xff000000, val); val = cckpd_t->cck_pd_table_jgr3[1][3][1][lv]; odm_set_bb_reg(dm, R_0x1ad4, 0xf8, val); } break; #endif default: /*@pr_debug("[%s] warning!\n", __func__);*/ break; } } void phydm_set_cck_pd_lv_type4(void *dm_void, enum cckpd_lv lv) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; enum cckpd_mode cck_mode = CCK_BW20_2R; enum channel_width cck_bw = CHANNEL_WIDTH_20; u8 cck_n_rx = 0; u32 val = 0; /*u32 val_dbg = 0;*/ PHYDM_DBG(dm, DBG_CCKPD, "%s ======>\n", __func__); PHYDM_DBG(dm, DBG_CCKPD, "lv: (%d) -> (%d)\n", cckpd_t->cck_pd_lv, lv); /*[Check Nrx]*/ cck_n_rx = (u8)odm_get_bb_reg(dm, R_0x1a2c, 0x60000) + 1; /*[Check BW]*/ val = odm_get_bb_reg(dm, R_0x9b0, 0xc); if (val == 0) cck_bw = CHANNEL_WIDTH_20; else if (val == 1) cck_bw = CHANNEL_WIDTH_40; else cck_bw = CHANNEL_WIDTH_80; /*[Check LV]*/ if (cckpd_t->cck_pd_lv == lv && cckpd_t->cck_n_rx == cck_n_rx && cckpd_t->cck_bw == cck_bw) { PHYDM_DBG(dm, DBG_CCKPD, "stay in lv=%d\n", lv); return; } cckpd_t->cck_bw = cck_bw; cckpd_t->cck_n_rx = cck_n_rx; cckpd_t->cck_pd_lv = lv; cckpd_t->cck_fa_ma = CCK_FA_MA_RESET; switch (cck_n_rx) { case 1: /*1R*/ { if (cck_bw == CHANNEL_WIDTH_20) cck_mode = CCK_BW20_1R; else if (cck_bw == CHANNEL_WIDTH_40) cck_mode = CCK_BW40_1R; } break; #if (defined(PHYDM_COMPILE_ABOVE_2SS)) case 2: /*2R*/ { if (cck_bw == CHANNEL_WIDTH_20) cck_mode = CCK_BW20_2R; else if (cck_bw == CHANNEL_WIDTH_40) cck_mode = CCK_BW40_2R; } break; #endif #if (defined(PHYDM_COMPILE_ABOVE_3SS)) case 3: /*3R*/ { if (cck_bw == CHANNEL_WIDTH_20) cck_mode = CCK_BW20_3R; else if (cck_bw == CHANNEL_WIDTH_40) cck_mode = CCK_BW40_3R; } break; #endif #if (defined(PHYDM_COMPILE_ABOVE_4SS)) case 4: /*4R*/ { if (cck_bw == CHANNEL_WIDTH_20) cck_mode = CCK_BW20_4R; else if (cck_bw == CHANNEL_WIDTH_40) cck_mode = CCK_BW40_4R; } break; #endif default: /*@pr_debug("[%s] warning!\n", __func__);*/ break; } phydm_write_cck_pd_type4(dm, lv, cck_mode); } void phydm_read_cckpd_para_type4(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; u8 bw = 0; /*r_RX_RF_BW*/ u8 n_rx = 0; u8 curr_cck_pd_t[2][4][2]; u32 reg0 = 0; u32 reg1 = 0; u32 reg2 = 0; u32 reg3 = 0; bw = (u8)odm_get_bb_reg(dm, R_0x9b0, 0xc); n_rx = (u8)odm_get_bb_reg(dm, R_0x1a2c, 0x60000) + 1; reg0 = odm_get_bb_reg(dm, R_0x1ac8, MASKDWORD); reg1 = odm_get_bb_reg(dm, R_0x1acc, MASKDWORD); reg2 = odm_get_bb_reg(dm, R_0x1ad0, MASKDWORD); reg3 = odm_get_bb_reg(dm, R_0x1ad4, MASKDWORD); curr_cck_pd_t[0][0][0] = (u8)(reg0 & 0x000000ff); curr_cck_pd_t[1][0][0] = (u8)(reg1 & 0x000000ff); curr_cck_pd_t[0][0][1] = (u8)(reg2 & 0x0000001f); curr_cck_pd_t[1][0][1] = (u8)((reg2 & 0x01f00000) >> 20); #if (defined(PHYDM_COMPILE_ABOVE_2SS)) if (dm->support_ic_type & PHYDM_IC_ABOVE_2SS) { curr_cck_pd_t[0][1][0] = (u8)((reg0 & 0x0000ff00) >> 8); curr_cck_pd_t[1][1][0] = (u8)((reg1 & 0x0000ff00) >> 8); curr_cck_pd_t[0][1][1] = (u8)((reg2 & 0x000003E0) >> 5); curr_cck_pd_t[1][1][1] = (u8)((reg2 & 0x3E000000) >> 25); } #endif #if (defined(PHYDM_COMPILE_ABOVE_3SS)) if (dm->support_ic_type & PHYDM_IC_ABOVE_3SS) { curr_cck_pd_t[0][2][0] = (u8)((reg0 & 0x00ff0000) >> 16); curr_cck_pd_t[1][2][0] = (u8)((reg1 & 0x00ff0000) >> 16); curr_cck_pd_t[0][2][1] = (u8)((reg2 & 0x00007C00) >> 10); curr_cck_pd_t[1][2][1] = (u8)((reg2 & 0xC0000000) >> 30) | (u8)((reg3 & 0x00000007) << 3); } #endif #if (defined(PHYDM_COMPILE_ABOVE_4SS)) if (dm->support_ic_type & PHYDM_IC_ABOVE_4SS) { curr_cck_pd_t[0][3][0] = (u8)((reg0 & 0xff000000) >> 24); curr_cck_pd_t[1][3][0] = (u8)((reg1 & 0xff000000) >> 24); curr_cck_pd_t[0][3][1] = (u8)((reg2 & 0x000F8000) >> 15); curr_cck_pd_t[1][3][1] = (u8)((reg3 & 0x000000F8) >> 3); } #endif PHYDM_DBG(dm, DBG_CCKPD, "bw=%dM, Nrx=%d\n", 20 << bw, n_rx); PHYDM_DBG(dm, DBG_CCKPD, "lv=%d, readback CS_th=0x%x, PD th=0x%x\n", cckpd_t->cck_pd_lv, curr_cck_pd_t[bw][n_rx - 1][1], curr_cck_pd_t[bw][n_rx - 1][0]); } void phydm_cckpd_type4(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; u8 igi = dm->dm_dig_table.cur_ig_value; enum cckpd_lv lv = 0; boolean is_update = true; PHYDM_DBG(dm, DBG_CCKPD, "%s ======>\n", __func__); if (dm->is_linked) { PHYDM_DBG(dm, DBG_CCKPD, "Linked!!!\n"); if (igi > 0x38 && dm->rssi_min > 32) { lv = CCK_PD_LV_4; PHYDM_DBG(dm, DBG_CCKPD, "Order 1\n"); } else if (igi > 0x2a && dm->rssi_min > 32) { lv = CCK_PD_LV_3; PHYDM_DBG(dm, DBG_CCKPD, "Order 2\n"); } else if (igi > 0x24 || dm->rssi_min > 24) { lv = CCK_PD_LV_2; PHYDM_DBG(dm, DBG_CCKPD, "Order 3\n"); } else { if (cckpd_t->cck_fa_ma > 1000) { lv = CCK_PD_LV_1; PHYDM_DBG(dm, DBG_CCKPD, "Order 4-1\n"); } else if (cckpd_t->cck_fa_ma < 500) { lv = CCK_PD_LV_0; PHYDM_DBG(dm, DBG_CCKPD, "Order 4-2\n"); } else { is_update = false; PHYDM_DBG(dm, DBG_CCKPD, "Order 4-3\n"); } } } else { PHYDM_DBG(dm, DBG_CCKPD, "UnLinked!!!\n"); if (cckpd_t->cck_fa_ma > 1000) { lv = CCK_PD_LV_1; PHYDM_DBG(dm, DBG_CCKPD, "Order 1\n"); } else if (cckpd_t->cck_fa_ma < 500) { lv = CCK_PD_LV_0; PHYDM_DBG(dm, DBG_CCKPD, "Order 2\n"); } else { is_update = false; PHYDM_DBG(dm, DBG_CCKPD, "Order 3\n"); } } if (is_update) { phydm_set_cck_pd_lv_type4(dm, lv); PHYDM_DBG(dm, DBG_CCKPD, "setting CS_th = 0x%x, PD th = 0x%x\n", cckpd_t->cck_pd_table_jgr3[cckpd_t->cck_bw] [cckpd_t->cck_n_rx - 1][1][lv], cckpd_t->cck_pd_table_jgr3[cckpd_t->cck_bw] [cckpd_t->cck_n_rx - 1][0][lv]); } phydm_read_cckpd_para_type4(dm); } void phydm_cck_pd_init_type4(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; u32 reg0 = 0; u32 reg1 = 0; u32 reg2 = 0; u32 reg3 = 0; u8 pd_step = 0; u8 cck_bw = 0; /*r_RX_RF_BW*/ u8 cck_n_rx = 0; u8 val = 0; u8 i = 0; PHYDM_DBG(dm, DBG_CCKPD, "[%s]======>\n", __func__); #if 0 /*@ *cckpd_t[0][0][0][0] = 1ac8[7:0] r_PD_lim_RFBW20_1R *cckpd_t[0][1][0][0] = 1ac8[15:8] r_PD_lim_RFBW20_2R *cckpd_t[0][2][0][0] = 1ac8[23:16] r_PD_lim_RFBW20_3R *cckpd_t[0][3][0][0] = 1ac8[31:24] r_PD_lim_RFBW20_4R *cckpd_t[1][0][0][0] = 1acc[7:0] r_PD_lim_RFBW40_1R *cckpd_t[1][1][0][0] = 1acc[15:8] r_PD_lim_RFBW40_2R *cckpd_t[1][2][0][0] = 1acc[23:16] r_PD_lim_RFBW40_3R *cckpd_t[1][3][0][0] = 1acc[31:24] r_PD_lim_RFBW40_4R * * *cckpd_t[0][0][1][0] = 1ad0[4:0] r_CS_ratio_RFBW20_1R[4:0] *cckpd_t[0][1][1][0] = 1ad0[9:5] r_CS_ratio_RFBW20_2R[4:0] *cckpd_t[0][2][1][0] = 1ad0[14:10] r_CS_ratio_RFBW20_3R[4:0] *cckpd_t[0][3][1][0] = 1ad0[19:15] r_CS_ratio_RFBW20_4R[4:0] *cckpd_t[1][0][1][0] = 1ad0[24:20] r_CS_ratio_RFBW40_1R[4:0] *cckpd_t[1][1][1][0] = 1ad0[29:25] r_CS_ratio_RFBW40_2R[4:0] *cckpd_t[1][2][1][0] = 1ad0[31:30] r_CS_ratio_RFBW40_3R[1:0] * 1ad4[2:0] r_CS_ratio_RFBW40_3R[4:2] *cckpd_t[1][3][1][0] = 1ad4[7:3] r_CS_ratio_RFBW40_4R[4:0] */ #endif /*[Check Nrx]*/ cck_n_rx = (u8)odm_get_bb_reg(dm, R_0x1a2c, 0x60000) + 1; /*[Check BW]*/ val = (u8)odm_get_bb_reg(dm, R_0x9b0, 0xc); if (val == 0) cck_bw = CHANNEL_WIDTH_20; else if (val == 1) cck_bw = CHANNEL_WIDTH_40; else cck_bw = CHANNEL_WIDTH_80; cckpd_t->cck_bw = cck_bw; cckpd_t->cck_n_rx = cck_n_rx; reg0 = odm_get_bb_reg(dm, R_0x1ac8, MASKDWORD); reg1 = odm_get_bb_reg(dm, R_0x1acc, MASKDWORD); reg2 = odm_get_bb_reg(dm, R_0x1ad0, MASKDWORD); reg3 = odm_get_bb_reg(dm, R_0x1ad4, MASKDWORD); for (i = 0 ; i < CCK_PD_LV_MAX ; i++) { pd_step = i * 2; val = (u8)(reg0 & 0x000000ff) + pd_step; PHYDM_DBG(dm, DBG_CCKPD, "lvl %d val = %x\n\n", i, val); cckpd_t->cck_pd_table_jgr3[0][0][0][i] = val; val = (u8)(reg1 & 0x000000ff) + pd_step; cckpd_t->cck_pd_table_jgr3[1][0][0][i] = val; val = (u8)(reg2 & 0x0000001F) + pd_step; cckpd_t->cck_pd_table_jgr3[0][0][1][i] = val; val = (u8)((reg2 & 0x01F00000) >> 20) + pd_step; cckpd_t->cck_pd_table_jgr3[1][0][1][i] = val; #ifdef PHYDM_COMPILE_ABOVE_2SS if (dm->support_ic_type & PHYDM_IC_ABOVE_2SS) { val = (u8)((reg0 & 0x0000ff00) >> 8) + pd_step; cckpd_t->cck_pd_table_jgr3[0][1][0][i] = val; val = (u8)((reg1 & 0x0000ff00) >> 8) + pd_step; cckpd_t->cck_pd_table_jgr3[1][1][0][i] = val; val = (u8)((reg2 & 0x000003E0) >> 5) + pd_step; cckpd_t->cck_pd_table_jgr3[0][1][1][i] = val; val = (u8)((reg2 & 0x3E000000) >> 25) + pd_step; cckpd_t->cck_pd_table_jgr3[1][1][1][i] = val; } #endif #ifdef PHYDM_COMPILE_ABOVE_3SS if (dm->support_ic_type & PHYDM_IC_ABOVE_3SS) { val = (u8)((reg0 & 0x00ff0000) >> 16) + pd_step; cckpd_t->cck_pd_table_jgr3[0][2][0][i] = val; val = (u8)((reg1 & 0x00ff0000) >> 16) + pd_step; cckpd_t->cck_pd_table_jgr3[1][2][0][i] = val; val = (u8)((reg2 & 0x00007C00) >> 10) + pd_step; cckpd_t->cck_pd_table_jgr3[0][2][1][i] = val; val = (u8)(((reg2 & 0xC0000000) >> 30) | ((reg3 & 0x7) << 3)) + pd_step; cckpd_t->cck_pd_table_jgr3[1][2][1][i] = val; } #endif #ifdef PHYDM_COMPILE_ABOVE_4SS if (dm->support_ic_type & PHYDM_IC_ABOVE_4SS) { val = (u8)((reg0 & 0xff000000) >> 24) + pd_step; cckpd_t->cck_pd_table_jgr3[0][3][0][i] = val; val = (u8)((reg1 & 0xff000000) >> 24) + pd_step; cckpd_t->cck_pd_table_jgr3[1][3][0][i] = val; val = (u8)((reg2 & 0x000F8000) >> 15) + pd_step; cckpd_t->cck_pd_table_jgr3[0][3][1][i] = val; val = (u8)((reg3 & 0x000000F8) >> 3) + pd_step; cckpd_t->cck_pd_table_jgr3[1][3][1][i] = val; } #endif } } void phydm_invalid_cckpd_type4(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; u8 val = 0; u8 i = 0; u8 k = 0; PHYDM_DBG(dm, DBG_CCKPD, "[%s]======>\n", __func__); for (i = 0; i < CCK_PD_LV_MAX; i++) { for (k = RF_PATH_A; k < dm->num_rf_path; k++) { val = cckpd_t->cck_pd_table_jgr3[0][k][1][i]; if (val == INVALID_CS_RATIO_0) cckpd_t->cck_pd_table_jgr3[0][k][1][i] = 28; else if (val == INVALID_CS_RATIO_1) cckpd_t->cck_pd_table_jgr3[0][k][1][i] = 30; else if (val > MAXVALID_CS_RATIO) cckpd_t->cck_pd_table_jgr3[0][k][1][i] = MAXVALID_CS_RATIO; val = cckpd_t->cck_pd_table_jgr3[1][k][1][i]; if (val == INVALID_CS_RATIO_0) cckpd_t->cck_pd_table_jgr3[1][k][1][i] = 28; else if (val == INVALID_CS_RATIO_1) cckpd_t->cck_pd_table_jgr3[1][k][1][i] = 30; else if (val > MAXVALID_CS_RATIO) cckpd_t->cck_pd_table_jgr3[1][k][1][i] = MAXVALID_CS_RATIO; val = cckpd_t->cck_pd_table_jgr3[0][k][0][i]; if (val > MAXVALID_PD_THRES) cckpd_t->cck_pd_table_jgr3[0][k][0][i] = MAXVALID_PD_THRES; val = cckpd_t->cck_pd_table_jgr3[1][k][0][i]; if (val > MAXVALID_PD_THRES) cckpd_t->cck_pd_table_jgr3[1][k][0][i] = MAXVALID_PD_THRES; } } } #endif /*#ifdef PHYDM_COMPILE_CCKPD_TYPE4*/ void phydm_set_cckpd_val(void *dm_void, u32 *val_buf, u8 val_len) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; enum cckpd_lv lv; if (val_len != 1) { PHYDM_DBG(dm, ODM_COMP_API, "[Error][CCKPD]Need val_len=1\n"); return; } lv = (enum cckpd_lv)val_buf[0]; if (lv > CCK_PD_LV_4) { pr_debug("[%s] warning! lv=%d\n", __func__, lv); return; } switch (cckpd_t->cckpd_hw_type) { #ifdef PHYDM_COMPILE_CCKPD_TYPE1 case 1: phydm_set_cckpd_lv_type1(dm, lv); break; #endif #ifdef PHYDM_COMPILE_CCKPD_TYPE2 case 2: phydm_set_cckpd_lv_type2(dm, lv); break; #endif #ifdef PHYDM_COMPILE_CCKPD_TYPE3 case 3: phydm_set_cckpd_lv_type3(dm, lv); break; #endif #ifdef PHYDM_COMPILE_CCKPD_TYPE4 case 4: phydm_set_cck_pd_lv_type4(dm, lv); break; #endif default: pr_debug("[%s]warning\n", __func__); break; } } boolean phydm_stop_cck_pd_th(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; if (!(dm->support_ability & (ODM_BB_CCK_PD | ODM_BB_FA_CNT))) { PHYDM_DBG(dm, DBG_CCKPD, "Not Support\n"); return true; } if (dm->pause_ability & ODM_BB_CCK_PD) { PHYDM_DBG(dm, DBG_CCKPD, "Return: Pause CCKPD in LV=%d\n", dm->pause_lv_table.lv_cckpd); return true; } if (dm->is_linked && (*dm->channel > 36)) { PHYDM_DBG(dm, DBG_CCKPD, "Return: 5G CH=%d\n", *dm->channel); return true; } return false; } void phydm_cck_pd_th(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_fa_struct *fa_t = &dm->false_alm_cnt; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; u32 cck_fa = fa_t->cnt_cck_fail; #ifdef PHYDM_TDMA_DIG_SUPPORT struct phydm_fa_acc_struct *fa_acc_t = &dm->false_alm_cnt_acc; #endif PHYDM_DBG(dm, DBG_CCKPD, "[%s] ======>\n", __func__); if (phydm_stop_cck_pd_th(dm)) return; #ifdef PHYDM_TDMA_DIG_SUPPORT if (dm->original_dig_restore) cck_fa = fa_t->cnt_cck_fail; else cck_fa = fa_acc_t->cnt_cck_fail_1sec; #endif if (cckpd_t->cck_fa_ma == CCK_FA_MA_RESET) cckpd_t->cck_fa_ma = cck_fa; else cckpd_t->cck_fa_ma = (cckpd_t->cck_fa_ma * 3 + cck_fa) >> 2; PHYDM_DBG(dm, DBG_CCKPD, "IGI=0x%x, rssi_min=%d, cck_fa=%d, cck_fa_ma=%d\n", dm->dm_dig_table.cur_ig_value, dm->rssi_min, cck_fa, cckpd_t->cck_fa_ma); switch (cckpd_t->cckpd_hw_type) { #ifdef PHYDM_COMPILE_CCKPD_TYPE1 case 1: phydm_cckpd_type1(dm); break; #endif #ifdef PHYDM_COMPILE_CCKPD_TYPE2 case 2: phydm_cckpd_type2(dm); break; #endif #ifdef PHYDM_COMPILE_CCKPD_TYPE3 case 3: phydm_cckpd_type3(dm); break; #endif #ifdef PHYDM_COMPILE_CCKPD_TYPE4 case 4: phydm_cckpd_type4(dm); break; #endif default: pr_debug("[%s]warning\n", __func__); break; } } void phydm_cck_pd_init(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct phydm_cckpd_struct *cckpd_t = &dm->dm_cckpd_table; if (dm->support_ic_type & CCK_PD_IC_TYPE1) cckpd_t->cckpd_hw_type = 1; else if (dm->support_ic_type & CCK_PD_IC_TYPE2) cckpd_t->cckpd_hw_type = 2; else if (dm->support_ic_type & CCK_PD_IC_TYPE3) cckpd_t->cckpd_hw_type = 3; else if (dm->support_ic_type & CCK_PD_IC_TYPE4) cckpd_t->cckpd_hw_type = 4; PHYDM_DBG(dm, DBG_CCKPD, "[%s] cckpd_hw_type=%d\n", __func__, cckpd_t->cckpd_hw_type); cckpd_t->cck_pd_lv = CCK_PD_LV_INIT; cckpd_t->cck_n_rx = 0xff; cckpd_t->cck_bw = CHANNEL_WIDTH_MAX; switch (cckpd_t->cckpd_hw_type) { #ifdef PHYDM_COMPILE_CCKPD_TYPE1 case 1: phydm_set_cckpd_lv_type1(dm, CCK_PD_LV_0); break; #endif #ifdef PHYDM_COMPILE_CCKPD_TYPE2 case 2: cckpd_t->aaa_default = odm_read_1byte(dm, 0xaaa) & 0x1f; phydm_set_cckpd_lv_type2(dm, CCK_PD_LV_0); break; #endif #ifdef PHYDM_COMPILE_CCKPD_TYPE3 case 3: phydm_cck_pd_init_type3(dm); phydm_set_cckpd_lv_type3(dm, CCK_PD_LV_0); break; #endif #ifdef PHYDM_COMPILE_CCKPD_TYPE4 case 4: phydm_cck_pd_init_type4(dm); phydm_invalid_cckpd_type4(dm); phydm_set_cck_pd_lv_type4(dm, CCK_PD_LV_0); break; #endif default: pr_debug("[%s]warning\n", __func__); break; } } #endif /*#ifdef PHYDM_SUPPORT_CCKPD*/