Commit e3037485 authored by Yan-Hsuan Chuang's avatar Yan-Hsuan Chuang Committed by Kalle Valo

rtw88: new Realtek 802.11ac driver

This is a new mac80211 driver for Realtek 802.11ac wireless network chips.
rtw88 now supports RTL8822BE/RTL8822CE now, with basic station mode
functionalities. The firmware for both can be found at linux-firmware.

https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git
For RTL8822BE: rtw88/rtw8822b_fw.bin
For RTL8822CE: rtw88/rtw8822c_fw.bin

And for now, only PCI buses (RTL8xxxE) are supported. We will add support
for USB and SDIO in the future. The bus interface abstraction can be seen
in this driver such as hci.h. Most of the hardware setting are the same
except for some TRX path or probing setup should be separated.

Supported:

 * Basic STA/AP/ADHOC mode, and TDLS (STA is well tested)

Missing feature:

 * WOW/PNO
 * USB & SDIO bus (such as RTL8xxxU/RTL8xxxS)
 * BT coexistence (8822B/8822C are combo ICs)
 * Multiple interfaces (for now single STA is better supported)
 * Dynamic hardware calibrations (to improve/stabilize performance)

Potential problems:

 * static calibration spends too much time, and it is painful for
   driver to leave IDLE state. And slows down associate process.
   But reload function are under development, will be added soon!
 * TRX statictics misleading, as we are not reporting status correctly,
   or say, not reporting for "every" packet.

The next patch set should have BT coexistence code since RTL8822B/C are
combo ICs, and the driver for BT can be found after Linux Kernel v4.20.
So it is better to add it first to make WiFi + BT work concurrently.

Although now rtw88 is simple but we are developing more features for it.
Even we want to add support for more chips such as RTL8821C/RTL8814B.

Finally, rtw88 has many authors, listed alphabetically:

Ping-Ke Shih <pkshih@realtek.com>
Tzu-En Huang <tehuang@realtek.com>
Yan-Hsuan Chuang <yhchuang@realtek.com>
Reviewed-by: default avatarStanislaw Gruszka <sgruszka@redhat.com>
Reviewed-by: default avatarBrian Norris <briannorris@chromium.org>
Tested-by: default avatarBrian Norris <briannorris@chromium.org>
Signed-off-by: default avatarYan-Hsuan Chuang <yhchuang@realtek.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent c745f722
......@@ -13396,6 +13396,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.g
S: Maintained
F: drivers/net/wireless/realtek/rtlwifi/
REALTEK WIRELESS DRIVER (rtw88)
M: Yan-Hsuan Chuang <yhchuang@realtek.com>
L: linux-wireless@vger.kernel.org
S: Maintained
F: drivers/net/wireless/realtek/rtw88/
RTL8XXXU WIRELESS DRIVER (rtl8xxxu)
M: Jes Sorensen <Jes.Sorensen@gmail.com>
L: linux-wireless@vger.kernel.org
......
......@@ -14,5 +14,6 @@ if WLAN_VENDOR_REALTEK
source "drivers/net/wireless/realtek/rtl818x/Kconfig"
source "drivers/net/wireless/realtek/rtlwifi/Kconfig"
source "drivers/net/wireless/realtek/rtl8xxxu/Kconfig"
source "drivers/net/wireless/realtek/rtw88/Kconfig"
endif # WLAN_VENDOR_REALTEK
......@@ -6,4 +6,5 @@ obj-$(CONFIG_RTL8180) += rtl818x/
obj-$(CONFIG_RTL8187) += rtl818x/
obj-$(CONFIG_RTLWIFI) += rtlwifi/
obj-$(CONFIG_RTL8XXXU) += rtl8xxxu/
obj-$(CONFIG_RTW88) += rtw88/
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
config RTW88_PCI
tristate
config RTW88_8822BE
bool "Realtek 8822BE PCI wireless network adapter"
depends on PCI
select RTW88_CORE
select RTW88_PCI
help
Select this option will enable support for 8822BE chipset
802.11ac PCIe wireless network adapter
config RTW88_8822CE
bool "Realtek 8822CE PCI wireless network adapter"
depends on PCI
select RTW88_CORE
select RTW88_PCI
help
Select this option will enable support for 8822CE chipset
802.11ac PCIe 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
endif
obj-$(CONFIG_RTW88_CORE) += rtw88.o
rtw88-y += main.o \
mac80211.o \
util.o \
debug.o \
tx.o \
rx.o \
mac.o \
phy.o \
efuse.o \
fw.o \
ps.o \
sec.o \
regd.o
rtw88-$(CONFIG_RTW88_8822BE) += rtw8822b.o rtw8822b_table.o
rtw88-$(CONFIG_RTW88_8822CE) += rtw8822c.o rtw8822c_table.o
obj-$(CONFIG_RTW88_PCI) += rtwpci.o
rtwpci-objs := pci.o
This diff is collapsed.
/* 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_ALL = 0xffffffff
};
#ifdef CONFIG_RTW88_DEBUGFS
void rtw_debugfs_init(struct rtw_dev *rtwdev);
#else
static inline void rtw_debugfs_init(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, ...);
#define rtw_dbg(rtwdev, a...) __rtw_dbg(rtwdev, ##a)
#else
static inline void rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask,
const char *fmt, ...) {}
#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
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#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)
{
struct rtw_chip_info *chip = rtwdev->chip;
u32 size = rtwdev->efuse.physical_size;
u32 efuse_ctl;
u32 addr;
u32 cnt;
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);
}
return 0;
}
int rtw_parse_efuse_map(struct rtw_dev *rtwdev)
{
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;
}
/* 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 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);
#endif
This diff is collapsed.
/* 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_HDR_VERSION 4
#define FW_HDR_SUBVERSION 6
#define FW_HDR_SUBINDEX 7
#define FW_HDR_MONTH 16
#define FW_HDR_DATE 17
#define FW_HDR_HOUR 18
#define FW_HDR_MIN 19
#define FW_HDR_YEAR 20
#define FW_HDR_MEM_USAGE 24
#define FW_HDR_H2C_FMT_VER 28
#define FW_HDR_DMEM_ADDR 32
#define FW_HDR_DMEM_SIZE 36
#define FW_HDR_IMEM_SIZE 48
#define FW_HDR_EMEM_SIZE 52
#define FW_HDR_EMEM_ADDR 56
#define FW_HDR_IMEM_ADDR 60
#define FIFO_PAGE_SIZE_SHIFT 12
#define FIFO_PAGE_SIZE 4096
#define RSVD_PAGE_START_ADDR 0x780
#define FIFO_DUMP_ADDR 0x8000
enum rtw_c2h_cmd_id {
C2H_BT_INFO = 0x09,
C2H_HW_FEATURE_REPORT = 0x19,
C2H_HW_FEATURE_DUMP = 0xfd,
C2H_HALMAC = 0xff,
};
enum rtw_c2h_cmd_id_ext {
C2H_CCX_RPT = 0x0f,
};
struct rtw_c2h_cmd {
u8 id;
u8 seq;
u8 payload[0];
} __packed;
enum rtw_rsvd_packet_type {
RSVD_BEACON,
RSVD_PS_POLL,
RSVD_PROBE_RESP,
RSVD_NULL,
RSVD_QOS_NULL,
};
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,
};
struct rtw_iqk_para {
u8 clear;
u8 segment_iqk;
};
struct rtw_rsvd_page {
struct list_head list;
struct sk_buff *skb;
enum rtw_rsvd_packet_type type;
u8 page;
bool add_txdesc;
};
/* C2H */
#define GET_CCX_REPORT_SEQNUM(c2h_payload) (c2h_payload[8] & 0xfc)
#define GET_CCX_REPORT_STATUS(c2h_payload) (c2h_payload[9] & 0xc0)
/* 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 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))
/* 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_RA_INFO 0x40
#define H2C_CMD_RSSI_MONITOR 0x42
#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_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 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))
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);
}
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_do_iqk(struct rtw_dev *rtwdev, struct rtw_iqk_para *para);
void rtw_fw_set_pwr_mode(struct rtw_dev *rtwdev);
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);
void rtw_fw_media_status_report(struct rtw_dev *rtwdev, u8 mac_id, bool conn);
void rtw_add_rsvd_page(struct rtw_dev *rtwdev, enum rtw_rsvd_packet_type type,
bool txdesc);
int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr,
u8 *buf, u32 size);
void rtw_reset_rsvd_page(struct rtw_dev *rtwdev);
int rtw_fw_download_rsvd_page(struct rtw_dev *rtwdev,
struct ieee80211_vif *vif);
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);
#endif
/* 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)(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
struct sk_buff *skb);
int (*setup)(struct rtw_dev *rtwdev);
int (*start)(struct rtw_dev *rtwdev);
void (*stop)(struct rtw_dev *rtwdev);
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(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
struct sk_buff *skb)
{
return rtwdev->hci.ops->tx(rtwdev, pkt_info, skb);
}
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 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_writ16_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)
{
unsigned long flags;
u32 val;
spin_lock_irqsave(&rtwdev->rf_lock, flags);
val = rtwdev->chip->ops->read_rf(rtwdev, rf_path, addr, mask);
spin_unlock_irqrestore(&rtwdev->rf_lock, flags);
return val;
}
static inline void
rtw_write_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask, u32 data)
{
unsigned long flags;
spin_lock_irqsave(&rtwdev->rf_lock, flags);
rtwdev->chip->ops->write_rf(rtwdev, rf_path, addr, mask, data);
spin_unlock_irqrestore(&rtwdev->rf_lock, flags);
}
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 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;
}
#endif
This diff is collapsed.
/* 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 SDIO_LOCAL_OFFSET 0x10250000
#define DDMA_POLLING_COUNT 1000
#define C2H_PKT_BUF 256
#define PHY_STATUS_SIZE 4
#define ILLEGAL_KEY_GROUP 0xFAAAAA00
/* HW memory address */
#define OCPBASE_TXBUF_88XX 0x18780000
#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_mac_power_on(struct rtw_dev *rtwdev);
void rtw_mac_power_off(struct rtw_dev *rtwdev);
int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw);
int rtw_mac_init(struct rtw_dev *rtwdev);
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTK_PCI_H_
#define __RTK_PCI_H_
#define RTK_PCI_DEVICE(vend, dev, hw_config) \
PCI_DEVICE(vend, dev), \
.driver_data = (kernel_ulong_t)&(hw_config),
#define RTK_DEFAULT_TX_DESC_NUM 128
#define RTK_BEQ_TX_DESC_NUM 256
#define RTK_MAX_RX_DESC_NUM 512
/* 8K + rx desc size */
#define RTK_PCI_RX_BUF_SIZE (8192 + 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_FLAG_V1 0x03F0
#define REG_MDIO_V1 0x03F4
#define REG_PCIE_MIX_CFG 0x03F8
#define BIT_MDIO_WFLAG_V1 BIT(5)
#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
/* 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)
/* 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 irq_lock;
u32 irq_mask[4];
bool irq_enabled;
u16 rx_tag;
struct rtw_pci_tx_ring tx_rings[RTK_MAX_TX_QUEUE_NUM];
struct rtw_pci_rx_ring rx_rings[RTK_MAX_RX_QUEUE_NUM];
void __iomem *mmap;
};
static 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
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* 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 2
int rtw_enter_ips(struct rtw_dev *rtwdev);
int rtw_leave_ips(struct rtw_dev *rtwdev);
void rtw_lps_work(struct work_struct *work);
void rtw_enter_lps_irqsafe(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif);
void rtw_leave_lps_irqsafe(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif);
void rtw_enter_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif);
void rtw_leave_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif);
bool rtw_in_lps(struct rtw_dev *rtwdev);
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment