// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2024 Realtek Corporation
*/
#include <linux/usb.h>
#include "main.h"
#include "coex.h"
#include "phy.h"
#include "rtw88xxa.h"
#include "mac.h"
#include "reg.h"
#include "sec.h"
#include "debug.h"
#include "bf.h"
#include "efuse.h"
#include "usb.h"
void rtw88xxa_efuse_grant(struct rtw_dev *rtwdev, bool on)
{
if (on) {
rtw_write8(rtwdev, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON);
rtw_write16_set(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_ELDR);
rtw_write16_set(rtwdev, REG_SYS_CLKR,
BIT_LOADER_CLK_EN | BIT_ANA8M);
} else {
rtw_write8(rtwdev, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF);
}
}
EXPORT_SYMBOL(rtw88xxa_efuse_grant);
static void rtw8812a_read_amplifier_type(struct rtw_dev *rtwdev)
{
struct rtw_efuse *efuse = &rtwdev->efuse;
efuse->ext_pa_2g = (efuse->pa_type_2g & BIT(5 )) &&
(efuse->pa_type_2g & BIT(4 ));
efuse->ext_lna_2g = (efuse->lna_type_2g & BIT(7 )) &&
(efuse->lna_type_2g & BIT(3 ));
efuse->ext_pa_5g = (efuse->pa_type_5g & BIT(1 )) &&
(efuse->pa_type_5g & BIT(0 ));
efuse->ext_lna_5g = (efuse->lna_type_5g & BIT(7 )) &&
(efuse->lna_type_5g & BIT(3 ));
/* For rtw_phy_cond2: */
if (efuse->ext_pa_2g) {
u8 ext_type_pa_2g_a = u8_get_bits(efuse->lna_type_2g, BIT(2 ));
u8 ext_type_pa_2g_b = u8_get_bits(efuse->lna_type_2g, BIT(6 ));
efuse->gpa_type = (ext_type_pa_2g_b << 2 ) | ext_type_pa_2g_a;
}
if (efuse->ext_pa_5g) {
u8 ext_type_pa_5g_a = u8_get_bits(efuse->lna_type_5g, BIT(2 ));
u8 ext_type_pa_5g_b = u8_get_bits(efuse->lna_type_5g, BIT(6 ));
efuse->apa_type = (ext_type_pa_5g_b << 2 ) | ext_type_pa_5g_a;
}
if (efuse->ext_lna_2g) {
u8 ext_type_lna_2g_a = u8_get_bits(efuse->lna_type_2g,
BIT(1 ) | BIT(0 ));
u8 ext_type_lna_2g_b = u8_get_bits(efuse->lna_type_2g,
BIT(5 ) | BIT(4 ));
efuse->glna_type = (ext_type_lna_2g_b << 2 ) | ext_type_lna_2g_a;
}
if (efuse->ext_lna_5g) {
u8 ext_type_lna_5g_a = u8_get_bits(efuse->lna_type_5g,
BIT(1 ) | BIT(0 ));
u8 ext_type_lna_5g_b = u8_get_bits(efuse->lna_type_5g,
BIT(5 ) | BIT(4 ));
efuse->alna_type = (ext_type_lna_5g_b << 2 ) | ext_type_lna_5g_a;
}
}
static void rtw8812a_read_rfe_type(struct rtw_dev *rtwdev,
struct rtw88xxa_efuse *map)
{
struct rtw_efuse *efuse = &rtwdev->efuse;
if (map->rfe_option == 0 xff) {
if (rtwdev->hci.type == RTW_HCI_TYPE_USB)
efuse->rfe_option = 0 ;
else if (rtwdev->hci.type == RTW_HCI_TYPE_PCIE)
efuse->rfe_option = 2 ;
else
efuse->rfe_option = 4 ;
} else if (map->rfe_option & BIT(7 )) {
if (efuse->ext_lna_5g) {
if (efuse->ext_pa_5g) {
if (efuse->ext_lna_2g && efuse->ext_pa_2g)
efuse->rfe_option = 3 ;
else
efuse->rfe_option = 0 ;
} else {
efuse->rfe_option = 2 ;
}
} else {
efuse->rfe_option = 4 ;
}
} else {
efuse->rfe_option = map->rfe_option & 0 x3f;
/* Due to other customer already use incorrect EFUSE map for
* their product. We need to add workaround to prevent to
* modify spec and notify all customer to revise the IC 0xca
* content.
*/
if (efuse->rfe_option == 4 &&
(efuse->ext_pa_5g || efuse->ext_pa_2g ||
efuse->ext_lna_5g || efuse->ext_lna_2g)) {
if (rtwdev->hci.type == RTW_HCI_TYPE_USB)
efuse->rfe_option = 0 ;
else if (rtwdev->hci.type == RTW_HCI_TYPE_PCIE)
efuse->rfe_option = 2 ;
}
}
}
static void rtw88xxa_read_usb_type(struct rtw_dev *rtwdev)
{
struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_hal *hal = &rtwdev->hal;
u8 antenna = 0 ;
u8 wmode = 0 ;
u8 val8, i;
efuse->hw_cap.bw = BIT(RTW_CHANNEL_WIDTH_20) |
BIT(RTW_CHANNEL_WIDTH_40) |
BIT(RTW_CHANNEL_WIDTH_80);
efuse->hw_cap.ptcl = EFUSE_HW_CAP_PTCL_VHT;
if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A)
efuse->hw_cap.nss = 1 ;
else
efuse->hw_cap.nss = 2 ;
if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A)
goto print_hw_cap;
for (i = 0 ; i < 2 ; i++) {
rtw_read8_physical_efuse(rtwdev, 1019 - i, &val8);
antenna = u8_get_bits(val8, GENMASK(7 , 5 ));
if (antenna)
break ;
antenna = u8_get_bits(val8, GENMASK(3 , 1 ));
if (antenna)
break ;
}
for (i = 0 ; i < 2 ; i++) {
rtw_read8_physical_efuse(rtwdev, 1021 - i, &val8);
wmode = u8_get_bits(val8, GENMASK(3 , 2 ));
if (wmode)
break ;
}
if (antenna == 1 ) {
rtw_info(rtwdev, "This RTL8812AU says it is 1T1R.\n" );
efuse->hw_cap.nss = 1 ;
hal->rf_type = RF_1T1R;
hal->rf_path_num = 1 ;
hal->rf_phy_num = 1 ;
hal->antenna_tx = BB_PATH_A;
hal->antenna_rx = BB_PATH_A;
} else {
/* Override rtw_chip_parameter_setup(). It detects 8812au as 1T1R. */
efuse->hw_cap.nss = 2 ;
hal->rf_type = RF_2T2R;
hal->rf_path_num = 2 ;
hal->rf_phy_num = 2 ;
hal->antenna_tx = BB_PATH_AB;
hal->antenna_rx = BB_PATH_AB;
if (antenna == 2 && wmode == 2 ) {
rtw_info(rtwdev, "This RTL8812AU says it can't do VHT.\n" );
/* Can't be EFUSE_HW_CAP_IGNORE and can't be
* EFUSE_HW_CAP_PTCL_VHT, so make it 1.
*/
efuse->hw_cap.ptcl = 1 ;
efuse->hw_cap.bw &= ~BIT(RTW_CHANNEL_WIDTH_80);
}
}
print_hw_cap:
rtw_dbg(rtwdev, RTW_DBG_EFUSE,
"hw cap: hci=0x%02x, bw=0x%02x, ptcl=0x%02x, ant_num=%d, nss=%d\n" ,
efuse->hw_cap.hci, efuse->hw_cap.bw, efuse->hw_cap.ptcl,
efuse->hw_cap.ant_num, efuse->hw_cap.nss);
}
int rtw88xxa_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw88xxa_efuse *map;
int i;
if (chip->id == RTW_CHIP_TYPE_8812A)
rtwdev->hal.cut_version += 1 ;
if (rtw_dbg_is_enabled(rtwdev, RTW_DBG_EFUSE))
print_hex_dump(KERN_INFO, "" , DUMP_PREFIX_OFFSET, 16 , 1 ,
log_map, chip->log_efuse_size, true );
map = (struct rtw88xxa_efuse *)log_map;
efuse->rf_board_option = map->rf_board_option;
efuse->crystal_cap = map->xtal_k;
if (efuse->crystal_cap == 0 xff)
efuse->crystal_cap = 0 x20;
efuse->pa_type_2g = map->pa_type;
efuse->pa_type_5g = map->pa_type;
efuse->lna_type_2g = map->lna_type_2g;
efuse->lna_type_5g = map->lna_type_5g;
if (chip->id == RTW_CHIP_TYPE_8812A) {
rtw8812a_read_amplifier_type(rtwdev);
rtw8812a_read_rfe_type(rtwdev, map);
efuse->usb_mode_switch = u8_get_bits(map->usb_mode, BIT(1 ));
}
efuse->channel_plan = map->channel_plan;
efuse->country_code[0 ] = map->country_code[0 ];
efuse->country_code[1 ] = map->country_code[1 ];
efuse->bt_setting = map->rf_bt_setting;
efuse->regd = map->rf_board_option & 0 x7;
efuse->thermal_meter[0 ] = map->thermal_meter;
efuse->thermal_meter[1 ] = map->thermal_meter;
efuse->thermal_meter_k = map->thermal_meter;
efuse->tx_bb_swing_setting_2g = map->tx_bb_swing_setting_2g;
efuse->tx_bb_swing_setting_5g = map->tx_bb_swing_setting_5g;
rtw88xxa_read_usb_type(rtwdev);
if (chip->id == RTW_CHIP_TYPE_8821A)
efuse->btcoex = rtw_read32_mask(rtwdev, REG_WL_BT_PWR_CTRL,
BIT_BT_FUNC_EN);
else
efuse->btcoex = (map->rf_board_option & 0 xe0) == 0 x20;
efuse->share_ant = !!(efuse->bt_setting & BIT(0 ));
/* No antenna diversity because it's disabled in the vendor driver */
efuse->ant_div_cfg = 0 ;
efuse->ant_div_type = map->rf_antenna_option;
if (efuse->ant_div_type == 0 xff)
efuse->ant_div_type = 0 x3;
for (i = 0 ; i < 4 ; i++)
efuse->txpwr_idx_table[i] = map->txpwr_idx_table[i];
switch (rtw_hci_type(rtwdev)) {
case RTW_HCI_TYPE_USB:
if (chip->id == RTW_CHIP_TYPE_8821A)
ether_addr_copy(efuse->addr, map->rtw8821au.mac_addr);
else
ether_addr_copy(efuse->addr, map->rtw8812au.mac_addr);
break ;
case RTW_HCI_TYPE_PCIE:
case RTW_HCI_TYPE_SDIO:
default :
/* unsupported now */
return -EOPNOTSUPP;
}
return 0 ;
}
EXPORT_SYMBOL(rtw88xxa_read_efuse);
static void rtw88xxa_reset_8051(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
u8 val8;
/* Reset MCU IO Wrapper */
rtw_write8_clr(rtwdev, REG_RSV_CTRL, BIT(1 ));
if (chip->id == RTW_CHIP_TYPE_8812A)
rtw_write8_clr(rtwdev, REG_RSV_CTRL + 1 , BIT(3 ));
else
rtw_write8_clr(rtwdev, REG_RSV_CTRL + 1 , BIT(0 ));
val8 = rtw_read8(rtwdev, REG_SYS_FUNC_EN + 1 );
rtw_write8(rtwdev, REG_SYS_FUNC_EN + 1 , val8 & ~BIT(2 ));
/* Enable MCU IO Wrapper */
rtw_write8_clr(rtwdev, REG_RSV_CTRL, BIT(1 ));
if (chip->id == RTW_CHIP_TYPE_8812A)
rtw_write8_set(rtwdev, REG_RSV_CTRL + 1 , BIT(3 ));
else
rtw_write8_set(rtwdev, REG_RSV_CTRL + 1 , BIT(0 ));
rtw_write8(rtwdev, REG_SYS_FUNC_EN + 1 , val8 | BIT(2 ));
}
/* A lightweight deinit function */
static void rtw88xxau_hw_reset(struct rtw_dev *rtwdev)
{
u8 val8;
if (!(rtw_read8(rtwdev, REG_MCUFW_CTRL) & BIT_RAM_DL_SEL))
return ;
rtw88xxa_reset_8051(rtwdev);
rtw_write8(rtwdev, REG_MCUFW_CTRL, 0 x00);
/* before BB reset should do clock gated */
rtw_write32_set(rtwdev, REG_FPGA0_XCD_RF_PARA, BIT(6 ));
/* reset BB */
rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN, BIT(0 ) | BIT(1 ));
/* reset RF */
rtw_write8(rtwdev, REG_RF_CTRL, 0 );
/* reset TRX path */
rtw_write16(rtwdev, REG_CR, 0 );
/* reset MAC, reg0x5[1], auto FSM off */
rtw_write8_set(rtwdev, REG_APS_FSMCO + 1 , APS_FSMCO_MAC_OFF >> 8 );
/* check if reg0x5[1] auto cleared */
if (read_poll_timeout_atomic(rtw_read8, val8,
!(val8 & (APS_FSMCO_MAC_OFF >> 8 )),
1 , 5000 , false ,
rtwdev, REG_APS_FSMCO + 1 ))
rtw_err(rtwdev, "%s: timed out waiting for 0x5[1]\n" , __func__);
/* reg0x5[0], auto FSM on */
val8 |= APS_FSMCO_MAC_ENABLE >> 8 ;
rtw_write8(rtwdev, REG_APS_FSMCO + 1 , val8);
rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN + 1 , BIT(4 ) | BIT(7 ));
rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1 , BIT(4 ) | BIT(7 ));
}
static int rtw88xxau_init_power_on(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
u16 val16;
int ret;
ret = rtw_pwr_seq_parser(rtwdev, chip->pwr_on_seq);
if (ret) {
rtw_err(rtwdev, "power on flow failed\n" );
return ret;
}
rtw_write16(rtwdev, REG_CR, 0 );
val16 = BIT_HCI_TXDMA_EN | BIT_HCI_RXDMA_EN | BIT_TXDMA_EN |
BIT_RXDMA_EN | BIT_PROTOCOL_EN | BIT_SCHEDULE_EN |
BIT_MAC_SEC_EN | BIT_32K_CAL_TMR_EN;
rtw_write16_set(rtwdev, REG_CR, val16);
if (chip->id == RTW_CHIP_TYPE_8821A) {
if (rtw_read8(rtwdev, REG_SYS_CFG1 + 3 ) & BIT(0 ))
rtw_write8_set(rtwdev, REG_LDO_SWR_CTRL, BIT(6 ));
}
return ret;
}
static int rtw88xxa_llt_write(struct rtw_dev *rtwdev, u32 address, u32 data)
{
u32 value = BIT_LLT_WRITE_ACCESS | (address << 8 ) | data;
int count = 0 ;
rtw_write32(rtwdev, REG_LLT_INIT, value);
do {
if (!rtw_read32_mask(rtwdev, REG_LLT_INIT, BIT(31 ) | BIT(30 )))
break ;
if (count > 20 ) {
rtw_err(rtwdev, "Failed to poll write LLT done at %d!\n" ,
address);
return -EBUSY;
}
} while (++count);
return 0 ;
}
static int rtw88xxa_llt_init(struct rtw_dev *rtwdev, u32 boundary)
{
u32 last_entry = 255 ;
int status = 0 ;
u32 i;
for (i = 0 ; i < boundary - 1 ; i++) {
status = rtw88xxa_llt_write(rtwdev, i, i + 1 );
if (status)
return status;
}
status = rtw88xxa_llt_write(rtwdev, boundary - 1 , 0 xFF);
if (status)
return status;
for (i = boundary; i < last_entry; i++) {
status = rtw88xxa_llt_write(rtwdev, i, i + 1 );
if (status)
return status;
}
status = rtw88xxa_llt_write(rtwdev, last_entry, boundary);
return status;
}
static void rtw88xxau_init_queue_reserved_page(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_fifo_conf *fifo = &rtwdev->fifo;
const struct rtw_page_table *pg_tbl = NULL;
u16 pubq_num;
u32 val32;
switch (rtw_hci_type(rtwdev)) {
case RTW_HCI_TYPE_PCIE:
pg_tbl = &chip->page_table[1 ];
break ;
case RTW_HCI_TYPE_USB:
if (rtwdev->hci.bulkout_num == 2 )
pg_tbl = &chip->page_table[2 ];
else if (rtwdev->hci.bulkout_num == 3 )
pg_tbl = &chip->page_table[3 ];
else if (rtwdev->hci.bulkout_num == 4 )
pg_tbl = &chip->page_table[4 ];
break ;
case RTW_HCI_TYPE_SDIO:
pg_tbl = &chip->page_table[0 ];
break ;
default :
break ;
}
pubq_num = fifo->acq_pg_num - pg_tbl->hq_num - pg_tbl->lq_num -
pg_tbl->nq_num - pg_tbl->exq_num - pg_tbl->gapq_num;
val32 = BIT_RQPN_NE(pg_tbl->nq_num, pg_tbl->exq_num);
rtw_write32(rtwdev, REG_RQPN_NPQ, val32);
val32 = BIT_RQPN_HLP(pg_tbl->hq_num, pg_tbl->lq_num, pubq_num);
rtw_write32(rtwdev, REG_RQPN, val32);
}
static void rtw88xxau_init_tx_buffer_boundary(struct rtw_dev *rtwdev)
{
struct rtw_fifo_conf *fifo = &rtwdev->fifo;
rtw_write8(rtwdev, REG_BCNQ_BDNY, fifo->rsvd_boundary);
rtw_write8(rtwdev, REG_MGQ_BDNY, fifo->rsvd_boundary);
rtw_write8(rtwdev, REG_WMAC_LBK_BF_HD, fifo->rsvd_boundary);
rtw_write8(rtwdev, REG_TRXFF_BNDY, fifo->rsvd_boundary);
rtw_write8(rtwdev, REG_DWBCN0_CTRL + 1 , fifo->rsvd_boundary);
}
static int rtw88xxau_init_queue_priority(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
u8 bulkout_num = rtwdev->hci.bulkout_num;
const struct rtw_rqpn *rqpn = NULL;
u16 txdma_pq_map;
switch (rtw_hci_type(rtwdev)) {
case RTW_HCI_TYPE_PCIE:
rqpn = &chip->rqpn_table[1 ];
break ;
case RTW_HCI_TYPE_USB:
if (bulkout_num == 2 )
rqpn = &chip->rqpn_table[2 ];
else if (bulkout_num == 3 )
rqpn = &chip->rqpn_table[3 ];
else if (bulkout_num == 4 )
rqpn = &chip->rqpn_table[4 ];
else
return -EINVAL;
break ;
case RTW_HCI_TYPE_SDIO:
rqpn = &chip->rqpn_table[0 ];
break ;
default :
return -EINVAL;
}
rtwdev->fifo.rqpn = rqpn;
txdma_pq_map = rtw_read16(rtwdev, REG_TXDMA_PQ_MAP) & 0 x7;
txdma_pq_map |= BIT_TXDMA_HIQ_MAP(rqpn->dma_map_hi);
txdma_pq_map |= BIT_TXDMA_MGQ_MAP(rqpn->dma_map_mg);
txdma_pq_map |= BIT_TXDMA_BKQ_MAP(rqpn->dma_map_bk);
txdma_pq_map |= BIT_TXDMA_BEQ_MAP(rqpn->dma_map_be);
txdma_pq_map |= BIT_TXDMA_VIQ_MAP(rqpn->dma_map_vi);
txdma_pq_map |= BIT_TXDMA_VOQ_MAP(rqpn->dma_map_vo);
rtw_write16(rtwdev, REG_TXDMA_PQ_MAP, txdma_pq_map);
/* Packet in Hi Queue Tx immediately (No constraint for ATIM Period). */
if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB && bulkout_num == 4 )
rtw_write8(rtwdev, REG_HIQ_NO_LMT_EN, 0 xff);
return 0 ;
}
static void rtw88xxa_init_wmac_setting(struct rtw_dev *rtwdev)
{
rtw_write16(rtwdev, REG_RXFLTMAP0, 0 xffff);
rtw_write16(rtwdev, REG_RXFLTMAP1, 0 x0400);
rtw_write16(rtwdev, REG_RXFLTMAP2, 0 xffff);
rtw_write32(rtwdev, REG_MAR, 0 xffffffff);
rtw_write32(rtwdev, REG_MAR + 4 , 0 xffffffff);
}
static void rtw88xxa_init_adaptive_ctrl(struct rtw_dev *rtwdev)
{
rtw_write32_mask(rtwdev, REG_RRSR, 0 xfffff, 0 xffff1);
rtw_write16(rtwdev, REG_RETRY_LIMIT, 0 x3030);
}
static void rtw88xxa_init_edca(struct rtw_dev *rtwdev)
{
rtw_write16(rtwdev, REG_SPEC_SIFS, 0 x100a);
rtw_write16(rtwdev, REG_MAC_SPEC_SIFS, 0 x100a);
rtw_write16(rtwdev, REG_SIFS, 0 x100a);
rtw_write16(rtwdev, REG_SIFS + 2 , 0 x100a);
rtw_write32(rtwdev, REG_EDCA_BE_PARAM, 0 x005EA42B);
rtw_write32(rtwdev, REG_EDCA_BK_PARAM, 0 x0000A44F);
rtw_write32(rtwdev, REG_EDCA_VI_PARAM, 0 x005EA324);
rtw_write32(rtwdev, REG_EDCA_VO_PARAM, 0 x002FA226);
rtw_write8(rtwdev, REG_USTIME_TSF, 0 x50);
rtw_write8(rtwdev, REG_USTIME_EDCA, 0 x50);
}
static void rtw88xxau_tx_aggregation(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
rtw_write32_mask(rtwdev, REG_DWBCN0_CTRL, 0 xf0,
chip->usb_tx_agg_desc_num);
if (chip->id == RTW_CHIP_TYPE_8821A)
rtw_write8(rtwdev, REG_DWBCN1_CTRL,
chip->usb_tx_agg_desc_num << 1 );
}
static void rtw88xxa_init_beacon_parameters(struct rtw_dev *rtwdev)
{
u16 val16;
val16 = (BIT_DIS_TSF_UDT << 8 ) | BIT_DIS_TSF_UDT;
if (rtwdev->efuse.btcoex)
val16 |= BIT_EN_BCN_FUNCTION;
rtw_write16(rtwdev, REG_BCN_CTRL, val16);
rtw_write32_mask(rtwdev, REG_TBTT_PROHIBIT, 0 xfffff, WLAN_TBTT_TIME);
rtw_write8(rtwdev, REG_DRVERLYINT, 0 x05);
rtw_write8(rtwdev, REG_BCNDMATIM, WLAN_BCN_DMA_TIME);
rtw_write16(rtwdev, REG_BCNTCFG, 0 x4413);
}
static void rtw88xxa_phy_bb_config(struct rtw_dev *rtwdev)
{
u8 val8, crystal_cap;
/* power on BB/RF domain */
val8 = rtw_read8(rtwdev, REG_SYS_FUNC_EN);
val8 |= BIT_FEN_USBA;
rtw_write8(rtwdev, REG_SYS_FUNC_EN, val8);
/* toggle BB reset */
val8 |= BIT_FEN_BB_RSTB | BIT_FEN_BB_GLB_RST;
rtw_write8(rtwdev, REG_SYS_FUNC_EN, val8);
rtw_write8(rtwdev, REG_RF_CTRL,
BIT_RF_EN | BIT_RF_RSTB | BIT_RF_SDM_RSTB);
rtw_write8(rtwdev, REG_RF_B_CTRL,
BIT_RF_EN | BIT_RF_RSTB | BIT_RF_SDM_RSTB);
rtw_load_table(rtwdev, rtwdev->chip->bb_tbl);
rtw_load_table(rtwdev, rtwdev->chip->agc_tbl);
crystal_cap = rtwdev->efuse.crystal_cap & 0 x3F;
if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A)
rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0 x7FF80000,
crystal_cap | (crystal_cap << 6 ));
else
rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0 x00FFF000,
crystal_cap | (crystal_cap << 6 ));
}
static void rtw88xxa_phy_rf_config(struct rtw_dev *rtwdev)
{
u8 rf_path;
for (rf_path = 0 ; rf_path < rtwdev->hal.rf_path_num; rf_path++)
rtw_load_table(rtwdev, rtwdev->chip->rf_tbl[rf_path]);
}
static void rtw8812a_config_1t(struct rtw_dev *rtwdev)
{
/* BB OFDM RX Path_A */
rtw_write32_mask(rtwdev, REG_RXPSEL, 0 xff, 0 x11);
/* BB OFDM TX Path_A */
rtw_write32_mask(rtwdev, REG_TXPSEL, MASKLWORD, 0 x1111);
/* BB CCK R/Rx Path_A */
rtw_write32_mask(rtwdev, REG_CCK_RX, 0 x0c000000, 0 x0);
/* MCS support */
rtw_write32_mask(rtwdev, REG_RX_MCS_LIMIT, 0 xc0000060, 0 x4);
/* RF Path_B HSSI OFF */
rtw_write32_mask(rtwdev, REG_3WIRE_SWB, 0 xf, 0 x4);
/* RF Path_B Power Down */
rtw_write32_mask(rtwdev, REG_LSSI_WRITE_B, MASKDWORD, 0 );
/* ADDA Path_B OFF */
rtw_write32_mask(rtwdev, REG_AFE_PWR1_B, MASKDWORD, 0 );
rtw_write32_mask(rtwdev, REG_AFE_PWR2_B, MASKDWORD, 0 );
}
static const u32 rtw88xxa_txscale_tbl[] = {
0 x081, 0 x088, 0 x090, 0 x099, 0 x0a2, 0 x0ac, 0 x0b6, 0 x0c0, 0 x0cc, 0 x0d8,
0 x0e5, 0 x0f2, 0 x101, 0 x110, 0 x120, 0 x131, 0 x143, 0 x156, 0 x16a, 0 x180,
0 x197, 0 x1af, 0 x1c8, 0 x1e3, 0 x200, 0 x21e, 0 x23e, 0 x261, 0 x285, 0 x2ab,
0 x2d3, 0 x2fe, 0 x32b, 0 x35c, 0 x38e, 0 x3c4, 0 x3fe
};
static u32 rtw88xxa_get_bb_swing(struct rtw_dev *rtwdev, u8 band, u8 path)
{
static const u32 swing2setting[4 ] = {0 x200, 0 x16a, 0 x101, 0 x0b6};
struct rtw_efuse *efuse = &rtwdev->efuse;
u8 tx_bb_swing;
if (band == RTW_BAND_2G)
tx_bb_swing = efuse->tx_bb_swing_setting_2g;
else
tx_bb_swing = efuse->tx_bb_swing_setting_5g;
if (path == RF_PATH_B)
tx_bb_swing >>= 2 ;
tx_bb_swing &= 0 x3;
return swing2setting[tx_bb_swing];
}
static u8 rtw88xxa_get_swing_index(struct rtw_dev *rtwdev)
{
u32 swing, table_value;
u8 i;
swing = rtw88xxa_get_bb_swing(rtwdev, rtwdev->hal.current_band_type,
RF_PATH_A);
for (i = 0 ; i < ARRAY_SIZE(rtw88xxa_txscale_tbl); i++) {
table_value = rtw88xxa_txscale_tbl[i];
if (swing == table_value)
return i;
}
return 24 ;
}
static void rtw88xxa_pwrtrack_init(struct rtw_dev *rtwdev)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
u8 path;
dm_info->default_ofdm_index = rtw88xxa_get_swing_index(rtwdev);
if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A)
dm_info->default_cck_index = 0 ;
else
dm_info->default_cck_index = 24 ;
for (path = RF_PATH_A; path < rtwdev->hal.rf_path_num; path++) {
ewma_thermal_init(&dm_info->avg_thermal[path]);
dm_info->delta_power_index[path] = 0 ;
dm_info->delta_power_index_last[path] = 0 ;
}
dm_info->pwr_trk_triggered = false ;
dm_info->pwr_trk_init_trigger = true ;
dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k;
}
void rtw88xxa_power_off(struct rtw_dev *rtwdev,
const struct rtw_pwr_seq_cmd *const *enter_lps_flow)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
enum usb_device_speed speed = rtwusb->udev->speed;
u16 ori_fsmc0;
u8 reg_cr;
reg_cr = rtw_read8(rtwdev, REG_CR);
/* Already powered off */
if (reg_cr == 0 || reg_cr == 0 xEA)
return ;
rtw_hci_stop(rtwdev);
if (!rtwdev->efuse.btcoex)
rtw_write16_clr(rtwdev, REG_GPIO_MUXCFG, BIT_EN_SIC);
/* set Reg 0xf008[3:4] to 2'11 to enable U1/U2 Mode in USB3.0. */
if (speed == USB_SPEED_SUPER)
rtw_write8_set(rtwdev, REG_USB_MOD, 0 x18);
rtw_write32(rtwdev, REG_HISR0, 0 xffffffff);
rtw_write32(rtwdev, REG_HISR1, 0 xffffffff);
rtw_write32(rtwdev, REG_HIMR0, 0 );
rtw_write32(rtwdev, REG_HIMR1, 0 );
if (rtwdev->efuse.btcoex)
rtw_coex_power_off_setting(rtwdev);
ori_fsmc0 = rtw_read16(rtwdev, REG_APS_FSMCO);
rtw_write16(rtwdev, REG_APS_FSMCO, ori_fsmc0 & ~APS_FSMCO_HW_POWERDOWN);
/* Stop Tx Report Timer. */
rtw_write8_clr(rtwdev, REG_TX_RPT_CTRL, BIT(1 ));
/* Stop Rx */
rtw_write8(rtwdev, REG_CR, 0 );
rtw_pwr_seq_parser(rtwdev, enter_lps_flow);
if (rtw_read8(rtwdev, REG_MCUFW_CTRL) & BIT_RAM_DL_SEL)
rtw88xxa_reset_8051(rtwdev);
rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN + 1 , BIT(2 ));
rtw_write8(rtwdev, REG_MCUFW_CTRL, 0 );
rtw_pwr_seq_parser(rtwdev, rtwdev->chip->pwr_off_seq);
if (ori_fsmc0 & APS_FSMCO_HW_POWERDOWN)
rtw_write16_set(rtwdev, REG_APS_FSMCO, APS_FSMCO_HW_POWERDOWN);
clear_bit(RTW_FLAG_POWERON, rtwdev->flags);
}
EXPORT_SYMBOL(rtw88xxa_power_off);
static void rtw88xxa_set_channel_bb_swing(struct rtw_dev *rtwdev, u8 band)
{
rtw_write32_mask(rtwdev, REG_TXSCALE_A, BB_SWING_MASK,
rtw88xxa_get_bb_swing(rtwdev, band, RF_PATH_A));
rtw_write32_mask(rtwdev, REG_TXSCALE_B, BB_SWING_MASK,
rtw88xxa_get_bb_swing(rtwdev, band, RF_PATH_B));
rtw88xxa_pwrtrack_init(rtwdev);
}
static void rtw8821a_set_ext_band_switch(struct rtw_dev *rtwdev, u8 band)
{
rtw_write32_mask(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN, 0 );
rtw_write32_mask(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL, 1 );
rtw_write32_mask(rtwdev, REG_RFE_INV_A, 0 xf, 7 );
rtw_write32_mask(rtwdev, REG_RFE_INV_A, 0 xf0, 7 );
if (band == RTW_BAND_2G)
rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(29 ) | BIT(28 ), 1 );
else
rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(29 ) | BIT(28 ), 2 );
}
static void rtw8821a_phy_set_rfe_reg_24g(struct rtw_dev *rtwdev)
{
struct rtw_efuse *efuse = &rtwdev->efuse;
/* Turn off RF PA and LNA */
/* 0xCB0[15:12] = 0x7 (LNA_On)*/
rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0 xF000, 0 x7);
/* 0xCB0[7:4] = 0x7 (PAPE_A)*/
rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0 xF0, 0 x7);
if (efuse->ext_lna_2g) {
/* Turn on 2.4G External LNA */
rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(20 ), 1 );
rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(22 ), 0 );
rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(2 , 0 ), 0 x2);
rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(10 , 8 ), 0 x2);
} else {
/* Bypass 2.4G External LNA */
rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(20 ), 0 );
rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(22 ), 0 );
rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(2 , 0 ), 0 x7);
rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(10 , 8 ), 0 x7);
}
}
static void rtw8821a_phy_set_rfe_reg_5g(struct rtw_dev *rtwdev)
{
/* Turn ON RF PA and LNA */
/* 0xCB0[15:12] = 0x7 (LNA_On)*/
rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0 xF000, 0 x5);
/* 0xCB0[7:4] = 0x7 (PAPE_A)*/
rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0 xF0, 0 x4);
/* Bypass 2.4G External LNA */
rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(20 ), 0 );
rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(22 ), 0 );
rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(2 , 0 ), 0 x7);
rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(10 , 8 ), 0 x7);
}
static void rtw8812a_phy_set_rfe_reg_24g(struct rtw_dev *rtwdev)
{
switch (rtwdev->efuse.rfe_option) {
case 0 :
case 2 :
rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0 x77777777);
rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0 x77777777);
rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0 x000);
rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0 x000);
break ;
case 1 :
if (rtwdev->efuse.btcoex) {
rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0 xffffff, 0 x777777);
rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0 x77777777);
rtw_write32_mask(rtwdev, REG_RFE_INV_A, 0 x33f00000, 0 x000);
rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0 x000);
} else {
rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0 x77777777);
rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0 x77777777);
rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0 x000);
rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0 x000);
}
break ;
case 3 :
rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0 x54337770);
rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0 x54337770);
rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0 x010);
rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0 x010);
rtw_write32_mask(rtwdev, REG_ANTSEL_SW, 0 x00000303, 0 x1);
break ;
case 4 :
rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0 x77777777);
rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0 x77777777);
rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0 x001);
rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0 x001);
break ;
case 5 :
rtw_write8(rtwdev, REG_RFE_PINMUX_A + 2 , 0 x77);
rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0 x77777777);
rtw_write8_clr(rtwdev, REG_RFE_INV_A + 3 , BIT(0 ));
rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0 x000);
break ;
case 6 :
rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0 x07772770);
rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0 x07772770);
rtw_write32(rtwdev, REG_RFE_INV_A, 0 x00000077);
rtw_write32(rtwdev, REG_RFE_INV_B, 0 x00000077);
break ;
default :
break ;
}
}
static void rtw8812a_phy_set_rfe_reg_5g(struct rtw_dev *rtwdev)
{
switch (rtwdev->efuse.rfe_option) {
case 0 :
rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0 x77337717);
rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0 x77337717);
rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0 x010);
rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0 x010);
break ;
case 1 :
if (rtwdev->efuse.btcoex) {
rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0 xffffff, 0 x337717);
rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0 x77337717);
rtw_write32_mask(rtwdev, REG_RFE_INV_A, 0 x33f00000, 0 x000);
rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0 x000);
} else {
rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0 x77337717);
rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0 x77337717);
rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0 x000);
rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0 x000);
}
break ;
case 2 :
case 4 :
rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0 x77337777);
rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0 x77337777);
rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0 x010);
rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0 x010);
break ;
case 3 :
rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0 x54337717);
rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0 x54337717);
rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0 x010);
rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0 x010);
rtw_write32_mask(rtwdev, REG_ANTSEL_SW, 0 x00000303, 0 x1);
break ;
case 5 :
rtw_write8(rtwdev, REG_RFE_PINMUX_A + 2 , 0 x33);
rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0 x77337777);
rtw_write8_set(rtwdev, REG_RFE_INV_A + 3 , BIT(0 ));
rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0 x010);
break ;
case 6 :
rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0 x07737717);
rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0 x07737717);
rtw_write32(rtwdev, REG_RFE_INV_A, 0 x00000077);
rtw_write32(rtwdev, REG_RFE_INV_B, 0 x00000077);
break ;
default :
break ;
}
}
static void rtw88xxa_switch_band(struct rtw_dev *rtwdev, u8 new_band, u8 bw)
{
const struct rtw_chip_info *chip = rtwdev->chip;
u16 basic_rates, reg_41a;
/* 8811au one antenna module doesn't support antenna div, so driver must
* control antenna band, otherwise one of the band will have issue
*/
if (chip->id == RTW_CHIP_TYPE_8821A && !rtwdev->efuse.btcoex &&
rtwdev->efuse.ant_div_cfg == 0 )
rtw8821a_set_ext_band_switch(rtwdev, new_band);
if (new_band == RTW_BAND_2G) {
rtw_write32_set(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST);
if (chip->id == RTW_CHIP_TYPE_8821A) {
rtw8821a_phy_set_rfe_reg_24g(rtwdev);
rtw_write32_mask(rtwdev, REG_TXSCALE_A, 0 xf00, 0 );
} else {
rtw_write32_mask(rtwdev, REG_BWINDICATION, 0 x3, 0 x1);
rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(17 , 13 ), 0 x17);
if (bw == RTW_CHANNEL_WIDTH_20 &&
rtwdev->hal.rf_type == RF_1T1R &&
!rtwdev->efuse.ext_lna_2g)
rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(3 , 1 ), 0 x02);
else
rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(3 , 1 ), 0 x04);
rtw_write32_mask(rtwdev, REG_CCASEL, 0 x3, 0 );
rtw8812a_phy_set_rfe_reg_24g(rtwdev);
}
rtw_write32_mask(rtwdev, REG_TXPSEL, 0 xf0, 0 x1);
rtw_write32_mask(rtwdev, REG_CCK_RX, 0 x0f000000, 0 x1);
basic_rates = BIT(DESC_RATE1M) | BIT(DESC_RATE2M) |
BIT(DESC_RATE5_5M) | BIT(DESC_RATE11M) |
BIT(DESC_RATE6M) | BIT(DESC_RATE12M) |
BIT(DESC_RATE24M);
rtw_write32_mask(rtwdev, REG_RRSR, 0 xfffff, basic_rates);
rtw_write8_clr(rtwdev, REG_CCK_CHECK, BIT_CHECK_CCK_EN);
} else { /* RTW_BAND_5G */
if (chip->id == RTW_CHIP_TYPE_8821A)
rtw8821a_phy_set_rfe_reg_5g(rtwdev);
rtw_write8_set(rtwdev, REG_CCK_CHECK, BIT_CHECK_CCK_EN);
read_poll_timeout_atomic(rtw_read16, reg_41a, (reg_41a & 0 x30) == 0 x30,
50 , 2500 , false , rtwdev, REG_TXPKT_EMPTY);
rtw_write32_set(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST);
if (chip->id == RTW_CHIP_TYPE_8821A) {
rtw_write32_mask(rtwdev, REG_TXSCALE_A, 0 xf00, 1 );
} else {
rtw_write32_mask(rtwdev, REG_BWINDICATION, 0 x3, 0 x2);
rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(17 , 13 ), 0 x15);
rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(3 , 1 ), 0 x04);
rtw_write32_mask(rtwdev, REG_CCASEL, 0 x3, 1 );
rtw8812a_phy_set_rfe_reg_5g(rtwdev);
}
rtw_write32_mask(rtwdev, REG_TXPSEL, 0 xf0, 0 );
rtw_write32_mask(rtwdev, REG_CCK_RX, 0 x0f000000, 0 xf);
basic_rates = BIT(DESC_RATE6M) | BIT(DESC_RATE12M) |
BIT(DESC_RATE24M);
rtw_write32_mask(rtwdev, REG_RRSR, 0 xfffff, basic_rates);
}
rtw88xxa_set_channel_bb_swing(rtwdev, new_band);
}
int rtw88xxa_power_on(struct rtw_dev *rtwdev)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_hal *hal = &rtwdev->hal;
int ret;
if (test_bit(RTW_FLAG_POWERON, rtwdev->flags))
return 0 ;
/* Override rtw_chip_efuse_info_setup() */
if (chip->id == RTW_CHIP_TYPE_8821A)
efuse->btcoex = rtw_read32_mask(rtwdev, REG_WL_BT_PWR_CTRL,
BIT_BT_FUNC_EN);
/* Override rtw_chip_efuse_info_setup() */
if (chip->id == RTW_CHIP_TYPE_8812A)
rtw8812a_read_amplifier_type(rtwdev);
ret = rtw_hci_setup(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to setup hci\n" );
goto err;
}
/* Revise for U2/U3 switch we can not update RF-A/B reset.
* Reset after MAC power on to prevent RF R/W error.
* Is it a right method?
*/
if (chip->id == RTW_CHIP_TYPE_8812A) {
rtw_write8(rtwdev, REG_RF_CTRL, 5 );
rtw_write8(rtwdev, REG_RF_CTRL, 7 );
rtw_write8(rtwdev, REG_RF_B_CTRL, 5 );
rtw_write8(rtwdev, REG_RF_B_CTRL, 7 );
}
/* If HW didn't go through a complete de-initial procedure,
* it probably occurs some problem for double initial
* procedure.
*/
rtw88xxau_hw_reset(rtwdev);
ret = rtw88xxau_init_power_on(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to power on\n" );
goto err;
}
ret = rtw_set_trx_fifo_info(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to set trx fifo info\n" );
goto err;
}
ret = rtw88xxa_llt_init(rtwdev, rtwdev->fifo.rsvd_boundary);
if (ret) {
rtw_err(rtwdev, "failed to init llt\n" );
goto err;
}
rtw_write32_set(rtwdev, REG_TXDMA_OFFSET_CHK, BIT_DROP_DATA_EN);
ret = rtw_wait_firmware_completion(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to wait firmware completion\n" );
goto err_off;
}
ret = rtw_download_firmware(rtwdev, &rtwdev->fw);
if (ret) {
rtw_err(rtwdev, "failed to download firmware\n" );
goto err_off;
}
rtw_write8(rtwdev, REG_HMETFR, 0 xf);
rtw_load_table(rtwdev, chip->mac_tbl);
rtw88xxau_init_queue_reserved_page(rtwdev);
rtw88xxau_init_tx_buffer_boundary(rtwdev);
rtw88xxau_init_queue_priority(rtwdev);
rtw_write16(rtwdev, REG_TRXFF_BNDY + 2 ,
chip->rxff_size - REPORT_BUF - 1 );
if (chip->id == RTW_CHIP_TYPE_8812A)
rtw_write8(rtwdev, REG_PBP,
u8_encode_bits(PBP_512, PBP_TX_MASK) |
u8_encode_bits(PBP_64, PBP_RX_MASK));
rtw_write8(rtwdev, REG_RX_DRVINFO_SZ, PHY_STATUS_SIZE);
rtw_write32(rtwdev, REG_HIMR0, 0 );
rtw_write32(rtwdev, REG_HIMR1, 0 );
rtw_write32_mask(rtwdev, REG_CR, 0 x30000, 0 x2);
rtw88xxa_init_wmac_setting(rtwdev);
rtw88xxa_init_adaptive_ctrl(rtwdev);
rtw88xxa_init_edca(rtwdev);
rtw_write8_set(rtwdev, REG_FWHW_TXQ_CTRL, BIT(7 ));
rtw_write8(rtwdev, REG_ACKTO, 0 x80);
rtw88xxau_tx_aggregation(rtwdev);
rtw88xxa_init_beacon_parameters(rtwdev);
rtw_write8(rtwdev, REG_BCN_MAX_ERR, 0 xff);
rtw_hci_interface_cfg(rtwdev);
/* usb3 rx interval */
rtw_write8(rtwdev, REG_USB3_RXITV, 0 x01);
/* burst length=4, set 0x3400 for burst length=2 */
rtw_write16(rtwdev, REG_RXDMA_STATUS, 0 x7400);
rtw_write8(rtwdev, REG_RXDMA_STATUS + 1 , 0 xf5);
/* 0x456 = 0x70, sugguested by Zhilin */
if (chip->id == RTW_CHIP_TYPE_8821A)
rtw_write8(rtwdev, REG_AMPDU_MAX_TIME, 0 x5e);
else
rtw_write8(rtwdev, REG_AMPDU_MAX_TIME, 0 x70);
rtw_write32(rtwdev, REG_AMPDU_MAX_LENGTH, 0 xffffffff);
rtw_write8(rtwdev, REG_USTIME_TSF, 0 x50);
rtw_write8(rtwdev, REG_USTIME_EDCA, 0 x50);
if (rtwusb->udev->speed == USB_SPEED_SUPER)
/* Disable U1/U2 Mode to avoid 2.5G spur in USB3.0. */
rtw_write8_clr(rtwdev, REG_USB_MOD, BIT(4 ) | BIT(3 ));
rtw_write8_set(rtwdev, REG_SINGLE_AMPDU_CTRL, BIT_EN_SINGLE_APMDU);
/* for VHT packet length 11K */
rtw_write8(rtwdev, REG_RX_PKT_LIMIT, 0 x18);
rtw_write8(rtwdev, REG_PIFS, 0 x00);
if (chip->id == RTW_CHIP_TYPE_8821A) {
/* 0x0a0a too small, it can't pass AC logo. change to 0x1f1f */
rtw_write16(rtwdev, REG_MAX_AGGR_NUM, 0 x1f1f);
rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL, 0 x80);
rtw_write32(rtwdev, REG_FAST_EDCA_CTRL, 0 x03087777);
} else {
rtw_write16(rtwdev, REG_MAX_AGGR_NUM, 0 x1f1f);
rtw_write8_clr(rtwdev, REG_FWHW_TXQ_CTRL, BIT(7 ));
}
/* to prevent mac is reseted by bus. */
rtw_write8_set(rtwdev, REG_RSV_CTRL, BIT(5 ) | BIT(6 ));
/* ARFB table 9 for 11ac 5G 2SS */
rtw_write32(rtwdev, REG_ARFR0, 0 x00000010);
rtw_write32(rtwdev, REG_ARFRH0, 0 xfffff000);
/* ARFB table 10 for 11ac 5G 1SS */
rtw_write32(rtwdev, REG_ARFR1_V1, 0 x00000010);
rtw_write32(rtwdev, REG_ARFRH1_V1, 0 x003ff000);
/* ARFB table 11 for 11ac 24G 1SS */
rtw_write32(rtwdev, REG_ARFR2_V1, 0 x00000015);
rtw_write32(rtwdev, REG_ARFRH2_V1, 0 x003ff000);
/* ARFB table 12 for 11ac 24G 2SS */
rtw_write32(rtwdev, REG_ARFR3_V1, 0 x00000015);
rtw_write32(rtwdev, REG_ARFRH3_V1, 0 xffcff000);
rtw_write8_set(rtwdev, REG_CR, BIT_MACTXEN | BIT_MACRXEN);
rtw88xxa_phy_bb_config(rtwdev);
rtw88xxa_phy_rf_config(rtwdev);
if (chip->id == RTW_CHIP_TYPE_8812A && hal->rf_path_num == 1 )
rtw8812a_config_1t(rtwdev);
rtw88xxa_switch_band(rtwdev, RTW_BAND_2G, RTW_CHANNEL_WIDTH_20);
rtw_write32(rtwdev, RTW_SEC_CMD_REG, BIT(31 ) | BIT(30 ));
rtw_write8(rtwdev, REG_HWSEQ_CTRL, 0 xff);
rtw_write32(rtwdev, REG_BAR_MODE_CTRL, 0 x0201ffff);
rtw_write8(rtwdev, REG_NAV_CTRL + 2 , 0 );
rtw_write8_clr(rtwdev, REG_GPIO_MUXCFG, BIT(5 ));
rtw_phy_init(rtwdev);
rtw88xxa_pwrtrack_init(rtwdev);
/* 0x4c6[3] 1: RTS BW = Data BW
* 0: RTS BW depends on CCA / secondary CCA result.
*/
rtw_write8_clr(rtwdev, REG_QUEUE_CTRL, BIT(3 ));
/* enable Tx report. */
rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL + 1 , 0 x0f);
/* Pretx_en, for WEP/TKIP SEC */
rtw_write8(rtwdev, REG_EARLY_MODE_CONTROL + 3 , 0 x01);
rtw_write16(rtwdev, REG_TX_RPT_TIME, 0 x3df0);
/* Reset USB mode switch setting */
rtw_write8(rtwdev, REG_SYS_SDIO_CTRL, 0 x0);
rtw_write8(rtwdev, REG_ACLK_MON, 0 x0);
rtw_write8(rtwdev, REG_USB_HRPWM, 0 );
/* ack for xmit mgmt frames. */
rtw_write32_set(rtwdev, REG_FWHW_TXQ_CTRL, BIT(12 ));
hal->cck_high_power = rtw_read32_mask(rtwdev, REG_CCK_RPT_FORMAT,
BIT_CCK_RPT_FORMAT);
ret = rtw_hci_start(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to start hci\n" );
goto err_off;
}
if (efuse->btcoex) {
rtw_coex_power_on_setting(rtwdev);
rtw_coex_init_hw_config(rtwdev, false );
}
set_bit(RTW_FLAG_POWERON, rtwdev->flags);
return 0 ;
err_off:
chip->ops->power_off(rtwdev);
err:
return ret;
}
EXPORT_SYMBOL(rtw88xxa_power_on);
u32 rtw88xxa_phy_read_rf(struct rtw_dev *rtwdev,
enum rtw_rf_path rf_path, u32 addr, u32 mask)
{
static const u32 pi_addr[2 ] = { REG_3WIRE_SWA, REG_3WIRE_SWB };
static const u32 read_addr[2 ][2 ] = {
{ REG_SI_READ_A, REG_SI_READ_B },
{ REG_PI_READ_A, REG_PI_READ_B }
};
const struct rtw_chip_info *chip = rtwdev->chip;
const struct rtw_hal *hal = &rtwdev->hal;
bool set_cca, pi_mode;
u32 val;
if (rf_path >= hal->rf_phy_num) {
rtw_err(rtwdev, "unsupported rf path (%d)\n" , rf_path);
return INV_RF_DATA;
}
/* CCA off to avoid reading the wrong value.
* Toggling CCA would affect RF 0x0, skip it.
*/
set_cca = addr != 0 x0 && chip->id == RTW_CHIP_TYPE_8812A &&
hal->cut_version != RTW_CHIP_VER_CUT_C;
if (set_cca)
rtw_write32_set(rtwdev, REG_CCA2ND, BIT(3 ));
addr &= 0 xff;
pi_mode = rtw_read32_mask(rtwdev, pi_addr[rf_path], 0 x4);
rtw_write32_mask(rtwdev, REG_HSSI_READ, MASKBYTE0, addr);
if (chip->id == RTW_CHIP_TYPE_8821A ||
hal->cut_version == RTW_CHIP_VER_CUT_C)
udelay(20 );
val = rtw_read32_mask(rtwdev, read_addr[pi_mode][rf_path], mask);
/* CCA on */
if (set_cca)
rtw_write32_clr(rtwdev, REG_CCA2ND, BIT(3 ));
return val;
}
EXPORT_SYMBOL(rtw88xxa_phy_read_rf);
static void rtw8812a_phy_fix_spur(struct rtw_dev *rtwdev, u8 channel, u8 bw)
{
/* C cut Item12 ADC FIFO CLOCK */
if (rtwdev->hal.cut_version == RTW_CHIP_VER_CUT_C) {
if (bw == RTW_CHANNEL_WIDTH_40 && channel == 11 )
rtw_write32_mask(rtwdev, REG_ADCCLK, 0 xC00, 0 x3);
else
rtw_write32_mask(rtwdev, REG_ADCCLK, 0 xC00, 0 x2);
/* A workaround to resolve 2480Mhz spur by setting ADC clock
* as 160M.
*/
if (bw == RTW_CHANNEL_WIDTH_20 && (channel == 13 || channel == 14 )) {
rtw_write32_mask(rtwdev, REG_ADCCLK, 0 x300, 0 x3);
rtw_write32_mask(rtwdev, REG_ADC160, BIT(30 ), 1 );
} else if (bw == RTW_CHANNEL_WIDTH_40 && channel == 11 ) {
rtw_write32_mask(rtwdev, REG_ADC160, BIT(30 ), 1 );
} else if (bw != RTW_CHANNEL_WIDTH_80) {
rtw_write32_mask(rtwdev, REG_ADCCLK, 0 x300, 0 x2);
rtw_write32_mask(rtwdev, REG_ADC160, BIT(30 ), 0 );
}
} else {
/* A workaround to resolve 2480Mhz spur by setting ADC clock
* as 160M.
*/
if (bw == RTW_CHANNEL_WIDTH_20 && (channel == 13 || channel == 14 ))
rtw_write32_mask(rtwdev, REG_ADCCLK, 0 x300, 0 x3);
else if (channel <= 14 ) /* 2.4G only */
rtw_write32_mask(rtwdev, REG_ADCCLK, 0 x300, 0 x2);
}
}
static void rtw88xxa_switch_channel(struct rtw_dev *rtwdev, u8 channel, u8 bw)
{
struct rtw_hal *hal = &rtwdev->hal;
u32 fc_area, rf_mod_ag;
u8 path;
switch (channel) {
case 36 ... 48 :
fc_area = 0 x494;
break ;
case 50 ... 64 :
fc_area = 0 x453;
break ;
case 100 ... 116 :
fc_area = 0 x452;
break ;
default :
if (channel >= 118 )
fc_area = 0 x412;
else
fc_area = 0 x96a;
break ;
}
rtw_write32_mask(rtwdev, REG_CLKTRK, 0 x1ffe0000, fc_area);
for (path = 0 ; path < hal->rf_path_num; path++) {
switch (channel) {
case 36 ... 64 :
rf_mod_ag = 0 x101;
break ;
case 100 ... 140 :
rf_mod_ag = 0 x301;
break ;
default :
if (channel > 140 )
rf_mod_ag = 0 x501;
else
rf_mod_ag = 0 x000;
break ;
}
rtw_write_rf(rtwdev, path, RF_CFGCH,
RF18_RFSI_MASK | RF18_BAND_MASK, rf_mod_ag);
if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A)
rtw8812a_phy_fix_spur(rtwdev, channel, bw);
rtw_write_rf(rtwdev, path, RF_CFGCH, RF18_CHANNEL_MASK, channel);
}
}
static void rtw88xxa_set_reg_bw(struct rtw_dev *rtwdev, u8 bw)
{
u16 val16 = rtw_read16(rtwdev, REG_WMAC_TRXPTCL_CTL);
val16 &= ~BIT_RFMOD;
if (bw == RTW_CHANNEL_WIDTH_80)
val16 |= BIT_RFMOD_80M;
else if (bw == RTW_CHANNEL_WIDTH_40)
val16 |= BIT_RFMOD_40M;
rtw_write16(rtwdev, REG_WMAC_TRXPTCL_CTL, val16);
}
static void rtw88xxa_post_set_bw_mode(struct rtw_dev *rtwdev, u8 channel,
u8 bw, u8 primary_chan_idx)
{
struct rtw_hal *hal = &rtwdev->hal;
u8 txsc40 = 0 , txsc20, txsc;
u8 reg_837, l1pkval;
rtw88xxa_set_reg_bw(rtwdev, bw);
txsc20 = primary_chan_idx;
if (bw == RTW_CHANNEL_WIDTH_80) {
if (txsc20 == RTW_SC_20_UPPER || txsc20 == RTW_SC_20_UPMOST)
txsc40 = RTW_SC_40_UPPER;
else
txsc40 = RTW_SC_40_LOWER;
}
txsc = BIT_TXSC_20M(txsc20) | BIT_TXSC_40M(txsc40);
rtw_write8(rtwdev, REG_DATA_SC, txsc);
reg_837 = rtw_read8(rtwdev, REG_BWINDICATION + 3 );
switch (bw) {
default :
case RTW_CHANNEL_WIDTH_20:
rtw_write32_mask(rtwdev, REG_ADCCLK, 0 x003003C3, 0 x00300200);
rtw_write32_mask(rtwdev, REG_ADC160, BIT(30 ), 0 );
if (hal->rf_type == RF_2T2R)
rtw_write32_mask(rtwdev, REG_L1PKTH, 0 x03C00000, 7 );
else
rtw_write32_mask(rtwdev, REG_L1PKTH, 0 x03C00000, 8 );
break ;
case RTW_CHANNEL_WIDTH_40:
rtw_write32_mask(rtwdev, REG_ADCCLK, 0 x003003C3, 0 x00300201);
rtw_write32_mask(rtwdev, REG_ADC160, BIT(30 ), 0 );
rtw_write32_mask(rtwdev, REG_ADCCLK, 0 x3C, txsc);
rtw_write32_mask(rtwdev, REG_CCA2ND, 0 xf0000000, txsc);
if (reg_837 & BIT(2 )) {
l1pkval = 6 ;
} else {
if (hal->rf_type == RF_2T2R)
l1pkval = 7 ;
else
l1pkval = 8 ;
}
rtw_write32_mask(rtwdev, REG_L1PKTH, 0 x03C00000, l1pkval);
if (txsc == RTW_SC_20_UPPER)
rtw_write32_set(rtwdev, REG_RXSB, BIT(4 ));
else
rtw_write32_clr(rtwdev, REG_RXSB, BIT(4 ));
break ;
case RTW_CHANNEL_WIDTH_80:
rtw_write32_mask(rtwdev, REG_ADCCLK, 0 x003003C3, 0 x00300202);
rtw_write32_mask(rtwdev, REG_ADC160, BIT(30 ), 1 );
rtw_write32_mask(rtwdev, REG_ADCCLK, 0 x3C, txsc);
rtw_write32_mask(rtwdev, REG_CCA2ND, 0 xf0000000, txsc);
if (reg_837 & BIT(2 )) {
l1pkval = 5 ;
} else {
if (hal->rf_type == RF_2T2R)
l1pkval = 6 ;
else
l1pkval = 7 ;
}
rtw_write32_mask(rtwdev, REG_L1PKTH, 0 x03C00000, l1pkval);
break ;
}
}
static void rtw88xxa_set_channel_rf(struct rtw_dev *rtwdev, u8 channel, u8 bw)
{
u8 path;
for (path = RF_PATH_A; path < rtwdev->hal.rf_path_num; path++) {
switch (bw) {
case RTW_CHANNEL_WIDTH_5:
case RTW_CHANNEL_WIDTH_10:
case RTW_CHANNEL_WIDTH_20:
default :
rtw_write_rf(rtwdev, path, RF_CFGCH, RF18_BW_MASK, 3 );
break ;
case RTW_CHANNEL_WIDTH_40:
rtw_write_rf(rtwdev, path, RF_CFGCH, RF18_BW_MASK, 1 );
break ;
case RTW_CHANNEL_WIDTH_80:
rtw_write_rf(rtwdev, path, RF_CFGCH, RF18_BW_MASK, 0 );
break ;
}
}
}
void rtw88xxa_set_channel(struct rtw_dev *rtwdev, u8 channel, u8 bw,
u8 primary_chan_idx)
{
u8 old_band, new_band;
if (rtw_read8(rtwdev, REG_CCK_CHECK) & BIT_CHECK_CCK_EN)
old_band = RTW_BAND_5G;
else
old_band = RTW_BAND_2G;
if (channel > 14 )
new_band = RTW_BAND_5G;
else
new_band = RTW_BAND_2G;
if (new_band != old_band)
rtw88xxa_switch_band(rtwdev, new_band, bw);
rtw88xxa_switch_channel(rtwdev, channel, bw);
rtw88xxa_post_set_bw_mode(rtwdev, channel, bw, primary_chan_idx);
if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A)
rtw8812a_phy_fix_spur(rtwdev, channel, bw);
rtw88xxa_set_channel_rf(rtwdev, channel, bw);
}
EXPORT_SYMBOL(rtw88xxa_set_channel);
void rtw88xxa_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
struct rtw_rx_pkt_stat *pkt_stat,
s8 (*cck_rx_pwr)(u8 lna_idx, u8 vga_idx))
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
struct rtw_jaguar_phy_status_rpt *rpt;
u8 gain[RTW_RF_PATH_MAX], rssi, i;
s8 rx_pwr_db, power_a, power_b;
const s8 min_rx_power = -120 ;
u8 lna_idx, vga_idx;
rpt = (struct rtw_jaguar_phy_status_rpt *)phy_status;
if (pkt_stat->rate <= DESC_RATE11M) {
lna_idx = le32_get_bits(rpt->w1, RTW_JGRPHY_W1_AGC_RPT_LNA_IDX);
vga_idx = le32_get_bits(rpt->w1, RTW_JGRPHY_W1_AGC_RPT_VGA_IDX);
rx_pwr_db = cck_rx_pwr(lna_idx, vga_idx);
pkt_stat->rx_power[RF_PATH_A] = rx_pwr_db;
pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1 );
dm_info->rssi[RF_PATH_A] = pkt_stat->rssi;
pkt_stat->bw = RTW_CHANNEL_WIDTH_20;
pkt_stat->signal_power = rx_pwr_db;
} else { /* OFDM rate */
gain[RF_PATH_A] = le32_get_bits(rpt->w0, RTW_JGRPHY_W0_GAIN_A);
gain[RF_PATH_B] = le32_get_bits(rpt->w0, RTW_JGRPHY_W0_GAIN_B);
for (i = RF_PATH_A; i < rtwdev->hal.rf_path_num; i++) {
pkt_stat->rx_power[i] = gain[i] - 110 ;
rssi = rtw_phy_rf_power_2_rssi(&pkt_stat->rx_power[i], 1 );
dm_info->rssi[i] = rssi;
}
pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power,
rtwdev->hal.rf_path_num);
power_a = pkt_stat->rx_power[RF_PATH_A];
power_b = pkt_stat->rx_power[RF_PATH_B];
if (rtwdev->hal.rf_path_num == 1 )
power_b = power_a;
pkt_stat->signal_power = max3(power_a, power_b, min_rx_power);
}
}
EXPORT_SYMBOL(rtw88xxa_query_phy_status);
static void
rtw88xxa_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path,
u8 rs, u32 *phy_pwr_idx)
{
static const u32 offset_txagc[2 ] = {
REG_TX_AGC_A_CCK_11_CCK_1, REG_TX_AGC_B_CCK_11_CCK_1
};
u8 rate, rate_idx, pwr_index, shift;
struct rtw_hal *hal = &rtwdev->hal;
bool write_1ss_mcs9;
u32 mask;
int j;
for (j = 0 ; j < rtw_rate_size[rs]; j++) {
rate = rtw_rate_section[rs][j];
pwr_index = hal->tx_pwr_tbl[path][rate];
shift = rate & 0 x3;
*phy_pwr_idx |= ((u32)pwr_index << (shift * 8 ));
write_1ss_mcs9 = rate == DESC_RATEVHT1SS_MCS9 &&
hal->rf_path_num == 1 ;
if (write_1ss_mcs9)
mask = MASKLWORD;
else
mask = MASKDWORD;
if (shift == 0 x3 || write_1ss_mcs9) {
rate_idx = rate & 0 xfc;
if (rate >= DESC_RATEVHT1SS_MCS0)
rate_idx -= 0 x10;
rtw_write32_mask(rtwdev, offset_txagc[path] + rate_idx,
mask, *phy_pwr_idx);
*phy_pwr_idx = 0 ;
}
}
}
static void rtw88xxa_tx_power_training(struct rtw_dev *rtwdev, u8 bw,
u8 channel, u8 path)
{
static const u32 write_offset[] = {
REG_TX_PWR_TRAINING_A, REG_TX_PWR_TRAINING_B,
};
u32 power_level, write_data;
u8 i;
power_level = rtwdev->hal.tx_pwr_tbl[path][DESC_RATEMCS7];
write_data = 0 ;
for (i = 0 ; i < 3 ; i++) {
if (i == 0 )
power_level -= 10 ;
else if (i == 1 )
power_level -= 8 ;
else
power_level -= 6 ;
write_data |= max_t(u32, power_level, 2 ) << (i * 8 );
}
rtw_write32_mask(rtwdev, write_offset[path], 0 xffffff, write_data);
}
void rtw88xxa_set_tx_power_index(struct rtw_dev *rtwdev)
{
struct rtw_hal *hal = &rtwdev->hal;
u32 phy_pwr_idx = 0 ;
int rs, path;
for (path = 0 ; path < hal->rf_path_num; path++) {
for (rs = 0 ; rs <= __RTW_RATE_SECTION_2SS_MAX; rs++) {
if (hal->rf_path_num == 1 &&
(rs == RTW_RATE_SECTION_HT_2S ||
rs == RTW_RATE_SECTION_VHT_2S))
continue ;
if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags) &&
rs > RTW_RATE_SECTION_OFDM)
continue ;
if (hal->current_band_type == RTW_BAND_5G &&
rs == RTW_RATE_SECTION_CCK)
continue ;
rtw88xxa_set_tx_power_index_by_rate(rtwdev, path, rs,
&phy_pwr_idx);
}
rtw88xxa_tx_power_training(rtwdev, hal->current_band_width,
hal->current_channel, path);
}
}
EXPORT_SYMBOL(rtw88xxa_set_tx_power_index);
void rtw88xxa_false_alarm_statistics(struct rtw_dev *rtwdev)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
u32 cck_fa_cnt, ofdm_fa_cnt;
u32 crc32_cnt, cca32_cnt;
u32 cck_enable;
cck_enable = rtw_read32(rtwdev, REG_RXPSEL) & BIT(28 );
cck_fa_cnt = rtw_read16(rtwdev, REG_FA_CCK);
ofdm_fa_cnt = rtw_read16(rtwdev, REG_FA_OFDM);
dm_info->cck_fa_cnt = cck_fa_cnt;
dm_info->ofdm_fa_cnt = ofdm_fa_cnt;
dm_info->total_fa_cnt = ofdm_fa_cnt;
if (cck_enable)
dm_info->total_fa_cnt += cck_fa_cnt;
crc32_cnt = rtw_read32(rtwdev, REG_CRC_CCK);
dm_info->cck_ok_cnt = u32_get_bits(crc32_cnt, MASKLWORD);
dm_info->cck_err_cnt = u32_get_bits(crc32_cnt, MASKHWORD);
crc32_cnt = rtw_read32(rtwdev, REG_CRC_OFDM);
dm_info->ofdm_ok_cnt = u32_get_bits(crc32_cnt, MASKLWORD);
dm_info->ofdm_err_cnt = u32_get_bits(crc32_cnt, MASKHWORD);
crc32_cnt = rtw_read32(rtwdev, REG_CRC_HT);
dm_info->ht_ok_cnt = u32_get_bits(crc32_cnt, MASKLWORD);
dm_info->ht_err_cnt = u32_get_bits(crc32_cnt, MASKHWORD);
crc32_cnt = rtw_read32(rtwdev, REG_CRC_VHT);
dm_info->vht_ok_cnt = u32_get_bits(crc32_cnt, MASKLWORD);
dm_info->vht_err_cnt = u32_get_bits(crc32_cnt, MASKHWORD);
cca32_cnt = rtw_read32(rtwdev, REG_CCA_OFDM);
dm_info->ofdm_cca_cnt = u32_get_bits(cca32_cnt, MASKHWORD);
dm_info->total_cca_cnt = dm_info->ofdm_cca_cnt;
if (cck_enable) {
cca32_cnt = rtw_read32(rtwdev, REG_CCA_CCK);
dm_info->cck_cca_cnt = u32_get_bits(cca32_cnt, MASKLWORD);
dm_info->total_cca_cnt += dm_info->cck_cca_cnt;
}
rtw_write32_set(rtwdev, REG_FAS, BIT(17 ));
rtw_write32_clr(rtwdev, REG_FAS, BIT(17 ));
rtw_write32_clr(rtwdev, REG_CCK0_FAREPORT, BIT(15 ));
rtw_write32_set(rtwdev, REG_CCK0_FAREPORT, BIT(15 ));
rtw_write32_set(rtwdev, REG_CNTRST, BIT(0 ));
rtw_write32_clr(rtwdev, REG_CNTRST, BIT(0 ));
}
EXPORT_SYMBOL(rtw88xxa_false_alarm_statistics);
void rtw88xxa_iqk_backup_mac_bb(struct rtw_dev *rtwdev,
u32 *macbb_backup,
const u32 *backup_macbb_reg,
u32 macbb_num)
{
u32 i;
/* [31] = 0 --> Page C */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x0);
/* save MACBB default value */
for (i = 0 ; i < macbb_num; i++)
macbb_backup[i] = rtw_read32(rtwdev, backup_macbb_reg[i]);
}
EXPORT_SYMBOL(rtw88xxa_iqk_backup_mac_bb);
void rtw88xxa_iqk_backup_afe(struct rtw_dev *rtwdev, u32 *afe_backup,
const u32 *backup_afe_reg, u32 afe_num)
{
u32 i;
/* [31] = 0 --> Page C */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x0);
/* Save AFE Parameters */
for (i = 0 ; i < afe_num; i++)
afe_backup[i] = rtw_read32(rtwdev, backup_afe_reg[i]);
}
EXPORT_SYMBOL(rtw88xxa_iqk_backup_afe);
void rtw88xxa_iqk_restore_mac_bb(struct rtw_dev *rtwdev,
u32 *macbb_backup,
const u32 *backup_macbb_reg,
u32 macbb_num)
{
u32 i;
/* [31] = 0 --> Page C */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x0);
/* Reload MacBB Parameters */
for (i = 0 ; i < macbb_num; i++)
rtw_write32(rtwdev, backup_macbb_reg[i], macbb_backup[i]);
}
EXPORT_SYMBOL(rtw88xxa_iqk_restore_mac_bb);
void rtw88xxa_iqk_configure_mac(struct rtw_dev *rtwdev)
{
/* [31] = 0 --> Page C */
rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31 ), 0 x0);
rtw_write8(rtwdev, REG_TXPAUSE, 0 x3f);
rtw_write32_mask(rtwdev, REG_BCN_CTRL,
(BIT_EN_BCN_FUNCTION << 8 ) | BIT_EN_BCN_FUNCTION, 0 x0);
/* RX ante off */
rtw_write8(rtwdev, REG_RXPSEL, 0 x00);
/* CCA off */
rtw_write32_mask(rtwdev, REG_CCA2ND, 0 xf, 0 xc);
/* CCK RX path off */
rtw_write8(rtwdev, REG_CCK_RX + 3 , 0 xf);
}
EXPORT_SYMBOL(rtw88xxa_iqk_configure_mac);
bool rtw88xxa_iqk_finish(int average, int threshold,
int *x_temp, int *y_temp, int *x, int *y,
bool break_inner, bool break_outer)
{
bool finish = false ;
int i, ii, dx, dy;
for (i = 0 ; i < average; i++) {
for (ii = i + 1 ; ii < average; ii++) {
dx = abs_diff(x_temp[i] >> 21 , x_temp[ii] >> 21 );
dy = abs_diff(y_temp[i] >> 21 , y_temp[ii] >> 21 );
if (dx < threshold && dy < threshold) {
*x = ((x_temp[i] >> 21 ) + (x_temp[ii] >> 21 ));
*y = ((y_temp[i] >> 21 ) + (y_temp[ii] >> 21 ));
*x /= 2 ;
*y /= 2 ;
finish = true ;
if (break_inner)
break ;
}
}
if (finish && break_outer)
break ;
}
return finish;
}
EXPORT_SYMBOL(rtw88xxa_iqk_finish);
static void rtw88xxa_pwrtrack_set(struct rtw_dev *rtwdev, u8 tx_rate, u8 path)
{
static const u32 reg_txscale[2 ] = { REG_TXSCALE_A, REG_TXSCALE_B };
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
u8 cck_swing_idx, ofdm_swing_idx;
u8 pwr_tracking_limit;
switch (tx_rate) {
case DESC_RATE1M ... DESC_RATE11M:
pwr_tracking_limit = 32 ;
break ;
case DESC_RATE6M ... DESC_RATE48M:
case DESC_RATEMCS3 ... DESC_RATEMCS4:
case DESC_RATEMCS11 ... DESC_RATEMCS12:
case DESC_RATEVHT1SS_MCS3 ... DESC_RATEVHT1SS_MCS4:
case DESC_RATEVHT2SS_MCS3 ... DESC_RATEVHT2SS_MCS4:
pwr_tracking_limit = 30 ;
break ;
case DESC_RATE54M:
case DESC_RATEMCS5 ... DESC_RATEMCS7:
case DESC_RATEMCS13 ... DESC_RATEMCS15:
case DESC_RATEVHT1SS_MCS5 ... DESC_RATEVHT1SS_MCS6:
case DESC_RATEVHT2SS_MCS5 ... DESC_RATEVHT2SS_MCS6:
pwr_tracking_limit = 28 ;
break ;
case DESC_RATEMCS0 ... DESC_RATEMCS2:
case DESC_RATEMCS8 ... DESC_RATEMCS10:
case DESC_RATEVHT1SS_MCS0 ... DESC_RATEVHT1SS_MCS2:
case DESC_RATEVHT2SS_MCS0 ... DESC_RATEVHT2SS_MCS2:
pwr_tracking_limit = 34 ;
break ;
case DESC_RATEVHT1SS_MCS7:
case DESC_RATEVHT2SS_MCS7:
pwr_tracking_limit = 26 ;
break ;
default :
case DESC_RATEVHT1SS_MCS8:
case DESC_RATEVHT2SS_MCS8:
pwr_tracking_limit = 24 ;
break ;
case DESC_RATEVHT1SS_MCS9:
case DESC_RATEVHT2SS_MCS9:
pwr_tracking_limit = 22 ;
break ;
}
cck_swing_idx = dm_info->delta_power_index[path] + dm_info->default_cck_index;
ofdm_swing_idx = dm_info->delta_power_index[path] + dm_info->default_ofdm_index;
if (ofdm_swing_idx > pwr_tracking_limit) {
if (path == RF_PATH_A)
dm_info->txagc_remnant_cck = cck_swing_idx - pwr_tracking_limit;
dm_info->txagc_remnant_ofdm[path] = ofdm_swing_idx - pwr_tracking_limit;
ofdm_swing_idx = pwr_tracking_limit;
} else if (ofdm_swing_idx == 0 ) {
if (path == RF_PATH_A)
dm_info->txagc_remnant_cck = cck_swing_idx;
dm_info->txagc_remnant_ofdm[path] = ofdm_swing_idx;
} else {
if (path == RF_PATH_A)
dm_info->txagc_remnant_cck = 0 ;
dm_info->txagc_remnant_ofdm[path] = 0 ;
}
rtw_write32_mask(rtwdev, reg_txscale[path], GENMASK(31 , 21 ),
rtw88xxa_txscale_tbl[ofdm_swing_idx]);
}
void rtw88xxa_phy_pwrtrack(struct rtw_dev *rtwdev,
void (*do_lck)(struct rtw_dev *rtwdev),
void (*do_iqk)(struct rtw_dev *rtwdev))
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
struct rtw_hal *hal = &rtwdev->hal;
struct rtw_swing_table swing_table;
s8 remnant_pre[RTW_RF_PATH_MAX];
u8 thermal_value, delta, path;
bool need_iqk;
rtw_phy_config_swing_table(rtwdev, &swing_table);
if (rtwdev->efuse.thermal_meter[0 ] == 0 xff) {
pr_err_once("efuse thermal meter is 0xff\n" );
return ;
}
thermal_value = rtw_read_rf(rtwdev, RF_PATH_A, RF_T_METER, 0 xfc00);
rtw_phy_pwrtrack_avg(rtwdev, thermal_value, RF_PATH_A);
need_iqk = rtw_phy_pwrtrack_need_iqk(rtwdev);
if (need_iqk && do_lck)
do_lck(rtwdev);
if (dm_info->pwr_trk_init_trigger)
dm_info->pwr_trk_init_trigger = false ;
else if (!rtw_phy_pwrtrack_thermal_changed(rtwdev, thermal_value,
RF_PATH_A))
goto iqk;
delta = rtw_phy_pwrtrack_get_delta(rtwdev, RF_PATH_A);
for (path = RF_PATH_A; path < hal->rf_path_num; path++) {
remnant_pre[path] = dm_info->txagc_remnant_ofdm[path];
dm_info->delta_power_index[path] =
rtw_phy_pwrtrack_get_pwridx(rtwdev, &swing_table, path,
RF_PATH_A, delta);
if (dm_info->delta_power_index[path] !=
dm_info->delta_power_index_last[path]) {
dm_info->delta_power_index_last[path] =
dm_info->delta_power_index[path];
rtw88xxa_pwrtrack_set(rtwdev, dm_info->tx_rate, path);
}
}
for (path = RF_PATH_A; path < hal->rf_path_num; path++) {
if (remnant_pre[path] != dm_info->txagc_remnant_ofdm[path]) {
rtw_phy_set_tx_power_level(rtwdev,
hal->current_channel);
break ;
}
}
iqk:
if (need_iqk)
do_iqk(rtwdev);
}
EXPORT_SYMBOL(rtw88xxa_phy_pwrtrack);
void rtw88xxa_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl)
{
static const u8 pd[CCK_PD_LV_MAX] = {0 x40, 0 x83, 0 xcd, 0 xdd, 0 xed};
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
/* Override rtw_phy_cck_pd_lv_link(). It implements something
* like type 2/3/4. We need type 1 here.
*/
if (rtw_is_assoc(rtwdev)) {
if (dm_info->min_rssi > 60 ) {
new_lvl = CCK_PD_LV3;
} else if (dm_info->min_rssi > 35 ) {
new_lvl = CCK_PD_LV2;
} else if (dm_info->min_rssi > 20 ) {
if (dm_info->cck_fa_avg > 500 )
new_lvl = CCK_PD_LV2;
else if (dm_info->cck_fa_avg < 250 )
new_lvl = CCK_PD_LV1;
else
return ;
} else {
new_lvl = CCK_PD_LV1;
}
}
rtw_dbg(rtwdev, RTW_DBG_PHY, "lv: (%d) -> (%d)\n" ,
dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A], new_lvl);
if (dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A] == new_lvl)
return ;
dm_info->cck_fa_avg = CCK_FA_AVG_RESET;
dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A] = new_lvl;
rtw_write8(rtwdev, REG_CCK_PD_TH, pd[new_lvl]);
}
EXPORT_SYMBOL(rtw88xxa_phy_cck_pd_set);
MODULE_AUTHOR("Realtek Corporation" );
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821a/8811a/8812a common code" );
MODULE_LICENSE("Dual BSD/GPL" );
Messung V0.5 in Prozent C=99 H=95 G=96
¤ Dauer der Verarbeitung: 0.20 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland