Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,271 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig RTW88
tristate "Realtek 802.11ac wireless chips support"
depends on MAC80211
help
This module adds support for mac80211-based wireless drivers that
enables Realtek IEEE 802.11ac wireless chipsets.
If you choose to build a module, it'll be called rtw88.
if RTW88
config RTW88_CORE
tristate
select WANT_DEV_COREDUMP
config RTW88_PCI
tristate
config RTW88_SDIO
tristate
config RTW88_USB
tristate
config RTW88_8822B
tristate
config RTW88_8822C
tristate
config RTW88_8723X
tristate
config RTW88_8703B
tristate
select RTW88_8723X
config RTW88_8723D
tristate
select RTW88_8723X
config RTW88_8821C
tristate
config RTW88_88XXA
tristate
config RTW88_8821A
tristate
select RTW88_88XXA
config RTW88_8812A
tristate
select RTW88_88XXA
config RTW88_8814A
tristate
config RTW88_8822BE
tristate "Realtek 8822BE PCI wireless network adapter"
depends on PCI
select RTW88_CORE
select RTW88_PCI
select RTW88_8822B
help
Select this option will enable support for 8822BE chipset
802.11ac PCIe wireless network adapter
config RTW88_8822BS
tristate "Realtek 8822BS SDIO wireless network adapter"
depends on MMC
select RTW88_CORE
select RTW88_SDIO
select RTW88_8822B
help
Select this option will enable support for 8822BS chipset
802.11ac SDIO wireless network adapter
config RTW88_8822BU
tristate "Realtek 8822BU USB wireless network adapter"
depends on USB
select RTW88_CORE
select RTW88_USB
select RTW88_8822B
help
Select this option will enable support for 8822BU chipset
802.11ac USB wireless network adapter
config RTW88_8822CE
tristate "Realtek 8822CE PCI wireless network adapter"
depends on PCI
select RTW88_CORE
select RTW88_PCI
select RTW88_8822C
help
Select this option will enable support for 8822CE chipset
802.11ac PCIe wireless network adapter
config RTW88_8822CS
tristate "Realtek 8822CS SDIO wireless network adapter"
depends on MMC
select RTW88_CORE
select RTW88_SDIO
select RTW88_8822C
help
Select this option will enable support for 8822CS chipset
802.11ac SDIO wireless network adapter
config RTW88_8822CU
tristate "Realtek 8822CU USB wireless network adapter"
depends on USB
select RTW88_CORE
select RTW88_USB
select RTW88_8822C
help
Select this option will enable support for 8822CU chipset
802.11ac USB wireless network adapter
config RTW88_8723DE
tristate "Realtek 8723DE PCI wireless network adapter"
depends on PCI
select RTW88_CORE
select RTW88_PCI
select RTW88_8723D
help
Select this option will enable support for 8723DE chipset
802.11n PCIe wireless network adapter
config RTW88_8723DS
tristate "Realtek 8723DS SDIO wireless network adapter"
depends on MMC
select RTW88_CORE
select RTW88_SDIO
select RTW88_8723D
help
Select this option will enable support for 8723DS chipset
802.11n SDIO wireless network adapter
config RTW88_8723CS
tristate "Realtek 8723CS SDIO wireless network adapter"
depends on MMC
select RTW88_CORE
select RTW88_SDIO
select RTW88_8703B
help
Select this option to enable support for 8723CS chipset (EXPERIMENTAL)
This module adds support for the 8723CS 802.11n SDIO
wireless network adapter.
If you choose to build a module, it'll be called rtw88_8723cs.
config RTW88_8723DU
tristate "Realtek 8723DU USB wireless network adapter"
depends on USB
select RTW88_CORE
select RTW88_USB
select RTW88_8723D
help
Select this option will enable support for 8723DU chipset
802.11n USB wireless network adapter
config RTW88_8821CE
tristate "Realtek 8821CE PCI wireless network adapter"
depends on PCI
select RTW88_CORE
select RTW88_PCI
select RTW88_8821C
help
Select this option will enable support for 8821CE chipset
802.11ac PCIe wireless network adapter
config RTW88_8821CS
tristate "Realtek 8821CS SDIO wireless network adapter"
depends on MMC
select RTW88_CORE
select RTW88_SDIO
select RTW88_8821C
help
Select this option will enable support for 8821CS chipset
802.11ac SDIO wireless network adapter
config RTW88_8821CU
tristate "Realtek 8821CU USB wireless network adapter"
depends on USB
select RTW88_CORE
select RTW88_USB
select RTW88_8821C
help
Select this option will enable support for 8821CU chipset
802.11ac USB wireless network adapter
config RTW88_8821AU
tristate "Realtek 8821AU/8811AU USB wireless network adapter"
depends on USB
select RTW88_CORE
select RTW88_USB
select RTW88_8821A
help
Select this option will enable support for 8821AU and 8811AU chipset
802.11ac USB wireless network adapter
config RTW88_8812AU
tristate "Realtek 8812AU USB wireless network adapter"
depends on USB
select RTW88_CORE
select RTW88_USB
select RTW88_8812A
help
Select this option will enable support for 8812AU chipset
802.11ac USB wireless network adapter
config RTW88_8814AE
tristate "Realtek 8814AE PCI wireless network adapter"
depends on PCI
select RTW88_CORE
select RTW88_PCI
select RTW88_8814A
help
Select this option will enable support for 8814AE chipset
802.11ac PCIe wireless network adapter
config RTW88_8814AU
tristate "Realtek 8814AU USB wireless network adapter"
depends on USB
select RTW88_CORE
select RTW88_USB
select RTW88_8814A
help
Select this option will enable support for 8814AU chipset
802.11ac USB wireless network adapter
config RTW88_DEBUG
bool "Realtek rtw88 debug support"
depends on RTW88_CORE
help
Enable debug support
If unsure, say Y to simplify debug problems
config RTW88_DEBUGFS
bool "Realtek rtw88 debugfs support"
depends on RTW88_CORE
help
Enable debug support
If unsure, say Y to simplify debug problems
config RTW88_LEDS
bool
depends on LEDS_CLASS=y || LEDS_CLASS=MAC80211
default y
endif
@@ -0,0 +1,113 @@
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
obj-$(CONFIG_RTW88_CORE) += rtw88_core.o
rtw88_core-y += main.o \
mac80211.o \
util.o \
debug.o \
tx.o \
rx.o \
mac.o \
phy.o \
coex.o \
efuse.o \
fw.o \
ps.o \
sec.o \
bf.o \
sar.o \
regd.o
rtw88_core-$(CONFIG_PM) += wow.o
rtw88_core-$(CONFIG_RTW88_LEDS) += led.o
obj-$(CONFIG_RTW88_8822B) += rtw88_8822b.o
rtw88_8822b-objs := rtw8822b.o rtw8822b_table.o
obj-$(CONFIG_RTW88_8822BE) += rtw88_8822be.o
rtw88_8822be-objs := rtw8822be.o
obj-$(CONFIG_RTW88_8822BS) += rtw88_8822bs.o
rtw88_8822bs-objs := rtw8822bs.o
obj-$(CONFIG_RTW88_8822BU) += rtw88_8822bu.o
rtw88_8822bu-objs := rtw8822bu.o
obj-$(CONFIG_RTW88_8822C) += rtw88_8822c.o
rtw88_8822c-objs := rtw8822c.o rtw8822c_table.o
obj-$(CONFIG_RTW88_8822CE) += rtw88_8822ce.o
rtw88_8822ce-objs := rtw8822ce.o
obj-$(CONFIG_RTW88_8822CS) += rtw88_8822cs.o
rtw88_8822cs-objs := rtw8822cs.o
obj-$(CONFIG_RTW88_8822CU) += rtw88_8822cu.o
rtw88_8822cu-objs := rtw8822cu.o
obj-$(CONFIG_RTW88_8723X) += rtw88_8723x.o
rtw88_8723x-objs := rtw8723x.o
obj-$(CONFIG_RTW88_8703B) += rtw88_8703b.o
rtw88_8703b-objs := rtw8703b.o rtw8703b_tables.o
obj-$(CONFIG_RTW88_8723CS) += rtw88_8723cs.o
rtw88_8723cs-objs := rtw8723cs.o
obj-$(CONFIG_RTW88_8723D) += rtw88_8723d.o
rtw88_8723d-objs := rtw8723d.o rtw8723d_table.o
obj-$(CONFIG_RTW88_8723DE) += rtw88_8723de.o
rtw88_8723de-objs := rtw8723de.o
obj-$(CONFIG_RTW88_8723DS) += rtw88_8723ds.o
rtw88_8723ds-objs := rtw8723ds.o
obj-$(CONFIG_RTW88_8723DU) += rtw88_8723du.o
rtw88_8723du-objs := rtw8723du.o
obj-$(CONFIG_RTW88_8821C) += rtw88_8821c.o
rtw88_8821c-objs := rtw8821c.o rtw8821c_table.o
obj-$(CONFIG_RTW88_8821CE) += rtw88_8821ce.o
rtw88_8821ce-objs := rtw8821ce.o
obj-$(CONFIG_RTW88_8821CS) += rtw88_8821cs.o
rtw88_8821cs-objs := rtw8821cs.o
obj-$(CONFIG_RTW88_8821CU) += rtw88_8821cu.o
rtw88_8821cu-objs := rtw8821cu.o
obj-$(CONFIG_RTW88_88XXA) += rtw88_88xxa.o
rtw88_88xxa-objs := rtw88xxa.o
obj-$(CONFIG_RTW88_8821A) += rtw88_8821a.o
rtw88_8821a-objs := rtw8821a.o rtw8821a_table.o
obj-$(CONFIG_RTW88_8812A) += rtw88_8812a.o
rtw88_8812a-objs := rtw8812a.o rtw8812a_table.o
obj-$(CONFIG_RTW88_8821AU) += rtw88_8821au.o
rtw88_8821au-objs := rtw8821au.o
obj-$(CONFIG_RTW88_8812AU) += rtw88_8812au.o
rtw88_8812au-objs := rtw8812au.o
obj-$(CONFIG_RTW88_8814A) += rtw88_8814a.o
rtw88_8814a-objs := rtw8814a.o rtw8814a_table.o
obj-$(CONFIG_RTW88_8814AE) += rtw88_8814ae.o
rtw88_8814ae-objs := rtw8814ae.o
obj-$(CONFIG_RTW88_8814AU) += rtw88_8814au.o
rtw88_8814au-objs := rtw8814au.o
obj-$(CONFIG_RTW88_PCI) += rtw88_pci.o
rtw88_pci-objs := pci.o
obj-$(CONFIG_RTW88_SDIO) += rtw88_sdio.o
rtw88_sdio-objs := sdio.o
obj-$(CONFIG_RTW88_USB) += rtw88_usb.o
rtw88_usb-objs := usb.o
@@ -0,0 +1,416 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation.
*/
#include "main.h"
#include "reg.h"
#include "bf.h"
#include "debug.h"
void rtw_bf_disassoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf)
{
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
struct rtw_bfee *bfee = &rtwvif->bfee;
struct rtw_bf_info *bfinfo = &rtwdev->bf_info;
if (bfee->role == RTW_BFEE_NONE)
return;
if (bfee->role == RTW_BFEE_MU)
bfinfo->bfer_mu_cnt--;
else if (bfee->role == RTW_BFEE_SU)
bfinfo->bfer_su_cnt--;
rtw_chip_config_bfee(rtwdev, rtwvif, bfee, false);
bfee->role = RTW_BFEE_NONE;
}
void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct ieee80211_hw *hw = rtwdev->hw;
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
struct rtw_bfee *bfee = &rtwvif->bfee;
struct rtw_bf_info *bfinfo = &rtwdev->bf_info;
struct ieee80211_sta *sta;
struct ieee80211_sta_vht_cap *vht_cap;
struct ieee80211_sta_vht_cap *ic_vht_cap;
const u8 *bssid = bss_conf->bssid;
u32 sound_dim;
u8 i;
if (!(chip->band & RTW_BAND_5G))
return;
rcu_read_lock();
sta = ieee80211_find_sta(vif, bssid);
if (!sta) {
rcu_read_unlock();
rtw_warn(rtwdev, "failed to find station entry for bss %pM\n",
bssid);
return;
}
ic_vht_cap = &hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap;
vht_cap = &sta->deflink.vht_cap;
rcu_read_unlock();
if ((ic_vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) &&
(vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) {
if (bfinfo->bfer_mu_cnt >= chip->bfer_mu_max_num) {
rtw_dbg(rtwdev, RTW_DBG_BF, "mu bfer number over limit\n");
return;
}
ether_addr_copy(bfee->mac_addr, bssid);
bfee->role = RTW_BFEE_MU;
bfee->p_aid = (bssid[5] << 1) | (bssid[4] >> 7);
bfee->aid = vif->cfg.aid;
bfinfo->bfer_mu_cnt++;
rtw_chip_config_bfee(rtwdev, rtwvif, bfee, true);
} else if ((ic_vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) &&
(vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) {
if (bfinfo->bfer_su_cnt >= chip->bfer_su_max_num) {
rtw_dbg(rtwdev, RTW_DBG_BF, "su bfer number over limit\n");
return;
}
sound_dim = vht_cap->cap &
IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
sound_dim >>= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
ether_addr_copy(bfee->mac_addr, bssid);
bfee->role = RTW_BFEE_SU;
bfee->sound_dim = (u8)sound_dim;
bfee->g_id = 0;
bfee->p_aid = (bssid[5] << 1) | (bssid[4] >> 7);
bfinfo->bfer_su_cnt++;
for (i = 0; i < chip->bfer_su_max_num; i++) {
if (!test_bit(i, bfinfo->bfer_su_reg_maping)) {
set_bit(i, bfinfo->bfer_su_reg_maping);
bfee->su_reg_index = i;
break;
}
}
rtw_chip_config_bfee(rtwdev, rtwvif, bfee, true);
}
}
void rtw_bf_init_bfer_entry_mu(struct rtw_dev *rtwdev,
struct mu_bfer_init_para *param)
{
u16 mu_bf_ctl = 0;
u8 *addr = param->bfer_address;
int i;
for (i = 0; i < ETH_ALEN; i++)
rtw_write8(rtwdev, REG_ASSOCIATED_BFMER0_INFO + i, addr[i]);
rtw_write16(rtwdev, REG_ASSOCIATED_BFMER0_INFO + 6, param->paid);
rtw_write16(rtwdev, REG_TX_CSI_RPT_PARAM_BW20, param->csi_para);
mu_bf_ctl = rtw_read16(rtwdev, REG_WMAC_MU_BF_CTL) & 0xC000;
mu_bf_ctl |= param->my_aid | (param->csi_length_sel << 12);
rtw_write16(rtwdev, REG_WMAC_MU_BF_CTL, mu_bf_ctl);
}
void rtw_bf_cfg_sounding(struct rtw_dev *rtwdev, struct rtw_vif *vif,
enum rtw_trx_desc_rate rate)
{
u8 csi_rsc = CSI_RSC_FOLLOW_RX_PACKET_BW;
u32 psf_ctl = 0;
if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C)
csi_rsc = CSI_RSC_PRIMARY_20M_BW;
psf_ctl = rtw_read32(rtwdev, REG_BBPSF_CTRL) |
BIT_WMAC_USE_NDPARATE |
(csi_rsc << 13);
rtw_write8_mask(rtwdev, REG_SND_PTCL_CTRL, BIT_MASK_BEAMFORM,
RTW_SND_CTRL_SOUNDING);
rtw_write8(rtwdev, REG_SND_PTCL_CTRL + 3, 0x26);
rtw_write8_clr(rtwdev, REG_RXFLTMAP1, BIT_RXFLTMAP1_BF_REPORT_POLL);
rtw_write8_clr(rtwdev, REG_RXFLTMAP4, BIT_RXFLTMAP4_BF_REPORT_POLL);
if (vif->net_type == RTW_NET_AP_MODE)
rtw_write32(rtwdev, REG_BBPSF_CTRL, psf_ctl | BIT(12));
else
rtw_write32(rtwdev, REG_BBPSF_CTRL, psf_ctl & ~BIT(12));
}
void rtw_bf_cfg_mu_bfee(struct rtw_dev *rtwdev, struct cfg_mumimo_para *param)
{
u8 mu_tbl_sel;
u8 mu_valid;
mu_valid = rtw_read8(rtwdev, REG_MU_TX_CTL) &
~BIT_MASK_R_MU_TABLE_VALID;
rtw_write8(rtwdev, REG_MU_TX_CTL,
(mu_valid | BIT(0) | BIT(1)) & ~(BIT(7)));
mu_tbl_sel = rtw_read8(rtwdev, REG_MU_TX_CTL + 1) & 0xF8;
rtw_write8(rtwdev, REG_MU_TX_CTL + 1, mu_tbl_sel);
rtw_write32(rtwdev, REG_MU_STA_GID_VLD, param->given_gid_tab[0]);
rtw_write32(rtwdev, REG_MU_STA_USER_POS_INFO, param->given_user_pos[0]);
rtw_write32(rtwdev, REG_MU_STA_USER_POS_INFO + 4,
param->given_user_pos[1]);
rtw_write8(rtwdev, REG_MU_TX_CTL + 1, mu_tbl_sel | 1);
rtw_write32(rtwdev, REG_MU_STA_GID_VLD, param->given_gid_tab[1]);
rtw_write32(rtwdev, REG_MU_STA_USER_POS_INFO, param->given_user_pos[2]);
rtw_write32(rtwdev, REG_MU_STA_USER_POS_INFO + 4,
param->given_user_pos[3]);
}
void rtw_bf_del_bfer_entry_mu(struct rtw_dev *rtwdev)
{
rtw_write32(rtwdev, REG_ASSOCIATED_BFMER0_INFO, 0);
rtw_write32(rtwdev, REG_ASSOCIATED_BFMER0_INFO + 4, 0);
rtw_write16(rtwdev, REG_WMAC_MU_BF_CTL, 0);
rtw_write8(rtwdev, REG_MU_TX_CTL, 0);
}
void rtw_bf_del_sounding(struct rtw_dev *rtwdev)
{
rtw_write8_mask(rtwdev, REG_SND_PTCL_CTRL, BIT_MASK_BEAMFORM, 0);
}
void rtw_bf_enable_bfee_su(struct rtw_dev *rtwdev, struct rtw_vif *vif,
struct rtw_bfee *bfee)
{
u8 nc_index = hweight8(rtwdev->hal.antenna_rx) - 1;
u8 nr_index = bfee->sound_dim;
u8 grouping = 0, codebookinfo = 1, coefficientsize = 3;
u32 addr_bfer_info, addr_csi_rpt, csi_param;
u8 i;
rtw_dbg(rtwdev, RTW_DBG_BF, "config as an su bfee\n");
switch (bfee->su_reg_index) {
case 1:
addr_bfer_info = REG_ASSOCIATED_BFMER1_INFO;
addr_csi_rpt = REG_TX_CSI_RPT_PARAM_BW20 + 2;
break;
case 0:
default:
addr_bfer_info = REG_ASSOCIATED_BFMER0_INFO;
addr_csi_rpt = REG_TX_CSI_RPT_PARAM_BW20;
break;
}
/* Sounding protocol control */
rtw_write8_mask(rtwdev, REG_SND_PTCL_CTRL, BIT_MASK_BEAMFORM,
RTW_SND_CTRL_SOUNDING);
/* MAC address/Partial AID of Beamformer */
for (i = 0; i < ETH_ALEN; i++)
rtw_write8(rtwdev, addr_bfer_info + i, bfee->mac_addr[i]);
csi_param = (u16)((coefficientsize << 10) |
(codebookinfo << 8) |
(grouping << 6) |
(nr_index << 3) |
nc_index);
rtw_write16(rtwdev, addr_csi_rpt, csi_param);
/* ndp rx standby timer */
rtw_write8(rtwdev, REG_SND_PTCL_CTRL + 3, RTW_NDP_RX_STANDBY_TIME);
}
EXPORT_SYMBOL(rtw_bf_enable_bfee_su);
/* nc index: 1 2T2R 0 1T1R
* nr index: 1 use Nsts 0 use reg setting
* codebookinfo: 1 802.11ac 3 802.11n
*/
void rtw_bf_enable_bfee_mu(struct rtw_dev *rtwdev, struct rtw_vif *vif,
struct rtw_bfee *bfee)
{
struct rtw_bf_info *bf_info = &rtwdev->bf_info;
struct mu_bfer_init_para param;
u8 nc_index = hweight8(rtwdev->hal.antenna_rx) - 1;
u8 nr_index = 1;
u8 grouping = 0, codebookinfo = 1, coefficientsize = 0;
u32 csi_param;
rtw_dbg(rtwdev, RTW_DBG_BF, "config as an mu bfee\n");
csi_param = (u16)((coefficientsize << 10) |
(codebookinfo << 8) |
(grouping << 6) |
(nr_index << 3) |
nc_index);
rtw_dbg(rtwdev, RTW_DBG_BF, "nc=%d nr=%d group=%d codebookinfo=%d coefficientsize=%d\n",
nc_index, nr_index, grouping, codebookinfo,
coefficientsize);
param.paid = bfee->p_aid;
param.csi_para = csi_param;
param.my_aid = bfee->aid & 0xfff;
param.csi_length_sel = HAL_CSI_SEG_4K;
ether_addr_copy(param.bfer_address, bfee->mac_addr);
rtw_bf_init_bfer_entry_mu(rtwdev, &param);
bf_info->cur_csi_rpt_rate = DESC_RATE6M;
rtw_bf_cfg_sounding(rtwdev, vif, DESC_RATE6M);
/* accept action_no_ack */
rtw_write16_set(rtwdev, REG_RXFLTMAP0, BIT_RXFLTMAP0_ACTIONNOACK);
/* accept NDPA and BF report poll */
rtw_write16_set(rtwdev, REG_RXFLTMAP1, BIT_RXFLTMAP1_BF);
}
EXPORT_SYMBOL(rtw_bf_enable_bfee_mu);
void rtw_bf_remove_bfee_su(struct rtw_dev *rtwdev,
struct rtw_bfee *bfee)
{
struct rtw_bf_info *bfinfo = &rtwdev->bf_info;
rtw_dbg(rtwdev, RTW_DBG_BF, "remove as a su bfee\n");
rtw_write8_mask(rtwdev, REG_SND_PTCL_CTRL, BIT_MASK_BEAMFORM,
RTW_SND_CTRL_REMOVE);
switch (bfee->su_reg_index) {
case 0:
rtw_write32(rtwdev, REG_ASSOCIATED_BFMER0_INFO, 0);
rtw_write16(rtwdev, REG_ASSOCIATED_BFMER0_INFO + 4, 0);
rtw_write16(rtwdev, REG_TX_CSI_RPT_PARAM_BW20, 0);
break;
case 1:
rtw_write32(rtwdev, REG_ASSOCIATED_BFMER1_INFO, 0);
rtw_write16(rtwdev, REG_ASSOCIATED_BFMER1_INFO + 4, 0);
rtw_write16(rtwdev, REG_TX_CSI_RPT_PARAM_BW20 + 2, 0);
break;
}
clear_bit(bfee->su_reg_index, bfinfo->bfer_su_reg_maping);
bfee->su_reg_index = 0xFF;
}
EXPORT_SYMBOL(rtw_bf_remove_bfee_su);
void rtw_bf_remove_bfee_mu(struct rtw_dev *rtwdev,
struct rtw_bfee *bfee)
{
struct rtw_bf_info *bfinfo = &rtwdev->bf_info;
rtw_write8_mask(rtwdev, REG_SND_PTCL_CTRL, BIT_MASK_BEAMFORM,
RTW_SND_CTRL_REMOVE);
rtw_bf_del_bfer_entry_mu(rtwdev);
if (bfinfo->bfer_su_cnt == 0 && bfinfo->bfer_mu_cnt == 0)
rtw_bf_del_sounding(rtwdev);
}
EXPORT_SYMBOL(rtw_bf_remove_bfee_mu);
void rtw_bf_set_gid_table(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *conf)
{
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
struct rtw_bfee *bfee = &rtwvif->bfee;
struct cfg_mumimo_para param;
if (bfee->role != RTW_BFEE_MU) {
rtw_dbg(rtwdev, RTW_DBG_BF, "this vif is not mu bfee\n");
return;
}
param.grouping_bitmap = 0;
param.mu_tx_en = 0;
memset(param.sounding_sts, 0, 6);
memcpy(param.given_gid_tab, conf->mu_group.membership, 8);
memcpy(param.given_user_pos, conf->mu_group.position, 16);
rtw_dbg(rtwdev, RTW_DBG_BF, "STA0: gid_valid=0x%x, user_position_l=0x%x, user_position_h=0x%x\n",
param.given_gid_tab[0], param.given_user_pos[0],
param.given_user_pos[1]);
rtw_dbg(rtwdev, RTW_DBG_BF, "STA1: gid_valid=0x%x, user_position_l=0x%x, user_position_h=0x%x\n",
param.given_gid_tab[1], param.given_user_pos[2],
param.given_user_pos[3]);
rtw_bf_cfg_mu_bfee(rtwdev, &param);
}
EXPORT_SYMBOL(rtw_bf_set_gid_table);
void rtw_bf_phy_init(struct rtw_dev *rtwdev)
{
u8 tmp8;
u32 tmp32;
u8 retry_limit = 0xA;
u8 ndpa_rate = 0x10;
u8 ack_policy = 3;
tmp32 = rtw_read32(rtwdev, REG_MU_TX_CTL);
/* Enable P1 aggr new packet according to P0 transfer time */
tmp32 |= BIT_MU_P1_WAIT_STATE_EN;
/* MU Retry Limit */
tmp32 &= ~BIT_MASK_R_MU_RL;
tmp32 |= (retry_limit << BIT_SHIFT_R_MU_RL) & BIT_MASK_R_MU_RL;
/* Disable Tx MU-MIMO until sounding done */
tmp32 &= ~BIT_EN_MU_MIMO;
/* Clear validity of MU STAs */
tmp32 &= ~BIT_MASK_R_MU_TABLE_VALID;
rtw_write32(rtwdev, REG_MU_TX_CTL, tmp32);
/* MU-MIMO Option as default value */
tmp8 = ack_policy << BIT_SHIFT_WMAC_TXMU_ACKPOLICY;
tmp8 |= BIT_WMAC_TXMU_ACKPOLICY_EN;
rtw_write8(rtwdev, REG_WMAC_MU_BF_OPTION, tmp8);
/* MU-MIMO Control as default value */
rtw_write16(rtwdev, REG_WMAC_MU_BF_CTL, 0);
/* Set MU NDPA rate & BW source */
rtw_write32_set(rtwdev, REG_TXBF_CTRL, BIT_USE_NDPA_PARAMETER);
/* Set NDPA Rate */
rtw_write8(rtwdev, REG_NDPA_OPT_CTRL, ndpa_rate);
rtw_write32_mask(rtwdev, REG_BBPSF_CTRL, BIT_MASK_CSI_RATE,
DESC_RATE6M);
}
EXPORT_SYMBOL(rtw_bf_phy_init);
void rtw_bf_cfg_csi_rate(struct rtw_dev *rtwdev, u8 rssi, u8 cur_rate,
u8 fixrate_en, u8 *new_rate)
{
u32 csi_cfg;
u16 cur_rrsr;
csi_cfg = rtw_read32(rtwdev, REG_BBPSF_CTRL) & ~BIT_MASK_CSI_RATE;
cur_rrsr = rtw_read16(rtwdev, REG_RRSR);
if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C)
csi_cfg |= BIT_CSI_FORCE_RATE;
if (rssi >= 40) {
if (cur_rate != DESC_RATE54M) {
cur_rrsr |= BIT(DESC_RATE54M);
csi_cfg |= (DESC_RATE54M & BIT_MASK_CSI_RATE_VAL) <<
BIT_SHIFT_CSI_RATE;
rtw_write16(rtwdev, REG_RRSR, cur_rrsr);
rtw_write32(rtwdev, REG_BBPSF_CTRL, csi_cfg);
}
*new_rate = DESC_RATE54M;
} else {
if (cur_rate != DESC_RATE24M) {
cur_rrsr &= ~BIT(DESC_RATE54M);
csi_cfg |= (DESC_RATE54M & BIT_MASK_CSI_RATE_VAL) <<
BIT_SHIFT_CSI_RATE;
rtw_write16(rtwdev, REG_RRSR, cur_rrsr);
rtw_write32(rtwdev, REG_BBPSF_CTRL, csi_cfg);
}
*new_rate = DESC_RATE24M;
}
}
EXPORT_SYMBOL(rtw_bf_cfg_csi_rate);
@@ -0,0 +1,124 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation.
*/
#ifndef __RTW_BF_H_
#define __RTW_BF_H_
#define REG_TXBF_CTRL 0x042C
#define REG_RRSR 0x0440
#define REG_NDPA_OPT_CTRL 0x045F
#define REG_ASSOCIATED_BFMER0_INFO 0x06E4
#define REG_ASSOCIATED_BFMER1_INFO 0x06EC
#define REG_TX_CSI_RPT_PARAM_BW20 0x06F4
#define REG_SND_PTCL_CTRL 0x0718
#define BIT_DIS_CHK_VHTSIGB_CRC BIT(6)
#define BIT_DIS_CHK_VHTSIGA_CRC BIT(5)
#define BIT_MASK_BEAMFORM (GENMASK(4, 0) | BIT(7))
#define REG_MU_TX_CTL 0x14C0
#define REG_MU_STA_GID_VLD 0x14C4
#define REG_MU_STA_USER_POS_INFO 0x14C8
#define REG_CSI_RRSR 0x1678
#define REG_WMAC_MU_BF_OPTION 0x167C
#define REG_WMAC_MU_BF_CTL 0x1680
#define BIT_WMAC_USE_NDPARATE BIT(30)
#define BIT_WMAC_TXMU_ACKPOLICY_EN BIT(6)
#define BIT_USE_NDPA_PARAMETER BIT(30)
#define BIT_MU_P1_WAIT_STATE_EN BIT(16)
#define BIT_EN_MU_MIMO BIT(7)
#define R_MU_RL 0xf
#define BIT_SHIFT_R_MU_RL 12
#define BIT_SHIFT_WMAC_TXMU_ACKPOLICY 4
#define BIT_SHIFT_CSI_RATE 24
#define BIT_CSI_FORCE_RATE BIT(15)
#define BIT_MASK_R_MU_RL (R_MU_RL << BIT_SHIFT_R_MU_RL)
#define BIT_MASK_R_MU_TABLE_VALID 0x3f
#define BIT_MASK_CSI_RATE_VAL 0x3F
#define BIT_MASK_CSI_RATE (BIT_MASK_CSI_RATE_VAL << BIT_SHIFT_CSI_RATE)
#define BIT_RXFLTMAP0_ACTIONNOACK BIT(14)
#define BIT_RXFLTMAP1_BF (BIT(4) | BIT(5))
#define BIT_RXFLTMAP1_BF_REPORT_POLL BIT(4)
#define BIT_RXFLTMAP4_BF_REPORT_POLL BIT(4)
#define RTW_NDP_RX_STANDBY_TIME 0x70
#define RTW_SND_CTRL_REMOVE 0x98
#define RTW_SND_CTRL_SOUNDING 0x9B
enum csi_rsc {
CSI_RSC_PRIMARY_20M_BW = 0,
CSI_RSC_FOLLOW_RX_PACKET_BW = 1,
CSI_RSC_DUPLICATE_MODE = 2,
};
enum csi_seg_len {
HAL_CSI_SEG_4K = 0,
HAL_CSI_SEG_8K = 1,
HAL_CSI_SEG_11K = 2,
};
struct cfg_mumimo_para {
u8 sounding_sts[6];
u16 grouping_bitmap;
u8 mu_tx_en;
u32 given_gid_tab[2];
u32 given_user_pos[4];
};
struct mu_bfer_init_para {
u16 paid;
u16 csi_para;
u16 my_aid;
enum csi_seg_len csi_length_sel;
u8 bfer_address[ETH_ALEN];
};
void rtw_bf_disassoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf);
void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf);
void rtw_bf_init_bfer_entry_mu(struct rtw_dev *rtwdev,
struct mu_bfer_init_para *param);
void rtw_bf_cfg_sounding(struct rtw_dev *rtwdev, struct rtw_vif *vif,
enum rtw_trx_desc_rate rate);
void rtw_bf_cfg_mu_bfee(struct rtw_dev *rtwdev, struct cfg_mumimo_para *param);
void rtw_bf_del_bfer_entry_mu(struct rtw_dev *rtwdev);
void rtw_bf_del_sounding(struct rtw_dev *rtwdev);
void rtw_bf_enable_bfee_su(struct rtw_dev *rtwdev, struct rtw_vif *vif,
struct rtw_bfee *bfee);
void rtw_bf_enable_bfee_mu(struct rtw_dev *rtwdev, struct rtw_vif *vif,
struct rtw_bfee *bfee);
void rtw_bf_remove_bfee_su(struct rtw_dev *rtwdev, struct rtw_bfee *bfee);
void rtw_bf_remove_bfee_mu(struct rtw_dev *rtwdev, struct rtw_bfee *bfee);
void rtw_bf_set_gid_table(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *conf);
void rtw_bf_phy_init(struct rtw_dev *rtwdev);
void rtw_bf_cfg_csi_rate(struct rtw_dev *rtwdev, u8 rssi, u8 cur_rate,
u8 fixrate_en, u8 *new_rate);
static inline void rtw_chip_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif,
struct rtw_bfee *bfee, bool enable)
{
if (rtwdev->chip->ops->config_bfee)
rtwdev->chip->ops->config_bfee(rtwdev, vif, bfee, enable);
}
static inline void rtw_chip_set_gid_table(struct rtw_dev *rtwdev,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *conf)
{
if (rtwdev->chip->ops->set_gid_table)
rtwdev->chip->ops->set_gid_table(rtwdev, vif, conf);
}
static inline void rtw_chip_cfg_csi_rate(struct rtw_dev *rtwdev, u8 rssi, u8 cur_rate,
u8 fixrate_en, u8 *new_rate)
{
if (rtwdev->chip->ops->cfg_csi_rate)
rtwdev->chip->ops->cfg_csi_rate(rtwdev, rssi, cur_rate,
fixrate_en, new_rate);
}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,433 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_COEX_H__
#define __RTW_COEX_H__
#define COEX_CCK_2 0x1
#define COEX_RESP_ACK_BY_WL_FW 0x1
#define COEX_REQUEST_TIMEOUT msecs_to_jiffies(10)
#define COEX_MIN_DELAY 10 /* delay unit in ms */
#define COEX_RFK_TIMEOUT 600 /* RFK timeout in ms */
#define COEX_BT_GAMEHID_CNT 800
#define COEX_RF_OFF 0x0
#define COEX_RF_ON 0x1
#define COEX_H2C69_WL_LEAKAP 0xc
#define PARA1_H2C69_DIS_5MS 0x1
#define PARA1_H2C69_EN_5MS 0x0
#define COEX_H2C69_TDMA_SLOT 0xb
#define PARA1_H2C69_TDMA_4SLOT 0xc1
#define PARA1_H2C69_TDMA_2SLOT 0x1
#define PARA1_H2C69_TBTT_TIMES GENMASK(5, 0)
#define PARA1_H2C69_TBTT_DIV100 BIT(7)
#define COEX_H2C69_TOGGLE_TABLE_A 0xd
#define COEX_H2C69_TOGGLE_TABLE_B 0x7
#define TDMA_4SLOT BIT(8)
#define TDMA_TIMER_TYPE_2SLOT 0
#define TDMA_TIMER_TYPE_4SLOT 3
#define COEX_RSSI_STEP 4
#define COEX_RSSI_HIGH(rssi) \
({ typeof(rssi) __rssi__ = rssi; \
(__rssi__ == COEX_RSSI_STATE_HIGH || \
__rssi__ == COEX_RSSI_STATE_STAY_HIGH ? true : false); })
#define COEX_RSSI_MEDIUM(rssi) \
({ typeof(rssi) __rssi__ = rssi; \
(__rssi__ == COEX_RSSI_STATE_MEDIUM || \
__rssi__ == COEX_RSSI_STATE_STAY_MEDIUM ? true : false); })
#define COEX_RSSI_LOW(rssi) \
({ typeof(rssi) __rssi__ = rssi; \
(__rssi__ == COEX_RSSI_STATE_LOW || \
__rssi__ == COEX_RSSI_STATE_STAY_LOW ? true : false); })
#define GET_COEX_RESP_BT_SUPP_VER(payload) \
le64_get_bits(*((__le64 *)(payload)), GENMASK_ULL(39, 32))
#define GET_COEX_RESP_BT_SUPP_FEAT(payload) \
le64_get_bits(*((__le64 *)(payload)), GENMASK_ULL(39, 24))
#define GET_COEX_RESP_BT_PATCH_VER(payload) \
le64_get_bits(*((__le64 *)(payload)), GENMASK_ULL(55, 24))
#define GET_COEX_RESP_BT_REG_VAL(payload) \
le64_get_bits(*((__le64 *)(payload)), GENMASK_ULL(39, 24))
#define GET_COEX_RESP_BT_SCAN_TYPE(payload) \
le64_get_bits(*((__le64 *)(payload)), GENMASK(31, 24))
enum coex_mp_info_op {
BT_MP_INFO_OP_PATCH_VER = 0x00,
BT_MP_INFO_OP_READ_REG = 0x11,
BT_MP_INFO_OP_SUPP_FEAT = 0x2a,
BT_MP_INFO_OP_SUPP_VER = 0x2b,
BT_MP_INFO_OP_SCAN_TYPE = 0x2d,
BT_MP_INFO_OP_LNA_CONSTRAINT = 0x32,
};
enum coex_set_ant_phase {
COEX_SET_ANT_INIT,
COEX_SET_ANT_WONLY,
COEX_SET_ANT_WOFF,
COEX_SET_ANT_2G,
COEX_SET_ANT_5G,
COEX_SET_ANT_POWERON,
COEX_SET_ANT_2G_WLBT,
COEX_SET_ANT_2G_FREERUN,
COEX_SET_ANT_MAX
};
enum coex_runreason {
COEX_RSN_2GSCANSTART = 0,
COEX_RSN_5GSCANSTART = 1,
COEX_RSN_SCANFINISH = 2,
COEX_RSN_2GSWITCHBAND = 3,
COEX_RSN_5GSWITCHBAND = 4,
COEX_RSN_2GCONSTART = 5,
COEX_RSN_5GCONSTART = 6,
COEX_RSN_2GCONFINISH = 7,
COEX_RSN_5GCONFINISH = 8,
COEX_RSN_2GMEDIA = 9,
COEX_RSN_5GMEDIA = 10,
COEX_RSN_MEDIADISCON = 11,
COEX_RSN_BTINFO = 12,
COEX_RSN_LPS = 13,
COEX_RSN_WLSTATUS = 14,
COEX_RSN_BTSTATUS = 15,
COEX_RSN_MAX
};
enum coex_lte_coex_table_type {
COEX_CTT_WL_VS_LTE,
COEX_CTT_BT_VS_LTE,
};
enum coex_gnt_setup_state {
COEX_GNT_SET_HW_PTA = 0x0,
COEX_GNT_SET_SW_LOW = 0x1,
COEX_GNT_SET_SW_HIGH = 0x3,
};
enum coex_ext_ant_switch_pos_type {
COEX_SWITCH_TO_BT,
COEX_SWITCH_TO_WLG,
COEX_SWITCH_TO_WLA,
COEX_SWITCH_TO_NOCARE,
COEX_SWITCH_TO_WLG_BT,
COEX_SWITCH_TO_MAX
};
enum coex_ext_ant_switch_ctrl_type {
COEX_SWITCH_CTRL_BY_BBSW,
COEX_SWITCH_CTRL_BY_PTA,
COEX_SWITCH_CTRL_BY_ANTDIV,
COEX_SWITCH_CTRL_BY_MAC,
COEX_SWITCH_CTRL_BY_BT,
COEX_SWITCH_CTRL_BY_FW,
COEX_SWITCH_CTRL_MAX
};
enum coex_algorithm {
COEX_ALGO_NOPROFILE = 0,
COEX_ALGO_HFP = 1,
COEX_ALGO_HID = 2,
COEX_ALGO_A2DP = 3,
COEX_ALGO_PAN = 4,
COEX_ALGO_A2DP_HID = 5,
COEX_ALGO_A2DP_PAN = 6,
COEX_ALGO_PAN_HID = 7,
COEX_ALGO_A2DP_PAN_HID = 8,
COEX_ALGO_MAX
};
enum coex_bt_profile {
BPM_NOPROFILE = 0,
BPM_HFP = BIT(0),
BPM_HID = BIT(1),
BPM_A2DP = BIT(2),
BPM_PAN = BIT(3),
BPM_HID_HFP = BPM_HID | BPM_HFP,
BPM_A2DP_HFP = BPM_A2DP | BPM_HFP,
BPM_A2DP_HID = BPM_A2DP | BPM_HID,
BPM_A2DP_HID_HFP = BPM_A2DP | BPM_HID | BPM_HFP,
BPM_PAN_HFP = BPM_PAN | BPM_HFP,
BPM_PAN_HID = BPM_PAN | BPM_HID,
BPM_PAN_HID_HFP = BPM_PAN | BPM_HID | BPM_HFP,
BPM_PAN_A2DP = BPM_PAN | BPM_A2DP,
BPM_PAN_A2DP_HFP = BPM_PAN | BPM_A2DP | BPM_HFP,
BPM_PAN_A2DP_HID = BPM_PAN | BPM_A2DP | BPM_HID,
BPM_PAN_A2DP_HID_HFP = BPM_PAN | BPM_A2DP | BPM_HID | BPM_HFP,
};
enum coex_wl_link_mode {
COEX_WLINK_2G1PORT = 0x0,
COEX_WLINK_5G = 0x3,
COEX_WLINK_2GFREE = 0x7,
COEX_WLINK_MAX
};
enum coex_wl2bt_scoreboard {
COEX_SCBD_ACTIVE = BIT(0),
COEX_SCBD_ONOFF = BIT(1),
COEX_SCBD_SCAN = BIT(2),
COEX_SCBD_UNDERTEST = BIT(3),
COEX_SCBD_RXGAIN = BIT(4),
COEX_SCBD_BT_RFK = BIT(5),
COEX_SCBD_WLBUSY = BIT(6),
COEX_SCBD_EXTFEM = BIT(8),
COEX_SCBD_TDMA = BIT(9),
COEX_SCBD_FIX2M = BIT(10),
COEX_SCBD_ALL = GENMASK(15, 0),
};
enum coex_power_save_type {
COEX_PS_WIFI_NATIVE = 0,
COEX_PS_LPS_ON = 1,
COEX_PS_LPS_OFF = 2,
};
enum coex_rssi_state {
COEX_RSSI_STATE_HIGH,
COEX_RSSI_STATE_MEDIUM,
COEX_RSSI_STATE_LOW,
COEX_RSSI_STATE_STAY_HIGH,
COEX_RSSI_STATE_STAY_MEDIUM,
COEX_RSSI_STATE_STAY_LOW,
};
enum coex_notify_type_ips {
COEX_IPS_LEAVE = 0x0,
COEX_IPS_ENTER = 0x1,
};
enum coex_notify_type_lps {
COEX_LPS_DISABLE = 0x0,
COEX_LPS_ENABLE = 0x1,
};
enum coex_notify_type_scan {
COEX_SCAN_FINISH,
COEX_SCAN_START,
COEX_SCAN_START_2G,
COEX_SCAN_START_5G,
};
enum coex_notify_type_switchband {
COEX_NOT_SWITCH,
COEX_SWITCH_TO_24G,
COEX_SWITCH_TO_5G,
COEX_SWITCH_TO_24G_NOFORSCAN,
};
enum coex_notify_type_associate {
COEX_ASSOCIATE_FINISH,
COEX_ASSOCIATE_START,
COEX_ASSOCIATE_5G_FINISH,
COEX_ASSOCIATE_5G_START,
};
enum coex_notify_type_media_status {
COEX_MEDIA_DISCONNECT,
COEX_MEDIA_CONNECT,
COEX_MEDIA_CONNECT_5G,
};
enum coex_bt_status {
COEX_BTSTATUS_NCON_IDLE = 0,
COEX_BTSTATUS_CON_IDLE = 1,
COEX_BTSTATUS_INQ_PAGE = 2,
COEX_BTSTATUS_ACL_BUSY = 3,
COEX_BTSTATUS_SCO_BUSY = 4,
COEX_BTSTATUS_ACL_SCO_BUSY = 5,
COEX_BTSTATUS_MAX
};
enum coex_wl_tput_dir {
COEX_WL_TPUT_TX = 0x0,
COEX_WL_TPUT_RX = 0x1,
COEX_WL_TPUT_MAX
};
enum coex_wl_priority_mask {
COEX_WLPRI_RX_RSP = 2,
COEX_WLPRI_TX_RSP = 3,
COEX_WLPRI_TX_BEACON = 4,
COEX_WLPRI_TX_OFDM = 11,
COEX_WLPRI_TX_CCK = 12,
COEX_WLPRI_TX_BEACONQ = 27,
COEX_WLPRI_RX_CCK = 28,
COEX_WLPRI_RX_OFDM = 29,
COEX_WLPRI_MAX
};
enum coex_commom_chip_setup {
COEX_CSETUP_INIT_HW = 0x0,
COEX_CSETUP_ANT_SWITCH = 0x1,
COEX_CSETUP_GNT_FIX = 0x2,
COEX_CSETUP_GNT_DEBUG = 0x3,
COEX_CSETUP_RFE_TYPE = 0x4,
COEX_CSETUP_COEXINFO_HW = 0x5,
COEX_CSETUP_WL_TX_POWER = 0x6,
COEX_CSETUP_WL_RX_GAIN = 0x7,
COEX_CSETUP_WLAN_ACT_IPS = 0x8,
COEX_CSETUP_MAX
};
enum coex_indirect_reg_type {
COEX_INDIRECT_1700 = 0x0,
COEX_INDIRECT_7C0 = 0x1,
COEX_INDIRECT_MAX
};
enum coex_pstdma_type {
COEX_PSTDMA_FORCE_LPSOFF = 0x0,
COEX_PSTDMA_FORCE_LPSON = 0x1,
COEX_PSTDMA_MAX
};
enum coex_btrssi_type {
COEX_BTRSSI_RATIO = 0x0,
COEX_BTRSSI_DBM = 0x1,
COEX_BTRSSI_MAX
};
struct coex_table_para {
u32 bt;
u32 wl;
};
struct coex_tdma_para {
u8 para[5];
};
struct coex_5g_afh_map {
u32 wl_5g_ch;
u8 bt_skip_ch;
u8 bt_skip_span;
};
struct coex_rf_para {
u8 wl_pwr_dec_lvl;
u8 bt_pwr_dec_lvl;
bool wl_low_gain_en;
u8 bt_lna_lvl;
};
static inline void rtw_coex_set_init(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
chip->ops->coex_set_init(rtwdev);
}
static inline
void rtw_coex_set_ant_switch(struct rtw_dev *rtwdev, u8 ctrl_type, u8 pos_type)
{
const struct rtw_chip_info *chip = rtwdev->chip;
if (!chip->ops->coex_set_ant_switch)
return;
chip->ops->coex_set_ant_switch(rtwdev, ctrl_type, pos_type);
}
static inline void rtw_coex_set_gnt_fix(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
chip->ops->coex_set_gnt_fix(rtwdev);
}
static inline void rtw_coex_set_gnt_debug(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
chip->ops->coex_set_gnt_debug(rtwdev);
}
static inline void rtw_coex_set_rfe_type(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
chip->ops->coex_set_rfe_type(rtwdev);
}
static inline void rtw_coex_set_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr)
{
const struct rtw_chip_info *chip = rtwdev->chip;
chip->ops->coex_set_wl_tx_power(rtwdev, wl_pwr);
}
static inline
void rtw_coex_set_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain)
{
const struct rtw_chip_info *chip = rtwdev->chip;
chip->ops->coex_set_wl_rx_gain(rtwdev, low_gain);
}
void rtw_coex_info_response(struct rtw_dev *rtwdev, struct sk_buff *skb);
u32 rtw_coex_read_indirect_reg(struct rtw_dev *rtwdev, u16 addr);
void rtw_coex_write_indirect_reg(struct rtw_dev *rtwdev, u16 addr,
u32 mask, u32 val);
void rtw_coex_write_scbd(struct rtw_dev *rtwdev, u16 bitpos, bool set);
void rtw_coex_query_bt_info(struct rtw_dev *rtwdev);
void rtw_coex_bt_relink_work(struct work_struct *work);
void rtw_coex_bt_reenable_work(struct work_struct *work);
void rtw_coex_defreeze_work(struct work_struct *work);
void rtw_coex_wl_remain_work(struct work_struct *work);
void rtw_coex_bt_remain_work(struct work_struct *work);
void rtw_coex_wl_connecting_work(struct work_struct *work);
void rtw_coex_bt_multi_link_remain_work(struct work_struct *work);
void rtw_coex_wl_ccklock_work(struct work_struct *work);
void rtw_coex_power_on_setting(struct rtw_dev *rtwdev);
void rtw_coex_power_off_setting(struct rtw_dev *rtwdev);
void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only);
void rtw_coex_ips_notify(struct rtw_dev *rtwdev, u8 type);
void rtw_coex_lps_notify(struct rtw_dev *rtwdev, u8 type);
void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type);
void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 type);
void rtw_coex_media_status_notify(struct rtw_dev *rtwdev, u8 type);
void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length);
void rtw_coex_bt_hid_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length);
void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length);
void rtw_coex_switchband_notify(struct rtw_dev *rtwdev, u8 type);
void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev, u32 type);
void rtw_coex_wl_status_check(struct rtw_dev *rtwdev);
void rtw_coex_query_bt_hid_list(struct rtw_dev *rtwdev);
void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m);
static inline bool rtw_coex_disabled(struct rtw_dev *rtwdev)
{
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat;
return coex_stat->bt_disabled;
}
static inline void rtw_coex_active_query_bt_info(struct rtw_dev *rtwdev)
{
/* The RTL8821AU firmware doesn't send C2H_BT_INFO by itself
* when bluetooth headphones are disconnected, so we have to
* ask for it regularly.
*/
if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A && rtwdev->efuse.btcoex)
rtw_coex_query_bt_info(rtwdev);
}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,76 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_DEBUG_H
#define __RTW_DEBUG_H
enum rtw_debug_mask {
RTW_DBG_PCI = 0x00000001,
RTW_DBG_TX = 0x00000002,
RTW_DBG_RX = 0x00000004,
RTW_DBG_PHY = 0x00000008,
RTW_DBG_FW = 0x00000010,
RTW_DBG_EFUSE = 0x00000020,
RTW_DBG_COEX = 0x00000040,
RTW_DBG_RFK = 0x00000080,
RTW_DBG_REGD = 0x00000100,
RTW_DBG_DEBUGFS = 0x00000200,
RTW_DBG_PS = 0x00000400,
RTW_DBG_BF = 0x00000800,
RTW_DBG_WOW = 0x00001000,
RTW_DBG_CFO = 0x00002000,
RTW_DBG_PATH_DIV = 0x00004000,
RTW_DBG_ADAPTIVITY = 0x00008000,
RTW_DBG_HW_SCAN = 0x00010000,
RTW_DBG_STATE = 0x00020000,
RTW_DBG_SDIO = 0x00040000,
RTW_DBG_USB = 0x00080000,
RTW_DBG_UNEXP = 0x80000000,
RTW_DBG_ALL = 0xffffffff
};
#ifdef CONFIG_RTW88_DEBUGFS
void rtw_debugfs_init(struct rtw_dev *rtwdev);
void rtw_debugfs_deinit(struct rtw_dev *rtwdev);
void rtw_debugfs_get_simple_phy_info(struct seq_file *m);
#else
static inline void rtw_debugfs_init(struct rtw_dev *rtwdev) {}
static inline void rtw_debugfs_deinit(struct rtw_dev *rtwdev) {}
#endif /* CONFIG_RTW88_DEBUGFS */
#ifdef CONFIG_RTW88_DEBUG
__printf(3, 4)
void rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask,
const char *fmt, ...);
static inline bool rtw_dbg_is_enabled(struct rtw_dev *rtwdev,
enum rtw_debug_mask mask)
{
return !!(rtw_debug_mask & mask);
}
#else
static inline void rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask,
const char *fmt, ...) {}
static inline bool rtw_dbg_is_enabled(struct rtw_dev *rtwdev,
enum rtw_debug_mask mask)
{
return false;
}
#endif /* CONFIG_RTW88_DEBUG */
#define rtw_info(rtwdev, a...) dev_info(rtwdev->dev, ##a)
#define rtw_warn(rtwdev, a...) dev_warn(rtwdev->dev, ##a)
#define rtw_err(rtwdev, a...) dev_err(rtwdev->dev, ##a)
#endif
@@ -0,0 +1,187 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include <linux/iopoll.h>
#include "main.h"
#include "efuse.h"
#include "reg.h"
#include "debug.h"
#define RTW_EFUSE_BANK_WIFI 0x0
static void switch_efuse_bank(struct rtw_dev *rtwdev)
{
rtw_write32_mask(rtwdev, REG_LDO_EFUSE_CTRL, BIT_MASK_EFUSE_BANK_SEL,
RTW_EFUSE_BANK_WIFI);
}
#define invalid_efuse_header(hdr1, hdr2) \
((hdr1) == 0xff || (((hdr1) & 0x1f) == 0xf && (hdr2) == 0xff))
#define invalid_efuse_content(word_en, i) \
(((word_en) & BIT(i)) != 0x0)
#define get_efuse_blk_idx_2_byte(hdr1, hdr2) \
((((hdr2) & 0xf0) >> 1) | (((hdr1) >> 5) & 0x07))
#define get_efuse_blk_idx_1_byte(hdr1) \
(((hdr1) & 0xf0) >> 4)
#define block_idx_to_logical_idx(blk_idx, i) \
(((blk_idx) << 3) + ((i) << 1))
/* efuse header format
*
* | 7 5 4 0 | 7 4 3 0 | 15 8 7 0 |
* block[2:0] 0 1111 block[6:3] word_en[3:0] byte0 byte1
* | header 1 (optional) | header 2 | word N |
*
* word_en: 4 bits each word. 0 -> write; 1 -> not write
* N: 1~4, depends on word_en
*/
static int rtw_dump_logical_efuse_map(struct rtw_dev *rtwdev, u8 *phy_map,
u8 *log_map)
{
u32 physical_size = rtwdev->efuse.physical_size;
u32 protect_size = rtwdev->efuse.protect_size;
u32 logical_size = rtwdev->efuse.logical_size;
u32 phy_idx, log_idx;
u8 hdr1, hdr2;
u8 blk_idx;
u8 word_en;
int i;
for (phy_idx = 0; phy_idx < physical_size - protect_size;) {
hdr1 = phy_map[phy_idx];
hdr2 = phy_map[phy_idx + 1];
if (invalid_efuse_header(hdr1, hdr2))
break;
if ((hdr1 & 0x1f) == 0xf) {
/* 2-byte header format */
blk_idx = get_efuse_blk_idx_2_byte(hdr1, hdr2);
word_en = hdr2 & 0xf;
phy_idx += 2;
} else {
/* 1-byte header format */
blk_idx = get_efuse_blk_idx_1_byte(hdr1);
word_en = hdr1 & 0xf;
phy_idx += 1;
}
for (i = 0; i < 4; i++) {
if (invalid_efuse_content(word_en, i))
continue;
log_idx = block_idx_to_logical_idx(blk_idx, i);
if (phy_idx + 1 > physical_size - protect_size ||
log_idx + 1 > logical_size)
return -EINVAL;
log_map[log_idx] = phy_map[phy_idx];
log_map[log_idx + 1] = phy_map[phy_idx + 1];
phy_idx += 2;
}
}
return 0;
}
static int rtw_dump_physical_efuse_map(struct rtw_dev *rtwdev, u8 *map)
{
const struct rtw_chip_info *chip = rtwdev->chip;
u32 size = rtwdev->efuse.physical_size;
u32 efuse_ctl;
u32 addr;
u32 cnt;
rtw_chip_efuse_grant_on(rtwdev);
switch_efuse_bank(rtwdev);
/* disable 2.5V LDO */
chip->ops->cfg_ldo25(rtwdev, false);
efuse_ctl = rtw_read32(rtwdev, REG_EFUSE_CTRL);
for (addr = 0; addr < size; addr++) {
efuse_ctl &= ~(BIT_MASK_EF_DATA | BITS_EF_ADDR);
efuse_ctl |= (addr & BIT_MASK_EF_ADDR) << BIT_SHIFT_EF_ADDR;
rtw_write32(rtwdev, REG_EFUSE_CTRL, efuse_ctl & (~BIT_EF_FLAG));
cnt = 1000000;
do {
udelay(1);
efuse_ctl = rtw_read32(rtwdev, REG_EFUSE_CTRL);
if (--cnt == 0)
return -EBUSY;
} while (!(efuse_ctl & BIT_EF_FLAG));
*(map + addr) = (u8)(efuse_ctl & BIT_MASK_EF_DATA);
}
rtw_chip_efuse_grant_off(rtwdev);
return 0;
}
int rtw_read8_physical_efuse(struct rtw_dev *rtwdev, u16 addr, u8 *data)
{
u32 efuse_ctl;
int ret;
rtw_write32_mask(rtwdev, REG_EFUSE_CTRL, 0x3ff00, addr);
rtw_write32_clr(rtwdev, REG_EFUSE_CTRL, BIT_EF_FLAG);
ret = read_poll_timeout(rtw_read32, efuse_ctl, efuse_ctl & BIT_EF_FLAG,
1000, 100000, false, rtwdev, REG_EFUSE_CTRL);
if (ret) {
*data = EFUSE_READ_FAIL;
return ret;
}
*data = rtw_read8(rtwdev, REG_EFUSE_CTRL);
return 0;
}
EXPORT_SYMBOL(rtw_read8_physical_efuse);
int rtw_parse_efuse_map(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse;
u32 phy_size = efuse->physical_size;
u32 log_size = efuse->logical_size;
u8 *phy_map = NULL;
u8 *log_map = NULL;
int ret = 0;
phy_map = kmalloc(phy_size, GFP_KERNEL);
log_map = kmalloc(log_size, GFP_KERNEL);
if (!phy_map || !log_map) {
ret = -ENOMEM;
goto out_free;
}
ret = rtw_dump_physical_efuse_map(rtwdev, phy_map);
if (ret) {
rtw_err(rtwdev, "failed to dump efuse physical map\n");
goto out_free;
}
memset(log_map, 0xff, log_size);
ret = rtw_dump_logical_efuse_map(rtwdev, phy_map, log_map);
if (ret) {
rtw_err(rtwdev, "failed to dump efuse logical map\n");
goto out_free;
}
ret = chip->ops->read_efuse(rtwdev, log_map);
if (ret) {
rtw_err(rtwdev, "failed to read efuse map\n");
goto out_free;
}
out_free:
kfree(log_map);
kfree(phy_map);
return ret;
}
@@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_EFUSE_H__
#define __RTW_EFUSE_H__
#define EFUSE_HW_CAP_IGNORE 0
#define EFUSE_HW_CAP_PTCL_VHT 3
#define EFUSE_HW_CAP_SUPP_BW80 7
#define EFUSE_HW_CAP_SUPP_BW40 6
#define EFUSE_READ_FAIL 0xff
#define GET_EFUSE_HW_CAP_HCI(hw_cap) \
le32_get_bits(*((__le32 *)(hw_cap) + 0x01), GENMASK(3, 0))
#define GET_EFUSE_HW_CAP_BW(hw_cap) \
le32_get_bits(*((__le32 *)(hw_cap) + 0x01), GENMASK(18, 16))
#define GET_EFUSE_HW_CAP_NSS(hw_cap) \
le32_get_bits(*((__le32 *)(hw_cap) + 0x01), GENMASK(20, 19))
#define GET_EFUSE_HW_CAP_ANT_NUM(hw_cap) \
le32_get_bits(*((__le32 *)(hw_cap) + 0x01), GENMASK(23, 21))
#define GET_EFUSE_HW_CAP_PTCL(hw_cap) \
le32_get_bits(*((__le32 *)(hw_cap) + 0x01), GENMASK(27, 26))
int rtw_parse_efuse_map(struct rtw_dev *rtwdev);
int rtw_read8_physical_efuse(struct rtw_dev *rtwdev, u16 addr, u8 *data);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,900 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_FW_H_
#define __RTW_FW_H_
#define H2C_PKT_SIZE 32
#define H2C_PKT_HDR_SIZE 8
/* FW bin information */
#define FW_HDR_SIZE 64
#define FW_HDR_CHKSUM_SIZE 8
#define FW_NLO_INFO_CHECK_SIZE 4
#define FIFO_PAGE_SIZE_SHIFT 12
#define FIFO_PAGE_SIZE 4096
#define FIFO_DUMP_ADDR 0x8000
#define DLFW_PAGE_SIZE_SHIFT_LEGACY 12
#define DLFW_PAGE_SIZE_LEGACY 0x1000
#define DLFW_BLK_SIZE_SHIFT_LEGACY 2
#define DLFW_BLK_SIZE_LEGACY 4
#define FW_START_ADDR_LEGACY 0x1000
#define BCN_LOSS_CNT 10
#define BCN_FILTER_NOTIFY_SIGNAL_CHANGE 0
#define BCN_FILTER_CONNECTION_LOSS 1
#define BCN_FILTER_CONNECTED 2
#define BCN_FILTER_NOTIFY_BEACON_LOSS 3
#define RTW_DEFAULT_CQM_THOLD -70
#define RTW_DEFAULT_CQM_HYST 4
#define SCAN_NOTIFY_TIMEOUT msecs_to_jiffies(10)
#define RTW_CHANNEL_TIME 45
#define RTW_OFF_CHAN_TIME 100
#define RTW_PASS_CHAN_TIME 105
#define RTW_DFS_CHAN_TIME 20
#define RTW_CH_INFO_SIZE 4
#define RTW_EX_CH_INFO_SIZE 3
#define RTW_EX_CH_INFO_HDR_SIZE 2
#define RTW_SCAN_WIDTH 0
#define RTW_PRI_CH_IDX 1
#define RTW_OLD_PROBE_PG_CNT 2
#define RTW_PROBE_PG_CNT 4
#define RTW_DEBUG_DUMP_TIMES 10
enum rtw_c2h_cmd_id {
C2H_CCX_TX_RPT = 0x03,
C2H_BT_INFO = 0x09,
C2H_BT_MP_INFO = 0x0b,
C2H_BT_HID_INFO = 0x45,
C2H_RA_RPT = 0x0c,
C2H_HW_FEATURE_REPORT = 0x19,
C2H_WLAN_INFO = 0x27,
C2H_WLAN_RFON = 0x32,
C2H_BCN_FILTER_NOTIFY = 0x36,
C2H_ADAPTIVITY = 0x37,
C2H_SCAN_RESULT = 0x38,
C2H_HW_FEATURE_DUMP = 0xfd,
C2H_HALMAC = 0xff,
};
enum rtw_c2h_cmd_id_ext {
C2H_SCAN_STATUS_RPT = 0x3,
C2H_CCX_RPT = 0x0f,
C2H_CHAN_SWITCH = 0x22,
};
struct rtw_c2h_cmd {
u8 id;
u8 seq;
u8 payload[];
} __packed;
struct rtw_c2h_adaptivity {
u8 density;
u8 igi;
u8 l2h_th_init;
u8 l2h;
u8 h2l;
u8 option;
} __packed;
struct rtw_c2h_ra_rpt {
u8 rate_sgi;
u8 mac_id;
u8 byte2;
u8 status;
u8 byte4;
u8 ra_ratio;
u8 bw;
} __packed;
#define RTW_C2H_RA_RPT_RATE GENMASK(6, 0)
#define RTW_C2H_RA_RPT_SGI BIT(7)
struct rtw_h2c_register {
u32 w0;
u32 w1;
} __packed;
#define RTW_H2C_W0_CMDID GENMASK(7, 0)
/* H2C_CMD_DEFAULT_PORT command */
#define RTW_H2C_DEFAULT_PORT_W0_PORTID GENMASK(15, 8)
#define RTW_H2C_DEFAULT_PORT_W0_MACID GENMASK(23, 16)
struct rtw_h2c_cmd {
__le32 msg;
__le32 msg_ext;
} __packed;
enum rtw_rsvd_packet_type {
RSVD_BEACON,
RSVD_DUMMY,
RSVD_PS_POLL,
RSVD_PROBE_RESP,
RSVD_NULL,
RSVD_QOS_NULL,
RSVD_LPS_PG_DPK,
RSVD_LPS_PG_INFO,
RSVD_PROBE_REQ,
RSVD_NLO_INFO,
RSVD_CH_INFO,
};
enum rtw_fw_rf_type {
FW_RF_1T2R = 0,
FW_RF_2T4R = 1,
FW_RF_2T2R = 2,
FW_RF_2T3R = 3,
FW_RF_1T1R = 4,
FW_RF_2T2R_GREEN = 5,
FW_RF_3T3R = 6,
FW_RF_3T4R = 7,
FW_RF_4T4R = 8,
FW_RF_MAX_TYPE = 0xF,
};
enum rtw_fw_feature {
FW_FEATURE_SIG = BIT(0),
FW_FEATURE_LPS_C2H = BIT(1),
FW_FEATURE_LCLK = BIT(2),
FW_FEATURE_PG = BIT(3),
FW_FEATURE_TX_WAKE = BIT(4),
FW_FEATURE_BCN_FILTER = BIT(5),
FW_FEATURE_NOTIFY_SCAN = BIT(6),
FW_FEATURE_ADAPTIVITY = BIT(7),
FW_FEATURE_SCAN_OFFLOAD = BIT(8),
FW_FEATURE_MAX = BIT(31),
};
enum rtw_fw_feature_ext {
FW_FEATURE_EXT_OLD_PAGE_NUM = BIT(0),
};
enum rtw_beacon_filter_offload_mode {
BCN_FILTER_OFFLOAD_MODE_0 = 0,
BCN_FILTER_OFFLOAD_MODE_1,
BCN_FILTER_OFFLOAD_MODE_2,
BCN_FILTER_OFFLOAD_MODE_3,
BCN_FILTER_OFFLOAD_MODE_DEFAULT = BCN_FILTER_OFFLOAD_MODE_0,
};
struct rtw_coex_info_req {
u8 seq;
u8 op_code;
u8 para1;
u8 para2;
u8 para3;
};
struct rtw_iqk_para {
u8 clear;
u8 segment_iqk;
};
struct rtw_lps_pg_dpk_hdr {
u16 dpk_path_ok;
u8 dpk_txagc[2];
u16 dpk_gs[2];
u32 coef[2][20];
u8 dpk_ch;
} __packed;
struct rtw_lps_pg_info_hdr {
u8 macid;
u8 mbssid;
u8 pattern_count;
u8 mu_tab_group_id;
u8 sec_cam_count;
u8 tx_bu_page_count;
u16 rsvd;
u8 sec_cam[MAX_PG_CAM_BACKUP_NUM];
} __packed;
struct rtw_rsvd_page {
/* associated with each vif */
struct list_head vif_list;
struct rtw_vif *rtwvif;
/* associated when build rsvd page */
struct list_head build_list;
struct sk_buff *skb;
enum rtw_rsvd_packet_type type;
u8 page;
u16 tim_offset;
bool add_txdesc;
struct cfg80211_ssid *ssid;
u16 probe_req_size;
};
enum rtw_keep_alive_pkt_type {
KEEP_ALIVE_NULL_PKT = 0,
KEEP_ALIVE_ARP_RSP = 1,
};
struct rtw_nlo_info_hdr {
u8 nlo_count;
u8 hidden_ap_count;
u8 rsvd1[2];
u8 pattern_check[FW_NLO_INFO_CHECK_SIZE];
u8 rsvd2[8];
u8 ssid_len[16];
u8 chiper[16];
u8 rsvd3[16];
u8 location[8];
} __packed;
enum rtw_packet_type {
RTW_PACKET_PROBE_REQ = 0x00,
RTW_PACKET_UNDEFINE = 0x7FFFFFFF,
};
struct rtw_fw_wow_keep_alive_para {
bool adopt;
u8 pkt_type;
u8 period; /* unit: sec */
};
struct rtw_fw_wow_disconnect_para {
bool adopt;
u8 period; /* unit: sec */
u8 retry_count;
};
enum rtw_channel_type {
RTW_CHANNEL_PASSIVE,
RTW_CHANNEL_ACTIVE,
RTW_CHANNEL_RADAR,
};
enum rtw_scan_extra_id {
RTW_SCAN_EXTRA_ID_DFS,
};
enum rtw_scan_extra_info {
RTW_SCAN_EXTRA_ACTION_SCAN,
};
enum rtw_scan_report_code {
RTW_SCAN_REPORT_SUCCESS = 0x00,
RTW_SCAN_REPORT_ERR_PHYDM = 0x01,
RTW_SCAN_REPORT_ERR_ID = 0x02,
RTW_SCAN_REPORT_ERR_TX = 0x03,
RTW_SCAN_REPORT_CANCELED = 0x10,
RTW_SCAN_REPORT_CANCELED_EXT = 0x11,
RTW_SCAN_REPORT_FW_DISABLED = 0xF0,
};
enum rtw_scan_notify_id {
RTW_SCAN_NOTIFY_ID_PRESWITCH = 0x00,
RTW_SCAN_NOTIFY_ID_POSTSWITCH = 0x01,
RTW_SCAN_NOTIFY_ID_PROBE_PRETX = 0x02,
RTW_SCAN_NOTIFY_ID_PROBE_ISSUETX = 0x03,
RTW_SCAN_NOTIFY_ID_NULL0_PRETX = 0x04,
RTW_SCAN_NOTIFY_ID_NULL0_ISSUETX = 0x05,
RTW_SCAN_NOTIFY_ID_NULL0_POSTTX = 0x06,
RTW_SCAN_NOTIFY_ID_NULL1_PRETX = 0x07,
RTW_SCAN_NOTIFY_ID_NULL1_ISSUETX = 0x08,
RTW_SCAN_NOTIFY_ID_NULL1_POSTTX = 0x09,
RTW_SCAN_NOTIFY_ID_DWELLEXT = 0x0A,
};
enum rtw_scan_notify_status {
RTW_SCAN_NOTIFY_STATUS_SUCCESS = 0x00,
RTW_SCAN_NOTIFY_STATUS_FAILURE = 0x01,
RTW_SCAN_NOTIFY_STATUS_RESOURCE = 0x02,
RTW_SCAN_NOTIFY_STATUS_TIMEOUT = 0x03,
};
struct rtw_ch_switch_option {
u8 periodic_option;
u32 tsf_high;
u32 tsf_low;
u8 dest_ch_en;
u8 absolute_time_en;
u8 dest_ch;
u8 normal_period;
u8 normal_period_sel;
u8 normal_cycle;
u8 slow_period;
u8 slow_period_sel;
u8 nlo_en;
bool switch_en;
bool back_op_en;
};
struct rtw_fw_hdr {
__le16 signature;
u8 category;
u8 function;
__le16 version; /* 0x04 */
u8 subversion;
u8 subindex;
__le32 rsvd; /* 0x08 */
__le32 feature; /* 0x0C */
u8 month; /* 0x10 */
u8 day;
u8 hour;
u8 min;
__le16 year; /* 0x14 */
__le16 rsvd3;
u8 mem_usage; /* 0x18 */
u8 rsvd4[3];
__le16 h2c_fmt_ver; /* 0x1C */
__le16 rsvd5;
__le32 dmem_addr; /* 0x20 */
__le32 dmem_size;
__le32 rsvd6;
__le32 rsvd7;
__le32 imem_size; /* 0x30 */
__le32 emem_size;
__le32 emem_addr;
__le32 imem_addr;
} __packed;
struct rtw_fw_hdr_legacy {
__le16 signature;
u8 category;
u8 function;
__le16 version; /* 0x04 */
u8 subversion1;
u8 subversion2;
u8 month; /* 0x08 */
u8 day;
u8 hour;
u8 minute;
__le16 size;
__le16 rsvd2;
__le32 idx; /* 0x10 */
__le32 rsvd3;
__le32 rsvd4; /* 0x18 */
__le32 rsvd5;
} __packed;
#define RTW_FW_VER_CODE(ver, sub_ver, idx) \
(((ver) << 16) | ((sub_ver) << 8) | (idx))
#define RTW_FW_SUIT_VER_CODE(s) \
RTW_FW_VER_CODE((s).version, (s).sub_version, (s).sub_index)
/* C2H */
#define GET_CCX_REPORT_SEQNUM_V0(c2h_payload) (c2h_payload[6] & 0xfc)
#define GET_CCX_REPORT_STATUS_V0(c2h_payload) (c2h_payload[0] & 0xc0)
#define GET_CCX_REPORT_SEQNUM_V1(c2h_payload) (c2h_payload[8] & 0xfc)
#define GET_CCX_REPORT_STATUS_V1(c2h_payload) (c2h_payload[9] & 0xc0)
#define GET_SCAN_REPORT_RETURN_CODE(c2h_payload) (c2h_payload[2] & 0xff)
#define GET_CHAN_SWITCH_CENTRAL_CH(c2h_payload) (c2h_payload[2])
#define GET_CHAN_SWITCH_ID(c2h_payload) (c2h_payload[3])
#define GET_CHAN_SWITCH_STATUS(c2h_payload) (c2h_payload[4])
#define GET_BCN_FILTER_NOTIFY_TYPE(c2h_payload) (c2h_payload[1] & 0xf)
#define GET_BCN_FILTER_NOTIFY_EVENT(c2h_payload) (c2h_payload[1] & 0x10)
#define GET_BCN_FILTER_NOTIFY_RSSI(c2h_payload) (c2h_payload[2] - 100)
/* PKT H2C */
#define H2C_PKT_CMD_ID 0xFF
#define H2C_PKT_CATEGORY 0x01
#define H2C_PKT_GENERAL_INFO 0x0D
#define H2C_PKT_PHYDM_INFO 0x11
#define H2C_PKT_IQK 0x0E
#define H2C_PKT_CH_SWITCH 0x02
#define H2C_PKT_UPDATE_PKT 0x0C
#define H2C_PKT_SCAN_OFFLOAD 0x19
#define H2C_PKT_CH_SWITCH_LEN 0x20
#define H2C_PKT_UPDATE_PKT_LEN 0x4
#define SET_PKT_H2C_CATEGORY(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(6, 0))
#define SET_PKT_H2C_CMD_ID(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
#define SET_PKT_H2C_SUB_CMD_ID(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 16))
#define SET_PKT_H2C_TOTAL_LEN(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(15, 0))
static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
{
SET_PKT_H2C_CATEGORY(h2c_pkt, H2C_PKT_CATEGORY);
SET_PKT_H2C_CMD_ID(h2c_pkt, H2C_PKT_CMD_ID);
SET_PKT_H2C_SUB_CMD_ID(h2c_pkt, sub_id);
}
#define FW_OFFLOAD_H2C_SET_SEQ_NUM(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(31, 16))
#define GENERAL_INFO_SET_FW_TX_BOUNDARY(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, GENMASK(23, 16))
#define PHYDM_INFO_SET_REF_TYPE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, GENMASK(7, 0))
#define PHYDM_INFO_SET_RF_TYPE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, GENMASK(15, 8))
#define PHYDM_INFO_SET_CUT_VER(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, GENMASK(23, 16))
#define PHYDM_INFO_SET_RX_ANT_STATUS(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, GENMASK(27, 24))
#define PHYDM_INFO_SET_TX_ANT_STATUS(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, GENMASK(31, 28))
#define IQK_SET_CLEAR(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, BIT(0))
#define IQK_SET_SEGMENT_IQK(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, BIT(1))
#define CHSW_INFO_SET_CH(pkt, value) \
le32p_replace_bits((__le32 *)(pkt) + 0x00, value, GENMASK(7, 0))
#define CHSW_INFO_SET_PRI_CH_IDX(pkt, value) \
le32p_replace_bits((__le32 *)(pkt) + 0x00, value, GENMASK(11, 8))
#define CHSW_INFO_SET_BW(pkt, value) \
le32p_replace_bits((__le32 *)(pkt) + 0x00, value, GENMASK(15, 12))
#define CHSW_INFO_SET_TIMEOUT(pkt, value) \
le32p_replace_bits((__le32 *)(pkt) + 0x00, value, GENMASK(23, 16))
#define CHSW_INFO_SET_ACTION_ID(pkt, value) \
le32p_replace_bits((__le32 *)(pkt) + 0x00, value, GENMASK(30, 24))
#define CHSW_INFO_SET_EXTRA_INFO(pkt, value) \
le32p_replace_bits((__le32 *)(pkt) + 0x00, value, BIT(31))
#define CH_INFO_SET_CH(pkt, value) \
u8p_replace_bits((u8 *)(pkt) + 0x00, value, GENMASK(7, 0))
#define CH_INFO_SET_PRI_CH_IDX(pkt, value) \
u8p_replace_bits((u8 *)(pkt) + 0x01, value, GENMASK(3, 0))
#define CH_INFO_SET_BW(pkt, value) \
u8p_replace_bits((u8 *)(pkt) + 0x01, value, GENMASK(7, 4))
#define CH_INFO_SET_TIMEOUT(pkt, value) \
u8p_replace_bits((u8 *)(pkt) + 0x02, value, GENMASK(7, 0))
#define CH_INFO_SET_ACTION_ID(pkt, value) \
u8p_replace_bits((u8 *)(pkt) + 0x03, value, GENMASK(6, 0))
#define CH_INFO_SET_EXTRA_INFO(pkt, value) \
u8p_replace_bits((u8 *)(pkt) + 0x03, value, BIT(7))
#define EXTRA_CH_INFO_SET_ID(pkt, value) \
u8p_replace_bits((u8 *)(pkt) + 0x04, value, GENMASK(6, 0))
#define EXTRA_CH_INFO_SET_INFO(pkt, value) \
u8p_replace_bits((u8 *)(pkt) + 0x04, value, BIT(7))
#define EXTRA_CH_INFO_SET_SIZE(pkt, value) \
u8p_replace_bits((u8 *)(pkt) + 0x05, value, GENMASK(7, 0))
#define EXTRA_CH_INFO_SET_DFS_EXT_TIME(pkt, value) \
u8p_replace_bits((u8 *)(pkt) + 0x06, value, GENMASK(7, 0))
#define UPDATE_PKT_SET_SIZE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, GENMASK(15, 0))
#define UPDATE_PKT_SET_PKT_ID(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, GENMASK(23, 16))
#define UPDATE_PKT_SET_LOCATION(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, GENMASK(31, 24))
#define CH_SWITCH_SET_START(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, BIT(0))
#define CH_SWITCH_SET_DEST_CH_EN(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, BIT(1))
#define CH_SWITCH_SET_ABSOLUTE_TIME(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, BIT(2))
#define CH_SWITCH_SET_PERIODIC_OPT(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, GENMASK(4, 3))
#define CH_SWITCH_SET_SCAN_MODE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, BIT(5))
#define CH_SWITCH_SET_BACK_OP_EN(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, BIT(6))
#define CH_SWITCH_SET_INFO_LOC(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, GENMASK(15, 8))
#define CH_SWITCH_SET_CH_NUM(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, GENMASK(23, 16))
#define CH_SWITCH_SET_PRI_CH_IDX(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, GENMASK(27, 24))
#define CH_SWITCH_SET_DEST_BW(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, GENMASK(31, 28))
#define CH_SWITCH_SET_DEST_CH(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x03, value, GENMASK(7, 0))
#define CH_SWITCH_SET_NORMAL_PERIOD(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x03, value, GENMASK(13, 8))
#define CH_SWITCH_SET_NORMAL_PERIOD_SEL(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x03, value, GENMASK(15, 14))
#define CH_SWITCH_SET_SLOW_PERIOD(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x03, value, GENMASK(21, 16))
#define CH_SWITCH_SET_SLOW_PERIOD_SEL(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x03, value, GENMASK(23, 22))
#define CH_SWITCH_SET_NORMAL_CYCLE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x03, value, GENMASK(31, 24))
#define CH_SWITCH_SET_TSF_HIGH(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x04, value, GENMASK(31, 0))
#define CH_SWITCH_SET_TSF_LOW(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x05, value, GENMASK(31, 0))
#define CH_SWITCH_SET_INFO_SIZE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x06, value, GENMASK(15, 0))
#define SCAN_OFFLOAD_SET_START(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, BIT(0))
#define SCAN_OFFLOAD_SET_BACK_OP_EN(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, BIT(1))
#define SCAN_OFFLOAD_SET_RANDOM_SEQ_EN(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, BIT(2))
#define SCAN_OFFLOAD_SET_NO_CCK_EN(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, BIT(3))
#define SCAN_OFFLOAD_SET_VERBOSE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, BIT(4))
#define SCAN_OFFLOAD_SET_CH_NUM(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, GENMASK(15, 8))
#define SCAN_OFFLOAD_SET_CH_INFO_SIZE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x02, value, GENMASK(31, 16))
#define SCAN_OFFLOAD_SET_CH_INFO_LOC(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x03, value, GENMASK(7, 0))
#define SCAN_OFFLOAD_SET_OP_CH(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x03, value, GENMASK(15, 8))
#define SCAN_OFFLOAD_SET_OP_PRI_CH_IDX(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x03, value, GENMASK(19, 16))
#define SCAN_OFFLOAD_SET_OP_BW(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x03, value, GENMASK(23, 20))
#define SCAN_OFFLOAD_SET_OP_PORT_ID(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x03, value, GENMASK(26, 24))
#define SCAN_OFFLOAD_SET_OP_DWELL_TIME(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x04, value, GENMASK(15, 0))
#define SCAN_OFFLOAD_SET_OP_GAP_TIME(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x04, value, GENMASK(31, 16))
#define SCAN_OFFLOAD_SET_MODE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x05, value, GENMASK(3, 0))
#define SCAN_OFFLOAD_SET_SSID_NUM(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x05, value, GENMASK(7, 4))
#define SCAN_OFFLOAD_SET_PKT_LOC(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x05, value, GENMASK(15, 8))
/* Command H2C */
#define H2C_CMD_RSVD_PAGE 0x0
#define H2C_CMD_MEDIA_STATUS_RPT 0x01
#define H2C_CMD_SET_PWR_MODE 0x20
#define H2C_CMD_LPS_PG_INFO 0x2b
#define H2C_CMD_DEFAULT_PORT 0x2c
#define H2C_CMD_RA_INFO 0x40
#define H2C_CMD_RSSI_MONITOR 0x42
#define H2C_CMD_RA_INFO_HI 0x46
#define H2C_CMD_BCN_FILTER_OFFLOAD_P0 0x56
#define H2C_CMD_BCN_FILTER_OFFLOAD_P1 0x57
#define H2C_CMD_WL_PHY_INFO 0x58
#define H2C_CMD_SCAN 0x59
#define H2C_CMD_ADAPTIVITY 0x5A
#define H2C_CMD_COEX_TDMA_TYPE 0x60
#define H2C_CMD_QUERY_BT_INFO 0x61
#define H2C_CMD_FORCE_BT_TX_POWER 0x62
#define H2C_CMD_IGNORE_WLAN_ACTION 0x63
#define H2C_CMD_WL_CH_INFO 0x66
#define H2C_CMD_QUERY_BT_MP_INFO 0x67
#define H2C_CMD_BT_WIFI_CONTROL 0x69
#define H2C_CMD_WIFI_CALIBRATION 0x6d
#define H2C_CMD_QUERY_BT_HID_INFO 0x73
#define H2C_CMD_KEEP_ALIVE 0x03
#define H2C_CMD_DISCONNECT_DECISION 0x04
#define H2C_CMD_WOWLAN 0x80
#define H2C_CMD_REMOTE_WAKE_CTRL 0x81
#define H2C_CMD_AOAC_GLOBAL_INFO 0x82
#define H2C_CMD_NLO_INFO 0x8C
#define H2C_CMD_RECOVER_BT_DEV 0xD1
#define SET_H2C_CMD_ID_CLASS(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(7, 0))
#define MEDIA_STATUS_RPT_SET_OP_MODE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
#define MEDIA_STATUS_RPT_SET_MACID(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
#define SET_WL_PHY_INFO_TX_TP(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(17, 8))
#define SET_WL_PHY_INFO_RX_TP(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(27, 18))
#define SET_WL_PHY_INFO_TX_RATE_DESC(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(7, 0))
#define SET_WL_PHY_INFO_RX_RATE_DESC(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(15, 8))
#define SET_WL_PHY_INFO_RX_EVM(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(23, 16))
#define SET_BCN_FILTER_OFFLOAD_P1_MACID(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
#define SET_BCN_FILTER_OFFLOAD_P1_ENABLE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(16))
#define SET_BCN_FILTER_OFFLOAD_P1_HYST(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(20, 17))
#define SET_BCN_FILTER_OFFLOAD_P1_OFFLOAD_MODE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 21))
#define SET_BCN_FILTER_OFFLOAD_P1_THRESHOLD(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24))
#define SET_BCN_FILTER_OFFLOAD_P1_BCN_LOSS_CNT(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(3, 0))
#define SET_BCN_FILTER_OFFLOAD_P1_BCN_INTERVAL(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(13, 4))
#define SET_SCAN_START(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
#define SET_ADAPTIVITY_MODE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(11, 8))
#define SET_ADAPTIVITY_OPTION(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 12))
#define SET_ADAPTIVITY_IGI(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
#define SET_ADAPTIVITY_L2H(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24))
#define SET_ADAPTIVITY_DENSITY(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(7, 0))
#define SET_PWR_MODE_SET_MODE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(14, 8))
#define SET_PWR_MODE_SET_RLBM(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(19, 16))
#define SET_PWR_MODE_SET_SMART_PS(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 20))
#define SET_PWR_MODE_SET_AWAKE_INTERVAL(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24))
#define SET_PWR_MODE_SET_PORT_ID(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(7, 5))
#define SET_PWR_MODE_SET_PWR_STATE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(15, 8))
#define LPS_PG_INFO_LOC(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
#define LPS_PG_DPK_LOC(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24))
#define LPS_PG_SEC_CAM_EN(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
#define LPS_PG_PATTERN_CAM_EN(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(10))
#define SET_RSSI_INFO_MACID(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
#define SET_RSSI_INFO_RSSI(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24))
#define SET_RSSI_INFO_STBC(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, BIT(1))
#define SET_RA_INFO_MACID(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
#define SET_RA_INFO_RATE_ID(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(20, 16))
#define SET_RA_INFO_INIT_RA_LVL(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(22, 21))
#define SET_RA_INFO_SGI_EN(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(23))
#define SET_RA_INFO_BW_MODE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(25, 24))
#define SET_RA_INFO_LDPC(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(26))
#define SET_RA_INFO_NO_UPDATE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(27))
#define SET_RA_INFO_VHT_EN(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(29, 28))
#define SET_RA_INFO_DIS_PT(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(30))
#define SET_RA_INFO_RA_MASK0(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(7, 0))
#define SET_RA_INFO_RA_MASK1(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(15, 8))
#define SET_RA_INFO_RA_MASK2(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(23, 16))
#define SET_RA_INFO_RA_MASK3(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(31, 24))
#define SET_QUERY_BT_INFO(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
#define SET_WL_CH_INFO_LINK(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
#define SET_WL_CH_INFO_CHNL(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
#define SET_WL_CH_INFO_BW(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24))
#define SET_BT_MP_INFO_SEQ(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 12))
#define SET_BT_MP_INFO_OP_CODE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
#define SET_BT_MP_INFO_PARA1(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24))
#define SET_BT_MP_INFO_PARA2(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(7, 0))
#define SET_BT_MP_INFO_PARA3(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(15, 8))
#define SET_BT_TX_POWER_INDEX(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
#define SET_IGNORE_WLAN_ACTION_EN(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
#define SET_COEX_TDMA_TYPE_PARA1(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
#define SET_COEX_TDMA_TYPE_PARA2(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
#define SET_COEX_TDMA_TYPE_PARA3(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24))
#define SET_COEX_TDMA_TYPE_PARA4(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(7, 0))
#define SET_COEX_TDMA_TYPE_PARA5(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(15, 8))
#define SET_BT_WIFI_CONTROL_OP_CODE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
#define SET_BT_WIFI_CONTROL_DATA1(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
#define SET_BT_WIFI_CONTROL_DATA2(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24))
#define SET_BT_WIFI_CONTROL_DATA3(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(7, 0))
#define SET_BT_WIFI_CONTROL_DATA4(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(15, 8))
#define SET_BT_WIFI_CONTROL_DATA5(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(23, 16))
#define SET_COEX_QUERY_HID_INFO_SUBID(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
#define SET_COEX_QUERY_HID_INFO_DATA1(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
#define SET_KEEP_ALIVE_ENABLE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
#define SET_KEEP_ALIVE_ADOPT(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(9))
#define SET_KEEP_ALIVE_PKT_TYPE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(10))
#define SET_KEEP_ALIVE_CHECK_PERIOD(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
#define SET_DISCONNECT_DECISION_ENABLE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
#define SET_DISCONNECT_DECISION_ADOPT(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(9))
#define SET_DISCONNECT_DECISION_CHECK_PERIOD(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
#define SET_DISCONNECT_DECISION_TRY_PKT_NUM(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24))
#define SET_WOWLAN_FUNC_ENABLE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
#define SET_WOWLAN_PATTERN_MATCH_ENABLE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(9))
#define SET_WOWLAN_MAGIC_PKT_ENABLE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(10))
#define SET_WOWLAN_UNICAST_PKT_ENABLE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(11))
#define SET_WOWLAN_REKEY_WAKEUP_ENABLE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(14))
#define SET_WOWLAN_DEAUTH_WAKEUP_ENABLE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(15))
#define SET_REMOTE_WAKECTRL_ENABLE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
#define SET_REMOTE_WAKE_CTRL_NLO_OFFLOAD_EN(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(12))
#define SET_AOAC_GLOBAL_INFO_PAIRWISE_ENC_ALG(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
#define SET_AOAC_GLOBAL_INFO_GROUP_ENC_ALG(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
#define SET_NLO_FUN_EN(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
#define SET_NLO_PS_32K(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(9))
#define SET_NLO_IGNORE_SECURITY(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(10))
#define SET_NLO_LOC_NLO_INFO(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
#define SET_RECOVER_BT_DEV_EN(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
#define GET_FW_DUMP_LEN(_header) \
le32_get_bits(*((__le32 *)(_header) + 0x00), GENMASK(15, 0))
#define GET_FW_DUMP_SEQ(_header) \
le32_get_bits(*((__le32 *)(_header) + 0x00), GENMASK(22, 16))
#define GET_FW_DUMP_MORE(_header) \
le32_get_bits(*((__le32 *)(_header) + 0x00), BIT(23))
#define GET_FW_DUMP_VERSION(_header) \
le32_get_bits(*((__le32 *)(_header) + 0x00), GENMASK(31, 24))
#define GET_FW_DUMP_TLV_TYPE(_header) \
le32_get_bits(*((__le32 *)(_header) + 0x01), GENMASK(15, 0))
#define GET_FW_DUMP_TLV_LEN(_header) \
le32_get_bits(*((__le32 *)(_header) + 0x01), GENMASK(31, 16))
#define GET_FW_DUMP_TLV_VAL(_header) \
le32_get_bits(*((__le32 *)(_header) + 0x02), GENMASK(31, 0))
#define RFK_SET_INFORM_START(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
static inline struct rtw_c2h_cmd *get_c2h_from_skb(struct sk_buff *skb)
{
u32 pkt_offset;
pkt_offset = *((u32 *)skb->cb);
return (struct rtw_c2h_cmd *)(skb->data + pkt_offset);
}
static inline bool rtw_fw_feature_check(struct rtw_fw_state *fw,
enum rtw_fw_feature feature)
{
return !!(fw->feature & feature);
}
static inline bool rtw_fw_feature_ext_check(struct rtw_fw_state *fw,
enum rtw_fw_feature_ext feature)
{
return !!(fw->feature_ext & feature);
}
void rtw_fw_dump_dbg_info(struct rtw_dev *rtwdev);
void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset,
struct sk_buff *skb);
void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb);
void rtw_fw_send_general_info(struct rtw_dev *rtwdev);
void rtw_fw_send_phydm_info(struct rtw_dev *rtwdev);
void rtw_fw_default_port(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif);
void rtw_fw_do_iqk(struct rtw_dev *rtwdev, struct rtw_iqk_para *para);
void rtw_fw_inform_rfk_status(struct rtw_dev *rtwdev, bool start);
void rtw_fw_set_pwr_mode(struct rtw_dev *rtwdev);
void rtw_fw_set_pg_info(struct rtw_dev *rtwdev);
void rtw_fw_query_bt_info(struct rtw_dev *rtwdev);
void rtw_fw_wl_ch_info(struct rtw_dev *rtwdev, u8 link, u8 ch, u8 bw);
void rtw_fw_query_bt_mp_info(struct rtw_dev *rtwdev,
struct rtw_coex_info_req *req);
void rtw_fw_force_bt_tx_power(struct rtw_dev *rtwdev, u8 bt_pwr_dec_lvl);
void rtw_fw_bt_ignore_wlan_action(struct rtw_dev *rtwdev, bool enable);
void rtw_fw_coex_tdma_type(struct rtw_dev *rtwdev,
u8 para1, u8 para2, u8 para3, u8 para4, u8 para5);
void rtw_fw_coex_query_hid_info(struct rtw_dev *rtwdev, u8 sub_id, u8 data);
void rtw_fw_bt_wifi_control(struct rtw_dev *rtwdev, u8 op_code, u8 *data);
void rtw_fw_send_rssi_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si);
void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si,
bool reset_ra_mask);
void rtw_fw_media_status_report(struct rtw_dev *rtwdev, u8 mac_id, bool conn);
void rtw_fw_update_wl_phy_info(struct rtw_dev *rtwdev);
void rtw_fw_beacon_filter_config(struct rtw_dev *rtwdev, bool connect,
struct ieee80211_vif *vif);
int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr,
u8 *buf, u32 size);
void rtw_remove_rsvd_page(struct rtw_dev *rtwdev,
struct rtw_vif *rtwvif);
void rtw_add_rsvd_page_bcn(struct rtw_dev *rtwdev,
struct rtw_vif *rtwvif);
void rtw_add_rsvd_page_pno(struct rtw_dev *rtwdev,
struct rtw_vif *rtwvif);
void rtw_add_rsvd_page_sta(struct rtw_dev *rtwdev,
struct rtw_vif *rtwvif);
int rtw_fw_download_rsvd_page(struct rtw_dev *rtwdev);
void rtw_fw_update_beacon_work(struct work_struct *work);
void rtw_send_rsvd_page_h2c(struct rtw_dev *rtwdev);
int rtw_dump_drv_rsvd_page(struct rtw_dev *rtwdev,
u32 offset, u32 size, u32 *buf);
void rtw_fw_set_remote_wake_ctrl_cmd(struct rtw_dev *rtwdev, bool enable);
void rtw_fw_set_wowlan_ctrl_cmd(struct rtw_dev *rtwdev, bool enable);
void rtw_fw_set_keep_alive_cmd(struct rtw_dev *rtwdev, bool enable);
void rtw_fw_set_disconnect_decision_cmd(struct rtw_dev *rtwdev, bool enable);
void rtw_fw_set_aoac_global_info_cmd(struct rtw_dev *rtwdev,
u8 pairwise_key_enc,
u8 group_key_enc);
void rtw_fw_set_nlo_info(struct rtw_dev *rtwdev, bool enable);
void rtw_fw_set_recover_bt_device(struct rtw_dev *rtwdev);
void rtw_fw_update_pkt_probe_req(struct rtw_dev *rtwdev,
struct cfg80211_ssid *ssid);
void rtw_fw_channel_switch(struct rtw_dev *rtwdev, bool enable);
void rtw_fw_h2c_cmd_dbg(struct rtw_dev *rtwdev, u8 *h2c);
void rtw_fw_c2h_cmd_isr(struct rtw_dev *rtwdev);
int rtw_fw_dump_fifo(struct rtw_dev *rtwdev, u8 fifo_sel, u32 addr, u32 size,
u32 *buffer);
void rtw_fw_scan_notify(struct rtw_dev *rtwdev, bool start);
void rtw_fw_adaptivity(struct rtw_dev *rtwdev);
void rtw_store_op_chan(struct rtw_dev *rtwdev, bool backup);
void rtw_clear_op_chan(struct rtw_dev *rtwdev);
void rtw_hw_scan_start(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_scan_request *req);
void rtw_hw_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
bool aborted);
int rtw_hw_scan_offload(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
bool enable);
void rtw_hw_scan_status_report(struct rtw_dev *rtwdev, struct sk_buff *skb);
void rtw_hw_scan_chan_switch(struct rtw_dev *rtwdev, struct sk_buff *skb);
void rtw_hw_scan_abort(struct rtw_dev *rtwdev);
#endif
@@ -0,0 +1,289 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_HCI_H__
#define __RTW_HCI_H__
/* ops for PCI, USB and SDIO */
struct rtw_hci_ops {
int (*tx_write)(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
struct sk_buff *skb);
void (*tx_kick_off)(struct rtw_dev *rtwdev);
void (*flush_queues)(struct rtw_dev *rtwdev, u32 queues, bool drop);
int (*setup)(struct rtw_dev *rtwdev);
int (*start)(struct rtw_dev *rtwdev);
void (*stop)(struct rtw_dev *rtwdev);
void (*deep_ps)(struct rtw_dev *rtwdev, bool enter);
void (*link_ps)(struct rtw_dev *rtwdev, bool enter);
void (*interface_cfg)(struct rtw_dev *rtwdev);
void (*dynamic_rx_agg)(struct rtw_dev *rtwdev, bool enable);
void (*write_firmware_page)(struct rtw_dev *rtwdev, u32 page,
const u8 *data, u32 size);
int (*write_data_rsvd_page)(struct rtw_dev *rtwdev, u8 *buf, u32 size);
int (*write_data_h2c)(struct rtw_dev *rtwdev, u8 *buf, u32 size);
u8 (*read8)(struct rtw_dev *rtwdev, u32 addr);
u16 (*read16)(struct rtw_dev *rtwdev, u32 addr);
u32 (*read32)(struct rtw_dev *rtwdev, u32 addr);
void (*write8)(struct rtw_dev *rtwdev, u32 addr, u8 val);
void (*write16)(struct rtw_dev *rtwdev, u32 addr, u16 val);
void (*write32)(struct rtw_dev *rtwdev, u32 addr, u32 val);
};
static inline int rtw_hci_tx_write(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
struct sk_buff *skb)
{
return rtwdev->hci.ops->tx_write(rtwdev, pkt_info, skb);
}
static inline void rtw_hci_tx_kick_off(struct rtw_dev *rtwdev)
{
return rtwdev->hci.ops->tx_kick_off(rtwdev);
}
static inline int rtw_hci_setup(struct rtw_dev *rtwdev)
{
return rtwdev->hci.ops->setup(rtwdev);
}
static inline int rtw_hci_start(struct rtw_dev *rtwdev)
{
return rtwdev->hci.ops->start(rtwdev);
}
static inline void rtw_hci_stop(struct rtw_dev *rtwdev)
{
rtwdev->hci.ops->stop(rtwdev);
}
static inline void rtw_hci_deep_ps(struct rtw_dev *rtwdev, bool enter)
{
rtwdev->hci.ops->deep_ps(rtwdev, enter);
}
static inline void rtw_hci_link_ps(struct rtw_dev *rtwdev, bool enter)
{
rtwdev->hci.ops->link_ps(rtwdev, enter);
}
static inline void rtw_hci_interface_cfg(struct rtw_dev *rtwdev)
{
rtwdev->hci.ops->interface_cfg(rtwdev);
}
static inline void rtw_hci_dynamic_rx_agg(struct rtw_dev *rtwdev, bool enable)
{
if (rtwdev->hci.ops->dynamic_rx_agg)
rtwdev->hci.ops->dynamic_rx_agg(rtwdev, enable);
}
static inline void rtw_hci_write_firmware_page(struct rtw_dev *rtwdev, u32 page,
const u8 *data, u32 size)
{
rtwdev->hci.ops->write_firmware_page(rtwdev, page, data, size);
}
static inline int
rtw_hci_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, u32 size)
{
return rtwdev->hci.ops->write_data_rsvd_page(rtwdev, buf, size);
}
static inline int
rtw_hci_write_data_h2c(struct rtw_dev *rtwdev, u8 *buf, u32 size)
{
return rtwdev->hci.ops->write_data_h2c(rtwdev, buf, size);
}
static inline u8 rtw_read8(struct rtw_dev *rtwdev, u32 addr)
{
return rtwdev->hci.ops->read8(rtwdev, addr);
}
static inline u16 rtw_read16(struct rtw_dev *rtwdev, u32 addr)
{
return rtwdev->hci.ops->read16(rtwdev, addr);
}
static inline u32 rtw_read32(struct rtw_dev *rtwdev, u32 addr)
{
return rtwdev->hci.ops->read32(rtwdev, addr);
}
static inline void rtw_write8(struct rtw_dev *rtwdev, u32 addr, u8 val)
{
rtwdev->hci.ops->write8(rtwdev, addr, val);
}
static inline void rtw_write16(struct rtw_dev *rtwdev, u32 addr, u16 val)
{
rtwdev->hci.ops->write16(rtwdev, addr, val);
}
static inline void rtw_write32(struct rtw_dev *rtwdev, u32 addr, u32 val)
{
rtwdev->hci.ops->write32(rtwdev, addr, val);
}
static inline void rtw_write8_set(struct rtw_dev *rtwdev, u32 addr, u8 bit)
{
u8 val;
val = rtw_read8(rtwdev, addr);
rtw_write8(rtwdev, addr, val | bit);
}
static inline void rtw_write16_set(struct rtw_dev *rtwdev, u32 addr, u16 bit)
{
u16 val;
val = rtw_read16(rtwdev, addr);
rtw_write16(rtwdev, addr, val | bit);
}
static inline void rtw_write32_set(struct rtw_dev *rtwdev, u32 addr, u32 bit)
{
u32 val;
val = rtw_read32(rtwdev, addr);
rtw_write32(rtwdev, addr, val | bit);
}
static inline void rtw_write8_clr(struct rtw_dev *rtwdev, u32 addr, u8 bit)
{
u8 val;
val = rtw_read8(rtwdev, addr);
rtw_write8(rtwdev, addr, val & ~bit);
}
static inline void rtw_write16_clr(struct rtw_dev *rtwdev, u32 addr, u16 bit)
{
u16 val;
val = rtw_read16(rtwdev, addr);
rtw_write16(rtwdev, addr, val & ~bit);
}
static inline void rtw_write32_clr(struct rtw_dev *rtwdev, u32 addr, u32 bit)
{
u32 val;
val = rtw_read32(rtwdev, addr);
rtw_write32(rtwdev, addr, val & ~bit);
}
static inline u32
rtw_read_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask)
{
u32 val;
lockdep_assert_held(&rtwdev->mutex);
val = rtwdev->chip->ops->read_rf(rtwdev, rf_path, addr, mask);
return val;
}
static inline void
rtw_write_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask, u32 data)
{
lockdep_assert_held(&rtwdev->mutex);
rtwdev->chip->ops->write_rf(rtwdev, rf_path, addr, mask, data);
}
static inline u32
rtw_read32_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask)
{
u32 shift = __ffs(mask);
u32 orig;
u32 ret;
orig = rtw_read32(rtwdev, addr);
ret = (orig & mask) >> shift;
return ret;
}
static inline u16
rtw_read16_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask)
{
u32 shift = __ffs(mask);
u32 orig;
u32 ret;
orig = rtw_read16(rtwdev, addr);
ret = (orig & mask) >> shift;
return ret;
}
static inline u8
rtw_read8_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask)
{
u32 shift = __ffs(mask);
u32 orig;
u32 ret;
orig = rtw_read8(rtwdev, addr);
ret = (orig & mask) >> shift;
return ret;
}
static inline void
rtw_write32_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data)
{
u32 shift = __ffs(mask);
u32 orig;
u32 set;
WARN(addr & 0x3, "should be 4-byte aligned, addr = 0x%08x\n", addr);
orig = rtw_read32(rtwdev, addr);
set = (orig & ~mask) | ((data << shift) & mask);
rtw_write32(rtwdev, addr, set);
}
static inline void
rtw_write8_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u8 data)
{
u32 shift;
u8 orig, set;
mask &= 0xff;
shift = __ffs(mask);
orig = rtw_read8(rtwdev, addr);
set = (orig & ~mask) | ((data << shift) & mask);
rtw_write8(rtwdev, addr, set);
}
static inline enum rtw_hci_type rtw_hci_type(struct rtw_dev *rtwdev)
{
return rtwdev->hci.type;
}
static inline void rtw_hci_flush_queues(struct rtw_dev *rtwdev, u32 queues,
bool drop)
{
if (rtwdev->hci.ops->flush_queues)
rtwdev->hci.ops->flush_queues(rtwdev, queues, drop);
}
static inline void rtw_hci_flush_all_queues(struct rtw_dev *rtwdev, bool drop)
{
if (rtwdev->hci.ops->flush_queues)
rtwdev->hci.ops->flush_queues(rtwdev,
BIT(rtwdev->hw->queues) - 1,
drop);
}
#endif
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2025 Realtek Corporation
*/
#include "main.h"
#include "debug.h"
#include "led.h"
static int rtw_led_set(struct led_classdev *led,
enum led_brightness brightness)
{
struct rtw_dev *rtwdev = container_of(led, struct rtw_dev, led_cdev);
mutex_lock(&rtwdev->mutex);
rtwdev->chip->ops->led_set(led, brightness);
mutex_unlock(&rtwdev->mutex);
return 0;
}
void rtw_led_init(struct rtw_dev *rtwdev)
{
static const struct ieee80211_tpt_blink rtw_tpt_blink[] = {
{ .throughput = 0 * 1024, .blink_time = 334 },
{ .throughput = 1 * 1024, .blink_time = 260 },
{ .throughput = 5 * 1024, .blink_time = 220 },
{ .throughput = 10 * 1024, .blink_time = 190 },
{ .throughput = 20 * 1024, .blink_time = 170 },
{ .throughput = 50 * 1024, .blink_time = 150 },
{ .throughput = 70 * 1024, .blink_time = 130 },
{ .throughput = 100 * 1024, .blink_time = 110 },
{ .throughput = 200 * 1024, .blink_time = 80 },
{ .throughput = 300 * 1024, .blink_time = 50 },
};
struct led_classdev *led = &rtwdev->led_cdev;
int err;
if (!rtwdev->chip->ops->led_set)
return;
led->brightness_set_blocking = rtw_led_set;
snprintf(rtwdev->led_name, sizeof(rtwdev->led_name),
"rtw88-%s", dev_name(rtwdev->dev));
led->name = rtwdev->led_name;
led->max_brightness = LED_ON;
led->default_trigger =
ieee80211_create_tpt_led_trigger(rtwdev->hw,
IEEE80211_TPT_LEDTRIG_FL_RADIO,
rtw_tpt_blink,
ARRAY_SIZE(rtw_tpt_blink));
err = led_classdev_register(rtwdev->dev, led);
if (err) {
rtw_warn(rtwdev, "Failed to register the LED, error %d\n", err);
return;
}
rtwdev->led_registered = true;
}
void rtw_led_deinit(struct rtw_dev *rtwdev)
{
struct led_classdev *led = &rtwdev->led_cdev;
if (!rtwdev->led_registered)
return;
rtwdev->chip->ops->led_set(led, LED_OFF);
led_classdev_unregister(led);
}
@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2025 Realtek Corporation
*/
#ifndef __RTW_LED_H
#define __RTW_LED_H
#ifdef CONFIG_RTW88_LEDS
void rtw_led_init(struct rtw_dev *rtwdev);
void rtw_led_deinit(struct rtw_dev *rtwdev);
#else
static inline void rtw_led_init(struct rtw_dev *rtwdev)
{
}
static inline void rtw_led_deinit(struct rtw_dev *rtwdev)
{
}
#endif
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_MAC_H__
#define __RTW_MAC_H__
#define RTW_HW_PORT_NUM 5
#define cut_version_to_mask(cut) (0x1 << ((cut) + 1))
#define DDMA_POLLING_COUNT 1000
#define C2H_PKT_BUF 256
#define REPORT_BUF 128
#define PHY_STATUS_SIZE 4
#define ILLEGAL_KEY_GROUP 0xFAAAAA00
/* HW memory address */
#define OCPBASE_RXBUF_FW_88XX 0x18680000
#define OCPBASE_TXBUF_88XX 0x18780000
#define OCPBASE_ROM_88XX 0x00000000
#define OCPBASE_IMEM_88XX 0x00030000
#define OCPBASE_DMEM_88XX 0x00200000
#define OCPBASE_EMEM_88XX 0x00100000
#define RSVD_PG_DRV_NUM 16
#define RSVD_PG_H2C_EXTRAINFO_NUM 24
#define RSVD_PG_H2C_STATICINFO_NUM 8
#define RSVD_PG_H2CQ_NUM 8
#define RSVD_PG_CPU_INSTRUCTION_NUM 0
#define RSVD_PG_FW_TXBUF_NUM 4
void rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw,
u8 primary_ch_idx);
int rtw_pwr_seq_parser(struct rtw_dev *rtwdev,
const struct rtw_pwr_seq_cmd * const *cmd_seq);
int rtw_mac_power_on(struct rtw_dev *rtwdev);
void rtw_mac_power_off(struct rtw_dev *rtwdev);
void rtw_write_firmware_page(struct rtw_dev *rtwdev, u32 page,
const u8 *data, u32 size);
int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw);
int rtw_mac_init(struct rtw_dev *rtwdev);
int rtw_mac_postinit(struct rtw_dev *rtwdev);
void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop);
int rtw_set_trx_fifo_info(struct rtw_dev *rtwdev);
int rtw_ddma_to_fw_fifo(struct rtw_dev *rtwdev, u32 ocp_src, u32 size);
static inline void rtw_mac_flush_all_queues(struct rtw_dev *rtwdev, bool drop)
{
rtw_mac_flush_queues(rtwdev, BIT(rtwdev->hw->queues) - 1, drop);
}
#endif
@@ -0,0 +1,991 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include "main.h"
#include "sec.h"
#include "tx.h"
#include "fw.h"
#include "mac.h"
#include "coex.h"
#include "ps.h"
#include "reg.h"
#include "bf.h"
#include "debug.h"
#include "wow.h"
#include "sar.h"
static void rtw_ops_tx(struct ieee80211_hw *hw,
struct ieee80211_tx_control *control,
struct sk_buff *skb)
{
struct rtw_dev *rtwdev = hw->priv;
if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) {
ieee80211_free_txskb(hw, skb);
return;
}
rtw_tx(rtwdev, control, skb);
}
static void rtw_ops_wake_tx_queue(struct ieee80211_hw *hw,
struct ieee80211_txq *txq)
{
struct rtw_dev *rtwdev = hw->priv;
struct rtw_txq *rtwtxq = (struct rtw_txq *)txq->drv_priv;
if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags))
return;
spin_lock_bh(&rtwdev->txq_lock);
if (list_empty(&rtwtxq->list))
list_add_tail(&rtwtxq->list, &rtwdev->txqs);
spin_unlock_bh(&rtwdev->txq_lock);
/* ensure to dequeue EAPOL (4/4) at the right time */
if (txq->ac == IEEE80211_AC_VO)
__rtw_tx_work(rtwdev);
else
queue_work(rtwdev->tx_wq, &rtwdev->tx_work);
}
static int rtw_ops_start(struct ieee80211_hw *hw)
{
struct rtw_dev *rtwdev = hw->priv;
int ret;
mutex_lock(&rtwdev->mutex);
ret = rtw_core_start(rtwdev);
mutex_unlock(&rtwdev->mutex);
return ret;
}
static void rtw_ops_stop(struct ieee80211_hw *hw, bool suspend)
{
struct rtw_dev *rtwdev = hw->priv;
mutex_lock(&rtwdev->mutex);
rtw_core_stop(rtwdev);
mutex_unlock(&rtwdev->mutex);
}
static int rtw_ops_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)
{
struct rtw_dev *rtwdev = hw->priv;
int ret = 0;
/* let previous ips work finish to ensure we don't leave ips twice */
cancel_work_sync(&rtwdev->ips_work);
mutex_lock(&rtwdev->mutex);
rtw_leave_lps_deep(rtwdev);
if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
!(hw->conf.flags & IEEE80211_CONF_IDLE)) {
ret = rtw_leave_ips(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to leave idle state\n");
goto out;
}
}
if (changed & IEEE80211_CONF_CHANGE_CHANNEL)
rtw_set_channel(rtwdev);
if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
(hw->conf.flags & IEEE80211_CONF_IDLE) &&
!test_bit(RTW_FLAG_SCANNING, rtwdev->flags))
rtw_enter_ips(rtwdev);
out:
mutex_unlock(&rtwdev->mutex);
return ret;
}
static const struct rtw_vif_port rtw_vif_port[] = {
[0] = {
.mac_addr = {.addr = 0x0610},
.bssid = {.addr = 0x0618},
.net_type = {.addr = 0x0100, .mask = 0x30000},
.aid = {.addr = 0x06a8, .mask = 0x7ff},
.bcn_ctrl = {.addr = 0x0550, .mask = 0xff},
},
[1] = {
.mac_addr = {.addr = 0x0700},
.bssid = {.addr = 0x0708},
.net_type = {.addr = 0x0100, .mask = 0xc0000},
.aid = {.addr = 0x0710, .mask = 0x7ff},
.bcn_ctrl = {.addr = 0x0551, .mask = 0xff},
},
[2] = {
.mac_addr = {.addr = 0x1620},
.bssid = {.addr = 0x1628},
.net_type = {.addr = 0x1100, .mask = 0x3},
.aid = {.addr = 0x1600, .mask = 0x7ff},
.bcn_ctrl = {.addr = 0x0578, .mask = 0xff},
},
[3] = {
.mac_addr = {.addr = 0x1630},
.bssid = {.addr = 0x1638},
.net_type = {.addr = 0x1100, .mask = 0xc},
.aid = {.addr = 0x1604, .mask = 0x7ff},
.bcn_ctrl = {.addr = 0x0579, .mask = 0xff},
},
[4] = {
.mac_addr = {.addr = 0x1640},
.bssid = {.addr = 0x1648},
.net_type = {.addr = 0x1100, .mask = 0x30},
.aid = {.addr = 0x1608, .mask = 0x7ff},
.bcn_ctrl = {.addr = 0x057a, .mask = 0xff},
},
};
static int rtw_ops_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct rtw_dev *rtwdev = hw->priv;
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
enum rtw_net_type net_type;
u32 config = 0;
u8 port;
u8 bcn_ctrl = 0;
if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER))
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
rtwvif->stats.tx_unicast = 0;
rtwvif->stats.rx_unicast = 0;
rtwvif->stats.tx_cnt = 0;
rtwvif->stats.rx_cnt = 0;
rtwvif->scan_req = NULL;
memset(&rtwvif->bfee, 0, sizeof(struct rtw_bfee));
rtw_txq_init(rtwdev, vif->txq);
INIT_LIST_HEAD(&rtwvif->rsvd_page_list);
mutex_lock(&rtwdev->mutex);
rtwvif->mac_id = rtw_acquire_macid(rtwdev);
if (rtwvif->mac_id >= RTW_MAX_MAC_ID_NUM) {
mutex_unlock(&rtwdev->mutex);
return -ENOSPC;
}
port = find_first_zero_bit(rtwdev->hw_port, RTW_PORT_NUM);
if (port >= RTW_PORT_NUM) {
mutex_unlock(&rtwdev->mutex);
return -EINVAL;
}
set_bit(port, rtwdev->hw_port);
rtwvif->port = port;
rtwvif->conf = &rtw_vif_port[port];
rtw_leave_lps_deep(rtwdev);
switch (vif->type) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
rtw_add_rsvd_page_bcn(rtwdev, rtwvif);
net_type = RTW_NET_AP_MODE;
bcn_ctrl = BIT_EN_BCN_FUNCTION | BIT_DIS_TSF_UDT;
break;
case NL80211_IFTYPE_ADHOC:
rtw_add_rsvd_page_bcn(rtwdev, rtwvif);
net_type = RTW_NET_AD_HOC;
bcn_ctrl = BIT_EN_BCN_FUNCTION | BIT_DIS_TSF_UDT;
break;
case NL80211_IFTYPE_STATION:
rtw_add_rsvd_page_sta(rtwdev, rtwvif);
net_type = RTW_NET_NO_LINK;
bcn_ctrl = BIT_EN_BCN_FUNCTION;
break;
default:
WARN_ON(1);
clear_bit(rtwvif->port, rtwdev->hw_port);
mutex_unlock(&rtwdev->mutex);
return -EINVAL;
}
ether_addr_copy(rtwvif->mac_addr, vif->addr);
config |= PORT_SET_MAC_ADDR;
rtwvif->net_type = net_type;
config |= PORT_SET_NET_TYPE;
rtwvif->bcn_ctrl = bcn_ctrl;
config |= PORT_SET_BCN_CTRL;
rtw_vif_port_config(rtwdev, rtwvif, config);
rtw_core_port_switch(rtwdev, vif);
rtw_recalc_lps(rtwdev, vif);
mutex_unlock(&rtwdev->mutex);
rtw_dbg(rtwdev, RTW_DBG_STATE, "start vif %pM mac_id %d on port %d\n",
vif->addr, rtwvif->mac_id, rtwvif->port);
return 0;
}
static void rtw_ops_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct rtw_dev *rtwdev = hw->priv;
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
u32 config = 0;
rtw_dbg(rtwdev, RTW_DBG_STATE, "stop vif %pM mac_id %d on port %d\n",
vif->addr, rtwvif->mac_id, rtwvif->port);
mutex_lock(&rtwdev->mutex);
rtw_leave_lps_deep(rtwdev);
rtw_txq_cleanup(rtwdev, vif->txq);
rtw_remove_rsvd_page(rtwdev, rtwvif);
eth_zero_addr(rtwvif->mac_addr);
config |= PORT_SET_MAC_ADDR;
rtwvif->net_type = RTW_NET_NO_LINK;
config |= PORT_SET_NET_TYPE;
rtwvif->bcn_ctrl = 0;
config |= PORT_SET_BCN_CTRL;
rtw_vif_port_config(rtwdev, rtwvif, config);
clear_bit(rtwvif->port, rtwdev->hw_port);
rtw_release_macid(rtwdev, rtwvif->mac_id);
rtw_recalc_lps(rtwdev, NULL);
mutex_unlock(&rtwdev->mutex);
}
static int rtw_ops_change_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum nl80211_iftype type, bool p2p)
{
struct rtw_dev *rtwdev = hw->priv;
rtw_dbg(rtwdev, RTW_DBG_STATE, "change vif %pM (%d)->(%d), p2p (%d)->(%d)\n",
vif->addr, vif->type, type, vif->p2p, p2p);
rtw_ops_remove_interface(hw, vif);
vif->type = type;
vif->p2p = p2p;
return rtw_ops_add_interface(hw, vif);
}
static void rtw_ops_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *new_flags,
u64 multicast)
{
struct rtw_dev *rtwdev = hw->priv;
*new_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_FCSFAIL |
FIF_BCN_PRBRESP_PROMISC;
mutex_lock(&rtwdev->mutex);
rtw_leave_lps_deep(rtwdev);
if (changed_flags & FIF_ALLMULTI) {
if (*new_flags & FIF_ALLMULTI)
rtwdev->hal.rcr |= BIT_AM;
else
rtwdev->hal.rcr &= ~(BIT_AM);
}
if (changed_flags & FIF_FCSFAIL) {
if (*new_flags & FIF_FCSFAIL)
rtwdev->hal.rcr |= BIT_ACRC32;
else
rtwdev->hal.rcr &= ~(BIT_ACRC32);
}
if (changed_flags & FIF_OTHER_BSS) {
if (*new_flags & FIF_OTHER_BSS)
rtwdev->hal.rcr |= BIT_AAP;
else
rtwdev->hal.rcr &= ~(BIT_AAP);
}
if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
rtwdev->hal.rcr &= ~(BIT_CBSSID_BCN | BIT_CBSSID_DATA);
else
rtwdev->hal.rcr |= BIT_CBSSID_BCN;
}
rtw_dbg(rtwdev, RTW_DBG_RX,
"config rx filter, changed=0x%08x, new=0x%08x, rcr=0x%08x\n",
changed_flags, *new_flags, rtwdev->hal.rcr);
rtw_write32(rtwdev, REG_RCR, rtwdev->hal.rcr);
mutex_unlock(&rtwdev->mutex);
}
/* Only have one group of EDCA parameters now */
static const u32 ac_to_edca_param[IEEE80211_NUM_ACS] = {
[IEEE80211_AC_VO] = REG_EDCA_VO_PARAM,
[IEEE80211_AC_VI] = REG_EDCA_VI_PARAM,
[IEEE80211_AC_BE] = REG_EDCA_BE_PARAM,
[IEEE80211_AC_BK] = REG_EDCA_BK_PARAM,
};
static u8 rtw_aifsn_to_aifs(struct rtw_dev *rtwdev,
struct rtw_vif *rtwvif, u8 aifsn)
{
struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
u8 slot_time;
u8 sifs;
slot_time = vif->bss_conf.use_short_slot ? 9 : 20;
sifs = rtwdev->hal.current_band_type == RTW_BAND_5G ? 16 : 10;
return aifsn * slot_time + sifs;
}
static void __rtw_conf_tx(struct rtw_dev *rtwdev,
struct rtw_vif *rtwvif, u16 ac)
{
struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac];
u32 edca_param = ac_to_edca_param[ac];
u8 ecw_max, ecw_min;
u8 aifs;
/* 2^ecw - 1 = cw; ecw = log2(cw + 1) */
ecw_max = ilog2(params->cw_max + 1);
ecw_min = ilog2(params->cw_min + 1);
aifs = rtw_aifsn_to_aifs(rtwdev, rtwvif, params->aifs);
rtw_write32_mask(rtwdev, edca_param, BIT_MASK_TXOP_LMT, params->txop);
rtw_write32_mask(rtwdev, edca_param, BIT_MASK_CWMAX, ecw_max);
rtw_write32_mask(rtwdev, edca_param, BIT_MASK_CWMIN, ecw_min);
rtw_write32_mask(rtwdev, edca_param, BIT_MASK_AIFS, aifs);
}
static void rtw_conf_tx(struct rtw_dev *rtwdev,
struct rtw_vif *rtwvif)
{
u16 ac;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
__rtw_conf_tx(rtwdev, rtwvif, ac);
}
static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *conf,
u64 changed)
{
struct rtw_dev *rtwdev = hw->priv;
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat;
u32 config = 0;
mutex_lock(&rtwdev->mutex);
rtw_leave_lps_deep(rtwdev);
if (changed & BSS_CHANGED_ASSOC) {
rtw_vif_assoc_changed(rtwvif, conf);
if (vif->cfg.assoc) {
rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_FINISH);
rtw_fw_download_rsvd_page(rtwdev);
rtw_send_rsvd_page_h2c(rtwdev);
rtw_fw_default_port(rtwdev, rtwvif);
rtw_coex_media_status_notify(rtwdev, vif->cfg.assoc);
if (rtw_bf_support)
rtw_bf_assoc(rtwdev, vif, conf);
rtw_set_ampdu_factor(rtwdev, vif, conf);
rtw_fw_beacon_filter_config(rtwdev, true, vif);
} else {
rtw_leave_lps(rtwdev);
rtw_bf_disassoc(rtwdev, vif, conf);
/* Abort ongoing scan if cancel_scan isn't issued
* when disconnected by peer
*/
if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags))
rtw_hw_scan_abort(rtwdev);
}
config |= PORT_SET_NET_TYPE;
config |= PORT_SET_AID;
}
if (changed & BSS_CHANGED_BSSID) {
ether_addr_copy(rtwvif->bssid, conf->bssid);
config |= PORT_SET_BSSID;
if (!rtw_core_check_sta_active(rtwdev))
rtw_clear_op_chan(rtwdev);
else
rtw_store_op_chan(rtwdev, true);
}
if (changed & BSS_CHANGED_BEACON_INT) {
if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_STATION)
coex_stat->wl_beacon_interval = conf->beacon_int;
}
if (changed & BSS_CHANGED_BEACON) {
rtw_set_dtim_period(rtwdev, conf->dtim_period);
rtw_fw_download_rsvd_page(rtwdev);
rtw_send_rsvd_page_h2c(rtwdev);
}
if (changed & BSS_CHANGED_BEACON_ENABLED) {
if (conf->enable_beacon)
rtw_write32_set(rtwdev, REG_FWHW_TXQ_CTRL,
BIT_EN_BCNQ_DL);
else
rtw_write32_clr(rtwdev, REG_FWHW_TXQ_CTRL,
BIT_EN_BCNQ_DL);
}
if (changed & BSS_CHANGED_CQM)
rtw_fw_beacon_filter_config(rtwdev, true, vif);
if (changed & BSS_CHANGED_MU_GROUPS)
rtw_chip_set_gid_table(rtwdev, vif, conf);
if (changed & BSS_CHANGED_ERP_SLOT)
rtw_conf_tx(rtwdev, rtwvif);
if (changed & BSS_CHANGED_PS)
rtw_recalc_lps(rtwdev, NULL);
rtw_vif_port_config(rtwdev, rtwvif, config);
mutex_unlock(&rtwdev->mutex);
}
static int rtw_ops_start_ap(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
struct rtw_dev *rtwdev = hw->priv;
const struct rtw_chip_info *chip = rtwdev->chip;
mutex_lock(&rtwdev->mutex);
rtw_write32_set(rtwdev, REG_TCR, BIT_TCR_UPDATE_HGQMD);
rtwdev->ap_active = true;
rtw_store_op_chan(rtwdev, true);
chip->ops->phy_calibration(rtwdev);
mutex_unlock(&rtwdev->mutex);
return 0;
}
static void rtw_ops_stop_ap(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
struct rtw_dev *rtwdev = hw->priv;
mutex_lock(&rtwdev->mutex);
rtw_write32_clr(rtwdev, REG_TCR, BIT_TCR_UPDATE_HGQMD);
rtwdev->ap_active = false;
if (!rtw_core_check_sta_active(rtwdev))
rtw_clear_op_chan(rtwdev);
mutex_unlock(&rtwdev->mutex);
}
static int rtw_ops_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
unsigned int link_id, u16 ac,
const struct ieee80211_tx_queue_params *params)
{
struct rtw_dev *rtwdev = hw->priv;
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
mutex_lock(&rtwdev->mutex);
rtw_leave_lps_deep(rtwdev);
rtwvif->tx_params[ac] = *params;
__rtw_conf_tx(rtwdev, rtwvif, ac);
mutex_unlock(&rtwdev->mutex);
return 0;
}
static int rtw_ops_sta_add(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct rtw_dev *rtwdev = hw->priv;
int ret = 0;
mutex_lock(&rtwdev->mutex);
ret = rtw_sta_add(rtwdev, sta, vif);
mutex_unlock(&rtwdev->mutex);
return ret;
}
static int rtw_ops_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct rtw_dev *rtwdev = hw->priv;
mutex_lock(&rtwdev->mutex);
rtw_fw_beacon_filter_config(rtwdev, false, vif);
rtw_sta_remove(rtwdev, sta, true);
mutex_unlock(&rtwdev->mutex);
return 0;
}
static int rtw_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
bool set)
{
struct rtw_dev *rtwdev = hw->priv;
ieee80211_queue_work(hw, &rtwdev->update_beacon_work);
return 0;
}
static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
struct rtw_dev *rtwdev = hw->priv;
struct rtw_sec_desc *sec = &rtwdev->sec;
u8 hw_key_type;
u8 hw_key_idx;
int ret = 0;
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
hw_key_type = RTW_CAM_WEP40;
break;
case WLAN_CIPHER_SUITE_WEP104:
hw_key_type = RTW_CAM_WEP104;
break;
case WLAN_CIPHER_SUITE_TKIP:
hw_key_type = RTW_CAM_TKIP;
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
break;
case WLAN_CIPHER_SUITE_CCMP:
hw_key_type = RTW_CAM_AES;
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
case WLAN_CIPHER_SUITE_CCMP_256:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
/* suppress error messages */
return -EOPNOTSUPP;
default:
return -ENOTSUPP;
}
mutex_lock(&rtwdev->mutex);
rtw_leave_lps_deep(rtwdev);
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
hw_key_idx = rtw_sec_get_free_cam(sec);
} else {
/* multiple interfaces? */
hw_key_idx = key->keyidx;
}
if (hw_key_idx > sec->total_cam_num) {
ret = -ENOSPC;
goto out;
}
switch (cmd) {
case SET_KEY:
/* need sw generated IV */
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
key->hw_key_idx = hw_key_idx;
rtw_sec_write_cam(rtwdev, sec, sta, key,
hw_key_type, hw_key_idx);
break;
case DISABLE_KEY:
rtw_hci_flush_all_queues(rtwdev, false);
rtw_mac_flush_all_queues(rtwdev, false);
rtw_sec_clear_cam(rtwdev, sec, key->hw_key_idx);
break;
}
/* download new cam settings for PG to backup */
if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_PG)
rtw_fw_download_rsvd_page(rtwdev);
out:
mutex_unlock(&rtwdev->mutex);
return ret;
}
static int rtw_ops_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_ampdu_params *params)
{
struct ieee80211_sta *sta = params->sta;
u16 tid = params->tid;
struct ieee80211_txq *txq = sta->txq[tid];
struct rtw_txq *rtwtxq = (struct rtw_txq *)txq->drv_priv;
switch (params->action) {
case IEEE80211_AMPDU_TX_START:
return IEEE80211_AMPDU_TX_START_IMMEDIATE;
case IEEE80211_AMPDU_TX_STOP_CONT:
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
clear_bit(RTW_TXQ_AMPDU, &rtwtxq->flags);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
set_bit(RTW_TXQ_AMPDU, &rtwtxq->flags);
break;
case IEEE80211_AMPDU_RX_START:
case IEEE80211_AMPDU_RX_STOP:
break;
default:
WARN_ON(1);
return -ENOTSUPP;
}
return 0;
}
static bool rtw_ops_can_aggregate_in_amsdu(struct ieee80211_hw *hw,
struct sk_buff *head,
struct sk_buff *skb)
{
struct rtw_dev *rtwdev = hw->priv;
struct rtw_hal *hal = &rtwdev->hal;
/* we don't want to enable TX AMSDU on 2.4G */
if (hal->current_band_type == RTW_BAND_2G)
return false;
return true;
}
static void rtw_ops_sw_scan_start(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
const u8 *mac_addr)
{
struct rtw_dev *rtwdev = hw->priv;
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
mutex_lock(&rtwdev->mutex);
rtw_core_scan_start(rtwdev, rtwvif, mac_addr, false);
mutex_unlock(&rtwdev->mutex);
}
static void rtw_ops_sw_scan_complete(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct rtw_dev *rtwdev = hw->priv;
mutex_lock(&rtwdev->mutex);
rtw_core_scan_complete(rtwdev, vif, false);
mutex_unlock(&rtwdev->mutex);
}
static void rtw_ops_mgd_prepare_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_prep_tx_info *info)
{
struct rtw_dev *rtwdev = hw->priv;
mutex_lock(&rtwdev->mutex);
rtw_leave_lps_deep(rtwdev);
rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_START);
rtw_chip_prepare_tx(rtwdev);
mutex_unlock(&rtwdev->mutex);
}
static int rtw_ops_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx,
u32 value)
{
struct rtw_dev *rtwdev = hw->priv;
mutex_lock(&rtwdev->mutex);
rtwdev->rts_threshold = value;
mutex_unlock(&rtwdev->mutex);
return 0;
}
static void rtw_ops_sta_statistics(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct station_info *sinfo)
{
struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
sinfo->txrate = si->ra_report.txrate;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
}
static void rtw_ops_flush(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u32 queues, bool drop)
{
struct rtw_dev *rtwdev = hw->priv;
mutex_lock(&rtwdev->mutex);
rtw_leave_lps_deep(rtwdev);
rtw_hci_flush_queues(rtwdev, queues, drop);
rtw_mac_flush_queues(rtwdev, queues, drop);
mutex_unlock(&rtwdev->mutex);
}
struct rtw_iter_bitrate_mask_data {
struct rtw_dev *rtwdev;
struct ieee80211_vif *vif;
const struct cfg80211_bitrate_mask *mask;
};
static void rtw_ra_mask_info_update_iter(void *data, struct ieee80211_sta *sta)
{
struct rtw_iter_bitrate_mask_data *br_data = data;
struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
if (si->vif != br_data->vif)
return;
/* free previous mask setting */
kfree(si->mask);
si->mask = kmemdup(br_data->mask, sizeof(struct cfg80211_bitrate_mask),
GFP_ATOMIC);
if (!si->mask) {
si->use_cfg_mask = false;
return;
}
si->use_cfg_mask = true;
rtw_update_sta_info(br_data->rtwdev, si, true);
}
static void rtw_ra_mask_info_update(struct rtw_dev *rtwdev,
struct ieee80211_vif *vif,
const struct cfg80211_bitrate_mask *mask)
{
struct rtw_iter_bitrate_mask_data br_data;
br_data.rtwdev = rtwdev;
br_data.vif = vif;
br_data.mask = mask;
rtw_iterate_stas(rtwdev, rtw_ra_mask_info_update_iter, &br_data);
}
static int rtw_ops_set_bitrate_mask(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
const struct cfg80211_bitrate_mask *mask)
{
struct rtw_dev *rtwdev = hw->priv;
mutex_lock(&rtwdev->mutex);
rtw_ra_mask_info_update(rtwdev, vif, mask);
mutex_unlock(&rtwdev->mutex);
return 0;
}
static int rtw_ops_set_antenna(struct ieee80211_hw *hw,
int radio_idx,
u32 tx_antenna,
u32 rx_antenna)
{
struct rtw_dev *rtwdev = hw->priv;
const struct rtw_chip_info *chip = rtwdev->chip;
int ret;
if (!chip->ops->set_antenna)
return -EOPNOTSUPP;
mutex_lock(&rtwdev->mutex);
ret = chip->ops->set_antenna(rtwdev, -1, tx_antenna, rx_antenna);
mutex_unlock(&rtwdev->mutex);
return ret;
}
static int rtw_ops_get_antenna(struct ieee80211_hw *hw,
int radio_idx,
u32 *tx_antenna,
u32 *rx_antenna)
{
struct rtw_dev *rtwdev = hw->priv;
struct rtw_hal *hal = &rtwdev->hal;
*tx_antenna = hal->antenna_tx;
*rx_antenna = hal->antenna_rx;
return 0;
}
#ifdef CONFIG_PM
static int rtw_ops_suspend(struct ieee80211_hw *hw,
struct cfg80211_wowlan *wowlan)
{
struct rtw_dev *rtwdev = hw->priv;
int ret;
mutex_lock(&rtwdev->mutex);
ret = rtw_wow_suspend(rtwdev, wowlan);
if (ret)
rtw_err(rtwdev, "failed to suspend for wow %d\n", ret);
mutex_unlock(&rtwdev->mutex);
return ret ? 1 : 0;
}
static int rtw_ops_resume(struct ieee80211_hw *hw)
{
struct rtw_dev *rtwdev = hw->priv;
int ret;
mutex_lock(&rtwdev->mutex);
ret = rtw_wow_resume(rtwdev);
if (ret)
rtw_err(rtwdev, "failed to resume for wow %d\n", ret);
mutex_unlock(&rtwdev->mutex);
return ret ? 1 : 0;
}
static void rtw_ops_set_wakeup(struct ieee80211_hw *hw, bool enabled)
{
struct rtw_dev *rtwdev = hw->priv;
device_set_wakeup_enable(rtwdev->dev, enabled);
}
#endif
static void rtw_reconfig_complete(struct ieee80211_hw *hw,
enum ieee80211_reconfig_type reconfig_type)
{
struct rtw_dev *rtwdev = hw->priv;
mutex_lock(&rtwdev->mutex);
if (reconfig_type == IEEE80211_RECONFIG_TYPE_RESTART)
clear_bit(RTW_FLAG_RESTARTING, rtwdev->flags);
mutex_unlock(&rtwdev->mutex);
}
static int rtw_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_scan_request *req)
{
struct rtw_dev *rtwdev = hw->priv;
int ret;
if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD))
return 1;
if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags))
return -EBUSY;
mutex_lock(&rtwdev->mutex);
rtw_hw_scan_start(rtwdev, vif, req);
ret = rtw_hw_scan_offload(rtwdev, vif, true);
if (ret) {
rtw_hw_scan_abort(rtwdev);
rtw_err(rtwdev, "HW scan failed with status: %d\n", ret);
}
mutex_unlock(&rtwdev->mutex);
return ret;
}
static void rtw_ops_cancel_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct rtw_dev *rtwdev = hw->priv;
if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD))
return;
if (!test_bit(RTW_FLAG_SCANNING, rtwdev->flags))
return;
mutex_lock(&rtwdev->mutex);
rtw_hw_scan_abort(rtwdev);
mutex_unlock(&rtwdev->mutex);
}
static int rtw_ops_set_sar_specs(struct ieee80211_hw *hw,
const struct cfg80211_sar_specs *sar)
{
struct rtw_dev *rtwdev = hw->priv;
mutex_lock(&rtwdev->mutex);
rtw_set_sar_specs(rtwdev, sar);
mutex_unlock(&rtwdev->mutex);
return 0;
}
static void rtw_ops_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_link_sta *link_sta,
u32 changed)
{
struct ieee80211_sta *sta = link_sta->sta;
struct rtw_dev *rtwdev = hw->priv;
struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
if (changed & IEEE80211_RC_BW_CHANGED)
ieee80211_queue_work(rtwdev->hw, &si->rc_work);
}
const struct ieee80211_ops rtw_ops = {
.add_chanctx = ieee80211_emulate_add_chanctx,
.remove_chanctx = ieee80211_emulate_remove_chanctx,
.change_chanctx = ieee80211_emulate_change_chanctx,
.switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,
.tx = rtw_ops_tx,
.wake_tx_queue = rtw_ops_wake_tx_queue,
.start = rtw_ops_start,
.stop = rtw_ops_stop,
.config = rtw_ops_config,
.add_interface = rtw_ops_add_interface,
.remove_interface = rtw_ops_remove_interface,
.change_interface = rtw_ops_change_interface,
.configure_filter = rtw_ops_configure_filter,
.bss_info_changed = rtw_ops_bss_info_changed,
.start_ap = rtw_ops_start_ap,
.stop_ap = rtw_ops_stop_ap,
.conf_tx = rtw_ops_conf_tx,
.sta_add = rtw_ops_sta_add,
.sta_remove = rtw_ops_sta_remove,
.set_tim = rtw_ops_set_tim,
.set_key = rtw_ops_set_key,
.ampdu_action = rtw_ops_ampdu_action,
.can_aggregate_in_amsdu = rtw_ops_can_aggregate_in_amsdu,
.sw_scan_start = rtw_ops_sw_scan_start,
.sw_scan_complete = rtw_ops_sw_scan_complete,
.mgd_prepare_tx = rtw_ops_mgd_prepare_tx,
.set_rts_threshold = rtw_ops_set_rts_threshold,
.sta_statistics = rtw_ops_sta_statistics,
.flush = rtw_ops_flush,
.set_bitrate_mask = rtw_ops_set_bitrate_mask,
.set_antenna = rtw_ops_set_antenna,
.get_antenna = rtw_ops_get_antenna,
.reconfig_complete = rtw_reconfig_complete,
.hw_scan = rtw_ops_hw_scan,
.cancel_hw_scan = rtw_ops_cancel_hw_scan,
.link_sta_rc_update = rtw_ops_sta_rc_update,
.set_sar_specs = rtw_ops_set_sar_specs,
#ifdef CONFIG_PM
.suspend = rtw_ops_suspend,
.resume = rtw_ops_resume,
.set_wakeup = rtw_ops_set_wakeup,
#endif
};
EXPORT_SYMBOL(rtw_ops);
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,280 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTK_PCI_H_
#define __RTK_PCI_H_
#include "main.h"
#define RTK_DEFAULT_TX_DESC_NUM 128
#define RTK_BEQ_TX_DESC_NUM 256
#define RTK_MAX_RX_DESC_NUM 512
/* 11K + rx desc size */
#define RTK_PCI_RX_BUF_SIZE (11454 + 24)
#define RTK_PCI_CTRL 0x300
#define BIT_RST_TRXDMA_INTF BIT(20)
#define BIT_RX_TAG_EN BIT(15)
#define REG_DBI_WDATA_V1 0x03E8
#define REG_DBI_RDATA_V1 0x03EC
#define REG_DBI_FLAG_V1 0x03F0
#define BIT_DBI_RFLAG BIT(17)
#define BIT_DBI_WFLAG BIT(16)
#define BITS_DBI_WREN GENMASK(15, 12)
#define BITS_DBI_ADDR_MASK GENMASK(11, 2)
#define REG_MDIO_V1 0x03F4
#define REG_PCIE_MIX_CFG 0x03F8
#define BITS_MDIO_ADDR_MASK GENMASK(4, 0)
#define BIT_MDIO_WFLAG_V1 BIT(5)
#define RTW_PCI_MDIO_PG_SZ BIT(5)
#define RTW_PCI_MDIO_PG_OFFS_G1 0
#define RTW_PCI_MDIO_PG_OFFS_G2 2
#define RTW_PCI_WR_RETRY_CNT 20
#define RTK_PCIE_LINK_CFG 0x0719
#define BIT_CLKREQ_SW_EN BIT(4)
#define BIT_L1_SW_EN BIT(3)
#define BIT_CLKREQ_N_PAD BIT(0)
#define RTK_PCIE_CLKDLY_CTRL 0x0725
#define BIT_PCI_BCNQ_FLAG BIT(4)
#define RTK_PCI_TXBD_DESA_BCNQ 0x308
#define RTK_PCI_TXBD_DESA_H2CQ 0x1320
#define RTK_PCI_TXBD_DESA_MGMTQ 0x310
#define RTK_PCI_TXBD_DESA_BKQ 0x330
#define RTK_PCI_TXBD_DESA_BEQ 0x328
#define RTK_PCI_TXBD_DESA_VIQ 0x320
#define RTK_PCI_TXBD_DESA_VOQ 0x318
#define RTK_PCI_TXBD_DESA_HI0Q 0x340
#define RTK_PCI_RXBD_DESA_MPDUQ 0x338
#define TRX_BD_IDX_MASK GENMASK(11, 0)
#define TRX_BD_HW_IDX_MASK GENMASK(27, 16)
/* BCNQ is specialized for rsvd page, does not need to specify a number */
#define RTK_PCI_TXBD_NUM_H2CQ 0x1328
#define RTK_PCI_TXBD_NUM_MGMTQ 0x380
#define RTK_PCI_TXBD_NUM_BKQ 0x38A
#define RTK_PCI_TXBD_NUM_BEQ 0x388
#define RTK_PCI_TXBD_NUM_VIQ 0x386
#define RTK_PCI_TXBD_NUM_VOQ 0x384
#define RTK_PCI_TXBD_NUM_HI0Q 0x38C
#define RTK_PCI_RXBD_NUM_MPDUQ 0x382
#define RTK_PCI_TXBD_IDX_H2CQ 0x132C
#define RTK_PCI_TXBD_IDX_MGMTQ 0x3B0
#define RTK_PCI_TXBD_IDX_BKQ 0x3AC
#define RTK_PCI_TXBD_IDX_BEQ 0x3A8
#define RTK_PCI_TXBD_IDX_VIQ 0x3A4
#define RTK_PCI_TXBD_IDX_VOQ 0x3A0
#define RTK_PCI_TXBD_IDX_HI0Q 0x3B8
#define RTK_PCI_RXBD_IDX_MPDUQ 0x3B4
#define RTK_PCI_TXBD_RWPTR_CLR 0x39C
#define RTK_PCI_TXBD_H2CQ_CSR 0x1330
#define BIT_CLR_H2CQ_HOST_IDX BIT(16)
#define BIT_CLR_H2CQ_HW_IDX BIT(8)
#define RTK_PCI_HIMR0 0x0B0
#define RTK_PCI_HISR0 0x0B4
#define RTK_PCI_HIMR1 0x0B8
#define RTK_PCI_HISR1 0x0BC
#define RTK_PCI_HIMR2 0x10B0
#define RTK_PCI_HISR2 0x10B4
#define RTK_PCI_HIMR3 0x10B8
#define RTK_PCI_HISR3 0x10BC
/* IMR 0 */
#define IMR_TIMER2 BIT(31)
#define IMR_TIMER1 BIT(30)
#define IMR_PSTIMEOUT BIT(29)
#define IMR_GTINT4 BIT(28)
#define IMR_GTINT3 BIT(27)
#define IMR_TBDER BIT(26)
#define IMR_TBDOK BIT(25)
#define IMR_TSF_BIT32_TOGGLE BIT(24)
#define IMR_BCNDMAINT0 BIT(20)
#define IMR_BCNDOK0 BIT(16)
#define IMR_HSISR_IND_ON_INT BIT(15)
#define IMR_BCNDMAINT_E BIT(14)
#define IMR_ATIMEND BIT(12)
#define IMR_HISR1_IND_INT BIT(11)
#define IMR_C2HCMD BIT(10)
#define IMR_CPWM2 BIT(9)
#define IMR_CPWM BIT(8)
#define IMR_HIGHDOK BIT(7)
#define IMR_MGNTDOK BIT(6)
#define IMR_BKDOK BIT(5)
#define IMR_BEDOK BIT(4)
#define IMR_VIDOK BIT(3)
#define IMR_VODOK BIT(2)
#define IMR_RDU BIT(1)
#define IMR_ROK BIT(0)
/* IMR 1 */
#define IMR_TXFIFO_TH_INT BIT(30)
#define IMR_BTON_STS_UPDATE BIT(29)
#define IMR_MCUERR BIT(28)
#define IMR_BCNDMAINT7 BIT(27)
#define IMR_BCNDMAINT6 BIT(26)
#define IMR_BCNDMAINT5 BIT(25)
#define IMR_BCNDMAINT4 BIT(24)
#define IMR_BCNDMAINT3 BIT(23)
#define IMR_BCNDMAINT2 BIT(22)
#define IMR_BCNDMAINT1 BIT(21)
#define IMR_BCNDOK7 BIT(20)
#define IMR_BCNDOK6 BIT(19)
#define IMR_BCNDOK5 BIT(18)
#define IMR_BCNDOK4 BIT(17)
#define IMR_BCNDOK3 BIT(16)
#define IMR_BCNDOK2 BIT(15)
#define IMR_BCNDOK1 BIT(14)
#define IMR_ATIMEND_E BIT(13)
#define IMR_ATIMEND BIT(12)
#define IMR_TXERR BIT(11)
#define IMR_RXERR BIT(10)
#define IMR_TXFOVW BIT(9)
#define IMR_RXFOVW BIT(8)
#define IMR_CPU_MGQ_TXDONE BIT(5)
#define IMR_PS_TIMER_C BIT(4)
#define IMR_PS_TIMER_B BIT(3)
#define IMR_PS_TIMER_A BIT(2)
#define IMR_CPUMGQ_TX_TIMER BIT(1)
/* IMR 3 */
#define IMR_H2CDOK BIT(16)
enum rtw_pci_flags {
RTW_PCI_FLAG_NAPI_RUNNING,
NUM_OF_RTW_PCI_FLAGS,
};
/* one element is reserved to know if the ring is closed */
static inline int avail_desc(u32 wp, u32 rp, u32 len)
{
if (rp > wp)
return rp - wp - 1;
else
return len - wp + rp - 1;
}
#define RTK_PCI_TXBD_OWN_OFFSET 15
#define RTK_PCI_TXBD_BCN_WORK 0x383
struct rtw_pci_tx_buffer_desc {
__le16 buf_size;
__le16 psb_len;
__le32 dma;
};
struct rtw_pci_tx_data {
dma_addr_t dma;
u8 sn;
};
struct rtw_pci_ring {
u8 *head;
dma_addr_t dma;
u8 desc_size;
u32 len;
u32 wp;
u32 rp;
};
struct rtw_pci_tx_ring {
struct rtw_pci_ring r;
struct sk_buff_head queue;
bool queue_stopped;
};
struct rtw_pci_rx_buffer_desc {
__le16 buf_size;
__le16 total_pkt_size;
__le32 dma;
};
struct rtw_pci_rx_ring {
struct rtw_pci_ring r;
struct sk_buff *buf[RTK_MAX_RX_DESC_NUM];
};
#define RX_TAG_MAX 8192
struct rtw_pci {
struct pci_dev *pdev;
/* Used for PCI interrupt. */
spinlock_t hwirq_lock;
/* Used for PCI TX ring/queueing, and enable INT. */
spinlock_t irq_lock;
u32 irq_mask[4];
bool irq_enabled;
bool running;
/* napi structure */
struct net_device *netdev;
struct napi_struct napi;
u16 rx_tag;
DECLARE_BITMAP(tx_queued, RTK_MAX_TX_QUEUE_NUM);
struct rtw_pci_tx_ring tx_rings[RTK_MAX_TX_QUEUE_NUM];
struct rtw_pci_rx_ring rx_rings[RTK_MAX_RX_QUEUE_NUM];
u16 link_ctrl;
atomic_t link_usage;
bool rx_no_aspm;
DECLARE_BITMAP(flags, NUM_OF_RTW_PCI_FLAGS);
void __iomem *mmap;
};
extern const struct dev_pm_ops rtw_pm_ops;
extern const struct pci_error_handlers rtw_pci_err_handler;
int rtw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id);
void rtw_pci_remove(struct pci_dev *pdev);
void rtw_pci_shutdown(struct pci_dev *pdev);
static inline u32 max_num_of_tx_queue(u8 queue)
{
u32 max_num;
switch (queue) {
case RTW_TX_QUEUE_BE:
max_num = RTK_BEQ_TX_DESC_NUM;
break;
case RTW_TX_QUEUE_BCN:
max_num = 1;
break;
default:
max_num = RTK_DEFAULT_TX_DESC_NUM;
break;
}
return max_num;
}
static inline struct
rtw_pci_tx_data *rtw_pci_get_tx_data(struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
BUILD_BUG_ON(sizeof(struct rtw_pci_tx_data) >
sizeof(info->status.status_driver_data));
return (struct rtw_pci_tx_data *)info->status.status_driver_data;
}
static inline
struct rtw_pci_tx_buffer_desc *get_tx_buffer_desc(struct rtw_pci_tx_ring *ring,
u32 size)
{
u8 *buf_desc;
buf_desc = ring->r.head + ring->r.wp * size;
return (struct rtw_pci_tx_buffer_desc *)buf_desc;
}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,204 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_PHY_H_
#define __RTW_PHY_H_
#include "debug.h"
extern const u8 rtw_cck_rates[];
extern const u8 rtw_ofdm_rates[];
extern const u8 rtw_ht_1s_rates[];
extern const u8 rtw_ht_2s_rates[];
extern const u8 rtw_vht_1s_rates[];
extern const u8 rtw_vht_2s_rates[];
extern const u8 rtw_ht_3s_rates[];
extern const u8 rtw_ht_4s_rates[];
extern const u8 rtw_vht_3s_rates[];
extern const u8 rtw_vht_4s_rates[];
extern const u8 * const rtw_rate_section[];
extern const u8 rtw_rate_size[];
void rtw_phy_init(struct rtw_dev *rtwdev);
void rtw_phy_dynamic_mechanism(struct rtw_dev *rtwdev);
u8 rtw_phy_rf_power_2_rssi(s8 *rf_power, u8 path_num);
u32 rtw_phy_read_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask);
u32 rtw_phy_read_rf_sipi(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask);
bool rtw_phy_write_rf_reg_sipi(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask, u32 data);
bool rtw_phy_write_rf_reg(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask, u32 data);
bool rtw_phy_write_rf_reg_mix(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask, u32 data);
void rtw_phy_setup_phy_cond(struct rtw_dev *rtwdev, u32 pkg);
void rtw_parse_tbl_phy_cond(struct rtw_dev *rtwdev, const struct rtw_table *tbl);
void rtw_parse_tbl_bb_pg(struct rtw_dev *rtwdev, const struct rtw_table *tbl);
void rtw_parse_tbl_txpwr_lmt(struct rtw_dev *rtwdev, const struct rtw_table *tbl);
void rtw_phy_cfg_mac(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
u32 addr, u32 data);
void rtw_phy_cfg_agc(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
u32 addr, u32 data);
void rtw_phy_cfg_bb(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
u32 addr, u32 data);
void rtw_phy_cfg_rf(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
u32 addr, u32 data);
void rtw_phy_init_tx_power(struct rtw_dev *rtwdev);
void rtw_phy_load_tables(struct rtw_dev *rtwdev);
u8 rtw_phy_get_tx_power_index(struct rtw_dev *rtwdev, u8 rf_path, u8 rate,
enum rtw_bandwidth bw, u8 channel, u8 regd);
void rtw_phy_set_tx_power_level(struct rtw_dev *rtwdev, u8 channel);
void rtw_phy_tx_power_by_rate_config(struct rtw_hal *hal);
void rtw_phy_tx_power_limit_config(struct rtw_hal *hal);
void rtw_phy_pwrtrack_avg(struct rtw_dev *rtwdev, u8 thermal, u8 path);
bool rtw_phy_pwrtrack_thermal_changed(struct rtw_dev *rtwdev, u8 thermal,
u8 path);
u8 rtw_phy_pwrtrack_get_delta(struct rtw_dev *rtwdev, u8 path);
s8 rtw_phy_pwrtrack_get_pwridx(struct rtw_dev *rtwdev,
struct rtw_swing_table *swing_table,
u8 tbl_path, u8 therm_path, u8 delta);
bool rtw_phy_pwrtrack_need_lck(struct rtw_dev *rtwdev);
bool rtw_phy_pwrtrack_need_iqk(struct rtw_dev *rtwdev);
void rtw_phy_config_swing_table(struct rtw_dev *rtwdev,
struct rtw_swing_table *swing_table);
void rtw_phy_set_edcca_th(struct rtw_dev *rtwdev, u8 l2h, u8 h2l);
void rtw_phy_adaptivity_set_mode(struct rtw_dev *rtwdev);
void rtw_phy_parsing_cfo(struct rtw_dev *rtwdev,
struct rtw_rx_pkt_stat *pkt_stat);
void rtw_phy_tx_path_diversity(struct rtw_dev *rtwdev);
struct rtw_txpwr_lmt_cfg_pair {
u8 regd;
u8 band;
u8 bw;
u8 rs;
u8 ch;
s8 txpwr_lmt;
};
struct rtw_phy_pg_cfg_pair {
u32 band;
u32 rf_path;
u32 tx_num;
u32 addr;
u32 bitmask;
u32 data;
};
#define RTW_DECL_TABLE_PHY_COND_CORE(name, cfg, path) \
const struct rtw_table name ## _tbl = { \
.data = name, \
.size = ARRAY_SIZE(name), \
.parse = rtw_parse_tbl_phy_cond, \
.do_cfg = cfg, \
.rf_path = path, \
}
#define RTW_DECL_TABLE_PHY_COND(name, cfg) \
RTW_DECL_TABLE_PHY_COND_CORE(name, cfg, 0)
#define RTW_DECL_TABLE_RF_RADIO(name, path) \
RTW_DECL_TABLE_PHY_COND_CORE(name, rtw_phy_cfg_rf, RF_PATH_ ## path)
#define RTW_DECL_TABLE_BB_PG(name) \
const struct rtw_table name ## _tbl = { \
.data = name, \
.size = ARRAY_SIZE(name), \
.parse = rtw_parse_tbl_bb_pg, \
}
#define RTW_DECL_TABLE_TXPWR_LMT(name) \
const struct rtw_table name ## _tbl = { \
.data = name, \
.size = ARRAY_SIZE(name), \
.parse = rtw_parse_tbl_txpwr_lmt, \
}
static inline const struct rtw_rfe_def *rtw_get_rfe_def(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse;
const struct rtw_rfe_def *rfe_def = NULL;
if (chip->rfe_defs_size == 0)
return NULL;
if (efuse->rfe_option < chip->rfe_defs_size)
rfe_def = &chip->rfe_defs[efuse->rfe_option];
rtw_dbg(rtwdev, RTW_DBG_PHY, "use rfe_def[%d]\n", efuse->rfe_option);
return rfe_def;
}
static inline int rtw_check_supported_rfe(struct rtw_dev *rtwdev)
{
const struct rtw_rfe_def *rfe_def = rtw_get_rfe_def(rtwdev);
if (!rfe_def || !rfe_def->phy_pg_tbl || !rfe_def->txpwr_lmt_tbl) {
rtw_err(rtwdev, "rfe %d isn't supported\n",
rtwdev->efuse.rfe_option);
return -ENODEV;
}
return 0;
}
void rtw_phy_dig_write(struct rtw_dev *rtwdev, u8 igi);
void rtw_phy_dig_reset(struct rtw_dev *rtwdev);
void rtw_phy_dig_set_max_coverage(struct rtw_dev *rtwdev);
struct rtw_power_params {
u8 pwr_base;
s8 pwr_offset;
s8 pwr_limit;
s8 pwr_remnant;
s8 pwr_sar;
};
void
rtw_get_tx_power_params(struct rtw_dev *rtwdev, u8 path,
u8 rate, u8 bw, u8 ch, u8 regd,
struct rtw_power_params *pwr_param);
enum rtw_phy_cck_pd_lv {
CCK_PD_LV0,
CCK_PD_LV1,
CCK_PD_LV2,
CCK_PD_LV3,
CCK_PD_LV4,
CCK_PD_LV_MAX,
};
#define MASKBYTE0 0xff
#define MASKBYTE1 0xff00
#define MASKBYTE2 0xff0000
#define MASKBYTE3 0xff000000
#define MASKHWORD 0xffff0000
#define MASKLWORD 0x0000ffff
#define MASKDWORD 0xffffffff
#define RFREG_MASK 0xfffff
#define MASK7BITS 0x7f
#define MASK12BITS 0xfff
#define MASKH4BITS 0xf0000000
#define MASK20BITS 0xfffff
#define MASK24BITS 0xffffff
#define MASKH3BYTES 0xffffff00
#define MASKL3BYTES 0x00ffffff
#define MASKBYTE2HIGHNIBBLE 0x00f00000
#define MASKBYTE3LOWNIBBLE 0x0f000000
#define MASKL3BYTES 0x00ffffff
#define CCK_FA_AVG_RESET 0xffffffff
#define LSSI_READ_ADDR_MASK 0x7f800000
#define LSSI_READ_EDGE_MASK 0x80000000
#define LSSI_READ_DATA_MASK 0xfffff
#define RRSR_RATE_ORDER_MAX 0xfffff
#define RRSR_RATE_ORDER_CCK_LEN 4
#endif
@@ -0,0 +1,343 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include "main.h"
#include "reg.h"
#include "fw.h"
#include "ps.h"
#include "mac.h"
#include "coex.h"
#include "debug.h"
static int rtw_ips_pwr_up(struct rtw_dev *rtwdev)
{
int ret;
ret = rtw_core_start(rtwdev);
if (ret)
rtw_err(rtwdev, "leave idle state failed\n");
rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE);
rtw_set_channel(rtwdev);
return ret;
}
int rtw_enter_ips(struct rtw_dev *rtwdev)
{
if (!test_bit(RTW_FLAG_POWERON, rtwdev->flags))
return 0;
rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER);
rtw_core_stop(rtwdev);
rtw_hci_link_ps(rtwdev, true);
return 0;
}
static void rtw_restore_port_cfg_iter(void *data, struct ieee80211_vif *vif)
{
struct rtw_dev *rtwdev = data;
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
u32 config = ~0;
rtw_vif_port_config(rtwdev, rtwvif, config);
}
int rtw_leave_ips(struct rtw_dev *rtwdev)
{
int ret;
if (test_bit(RTW_FLAG_POWERON, rtwdev->flags))
return 0;
rtw_hci_link_ps(rtwdev, false);
ret = rtw_ips_pwr_up(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to leave ips state\n");
return ret;
}
rtw_iterate_vifs(rtwdev, rtw_restore_port_cfg_iter, rtwdev);
return 0;
}
void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter)
{
u8 request, confirm, polling;
int ret;
request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr);
confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
/* toggle to request power mode, others remain 0 */
request ^= request | BIT_RPWM_TOGGLE;
if (enter) {
request |= POWER_MODE_LCLK;
if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_PG)
request |= POWER_MODE_PG;
}
/* Each request require an ack from firmware */
request |= POWER_MODE_ACK;
if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_TX_WAKE))
request |= POWER_TX_WAKE;
rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request);
/* Check firmware get the power requset and ack via cpwm register */
ret = read_poll_timeout_atomic(rtw_read8, polling,
(polling ^ confirm) & BIT_RPWM_TOGGLE,
100, 15000, true, rtwdev,
rtwdev->hci.cpwm_addr);
if (ret) {
/* Hit here means that driver failed to get an ack from firmware.
* The reason could be that hardware is locked at Deep sleep,
* so most of the hardware circuits are not working, even
* register read/write; or firmware is locked in some state and
* cannot get the request. It should be treated as fatal error
* and requires an entire analysis about the firmware/hardware.
*/
WARN(1, "firmware failed to ack driver for %s Deep Power mode\n",
enter ? "entering" : "leaving");
rtw_fw_dump_dbg_info(rtwdev);
}
}
EXPORT_SYMBOL(rtw_power_mode_change);
static void __rtw_leave_lps_deep(struct rtw_dev *rtwdev)
{
rtw_hci_deep_ps(rtwdev, false);
}
static int __rtw_fw_leave_lps_check_reg(struct rtw_dev *rtwdev)
{
int i;
/* Driver needs to wait for firmware to leave LPS state
* successfully. Firmware will send null packet to inform AP,
* and see if AP sends an ACK back, then firmware will restore
* the REG_TCR register.
*
* If driver does not wait for firmware, null packet with
* PS bit could be sent due to incorrect REG_TCR setting.
*
* In our test, 100ms should be enough for firmware to finish
* the flow. If REG_TCR Register is still incorrect after 100ms,
* just modify it directly, and throw a warn message.
*/
for (i = 0 ; i < LEAVE_LPS_TRY_CNT; i++) {
if (rtw_read32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN) == 0)
return 0;
msleep(20);
}
return -EBUSY;
}
static int __rtw_fw_leave_lps_check_c2h(struct rtw_dev *rtwdev)
{
if (wait_for_completion_timeout(&rtwdev->lps_leave_check,
LEAVE_LPS_TIMEOUT))
return 0;
return -EBUSY;
}
static void rtw_fw_leave_lps_check(struct rtw_dev *rtwdev)
{
bool ret = false;
struct rtw_fw_state *fw;
if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags))
fw = &rtwdev->wow_fw;
else
fw = &rtwdev->fw;
if (rtw_fw_feature_check(fw, FW_FEATURE_LPS_C2H))
ret = __rtw_fw_leave_lps_check_c2h(rtwdev);
else
ret = __rtw_fw_leave_lps_check_reg(rtwdev);
if (ret) {
rtw_write32_clr(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN);
rtw_warn(rtwdev, "firmware failed to leave lps state\n");
rtw_fw_dump_dbg_info(rtwdev);
}
}
static void rtw_fw_leave_lps_check_prepare(struct rtw_dev *rtwdev)
{
struct rtw_fw_state *fw;
if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags))
fw = &rtwdev->wow_fw;
else
fw = &rtwdev->fw;
if (rtw_fw_feature_check(fw, FW_FEATURE_LPS_C2H))
reinit_completion(&rtwdev->lps_leave_check);
}
static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
{
struct rtw_lps_conf *conf = &rtwdev->lps_conf;
conf->state = RTW_ALL_ON;
conf->awake_interval = 1;
conf->rlbm = 0;
conf->smart_ps = 0;
rtw_hci_link_ps(rtwdev, false);
rtw_fw_leave_lps_check_prepare(rtwdev);
rtw_fw_set_pwr_mode(rtwdev);
rtw_fw_leave_lps_check(rtwdev);
clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE);
}
enum rtw_lps_deep_mode rtw_get_lps_deep_mode(struct rtw_dev *rtwdev)
{
if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags))
return rtwdev->lps_conf.wow_deep_mode;
else
return rtwdev->lps_conf.deep_mode;
}
static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev)
{
if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_NONE)
return;
if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) {
rtw_dbg(rtwdev, RTW_DBG_PS,
"Should enter LPS before entering deep PS\n");
return;
}
if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_PG)
rtw_fw_set_pg_info(rtwdev);
rtw_hci_deep_ps(rtwdev, true);
}
static void rtw_enter_lps_core(struct rtw_dev *rtwdev)
{
struct rtw_lps_conf *conf = &rtwdev->lps_conf;
conf->state = RTW_RF_OFF;
conf->awake_interval = 1;
conf->rlbm = 1;
conf->smart_ps = 2;
rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE);
rtw_fw_set_pwr_mode(rtwdev);
rtw_hci_link_ps(rtwdev, true);
set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
}
static void __rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id)
{
struct rtw_lps_conf *conf = &rtwdev->lps_conf;
if (test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags))
return;
conf->mode = RTW_MODE_LPS;
conf->port_id = port_id;
rtw_enter_lps_core(rtwdev);
}
static void __rtw_leave_lps(struct rtw_dev *rtwdev)
{
struct rtw_lps_conf *conf = &rtwdev->lps_conf;
if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) {
rtw_dbg(rtwdev, RTW_DBG_PS,
"Should leave deep PS before leaving LPS\n");
__rtw_leave_lps_deep(rtwdev);
}
if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags))
return;
conf->mode = RTW_MODE_ACTIVE;
rtw_leave_lps_core(rtwdev);
}
void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id)
{
lockdep_assert_held(&rtwdev->mutex);
if (rtwdev->coex.stat.wl_force_lps_ctrl)
return;
__rtw_enter_lps(rtwdev, port_id);
__rtw_enter_lps_deep(rtwdev);
}
void rtw_leave_lps(struct rtw_dev *rtwdev)
{
lockdep_assert_held(&rtwdev->mutex);
__rtw_leave_lps_deep(rtwdev);
__rtw_leave_lps(rtwdev);
}
void rtw_leave_lps_deep(struct rtw_dev *rtwdev)
{
lockdep_assert_held(&rtwdev->mutex);
__rtw_leave_lps_deep(rtwdev);
}
struct rtw_vif_recalc_lps_iter_data {
struct rtw_dev *rtwdev;
struct ieee80211_vif *found_vif;
int count;
};
static void __rtw_vif_recalc_lps(struct rtw_vif_recalc_lps_iter_data *data,
struct ieee80211_vif *vif)
{
if (data->count < 0)
return;
if (vif->type != NL80211_IFTYPE_STATION) {
data->count = -1;
return;
}
data->count++;
data->found_vif = vif;
}
static void rtw_vif_recalc_lps_iter(void *data, struct ieee80211_vif *vif)
{
__rtw_vif_recalc_lps(data, vif);
}
void rtw_recalc_lps(struct rtw_dev *rtwdev, struct ieee80211_vif *new_vif)
{
struct rtw_vif_recalc_lps_iter_data data = { .rtwdev = rtwdev };
if (new_vif)
__rtw_vif_recalc_lps(&data, new_vif);
rtw_iterate_vifs(rtwdev, rtw_vif_recalc_lps_iter, &data);
if (data.count == 1 && data.found_vif->cfg.ps) {
rtwdev->ps_enabled = true;
} else {
rtwdev->ps_enabled = false;
rtw_leave_lps(rtwdev);
}
}
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_PS_H_
#define __RTW_PS_H_
#define RTW_LPS_THRESHOLD 50
#define POWER_MODE_ACK BIT(6)
#define POWER_MODE_PG BIT(4)
#define POWER_TX_WAKE BIT(1)
#define POWER_MODE_LCLK BIT(0)
#define LEAVE_LPS_TRY_CNT 5
#define LEAVE_LPS_TIMEOUT msecs_to_jiffies(100)
int rtw_enter_ips(struct rtw_dev *rtwdev);
int rtw_leave_ips(struct rtw_dev *rtwdev);
void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter);
void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id);
void rtw_leave_lps(struct rtw_dev *rtwdev);
void rtw_leave_lps_deep(struct rtw_dev *rtwdev);
enum rtw_lps_deep_mode rtw_get_lps_deep_mode(struct rtw_dev *rtwdev);
void rtw_recalc_lps(struct rtw_dev *rtwdev, struct ieee80211_vif *new_vif);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,541 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include "main.h"
#include "regd.h"
#include "debug.h"
#include "phy.h"
#define COUNTRY_REGD_ENT(_alpha2, _regd_2g, _regd_5g) \
{.alpha2 = (_alpha2), \
.txpwr_regd_2g = (_regd_2g), \
.txpwr_regd_5g = (_regd_5g), \
}
#define rtw_dbg_regd_dump(_dev, _msg, _args...) \
do { \
struct rtw_dev *__d = (_dev); \
const struct rtw_regd *__r = &__d->regd; \
rtw_dbg(__d, RTW_DBG_REGD, _msg \
"apply alpha2 %c%c, regd {%d, %d}, dfs_region %d\n",\
##_args, \
__r->regulatory->alpha2[0], \
__r->regulatory->alpha2[1], \
__r->regulatory->txpwr_regd_2g, \
__r->regulatory->txpwr_regd_5g, \
__r->dfs_region); \
} while (0)
/* If country code is not correctly defined in efuse,
* use worldwide country code and txpwr regd.
*/
static const struct rtw_regulatory rtw_reg_ww =
COUNTRY_REGD_ENT("00", RTW_REGD_WW, RTW_REGD_WW);
static const struct rtw_regulatory rtw_reg_map[] = {
COUNTRY_REGD_ENT("AD", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("AE", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("AF", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("AG", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("AI", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("AL", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("AM", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("AN", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("AO", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("AQ", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("AR", RTW_REGD_MEXICO, RTW_REGD_MEXICO),
COUNTRY_REGD_ENT("AS", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("AT", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("AU", RTW_REGD_ACMA, RTW_REGD_ACMA),
COUNTRY_REGD_ENT("AW", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("AZ", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("BA", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("BB", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("BD", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("BE", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("BF", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("BG", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("BH", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("BI", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("BJ", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("BM", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("BN", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("BO", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("BR", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("BS", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("BT", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("BV", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("BW", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("BY", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("BZ", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("CA", RTW_REGD_IC, RTW_REGD_IC),
COUNTRY_REGD_ENT("CC", RTW_REGD_ACMA, RTW_REGD_ACMA),
COUNTRY_REGD_ENT("CD", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("CF", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("CG", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("CH", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("CI", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("CK", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("CL", RTW_REGD_CHILE, RTW_REGD_CHILE),
COUNTRY_REGD_ENT("CM", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("CN", RTW_REGD_CN, RTW_REGD_CN),
COUNTRY_REGD_ENT("CO", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("CR", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("CV", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("CX", RTW_REGD_ACMA, RTW_REGD_ACMA),
COUNTRY_REGD_ENT("CY", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("CZ", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("DE", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("DJ", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("DK", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("DM", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("DO", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("DZ", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("EC", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("EE", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("EG", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("EH", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("ER", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("ES", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("ET", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("FI", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("FJ", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("FK", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("FM", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("FO", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("FR", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("GA", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("GB", RTW_REGD_UK, RTW_REGD_UK),
COUNTRY_REGD_ENT("GD", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("GE", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("GF", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("GG", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("GH", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("GI", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("GL", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("GM", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("GN", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("GP", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("GQ", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("GR", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("GS", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("GT", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("GU", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("GW", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("GY", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("HK", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("HM", RTW_REGD_ACMA, RTW_REGD_ACMA),
COUNTRY_REGD_ENT("HN", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("HR", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("HT", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("HU", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("ID", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("IE", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("IL", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("IM", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("IN", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("IO", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("IQ", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("IR", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("IS", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("IT", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("JE", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("JM", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("JO", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("JP", RTW_REGD_MKK, RTW_REGD_MKK),
COUNTRY_REGD_ENT("KE", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("KG", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("KH", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("KI", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("KM", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("KN", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("KR", RTW_REGD_KCC, RTW_REGD_KCC),
COUNTRY_REGD_ENT("KW", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("KY", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("KZ", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("LA", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("LB", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("LC", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("LI", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("LK", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("LR", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("LS", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("LT", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("LU", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("LV", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("LY", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MA", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MC", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MD", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("ME", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MF", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("MG", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MH", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("MK", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("ML", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MM", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MN", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MO", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MP", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("MQ", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MR", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MS", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MT", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MU", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MV", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MW", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MX", RTW_REGD_MEXICO, RTW_REGD_MEXICO),
COUNTRY_REGD_ENT("MY", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("MZ", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("NA", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("NC", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("NE", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("NF", RTW_REGD_ACMA, RTW_REGD_ACMA),
COUNTRY_REGD_ENT("NG", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("NI", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("NL", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("NO", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("NP", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("NR", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("NU", RTW_REGD_ACMA, RTW_REGD_ACMA),
COUNTRY_REGD_ENT("NZ", RTW_REGD_ACMA, RTW_REGD_ACMA),
COUNTRY_REGD_ENT("OM", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("PA", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("PE", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("PF", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("PG", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("PH", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("PK", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("PL", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("PM", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("PR", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("PS", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("PT", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("PW", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("PY", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("QA", RTW_REGD_QATAR, RTW_REGD_QATAR),
COUNTRY_REGD_ENT("RE", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("RO", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("RS", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("RU", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("RW", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("SA", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("SB", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("SC", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("SE", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("SG", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("SH", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("SI", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("SJ", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("SK", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("SL", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("SM", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("SN", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("SO", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("SR", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("ST", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("SV", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("SX", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("SZ", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("TC", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("TD", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("TF", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("TG", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("TH", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("TJ", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("TK", RTW_REGD_ACMA, RTW_REGD_ACMA),
COUNTRY_REGD_ENT("TM", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("TN", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("TO", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("TR", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("TT", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("TV", RTW_REGD_ETSI, RTW_REGD_WW),
COUNTRY_REGD_ENT("TW", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("TZ", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("UA", RTW_REGD_UKRAINE, RTW_REGD_UKRAINE),
COUNTRY_REGD_ENT("UG", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("US", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("UY", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("UZ", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("VA", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("VC", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("VE", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("VG", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("VI", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("VN", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("VU", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("WF", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("WS", RTW_REGD_FCC, RTW_REGD_FCC),
COUNTRY_REGD_ENT("XK", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("YE", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("YT", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("ZA", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("ZM", RTW_REGD_ETSI, RTW_REGD_ETSI),
COUNTRY_REGD_ENT("ZW", RTW_REGD_ETSI, RTW_REGD_ETSI),
};
static void rtw_regd_apply_hw_cap_flags(struct wiphy *wiphy)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
struct rtw_dev *rtwdev = hw->priv;
struct rtw_efuse *efuse = &rtwdev->efuse;
int i;
if (efuse->hw_cap.bw & BIT(RTW_CHANNEL_WIDTH_80))
return;
sband = wiphy->bands[NL80211_BAND_2GHZ];
if (!sband)
goto out_5g;
for (i = 0; i < sband->n_channels; i++) {
ch = &sband->channels[i];
ch->flags |= IEEE80211_CHAN_NO_80MHZ;
}
out_5g:
sband = wiphy->bands[NL80211_BAND_5GHZ];
if (!sband)
return;
for (i = 0; i < sband->n_channels; i++) {
ch = &sband->channels[i];
ch->flags |= IEEE80211_CHAN_NO_80MHZ;
}
}
static bool rtw_reg_is_ww(const struct rtw_regulatory *reg)
{
return reg == &rtw_reg_ww;
}
static bool rtw_reg_match(const struct rtw_regulatory *reg, const char *alpha2)
{
return memcmp(reg->alpha2, alpha2, 2) == 0;
}
static const struct rtw_regulatory *rtw_reg_find_by_name(const char *alpha2)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(rtw_reg_map); i++) {
if (rtw_reg_match(&rtw_reg_map[i], alpha2))
return &rtw_reg_map[i];
}
return &rtw_reg_ww;
}
static
void rtw_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request);
/* call this before ieee80211_register_hw() */
int rtw_regd_init(struct rtw_dev *rtwdev)
{
struct wiphy *wiphy = rtwdev->hw->wiphy;
const struct rtw_regulatory *chip_reg;
if (!wiphy)
return -EINVAL;
wiphy->reg_notifier = rtw_regd_notifier;
chip_reg = rtw_reg_find_by_name(rtwdev->efuse.country_code);
if (!rtw_reg_is_ww(chip_reg)) {
rtwdev->regd.state = RTW_REGD_STATE_PROGRAMMED;
/* Set REGULATORY_STRICT_REG before ieee80211_register_hw(),
* stack will wait for regulatory_hint() and consider it
* as the superset for our regulatory rule.
*/
wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
} else {
rtwdev->regd.state = RTW_REGD_STATE_WORLDWIDE;
}
rtwdev->regd.regulatory = &rtw_reg_ww;
rtwdev->regd.dfs_region = NL80211_DFS_UNSET;
rtw_dbg_regd_dump(rtwdev, "regd init state %d: ", rtwdev->regd.state);
rtw_regd_apply_hw_cap_flags(wiphy);
return 0;
}
/* call this after ieee80211_register_hw() */
int rtw_regd_hint(struct rtw_dev *rtwdev)
{
struct wiphy *wiphy = rtwdev->hw->wiphy;
int ret;
if (!wiphy)
return -EINVAL;
if (rtwdev->regd.state == RTW_REGD_STATE_PROGRAMMED) {
rtw_dbg(rtwdev, RTW_DBG_REGD,
"country domain %c%c is PGed on efuse",
rtwdev->efuse.country_code[0],
rtwdev->efuse.country_code[1]);
ret = regulatory_hint(wiphy, rtwdev->efuse.country_code);
if (ret) {
rtw_warn(rtwdev,
"failed to hint regulatory: %d\n", ret);
return ret;
}
}
return 0;
}
static bool rtw_regd_mgmt_worldwide(struct rtw_dev *rtwdev,
struct rtw_regd *next_regd,
struct regulatory_request *request)
{
struct wiphy *wiphy = rtwdev->hw->wiphy;
next_regd->state = RTW_REGD_STATE_WORLDWIDE;
if (request->initiator == NL80211_REGDOM_SET_BY_USER &&
!rtw_reg_is_ww(next_regd->regulatory)) {
next_regd->state = RTW_REGD_STATE_SETTING;
wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
}
return true;
}
static bool rtw_regd_mgmt_programmed(struct rtw_dev *rtwdev,
struct rtw_regd *next_regd,
struct regulatory_request *request)
{
if (request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
rtw_reg_match(next_regd->regulatory, rtwdev->efuse.country_code)) {
next_regd->state = RTW_REGD_STATE_PROGRAMMED;
return true;
}
return false;
}
static bool rtw_regd_mgmt_setting(struct rtw_dev *rtwdev,
struct rtw_regd *next_regd,
struct regulatory_request *request)
{
struct wiphy *wiphy = rtwdev->hw->wiphy;
if (request->initiator != NL80211_REGDOM_SET_BY_USER)
return false;
next_regd->state = RTW_REGD_STATE_SETTING;
if (rtw_reg_is_ww(next_regd->regulatory)) {
next_regd->state = RTW_REGD_STATE_WORLDWIDE;
wiphy->regulatory_flags &= ~REGULATORY_COUNTRY_IE_IGNORE;
}
return true;
}
static bool (*const rtw_regd_handler[RTW_REGD_STATE_NR])
(struct rtw_dev *, struct rtw_regd *, struct regulatory_request *) = {
[RTW_REGD_STATE_WORLDWIDE] = rtw_regd_mgmt_worldwide,
[RTW_REGD_STATE_PROGRAMMED] = rtw_regd_mgmt_programmed,
[RTW_REGD_STATE_SETTING] = rtw_regd_mgmt_setting,
};
static bool rtw_regd_state_hdl(struct rtw_dev *rtwdev,
struct rtw_regd *next_regd,
struct regulatory_request *request)
{
next_regd->regulatory = rtw_reg_find_by_name(request->alpha2);
next_regd->dfs_region = request->dfs_region;
return rtw_regd_handler[rtwdev->regd.state](rtwdev, next_regd, request);
}
static
void rtw_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct rtw_dev *rtwdev = hw->priv;
struct rtw_hal *hal = &rtwdev->hal;
struct rtw_regd next_regd = {0};
bool hdl;
hdl = rtw_regd_state_hdl(rtwdev, &next_regd, request);
if (!hdl) {
rtw_dbg(rtwdev, RTW_DBG_REGD,
"regd state %d: ignore request %c%c of initiator %d\n",
rtwdev->regd.state,
request->alpha2[0],
request->alpha2[1],
request->initiator);
return;
}
rtw_dbg(rtwdev, RTW_DBG_REGD, "regd state: %d -> %d\n",
rtwdev->regd.state, next_regd.state);
mutex_lock(&rtwdev->mutex);
rtwdev->regd = next_regd;
rtw_dbg_regd_dump(rtwdev, "get alpha2 %c%c from initiator %d: ",
request->alpha2[0],
request->alpha2[1],
request->initiator);
rtw_phy_adaptivity_set_mode(rtwdev);
rtw_phy_set_tx_power_level(rtwdev, hal->current_channel);
mutex_unlock(&rtwdev->mutex);
}
u8 rtw_regd_get(struct rtw_dev *rtwdev)
{
struct rtw_hal *hal = &rtwdev->hal;
u8 band = hal->current_band_type;
return band == RTW_BAND_2G ?
rtwdev->regd.regulatory->txpwr_regd_2g :
rtwdev->regd.regulatory->txpwr_regd_5g;
}
EXPORT_SYMBOL(rtw_regd_get);
bool rtw_regd_srrc(struct rtw_dev *rtwdev)
{
struct rtw_regd *regd = &rtwdev->regd;
return rtw_reg_match(regd->regulatory, "CN");
}
EXPORT_SYMBOL(rtw_regd_srrc);
struct rtw_regd_alternative_t {
bool set;
u8 alt;
};
#define DECL_REGD_ALT(_regd, _regd_alt) \
[(_regd)] = {.set = true, .alt = (_regd_alt)}
static const struct rtw_regd_alternative_t
rtw_regd_alt[RTW_REGD_MAX] = {
DECL_REGD_ALT(RTW_REGD_IC, RTW_REGD_FCC),
DECL_REGD_ALT(RTW_REGD_KCC, RTW_REGD_ETSI),
DECL_REGD_ALT(RTW_REGD_ACMA, RTW_REGD_ETSI),
DECL_REGD_ALT(RTW_REGD_CHILE, RTW_REGD_FCC),
DECL_REGD_ALT(RTW_REGD_UKRAINE, RTW_REGD_ETSI),
DECL_REGD_ALT(RTW_REGD_MEXICO, RTW_REGD_FCC),
DECL_REGD_ALT(RTW_REGD_CN, RTW_REGD_ETSI),
DECL_REGD_ALT(RTW_REGD_QATAR, RTW_REGD_ETSI),
DECL_REGD_ALT(RTW_REGD_UK, RTW_REGD_ETSI),
};
bool rtw_regd_has_alt(u8 regd, u8 *regd_alt)
{
if (!rtw_regd_alt[regd].set)
return false;
*regd_alt = rtw_regd_alt[regd].alt;
return true;
}
@@ -0,0 +1,73 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_REGD_H_
#define __RTW_REGD_H_
#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR
#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR
enum rtw_chplan_id {
RTW_CHPLAN_ETSI1_NULL = 0x21,
RTW_CHPLAN_WORLD_ETSI1 = 0x26,
RTW_CHPLAN_MKK1_MKK1 = 0x27,
RTW_CHPLAN_IC1_IC2 = 0x2B,
RTW_CHPLAN_WORLD_CHILE1 = 0x2D,
RTW_CHPLAN_WORLD_FCC3 = 0x30,
RTW_CHPLAN_WORLD_FCC5 = 0x32,
RTW_CHPLAN_FCC1_FCC7 = 0x34,
RTW_CHPLAN_WORLD_ETSI2 = 0x35,
RTW_CHPLAN_WORLD_ETSI3 = 0x36,
RTW_CHPLAN_ETSI1_ETSI12 = 0x3D,
RTW_CHPLAN_KCC1_KCC2 = 0x3E,
RTW_CHPLAN_ETSI1_ETSI4 = 0x42,
RTW_CHPLAN_FCC1_NCC3 = 0x44,
RTW_CHPLAN_WORLD_ACMA1 = 0x45,
RTW_CHPLAN_WORLD_ETSI6 = 0x47,
RTW_CHPLAN_WORLD_ETSI7 = 0x48,
RTW_CHPLAN_WORLD_ETSI8 = 0x49,
RTW_CHPLAN_KCC1_KCC3 = 0x4B,
RTW_CHPLAN_WORLD_ETSI10 = 0x51,
RTW_CHPLAN_WORLD_ETSI14 = 0x59,
RTW_CHPLAN_FCC2_FCC7 = 0x61,
RTW_CHPLAN_FCC2_FCC1 = 0x62,
RTW_CHPLAN_WORLD_ETSI15 = 0x63,
RTW_CHPLAN_WORLD_FCC7 = 0x73,
RTW_CHPLAN_FCC2_FCC17 = 0x74,
RTW_CHPLAN_WORLD_ETSI20 = 0x75,
RTW_CHPLAN_FCC2_FCC11 = 0x76,
RTW_CHPLAN_REALTEK_DEFINE = 0x7f,
};
struct country_code_to_enum_rd {
u16 countrycode;
const char *iso_name;
};
enum country_code_type {
COUNTRY_CODE_FCC = 0,
COUNTRY_CODE_IC = 1,
COUNTRY_CODE_ETSI = 2,
COUNTRY_CODE_SPAIN = 3,
COUNTRY_CODE_FRANCE = 4,
COUNTRY_CODE_MKK = 5,
COUNTRY_CODE_MKK1 = 6,
COUNTRY_CODE_ISRAEL = 7,
COUNTRY_CODE_TELEC = 8,
COUNTRY_CODE_MIC = 9,
COUNTRY_CODE_GLOBAL_DOMAIN = 10,
COUNTRY_CODE_WORLD_WIDE_13 = 11,
COUNTRY_CODE_TELEC_NETGEAR = 12,
COUNTRY_CODE_WORLD_WIDE_13_5G_ALL = 13,
/* new channel plan above this */
COUNTRY_CODE_MAX
};
int rtw_regd_init(struct rtw_dev *rtwdev);
int rtw_regd_hint(struct rtw_dev *rtwdev);
u8 rtw_regd_get(struct rtw_dev *rtwdev);
bool rtw_regd_has_alt(u8 regd, u8 *regd_alt);
bool rtw_regd_srrc(struct rtw_dev *rtwdev);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,102 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright Fiona Klute <fiona.klute@gmx.de> */
#ifndef __RTW8703B_H__
#define __RTW8703B_H__
#include "rtw8723x.h"
extern const struct rtw_chip_info rtw8703b_hw_spec;
/* phy status parsing */
#define VGA_BITS GENMASK(4, 0)
#define LNA_L_BITS GENMASK(7, 5)
#define LNA_H_BIT BIT(7)
/* masks for assembling LNA index from high and low bits */
#define BIT_LNA_H_MASK BIT(3)
#define BIT_LNA_L_MASK GENMASK(2, 0)
struct phy_rx_agc_info {
#ifdef __LITTLE_ENDIAN
u8 gain: 7;
u8 trsw: 1;
#else
u8 trsw: 1;
u8 gain: 7;
#endif
} __packed;
/* This struct is called phy_status_rpt_8192cd in the vendor driver,
* there might be potential to share it with drivers for other chips
* of the same generation.
*/
struct phy_status_8703b {
struct phy_rx_agc_info path_agc[2];
u8 ch_corr[2];
u8 cck_sig_qual_ofdm_pwdb_all;
/* for CCK: bits 0:4: VGA index, bits 5:7: LNA index (low) */
u8 cck_agc_rpt_ofdm_cfosho_a;
/* for CCK: bit 7 is high bit of LNA index if long report type */
u8 cck_rpt_b_ofdm_cfosho_b;
u8 reserved_1;
u8 noise_power_db_msb;
s8 path_cfotail[2];
u8 pcts_mask[2];
s8 stream_rxevm[2];
u8 path_rxsnr[2];
u8 noise_power_db_lsb;
u8 reserved_2[3];
u8 stream_csi[2];
u8 stream_target_csi[2];
s8 sig_evm;
u8 reserved_3;
#ifdef __LITTLE_ENDIAN
u8 antsel_rx_keep_2: 1;
u8 sgi_en: 1;
u8 rxsc: 2;
u8 idle_long: 1;
u8 r_ant_train_en: 1;
u8 ant_sel_b: 1;
u8 ant_sel: 1;
#else /* __BIG_ENDIAN */
u8 ant_sel: 1;
u8 ant_sel_b: 1;
u8 r_ant_train_en: 1;
u8 idle_long: 1;
u8 rxsc: 2;
u8 sgi_en: 1;
u8 antsel_rx_keep_2: 1;
#endif
} __packed;
/* Baseband registers */
#define REG_BB_PWR_SAV5_11N 0x0818
/* BIT(11) should be 1 for 8703B *and* 8723D, which means LNA uses 4
* bit for CCK rates in report, not 3. Vendor driver logs a warning if
* it's 0, but handles the case.
*
* Purpose of other parts of this register is unknown, 8723cs driver
* code indicates some other chips use certain bits for antenna
* diversity.
*/
#define REG_BB_AMP 0x0950
#define BIT_MASK_RX_LNA (BIT(11))
/* 0xaXX: 40MHz channel settings */
#define REG_CCK_TXSF2 0x0a24 /* CCK TX filter 2 */
#define REG_CCK_DBG 0x0a28 /* debug port */
#define REG_OFDM0_A_TX_AFE 0x0c84
#define REG_TXIQK_MATRIXB_LSB2_11N 0x0c9c
#define REG_OFDM0_TX_PSD_NOISE 0x0ce4 /* TX pseudo noise weighting */
#define REG_IQK_RDY 0x0e90 /* is != 0 when IQK is done */
/* RF registers */
#define RF_RCK1 0x1E
#define AGG_BURST_NUM 3
#define AGG_BURST_SIZE 0 /* 1K */
#define BIT_MASK_AGG_BURST_NUM (GENMASK(3, 2))
#define BIT_MASK_AGG_BURST_SIZE (GENMASK(5, 4))
#endif /* __RTW8703B_H__ */
@@ -0,0 +1,902 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright Fiona Klute <fiona.klute@gmx.de> */
#include "main.h"
#include "phy.h"
#include "rtw8703b_tables.h"
static const struct rtw_phy_pg_cfg_pair rtw8703b_bb_pg[] = {
{ 0, 0, 0, 0x00000e08, 0x0000ff00, 0x00003200, },
{ 0, 0, 0, 0x0000086c, 0xffffff00, 0x32323200, },
{ 0, 0, 0, 0x00000e00, 0xffffffff, 0x34363636, },
{ 0, 0, 0, 0x00000e04, 0xffffffff, 0x28303234, },
{ 0, 0, 0, 0x00000e10, 0xffffffff, 0x30343434, },
{ 0, 0, 0, 0x00000e14, 0xffffffff, 0x26262830, },
};
RTW_DECL_TABLE_BB_PG(rtw8703b_bb_pg);
/* Regd: FCC -> 0, ETSI -> 2, MKK -> 1
* Band: 2.4G -> 0, 5G -> 1
* Bandwidth (bw): 20M -> 0, 40M -> 1, 80M -> 2, 160M -> 3
* Rate Section (rs): CCK -> 0, OFDM -> 1, HT -> 2, VHT -> 3
*/
static const struct rtw_txpwr_lmt_cfg_pair rtw8703b_txpwr_lmt[] = {
{0, 0, 0, 0, 1, 30},
{2, 0, 0, 0, 1, 26},
{1, 0, 0, 0, 1, 32},
{0, 0, 0, 0, 2, 30},
{2, 0, 0, 0, 2, 26},
{1, 0, 0, 0, 2, 32},
{0, 0, 0, 0, 3, 30},
{2, 0, 0, 0, 3, 26},
{1, 0, 0, 0, 3, 32},
{0, 0, 0, 0, 4, 30},
{2, 0, 0, 0, 4, 26},
{1, 0, 0, 0, 4, 32},
{0, 0, 0, 0, 5, 30},
{2, 0, 0, 0, 5, 26},
{1, 0, 0, 0, 5, 32},
{0, 0, 0, 0, 6, 30},
{2, 0, 0, 0, 6, 26},
{1, 0, 0, 0, 6, 32},
{0, 0, 0, 0, 7, 30},
{2, 0, 0, 0, 7, 26},
{1, 0, 0, 0, 7, 32},
{0, 0, 0, 0, 8, 30},
{2, 0, 0, 0, 8, 26},
{1, 0, 0, 0, 8, 32},
{0, 0, 0, 0, 9, 30},
{2, 0, 0, 0, 9, 26},
{1, 0, 0, 0, 9, 32},
{0, 0, 0, 0, 10, 30},
{2, 0, 0, 0, 10, 26},
{1, 0, 0, 0, 10, 32},
{0, 0, 0, 0, 11, 30},
{2, 0, 0, 0, 11, 26},
{1, 0, 0, 0, 11, 32},
{0, 0, 0, 0, 12, 63},
{2, 0, 0, 0, 12, 26},
{1, 0, 0, 0, 12, 32},
{0, 0, 0, 0, 13, 63},
{2, 0, 0, 0, 13, 26},
{1, 0, 0, 0, 13, 32},
{0, 0, 0, 0, 14, 63},
{2, 0, 0, 0, 14, 63},
{1, 0, 0, 0, 14, 32},
{0, 0, 0, 1, 1, 28},
{2, 0, 0, 1, 1, 28},
{1, 0, 0, 1, 1, 28},
{0, 0, 0, 1, 2, 28},
{2, 0, 0, 1, 2, 32},
{1, 0, 0, 1, 2, 32},
{0, 0, 0, 1, 3, 32},
{2, 0, 0, 1, 3, 32},
{1, 0, 0, 1, 3, 32},
{0, 0, 0, 1, 4, 32},
{2, 0, 0, 1, 4, 32},
{1, 0, 0, 1, 4, 32},
{0, 0, 0, 1, 5, 32},
{2, 0, 0, 1, 5, 32},
{1, 0, 0, 1, 5, 32},
{0, 0, 0, 1, 6, 32},
{2, 0, 0, 1, 6, 32},
{1, 0, 0, 1, 6, 32},
{0, 0, 0, 1, 7, 32},
{2, 0, 0, 1, 7, 32},
{1, 0, 0, 1, 7, 32},
{0, 0, 0, 1, 8, 32},
{2, 0, 0, 1, 8, 32},
{1, 0, 0, 1, 8, 32},
{0, 0, 0, 1, 9, 32},
{2, 0, 0, 1, 9, 32},
{1, 0, 0, 1, 9, 32},
{0, 0, 0, 1, 10, 28},
{2, 0, 0, 1, 10, 32},
{1, 0, 0, 1, 10, 32},
{0, 0, 0, 1, 11, 28},
{2, 0, 0, 1, 11, 32},
{1, 0, 0, 1, 11, 32},
{0, 0, 0, 1, 12, 63},
{2, 0, 0, 1, 12, 32},
{1, 0, 0, 1, 12, 32},
{0, 0, 0, 1, 13, 63},
{2, 0, 0, 1, 13, 28},
{1, 0, 0, 1, 13, 28},
{0, 0, 0, 1, 14, 63},
{2, 0, 0, 1, 14, 63},
{1, 0, 0, 1, 14, 63},
{0, 0, 0, 2, 1, 26},
{2, 0, 0, 2, 1, 26},
{1, 0, 0, 2, 1, 28},
{0, 0, 0, 2, 2, 26},
{2, 0, 0, 2, 2, 32},
{1, 0, 0, 2, 2, 32},
{0, 0, 0, 2, 3, 32},
{2, 0, 0, 2, 3, 32},
{1, 0, 0, 2, 3, 32},
{0, 0, 0, 2, 4, 32},
{2, 0, 0, 2, 4, 32},
{1, 0, 0, 2, 4, 32},
{0, 0, 0, 2, 5, 32},
{2, 0, 0, 2, 5, 32},
{1, 0, 0, 2, 5, 32},
{0, 0, 0, 2, 6, 32},
{2, 0, 0, 2, 6, 32},
{1, 0, 0, 2, 6, 32},
{0, 0, 0, 2, 7, 32},
{2, 0, 0, 2, 7, 32},
{1, 0, 0, 2, 7, 32},
{0, 0, 0, 2, 8, 32},
{2, 0, 0, 2, 8, 32},
{1, 0, 0, 2, 8, 32},
{0, 0, 0, 2, 9, 32},
{2, 0, 0, 2, 9, 32},
{1, 0, 0, 2, 9, 32},
{0, 0, 0, 2, 10, 26},
{2, 0, 0, 2, 10, 32},
{1, 0, 0, 2, 10, 32},
{0, 0, 0, 2, 11, 26},
{2, 0, 0, 2, 11, 32},
{1, 0, 0, 2, 11, 32},
{0, 0, 0, 2, 12, 63},
{2, 0, 0, 2, 12, 32},
{1, 0, 0, 2, 12, 32},
{0, 0, 0, 2, 13, 63},
{2, 0, 0, 2, 13, 26},
{1, 0, 0, 2, 13, 28},
{0, 0, 0, 2, 14, 63},
{2, 0, 0, 2, 14, 63},
{1, 0, 0, 2, 14, 63},
{0, 0, 1, 2, 1, 63},
{2, 0, 1, 2, 1, 63},
{1, 0, 1, 2, 1, 63},
{0, 0, 1, 2, 2, 63},
{2, 0, 1, 2, 2, 63},
{1, 0, 1, 2, 2, 63},
{0, 0, 1, 2, 3, 26},
{2, 0, 1, 2, 3, 26},
{1, 0, 1, 2, 3, 26},
{0, 0, 1, 2, 4, 26},
{2, 0, 1, 2, 4, 28},
{1, 0, 1, 2, 4, 26},
{0, 0, 1, 2, 5, 28},
{2, 0, 1, 2, 5, 28},
{1, 0, 1, 2, 5, 26},
{0, 0, 1, 2, 6, 28},
{2, 0, 1, 2, 6, 28},
{1, 0, 1, 2, 6, 26},
{0, 0, 1, 2, 7, 28},
{2, 0, 1, 2, 7, 28},
{1, 0, 1, 2, 7, 26},
{0, 0, 1, 2, 8, 26},
{2, 0, 1, 2, 8, 28},
{1, 0, 1, 2, 8, 26},
{0, 0, 1, 2, 9, 26},
{2, 0, 1, 2, 9, 28},
{1, 0, 1, 2, 9, 26},
{0, 0, 1, 2, 10, 26},
{2, 0, 1, 2, 10, 28},
{1, 0, 1, 2, 10, 26},
{0, 0, 1, 2, 11, 26},
{2, 0, 1, 2, 11, 26},
{1, 0, 1, 2, 11, 26},
{0, 0, 1, 2, 12, 63},
{2, 0, 1, 2, 12, 26},
{1, 0, 1, 2, 12, 26},
{0, 0, 1, 2, 13, 63},
{2, 0, 1, 2, 13, 26},
{1, 0, 1, 2, 13, 26},
{0, 0, 1, 2, 14, 63},
{2, 0, 1, 2, 14, 63},
{1, 0, 1, 2, 14, 63},
};
RTW_DECL_TABLE_TXPWR_LMT(rtw8703b_txpwr_lmt);
static const u32 rtw8703b_mac[] = {
0x02F, 0x00000030,
0x035, 0x00000000,
0x067, 0x00000002,
0x092, 0x00000080,
0x421, 0x0000000F,
0x428, 0x0000000A,
0x429, 0x00000010,
0x430, 0x00000000,
0x431, 0x00000000,
0x432, 0x00000000,
0x433, 0x00000001,
0x434, 0x00000002,
0x435, 0x00000003,
0x436, 0x00000005,
0x437, 0x00000007,
0x438, 0x00000000,
0x439, 0x00000000,
0x43A, 0x00000000,
0x43B, 0x00000001,
0x43C, 0x00000002,
0x43D, 0x00000003,
0x43E, 0x00000005,
0x43F, 0x00000007,
0x440, 0x0000005D,
0x441, 0x00000001,
0x442, 0x00000000,
0x444, 0x00000010,
0x445, 0x00000000,
0x446, 0x00000000,
0x447, 0x00000000,
0x448, 0x00000000,
0x449, 0x000000F0,
0x44A, 0x0000000F,
0x44B, 0x0000003E,
0x44C, 0x00000010,
0x44D, 0x00000000,
0x44E, 0x00000000,
0x44F, 0x00000000,
0x450, 0x00000000,
0x451, 0x000000F0,
0x452, 0x0000000F,
0x453, 0x00000000,
0x456, 0x0000005E,
0x460, 0x00000066,
0x461, 0x00000066,
0x4C8, 0x000000FF,
0x4C9, 0x00000008,
0x4CC, 0x000000FF,
0x4CD, 0x000000FF,
0x4CE, 0x00000001,
0x500, 0x00000026,
0x501, 0x000000A2,
0x502, 0x0000002F,
0x503, 0x00000000,
0x504, 0x00000028,
0x505, 0x000000A3,
0x506, 0x0000005E,
0x507, 0x00000000,
0x508, 0x0000002B,
0x509, 0x000000A4,
0x50A, 0x0000005E,
0x50B, 0x00000000,
0x50C, 0x0000004F,
0x50D, 0x000000A4,
0x50E, 0x00000000,
0x50F, 0x00000000,
0x512, 0x0000001C,
0x514, 0x0000000A,
0x516, 0x0000000A,
0x525, 0x0000004F,
0x550, 0x00000010,
0x551, 0x00000010,
0x559, 0x00000002,
0x55C, 0x00000028,
0x55D, 0x000000FF,
0x605, 0x00000030,
0x608, 0x0000000E,
0x609, 0x0000002A,
0x620, 0x000000FF,
0x621, 0x000000FF,
0x622, 0x000000FF,
0x623, 0x000000FF,
0x624, 0x000000FF,
0x625, 0x000000FF,
0x626, 0x000000FF,
0x627, 0x000000FF,
0x638, 0x00000028,
0x63C, 0x0000000A,
0x63D, 0x0000000A,
0x63E, 0x0000000C,
0x63F, 0x0000000C,
0x640, 0x00000040,
0x642, 0x00000040,
0x643, 0x00000000,
0x652, 0x000000C8,
0x66A, 0x000000B0,
0x66E, 0x00000005,
0x700, 0x00000021,
0x701, 0x00000043,
0x702, 0x00000065,
0x703, 0x00000087,
0x708, 0x00000021,
0x709, 0x00000043,
0x70A, 0x00000065,
0x70B, 0x00000087,
0x765, 0x00000018,
0x76E, 0x00000004,
};
RTW_DECL_TABLE_PHY_COND(rtw8703b_mac, rtw_phy_cfg_mac);
static const u32 rtw8703b_agc[] = {
0xC78, 0xFC000101,
0xC78, 0xFB010101,
0xC78, 0xFA020101,
0xC78, 0xF9030101,
0xC78, 0xF8040101,
0xC78, 0xF7050101,
0xC78, 0xF6060101,
0xC78, 0xF5070101,
0xC78, 0xF4080101,
0xC78, 0xF3090101,
0xC78, 0xF20A0101,
0xC78, 0xF10B0101,
0xC78, 0xF00C0101,
0xC78, 0xEF0D0101,
0xC78, 0xEE0E0101,
0xC78, 0xED0F0101,
0xC78, 0xEC100101,
0xC78, 0xEB110101,
0xC78, 0xEA120101,
0xC78, 0xE9130101,
0xC78, 0xE8140101,
0xC78, 0xE7150101,
0xC78, 0xE6160101,
0xC78, 0xE5170101,
0xC78, 0xE4180101,
0xC78, 0xE3190101,
0xC78, 0x661A0101,
0xC78, 0x651B0101,
0xC78, 0x641C0101,
0xC78, 0x631D0101,
0xC78, 0x071E0101,
0xC78, 0x061F0101,
0xC78, 0x05200101,
0xC78, 0x04210101,
0xC78, 0x03220101,
0xC78, 0xE8230001,
0xC78, 0xE7240001,
0xC78, 0xE6250001,
0xC78, 0xE5260001,
0xC78, 0xE4270001,
0xC78, 0x89280001,
0xC78, 0x88290001,
0xC78, 0x872A0001,
0xC78, 0x862B0001,
0xC78, 0x852C0001,
0xC78, 0x482D0001,
0xC78, 0x472E0001,
0xC78, 0x462F0001,
0xC78, 0x45300001,
0xC78, 0x44310001,
0xC78, 0x07320001,
0xC78, 0x06330001,
0xC78, 0x05340001,
0xC78, 0x04350001,
0xC78, 0x03360001,
0xC78, 0x02370001,
0xC78, 0x01380001,
0xC78, 0x00390001,
0xC78, 0x003A0001,
0xC78, 0x003B0001,
0xC78, 0x003C0001,
0xC78, 0x003D0001,
0xC78, 0x003E0001,
0xC78, 0x003F0001,
0xC78, 0x7F002001,
0xC78, 0x7F012001,
0xC78, 0x7F022001,
0xC78, 0x7F032001,
0xC78, 0x7F042001,
0xC78, 0x7F052001,
0xC78, 0x7F062001,
0xC78, 0x7F072001,
0xC78, 0x7F082001,
0xC78, 0x7F092001,
0xC78, 0x7F0A2001,
0xC78, 0x7F0B2001,
0xC78, 0x7F0C2001,
0xC78, 0x7F0D2001,
0xC78, 0x7F0E2001,
0xC78, 0x7F0F2001,
0xC78, 0x7F102001,
0xC78, 0x7F112001,
0xC78, 0x7E122001,
0xC78, 0x7D132001,
0xC78, 0x7C142001,
0xC78, 0x7B152001,
0xC78, 0x7A162001,
0xC78, 0x79172001,
0xC78, 0x78182001,
0xC78, 0x77192001,
0xC78, 0x761A2001,
0xC78, 0x751B2001,
0xC78, 0x741C2001,
0xC78, 0x731D2001,
0xC78, 0x721E2001,
0xC78, 0x711F2001,
0xC78, 0x70202001,
0xC78, 0x6F212001,
0xC78, 0x6E222001,
0xC78, 0x6D232001,
0xC78, 0x6C242001,
0xC78, 0x6B252001,
0xC78, 0x6A262001,
0xC78, 0x69272001,
0xC78, 0x68282001,
0xC78, 0x67292001,
0xC78, 0x662A2001,
0xC78, 0x652B2001,
0xC78, 0x642C2001,
0xC78, 0x632D2001,
0xC78, 0x622E2001,
0xC78, 0x612F2001,
0xC78, 0x60302001,
0xC78, 0x42312001,
0xC78, 0x41322001,
0xC78, 0x40332001,
0xC78, 0x23342001,
0xC78, 0x22352001,
0xC78, 0x21362001,
0xC78, 0x20372001,
0xC78, 0x00382001,
0xC78, 0x02392001,
0xC78, 0x013A2001,
0xC78, 0x003B2001,
0xC78, 0x003C2001,
0xC78, 0x003D2001,
0xC78, 0x003E2001,
0xC78, 0x003F2001,
0xC78, 0x7F003101,
0xC78, 0x7F013101,
0xC78, 0x7F023101,
0xC78, 0x7F033101,
0xC78, 0x7F043101,
0xC78, 0x7F053101,
0xC78, 0x7F063101,
0xC78, 0x7E073101,
0xC78, 0x7D083101,
0xC78, 0x7C093101,
0xC78, 0x7B0A3101,
0xC78, 0x7A0B3101,
0xC78, 0x790C3101,
0xC78, 0x780D3101,
0xC78, 0x770E3101,
0xC78, 0x760F3101,
0xC78, 0x75103101,
0xC78, 0x74113101,
0xC78, 0x73123101,
0xC78, 0x72133101,
0xC78, 0x71143101,
0xC78, 0x70153101,
0xC78, 0x6F163101,
0xC78, 0x69173101,
0xC78, 0x68183101,
0xC78, 0x67193101,
0xC78, 0x661A3101,
0xC78, 0x651B3101,
0xC78, 0x641C3101,
0xC78, 0x631D3101,
0xC78, 0x621E3101,
0xC78, 0x611F3101,
0xC78, 0x60203101,
0xC78, 0x42213101,
0xC78, 0x41223101,
0xC78, 0x40233101,
0xC78, 0x22243101,
0xC78, 0x21253101,
0xC78, 0x20263101,
0xC78, 0x00273101,
0xC78, 0x00283101,
0xC78, 0x00293101,
0xC78, 0x002A3101,
0xC78, 0x002B3101,
0xC78, 0x002C3101,
0xC78, 0x002D3101,
0xC78, 0x002E3101,
0xC78, 0x002F3101,
0xC78, 0x00303101,
0xC78, 0x00313101,
0xC78, 0x00323101,
0xC78, 0x00333101,
0xC78, 0x00343101,
0xC78, 0x00353101,
0xC78, 0x00363101,
0xC78, 0x00373101,
0xC78, 0x00383101,
0xC78, 0x00393101,
0xC78, 0x003A3101,
0xC78, 0x003B3101,
0xC78, 0x003C3101,
0xC78, 0x003D3101,
0xC78, 0x003E3101,
0xC78, 0x003F3101,
0xC78, 0xFA403101,
0xC78, 0xF9413101,
0xC78, 0xF8423101,
0xC78, 0xF7433101,
0xC78, 0xF6443101,
0xC78, 0xF5453101,
0xC78, 0xF4463101,
0xC78, 0xF3473101,
0xC78, 0xF2483101,
0xC78, 0xE1493101,
0xC78, 0xE04A3101,
0xC78, 0xEF4B3101,
0xC78, 0xEE4C3101,
0xC78, 0xED4D3101,
0xC78, 0xEC4E3101,
0xC78, 0xEB4F3101,
0xC78, 0xEA503101,
0xC78, 0xE9513101,
0xC78, 0xE8523101,
0xC78, 0xE7533101,
0xC78, 0xE6543101,
0xC78, 0xE5553101,
0xC78, 0xE4563101,
0xC78, 0xE3573101,
0xC78, 0xE2583101,
0xC78, 0xE1593101,
0xC78, 0xE05A3101,
0xC78, 0xC25B3101,
0xC78, 0xC15C3101,
0xC78, 0xC05D3101,
0xC78, 0x825E3101,
0xC78, 0x815F3101,
0xC78, 0x80603101,
0xC78, 0x80613101,
0xC78, 0x80623101,
0xC78, 0x80633101,
0xC78, 0x80643101,
0xC78, 0x80653101,
0xC78, 0x80663101,
0xC78, 0x80673101,
0xC78, 0x80683101,
0xC78, 0x80693101,
0xC78, 0x806A3101,
0xC78, 0x806B3101,
0xC78, 0x806C3101,
0xC78, 0x806D3101,
0xC78, 0x806E3101,
0xC78, 0x806F3101,
0xC78, 0x80703101,
0xC78, 0x80713101,
0xC78, 0x80723101,
0xC78, 0x80733101,
0xC78, 0x80743101,
0xC78, 0x80753101,
0xC78, 0x80763101,
0xC78, 0x80773101,
0xC78, 0x80783101,
0xC78, 0x80793101,
0xC78, 0x807A3101,
0xC78, 0x807B3101,
0xC78, 0x807C3101,
0xC78, 0x807D3101,
0xC78, 0x807E3101,
0xC78, 0x807F3101,
0xC78, 0xFF402001,
0xC78, 0xFF412001,
0xC78, 0xFF422001,
0xC78, 0xFF432001,
0xC78, 0xFF442001,
0xC78, 0xFF452001,
0xC78, 0xFF462001,
0xC78, 0xFF472001,
0xC78, 0xFF482001,
0xC78, 0xFF492001,
0xC78, 0xFF4A2001,
0xC78, 0xFF4B2001,
0xC78, 0xFF4C2001,
0xC78, 0xFE4D2001,
0xC78, 0xFD4E2001,
0xC78, 0xFC4F2001,
0xC78, 0xFB502001,
0xC78, 0xFA512001,
0xC78, 0xF9522001,
0xC78, 0xF8532001,
0xC78, 0xF7542001,
0xC78, 0xF6552001,
0xC78, 0xF5562001,
0xC78, 0xF4572001,
0xC78, 0xF3582001,
0xC78, 0xF2592001,
0xC78, 0xF15A2001,
0xC78, 0xF05B2001,
0xC78, 0xEF5C2001,
0xC78, 0xEE5D2001,
0xC78, 0xED5E2001,
0xC78, 0xEC5F2001,
0xC78, 0xEB602001,
0xC78, 0xEA612001,
0xC78, 0xE9622001,
0xC78, 0xE8632001,
0xC78, 0xE7642001,
0xC78, 0xE6652001,
0xC78, 0xE5662001,
0xC78, 0xE4672001,
0xC78, 0xE3682001,
0xC78, 0xC5692001,
0xC78, 0xC46A2001,
0xC78, 0xC36B2001,
0xC78, 0xA46C2001,
0xC78, 0x846D2001,
0xC78, 0x836E2001,
0xC78, 0x826F2001,
0xC78, 0x81702001,
0xC78, 0x80712001,
0xC78, 0x80722001,
0xC78, 0x80732001,
0xC78, 0x80742001,
0xC78, 0x80752001,
0xC78, 0x80762001,
0xC78, 0x80772001,
0xC78, 0x80782001,
0xC78, 0x80792001,
0xC78, 0x807A2001,
0xC78, 0x807B2001,
0xC78, 0x807C2001,
0xC78, 0x807D2001,
0xC78, 0x807E2001,
0xC78, 0x807F2001,
0xC50, 0x69553422,
0xC50, 0x69553420,
};
RTW_DECL_TABLE_PHY_COND(rtw8703b_agc, rtw_phy_cfg_agc);
/* init values for BB registers */
static const u32 rtw8703b_bb[] = {
0x800, 0x83045700,
0x804, 0x00000003,
0x808, 0x0000FC00,
0x80C, 0x0000000A,
0x810, 0x10001331,
0x814, 0x020C3D10,
0x818, 0x02200385,
0x81C, 0x00000000,
0x820, 0x01000100,
0x824, 0x00390204,
0x828, 0x00000000,
0x82C, 0x00000000,
0x830, 0x00000000,
0x834, 0x00000000,
0x838, 0x00000000,
0x83C, 0x00000000,
0x840, 0x00010000,
0x844, 0x00000000,
0x848, 0x00000000,
0x84C, 0x00000000,
0x850, 0x00000000,
0x854, 0x00000000,
0x858, 0x569A11A9,
0x85C, 0x01000014,
0x860, 0x66F60110,
0x864, 0x061F0649,
0x868, 0x00000000,
0x86C, 0x27272700,
0x870, 0x07000760,
0x874, 0x25004000,
0x878, 0x00000808,
0x87C, 0x004F0201,
0x880, 0xB0000B1E,
0x884, 0x00000001,
0x888, 0x00000000,
0x88C, 0xCCC000C0,
0x890, 0x00000800,
0x894, 0xFFFFFFFE,
0x898, 0x40302010,
0x89C, 0x00706050,
0x900, 0x00000000,
0x904, 0x00000023,
0x908, 0x00000000,
0x90C, 0x81121111,
0x910, 0x00000002,
0x914, 0x00000201,
0x948, 0x99000000,
0x94C, 0x00000010,
0x950, 0x20003800,
0x954, 0x4A880000,
0x958, 0x4BC5D87A,
0x95C, 0x04EB9B79,
0xA00, 0x00D047C8,
0xA04, 0x80FF800C,
0xA08, 0x8C838300,
0xA0C, 0x2E7F120F,
0xA10, 0x9500BB78,
0xA14, 0x1114D028,
0xA18, 0x00881117,
0xA1C, 0x89140F00,
0xA20, 0xD1D80000,
0xA24, 0x5A7DA0BD,
0xA28, 0x0000223B,
0xA2C, 0x00D30000,
0xA70, 0x101FBF00,
0xA74, 0x00000007,
0xA78, 0x00008900,
0xA7C, 0x225B0606,
0xA80, 0x2180FA74,
0xA84, 0x00120000,
0xA88, 0x040C0000,
0xA8C, 0x12345678,
0xA90, 0xABCDEF00,
0xA94, 0x001B1B89,
0xA98, 0x05100000,
0xA9C, 0x3F000000,
0xAA0, 0x00000000,
0xB2C, 0x00000000,
0xC00, 0x48071D40,
0xC04, 0x03A05611,
0xC08, 0x000000E4,
0xC0C, 0x6C6C6C6C,
0xC10, 0x18800000,
0xC14, 0x40000100,
0xC18, 0x08800000,
0xC1C, 0x40000100,
0xC20, 0x00000000,
0xC24, 0x00000000,
0xC28, 0x00000000,
0xC2C, 0x00000000,
0xC30, 0x69E9AC4B,
0xC34, 0x31000040,
0xC38, 0x21688080,
0xC3C, 0x000016CC,
0xC40, 0x1F78403F,
0xC44, 0x00010036,
0xC48, 0xEC020107,
0xC4C, 0x007F037F,
0xC50, 0x69553420,
0xC54, 0x43BC0094,
0xC58, 0x00015967,
0xC5C, 0x18250492,
0xC60, 0x00000000,
0xC64, 0x7112848B,
0xC68, 0x47C07BFF,
0xC6C, 0x00000036,
0xC70, 0x2C7F000D,
0xC74, 0x020600DB,
0xC78, 0x0000001F,
0xC7C, 0x00B91612,
0xC80, 0x390000E4,
0xC84, 0x19F60000,
0xC88, 0x40000100,
0xC8C, 0x20200000,
0xC90, 0x00091521,
0xC94, 0x00000000,
0xC98, 0x00121820,
0xC9C, 0x00007F7F,
0xCA0, 0x00000000,
0xCA4, 0x000300A0,
0xCA8, 0x00000000,
0xCAC, 0x00000000,
0xCB0, 0x00000000,
0xCB4, 0x00000000,
0xCB8, 0x00000000,
0xCBC, 0x28000000,
0xCC0, 0x00000000,
0xCC4, 0x00000000,
0xCC8, 0x00000000,
0xCCC, 0x00000000,
0xCD0, 0x00000000,
0xCD4, 0x00000000,
0xCD8, 0x64B22427,
0xCDC, 0x00766932,
0xCE0, 0x00222222,
0xCE4, 0x10000000,
0xCE8, 0x37644302,
0xCEC, 0x2F97D40C,
0xD00, 0x00030740,
0xD04, 0x40020401,
0xD08, 0x0000907F,
0xD0C, 0x20010201,
0xD10, 0xA0633333,
0xD14, 0x3333BC53,
0xD18, 0x7A8F5B6F,
0xD2C, 0xCB979975,
0xD30, 0x00000000,
0xD34, 0x80608000,
0xD38, 0x98000000,
0xD3C, 0x40127353,
0xD40, 0x00000000,
0xD44, 0x00000000,
0xD48, 0x00000000,
0xD4C, 0x00000000,
0xD50, 0x6437140A,
0xD54, 0x00000000,
0xD58, 0x00000282,
0xD5C, 0x30032064,
0xD60, 0x4653DE68,
0xD64, 0x04518A3C,
0xD68, 0x00002101,
0xE00, 0x2D2D2D2D,
0xE04, 0x2D2D2D2D,
0xE08, 0x0390272D,
0xE10, 0x2D2D2D2D,
0xE14, 0x2D2D2D2D,
0xE18, 0x2D2D2D2D,
0xE1C, 0x2D2D2D2D,
0xE28, 0x00000000,
0xE30, 0x1000DC1F,
0xE34, 0x10008C1F,
0xE38, 0x02140102,
0xE3C, 0x681604C2,
0xE40, 0x01007C00,
0xE44, 0x01004800,
0xE48, 0xFB000000,
0xE4C, 0x000028D1,
0xE50, 0x1000DC1F,
0xE54, 0x10008C1F,
0xE58, 0x02140102,
0xE5C, 0x28160D05,
0xE60, 0x00000048,
0xE68, 0x001B25A4,
0xE6C, 0x01C00014,
0xE70, 0x01C00014,
0xE74, 0x02000014,
0xE78, 0x02000014,
0xE7C, 0x02000014,
0xE80, 0x02000014,
0xE84, 0x01C00014,
0xE88, 0x02000014,
0xE8C, 0x01C00014,
0xED0, 0x01C00014,
0xED4, 0x01C00014,
0xED8, 0x01C00014,
0xEDC, 0x00000014,
0xEE0, 0x00000014,
0xEE8, 0x21555448,
0xEEC, 0x03C00014,
0xF14, 0x00000003,
0xF4C, 0x00000000,
0xF00, 0x00000300,
};
RTW_DECL_TABLE_PHY_COND(rtw8703b_bb, rtw_phy_cfg_bb);
static const u32 rtw8703b_rf_a[] = {
0x018, 0x00008C01,
0x0B5, 0x0008C050,
0x0B1, 0x00054258,
0x0B2, 0x00054C00,
0x030, 0x00018000,
0x031, 0x00000027,
0x032, 0x000A7F07,
0x030, 0x00020000,
0x031, 0x00000027,
0x032, 0x000E7D87,
0x01C, 0x000F8635,
0x0EF, 0x00080000,
0x030, 0x00008000,
0x031, 0x00000004,
0x032, 0x00006105,
0x0EF, 0x00000000,
0x0EF, 0x00000400,
0x041, 0x0000BD54,
0x041, 0x00003DD4,
0x041, 0x0000FDD4,
0x0EF, 0x00000000,
0x0DF, 0x00000600,
0x050, 0x0000C6DB,
0x051, 0x00004505,
0x052, 0x0000E31D,
0x053, 0x00040579,
0x054, 0x00000000,
0x055, 0x0008206E,
0x056, 0x00040000,
0x0EF, 0x00000100,
0x034, 0x0000ADD7,
0x034, 0x00009DD4,
0x034, 0x00008DD1,
0x034, 0x00007DCE,
0x034, 0x00006DCB,
0x034, 0x00005CCE,
0x034, 0x000048CD,
0x034, 0x000034CC,
0x034, 0x0000244F,
0x034, 0x0000144C,
0x034, 0x0000004E,
0x0EF, 0x00000000,
0x0EF, 0x00002000,
0x03B, 0x0003801F,
0x03B, 0x00030002,
0x03B, 0x00028001,
0x03B, 0x00020000,
0x03B, 0x00018003,
0x03B, 0x00010002,
0x03B, 0x00008001,
0x03B, 0x00000000,
0x0EF, 0x00000000,
0x082, 0x000C0000,
0x083, 0x000AF025,
0x01E, 0x00000C08,
};
RTW_DECL_TABLE_RF_RADIO(rtw8703b_rf_a, A);
@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright Fiona Klute <fiona.klute@gmx.de> */
#ifndef __RTW8703B_TABLES_H__
#define __RTW8703B_TABLES_H__
extern const struct rtw_table rtw8703b_bb_pg_tbl;
extern const struct rtw_table rtw8703b_txpwr_lmt_tbl;
extern const struct rtw_table rtw8703b_mac_tbl;
extern const struct rtw_table rtw8703b_agc_tbl;
extern const struct rtw_table rtw8703b_bb_tbl;
extern const struct rtw_table rtw8703b_rf_a_tbl;
#endif
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright Fiona Klute <fiona.klute@gmx.de> */
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/module.h>
#include "main.h"
#include "rtw8703b.h"
#include "sdio.h"
static const struct sdio_device_id rtw_8723cs_id_table[] = {
{
SDIO_DEVICE(SDIO_VENDOR_ID_REALTEK,
SDIO_DEVICE_ID_REALTEK_RTW8723CS),
.driver_data = (kernel_ulong_t)&rtw8703b_hw_spec,
},
{}
};
MODULE_DEVICE_TABLE(sdio, rtw_8723cs_id_table);
static struct sdio_driver rtw_8723cs_driver = {
.name = KBUILD_MODNAME,
.id_table = rtw_8723cs_id_table,
.probe = rtw_sdio_probe,
.remove = rtw_sdio_remove,
.shutdown = rtw_sdio_shutdown,
.drv = {
.pm = &rtw_sdio_pm_ops,
}};
module_sdio_driver(rtw_8723cs_driver);
MODULE_AUTHOR("Fiona Klute <fiona.klute@gmx.de>");
MODULE_DESCRIPTION("Realtek 802.11n wireless 8723cs driver");
MODULE_LICENSE("Dual BSD/GPL");
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW8723D_H__
#define __RTW8723D_H__
#include "rtw8723x.h"
extern const struct rtw_chip_info rtw8723d_hw_spec;
/* phy status page0 */
#define GET_PHY_STAT_P0_PWDB(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(15, 8))
/* phy status page1 */
#define GET_PHY_STAT_P1_PWDB_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(15, 8))
#define GET_PHY_STAT_P1_PWDB_B(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(23, 16))
#define GET_PHY_STAT_P1_RF_MODE(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x03), GENMASK(29, 28))
#define GET_PHY_STAT_P1_L_RXSC(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(11, 8))
#define GET_PHY_STAT_P1_HT_RXSC(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(15, 12))
#define GET_PHY_STAT_P1_RXEVM_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(7, 0))
#define GET_PHY_STAT_P1_CFO_TAIL_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(7, 0))
#define GET_PHY_STAT_P1_RXSNR_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(7, 0))
#define RTW_DEF_OFDM_SWING_INDEX 28
#define RTW_DEF_CCK_SWING_INDEX 28
#define CCK_DFIR_NR 3
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW8723D_TABLE_H__
#define __RTW8723D_TABLE_H__
extern const struct rtw_table rtw8723d_mac_tbl;
extern const struct rtw_table rtw8723d_agc_tbl;
extern const struct rtw_table rtw8723d_bb_tbl;
extern const struct rtw_table rtw8723d_bb_pg_tbl;
extern const struct rtw_table rtw8723d_rf_a_tbl;
extern const struct rtw_table rtw8723d_txpwr_lmt_tbl;
#endif
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/pci.h>
#include "pci.h"
#include "rtw8723d.h"
static const struct pci_device_id rtw_8723de_id_table[] = {
{
PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xD723),
.driver_data = (kernel_ulong_t)&rtw8723d_hw_spec
},
{}
};
MODULE_DEVICE_TABLE(pci, rtw_8723de_id_table);
static struct pci_driver rtw_8723de_driver = {
.name = KBUILD_MODNAME,
.id_table = rtw_8723de_id_table,
.probe = rtw_pci_probe,
.remove = rtw_pci_remove,
.driver.pm = &rtw_pm_ops,
.shutdown = rtw_pci_shutdown,
.err_handler = &rtw_pci_err_handler,
};
module_pci_driver(rtw_8723de_driver);
MODULE_AUTHOR("Realtek Corporation");
MODULE_DESCRIPTION("Realtek 802.11n wireless 8723de driver");
MODULE_LICENSE("Dual BSD/GPL");
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) Martin Blumenstingl <martin.blumenstingl@googlemail.com>
*/
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/module.h>
#include "main.h"
#include "rtw8723d.h"
#include "sdio.h"
static const struct sdio_device_id rtw_8723ds_id_table[] = {
{
SDIO_DEVICE(SDIO_VENDOR_ID_REALTEK,
SDIO_DEVICE_ID_REALTEK_RTW8723DS_1ANT),
.driver_data = (kernel_ulong_t)&rtw8723d_hw_spec,
},
{
SDIO_DEVICE(SDIO_VENDOR_ID_REALTEK,
SDIO_DEVICE_ID_REALTEK_RTW8723DS_2ANT),
.driver_data = (kernel_ulong_t)&rtw8723d_hw_spec,
},
{}
};
MODULE_DEVICE_TABLE(sdio, rtw_8723ds_id_table);
static struct sdio_driver rtw_8723ds_driver = {
.name = KBUILD_MODNAME,
.probe = rtw_sdio_probe,
.remove = rtw_sdio_remove,
.shutdown = rtw_sdio_shutdown,
.id_table = rtw_8723ds_id_table,
.drv = {
.pm = &rtw_sdio_pm_ops,
}
};
module_sdio_driver(rtw_8723ds_driver);
MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
MODULE_DESCRIPTION("Realtek 802.11n wireless 8723ds driver");
MODULE_LICENSE("Dual BSD/GPL");
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/usb.h>
#include "main.h"
#include "rtw8723d.h"
#include "usb.h"
static const struct usb_device_id rtw_8723du_id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xd723, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8723d_hw_spec) }, /* 8723DU 1*1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xd611, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8723d_hw_spec) }, /* Edimax EW-7611ULB V2 */
{ },
};
MODULE_DEVICE_TABLE(usb, rtw_8723du_id_table);
static int rtw8723du_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return rtw_usb_probe(intf, id);
}
static struct usb_driver rtw_8723du_driver = {
.name = KBUILD_MODNAME,
.id_table = rtw_8723du_id_table,
.probe = rtw8723du_probe,
.disconnect = rtw_usb_disconnect,
};
module_usb_driver(rtw_8723du_driver);
MODULE_AUTHOR("Hans Ulli Kroll <linux@ulli-kroll.de>");
MODULE_DESCRIPTION("Realtek 802.11n wireless 8723du driver");
MODULE_LICENSE("Dual BSD/GPL");
@@ -0,0 +1,788 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright 2024 Fiona Klute
*
* Based on code originally in rtw8723d.[ch],
* Copyright(c) 2018-2019 Realtek Corporation
*/
#include "main.h"
#include "debug.h"
#include "phy.h"
#include "reg.h"
#include "tx.h"
#include "rtw8723x.h"
static const struct rtw_hw_reg rtw8723x_txagc[] = {
[DESC_RATE1M] = { .addr = 0xe08, .mask = 0x0000ff00 },
[DESC_RATE2M] = { .addr = 0x86c, .mask = 0x0000ff00 },
[DESC_RATE5_5M] = { .addr = 0x86c, .mask = 0x00ff0000 },
[DESC_RATE11M] = { .addr = 0x86c, .mask = 0xff000000 },
[DESC_RATE6M] = { .addr = 0xe00, .mask = 0x000000ff },
[DESC_RATE9M] = { .addr = 0xe00, .mask = 0x0000ff00 },
[DESC_RATE12M] = { .addr = 0xe00, .mask = 0x00ff0000 },
[DESC_RATE18M] = { .addr = 0xe00, .mask = 0xff000000 },
[DESC_RATE24M] = { .addr = 0xe04, .mask = 0x000000ff },
[DESC_RATE36M] = { .addr = 0xe04, .mask = 0x0000ff00 },
[DESC_RATE48M] = { .addr = 0xe04, .mask = 0x00ff0000 },
[DESC_RATE54M] = { .addr = 0xe04, .mask = 0xff000000 },
[DESC_RATEMCS0] = { .addr = 0xe10, .mask = 0x000000ff },
[DESC_RATEMCS1] = { .addr = 0xe10, .mask = 0x0000ff00 },
[DESC_RATEMCS2] = { .addr = 0xe10, .mask = 0x00ff0000 },
[DESC_RATEMCS3] = { .addr = 0xe10, .mask = 0xff000000 },
[DESC_RATEMCS4] = { .addr = 0xe14, .mask = 0x000000ff },
[DESC_RATEMCS5] = { .addr = 0xe14, .mask = 0x0000ff00 },
[DESC_RATEMCS6] = { .addr = 0xe14, .mask = 0x00ff0000 },
[DESC_RATEMCS7] = { .addr = 0xe14, .mask = 0xff000000 },
};
static void __rtw8723x_lck(struct rtw_dev *rtwdev)
{
u32 lc_cal;
u8 val_ctx, rf_val;
int ret;
val_ctx = rtw_read8(rtwdev, REG_CTX);
if ((val_ctx & BIT_MASK_CTX_TYPE) != 0)
rtw_write8(rtwdev, REG_CTX, val_ctx & ~BIT_MASK_CTX_TYPE);
else
rtw_write8(rtwdev, REG_TXPAUSE, 0xFF);
lc_cal = rtw_read_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK);
rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK, lc_cal | BIT_LCK);
ret = read_poll_timeout(rtw_read_rf, rf_val, rf_val != 0x1,
10000, 1000000, false,
rtwdev, RF_PATH_A, RF_CFGCH, BIT_LCK);
if (ret)
rtw_warn(rtwdev, "failed to poll LCK status bit\n");
rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK, lc_cal);
if ((val_ctx & BIT_MASK_CTX_TYPE) != 0)
rtw_write8(rtwdev, REG_CTX, val_ctx);
else
rtw_write8(rtwdev, REG_TXPAUSE, 0x00);
}
#define DBG_EFUSE_VAL(rtwdev, map, name) \
rtw_dbg(rtwdev, RTW_DBG_EFUSE, # name "=0x%02x\n", \
(map)->name)
#define DBG_EFUSE_2BYTE(rtwdev, map, name) \
rtw_dbg(rtwdev, RTW_DBG_EFUSE, # name "=0x%02x%02x\n", \
(map)->name[0], (map)->name[1])
#define DBG_EFUSE_FIX(rtwdev, name) \
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "Fixed invalid EFUSE value: " \
# name "=0x%x\n", rtwdev->efuse.name)
static void rtw8723xe_efuse_debug(struct rtw_dev *rtwdev,
struct rtw8723x_efuse *map)
{
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "mac_addr=%pM\n", map->e.mac_addr);
DBG_EFUSE_2BYTE(rtwdev, map, e.vendor_id);
DBG_EFUSE_2BYTE(rtwdev, map, e.device_id);
DBG_EFUSE_2BYTE(rtwdev, map, e.sub_vendor_id);
DBG_EFUSE_2BYTE(rtwdev, map, e.sub_device_id);
}
static void rtw8723xu_efuse_debug(struct rtw_dev *rtwdev,
struct rtw8723x_efuse *map)
{
DBG_EFUSE_2BYTE(rtwdev, map, u.vendor_id);
DBG_EFUSE_2BYTE(rtwdev, map, u.product_id);
DBG_EFUSE_VAL(rtwdev, map, u.usb_option);
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "mac_addr=%pM\n", map->u.mac_addr);
}
static void rtw8723xs_efuse_debug(struct rtw_dev *rtwdev,
struct rtw8723x_efuse *map)
{
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "mac_addr=%pM\n", map->s.mac_addr);
}
static void __rtw8723x_debug_txpwr_limit(struct rtw_dev *rtwdev,
struct rtw_txpwr_idx *table,
int tx_path_count)
{
if (!rtw_dbg_is_enabled(rtwdev, RTW_DBG_EFUSE))
return;
rtw_dbg(rtwdev, RTW_DBG_EFUSE,
"Power index table (2.4G):\n");
/* CCK base */
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "CCK base\n");
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "RF G0 G1 G2 G3 G4 G5\n");
for (int i = 0; i < tx_path_count; i++)
rtw_dbg(rtwdev, RTW_DBG_EFUSE,
"[%c]: %3u %3u %3u %3u %3u %3u\n",
'A' + i,
table[i].pwr_idx_2g.cck_base[0],
table[i].pwr_idx_2g.cck_base[1],
table[i].pwr_idx_2g.cck_base[2],
table[i].pwr_idx_2g.cck_base[3],
table[i].pwr_idx_2g.cck_base[4],
table[i].pwr_idx_2g.cck_base[5]);
/* CCK diff */
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "CCK diff\n");
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "RF 1S 2S 3S 4S\n");
for (int i = 0; i < tx_path_count; i++)
rtw_dbg(rtwdev, RTW_DBG_EFUSE,
"[%c]: %2d %2d %2d %2d\n",
'A' + i, 0 /* no diff for 1S */,
table[i].pwr_idx_2g.ht_2s_diff.cck,
table[i].pwr_idx_2g.ht_3s_diff.cck,
table[i].pwr_idx_2g.ht_4s_diff.cck);
/* BW40-1S base */
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "BW40-1S base\n");
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "RF G0 G1 G2 G3 G4\n");
for (int i = 0; i < tx_path_count; i++)
rtw_dbg(rtwdev, RTW_DBG_EFUSE,
"[%c]: %3u %3u %3u %3u %3u\n",
'A' + i,
table[i].pwr_idx_2g.bw40_base[0],
table[i].pwr_idx_2g.bw40_base[1],
table[i].pwr_idx_2g.bw40_base[2],
table[i].pwr_idx_2g.bw40_base[3],
table[i].pwr_idx_2g.bw40_base[4]);
/* OFDM diff */
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "OFDM diff\n");
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "RF 1S 2S 3S 4S\n");
for (int i = 0; i < tx_path_count; i++)
rtw_dbg(rtwdev, RTW_DBG_EFUSE,
"[%c]: %2d %2d %2d %2d\n",
'A' + i,
table[i].pwr_idx_2g.ht_1s_diff.ofdm,
table[i].pwr_idx_2g.ht_2s_diff.ofdm,
table[i].pwr_idx_2g.ht_3s_diff.ofdm,
table[i].pwr_idx_2g.ht_4s_diff.ofdm);
/* BW20 diff */
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "BW20 diff\n");
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "RF 1S 2S 3S 4S\n");
for (int i = 0; i < tx_path_count; i++)
rtw_dbg(rtwdev, RTW_DBG_EFUSE,
"[%c]: %2d %2d %2d %2d\n",
'A' + i,
table[i].pwr_idx_2g.ht_1s_diff.bw20,
table[i].pwr_idx_2g.ht_2s_diff.bw20,
table[i].pwr_idx_2g.ht_3s_diff.bw20,
table[i].pwr_idx_2g.ht_4s_diff.bw20);
/* BW40 diff */
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "BW40 diff\n");
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "RF 1S 2S 3S 4S\n");
for (int i = 0; i < tx_path_count; i++)
rtw_dbg(rtwdev, RTW_DBG_EFUSE,
"[%c]: %2d %2d %2d %2d\n",
'A' + i, 0 /* no diff for 1S */,
table[i].pwr_idx_2g.ht_2s_diff.bw40,
table[i].pwr_idx_2g.ht_3s_diff.bw40,
table[i].pwr_idx_2g.ht_4s_diff.bw40);
}
static void efuse_debug_dump(struct rtw_dev *rtwdev,
struct rtw8723x_efuse *map)
{
if (!rtw_dbg_is_enabled(rtwdev, RTW_DBG_EFUSE))
return;
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "EFUSE raw logical map:\n");
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1,
(u8 *)map, sizeof(struct rtw8723x_efuse), false);
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "Parsed rtw8723x EFUSE data:\n");
DBG_EFUSE_VAL(rtwdev, map, rtl_id);
DBG_EFUSE_VAL(rtwdev, map, afe);
rtw8723x_debug_txpwr_limit(rtwdev, map->txpwr_idx_table, 4);
DBG_EFUSE_VAL(rtwdev, map, channel_plan);
DBG_EFUSE_VAL(rtwdev, map, xtal_k);
DBG_EFUSE_VAL(rtwdev, map, thermal_meter);
DBG_EFUSE_VAL(rtwdev, map, iqk_lck);
DBG_EFUSE_VAL(rtwdev, map, pa_type);
DBG_EFUSE_2BYTE(rtwdev, map, lna_type_2g);
DBG_EFUSE_2BYTE(rtwdev, map, lna_type_5g);
DBG_EFUSE_VAL(rtwdev, map, rf_board_option);
DBG_EFUSE_VAL(rtwdev, map, rf_feature_option);
DBG_EFUSE_VAL(rtwdev, map, rf_bt_setting);
DBG_EFUSE_VAL(rtwdev, map, eeprom_version);
DBG_EFUSE_VAL(rtwdev, map, eeprom_customer_id);
DBG_EFUSE_VAL(rtwdev, map, tx_bb_swing_setting_2g);
DBG_EFUSE_VAL(rtwdev, map, tx_pwr_calibrate_rate);
DBG_EFUSE_VAL(rtwdev, map, rf_antenna_option);
DBG_EFUSE_VAL(rtwdev, map, rfe_option);
DBG_EFUSE_2BYTE(rtwdev, map, country_code);
switch (rtw_hci_type(rtwdev)) {
case RTW_HCI_TYPE_PCIE:
rtw8723xe_efuse_debug(rtwdev, map);
break;
case RTW_HCI_TYPE_USB:
rtw8723xu_efuse_debug(rtwdev, map);
break;
case RTW_HCI_TYPE_SDIO:
rtw8723xs_efuse_debug(rtwdev, map);
break;
default:
/* unsupported now */
break;
}
}
static void rtw8723xe_efuse_parsing(struct rtw_efuse *efuse,
struct rtw8723x_efuse *map)
{
ether_addr_copy(efuse->addr, map->e.mac_addr);
}
static void rtw8723xu_efuse_parsing(struct rtw_efuse *efuse,
struct rtw8723x_efuse *map)
{
ether_addr_copy(efuse->addr, map->u.mac_addr);
}
static void rtw8723xs_efuse_parsing(struct rtw_efuse *efuse,
struct rtw8723x_efuse *map)
{
ether_addr_copy(efuse->addr, map->s.mac_addr);
}
/* Default power index table for RTL8703B/RTL8723D, used if EFUSE does
* not contain valid data. Replaces EFUSE data from offset 0x10 (start
* of txpwr_idx_table).
*/
static const u8 rtw8723x_txpwr_idx_table[] = {
0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D,
0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02
};
static int __rtw8723x_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
{
struct rtw_efuse *efuse = &rtwdev->efuse;
u8 *pwr = (u8 *)efuse->txpwr_idx_table;
struct rtw8723x_efuse *map;
bool valid = false;
int i;
map = (struct rtw8723x_efuse *)log_map;
efuse_debug_dump(rtwdev, map);
efuse->rfe_option = 0;
efuse->rf_board_option = map->rf_board_option;
efuse->crystal_cap = map->xtal_k;
efuse->pa_type_2g = map->pa_type;
efuse->lna_type_2g = map->lna_type_2g[0];
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 & 0x7;
efuse->thermal_meter[0] = map->thermal_meter;
efuse->thermal_meter_k = map->thermal_meter;
efuse->afe = map->afe;
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_PCIE:
rtw8723xe_efuse_parsing(efuse, map);
break;
case RTW_HCI_TYPE_USB:
rtw8723xu_efuse_parsing(efuse, map);
break;
case RTW_HCI_TYPE_SDIO:
rtw8723xs_efuse_parsing(efuse, map);
break;
default:
/* unsupported now */
return -EOPNOTSUPP;
}
/* If TX power index table in EFUSE is invalid, fall back to
* built-in table.
*/
for (i = 0; i < ARRAY_SIZE(rtw8723x_txpwr_idx_table); i++)
if (pwr[i] != 0xff) {
valid = true;
break;
}
if (!valid) {
for (i = 0; i < ARRAY_SIZE(rtw8723x_txpwr_idx_table); i++)
pwr[i] = rtw8723x_txpwr_idx_table[i];
rtw_dbg(rtwdev, RTW_DBG_EFUSE,
"Replaced invalid EFUSE TX power index table.");
rtw8723x_debug_txpwr_limit(rtwdev,
efuse->txpwr_idx_table, 2);
}
/* Override invalid antenna settings. */
if (efuse->bt_setting == 0xff) {
/* shared antenna */
efuse->bt_setting |= BIT(0);
/* RF path A */
efuse->bt_setting &= ~BIT(6);
DBG_EFUSE_FIX(rtwdev, bt_setting);
}
/* Override invalid board options: The coex code incorrectly
* assumes that if bits 6 & 7 are set the board doesn't
* support coex. Regd is also derived from rf_board_option and
* should be 0 if there's no valid data.
*/
if (efuse->rf_board_option == 0xff) {
efuse->regd = 0;
efuse->rf_board_option &= GENMASK(5, 0);
DBG_EFUSE_FIX(rtwdev, rf_board_option);
}
/* Override invalid crystal cap setting, default comes from
* vendor driver. Chip specific.
*/
if (efuse->crystal_cap == 0xff) {
efuse->crystal_cap = 0x20;
DBG_EFUSE_FIX(rtwdev, crystal_cap);
}
return 0;
}
#define BIT_CFENDFORM BIT(9)
#define BIT_WMAC_TCR_ERR0 BIT(12)
#define BIT_WMAC_TCR_ERR1 BIT(13)
#define BIT_TCR_CFG (BIT_CFENDFORM | BIT_WMAC_TCR_ERR0 | \
BIT_WMAC_TCR_ERR1)
#define WLAN_RX_FILTER0 0xFFFF
#define WLAN_RX_FILTER1 0x400
#define WLAN_RX_FILTER2 0xFFFF
#define WLAN_RCR_CFG 0x700060CE
static int __rtw8723x_mac_init(struct rtw_dev *rtwdev)
{
rtw_write32(rtwdev, REG_TCR, BIT_TCR_CFG);
rtw_write16(rtwdev, REG_RXFLTMAP0, WLAN_RX_FILTER0);
rtw_write16(rtwdev, REG_RXFLTMAP1, WLAN_RX_FILTER1);
rtw_write16(rtwdev, REG_RXFLTMAP2, WLAN_RX_FILTER2);
rtw_write32(rtwdev, REG_RCR, WLAN_RCR_CFG);
rtw_write32(rtwdev, REG_INT_MIG, 0);
rtw_write32(rtwdev, REG_MCUTST_1, 0x0);
rtw_write8(rtwdev, REG_MISC_CTRL, BIT_DIS_SECOND_CCA);
rtw_write8(rtwdev, REG_2ND_CCA_CTRL, 0);
return 0;
}
static int __rtw8723x_mac_postinit(struct rtw_dev *rtwdev)
{
rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL + 1, WLAN_TXQ_RPT_EN);
return 0;
}
static void __rtw8723x_cfg_ldo25(struct rtw_dev *rtwdev, bool enable)
{
u8 ldo_pwr;
ldo_pwr = rtw_read8(rtwdev, REG_LDO_EFUSE_CTRL + 3);
if (enable) {
ldo_pwr &= ~BIT_MASK_LDO25_VOLTAGE;
ldo_pwr |= (BIT_LDO25_VOLTAGE_V25 << 4) | BIT_LDO25_EN;
} else {
ldo_pwr &= ~BIT_LDO25_EN;
}
rtw_write8(rtwdev, REG_LDO_EFUSE_CTRL + 3, ldo_pwr);
}
static void
rtw8723x_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs)
{
struct rtw_hal *hal = &rtwdev->hal;
const struct rtw_hw_reg *txagc;
u8 rate, pwr_index;
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];
if (rate >= ARRAY_SIZE(rtw8723x_txagc)) {
rtw_warn(rtwdev, "rate 0x%x isn't supported\n", rate);
continue;
}
txagc = &rtw8723x_txagc[rate];
if (!txagc->addr) {
rtw_warn(rtwdev, "rate 0x%x isn't defined\n", rate);
continue;
}
rtw_write32_mask(rtwdev, txagc->addr, txagc->mask, pwr_index);
}
}
static void __rtw8723x_set_tx_power_index(struct rtw_dev *rtwdev)
{
struct rtw_hal *hal = &rtwdev->hal;
int rs, path;
for (path = 0; path < hal->rf_path_num; path++) {
for (rs = 0; rs <= RTW_RATE_SECTION_HT_1S; rs++)
rtw8723x_set_tx_power_index_by_rate(rtwdev, path, rs);
}
}
static void __rtw8723x_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);
}
}
static void __rtw8723x_false_alarm_statistics(struct rtw_dev *rtwdev)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
u32 cck_fa_cnt;
u32 ofdm_fa_cnt;
u32 crc32_cnt;
u32 val32;
/* hold counter */
rtw_write32_mask(rtwdev, REG_OFDM_FA_HOLDC_11N, BIT_MASK_OFDM_FA_KEEP, 1);
rtw_write32_mask(rtwdev, REG_OFDM_FA_RSTD_11N, BIT_MASK_OFDM_FA_KEEP1, 1);
rtw_write32_mask(rtwdev, REG_CCK_FA_RST_11N, BIT_MASK_CCK_CNT_KEEP, 1);
rtw_write32_mask(rtwdev, REG_CCK_FA_RST_11N, BIT_MASK_CCK_FA_KEEP, 1);
cck_fa_cnt = rtw_read32_mask(rtwdev, REG_CCK_FA_LSB_11N, MASKBYTE0);
cck_fa_cnt += rtw_read32_mask(rtwdev, REG_CCK_FA_MSB_11N, MASKBYTE3) << 8;
val32 = rtw_read32(rtwdev, REG_OFDM_FA_TYPE1_11N);
ofdm_fa_cnt = u32_get_bits(val32, BIT_MASK_OFDM_FF_CNT);
ofdm_fa_cnt += u32_get_bits(val32, BIT_MASK_OFDM_SF_CNT);
val32 = rtw_read32(rtwdev, REG_OFDM_FA_TYPE2_11N);
dm_info->ofdm_cca_cnt = u32_get_bits(val32, BIT_MASK_OFDM_CCA_CNT);
ofdm_fa_cnt += u32_get_bits(val32, BIT_MASK_OFDM_PF_CNT);
val32 = rtw_read32(rtwdev, REG_OFDM_FA_TYPE3_11N);
ofdm_fa_cnt += u32_get_bits(val32, BIT_MASK_OFDM_RI_CNT);
ofdm_fa_cnt += u32_get_bits(val32, BIT_MASK_OFDM_CRC_CNT);
val32 = rtw_read32(rtwdev, REG_OFDM_FA_TYPE4_11N);
ofdm_fa_cnt += u32_get_bits(val32, BIT_MASK_OFDM_MNS_CNT);
dm_info->cck_fa_cnt = cck_fa_cnt;
dm_info->ofdm_fa_cnt = ofdm_fa_cnt;
dm_info->total_fa_cnt = cck_fa_cnt + ofdm_fa_cnt;
dm_info->cck_err_cnt = rtw_read32(rtwdev, REG_IGI_C_11N);
dm_info->cck_ok_cnt = rtw_read32(rtwdev, REG_IGI_D_11N);
crc32_cnt = rtw_read32(rtwdev, REG_OFDM_CRC32_CNT_11N);
dm_info->ofdm_err_cnt = u32_get_bits(crc32_cnt, BIT_MASK_OFDM_LCRC_ERR);
dm_info->ofdm_ok_cnt = u32_get_bits(crc32_cnt, BIT_MASK_OFDM_LCRC_OK);
crc32_cnt = rtw_read32(rtwdev, REG_HT_CRC32_CNT_11N);
dm_info->ht_err_cnt = u32_get_bits(crc32_cnt, BIT_MASK_HT_CRC_ERR);
dm_info->ht_ok_cnt = u32_get_bits(crc32_cnt, BIT_MASK_HT_CRC_OK);
dm_info->vht_err_cnt = 0;
dm_info->vht_ok_cnt = 0;
val32 = rtw_read32(rtwdev, REG_CCK_CCA_CNT_11N);
dm_info->cck_cca_cnt = (u32_get_bits(val32, BIT_MASK_CCK_FA_MSB) << 8) |
u32_get_bits(val32, BIT_MASK_CCK_FA_LSB);
dm_info->total_cca_cnt = dm_info->cck_cca_cnt + dm_info->ofdm_cca_cnt;
/* reset counter */
rtw_write32_mask(rtwdev, REG_OFDM_FA_RSTC_11N, BIT_MASK_OFDM_FA_RST, 1);
rtw_write32_mask(rtwdev, REG_OFDM_FA_RSTC_11N, BIT_MASK_OFDM_FA_RST, 0);
rtw_write32_mask(rtwdev, REG_OFDM_FA_RSTD_11N, BIT_MASK_OFDM_FA_RST1, 1);
rtw_write32_mask(rtwdev, REG_OFDM_FA_RSTD_11N, BIT_MASK_OFDM_FA_RST1, 0);
rtw_write32_mask(rtwdev, REG_OFDM_FA_HOLDC_11N, BIT_MASK_OFDM_FA_KEEP, 0);
rtw_write32_mask(rtwdev, REG_OFDM_FA_RSTD_11N, BIT_MASK_OFDM_FA_KEEP1, 0);
rtw_write32_mask(rtwdev, REG_CCK_FA_RST_11N, BIT_MASK_CCK_CNT_KPEN, 0);
rtw_write32_mask(rtwdev, REG_CCK_FA_RST_11N, BIT_MASK_CCK_CNT_KPEN, 2);
rtw_write32_mask(rtwdev, REG_CCK_FA_RST_11N, BIT_MASK_CCK_FA_KPEN, 0);
rtw_write32_mask(rtwdev, REG_CCK_FA_RST_11N, BIT_MASK_CCK_FA_KPEN, 2);
rtw_write32_mask(rtwdev, REG_PAGE_F_RST_11N, BIT_MASK_F_RST_ALL, 1);
rtw_write32_mask(rtwdev, REG_PAGE_F_RST_11N, BIT_MASK_F_RST_ALL, 0);
}
/* IQK (IQ calibration) */
static
void __rtw8723x_iqk_backup_regs(struct rtw_dev *rtwdev,
struct rtw8723x_iqk_backup_regs *backup)
{
int i;
for (i = 0; i < RTW8723X_IQK_ADDA_REG_NUM; i++)
backup->adda[i] = rtw_read32(rtwdev,
rtw8723x_common.iqk_adda_regs[i]);
for (i = 0; i < RTW8723X_IQK_MAC8_REG_NUM; i++)
backup->mac8[i] = rtw_read8(rtwdev,
rtw8723x_common.iqk_mac8_regs[i]);
for (i = 0; i < RTW8723X_IQK_MAC32_REG_NUM; i++)
backup->mac32[i] = rtw_read32(rtwdev,
rtw8723x_common.iqk_mac32_regs[i]);
for (i = 0; i < RTW8723X_IQK_BB_REG_NUM; i++)
backup->bb[i] = rtw_read32(rtwdev,
rtw8723x_common.iqk_bb_regs[i]);
backup->igia = rtw_read32_mask(rtwdev, REG_OFDM0_XAAGC1, MASKBYTE0);
backup->igib = rtw_read32_mask(rtwdev, REG_OFDM0_XBAGC1, MASKBYTE0);
backup->bb_sel_btg = rtw_read32(rtwdev, REG_BB_SEL_BTG);
}
static
void __rtw8723x_iqk_restore_regs(struct rtw_dev *rtwdev,
const struct rtw8723x_iqk_backup_regs *backup)
{
int i;
for (i = 0; i < RTW8723X_IQK_ADDA_REG_NUM; i++)
rtw_write32(rtwdev, rtw8723x_common.iqk_adda_regs[i],
backup->adda[i]);
for (i = 0; i < RTW8723X_IQK_MAC8_REG_NUM; i++)
rtw_write8(rtwdev, rtw8723x_common.iqk_mac8_regs[i],
backup->mac8[i]);
for (i = 0; i < RTW8723X_IQK_MAC32_REG_NUM; i++)
rtw_write32(rtwdev, rtw8723x_common.iqk_mac32_regs[i],
backup->mac32[i]);
for (i = 0; i < RTW8723X_IQK_BB_REG_NUM; i++)
rtw_write32(rtwdev, rtw8723x_common.iqk_bb_regs[i],
backup->bb[i]);
rtw_write32_mask(rtwdev, REG_OFDM0_XAAGC1, MASKBYTE0, 0x50);
rtw_write32_mask(rtwdev, REG_OFDM0_XAAGC1, MASKBYTE0, backup->igia);
rtw_write32_mask(rtwdev, REG_OFDM0_XBAGC1, MASKBYTE0, 0x50);
rtw_write32_mask(rtwdev, REG_OFDM0_XBAGC1, MASKBYTE0, backup->igib);
rtw_write32(rtwdev, REG_TXIQK_TONE_A_11N, 0x01008c00);
rtw_write32(rtwdev, REG_RXIQK_TONE_A_11N, 0x01008c00);
}
static
bool __rtw8723x_iqk_similarity_cmp(struct rtw_dev *rtwdev,
s32 result[][IQK_NR],
u8 c1, u8 c2)
{
u32 i, j, diff;
u32 bitmap = 0;
u8 candidate[PATH_NR] = {IQK_ROUND_INVALID, IQK_ROUND_INVALID};
bool ret = true;
s32 tmp1, tmp2;
for (i = 0; i < IQK_NR; i++) {
tmp1 = iqkxy_to_s32(result[c1][i]);
tmp2 = iqkxy_to_s32(result[c2][i]);
diff = abs(tmp1 - tmp2);
if (diff <= MAX_TOLERANCE)
continue;
if ((i == IQK_S1_RX_X || i == IQK_S0_RX_X) && !bitmap) {
if (result[c1][i] + result[c1][i + 1] == 0)
candidate[i / IQK_SX_NR] = c2;
else if (result[c2][i] + result[c2][i + 1] == 0)
candidate[i / IQK_SX_NR] = c1;
else
bitmap |= BIT(i);
} else {
bitmap |= BIT(i);
}
}
if (bitmap != 0)
goto check_sim;
for (i = 0; i < PATH_NR; i++) {
if (candidate[i] == IQK_ROUND_INVALID)
continue;
for (j = i * IQK_SX_NR; j < i * IQK_SX_NR + 2; j++)
result[IQK_ROUND_HYBRID][j] = result[candidate[i]][j];
ret = false;
}
return ret;
check_sim:
for (i = 0; i < IQK_NR; i++) {
j = i & ~1; /* 2 bits are a pair for IQ[X, Y] */
if (bitmap & GENMASK(j + 1, j))
continue;
result[IQK_ROUND_HYBRID][i] = result[c1][i];
}
return false;
}
static u8 __rtw8723x_pwrtrack_get_limit_ofdm(struct rtw_dev *rtwdev)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
u8 tx_rate = dm_info->tx_rate;
u8 limit_ofdm = 30;
switch (tx_rate) {
case DESC_RATE1M...DESC_RATE5_5M:
case DESC_RATE11M:
break;
case DESC_RATE6M...DESC_RATE48M:
limit_ofdm = 36;
break;
case DESC_RATE54M:
limit_ofdm = 34;
break;
case DESC_RATEMCS0...DESC_RATEMCS2:
limit_ofdm = 38;
break;
case DESC_RATEMCS3...DESC_RATEMCS4:
limit_ofdm = 36;
break;
case DESC_RATEMCS5...DESC_RATEMCS7:
limit_ofdm = 34;
break;
default:
rtw_warn(rtwdev, "pwrtrack unhandled tx_rate 0x%x\n", tx_rate);
break;
}
return limit_ofdm;
}
static
void __rtw8723x_pwrtrack_set_xtal(struct rtw_dev *rtwdev, u8 therm_path,
u8 delta)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
const struct rtw_rfe_def *rfe_def = rtw_get_rfe_def(rtwdev);
const struct rtw_pwr_track_tbl *tbl = rfe_def->pwr_track_tbl;
const s8 *pwrtrk_xtal;
s8 xtal_cap;
if (dm_info->thermal_avg[therm_path] >
rtwdev->efuse.thermal_meter[therm_path])
pwrtrk_xtal = tbl->pwrtrk_xtal_p;
else
pwrtrk_xtal = tbl->pwrtrk_xtal_n;
xtal_cap = rtwdev->efuse.crystal_cap & 0x3F;
xtal_cap = clamp_t(s8, xtal_cap + pwrtrk_xtal[delta], 0, 0x3F);
rtw_write32_mask(rtwdev, REG_AFE_CTRL3, BIT_MASK_XTAL,
xtal_cap | (xtal_cap << 6));
}
static
void __rtw8723x_fill_txdesc_checksum(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *txdesc)
{
size_t words = 32 / 2; /* calculate the first 32 bytes (16 words) */
__le16 chksum = 0;
__le16 *data = (__le16 *)(txdesc);
struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)txdesc;
le32p_replace_bits(&tx_desc->w7, 0, RTW_TX_DESC_W7_TXDESC_CHECKSUM);
while (words--)
chksum ^= *data++;
chksum = ~chksum;
le32p_replace_bits(&tx_desc->w7, __le16_to_cpu(chksum),
RTW_TX_DESC_W7_TXDESC_CHECKSUM);
}
static void __rtw8723x_coex_cfg_init(struct rtw_dev *rtwdev)
{
/* enable TBTT nterrupt */
rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION);
/* BT report packet sample rate */
/* 0x790[5:0]=0x5 */
rtw_write8_mask(rtwdev, REG_BT_TDMA_TIME, BIT_MASK_SAMPLE_RATE, 0x5);
/* enable BT counter statistics */
rtw_write8(rtwdev, REG_BT_STAT_CTRL, 0x1);
/* enable PTA (3-wire function form BT side) */
rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_PTA_EN);
rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_PO_BT_PTA_PINS);
/* enable PTA (tx/rx signal form WiFi side) */
rtw_write8_set(rtwdev, REG_QUEUE_CTRL, BIT_PTA_WL_TX_EN);
}
const struct rtw8723x_common rtw8723x_common = {
.iqk_adda_regs = {
0x85c, 0xe6c, 0xe70, 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84,
0xe88, 0xe8c, 0xed0, 0xed4, 0xed8, 0xedc, 0xee0, 0xeec
},
.iqk_mac8_regs = {0x522, 0x550, 0x551},
.iqk_mac32_regs = {0x40},
.iqk_bb_regs = {
0xc04, 0xc08, 0x874, 0xb68, 0xb6c, 0x870, 0x860, 0x864, 0xa04
},
.ltecoex_addr = {
.ctrl = REG_LTECOEX_CTRL,
.wdata = REG_LTECOEX_WRITE_DATA,
.rdata = REG_LTECOEX_READ_DATA,
},
.rf_sipi_addr = {
[RF_PATH_A] = { .hssi_1 = 0x820, .lssi_read = 0x8a0,
.hssi_2 = 0x824, .lssi_read_pi = 0x8b8},
[RF_PATH_B] = { .hssi_1 = 0x828, .lssi_read = 0x8a4,
.hssi_2 = 0x82c, .lssi_read_pi = 0x8bc},
},
.dig = {
[0] = { .addr = 0xc50, .mask = 0x7f },
[1] = { .addr = 0xc50, .mask = 0x7f },
},
.dig_cck = {
[0] = { .addr = 0xa0c, .mask = 0x3f00 },
},
.prioq_addrs = {
.prio[RTW_DMA_MAPPING_EXTRA] = {
.rsvd = REG_RQPN_NPQ + 2, .avail = REG_RQPN_NPQ + 3,
},
.prio[RTW_DMA_MAPPING_LOW] = {
.rsvd = REG_RQPN + 1, .avail = REG_FIFOPAGE_CTRL_2 + 1,
},
.prio[RTW_DMA_MAPPING_NORMAL] = {
.rsvd = REG_RQPN_NPQ, .avail = REG_RQPN_NPQ + 1,
},
.prio[RTW_DMA_MAPPING_HIGH] = {
.rsvd = REG_RQPN, .avail = REG_FIFOPAGE_CTRL_2,
},
.wsize = false,
},
.lck = __rtw8723x_lck,
.read_efuse = __rtw8723x_read_efuse,
.mac_init = __rtw8723x_mac_init,
.mac_postinit = __rtw8723x_mac_postinit,
.cfg_ldo25 = __rtw8723x_cfg_ldo25,
.set_tx_power_index = __rtw8723x_set_tx_power_index,
.efuse_grant = __rtw8723x_efuse_grant,
.false_alarm_statistics = __rtw8723x_false_alarm_statistics,
.iqk_backup_regs = __rtw8723x_iqk_backup_regs,
.iqk_restore_regs = __rtw8723x_iqk_restore_regs,
.iqk_similarity_cmp = __rtw8723x_iqk_similarity_cmp,
.pwrtrack_get_limit_ofdm = __rtw8723x_pwrtrack_get_limit_ofdm,
.pwrtrack_set_xtal = __rtw8723x_pwrtrack_set_xtal,
.coex_cfg_init = __rtw8723x_coex_cfg_init,
.fill_txdesc_checksum = __rtw8723x_fill_txdesc_checksum,
.debug_txpwr_limit = __rtw8723x_debug_txpwr_limit,
};
EXPORT_SYMBOL(rtw8723x_common);
MODULE_AUTHOR("Realtek Corporation");
MODULE_AUTHOR("Fiona Klute <fiona.klute@gmx.de>");
MODULE_DESCRIPTION("Common functions for Realtek 802.11n wireless 8723x drivers");
MODULE_LICENSE("Dual BSD/GPL");
@@ -0,0 +1,524 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright 2024 Fiona Klute
*
* Based on code originally in rtw8723d.[ch],
* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW8723X_H__
#define __RTW8723X_H__
#include "main.h"
#include "debug.h"
#include "phy.h"
#include "reg.h"
enum rtw8723x_path {
PATH_S1,
PATH_S0,
PATH_NR,
};
enum rtw8723x_iqk_round {
IQK_ROUND_0,
IQK_ROUND_1,
IQK_ROUND_2,
IQK_ROUND_HYBRID,
IQK_ROUND_SIZE,
IQK_ROUND_INVALID = 0xff,
};
enum rtw8723x_iqk_result {
IQK_S1_TX_X,
IQK_S1_TX_Y,
IQK_S1_RX_X,
IQK_S1_RX_Y,
IQK_S0_TX_X,
IQK_S0_TX_Y,
IQK_S0_RX_X,
IQK_S0_RX_Y,
IQK_NR,
IQK_SX_NR = IQK_NR / PATH_NR,
};
struct rtw8723xe_efuse {
u8 mac_addr[ETH_ALEN]; /* 0xd0 */
u8 vendor_id[2];
u8 device_id[2];
u8 sub_vendor_id[2];
u8 sub_device_id[2];
} __packed;
struct rtw8723xu_efuse {
u8 res4[48]; /* 0xd0 */
u8 vendor_id[2]; /* 0x100 */
u8 product_id[2]; /* 0x102 */
u8 usb_option; /* 0x104 */
u8 res5[2]; /* 0x105 */
u8 mac_addr[ETH_ALEN]; /* 0x107 */
} __packed;
struct rtw8723xs_efuse {
u8 res4[0x4a]; /* 0xd0 */
u8 mac_addr[ETH_ALEN]; /* 0x11a */
} __packed;
struct rtw8723x_efuse {
__le16 rtl_id;
u8 rsvd[2];
u8 afe;
u8 rsvd1[11];
/* power index for four RF paths */
struct rtw_txpwr_idx txpwr_idx_table[4];
u8 channel_plan; /* 0xb8 */
u8 xtal_k;
u8 thermal_meter;
u8 iqk_lck;
u8 pa_type; /* 0xbc */
u8 lna_type_2g[2]; /* 0xbd */
u8 lna_type_5g[2];
u8 rf_board_option;
u8 rf_feature_option;
u8 rf_bt_setting;
u8 eeprom_version;
u8 eeprom_customer_id;
u8 tx_bb_swing_setting_2g;
u8 res_c7;
u8 tx_pwr_calibrate_rate;
u8 rf_antenna_option; /* 0xc9 */
u8 rfe_option;
u8 country_code[2];
u8 res[3];
union {
struct rtw8723xe_efuse e;
struct rtw8723xu_efuse u;
struct rtw8723xs_efuse s;
};
} __packed;
#define RTW8723X_IQK_ADDA_REG_NUM 16
#define RTW8723X_IQK_MAC8_REG_NUM 3
#define RTW8723X_IQK_MAC32_REG_NUM 1
#define RTW8723X_IQK_BB_REG_NUM 9
struct rtw8723x_iqk_backup_regs {
u32 adda[RTW8723X_IQK_ADDA_REG_NUM];
u8 mac8[RTW8723X_IQK_MAC8_REG_NUM];
u32 mac32[RTW8723X_IQK_MAC32_REG_NUM];
u32 bb[RTW8723X_IQK_BB_REG_NUM];
u32 lte_path;
u32 lte_gnt;
u32 bb_sel_btg;
u8 btg_sel;
u8 igia;
u8 igib;
};
struct rtw8723x_common {
/* registers that must be backed up before IQK and restored after */
u32 iqk_adda_regs[RTW8723X_IQK_ADDA_REG_NUM];
u32 iqk_mac8_regs[RTW8723X_IQK_MAC8_REG_NUM];
u32 iqk_mac32_regs[RTW8723X_IQK_MAC32_REG_NUM];
u32 iqk_bb_regs[RTW8723X_IQK_BB_REG_NUM];
/* chip register definitions */
struct rtw_ltecoex_addr ltecoex_addr;
struct rtw_rf_sipi_addr rf_sipi_addr[2];
struct rtw_hw_reg dig[2];
struct rtw_hw_reg dig_cck[1];
struct rtw_prioq_addrs prioq_addrs;
/* common functions */
void (*lck)(struct rtw_dev *rtwdev);
int (*read_efuse)(struct rtw_dev *rtwdev, u8 *log_map);
int (*mac_init)(struct rtw_dev *rtwdev);
int (*mac_postinit)(struct rtw_dev *rtwdev);
void (*cfg_ldo25)(struct rtw_dev *rtwdev, bool enable);
void (*set_tx_power_index)(struct rtw_dev *rtwdev);
void (*efuse_grant)(struct rtw_dev *rtwdev, bool on);
void (*false_alarm_statistics)(struct rtw_dev *rtwdev);
void (*iqk_backup_regs)(struct rtw_dev *rtwdev,
struct rtw8723x_iqk_backup_regs *backup);
void (*iqk_restore_regs)(struct rtw_dev *rtwdev,
const struct rtw8723x_iqk_backup_regs *backup);
bool (*iqk_similarity_cmp)(struct rtw_dev *rtwdev, s32 result[][IQK_NR],
u8 c1, u8 c2);
u8 (*pwrtrack_get_limit_ofdm)(struct rtw_dev *rtwdev);
void (*pwrtrack_set_xtal)(struct rtw_dev *rtwdev, u8 therm_path,
u8 delta);
void (*coex_cfg_init)(struct rtw_dev *rtwdev);
void (*fill_txdesc_checksum)(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *txdesc);
void (*debug_txpwr_limit)(struct rtw_dev *rtwdev,
struct rtw_txpwr_idx *table,
int tx_path_count);
};
extern const struct rtw8723x_common rtw8723x_common;
#define PATH_IQK_RETRY 2
#define MAX_TOLERANCE 5
#define IQK_TX_X_ERR 0x142
#define IQK_TX_Y_ERR 0x42
#define IQK_RX_X_ERR 0x132
#define IQK_RX_Y_ERR 0x36
#define IQK_RX_X_UPPER 0x11a
#define IQK_RX_X_LOWER 0xe6
#define IQK_RX_Y_LMT 0x1a
#define IQK_TX_OK BIT(0)
#define IQK_RX_OK BIT(1)
#define WLAN_TXQ_RPT_EN 0x1F
#define SPUR_THRES 0x16
#define DIS_3WIRE 0xccf000c0
#define EN_3WIRE 0xccc000c0
#define START_PSD 0x400000
#define FREQ_CH5 0xfccd
#define FREQ_CH6 0xfc4d
#define FREQ_CH7 0xffcd
#define FREQ_CH8 0xff4d
#define FREQ_CH13 0xfccd
#define FREQ_CH14 0xff9a
#define RFCFGCH_CHANNEL_MASK GENMASK(7, 0)
#define RFCFGCH_BW_MASK (BIT(11) | BIT(10))
#define RFCFGCH_BW_20M (BIT(11) | BIT(10))
#define RFCFGCH_BW_40M BIT(10)
#define BIT_MASK_RFMOD BIT(0)
#define BIT_LCK BIT(15)
#define REG_GPIO_INTM 0x0048
#define REG_BTG_SEL 0x0067
#define BIT_MASK_BTG_WL BIT(7)
#define REG_LTECOEX_PATH_CONTROL 0x0070
#define REG_LTECOEX_CTRL 0x07c0
#define REG_LTECOEX_WRITE_DATA 0x07c4
#define REG_LTECOEX_READ_DATA 0x07c8
#define REG_PSDFN 0x0808
#define REG_BB_PWR_SAV1_11N 0x0874
#define REG_ANA_PARAM1 0x0880
#define REG_ANALOG_P4 0x088c
#define REG_PSDRPT 0x08b4
#define REG_FPGA1_RFMOD 0x0900
#define REG_BB_SEL_BTG 0x0948
#define REG_BBRX_DFIR 0x0954
#define BIT_MASK_RXBB_DFIR GENMASK(27, 24)
#define BIT_RXBB_DFIR_EN BIT(19)
#define REG_CCK0_SYS 0x0a00
#define BIT_CCK_SIDE_BAND BIT(4)
#define REG_CCK_ANT_SEL_11N 0x0a04
#define REG_PWRTH 0x0a08
#define REG_CCK_FA_RST_11N 0x0a2c
#define BIT_MASK_CCK_CNT_KEEP BIT(12)
#define BIT_MASK_CCK_CNT_EN BIT(13)
#define BIT_MASK_CCK_CNT_KPEN (BIT_MASK_CCK_CNT_KEEP | BIT_MASK_CCK_CNT_EN)
#define BIT_MASK_CCK_FA_KEEP BIT(14)
#define BIT_MASK_CCK_FA_EN BIT(15)
#define BIT_MASK_CCK_FA_KPEN (BIT_MASK_CCK_FA_KEEP | BIT_MASK_CCK_FA_EN)
#define REG_CCK_FA_LSB_11N 0x0a5c
#define REG_CCK_FA_MSB_11N 0x0a58
#define REG_CCK_CCA_CNT_11N 0x0a60
#define BIT_MASK_CCK_FA_MSB GENMASK(7, 0)
#define BIT_MASK_CCK_FA_LSB GENMASK(15, 8)
#define REG_PWRTH2 0x0aa8
#define REG_CSRATIO 0x0aaa
#define REG_OFDM_FA_HOLDC_11N 0x0c00
#define BIT_MASK_OFDM_FA_KEEP BIT(31)
#define REG_BB_RX_PATH_11N 0x0c04
#define REG_TRMUX_11N 0x0c08
#define REG_OFDM_FA_RSTC_11N 0x0c0c
#define BIT_MASK_OFDM_FA_RST BIT(31)
#define REG_A_RXIQI 0x0c14
#define BIT_MASK_RXIQ_S1_X 0x000003FF
#define BIT_MASK_RXIQ_S1_Y1 0x0000FC00
#define BIT_SET_RXIQ_S1_Y1(y) ((y) & 0x3F)
#define REG_OFDM0_RXDSP 0x0c40
#define BIT_MASK_RXDSP GENMASK(28, 24)
#define BIT_EN_RXDSP BIT(9)
#define REG_OFDM_0_ECCA_THRESHOLD 0x0c4c
#define BIT_MASK_OFDM0_EXT_A BIT(31)
#define BIT_MASK_OFDM0_EXT_C BIT(29)
#define BIT_MASK_OFDM0_EXTS (BIT(31) | BIT(29) | BIT(28))
#define BIT_SET_OFDM0_EXTS(a, c, d) (((a) << 31) | ((c) << 29) | ((d) << 28))
#define BIT_MASK_OFDM0_EXTS_B (BIT(27) | BIT(25) | BIT(24))
#define BIT_SET_OFDM0_EXTS_B(a, c, d) (((a) << 27) | ((c) << 25) | ((d) << 24))
#define REG_OFDM0_XAAGC1 0x0c50
#define REG_OFDM0_XBAGC1 0x0c58
#define REG_AGCRSSI 0x0c78
#define REG_OFDM_0_XA_TX_IQ_IMBALANCE 0x0c80
#define REG_OFDM_0_XB_TX_IQ_IMBALANCE 0x0c88
#define BIT_MASK_TXIQ_ELM_A 0x03ff
#define BIT_SET_TXIQ_ELM_ACD(a, c, d) (((d) << 22) | (((c) & 0x3F) << 16) | \
((a) & 0x03ff))
#define BIT_MASK_TXIQ_ELM_C GENMASK(21, 16)
#define BIT_SET_TXIQ_ELM_C2(c) ((c) & 0x3F)
#define BIT_MASK_TXIQ_ELM_D GENMASK(31, 22)
#define REG_TXIQK_MATRIXA_LSB2_11N 0x0c94
#define BIT_SET_TXIQ_ELM_C1(c) (((c) & 0x000003C0) >> 6)
#define REG_RXIQK_MATRIX_LSB_11N 0x0ca0
#define BIT_MASK_RXIQ_S1_Y2 0xF0000000
#define BIT_SET_RXIQ_S1_Y2(y) (((y) >> 6) & 0xF)
#define REG_TXIQ_AB_S0 0x0cd0
#define BIT_MASK_TXIQ_A_S0 0x000007FE
#define BIT_MASK_TXIQ_A_EXT_S0 BIT(0)
#define BIT_MASK_TXIQ_B_S0 0x0007E000
#define REG_TXIQ_CD_S0 0x0cd4
#define BIT_MASK_TXIQ_C_S0 0x000007FE
#define BIT_MASK_TXIQ_C_EXT_S0 BIT(0)
#define BIT_MASK_TXIQ_D_S0 GENMASK(22, 13)
#define BIT_MASK_TXIQ_D_EXT_S0 BIT(12)
#define REG_RXIQ_AB_S0 0x0cd8
#define BIT_MASK_RXIQ_X_S0 0x000003FF
#define BIT_MASK_RXIQ_Y_S0 0x003FF000
#define REG_OFDM_FA_TYPE1_11N 0x0cf0
#define BIT_MASK_OFDM_FF_CNT GENMASK(15, 0)
#define BIT_MASK_OFDM_SF_CNT GENMASK(31, 16)
#define REG_OFDM_FA_RSTD_11N 0x0d00
#define BIT_MASK_OFDM_FA_RST1 BIT(27)
#define BIT_MASK_OFDM_FA_KEEP1 BIT(31)
#define REG_CTX 0x0d03
#define BIT_MASK_CTX_TYPE GENMASK(6, 4)
#define REG_OFDM1_CFOTRK 0x0d2c
#define BIT_EN_CFOTRK BIT(28)
#define REG_OFDM1_CSI1 0x0d40
#define REG_OFDM1_CSI2 0x0d44
#define REG_OFDM1_CSI3 0x0d48
#define REG_OFDM1_CSI4 0x0d4c
#define REG_OFDM_FA_TYPE2_11N 0x0da0
#define BIT_MASK_OFDM_CCA_CNT GENMASK(15, 0)
#define BIT_MASK_OFDM_PF_CNT GENMASK(31, 16)
#define REG_OFDM_FA_TYPE3_11N 0x0da4
#define BIT_MASK_OFDM_RI_CNT GENMASK(15, 0)
#define BIT_MASK_OFDM_CRC_CNT GENMASK(31, 16)
#define REG_OFDM_FA_TYPE4_11N 0x0da8
#define BIT_MASK_OFDM_MNS_CNT GENMASK(15, 0)
#define REG_FPGA0_IQK_11N 0x0e28
#define BIT_MASK_IQK_MOD 0xffffff00
#define EN_IQK 0x808000
#define RST_IQK 0x000000
#define REG_TXIQK_TONE_A_11N 0x0e30
#define REG_RXIQK_TONE_A_11N 0x0e34
#define REG_TXIQK_PI_A_11N 0x0e38
#define REG_RXIQK_PI_A_11N 0x0e3c
#define REG_TXIQK_11N 0x0e40
#define BIT_SET_TXIQK_11N(x, y) (0x80007C00 | ((x) << 16) | (y))
#define REG_RXIQK_11N 0x0e44
#define REG_IQK_AGC_PTS_11N 0x0e48
#define REG_IQK_AGC_RSP_11N 0x0e4c
#define REG_TX_IQK_TONE_B 0x0e50
#define REG_RX_IQK_TONE_B 0x0e54
#define REG_TXIQK_PI_B 0x0e58
#define REG_RXIQK_PI_B 0x0e5c
#define REG_IQK_RES_TX 0x0e94
#define BIT_MASK_RES_TX GENMASK(25, 16)
#define REG_IQK_RES_TY 0x0e9c
#define BIT_MASK_RES_TY GENMASK(25, 16)
#define REG_IQK_RES_RX 0x0ea4
#define BIT_MASK_RES_RX GENMASK(25, 16)
#define REG_IQK_RES_RY 0x0eac
#define BIT_IQK_TX_FAIL BIT(28)
#define BIT_IQK_RX_FAIL BIT(27)
#define BIT_IQK_DONE BIT(26)
#define BIT_MASK_RES_RY GENMASK(25, 16)
#define REG_PAGE_F_RST_11N 0x0f14
#define BIT_MASK_F_RST_ALL BIT(16)
#define REG_IGI_C_11N 0x0f84
#define REG_IGI_D_11N 0x0f88
#define REG_HT_CRC32_CNT_11N 0x0f90
#define BIT_MASK_HT_CRC_OK GENMASK(15, 0)
#define BIT_MASK_HT_CRC_ERR GENMASK(31, 16)
#define REG_OFDM_CRC32_CNT_11N 0x0f94
#define BIT_MASK_OFDM_LCRC_OK GENMASK(15, 0)
#define BIT_MASK_OFDM_LCRC_ERR GENMASK(31, 16)
#define REG_HT_CRC32_CNT_11N_AGG 0x0fb8
#define OFDM_SWING_A(swing) FIELD_GET(GENMASK(9, 0), swing)
#define OFDM_SWING_B(swing) FIELD_GET(GENMASK(15, 10), swing)
#define OFDM_SWING_C(swing) FIELD_GET(GENMASK(21, 16), swing)
#define OFDM_SWING_D(swing) FIELD_GET(GENMASK(31, 22), swing)
static inline s32 iqkxy_to_s32(s32 val)
{
/* val is Q10.8 */
return sign_extend32(val, 9);
}
static inline s32 iqk_mult(s32 x, s32 y, s32 *ext)
{
/* x, y and return value are Q10.8 */
s32 t;
t = x * y;
if (ext)
*ext = (t >> 7) & 0x1; /* Q.16 --> Q.9; get LSB of Q.9 */
return (t >> 8); /* Q.16 --> Q.8 */
}
static inline
void rtw8723x_debug_txpwr_limit(struct rtw_dev *rtwdev,
struct rtw_txpwr_idx *table,
int tx_path_count)
{
rtw8723x_common.debug_txpwr_limit(rtwdev, table, tx_path_count);
}
static inline void rtw8723x_lck(struct rtw_dev *rtwdev)
{
rtw8723x_common.lck(rtwdev);
}
static inline int rtw8723x_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
{
return rtw8723x_common.read_efuse(rtwdev, log_map);
}
static inline int rtw8723x_mac_init(struct rtw_dev *rtwdev)
{
return rtw8723x_common.mac_init(rtwdev);
}
static inline int rtw8723x_mac_postinit(struct rtw_dev *rtwdev)
{
return rtw8723x_common.mac_postinit(rtwdev);
}
static inline void rtw8723x_cfg_ldo25(struct rtw_dev *rtwdev, bool enable)
{
rtw8723x_common.cfg_ldo25(rtwdev, enable);
}
static inline void rtw8723x_set_tx_power_index(struct rtw_dev *rtwdev)
{
rtw8723x_common.set_tx_power_index(rtwdev);
}
static inline void rtw8723x_efuse_grant(struct rtw_dev *rtwdev, bool on)
{
rtw8723x_common.efuse_grant(rtwdev, on);
}
static inline void rtw8723x_false_alarm_statistics(struct rtw_dev *rtwdev)
{
rtw8723x_common.false_alarm_statistics(rtwdev);
}
static inline
void rtw8723x_iqk_backup_regs(struct rtw_dev *rtwdev,
struct rtw8723x_iqk_backup_regs *backup)
{
rtw8723x_common.iqk_backup_regs(rtwdev, backup);
}
static inline
void rtw8723x_iqk_restore_regs(struct rtw_dev *rtwdev,
const struct rtw8723x_iqk_backup_regs *backup)
{
rtw8723x_common.iqk_restore_regs(rtwdev, backup);
}
static inline
bool rtw8723x_iqk_similarity_cmp(struct rtw_dev *rtwdev, s32 result[][IQK_NR],
u8 c1, u8 c2)
{
return rtw8723x_common.iqk_similarity_cmp(rtwdev, result, c1, c2);
}
static inline u8 rtw8723x_pwrtrack_get_limit_ofdm(struct rtw_dev *rtwdev)
{
return rtw8723x_common.pwrtrack_get_limit_ofdm(rtwdev);
}
static inline
void rtw8723x_pwrtrack_set_xtal(struct rtw_dev *rtwdev, u8 therm_path,
u8 delta)
{
rtw8723x_common.pwrtrack_set_xtal(rtwdev, therm_path, delta);
}
static inline void rtw8723x_coex_cfg_init(struct rtw_dev *rtwdev)
{
rtw8723x_common.coex_cfg_init(rtwdev);
}
static inline
void rtw8723x_fill_txdesc_checksum(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *txdesc)
{
rtw8723x_common.fill_txdesc_checksum(rtwdev, pkt_info, txdesc);
}
/* IQK helper functions, defined as inline so they can be shared
* without needing an EXPORT_SYMBOL each.
*/
static inline void
rtw8723x_iqk_backup_path_ctrl(struct rtw_dev *rtwdev,
struct rtw8723x_iqk_backup_regs *backup)
{
backup->btg_sel = rtw_read8(rtwdev, REG_BTG_SEL);
rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] original 0x67 = 0x%x\n",
backup->btg_sel);
}
static inline void rtw8723x_iqk_config_path_ctrl(struct rtw_dev *rtwdev)
{
rtw_write32_mask(rtwdev, REG_PAD_CTRL1, BIT_BT_BTG_SEL, 0x1);
rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] set 0x67 = 0x%x\n",
rtw_read32_mask(rtwdev, REG_PAD_CTRL1, MASKBYTE3));
}
static inline void
rtw8723x_iqk_restore_path_ctrl(struct rtw_dev *rtwdev,
const struct rtw8723x_iqk_backup_regs *backup)
{
rtw_write8(rtwdev, REG_BTG_SEL, backup->btg_sel);
rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] restore 0x67 = 0x%x\n",
rtw_read32_mask(rtwdev, REG_PAD_CTRL1, MASKBYTE3));
}
static inline void
rtw8723x_iqk_backup_lte_path_gnt(struct rtw_dev *rtwdev,
struct rtw8723x_iqk_backup_regs *backup)
{
backup->lte_path = rtw_read32(rtwdev, REG_LTECOEX_PATH_CONTROL);
rtw_write32(rtwdev, REG_LTECOEX_CTRL, 0x800f0038);
mdelay(1);
backup->lte_gnt = rtw_read32(rtwdev, REG_LTECOEX_READ_DATA);
rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] OriginalGNT = 0x%x\n",
backup->lte_gnt);
}
static inline void
rtw8723x_iqk_config_lte_path_gnt(struct rtw_dev *rtwdev,
u32 write_data)
{
rtw_write32(rtwdev, REG_LTECOEX_WRITE_DATA, write_data);
rtw_write32(rtwdev, REG_LTECOEX_CTRL, 0xc0020038);
rtw_write32_mask(rtwdev, REG_LTECOEX_PATH_CONTROL,
BIT_LTE_MUX_CTRL_PATH, 0x1);
}
static inline void
rtw8723x_iqk_restore_lte_path_gnt(struct rtw_dev *rtwdev,
const struct rtw8723x_iqk_backup_regs *bak)
{
rtw_write32(rtwdev, REG_LTECOEX_WRITE_DATA, bak->lte_gnt);
rtw_write32(rtwdev, REG_LTECOEX_CTRL, 0xc00f0038);
rtw_write32(rtwdev, REG_LTECOEX_PATH_CONTROL, bak->lte_path);
}
/* set all ADDA registers to the given value */
static inline void rtw8723x_iqk_path_adda_on(struct rtw_dev *rtwdev, u32 value)
{
for (int i = 0; i < RTW8723X_IQK_ADDA_REG_NUM; i++)
rtw_write32(rtwdev, rtw8723x_common.iqk_adda_regs[i], value);
}
#endif /* __RTW8723X_H__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2024 Realtek Corporation
*/
#ifndef __RTW8812A_H__
#define __RTW8812A_H__
extern const struct rtw_chip_info rtw8812a_hw_spec;
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2024 Realtek Corporation
*/
#ifndef __RTW8812A_TABLE_H__
#define __RTW8812A_TABLE_H__
extern const struct rtw_table rtw8812a_mac_tbl;
extern const struct rtw_table rtw8812a_agc_tbl;
extern const struct rtw_table rtw8812a_agc_diff_lb_tbl;
extern const struct rtw_table rtw8812a_agc_diff_hb_tbl;
extern const struct rtw_table rtw8812a_bb_tbl;
extern const struct rtw_table rtw8812a_bb_pg_tbl;
extern const struct rtw_table rtw8812a_bb_pg_rfe3_tbl;
extern const struct rtw_table rtw8812a_rf_a_tbl;
extern const struct rtw_table rtw8812a_rf_b_tbl;
extern const struct rtw_table rtw8812a_txpwr_lmt_tbl;
extern const struct rtw_pwr_seq_cmd * const card_enable_flow_8812a[];
extern const struct rtw_pwr_seq_cmd * const enter_lps_flow_8812a[];
extern const struct rtw_pwr_seq_cmd * const card_disable_flow_8812a[];
extern const struct rtw_pwr_track_tbl rtw8812a_rtw_pwr_track_tbl;
extern const struct rtw_pwr_track_tbl rtw8812a_rtw_pwr_track_rfe3_tbl;
#endif
@@ -0,0 +1,94 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2024 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/usb.h>
#include "main.h"
#include "rtw8812a.h"
#include "usb.h"
static const struct usb_device_id rtw_8812au_id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x8812, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x881a, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x881b, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x881c, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x0409, 0x0408, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* NEC */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0411, 0x025d, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* Buffalo */
{ USB_DEVICE_AND_INTERFACE_INFO(0x04bb, 0x0952, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* I-O DATA */
{ USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x1106, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* Belkin */
{ USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x1109, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* Belkin */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0586, 0x3426, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* ZyXEL */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0789, 0x016e, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* Logitec */
{ USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8812, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* Abocom */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9051, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* Netgear */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x17d2, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* ASUS */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0074, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* Sitecom */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0022, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* Hawking */
{ USB_DEVICE_AND_INTERFACE_INFO(0x1058, 0x0632, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* WD */
{ USB_DEVICE_AND_INTERFACE_INFO(0x13b1, 0x003f, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* Linksys */
{ USB_DEVICE_AND_INTERFACE_INFO(0x148f, 0x9097, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* Amped Wireless */
{ USB_DEVICE_AND_INTERFACE_INFO(0x1740, 0x0100, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* EnGenius */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x330e, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* D-Link */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3313, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* D-Link */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3315, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* D-Link */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3316, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* D-Link */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab30, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* Planex */
{ USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x805b, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* TRENDnet */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0101, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* TP-Link */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0103, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* TP-Link */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x010d, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* TP-Link */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x010e, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* TP-Link */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x010f, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* TP-Link */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0122, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* TP-Link */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2604, 0x0012, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* Tenda */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xa822, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, /* Edimax */
{},
};
MODULE_DEVICE_TABLE(usb, rtw_8812au_id_table);
static struct usb_driver rtw_8812au_driver = {
.name = KBUILD_MODNAME,
.id_table = rtw_8812au_id_table,
.probe = rtw_usb_probe,
.disconnect = rtw_usb_disconnect,
};
module_usb_driver(rtw_8812au_driver);
MODULE_AUTHOR("Bitterblue Smith <rtl8821cerfe2@gmail.com>");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8812au driver");
MODULE_LICENSE("Dual BSD/GPL");
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,62 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2025 Realtek Corporation
*/
#ifndef __RTW8814A_H__
#define __RTW8814A_H__
struct rtw8814au_efuse {
u8 vid[2]; /* 0xd0 */
u8 pid[2]; /* 0xd2 */
u8 res[4]; /* 0xd4 */
u8 mac_addr[ETH_ALEN]; /* 0xd8 */
} __packed;
struct rtw8814ae_efuse {
u8 mac_addr[ETH_ALEN]; /* 0xd0 */
u8 vid[2]; /* 0xd6 */
u8 did[2]; /* 0xd8 */
u8 svid[2]; /* 0xda */
u8 smid[2]; /* 0xdc */
} __packed;
struct rtw8814a_efuse {
__le16 rtl_id;
u8 res0[0x0c];
u8 usb_mode; /* 0x0e */
u8 res1;
/* power index for four RF paths */
struct rtw_txpwr_idx txpwr_idx_table[4];
u8 channel_plan; /* 0xb8 */
u8 xtal_k; /* 0xb9 */
u8 thermal_meter; /* 0xba */
u8 iqk_lck; /* 0xbb */
u8 pa_type; /* 0xbc */
u8 lna_type_2g[2]; /* 0xbd */
u8 lna_type_5g[2]; /* 0xbf */
u8 rf_board_option; /* 0xc1 */
u8 res2;
u8 rf_bt_setting; /* 0xc3 */
u8 eeprom_version; /* 0xc4 */
u8 eeprom_customer_id; /* 0xc5 */
u8 tx_bb_swing_setting_2g; /* 0xc6 */
u8 tx_bb_swing_setting_5g; /* 0xc7 */
u8 res3;
u8 trx_antenna_option; /* 0xc9 */
u8 rfe_option; /* 0xca */
u8 country_code[2]; /* 0xcb */
u8 res4[3];
union {
struct rtw8814au_efuse u;
struct rtw8814ae_efuse e;
};
u8 res5[0x122]; /* 0xde */
} __packed;
static_assert(sizeof(struct rtw8814a_efuse) == 512);
extern const struct rtw_chip_info rtw8814a_hw_spec;
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,40 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2025 Realtek Corporation
*/
#ifndef __RTW8814A_TABLE_H__
#define __RTW8814A_TABLE_H__
extern const struct rtw_table rtw8814a_mac_tbl;
extern const struct rtw_table rtw8814a_agc_tbl;
extern const struct rtw_table rtw8814a_bb_tbl;
extern const struct rtw_table rtw8814a_bb_pg_tbl;
extern const struct rtw_table rtw8814a_bb_pg_type0_tbl;
extern const struct rtw_table rtw8814a_bb_pg_type2_tbl;
extern const struct rtw_table rtw8814a_bb_pg_type3_tbl;
extern const struct rtw_table rtw8814a_bb_pg_type4_tbl;
extern const struct rtw_table rtw8814a_bb_pg_type5_tbl;
extern const struct rtw_table rtw8814a_bb_pg_type7_tbl;
extern const struct rtw_table rtw8814a_bb_pg_type8_tbl;
extern const struct rtw_table rtw8814a_rf_a_tbl;
extern const struct rtw_table rtw8814a_rf_b_tbl;
extern const struct rtw_table rtw8814a_rf_c_tbl;
extern const struct rtw_table rtw8814a_rf_d_tbl;
extern const struct rtw_table rtw8814a_txpwr_lmt_tbl;
extern const struct rtw_table rtw8814a_txpwr_lmt_type0_tbl;
extern const struct rtw_table rtw8814a_txpwr_lmt_type1_tbl;
extern const struct rtw_table rtw8814a_txpwr_lmt_type2_tbl;
extern const struct rtw_table rtw8814a_txpwr_lmt_type3_tbl;
extern const struct rtw_table rtw8814a_txpwr_lmt_type5_tbl;
extern const struct rtw_table rtw8814a_txpwr_lmt_type7_tbl;
extern const struct rtw_table rtw8814a_txpwr_lmt_type8_tbl;
extern const struct rtw_pwr_track_tbl rtw8814a_rtw_pwrtrk_tbl;
extern const struct rtw_pwr_track_tbl rtw8814a_rtw_pwrtrk_type0_tbl;
extern const struct rtw_pwr_track_tbl rtw8814a_rtw_pwrtrk_type2_tbl;
extern const struct rtw_pwr_track_tbl rtw8814a_rtw_pwrtrk_type5_tbl;
extern const struct rtw_pwr_track_tbl rtw8814a_rtw_pwrtrk_type7_tbl;
extern const struct rtw_pwr_track_tbl rtw8814a_rtw_pwrtrk_type8_tbl;
extern const struct rtw_pwr_seq_cmd * const card_disable_flow_8814a[];
extern const struct rtw_pwr_seq_cmd * const card_enable_flow_8814a[];
#endif
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2025 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/pci.h>
#include "pci.h"
#include "rtw8814a.h"
static const struct pci_device_id rtw_8814ae_id_table[] = {
{
PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8813),
.driver_data = (kernel_ulong_t)&rtw8814a_hw_spec
},
{}
};
MODULE_DEVICE_TABLE(pci, rtw_8814ae_id_table);
static struct pci_driver rtw_8814ae_driver = {
.name = KBUILD_MODNAME,
.id_table = rtw_8814ae_id_table,
.probe = rtw_pci_probe,
.remove = rtw_pci_remove,
.driver.pm = &rtw_pm_ops,
.shutdown = rtw_pci_shutdown,
};
module_pci_driver(rtw_8814ae_driver);
MODULE_AUTHOR("Bitterblue Smith <rtl8821cerfe2@gmail.com>");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8814ae driver");
MODULE_LICENSE("Dual BSD/GPL");
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2025 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/usb.h>
#include "main.h"
#include "rtw8814a.h"
#include "usb.h"
static const struct usb_device_id rtw_8814au_id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x8813, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8814a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x056e, 0x400b, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8814a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x056e, 0x400d, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8814a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9054, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8814a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x1817, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8814a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x1852, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8814a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x1853, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8814a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0026, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8814a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331a, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8814a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x809a, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8814a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x809b, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8814a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0106, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8814a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xa834, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8814a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xa833, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8814a_hw_spec) },
{},
};
MODULE_DEVICE_TABLE(usb, rtw_8814au_id_table);
static struct usb_driver rtw_8814au_driver = {
.name = KBUILD_MODNAME,
.id_table = rtw_8814au_id_table,
.probe = rtw_usb_probe,
.disconnect = rtw_usb_disconnect,
};
module_usb_driver(rtw_8814au_driver);
MODULE_AUTHOR("Bitterblue Smith <rtl8821cerfe2@gmail.com>");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8814au driver");
MODULE_LICENSE("Dual BSD/GPL");
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2024 Realtek Corporation
*/
#ifndef __RTW8821A_H__
#define __RTW8821A_H__
extern const struct rtw_chip_info rtw8821a_hw_spec;
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2024 Realtek Corporation
*/
#ifndef __RTW8821A_TABLE_H__
#define __RTW8821A_TABLE_H__
extern const struct rtw_table rtw8821a_mac_tbl;
extern const struct rtw_table rtw8821a_agc_tbl;
extern const struct rtw_table rtw8821a_bb_tbl;
extern const struct rtw_table rtw8821a_bb_pg_tbl;
extern const struct rtw_table rtw8821a_rf_a_tbl;
extern const struct rtw_table rtw8821a_txpwr_lmt_tbl;
extern const struct rtw_pwr_seq_cmd * const card_enable_flow_8821a[];
extern const struct rtw_pwr_seq_cmd * const enter_lps_flow_8821a[];
extern const struct rtw_pwr_seq_cmd * const card_disable_flow_8821a[];
extern const struct rtw_pwr_track_tbl rtw8821a_rtw_pwr_track_tbl;
#endif
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2024 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/usb.h>
#include "main.h"
#include "rtw8821a.h"
#include "usb.h"
static const struct usb_device_id rtw_8821au_id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x0811, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x0820, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x0821, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x8822, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x0823, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xa811, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x0411, 0x0242, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* Buffalo */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0411, 0x029b, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* Buffalo */
{ USB_DEVICE_AND_INTERFACE_INFO(0x04bb, 0x0953, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* I-O DATA */
{ USB_DEVICE_AND_INTERFACE_INFO(0x056e, 0x4007, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* ELECOM */
{ USB_DEVICE_AND_INTERFACE_INFO(0x056e, 0x400e, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* ELECOM */
{ USB_DEVICE_AND_INTERFACE_INFO(0x056e, 0x400f, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* ELECOM */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9052, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* Netgear */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0023, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* HAWKING */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3314, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* D-Link */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3318, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* D-Link */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab32, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* Planex */
{ USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x804b, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* TRENDnet */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x011e, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* TP Link */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x011f, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* TP Link */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0120, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* TP Link */
{ USB_DEVICE_AND_INTERFACE_INFO(0x3823, 0x6249, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* Obihai */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xa811, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* Edimax */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xa812, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* Edimax */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xa813, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* Edimax */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xb611, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, /* Edimax */
{},
};
MODULE_DEVICE_TABLE(usb, rtw_8821au_id_table);
static struct usb_driver rtw_8821au_driver = {
.name = KBUILD_MODNAME,
.id_table = rtw_8821au_id_table,
.probe = rtw_usb_probe,
.disconnect = rtw_usb_disconnect,
};
module_usb_driver(rtw_8821au_driver);
MODULE_AUTHOR("Bitterblue Smith <rtl8821cerfe2@gmail.com>");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821au/8811au driver");
MODULE_LICENSE("Dual BSD/GPL");
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,286 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW8821C_H__
#define __RTW8821C_H__
#include <asm/byteorder.h>
#define RCR_VHT_ACK BIT(26)
struct rtw8821cu_efuse {
u8 res4[4]; /* 0xd0 */
u8 usb_optional_function;
u8 res5[0x1e];
u8 res6[2];
u8 serial[0x0b]; /* 0xf5 */
u8 vid; /* 0x100 */
u8 res7;
u8 pid;
u8 res8[4];
u8 mac_addr[ETH_ALEN]; /* 0x107 */
u8 res9[2];
u8 vendor_name[0x07];
u8 res10[2];
u8 device_name[0x14];
u8 res11[0xcf];
u8 package_type; /* 0x1fb */
u8 res12[0x4];
} __packed;
struct rtw8821ce_efuse {
u8 mac_addr[ETH_ALEN]; /* 0xd0 */
u8 vender_id[2];
u8 device_id[2];
u8 sub_vender_id[2];
u8 sub_device_id[2];
u8 pmc[2];
u8 exp_device_cap[2];
u8 msi_cap;
u8 ltr_cap; /* 0xe3 */
u8 exp_link_control[2];
u8 link_cap[4];
u8 link_control[2];
u8 serial_number[8];
u8 res0:2; /* 0xf4 */
u8 ltr_en:1;
u8 res1:2;
u8 obff:2;
u8 res2_1:1;
u8 res2_2:2;
u8 obff_cap:2;
u8 res3:4;
u8 res4[3];
u8 class_code[3];
u8 pci_pm_L1_2_supp:1;
u8 pci_pm_L1_1_supp:1;
u8 aspm_pm_L1_2_supp:1;
u8 aspm_pm_L1_1_supp:1;
u8 L1_pm_substates_supp:1;
u8 res5:3;
u8 port_common_mode_restore_time;
u8 port_t_power_on_scale:2;
u8 res6:1;
u8 port_t_power_on_value:5;
u8 res7;
} __packed;
struct rtw8821cs_efuse {
u8 res4[0x4a]; /* 0xd0 */
u8 mac_addr[ETH_ALEN]; /* 0x11a */
} __packed;
struct rtw8821c_efuse {
__le16 rtl_id;
u8 res0[0x0e];
/* power index for four RF paths */
struct rtw_txpwr_idx txpwr_idx_table[4];
u8 channel_plan; /* 0xb8 */
u8 xtal_k;
u8 thermal_meter;
u8 iqk_lck;
u8 pa_type; /* 0xbc */
u8 lna_type_2g[2]; /* 0xbd */
u8 lna_type_5g[2];
u8 rf_board_option;
u8 rf_feature_option;
u8 rf_bt_setting;
u8 eeprom_version;
u8 eeprom_customer_id;
u8 tx_bb_swing_setting_2g;
u8 tx_bb_swing_setting_5g;
u8 tx_pwr_calibrate_rate;
u8 rf_antenna_option; /* 0xc9 */
u8 rfe_option;
u8 country_code[2];
u8 res[3];
union {
struct rtw8821ce_efuse e;
struct rtw8821cu_efuse u;
struct rtw8821cs_efuse s;
};
} __packed;
static inline void
_rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data)
{
/* 0xC00-0xCFF and 0xE00-0xEFF have the same layout */
rtw_write32_mask(rtwdev, addr, mask, data);
rtw_write32_mask(rtwdev, addr + 0x200, mask, data);
}
extern const struct rtw_chip_info rtw8821c_hw_spec;
#define rtw_write32s_mask(rtwdev, addr, mask, data) \
do { \
BUILD_BUG_ON((addr) < 0xC00 || (addr) >= 0xD00); \
\
_rtw_write32s_mask(rtwdev, addr, mask, data); \
} while (0)
#define BIT_FEN_PCIEA BIT(6)
#define WLAN_SLOT_TIME 0x09
#define WLAN_PIFS_TIME 0x19
#define WLAN_SIFS_CCK_CONT_TX 0xA
#define WLAN_SIFS_OFDM_CONT_TX 0xE
#define WLAN_SIFS_CCK_TRX 0x10
#define WLAN_SIFS_OFDM_TRX 0x10
#define WLAN_VO_TXOP_LIMIT 0x186
#define WLAN_VI_TXOP_LIMIT 0x3BC
#define WLAN_RDG_NAV 0x05
#define WLAN_TXOP_NAV 0x1B
#define WLAN_CCK_RX_TSF 0x30
#define WLAN_OFDM_RX_TSF 0x30
#define WLAN_TBTT_PROHIBIT 0x04
#define WLAN_TBTT_HOLD_TIME 0x064
#define WLAN_DRV_EARLY_INT 0x04
#define WLAN_BCN_DMA_TIME 0x02
#define WLAN_RX_FILTER0 0x0FFFFFFF
#define WLAN_RX_FILTER2 0xFFFF
#define WLAN_RCR_CFG 0xE400220E
#define WLAN_RXPKT_MAX_SZ 12288
#define WLAN_RXPKT_MAX_SZ_512 (WLAN_RXPKT_MAX_SZ >> 9)
#define WLAN_AMPDU_MAX_TIME 0x70
#define WLAN_RTS_LEN_TH 0xFF
#define WLAN_RTS_TX_TIME_TH 0x08
#define WLAN_MAX_AGG_PKT_LIMIT 0x20
#define WLAN_RTS_MAX_AGG_PKT_LIMIT 0x20
#define FAST_EDCA_VO_TH 0x06
#define FAST_EDCA_VI_TH 0x06
#define FAST_EDCA_BE_TH 0x06
#define FAST_EDCA_BK_TH 0x06
#define WLAN_BAR_RETRY_LIMIT 0x01
#define WLAN_RA_TRY_RATE_AGG_LIMIT 0x08
#define WLAN_TX_FUNC_CFG1 0x30
#define WLAN_TX_FUNC_CFG2 0x30
#define WLAN_MAC_OPT_NORM_FUNC1 0x98
#define WLAN_MAC_OPT_LB_FUNC1 0x80
#define WLAN_MAC_OPT_FUNC2 0xb0810041
#define WLAN_SIFS_CFG (WLAN_SIFS_CCK_CONT_TX | \
(WLAN_SIFS_OFDM_CONT_TX << BIT_SHIFT_SIFS_OFDM_CTX) | \
(WLAN_SIFS_CCK_TRX << BIT_SHIFT_SIFS_CCK_TRX) | \
(WLAN_SIFS_OFDM_TRX << BIT_SHIFT_SIFS_OFDM_TRX))
#define WLAN_TBTT_TIME (WLAN_TBTT_PROHIBIT |\
(WLAN_TBTT_HOLD_TIME << BIT_SHIFT_TBTT_HOLD_TIME_AP))
#define WLAN_NAV_CFG (WLAN_RDG_NAV | (WLAN_TXOP_NAV << 16))
#define WLAN_RX_TSF_CFG (WLAN_CCK_RX_TSF | (WLAN_OFDM_RX_TSF) << 8)
#define WLAN_PRE_TXCNT_TIME_TH 0x1E4
/* phy status page0 */
#define GET_PHY_STAT_P0_PWDB(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(15, 8))
#define GET_PHY_STAT_P0_VGA(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x03), GENMASK(12, 8))
#define GET_PHY_STAT_P0_LNA_L(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x03), GENMASK(15, 13))
#define GET_PHY_STAT_P0_LNA_H(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x03), BIT(23))
#define BIT_LNA_H_MASK BIT(3)
#define BIT_LNA_L_MASK GENMASK(2, 0)
/* phy status page1 */
#define GET_PHY_STAT_P1_PWDB_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(15, 8))
#define GET_PHY_STAT_P1_PWDB_B(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(23, 16))
#define GET_PHY_STAT_P1_RF_MODE(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x03), GENMASK(29, 28))
#define GET_PHY_STAT_P1_L_RXSC(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(11, 8))
#define GET_PHY_STAT_P1_HT_RXSC(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(15, 12))
#define GET_PHY_STAT_P1_RXEVM_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(7, 0))
#define GET_PHY_STAT_P1_RXEVM_B(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(15, 8))
#define GET_PHY_STAT_P1_CFO_TAIL_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(7, 0))
#define GET_PHY_STAT_P1_CFO_TAIL_B(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(15, 8))
#define GET_PHY_STAT_P1_RXSNR_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(7, 0))
#define GET_PHY_STAT_P1_RXSNR_B(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(15, 8))
#define REG_SYS_CTRL 0x000
#define BIT_FEN_EN BIT(26)
#define REG_INIRTS_RATE_SEL 0x0480
#define REG_HTSTFWT 0x800
#define REG_RXCCAMSK 0x814
#define REG_L1WT 0x83c
#define REG_L1PKWT 0x840
#define REG_MRC 0x850
#define REG_ADC40 0x8c8
#define REG_CHFIR 0x8f0
#define REG_CDDTXP 0x93c
#define REG_TXPSEL1 0x940
#define REG_ACBB0 0x948
#define REG_ACBBRXFIR 0x94c
#define REG_ACGG2TBL 0x958
#define REG_ADCINI 0xa04
#define REG_PWRTH 0xa08
#define REG_CCA_FLTR 0xa20
#define REG_TXSF2 0xa24
#define REG_TXSF6 0xa28
#define REG_RXDESC 0xa2c
#define REG_ENTXCCK 0xa80
#define BTG_LNA 0xfc84
#define WLG_LNA 0x7532
#define REG_ENRXCCA 0xa84
#define BTG_CCA 0x0e
#define WLG_CCA 0x12
#define REG_PWRTH2 0xaa8
#define REG_CSRATIO 0xaaa
#define REG_TXFILTER 0xaac
#define REG_AGCTR_A 0xc08
#define REG_TXDFIR 0xc20
#define REG_TRSW 0xca0
#define REG_RFESEL0 0xcb0
#define REG_RFESEL8 0xcb4
#define REG_RFECTL 0xcb8
#define B_BTG_SWITCH BIT(16)
#define B_CTRL_SWITCH BIT(18)
#define B_WL_SWITCH (BIT(20) | BIT(22))
#define B_WLG_SWITCH BIT(21)
#define B_WLA_SWITCH BIT(23)
#define REG_RFEINV 0xcbc
#define REG_AGCTR_B 0xe08
#define REG_DMEM_CTRL 0x1080
#define BIT_WL_RST BIT(16)
#define REG_ANTWT 0x1904
#define REG_IQKFAILMSK 0x1bf0
#define BIT_MASK_R_RFE_SEL_15 GENMASK(31, 28)
#define BIT_SDIO_INT BIT(18)
#define BT_CNT_ENABLE 0x1
#define BIT_BCN_QUEUE BIT(3)
#define BCN_PRI_EN 0x1
#define PTA_CTRL_PIN 0x66
#define DPDT_CTRL_PIN 0x77
#define ANTDIC_CTRL_PIN 0x88
#define REG_CTRL_TYPE 0x67
#define BIT_CTRL_TYPE1 BIT(5)
#define BIT_CTRL_TYPE2 BIT(4)
#define CTRL_TYPE_MASK GENMASK(15, 8)
#define RF18_BAND_MASK (BIT(16) | BIT(9) | BIT(8))
#define RF18_BAND_2G (0)
#define RF18_BAND_5G (BIT(16) | BIT(8))
#define RF18_CHANNEL_MASK (MASKBYTE0)
#define RF18_RFSI_MASK (BIT(18) | BIT(17))
#define RF18_RFSI_GE (BIT(17))
#define RF18_RFSI_GT (BIT(18))
#define RF18_BW_MASK (BIT(11) | BIT(10))
#define RF18_BW_20M (BIT(11) | BIT(10))
#define RF18_BW_40M (BIT(11))
#define RF18_BW_80M (BIT(10))
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW8821C_TABLE_H__
#define __RTW8821C_TABLE_H__
extern const struct rtw_table rtw8821c_mac_tbl;
extern const struct rtw_table rtw8821c_agc_tbl;
extern const struct rtw_table rtw8821c_agc_btg_type2_tbl;
extern const struct rtw_table rtw8821c_bb_tbl;
extern const struct rtw_table rtw8821c_bb_pg_type0_tbl;
extern const struct rtw_table rtw8821c_rf_a_tbl;
extern const struct rtw_table rtw8821c_txpwr_lmt_type0_tbl;
#endif
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/pci.h>
#include "pci.h"
#include "rtw8821c.h"
static const struct pci_device_id rtw_8821ce_id_table[] = {
{
PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xB821),
.driver_data = (kernel_ulong_t)&rtw8821c_hw_spec
},
{
PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xC821),
.driver_data = (kernel_ulong_t)&rtw8821c_hw_spec
},
{}
};
MODULE_DEVICE_TABLE(pci, rtw_8821ce_id_table);
static struct pci_driver rtw_8821ce_driver = {
.name = KBUILD_MODNAME,
.id_table = rtw_8821ce_id_table,
.probe = rtw_pci_probe,
.remove = rtw_pci_remove,
.driver.pm = &rtw_pm_ops,
.shutdown = rtw_pci_shutdown,
.err_handler = &rtw_pci_err_handler,
};
module_pci_driver(rtw_8821ce_driver);
MODULE_AUTHOR("Realtek Corporation");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821ce driver");
MODULE_LICENSE("Dual BSD/GPL");
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) Martin Blumenstingl <martin.blumenstingl@googlemail.com>
*/
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/module.h>
#include "main.h"
#include "rtw8821c.h"
#include "sdio.h"
static const struct sdio_device_id rtw_8821cs_id_table[] = {
{
SDIO_DEVICE(SDIO_VENDOR_ID_REALTEK,
SDIO_DEVICE_ID_REALTEK_RTW8821CS),
.driver_data = (kernel_ulong_t)&rtw8821c_hw_spec,
},
{}
};
MODULE_DEVICE_TABLE(sdio, rtw_8821cs_id_table);
static struct sdio_driver rtw_8821cs_driver = {
.name = KBUILD_MODNAME,
.probe = rtw_sdio_probe,
.remove = rtw_sdio_remove,
.shutdown = rtw_sdio_shutdown,
.id_table = rtw_8821cs_id_table,
.drv = {
.pm = &rtw_sdio_pm_ops,
}
};
module_sdio_driver(rtw_8821cs_driver);
MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821cs driver");
MODULE_LICENSE("Dual BSD/GPL");
@@ -0,0 +1,62 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/usb.h>
#include "main.h"
#include "rtw8821c.h"
#include "usb.h"
static const struct usb_device_id rtw_8821cu_id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x2006, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x8731, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x8811, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb820, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb82b, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc80c, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc811, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc820, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc821, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82a, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82b, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331d, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* D-Link */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xc811, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* Edimax */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xd811, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* Edimax */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2c4e, 0x0105, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* Mercusys */
{},
};
MODULE_DEVICE_TABLE(usb, rtw_8821cu_id_table);
static int rtw_8821cu_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return rtw_usb_probe(intf, id);
}
static struct usb_driver rtw_8821cu_driver = {
.name = KBUILD_MODNAME,
.id_table = rtw_8821cu_id_table,
.probe = rtw_8821cu_probe,
.disconnect = rtw_usb_disconnect,
};
module_usb_driver(rtw_8821cu_driver);
MODULE_AUTHOR("Hans Ulli Kroll <linux@ulli-kroll.de>");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821cu driver");
MODULE_LICENSE("Dual BSD/GPL");
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,189 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW8822B_H__
#define __RTW8822B_H__
#include <asm/byteorder.h>
#define RCR_VHT_ACK BIT(26)
struct rtw8822bu_efuse {
u8 res4[4]; /* 0xd0 */
u8 usb_optional_function;
u8 res5[0x1e];
u8 res6[2];
u8 serial[0x0b]; /* 0xf5 */
u8 vid; /* 0x100 */
u8 res7;
u8 pid;
u8 res8[4];
u8 mac_addr[ETH_ALEN]; /* 0x107 */
u8 res9[2];
u8 vendor_name[0x07];
u8 res10[2];
u8 device_name[0x14];
u8 res11[0xcf];
u8 package_type; /* 0x1fb */
u8 res12[0x4];
} __packed;
struct rtw8822be_efuse {
u8 mac_addr[ETH_ALEN]; /* 0xd0 */
u8 vender_id[2];
u8 device_id[2];
u8 sub_vender_id[2];
u8 sub_device_id[2];
u8 pmc[2];
u8 exp_device_cap[2];
u8 msi_cap;
u8 ltr_cap; /* 0xe3 */
u8 exp_link_control[2];
u8 link_cap[4];
u8 link_control[2];
u8 serial_number[8];
u8 res0:2; /* 0xf4 */
u8 ltr_en:1;
u8 res1:2;
u8 obff:2;
u8 res2_1:1;
u8 res2_2:2;
u8 obff_cap:2;
u8 res3:4;
u8 res4[3];
u8 class_code[3];
u8 pci_pm_L1_2_supp:1;
u8 pci_pm_L1_1_supp:1;
u8 aspm_pm_L1_2_supp:1;
u8 aspm_pm_L1_1_supp:1;
u8 L1_pm_substates_supp:1;
u8 res5:3;
u8 port_common_mode_restore_time;
u8 port_t_power_on_scale:2;
u8 res6:1;
u8 port_t_power_on_value:5;
u8 res7;
} __packed;
struct rtw8822bs_efuse {
u8 res4[0x4a]; /* 0xd0 */
u8 mac_addr[ETH_ALEN]; /* 0x11a */
} __packed;
struct rtw8822b_efuse {
__le16 rtl_id;
u8 res0[4];
u8 usb_mode;
u8 res1[0x09];
/* power index for four RF paths */
struct rtw_txpwr_idx txpwr_idx_table[4];
u8 channel_plan; /* 0xb8 */
u8 xtal_k;
u8 thermal_meter;
u8 iqk_lck;
u8 pa_type; /* 0xbc */
u8 lna_type_2g[2]; /* 0xbd */
u8 lna_type_5g[2];
u8 rf_board_option;
u8 rf_feature_option;
u8 rf_bt_setting;
u8 eeprom_version;
u8 eeprom_customer_id;
u8 tx_bb_swing_setting_2g;
u8 tx_bb_swing_setting_5g;
u8 tx_pwr_calibrate_rate;
u8 rf_antenna_option; /* 0xc9 */
u8 rfe_option;
u8 country_code[2];
u8 res[3];
union {
struct rtw8822be_efuse e;
struct rtw8822bu_efuse u;
struct rtw8822bs_efuse s;
};
} __packed;
static inline void
_rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data)
{
/* 0xC00-0xCFF and 0xE00-0xEFF have the same layout */
rtw_write32_mask(rtwdev, addr, mask, data);
rtw_write32_mask(rtwdev, addr + 0x200, mask, data);
}
#define rtw_write32s_mask(rtwdev, addr, mask, data) \
do { \
BUILD_BUG_ON((addr) < 0xC00 || (addr) >= 0xD00); \
\
_rtw_write32s_mask(rtwdev, addr, mask, data); \
} while (0)
/* phy status page0 */
#define GET_PHY_STAT_P0_PWDB(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(15, 8))
/* phy status page1 */
#define GET_PHY_STAT_P1_PWDB_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(15, 8))
#define GET_PHY_STAT_P1_PWDB_B(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(23, 16))
#define GET_PHY_STAT_P1_RF_MODE(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x03), GENMASK(29, 28))
#define GET_PHY_STAT_P1_L_RXSC(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(11, 8))
#define GET_PHY_STAT_P1_HT_RXSC(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(15, 12))
#define GET_PHY_STAT_P1_RXEVM_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(7, 0))
#define GET_PHY_STAT_P1_RXEVM_B(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(15, 8))
#define GET_PHY_STAT_P1_CFO_TAIL_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(7, 0))
#define GET_PHY_STAT_P1_CFO_TAIL_B(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(15, 8))
#define GET_PHY_STAT_P1_RXSNR_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(7, 0))
#define GET_PHY_STAT_P1_RXSNR_B(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(15, 8))
#define RTW8822B_EDCCA_MAX 0x7f
#define RTW8822B_EDCCA_SRC_DEF 1
#define REG_HTSTFWT 0x800
#define REG_RXCCAMSK 0x814
#define REG_L1WT 0x83c
#define REG_L1PKWT 0x840
#define REG_MRC 0x850
#define REG_EDCCA_POW_MA 0x8a0
#define BIT_MA_LEVEL GENMASK(1, 0)
#define REG_ADC40 0x8c8
#define REG_EDCCA_DECISION 0x8dc
#define BIT_EDCCA_OPTION BIT(5)
#define REG_CDDTXP 0x93c
#define REG_TXPSEL1 0x940
#define REG_EDCCA_SOURCE 0x944
#define BIT_SOURCE_OPTION GENMASK(29, 28)
#define REG_ACBB0 0x948
#define REG_ACBBRXFIR 0x94c
#define REG_ACGG2TBL 0x958
#define REG_ADCINI 0xa04
#define REG_TXSF2 0xa24
#define REG_TXSF6 0xa28
#define REG_RXDESC 0xa2c
#define REG_ENTXCCK 0xa80
#define REG_AGCTR_A 0xc08
#define REG_TXDFIR 0xc20
#define REG_TRSW 0xca0
#define REG_RFESEL0 0xcb0
#define REG_RFESEL8 0xcb4
#define REG_RFECTL 0xcb8
#define REG_RFEINV 0xcbc
#define REG_AGCTR_B 0xe08
#define REG_ANTWT 0x1904
#define REG_IQKFAILMSK 0x1bf0
extern const struct rtw_chip_info rtw8822b_hw_spec;
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW8822B_TABLE_H__
#define __RTW8822B_TABLE_H__
extern const struct rtw_table rtw8822b_mac_tbl;
extern const struct rtw_table rtw8822b_agc_tbl;
extern const struct rtw_table rtw8822b_bb_tbl;
extern const struct rtw_table rtw8822b_bb_pg_type2_tbl;
extern const struct rtw_table rtw8822b_bb_pg_type3_tbl;
extern const struct rtw_table rtw8822b_bb_pg_type5_tbl;
extern const struct rtw_table rtw8822b_rf_a_tbl;
extern const struct rtw_table rtw8822b_rf_b_tbl;
extern const struct rtw_table rtw8822b_txpwr_lmt_type0_tbl;
extern const struct rtw_table rtw8822b_txpwr_lmt_type2_tbl;
extern const struct rtw_table rtw8822b_txpwr_lmt_type5_tbl;
#endif
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/pci.h>
#include "pci.h"
#include "rtw8822b.h"
static const struct pci_device_id rtw_8822be_id_table[] = {
{
PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xB822),
.driver_data = (kernel_ulong_t)&rtw8822b_hw_spec
},
{}
};
MODULE_DEVICE_TABLE(pci, rtw_8822be_id_table);
static struct pci_driver rtw_8822be_driver = {
.name = KBUILD_MODNAME,
.id_table = rtw_8822be_id_table,
.probe = rtw_pci_probe,
.remove = rtw_pci_remove,
.driver.pm = &rtw_pm_ops,
.shutdown = rtw_pci_shutdown,
.err_handler = &rtw_pci_err_handler,
};
module_pci_driver(rtw_8822be_driver);
MODULE_AUTHOR("Realtek Corporation");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822be driver");
MODULE_LICENSE("Dual BSD/GPL");
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) Jernej Skrabec <jernej.skrabec@gmail.com>
*/
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/module.h>
#include "main.h"
#include "rtw8822b.h"
#include "sdio.h"
static const struct sdio_device_id rtw_8822bs_id_table[] = {
{
SDIO_DEVICE(SDIO_VENDOR_ID_REALTEK,
SDIO_DEVICE_ID_REALTEK_RTW8822BS),
.driver_data = (kernel_ulong_t)&rtw8822b_hw_spec,
},
{}
};
MODULE_DEVICE_TABLE(sdio, rtw_8822bs_id_table);
static struct sdio_driver rtw_8822bs_driver = {
.name = KBUILD_MODNAME,
.probe = rtw_sdio_probe,
.remove = rtw_sdio_remove,
.shutdown = rtw_sdio_shutdown,
.id_table = rtw_8822bs_id_table,
.drv = {
.pm = &rtw_sdio_pm_ops,
}
};
module_sdio_driver(rtw_8822bs_driver);
MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@gmail.com>");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822bs driver");
MODULE_LICENSE("Dual BSD/GPL");
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/usb.h>
#include "main.h"
#include "rtw8822b.h"
#include "usb.h"
static const struct usb_device_id rtw_8822bu_id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb812, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb82c, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x2102, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* CCNC */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xb822, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax EW-7822ULC */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xc822, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax EW-7822UTC */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xd822, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xe822, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xf822, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax EW-7822UAD */
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb81a, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Default ID */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x1841, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS AC1300 USB-AC55 B1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x184c, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS U2 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0B05, 0x19aa, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS - USB-AC58 rev A1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0B05, 0x1870, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0B05, 0x1874, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331e, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Dlink - DWA-181 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331c, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Dlink - DWA-182 - D1 */
{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331f, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec)}, /* Dlink - DWA-183 D Ver */
{ USB_DEVICE_AND_INTERFACE_INFO(0x13b1, 0x0043, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Linksys WUSB6400M */
{ USB_DEVICE_AND_INTERFACE_INFO(0x13b1, 0x0045, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Linksys WUSB3600 v2 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x012d, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-Link Archer T3U v1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0138, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-Link Archer T3U Plus v1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0115, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-Link Archer T4U V3 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x012e, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-LINK */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0116, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-LINK */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0117, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-LINK */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9055, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Netgear A6150 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0025, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Hawking HW12ACU */
{ USB_DEVICE_AND_INTERFACE_INFO(0x04ca, 0x8602, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* LiteOn */
{ USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x808a, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TRENDnet TEW-808UBM */
{ USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x805a, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TRENDnet TEW-805UBH */
{ USB_DEVICE_AND_INTERFACE_INFO(0x056e, 0x4011, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ELECOM WDB-867DU3S */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2c4e, 0x0107, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Mercusys MA30H */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2c4e, 0x010a, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Mercusys MA30N */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3322, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* D-Link DWA-T185 rev. A1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0411, 0x03d1, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* BUFFALO WI-U2-866DM */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0411, 0x03d0, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* BUFFALO WI-U3-866DHP */
{},
};
MODULE_DEVICE_TABLE(usb, rtw_8822bu_id_table);
static int rtw8822bu_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return rtw_usb_probe(intf, id);
}
static struct usb_driver rtw_8822bu_driver = {
.name = KBUILD_MODNAME,
.id_table = rtw_8822bu_id_table,
.probe = rtw8822bu_probe,
.disconnect = rtw_usb_disconnect,
};
module_usb_driver(rtw_8822bu_driver);
MODULE_AUTHOR("Realtek Corporation");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822bu driver");
MODULE_LICENSE("Dual BSD/GPL");
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,429 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW8822C_H__
#define __RTW8822C_H__
#include <asm/byteorder.h>
struct rtw8822cu_efuse {
u8 res0[0x30]; /* 0x120 */
u8 vid[2]; /* 0x150 */
u8 pid[2];
u8 res1[3];
u8 mac_addr[ETH_ALEN]; /* 0x157 */
u8 res2[0x3d];
} __packed;
struct rtw8822cs_efuse {
u8 res0[0x4a]; /* 0x120 */
u8 mac_addr[ETH_ALEN]; /* 0x16a */
} __packed;
struct rtw8822ce_efuse {
u8 mac_addr[ETH_ALEN]; /* 0x120 */
u8 vender_id[2];
u8 device_id[2];
u8 sub_vender_id[2];
u8 sub_device_id[2];
u8 pmc[2];
u8 exp_device_cap[2];
u8 msi_cap;
u8 ltr_cap; /* 0x133 */
u8 exp_link_control[2];
u8 link_cap[4];
u8 link_control[2];
u8 serial_number[8];
u8 res0:2; /* 0x144 */
u8 ltr_en:1;
u8 res1:2;
u8 obff:2;
u8 res2_1:1;
u8 res2_2:2;
u8 obff_cap:2;
u8 res3:4;
u8 class_code[3];
u8 res4;
u8 pci_pm_L1_2_supp:1;
u8 pci_pm_L1_1_supp:1;
u8 aspm_pm_L1_2_supp:1;
u8 aspm_pm_L1_1_supp:1;
u8 L1_pm_substates_supp:1;
u8 res5:3;
u8 port_common_mode_restore_time;
u8 port_t_power_on_scale:2;
u8 res6:1;
u8 port_t_power_on_value:5;
u8 res7;
} __packed;
struct rtw8822c_efuse {
__le16 rtl_id;
u8 res0[4];
u8 usb_mode;
u8 res1[0x09];
/* power index for four RF paths */
struct rtw_txpwr_idx txpwr_idx_table[4];
u8 channel_plan; /* 0xb8 */
u8 xtal_k;
u8 res2;
u8 iqk_lck;
u8 res3[5]; /* 0xbc */
u8 rf_board_option;
u8 rf_feature_option;
u8 rf_bt_setting;
u8 eeprom_version;
u8 eeprom_customer_id;
u8 tx_bb_swing_setting_2g;
u8 tx_bb_swing_setting_5g;
u8 tx_pwr_calibrate_rate;
u8 rf_antenna_option; /* 0xc9 */
u8 rfe_option;
u8 country_code[2];
u8 res4[3];
u8 path_a_thermal; /* 0xd0 */
u8 path_b_thermal;
u8 res5[2];
u8 rx_gain_gap_2g_ofdm;
u8 res6;
u8 rx_gain_gap_2g_cck;
u8 res7;
u8 rx_gain_gap_5gl;
u8 res8;
u8 rx_gain_gap_5gm;
u8 res9;
u8 rx_gain_gap_5gh;
u8 res10;
u8 res11[0x42];
union {
struct rtw8822ce_efuse e;
struct rtw8822cu_efuse u;
struct rtw8822cs_efuse s;
};
} __packed;
enum rtw8822c_dpk_agc_phase {
RTW_DPK_GAIN_CHECK,
RTW_DPK_GAIN_LARGE,
RTW_DPK_GAIN_LESS,
RTW_DPK_GL_LARGE,
RTW_DPK_GL_LESS,
RTW_DPK_LOSS_CHECK,
RTW_DPK_AGC_OUT,
};
enum rtw8822c_dpk_one_shot_action {
RTW_DPK_CAL_PWR,
RTW_DPK_GAIN_LOSS,
RTW_DPK_DO_DPK,
RTW_DPK_DPK_ON,
RTW_DPK_DAGC,
RTW_DPK_ACTION_MAX
};
void rtw8822c_parse_tbl_dpk(struct rtw_dev *rtwdev,
const struct rtw_table *tbl);
extern const struct rtw_chip_info rtw8822c_hw_spec;
#define RTW_DECL_TABLE_DPK(name) \
const struct rtw_table name ## _tbl = { \
.data = name, \
.size = ARRAY_SIZE(name), \
.parse = rtw8822c_parse_tbl_dpk, \
}
#define DACK_PATH_8822C 2
#define DACK_REG_8822C 16
#define DACK_RF_8822C 1
#define DACK_SN_8822C 100
/* phy status page0 */
#define GET_PHY_STAT_P0_PWDB_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(15, 8))
#define GET_PHY_STAT_P0_PWDB_B(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(7, 0))
#define GET_PHY_STAT_P0_GAIN_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(21, 16))
#define GET_PHY_STAT_P0_CHANNEL(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(23, 16))
#define GET_PHY_STAT_P0_GAIN_B(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(29, 24))
/* phy status page1 */
#define GET_PHY_STAT_P1_PWDB_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(15, 8))
#define GET_PHY_STAT_P1_PWDB_B(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(23, 16))
#define GET_PHY_STAT_P1_L_RXSC(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(11, 8))
#define GET_PHY_STAT_P1_HT_RXSC(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(15, 12))
#define GET_PHY_STAT_P1_CHANNEL(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(23, 16))
#define GET_PHY_STAT_P1_RXEVM_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(7, 0))
#define GET_PHY_STAT_P1_RXEVM_B(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(15, 8))
#define GET_PHY_STAT_P1_CFO_TAIL_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(7, 0))
#define GET_PHY_STAT_P1_CFO_TAIL_B(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(15, 8))
#define GET_PHY_STAT_P1_RXSNR_A(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(7, 0))
#define GET_PHY_STAT_P1_RXSNR_B(phy_stat) \
le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(15, 8))
#define RTW8822C_EDCCA_MAX 0x7f
#define REG_ANAPARLDO_POW_MAC 0x0029
#define BIT_LDOE25_PON BIT(0)
#define XCAP_MASK GENMASK(6, 0)
#define CFO_TRK_ENABLE_TH 20
#define CFO_TRK_STOP_TH 10
#define CFO_TRK_ADJ_TH 10
#define REG_TXDFIR0 0x808
#define REG_DFIRBW 0x810
#define REG_ANTMAP0 0x820
#define BIT_ANT_PATH GENMASK(1, 0)
#define REG_ANTMAP 0x824
#define REG_EDCCA_DECISION 0x844
#define BIT_EDCCA_OPTION GENMASK(30, 29)
#define REG_DYMPRITH 0x86c
#define REG_DYMENTH0 0x870
#define REG_DYMENTH 0x874
#define REG_SBD 0x88c
#define BITS_SUBTUNE GENMASK(15, 12)
#define REG_DYMTHMIN 0x8a4
#define REG_TXBWCTL 0x9b0
#define REG_TXCLK 0x9b4
#define REG_SCOTRK 0xc30
#define REG_MRCM 0xc38
#define REG_AGCSWSH 0xc44
#define REG_ANTWTPD 0xc54
#define REG_PT_CHSMO 0xcbc
#define BIT_PT_OPT BIT(21)
#define REG_ORITXCODE 0x1800
#define BIT_PATH_EN BIT(31)
#define REG_3WIRE 0x180c
#define BIT_DIS_SHARERX_TXGAT BIT(27)
#define BIT_3WIRE_TX_EN BIT(0)
#define BIT_3WIRE_RX_EN BIT(1)
#define BIT_3WIRE_EN GENMASK(1, 0)
#define BIT_3WIRE_PI_ON BIT(28)
#define REG_ANAPAR_A 0x1830
#define BIT_ANAPAR_UPDATE BIT(29)
#define REG_RFTXEN_GCK_A 0x1864
#define BIT_RFTXEN_GCK_FORCE_ON BIT(31)
#define REG_DIS_SHARE_RX_A 0x186c
#define BIT_TX_SCALE_0DB BIT(7)
#define REG_RXAGCCTL0 0x18ac
#define BITS_RXAGC_CCK GENMASK(15, 12)
#define BITS_RXAGC_OFDM GENMASK(8, 4)
#define REG_DCKA_I_0 0x18bc
#define REG_DCKA_I_1 0x18c0
#define REG_DCKA_Q_0 0x18d8
#define REG_DCKA_Q_1 0x18dc
#define REG_CCKSB 0x1a00
#define BIT_BBMODE GENMASK(2, 1)
#define REG_RXCCKSEL 0x1a04
#define REG_BGCTRL 0x1a14
#define BITS_RX_IQ_WEIGHT (BIT(8) | BIT(9))
#define REG_TXF0 0x1a20
#define REG_TXF1 0x1a24
#define REG_TXF2 0x1a28
#define REG_CCANRX 0x1a2c
#define BIT_CCK_FA_RST (BIT(14) | BIT(15))
#define BIT_OFDM_FA_RST (BIT(12) | BIT(13))
#define REG_CCK_FACNT 0x1a5c
#define REG_CCKTXONLY 0x1a80
#define BIT_BB_CCK_CHECK_EN BIT(18)
#define REG_TXF3 0x1a98
#define REG_TXF4 0x1a9c
#define REG_TXF5 0x1aa0
#define REG_TXF6 0x1aac
#define REG_TXF7 0x1ab0
#define REG_CCK_SOURCE 0x1abc
#define BIT_NBI_EN BIT(30)
#define REG_NCTL0 0x1b00
#define BIT_SEL_PATH GENMASK(2, 1)
#define BIT_SUBPAGE GENMASK(3, 0)
#define REG_DPD_CTL0_S0 0x1b04
#define BIT_GS_PWSF GENMASK(27, 0)
#define REG_DPD_CTL1_S0 0x1b08
#define BIT_DPD_EN BIT(31)
#define BIT_PS_EN BIT(7)
#define REG_IQKSTAT 0x1b10
#define REG_IQK_CTL1 0x1b20
#define BIT_TX_CFIR GENMASK(31, 30)
#define BIT_CFIR_EN GENMASK(26, 24)
#define BIT_BYPASS_DPD BIT(25)
#define REG_TX_TONE_IDX 0x1b2c
#define REG_DPD_LUT0 0x1b44
#define BIT_GLOSS_DB GENMASK(14, 12)
#define REG_DPD_CTL0_S1 0x1b5c
#define REG_DPD_CTL1_S1 0x1b60
#define REG_DPD_AGC 0x1b67
#define REG_TABLE_SEL 0x1b98
#define BIT_I_GAIN GENMASK(19, 16)
#define BIT_GAIN_RST BIT(15)
#define BIT_Q_GAIN_SEL GENMASK(14, 12)
#define BIT_Q_GAIN GENMASK(11, 0)
#define REG_TX_GAIN_SET 0x1b9c
#define BIT_GAPK_RPT_IDX GENMASK(11, 8)
#define REG_DPD_CTL0 0x1bb4
#define REG_SINGLE_TONE_SW 0x1bb8
#define BIT_IRQ_TEST_MODE BIT(20)
#define REG_R_CONFIG 0x1bcc
#define BIT_INNER_LB BIT(21)
#define BIT_IQ_SWITCH GENMASK(5, 0)
#define BIT_2G_SWING 0x2d
#define BIT_5G_SWING 0x36
#define REG_RXSRAM_CTL 0x1bd4
#define BIT_RPT_EN BIT(21)
#define BIT_RPT_SEL GENMASK(20, 16)
#define BIT_DPD_CLK GENMASK(7, 4)
#define REG_DPD_CTL11 0x1be4
#define REG_DPD_CTL12 0x1be8
#define REG_DPD_CTL15 0x1bf4
#define REG_DPD_CTL16 0x1bf8
#define REG_STAT_RPT 0x1bfc
#define BIT_RPT_DGAIN GENMASK(27, 16)
#define BIT_GAPK_RPT0 GENMASK(3, 0)
#define BIT_GAPK_RPT1 GENMASK(7, 4)
#define BIT_GAPK_RPT2 GENMASK(11, 8)
#define BIT_GAPK_RPT3 GENMASK(15, 12)
#define BIT_GAPK_RPT4 GENMASK(19, 16)
#define BIT_GAPK_RPT5 GENMASK(23, 20)
#define BIT_GAPK_RPT6 GENMASK(27, 24)
#define BIT_GAPK_RPT7 GENMASK(31, 28)
#define REG_TXANT 0x1c28
#define REG_IQK_CTRL 0x1c38
#define REG_ENCCK 0x1c3c
#define BIT_CCK_BLK_EN BIT(1)
#define BIT_CCK_OFDM_BLK_EN (BIT(0) | BIT(1))
#define REG_CCAMSK 0x1c80
#define REG_RSTB 0x1c90
#define BIT_RSTB_3WIRE BIT(8)
#define REG_CH_DELAY_EXTR2 0x1cd0
#define BIT_TST_IQK2SET_SRC BIT(31)
#define BIT_EN_IOQ_IQK_DPK BIT(30)
#define BIT_IQK_DPK_RESET_SRC BIT(29)
#define BIT_IQK_DPK_CLOCK_SRC BIT(28)
#define REG_RX_BREAK 0x1d2c
#define BIT_COM_RX_GCK_EN BIT(31)
#define REG_RXFNCTL 0x1d30
#define REG_CCA_OFF 0x1d58
#define BIT_CCA_ON_BY_PW GENMASK(11, 3)
#define REG_RXIGI 0x1d70
#define REG_ENFN 0x1e24
#define BIT_IQK_DPK_EN BIT(17)
#define REG_TXANTSEG 0x1e28
#define BIT_ANTSEG GENMASK(3, 0)
#define REG_TXLGMAP 0x1e2c
#define REG_CCKPATH 0x1e5c
#define REG_TX_FIFO 0x1e70
#define BIT_STOP_TX GENMASK(3, 0)
#define REG_CNT_CTRL 0x1eb4
#define BIT_ALL_CNT_RST BIT(25)
#define REG_OFDM_FACNT 0x2d00
#define REG_OFDM_FACNT1 0x2d04
#define REG_OFDM_FACNT2 0x2d08
#define REG_OFDM_FACNT3 0x2d0c
#define REG_OFDM_FACNT4 0x2d10
#define REG_OFDM_FACNT5 0x2d20
#define REG_RPT_CIP 0x2d9c
#define BIT_RPT_CIP_STATUS GENMASK(7, 0)
#define REG_OFDM_TXCNT 0x2de0
#define REG_ORITXCODE2 0x4100
#define REG_3WIRE2 0x410c
#define REG_ANAPAR_B 0x4130
#define REG_RFTXEN_GCK_B 0x4164
#define REG_DIS_SHARE_RX_B 0x416c
#define BIT_EXT_TIA_BW BIT(1)
#define REG_RXAGCCTL 0x41ac
#define REG_DCKB_I_0 0x41bc
#define REG_DCKB_I_1 0x41c0
#define REG_DCKB_Q_0 0x41d8
#define REG_DCKB_Q_1 0x41dc
#define RF_MODE_TRXAGC 0x00
#define BIT_RF_MODE GENMASK(19, 16)
#define BIT_RXAGC GENMASK(9, 5)
#define BIT_TXAGC GENMASK(4, 0)
#define RF_RXAGC_OFFSET 0x19
#define RF_BW_TRXBB 0x1a
#define BIT_TX_CCK_IND BIT(16)
#define BIT_BW_TXBB GENMASK(14, 12)
#define BIT_BW_RXBB GENMASK(11, 10)
#define BIT_DBG_CCK_CCA BIT(1)
#define RF_TX_GAIN_OFFSET 0x55
#define BIT_BB_GAIN GENMASK(18, 14)
#define BIT_RF_GAIN GENMASK(4, 2)
#define RF_TX_GAIN 0x56
#define BIT_GAIN_TXBB GENMASK(4, 0)
#define RF_IDAC 0x58
#define BIT_TX_MODE GENMASK(19, 8)
#define RF_TX_RESULT 0x5f
#define BIT_GAIN_TX_PAD_H GENMASK(11, 8)
#define BIT_GAIN_TX_PAD_L GENMASK(7, 4)
#define RF_PA 0x60
#define RF_PABIAS_2G_MASK GENMASK(15, 12)
#define RF_PABIAS_5G_MASK GENMASK(19, 16)
#define RF_TXA_LB_SW 0x63
#define BIT_TXA_LB_ATT GENMASK(15, 14)
#define BIT_LB_SW GENMASK(13, 12)
#define BIT_LB_ATT GENMASK(4, 2)
#define RF_RXG_GAIN 0x87
#define BIT_RXG_GAIN BIT(18)
#define RF_RXA_MIX_GAIN 0x8a
#define BIT_RXA_MIX_GAIN GENMASK(4, 3)
#define RF_EXT_TIA_BW 0x8f
#define BIT_PW_EXT_TIA BIT(1)
#define RF_DIS_BYPASS_TXBB 0x9e
#define BIT_TXBB BIT(10)
#define BIT_TIA_BYPASS BIT(5)
#define RF_DEBUG 0xde
#define BIT_DE_PWR_TRIM BIT(19)
#define BIT_DE_TX_GAIN BIT(16)
#define BIT_DE_TRXBW BIT(2)
#define PPG_THERMAL_B 0x1b0
#define RF_THEMAL_MASK GENMASK(19, 16)
#define PPG_2GH_TXAB 0x1d2
#define PPG_2G_A_MASK GENMASK(3, 0)
#define PPG_2G_B_MASK GENMASK(7, 4)
#define PPG_2GL_TXAB 0x1d4
#define PPG_PABIAS_2GB 0x1d5
#define PPG_PABIAS_2GA 0x1d6
#define PPG_PABIAS_MASK GENMASK(3, 0)
#define PPG_PABIAS_5GB 0x1d7
#define PPG_PABIAS_5GA 0x1d8
#define PPG_5G_MASK GENMASK(4, 0)
#define PPG_5GH1_TXB 0x1db
#define PPG_5GH1_TXA 0x1dc
#define PPG_5GM2_TXB 0x1df
#define PPG_5GM2_TXA 0x1e0
#define PPG_5GM1_TXB 0x1e3
#define PPG_5GM1_TXA 0x1e4
#define PPG_5GL2_TXB 0x1e7
#define PPG_5GL2_TXA 0x1e8
#define PPG_5GL1_TXB 0x1eb
#define PPG_5GL1_TXA 0x1ec
#define PPG_2GM_TXAB 0x1ee
#define PPG_THERMAL_A 0x1ef
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW8822C_TABLE_H__
#define __RTW8822C_TABLE_H__
extern const struct rtw_table rtw8822c_mac_tbl;
extern const struct rtw_table rtw8822c_agc_tbl;
extern const struct rtw_table rtw8822c_bb_tbl;
extern const struct rtw_table rtw8822c_bb_pg_type0_tbl;
extern const struct rtw_table rtw8822c_rf_a_tbl;
extern const struct rtw_table rtw8822c_rf_b_tbl;
extern const struct rtw_table rtw8822c_txpwr_lmt_type0_tbl;
extern const struct rtw_table rtw8822c_txpwr_lmt_type5_tbl;
extern const struct rtw_table rtw8822c_dpk_afe_no_dpk_tbl;
extern const struct rtw_table rtw8822c_dpk_afe_is_dpk_tbl;
extern const struct rtw_table rtw8822c_dpk_mac_bb_tbl;
extern const struct rtw_table rtw8822c_array_mp_cal_init_tbl;
#endif
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/pci.h>
#include "pci.h"
#include "rtw8822c.h"
static const struct pci_device_id rtw_8822ce_id_table[] = {
{
PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xC822),
.driver_data = (kernel_ulong_t)&rtw8822c_hw_spec
},
{
PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xC82F),
.driver_data = (kernel_ulong_t)&rtw8822c_hw_spec
},
{}
};
MODULE_DEVICE_TABLE(pci, rtw_8822ce_id_table);
static struct pci_driver rtw_8822ce_driver = {
.name = KBUILD_MODNAME,
.id_table = rtw_8822ce_id_table,
.probe = rtw_pci_probe,
.remove = rtw_pci_remove,
.driver.pm = &rtw_pm_ops,
.shutdown = rtw_pci_shutdown,
.err_handler = &rtw_pci_err_handler,
};
module_pci_driver(rtw_8822ce_driver);
MODULE_AUTHOR("Realtek Corporation");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822ce driver");
MODULE_LICENSE("Dual BSD/GPL");
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) Martin Blumenstingl <martin.blumenstingl@googlemail.com>
*/
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/module.h>
#include "main.h"
#include "rtw8822c.h"
#include "sdio.h"
static const struct sdio_device_id rtw_8822cs_id_table[] = {
{
SDIO_DEVICE(SDIO_VENDOR_ID_REALTEK,
SDIO_DEVICE_ID_REALTEK_RTW8822CS),
.driver_data = (kernel_ulong_t)&rtw8822c_hw_spec,
},
{}
};
MODULE_DEVICE_TABLE(sdio, rtw_8822cs_id_table);
static struct sdio_driver rtw_8822cs_driver = {
.name = KBUILD_MODNAME,
.probe = rtw_sdio_probe,
.remove = rtw_sdio_remove,
.shutdown = rtw_sdio_shutdown,
.id_table = rtw_8822cs_id_table,
.drv = {
.pm = &rtw_sdio_pm_ops,
}
};
module_sdio_driver(rtw_8822cs_driver);
MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822cs driver");
MODULE_LICENSE("Dual BSD/GPL");
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/usb.h>
#include "main.h"
#include "rtw8822c.h"
#include "usb.h"
static const struct usb_device_id rtw_8822cu_id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82c, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc812, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82e, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xd820, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xd82b, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x13b1, 0x0043, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) }, /* Alpha - Alpha */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3329, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) }, /* D-Link AC13U rev. A1 */
{},
};
MODULE_DEVICE_TABLE(usb, rtw_8822cu_id_table);
static int rtw8822cu_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return rtw_usb_probe(intf, id);
}
static struct usb_driver rtw_8822cu_driver = {
.name = KBUILD_MODNAME,
.id_table = rtw_8822cu_id_table,
.probe = rtw8822cu_probe,
.disconnect = rtw_usb_disconnect,
};
module_usb_driver(rtw_8822cu_driver);
MODULE_AUTHOR("Realtek Corporation");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822cu driver");
MODULE_LICENSE("Dual BSD/GPL");
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,175 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2024 Realtek Corporation
*/
#ifndef __RTW88XXA_H__
#define __RTW88XXA_H__
#include <asm/byteorder.h>
#include "reg.h"
struct rtw8821au_efuse {
u8 res4[48]; /* 0xd0 */
u8 vid[2]; /* 0x100 */
u8 pid[2];
u8 res8[3];
u8 mac_addr[ETH_ALEN]; /* 0x107 */
u8 res9[243];
} __packed;
struct rtw8812au_efuse {
u8 vid[2]; /* 0xd0 */
u8 pid[2]; /* 0xd2 */
u8 res0[3];
u8 mac_addr[ETH_ALEN]; /* 0xd7 */
u8 res1[291];
} __packed;
struct rtw88xxa_efuse {
__le16 rtl_id;
u8 res0[6]; /* 0x02 */
u8 usb_mode; /* 0x08 */
u8 res1[7]; /* 0x09 */
/* power index for four RF paths */
struct rtw_txpwr_idx txpwr_idx_table[4];
u8 channel_plan; /* 0xb8 */
u8 xtal_k;
u8 thermal_meter;
u8 iqk_lck;
u8 pa_type; /* 0xbc */
u8 lna_type_2g; /* 0xbd */
u8 res2;
u8 lna_type_5g; /* 0xbf */
u8 res3;
u8 rf_board_option; /* 0xc1 */
u8 rf_feature_option;
u8 rf_bt_setting;
u8 eeprom_version;
u8 eeprom_customer_id; /* 0xc5 */
u8 tx_bb_swing_setting_2g;
u8 tx_bb_swing_setting_5g;
u8 tx_pwr_calibrate_rate;
u8 rf_antenna_option; /* 0xc9 */
u8 rfe_option;
u8 country_code[2];
u8 res4[3];
union {
struct rtw8821au_efuse rtw8821au;
struct rtw8812au_efuse rtw8812au;
};
} __packed;
static_assert(sizeof(struct rtw88xxa_efuse) == 512);
#define WLAN_BCN_DMA_TIME 0x02
#define WLAN_TBTT_PROHIBIT 0x04
#define WLAN_TBTT_HOLD_TIME 0x064
#define WLAN_TBTT_TIME (WLAN_TBTT_PROHIBIT |\
(WLAN_TBTT_HOLD_TIME << BIT_SHIFT_TBTT_HOLD_TIME_AP))
struct rtw_jaguar_phy_status_rpt {
__le32 w0;
__le32 w1;
__le32 w2;
__le32 w3;
__le32 w4;
__le32 w5;
__le32 w6;
} __packed;
#define RTW_JGRPHY_W0_GAIN_A GENMASK(6, 0)
#define RTW_JGRPHY_W0_TRSW_A BIT(7)
#define RTW_JGRPHY_W0_GAIN_B GENMASK(14, 8)
#define RTW_JGRPHY_W0_TRSW_B BIT(15)
#define RTW_JGRPHY_W0_CHL_NUM GENMASK(25, 16)
#define RTW_JGRPHY_W0_SUB_CHNL GENMASK(29, 26)
#define RTW_JGRPHY_W0_R_RFMOD GENMASK(31, 30)
/* CCK: */
#define RTW_JGRPHY_W1_SIG_QUAL GENMASK(7, 0)
#define RTW_JGRPHY_W1_AGC_RPT_VGA_IDX GENMASK(12, 8)
#define RTW_JGRPHY_W1_AGC_RPT_LNA_IDX GENMASK(15, 13)
#define RTW_JGRPHY_W1_BB_POWER GENMASK(23, 16)
/* OFDM: */
#define RTW_JGRPHY_W1_PWDB_ALL GENMASK(7, 0)
#define RTW_JGRPHY_W1_CFO_SHORT_A GENMASK(15, 8) /* s8 */
#define RTW_JGRPHY_W1_CFO_SHORT_B GENMASK(23, 16) /* s8 */
#define RTW_JGRPHY_W1_BT_RF_CH_MSB GENMASK(31, 30)
#define RTW_JGRPHY_W2_ANT_DIV_SW_A BIT(0)
#define RTW_JGRPHY_W2_ANT_DIV_SW_B BIT(1)
#define RTW_JGRPHY_W2_BT_RF_CH_LSB GENMASK(7, 2)
#define RTW_JGRPHY_W2_CFO_TAIL_A GENMASK(15, 8) /* s8 */
#define RTW_JGRPHY_W2_CFO_TAIL_B GENMASK(23, 16) /* s8 */
#define RTW_JGRPHY_W2_PCTS_MSK_RPT_0 GENMASK(31, 24)
#define RTW_JGRPHY_W3_PCTS_MSK_RPT_1 GENMASK(7, 0)
/* Stream 1 and 2 RX EVM: */
#define RTW_JGRPHY_W3_RXEVM_1 GENMASK(15, 8) /* s8 */
#define RTW_JGRPHY_W3_RXEVM_2 GENMASK(23, 16) /* s8 */
#define RTW_JGRPHY_W3_RXSNR_A GENMASK(31, 24) /* s8 */
#define RTW_JGRPHY_W4_RXSNR_B GENMASK(7, 0) /* s8 */
#define RTW_JGRPHY_W4_PCTS_MSK_RPT_2 GENMASK(21, 8)
#define RTW_JGRPHY_W4_PCTS_RPT_VALID BIT(22)
#define RTW_JGRPHY_W4_RXEVM_3 GENMASK(31, 24) /* s8 */
#define RTW_JGRPHY_W5_RXEVM_4 GENMASK(7, 0) /* s8 */
/* 8812a, stream 1 and 2 CSI: */
#define RTW_JGRPHY_W5_CSI_CURRENT_1 GENMASK(15, 8)
#define RTW_JGRPHY_W5_CSI_CURRENT_2 GENMASK(23, 16)
/* 8814a: */
#define RTW_JGRPHY_W5_RXSNR_C GENMASK(15, 8) /* s8 */
#define RTW_JGRPHY_W5_RXSNR_D GENMASK(23, 16) /* s8 */
#define RTW_JGRPHY_W5_GAIN_C GENMASK(30, 24)
#define RTW_JGRPHY_W5_TRSW_C BIT(31)
#define RTW_JGRPHY_W6_GAIN_D GENMASK(6, 0)
#define RTW_JGRPHY_W6_TRSW_D BIT(7)
#define RTW_JGRPHY_W6_SIGEVM GENMASK(15, 8) /* s8 */
#define RTW_JGRPHY_W6_ANTIDX_ANTC GENMASK(18, 16)
#define RTW_JGRPHY_W6_ANTIDX_ANTD GENMASK(21, 19)
#define RTW_JGRPHY_W6_DPDT_CTRL_KEEP BIT(22)
#define RTW_JGRPHY_W6_GNT_BT_KEEP BIT(23)
#define RTW_JGRPHY_W6_ANTIDX_ANTA GENMASK(26, 24)
#define RTW_JGRPHY_W6_ANTIDX_ANTB GENMASK(29, 27)
#define RTW_JGRPHY_W6_HW_ANTSW_OCCUR GENMASK(31, 30)
#define RF18_BW_MASK (BIT(11) | BIT(10))
void rtw88xxa_efuse_grant(struct rtw_dev *rtwdev, bool on);
int rtw88xxa_read_efuse(struct rtw_dev *rtwdev, u8 *log_map);
void rtw88xxa_power_off(struct rtw_dev *rtwdev,
const struct rtw_pwr_seq_cmd *const *enter_lps_flow);
int rtw88xxa_power_on(struct rtw_dev *rtwdev);
u32 rtw88xxa_phy_read_rf(struct rtw_dev *rtwdev,
enum rtw_rf_path rf_path, u32 addr, u32 mask);
void rtw88xxa_set_channel(struct rtw_dev *rtwdev, u8 channel, u8 bw,
u8 primary_chan_idx);
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));
void rtw88xxa_set_tx_power_index(struct rtw_dev *rtwdev);
void rtw88xxa_false_alarm_statistics(struct rtw_dev *rtwdev);
void rtw88xxa_iqk_backup_mac_bb(struct rtw_dev *rtwdev,
u32 *macbb_backup,
const u32 *backup_macbb_reg,
u32 macbb_num);
void rtw88xxa_iqk_backup_afe(struct rtw_dev *rtwdev, u32 *afe_backup,
const u32 *backup_afe_reg, u32 afe_num);
void rtw88xxa_iqk_restore_mac_bb(struct rtw_dev *rtwdev,
u32 *macbb_backup,
const u32 *backup_macbb_reg,
u32 macbb_num);
void rtw88xxa_iqk_configure_mac(struct rtw_dev *rtwdev);
bool rtw88xxa_iqk_finish(int average, int threshold,
int *x_temp, int *y_temp, int *x, int *y,
bool break_inner, bool break_outer);
void rtw88xxa_phy_pwrtrack(struct rtw_dev *rtwdev,
void (*do_lck)(struct rtw_dev *rtwdev),
void (*do_iqk)(struct rtw_dev *rtwdev));
void rtw88xxa_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl);
#endif
@@ -0,0 +1,333 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include "main.h"
#include "mac.h"
#include "rx.h"
#include "ps.h"
#include "debug.h"
#include "fw.h"
void rtw_rx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
struct rtw_vif *rtwvif;
hdr = (struct ieee80211_hdr *)skb->data;
if (!ieee80211_is_data(hdr->frame_control))
return;
if (!is_broadcast_ether_addr(hdr->addr1) &&
!is_multicast_ether_addr(hdr->addr1)) {
rtwdev->stats.rx_unicast += skb->len;
rtwdev->stats.rx_cnt++;
if (vif) {
rtwvif = (struct rtw_vif *)vif->drv_priv;
rtwvif->stats.rx_unicast += skb->len;
rtwvif->stats.rx_cnt++;
}
}
}
EXPORT_SYMBOL(rtw_rx_stats);
struct rtw_rx_addr_match_data {
struct rtw_dev *rtwdev;
struct ieee80211_hdr *hdr;
struct rtw_rx_pkt_stat *pkt_stat;
u8 *bssid;
};
static void rtw_rx_phy_stat(struct rtw_dev *rtwdev,
struct rtw_rx_pkt_stat *pkt_stat,
struct ieee80211_hdr *hdr)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
struct rtw_pkt_count *cur_pkt_cnt = &dm_info->cur_pkt_count;
u8 rate_ss, rate_ss_evm, evm_id;
u8 i, idx;
dm_info->curr_rx_rate = pkt_stat->rate;
if (ieee80211_is_beacon(hdr->frame_control))
cur_pkt_cnt->num_bcn_pkt++;
switch (pkt_stat->rate) {
case DESC_RATE1M...DESC_RATE11M:
goto pkt_num;
case DESC_RATE6M...DESC_RATE54M:
rate_ss = 0;
rate_ss_evm = 1;
evm_id = RTW_EVM_OFDM;
break;
case DESC_RATEMCS0...DESC_RATEMCS7:
case DESC_RATEVHT1SS_MCS0...DESC_RATEVHT1SS_MCS9:
rate_ss = 1;
rate_ss_evm = 1;
evm_id = RTW_EVM_1SS;
break;
case DESC_RATEMCS8...DESC_RATEMCS15:
case DESC_RATEVHT2SS_MCS0...DESC_RATEVHT2SS_MCS9:
rate_ss = 2;
rate_ss_evm = 2;
evm_id = RTW_EVM_2SS_A;
break;
case DESC_RATEMCS16...DESC_RATEMCS23:
case DESC_RATEVHT3SS_MCS0...DESC_RATEVHT3SS_MCS9:
rate_ss = 3;
rate_ss_evm = 3;
evm_id = RTW_EVM_3SS_A;
break;
default:
rtw_warn(rtwdev, "unknown pkt rate = %d\n", pkt_stat->rate);
return;
}
for (i = 0; i < rate_ss_evm; i++) {
idx = evm_id + i;
ewma_evm_add(&dm_info->ewma_evm[idx],
dm_info->rx_evm_dbm[i]);
}
for (i = 0; i < rtwdev->hal.rf_path_num; i++) {
idx = RTW_SNR_OFDM_A + 4 * rate_ss + i;
ewma_snr_add(&dm_info->ewma_snr[idx],
dm_info->rx_snr[i]);
}
pkt_num:
cur_pkt_cnt->num_qry_pkt[pkt_stat->rate]++;
}
static void rtw_rx_addr_match_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct rtw_rx_addr_match_data *iter_data = data;
struct ieee80211_sta *sta;
struct ieee80211_hdr *hdr = iter_data->hdr;
struct rtw_dev *rtwdev = iter_data->rtwdev;
struct rtw_sta_info *si;
struct rtw_rx_pkt_stat *pkt_stat = iter_data->pkt_stat;
u8 *bssid = iter_data->bssid;
if (!ether_addr_equal(vif->bss_conf.bssid, bssid))
return;
if (!(ether_addr_equal(vif->addr, hdr->addr1) ||
ieee80211_is_beacon(hdr->frame_control)))
return;
rtw_rx_phy_stat(rtwdev, pkt_stat, hdr);
sta = ieee80211_find_sta_by_ifaddr(rtwdev->hw, hdr->addr2,
vif->addr);
if (!sta)
return;
si = (struct rtw_sta_info *)sta->drv_priv;
ewma_rssi_add(&si->avg_rssi, pkt_stat->rssi);
}
static void rtw_rx_addr_match(struct rtw_dev *rtwdev,
struct rtw_rx_pkt_stat *pkt_stat,
struct ieee80211_hdr *hdr)
{
struct rtw_rx_addr_match_data data = {};
if (pkt_stat->crc_err || pkt_stat->icv_err || !pkt_stat->phy_status ||
ieee80211_is_ctl(hdr->frame_control))
return;
data.rtwdev = rtwdev;
data.hdr = hdr;
data.pkt_stat = pkt_stat;
data.bssid = get_hdr_bssid(hdr);
rtw_iterate_vifs_atomic(rtwdev, rtw_rx_addr_match_iter, &data);
}
static void rtw_set_rx_freq_by_pktstat(struct rtw_rx_pkt_stat *pkt_stat,
struct ieee80211_rx_status *rx_status)
{
rx_status->freq = pkt_stat->freq;
rx_status->band = pkt_stat->band;
}
void rtw_update_rx_freq_from_ie(struct rtw_dev *rtwdev, struct sk_buff *skb,
struct ieee80211_rx_status *rx_status,
struct rtw_rx_pkt_stat *pkt_stat)
{
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
int channel = rtwdev->hal.current_channel;
size_t hdr_len, ielen;
int channel_number;
u8 *variable;
if (!test_bit(RTW_FLAG_SCANNING, rtwdev->flags))
goto fill_rx_status;
if (ieee80211_is_beacon(mgmt->frame_control)) {
variable = mgmt->u.beacon.variable;
hdr_len = offsetof(struct ieee80211_mgmt,
u.beacon.variable);
} else if (ieee80211_is_probe_resp(mgmt->frame_control)) {
variable = mgmt->u.probe_resp.variable;
hdr_len = offsetof(struct ieee80211_mgmt,
u.probe_resp.variable);
} else {
goto fill_rx_status;
}
if (skb->len > hdr_len)
ielen = skb->len - hdr_len;
else
goto fill_rx_status;
channel_number = cfg80211_get_ies_channel_number(variable, ielen,
NL80211_BAND_2GHZ);
if (channel_number != -1)
channel = channel_number;
fill_rx_status:
rtw_set_rx_freq_band(pkt_stat, channel);
rtw_set_rx_freq_by_pktstat(pkt_stat, rx_status);
}
EXPORT_SYMBOL(rtw_update_rx_freq_from_ie);
static void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev,
struct rtw_rx_pkt_stat *pkt_stat,
struct ieee80211_hdr *hdr,
struct ieee80211_rx_status *rx_status)
{
struct ieee80211_hw *hw = rtwdev->hw;
u8 path;
memset(rx_status, 0, sizeof(*rx_status));
rx_status->freq = hw->conf.chandef.chan->center_freq;
rx_status->band = hw->conf.chandef.chan->band;
if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD) &&
test_bit(RTW_FLAG_SCANNING, rtwdev->flags))
rtw_set_rx_freq_by_pktstat(pkt_stat, rx_status);
if (pkt_stat->crc_err)
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
if (pkt_stat->decrypted)
rx_status->flag |= RX_FLAG_DECRYPTED;
if (pkt_stat->rate >= DESC_RATEVHT1SS_MCS0)
rx_status->encoding = RX_ENC_VHT;
else if (pkt_stat->rate >= DESC_RATEMCS0)
rx_status->encoding = RX_ENC_HT;
if (rx_status->band == NL80211_BAND_5GHZ &&
pkt_stat->rate >= DESC_RATE6M &&
pkt_stat->rate <= DESC_RATE54M) {
rx_status->rate_idx = pkt_stat->rate - DESC_RATE6M;
} else if (rx_status->band == NL80211_BAND_2GHZ &&
pkt_stat->rate >= DESC_RATE1M &&
pkt_stat->rate <= DESC_RATE54M) {
rx_status->rate_idx = pkt_stat->rate - DESC_RATE1M;
} else if (pkt_stat->rate >= DESC_RATEMCS0) {
rtw_desc_to_mcsrate(pkt_stat->rate, &rx_status->rate_idx,
&rx_status->nss);
}
rx_status->flag |= RX_FLAG_MACTIME_START;
rx_status->mactime = pkt_stat->tsf_low;
if (pkt_stat->bw == RTW_CHANNEL_WIDTH_80)
rx_status->bw = RATE_INFO_BW_80;
else if (pkt_stat->bw == RTW_CHANNEL_WIDTH_40)
rx_status->bw = RATE_INFO_BW_40;
else
rx_status->bw = RATE_INFO_BW_20;
if (pkt_stat->phy_status) {
rx_status->signal = pkt_stat->signal_power;
for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
rx_status->chains |= BIT(path);
rx_status->chain_signal[path] = pkt_stat->rx_power[path];
}
} else {
rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
}
rtw_rx_addr_match(rtwdev, pkt_stat, hdr);
/* Rtl8723cs driver checks for size < 14 or size > 8192 and
* simply drops the packet.
*/
if (rtwdev->chip->id == RTW_CHIP_TYPE_8703B && pkt_stat->pkt_len == 0) {
rx_status->flag |= RX_FLAG_NO_PSDU;
rtw_dbg(rtwdev, RTW_DBG_RX, "zero length packet");
}
}
int rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8,
struct rtw_rx_pkt_stat *pkt_stat,
struct ieee80211_rx_status *rx_status)
{
u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz;
struct rtw_rx_desc *rx_desc = rx_desc8;
struct ieee80211_hdr *hdr;
u32 enc_type, swdec;
void *phy_status;
memset(pkt_stat, 0, sizeof(*pkt_stat));
pkt_stat->pkt_len = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_PKT_LEN);
pkt_stat->crc_err = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_CRC32);
pkt_stat->icv_err = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_ICV_ERR);
pkt_stat->drv_info_sz = le32_get_bits(rx_desc->w0,
RTW_RX_DESC_W0_DRV_INFO_SIZE);
enc_type = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_ENC_TYPE);
pkt_stat->shift = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_SHIFT);
pkt_stat->phy_status = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_PHYST);
swdec = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_SWDEC);
pkt_stat->decrypted = !swdec && enc_type != RX_DESC_ENC_NONE;
pkt_stat->cam_id = le32_get_bits(rx_desc->w1, RTW_RX_DESC_W1_MACID);
pkt_stat->is_c2h = le32_get_bits(rx_desc->w2, RTW_RX_DESC_W2_C2H);
pkt_stat->ppdu_cnt = le32_get_bits(rx_desc->w2, RTW_RX_DESC_W2_PPDU_CNT);
pkt_stat->rate = le32_get_bits(rx_desc->w3, RTW_RX_DESC_W3_RX_RATE);
pkt_stat->bw = le32_get_bits(rx_desc->w4, RTW_RX_DESC_W4_BW);
pkt_stat->tsf_low = le32_get_bits(rx_desc->w5, RTW_RX_DESC_W5_TSFL);
if (unlikely(pkt_stat->rate >= DESC_RATE_MAX))
return -EINVAL;
if (unlikely(pkt_stat->drv_info_sz &&
pkt_stat->drv_info_sz != PHY_STATUS_SIZE))
return -EINVAL;
if (unlikely(pkt_stat->phy_status && !pkt_stat->drv_info_sz))
return -EINVAL;
if (unlikely(pkt_stat->pkt_len > IEEE80211_MAX_MPDU_LEN_VHT_11454))
return -EINVAL;
/* drv_info_sz is in unit of 8-bytes */
pkt_stat->drv_info_sz *= 8;
/* c2h cmd pkt's rx/phy status is not interested */
if (pkt_stat->is_c2h)
return 0;
if (unlikely(pkt_stat->pkt_len <= FCS_LEN))
return -EINVAL;
phy_status = rx_desc8 + desc_sz + pkt_stat->shift;
hdr = phy_status + pkt_stat->drv_info_sz;
pkt_stat->hdr = hdr;
if (pkt_stat->phy_status)
rtwdev->chip->ops->query_phy_status(rtwdev, phy_status, pkt_stat);
rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status);
return 0;
}
EXPORT_SYMBOL(rtw_rx_query_rx_desc);
@@ -0,0 +1,65 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_RX_H_
#define __RTW_RX_H_
enum rtw_rx_desc_enc {
RX_DESC_ENC_NONE = 0,
RX_DESC_ENC_WEP40 = 1,
RX_DESC_ENC_TKIP_WO_MIC = 2,
RX_DESC_ENC_TKIP_MIC = 3,
RX_DESC_ENC_AES = 4,
RX_DESC_ENC_WEP104 = 5,
};
struct rtw_rx_desc {
__le32 w0;
__le32 w1;
__le32 w2;
__le32 w3;
__le32 w4;
__le32 w5;
} __packed;
#define RTW_RX_DESC_W0_PKT_LEN GENMASK(13, 0)
#define RTW_RX_DESC_W0_CRC32 BIT(14)
#define RTW_RX_DESC_W0_ICV_ERR BIT(15)
#define RTW_RX_DESC_W0_DRV_INFO_SIZE GENMASK(19, 16)
#define RTW_RX_DESC_W0_ENC_TYPE GENMASK(22, 20)
#define RTW_RX_DESC_W0_SHIFT GENMASK(25, 24)
#define RTW_RX_DESC_W0_PHYST BIT(26)
#define RTW_RX_DESC_W0_SWDEC BIT(27)
#define RTW_RX_DESC_W1_MACID GENMASK(6, 0)
#define RTW_RX_DESC_W2_C2H BIT(28)
#define RTW_RX_DESC_W2_PPDU_CNT GENMASK(30, 29)
#define RTW_RX_DESC_W3_RX_RATE GENMASK(6, 0)
#define RTW_RX_DESC_W4_BW GENMASK(5, 4)
#define RTW_RX_DESC_W5_TSFL GENMASK(31, 0)
void rtw_rx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct sk_buff *skb);
int rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8,
struct rtw_rx_pkt_stat *pkt_stat,
struct ieee80211_rx_status *rx_status);
void rtw_update_rx_freq_from_ie(struct rtw_dev *rtwdev, struct sk_buff *skb,
struct ieee80211_rx_status *rx_status,
struct rtw_rx_pkt_stat *pkt_stat);
static inline
void rtw_update_rx_freq_for_invalid(struct rtw_dev *rtwdev, struct sk_buff *skb,
struct ieee80211_rx_status *rx_status,
struct rtw_rx_pkt_stat *pkt_stat)
{
if (pkt_stat->channel_invalid)
rtw_update_rx_freq_from_ie(rtwdev, skb, rx_status, pkt_stat);
}
#endif
@@ -0,0 +1,114 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2021 Realtek Corporation
*/
#include "sar.h"
#include "phy.h"
#include "debug.h"
s8 rtw_query_sar(struct rtw_dev *rtwdev, const struct rtw_sar_arg *arg)
{
const struct rtw_hal *hal = &rtwdev->hal;
const struct rtw_sar *sar = &hal->sar;
switch (sar->src) {
default:
rtw_warn(rtwdev, "unknown SAR source: %d\n", sar->src);
fallthrough;
case RTW_SAR_SOURCE_NONE:
return (s8)rtwdev->chip->max_power_index;
case RTW_SAR_SOURCE_COMMON:
return sar->cfg[arg->path][arg->rs].common[arg->sar_band];
}
}
static int rtw_apply_sar(struct rtw_dev *rtwdev, const struct rtw_sar *new)
{
struct rtw_hal *hal = &rtwdev->hal;
struct rtw_sar *sar = &hal->sar;
if (sar->src != RTW_SAR_SOURCE_NONE && new->src != sar->src) {
rtw_warn(rtwdev, "SAR source: %d is in use\n", sar->src);
return -EBUSY;
}
*sar = *new;
rtw_phy_set_tx_power_level(rtwdev, hal->current_channel);
return 0;
}
static s8 rtw_sar_to_phy(struct rtw_dev *rtwdev, u8 fct, s32 sar,
const struct rtw_sar_arg *arg)
{
struct rtw_hal *hal = &rtwdev->hal;
u8 txgi = rtwdev->chip->txgi_factor;
u8 max = rtwdev->chip->max_power_index;
s32 tmp;
s8 base;
tmp = fct > txgi ? sar >> (fct - txgi) : sar << (txgi - fct);
base = arg->sar_band == RTW_SAR_BAND_0 ?
hal->tx_pwr_by_rate_base_2g[arg->path][arg->rs] :
hal->tx_pwr_by_rate_base_5g[arg->path][arg->rs];
return (s8)clamp_t(s32, tmp, -max - 1, max) - base;
}
static const struct cfg80211_sar_freq_ranges rtw_common_sar_freq_ranges[] = {
[RTW_SAR_BAND_0] = { .start_freq = 2412, .end_freq = 2484, },
[RTW_SAR_BAND_1] = { .start_freq = 5180, .end_freq = 5320, },
[RTW_SAR_BAND_3] = { .start_freq = 5500, .end_freq = 5720, },
[RTW_SAR_BAND_4] = { .start_freq = 5745, .end_freq = 5825, },
};
static_assert(ARRAY_SIZE(rtw_common_sar_freq_ranges) == RTW_SAR_BAND_NR);
const struct cfg80211_sar_capa rtw_sar_capa = {
.type = NL80211_SAR_TYPE_POWER,
.num_freq_ranges = RTW_SAR_BAND_NR,
.freq_ranges = rtw_common_sar_freq_ranges,
};
int rtw_set_sar_specs(struct rtw_dev *rtwdev,
const struct cfg80211_sar_specs *sar)
{
struct rtw_sar_arg arg = {0};
struct rtw_sar new = {0};
u32 idx, i, j, k;
s32 power;
s8 val;
if (sar->type != NL80211_SAR_TYPE_POWER)
return -EINVAL;
memset(&new, rtwdev->chip->max_power_index, sizeof(new));
new.src = RTW_SAR_SOURCE_COMMON;
for (i = 0; i < sar->num_sub_specs; i++) {
idx = sar->sub_specs[i].freq_range_index;
if (idx >= RTW_SAR_BAND_NR)
return -EINVAL;
power = sar->sub_specs[i].power;
rtw_dbg(rtwdev, RTW_DBG_REGD, "On freq %u to %u, set SAR %d in 1/%lu dBm\n",
rtw_common_sar_freq_ranges[idx].start_freq,
rtw_common_sar_freq_ranges[idx].end_freq,
power, BIT(RTW_COMMON_SAR_FCT));
for (j = 0; j < RTW_RF_PATH_MAX; j++) {
for (k = 0; k < RTW_RATE_SECTION_NUM; k++) {
arg = (struct rtw_sar_arg){
.sar_band = idx,
.path = j,
.rs = k,
};
val = rtw_sar_to_phy(rtwdev, RTW_COMMON_SAR_FCT,
power, &arg);
new.cfg[j][k].common[idx] = val;
}
}
}
return rtw_apply_sar(rtwdev, &new);
}
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2021 Realtek Corporation
*/
#include "main.h"
/* NL80211_SAR_TYPE_POWER means unit is in 0.25 dBm,
* where 0.25 = 1/4 = 2^(-2), so make factor 2.
*/
#define RTW_COMMON_SAR_FCT 2
struct rtw_sar_arg {
u8 sar_band;
u8 path;
u8 rs;
};
extern const struct cfg80211_sar_capa rtw_sar_capa;
s8 rtw_query_sar(struct rtw_dev *rtwdev, const struct rtw_sar_arg *arg);
int rtw_set_sar_specs(struct rtw_dev *rtwdev,
const struct cfg80211_sar_specs *sar);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,178 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright (C) 2021 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
* Copyright (C) 2021 Jernej Skrabec <jernej.skrabec@gmail.com>
*/
#ifndef __REG_SDIO_H_
#define __REG_SDIO_H_
/* I/O bus domain address mapping */
#define SDIO_LOCAL_OFFSET 0x10250000
#define WLAN_IOREG_OFFSET 0x10260000
#define FIRMWARE_FIFO_OFFSET 0x10270000
#define TX_HIQ_OFFSET 0x10310000
#define TX_MIQ_OFFSET 0x10320000
#define TX_LOQ_OFFSET 0x10330000
#define TX_EPQ_OFFSET 0x10350000
#define RX_RX0FF_OFFSET 0x10340000
#define RTW_SDIO_BUS_MSK 0xffff0000
#define SDIO_LOCAL_REG_MSK 0x00000fff
#define WLAN_IOREG_REG_MSK 0x0000ffff
/* SDIO Tx Control */
#define REG_SDIO_TX_CTRL (SDIO_LOCAL_OFFSET + 0x0000)
/*SDIO status timeout*/
#define REG_SDIO_TIMEOUT (SDIO_LOCAL_OFFSET + 0x0002)
/* SDIO Host Interrupt Mask */
#define REG_SDIO_HIMR (SDIO_LOCAL_OFFSET + 0x0014)
#define REG_SDIO_HIMR_RX_REQUEST BIT(0)
#define REG_SDIO_HIMR_AVAL BIT(1)
#define REG_SDIO_HIMR_TXERR BIT(2)
#define REG_SDIO_HIMR_RXERR BIT(3)
#define REG_SDIO_HIMR_TXFOVW BIT(4)
#define REG_SDIO_HIMR_RXFOVW BIT(5)
#define REG_SDIO_HIMR_TXBCNOK BIT(6)
#define REG_SDIO_HIMR_TXBCNERR BIT(7)
#define REG_SDIO_HIMR_BCNERLY_INT BIT(16)
#define REG_SDIO_HIMR_C2HCMD BIT(17)
#define REG_SDIO_HIMR_CPWM1 BIT(18)
#define REG_SDIO_HIMR_CPWM2 BIT(19)
#define REG_SDIO_HIMR_HSISR_IND BIT(20)
#define REG_SDIO_HIMR_GTINT3_IND BIT(21)
#define REG_SDIO_HIMR_GTINT4_IND BIT(22)
#define REG_SDIO_HIMR_PSTIMEOUT BIT(23)
#define REG_SDIO_HIMR_OCPINT BIT(24)
#define REG_SDIO_HIMR_ATIMEND BIT(25)
#define REG_SDIO_HIMR_ATIMEND_E BIT(26)
#define REG_SDIO_HIMR_CTWEND BIT(27)
/* the following two are RTL8188 SDIO Specific */
#define REG_SDIO_HIMR_MCU_ERR BIT(28)
#define REG_SDIO_HIMR_TSF_BIT32_TOGGLE BIT(29)
/* SDIO Host Interrupt Service Routine */
#define REG_SDIO_HISR (SDIO_LOCAL_OFFSET + 0x0018)
#define REG_SDIO_HISR_RX_REQUEST BIT(0)
#define REG_SDIO_HISR_AVAL BIT(1)
#define REG_SDIO_HISR_TXERR BIT(2)
#define REG_SDIO_HISR_RXERR BIT(3)
#define REG_SDIO_HISR_TXFOVW BIT(4)
#define REG_SDIO_HISR_RXFOVW BIT(5)
#define REG_SDIO_HISR_TXBCNOK BIT(6)
#define REG_SDIO_HISR_TXBCNERR BIT(7)
#define REG_SDIO_HISR_BCNERLY_INT BIT(16)
#define REG_SDIO_HISR_C2HCMD BIT(17)
#define REG_SDIO_HISR_CPWM1 BIT(18)
#define REG_SDIO_HISR_CPWM2 BIT(19)
#define REG_SDIO_HISR_HSISR_IND BIT(20)
#define REG_SDIO_HISR_GTINT3_IND BIT(21)
#define REG_SDIO_HISR_GTINT4_IND BIT(22)
#define REG_SDIO_HISR_PSTIMEOUT BIT(23)
#define REG_SDIO_HISR_OCPINT BIT(24)
#define REG_SDIO_HISR_ATIMEND BIT(25)
#define REG_SDIO_HISR_ATIMEND_E BIT(26)
#define REG_SDIO_HISR_CTWEND BIT(27)
/* the following two are RTL8188 SDIO Specific */
#define REG_SDIO_HISR_MCU_ERR BIT(28)
#define REG_SDIO_HISR_TSF_BIT32_TOGGLE BIT(29)
/* HCI Current Power Mode */
#define REG_SDIO_HCPWM (SDIO_LOCAL_OFFSET + 0x0019)
/* RXDMA Request Length */
#define REG_SDIO_RX0_REQ_LEN (SDIO_LOCAL_OFFSET + 0x001C)
/* OQT Free Page */
#define REG_SDIO_OQT_FREE_PG (SDIO_LOCAL_OFFSET + 0x001E)
/* Free Tx Buffer Page */
#define REG_SDIO_FREE_TXPG (SDIO_LOCAL_OFFSET + 0x0020)
/* HCI Current Power Mode 1 */
#define REG_SDIO_HCPWM1 (SDIO_LOCAL_OFFSET + 0x0024)
/* HCI Current Power Mode 2 */
#define REG_SDIO_HCPWM2 (SDIO_LOCAL_OFFSET + 0x0026)
/* Free Tx Page Sequence */
#define REG_SDIO_FREE_TXPG_SEQ (SDIO_LOCAL_OFFSET + 0x0028)
/* HTSF Information */
#define REG_SDIO_HTSFR_INFO (SDIO_LOCAL_OFFSET + 0x0030)
#define REG_SDIO_HCPWM1_V2 (SDIO_LOCAL_OFFSET + 0x0038)
/* H2C */
#define REG_SDIO_H2C (SDIO_LOCAL_OFFSET + 0x0060)
/* HCI Request Power Mode 1 */
#define REG_SDIO_HRPWM1 (SDIO_LOCAL_OFFSET + 0x0080)
/* HCI Request Power Mode 2 */
#define REG_SDIO_HRPWM2 (SDIO_LOCAL_OFFSET + 0x0082)
/* HCI Power Save Clock */
#define REG_SDIO_HPS_CLKR (SDIO_LOCAL_OFFSET + 0x0084)
/* SDIO HCI Suspend Control */
#define REG_SDIO_HSUS_CTRL (SDIO_LOCAL_OFFSET + 0x0086)
#define BIT_HCI_SUS_REQ BIT(0)
#define BIT_HCI_RESUME_RDY BIT(1)
/* SDIO Host Extension Interrupt Mask Always */
#define REG_SDIO_HIMR_ON (SDIO_LOCAL_OFFSET + 0x0090)
/* SDIO Host Extension Interrupt Status Always */
#define REG_SDIO_HISR_ON (SDIO_LOCAL_OFFSET + 0x0091)
#define REG_SDIO_INDIRECT_REG_CFG (SDIO_LOCAL_OFFSET + 0x0040)
#define BIT_SDIO_INDIRECT_REG_CFG_WORD BIT(16)
#define BIT_SDIO_INDIRECT_REG_CFG_DWORD BIT(17)
#define BIT_SDIO_INDIRECT_REG_CFG_WRITE BIT(18)
#define BIT_SDIO_INDIRECT_REG_CFG_READ BIT(19)
#define BIT_SDIO_INDIRECT_REG_CFG_UNK20 BIT(20)
#define REG_SDIO_INDIRECT_REG_DATA (SDIO_LOCAL_OFFSET + 0x0044)
/* Sdio Address for SDIO Local Reg, TRX FIFO, MAC Reg */
#define REG_SDIO_CMD_ADDR_MSK GENMASK(16, 13)
#define REG_SDIO_CMD_ADDR_SDIO_REG 0
#define REG_SDIO_CMD_ADDR_MAC_REG 8
#define REG_SDIO_CMD_ADDR_TXFF_HIGH 4
#define REG_SDIO_CMD_ADDR_TXFF_LOW 6
#define REG_SDIO_CMD_ADDR_TXFF_NORMAL 5
#define REG_SDIO_CMD_ADDR_TXFF_EXTRA 7
#define REG_SDIO_CMD_ADDR_RXFF 7
#define RTW_SDIO_BLOCK_SIZE 512
#define RTW_SDIO_ADDR_RX_RX0FF_GEN(_id) (0x0e000 | ((_id) & 0x3))
#define RTW_SDIO_DATA_PTR_ALIGN 8
struct sdio_func;
struct sdio_device_id;
struct rtw_sdio_tx_data {
u8 sn;
};
struct rtw_sdio_work_data {
struct work_struct work;
struct rtw_dev *rtwdev;
};
struct rtw_sdio {
struct sdio_func *sdio_func;
u32 irq_mask;
u8 rx_addr;
bool sdio3_bus_mode;
void *irq_thread;
struct workqueue_struct *txwq;
struct rtw_sdio_work_data *tx_handler_data;
struct sk_buff_head tx_queue[RTK_MAX_TX_QUEUE_NUM];
};
extern const struct dev_pm_ops rtw_sdio_pm_ops;
int rtw_sdio_probe(struct sdio_func *sdio_func,
const struct sdio_device_id *id);
void rtw_sdio_remove(struct sdio_func *sdio_func);
void rtw_sdio_shutdown(struct sdio_func *sdio_func);
static inline bool rtw_sdio_is_sdio30_supported(struct rtw_dev *rtwdev)
{
struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv;
return rtwsdio->sdio3_bus_mode;
}
#endif
@@ -0,0 +1,145 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include "main.h"
#include "sec.h"
#include "reg.h"
int rtw_sec_get_free_cam(struct rtw_sec_desc *sec)
{
/* if default key search is enabled, the first 4 cam entries
* are used to direct map to group key with its key->key_idx, so
* driver should use cam entries after 4 to install pairwise key
*/
if (sec->default_key_search)
return find_next_zero_bit(sec->cam_map, RTW_MAX_SEC_CAM_NUM,
RTW_SEC_DEFAULT_KEY_NUM);
return find_first_zero_bit(sec->cam_map, RTW_MAX_SEC_CAM_NUM);
}
void rtw_sec_write_cam(struct rtw_dev *rtwdev,
struct rtw_sec_desc *sec,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key,
u8 hw_key_type, u8 hw_key_idx)
{
struct rtw_cam_entry *cam = &sec->cam_table[hw_key_idx];
u32 write_cmd;
u32 command;
u32 content;
u32 addr;
int i, j;
set_bit(hw_key_idx, sec->cam_map);
cam->valid = true;
cam->group = !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE);
cam->hw_key_type = hw_key_type;
cam->key = key;
if (sta)
ether_addr_copy(cam->addr, sta->addr);
else
eth_broadcast_addr(cam->addr);
write_cmd = RTW_SEC_CMD_WRITE_ENABLE | RTW_SEC_CMD_POLLING;
addr = hw_key_idx << RTW_SEC_CAM_ENTRY_SHIFT;
for (i = 7; i >= 0; i--) {
switch (i) {
case 0:
content = ((key->keyidx & 0x3)) |
((hw_key_type & 0x7) << 2) |
(cam->group << 6) |
(cam->valid << 15) |
(cam->addr[0] << 16) |
(cam->addr[1] << 24);
break;
case 1:
content = (cam->addr[2]) |
(cam->addr[3] << 8) |
(cam->addr[4] << 16) |
(cam->addr[5] << 24);
break;
case 6:
case 7:
content = 0;
break;
default:
j = (i - 2) << 2;
content = (key->key[j]) |
(key->key[j + 1] << 8) |
(key->key[j + 2] << 16) |
(key->key[j + 3] << 24);
break;
}
command = write_cmd | (addr + i);
rtw_write32(rtwdev, RTW_SEC_WRITE_REG, content);
rtw_write32(rtwdev, RTW_SEC_CMD_REG, command);
}
}
void rtw_sec_clear_cam(struct rtw_dev *rtwdev,
struct rtw_sec_desc *sec,
u8 hw_key_idx)
{
struct rtw_cam_entry *cam = &sec->cam_table[hw_key_idx];
u32 write_cmd;
u32 command;
u32 addr;
clear_bit(hw_key_idx, sec->cam_map);
cam->valid = false;
cam->key = NULL;
eth_zero_addr(cam->addr);
write_cmd = RTW_SEC_CMD_WRITE_ENABLE | RTW_SEC_CMD_POLLING;
addr = hw_key_idx << RTW_SEC_CAM_ENTRY_SHIFT;
command = write_cmd | addr;
rtw_write32(rtwdev, RTW_SEC_WRITE_REG, 0);
rtw_write32(rtwdev, RTW_SEC_CMD_REG, command);
}
u8 rtw_sec_cam_pg_backup(struct rtw_dev *rtwdev, u8 *used_cam)
{
struct rtw_sec_desc *sec = &rtwdev->sec;
u8 offset = 0;
u8 count, n;
if (!used_cam)
return 0;
for (count = 0; count < MAX_PG_CAM_BACKUP_NUM; count++) {
n = find_next_bit(sec->cam_map, RTW_MAX_SEC_CAM_NUM, offset);
if (n == RTW_MAX_SEC_CAM_NUM)
break;
used_cam[count] = n;
offset = n + 1;
}
return count;
}
void rtw_sec_enable_sec_engine(struct rtw_dev *rtwdev)
{
struct rtw_sec_desc *sec = &rtwdev->sec;
u16 ctrl_reg;
u16 sec_config;
/* default use default key search for now */
sec->default_key_search = true;
ctrl_reg = rtw_read16(rtwdev, REG_CR);
ctrl_reg |= RTW_SEC_ENGINE_EN;
rtw_write16(rtwdev, REG_CR, ctrl_reg);
sec_config = rtw_read16(rtwdev, RTW_SEC_CONFIG);
sec_config |= RTW_SEC_TX_DEC_EN | RTW_SEC_RX_DEC_EN;
if (sec->default_key_search)
sec_config |= RTW_SEC_TX_UNI_USE_DK | RTW_SEC_RX_UNI_USE_DK |
RTW_SEC_TX_BC_USE_DK | RTW_SEC_RX_BC_USE_DK;
rtw_write16(rtwdev, RTW_SEC_CONFIG, sec_config);
}
@@ -0,0 +1,40 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_SEC_H_
#define __RTW_SEC_H_
#define RTW_SEC_CMD_REG 0x670
#define RTW_SEC_WRITE_REG 0x674
#define RTW_SEC_READ_REG 0x678
#define RTW_SEC_CONFIG 0x680
#define RTW_SEC_CAM_ENTRY_SHIFT 3
#define RTW_SEC_DEFAULT_KEY_NUM 4
#define RTW_SEC_CMD_WRITE_ENABLE BIT(16)
#define RTW_SEC_CMD_CLEAR BIT(30)
#define RTW_SEC_CMD_POLLING BIT(31)
#define RTW_SEC_TX_UNI_USE_DK BIT(0)
#define RTW_SEC_RX_UNI_USE_DK BIT(1)
#define RTW_SEC_TX_DEC_EN BIT(2)
#define RTW_SEC_RX_DEC_EN BIT(3)
#define RTW_SEC_TX_BC_USE_DK BIT(6)
#define RTW_SEC_RX_BC_USE_DK BIT(7)
#define RTW_SEC_ENGINE_EN BIT(9)
int rtw_sec_get_free_cam(struct rtw_sec_desc *sec);
void rtw_sec_write_cam(struct rtw_dev *rtwdev,
struct rtw_sec_desc *sec,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key,
u8 hw_key_type, u8 hw_key_idx);
void rtw_sec_clear_cam(struct rtw_dev *rtwdev,
struct rtw_sec_desc *sec,
u8 hw_key_idx);
u8 rtw_sec_cam_pg_backup(struct rtw_dev *rtwdev, u8 *used_cam);
void rtw_sec_enable_sec_engine(struct rtw_dev *rtwdev);
#endif
@@ -0,0 +1,745 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include "main.h"
#include "tx.h"
#include "fw.h"
#include "ps.h"
#include "debug.h"
static
void rtw_tx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
struct rtw_vif *rtwvif;
hdr = (struct ieee80211_hdr *)skb->data;
if (!ieee80211_is_data(hdr->frame_control))
return;
if (!is_broadcast_ether_addr(hdr->addr1) &&
!is_multicast_ether_addr(hdr->addr1)) {
rtwdev->stats.tx_unicast += skb->len;
rtwdev->stats.tx_cnt++;
if (vif) {
rtwvif = (struct rtw_vif *)vif->drv_priv;
rtwvif->stats.tx_unicast += skb->len;
rtwvif->stats.tx_cnt++;
}
}
}
void rtw_tx_fill_tx_desc(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb)
{
struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data;
bool more_data = false;
if (pkt_info->qsel == TX_DESC_QSEL_HIGH)
more_data = true;
tx_desc->w0 = le32_encode_bits(pkt_info->tx_pkt_size, RTW_TX_DESC_W0_TXPKTSIZE) |
le32_encode_bits(pkt_info->offset, RTW_TX_DESC_W0_OFFSET) |
le32_encode_bits(pkt_info->bmc, RTW_TX_DESC_W0_BMC) |
le32_encode_bits(pkt_info->ls, RTW_TX_DESC_W0_LS) |
le32_encode_bits(pkt_info->dis_qselseq, RTW_TX_DESC_W0_DISQSELSEQ);
tx_desc->w1 = le32_encode_bits(pkt_info->mac_id, RTW_TX_DESC_W1_MACID) |
le32_encode_bits(pkt_info->qsel, RTW_TX_DESC_W1_QSEL) |
le32_encode_bits(pkt_info->rate_id, RTW_TX_DESC_W1_RATE_ID) |
le32_encode_bits(pkt_info->sec_type, RTW_TX_DESC_W1_SEC_TYPE) |
le32_encode_bits(pkt_info->pkt_offset, RTW_TX_DESC_W1_PKT_OFFSET) |
le32_encode_bits(more_data, RTW_TX_DESC_W1_MORE_DATA);
tx_desc->w2 = le32_encode_bits(pkt_info->ampdu_en, RTW_TX_DESC_W2_AGG_EN) |
le32_encode_bits(pkt_info->report, RTW_TX_DESC_W2_SPE_RPT) |
le32_encode_bits(pkt_info->ampdu_density, RTW_TX_DESC_W2_AMPDU_DEN) |
le32_encode_bits(pkt_info->bt_null, RTW_TX_DESC_W2_BT_NULL);
tx_desc->w3 = le32_encode_bits(pkt_info->hw_ssn_sel, RTW_TX_DESC_W3_HW_SSN_SEL) |
le32_encode_bits(pkt_info->use_rate, RTW_TX_DESC_W3_USE_RATE) |
le32_encode_bits(pkt_info->dis_rate_fallback, RTW_TX_DESC_W3_DISDATAFB) |
le32_encode_bits(pkt_info->rts, RTW_TX_DESC_W3_USE_RTS) |
le32_encode_bits(pkt_info->nav_use_hdr, RTW_TX_DESC_W3_NAVUSEHDR) |
le32_encode_bits(pkt_info->ampdu_factor, RTW_TX_DESC_W3_MAX_AGG_NUM);
tx_desc->w4 = le32_encode_bits(pkt_info->rate, RTW_TX_DESC_W4_DATARATE);
if (rtwdev->chip->old_datarate_fb_limit)
tx_desc->w4 |= le32_encode_bits(0x1f, RTW_TX_DESC_W4_DATARATE_FB_LIMIT);
tx_desc->w5 = le32_encode_bits(pkt_info->short_gi, RTW_TX_DESC_W5_DATA_SHORT) |
le32_encode_bits(pkt_info->bw, RTW_TX_DESC_W5_DATA_BW) |
le32_encode_bits(pkt_info->ldpc, RTW_TX_DESC_W5_DATA_LDPC) |
le32_encode_bits(pkt_info->stbc, RTW_TX_DESC_W5_DATA_STBC);
tx_desc->w6 = le32_encode_bits(pkt_info->sn, RTW_TX_DESC_W6_SW_DEFINE);
tx_desc->w8 = le32_encode_bits(pkt_info->en_hwseq, RTW_TX_DESC_W8_EN_HWSEQ);
tx_desc->w9 = le32_encode_bits(pkt_info->seq, RTW_TX_DESC_W9_SW_SEQ);
if (pkt_info->rts) {
tx_desc->w4 |= le32_encode_bits(DESC_RATE24M, RTW_TX_DESC_W4_RTSRATE);
tx_desc->w5 |= le32_encode_bits(1, RTW_TX_DESC_W5_DATA_RTS_SHORT);
}
if (pkt_info->tim_offset)
tx_desc->w9 |= le32_encode_bits(1, RTW_TX_DESC_W9_TIM_EN) |
le32_encode_bits(pkt_info->tim_offset, RTW_TX_DESC_W9_TIM_OFFSET);
}
EXPORT_SYMBOL(rtw_tx_fill_tx_desc);
static u8 get_tx_ampdu_factor(struct ieee80211_sta *sta)
{
u8 exp = sta->deflink.ht_cap.ampdu_factor;
/* the least ampdu factor is 8K, and the value in the tx desc is the
* max aggregation num, which represents val * 2 packets can be
* aggregated in an AMPDU, so here we should use 8/2=4 as the base
*/
return (BIT(2) << exp) - 1;
}
static u8 get_tx_ampdu_density(struct ieee80211_sta *sta)
{
return sta->deflink.ht_cap.ampdu_density;
}
static u8 get_highest_ht_tx_rate(struct rtw_dev *rtwdev,
struct ieee80211_sta *sta)
{
u8 rate;
if (rtwdev->hal.rf_type == RF_2T2R && sta->deflink.ht_cap.mcs.rx_mask[1] != 0)
rate = DESC_RATEMCS15;
else
rate = DESC_RATEMCS7;
return rate;
}
static u8 get_highest_vht_tx_rate(struct rtw_dev *rtwdev,
struct ieee80211_sta *sta)
{
struct rtw_efuse *efuse = &rtwdev->efuse;
u8 rate;
u16 tx_mcs_map;
tx_mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.tx_mcs_map);
if (efuse->hw_cap.nss == 1) {
switch (tx_mcs_map & 0x3) {
case IEEE80211_VHT_MCS_SUPPORT_0_7:
rate = DESC_RATEVHT1SS_MCS7;
break;
case IEEE80211_VHT_MCS_SUPPORT_0_8:
rate = DESC_RATEVHT1SS_MCS8;
break;
default:
case IEEE80211_VHT_MCS_SUPPORT_0_9:
rate = DESC_RATEVHT1SS_MCS9;
break;
}
} else if (efuse->hw_cap.nss >= 2) {
switch ((tx_mcs_map & 0xc) >> 2) {
case IEEE80211_VHT_MCS_SUPPORT_0_7:
rate = DESC_RATEVHT2SS_MCS7;
break;
case IEEE80211_VHT_MCS_SUPPORT_0_8:
rate = DESC_RATEVHT2SS_MCS8;
break;
default:
case IEEE80211_VHT_MCS_SUPPORT_0_9:
rate = DESC_RATEVHT2SS_MCS9;
break;
}
} else {
rate = DESC_RATEVHT1SS_MCS9;
}
return rate;
}
static void rtw_tx_report_enable(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info)
{
struct rtw_tx_report *tx_report = &rtwdev->tx_report;
/* [11:8], reserved, fills with zero
* [7:2], tx report sequence number
* [1:0], firmware use, fills with zero
*/
pkt_info->sn = (atomic_inc_return(&tx_report->sn) << 2) & 0xfc;
pkt_info->report = true;
}
void rtw_tx_report_purge_timer(struct timer_list *t)
{
struct rtw_dev *rtwdev = timer_container_of(rtwdev, t,
tx_report.purge_timer);
struct rtw_tx_report *tx_report = &rtwdev->tx_report;
unsigned long flags;
if (skb_queue_len(&tx_report->queue) == 0)
return;
rtw_warn(rtwdev, "failed to get tx report from firmware\n");
spin_lock_irqsave(&tx_report->q_lock, flags);
skb_queue_purge(&tx_report->queue);
spin_unlock_irqrestore(&tx_report->q_lock, flags);
}
void rtw_tx_report_enqueue(struct rtw_dev *rtwdev, struct sk_buff *skb, u8 sn)
{
struct rtw_tx_report *tx_report = &rtwdev->tx_report;
unsigned long timeout = RTW_TX_PROBE_TIMEOUT;
unsigned long flags;
u8 *drv_data;
/* pass sn to tx report handler through driver data */
drv_data = (u8 *)IEEE80211_SKB_CB(skb)->status.status_driver_data;
*drv_data = sn;
spin_lock_irqsave(&tx_report->q_lock, flags);
__skb_queue_tail(&tx_report->queue, skb);
spin_unlock_irqrestore(&tx_report->q_lock, flags);
if (rtwdev->chip->id == RTW_CHIP_TYPE_8723D &&
rtwdev->hci.type == RTW_HCI_TYPE_USB)
timeout = msecs_to_jiffies(2500);
mod_timer(&tx_report->purge_timer, jiffies + timeout);
}
EXPORT_SYMBOL(rtw_tx_report_enqueue);
static void rtw_tx_report_tx_status(struct rtw_dev *rtwdev,
struct sk_buff *skb, bool acked)
{
struct ieee80211_tx_info *info;
info = IEEE80211_SKB_CB(skb);
ieee80211_tx_info_clear_status(info);
if (acked)
info->flags |= IEEE80211_TX_STAT_ACK;
else
info->flags &= ~IEEE80211_TX_STAT_ACK;
ieee80211_tx_status_irqsafe(rtwdev->hw, skb);
}
void rtw_tx_report_handle(struct rtw_dev *rtwdev, struct sk_buff *skb, int src)
{
struct rtw_tx_report *tx_report = &rtwdev->tx_report;
struct rtw_c2h_cmd *c2h;
struct sk_buff *cur, *tmp;
unsigned long flags;
u8 sn, st;
u8 *n;
c2h = get_c2h_from_skb(skb);
if (src == C2H_CCX_TX_RPT) {
sn = GET_CCX_REPORT_SEQNUM_V0(c2h->payload);
st = GET_CCX_REPORT_STATUS_V0(c2h->payload);
} else {
sn = GET_CCX_REPORT_SEQNUM_V1(c2h->payload);
st = GET_CCX_REPORT_STATUS_V1(c2h->payload);
}
spin_lock_irqsave(&tx_report->q_lock, flags);
skb_queue_walk_safe(&tx_report->queue, cur, tmp) {
n = (u8 *)IEEE80211_SKB_CB(cur)->status.status_driver_data;
if (*n == sn) {
__skb_unlink(cur, &tx_report->queue);
rtw_tx_report_tx_status(rtwdev, cur, st == 0);
break;
}
}
spin_unlock_irqrestore(&tx_report->q_lock, flags);
}
static u8 rtw_get_mgmt_rate(struct rtw_dev *rtwdev, struct sk_buff *skb,
u8 lowest_rate, bool ignore_rate)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = tx_info->control.vif;
bool force_lowest = test_bit(RTW_FLAG_FORCE_LOWEST_RATE, rtwdev->flags);
if (!vif || !vif->bss_conf.basic_rates || ignore_rate || force_lowest)
return lowest_rate;
return __ffs(vif->bss_conf.basic_rates) + lowest_rate;
}
static void rtw_tx_pkt_info_update_rate(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
struct sk_buff *skb,
bool ignore_rate)
{
if (rtwdev->hal.current_band_type == RTW_BAND_2G) {
pkt_info->rate_id = RTW_RATEID_B_20M;
pkt_info->rate = rtw_get_mgmt_rate(rtwdev, skb, DESC_RATE1M,
ignore_rate);
} else {
pkt_info->rate_id = RTW_RATEID_G;
pkt_info->rate = rtw_get_mgmt_rate(rtwdev, skb, DESC_RATE6M,
ignore_rate);
}
pkt_info->use_rate = true;
pkt_info->dis_rate_fallback = true;
}
static void rtw_tx_pkt_info_update_sec(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u8 sec_type = 0;
if (info && info->control.hw_key) {
struct ieee80211_key_conf *key = info->control.hw_key;
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
case WLAN_CIPHER_SUITE_TKIP:
sec_type = 0x01;
break;
case WLAN_CIPHER_SUITE_CCMP:
sec_type = 0x03;
break;
default:
break;
}
}
pkt_info->sec_type = sec_type;
}
static void rtw_tx_mgmt_pkt_info_update(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
struct ieee80211_sta *sta,
struct sk_buff *skb)
{
rtw_tx_pkt_info_update_rate(rtwdev, pkt_info, skb, false);
pkt_info->dis_qselseq = true;
pkt_info->en_hwseq = true;
pkt_info->hw_ssn_sel = 0;
/* TODO: need to change hw port and hw ssn sel for multiple vifs */
}
static void rtw_tx_data_pkt_info_update(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
struct ieee80211_sta *sta,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hw *hw = rtwdev->hw;
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
struct rtw_sta_info *si;
u8 fix_rate;
u16 seq;
u8 ampdu_factor = 0;
u8 ampdu_density = 0;
bool ampdu_en = false;
u8 rate = DESC_RATE6M;
u8 rate_id = 6;
u8 bw = RTW_CHANNEL_WIDTH_20;
bool stbc = false;
bool ldpc = false;
seq = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
/* for broadcast/multicast, use default values */
if (!sta)
goto out;
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
ampdu_en = true;
ampdu_factor = get_tx_ampdu_factor(sta);
ampdu_density = get_tx_ampdu_density(sta);
}
if (info->control.use_rts || skb->len > hw->wiphy->rts_threshold)
pkt_info->rts = true;
if (sta->deflink.vht_cap.vht_supported)
rate = get_highest_vht_tx_rate(rtwdev, sta);
else if (sta->deflink.ht_cap.ht_supported)
rate = get_highest_ht_tx_rate(rtwdev, sta);
else if (sta->deflink.supp_rates[0] <= 0xf)
rate = DESC_RATE11M;
else
rate = DESC_RATE54M;
si = (struct rtw_sta_info *)sta->drv_priv;
bw = si->bw_mode;
rate_id = si->rate_id;
stbc = rtwdev->hal.txrx_1ss ? false : si->stbc_en;
ldpc = si->ldpc_en;
out:
pkt_info->seq = seq;
pkt_info->ampdu_factor = ampdu_factor;
pkt_info->ampdu_density = ampdu_density;
pkt_info->ampdu_en = ampdu_en;
pkt_info->rate = rate;
pkt_info->rate_id = rate_id;
pkt_info->bw = bw;
pkt_info->stbc = stbc;
pkt_info->ldpc = ldpc;
fix_rate = dm_info->fix_rate;
if (fix_rate < DESC_RATE_MAX) {
pkt_info->rate = fix_rate;
pkt_info->dis_rate_fallback = true;
pkt_info->use_rate = true;
}
}
void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
struct ieee80211_sta *sta,
struct sk_buff *skb)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_vif *vif = info->control.vif;
struct rtw_sta_info *si;
struct rtw_vif *rtwvif;
__le16 fc = hdr->frame_control;
bool bmc;
if (sta) {
si = (struct rtw_sta_info *)sta->drv_priv;
pkt_info->mac_id = si->mac_id;
} else if (vif) {
rtwvif = (struct rtw_vif *)vif->drv_priv;
pkt_info->mac_id = rtwvif->mac_id;
}
if (ieee80211_is_mgmt(fc) || ieee80211_is_any_nullfunc(fc))
rtw_tx_mgmt_pkt_info_update(rtwdev, pkt_info, sta, skb);
else if (ieee80211_is_data(fc))
rtw_tx_data_pkt_info_update(rtwdev, pkt_info, sta, skb);
bmc = is_broadcast_ether_addr(hdr->addr1) ||
is_multicast_ether_addr(hdr->addr1);
if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)
rtw_tx_report_enable(rtwdev, pkt_info);
pkt_info->bmc = bmc;
rtw_tx_pkt_info_update_sec(rtwdev, pkt_info, skb);
pkt_info->tx_pkt_size = skb->len;
pkt_info->offset = chip->tx_pkt_desc_sz;
pkt_info->qsel = skb->priority;
pkt_info->ls = true;
/* maybe merge with tx status ? */
rtw_tx_stats(rtwdev, vif, skb);
}
void rtw_tx_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
struct sk_buff *skb,
enum rtw_rsvd_packet_type type)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
bool bmc;
/* A beacon or dummy reserved page packet indicates that it is the first
* reserved page, and the qsel of it will be set in each hci.
*/
if (type != RSVD_BEACON && type != RSVD_DUMMY)
pkt_info->qsel = TX_DESC_QSEL_MGMT;
rtw_tx_pkt_info_update_rate(rtwdev, pkt_info, skb, true);
bmc = is_broadcast_ether_addr(hdr->addr1) ||
is_multicast_ether_addr(hdr->addr1);
pkt_info->bmc = bmc;
pkt_info->tx_pkt_size = skb->len;
pkt_info->offset = chip->tx_pkt_desc_sz;
pkt_info->ls = true;
if (type == RSVD_PS_POLL) {
pkt_info->nav_use_hdr = true;
} else {
pkt_info->dis_qselseq = true;
pkt_info->en_hwseq = true;
pkt_info->hw_ssn_sel = 0;
}
if (type == RSVD_QOS_NULL)
pkt_info->bt_null = true;
if (type == RSVD_BEACON) {
struct rtw_rsvd_page *rsvd_pkt;
int hdr_len;
rsvd_pkt = list_first_entry_or_null(&rtwdev->rsvd_page_list,
struct rtw_rsvd_page,
build_list);
if (rsvd_pkt && rsvd_pkt->tim_offset != 0) {
hdr_len = sizeof(struct ieee80211_hdr_3addr);
pkt_info->tim_offset = rsvd_pkt->tim_offset - hdr_len;
}
}
rtw_tx_pkt_info_update_sec(rtwdev, pkt_info, skb);
/* TODO: need to change hw port and hw ssn sel for multiple vifs */
}
struct sk_buff *
rtw_tx_write_data_rsvd_page_get(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *buf, u32 size)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct sk_buff *skb;
u32 tx_pkt_desc_sz;
u32 length;
tx_pkt_desc_sz = chip->tx_pkt_desc_sz;
length = size + tx_pkt_desc_sz;
skb = dev_alloc_skb(length);
if (!skb) {
rtw_err(rtwdev, "failed to alloc write data rsvd page skb\n");
return NULL;
}
skb_reserve(skb, tx_pkt_desc_sz);
skb_put_data(skb, buf, size);
rtw_tx_rsvd_page_pkt_info_update(rtwdev, pkt_info, skb, RSVD_BEACON);
return skb;
}
EXPORT_SYMBOL(rtw_tx_write_data_rsvd_page_get);
struct sk_buff *
rtw_tx_write_data_h2c_get(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *buf, u32 size)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct sk_buff *skb;
u32 tx_pkt_desc_sz;
u32 length;
tx_pkt_desc_sz = chip->tx_pkt_desc_sz;
length = size + tx_pkt_desc_sz;
skb = dev_alloc_skb(length);
if (!skb) {
rtw_err(rtwdev, "failed to alloc write data h2c skb\n");
return NULL;
}
skb_reserve(skb, tx_pkt_desc_sz);
skb_put_data(skb, buf, size);
pkt_info->tx_pkt_size = size;
return skb;
}
EXPORT_SYMBOL(rtw_tx_write_data_h2c_get);
void rtw_tx(struct rtw_dev *rtwdev,
struct ieee80211_tx_control *control,
struct sk_buff *skb)
{
struct rtw_tx_pkt_info pkt_info = {0};
int ret;
rtw_tx_pkt_info_update(rtwdev, &pkt_info, control->sta, skb);
ret = rtw_hci_tx_write(rtwdev, &pkt_info, skb);
if (ret) {
rtw_err(rtwdev, "failed to write TX skb to HCI\n");
goto out;
}
rtw_hci_tx_kick_off(rtwdev);
return;
out:
ieee80211_free_txskb(rtwdev->hw, skb);
}
static void rtw_txq_check_agg(struct rtw_dev *rtwdev,
struct rtw_txq *rtwtxq,
struct sk_buff *skb)
{
struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq);
struct ieee80211_tx_info *info;
struct rtw_sta_info *si;
if (test_bit(RTW_TXQ_AMPDU, &rtwtxq->flags)) {
info = IEEE80211_SKB_CB(skb);
info->flags |= IEEE80211_TX_CTL_AMPDU;
return;
}
if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
return;
if (test_bit(RTW_TXQ_BLOCK_BA, &rtwtxq->flags))
return;
if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
return;
if (!txq->sta)
return;
si = (struct rtw_sta_info *)txq->sta->drv_priv;
set_bit(txq->tid, si->tid_ba);
ieee80211_queue_work(rtwdev->hw, &rtwdev->ba_work);
}
static int rtw_txq_push_skb(struct rtw_dev *rtwdev,
struct rtw_txq *rtwtxq,
struct sk_buff *skb)
{
struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq);
struct rtw_tx_pkt_info pkt_info = {0};
int ret;
rtw_txq_check_agg(rtwdev, rtwtxq, skb);
rtw_tx_pkt_info_update(rtwdev, &pkt_info, txq->sta, skb);
ret = rtw_hci_tx_write(rtwdev, &pkt_info, skb);
if (ret) {
rtw_err(rtwdev, "failed to write TX skb to HCI\n");
return ret;
}
return 0;
}
static void rtw_txq_push(struct rtw_dev *rtwdev,
struct rtw_txq *rtwtxq,
unsigned long frames)
{
struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq);
struct sk_buff *skb;
unsigned long i;
int ret;
rcu_read_lock();
for (i = 0; i < frames; i++) {
skb = ieee80211_tx_dequeue(rtwdev->hw, txq);
if (!skb)
break;
ret = rtw_txq_push_skb(rtwdev, rtwtxq, skb);
if (ret) {
rtw_err(rtwdev, "failed to pusk skb, ret %d\n", ret);
break;
}
}
rcu_read_unlock();
}
void __rtw_tx_work(struct rtw_dev *rtwdev)
{
struct rtw_txq *rtwtxq, *tmp;
spin_lock_bh(&rtwdev->txq_lock);
list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->txqs, list) {
struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq);
unsigned long frame_cnt;
ieee80211_txq_get_depth(txq, &frame_cnt, NULL);
rtw_txq_push(rtwdev, rtwtxq, frame_cnt);
list_del_init(&rtwtxq->list);
}
rtw_hci_tx_kick_off(rtwdev);
spin_unlock_bh(&rtwdev->txq_lock);
}
void rtw_tx_work(struct work_struct *w)
{
struct rtw_dev *rtwdev = container_of(w, struct rtw_dev, tx_work);
__rtw_tx_work(rtwdev);
}
void rtw_txq_init(struct rtw_dev *rtwdev, struct ieee80211_txq *txq)
{
struct rtw_txq *rtwtxq;
if (!txq)
return;
rtwtxq = (struct rtw_txq *)txq->drv_priv;
INIT_LIST_HEAD(&rtwtxq->list);
}
void rtw_txq_cleanup(struct rtw_dev *rtwdev, struct ieee80211_txq *txq)
{
struct rtw_txq *rtwtxq;
if (!txq)
return;
rtwtxq = (struct rtw_txq *)txq->drv_priv;
spin_lock_bh(&rtwdev->txq_lock);
if (!list_empty(&rtwtxq->list))
list_del_init(&rtwtxq->list);
spin_unlock_bh(&rtwdev->txq_lock);
}
static const enum rtw_tx_queue_type ac_to_hwq[] = {
[IEEE80211_AC_VO] = RTW_TX_QUEUE_VO,
[IEEE80211_AC_VI] = RTW_TX_QUEUE_VI,
[IEEE80211_AC_BE] = RTW_TX_QUEUE_BE,
[IEEE80211_AC_BK] = RTW_TX_QUEUE_BK,
};
static_assert(ARRAY_SIZE(ac_to_hwq) == IEEE80211_NUM_ACS);
enum rtw_tx_queue_type rtw_tx_ac_to_hwq(enum ieee80211_ac_numbers ac)
{
if (WARN_ON(unlikely(ac >= IEEE80211_NUM_ACS)))
return RTW_TX_QUEUE_BE;
return ac_to_hwq[ac];
}
EXPORT_SYMBOL(rtw_tx_ac_to_hwq);
enum rtw_tx_queue_type rtw_tx_queue_mapping(struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc = hdr->frame_control;
u8 q_mapping = skb_get_queue_mapping(skb);
enum rtw_tx_queue_type queue;
if (unlikely(ieee80211_is_beacon(fc)))
queue = RTW_TX_QUEUE_BCN;
else if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)))
queue = RTW_TX_QUEUE_MGMT;
else if (is_broadcast_ether_addr(hdr->addr1) ||
is_multicast_ether_addr(hdr->addr1))
queue = RTW_TX_QUEUE_HI0;
else if (WARN_ON_ONCE(q_mapping >= ARRAY_SIZE(ac_to_hwq)))
queue = ac_to_hwq[IEEE80211_AC_BE];
else
queue = ac_to_hwq[q_mapping];
return queue;
}
EXPORT_SYMBOL(rtw_tx_queue_mapping);
@@ -0,0 +1,143 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_TX_H_
#define __RTW_TX_H_
#define RTK_TX_MAX_AGG_NUM_MASK 0x1f
#define RTW_TX_PROBE_TIMEOUT msecs_to_jiffies(500)
struct rtw_tx_desc {
__le32 w0;
__le32 w1;
__le32 w2;
__le32 w3;
__le32 w4;
__le32 w5;
__le32 w6;
__le32 w7;
__le32 w8;
__le32 w9;
} __packed;
#define RTW_TX_DESC_W0_TXPKTSIZE GENMASK(15, 0)
#define RTW_TX_DESC_W0_OFFSET GENMASK(23, 16)
#define RTW_TX_DESC_W0_BMC BIT(24)
#define RTW_TX_DESC_W0_LS BIT(26)
#define RTW_TX_DESC_W0_DISQSELSEQ BIT(31)
#define RTW_TX_DESC_W1_MACID GENMASK(7, 0)
#define RTW_TX_DESC_W1_QSEL GENMASK(12, 8)
#define RTW_TX_DESC_W1_RATE_ID GENMASK(20, 16)
#define RTW_TX_DESC_W1_SEC_TYPE GENMASK(23, 22)
#define RTW_TX_DESC_W1_PKT_OFFSET GENMASK(28, 24)
#define RTW_TX_DESC_W1_MORE_DATA BIT(29)
#define RTW_TX_DESC_W2_AGG_EN BIT(12)
#define RTW_TX_DESC_W2_SPE_RPT BIT(19)
#define RTW_TX_DESC_W2_AMPDU_DEN GENMASK(22, 20)
#define RTW_TX_DESC_W2_BT_NULL BIT(23)
#define RTW_TX_DESC_W3_HW_SSN_SEL GENMASK(7, 6)
#define RTW_TX_DESC_W3_USE_RATE BIT(8)
#define RTW_TX_DESC_W3_DISDATAFB BIT(10)
#define RTW_TX_DESC_W3_USE_RTS BIT(12)
#define RTW_TX_DESC_W3_NAVUSEHDR BIT(15)
#define RTW_TX_DESC_W3_MAX_AGG_NUM GENMASK(21, 17)
#define RTW_TX_DESC_W4_DATARATE GENMASK(6, 0)
#define RTW_TX_DESC_W4_DATARATE_FB_LIMIT GENMASK(12, 8)
#define RTW_TX_DESC_W4_RTSRATE GENMASK(28, 24)
#define RTW_TX_DESC_W5_DATA_SHORT BIT(4)
#define RTW_TX_DESC_W5_DATA_BW GENMASK(6, 5)
#define RTW_TX_DESC_W5_DATA_LDPC BIT(7)
#define RTW_TX_DESC_W5_DATA_STBC GENMASK(9, 8)
#define RTW_TX_DESC_W5_DATA_RTS_SHORT BIT(12)
#define RTW_TX_DESC_W6_SW_DEFINE GENMASK(11, 0)
#define RTW_TX_DESC_W7_TXDESC_CHECKSUM GENMASK(15, 0)
#define RTW_TX_DESC_W7_DMA_TXAGG_NUM GENMASK(31, 24)
#define RTW_TX_DESC_W8_EN_HWSEQ BIT(15)
#define RTW_TX_DESC_W9_SW_SEQ GENMASK(23, 12)
#define RTW_TX_DESC_W9_TIM_EN BIT(7)
#define RTW_TX_DESC_W9_TIM_OFFSET GENMASK(6, 0)
enum rtw_tx_desc_queue_select {
TX_DESC_QSEL_TID0 = 0,
TX_DESC_QSEL_TID1 = 1,
TX_DESC_QSEL_TID2 = 2,
TX_DESC_QSEL_TID3 = 3,
TX_DESC_QSEL_TID4 = 4,
TX_DESC_QSEL_TID5 = 5,
TX_DESC_QSEL_TID6 = 6,
TX_DESC_QSEL_TID7 = 7,
TX_DESC_QSEL_TID8 = 8,
TX_DESC_QSEL_TID9 = 9,
TX_DESC_QSEL_TID10 = 10,
TX_DESC_QSEL_TID11 = 11,
TX_DESC_QSEL_TID12 = 12,
TX_DESC_QSEL_TID13 = 13,
TX_DESC_QSEL_TID14 = 14,
TX_DESC_QSEL_TID15 = 15,
TX_DESC_QSEL_BEACON = 16,
TX_DESC_QSEL_HIGH = 17,
TX_DESC_QSEL_MGMT = 18,
TX_DESC_QSEL_H2C = 19,
};
enum rtw_rsvd_packet_type;
void rtw_tx(struct rtw_dev *rtwdev,
struct ieee80211_tx_control *control,
struct sk_buff *skb);
void rtw_txq_init(struct rtw_dev *rtwdev, struct ieee80211_txq *txq);
void rtw_txq_cleanup(struct rtw_dev *rtwdev, struct ieee80211_txq *txq);
void rtw_tx_work(struct work_struct *w);
void __rtw_tx_work(struct rtw_dev *rtwdev);
void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
struct ieee80211_sta *sta,
struct sk_buff *skb);
void rtw_tx_fill_tx_desc(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb);
void rtw_tx_report_enqueue(struct rtw_dev *rtwdev, struct sk_buff *skb, u8 sn);
void rtw_tx_report_handle(struct rtw_dev *rtwdev, struct sk_buff *skb, int src);
void rtw_tx_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
struct sk_buff *skb,
enum rtw_rsvd_packet_type type);
struct sk_buff *
rtw_tx_write_data_rsvd_page_get(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *buf, u32 size);
struct sk_buff *
rtw_tx_write_data_h2c_get(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *buf, u32 size);
enum rtw_tx_queue_type rtw_tx_ac_to_hwq(enum ieee80211_ac_numbers ac);
enum rtw_tx_queue_type rtw_tx_queue_mapping(struct sk_buff *skb);
static inline
void fill_txdesc_checksum_common(u8 *txdesc, size_t words)
{
__le16 chksum = 0;
__le16 *data = (__le16 *)(txdesc);
struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)txdesc;
le32p_replace_bits(&tx_desc->w7, 0, RTW_TX_DESC_W7_TXDESC_CHECKSUM);
while (words--)
chksum ^= *data++;
le32p_replace_bits(&tx_desc->w7, __le16_to_cpu(chksum),
RTW_TX_DESC_W7_TXDESC_CHECKSUM);
}
static inline void rtw_tx_fill_txdesc_checksum(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *txdesc)
{
const struct rtw_chip_info *chip = rtwdev->chip;
chip->ops->fill_txdesc_checksum(rtwdev, pkt_info, txdesc);
}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,103 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_USB_H_
#define __RTW_USB_H_
#define FW_8192C_START_ADDRESS 0x1000
#define FW_8192C_END_ADDRESS 0x5fff
#define RTW_USB_MAX_RXTX_COUNT 128
#define RTW_USB_VENQT_MAX_BUF_SIZE 254
#define MAX_USBCTRL_VENDORREQ_TIMES 10
#define RTW_USB_CMD_READ 0xc0
#define RTW_USB_CMD_WRITE 0x40
#define RTW_USB_CMD_REQ 0x05
#define RTW_USB_VENQT_CMD_IDX 0x00
#define RTW_USB_TX_SEL_HQ BIT(0)
#define RTW_USB_TX_SEL_LQ BIT(1)
#define RTW_USB_TX_SEL_NQ BIT(2)
#define RTW_USB_TX_SEL_EQ BIT(3)
#define RTW_USB_BULK_IN_ADDR 0x80
#define RTW_USB_INT_IN_ADDR 0x81
#define RTW_USB_HW_QUEUE_ENTRY 8
#define RTW_USB_PACKET_OFFSET_SZ 8
#define RTW_USB_MAX_XMITBUF_SZ (1024 * 20)
#define RTW_USB_MAX_RECVBUF_SZ 32768
#define RTW_USB_RECVBUFF_ALIGN_SZ 8
#define RTW_USB_RXAGG_SIZE 6
#define RTW_USB_RXAGG_TIMEOUT 10
#define RTW_USB_RXCB_NUM 4
#define RTW_USB_RX_SKB_NUM 8
#define RTW_USB_EP_MAX 4
#define TX_DESC_QSEL_MAX 20
#define RTW_USB_VENDOR_ID_REALTEK 0x0bda
static inline struct rtw_usb *rtw_get_usb_priv(struct rtw_dev *rtwdev)
{
return (struct rtw_usb *)rtwdev->priv;
}
struct rx_usb_ctrl_block {
struct rtw_dev *rtwdev;
struct urb *rx_urb;
struct sk_buff *rx_skb;
};
struct rtw_usb_tx_data {
u8 sn;
};
struct rtw_usb {
struct rtw_dev *rtwdev;
struct usb_device *udev;
/* protects usb_data_index */
spinlock_t usb_lock;
__le32 *usb_data;
unsigned int usb_data_index;
u8 pipe_interrupt;
u8 pipe_in;
u8 out_ep[RTW_USB_EP_MAX];
int qsel_to_ep[TX_DESC_QSEL_MAX];
struct workqueue_struct *txwq, *rxwq;
struct sk_buff_head tx_queue[RTW_USB_EP_MAX];
struct work_struct tx_work;
struct rx_usb_ctrl_block rx_cb[RTW_USB_RXCB_NUM];
struct sk_buff_head rx_queue;
struct sk_buff_head rx_free_queue;
struct work_struct rx_work;
struct work_struct rx_urb_work;
};
static inline struct rtw_usb_tx_data *rtw_usb_get_tx_data(struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
BUILD_BUG_ON(sizeof(struct rtw_usb_tx_data) >
sizeof(info->status.status_driver_data));
return (struct rtw_usb_tx_data *)info->status.status_driver_data;
}
int rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id);
void rtw_usb_disconnect(struct usb_interface *intf);
#endif
@@ -0,0 +1,208 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include "main.h"
#include "util.h"
#include "reg.h"
bool check_hw_ready(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 target)
{
u32 cnt;
for (cnt = 0; cnt < 1000; cnt++) {
if (rtw_read32_mask(rtwdev, addr, mask) == target)
return true;
udelay(10);
}
return false;
}
EXPORT_SYMBOL(check_hw_ready);
bool ltecoex_read_reg(struct rtw_dev *rtwdev, u16 offset, u32 *val)
{
const struct rtw_chip_info *chip = rtwdev->chip;
const struct rtw_ltecoex_addr *ltecoex = chip->ltecoex_addr;
if (!check_hw_ready(rtwdev, ltecoex->ctrl, LTECOEX_READY, 1))
return false;
rtw_write32(rtwdev, ltecoex->ctrl, 0x800F0000 | offset);
*val = rtw_read32(rtwdev, ltecoex->rdata);
return true;
}
bool ltecoex_reg_write(struct rtw_dev *rtwdev, u16 offset, u32 value)
{
const struct rtw_chip_info *chip = rtwdev->chip;
const struct rtw_ltecoex_addr *ltecoex = chip->ltecoex_addr;
if (!check_hw_ready(rtwdev, ltecoex->ctrl, LTECOEX_READY, 1))
return false;
rtw_write32(rtwdev, ltecoex->wdata, value);
rtw_write32(rtwdev, ltecoex->ctrl, 0xC00F0000 | offset);
return true;
}
void rtw_restore_reg(struct rtw_dev *rtwdev,
struct rtw_backup_info *bckp, u32 num)
{
u8 len;
u32 reg;
u32 val;
int i;
for (i = 0; i < num; i++, bckp++) {
len = bckp->len;
reg = bckp->reg;
val = bckp->val;
switch (len) {
case 1:
rtw_write8(rtwdev, reg, (u8)val);
break;
case 2:
rtw_write16(rtwdev, reg, (u16)val);
break;
case 4:
rtw_write32(rtwdev, reg, (u32)val);
break;
default:
break;
}
}
}
EXPORT_SYMBOL(rtw_restore_reg);
void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss)
{
if (rate <= DESC_RATE54M)
return;
if (rate >= DESC_RATEVHT1SS_MCS0 &&
rate <= DESC_RATEVHT1SS_MCS9) {
*nss = 1;
*mcs = rate - DESC_RATEVHT1SS_MCS0;
} else if (rate >= DESC_RATEVHT2SS_MCS0 &&
rate <= DESC_RATEVHT2SS_MCS9) {
*nss = 2;
*mcs = rate - DESC_RATEVHT2SS_MCS0;
} else if (rate >= DESC_RATEVHT3SS_MCS0 &&
rate <= DESC_RATEVHT3SS_MCS9) {
*nss = 3;
*mcs = rate - DESC_RATEVHT3SS_MCS0;
} else if (rate >= DESC_RATEVHT4SS_MCS0 &&
rate <= DESC_RATEVHT4SS_MCS9) {
*nss = 4;
*mcs = rate - DESC_RATEVHT4SS_MCS0;
} else if (rate >= DESC_RATEMCS0 &&
rate <= DESC_RATEMCS31) {
*nss = 0;
*mcs = rate - DESC_RATEMCS0;
}
}
struct rtw_stas_entry {
struct list_head list;
struct ieee80211_sta *sta;
};
struct rtw_iter_stas_data {
struct rtw_dev *rtwdev;
struct list_head list;
};
static void rtw_collect_sta_iter(void *data, struct ieee80211_sta *sta)
{
struct rtw_iter_stas_data *iter_stas = data;
struct rtw_stas_entry *stas_entry;
stas_entry = kmalloc_obj(*stas_entry, GFP_ATOMIC);
if (!stas_entry)
return;
stas_entry->sta = sta;
list_add_tail(&stas_entry->list, &iter_stas->list);
}
void rtw_iterate_stas(struct rtw_dev *rtwdev,
void (*iterator)(void *data,
struct ieee80211_sta *sta),
void *data)
{
struct rtw_iter_stas_data iter_data;
struct rtw_stas_entry *sta_entry, *tmp;
/* &rtwdev->mutex makes sure no stations can be removed between
* collecting the stations and iterating over them.
*/
lockdep_assert_held(&rtwdev->mutex);
iter_data.rtwdev = rtwdev;
INIT_LIST_HEAD(&iter_data.list);
ieee80211_iterate_stations_atomic(rtwdev->hw, rtw_collect_sta_iter,
&iter_data);
list_for_each_entry_safe(sta_entry, tmp, &iter_data.list,
list) {
list_del_init(&sta_entry->list);
iterator(data, sta_entry->sta);
kfree(sta_entry);
}
}
struct rtw_vifs_entry {
struct list_head list;
struct ieee80211_vif *vif;
};
struct rtw_iter_vifs_data {
struct rtw_dev *rtwdev;
struct list_head list;
};
static void rtw_collect_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
{
struct rtw_iter_vifs_data *iter_stas = data;
struct rtw_vifs_entry *vifs_entry;
vifs_entry = kmalloc_obj(*vifs_entry, GFP_ATOMIC);
if (!vifs_entry)
return;
vifs_entry->vif = vif;
list_add_tail(&vifs_entry->list, &iter_stas->list);
}
void rtw_iterate_vifs(struct rtw_dev *rtwdev,
void (*iterator)(void *data, struct ieee80211_vif *vif),
void *data)
{
struct rtw_iter_vifs_data iter_data;
struct rtw_vifs_entry *vif_entry, *tmp;
/* &rtwdev->mutex makes sure no interfaces can be removed between
* collecting the interfaces and iterating over them.
*/
lockdep_assert_held(&rtwdev->mutex);
iter_data.rtwdev = rtwdev;
INIT_LIST_HEAD(&iter_data.list);
ieee80211_iterate_active_interfaces_atomic(rtwdev->hw,
IEEE80211_IFACE_ITER_NORMAL,
rtw_collect_vif_iter, &iter_data);
list_for_each_entry_safe(vif_entry, tmp, &iter_data.list,
list) {
list_del_init(&vif_entry->list);
iterator(data, vif_entry->vif);
kfree(vif_entry);
}
}
@@ -0,0 +1,43 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_UTIL_H__
#define __RTW_UTIL_H__
struct rtw_dev;
#define rtw_iterate_vifs_atomic(rtwdev, iterator, data) \
ieee80211_iterate_active_interfaces_atomic(rtwdev->hw, \
IEEE80211_IFACE_ITER_NORMAL, iterator, data)
#define rtw_iterate_stas_atomic(rtwdev, iterator, data) \
ieee80211_iterate_stations_atomic(rtwdev->hw, iterator, data)
#define rtw_iterate_keys(rtwdev, vif, iterator, data) \
ieee80211_iter_keys(rtwdev->hw, vif, iterator, data)
#define rtw_iterate_keys_rcu(rtwdev, vif, iterator, data) \
ieee80211_iter_keys_rcu((rtwdev)->hw, vif, iterator, data)
void rtw_iterate_vifs(struct rtw_dev *rtwdev,
void (*iterator)(void *data, struct ieee80211_vif *vif),
void *data);
void rtw_iterate_stas(struct rtw_dev *rtwdev,
void (*iterator)(void *data,
struct ieee80211_sta *sta),
void *data);
static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr)
{
__le16 fc = hdr->frame_control;
u8 *bssid;
if (ieee80211_has_tods(fc))
bssid = hdr->addr1;
else if (ieee80211_has_fromds(fc))
bssid = hdr->addr2;
else
bssid = hdr->addr3;
return bssid;
}
#endif
@@ -0,0 +1,913 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include "main.h"
#include "fw.h"
#include "wow.h"
#include "reg.h"
#include "debug.h"
#include "mac.h"
#include "ps.h"
static void rtw_wow_show_wakeup_reason(struct rtw_dev *rtwdev)
{
struct cfg80211_wowlan_nd_info nd_info;
struct cfg80211_wowlan_wakeup wakeup = {
.pattern_idx = -1,
};
u8 reason;
reason = rtw_read8(rtwdev, REG_WOWLAN_WAKE_REASON);
switch (reason) {
case RTW_WOW_RSN_RX_DEAUTH:
wakeup.disconnect = true;
rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx deauth\n");
break;
case RTW_WOW_RSN_DISCONNECT:
wakeup.disconnect = true;
rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: AP is off\n");
break;
case RTW_WOW_RSN_RX_MAGIC_PKT:
wakeup.magic_pkt = true;
rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx magic packet\n");
break;
case RTW_WOW_RSN_RX_GTK_REKEY:
wakeup.gtk_rekey_failure = true;
rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx gtk rekey\n");
break;
case RTW_WOW_RSN_RX_PATTERN_MATCH:
/* Current firmware and driver don't report pattern index
* Use pattern_idx to 0 defaultly.
*/
wakeup.pattern_idx = 0;
rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx pattern match packet\n");
break;
case RTW_WOW_RSN_RX_NLO:
/* Current firmware and driver don't report ssid index.
* Use 0 for n_matches based on its comment.
*/
nd_info.n_matches = 0;
wakeup.net_detect = &nd_info;
rtw_dbg(rtwdev, RTW_DBG_WOW, "Rx NLO\n");
break;
default:
rtw_warn(rtwdev, "Unknown wakeup reason %x\n", reason);
ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, NULL,
GFP_KERNEL);
return;
}
ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, &wakeup,
GFP_KERNEL);
}
static void rtw_wow_pattern_write_cam(struct rtw_dev *rtwdev, u8 addr,
u32 wdata)
{
rtw_write32(rtwdev, REG_WKFMCAM_RWD, wdata);
rtw_write32(rtwdev, REG_WKFMCAM_CMD, BIT_WKFCAM_POLLING_V1 |
BIT_WKFCAM_WE | BIT_WKFCAM_ADDR_V2(addr));
if (!check_hw_ready(rtwdev, REG_WKFMCAM_CMD, BIT_WKFCAM_POLLING_V1, 0))
rtw_err(rtwdev, "failed to write pattern cam\n");
}
static void rtw_wow_pattern_write_cam_ent(struct rtw_dev *rtwdev, u8 id,
struct rtw_wow_pattern *rtw_pattern)
{
int i;
u8 addr;
u32 wdata;
for (i = 0; i < RTW_MAX_PATTERN_MASK_SIZE / 4; i++) {
addr = (id << 3) + i;
wdata = rtw_pattern->mask[i * 4];
wdata |= rtw_pattern->mask[i * 4 + 1] << 8;
wdata |= rtw_pattern->mask[i * 4 + 2] << 16;
wdata |= rtw_pattern->mask[i * 4 + 3] << 24;
rtw_wow_pattern_write_cam(rtwdev, addr, wdata);
}
wdata = rtw_pattern->crc;
addr = (id << 3) + RTW_MAX_PATTERN_MASK_SIZE / 4;
switch (rtw_pattern->type) {
case RTW_PATTERN_BROADCAST:
wdata |= BIT_WKFMCAM_BC | BIT_WKFMCAM_VALID;
break;
case RTW_PATTERN_MULTICAST:
wdata |= BIT_WKFMCAM_MC | BIT_WKFMCAM_VALID;
break;
case RTW_PATTERN_UNICAST:
wdata |= BIT_WKFMCAM_UC | BIT_WKFMCAM_VALID;
break;
default:
break;
}
rtw_wow_pattern_write_cam(rtwdev, addr, wdata);
}
/* RTK internal CRC16 for Pattern Cam */
static u16 __rtw_cal_crc16(u8 data, u16 crc)
{
u8 shift_in, data_bit;
u8 crc_bit4, crc_bit11, crc_bit15;
u16 crc_result;
int index;
for (index = 0; index < 8; index++) {
crc_bit15 = ((crc & BIT(15)) ? 1 : 0);
data_bit = (data & (BIT(0) << index) ? 1 : 0);
shift_in = crc_bit15 ^ data_bit;
crc_result = crc << 1;
if (shift_in == 0)
crc_result &= (~BIT(0));
else
crc_result |= BIT(0);
crc_bit11 = ((crc & BIT(11)) ? 1 : 0) ^ shift_in;
if (crc_bit11 == 0)
crc_result &= (~BIT(12));
else
crc_result |= BIT(12);
crc_bit4 = ((crc & BIT(4)) ? 1 : 0) ^ shift_in;
if (crc_bit4 == 0)
crc_result &= (~BIT(5));
else
crc_result |= BIT(5);
crc = crc_result;
}
return crc;
}
static u16 rtw_calc_crc(u8 *pdata, int length)
{
u16 crc = 0xffff;
int i;
for (i = 0; i < length; i++)
crc = __rtw_cal_crc16(pdata[i], crc);
/* get 1' complement */
return ~crc;
}
static void rtw_wow_pattern_generate(struct rtw_dev *rtwdev,
struct rtw_vif *rtwvif,
const struct cfg80211_pkt_pattern *pkt_pattern,
struct rtw_wow_pattern *rtw_pattern)
{
const u8 *mask;
const u8 *pattern;
u8 mask_hw[RTW_MAX_PATTERN_MASK_SIZE] = {0};
u8 content[RTW_MAX_PATTERN_SIZE] = {0};
u8 mac_addr[ETH_ALEN] = {0};
u8 mask_len;
u16 count;
int len;
int i;
pattern = pkt_pattern->pattern;
len = pkt_pattern->pattern_len;
mask = pkt_pattern->mask;
ether_addr_copy(mac_addr, rtwvif->mac_addr);
memset(rtw_pattern, 0, sizeof(*rtw_pattern));
mask_len = DIV_ROUND_UP(len, 8);
if (is_broadcast_ether_addr(pattern))
rtw_pattern->type = RTW_PATTERN_BROADCAST;
else if (is_multicast_ether_addr(pattern))
rtw_pattern->type = RTW_PATTERN_MULTICAST;
else if (ether_addr_equal(pattern, mac_addr))
rtw_pattern->type = RTW_PATTERN_UNICAST;
else
rtw_pattern->type = RTW_PATTERN_INVALID;
/* translate mask from os to mask for hw
* pattern from OS uses 'ethenet frame', like this:
* | 6 | 6 | 2 | 20 | Variable | 4 |
* |--------+--------+------+-----------+------------+-----|
* | 802.3 Mac Header | IP Header | TCP Packet | FCS |
* | DA | SA | Type |
*
* BUT, packet catched by our HW is in '802.11 frame', begin from LLC
* | 24 or 30 | 6 | 2 | 20 | Variable | 4 |
* |-------------------+--------+------+-----------+------------+-----|
* | 802.11 MAC Header | LLC | IP Header | TCP Packet | FCS |
* | Others | Tpye |
*
* Therefore, we need translate mask_from_OS to mask_to_hw.
* We should left-shift mask by 6 bits, then set the new bit[0~5] = 0,
* because new mask[0~5] means 'SA', but our HW packet begins from LLC,
* bit[0~5] corresponds to first 6 Bytes in LLC, they just don't match.
*/
/* Shift 6 bits */
for (i = 0; i < mask_len - 1; i++) {
mask_hw[i] = u8_get_bits(mask[i], GENMASK(7, 6));
mask_hw[i] |= u8_get_bits(mask[i + 1], GENMASK(5, 0)) << 2;
}
mask_hw[i] = u8_get_bits(mask[i], GENMASK(7, 6));
/* Set bit 0-5 to zero */
mask_hw[0] &= (~GENMASK(5, 0));
memcpy(rtw_pattern->mask, mask_hw, RTW_MAX_PATTERN_MASK_SIZE);
/* To get the wake up pattern from the mask.
* We do not count first 12 bits which means
* DA[6] and SA[6] in the pattern to match HW design.
*/
count = 0;
for (i = 12; i < len; i++) {
if ((mask[i / 8] >> (i % 8)) & 0x01) {
content[count] = pattern[i];
count++;
}
}
rtw_pattern->crc = rtw_calc_crc(content, count);
}
static void rtw_wow_pattern_clear_cam(struct rtw_dev *rtwdev)
{
bool ret;
rtw_write32(rtwdev, REG_WKFMCAM_CMD, BIT_WKFCAM_POLLING_V1 |
BIT_WKFCAM_CLR_V1);
ret = check_hw_ready(rtwdev, REG_WKFMCAM_CMD, BIT_WKFCAM_POLLING_V1, 0);
if (!ret)
rtw_err(rtwdev, "failed to clean pattern cam\n");
}
static void rtw_wow_pattern_write(struct rtw_dev *rtwdev)
{
struct rtw_wow_param *rtw_wow = &rtwdev->wow;
struct rtw_wow_pattern *rtw_pattern = rtw_wow->patterns;
int i = 0;
for (i = 0; i < rtw_wow->pattern_cnt; i++)
rtw_wow_pattern_write_cam_ent(rtwdev, i, rtw_pattern + i);
}
static void rtw_wow_pattern_clear(struct rtw_dev *rtwdev)
{
struct rtw_wow_param *rtw_wow = &rtwdev->wow;
rtw_wow_pattern_clear_cam(rtwdev);
rtw_wow->pattern_cnt = 0;
memset(rtw_wow->patterns, 0, sizeof(rtw_wow->patterns));
}
static void rtw_wow_bb_stop(struct rtw_dev *rtwdev)
{
struct rtw_wow_param *rtw_wow = &rtwdev->wow;
/* wait 100ms for firmware to finish TX */
msleep(100);
if (!rtw_read32_mask(rtwdev, REG_BCNQ_INFO, BIT_MGQ_CPU_EMPTY))
rtw_warn(rtwdev, "Wrong status of MGQ_CPU empty!\n");
rtw_wow->txpause = rtw_read8(rtwdev, REG_TXPAUSE);
rtw_write8(rtwdev, REG_TXPAUSE, 0xff);
rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_BB_RSTB);
}
static void rtw_wow_bb_start(struct rtw_dev *rtwdev)
{
struct rtw_wow_param *rtw_wow = &rtwdev->wow;
rtw_write8_set(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_BB_RSTB);
rtw_write8(rtwdev, REG_TXPAUSE, rtw_wow->txpause);
}
static void rtw_wow_rx_dma_stop(struct rtw_dev *rtwdev)
{
/* wait 100ms for HW to finish rx dma */
msleep(100);
rtw_write32_set(rtwdev, REG_RXPKT_NUM, BIT_RW_RELEASE);
if (!check_hw_ready(rtwdev, REG_RXPKT_NUM, BIT_RXDMA_IDLE, 1))
rtw_err(rtwdev, "failed to stop rx dma\n");
}
static void rtw_wow_rx_dma_start(struct rtw_dev *rtwdev)
{
rtw_write32_clr(rtwdev, REG_RXPKT_NUM, BIT_RW_RELEASE);
}
static int rtw_wow_check_fw_status(struct rtw_dev *rtwdev, bool wow_enable)
{
int ret;
u8 check;
u32 check_dis;
if (wow_enable) {
ret = read_poll_timeout(rtw_read8, check, !check, 1000,
100000, true, rtwdev,
REG_WOWLAN_WAKE_REASON);
if (ret)
goto wow_fail;
} else {
ret = read_poll_timeout(rtw_read32_mask, check_dis,
!check_dis, 1000, 100000, true, rtwdev,
REG_FE1IMR, BIT_FS_RXDONE);
if (ret)
goto wow_fail;
ret = read_poll_timeout(rtw_read32_mask, check_dis,
!check_dis, 1000, 100000, false, rtwdev,
REG_RXPKT_NUM, BIT_RW_RELEASE);
if (ret)
goto wow_fail;
}
return 0;
wow_fail:
rtw_err(rtwdev, "failed to check wow status %s\n",
wow_enable ? "enabled" : "disabled");
return -EBUSY;
}
static void rtw_wow_fw_security_type_iter(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key,
void *data)
{
struct rtw_fw_key_type_iter_data *iter_data = data;
struct rtw_dev *rtwdev = hw->priv;
u8 hw_key_type;
if (vif != rtwdev->wow.wow_vif)
return;
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
hw_key_type = RTW_CAM_WEP40;
break;
case WLAN_CIPHER_SUITE_WEP104:
hw_key_type = RTW_CAM_WEP104;
break;
case WLAN_CIPHER_SUITE_TKIP:
hw_key_type = RTW_CAM_TKIP;
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
break;
case WLAN_CIPHER_SUITE_CCMP:
hw_key_type = RTW_CAM_AES;
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
break;
default:
rtw_err(rtwdev, "Unsupported key type for wowlan mode: %#x\n",
key->cipher);
hw_key_type = 0;
break;
}
if (sta)
iter_data->pairwise_key_type = hw_key_type;
else
iter_data->group_key_type = hw_key_type;
}
static void rtw_wow_fw_security_type(struct rtw_dev *rtwdev)
{
struct rtw_fw_key_type_iter_data data = {};
struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
data.rtwdev = rtwdev;
rtw_iterate_keys(rtwdev, wow_vif,
rtw_wow_fw_security_type_iter, &data);
rtw_fw_set_aoac_global_info_cmd(rtwdev, data.pairwise_key_type,
data.group_key_type);
}
static int rtw_wow_fw_start(struct rtw_dev *rtwdev)
{
if (rtw_wow_mgd_linked(rtwdev)) {
rtw_send_rsvd_page_h2c(rtwdev);
rtw_wow_pattern_write(rtwdev);
rtw_wow_fw_security_type(rtwdev);
rtw_fw_set_disconnect_decision_cmd(rtwdev, true);
rtw_fw_set_keep_alive_cmd(rtwdev, true);
} else if (rtw_wow_no_link(rtwdev)) {
rtw_fw_set_nlo_info(rtwdev, true);
rtw_fw_update_pkt_probe_req(rtwdev, NULL);
rtw_fw_channel_switch(rtwdev, true);
}
rtw_fw_set_wowlan_ctrl_cmd(rtwdev, true);
rtw_fw_set_remote_wake_ctrl_cmd(rtwdev, true);
return rtw_wow_check_fw_status(rtwdev, true);
}
static int rtw_wow_fw_stop(struct rtw_dev *rtwdev)
{
if (rtw_wow_mgd_linked(rtwdev)) {
rtw_fw_set_disconnect_decision_cmd(rtwdev, false);
rtw_fw_set_keep_alive_cmd(rtwdev, false);
rtw_wow_pattern_clear(rtwdev);
} else if (rtw_wow_no_link(rtwdev)) {
rtw_fw_channel_switch(rtwdev, false);
rtw_fw_set_nlo_info(rtwdev, false);
}
rtw_fw_set_wowlan_ctrl_cmd(rtwdev, false);
rtw_fw_set_remote_wake_ctrl_cmd(rtwdev, false);
return rtw_wow_check_fw_status(rtwdev, false);
}
static void rtw_wow_avoid_reset_mac(struct rtw_dev *rtwdev)
{
/* When resuming from wowlan mode, some hosts issue signal
* (PCIE: PREST, USB: SE0RST) to device, and lead to reset
* mac core. If it happens, the connection to AP will be lost.
* Setting REG_RSV_CTRL Register can avoid this process.
*/
switch (rtw_hci_type(rtwdev)) {
case RTW_HCI_TYPE_PCIE:
case RTW_HCI_TYPE_USB:
rtw_write8(rtwdev, REG_RSV_CTRL, BIT_WLOCK_1C_B6);
rtw_write8(rtwdev, REG_RSV_CTRL,
BIT_WLOCK_1C_B6 | BIT_R_DIS_PRST);
break;
default:
rtw_warn(rtwdev, "Unsupported hci type to disable reset MAC\n");
break;
}
}
static void rtw_wow_fw_media_status_iter(void *data, struct ieee80211_sta *sta)
{
struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
struct rtw_fw_media_status_iter_data *iter_data = data;
struct rtw_dev *rtwdev = iter_data->rtwdev;
rtw_fw_media_status_report(rtwdev, si->mac_id, iter_data->connect);
}
static void rtw_wow_fw_media_status(struct rtw_dev *rtwdev, bool connect)
{
struct rtw_fw_media_status_iter_data data;
data.rtwdev = rtwdev;
data.connect = connect;
rtw_iterate_stas_atomic(rtwdev, rtw_wow_fw_media_status_iter, &data);
}
static int rtw_wow_config_wow_fw_rsvd_page(struct rtw_dev *rtwdev)
{
struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
struct rtw_vif *rtwvif = (struct rtw_vif *)wow_vif->drv_priv;
rtw_remove_rsvd_page(rtwdev, rtwvif);
if (rtw_wow_no_link(rtwdev))
rtw_add_rsvd_page_pno(rtwdev, rtwvif);
else
rtw_add_rsvd_page_sta(rtwdev, rtwvif);
return rtw_fw_download_rsvd_page(rtwdev);
}
static int rtw_wow_config_normal_fw_rsvd_page(struct rtw_dev *rtwdev)
{
struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
struct rtw_vif *rtwvif = (struct rtw_vif *)wow_vif->drv_priv;
rtw_remove_rsvd_page(rtwdev, rtwvif);
rtw_add_rsvd_page_sta(rtwdev, rtwvif);
if (rtw_wow_no_link(rtwdev))
return 0;
return rtw_fw_download_rsvd_page(rtwdev);
}
static int rtw_wow_swap_fw(struct rtw_dev *rtwdev, enum rtw_fw_type type)
{
struct rtw_fw_state *fw;
int ret;
switch (type) {
case RTW_WOWLAN_FW:
fw = &rtwdev->wow_fw;
break;
case RTW_NORMAL_FW:
fw = &rtwdev->fw;
break;
default:
rtw_warn(rtwdev, "unsupported firmware type to swap\n");
return -ENOENT;
}
ret = rtw_download_firmware(rtwdev, fw);
if (ret)
goto out;
rtw_fw_send_general_info(rtwdev);
rtw_fw_send_phydm_info(rtwdev);
rtw_wow_fw_media_status(rtwdev, true);
out:
return ret;
}
static void rtw_wow_check_pno(struct rtw_dev *rtwdev,
struct cfg80211_sched_scan_request *nd_config)
{
struct rtw_wow_param *rtw_wow = &rtwdev->wow;
struct rtw_pno_request *pno_req = &rtw_wow->pno_req;
struct ieee80211_channel *channel;
int i, size;
if (!nd_config->n_match_sets || !nd_config->n_channels)
goto err;
pno_req->match_set_cnt = nd_config->n_match_sets;
size = sizeof(*pno_req->match_sets) * pno_req->match_set_cnt;
pno_req->match_sets = kmemdup(nd_config->match_sets, size, GFP_KERNEL);
if (!pno_req->match_sets)
goto err;
pno_req->channel_cnt = nd_config->n_channels;
size = sizeof(*nd_config->channels[0]) * nd_config->n_channels;
pno_req->channels = kmalloc(size, GFP_KERNEL);
if (!pno_req->channels)
goto channel_err;
for (i = 0 ; i < pno_req->channel_cnt; i++) {
channel = pno_req->channels + i;
memcpy(channel, nd_config->channels[i], sizeof(*channel));
}
pno_req->scan_plan = *nd_config->scan_plans;
pno_req->inited = true;
rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: net-detect is enabled\n");
return;
channel_err:
kfree(pno_req->match_sets);
err:
rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: net-detect is disabled\n");
}
static int rtw_wow_leave_linked_ps(struct rtw_dev *rtwdev)
{
if (!test_bit(RTW_FLAG_WOWLAN, rtwdev->flags))
cancel_delayed_work_sync(&rtwdev->watch_dog_work);
rtw_leave_lps(rtwdev);
return 0;
}
static int rtw_wow_leave_no_link_ps(struct rtw_dev *rtwdev)
{
struct rtw_wow_param *rtw_wow = &rtwdev->wow;
int ret = 0;
if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags)) {
if (rtw_get_lps_deep_mode(rtwdev) != LPS_DEEP_MODE_NONE)
rtw_leave_lps_deep(rtwdev);
} else {
if (!test_bit(RTW_FLAG_POWERON, rtwdev->flags)) {
rtw_wow->ips_enabled = true;
ret = rtw_leave_ips(rtwdev);
if (ret)
return ret;
}
}
return 0;
}
static int rtw_wow_leave_ps(struct rtw_dev *rtwdev)
{
int ret = 0;
if (rtw_wow_mgd_linked(rtwdev))
ret = rtw_wow_leave_linked_ps(rtwdev);
else if (rtw_wow_no_link(rtwdev))
ret = rtw_wow_leave_no_link_ps(rtwdev);
return ret;
}
static int rtw_wow_restore_ps(struct rtw_dev *rtwdev)
{
int ret = 0;
if (rtw_wow_no_link(rtwdev) && rtwdev->wow.ips_enabled)
ret = rtw_enter_ips(rtwdev);
return ret;
}
static int rtw_wow_enter_linked_ps(struct rtw_dev *rtwdev)
{
struct rtw_wow_param *rtw_wow = &rtwdev->wow;
struct ieee80211_vif *wow_vif = rtw_wow->wow_vif;
struct rtw_vif *rtwvif = (struct rtw_vif *)wow_vif->drv_priv;
rtw_enter_lps(rtwdev, rtwvif->port);
return 0;
}
static int rtw_wow_enter_no_link_ps(struct rtw_dev *rtwdev)
{
/* firmware enters deep ps by itself if supported */
set_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags);
return 0;
}
static int rtw_wow_enter_ps(struct rtw_dev *rtwdev)
{
int ret = 0;
if (rtw_wow_mgd_linked(rtwdev))
ret = rtw_wow_enter_linked_ps(rtwdev);
else if (rtw_wow_no_link(rtwdev) &&
rtw_get_lps_deep_mode(rtwdev) != LPS_DEEP_MODE_NONE)
ret = rtw_wow_enter_no_link_ps(rtwdev);
return ret;
}
static void rtw_wow_stop_trx(struct rtw_dev *rtwdev)
{
rtw_wow_bb_stop(rtwdev);
rtw_wow_rx_dma_stop(rtwdev);
}
static int rtw_wow_start(struct rtw_dev *rtwdev)
{
int ret;
ret = rtw_wow_fw_start(rtwdev);
if (ret)
goto out;
rtw_hci_stop(rtwdev);
rtw_wow_bb_start(rtwdev);
rtw_wow_avoid_reset_mac(rtwdev);
out:
return ret;
}
static int rtw_wow_enable(struct rtw_dev *rtwdev)
{
int ret = 0;
rtw_wow_stop_trx(rtwdev);
ret = rtw_wow_swap_fw(rtwdev, RTW_WOWLAN_FW);
if (ret) {
rtw_err(rtwdev, "failed to swap wow fw\n");
goto error;
}
set_bit(RTW_FLAG_WOWLAN, rtwdev->flags);
ret = rtw_wow_config_wow_fw_rsvd_page(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to download wowlan rsvd page\n");
goto error;
}
ret = rtw_wow_start(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to start wow\n");
goto error;
}
return ret;
error:
clear_bit(RTW_FLAG_WOWLAN, rtwdev->flags);
return ret;
}
static int rtw_wow_stop(struct rtw_dev *rtwdev)
{
int ret;
/* some HCI related registers will be reset after resume,
* need to set them again.
*/
ret = rtw_hci_setup(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to setup hci\n");
return ret;
}
ret = rtw_hci_start(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to start hci\n");
return ret;
}
ret = rtw_wow_fw_stop(rtwdev);
if (ret)
rtw_err(rtwdev, "failed to stop wowlan fw\n");
rtw_wow_bb_stop(rtwdev);
return ret;
}
static void rtw_wow_resume_trx(struct rtw_dev *rtwdev)
{
rtw_wow_rx_dma_start(rtwdev);
rtw_wow_bb_start(rtwdev);
ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->watch_dog_work,
RTW_WATCH_DOG_DELAY_TIME);
}
static int rtw_wow_disable(struct rtw_dev *rtwdev)
{
int ret;
clear_bit(RTW_FLAG_WOWLAN, rtwdev->flags);
ret = rtw_wow_stop(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to stop wow\n");
goto out;
}
ret = rtw_wow_swap_fw(rtwdev, RTW_NORMAL_FW);
if (ret) {
rtw_err(rtwdev, "failed to swap normal fw\n");
goto out;
}
ret = rtw_wow_config_normal_fw_rsvd_page(rtwdev);
if (ret)
rtw_err(rtwdev, "failed to download normal rsvd page\n");
out:
rtw_wow_resume_trx(rtwdev);
return ret;
}
static void rtw_wow_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
{
struct rtw_dev *rtwdev = data;
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
struct rtw_wow_param *rtw_wow = &rtwdev->wow;
/* Current wowlan function support setting of only one STATION vif.
* So when one suitable vif is found, stop the iteration.
*/
if (rtw_wow->wow_vif || vif->type != NL80211_IFTYPE_STATION)
return;
switch (rtwvif->net_type) {
case RTW_NET_MGD_LINKED:
rtw_wow->wow_vif = vif;
break;
case RTW_NET_NO_LINK:
if (rtw_wow->pno_req.inited)
rtwdev->wow.wow_vif = vif;
break;
default:
break;
}
}
static int rtw_wow_set_wakeups(struct rtw_dev *rtwdev,
struct cfg80211_wowlan *wowlan)
{
struct rtw_wow_param *rtw_wow = &rtwdev->wow;
struct rtw_wow_pattern *rtw_patterns = rtw_wow->patterns;
struct rtw_vif *rtwvif;
int i;
if (wowlan->disconnect)
set_bit(RTW_WOW_FLAG_EN_DISCONNECT, rtw_wow->flags);
if (wowlan->magic_pkt)
set_bit(RTW_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags);
if (wowlan->gtk_rekey_failure)
set_bit(RTW_WOW_FLAG_EN_REKEY_PKT, rtw_wow->flags);
if (wowlan->nd_config)
rtw_wow_check_pno(rtwdev, wowlan->nd_config);
rtw_iterate_vifs_atomic(rtwdev, rtw_wow_vif_iter, rtwdev);
if (!rtw_wow->wow_vif)
return -EPERM;
rtwvif = (struct rtw_vif *)rtw_wow->wow_vif->drv_priv;
if (wowlan->n_patterns && wowlan->patterns) {
rtw_wow->pattern_cnt = wowlan->n_patterns;
for (i = 0; i < wowlan->n_patterns; i++)
rtw_wow_pattern_generate(rtwdev, rtwvif,
wowlan->patterns + i,
rtw_patterns + i);
}
return 0;
}
static void rtw_wow_clear_wakeups(struct rtw_dev *rtwdev)
{
struct rtw_wow_param *rtw_wow = &rtwdev->wow;
struct rtw_pno_request *pno_req = &rtw_wow->pno_req;
if (pno_req->inited) {
kfree(pno_req->channels);
kfree(pno_req->match_sets);
}
memset(rtw_wow, 0, sizeof(rtwdev->wow));
}
int rtw_wow_suspend(struct rtw_dev *rtwdev, struct cfg80211_wowlan *wowlan)
{
int ret = 0;
ret = rtw_wow_set_wakeups(rtwdev, wowlan);
if (ret) {
rtw_err(rtwdev, "failed to set wakeup event\n");
goto out;
}
ret = rtw_wow_leave_ps(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to leave ps from normal mode\n");
goto out;
}
ret = rtw_wow_enable(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to enable wow\n");
rtw_wow_restore_ps(rtwdev);
goto out;
}
ret = rtw_wow_enter_ps(rtwdev);
if (ret)
rtw_err(rtwdev, "failed to enter ps for wow\n");
out:
return ret;
}
int rtw_wow_resume(struct rtw_dev *rtwdev)
{
int ret;
/* If wowlan mode is not enabled, do nothing */
if (!test_bit(RTW_FLAG_WOWLAN, rtwdev->flags)) {
rtw_err(rtwdev, "wow is not enabled\n");
ret = -EPERM;
goto out;
}
ret = rtw_wow_leave_ps(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to leave ps from wowlan mode\n");
goto out;
}
rtw_wow_show_wakeup_reason(rtwdev);
ret = rtw_wow_disable(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to disable wow\n");
goto out;
}
ret = rtw_wow_restore_ps(rtwdev);
if (ret)
rtw_err(rtwdev, "failed to restore ps to normal mode\n");
out:
rtw_wow_clear_wakeups(rtwdev);
return ret;
}
@@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_WOW_H__
#define __RTW_WOW_H__
#define PNO_CHECK_BYTE 4
enum rtw_wow_pattern_type {
RTW_PATTERN_BROADCAST = 0,
RTW_PATTERN_MULTICAST,
RTW_PATTERN_UNICAST,
RTW_PATTERN_VALID,
RTW_PATTERN_INVALID,
};
enum rtw_wake_reason {
RTW_WOW_RSN_RX_PTK_REKEY = 0x1,
RTW_WOW_RSN_RX_GTK_REKEY = 0x2,
RTW_WOW_RSN_RX_DEAUTH = 0x8,
RTW_WOW_RSN_DISCONNECT = 0x10,
RTW_WOW_RSN_RX_MAGIC_PKT = 0x21,
RTW_WOW_RSN_RX_PATTERN_MATCH = 0x23,
RTW_WOW_RSN_RX_NLO = 0x55,
};
struct rtw_fw_media_status_iter_data {
struct rtw_dev *rtwdev;
u8 connect;
};
struct rtw_fw_key_type_iter_data {
struct rtw_dev *rtwdev;
u8 group_key_type;
u8 pairwise_key_type;
};
static inline bool rtw_wow_mgd_linked(struct rtw_dev *rtwdev)
{
struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
struct rtw_vif *rtwvif = (struct rtw_vif *)wow_vif->drv_priv;
return (rtwvif->net_type == RTW_NET_MGD_LINKED);
}
static inline bool rtw_wow_no_link(struct rtw_dev *rtwdev)
{
struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
struct rtw_vif *rtwvif = (struct rtw_vif *)wow_vif->drv_priv;
return (rtwvif->net_type == RTW_NET_NO_LINK);
}
int rtw_wow_suspend(struct rtw_dev *rtwdev, struct cfg80211_wowlan *wowlan);
int rtw_wow_resume(struct rtw_dev *rtwdev);
#endif