You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
mt76: add driver for MT7603E and MT7628/7688
This driver is for a newer generation of 2x2 MediaTek 802.11n chipsets. MT7603E is a PCIe chip. MT7628 and MT7688 are MIPS SoC devices with built-in WLAN. MT7688 is limited to 1x1 This driver fully supports AP, station, mesh, ad-hoc and monitor mode. Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
@@ -21,3 +21,4 @@ config MT76x02_USB
|
||||
|
||||
source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig"
|
||||
source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig"
|
||||
source "drivers/net/wireless/mediatek/mt76/mt7603/Kconfig"
|
||||
|
||||
@@ -22,3 +22,4 @@ mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
|
||||
|
||||
obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
|
||||
obj-$(CONFIG_MT76x2_COMMON) += mt76x2/
|
||||
obj-$(CONFIG_MT7603E) += mt7603/
|
||||
|
||||
9
drivers/net/wireless/mediatek/mt76/mt7603/Kconfig
Normal file
9
drivers/net/wireless/mediatek/mt76/mt7603/Kconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
config MT7603E
|
||||
tristate "MediaTek MT7603E (PCIe) and MT76x8 WLAN support"
|
||||
select MT76_CORE
|
||||
depends on MAC80211
|
||||
depends on PCI
|
||||
help
|
||||
This adds support for MT7603E wireless PCIe devices and the WLAN core on
|
||||
MT7628/MT7688 SoC devices
|
||||
|
||||
6
drivers/net/wireless/mediatek/mt76/mt7603/Makefile
Normal file
6
drivers/net/wireless/mediatek/mt76/mt7603/Makefile
Normal file
@@ -0,0 +1,6 @@
|
||||
obj-$(CONFIG_MT7603E) += mt7603e.o
|
||||
|
||||
mt7603e-y := \
|
||||
pci.o soc.o main.o init.o mcu.o \
|
||||
core.o dma.o mac.o eeprom.o \
|
||||
beacon.o debugfs.o
|
||||
186
drivers/net/wireless/mediatek/mt76/mt7603/beacon.c
Normal file
186
drivers/net/wireless/mediatek/mt76/mt7603/beacon.c
Normal file
@@ -0,0 +1,186 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
|
||||
#include "mt7603.h"
|
||||
|
||||
struct beacon_bc_data {
|
||||
struct mt7603_dev *dev;
|
||||
struct sk_buff_head q;
|
||||
struct sk_buff *tail[MT7603_MAX_INTERFACES];
|
||||
int count[MT7603_MAX_INTERFACES];
|
||||
};
|
||||
|
||||
static void
|
||||
mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct mt7603_dev *dev = (struct mt7603_dev *)priv;
|
||||
struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv;
|
||||
struct sk_buff *skb = NULL;
|
||||
|
||||
if (!(dev->beacon_mask & BIT(mvif->idx)))
|
||||
return;
|
||||
|
||||
skb = ieee80211_beacon_get(mt76_hw(dev), vif);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
mt76_dma_tx_queue_skb(&dev->mt76, &dev->mt76.q_tx[MT_TXQ_BEACON], skb,
|
||||
&mvif->sta.wcid, NULL);
|
||||
|
||||
spin_lock_bh(&dev->ps_lock);
|
||||
mt76_wr(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY |
|
||||
FIELD_PREP(MT_DMA_FQCR0_TARGET_WCID, mvif->sta.wcid.idx) |
|
||||
FIELD_PREP(MT_DMA_FQCR0_TARGET_QID,
|
||||
dev->mt76.q_tx[MT_TXQ_CAB].hw_idx) |
|
||||
FIELD_PREP(MT_DMA_FQCR0_DEST_PORT_ID, 3) |
|
||||
FIELD_PREP(MT_DMA_FQCR0_DEST_QUEUE_ID, 8));
|
||||
|
||||
if (!mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY, 0, 5000))
|
||||
dev->beacon_check = MT7603_WATCHDOG_TIMEOUT;
|
||||
|
||||
spin_unlock_bh(&dev->ps_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7603_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct beacon_bc_data *data = priv;
|
||||
struct mt7603_dev *dev = data->dev;
|
||||
struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv;
|
||||
struct ieee80211_tx_info *info;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!(dev->beacon_mask & BIT(mvif->idx)))
|
||||
return;
|
||||
|
||||
skb = ieee80211_get_buffered_bc(mt76_hw(dev), vif);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
info->control.vif = vif;
|
||||
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
||||
mt76_skb_set_moredata(skb, true);
|
||||
__skb_queue_tail(&data->q, skb);
|
||||
data->tail[mvif->idx] = skb;
|
||||
data->count[mvif->idx]++;
|
||||
}
|
||||
|
||||
void mt7603_pre_tbtt_tasklet(unsigned long arg)
|
||||
{
|
||||
struct mt7603_dev *dev = (struct mt7603_dev *)arg;
|
||||
struct mt76_queue *q;
|
||||
struct beacon_bc_data data = {};
|
||||
struct sk_buff *skb;
|
||||
int i, nframes;
|
||||
|
||||
data.dev = dev;
|
||||
__skb_queue_head_init(&data.q);
|
||||
|
||||
q = &dev->mt76.q_tx[MT_TXQ_BEACON];
|
||||
spin_lock_bh(&q->lock);
|
||||
ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
|
||||
IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||
mt7603_update_beacon_iter, dev);
|
||||
mt76_queue_kick(dev, q);
|
||||
spin_unlock_bh(&q->lock);
|
||||
|
||||
/* Flush all previous CAB queue packets */
|
||||
mt76_wr(dev, MT_WF_ARB_CAB_FLUSH, GENMASK(30, 16) | BIT(0));
|
||||
|
||||
mt76_queue_tx_cleanup(dev, MT_TXQ_CAB, false);
|
||||
|
||||
mt76_csa_check(&dev->mt76);
|
||||
if (dev->mt76.csa_complete)
|
||||
goto out;
|
||||
|
||||
q = &dev->mt76.q_tx[MT_TXQ_CAB];
|
||||
do {
|
||||
nframes = skb_queue_len(&data.q);
|
||||
ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
|
||||
IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||
mt7603_add_buffered_bc, &data);
|
||||
} while (nframes != skb_queue_len(&data.q) &&
|
||||
skb_queue_len(&data.q) < 8);
|
||||
|
||||
if (skb_queue_empty(&data.q))
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(data.tail); i++) {
|
||||
if (!data.tail[i])
|
||||
continue;
|
||||
|
||||
mt76_skb_set_moredata(data.tail[i], false);
|
||||
}
|
||||
|
||||
spin_lock_bh(&q->lock);
|
||||
while ((skb = __skb_dequeue(&data.q)) != NULL) {
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_vif *vif = info->control.vif;
|
||||
struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv;
|
||||
|
||||
mt76_dma_tx_queue_skb(&dev->mt76, q, skb, &mvif->sta.wcid,
|
||||
NULL);
|
||||
}
|
||||
mt76_queue_kick(dev, q);
|
||||
spin_unlock_bh(&q->lock);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(data.count); i++)
|
||||
mt76_wr(dev, MT_WF_ARB_CAB_COUNT_B0_REG(i),
|
||||
data.count[i] << MT_WF_ARB_CAB_COUNT_B0_SHIFT(i));
|
||||
|
||||
mt76_wr(dev, MT_WF_ARB_CAB_START,
|
||||
MT_WF_ARB_CAB_START_BSSn(0) |
|
||||
(MT_WF_ARB_CAB_START_BSS0n(1) *
|
||||
((1 << (MT7603_MAX_INTERFACES - 1)) - 1)));
|
||||
|
||||
out:
|
||||
mt76_queue_tx_cleanup(dev, MT_TXQ_BEACON, false);
|
||||
if (dev->mt76.q_tx[MT_TXQ_BEACON].queued >
|
||||
__sw_hweight8(dev->beacon_mask))
|
||||
dev->beacon_check++;
|
||||
}
|
||||
|
||||
void mt7603_beacon_set_timer(struct mt7603_dev *dev, int idx, int intval)
|
||||
{
|
||||
u32 pre_tbtt = MT7603_PRE_TBTT_TIME / 64;
|
||||
|
||||
if (idx >= 0) {
|
||||
if (intval)
|
||||
dev->beacon_mask |= BIT(idx);
|
||||
else
|
||||
dev->beacon_mask &= ~BIT(idx);
|
||||
}
|
||||
|
||||
if (!dev->beacon_mask || (!intval && idx < 0)) {
|
||||
mt7603_irq_disable(dev, MT_INT_MAC_IRQ3);
|
||||
mt76_clear(dev, MT_ARB_SCR, MT_ARB_SCR_BCNQ_OPMODE_MASK);
|
||||
mt76_wr(dev, MT_HW_INT_MASK(3), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
dev->beacon_int = intval;
|
||||
mt76_wr(dev, MT_TBTT,
|
||||
FIELD_PREP(MT_TBTT_PERIOD, intval) | MT_TBTT_CAL_ENABLE);
|
||||
|
||||
mt76_wr(dev, MT_TBTT_TIMER_CFG, 0x99); /* start timer */
|
||||
|
||||
mt76_rmw_field(dev, MT_ARB_SCR, MT_ARB_SCR_BCNQ_OPMODE_MASK,
|
||||
MT_BCNQ_OPMODE_AP);
|
||||
mt76_clear(dev, MT_ARB_SCR, MT_ARB_SCR_TBTT_BCN_PRIO);
|
||||
mt76_set(dev, MT_ARB_SCR, MT_ARB_SCR_TBTT_BCAST_PRIO);
|
||||
|
||||
mt76_wr(dev, MT_PRE_TBTT, pre_tbtt);
|
||||
|
||||
mt76_set(dev, MT_HW_INT_MASK(3),
|
||||
MT_HW_INT3_PRE_TBTT0 | MT_HW_INT3_TBTT0);
|
||||
|
||||
mt76_set(dev, MT_WF_ARB_BCN_START,
|
||||
MT_WF_ARB_BCN_START_BSSn(0) |
|
||||
((dev->beacon_mask >> 1) * MT_WF_ARB_BCN_START_BSS0n(1)));
|
||||
mt7603_irq_enable(dev, MT_INT_MAC_IRQ3);
|
||||
|
||||
if (dev->beacon_mask & ~BIT(0))
|
||||
mt76_set(dev, MT_LPON_SBTOR(0), MT_LPON_SBTOR_SUB_BSS_EN);
|
||||
else
|
||||
mt76_clear(dev, MT_LPON_SBTOR(0), MT_LPON_SBTOR_SUB_BSS_EN);
|
||||
}
|
||||
73
drivers/net/wireless/mediatek/mt76/mt7603/core.c
Normal file
73
drivers/net/wireless/mediatek/mt76/mt7603/core.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
|
||||
#include "mt7603.h"
|
||||
|
||||
void mt7603_set_irq_mask(struct mt7603_dev *dev, u32 clear, u32 set)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->mt76.mmio.irq_lock, flags);
|
||||
dev->mt76.mmio.irqmask &= ~clear;
|
||||
dev->mt76.mmio.irqmask |= set;
|
||||
mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask);
|
||||
spin_unlock_irqrestore(&dev->mt76.mmio.irq_lock, flags);
|
||||
}
|
||||
|
||||
void mt7603_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
|
||||
{
|
||||
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
|
||||
|
||||
mt7603_irq_enable(dev, MT_INT_RX_DONE(q));
|
||||
}
|
||||
|
||||
irqreturn_t mt7603_irq_handler(int irq, void *dev_instance)
|
||||
{
|
||||
struct mt7603_dev *dev = dev_instance;
|
||||
u32 intr;
|
||||
|
||||
intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
|
||||
mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
|
||||
|
||||
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state))
|
||||
return IRQ_NONE;
|
||||
|
||||
intr &= dev->mt76.mmio.irqmask;
|
||||
|
||||
if (intr & MT_INT_MAC_IRQ3) {
|
||||
u32 hwintr = mt76_rr(dev, MT_HW_INT_STATUS(3));
|
||||
|
||||
mt76_wr(dev, MT_HW_INT_STATUS(3), hwintr);
|
||||
if (hwintr & MT_HW_INT3_PRE_TBTT0)
|
||||
tasklet_schedule(&dev->pre_tbtt_tasklet);
|
||||
|
||||
if ((hwintr & MT_HW_INT3_TBTT0) && dev->mt76.csa_complete)
|
||||
mt76_csa_finish(&dev->mt76);
|
||||
}
|
||||
|
||||
if (intr & MT_INT_TX_DONE_ALL) {
|
||||
mt7603_irq_disable(dev, MT_INT_TX_DONE_ALL);
|
||||
tasklet_schedule(&dev->tx_tasklet);
|
||||
}
|
||||
|
||||
if (intr & MT_INT_RX_DONE(0)) {
|
||||
mt7603_irq_disable(dev, MT_INT_RX_DONE(0));
|
||||
napi_schedule(&dev->mt76.napi[0]);
|
||||
}
|
||||
|
||||
if (intr & MT_INT_RX_DONE(1)) {
|
||||
mt7603_irq_disable(dev, MT_INT_RX_DONE(1));
|
||||
napi_schedule(&dev->mt76.napi[1]);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
u32 mt7603_reg_map(struct mt7603_dev *dev, u32 addr)
|
||||
{
|
||||
u32 base = addr & GENMASK(31, 19);
|
||||
u32 offset = addr & GENMASK(18, 0);
|
||||
|
||||
dev->bus_ops->wr(&dev->mt76, MT_MCU_PCIE_REMAP_2, base);
|
||||
|
||||
return MT_PCIE_REMAP_BASE_2 + offset;
|
||||
}
|
||||
56
drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c
Normal file
56
drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
|
||||
#include "mt7603.h"
|
||||
|
||||
static int
|
||||
mt7603_reset_read(struct seq_file *s, void *data)
|
||||
{
|
||||
struct mt7603_dev *dev = dev_get_drvdata(s->private);
|
||||
static const char * const reset_cause_str[] = {
|
||||
[RESET_CAUSE_TX_HANG] = "TX hang",
|
||||
[RESET_CAUSE_TX_BUSY] = "TX DMA busy stuck",
|
||||
[RESET_CAUSE_RX_BUSY] = "RX DMA busy stuck",
|
||||
[RESET_CAUSE_RX_PSE_BUSY] = "RX PSE busy stuck",
|
||||
[RESET_CAUSE_BEACON_STUCK] = "Beacon stuck",
|
||||
[RESET_CAUSE_MCU_HANG] = "MCU hang",
|
||||
[RESET_CAUSE_RESET_FAILED] = "PSE reset failed",
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(reset_cause_str); i++) {
|
||||
if (!reset_cause_str[i])
|
||||
continue;
|
||||
|
||||
seq_printf(s, "%20s: %u\n", reset_cause_str[i],
|
||||
dev->reset_cause[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7603_radio_read(struct seq_file *s, void *data)
|
||||
{
|
||||
struct mt7603_dev *dev = dev_get_drvdata(s->private);
|
||||
|
||||
seq_printf(s, "Sensitivity: %d\n", dev->sensitivity);
|
||||
seq_printf(s, "False CCA: ofdm=%d cck=%d\n",
|
||||
dev->false_cca_ofdm, dev->false_cca_cck);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mt7603_init_debugfs(struct mt7603_dev *dev)
|
||||
{
|
||||
struct dentry *dir;
|
||||
|
||||
dir = mt76_register_debugfs(&dev->mt76);
|
||||
if (!dir)
|
||||
return;
|
||||
|
||||
debugfs_create_u32("reset_test", 0600, dir, &dev->reset_test);
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "reset", dir,
|
||||
mt7603_reset_read);
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "radio", dir,
|
||||
mt7603_radio_read);
|
||||
}
|
||||
215
drivers/net/wireless/mediatek/mt76/mt7603/dma.c
Normal file
215
drivers/net/wireless/mediatek/mt76/mt7603/dma.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
|
||||
#include "mt7603.h"
|
||||
#include "mac.h"
|
||||
#include "../dma.h"
|
||||
|
||||
static int
|
||||
mt7603_init_tx_queue(struct mt7603_dev *dev, struct mt76_queue *q,
|
||||
int idx, int n_desc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
q->hw_idx = idx;
|
||||
q->regs = dev->mt76.mmio.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE;
|
||||
q->ndesc = n_desc;
|
||||
|
||||
ret = mt76_queue_alloc(dev, q);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mt7603_irq_enable(dev, MT_INT_TX_DONE(idx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb)
|
||||
{
|
||||
__le32 *txd = (__le32 *)skb->data;
|
||||
struct mt7603_sta *msta;
|
||||
struct mt76_wcid *wcid;
|
||||
int idx;
|
||||
u32 val;
|
||||
|
||||
if (skb->len < sizeof(MT_TXD_SIZE) + sizeof(struct ieee80211_hdr))
|
||||
goto free;
|
||||
|
||||
val = le32_to_cpu(txd[1]);
|
||||
idx = FIELD_GET(MT_TXD1_WLAN_IDX, val);
|
||||
skb->priority = FIELD_GET(MT_TXD1_TID, val);
|
||||
|
||||
if (idx >= MT7603_WTBL_STA - 1)
|
||||
goto free;
|
||||
|
||||
wcid = rcu_dereference(dev->mt76.wcid[idx]);
|
||||
if (!wcid)
|
||||
goto free;
|
||||
|
||||
msta = container_of(wcid, struct mt7603_sta, wcid);
|
||||
val = le32_to_cpu(txd[0]);
|
||||
skb_set_queue_mapping(skb, FIELD_GET(MT_TXD0_Q_IDX, val));
|
||||
|
||||
spin_lock_bh(&dev->ps_lock);
|
||||
__skb_queue_tail(&msta->psq, skb);
|
||||
if (skb_queue_len(&msta->psq) >= 64) {
|
||||
skb = __skb_dequeue(&msta->psq);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
spin_unlock_bh(&dev->ps_lock);
|
||||
return;
|
||||
|
||||
free:
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
void mt7603_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
|
||||
__le32 *rxd = (__le32 *)skb->data;
|
||||
__le32 *end = (__le32 *)&skb->data[skb->len];
|
||||
enum rx_pkt_type type;
|
||||
|
||||
type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0]));
|
||||
|
||||
if (q == MT_RXQ_MCU) {
|
||||
if (type == PKT_TYPE_RX_EVENT)
|
||||
mt76_mcu_rx_event(&dev->mt76, skb);
|
||||
else
|
||||
mt7603_rx_loopback_skb(dev, skb);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case PKT_TYPE_TXS:
|
||||
for (rxd++; rxd + 5 <= end; rxd += 5)
|
||||
mt7603_mac_add_txs(dev, rxd);
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
case PKT_TYPE_RX_EVENT:
|
||||
mt76_mcu_rx_event(&dev->mt76, skb);
|
||||
return;
|
||||
case PKT_TYPE_NORMAL:
|
||||
if (mt7603_mac_fill_rx(dev, skb) == 0) {
|
||||
mt76_rx(&dev->mt76, q, skb);
|
||||
return;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
mt7603_init_rx_queue(struct mt7603_dev *dev, struct mt76_queue *q,
|
||||
int idx, int n_desc, int bufsize)
|
||||
{
|
||||
int ret;
|
||||
|
||||
q->regs = dev->mt76.mmio.regs + MT_RX_RING_BASE + idx * MT_RING_SIZE;
|
||||
q->ndesc = n_desc;
|
||||
q->buf_size = bufsize;
|
||||
|
||||
ret = mt76_queue_alloc(dev, q);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mt7603_irq_enable(dev, MT_INT_RX_DONE(idx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7603_tx_tasklet(unsigned long data)
|
||||
{
|
||||
struct mt7603_dev *dev = (struct mt7603_dev *)data;
|
||||
int i;
|
||||
|
||||
dev->tx_dma_check = 0;
|
||||
for (i = MT_TXQ_MCU; i >= 0; i--)
|
||||
mt76_queue_tx_cleanup(dev, i, false);
|
||||
|
||||
mt7603_irq_enable(dev, MT_INT_TX_DONE_ALL);
|
||||
}
|
||||
|
||||
int mt7603_dma_init(struct mt7603_dev *dev)
|
||||
{
|
||||
static const u8 wmm_queue_map[] = {
|
||||
[IEEE80211_AC_BK] = 0,
|
||||
[IEEE80211_AC_BE] = 1,
|
||||
[IEEE80211_AC_VI] = 2,
|
||||
[IEEE80211_AC_VO] = 3,
|
||||
};
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
mt76_dma_attach(&dev->mt76);
|
||||
|
||||
init_waitqueue_head(&dev->mt76.mmio.mcu.wait);
|
||||
skb_queue_head_init(&dev->mt76.mmio.mcu.res_q);
|
||||
|
||||
tasklet_init(&dev->tx_tasklet, mt7603_tx_tasklet, (unsigned long)dev);
|
||||
|
||||
mt76_clear(dev, MT_WPDMA_GLO_CFG,
|
||||
MT_WPDMA_GLO_CFG_TX_DMA_EN |
|
||||
MT_WPDMA_GLO_CFG_RX_DMA_EN |
|
||||
MT_WPDMA_GLO_CFG_DMA_BURST_SIZE |
|
||||
MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
|
||||
|
||||
mt76_wr(dev, MT_WPDMA_RST_IDX, ~0);
|
||||
mt7603_pse_client_reset(dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) {
|
||||
ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[i],
|
||||
wmm_queue_map[i],
|
||||
MT_TX_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_PSD],
|
||||
MT_TX_HW_QUEUE_MGMT, MT_TX_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
|
||||
MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_BEACON],
|
||||
MT_TX_HW_QUEUE_BCN, MT_MCU_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_CAB],
|
||||
MT_TX_HW_QUEUE_BMC, MT_MCU_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt7603_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1,
|
||||
MT_MCU_RING_SIZE, MT_RX_BUF_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt7603_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], 0,
|
||||
MT7603_RX_RING_SIZE, MT_RX_BUF_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mt76_wr(dev, MT_DELAY_INT_CFG, 0);
|
||||
return mt76_init_queues(dev);
|
||||
}
|
||||
|
||||
void mt7603_dma_cleanup(struct mt7603_dev *dev)
|
||||
{
|
||||
mt76_clear(dev, MT_WPDMA_GLO_CFG,
|
||||
MT_WPDMA_GLO_CFG_TX_DMA_EN |
|
||||
MT_WPDMA_GLO_CFG_RX_DMA_EN |
|
||||
MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
|
||||
|
||||
tasklet_kill(&dev->tx_tasklet);
|
||||
mt76_dma_cleanup(&dev->mt76);
|
||||
}
|
||||
168
drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c
Normal file
168
drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
|
||||
#include "mt7603.h"
|
||||
#include "eeprom.h"
|
||||
|
||||
static int
|
||||
mt7603_efuse_read(struct mt7603_dev *dev, u32 base, u16 addr, u8 *data)
|
||||
{
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
val = mt76_rr(dev, base + MT_EFUSE_CTRL);
|
||||
val &= ~(MT_EFUSE_CTRL_AIN |
|
||||
MT_EFUSE_CTRL_MODE);
|
||||
val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf);
|
||||
val |= MT_EFUSE_CTRL_KICK;
|
||||
mt76_wr(dev, base + MT_EFUSE_CTRL, val);
|
||||
|
||||
if (!mt76_poll(dev, base + MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
udelay(2);
|
||||
|
||||
val = mt76_rr(dev, base + MT_EFUSE_CTRL);
|
||||
if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT ||
|
||||
WARN_ON_ONCE(!(val & MT_EFUSE_CTRL_VALID))) {
|
||||
memset(data, 0xff, 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
val = mt76_rr(dev, base + MT_EFUSE_RDATA(i));
|
||||
put_unaligned_le32(val, data + 4 * i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7603_efuse_init(struct mt7603_dev *dev)
|
||||
{
|
||||
u32 base = mt7603_reg_map(dev, MT_EFUSE_BASE);
|
||||
int len = MT7603_EEPROM_SIZE;
|
||||
void *buf;
|
||||
int ret, i;
|
||||
|
||||
if (mt76_rr(dev, base + MT_EFUSE_BASE_CTRL) & MT_EFUSE_BASE_CTRL_EMPTY)
|
||||
return 0;
|
||||
|
||||
dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, len, GFP_KERNEL);
|
||||
dev->mt76.otp.size = len;
|
||||
if (!dev->mt76.otp.data)
|
||||
return -ENOMEM;
|
||||
|
||||
buf = dev->mt76.otp.data;
|
||||
for (i = 0; i + 16 <= len; i += 16) {
|
||||
ret = mt7603_efuse_read(dev, base, i, buf + i);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
mt7603_has_cal_free_data(struct mt7603_dev *dev, u8 *efuse)
|
||||
{
|
||||
if (!efuse[MT_EE_TEMP_SENSOR_CAL])
|
||||
return false;
|
||||
|
||||
if (get_unaligned_le16(efuse + MT_EE_TX_POWER_0_START_2G) == 0)
|
||||
return false;
|
||||
|
||||
if (get_unaligned_le16(efuse + MT_EE_TX_POWER_1_START_2G) == 0)
|
||||
return false;
|
||||
|
||||
if (!efuse[MT_EE_CP_FT_VERSION])
|
||||
return false;
|
||||
|
||||
if (!efuse[MT_EE_XTAL_FREQ_OFFSET])
|
||||
return false;
|
||||
|
||||
if (!efuse[MT_EE_XTAL_WF_RFCAL])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7603_apply_cal_free_data(struct mt7603_dev *dev, u8 *efuse)
|
||||
{
|
||||
static const u8 cal_free_bytes[] = {
|
||||
MT_EE_TEMP_SENSOR_CAL,
|
||||
MT_EE_CP_FT_VERSION,
|
||||
MT_EE_XTAL_FREQ_OFFSET,
|
||||
MT_EE_XTAL_WF_RFCAL,
|
||||
/* Skip for MT7628 */
|
||||
MT_EE_TX_POWER_0_START_2G,
|
||||
MT_EE_TX_POWER_0_START_2G + 1,
|
||||
MT_EE_TX_POWER_1_START_2G,
|
||||
MT_EE_TX_POWER_1_START_2G + 1,
|
||||
};
|
||||
u8 *eeprom = dev->mt76.eeprom.data;
|
||||
int n = ARRAY_SIZE(cal_free_bytes);
|
||||
int i;
|
||||
|
||||
if (!mt7603_has_cal_free_data(dev, efuse))
|
||||
return;
|
||||
|
||||
if (is_mt7628(dev))
|
||||
n -= 4;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
int offset = cal_free_bytes[i];
|
||||
|
||||
eeprom[offset] = efuse[offset];
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
mt7603_eeprom_load(struct mt7603_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mt76_eeprom_init(&dev->mt76, MT7603_EEPROM_SIZE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return mt7603_efuse_init(dev);
|
||||
}
|
||||
|
||||
static int mt7603_check_eeprom(struct mt76_dev *dev)
|
||||
{
|
||||
u16 val = get_unaligned_le16(dev->eeprom.data);
|
||||
|
||||
switch (val) {
|
||||
case 0x7628:
|
||||
case 0x7603:
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int mt7603_eeprom_init(struct mt7603_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mt7603_eeprom_load(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (dev->mt76.otp.data) {
|
||||
if (mt7603_check_eeprom(&dev->mt76) == 0)
|
||||
mt7603_apply_cal_free_data(dev, dev->mt76.otp.data);
|
||||
else
|
||||
memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data,
|
||||
MT7603_EEPROM_SIZE);
|
||||
}
|
||||
|
||||
dev->mt76.cap.has_2ghz = true;
|
||||
memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
|
||||
ETH_ALEN);
|
||||
|
||||
mt76_eeprom_override(&dev->mt76);
|
||||
|
||||
return 0;
|
||||
}
|
||||
86
drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h
Normal file
86
drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
|
||||
#ifndef __MT7603_EEPROM_H
|
||||
#define __MT7603_EEPROM_H
|
||||
|
||||
#include "mt7603.h"
|
||||
|
||||
enum mt7603_eeprom_field {
|
||||
MT_EE_CHIP_ID = 0x000,
|
||||
MT_EE_VERSION = 0x002,
|
||||
MT_EE_MAC_ADDR = 0x004,
|
||||
MT_EE_NIC_CONF_0 = 0x034,
|
||||
MT_EE_NIC_CONF_1 = 0x036,
|
||||
MT_EE_NIC_CONF_2 = 0x042,
|
||||
|
||||
MT_EE_XTAL_TRIM_1 = 0x03a,
|
||||
|
||||
MT_EE_RSSI_OFFSET_2G = 0x046,
|
||||
MT_EE_WIFI_RF_SETTING = 0x048,
|
||||
MT_EE_RSSI_OFFSET_5G = 0x04a,
|
||||
|
||||
MT_EE_TX_POWER_DELTA_BW40 = 0x050,
|
||||
MT_EE_TX_POWER_DELTA_BW80 = 0x052,
|
||||
|
||||
MT_EE_TX_POWER_EXT_PA_5G = 0x054,
|
||||
|
||||
MT_EE_TEMP_SENSOR_CAL = 0x055,
|
||||
|
||||
MT_EE_TX_POWER_0_START_2G = 0x056,
|
||||
MT_EE_TX_POWER_1_START_2G = 0x05c,
|
||||
|
||||
/* used as byte arrays */
|
||||
#define MT_TX_POWER_GROUP_SIZE_5G 5
|
||||
#define MT_TX_POWER_GROUPS_5G 6
|
||||
MT_EE_TX_POWER_0_START_5G = 0x062,
|
||||
|
||||
MT_EE_TX_POWER_0_GRP3_TX_POWER_DELTA = 0x074,
|
||||
MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE = 0x076,
|
||||
|
||||
MT_EE_TX_POWER_1_START_5G = 0x080,
|
||||
|
||||
MT_EE_TX_POWER_CCK = 0x0a0,
|
||||
MT_EE_TX_POWER_OFDM_2G_6M = 0x0a2,
|
||||
MT_EE_TX_POWER_OFDM_2G_24M = 0x0a4,
|
||||
MT_EE_TX_POWER_OFDM_2G_54M = 0x0a6,
|
||||
MT_EE_TX_POWER_HT_BPSK_QPSK = 0x0a8,
|
||||
MT_EE_TX_POWER_HT_16_64_QAM = 0x0aa,
|
||||
MT_EE_TX_POWER_HT_64_QAM = 0x0ac,
|
||||
|
||||
MT_EE_ELAN_RX_MODE_GAIN = 0x0c0,
|
||||
MT_EE_ELAN_RX_MODE_NF = 0x0c1,
|
||||
MT_EE_ELAN_RX_MODE_P1DB = 0x0c2,
|
||||
|
||||
MT_EE_ELAN_BYPASS_MODE_GAIN = 0x0c3,
|
||||
MT_EE_ELAN_BYPASS_MODE_NF = 0x0c4,
|
||||
MT_EE_ELAN_BYPASS_MODE_P1DB = 0x0c5,
|
||||
|
||||
MT_EE_STEP_NUM_NEG_6_7 = 0x0c6,
|
||||
MT_EE_STEP_NUM_NEG_4_5 = 0x0c8,
|
||||
MT_EE_STEP_NUM_NEG_2_3 = 0x0ca,
|
||||
MT_EE_STEP_NUM_NEG_0_1 = 0x0cc,
|
||||
|
||||
MT_EE_REF_STEP_24G = 0x0ce,
|
||||
|
||||
MT_EE_STEP_NUM_PLUS_1_2 = 0x0d0,
|
||||
MT_EE_STEP_NUM_PLUS_3_4 = 0x0d2,
|
||||
MT_EE_STEP_NUM_PLUS_5_6 = 0x0d4,
|
||||
MT_EE_STEP_NUM_PLUS_7 = 0x0d6,
|
||||
|
||||
MT_EE_CP_FT_VERSION = 0x0f0,
|
||||
|
||||
MT_EE_XTAL_FREQ_OFFSET = 0x0f4,
|
||||
MT_EE_XTAL_TRIM_2_COMP = 0x0f5,
|
||||
MT_EE_XTAL_TRIM_3_COMP = 0x0f6,
|
||||
MT_EE_XTAL_WF_RFCAL = 0x0f7,
|
||||
|
||||
__MT_EE_MAX
|
||||
};
|
||||
|
||||
enum mt7603_eeprom_source {
|
||||
MT_EE_SRC_PROM,
|
||||
MT_EE_SRC_EFUSE,
|
||||
MT_EE_SRC_FLASH,
|
||||
};
|
||||
|
||||
#endif
|
||||
578
drivers/net/wireless/mediatek/mt76/mt7603/init.c
Normal file
578
drivers/net/wireless/mediatek/mt76/mt7603/init.c
Normal file
File diff suppressed because it is too large
Load Diff
1749
drivers/net/wireless/mediatek/mt76/mt7603/mac.c
Normal file
1749
drivers/net/wireless/mediatek/mt76/mt7603/mac.c
Normal file
File diff suppressed because it is too large
Load Diff
242
drivers/net/wireless/mediatek/mt76/mt7603/mac.h
Normal file
242
drivers/net/wireless/mediatek/mt76/mt7603/mac.h
Normal file
@@ -0,0 +1,242 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
|
||||
#ifndef __MT7603_MAC_H
|
||||
#define __MT7603_MAC_H
|
||||
|
||||
#define MT_RXD0_LENGTH GENMASK(15, 0)
|
||||
#define MT_RXD0_PKT_TYPE GENMASK(31, 29)
|
||||
|
||||
#define MT_RXD0_NORMAL_ETH_TYPE_OFS GENMASK(22, 16)
|
||||
#define MT_RXD0_NORMAL_IP_SUM BIT(23)
|
||||
#define MT_RXD0_NORMAL_UDP_TCP_SUM BIT(24)
|
||||
#define MT_RXD0_NORMAL_GROUP_1 BIT(25)
|
||||
#define MT_RXD0_NORMAL_GROUP_2 BIT(26)
|
||||
#define MT_RXD0_NORMAL_GROUP_3 BIT(27)
|
||||
#define MT_RXD0_NORMAL_GROUP_4 BIT(28)
|
||||
|
||||
enum rx_pkt_type {
|
||||
PKT_TYPE_TXS = 0,
|
||||
PKT_TYPE_TXRXV = 1,
|
||||
PKT_TYPE_NORMAL = 2,
|
||||
PKT_TYPE_RX_DUP_RFB = 3,
|
||||
PKT_TYPE_RX_TMR = 4,
|
||||
PKT_TYPE_RETRIEVE = 5,
|
||||
PKT_TYPE_RX_EVENT = 7,
|
||||
};
|
||||
|
||||
#define MT_RXD1_NORMAL_BSSID GENMASK(31, 26)
|
||||
#define MT_RXD1_NORMAL_PAYLOAD_FORMAT GENMASK(25, 24)
|
||||
#define MT_RXD1_NORMAL_HDR_TRANS BIT(23)
|
||||
#define MT_RXD1_NORMAL_HDR_OFFSET BIT(22)
|
||||
#define MT_RXD1_NORMAL_MAC_HDR_LEN GENMASK(21, 16)
|
||||
#define MT_RXD1_NORMAL_CH_FREQ GENMASK(15, 8)
|
||||
#define MT_RXD1_NORMAL_KEY_ID GENMASK(7, 6)
|
||||
#define MT_RXD1_NORMAL_BEACON_UC BIT(5)
|
||||
#define MT_RXD1_NORMAL_BEACON_MC BIT(4)
|
||||
#define MT_RXD1_NORMAL_BCAST BIT(3)
|
||||
#define MT_RXD1_NORMAL_MCAST BIT(2)
|
||||
#define MT_RXD1_NORMAL_U2M BIT(1)
|
||||
#define MT_RXD1_NORMAL_HTC_VLD BIT(0)
|
||||
|
||||
#define MT_RXD2_NORMAL_NON_AMPDU BIT(31)
|
||||
#define MT_RXD2_NORMAL_NON_AMPDU_SUB BIT(30)
|
||||
#define MT_RXD2_NORMAL_NDATA BIT(29)
|
||||
#define MT_RXD2_NORMAL_NULL_FRAME BIT(28)
|
||||
#define MT_RXD2_NORMAL_FRAG BIT(27)
|
||||
#define MT_RXD2_NORMAL_UDF_VALID BIT(26)
|
||||
#define MT_RXD2_NORMAL_LLC_MIS BIT(25)
|
||||
#define MT_RXD2_NORMAL_MAX_LEN_ERROR BIT(24)
|
||||
#define MT_RXD2_NORMAL_AMSDU_ERR BIT(23)
|
||||
#define MT_RXD2_NORMAL_LEN_MISMATCH BIT(22)
|
||||
#define MT_RXD2_NORMAL_TKIP_MIC_ERR BIT(21)
|
||||
#define MT_RXD2_NORMAL_ICV_ERR BIT(20)
|
||||
#define MT_RXD2_NORMAL_CLM BIT(19)
|
||||
#define MT_RXD2_NORMAL_CM BIT(18)
|
||||
#define MT_RXD2_NORMAL_FCS_ERR BIT(17)
|
||||
#define MT_RXD2_NORMAL_SW_BIT BIT(16)
|
||||
#define MT_RXD2_NORMAL_SEC_MODE GENMASK(15, 12)
|
||||
#define MT_RXD2_NORMAL_TID GENMASK(11, 8)
|
||||
#define MT_RXD2_NORMAL_WLAN_IDX GENMASK(7, 0)
|
||||
|
||||
#define MT_RXD3_NORMAL_PF_STS GENMASK(31, 30)
|
||||
#define MT_RXD3_NORMAL_PF_MODE BIT(29)
|
||||
#define MT_RXD3_NORMAL_CLS_BITMAP GENMASK(28, 19)
|
||||
#define MT_RXD3_NORMAL_WOL GENMASK(18, 14)
|
||||
#define MT_RXD3_NORMAL_MAGIC_PKT BIT(13)
|
||||
#define MT_RXD3_NORMAL_OFLD GENMASK(12, 11)
|
||||
#define MT_RXD3_NORMAL_CLS BIT(10)
|
||||
#define MT_RXD3_NORMAL_PATTERN_DROP BIT(9)
|
||||
#define MT_RXD3_NORMAL_TSF_COMPARE_LOSS BIT(8)
|
||||
#define MT_RXD3_NORMAL_RXV_SEQ GENMASK(7, 0)
|
||||
|
||||
#define MT_RXV1_VHTA1_B5_B4 GENMASK(31, 30)
|
||||
#define MT_RXV1_VHTA2_B8_B1 GENMASK(29, 22)
|
||||
#define MT_RXV1_HT_NO_SOUND BIT(21)
|
||||
#define MT_RXV1_HT_SMOOTH BIT(20)
|
||||
#define MT_RXV1_HT_SHORT_GI BIT(19)
|
||||
#define MT_RXV1_HT_AGGR BIT(18)
|
||||
#define MT_RXV1_VHTA1_B22 BIT(17)
|
||||
#define MT_RXV1_FRAME_MODE GENMASK(16, 15)
|
||||
#define MT_RXV1_TX_MODE GENMASK(14, 12)
|
||||
#define MT_RXV1_HT_EXT_LTF GENMASK(11, 10)
|
||||
#define MT_RXV1_HT_AD_CODE BIT(9)
|
||||
#define MT_RXV1_HT_STBC GENMASK(8, 7)
|
||||
#define MT_RXV1_TX_RATE GENMASK(6, 0)
|
||||
|
||||
#define MT_RXV2_VHTA1_B16_B6 GENMASK(31, 21)
|
||||
#define MT_RXV2_LENGTH GENMASK(20, 0)
|
||||
|
||||
#define MT_RXV3_F_AGC1_CAL_GAIN GENMASK(31, 29)
|
||||
#define MT_RXV3_F_AGC1_EQ_CAL BIT(28)
|
||||
#define MT_RXV3_RCPI1 GENMASK(27, 20)
|
||||
#define MT_RXV3_F_AGC0_CAL_GAIN GENMASK(19, 17)
|
||||
#define MT_RXV3_F_AGC0_EQ_CAL BIT(16)
|
||||
#define MT_RXV3_RCPI0 GENMASK(15, 8)
|
||||
#define MT_RXV3_SEL_ANT BIT(7)
|
||||
#define MT_RXV3_ACI_DET_X BIT(6)
|
||||
#define MT_RXV3_OFDM_FREQ_TRANS_DETECT BIT(5)
|
||||
#define MT_RXV3_VHTA1_B21_B17 GENMASK(4, 0)
|
||||
|
||||
#define MT_RXV4_F_AGC_CAL_GAIN GENMASK(31, 29)
|
||||
#define MT_RXV4_F_AGC2_EQ_CAL BIT(28)
|
||||
#define MT_RXV4_IB_RSSI1 GENMASK(27, 20)
|
||||
#define MT_RXV4_F_AGC_LPF_GAIN_X GENMASK(19, 16)
|
||||
#define MT_RXV4_WB_RSSI_X GENMASK(15, 8)
|
||||
#define MT_RXV4_IB_RSSI0 GENMASK(7, 0)
|
||||
|
||||
#define MT_RXV5_LTF_SNR0 GENMASK(31, 26)
|
||||
#define MT_RXV5_LTF_PROC_TIME GENMASK(25, 19)
|
||||
#define MT_RXV5_FOE GENMASK(18, 7)
|
||||
#define MT_RXV5_C_AGC_SATE GENMASK(6, 4)
|
||||
#define MT_RXV5_F_AGC_LNA_GAIN_0 GENMASK(3, 2)
|
||||
#define MT_RXV5_F_AGC_LNA_GAIN_1 GENMASK(1, 0)
|
||||
|
||||
#define MT_RXV6_C_AGC_STATE GENMASK(30, 28)
|
||||
#define MT_RXV6_NS_TS_FIELD GENMASK(27, 25)
|
||||
#define MT_RXV6_RX_VALID BIT(24)
|
||||
#define MT_RXV6_NF2 GENMASK(23, 16)
|
||||
#define MT_RXV6_NF1 GENMASK(15, 8)
|
||||
#define MT_RXV6_NF0 GENMASK(7, 0)
|
||||
|
||||
enum mt7603_tx_header_format {
|
||||
MT_HDR_FORMAT_802_3,
|
||||
MT_HDR_FORMAT_CMD,
|
||||
MT_HDR_FORMAT_802_11,
|
||||
MT_HDR_FORMAT_802_11_EXT,
|
||||
};
|
||||
|
||||
#define MT_TXD_SIZE (8 * 4)
|
||||
|
||||
#define MT_TXD0_P_IDX BIT(31)
|
||||
#define MT_TXD0_Q_IDX GENMASK(30, 27)
|
||||
#define MT_TXD0_UTXB BIT(26)
|
||||
#define MT_TXD0_UNXV BIT(25)
|
||||
#define MT_TXD0_UDP_TCP_SUM BIT(24)
|
||||
#define MT_TXD0_IP_SUM BIT(23)
|
||||
#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16)
|
||||
#define MT_TXD0_TX_BYTES GENMASK(15, 0)
|
||||
|
||||
#define MT_TXD1_OWN_MAC GENMASK(31, 26)
|
||||
#define MT_TXD1_PROTECTED BIT(23)
|
||||
#define MT_TXD1_TID GENMASK(22, 20)
|
||||
#define MT_TXD1_NO_ACK BIT(19)
|
||||
#define MT_TXD1_HDR_PAD GENMASK(18, 16)
|
||||
#define MT_TXD1_LONG_FORMAT BIT(15)
|
||||
#define MT_TXD1_HDR_FORMAT GENMASK(14, 13)
|
||||
#define MT_TXD1_HDR_INFO GENMASK(12, 8)
|
||||
#define MT_TXD1_WLAN_IDX GENMASK(7, 0)
|
||||
|
||||
#define MT_TXD2_FIX_RATE BIT(31)
|
||||
#define MT_TXD2_TIMING_MEASURE BIT(30)
|
||||
#define MT_TXD2_BA_DISABLE BIT(29)
|
||||
#define MT_TXD2_POWER_OFFSET GENMASK(28, 24)
|
||||
#define MT_TXD2_MAX_TX_TIME GENMASK(23, 16)
|
||||
#define MT_TXD2_FRAG GENMASK(15, 14)
|
||||
#define MT_TXD2_HTC_VLD BIT(13)
|
||||
#define MT_TXD2_DURATION BIT(12)
|
||||
#define MT_TXD2_BIP BIT(11)
|
||||
#define MT_TXD2_MULTICAST BIT(10)
|
||||
#define MT_TXD2_RTS BIT(9)
|
||||
#define MT_TXD2_SOUNDING BIT(8)
|
||||
#define MT_TXD2_NDPA BIT(7)
|
||||
#define MT_TXD2_NDP BIT(6)
|
||||
#define MT_TXD2_FRAME_TYPE GENMASK(5, 4)
|
||||
#define MT_TXD2_SUB_TYPE GENMASK(3, 0)
|
||||
|
||||
#define MT_TXD3_SN_VALID BIT(31)
|
||||
#define MT_TXD3_PN_VALID BIT(30)
|
||||
#define MT_TXD3_SEQ GENMASK(27, 16)
|
||||
#define MT_TXD3_REM_TX_COUNT GENMASK(15, 11)
|
||||
#define MT_TXD3_TX_COUNT GENMASK(10, 6)
|
||||
|
||||
#define MT_TXD4_PN_LOW GENMASK(31, 0)
|
||||
|
||||
#define MT_TXD5_PN_HIGH GENMASK(31, 16)
|
||||
#define MT_TXD5_SW_POWER_MGMT BIT(13)
|
||||
#define MT_TXD5_BA_SEQ_CTRL BIT(12)
|
||||
#define MT_TXD5_DA_SELECT BIT(11)
|
||||
#define MT_TXD5_TX_STATUS_HOST BIT(10)
|
||||
#define MT_TXD5_TX_STATUS_MCU BIT(9)
|
||||
#define MT_TXD5_TX_STATUS_FMT BIT(8)
|
||||
#define MT_TXD5_PID GENMASK(7, 0)
|
||||
|
||||
#define MT_TXD6_SGI BIT(31)
|
||||
#define MT_TXD6_LDPC BIT(30)
|
||||
#define MT_TXD6_TX_RATE GENMASK(29, 18)
|
||||
#define MT_TXD6_I_TXBF BIT(17)
|
||||
#define MT_TXD6_E_TXBF BIT(16)
|
||||
#define MT_TXD6_DYN_BW BIT(15)
|
||||
#define MT_TXD6_ANT_PRI GENMASK(14, 12)
|
||||
#define MT_TXD6_SPE_EN BIT(11)
|
||||
#define MT_TXD6_FIXED_BW BIT(10)
|
||||
#define MT_TXD6_BW GENMASK(9, 8)
|
||||
#define MT_TXD6_ANT_ID GENMASK(7, 2)
|
||||
#define MT_TXD6_FIXED_RATE BIT(0)
|
||||
|
||||
#define MT_TX_RATE_STBC BIT(11)
|
||||
#define MT_TX_RATE_NSS GENMASK(10, 9)
|
||||
#define MT_TX_RATE_MODE GENMASK(8, 6)
|
||||
#define MT_TX_RATE_IDX GENMASK(5, 0)
|
||||
|
||||
#define MT_TXS0_ANTENNA GENMASK(31, 26)
|
||||
#define MT_TXS0_TID GENMASK(25, 22)
|
||||
#define MT_TXS0_BA_ERROR BIT(22)
|
||||
#define MT_TXS0_PS_FLAG BIT(21)
|
||||
#define MT_TXS0_TXOP_TIMEOUT BIT(20)
|
||||
#define MT_TXS0_BIP_ERROR BIT(19)
|
||||
|
||||
#define MT_TXS0_QUEUE_TIMEOUT BIT(18)
|
||||
#define MT_TXS0_RTS_TIMEOUT BIT(17)
|
||||
#define MT_TXS0_ACK_TIMEOUT BIT(16)
|
||||
#define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16)
|
||||
|
||||
#define MT_TXS0_TX_STATUS_HOST BIT(15)
|
||||
#define MT_TXS0_TX_STATUS_MCU BIT(14)
|
||||
#define MT_TXS0_TXS_FORMAT BIT(13)
|
||||
#define MT_TXS0_FIXED_RATE BIT(12)
|
||||
#define MT_TXS0_TX_RATE GENMASK(11, 0)
|
||||
|
||||
#define MT_TXS1_F0_TIMESTAMP GENMASK(31, 0)
|
||||
#define MT_TXS1_F1_NOISE_2 GENMASK(23, 16)
|
||||
#define MT_TXS1_F1_NOISE_1 GENMASK(15, 8)
|
||||
#define MT_TXS1_F1_NOISE_0 GENMASK(7, 0)
|
||||
|
||||
#define MT_TXS2_F0_FRONT_TIME GENMASK(24, 0)
|
||||
#define MT_TXS2_F1_RCPI_2 GENMASK(23, 16)
|
||||
#define MT_TXS2_F1_RCPI_1 GENMASK(15, 8)
|
||||
#define MT_TXS2_F1_RCPI_0 GENMASK(7, 0)
|
||||
|
||||
#define MT_TXS3_WCID GENMASK(31, 24)
|
||||
#define MT_TXS3_RXV_SEQNO GENMASK(23, 16)
|
||||
#define MT_TXS3_TX_DELAY GENMASK(15, 0)
|
||||
|
||||
#define MT_TXS4_LAST_TX_RATE GENMASK(31, 29)
|
||||
#define MT_TXS4_TX_COUNT GENMASK(28, 24)
|
||||
#define MT_TXS4_AMPDU BIT(23)
|
||||
#define MT_TXS4_ACKED_MPDU BIT(22)
|
||||
#define MT_TXS4_PID GENMASK(21, 14)
|
||||
#define MT_TXS4_BW GENMASK(13, 12)
|
||||
#define MT_TXS4_F0_SEQNO GENMASK(11, 0)
|
||||
#define MT_TXS4_F1_TSSI GENMASK(11, 0)
|
||||
|
||||
#endif
|
||||
709
drivers/net/wireless/mediatek/mt76/mt7603/main.c
Normal file
709
drivers/net/wireless/mediatek/mt76/mt7603/main.c
Normal file
File diff suppressed because it is too large
Load Diff
483
drivers/net/wireless/mediatek/mt76/mt7603/mcu.c
Normal file
483
drivers/net/wireless/mediatek/mt76/mt7603/mcu.c
Normal file
@@ -0,0 +1,483 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
|
||||
#include <linux/firmware.h>
|
||||
#include "mt7603.h"
|
||||
#include "mcu.h"
|
||||
#include "eeprom.h"
|
||||
|
||||
#define MCU_SKB_RESERVE 8
|
||||
|
||||
struct mt7603_fw_trailer {
|
||||
char fw_ver[10];
|
||||
char build_date[15];
|
||||
__le32 dl_len;
|
||||
} __packed;
|
||||
|
||||
static int
|
||||
__mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb, int cmd,
|
||||
int query, int *wait_seq)
|
||||
{
|
||||
int hdrlen = dev->mcu_running ? sizeof(struct mt7603_mcu_txd) : 12;
|
||||
struct mt76_dev *mdev = &dev->mt76;
|
||||
struct mt7603_mcu_txd *txd;
|
||||
u8 seq;
|
||||
|
||||
if (!skb)
|
||||
return -EINVAL;
|
||||
|
||||
seq = ++mdev->mmio.mcu.msg_seq & 0xf;
|
||||
if (!seq)
|
||||
seq = ++mdev->mmio.mcu.msg_seq & 0xf;
|
||||
|
||||
txd = (struct mt7603_mcu_txd *)skb_push(skb, hdrlen);
|
||||
memset(txd, 0, hdrlen);
|
||||
|
||||
txd->len = cpu_to_le16(skb->len);
|
||||
if (cmd == -MCU_CMD_FW_SCATTER)
|
||||
txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE_FW);
|
||||
else
|
||||
txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE);
|
||||
txd->pkt_type = MCU_PKT_ID;
|
||||
txd->seq = seq;
|
||||
|
||||
if (cmd < 0) {
|
||||
txd->cid = -cmd;
|
||||
} else {
|
||||
txd->cid = MCU_CMD_EXT_CID;
|
||||
txd->ext_cid = cmd;
|
||||
if (query != MCU_Q_NA)
|
||||
txd->ext_cid_ack = 1;
|
||||
}
|
||||
|
||||
txd->set_query = query;
|
||||
|
||||
if (wait_seq)
|
||||
*wait_seq = seq;
|
||||
|
||||
return mt76_tx_queue_skb_raw(dev, MT_TXQ_MCU, skb, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb, int cmd,
|
||||
int query)
|
||||
{
|
||||
struct mt76_dev *mdev = &dev->mt76;
|
||||
unsigned long expires = jiffies + 3 * HZ;
|
||||
struct mt7603_mcu_rxd *rxd;
|
||||
int ret, seq;
|
||||
|
||||
mutex_lock(&mdev->mmio.mcu.mutex);
|
||||
|
||||
ret = __mt7603_mcu_msg_send(dev, skb, cmd, query, &seq);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
while (1) {
|
||||
bool check_seq = false;
|
||||
|
||||
skb = mt76_mcu_get_response(&dev->mt76, expires);
|
||||
if (!skb) {
|
||||
dev_err(mdev->dev,
|
||||
"MCU message %d (seq %d) timed out\n",
|
||||
cmd, seq);
|
||||
dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT;
|
||||
ret = -ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
rxd = (struct mt7603_mcu_rxd *)skb->data;
|
||||
if (seq == rxd->seq)
|
||||
check_seq = true;
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
if (check_seq)
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&mdev->mmio.mcu.mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len)
|
||||
{
|
||||
struct {
|
||||
__le32 addr;
|
||||
__le32 len;
|
||||
__le32 mode;
|
||||
} req = {
|
||||
.addr = cpu_to_le32(addr),
|
||||
.len = cpu_to_le32(len),
|
||||
.mode = cpu_to_le32(BIT(31)),
|
||||
};
|
||||
struct sk_buff *skb = mt7603_mcu_msg_alloc(&req, sizeof(req));
|
||||
|
||||
return mt7603_mcu_msg_send(dev, skb, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
|
||||
MCU_Q_NA);
|
||||
}
|
||||
|
||||
static int
|
||||
mt7603_mcu_send_firmware(struct mt7603_dev *dev, const void *data, int len)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int ret = 0;
|
||||
|
||||
while (len > 0) {
|
||||
int cur_len = min_t(int, 4096 - sizeof(struct mt7603_mcu_txd),
|
||||
len);
|
||||
|
||||
skb = mt7603_mcu_msg_alloc(data, cur_len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = __mt7603_mcu_msg_send(dev, skb, -MCU_CMD_FW_SCATTER,
|
||||
MCU_Q_NA, NULL);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
data += cur_len;
|
||||
len -= cur_len;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr)
|
||||
{
|
||||
struct {
|
||||
__le32 override;
|
||||
__le32 addr;
|
||||
} req = {
|
||||
.override = cpu_to_le32(addr ? 1 : 0),
|
||||
.addr = cpu_to_le32(addr),
|
||||
};
|
||||
struct sk_buff *skb = mt7603_mcu_msg_alloc(&req, sizeof(req));
|
||||
|
||||
return mt7603_mcu_msg_send(dev, skb, -MCU_CMD_FW_START_REQ,
|
||||
MCU_Q_NA);
|
||||
}
|
||||
|
||||
static int
|
||||
mt7603_mcu_restart(struct mt7603_dev *dev)
|
||||
{
|
||||
struct sk_buff *skb = mt7603_mcu_msg_alloc(NULL, 0);
|
||||
|
||||
return mt7603_mcu_msg_send(dev, skb, -MCU_CMD_RESTART_DL_REQ,
|
||||
MCU_Q_NA);
|
||||
}
|
||||
|
||||
static int
|
||||
mt7603_load_firmware(struct mt7603_dev *dev)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
const struct mt7603_fw_trailer *hdr;
|
||||
const char *firmware;
|
||||
int dl_len;
|
||||
u32 addr, val;
|
||||
int ret;
|
||||
|
||||
if (is_mt7628(dev)) {
|
||||
if (mt76xx_rev(dev) == MT7628_REV_E1)
|
||||
firmware = MT7628_FIRMWARE_E1;
|
||||
else
|
||||
firmware = MT7628_FIRMWARE_E2;
|
||||
} else {
|
||||
if (mt76xx_rev(dev) < MT7603_REV_E2)
|
||||
firmware = MT7603_FIRMWARE_E1;
|
||||
else
|
||||
firmware = MT7603_FIRMWARE_E2;
|
||||
}
|
||||
|
||||
ret = request_firmware(&fw, firmware, dev->mt76.dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
|
||||
dev_err(dev->mt76.dev, "Invalid firmware\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hdr = (const struct mt7603_fw_trailer *)(fw->data + fw->size -
|
||||
sizeof(*hdr));
|
||||
|
||||
dev_info(dev->mt76.dev, "Firmware Version: %.10s\n", hdr->fw_ver);
|
||||
dev_info(dev->mt76.dev, "Build Time: %.15s\n", hdr->build_date);
|
||||
|
||||
addr = mt7603_reg_map(dev, 0x50012498);
|
||||
mt76_wr(dev, addr, 0x5);
|
||||
mt76_wr(dev, addr, 0x5);
|
||||
udelay(1);
|
||||
|
||||
/* switch to bypass mode */
|
||||
mt76_rmw(dev, MT_SCH_4, MT_SCH_4_FORCE_QID,
|
||||
MT_SCH_4_BYPASS | FIELD_PREP(MT_SCH_4_FORCE_QID, 5));
|
||||
|
||||
val = mt76_rr(dev, MT_TOP_MISC2);
|
||||
if (val & BIT(1)) {
|
||||
dev_info(dev->mt76.dev, "Firmware already running...\n");
|
||||
goto running;
|
||||
}
|
||||
|
||||
if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(0) | BIT(1), BIT(0), 500)) {
|
||||
dev_err(dev->mt76.dev, "Timeout waiting for ROM code to become ready\n");
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dl_len = le32_to_cpu(hdr->dl_len) + 4;
|
||||
ret = mt7603_mcu_init_download(dev, MCU_FIRMWARE_ADDRESS, dl_len);
|
||||
if (ret) {
|
||||
dev_err(dev->mt76.dev, "Download request failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = mt7603_mcu_send_firmware(dev, fw->data, dl_len);
|
||||
if (ret) {
|
||||
dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = mt7603_mcu_start_firmware(dev, MCU_FIRMWARE_ADDRESS);
|
||||
if (ret) {
|
||||
dev_err(dev->mt76.dev, "Failed to start firmware\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(1), BIT(1), 500)) {
|
||||
dev_err(dev->mt76.dev, "Timeout waiting for firmware to initialize\n");
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
running:
|
||||
mt76_clear(dev, MT_SCH_4, MT_SCH_4_FORCE_QID | MT_SCH_4_BYPASS);
|
||||
|
||||
mt76_set(dev, MT_SCH_4, BIT(8));
|
||||
mt76_clear(dev, MT_SCH_4, BIT(8));
|
||||
|
||||
dev->mcu_running = true;
|
||||
dev_info(dev->mt76.dev, "firmware init done\n");
|
||||
|
||||
out:
|
||||
release_firmware(fw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mt7603_mcu_init(struct mt7603_dev *dev)
|
||||
{
|
||||
mutex_init(&dev->mt76.mmio.mcu.mutex);
|
||||
|
||||
return mt7603_load_firmware(dev);
|
||||
}
|
||||
|
||||
void mt7603_mcu_exit(struct mt7603_dev *dev)
|
||||
{
|
||||
mt7603_mcu_restart(dev);
|
||||
skb_queue_purge(&dev->mt76.mmio.mcu.res_q);
|
||||
}
|
||||
|
||||
int mt7603_mcu_set_eeprom(struct mt7603_dev *dev)
|
||||
{
|
||||
static const u16 req_fields[] = {
|
||||
#define WORD(_start) \
|
||||
_start, \
|
||||
_start + 1
|
||||
#define GROUP_2G(_start) \
|
||||
WORD(_start), \
|
||||
WORD(_start + 2), \
|
||||
WORD(_start + 4)
|
||||
|
||||
MT_EE_NIC_CONF_0 + 1,
|
||||
WORD(MT_EE_NIC_CONF_1),
|
||||
MT_EE_WIFI_RF_SETTING,
|
||||
MT_EE_TX_POWER_DELTA_BW40,
|
||||
MT_EE_TX_POWER_DELTA_BW80 + 1,
|
||||
MT_EE_TX_POWER_EXT_PA_5G,
|
||||
MT_EE_TEMP_SENSOR_CAL,
|
||||
GROUP_2G(MT_EE_TX_POWER_0_START_2G),
|
||||
GROUP_2G(MT_EE_TX_POWER_1_START_2G),
|
||||
WORD(MT_EE_TX_POWER_CCK),
|
||||
WORD(MT_EE_TX_POWER_OFDM_2G_6M),
|
||||
WORD(MT_EE_TX_POWER_OFDM_2G_24M),
|
||||
WORD(MT_EE_TX_POWER_OFDM_2G_54M),
|
||||
WORD(MT_EE_TX_POWER_HT_BPSK_QPSK),
|
||||
WORD(MT_EE_TX_POWER_HT_16_64_QAM),
|
||||
WORD(MT_EE_TX_POWER_HT_64_QAM),
|
||||
MT_EE_ELAN_RX_MODE_GAIN,
|
||||
MT_EE_ELAN_RX_MODE_NF,
|
||||
MT_EE_ELAN_RX_MODE_P1DB,
|
||||
MT_EE_ELAN_BYPASS_MODE_GAIN,
|
||||
MT_EE_ELAN_BYPASS_MODE_NF,
|
||||
MT_EE_ELAN_BYPASS_MODE_P1DB,
|
||||
WORD(MT_EE_STEP_NUM_NEG_6_7),
|
||||
WORD(MT_EE_STEP_NUM_NEG_4_5),
|
||||
WORD(MT_EE_STEP_NUM_NEG_2_3),
|
||||
WORD(MT_EE_STEP_NUM_NEG_0_1),
|
||||
WORD(MT_EE_REF_STEP_24G),
|
||||
WORD(MT_EE_STEP_NUM_PLUS_1_2),
|
||||
WORD(MT_EE_STEP_NUM_PLUS_3_4),
|
||||
WORD(MT_EE_STEP_NUM_PLUS_5_6),
|
||||
MT_EE_STEP_NUM_PLUS_7,
|
||||
MT_EE_XTAL_FREQ_OFFSET,
|
||||
MT_EE_XTAL_TRIM_2_COMP,
|
||||
MT_EE_XTAL_TRIM_3_COMP,
|
||||
MT_EE_XTAL_WF_RFCAL,
|
||||
|
||||
/* unknown fields below */
|
||||
WORD(0x24),
|
||||
0x34,
|
||||
0x39,
|
||||
0x3b,
|
||||
WORD(0x42),
|
||||
WORD(0x9e),
|
||||
0xf2,
|
||||
WORD(0xf8),
|
||||
0xfa,
|
||||
0x12e,
|
||||
WORD(0x130), WORD(0x132), WORD(0x134), WORD(0x136),
|
||||
WORD(0x138), WORD(0x13a), WORD(0x13c), WORD(0x13e),
|
||||
|
||||
#undef GROUP_2G
|
||||
#undef WORD
|
||||
|
||||
};
|
||||
struct req_data {
|
||||
u16 addr;
|
||||
u8 val;
|
||||
u8 pad;
|
||||
} __packed;
|
||||
struct {
|
||||
u8 buffer_mode;
|
||||
u8 len;
|
||||
u8 pad[2];
|
||||
} req_hdr = {
|
||||
.buffer_mode = 1,
|
||||
.len = ARRAY_SIZE(req_fields) - 1,
|
||||
};
|
||||
struct sk_buff *skb;
|
||||
struct req_data *data;
|
||||
const int size = 0xff * sizeof(struct req_data);
|
||||
u8 *eep = (u8 *)dev->mt76.eeprom.data;
|
||||
int i;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(req_fields) * sizeof(*data) > size);
|
||||
|
||||
skb = mt7603_mcu_msg_alloc(NULL, size + sizeof(req_hdr));
|
||||
memcpy(skb_put(skb, sizeof(req_hdr)), &req_hdr, sizeof(req_hdr));
|
||||
data = (struct req_data *)skb_put(skb, size);
|
||||
memset(data, 0, size);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(req_fields); i++) {
|
||||
data[i].addr = cpu_to_le16(req_fields[i]);
|
||||
data[i].val = eep[req_fields[i]];
|
||||
data[i].pad = 0;
|
||||
}
|
||||
|
||||
return mt7603_mcu_msg_send(dev, skb, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
|
||||
MCU_Q_SET);
|
||||
}
|
||||
|
||||
static int mt7603_mcu_set_tx_power(struct mt7603_dev *dev)
|
||||
{
|
||||
struct {
|
||||
u8 center_channel;
|
||||
u8 tssi;
|
||||
u8 temp_comp;
|
||||
u8 target_power[2];
|
||||
u8 rate_power_delta[14];
|
||||
u8 bw_power_delta;
|
||||
u8 ch_power_delta[6];
|
||||
u8 temp_comp_power[17];
|
||||
u8 reserved;
|
||||
} req = {
|
||||
.center_channel = dev->mt76.chandef.chan->hw_value,
|
||||
#define EEP_VAL(n) ((u8 *)dev->mt76.eeprom.data)[n]
|
||||
.tssi = EEP_VAL(MT_EE_NIC_CONF_1 + 1),
|
||||
.temp_comp = EEP_VAL(MT_EE_NIC_CONF_1),
|
||||
.target_power = {
|
||||
EEP_VAL(MT_EE_TX_POWER_0_START_2G + 2),
|
||||
EEP_VAL(MT_EE_TX_POWER_1_START_2G + 2)
|
||||
},
|
||||
.bw_power_delta = EEP_VAL(MT_EE_TX_POWER_DELTA_BW40),
|
||||
.ch_power_delta = {
|
||||
EEP_VAL(MT_EE_TX_POWER_0_START_2G + 3),
|
||||
EEP_VAL(MT_EE_TX_POWER_0_START_2G + 4),
|
||||
EEP_VAL(MT_EE_TX_POWER_0_START_2G + 5),
|
||||
EEP_VAL(MT_EE_TX_POWER_1_START_2G + 3),
|
||||
EEP_VAL(MT_EE_TX_POWER_1_START_2G + 4),
|
||||
EEP_VAL(MT_EE_TX_POWER_1_START_2G + 5)
|
||||
},
|
||||
#undef EEP_VAL
|
||||
};
|
||||
struct sk_buff *skb;
|
||||
u8 *eep = (u8 *)dev->mt76.eeprom.data;
|
||||
|
||||
memcpy(req.rate_power_delta, eep + MT_EE_TX_POWER_CCK,
|
||||
sizeof(req.rate_power_delta));
|
||||
|
||||
memcpy(req.temp_comp_power, eep + MT_EE_STEP_NUM_NEG_6_7,
|
||||
sizeof(req.temp_comp_power));
|
||||
|
||||
skb = mt7603_mcu_msg_alloc(&req, sizeof(req));
|
||||
return mt7603_mcu_msg_send(dev, skb, MCU_EXT_CMD_SET_TX_POWER_CTRL,
|
||||
MCU_Q_SET);
|
||||
}
|
||||
|
||||
int mt7603_mcu_set_channel(struct mt7603_dev *dev)
|
||||
{
|
||||
struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
|
||||
struct ieee80211_hw *hw = mt76_hw(dev);
|
||||
int n_chains = __sw_hweight8(dev->mt76.antenna_mask);
|
||||
struct {
|
||||
u8 control_chan;
|
||||
u8 center_chan;
|
||||
u8 bw;
|
||||
u8 tx_streams;
|
||||
u8 rx_streams;
|
||||
u8 _res0[7];
|
||||
u8 txpower[21];
|
||||
u8 _res1[3];
|
||||
} req = {
|
||||
.control_chan = chandef->chan->hw_value,
|
||||
.center_chan = chandef->chan->hw_value,
|
||||
.bw = MT_BW_20,
|
||||
.tx_streams = n_chains,
|
||||
.rx_streams = n_chains,
|
||||
};
|
||||
struct sk_buff *skb;
|
||||
s8 tx_power;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_40) {
|
||||
req.bw = MT_BW_40;
|
||||
if (chandef->center_freq1 > chandef->chan->center_freq)
|
||||
req.center_chan += 2;
|
||||
else
|
||||
req.center_chan -= 2;
|
||||
}
|
||||
|
||||
tx_power = hw->conf.power_level * 2;
|
||||
if (dev->mt76.antenna_mask == 3)
|
||||
tx_power -= 6;
|
||||
tx_power = min(tx_power, dev->tx_power_limit);
|
||||
|
||||
dev->mt76.txpower_cur = tx_power;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(req.txpower); i++)
|
||||
req.txpower[i] = tx_power;
|
||||
|
||||
skb = mt7603_mcu_msg_alloc(&req, sizeof(req));
|
||||
ret = mt7603_mcu_msg_send(dev, skb, MCU_EXT_CMD_CHANNEL_SWITCH,
|
||||
MCU_Q_SET);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return mt7603_mcu_set_tx_power(dev);
|
||||
}
|
||||
110
drivers/net/wireless/mediatek/mt76/mt7603/mcu.h
Normal file
110
drivers/net/wireless/mediatek/mt76/mt7603/mcu.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
|
||||
#ifndef __MT7603_MCU_H
|
||||
#define __MT7603_MCU_H
|
||||
|
||||
struct mt7603_mcu_txd {
|
||||
__le16 len;
|
||||
__le16 pq_id;
|
||||
|
||||
u8 cid;
|
||||
u8 pkt_type;
|
||||
u8 set_query;
|
||||
u8 seq;
|
||||
|
||||
u8 uc_d2b0_rev;
|
||||
u8 ext_cid;
|
||||
u8 uc_d2b2_rev;
|
||||
u8 ext_cid_ack;
|
||||
|
||||
u32 au4_d3_to_d7_rev[5];
|
||||
} __packed __aligned(4);
|
||||
|
||||
struct mt7603_mcu_rxd {
|
||||
__le16 len;
|
||||
__le16 pkt_type_id;
|
||||
|
||||
u8 eid;
|
||||
u8 seq;
|
||||
__le16 __rsv;
|
||||
|
||||
u8 ext_eid;
|
||||
u8 __rsv1[3];
|
||||
};
|
||||
|
||||
#define MCU_PKT_ID 0xa0
|
||||
#define MCU_PORT_QUEUE 0x8000
|
||||
#define MCU_PORT_QUEUE_FW 0xc000
|
||||
|
||||
#define MCU_FIRMWARE_ADDRESS 0x100000
|
||||
|
||||
enum {
|
||||
MCU_Q_QUERY,
|
||||
MCU_Q_SET,
|
||||
MCU_Q_RESERVED,
|
||||
MCU_Q_NA
|
||||
};
|
||||
|
||||
enum {
|
||||
MCU_CMD_TARGET_ADDRESS_LEN_REQ = 0x01,
|
||||
MCU_CMD_FW_START_REQ = 0x02,
|
||||
MCU_CMD_INIT_ACCESS_REG = 0x3,
|
||||
MCU_CMD_PATCH_START_REQ = 0x05,
|
||||
MCU_CMD_PATCH_FINISH_REQ = 0x07,
|
||||
MCU_CMD_PATCH_SEM_CONTROL = 0x10,
|
||||
MCU_CMD_HIF_LOOPBACK = 0x20,
|
||||
MCU_CMD_CH_PRIVILEGE = 0x20,
|
||||
MCU_CMD_ACCESS_REG = 0xC2,
|
||||
MCU_CMD_EXT_CID = 0xED,
|
||||
MCU_CMD_FW_SCATTER = 0xEE,
|
||||
MCU_CMD_RESTART_DL_REQ = 0xEF,
|
||||
};
|
||||
|
||||
enum {
|
||||
MCU_EXT_CMD_RF_REG_ACCESS = 0x02,
|
||||
MCU_EXT_CMD_RF_TEST = 0x04,
|
||||
MCU_EXT_CMD_RADIO_ON_OFF_CTRL = 0x05,
|
||||
MCU_EXT_CMD_WIFI_RX_DISABLE = 0x06,
|
||||
MCU_EXT_CMD_PM_STATE_CTRL = 0x07,
|
||||
MCU_EXT_CMD_CHANNEL_SWITCH = 0x08,
|
||||
MCU_EXT_CMD_NIC_CAPABILITY = 0x09,
|
||||
MCU_EXT_CMD_PWR_SAVING = 0x0A,
|
||||
MCU_EXT_CMD_MULTIPLE_REG_ACCESS = 0x0E,
|
||||
MCU_EXT_CMD_AP_PWR_SAVING_CAPABILITY = 0xF,
|
||||
MCU_EXT_CMD_SEC_ADDREMOVE_KEY = 0x10,
|
||||
MCU_EXT_CMD_SET_TX_POWER_CTRL = 0x11,
|
||||
MCU_EXT_CMD_FW_LOG_2_HOST = 0x13,
|
||||
MCU_EXT_CMD_PS_RETRIEVE_START = 0x14,
|
||||
MCU_EXT_CMD_LED_CTRL = 0x17,
|
||||
MCU_EXT_CMD_PACKET_FILTER = 0x18,
|
||||
MCU_EXT_CMD_PWR_MGT_BIT_WIFI = 0x1B,
|
||||
MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21,
|
||||
MCU_EXT_CMD_THERMAL_PROTECT = 0x23,
|
||||
MCU_EXT_CMD_EDCA_SET = 0x27,
|
||||
MCU_EXT_CMD_SLOT_TIME_SET = 0x28,
|
||||
MCU_EXT_CMD_CONFIG_INTERNAL_SETTING = 0x29,
|
||||
MCU_EXT_CMD_NOA_OFFLOAD_CTRL = 0x2B,
|
||||
MCU_EXT_CMD_GET_THEMAL_SENSOR = 0x2C,
|
||||
MCU_EXT_CMD_WAKEUP_OPTION = 0x2E,
|
||||
MCU_EXT_CMD_AC_QUEUE_CONTROL = 0x31,
|
||||
MCU_EXT_CMD_BCN_UPDATE = 0x33
|
||||
};
|
||||
|
||||
enum {
|
||||
MCU_EXT_EVENT_CMD_RESULT = 0x0,
|
||||
MCU_EXT_EVENT_RF_REG_ACCESS = 0x2,
|
||||
MCU_EXT_EVENT_MULTI_CR_ACCESS = 0x0E,
|
||||
MCU_EXT_EVENT_FW_LOG_2_HOST = 0x13,
|
||||
MCU_EXT_EVENT_BEACON_LOSS = 0x1A,
|
||||
MCU_EXT_EVENT_THERMAL_PROTECT = 0x22,
|
||||
MCU_EXT_EVENT_BCN_UPDATE = 0x31,
|
||||
};
|
||||
|
||||
static inline struct sk_buff *
|
||||
mt7603_mcu_msg_alloc(const void *data, int len)
|
||||
{
|
||||
return mt76_mcu_msg_alloc(data, sizeof(struct mt7603_mcu_txd),
|
||||
len, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
253
drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
Normal file
253
drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
Normal file
@@ -0,0 +1,253 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
|
||||
#ifndef __MT7603_H
|
||||
#define __MT7603_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ktime.h>
|
||||
#include "../mt76.h"
|
||||
#include "regs.h"
|
||||
|
||||
#define MT7603_MAX_INTERFACES 4
|
||||
#define MT7603_WTBL_SIZE 128
|
||||
#define MT7603_WTBL_RESERVED (MT7603_WTBL_SIZE - 1)
|
||||
#define MT7603_WTBL_STA (MT7603_WTBL_RESERVED - MT7603_MAX_INTERFACES)
|
||||
|
||||
#define MT7603_RATE_RETRY 2
|
||||
|
||||
#define MT7603_RX_RING_SIZE 128
|
||||
|
||||
#define MT7603_FIRMWARE_E1 "mt7603_e1.bin"
|
||||
#define MT7603_FIRMWARE_E2 "mt7603_e2.bin"
|
||||
#define MT7628_FIRMWARE_E1 "mt7628_e1.bin"
|
||||
#define MT7628_FIRMWARE_E2 "mt7628_e2.bin"
|
||||
|
||||
#define MT7603_EEPROM_SIZE 1024
|
||||
|
||||
#define MT_AGG_SIZE_LIMIT(_n) (((_n) + 1) * 4)
|
||||
|
||||
#define MT7603_PRE_TBTT_TIME 5000 /* ms */
|
||||
|
||||
#define MT7603_WATCHDOG_TIME 100 /* ms */
|
||||
#define MT7603_WATCHDOG_TIMEOUT 10 /* number of checks */
|
||||
|
||||
#define MT7603_EDCCA_BLOCK_TH 10
|
||||
|
||||
#define MT7603_CFEND_RATE_DEFAULT 0x69 /* chip default (24M) */
|
||||
#define MT7603_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
|
||||
|
||||
struct mt7603_vif;
|
||||
struct mt7603_sta;
|
||||
|
||||
enum {
|
||||
MT7603_REV_E1 = 0x00,
|
||||
MT7603_REV_E2 = 0x10,
|
||||
MT7628_REV_E1 = 0x8a00,
|
||||
};
|
||||
|
||||
enum mt7603_bw {
|
||||
MT_BW_20,
|
||||
MT_BW_40,
|
||||
MT_BW_80,
|
||||
};
|
||||
|
||||
struct mt7603_sta {
|
||||
struct mt76_wcid wcid; /* must be first */
|
||||
|
||||
struct mt7603_vif *vif;
|
||||
|
||||
struct sk_buff_head psq;
|
||||
|
||||
struct ieee80211_tx_rate rates[8];
|
||||
u8 rate_count;
|
||||
u8 n_rates;
|
||||
|
||||
u8 rate_probe;
|
||||
u8 smps;
|
||||
|
||||
u8 ps;
|
||||
};
|
||||
|
||||
struct mt7603_vif {
|
||||
struct mt7603_sta sta; /* must be first */
|
||||
|
||||
u8 idx;
|
||||
};
|
||||
|
||||
enum mt7603_reset_cause {
|
||||
RESET_CAUSE_TX_HANG,
|
||||
RESET_CAUSE_TX_BUSY,
|
||||
RESET_CAUSE_RX_BUSY,
|
||||
RESET_CAUSE_BEACON_STUCK,
|
||||
RESET_CAUSE_RX_PSE_BUSY,
|
||||
RESET_CAUSE_MCU_HANG,
|
||||
RESET_CAUSE_RESET_FAILED,
|
||||
__RESET_CAUSE_MAX
|
||||
};
|
||||
|
||||
struct mt7603_dev {
|
||||
struct mt76_dev mt76; /* must be first */
|
||||
|
||||
const struct mt76_bus_ops *bus_ops;
|
||||
|
||||
u32 rxfilter;
|
||||
|
||||
u8 vif_mask;
|
||||
|
||||
struct mt7603_sta global_sta;
|
||||
|
||||
u32 agc0, agc3;
|
||||
u32 false_cca_ofdm, false_cca_cck;
|
||||
unsigned long last_cca_adj;
|
||||
|
||||
u8 rssi_offset[3];
|
||||
|
||||
u8 slottime;
|
||||
s16 coverage_class;
|
||||
|
||||
s8 tx_power_limit;
|
||||
|
||||
ktime_t survey_time;
|
||||
ktime_t ed_time;
|
||||
int beacon_int;
|
||||
|
||||
struct mt76_queue q_rx;
|
||||
|
||||
spinlock_t ps_lock;
|
||||
|
||||
u8 mac_work_count;
|
||||
|
||||
u8 mcu_running;
|
||||
u8 ed_monitor;
|
||||
|
||||
s8 ed_trigger;
|
||||
u8 ed_strict_mode;
|
||||
u8 ed_strong_signal;
|
||||
|
||||
s8 sensitivity;
|
||||
|
||||
u8 beacon_mask;
|
||||
|
||||
u8 beacon_check;
|
||||
u8 tx_hang_check;
|
||||
u8 tx_dma_check;
|
||||
u8 rx_dma_check;
|
||||
u8 rx_pse_check;
|
||||
u8 mcu_hang;
|
||||
|
||||
enum mt7603_reset_cause cur_reset_cause;
|
||||
|
||||
u16 tx_dma_idx[4];
|
||||
u16 rx_dma_idx;
|
||||
|
||||
u32 reset_test;
|
||||
|
||||
unsigned int reset_cause[__RESET_CAUSE_MAX];
|
||||
|
||||
struct delayed_work mac_work;
|
||||
struct tasklet_struct tx_tasklet;
|
||||
struct tasklet_struct pre_tbtt_tasklet;
|
||||
};
|
||||
|
||||
extern const struct mt76_driver_ops mt7603_drv_ops;
|
||||
extern const struct ieee80211_ops mt7603_ops;
|
||||
extern struct pci_driver mt7603_pci_driver;
|
||||
extern struct platform_driver mt76_wmac_driver;
|
||||
|
||||
static inline bool is_mt7603(struct mt7603_dev *dev)
|
||||
{
|
||||
return mt76xx_chip(dev) == 0x7603;
|
||||
}
|
||||
|
||||
static inline bool is_mt7628(struct mt7603_dev *dev)
|
||||
{
|
||||
return mt76xx_chip(dev) == 0x7628;
|
||||
}
|
||||
|
||||
/* need offset to prevent conflict with ampdu_ack_len */
|
||||
#define MT_RATE_DRIVER_DATA_OFFSET 4
|
||||
|
||||
u32 mt7603_reg_map(struct mt7603_dev *dev, u32 addr);
|
||||
|
||||
irqreturn_t mt7603_irq_handler(int irq, void *dev_instance);
|
||||
|
||||
int mt7603_register_device(struct mt7603_dev *dev);
|
||||
void mt7603_unregister_device(struct mt7603_dev *dev);
|
||||
int mt7603_eeprom_init(struct mt7603_dev *dev);
|
||||
int mt7603_dma_init(struct mt7603_dev *dev);
|
||||
void mt7603_dma_cleanup(struct mt7603_dev *dev);
|
||||
int mt7603_mcu_init(struct mt7603_dev *dev);
|
||||
void mt7603_init_debugfs(struct mt7603_dev *dev);
|
||||
|
||||
void mt7603_set_irq_mask(struct mt7603_dev *dev, u32 clear, u32 set);
|
||||
|
||||
static inline void mt7603_irq_enable(struct mt7603_dev *dev, u32 mask)
|
||||
{
|
||||
mt7603_set_irq_mask(dev, 0, mask);
|
||||
}
|
||||
|
||||
static inline void mt7603_irq_disable(struct mt7603_dev *dev, u32 mask)
|
||||
{
|
||||
mt7603_set_irq_mask(dev, mask, 0);
|
||||
}
|
||||
|
||||
void mt7603_mac_dma_start(struct mt7603_dev *dev);
|
||||
void mt7603_mac_start(struct mt7603_dev *dev);
|
||||
void mt7603_mac_stop(struct mt7603_dev *dev);
|
||||
void mt7603_mac_work(struct work_struct *work);
|
||||
void mt7603_mac_set_timing(struct mt7603_dev *dev);
|
||||
void mt7603_beacon_set_timer(struct mt7603_dev *dev, int idx, int intval);
|
||||
int mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb);
|
||||
void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data);
|
||||
void mt7603_mac_rx_ba_reset(struct mt7603_dev *dev, void *addr, u8 tid);
|
||||
void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, int ssn,
|
||||
int ba_size);
|
||||
|
||||
void mt7603_pse_client_reset(struct mt7603_dev *dev);
|
||||
|
||||
int mt7603_mcu_set_channel(struct mt7603_dev *dev);
|
||||
int mt7603_mcu_set_eeprom(struct mt7603_dev *dev);
|
||||
void mt7603_mcu_exit(struct mt7603_dev *dev);
|
||||
|
||||
void mt7603_wtbl_init(struct mt7603_dev *dev, int idx, int vif,
|
||||
const u8 *mac_addr);
|
||||
void mt7603_wtbl_clear(struct mt7603_dev *dev, int idx);
|
||||
void mt7603_wtbl_update_cap(struct mt7603_dev *dev, struct ieee80211_sta *sta);
|
||||
void mt7603_wtbl_set_rates(struct mt7603_dev *dev, struct mt7603_sta *sta,
|
||||
struct ieee80211_tx_rate *probe_rate,
|
||||
struct ieee80211_tx_rate *rates);
|
||||
int mt7603_wtbl_set_key(struct mt7603_dev *dev, int wcid,
|
||||
struct ieee80211_key_conf *key);
|
||||
void mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta,
|
||||
bool enabled);
|
||||
void mt7603_wtbl_set_smps(struct mt7603_dev *dev, struct mt7603_sta *sta,
|
||||
bool enabled);
|
||||
void mt7603_filter_tx(struct mt7603_dev *dev, int idx, bool abort);
|
||||
|
||||
int mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
||||
struct sk_buff *skb, struct mt76_queue *q,
|
||||
struct mt76_wcid *wcid, struct ieee80211_sta *sta,
|
||||
u32 *tx_info);
|
||||
|
||||
void mt7603_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
|
||||
struct mt76_queue_entry *e, bool flush);
|
||||
|
||||
void mt7603_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
||||
struct sk_buff *skb);
|
||||
void mt7603_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q);
|
||||
void mt7603_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
|
||||
int mt7603_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta);
|
||||
void mt7603_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta);
|
||||
void mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta);
|
||||
|
||||
void mt7603_pre_tbtt_tasklet(unsigned long arg);
|
||||
|
||||
void mt7603_update_channel(struct mt76_dev *mdev);
|
||||
|
||||
void mt7603_edcca_set_strict(struct mt7603_dev *dev, bool val);
|
||||
void mt7603_cca_stats_reset(struct mt7603_dev *dev);
|
||||
|
||||
#endif
|
||||
80
drivers/net/wireless/mediatek/mt76/mt7603/pci.c
Normal file
80
drivers/net/wireless/mediatek/mt76/mt7603/pci.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "mt7603.h"
|
||||
|
||||
static const struct pci_device_id mt76pci_device_table[] = {
|
||||
{ PCI_DEVICE(0x14c3, 0x7603) },
|
||||
{ },
|
||||
};
|
||||
|
||||
static int
|
||||
mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct mt7603_dev *dev;
|
||||
struct mt76_dev *mdev;
|
||||
int ret;
|
||||
|
||||
ret = pcim_enable_device(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7603_ops,
|
||||
&mt7603_drv_ops);
|
||||
if (!mdev)
|
||||
return -ENOMEM;
|
||||
|
||||
dev = container_of(mdev, struct mt7603_dev, mt76);
|
||||
mt76_mmio_init(mdev, pcim_iomap_table(pdev)[0]);
|
||||
|
||||
mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
|
||||
(mt76_rr(dev, MT_HW_REV) & 0xff);
|
||||
dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
|
||||
|
||||
ret = devm_request_irq(mdev->dev, pdev->irq, mt7603_irq_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, dev);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = mt7603_register_device(dev);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
error:
|
||||
ieee80211_free_hw(mt76_hw(dev));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
mt76pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct mt76_dev *mdev = pci_get_drvdata(pdev);
|
||||
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
|
||||
|
||||
mt7603_unregister_device(dev);
|
||||
}
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, mt76pci_device_table);
|
||||
MODULE_FIRMWARE(MT7603_FIRMWARE_E1);
|
||||
MODULE_FIRMWARE(MT7603_FIRMWARE_E2);
|
||||
|
||||
struct pci_driver mt7603_pci_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = mt76pci_device_table,
|
||||
.probe = mt76pci_probe,
|
||||
.remove = mt76pci_remove,
|
||||
};
|
||||
774
drivers/net/wireless/mediatek/mt76/mt7603/regs.h
Normal file
774
drivers/net/wireless/mediatek/mt76/mt7603/regs.h
Normal file
File diff suppressed because it is too large
Load Diff
85
drivers/net/wireless/mediatek/mt76/mt7603/soc.c
Normal file
85
drivers/net/wireless/mediatek/mt76/mt7603/soc.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "mt7603.h"
|
||||
|
||||
static int
|
||||
mt76_wmac_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct mt7603_dev *dev;
|
||||
void __iomem *mem_base;
|
||||
struct mt76_dev *mdev;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get device IRQ\n");
|
||||
return irq;
|
||||
}
|
||||
|
||||
mem_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (!mem_base) {
|
||||
dev_err(&pdev->dev, "Failed to get memory resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7603_ops,
|
||||
&mt7603_drv_ops);
|
||||
if (!mdev)
|
||||
return -ENOMEM;
|
||||
|
||||
dev = container_of(mdev, struct mt7603_dev, mt76);
|
||||
mt76_mmio_init(mdev, mem_base);
|
||||
|
||||
mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
|
||||
(mt76_rr(dev, MT_HW_REV) & 0xff);
|
||||
dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
|
||||
|
||||
ret = devm_request_irq(mdev->dev, irq, mt7603_irq_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, dev);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = mt7603_register_device(dev);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
error:
|
||||
ieee80211_free_hw(mt76_hw(dev));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
mt76_wmac_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mt76_dev *mdev = platform_get_drvdata(pdev);
|
||||
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
|
||||
|
||||
mt7603_unregister_device(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id of_wmac_match[] = {
|
||||
{ .compatible = "mediatek,mt7628-wmac" },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, of_wmac_match);
|
||||
MODULE_FIRMWARE(MT7628_FIRMWARE_E1);
|
||||
MODULE_FIRMWARE(MT7628_FIRMWARE_E2);
|
||||
|
||||
struct platform_driver mt76_wmac_driver = {
|
||||
.probe = mt76_wmac_probe,
|
||||
.remove = mt76_wmac_remove,
|
||||
.driver = {
|
||||
.name = "mt76_wmac",
|
||||
.of_match_table = of_wmac_match,
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user