Skip to content
Snippets Groups Projects
Commit 98686cd2 authored by Shayne Chen's avatar Shayne Chen Committed by Felix Fietkau
Browse files

wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices


The driver first supports Filogic 680 PCI device, which is a Wi-Fi 7
chipset supporting concurrent tri-band operation at 6 GHz, 5 GHz, and
2.4 GHz with 4x4 antennas on each band.

Currently, mt7996 only supports tri-band HE or older mode.
EHT mode and more variants of Filogic 680 support will be introduced
in further patches.

Reviewed-by: default avatarRyder Lee <ryder.lee@mediatek.com>
Co-developed-by: default avatarPeter Chiu <chui-hao.chiu@mediatek.com>
Signed-off-by: default avatarPeter Chiu <chui-hao.chiu@mediatek.com>
Co-developed-by: default avatarBo Jiao <Bo.Jiao@mediatek.com>
Signed-off-by: default avatarBo Jiao <Bo.Jiao@mediatek.com>
Co-developed-by: default avatarHoward Hsu <howard-yh.hsu@mediatek.com>
Signed-off-by: default avatarHoward Hsu <howard-yh.hsu@mediatek.com>
Co-developed-by: default avatarMeiChia Chiu <meichia.chiu@mediatek.com>
Signed-off-by: default avatarMeiChia Chiu <meichia.chiu@mediatek.com>
Co-developed-by: default avatarStanleyYP Wang <StanleyYP.Wang@mediatek.com>
Signed-off-by: default avatarStanleyYP Wang <StanleyYP.Wang@mediatek.com>
Co-developed-by: default avatarMoney Wang <Money.Wang@mediatek.com>
Signed-off-by: default avatarMoney Wang <Money.Wang@mediatek.com>
Co-developed-by: default avatarEvelyn Tsai <evelyn.tsai@mediatek.com>
Signed-off-by: default avatarEvelyn Tsai <evelyn.tsai@mediatek.com>
Signed-off-by: default avatarShayne Chen <shayne.chen@mediatek.com>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent f4cfd3f9
No related branches found
No related tags found
No related merge requests found
Showing
with 12289 additions and 0 deletions
...@@ -34,3 +34,4 @@ source "drivers/net/wireless/mediatek/mt76/mt7603/Kconfig" ...@@ -34,3 +34,4 @@ source "drivers/net/wireless/mediatek/mt76/mt7603/Kconfig"
source "drivers/net/wireless/mediatek/mt76/mt7615/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7615/Kconfig"
source "drivers/net/wireless/mediatek/mt76/mt7915/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7915/Kconfig"
source "drivers/net/wireless/mediatek/mt76/mt7921/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7921/Kconfig"
source "drivers/net/wireless/mediatek/mt76/mt7996/Kconfig"
...@@ -35,3 +35,4 @@ obj-$(CONFIG_MT7603E) += mt7603/ ...@@ -35,3 +35,4 @@ obj-$(CONFIG_MT7603E) += mt7603/
obj-$(CONFIG_MT7615_COMMON) += mt7615/ obj-$(CONFIG_MT7615_COMMON) += mt7615/
obj-$(CONFIG_MT7915E) += mt7915/ obj-$(CONFIG_MT7915E) += mt7915/
obj-$(CONFIG_MT7921_COMMON) += mt7921/ obj-$(CONFIG_MT7921_COMMON) += mt7921/
obj-$(CONFIG_MT7996E) += mt7996/
# SPDX-License-Identifier: ISC
config MT7996E
tristate "MediaTek MT7996 (PCIe) support"
select MT76_CONNAC_LIB
depends on MAC80211
depends on PCI
help
This adds support for MT7996-based wireless PCIe devices,
which support concurrent tri-band operation at 6GHz, 5GHz,
and 2.4GHz IEEE 802.11be 4x4:4SS 4096-QAM, 320MHz channels.
To compile this driver as a module, choose M here.
# SPDX-License-Identifier: ISC
obj-$(CONFIG_MT7996E) += mt7996e.o
mt7996e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \
debugfs.o mmio.o
This diff is collapsed.
// SPDX-License-Identifier: ISC
/*
* Copyright (C) 2022 MediaTek Inc.
*/
#include "mt7996.h"
#include "../dma.h"
#include "mac.h"
static int mt7996_poll_tx(struct napi_struct *napi, int budget)
{
struct mt7996_dev *dev;
dev = container_of(napi, struct mt7996_dev, mt76.tx_napi);
mt76_connac_tx_cleanup(&dev->mt76);
if (napi_complete_done(napi, 0))
mt7996_irq_enable(dev, MT_INT_TX_DONE_MCU);
return 0;
}
static void mt7996_dma_config(struct mt7996_dev *dev)
{
#define Q_CONFIG(q, wfdma, int, id) do { \
if (wfdma) \
dev->q_wfdma_mask |= (1 << (q)); \
dev->q_int_mask[(q)] = int; \
dev->q_id[(q)] = id; \
} while (0)
#define MCUQ_CONFIG(q, wfdma, int, id) Q_CONFIG(q, (wfdma), (int), (id))
#define RXQ_CONFIG(q, wfdma, int, id) Q_CONFIG(__RXQ(q), (wfdma), (int), (id))
#define TXQ_CONFIG(q, wfdma, int, id) Q_CONFIG(__TXQ(q), (wfdma), (int), (id))
/* rx queue */
RXQ_CONFIG(MT_RXQ_MCU, WFDMA0, MT_INT_RX_DONE_WM, MT7996_RXQ_MCU_WM);
RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_RX_DONE_WA, MT7996_RXQ_MCU_WA);
/* band0/band1 */
RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0, MT7996_RXQ_BAND0);
RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_RX_DONE_WA_MAIN, MT7996_RXQ_MCU_WA_MAIN);
/* band2 */
RXQ_CONFIG(MT_RXQ_BAND2, WFDMA0, MT_INT_RX_DONE_BAND2, MT7996_RXQ_BAND2);
RXQ_CONFIG(MT_RXQ_BAND2_WA, WFDMA0, MT_INT_RX_DONE_WA_TRI, MT7996_RXQ_MCU_WA_TRI);
/* data tx queue */
TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0);
TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1);
TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, MT7996_TXQ_BAND2);
/* mcu tx queue */
MCUQ_CONFIG(MT_MCUQ_WM, WFDMA0, MT_INT_TX_DONE_MCU_WM, MT7996_TXQ_MCU_WM);
MCUQ_CONFIG(MT_MCUQ_WA, WFDMA0, MT_INT_TX_DONE_MCU_WA, MT7996_TXQ_MCU_WA);
MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA0, MT_INT_TX_DONE_FWDL, MT7996_TXQ_FWDL);
}
static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs)
{
#define PREFETCH(_base, _depth) ((_base) << 16 | (_depth))
/* prefetch SRAM wrapping boundary for tx/rx ring. */
mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_FWDL) + ofs, PREFETCH(0x0, 0x2));
mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WM) + ofs, PREFETCH(0x20, 0x2));
mt76_wr(dev, MT_TXQ_EXT_CTRL(0) + ofs, PREFETCH(0x40, 0x4));
mt76_wr(dev, MT_TXQ_EXT_CTRL(1) + ofs, PREFETCH(0x80, 0x4));
mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0xc0, 0x2));
mt76_wr(dev, MT_TXQ_EXT_CTRL(2) + ofs, PREFETCH(0xe0, 0x4));
mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(0x120, 0x2));
mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(0x140, 0x2));
mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(0x160, 0x2));
mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2_WA) + ofs, PREFETCH(0x180, 0x2));
mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x1a0, 0x10));
mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2) + ofs, PREFETCH(0x2a0, 0x10));
mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1 + ofs, WF_WFDMA0_GLO_CFG_EXT1_CALC_MODE);
}
void mt7996_dma_prefetch(struct mt7996_dev *dev)
{
__mt7996_dma_prefetch(dev, 0);
if (dev->hif2)
__mt7996_dma_prefetch(dev, MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0));
}
static void mt7996_dma_disable(struct mt7996_dev *dev, bool reset)
{
u32 hif1_ofs = 0;
if (dev->hif2)
hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
if (reset) {
mt76_clear(dev, MT_WFDMA0_RST,
MT_WFDMA0_RST_DMASHDL_ALL_RST |
MT_WFDMA0_RST_LOGIC_RST);
mt76_set(dev, MT_WFDMA0_RST,
MT_WFDMA0_RST_DMASHDL_ALL_RST |
MT_WFDMA0_RST_LOGIC_RST);
if (dev->hif2) {
mt76_clear(dev, MT_WFDMA0_RST + hif1_ofs,
MT_WFDMA0_RST_DMASHDL_ALL_RST |
MT_WFDMA0_RST_LOGIC_RST);
mt76_set(dev, MT_WFDMA0_RST + hif1_ofs,
MT_WFDMA0_RST_DMASHDL_ALL_RST |
MT_WFDMA0_RST_LOGIC_RST);
}
}
/* disable */
mt76_clear(dev, MT_WFDMA0_GLO_CFG,
MT_WFDMA0_GLO_CFG_TX_DMA_EN |
MT_WFDMA0_GLO_CFG_RX_DMA_EN |
MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
MT_WFDMA0_GLO_CFG_OMIT_RX_INFO |
MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
if (dev->hif2) {
mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
MT_WFDMA0_GLO_CFG_TX_DMA_EN |
MT_WFDMA0_GLO_CFG_RX_DMA_EN |
MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
MT_WFDMA0_GLO_CFG_OMIT_RX_INFO |
MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
}
}
static int mt7996_dma_enable(struct mt7996_dev *dev)
{
u32 hif1_ofs = 0;
u32 irq_mask;
if (dev->hif2)
hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
/* reset dma idx */
mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0);
if (dev->hif2)
mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR + hif1_ofs, ~0);
/* configure delay interrupt off */
mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0);
mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG1, 0);
mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG2, 0);
if (dev->hif2) {
mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0 + hif1_ofs, 0);
mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG1 + hif1_ofs, 0);
mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG2 + hif1_ofs, 0);
}
/* configure perfetch settings */
mt7996_dma_prefetch(dev);
/* hif wait WFDMA idle */
mt76_set(dev, MT_WFDMA0_BUSY_ENA,
MT_WFDMA0_BUSY_ENA_TX_FIFO0 |
MT_WFDMA0_BUSY_ENA_TX_FIFO1 |
MT_WFDMA0_BUSY_ENA_RX_FIFO);
if (dev->hif2)
mt76_set(dev, MT_WFDMA0_BUSY_ENA + hif1_ofs,
MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 |
MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 |
MT_WFDMA0_PCIE1_BUSY_ENA_RX_FIFO);
mt76_poll(dev, MT_WFDMA_EXT_CSR_HIF_MISC,
MT_WFDMA_EXT_CSR_HIF_MISC_BUSY, 0, 1000);
/* set WFDMA Tx/Rx */
mt76_set(dev, MT_WFDMA0_GLO_CFG,
MT_WFDMA0_GLO_CFG_TX_DMA_EN |
MT_WFDMA0_GLO_CFG_RX_DMA_EN |
MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
/* GLO_CFG_EXT0 */
mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT0,
WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD |
WF_WFDMA0_GLO_CFG_EXT0_WED_MERGE_MODE);
/* GLO_CFG_EXT1 */
mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1,
WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE);
if (dev->hif2) {
mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
MT_WFDMA0_GLO_CFG_TX_DMA_EN |
MT_WFDMA0_GLO_CFG_RX_DMA_EN |
MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
/* GLO_CFG_EXT0 */
mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD |
WF_WFDMA0_GLO_CFG_EXT0_WED_MERGE_MODE);
/* GLO_CFG_EXT1 */
mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1 + hif1_ofs,
WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE);
mt76_set(dev, MT_WFDMA_HOST_CONFIG,
MT_WFDMA_HOST_CONFIG_PDMA_BAND);
}
if (dev->hif2) {
/* fix hardware limitation, pcie1's rx ring3 is not available
* so, redirect pcie0 rx ring3 interrupt to pcie1
*/
mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL,
MT_WFDMA0_RX_INT_SEL_RING3);
/* TODO: redirect rx ring6 interrupt to pcie0 for wed function */
}
/* enable interrupts for TX/RX rings */
irq_mask = MT_INT_RX_DONE_MCU |
MT_INT_TX_DONE_MCU |
MT_INT_MCU_CMD;
if (!dev->mphy.band_idx)
irq_mask |= MT_INT_BAND0_RX_DONE;
if (dev->dbdc_support)
irq_mask |= MT_INT_BAND1_RX_DONE;
if (dev->tbtc_support)
irq_mask |= MT_INT_BAND2_RX_DONE;
mt7996_irq_enable(dev, irq_mask);
return 0;
}
int mt7996_dma_init(struct mt7996_dev *dev)
{
u32 hif1_ofs = 0;
int ret;
mt7996_dma_config(dev);
mt76_dma_attach(&dev->mt76);
if (dev->hif2)
hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
mt7996_dma_disable(dev, true);
/* init tx queue */
ret = mt76_connac_init_tx_queues(dev->phy.mt76,
MT_TXQ_ID(dev->mphy.band_idx),
MT7996_TX_RING_SIZE,
MT_TXQ_RING_BASE(0), 0);
if (ret)
return ret;
/* command to WM */
ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM,
MT_MCUQ_ID(MT_MCUQ_WM),
MT7996_TX_MCU_RING_SIZE,
MT_MCUQ_RING_BASE(MT_MCUQ_WM));
if (ret)
return ret;
/* command to WA */
ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WA,
MT_MCUQ_ID(MT_MCUQ_WA),
MT7996_TX_MCU_RING_SIZE,
MT_MCUQ_RING_BASE(MT_MCUQ_WA));
if (ret)
return ret;
/* firmware download */
ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL,
MT_MCUQ_ID(MT_MCUQ_FWDL),
MT7996_TX_FWDL_RING_SIZE,
MT_MCUQ_RING_BASE(MT_MCUQ_FWDL));
if (ret)
return ret;
/* event from WM */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU],
MT_RXQ_ID(MT_RXQ_MCU),
MT7996_RX_MCU_RING_SIZE,
MT_RX_BUF_SIZE,
MT_RXQ_RING_BASE(MT_RXQ_MCU));
if (ret)
return ret;
/* event from WA */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA],
MT_RXQ_ID(MT_RXQ_MCU_WA),
MT7996_RX_MCU_RING_SIZE,
MT_RX_BUF_SIZE,
MT_RXQ_RING_BASE(MT_RXQ_MCU_WA));
if (ret)
return ret;
/* rx data queue for band0 and band1 */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN],
MT_RXQ_ID(MT_RXQ_MAIN),
MT7996_RX_RING_SIZE,
MT_RX_BUF_SIZE,
MT_RXQ_RING_BASE(MT_RXQ_MAIN));
if (ret)
return ret;
/* tx free notify event from WA for band0 */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN_WA],
MT_RXQ_ID(MT_RXQ_MAIN_WA),
MT7996_RX_MCU_RING_SIZE,
MT_RX_BUF_SIZE,
MT_RXQ_RING_BASE(MT_RXQ_MAIN_WA));
if (ret)
return ret;
if (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) {
/* rx data queue for band2 */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2],
MT_RXQ_ID(MT_RXQ_BAND2),
MT7996_RX_RING_SIZE,
MT_RX_BUF_SIZE,
MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs);
if (ret)
return ret;
/* tx free notify event from WA for band2
* use pcie0's rx ring3, but, redirect pcie0 rx ring3 interrupt to pcie1
*/
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2_WA],
MT_RXQ_ID(MT_RXQ_BAND2_WA),
MT7996_RX_MCU_RING_SIZE,
MT_RX_BUF_SIZE,
MT_RXQ_RING_BASE(MT_RXQ_BAND2_WA));
if (ret)
return ret;
}
ret = mt76_init_queues(dev, mt76_dma_rx_poll);
if (ret < 0)
return ret;
netif_napi_add_tx(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi,
mt7996_poll_tx);
napi_enable(&dev->mt76.tx_napi);
mt7996_dma_enable(dev);
return 0;
}
void mt7996_dma_cleanup(struct mt7996_dev *dev)
{
mt7996_dma_disable(dev, true);
mt76_dma_cleanup(&dev->mt76);
}
// SPDX-License-Identifier: ISC
/*
* Copyright (C) 2022 MediaTek Inc.
*/
#include <linux/firmware.h>
#include "mt7996.h"
#include "eeprom.h"
static int mt7996_check_eeprom(struct mt7996_dev *dev)
{
u8 *eeprom = dev->mt76.eeprom.data;
u16 val = get_unaligned_le16(eeprom);
switch (val) {
case 0x7990:
return 0;
default:
return -EINVAL;
}
}
static char *mt7996_eeprom_name(struct mt7996_dev *dev)
{
/* reserve for future variants */
return MT7996_EEPROM_DEFAULT;
}
static int
mt7996_eeprom_load_default(struct mt7996_dev *dev)
{
u8 *eeprom = dev->mt76.eeprom.data;
const struct firmware *fw = NULL;
int ret;
ret = request_firmware(&fw, mt7996_eeprom_name(dev), dev->mt76.dev);
if (ret)
return ret;
if (!fw || !fw->data) {
dev_err(dev->mt76.dev, "Invalid default bin\n");
ret = -EINVAL;
goto out;
}
memcpy(eeprom, fw->data, MT7996_EEPROM_SIZE);
dev->flash_mode = true;
out:
release_firmware(fw);
return ret;
}
static int mt7996_eeprom_load(struct mt7996_dev *dev)
{
int ret;
ret = mt76_eeprom_init(&dev->mt76, MT7996_EEPROM_SIZE);
if (ret < 0)
return ret;
if (ret) {
dev->flash_mode = true;
} else {
u8 free_block_num;
u32 block_num, i;
/* TODO: check free block event */
mt7996_mcu_get_eeprom_free_block(dev, &free_block_num);
/* efuse info not enough */
if (free_block_num >= 59)
return -EINVAL;
/* read eeprom data from efuse */
block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, MT7996_EEPROM_BLOCK_SIZE);
for (i = 0; i < block_num; i++)
mt7996_mcu_get_eeprom(dev, i * MT7996_EEPROM_BLOCK_SIZE);
}
return mt7996_check_eeprom(dev);
}
static int mt7996_eeprom_parse_band_config(struct mt7996_phy *phy)
{
u8 *eeprom = phy->dev->mt76.eeprom.data;
u32 val = eeprom[MT_EE_WIFI_CONF];
int ret = 0;
switch (phy->mt76->band_idx) {
case MT_BAND1:
val = FIELD_GET(MT_EE_WIFI_CONF1_BAND_SEL, val);
break;
case MT_BAND2:
val = eeprom[MT_EE_WIFI_CONF + 1];
val = FIELD_GET(MT_EE_WIFI_CONF2_BAND_SEL, val);
break;
default:
val = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val);
break;
}
switch (val) {
case MT_EE_BAND_SEL_2GHZ:
phy->mt76->cap.has_2ghz = true;
break;
case MT_EE_BAND_SEL_5GHZ:
phy->mt76->cap.has_5ghz = true;
break;
case MT_EE_BAND_SEL_6GHZ:
phy->mt76->cap.has_6ghz = true;
break;
case MT_EE_BAND_SEL_5GHZ_6GHZ:
phy->mt76->cap.has_5ghz = true;
phy->mt76->cap.has_6ghz = true;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy)
{
u8 path, nss, band_idx = phy->mt76->band_idx;
u8 *eeprom = dev->mt76.eeprom.data;
struct mt76_phy *mphy = phy->mt76;
switch (band_idx) {
case MT_BAND1:
path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND1,
eeprom[MT_EE_WIFI_CONF + 2]);
nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND1,
eeprom[MT_EE_WIFI_CONF + 5]);
break;
case MT_BAND2:
path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND2,
eeprom[MT_EE_WIFI_CONF + 2]);
nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND2,
eeprom[MT_EE_WIFI_CONF + 5]);
break;
default:
path = FIELD_GET(MT_EE_WIFI_CONF1_TX_PATH_BAND0,
eeprom[MT_EE_WIFI_CONF + 1]);
nss = FIELD_GET(MT_EE_WIFI_CONF4_STREAM_NUM_BAND0,
eeprom[MT_EE_WIFI_CONF + 4]);
break;
}
if (!path || path > 4)
path = 4;
nss = min_t(u8, min_t(u8, 4, nss), path);
mphy->antenna_mask = BIT(nss) - 1;
mphy->chainmask = (BIT(path) - 1) << dev->chainshift[band_idx];
dev->chainmask |= mphy->chainmask;
if (band_idx < MT_BAND2)
dev->chainshift[band_idx + 1] = dev->chainshift[band_idx] +
hweight16(mphy->chainmask);
return mt7996_eeprom_parse_band_config(phy);
}
int mt7996_eeprom_init(struct mt7996_dev *dev)
{
int ret;
ret = mt7996_eeprom_load(dev);
if (ret < 0) {
if (ret != -EINVAL)
return ret;
dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n");
ret = mt7996_eeprom_load_default(dev);
if (ret)
return ret;
}
ret = mt7996_eeprom_parse_hw_cap(dev, &dev->phy);
if (ret < 0)
return ret;
memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, ETH_ALEN);
mt76_eeprom_override(&dev->mphy);
return 0;
}
int mt7996_eeprom_get_target_power(struct mt7996_dev *dev,
struct ieee80211_channel *chan)
{
u8 *eeprom = dev->mt76.eeprom.data;
int target_power;
if (chan->band == NL80211_BAND_5GHZ)
target_power = eeprom[MT_EE_TX0_POWER_5G +
mt7996_get_channel_group_5g(chan->hw_value)];
else if (chan->band == NL80211_BAND_6GHZ)
target_power = eeprom[MT_EE_TX0_POWER_6G +
mt7996_get_channel_group_6g(chan->hw_value)];
else
target_power = eeprom[MT_EE_TX0_POWER_2G];
return target_power;
}
s8 mt7996_eeprom_get_power_delta(struct mt7996_dev *dev, int band)
{
u8 *eeprom = dev->mt76.eeprom.data;
u32 val;
s8 delta;
if (band == NL80211_BAND_5GHZ)
val = eeprom[MT_EE_RATE_DELTA_5G];
else if (band == NL80211_BAND_6GHZ)
val = eeprom[MT_EE_RATE_DELTA_6G];
else
val = eeprom[MT_EE_RATE_DELTA_2G];
if (!(val & MT_EE_RATE_DELTA_EN))
return 0;
delta = FIELD_GET(MT_EE_RATE_DELTA_MASK, val);
return val & MT_EE_RATE_DELTA_SIGN ? delta : -delta;
}
/* SPDX-License-Identifier: ISC */
/*
* Copyright (C) 2022 MediaTek Inc.
*/
#ifndef __MT7996_EEPROM_H
#define __MT7996_EEPROM_H
#include "mt7996.h"
enum mt7996_eeprom_field {
MT_EE_CHIP_ID = 0x000,
MT_EE_VERSION = 0x002,
MT_EE_MAC_ADDR = 0x004,
MT_EE_MAC_ADDR2 = 0x00a,
MT_EE_WIFI_CONF = 0x190,
MT_EE_MAC_ADDR3 = 0x2c0,
MT_EE_RATE_DELTA_2G = 0x1400,
MT_EE_RATE_DELTA_5G = 0x147d,
MT_EE_RATE_DELTA_6G = 0x154a,
MT_EE_TX0_POWER_2G = 0x1300,
MT_EE_TX0_POWER_5G = 0x1301,
MT_EE_TX0_POWER_6G = 0x1310,
__MT_EE_MAX = 0x1dff,
};
#define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0)
#define MT_EE_WIFI_CONF0_BAND_SEL GENMASK(2, 0)
#define MT_EE_WIFI_CONF1_BAND_SEL GENMASK(5, 3)
#define MT_EE_WIFI_CONF2_BAND_SEL GENMASK(2, 0)
#define MT_EE_WIFI_CONF1_TX_PATH_BAND0 GENMASK(5, 3)
#define MT_EE_WIFI_CONF2_TX_PATH_BAND1 GENMASK(5, 3)
#define MT_EE_WIFI_CONF2_TX_PATH_BAND2 GENMASK(2, 0)
#define MT_EE_WIFI_CONF4_STREAM_NUM_BAND0 GENMASK(5, 3)
#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND1 GENMASK(5, 3)
#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND2 GENMASK(2, 0)
#define MT_EE_RATE_DELTA_MASK GENMASK(5, 0)
#define MT_EE_RATE_DELTA_SIGN BIT(6)
#define MT_EE_RATE_DELTA_EN BIT(7)
enum mt7996_eeprom_band {
MT_EE_BAND_SEL_DEFAULT,
MT_EE_BAND_SEL_2GHZ,
MT_EE_BAND_SEL_5GHZ,
MT_EE_BAND_SEL_6GHZ,
MT_EE_BAND_SEL_5GHZ_6GHZ,
};
static inline int
mt7996_get_channel_group_5g(int channel)
{
if (channel <= 64)
return 0;
if (channel <= 96)
return 1;
if (channel <= 128)
return 2;
if (channel <= 144)
return 3;
return 4;
}
static inline int
mt7996_get_channel_group_6g(int channel)
{
if (channel <= 29)
return 0;
return DIV_ROUND_UP(channel - 29, 32);
}
#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.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment