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);
} }
...@@ -16,131 +16,33 @@ ...@@ -16,131 +16,33 @@
#ifndef __MT76X0U_EEPROM_H #ifndef __MT76X0U_EEPROM_H
#define __MT76X0U_EEPROM_H #define __MT76X0U_EEPROM_H
#include "../mt76x02_eeprom.h"
struct mt76x0_dev; struct mt76x0_dev;
#define MT76X0U_EE_MAX_VER 0x0c #define MT76X0U_EE_MAX_VER 0x0c
#define MT76X0_EEPROM_SIZE 512 #define MT76X0_EEPROM_SIZE 512
#define MT76X0U_DEFAULT_TX_POWER 6 struct mt76x0_caldata {
s8 rssi_offset[2];
enum mt76_eeprom_field { s8 lna_gain;
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 + \
(i) * 4)
#define MT_EFUSE_USAGE_MAP_SIZE (MT_EE_USAGE_MAP_END - \
MT_EE_USAGE_MAP_START + 1)
enum mt76x0_eeprom_access_modes { s16 temp_offset;
MT_EE_READ = 0, u8 freq_offset;
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. */
u32 tx_pwr_cfg_2g[5][2];
u32 tx_pwr_cfg_5g[5][2];
u8 tx_pwr_per_chan[58];
struct reg_channel_bounds reg;
}; };
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);
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); 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;
......
...@@ -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,8 +60,8 @@ mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr) ...@@ -78,8 +60,8 @@ 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,10 +112,9 @@ mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ...@@ -130,10 +112,9 @@ 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,
struct ieee80211_vif *vif,
const u8 *mac_addr) const u8 *mac_addr)
{ {
struct mt76x0_dev *dev = hw->priv; struct mt76x0_dev *dev = hw->priv;
...@@ -142,9 +123,9 @@ mt76x0_sw_scan(struct ieee80211_hw *hw, ...@@ -142,9 +123,9 @@ 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,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#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)
...@@ -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)
......
/*
* 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)
......
...@@ -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);
......
...@@ -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);
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment