/****************************************************************************** * * 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" void halbb_cfg_timers(struct bb_info *bb, enum bb_timer_cfg_t cfg, struct halbb_timer_info *timer) { BB_DBG(bb, DBG_DBG_API, "[%s] %s timer\n", __func__, ((cfg == BB_SET_TIMER) ? "SET" : ((cfg == BB_CANCEL_TIMER) ? "CANCEL" : ("RLS")))); if (cfg == BB_INIT_TIMER) { BB_WARNING("[%s]\n", __func__); return; } if (cfg == BB_SET_TIMER) { if (timer->timer_state != BB_TIMER_IDLE) { BB_WARNING("[%s] state=%d\n", __func__, timer->timer_state); return; } timer->timer_state = BB_TIMER_RUN; halbb_set_timer(bb, &timer->timer_list, timer->cb_time); } else if (cfg == BB_CANCEL_TIMER) { halbb_cancel_timer(bb, &timer->timer_list); timer->timer_state = BB_TIMER_IDLE; } else if (cfg == BB_RELEASE_TIMER) { halbb_release_timer(bb, &timer->timer_list); timer->timer_state = BB_TIMER_RELEASE; } } u32 halbb_get_sys_time(struct bb_info *bb) { return 0; } u32 halbb_phy0_to_phy1_ofst(struct bb_info *bb, u32 addr) { u32 ofst = 0; #ifdef HALBB_DBCC_SUPPORT switch (bb->ic_type) { #ifdef BB_8852A_CAV_SUPPORT case BB_RTL8852AA: ofst = halbb_phy0_to_phy1_ofst_8852a(bb, addr); break; #endif #ifdef BB_8852A_2_SUPPORT case BB_RTL8852A: ofst = halbb_phy0_to_phy1_ofst_8852a_2(bb, addr); break; #endif #ifdef BB_8852C_SUPPORT case BB_RTL8852C: ofst = halbb_phy0_to_phy1_ofst_8852c(bb, addr); break; #endif default: break; } #endif return ofst; } #ifdef BB_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_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; } #endif void halbb_set_cr(struct bb_info *bb, u32 addr, u32 val) { if (bb->bb_dbg_i.cr_recorder_en) BB_TRACE("[W] 0x%04x = 0x%08x\n", addr, val); halbb_set_32(bb, addr, val); } u32 halbb_get_cr(struct bb_info *bb, u32 addr) { u32 val = halbb_get_32(bb, addr); if (bb->bb_dbg_i.cr_recorder_en) BB_TRACE("[R] 0x%04x = 0x%08x\n", addr, val); return val; } void halbb_set_reg(struct bb_info *bb, u32 addr, u32 mask, u32 val) { u32 ori_val = 0; u32 shift; if (mask != MASKDWORD) { ori_val = halbb_get_32(bb, addr); shift = halbb_cal_bit_shift(mask); val = ((ori_val) & (~mask)) | (((val << shift)) & mask); } halbb_set_cr(bb, addr, val); } void halbb_set_reg_cmn(struct bb_info *bb, u32 addr, u32 mask, u32 val, enum phl_phy_idx phy_idx) { u32 ori_val, shift; 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 if (mask != MASKDWORD) { shift = halbb_cal_bit_shift(mask); ori_val = halbb_get_32(bb, addr); val_mod = ((ori_val) & (~mask)) | (((val << shift)) & mask); } halbb_set_cr(bb, addr, val_mod); } void halbb_set_reg_phy0_1(struct bb_info *bb, u32 addr, u32 mask, u32 val) { u32 ori_val = 0, shift = 0; u32 val_mod = val; if (mask != MASKDWORD) { shift = halbb_cal_bit_shift(mask); ori_val = halbb_get_32(bb, addr); val_mod = ((ori_val) & (~mask)) | (((val << shift)) & mask); } halbb_set_cr(bb, addr, val_mod); #ifdef HALBB_DBCC_SUPPORT if (!bb->hal_com->dbcc_en) return; addr += halbb_phy0_to_phy1_ofst(bb, addr); if (mask != MASKDWORD) { ori_val = halbb_get_32(bb, addr); val_mod = ((ori_val) & (~mask)) | (((val << shift)) & mask); } halbb_set_cr(bb, addr, val_mod); #endif } u32 halbb_get_reg(struct bb_info *bb, u32 addr, u32 mask) { u32 val_0 = 0; val_0 = (halbb_get_cr(bb, addr) & mask) >> halbb_cal_bit_shift(mask); return val_0; } u32 halbb_get_reg_cmn(struct bb_info *bb, u32 addr, u32 mask, enum phl_phy_idx phy_idx) { u32 val_0 = 0; #ifdef HALBB_DBCC_SUPPORT if (bb->hal_com->dbcc_en && phy_idx == HW_PHY_1) addr += halbb_phy0_to_phy1_ofst(bb, addr); #endif val_0 = (halbb_get_cr(bb, addr) & mask) >> halbb_cal_bit_shift(mask); return val_0; } u32 halbb_get_reg_phy0_1(struct bb_info *bb, u32 addr, u32 mask, u32 *val_1) { u32 val_0 = 0; u32 shift = halbb_cal_bit_shift(mask); val_0 = (halbb_get_cr(bb, addr) & mask) >> shift; #ifdef HALBB_DBCC_SUPPORT if (!bb->hal_com->dbcc_en) return val_0; addr += halbb_phy0_to_phy1_ofst(bb, addr); *val_1 = (halbb_get_cr(bb, addr) & mask) >> shift; #endif return val_0; } bool halbb_fill_h2c_cmd(struct bb_info *bb, u16 cmdlen, u8 cmdid, u8 classid, u32 *pval) { u32 rt_val = 0; struct rtw_g6_h2c_hdr hdr = {0}; struct rtw_hal_com_t *hal_com = NULL; hdr.h2c_class = classid; hdr.h2c_func = cmdid; hdr.content_len = cmdlen; hdr.type = H2CB_TYPE_LONG_DATA; hdr.rec_ack = 0; hdr.done_ack = 0; hal_com = bb->hal_com; BB_DBG(bb, DBG_FW_INFO, "H2C: %x %x %x\n", classid, cmdid, cmdlen); rt_val = rtw_hal_mac_send_h2c(hal_com, &hdr, pval); if (rt_val != 0) { BB_WARNING("Error H2C CLASS=%d, ID=%d, Rt_v = %d\n", classid, cmdid, rt_val); return false; } else { return true; } } bool halbb_test_h2c_c2h_flow(struct bb_info *bb) { u32 rt_val = 0; u32 *bb_h2c; u8 h2ctest[4] = {1, 0, 0, 0}; bb_h2c = (u32 *) &h2ctest; rt_val = halbb_fill_h2c_cmd(bb, 1, DM_H2C_FW_H2C_TEST, HALBB_H2C_DM, bb_h2c); if (rt_val != 0) { BB_WARNING("Error H2C TEST\n"); return false; } else { return true; } } u32 halbb_c2h_rua_parsing(struct bb_info *bb, u8 cmdid, u8 len, u8 *c2h) { u32 val = 0; return val; } u32 halbb_c2h_mu_gptbl_rpt(struct bb_info *bb, u16 len, u8 *c2h) { /* Set MU grouping table and return value */ u32 val = 0; u8 i = 0; u8 j = 0; u8 k = 0; u8 mask = 0x03; struct hal_mu_score_tbl *mu_sc_tbl = &bb->hal_com->bb_mu_score_tbl; /* Need to do MU protect to prevent error c2h sending this function will be return to prevent error c2h */ return val; for (i = 0; i < HAL_MAX_MU_STA_NUM; i++) for (j = 0; j < HAL_MAX_MU_SCORE_SIZE; j++) { if (mask == 0x03) { mu_sc_tbl->mu_score[i].score[j] = (c2h[k]&mask); mask = mask <<2; } else if (mask == 0x0c) { mu_sc_tbl->mu_score[i].score[j] = (c2h[k]&mask)>>2; mask = mask <<2; } else if (mask == 0x30) { mu_sc_tbl->mu_score[i].score[j] = (c2h[k]&mask)>>4; mask = mask <<2; } else { /*(mask == 0xc0) */ mu_sc_tbl->mu_score[i].score[j] = (c2h[k]&mask)>>6; mask = 0x03; k++; } } return val; } #ifdef HALBB_DYN_L2H_SUPPORT u32 halbb_c2h_lowrt_rty(struct bb_info *bb, u16 len, u8 *c2h) { u32 c2h_rty_cnt = 0; struct bb_dyn_l2h_info *dyn_l2h_i = &bb->bb_dyn_l2h_i; c2h_rty_cnt = (*c2h) + ((*(c2h+1))<<8); dyn_l2h_i->low_rate_rty_cnt += c2h_rty_cnt; return 0; } void halbb_fw_ctrl_rtyrpt(struct bb_info *bb, u8 rpt_rtycnt, u8 en_fw_rpt) { struct bb_fw_dbg_cmn_info *fwmn_i = &bb->bb_fwdbg_i; u32 *bb_h2c = (u32 *) fwmn_i; u8 cmdlen = sizeof(struct bb_fw_dbg_cmn_info); bool ret_val = false; fwmn_i->fw_cmn_info |= (en_fw_rpt & 0x01); fwmn_i->fw_rty_rpt_ctrl = rpt_rtycnt; BB_DBG(bb, DBG_FW_INFO, "FW CTRL RTYRPT: %d %d\n", fwmn_i->fw_cmn_info, fwmn_i->fw_rty_rpt_ctrl); BB_DBG(bb, DBG_FW_INFO, "FW CMN CTRL: %x %x\n", bb_h2c[0], bb_h2c[1]); ret_val = halbb_fill_h2c_cmd(bb, cmdlen, DM_H2C_FWTRACE, HALBB_H2C_DM, bb_h2c); } #endif /* Remove after 8852A B cut */ /* u32 halbb_c2h_fw_trig_tx_rpt(struct bb_info *bb, u16 len, u8 *c2h) { struct bb_c2h_fw_tx_rpt *fw_tx_i = &bb->bb_fwtx_c2h_i; bool tx_stat = c2h[0] & BIT(0); u32 val = (u32)false; if (tx_stat) { BB_DBG(bb, DBG_FW_INFO, "[FW][C2H] Tx done\n"); } else { BB_DBG(bb, DBG_FW_INFO, "[FW][C2H] Tx fail\n"); } // PD hit enable halbb_set_reg(bb, 0xa3c, BIT(9), 0); halbb_set_reg(bb, 0xabc, BIT(9), 0); fw_tx_i->tx_done = tx_stat; val = (u32)true; return val; }*/ u32 halbb_c2h_fw_h2c_test(struct bb_info *bb, u16 len, u8 *c2h) { u16 i; u32 val = (u32)false; for (i = 0; i < len; i++) { BB_DBG(bb, DBG_FW_INFO, "FW H2C and C2H test: %d\n", c2h[i]); } return val; } u32 halbb_c2h_ra_parsing(struct bb_info *bb, u8 cmdid, u16 len, u8 *c2h) { u32 val = 0; u16 i; BB_DBG(bb, DBG_FW_INFO, "FW C2H RA parsing: cmdid:%d len:%d\n", cmdid, len); BB_DBG(bb, DBG_FW_INFO, "FW C2H RA parsing: content ==>"); for (i = 0; i < len; i++) BB_DBG(bb, DBG_FW_INFO, "%x", *(c2h+i)); BB_DBG(bb, DBG_FW_INFO, "<== \n "); switch(cmdid) { case HALBB_C2HRA_STS_RPT: val = halbb_get_fw_ra_rpt(bb, len, c2h); break; case HALBB_C2HRA_MU_GPTBL_RPT: val = halbb_c2h_mu_gptbl_rpt(bb, len, c2h); break; case HALBB_C2HRA_TXSTS: val = halbb_get_txsts_rpt(bb, len, c2h); break; default: break; } return val; } u32 halbb_c2h_dm_parsing(struct bb_info *bb, u8 cmdid, u16 len, u8 *c2h) { u32 val = 0; u16 i; BB_DBG(bb, DBG_FW_INFO, "FW C2H DM parsing: cmdid:%d len:%d\n", cmdid, len); BB_DBG(bb, DBG_FW_INFO, "FW C2H DM parsing: content ==>"); for (i = 0; i < len; i++) BB_DBG(bb, DBG_FW_INFO, "%x", *(c2h+i)); BB_DBG(bb, DBG_FW_INFO, "<== \n "); switch(cmdid) { case DM_C2H_FW_TEST: val = halbb_c2h_fw_h2c_test(bb, len, c2h); break; case DM_C2H_FW_TRIG_TX_RPT: /* Remove after 8852A B cut */ break; #ifdef HALBB_DYN_L2H_SUPPORT case DM_C2H_LOWRT_RTY: val = halbb_c2h_lowrt_rty(bb, len, c2h); break; #endif #ifdef HALBB_DIG_MCC_SUPPORT case DM_C2H_MCC_DIG: val = halbb_c2h_mccdm_check(bb, len, c2h); break; #endif default: break; } return val; } u32 rtw_halbb_c2h_parsing(struct bb_info *bb, u8 classid, u8 cmdid, u16 len, u8 *c2h) { u32 val = 0; switch(classid) { case HALBB_C2H_RUA: break; case HALBB_C2H_RA: val = halbb_c2h_ra_parsing(bb, cmdid, len, c2h); break; case HALBB_C2H_DM: val = halbb_c2h_dm_parsing(bb, cmdid, len, c2h); break; default: break; } return val; } u8 halbb_set_cmac_txpwr_mode(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { /* power by macid */ return 0; } u8 halbb_set_cmac_ntx_en(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { return 1; } u8 halbb_set_cmac_path_map_a(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { return 0; } u8 halbb_set_cmac_path_map_b(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { return 1; } u8 halbb_set_cmac_path_map_c(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { return 2; } u8 halbb_set_cmac_path_map_d(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { return 3; } u8 halbb_set_cmac_antsel_a(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { /* antenna selection*/ return 0; } u8 halbb_set_cmac_antsel_b(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { return 0; } u8 halbb_set_cmac_antsel_c(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { return 0; } u8 halbb_set_cmac_antsel_d(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { return 0; } u8 halbb_set_cmac_pwr_tol(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { return 0; } u8 halbb_set_cmac_databw_er(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { /* 0: RU242, 1:RU106*/ return 0; } bool halbb_set_pwr_by_rate_tbl(struct bb_info *bb, struct rtw_phl_stainfo_t *phl_sta_i) { struct halbb_pwr_by_rate_tbl pwr_t = {{0}}; u8 i = 0; enum rtw_data_rate ru_pwr_rate[PWR_TBL_NUM] = {RTW_DATA_RATE_HE_NSS1_MCS0, RTW_DATA_RATE_HE_NSS1_MCS1, RTW_DATA_RATE_HE_NSS1_MCS2, RTW_DATA_RATE_HE_NSS1_MCS3, RTW_DATA_RATE_HE_NSS1_MCS4, RTW_DATA_RATE_HE_NSS1_MCS5, RTW_DATA_RATE_HE_NSS1_MCS6, RTW_DATA_RATE_HE_NSS1_MCS7, RTW_DATA_RATE_HE_NSS1_MCS8, RTW_DATA_RATE_HE_NSS1_MCS9, RTW_DATA_RATE_HE_NSS1_MCS10, RTW_DATA_RATE_HE_NSS1_MCS11, RTW_DATA_RATE_HE_NSS2_MCS0, RTW_DATA_RATE_HE_NSS2_MCS1, RTW_DATA_RATE_HE_NSS2_MCS2, RTW_DATA_RATE_HE_NSS2_MCS3, RTW_DATA_RATE_HE_NSS2_MCS4, RTW_DATA_RATE_HE_NSS2_MCS5, RTW_DATA_RATE_HE_NSS2_MCS6, RTW_DATA_RATE_HE_NSS2_MCS7, RTW_DATA_RATE_HE_NSS2_MCS8, RTW_DATA_RATE_HE_NSS2_MCS9, RTW_DATA_RATE_HE_NSS2_MCS10, RTW_DATA_RATE_HE_NSS2_MCS11, RTW_DATA_RATE_HE_NSS1_MCS0, RTW_DATA_RATE_HE_NSS1_MCS1, RTW_DATA_RATE_HE_NSS1_MCS3, RTW_DATA_RATE_HE_NSS1_MCS4, RTW_DATA_RATE_HE_NSS2_MCS0, RTW_DATA_RATE_HE_NSS2_MCS1, RTW_DATA_RATE_HE_NSS2_MCS3, RTW_DATA_RATE_HE_NSS2_MCS4}; u32 *pval = (u32 *)&pwr_t; u8 cmdlen = sizeof(pwr_t); u8 dcm = 0; enum rtw_data_rate rate; enum channel_width bw = phl_sta_i->chandef.bw; u8 channel = phl_sta_i->chandef.center_ch; s16 pwr_db = 0; for (i = 0; i < PWR_TBL_NUM; i++) { rate = ru_pwr_rate[i]; if (i >=24) dcm = 1; /*rtw_hal_rf_read_pwr_table(bb->hal_com, 0, rate, bw, channel, 0, dcm, 0, &pwr_db);*/ pwr_t.pwr_by_rate[i*2] = (u8)(pwr_db&0xff); pwr_t.pwr_by_rate[i*2+1] = (u8)((pwr_db>>8)&0xff); } /* Get pwr by rate tbl from halrf */ halbb_fill_h2c_cmd(bb, cmdlen, RUA_H2C_PWR_TBL, HALBB_H2C_RUA, pval); return false; }