Commit c869f77d authored by Jakub Kicinski's avatar Jakub Kicinski Committed by Kalle Valo

add mt7601u driver

Add support for the simplest of MediaTek Wi-Fi devices - MT7601U.
It is a single stream bgn chip with no bells or whistles.
This driver is partially based on Felix's mt76 but IMHO it doesn't
make sense to merge the two right now because MT7601U is a design
somewhere between old Ralink devices and new Mediatek chips.  There
wouldn't be all that much code sharing with the devices mt76 supports.
Situation may obviously change when someone decides to extend m76 with
support for the more recent USB dongles.

The driver supports only station mode.  I'm hoping to add AP support
when time allows.

This driver sat on GitHub for quite a while and got some testing there:
http://github.com/kuba-moo/mt7601uSigned-off-by: default avatarJakub Kicinski <kubakici@wp.pl>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 00e27eeb
......@@ -6365,6 +6365,12 @@ F: include/uapi/linux/meye.h
F: include/uapi/linux/ivtv*
F: include/uapi/linux/uvcvideo.h
MEDIATEK MT7601U WIRELESS LAN DRIVER
M: Jakub Kicinski <kubakici@wp.pl>
L: linux-wireless@vger.kernel.org
S: Maintained
F: drivers/net/wireless/mediatek/mt7601u/
MEGARAID SCSI/SAS DRIVERS
M: Kashyap Desai <kashyap.desai@avagotech.com>
M: Sumit Saxena <sumit.saxena@avagotech.com>
......
......@@ -277,6 +277,7 @@ source "drivers/net/wireless/libertas/Kconfig"
source "drivers/net/wireless/orinoco/Kconfig"
source "drivers/net/wireless/p54/Kconfig"
source "drivers/net/wireless/rt2x00/Kconfig"
source "drivers/net/wireless/mediatek/Kconfig"
source "drivers/net/wireless/rtlwifi/Kconfig"
source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
......
......@@ -45,6 +45,8 @@ obj-$(CONFIG_IWLWIFI) += iwlwifi/
obj-$(CONFIG_IWLEGACY) += iwlegacy/
obj-$(CONFIG_RT2X00) += rt2x00/
obj-$(CONFIG_WL_MEDIATEK) += mediatek/
obj-$(CONFIG_P54_COMMON) += p54/
obj-$(CONFIG_ATH_CARDS) += ath/
......
menuconfig WL_MEDIATEK
bool "Mediatek Wireless LAN support"
---help---
Enable community drivers for MediaTek WiFi devices.
Those drivers make use of the Linux mac80211 stack.
if WL_MEDIATEK
source "drivers/net/wireless/mediatek/mt7601u/Kconfig"
endif # WL_MEDIATEK
obj-$(CONFIG_MT7601U) += mt7601u/
config MT7601U
tristate "MediaTek MT7601U (USB) support"
depends on MAC80211
depends on USB
---help---
This adds support for MT7601U-based wireless USB dongles.
ccflags-y += -D__CHECK_ENDIAN__
obj-$(CONFIG_MT7601U) += mt7601u.o
mt7601u-objs = \
usb.o init.o main.o mcu.o trace.o dma.o core.o eeprom.o phy.o \
mac.o util.o debugfs.o tx.o
CFLAGS_trace.o := -I$(src)
/*
* Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "mt7601u.h"
int mt7601u_wait_asic_ready(struct mt7601u_dev *dev)
{
int i = 100;
u32 val;
do {
if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
return -EIO;
val = mt7601u_rr(dev, MT_MAC_CSR0);
if (val && ~val)
return 0;
udelay(10);
} while (i--);
return -EIO;
}
bool mt76_poll(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val,
int timeout)
{
u32 cur;
timeout /= 10;
do {
if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
return false;
cur = mt7601u_rr(dev, offset) & mask;
if (cur == val)
return true;
udelay(10);
} while (timeout-- > 0);
dev_err(dev->dev, "Error: Time out with reg %08x\n", offset);
return false;
}
bool mt76_poll_msec(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val,
int timeout)
{
u32 cur;
timeout /= 10;
do {
if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
return false;
cur = mt7601u_rr(dev, offset) & mask;
if (cur == val)
return true;
msleep(10);
} while (timeout-- > 0);
dev_err(dev->dev, "Error: Time out with reg %08x\n", offset);
return false;
}
/*
* Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/debugfs.h>
#include "mt7601u.h"
#include "eeprom.h"
static int
mt76_reg_set(void *data, u64 val)
{
struct mt7601u_dev *dev = data;
mt76_wr(dev, dev->debugfs_reg, val);
return 0;
}
static int
mt76_reg_get(void *data, u64 *val)
{
struct mt7601u_dev *dev = data;
*val = mt76_rr(dev, dev->debugfs_reg);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n");
static int
mt7601u_ampdu_stat_read(struct seq_file *file, void *data)
{
struct mt7601u_dev *dev = file->private;
int i, j;
#define stat_printf(grp, off, name) \
seq_printf(file, #name ":\t%llu\n", dev->stats.grp[off])
stat_printf(rx_stat, 0, rx_crc_err);
stat_printf(rx_stat, 1, rx_phy_err);
stat_printf(rx_stat, 2, rx_false_cca);
stat_printf(rx_stat, 3, rx_plcp_err);
stat_printf(rx_stat, 4, rx_fifo_overflow);
stat_printf(rx_stat, 5, rx_duplicate);
stat_printf(tx_stat, 0, tx_fail_cnt);
stat_printf(tx_stat, 1, tx_bcn_cnt);
stat_printf(tx_stat, 2, tx_success);
stat_printf(tx_stat, 3, tx_retransmit);
stat_printf(tx_stat, 4, tx_zero_len);
stat_printf(tx_stat, 5, tx_underflow);
stat_printf(aggr_stat, 0, non_aggr_tx);
stat_printf(aggr_stat, 1, aggr_tx);
stat_printf(zero_len_del, 0, tx_zero_len_del);
stat_printf(zero_len_del, 1, rx_zero_len_del);
#undef stat_printf
seq_puts(file, "Aggregations stats:\n");
for (i = 0; i < 4; i++) {
for (j = 0; j < 8; j++)
seq_printf(file, "%08llx ",
dev->stats.aggr_n[i * 8 + j]);
seq_putc(file, '\n');
}
seq_printf(file, "recent average AMPDU len: %d\n",
atomic_read(&dev->avg_ampdu_len));
return 0;
}
static int
mt7601u_ampdu_stat_open(struct inode *inode, struct file *f)
{
return single_open(f, mt7601u_ampdu_stat_read, inode->i_private);
}
static const struct file_operations fops_ampdu_stat = {
.open = mt7601u_ampdu_stat_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int
mt7601u_eeprom_param_read(struct seq_file *file, void *data)
{
struct mt7601u_dev *dev = file->private;
struct mt7601u_rate_power *rp = &dev->ee->power_rate_table;
struct tssi_data *td = &dev->ee->tssi_data;
int i;
seq_printf(file, "RF freq offset: %hhx\n", dev->ee->rf_freq_off);
seq_printf(file, "RSSI offset: %hhx %hhx\n",
dev->ee->rssi_offset[0], dev->ee->rssi_offset[1]);
seq_printf(file, "Reference temp: %hhx\n", dev->ee->ref_temp);
seq_printf(file, "LNA gain: %hhx\n", dev->ee->lna_gain);
seq_printf(file, "Reg channels: %hhu-%hhu\n", dev->ee->reg.start,
dev->ee->reg.start + dev->ee->reg.num - 1);
seq_puts(file, "Per rate power:\n");
for (i = 0; i < 2; i++)
seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n",
rp->cck[i].raw, rp->cck[i].bw20, rp->cck[i].bw40);
for (i = 0; i < 4; i++)
seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n",
rp->ofdm[i].raw, rp->ofdm[i].bw20, rp->ofdm[i].bw40);
for (i = 0; i < 4; i++)
seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n",
rp->ht[i].raw, rp->ht[i].bw20, rp->ht[i].bw40);
seq_puts(file, "Per channel power:\n");
for (i = 0; i < 7; i++)
seq_printf(file, "\t tx_power ch%u:%02hhx ch%u:%02hhx\n",
i * 2 + 1, dev->ee->chan_pwr[i * 2],
i * 2 + 2, dev->ee->chan_pwr[i * 2 + 1]);
if (!dev->ee->tssi_enabled)
return 0;
seq_puts(file, "TSSI:\n");
seq_printf(file, "\t slope:%02hhx\n", td->slope);
seq_printf(file, "\t offset=%02hhx %02hhx %02hhx\n",
td->offset[0], td->offset[1], td->offset[2]);
seq_printf(file, "\t delta_off:%08x\n", td->tx0_delta_offset);
return 0;
}
static int
mt7601u_eeprom_param_open(struct inode *inode, struct file *f)
{
return single_open(f, mt7601u_eeprom_param_read, inode->i_private);
}
static const struct file_operations fops_eeprom_param = {
.open = mt7601u_eeprom_param_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
void mt7601u_init_debugfs(struct mt7601u_dev *dev)
{
struct dentry *dir;
dir = debugfs_create_dir("mt7601u", dev->hw->wiphy->debugfsdir);
if (!dir)
return;
debugfs_create_u8("temperature", S_IRUSR, dir, &dev->raw_temp);
debugfs_create_u32("temp_mode", S_IRUSR, dir, &dev->temp_mode);
debugfs_create_u32("regidx", S_IRUSR | S_IWUSR, dir, &dev->debugfs_reg);
debugfs_create_file("regval", S_IRUSR | S_IWUSR, dir, dev,
&fops_regval);
debugfs_create_file("ampdu_stat", S_IRUSR, dir, dev, &fops_ampdu_stat);
debugfs_create_file("eeprom_param", S_IRUSR, dir, dev,
&fops_eeprom_param);
}
This diff is collapsed.
/*
* Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __MT7601U_DMA_H
#define __MT7601U_DMA_H
#include <asm/unaligned.h>
#include <linux/skbuff.h>
#include "util.h"
#define MT_DMA_HDR_LEN 4
#define MT_RX_INFO_LEN 4
#define MT_FCE_INFO_LEN 4
#define MT_DMA_HDRS (MT_DMA_HDR_LEN + MT_RX_INFO_LEN)
/* Common Tx DMA descriptor fields */
#define MT_TXD_INFO_LEN GENMASK(15, 0)
#define MT_TXD_INFO_D_PORT GENMASK(29, 27)
#define MT_TXD_INFO_TYPE GENMASK(31, 30)
enum mt76_msg_port {
WLAN_PORT,
CPU_RX_PORT,
CPU_TX_PORT,
HOST_PORT,
VIRTUAL_CPU_RX_PORT,
VIRTUAL_CPU_TX_PORT,
DISCARD,
};
enum mt76_info_type {
DMA_PACKET,
DMA_COMMAND,
};
/* Tx DMA packet specific flags */
#define MT_TXD_PKT_INFO_NEXT_VLD BIT(16)
#define MT_TXD_PKT_INFO_TX_BURST BIT(17)
#define MT_TXD_PKT_INFO_80211 BIT(19)
#define MT_TXD_PKT_INFO_TSO BIT(20)
#define MT_TXD_PKT_INFO_CSO BIT(21)
#define MT_TXD_PKT_INFO_WIV BIT(24)
#define MT_TXD_PKT_INFO_QSEL GENMASK(26, 25)
enum mt76_qsel {
MT_QSEL_MGMT,
MT_QSEL_HCCA,
MT_QSEL_EDCA,
MT_QSEL_EDCA_2,
};
/* Tx DMA MCU command specific flags */
#define MT_TXD_CMD_INFO_SEQ GENMASK(19, 16)
#define MT_TXD_CMD_INFO_TYPE GENMASK(26, 20)
static inline int mt7601u_dma_skb_wrap(struct sk_buff *skb,
enum mt76_msg_port d_port,
enum mt76_info_type type, u32 flags)
{
u32 info;
/* Buffer layout:
* | 4B | xfer len | pad | 4B |
* | TXINFO | pkt/cmd | zero pad to 4B | zero |
*
* length field of TXINFO should be set to 'xfer len'.
*/
info = flags |
MT76_SET(MT_TXD_INFO_LEN, round_up(skb->len, 4)) |
MT76_SET(MT_TXD_INFO_D_PORT, d_port) |
MT76_SET(MT_TXD_INFO_TYPE, type);
put_unaligned_le32(info, skb_push(skb, sizeof(info)));
return skb_put_padto(skb, round_up(skb->len, 4) + 4);
}
static inline int
mt7601u_dma_skb_wrap_pkt(struct sk_buff *skb, enum mt76_qsel qsel, u32 flags)
{
flags |= MT76_SET(MT_TXD_PKT_INFO_QSEL, qsel);
return mt7601u_dma_skb_wrap(skb, WLAN_PORT, DMA_PACKET, flags);
}
/* Common Rx DMA descriptor fields */
#define MT_RXD_INFO_LEN GENMASK(13, 0)
#define MT_RXD_INFO_PCIE_INTR BIT(24)
#define MT_RXD_INFO_QSEL GENMASK(26, 25)
#define MT_RXD_INFO_PORT GENMASK(29, 27)
#define MT_RXD_INFO_TYPE GENMASK(31, 30)
/* Rx DMA packet specific flags */
#define MT_RXD_PKT_INFO_UDP_ERR BIT(16)
#define MT_RXD_PKT_INFO_TCP_ERR BIT(17)
#define MT_RXD_PKT_INFO_IP_ERR BIT(18)
#define MT_RXD_PKT_INFO_PKT_80211 BIT(19)
#define MT_RXD_PKT_INFO_L3L4_DONE BIT(20)
#define MT_RXD_PKT_INFO_MAC_LEN GENMASK(23, 21)
/* Rx DMA MCU command specific flags */
#define MT_RXD_CMD_INFO_SELF_GEN BIT(15)
#define MT_RXD_CMD_INFO_CMD_SEQ GENMASK(19, 16)
#define MT_RXD_CMD_INFO_EVT_TYPE GENMASK(23, 20)
enum mt76_evt_type {
CMD_DONE,
CMD_ERROR,
CMD_RETRY,
EVENT_PWR_RSP,
EVENT_WOW_RSP,
EVENT_CARRIER_DETECT_RSP,
EVENT_DFS_DETECT_RSP,
};
#endif
This diff is collapsed.
/*
* Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __MT7601U_EEPROM_H
#define __MT7601U_EEPROM_H
struct mt7601u_dev;
#define MT7601U_EE_MAX_VER 0x0c
#define MT7601U_EEPROM_SIZE 256
#define MT7601U_DEFAULT_TX_POWER 6
enum mt76_eeprom_field {
MT_EE_CHIP_ID = 0x00,
MT_EE_VERSION_FAE = 0x02,
MT_EE_VERSION_EE = 0x03,
MT_EE_MAC_ADDR = 0x04,
MT_EE_NIC_CONF_0 = 0x34,
MT_EE_NIC_CONF_1 = 0x36,
MT_EE_COUNTRY_REGION = 0x39,
MT_EE_FREQ_OFFSET = 0x3a,
MT_EE_NIC_CONF_2 = 0x42,
MT_EE_LNA_GAIN = 0x44,
MT_EE_RSSI_OFFSET = 0x46,
MT_EE_TX_POWER_DELTA_BW40 = 0x50,
MT_EE_TX_POWER_OFFSET = 0x52,
MT_EE_TX_TSSI_SLOPE = 0x6e,
MT_EE_TX_TSSI_OFFSET_GROUP = 0x6f,
MT_EE_TX_TSSI_OFFSET = 0x76,
MT_EE_TX_TSSI_TARGET_POWER = 0xd0,
MT_EE_REF_TEMP = 0xd1,
MT_EE_FREQ_OFFSET_COMPENSATION = 0xdb,
MT_EE_TX_POWER_BYRATE_BASE = 0xde,
MT_EE_USAGE_MAP_START = 0x1e0,
MT_EE_USAGE_MAP_END = 0x1fc,
};
#define MT_EE_NIC_CONF_0_RX_PATH GENMASK(3, 0)
#define MT_EE_NIC_CONF_0_TX_PATH GENMASK(7, 4)
#define MT_EE_NIC_CONF_0_BOARD_TYPE GENMASK(13, 12)
#define MT_EE_NIC_CONF_1_HW_RF_CTRL BIT(0)
#define MT_EE_NIC_CONF_1_TEMP_TX_ALC BIT(1)
#define MT_EE_NIC_CONF_1_LNA_EXT_2G BIT(2)
#define MT_EE_NIC_CONF_1_LNA_EXT_5G BIT(3)
#define MT_EE_NIC_CONF_1_TX_ALC_EN BIT(13)
#define MT_EE_NIC_CONF_2_RX_STREAM GENMASK(3, 0)
#define MT_EE_NIC_CONF_2_TX_STREAM GENMASK(7, 4)
#define MT_EE_NIC_CONF_2_HW_ANTDIV BIT(8)
#define MT_EE_NIC_CONF_2_XTAL_OPTION GENMASK(10, 9)
#define MT_EE_NIC_CONF_2_TEMP_DISABLE BIT(11)
#define MT_EE_NIC_CONF_2_COEX_METHOD GENMASK(15, 13)
#define MT_EE_TX_POWER_BYRATE(i) (MT_EE_TX_POWER_BYRATE_BASE + \
(i) * 4)
#define MT_EFUSE_USAGE_MAP_SIZE (MT_EE_USAGE_MAP_END - \
MT_EE_USAGE_MAP_START + 1)
enum mt7601u_eeprom_access_modes {
MT_EE_READ = 0,
MT_EE_PHYSICAL_READ = 1,
};
struct power_per_rate {
u8 raw; /* validated s6 value */
s8 bw20; /* sign-extended int */
s8 bw40; /* sign-extended int */
};
/* Power per rate - one value per two rates */
struct mt7601u_rate_power {
struct power_per_rate cck[2];
struct power_per_rate ofdm[4];
struct power_per_rate ht[4];
};
struct reg_channel_bounds {
u8 start;
u8 num;
};
struct mt7601u_eeprom_params {
bool tssi_enabled;
u8 rf_freq_off;
s8 rssi_offset[2];
s8 ref_temp;
s8 lna_gain;
u8 chan_pwr[14];
struct mt7601u_rate_power power_rate_table;
s8 real_cck_bw20[2];
/* TSSI stuff - only with internal TX ALC */
struct tssi_data {
int tx0_delta_offset;
u8 slope;
u8 offset[3];
} tssi_data;
struct reg_channel_bounds reg;
};
int mt7601u_eeprom_init(struct mt7601u_dev *dev);
static inline u32 s6_validate(u32 reg)
{
WARN_ON(reg & ~GENMASK(5, 0));
return reg & GENMASK(5, 0);
}
static inline int s6_to_int(u32 reg)
{
int s6;
s6 = s6_validate(reg);
if (s6 & BIT(5))
s6 -= BIT(6);
return s6;
}
static inline u32 int_to_s6(int val)
{
if (val < -0x20)
return 0x20;
if (val > 0x1f)
return 0x1f;
return val & 0x3f;
}
#endif
This diff is collapsed.
/*
* (c) Copyright 2002-2010, Ralink Technology, Inc.
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __MT7601U_INITVALS_H
#define __MT7601U_INITVALS_H
static const struct mt76_reg_pair bbp_common_vals[] = {
{ 65, 0x2c },
{ 66, 0x38 },
{ 68, 0x0b },
{ 69, 0x12 },
{ 70, 0x0a },
{ 73, 0x10 },
{ 81, 0x37 },
{ 82, 0x62 },
{ 83, 0x6a },
{ 84, 0x99 },
{ 86, 0x00 },
{ 91, 0x04 },
{ 92, 0x00 },
{ 103, 0x00 },
{ 105, 0x05 },
{ 106, 0x35 },
};
static const struct mt76_reg_pair bbp_chip_vals[] = {
{ 1, 0x04 }, { 4, 0x40 }, { 20, 0x06 }, { 31, 0x08 },
/* CCK Tx Control */
{ 178, 0xff },
/* AGC/Sync controls */
{ 66, 0x14 }, { 68, 0x8b }, { 69, 0x12 }, { 70, 0x09 },
{ 73, 0x11 }, { 75, 0x60 }, { 76, 0x44 }, { 84, 0x9a },
{ 86, 0x38 }, { 91, 0x07 }, { 92, 0x02 },
/* Rx Path Controls */
{ 99, 0x50 }, { 101, 0x00 }, { 103, 0xc0 }, { 104, 0x92 },
{ 105, 0x3c }, { 106, 0x03 }, { 128, 0x12 },
/* Change RXWI content: Gain Report */
{ 142, 0x04 }, { 143, 0x37 },
/* Change RXWI content: Antenna Report */
{ 142, 0x03 }, { 143, 0x99 },
/* Calibration Index Register */
/* CCK Receiver Control */
{ 160, 0xeb }, { 161, 0xc4 }, { 162, 0x77 }, { 163, 0xf9 },
{ 164, 0x88 }, { 165, 0x80 }, { 166, 0xff }, { 167, 0xe4 },
/* Added AGC controls - these AGC/GLRT registers are accessed
* through R195 and R196.
*/
{ 195, 0x00 }, { 196, 0x00 },
{ 195, 0x01 }, { 196, 0x04 },
{ 195, 0x02 }, { 196, 0x20 },
{ 195, 0x03 }, { 196, 0x0a },
{ 195, 0x06 }, { 196, 0x16 },
{ 195, 0x07 }, { 196, 0x05 },
{ 195, 0x08 }, { 196, 0x37 },
{ 195, 0x0a }, { 196, 0x15 },
{ 195, 0x0b }, { 196, 0x17 },
{ 195, 0x0c }, { 196, 0x06 },
{ 195, 0x0d }, { 196, 0x09 },
{ 195, 0x0e }, { 196, 0x05 },
{ 195, 0x0f }, { 196, 0x09 },
{ 195, 0x10 }, { 196, 0x20 },
{ 195, 0x20 }, { 196, 0x17 },
{ 195, 0x21 }, { 196, 0x06 },
{ 195, 0x22 }, { 196, 0x09 },
{ 195, 0x23 }, { 196, 0x17 },
{ 195, 0x24 }, { 196, 0x06 },
{ 195, 0x25 }, { 196, 0x09 },
{ 195, 0x26 }, { 196, 0x17 },
{ 195, 0x27 }, { 196, 0x06 },
{ 195, 0x28 }, { 196, 0x09 },
{ 195, 0x29 }, { 196, 0x05 },
{ 195, 0x2a }, { 196, 0x09 },
{ 195, 0x80 }, { 196, 0x8b },
{ 195, 0x81 }, { 196, 0x12 },
{ 195, 0x82 }, { 196, 0x09 },
{ 195, 0x83 }, { 196, 0x17 },
{ 195, 0x84 }, { 196, 0x11 },
{ 195, 0x85 }, { 196, 0x00 },
{ 195, 0x86 }, { 196, 0x00 },
{ 195, 0x87 }, { 196, 0x18 },
{ 195, 0x88 }, { 196, 0x60 },
{ 195, 0x89 }, { 196, 0x44 },
{ 195, 0x8a }, { 196, 0x8b },
{ 195, 0x8b }, { 196, 0x8b },
{ 195, 0x8c }, { 196, 0x8b },
{ 195, 0x8d }, { 196, 0x8b },
{ 195, 0x8e }, { 196, 0x09 },
{ 195, 0x8f }, { 196, 0x09 },
{ 195, 0x90 }, { 196, 0x09 },
{ 195, 0x91 }, { 196, 0x09 },
{ 195, 0x92 }, { 196, 0x11 },
{ 195, 0x93 }, { 196, 0x11 },
{ 195, 0x94 }, { 196, 0x11 },
{ 195, 0x95 }, { 196, 0x11 },
/* PPAD */
{ 47, 0x80 }, { 60, 0x80 }, { 150, 0xd2 }, { 151, 0x32 },
{ 152, 0x23 }, { 153, 0x41 }, { 154, 0x00 }, { 155, 0x4f },
{ 253, 0x7e }, { 195, 0x30 }, { 196, 0x32 }, { 195, 0x31 },
{ 196, 0x23 }, { 195, 0x32 }, { 196, 0x45 }, { 195, 0x35 },
{ 196, 0x4a }, { 195, 0x36 }, { 196, 0x5a }, { 195, 0x37 },
{ 196, 0x5a },
};
static const struct mt76_reg_pair mac_common_vals[] = {
{ MT_LEGACY_BASIC_RATE, 0x0000013f },
{ MT_HT_BASIC_RATE, 0x00008003 },
{ MT_MAC_SYS_CTRL, 0x00000000 },
{ MT_RX_FILTR_CFG, 0x00017f97 },
{ MT_BKOFF_SLOT_CFG, 0x00000209 },
{ MT_TX_SW_CFG0, 0x00000000 },
{ MT_TX_SW_CFG1, 0x00080606 },
{ MT_TX_LINK_CFG, 0x00001020 },
{ MT_TX_TIMEOUT_CFG, 0x000a2090 },
{ MT_MAX_LEN_CFG, 0x00003fff },
{ MT_PBF_TX_MAX_PCNT, 0x1fbf1f1f },
{ MT_PBF_RX_MAX_PCNT, 0x0000009f },
{ MT_TX_RETRY_CFG, 0x47d01f0f },
{ MT_AUTO_RSP_CFG, 0x00000013 },
{ MT_CCK_PROT_CFG, 0x05740003 },
{ MT_OFDM_PROT_CFG, 0x05740003 },
{ MT_MM40_PROT_CFG, 0x03f44084 },
{ MT_GF20_PROT_CFG, 0x01744004 },
{ MT_GF40_PROT_CFG, 0x03f44084 },
{ MT_MM20_PROT_CFG, 0x01744004 },
{ MT_TXOP_CTRL_CFG, 0x0000583f },
{ MT_TX_RTS_CFG, 0x01092b20 },
{ MT_EXP_ACK_TIME, 0x002400ca },
{ MT_TXOP_HLDR_ET, 0x00000002 },
{ MT_XIFS_TIME_CFG, 0x33a41010 },
{ MT_PWR_PIN_CFG, 0x00000000 },
};
static const struct mt76_reg_pair mac_chip_vals[] = {
{ MT_TSO_CTRL, 0x00006050 },
{ MT_BCN_OFFSET(0), 0x18100800 },
{ MT_BCN_OFFSET(1), 0x38302820 },
{ MT_PBF_SYS_CTRL, 0x00080c00 },
{ MT_PBF_CFG, 0x7f723c1f },
{ MT_FCE_PSE_CTRL, 0x00000001 },
{ MT_PAUSE_ENABLE_CONTROL1, 0x00000000 },
{ MT_TX0_RF_GAIN_CORR, 0x003b0005 },
{ MT_TX0_RF_GAIN_ATTEN, 0x00006900 },
{ MT_TX0_BB_GAIN_ATTEN, 0x00000400 },
{ MT_TX_ALC_VGA3, 0x00060006 },
{ MT_TX_SW_CFG0, 0x00000402 },
{ MT_TX_SW_CFG1, 0x00000000 },
{ MT_TX_SW_CFG2, 0x00000000 },
{ MT_HEADER_TRANS_CTRL_REG, 0x00000000 },
{ MT_FCE_CSO, 0x0000030f },
{ MT_FCE_PARAMETERS, 0x00256f0f },
};
#endif
/*
* (c) Copyright 2002-2010, Ralink Technology, Inc.
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __MT7601U_PHY_INITVALS_H
#define __MT7601U_PHY_INITVALS_H
#define RF_REG_PAIR(bank, reg, value) \
{ MT_MCU_MEMMAP_RF | (bank) << 16 | (reg), value }
static const struct mt76_reg_pair rf_central[] = {
/* Bank 0 - for central blocks: BG, PLL, XTAL, LO, ADC/DAC */
RF_REG_PAIR(0, 0, 0x02),
RF_REG_PAIR(0, 1, 0x01),
RF_REG_PAIR(0, 2, 0x11),
RF_REG_PAIR(0, 3, 0xff),
RF_REG_PAIR(0, 4, 0x0a),
RF_REG_PAIR(0, 5, 0x20),
RF_REG_PAIR(0, 6, 0x00),
/* B/G */
RF_REG_PAIR(0, 7, 0x00),
RF_REG_PAIR(0, 8, 0x00),
RF_REG_PAIR(0, 9, 0x00),
RF_REG_PAIR(0, 10, 0x00),
RF_REG_PAIR(0, 11, 0x21),
/* XO */
RF_REG_PAIR(0, 13, 0x00), /* 40mhz xtal */
/* RF_REG_PAIR(0, 13, 0x13), */ /* 20mhz xtal */
RF_REG_PAIR(0, 14, 0x7c),
RF_REG_PAIR(0, 15, 0x22),
RF_REG_PAIR(0, 16, 0x80),
/* PLL */
RF_REG_PAIR(0, 17, 0x99),
RF_REG_PAIR(0, 18, 0x99),
RF_REG_PAIR(0, 19, 0x09),
RF_REG_PAIR(0, 20, 0x50),
RF_REG_PAIR(0, 21, 0xb0),
RF_REG_PAIR(0, 22, 0x00),
RF_REG_PAIR(0, 23, 0xc5),
RF_REG_PAIR(0, 24, 0xfc),
RF_REG_PAIR(0, 25, 0x40),
RF_REG_PAIR(0, 26, 0x4d),
RF_REG_PAIR(0, 27, 0x02),
RF_REG_PAIR(0, 28, 0x72),
RF_REG_PAIR(0, 29, 0x01),
RF_REG_PAIR(0, 30, 0x00),
RF_REG_PAIR(0, 31, 0x00),
/* test ports */
RF_REG_PAIR(0, 32, 0x00),
RF_REG_PAIR(0, 33, 0x00),
RF_REG_PAIR(0, 34, 0x23),
RF_REG_PAIR(0, 35, 0x01), /* change setting to reduce spurs */
RF_REG_PAIR(0, 36, 0x00),
RF_REG_PAIR(0, 37, 0x00),
/* ADC/DAC */
RF_REG_PAIR(0, 38, 0x00),
RF_REG_PAIR(0, 39, 0x20),
RF_REG_PAIR(0, 40, 0x00),
RF_REG_PAIR(0, 41, 0xd0),
RF_REG_PAIR(0, 42, 0x1b),
RF_REG_PAIR(0, 43, 0x02),
RF_REG_PAIR(0, 44, 0x00),
};
static const struct mt76_reg_pair rf_channel[] = {
RF_REG_PAIR(4, 0, 0x01),
RF_REG_PAIR(4, 1, 0x00),
RF_REG_PAIR(4, 2, 0x00),
RF_REG_PAIR(4, 3, 0x00),
/* LDO */
RF_REG_PAIR(4, 4, 0x00),
RF_REG_PAIR(4, 5, 0x08),
RF_REG_PAIR(4, 6, 0x00),
/* RX */
RF_REG_PAIR(4, 7, 0x5b),
RF_REG_PAIR(4, 8, 0x52),
RF_REG_PAIR(4, 9, 0xb6),
RF_REG_PAIR(4, 10, 0x57),
RF_REG_PAIR(4, 11, 0x33),
RF_REG_PAIR(4, 12, 0x22),
RF_REG_PAIR(4, 13, 0x3d),
RF_REG_PAIR(4, 14, 0x3e),
RF_REG_PAIR(4, 15, 0x13),
RF_REG_PAIR(4, 16, 0x22),
RF_REG_PAIR(4, 17, 0x23),
RF_REG_PAIR(4, 18, 0x02),
RF_REG_PAIR(4, 19, 0xa4),
RF_REG_PAIR(4, 20, 0x01),
RF_REG_PAIR(4, 21, 0x12),
RF_REG_PAIR(4, 22, 0x80),
RF_REG_PAIR(4, 23, 0xb3),
RF_REG_PAIR(4, 24, 0x00), /* reserved */
RF_REG_PAIR(4, 25, 0x00), /* reserved */
RF_REG_PAIR(4, 26, 0x00), /* reserved */
RF_REG_PAIR(4, 27, 0x00), /* reserved */
/* LOGEN */
RF_REG_PAIR(4, 28, 0x18),
RF_REG_PAIR(4, 29, 0xee),
RF_REG_PAIR(4, 30, 0x6b),
RF_REG_PAIR(4, 31, 0x31),
RF_REG_PAIR(4, 32, 0x5d),
RF_REG_PAIR(4, 33, 0x00), /* reserved */
/* TX */
RF_REG_PAIR(4, 34, 0x96),
RF_REG_PAIR(4, 35, 0x55),
RF_REG_PAIR(4, 36, 0x08),
RF_REG_PAIR(4, 37, 0xbb),
RF_REG_PAIR(4, 38, 0xb3),
RF_REG_PAIR(4, 39, 0xb3),
RF_REG_PAIR(4, 40, 0x03),
RF_REG_PAIR(4, 41, 0x00), /* reserved */
RF_REG_PAIR(4, 42, 0x00), /* reserved */
RF_REG_PAIR(4, 43, 0xc5),
RF_REG_PAIR(4, 44, 0xc5),
RF_REG_PAIR(4, 45, 0xc5),
RF_REG_PAIR(4, 46, 0x07),
RF_REG_PAIR(4, 47, 0xa8),
RF_REG_PAIR(4, 48, 0xef),
RF_REG_PAIR(4, 49, 0x1a),
/* PA */
RF_REG_PAIR(4, 54, 0x07),
RF_REG_PAIR(4, 55, 0xa7),
RF_REG_PAIR(4, 56, 0xcc),
RF_REG_PAIR(4, 57, 0x14),
RF_REG_PAIR(4, 58, 0x07),
RF_REG_PAIR(4, 59, 0xa8),
RF_REG_PAIR(4, 60, 0xd7),
RF_REG_PAIR(4, 61, 0x10),
RF_REG_PAIR(4, 62, 0x1c),
RF_REG_PAIR(4, 63, 0x00), /* reserved */
};
static const struct mt76_reg_pair rf_vga[] = {
RF_REG_PAIR(5, 0, 0x47),
RF_REG_PAIR(5, 1, 0x00),
RF_REG_PAIR(5, 2, 0x00),
RF_REG_PAIR(5, 3, 0x08),
RF_REG_PAIR(5, 4, 0x04),
RF_REG_PAIR(5, 5, 0x20),
RF_REG_PAIR(5, 6, 0x3a),
RF_REG_PAIR(5, 7, 0x3a),
RF_REG_PAIR(5, 8, 0x00),
RF_REG_PAIR(5, 9, 0x00),
RF_REG_PAIR(5, 10, 0x10),
RF_REG_PAIR(5, 11, 0x10),
RF_REG_PAIR(5, 12, 0x10),
RF_REG_PAIR(5, 13, 0x10),
RF_REG_PAIR(5, 14, 0x10),
RF_REG_PAIR(5, 15, 0x20),
RF_REG_PAIR(5, 16, 0x22),
RF_REG_PAIR(5, 17, 0x7c),
RF_REG_PAIR(5, 18, 0x00),
RF_REG_PAIR(5, 19, 0x00),
RF_REG_PAIR(5, 20, 0x00),
RF_REG_PAIR(5, 21, 0xf1),
RF_REG_PAIR(5, 22, 0x11),
RF_REG_PAIR(5, 23, 0x02),
RF_REG_PAIR(5, 24, 0x41),
RF_REG_PAIR(5, 25, 0x20),
RF_REG_PAIR(5, 26, 0x00),
RF_REG_PAIR(5, 27, 0xd7),
RF_REG_PAIR(5, 28, 0xa2),
RF_REG_PAIR(5, 29, 0x20),
RF_REG_PAIR(5, 30, 0x49),
RF_REG_PAIR(5, 31, 0x20),
RF_REG_PAIR(5, 32, 0x04),
RF_REG_PAIR(5, 33, 0xf1),
RF_REG_PAIR(5, 34, 0xa1),
RF_REG_PAIR(5, 35, 0x01),
RF_REG_PAIR(5, 41, 0x00),
RF_REG_PAIR(5, 42, 0x00),
RF_REG_PAIR(5, 43, 0x00),
RF_REG_PAIR(5, 44, 0x00),
RF_REG_PAIR(5, 45, 0x00),
RF_REG_PAIR(5, 46, 0x00),
RF_REG_PAIR(5, 47, 0x00),
RF_REG_PAIR(5, 48, 0x00),
RF_REG_PAIR(5, 49, 0x00),
RF_REG_PAIR(5, 50, 0x00),
RF_REG_PAIR(5, 51, 0x00),
RF_REG_PAIR(5, 52, 0x00),
RF_REG_PAIR(5, 53, 0x00),
RF_REG_PAIR(5, 54, 0x00),
RF_REG_PAIR(5, 55, 0x00),
RF_REG_PAIR(5, 56, 0x00),
RF_REG_PAIR(5, 57, 0x00),
RF_REG_PAIR(5, 58, 0x31),
RF_REG_PAIR(5, 59, 0x31),
RF_REG_PAIR(5, 60, 0x0a),
RF_REG_PAIR(5, 61, 0x02),
RF_REG_PAIR(5, 62, 0x00),
RF_REG_PAIR(5, 63, 0x00),
};
/* TODO: BBP178 is set to 0xff for "CCK CH14 OBW" which overrides the settings
* from channel switching. Seems stupid at best.
*/
static const struct mt76_reg_pair bbp_high_temp[] = {
{ 75, 0x60 },
{ 92, 0x02 },
{ 178, 0xff }, /* For CCK CH14 OBW */
{ 195, 0x88 }, { 196, 0x60 },
}, bbp_high_temp_bw20[] = {
{ 69, 0x12 },
{ 91, 0x07 },
{ 195, 0x23 }, { 196, 0x17 },
{ 195, 0x24 }, { 196, 0x06 },
{ 195, 0x81 }, { 196, 0x12 },
{ 195, 0x83 }, { 196, 0x17 },
}, bbp_high_temp_bw40[] = {
{ 69, 0x15 },
{ 91, 0x04 },
{ 195, 0x23 }, { 196, 0x12 },
{ 195, 0x24 }, { 196, 0x08 },
{ 195, 0x81 }, { 196, 0x15 },
{ 195, 0x83 }, { 196, 0x16 },
}, bbp_low_temp[] = {
{ 178, 0xff }, /* For CCK CH14 OBW */
}, bbp_low_temp_bw20[] = {
{ 69, 0x12 },
{ 75, 0x5e },
{ 91, 0x07 },
{ 92, 0x02 },
{ 195, 0x23 }, { 196, 0x17 },
{ 195, 0x24 }, { 196, 0x06 },
{ 195, 0x81 }, { 196, 0x12 },
{ 195, 0x83 }, { 196, 0x17 },
{ 195, 0x88 }, { 196, 0x5e },
}, bbp_low_temp_bw40[] = {
{ 69, 0x15 },
{ 75, 0x5c },
{ 91, 0x04 },
{ 92, 0x03 },
{ 195, 0x23 }, { 196, 0x10 },
{ 195, 0x24 }, { 196, 0x08 },
{ 195, 0x81 }, { 196, 0x15 },
{ 195, 0x83 }, { 196, 0x16 },
{ 195, 0x88 }, { 196, 0x5b },
}, bbp_normal_temp[] = {
{ 75, 0x60 },
{ 92, 0x02 },
{ 178, 0xff }, /* For CCK CH14 OBW */
{ 195, 0x88 }, { 196, 0x60 },
}, bbp_normal_temp_bw20[] = {
{ 69, 0x12 },
{ 91, 0x07 },
{ 195, 0x23 }, { 196, 0x17 },
{ 195, 0x24 }, { 196, 0x06 },
{ 195, 0x81 }, { 196, 0x12 },
{ 195, 0x83 }, { 196, 0x17 },
}, bbp_normal_temp_bw40[] = {
{ 69, 0x15 },
{ 91, 0x04 },
{ 195, 0x23 }, { 196, 0x12 },
{ 195, 0x24 }, { 196, 0x08 },
{ 195, 0x81 }, { 196, 0x15 },
{ 195, 0x83 }, { 196, 0x16 },
};
#define BBP_TABLE(arr) { arr, ARRAY_SIZE(arr), }
static const struct reg_table {
const struct mt76_reg_pair *regs;
size_t n;
} bbp_mode_table[3][3] = {
{
BBP_TABLE(bbp_normal_temp_bw20),
BBP_TABLE(bbp_normal_temp_bw40),
BBP_TABLE(bbp_normal_temp),
}, {
BBP_TABLE(bbp_high_temp_bw20),
BBP_TABLE(bbp_high_temp_bw40),
BBP_TABLE(bbp_high_temp),
}, {
BBP_TABLE(bbp_low_temp_bw20),
BBP_TABLE(bbp_low_temp_bw40),
BBP_TABLE(bbp_low_temp),
}
};
#endif
This diff is collapsed.
/*
* Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __MT76_MAC_H
#define __MT76_MAC_H
struct mt76_tx_status {
u8 valid:1;
u8 success:1;
u8 aggr:1;
u8 ack_req:1;
u8 is_probe:1;
u8 wcid;
u8 pktid;
u8 retry;
u16 rate;
} __packed __aligned(2);
/* Note: values in original "RSSI" and "SNR" fields are not actually what they
* are called for MT7601U, names used by this driver are educated guesses
* (see vendor mac/ral_omac.c).
*/
struct mt7601u_rxwi {
__le32 rxinfo;
__le32 ctl;
__le16 frag_sn;
__le16 rate;
u8 unknown;
u8 zero[3];
u8 snr;
u8 ant;
u8 gain;
u8 freq_off;
__le32 resv2;
__le32 expert_ant;
} __packed __aligned(4);
#define MT_RXINFO_BA BIT(0)
#define MT_RXINFO_DATA BIT(1)
#define MT_RXINFO_NULL BIT(2)
#define MT_RXINFO_FRAG BIT(3)
#define MT_RXINFO_U2M BIT(4)
#define MT_RXINFO_MULTICAST BIT(5)
#define MT_RXINFO_BROADCAST BIT(6)
#define MT_RXINFO_MYBSS BIT(7)
#define MT_RXINFO_CRCERR BIT(8)
#define MT_RXINFO_ICVERR BIT(9)
#define MT_RXINFO_MICERR BIT(10)
#define MT_RXINFO_AMSDU BIT(11)
#define MT_RXINFO_HTC BIT(12)
#define MT_RXINFO_RSSI BIT(13)
#define MT_RXINFO_L2PAD BIT(14)
#define MT_RXINFO_AMPDU BIT(15)
#define MT_RXINFO_DECRYPT BIT(16)
#define MT_RXINFO_BSSIDX3 BIT(17)
#define MT_RXINFO_WAPI_KEY BIT(18)
#define MT_RXINFO_PN_LEN GENMASK(21, 19)
#define MT_RXINFO_SW_PKT_80211 BIT(22)
#define MT_RXINFO_TCP_SUM_BYPASS BIT(28)
#define MT_RXINFO_IP_SUM_BYPASS BIT(29)
#define MT_RXINFO_TCP_SUM_ERR BIT(30)
#define MT_RXINFO_IP_SUM_ERR BIT(31)
#define MT_RXWI_CTL_WCID GENMASK(7, 0)
#define MT_RXWI_CTL_KEY_IDX GENMASK(9, 8)
#define MT_RXWI_CTL_BSS_IDX GENMASK(12, 10)
#define MT_RXWI_CTL_UDF GENMASK(15, 13)
#define MT_RXWI_CTL_MPDU_LEN GENMASK(27, 16)
#define MT_RXWI_CTL_TID GENMASK(31, 28)
#define MT_RXWI_FRAG GENMASK(3, 0)
#define MT_RXWI_SN GENMASK(15, 4)
#define MT_RXWI_RATE_MCS GENMASK(6, 0)
#define MT_RXWI_RATE_BW BIT(7)
#define MT_RXWI_RATE_SGI BIT(8)
#define MT_RXWI_RATE_STBC GENMASK(10, 9)
#define MT_RXWI_RATE_ETXBF BIT(11)
#define MT_RXWI_RATE_SND BIT(12)
#define MT_RXWI_RATE_ITXBF BIT(13)
#define MT_RXWI_RATE_PHY GENMASK(15, 14)
#define MT_RXWI_GAIN_RSSI_VAL GENMASK(5, 0)
#define MT_RXWI_GAIN_RSSI_LNA_ID GENMASK(7, 6)
#define MT_RXWI_ANT_AUX_LNA BIT(7)
#define MT_RXWI_EANT_ENC_ANT_ID GENMASK(7, 0)
enum mt76_phy_type {
MT_PHY_TYPE_CCK,
MT_PHY_TYPE_OFDM,
MT_PHY_TYPE_HT,
MT_PHY_TYPE_HT_GF,
};
enum mt76_phy_bandwidth {
MT_PHY_BW_20,
MT_PHY_BW_40,
};
struct mt76_txwi {
__le16 flags;
__le16 rate_ctl;
u8 ack_ctl;
u8 wcid;
__le16 len_ctl;
__le32 iv;
__le32 eiv;
u8 aid;
u8 txstream;
__le16 ctl;
} __packed __aligned(4);
#define MT_TXWI_FLAGS_FRAG BIT(0)
#define MT_TXWI_FLAGS_MMPS BIT(1)
#define MT_TXWI_FLAGS_CFACK BIT(2)
#define MT_TXWI_FLAGS_TS BIT(3)
#define MT_TXWI_FLAGS_AMPDU BIT(4)
#define MT_TXWI_FLAGS_MPDU_DENSITY GENMASK(7, 5)
#define MT_TXWI_FLAGS_TXOP GENMASK(9, 8)
#define MT_TXWI_FLAGS_CWMIN GENMASK(12, 10)
#define MT_TXWI_FLAGS_NO_RATE_FALLBACK BIT(13)
#define MT_TXWI_FLAGS_TX_RPT BIT(14)
#define MT_TXWI_FLAGS_TX_RATE_LUT BIT(15)
#define MT_TXWI_RATE_MCS GENMASK(6, 0)
#define MT_TXWI_RATE_BW BIT(7)
#define MT_TXWI_RATE_SGI BIT(8)
#define MT_TXWI_RATE_STBC GENMASK(10, 9)
#define MT_TXWI_RATE_PHY_MODE GENMASK(15, 14)
#define MT_TXWI_ACK_CTL_REQ BIT(0)
#define MT_TXWI_ACK_CTL_NSEQ BIT(1)
#define MT_TXWI_ACK_CTL_BA_WINDOW GENMASK(7, 2)
#define MT_TXWI_LEN_BYTE_CNT GENMASK(11, 0)
#define MT_TXWI_LEN_PKTID GENMASK(15, 12)
#define MT_TXWI_CTL_TX_POWER_ADJ GENMASK(3, 0)
#define MT_TXWI_CTL_CHAN_CHECK_PKT BIT(4)
#define MT_TXWI_CTL_PIFS_REV BIT(6)
u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb,
u8 *data, void *rxi);
int mt76_mac_wcid_set_key(struct mt7601u_dev *dev, u8 idx,
struct ieee80211_key_conf *key);
void mt76_mac_wcid_set_rate(struct mt7601u_dev *dev, struct mt76_wcid *wcid,
const struct ieee80211_tx_rate *rate);
int mt76_mac_shared_key_setup(struct mt7601u_dev *dev, u8 vif_idx, u8 key_idx,
struct ieee80211_key_conf *key);
u16 mt76_mac_tx_rate_val(struct mt7601u_dev *dev,
const struct ieee80211_tx_rate *rate, u8 *nss_val);
struct mt76_tx_status
mt7601u_mac_fetch_tx_status(struct mt7601u_dev *dev);
void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat);
#endif
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __MT7601U_MCU_H
#define __MT7601U_MCU_H
struct mt7601u_dev;
/* Register definitions */
#define MT_MCU_RESET_CTL 0x070C
#define MT_MCU_INT_LEVEL 0x0718
#define MT_MCU_COM_REG0 0x0730
#define MT_MCU_COM_REG1 0x0734
#define MT_MCU_COM_REG2 0x0738
#define MT_MCU_COM_REG3 0x073C
#define MT_MCU_IVB_SIZE 0x40
#define MT_MCU_DLM_OFFSET 0x80000
#define MT_MCU_MEMMAP_WLAN 0x00410000
#define MT_MCU_MEMMAP_BBP 0x40000000
#define MT_MCU_MEMMAP_RF 0x80000000
#define INBAND_PACKET_MAX_LEN 192
enum mcu_cmd {
CMD_FUN_SET_OP = 1,
CMD_LOAD_CR = 2,
CMD_INIT_GAIN_OP = 3,
CMD_DYNC_VGA_OP = 6,
CMD_TDLS_CH_SW = 7,
CMD_BURST_WRITE = 8,
CMD_READ_MODIFY_WRITE = 9,
CMD_RANDOM_READ = 10,
CMD_BURST_READ = 11,
CMD_RANDOM_WRITE = 12,
CMD_LED_MODE_OP = 16,
CMD_POWER_SAVING_OP = 20,
CMD_WOW_CONFIG = 21,
CMD_WOW_QUERY = 22,
CMD_WOW_FEATURE = 24,
CMD_CARRIER_DETECT_OP = 28,
CMD_RADOR_DETECT_OP = 29,
CMD_SWITCH_CHANNEL_OP = 30,
CMD_CALIBRATION_OP = 31,
CMD_BEACON_OP = 32,
CMD_ANTENNA_OP = 33,
};
enum mcu_function {
Q_SELECT = 1,
ATOMIC_TSSI_SETTING = 5,
};
enum mcu_power_mode {
RADIO_OFF = 0x30,
RADIO_ON = 0x31,
RADIO_OFF_AUTO_WAKEUP = 0x32,
RADIO_OFF_ADVANCE = 0x33,
RADIO_ON_ADVANCE = 0x34,
};
enum mcu_calibrate {
MCU_CAL_R = 1,
MCU_CAL_DCOC,
MCU_CAL_LC,
MCU_CAL_LOFT,
MCU_CAL_TXIQ,
MCU_CAL_BW,
MCU_CAL_DPD,
MCU_CAL_RXIQ,
MCU_CAL_TXDCOC,
};
int mt7601u_mcu_init(struct mt7601u_dev *dev);
int mt7601u_mcu_cmd_init(struct mt7601u_dev *dev);
void mt7601u_mcu_cmd_deinit(struct mt7601u_dev *dev);
int
mt7601u_mcu_calibrate(struct mt7601u_dev *dev, enum mcu_calibrate cal, u32 val);
int mt7601u_mcu_tssi_read_kick(struct mt7601u_dev *dev, int use_hvga);
#endif
/*
* Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef MT7601U_H
#define MT7601U_H
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/usb.h>
#include <linux/completion.h>
#include <net/mac80211.h>
#include <linux/debugfs.h>
#include "regs.h"
#include "util.h"
#define MT_CALIBRATE_INTERVAL (4 * HZ)
#define MT_FREQ_CAL_INIT_DELAY (30 * HZ)
#define MT_FREQ_CAL_CHECK_INTERVAL (10 * HZ)
#define MT_FREQ_CAL_ADJ_INTERVAL (HZ / 2)
#define MT_BBP_REG_VERSION 0x00
#define MT_USB_AGGR_SIZE_LIMIT 28 /* * 1024B */
#define MT_USB_AGGR_TIMEOUT 0x80 /* * 33ns */
#define MT_RX_ORDER 3
#define MT_RX_URB_SIZE (PAGE_SIZE << MT_RX_ORDER)
struct mt7601u_dma_buf {
struct urb *urb;
void *buf;
dma_addr_t dma;
size_t len;
};
struct mt7601u_mcu {
struct mutex mutex;
u8 msg_seq;
struct mt7601u_dma_buf resp;
struct completion resp_cmpl;
};
struct mt7601u_freq_cal {
struct delayed_work work;
u8 freq;
bool enabled;
bool adjusting;
};
struct mac_stats {
u64 rx_stat[6];
u64 tx_stat[6];
u64 aggr_stat[2];
u64 aggr_n[32];
u64 zero_len_del[2];
};
#define N_RX_ENTRIES 16
struct mt7601u_rx_queue {
struct mt7601u_dev *dev;
struct mt7601u_dma_buf_rx {
struct urb *urb;
struct page *p;
} e[N_RX_ENTRIES];
unsigned int start;
unsigned int end;
unsigned int entries;
unsigned int pending;
};
#define N_TX_ENTRIES 64
struct mt7601u_tx_queue {
struct mt7601u_dev *dev;
struct mt7601u_dma_buf_tx {
struct urb *urb;
struct sk_buff *skb;
} e[N_TX_ENTRIES];
unsigned int start;
unsigned int end;
unsigned int entries;
unsigned int used;
unsigned int fifo_seq;
};
/* WCID allocation:
* 0: mcast wcid
* 1: bssid wcid
* 1...: STAs
* ...7e: group wcids
* 7f: reserved
*/
#define N_WCIDS 128
#define GROUP_WCID(idx) (N_WCIDS - 2 - idx)
struct mt7601u_eeprom_params;
#define MT_EE_TEMPERATURE_SLOPE 39
#define MT_FREQ_OFFSET_INVALID -128
enum mt_temp_mode {
MT_TEMP_MODE_NORMAL,
MT_TEMP_MODE_HIGH,
MT_TEMP_MODE_LOW,
};
enum mt_bw {
MT_BW_20,
MT_BW_40,
};
enum {
MT7601U_STATE_INITIALIZED,
MT7601U_STATE_REMOVED,
MT7601U_STATE_WLAN_RUNNING,
MT7601U_STATE_MCU_RUNNING,
MT7601U_STATE_SCANNING,
MT7601U_STATE_READING_STATS,
MT7601U_STATE_MORE_STATS,
};
/**
* struct mt7601u_dev - adapter structure
* @lock: protects @wcid->tx_rate.
* @tx_lock: protects @tx_q and changes of MT7601U_STATE_*_STATS
flags in @state.
* @rx_lock: protects @rx_q.
* @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi.
* @mutex: ensures exclusive access from mac80211 callbacks.
* @vendor_req_mutex: ensures atomicity of vendor requests.
* @reg_atomic_mutex: ensures atomicity of indirect register accesses
* (accesses to RF and BBP).
* @hw_atomic_mutex: ensures exclusive access to HW during critical
* operations (power management, channel switch).
*/
struct mt7601u_dev {
struct ieee80211_hw *hw;
struct device *dev;
unsigned long state;
struct mutex mutex;
unsigned long wcid_mask[N_WCIDS / BITS_PER_LONG];
struct cfg80211_chan_def chandef;
struct ieee80211_supported_band *sband_2g;
struct mt7601u_mcu mcu;
struct delayed_work cal_work;
struct delayed_work mac_work;
struct workqueue_struct *stat_wq;
struct delayed_work stat_work;
struct mt76_wcid *mon_wcid;
struct mt76_wcid __rcu *wcid[N_WCIDS];
spinlock_t lock;
const u16 *beacon_offsets;
u8 macaddr[ETH_ALEN];
struct mt7601u_eeprom_params *ee;
struct mutex vendor_req_mutex;
struct mutex reg_atomic_mutex;
struct mutex hw_atomic_mutex;
u32 rxfilter;
u32 debugfs_reg;
u8 out_eps[8];
u8 in_eps[8];
u16 out_max_packet;
u16 in_max_packet;
/* TX */
spinlock_t tx_lock;
struct mt7601u_tx_queue *tx_q;
atomic_t avg_ampdu_len;
/* RX */
spinlock_t rx_lock;
struct tasklet_struct rx_tasklet;
struct mt7601u_rx_queue rx_q;
/* Connection monitoring things */
spinlock_t con_mon_lock;
u8 ap_bssid[ETH_ALEN];
s8 bcn_freq_off;
u8 bcn_phy_mode;
int avg_rssi; /* starts at 0 and converges */
u8 agc_save;
struct mt7601u_freq_cal freq_cal;
bool tssi_read_trig;
s8 tssi_init;
s8 tssi_init_hvga;
s16 tssi_init_hvga_offset_db;
int prev_pwr_diff;
enum mt_temp_mode temp_mode;
int curr_temp;
int dpd_temp;
s8 raw_temp;
bool pll_lock_protect;
u8 bw;
bool chan_ext_below;
/* PA mode */
u32 rf_pa_mode[2];
struct mac_stats stats;
};
struct mt7601u_tssi_params {
char tssi0;
int trgt_power;
};
struct mt76_wcid {
u8 idx;
u8 hw_key_idx;
u16 tx_rate;
bool tx_rate_set;
u8 tx_rate_nss;
};
struct mt76_vif {
u8 idx;
struct mt76_wcid group_wcid;
};
struct mt76_sta {
struct mt76_wcid wcid;
u16 agg_ssn[IEEE80211_NUM_TIDS];
};
struct mt76_reg_pair {
u32 reg;
u32 value;
};
struct mt7601u_rxwi;
extern const struct ieee80211_ops mt7601u_ops;
void mt7601u_init_debugfs(struct mt7601u_dev *dev);
u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset);
void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val);
u32 mt7601u_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val);
u32 mt7601u_rmc(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val);
void mt7601u_wr_copy(struct mt7601u_dev *dev, u32 offset,
const void *data, int len);
int mt7601u_wait_asic_ready(struct mt7601u_dev *dev);
bool mt76_poll(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val,
int timeout);
bool mt76_poll_msec(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val,
int timeout);
/* Compatibility with mt76 */
#define mt76_rmw_field(_dev, _reg, _field, _val) \
mt76_rmw(_dev, _reg, _field, MT76_SET(_field, _val))
static inline u32 mt76_rr(struct mt7601u_dev *dev, u32 offset)
{
return mt7601u_rr(dev, offset);
}
static inline void mt76_wr(struct mt7601u_dev *dev, u32 offset, u32 val)
{
return mt7601u_wr(dev, offset, val);
}
static inline u32
mt76_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val)
{
return mt7601u_rmw(dev, offset, mask, val);
}
static inline u32 mt76_set(struct mt7601u_dev *dev, u32 offset, u32 val)
{
return mt76_rmw(dev, offset, 0, val);
}
static inline u32 mt76_clear(struct mt7601u_dev *dev, u32 offset, u32 val)
{
return mt76_rmw(dev, offset, val, 0);
}
int mt7601u_write_reg_pairs(struct mt7601u_dev *dev, u32 base,
const struct mt76_reg_pair *data, int len);
int mt7601u_burst_write_regs(struct mt7601u_dev *dev, u32 offset,
const u32 *data, int n);
void mt7601u_addr_wr(struct mt7601u_dev *dev, const u32 offset, const u8 *addr);
/* Init */
struct mt7601u_dev *mt7601u_alloc_device(struct device *dev);
int mt7601u_init_hardware(struct mt7601u_dev *dev);
int mt7601u_register_device(struct mt7601u_dev *dev);
void mt7601u_cleanup(struct mt7601u_dev *dev);
int mt7601u_mac_start(struct mt7601u_dev *dev);
void mt7601u_mac_stop(struct mt7601u_dev *dev);
/* PHY */
int mt7601u_phy_init(struct mt7601u_dev *dev);
int mt7601u_wait_bbp_ready(struct mt7601u_dev *dev);
void mt7601u_set_rx_path(struct mt7601u_dev *dev, u8 path);
void mt7601u_set_tx_dac(struct mt7601u_dev *dev, u8 path);
int mt7601u_bbp_set_bw(struct mt7601u_dev *dev, int bw);
void mt7601u_agc_save(struct mt7601u_dev *dev);
void mt7601u_agc_restore(struct mt7601u_dev *dev);
int mt7601u_phy_set_channel(struct mt7601u_dev *dev,
struct cfg80211_chan_def *chandef);
void mt7601u_phy_recalibrate_after_assoc(struct mt7601u_dev *dev);
int mt7601u_phy_get_rssi(struct mt7601u_dev *dev,
struct mt7601u_rxwi *rxwi, u16 rate);
void mt7601u_phy_con_cal_onoff(struct mt7601u_dev *dev,
struct ieee80211_bss_conf *info);
/* MAC */
void mt7601u_mac_work(struct work_struct *work);
void mt7601u_mac_set_protection(struct mt7601u_dev *dev, bool legacy_prot,
int ht_mode);
void mt7601u_mac_set_short_preamble(struct mt7601u_dev *dev, bool short_preamb);
void mt7601u_mac_config_tsf(struct mt7601u_dev *dev, bool enable, int interval);
void
mt7601u_mac_wcid_setup(struct mt7601u_dev *dev, u8 idx, u8 vif_idx, u8 *mac);
void mt7601u_mac_set_ampdu_factor(struct mt7601u_dev *dev);
/* TX */
void mt7601u_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
struct sk_buff *skb);
int mt7601u_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u16 queue, const struct ieee80211_tx_queue_params *params);
void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb);
void mt7601u_tx_stat(struct work_struct *work);
/* util */
void mt76_remove_hdr_pad(struct sk_buff *skb);
int mt76_insert_hdr_pad(struct sk_buff *skb);
u32 mt7601u_bbp_set_ctrlch(struct mt7601u_dev *dev, bool below);
static inline u32 mt7601u_mac_set_ctrlch(struct mt7601u_dev *dev, bool below)
{
return mt7601u_rmc(dev, MT_TX_BAND_CFG, 1, below);
}
int mt7601u_dma_init(struct mt7601u_dev *dev);
void mt7601u_dma_cleanup(struct mt7601u_dev *dev);
int mt7601u_dma_enqueue_tx(struct mt7601u_dev *dev, struct sk_buff *skb,
struct mt76_wcid *wcid, int hw_q);
#endif
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/module.h>
#ifndef __CHECKER__
#define CREATE_TRACE_POINTS
#include "trace.h"
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __MT7601U_USB_H
#define __MT7601U_USB_H
#include "mt7601u.h"
#define MT7601U_FIRMWARE "mt7601u.bin"
#define MT_VEND_REQ_MAX_RETRY 10
#define MT_VEND_REQ_TOUT_MS 300
#define MT_VEND_DEV_MODE_RESET 1
enum mt_vendor_req {
MT_VEND_DEV_MODE = 1,
MT_VEND_WRITE = 2,
MT_VEND_MULTI_READ = 7,
MT_VEND_WRITE_FCE = 0x42,
};
enum mt_usb_ep_in {
MT_EP_IN_PKT_RX,
MT_EP_IN_CMD_RESP,
__MT_EP_IN_MAX,
};
enum mt_usb_ep_out {
MT_EP_OUT_INBAND_CMD,
MT_EP_OUT_AC_BK,
MT_EP_OUT_AC_BE,
MT_EP_OUT_AC_VI,
MT_EP_OUT_AC_VO,
MT_EP_OUT_HCCA,
__MT_EP_OUT_MAX,
};
static inline struct usb_device *mt7601u_to_usb_dev(struct mt7601u_dev *mt7601u)
{
return interface_to_usbdev(to_usb_interface(mt7601u->dev));
}
static inline bool mt7601u_urb_has_error(struct urb *urb)
{
return urb->status &&
urb->status != -ENOENT &&
urb->status != -ECONNRESET &&
urb->status != -ESHUTDOWN;
}
bool mt7601u_usb_alloc_buf(struct mt7601u_dev *dev, size_t len,
struct mt7601u_dma_buf *buf);
void mt7601u_usb_free_buf(struct mt7601u_dev *dev, struct mt7601u_dma_buf *buf);
int mt7601u_usb_submit_buf(struct mt7601u_dev *dev, int dir, int ep_idx,
struct mt7601u_dma_buf *buf, gfp_t gfp,
usb_complete_t complete_fn, void *context);
void mt7601u_complete_urb(struct urb *urb);
int mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req,
const u8 direction, const u16 val, const u16 offset,
void *buf, const size_t buflen);
void mt7601u_vendor_reset(struct mt7601u_dev *dev);
int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req,
const u16 offset, const u32 val);
#endif
/*
* Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "mt7601u.h"
void mt76_remove_hdr_pad(struct sk_buff *skb)
{
int len = ieee80211_get_hdrlen_from_skb(skb);
memmove(skb->data + 2, skb->data, len);
skb_pull(skb, 2);
}
int mt76_insert_hdr_pad(struct sk_buff *skb)
{
int len = ieee80211_get_hdrlen_from_skb(skb);
int ret;
if (len % 4 == 0)
return 0;
ret = skb_cow(skb, 2);
if (ret)
return ret;
skb_push(skb, 2);
memmove(skb->data, skb->data + 2, len);
skb->data[len] = 0;
skb->data[len + 1] = 0;
return 0;
}
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