Commit 9434dca9 authored by Kalle Valo's avatar Kalle Valo

Merge tag 'mt76-for-kvalo-2018-10-01' of https://github.com/nbd168/wireless

mt76 patches for 4.20

* unify code between mt76x0, mt76x2
* mt76x0 fixes
* tx power configuration fix for 76x2
* more progress on mt76x0e support
* support for getting firmware version via ethtool
* fix for rx buffer allocation regression on usb
* fix for handling powersave responses
* fix for mt76x2 beacon transmission
parents 09afaba1 5289976a
...@@ -15,7 +15,8 @@ mt76-usb-y := usb.o usb_trace.o usb_mcu.o ...@@ -15,7 +15,8 @@ mt76-usb-y := usb.o usb_trace.o usb_mcu.o
CFLAGS_trace.o := -I$(src) CFLAGS_trace.o := -I$(src)
CFLAGS_usb_trace.o := -I$(src) CFLAGS_usb_trace.o := -I$(src)
mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \
mt76x02_eeprom.o mt76x02_phy.o mt76x02_mmio.o
mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
......
...@@ -56,6 +56,35 @@ mt76_queues_read(struct seq_file *s, void *data) ...@@ -56,6 +56,35 @@ mt76_queues_read(struct seq_file *s, void *data)
return 0; return 0;
} }
void mt76_seq_puts_array(struct seq_file *file, const char *str,
s8 *val, int len)
{
int i;
seq_printf(file, "%10s:", str);
for (i = 0; i < len; i++)
seq_printf(file, " %2d", val[i]);
seq_puts(file, "\n");
}
EXPORT_SYMBOL_GPL(mt76_seq_puts_array);
static int mt76_read_rate_txpower(struct seq_file *s, void *data)
{
struct mt76_dev *dev = dev_get_drvdata(s->private);
mt76_seq_puts_array(s, "CCK", dev->rate_power.cck,
ARRAY_SIZE(dev->rate_power.cck));
mt76_seq_puts_array(s, "OFDM", dev->rate_power.ofdm,
ARRAY_SIZE(dev->rate_power.ofdm));
mt76_seq_puts_array(s, "STBC", dev->rate_power.stbc,
ARRAY_SIZE(dev->rate_power.stbc));
mt76_seq_puts_array(s, "HT", dev->rate_power.ht,
ARRAY_SIZE(dev->rate_power.ht));
mt76_seq_puts_array(s, "VHT", dev->rate_power.vht,
ARRAY_SIZE(dev->rate_power.vht));
return 0;
}
struct dentry *mt76_register_debugfs(struct mt76_dev *dev) struct dentry *mt76_register_debugfs(struct mt76_dev *dev)
{ {
struct dentry *dir; struct dentry *dir;
...@@ -72,6 +101,8 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev) ...@@ -72,6 +101,8 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev)
if (dev->otp.data) if (dev->otp.data)
debugfs_create_blob("otp", 0400, dir, &dev->otp); debugfs_create_blob("otp", 0400, dir, &dev->otp);
debugfs_create_devm_seqfile(dev->dev, "queues", dir, mt76_queues_read); debugfs_create_devm_seqfile(dev->dev, "queues", dir, mt76_queues_read);
debugfs_create_devm_seqfile(dev->dev, "rate_txpower", dir,
mt76_read_rate_txpower);
return dir; return dir;
} }
......
...@@ -550,6 +550,12 @@ mt76_check_ps(struct mt76_dev *dev, struct sk_buff *skb) ...@@ -550,6 +550,12 @@ mt76_check_ps(struct mt76_dev *dev, struct sk_buff *skb)
struct mt76_wcid *wcid = status->wcid; struct mt76_wcid *wcid = status->wcid;
bool ps; bool ps;
if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) {
sta = ieee80211_find_sta_by_ifaddr(dev->hw, hdr->addr2, NULL);
if (sta)
wcid = status->wcid = (struct mt76_wcid *) sta->drv_priv;
}
if (!wcid || !wcid->sta) if (!wcid || !wcid->sta)
return; return;
......
...@@ -46,6 +46,30 @@ static void mt76_mmio_copy(struct mt76_dev *dev, u32 offset, const void *data, ...@@ -46,6 +46,30 @@ static void mt76_mmio_copy(struct mt76_dev *dev, u32 offset, const void *data,
__iowrite32_copy(dev->mmio.regs + offset, data, len >> 2); __iowrite32_copy(dev->mmio.regs + offset, data, len >> 2);
} }
static int mt76_mmio_wr_rp(struct mt76_dev *dev, u32 base,
const struct mt76_reg_pair *data, int len)
{
while (len > 0) {
mt76_mmio_wr(dev, data->reg, data->value);
data++;
len--;
}
return 0;
}
static int mt76_mmio_rd_rp(struct mt76_dev *dev, u32 base,
struct mt76_reg_pair *data, int len)
{
while (len > 0) {
data->value = mt76_mmio_rr(dev, data->reg);
data++;
len--;
}
return 0;
}
void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs)
{ {
static const struct mt76_bus_ops mt76_mmio_ops = { static const struct mt76_bus_ops mt76_mmio_ops = {
...@@ -53,6 +77,8 @@ void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) ...@@ -53,6 +77,8 @@ void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs)
.rmw = mt76_mmio_rmw, .rmw = mt76_mmio_rmw,
.wr = mt76_mmio_wr, .wr = mt76_mmio_wr,
.copy = mt76_mmio_copy, .copy = mt76_mmio_copy,
.wr_rp = mt76_mmio_wr_rp,
.rd_rp = mt76_mmio_rd_rp,
}; };
dev->bus = &mt76_mmio_ops; dev->bus = &mt76_mmio_ops;
...@@ -60,6 +86,7 @@ void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) ...@@ -60,6 +86,7 @@ void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs)
skb_queue_head_init(&dev->mmio.mcu.res_q); skb_queue_head_init(&dev->mmio.mcu.res_q);
init_waitqueue_head(&dev->mmio.mcu.wait); init_waitqueue_head(&dev->mmio.mcu.wait);
spin_lock_init(&dev->mmio.irq_lock);
mutex_init(&dev->mmio.mcu.mutex); mutex_init(&dev->mmio.mcu.mutex);
} }
EXPORT_SYMBOL_GPL(mt76_mmio_init); EXPORT_SYMBOL_GPL(mt76_mmio_init);
...@@ -122,6 +122,7 @@ struct mt76_queue { ...@@ -122,6 +122,7 @@ struct mt76_queue {
dma_addr_t desc_dma; dma_addr_t desc_dma;
struct sk_buff *rx_head; struct sk_buff *rx_head;
struct page_frag_cache rx_page; struct page_frag_cache rx_page;
spinlock_t rx_page_lock;
}; };
struct mt76_mcu_ops { struct mt76_mcu_ops {
...@@ -275,6 +276,19 @@ struct mt76_sband { ...@@ -275,6 +276,19 @@ struct mt76_sband {
struct mt76_channel_state *chan; struct mt76_channel_state *chan;
}; };
struct mt76_rate_power {
union {
struct {
s8 cck[4];
s8 ofdm[8];
s8 stbc[10];
s8 ht[16];
s8 vht[10];
};
s8 all[48];
};
};
/* addr req mask */ /* addr req mask */
#define MT_VEND_TYPE_EEPROM BIT(31) #define MT_VEND_TYPE_EEPROM BIT(31)
#define MT_VEND_TYPE_CFG BIT(30) #define MT_VEND_TYPE_CFG BIT(30)
...@@ -349,6 +363,8 @@ struct mt76_mmio { ...@@ -349,6 +363,8 @@ struct mt76_mmio {
u32 msg_seq; u32 msg_seq;
} mcu; } mcu;
void __iomem *regs; void __iomem *regs;
spinlock_t irq_lock;
u32 irqmask;
}; };
struct mt76_dev { struct mt76_dev {
...@@ -388,6 +404,7 @@ struct mt76_dev { ...@@ -388,6 +404,7 @@ struct mt76_dev {
unsigned long state; unsigned long state;
u8 antenna_mask; u8 antenna_mask;
u16 chainmask;
struct mt76_sband sband_2g; struct mt76_sband sband_2g;
struct mt76_sband sband_5g; struct mt76_sband sband_5g;
...@@ -395,6 +412,10 @@ struct mt76_dev { ...@@ -395,6 +412,10 @@ struct mt76_dev {
struct debugfs_blob_wrapper otp; struct debugfs_blob_wrapper otp;
struct mt76_hw_cap cap; struct mt76_hw_cap cap;
struct mt76_rate_power rate_power;
int txpower_conf;
int txpower_cur;
u32 debugfs_reg; u32 debugfs_reg;
struct led_classdev led_cdev; struct led_classdev led_cdev;
...@@ -418,18 +439,6 @@ enum mt76_phy_type { ...@@ -418,18 +439,6 @@ enum mt76_phy_type {
MT_PHY_TYPE_VHT, MT_PHY_TYPE_VHT,
}; };
struct mt76_rate_power {
union {
struct {
s8 cck[4];
s8 ofdm[8];
s8 ht[16];
s8 vht[10];
};
s8 all[38];
};
};
struct mt76_rx_status { struct mt76_rx_status {
struct mt76_wcid *wcid; struct mt76_wcid *wcid;
...@@ -510,8 +519,8 @@ static inline u16 mt76_rev(struct mt76_dev *dev) ...@@ -510,8 +519,8 @@ static inline u16 mt76_rev(struct mt76_dev *dev)
#define mt76xx_chip(dev) mt76_chip(&((dev)->mt76)) #define mt76xx_chip(dev) mt76_chip(&((dev)->mt76))
#define mt76xx_rev(dev) mt76_rev(&((dev)->mt76)) #define mt76xx_rev(dev) mt76_rev(&((dev)->mt76))
#define mt76_init_queues(dev) (dev)->mt76.queue_ops->init(&((dev)->mt76)) #define __mt76_init_queues(dev) (dev)->queue_ops->init((dev))
#define mt76_queue_alloc(dev, ...) (dev)->mt76.queue_ops->alloc(&((dev)->mt76), __VA_ARGS__) #define __mt76_queue_alloc(dev, ...) (dev)->queue_ops->alloc((dev), __VA_ARGS__)
#define mt76_queue_add_buf(dev, ...) (dev)->mt76.queue_ops->add_buf(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_add_buf(dev, ...) (dev)->mt76.queue_ops->add_buf(&((dev)->mt76), __VA_ARGS__)
#define mt76_queue_rx_reset(dev, ...) (dev)->mt76.queue_ops->rx_reset(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_rx_reset(dev, ...) (dev)->mt76.queue_ops->rx_reset(&((dev)->mt76), __VA_ARGS__)
#define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__)
...@@ -539,6 +548,8 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, ...@@ -539,6 +548,8 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
void mt76_unregister_device(struct mt76_dev *dev); void mt76_unregister_device(struct mt76_dev *dev);
struct dentry *mt76_register_debugfs(struct mt76_dev *dev); struct dentry *mt76_register_debugfs(struct mt76_dev *dev);
void mt76_seq_puts_array(struct seq_file *file, const char *str,
s8 *val, int len);
int mt76_eeprom_init(struct mt76_dev *dev, int len); int mt76_eeprom_init(struct mt76_dev *dev, int len);
void mt76_eeprom_override(struct mt76_dev *dev); void mt76_eeprom_override(struct mt76_dev *dev);
......
...@@ -5,8 +5,8 @@ obj-$(CONFIG_MT76x0_COMMON) += mt76x0-common.o ...@@ -5,8 +5,8 @@ obj-$(CONFIG_MT76x0_COMMON) += mt76x0-common.o
mt76x0-common-y := \ mt76x0-common-y := \
init.o main.o trace.o eeprom.o phy.o \ init.o main.o trace.o eeprom.o phy.o \
mac.o debugfs.o tx.o mac.o debugfs.o tx.o
mt76x0u-y := usb.o mt76x0u-y := usb.o usb_mcu.o
mt76x0e-y := pci.o mt76x0e-y := pci.o pci_mcu.o
# ccflags-y := -DDEBUG # ccflags-y := -DDEBUG
CFLAGS_trace.o := -I$(src) CFLAGS_trace.o := -I$(src)
...@@ -18,26 +18,6 @@ ...@@ -18,26 +18,6 @@
#include "mt76x0.h" #include "mt76x0.h"
#include "eeprom.h" #include "eeprom.h"
static int
mt76_reg_set(void *data, u64 val)
{
struct mt76x0_dev *dev = data;
mt76_wr(dev, dev->debugfs_reg, val);
return 0;
}
static int
mt76_reg_get(void *data, u64 *val)
{
struct mt76x0_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 static int
mt76x0_ampdu_stat_read(struct seq_file *file, void *data) mt76x0_ampdu_stat_read(struct seq_file *file, void *data)
{ {
...@@ -95,72 +75,13 @@ static const struct file_operations fops_ampdu_stat = { ...@@ -95,72 +75,13 @@ static const struct file_operations fops_ampdu_stat = {
.release = single_release, .release = single_release,
}; };
static int
mt76x0_eeprom_param_read(struct seq_file *file, void *data)
{
struct mt76x0_dev *dev = file->private;
int i;
seq_printf(file, "RF freq offset: %hhx\n", dev->ee->rf_freq_off);
seq_printf(file, "RSSI offset 2GHz: %hhx %hhx\n",
dev->ee->rssi_offset_2ghz[0], dev->ee->rssi_offset_2ghz[1]);
seq_printf(file, "RSSI offset 5GHz: %hhx %hhx %hhx\n",
dev->ee->rssi_offset_5ghz[0], dev->ee->rssi_offset_5ghz[1],
dev->ee->rssi_offset_5ghz[2]);
seq_printf(file, "Temperature offset: %hhx\n", dev->ee->temp_off);
seq_printf(file, "LNA gain 2Ghz: %hhx\n", dev->ee->lna_gain_2ghz);
seq_printf(file, "LNA gain 5Ghz: %hhx %hhx %hhx\n",
dev->ee->lna_gain_5ghz[0], dev->ee->lna_gain_5ghz[1],
dev->ee->lna_gain_5ghz[2]);
seq_printf(file, "Power Amplifier type %hhx\n", dev->ee->pa_type);
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 channel power:\n");
for (i = 0; i < 58; i++)
seq_printf(file, "\t%d chan:%d pwr:%d\n", i, i,
dev->ee->tx_pwr_per_chan[i]);
seq_puts(file, "Per rate power 2GHz:\n");
for (i = 0; i < 5; i++)
seq_printf(file, "\t %d bw20:%d bw40:%d\n",
i, dev->ee->tx_pwr_cfg_2g[i][0],
dev->ee->tx_pwr_cfg_5g[i][1]);
seq_puts(file, "Per rate power 5GHz:\n");
for (i = 0; i < 5; i++)
seq_printf(file, "\t %d bw20:%d bw40:%d\n",
i, dev->ee->tx_pwr_cfg_5g[i][0],
dev->ee->tx_pwr_cfg_5g[i][1]);
return 0;
}
static int
mt76x0_eeprom_param_open(struct inode *inode, struct file *f)
{
return single_open(f, mt76x0_eeprom_param_read, inode->i_private);
}
static const struct file_operations fops_eeprom_param = {
.open = mt76x0_eeprom_param_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
void mt76x0_init_debugfs(struct mt76x0_dev *dev) void mt76x0_init_debugfs(struct mt76x0_dev *dev)
{ {
struct dentry *dir; struct dentry *dir;
dir = debugfs_create_dir("mt76x0", dev->mt76.hw->wiphy->debugfsdir); dir = mt76_register_debugfs(&dev->mt76);
if (!dir) if (!dir)
return; return;
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("ampdu_stat", S_IRUSR, dir, dev, &fops_ampdu_stat);
debugfs_create_file("eeprom_param", S_IRUSR, dir, dev,
&fops_eeprom_param);
} }
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
...@@ -20,66 +21,7 @@ ...@@ -20,66 +21,7 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include "mt76x0.h" #include "mt76x0.h"
#include "eeprom.h" #include "eeprom.h"
#include "../mt76x02_phy.h"
static bool
field_valid(u8 val)
{
return val != 0xff;
}
static s8
field_validate(u8 val)
{
if (!field_valid(val))
return 0;
return val;
}
static inline int
sign_extend(u32 val, unsigned int size)
{
bool sign = val & BIT(size - 1);
val &= BIT(size - 1) - 1;
return sign ? val : -val;
}
static int
mt76x0_efuse_read(struct mt76x0_dev *dev, u16 addr, u8 *data,
enum mt76x0_eeprom_access_modes mode)
{
u32 val;
int i;
val = mt76_rr(dev, MT_EFUSE_CTRL);
val &= ~(MT_EFUSE_CTRL_AIN |
MT_EFUSE_CTRL_MODE);
val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf) |
FIELD_PREP(MT_EFUSE_CTRL_MODE, mode) |
MT_EFUSE_CTRL_KICK;
mt76_wr(dev, MT_EFUSE_CTRL, val);
if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
return -ETIMEDOUT;
val = mt76_rr(dev, MT_EFUSE_CTRL);
if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) {
/* Parts of eeprom not in the usage map (0x80-0xc0,0xf0)
* will not return valid data but it's ok.
*/
memset(data, 0xff, 16);
return 0;
}
for (i = 0; i < 4; i++) {
val = mt76_rr(dev, MT_EFUSE_DATA(i));
put_unaligned_le32(val, data + 4 * i);
}
return 0;
}
#define MT_MAP_READS DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16) #define MT_MAP_READS DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16)
static int static int
...@@ -89,12 +31,10 @@ mt76x0_efuse_physical_size_check(struct mt76x0_dev *dev) ...@@ -89,12 +31,10 @@ mt76x0_efuse_physical_size_check(struct mt76x0_dev *dev)
int ret, i; int ret, i;
u32 start = 0, end = 0, cnt_free; u32 start = 0, end = 0, cnt_free;
for (i = 0; i < MT_MAP_READS; i++) { ret = mt76x02_get_efuse_data(&dev->mt76, MT_EE_USAGE_MAP_START,
ret = mt76x0_efuse_read(dev, MT_EE_USAGE_MAP_START + i * 16, data, sizeof(data), MT_EE_PHYSICAL_READ);
data + i * 16, MT_EE_PHYSICAL_READ); if (ret)
if (ret) return ret;
return ret;
}
for (i = 0; i < MT_EFUSE_USAGE_MAP_SIZE; i++) for (i = 0; i < MT_EFUSE_USAGE_MAP_SIZE; i++)
if (!data[i]) { if (!data[i]) {
...@@ -105,345 +45,307 @@ mt76x0_efuse_physical_size_check(struct mt76x0_dev *dev) ...@@ -105,345 +45,307 @@ mt76x0_efuse_physical_size_check(struct mt76x0_dev *dev)
cnt_free = end - start + 1; cnt_free = end - start + 1;
if (MT_EFUSE_USAGE_MAP_SIZE - cnt_free < 5) { if (MT_EFUSE_USAGE_MAP_SIZE - cnt_free < 5) {
dev_err(dev->mt76.dev, "Error: your device needs default EEPROM file and this driver doesn't support it!\n"); dev_err(dev->mt76.dev,
"driver does not support default EEPROM\n");
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
} }
static void static void mt76x0_set_chip_cap(struct mt76x0_dev *dev)
mt76x0_set_chip_cap(struct mt76x0_dev *dev, u8 *eeprom)
{ {
enum mt76x2_board_type { BOARD_TYPE_2GHZ = 1, BOARD_TYPE_5GHZ = 2 }; u16 nic_conf0 = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0);
u16 nic_conf0 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_0); u16 nic_conf1 = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_1);
u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1);
dev_dbg(dev->mt76.dev, "NIC_CONF0: %04x NIC_CONF1: %04x\n", nic_conf0, nic_conf1);
switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, nic_conf0)) {
case BOARD_TYPE_5GHZ:
dev->mt76.cap.has_5ghz = true;
break;
case BOARD_TYPE_2GHZ:
dev->mt76.cap.has_2ghz = true;
break;
default:
dev->mt76.cap.has_2ghz = true;
dev->mt76.cap.has_5ghz = true;
break;
}
dev_dbg(dev->mt76.dev, "Has 2GHZ %d 5GHZ %d\n", mt76x02_eeprom_parse_hw_cap(&dev->mt76);
dev_dbg(dev->mt76.dev, "2GHz %d 5GHz %d\n",
dev->mt76.cap.has_2ghz, dev->mt76.cap.has_5ghz); dev->mt76.cap.has_2ghz, dev->mt76.cap.has_5ghz);
if (!field_valid(nic_conf1 & 0xff)) if (dev->no_2ghz) {
dev->mt76.cap.has_2ghz = false;
dev_dbg(dev->mt76.dev, "mask out 2GHz support\n");
}
if (!mt76x02_field_valid(nic_conf1 & 0xff))
nic_conf1 &= 0xff00; nic_conf1 &= 0xff00;
if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL) if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL)
dev_err(dev->mt76.dev, dev_err(dev->mt76.dev,
"Error: this driver does not support HW RF ctrl\n"); "driver does not support HW RF ctrl\n");
if (!field_valid(nic_conf0 >> 8)) if (!mt76x02_field_valid(nic_conf0 >> 8))
return; return;
if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 || if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 ||
FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1) FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1)
dev_err(dev->mt76.dev, dev_err(dev->mt76.dev, "invalid tx-rx stream\n");
"Error: device has more than 1 RX/TX stream!\n");
dev->ee->pa_type = FIELD_GET(MT_EE_NIC_CONF_0_PA_TYPE, nic_conf0);
dev_dbg(dev->mt76.dev, "PA Type %d\n", dev->ee->pa_type);
} }
static int static void mt76x0_set_temp_offset(struct mt76x0_dev *dev)
mt76x0_set_macaddr(struct mt76x0_dev *dev, const u8 *eeprom)
{ {
const void *src = eeprom + MT_EE_MAC_ADDR; u8 val;
u8 *dst = dev->mt76.macaddr;
ether_addr_copy(dev->mt76.macaddr, src);
if (!is_valid_ether_addr(dst)) { val = mt76x02_eeprom_get(&dev->mt76, MT_EE_2G_TARGET_POWER) >> 8;
eth_random_addr(dst); if (mt76x02_field_valid(val))
dev_info(dev->mt76.dev, dev->caldata.temp_offset = mt76x02_sign_extend(val, 8);
"Invalid MAC address, using random address %pM\n",
dst);
}
mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dst));
mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dst + 4) |
FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
return 0;
}
static void
mt76x0_set_temp_offset(struct mt76x0_dev *dev, u8 *eeprom)
{
u8 temp = eeprom[MT_EE_TEMP_OFFSET];
if (field_valid(temp))
dev->ee->temp_off = sign_extend(temp, 8);
else else
dev->ee->temp_off = -10; dev->caldata.temp_offset = -10;
} }
static void static void mt76x0_set_freq_offset(struct mt76x0_dev *dev)
mt76x0_set_country_reg(struct mt76x0_dev *dev, u8 *eeprom)
{ {
/* Note: - region 31 is not valid for mt76x0 (see rtmp_init.c) struct mt76x0_caldata *caldata = &dev->caldata;
* - comments in rtmp_def.h are incorrect (see rt_channel.c) u8 val;
*/
static const struct reg_channel_bounds chan_bounds[] = {
/* EEPROM country regions 0 - 7 */
{ 1, 11 }, { 1, 13 }, { 10, 2 }, { 10, 4 },
{ 14, 1 }, { 1, 14 }, { 3, 7 }, { 5, 9 },
/* EEPROM country regions 32 - 33 */
{ 1, 11 }, { 1, 14 }
};
u8 val = eeprom[MT_EE_COUNTRY_REGION_2GHZ];
int idx = -1;
dev_dbg(dev->mt76.dev, "REG 2GHZ %u REG 5GHZ %u\n", val, eeprom[MT_EE_COUNTRY_REGION_5GHZ]);
if (val < 8)
idx = val;
if (val > 31 && val < 33)
idx = val - 32 + 8;
if (idx != -1)
dev_info(dev->mt76.dev,
"EEPROM country region %02hhx (channels %hhd-%hhd)\n",
val, chan_bounds[idx].start,
chan_bounds[idx].start + chan_bounds[idx].num - 1);
else
idx = 5; /* channels 1 - 14 */
dev->ee->reg = chan_bounds[idx];
/* TODO: country region 33 is special - phy should be set to B-mode
* before entering channel 14 (see sta/connect.c)
*/
}
static void val = mt76x02_eeprom_get(&dev->mt76, MT_EE_FREQ_OFFSET);
mt76x0_set_rf_freq_off(struct mt76x0_dev *dev, u8 *eeprom) if (!mt76x02_field_valid(val))
{ val = 0;
u8 comp; caldata->freq_offset = val;
dev->ee->rf_freq_off = field_validate(eeprom[MT_EE_FREQ_OFFSET]); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TSSI_BOUND4) >> 8;
comp = field_validate(eeprom[MT_EE_FREQ_OFFSET_COMPENSATION]); if (!mt76x02_field_valid(val))
val = 0;
if (comp & BIT(7)) caldata->freq_offset -= mt76x02_sign_extend(val, 8);
dev->ee->rf_freq_off -= comp & 0x7f;
else
dev->ee->rf_freq_off += comp;
} }
static void void mt76x0_read_rx_gain(struct mt76x0_dev *dev)
mt76x0_set_lna_gain(struct mt76x0_dev *dev, u8 *eeprom)
{ {
u8 gain; struct ieee80211_channel *chan = dev->mt76.chandef.chan;
struct mt76x0_caldata *caldata = &dev->caldata;
s8 val, lna_5g[3], lna_2g;
u16 rssi_offset;
int i;
dev->ee->lna_gain_2ghz = eeprom[MT_EE_LNA_GAIN_2GHZ]; mt76x02_get_rx_gain(&dev->mt76, chan->band, &rssi_offset,
dev->ee->lna_gain_5ghz[0] = eeprom[MT_EE_LNA_GAIN_5GHZ_0]; &lna_2g, lna_5g);
caldata->lna_gain = mt76x02_get_lna_gain(&dev->mt76, &lna_2g,
lna_5g, chan);
gain = eeprom[MT_EE_LNA_GAIN_5GHZ_1]; for (i = 0; i < ARRAY_SIZE(caldata->rssi_offset); i++) {
if (gain == 0xff || gain == 0) val = rssi_offset >> (8 * i);
dev->ee->lna_gain_5ghz[1] = dev->ee->lna_gain_5ghz[0]; if (val < -10 || val > 10)
else val = 0;
dev->ee->lna_gain_5ghz[1] = gain;
gain = eeprom[MT_EE_LNA_GAIN_5GHZ_2]; caldata->rssi_offset[i] = val;
if (gain == 0xff || gain == 0) }
dev->ee->lna_gain_5ghz[2] = dev->ee->lna_gain_5ghz[0];
else
dev->ee->lna_gain_5ghz[2] = gain;
} }
static void static s8 mt76x0_get_delta(struct mt76_dev *dev)
mt76x0_set_rssi_offset(struct mt76x0_dev *dev, u8 *eeprom)
{ {
int i; struct cfg80211_chan_def *chandef = &dev->chandef;
s8 *rssi_offset = dev->ee->rssi_offset_2ghz; u8 val;
for (i = 0; i < 2; i++) { if (mt76x02_tssi_enabled(dev))
rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET + i]; return 0;
if (rssi_offset[i] < -10 || rssi_offset[i] > 10) {
dev_warn(dev->mt76.dev,
"Warning: EEPROM RSSI is invalid %02hhx\n",
rssi_offset[i]);
rssi_offset[i] = 0;
}
}
rssi_offset = dev->ee->rssi_offset_5ghz;
for (i = 0; i < 3; i++) { if (chandef->width == NL80211_CHAN_WIDTH_80) {
rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET_5GHZ + i]; val = mt76x02_eeprom_get(dev, MT_EE_5G_TARGET_POWER) >> 8;
} else if (chandef->width == NL80211_CHAN_WIDTH_40) {
u16 data;
if (rssi_offset[i] < -10 || rssi_offset[i] > 10) { data = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40);
dev_warn(dev->mt76.dev, if (chandef->chan->band == NL80211_BAND_5GHZ)
"Warning: EEPROM RSSI is invalid %02hhx\n", val = data >> 8;
rssi_offset[i]); else
rssi_offset[i] = 0; val = data;
} } else {
return 0;
} }
return mt76x02_rate_power_val(val);
} }
static u32 void mt76x0_get_tx_power_per_rate(struct mt76x0_dev *dev)
calc_bw40_power_rate(u32 value, int delta)
{ {
u32 ret = 0; struct ieee80211_channel *chan = dev->mt76.chandef.chan;
int i, tmp; bool is_2ghz = chan->band == NL80211_BAND_2GHZ;
struct mt76_rate_power *t = &dev->mt76.rate_power;
for (i = 0; i < 4; i++) { s8 delta = mt76x0_get_delta(&dev->mt76);
tmp = s6_to_int((value >> i*8) & 0xff) + delta; u16 val, addr;
ret |= (u32)(int_to_s6(tmp)) << i*8;
} memset(t, 0, sizeof(*t));
return ret; /* cck 1M, 2M, 5.5M, 11M */
val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_BYRATE_BASE);
t->cck[0] = t->cck[1] = s6_to_s8(val);
t->cck[2] = t->cck[3] = s6_to_s8(val >> 8);
/* ofdm 6M, 9M, 12M, 18M */
addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 2 : 0x120;
val = mt76x02_eeprom_get(&dev->mt76, addr);
t->ofdm[0] = t->ofdm[1] = s6_to_s8(val);
t->ofdm[2] = t->ofdm[3] = s6_to_s8(val >> 8);
/* ofdm 24M, 36M, 48M, 54M */
addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 4 : 0x122;
val = mt76x02_eeprom_get(&dev->mt76, addr);
t->ofdm[4] = t->ofdm[5] = s6_to_s8(val);
t->ofdm[6] = t->ofdm[7] = s6_to_s8(val >> 8);
/* ht-vht mcs 1ss 0, 1, 2, 3 */
addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 6 : 0x124;
val = mt76x02_eeprom_get(&dev->mt76, addr);
t->ht[0] = t->ht[1] = t->vht[0] = t->vht[1] = s6_to_s8(val);
t->ht[2] = t->ht[3] = t->vht[2] = t->vht[3] = s6_to_s8(val >> 8);
/* ht-vht mcs 1ss 4, 5, 6 */
addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 8 : 0x126;
val = mt76x02_eeprom_get(&dev->mt76, addr);
t->ht[4] = t->ht[5] = t->vht[4] = t->vht[5] = s6_to_s8(val);
t->ht[6] = t->vht[6] = s6_to_s8(val >> 8);
/* ht-vht mcs 1ss 0, 1, 2, 3 stbc */
addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 14 : 0xec;
val = mt76x02_eeprom_get(&dev->mt76, addr);
t->stbc[0] = t->stbc[1] = s6_to_s8(val);
t->stbc[2] = t->stbc[3] = s6_to_s8(val >> 8);
/* ht-vht mcs 1ss 4, 5, 6 stbc */
addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 16 : 0xee;
val = mt76x02_eeprom_get(&dev->mt76, addr);
t->stbc[4] = t->stbc[5] = s6_to_s8(val);
t->stbc[6] = t->stbc[7] = s6_to_s8(val >> 8);
/* vht mcs 8, 9 5GHz */
val = mt76x02_eeprom_get(&dev->mt76, 0x132);
t->vht[7] = s6_to_s8(val);
t->vht[8] = s6_to_s8(val >> 8);
mt76x02_add_rate_power_offset(t, delta);
} }
static s8 void mt76x0_get_power_info(struct mt76x0_dev *dev, u8 *info)
get_delta(u8 val)
{ {
s8 ret; struct mt76x0_chan_map {
u8 chan;
u8 offset;
} chan_map[] = {
{ 2, 0 }, { 4, 1 }, { 6, 2 }, { 8, 3 },
{ 10, 4 }, { 12, 5 }, { 14, 6 }, { 38, 0 },
{ 44, 1 }, { 48, 2 }, { 54, 3 }, { 60, 4 },
{ 64, 5 }, { 102, 6 }, { 108, 7 }, { 112, 8 },
{ 118, 9 }, { 124, 10 }, { 128, 11 }, { 134, 12 },
{ 140, 13 }, { 151, 14 }, { 157, 15 }, { 161, 16 },
{ 167, 17 }, { 171, 18 }, { 173, 19 },
};
struct ieee80211_channel *chan = dev->mt76.chandef.chan;
u8 offset, addr;
u16 data;
int i;
if (!field_valid(val) || !(val & BIT(7))) for (i = 0; i < ARRAY_SIZE(chan_map); i++) {
return 0; if (chan_map[i].chan <= chan->hw_value) {
offset = chan_map[i].offset;
break;
}
}
if (i == ARRAY_SIZE(chan_map))
offset = chan_map[0].offset;
if (chan->band == NL80211_BAND_2GHZ) {
addr = MT_EE_TX_POWER_DELTA_BW80 + offset;
} else {
switch (chan->hw_value) {
case 58:
offset = 8;
break;
case 106:
offset = 14;
break;
case 112:
offset = 20;
break;
case 155:
offset = 30;
break;
default:
break;
}
addr = MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE + 2 + offset;
}
data = mt76x02_eeprom_get(&dev->mt76, addr);
ret = val & 0x1f; info[0] = data;
if (ret > 8) if (!info[0] || info[0] > 0x3f)
ret = 8; info[0] = 5;
if (val & BIT(6))
ret = -ret;
return ret; info[1] = data >> 8;
if (!info[1] || info[1] > 0x3f)
info[1] = 5;
} }
static void static int mt76x0_check_eeprom(struct mt76x0_dev *dev)
mt76x0_set_tx_power_per_rate(struct mt76x0_dev *dev, u8 *eeprom)
{ {
s8 bw40_delta_2g, bw40_delta_5g; u16 val;
u32 val;
int i;
bw40_delta_2g = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40]);
bw40_delta_5g = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40 + 1]);
for (i = 0; i < 5; i++) { val = get_unaligned_le16(dev->mt76.eeprom.data);
val = get_unaligned_le32(eeprom + MT_EE_TX_POWER_BYRATE(i)); if (!val)
val = get_unaligned_le16(dev->mt76.eeprom.data +
MT_EE_PCI_ID);
/* Skip last 16 bits. */ switch (val) {
if (i == 4) case 0x7650:
val &= 0x0000ffff; case 0x7610:
return 0;
dev->ee->tx_pwr_cfg_2g[i][0] = val; default:
dev->ee->tx_pwr_cfg_2g[i][1] = calc_bw40_power_rate(val, bw40_delta_2g); dev_err(dev->mt76.dev, "EEPROM data check failed: %04x\n",
val);
return -EINVAL;
} }
/* Reading per rate tx power for 5 GHz band is a bit more complex. Note
* we mix 16 bit and 32 bit reads and sometimes do shifts.
*/
val = get_unaligned_le16(eeprom + 0x120);
val <<= 16;
dev->ee->tx_pwr_cfg_5g[0][0] = val;
dev->ee->tx_pwr_cfg_5g[0][1] = calc_bw40_power_rate(val, bw40_delta_5g);
val = get_unaligned_le32(eeprom + 0x122);
dev->ee->tx_pwr_cfg_5g[1][0] = val;
dev->ee->tx_pwr_cfg_5g[1][1] = calc_bw40_power_rate(val, bw40_delta_5g);
val = get_unaligned_le16(eeprom + 0x126);
dev->ee->tx_pwr_cfg_5g[2][0] = val;
dev->ee->tx_pwr_cfg_5g[2][1] = calc_bw40_power_rate(val, bw40_delta_5g);
val = get_unaligned_le16(eeprom + 0xec);
val <<= 16;
dev->ee->tx_pwr_cfg_5g[3][0] = val;
dev->ee->tx_pwr_cfg_5g[3][1] = calc_bw40_power_rate(val, bw40_delta_5g);
val = get_unaligned_le16(eeprom + 0xee);
dev->ee->tx_pwr_cfg_5g[4][0] = val;
dev->ee->tx_pwr_cfg_5g[4][1] = calc_bw40_power_rate(val, bw40_delta_5g);
} }
static void static int mt76x0_load_eeprom(struct mt76x0_dev *dev)
mt76x0_set_tx_power_per_chan(struct mt76x0_dev *dev, u8 *eeprom)
{ {
int i; int found;
u8 tx_pwr;
for (i = 0; i < 14; i++) { found = mt76_eeprom_init(&dev->mt76, MT76X0_EEPROM_SIZE);
tx_pwr = eeprom[MT_EE_TX_POWER_OFFSET_2GHZ + i]; if (found < 0)
if (tx_pwr <= 0x3f && tx_pwr > 0) return found;
dev->ee->tx_pwr_per_chan[i] = tx_pwr;
else
dev->ee->tx_pwr_per_chan[i] = 5;
}
for (i = 0; i < 40; i++) { if (found && !mt76x0_check_eeprom(dev))
tx_pwr = eeprom[MT_EE_TX_POWER_OFFSET_5GHZ + i]; return 0;
if (tx_pwr <= 0x3f && tx_pwr > 0)
dev->ee->tx_pwr_per_chan[14 + i] = tx_pwr; found = mt76x0_efuse_physical_size_check(dev);
else if (found < 0)
dev->ee->tx_pwr_per_chan[14 + i] = 5; return found;
}
dev->ee->tx_pwr_per_chan[54] = dev->ee->tx_pwr_per_chan[22]; return mt76x02_get_efuse_data(&dev->mt76, 0, dev->mt76.eeprom.data,
dev->ee->tx_pwr_per_chan[55] = dev->ee->tx_pwr_per_chan[28]; MT76X0_EEPROM_SIZE, MT_EE_READ);
dev->ee->tx_pwr_per_chan[56] = dev->ee->tx_pwr_per_chan[34];
dev->ee->tx_pwr_per_chan[57] = dev->ee->tx_pwr_per_chan[44];
} }
int int mt76x0_eeprom_init(struct mt76x0_dev *dev)
mt76x0_eeprom_init(struct mt76x0_dev *dev)
{ {
u8 *eeprom; u8 version, fae;
int i, ret; u16 data;
int err;
ret = mt76x0_efuse_physical_size_check(dev);
if (ret)
return ret;
dev->ee = devm_kzalloc(dev->mt76.dev, sizeof(*dev->ee), GFP_KERNEL); err = mt76x0_load_eeprom(dev);
if (!dev->ee) if (err < 0)
return -ENOMEM; return err;
eeprom = kmalloc(MT76X0_EEPROM_SIZE, GFP_KERNEL); data = mt76x02_eeprom_get(&dev->mt76, MT_EE_VERSION);
if (!eeprom) version = data >> 8;
return -ENOMEM; fae = data;
for (i = 0; i + 16 <= MT76X0_EEPROM_SIZE; i += 16) { if (version > MT76X0U_EE_MAX_VER)
ret = mt76x0_efuse_read(dev, i, eeprom + i, MT_EE_READ);
if (ret)
goto out;
}
if (eeprom[MT_EE_VERSION_EE] > MT76X0U_EE_MAX_VER)
dev_warn(dev->mt76.dev, dev_warn(dev->mt76.dev,
"Warning: unsupported EEPROM version %02hhx\n", "Warning: unsupported EEPROM version %02hhx\n",
eeprom[MT_EE_VERSION_EE]); version);
dev_info(dev->mt76.dev, "EEPROM ver:%02hhx fae:%02hhx\n", dev_info(dev->mt76.dev, "EEPROM ver:%02hhx fae:%02hhx\n",
eeprom[MT_EE_VERSION_EE], eeprom[MT_EE_VERSION_FAE]); version, fae);
mt76x0_set_macaddr(dev, eeprom); mt76x02_mac_setaddr(&dev->mt76,
mt76x0_set_chip_cap(dev, eeprom); dev->mt76.eeprom.data + MT_EE_MAC_ADDR);
mt76x0_set_country_reg(dev, eeprom); mt76x0_set_chip_cap(dev);
mt76x0_set_rf_freq_off(dev, eeprom); mt76x0_set_freq_offset(dev);
mt76x0_set_temp_offset(dev, eeprom); mt76x0_set_temp_offset(dev);
mt76x0_set_lna_gain(dev, eeprom);
mt76x0_set_rssi_offset(dev, eeprom); dev->mt76.chainmask = 0x0101;
dev->chainmask = 0x0101;
return 0;
mt76x0_set_tx_power_per_rate(dev, eeprom);
mt76x0_set_tx_power_per_chan(dev, eeprom);
out:
kfree(eeprom);
return ret;
} }
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
...@@ -16,131 +16,33 @@ ...@@ -16,131 +16,33 @@
#ifndef __MT76X0U_EEPROM_H #ifndef __MT76X0U_EEPROM_H
#define __MT76X0U_EEPROM_H #define __MT76X0U_EEPROM_H
struct mt76x0_dev; #include "../mt76x02_eeprom.h"
#define MT76X0U_EE_MAX_VER 0x0c
#define MT76X0_EEPROM_SIZE 512
#define MT76X0U_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_5GHZ = 0x38,
MT_EE_COUNTRY_REGION_2GHZ = 0x39,
MT_EE_FREQ_OFFSET = 0x3a,
MT_EE_NIC_CONF_2 = 0x42,
MT_EE_LNA_GAIN_2GHZ = 0x44,
MT_EE_LNA_GAIN_5GHZ_0 = 0x45,
MT_EE_RSSI_OFFSET = 0x46,
MT_EE_RSSI_OFFSET_5GHZ = 0x4a,
MT_EE_LNA_GAIN_5GHZ_1 = 0x49,
MT_EE_LNA_GAIN_5GHZ_2 = 0x4d,
MT_EE_TX_POWER_DELTA_BW40 = 0x50,
MT_EE_TX_POWER_OFFSET_2GHZ = 0x52,
MT_EE_TX_TSSI_SLOPE = 0x6e,
MT_EE_TX_TSSI_OFFSET_GROUP = 0x6f,
MT_EE_TX_TSSI_OFFSET = 0x76,
MT_EE_TX_POWER_OFFSET_5GHZ = 0x78,
MT_EE_TEMP_OFFSET = 0xd1,
MT_EE_FREQ_OFFSET_COMPENSATION = 0xdb,
MT_EE_TX_POWER_BYRATE_BASE = 0xde,
MT_EE_TX_POWER_BYRATE_BASE_5GHZ = 0x120,
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_PA_TYPE GENMASK(9, 8)
#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 + \ struct mt76x0_dev;
(i) * 4)
#define MT_EFUSE_USAGE_MAP_SIZE (MT_EE_USAGE_MAP_END - \
MT_EE_USAGE_MAP_START + 1)
enum mt76x0_eeprom_access_modes {
MT_EE_READ = 0,
MT_EE_PHYSICAL_READ = 1,
};
struct reg_channel_bounds {
u8 start;
u8 num;
};
struct mt76x0_eeprom_params {
u8 rf_freq_off;
s16 temp_off;
s8 rssi_offset_2ghz[2];
s8 rssi_offset_5ghz[3];
s8 lna_gain_2ghz;
s8 lna_gain_5ghz[3];
u8 pa_type;
/* TX_PWR_CFG_* values from EEPROM for 20 and 40 Mhz bandwidths. */ #define MT76X0U_EE_MAX_VER 0x0c
u32 tx_pwr_cfg_2g[5][2]; #define MT76X0_EEPROM_SIZE 512
u32 tx_pwr_cfg_5g[5][2];
u8 tx_pwr_per_chan[58]; struct mt76x0_caldata {
s8 rssi_offset[2];
s8 lna_gain;
struct reg_channel_bounds reg; s16 temp_offset;
u8 freq_offset;
}; };
int mt76x0_eeprom_init(struct mt76x0_dev *dev); int mt76x0_eeprom_init(struct mt76x0_dev *dev);
void mt76x0_read_rx_gain(struct mt76x0_dev *dev);
void mt76x0_get_tx_power_per_rate(struct mt76x0_dev *dev);
void mt76x0_get_power_info(struct mt76x0_dev *dev, u8 *info);
static inline u32 s6_validate(u32 reg) static inline s8 s6_to_s8(u32 val)
{
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) s8 ret = val & GENMASK(5, 0);
return 0x20;
if (val > 0x1f)
return 0x1f;
return val & 0x3f; if (ret & BIT(5))
ret -= BIT(6);
return ret;
} }
#endif #endif
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "trace.h" #include "trace.h"
#include "mcu.h" #include "mcu.h"
#include "../mt76x02_util.h" #include "../mt76x02_util.h"
#include "../mt76x02_dma.h"
#include "initvals.h" #include "initvals.h"
...@@ -43,7 +44,7 @@ static void mt76x0_vht_cap_mask(struct ieee80211_supported_band *sband) ...@@ -43,7 +44,7 @@ static void mt76x0_vht_cap_mask(struct ieee80211_supported_band *sband)
static void static void
mt76x0_set_wlan_state(struct mt76x0_dev *dev, u32 val, bool enable) mt76x0_set_wlan_state(struct mt76x0_dev *dev, u32 val, bool enable)
{ {
int i; u32 mask = MT_CMB_CTRL_XTAL_RDY | MT_CMB_CTRL_PLL_LD;
/* Note: we don't turn off WLAN_CLK because that makes the device /* Note: we don't turn off WLAN_CLK because that makes the device
* not respond properly on the probe path. * not respond properly on the probe path.
...@@ -60,24 +61,12 @@ mt76x0_set_wlan_state(struct mt76x0_dev *dev, u32 val, bool enable) ...@@ -60,24 +61,12 @@ mt76x0_set_wlan_state(struct mt76x0_dev *dev, u32 val, bool enable)
mt76_wr(dev, MT_WLAN_FUN_CTRL, val); mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
udelay(20); udelay(20);
if (!enable)
return;
for (i = 200; i; i--) {
val = mt76_rr(dev, MT_CMB_CTRL);
if (val & MT_CMB_CTRL_XTAL_RDY && val & MT_CMB_CTRL_PLL_LD)
break;
udelay(20);
}
/* Note: vendor driver tries to disable/enable wlan here and retry /* Note: vendor driver tries to disable/enable wlan here and retry
* but the code which does it is so buggy it must have never * but the code which does it is so buggy it must have never
* triggered, so don't bother. * triggered, so don't bother.
*/ */
if (!i) if (enable && !mt76_poll(dev, MT_CMB_CTRL, mask, mask, 2000))
dev_err(dev->mt76.dev, "Error: PLL and XTAL check failed!\n"); dev_err(dev->mt76.dev, "PLL and XTAL check failed\n");
} }
void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset) void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset)
...@@ -114,43 +103,13 @@ EXPORT_SYMBOL_GPL(mt76x0_chip_onoff); ...@@ -114,43 +103,13 @@ EXPORT_SYMBOL_GPL(mt76x0_chip_onoff);
static void mt76x0_reset_csr_bbp(struct mt76x0_dev *dev) static void mt76x0_reset_csr_bbp(struct mt76x0_dev *dev)
{ {
u32 val; mt76_wr(dev, MT_MAC_SYS_CTRL,
MT_MAC_SYS_CTRL_RESET_CSR |
val = mt76_rr(dev, MT_PBF_SYS_CTRL); MT_MAC_SYS_CTRL_RESET_BBP);
val &= ~0x2000;
mt76_wr(dev, MT_PBF_SYS_CTRL, val);
mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR |
MT_MAC_SYS_CTRL_RESET_BBP);
msleep(200); msleep(200);
} mt76_clear(dev, MT_MAC_SYS_CTRL,
MT_MAC_SYS_CTRL_RESET_CSR |
static void mt76x0_init_usb_dma(struct mt76x0_dev *dev) MT_MAC_SYS_CTRL_RESET_BBP);
{
u32 val;
val = mt76_rr(dev, MT_USB_DMA_CFG);
val |= MT_USB_DMA_CFG_RX_BULK_EN |
MT_USB_DMA_CFG_TX_BULK_EN;
/* disable AGGR_BULK_RX in order to receive one
* frame in each rx urb and avoid copies
*/
val &= ~MT_USB_DMA_CFG_RX_BULK_AGG_EN;
mt76_wr(dev, MT_USB_DMA_CFG, val);
val = mt76_rr(dev, MT_COM_REG0);
if (val & 1)
dev_dbg(dev->mt76.dev, "MCU not ready\n");
val = mt76_rr(dev, MT_USB_DMA_CFG);
val |= MT_USB_DMA_CFG_RX_DROP_OR_PAD;
mt76_wr(dev, MT_USB_DMA_CFG, val);
val &= ~MT_USB_DMA_CFG_RX_DROP_OR_PAD;
mt76_wr(dev, MT_USB_DMA_CFG, val);
} }
#define RANDOM_WRITE(dev, tab) \ #define RANDOM_WRITE(dev, tab) \
...@@ -180,30 +139,13 @@ static int mt76x0_init_bbp(struct mt76x0_dev *dev) ...@@ -180,30 +139,13 @@ static int mt76x0_init_bbp(struct mt76x0_dev *dev)
return 0; return 0;
} }
static void
mt76_init_beacon_offsets(struct mt76x0_dev *dev)
{
u16 base = MT_BEACON_BASE;
u32 regs[4] = {};
int i;
for (i = 0; i < 16; i++) {
u16 addr = dev->beacon_offsets[i];
regs[i / 4] |= ((addr - base) / 64) << (8 * (i % 4));
}
for (i = 0; i < 4; i++)
mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]);
}
static void mt76x0_init_mac_registers(struct mt76x0_dev *dev) static void mt76x0_init_mac_registers(struct mt76x0_dev *dev)
{ {
u32 reg; u32 reg;
RANDOM_WRITE(dev, common_mac_reg_table); RANDOM_WRITE(dev, common_mac_reg_table);
mt76_init_beacon_offsets(dev); mt76x02_set_beacon_offsets(&dev->mt76);
/* Enable PBF and MAC clock SYS_CTRL[11:10] = 0x3 */ /* Enable PBF and MAC clock SYS_CTRL[11:10] = 0x3 */
RANDOM_WRITE(dev, mt76x0_mac_reg_table); RANDOM_WRITE(dev, mt76x0_mac_reg_table);
...@@ -213,13 +155,6 @@ static void mt76x0_init_mac_registers(struct mt76x0_dev *dev) ...@@ -213,13 +155,6 @@ static void mt76x0_init_mac_registers(struct mt76x0_dev *dev)
reg &= ~0x3; reg &= ~0x3;
mt76_wr(dev, MT_MAC_SYS_CTRL, reg); mt76_wr(dev, MT_MAC_SYS_CTRL, reg);
if (is_mt7610e(dev)) {
/* Disable COEX_EN */
reg = mt76_rr(dev, MT_COEXCFG0);
reg &= 0xFFFFFFFE;
mt76_wr(dev, MT_COEXCFG0, reg);
}
/* Set 0x141C[15:12]=0xF */ /* Set 0x141C[15:12]=0xF */
reg = mt76_rr(dev, MT_EXT_CCA_CFG); reg = mt76_rr(dev, MT_EXT_CCA_CFG);
reg |= 0x0000F000; reg |= 0x0000F000;
...@@ -302,45 +237,22 @@ int mt76x0_mac_start(struct mt76x0_dev *dev) ...@@ -302,45 +237,22 @@ int mt76x0_mac_start(struct mt76x0_dev *dev)
{ {
mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000))
MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 200000))
return -ETIMEDOUT; return -ETIMEDOUT;
dev->mt76.rxfilter = MT_RX_FILTR_CFG_CRC_ERR |
MT_RX_FILTR_CFG_PHY_ERR | MT_RX_FILTR_CFG_PROMISC |
MT_RX_FILTR_CFG_VER_ERR | MT_RX_FILTR_CFG_DUP |
MT_RX_FILTR_CFG_CFACK | MT_RX_FILTR_CFG_CFEND |
MT_RX_FILTR_CFG_ACK | MT_RX_FILTR_CFG_CTS |
MT_RX_FILTR_CFG_RTS | MT_RX_FILTR_CFG_PSPOLL |
MT_RX_FILTR_CFG_BA | MT_RX_FILTR_CFG_CTRL_RSV;
mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
mt76_wr(dev, MT_MAC_SYS_CTRL, mt76_wr(dev, MT_MAC_SYS_CTRL,
MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | return !mt76x02_wait_for_wpdma(&dev->mt76, 50) ? -ETIMEDOUT : 0;
MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 50))
return -ETIMEDOUT;
return 0;
} }
EXPORT_SYMBOL_GPL(mt76x0_mac_start);
static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev) void mt76x0_mac_stop(struct mt76x0_dev *dev)
{ {
int i, ok; int i = 200, ok = 0;
if (test_bit(MT76_REMOVED, &dev->mt76.state))
return;
mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN |
MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN |
MT_BEACON_TIME_CFG_BEACON_TX);
if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000))
dev_warn(dev->mt76.dev, "Warning: TX DMA did not stop!\n");
/* Page count on TxQ */ /* Page count on TxQ */
i = 200;
while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) || while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) ||
(mt76_rr(dev, 0x0a30) & 0x000000ff) || (mt76_rr(dev, 0x0a30) & 0x000000ff) ||
(mt76_rr(dev, 0x0a34) & 0x00ff00ff))) (mt76_rr(dev, 0x0a34) & 0x00ff00ff)))
...@@ -353,9 +265,7 @@ static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev) ...@@ -353,9 +265,7 @@ static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev)
MT_MAC_SYS_CTRL_ENABLE_TX); MT_MAC_SYS_CTRL_ENABLE_TX);
/* Page count on RxQ */ /* Page count on RxQ */
ok = 0; for (i = 0; i < 200; i++) {
i = 200;
while (i--) {
if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) && if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) &&
!mt76_rr(dev, 0x0a30) && !mt76_rr(dev, 0x0a30) &&
!mt76_rr(dev, 0x0a34)) { !mt76_rr(dev, 0x0a34)) {
...@@ -368,36 +278,14 @@ static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev) ...@@ -368,36 +278,14 @@ static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev)
if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000)) if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000))
dev_warn(dev->mt76.dev, "Warning: MAC RX did not stop!\n"); dev_warn(dev->mt76.dev, "Warning: MAC RX did not stop!\n");
if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000))
dev_warn(dev->mt76.dev, "Warning: RX DMA did not stop!\n");
}
void mt76x0_mac_stop(struct mt76x0_dev *dev)
{
cancel_delayed_work_sync(&dev->cal_work);
cancel_delayed_work_sync(&dev->mac_work);
mt76u_stop_stat_wk(&dev->mt76);
mt76x0_mac_stop_hw(dev);
} }
EXPORT_SYMBOL_GPL(mt76x0_mac_stop); EXPORT_SYMBOL_GPL(mt76x0_mac_stop);
int mt76x0_init_hardware(struct mt76x0_dev *dev) int mt76x0_init_hardware(struct mt76x0_dev *dev)
{ {
static const u16 beacon_offsets[16] = {
/* 512 byte per beacon */
0xc000, 0xc200, 0xc400, 0xc600,
0xc800, 0xca00, 0xcc00, 0xce00,
0xd000, 0xd200, 0xd400, 0xd600,
0xd800, 0xda00, 0xdc00, 0xde00
};
int ret; int ret;
dev->beacon_offsets = beacon_offsets; if (!mt76x02_wait_for_wpdma(&dev->mt76, 1000))
if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG,
MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100))
return -EIO; return -EIO;
/* Wait for ASIC ready after FW load. */ /* Wait for ASIC ready after FW load. */
...@@ -405,25 +293,21 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) ...@@ -405,25 +293,21 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev)
return -ETIMEDOUT; return -ETIMEDOUT;
mt76x0_reset_csr_bbp(dev); mt76x0_reset_csr_bbp(dev);
mt76x0_init_usb_dma(dev);
mt76_wr(dev, MT_HEADER_TRANS_CTRL_REG, 0x0);
mt76_wr(dev, MT_TSO_CTRL, 0x0);
ret = mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, false); ret = mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, false);
if (ret) if (ret)
return ret; return ret;
mt76x0_init_mac_registers(dev); mt76x0_init_mac_registers(dev);
if (!mt76_poll_msec(dev, MT_MAC_STATUS, if (!mt76x02_wait_for_txrx_idle(&dev->mt76))
MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 0, 1000))
return -EIO; return -EIO;
ret = mt76x0_init_bbp(dev); ret = mt76x0_init_bbp(dev);
if (ret) if (ret)
return ret; return ret;
dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG);
ret = mt76x0_init_wcid_mem(dev); ret = mt76x0_init_wcid_mem(dev);
if (ret) if (ret)
return ret; return ret;
...@@ -441,12 +325,6 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) ...@@ -441,12 +325,6 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev)
mt76x0_reset_counters(dev); mt76x0_reset_counters(dev);
mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e);
mt76_wr(dev, MT_TXOP_CTRL_CFG,
FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) |
FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58));
ret = mt76x0_eeprom_init(dev); ret = mt76x0_eeprom_init(dev);
if (ret) if (ret)
return ret; return ret;
...@@ -457,22 +335,15 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) ...@@ -457,22 +335,15 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev)
} }
EXPORT_SYMBOL_GPL(mt76x0_init_hardware); EXPORT_SYMBOL_GPL(mt76x0_init_hardware);
void mt76x0_cleanup(struct mt76x0_dev *dev)
{
clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
mt76x0_chip_onoff(dev, false, false);
mt76u_queues_deinit(&dev->mt76);
mt76u_mcu_deinit(&dev->mt76);
}
EXPORT_SYMBOL_GPL(mt76x0_cleanup);
struct mt76x0_dev * struct mt76x0_dev *
mt76x0_alloc_device(struct device *pdev, const struct mt76_driver_ops *drv_ops) mt76x0_alloc_device(struct device *pdev,
const struct mt76_driver_ops *drv_ops,
const struct ieee80211_ops *ops)
{ {
struct mt76x0_dev *dev; struct mt76x0_dev *dev;
struct mt76_dev *mdev; struct mt76_dev *mdev;
mdev = mt76_alloc_device(sizeof(*dev), &mt76x0_ops); mdev = mt76_alloc_device(sizeof(*dev), ops);
if (!mdev) if (!mdev)
return NULL; return NULL;
...@@ -497,10 +368,6 @@ int mt76x0_register_device(struct mt76x0_dev *dev) ...@@ -497,10 +368,6 @@ int mt76x0_register_device(struct mt76x0_dev *dev)
struct wiphy *wiphy = hw->wiphy; struct wiphy *wiphy = hw->wiphy;
int ret; int ret;
ret = mt76x0_init_hardware(dev);
if (ret)
return ret;
/* Reserve WCID 0 for mcast - thanks to this APs WCID will go to /* Reserve WCID 0 for mcast - thanks to this APs WCID will go to
* entry no. 1 like it does in the vendor driver. * entry no. 1 like it does in the vendor driver.
*/ */
...@@ -535,12 +402,6 @@ int mt76x0_register_device(struct mt76x0_dev *dev) ...@@ -535,12 +402,6 @@ int mt76x0_register_device(struct mt76x0_dev *dev)
if (mdev->cap.has_5ghz) if (mdev->cap.has_5ghz)
mt76x0_vht_cap_mask(&dev->mt76.sband_5g.sband); mt76x0_vht_cap_mask(&dev->mt76.sband_5g.sband);
/* check hw sg support in order to enable AMSDU */
if (mt76u_check_sg(mdev))
hw->max_tx_fragments = MT_SG_MAX_SIZE;
else
hw->max_tx_fragments = 1;
mt76x0_init_debugfs(dev); mt76x0_init_debugfs(dev);
return 0; return 0;
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* (c) Copyright 2002-2010, Ralink Technology, Inc. * (c) Copyright 2002-2010, Ralink Technology, Inc.
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
* Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
* Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 * it under the terms of the GNU General Public License version 2
...@@ -19,264 +20,214 @@ ...@@ -19,264 +20,214 @@
#include "phy.h" #include "phy.h"
static const struct mt76_reg_pair common_mac_reg_table[] = { static const struct mt76_reg_pair common_mac_reg_table[] = {
#if 1 { MT_BCN_OFFSET(0), 0xf8f0e8e0 },
{MT_BCN_OFFSET(0), 0xf8f0e8e0}, /* 0x3800(e0), 0x3A00(e8), 0x3C00(f0), 0x3E00(f8), 512B for each beacon */ { MT_BCN_OFFSET(1), 0x6f77d0c8 },
{MT_BCN_OFFSET(1), 0x6f77d0c8}, /* 0x3200(c8), 0x3400(d0), 0x1DC0(77), 0x1BC0(6f), 512B for each beacon */ { MT_LEGACY_BASIC_RATE, 0x0000013f },
#endif { MT_HT_BASIC_RATE, 0x00008003 },
{ MT_MAC_SYS_CTRL, 0x00000000 },
{MT_LEGACY_BASIC_RATE, 0x0000013f}, /* Basic rate set bitmap*/ { MT_RX_FILTR_CFG, 0x00017f97 },
{MT_HT_BASIC_RATE, 0x00008003}, /* Basic HT rate set , 20M, MCS=3, MM. Format is the same as in TXWI.*/ { MT_BKOFF_SLOT_CFG, 0x00000209 },
{MT_MAC_SYS_CTRL, 0x00}, /* 0x1004, , default Disable RX*/ { MT_TX_SW_CFG0, 0x00000000 },
{MT_RX_FILTR_CFG, 0x17f97}, /*0x1400 , RX filter control, */ { MT_TX_SW_CFG1, 0x00080606 },
{MT_BKOFF_SLOT_CFG, 0x209}, /* default set short slot time, CC_DELAY_TIME should be 2 */ { MT_TX_LINK_CFG, 0x00001020 },
/*{TX_SW_CFG0, 0x40a06}, Gary,2006-08-23 */ { MT_TX_TIMEOUT_CFG, 0x000a2090 },
{MT_TX_SW_CFG0, 0x0}, /* Gary,2008-05-21 for CWC test */ { MT_MAX_LEN_CFG, 0xa0fff | 0x00001000 },
{MT_TX_SW_CFG1, 0x80606}, /* Gary,2006-08-23 */ { MT_LED_CFG, 0x7f031e46 },
{MT_TX_LINK_CFG, 0x1020}, /* Gary,2006-08-23 */ { MT_PBF_TX_MAX_PCNT, 0x1fbf1f1f },
/*{TX_TIMEOUT_CFG, 0x00182090}, CCK has some problem. So increase timieout value. 2006-10-09 MArvek RT*/ { MT_PBF_RX_MAX_PCNT, 0x0000fe9f },
{MT_TX_TIMEOUT_CFG, 0x000a2090}, /* CCK has some problem. So increase timieout value. 2006-10-09 MArvek RT , Modify for 2860E ,2007-08-01*/ { MT_TX_RETRY_CFG, 0x47d01f0f },
{MT_MAX_LEN_CFG, 0xa0fff | 0x00001000}, /* 0x3018, MAX frame length. Max PSDU = 16kbytes.*/ { MT_AUTO_RSP_CFG, 0x00000013 },
{MT_LED_CFG, 0x7f031e46}, /* Gary, 2006-08-23*/ { MT_CCK_PROT_CFG, 0x05740003 },
{ MT_OFDM_PROT_CFG, 0x05740003 },
{MT_PBF_TX_MAX_PCNT, 0x1fbf1f1f /*0xbfbf3f1f*/}, { MT_PBF_CFG, 0x00f40006 },
{MT_PBF_RX_MAX_PCNT, 0x9f}, { MT_WPDMA_GLO_CFG, 0x00000030 },
{ MT_GF20_PROT_CFG, 0x01744004 },
/*{TX_RTY_CFG, 0x6bb80408}, Jan, 2006/11/16*/ { MT_GF40_PROT_CFG, 0x03f44084 },
/* WMM_ACM_SUPPORT */ { MT_MM20_PROT_CFG, 0x01744004 },
/* {TX_RTY_CFG, 0x6bb80101}, sample*/ { MT_MM40_PROT_CFG, 0x03f54084 },
{MT_TX_RETRY_CFG, 0x47d01f0f}, /* Jan, 2006/11/16, Set TxWI->ACK =0 in Probe Rsp Modify for 2860E ,2007-08-03*/ { MT_TXOP_CTRL_CFG, 0x0000583f },
{ MT_TX_RTS_CFG, 0x00092b20 },
{MT_AUTO_RSP_CFG, 0x00000013}, /* Initial Auto_Responder, because QA will turn off Auto-Responder*/ { MT_EXP_ACK_TIME, 0x002400ca },
{MT_CCK_PROT_CFG, 0x05740003 /*0x01740003*/}, /* Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. */ { MT_TXOP_HLDR_ET, 0x00000002 },
{MT_OFDM_PROT_CFG, 0x05740003 /*0x01740003*/}, /* Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. */ { MT_XIFS_TIME_CFG, 0x33a41010 },
{MT_PBF_CFG, 0xf40006}, /* Only enable Queue 2*/ { MT_PWR_PIN_CFG, 0x00000000 },
{MT_MM40_PROT_CFG, 0x3F44084}, /* Initial Auto_Responder, because QA will turn off Auto-Responder*/
{MT_WPDMA_GLO_CFG, 0x00000030},
{MT_GF20_PROT_CFG, 0x01744004}, /* set 19:18 --> Short NAV for MIMO PS*/
{MT_GF40_PROT_CFG, 0x03F44084},
{MT_MM20_PROT_CFG, 0x01744004},
{MT_TXOP_CTRL_CFG, 0x0000583f, /*0x0000243f*/ /*0x000024bf*/}, /*Extension channel backoff.*/
{MT_TX_RTS_CFG, 0x00092b20},
{MT_EXP_ACK_TIME, 0x002400ca}, /* default value */
{MT_TXOP_HLDR_ET, 0x00000002},
/* Jerry comments 2008/01/16: we use SIFS = 10us in CCK defaultly, but it seems that 10us
is too small for INTEL 2200bg card, so in MBSS mode, the delta time between beacon0
and beacon1 is SIFS (10us), so if INTEL 2200bg card connects to BSS0, the ping
will always lost. So we change the SIFS of CCK from 10us to 16us. */
{MT_XIFS_TIME_CFG, 0x33a41010},
{MT_PWR_PIN_CFG, 0x00000000},
}; };
static const struct mt76_reg_pair mt76x0_mac_reg_table[] = { static const struct mt76_reg_pair mt76x0_mac_reg_table[] = {
/* {MT_IOCFG_6, 0xA0040080 }, */ { MT_IOCFG_6, 0xa0040080 },
{MT_PBF_SYS_CTRL, 0x00080c00 }, { MT_PBF_SYS_CTRL, 0x00080c00 },
{MT_PBF_CFG, 0x77723c1f }, { MT_PBF_CFG, 0x77723c1f },
{MT_FCE_PSE_CTRL, 0x00000001 }, { MT_FCE_PSE_CTRL, 0x00000001 },
{ MT_AMPDU_MAX_LEN_20M1S, 0xAAA99887 },
{MT_AMPDU_MAX_LEN_20M1S, 0xBAA99887 }, { MT_TX_SW_CFG0, 0x00000601 },
{ MT_TX_SW_CFG1, 0x00040000 },
/* Delay bb_tx_pe for proper tx_mcs_pwr update */ { MT_TX_SW_CFG2, 0x00000000 },
{MT_TX_SW_CFG0, 0x00000601 }, { 0xa44, 0x00000000 },
{ MT_HEADER_TRANS_CTRL_REG, 0x00000000 },
/* Set rf_tx_pe deassert time to 1us by Chee's comment @MT7650_CR_setting_1018.xlsx */ { MT_TSO_CTRL, 0x00000000 },
{MT_TX_SW_CFG1, 0x00040000 }, { MT_BB_PA_MODE_CFG1, 0x00500055 },
{MT_TX_SW_CFG2, 0x00000000 }, { MT_RF_PA_MODE_CFG1, 0x00500055 },
{ MT_TX_ALC_CFG_0, 0x2F2F000C },
/* disable Tx info report */ { MT_TX0_BB_GAIN_ATTEN, 0x00000000 },
{0xa44, 0x0000000 }, { MT_TX_PWR_CFG_0, 0x3A3A3A3A },
{ MT_TX_PWR_CFG_1, 0x3A3A3A3A },
{MT_HEADER_TRANS_CTRL_REG, 0x0}, { MT_TX_PWR_CFG_2, 0x3A3A3A3A },
{MT_TSO_CTRL, 0x0}, { MT_TX_PWR_CFG_3, 0x3A3A3A3A },
{ MT_TX_PWR_CFG_4, 0x3A3A3A3A },
/* BB_PA_MODE_CFG0(0x1214) Keep default value @20120903 */ { MT_TX_PWR_CFG_7, 0x3A3A3A3A },
{MT_BB_PA_MODE_CFG1, 0x00500055}, { MT_TX_PWR_CFG_8, 0x0000003A },
{ MT_TX_PWR_CFG_9, 0x0000003A },
/* RF_PA_MODE_CFG0(0x121C) Keep default value @20120903 */ { 0x150C, 0x00000002 },
{MT_RF_PA_MODE_CFG1, 0x00500055}, { 0x1238, 0x001700C8 },
{ MT_LDO_CTRL_0, 0x00A647B6 },
{MT_TX_ALC_CFG_0, 0x2F2F000C}, { MT_LDO_CTRL_1, 0x6B006464 },
{MT_TX0_BB_GAIN_ATTEN, 0x00000000}, /* set BBP atten gain = 0 */ { MT_HT_BASIC_RATE, 0x00004003 },
{ MT_HT_CTRL_CFG, 0x000001FF },
{MT_TX_PWR_CFG_0, 0x3A3A3A3A}, { MT_TXOP_HLDR_ET, 0x00000000 }
{MT_TX_PWR_CFG_1, 0x3A3A3A3A},
{MT_TX_PWR_CFG_2, 0x3A3A3A3A},
{MT_TX_PWR_CFG_3, 0x3A3A3A3A},
{MT_TX_PWR_CFG_4, 0x3A3A3A3A},
{MT_TX_PWR_CFG_7, 0x3A3A3A3A},
{MT_TX_PWR_CFG_8, 0x3A},
{MT_TX_PWR_CFG_9, 0x3A},
/* Enable Tx length > 4095 byte */
{0x150C, 0x00000002},
/* Disable bt_abort_tx_en(0x1238[21] = 0) which is not used at MT7650 */
{0x1238, 0x001700C8},
/* PMU_OCLEVEL<5:1> from default <5'b10010> to <5'b11011> for normal driver */
/* {MT_LDO_CTRL_0, 0x00A647B6}, */
/* Default LDO_DIG supply 1.26V, change to 1.2V */
{MT_LDO_CTRL_1, 0x6B006464 },
/*
{MT_HT_BASIC_RATE, 0x00004003 },
{MT_HT_CTRL_CFG, 0x000001FF },
*/
}; };
static const struct mt76_reg_pair mt76x0_bbp_init_tab[] = { static const struct mt76_reg_pair mt76x0_bbp_init_tab[] = {
{MT_BBP(CORE, 1), 0x00000002}, { MT_BBP(CORE, 1), 0x00000002 },
{MT_BBP(CORE, 4), 0x00000000}, { MT_BBP(CORE, 4), 0x00000000 },
{MT_BBP(CORE, 24), 0x00000000}, { MT_BBP(CORE, 24), 0x00000000 },
{MT_BBP(CORE, 32), 0x4003000a}, { MT_BBP(CORE, 32), 0x4003000a },
{MT_BBP(CORE, 42), 0x00000000}, { MT_BBP(CORE, 42), 0x00000000 },
{MT_BBP(CORE, 44), 0x00000000}, { MT_BBP(CORE, 44), 0x00000000 },
{ MT_BBP(IBI, 11), 0x0FDE8081 },
{MT_BBP(IBI, 11), 0x00000080}, { MT_BBP(AGC, 0), 0x00021400 },
{ MT_BBP(AGC, 1), 0x00000003 },
/* { MT_BBP(AGC, 2), 0x003A6464 },
0x2300[5] Default Antenna: { MT_BBP(AGC, 15), 0x88A28CB8 },
0 for WIFI main antenna { MT_BBP(AGC, 22), 0x00001E21 },
1 for WIFI aux antenna { MT_BBP(AGC, 23), 0x0000272C },
{ MT_BBP(AGC, 24), 0x00002F3A },
*/ { MT_BBP(AGC, 25), 0x8000005A },
{MT_BBP(AGC, 0), 0x00021400}, { MT_BBP(AGC, 26), 0x007C2005 },
{MT_BBP(AGC, 1), 0x00000003}, { MT_BBP(AGC, 33), 0x00003238 },
{MT_BBP(AGC, 2), 0x003A6464}, { MT_BBP(AGC, 34), 0x000A0C0C },
{MT_BBP(AGC, 15), 0x88A28CB8}, { MT_BBP(AGC, 37), 0x2121262C },
{MT_BBP(AGC, 22), 0x00001E21}, { MT_BBP(AGC, 41), 0x38383E45 },
{MT_BBP(AGC, 23), 0x0000272C}, { MT_BBP(AGC, 57), 0x00001010 },
{MT_BBP(AGC, 24), 0x00002F3A}, { MT_BBP(AGC, 59), 0xBAA20E96 },
{MT_BBP(AGC, 25), 0x8000005A}, { MT_BBP(AGC, 63), 0x00000001 },
{MT_BBP(AGC, 26), 0x007C2005}, { MT_BBP(TXC, 0), 0x00280403 },
{MT_BBP(AGC, 34), 0x000A0C0C}, { MT_BBP(TXC, 1), 0x00000000 },
{MT_BBP(AGC, 37), 0x2121262C}, { MT_BBP(RXC, 1), 0x00000012 },
{MT_BBP(AGC, 41), 0x38383E45}, { MT_BBP(RXC, 2), 0x00000011 },
{MT_BBP(AGC, 57), 0x00001010}, { MT_BBP(RXC, 3), 0x00000005 },
{MT_BBP(AGC, 59), 0xBAA20E96}, { MT_BBP(RXC, 4), 0x00000000 },
{MT_BBP(AGC, 63), 0x00000001}, { MT_BBP(RXC, 5), 0xF977C4EC },
{ MT_BBP(RXC, 7), 0x00000090 },
{MT_BBP(TXC, 0), 0x00280403}, { MT_BBP(TXO, 8), 0x00000000 },
{MT_BBP(TXC, 1), 0x00000000}, { MT_BBP(TXBE, 0), 0x00000000 },
{ MT_BBP(TXBE, 4), 0x00000004 },
{MT_BBP(RXC, 1), 0x00000012}, { MT_BBP(TXBE, 6), 0x00000000 },
{MT_BBP(RXC, 2), 0x00000011}, { MT_BBP(TXBE, 8), 0x00000014 },
{MT_BBP(RXC, 3), 0x00000005}, { MT_BBP(TXBE, 9), 0x20000000 },
{MT_BBP(RXC, 4), 0x00000000}, { MT_BBP(TXBE, 10), 0x00000000 },
{MT_BBP(RXC, 5), 0xF977C4EC}, { MT_BBP(TXBE, 12), 0x00000000 },
{MT_BBP(RXC, 7), 0x00000090}, { MT_BBP(TXBE, 13), 0x00000000 },
{ MT_BBP(TXBE, 14), 0x00000000 },
{MT_BBP(TXO, 8), 0x00000000}, { MT_BBP(TXBE, 15), 0x00000000 },
{ MT_BBP(TXBE, 16), 0x00000000 },
{MT_BBP(TXBE, 0), 0x00000000}, { MT_BBP(TXBE, 17), 0x00000000 },
{MT_BBP(TXBE, 4), 0x00000004}, { MT_BBP(RXFE, 1), 0x00008800 },
{MT_BBP(TXBE, 6), 0x00000000}, { MT_BBP(RXFE, 3), 0x00000000 },
{MT_BBP(TXBE, 8), 0x00000014}, { MT_BBP(RXFE, 4), 0x00000000 },
{MT_BBP(TXBE, 9), 0x20000000}, { MT_BBP(RXO, 13), 0x00000192 },
{MT_BBP(TXBE, 10), 0x00000000}, { MT_BBP(RXO, 14), 0x00060612 },
{MT_BBP(TXBE, 12), 0x00000000}, { MT_BBP(RXO, 15), 0xC8321B18 },
{MT_BBP(TXBE, 13), 0x00000000}, { MT_BBP(RXO, 16), 0x0000001E },
{MT_BBP(TXBE, 14), 0x00000000}, { MT_BBP(RXO, 17), 0x00000000 },
{MT_BBP(TXBE, 15), 0x00000000}, { MT_BBP(RXO, 18), 0xCC00A993 },
{MT_BBP(TXBE, 16), 0x00000000}, { MT_BBP(RXO, 19), 0xB9CB9CB9 },
{MT_BBP(TXBE, 17), 0x00000000}, { MT_BBP(RXO, 20), 0x26c00057 },
{ MT_BBP(RXO, 21), 0x00000001 },
{MT_BBP(RXFE, 1), 0x00008800}, /* Add for E3 */ { MT_BBP(RXO, 24), 0x00000006 },
{MT_BBP(RXFE, 3), 0x00000000}, { MT_BBP(RXO, 28), 0x0000003F },
{MT_BBP(RXFE, 4), 0x00000000},
{MT_BBP(RXO, 13), 0x00000092},
{MT_BBP(RXO, 14), 0x00060612},
{MT_BBP(RXO, 15), 0xC8321B18},
{MT_BBP(RXO, 16), 0x0000001E},
{MT_BBP(RXO, 17), 0x00000000},
{MT_BBP(RXO, 18), 0xCC00A993},
{MT_BBP(RXO, 19), 0xB9CB9CB9},
{MT_BBP(RXO, 20), 0x26c00057},
{MT_BBP(RXO, 21), 0x00000001},
{MT_BBP(RXO, 24), 0x00000006},
}; };
static const struct mt76x0_bbp_switch_item mt76x0_bbp_switch_tab[] = { static const struct mt76x0_bbp_switch_item mt76x0_bbp_switch_tab[] = {
{RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 8), 0x0E344EF0}}, { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 4), 0x1FEDA049 } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 8), 0x122C54F2}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 4), 0x1FECA054 } },
{ RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 6), 0x00000045 } },
{ RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 6), 0x0000000A } },
{RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 14), 0x310F2E39}}, { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 8), 0x16344EF0 } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 14), 0x310F2A3F}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 8), 0x122C54F2 } },
{RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 32), 0x00003230}}, { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 12), 0x05052879 } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 32), 0x0000181C}}, { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 12), 0x050528F9 } },
{ RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 12), 0x050528F9 } },
{RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 33), 0x00003240}}, { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 13), 0x35050004 } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 33), 0x00003218}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 13), 0x2C3A0406 } },
{RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 35), 0x11112016}}, { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 14), 0x310F2E3C } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 35), 0x11112016}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 14), 0x310F2A3F } },
{RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(RXO, 28), 0x0000008A}}, { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 26), 0x007C2005 } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(RXO, 28), 0x0000008A}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 26), 0x007C2005 } },
{RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 4), 0x1FEDA049}}, { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 27), 0x000000E1 } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 4), 0x1FECA054}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 27), 0x000000EC } },
{RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 6), 0x00000045}}, { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 28), 0x00060806 } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 6), 0x0000000A}}, { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 28), 0x00050806 } },
{ RF_A_BAND | RF_BW_40, { MT_BBP(AGC, 28), 0x00060801 } },
{ RF_A_BAND | RF_BW_20 | RF_BW_80, { MT_BBP(AGC, 28), 0x00060806 } },
{RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 12), 0x05052879}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(RXO, 28), 0x0000008A } },
{RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 12), 0x050528F9}},
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 12), 0x050528F9}},
{RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 13), 0x35050004}}, { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 31), 0x00000E23 } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 13), 0x2C3A0406}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 31), 0x00000E13 } },
{RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 27), 0x000000E1}}, { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 32), 0x00003218 } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 27), 0x000000EC}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 32), 0x0000181C } },
{RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 28), 0x00060806}}, { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 33), 0x00003240 } },
{RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 28), 0x00050806}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 33), 0x00003218 } },
{RF_A_BAND | RF_BW_40, {MT_BBP(AGC, 28), 0x00060801}},
{RF_A_BAND | RF_BW_20 | RF_BW_80, {MT_BBP(AGC, 28), 0x00060806}},
{RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 31), 0x00000F23}}, { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 35), 0x11111616 } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 31), 0x00000F13}}, { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 35), 0x11111516 } },
{ RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 35), 0x11111111 } },
{RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 39), 0x2A2A3036}}, { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 39), 0x2A2A3036 } },
{RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 39), 0x2A2A2C36}}, { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 39), 0x2A2A2C36 } },
{RF_A_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 39), 0x2A2A3036}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 39), 0x2A2A2A2A } },
{RF_A_BAND | RF_BW_80, {MT_BBP(AGC, 39), 0x2A2A2A36}},
{RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 43), 0x27273438}}, { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 43), 0x27273438 } },
{RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 43), 0x27272D38}}, { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 43), 0x27272D38 } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 43), 0x27272B30}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 43), 0x27271A1A } },
{RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 51), 0x17171C1C}}, { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 51), 0x17171C1C } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 51), 0xFFFFFFFF}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 51), 0xFFFFFFFF } },
{RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 53), 0x26262A2F}}, { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 53), 0x26262A2F } },
{RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 53), 0x2626322F}}, { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 53), 0x2626322F } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 53), 0xFFFFFFFF}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 53), 0xFFFFFFFF } },
{RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 55), 0x40404E58}}, { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 55), 0x40404040 } },
{RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 55), 0x40405858}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 55), 0xFFFFFFFF } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 55), 0xFFFFFFFF}},
{RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 58), 0x00001010}}, { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 58), 0x00001010 } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 58), 0x00000000}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 58), 0x00000000 } },
{RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(RXFE, 0), 0x3D5000E0}}, { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(RXFE, 0), 0x3D5000E0 } },
{RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(RXFE, 0), 0x895000E0}}, { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(RXFE, 0), 0x895000E0 } },
}; };
static const struct mt76_reg_pair mt76x0_dcoc_tab[] = { static const struct mt76_reg_pair mt76x0_dcoc_tab[] = {
{MT_BBP(CAL, 47), 0x000010F0 }, { MT_BBP(CAL, 47), 0x000010F0 },
{MT_BBP(CAL, 48), 0x00008080 }, { MT_BBP(CAL, 48), 0x00008080 },
{MT_BBP(CAL, 49), 0x00000F07 }, { MT_BBP(CAL, 49), 0x00000F07 },
{MT_BBP(CAL, 50), 0x00000040 }, { MT_BBP(CAL, 50), 0x00000040 },
{MT_BBP(CAL, 51), 0x00000404 }, { MT_BBP(CAL, 51), 0x00000404 },
{MT_BBP(CAL, 52), 0x00080803 }, { MT_BBP(CAL, 52), 0x00080803 },
{MT_BBP(CAL, 53), 0x00000704 }, { MT_BBP(CAL, 53), 0x00000704 },
{MT_BBP(CAL, 54), 0x00002828 }, { MT_BBP(CAL, 54), 0x00002828 },
{MT_BBP(CAL, 55), 0x00005050 }, { MT_BBP(CAL, 55), 0x00005050 },
}; };
#endif #endif
...@@ -18,42 +18,7 @@ ...@@ -18,42 +18,7 @@
#include "../mt76x02_util.h" #include "../mt76x02_util.h"
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
static int mt76x0_start(struct ieee80211_hw *hw) int mt76x0_config(struct ieee80211_hw *hw, u32 changed)
{
struct mt76x0_dev *dev = hw->priv;
int ret;
mutex_lock(&dev->mt76.mutex);
ret = mt76x0_mac_start(dev);
if (ret)
goto out;
ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work,
MT_CALIBRATE_INTERVAL);
ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work,
MT_CALIBRATE_INTERVAL);
set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
out:
mutex_unlock(&dev->mt76.mutex);
return ret;
}
static void mt76x0_stop(struct ieee80211_hw *hw)
{
struct mt76x0_dev *dev = hw->priv;
mutex_lock(&dev->mt76.mutex);
clear_bit(MT76_STATE_RUNNING, &dev->mt76.state);
mt76x0_mac_stop(dev);
mutex_unlock(&dev->mt76.mutex);
}
static int mt76x0_config(struct ieee80211_hw *hw, u32 changed)
{ {
struct mt76x0_dev *dev = hw->priv; struct mt76x0_dev *dev = hw->priv;
int ret = 0; int ret = 0;
...@@ -66,10 +31,27 @@ static int mt76x0_config(struct ieee80211_hw *hw, u32 changed) ...@@ -66,10 +31,27 @@ static int mt76x0_config(struct ieee80211_hw *hw, u32 changed)
ieee80211_wake_queues(hw); ieee80211_wake_queues(hw);
} }
if (changed & IEEE80211_CONF_CHANGE_POWER) {
dev->mt76.txpower_conf = hw->conf.power_level * 2;
if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state))
mt76x0_phy_set_txpower(dev);
}
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC;
else
dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC;
mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
}
mutex_unlock(&dev->mt76.mutex); mutex_unlock(&dev->mt76.mutex);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(mt76x0_config);
static void static void
mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr) mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr)
...@@ -78,9 +60,9 @@ mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr) ...@@ -78,9 +60,9 @@ mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr)
mt76_wr(dev, offset + 4, addr[4] | addr[5] << 8); mt76_wr(dev, offset + 4, addr[4] | addr[5] << 8);
} }
static void void mt76x0_bss_info_changed(struct ieee80211_hw *hw,
mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info, u32 changed) struct ieee80211_bss_conf *info, u32 changed)
{ {
struct mt76x0_dev *dev = hw->priv; struct mt76x0_dev *dev = hw->priv;
...@@ -130,11 +112,10 @@ mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ...@@ -130,11 +112,10 @@ mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mutex_unlock(&dev->mt76.mutex); mutex_unlock(&dev->mt76.mutex);
} }
EXPORT_SYMBOL_GPL(mt76x0_bss_info_changed);
static void void mt76x0_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mt76x0_sw_scan(struct ieee80211_hw *hw, const u8 *mac_addr)
struct ieee80211_vif *vif,
const u8 *mac_addr)
{ {
struct mt76x0_dev *dev = hw->priv; struct mt76x0_dev *dev = hw->priv;
...@@ -142,10 +123,10 @@ mt76x0_sw_scan(struct ieee80211_hw *hw, ...@@ -142,10 +123,10 @@ mt76x0_sw_scan(struct ieee80211_hw *hw,
mt76x0_agc_save(dev); mt76x0_agc_save(dev);
set_bit(MT76_SCANNING, &dev->mt76.state); set_bit(MT76_SCANNING, &dev->mt76.state);
} }
EXPORT_SYMBOL_GPL(mt76x0_sw_scan);
static void void mt76x0_sw_scan_complete(struct ieee80211_hw *hw,
mt76x0_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
struct ieee80211_vif *vif)
{ {
struct mt76x0_dev *dev = hw->priv; struct mt76x0_dev *dev = hw->priv;
...@@ -155,8 +136,9 @@ mt76x0_sw_scan_complete(struct ieee80211_hw *hw, ...@@ -155,8 +136,9 @@ mt76x0_sw_scan_complete(struct ieee80211_hw *hw,
ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work,
MT_CALIBRATE_INTERVAL); MT_CALIBRATE_INTERVAL);
} }
EXPORT_SYMBOL_GPL(mt76x0_sw_scan_complete);
static int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value) int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{ {
struct mt76x0_dev *dev = hw->priv; struct mt76x0_dev *dev = hw->priv;
...@@ -164,24 +146,4 @@ static int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value) ...@@ -164,24 +146,4 @@ static int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(mt76x0_set_rts_threshold);
const struct ieee80211_ops mt76x0_ops = {
.tx = mt76x0_tx,
.start = mt76x0_start,
.stop = mt76x0_stop,
.add_interface = mt76x02_add_interface,
.remove_interface = mt76x02_remove_interface,
.config = mt76x0_config,
.configure_filter = mt76x02_configure_filter,
.bss_info_changed = mt76x0_bss_info_changed,
.sta_add = mt76x02_sta_add,
.sta_remove = mt76x02_sta_remove,
.set_key = mt76x02_set_key,
.conf_tx = mt76x02_conf_tx,
.sw_scan_start = mt76x0_sw_scan,
.sw_scan_complete = mt76x0_sw_scan_complete,
.ampdu_action = mt76x02_ampdu_action,
.sta_rate_tbl_update = mt76x02_sta_rate_tbl_update,
.set_rts_threshold = mt76x0_set_rts_threshold,
.wake_tx_queue = mt76_wake_tx_queue,
};
...@@ -41,4 +41,11 @@ enum mcu_calibrate { ...@@ -41,4 +41,11 @@ enum mcu_calibrate {
MCU_CAL_TX_GROUP_DELAY, MCU_CAL_TX_GROUP_DELAY,
}; };
int mt76x0e_mcu_init(struct mt76x0_dev *dev);
int mt76x0u_mcu_init(struct mt76x0_dev *dev);
static inline int mt76x0_firmware_running(struct mt76x0_dev *dev)
{
return mt76_rr(dev, MT_MCU_COM_REG0) == 1;
}
#endif #endif
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "../mt76.h" #include "../mt76.h"
#include "../mt76x02_regs.h" #include "../mt76x02_regs.h"
#include "../mt76x02_mac.h" #include "../mt76x02_mac.h"
#include "eeprom.h"
#define MT_CALIBRATE_INTERVAL (4 * HZ) #define MT_CALIBRATE_INTERVAL (4 * HZ)
...@@ -86,15 +87,11 @@ struct mt76x0_dev { ...@@ -86,15 +87,11 @@ struct mt76x0_dev {
spinlock_t mac_lock; spinlock_t mac_lock;
const u16 *beacon_offsets; struct mt76x0_caldata caldata;
struct mt76x0_eeprom_params *ee;
struct mutex reg_atomic_mutex; struct mutex reg_atomic_mutex;
struct mutex hw_atomic_mutex; struct mutex hw_atomic_mutex;
u32 debugfs_reg;
atomic_t avg_ampdu_len; atomic_t avg_ampdu_len;
/* Connection monitoring things */ /* Connection monitoring things */
...@@ -107,13 +104,12 @@ struct mt76x0_dev { ...@@ -107,13 +104,12 @@ struct mt76x0_dev {
int avg_rssi; /* starts at 0 and converges */ int avg_rssi; /* starts at 0 and converges */
u8 agc_save; u8 agc_save;
u16 chainmask;
bool no_2ghz;
struct mac_stats stats; struct mac_stats stats;
}; };
extern const struct ieee80211_ops mt76x0_ops;
static inline bool is_mt7610e(struct mt76x0_dev *dev) static inline bool is_mt7610e(struct mt76x0_dev *dev)
{ {
/* TODO */ /* TODO */
...@@ -128,15 +124,26 @@ void mt76x0_init_debugfs(struct mt76x0_dev *dev); ...@@ -128,15 +124,26 @@ void mt76x0_init_debugfs(struct mt76x0_dev *dev);
/* Init */ /* Init */
struct mt76x0_dev * struct mt76x0_dev *
mt76x0_alloc_device(struct device *pdev, const struct mt76_driver_ops *drv_ops); mt76x0_alloc_device(struct device *pdev,
const struct mt76_driver_ops *drv_ops,
const struct ieee80211_ops *ops);
int mt76x0_init_hardware(struct mt76x0_dev *dev); int mt76x0_init_hardware(struct mt76x0_dev *dev);
int mt76x0_register_device(struct mt76x0_dev *dev); int mt76x0_register_device(struct mt76x0_dev *dev);
void mt76x0_cleanup(struct mt76x0_dev *dev);
void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset); void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset);
int mt76x0_mac_start(struct mt76x0_dev *dev); int mt76x0_mac_start(struct mt76x0_dev *dev);
void mt76x0_mac_stop(struct mt76x0_dev *dev); void mt76x0_mac_stop(struct mt76x0_dev *dev);
int mt76x0_config(struct ieee80211_hw *hw, u32 changed);
void mt76x0_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info, u32 changed);
void mt76x0_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
const u8 *mac_addr);
void mt76x0_sw_scan_complete(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
/* PHY */ /* PHY */
void mt76x0_phy_init(struct mt76x0_dev *dev); void mt76x0_phy_init(struct mt76x0_dev *dev);
int mt76x0_wait_bbp_ready(struct mt76x0_dev *dev); int mt76x0_wait_bbp_ready(struct mt76x0_dev *dev);
...@@ -148,6 +155,7 @@ void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev); ...@@ -148,6 +155,7 @@ void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev);
int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi); int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi);
void mt76x0_phy_con_cal_onoff(struct mt76x0_dev *dev, void mt76x0_phy_con_cal_onoff(struct mt76x0_dev *dev,
struct ieee80211_bss_conf *info); struct ieee80211_bss_conf *info);
void mt76x0_phy_set_txpower(struct mt76x0_dev *dev);
/* MAC */ /* MAC */
void mt76x0_mac_work(struct work_struct *work); void mt76x0_mac_work(struct work_struct *work);
...@@ -160,12 +168,12 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev); ...@@ -160,12 +168,12 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev);
/* TX */ /* TX */
void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
struct sk_buff *skb); struct sk_buff *skb);
struct mt76x02_txwi *
mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb,
struct ieee80211_sta *sta, struct mt76_wcid *wcid,
int pkt_len);
void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb); struct sk_buff *skb);
int mt76x0_tx_prepare_skb(struct mt76_dev *mdev, void *data,
struct sk_buff *skb, struct mt76_queue *q,
struct mt76_wcid *wcid, struct ieee80211_sta *sta,
u32 *tx_info);
#endif #endif
...@@ -19,6 +19,106 @@ ...@@ -19,6 +19,106 @@
#include <linux/pci.h> #include <linux/pci.h>
#include "mt76x0.h" #include "mt76x0.h"
#include "mcu.h"
#include "../mt76x02_dma.h"
#include "../mt76x02_util.h"
static int mt76x0e_start(struct ieee80211_hw *hw)
{
struct mt76x0_dev *dev = hw->priv;
mutex_lock(&dev->mt76.mutex);
mt76x02_mac_start(&dev->mt76);
ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work,
MT_CALIBRATE_INTERVAL);
ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work,
MT_CALIBRATE_INTERVAL);
set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
mutex_unlock(&dev->mt76.mutex);
return 0;
}
static void mt76x0e_stop(struct ieee80211_hw *hw)
{
struct mt76x0_dev *dev = hw->priv;
mutex_lock(&dev->mt76.mutex);
clear_bit(MT76_STATE_RUNNING, &dev->mt76.state);
cancel_delayed_work_sync(&dev->cal_work);
cancel_delayed_work_sync(&dev->mac_work);
if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY,
0, 1000))
dev_warn(dev->mt76.dev, "TX DMA did not stop\n");
mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN);
mt76x0_mac_stop(dev);
if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_BUSY,
0, 1000))
dev_warn(dev->mt76.dev, "TX DMA did not stop\n");
mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_EN);
mutex_unlock(&dev->mt76.mutex);
}
static const struct ieee80211_ops mt76x0e_ops = {
.tx = mt76x0_tx,
.start = mt76x0e_start,
.stop = mt76x0e_stop,
.config = mt76x0_config,
.add_interface = mt76x02_add_interface,
.remove_interface = mt76x02_remove_interface,
.configure_filter = mt76x02_configure_filter,
};
static int mt76x0e_register_device(struct mt76x0_dev *dev)
{
int err;
mt76x0_chip_onoff(dev, true, false);
if (!mt76x02_wait_for_mac(&dev->mt76))
return -ETIMEDOUT;
mt76x02_dma_disable(&dev->mt76);
err = mt76x0e_mcu_init(dev);
if (err < 0)
return err;
err = mt76x02_dma_init(&dev->mt76);
if (err < 0)
return err;
err = mt76x0_init_hardware(dev);
if (err < 0)
return err;
if (mt76_chip(&dev->mt76) == 0x7610) {
u16 val;
mt76_clear(dev, MT_COEXCFG0, BIT(0));
val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0);
if (val & MT_EE_NIC_CONF_0_PA_IO_CURRENT) {
u32 data;
/* set external external PA I/O
* current to 16mA
*/
data = mt76_rr(dev, 0x11c);
val |= 0xc03;
mt76_wr(dev, 0x11c, val);
}
}
mt76_clear(dev, 0x110, BIT(9));
mt76_set(dev, MT_MAX_LEN_CFG, BIT(13));
return 0;
}
static int static int
mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
...@@ -40,7 +140,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -40,7 +140,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret) if (ret)
return ret; return ret;
dev = mt76x0_alloc_device(&pdev->dev, NULL); dev = mt76x0_alloc_device(&pdev->dev, NULL, &mt76x0e_ops);
if (!dev) if (!dev)
return -ENOMEM; return -ENOMEM;
...@@ -49,7 +149,13 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -49,7 +149,13 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION); dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION);
dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev);
/* error: */ ret = mt76x0e_register_device(dev);
if (ret < 0)
goto error;
return 0;
error:
ieee80211_free_hw(mt76_hw(dev)); ieee80211_free_hw(mt76_hw(dev));
return ret; return ret;
} }
...@@ -65,6 +171,7 @@ mt76x0e_remove(struct pci_dev *pdev) ...@@ -65,6 +171,7 @@ mt76x0e_remove(struct pci_dev *pdev)
static const struct pci_device_id mt76x0e_device_table[] = { static const struct pci_device_id mt76x0e_device_table[] = {
{ PCI_DEVICE(0x14c3, 0x7630) }, { PCI_DEVICE(0x14c3, 0x7630) },
{ PCI_DEVICE(0x14c3, 0x7650) },
{ }, { },
}; };
......
/*
* Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/firmware.h>
#include "mt76x0.h"
#include "mcu.h"
#define MT7610E_FIRMWARE "mediatek/mt7610e.bin"
#define MT7650E_FIRMWARE "mediatek/mt7650e.bin"
#define MT_MCU_IVB_ADDR (MT_MCU_ILM_ADDR + 0x54000 - MT_MCU_IVB_SIZE)
static int mt76x0e_load_firmware(struct mt76x0_dev *dev)
{
bool is_combo_chip = mt76_chip(&dev->mt76) != 0x7610;
u32 val, ilm_len, dlm_len, offset = 0;
const struct mt76x02_fw_header *hdr;
const struct firmware *fw;
const char *firmware;
const u8 *fw_payload;
int len, err;
if (is_combo_chip)
firmware = MT7650E_FIRMWARE;
else
firmware = MT7610E_FIRMWARE;
err = request_firmware(&fw, firmware, dev->mt76.dev);
if (err)
return err;
if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
err = -EIO;
goto out;
}
hdr = (const struct mt76x02_fw_header *)fw->data;
len = sizeof(*hdr);
len += le32_to_cpu(hdr->ilm_len);
len += le32_to_cpu(hdr->dlm_len);
if (fw->size != len) {
err = -EIO;
goto out;
}
fw_payload = fw->data + sizeof(*hdr);
val = le16_to_cpu(hdr->fw_ver);
dev_info(dev->mt76.dev, "Firmware Version: %d.%d.%02d\n",
(val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf);
val = le16_to_cpu(hdr->fw_ver);
dev_dbg(dev->mt76.dev,
"Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n",
(val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf,
le16_to_cpu(hdr->build_ver), hdr->build_time);
if (is_combo_chip && !mt76_poll(dev, MT_MCU_SEMAPHORE_00, 1, 1, 600)) {
dev_err(dev->mt76.dev,
"Could not get hardware semaphore for loading fw\n");
err = -ETIMEDOUT;
goto out;
}
/* upload ILM. */
mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0);
ilm_len = le32_to_cpu(hdr->ilm_len);
if (is_combo_chip) {
ilm_len -= MT_MCU_IVB_SIZE;
offset = MT_MCU_IVB_SIZE;
}
dev_dbg(dev->mt76.dev, "loading FW - ILM %u\n", ilm_len);
mt76_wr_copy(dev, MT_MCU_ILM_ADDR + offset, fw_payload + offset,
ilm_len);
/* upload IVB. */
if (is_combo_chip) {
dev_dbg(dev->mt76.dev, "loading FW - IVB %u\n",
MT_MCU_IVB_SIZE);
mt76_wr_copy(dev, MT_MCU_IVB_ADDR, fw_payload, MT_MCU_IVB_SIZE);
}
/* upload DLM. */
mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_DLM_OFFSET);
dlm_len = le32_to_cpu(hdr->dlm_len);
dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len);
mt76_wr_copy(dev, MT_MCU_ILM_ADDR,
fw_payload + le32_to_cpu(hdr->ilm_len), dlm_len);
/* trigger firmware */
mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0);
if (is_combo_chip)
mt76_wr(dev, MT_MCU_INT_LEVEL, 0x3);
else
mt76_wr(dev, MT_MCU_RESET_CTL, 0x300);
if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 1000)) {
dev_err(dev->mt76.dev, "Firmware failed to start\n");
err = -ETIMEDOUT;
goto out;
}
dev_dbg(dev->mt76.dev, "Firmware running!\n");
out:
if (is_combo_chip)
mt76_wr(dev, MT_MCU_SEMAPHORE_00, 0x1);
release_firmware(fw);
return err;
}
int mt76x0e_mcu_init(struct mt76x0_dev *dev)
{
static const struct mt76_mcu_ops mt76x0e_mcu_ops = {
.mcu_msg_alloc = mt76x02_mcu_msg_alloc,
.mcu_send_msg = mt76x02_mcu_msg_send,
};
int err;
dev->mt76.mcu_ops = &mt76x0e_mcu_ops;
err = mt76x0e_load_firmware(dev);
if (err < 0)
return err;
set_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state);
return 0;
}
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "phy.h" #include "phy.h"
#include "initvals.h" #include "initvals.h"
#include "initvals_phy.h" #include "initvals_phy.h"
#include "../mt76x02_phy.h"
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
...@@ -228,20 +229,9 @@ mt76x0_bbp_set_ctrlch(struct mt76x0_dev *dev, enum nl80211_chan_width width, ...@@ -228,20 +229,9 @@ mt76x0_bbp_set_ctrlch(struct mt76x0_dev *dev, enum nl80211_chan_width width,
int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi) int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi)
{ {
s8 lna_gain, rssi_offset; struct mt76x0_caldata *caldata = &dev->caldata;
int val;
if (dev->mt76.chandef.chan->band == NL80211_BAND_2GHZ) { return rxwi->rssi[0] + caldata->rssi_offset[0] - caldata->lna_gain;
lna_gain = dev->ee->lna_gain_2ghz;
rssi_offset = dev->ee->rssi_offset_2ghz[0];
} else {
lna_gain = dev->ee->lna_gain_5ghz[0];
rssi_offset = dev->ee->rssi_offset_5ghz[0];
}
val = rxwi->rssi[0] + rssi_offset - lna_gain;
return val;
} }
static void mt76x0_vco_cal(struct mt76x0_dev *dev, u8 channel) static void mt76x0_vco_cal(struct mt76x0_dev *dev, u8 channel)
...@@ -340,16 +330,12 @@ mt76x0_phy_set_band(struct mt76x0_dev *dev, enum nl80211_band band) ...@@ -340,16 +330,12 @@ mt76x0_phy_set_band(struct mt76x0_dev *dev, enum nl80211_band band)
} }
} }
#define EXT_PA_2G_5G 0x0
#define EXT_PA_5G_ONLY 0x1
#define EXT_PA_2G_ONLY 0x2
#define INT_PA_2G_5G 0x3
static void static void
mt76x0_phy_set_chan_rf_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_band) mt76x0_phy_set_chan_rf_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_band)
{ {
u16 rf_band = rf_bw_band & 0xff00; u16 rf_band = rf_bw_band & 0xff00;
u16 rf_bw = rf_bw_band & 0x00ff; u16 rf_bw = rf_bw_band & 0x00ff;
enum nl80211_band band;
u32 mac_reg; u32 mac_reg;
u8 rf_val; u8 rf_val;
int i; int i;
...@@ -496,11 +482,8 @@ mt76x0_phy_set_chan_rf_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_band ...@@ -496,11 +482,8 @@ mt76x0_phy_set_chan_rf_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_band
mac_reg &= ~0xC; /* Clear 0x518[3:2] */ mac_reg &= ~0xC; /* Clear 0x518[3:2] */
mt76_wr(dev, MT_RF_MISC, mac_reg); mt76_wr(dev, MT_RF_MISC, mac_reg);
if (dev->ee->pa_type == INT_PA_2G_5G || band = (rf_band & RF_G_BAND) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
(dev->ee->pa_type == EXT_PA_5G_ONLY && (rf_band & RF_G_BAND)) || if (mt76x02_ext_pa_enabled(&dev->mt76, band)) {
(dev->ee->pa_type == EXT_PA_2G_ONLY && (rf_band & RF_A_BAND))) {
; /* Internal PA - nothing to do. */
} else {
/* /*
MT_RF_MISC (offset: 0x0518) MT_RF_MISC (offset: 0x0518)
[2]1'b1: enable external A band PA, 1'b0: disable external A band PA [2]1'b1: enable external A band PA, 1'b0: disable external A band PA
...@@ -552,20 +535,10 @@ mt76x0_phy_set_chan_bbp_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_ban ...@@ -552,20 +535,10 @@ mt76x0_phy_set_chan_bbp_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_ban
if (pair->reg == MT_BBP(AGC, 8)) { if (pair->reg == MT_BBP(AGC, 8)) {
u32 val = pair->value; u32 val = pair->value;
u8 gain = FIELD_GET(MT_BBP_AGC_GAIN, val); u8 gain;
if (channel > 14) {
if (channel < 100)
gain -= dev->ee->lna_gain_5ghz[0]*2;
else if (channel < 137)
gain -= dev->ee->lna_gain_5ghz[1]*2;
else
gain -= dev->ee->lna_gain_5ghz[2]*2;
} else {
gain -= dev->ee->lna_gain_2ghz*2;
}
gain = FIELD_GET(MT_BBP_AGC_GAIN, val);
gain -= dev->caldata.lna_gain * 2;
val &= ~MT_BBP_AGC_GAIN; val &= ~MT_BBP_AGC_GAIN;
val |= FIELD_PREP(MT_BBP_AGC_GAIN, gain); val |= FIELD_PREP(MT_BBP_AGC_GAIN, gain);
mt76_wr(dev, pair->reg, val); mt76_wr(dev, pair->reg, val);
...@@ -575,43 +548,24 @@ mt76x0_phy_set_chan_bbp_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_ban ...@@ -575,43 +548,24 @@ mt76x0_phy_set_chan_bbp_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_ban
} }
} }
#if 0 static void mt76x0_ant_select(struct mt76x0_dev *dev)
static void
mt76x0_extra_power_over_mac(struct mt76x0_dev *dev)
{
u32 val;
val = ((mt76_rr(dev, MT_TX_PWR_CFG_1) & 0x00003f00) >> 8);
val |= ((mt76_rr(dev, MT_TX_PWR_CFG_2) & 0x00003f00) << 8);
mt76_wr(dev, MT_TX_PWR_CFG_7, val);
/* TODO: fix VHT */
val = ((mt76_rr(dev, MT_TX_PWR_CFG_3) & 0x0000ff00) >> 8);
mt76_wr(dev, MT_TX_PWR_CFG_8, val);
val = ((mt76_rr(dev, MT_TX_PWR_CFG_4) & 0x0000ff00) >> 8);
mt76_wr(dev, MT_TX_PWR_CFG_9, val);
}
static void
mt76x0_phy_set_tx_power(struct mt76x0_dev *dev, u8 channel, u8 rf_bw_band)
{ {
u32 val; struct ieee80211_channel *chan = dev->mt76.chandef.chan;
int i;
int bw = (rf_bw_band & RF_BW_20) ? 0 : 1;
for (i = 0; i < 4; i++) { /* single antenna mode */
if (channel <= 14) if (chan->band == NL80211_BAND_2GHZ) {
val = dev->ee->tx_pwr_cfg_2g[i][bw]; mt76_rmw(dev, MT_COEXCFG3,
else BIT(5) | BIT(4) | BIT(3) | BIT(2), BIT(1));
val = dev->ee->tx_pwr_cfg_5g[i][bw]; mt76_rmw(dev, MT_WLAN_FUN_CTRL, BIT(5), BIT(6));
} else {
mt76_wr(dev, MT_TX_PWR_CFG_0 + 4*i, val); mt76_rmw(dev, MT_COEXCFG3, BIT(5) | BIT(2),
BIT(4) | BIT(3));
mt76_clear(dev, MT_WLAN_FUN_CTRL,
BIT(6) | BIT(5));
} }
mt76_clear(dev, MT_CMB_CTRL, BIT(14) | BIT(12));
mt76x0_extra_power_over_mac(dev); mt76_clear(dev, MT_COEXCFG0, BIT(2));
} }
#endif
static void static void
mt76x0_bbp_set_bw(struct mt76x0_dev *dev, enum nl80211_chan_width width) mt76x0_bbp_set_bw(struct mt76x0_dev *dev, enum nl80211_chan_width width)
...@@ -644,31 +598,20 @@ mt76x0_bbp_set_bw(struct mt76x0_dev *dev, enum nl80211_chan_width width) ...@@ -644,31 +598,20 @@ mt76x0_bbp_set_bw(struct mt76x0_dev *dev, enum nl80211_chan_width width)
mt76x02_mcu_function_select(&dev->mt76, BW_SETTING, bw, false); mt76x02_mcu_function_select(&dev->mt76, BW_SETTING, bw, false);
} }
static void void mt76x0_phy_set_txpower(struct mt76x0_dev *dev)
mt76x0_phy_set_chan_pwr(struct mt76x0_dev *dev, u8 channel)
{ {
static const int mt76x0_tx_pwr_ch_list[] = { struct mt76_rate_power *t = &dev->mt76.rate_power;
1,2,3,4,5,6,7,8,9,10,11,12,13,14, u8 info[2];
36,38,40,44,46,48,52,54,56,60,62,64,
100,102,104,108,110,112,116,118,120,124,126,128,132,134,136,140,
149,151,153,157,159,161,165,167,169,171,173,
42,58,106,122,155
};
int i;
u32 val;
for (i = 0; i < ARRAY_SIZE(mt76x0_tx_pwr_ch_list); i++) mt76x0_get_power_info(dev, info);
if (mt76x0_tx_pwr_ch_list[i] == channel) mt76x0_get_tx_power_per_rate(dev);
break;
if (WARN_ON(i == ARRAY_SIZE(mt76x0_tx_pwr_ch_list))) mt76x02_add_rate_power_offset(t, info[0]);
return; mt76x02_limit_rate_power(t, dev->mt76.txpower_conf);
dev->mt76.txpower_cur = mt76x02_get_max_rate_power(t);
mt76x02_add_rate_power_offset(t, -info[0]);
val = mt76_rr(dev, MT_TX_ALC_CFG_0); mt76x02_phy_set_txpower(&dev->mt76, info[0], info[1]);
val &= ~0x3f3f;
val |= dev->ee->tx_pwr_per_chan[i];
val |= 0x2f2f << 16;
mt76_wr(dev, MT_TX_ALC_CFG_0, val);
} }
static int static int
...@@ -707,6 +650,7 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev, ...@@ -707,6 +650,7 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev,
freq1 = chandef->center_freq1; freq1 = chandef->center_freq1;
channel = chandef->chan->hw_value; channel = chandef->chan->hw_value;
rf_bw_band = (channel <= 14) ? RF_G_BAND : RF_A_BAND; rf_bw_band = (channel <= 14) ? RF_G_BAND : RF_A_BAND;
dev->mt76.chandef = *chandef;
switch (chandef->width) { switch (chandef->width) {
case NL80211_CHAN_WIDTH_40: case NL80211_CHAN_WIDTH_40:
...@@ -733,6 +677,7 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev, ...@@ -733,6 +677,7 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev,
mt76x0_bbp_set_bw(dev, chandef->width); mt76x0_bbp_set_bw(dev, chandef->width);
mt76x0_bbp_set_ctrlch(dev, chandef->width, ch_group_index); mt76x0_bbp_set_ctrlch(dev, chandef->width, ch_group_index);
mt76x0_mac_set_ctrlch(dev, ch_group_index & 1); mt76x0_mac_set_ctrlch(dev, ch_group_index & 1);
mt76x0_ant_select(dev);
mt76_rmw(dev, MT_EXT_CCA_CFG, mt76_rmw(dev, MT_EXT_CCA_CFG,
(MT_EXT_CCA_CFG_CCA0 | (MT_EXT_CCA_CFG_CCA0 |
...@@ -744,6 +689,7 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev, ...@@ -744,6 +689,7 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev,
mt76x0_phy_set_band(dev, chandef->chan->band); mt76x0_phy_set_band(dev, chandef->chan->band);
mt76x0_phy_set_chan_rf_params(dev, channel, rf_bw_band); mt76x0_phy_set_chan_rf_params(dev, channel, rf_bw_band);
mt76x0_read_rx_gain(dev);
/* set Japan Tx filter at channel 14 */ /* set Japan Tx filter at channel 14 */
val = mt76_rr(dev, MT_BBP(CORE, 1)); val = mt76_rr(dev, MT_BBP(CORE, 1));
...@@ -762,9 +708,8 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev, ...@@ -762,9 +708,8 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev,
if (scan) if (scan)
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, 1, false); mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, 1, false);
mt76x0_phy_set_chan_pwr(dev, channel); mt76x0_phy_set_txpower(dev);
dev->mt76.chandef = *chandef;
return 0; return 0;
} }
...@@ -863,7 +808,7 @@ static void mt76x0_temp_sensor(struct mt76x0_dev *dev) ...@@ -863,7 +808,7 @@ static void mt76x0_temp_sensor(struct mt76x0_dev *dev)
else else
sval |= 0xffffff00; /* Negative */ sval |= 0xffffff00; /* Negative */
temp = (35 * (sval - dev->ee->temp_off))/ 10 + 25; temp = (35 * (sval - dev->caldata.temp_offset)) / 10 + 25;
done: done:
rf_wr(dev, MT_RF(7, 73), rf_b7_73); rf_wr(dev, MT_RF(7, 73), rf_b7_73);
...@@ -910,32 +855,6 @@ void mt76x0_phy_con_cal_onoff(struct mt76x0_dev *dev, ...@@ -910,32 +855,6 @@ void mt76x0_phy_con_cal_onoff(struct mt76x0_dev *dev,
spin_unlock_bh(&dev->con_mon_lock); spin_unlock_bh(&dev->con_mon_lock);
} }
static void
mt76x0_set_rx_chains(struct mt76x0_dev *dev)
{
u32 val;
val = mt76_rr(dev, MT_BBP(AGC, 0));
val &= ~(BIT(3) | BIT(4));
if (dev->chainmask & BIT(1))
val |= BIT(3);
mt76_wr(dev, MT_BBP(AGC, 0), val);
mb();
val = mt76_rr(dev, MT_BBP(AGC, 0));
}
static void
mt76x0_set_tx_dac(struct mt76x0_dev *dev)
{
if (dev->chainmask & BIT(1))
mt76_set(dev, MT_BBP(TXBE, 5), 3);
else
mt76_clear(dev, MT_BBP(TXBE, 5), 3);
}
static void static void
mt76x0_rf_init(struct mt76x0_dev *dev) mt76x0_rf_init(struct mt76x0_dev *dev)
{ {
...@@ -969,7 +888,8 @@ mt76x0_rf_init(struct mt76x0_dev *dev) ...@@ -969,7 +888,8 @@ mt76x0_rf_init(struct mt76x0_dev *dev)
E1: B0.R22<6:0>: xo_cxo<6:0> E1: B0.R22<6:0>: xo_cxo<6:0>
E2: B0.R21<0>: xo_cxo<0>, B0.R22<7:0>: xo_cxo<8:1> E2: B0.R21<0>: xo_cxo<0>, B0.R22<7:0>: xo_cxo<8:1>
*/ */
rf_wr(dev, MT_RF(0, 22), min_t(u8, dev->ee->rf_freq_off, 0xBF)); rf_wr(dev, MT_RF(0, 22),
min_t(u8, dev->caldata.freq_offset, 0xbf));
val = rf_rr(dev, MT_RF(0, 22)); val = rf_rr(dev, MT_RF(0, 22));
/* /*
...@@ -989,23 +909,11 @@ mt76x0_rf_init(struct mt76x0_dev *dev) ...@@ -989,23 +909,11 @@ mt76x0_rf_init(struct mt76x0_dev *dev)
rf_set(dev, MT_RF(0, 4), 0x80); rf_set(dev, MT_RF(0, 4), 0x80);
} }
static void mt76x0_ant_select(struct mt76x0_dev *dev)
{
/* Single antenna mode. */
mt76_rmw(dev, MT_WLAN_FUN_CTRL, BIT(5), BIT(6));
mt76_clear(dev, MT_CMB_CTRL, BIT(14) | BIT(12));
mt76_clear(dev, MT_COEXCFG0, BIT(2));
mt76_rmw(dev, MT_COEXCFG3, BIT(5) | BIT(4) | BIT(3) | BIT(2), BIT(1));
}
void mt76x0_phy_init(struct mt76x0_dev *dev) void mt76x0_phy_init(struct mt76x0_dev *dev)
{ {
INIT_DELAYED_WORK(&dev->cal_work, mt76x0_phy_calibrate); INIT_DELAYED_WORK(&dev->cal_work, mt76x0_phy_calibrate);
mt76x0_ant_select(dev);
mt76x0_rf_init(dev); mt76x0_rf_init(dev);
mt76x02_phy_set_rxpath(&dev->mt76);
mt76x0_set_rx_chains(dev); mt76x02_phy_set_txdac(&dev->mt76);
mt76x0_set_tx_dac(dev);
} }
...@@ -17,10 +17,10 @@ ...@@ -17,10 +17,10 @@
#include "../mt76x02_util.h" #include "../mt76x02_util.h"
#include "../mt76x02_usb.h" #include "../mt76x02_usb.h"
static struct mt76x02_txwi * struct mt76x02_txwi *
mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb, mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb,
struct ieee80211_sta *sta, struct mt76_wcid *wcid, struct ieee80211_sta *sta, struct mt76_wcid *wcid,
int pkt_len) int pkt_len)
{ {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_rate *rate = &info->control.rates[0]; struct ieee80211_tx_rate *rate = &info->control.rates[0];
...@@ -53,6 +53,7 @@ mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb, ...@@ -53,6 +53,7 @@ mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb,
return txwi; return txwi;
} }
EXPORT_SYMBOL_GPL(mt76x0_push_txwi);
void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
struct sk_buff *skb) struct sk_buff *skb)
...@@ -81,22 +82,7 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, ...@@ -81,22 +82,7 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
mt76_tx(&dev->mt76, control->sta, wcid, skb); mt76_tx(&dev->mt76, control->sta, wcid, skb);
} }
EXPORT_SYMBOL_GPL(mt76x0_tx);
int mt76x0_tx_prepare_skb(struct mt76_dev *mdev, void *data,
struct sk_buff *skb, struct mt76_queue *q,
struct mt76_wcid *wcid, struct ieee80211_sta *sta,
u32 *tx_info)
{
struct mt76x0_dev *dev = container_of(mdev, struct mt76x0_dev, mt76);
struct mt76x02_txwi *txwi;
int len = skb->len;
mt76x02_insert_hdr_pad(skb);
txwi = mt76x0_push_txwi(dev, skb, sta, wcid, len);
return mt76x02u_set_txinfo(skb, wcid, q2ep(q->hw_idx));
}
EXPORT_SYMBOL_GPL(mt76x0_tx_prepare_skb);
void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb) struct sk_buff *skb)
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/firmware.h>
#include <linux/usb.h> #include <linux/usb.h>
#include "mt76x0.h" #include "mt76x0.h"
...@@ -22,8 +21,6 @@ ...@@ -22,8 +21,6 @@
#include "../mt76x02_util.h" #include "../mt76x02_util.h"
#include "../mt76x02_usb.h" #include "../mt76x02_usb.h"
#define MT7610U_FIRMWARE "mediatek/mt7610u.bin"
static struct usb_device_id mt76x0_device_table[] = { static struct usb_device_id mt76x0_device_table[] = {
{ USB_DEVICE(0x148F, 0x7610) }, /* MT7610U */ { USB_DEVICE(0x148F, 0x7610) }, /* MT7610U */
{ USB_DEVICE(0x13B1, 0x003E) }, /* Linksys AE6000 */ { USB_DEVICE(0x13B1, 0x003E) }, /* Linksys AE6000 */
...@@ -45,174 +42,195 @@ static struct usb_device_id mt76x0_device_table[] = { ...@@ -45,174 +42,195 @@ static struct usb_device_id mt76x0_device_table[] = {
{ USB_DEVICE(0x20f4, 0x806b) }, /* TRENDnet TEW-806UBH */ { USB_DEVICE(0x20f4, 0x806b) }, /* TRENDnet TEW-806UBH */
{ USB_DEVICE(0x7392, 0xc711) }, /* Devolo Wifi ac Stick */ { USB_DEVICE(0x7392, 0xc711) }, /* Devolo Wifi ac Stick */
{ USB_DEVICE(0x0df6, 0x0079) }, /* Sitecom Europe B.V. ac Stick */ { USB_DEVICE(0x0df6, 0x0079) }, /* Sitecom Europe B.V. ac Stick */
{ USB_DEVICE(0x2357, 0x0105) }, /* TP-LINK Archer T1U */ { USB_DEVICE(0x2357, 0x0105),
.driver_info = 1, }, /* TP-LINK Archer T1U */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0E8D, 0x7630, 0xff, 0x2, 0xff)}, /* MT7630U */ { USB_DEVICE_AND_INTERFACE_INFO(0x0E8D, 0x7630, 0xff, 0x2, 0xff)}, /* MT7630U */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0E8D, 0x7650, 0xff, 0x2, 0xff)}, /* MT7650U */ { USB_DEVICE_AND_INTERFACE_INFO(0x0E8D, 0x7650, 0xff, 0x2, 0xff)}, /* MT7650U */
{ 0, } { 0, }
}; };
#define MCU_FW_URB_MAX_PAYLOAD 0x38f8 static void mt76x0_init_usb_dma(struct mt76x0_dev *dev)
#define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12)
static inline int mt76x0_firmware_running(struct mt76x0_dev *dev)
{ {
return mt76_rr(dev, MT_MCU_COM_REG0) == 1; u32 val;
}
static int val = mt76_rr(dev, MT_USB_DMA_CFG);
mt76x0u_upload_firmware(struct mt76x0_dev *dev,
const struct mt76x02_fw_header *hdr)
{
u8 *fw_payload = (u8 *)(hdr + 1);
u32 ilm_len, dlm_len;
void *ivb;
int err;
ivb = kmemdup(fw_payload, MT_MCU_IVB_SIZE, GFP_KERNEL); val |= MT_USB_DMA_CFG_RX_BULK_EN |
if (!ivb) MT_USB_DMA_CFG_TX_BULK_EN;
return -ENOMEM;
ilm_len = le32_to_cpu(hdr->ilm_len) - MT_MCU_IVB_SIZE; /* disable AGGR_BULK_RX in order to receive one
dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %u\n", * frame in each rx urb and avoid copies
ilm_len, MT_MCU_IVB_SIZE); */
err = mt76x02u_mcu_fw_send_data(&dev->mt76, val &= ~MT_USB_DMA_CFG_RX_BULK_AGG_EN;
fw_payload + MT_MCU_IVB_SIZE, mt76_wr(dev, MT_USB_DMA_CFG, val);
ilm_len, MCU_FW_URB_MAX_PAYLOAD,
MT_MCU_IVB_SIZE);
if (err)
goto out;
dlm_len = le32_to_cpu(hdr->dlm_len); val = mt76_rr(dev, MT_COM_REG0);
dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len); if (val & 1)
err = mt76x02u_mcu_fw_send_data(&dev->mt76, dev_dbg(dev->mt76.dev, "MCU not ready\n");
fw_payload + le32_to_cpu(hdr->ilm_len),
dlm_len, MCU_FW_URB_MAX_PAYLOAD,
MT_MCU_DLM_OFFSET);
if (err)
goto out;
err = mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, val = mt76_rr(dev, MT_USB_DMA_CFG);
USB_DIR_OUT | USB_TYPE_VENDOR,
0x12, 0, ivb, MT_MCU_IVB_SIZE);
if (err < 0)
goto out;
if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 1000)) { val |= MT_USB_DMA_CFG_RX_DROP_OR_PAD;
dev_err(dev->mt76.dev, "Firmware failed to start\n"); mt76_wr(dev, MT_USB_DMA_CFG, val);
err = -ETIMEDOUT; val &= ~MT_USB_DMA_CFG_RX_DROP_OR_PAD;
goto out; mt76_wr(dev, MT_USB_DMA_CFG, val);
} }
static void mt76x0u_cleanup(struct mt76x0_dev *dev)
{
clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
mt76x0_chip_onoff(dev, false, false);
mt76u_queues_deinit(&dev->mt76);
mt76u_mcu_deinit(&dev->mt76);
}
dev_dbg(dev->mt76.dev, "Firmware running!\n"); static void mt76x0u_mac_stop(struct mt76x0_dev *dev)
{
if (test_bit(MT76_REMOVED, &dev->mt76.state))
return;
out: clear_bit(MT76_STATE_RUNNING, &dev->mt76.state);
kfree(ivb); cancel_delayed_work_sync(&dev->cal_work);
cancel_delayed_work_sync(&dev->mac_work);
mt76u_stop_stat_wk(&dev->mt76);
return err; mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN |
MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN |
MT_BEACON_TIME_CFG_BEACON_TX);
if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000))
dev_warn(dev->mt76.dev, "TX DMA did not stop\n");
mt76x0_mac_stop(dev);
if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000))
dev_warn(dev->mt76.dev, "RX DMA did not stop\n");
} }
static int mt76x0u_load_firmware(struct mt76x0_dev *dev) static int mt76x0u_start(struct ieee80211_hw *hw)
{ {
const struct firmware *fw; struct mt76x0_dev *dev = hw->priv;
const struct mt76x02_fw_header *hdr; int ret;
int len, ret;
u32 val;
mt76_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN |
MT_USB_DMA_CFG_TX_BULK_EN));
if (mt76x0_firmware_running(dev)) mutex_lock(&dev->mt76.mutex);
return 0;
ret = request_firmware(&fw, MT7610U_FIRMWARE, dev->mt76.dev); ret = mt76x0_mac_start(dev);
if (ret) if (ret)
return ret; goto out;
if (!fw || !fw->data || fw->size < sizeof(*hdr)) ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work,
goto err_inv_fw; MT_CALIBRATE_INTERVAL);
ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work,
MT_CALIBRATE_INTERVAL);
set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
hdr = (const struct mt76x02_fw_header *)fw->data; out:
mutex_unlock(&dev->mt76.mutex);
return ret;
}
if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE) static void mt76x0u_stop(struct ieee80211_hw *hw)
goto err_inv_fw; {
struct mt76x0_dev *dev = hw->priv;
len = sizeof(*hdr); mutex_lock(&dev->mt76.mutex);
len += le32_to_cpu(hdr->ilm_len); mt76x0u_mac_stop(dev);
len += le32_to_cpu(hdr->dlm_len); mutex_unlock(&dev->mt76.mutex);
}
if (fw->size != len) static const struct ieee80211_ops mt76x0u_ops = {
goto err_inv_fw; .tx = mt76x0_tx,
.start = mt76x0u_start,
.stop = mt76x0u_stop,
.add_interface = mt76x02_add_interface,
.remove_interface = mt76x02_remove_interface,
.config = mt76x0_config,
.configure_filter = mt76x02_configure_filter,
.bss_info_changed = mt76x0_bss_info_changed,
.sta_add = mt76x02_sta_add,
.sta_remove = mt76x02_sta_remove,
.set_key = mt76x02_set_key,
.conf_tx = mt76x02_conf_tx,
.sw_scan_start = mt76x0_sw_scan,
.sw_scan_complete = mt76x0_sw_scan_complete,
.ampdu_action = mt76x02_ampdu_action,
.sta_rate_tbl_update = mt76x02_sta_rate_tbl_update,
.set_rts_threshold = mt76x0_set_rts_threshold,
.wake_tx_queue = mt76_wake_tx_queue,
};
static int mt76x0u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
struct sk_buff *skb, struct mt76_queue *q,
struct mt76_wcid *wcid, struct ieee80211_sta *sta,
u32 *tx_info)
{
struct mt76x0_dev *dev = container_of(mdev, struct mt76x0_dev, mt76);
struct mt76x02_txwi *txwi;
int len = skb->len;
val = le16_to_cpu(hdr->fw_ver); mt76x02_insert_hdr_pad(skb);
dev_dbg(dev->mt76.dev, txwi = mt76x0_push_txwi(dev, skb, sta, wcid, len);
"Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n",
(val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf,
le16_to_cpu(hdr->build_ver), hdr->build_time);
len = le32_to_cpu(hdr->ilm_len); return mt76x02u_set_txinfo(skb, wcid, q2ep(q->hw_idx));
}
mt76_wr(dev, 0x1004, 0x2c); static int mt76x0u_register_device(struct mt76x0_dev *dev)
{
struct ieee80211_hw *hw = dev->mt76.hw;
int err;
mt76_set(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | err = mt76u_mcu_init_rx(&dev->mt76);
MT_USB_DMA_CFG_TX_BULK_EN) | if (err < 0)
FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20)); return err;
mt76x02u_mcu_fw_reset(&dev->mt76);
msleep(5);
/*
mt76x0_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN |
MT_PBF_CFG_TX1Q_EN |
MT_PBF_CFG_TX2Q_EN |
MT_PBF_CFG_TX3Q_EN));
*/
mt76_wr(dev, MT_FCE_PSE_CTRL, 1);
/* FCE tx_fs_base_ptr */
mt76_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230);
/* FCE tx_fs_max_cnt */
mt76_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 1);
/* FCE pdma enable */
mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44);
/* FCE skip_fs_en */
mt76_wr(dev, MT_FCE_SKIP_FS, 3);
val = mt76_rr(dev, MT_USB_DMA_CFG); err = mt76u_alloc_queues(&dev->mt76);
val |= MT_USB_DMA_CFG_UDMA_TX_WL_DROP; if (err < 0)
mt76_wr(dev, MT_USB_DMA_CFG, val); return err;
val &= ~MT_USB_DMA_CFG_UDMA_TX_WL_DROP;
mt76_wr(dev, MT_USB_DMA_CFG, val);
ret = mt76x0u_upload_firmware(dev, hdr); mt76x0_chip_onoff(dev, true, true);
release_firmware(fw); if (!mt76x02_wait_for_mac(&dev->mt76)) {
err = -ETIMEDOUT;
goto err;
}
mt76_wr(dev, MT_FCE_PSE_CTRL, 1); err = mt76x0u_mcu_init(dev);
if (err < 0)
goto err;
return ret; mt76x0_init_usb_dma(dev);
err = mt76x0_init_hardware(dev);
if (err < 0)
goto err;
err_inv_fw: mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e);
dev_err(dev->mt76.dev, "Invalid firmware image\n"); mt76_wr(dev, MT_TXOP_CTRL_CFG,
release_firmware(fw); FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) |
return -ENOENT; FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58));
}
static int mt76x0u_mcu_init(struct mt76x0_dev *dev) err = mt76x0_register_device(dev);
{ if (err < 0)
int ret; goto err;
ret = mt76x0u_load_firmware(dev); /* check hw sg support in order to enable AMSDU */
if (ret < 0) if (mt76u_check_sg(&dev->mt76))
return ret; hw->max_tx_fragments = MT_SG_MAX_SIZE;
else
hw->max_tx_fragments = 1;
set_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state); set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
return 0; return 0;
err:
mt76x0u_cleanup(dev);
return err;
} }
static int mt76x0u_probe(struct usb_interface *usb_intf, static int mt76x0u_probe(struct usb_interface *usb_intf,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
static const struct mt76_driver_ops drv_ops = { static const struct mt76_driver_ops drv_ops = {
.tx_prepare_skb = mt76x0_tx_prepare_skb, .tx_prepare_skb = mt76x0u_tx_prepare_skb,
.tx_complete_skb = mt76x02_tx_complete_skb, .tx_complete_skb = mt76x02_tx_complete_skb,
.tx_status_data = mt76x02_tx_status_data, .tx_status_data = mt76x02_tx_status_data,
.rx_skb = mt76x0_queue_rx_skb, .rx_skb = mt76x0_queue_rx_skb,
...@@ -222,10 +240,15 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, ...@@ -222,10 +240,15 @@ static int mt76x0u_probe(struct usb_interface *usb_intf,
u32 asic_rev, mac_rev; u32 asic_rev, mac_rev;
int ret; int ret;
dev = mt76x0_alloc_device(&usb_intf->dev, &drv_ops); dev = mt76x0_alloc_device(&usb_intf->dev, &drv_ops,
&mt76x0u_ops);
if (!dev) if (!dev)
return -ENOMEM; return -ENOMEM;
/* Quirk for Archer T1U */
if (id->driver_info)
dev->no_2ghz = true;
usb_dev = usb_get_dev(usb_dev); usb_dev = usb_get_dev(usb_dev);
usb_reset_device(usb_dev); usb_reset_device(usb_dev);
...@@ -253,32 +276,12 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, ...@@ -253,32 +276,12 @@ static int mt76x0u_probe(struct usb_interface *usb_intf,
if (!(mt76_rr(dev, MT_EFUSE_CTRL) & MT_EFUSE_CTRL_SEL)) if (!(mt76_rr(dev, MT_EFUSE_CTRL) & MT_EFUSE_CTRL_SEL))
dev_warn(dev->mt76.dev, "Warning: eFUSE not present\n"); dev_warn(dev->mt76.dev, "Warning: eFUSE not present\n");
ret = mt76u_mcu_init_rx(&dev->mt76); ret = mt76x0u_register_device(dev);
if (ret < 0)
goto err;
ret = mt76u_alloc_queues(&dev->mt76);
if (ret < 0) if (ret < 0)
goto err; goto err;
mt76x0_chip_onoff(dev, true, true);
if (!mt76x02_wait_for_mac(&dev->mt76))
return -ETIMEDOUT;
ret = mt76x0u_mcu_init(dev);
if (ret)
goto err_hw;
ret = mt76x0_register_device(dev);
if (ret)
goto err_hw;
set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
return 0; return 0;
err_hw:
mt76x0_cleanup(dev);
err: err:
usb_set_intfdata(usb_intf, NULL); usb_set_intfdata(usb_intf, NULL);
usb_put_dev(interface_to_usbdev(usb_intf)); usb_put_dev(interface_to_usbdev(usb_intf));
...@@ -296,7 +299,7 @@ static void mt76x0_disconnect(struct usb_interface *usb_intf) ...@@ -296,7 +299,7 @@ static void mt76x0_disconnect(struct usb_interface *usb_intf)
return; return;
ieee80211_unregister_hw(dev->mt76.hw); ieee80211_unregister_hw(dev->mt76.hw);
mt76x0_cleanup(dev); mt76x0u_cleanup(dev);
usb_set_intfdata(usb_intf, NULL); usb_set_intfdata(usb_intf, NULL);
usb_put_dev(interface_to_usbdev(usb_intf)); usb_put_dev(interface_to_usbdev(usb_intf));
...@@ -311,7 +314,7 @@ static int __maybe_unused mt76x0_suspend(struct usb_interface *usb_intf, ...@@ -311,7 +314,7 @@ static int __maybe_unused mt76x0_suspend(struct usb_interface *usb_intf,
struct mt76_usb *usb = &dev->mt76.usb; struct mt76_usb *usb = &dev->mt76.usb;
mt76u_stop_queues(&dev->mt76); mt76u_stop_queues(&dev->mt76);
mt76x0_mac_stop(dev); mt76x0u_mac_stop(dev);
usb_kill_urb(usb->mcu.res.urb); usb_kill_urb(usb->mcu.res.urb);
return 0; return 0;
...@@ -345,12 +348,11 @@ static int __maybe_unused mt76x0_resume(struct usb_interface *usb_intf) ...@@ -345,12 +348,11 @@ static int __maybe_unused mt76x0_resume(struct usb_interface *usb_intf)
return 0; return 0;
err: err:
mt76x0_cleanup(dev); mt76x0u_cleanup(dev);
return ret; return ret;
} }
MODULE_DEVICE_TABLE(usb, mt76x0_device_table); MODULE_DEVICE_TABLE(usb, mt76x0_device_table);
MODULE_FIRMWARE(MT7610U_FIRMWARE);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static struct usb_driver mt76x0_driver = { static struct usb_driver mt76x0_driver = {
......
/*
* Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/firmware.h>
#include "mt76x0.h"
#include "mcu.h"
#include "../mt76x02_usb.h"
#define MCU_FW_URB_MAX_PAYLOAD 0x38f8
#define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12)
#define MT7610U_FIRMWARE "mediatek/mt7610u.bin"
static int
mt76x0u_upload_firmware(struct mt76x0_dev *dev,
const struct mt76x02_fw_header *hdr)
{
u8 *fw_payload = (u8 *)(hdr + 1);
u32 ilm_len, dlm_len;
void *ivb;
int err;
ivb = kmemdup(fw_payload, MT_MCU_IVB_SIZE, GFP_KERNEL);
if (!ivb)
return -ENOMEM;
ilm_len = le32_to_cpu(hdr->ilm_len) - MT_MCU_IVB_SIZE;
dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %u\n",
ilm_len, MT_MCU_IVB_SIZE);
err = mt76x02u_mcu_fw_send_data(&dev->mt76,
fw_payload + MT_MCU_IVB_SIZE,
ilm_len, MCU_FW_URB_MAX_PAYLOAD,
MT_MCU_IVB_SIZE);
if (err)
goto out;
dlm_len = le32_to_cpu(hdr->dlm_len);
dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len);
err = mt76x02u_mcu_fw_send_data(&dev->mt76,
fw_payload + le32_to_cpu(hdr->ilm_len),
dlm_len, MCU_FW_URB_MAX_PAYLOAD,
MT_MCU_DLM_OFFSET);
if (err)
goto out;
err = mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE,
USB_DIR_OUT | USB_TYPE_VENDOR,
0x12, 0, ivb, MT_MCU_IVB_SIZE);
if (err < 0)
goto out;
if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 1000)) {
dev_err(dev->mt76.dev, "Firmware failed to start\n");
err = -ETIMEDOUT;
goto out;
}
dev_dbg(dev->mt76.dev, "Firmware running!\n");
out:
kfree(ivb);
return err;
}
static int mt76x0u_load_firmware(struct mt76x0_dev *dev)
{
const struct firmware *fw;
const struct mt76x02_fw_header *hdr;
int len, ret;
u32 val;
mt76_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN |
MT_USB_DMA_CFG_TX_BULK_EN));
if (mt76x0_firmware_running(dev))
return 0;
ret = request_firmware(&fw, MT7610U_FIRMWARE, dev->mt76.dev);
if (ret)
return ret;
if (!fw || !fw->data || fw->size < sizeof(*hdr))
goto err_inv_fw;
hdr = (const struct mt76x02_fw_header *)fw->data;
if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE)
goto err_inv_fw;
len = sizeof(*hdr);
len += le32_to_cpu(hdr->ilm_len);
len += le32_to_cpu(hdr->dlm_len);
if (fw->size != len)
goto err_inv_fw;
val = le16_to_cpu(hdr->fw_ver);
dev_dbg(dev->mt76.dev,
"Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n",
(val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf,
le16_to_cpu(hdr->build_ver), hdr->build_time);
len = le32_to_cpu(hdr->ilm_len);
mt76_wr(dev, 0x1004, 0x2c);
mt76_set(dev, MT_USB_DMA_CFG,
(MT_USB_DMA_CFG_RX_BULK_EN | MT_USB_DMA_CFG_TX_BULK_EN) |
FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20));
mt76x02u_mcu_fw_reset(&dev->mt76);
usleep_range(5000, 6000);
/*
mt76x0_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN |
MT_PBF_CFG_TX1Q_EN |
MT_PBF_CFG_TX2Q_EN |
MT_PBF_CFG_TX3Q_EN));
*/
mt76_wr(dev, MT_FCE_PSE_CTRL, 1);
/* FCE tx_fs_base_ptr */
mt76_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230);
/* FCE tx_fs_max_cnt */
mt76_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 1);
/* FCE pdma enable */
mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44);
/* FCE skip_fs_en */
mt76_wr(dev, MT_FCE_SKIP_FS, 3);
val = mt76_rr(dev, MT_USB_DMA_CFG);
val |= MT_USB_DMA_CFG_UDMA_TX_WL_DROP;
mt76_wr(dev, MT_USB_DMA_CFG, val);
val &= ~MT_USB_DMA_CFG_UDMA_TX_WL_DROP;
mt76_wr(dev, MT_USB_DMA_CFG, val);
ret = mt76x0u_upload_firmware(dev, hdr);
release_firmware(fw);
mt76_wr(dev, MT_FCE_PSE_CTRL, 1);
return ret;
err_inv_fw:
dev_err(dev->mt76.dev, "Invalid firmware image\n");
release_firmware(fw);
return -ENOENT;
}
int mt76x0u_mcu_init(struct mt76x0_dev *dev)
{
int ret;
ret = mt76x0u_load_firmware(dev);
if (ret < 0)
return ret;
set_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state);
return 0;
}
MODULE_FIRMWARE(MT7610U_FIRMWARE);
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#define __MT76x02_DMA_H #define __MT76x02_DMA_H
#include "dma.h" #include "dma.h"
#include "mt76x02_regs.h"
#define MT_TXD_INFO_LEN GENMASK(15, 0) #define MT_TXD_INFO_LEN GENMASK(15, 0)
#define MT_TXD_INFO_NEXT_VLD BIT(16) #define MT_TXD_INFO_NEXT_VLD BIT(16)
...@@ -47,6 +48,9 @@ ...@@ -47,6 +48,9 @@
#define MT_MCU_MSG_TYPE GENMASK(31, 30) #define MT_MCU_MSG_TYPE GENMASK(31, 30)
#define MT_MCU_MSG_TYPE_CMD BIT(30) #define MT_MCU_MSG_TYPE_CMD BIT(30)
#define MT_RX_HEADROOM 32
#define MT76X02_RX_RING_SIZE 256
enum dma_msg_port { enum dma_msg_port {
WLAN_PORT, WLAN_PORT,
CPU_RX_PORT, CPU_RX_PORT,
...@@ -57,4 +61,17 @@ enum dma_msg_port { ...@@ -57,4 +61,17 @@ enum dma_msg_port {
DISCARD, DISCARD,
}; };
static inline bool
mt76x02_wait_for_wpdma(struct mt76_dev *dev, int timeout)
{
return __mt76_poll(dev, MT_WPDMA_GLO_CFG,
MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
MT_WPDMA_GLO_CFG_RX_DMA_BUSY,
0, timeout);
}
int mt76x02_dma_init(struct mt76_dev *dev);
void mt76x02_dma_enable(struct mt76_dev *dev);
void mt76x02_dma_disable(struct mt76_dev *dev);
#endif /* __MT76x02_DMA_H */ #endif /* __MT76x02_DMA_H */
/*
* Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <asm/unaligned.h>
#include "mt76.h"
#include "mt76x02_eeprom.h"
#include "mt76x02_regs.h"
static int
mt76x02_efuse_read(struct mt76_dev *dev, u16 addr, u8 *data,
enum mt76x02_eeprom_modes mode)
{
u32 val;
int i;
val = __mt76_rr(dev, MT_EFUSE_CTRL);
val &= ~(MT_EFUSE_CTRL_AIN |
MT_EFUSE_CTRL_MODE);
val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf);
val |= FIELD_PREP(MT_EFUSE_CTRL_MODE, mode);
val |= MT_EFUSE_CTRL_KICK;
__mt76_wr(dev, MT_EFUSE_CTRL, val);
if (!__mt76_poll_msec(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK,
0, 1000))
return -ETIMEDOUT;
udelay(2);
val = __mt76_rr(dev, MT_EFUSE_CTRL);
if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) {
memset(data, 0xff, 16);
return 0;
}
for (i = 0; i < 4; i++) {
val = __mt76_rr(dev, MT_EFUSE_DATA(i));
put_unaligned_le32(val, data + 4 * i);
}
return 0;
}
int mt76x02_get_efuse_data(struct mt76_dev *dev, u16 base, void *buf,
int len, enum mt76x02_eeprom_modes mode)
{
int ret, i;
for (i = 0; i + 16 <= len; i += 16) {
ret = mt76x02_efuse_read(dev, base + i, buf + i, mode);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(mt76x02_get_efuse_data);
void mt76x02_eeprom_parse_hw_cap(struct mt76_dev *dev)
{
u16 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0);
switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) {
case BOARD_TYPE_5GHZ:
dev->cap.has_5ghz = true;
break;
case BOARD_TYPE_2GHZ:
dev->cap.has_2ghz = true;
break;
default:
dev->cap.has_2ghz = true;
dev->cap.has_5ghz = true;
break;
}
}
EXPORT_SYMBOL_GPL(mt76x02_eeprom_parse_hw_cap);
bool mt76x02_ext_pa_enabled(struct mt76_dev *dev, enum nl80211_band band)
{
u16 conf0 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0);
if (band == NL80211_BAND_5GHZ)
return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G);
else
return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G);
}
EXPORT_SYMBOL_GPL(mt76x02_ext_pa_enabled);
void mt76x02_get_rx_gain(struct mt76_dev *dev, enum nl80211_band band,
u16 *rssi_offset, s8 *lna_2g, s8 *lna_5g)
{
u16 val;
val = mt76x02_eeprom_get(dev, MT_EE_LNA_GAIN);
*lna_2g = val & 0xff;
lna_5g[0] = val >> 8;
val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_1);
lna_5g[1] = val >> 8;
val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1);
lna_5g[2] = val >> 8;
if (!mt76x02_field_valid(lna_5g[1]))
lna_5g[1] = lna_5g[0];
if (!mt76x02_field_valid(lna_5g[2]))
lna_5g[2] = lna_5g[0];
if (band == NL80211_BAND_2GHZ)
*rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_0);
else
*rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_0);
}
EXPORT_SYMBOL_GPL(mt76x02_get_rx_gain);
u8 mt76x02_get_lna_gain(struct mt76_dev *dev,
s8 *lna_2g, s8 *lna_5g,
struct ieee80211_channel *chan)
{
u16 val;
u8 lna;
val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1);
if (val & MT_EE_NIC_CONF_1_LNA_EXT_2G)
*lna_2g = 0;
if (val & MT_EE_NIC_CONF_1_LNA_EXT_5G)
memset(lna_5g, 0, sizeof(s8) * 3);
if (chan->band == NL80211_BAND_2GHZ)
lna = *lna_2g;
else if (chan->hw_value <= 64)
lna = lna_5g[0];
else if (chan->hw_value <= 128)
lna = lna_5g[1];
else
lna = lna_5g[2];
return lna != 0xff ? lna : 0;
}
EXPORT_SYMBOL_GPL(mt76x02_get_lna_gain);
/*
* Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __MT76x02_EEPROM_H
#define __MT76x02_EEPROM_H
enum mt76x02_eeprom_field {
MT_EE_CHIP_ID = 0x000,
MT_EE_VERSION = 0x002,
MT_EE_MAC_ADDR = 0x004,
MT_EE_PCI_ID = 0x00A,
MT_EE_NIC_CONF_0 = 0x034,
MT_EE_NIC_CONF_1 = 0x036,
MT_EE_COUNTRY_REGION_5GHZ = 0x038,
MT_EE_COUNTRY_REGION_2GHZ = 0x039,
MT_EE_FREQ_OFFSET = 0x03a,
MT_EE_NIC_CONF_2 = 0x042,
MT_EE_XTAL_TRIM_1 = 0x03a,
MT_EE_XTAL_TRIM_2 = 0x09e,
MT_EE_LNA_GAIN = 0x044,
MT_EE_RSSI_OFFSET_2G_0 = 0x046,
MT_EE_RSSI_OFFSET_2G_1 = 0x048,
MT_EE_LNA_GAIN_5GHZ_1 = 0x049,
MT_EE_RSSI_OFFSET_5G_0 = 0x04a,
MT_EE_RSSI_OFFSET_5G_1 = 0x04c,
MT_EE_LNA_GAIN_5GHZ_2 = 0x04d,
MT_EE_TX_POWER_DELTA_BW40 = 0x050,
MT_EE_TX_POWER_DELTA_BW80 = 0x052,
MT_EE_TX_POWER_EXT_PA_5G = 0x054,
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_5G_6M = 0x0b2,
MT_EE_TX_POWER_OFDM_5G_24M = 0x0b4,
MT_EE_TX_POWER_HT_MCS0 = 0x0a6,
MT_EE_TX_POWER_HT_MCS4 = 0x0a8,
MT_EE_TX_POWER_HT_MCS8 = 0x0aa,
MT_EE_TX_POWER_HT_MCS12 = 0x0ac,
MT_EE_TX_POWER_VHT_MCS0 = 0x0ba,
MT_EE_TX_POWER_VHT_MCS4 = 0x0bc,
MT_EE_TX_POWER_VHT_MCS8 = 0x0be,
MT_EE_2G_TARGET_POWER = 0x0d0,
MT_EE_TEMP_OFFSET = 0x0d1,
MT_EE_5G_TARGET_POWER = 0x0d2,
MT_EE_TSSI_BOUND1 = 0x0d4,
MT_EE_TSSI_BOUND2 = 0x0d6,
MT_EE_TSSI_BOUND3 = 0x0d8,
MT_EE_TSSI_BOUND4 = 0x0da,
MT_EE_FREQ_OFFSET_COMPENSATION = 0x0db,
MT_EE_TSSI_BOUND5 = 0x0dc,
MT_EE_TX_POWER_BYRATE_BASE = 0x0de,
MT_EE_RF_TEMP_COMP_SLOPE_5G = 0x0f2,
MT_EE_RF_TEMP_COMP_SLOPE_2G = 0x0f4,
MT_EE_RF_2G_TSSI_OFF_TXPOWER = 0x0f6,
MT_EE_RF_2G_RX_HIGH_GAIN = 0x0f8,
MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN = 0x0fa,
MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN = 0x0fc,
MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN = 0x0fe,
MT_EE_BT_RCAL_RESULT = 0x138,
MT_EE_BT_VCDL_CALIBRATION = 0x13c,
MT_EE_BT_PMUCFG = 0x13e,
MT_EE_USAGE_MAP_START = 0x1e0,
MT_EE_USAGE_MAP_END = 0x1fc,
__MT_EE_MAX
};
#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_PA_TYPE GENMASK(9, 8)
#define MT_EE_NIC_CONF_0_PA_INT_2G BIT(8)
#define MT_EE_NIC_CONF_0_PA_INT_5G BIT(9)
#define MT_EE_NIC_CONF_0_PA_IO_CURRENT BIT(10)
#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_EFUSE_USAGE_MAP_SIZE (MT_EE_USAGE_MAP_END - \
MT_EE_USAGE_MAP_START + 1)
enum mt76x02_eeprom_modes {
MT_EE_READ,
MT_EE_PHYSICAL_READ,
};
enum mt76x02_board_type {
BOARD_TYPE_2GHZ = 1,
BOARD_TYPE_5GHZ = 2,
};
static inline bool mt76x02_field_valid(u8 val)
{
return val != 0 && val != 0xff;
}
static inline int
mt76x02_sign_extend(u32 val, unsigned int size)
{
bool sign = val & BIT(size - 1);
val &= BIT(size - 1) - 1;
return sign ? val : -val;
}
static inline int
mt76x02_sign_extend_optional(u32 val, unsigned int size)
{
bool enable = val & BIT(size);
return enable ? mt76x02_sign_extend(val, size) : 0;
}
static inline s8 mt76x02_rate_power_val(u8 val)
{
if (!mt76x02_field_valid(val))
return 0;
return mt76x02_sign_extend_optional(val, 7);
}
static inline int
mt76x02_eeprom_get(struct mt76_dev *dev,
enum mt76x02_eeprom_field field)
{
if ((field & 1) || field >= __MT_EE_MAX)
return -1;
return get_unaligned_le16(dev->eeprom.data + field);
}
static inline bool
mt76x02_temp_tx_alc_enabled(struct mt76_dev *dev)
{
u16 val;
val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G);
if (!(val & BIT(15)))
return false;
return mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) &
MT_EE_NIC_CONF_1_TEMP_TX_ALC;
}
static inline bool
mt76x02_tssi_enabled(struct mt76_dev *dev)
{
return !mt76x02_temp_tx_alc_enabled(dev) &&
(mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) &
MT_EE_NIC_CONF_1_TX_ALC_EN);
}
bool mt76x02_ext_pa_enabled(struct mt76_dev *dev, enum nl80211_band band);
int mt76x02_get_efuse_data(struct mt76_dev *dev, u16 base, void *buf,
int len, enum mt76x02_eeprom_modes mode);
void mt76x02_get_rx_gain(struct mt76_dev *dev, enum nl80211_band band,
u16 *rssi_offset, s8 *lna_2g, s8 *lna_5g);
u8 mt76x02_get_lna_gain(struct mt76_dev *dev,
s8 *lna_2g, s8 *lna_5g,
struct ieee80211_channel *chan);
void mt76x02_eeprom_parse_hw_cap(struct mt76_dev *dev);
#endif /* __MT76x02_EEPROM_H */
...@@ -502,3 +502,21 @@ mt76x02_mac_process_rate(struct mt76_rx_status *status, u16 rate) ...@@ -502,3 +502,21 @@ mt76x02_mac_process_rate(struct mt76_rx_status *status, u16 rate)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(mt76x02_mac_process_rate); EXPORT_SYMBOL_GPL(mt76x02_mac_process_rate);
void mt76x02_mac_setaddr(struct mt76_dev *dev, u8 *addr)
{
ether_addr_copy(dev->macaddr, addr);
if (!is_valid_ether_addr(dev->macaddr)) {
eth_random_addr(dev->macaddr);
dev_info(dev->dev,
"Invalid MAC address, using random address %pM\n",
dev->macaddr);
}
__mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr));
__mt76_wr(dev, MT_MAC_ADDR_DW1,
get_unaligned_le16(dev->macaddr + 4) |
FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
}
EXPORT_SYMBOL_GPL(mt76x02_mac_setaddr);
...@@ -165,7 +165,7 @@ static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev) ...@@ -165,7 +165,7 @@ static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev)
for (i = 0; i < 500; i++) { for (i = 0; i < 500; i++) {
if (test_bit(MT76_REMOVED, &dev->state)) if (test_bit(MT76_REMOVED, &dev->state))
return -EIO; return false;
switch (dev->bus->rr(dev, MAC_CSR0)) { switch (dev->bus->rr(dev, MAC_CSR0)) {
case 0: case 0:
...@@ -202,4 +202,5 @@ void mt76x02_send_tx_status(struct mt76_dev *dev, ...@@ -202,4 +202,5 @@ void mt76x02_send_tx_status(struct mt76_dev *dev,
struct mt76x02_tx_status *stat, u8 *update); struct mt76x02_tx_status *stat, u8 *update);
int int
mt76x02_mac_process_rate(struct mt76_rx_status *status, u16 rate); mt76x02_mac_process_rate(struct mt76_rx_status *status, u16 rate);
void mt76x02_mac_setaddr(struct mt76_dev *dev, u8 *addr);
#endif #endif
...@@ -211,3 +211,16 @@ int mt76x02_mcu_cleanup(struct mt76_dev *dev) ...@@ -211,3 +211,16 @@ int mt76x02_mcu_cleanup(struct mt76_dev *dev)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(mt76x02_mcu_cleanup); EXPORT_SYMBOL_GPL(mt76x02_mcu_cleanup);
void mt76x02_set_ethtool_fwver(struct mt76_dev *dev,
const struct mt76x02_fw_header *h)
{
u16 bld = le16_to_cpu(h->build_ver);
u16 ver = le16_to_cpu(h->fw_ver);
snprintf(dev->hw->wiphy->fw_version,
sizeof(dev->hw->wiphy->fw_version),
"%d.%d.%02d-b%x",
(ver >> 12) & 0xf, (ver >> 8) & 0xf, ver & 0xf, bld);
}
EXPORT_SYMBOL_GPL(mt76x02_set_ethtool_fwver);
...@@ -27,6 +27,15 @@ ...@@ -27,6 +27,15 @@
#define MT_INBAND_PACKET_MAX_LEN 192 #define MT_INBAND_PACKET_MAX_LEN 192
#define MT_MCU_MEMMAP_WLAN 0x410000 #define MT_MCU_MEMMAP_WLAN 0x410000
#define MT_MCU_PCIE_REMAP_BASE4 0x074C
#define MT_MCU_SEMAPHORE_00 0x07B0
#define MT_MCU_SEMAPHORE_01 0x07B4
#define MT_MCU_SEMAPHORE_02 0x07B8
#define MT_MCU_SEMAPHORE_03 0x07BC
#define MT_MCU_ILM_ADDR 0x80000
enum mcu_cmd { enum mcu_cmd {
CMD_FUN_SET_OP = 1, CMD_FUN_SET_OP = 1,
CMD_LOAD_CR = 2, CMD_LOAD_CR = 2,
...@@ -96,5 +105,7 @@ int mt76x02_mcu_function_select(struct mt76_dev *dev, ...@@ -96,5 +105,7 @@ int mt76x02_mcu_function_select(struct mt76_dev *dev,
u32 val, bool wait_resp); u32 val, bool wait_resp);
int mt76x02_mcu_set_radio_state(struct mt76_dev *dev, bool on, int mt76x02_mcu_set_radio_state(struct mt76_dev *dev, bool on,
bool wait_resp); bool wait_resp);
void mt76x02_set_ethtool_fwver(struct mt76_dev *dev,
const struct mt76x02_fw_header *h);
#endif /* __MT76x02_MCU_H */ #endif /* __MT76x02_MCU_H */
/*
* Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include "mt76.h"
#include "mt76x02_dma.h"
#include "mt76x02_util.h"
#include "mt76x02_mac.h"
static int
mt76x02_init_tx_queue(struct mt76_dev *dev, struct mt76_queue *q,
int idx, int n_desc)
{
int ret;
q->regs = dev->mmio.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE;
q->ndesc = n_desc;
q->hw_idx = idx;
ret = __mt76_queue_alloc(dev, q);
if (ret)
return ret;
mt76x02_irq_enable(dev, MT_INT_TX_DONE(idx));
return 0;
}
static int
mt76x02_init_rx_queue(struct mt76_dev *dev, struct mt76_queue *q,
int idx, int n_desc, int bufsize)
{
int ret;
q->regs = dev->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;
mt76x02_irq_enable(dev, MT_INT_RX_DONE(idx));
return 0;
}
int mt76x02_dma_init(struct mt76_dev *dev)
{
struct mt76_txwi_cache __maybe_unused *t;
struct mt76_queue *q;
int i, ret;
BUILD_BUG_ON(sizeof(t->txwi) < sizeof(struct mt76x02_txwi));
BUILD_BUG_ON(sizeof(struct mt76x02_rxwi) > MT_RX_HEADROOM);
mt76_dma_attach(dev);
__mt76_wr(dev, MT_WPDMA_RST_IDX, ~0);
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
ret = mt76x02_init_tx_queue(dev, &dev->q_tx[i],
mt76_ac_to_hwq(i),
MT_TX_RING_SIZE);
if (ret)
return ret;
}
ret = mt76x02_init_tx_queue(dev, &dev->q_tx[MT_TXQ_PSD],
MT_TX_HW_QUEUE_MGMT, MT_TX_RING_SIZE);
if (ret)
return ret;
ret = mt76x02_init_tx_queue(dev, &dev->q_tx[MT_TXQ_MCU],
MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE);
if (ret)
return ret;
ret = mt76x02_init_rx_queue(dev, &dev->q_rx[MT_RXQ_MCU], 1,
MT_MCU_RING_SIZE, MT_RX_BUF_SIZE);
if (ret)
return ret;
q = &dev->q_rx[MT_RXQ_MAIN];
q->buf_offset = MT_RX_HEADROOM - sizeof(struct mt76x02_rxwi);
ret = mt76x02_init_rx_queue(dev, q, 0, MT76X02_RX_RING_SIZE,
MT_RX_BUF_SIZE);
if (ret)
return ret;
return __mt76_init_queues(dev);
}
EXPORT_SYMBOL_GPL(mt76x02_dma_init);
void mt76x02_set_irq_mask(struct mt76_dev *dev, u32 clear, u32 set)
{
unsigned long flags;
spin_lock_irqsave(&dev->mmio.irq_lock, flags);
dev->mmio.irqmask &= ~clear;
dev->mmio.irqmask |= set;
__mt76_wr(dev, MT_INT_MASK_CSR, dev->mmio.irqmask);
spin_unlock_irqrestore(&dev->mmio.irq_lock, flags);
}
EXPORT_SYMBOL_GPL(mt76x02_set_irq_mask);
void mt76x02_dma_enable(struct mt76_dev *dev)
{
u32 val;
__mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
mt76x02_wait_for_wpdma(dev, 1000);
usleep_range(50, 100);
val = FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3) |
MT_WPDMA_GLO_CFG_TX_DMA_EN |
MT_WPDMA_GLO_CFG_RX_DMA_EN;
__mt76_set(dev, MT_WPDMA_GLO_CFG, val);
__mt76_clear(dev, MT_WPDMA_GLO_CFG,
MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
}
EXPORT_SYMBOL_GPL(mt76x02_dma_enable);
void mt76x02_dma_disable(struct mt76_dev *dev)
{
u32 val = __mt76_rr(dev, MT_WPDMA_GLO_CFG);
val &= MT_WPDMA_GLO_CFG_DMA_BURST_SIZE |
MT_WPDMA_GLO_CFG_BIG_ENDIAN |
MT_WPDMA_GLO_CFG_HDR_SEG_LEN;
val |= MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE;
__mt76_wr(dev, MT_WPDMA_GLO_CFG, val);
}
EXPORT_SYMBOL_GPL(mt76x02_dma_disable);
void mt76x02_mac_start(struct mt76_dev *dev)
{
mt76x02_dma_enable(dev);
__mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter);
__mt76_wr(dev, MT_MAC_SYS_CTRL,
MT_MAC_SYS_CTRL_ENABLE_TX |
MT_MAC_SYS_CTRL_ENABLE_RX);
mt76x02_irq_enable(dev,
MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
MT_INT_TX_STAT);
}
EXPORT_SYMBOL_GPL(mt76x02_mac_start);
/*
* Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include "mt76.h"
#include "mt76x02_phy.h"
void mt76x02_phy_set_rxpath(struct mt76_dev *dev)
{
u32 val;
val = __mt76_rr(dev, MT_BBP(AGC, 0));
val &= ~BIT(4);
switch (dev->chainmask & 0xf) {
case 2:
val |= BIT(3);
break;
default:
val &= ~BIT(3);
break;
}
__mt76_wr(dev, MT_BBP(AGC, 0), val);
mb();
val = __mt76_rr(dev, MT_BBP(AGC, 0));
}
EXPORT_SYMBOL_GPL(mt76x02_phy_set_rxpath);
void mt76x02_phy_set_txdac(struct mt76_dev *dev)
{
int txpath;
txpath = (dev->chainmask >> 8) & 0xf;
switch (txpath) {
case 2:
__mt76_set(dev, MT_BBP(TXBE, 5), 0x3);
break;
default:
__mt76_clear(dev, MT_BBP(TXBE, 5), 0x3);
break;
}
}
EXPORT_SYMBOL_GPL(mt76x02_phy_set_txdac);
static u32
mt76x02_tx_power_mask(u8 v1, u8 v2, u8 v3, u8 v4)
{
u32 val = 0;
val |= (v1 & (BIT(6) - 1)) << 0;
val |= (v2 & (BIT(6) - 1)) << 8;
val |= (v3 & (BIT(6) - 1)) << 16;
val |= (v4 & (BIT(6) - 1)) << 24;
return val;
}
int mt76x02_get_max_rate_power(struct mt76_rate_power *r)
{
s8 ret = 0;
int i;
for (i = 0; i < sizeof(r->all); i++)
ret = max(ret, r->all[i]);
return ret;
}
EXPORT_SYMBOL_GPL(mt76x02_get_max_rate_power);
void mt76x02_limit_rate_power(struct mt76_rate_power *r, int limit)
{
int i;
for (i = 0; i < sizeof(r->all); i++)
if (r->all[i] > limit)
r->all[i] = limit;
}
EXPORT_SYMBOL_GPL(mt76x02_limit_rate_power);
void mt76x02_add_rate_power_offset(struct mt76_rate_power *r, int offset)
{
int i;
for (i = 0; i < sizeof(r->all); i++)
r->all[i] += offset;
}
EXPORT_SYMBOL_GPL(mt76x02_add_rate_power_offset);
void mt76x02_phy_set_txpower(struct mt76_dev *dev, int txp_0, int txp_1)
{
struct mt76_rate_power *t = &dev->rate_power;
__mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_0,
txp_0);
__mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_1,
txp_1);
__mt76_wr(dev, MT_TX_PWR_CFG_0,
mt76x02_tx_power_mask(t->cck[0], t->cck[2], t->ofdm[0],
t->ofdm[2]));
__mt76_wr(dev, MT_TX_PWR_CFG_1,
mt76x02_tx_power_mask(t->ofdm[4], t->ofdm[6], t->ht[0],
t->ht[2]));
__mt76_wr(dev, MT_TX_PWR_CFG_2,
mt76x02_tx_power_mask(t->ht[4], t->ht[6], t->ht[8],
t->ht[10]));
__mt76_wr(dev, MT_TX_PWR_CFG_3,
mt76x02_tx_power_mask(t->ht[12], t->ht[14], t->stbc[0],
t->stbc[2]));
__mt76_wr(dev, MT_TX_PWR_CFG_4,
mt76x02_tx_power_mask(t->stbc[4], t->stbc[6], 0, 0));
__mt76_wr(dev, MT_TX_PWR_CFG_7,
mt76x02_tx_power_mask(t->ofdm[7], t->vht[8], t->ht[7],
t->vht[9]));
__mt76_wr(dev, MT_TX_PWR_CFG_8,
mt76x02_tx_power_mask(t->ht[14], 0, t->vht[8], t->vht[9]));
__mt76_wr(dev, MT_TX_PWR_CFG_9,
mt76x02_tx_power_mask(t->ht[7], 0, t->stbc[8], t->stbc[9]));
}
EXPORT_SYMBOL_GPL(mt76x02_phy_set_txpower);
/*
* Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __MT76x02_PHY_H
#define __MT76x02_PHY_H
#include "mt76x02_regs.h"
void mt76x02_add_rate_power_offset(struct mt76_rate_power *r, int offset);
void mt76x02_phy_set_txpower(struct mt76_dev *dev, int txp_0, int txp_2);
void mt76x02_limit_rate_power(struct mt76_rate_power *r, int limit);
int mt76x02_get_max_rate_power(struct mt76_rate_power *r);
void mt76x02_phy_set_rxpath(struct mt76_dev *dev);
void mt76x02_phy_set_txdac(struct mt76_dev *dev);
#endif /* __MT76x02_PHY_H */
...@@ -43,7 +43,7 @@ int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) ...@@ -43,7 +43,7 @@ int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags)
} }
if (unlikely(pad)) { if (unlikely(pad)) {
if (__skb_pad(last, pad, true)) if (skb_pad(last, pad))
return -ENOMEM; return -ENOMEM;
__skb_put(last, pad); __skb_put(last, pad);
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <linux/module.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include "mt76.h" #include "mt76.h"
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <linux/module.h>
#include "mt76.h" #include "mt76.h"
#include "mt76x02_dma.h" #include "mt76x02_dma.h"
#include "mt76x02_regs.h" #include "mt76x02_regs.h"
...@@ -453,4 +454,42 @@ bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update) ...@@ -453,4 +454,42 @@ bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update)
} }
EXPORT_SYMBOL_GPL(mt76x02_tx_status_data); EXPORT_SYMBOL_GPL(mt76x02_tx_status_data);
const u16 mt76x02_beacon_offsets[16] = {
/* 1024 byte per beacon */
0xc000,
0xc400,
0xc800,
0xcc00,
0xd000,
0xd400,
0xd800,
0xdc00,
/* BSS idx 8-15 not used for beacons */
0xc000,
0xc000,
0xc000,
0xc000,
0xc000,
0xc000,
0xc000,
0xc000,
};
EXPORT_SYMBOL_GPL(mt76x02_beacon_offsets);
void mt76x02_set_beacon_offsets(struct mt76_dev *dev)
{
u16 val, base = MT_BEACON_BASE;
u32 regs[4] = {};
int i;
for (i = 0; i < 16; i++) {
val = mt76x02_beacon_offsets[i] - base;
regs[i / 4] |= (val / 64) << (8 * (i % 4));
}
for (i = 0; i < 4; i++)
__mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]);
}
EXPORT_SYMBOL_GPL(mt76x02_set_beacon_offsets);
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
...@@ -51,4 +51,28 @@ void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb); ...@@ -51,4 +51,28 @@ void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb);
void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
struct mt76_queue_entry *e, bool flush); struct mt76_queue_entry *e, bool flush);
bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update); bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update);
extern const u16 mt76x02_beacon_offsets[16];
void mt76x02_set_beacon_offsets(struct mt76_dev *dev);
void mt76x02_set_irq_mask(struct mt76_dev *dev, u32 clear, u32 set);
void mt76x02_mac_start(struct mt76_dev *dev);
static inline void mt76x02_irq_enable(struct mt76_dev *dev, u32 mask)
{
mt76x02_set_irq_mask(dev, 0, mask);
}
static inline void mt76x02_irq_disable(struct mt76_dev *dev, u32 mask)
{
mt76x02_set_irq_mask(dev, mask, 0);
}
static inline bool
mt76x02_wait_for_txrx_idle(struct mt76_dev *dev)
{
return __mt76_poll_msec(dev, MT_MAC_STATUS,
MT_MAC_STATUS_TX | MT_MAC_STATUS_RX,
0, 100);
}
#endif #endif
...@@ -35,9 +35,6 @@ ...@@ -35,9 +35,6 @@
#define MT7662U_FIRMWARE "mediatek/mt7662u.bin" #define MT7662U_FIRMWARE "mediatek/mt7662u.bin"
#define MT7662U_ROM_PATCH "mediatek/mt7662u_rom_patch.bin" #define MT7662U_ROM_PATCH "mediatek/mt7662u_rom_patch.bin"
#define MT76x2_RX_RING_SIZE 256
#define MT_RX_HEADROOM 32
#define MT_MAX_CHAINS 2 #define MT_MAX_CHAINS 2
#define MT_CALIBRATE_INTERVAL HZ #define MT_CALIBRATE_INTERVAL HZ
...@@ -81,10 +78,6 @@ struct mt76x2_dev { ...@@ -81,10 +78,6 @@ struct mt76x2_dev {
struct mutex mutex; struct mutex mutex;
const u16 *beacon_offsets;
int txpower_conf;
int txpower_cur;
u8 txdone_seq; u8 txdone_seq;
DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status); DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status);
...@@ -97,9 +90,6 @@ struct mt76x2_dev { ...@@ -97,9 +90,6 @@ struct mt76x2_dev {
u32 aggr_stats[32]; u32 aggr_stats[32];
spinlock_t irq_lock;
u32 irqmask;
struct sk_buff *beacons[8]; struct sk_buff *beacons[8];
u8 beacon_mask; u8 beacon_mask;
u8 beacon_data_mask; u8 beacon_data_mask;
...@@ -107,13 +97,10 @@ struct mt76x2_dev { ...@@ -107,13 +97,10 @@ struct mt76x2_dev {
u8 tbtt_count; u8 tbtt_count;
u16 beacon_int; u16 beacon_int;
u16 chainmask;
struct mt76x2_calibration cal; struct mt76x2_calibration cal;
s8 target_power; s8 target_power;
s8 target_power_delta[2]; s8 target_power_delta[2];
struct mt76_rate_power rate_power;
bool enable_tpc; bool enable_tpc;
u8 coverage_class; u8 coverage_class;
...@@ -127,8 +114,6 @@ static inline bool is_mt7612(struct mt76x2_dev *dev) ...@@ -127,8 +114,6 @@ static inline bool is_mt7612(struct mt76x2_dev *dev)
return mt76_chip(&dev->mt76) == 0x7612; return mt76_chip(&dev->mt76) == 0x7612;
} }
void mt76x2_set_irq_mask(struct mt76x2_dev *dev, u32 clear, u32 set);
static inline bool mt76x2_channel_silent(struct mt76x2_dev *dev) static inline bool mt76x2_channel_silent(struct mt76x2_dev *dev)
{ {
struct ieee80211_channel *chan = dev->mt76.chandef.chan; struct ieee80211_channel *chan = dev->mt76.chandef.chan;
...@@ -137,31 +122,6 @@ static inline bool mt76x2_channel_silent(struct mt76x2_dev *dev) ...@@ -137,31 +122,6 @@ static inline bool mt76x2_channel_silent(struct mt76x2_dev *dev)
chan->dfs_state != NL80211_DFS_AVAILABLE); chan->dfs_state != NL80211_DFS_AVAILABLE);
} }
static inline void mt76x2_irq_enable(struct mt76x2_dev *dev, u32 mask)
{
mt76x2_set_irq_mask(dev, 0, mask);
}
static inline void mt76x2_irq_disable(struct mt76x2_dev *dev, u32 mask)
{
mt76x2_set_irq_mask(dev, mask, 0);
}
static inline bool mt76x2_wait_for_bbp(struct mt76x2_dev *dev)
{
return mt76_poll_msec(dev, MT_MAC_STATUS,
MT_MAC_STATUS_TX | MT_MAC_STATUS_RX,
0, 100);
}
static inline bool wait_for_wpdma(struct mt76x2_dev *dev)
{
return mt76_poll(dev, MT_WPDMA_GLO_CFG,
MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
MT_WPDMA_GLO_CFG_RX_DMA_BUSY,
0, 1000);
}
extern const struct ieee80211_ops mt76x2_ops; extern const struct ieee80211_ops mt76x2_ops;
struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev); struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev);
...@@ -191,7 +151,7 @@ int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, ...@@ -191,7 +151,7 @@ int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw,
int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level,
u8 channel); u8 channel);
int mt76x2_dma_init(struct mt76x2_dev *dev); void mt76x2_tx_tasklet(unsigned long data);
void mt76x2_dma_cleanup(struct mt76x2_dev *dev); void mt76x2_dma_cleanup(struct mt76x2_dev *dev);
void mt76x2_cleanup(struct mt76x2_dev *dev); void mt76x2_cleanup(struct mt76x2_dev *dev);
......
...@@ -17,23 +17,11 @@ ...@@ -17,23 +17,11 @@
#include <linux/delay.h> #include <linux/delay.h>
#include "mt76x2.h" #include "mt76x2.h"
#include "mt76x2_trace.h" #include "mt76x2_trace.h"
#include "mt76x02_util.h"
void mt76x2_set_irq_mask(struct mt76x2_dev *dev, u32 clear, u32 set)
{
unsigned long flags;
spin_lock_irqsave(&dev->irq_lock, flags);
dev->irqmask &= ~clear;
dev->irqmask |= set;
mt76_wr(dev, MT_INT_MASK_CSR, dev->irqmask);
spin_unlock_irqrestore(&dev->irq_lock, flags);
}
void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
{ {
struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); mt76x02_irq_enable(mdev, MT_INT_RX_DONE(q));
mt76x2_irq_enable(dev, MT_INT_RX_DONE(q));
} }
irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance) irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance)
...@@ -47,22 +35,22 @@ irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance) ...@@ -47,22 +35,22 @@ irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance)
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state)) if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state))
return IRQ_NONE; return IRQ_NONE;
trace_dev_irq(dev, intr, dev->irqmask); trace_dev_irq(dev, intr, dev->mt76.mmio.irqmask);
intr &= dev->irqmask; intr &= dev->mt76.mmio.irqmask;
if (intr & MT_INT_TX_DONE_ALL) { if (intr & MT_INT_TX_DONE_ALL) {
mt76x2_irq_disable(dev, MT_INT_TX_DONE_ALL); mt76x02_irq_disable(&dev->mt76, MT_INT_TX_DONE_ALL);
tasklet_schedule(&dev->tx_tasklet); tasklet_schedule(&dev->tx_tasklet);
} }
if (intr & MT_INT_RX_DONE(0)) { if (intr & MT_INT_RX_DONE(0)) {
mt76x2_irq_disable(dev, MT_INT_RX_DONE(0)); mt76x02_irq_disable(&dev->mt76, MT_INT_RX_DONE(0));
napi_schedule(&dev->mt76.napi[0]); napi_schedule(&dev->mt76.napi[0]);
} }
if (intr & MT_INT_RX_DONE(1)) { if (intr & MT_INT_RX_DONE(1)) {
mt76x2_irq_disable(dev, MT_INT_RX_DONE(1)); mt76x02_irq_disable(&dev->mt76, MT_INT_RX_DONE(1));
napi_schedule(&dev->mt76.napi[1]); napi_schedule(&dev->mt76.napi[1]);
} }
...@@ -79,7 +67,7 @@ irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance) ...@@ -79,7 +67,7 @@ irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance)
} }
if (intr & MT_INT_GPTIMER) { if (intr & MT_INT_GPTIMER) {
mt76x2_irq_disable(dev, MT_INT_GPTIMER); mt76x02_irq_disable(&dev->mt76, MT_INT_GPTIMER);
tasklet_schedule(&dev->dfs_pd.dfs_tasklet); tasklet_schedule(&dev->dfs_pd.dfs_tasklet);
} }
......
...@@ -47,33 +47,14 @@ mt76x2_ampdu_stat_open(struct inode *inode, struct file *f) ...@@ -47,33 +47,14 @@ mt76x2_ampdu_stat_open(struct inode *inode, struct file *f)
return single_open(f, mt76x2_ampdu_stat_read, inode->i_private); return single_open(f, mt76x2_ampdu_stat_read, inode->i_private);
} }
static void
seq_puts_array(struct seq_file *file, const char *str, s8 *val, int len)
{
int i;
seq_printf(file, "%10s:", str);
for (i = 0; i < len; i++)
seq_printf(file, " %2d", val[i]);
seq_puts(file, "\n");
}
static int read_txpower(struct seq_file *file, void *data) static int read_txpower(struct seq_file *file, void *data)
{ {
struct mt76x2_dev *dev = dev_get_drvdata(file->private); struct mt76x2_dev *dev = dev_get_drvdata(file->private);
seq_printf(file, "Target power: %d\n", dev->target_power); seq_printf(file, "Target power: %d\n", dev->target_power);
seq_puts_array(file, "Delta", dev->target_power_delta, mt76_seq_puts_array(file, "Delta", dev->target_power_delta,
ARRAY_SIZE(dev->target_power_delta)); ARRAY_SIZE(dev->target_power_delta));
seq_puts_array(file, "CCK", dev->rate_power.cck,
ARRAY_SIZE(dev->rate_power.cck));
seq_puts_array(file, "OFDM", dev->rate_power.ofdm,
ARRAY_SIZE(dev->rate_power.ofdm));
seq_puts_array(file, "HT", dev->rate_power.ht,
ARRAY_SIZE(dev->rate_power.ht));
seq_puts_array(file, "VHT", dev->rate_power.vht,
ARRAY_SIZE(dev->rate_power.vht));
return 0; return 0;
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
#include "mt76x2.h" #include "mt76x2.h"
#include "mt76x02_util.h"
#define RADAR_SPEC(m, len, el, eh, wl, wh, \ #define RADAR_SPEC(m, len, el, eh, wl, wh, \
w_tolerance, tl, th, t_tolerance, \ w_tolerance, tl, th, t_tolerance, \
...@@ -678,7 +679,7 @@ static void mt76x2_dfs_tasklet(unsigned long arg) ...@@ -678,7 +679,7 @@ static void mt76x2_dfs_tasklet(unsigned long arg)
mt76_wr(dev, MT_BBP(DFS, 1), 0xf); mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
out: out:
mt76x2_irq_enable(dev, MT_INT_GPTIMER); mt76x02_irq_enable(&dev->mt76, MT_INT_GPTIMER);
} }
static void mt76x2_dfs_init_sw_detector(struct mt76x2_dev *dev) static void mt76x2_dfs_init_sw_detector(struct mt76x2_dev *dev)
...@@ -834,7 +835,7 @@ void mt76x2_dfs_init_params(struct mt76x2_dev *dev) ...@@ -834,7 +835,7 @@ void mt76x2_dfs_init_params(struct mt76x2_dev *dev)
/* enable debug mode */ /* enable debug mode */
mt76x2_dfs_set_capture_mode_ctrl(dev, true); mt76x2_dfs_set_capture_mode_ctrl(dev, true);
mt76x2_irq_enable(dev, MT_INT_GPTIMER); mt76x02_irq_enable(&dev->mt76, MT_INT_GPTIMER);
mt76_rmw_field(dev, MT_INT_TIMER_EN, mt76_rmw_field(dev, MT_INT_TIMER_EN,
MT_INT_TIMER_EN_GP_TIMER_EN, 1); MT_INT_TIMER_EN_GP_TIMER_EN, 1);
} else { } else {
...@@ -844,7 +845,7 @@ void mt76x2_dfs_init_params(struct mt76x2_dev *dev) ...@@ -844,7 +845,7 @@ void mt76x2_dfs_init_params(struct mt76x2_dev *dev)
mt76_wr(dev, MT_BBP(DFS, 1), 0xf); mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
mt76_wr(dev, 0x212c, 0); mt76_wr(dev, 0x212c, 0);
mt76x2_irq_disable(dev, MT_INT_GPTIMER); mt76x02_irq_disable(&dev->mt76, MT_INT_GPTIMER);
mt76_rmw_field(dev, MT_INT_TIMER_EN, mt76_rmw_field(dev, MT_INT_TIMER_EN,
MT_INT_TIMER_EN_GP_TIMER_EN, 0); MT_INT_TIMER_EN_GP_TIMER_EN, 0);
} }
......
...@@ -16,47 +16,9 @@ ...@@ -16,47 +16,9 @@
#include "mt76x2.h" #include "mt76x2.h"
#include "mt76x02_dma.h" #include "mt76x02_dma.h"
#include "mt76x02_util.h"
static int void mt76x2_tx_tasklet(unsigned long data)
mt76x2_init_tx_queue(struct mt76x2_dev *dev, struct mt76_queue *q,
int idx, int n_desc)
{
int ret;
q->regs = dev->mt76.mmio.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE;
q->ndesc = n_desc;
q->hw_idx = idx;
ret = mt76_queue_alloc(dev, q);
if (ret)
return ret;
mt76x2_irq_enable(dev, MT_INT_TX_DONE(idx));
return 0;
}
static int
mt76x2_init_rx_queue(struct mt76x2_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;
mt76x2_irq_enable(dev, MT_INT_RX_DONE(idx));
return 0;
}
static void
mt76x2_tx_tasklet(unsigned long data)
{ {
struct mt76x2_dev *dev = (struct mt76x2_dev *) data; struct mt76x2_dev *dev = (struct mt76x2_dev *) data;
int i; int i;
...@@ -67,54 +29,7 @@ mt76x2_tx_tasklet(unsigned long data) ...@@ -67,54 +29,7 @@ mt76x2_tx_tasklet(unsigned long data)
mt76_queue_tx_cleanup(dev, i, false); mt76_queue_tx_cleanup(dev, i, false);
mt76x2_mac_poll_tx_status(dev, false); mt76x2_mac_poll_tx_status(dev, false);
mt76x2_irq_enable(dev, MT_INT_TX_DONE_ALL); mt76x02_irq_enable(&dev->mt76, MT_INT_TX_DONE_ALL);
}
int mt76x2_dma_init(struct mt76x2_dev *dev)
{
int ret;
int i;
struct mt76_txwi_cache __maybe_unused *t;
struct mt76_queue *q;
BUILD_BUG_ON(sizeof(t->txwi) < sizeof(struct mt76x02_txwi));
BUILD_BUG_ON(sizeof(struct mt76x02_rxwi) > MT_RX_HEADROOM);
mt76_dma_attach(&dev->mt76);
tasklet_init(&dev->tx_tasklet, mt76x2_tx_tasklet, (unsigned long) dev);
mt76_wr(dev, MT_WPDMA_RST_IDX, ~0);
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
ret = mt76x2_init_tx_queue(dev, &dev->mt76.q_tx[i],
mt76_ac_to_hwq(i), MT_TX_RING_SIZE);
if (ret)
return ret;
}
ret = mt76x2_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 = mt76x2_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 = mt76x2_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1,
MT_MCU_RING_SIZE, MT_RX_BUF_SIZE);
if (ret)
return ret;
q = &dev->mt76.q_rx[MT_RXQ_MAIN];
q->buf_offset = MT_RX_HEADROOM - sizeof(struct mt76x02_rxwi);
ret = mt76x2_init_rx_queue(dev, q, 0, MT76x2_RX_RING_SIZE, MT_RX_BUF_SIZE);
if (ret)
return ret;
return mt76_init_queues(dev);
} }
void mt76x2_dma_cleanup(struct mt76x2_dev *dev) void mt76x2_dma_cleanup(struct mt76x2_dev *dev)
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <linux/module.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include "mt76x2.h" #include "mt76x2.h"
#include "mt76x2_eeprom.h" #include "mt76x2_eeprom.h"
...@@ -21,7 +22,7 @@ ...@@ -21,7 +22,7 @@
#define EE_FIELD(_name, _value) [MT_EE_##_name] = (_value) | 1 #define EE_FIELD(_name, _value) [MT_EE_##_name] = (_value) | 1
static int static int
mt76x2_eeprom_copy(struct mt76x2_dev *dev, enum mt76x2_eeprom_field field, mt76x2_eeprom_copy(struct mt76x2_dev *dev, enum mt76x02_eeprom_field field,
void *dest, int len) void *dest, int len)
{ {
if (field + len > dev->mt76.eeprom.size) if (field + len > dev->mt76.eeprom.size)
...@@ -40,71 +41,6 @@ mt76x2_eeprom_get_macaddr(struct mt76x2_dev *dev) ...@@ -40,71 +41,6 @@ mt76x2_eeprom_get_macaddr(struct mt76x2_dev *dev)
return 0; return 0;
} }
void mt76x2_eeprom_parse_hw_cap(struct mt76x2_dev *dev)
{
u16 val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0);
switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) {
case BOARD_TYPE_5GHZ:
dev->mt76.cap.has_5ghz = true;
break;
case BOARD_TYPE_2GHZ:
dev->mt76.cap.has_2ghz = true;
break;
default:
dev->mt76.cap.has_2ghz = true;
dev->mt76.cap.has_5ghz = true;
break;
}
}
EXPORT_SYMBOL_GPL(mt76x2_eeprom_parse_hw_cap);
static int
mt76x2_efuse_read(struct mt76x2_dev *dev, u16 addr, u8 *data)
{
u32 val;
int i;
val = mt76_rr(dev, 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, MT_EFUSE_CTRL, val);
if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
return -ETIMEDOUT;
udelay(2);
val = mt76_rr(dev, MT_EFUSE_CTRL);
if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) {
memset(data, 0xff, 16);
return 0;
}
for (i = 0; i < 4; i++) {
val = mt76_rr(dev, MT_EFUSE_DATA(i));
put_unaligned_le32(val, data + 4 * i);
}
return 0;
}
static int
mt76x2_get_efuse_data(struct mt76x2_dev *dev, void *buf, int len)
{
int ret, i;
for (i = 0; i + 16 <= len; i += 16) {
ret = mt76x2_efuse_read(dev, i, buf + i);
if (ret)
return ret;
}
return 0;
}
static bool static bool
mt76x2_has_cal_free_data(struct mt76x2_dev *dev, u8 *efuse) mt76x2_has_cal_free_data(struct mt76x2_dev *dev, u8 *efuse)
{ {
...@@ -241,7 +177,8 @@ mt76x2_eeprom_load(struct mt76x2_dev *dev) ...@@ -241,7 +177,8 @@ mt76x2_eeprom_load(struct mt76x2_dev *dev)
efuse = dev->mt76.otp.data; efuse = dev->mt76.otp.data;
if (mt76x2_get_efuse_data(dev, efuse, MT7662_EEPROM_SIZE)) if (mt76x02_get_efuse_data(&dev->mt76, 0, efuse,
MT7662_EEPROM_SIZE, MT_EE_READ))
goto out; goto out;
if (found) { if (found) {
...@@ -259,43 +196,19 @@ mt76x2_eeprom_load(struct mt76x2_dev *dev) ...@@ -259,43 +196,19 @@ mt76x2_eeprom_load(struct mt76x2_dev *dev)
return 0; return 0;
} }
static inline int
mt76x2_sign_extend(u32 val, unsigned int size)
{
bool sign = val & BIT(size - 1);
val &= BIT(size - 1) - 1;
return sign ? val : -val;
}
static inline int
mt76x2_sign_extend_optional(u32 val, unsigned int size)
{
bool enable = val & BIT(size);
return enable ? mt76x2_sign_extend(val, size) : 0;
}
static bool
field_valid(u8 val)
{
return val != 0 && val != 0xff;
}
static void static void
mt76x2_set_rx_gain_group(struct mt76x2_dev *dev, u8 val) mt76x2_set_rx_gain_group(struct mt76x2_dev *dev, u8 val)
{ {
s8 *dest = dev->cal.rx.high_gain; s8 *dest = dev->cal.rx.high_gain;
if (!field_valid(val)) { if (!mt76x02_field_valid(val)) {
dest[0] = 0; dest[0] = 0;
dest[1] = 0; dest[1] = 0;
return; return;
} }
dest[0] = mt76x2_sign_extend(val, 4); dest[0] = mt76x02_sign_extend(val, 4);
dest[1] = mt76x2_sign_extend(val >> 4, 4); dest[1] = mt76x02_sign_extend(val >> 4, 4);
} }
static void static void
...@@ -303,12 +216,12 @@ mt76x2_set_rssi_offset(struct mt76x2_dev *dev, int chain, u8 val) ...@@ -303,12 +216,12 @@ mt76x2_set_rssi_offset(struct mt76x2_dev *dev, int chain, u8 val)
{ {
s8 *dest = dev->cal.rx.rssi_offset; s8 *dest = dev->cal.rx.rssi_offset;
if (!field_valid(val)) { if (!mt76x02_field_valid(val)) {
dest[chain] = 0; dest[chain] = 0;
return; return;
} }
dest[chain] = mt76x2_sign_extend_optional(val, 7); dest[chain] = mt76x02_sign_extend_optional(val, 7);
} }
static enum mt76x2_cal_channel_group static enum mt76x2_cal_channel_group
...@@ -335,17 +248,23 @@ mt76x2_get_5g_rx_gain(struct mt76x2_dev *dev, u8 channel) ...@@ -335,17 +248,23 @@ mt76x2_get_5g_rx_gain(struct mt76x2_dev *dev, u8 channel)
group = mt76x2_get_cal_channel_group(channel); group = mt76x2_get_cal_channel_group(channel);
switch (group) { switch (group) {
case MT_CH_5G_JAPAN: case MT_CH_5G_JAPAN:
return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN); return mt76x02_eeprom_get(&dev->mt76,
MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN);
case MT_CH_5G_UNII_1: case MT_CH_5G_UNII_1:
return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN) >> 8; return mt76x02_eeprom_get(&dev->mt76,
MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN) >> 8;
case MT_CH_5G_UNII_2: case MT_CH_5G_UNII_2:
return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN); return mt76x02_eeprom_get(&dev->mt76,
MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN);
case MT_CH_5G_UNII_2E_1: case MT_CH_5G_UNII_2E_1:
return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN) >> 8; return mt76x02_eeprom_get(&dev->mt76,
MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN) >> 8;
case MT_CH_5G_UNII_2E_2: case MT_CH_5G_UNII_2E_2:
return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN); return mt76x02_eeprom_get(&dev->mt76,
MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN);
default: default:
return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN) >> 8; return mt76x02_eeprom_get(&dev->mt76,
MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN) >> 8;
} }
} }
...@@ -358,74 +277,27 @@ void mt76x2_read_rx_gain(struct mt76x2_dev *dev) ...@@ -358,74 +277,27 @@ void mt76x2_read_rx_gain(struct mt76x2_dev *dev)
u16 val; u16 val;
if (chan->band == NL80211_BAND_2GHZ) if (chan->band == NL80211_BAND_2GHZ)
val = mt76x2_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN) >> 8; val = mt76x02_eeprom_get(&dev->mt76,
MT_EE_RF_2G_RX_HIGH_GAIN) >> 8;
else else
val = mt76x2_get_5g_rx_gain(dev, channel); val = mt76x2_get_5g_rx_gain(dev, channel);
mt76x2_set_rx_gain_group(dev, val); mt76x2_set_rx_gain_group(dev, val);
if (chan->band == NL80211_BAND_2GHZ) { mt76x02_get_rx_gain(&dev->mt76, chan->band, &val, &lna_2g, lna_5g);
val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_0); mt76x2_set_rssi_offset(dev, 0, val);
mt76x2_set_rssi_offset(dev, 0, val); mt76x2_set_rssi_offset(dev, 1, val >> 8);
mt76x2_set_rssi_offset(dev, 1, val >> 8);
} else {
val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_0);
mt76x2_set_rssi_offset(dev, 0, val);
mt76x2_set_rssi_offset(dev, 1, val >> 8);
}
val = mt76x2_eeprom_get(dev, MT_EE_LNA_GAIN);
lna_2g = val & 0xff;
lna_5g[0] = val >> 8;
val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_1);
lna_5g[1] = val >> 8;
val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1);
lna_5g[2] = val >> 8;
if (!field_valid(lna_5g[1]))
lna_5g[1] = lna_5g[0];
if (!field_valid(lna_5g[2]))
lna_5g[2] = lna_5g[0];
dev->cal.rx.mcu_gain = (lna_2g & 0xff); dev->cal.rx.mcu_gain = (lna_2g & 0xff);
dev->cal.rx.mcu_gain |= (lna_5g[0] & 0xff) << 8; dev->cal.rx.mcu_gain |= (lna_5g[0] & 0xff) << 8;
dev->cal.rx.mcu_gain |= (lna_5g[1] & 0xff) << 16; dev->cal.rx.mcu_gain |= (lna_5g[1] & 0xff) << 16;
dev->cal.rx.mcu_gain |= (lna_5g[2] & 0xff) << 24; dev->cal.rx.mcu_gain |= (lna_5g[2] & 0xff) << 24;
val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1); lna = mt76x02_get_lna_gain(&dev->mt76, &lna_2g, lna_5g, chan);
if (val & MT_EE_NIC_CONF_1_LNA_EXT_2G) dev->cal.rx.lna_gain = mt76x02_sign_extend(lna, 8);
lna_2g = 0;
if (val & MT_EE_NIC_CONF_1_LNA_EXT_5G)
memset(lna_5g, 0, sizeof(lna_5g));
if (chan->band == NL80211_BAND_2GHZ)
lna = lna_2g;
else if (channel <= 64)
lna = lna_5g[0];
else if (channel <= 128)
lna = lna_5g[1];
else
lna = lna_5g[2];
if (lna == 0xff)
lna = 0;
dev->cal.rx.lna_gain = mt76x2_sign_extend(lna, 8);
} }
EXPORT_SYMBOL_GPL(mt76x2_read_rx_gain); EXPORT_SYMBOL_GPL(mt76x2_read_rx_gain);
static s8
mt76x2_rate_power_val(u8 val)
{
if (!field_valid(val))
return 0;
return mt76x2_sign_extend_optional(val, 7);
}
void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t,
struct ieee80211_channel *chan) struct ieee80211_channel *chan)
{ {
...@@ -436,66 +308,62 @@ void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, ...@@ -436,66 +308,62 @@ void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t,
memset(t, 0, sizeof(*t)); memset(t, 0, sizeof(*t));
val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_CCK); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_CCK);
t->cck[0] = t->cck[1] = mt76x2_rate_power_val(val); t->cck[0] = t->cck[1] = mt76x02_rate_power_val(val);
t->cck[2] = t->cck[3] = mt76x2_rate_power_val(val >> 8); t->cck[2] = t->cck[3] = mt76x02_rate_power_val(val >> 8);
if (is_5ghz) if (is_5ghz)
val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_6M); val = mt76x02_eeprom_get(&dev->mt76,
MT_EE_TX_POWER_OFDM_5G_6M);
else else
val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_6M); val = mt76x02_eeprom_get(&dev->mt76,
t->ofdm[0] = t->ofdm[1] = mt76x2_rate_power_val(val); MT_EE_TX_POWER_OFDM_2G_6M);
t->ofdm[2] = t->ofdm[3] = mt76x2_rate_power_val(val >> 8); t->ofdm[0] = t->ofdm[1] = mt76x02_rate_power_val(val);
t->ofdm[2] = t->ofdm[3] = mt76x02_rate_power_val(val >> 8);
if (is_5ghz) if (is_5ghz)
val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_24M); val = mt76x02_eeprom_get(&dev->mt76,
MT_EE_TX_POWER_OFDM_5G_24M);
else else
val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_24M); val = mt76x02_eeprom_get(&dev->mt76,
t->ofdm[4] = t->ofdm[5] = mt76x2_rate_power_val(val); MT_EE_TX_POWER_OFDM_2G_24M);
t->ofdm[6] = t->ofdm[7] = mt76x2_rate_power_val(val >> 8); t->ofdm[4] = t->ofdm[5] = mt76x02_rate_power_val(val);
t->ofdm[6] = t->ofdm[7] = mt76x02_rate_power_val(val >> 8);
val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS0); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS0);
t->ht[0] = t->ht[1] = mt76x2_rate_power_val(val); t->ht[0] = t->ht[1] = mt76x02_rate_power_val(val);
t->ht[2] = t->ht[3] = mt76x2_rate_power_val(val >> 8); t->ht[2] = t->ht[3] = mt76x02_rate_power_val(val >> 8);
val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS4); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS4);
t->ht[4] = t->ht[5] = mt76x2_rate_power_val(val); t->ht[4] = t->ht[5] = mt76x02_rate_power_val(val);
t->ht[6] = t->ht[7] = mt76x2_rate_power_val(val >> 8); t->ht[6] = t->ht[7] = mt76x02_rate_power_val(val >> 8);
val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS8); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS8);
t->ht[8] = t->ht[9] = mt76x2_rate_power_val(val); t->ht[8] = t->ht[9] = mt76x02_rate_power_val(val);
t->ht[10] = t->ht[11] = mt76x2_rate_power_val(val >> 8); t->ht[10] = t->ht[11] = mt76x02_rate_power_val(val >> 8);
val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS12); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS12);
t->ht[12] = t->ht[13] = mt76x2_rate_power_val(val); t->ht[12] = t->ht[13] = mt76x02_rate_power_val(val);
t->ht[14] = t->ht[15] = mt76x2_rate_power_val(val >> 8); t->ht[14] = t->ht[15] = mt76x02_rate_power_val(val >> 8);
val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS0); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS0);
t->vht[0] = t->vht[1] = mt76x2_rate_power_val(val); t->vht[0] = t->vht[1] = mt76x02_rate_power_val(val);
t->vht[2] = t->vht[3] = mt76x2_rate_power_val(val >> 8); t->vht[2] = t->vht[3] = mt76x02_rate_power_val(val >> 8);
val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS4); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS4);
t->vht[4] = t->vht[5] = mt76x2_rate_power_val(val); t->vht[4] = t->vht[5] = mt76x02_rate_power_val(val);
t->vht[6] = t->vht[7] = mt76x2_rate_power_val(val >> 8); t->vht[6] = t->vht[7] = mt76x02_rate_power_val(val >> 8);
val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS8); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS8);
if (!is_5ghz) if (!is_5ghz)
val >>= 8; val >>= 8;
t->vht[8] = t->vht[9] = mt76x2_rate_power_val(val >> 8); t->vht[8] = t->vht[9] = mt76x02_rate_power_val(val >> 8);
}
EXPORT_SYMBOL_GPL(mt76x2_get_rate_power);
int mt76x2_get_max_rate_power(struct mt76_rate_power *r) memcpy(t->stbc, t->ht, sizeof(t->stbc[0]) * 8);
{ t->stbc[8] = t->vht[8];
int i; t->stbc[9] = t->vht[9];
s8 ret = 0;
for (i = 0; i < sizeof(r->all); i++)
ret = max(ret, r->all[i]);
return ret;
} }
EXPORT_SYMBOL_GPL(mt76x2_get_max_rate_power); EXPORT_SYMBOL_GPL(mt76x2_get_rate_power);
static void static void
mt76x2_get_power_info_2g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, mt76x2_get_power_info_2g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t,
...@@ -518,9 +386,9 @@ mt76x2_get_power_info_2g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, ...@@ -518,9 +386,9 @@ mt76x2_get_power_info_2g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t,
t->chain[chain].tssi_slope = data[0]; t->chain[chain].tssi_slope = data[0];
t->chain[chain].tssi_offset = data[1]; t->chain[chain].tssi_offset = data[1];
t->chain[chain].target_power = data[2]; t->chain[chain].target_power = data[2];
t->chain[chain].delta = mt76x2_sign_extend_optional(data[delta_idx], 7); t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7);
val = mt76x2_eeprom_get(dev, MT_EE_RF_2G_TSSI_OFF_TXPOWER); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RF_2G_TSSI_OFF_TXPOWER);
t->target_power = val >> 8; t->target_power = val >> 8;
} }
...@@ -567,9 +435,9 @@ mt76x2_get_power_info_5g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, ...@@ -567,9 +435,9 @@ mt76x2_get_power_info_5g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t,
t->chain[chain].tssi_slope = data[0]; t->chain[chain].tssi_slope = data[0];
t->chain[chain].tssi_offset = data[1]; t->chain[chain].tssi_offset = data[1];
t->chain[chain].target_power = data[2]; t->chain[chain].target_power = data[2];
t->chain[chain].delta = mt76x2_sign_extend_optional(data[delta_idx], 7); t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7);
val = mt76x2_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RF_2G_RX_HIGH_GAIN);
t->target_power = val & 0xff; t->target_power = val & 0xff;
} }
...@@ -581,8 +449,8 @@ void mt76x2_get_power_info(struct mt76x2_dev *dev, ...@@ -581,8 +449,8 @@ void mt76x2_get_power_info(struct mt76x2_dev *dev,
memset(t, 0, sizeof(*t)); memset(t, 0, sizeof(*t));
bw40 = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40); bw40 = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_DELTA_BW40);
bw80 = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80); bw80 = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_DELTA_BW80);
if (chan->band == NL80211_BAND_5GHZ) { if (chan->band == NL80211_BAND_5GHZ) {
bw40 >>= 8; bw40 >>= 8;
...@@ -597,11 +465,12 @@ void mt76x2_get_power_info(struct mt76x2_dev *dev, ...@@ -597,11 +465,12 @@ void mt76x2_get_power_info(struct mt76x2_dev *dev,
MT_EE_TX_POWER_1_START_2G); MT_EE_TX_POWER_1_START_2G);
} }
if (mt76x2_tssi_enabled(dev) || !field_valid(t->target_power)) if (mt76x02_tssi_enabled(&dev->mt76) ||
!mt76x02_field_valid(t->target_power))
t->target_power = t->chain[0].target_power; t->target_power = t->chain[0].target_power;
t->delta_bw40 = mt76x2_rate_power_val(bw40); t->delta_bw40 = mt76x02_rate_power_val(bw40);
t->delta_bw80 = mt76x2_rate_power_val(bw80); t->delta_bw80 = mt76x02_rate_power_val(bw80);
} }
EXPORT_SYMBOL_GPL(mt76x2_get_power_info); EXPORT_SYMBOL_GPL(mt76x2_get_power_info);
...@@ -613,20 +482,24 @@ int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t) ...@@ -613,20 +482,24 @@ int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t)
memset(t, 0, sizeof(*t)); memset(t, 0, sizeof(*t));
if (!mt76x2_temp_tx_alc_enabled(dev)) if (!mt76x02_temp_tx_alc_enabled(&dev->mt76))
return -EINVAL; return -EINVAL;
if (!mt76x2_ext_pa_enabled(dev, band)) if (!mt76x02_ext_pa_enabled(&dev->mt76, band))
return -EINVAL; return -EINVAL;
val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G) >> 8; val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_EXT_PA_5G) >> 8;
t->temp_25_ref = val & 0x7f; t->temp_25_ref = val & 0x7f;
if (band == NL80211_BAND_5GHZ) { if (band == NL80211_BAND_5GHZ) {
slope = mt76x2_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_5G); slope = mt76x02_eeprom_get(&dev->mt76,
bounds = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G); MT_EE_RF_TEMP_COMP_SLOPE_5G);
bounds = mt76x02_eeprom_get(&dev->mt76,
MT_EE_TX_POWER_EXT_PA_5G);
} else { } else {
slope = mt76x2_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_2G); slope = mt76x02_eeprom_get(&dev->mt76,
bounds = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80) >> 8; MT_EE_RF_TEMP_COMP_SLOPE_2G);
bounds = mt76x02_eeprom_get(&dev->mt76,
MT_EE_TX_POWER_DELTA_BW80) >> 8;
} }
t->high_slope = slope & 0xff; t->high_slope = slope & 0xff;
...@@ -638,17 +511,6 @@ int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t) ...@@ -638,17 +511,6 @@ int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t)
} }
EXPORT_SYMBOL_GPL(mt76x2_get_temp_comp); EXPORT_SYMBOL_GPL(mt76x2_get_temp_comp);
bool mt76x2_ext_pa_enabled(struct mt76x2_dev *dev, enum nl80211_band band)
{
u16 conf0 = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0);
if (band == NL80211_BAND_5GHZ)
return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G);
else
return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G);
}
EXPORT_SYMBOL_GPL(mt76x2_ext_pa_enabled);
int mt76x2_eeprom_init(struct mt76x2_dev *dev) int mt76x2_eeprom_init(struct mt76x2_dev *dev)
{ {
int ret; int ret;
...@@ -657,7 +519,7 @@ int mt76x2_eeprom_init(struct mt76x2_dev *dev) ...@@ -657,7 +519,7 @@ int mt76x2_eeprom_init(struct mt76x2_dev *dev)
if (ret) if (ret)
return ret; return ret;
mt76x2_eeprom_parse_hw_cap(dev); mt76x02_eeprom_parse_hw_cap(&dev->mt76);
mt76x2_eeprom_get_macaddr(dev); mt76x2_eeprom_get_macaddr(dev);
mt76_eeprom_override(&dev->mt76); mt76_eeprom_override(&dev->mt76);
dev->mt76.macaddr[0] &= ~BIT(1); dev->mt76.macaddr[0] &= ~BIT(1);
......
...@@ -17,93 +17,7 @@ ...@@ -17,93 +17,7 @@
#ifndef __MT76x2_EEPROM_H #ifndef __MT76x2_EEPROM_H
#define __MT76x2_EEPROM_H #define __MT76x2_EEPROM_H
#include "mt76x2.h" #include "mt76x02_eeprom.h"
enum mt76x2_eeprom_field {
MT_EE_CHIP_ID = 0x000,
MT_EE_VERSION = 0x002,
MT_EE_MAC_ADDR = 0x004,
MT_EE_PCI_ID = 0x00A,
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_XTAL_TRIM_2 = 0x09e,
MT_EE_LNA_GAIN = 0x044,
MT_EE_RSSI_OFFSET_2G_0 = 0x046,
MT_EE_RSSI_OFFSET_2G_1 = 0x048,
MT_EE_RSSI_OFFSET_5G_0 = 0x04a,
MT_EE_RSSI_OFFSET_5G_1 = 0x04c,
MT_EE_TX_POWER_DELTA_BW40 = 0x050,
MT_EE_TX_POWER_DELTA_BW80 = 0x052,
MT_EE_TX_POWER_EXT_PA_5G = 0x054,
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_5G_6M = 0x0b2,
MT_EE_TX_POWER_OFDM_5G_24M = 0x0b4,
MT_EE_TX_POWER_HT_MCS0 = 0x0a6,
MT_EE_TX_POWER_HT_MCS4 = 0x0a8,
MT_EE_TX_POWER_HT_MCS8 = 0x0aa,
MT_EE_TX_POWER_HT_MCS12 = 0x0ac,
MT_EE_TX_POWER_VHT_MCS0 = 0x0ba,
MT_EE_TX_POWER_VHT_MCS4 = 0x0bc,
MT_EE_TX_POWER_VHT_MCS8 = 0x0be,
MT_EE_RF_TEMP_COMP_SLOPE_5G = 0x0f2,
MT_EE_RF_TEMP_COMP_SLOPE_2G = 0x0f4,
MT_EE_RF_2G_TSSI_OFF_TXPOWER = 0x0f6,
MT_EE_RF_2G_RX_HIGH_GAIN = 0x0f8,
MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN = 0x0fa,
MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN = 0x0fc,
MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN = 0x0fe,
MT_EE_BT_RCAL_RESULT = 0x138,
MT_EE_BT_VCDL_CALIBRATION = 0x13c,
MT_EE_BT_PMUCFG = 0x13e,
__MT_EE_MAX
};
#define MT_EE_NIC_CONF_0_PA_INT_2G BIT(8)
#define MT_EE_NIC_CONF_0_PA_INT_5G BIT(9)
#define MT_EE_NIC_CONF_0_BOARD_TYPE GENMASK(13, 12)
#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)
enum mt76x2_board_type {
BOARD_TYPE_2GHZ = 1,
BOARD_TYPE_5GHZ = 2,
};
enum mt76x2_cal_channel_group { enum mt76x2_cal_channel_group {
MT_CH_5G_JAPAN, MT_CH_5G_JAPAN,
...@@ -137,51 +51,18 @@ struct mt76x2_temp_comp { ...@@ -137,51 +51,18 @@ struct mt76x2_temp_comp {
unsigned int low_slope; /* J / dB */ unsigned int low_slope; /* J / dB */
}; };
static inline int
mt76x2_eeprom_get(struct mt76x2_dev *dev, enum mt76x2_eeprom_field field)
{
if ((field & 1) || field >= __MT_EE_MAX)
return -1;
return get_unaligned_le16(dev->mt76.eeprom.data + field);
}
void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t,
struct ieee80211_channel *chan); struct ieee80211_channel *chan);
int mt76x2_get_max_rate_power(struct mt76_rate_power *r);
void mt76x2_get_power_info(struct mt76x2_dev *dev, void mt76x2_get_power_info(struct mt76x2_dev *dev,
struct mt76x2_tx_power_info *t, struct mt76x2_tx_power_info *t,
struct ieee80211_channel *chan); struct ieee80211_channel *chan);
int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t); int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t);
bool mt76x2_ext_pa_enabled(struct mt76x2_dev *dev, enum nl80211_band band);
void mt76x2_read_rx_gain(struct mt76x2_dev *dev); void mt76x2_read_rx_gain(struct mt76x2_dev *dev);
void mt76x2_eeprom_parse_hw_cap(struct mt76x2_dev *dev);
static inline bool
mt76x2_temp_tx_alc_enabled(struct mt76x2_dev *dev)
{
u16 val;
val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G);
if (!(val & BIT(15)))
return false;
return mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) &
MT_EE_NIC_CONF_1_TEMP_TX_ALC;
}
static inline bool
mt76x2_tssi_enabled(struct mt76x2_dev *dev)
{
return !mt76x2_temp_tx_alc_enabled(dev) &&
(mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) &
MT_EE_NIC_CONF_1_TX_ALC_EN);
}
static inline bool static inline bool
mt76x2_has_ext_lna(struct mt76x2_dev *dev) mt76x2_has_ext_lna(struct mt76x2_dev *dev)
{ {
u32 val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1); u32 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_1);
if (dev->mt76.chandef.chan->band == NL80211_BAND_2GHZ) if (dev->mt76.chandef.chan->band == NL80211_BAND_2GHZ)
return val & MT_EE_NIC_CONF_1_LNA_EXT_2G; return val & MT_EE_NIC_CONF_1_LNA_EXT_2G;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "mt76x2_eeprom.h" #include "mt76x2_eeprom.h"
#include "mt76x2_mcu.h" #include "mt76x2_mcu.h"
#include "mt76x02_util.h" #include "mt76x02_util.h"
#include "mt76x02_dma.h"
static void static void
mt76x2_mac_pbf_init(struct mt76x2_dev *dev) mt76x2_mac_pbf_init(struct mt76x2_dev *dev)
...@@ -44,7 +45,7 @@ mt76x2_fixup_xtal(struct mt76x2_dev *dev) ...@@ -44,7 +45,7 @@ mt76x2_fixup_xtal(struct mt76x2_dev *dev)
u16 eep_val; u16 eep_val;
s8 offset = 0; s8 offset = 0;
eep_val = mt76x2_eeprom_get(dev, MT_EE_XTAL_TRIM_2); eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_2);
offset = eep_val & 0x7f; offset = eep_val & 0x7f;
if ((eep_val & 0xff) == 0xff) if ((eep_val & 0xff) == 0xff)
...@@ -54,7 +55,7 @@ mt76x2_fixup_xtal(struct mt76x2_dev *dev) ...@@ -54,7 +55,7 @@ mt76x2_fixup_xtal(struct mt76x2_dev *dev)
eep_val >>= 8; eep_val >>= 8;
if (eep_val == 0x00 || eep_val == 0xff) { if (eep_val == 0x00 || eep_val == 0xff) {
eep_val = mt76x2_eeprom_get(dev, MT_EE_XTAL_TRIM_1); eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_1);
eep_val &= 0xff; eep_val &= 0xff;
if (eep_val == 0x00 || eep_val == 0xff) if (eep_val == 0x00 || eep_val == 0xff)
...@@ -65,7 +66,7 @@ mt76x2_fixup_xtal(struct mt76x2_dev *dev) ...@@ -65,7 +66,7 @@ mt76x2_fixup_xtal(struct mt76x2_dev *dev)
mt76_rmw_field(dev, MT_XO_CTRL5, MT_XO_CTRL5_C2_VAL, eep_val + offset); mt76_rmw_field(dev, MT_XO_CTRL5, MT_XO_CTRL5_C2_VAL, eep_val + offset);
mt76_set(dev, MT_XO_CTRL6, MT_XO_CTRL6_C2_CTRL); mt76_set(dev, MT_XO_CTRL6, MT_XO_CTRL6_C2_CTRL);
eep_val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_2); eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_2);
switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) { switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) {
case 0: case 0:
mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80); mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80);
...@@ -78,23 +79,6 @@ mt76x2_fixup_xtal(struct mt76x2_dev *dev) ...@@ -78,23 +79,6 @@ mt76x2_fixup_xtal(struct mt76x2_dev *dev)
} }
} }
static void
mt76x2_init_beacon_offsets(struct mt76x2_dev *dev)
{
u16 base = MT_BEACON_BASE;
u32 regs[4] = {};
int i;
for (i = 0; i < 16; i++) {
u16 addr = dev->beacon_offsets[i];
regs[i / 4] |= ((addr - base) / 64) << (8 * (i % 4));
}
for (i = 0; i < 4; i++)
mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]);
}
static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard)
{ {
static const u8 null_addr[ETH_ALEN] = {}; static const u8 null_addr[ETH_ALEN] = {};
...@@ -186,7 +170,7 @@ static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) ...@@ -186,7 +170,7 @@ static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard)
MT_CH_TIME_CFG_EIFS_AS_BUSY | MT_CH_TIME_CFG_EIFS_AS_BUSY |
FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1));
mt76x2_init_beacon_offsets(dev); mt76x02_set_beacon_offsets(&dev->mt76);
mt76x2_set_tx_ackto(dev); mt76x2_set_tx_ackto(dev);
...@@ -204,25 +188,7 @@ int mt76x2_mac_start(struct mt76x2_dev *dev) ...@@ -204,25 +188,7 @@ int mt76x2_mac_start(struct mt76x2_dev *dev)
mt76_rr(dev, MT_TX_STAT_FIFO); mt76_rr(dev, MT_TX_STAT_FIFO);
memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats)); memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats));
mt76x02_mac_start(&dev->mt76);
mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
wait_for_wpdma(dev);
usleep_range(50, 100);
mt76_set(dev, MT_WPDMA_GLO_CFG,
MT_WPDMA_GLO_CFG_TX_DMA_EN |
MT_WPDMA_GLO_CFG_RX_DMA_EN);
mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
mt76_wr(dev, MT_MAC_SYS_CTRL,
MT_MAC_SYS_CTRL_ENABLE_TX |
MT_MAC_SYS_CTRL_ENABLE_RX);
mt76x2_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
MT_INT_TX_STAT);
return 0; return 0;
} }
...@@ -332,41 +298,12 @@ void mt76x2_set_tx_ackto(struct mt76x2_dev *dev) ...@@ -332,41 +298,12 @@ void mt76x2_set_tx_ackto(struct mt76x2_dev *dev)
int mt76x2_init_hardware(struct mt76x2_dev *dev) int mt76x2_init_hardware(struct mt76x2_dev *dev)
{ {
static const u16 beacon_offsets[16] = {
/* 1024 byte per beacon */
0xc000,
0xc400,
0xc800,
0xcc00,
0xd000,
0xd400,
0xd800,
0xdc00,
/* BSS idx 8-15 not used for beacons */
0xc000,
0xc000,
0xc000,
0xc000,
0xc000,
0xc000,
0xc000,
0xc000,
};
u32 val;
int ret; int ret;
dev->beacon_offsets = beacon_offsets;
tasklet_init(&dev->pre_tbtt_tasklet, mt76x2_pre_tbtt_tasklet, tasklet_init(&dev->pre_tbtt_tasklet, mt76x2_pre_tbtt_tasklet,
(unsigned long) dev); (unsigned long) dev);
val = mt76_rr(dev, MT_WPDMA_GLO_CFG); mt76x02_dma_disable(&dev->mt76);
val &= MT_WPDMA_GLO_CFG_DMA_BURST_SIZE |
MT_WPDMA_GLO_CFG_BIG_ENDIAN |
MT_WPDMA_GLO_CFG_HDR_SEG_LEN;
val |= MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE;
mt76_wr(dev, MT_WPDMA_GLO_CFG, val);
mt76x2_reset_wlan(dev, true); mt76x2_reset_wlan(dev, true);
mt76x2_power_on(dev); mt76x2_power_on(dev);
...@@ -380,7 +317,7 @@ int mt76x2_init_hardware(struct mt76x2_dev *dev) ...@@ -380,7 +317,7 @@ int mt76x2_init_hardware(struct mt76x2_dev *dev)
dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG);
ret = mt76x2_dma_init(dev); ret = mt76x02_dma_init(&dev->mt76);
if (ret) if (ret)
return ret; return ret;
...@@ -437,7 +374,6 @@ struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) ...@@ -437,7 +374,6 @@ struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev)
dev = container_of(mdev, struct mt76x2_dev, mt76); dev = container_of(mdev, struct mt76x2_dev, mt76);
mdev->dev = pdev; mdev->dev = pdev;
mdev->drv = &drv_ops; mdev->drv = &drv_ops;
spin_lock_init(&dev->irq_lock);
return dev; return dev;
} }
...@@ -540,6 +476,7 @@ int mt76x2_register_device(struct mt76x2_dev *dev) ...@@ -540,6 +476,7 @@ int mt76x2_register_device(struct mt76x2_dev *dev)
if (!status_fifo) if (!status_fifo)
return -ENOMEM; return -ENOMEM;
tasklet_init(&dev->tx_tasklet, mt76x2_tx_tasklet, (unsigned long)dev);
kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size); kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size);
INIT_DELAYED_WORK(&dev->cal_work, mt76x2_phy_calibrate); INIT_DELAYED_WORK(&dev->cal_work, mt76x2_phy_calibrate);
INIT_DELAYED_WORK(&dev->mac_work, mt76x2_mac_work); INIT_DELAYED_WORK(&dev->mac_work, mt76x2_mac_work);
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "mt76x2.h" #include "mt76x2.h"
#include "mt76x2_eeprom.h" #include "mt76x2_eeprom.h"
#include "mt76x02_phy.h"
static void static void
mt76x2_set_wlan_state(struct mt76x2_dev *dev, bool enable) mt76x2_set_wlan_state(struct mt76x2_dev *dev, bool enable)
...@@ -38,6 +39,9 @@ void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable) ...@@ -38,6 +39,9 @@ void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable)
{ {
u32 val; u32 val;
if (!enable)
goto out;
val = mt76_rr(dev, MT_WLAN_FUN_CTRL); val = mt76_rr(dev, MT_WLAN_FUN_CTRL);
val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL; val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL;
...@@ -53,21 +57,11 @@ void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable) ...@@ -53,21 +57,11 @@ void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable)
mt76_wr(dev, MT_WLAN_FUN_CTRL, val); mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
udelay(20); udelay(20);
out:
mt76x2_set_wlan_state(dev, enable); mt76x2_set_wlan_state(dev, enable);
} }
EXPORT_SYMBOL_GPL(mt76x2_reset_wlan); EXPORT_SYMBOL_GPL(mt76x2_reset_wlan);
static void
mt76x2_write_reg_pairs(struct mt76x2_dev *dev,
const struct mt76_reg_pair *data, int len)
{
while (len > 0) {
mt76_wr(dev, data->reg, data->value);
len--;
data++;
}
}
void mt76_write_mac_initvals(struct mt76x2_dev *dev) void mt76_write_mac_initvals(struct mt76x2_dev *dev)
{ {
#define DEFAULT_PROT_CFG_CCK \ #define DEFAULT_PROT_CFG_CCK \
...@@ -159,8 +153,8 @@ void mt76_write_mac_initvals(struct mt76x2_dev *dev) ...@@ -159,8 +153,8 @@ void mt76_write_mac_initvals(struct mt76x2_dev *dev)
{ MT_GF40_PROT_CFG, DEFAULT_PROT_CFG_40 }, { MT_GF40_PROT_CFG, DEFAULT_PROT_CFG_40 },
}; };
mt76x2_write_reg_pairs(dev, vals, ARRAY_SIZE(vals)); mt76_wr_rp(dev, 0, vals, ARRAY_SIZE(vals));
mt76x2_write_reg_pairs(dev, prot_vals, ARRAY_SIZE(prot_vals)); mt76_wr_rp(dev, 0, prot_vals, ARRAY_SIZE(prot_vals));
} }
EXPORT_SYMBOL_GPL(mt76_write_mac_initvals); EXPORT_SYMBOL_GPL(mt76_write_mac_initvals);
...@@ -183,7 +177,7 @@ void mt76x2_init_device(struct mt76x2_dev *dev) ...@@ -183,7 +177,7 @@ void mt76x2_init_device(struct mt76x2_dev *dev)
dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
dev->mt76.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; dev->mt76.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
dev->chainmask = 0x202; dev->mt76.chainmask = 0x202;
dev->mt76.global_wcid.idx = 255; dev->mt76.global_wcid.idx = 255;
dev->mt76.global_wcid.hw_key_idx = -1; dev->mt76.global_wcid.hw_key_idx = -1;
dev->slottime = 9; dev->slottime = 9;
...@@ -214,7 +208,7 @@ void mt76x2_init_txpower(struct mt76x2_dev *dev, ...@@ -214,7 +208,7 @@ void mt76x2_init_txpower(struct mt76x2_dev *dev,
mt76x2_get_rate_power(dev, &t, chan); mt76x2_get_rate_power(dev, &t, chan);
chan->max_power = mt76x2_get_max_rate_power(&t) + chan->max_power = mt76x02_get_max_rate_power(&t) +
target_power; target_power;
chan->max_power /= 2; chan->max_power /= 2;
......
...@@ -42,9 +42,9 @@ void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq) ...@@ -42,9 +42,9 @@ void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq)
trace_mac_txstat_poll(dev); trace_mac_txstat_poll(dev);
while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) { while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) {
spin_lock_irqsave(&dev->irq_lock, flags); spin_lock_irqsave(&dev->mt76.mmio.irq_lock, flags);
ret = mt76x02_mac_load_tx_status(&dev->mt76, &stat); ret = mt76x02_mac_load_tx_status(&dev->mt76, &stat);
spin_unlock_irqrestore(&dev->irq_lock, flags); spin_unlock_irqrestore(&dev->mt76.mmio.irq_lock, flags);
if (!ret) if (!ret)
break; break;
...@@ -100,7 +100,7 @@ void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, ...@@ -100,7 +100,7 @@ void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
static int static int
mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb) mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb)
{ {
int beacon_len = dev->beacon_offsets[1] - dev->beacon_offsets[0]; int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0];
struct mt76x02_txwi txwi; struct mt76x02_txwi txwi;
if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi))) if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi)))
...@@ -118,8 +118,8 @@ mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb) ...@@ -118,8 +118,8 @@ mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb)
static int static int
__mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 bcn_idx, struct sk_buff *skb) __mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 bcn_idx, struct sk_buff *skb)
{ {
int beacon_len = dev->beacon_offsets[1] - dev->beacon_offsets[0]; int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0];
int beacon_addr = dev->beacon_offsets[bcn_idx]; int beacon_addr = mt76x02_beacon_offsets[bcn_idx];
int ret = 0; int ret = 0;
int i; int i;
...@@ -129,8 +129,7 @@ __mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 bcn_idx, struct sk_buff *skb) ...@@ -129,8 +129,7 @@ __mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 bcn_idx, struct sk_buff *skb)
if (skb) { if (skb) {
ret = mt76_write_beacon(dev, beacon_addr, skb); ret = mt76_write_beacon(dev, beacon_addr, skb);
if (!ret) if (!ret)
dev->beacon_data_mask |= BIT(bcn_idx) & dev->beacon_data_mask |= BIT(bcn_idx);
dev->beacon_mask;
} else { } else {
dev->beacon_data_mask &= ~BIT(bcn_idx); dev->beacon_data_mask &= ~BIT(bcn_idx);
for (i = 0; i < beacon_len; i += 4) for (i = 0; i < beacon_len; i += 4)
...@@ -202,9 +201,9 @@ void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val) ...@@ -202,9 +201,9 @@ void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val)
mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en); mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en);
if (en) if (en)
mt76x2_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); mt76x02_irq_enable(&dev->mt76, MT_INT_PRE_TBTT | MT_INT_TBTT);
else else
mt76x2_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); mt76x02_irq_disable(&dev->mt76, MT_INT_PRE_TBTT | MT_INT_TBTT);
} }
void mt76x2_update_channel(struct mt76_dev *mdev) void mt76x2_update_channel(struct mt76_dev *mdev)
......
...@@ -100,7 +100,7 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, ...@@ -100,7 +100,7 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi,
} }
spin_unlock_bh(&dev->mt76.lock); spin_unlock_bh(&dev->mt76.lock);
txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, dev->txpower_conf, txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, dev->mt76.txpower_conf,
max_txpwr_adj); max_txpwr_adj);
txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj); txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj);
......
...@@ -106,14 +106,14 @@ mt76x2_config(struct ieee80211_hw *hw, u32 changed) ...@@ -106,14 +106,14 @@ mt76x2_config(struct ieee80211_hw *hw, u32 changed)
} }
if (changed & IEEE80211_CONF_CHANGE_POWER) { if (changed & IEEE80211_CONF_CHANGE_POWER) {
dev->txpower_conf = hw->conf.power_level * 2; dev->mt76.txpower_conf = hw->conf.power_level * 2;
/* convert to per-chain power for 2x2 devices */ /* convert to per-chain power for 2x2 devices */
dev->txpower_conf -= 6; dev->mt76.txpower_conf -= 6;
if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) { if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) {
mt76x2_phy_set_txpower(dev); mt76x2_phy_set_txpower(dev);
mt76x2_tx_set_txpwr_auto(dev, dev->txpower_conf); mt76x2_tx_set_txpwr_auto(dev, dev->mt76.txpower_conf);
} }
} }
...@@ -206,7 +206,7 @@ mt76x2_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm) ...@@ -206,7 +206,7 @@ mt76x2_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm)
{ {
struct mt76x2_dev *dev = hw->priv; struct mt76x2_dev *dev = hw->priv;
*dbm = dev->txpower_cur / 2; *dbm = dev->mt76.txpower_cur / 2;
/* convert from per-chain power to combined output on 2x2 devices */ /* convert from per-chain power to combined output on 2x2 devices */
*dbm += 3; *dbm += 3;
...@@ -241,7 +241,7 @@ static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, ...@@ -241,7 +241,7 @@ static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant,
mutex_lock(&dev->mt76.mutex); mutex_lock(&dev->mt76.mutex);
dev->chainmask = (tx_ant == 3) ? 0x202 : 0x101; dev->mt76.chainmask = (tx_ant == 3) ? 0x202 : 0x101;
dev->mt76.antenna_mask = tx_ant; dev->mt76.antenna_mask = tx_ant;
mt76_set_stream_caps(&dev->mt76, true); mt76_set_stream_caps(&dev->mt76, true);
......
...@@ -141,7 +141,7 @@ mt76pci_load_firmware(struct mt76x2_dev *dev) ...@@ -141,7 +141,7 @@ mt76pci_load_firmware(struct mt76x2_dev *dev)
mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0);
val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_2); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_2);
if (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, val) == 1) if (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, val) == 1)
mt76_set(dev, MT_MCU_COM_REG0, BIT(30)); mt76_set(dev, MT_MCU_COM_REG0, BIT(30));
...@@ -154,6 +154,7 @@ mt76pci_load_firmware(struct mt76x2_dev *dev) ...@@ -154,6 +154,7 @@ mt76pci_load_firmware(struct mt76x2_dev *dev)
} }
dev_info(dev->mt76.dev, "Firmware running!\n"); dev_info(dev->mt76.dev, "Firmware running!\n");
mt76x02_set_ethtool_fwver(&dev->mt76, hdr);
release_firmware(fw); release_firmware(fw);
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#define MT_MCU_PCIE_REMAP_BASE1 0x0740 #define MT_MCU_PCIE_REMAP_BASE1 0x0740
#define MT_MCU_PCIE_REMAP_BASE2 0x0744 #define MT_MCU_PCIE_REMAP_BASE2 0x0744
#define MT_MCU_PCIE_REMAP_BASE3 0x0748 #define MT_MCU_PCIE_REMAP_BASE3 0x0748
#define MT_MCU_PCIE_REMAP_BASE4 0x074C
#define MT_LED_CTRL 0x0770 #define MT_LED_CTRL 0x0770
#define MT_LED_CTRL_REPLAY(_n) BIT(0 + (8 * (_n))) #define MT_LED_CTRL_REPLAY(_n) BIT(0 + (8 * (_n)))
...@@ -50,16 +49,10 @@ ...@@ -50,16 +49,10 @@
#define MT_LED_STATUS_DURATION(_v) (((_v) << __ffs(MT_LED_STATUS_DURATION_MASK)) & \ #define MT_LED_STATUS_DURATION(_v) (((_v) << __ffs(MT_LED_STATUS_DURATION_MASK)) & \
MT_LED_STATUS_DURATION_MASK) MT_LED_STATUS_DURATION_MASK)
#define MT_MCU_SEMAPHORE_00 0x07B0
#define MT_MCU_SEMAPHORE_01 0x07B4
#define MT_MCU_SEMAPHORE_02 0x07B8
#define MT_MCU_SEMAPHORE_03 0x07BC
#define MT_MCU_ROM_PATCH_OFFSET 0x80000 #define MT_MCU_ROM_PATCH_OFFSET 0x80000
#define MT_MCU_ROM_PATCH_ADDR 0x90000 #define MT_MCU_ROM_PATCH_ADDR 0x90000
#define MT_MCU_ILM_OFFSET 0x80000 #define MT_MCU_ILM_OFFSET 0x80000
#define MT_MCU_ILM_ADDR 0x80000
#define MT_MCU_DLM_OFFSET 0x100000 #define MT_MCU_DLM_OFFSET 0x100000
#define MT_MCU_DLM_ADDR 0x90000 #define MT_MCU_DLM_ADDR 0x90000
......
...@@ -42,7 +42,7 @@ int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, ...@@ -42,7 +42,7 @@ int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw,
.idx = channel, .idx = channel,
.scan = scan, .scan = scan,
.bw = bw, .bw = bw,
.chainmask = cpu_to_le16(dev->chainmask), .chainmask = cpu_to_le16(dev->mt76.chainmask),
}; };
/* first set the channel without the extension channel info */ /* first set the channel without the extension channel info */
...@@ -60,6 +60,7 @@ EXPORT_SYMBOL_GPL(mt76x2_mcu_set_channel); ...@@ -60,6 +60,7 @@ EXPORT_SYMBOL_GPL(mt76x2_mcu_set_channel);
int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level,
u8 channel) u8 channel)
{ {
struct mt76_dev *mdev = &dev->mt76;
struct sk_buff *skb; struct sk_buff *skb;
struct { struct {
u8 cr_mode; u8 cr_mode;
...@@ -76,8 +77,8 @@ int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, ...@@ -76,8 +77,8 @@ int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level,
u32 val; u32 val;
val = BIT(31); val = BIT(31);
val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff; val |= (mt76x02_eeprom_get(mdev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff;
val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) << 8) & 0xff00; val |= (mt76x02_eeprom_get(mdev, MT_EE_NIC_CONF_1) << 8) & 0xff00;
msg.cfg = cpu_to_le32(val); msg.cfg = cpu_to_le32(val);
/* first set the channel without the extension channel info */ /* first set the channel without the extension channel info */
......
...@@ -53,6 +53,7 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -53,6 +53,7 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return -ENOMEM; return -ENOMEM;
mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
mt76x2_reset_wlan(dev, false);
dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION); dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION);
dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev);
......
...@@ -25,7 +25,7 @@ mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev) ...@@ -25,7 +25,7 @@ mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev)
struct ieee80211_channel *chan = dev->mt76.chandef.chan; struct ieee80211_channel *chan = dev->mt76.chandef.chan;
u32 flag = 0; u32 flag = 0;
if (!mt76x2_tssi_enabled(dev)) if (!mt76x02_tssi_enabled(&dev->mt76))
return false; return false;
if (mt76x2_channel_silent(dev)) if (mt76x2_channel_silent(dev))
...@@ -34,7 +34,7 @@ mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev) ...@@ -34,7 +34,7 @@ mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev)
if (chan->band == NL80211_BAND_5GHZ) if (chan->band == NL80211_BAND_5GHZ)
flag |= BIT(0); flag |= BIT(0);
if (mt76x2_ext_pa_enabled(dev, chan->band)) if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band))
flag |= BIT(8); flag |= BIT(8);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TSSI, flag, true); mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TSSI, flag, true);
...@@ -360,7 +360,7 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev, ...@@ -360,7 +360,7 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev,
mt76_set(dev, MT_BBP(RXO, 13), BIT(10)); mt76_set(dev, MT_BBP(RXO, 13), BIT(10));
if (!dev->cal.init_cal_done) { if (!dev->cal.init_cal_done) {
u8 val = mt76x2_eeprom_get(dev, MT_EE_BT_RCAL_RESULT); u8 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_BT_RCAL_RESULT);
if (val != 0xff) if (val != 0xff)
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, 0, true); mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, 0, true);
...@@ -390,7 +390,7 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev, ...@@ -390,7 +390,7 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev,
sizeof(dev->cal.agc_gain_cur)); sizeof(dev->cal.agc_gain_cur));
/* init default values for temp compensation */ /* init default values for temp compensation */
if (mt76x2_tssi_enabled(dev)) { if (mt76x02_tssi_enabled(&dev->mt76)) {
mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP,
0x38); 0x38);
mt76_rmw_field(dev, MT_TX_ALC_CFG_2, MT_TX_ALC_CFG_2_TEMP_COMP, mt76_rmw_field(dev, MT_TX_ALC_CFG_2, MT_TX_ALC_CFG_2_TEMP_COMP,
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "mt76x2.h" #include "mt76x2.h"
#include "mt76x2_eeprom.h" #include "mt76x2_eeprom.h"
#include "mt76x2_mcu.h" #include "mt76x2_mcu.h"
#include "mt76x02_phy.h"
static void static void
mt76x2_adjust_high_lna_gain(struct mt76x2_dev *dev, int reg, s8 offset) mt76x2_adjust_high_lna_gain(struct mt76x2_dev *dev, int reg, s8 offset)
...@@ -64,7 +65,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, ...@@ -64,7 +65,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev,
mt76_wr(dev, MT_TX_ALC_CFG_2, 0x35160a00); mt76_wr(dev, MT_TX_ALC_CFG_2, 0x35160a00);
mt76_wr(dev, MT_TX_ALC_CFG_3, 0x35160a06); mt76_wr(dev, MT_TX_ALC_CFG_3, 0x35160a06);
if (mt76x2_ext_pa_enabled(dev, band)) { if (mt76x02_ext_pa_enabled(&dev->mt76, band)) {
mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0x0000ec00); mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0x0000ec00);
mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0x0000ec00); mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0x0000ec00);
} else { } else {
...@@ -75,7 +76,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, ...@@ -75,7 +76,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev,
pa_mode[0] = 0x0000ffff; pa_mode[0] = 0x0000ffff;
pa_mode[1] = 0x00ff00ff; pa_mode[1] = 0x00ff00ff;
if (mt76x2_ext_pa_enabled(dev, band)) { if (mt76x02_ext_pa_enabled(&dev->mt76, band)) {
mt76_wr(dev, MT_TX_ALC_CFG_2, 0x2f0f0400); mt76_wr(dev, MT_TX_ALC_CFG_2, 0x2f0f0400);
mt76_wr(dev, MT_TX_ALC_CFG_3, 0x2f0f0476); mt76_wr(dev, MT_TX_ALC_CFG_3, 0x2f0f0476);
} else { } else {
...@@ -83,7 +84,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, ...@@ -83,7 +84,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev,
mt76_wr(dev, MT_TX_ALC_CFG_3, 0x1b0f0476); mt76_wr(dev, MT_TX_ALC_CFG_3, 0x1b0f0476);
} }
if (mt76x2_ext_pa_enabled(dev, band)) if (mt76x02_ext_pa_enabled(&dev->mt76, band))
pa_mode_adj = 0x04000000; pa_mode_adj = 0x04000000;
else else
pa_mode_adj = 0; pa_mode_adj = 0;
...@@ -97,7 +98,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, ...@@ -97,7 +98,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev,
mt76_wr(dev, MT_RF_PA_MODE_CFG0, pa_mode[0]); mt76_wr(dev, MT_RF_PA_MODE_CFG0, pa_mode[0]);
mt76_wr(dev, MT_RF_PA_MODE_CFG1, pa_mode[1]); mt76_wr(dev, MT_RF_PA_MODE_CFG1, pa_mode[1]);
if (mt76x2_ext_pa_enabled(dev, band)) { if (mt76x02_ext_pa_enabled(&dev->mt76, band)) {
u32 val; u32 val;
if (band == NL80211_BAND_2GHZ) if (band == NL80211_BAND_2GHZ)
...@@ -124,37 +125,6 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, ...@@ -124,37 +125,6 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev,
} }
EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower_regs); EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower_regs);
static void
mt76x2_limit_rate_power(struct mt76_rate_power *r, int limit)
{
int i;
for (i = 0; i < sizeof(r->all); i++)
if (r->all[i] > limit)
r->all[i] = limit;
}
static u32
mt76x2_tx_power_mask(u8 v1, u8 v2, u8 v3, u8 v4)
{
u32 val = 0;
val |= (v1 & (BIT(6) - 1)) << 0;
val |= (v2 & (BIT(6) - 1)) << 8;
val |= (v3 & (BIT(6) - 1)) << 16;
val |= (v4 & (BIT(6) - 1)) << 24;
return val;
}
static void
mt76x2_add_rate_power_offset(struct mt76_rate_power *r, int offset)
{
int i;
for (i = 0; i < sizeof(r->all); i++)
r->all[i] += offset;
}
static int static int
mt76x2_get_min_rate_power(struct mt76_rate_power *r) mt76x2_get_min_rate_power(struct mt76_rate_power *r)
{ {
...@@ -191,9 +161,9 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev) ...@@ -191,9 +161,9 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev)
delta = txp.delta_bw80; delta = txp.delta_bw80;
mt76x2_get_rate_power(dev, &t, chan); mt76x2_get_rate_power(dev, &t, chan);
mt76x2_add_rate_power_offset(&t, txp.chain[0].target_power); mt76x02_add_rate_power_offset(&t, txp.chain[0].target_power);
mt76x2_limit_rate_power(&t, dev->txpower_conf); mt76x02_limit_rate_power(&t, dev->mt76.txpower_conf);
dev->txpower_cur = mt76x2_get_max_rate_power(&t); dev->mt76.txpower_cur = mt76x02_get_max_rate_power(&t);
base_power = mt76x2_get_min_rate_power(&t); base_power = mt76x2_get_min_rate_power(&t);
delta += base_power - txp.chain[0].target_power; delta += base_power - txp.chain[0].target_power;
...@@ -211,31 +181,13 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev) ...@@ -211,31 +181,13 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev)
txp_1 = 0x2f; txp_1 = 0x2f;
} }
mt76x2_add_rate_power_offset(&t, -base_power); mt76x02_add_rate_power_offset(&t, -base_power);
dev->target_power = txp.chain[0].target_power; dev->target_power = txp.chain[0].target_power;
dev->target_power_delta[0] = txp_0 - txp.chain[0].target_power; dev->target_power_delta[0] = txp_0 - txp.chain[0].target_power;
dev->target_power_delta[1] = txp_1 - txp.chain[0].target_power; dev->target_power_delta[1] = txp_1 - txp.chain[0].target_power;
dev->rate_power = t; dev->mt76.rate_power = t;
mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_0, txp_0); mt76x02_phy_set_txpower(&dev->mt76, txp_0, txp_1);
mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_1, txp_1);
mt76_wr(dev, MT_TX_PWR_CFG_0,
mt76x2_tx_power_mask(t.cck[0], t.cck[2], t.ofdm[0], t.ofdm[2]));
mt76_wr(dev, MT_TX_PWR_CFG_1,
mt76x2_tx_power_mask(t.ofdm[4], t.ofdm[6], t.ht[0], t.ht[2]));
mt76_wr(dev, MT_TX_PWR_CFG_2,
mt76x2_tx_power_mask(t.ht[4], t.ht[6], t.ht[8], t.ht[10]));
mt76_wr(dev, MT_TX_PWR_CFG_3,
mt76x2_tx_power_mask(t.ht[12], t.ht[14], t.ht[0], t.ht[2]));
mt76_wr(dev, MT_TX_PWR_CFG_4,
mt76x2_tx_power_mask(t.ht[4], t.ht[6], 0, 0));
mt76_wr(dev, MT_TX_PWR_CFG_7,
mt76x2_tx_power_mask(t.ofdm[6], t.vht[8], t.ht[6], t.vht[8]));
mt76_wr(dev, MT_TX_PWR_CFG_8,
mt76x2_tx_power_mask(t.ht[14], t.vht[8], t.vht[8], 0));
mt76_wr(dev, MT_TX_PWR_CFG_9,
mt76x2_tx_power_mask(t.ht[6], t.vht[8], t.vht[8], 0));
} }
EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower); EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower);
...@@ -244,7 +196,7 @@ void mt76x2_configure_tx_delay(struct mt76x2_dev *dev, ...@@ -244,7 +196,7 @@ void mt76x2_configure_tx_delay(struct mt76x2_dev *dev,
{ {
u32 cfg0, cfg1; u32 cfg0, cfg1;
if (mt76x2_ext_pa_enabled(dev, band)) { if (mt76x02_ext_pa_enabled(&dev->mt76, band)) {
cfg0 = bw ? 0x000b0c01 : 0x00101101; cfg0 = bw ? 0x000b0c01 : 0x00101101;
cfg1 = 0x00011414; cfg1 = 0x00011414;
} else { } else {
...@@ -370,7 +322,7 @@ void mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev, bool wait) ...@@ -370,7 +322,7 @@ void mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev, bool wait)
dev->cal.tssi_comp_pending = false; dev->cal.tssi_comp_pending = false;
mt76x2_get_power_info(dev, &txp, chan); mt76x2_get_power_info(dev, &txp, chan);
if (mt76x2_ext_pa_enabled(dev, chan->band)) if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band))
t.pa_mode = 1; t.pa_mode = 1;
t.cal_mode = BIT(1); t.cal_mode = BIT(1);
......
...@@ -57,23 +57,23 @@ s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *mdev, ...@@ -57,23 +57,23 @@ s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *mdev,
u8 mcs = ieee80211_rate_get_vht_mcs(rate); u8 mcs = ieee80211_rate_get_vht_mcs(rate);
if (mcs == 8 || mcs == 9) { if (mcs == 8 || mcs == 9) {
max_txpwr = dev->rate_power.vht[8]; max_txpwr = mdev->rate_power.vht[8];
} else { } else {
u8 nss, idx; u8 nss, idx;
nss = ieee80211_rate_get_vht_nss(rate); nss = ieee80211_rate_get_vht_nss(rate);
idx = ((nss - 1) << 3) + mcs; idx = ((nss - 1) << 3) + mcs;
max_txpwr = dev->rate_power.ht[idx & 0xf]; max_txpwr = mdev->rate_power.ht[idx & 0xf];
} }
} else if (rate->flags & IEEE80211_TX_RC_MCS) { } else if (rate->flags & IEEE80211_TX_RC_MCS) {
max_txpwr = dev->rate_power.ht[rate->idx & 0xf]; max_txpwr = mdev->rate_power.ht[rate->idx & 0xf];
} else { } else {
enum nl80211_band band = dev->mt76.chandef.chan->band; enum nl80211_band band = dev->mt76.chandef.chan->band;
if (band == NL80211_BAND_2GHZ) { if (band == NL80211_BAND_2GHZ) {
const struct ieee80211_rate *r; const struct ieee80211_rate *r;
struct wiphy *wiphy = mt76_hw(dev)->wiphy; struct wiphy *wiphy = mt76_hw(dev)->wiphy;
struct mt76_rate_power *rp = &dev->rate_power; struct mt76_rate_power *rp = &mdev->rate_power;
r = &wiphy->bands[band]->bitrates[rate->idx]; r = &wiphy->bands[band]->bitrates[rate->idx];
if (r->flags & IEEE80211_RATE_SHORT_PREAMBLE) if (r->flags & IEEE80211_RATE_SHORT_PREAMBLE)
...@@ -81,7 +81,7 @@ s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *mdev, ...@@ -81,7 +81,7 @@ s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *mdev,
else else
max_txpwr = rp->ofdm[r->hw_value & 0x7]; max_txpwr = rp->ofdm[r->hw_value & 0x7];
} else { } else {
max_txpwr = dev->rate_power.ofdm[rate->idx & 0x7]; max_txpwr = mdev->rate_power.ofdm[rate->idx & 0x7];
} }
} }
...@@ -91,7 +91,7 @@ EXPORT_SYMBOL_GPL(mt76x2_tx_get_max_txpwr_adj); ...@@ -91,7 +91,7 @@ EXPORT_SYMBOL_GPL(mt76x2_tx_get_max_txpwr_adj);
s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj) s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj)
{ {
txpwr = min_t(s8, txpwr, dev->txpower_conf); txpwr = min_t(s8, txpwr, dev->mt76.txpower_conf);
txpwr -= (dev->target_power + dev->target_power_delta[0]); txpwr -= (dev->target_power + dev->target_power_delta[0]);
txpwr = min_t(s8, txpwr, max_txpwr_adj); txpwr = min_t(s8, txpwr, max_txpwr_adj);
...@@ -109,7 +109,7 @@ void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr) ...@@ -109,7 +109,7 @@ void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr)
s8 txpwr_adj; s8 txpwr_adj;
txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, txpwr, txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, txpwr,
dev->rate_power.ofdm[4]); dev->mt76.rate_power.ofdm[4]);
mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG, mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG,
MT_PROT_AUTO_TX_CFG_PROT_PADJ, txpwr_adj); MT_PROT_AUTO_TX_CFG_PROT_PADJ, txpwr_adj);
mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG, mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG,
......
...@@ -36,7 +36,6 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev); ...@@ -36,7 +36,6 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev);
void mt76x2u_cleanup(struct mt76x2_dev *dev); void mt76x2u_cleanup(struct mt76x2_dev *dev);
void mt76x2u_stop_hw(struct mt76x2_dev *dev); void mt76x2u_stop_hw(struct mt76x2_dev *dev);
void mt76x2u_mac_setaddr(struct mt76x2_dev *dev, u8 *addr);
int mt76x2u_mac_reset(struct mt76x2_dev *dev); int mt76x2u_mac_reset(struct mt76x2_dev *dev);
void mt76x2u_mac_resume(struct mt76x2_dev *dev); void mt76x2u_mac_resume(struct mt76x2_dev *dev);
int mt76x2u_mac_start(struct mt76x2_dev *dev); int mt76x2u_mac_start(struct mt76x2_dev *dev);
...@@ -46,8 +45,6 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, ...@@ -46,8 +45,6 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev,
struct cfg80211_chan_def *chandef); struct cfg80211_chan_def *chandef);
void mt76x2u_phy_calibrate(struct work_struct *work); void mt76x2u_phy_calibrate(struct work_struct *work);
void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev); void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev);
void mt76x2u_phy_set_txdac(struct mt76x2_dev *dev);
void mt76x2u_phy_set_rxpath(struct mt76x2_dev *dev);
void mt76x2u_mcu_complete_urb(struct urb *urb); void mt76x2u_mcu_complete_urb(struct urb *urb);
int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap,
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "mt76x2u.h" #include "mt76x2u.h"
#include "mt76x02_util.h" #include "mt76x02_util.h"
#include "mt76x02_phy.h"
#include "mt76x2_eeprom.h" #include "mt76x2_eeprom.h"
static void mt76x2u_init_dma(struct mt76x2_dev *dev) static void mt76x2u_init_dma(struct mt76x2_dev *dev)
...@@ -129,7 +130,7 @@ static int mt76x2u_init_eeprom(struct mt76x2_dev *dev) ...@@ -129,7 +130,7 @@ static int mt76x2u_init_eeprom(struct mt76x2_dev *dev)
put_unaligned_le32(val, dev->mt76.eeprom.data + i); put_unaligned_le32(val, dev->mt76.eeprom.data + i);
} }
mt76x2_eeprom_parse_hw_cap(dev); mt76x02_eeprom_parse_hw_cap(&dev->mt76);
return 0; return 0;
} }
...@@ -165,21 +166,12 @@ static void mt76x2u_init_beacon_offsets(struct mt76x2_dev *dev) ...@@ -165,21 +166,12 @@ static void mt76x2u_init_beacon_offsets(struct mt76x2_dev *dev)
int mt76x2u_init_hardware(struct mt76x2_dev *dev) int mt76x2u_init_hardware(struct mt76x2_dev *dev)
{ {
static const u16 beacon_offsets[] = {
/* 512 byte per beacon */
0xc000, 0xc200, 0xc400, 0xc600,
0xc800, 0xca00, 0xcc00, 0xce00,
0xd000, 0xd200, 0xd400, 0xd600,
0xd800, 0xda00, 0xdc00, 0xde00
};
const struct mt76_wcid_addr addr = { const struct mt76_wcid_addr addr = {
.macaddr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, .macaddr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.ba_mask = 0, .ba_mask = 0,
}; };
int i, err; int i, err;
dev->beacon_offsets = beacon_offsets;
mt76x2_reset_wlan(dev, true); mt76x2_reset_wlan(dev, true);
mt76x2u_power_on(dev); mt76x2u_power_on(dev);
...@@ -212,12 +204,13 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev) ...@@ -212,12 +204,13 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev)
if (err < 0) if (err < 0)
return err; return err;
mt76x2u_mac_setaddr(dev, dev->mt76.eeprom.data + MT_EE_MAC_ADDR); mt76x02_mac_setaddr(&dev->mt76,
dev->mt76.eeprom.data + MT_EE_MAC_ADDR);
dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG);
mt76x2u_init_beacon_offsets(dev); mt76x2u_init_beacon_offsets(dev);
if (!mt76x2_wait_for_bbp(dev)) if (!mt76x02_wait_for_txrx_idle(&dev->mt76))
return -ETIMEDOUT; return -ETIMEDOUT;
/* reset wcid table */ /* reset wcid table */
...@@ -244,8 +237,8 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev) ...@@ -244,8 +237,8 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev)
if (err < 0) if (err < 0)
return err; return err;
mt76x2u_phy_set_rxpath(dev); mt76x02_phy_set_rxpath(&dev->mt76);
mt76x2u_phy_set_txdac(dev); mt76x02_phy_set_txdac(&dev->mt76);
return mt76x2u_mac_stop(dev); return mt76x2u_mac_stop(dev);
} }
...@@ -263,14 +256,14 @@ int mt76x2u_register_device(struct mt76x2_dev *dev) ...@@ -263,14 +256,14 @@ int mt76x2u_register_device(struct mt76x2_dev *dev)
if (err < 0) if (err < 0)
return err; return err;
err = mt76u_mcu_init_rx(&dev->mt76);
if (err < 0)
return err;
err = mt76u_alloc_queues(&dev->mt76); err = mt76u_alloc_queues(&dev->mt76);
if (err < 0) if (err < 0)
goto fail; goto fail;
err = mt76u_mcu_init_rx(&dev->mt76);
if (err < 0)
return err;
err = mt76x2u_init_hardware(dev); err = mt76x2u_init_hardware(dev);
if (err < 0) if (err < 0)
goto fail; goto fail;
......
...@@ -32,7 +32,7 @@ static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev) ...@@ -32,7 +32,7 @@ static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev)
s8 offset = 0; s8 offset = 0;
u16 eep_val; u16 eep_val;
eep_val = mt76x2_eeprom_get(dev, MT_EE_XTAL_TRIM_2); eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_2);
offset = eep_val & 0x7f; offset = eep_val & 0x7f;
if ((eep_val & 0xff) == 0xff) if ((eep_val & 0xff) == 0xff)
...@@ -42,7 +42,7 @@ static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev) ...@@ -42,7 +42,7 @@ static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev)
eep_val >>= 8; eep_val >>= 8;
if (eep_val == 0x00 || eep_val == 0xff) { if (eep_val == 0x00 || eep_val == 0xff) {
eep_val = mt76x2_eeprom_get(dev, MT_EE_XTAL_TRIM_1); eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_1);
eep_val &= 0xff; eep_val &= 0xff;
if (eep_val == 0x00 || eep_val == 0xff) if (eep_val == 0x00 || eep_val == 0xff)
...@@ -67,7 +67,7 @@ static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev) ...@@ -67,7 +67,7 @@ static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev)
/* init fce */ /* init fce */
mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN);
eep_val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_2); eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_2);
switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) { switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) {
case 0: case 0:
mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80); mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80);
...@@ -119,7 +119,7 @@ int mt76x2u_mac_start(struct mt76x2_dev *dev) ...@@ -119,7 +119,7 @@ int mt76x2u_mac_start(struct mt76x2_dev *dev)
mt76x2u_mac_reset_counters(dev); mt76x2u_mac_reset_counters(dev);
mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
wait_for_wpdma(dev); mt76x02_wait_for_wpdma(&dev->mt76, 1000);
usleep_range(50, 100); usleep_range(50, 100);
mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
...@@ -220,21 +220,3 @@ void mt76x2u_mac_resume(struct mt76x2_dev *dev) ...@@ -220,21 +220,3 @@ void mt76x2u_mac_resume(struct mt76x2_dev *dev)
mt76_set(dev, MT_TXOP_CTRL_CFG, BIT(20)); mt76_set(dev, MT_TXOP_CTRL_CFG, BIT(20));
mt76_set(dev, MT_TXOP_HLDR_ET, BIT(1)); mt76_set(dev, MT_TXOP_HLDR_ET, BIT(1));
} }
void mt76x2u_mac_setaddr(struct mt76x2_dev *dev, u8 *addr)
{
ether_addr_copy(dev->mt76.macaddr, addr);
if (!is_valid_ether_addr(dev->mt76.macaddr)) {
eth_random_addr(dev->mt76.macaddr);
dev_info(dev->mt76.dev,
"Invalid MAC address, using random address %pM\n",
dev->mt76.macaddr);
}
mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->mt76.macaddr));
mt76_wr(dev, MT_MAC_ADDR_DW1,
get_unaligned_le16(dev->mt76.macaddr + 4) |
FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
}
...@@ -51,7 +51,7 @@ static int mt76x2u_add_interface(struct ieee80211_hw *hw, ...@@ -51,7 +51,7 @@ static int mt76x2u_add_interface(struct ieee80211_hw *hw,
struct mt76x2_dev *dev = hw->priv; struct mt76x2_dev *dev = hw->priv;
if (!ether_addr_equal(dev->mt76.macaddr, vif->addr)) if (!ether_addr_equal(dev->mt76.macaddr, vif->addr))
mt76x2u_mac_setaddr(dev, vif->addr); mt76x02_mac_setaddr(&dev->mt76, vif->addr);
mt76x02_vif_init(&dev->mt76, vif, 0); mt76x02_vif_init(&dev->mt76, vif, 0);
return 0; return 0;
...@@ -128,10 +128,10 @@ mt76x2u_config(struct ieee80211_hw *hw, u32 changed) ...@@ -128,10 +128,10 @@ mt76x2u_config(struct ieee80211_hw *hw, u32 changed)
} }
if (changed & IEEE80211_CONF_CHANGE_POWER) { if (changed & IEEE80211_CONF_CHANGE_POWER) {
dev->txpower_conf = hw->conf.power_level * 2; dev->mt76.txpower_conf = hw->conf.power_level * 2;
/* convert to per-chain power for 2x2 devices */ /* convert to per-chain power for 2x2 devices */
dev->txpower_conf -= 6; dev->mt76.txpower_conf -= 6;
if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state))
mt76x2_phy_set_txpower(dev); mt76x2_phy_set_txpower(dev);
......
...@@ -261,6 +261,7 @@ static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev) ...@@ -261,6 +261,7 @@ static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev)
/* enable FCE to send in-band cmd */ /* enable FCE to send in-band cmd */
mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1); mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1);
dev_dbg(dev->mt76.dev, "firmware running\n"); dev_dbg(dev->mt76.dev, "firmware running\n");
mt76x02_set_ethtool_fwver(&dev->mt76, hdr);
out: out:
release_firmware(fw); release_firmware(fw);
......
...@@ -17,39 +17,6 @@ ...@@ -17,39 +17,6 @@
#include "mt76x2u.h" #include "mt76x2u.h"
#include "mt76x2_eeprom.h" #include "mt76x2_eeprom.h"
void mt76x2u_phy_set_rxpath(struct mt76x2_dev *dev)
{
u32 val;
val = mt76_rr(dev, MT_BBP(AGC, 0));
val &= ~BIT(4);
switch (dev->chainmask & 0xf) {
case 2:
val |= BIT(3);
break;
default:
val &= ~BIT(3);
break;
}
mt76_wr(dev, MT_BBP(AGC, 0), val);
}
void mt76x2u_phy_set_txdac(struct mt76x2_dev *dev)
{
int txpath;
txpath = (dev->chainmask >> 8) & 0xf;
switch (txpath) {
case 2:
mt76_set(dev, MT_BBP(TXBE, 5), 0x3);
break;
default:
mt76_clear(dev, MT_BBP(TXBE, 5), 0x3);
break;
}
}
void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev) void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev)
{ {
struct ieee80211_channel *chan = dev->mt76.chandef.chan; struct ieee80211_channel *chan = dev->mt76.chandef.chan;
...@@ -209,7 +176,7 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, ...@@ -209,7 +176,7 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev,
mt76_set(dev, MT_BBP(RXO, 13), BIT(10)); mt76_set(dev, MT_BBP(RXO, 13), BIT(10));
if (!dev->cal.init_cal_done) { if (!dev->cal.init_cal_done) {
u8 val = mt76x2_eeprom_get(dev, MT_EE_BT_RCAL_RESULT); u8 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_BT_RCAL_RESULT);
if (val != 0xff) if (val != 0xff)
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R,
...@@ -235,7 +202,7 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, ...@@ -235,7 +202,7 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev,
if (scan) if (scan)
return 0; return 0;
if (mt76x2_tssi_enabled(dev)) { if (mt76x02_tssi_enabled(&dev->mt76)) {
/* init default values for temp compensation */ /* init default values for temp compensation */
mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP,
0x38); 0x38);
...@@ -250,7 +217,7 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, ...@@ -250,7 +217,7 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev,
chan = dev->mt76.chandef.chan; chan = dev->mt76.chandef.chan;
if (chan->band == NL80211_BAND_5GHZ) if (chan->band == NL80211_BAND_5GHZ)
flag |= BIT(0); flag |= BIT(0);
if (mt76x2_ext_pa_enabled(dev, chan->band)) if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band))
flag |= BIT(8); flag |= BIT(8);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TSSI, mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TSSI,
flag, false); flag, false);
......
...@@ -91,11 +91,23 @@ mt76_txq_get_qid(struct ieee80211_txq *txq) ...@@ -91,11 +91,23 @@ mt76_txq_get_qid(struct ieee80211_txq *txq)
return txq->ac; return txq->ac;
} }
static void
mt76_check_agg_ssn(struct mt76_txq *mtxq, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
if (!ieee80211_is_data_qos(hdr->frame_control))
return;
mtxq->agg_ssn = le16_to_cpu(hdr->seq_ctrl) + 0x10;
}
void void
mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta, mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta,
struct mt76_wcid *wcid, struct sk_buff *skb) struct mt76_wcid *wcid, struct sk_buff *skb)
{ {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct mt76_queue *q; struct mt76_queue *q;
int qid = skb_get_queue_mapping(skb); int qid = skb_get_queue_mapping(skb);
...@@ -108,6 +120,19 @@ mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta, ...@@ -108,6 +120,19 @@ mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta,
ieee80211_get_tx_rates(info->control.vif, sta, skb, ieee80211_get_tx_rates(info->control.vif, sta, skb,
info->control.rates, 1); info->control.rates, 1);
if (sta && ieee80211_is_data_qos(hdr->frame_control)) {
struct ieee80211_txq *txq;
struct mt76_txq *mtxq;
u8 tid;
tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
txq = sta->txq[tid];
mtxq = (struct mt76_txq *) txq->drv_priv;
if (mtxq->aggr)
mt76_check_agg_ssn(mtxq, skb);
}
q = &dev->q_tx[qid]; q = &dev->q_tx[qid];
spin_lock_bh(&q->lock); spin_lock_bh(&q->lock);
...@@ -143,17 +168,6 @@ mt76_txq_dequeue(struct mt76_dev *dev, struct mt76_txq *mtxq, bool ps) ...@@ -143,17 +168,6 @@ mt76_txq_dequeue(struct mt76_dev *dev, struct mt76_txq *mtxq, bool ps)
return skb; return skb;
} }
static void
mt76_check_agg_ssn(struct mt76_txq *mtxq, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
if (!ieee80211_is_data_qos(hdr->frame_control))
return;
mtxq->agg_ssn = le16_to_cpu(hdr->seq_ctrl) + 0x10;
}
static void static void
mt76_queue_ps_skb(struct mt76_dev *dev, struct ieee80211_sta *sta, mt76_queue_ps_skb(struct mt76_dev *dev, struct ieee80211_sta *sta,
struct sk_buff *skb, bool last) struct sk_buff *skb, bool last)
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <linux/module.h>
#include "mt76.h" #include "mt76.h"
#include "usb_trace.h" #include "usb_trace.h"
#include "dma.h" #include "dma.h"
...@@ -279,6 +280,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf, ...@@ -279,6 +280,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf,
struct urb *urb = buf->urb; struct urb *urb = buf->urb;
int i; int i;
spin_lock_bh(&q->rx_page_lock);
for (i = 0; i < nsgs; i++) { for (i = 0; i < nsgs; i++) {
struct page *page; struct page *page;
void *data; void *data;
...@@ -292,6 +294,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf, ...@@ -292,6 +294,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf,
offset = data - page_address(page); offset = data - page_address(page);
sg_set_page(&urb->sg[i], page, sglen, offset); sg_set_page(&urb->sg[i], page, sglen, offset);
} }
spin_unlock_bh(&q->rx_page_lock);
if (i < nsgs) { if (i < nsgs) {
int j; int j;
...@@ -383,9 +386,9 @@ static int mt76u_get_rx_entry_len(u8 *data, u32 data_len) ...@@ -383,9 +386,9 @@ static int mt76u_get_rx_entry_len(u8 *data, u32 data_len)
min_len = MT_DMA_HDR_LEN + MT_RX_RXWI_LEN + min_len = MT_DMA_HDR_LEN + MT_RX_RXWI_LEN +
MT_FCE_INFO_LEN; MT_FCE_INFO_LEN;
if (data_len < min_len || WARN_ON(!dma_len) || if (data_len < min_len || !dma_len ||
WARN_ON(dma_len + MT_DMA_HDR_LEN > data_len) || dma_len + MT_DMA_HDR_LEN > data_len ||
WARN_ON(dma_len & 0x3)) (dma_len & 0x3))
return -EINVAL; return -EINVAL;
return dma_len; return dma_len;
} }
...@@ -520,6 +523,7 @@ static int mt76u_alloc_rx(struct mt76_dev *dev) ...@@ -520,6 +523,7 @@ static int mt76u_alloc_rx(struct mt76_dev *dev)
struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
int i, err, nsgs; int i, err, nsgs;
spin_lock_init(&q->rx_page_lock);
spin_lock_init(&q->lock); spin_lock_init(&q->lock);
q->entry = devm_kzalloc(dev->dev, q->entry = devm_kzalloc(dev->dev,
MT_NUM_RX_ENTRIES * sizeof(*q->entry), MT_NUM_RX_ENTRIES * sizeof(*q->entry),
...@@ -557,12 +561,15 @@ static void mt76u_free_rx(struct mt76_dev *dev) ...@@ -557,12 +561,15 @@ static void mt76u_free_rx(struct mt76_dev *dev)
for (i = 0; i < q->ndesc; i++) for (i = 0; i < q->ndesc; i++)
mt76u_buf_free(&q->entry[i].ubuf); mt76u_buf_free(&q->entry[i].ubuf);
spin_lock_bh(&q->rx_page_lock);
if (!q->rx_page.va) if (!q->rx_page.va)
return; goto out;
page = virt_to_page(q->rx_page.va); page = virt_to_page(q->rx_page.va);
__page_frag_cache_drain(page, q->rx_page.pagecnt_bias); __page_frag_cache_drain(page, q->rx_page.pagecnt_bias);
memset(&q->rx_page, 0, sizeof(q->rx_page)); memset(&q->rx_page, 0, sizeof(q->rx_page));
out:
spin_unlock_bh(&q->rx_page_lock);
} }
static void mt76u_stop_rx(struct mt76_dev *dev) static void mt76u_stop_rx(struct mt76_dev *dev)
......
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