/****************************************************************************** * * Copyright(c) 2007 - 2020 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 "halbb_precomp.h" #ifdef HALBB_FW_OFLD_SUPPORT bool halbb_check_fw_ofld(struct bb_info *bb) { bool ret = bb->phl_com->dev_cap.fw_cap.offload_cap & BIT0; BB_DBG(bb, DBG_FW_INFO, "FW ofld ret = %d\n", (u8)ret); return ret; } bool halbb_fw_delay(struct bb_info *bb, u32 val) { /* halbb_set_reg */ struct rtw_mac_cmd cmd; u32 ret; cmd.type = RTW_MAC_DELAY_OFLD; cmd.lc = 0; cmd.value = val; /*delay us*/ ret = rtw_hal_mac_add_cmd_ofld(bb->hal_com, &cmd); BB_DBG(bb, DBG_FW_INFO, "FW ofld delay:%x\n", val); if (ret) { BB_WARNING("IO offload fail: %d\n", ret); return false; } else { return true; } } bool halbb_fw_set_reg(struct bb_info *bb, u32 addr, u32 mask, u32 val, u8 lc) { /* halbb_set_reg */ struct rtw_mac_cmd cmd; u32 ret; cmd.src = RTW_MAC_BB_CMD_OFLD; cmd.type = RTW_MAC_WRITE_OFLD; cmd.lc = lc; cmd.offset = (u16)addr; cmd.value = val; cmd.mask = mask; ret = rtw_hal_mac_add_cmd_ofld(bb->hal_com, &cmd); BB_DBG(bb, DBG_FW_INFO, "FW ofld addr:%x, val:%x, msk:%x\n", addr, val, mask); if (ret) { BB_WARNING("IO offload fail: %d\n", ret); return false; } else { return true; } } bool halbb_fw_set_reg_cmn(struct bb_info *bb, u32 addr, u32 mask, u32 val, enum phl_phy_idx phy_idx, u8 lc) { bool ret = true; u32 val_mod = val; #ifdef HALBB_DBCC_SUPPORT if (bb->hal_com->dbcc_en && phy_idx == HW_PHY_1) addr += halbb_phy0_to_phy1_ofst(bb, addr); #endif ret = halbb_fw_set_reg(bb, addr, mask, val_mod, lc); return ret; } bool halbb_fwcfg_bb_phy_8852a_2(struct bb_info *bb, u32 addr, u32 data, enum phl_phy_idx phy_idx) { #ifdef HALBB_DBCC_SUPPORT u32 ofst = 0; #endif bool ret = true; if (addr == 0xfe) { halbb_delay_ms(bb, 50); BB_DBG(bb, DBG_INIT, "Delay 50 ms\n"); } else if (addr == 0xfd) { halbb_delay_ms(bb, 5); BB_DBG(bb, DBG_INIT, "Delay 5 ms\n"); } else if (addr == 0xfc) { halbb_delay_ms(bb, 1); BB_DBG(bb, DBG_INIT, "Delay 1 ms\n"); } else if (addr == 0xfb) { halbb_delay_us(bb, 50); BB_DBG(bb, DBG_INIT, "Delay 50 us\n"); } else if (addr == 0xfa) { halbb_delay_us(bb, 5); BB_DBG(bb, DBG_INIT, "Delay 5 us\n"); } else if (addr == 0xf9) { halbb_delay_us(bb, 1); BB_DBG(bb, DBG_INIT, "Delay 1 us\n"); } else { #ifdef HALBB_DBCC_SUPPORT if ((bb->hal_com->dbcc_en || bb->bb_dbg_i.cr_dbg_mode_en) && phy_idx == HW_PHY_1) { ofst = halbb_phy0_to_phy1_ofst(bb, addr); if (ofst == 0) return true; addr += ofst; } else { phy_idx = HW_PHY_0; } #endif /*FWOFLD in init BB reg flow */ if (halbb_check_fw_ofld(bb)) { ret &= halbb_fw_set_reg(bb, addr, MASKDWORD, data, 0); BB_DBG(bb, DBG_INIT, "[REG FWOFLD]0x%04X = 0x%08X, ret = %d\n", addr, data, (u8)ret); } else { halbb_set_reg(bb, addr, MASKDWORD, data); #ifdef HALBB_DBCC_SUPPORT BB_DBG(bb, DBG_INIT, "[REG][%d]0x%04X = 0x%08X\n", phy_idx, addr, data); #else BB_DBG(bb, DBG_INIT, "[REG]0x%04X = 0x%08X\n", addr, data); #endif } } return ret; } bool halbb_fwofld_cck_en_8852a_2(struct bb_info *bb, bool cck_en, enum phl_phy_idx phy_idx) { bool ret = true; if (cck_en) { ret &= halbb_fw_set_reg(bb, 0x2344, BIT(31), 0, 0); } else { ret &= halbb_fw_set_reg(bb, 0x2344, BIT(31), 1, 0); } BB_DBG(bb, DBG_PHY_CONFIG, "[CCK Enable for PHY%d]\n", phy_idx); return ret; } bool halbb_fwofld_btg_8852a_2(struct bb_info *bb, bool btg) { struct rtw_phl_com_t *phl = bb->phl_com; struct dev_cap_t *dev = &phl->dev_cap; bool ret = true; if (dev->rfe_type >= 50) return true; BB_DBG(bb, DBG_PHY_CONFIG, "<====== %s ======>\n", __func__); if (btg) { // Path A ret &= halbb_fw_set_reg(bb, 0x466c, BIT(18) | BIT(17), 0x1, 0); // Path B ret &= halbb_fw_set_reg(bb, 0x4740, BIT(18) | BIT(17), 0x3, 0); BB_DBG(bb, DBG_PHY_CONFIG, "[BT] Apply BTG Setting\n"); // Apply Grant BT by TMAC Setting ret &= halbb_fw_set_reg(bb, 0x980, 0x1e0000, 0x0, 0); BB_DBG(bb, DBG_PHY_CONFIG, "[BT] Apply Grant BT by TMAC Setting\n"); // Add BT share ret &= halbb_fw_set_reg(bb, 0x4978, BIT(14), 0x1, 0); ret &= halbb_fw_set_reg(bb, 0x4974, 0x3c00000, 0x2, 0); ret &= halbb_fw_set_reg(bb, 0x441c, BIT(31), 0x1, 0); } else { // Path A ret &= halbb_fw_set_reg(bb, 0x466c, BIT(18) | BIT(17), 0x0, 0); // Path B ret &= halbb_fw_set_reg(bb, 0x4740, BIT(18) | BIT(17), 0x0, 0); BB_DBG(bb, DBG_PHY_CONFIG, "[BT] Disable BTG Setting\n"); // Ignore Grant BT by PMAC Setting ret &= halbb_fw_set_reg(bb, 0x980, 0x1e0000, 0xf, 0); ret &= halbb_fw_set_reg(bb, 0x980, 0x3c000000, 0x4, 0); BB_DBG(bb, DBG_PHY_CONFIG, "[BT] Ignore Grant BT by PMAC Setting\n"); // Reset BT share ret &= halbb_fw_set_reg(bb, 0x4978, BIT(14), 0x0, 0); ret &= halbb_fw_set_reg(bb, 0x4974, 0x3c00000, 0x0, 0); ret &= halbb_fw_set_reg(bb, 0x441c, BIT(31), 0x0, 0); } return ret; } bool halbb_fw_5m_mask_8852a_2(struct bb_info *bb, u8 pri_ch, enum channel_width bw) { bool mask_5m_low = false; bool mask_5m_en = false; bool ret = true; switch (bw) { case CHANNEL_WIDTH_40: /* Prich=1 : Mask 5M High Prich=2 : Mask 5M Low */ mask_5m_en = true; mask_5m_low = pri_ch == 2 ? true : false; break; case CHANNEL_WIDTH_80: /* Prich=3 : Mask 5M High Prich=4 : Mask 5M Low Else : Mask 5M Disable */ mask_5m_en = ((pri_ch == 3) || (pri_ch == 4)) ? true : false; mask_5m_low = pri_ch == 4 ? true : false; break; default: mask_5m_en = false; break; } BB_DBG(bb, DBG_PHY_CONFIG, "[5M Mask] pri_ch = %d, bw = %d", pri_ch, bw); if (!mask_5m_en) { ret &= halbb_fw_set_reg(bb, 0x46b0, BIT(12), 0x0, 0); ret &= halbb_fw_set_reg(bb, 0x4784, BIT(12), 0x0, 0); } else { if (mask_5m_low) { ret &= halbb_fw_set_reg(bb, 0x46b0, 0x3f, 0x4, 0); ret &= halbb_fw_set_reg(bb, 0x46b0, BIT(12) | BIT(8) | BIT(6), 0x5, 0); ret &= halbb_fw_set_reg(bb, 0x4784, 0x3f, 0x4, 0); ret &= halbb_fw_set_reg(bb, 0x4784, BIT(12) | BIT(8) | BIT(6), 0x5, 0); } else { ret &= halbb_fw_set_reg(bb, 0x46b0, 0x3f, 0x4, 0); ret &= halbb_fw_set_reg(bb, 0x46b0, BIT(12) | BIT(8) | BIT(6), 0x6, 0); ret &= halbb_fw_set_reg(bb, 0x4784, 0x3f, 0x4, 0); ret &= halbb_fw_set_reg(bb, 0x4784, BIT(12) | BIT(8) | BIT(6), 0x6, 0); } } return ret; } bool halbb_fw_set_rf_reg_8852a_2(struct bb_info *bb, enum rf_path path, u32 reg_addr, u32 bit_mask, u32 data, u8 lc) { /* halbb_write_rf_reg_8852a_2 */ bool ret = true; u32 direct_addr = 0; u32 offset_write_rf[2] = {0xc000, 0xd000}; /*==== Error handling ====*/ if (path > RF_PATH_B) { BB_WARNING("[%s] Unsupported path (%d)\n", __func__, path); return false; } /*==== Calculate offset ====*/ reg_addr &= 0xff; direct_addr = offset_write_rf[path] + (reg_addr << 2); /*==== RF register only has 20bits ====*/ bit_mask &= RFREGOFFSETMASK; halbb_fw_delay(bb, 1); /*==== Write RF register directly ====*/ ret = halbb_fw_set_reg(bb, direct_addr, bit_mask, data, lc); /*halbb_delay_us(bb, 1);*/ halbb_fw_delay(bb, 1); BB_DBG(bb, DBG_FW_INFO, "FW OFLD RF-%d 0x%x = 0x%x , bit mask = 0x%x, ret = %d\n", path, reg_addr, data, bit_mask, (u8)ret); return ret; } bool halbb_fw_set_efuse_8852a_2(struct bb_info *bb, u8 central_ch, enum rf_path path, enum phl_phy_idx phy_idx) { u8 band; bool ret = true; u8 upper_bound = 60; // S(7,4): 3.75 u8 lower_bound = 64; // S(7,4): -4 s32 hidden_efuse = 0, normal_efuse = 0, normal_efuse_cck = 0; s32 tmp = 0; u32 efuse_5g[BB_PATH_MAX_8852A] = {0x4624, 0x46f8}; u32 efuse_5g_mask = 0x07e00000; u32 efuse_2g[BB_PATH_MAX_8852A] = {0x4628, 0x46fc}; u32 efuse_2g_mask = 0x0000003f; BB_DBG(bb, DBG_PHY_CONFIG, "<====== %s ======>\n", __func__); // 2G Band: (0) // 5G Band: (1):Low, (2): Mid, (3):High if (central_ch >= 0 && central_ch <= 14) band = 0; else if (central_ch >= 36 && central_ch <= 64) band = 1; else if (central_ch >= 100 && central_ch <= 144) band = 2; else if (central_ch >= 149 && central_ch <= 177) band = 3; else band = 0; // === [Set hidden efuse] === // if (bb->bb_efuse_i.hidden_efuse_check) { for (path = RF_PATH_A; path < BB_PATH_MAX_8852A; path++) { if (central_ch >= 0 && central_ch <= 14) { hidden_efuse = (bb->bb_efuse_i.gain_cg[path][band] << 2); ret &= halbb_fw_set_reg(bb, efuse_2g[path], efuse_2g_mask, (hidden_efuse & 0x3f), 0); } else { hidden_efuse = (bb->bb_efuse_i.gain_cg[path][band] << 2); ret &= halbb_fw_set_reg(bb, efuse_5g[path], efuse_5g_mask, (hidden_efuse & 0x3f), 0); } } BB_DBG(bb, DBG_INIT, "[Efuse][FWOFLD] Hidden efuse dynamic setting!!\n"); } else { BB_DBG(bb, DBG_INIT, "[Efuse][FWOFLD] Values of hidden efuse are all 0xff, bypass dynamic setting!!\n"); } // === [Set normal efuse] === // if (bb->bb_efuse_i.normal_efuse_check) { if ((bb->rx_path == RF_PATH_A) || (bb->rx_path == RF_PATH_AB)) { normal_efuse = bb->bb_efuse_i.gain_offset[RF_PATH_A][band + 1]; normal_efuse_cck = bb->bb_efuse_i.gain_offset[RF_PATH_A][0]; } else if (bb->rx_path == RF_PATH_B) { normal_efuse = bb->bb_efuse_i.gain_offset[RF_PATH_B][band + 1]; normal_efuse_cck = bb->bb_efuse_i.gain_offset[RF_PATH_B][0]; } normal_efuse *= (-1); normal_efuse_cck *= (-1); // OFDM normal efuse if (normal_efuse > 3) { tmp = (normal_efuse << 4) + (bb->bb_efuse_i.efuse_ofst << 2) - upper_bound; ret &= halbb_fw_set_reg_cmn(bb, 0x494c, 0xf8000000, ((tmp >> 2) & 0x1f), phy_idx, 0); ret &= halbb_fw_set_reg_cmn(bb, 0x4964, 0xfe00000, (tmp & 0x7f), phy_idx, 0); // Set efuse ret &= halbb_fw_set_reg_cmn(bb, 0x4960, 0xfe00000, (upper_bound & 0x7f), phy_idx, 0); ret &= halbb_fw_set_reg_cmn(bb, 0x4964, 0x7f, (upper_bound & 0x7f), phy_idx, 0); ret &= halbb_fw_set_reg_cmn(bb, 0x4964, 0x3f80, (upper_bound & 0x7f), phy_idx, 0); } else if (normal_efuse < -4) { tmp = (normal_efuse << 4) + (bb->bb_efuse_i.efuse_ofst << 2) + lower_bound; // r_1_rpl_bias_comp ret &= halbb_fw_set_reg_cmn(bb, 0x494c, 0xf8000000, ((tmp >> 2) & 0x1f), phy_idx, 0); // r_tb_rssi_bias_comp ret &= halbb_fw_set_reg_cmn(bb, 0x4964, 0xfe00000, (tmp & 0x7f), phy_idx, 0); // Set efuse ret &= halbb_fw_set_reg_cmn(bb, 0x4960, 0xfe00000, (lower_bound & 0x7f), phy_idx, 0); ret &= halbb_fw_set_reg_cmn(bb, 0x4964, 0x7f, (lower_bound & 0x7f), phy_idx, 0); ret &= halbb_fw_set_reg_cmn(bb, 0x4964, 0x3f80, (lower_bound & 0x7f), phy_idx, 0); } else { ret &= halbb_fw_set_reg_cmn(bb, 0x494c, 0xf8000000, (bb->bb_efuse_i.efuse_ofst & 0x1f), phy_idx, 0); ret &= halbb_fw_set_reg_cmn(bb, 0x4964, 0xfe00000, (bb->bb_efuse_i.efuse_ofst_tb & 0x7f), phy_idx, 0); // Set efuse ret &= halbb_fw_set_reg_cmn(bb, 0x4960, 0xfe00000, ((normal_efuse << 4) & 0x7f), phy_idx, 0); ret &= halbb_fw_set_reg_cmn(bb, 0x4964, 0x7f, ((normal_efuse << 4) & 0x7f), phy_idx, 0); ret &= halbb_fw_set_reg_cmn(bb, 0x4964, 0x3f80, ((normal_efuse << 4) & 0x7f), phy_idx, 0); } // CCK normal efuse if (band == 0) { tmp = normal_efuse_cck << 3; ret &= halbb_fw_set_reg(bb, 0x23ac, 0x7f, (tmp & 0x7f), 0); } BB_DBG(bb, DBG_INIT, "[Efuse][FWOFLD] Normal efuse dynamic setting!!\n"); } else { BB_DBG(bb, DBG_INIT, "[Efuse][FWOFLD] Values of normal efuse are all 0xff, bypass dynamic setting!!\n"); } return ret; } bool halbb_fw_set_gain_error_8852a_2(struct bb_info *bb, u8 central_ch) { bool ret = true; u8 band; u8 path = 0, lna_idx = 0, tia_idx = 0; s32 tmp = 0; u32 lna_err_a_5g[BB_PATH_MAX_8852A][7] = {{0x462c, 0x462c, 0x4630, 0x4634, 0x4634, 0x4638, 0x4638}, {0x4700, 0x4700, 0x4704, 0x4708, 0x4708, 0x470c, 0x470c}}; u32 lna_err_a_5g_mask[7] = {0x00000fc0, 0x3f000000, 0x0003f000, 0x0000003f, 0x00fc0000, 0x00000fc0, 0x3f000000}; u32 lna_err_a_2g[BB_PATH_MAX_8852A][7] = {{0x462c, 0x4630, 0x4630, 0x4634, 0x4634, 0x4638, 0x463c}, {0x4700, 0x4704, 0x4704, 0x4708, 0x4708, 0x470c, 0x4710}}; u32 lna_err_a_2g_mask[7] = {0x0003f000, 0x0000003f, 0x00fc0000, 0x00000fc0, 0x3f000000, 0x0003f000, 0x0000003f}; u32 tia_err_a_5g[BB_PATH_MAX_8852A][2] = {{0x4640, 0x4644}, {0x4714, 0x4718}}; u32 tia_err_a_5g_mask[2] = {0x0003f000, 0x0000003f}; u32 tia_err_a_2g[BB_PATH_MAX_8852A][2] = {{0x4640, 0x4644}, {0x4714, 0x4718}}; u32 tia_err_a_2g_mask[2] = {0x00fc0000, 0x00000fc0}; BB_DBG(bb, DBG_PHY_CONFIG, "<====== %s ======>\n", __func__); // 2G Band: (0) // 5G Band: (1):Low, (2): Mid, (3):High if (central_ch >= 0 && central_ch <= 14) band = 0; else if (central_ch >= 36 && central_ch <= 64) band = 1; else if (central_ch >= 100 && central_ch <= 144) band = 2; else if (central_ch >= 149 && central_ch <= 177) band = 3; else band = 0; if (central_ch >= 0 && central_ch <= 14) { for (path = RF_PATH_A; path < BB_PATH_MAX_8852A; path++) { // Set 2G LNA Gain Err for (lna_idx = 0; lna_idx < 7; lna_idx++) { tmp = bb->bb_gain_i.lna_gain[band][path][lna_idx]; ret &= halbb_fw_set_reg(bb, lna_err_a_2g[path][lna_idx], lna_err_a_2g_mask[lna_idx], (tmp & 0x3f), 0); } // Set 2G TIA Gain Err for (tia_idx = 0; tia_idx < 2; tia_idx++) { tmp = bb->bb_gain_i.tia_gain[band][path][tia_idx]; ret &= halbb_fw_set_reg(bb, tia_err_a_2g[path][tia_idx], tia_err_a_2g_mask[tia_idx], (tmp & 0x3f), 0); } } } else { for (path = RF_PATH_A; path < BB_PATH_MAX_8852A; path++) { // Set 5G LNA Gain Err for (lna_idx = 0; lna_idx < 7; lna_idx++) { tmp = bb->bb_gain_i.lna_gain[band][path][lna_idx]; ret &= halbb_fw_set_reg(bb, lna_err_a_5g[path][lna_idx], lna_err_a_5g_mask[lna_idx], (tmp & 0x3f), 0); } // Set 5G TIA Gain Err for (tia_idx = 0; tia_idx < 2; tia_idx++) { tmp = bb->bb_gain_i.tia_gain[band][path][tia_idx]; ret &= halbb_fw_set_reg(bb, tia_err_a_5g[path][tia_idx], tia_err_a_5g_mask[tia_idx], (tmp & 0x3f), 0); } } } return ret; } bool halbb_fwofld_sco_cck_8852a_2(struct bb_info *bb, u8 pri_ch) { u32 sco_barker_threshold[14] = {0x1cfea, 0x1d0e1, 0x1d1d7, 0x1d2cd, 0x1d3c3, 0x1d4b9, 0x1d5b0, 0x1d6a6, 0x1d79c, 0x1d892, 0x1d988, 0x1da7f, 0x1db75, 0x1ddc4}; u32 sco_cck_threshold[14] = {0x27de3, 0x27f35, 0x28088, 0x281da, 0x2832d, 0x2847f, 0x285d2, 0x28724, 0x28877, 0x289c9, 0x28b1c, 0x28c6e, 0x28dc1, 0x290ed}; bool rpt = true; if (pri_ch > 14) { BB_DBG(bb, DBG_PHY_CONFIG, "[CCK SCO Fail]"); /*Return true because its not FW offload fail*/ return true; } rpt &= halbb_fw_set_reg(bb, 0x23b0, 0x7ffff, sco_barker_threshold[pri_ch - 1], 0); rpt &= halbb_fw_set_reg(bb, 0x23b4, 0x7ffff, sco_cck_threshold[pri_ch - 1], 0); BB_DBG(bb, DBG_PHY_CONFIG, "[CCK SCO Success]"); return rpt; } bool halbb_fwofld_rf_ch_8852a_2(struct bb_info *bb, u8 central_ch, enum rf_path path, bool *is_2g_ch, u32 *rf_reg18) { //u32 rf_reg18 = 0; bool ret = true; /*rf_reg18 = halbb_read_rf_reg_8852a_2(bb, path, 0x18, RFREGOFFSETMASK);*/ /*==== [Error handling] ====*/ if (*rf_reg18 == INVALID_RF_DATA) { BB_WARNING("Invalid RF_0x18 for Path-%d\n", path); return false; } *is_2g_ch = (central_ch <= 14) ? true : false; /*==== [Set RF Reg 0x18] ====*/ *rf_reg18 &= ~0x303ff; /*[17:16],[9:8],[7:0]*/ *rf_reg18 |= central_ch; /* Channel*/ /*==== [5G Setting] ====*/ if (!*is_2g_ch) *rf_reg18 |= (BIT(16) | BIT(8)); /*ret &= halbb_fw_set_rf_reg_8852a_2(bb, path, 0x18, RFREGOFFSETMASK, *rf_reg18);*/ BB_DBG(bb, DBG_PHY_CONFIG, "[Success][ch_setting] CH: %d for Path-%d\n", central_ch, path); return ret; } bool halbb_fwofld_ch_8852a_2(struct bb_info *bb, u8 central_ch, enum phl_phy_idx phy_idx, u32 *path0_rf18, u32 *path1_rf18) { u8 sco_comp; bool is_2g_ch = false; bool ret = true; if (bb->is_disable_phy_api) { BB_DBG(bb, DBG_PHY_CONFIG, "[%s] Disable PHY API\n", __func__); return true; } /*==== Error handling ====*/ if ((central_ch > 14 && central_ch < 36) || (central_ch > 64 && central_ch < 100) || (central_ch > 144 && central_ch < 149) || central_ch > 177 ) { BB_WARNING("Invalid CH:%d for PHY%d\n", central_ch, phy_idx); return false; } if (phy_idx == HW_PHY_0) { /*============== [Path A] ==============*/ ret &= halbb_fwofld_rf_ch_8852a_2(bb, central_ch, RF_PATH_A, &is_2g_ch, path0_rf18); //------------- [Mode Sel - Path A] ------------// if (is_2g_ch) ret &= halbb_fw_set_reg_cmn(bb, 0x4644, BIT(31) | BIT(30), 1, phy_idx, 0); else ret &= halbb_fw_set_reg_cmn(bb, 0x4644, BIT(31) | BIT(30), 0, phy_idx, 0); /*============== [Path B] ==============*/ if (!bb->hal_com->dbcc_en) { ret &= halbb_fwofld_rf_ch_8852a_2(bb, central_ch, RF_PATH_B, &is_2g_ch, path1_rf18); //------------- [Mode Sel - Path B] ------------// if (is_2g_ch) ret &= halbb_fw_set_reg_cmn(bb, 0x4718, BIT(31) | BIT(30), 1, phy_idx, 0); else ret &= halbb_fw_set_reg_cmn(bb, 0x4718, BIT(31) | BIT(30), 0, phy_idx, 0); } else { /*==== [Phy0 config at 2/5G] ====*/ if (is_2g_ch) ret &= halbb_fw_set_reg(bb, 0x4970, BIT(1), 0, 0); else ret &= halbb_fw_set_reg(bb, 0x4970, BIT(1), 1, 0); } /*==== [SCO compensate fc setting] ====*/ sco_comp = halbb_sco_mapping_8852a_2(bb, central_ch); ret &= halbb_fw_set_reg_cmn(bb, 0x4974, 0x7f, sco_comp, phy_idx, 0); } else { /*============== [Path B] ==============*/ ret &= halbb_fwofld_rf_ch_8852a_2(bb, central_ch, RF_PATH_B, &is_2g_ch, path0_rf18); //------------- [Mode Sel - Path B] ------------// if (is_2g_ch) ret &= halbb_fw_set_reg_cmn(bb, 0x4718, BIT(31) | BIT(30), 1, phy_idx, 0); else ret &= halbb_fw_set_reg_cmn(bb, 0x4718, BIT(31) | BIT(30), 0, phy_idx, 0); /*==== [SCO compensate fc setting] ====*/ sco_comp = halbb_sco_mapping_8852a_2(bb, central_ch); ret &= halbb_fw_set_reg_cmn(bb, 0x4974, 0x7f, sco_comp, phy_idx, 0); } /* === Bandedge ===*/ if (is_2g_ch) ret &= halbb_fw_set_reg_cmn(bb, 0x4498, BIT(30), 1, phy_idx, 0); else ret &= halbb_fw_set_reg_cmn(bb, 0x4498, BIT(30), 0, phy_idx, 0); /* === CCK Parameters === */ if (central_ch == 14) { ret &= halbb_fw_set_reg(bb, 0x2300, 0xffffff, 0x3b13ff, 0); ret &= halbb_fw_set_reg(bb, 0x2304, 0xffffff, 0x1c42de, 0); ret &= halbb_fw_set_reg(bb, 0x2308, 0xffffff, 0xfdb0ad, 0); ret &= halbb_fw_set_reg(bb, 0x230c, 0xffffff, 0xf60f6e, 0); ret &= halbb_fw_set_reg(bb, 0x2310, 0xffffff, 0xfd8f92, 0); ret &= halbb_fw_set_reg(bb, 0x2314, 0xffffff, 0x2d011, 0); ret &= halbb_fw_set_reg(bb, 0x2318, 0xffffff, 0x1c02c, 0); ret &= halbb_fw_set_reg(bb, 0x231c, 0xffffff, 0xfff00a, 0); } else { ret &= halbb_fw_set_reg(bb, 0x2300, 0xffffff, 0x3d23ff, 0); ret &= halbb_fw_set_reg(bb, 0x2304, 0xffffff, 0x29b354, 0); ret &= halbb_fw_set_reg(bb, 0x2308, 0xffffff, 0xfc1c8, 0); ret &= halbb_fw_set_reg(bb, 0x230c, 0xffffff, 0xfdb053, 0); ret &= halbb_fw_set_reg(bb, 0x2310, 0xffffff, 0xf86f9a, 0); ret &= halbb_fw_set_reg(bb, 0x2314, 0xffffff, 0xfaef92, 0); ret &= halbb_fw_set_reg(bb, 0x2318, 0xffffff, 0xfe5fcc, 0); ret &= halbb_fw_set_reg(bb, 0x231c, 0xffffff, 0xffdff5, 0); } /* === Set Gain Error === */ ret &= halbb_fw_set_gain_error_8852a_2(bb, central_ch); /* === Set Efuse === */ ret &= halbb_fw_set_efuse_8852a_2(bb, central_ch, bb->rx_path, phy_idx); /* === Set Ch idx report in phy-sts === */ /* write for last cmd*/ ret &= halbb_fw_set_reg_cmn(bb, 0x0734, 0x0ff0000, central_ch, phy_idx, 0); BB_DBG(bb, DBG_PHY_CONFIG, "[Switch CH] CH: %d for PHY%d, ret = %d\n", central_ch, phy_idx, (u8)ret); return ret; } bool halbb_fw_bw_setting_8852a_2(struct bb_info *bb, enum channel_width bw, enum rf_path path, u32 *rf_reg18) { bool ret = true; /*u32 rf_reg18 = 0;*/ u32 adc_sel[2] = {0x12d0, 0x32d0}; u32 wbadc_sel[2] = {0x12ec, 0x32ec}; /*rf_reg18 = halbb_read_rf_reg_8852a_2(bb, path, 0x18, RFREGOFFSETMASK);*/ /*==== [Error handling] ====*/ if (*rf_reg18 == INVALID_RF_DATA) { BB_WARNING("Invalid RF_0x18 for Path-%d\n", path); return false; } *rf_reg18 &= ~(BIT(11) | BIT(10)); /*==== [Switch bandwidth] ====*/ switch (bw) { case CHANNEL_WIDTH_5: case CHANNEL_WIDTH_10: case CHANNEL_WIDTH_20: if (bw == CHANNEL_WIDTH_5) { /*ADC clock = 20M & WB ADC clock = 40M for BW5 */ ret &= halbb_fw_set_reg(bb, adc_sel[path], 0x6000, 0x1, 0); ret &= halbb_fw_set_reg(bb, wbadc_sel[path], 0x30, 0x0, 0); } else if (bw == CHANNEL_WIDTH_10) { /*ADC clock = 40M & WB ADC clock = 80M for BW10 */ ret &= halbb_fw_set_reg(bb, adc_sel[path], 0x6000, 0x2, 0); ret &= halbb_fw_set_reg(bb, wbadc_sel[path], 0x30, 0x1, 0); } else if (bw == CHANNEL_WIDTH_20) { /*ADC clock = 80M & WB ADC clock = 160M for BW20 */ ret &= halbb_fw_set_reg(bb, adc_sel[path], 0x6000, 0x0, 0); ret &= halbb_fw_set_reg(bb, wbadc_sel[path], 0x30, 0x2, 0); } /*RF bandwidth */ *rf_reg18 |= (BIT(11) | BIT(10)); break; case CHANNEL_WIDTH_40: /*ADC clock = 80M & WB ADC clock = 160M for BW40 */ ret &= halbb_fw_set_reg(bb, adc_sel[path], 0x6000, 0x0, 0); ret &= halbb_fw_set_reg(bb, wbadc_sel[path], 0x30, 0x2, 0); /*RF bandwidth */ *rf_reg18 |= BIT(11); break; case CHANNEL_WIDTH_80: /*ADC clock = 160M & WB ADC clock = 160M for BW40 */ ret &= halbb_fw_set_reg(bb, adc_sel[path], 0x6000, 0x0, 0); ret &= halbb_fw_set_reg(bb, wbadc_sel[path], 0x30, 0x2, 0); /*RF bandwidth */ *rf_reg18 |= BIT(10); break; default: BB_WARNING("Fail to set ADC\n"); } /*==== [Write RF register] ====*/ /*ret &= halbb_fw_set_rf_reg_8852a_2(bb, path, 0x18, RFREGOFFSETMASK, rf_reg18);*/ BB_DBG(bb, DBG_PHY_CONFIG, "[bw_setting] ADC setting for Path-%d\n, ret = %d", path, (u8)ret); return ret; } bool halbb_fwofld_bw_8852a_2(struct bb_info *bb, u8 pri_ch, enum channel_width bw, enum phl_phy_idx phy_idx, u32 *path0_rf18, u32 *path1_rf18) { bool ret = true; if (bb->is_disable_phy_api) { BB_DBG(bb, DBG_PHY_CONFIG, "[%s] Disable PHY API\n", __func__); return true; } /*==== Error handling ====*/ if (bw >= CHANNEL_WIDTH_MAX || (bw == CHANNEL_WIDTH_40 && pri_ch > 2) || (bw == CHANNEL_WIDTH_80 && pri_ch > 4)) { BB_WARNING("Fail to switch bw(bw:%d, pri ch:%d)\n", bw, pri_ch); return true; } /*==== Switch bandwidth ====*/ switch (bw) { case CHANNEL_WIDTH_5: case CHANNEL_WIDTH_10: case CHANNEL_WIDTH_20: if (bw == CHANNEL_WIDTH_5) { /*RF_BW:[31:30]=0x0 */ ret &= halbb_fw_set_reg_cmn(bb, 0x4974, 0xC0000000, 0x0, phy_idx, 0); /*small BW:[13:12]=0x1 */ ret &= halbb_fw_set_reg_cmn(bb, 0x4978, 0x3000, 0x1, phy_idx, 0); /*Pri ch:[11:8]=0x0 */ ret &= halbb_fw_set_reg_cmn(bb, 0x4978, 0xf00, 0x0, phy_idx, 0); } else if (bw == CHANNEL_WIDTH_10) { /*RF_BW:[31:30]=0x0 */ ret &= halbb_fw_set_reg_cmn(bb, 0x4974, 0xC0000000, 0x0, phy_idx, 0); /*small BW:[13:12]=0x2 */ ret &= halbb_fw_set_reg_cmn(bb, 0x4978, 0x3000, 0x2, phy_idx, 0); /*Pri ch:[11:8]=0x0 */ ret &= halbb_fw_set_reg_cmn(bb, 0x4978, 0xf00, 0x0, phy_idx, 0); } else if (bw == CHANNEL_WIDTH_20) { /*RF_BW:[31:30]=0x0 */ ret &= halbb_fw_set_reg_cmn(bb, 0x4974, 0xC0000000, 0x0, phy_idx, 0); /*small BW:[13:12]=0x0 */ ret &= halbb_fw_set_reg_cmn(bb, 0x4978, 0x3000, 0x0, phy_idx, 0); /*Pri ch:[11:8]=0x0 */ ret &= halbb_fw_set_reg_cmn(bb, 0x4978, 0xf00, 0x0, phy_idx, 0); } break; case CHANNEL_WIDTH_40: /*RF_BW:[31:30]=0x1 */ ret &= halbb_fw_set_reg_cmn(bb, 0x4974, 0xC0000000, 0x1, phy_idx, 0); /*small BW:[13:12]=0x0 */ ret &= halbb_fw_set_reg_cmn(bb, 0x4978, 0x3000, 0x0, phy_idx, 0); /*Pri ch:[11:8] */ ret &= halbb_fw_set_reg_cmn(bb, 0x4978, 0xf00, pri_ch, phy_idx, 0); /*CCK primary channel */ if (pri_ch == 1) ret &= halbb_fw_set_reg(bb, 0x237c, BIT(0), 1, 0); else ret &= halbb_fw_set_reg(bb, 0x237c, BIT(0), 0, 0); break; case CHANNEL_WIDTH_80: /*RF_BW:[31:30]=0x2 */ ret &= halbb_fw_set_reg_cmn(bb, 0x4974, 0xC0000000, 0x2, phy_idx, 0); /*small BW:[13:12]=0x0 */ ret &= halbb_fw_set_reg_cmn(bb, 0x4978, 0x3000, 0x0, phy_idx, 0); /*Pri ch:[11:8] */ ret &= halbb_fw_set_reg_cmn(bb, 0x4978, 0xf00, pri_ch, phy_idx, 0); break; default: BB_WARNING("Fail to switch bw (bw:%d, pri ch:%d)\n", bw, pri_ch); } if (phy_idx == HW_PHY_0) { /*============== [Path A] ==============*/ ret &= halbb_fw_bw_setting_8852a_2(bb, bw, RF_PATH_A, path0_rf18); /*============== [Path B] ==============*/ if (!bb->hal_com->dbcc_en) ret &= halbb_fw_bw_setting_8852a_2(bb, bw, RF_PATH_B, path1_rf18); } else { /*============== [Path B] ==============*/ ret &= halbb_fw_bw_setting_8852a_2(bb, bw, RF_PATH_B, path1_rf18); } BB_DBG(bb, DBG_PHY_CONFIG, "[Switch BW] BW: %d for PHY%d\n, ret = %d", bw, phy_idx, (u8)ret); return ret; } bool halbb_fwofld_bw_ch_8852a_2(struct bb_info *bb, u8 pri_ch, u8 central_ch, enum channel_width bw, enum phl_phy_idx phy_idx) { bool rpt = true; bool cck_en = false; bool is_2g_ch = false; u8 pri_ch_idx = 0; u32 path0_rf18 = 0; u32 path1_rf18 = 0; /*==== [Set pri_ch idx] ====*/ if (central_ch <= 14) { // === 2G === // switch (bw) { case CHANNEL_WIDTH_20: break; case CHANNEL_WIDTH_40: pri_ch_idx = pri_ch > central_ch ? 1 : 2; break; default: break; } /*==== [CCK SCO Compesate] ====*/ rpt &= halbb_fwofld_sco_cck_8852a_2(bb, pri_ch); cck_en = true; is_2g_ch = true; } else { // === 5G === // switch (bw) { case CHANNEL_WIDTH_20: break; case CHANNEL_WIDTH_40: case CHANNEL_WIDTH_80: if (pri_ch > central_ch) pri_ch_idx = (pri_ch - central_ch) >> 1; else pri_ch_idx = ((central_ch - pri_ch) >> 1) + 1; break; default: break; } cck_en = false; is_2g_ch = false; } if (!bb->hal_com->dbcc_en) { /*============== [Path A] ==============*/ path0_rf18 = halbb_read_rf_reg_8852a_2(bb, RF_PATH_A, 0x18, RFREGOFFSETMASK); /*============== [Path B] ==============*/ path1_rf18 = halbb_read_rf_reg_8852a_2(bb, RF_PATH_B, 0x18, RFREGOFFSETMASK); } else { if (phy_idx == HW_PHY_0) { /*============== [Path A] ==============*/ path0_rf18 = halbb_read_rf_reg_8852a_2(bb, RF_PATH_A, 0x18, RFREGOFFSETMASK); } else { /*============== [Path B] ==============*/ path1_rf18 = halbb_read_rf_reg_8852a_2(bb, RF_PATH_B, 0x18, RFREGOFFSETMASK); } } /*BB_WARNING("RF a/b = %x , %x", path0_rf18, path1_rf18);*/ /*==== [Switch BW] ====*/ rpt &= halbb_fwofld_bw_8852a_2(bb, pri_ch_idx, bw, phy_idx, &path0_rf18, &path1_rf18); /*BB_WARNING("SwBW : RF a/b = %x , %x", path0_rf18, path1_rf18);*/ /*==== [Switch CH] ====*/ rpt &= halbb_fwofld_ch_8852a_2(bb, central_ch, phy_idx, &path0_rf18, &path1_rf18); /*BB_WARNING("SwCH : RF a/b = %x , %x", path0_rf18, path1_rf18);*/ if (!bb->hal_com->dbcc_en) { /*============== [Path A] ==============*/ rpt &= halbb_fw_set_rf_reg_8852a_2(bb, RF_PATH_A, 0x18, RFREGOFFSETMASK, path0_rf18, 0); /*============== [Path B] ==============*/ rpt &= halbb_fw_set_rf_reg_8852a_2(bb, RF_PATH_B, 0x18, RFREGOFFSETMASK, path1_rf18, 0); } else { if (phy_idx == HW_PHY_0) { /*============== [Path A] ==============*/ rpt &= halbb_fw_set_rf_reg_8852a_2(bb, RF_PATH_A, 0x18, RFREGOFFSETMASK, path0_rf18, 0); } else { /*============== [Path B] ==============*/ rpt &= halbb_fw_set_rf_reg_8852a_2(bb, RF_PATH_B, 0x18, RFREGOFFSETMASK, path1_rf18, 0); } } /*==== [CCK Enable / Disable] ====*/ rpt &= halbb_fwofld_cck_en_8852a_2(bb, cck_en, phy_idx); /*==== [Spur elimination] ====*/ if (central_ch == 153) { rpt &= halbb_fw_set_reg(bb, 0x469c, 0xfff, 0x210, 0); rpt &= halbb_fw_set_reg(bb, 0x4770, 0xfff, 0x210, 0); rpt &= halbb_fw_set_reg(bb, 0x42ac, 0xfff, 0x7c0, 0); rpt &= halbb_fw_set_reg(bb, 0x469c, BIT(12), 0x1, 0); rpt &= halbb_fw_set_reg(bb, 0x4770, BIT(12), 0x1, 0); rpt &= halbb_fw_set_reg(bb, 0x42c4, BIT(23), 0x1, 0); } else if (central_ch == 151) { rpt &= halbb_fw_set_reg(bb, 0x469c, 0xfff, 0x210, 0); rpt &= halbb_fw_set_reg(bb, 0x4770, 0xfff, 0x210, 0); rpt &= halbb_fw_set_reg(bb, 0x42ac, 0xfff, 0x40, 0); rpt &= halbb_fw_set_reg(bb, 0x469c, BIT(12), 0x1, 0); rpt &= halbb_fw_set_reg(bb, 0x4770, BIT(12), 0x1, 0); rpt &= halbb_fw_set_reg(bb, 0x42c4, BIT(23), 0x1, 0); } else if (central_ch == 155) { rpt &= halbb_fw_set_reg(bb, 0x469c, 0xfff, 0x2d0, 0); rpt &= halbb_fw_set_reg(bb, 0x4770, 0xfff, 0x2d0, 0); rpt &= halbb_fw_set_reg(bb, 0x42ac, 0xfff, 0x740, 0); rpt &= halbb_fw_set_reg(bb, 0x469c, BIT(12), 0x1, 0); rpt &= halbb_fw_set_reg(bb, 0x4770, BIT(12), 0x1, 0); rpt &= halbb_fw_set_reg(bb, 0x42c4, BIT(23), 0x1, 0); } else { rpt &= halbb_fw_set_reg(bb, 0x469c, BIT(12), 0x0, 0); rpt &= halbb_fw_set_reg(bb, 0x4770, BIT(12), 0x0, 0); rpt &= halbb_fw_set_reg(bb, 0x42c4, BIT(23), 0x0, 0); } if (is_2g_ch && ((bb->rx_path == RF_PATH_B) || (bb->rx_path == RF_PATH_AB))) rpt &=halbb_fwofld_btg_8852a_2(bb, true); else rpt &=halbb_fwofld_btg_8852a_2(bb, false); /* Dynamic 5M Mask Setting */ rpt &=halbb_fw_5m_mask_8852a_2(bb, pri_ch, bw); /*==== [TSSI reset] ====*/ if (!bb->hal_com->dbcc_en) { // Path A rpt &= halbb_fw_set_reg(bb, 0x58dc, BIT(31) | BIT(30), 0x1, 0); rpt &= halbb_fw_set_reg(bb, 0x58dc, BIT(31) | BIT(30), 0x3, 0); // Path B rpt &= halbb_fw_set_reg(bb, 0x78dc, BIT(31) | BIT(30), 0x1, 0); rpt &= halbb_fw_set_reg(bb, 0x78dc, BIT(31) | BIT(30), 0x3, 1); } else { if (phy_idx == HW_PHY_0) { // Path A rpt &= halbb_fw_set_reg(bb, 0x58dc, BIT(31) | BIT(30), 0x1, 0); rpt &= halbb_fw_set_reg(bb, 0x58dc, BIT(31) | BIT(30), 0x3, 1); } else { // Path B rpt &= halbb_fw_set_reg(bb, 0x78dc, BIT(31) | BIT(30), 0x1, 0); rpt &= halbb_fw_set_reg(bb, 0x78dc, BIT(31) | BIT(30), 0x3, 1); } } return rpt; } #endif